From b4b8410d4ef80c3dedacddf602a00c62e2f93d3e Mon Sep 17 00:00:00 2001 From: Olivier Sallou Date: Sat, 10 Feb 2018 17:32:50 +0000 Subject: [PATCH] New upstream version 2.7.1 --- c++/compilers/cygwin/build.sh | 15 +- c++/compilers/vs2013/datatool.bat | 12 +- c++/compilers/vs2013/make.bat | 2 +- c++/compilers/vs2013/ptb.bat | 2 +- .../serial/datatool/datatool.exe.vcxproj | 12 + c++/compilers/vs2015/datatool.bat | 12 +- c++/compilers/vs2015/make.bat | 2 +- c++/compilers/vs2015/ptb.bat | 2 +- .../serial/datatool/datatool.exe.vcxproj | 12 + c++/compilers/xcode30_prj/configure | 2 +- c++/compilers/xcode30_prj/datatool.sh | 12 +- .../PTB.xcodeproj/project.pbxproj | 44 + c++/include/algo/blast/api/blast_options.hpp | 38 +- .../algo/blast/api/blast_options_builder.hpp | 5 +- c++/include/algo/blast/api/blast_results.hpp | 11 +- .../algo/blast/api/blast_seqinfosrc.hpp | 4 +- .../algo/blast/api/blast_seqinfosrc_aux.hpp | 2 +- c++/include/algo/blast/api/blast_types.hpp | 3 +- .../algo/blast/api/blastp_kmer_options.hpp | 123 + c++/include/algo/blast/api/magicblast.hpp | 174 +- .../algo/blast/api/magicblast_options.hpp | 44 +- c++/include/algo/blast/api/prelim_stage.hpp | 13 +- c++/include/algo/blast/api/remote_blast.hpp | 4 +- .../algo/blast/api/seqinfosrc_seqdb.hpp | 4 +- c++/include/algo/blast/api/setup_factory.hpp | 9 +- .../algo/blast/blastinput/blast_args.hpp | 85 +- .../blast/blastinput/blast_asn1_input.hpp | 36 +- .../blast/blastinput/blast_fasta_input.hpp | 47 +- .../algo/blast/blastinput/blast_input.hpp | 49 +- .../algo/blast/blastinput/blast_input_aux.hpp | 9 +- .../algo/blast/blastinput/blast_scope_src.hpp | 2 +- .../algo/blast/blastinput/cmdline_flags.hpp | 36 +- .../algo/blast/blastinput/kblastp_args.hpp | 9 +- .../algo/blast/blastinput/rpsblast_args.hpp | 9 +- c++/include/algo/blast/core/blast_hits.h | 58 +- c++/include/algo/blast/core/blast_hspstream.h | 3 +- c++/include/algo/blast/core/blast_lookup.h | 24 +- c++/include/algo/blast/core/blast_nalookup.h | 8 +- c++/include/algo/blast/core/blast_options.h | 34 +- .../algo/blast/core/blast_query_info.h | 2 +- .../algo/blast/core/hspfilter_mapper.h | 18 +- c++/include/algo/blast/core/lookup_wrap.h | 27 +- c++/include/algo/blast/core/spliced_hits.h | 113 + c++/include/algo/blast/dbindex/dbindex.hpp | 11 +- .../blast/dbindex/sequence_istream_fasta.hpp | 3 +- .../algo/blast/format/blast_async_format.hpp | 105 + .../algo/blast/format/blast_format.hpp | 7 +- c++/include/algo/blast/igblast/igblast.hpp | 26 +- .../algo/blast/proteinkmer/blastkmer.hpp | 181 + .../algo/blast/proteinkmer/blastkmerindex.hpp | 104 + .../blast/proteinkmer/blastkmeroptions.hpp | 106 + .../blast/proteinkmer/blastkmerresults.hpp | 236 + .../algo/blast/proteinkmer/blastkmerutils.hpp | 311 + .../algo/blast/proteinkmer/kblastapi.hpp | 106 + c++/include/algo/blast/proteinkmer/mhfile.hpp | 197 + c++/include/algo/winmask/seq_masker_istat.hpp | 4 +- c++/include/algo/winmask/seq_masker_ostat.hpp | 8 +- c++/include/cgi/cgi_exception.hpp | 27 +- c++/include/cgi/cgi_serial.hpp | 9 +- c++/include/cgi/cgiapp.hpp | 63 +- c++/include/cgi/cgictx.hpp | 29 +- c++/include/cgi/ncbicgi.hpp | 5 +- c++/include/cgi/ncbicgir.hpp | 10 +- c++/include/cgi/user_agent.hpp | 2 +- c++/include/common/boost_skew_guard.hpp | 5 +- c++/include/common/config/ncbiconf_msvc.h | 5 +- .../common/config/ncbiconf_universal.h | 2 +- c++/include/common/config/ncbiconf_xcode.h | 20 +- c++/include/common/ncbi_build_ver.h.in | 4 +- c++/include/common/ncbi_export.h | 20 +- c++/include/common/ncbi_package_ver.h | 4 +- c++/include/common/ncbi_skew_guard.h | 4 +- c++/include/common/ncbi_source_ver.h | 6 +- c++/include/common/ncbiconf_impl.h | 17 +- c++/include/common/test_data_path.h | 21 +- c++/include/connect/error_codes.hpp | 3 +- .../connect/impl/thread_pool_for_server.hpp | 9 +- c++/include/connect/ncbi_conn_stream.hpp | 27 +- c++/include/connect/ncbi_conn_test.hpp | 4 +- c++/include/connect/ncbi_connector.h | 2 +- c++/include/connect/ncbi_connutil.h | 12 +- c++/include/connect/ncbi_core.h | 156 +- c++/include/connect/ncbi_core_cxx.hpp | 50 +- c++/include/connect/ncbi_gnutls.h | 18 +- c++/include/connect/ncbi_heapmgr.h | 9 +- c++/include/connect/ncbi_host_info.h | 8 +- c++/include/connect/ncbi_http_session.hpp | 38 +- c++/include/connect/ncbi_iprange.h | 90 + c++/include/connect/ncbi_ipv6.h | 213 + c++/include/connect/ncbi_lbos.hpp | 69 +- c++/include/connect/ncbi_localip.h | 86 + c++/include/connect/ncbi_mbedtls.h | 79 + c++/include/connect/ncbi_monkey.hpp | 69 +- .../connect/ncbi_namedpipe_connector.hpp | 6 +- c++/include/connect/ncbi_pipe_connector.hpp | 6 +- c++/include/connect/ncbi_sendmail.h | 28 +- c++/include/connect/ncbi_server_info.h | 163 +- c++/include/connect/ncbi_service.h | 31 +- c++/include/connect/ncbi_service_connector.h | 6 +- c++/include/connect/ncbi_socket.h | 26 +- c++/include/connect/ncbi_tls.h | 88 + c++/include/connect/ncbi_types.h | 6 +- c++/include/connect/ncbi_util.h | 45 +- .../services/grid_app_version_info.hpp | 24 +- c++/include/connect/services/grid_client.hpp | 36 +- c++/include/connect/services/grid_globals.hpp | 10 +- c++/include/connect/services/grid_rw_impl.hpp | 57 +- c++/include/connect/services/grid_worker.hpp | 12 +- .../connect/services/grid_worker_app.hpp | 38 +- .../services/impl/netschedule_api_int.hpp | 14 +- .../connect/services/impl/netstorage_impl.hpp | 242 +- .../connect/services/impl/netstorage_int.hpp | 66 +- .../connect/services/json_over_uttp.hpp | 30 +- .../connect/services/netcache_admin.hpp | 2 +- c++/include/connect/services/netcache_api.hpp | 16 +- .../connect/services/netcache_search.hpp | 2 +- c++/include/connect/services/netcomponent.hpp | 12 +- .../connect/services/neticache_client.hpp | 30 +- .../connect/services/netschedule_api.hpp | 54 +- .../connect/services/netservice_api.hpp | 6 +- c++/include/connect/services/netstorage.hpp | 17 +- .../connect/services/ns_output_parser.hpp | 24 +- c++/include/connect/services/remote_app.hpp | 8 +- .../connect/services/srv_connections.hpp | 10 +- c++/include/connect/services/util.hpp | 20 +- c++/include/corelib/error_codes.hpp | 4 +- c++/include/corelib/impl/ncbi_dbsvcmapper.hpp | 64 +- c++/include/corelib/impl/rwstreambuf.hpp | 14 +- c++/include/corelib/ncbi_cookies.hpp | 2 +- c++/include/corelib/ncbi_process.hpp | 10 +- c++/include/corelib/ncbi_safe_static.hpp | 80 +- c++/include/corelib/ncbi_stack.hpp | 7 +- c++/include/corelib/ncbi_system.hpp | 8 +- c++/include/corelib/ncbi_tree.hpp | 4 +- c++/include/corelib/ncbi_url.hpp | 87 +- c++/include/corelib/ncbiapp.hpp | 40 +- c++/include/corelib/ncbiargs.hpp | 11 +- c++/include/corelib/ncbidiag.hpp | 2 +- c++/include/corelib/ncbidll.hpp | 15 +- c++/include/corelib/ncbierror.hpp | 2 +- c++/include/corelib/ncbiexpt.hpp | 4 +- c++/include/corelib/ncbifile.hpp | 276 +- c++/include/corelib/ncbimisc.hpp | 345 +- c++/include/corelib/ncbimtx.hpp | 64 +- c++/include/corelib/ncbiobj.hpp | 11 +- c++/include/corelib/ncbireg.hpp | 81 +- c++/include/corelib/ncbistr.hpp | 340 +- c++/include/corelib/ncbistr_util.hpp | 11 +- c++/include/corelib/ncbistre.hpp | 44 +- c++/include/corelib/ncbithr.hpp | 11 +- c++/include/corelib/ncbiutil.hpp | 4 +- c++/include/corelib/perf_log.hpp | 12 +- c++/include/corelib/request_ctx.hpp | 4 +- c++/include/corelib/request_status.hpp | 4 +- c++/include/corelib/syslog.hpp | 4 +- .../corelib/teamcity_messages.h | 7 +- c++/include/corelib/tempstr.hpp | 3 +- c++/include/corelib/test_boost.hpp | 17 +- c++/include/corelib/version.hpp | 24 +- c++/include/db/error_codes.hpp | 60 + c++/include/db/sqlite/sqlitewrapp.hpp | 948 + c++/include/dbapi/dbapi.hpp | 6 +- .../dbapi/driver/dbapi_conn_factory.hpp | 11 +- .../dbapi/driver/dbapi_driver_conn_mgr.hpp | 4 +- c++/include/dbapi/driver/dbapi_svc_mapper.hpp | 3 +- .../dbapi/driver/impl/dbapi_driver_utils.hpp | 25 +- .../dbapi/driver/impl/dbapi_impl_cmd.hpp | 6 +- .../driver/impl/dbapi_impl_connection.hpp | 6 +- .../dbapi/driver/impl/dbapi_impl_context.hpp | 32 +- c++/include/dbapi/driver/interfaces.hpp | 8 +- c++/include/dbapi/driver/odbc/interfaces.hpp | 8 +- c++/include/dbapi/driver/public.hpp | 4 +- c++/include/dbapi/error_codes.hpp | 3 +- c++/include/dbapi/variant.hpp | 4 +- c++/include/html/html.hpp | 4 +- c++/include/html/node.hpp | 6 +- c++/include/ncbi_pch.hpp | 2 +- c++/include/ncbi_source_ver.h | 2 +- c++/include/ncbiconf.h | 2 +- c++/include/objects/general/Dbtag.hpp | 8 +- c++/include/objects/general/Name_std.hpp | 2 +- .../objects/genomecoll/GC_Assembly.hpp | 12 +- .../objects/genomecoll/GC_AssemblyUnit.hpp | 5 +- .../objects/genomecoll/cached_assembly.hpp | 2 - .../genomecoll/genomic_collections_cli.hpp | 69 +- c++/include/objects/id2/ID2_Reply_Data.hpp | 107 + c++/include/objects/id2/id2processor.hpp | 53 +- .../objects/id2/id2processor_interface.hpp | 4 +- .../objects/macro/Location_constraint.hpp | 4 +- c++/include/objects/macro/Search_func.hpp | 27 +- .../objects/macro/String_constraint.hpp | 34 +- c++/include/objects/macro/Suspect_rule.hpp | 23 +- .../objects/misc/sequence_util_macros.hpp | 8 +- c++/include/objects/pub/Pub.hpp | 3 +- c++/include/objects/seq/Seq_inst.hpp | 2 +- c++/include/objects/seq/seq_id_handle.hpp | 4 +- .../objects/seq/seq_loc_mapper_base.hpp | 31 +- c++/include/objects/seq/so_map.hpp | 127 + c++/include/objects/seq/sofa_map.hpp | 11 +- c++/include/objects/seqalign/Dense_seg.hpp | 4 +- c++/include/objects/seqalign/Seq_align.hpp | 6 +- c++/include/objects/seqfeat/BioSource.hpp | 5 +- c++/include/objects/seqfeat/Gb_qual.hpp | 6 +- .../objects/seqfeat/Genetic_code_table.hpp | 13 +- c++/include/objects/seqfeat/OrgMod.hpp | 14 +- c++/include/objects/seqfeat/OrgName.hpp | 25 +- c++/include/objects/seqfeat/Org_ref.hpp | 47 +- c++/include/objects/seqfeat/RNA_gen.hpp | 5 +- c++/include/objects/seqfeat/SeqFeatData.hpp | 15 +- c++/include/objects/seqfeat/Seq_feat.hpp | 2 +- c++/include/objects/seqfeat/SubSource.hpp | 7 +- c++/include/objects/seqloc/Seq_id.hpp | 23 +- c++/include/objects/seqloc/Seq_loc.hpp | 6 +- c++/include/objects/seqset/Bioseq_set.hpp | 2 +- c++/include/objects/taxon1/taxon1.hpp | 129 +- c++/include/objects/taxon3/T3Data.hpp | 5 +- c++/include/objects/taxon3/itaxon3.hpp | 41 +- c++/include/objects/taxon3/taxon3.hpp | 48 +- .../objects/trackmgr/gridrpcclient.hpp | 8 +- c++/include/objects/trackmgr/primary_snp.hpp | 76 + .../objects/trackmgr/trackmgr_client.hpp | 17 +- c++/include/objects/valerr/ValidErrItem.hpp | 17 +- c++/include/objects/valerr/ValidError.hpp | 6 +- c++/include/objmgr/align_ci.hpp | 14 +- c++/include/objmgr/annot_selector.hpp | 24 +- c++/include/objmgr/annot_types_ci.hpp | 29 +- c++/include/objmgr/data_loader.hpp | 9 +- c++/include/objmgr/feat_ci.hpp | 14 +- c++/include/objmgr/graph_ci.hpp | 14 +- c++/include/objmgr/impl/annot_collector.hpp | 8 +- .../objmgr/impl/annot_object_index.hpp | 2 +- c++/include/objmgr/impl/bioseq_set_info.hpp | 15 +- c++/include/objmgr/impl/data_source.hpp | 7 +- c++/include/objmgr/impl/scope_impl.hpp | 5 +- c++/include/objmgr/impl/scope_info.hpp | 39 +- c++/include/objmgr/impl/seq_entry_info.hpp | 2 +- c++/include/objmgr/impl/seq_table_setters.hpp | 2 +- .../objmgr/impl/seq_vector_cvt_gen.hpp | 2 +- c++/include/objmgr/impl/tse_assigner.hpp | 14 +- c++/include/objmgr/impl/tse_chunk_info.hpp | 39 +- c++/include/objmgr/impl/tse_info.hpp | 3 +- c++/include/objmgr/impl/tse_info_object.hpp | 2 +- c++/include/objmgr/impl/tse_split_info.hpp | 7 +- c++/include/objmgr/objmgr_exception.hpp | 5 +- c++/include/objmgr/seq_entry_ci.hpp | 10 +- c++/include/objmgr/seq_loc_mapper.hpp | 18 +- c++/include/objmgr/seq_vector_ci.hpp | 4 +- c++/include/objmgr/split/size.hpp | 2 +- c++/include/objmgr/tse_handle.hpp | 5 +- c++/include/objmgr/util/autodef.hpp | 344 + .../util}/autodef_available_modifier.hpp | 8 +- .../util}/autodef_feature_clause.hpp | 10 +- .../util}/autodef_feature_clause_base.hpp | 12 +- .../util}/autodef_mod_combo.hpp | 16 +- c++/include/objmgr/util/autodef_options.hpp | 291 + .../objmgr/util/autodef_source_desc.hpp | 159 + .../util}/autodef_source_group.hpp | 12 +- c++/include/objmgr/util/create_defline.hpp | 55 +- c++/include/objmgr/util/feature_edit.hpp | 90 + c++/include/objmgr/util/indexer.hpp | 856 + c++/include/objmgr/util/obj_sniff.hpp | 2 +- c++/include/objmgr/util/objutil.hpp | 67 +- c++/include/objmgr/util/seq_align_util.hpp | 9 +- c++/include/objmgr/util/sequence.hpp | 26 +- .../align_format/align_format_util.hpp | 223 +- .../objtools/align_format/format_flags.hpp | 2 +- .../objtools/align_format/showalign.hpp | 10 +- .../objtools/align_format/showdefline.hpp | 26 +- c++/include/objtools/align_format/tabular.hpp | 16 +- .../objtools/align_format/taxFormat.hpp | 4 +- c++/include/objtools/alnmgr/aln_stats.hpp | 8 +- c++/include/objtools/alnmgr/alnmatch.hpp | 4 +- c++/include/objtools/alnmgr/pairwise_aln.hpp | 5 +- .../objtools/alnmgr/seqids_extractor.hpp | 8 +- c++/include/objtools/alnmgr/sparse_aln.hpp | 2 +- .../blastdb_format/blastdb_dataextract.hpp | 2 +- .../blast/blastdb_format/seq_writer.hpp | 2 +- .../blast/seqdb_reader/impl/seqdbatlas.hpp | 1849 +- .../blast/seqdb_reader/impl/seqdbcol.hpp | 62 +- .../blast/seqdb_reader/impl/seqdbfile.hpp | 242 +- .../blast/seqdb_reader/impl/seqdbgeneral.hpp | 2 +- .../blast/seqdb_reader/impl/seqdbisam.hpp | 313 +- .../blast/seqdb_reader/impl/seqdbtax.hpp | 81 +- .../blast/seqdb_reader/impl/seqdbvol.hpp | 106 +- .../objtools/blast/seqdb_reader/seqdb.hpp | 84 +- .../blast/seqdb_reader/seqdbcommon.hpp | 95 +- .../objtools/blast/seqdb_writer/build_db.hpp | 2 +- .../blast/seqdb_writer/impl/criteria.hpp | 2 +- .../objtools/blast/seqdb_writer/writedb.hpp | 2 +- .../blast/seqdb_writer/writedb_files.hpp | 8 +- c++/include/objtools/cleanup/cleanup.hpp | 49 +- .../objtools/cleanup/cleanup_change.hpp | 3 +- c++/include/objtools/cleanup/newcleanup.hpp | 2 +- .../data_loaders/blastdb/blastdb_adapter.hpp | 4 +- .../data_loaders/genbank/gbloader.hpp | 50 +- .../genbank/impl/reader_id2_base.hpp | 23 +- .../objtools/data_loaders/genbank/reader.hpp | 4 +- .../data_loaders/genbank/reader_interface.hpp | 4 +- .../genbank/readers/id2/reader_id2.hpp | 2 +- c++/include/objtools/edit/autodef.hpp | 312 +- c++/include/objtools/edit/autodef_options.hpp | 259 +- .../objtools/edit/autodef_source_desc.hpp | 127 +- .../autodef_with_tax.hpp} | 51 +- c++/include/objtools/edit/feattable_edit.hpp | 42 +- c++/include/objtools/edit/field_handler.hpp | 6 +- c++/include/objtools/edit/gap_trim.hpp | 156 + c++/include/objtools/edit/gaps_edit.hpp | 2 +- c++/include/objtools/edit/loc_edit.hpp | 8 +- c++/include/objtools/edit/mail_report.hpp | 2 +- c++/include/objtools/edit/rna_edit.hpp | 2 +- c++/include/objtools/edit/seq_entry_edit.hpp | 5 +- c++/include/objtools/edit/source_edit.hpp | 5 +- .../objtools/edit/string_constraint.hpp | 2 +- c++/include/objtools/error_codes.hpp | 3 +- c++/include/objtools/format/context.hpp | 19 +- .../objtools/format/flat_file_config.hpp | 104 +- .../objtools/format/flat_file_generator.hpp | 5 +- c++/include/objtools/format/gather_items.hpp | 8 +- .../objtools/format/gff3_formatter.hpp | 172 - c++/include/objtools/format/gff_formatter.hpp | 139 - .../objtools/format/items/feature_item.hpp | 26 +- .../objtools/format/items/flat_qual_slots.hpp | 2 +- .../objtools/format/items/flat_seqloc.hpp | 21 +- .../objtools/format/items/item_base.hpp | 25 +- .../objtools/format/items/reference_item.hpp | 4 +- c++/include/objtools/format/text_ostream.hpp | 4 +- .../objtools/readers/agp_converter.hpp | 4 +- c++/include/objtools/readers/agp_util.hpp | 4 +- c++/include/objtools/readers/aln_reader.hpp | 57 +- c++/include/objtools/readers/bed_reader.hpp | 6 +- c++/include/objtools/readers/fasta.hpp | 105 +- .../objtools/readers/fasta_reader_utils.hpp | 220 + c++/include/objtools/readers/gff2_data.hpp | 33 +- c++/include/objtools/readers/gff2_reader.hpp | 95 +- c++/include/objtools/readers/gff3_reader.hpp | 5 +- c++/include/objtools/readers/gff3_sofa.hpp | 2 +- c++/include/objtools/readers/gtf_reader.hpp | 63 +- c++/include/objtools/readers/gvf_reader.hpp | 2 +- c++/include/objtools/readers/line_error.hpp | 5 +- .../objtools/readers/microarray_reader.hpp | 2 +- c++/include/objtools/readers/reader_base.hpp | 10 +- .../objtools/readers/reader_exception.hpp | 6 +- c++/include/objtools/readers/reader_idgen.hpp | 4 +- c++/include/objtools/readers/readfeat.hpp | 3 +- .../objtools/readers/source_mod_parser.hpp | 56 +- .../objtools/readers/struct_cmt_reader.hpp | 54 +- c++/include/objtools/readers/track_data.hpp | 2 +- c++/include/objtools/readers/vcf_reader.hpp | 14 +- .../objtools/readers/wiggle_reader.hpp | 2 +- .../objtools/seqmasks_io/mask_bdb_reader.hpp | 3 +- .../seqmasks_io/mask_fasta_reader.hpp | 4 +- c++/include/serial/impl/enumerated.hpp | 2 +- c++/include/serial/impl/objectio.inl | 7 +- c++/include/serial/impl/objistrasnb.inl | 4 +- c++/include/serial/impl/objstack.hpp | 9 +- c++/include/serial/impl/objstrasnb.hpp | 3 +- c++/include/serial/impl/objstrasnb.inl | 9 +- c++/include/serial/impl/stltypes.hpp | 3 +- c++/include/serial/objectio.hpp | 6 +- c++/include/serial/objhook.hpp | 22 +- c++/include/serial/objistrasn.hpp | 20 +- c++/include/serial/objistrjson.hpp | 12 +- c++/include/serial/objistrxml.hpp | 11 +- c++/include/serial/objostrasn.hpp | 12 +- c++/include/serial/objostrjson.hpp | 6 +- c++/include/serial/objostrxml.hpp | 6 +- c++/include/serial/rpcbase.hpp | 16 +- c++/include/serial/rpcbase_impl.hpp | 9 +- c++/include/serial/serialbase.hpp | 5 +- c++/include/serial/serialdef.hpp | 10 +- c++/include/serial/streamiter.hpp | 1656 +- c++/include/serial/typeinfo.hpp | 9 +- c++/include/util/bitset/bm.h | 122 +- c++/include/util/bitset/bmalgo_impl.h | 76 +- c++/include/util/bitset/bmalloc.h | 15 +- c++/include/util/bitset/bmblocks.h | 103 +- c++/include/util/bitset/bmconst.h | 8 +- c++/include/util/bitset/bmdbg.h | 46 +- c++/include/util/bitset/bmdef.h | 42 +- c++/include/util/bitset/bmfunc.h | 184 +- c++/include/util/bitset/bmgamma.h | 7 + c++/include/util/bitset/bmserial.h | 130 +- c++/include/util/bitset/bmsparsevec.h | 721 + c++/include/util/bitset/bmsparsevec_algo.h | 142 + c++/include/util/bitset/bmsparsevec_serial.h | 324 + c++/include/util/bitset/bmsse2.h | 10 +- c++/include/util/bitset/bmsse4.h | 22 +- c++/include/util/bitset/bmsse_util.h | 14 +- c++/include/util/bitset/bmtrans.h | 1 + c++/include/util/bitset/bmundef.h | 2 - c++/include/util/bitset/encoding.h | 75 +- c++/include/util/bitset/ncbi_bitset.hpp | 19 +- c++/include/util/bytesrc.hpp | 7 +- c++/include/util/cache/icache.hpp | 12 +- c++/include/util/compress/archive.hpp | 28 +- c++/include/util/compress/bzip2.hpp | 9 +- c++/include/util/compress/compress.hpp | 27 +- c++/include/util/compress/lzo.hpp | 63 +- c++/include/util/compress/reader_zlib.hpp | 24 +- c++/include/util/compress/stream.hpp | 83 +- c++/include/util/compress/tar.hpp | 65 +- c++/include/util/compress/zlib.hpp | 42 +- c++/include/util/distribution.hpp | 36 +- c++/include/util/format_guess.hpp | 11 +- c++/include/util/mutex_pool.hpp | 20 +- c++/include/util/ncbi_cache.hpp | 4 +- c++/include/util/rangelist.hpp | 50 +- c++/include/util/row_reader.hpp | 2053 +++ c++/include/util/row_reader.inl | 782 + c++/include/util/row_reader_base.hpp | 223 + .../util/row_reader_char_delimited.hpp | 174 + c++/include/util/row_reader_excel_csv.hpp | 372 + c++/include/util/row_reader_iana_csv.hpp | 361 + c++/include/util/row_reader_iana_tsv.hpp | 328 + c++/include/util/row_reader_ncbi_tsv.hpp | 218 + c++/include/util/static_set.hpp | 8 +- c++/include/util/strbuffer.inl | 10 +- c++/include/util/stream_source.hpp | 16 +- c++/include/util/sync_queue.hpp | 4 +- c++/include/util/text_joiner.hpp | 8 +- c++/include/util/util_misc.hpp | 9 +- c++/scripts/common/add_vdb.sh | 2 +- c++/scripts/common/check/check_add.sh | 2 +- c++/scripts/common/check/check_make_cfg.sh | 28 +- c++/scripts/common/check/check_make_unix.sh | 29 +- c++/scripts/common/check/check_run.sh | 4 +- .../common/check/inspxe-suppressions/_vs.sup | 48 +- .../check/inspxe-suppressions/connect.sup | 11 + .../common/check/inspxe-suppressions/misc.sup | 10 - .../common/impl/define_random_macros.sh | 13 + .../common/impl/generate_all_objects.sh | 8 +- c++/scripts/common/impl/install.sh | 2 +- c++/scripts/common/impl/ncbicxx_build_info.py | 389 + .../common/impl/update_configurable.sh | 2 +- c++/scripts/common/impl/yaml.py | 110 + c++/scripts/common/project_utilits.js | 6 +- c++/scripts/projects/blast/Manifest | 9 +- c++/scripts/projects/blast/components.link | 16 +- .../blast/post_build/make_installers.py | 4 +- .../projects/blast/post_build/rpm/make_rpm.py | 4 +- .../blast/post_build/rpm/ncbi-blast.spec | 83 +- .../projects/blast/post_build/win/make_win.py | 6 +- .../blast/post_build/win/ncbi-blast.nsi | 4 + c++/scripts/projects/blast/project.lst | 5 + c++/scripts/projects/clog.lst | 10 + c++/scripts/projects/cobalt/ChangeLog | 8 + c++/scripts/projects/cobalt/LICENSE | 1 + c++/scripts/projects/cobalt/Manifest | 24 +- c++/scripts/projects/cobalt/components.link | 17 +- .../projects/cobalt/post_build/blast_utils.py | 128 + .../macosx/large-Blue_ncbi_logo.tiff | Bin 0 -> 5536538 bytes .../cobalt/post_build/macosx/ncbi-cobalt.sh | 86 + .../macosx/uninstall_ncbi_cobalt.zip | Bin 0 -> 58655 bytes .../cobalt/post_build/macosx/welcome.txt | 6 + .../cobalt/post_build/make_installers.py | 92 + .../cobalt/post_build/rpm/make_rpm.py | 173 + .../cobalt/post_build/rpm/ncbi-cobalt.spec | 43 + .../cobalt/post_build/win/EnvVarUpdate.nsh | 568 + .../cobalt/post_build/win/make_win.py | 84 + .../cobalt/post_build/win/ncbi-cobalt.nsi | 94 + .../cobalt/post_build/win/ncbilogo.ico | Bin 0 -> 25214 bytes .../cobalt/post_build/win/unix2dos.nsh | 56 + c++/scripts/projects/cobalt/project.lst | 5 + c++/scripts/projects/connect.lst | 2 + c++/scripts/projects/datatool/ChangeLog | 8 + c++/scripts/projects/datatool/Manifest | 12 +- c++/scripts/projects/datatool/components.link | 4 +- c++/scripts/projects/dbapi.lst | 1 + c++/scripts/projects/dispatcher/Manifest | 21 +- c++/scripts/projects/dispatcher/README | 2 +- c++/scripts/projects/dispatcher/project.lst | 27 +- c++/scripts/projects/igblast/ChangeLog | 16 +- c++/scripts/projects/igblast/Manifest | 13 +- c++/scripts/projects/igblast/README | 102 +- c++/scripts/projects/igblast/components.link | 16 +- .../projects/igblast/edit_imgt_file.pl | 22 + .../igblast/post_build/macosx/ncbi-igblast.sh | 6 +- .../igblast/post_build/make_installers.py | 5 +- .../igblast/post_build/rpm/ncbi-igblast.spec | 2 +- .../igblast/post_build/win/make_win.py | 7 +- .../igblast/post_build/win/ncbi-blast.nsi | 3 + c++/scripts/projects/igblast/project.lst | 11 + c++/scripts/projects/magicblast/ChangeLog | 13 +- c++/scripts/projects/magicblast/Manifest | 4 +- c++/scripts/projects/magicblast/README | 18 +- .../projects/magicblast/components.link | 16 +- .../post_build/macosx/ncbi-magicblast.sh | 6 +- .../magicblast/post_build/make_installers.py | 4 +- .../magicblast/post_build/win/make_win.py | 7 +- .../magicblast/post_build/win/ncbi-blast.nsi | 2 + c++/scripts/projects/magicblast/project.lst | 10 + c++/scripts/projects/ncbi_applog/ChangeLog | 5 + c++/scripts/projects/ncbi_applog/Manifest | 14 +- c++/scripts/projects/ncbi_cpp.lst | 1 + c++/scripts/projects/ncbi_cpp_dll.lst | 1 + c++/scripts/projects/ncbi_gui_base.lst | 2 + c++/scripts/projects/netcache/ChangeLog | 54 +- c++/scripts/projects/netcache/Manifest | 16 +- c++/scripts/projects/netcache/README | 5 + c++/scripts/projects/netcache/components.link | 6 +- c++/scripts/projects/netschedule/ChangeLog | 27 + c++/scripts/projects/netschedule/project.lst | 10 +- c++/scripts/projects/netstorage/Manifest | 5 +- c++/scripts/projects/netstorage/project.lst | 2 + .../projects/netstorage_gc/project.lst | 1 + .../projects/project_tree_builder/ChangeLog | 11 + .../projects/project_tree_builder/Manifest | 4 +- c++/scripts/projects/public/Manifest | 4 +- c++/scripts/projects/public/project.lst | 4 - .../projects/python_ncbi_dbapi/ChangeLog | 13 + .../python_ncbi_dbapi/components.link | 6 +- .../projects/python_ncbi_dbapi/project.lst | 1 + c++/scripts/projects/test_ccpp_read/ChangeLog | 6 + c++/scripts/projects/test_ccpp_read/Manifest | 8 +- .../projects/test_ccpp_read/project.lst | 6 +- .../projects/testres-testapp/ChangeLog | 1 + c++/scripts/projects/testres-testapp/LICENSE | 19 + c++/scripts/projects/testres-testapp/Manifest | 24 + c++/scripts/projects/testres-testapp/README | 2 + .../projects/testres-testapp/components.link | 6 + .../projects/testres-testapp/project.lst | 16 + .../projects/testres-testcgi/ChangeLog | 1 + c++/scripts/projects/testres-testcgi/LICENSE | 19 + c++/scripts/projects/testres-testcgi/Manifest | 24 + c++/scripts/projects/testres-testcgi/README | 9 + .../projects/testres-testcgi/components.link | 6 + .../projects/testres-testcgi/project.lst | 16 + c++/scripts/projects/xmlwrapp/Manifest | 15 +- c++/scripts/projects/xmlwrapp/project.lst | 1 + c++/src/CMakeLists.txt | 40 + c++/src/Makefile.in | 2 +- c++/src/algo/CMakeLists.txt | 24 + c++/src/algo/blast/CMakeLists.txt | 19 + c++/src/algo/blast/Makefile.blast_macros.mk | 9 +- c++/src/algo/blast/Makefile.in | 6 +- c++/src/algo/blast/api/CMakeLists.txt | 7 + .../algo/blast/api/CMakeLists.xblast.lib.txt | 91 + c++/src/algo/blast/api/Makefile.xblast.lib | 8 +- .../blast/api/bioseq_extract_data_priv.hpp | 2 +- c++/src/algo/blast/api/bl2seq.cpp | 4 +- c++/src/algo/blast/api/blast_aux.cpp | 3 +- c++/src/algo/blast/api/blast_aux_priv.cpp | 13 +- c++/src/algo/blast/api/blast_aux_priv.hpp | 12 +- c++/src/algo/blast/api/blast_dbindex.cpp | 5 +- c++/src/algo/blast/api/blast_objmgr_priv.hpp | 2 +- .../algo/blast/api/blast_options_builder.cpp | 2 +- c++/src/algo/blast/api/blast_options_cxx.cpp | 98 + .../algo/blast/api/blast_options_handle.cpp | 15 +- .../blast/api/blast_options_local_priv.cpp | 8 + .../blast/api/blast_options_local_priv.hpp | 112 +- c++/src/algo/blast/api/blast_results.cpp | 17 +- c++/src/algo/blast/api/blast_seqalign.cpp | 21 +- c++/src/algo/blast/api/blast_seqalign.hpp | 4 +- .../algo/blast/api/blast_seqinfosrc_aux.cpp | 2 +- c++/src/algo/blast/api/blast_setup.hpp | 2 +- .../algo/blast/api/blastp_kmer_options.cpp | 59 + c++/src/algo/blast/api/magicblast.cpp | 372 +- c++/src/algo/blast/api/magicblast_options.cpp | 16 +- c++/src/algo/blast/api/msa_pssm_input.cpp | 8 +- .../algo/blast/api/prelim_search_runner.hpp | 2 +- c++/src/algo/blast/api/prelim_stage.cpp | 16 +- c++/src/algo/blast/api/remote_blast.cpp | 4 +- c++/src/algo/blast/api/seedtop.cpp | 4 +- c++/src/algo/blast/api/seqinfosrc_seqdb.cpp | 5 - c++/src/algo/blast/api/seqsrc_seqdb.cpp | 2 +- c++/src/algo/blast/api/setup_factory.cpp | 22 +- .../algo/blast/api/split_query_aux_priv.cpp | 4 +- .../algo/blast/api/split_query_aux_priv.hpp | 4 +- c++/src/algo/blast/api/traceback_stage.cpp | 1 - c++/src/algo/blast/api/uniform_search.cpp | 25 +- .../blastinput/CMakeLists.blastinput.lib.txt | 18 + c++/src/algo/blast/blastinput/CMakeLists.txt | 10 + .../blast/blastinput/Makefile.blastinput.lib | 2 +- c++/src/algo/blast/blastinput/blast_args.cpp | 298 +- .../blast/blastinput/blast_asn1_input.cpp | 273 +- .../blast/blastinput/blast_fasta_input.cpp | 618 +- c++/src/algo/blast/blastinput/blast_input.cpp | 36 +- .../algo/blast/blastinput/blast_input_aux.cpp | 36 +- .../algo/blast/blastinput/cmdline_flags.cpp | 19 +- .../algo/blast/blastinput/igblastn_args.cpp | 27 +- .../algo/blast/blastinput/igblastp_args.cpp | 17 +- .../algo/blast/blastinput/kblastp_args.cpp | 30 +- .../algo/blast/blastinput/magicblast_args.cpp | 100 +- .../algo/blast/blastinput/psiblast_args.cpp | 2 +- .../algo/blast/blastinput/rpsblast_args.cpp | 22 +- .../CMakeLists.blastinput_unit_test.app.txt | 15 + .../blast/blastinput/unit_test/CMakeLists.txt | 8 + .../unit_test/blast_input_unit_test_aux.hpp | 9 +- .../unit_test/blast_scope_src_unit_test.cpp | 4 +- .../unit_test/blastinput_unit_test.cpp | 446 +- .../unit_test/blastinput_unit_test.ini | 1 + .../unit_test/data/paired_reads.fastc | 6 + .../CMakeLists.composition_adjustment.lib.txt | 12 + .../composition_adjustment/CMakeLists.txt | 7 + .../algo/blast/core/CMakeLists.blast.lib.txt | 14 + .../algo/blast/core/CMakeLists.blast.objs.txt | 65 + c++/src/algo/blast/core/CMakeLists.txt | 7 + c++/src/algo/blast/core/Makefile.blast.lib | 4 +- c++/src/algo/blast/core/blast_engine.c | 18 +- c++/src/algo/blast/core/blast_filter.c | 10 +- c++/src/algo/blast/core/blast_gapalign.c | 23 +- c++/src/algo/blast/core/blast_hits.c | 50 +- c++/src/algo/blast/core/blast_kappa.c | 2 +- c++/src/algo/blast/core/blast_lookup.c | 107 +- c++/src/algo/blast/core/blast_nalookup.c | 676 +- c++/src/algo/blast/core/blast_options.c | 36 +- c++/src/algo/blast/core/blast_parameters.c | 6 +- c++/src/algo/blast/core/blast_query_info.c | 2 +- c++/src/algo/blast/core/blast_seg.c | 2 +- c++/src/algo/blast/core/blast_traceback.c | 5 +- .../algo/blast/core/blast_traceback_mt_priv.c | 4 +- c++/src/algo/blast/core/blast_util.c | 2 +- c++/src/algo/blast/core/hspfilter_culling.c | 19 +- c++/src/algo/blast/core/hspfilter_mapper.c | 734 +- c++/src/algo/blast/core/jumper.c | 577 +- c++/src/algo/blast/core/jumper.h | 34 +- c++/src/algo/blast/core/lookup_wrap.c | 31 +- c++/src/algo/blast/core/na_ungapped.c | 26 +- c++/src/algo/blast/core/spliced_hits.c | 188 + c++/src/algo/blast/dbindex/CMakeLists.txt | 9 + .../CMakeLists.xalgoblastdbindex.lib.txt | 15 + c++/src/algo/blast/dbindex/dbindex.cpp | 4 +- .../algo/blast/dbindex/dbindex_factory.cpp | 4 +- .../makeindex/CMakeLists.makeindex.app.txt | 13 + .../blast/dbindex/makeindex/CMakeLists.txt | 7 + .../blast/dbindex/sequence_istream_fasta.cpp | 6 +- c++/src/algo/blast/format/CMakeLists.txt | 7 + .../format/CMakeLists.xblastformat.lib.txt | 15 + .../blast/format/Makefile.xblastformat.lib | 4 +- .../algo/blast/format/blast_async_format.cpp | 133 + c++/src/algo/blast/format/blast_format.cpp | 4 +- .../blast/igblast/CMakeLists.igblast.lib.txt | 13 + c++/src/algo/blast/igblast/CMakeLists.txt | 7 + c++/src/algo/blast/igblast/igblast.cpp | 426 +- .../CMakeLists.proteinkmer.lib.txt | 13 + c++/src/algo/blast/proteinkmer/CMakeLists.txt | 7 + c++/src/algo/blast/proteinkmer/Makefile.in | 10 + .../proteinkmer/Makefile.proteinkmer.lib | 13 + c++/src/algo/blast/proteinkmer/blastkmer.cpp | 382 + .../algo/blast/proteinkmer/blastkmerindex.cpp | 749 + .../blast/proteinkmer/blastkmeroptions.cpp} | 43 +- .../blast/proteinkmer/blastkmerresults.cpp | 188 + .../algo/blast/proteinkmer/blastkmerutils.cpp | 938 + c++/src/algo/blast/proteinkmer/kblastapi.cpp | 255 + c++/src/algo/blast/proteinkmer/mhfile.cpp | 173 + c++/src/algo/blast/proteinkmer/pearson.cpp | 99 + c++/src/algo/blast/proteinkmer/pearson.hpp | 72 + .../blast/proteinkmer/unit_test/Makefile.in | 13 + .../Makefile.proteinkmer_unit_test.app | 31 + .../proteinkmer/unit_test/data/129295.fsa | 4 + .../proteinkmer/unit_test/data/129295.iupacaa | 28 + .../proteinkmer/unit_test/data/129295.ncbieaa | 28 + .../proteinkmer/unit_test/data/129295.stdaa | 31 + .../proteinkmer/unit_test/data/129296.ncbieaa | 19 + .../unit_test/data/XP_001468867.phr | Bin 0 -> 124 bytes .../unit_test/data/XP_001468867.pin | Bin 0 -> 88 bytes .../unit_test/data/XP_001468867.pnd | Bin 0 -> 8 bytes .../unit_test/data/XP_001468867.pni | Bin 0 -> 52 bytes .../unit_test/data/XP_001468867.pog | Bin 0 -> 36 bytes .../unit_test/data/XP_001468867.psd | 2 + .../unit_test/data/XP_001468867.psi | Bin 0 -> 67 bytes .../unit_test/data/XP_001468867.psq | Bin 0 -> 5969 bytes .../blast/proteinkmer/unit_test/data/allX.asn | 23 + .../blast/proteinkmer/unit_test/data/bad.asn | 22 + .../proteinkmer/unit_test/data/manyXs.phr | Bin 0 -> 65 bytes .../proteinkmer/unit_test/data/manyXs.pin | Bin 0 -> 80 bytes .../proteinkmer/unit_test/data/manyXs.pog | Bin 0 -> 36 bytes .../proteinkmer/unit_test/data/manyXs.psd | 2 + .../proteinkmer/unit_test/data/manyXs.psi | Bin 0 -> 70 bytes .../proteinkmer/unit_test/data/manyXs.psq | Bin 0 -> 82 bytes .../proteinkmer/unit_test/data/nr_test.phr | Bin 0 -> 840 bytes .../proteinkmer/unit_test/data/nr_test.pin | Bin 0 -> 120 bytes .../proteinkmer/unit_test/data/nr_test.pkd | Bin 0 -> 1156 bytes .../proteinkmer/unit_test/data/nr_test.pki | Bin 0 -> 134220152 bytes .../proteinkmer/unit_test/data/nr_test.pnd | Bin 0 -> 48 bytes .../proteinkmer/unit_test/data/nr_test.pni | Bin 0 -> 52 bytes .../proteinkmer/unit_test/data/nr_test.pog | Bin 0 -> 56 bytes .../proteinkmer/unit_test/data/nr_test.psd | 14 + .../proteinkmer/unit_test/data/nr_test.psi | Bin 0 -> 63 bytes .../proteinkmer/unit_test/data/nr_test.psq | Bin 0 -> 2191 bytes .../unit_test/proteinkmer_unit_test.cpp | 1155 ++ c++/src/algo/blast/unit_tests/CMakeLists.txt | 12 + .../api/CMakeLists.aalookup_unit_test.app.txt | 15 + .../api/CMakeLists.aascan_unit_test.app.txt | 15 + .../api/CMakeLists.bl2seq_unit_test.app.txt | 15 + .../api/CMakeLists.blast_unit_test.app.txt | 15 + .../CMakeLists.blast_unit_test_util.lib.txt | 17 + .../CMakeLists.blastdiag_unit_test.app.txt | 14 + .../CMakeLists.blastengine_unit_test.app.txt | 15 + .../CMakeLists.blastextend_unit_test.app.txt | 15 + .../CMakeLists.blastfilter_unit_test.app.txt | 15 + .../CMakeLists.blasthits_unit_test.app.txt | 17 + .../CMakeLists.blastoptions_unit_test.app.txt | 15 + .../CMakeLists.blastsetup_unit_test.app.txt | 15 + .../api/CMakeLists.delta_unit_test.app.txt | 15 + .../api/CMakeLists.gapinfo_unit_test.app.txt | 15 + ...eLists.gencode_singleton_unit_test.app.txt | 15 + ...eLists.hspfilter_besthit_unit_test.app.txt | 15 + ...eLists.hspfilter_culling_unit_test.app.txt | 15 + .../CMakeLists.hspstream_unit_test.app.txt | 15 + .../api/CMakeLists.linkhsp_unit_test.app.txt | 15 + .../CMakeLists.magicblast_unit_test.app.txt | 9 + .../api/CMakeLists.msa2pssm_unit_test.app.txt | 15 + .../api/CMakeLists.ntlookup_unit_test.app.txt | 15 + .../api/CMakeLists.ntscan_unit_test.app.txt | 15 + ...CMakeLists.optionshandle_unit_test.app.txt | 15 + .../api/CMakeLists.phiblast_unit_test.app.txt | 15 + .../CMakeLists.prelimsearch_unit_test.app.txt | 15 + .../CMakeLists.psibl2seq_unit_test.app.txt | 15 + ...Lists.psiblast_iteration_unit_test.app.txt | 15 + .../api/CMakeLists.psiblast_unit_test.app.txt | 15 + .../CMakeLists.pssmcreate_unit_test.app.txt | 15 + ...sts.pssmenginefreqratios_unit_test.app.txt | 15 + .../CMakeLists.querydata_unit_test.app.txt | 15 + .../CMakeLists.queryinfo_unit_test.app.txt | 15 + ...CMakeLists.redoalignment_unit_test.app.txt | 15 + .../CMakeLists.remote_blast_unit_test.app.txt | 15 + .../api/CMakeLists.rps_unit_test.app.txt | 15 + .../api/CMakeLists.scoreblk_unit_test.app.txt | 15 + ...akeLists.search_strategy_unit_test.app.txt | 15 + .../api/CMakeLists.seqalign_util.lib.txt | 13 + .../CMakeLists.seqinfosrc_unit_test.app.txt | 15 + .../api/CMakeLists.seqsrc_unit_test.app.txt | 15 + .../CMakeLists.setupfactory_unit_test.app.txt | 15 + .../CMakeLists.split_query_unit_test.app.txt | 15 + .../api/CMakeLists.stat_unit_test.app.txt | 9 + .../CMakeLists.subj_ranges_unit_test.app.txt | 15 + .../CMakeLists.traceback_unit_test.app.txt | 15 + ...akeLists.tracebacksearch_unit_test.app.txt | 15 + .../algo/blast/unit_tests/api/CMakeLists.txt | 57 + ...MakeLists.uniform_search_unit_test.app.txt | 15 + ...eLists.version_reference_unit_test.app.txt | 15 + .../api/Makefile.bl2seq_unit_test.app | 4 +- .../api/Makefile.gapinfo_unit_test.app | 4 +- .../blast/unit_tests/api/bl2seq_unit_test.ini | 6 +- .../unit_tests/api/blastengine_unit_test.cpp | 19 +- .../unit_tests/api/blastfilter_unit_test.ini | 5 +- .../unit_tests/api/blasthits_unit_test.cpp | 2 +- .../unit_tests/api/blastoptions_unit_test.cpp | 4 +- .../unit_tests/api/blastsetup_unit_test.cpp | 2 +- .../blast/unit_tests/api/delta_unit_test.cpp | 34 +- .../unit_tests/api/magicblast_unit_test.cpp | 77 +- .../unit_tests/api/magicblast_unit_test.ini | 2 +- .../unit_tests/api/ntlookup_unit_test.cpp | 39 +- .../api/optionshandle_unit_test.cpp | 13 +- .../unit_tests/api/psiblast_unit_test.cpp | 19 +- .../unit_tests/api/subj_ranges_unit_test.cpp | 4 +- .../unit_tests/api/traceback_unit_test.cpp | 2 +- .../api/tracebacksearch_unit_test.cpp | 9 +- .../api/version_reference_unit_test.cpp | 6 +- .../CMakeLists.blast_format_unit_test.app.txt | 16 + .../unit_tests/blast_format/CMakeLists.txt | 9 + .../Makefile.blast_format_unit_test.app | 4 +- .../blast_format/blast_format_unit_test.cpp | 198 + .../blast_format/blastfmtutil_unit_test.cpp | 17 +- .../unit_tests/blast_format/data/archive.asn | 4840 +---- .../CMakeLists.bdbloader_unit_test.app.txt | 15 + .../blast/unit_tests/blastdb/CMakeLists.txt | 9 + .../blastdb/bdbloader_unit_test.cpp | 6 +- .../CMakeLists.seqdb_unit_test.app.txt | 15 + .../unit_tests/seqdb_reader/CMakeLists.txt | 9 + .../seqdb_reader/Makefile.seqdb_unit_test.app | 4 +- .../seqdb_reader/data/empty-mask-data-db.naa | Bin 0 -> 228 bytes .../seqdb_reader/data/empty-mask-data-db.nab | Bin 0 -> 112 bytes .../seqdb_reader/data/empty-mask-data-db.nac | Bin 0 -> 112 bytes .../seqdb_reader/data/empty-mask-data-db.nhr | Bin 0 -> 4172 bytes .../seqdb_reader/data/empty-mask-data-db.nin | Bin 0 -> 428 bytes .../seqdb_reader/data/empty-mask-data-db.nog | Bin 0 -> 144 bytes .../seqdb_reader/data/empty-mask-data-db.nsd | 56 + .../seqdb_reader/data/empty-mask-data-db.nsi | Bin 0 -> 65 bytes .../seqdb_reader/data/empty-mask-data-db.nsq | Bin 0 -> 2011456 bytes .../seqdb_reader/data/testfile1.sqlite | Bin 0 -> 163840 bytes .../seqdb_reader/data/wb1206.gis.txt | 150 - .../seqdb_reader/data/wb1206.long.gis.txt | 550 - .../seqdb_reader/seqdb_unit_test.cpp | 231 +- .../seqdb_reader/seqdb_unit_test.ini | 10 +- c++/src/algo/dustmask/CMakeLists.txt | 7 + .../dustmask/CMakeLists.xalgodustmask.lib.txt | 13 + c++/src/algo/segmask/CMakeLists.txt | 7 + .../segmask/CMakeLists.xalgosegmask.lib.txt | 13 + c++/src/algo/winmask/CMakeLists.txt | 7 + .../winmask/CMakeLists.xalgowinmask.lib.txt | 23 + c++/src/app/CMakeLists.txt | 54 + c++/src/app/Makefile.in | 5 +- .../blast/CMakeLists.blast_app_util.lib.txt | 13 + .../blast/CMakeLists.blast_formatter.app.txt | 13 + c++/src/app/blast/CMakeLists.blastn.app.txt | 13 + c++/src/app/blast/CMakeLists.blastp.app.txt | 13 + c++/src/app/blast/CMakeLists.blastx.app.txt | 13 + .../app/blast/CMakeLists.deltablast.app.txt | 13 + c++/src/app/blast/CMakeLists.legacy_blast.txt | 7 + c++/src/app/blast/CMakeLists.psiblast.app.txt | 13 + c++/src/app/blast/CMakeLists.rpsblast.app.txt | 13 + .../app/blast/CMakeLists.rpstblastn.app.txt | 13 + c++/src/app/blast/CMakeLists.seedtop.app.txt | 13 + c++/src/app/blast/CMakeLists.tblastn.app.txt | 13 + c++/src/app/blast/CMakeLists.tblastx.app.txt | 13 + c++/src/app/blast/CMakeLists.txt | 19 + .../app/blast/CMakeLists.update_blastdb.txt | 8 + .../app/blast/Makefile.blast_formatter.app | 2 +- c++/src/app/blast/Makefile.blastp.app | 4 +- c++/src/app/blast/Makefile.blastx.app | 4 +- c++/src/app/blast/Makefile.deltablast.app | 2 +- c++/src/app/blast/Makefile.psiblast.app | 2 +- c++/src/app/blast/Makefile.rpsblast.app | 2 +- c++/src/app/blast/Makefile.rpstblastn.app | 2 +- c++/src/app/blast/Makefile.seedtop.app | 2 +- c++/src/app/blast/Makefile.tblastn.app | 4 +- c++/src/app/blast/Makefile.tblastx.app | 4 +- c++/src/app/blast/blast_app_util.cpp | 2 +- c++/src/app/blast/blast_app_util.hpp | 7 +- c++/src/app/blast/blast_formatter.cpp | 2 +- c++/src/app/blast/blastn_app.cpp | 4 +- c++/src/app/blast/blastp_app.cpp | 4 +- c++/src/app/blast/blastx_app.cpp | 2 +- c++/src/app/blast/deltablast_app.cpp | 2 +- c++/src/app/blast/psiblast_app.cpp | 2 +- c++/src/app/blast/rpsblast_app.cpp | 2 +- c++/src/app/blast/rpstblastn_app.cpp | 6 +- c++/src/app/blast/tblastn_app.cpp | 2 +- c++/src/app/blast/tblastx_app.cpp | 2 +- .../CMakeLists.blastdb_aliastool.app.txt | 13 + .../blastdb/CMakeLists.blastdbcheck.app.txt | 13 + .../app/blastdb/CMakeLists.blastdbcmd.app.txt | 13 + .../app/blastdb/CMakeLists.blastdbcp.app.txt | 13 + .../CMakeLists.convert2blastmask.app.txt | 13 + .../blastdb/CMakeLists.makeblastdb.app.txt | 13 + .../blastdb/CMakeLists.makeprofiledb.app.txt | 13 + c++/src/app/blastdb/CMakeLists.txt | 13 + c++/src/app/blastdb/blastdb_aliastool.cpp | 4 +- c++/src/app/blastdb/blastdbcheck.cpp | 8 +- c++/src/app/blastdb/blastdbcmd.cpp | 4 +- c++/src/app/blastdb/blastdbcp.cpp | 7 +- c++/src/app/blastdb/makeblastdb.cpp | 2 +- c++/src/app/blastdb/makeprofiledb.cpp | 4 +- .../dustmasker/CMakeLists.dustmasker.app.txt | 17 + c++/src/app/dustmasker/CMakeLists.txt | 7 + c++/src/app/dustmasker/dust_mask_app.cpp | 88 +- .../segmasker/CMakeLists.segmasker.app.txt | 18 + c++/src/app/segmasker/CMakeLists.txt | 7 + c++/src/app/winmasker/CMakeLists.txt | 7 + ...CMakeLists.windowmasker_2.2.22_adapter.txt | 8 + .../winmasker/CMakeLists.winmasker.app.txt | 17 + .../app/winmasker/win_mask_sdust_masker.cpp | 5 +- .../app/winmasker/win_mask_sdust_masker.hpp | 4 +- c++/src/build-system/CMakeLists.txt | 9 + c++/src/build-system/Makefile.app.in | 15 +- .../build-system/Makefile.configurables.real | 8 +- c++/src/build-system/Makefile.dll.in | 18 +- c++/src/build-system/Makefile.in.top | 9 +- c++/src/build-system/Makefile.meta.gmake=yes | 11 +- c++/src/build-system/Makefile.meta.in | 5 +- c++/src/build-system/Makefile.meta_l | 38 +- c++/src/build-system/Makefile.mk.in | 72 +- c++/src/build-system/Makefile.module | 6 +- c++/src/build-system/Makefile.rules.in | 15 +- .../cmake/CMakeChecks.BerkeleyDB.cmake | 19 + .../cmake/CMakeChecks.basic-checks.cmake | 189 + .../cmake/CMakeChecks.boost.cmake | 38 + c++/src/build-system/cmake/CMakeChecks.cmake | 1259 +- .../cmake/CMakeChecks.compiler.cmake | 129 + .../cmake/CMakeChecks.compress.cmake | 34 + .../cmake/CMakeChecks.final-message.cmake | 67 + .../cmake/CMakeChecks.image.cmake | 41 + .../build-system/cmake/CMakeChecks.os.cmake | 48 + .../build-system/cmake/CMakeChecks.pcre.cmake | 22 + .../cmake/CMakeChecks.sqlite3.cmake | 22 + .../cmake/CMakeChecks.wxwidgets.cmake | 52 + .../cmake/CMakeLists.defaults.cmake | 48 - c++/src/build-system/cmake/CMakeMacros.cmake | 304 + .../build-system/cmake/FindBerkeleyDB.cmake | 38 + .../cmake/FindExternalLibrary.cmake | 251 + c++/src/build-system/cmake/FindFTGL.cmake | 146 + c++/src/build-system/cmake/FindLZO.cmake | 43 + c++/src/build-system/cmake/FindMongoCXX.cmake | 46 + c++/src/build-system/cmake/FindMysql.cmake | 73 + c++/src/build-system/cmake/FindOSMesa.cmake | 47 + c++/src/build-system/cmake/FindPCRE.cmake | 33 +- c++/src/build-system/cmake/FindSqlite3.cmake | 105 + .../build-system/cmake/FindwxWidgets.cmake | 1044 ++ c++/src/build-system/cmake/HunterGate.cmake | 529 + .../build-system/cmake/Sqlite3Config.cmake | 25 + c++/src/build-system/cmake/cmake-configure | 522 + c++/src/build-system/cmake/config.cmake.h.in | 948 + .../build-system/cmake/configure-custom.sh | 42 + .../ncbi-berkeleydb-config.cmake | 66 + .../ncbi-defaults/ncbi-ftgl-config.cmake | 43 + .../ncbi-defaults/ncbi-glew-config.cmake | 44 + .../ncbi-defaults/ncbi-gnutls-config.cmake | 48 + .../ncbi-defaults/ncbi-libxml2-config.cmake | 54 + .../ncbi-defaults/ncbi-libxslt-config.cmake | 57 + .../cmake/ncbi-defaults/ncbi-lzo-config.cmake | 44 + .../ncbi-defaults/ncbi-opengl-config.cmake | 55 + .../ncbi-defaults/ncbi-osmesa-config.cmake | 44 + .../cmake/ncbiconf_msvc_site.h.in | 46 + c++/src/build-system/config.h.in | 51 +- c++/src/build-system/configure | 4891 +++-- c++/src/build-system/configure.ac | 727 +- c++/src/build-system/helpers/run_with_lock.c | 2 +- c++/src/build-system/install.sh.in | 10 +- c++/src/build-system/library_relations.txt | 226 +- c++/src/build-system/ncbi_package | 2 +- c++/src/build-system/ncbi_package_name | 2 +- c++/src/build-system/ncbi_package_version | 2 +- c++/src/build-system/new_module.sh.in | 8 +- c++/src/build-system/project_tree_builder.ini | 78 +- .../CMakeLists.project_tree_builder.app.txt | 19 + .../project_tree_builder/CMakeLists.txt | 9 + .../msbuild/CMakeLists.txt | 6 + .../project_tree_builder/msvc_configure.cpp | 69 +- .../project_tree_builder/msvc_configure.hpp | 7 +- .../project_tree_builder/proj_builder_app.cpp | 34 +- .../project_tree_builder/proj_builder_app.hpp | 5 +- .../project_tree_builder/proj_projects.cpp | 5 +- .../project_tree_builder/proj_tree.cpp | 434 +- .../project_tree_builder/proj_tree.hpp | 9 +- .../proj_tree_builder.cpp | 4 +- c++/src/build-system/ptb_version.txt | 2 +- c++/src/build-system/relocate.sh.in | 17 +- .../build-system/run_with_cd_reporter.py.in | 43 + c++/src/cgi/CMakeLists.cgi.lib.txt | 13 + c++/src/cgi/CMakeLists.fcgi.lib.txt | 14 + c++/src/cgi/CMakeLists.txt | 12 + c++/src/cgi/cgi_exception.cpp | 48 +- c++/src/cgi/cgiapp.cpp | 348 +- c++/src/cgi/cgictx.cpp | 82 +- c++/src/cgi/fcgi_run.cpp | 13 +- c++/src/cgi/ncbicgi.cpp | 4 +- c++/src/cgi/ncbires.cpp | 6 +- c++/src/cgi/user_agent.cpp | 2 +- c++/src/connect/CMakeLists.connect.lib.txt | 11 + c++/src/connect/CMakeLists.connssl.lib.txt | 13 + c++/src/connect/CMakeLists.txt | 94 + c++/src/connect/CMakeLists.xconnect.lib.txt | 12 + c++/src/connect/CMakeLists.xthrserv.lib.txt | 9 + c++/src/connect/CMakeLists.xxconnect.lib.txt | 36 + c++/src/connect/Makefile.connect.lib | 6 +- c++/src/connect/Makefile.connect.lib.unix | 5 +- c++/src/connect/Makefile.connssl.lib | 28 +- c++/src/connect/Makefile.connssl.lib.unix | 8 + c++/src/connect/Makefile.in | 4 +- c++/src/connect/Makefile.xconnect.lib | 10 +- c++/src/connect/Makefile.xxconnect.lib | 8 +- c++/src/connect/Makefile.xxconnect.lib.unix | 3 +- c++/src/connect/mbedtls/aes.c | 1492 ++ c++/src/connect/mbedtls/aesni.c | 464 + c++/src/connect/mbedtls/apache-2.0.txt | 202 + c++/src/connect/mbedtls/arc4.c | 205 + c++/src/connect/mbedtls/asn1parse.c | 393 + c++/src/connect/mbedtls/asn1write.c | 390 + c++/src/connect/mbedtls/base64.c | 293 + c++/src/connect/mbedtls/bignum.c | 2447 +++ c++/src/connect/mbedtls/blowfish.c | 656 + c++/src/connect/mbedtls/camellia.c | 1072 ++ c++/src/connect/mbedtls/ccm.c | 464 + c++/src/connect/mbedtls/certs.c | 351 + c++/src/connect/mbedtls/cipher.c | 917 + c++/src/connect/mbedtls/cipher_wrap.c | 1451 ++ c++/src/connect/mbedtls/cmac.c | 1074 ++ c++/src/connect/mbedtls/ctr_drbg.c | 594 + c++/src/connect/mbedtls/debug.c | 368 + c++/src/connect/mbedtls/des.c | 1061 ++ c++/src/connect/mbedtls/dhm.c | 627 + c++/src/connect/mbedtls/ecdh.c | 264 + c++/src/connect/mbedtls/ecdsa.c | 448 + c++/src/connect/mbedtls/ecjpake.c | 1103 ++ c++/src/connect/mbedtls/ecp.c | 2092 +++ c++/src/connect/mbedtls/ecp_curves.c | 1325 ++ c++/src/connect/mbedtls/entropy.c | 655 + c++/src/connect/mbedtls/entropy_poll.c | 268 + c++/src/connect/mbedtls/error.c | 707 + c++/src/connect/mbedtls/gcm.c | 952 + c++/src/connect/mbedtls/havege.c | 245 + c++/src/connect/mbedtls/hmac_drbg.c | 529 + c++/src/connect/mbedtls/mbedtls/aes.h | 297 + c++/src/connect/mbedtls/mbedtls/aesni.h | 111 + c++/src/connect/mbedtls/mbedtls/arc4.h | 113 + c++/src/connect/mbedtls/mbedtls/asn1.h | 342 + c++/src/connect/mbedtls/mbedtls/asn1write.h | 239 + c++/src/connect/mbedtls/mbedtls/base64.h | 88 + c++/src/connect/mbedtls/mbedtls/bignum.h | 717 + c++/src/connect/mbedtls/mbedtls/blowfish.h | 203 + c++/src/connect/mbedtls/mbedtls/bn_mul.h | 885 + c++/src/connect/mbedtls/mbedtls/camellia.h | 235 + c++/src/connect/mbedtls/mbedtls/ccm.h | 141 + c++/src/connect/mbedtls/mbedtls/certs.h | 99 + .../connect/mbedtls/mbedtls/check_config.h | 628 + c++/src/connect/mbedtls/mbedtls/cipher.h | 709 + .../connect/mbedtls/mbedtls/cipher_internal.h | 109 + c++/src/connect/mbedtls/mbedtls/cmac.h | 170 + c++/src/connect/mbedtls/mbedtls/compat-1.3.h | 2633 +++ c++/src/connect/mbedtls/mbedtls/config.h | 2614 +++ c++/src/connect/mbedtls/mbedtls/ctr_drbg.h | 290 + c++/src/connect/mbedtls/mbedtls/debug.h | 228 + c++/src/connect/mbedtls/mbedtls/des.h | 306 + c++/src/connect/mbedtls/mbedtls/dhm.h | 305 + c++/src/connect/mbedtls/mbedtls/ecdh.h | 214 + c++/src/connect/mbedtls/mbedtls/ecdsa.h | 248 + c++/src/connect/mbedtls/mbedtls/ecjpake.h | 238 + c++/src/connect/mbedtls/mbedtls/ecp.h | 669 + c++/src/connect/mbedtls/mbedtls/entropy.h | 287 + .../connect/mbedtls/mbedtls/entropy_poll.h | 109 + c++/src/connect/mbedtls/mbedtls/error.h | 107 + c++/src/connect/mbedtls/mbedtls/gcm.h | 220 + c++/src/connect/mbedtls/mbedtls/havege.h | 74 + c++/src/connect/mbedtls/mbedtls/hmac_drbg.h | 299 + c++/src/connect/mbedtls/mbedtls/md.h | 354 + c++/src/connect/mbedtls/mbedtls/md2.h | 136 + c++/src/connect/mbedtls/mbedtls/md4.h | 136 + c++/src/connect/mbedtls/mbedtls/md5.h | 136 + c++/src/connect/mbedtls/mbedtls/md_internal.h | 114 + .../mbedtls/mbedtls/memory_buffer_alloc.h | 150 + .../mbedtls/mbedtls/ncbicxx_rename_mbedtls.h | 1450 ++ c++/src/connect/mbedtls/mbedtls/net.h | 31 + c++/src/connect/mbedtls/mbedtls/net_sockets.h | 225 + c++/src/connect/mbedtls/mbedtls/oid.h | 570 + c++/src/connect/mbedtls/mbedtls/padlock.h | 107 + c++/src/connect/mbedtls/mbedtls/pem.h | 129 + c++/src/connect/mbedtls/mbedtls/pk.h | 616 + c++/src/connect/mbedtls/mbedtls/pk_internal.h | 114 + c++/src/connect/mbedtls/mbedtls/pkcs11.h | 173 + c++/src/connect/mbedtls/mbedtls/pkcs12.h | 119 + c++/src/connect/mbedtls/mbedtls/pkcs5.h | 94 + c++/src/connect/mbedtls/mbedtls/platform.h | 295 + .../connect/mbedtls/mbedtls/platform_time.h | 81 + c++/src/connect/mbedtls/mbedtls/ripemd160.h | 138 + c++/src/connect/mbedtls/mbedtls/rsa.h | 652 + c++/src/connect/mbedtls/mbedtls/sha1.h | 136 + c++/src/connect/mbedtls/mbedtls/sha256.h | 141 + c++/src/connect/mbedtls/mbedtls/sha512.h | 141 + c++/src/connect/mbedtls/mbedtls/ssl.h | 2559 +++ c++/src/connect/mbedtls/mbedtls/ssl_cache.h | 143 + .../mbedtls/mbedtls/ssl_ciphersuites.h | 321 + c++/src/connect/mbedtls/mbedtls/ssl_cookie.h | 108 + .../connect/mbedtls/mbedtls/ssl_internal.h | 500 + c++/src/connect/mbedtls/mbedtls/ssl_ticket.h | 135 + c++/src/connect/mbedtls/mbedtls/threading.h | 106 + .../mbedtls/threading_alt.h} | 22 +- c++/src/connect/mbedtls/mbedtls/timing.h | 141 + c++/src/connect/mbedtls/mbedtls/version.h | 111 + c++/src/connect/mbedtls/mbedtls/x509.h | 331 + c++/src/connect/mbedtls/mbedtls/x509_crl.h | 173 + c++/src/connect/mbedtls/mbedtls/x509_crt.h | 654 + c++/src/connect/mbedtls/mbedtls/x509_csr.h | 298 + c++/src/connect/mbedtls/mbedtls/xtea.h | 139 + c++/src/connect/mbedtls/mbedtls_md5.c | 404 + c++/src/connect/mbedtls/mbedtls_version.c | 50 + c++/src/connect/mbedtls/md.c | 471 + c++/src/connect/mbedtls/md2.c | 288 + c++/src/connect/mbedtls/md4.c | 384 + c++/src/connect/mbedtls/md_wrap.c | 575 + c++/src/connect/mbedtls/memory_buffer_alloc.c | 745 + c++/src/connect/mbedtls/net_sockets.c | 586 + c++/src/connect/mbedtls/oid.c | 710 + c++/src/connect/mbedtls/padlock.c | 170 + c++/src/connect/mbedtls/pem.c | 449 + c++/src/connect/mbedtls/pk.c | 383 + c++/src/connect/mbedtls/pk_wrap.c | 513 + c++/src/connect/mbedtls/pkcs11.c | 240 + c++/src/connect/mbedtls/pkcs12.c | 365 + c++/src/connect/mbedtls/pkcs5.c | 406 + c++/src/connect/mbedtls/pkparse.c | 1293 ++ c++/src/connect/mbedtls/pkwrite.c | 439 + c++/src/connect/mbedtls/platform.c | 307 + c++/src/connect/mbedtls/ripemd160.c | 467 + c++/src/connect/mbedtls/rsa.c | 1730 ++ c++/src/connect/mbedtls/sha1.c | 448 + c++/src/connect/mbedtls/sha256.c | 458 + c++/src/connect/mbedtls/sha512.c | 514 + c++/src/connect/mbedtls/ssl_cache.c | 326 + c++/src/connect/mbedtls/ssl_ciphersuites.c | 1857 ++ c++/src/connect/mbedtls/ssl_cli.c | 3405 ++++ c++/src/connect/mbedtls/ssl_cookie.c | 260 + c++/src/connect/mbedtls/ssl_srv.c | 3926 ++++ c++/src/connect/mbedtls/ssl_ticket.c | 489 + c++/src/connect/mbedtls/ssl_tls.c | 7687 ++++++++ c++/src/connect/mbedtls/threading.c | 138 + c++/src/connect/mbedtls/timing.c | 525 + c++/src/connect/mbedtls/version_features.c | 648 + c++/src/connect/mbedtls/x509.c | 1098 ++ c++/src/connect/mbedtls/x509_create.c | 340 + c++/src/connect/mbedtls/x509_crl.c | 723 + c++/src/connect/mbedtls/x509_crt.c | 2404 +++ c++/src/connect/mbedtls/x509_csr.c | 423 + c++/src/connect/mbedtls/x509write_crt.c | 459 + c++/src/connect/mbedtls/x509write_csr.c | 259 + c++/src/connect/mbedtls/xtea.c | 281 + c++/src/connect/ncbi_ansi_ext.c | 38 +- c++/src/connect/ncbi_ansi_ext.h | 151 +- c++/src/connect/ncbi_assert.h | 5 +- c++/src/connect/ncbi_comm.h | 2 +- c++/src/connect/ncbi_conn_stream.cpp | 104 +- c++/src/connect/ncbi_conn_streambuf.cpp | 94 +- c++/src/connect/ncbi_conn_streambuf.hpp | 18 +- c++/src/connect/ncbi_conn_test.cpp | 15 +- c++/src/connect/ncbi_connection.c | 16 +- c++/src/connect/ncbi_connector.c | 2 +- c++/src/connect/ncbi_connssl.h | 33 +- c++/src/connect/ncbi_connutil.c | 172 +- c++/src/connect/ncbi_core.c | 325 +- c++/src/connect/ncbi_core_cxx.cpp | 129 +- c++/src/connect/ncbi_dispd.c | 4 +- c++/src/connect/ncbi_ftp_connector.c | 47 +- c++/src/connect/ncbi_gnutls.c | 280 +- c++/src/connect/ncbi_heapmgr.c | 132 +- c++/src/connect/ncbi_http_connector.c | 110 +- c++/src/connect/ncbi_http_session.cpp | 54 +- c++/src/connect/ncbi_iprange.c | 399 + c++/src/connect/ncbi_ipv6.c | 693 + c++/src/connect/ncbi_lbos.c | 221 +- c++/src/connect/ncbi_lbos_cxx.cpp | 7 +- c++/src/connect/ncbi_localip.c | 396 + c++/src/connect/ncbi_mbedtls.c | 739 + c++/src/connect/ncbi_monkey.cpp | 819 +- c++/src/connect/ncbi_monkeyp.hpp | 56 +- c++/src/connect/ncbi_namerd.c | 1542 ++ c++/src/connect/ncbi_namerd.h | 55 + c++/src/connect/ncbi_once.h | 63 + c++/src/connect/ncbi_priv.c | 4 +- c++/src/connect/ncbi_priv.h | 52 +- c++/src/connect/ncbi_sendmail.c | 132 +- c++/src/connect/ncbi_server_info.c | 348 +- c++/src/connect/ncbi_server_infop.h | 8 +- c++/src/connect/ncbi_service.c | 42 +- c++/src/connect/ncbi_service_connector.c | 253 +- c++/src/connect/ncbi_socket.c | 417 +- c++/src/connect/ncbi_socket_connector.c | 4 +- c++/src/connect/ncbi_strerror.c | 59 +- c++/src/connect/ncbi_tls.c | 98 + c++/src/connect/ncbi_util.c | 166 +- c++/src/connect/parson.c | 59 +- c++/src/connect/parson.h | 412 +- c++/src/connect/server.cpp | 19 +- ...keLists.ncbi_xblobstorage_netcache.lib.txt | 9 + .../CMakeLists.ncbi_xcache_netcache.lib.txt | 9 + c++/src/connect/services/CMakeLists.txt | 11 + .../services/CMakeLists.xconnserv.lib.txt | 25 + .../connect/services/Makefile.xconnserv.lib | 6 +- c++/src/connect/services/balancing.cpp | 87 - c++/src/connect/services/balancing.hpp | 52 +- c++/src/connect/services/clparser.cpp | 13 +- c++/src/connect/services/compound_id.cpp | 12 +- c++/src/connect/services/compound_id_v0.cpp | 151 +- c++/src/connect/services/grid_client.cpp | 72 +- .../connect/services/grid_control_thread.cpp | 27 +- .../connect/services/grid_control_thread.hpp | 12 +- c++/src/connect/services/grid_globals.cpp | 16 +- c++/src/connect/services/grid_rw_impl.cpp | 360 +- c++/src/connect/services/grid_worker.cpp | 31 +- c++/src/connect/services/grid_worker_impl.hpp | 46 +- c++/src/connect/services/json_over_uttp.cpp | 67 +- c++/src/connect/services/netcache_api.cpp | 125 +- .../connect/services/netcache_api_impl.hpp | 36 +- c++/src/connect/services/netcache_key.cpp | 7 +- c++/src/connect/services/netcache_rw.cpp | 33 +- c++/src/connect/services/netcache_search.cpp | 39 +- c++/src/connect/services/neticache_client.cpp | 235 +- c++/src/connect/services/netschedule_api.cpp | 510 +- .../services/netschedule_api_admin.cpp | 18 +- .../services/netschedule_api_executor.cpp | 217 +- .../services/netschedule_api_getjob.cpp | 2 +- .../services/netschedule_api_getjob.hpp | 2 +- .../connect/services/netschedule_api_impl.hpp | 253 +- .../services/netschedule_api_reader.cpp | 36 +- .../services/netschedule_api_submitter.cpp | 253 +- c++/src/connect/services/netschedule_key.cpp | 11 +- c++/src/connect/services/netservice_api.cpp | 587 +- .../connect/services/netservice_api_impl.hpp | 138 +- .../connect/services/netservice_params.cpp | 289 +- .../connect/services/netservice_params.hpp | 257 +- c++/src/connect/services/netstorage.cpp | 280 +- .../connect/services/netstorage_direct_nc.cpp | 189 +- .../connect/services/netstorage_direct_nc.hpp | 109 +- c++/src/connect/services/netstorage_rpc.cpp | 1243 +- c++/src/connect/services/netstorage_rpc.hpp | 43 +- .../connect/services/netstorageobjectinfo.cpp | 13 +- .../connect/services/netstorageobjectloc.cpp | 129 +- c++/src/connect/services/pack_int.cpp | 146 - c++/src/connect/services/pack_int.hpp | 103 - c++/src/connect/services/remote_app.cpp | 76 +- c++/src/connect/services/srv_connections.cpp | 309 +- .../connect/services/srv_connections_impl.hpp | 58 +- c++/src/connect/services/tmp_wn_info.cpp | 6 +- c++/src/connect/services/util.cpp | 86 +- c++/src/connect/services/wn_commit_thread.cpp | 9 +- c++/src/connect/services/wn_main_loop.cpp | 52 +- c++/src/connect/services/wn_offline_mode.cpp | 7 +- c++/src/corelib/CMakeLists.corelib.lib.txt | 41 + c++/src/corelib/CMakeLists.test_boost.lib.txt | 12 + c++/src/corelib/CMakeLists.test_mt.lib.txt | 11 + c++/src/corelib/CMakeLists.txt | 11 + c++/src/corelib/Makefile.corelib.lib | 6 +- c++/src/corelib/blob_storage.cpp | 4 +- c++/src/corelib/env_reg.cpp | 10 +- c++/src/corelib/ncbi_config.cpp | 18 +- c++/src/corelib/ncbi_cookies.cpp | 2 +- c++/src/corelib/ncbi_process.cpp | 4 +- c++/src/corelib/ncbi_safe_static.cpp | 39 +- c++/src/corelib/ncbi_stack.cpp | 6 +- c++/src/corelib/ncbi_stack_libunwind.cpp | 120 + c++/src/corelib/ncbi_stack_linux.cpp | 6 +- c++/src/corelib/ncbi_stack_win32.cpp | 4 +- c++/src/corelib/ncbi_system.cpp | 16 +- c++/src/corelib/ncbi_toolkit.cpp | 6 +- c++/src/corelib/ncbi_url.cpp | 431 +- c++/src/corelib/ncbi_version.xsd | 95 + c++/src/corelib/ncbiapp.cpp | 11 +- c++/src/corelib/ncbiargs.cpp | 24 +- c++/src/corelib/ncbidiag.cpp | 54 +- c++/src/corelib/ncbierror.cpp | 2 +- c++/src/corelib/ncbiexec.cpp | 4 +- c++/src/corelib/ncbiexpt.cpp | 6 +- c++/src/corelib/ncbifile.cpp | 1056 +- c++/src/corelib/ncbimtx.cpp | 28 +- c++/src/corelib/ncbireg.cpp | 17 +- c++/src/corelib/ncbistr.cpp | 290 +- c++/src/corelib/ncbistre.cpp | 18 +- c++/src/corelib/ncbithr.cpp | 72 +- c++/src/corelib/ncbitime.cpp | 35 +- c++/src/corelib/request_ctx.cpp | 2 +- c++/src/corelib/request_status.cpp | 97 + c++/src/corelib/rwstreambuf.cpp | 63 +- c++/src/corelib/stream_utils.cpp | 6 +- c++/src/corelib/syslog.cpp | 4 +- c++/src/corelib/teamcity_boost.cpp | 4 +- c++/src/corelib/teamcity_messages.cpp | 4 +- c++/src/corelib/test_boost.cpp | 28 +- c++/src/corelib/test_mt.cpp | 4 +- c++/src/corelib/version.cpp | 222 +- c++/src/db/CMakeLists.txt | 9 + c++/src/db/Makefile.in | 13 + .../db/sqlite/CMakeLists.sqlitewrapp.lib.txt | 11 + c++/src/db/sqlite/CMakeLists.txt | 7 + c++/src/db/sqlite/Makefile.in | 9 + c++/src/db/sqlite/Makefile.sqlitewrapp.lib | 15 + c++/src/db/sqlite/sqlitewrapp.cpp | 1049 ++ c++/src/dbapi/CMakeLists.dbapi.lib.txt | 12 + c++/src/dbapi/CMakeLists.txt | 19 + c++/src/dbapi/bytestreambuf.hpp | 6 +- .../CMakeLists.ncbi_xcache_dbapi.lib.txt | 11 + c++/src/dbapi/cache/CMakeLists.txt | 10 + c++/src/dbapi/cache/dbapi_blob_cache.cpp | 14 +- c++/src/dbapi/cache/dbapi_blob_cache_cf.cpp | 4 +- .../driver/CMakeLists.dbapi_driver.lib.txt | 20 + c++/src/dbapi/driver/CMakeLists.txt | 24 + .../dbapi/driver/Makefile.dbapi_driver.lib | 4 +- c++/src/dbapi/driver/dbapi_conn_factory.cpp | 157 +- .../dbapi/driver/dbapi_driver_conn_mgr.cpp | 4 +- .../dbapi/driver/dbapi_driver_conn_params.cpp | 2 +- .../driver/dbapi_driver_exception_storage.cpp | 4 +- .../dbapi/driver/dbapi_driver_sample_base.cpp | 4 +- c++/src/dbapi/driver/dbapi_driver_utils.cpp | 12 +- c++/src/dbapi/driver/dbapi_impl_cmd.cpp | 6 +- .../dbapi/driver/dbapi_impl_connection.cpp | 33 +- c++/src/dbapi/driver/dbapi_impl_context.cpp | 92 +- c++/src/dbapi/driver/dbapi_pool_balancer.cpp | 407 + c++/src/dbapi/driver/dbapi_pool_balancer.hpp | 82 + c++/src/dbapi/driver/dbapi_svc_mapper.cpp | 14 +- c++/src/dbapi/driver/driver_mgr.cpp | 10 +- c++/src/dbapi/driver/exception.cpp | 6 +- c++/src/dbapi/driver/ncbi_win_hook.cpp | 4 +- .../odbc/CMakeLists.ncbi_xdbapi_odbc.lib.txt | 11 + c++/src/dbapi/driver/odbc/CMakeLists.txt | 9 + c++/src/dbapi/driver/odbc/context.cpp | 4 +- c++/src/dbapi/driver/odbc/cursor.cpp | 24 +- c++/src/dbapi/driver/parameters.cpp | 4 +- c++/src/dbapi/driver/public.cpp | 32 +- c++/src/dbapi/err_handler.hpp | 6 +- c++/src/dbapi/rs_impl.cpp | 6 +- c++/src/dbapi/rw_impl.hpp | 4 +- c++/src/dbapi/stmt_impl.cpp | 6 +- c++/src/html/CMakeLists.html.lib.txt | 11 + c++/src/html/CMakeLists.txt | 10 + c++/src/html/page.cpp | 6 +- c++/src/misc/CMakeLists.txt | 5 +- c++/src/misc/Makefile.in | 7 +- c++/src/misc/third_party/CMakeLists.txt | 2 +- .../misc/third_party_static/CMakeLists.txt | 2 +- c++/src/objects/CMakeLists.txt | 104 + .../objects/access/CMakeLists.access.asn.txt | 20 + c++/src/objects/access/CMakeLists.txt | 7 + .../objects/biblio/CMakeLists.biblio.asn.txt | 17 + c++/src/objects/biblio/CMakeLists.txt | 7 + .../biotree/CMakeLists.biotree.asn.txt | 20 + c++/src/objects/biotree/CMakeLists.txt | 7 + c++/src/objects/biotree/biotree.asn | 4 +- .../objects/blast/CMakeLists.blast.asn.txt | 17 + c++/src/objects/blast/CMakeLists.txt | 8 + .../blast/CMakeLists.xnetblastcli.lib.txt | 12 + .../blastdb/CMakeLists.blastdb.asn.txt | 16 + c++/src/objects/blastdb/CMakeLists.txt | 7 + .../blastxml/CMakeLists.blastxml.asn.txt | 20 + c++/src/objects/blastxml/CMakeLists.txt | 7 + .../blastxml2/CMakeLists.blastxml2.asn.txt | 20 + c++/src/objects/blastxml2/CMakeLists.txt | 7 + c++/src/objects/cdd/CMakeLists.cdd.asn.txt | 20 + c++/src/objects/cdd/CMakeLists.txt | 7 + c++/src/objects/cdd/Makefile.cdd.lib | 1 + c++/src/objects/cn3d/CMakeLists.cn3d.asn.txt | 20 + c++/src/objects/cn3d/CMakeLists.txt | 7 + .../coords/CMakeLists.objcoords.asn.txt | 21 + c++/src/objects/coords/CMakeLists.txt | 7 + .../objects/docsum/CMakeLists.docsum.asn.txt | 20 + c++/src/objects/docsum/CMakeLists.txt | 7 + c++/src/objects/docsum/docsum.def | 5 + .../entrez2/CMakeLists.entrez2.asn.txt | 17 + .../entrez2/CMakeLists.entrez2cli.lib.txt | 10 + c++/src/objects/entrez2/CMakeLists.txt | 10 + .../objects/entrez2/Makefile.entrez2cli.lib | 1 + .../entrezgene/CMakeLists.entrezgene.asn.txt | 20 + c++/src/objects/entrezgene/CMakeLists.txt | 7 + c++/src/objects/entrezgene/entrezgene.asn | 6 +- .../featdef/CMakeLists.featdef.asn.txt | 20 + c++/src/objects/featdef/CMakeLists.txt | 7 + .../objects/gbproj/CMakeLists.gbproj.asn.txt | 20 + c++/src/objects/gbproj/CMakeLists.txt | 7 + .../objects/gbseq/CMakeLists.gbseq.asn.txt | 20 + c++/src/objects/gbseq/CMakeLists.txt | 7 + .../general/CMakeLists.general.asn.txt | 19 + c++/src/objects/general/CMakeLists.txt | 10 + c++/src/objects/general/Dbtag.cpp | 62 +- c++/src/objects/general/Name_std.cpp | 2 +- .../genesbyloc/CMakeLists.genesbyloc.asn.txt | 20 + c++/src/objects/genesbyloc/CMakeLists.txt | 7 + .../CMakeLists.gencoll_client.asn.txt | 25 + .../CMakeLists.genome_collection.asn.txt | 21 + c++/src/objects/genomecoll/CMakeLists.txt | 10 + c++/src/objects/genomecoll/GC_Assembly.cpp | 37 +- .../objects/genomecoll/GC_AssemblyUnit.cpp | 8 +- c++/src/objects/genomecoll/Makefile.in | 2 +- .../objects/genomecoll/cached_assembly.cpp | 50 - .../gc_cli/CMakeLists.gc_cli.app.txt | 13 + .../objects/genomecoll/gc_cli/CMakeLists.txt | 7 + .../genomecoll/gc_cli/Makefile.gc_cli.app | 34 + c++/src/objects/genomecoll/gc_cli/Makefile.in | 16 + c++/src/objects/genomecoll/gc_cli/gc_cli.cpp | 377 + .../genomecoll/genomic_collections_cli.cpp | 216 +- .../homologene/CMakeLists.homologene.asn.txt | 20 + c++/src/objects/homologene/CMakeLists.txt | 7 + c++/src/objects/id1/CMakeLists.id1.asn.txt | 17 + c++/src/objects/id1/CMakeLists.id1cli.lib.txt | 11 + c++/src/objects/id1/CMakeLists.txt | 10 + c++/src/objects/id2/CMakeLists.id2.asn.txt | 17 + c++/src/objects/id2/CMakeLists.id2cli.lib.txt | 11 + c++/src/objects/id2/CMakeLists.txt | 8 + c++/src/objects/id2/ID2_Reply_Data.cpp | 83 + c++/src/objects/id2/ID2_Request_Packet.cpp | 71 +- c++/src/objects/id2/id2.asn | 4 +- .../insdseq/CMakeLists.insdseq.asn.txt | 20 + c++/src/objects/insdseq/CMakeLists.txt | 7 + .../objects/macro/CMakeLists.macro.asn.txt | 24 + c++/src/objects/macro/CMakeLists.txt | 9 + c++/src/objects/macro/Location_constraint.cpp | 73 +- c++/src/objects/macro/Search_func.cpp | 25 +- c++/src/objects/macro/Simple_replace.cpp | 4 +- c++/src/objects/macro/String_constraint.cpp | 65 +- c++/src/objects/macro/Suspect_rule.cpp | 704 +- c++/src/objects/macro/Suspect_rule_set.cpp | 10 +- c++/src/objects/macro/product_rules.inc | 591 +- c++/src/objects/macro/product_rules.prt | 589 +- .../medlars/CMakeLists.medlars.asn.txt | 20 + c++/src/objects/medlars/CMakeLists.txt | 7 + .../medline/CMakeLists.medline.asn.txt | 17 + c++/src/objects/medline/CMakeLists.txt | 7 + c++/src/objects/mim/CMakeLists.mim.asn.txt | 20 + c++/src/objects/mim/CMakeLists.txt | 7 + c++/src/objects/mla/CMakeLists.mla.asn.txt | 21 + c++/src/objects/mla/CMakeLists.mlacli.lib.txt | 10 + c++/src/objects/mla/CMakeLists.txt | 8 + c++/src/objects/mmdb/CMakeLists.mmdb.lib.txt | 21 + c++/src/objects/mmdb/CMakeLists.txt | 7 + c++/src/objects/mmdb/Makefile.mmdb.lib | 3 +- .../ncbimime/CMakeLists.ncbimime.asn.txt | 20 + c++/src/objects/ncbimime/CMakeLists.txt | 9 + .../objects/objprt/CMakeLists.objprt.asn.txt | 20 + c++/src/objects/objprt/CMakeLists.txt | 7 + .../objects/omssa/CMakeLists.omssa.asn.txt | 20 + c++/src/objects/omssa/CMakeLists.txt | 7 + c++/src/objects/omssa/Makefile.omssa.lib | 1 + .../pcassay/CMakeLists.pcassay.asn.txt | 20 + c++/src/objects/pcassay/CMakeLists.txt | 7 + .../CMakeLists.pcsubstance.asn.txt | 20 + c++/src/objects/pcsubstance/CMakeLists.txt | 7 + c++/src/objects/proj/CMakeLists.proj.asn.txt | 20 + c++/src/objects/proj/CMakeLists.txt | 7 + c++/src/objects/pub/CMakeLists.pub.asn.txt | 16 + c++/src/objects/pub/CMakeLists.txt | 7 + c++/src/objects/pub/Pub.cpp | 26 +- .../objects/pubmed/CMakeLists.pubmed.asn.txt | 20 + c++/src/objects/pubmed/CMakeLists.txt | 7 + .../objects/remap/CMakeLists.remap.asn.txt | 21 + .../objects/remap/CMakeLists.remapcli.lib.txt | 10 + c++/src/objects/remap/CMakeLists.txt | 8 + .../scoremat/CMakeLists.scoremat.asn.txt | 20 + c++/src/objects/scoremat/CMakeLists.txt | 7 + c++/src/objects/seq/CMakeLists.seq.asn.txt | 26 + c++/src/objects/seq/CMakeLists.txt | 10 + c++/src/objects/seq/Delta_ext.cpp | 2 +- c++/src/objects/seq/Makefile.seq.lib | 6 +- c++/src/objects/seq/Seq_gap.cpp | 2 +- c++/src/objects/seq/Seq_inst.cpp | 10 +- c++/src/objects/seq/seq_id_handle.cpp | 52 +- c++/src/objects/seq/seq_id_tree.cpp | 18 +- c++/src/objects/seq/seq_id_tree.hpp | 32 +- c++/src/objects/seq/seq_loc_from_string.cpp | 2 +- c++/src/objects/seq/seq_loc_mapper_base.cpp | 142 +- c++/src/objects/seq/so_map.cpp | 1230 ++ c++/src/objects/seq/sofa_map.cpp | 166 +- c++/src/objects/seqalign/Seq_align.cpp | 96 +- c++/src/objects/seqalign/Sparse_align.cpp | 2 +- c++/src/objects/seqalign/Sparse_seg.cpp | 2 +- c++/src/objects/seqalign/Spliced_seg.cpp | 2 +- c++/src/objects/seqalign/Std_seg.cpp | 2 +- .../seqcode/CMakeLists.seqcode.asn.txt | 16 + c++/src/objects/seqcode/CMakeLists.txt | 7 + .../seqedit/CMakeLists.seqedit.asn.txt | 16 + c++/src/objects/seqedit/CMakeLists.txt | 7 + c++/src/objects/seqfeat/BioSource.cpp | 251 +- c++/src/objects/seqfeat/Delta_item.cpp | 2 +- c++/src/objects/seqfeat/Gb_qual.cpp | 299 +- .../objects/seqfeat/Genetic_code_table.cpp | 34 +- c++/src/objects/seqfeat/OrgMod.cpp | 344 +- c++/src/objects/seqfeat/OrgName.cpp | 209 +- c++/src/objects/seqfeat/Org_ref.cpp | 262 +- c++/src/objects/seqfeat/Prot_ref.cpp | 12 +- c++/src/objects/seqfeat/RNA_gen.cpp | 93 +- c++/src/objects/seqfeat/SeqFeatData.cpp | 142 +- c++/src/objects/seqfeat/Seq_feat.cpp | 2 +- c++/src/objects/seqfeat/SubSource.cpp | 738 +- c++/src/objects/seqfeat/Trna_ext.cpp | 2 +- c++/src/objects/seqfeat/Variation_ref.cpp | 2 +- c++/src/objects/seqfeat/cell_line.inc | 975 +- c++/src/objects/seqfeat/cell_line.txt | 201 +- c++/src/objects/seqfeat/common_tax.inc | 934 + c++/src/objects/seqfeat/common_tax.txt | 900 + c++/src/objects/seqfeat/ecnum_ambiguous.inc | 1484 +- c++/src/objects/seqfeat/ecnum_ambiguous.txt | 6 + c++/src/objects/seqfeat/ecnum_deleted.inc | 4 +- c++/src/objects/seqfeat/ecnum_deleted.txt | 2 + c++/src/objects/seqfeat/ecnum_replaced.inc | 1936 +- c++/src/objects/seqfeat/ecnum_replaced.txt | 54 +- c++/src/objects/seqfeat/ecnum_specific.inc | 11793 ++++++------ c++/src/objects/seqfeat/ecnum_specific.txt | 351 +- c++/src/objects/seqfeat/institution_codes.inc | 15226 ++++++++-------- c++/src/objects/seqfeat/institution_codes.txt | 14402 +++++++-------- c++/src/objects/seqfeat/isolation_sources.inc | 367 + c++/src/objects/seqfeat/isolation_sources.txt | 333 + c++/src/objects/seqfeat/lat_lon_country.inc | 2 +- c++/src/objects/seqfeat/prepare_taxtable.sh | 25 + c++/src/objects/seqfeat/seqfeat.asn | 3 +- c++/src/objects/seqloc/Seq_id.cpp | 230 +- c++/src/objects/seqloc/Seq_loc.cpp | 84 +- c++/src/objects/seqloc/accguide.inc | 2389 ++- c++/src/objects/seqloc/accguide.txt | 2387 ++- c++/src/objects/seqset/Bioseq_set.cpp | 2 +- .../objects/seqset/CMakeLists.seqset.asn.txt | 16 + c++/src/objects/seqset/CMakeLists.txt | 9 + c++/src/objects/seqset/Makefile.seqset.lib | 1 + c++/src/objects/seqset/Seq_entry.cpp | 20 +- .../seqsplit/CMakeLists.seqsplit.asn.txt | 16 + c++/src/objects/seqsplit/CMakeLists.txt | 7 + .../seqtest/CMakeLists.seqtest.asn.txt | 20 + c++/src/objects/seqtest/CMakeLists.txt | 7 + .../objects/submit/CMakeLists.submit.asn.txt | 16 + c++/src/objects/submit/CMakeLists.txt | 7 + .../objects/taxon1/CMakeLists.taxon1.asn.txt | 20 + c++/src/objects/taxon1/CMakeLists.txt | 7 + c++/src/objects/taxon1/cache.cpp | 814 +- c++/src/objects/taxon1/cache.hpp | 142 +- c++/src/objects/taxon1/taxon1.asn | 8 +- c++/src/objects/taxon1/taxon1.cpp | 1124 +- c++/src/objects/taxon1/taxon1.def | 3 - c++/src/objects/taxon1/utils.cpp | 149 +- .../objects/taxon3/CMakeLists.taxon3.asn.txt | 20 + c++/src/objects/taxon3/CMakeLists.txt | 7 + c++/src/objects/taxon3/Makefile.taxon3.lib | 5 +- c++/src/objects/taxon3/T3Data.cpp | 24 +- c++/src/objects/taxon3/taxon3.cpp | 94 +- .../tinyseq/CMakeLists.tinyseq.asn.txt | 20 + c++/src/objects/tinyseq/CMakeLists.txt | 7 + .../trackmgr/CMakeLists.trackmgr.asn.txt | 21 + .../trackmgr/CMakeLists.trackmgrcli.lib.txt | 10 + .../CMakeLists.trackmgrgridcli.lib.txt | 12 + c++/src/objects/trackmgr/CMakeLists.txt | 9 + c++/src/objects/trackmgr/trackmgr.asn | 28 +- c++/src/objects/trackmgr/trackmgr.def | 3 + c++/src/objects/trackmgr/trackmgr_client.cpp | 62 +- c++/src/objects/valerr/CMakeLists.txt | 7 + .../objects/valerr/CMakeLists.valerr.asn.txt | 24 + c++/src/objects/valerr/ValidErrItem.cpp | 69 +- c++/src/objects/valerr/ValidError.cpp | 28 +- c++/src/objects/valerr/valerr.asn | 9 +- c++/src/objects/valid/CMakeLists.txt | 7 + .../objects/valid/CMakeLists.valid.asn.txt | 20 + c++/src/objects/valid/Comment_rule.cpp | 4 +- c++/src/objects/valid/Comment_set.cpp | 4 +- c++/src/objects/valid/validrules.inc | 52 +- c++/src/objects/valid/validrules.prt | 50 +- c++/src/objects/variation/CMakeLists.txt | 7 + .../variation/CMakeLists.variation.asn.txt | 20 + c++/src/objects/varrep/CMakeLists.txt | 7 + .../objects/varrep/CMakeLists.varrep.asn.txt | 21 + c++/src/objects/varrep/varrep.asn | 1 + c++/src/objmgr/CMakeLists.objmgr.lib.txt | 27 + c++/src/objmgr/CMakeLists.txt | 11 + c++/src/objmgr/align_ci.cpp | 22 +- c++/src/objmgr/annot_collector.cpp | 64 +- c++/src/objmgr/annot_object_index.cpp | 2 +- c++/src/objmgr/annot_selector.cpp | 6 +- c++/src/objmgr/annot_types_ci.cpp | 15 +- c++/src/objmgr/bioseq_base_info.cpp | 2 +- c++/src/objmgr/bioseq_info.cpp | 2 +- c++/src/objmgr/bioseq_set_info.cpp | 40 +- c++/src/objmgr/data_loader.cpp | 20 +- c++/src/objmgr/data_source.cpp | 41 +- c++/src/objmgr/edits_db_saver.cpp | 2 +- c++/src/objmgr/feat_ci.cpp | 24 +- c++/src/objmgr/gc_assembly_parser.cpp | 2 +- c++/src/objmgr/graph_ci.cpp | 24 +- c++/src/objmgr/mapped_feat.cpp | 8 +- c++/src/objmgr/objmgr_exception.cpp | 3 +- c++/src/objmgr/prefetch_actions.cpp | 2 +- c++/src/objmgr/scope_impl.cpp | 167 +- c++/src/objmgr/scope_info.cpp | 37 +- c++/src/objmgr/seq_annot_info.cpp | 4 +- c++/src/objmgr/seq_entry_info.cpp | 2 +- c++/src/objmgr/seq_loc_mapper.cpp | 26 +- c++/src/objmgr/seq_map.cpp | 6 +- c++/src/objmgr/seq_map_ci.cpp | 2 +- c++/src/objmgr/seq_map_switch.cpp | 2 +- c++/src/objmgr/seq_table_info.cpp | 2 +- c++/src/objmgr/seq_table_setters.cpp | 2 +- c++/src/objmgr/seq_vector.cpp | 2 +- c++/src/objmgr/snp_annot_info.cpp | 2 +- .../objmgr/split/CMakeLists.id2_split.lib.txt | 17 + c++/src/objmgr/split/CMakeLists.txt | 8 + c++/src/objmgr/split/annot_piece.cpp | 2 +- c++/src/objmgr/split/blob_splitter_impl.cpp | 2 +- c++/src/objmgr/split/blob_splitter_maker.cpp | 2 +- c++/src/objmgr/split/blob_splitter_parser.cpp | 42 +- c++/src/objmgr/split/id_range.cpp | 2 +- c++/src/objmgr/split/object_splitinfo.cpp | 2 +- c++/src/objmgr/split/size.cpp | 2 +- c++/src/objmgr/split_parser.cpp | 7 +- c++/src/objmgr/tse_assigner.cpp | 27 +- c++/src/objmgr/tse_chunk_info.cpp | 49 +- c++/src/objmgr/tse_handle.cpp | 8 +- c++/src/objmgr/tse_info.cpp | 18 +- c++/src/objmgr/tse_split_info.cpp | 35 +- c++/src/objmgr/unsupp_editsaver.cpp | 2 +- c++/src/objmgr/util/CMakeLists.txt | 9 + c++/src/objmgr/util/CMakeLists.util.lib.txt | 17 + c++/src/objmgr/util/Makefile.util.lib | 11 +- .../edit => objmgr/util}/autodef.cpp | 232 +- .../util}/autodef_available_modifier.cpp | 4 +- .../util}/autodef_feature_clause.cpp | 45 +- .../util}/autodef_feature_clause_base.cpp | 6 +- .../util}/autodef_mod_combo.cpp | 38 +- .../edit => objmgr/util}/autodef_options.cpp | 4 +- .../util}/autodef_source_desc.cpp | 4 +- .../util}/autodef_source_group.cpp | 26 +- c++/src/objmgr/util/create_defline.cpp | 854 +- c++/src/objmgr/util/feature.cpp | 131 +- c++/src/objmgr/util/feature_edit.cpp | 400 + c++/src/objmgr/util/indexer.cpp | 1941 ++ c++/src/objmgr/util/obj_sniff.cpp | 2 +- c++/src/objmgr/util/objutil.cpp | 69 +- c++/src/objmgr/util/seq_align_util.cpp | 218 +- c++/src/objmgr/util/seq_loc_util.cpp | 19 +- c++/src/objmgr/util/seq_trimmer.cpp | 26 +- c++/src/objmgr/util/seqtitle.cpp | 2 +- c++/src/objmgr/util/sequence.cpp | 789 +- c++/src/objmgr/util/weight.cpp | 2 +- c++/src/objtools/CMakeLists.txt | 30 + .../CMakeLists.align_format.lib.txt | 12 + c++/src/objtools/align_format/CMakeLists.txt | 9 + .../align_format/align_format_util.cpp | 604 +- .../objtools/align_format/format_flags.cpp | 2 +- c++/src/objtools/align_format/showalign.cpp | 134 +- c++/src/objtools/align_format/showdefline.cpp | 146 +- c++/src/objtools/align_format/tabular.cpp | 22 +- c++/src/objtools/align_format/taxFormat.cpp | 37 +- .../CMakeLists.align_format_unit_test.app.txt | 16 + .../align_format/unit_test/CMakeLists.txt | 9 + .../unit_test/aln_printer_unit_test.cpp | 52 +- .../unit_test/showalign_unit_test.cpp | 9 +- .../unit_test/showdefline_unit_test.cpp | 7 +- .../unit_test/tabularinof_unit_test.cpp | 9 +- .../objtools/alnmgr/CMakeLists.alnmgr.lib.txt | 16 + c++/src/objtools/alnmgr/CMakeLists.txt | 10 + c++/src/objtools/alnmgr/Makefile.alnmgr.lib | 4 +- c++/src/objtools/alnmgr/aln_converters.cpp | 17 +- c++/src/objtools/alnmgr/alnmix.cpp | 22 +- c++/src/objtools/alnmgr/alnvec.cpp | 2 +- c++/src/objtools/alnmgr/sparse_aln.cpp | 4 +- c++/src/objtools/alnmgr/sparse_ci.cpp | 4 +- c++/src/objtools/blast/CMakeLists.txt | 13 + .../CMakeLists.blastdb_format.lib.txt | 14 + .../blast/blastdb_format/CMakeLists.txt | 9 + .../Makefile.blastdb_format.lib | 2 +- .../blastdb_format/blastdb_dataextract.cpp | 26 +- .../blast/blastdb_format/seq_formatter.cpp | 1 - .../blast/blastdb_format/seq_writer.cpp | 2 +- ...MakeLists.blastdb_format_unit_test.app.txt | 15 + .../blastdb_format/unit_test/CMakeLists.txt | 9 + .../Makefile.blastdb_format_unit_test.app | 2 +- .../unit_test/seq_formatter_unit_test.cpp | 14 +- .../unit_test/seq_writer_unit_test.cpp | 2 +- .../CMakeLists.gene_info.lib.txt | 10 + .../blast/gene_info_reader/CMakeLists.txt | 10 + .../demo/CMakeLists.gene_info_reader.app.txt | 17 + .../gene_info_reader/demo/CMakeLists.txt | 7 + .../blast/gene_info_reader/file_utils.cpp | 4 +- .../blast/gene_info_reader/gene_info.cpp | 4 +- .../CMakeLists.gene_info_unit_test.app.txt | 19 + .../gene_info_reader/unit_test/CMakeLists.txt | 9 + .../unit_test/gene_info_test.cpp | 22 +- .../seqdb_reader/CMakeLists.seqdb.lib.txt | 16 + .../blast/seqdb_reader/CMakeLists.txt | 10 + .../objtools/blast/seqdb_reader/Makefile.in | 2 +- .../blast/seqdb_reader/Makefile.seqdb.lib | 4 +- .../demo/CMakeLists.seqdb_demo.app.txt | 9 + .../blast/seqdb_reader/demo/CMakeLists.txt | 6 + .../blast/seqdb_reader/demo/seqdb_demo.cpp | 633 +- c++/src/objtools/blast/seqdb_reader/seqdb.cpp | 313 +- .../blast/seqdb_reader/seqdbalias.cpp | 74 +- .../blast/seqdb_reader/seqdbalias.hpp | 10 +- .../blast/seqdb_reader/seqdbatlas.cpp | 1381 +- .../blast/seqdb_reader/seqdbbitset.cpp | 12 +- .../blast/seqdb_reader/seqdbbitset.hpp | 7 +- .../objtools/blast/seqdb_reader/seqdbcol.cpp | 34 +- .../blast/seqdb_reader/seqdbcommon.cpp | 109 +- .../blast/seqdb_reader/seqdbexpert.cpp | 28 +- .../objtools/blast/seqdb_reader/seqdbfile.cpp | 115 +- .../blast/seqdb_reader/seqdbfilter.hpp | 13 +- .../blast/seqdb_reader/seqdbgilistset.cpp | 15 +- .../blast/seqdb_reader/seqdbgimask.cpp | 69 +- .../blast/seqdb_reader/seqdbgimask.hpp | 26 +- .../objtools/blast/seqdb_reader/seqdbimpl.cpp | 158 +- .../objtools/blast/seqdb_reader/seqdbimpl.hpp | 108 +- .../objtools/blast/seqdb_reader/seqdbisam.cpp | 528 +- .../blast/seqdb_reader/seqdboidlist.cpp | 56 +- .../blast/seqdb_reader/seqdboidlist.hpp | 20 +- .../objtools/blast/seqdb_reader/seqdbtax.cpp | 214 +- .../objtools/blast/seqdb_reader/seqdbvol.cpp | 356 +- .../blast/seqdb_reader/seqdbvolset.cpp | 8 +- .../blast/seqdb_reader/seqdbvolset.hpp | 8 +- .../test/CMakeLists.seqdb_perf.app.txt | 9 + .../blast/seqdb_reader/test/CMakeLists.txt | 6 + .../blast/seqdb_writer/CMakeLists.txt | 9 + .../seqdb_writer/CMakeLists.writedb.lib.txt | 15 + .../objtools/blast/seqdb_writer/Makefile.in | 2 +- .../blast/seqdb_writer/Makefile.writedb.lib | 7 +- .../blast/seqdb_writer/build-alias-index | 2 +- .../objtools/blast/seqdb_writer/build_db.cpp | 7 +- .../seqdb_writer/unit_test/CMakeLists.txt | 9 + .../CMakeLists.writedb_unit_test.app.txt | 15 + .../unit_test/Makefile.writedb_unit_test.app | 4 +- .../unit_test/data/writedb_nucl.nhr | Bin 0 -> 8179 bytes .../unit_test/data/writedb_nucl.nin | Bin 0 -> 716 bytes .../unit_test/data/writedb_nucl.nnd | Bin 0 -> 464 bytes .../unit_test/data/writedb_nucl.nni | Bin 0 -> 52 bytes .../unit_test/data/writedb_nucl.nog | Bin 0 -> 240 bytes .../unit_test/data/writedb_nucl.nsd | 117 + .../unit_test/data/writedb_nucl.nsi | Bin 0 -> 83 bytes .../unit_test/data/writedb_nucl.nsq | Bin 0 -> 20028 bytes .../unit_test/data/writedb_prot.phr | Bin 0 -> 14567 bytes .../unit_test/data/writedb_prot.pin | Bin 0 -> 776 bytes .../unit_test/data/writedb_prot.pnd | Bin 0 -> 912 bytes .../unit_test/data/writedb_prot.pni | Bin 0 -> 52 bytes .../unit_test/data/writedb_prot.pog | Bin 0 -> 376 bytes .../unit_test/data/writedb_prot.psd | 244 + .../unit_test/data/writedb_prot.psi | Bin 0 -> 117 bytes .../unit_test/data/writedb_prot.psq | Bin 0 -> 29605 bytes .../unit_test/writedb_unit_test.cpp | 80 +- .../objtools/blast/seqdb_writer/writedb.cpp | 2 +- .../blast/seqdb_writer/writedb_files.cpp | 14 +- .../blast/seqdb_writer/writedb_impl.cpp | 11 +- .../blast/seqdb_writer/writedb_impl.hpp | 2 +- .../blast/seqdb_writer/writedb_volume.hpp | 3 +- .../CMakeLists.blast_services.lib.txt | 13 + .../objtools/blast/services/CMakeLists.txt | 9 + ...MakeLists.blast_services_unit_test.app.txt | 15 + .../blast/services/unit_test/CMakeLists.txt | 9 + .../unit_test/blast_services_test.cpp | 4 +- .../cleanup/CMakeLists.cleanup.lib.txt | 14 + c++/src/objtools/cleanup/CMakeLists.txt | 9 + c++/src/objtools/cleanup/Makefile.cleanup.lib | 2 +- .../cleanup/autogenerated_cleanup.cpp | 3 +- .../cleanup/autogenerated_cleanup.hpp | 2 +- .../cleanup/autogenerated_cleanup.txt | 5 + .../autogenerated_extended_cleanup.cpp | 2 +- c++/src/objtools/cleanup/cleanup.cpp | 962 +- c++/src/objtools/cleanup/cleanup_utils.cpp | 4 +- c++/src/objtools/cleanup/newcleanupp.cpp | 714 +- c++/src/objtools/cleanup/newcleanupp.hpp | 12 +- c++/src/objtools/data_loaders/CMakeLists.txt | 13 + c++/src/objtools/data_loaders/Makefile.in | 4 +- .../CMakeLists.ncbi_xloader_blastdb.lib.txt | 14 + ...MakeLists.ncbi_xloader_blastdb_rmt.lib.txt | 13 + .../data_loaders/blastdb/CMakeLists.txt | 10 + .../CMakeLists.ncbi_xloader_genbank.lib.txt | 13 + .../genbank/CMakeLists.ncbi_xreader.lib.txt | 16 + .../data_loaders/genbank/CMakeLists.txt | 16 + .../CMakeLists.ncbi_xreader_cache.lib.txt | 15 + .../data_loaders/genbank/cache/CMakeLists.txt | 7 + .../data_loaders/genbank/gbloader.cpp | 163 +- .../CMakeLists.ncbi_xreader_gicache.lib.txt | 12 + .../genbank/gicache/CMakeLists.txt | 7 + .../data_loaders/genbank/gicache/Makefile.in | 2 +- .../gicache/Makefile.ncbi_xreader_gicache.lib | 4 +- .../data_loaders/genbank/gicache/gicache.c | 204 +- .../data_loaders/genbank/gicache/gicache.h | 16 +- .../genbank/gicache/reader_gicache.cpp | 2 +- .../id1/CMakeLists.ncbi_xreader_id1.lib.txt | 15 + .../data_loaders/genbank/id1/CMakeLists.txt | 7 + .../genbank/id1/Makefile.ncbi_xreader_id1.lib | 4 +- .../id2/CMakeLists.ncbi_xreader_id2.lib.txt | 15 + .../data_loaders/genbank/id2/CMakeLists.txt | 7 + .../data_loaders/genbank/processors.cpp | 16 +- .../objtools/data_loaders/genbank/reader.cpp | 14 +- .../data_loaders/genbank/reader_id1_base.cpp | 12 +- .../data_loaders/genbank/reader_id2_base.cpp | 347 +- c++/src/objtools/edit/CMakeLists.edit.lib.txt | 16 + c++/src/objtools/edit/CMakeLists.txt | 10 + c++/src/objtools/edit/Makefile.edit.lib | 12 +- c++/src/objtools/edit/Makefile.in | 4 +- c++/src/objtools/edit/autodef_with_tax.cpp | 169 + .../objtools/edit/capitalization_string.cpp | 39 +- c++/src/objtools/edit/cds_fix.cpp | 29 +- c++/src/objtools/edit/feattable_edit.cpp | 408 +- c++/src/objtools/edit/gap_trim.cpp | 801 + c++/src/objtools/edit/gaps_edit.cpp | 8 +- c++/src/objtools/edit/loc_edit.cpp | 219 +- c++/src/objtools/edit/mail_report.cpp | 2 +- c++/src/objtools/edit/remote_updater.cpp | 3 +- c++/src/objtools/edit/rna_edit.cpp | 2 +- c++/src/objtools/edit/seq_entry_edit.cpp | 315 +- c++/src/objtools/edit/seqid_guesser.cpp | 17 +- c++/src/objtools/edit/source_edit.cpp | 128 +- c++/src/objtools/edit/string_constraint.cpp | 2 +- c++/src/objtools/format/CMakeLists.txt | 7 + .../format/CMakeLists.xformat.lib.txt | 25 + c++/src/objtools/format/accession_item.cpp | 63 +- c++/src/objtools/format/comment_item.cpp | 14 +- c++/src/objtools/format/context.cpp | 28 +- c++/src/objtools/format/dbsource_item.cpp | 10 +- c++/src/objtools/format/feature_item.cpp | 501 +- c++/src/objtools/format/flat_file_config.cpp | 44 +- .../objtools/format/flat_file_generator.cpp | 77 +- c++/src/objtools/format/flat_qual_slots.cpp | 2 +- c++/src/objtools/format/flat_seqloc.cpp | 98 +- c++/src/objtools/format/ftable_formatter.cpp | 17 +- c++/src/objtools/format/gather_items.cpp | 479 +- c++/src/objtools/format/gbseq_formatter.cpp | 8 +- c++/src/objtools/format/genbank_formatter.cpp | 115 +- c++/src/objtools/format/genbank_gather.cpp | 4 +- c++/src/objtools/format/gene_finder.cpp | 4 +- c++/src/objtools/format/gff3_formatter.cpp | 949 - c++/src/objtools/format/gff_formatter.cpp | 591 - c++/src/objtools/format/gff_gather.cpp | 104 - c++/src/objtools/format/inst_info_map.cpp | 10 +- c++/src/objtools/format/item_formatter.cpp | 5 +- c++/src/objtools/format/keywords_item.cpp | 4 +- c++/src/objtools/format/locus_item.cpp | 2 +- c++/src/objtools/format/primary_item.cpp | 9 +- c++/src/objtools/format/qualifiers.cpp | 28 +- c++/src/objtools/format/reference_item.cpp | 96 +- c++/src/objtools/format/source_item.cpp | 70 +- c++/src/objtools/readers/CMakeLists.txt | 12 + .../readers/CMakeLists.xobjread.lib.txt | 25 + .../readers/CMakeLists.xobjreadex.lib.txt | 15 + .../objtools/readers/Makefile.xobjread.lib | 6 +- .../objtools/readers/Makefile.xobjreadex.lib | 4 +- c++/src/objtools/readers/agp_converter.cpp | 4 +- c++/src/objtools/readers/agp_read.cpp | 6 +- c++/src/objtools/readers/agp_util.cpp | 7 +- .../objtools/readers/agp_validate_reader.cpp | 24 +- c++/src/objtools/readers/aln_reader.cpp | 305 +- c++/src/objtools/readers/bed_reader.cpp | 22 +- c++/src/objtools/readers/fasta.cpp | 1014 +- .../objtools/readers/fasta_reader_utils.cpp | 710 + c++/src/objtools/readers/format_guess_ex.cpp | 14 +- c++/src/objtools/readers/gff2_data.cpp | 318 +- c++/src/objtools/readers/gff2_reader.cpp | 879 +- c++/src/objtools/readers/gff3_reader.cpp | 66 +- c++/src/objtools/readers/gff3_sofa.cpp | 51 +- c++/src/objtools/readers/gff_reader.cpp | 14 +- c++/src/objtools/readers/glimmer_reader.cpp | 4 +- c++/src/objtools/readers/gtf_reader.cpp | 535 +- c++/src/objtools/readers/gvf_reader.cpp | 12 +- c++/src/objtools/readers/idmapper_config.cpp | 4 +- .../objtools/readers/microarray_reader.cpp | 4 +- c++/src/objtools/readers/read_util.cpp | 8 +- c++/src/objtools/readers/reader_base.cpp | 23 +- c++/src/objtools/readers/readfeat.cpp | 885 +- c++/src/objtools/readers/rm_reader.cpp | 4 +- .../objtools/readers/source_mod_parser.cpp | 524 +- .../objtools/readers/struct_cmt_reader.cpp | 32 +- c++/src/objtools/readers/track_data.cpp | 17 +- .../objtools/readers/ucscregion_reader.cpp | 12 +- c++/src/objtools/readers/vcf_reader.cpp | 94 +- c++/src/objtools/readers/wiggle_reader.cpp | 4 +- .../CMakeLists.seqmasks_io.lib.txt | 15 + c++/src/objtools/seqmasks_io/CMakeLists.txt | 9 + c++/src/objtools/simple/CMakeLists.txt | 7 + .../simple/CMakeLists.xobjsimple.lib.txt | 14 + c++/src/serial/CMakeLists.cserial.lib.txt | 15 + c++/src/serial/CMakeLists.serial.lib.txt | 17 + c++/src/serial/CMakeLists.txt | 12 + c++/src/serial/classinfo.cpp | 15 +- .../datatool/CMakeLists.datatool.app.txt | 22 + c++/src/serial/datatool/CMakeLists.txt | 8 + c++/src/serial/datatool/Makefile.datatool.app | 4 +- c++/src/serial/datatool/aliasstr.cpp | 3 +- c++/src/serial/datatool/choiceptrstr.cpp | 4 +- c++/src/serial/datatool/choicestr.cpp | 3 +- c++/src/serial/datatool/classstr.cpp | 9 +- c++/src/serial/datatool/datatool.cpp | 30 +- c++/src/serial/datatool/datatool.hpp | 4 +- c++/src/serial/datatool/datatool.sh | 8 +- c++/src/serial/datatool/datatool_xml.sh | 8 +- c++/src/serial/datatool/dtdaux.cpp | 20 +- c++/src/serial/datatool/dtdaux.hpp | 10 +- c++/src/serial/datatool/dtdparser.cpp | 53 +- c++/src/serial/datatool/dtdparser.hpp | 7 +- c++/src/serial/datatool/enumtype.cpp | 2 +- c++/src/serial/datatool/exceptions.hpp | 2 +- c++/src/serial/datatool/filecode.cpp | 2 +- c++/src/serial/datatool/fileutil.cpp | 6 +- c++/src/serial/datatool/fileutil.hpp | 5 +- c++/src/serial/datatool/jsdlexer.cpp | 176 + c++/src/serial/datatool/jsdlexer.hpp | 59 + c++/src/serial/datatool/jsdparser.cpp | 506 + c++/src/serial/datatool/jsdparser.hpp | 82 + c++/src/serial/datatool/module.cpp | 2 +- c++/src/serial/datatool/srcutil.cpp | 2 +- c++/src/serial/datatool/statictype.cpp | 6 +- c++/src/serial/datatool/tokens.hpp | 11 +- .../datatool/traversal_code_generator.cpp | 2 +- c++/src/serial/datatool/traversal_node.cpp | 2 +- .../traversal_pattern_match_callback.cpp | 2 +- .../datatool/traversal_spec_file_parser.cpp | 2 +- c++/src/serial/datatool/type.cpp | 18 +- c++/src/serial/datatool/type.hpp | 16 +- c++/src/serial/datatool/typestr.cpp | 2 +- c++/src/serial/datatool/unitype.cpp | 14 +- c++/src/serial/datatool/wsdlparser.cpp | 4 +- c++/src/serial/datatool/wsdlstr.cpp | 2 +- c++/src/serial/datatool/xsdlexer.cpp | 2 +- c++/src/serial/datatool/xsdparser.cpp | 6 +- c++/src/serial/member.cpp | 14 +- c++/src/serial/objectio.cpp | 16 +- c++/src/serial/objistr.cpp | 12 +- c++/src/serial/objistrasn.cpp | 3 +- c++/src/serial/objistrasnb.cpp | 38 +- c++/src/serial/objistrjson.cpp | 151 +- c++/src/serial/objistrxml.cpp | 148 +- c++/src/serial/objostrasn.cpp | 10 +- c++/src/serial/objostrasnb.cpp | 36 +- c++/src/serial/objostrjson.cpp | 75 +- c++/src/serial/objostrxml.cpp | 90 +- c++/src/serial/objstack.cpp | 53 +- c++/src/serial/rpcbase.cpp | 33 +- c++/src/serial/serial.cpp | 10 +- c++/src/serial/typeinfo.cpp | 5 +- c++/src/util/CMakeLists.txt | 21 + c++/src/util/CMakeLists.util.lib.txt | 16 + c++/src/util/Makefile.in | 4 +- c++/src/util/bitset/CMakeLists.txt | 9 + c++/src/util/bytesrc.cpp | 2 +- c++/src/util/compress/CMakeLists.txt | 15 + .../compress/api/CMakeLists.compress.lib.txt | 13 + c++/src/util/compress/api/CMakeLists.txt | 7 + c++/src/util/compress/api/archive.cpp | 30 +- c++/src/util/compress/api/bzip2.cpp | 223 +- c++/src/util/compress/api/compress.cpp | 9 +- c++/src/util/compress/api/lzo.cpp | 190 +- c++/src/util/compress/api/stream.cpp | 105 +- c++/src/util/compress/api/tar.cpp | 79 +- c++/src/util/compress/api/zlib.cpp | 448 +- .../compress/bzip2/CMakeLists.bzip2.lib.txt | 8 + c++/src/util/compress/bzip2/CMakeLists.txt | 7 + c++/src/util/compress/zlib/CMakeLists.txt | 7 + .../compress/zlib/CMakeLists.zlib.lib.txt | 10 + .../util/creaders/CMakeLists.creaders.lib.txt | 6 + c++/src/util/creaders/CMakeLists.txt | 7 + c++/src/util/creaders/alnread.c | 43 +- c++/src/util/ddump_viewer.cpp | 6 +- c++/src/util/distribution.cpp | 6 +- c++/src/util/format_guess.cpp | 224 +- c++/src/util/mutex_pool.cpp | 6 +- c++/src/util/rangelist.cpp | 4 +- c++/src/util/regexp/CMakeLists.regexp.lib.txt | 14 + .../util/regexp/CMakeLists.test_pcre.app.txt | 13 + c++/src/util/regexp/CMakeLists.txt | 10 + .../util/sequtil/CMakeLists.sequtil.lib.txt | 11 + c++/src/util/sequtil/CMakeLists.txt | 8 + c++/src/util/strbuffer.cpp | 2 +- c++/src/util/stream_source.cpp | 9 +- c++/src/util/tables/CMakeLists.tables.lib.txt | 8 + c++/src/util/tables/CMakeLists.txt | 9 + c++/src/util/thread_pool.cpp | 4 +- c++/src/util/util_misc.cpp | 32 +- c++/src/util/xregexp/CMakeLists.txt | 8 + .../util/xregexp/CMakeLists.xregexp.lib.txt | 11 + ...CMakeLists.xregexp_template_tester.lib.txt | 9 + debian/changelog | 16 + debian/control | 5 +- debian/copyright | 15 + debian/patches/fix_lib_deps | 146 +- debian/patches/hurd_fixes | 4 +- debian/patches/no_multiarch_rpath | 4 +- debian/patches/suppress_gnutls_version_check | 8 +- debian/patches/use_pie_for_apps | 16 +- debian/rules | 4 +- 1916 files changed, 205115 insertions(+), 59046 deletions(-) create mode 100644 c++/include/algo/blast/api/blastp_kmer_options.hpp create mode 100644 c++/include/algo/blast/core/spliced_hits.h create mode 100644 c++/include/algo/blast/format/blast_async_format.hpp create mode 100644 c++/include/algo/blast/proteinkmer/blastkmer.hpp create mode 100644 c++/include/algo/blast/proteinkmer/blastkmerindex.hpp create mode 100644 c++/include/algo/blast/proteinkmer/blastkmeroptions.hpp create mode 100644 c++/include/algo/blast/proteinkmer/blastkmerresults.hpp create mode 100644 c++/include/algo/blast/proteinkmer/blastkmerutils.hpp create mode 100644 c++/include/algo/blast/proteinkmer/kblastapi.hpp create mode 100644 c++/include/algo/blast/proteinkmer/mhfile.hpp create mode 100644 c++/include/connect/ncbi_iprange.h create mode 100644 c++/include/connect/ncbi_ipv6.h create mode 100644 c++/include/connect/ncbi_localip.h create mode 100644 c++/include/connect/ncbi_mbedtls.h create mode 100644 c++/include/connect/ncbi_tls.h rename c++/{src => include}/corelib/teamcity_messages.h (96%) create mode 100644 c++/include/db/error_codes.hpp create mode 100644 c++/include/db/sqlite/sqlitewrapp.hpp create mode 100644 c++/include/objects/id2/ID2_Reply_Data.hpp create mode 100644 c++/include/objects/seq/so_map.hpp create mode 100644 c++/include/objects/trackmgr/primary_snp.hpp create mode 100644 c++/include/objmgr/util/autodef.hpp rename c++/include/{objtools/edit => objmgr/util}/autodef_available_modifier.hpp (93%) rename c++/include/{objtools/edit => objmgr/util}/autodef_feature_clause.hpp (97%) rename c++/include/{objtools/edit => objmgr/util}/autodef_feature_clause_base.hpp (96%) rename c++/include/{objtools/edit => objmgr/util}/autodef_mod_combo.hpp (95%) create mode 100644 c++/include/objmgr/util/autodef_options.hpp create mode 100644 c++/include/objmgr/util/autodef_source_desc.hpp rename c++/include/{objtools/edit => objmgr/util}/autodef_source_group.hpp (91%) create mode 100644 c++/include/objmgr/util/feature_edit.hpp create mode 100644 c++/include/objmgr/util/indexer.hpp rename c++/include/objtools/{format/gff_gather.hpp => edit/autodef_with_tax.hpp} (53%) create mode 100644 c++/include/objtools/edit/gap_trim.hpp delete mode 100644 c++/include/objtools/format/gff3_formatter.hpp delete mode 100644 c++/include/objtools/format/gff_formatter.hpp create mode 100644 c++/include/objtools/readers/fasta_reader_utils.hpp create mode 100644 c++/include/util/bitset/bmsparsevec.h create mode 100644 c++/include/util/bitset/bmsparsevec_algo.h create mode 100644 c++/include/util/bitset/bmsparsevec_serial.h create mode 100644 c++/include/util/row_reader.hpp create mode 100644 c++/include/util/row_reader.inl create mode 100644 c++/include/util/row_reader_base.hpp create mode 100644 c++/include/util/row_reader_char_delimited.hpp create mode 100644 c++/include/util/row_reader_excel_csv.hpp create mode 100644 c++/include/util/row_reader_iana_csv.hpp create mode 100644 c++/include/util/row_reader_iana_tsv.hpp create mode 100644 c++/include/util/row_reader_ncbi_tsv.hpp create mode 100755 c++/scripts/common/impl/define_random_macros.sh create mode 100644 c++/scripts/common/impl/ncbicxx_build_info.py create mode 100644 c++/scripts/common/impl/yaml.py create mode 100644 c++/scripts/projects/clog.lst create mode 100644 c++/scripts/projects/cobalt/post_build/blast_utils.py create mode 100644 c++/scripts/projects/cobalt/post_build/macosx/large-Blue_ncbi_logo.tiff create mode 100755 c++/scripts/projects/cobalt/post_build/macosx/ncbi-cobalt.sh create mode 100644 c++/scripts/projects/cobalt/post_build/macosx/uninstall_ncbi_cobalt.zip create mode 100644 c++/scripts/projects/cobalt/post_build/macosx/welcome.txt create mode 100755 c++/scripts/projects/cobalt/post_build/make_installers.py create mode 100755 c++/scripts/projects/cobalt/post_build/rpm/make_rpm.py create mode 100644 c++/scripts/projects/cobalt/post_build/rpm/ncbi-cobalt.spec create mode 100644 c++/scripts/projects/cobalt/post_build/win/EnvVarUpdate.nsh create mode 100644 c++/scripts/projects/cobalt/post_build/win/make_win.py create mode 100755 c++/scripts/projects/cobalt/post_build/win/ncbi-cobalt.nsi create mode 100644 c++/scripts/projects/cobalt/post_build/win/ncbilogo.ico create mode 100644 c++/scripts/projects/cobalt/post_build/win/unix2dos.nsh create mode 100755 c++/scripts/projects/igblast/edit_imgt_file.pl create mode 100644 c++/scripts/projects/testres-testapp/ChangeLog create mode 100644 c++/scripts/projects/testres-testapp/LICENSE create mode 100644 c++/scripts/projects/testres-testapp/Manifest create mode 100644 c++/scripts/projects/testres-testapp/README create mode 100644 c++/scripts/projects/testres-testapp/components.link create mode 100644 c++/scripts/projects/testres-testapp/project.lst create mode 100644 c++/scripts/projects/testres-testcgi/ChangeLog create mode 100644 c++/scripts/projects/testres-testcgi/LICENSE create mode 100644 c++/scripts/projects/testres-testcgi/Manifest create mode 100644 c++/scripts/projects/testres-testcgi/README create mode 100644 c++/scripts/projects/testres-testcgi/components.link create mode 100644 c++/scripts/projects/testres-testcgi/project.lst create mode 100644 c++/src/CMakeLists.txt create mode 100644 c++/src/algo/CMakeLists.txt create mode 100644 c++/src/algo/blast/CMakeLists.txt create mode 100644 c++/src/algo/blast/api/CMakeLists.txt create mode 100644 c++/src/algo/blast/api/CMakeLists.xblast.lib.txt create mode 100644 c++/src/algo/blast/api/blastp_kmer_options.cpp create mode 100644 c++/src/algo/blast/blastinput/CMakeLists.blastinput.lib.txt create mode 100644 c++/src/algo/blast/blastinput/CMakeLists.txt create mode 100644 c++/src/algo/blast/blastinput/unit_test/CMakeLists.blastinput_unit_test.app.txt create mode 100644 c++/src/algo/blast/blastinput/unit_test/CMakeLists.txt create mode 100644 c++/src/algo/blast/blastinput/unit_test/data/paired_reads.fastc create mode 100644 c++/src/algo/blast/composition_adjustment/CMakeLists.composition_adjustment.lib.txt create mode 100644 c++/src/algo/blast/composition_adjustment/CMakeLists.txt create mode 100644 c++/src/algo/blast/core/CMakeLists.blast.lib.txt create mode 100644 c++/src/algo/blast/core/CMakeLists.blast.objs.txt create mode 100644 c++/src/algo/blast/core/CMakeLists.txt create mode 100644 c++/src/algo/blast/core/spliced_hits.c create mode 100644 c++/src/algo/blast/dbindex/CMakeLists.txt create mode 100644 c++/src/algo/blast/dbindex/CMakeLists.xalgoblastdbindex.lib.txt create mode 100644 c++/src/algo/blast/dbindex/makeindex/CMakeLists.makeindex.app.txt create mode 100644 c++/src/algo/blast/dbindex/makeindex/CMakeLists.txt create mode 100644 c++/src/algo/blast/format/CMakeLists.txt create mode 100644 c++/src/algo/blast/format/CMakeLists.xblastformat.lib.txt create mode 100644 c++/src/algo/blast/format/blast_async_format.cpp create mode 100644 c++/src/algo/blast/igblast/CMakeLists.igblast.lib.txt create mode 100644 c++/src/algo/blast/igblast/CMakeLists.txt create mode 100644 c++/src/algo/blast/proteinkmer/CMakeLists.proteinkmer.lib.txt create mode 100644 c++/src/algo/blast/proteinkmer/CMakeLists.txt create mode 100644 c++/src/algo/blast/proteinkmer/Makefile.in create mode 100644 c++/src/algo/blast/proteinkmer/Makefile.proteinkmer.lib create mode 100644 c++/src/algo/blast/proteinkmer/blastkmer.cpp create mode 100644 c++/src/algo/blast/proteinkmer/blastkmerindex.cpp rename c++/{include/connect/services/netstorage_impl.hpp => src/algo/blast/proteinkmer/blastkmeroptions.cpp} (68%) create mode 100644 c++/src/algo/blast/proteinkmer/blastkmerresults.cpp create mode 100644 c++/src/algo/blast/proteinkmer/blastkmerutils.cpp create mode 100644 c++/src/algo/blast/proteinkmer/kblastapi.cpp create mode 100644 c++/src/algo/blast/proteinkmer/mhfile.cpp create mode 100644 c++/src/algo/blast/proteinkmer/pearson.cpp create mode 100644 c++/src/algo/blast/proteinkmer/pearson.hpp create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/Makefile.in create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/Makefile.proteinkmer_unit_test.app create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/129295.fsa create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/129295.iupacaa create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/129295.ncbieaa create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/129295.stdaa create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/129296.ncbieaa create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.phr create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pin create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pnd create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pni create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pog create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.psd create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.psi create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.psq create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/allX.asn create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/bad.asn create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/manyXs.phr create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/manyXs.pin create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/manyXs.pog create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/manyXs.psd create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/manyXs.psi create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/manyXs.psq create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.phr create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pin create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pkd create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pki create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pnd create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pni create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pog create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.psd create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.psi create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.psq create mode 100644 c++/src/algo/blast/proteinkmer/unit_test/proteinkmer_unit_test.cpp create mode 100644 c++/src/algo/blast/unit_tests/CMakeLists.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.aalookup_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.aascan_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.bl2seq_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.blast_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.blast_unit_test_util.lib.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.blastdiag_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.blastengine_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.blastextend_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.blastfilter_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.blasthits_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.blastoptions_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.blastsetup_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.delta_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.gapinfo_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.gencode_singleton_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.hspfilter_besthit_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.hspfilter_culling_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.hspstream_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.linkhsp_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.magicblast_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.msa2pssm_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.ntlookup_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.ntscan_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.optionshandle_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.phiblast_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.prelimsearch_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.psibl2seq_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.psiblast_iteration_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.psiblast_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.pssmcreate_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.pssmenginefreqratios_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.querydata_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.queryinfo_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.redoalignment_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.remote_blast_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.rps_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.scoreblk_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.search_strategy_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.seqalign_util.lib.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.seqinfosrc_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.seqsrc_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.setupfactory_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.split_query_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.stat_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.subj_ranges_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.traceback_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.tracebacksearch_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.uniform_search_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/api/CMakeLists.version_reference_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/blast_format/CMakeLists.blast_format_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/blast_format/CMakeLists.txt create mode 100644 c++/src/algo/blast/unit_tests/blast_format/blast_format_unit_test.cpp create mode 100644 c++/src/algo/blast/unit_tests/blastdb/CMakeLists.bdbloader_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/blastdb/CMakeLists.txt create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/CMakeLists.seqdb_unit_test.app.txt create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/CMakeLists.txt create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/empty-mask-data-db.naa create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/empty-mask-data-db.nab create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/empty-mask-data-db.nac create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/empty-mask-data-db.nhr create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/empty-mask-data-db.nin create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/empty-mask-data-db.nog create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/empty-mask-data-db.nsd create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/empty-mask-data-db.nsi create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/empty-mask-data-db.nsq create mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/testfile1.sqlite delete mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/wb1206.gis.txt delete mode 100644 c++/src/algo/blast/unit_tests/seqdb_reader/data/wb1206.long.gis.txt create mode 100644 c++/src/algo/dustmask/CMakeLists.txt create mode 100644 c++/src/algo/dustmask/CMakeLists.xalgodustmask.lib.txt create mode 100644 c++/src/algo/segmask/CMakeLists.txt create mode 100644 c++/src/algo/segmask/CMakeLists.xalgosegmask.lib.txt create mode 100644 c++/src/algo/winmask/CMakeLists.txt create mode 100644 c++/src/algo/winmask/CMakeLists.xalgowinmask.lib.txt create mode 100644 c++/src/app/CMakeLists.txt create mode 100644 c++/src/app/blast/CMakeLists.blast_app_util.lib.txt create mode 100644 c++/src/app/blast/CMakeLists.blast_formatter.app.txt create mode 100644 c++/src/app/blast/CMakeLists.blastn.app.txt create mode 100644 c++/src/app/blast/CMakeLists.blastp.app.txt create mode 100644 c++/src/app/blast/CMakeLists.blastx.app.txt create mode 100644 c++/src/app/blast/CMakeLists.deltablast.app.txt create mode 100644 c++/src/app/blast/CMakeLists.legacy_blast.txt create mode 100644 c++/src/app/blast/CMakeLists.psiblast.app.txt create mode 100644 c++/src/app/blast/CMakeLists.rpsblast.app.txt create mode 100644 c++/src/app/blast/CMakeLists.rpstblastn.app.txt create mode 100644 c++/src/app/blast/CMakeLists.seedtop.app.txt create mode 100644 c++/src/app/blast/CMakeLists.tblastn.app.txt create mode 100644 c++/src/app/blast/CMakeLists.tblastx.app.txt create mode 100644 c++/src/app/blast/CMakeLists.txt create mode 100644 c++/src/app/blast/CMakeLists.update_blastdb.txt create mode 100644 c++/src/app/blastdb/CMakeLists.blastdb_aliastool.app.txt create mode 100644 c++/src/app/blastdb/CMakeLists.blastdbcheck.app.txt create mode 100644 c++/src/app/blastdb/CMakeLists.blastdbcmd.app.txt create mode 100644 c++/src/app/blastdb/CMakeLists.blastdbcp.app.txt create mode 100644 c++/src/app/blastdb/CMakeLists.convert2blastmask.app.txt create mode 100644 c++/src/app/blastdb/CMakeLists.makeblastdb.app.txt create mode 100644 c++/src/app/blastdb/CMakeLists.makeprofiledb.app.txt create mode 100644 c++/src/app/blastdb/CMakeLists.txt create mode 100644 c++/src/app/dustmasker/CMakeLists.dustmasker.app.txt create mode 100644 c++/src/app/dustmasker/CMakeLists.txt create mode 100644 c++/src/app/segmasker/CMakeLists.segmasker.app.txt create mode 100644 c++/src/app/segmasker/CMakeLists.txt create mode 100644 c++/src/app/winmasker/CMakeLists.txt create mode 100644 c++/src/app/winmasker/CMakeLists.windowmasker_2.2.22_adapter.txt create mode 100644 c++/src/app/winmasker/CMakeLists.winmasker.app.txt create mode 100644 c++/src/build-system/CMakeLists.txt create mode 100644 c++/src/build-system/cmake/CMakeChecks.BerkeleyDB.cmake create mode 100644 c++/src/build-system/cmake/CMakeChecks.basic-checks.cmake create mode 100644 c++/src/build-system/cmake/CMakeChecks.boost.cmake mode change 100755 => 100644 c++/src/build-system/cmake/CMakeChecks.cmake create mode 100644 c++/src/build-system/cmake/CMakeChecks.compiler.cmake create mode 100644 c++/src/build-system/cmake/CMakeChecks.compress.cmake create mode 100644 c++/src/build-system/cmake/CMakeChecks.final-message.cmake create mode 100644 c++/src/build-system/cmake/CMakeChecks.image.cmake create mode 100644 c++/src/build-system/cmake/CMakeChecks.os.cmake create mode 100644 c++/src/build-system/cmake/CMakeChecks.pcre.cmake create mode 100644 c++/src/build-system/cmake/CMakeChecks.sqlite3.cmake create mode 100644 c++/src/build-system/cmake/CMakeChecks.wxwidgets.cmake delete mode 100755 c++/src/build-system/cmake/CMakeLists.defaults.cmake create mode 100644 c++/src/build-system/cmake/CMakeMacros.cmake create mode 100644 c++/src/build-system/cmake/FindBerkeleyDB.cmake create mode 100644 c++/src/build-system/cmake/FindExternalLibrary.cmake create mode 100644 c++/src/build-system/cmake/FindFTGL.cmake create mode 100644 c++/src/build-system/cmake/FindLZO.cmake create mode 100644 c++/src/build-system/cmake/FindMongoCXX.cmake create mode 100644 c++/src/build-system/cmake/FindMysql.cmake create mode 100644 c++/src/build-system/cmake/FindOSMesa.cmake mode change 100755 => 100644 c++/src/build-system/cmake/FindPCRE.cmake create mode 100644 c++/src/build-system/cmake/FindSqlite3.cmake create mode 100644 c++/src/build-system/cmake/FindwxWidgets.cmake create mode 100644 c++/src/build-system/cmake/HunterGate.cmake create mode 100644 c++/src/build-system/cmake/Sqlite3Config.cmake create mode 100755 c++/src/build-system/cmake/cmake-configure create mode 100644 c++/src/build-system/cmake/config.cmake.h.in create mode 100755 c++/src/build-system/cmake/configure-custom.sh create mode 100644 c++/src/build-system/cmake/ncbi-defaults/ncbi-berkeleydb-config.cmake create mode 100644 c++/src/build-system/cmake/ncbi-defaults/ncbi-ftgl-config.cmake create mode 100644 c++/src/build-system/cmake/ncbi-defaults/ncbi-glew-config.cmake create mode 100644 c++/src/build-system/cmake/ncbi-defaults/ncbi-gnutls-config.cmake create mode 100644 c++/src/build-system/cmake/ncbi-defaults/ncbi-libxml2-config.cmake create mode 100644 c++/src/build-system/cmake/ncbi-defaults/ncbi-libxslt-config.cmake create mode 100644 c++/src/build-system/cmake/ncbi-defaults/ncbi-lzo-config.cmake create mode 100644 c++/src/build-system/cmake/ncbi-defaults/ncbi-opengl-config.cmake create mode 100644 c++/src/build-system/cmake/ncbi-defaults/ncbi-osmesa-config.cmake create mode 100644 c++/src/build-system/cmake/ncbiconf_msvc_site.h.in create mode 100644 c++/src/build-system/project_tree_builder/CMakeLists.project_tree_builder.app.txt create mode 100644 c++/src/build-system/project_tree_builder/CMakeLists.txt create mode 100644 c++/src/build-system/project_tree_builder/msbuild/CMakeLists.txt create mode 100644 c++/src/build-system/run_with_cd_reporter.py.in create mode 100644 c++/src/cgi/CMakeLists.cgi.lib.txt create mode 100644 c++/src/cgi/CMakeLists.fcgi.lib.txt create mode 100644 c++/src/cgi/CMakeLists.txt create mode 100644 c++/src/connect/CMakeLists.connect.lib.txt create mode 100644 c++/src/connect/CMakeLists.connssl.lib.txt create mode 100644 c++/src/connect/CMakeLists.txt create mode 100644 c++/src/connect/CMakeLists.xconnect.lib.txt create mode 100644 c++/src/connect/CMakeLists.xthrserv.lib.txt create mode 100644 c++/src/connect/CMakeLists.xxconnect.lib.txt create mode 100644 c++/src/connect/Makefile.connssl.lib.unix create mode 100644 c++/src/connect/mbedtls/aes.c create mode 100644 c++/src/connect/mbedtls/aesni.c create mode 100644 c++/src/connect/mbedtls/apache-2.0.txt create mode 100644 c++/src/connect/mbedtls/arc4.c create mode 100644 c++/src/connect/mbedtls/asn1parse.c create mode 100644 c++/src/connect/mbedtls/asn1write.c create mode 100644 c++/src/connect/mbedtls/base64.c create mode 100644 c++/src/connect/mbedtls/bignum.c create mode 100644 c++/src/connect/mbedtls/blowfish.c create mode 100644 c++/src/connect/mbedtls/camellia.c create mode 100644 c++/src/connect/mbedtls/ccm.c create mode 100644 c++/src/connect/mbedtls/certs.c create mode 100644 c++/src/connect/mbedtls/cipher.c create mode 100644 c++/src/connect/mbedtls/cipher_wrap.c create mode 100644 c++/src/connect/mbedtls/cmac.c create mode 100644 c++/src/connect/mbedtls/ctr_drbg.c create mode 100644 c++/src/connect/mbedtls/debug.c create mode 100644 c++/src/connect/mbedtls/des.c create mode 100644 c++/src/connect/mbedtls/dhm.c create mode 100644 c++/src/connect/mbedtls/ecdh.c create mode 100644 c++/src/connect/mbedtls/ecdsa.c create mode 100644 c++/src/connect/mbedtls/ecjpake.c create mode 100644 c++/src/connect/mbedtls/ecp.c create mode 100644 c++/src/connect/mbedtls/ecp_curves.c create mode 100644 c++/src/connect/mbedtls/entropy.c create mode 100644 c++/src/connect/mbedtls/entropy_poll.c create mode 100644 c++/src/connect/mbedtls/error.c create mode 100644 c++/src/connect/mbedtls/gcm.c create mode 100644 c++/src/connect/mbedtls/havege.c create mode 100644 c++/src/connect/mbedtls/hmac_drbg.c create mode 100644 c++/src/connect/mbedtls/mbedtls/aes.h create mode 100644 c++/src/connect/mbedtls/mbedtls/aesni.h create mode 100644 c++/src/connect/mbedtls/mbedtls/arc4.h create mode 100644 c++/src/connect/mbedtls/mbedtls/asn1.h create mode 100644 c++/src/connect/mbedtls/mbedtls/asn1write.h create mode 100644 c++/src/connect/mbedtls/mbedtls/base64.h create mode 100644 c++/src/connect/mbedtls/mbedtls/bignum.h create mode 100644 c++/src/connect/mbedtls/mbedtls/blowfish.h create mode 100644 c++/src/connect/mbedtls/mbedtls/bn_mul.h create mode 100644 c++/src/connect/mbedtls/mbedtls/camellia.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ccm.h create mode 100644 c++/src/connect/mbedtls/mbedtls/certs.h create mode 100644 c++/src/connect/mbedtls/mbedtls/check_config.h create mode 100644 c++/src/connect/mbedtls/mbedtls/cipher.h create mode 100644 c++/src/connect/mbedtls/mbedtls/cipher_internal.h create mode 100644 c++/src/connect/mbedtls/mbedtls/cmac.h create mode 100644 c++/src/connect/mbedtls/mbedtls/compat-1.3.h create mode 100644 c++/src/connect/mbedtls/mbedtls/config.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ctr_drbg.h create mode 100644 c++/src/connect/mbedtls/mbedtls/debug.h create mode 100644 c++/src/connect/mbedtls/mbedtls/des.h create mode 100644 c++/src/connect/mbedtls/mbedtls/dhm.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ecdh.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ecdsa.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ecjpake.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ecp.h create mode 100644 c++/src/connect/mbedtls/mbedtls/entropy.h create mode 100644 c++/src/connect/mbedtls/mbedtls/entropy_poll.h create mode 100644 c++/src/connect/mbedtls/mbedtls/error.h create mode 100644 c++/src/connect/mbedtls/mbedtls/gcm.h create mode 100644 c++/src/connect/mbedtls/mbedtls/havege.h create mode 100644 c++/src/connect/mbedtls/mbedtls/hmac_drbg.h create mode 100644 c++/src/connect/mbedtls/mbedtls/md.h create mode 100644 c++/src/connect/mbedtls/mbedtls/md2.h create mode 100644 c++/src/connect/mbedtls/mbedtls/md4.h create mode 100644 c++/src/connect/mbedtls/mbedtls/md5.h create mode 100644 c++/src/connect/mbedtls/mbedtls/md_internal.h create mode 100644 c++/src/connect/mbedtls/mbedtls/memory_buffer_alloc.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ncbicxx_rename_mbedtls.h create mode 100644 c++/src/connect/mbedtls/mbedtls/net.h create mode 100644 c++/src/connect/mbedtls/mbedtls/net_sockets.h create mode 100644 c++/src/connect/mbedtls/mbedtls/oid.h create mode 100644 c++/src/connect/mbedtls/mbedtls/padlock.h create mode 100644 c++/src/connect/mbedtls/mbedtls/pem.h create mode 100644 c++/src/connect/mbedtls/mbedtls/pk.h create mode 100644 c++/src/connect/mbedtls/mbedtls/pk_internal.h create mode 100644 c++/src/connect/mbedtls/mbedtls/pkcs11.h create mode 100644 c++/src/connect/mbedtls/mbedtls/pkcs12.h create mode 100644 c++/src/connect/mbedtls/mbedtls/pkcs5.h create mode 100644 c++/src/connect/mbedtls/mbedtls/platform.h create mode 100644 c++/src/connect/mbedtls/mbedtls/platform_time.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ripemd160.h create mode 100644 c++/src/connect/mbedtls/mbedtls/rsa.h create mode 100644 c++/src/connect/mbedtls/mbedtls/sha1.h create mode 100644 c++/src/connect/mbedtls/mbedtls/sha256.h create mode 100644 c++/src/connect/mbedtls/mbedtls/sha512.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ssl.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ssl_cache.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ssl_ciphersuites.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ssl_cookie.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ssl_internal.h create mode 100644 c++/src/connect/mbedtls/mbedtls/ssl_ticket.h create mode 100644 c++/src/connect/mbedtls/mbedtls/threading.h rename c++/src/connect/{services/util.hpp => mbedtls/mbedtls/threading_alt.h} (76%) create mode 100644 c++/src/connect/mbedtls/mbedtls/timing.h create mode 100644 c++/src/connect/mbedtls/mbedtls/version.h create mode 100644 c++/src/connect/mbedtls/mbedtls/x509.h create mode 100644 c++/src/connect/mbedtls/mbedtls/x509_crl.h create mode 100644 c++/src/connect/mbedtls/mbedtls/x509_crt.h create mode 100644 c++/src/connect/mbedtls/mbedtls/x509_csr.h create mode 100644 c++/src/connect/mbedtls/mbedtls/xtea.h create mode 100644 c++/src/connect/mbedtls/mbedtls_md5.c create mode 100644 c++/src/connect/mbedtls/mbedtls_version.c create mode 100644 c++/src/connect/mbedtls/md.c create mode 100644 c++/src/connect/mbedtls/md2.c create mode 100644 c++/src/connect/mbedtls/md4.c create mode 100644 c++/src/connect/mbedtls/md_wrap.c create mode 100644 c++/src/connect/mbedtls/memory_buffer_alloc.c create mode 100644 c++/src/connect/mbedtls/net_sockets.c create mode 100644 c++/src/connect/mbedtls/oid.c create mode 100644 c++/src/connect/mbedtls/padlock.c create mode 100644 c++/src/connect/mbedtls/pem.c create mode 100644 c++/src/connect/mbedtls/pk.c create mode 100644 c++/src/connect/mbedtls/pk_wrap.c create mode 100644 c++/src/connect/mbedtls/pkcs11.c create mode 100644 c++/src/connect/mbedtls/pkcs12.c create mode 100644 c++/src/connect/mbedtls/pkcs5.c create mode 100644 c++/src/connect/mbedtls/pkparse.c create mode 100644 c++/src/connect/mbedtls/pkwrite.c create mode 100644 c++/src/connect/mbedtls/platform.c create mode 100644 c++/src/connect/mbedtls/ripemd160.c create mode 100644 c++/src/connect/mbedtls/rsa.c create mode 100644 c++/src/connect/mbedtls/sha1.c create mode 100644 c++/src/connect/mbedtls/sha256.c create mode 100644 c++/src/connect/mbedtls/sha512.c create mode 100644 c++/src/connect/mbedtls/ssl_cache.c create mode 100644 c++/src/connect/mbedtls/ssl_ciphersuites.c create mode 100644 c++/src/connect/mbedtls/ssl_cli.c create mode 100644 c++/src/connect/mbedtls/ssl_cookie.c create mode 100644 c++/src/connect/mbedtls/ssl_srv.c create mode 100644 c++/src/connect/mbedtls/ssl_ticket.c create mode 100644 c++/src/connect/mbedtls/ssl_tls.c create mode 100644 c++/src/connect/mbedtls/threading.c create mode 100644 c++/src/connect/mbedtls/timing.c create mode 100644 c++/src/connect/mbedtls/version_features.c create mode 100644 c++/src/connect/mbedtls/x509.c create mode 100644 c++/src/connect/mbedtls/x509_create.c create mode 100644 c++/src/connect/mbedtls/x509_crl.c create mode 100644 c++/src/connect/mbedtls/x509_crt.c create mode 100644 c++/src/connect/mbedtls/x509_csr.c create mode 100644 c++/src/connect/mbedtls/x509write_crt.c create mode 100644 c++/src/connect/mbedtls/x509write_csr.c create mode 100644 c++/src/connect/mbedtls/xtea.c create mode 100644 c++/src/connect/ncbi_iprange.c create mode 100644 c++/src/connect/ncbi_ipv6.c create mode 100644 c++/src/connect/ncbi_localip.c create mode 100644 c++/src/connect/ncbi_mbedtls.c create mode 100644 c++/src/connect/ncbi_namerd.c create mode 100644 c++/src/connect/ncbi_namerd.h create mode 100644 c++/src/connect/ncbi_once.h create mode 100644 c++/src/connect/ncbi_tls.c create mode 100644 c++/src/connect/services/CMakeLists.ncbi_xblobstorage_netcache.lib.txt create mode 100644 c++/src/connect/services/CMakeLists.ncbi_xcache_netcache.lib.txt create mode 100644 c++/src/connect/services/CMakeLists.txt create mode 100644 c++/src/connect/services/CMakeLists.xconnserv.lib.txt delete mode 100644 c++/src/connect/services/balancing.cpp delete mode 100644 c++/src/connect/services/pack_int.cpp delete mode 100644 c++/src/connect/services/pack_int.hpp create mode 100644 c++/src/corelib/CMakeLists.corelib.lib.txt create mode 100644 c++/src/corelib/CMakeLists.test_boost.lib.txt create mode 100644 c++/src/corelib/CMakeLists.test_mt.lib.txt create mode 100644 c++/src/corelib/CMakeLists.txt create mode 100644 c++/src/corelib/ncbi_stack_libunwind.cpp create mode 100644 c++/src/corelib/ncbi_version.xsd create mode 100644 c++/src/corelib/request_status.cpp create mode 100644 c++/src/db/CMakeLists.txt create mode 100644 c++/src/db/Makefile.in create mode 100644 c++/src/db/sqlite/CMakeLists.sqlitewrapp.lib.txt create mode 100644 c++/src/db/sqlite/CMakeLists.txt create mode 100644 c++/src/db/sqlite/Makefile.in create mode 100644 c++/src/db/sqlite/Makefile.sqlitewrapp.lib create mode 100644 c++/src/db/sqlite/sqlitewrapp.cpp create mode 100644 c++/src/dbapi/CMakeLists.dbapi.lib.txt create mode 100644 c++/src/dbapi/CMakeLists.txt create mode 100644 c++/src/dbapi/cache/CMakeLists.ncbi_xcache_dbapi.lib.txt create mode 100644 c++/src/dbapi/cache/CMakeLists.txt create mode 100644 c++/src/dbapi/driver/CMakeLists.dbapi_driver.lib.txt create mode 100644 c++/src/dbapi/driver/CMakeLists.txt create mode 100644 c++/src/dbapi/driver/dbapi_pool_balancer.cpp create mode 100644 c++/src/dbapi/driver/dbapi_pool_balancer.hpp create mode 100644 c++/src/dbapi/driver/odbc/CMakeLists.ncbi_xdbapi_odbc.lib.txt create mode 100644 c++/src/dbapi/driver/odbc/CMakeLists.txt create mode 100644 c++/src/html/CMakeLists.html.lib.txt create mode 100644 c++/src/html/CMakeLists.txt create mode 100644 c++/src/objects/CMakeLists.txt create mode 100644 c++/src/objects/access/CMakeLists.access.asn.txt create mode 100644 c++/src/objects/access/CMakeLists.txt create mode 100644 c++/src/objects/biblio/CMakeLists.biblio.asn.txt create mode 100644 c++/src/objects/biblio/CMakeLists.txt create mode 100644 c++/src/objects/biotree/CMakeLists.biotree.asn.txt create mode 100644 c++/src/objects/biotree/CMakeLists.txt create mode 100644 c++/src/objects/blast/CMakeLists.blast.asn.txt create mode 100644 c++/src/objects/blast/CMakeLists.txt create mode 100644 c++/src/objects/blast/CMakeLists.xnetblastcli.lib.txt create mode 100644 c++/src/objects/blastdb/CMakeLists.blastdb.asn.txt create mode 100644 c++/src/objects/blastdb/CMakeLists.txt create mode 100644 c++/src/objects/blastxml/CMakeLists.blastxml.asn.txt create mode 100644 c++/src/objects/blastxml/CMakeLists.txt create mode 100644 c++/src/objects/blastxml2/CMakeLists.blastxml2.asn.txt create mode 100644 c++/src/objects/blastxml2/CMakeLists.txt create mode 100644 c++/src/objects/cdd/CMakeLists.cdd.asn.txt create mode 100644 c++/src/objects/cdd/CMakeLists.txt create mode 100644 c++/src/objects/cn3d/CMakeLists.cn3d.asn.txt create mode 100644 c++/src/objects/cn3d/CMakeLists.txt create mode 100644 c++/src/objects/coords/CMakeLists.objcoords.asn.txt create mode 100644 c++/src/objects/coords/CMakeLists.txt create mode 100644 c++/src/objects/docsum/CMakeLists.docsum.asn.txt create mode 100644 c++/src/objects/docsum/CMakeLists.txt create mode 100644 c++/src/objects/entrez2/CMakeLists.entrez2.asn.txt create mode 100644 c++/src/objects/entrez2/CMakeLists.entrez2cli.lib.txt create mode 100644 c++/src/objects/entrez2/CMakeLists.txt create mode 100644 c++/src/objects/entrezgene/CMakeLists.entrezgene.asn.txt create mode 100644 c++/src/objects/entrezgene/CMakeLists.txt create mode 100644 c++/src/objects/featdef/CMakeLists.featdef.asn.txt create mode 100644 c++/src/objects/featdef/CMakeLists.txt create mode 100644 c++/src/objects/gbproj/CMakeLists.gbproj.asn.txt create mode 100644 c++/src/objects/gbproj/CMakeLists.txt create mode 100644 c++/src/objects/gbseq/CMakeLists.gbseq.asn.txt create mode 100644 c++/src/objects/gbseq/CMakeLists.txt create mode 100644 c++/src/objects/general/CMakeLists.general.asn.txt create mode 100644 c++/src/objects/general/CMakeLists.txt create mode 100644 c++/src/objects/genesbyloc/CMakeLists.genesbyloc.asn.txt create mode 100644 c++/src/objects/genesbyloc/CMakeLists.txt create mode 100644 c++/src/objects/genomecoll/CMakeLists.gencoll_client.asn.txt create mode 100644 c++/src/objects/genomecoll/CMakeLists.genome_collection.asn.txt create mode 100644 c++/src/objects/genomecoll/CMakeLists.txt create mode 100644 c++/src/objects/genomecoll/gc_cli/CMakeLists.gc_cli.app.txt create mode 100644 c++/src/objects/genomecoll/gc_cli/CMakeLists.txt create mode 100644 c++/src/objects/genomecoll/gc_cli/Makefile.gc_cli.app create mode 100644 c++/src/objects/genomecoll/gc_cli/Makefile.in create mode 100644 c++/src/objects/genomecoll/gc_cli/gc_cli.cpp create mode 100644 c++/src/objects/homologene/CMakeLists.homologene.asn.txt create mode 100644 c++/src/objects/homologene/CMakeLists.txt create mode 100644 c++/src/objects/id1/CMakeLists.id1.asn.txt create mode 100644 c++/src/objects/id1/CMakeLists.id1cli.lib.txt create mode 100644 c++/src/objects/id1/CMakeLists.txt create mode 100644 c++/src/objects/id2/CMakeLists.id2.asn.txt create mode 100644 c++/src/objects/id2/CMakeLists.id2cli.lib.txt create mode 100644 c++/src/objects/id2/CMakeLists.txt create mode 100644 c++/src/objects/id2/ID2_Reply_Data.cpp create mode 100644 c++/src/objects/insdseq/CMakeLists.insdseq.asn.txt create mode 100644 c++/src/objects/insdseq/CMakeLists.txt create mode 100644 c++/src/objects/macro/CMakeLists.macro.asn.txt create mode 100644 c++/src/objects/macro/CMakeLists.txt create mode 100644 c++/src/objects/medlars/CMakeLists.medlars.asn.txt create mode 100644 c++/src/objects/medlars/CMakeLists.txt create mode 100644 c++/src/objects/medline/CMakeLists.medline.asn.txt create mode 100644 c++/src/objects/medline/CMakeLists.txt create mode 100644 c++/src/objects/mim/CMakeLists.mim.asn.txt create mode 100644 c++/src/objects/mim/CMakeLists.txt create mode 100644 c++/src/objects/mla/CMakeLists.mla.asn.txt create mode 100644 c++/src/objects/mla/CMakeLists.mlacli.lib.txt create mode 100644 c++/src/objects/mla/CMakeLists.txt create mode 100644 c++/src/objects/mmdb/CMakeLists.mmdb.lib.txt create mode 100644 c++/src/objects/mmdb/CMakeLists.txt create mode 100644 c++/src/objects/ncbimime/CMakeLists.ncbimime.asn.txt create mode 100644 c++/src/objects/ncbimime/CMakeLists.txt create mode 100644 c++/src/objects/objprt/CMakeLists.objprt.asn.txt create mode 100644 c++/src/objects/objprt/CMakeLists.txt create mode 100644 c++/src/objects/omssa/CMakeLists.omssa.asn.txt create mode 100644 c++/src/objects/omssa/CMakeLists.txt create mode 100644 c++/src/objects/pcassay/CMakeLists.pcassay.asn.txt create mode 100644 c++/src/objects/pcassay/CMakeLists.txt create mode 100644 c++/src/objects/pcsubstance/CMakeLists.pcsubstance.asn.txt create mode 100644 c++/src/objects/pcsubstance/CMakeLists.txt create mode 100644 c++/src/objects/proj/CMakeLists.proj.asn.txt create mode 100644 c++/src/objects/proj/CMakeLists.txt create mode 100644 c++/src/objects/pub/CMakeLists.pub.asn.txt create mode 100644 c++/src/objects/pub/CMakeLists.txt create mode 100644 c++/src/objects/pubmed/CMakeLists.pubmed.asn.txt create mode 100644 c++/src/objects/pubmed/CMakeLists.txt create mode 100644 c++/src/objects/remap/CMakeLists.remap.asn.txt create mode 100644 c++/src/objects/remap/CMakeLists.remapcli.lib.txt create mode 100644 c++/src/objects/remap/CMakeLists.txt create mode 100644 c++/src/objects/scoremat/CMakeLists.scoremat.asn.txt create mode 100644 c++/src/objects/scoremat/CMakeLists.txt create mode 100644 c++/src/objects/seq/CMakeLists.seq.asn.txt create mode 100644 c++/src/objects/seq/CMakeLists.txt create mode 100644 c++/src/objects/seq/so_map.cpp create mode 100644 c++/src/objects/seqcode/CMakeLists.seqcode.asn.txt create mode 100644 c++/src/objects/seqcode/CMakeLists.txt create mode 100644 c++/src/objects/seqedit/CMakeLists.seqedit.asn.txt create mode 100644 c++/src/objects/seqedit/CMakeLists.txt create mode 100644 c++/src/objects/seqfeat/common_tax.inc create mode 100644 c++/src/objects/seqfeat/common_tax.txt create mode 100644 c++/src/objects/seqfeat/isolation_sources.inc create mode 100644 c++/src/objects/seqfeat/isolation_sources.txt create mode 100644 c++/src/objects/seqfeat/prepare_taxtable.sh create mode 100644 c++/src/objects/seqset/CMakeLists.seqset.asn.txt create mode 100644 c++/src/objects/seqset/CMakeLists.txt create mode 100644 c++/src/objects/seqsplit/CMakeLists.seqsplit.asn.txt create mode 100644 c++/src/objects/seqsplit/CMakeLists.txt create mode 100644 c++/src/objects/seqtest/CMakeLists.seqtest.asn.txt create mode 100644 c++/src/objects/seqtest/CMakeLists.txt create mode 100644 c++/src/objects/submit/CMakeLists.submit.asn.txt create mode 100644 c++/src/objects/submit/CMakeLists.txt create mode 100644 c++/src/objects/taxon1/CMakeLists.taxon1.asn.txt create mode 100644 c++/src/objects/taxon1/CMakeLists.txt create mode 100644 c++/src/objects/taxon3/CMakeLists.taxon3.asn.txt create mode 100644 c++/src/objects/taxon3/CMakeLists.txt create mode 100644 c++/src/objects/tinyseq/CMakeLists.tinyseq.asn.txt create mode 100644 c++/src/objects/tinyseq/CMakeLists.txt create mode 100644 c++/src/objects/trackmgr/CMakeLists.trackmgr.asn.txt create mode 100644 c++/src/objects/trackmgr/CMakeLists.trackmgrcli.lib.txt create mode 100644 c++/src/objects/trackmgr/CMakeLists.trackmgrgridcli.lib.txt create mode 100644 c++/src/objects/trackmgr/CMakeLists.txt create mode 100644 c++/src/objects/valerr/CMakeLists.txt create mode 100644 c++/src/objects/valerr/CMakeLists.valerr.asn.txt create mode 100644 c++/src/objects/valid/CMakeLists.txt create mode 100644 c++/src/objects/valid/CMakeLists.valid.asn.txt create mode 100644 c++/src/objects/variation/CMakeLists.txt create mode 100644 c++/src/objects/variation/CMakeLists.variation.asn.txt create mode 100644 c++/src/objects/varrep/CMakeLists.txt create mode 100644 c++/src/objects/varrep/CMakeLists.varrep.asn.txt create mode 100644 c++/src/objmgr/CMakeLists.objmgr.lib.txt create mode 100644 c++/src/objmgr/CMakeLists.txt create mode 100644 c++/src/objmgr/split/CMakeLists.id2_split.lib.txt create mode 100644 c++/src/objmgr/split/CMakeLists.txt create mode 100644 c++/src/objmgr/util/CMakeLists.txt create mode 100644 c++/src/objmgr/util/CMakeLists.util.lib.txt rename c++/src/{objtools/edit => objmgr/util}/autodef.cpp (90%) rename c++/src/{objtools/edit => objmgr/util}/autodef_available_modifier.cpp (99%) rename c++/src/{objtools/edit => objmgr/util}/autodef_feature_clause.cpp (98%) rename c++/src/{objtools/edit => objmgr/util}/autodef_feature_clause_base.cpp (99%) rename c++/src/{objtools/edit => objmgr/util}/autodef_mod_combo.cpp (95%) rename c++/src/{objtools/edit => objmgr/util}/autodef_options.cpp (99%) rename c++/src/{objtools/edit => objmgr/util}/autodef_source_desc.cpp (98%) rename c++/src/{objtools/edit => objmgr/util}/autodef_source_group.cpp (93%) create mode 100644 c++/src/objmgr/util/feature_edit.cpp create mode 100644 c++/src/objmgr/util/indexer.cpp create mode 100644 c++/src/objtools/CMakeLists.txt create mode 100644 c++/src/objtools/align_format/CMakeLists.align_format.lib.txt create mode 100644 c++/src/objtools/align_format/CMakeLists.txt create mode 100644 c++/src/objtools/align_format/unit_test/CMakeLists.align_format_unit_test.app.txt create mode 100644 c++/src/objtools/align_format/unit_test/CMakeLists.txt create mode 100644 c++/src/objtools/alnmgr/CMakeLists.alnmgr.lib.txt create mode 100644 c++/src/objtools/alnmgr/CMakeLists.txt create mode 100644 c++/src/objtools/blast/CMakeLists.txt create mode 100644 c++/src/objtools/blast/blastdb_format/CMakeLists.blastdb_format.lib.txt create mode 100644 c++/src/objtools/blast/blastdb_format/CMakeLists.txt create mode 100644 c++/src/objtools/blast/blastdb_format/unit_test/CMakeLists.blastdb_format_unit_test.app.txt create mode 100644 c++/src/objtools/blast/blastdb_format/unit_test/CMakeLists.txt create mode 100644 c++/src/objtools/blast/gene_info_reader/CMakeLists.gene_info.lib.txt create mode 100644 c++/src/objtools/blast/gene_info_reader/CMakeLists.txt create mode 100644 c++/src/objtools/blast/gene_info_reader/demo/CMakeLists.gene_info_reader.app.txt create mode 100644 c++/src/objtools/blast/gene_info_reader/demo/CMakeLists.txt create mode 100644 c++/src/objtools/blast/gene_info_reader/unit_test/CMakeLists.gene_info_unit_test.app.txt create mode 100644 c++/src/objtools/blast/gene_info_reader/unit_test/CMakeLists.txt create mode 100644 c++/src/objtools/blast/seqdb_reader/CMakeLists.seqdb.lib.txt create mode 100644 c++/src/objtools/blast/seqdb_reader/CMakeLists.txt create mode 100644 c++/src/objtools/blast/seqdb_reader/demo/CMakeLists.seqdb_demo.app.txt create mode 100644 c++/src/objtools/blast/seqdb_reader/demo/CMakeLists.txt create mode 100644 c++/src/objtools/blast/seqdb_reader/test/CMakeLists.seqdb_perf.app.txt create mode 100644 c++/src/objtools/blast/seqdb_reader/test/CMakeLists.txt create mode 100644 c++/src/objtools/blast/seqdb_writer/CMakeLists.txt create mode 100644 c++/src/objtools/blast/seqdb_writer/CMakeLists.writedb.lib.txt create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/CMakeLists.txt create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/CMakeLists.writedb_unit_test.app.txt create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nhr create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nin create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nnd create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nni create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nog create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nsd create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nsi create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nsq create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.phr create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.pin create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.pnd create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.pni create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.pog create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.psd create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.psi create mode 100644 c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.psq create mode 100644 c++/src/objtools/blast/services/CMakeLists.blast_services.lib.txt create mode 100644 c++/src/objtools/blast/services/CMakeLists.txt create mode 100644 c++/src/objtools/blast/services/unit_test/CMakeLists.blast_services_unit_test.app.txt create mode 100644 c++/src/objtools/blast/services/unit_test/CMakeLists.txt create mode 100644 c++/src/objtools/cleanup/CMakeLists.cleanup.lib.txt create mode 100644 c++/src/objtools/cleanup/CMakeLists.txt create mode 100644 c++/src/objtools/data_loaders/CMakeLists.txt create mode 100644 c++/src/objtools/data_loaders/blastdb/CMakeLists.ncbi_xloader_blastdb.lib.txt create mode 100644 c++/src/objtools/data_loaders/blastdb/CMakeLists.ncbi_xloader_blastdb_rmt.lib.txt create mode 100644 c++/src/objtools/data_loaders/blastdb/CMakeLists.txt create mode 100644 c++/src/objtools/data_loaders/genbank/CMakeLists.ncbi_xloader_genbank.lib.txt create mode 100644 c++/src/objtools/data_loaders/genbank/CMakeLists.ncbi_xreader.lib.txt create mode 100644 c++/src/objtools/data_loaders/genbank/CMakeLists.txt create mode 100644 c++/src/objtools/data_loaders/genbank/cache/CMakeLists.ncbi_xreader_cache.lib.txt create mode 100644 c++/src/objtools/data_loaders/genbank/cache/CMakeLists.txt create mode 100644 c++/src/objtools/data_loaders/genbank/gicache/CMakeLists.ncbi_xreader_gicache.lib.txt create mode 100644 c++/src/objtools/data_loaders/genbank/gicache/CMakeLists.txt create mode 100644 c++/src/objtools/data_loaders/genbank/id1/CMakeLists.ncbi_xreader_id1.lib.txt create mode 100644 c++/src/objtools/data_loaders/genbank/id1/CMakeLists.txt create mode 100644 c++/src/objtools/data_loaders/genbank/id2/CMakeLists.ncbi_xreader_id2.lib.txt create mode 100644 c++/src/objtools/data_loaders/genbank/id2/CMakeLists.txt create mode 100644 c++/src/objtools/edit/CMakeLists.edit.lib.txt create mode 100644 c++/src/objtools/edit/CMakeLists.txt create mode 100644 c++/src/objtools/edit/autodef_with_tax.cpp create mode 100644 c++/src/objtools/edit/gap_trim.cpp create mode 100644 c++/src/objtools/format/CMakeLists.txt create mode 100644 c++/src/objtools/format/CMakeLists.xformat.lib.txt delete mode 100644 c++/src/objtools/format/gff3_formatter.cpp delete mode 100644 c++/src/objtools/format/gff_formatter.cpp delete mode 100644 c++/src/objtools/format/gff_gather.cpp create mode 100644 c++/src/objtools/readers/CMakeLists.txt create mode 100644 c++/src/objtools/readers/CMakeLists.xobjread.lib.txt create mode 100644 c++/src/objtools/readers/CMakeLists.xobjreadex.lib.txt create mode 100644 c++/src/objtools/readers/fasta_reader_utils.cpp create mode 100644 c++/src/objtools/seqmasks_io/CMakeLists.seqmasks_io.lib.txt create mode 100644 c++/src/objtools/seqmasks_io/CMakeLists.txt create mode 100644 c++/src/objtools/simple/CMakeLists.txt create mode 100644 c++/src/objtools/simple/CMakeLists.xobjsimple.lib.txt create mode 100644 c++/src/serial/CMakeLists.cserial.lib.txt create mode 100644 c++/src/serial/CMakeLists.serial.lib.txt create mode 100644 c++/src/serial/CMakeLists.txt create mode 100644 c++/src/serial/datatool/CMakeLists.datatool.app.txt create mode 100644 c++/src/serial/datatool/CMakeLists.txt create mode 100644 c++/src/serial/datatool/jsdlexer.cpp create mode 100644 c++/src/serial/datatool/jsdlexer.hpp create mode 100644 c++/src/serial/datatool/jsdparser.cpp create mode 100644 c++/src/serial/datatool/jsdparser.hpp create mode 100644 c++/src/util/CMakeLists.txt create mode 100644 c++/src/util/CMakeLists.util.lib.txt create mode 100644 c++/src/util/bitset/CMakeLists.txt create mode 100644 c++/src/util/compress/CMakeLists.txt create mode 100644 c++/src/util/compress/api/CMakeLists.compress.lib.txt create mode 100644 c++/src/util/compress/api/CMakeLists.txt create mode 100644 c++/src/util/compress/bzip2/CMakeLists.bzip2.lib.txt create mode 100644 c++/src/util/compress/bzip2/CMakeLists.txt create mode 100644 c++/src/util/compress/zlib/CMakeLists.txt create mode 100644 c++/src/util/compress/zlib/CMakeLists.zlib.lib.txt create mode 100644 c++/src/util/creaders/CMakeLists.creaders.lib.txt create mode 100644 c++/src/util/creaders/CMakeLists.txt create mode 100644 c++/src/util/regexp/CMakeLists.regexp.lib.txt create mode 100644 c++/src/util/regexp/CMakeLists.test_pcre.app.txt create mode 100644 c++/src/util/regexp/CMakeLists.txt create mode 100644 c++/src/util/sequtil/CMakeLists.sequtil.lib.txt create mode 100644 c++/src/util/sequtil/CMakeLists.txt create mode 100644 c++/src/util/tables/CMakeLists.tables.lib.txt create mode 100644 c++/src/util/tables/CMakeLists.txt create mode 100644 c++/src/util/xregexp/CMakeLists.txt create mode 100644 c++/src/util/xregexp/CMakeLists.xregexp.lib.txt create mode 100644 c++/src/util/xregexp/CMakeLists.xregexp_template_tester.lib.txt diff --git a/c++/compilers/cygwin/build.sh b/c++/compilers/cygwin/build.sh index 811deaea..51b892e9 100644 --- a/c++/compilers/cygwin/build.sh +++ b/c++/compilers/cygwin/build.sh @@ -1,5 +1,5 @@ #! /bin/sh -# $Id: build.sh 466738 2015-05-06 11:20:57Z ivanov $ +# $Id: build.sh 540404 2017-07-06 15:48:28Z ivanov $ # Author: Vladimir Ivanov (ivanov@ncbi.nlm.nih.gov) # # Build C++ Toolkit using Cygwin @@ -8,18 +8,14 @@ ########### Arguments script="$0" -cfgs="${1:-Debug DebugMT Release ReleaseMT}" +cfgs="${1:-DebugMT ReleaseMT}" arch=${2} ########### Global variables -cmd_Debug='--with-debug --without-mt --without-dll CFLAGS=-g0 CXXFLAGS=-g0' cmd_DebugMT='--with-debug --with-mt --without-dll CFLAGS=-g0 CXXFLAGS=-g0' -##cmd_DebugDLL='--with-debug --with-mt --with-dll' -cmd_Release='--without-debug --without-mt --without-dll' cmd_ReleaseMT='--without-debug --with-mt --without-dll' -##cmd_ReleaseDLL='--without-debug --with-mt --with-dll' cmd_common='--without-internal' timer="date +'%H:%M'" @@ -64,8 +60,11 @@ for cfg in $cfgs ; do echo "Build time: $start - `eval $timer`" # Build - - dir=`find . -maxdepth 1 -name "*-$cfg*" | head -1 | sed 's|^.*/||g'` + + dir="$cfg" + if [ ! -d "$dir" ] ; then + dir=`find . -maxdepth 1 -name "*-$cfg*" | head -1 | sed 's|^.*/||g'` + fi if [ -z "$dir" -o ! -d "$dir" ] ; then error "Build directory for \"$cfg\" configuration not found" fi diff --git a/c++/compilers/vs2013/datatool.bat b/c++/compilers/vs2013/datatool.bat index d4594fd7..2f67d6e4 100644 --- a/c++/compilers/vs2013/datatool.bat +++ b/c++/compilers/vs2013/datatool.bat @@ -1,5 +1,5 @@ @echo off -REM $Id: datatool.bat 430635 2014-03-27 17:34:42Z gouriano $ +REM $Id: datatool.bat 532246 2017-04-03 15:48:07Z gouriano $ REM =========================================================================== REM REM PUBLIC DOMAIN NOTICE @@ -87,6 +87,10 @@ for %%v in ("%DATATOOL_PATH%" "%TREE_ROOT%" "%BUILD_TREE_ROOT%" "%PTB_PLATFORM%" ) set DEFDT_VERSION_FILE=%TREE_ROOT%\src\build-system\datatool_version.txt set PTB_SLN=%BUILD_TREE_ROOT%\static\build\UtilityProjects\PTB.sln +set NCBICONF_MSVC=%TREE_ROOT%\include\common\config\ncbiconf_msvc_site.h +if exist "%NCBICONF_MSVC%" ( + set NCBICONF_MSVC= +) set DT=datatool.exe call "%BUILD_TREE_ROOT%\msvcvars.bat" @@ -156,7 +160,13 @@ if not exist "%DATATOOL_EXE%" ( echo Building %DT% locally, please wait echo ****************************************************************************** @echo %DEVENV% "%PTB_SLN%" /rebuild "ReleaseDLL|%PTB_PLATFORM%" /project "datatool.exe" + if not "%NCBICONF_MSVC%"=="" ( + echo // > "%NCBICONF_MSVC%" + ) %DEVENV% "%PTB_SLN%" /rebuild "ReleaseDLL|%PTB_PLATFORM%" /project "datatool.exe" + if not "%NCBICONF_MSVC%"=="" ( + del "%NCBICONF_MSVC%" + ) ) else ( echo ERROR: do not know how to build %DT% ) diff --git a/c++/compilers/vs2013/make.bat b/c++/compilers/vs2013/make.bat index 88d4e1ff..df6068d9 100644 --- a/c++/compilers/vs2013/make.bat +++ b/c++/compilers/vs2013/make.bat @@ -1,5 +1,5 @@ @ECHO OFF -REM $Id: make.bat 509501 2016-08-05 19:08:31Z fukanchi $ +REM $Id: make.bat 509141 2016-08-03 16:34:16Z gouriano $ REM =========================================================================== REM REM PUBLIC DOMAIN NOTICE diff --git a/c++/compilers/vs2013/ptb.bat b/c++/compilers/vs2013/ptb.bat index c7560219..525e116c 100644 --- a/c++/compilers/vs2013/ptb.bat +++ b/c++/compilers/vs2013/ptb.bat @@ -1,5 +1,5 @@ @echo off -REM $Id: ptb.bat 507295 2016-07-18 15:40:58Z gouriano $ +REM $Id: ptb.bat 532246 2017-04-03 15:48:07Z gouriano $ REM =========================================================================== REM REM PUBLIC DOMAIN NOTICE diff --git a/c++/compilers/vs2013/static/build/serial/datatool/datatool.exe.vcxproj b/c++/compilers/vs2013/static/build/serial/datatool/datatool.exe.vcxproj index 74f48f28..62888826 100644 --- a/c++/compilers/vs2013/static/build/serial/datatool/datatool.exe.vcxproj +++ b/c++/compilers/vs2013/static/build/serial/datatool/datatool.exe.vcxproj @@ -396,6 +396,18 @@ NCBI_USE_PCH;%(PreprocessorDefinitions) ncbi_pch.hpp + + NCBI_USE_PCH;%(PreprocessorDefinitions) + ncbi_pch.hpp + NCBI_USE_PCH;%(PreprocessorDefinitions) + ncbi_pch.hpp + + + NCBI_USE_PCH;%(PreprocessorDefinitions) + ncbi_pch.hpp + NCBI_USE_PCH;%(PreprocessorDefinitions) + ncbi_pch.hpp + NCBI_USE_PCH;%(PreprocessorDefinitions) ncbi_pch.hpp diff --git a/c++/compilers/vs2015/datatool.bat b/c++/compilers/vs2015/datatool.bat index 36a4feda..2f67d6e4 100644 --- a/c++/compilers/vs2015/datatool.bat +++ b/c++/compilers/vs2015/datatool.bat @@ -1,5 +1,5 @@ @echo off -REM $Id: datatool.bat 492980 2016-02-23 16:24:57Z gouriano $ +REM $Id: datatool.bat 532246 2017-04-03 15:48:07Z gouriano $ REM =========================================================================== REM REM PUBLIC DOMAIN NOTICE @@ -87,6 +87,10 @@ for %%v in ("%DATATOOL_PATH%" "%TREE_ROOT%" "%BUILD_TREE_ROOT%" "%PTB_PLATFORM%" ) set DEFDT_VERSION_FILE=%TREE_ROOT%\src\build-system\datatool_version.txt set PTB_SLN=%BUILD_TREE_ROOT%\static\build\UtilityProjects\PTB.sln +set NCBICONF_MSVC=%TREE_ROOT%\include\common\config\ncbiconf_msvc_site.h +if exist "%NCBICONF_MSVC%" ( + set NCBICONF_MSVC= +) set DT=datatool.exe call "%BUILD_TREE_ROOT%\msvcvars.bat" @@ -156,7 +160,13 @@ if not exist "%DATATOOL_EXE%" ( echo Building %DT% locally, please wait echo ****************************************************************************** @echo %DEVENV% "%PTB_SLN%" /rebuild "ReleaseDLL|%PTB_PLATFORM%" /project "datatool.exe" + if not "%NCBICONF_MSVC%"=="" ( + echo // > "%NCBICONF_MSVC%" + ) %DEVENV% "%PTB_SLN%" /rebuild "ReleaseDLL|%PTB_PLATFORM%" /project "datatool.exe" + if not "%NCBICONF_MSVC%"=="" ( + del "%NCBICONF_MSVC%" + ) ) else ( echo ERROR: do not know how to build %DT% ) diff --git a/c++/compilers/vs2015/make.bat b/c++/compilers/vs2015/make.bat index 88352cd1..66037480 100644 --- a/c++/compilers/vs2015/make.bat +++ b/c++/compilers/vs2015/make.bat @@ -1,5 +1,5 @@ @ECHO OFF -REM $Id: make.bat 509501 2016-08-05 19:08:31Z fukanchi $ +REM $Id: make.bat 509141 2016-08-03 16:34:16Z gouriano $ REM =========================================================================== REM REM PUBLIC DOMAIN NOTICE diff --git a/c++/compilers/vs2015/ptb.bat b/c++/compilers/vs2015/ptb.bat index 42dbd490..2039b594 100644 --- a/c++/compilers/vs2015/ptb.bat +++ b/c++/compilers/vs2015/ptb.bat @@ -1,5 +1,5 @@ @echo off -REM $Id: ptb.bat 507295 2016-07-18 15:40:58Z gouriano $ +REM $Id: ptb.bat 532246 2017-04-03 15:48:07Z gouriano $ REM =========================================================================== REM REM PUBLIC DOMAIN NOTICE diff --git a/c++/compilers/vs2015/static/build/serial/datatool/datatool.exe.vcxproj b/c++/compilers/vs2015/static/build/serial/datatool/datatool.exe.vcxproj index e1a2ba83..f1fda982 100644 --- a/c++/compilers/vs2015/static/build/serial/datatool/datatool.exe.vcxproj +++ b/c++/compilers/vs2015/static/build/serial/datatool/datatool.exe.vcxproj @@ -395,6 +395,18 @@ NCBI_USE_PCH;%(PreprocessorDefinitions) ncbi_pch.hpp + + NCBI_USE_PCH;%(PreprocessorDefinitions) + ncbi_pch.hpp + NCBI_USE_PCH;%(PreprocessorDefinitions) + ncbi_pch.hpp + + + NCBI_USE_PCH;%(PreprocessorDefinitions) + ncbi_pch.hpp + NCBI_USE_PCH;%(PreprocessorDefinitions) + ncbi_pch.hpp + NCBI_USE_PCH;%(PreprocessorDefinitions) ncbi_pch.hpp diff --git a/c++/compilers/xcode30_prj/configure b/c++/compilers/xcode30_prj/configure index 0346b2a2..0fb0a80d 100755 --- a/c++/compilers/xcode30_prj/configure +++ b/c++/compilers/xcode30_prj/configure @@ -1,6 +1,6 @@ #!/bin/sh -# $Id: configure 509262 2016-08-04 14:17:42Z ivanov $ +# $Id: configure 509208 2016-08-03 20:57:59Z ucko $ # Author: Andrei Gourianov, NCBI (gouriano@ncbi.nlm.nih.gov) #----------------------------------------------------------------------------- diff --git a/c++/compilers/xcode30_prj/datatool.sh b/c++/compilers/xcode30_prj/datatool.sh index ee141bc3..f760a3ee 100755 --- a/c++/compilers/xcode30_prj/datatool.sh +++ b/c++/compilers/xcode30_prj/datatool.sh @@ -1,5 +1,5 @@ #!/bin/sh -# $Id: datatool.sh 471603 2015-06-29 18:48:10Z ucko $ +# $Id: datatool.sh 532256 2017-04-03 16:04:28Z gouriano $ # =========================================================================== # # PUBLIC DOMAIN NOTICE @@ -43,6 +43,10 @@ for v in "$DATATOOL_PATH" "$TREE_ROOT" "$BUILD_TREE_ROOT"; do done DEFDT_VERSION_FILE="${TREE_ROOT}/src/build-system/datatool_version.txt" PTB_SLN="${BUILD_TREE_ROOT}/static/UtilityProjects/PTB.xcodeproj" +NCBICONF_MSVC="${TREE_ROOT}/include/common/config/ncbiconf_xcode_site.h" +if test -e "${NCBICONF_MSVC}"; then + NCBICONF_MSVC= +fi DT="datatool" # ------------------------------------------------------------------------- @@ -94,7 +98,13 @@ if test ! -x "$DATATOOL_EXE"; then cmd="`dirname $0`/xcodebuild.sh -project $PTB_SLN -target $DT -configuration ReleaseDLL" echo "$cmd" echo "==============================================================================" + if test "${NCBICONF_MSVC}" != ""; then + echo // > "${NCBICONF_MSVC}" + fi $cmd + if test "${NCBICONF_MSVC}" != ""; then + rm "${NCBICONF_MSVC}" + fi else echo "==============================================================================" echo "Using PREBUILT $DT at $DATATOOL_EXE" diff --git a/c++/compilers/xcode30_prj/static/UtilityProjects/PTB.xcodeproj/project.pbxproj b/c++/compilers/xcode30_prj/static/UtilityProjects/PTB.xcodeproj/project.pbxproj index 3b6a417d..1ed01af8 100644 --- a/c++/compilers/xcode30_prj/static/UtilityProjects/PTB.xcodeproj/project.pbxproj +++ b/c++/compilers/xcode30_prj/static/UtilityProjects/PTB.xcodeproj/project.pbxproj @@ -764,6 +764,8 @@ ABCDABCDABCDABCD0000008C ABCDABCDABCDABCD0000008E ABCDABCDABCDABCD00000090 + ABCDABCDABCDABCD1000008E + ABCDABCDABCDABCD10000090 isa PBXGroup @@ -1787,6 +1789,46 @@ isa PBXBuildFile + ABCDABCDABCDABCD1000008E + + isa + PBXFileReference + lastKnownFileType + sourcecode.cpp.cpp + name + jsdlexer.cpp + path + ../../../../src/serial/datatool/jsdlexer.cpp + sourceTree + SOURCE_ROOT + + ABCDABCDABCDABCD1000008F + + fileRef + ABCDABCDABCDABCD1000008E + isa + PBXBuildFile + + ABCDABCDABCDABCD10000090 + + isa + PBXFileReference + lastKnownFileType + sourcecode.cpp.cpp + name + jsdparser.cpp + path + ../../../../src/serial/datatool/jsdparser.cpp + sourceTree + SOURCE_ROOT + + ABCDABCDABCDABCD10000091 + + fileRef + ABCDABCDABCDABCD10000090 + isa + PBXBuildFile + ABCDABCDABCDABCD00000092 isa @@ -2475,6 +2517,8 @@ ABCDABCDABCDABCD0000008D ABCDABCDABCDABCD0000008F ABCDABCDABCDABCD00000091 + ABCDABCDABCDABCD1000008F + ABCDABCDABCDABCD10000091 isa PBXSourcesBuildPhase diff --git a/c++/include/algo/blast/api/blast_options.hpp b/c++/include/algo/blast/api/blast_options.hpp index 50331db8..eb788eb8 100644 --- a/c++/include/algo/blast/api/blast_options.hpp +++ b/c++/include/algo/blast/api/blast_options.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_options.hpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_options.hpp 544251 2017-08-21 14:19:11Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,10 +34,7 @@ #ifndef ALGO_BLAST_API___BLAST_OPTION__HPP #define ALGO_BLAST_API___BLAST_OPTION__HPP -#include -#include -#include -#include +#include #include #include @@ -59,6 +56,7 @@ BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) class CSeq_loc; + class CBlast4_parameters; END_SCOPE(objects) /** @addtogroup AlgoBlast @@ -241,6 +239,27 @@ public: /// silently void SetWindowMaskerDatabase(const char* db); + /// Returns true if next-generation read quality filtering is turned on + bool GetReadQualityFiltering() const; + + /// Turn on/off next-generation read quality filtering with deafult + /// parameters + void SetReadQualityFiltering(bool val = true); + + /// Get maximum fraction of ambiguous bases for next-generation read + /// quality filtering + double GetReadMaxFractionAmbiguous() const; + + /// Set maximum fraction of ambiguous bases for next-generation read + /// quality filtering + void SetReadMaxFractionAmbiguous(double val); + + /// Get minimum dimer entropy for next-generation read quality filtering + int GetReadMinDimerEntropy() const; + + /// Set minimum dimer entropy for next-generation read quality filtering + void SetReadMinDimerEntropy(int val); + #ifndef SKIP_DOXYGEN_PROCESSING objects::ENa_strand GetStrandOption() const; void SetStrandOption(objects::ENa_strand s); @@ -316,9 +335,18 @@ public: int GetCutoffScore() const; void SetCutoffScore(int s); + // Raw score cutoff as a linear function of query length + // x[0] + x[1] * length + vector GetCutoffScoreCoeffs() const; + void SetCutoffScoreCoeffs(const vector& c); + double GetPercentIdentity() const; void SetPercentIdentity(double p); + // Set max edit distance for mapping NGS sequences + int GetMaxEditDistance() const; + void SetMaxEditDistance(int e); + double GetQueryCovHspPerc() const; void SetQueryCovHspPerc(double p); diff --git a/c++/include/algo/blast/api/blast_options_builder.hpp b/c++/include/algo/blast/api/blast_options_builder.hpp index 54541cfa..4b133d31 100644 --- a/c++/include/algo/blast/api/blast_options_builder.hpp +++ b/c++/include/algo/blast/api/blast_options_builder.hpp @@ -1,7 +1,7 @@ #ifndef ALGO_BLAST_API___BLAST_OPTIONS_BUILDER__HPP #define ALGO_BLAST_API___BLAST_OPTIONS_BUILDER__HPP -/* $Id: blast_options_builder.hpp 481634 2015-10-14 15:21:43Z fongah2 $ +/* $Id: blast_options_builder.hpp 518798 2016-11-07 22:49:25Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,6 +34,9 @@ /// Declares the CBlastOptionsBuilder class. #include +#include +#include + /** @addtogroup AlgoBlast * diff --git a/c++/include/algo/blast/api/blast_results.hpp b/c++/include/algo/blast/api/blast_results.hpp index 8e4262f2..584977f9 100644 --- a/c++/include/algo/blast/api/blast_results.hpp +++ b/c++/include/algo/blast/api/blast_results.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_results.hpp 480884 2015-10-05 17:23:10Z jianye $ +/* $Id: blast_results.hpp 542542 2017-08-01 12:44:33Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -83,15 +83,10 @@ public: ~CBlastAncillaryData(); /// Copy-constructor - CBlastAncillaryData(const CBlastAncillaryData& rhs) { - do_copy(rhs); - } + CBlastAncillaryData(const CBlastAncillaryData& rhs); /// Assignment operator - CBlastAncillaryData& operator=(const CBlastAncillaryData& rhs) { - do_copy(rhs); - return *this; - } + CBlastAncillaryData& operator=(const CBlastAncillaryData& rhs); /// Retrieve gumbel parameters const Blast_GumbelBlk * GetGumbelBlk() const { diff --git a/c++/include/algo/blast/api/blast_seqinfosrc.hpp b/c++/include/algo/blast/api/blast_seqinfosrc.hpp index 5b21f1d6..dc67c57e 100644 --- a/c++/include/algo/blast/api/blast_seqinfosrc.hpp +++ b/c++/include/algo/blast/api/blast_seqinfosrc.hpp @@ -1,7 +1,7 @@ #ifndef ALGO_BLAST_API__BLAST_SEQINFOSRC__HPP #define ALGO_BLAST_API__BLAST_SEQINFOSRC__HPP -/* $Id: blast_seqinfosrc.hpp 499693 2016-04-27 17:19:56Z madden $ +/* $Id: blast_seqinfosrc.hpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -105,8 +105,6 @@ public: /// return true. virtual bool CanReturnPartialSequence() const = 0; - /// Allow implementations to provide a facility to release memory - virtual void GarbageCollect() {}; }; END_SCOPE(blast) diff --git a/c++/include/algo/blast/api/blast_seqinfosrc_aux.hpp b/c++/include/algo/blast/api/blast_seqinfosrc_aux.hpp index d50a10e5..6944e760 100644 --- a/c++/include/algo/blast/api/blast_seqinfosrc_aux.hpp +++ b/c++/include/algo/blast/api/blast_seqinfosrc_aux.hpp @@ -1,7 +1,7 @@ #ifndef ALGO_BLAST_API___BLAST_SEQINFOSRC_AUX__HPP #define ALGO_BLAST_API___BLAST_SEQINFOSRC_AUX__HPP -/* $Id: blast_seqinfosrc_aux.hpp 520431 2016-11-28 18:26:12Z ivanov $ +/* $Id: blast_seqinfosrc_aux.hpp 520163 2016-11-23 13:38:30Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/algo/blast/api/blast_types.hpp b/c++/include/algo/blast/api/blast_types.hpp index 475684c0..55a9a0fe 100644 --- a/c++/include/algo/blast/api/blast_types.hpp +++ b/c++/include/algo/blast/api/blast_types.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_types.hpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_types.hpp 535507 2017-05-09 15:35:47Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -71,6 +71,7 @@ enum EProgram { eDeltaBlast, ///< Delta Blast eVecScreen, ///< Vector screening eMapper, ///< Jumper alignment for mapping + eKBlastp, ///< KMER screening and BLASTP eBlastProgramMax ///< Undefined program }; diff --git a/c++/include/algo/blast/api/blastp_kmer_options.hpp b/c++/include/algo/blast/api/blastp_kmer_options.hpp new file mode 100644 index 00000000..1184d5db --- /dev/null +++ b/c++/include/algo/blast/api/blastp_kmer_options.hpp @@ -0,0 +1,123 @@ +#ifndef ALGO_BLAST_API___BLASTP_KMER_OPTIONS_HPP +#define ALGO_BLAST_API___BLASTP_KMER_OPTIONS_HPP + +/* $Id: blastp_kmer_options.hpp 535510 2017-05-09 16:22:23Z madden $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Tom Madden + * + */ + +/// @file blastp_kmer_options.hpp +/// Declares the CBlastpKmerOptionsHandle class. + +#include + +/** @addtogroup AlgoBlast + * + * @{ + */ + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(blast) + +/// Handle to the KMER BLASTP options +/// +/// Adapter class for KMER BLASTP comparisons. +/// Exposes an interface to allow manipulation the options that are relevant to +/// this type of search. + +class NCBI_XBLAST_EXPORT CBlastpKmerOptionsHandle : + public CBlastAdvancedProteinOptionsHandle +{ +public: + + /// Creates object with default options set + CBlastpKmerOptionsHandle(EAPILocality locality = CBlastOptions::eLocal); + CBlastpKmerOptionsHandle(CRef opt):CBlastAdvancedProteinOptionsHandle(opt) {} + ~CBlastpKmerOptionsHandle() {} + + /******************* KMER specific options *******************/ + /// Returns threshold for Jaccard distance (range: 0-1) + double GetThresh() const { + return m_Thresh; + } + /// Sets Threshold for Jaccard distance + /// @param thresh Jaccard threshold [in] + void SetThresh(double thresh = 0.1) { + m_Thresh = thresh; + } + /// Returns the number of hits to initiate calculation of Jaccard distance + int GetMinHits() const { + return m_MinHits; + } + /// Sets the number of hits ot initiate calculation of Jaccard distance + /// @param hits Minimum number of LSH hits to proceed with subject [in] + void SetMinHits(int minhits = 1) { + m_MinHits = minhits; + } + /// Gets the max number of candidate matches to process with BLAST + int GetCandidateSeqs() const { + return m_Candidates; + } + /// Sets the max number of candidate matches to process with BLAST + /// @candidates max number of target sequences to process with BLAST [in] + void SetCandidateSeqs(int candidates = 1000) { + m_Candidates = candidates; + } + +protected: + /// Set the program and service name for remote blast. + virtual void SetRemoteProgramAndService_Blast3() + { + m_Opts->SetRemoteProgramAndService_Blast3("kblastp", "plain"); + } + +private: + /// Disallow copy constructor + CBlastpKmerOptionsHandle(const CBlastpKmerOptionsHandle& rhs); + /// Disallow assignment operator + CBlastpKmerOptionsHandle& operator=(const CBlastpKmerOptionsHandle& rhs); + + /// Jaccard distance cutoff + double m_Thresh; + + /// number of hits to initiate calculation of Jaccard distance in LSH + int m_MinHits; + + /// Number of target seqs to process with BLAST + int m_Candidates; + + +}; + +END_SCOPE(blast) +END_NCBI_SCOPE + + +/* @} */ + + +#endif /* ALGO_BLAST_API___BLASTP_KMER_OPTIONS_HPP */ diff --git a/c++/include/algo/blast/api/magicblast.hpp b/c++/include/algo/blast/api/magicblast.hpp index faca1c9e..39b74f81 100644 --- a/c++/include/algo/blast/api/magicblast.hpp +++ b/c++/include/algo/blast/api/magicblast.hpp @@ -1,4 +1,4 @@ -/* $Id: magicblast.hpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: magicblast.hpp 545407 2017-09-06 15:05:55Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,11 +33,13 @@ #ifndef ALGO_BLAST_API___MAGICBLAST__HPP #define ALGO_BLAST_API___MAGICBLAST__HPP +#include #include #include #include #include #include +#include /** @addtogroup AlgoBlast * @@ -49,6 +51,7 @@ BEGIN_SCOPE(blast) // Forward declarations class IQueryFactory; +class CMagicBlastResultSet; /// BLAST RNA-Seq mapper class NCBI_XBLAST_EXPORT CMagicBlast : public CObject, public CThreadable @@ -73,6 +76,8 @@ public: /// Run the RNA-Seq mapping CRef Run(void); + CRef RunEx(void); + TSearchMessages GetSearchMessages(void) const {return m_Messages;} @@ -86,8 +91,21 @@ protected: /// Perform sanity checks on input arguments void x_Validate(void); + int x_Run(void); + + + CRef x_BuildSeqAlignSet( + const BlastMappingResults* results); + + CRef x_BuildResultSet( + const BlastMappingResults* results); + + /// Create results - CRef x_CreateSeqAlignSet(BlastMappingResults* results); + static CRef x_CreateSeqAlignSet(const HSPChain* results, + CRef qdata, + CRef seqinfo_src, + const BlastQueryInfo* query_info); private: /// Queries @@ -99,6 +117,9 @@ private: /// Options to configure the search CRef m_Options; + /// Object that runs BLAST search + CRef m_PrelimSearch; + /// Internal data strctures CRef m_InternalData; @@ -107,6 +128,155 @@ private: }; +/// Magic-BLAST results for a single query/read or a pair of reads +class NCBI_XBLAST_EXPORT CMagicBlastResults : public CObject +{ +public: + + /// Information flags about mapping results + typedef enum { + /// Read is unaligned + fUnaligned = 1, + + /// Read did not pass quality filtering + fFiltered = 1 << 1 + } EResultsInfo; + + typedef int TResultsInfo; + + /// Constructor for a pair + CMagicBlastResults(CConstRef query_id, CConstRef mate_id, + CRef aligns, + const TMaskedQueryRegions* query_mask = NULL, + const TMaskedQueryRegions* mate_mask = NULL, + int query_length = 0, + int mate_length = 0); + + + /// Constructor for a single read + CMagicBlastResults(CConstRef query_id, + CRef aligns, + const TMaskedQueryRegions* query_mask = NULL, + int query_length = 0); + + /// Get alignments + CConstRef GetSeqAlign(void) const {return m_Aligns;} + + /// Get non-const alignments + CRef SetSeqAlign(void) {return m_Aligns;} + + /// Are alignments computed for paired reads + bool IsPaired(void) const {return m_Paired;} + + /// Get alignment flags for the query + TResultsInfo GetFirstInfo(void) const {return m_FirstInfo;} + + /// Get alignment flags for the mate + TResultsInfo GetLastInfo(void) const {return m_LastInfo;} + + /// Get query sequence id + const CSeq_id& GetQueryId(void) const {return *m_QueryId;} + + /// Get sequence id of the first segment of a paired read + const CSeq_id& GetFirstId(void) const {return GetQueryId();} + + /// Get sequence id of the last sequence of a paired read + const CSeq_id& GetLastId(void) const {return *m_MateId;} + + /// Is the query aligned + bool FirstAligned(void) const {return (m_FirstInfo & fUnaligned) != 0;} + + /// Is the mate aligned + bool LastAligned(void) const {return (m_LastInfo & fUnaligned) != 0;} + +private: + void x_SetInfo(int first_length, + const TMaskedQueryRegions* first_masks, + int last_length = 0, + const TMaskedQueryRegions* last_masks = NULL); + + +private: + /// Query id + CConstRef m_QueryId; + + /// Mate id if results are for paired reads + CConstRef m_MateId; + + /// Alignments for a single or a pair of reads + CRef m_Aligns; + + /// True if results are for paired reads + bool m_Paired; + + /// Alignment flags for the query + TResultsInfo m_FirstInfo; + + /// Alignment flags for the mate + TResultsInfo m_LastInfo; +}; + + +/// Results of Magic-BLAST mapping +class NCBI_XBLAST_EXPORT CMagicBlastResultSet : public CObject +{ +public: + + /// data type contained by this container + typedef CRef value_type; + + /// size_type type definition + typedef vector::size_type size_type; + + /// const_iterator type definition + typedef vector::const_iterator const_iterator; + + /// iterator type definition + typedef vector::iterator iterator; + + /// Create an empty results set + CMagicBlastResultSet(void) {} + + /// Get all results as a single Seq-align-set object + CRef GetFlatResults(void); + + /// Get number of results, provided to facilitate STL-style iteration + size_type size() const {return m_Results.size();} + + /// Is the container empty + bool empty() const {return size() == 0;} + + /// Returns const iteartor to the beginning of the container, + /// provided to facilitate STL-style iteartion + const_iterator begin() const {return m_Results.begin();} + + /// Returns const iterator to the end of the container + const_iterator end() const {return m_Results.end();} + + /// Returns iterator to the beginning of the container + iterator begin() {return m_Results.begin();} + + /// Returns iterator to the end of the container + iterator end() {return m_Results.end();} + + /// Clear all results + void clear() {m_Results.clear();} + + /// Reserve memory for a number of result elemetns + void reserve(size_t num) {m_Results.reserve(num);} + + /// Add results to the end of the container + void push_back(CMagicBlastResultSet::value_type& element) + {m_Results.push_back(element);} + +private: + CMagicBlastResultSet(const CMagicBlastResultSet&); + CMagicBlastResultSet& operator=(const CMagicBlastResultSet&); + + vector< CRef > m_Results; +}; + + END_SCOPE(blast) END_NCBI_SCOPE diff --git a/c++/include/algo/blast/api/magicblast_options.hpp b/c++/include/algo/blast/api/magicblast_options.hpp index 446ca5e8..7069c844 100644 --- a/c++/include/algo/blast/api/magicblast_options.hpp +++ b/c++/include/algo/blast/api/magicblast_options.hpp @@ -1,7 +1,7 @@ #ifndef ALGO_BLAST_API___MAGIC_BLAST_OPTIONS__HPP #define ALGO_BLAST_API___MAGIC_BLAST_OPTIONS__HPP -/* $Id: magicblast_options.hpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: magicblast_options.hpp 544251 2017-08-21 14:19:11Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -98,6 +98,28 @@ public: /******************* Query setup options ************************/ + /// Return true if query quality filtering is on + bool GetReadQualityFiltering() const + { return m_Opts->GetReadQualityFiltering(); } + + /// Turn on/off query quaility filtering with default parameters + void SetReadQualityFiltering(bool val = true) + { m_Opts->SetReadQualityFiltering(val); } + + /// Get maximum fraction of ambiguous bases for query quality filtering + double GetMaxFractionAmbiguous() const + { return m_Opts->GetReadMaxFractionAmbiguous(); } + + /// Get maximum fraction of ambiguous bases for query quality filtering + void SetMaxFractionAmbiguous(double val) + { m_Opts->SetReadMaxFractionAmbiguous(val); } + + /// Get mininum dimer entropy for query quality filtering + int GetMinDimerEntropy() const { return m_Opts->GetReadMinDimerEntropy(); } + + /// Set minimum dimer entropy for query quality filtering + void SetMinDimerEntropy(int val) { m_Opts->SetReadMinDimerEntropy(val); } + /******************* Initial word options ***********************/ @@ -110,6 +132,12 @@ public: /******************* Gapped extension options *******************/ + /// Return x-dropoff parameter for gapped alignment + int GetGapXDropoff() const { return m_Opts->GetGapXDropoff(); } + + /// Set x-dropoff parameter for gapped alignment + /// @param d x-dropoff value [in] + void SetGapXDropoff(int d) { m_Opts->SetGapXDropoff(d); } /************************ Scoring options ************************/ @@ -141,6 +169,20 @@ public: /// @param s cutoff score [in] void SetCutoffScore(int s) { m_Opts->SetCutoffScore(s); } + /// Get coefficients for alignment cutoff score as a linear function of + /// query length: x[0] + x[1] * length + vector GetCutoffScoreCoeffs() + { return m_Opts->GetCutoffScoreCoeffs(); } + + /// Set coefficients for alignment cutoff score as a linear function of + /// query length: x[0] + x[1] * length + /// @param c function coefficients [in] + void SetCutoffScoreCoeffs(const vector& c) + { m_Opts->SetCutoffScoreCoeffs(c); } + + int GetMaxEditDistance() const { return m_Opts->GetMaxEditDistance(); } + void SetMaxEditDistance(int e) { m_Opts->SetMaxEditDistance(e); } + /************************ Mapping options ************************/ diff --git a/c++/include/algo/blast/api/prelim_stage.hpp b/c++/include/algo/blast/api/prelim_stage.hpp index f54bd091..4f50ead5 100644 --- a/c++/include/algo/blast/api/prelim_stage.hpp +++ b/c++/include/algo/blast/api/prelim_stage.hpp @@ -1,4 +1,4 @@ -/* $Id: prelim_stage.hpp 358496 2012-04-03 13:25:45Z merezhuk $ +/* $Id: prelim_stage.hpp 533643 2017-04-18 18:08:51Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -66,7 +66,8 @@ public: /// @note we don't own the BlastSeqSrc CBlastPrelimSearch(CRef query_factory, CRef options, - CRef db); + CRef db, + size_t num_threads = 1); /// Constructor which takes a PSSM and an already initialized BlastSeqSrc /// object @@ -128,6 +129,10 @@ public: // bool Run( vector > > & results ); + /// Return query masks + const TSeqLocInfoVector& GetQueryMasks(void) const + {return m_MasksForAllQueries;} + private: /// Prohibit copy constructor CBlastPrelimSearch(const CBlastPrelimSearch& rhs); @@ -140,10 +145,12 @@ private: /// @param options BLAST algorithm options [in] /// @param pssm PSSM to initialize PSI-BLAST /// @param seqsrc Wrapper for source of database sequences [in] + /// @param num_threads Number of threads to use [in] void x_Init(CRef query_factory, CRef options, CConstRef pssm, - BlastSeqSrc* seqsrc); + BlastSeqSrc* seqsrc, + size_t num_threads = 1); /// Runs the preliminary search in multi-threaded mode /// @param internal_data internal preliminary data structures diff --git a/c++/include/algo/blast/api/remote_blast.hpp b/c++/include/algo/blast/api/remote_blast.hpp index f0aee84d..8fd50a2e 100644 --- a/c++/include/algo/blast/api/remote_blast.hpp +++ b/c++/include/algo/blast/api/remote_blast.hpp @@ -1,7 +1,7 @@ #ifndef ALGO_BLAST_API___REMOTE_BLAST__HPP #define ALGO_BLAST_API___REMOTE_BLAST__HPP -/* $Id: remote_blast.hpp 494040 2016-03-03 14:36:13Z fongah2 $ +/* $Id: remote_blast.hpp 542542 2017-08-01 12:44:33Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -546,7 +546,7 @@ private: }; /// The default timeout is 3.5 hours. - const int x_DefaultTimeout(void); + int x_DefaultTimeout(void); /// Uses the file to populate results. /// The file may be text or binary ASN.1 or XML. type is automatically detected. diff --git a/c++/include/algo/blast/api/seqinfosrc_seqdb.hpp b/c++/include/algo/blast/api/seqinfosrc_seqdb.hpp index 8b5a75a1..668e4f61 100644 --- a/c++/include/algo/blast/api/seqinfosrc_seqdb.hpp +++ b/c++/include/algo/blast/api/seqinfosrc_seqdb.hpp @@ -1,7 +1,7 @@ #ifndef ALGO_BLAST_API__SEQINFOSRC_SEQDB__HPP #define ALGO_BLAST_API__SEQINFOSRC_SEQDB__HPP -/* $Id: seqinfosrc_seqdb.hpp 499693 2016-04-27 17:19:56Z madden $ +/* $Id: seqinfosrc_seqdb.hpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -113,8 +113,6 @@ public: /// return true. virtual bool CanReturnPartialSequence() const {return false;} - /// Invoke CSeqDB's garbage collector - virtual void GarbageCollect(); private: mutable CRef m_iSeqDb; ///< BLAST database object diff --git a/c++/include/algo/blast/api/setup_factory.hpp b/c++/include/algo/blast/api/setup_factory.hpp index 310fd126..3bbc6f81 100644 --- a/c++/include/algo/blast/api/setup_factory.hpp +++ b/c++/include/algo/blast/api/setup_factory.hpp @@ -1,4 +1,4 @@ -/* $Id: setup_factory.hpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: setup_factory.hpp 542542 2017-08-01 12:44:33Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -235,13 +235,16 @@ public: /// CreateRpsStructures [in] /// @param seqsrc BlastSeqSrc structure, only needed when performing /// megablast indexed-database searches [in] + /// @param num_threads Number of threads to use. Multithreaded + /// implementation is only avaliable for Magic-BLAST lookup tables. [in] static LookupTableWrap* CreateLookupTable(CRef query_data, const CBlastOptionsMemento* opts_memento, BlastScoreBlk* score_blk, CRef< CBlastSeqLocWrap > lookup_segments, const CBlastRPSInfo* rps_info = NULL, - BlastSeqSrc* seqsrc = NULL); + BlastSeqSrc* seqsrc = NULL, + size_t num_threads = 1); /// Create and initialize the BlastDiagnostics structure for /// single-threaded applications @@ -363,7 +366,7 @@ struct NCBI_XBLAST_EXPORT SDatabaseScanData : public CObject inline void CThreadable::SetNumberOfThreads(size_t nthreads) { - m_NumThreads = nthreads == 0 ? kMinNumThreads : nthreads; + m_NumThreads = nthreads == 0 ? static_cast(kMinNumThreads) : nthreads; } inline size_t diff --git a/c++/include/algo/blast/blastinput/blast_args.hpp b/c++/include/algo/blast/blastinput/blast_args.hpp index 1d1afe2c..89bc5571 100644 --- a/c++/include/algo/blast/blastinput/blast_args.hpp +++ b/c++/include/algo/blast/blastinput/blast_args.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_args.hpp 514850 2016-09-26 17:23:32Z ivanov $ +/* $Id: blast_args.hpp 546749 2017-09-21 11:22:02Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -111,7 +111,8 @@ class NCBI_BLASTINPUT_EXPORT CStdCmdLineArgs : public IBlastCmdLineArgs public: /** Default constructor */ CStdCmdLineArgs() : m_InputStream(0), m_OutputStream(0), - m_GzipEnabled(false) {}; + m_GzipEnabled(false), + m_SRAaccessionEnabled(false){}; /** Interface method, \sa IBlastCmdLineArgs::SetArgumentDescriptions */ virtual void SetArgumentDescriptions(CArgDescriptions& arg_desc); /** Interface method, \sa IBlastCmdLineArgs::SetArgumentDescriptions */ @@ -131,6 +132,11 @@ public: */ void SetGzipEnabled(bool g) {m_GzipEnabled = g;} + /** enables sra accession flag + * @param g If true "-sra" will be added (not compatible with "-query") + */ + void SetSRAaccessionEnabled(bool g) {m_SRAaccessionEnabled = g;} + private: CNcbiIstream* m_InputStream; ///< Application's input stream CNcbiOstream* m_OutputStream; ///< Application's output stream @@ -144,6 +150,10 @@ private: /// If true input file will be decompressed with gzip if filename ends /// with ".gz" bool m_GzipEnabled; + + /// If true, option to specify SRA runs will be presented as possible + /// query input + bool m_SRAaccessionEnabled; }; /** Argument class to populate an application's name and description */ @@ -637,7 +647,7 @@ class NCBI_BLASTINPUT_EXPORT CKBlastpArgs : public IBlastCmdLineArgs public: /// Constructor - CKBlastpArgs(void) : m_JDistance(0.05), m_MinHits(0), m_TargetSeqs(5000) {} + CKBlastpArgs(void) : m_JDistance(0.10), m_MinHits(0), m_CandidateSeqs(1000) {} /// Our virtual destructor virtual ~CKBlastpArgs() {} @@ -658,8 +668,8 @@ public: /// The database string GetDatabase(void) {return m_DbIndex;} - /// Number of target sequences. - int GetTargetSeqs(void) {return m_TargetSeqs;} + /// Number of candidate sequences to attempt with BLASTP + int GetCandidateSeqs(void) {return m_CandidateSeqs;} private: /// Prohibit copy constructor @@ -670,14 +680,14 @@ private: /// Jaccard distance double m_JDistance; - /// Minimum number of hits + /// Minimum number of hits in LSH phase int m_MinHits; /// Database/index string m_DbIndex; - /// Number of target sequences to try BLAST on. - int m_TargetSeqs; + /// Number of candidate sequences to try BLAST on. + int m_CandidateSeqs; }; /// Argument class to collect options specific to DELTA-BLAST @@ -807,8 +817,8 @@ public: : CQueryOptionsArgs(false), m_IsPaired(false), m_InputFormat(eFasta), - m_QualityFilter(false), - m_MateInputStream(NULL) + m_MateInputStream(NULL), + m_EnableSraCache(false) {} /** Interface method, \sa IBlastCmdLineArgs::SetArgumentDescriptions */ @@ -823,9 +833,6 @@ public: EInputFormat GetInputFormat(void) const {return m_InputFormat;} - /// Should low quality sequences be rejected - bool DoQualityFilter(void) const {return m_QualityFilter;} - /// Does the mate input stream exits bool HasMateInputStream(void) const {return m_MateInputStream;} @@ -836,14 +843,20 @@ public: const vector& GetSraAccessions(void) const {return m_SraAccessions;} + /// Is SRA caching in local files enabled + /// (see File Caching at + /// https://github.com/ncbi/sra-tools/wiki/Toolkit-Configuration) + bool IsSraCacheEnabled(void) const {return m_EnableSraCache;} + private: bool m_IsPaired; EInputFormat m_InputFormat; - bool m_QualityFilter; vector m_SraAccessions; CNcbiIstream* m_MateInputStream; auto_ptr m_DecompressIStream; + + bool m_EnableSraCache; }; @@ -872,7 +885,8 @@ public: CBlastDatabaseArgs(bool request_mol_type = false, bool is_rpsblast = false, bool is_igblast = false, - bool is_mapper = false); + bool is_mapper = false, + bool is_kblast = false); /** Interface method, \sa IBlastCmdLineArgs::SetArgumentDescriptions */ virtual void SetArgumentDescriptions(CArgDescriptions& arg_desc); /** Interface method, \sa IBlastCmdLineArgs::SetArgumentDescriptions */ @@ -938,6 +952,7 @@ protected: bool m_IsProtein; /**< Is the database/subject(s) protein? */ bool m_IsMapper; /**< true for short read mapper */ + bool m_IsKBlast; /**< true for Kblastp */ CRef m_Subjects; /**< The subject sequences */ CRef m_Scope; /**< CScope object in which all subject sequences read are kept */ @@ -1137,14 +1152,43 @@ protected: EFormatFlags m_FormatFlags; }; +/// Formatting args for magicblast advertising only SAM and fast tabular +/// formats +class NCBI_BLASTINPUT_EXPORT CMapperFormattingArgs : public CFormattingArgs +{ +public: + + CMapperFormattingArgs(void) : CFormattingArgs(), m_TrimReadIds(true), + m_PrintUnaligned(true) {} + + virtual void SetArgumentDescriptions(CArgDescriptions& arg_desc); + + virtual void ExtractAlgorithmOptions(const CArgs& args, CBlastOptions& opt); + + virtual bool ArchiveFormatRequested(const CArgs& /*args*/) const { + return false; + } + + /// Should read ids be in SAM format be trimmed of .1 and .2 endings + /// for paired mapping + bool TrimReadIds(void) const {return m_TrimReadIds;} + + /// Should unaligned reads be reported + bool PrintUnaligned(void) const {return m_PrintUnaligned;} + +private: + bool m_TrimReadIds; + bool m_PrintUnaligned; +}; + /// Argument class to collect multi-threaded arguments class NCBI_BLASTINPUT_EXPORT CMTArgs : public IBlastCmdLineArgs { public: /// Default Constructor - CMTArgs(bool isRpsBlast = false) : - m_NumThreads(isRpsBlast? 0:CThreadable::kMinNumThreads), - m_IsRpsBlast(isRpsBlast) { + CMTArgs(size_t default_num_threads = CThreadable::kMinNumThreads) : + m_NumThreads(default_num_threads) + { #ifdef NCBI_NO_THREADS // No threads can be set in NON-MT mode m_NumThreads = CThreadable::kMinNumThreads; @@ -1160,11 +1204,6 @@ public: size_t GetNumThreads() const { return m_NumThreads; } private: size_t m_NumThreads; ///< Number of threads to spawn - bool m_IsRpsBlast; - static const int kDefaultRpsNumThreads = 1; - - void x_SetArgumentDescriptionsRpsBlast(CArgDescriptions& arg_desc); - void x_ExtractAlgorithmOptionsRpsBlast(const CArgs& cmd_line_args); }; /// Argument class to collect remote vs. local execution diff --git a/c++/include/algo/blast/blastinput/blast_asn1_input.hpp b/c++/include/algo/blast/blastinput/blast_asn1_input.hpp index 8660de06..e9224fee 100644 --- a/c++/include/algo/blast/blastinput/blast_asn1_input.hpp +++ b/c++/include/algo/blast/blastinput/blast_asn1_input.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_asn1_input.hpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_asn1_input.hpp 539881 2017-06-28 14:57:30Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -49,33 +49,24 @@ public: /// Constructor /// @param infile Input stream for query sequences [in] - /// @param num_seqs_in_batch Number of sequences to read in a single batch - /// [in] /// @param is_bin Is input in binary ASN.1 format [in] /// @param is_paired Are queries paired [in] /// @param validate Should sequence validation be applied to each read - /// sequence; if true sequences that do not pass validation will be - /// rejected [in] - CASN1InputSourceOMF(CNcbiIstream& infile, TSeqPos num_seqs_in_bacth, - bool is_bin = false, bool is_paired = false, - bool validate = true); + CASN1InputSourceOMF(CNcbiIstream& infile, bool is_bin = false, + bool is_paired = false); /// Constructor for reading sequences from two files for paired short reads /// @param infile1 Input stream for query sequences [in] /// @param infile2 Input stream for query mates [in] - /// @param num_seqs_in_batch Number of sequences to read in a single batch - /// [in] /// @param is_bin Is input in binary ASN.1 format [in] /// @param validate Should sequence validation be applied to each read - /// sequence; if true sequences that do not pass validation will be - /// rejected [in] CASN1InputSourceOMF(CNcbiIstream& infile1, CNcbiIstream& infile2, - TSeqPos num_seqs_in_bacth, bool is_bin = false, - bool validate = true); + bool is_bin = false); virtual ~CASN1InputSourceOMF() {} - virtual void GetNextNumSequences(CBioseq_set& bioseq_set, TSeqPos num_seqs); + virtual int GetNextSequence(CBioseq_set& bioseq_set); + virtual bool End(void) {return m_InputStream->eof();} @@ -83,12 +74,8 @@ private: CASN1InputSourceOMF(const CASN1InputSourceOMF&); CASN1InputSourceOMF& operator=(const CASN1InputSourceOMF&); - bool x_ValidateSequence(const CSeq_data& seq_data, int length); - /// Compute dimer entropy for sequence in Ncbi2NA format - int x_FindDimerEntropy2NA(const vector& sequence, int length); - /// Read one sequence from - int x_ReadOneSeq(CNcbiIstream& instream); + CRef x_ReadOneSeq(CNcbiIstream& instream); /// Read sequences from one stream bool x_ReadFromSingleFile(CBioseq_set& bioseq_set); @@ -96,20 +83,15 @@ private: /// Read sequences from two streams bool x_ReadFromTwoFiles(CBioseq_set& bioseq_set); - TSeqPos m_NumSeqsInBatch; + /// Number of bases added so far + TSeqPos m_BasesAdded; CNcbiIstream* m_InputStream; // for reading paired reads from two FASTA files CNcbiIstream* m_SecondInputStream; /// Are queries paired bool m_IsPaired; - /// Validate quereis and reject those that do not pass - bool m_Validate; /// Is input binary ASN1 bool m_IsBinary; - /// Used for indexing Seq-entries when reading from two files - int m_Index; - - vector< CRef > m_Entries; }; diff --git a/c++/include/algo/blast/blastinput/blast_fasta_input.hpp b/c++/include/algo/blast/blastinput/blast_fasta_input.hpp index 7835f065..68125fa1 100644 --- a/c++/include/algo/blast/blastinput/blast_fasta_input.hpp +++ b/c++/include/algo/blast/blastinput/blast_fasta_input.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_fasta_input.hpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_fasta_input.hpp 547030 2017-09-25 17:24:51Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -123,41 +123,35 @@ public: }; - CShortReadFastaInputSource(CNcbiIstream& infile, TSeqPos num_seqs_in_bacth, + CShortReadFastaInputSource(CNcbiIstream& infile, EInputFormat format = eFasta, - bool paired = false, bool validate = true); + bool paired = false); CShortReadFastaInputSource(CNcbiIstream& infile1, CNcbiIstream& infile2, - TSeqPos num_seqs_in_bacth, - EInputFormat format = eFasta, - bool validate = true); + EInputFormat format = eFasta); virtual ~CShortReadFastaInputSource() {} - virtual void GetNextNumSequences(CBioseq_set& bioseq_set, TSeqPos num_seqs); + virtual int GetNextSequence(CBioseq_set& bioseq_set); + virtual bool End(void) {return m_LineReader->AtEOF();} - /// Get number of rejected queries - Int4 GetNumRejected(void) const {return m_NumRejected;} + void SetParseSeqIds(bool val) {m_ParseSeqIds = val;} private: CShortReadFastaInputSource(const CShortReadFastaInputSource&); CShortReadFastaInputSource& operator=(const CShortReadFastaInputSource&); CTempString x_ParseDefline(CTempString& line); - bool x_ValidateSequence(const char* sequence, int length); - - /// Read sequences in FASTA format - void x_ReadFasta(CBioseq_set& bioseq_set); - /// Read sequences in FASTQ format - void x_ReadFastq(CBioseq_set& bioseq_set); + /// Read sequences in FASTA or FASTQ format + void x_ReadFastaOrFastq(CBioseq_set& bioseq_set); /// Read one sequence from a FASTA file - int x_ReadFastaOneSeq(CRef line_reader); + CRef x_ReadFastaOneSeq(CRef line_reader); /// Read one sequence from a FASTQ file - int x_ReadFastqOneSeq(CRef line_reader); + CRef x_ReadFastqOneSeq(CRef line_reader); /// Read sequences from two FASTA or FASTQ files (for paired reads) bool x_ReadFromTwoFiles(CBioseq_set& bioseq_set, EInputFormat format); @@ -166,27 +160,24 @@ private: /// on a single line separated by '><' void x_ReadFastc(CBioseq_set& bioseq_set); - TSeqPos m_NumSeqsInBatch; + CRef x_GetNextSeqId(void); + + /// Number of bases added so far + TSeqPos m_BasesAdded; /// string::capacity() can be used instead TSeqPos m_SeqBuffLen; CRef m_LineReader; // for reading paired reads from two FASTA files CRef m_SecondLineReader; string m_Sequence; - CTempString m_Line; /// Are paired sequences in the input bool m_IsPaired; - /// Validate quereis and reject those that do not pass - bool m_Validate; - /// Number of queries that did not pass validation and were rejected - Int4 m_NumRejected; /// Input format: FASTA, FASTQ, FASTC EInputFormat m_Format; - /// Used for indexing Seq-entries when reading from two files - int m_Index; - - vector< CRef > m_SeqIds; - vector< CRef > m_Entries; + /// A counter for generating local ids + unsigned int m_Id; + /// Should defline ids be used Bioseq objects + bool m_ParseSeqIds; }; diff --git a/c++/include/algo/blast/blastinput/blast_input.hpp b/c++/include/algo/blast/blastinput/blast_input.hpp index 21a3fd8d..d6bb55ce 100644 --- a/c++/include/algo/blast/blastinput/blast_input.hpp +++ b/c++/include/algo/blast/blastinput/blast_input.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_input.hpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_input.hpp 543932 2017-08-15 16:50:39Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -93,6 +93,8 @@ public: /// type guessing (see @ref kSeqLenThreshold2Guess) [in] /// @param local_id_counter counter used to create the CSeqidGenerator to /// create local identifiers for sequences read [in] + /// @param skip_seq_check When set this will avoid the sequence + /// validation step when using the CFastaReader. -RMH- CBlastInputSourceConfig(const SDataLoaderConfig& dlconfig, objects::ENa_strand strand = objects::eNa_strand_other, bool lowercase = false, @@ -101,7 +103,8 @@ public: bool retrieve_seq_data = true, int local_id_counter = 1, unsigned int seqlen_thresh2guess = - numeric_limits::max()); + numeric_limits::max(), + bool skip_seq_check = false /* -RMH- */ ); /// Destructor /// @@ -136,6 +139,18 @@ public: /// bool GetBelieveDeflines() const { return m_BelieveDeflines; } + /// Retrieve status of sequence alphabet validation + /// @return boolean to toggle validation of seq data + /// -RMH- + /// + bool GetSkipSeqCheck() const { return m_SkipSeqCheck; } + + /// Turn validation of sequence on/off + /// @param skip boolean to toggle validation of sequence + /// -RMH- + /// + void SetSkipSeqCheck(bool skip) { m_SkipSeqCheck = skip; } + /// Set range for all sequences /// @param r range to use [in] void SetRange(const TSeqRange& r) { m_Range = r; } @@ -201,6 +216,8 @@ private: bool m_LowerCaseMask; /// Whether to parse sequence IDs bool m_BelieveDeflines; + /// Whether to validate sequence data -RMH- + bool m_SkipSeqCheck; /// Sequence range TSeqRange m_Range; /// Configuration object for data loaders, used by CBlastInputReader @@ -396,12 +413,16 @@ private: }; -class NCBI_BLASTINPUT_EXPORT CBlastInputSourceOMF : public CObject +class NCBI_BLASTINPUT_EXPORT CBlastInputSourceOMF { -protected: +public: virtual ~CBlastInputSourceOMF() {} - virtual void GetNextNumSequences(CBioseq_set& bioseq_set, - TSeqPos num_seqs) = 0; + +protected: + /// Get one sequence (or a pair for NGS reads) + /// @param bioseq_set Read sequences will be appended there [in|out] + /// @return Number of bases read + virtual int GetNextSequence(CBioseq_set& bioseq_set) = 0; virtual bool End(void) = 0; @@ -412,14 +433,17 @@ protected: class NCBI_BLASTINPUT_EXPORT CBlastInputOMF : public CObject { public: - CBlastInputOMF(CRef source, - TSeqPos num_seqs_in_batch = kMax_Int); + CBlastInputOMF(CBlastInputSourceOMF* source, + TSeqPos batch_size); void GetNextSeqBatch(CBioseq_set& bioseq_set); CRef GetNextSeqBatch(void); - void SetNumSeqsInBatch(TSeqPos num) {m_NumSeqsInBatch = num;} - TSeqPos GetNumSeqsInBatch(void) {return m_NumSeqsInBatch;} + void SetBatchSize(TSeqPos num) {m_BatchSize = num;} + TSeqPos GetBatchSize(void) const {return m_BatchSize;} + + void SetMaxBatchNumSeqs(TSeqPos num) {m_MaxNumSequences = num;} + TSeqPos GetMaxBatchNumSeqs(void) const {return m_MaxNumSequences;} bool End(void) {return m_Source->End();} @@ -427,8 +451,9 @@ private: CBlastInputOMF(const CBlastInputOMF& rhs); CBlastInputOMF& operator=(const CBlastInputOMF& rhs); - CRef m_Source; - TSeqPos m_NumSeqsInBatch; + CBlastInputSourceOMF* m_Source; + TSeqPos m_BatchSize; + TSeqPos m_MaxNumSequences; CRef m_BioseqSet; }; diff --git a/c++/include/algo/blast/blastinput/blast_input_aux.hpp b/c++/include/algo/blast/blastinput/blast_input_aux.hpp index 1eb41ce0..70479c10 100644 --- a/c++/include/algo/blast/blastinput/blast_input_aux.hpp +++ b/c++/include/algo/blast/blastinput/blast_input_aux.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_input_aux.hpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_input_aux.hpp 533238 2017-04-13 19:29:13Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -330,13 +330,6 @@ CheckForEmptySequences(CRef sequences, string& warnings); NCBI_BLASTINPUT_EXPORT void CheckForEmptySequences(CRef sequences, string& warnings); -/// Compute entropy of 2-mers in a nucleotide IUPACNA sequence -/// @param sequence Nucleotide sequence [in] -/// @param length Sequence length [in] -/// @return Entropy of 2-base words -NCBI_BLASTINPUT_EXPORT int -FindDimerEntropy(const char* sequence, int length); - END_SCOPE(blast) END_NCBI_SCOPE diff --git a/c++/include/algo/blast/blastinput/blast_scope_src.hpp b/c++/include/algo/blast/blastinput/blast_scope_src.hpp index 731fcc14..d24535ab 100644 --- a/c++/include/algo/blast/blastinput/blast_scope_src.hpp +++ b/c++/include/algo/blast/blastinput/blast_scope_src.hpp @@ -1,7 +1,7 @@ #ifndef ALGO_BLAST_BLASTINPUT___BLAST_SCOPE_SRC__HPP #define ALGO_BLAST_BLASTINPUT___BLAST_SCOPE_SRC__HPP -/* $Id: blast_scope_src.hpp 516396 2016-10-13 12:26:43Z ivanov $ +/* $Id: blast_scope_src.hpp 515237 2016-09-29 12:32:30Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/algo/blast/blastinput/cmdline_flags.hpp b/c++/include/algo/blast/blastinput/cmdline_flags.hpp index 449db402..01362edc 100644 --- a/c++/include/algo/blast/blastinput/cmdline_flags.hpp +++ b/c++/include/algo/blast/blastinput/cmdline_flags.hpp @@ -1,4 +1,4 @@ -/* $Id: cmdline_flags.hpp 514854 2016-09-26 17:24:36Z ivanov $ +/* $Id: cmdline_flags.hpp 546749 2017-09-21 11:22:02Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -71,9 +71,13 @@ NCBI_BLASTINPUT_EXPORT extern const string kArgDbTitle; /// seqid list file name to restrict BLAST database NCBI_BLASTINPUT_EXPORT extern const string kArgSeqIdList; -/// argument for gi list to exclude from a BLAST database search +/// argument for seqid list to exclude from a BLAST database search NCBI_BLASTINPUT_EXPORT extern const string kArgNegativeGiList; +/// argument for gi list to exclude from a BLAST database search +NCBI_BLASTINPUT_EXPORT extern const string kArgNegativeSeqidList; + + /// List of filtering algorithms to apply to subjects as soft masking extern const string kArgDbSoftMask; // List of filtering algorithms to apply to subjects as hard masking @@ -92,6 +96,8 @@ NCBI_BLASTINPUT_EXPORT extern const string kArgRemote; /// Argument to determine the number of threads to use when running BLAST NCBI_BLASTINPUT_EXPORT extern const string kArgNumThreads; +/// Default number of threads for IgBLAST command line tools +NCBI_BLASTINPUT_EXPORT extern const size_t kDfltIgBlastNumThreads; /// Argument for scoring matrix NCBI_BLASTINPUT_EXPORT extern const string kArgMatrixName; @@ -294,6 +300,8 @@ NCBI_BLASTINPUT_EXPORT extern const string kArgGLDomainSystem; NCBI_BLASTINPUT_EXPORT extern const string kArgGLFocusV; /// Arugment to specify if Igblast alignment should be extends at 5' end NCBI_BLASTINPUT_EXPORT extern const string kArgExtendAlign; +/// Arugment to to detect overlap at vdj junction +NCBI_BLASTINPUT_EXPORT extern const string kArgDetectOverlap; ///Argument to specify minimal required V length NCBI_BLASTINPUT_EXPORT extern const string kArgMinVLength; ///Argument to specify minimal required J gene length @@ -308,6 +316,8 @@ NCBI_BLASTINPUT_EXPORT extern const string kArgTranslate; NCBI_BLASTINPUT_EXPORT extern const string kArgMinDMatch; /// Argument to specify mismatch penalty for D gene search NCBI_BLASTINPUT_EXPORT extern const string kArgDPenalty; +/// Argument to specify mismatch penalty for J gene search +NCBI_BLASTINPUT_EXPORT extern const string kArgJPenalty; /// Argument to specify IgBlast sequence type NCBI_BLASTINPUT_EXPORT extern const string kArgIgSeqType; /// Argument to specify non-greedy dynamic programming extension @@ -353,18 +363,15 @@ NCBI_BLASTINPUT_EXPORT extern const string kDfltArgRpsDb; /// KBLASTP arguments /// Specifies Jaccard distance (threshold) NCBI_BLASTINPUT_EXPORT extern const string kArgJDistance; -/// Default value +/// Jaccard default value NCBI_BLASTINPUT_EXPORT extern const string kDfltArgJDistance; /// Specifies minimal number of LSH matches NCBI_BLASTINPUT_EXPORT extern const string kArgMinHits; -/// Default value +/// LSH matches default value. NCBI_BLASTINPUT_EXPORT extern const string kDfltArgMinHits; -/// KMER index -NCBI_BLASTINPUT_EXPORT extern const string kArgKIndex; -NCBI_BLASTINPUT_EXPORT extern const string kDfltArgKIndex; /// Number of sequences to attempt BLAST on. -NCBI_BLASTINPUT_EXPORT extern const string kArgTargetSeqs; -NCBI_BLASTINPUT_EXPORT extern const string kDfltArgTargetSeqs; +NCBI_BLASTINPUT_EXPORT extern const string kArgCandidateSeqs; +NCBI_BLASTINPUT_EXPORT extern const string kDfltArgCandidateSeqs; /// Argument to specify inclusion e-value threshold for conserved domains @@ -387,7 +394,7 @@ NCBI_BLASTINPUT_EXPORT extern const string kArgLineLength; // Mapper arguments /// Argument to specify whether mapped reads are paired NCBI_BLASTINPUT_EXPORT extern const string kArgPaired; -/// Argument to specify cutoff score for accepting non-spliced alignment +/// Argument to specify cutoff score for accepting a spliced alignment NCBI_BLASTINPUT_EXPORT extern const string kArgScore; /// Argument to specify filtering lookup tables words by frequency in the /// searched database @@ -408,6 +415,15 @@ NCBI_BLASTINPUT_EXPORT extern const string kArgRefType; NCBI_BLASTINPUT_EXPORT extern const string kArgOutputGzip; /// Argument to specify SRA accessions NCBI_BLASTINPUT_EXPORT extern const string kArgSraAccession; +/// Argument to specify not trimming of '.1' and '.2' at the end of read ids +/// in SAM format for paired reads +NCBI_BLASTINPUT_EXPORT extern const string kArgNoReadIdTrim; +/// Argument to trun off printing of unaligned reads +NCBI_BLASTINPUT_EXPORT extern const string kArgNoUnaligned; +/// Argument to enable SRA caching in local files +NCBI_BLASTINPUT_EXPORT extern const string kArgEnableSraCache; +/// Argument to specify a cutoff edit distance fot an alignment +NCBI_BLASTINPUT_EXPORT extern const string kArgMaxEditDist; END_SCOPE(blast) END_NCBI_SCOPE diff --git a/c++/include/algo/blast/blastinput/kblastp_args.hpp b/c++/include/algo/blast/blastinput/kblastp_args.hpp index 8797f0ee..29d9ee94 100644 --- a/c++/include/algo/blast/blastinput/kblastp_args.hpp +++ b/c++/include/algo/blast/blastinput/kblastp_args.hpp @@ -1,4 +1,4 @@ -/* $Id: kblastp_args.hpp 514851 2016-09-26 17:23:54Z ivanov $ +/* $Id: kblastp_args.hpp 533962 2017-04-21 12:57:45Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -46,13 +46,14 @@ public: /// Constructor CKBlastpAppArgs(); + /// Obtain Jaccard distance double GetJaccardDistance() { return m_KBlastpArgs->GetJaccardDistance(); } + /// Number of matches in LSH phase int GetMinHits() { return m_KBlastpArgs->GetMinHits(); } - string GetDatabase() {return m_KBlastpArgs->GetDatabase(); } - - int GetTargetSeqs() {return m_KBlastpArgs->GetTargetSeqs(); } + /// Number of sequences to attempt BLASTP on. + int GetCandidateSeqs() {return m_KBlastpArgs->GetCandidateSeqs(); } /// @inheritDoc virtual int GetQueryBatchSize() const; diff --git a/c++/include/algo/blast/blastinput/rpsblast_args.hpp b/c++/include/algo/blast/blastinput/rpsblast_args.hpp index 1c5fdc49..673eb8e9 100644 --- a/c++/include/algo/blast/blastinput/rpsblast_args.hpp +++ b/c++/include/algo/blast/blastinput/rpsblast_args.hpp @@ -1,4 +1,4 @@ -/* $Id: rpsblast_args.hpp 161402 2009-05-27 17:35:47Z camacho $ +/* $Id: rpsblast_args.hpp 546749 2017-09-21 11:22:02Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -39,6 +39,13 @@ BEGIN_NCBI_SCOPE BEGIN_SCOPE(blast) +class NCBI_BLASTINPUT_EXPORT CRPSBlastMTArgs : public CMTArgs +{ +public: + /** Interface method, \sa IBlastCmdLineArgs::SetArgumentDescriptions */ + virtual void SetArgumentDescriptions(CArgDescriptions& arg_desc); +}; + /// Handles command line arguments for blastp binary class NCBI_BLASTINPUT_EXPORT CRPSBlastAppArgs : public CBlastAppArgs { diff --git a/c++/include/algo/blast/core/blast_hits.h b/c++/include/algo/blast/core/blast_hits.h index 003dea31..f45214f2 100644 --- a/c++/include/algo/blast/core/blast_hits.h +++ b/c++/include/algo/blast/core/blast_hits.h @@ -1,4 +1,4 @@ -/* $Id: blast_hits.h 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_hits.h 532442 2017-04-05 13:47:44Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -936,62 +936,6 @@ Int2 Blast_HSPResultsApplyMasklevel(BlastHSPResults *results, Int4 masklevel, Int4 query_length); -/******************************************************************************** - Mapping hits API. -********************************************************************************/ - - -/** Structre to store a spliced alignment */ -typedef struct BlastHSPChain -{ - Int4 num_hsps; /**< Number of HSPs in the chain */ - BlastHSP** hsp_array; /**< Array of pointers to HSPs */ - - Int4 query_index; /**< Index of query sequence */ - Int4 oid; /**< Oid for the subject sequence */ - Int4 score; /**< Alignment score for the chain */ - Int4 adapter; /**< Position of detected adapted sequence in - the query */ - Int4 polyA; /**< Position of PolyA seqence in the query */ - - struct BlastHSPChain* pair; /**< Pointer to mapped mate alignment for - paired short reads */ - - Int4 multiplicity; /**< Number of idependent mappings for the same - query (including this one) */ -} BlastHSPChain; - - -/** Structure that contains BLAST mapping results */ -typedef struct BlastMappingResults -{ - Int4 num_results; - BlastHSPChain** chain_array; -} BlastMappingResults; - - -/** Initialize the chain structure. - */ -NCBI_XBLAST_EXPORT -BlastHSPChain* Blast_HSPChainNew(void); - -/** Free the chain structure - * @param ch Chain to be freed - */ -NCBI_XBLAST_EXPORT -BlastHSPChain* Blast_HSPChainFree(BlastHSPChain* ch); - -/** Initialize BlastMappingResults structure - */ -NCBI_XBLAST_EXPORT -BlastMappingResults* Blast_MappingResultsNew(void); - -/** Free BlastMappingResults structure - */ -NCBI_XBLAST_EXPORT -BlastMappingResults* Blast_MappingResultsFree(BlastMappingResults* results); - - #ifdef __cplusplus } #endif diff --git a/c++/include/algo/blast/core/blast_hspstream.h b/c++/include/algo/blast/core/blast_hspstream.h index 1a75e898..7c1a78f0 100644 --- a/c++/include/algo/blast/core/blast_hspstream.h +++ b/c++/include/algo/blast/core/blast_hspstream.h @@ -1,4 +1,4 @@ -/* $Id: blast_hspstream.h 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_hspstream.h 532442 2017-04-05 13:47:44Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -41,6 +41,7 @@ #include #include #include +#include #include #ifdef __cplusplus diff --git a/c++/include/algo/blast/core/blast_lookup.h b/c++/include/algo/blast/core/blast_lookup.h index 79a605dd..0dfed64d 100644 --- a/c++/include/algo/blast/core/blast_lookup.h +++ b/c++/include/algo/blast/core/blast_lookup.h @@ -1,4 +1,4 @@ -/* $Id: blast_lookup.h 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_lookup.h 523540 2017-01-04 16:58:25Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -132,9 +132,8 @@ static NCBI_INLINE Int4 ComputeTableIndexIncremental(Int4 wordsize, typedef struct BackboneCell { Uint4 word; - Int4* offsets; + Int4 offset; Int4 num_offsets; - Int4 allocated; struct BackboneCell* next; } BackboneCell; @@ -148,9 +147,15 @@ BackboneCell* BackboneCellFree(BackboneCell* cell); /** Create a new cell for a given word and offset *@param word Nucleotide word in 2na [in] *@param offset Offset for the word [in] - *@param size Size of the offset array to be allocated [in] */ -BackboneCell* BackboneCellNew(Uint4 word, Int4 offset, Int4 size); +BackboneCell* BackboneCellNew(Uint4 word, Int4 offset); + +/** Initialize an olready allocated cell for a given word and offset + *@param cell Pointer to allocated cell [in|out] + *@param word Nucleotide word in 2na [in] + *@param offset Offset for the word [in] + */ +Int4 BackboneCellInit(BackboneCell* cell, Uint4 word, Int4 offset); /** Add all applicable query offsets to a hashed lookup table @@ -163,10 +168,11 @@ BackboneCell* BackboneCellNew(Uint4 word, Int4 offset, Int4 size); * @param query The query sequence [in] * @param locations What locations on the query sequence to index? [in] * @param hash_func Hash function for words in 2na [in] - * @param counts Word counts in a database, to limit lookup table by databse - * word frequency [in] + * @param pv_array A bit fields with bits set for words that are to be included + * in the lookup table. Must be 1 bit per word. [in] */ -void BlastHashLookupIndexQueryExactMatches(BackboneCell **backbone, +void BlastHashLookupIndexQueryExactMatches(BackboneCell *backbone, + Int4* offsets, Int4 word_length, Int4 charsize, Int4 lut_word_length, @@ -174,7 +180,7 @@ void BlastHashLookupIndexQueryExactMatches(BackboneCell **backbone, BlastSeqLoc* locations, TNaLookupHashFunction hash_func, Uint4 mask, - Uint1* counts); + PV_ARRAY_TYPE* pv_array); diff --git a/c++/include/algo/blast/core/blast_nalookup.h b/c++/include/algo/blast/core/blast_nalookup.h index 11c1eda9..e841f621 100644 --- a/c++/include/algo/blast/core/blast_nalookup.h +++ b/c++/include/algo/blast/core/blast_nalookup.h @@ -1,4 +1,4 @@ -/* $Id: blast_nalookup.h 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_nalookup.h 544843 2017-08-28 16:55:23Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -668,19 +668,21 @@ typedef struct BlastNaHashLookupTable { #define NA_WORDS_PER_HASH 3 #define NA_OFFSETS_PER_HASH 9 - +NCBI_XBLAST_EXPORT Int4 BlastNaHashLookupTableNew(BLAST_SequenceBlk* query, BlastSeqLoc* locations, BlastNaHashLookupTable** lut, const LookupTableOptions* opt, const QuerySetUpOptions* query_options, - BlastSeqSrc* seqsrc); + BlastSeqSrc* seqsrc, + Uint4 num_threads); /** Free a nucleotide lookup table. * @param lookup The lookup table structure to be freed * @return NULL */ +NCBI_XBLAST_EXPORT BlastNaHashLookupTable* BlastNaHashLookupTableDestruct(BlastNaHashLookupTable* lookup); diff --git a/c++/include/algo/blast/core/blast_options.h b/c++/include/algo/blast/core/blast_options.h index 0f2e7547..8b3dc18c 100644 --- a/c++/include/algo/blast/core/blast_options.h +++ b/c++/include/algo/blast/core/blast_options.h @@ -1,4 +1,4 @@ -/* $Id: blast_options.h 506100 2016-07-01 15:46:25Z boratyng $ +/* $Id: blast_options.h 546023 2017-09-13 11:14:25Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -70,7 +70,7 @@ extern "C" { the word size is explicitly overridden) */ -#define BLAST_WORDSIZE_MAPPER 16 /**< default word size for mapping rna-seq +#define BLAST_WORDSIZE_MAPPER 18 /**< default word size for mapping rna-seq to a genome */ /** Default matrix name: BLOSUM62 */ @@ -95,7 +95,7 @@ extern "C" { #define BLAST_GAP_EXTN_MEGABLAST 0 /**< default gap open penalty (megablast) with greedy gapped alignment) */ -#define BLAST_GAP_EXTN_MAPPER 8 +#define BLAST_GAP_EXTN_MAPPER 4 /** neighboring word score thresholds; a threshold of zero * means that only query and subject words that match exactly @@ -147,7 +147,7 @@ extern "C" { #define BLAST_PENALTY -3 /**< default nucleotide mismatch score */ #define BLAST_REWARD 1 /**< default nucleotide match score */ -#define BLAST_PENALTY_MAPPER -8 +#define BLAST_PENALTY_MAPPER -4 #define BLAST_REWARD_MAPPER 1 /** Default parameters for saving hits */ @@ -245,6 +245,12 @@ typedef struct SWindowMaskerOptions { const char * database; /**< Use winmasker database at this location. */ } SWindowMaskerOptions; +/** Filtering options for mapping next-generation sequences */ +typedef struct SReadQualityOptions { + double frac_ambig; /**< Fraction of ambiguous bases */ + int entropy; /**< Dimer entropy */ +} SReadQualityOptions; + /** All filtering options */ typedef struct SBlastFilterOptions { Boolean mask_at_hash; /**< mask query only for lookup table creation */ @@ -253,6 +259,8 @@ typedef struct SBlastFilterOptions { (includes translated nucleotides). */ SRepeatFilterOptions* repeatFilterOptions; /**< for organism specific repeat filtering. */ SWindowMaskerOptions* windowMaskerOptions; /**< organism specific filtering with window masker. */ + + SReadQualityOptions* readQualityOptions; /**< quality filtering for mapping next-generation sequences */ } SBlastFilterOptions; @@ -358,8 +366,13 @@ typedef struct BlastHitSavingOptions { double expect_value; /**< The expect value cut-off threshold for an HSP, or a combined hit if sum statistics is used */ Int4 cutoff_score; /**< The (raw) score cut-off threshold */ + Int4 cutoff_score_fun[2]; /**< Coefficients x100 for the raw score cut-off + threshold as a function of query length: + x[0] + x[1] * query_length*/ double percent_identity; /**< The percent identity cut-off threshold */ + Int4 max_edit_distance; /**< Maximum number of mismatches and gaps */ + Int4 hitlist_size;/**< Maximal number of database sequences to return results for */ Int4 hsp_num_max; /**< Maximal number of HSPs to save for one database @@ -603,6 +616,19 @@ Int2 SRepeatFilterOptionsNew(SRepeatFilterOptions ** repeat_options); NCBI_XBLAST_EXPORT Int2 SWindowMaskerOptionsNew(SWindowMaskerOptions ** winmask_options); +/** Allocates memory for SReadQualityOptions, fills in defaults. + * @param read_quality_ptions options that are being returned [in|out] + * @return zero on sucess + */ +NCBI_XBLAST_EXPORT +Int2 SReadQualityOptionsNew(SReadQualityOptions ** read_quality_options); + +/** Frees memory for SReadQualityOptions */ +NCBI_XBLAST_EXPORT +SReadQualityOptions* SReadQualityOptionsFree( + SReadQualityOptions * read_quality_options); + + /** Frees SBlastFilterOptions and all subservient structures. * @param filter_options object to free * @return NULL pointer diff --git a/c++/include/algo/blast/core/blast_query_info.h b/c++/include/algo/blast/core/blast_query_info.h index 74cc3a15..0242106c 100644 --- a/c++/include/algo/blast/core/blast_query_info.h +++ b/c++/include/algo/blast/core/blast_query_info.h @@ -1,4 +1,4 @@ -/* $Id: blast_query_info.h 517499 2016-10-25 17:20:41Z ivanov $ +/* $Id: blast_query_info.h 516747 2016-10-17 19:00:07Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/algo/blast/core/hspfilter_mapper.h b/c++/include/algo/blast/core/hspfilter_mapper.h index f4ac1ca8..5da2e377 100644 --- a/c++/include/algo/blast/core/hspfilter_mapper.h +++ b/c++/include/algo/blast/core/hspfilter_mapper.h @@ -1,4 +1,4 @@ -/* $Id: hspfilter_mapper.h 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: hspfilter_mapper.h 544251 2017-08-21 14:19:11Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -64,6 +64,12 @@ typedef struct BlastHSPMapperParams { part of search. */ Boolean paired; /**< mapping with paired reads */ Boolean splice; /**< mapping spliced reads (RNA-seq to a genome) */ + Int4 longest_intron; /**< max intron length */ + Int4 cutoff_score; /**< min score to accept a chain alignment */ + Int4 cutoff_score_fun[2]; /**< coefficients for cutoff score as a function + of query length: x[0] + x[1] * length */ + Int4 cutoff_edit_dist; /**< max edit distance to accept a chain + alignment */ } BlastHSPMapperParams; /** Sets up parameter set for use by collector. @@ -94,6 +100,16 @@ NCBI_XBLAST_EXPORT BlastHSPWriterInfo* BlastHSPMapperInfoNew(BlastHSPMapperParams* params); +typedef struct HSPChain HSPChain; + +/** Find HSP chains that do not cover full extend of queries for a given + subject */ +NCBI_XBLAST_EXPORT +HSPChain* +FindPartialyCoveredQueries(void* data, Int4 oid, Int4 word_size); + + + #ifdef __cplusplus } #endif diff --git a/c++/include/algo/blast/core/lookup_wrap.h b/c++/include/algo/blast/core/lookup_wrap.h index d983b4e0..0ef64622 100644 --- a/c++/include/algo/blast/core/lookup_wrap.h +++ b/c++/include/algo/blast/core/lookup_wrap.h @@ -1,4 +1,4 @@ -/* $Id: lookup_wrap.h 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: lookup_wrap.h 521162 2016-12-06 15:28:14Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -86,6 +86,31 @@ Int2 LookupTableWrapInit(BLAST_SequenceBlk* query, Blast_Message* *error_msg, BlastSeqSrc* seqsrc); +/** Create the lookup table for all query words (possibly multithreaded, + depends on implementation). + * @param query The query sequence [in] + * @param lookup_options What kind of lookup table to build? [in] + * @param query_options options for query setup [in] + * @param lookup_segments Locations on query to be used for lookup table + * construction [in] + * @param sbp Scoring block containing matrix [in] + * @param lookup_wrap_ptr The initialized lookup table [out] + * @param rps_info Structure containing RPS blast setup information [in] + * @param error_msg message with warning or errors [in|out] + * @param seqsrc Database sequences [in] + * @param num_threads Number of threads to use [in] + */ +NCBI_XBLAST_EXPORT +Int2 LookupTableWrapInit_MT(BLAST_SequenceBlk* query, + const LookupTableOptions* lookup_options, + const QuerySetUpOptions* query_options, + BlastSeqLoc* lookup_segments, BlastScoreBlk* sbp, + LookupTableWrap** lookup_wrap_ptr, const BlastRPSInfo *rps_info, + Blast_Message* *error_msg, + BlastSeqSrc* seqsrc, + Uint4 num_threads); + + /** Deallocate memory for the lookup table */ NCBI_XBLAST_EXPORT LookupTableWrap* LookupTableWrapFree(LookupTableWrap* lookup); diff --git a/c++/include/algo/blast/core/spliced_hits.h b/c++/include/algo/blast/core/spliced_hits.h new file mode 100644 index 00000000..4d1153a0 --- /dev/null +++ b/c++/include/algo/blast/core/spliced_hits.h @@ -0,0 +1,113 @@ +/* $Id: spliced_hits.h 532442 2017-04-05 13:47:44Z boratyng $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Greg Boratyn + * + * Structures and methods for spliced alignments + * + */ + +#ifndef ALGO_BLAST_CORE__SPLICED_HITS__H +#define ALGO_BLAST_CORE__SPLICED_HITS__H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* A container to create a list of HSPs */ +typedef struct HSPContainer +{ + BlastHSP* hsp; + struct HSPContainer* next; +} HSPContainer; + + +/** Create HSPContainer and take ownership of the HSP */ +HSPContainer* HSPContainerNew(BlastHSP** hsp); + +/** Free the list of HSPs, along with the stored HSPs */ +HSPContainer* HSPContainerFree(HSPContainer* hc); + +/** Clone a list of HSP containers */ +HSPContainer* HSPContainerDup(HSPContainer* inh); + +/** A chain of HSPs: spliced alignment */ +typedef struct HSPChain +{ + Int4 context; /**< Contex number of query sequence */ + Int4 oid; /**< Subject oid */ + Int4 score; /**< Alignment score for the chain */ + HSPContainer* hsps; /**< A list of HSPs that belong to this chain */ + + Int4 count; /**< Number of placements for the read */ + struct HSPChain* pair; /**< Pointer to mapped mate alignmemt + (for paired reads) */ + Uint1 pair_conf; /**< Pair configuration */ + + Int4 adapter; /**< Position of detected adapter sequence in the query */ + Int4 polyA; /**< Position of detected PolyA sequence in the query */ + struct HSPChain* next; /**< Pointer to the next chain in a list */ +} HSPChain; + + +/** Deallocate a chain or list of chains */ +NCBI_XBLAST_EXPORT +HSPChain* HSPChainFree(HSPChain* chain_list); + +/** Allocate a chain */ +NCBI_XBLAST_EXPORT +HSPChain* HSPChainNew(Int4 context); + +/** Clone a single HSP chain */ +HSPChain* CloneChain(const HSPChain* chain); + + +/** Structure that contains BLAST mapping results */ +typedef struct BlastMappingResults +{ + Int4 num_queries; + HSPChain** chain_array; +} BlastMappingResults; + + +/** Initialize BlastMappingResults structure + */ +NCBI_XBLAST_EXPORT +BlastMappingResults* Blast_MappingResultsNew(void); + +/** Free BlastMappingResults structure + */ +NCBI_XBLAST_EXPORT +BlastMappingResults* Blast_MappingResultsFree(BlastMappingResults* results); + + + +#ifdef __cplusplus +} +#endif + +#endif /* !ALGO_BLAST_CORE__SPLICED_HITS__H */ diff --git a/c++/include/algo/blast/dbindex/dbindex.hpp b/c++/include/algo/blast/dbindex/dbindex.hpp index 9e10aa12..724f920a 100644 --- a/c++/include/algo/blast/dbindex/dbindex.hpp +++ b/c++/include/algo/blast/dbindex/dbindex.hpp @@ -1,4 +1,4 @@ -/* $Id: dbindex.hpp 363927 2012-05-21 18:37:51Z morgulis $ +/* $Id: dbindex.hpp 542542 2017-08-01 12:44:33Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -307,7 +307,7 @@ struct SIndexHeader @param fname [I] name of the index volume file @return the number of subjects in the index volume (from the volume header) */ -const size_t GetIdxVolNumOIDs( const std::string & fname ); +size_t GetIdxVolNumOIDs( const std::string & fname ); /** A vector or pointer based sequence wrapper. Serves as either a std::vector wrapper or holds a constant size @@ -797,7 +797,7 @@ class NCBI_XBLAST_EXPORT CDbIndex : public CObject @return Length of the sequence in bases. */ - virtual TSeqPos GetSeqLen( TSeqNum oid ) const + virtual TSeqPos GetSeqLen( TSeqNum /*oid*/ ) const { NCBI_THROW( CDbIndex_Exception, eBadVersion, @@ -811,7 +811,7 @@ class NCBI_XBLAST_EXPORT CDbIndex : public CObject @return Pointer to the sequence data. */ - virtual const Uint1 * GetSeqData( TSeqNum oid ) const + virtual const Uint1 * GetSeqData( TSeqNum /*oid*/ ) const { NCBI_THROW( CDbIndex_Exception, eBadVersion, @@ -1323,7 +1323,8 @@ class CSubjectMap (TSeqPos)(loff - (*res - lid_start)*CR) ); } - TSeqPos getSOff( TSeqNum sid, TSeqNum rcid, TSeqPos coff ) const + TSeqPos getSOff( TSeqNum _DEBUG_ARG(sid), + TSeqNum rcid, TSeqPos coff ) const { ASSERT( sid < subjects_.size() - 1 ); ASSERT( subjects_[sid] - 1 + rcid < chunks_.size() ); diff --git a/c++/include/algo/blast/dbindex/sequence_istream_fasta.hpp b/c++/include/algo/blast/dbindex/sequence_istream_fasta.hpp index c113c965..69debdb1 100644 --- a/c++/include/algo/blast/dbindex/sequence_istream_fasta.hpp +++ b/c++/include/algo/blast/dbindex/sequence_istream_fasta.hpp @@ -1,4 +1,4 @@ -/* $Id: sequence_istream_fasta.hpp 140978 2008-09-23 12:48:49Z morgulis $ +/* $Id: sequence_istream_fasta.hpp 539175 2017-06-19 17:06:43Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -52,7 +52,6 @@ class NCBI_XBLAST_EXPORT CSequenceIStreamFasta : public CSequenceIStream bool stream_allocated_; /**< Whether to deallocate the stream at destruction. */ CNcbiIstream * istream_; /**< Standard IO stream for reading FASTA data. */ - size_t curr_seq_; /**< Current sequence number. */ objects::CFastaReader * fasta_reader_; /**< Object to read fasta files. */ diff --git a/c++/include/algo/blast/format/blast_async_format.hpp b/c++/include/algo/blast/format/blast_async_format.hpp new file mode 100644 index 00000000..346c76c9 --- /dev/null +++ b/c++/include/algo/blast/format/blast_async_format.hpp @@ -0,0 +1,105 @@ +/* $Id: blast_async_format.hpp 530618 2017-03-16 12:03:45Z madden $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Tom Madden + * + * File Description: + * Class to print results in an asynchronous manner + * + */ + +#ifndef ALGO_BLAST_FORMAT___BLAST_ASYNC_FORMAT__HPP +#define ALGO_BLAST_FORMAT___BLAST_ASYNC_FORMAT__HPP + +#include +#include +#include +#include +#include +#include +#include +#include + + +USING_NCBI_SCOPE; +USING_SCOPE(objects); +USING_SCOPE(blast); + + +/// Contains query, results and CBlastFormat for one batch +struct SFormatResultValues { + + CRef qVec; ///< Queries + CRef blastResults; ///< Results + CRef formatter; ///< Information for formatting + SFormatResultValues(CRef qv, CRef br, CRef fmt) + : qVec(qv), blastResults(br), formatter(fmt) {} +}; + +///////////////////////////////////////////////////////////////////////////// +/// Run as separate thread and format results. +class NCBI_XBLASTFORMAT_EXPORT CBlastAsyncFormatThread : public CThread +{ +public: + CBlastAsyncFormatThread() + : m_ResultsMap(), m_Done(false), m_Semaphore(0, kMax_Int) + { + } + + /// Queue results for printing. + /// Will throw if called after call to Finalize or if a duplicate + /// batchNumber is entered. + /// Batch numbers should start at zero and increase. Missing numbers NOT allowed. + /// @param batchNumber orders how the results are printed. + /// Numbering starts at zero and missing values not allowed. + /// @param results data needed for formatting + void QueueResults(int batchNumber, vector results); + + /// Close queue for printing. No calls to QueueResults allowed after this. + void Finalize(); + + /// Calls Finalize (if not already called) then CThread::Join(); + /// Should only be called if QueueResults will no longer be called. + void Join(); + +protected: + virtual ~CBlastAsyncFormatThread(void); + + virtual void* Main(void); +private: + + // Prohibit copy constructor and assignment operator + CBlastAsyncFormatThread(const CBlastAsyncFormatThread&); + CBlastAsyncFormatThread& operator= (const CBlastAsyncFormatThread&); + + std::map> m_ResultsMap; + + bool m_Done; + + CSemaphore m_Semaphore; +}; + +#endif /* ALGO_BLAST_FORMAT___BLAST__ASYNC_FORMAT__HPP */ + diff --git a/c++/include/algo/blast/format/blast_format.hpp b/c++/include/algo/blast/format/blast_format.hpp index 1f1a3f86..405c31f7 100644 --- a/c++/include/algo/blast/format/blast_format.hpp +++ b/c++/include/algo/blast/format/blast_format.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_format.hpp 513847 2016-09-15 17:36:25Z ivanov $ +/* $Id: blast_format.hpp 537527 2017-06-01 14:23:49Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -62,7 +62,7 @@ USING_SCOPE(align_format); class CCmdLineBlastXML2ReportData; /// This class formats the BLAST results for command line applications -class NCBI_XBLASTFORMAT_EXPORT CBlastFormat +class NCBI_XBLASTFORMAT_EXPORT CBlastFormat : public CObject { public: @@ -355,9 +355,6 @@ private: /// The custom output format specification string m_CustomOutputFormatSpec; - /// Flag indicating a non-Blast DB source of subject sequences. - bool m_IsNonBlastDB; - /// Structure for incremental XML BLAST output. CRef m_BlastXMLIncremental; diff --git a/c++/include/algo/blast/igblast/igblast.hpp b/c++/include/algo/blast/igblast/igblast.hpp index c5863c5e..10922d26 100644 --- a/c++/include/algo/blast/igblast/igblast.hpp +++ b/c++/include/algo/blast/igblast/igblast.hpp @@ -1,4 +1,4 @@ -/* $Id: igblast.hpp 514854 2016-09-26 17:24:36Z ivanov $ +/* $Id: igblast.hpp 532687 2017-04-07 16:10:42Z jianye $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -69,6 +69,7 @@ public: string m_SequenceType; //ig or tcr? int m_Min_D_match; //the word size for D gene search int m_D_penalty; //the mismatch penalty for D gene search + int m_J_penalty; //the mismatch penalty for J gene search string m_AuxFilename; // auxulary file name string m_IgDataPath; // internal data path CRef m_Db[4]; // user specified germline database @@ -80,6 +81,7 @@ public: bool m_ExtendAlign; int m_MinVLength; int m_MinJLength; + bool m_DetectOverlap; }; class CIgAnnotation : public CObject @@ -294,7 +296,12 @@ private: CRef &qf, CRef &opts_hndl, int db_type); - + void x_SetupNoOverlapDSearch(const vector > &annots, + CRef &results, + CRef &qf, + CRef &opts_hndl, + int db_type); + /// Prepare blast option handle and query for specified database search void x_SetupDbSearch(vector > &annot, CRef &qf); @@ -308,6 +315,11 @@ private: CRef &results_J, vector > &annot); + void x_AnnotateD(CRef &results_D, + vector > &annot); + void x_AnnotateJ(CRef &results_J, + vector > &annot); + /// Annotate the query chaintype and domains based on blast results void x_AnnotateDomain(CRef &gl_results, CRef &dm_results, @@ -357,7 +369,15 @@ private: void x_ExtendAlign(CRef & results); void x_ScreenByAlignLength(CRef & results, int length); void x_FillJDomain(CRef & align, CRef & annot); - + void x_ProcessDJResult(CRef& results_V, + CRef& results_D, + CRef& results_J, + vector > &annots); + void x_ProcessDGeneResult(CRef& results_V, + CRef& results_D, + CRef& results_J, + vector > &annots); + }; END_SCOPE(blast) diff --git a/c++/include/algo/blast/proteinkmer/blastkmer.hpp b/c++/include/algo/blast/proteinkmer/blastkmer.hpp new file mode 100644 index 00000000..cca47def --- /dev/null +++ b/c++/include/algo/blast/proteinkmer/blastkmer.hpp @@ -0,0 +1,181 @@ +/* $Id: blastkmer.hpp 536866 2017-05-24 01:23:19Z ucko $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Tom Madden + * + * File Description: + * BLAST-kmer searches + * + */ + +#ifndef BLAST_KMER_KMER_HPP +#define BLAST_KMER_KMER_HPP + + +#include +#include +#include +#include +#include +#include +#include + +#include "blastkmerresults.hpp" +#include "blastkmeroptions.hpp" +#include "mhfile.hpp" +#include "blastkmerutils.hpp" + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(blast) +USING_SCOPE(objects); + +/// Class to perform a KMER-BLASTP search. +/// To run, first call the constructor, then RunSearches, then +/// access results through CBlastKmerResultsSet. +/// The Run method is deprecated and will be removed. +/// A few notes/caveats: +/// The CBlastKmerOptions constructor can be called and the resulting +/// object used as input. +/// The string kmerfile should be kEmptyStr so that the volumes for +/// the database in the seqdb parameter will be used. +/// If kEmptyStr is not used for the kmerfile, then, for nr, it would +/// be "nr.00 nr.01 nr.02 nr.03" etc. +/// These should correspond exactly to the database as they rely on the oids in +/// the database. If the kmerfiles are derived from the BLAST database +/// then the BLASTDB paths etc. will be respected for the kmerfiles. +/// NOTE: recoverable errors (e.g., query shorter than KMER size) will NOT +/// trigger an exception but the CBlastKmerResults for that query will have +/// an error or warning. Use the HasError or HasWarning message to check. +class NCBI_XBLAST_EXPORT CBlastKmer : public CObject, public CThreadable +{ +public: + /// Constructor + /// Processes all proteins in TSeqLocVector + /// @param query_vector specifes one protein query sequence [in] + /// @param options sets kblastp parameters. [in] + /// @param seqdb CSeqDB pointer for database to be searched. + /// @param kmerfile assume same names as seqdb volumes if kEmptyStr [in] + CBlastKmer(TSeqLocVector& query_vector, + CRef options, + CRef seqdb, + string kmerfile=kEmptyStr); + + /// Constructor + /// @param query specifes one protein query sequence [in] + /// @param options sets kblastp parameters. [in] + /// @param dbname name of a BLAST database [in] + CBlastKmer(SSeqLoc& query, + CRef options, + const string& dbname); + + /// Destructor + ~CBlastKmer() {} + + /// Performs search on one or more queries + /// Performs search on one or more queries + /// @throw CInputException if the query has no KMERs + CRef Run(); + + /// @deprecated Use Run method instead + /// Performs search on one or more queries + /// Just calls Run method. + /// @throw CInputException if the query has no KMERs + CRef RunSearches(); + + + /// Limits output by GILIST + /// @param list CRef to limit by [in] + void SetGiListLimit(CRef list) {m_GIList=list;} + + /// Limits output by negative GILIST + /// @param list CRef to limit by [in] + void SetGiListLimit(CRef list) {m_NegGIList=list;} + +private: + + /// Preprocess query to sequence hashes. + /// @param query_seq contains query in ncbistdaa [in] + /// @param seq_hash All hash values for query [out] + /// @param query_LSH_hashes LSH values [out] + /// @param num_hashes Number of hash functions [in] + /// @param rows_per_band [in] + /// @param samples how many samples to check (Buhler) [in] + /// @param a Array of num_hash hash values [in] + /// @param b Array of num_hash hash values [in] + /// @param kmerNum size of kmer [in] + /// @param alphabetChoice 0 is 15 letter, 1 is 10 letter alphabet [in] + /// @param version which version of the kmer index to use [in] + /// @param kvalues Buhler LSH points [in] + /// @param badMers Overrepresented KMERs [in] + /// @throw CInputException if the query has no KMERs + void x_ProcessQuery(const string& query_seq, + SOneBlastKmerSearch& kmerSearch, + const SBlastKmerParameters& kmerParams, + uint32_t *a, + uint32_t *b, + vector < vector >& kvalues, + vector badMers); + + /// Search individual kmer file. + /// @param query_hash All hash values for query [in] + /// @param query_LSH_hashes LSH values [in] + /// @param filename basename of kmer files. [in] + /// @param score_vector results vector [out] + /// @param kmer_stats ancillary information about run [out] + void x_RunKmerFile(const vector < vector >& query_hash, const vector < vector >& query_LSH_hash, CMinHashFile& mhfile, TBlastKmerPrelimScoreVector& score_vector, BlastKmerStats& kmer_stats); + + + /// Search multiple queries. + CRef + x_SearchMultipleQueries(int firstQuery, int numQuery, const SBlastKmerParameters& kmerParams, uint32_t *a, uint32_t *b, vector < vector >& kValues, vector badMers); + + +private: + + /// Holds the query seqloc and scope + TSeqLocVector m_QueryVector; + + /// Specifies values for some options (e.g., threshold) + CRef m_Opts; + + /// CSeqDB for BLAST db. + CRef m_SeqDB; + + /// Name of the kmer files. + vector m_KmerFiles; + + /// GIList to limit search by. + CRef m_GIList; + + /// Negative GIList to limit search by. + /// Only one of the gilist or negative GIlist should be set. + CRef m_NegGIList; +}; + + +END_SCOPE(blast) +END_NCBI_SCOPE + +#endif /* BLAST_KMER_KMER_HPP */ diff --git a/c++/include/algo/blast/proteinkmer/blastkmerindex.hpp b/c++/include/algo/blast/proteinkmer/blastkmerindex.hpp new file mode 100644 index 00000000..d7c26eec --- /dev/null +++ b/c++/include/algo/blast/proteinkmer/blastkmerindex.hpp @@ -0,0 +1,104 @@ +/* $Id: blastkmerindex.hpp 536866 2017-05-24 01:23:19Z ucko $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Tom Madden + * + * File Description: + * Build index for BLAST-kmer searches + * + */ + +#ifndef BLAST_KMER_INDEX_HPP +#define BLAST_KMER_INDEX_HPP + + +#include +#include +#include +#include +#include +#include + +#include "blastkmerutils.hpp" + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(blast) +USING_SCOPE(objects); + + +class NCBI_XBLAST_EXPORT CBlastKmerBuildIndex : public CObject +{ +public: + /// Constructor + + CBlastKmerBuildIndex(CRef seqdb, + int kmerSize=5, + int numHashFct=32, + int samples=0, + int compress=2, + int alphabet=0, + int version=0, + int chunkSize=150); + + /// Destructor + ~CBlastKmerBuildIndex() {} + + /// Build the index + void Build(int numThreads=1); + +private: + /// Writes out the data file + void x_WriteDataFile(vector < vector < vector < uint32_t > > > & seq_hash, int num_seqs, CNcbiOfstream& data_file); + /// BUild index for an individual BLAST volume. + void x_BuildIndex(string& name, int start=0, int number=0); + + int m_NumHashFct; /// Number of hash functions. + + int m_NumBands; /// Number of LSH bands. + + int m_RowsPerBand; /// Number of rows per band + + int m_KmerSize; /// Residues in kmer + + CRef m_SeqDB; /// BLAST database. + + bool m_DoSeg; /// Should Seg be run on sequences. + + int m_Samples; /// Number of samples (Buhler only) + + int m_Compress; /// Compress the arrays for Jaccard matches. + + int m_Alphabet; /// 0 for 15 letters, 1 for 10 letters. + + int m_Version; /// version of index file + + int m_ChunkSize; /// # residues in a chunk. +}; + + +END_SCOPE(blast) +END_NCBI_SCOPE + +#endif /* BLAST_KMER_KMER_HPP */ diff --git a/c++/include/algo/blast/proteinkmer/blastkmeroptions.hpp b/c++/include/algo/blast/proteinkmer/blastkmeroptions.hpp new file mode 100644 index 00000000..0429a382 --- /dev/null +++ b/c++/include/algo/blast/proteinkmer/blastkmeroptions.hpp @@ -0,0 +1,106 @@ +/* $Id: blastkmeroptions.hpp 536866 2017-05-24 01:23:19Z ucko $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Tom Madden + * + * File Description: + * Options for BLAST-kmer searches + * + */ + +#ifndef BLAST_KMER_OPTIONS_HPP +#define BLAST_KMER_OPTIONS_HPP + +#include +#include +#include +#include + +BEGIN_NCBI_SCOPE +USING_SCOPE(blast); + + +/// Class of optiosn for the KMEr search. +class NCBI_XBLAST_EXPORT CBlastKmerOptions : public CObject +{ +public: + /// Constructor + CBlastKmerOptions(); + + /// Destructor + ~CBlastKmerOptions() {} + + /// Checks that options are valid + bool Validate() const; + + /// Get the threshold + /// @return double between 0 and 1. + double GetThresh() const {return m_Thresh;} + + /// Set the threshold. 1 means (nearly) identical matches. + /// the closer to zero, the lower the identity of the matches + /// is likely to be. + // @thresh double 0 < thresh <= 1 [in] + void SetThresh(double thresh) {m_Thresh = thresh;} + + /// Get the number of LSH hits to initiate the + /// calculation of the Jaccard distance. + /// Returning zero means CBlastKmer chooses a value based upon the alphabet. + /// @return integer + int GetMinHits() const {return m_MinHits;} + + /// Set the minimum number of LSH hits to initiate + /// a calculation of the Jaccard distance. + /// Setting to zero permits CBlastKmer to choose a value based upon the alphabet. + // @param minhits integer + void SetMinHits(int minhits) {m_MinHits = minhits;} + + /// Gets the number of matches (subject sequences) + /// to return + /// @return integer + int GetNumTargetSeqs() const {return m_NumTargetSeqs;} + + /// Sets the number of matches (subject sequences) + /// to return. Zero indicates all. + /// @param num integer + void SetNumTargetSeqs(int matches) {m_NumTargetSeqs = matches;} + +private: + + /// value of the threshold + double m_Thresh; + + /// Value of number of LSH hits to initiate the + /// calculation of the Jaccard distance. + int m_MinHits; + + /// Number of matches to return + int m_NumTargetSeqs; +}; + + +END_NCBI_SCOPE + +#endif /* BLAST_KMER_OPTIONS_HPP */ diff --git a/c++/include/algo/blast/proteinkmer/blastkmerresults.hpp b/c++/include/algo/blast/proteinkmer/blastkmerresults.hpp new file mode 100644 index 00000000..b982cf86 --- /dev/null +++ b/c++/include/algo/blast/proteinkmer/blastkmerresults.hpp @@ -0,0 +1,236 @@ +/* $Id: blastkmerresults.hpp 536866 2017-05-24 01:23:19Z ucko $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Tom Madden + * + * File Description: + * Results for BLAST-kmer searches + * + */ + +#ifndef BLAST_KMER_RESULTS_HPP +#define BLAST_KMER_RESULTS_HPP + + +#include +#include +#include +#include +#include +#include + +#include + +#include "blastkmerutils.hpp" + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(blast) + + +/// Vector of pairs of seq-ids and scores +typedef vector< pair, double> > TBlastKmerScoreVector; + +/// This class represents the results for one KMER search (one query). +/// The structure is filled in after the search is done. +/// NOTE: recoverable errors (e.g., query shorter than KMER size) will NOT +/// trigger an exception but the CBlastKmerResults for that query will have +/// an error or warning. Use the HasError or HasWarning message to check. +class NCBI_XBLAST_EXPORT CBlastKmerResults : public CObject +{ +public: + /// Constructor + /// @param query Seq-id of the query + /// @param scores Scores of the result + /// @param stats Statistics about the results + /// @param errs warning and messages + CBlastKmerResults(CConstRef query, + TBlastKmerPrelimScoreVector& scores, + BlastKmerStats& stats, + CRef seqdb, + const TQueryMessages& errs); + + /// Destructor + ~CBlastKmerResults() { + } + + + /// Get the vector of GIs and scores for the matches + const TBlastKmerScoreVector& GetScores() const { + return m_Scores; + } + + /// Get the results as a TSeqLocVector + /// @param tsl TSeqLocVector to fill [in/out] + /// @param scope CScope to use in the TSL [in] + void GetTSL(TSeqLocVector& tsl, CRef scope) const; + + /// Get the statistics for the search. + const BlastKmerStats& GetStats() const { + return m_Stats ; + } + + /// Set the statistics + /// @param stats structure of ancillary data. Will make deep copy. + void SetStats(BlastKmerStats& stats) { + m_Stats = stats; + } + + /// Return Query ID + CConstRef GetSeqId() const { + return m_QueryId; + } + + /// Accessor for the error/warning messsages for this query + /// @param min_severity minimum severity to report errors [in] + TQueryMessages GetErrors(int min_severity = eBlastSevError) const; + + /// Returns true if there are errors among the results for this object + bool HasErrors() const; + /// Returns true if there are warnings among the results for this object + bool HasWarnings() const; + +private: + + /// Saves the matches as TBlastKmerScoreVector. + /// Also does the lookup of the Seq-id of subject sequences. + /// @param scores results to be processed and saved. + void x_InitScoreVec(TBlastKmerPrelimScoreVector& scores); + + /// Query ID. + CConstRef m_QueryId; + + /// Vector of Seq-ids and scores + TBlastKmerScoreVector m_Scores; + + /// Ancillary data + BlastKmerStats m_Stats; + + /// Database searched + CRef m_SeqDB; + + /// error/warning messages for this query + TQueryMessages m_Errors; +}; + +/// This class holds one or more CBlastKmerResults +class NCBI_XBLAST_EXPORT CBlastKmerResultsSet : public CObject +{ +public: + + /// data type contained by this container + typedef CRef value_type; + + /// size_type type definition + typedef vector::size_type size_type; + + /// const_iterator type definition + typedef vector::const_iterator const_iterator; + + /// iterator type definition + typedef vector::iterator iterator; + + /// List of query ids. + typedef vector< CConstRef > TQueryIdVector; + + /// Vector of TBlastKmerScoreVector (scores) + typedef vector TBlastKmerPrelimScoreVectorSet; + + /// Vector of KmerStats + typedef vector TBlastKmerStatsVector; + + /// Default constructor + CBlastKmerResultsSet(); + + /// Constructor + /// @param ids vector of Query IDs + /// @param scores vector of TBlastKmerScoreVector + /// @param stats vector of Statistics + /// @param seqdb CSeqDB object for search. + /// @param msg_vec vector of messages and warnings. + CBlastKmerResultsSet(TQueryIdVector& ids, + TBlastKmerPrelimScoreVectorSet& scores, + TBlastKmerStatsVector& stats, + CRef seqdb, + TSearchMessages msg_vec); + + /// Destructor + ~CBlastKmerResultsSet() { + } + + + CBlastKmerResults & operator[](size_type i) { + return *m_Results[i]; + } + + const CBlastKmerResults & operator[](size_type i) const { + return *m_Results[i]; + } + + /// Array like acces with CSeq_id indices + /// @param ident query sequence id [in] + CRef operator[](const CSeq_id &ident); + + /// Returns the number of queries. + size_t GetNumQueries() const { return m_NumQueries;} + + /// Add an element to m_Results + /// @param element to add [in] + void push_back(value_type& element); + +private: + + /// @param ids vector of Query IDs + /// @param scores vector of TBlastKmerScoreVector + /// @param stats vector of Statistics + /// @param seqdb CSeqDB object for search. + /// @param msg_vec vector of messages and warnings. + void x_Init(TQueryIdVector& ids, + TBlastKmerPrelimScoreVectorSet& scores, + TBlastKmerStatsVector& stats, + CRef seqdb, + TSearchMessages msg_vec); + + /// Vectors of results + vector< CRef > m_Results; + + /// Number or queries + size_t m_NumQueries; +}; + +/// Empty results (use on error) +/// @param queryVector Query information. +/// @param queryNum zero offset number of query +/// @param errMsg error message +/// @param severity Severity of messages (e.g., error or warning) +CRef +MakeEmptyResults(TSeqLocVector& queryVector, + int queryNum, + const string& errMsg, + EBlastSeverity severity=eBlastSevError); + +END_SCOPE(blast) +END_NCBI_SCOPE + +#endif /* BLAST_KMER_RESULTS_HPP */ diff --git a/c++/include/algo/blast/proteinkmer/blastkmerutils.hpp b/c++/include/algo/blast/proteinkmer/blastkmerutils.hpp new file mode 100644 index 00000000..330e07a6 --- /dev/null +++ b/c++/include/algo/blast/proteinkmer/blastkmerutils.hpp @@ -0,0 +1,311 @@ +/* $Id: blastkmerutils.hpp 536877 2017-05-24 13:12:55Z madden $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Tom Madden + * + * File Description: + * Utilities for BLAST kmer + * + */ + +#ifndef BLAST_KMER_UTILS_HPP +#define BLAST_KMER_UTILS_HPP + + +#include +#include +#include +#include + +#include "mhfile.hpp" + +BEGIN_NCBI_SCOPE +USING_SCOPE(blast); + +// From http://primes.utm.edu/lists/small/millions +#define PKMER_PRIME 1048583 + +/// Structure for ancillary data on KMER search. +/// Describes how many hits were examined etc. +struct BlastKmerStats { + /// Constructor + /// @param hit_count How many hits to the hash array + /// @param jd_count how often was Jaccard distance calculated. + /// @param jd_oid_count how many OIDs for Jaccard distance. + /// @param oids_considered Number OIDs considered as candidates. + /// @param total_matches Number of matches returned. + /// @param seqs Number of database sequences considered + BlastKmerStats(int hit_count=0, + int jd_count=0, + int jd_oid_count=0, + int oids_considered=0, + int total_matches=0, + int seqs=0) + : hit_count(hit_count), + jd_count(jd_count), + jd_oid_count(jd_oid_count), + oids_considered(oids_considered), + total_matches(total_matches), + num_sequences(seqs) + { + } + /// How many hits to the hash array were there? + int hit_count; + /// How often was the Jaccard distance calculated. + int jd_count; + /// How many OIDs was the Jaccard distance calculated for. + int jd_oid_count; + /// How many OIDs were considered as candidates. + int oids_considered; + /// How many matches returned. + int total_matches; + /// Number of database sequences considered (in this volume) + int num_sequences; +}; + +struct SBlastKmerParameters { + /// Constructor + /// + SBlastKmerParameters(int numHashes, + int rowsPerBand, + int samples, + int kmerNum, + int alphabetChoice, + int version, + int chunkSize=150) + : numHashes(numHashes), rowsPerBand(rowsPerBand), samples(samples), + kmerNum(kmerNum), alphabetChoice(alphabetChoice), version(version), + chunkSize(chunkSize) + { + } + /// Number of hash functions per signature + int numHashes; + /// Number of values sampled from signature. + int rowsPerBand; + /// Number of samples of query signature are made? + int samples; + /// number of letters in KMER. + int kmerNum; + /// 15 or 10 letter alphabet (0 for 15, 1 for 10). + int alphabetChoice; + /// Version of index used (0 indicates default). + int version; + /// size of a query chunk to process (default is 150). + int chunkSize; +}; + +/// Vector of pairs of database OIDs and scores. +/// ONLY for use during KMER search, not presentation of results +/// or communication with other modules (BLAST or not). +typedef vector< pair > TBlastKmerPrelimScoreVector; + +struct SOneBlastKmerSearch { + + /// Constructor + /// @param numFiles Number of (alias) files to search + SOneBlastKmerSearch(int numFiles=0) + : qSeqid(), queryHash(), queryLSHHash() + { + scoreVector.resize(numFiles); + kmerStatsVector.resize(numFiles); + status=0; + severity=eBlastSevInfo; + errDescription=kEmptyStr; + } + + /// Seqid of the query. + CRef qSeqid; + /// Hashes for one query (multiple chunks) + vector < vector > queryHash; + /// LSH Hashes for one query (multiple chunks) + vector < vector > queryLSHHash; + /// Scores for one query + vector< TBlastKmerPrelimScoreVector > scoreVector; + /// Stats for one query + vector< BlastKmerStats > kmerStatsVector; + /// Status of the query (0 is good, otherwise an error has occurred) + int status; + /// Error or warning (only use if status is non-zero). + EBlastSeverity severity; + /// Error description + string errDescription; +}; + +/// Get KMERs for a given sequence using a compressed alphabet. +/// +///@param query_sequence string with one sequence [in] +///@param do_seg Should the sequence be segged (not recommended) [in] +///@param range portion of sequence to be processed [in] +///@param kmerNum size of kmer [in] +///@param alphabetChoice 0 is 15 letter, 1 is 10 letter alphabet [in] +///@return set of unsigned ints for the kmers. +NCBI_XBLAST_EXPORT +set BlastKmerGetKmerSet(const string& query_sequence, bool do_seg, TSeqRange& range, int kmerNum, int alphabetChoice); + +/// Get KMERs for a given sequence using a compressed alphabet. +/// This version can read in overrepresented KMERs and extend them by one. +///@param query_sequence string with one sequence [in] +///@param range portion of sequence to be processed [in] +///@param kmerNum size of kmer [in] +///@param alphabetChoice 0 is 15 letter, 1 is 10 letter alphabet [in] +///@param badMers Overrepresented KMERs [in] +///@return set of unsigned ints for the kmers. +NCBI_XBLAST_EXPORT +set BlastKmerGetKmerSet2(const string& query_sequence, TSeqRange& range, int kmerNum, int alphabetChoice, vector badMers); + +/// Simplified version of BlastKmerGetKmerSet. Intended +/// for gathering statistics on KMERS in the database. +/// +///@param query_sequence string with one sequence [in] +///@param kmerNum size of kmer [in] +///@return param kmerCount Count population of different KMERS +///@return param kmerCount Count population of different KMERS one longer than kmerNum +///@param alphabetChoice 0 is 15 letter, 1 is 10 letter alphabet [in] +///@param perQuery COunt kmers per query or total in database. +///@return set of unsigned ints for the kmers. +NCBI_XBLAST_EXPORT +set BlastKmerGetKmerSetStats(const string& query_sequence, int kmerNum, map& kmerCount, map& kmerCountPlus, int alphabetChoice, bool perQuery); + +/// Breaks a sequences up into chunks if the sequences is above a certain length. +/// Each chunk has an overlap with the adjoining chunks. +/// Breaking sequences up into chunks makes the minhash procedure much more +/// effective two sequences of different lengths are being compared. +/// +/// @param length Total length of sequence being broken up [in] +/// @param range_v Vector of ranges to be filled in [out] +/// @param chunkSize number of residues in sequence chunk [in] +/// @return number of chunks. Should be integer more than zero. Zero or less indicates an error. +NCBI_XBLAST_EXPORT +int BlastKmerBreakUpSequence(int length, vector& range_v, int chunkSize); + +/// Creates translation table for compressed alphabets +/// +/// @param trans_table Translation table [out] +/// @param alphabetChoice 0 is 15 letter, 1 is 10 letter alphabet [in] +/// +NCBI_XBLAST_EXPORT +void BlastKmerGetCompressedTranslationTable(vector& trans_table, int alphabetChoice); + +/// Calculates the number of differences between two minhash arrays. +/// Used to decide whether two arrays are similar enough. The assumption +/// is made that both arrays are of the same size. +/// @param minhash1 First array [in] +/// @param minhash2 Second array [in] +/// @return distance. +NCBI_XBLAST_EXPORT +int BlastKmerGetDistance(const vector& minhash1, const vector& minhash2); + +NCBI_XBLAST_EXPORT +bool minhash_query(const string& query, + vector < vector >& seq_hash, + int num_hashes, + uint32_t *a, + uint32_t *b, + int do_seg, + int kmerNum, + int alphabetChoice, + int chunkSize); + +/// Hash the query for the minimum values; +/// @param query as a ASCII string [in] +/// @param seq_hash hash values for all kmers [out] +/// @param kmerNum number of letters in a KMER [in] +/// @param numHashes number of hashes in a signature [in] +/// @param alphabetChoice 15 or 10 letters [in] +/// @param badMers Overrepresented KMERS [in] +NCBI_XBLAST_EXPORT +bool minhash_query2(const string& query, + vector < vector >& seq_hash, + int kmerNum, + int numHashes, + int alphabetChoice, + vector badMers, + int chunkSize); + +NCBI_XBLAST_EXPORT +void get_LSH_match_from_hash(const vector< vector > &lsh_hash_vec, + const uint64_t* lsh_array, + vector < set >& candidates); + +NCBI_XBLAST_EXPORT +void get_LSH_hashes(vector < vector >& query_hash, + vector < vector >& lsh_hash_vec, + int num_bands, + int rows_per_band); + +/// Gets the LSH hash for one hash function. +/// @param query_hash Hash values for query [in] +/// @param lsh_hash_vec LSH query hash [out] +/// @param numHashes number of hashes in signature [in] +/// @param numRows number of rows (2?) in LSH [in] +NCBI_XBLAST_EXPORT +void get_LSH_hashes5(vector < vector >& query_hash, + vector < vector >&lsh_hash_vec, + int numHashes, + int numRows); + +NCBI_XBLAST_EXPORT +void neighbor_query(const vector < vector >& query_hash, + const uint64_t* lsh, + vector< set >& candidates, + CMinHashFile& mhfile, + int num_hashes, + int min_hits, + double thresh, + TBlastKmerPrelimScoreVector& score_vector, + BlastKmerStats& kmer_stats, + int kmerVersion); + +/// Get the random numbers for the hash function. +NCBI_XBLAST_EXPORT +void GetRandomNumbers(uint32_t* a, + uint32_t* b, + int numHashes); + +/// Function to get the k sites to compare for Buhler LSH. +NCBI_XBLAST_EXPORT +void GetKValues(vector< vector >& kvector, + int k_value, + int l_value, + int array_size); + +// Find candidate matches with LSH. +// Based on article by Buhler (PMID:11331236) but applied to our arrays +// of hash functions rather than sequences. +// +NCBI_XBLAST_EXPORT +void get_LSH_hashes2(vector < vector >& query_hash, + vector < vector >&lsh_hash_vec, + int num_k, + int num_l, + vector< vector >& kValues); + + + +NCBI_XBLAST_EXPORT +int BlastKmerVerifyIndex(CRef seqdb, string &error_msg); + +END_NCBI_SCOPE +#endif /* BLAST_KMER_UTILS_HPP */ diff --git a/c++/include/algo/blast/proteinkmer/kblastapi.hpp b/c++/include/algo/blast/proteinkmer/kblastapi.hpp new file mode 100644 index 00000000..8850b5bc --- /dev/null +++ b/c++/include/algo/blast/proteinkmer/kblastapi.hpp @@ -0,0 +1,106 @@ +/* $Id: kblastapi.hpp 536866 2017-05-24 01:23:19Z ucko $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Tom Madden + * + * File Description: + * Class to run BLAST search based on KMER preprocessing. + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#ifndef BLAST_KMER_API_HPP +#define BLAST_KMER_API_HPP + + +USING_NCBI_SCOPE; +USING_SCOPE(objects); +USING_SCOPE(blast); + +///////////////////////////////////////////////////////////////////////////// +/// Threading class for BlastKmer searches. +/// Each thread runs a batch of input sequences +/// through KMER lookup and then through BLAST. +//////////// +class NCBI_XBLAST_EXPORT CBlastKmerSearch : public CObject +{ +public: + CBlastKmerSearch(CRef queryFactory, + CRef optsHndl, + CRef db) + : m_QueryFactory(queryFactory), + m_OptsHandle(optsHndl), + m_Database(db) + { } + + CBlastKmerSearch(CRef optsHndl, + CRef db) + : m_OptsHandle(optsHndl), + m_Database(db) + { } + + /// Sets the queries. Overrides any queries already set. + void SetQuery(CRef queryFactory) {m_QueryFactory = queryFactory;} + + /// Limits output by GILIST + /// @param list CRef to limit by [in] + void SetGiListLimit(CRef list) {m_GIList=list;} + + /// Limits output by negative GILIST + /// @param list CRef to limit by [in] + void SetGiListLimit(CRef list) {m_NegGIList=list;} + + /// Run a KMER and then BLAST search + CRef Run(void); + +private: + + /// Holds the query seqloc and scope + CRef m_QueryFactory; + + /// Options for KMER search + CRef m_OptsHandle; + + /// Database to search. + CRef m_Database; + + /// GIList to limit search by. + CRef m_GIList; + + /// Negative GIList to limit search by. + /// Only one of the gilist or negative GIlist should be set. + CRef m_NegGIList; +}; + +#endif /* BLAST_KMER_API_HPP */ diff --git a/c++/include/algo/blast/proteinkmer/mhfile.hpp b/c++/include/algo/blast/proteinkmer/mhfile.hpp new file mode 100644 index 00000000..9023fde5 --- /dev/null +++ b/c++/include/algo/blast/proteinkmer/mhfile.hpp @@ -0,0 +1,197 @@ +/* $Id: mhfile.hpp 536866 2017-05-24 01:23:19Z ucko $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Tom Madden + * + * File Description: + * Access minhash files. + * + */ + +#ifndef MHFILE_HEADER__HPP +#define MHFILE_HEADER__HPP + +#include +#include +#include + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(blast) + +class NCBI_XBLAST_EXPORT CMinHashException : public CException { +public: + /// Error types + enum EErrCode { + /// Argument validation failed. + eArgErr, + + /// Zero length files. + eFileEmpty, + + /// Memory allocation failed. + eMemErr + }; + + /// Get a message describing the situation leading to the throw. + virtual const char* GetErrCodeString() const + { + switch ( GetErrCode() ) { + case eArgErr: return "eArgErr"; + case eFileEmpty: return "eFileErr"; + default: return CException::GetErrCodeString(); + } + } + + /// Include standard NCBI exception behavior. + NCBI_EXCEPTION_DEFAULT(CMinHashException,CException); + +}; + +#define KMER_LSH_ARRAY_SIZE 0x1000001 +#define KMER_RANDOM_NUM_OFFSET 48 // 48 bytes after start of file. + +/// Structure of file on disk +struct MinHashIndexHeader { + /// Version of the index + int version; + /// Number of sequences represented in the index. + int num_seqs; + /// Number of hash functions + int num_hashes; + /// Should seg be run? + int do_seg; + /// Size of KMER used. + int kmerNum; + /// How many hash functions per band + int rows_per_band; + /// Width of the data (1 is one byte, 2 is a short, 0 or 4 is an integer) + int dataWidth; + /// zero is 15 letter, 1 is 10 letter alphabet. + int Alphabet; + /// Starts of the LSH matches. + int LSHStart; + /// How many are there (is this number of integers or 4*number)? + int LSHSize; + /// End of the LSH matches. + uint64_t LSHMatchEnd; + /// Residues in one Chunk (version 3 or greater) + int chunkSize; + /// For use in future. + int futureUse; +}; + + + +/// Access data in Minhash files +class NCBI_XBLAST_EXPORT CMinHashFile : public CObject { +public: + /// parameterized constructor + CMinHashFile(const string& indexname); + + int GetVersion(void) const { return m_Data->version;} + + int GetNumSeqs(void) const { return m_Data->num_seqs;} + + /// Returns the number of values in an array of hashes (probably 32) + int GetNumHashes(void) const { return m_Data->num_hashes;} + + int GetSegStatus(void) const { return m_Data->do_seg;} + + /// Returns the length of the KMER + int GetKmerSize(void) const { return m_Data->kmerNum;} + + int GetRows(void) const { return m_Data->rows_per_band;} + + int GetDataWidth(void) const { return (m_Data->dataWidth == 0 ? 4 : m_Data->dataWidth);} + + /// One of two alphabets from Shiryev et al.(2007), Bioinformatics, 23:2949-2951 + /// 0 means 15 letters (based on SE_B(14)), 1 means 10 letters (based on SE-V(10)) + int GetAlphabet(void) const { return m_Data->Alphabet;} + + int GetLSHSize(void) const { return m_Data->LSHSize;} + + int GetLSHStart(void) const {return m_Data->LSHStart;} + // Needed? + uint64_t GetLSHMatchEnd(void) const {return m_Data->LSHMatchEnd;} + + /// Get number of letters in a chunk (version 3 or higher) + int GetChunkSize(void) const { return m_Data->chunkSize;} + + // Random numbers come after the LSH matches. + uint32_t* GetRandomNumbers(void) const; + + /// Overrepresented KMERs + void GetBadMers(vector &badMers) const; + + /// LSH points for Buhler approach. + unsigned char* GetKValues(void) const; + + uint64_t* GetLSHArray(void) const { return ((uint64_t*)m_MmappedIndex->GetPtr()) + (uint64_t)GetLSHStart()/8;} + + int* GetHits(uint64_t offset) const {return ((int*) m_MmappedIndex->GetPtr()) + offset/4;} + + uint32_t* GetMinHits(int oid) const {return (uint32_t*) (m_MinHitsData + (uint64_t)4*(GetNumHashes()+1)*oid); } + + /// Gets the database OID and vector of hash values for entry given by oid. + /// @param oid Entry to fetch. + /// @param subjectOid OID of the BLAST database (for current volume) + /// @param hits Vector of the hash values read from disk. + void GetMinHits(int oid, int& subjectOid, vector& hits) const; + + /// Returns the number of hash arrays. + int GetNumSignatures() const {return (m_DataFileSize/(GetDataWidth()*GetNumHashes()+4));} + +private: + + uint32_t* x_GetMinHits32(int oid, int& subjectOid) const; + + uint16_t* x_GetMinHits16(int oid, int& subjectOid) const; + + unsigned char* x_GetMinHits8(int oid, int& subjectOid) const; + + // pointer to memory mapped index file. + auto_ptr m_MmappedIndex; + + // pointer to memory mapped data file. + auto_ptr m_MmappedData; + + MinHashIndexHeader* m_Data; + + /// Pointer to start of min-hits arrays. + unsigned char* m_MinHitsData; + + void x_Init(); + + /// m_MmappedData File size + Int8 m_DataFileSize; + + /// Name of the index file. + string m_IndexName; + +}; + +END_SCOPE(blast) +END_NCBI_SCOPE +#endif /* MHFILE_HEADER__HPP */ diff --git a/c++/include/algo/winmask/seq_masker_istat.hpp b/c++/include/algo/winmask/seq_masker_istat.hpp index c33bdf63..0eeb085d 100644 --- a/c++/include/algo/winmask/seq_masker_istat.hpp +++ b/c++/include/algo/winmask/seq_masker_istat.hpp @@ -1,4 +1,4 @@ -/* $Id: seq_masker_istat.hpp 462550 2015-03-19 14:07:19Z morgulis $ +/* $Id: seq_masker_istat.hpp 542542 2017-08-01 12:44:33Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -132,7 +132,7 @@ public: **\brief Get the value of the unit used to represent an ambuguity. **\return ambiguity unit value **/ - const CSeqMaskerWindow::TUnit AmbigUnit() const + CSeqMaskerWindow::TUnit AmbigUnit() const { return ambig_unit; } /** diff --git a/c++/include/algo/winmask/seq_masker_ostat.hpp b/c++/include/algo/winmask/seq_masker_ostat.hpp index d9f352bd..e1fdb73a 100644 --- a/c++/include/algo/winmask/seq_masker_ostat.hpp +++ b/c++/include/algo/winmask/seq_masker_ostat.hpp @@ -1,4 +1,4 @@ -/* $Id: seq_masker_ostat.hpp 462550 2015-03-19 14:07:19Z morgulis $ +/* $Id: seq_masker_ostat.hpp 542542 2017-08-01 12:44:33Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -153,9 +153,9 @@ protected: /**\name Methods used to delegate functionality to derived classes */ /**@{*/ virtual void doSetUnitSize( Uint4 us ) { unit_size = (Uint1)us; } - virtual void doSetUnitCount( Uint4 unit, Uint4 count ) = 0; - virtual void doSetComment( const string & msg ) {} - virtual void doSetParam( const string & name, Uint4 value ); + virtual void doSetUnitCount( Uint4 /*unit*/, Uint4 /*count*/ ) = 0; + virtual void doSetComment( const string & /*msg*/ ) {} + virtual void doSetParam( const string & /*name*/, Uint4 /*value*/ ); // virtual void doSetBlank() {} virtual void doFinalize() {} /**@}*/ diff --git a/c++/include/cgi/cgi_exception.hpp b/c++/include/cgi/cgi_exception.hpp index c0ed6b50..d1476ca7 100644 --- a/c++/include/cgi/cgi_exception.hpp +++ b/c++/include/cgi/cgi_exception.hpp @@ -1,7 +1,7 @@ #ifndef CGI___CGI_EXCEPTION__HPP #define CGI___CGI_EXCEPTION__HPP -/* $Id: cgi_exception.hpp 441525 2014-07-24 16:55:45Z grichenk $ +/* $Id: cgi_exception.hpp 541889 2017-07-24 13:05:43Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -368,6 +368,31 @@ public: }; +///////////////////////////////////////////////////////////////////////////// +/// +/// CCgiAppException -- +/// +/// Other CCgiApplication exceptions. + +class CCgiAppException : public CCgiException +{ +public: + enum EErrCode { + eApp //< Other error + }; + + virtual const char* GetErrCodeString(void) const + { + switch (GetErrCode()) { + case eApp: return "CGI application error"; + default: return CException::GetErrCodeString(); + } + } + + NCBI_EXCEPTION_DEFAULT(CCgiAppException, CCgiException); +}; + + #define NCBI_CGI_THROW_WITH_STATUS(exception, err_code, message, status) \ { \ NCBI_EXCEPTION_VAR(cgi_exception, exception, err_code, message); \ diff --git a/c++/include/cgi/cgi_serial.hpp b/c++/include/cgi/cgi_serial.hpp index 056012f8..7d4d258b 100644 --- a/c++/include/cgi/cgi_serial.hpp +++ b/c++/include/cgi/cgi_serial.hpp @@ -1,7 +1,7 @@ #ifndef CGI___CGI_SERIAL__HPP #define CGI___CGI_SERIAL__HPP -/* $Id: cgi_serial.hpp 484889 2015-11-16 21:56:43Z lavr $ +/* $Id: cgi_serial.hpp 535133 2017-05-05 14:01:02Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -96,7 +96,7 @@ public: class COStreamHelper { public: - COStreamHelper(CNcbiOstream& os) : m_Ostream(os), m_str(NULL) {} + COStreamHelper(CNcbiOstream& os) : m_Ostream(os), m_str(nullptr) {} ~COStreamHelper() { try { flush(); } catch (...) {} } operator CNcbiOstream&() { return x_GetStrm(); } @@ -111,7 +111,7 @@ public: void flush(bool write_empty_data = false) { if (m_str.get() != NULL) { - auto_ptr strm(m_str.release()); + unique_ptr strm(m_str.release()); string s = CNcbiOstrstreamToString(*strm); // Historically counted, but did not output, a final \0. m_Ostream << (s.size() + 1) << ' ' << s; @@ -127,8 +127,7 @@ private: return *m_str; } CNcbiOstream& m_Ostream; - auto_ptr m_str; - + unique_ptr m_str; }; diff --git a/c++/include/cgi/cgiapp.hpp b/c++/include/cgi/cgiapp.hpp index a5e35b27..e9922c9d 100644 --- a/c++/include/cgi/cgiapp.hpp +++ b/c++/include/cgi/cgiapp.hpp @@ -1,7 +1,7 @@ #ifndef CGI___CGIAPP__HPP #define CGI___CGIAPP__HPP -/* $Id: cgiapp.hpp 497034 2016-04-04 12:46:26Z dicuccio $ +/* $Id: cgiapp.hpp 523183 2016-12-29 14:53:26Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -150,6 +150,8 @@ private: void SaveResultToCache(const CCgiRequest& request, CNcbiIstream& is); void SaveRequest(const string& rid, const CCgiRequest& request); CCgiRequest* GetSavedRequest(const string& rid); + bool x_ProcessHelpRequest(void); + bool x_ProcessVersionRequest(void); protected: /// Check the command line arguments before parsing them. @@ -273,6 +275,65 @@ protected: /// @sa CHttpResponse::SetStatus() void SetHTTPStatus(unsigned int status, const string& reason = kEmptyStr); + /// Process help request: set content type, print usage informations etc. + /// For automatic handling of help request all of the following conditions + /// must be met: + /// - CGI_ENABLE_HELP_REQUEST=t must be set in the environment or + /// EnableHelpRequest=t in [CGI] section of the INI file. + /// - REQUEST_METHOD must be GET + /// - query string must include ncbi_help[=] argument (all other + /// arguments are ignored). + /// The default implementation looks for .help. files in + /// the app directory, then for help.. The formats are checked in + /// the following order: + /// 1. If format argument is present, try to open .help., + /// then help.. + /// 2. Check 'Accept:' http header; for each 'type/subtype' entry try to open + /// .help. and help.. + /// 3. Check availability of help files for html, xml, and json formats. + /// 4. Use CArgDescriptions to print help in XML format. + /// If a help file starts with 'Content-type: ...' followed by double- + /// newline, the specified content type is sent in the response regardless + /// of the actual format selected. + virtual void ProcessHelpRequest(const string& format); + + enum EVersionType { + eVersion_Short, + eVersion_Full + }; + + /// Process version request: set content type, print version informations etc. + /// For automatic handling of version request all of the following conditions + /// must be met: + /// - CGI_ENABLE_VERSION_REQUEST=t must be set in the environment or + /// EnableVersionRequest=t in [CGI] section of the INI file. + /// - REQUEST_METHOD must be GET + /// - query string must include ncbi_version=[short|full] argument (all other + /// arguments are ignored). + /// The default implementation prints GetVersion/GetFullVersion as plain text + /// (default), XML or JSON depending on the 'Accept:' HTTP header, if any. + virtual void ProcessVersionRequest(EVersionType ver_type); + + /// "Accept:" header entry. + struct SAcceptEntry { + SAcceptEntry(void) : m_Quality(1) {} + + typedef map TParams; + + string m_Type; + string m_Subtype; + float m_Quality; ///< Quality factor or "1" if not set (or not numeric). + string m_MediaRangeParams; ///< Media range parameters + TParams m_AcceptParams; ///< Accept parameters + + bool operator<(const SAcceptEntry& entry) const; + }; + + typedef list TAcceptEntries; + + /// Parse "Accept:" header, put entries to the list, more specific first. + void ParseAcceptHeader(TAcceptEntries& entries) const; + protected: /// Set CONN_HTTP_REFERER, print self-URL and referer to log. void ProcessHttpReferer(void); diff --git a/c++/include/cgi/cgictx.hpp b/c++/include/cgi/cgictx.hpp index 8325ac17..c4d60731 100644 --- a/c++/include/cgi/cgictx.hpp +++ b/c++/include/cgi/cgictx.hpp @@ -1,7 +1,7 @@ #ifndef NCBI_CGI_CTX__HPP #define NCBI_CGI_CTX__HPP -/* $Id: cgictx.hpp 500790 2016-05-09 11:30:33Z ivanov $ +/* $Id: cgictx.hpp 541889 2017-07-24 13:05:43Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -148,6 +148,17 @@ public: CCgiRequest::TFlags flags = 0 ); + CCgiContext(ICgiSessionStorage* session_storage, + const CNcbiArguments* args = 0 /* D: app.GetArguments() */, + const CNcbiEnvironment* env = 0 /* D: app.GetEnvironment() */, + CNcbiIstream* inp = 0 /* see ::CCgiRequest(istr) */, + CNcbiOstream* out = 0 /* see ::CCgiResponse(out) */, + int ifd = -1, + int ofd = -1, + size_t errbuf_size = 256, /* see CCgiRequest */ + CCgiRequest::TFlags flags = 0 + ); + virtual ~CCgiContext(void); const CCgiApplication& GetApp(void) const; @@ -239,8 +250,10 @@ public: CCgiResponse& response); private: + CCgiApplication& x_GetApp(void) const; CCgiServerContext& x_GetServerContext(void) const; - void x_InitSession(CCgiRequest::TFlags flags); + void x_InitSession(CCgiRequest::TFlags flags, + ICgiSessionStorage* session_storage = nullptr); void x_SetStatus(CCgiException::EStatusCode code, const string& msg) const; @@ -251,17 +264,17 @@ private: eSecure_On }; - CCgiApplication& m_App; - auto_ptr m_Request; // CGI request information - CCgiResponse m_Response; // CGI response information - auto_ptr m_Session; // CGI session + CCgiApplication* m_App; + unique_ptr m_Request; // CGI request information + CCgiResponse m_Response; // CGI response information + unique_ptr m_Session; // CGI session // message buffer typedef list< AutoPtr > TMessages; TMessages m_Messages; // server context will be obtained from CCgiApp::LoadServerContext() - auto_ptr m_ServerContext; // application defined context + unique_ptr m_ServerContext; // application defined context mutable string m_SelfURL; mutable string m_TrackingId; // cached tracking id @@ -353,7 +366,7 @@ private: inline const CCgiApplication& CCgiContext::GetApp(void) const { - return m_App; + return x_GetApp(); } diff --git a/c++/include/cgi/ncbicgi.hpp b/c++/include/cgi/ncbicgi.hpp index a262af45..8b99bba9 100644 --- a/c++/include/cgi/ncbicgi.hpp +++ b/c++/include/cgi/ncbicgi.hpp @@ -1,7 +1,7 @@ #ifndef CGI___NCBICGI__HPP #define CGI___NCBICGI__HPP -/* $Id: ncbicgi.hpp 497034 2016-04-04 12:46:26Z dicuccio $ +/* $Id: ncbicgi.hpp 512597 2016-09-01 15:49:22Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -419,7 +419,8 @@ private: : m_Value(value), m_Filename(filename), m_ContentType(type), m_Position(position) { } SData(const SData& data) - : m_Value(data.m_Value), m_Filename(data.m_Filename), + : CObject(), + m_Value(data.m_Value), m_Filename(data.m_Filename), m_ContentType(data.m_ContentType), m_Position(data.m_Position) { _ASSERT( !data.m_Reader.get() ); } diff --git a/c++/include/cgi/ncbicgir.hpp b/c++/include/cgi/ncbicgir.hpp index 54c85f94..f364f359 100644 --- a/c++/include/cgi/ncbicgir.hpp +++ b/c++/include/cgi/ncbicgir.hpp @@ -1,7 +1,7 @@ #ifndef CGI___NCBICGIR__HPP #define CGI___NCBICGIR__HPP -/* $Id: ncbicgir.hpp 500790 2016-05-09 11:30:33Z ivanov $ +/* $Id: ncbicgir.hpp 534862 2017-05-03 12:54:15Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -290,9 +290,9 @@ private: static bool x_ClientSupportsChunkedTransfer(const CNcbiEnvironment& env); - const CCgiSession* m_Session; - auto_ptr m_TrackingCookie; - bool m_DisableTrackingCookie; + const CCgiSession* m_Session; + unique_ptr m_TrackingCookie; + bool m_DisableTrackingCookie; NCBI_PARAM_DECL(bool, CGI, ThrowOnBadOutput); typedef NCBI_PARAM_TYPE(CGI, ThrowOnBadOutput) TCGI_ThrowOnBadOutput; @@ -304,7 +304,7 @@ private: const CCgiRequest* m_Request; bool m_ChunkedTransfer; - mutable auto_ptr m_TrailerEnabled; + mutable unique_ptr m_TrailerEnabled; friend class CCgiContext; // to set m_JQuery_Callback friend class CCgiApplication; // need x_ClientSupportsChunkedTransfer() diff --git a/c++/include/cgi/user_agent.hpp b/c++/include/cgi/user_agent.hpp index d10ed173..d7207091 100644 --- a/c++/include/cgi/user_agent.hpp +++ b/c++/include/cgi/user_agent.hpp @@ -1,7 +1,7 @@ #ifndef CGI___USER_AGENT__HPP #define CGI___USER_AGENT__HPP -/* $Id: user_agent.hpp 514810 2016-09-26 15:28:00Z ivanov $ +/* $Id: user_agent.hpp 514598 2016-09-22 17:36:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/common/boost_skew_guard.hpp b/c++/include/common/boost_skew_guard.hpp index 2ae88075..f97438ed 100644 --- a/c++/include/common/boost_skew_guard.hpp +++ b/c++/include/common/boost_skew_guard.hpp @@ -1,7 +1,7 @@ #ifndef COMMON___BOOST_SKEW_GUARD__HPP #define COMMON___BOOST_SKEW_GUARD__HPP -/* $Id: boost_skew_guard.hpp 477547 2015-08-31 15:59:25Z ucko $ +/* $Id: boost_skew_guard.hpp 532719 2017-04-07 18:52:57Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -47,6 +47,9 @@ # include # include # include +# ifndef BOOST_STATIC_ASSERT_MSG +# define BOOST_STATIC_ASSERT_MSG(a, m) BOOST_STATIC_ASSERT(a) +# endif BEGIN_LOCAL_NAMESPACE; BOOST_STATIC_ASSERT_MSG(BOOST_VERSION == NCBI_EXPECTED_BOOST_VERSION, "Boost version skew detected; please remember to use $(BOOST_INCLUDE)!" diff --git a/c++/include/common/config/ncbiconf_msvc.h b/c++/include/common/config/ncbiconf_msvc.h index c5d805a4..c89a2c28 100644 --- a/c++/include/common/config/ncbiconf_msvc.h +++ b/c++/include/common/config/ncbiconf_msvc.h @@ -1,4 +1,4 @@ -/* $Id: ncbiconf_msvc.h 487459 2015-12-17 18:57:21Z ucko $ +/* $Id: ncbiconf_msvc.h 535284 2017-05-08 13:25:16Z ucko $ * By Denis Vakatov, NCBI (vakatov@ncbi.nlm.nih.gov) * * MS-Win 32/64, MSVC++ 6.0/.NET @@ -32,9 +32,6 @@ #define HAVE_STRDUP 1 #define HAVE_STRICMP 1 #define NCBI_USE_THROW_SPEC 1 -#if _MSC_VER < 1400 -# define HAVE_NO_AUTO_PTR 1 -#endif #define STACK_GROWS_DOWN 1 #define HAVE_IOS_REGISTER_CALLBACK 1 #define HAVE_IOS_XALLOC 1 diff --git a/c++/include/common/config/ncbiconf_universal.h b/c++/include/common/config/ncbiconf_universal.h index a92303c4..94fbbd59 100644 --- a/c++/include/common/config/ncbiconf_universal.h +++ b/c++/include/common/config/ncbiconf_universal.h @@ -1,7 +1,7 @@ #ifndef NCBICONF_UNIVERSAL_H #define NCBICONF_UNIVERSAL_H -/* $Id: ncbiconf_universal.h 509096 2016-08-03 11:33:41Z ivanov $ +/* $Id: ncbiconf_universal.h 508813 2016-08-01 17:08:36Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/common/config/ncbiconf_xcode.h b/c++/include/common/config/ncbiconf_xcode.h index 857a2591..4de27f91 100644 --- a/c++/include/common/config/ncbiconf_xcode.h +++ b/c++/include/common/config/ncbiconf_xcode.h @@ -1,4 +1,4 @@ -/* $Id: ncbiconf_xcode.h 509096 2016-08-03 11:33:41Z ivanov $ +/* $Id: ncbiconf_xcode.h 535285 2017-05-08 13:28:00Z ucko $ * By Vlad Lebedev, NCBI (lebedev@ncbi.nlm.nih.gov) * * Mac OS X - xCode Build @@ -418,18 +418,6 @@ /* Define to 1 if you have the header file. */ #define HAVE_NETINET_TCP_H 1 -/* Define to 1 if `auto_ptr' is missing or broken. */ -/* #undef HAVE_NO_AUTO_PTR */ - -/* Define to 1 if `std::char_traits' is missing. */ -/* #undef HAVE_NO_CHAR_TRAITS */ - -/* Define to 1 if new C++ streams lack `ios_base::'. */ -/* #undef HAVE_NO_IOS_BASE */ - -/* Define to 1 if `min'/`max' templates are not implemented. */ -/* #undef HAVE_NO_MINMAX_TEMPLATE */ - /* Define to 1 if the ORBacus CORBA package is available. */ /* #undef HAVE_ORBACUS */ @@ -546,6 +534,9 @@ /* Define to 1 if you have the `strndup' function. */ /* #undef HAVE_STRNDUP */ +/* Define to 1 if you have the `strnlen' function. */ +#define HAVE_STRNLEN 1 + /* Define to 1 if you have the `strsep' function. */ #undef HAVE_STRSEP @@ -698,9 +689,6 @@ functions that never return. */ #define NCBI_NORETURN __attribute__((__noreturn__)) -/* Define to 1 if `string::compare()' is non-standard. */ -/* #undef NCBI_OBSOLETE_STR_COMPARE */ - /* Define to whatever syntax, if any, your compiler supports for marking types as packed to save memory. */ #define NCBI_PACKED __attribute__((packed)) diff --git a/c++/include/common/ncbi_build_ver.h.in b/c++/include/common/ncbi_build_ver.h.in index c986400d..624da6ba 100644 --- a/c++/include/common/ncbi_build_ver.h.in +++ b/c++/include/common/ncbi_build_ver.h.in @@ -1,4 +1,4 @@ -/* $Id: ncbi_build_ver.h.in 513308 2016-09-09 12:04:16Z ivanov $ +/* $Id: ncbi_build_ver.h.in 548545 2017-10-16 15:19:46Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -26,6 +26,8 @@ #if @NCBI_TEAMCITY_BUILD_NUMBER@ != 0 # define NCBI_TEAMCITY_BUILD_NUMBER @NCBI_TEAMCITY_BUILD_NUMBER@ +# define NCBI_TEAMCITY_PROJECT_NAME "@NCBI_TEAMCITY_PROJECT_NAME@" +# define NCBI_TEAMCITY_BUILDCONF_NAME "@NCBI_TEAMCITY_BUILDCONF_NAME@" #endif #if @NCBI_SUBVERSION_REVISION@ != 0 diff --git a/c++/include/common/ncbi_export.h b/c++/include/common/ncbi_export.h index 97ab0d79..a2c1e445 100644 --- a/c++/include/common/ncbi_export.h +++ b/c++/include/common/ncbi_export.h @@ -1,7 +1,7 @@ #ifndef COMMON___NCBI_EXPORT__H #define COMMON___NCBI_EXPORT__H -/* $Id: ncbi_export.h 498832 2016-04-19 21:18:13Z vasilche $ +/* $Id: ncbi_export.h 534723 2017-05-01 18:22:26Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1463,6 +1463,24 @@ #endif +/* Export specifier for library cdd_access + */ +#ifdef NCBI_CDD_ACCESS_EXPORTS +# define NCBI_CDD_ACCESS_EXPORT NCBI_DLL_EXPORT +#else +# define NCBI_CDD_ACCESS_EXPORT NCBI_DLL_IMPORT +#endif + + +/* Export specifier for library ncbi_id2proc_cdd + */ +#ifdef NCBI_ID2PROC_CDD_EXPORTS +# define NCBI_ID2PROC_CDD_EXPORT NCBI_DLL_EXPORT +#else +# define NCBI_ID2PROC_CDD_EXPORT NCBI_DLL_IMPORT +#endif + + /* STATIC LIBRARIES SECTION */ /* This section is for static-only libraries */ diff --git a/c++/include/common/ncbi_package_ver.h b/c++/include/common/ncbi_package_ver.h index c4b937c4..eef44436 100644 --- a/c++/include/common/ncbi_package_ver.h +++ b/c++/include/common/ncbi_package_ver.h @@ -7,8 +7,8 @@ #define NCBI_PACKAGE 1 #define NCBI_PACKAGE_NAME "blast" #define NCBI_PACKAGE_VERSION_MAJOR 2 -#define NCBI_PACKAGE_VERSION_MINOR 6 -#define NCBI_PACKAGE_VERSION_PATCH 0 +#define NCBI_PACKAGE_VERSION_MINOR 7 +#define NCBI_PACKAGE_VERSION_PATCH 1 #define NCBI_PACKAGE_CONFIG "" #define NCBI_PACKAGE_VERSION_STRINGIFY(x) #x diff --git a/c++/include/common/ncbi_skew_guard.h b/c++/include/common/ncbi_skew_guard.h index 44c6919c..56d11457 100644 --- a/c++/include/common/ncbi_skew_guard.h +++ b/c++/include/common/ncbi_skew_guard.h @@ -1,4 +1,4 @@ -/* $Id: ncbi_skew_guard.h 346326 2011-12-06 15:28:48Z ucko $ +/* $Id: ncbi_skew_guard.h 546682 2017-09-20 15:48:00Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -46,7 +46,7 @@ /* #undef NCBI_EXPECTED_CXX_VER */ #if defined(_NCBILCL_) && defined(FORWARDING_NCBICONF_H) \ - && !defined(NCBI_ALLOW_MISMATCHED_VERSIONS) + && !defined(NCBI_ALLOW_MISMATCHED_VERSIONS) && !defined(CTRANSITION_NS) /* The last change to shared headers before this guard came along occurred * on Nov. 30, 2011. */ diff --git a/c++/include/common/ncbi_source_ver.h b/c++/include/common/ncbi_source_ver.h index 0c86e107..381b316b 100644 --- a/c++/include/common/ncbi_source_ver.h +++ b/c++/include/common/ncbi_source_ver.h @@ -1,4 +1,4 @@ -/* $Id: ncbi_source_ver.h 510638 2016-08-14 02:48:40Z ucko $ +/* $Id: ncbi_source_ver.h 548044 2017-10-08 12:37:17Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -26,8 +26,8 @@ #include -#define NCBI_PRODUCTION_VER 20160806 -#define NCBI_DEVELOPMENT_VER 20160726 +#define NCBI_PRODUCTION_VER 20170709 +#define NCBI_DEVELOPMENT_VER 20170605 #ifdef HAVE_COMMON_NCBI_BUILD_VER_H # include diff --git a/c++/include/common/ncbiconf_impl.h b/c++/include/common/ncbiconf_impl.h index e7a0f9d8..e25611f4 100644 --- a/c++/include/common/ncbiconf_impl.h +++ b/c++/include/common/ncbiconf_impl.h @@ -1,7 +1,7 @@ #ifndef COMMON___NCBICONF_IMPL__H #define COMMON___NCBICONF_IMPL__H -/* $Id: ncbiconf_impl.h 491618 2016-02-08 14:08:15Z ucko $ +/* $Id: ncbiconf_impl.h 548542 2017-10-16 15:18:59Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -127,6 +127,21 @@ # define NCBI_WARN_UNUSED_RESULT #endif +#if defined(__SSE_4_2__) || defined(__AVX__) +# define NCBI_SSE 42 +#elif defined(__SSE_4_1__) +# define NCBI_SSE 41 +#elif defined(__SSSE3__) +# define NCBI_SSE 40 +#elif defined(__SSE3__) +# define NCBI_SSE 30 +#elif defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64) \ + || (defined(_M_IX86_FP) && _M_IX86_FP >= 2) +# define NCBI_SSE 20 +#elif defined(__SSE__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1) +# define NCBI_SSE 10 +#endif + #ifdef __cplusplus # if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) \ || defined(__GXX_EXPERIMENTAL_CPP0X__) \ diff --git a/c++/include/common/test_data_path.h b/c++/include/common/test_data_path.h index 60e6f416..654a3716 100644 --- a/c++/include/common/test_data_path.h +++ b/c++/include/common/test_data_path.h @@ -1,7 +1,7 @@ #ifndef COMMON__TEST_DATA_PATH__H #define COMMON__TEST_DATA_PATH__H -/* $Id: test_data_path.h 381648 2012-11-27 16:33:11Z gouriano $ +/* $Id: test_data_path.h 535114 2017-05-05 11:49:52Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -41,7 +41,7 @@ /// Get the directory where test data is stored at NCBI. /// The location is hard coded, but can be changed using -/// environment variable NCBI_TEST_DATA_PATH. +/// environment variables NCBI_TEST_DATA_PATH or NCBI_TEST_DATA. /// /// @return /// Pointer to internal zero-terminated string buffer. @@ -49,13 +49,18 @@ static const char* NCBI_GetTestDataPath(void) { static const char* s_NcbiTestDataPath = NULL; - if ( s_NcbiTestDataPath ) + if (s_NcbiTestDataPath) { return s_NcbiTestDataPath; - + } + s_NcbiTestDataPath = getenv("NCBI_TEST_DATA"); + if (s_NcbiTestDataPath) { + return s_NcbiTestDataPath = strdup(s_NcbiTestDataPath); + } s_NcbiTestDataPath = getenv("NCBI_TEST_DATA_PATH"); - if ( s_NcbiTestDataPath ) + if (s_NcbiTestDataPath) { return s_NcbiTestDataPath = strdup(s_NcbiTestDataPath); - + } + s_NcbiTestDataPath = //#ifdef NCBI_OS_DARWIN @@ -63,9 +68,9 @@ static const char* NCBI_GetTestDataPath(void) //#elif defined(NCBI_OS_MSWIN) #if defined(NCBI_OS_MSWIN) - "\\\\snowman\\toolkit_test_data\\" + "\\\\snowman\\win-coremake\\Scripts\\test_data\\" #else - "/net/snowman/vol/projects/toolkit_test_data/" + "/am/ncbiapdata/test_data/" #endif ; return s_NcbiTestDataPath; diff --git a/c++/include/connect/error_codes.hpp b/c++/include/connect/error_codes.hpp index 00e73e93..2502e4aa 100644 --- a/c++/include/connect/error_codes.hpp +++ b/c++/include/connect/error_codes.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT___ERROR_CODES__HPP #define CONNECT___ERROR_CODES__HPP -/* $Id: error_codes.hpp 451390 2014-11-06 15:25:51Z lavr $ +/* $Id: error_codes.hpp 533755 2017-04-19 16:26:34Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,7 +33,6 @@ /// @file error_codes.hpp /// Definition of all error codes used in connect library /// (xconnect.lib, xconnext.lib etc). -/// #include diff --git a/c++/include/connect/impl/thread_pool_for_server.hpp b/c++/include/connect/impl/thread_pool_for_server.hpp index 709b8d5d..e8b0d9c1 100644 --- a/c++/include/connect/impl/thread_pool_for_server.hpp +++ b/c++/include/connect/impl/thread_pool_for_server.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT__IMPL__THREAD_POOL_FOR_SERVER__HPP #define CONNECT__IMPL__THREAD_POOL_FOR_SERVER__HPP -/* $Id: thread_pool_for_server.hpp 503649 2016-06-06 22:11:35Z satskyse $ +/* $Id: thread_pool_for_server.hpp 508624 2016-07-29 15:32:34Z satskyse $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -91,9 +91,6 @@ public: /// Constructor CBlockingQueue_ForServer(void) -#ifndef NCBI_HAVE_CONDITIONAL_VARIABLE - : m_GetSem(0,1) -#endif {} /// Put a request into the queue. If the queue remains full for @@ -140,11 +137,7 @@ protected: // Derived classes should take care to use these members properly. TRealQueue m_Queue; ///< The queue - #ifdef NCBI_HAVE_CONDITIONAL_VARIABLE CConditionVariable m_GetCond; - #else - CSemaphore m_GetSem; ///< Raised if the queue contains data - #endif mutable CMutex m_Mutex; ///< Guards access to queue private: diff --git a/c++/include/connect/ncbi_conn_stream.hpp b/c++/include/connect/ncbi_conn_stream.hpp index 3f311478..6ed94653 100644 --- a/c++/include/connect/ncbi_conn_stream.hpp +++ b/c++/include/connect/ncbi_conn_stream.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CONN_STREAM__HPP #define CONNECT___NCBI_CONN_STREAM__HPP -/* $Id: ncbi_conn_stream.hpp 475395 2015-08-07 14:35:49Z vasilche $ +/* $Id: ncbi_conn_stream.hpp 547023 2017-09-25 17:18:32Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -28,8 +28,8 @@ * * Authors: Denis Vakatov, Anton Lavrentiev * - * @file * File Description: + * @file ncbi_conn_stream.hpp * CONN-based C++ streams * * Classes: @@ -473,8 +473,9 @@ public: /// Helper class to fetch HTTP status code and text struct SHTTP_StatusData { - int code; - string text; + int code; + CTempString text; + string header; SHTTP_StatusData(void) : code(0) { } }; @@ -519,7 +520,7 @@ public: const string& path, const string& args = kEmptyStr, const string& user_header = kEmptyStr, - unsigned short port = 0, ///< 0 means default (80 for HTTP) + unsigned short port = 0, ///< 0 means default(eg 80 for HTTP) THTTP_Flags flags = fHTTP_AutoReconnect, const STimeout* timeout = kDefaultTimeout, size_t buf_size = kConn_DefaultBufSize @@ -572,10 +573,13 @@ public: EIO_Status Fetch(const STimeout* timeout = kDefaultTimeout); /// Get the last seen HTTP status code - int GetStatusCode(void) const { return m_StatusData.code; } + int GetStatusCode(void) const { return m_StatusData.code; } /// Get the last seen HTTP status text - const string& GetStatusText(void) const { return m_StatusData.text; } + const CTempString GetStatusText(void) const { return m_StatusData.text; } + + /// Get the entire HTTP header as received + const string& GetHTTPHeader(void) const { return m_StatusData.header; } protected: // Chained callbacks @@ -643,10 +647,13 @@ public: EIO_Status Fetch(const STimeout* timeout = kDefaultTimeout); /// Get the last seen HTTP status code, if available - int GetStatusCode(void) const { return m_CBData.status.code; } + int GetStatusCode(void) const { return m_CBD.status.code; } + + /// Get the last seen HTTP status text, if available + const CTempString GetStatusText(void) const { return m_CBD.status.text; } /// Get the last seen HTTP status text, if available - const string& GetStatusText(void) const { return m_CBData.status.text; } + const string& GetHTTPHeader(void) const { return m_CBD.status.header; } /// Get underlying SOCK, if available after Fetch() SOCK GetSOCK(void); @@ -660,7 +667,7 @@ public: protected: // Chained callbacks - SSERVICE_CBData m_CBData; + SSERVICE_CBData m_CBD; private: // Interceptors diff --git a/c++/include/connect/ncbi_conn_test.hpp b/c++/include/connect/ncbi_conn_test.hpp index f3b05773..bdb8e122 100644 --- a/c++/include/connect/ncbi_conn_test.hpp +++ b/c++/include/connect/ncbi_conn_test.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CONN_TEST__HPP #define CONNECT___NCBI_CONN_TEST__HPP -/* $Id: ncbi_conn_test.hpp 409076 2013-08-05 18:52:43Z lavr $ +/* $Id: ncbi_conn_test.hpp 533755 2017-04-19 16:26:34Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -28,8 +28,8 @@ * * Author: Anton Lavrentiev * - * @file * File Description: +///@file ncbi_conn_test.hpp * NCBI connectivity test suite. * */ diff --git a/c++/include/connect/ncbi_connector.h b/c++/include/connect/ncbi_connector.h index b9f3ac3e..c5748ded 100644 --- a/c++/include/connect/ncbi_connector.h +++ b/c++/include/connect/ncbi_connector.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CONNECTOR__H #define CONNECT___NCBI_CONNECTOR__H -/* $Id: ncbi_connector.h 513293 2016-09-09 11:36:15Z ivanov $ +/* $Id: ncbi_connector.h 513232 2016-09-08 15:47:40Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/connect/ncbi_connutil.h b/c++/include/connect/ncbi_connutil.h index 02835c73..f9a6620b 100644 --- a/c++/include/connect/ncbi_connutil.h +++ b/c++/include/connect/ncbi_connutil.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CONNUTIL__H #define CONNECT___NCBI_CONNUTIL__H -/* $Id: ncbi_connutil.h 513929 2016-09-16 15:08:30Z ivanov $ +/* $Id: ncbi_connutil.h 533483 2017-04-17 12:34:50Z mcelhany $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -110,6 +110,11 @@ typedef enum { eReqMethod_Connect, /* 4 */ /* HTTP/1.1 */ eReqMethod_v1 = 8, + eReqMethod_Any11 = eReqMethod_v1 | eReqMethod_Any, + eReqMethod_Get11 = eReqMethod_v1 | eReqMethod_Get, + eReqMethod_Post11 = eReqMethod_v1 | eReqMethod_Post, + eReqMethod_Head11 = eReqMethod_v1 | eReqMethod_Head, + eReqMethod_Connect11 = eReqMethod_v1 | eReqMethod_Connect, eReqMethod_Put = 16, /* 16 */ eReqMethod_Patch, /* 17 */ eReqMethod_Trace, /* 18 */ @@ -152,8 +157,8 @@ typedef unsigned EBDebugPrintout; /* Network connection-related configurable informational structure. * ATTENTION: Do NOT fill out this structure (SConnNetInfo) "from scratch"! - * Instead, use ConnNetInfo_Create() described below to create - * it, and then fix (hard-code) some fields, if really necessary. + * Instead, use ConnNetInfo_Create() described below to create it, + * and then fix (hard-code) some fields, if really necessary. * NOTE1: Not every field may be fully utilized throughout the library. * NOTE2: HTTP passwords can be either clear text or Base64 encoded values * enclosed in square brackets [] (which are not Base-64 charset). @@ -272,6 +277,7 @@ typedef struct { /* NCBI_FAKE_WARNING: ICC */ #define REG_CONN_LOCAL_ENABLE "LOCAL_ENABLE" #define REG_CONN_LBSMD_DISABLE "LBSMD_DISABLE" #define REG_CONN_LBOS_ENABLE "LBOS_ENABLE" +#define REG_CONN_NAMERD_ENABLE "NAMERD_ENABLE" #define REG_CONN_DISPD_DISABLE "DISPD_DISABLE" /* Local service dispatcher */ diff --git a/c++/include/connect/ncbi_core.h b/c++/include/connect/ncbi_core.h index 14caa802..b48a72da 100644 --- a/c++/include/connect/ncbi_core.h +++ b/c++/include/connect/ncbi_core.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CORE__H #define CONNECT___NCBI_CORE__H -/* $Id: ncbi_core.h 505000 2016-06-21 16:48:46Z vakatov $ +/* $Id: ncbi_core.h 533755 2017-04-19 16:26:34Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -28,8 +28,8 @@ * * Author: Denis Vakatov * - * @file * File Description: + * @file ncbi_core.h * Types and code shared by all "ncbi_*.[ch]" modules. * * I/O status and direction: @@ -180,8 +180,8 @@ typedef enum { /** MT locking callback (operates like a [recursive] mutex or RW-lock). - * @param user_data - * See "user_data" in MT_LOCK_Create() + * @param data + * See "data" in MT_LOCK_Create() * @param how * As passed to MT_LOCK_Do() * @return @@ -195,23 +195,23 @@ typedef enum { * MT_LOCK_Create, MT_LOCK_Delete */ typedef int/*bool*/ (*FMT_LOCK_Handler) -(void* user_data, +(void* data, EMT_Lock how ); /** MT lock cleanup callback. - * @param user_data - * See "user_data" in MT_LOCK_Create() + * @param data + * See "data" in MT_LOCK_Create() * @sa * MT_LOCK_Create, MT_LOCK_Delete */ typedef void (*FMT_LOCK_Cleanup) -(void* user_data +(void* data ); -/** Create new MT lock (with an internal reference counter set to 1). - * @param user_data +/** Create a new MT lock (with an internal reference count set to 1). + * @param data * Unspecified data to call "handler" and "cleanup" with * @param handler * Locking callback @@ -221,13 +221,13 @@ typedef void (*FMT_LOCK_Cleanup) * FMT_LOCK_Handler, FMT_LOCK_Cleanup, MT_LOCK_Delete */ extern NCBI_XCONNECT_EXPORT MT_LOCK MT_LOCK_Create -(void* user_data, +(void* data, FMT_LOCK_Handler handler, FMT_LOCK_Cleanup cleanup ); -/** Increment internal reference counter by 1, then return "lk". +/** Increment internal reference count by 1, then return "lk". * @param lk * A handle previously obtained from MT_LOCK_Create * @sa @@ -236,9 +236,9 @@ extern NCBI_XCONNECT_EXPORT MT_LOCK MT_LOCK_Create extern NCBI_XCONNECT_EXPORT MT_LOCK MT_LOCK_AddRef(MT_LOCK lk); -/** Decrement internal reference counter by 1, and if it reaches 0, then - * destroy the handle, call "lk->cleanup(lk->user_data)", and return NULL; - * otherwise (if the reference counter is still > 0), return "lk". +/** Decrement internal reference count by 1, and if it reaches 0, then + * destroy the handle, call "lk->cleanup(lk->data)", and return NULL; + * otherwise (if the reference count is still > 0), return "lk". * @param lk * A handle previously obtained from MT_LOCK_Create * @sa @@ -247,7 +247,7 @@ extern NCBI_XCONNECT_EXPORT MT_LOCK MT_LOCK_AddRef(MT_LOCK lk); extern NCBI_XCONNECT_EXPORT MT_LOCK MT_LOCK_Delete(MT_LOCK lk); -/** Call "lk->handler(lk->user_data, how)". +/** Call "lk->handler(lk->data, how)". * @param lk * A handle previously obtained from MT_LOCK_Create * @param how @@ -338,66 +338,64 @@ typedef struct { size_t raw_size; int err_code; int err_subcode; -} SLOG_Handler; +} SLOG_Message; /** Log post callback. - * @param user_data + * @param data * Unspeficied data as passed to LOG_Create() or LOG_Reset() - * @param call_data + * @param mess * Composed from arguments passed to LOG_WriteInternal() * @sa - * SLOG_Handler, LOG_Create, LOG_Reset, LOG_WriteInternal + * SLOG_Message, LOG_Create, LOG_Reset, LOG_WriteInternal */ typedef void (*FLOG_Handler) -(void* user_data, - SLOG_Handler* call_data +(void* data, + SLOG_Message* mess ); /** Log cleanup callback. - * @param user_data + * @param data * Unspeficied data as passed to LOG_Create() or LOG_Reset() * @sa * LOG_Create, LOG_Reset * */ typedef void (*FLOG_Cleanup) -(void* user_data +(void* data ); -/** Create new LOG (with an internal reference counter set to 1). +/** Create a new LOG (with an internal reference count set to 1). * @par ATTENTION: - * If non-NULL "mt_lock" is specified then - * MT_LOCK_Delete() will be called on it when this LOG gets deleted - * -- be aware of it (hence, if the lock is also to be used with something - * else, then call MT_LOCK_AddRef() on it before passing to LOG_Create)! - * @param user_data + * If non-NULL "lock" is specified then MT_LOCK_AddRef() is called on it here, + * and MT_LOCK_Delete() will be called on it when this LOG gets deleted. + * @param data * Unspecified data to call "handler" and "cleanup" with * @param handler * Log post callback * @param cleanup * Cleanup callback - * @param mt_lock - * Protective MT lock (can be NULL) + * @param lock + * Protective MT lock (may be NULL) * @sa * MT_LOCK, MT_LOCK_AddRef, FLOG_Handler, FLOG_Cleanup, LOG_Reset, LOG_Delete */ extern NCBI_XCONNECT_EXPORT LOG LOG_Create -(void* user_data, +(void* data, FLOG_Handler handler, FLOG_Cleanup cleanup, - MT_LOCK mt_lock + MT_LOCK lock ); -/** Reset the "lg" to use the new "user_data", "handler" and "cleanup". +/** Reset the "lg" to use the new "data", "handler" and "cleanup". * @par NOTE: - * It does not change the reference counter of the log. + * It does not change the reference count of the log. * @param lg * A log handle previously obtained from LOG_Create - * @param user_data + * @param data * New user data * @param handler * New log post callback @@ -410,13 +408,13 @@ extern NCBI_XCONNECT_EXPORT LOG LOG_Create */ extern NCBI_XCONNECT_EXPORT LOG LOG_Reset (LOG lg, - void* user_data, + void* data, FLOG_Handler handler, FLOG_Cleanup cleanup ); -/** Increment internal reference counter by 1, then return "lg". +/** Increment internal reference count by 1, then return "lg". * @param lg * A log handle previously obtained from LOG_Create * @sa @@ -425,9 +423,9 @@ extern NCBI_XCONNECT_EXPORT LOG LOG_Reset extern NCBI_XCONNECT_EXPORT LOG LOG_AddRef(LOG lg); -/** Decrement internal reference counter by 1, and if it reaches 0, then - * call "lg->cleanup(lg->user_data)", destroy the handle, and return NULL; - * otherwise (if reference counter is still > 0), return "lg". +/** Decrement internal reference count by 1, and if it reaches 0, then + * call "lg->cleanup(lg->data)", destroy the handle, and return NULL; + * otherwise (if reference count is still > 0), return "lg". * @param lg * A log handle previously obtained from LOG_Create * @sa @@ -480,10 +478,10 @@ extern NCBI_XCONNECT_EXPORT void LOG_Write /** Write message (perhaps with raw data attached) to the log by calling - * "lg->handler(lg->user_data, call_data)". + * "lg->handler(lg->data, mess)". * @par NOTE: * Do not call this function directly, if possible. - * Instead, use LOG_WRITE() and LOG_DATA() macros from ! + * Instead, use the LOG_WRITE() and LOG_DATA() macros from ! * @param lg * A log handle previously obtained from LOG_Create * @sa @@ -491,7 +489,7 @@ extern NCBI_XCONNECT_EXPORT void LOG_Write */ extern NCBI_XCONNECT_EXPORT void LOG_WriteInternal (LOG lg, - SLOG_Handler* call_data + SLOG_Message* mess ); @@ -522,10 +520,10 @@ typedef enum { * the persistent storage. Do not modify the "value" (leave it "as is", * i.e. default) if the requested entry is not found in the registry. * @par NOTE: - * Always terminate value by '\0'. + * Always terminate value with '\0'. * @par NOTE: * Do not put more than "value_size" bytes to "value". - * @param user_data + * @param data * Unspecified data as passed to REG_Create or REG_Reset * @param section * Section name to search @@ -539,7 +537,7 @@ typedef enum { * REG_Create, REG_Reset */ typedef void (*FREG_Get) -(void* user_data, +(void* data, const char* section, const char* name, char* value, @@ -550,7 +548,7 @@ typedef void (*FREG_Get) /** Registry setter callback. * Store the "value" to the registry section "section" under name "name", * and according to "storage". - * @param user_data + * @param data * Unspecified data as passed to REG_Create or REG_Reset * @param section * Section name to add the key to @@ -566,7 +564,7 @@ typedef void (*FREG_Get) * REG_Create, REG_Reset, EREG_Storage */ typedef int (*FREG_Set) -(void* user_data, +(void* data, const char* section, const char* name, const char* value, @@ -575,25 +573,23 @@ typedef int (*FREG_Set) /** Registry cleanup callback. - * @param user_data + * @param data * Unspecified data as passed to REG_Create or REG_Reset * @sa * REG_Reset, REG_Delete */ typedef void (*FREG_Cleanup) -(void* user_data +(void* data ); -/** Create new registry (with an internal reference counter set to 1). +/** Create a new registry (with an internal reference count set to 1). * @par ATTENTION: - * if non-NULL "mt_lock" is specified then - * MT_LOCK_Delete() will be called on it when this REG gets destroyed - * -- be aware of it (hence, if the lock is also to be used with something - * else, then call MT_LOCK_AddRef() on it before passing to REG_Create)! - * Passing NULL callbacks below causes limiting the functionality - * only to those operations that have the callbacks set. - * @param user_data + * if non-NULL "lock" is specified then MT_LOCK_AddRef() is called on it here, + * and MT_LOCK_Delete() will be called on it when this REG gets destroyed. + * Passing NULL callbacks below causes limiting the functionality + * only to those operations that have the callbacks set for. + * @param data * Unspecified data to call "set", "get" and "cleanup" with * @param get * Getter callback @@ -601,27 +597,27 @@ typedef void (*FREG_Cleanup) * Setter callback * @param cleanup * Cleanup callback - * @param mt_lock - * Protective MT lock (can be NULL) + * @param lock + * Protective MT lock (may be NULL) * @sa * MT_LOCK, MT_LOCK_AddRef, REG_Get, REG_Set, REG_Reset, REG_Delete */ extern NCBI_XCONNECT_EXPORT REG REG_Create -(void* user_data, +(void* data, FREG_Get get, FREG_Set set, FREG_Cleanup cleanup, - MT_LOCK mt_lock + MT_LOCK lock ); -/** Reset the registry handle to use the new "user_data", "set", "get", +/** Reset the registry handle to use the new "data", "set", "get", * and "cleanup". * @par NOTE: - * No change to the internal reference counter. + * No change to the internal reference count. * @param rg * Registry handle as previously obtained from REG_Create - * @param user_data + * @param data * New user data * @param get * New getter callback @@ -636,7 +632,7 @@ extern NCBI_XCONNECT_EXPORT REG REG_Create */ extern NCBI_XCONNECT_EXPORT void REG_Reset (REG rg, - void* user_data, + void* data, FREG_Get get, FREG_Set set, FREG_Cleanup cleanup, @@ -644,7 +640,7 @@ extern NCBI_XCONNECT_EXPORT void REG_Reset ); -/** Increment internal reference counter by 1, then return "rg". +/** Increment internal reference count by 1, then return "rg". * @param rg * Registry handle as previously obtained from REG_Create * @sa @@ -653,9 +649,9 @@ extern NCBI_XCONNECT_EXPORT void REG_Reset extern NCBI_XCONNECT_EXPORT REG REG_AddRef(REG rg); -/** Decrement internal referecne counter by 1, and if it reaches 0, then - * call "rg->cleanup(rg->user_data)", destroy the handle, and return NULL; - * otherwise (if the reference counter is still > 0), return "rg". +/** Decrement internal reference count by 1, and if it reaches 0, then + * call "rg->cleanup(rg->data)", destroy the handle, and return NULL; + * otherwise (if the reference count is still > 0), return "rg". * @param rg * Registry handle as previously obtained from REG_Create * @sa @@ -664,12 +660,12 @@ extern NCBI_XCONNECT_EXPORT REG REG_AddRef(REG rg); extern NCBI_XCONNECT_EXPORT REG REG_Delete(REG rg); -/** Copy the registry value stored in "section" under name "name" - * to buffer "value"; if the entry is found in both transient and persistent - * storages, then copy the one from the transient storage. - * If the specified entry is not found in the registry (or if there is - * no registry defined), and "def_value" is not NULL, then copy "def_value" - * to "value" (although, only up to "value_size" characters). +/** Copy the registry value stored in "section" under name "name" to buffer + * "value"; if the entry is found in both transient and persistent storages, + * then copy the one from the transient storage. + * If the specified entry is not found in the registry (or if there is no + * registry defined), and "def_value" is not NULL, then copy "def_value" to + * "value" (although, only up to "value_size" characters). * @param rg * Registry handle as previously obtained from REG_Create * @param section @@ -684,7 +680,7 @@ extern NCBI_XCONNECT_EXPORT REG REG_Delete(REG rg); * Default value (none if passed NULL) * @return * Return "value" (however, if "value_size" is zero, then return NULL). - * If non-NULL, the returned "value" will be terminated by '\0'. + * If non-NULL, the returned "value" will be terminated with '\0'. * @sa * REG_Create, REG_Set */ @@ -699,7 +695,7 @@ extern NCBI_XCONNECT_EXPORT const char* REG_Get /** Store the "value" to the registry section "section" under name "name", - * and according with "storage". + * and according to "storage". * @param rg * Registry handle as previously obtained from REG_Create * @param section diff --git a/c++/include/connect/ncbi_core_cxx.hpp b/c++/include/connect/ncbi_core_cxx.hpp index baf48bb2..7608dc93 100644 --- a/c++/include/connect/ncbi_core_cxx.hpp +++ b/c++/include/connect/ncbi_core_cxx.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CORE_CXX__H #define CONNECT___NCBI_CORE_CXX__H -/* $Id: ncbi_core_cxx.hpp 507476 2016-07-19 17:46:14Z lavr $ +/* $Id: ncbi_core_cxx.hpp 533755 2017-04-19 16:26:34Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -29,7 +29,7 @@ * Author: Anton Lavrentiev * * File description: - * @file + * @file ncbi_core_cxx.hpp * C++->C conversion functions for basic CORE connect stuff: * - Registry, * - Logging, @@ -37,8 +37,8 @@ * */ -#include #include +#include /** @addtogroup UtilityFunc @@ -51,8 +51,8 @@ BEGIN_NCBI_SCOPE /// Convert a C++ Toolkit registry object to a REG registry. -/// @note The C++ registries are CObjects, any we "own" will be deleted -/// if and only if nothing else still holds a reference to them. +/// @note The C++ registries are CObjects, any we "own" will be deleted +/// if and only if nothing else still holds a reference to them. /// @param reg /// A C++ toolkit registry, on top of which new REG registry is to be created /// @param pass_ownership @@ -67,6 +67,26 @@ extern NCBI_XCONNECT_EXPORT REG REG_cxx2c ); +/// Convert a C++ Toolkit read-only registry object to a REG registry. +/// @note The returned registry won't have a set method available, and any +/// attempt to set a parameter will fail. +/// @note The C++ registries are CObjects, any we "own" will be deleted +/// if and only if nothing else still holds a reference to them. +/// attem0pe +/// @param reg +/// A C++ toolkit registry, on top of which new REG registry is to be created +/// @param pass_ownership +/// True if the ownership of "reg" gets passed to new REG +/// @return +/// New REG registry (or NULL on error) +/// @sa +/// REG_Create, CONNECT_Init +extern NCBI_XCONNECT_EXPORT REG REG_cxx2c +(const IRWRegistry* reg, + bool pass_ownership = false + ); + + /// Create LOG on top of C++ Toolkit CNcbiDiag. /// @return /// New LOG log (or NULL on error) @@ -85,8 +105,8 @@ extern NCBI_XCONNECT_EXPORT LOG LOG_cxx2c(void); /// @sa /// MT_LOCK_Create, CONNECT_Init extern NCBI_XCONNECT_EXPORT MT_LOCK MT_LOCK_cxx2c -(CRWLock* lock = 0, - bool pass_ownership = false +(CRWLock* lock = 0, + bool pass_ownership = false ); @@ -104,21 +124,25 @@ typedef unsigned int TConnectInitFlags; ///< Bitwise OR of EConnectInitFlag /// Init [X]CONNECT library with the specified "reg" and "lock" (ownerhsip /// for either or both can be detailed in the "flag" parameter). -/// @note MUST be called in MT applications to make CONNECT MT-safe, or -/// CConnIniter must be used as a base-class. +/// @note MUST be called in MT applications to make CONNECT MT-safe, or +/// CConnIniter must be used as a base-class. /// @param reg -/// Registry to use (none if NULL) +/// Registry to use, non-modifiable (none if NULL) /// @param lock /// Lock to use (new lock will get created if NULL) /// @param flag /// Ownership control +/// @param ssl +/// TLS provider to use for SSL (ignored if eConnectInit_NoSSL, +/// 0 selects default) /// @note LOG will get created out of CNcbiDiag automatically. /// @sa /// REG_cxx2c, LOG_cxx2c, MT_LOCK_cxx2c, CConnIniter, CNcbiApplication extern NCBI_XCONNECT_EXPORT void CONNECT_Init -(IRWRegistry* reg = 0, - CRWLock* lock = 0, - TConnectInitFlags flag = eConnectInit_OwnNothing); +(const IRWRegistry* reg = 0, + CRWLock* lock = 0, + TConnectInitFlags flag = eConnectInit_OwnNothing, + FSSLSetup ssl = 0); ///////////////////////////////////////////////////////////////////////////// diff --git a/c++/include/connect/ncbi_gnutls.h b/c++/include/connect/ncbi_gnutls.h index c9a40d0b..1c9a83bc 100644 --- a/c++/include/connect/ncbi_gnutls.h +++ b/c++/include/connect/ncbi_gnutls.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_GNUTLS__H #define CONNECT___NCBI_GNUTLS__H -/* $Id: ncbi_gnutls.h 507002 2016-07-13 21:10:28Z lavr $ +/* $Id: ncbi_gnutls.h 531324 2017-03-23 16:34:47Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -29,7 +29,7 @@ * Author: Anton Lavrentiev * * File Description: - * GNUTLS support for SSL in connection library + * GNUTLS support for SSL (Secure Socket Layer) in connection library * */ @@ -47,10 +47,24 @@ extern "C" { #endif +/** Explicitly setup GNUTLS library to support SSL in ncbi_socket.h[pp]. + * + * @note Do not use this call! Instead, use NcbiSetupTls declared in + * . + * + * @sa + * NcbiSetupTls + */ extern NCBI_XCONNECT_EXPORT SOCKSSL NcbiSetupGnuTls(void); +/** Convert native GNUTLS certificate credentials' handle into an abstract + * toolkit handle. + * + * @note Does not create a copy of xcred, so xcred must remain valid for the + * entire duration of a session (or sessions) that it is being used in. + */ extern NCBI_XCONNECT_EXPORT NCBI_CRED NcbiCredGnuTls(void* xcred); diff --git a/c++/include/connect/ncbi_heapmgr.h b/c++/include/connect/ncbi_heapmgr.h index 237eab96..fe5cbb96 100644 --- a/c++/include/connect/ncbi_heapmgr.h +++ b/c++/include/connect/ncbi_heapmgr.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_HEAPMGR__H #define CONNECT___NCBI_HEAPMGR__H -/* $Id: ncbi_heapmgr.h 404441 2013-06-24 19:00:21Z lavr $ +/* $Id: ncbi_heapmgr.h 527594 2017-02-14 18:41:11Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -56,8 +56,9 @@ typedef struct SHEAP_tag* HEAP; /* Header of a heap block */ typedef struct { - unsigned int flag; /* (flag & 1) == 0 if the block is vacant */ - TNCBI_Size size; /* size of the block (including the block header) */ + unsigned int flag; /* (flag & 1) == 0 if the block is vacant; + * other bits reserved, do not assume their values! */ + TNCBI_Size size; /* size of the block (including this header), bytes */ } SHEAP_Block; @@ -192,7 +193,7 @@ extern NCBI_XCONNECT_EXPORT HEAP HEAP_Copy /* Add reference counter to the given copy heap (no effect on - * a heap, which have been HEAP_Create()'d or HEAP_Attach[Fast]()'d). + * a heap, which has been HEAP_Create()'d or HEAP_Attach[Fast]()'d). * The heap handle then will be destroyed only when the internal * reference counter reaches 0. No internal locking is provided. * Return the resultant value of the reference counter. diff --git a/c++/include/connect/ncbi_host_info.h b/c++/include/connect/ncbi_host_info.h index 174c5f6c..d4a05a56 100644 --- a/c++/include/connect/ncbi_host_info.h +++ b/c++/include/connect/ncbi_host_info.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_HOST_INFO__H #define CONNECT___NCBI_HOST_INFO__H -/* $Id: ncbi_host_info.h 435172 2014-05-14 13:31:37Z lavr $ +/* $Id: ncbi_host_info.h 533755 2017-04-19 16:26:34Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -29,7 +29,7 @@ * Author: Anton Lavrentiev * * File Description: - * @file + * @file ncbi_host_info.h * NCBI host info getters * * Host information handle becomes available from SERV_Get[Next]InfoEx() @@ -142,7 +142,9 @@ int/*bool*/ HINFO_Memusage(const HOST_INFO host_info, double memusage[5]); typedef enum { - eArch_Unknown + fArch_Virtual = 1, /**< Set when a VM */ + /* 31 different CPU types (6-bit even values) can be defined */ + fArch_Unknown = 0 /**< Unknown/undefined CPU type */ } ENcbiArch; typedef unsigned short TNcbiArch; diff --git a/c++/include/connect/ncbi_http_session.hpp b/c++/include/connect/ncbi_http_session.hpp index 666b9cdb..481fbd74 100644 --- a/c++/include/connect/ncbi_http_session.hpp +++ b/c++/include/connect/ncbi_http_session.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_HTTP_SESSION__HPP #define CONNECT___NCBI_HTTP_SESSION__HPP -/* $Id: ncbi_http_session.hpp 519414 2016-11-15 18:23:40Z ivanov $ +/* $Id: ncbi_http_session.hpp 523493 2017-01-04 14:12:16Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -507,11 +507,36 @@ public: /// @sa Execute() SetDeadline() CHttpRequest& SetRetryProcessing(ESwitch on_off); + /// Set callback to adjust URL after resolving service location. + /// The callback must take a CUrl reference and return bool: + /// bool AdjustUrlCallback(CUrl& url); + /// The callback should return true for the adjusted URL to be used to + /// make the request, or false if the changes should be discarded. + template + void SetAdjustUrlCallback(TCallback callback) { + m_AdjustUrl.Reset(new CAdjustUrlCallback(callback)); + } + private: friend class CHttpSession; CHttpRequest(CHttpSession& session, const CUrl& url, EReqMethod method); + class CAdjustUrlCallback_Base : public CObject { + public: + virtual ~CAdjustUrlCallback_Base(void) {} + virtual bool AdjustUrl(CUrl& url) = 0; + }; + + template + class CAdjustUrlCallback : public CAdjustUrlCallback_Base { + public: + CAdjustUrlCallback(TCallback& callback) : m_Callback(callback) {} + virtual bool AdjustUrl(CUrl& url) { return m_Callback(url); } + private: + TCallback m_Callback; + }; + // Open connection, initialize response. void x_InitConnection(bool use_form_data); @@ -534,6 +559,7 @@ private: CRef m_Session; CUrl m_Url; + bool m_IsService; EReqMethod m_Method; CRef m_Headers; CRef m_FormData; @@ -543,6 +569,7 @@ private: THttpRetries m_Retries; CTimeout m_Deadline; ESwitch m_RetryProcessing; + CRef m_AdjustUrl; }; @@ -554,10 +581,11 @@ public: /// Supported request methods, proxy for EReqMethod. /// @sa EReqMethod enum ERequestMethod { - eHead = eReqMethod_Head, - eGet = eReqMethod_Get, - ePost = eReqMethod_Post, - ePut = eReqMethod_Put + eHead = eReqMethod_Head, + eGet = eReqMethod_Get, + ePost = eReqMethod_Post, + ePut = eReqMethod_Put, + eDelete = eReqMethod_Delete }; /// Initialize request. This does not open connection to the server. diff --git a/c++/include/connect/ncbi_iprange.h b/c++/include/connect/ncbi_iprange.h new file mode 100644 index 00000000..d5797833 --- /dev/null +++ b/c++/include/connect/ncbi_iprange.h @@ -0,0 +1,90 @@ +#ifndef CONNECT___NCBI_IPRANGE__H +#define CONNECT___NCBI_IPRANGE__H + +/* $Id: ncbi_iprange.h 537450 2017-05-31 18:55:16Z lavr $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * IP range manipulating API + * + */ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + eIPRange_None = 0, /* invalid entry */ + eIPRange_Host, /* a is set, b is 0 */ + eIPRange_Range, /* a is set, b is set, IPv4 only */ + eIPRange_Network, /* a is set, b is mask for IPv4, bits for IPv6 */ + eIPRange_Application /* a and b application-specific */ +} EIPRangeType; + + +typedef struct { + EIPRangeType type; + TNCBI_IPv6Addr a; /* IPv4 | IPv6 */ + unsigned int b; /* IPv4 | bits */ +} SIPRange; + + +extern NCBI_XCONNECT_EXPORT +int/*bool*/ NcbiIsInIPRange(const SIPRange* range, + const TNCBI_IPv6Addr* addr); + + +/* NB: NOP for IPv6 (which can be either "Host" or "Network") */ +extern NCBI_XCONNECT_EXPORT +SIPRange NcbiTrueIPRange(const SIPRange* range); + + +extern NCBI_XCONNECT_EXPORT +const char* NcbiDumpIPRange(const SIPRange* range, char* buf, size_t bufsize); + + +/* Acceptable forms (masked IPv4s may omit trailing .0s): + * 4 quad full IP: 123.123.123.123 + * IP range: 123.123.1-123 (meaning 123.123.1.0 thru 123.123.123.255) + * Masked: 123.123/255.255.240.0 (equivalent to the following line) + * CIDR: 123.123/20 (meaning 123.123.0.0 thru 123.123.15.255) + * Wildcard: 123.123.* (meaning 123.123.0.0 thru 123.123.255.255) + * IPv6[/CIDR]: aa:bb::cc/64 (IPv6 addr must be complete,/CIDR optional) + */ +extern NCBI_XCONNECT_EXPORT +int/*bool*/ NcbiParseIPRange(SIPRange* range, const char* s); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /*CONNECT___NCBI_IPRANGE__H*/ diff --git a/c++/include/connect/ncbi_ipv6.h b/c++/include/connect/ncbi_ipv6.h new file mode 100644 index 00000000..330b6265 --- /dev/null +++ b/c++/include/connect/ncbi_ipv6.h @@ -0,0 +1,213 @@ +#ifndef CONNECT___NCBI_IPV6__H +#define CONNECT___NCBI_IPV6__H + +/* $Id: ncbi_ipv6.h 533755 2017-04-19 16:26:34Z lavr $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * @file ncbi_ipv6.h + * IPv6 addressing support + * + */ + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + + +typedef struct { + unsigned char octet[16]; /* assume no alignment */ +} TNCBI_IPv6Addr; + + +/** Return non-zero if the address is empty (either as IPv6 or IPv4); return + * zero otherwise. + * @sa + * NcbiIsIPv4 + */ +extern NCBI_XCONNECT_EXPORT +int/*bool*/ NcbiIsEmptyIPv6(const TNCBI_IPv6Addr* addr); + + +/** Return non-zero if the address is either IPv4 compatible or a mapped IPv4 + * address; return zero otherwise. + * @sa + * NcbiIPv4ToIPv6, NcbiIPv6ToIPv4 + */ +extern NCBI_XCONNECT_EXPORT +int/*bool*/ NcbiIsIPv4 (const TNCBI_IPv6Addr* addr); + + +/** Extract and return an IPv4 embedded address from an IPv6 address, using the + * specified prefix length (RFC6052). Return INADDR_NONE (-1,255.255.255.255) + * when the specified prefix length is not valid. As a special case (and the + * most anticipated common use-case) is to use prefix length 0, which checks + * that the passed IPv6 address is actually a mapped IPv4 address, then + * extracts it using the prefix length 96. Return 0 if the extraction cannot + * be made (not an IPv4 mapped address). + * @sa + * NcbiIsIPv4, NcbiIPv4ToIPv6 + */ +extern NCBI_XCONNECT_EXPORT +unsigned int NcbiIPv6ToIPv4(const TNCBI_IPv6Addr* addr, size_t pfxlen); + + +/** Embed a passed IPv4 address into an IPv6 address using the specified prefix + * length (RFC6052). Return zero when the specified prefix length is not + * valid, non-zero otherwise. Special case (and the most anticipated common + * use-case) is to use prefix length 0, which first clears the passed IPv6 + * address, then embeds the IPv4 address as a mapped address using the prefix + * length 96. + * @sa + * NcbiIsIPv4, NcbiIPv6ToIPv4 + */ +extern NCBI_XCONNECT_EXPORT +int/*bool*/ NcbiIPv4ToIPv6(TNCBI_IPv6Addr* addr, + unsigned int ipv4, size_t pfxlen); + +/** Convert into an IPv4 address, the first "len" (or "strlen(str)" if "len" is + * 0) bytes of "str" from a full-quad decimal notation; return a non-zero + * string pointer to the first non-converted character (which is neither a + * digit nor a dot); return 0 if conversion failed and no IPv4 address had + * been found. + * @sa + * NcbiIPToAddr, NcbiIPv4ToIPv6, NcbiStringToAddr, + * SOCK_StringToHostPort, SOCK_gethostbyname + */ +extern NCBI_XCONNECT_EXPORT +const char* NcbiStringToIPv4(unsigned int* addr, + const char* str, size_t len); + + +/** Convert into an IPv6 address, the first "len" (or "strlen(str)" if "len" is + * 0) bytes of "str" from a hexadecimal colon-separated notation (including + * full-quad trailing IPv4); return a non-zero string pointer to the first + * non-converted character (which is neither a hex-digit, nor a colon, nor a + * dot); return 0 if conversion failed and no IPv6 address had been found. + * @sa + * NcbiIPToAddr, NcbiStringToAddr + */ +extern NCBI_XCONNECT_EXPORT +const char* NcbiStringToIPv6(TNCBI_IPv6Addr* addr, + const char* str, size_t len); + + +/** Convert into an IPv6 address, the first "len" (or "strlen(str)" if "len" is + * 0) bytes of "str" from either a full-quad decimal IPv4 or a hexadecimal + * colon-separated IPv6; return a non-zero string pointer to the first + * non-converted character (which is neither a [hex-]digit, nor a colon, nor a + * dot); return 0 if no conversion can be made. + * @sa + * NcbiStringToIPv4, NcbiStringToIPv6, NcbiStingToAddr, NcbiAddrToString + */ +extern NCBI_XCONNECT_EXPORT +const char* NcbiIPToAddr(TNCBI_IPv6Addr* addr, + const char* str, size_t len); + + +/** Convert into an IPv6 address, the first "len" (or "strlen(str)" if "len" is + * 0) bytes of "str", which can be either of a full-quad decimal IPv4, a + * hexadecimal colon-separated IPv6, an .in-addr.arpa- or an .in6.arpa-domain + * names; return a non-zero string pointer to the first non-converted + * character (which is neither a [hex-]digit, nor a colon, nor a dot); return + * 0 if no conversion can be made. + * @sa + * NcbiAddrToString, NcbiAddrToDNS + */ +extern NCBI_XCONNECT_EXPORT +const char* NcbiStringToAddr(TNCBI_IPv6Addr* addr, + const char* str, size_t len); + + +/** Convert network byte order IPv4 into a full-quad text form and store the + * result in the "buf" of size "bufsize". Return non-zero string address + * past the stored result, or 0 when the conversion failed for buffer being + * too small. + * @sa + * NcbiStringToIPv4, SOCK_ntoa, SOCK_HostPortToString + */ +extern NCBI_XCONNECT_EXPORT +char* NcbiIPv4ToString(char* buf, size_t bufsize, + unsigned int addr); + + +/** Convert IPv6 address into a hex colon-separated text form and store the + * result in the "buf" of size "bufsize". Return non-zero string address + * past the stored result, or 0 when the conversion failed for buffer being + * too small. + * @sa + * NcbiStringToIPv6, NcbiStringToAddr, NcbiAddrToString + */ +extern NCBI_XCONNECT_EXPORT +char* NcbiIPv6ToString(char* buf, size_t bufsize, + const TNCBI_IPv6Addr* addr); + + +/** Convert IPv6 address into either a full-quad text IPv4 (for IPv4-compatible + * IPv6 addresses) or a hex colon-separated text form(for all other) and store + * the result in the "buf" of size "bufsize". Return non-zero string address + * past the stored result, or 0 when the conversion failed for buffer being + * too small. + * @sa + * NcbiStringToAddr, NcbiAddrToDNS, SOCK_ntoa, SOCK_HostPortToString + */ +extern NCBI_XCONNECT_EXPORT +char* NcbiAddrToString(char* buf, size_t bufsize, + const TNCBI_IPv6Addr* addr); + + +/** Convert IPv6 address into either .in-addr.arpa domain (for IPv4-compatible + * IPv6 addresses) or .ip6.arpa domain (for all other) and store the result in + * the "buf" of size "bufsize". Return non-zero string address past the + * stored result, or 0 when the conversion failed for buffer being too small. + * @sa + * NcbiAddrToString + */ +extern NCBI_XCONNECT_EXPORT +const char* NcbiAddrToDNS(char* buf, size_t bufsize, + const TNCBI_IPv6Addr* addr); + + +/** Return non-zero if "addr" belongs to the network specified as CIDR + * "base/bits"; return zero otherwise. + */ +extern NCBI_XCONNECT_EXPORT +int/*bool*/ NcbiIsInIPv6Network(const TNCBI_IPv6Addr* base, + unsigned int bits, + const TNCBI_IPv6Addr* addr); + + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + + +#endif /* CONNECT___NCBI_IPV6__H */ diff --git a/c++/include/connect/ncbi_lbos.hpp b/c++/include/connect/ncbi_lbos.hpp index 12f8cda2..96d66cf2 100644 --- a/c++/include/connect/ncbi_lbos.hpp +++ b/c++/include/connect/ncbi_lbos.hpp @@ -1,39 +1,40 @@ #ifndef CONNECT___NCBI_LBOS__HPP #define CONNECT___NCBI_LBOS__HPP -/* -* =========================================================================== -* -* PUBLIC DOMAIN NOTICE -* National Center for Biotechnology Information -* -* This software/database is a "United States Government Work" under the -* terms of the United States Copyright Act. It was written as part of -* the author's official duties as a United States Government employee and -* thus cannot be copyrighted. This software/database is freely available -* to the public for use. The National Library of Medicine and the U.S. -* Government have not placed any restriction on its use or reproduction. -* -* Although all reasonable efforts have been taken to ensure the accuracy -* and reliability of the software and data, the NLM and the U.S. -* Government do not and cannot warrant the performance or results that -* may be obtained by using this software or data. The NLM and the U.S. -* Government disclaim all warranties, express or implied, including -* warranties of performance, merchantability or fitness for any particular -* purpose. -* -* Please cite the author in any work or product based on this material. -* -* =========================================================================== -* -* Authors: Dmitriy Elisov -* Credits: Denis Vakatov -* -* @file -* File Description: -* A client for service discovery API based on LBOS. -* (LBOS is a client for ZooKeeper cloud-based DB.) -* LBOS allows to announce, deannounce and resolve services. -*/ + +/* $Id: ncbi_lbos.hpp 533755 2017-04-19 16:26:34Z lavr $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Dmitriy Elisov + * Credits: Denis Vakatov + * + * File Description: + * @file ncbi_lbos.hpp + * A client for service discovery API based on LBOS. + * (LBOS is a client for ZooKeeper cloud-based DB.) + * LBOS allows to announce, deannounce and resolve services. + */ #include #include diff --git a/c++/include/connect/ncbi_localip.h b/c++/include/connect/ncbi_localip.h new file mode 100644 index 00000000..2e9ba652 --- /dev/null +++ b/c++/include/connect/ncbi_localip.h @@ -0,0 +1,86 @@ +#ifndef CONNECT___NCBI_LOCALIP__H +#define CONNECT___NCBI_LOCALIP__H + +/* $Id: ncbi_localip.h 537450 2017-05-31 18:55:16Z lavr $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * Determine IP locality (within NCBI) of a given address + * + */ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * Init local IP classification. + * NB: This call invalidates any domain information returned to client via the + * NcbiIsLocalIPEx() calls. + */ +extern NCBI_XCONNECT_EXPORT +void NcbiInitLocalIP(void); + + +/** + * Return non-zero (true) if the IP address (in network byte order) provided as + * an agrument, is a local one (i.e. belongs to NCBI); return zero (false) + * otherwise. + */ +extern NCBI_XCONNECT_EXPORT +int/*bool*/ NcbiIsLocalIP(unsigned int ip); + + +typedef struct { + const char* sfx; /* textual domain suffix (may be truncated) */ + unsigned int num; /* numerical domain sequence number (non-0) */ +} SNcbiDomainInfo; + + +/** + * Return non-zero (true) if the IP address (in network byte order) provided as + * an agrument, is a local one (i.e. belongs to NCBI), and update domain info + * (when passed non-NULL) of the address, if available; return zero (false) + * otherwise. + * NB: Domain information remains valid until a call for NcbiInitLocalIP(). + */ +extern NCBI_XCONNECT_EXPORT +int/*bool*/ NcbiIsLocalIPEx +(const TNCBI_IPv6Addr* addr, + SNcbiDomainInfo* info); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +#endif /*CONNECT___NCBI_LOCALIP__H*/ diff --git a/c++/include/connect/ncbi_mbedtls.h b/c++/include/connect/ncbi_mbedtls.h new file mode 100644 index 00000000..39fb6fcd --- /dev/null +++ b/c++/include/connect/ncbi_mbedtls.h @@ -0,0 +1,79 @@ +#ifndef CONNECT___NCBI_MBEDTLS__H +#define CONNECT___NCBI_MBEDTLS__H + +/* $Id: ncbi_mbedtls.h 531324 2017-03-23 16:34:47Z lavr $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * mbedTLS support for SSL (Secure Socket Layer) in connection library + * + */ + +#include + + +/** @addtogroup Sockets + * + * @{ + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Explicitly setup mbedTLS library to support SSL in ncbi_socket.h[pp]. + * + * @note Do not use this call! Instead use NcbiSetupTls declared in + * . + * + * @sa + * NcbiSetupTls + */ +extern NCBI_XCONNECT_EXPORT +SOCKSSL NcbiSetupMbedTls(void); + + +/** Convert native mbedTLS certificate credentials handle into an abstract + * toolkit handle. + * + * @note Does not create a copy of xcred, so xcred must remain valid for the + * entire duration of a session (or sessions) that it is being used in. + */ +extern NCBI_XCONNECT_EXPORT +NCBI_CRED NcbiCredMbedTls(void* xcred); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +/* @} */ + +#endif /* CONNECT___NCBI_MBEDTLS_H */ diff --git a/c++/include/connect/ncbi_monkey.hpp b/c++/include/connect/ncbi_monkey.hpp index 709014dd..14d75765 100644 --- a/c++/include/connect/ncbi_monkey.hpp +++ b/c++/include/connect/ncbi_monkey.hpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_monkey.hpp 505633 2016-06-27 19:28:13Z elisovdn $ +/* $Id: ncbi_monkey.hpp 512257 2016-08-29 16:51:24Z elisovdn $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -78,9 +78,6 @@ public: virtual const char* what(void) const throw(); private: - unsigned short m_StatusCode; - string m_Message; - NCBI_EXCEPTION_DEFAULT(CMonkeyException, CException); }; @@ -134,27 +131,32 @@ public: /** Check that this rule will trigger on this run (host and port have * already been successfully matched if this check is run) */ bool CheckRun(MONKEY_SOCKTYPE sock, + unsigned short rule_probability, unsigned short probability_left = 100) const; /** Get probability that the rule will run next time */ unsigned short GetProbability(MONKEY_SOCKTYPE sock) const; + + /* Iterate m_Runs */ + void IterateRun(MONKEY_SOCKTYPE sock); protected: CMonkeyRuleBase(EMonkeyActionType action_type, + string section, const vector& name_value); int /* EIO_Status or -1 */ GetReturnStatus(void) const; - unsigned long GetDelay(void) const; - - /* Iterate m_Runs */ - void IterateRun(MONKEY_SOCKTYPE sock); + unsigned long GetDelay(void) const; + string GetSection(void) const; + EMonkeyActionType GetActionType(void) const; private: void x_ReadRuns (const string& runs); void x_ReadEIOStatus(const string& eIOStatus_str); int m_ReturnStatus; ERepeatType m_RepeatType; - unsigned long m_Delay; - vector m_Runs; EMonkeyActionType m_ActionType; map m_RunPos; + unsigned long m_Delay; + string m_Section; + vector m_Runs; /** If there are no-interception runs before repeating the cycle, * we know that from m_RunsSize */ size_t m_RunsSize; @@ -173,31 +175,20 @@ private: */ class CMonkeyRWRuleBase : public CMonkeyRuleBase { -public: - enum EFillType { - eMonkey_FillRepeat, - eMonkey_FillLastLetter - }; protected: - CMonkeyRWRuleBase(EMonkeyActionType action_type, + CMonkeyRWRuleBase(EMonkeyActionType action_type, + string section, const vector& name_value); string GetText (void) const; size_t GetTextLength(void) const; bool GetGarbage (void) const; - EFillType GetFillType (void) const; -private: - void x_ReadFill(const string& fill_str); - string m_Text; - size_t m_TextLength; - bool m_Garbage; - EFillType m_FillType; }; class CMonkeyWriteRule : public CMonkeyRWRuleBase { public: - CMonkeyWriteRule(const vector& name_value); + CMonkeyWriteRule(string section, const vector& name_value); MONKEY_RETTYPE Run(MONKEY_SOCKTYPE sock, const MONKEY_DATATYPE data, @@ -210,7 +201,7 @@ public: class CMonkeyReadRule : public CMonkeyRWRuleBase { public: - CMonkeyReadRule(const vector& name_value); + CMonkeyReadRule(string section, const vector& name_value); MONKEY_RETTYPE Run(MONKEY_SOCKTYPE sock, MONKEY_DATATYPE buf, @@ -226,7 +217,7 @@ private: class CMonkeyConnectRule : public CMonkeyRuleBase { public: - CMonkeyConnectRule(const vector& name_value); + CMonkeyConnectRule(string section, const vector& name_value); int Run(MONKEY_SOCKTYPE sock, const struct sockaddr* name, @@ -239,7 +230,7 @@ private: class CMonkeyPollRule : public CMonkeyRuleBase { public: - CMonkeyPollRule(const vector& name_value); + CMonkeyPollRule(string section, const vector& name_value); bool Run(size_t* n, SOCK* sock, @@ -369,9 +360,20 @@ public: /* Not a real Chaos Monkey interceptor, just a function to remove the socket * that was closed from m_KnownSockets */ void Close(MONKEY_SOCKTYPE sock); + + /* Remember to 'socket' descriptor was created for 'sock' structure */ + void SockHasSocket(SOCK sock, MONKEY_SOCKTYPE socket); + + MONKEY_SOCKTYPE GetSockBySocketid(MONKEY_SOCKTYPE socket); static void MonkeyHookSwitchSet(FMonkeyHookSwitch hook_switch_func); private: + struct SFqdnIp + { + SFqdnIp(string fqdn="", string ip="") : fqdn(fqdn), ip(ip) {} + string fqdn; + string ip; + }; /* No one can create a separate instance of CMonkey*/ CMonkey(void); /** Return plan for the socket, new or already assigned one. If the socket @@ -382,19 +384,30 @@ private: * the check is omitted. */ CMonkeyPlan* x_FindPlan(MONKEY_SOCKTYPE sock, const string& hostname, const string& host_IP, unsigned short port); + SFqdnIp x_GetFqdnIp(unsigned host); + void x_GetSocketDestinations(MONKEY_SOCKTYPE sock, + string* fqdn, + string* IP, + unsigned short* my_port, + unsigned short* peer_port); /** Sockets that are already assigned to a plan (or known to be ignored) */ map m_KnownSockets; static CMonkey* sm_Instance; vector m_Plans; - double m_Probability; + unsigned short m_Probability; bool m_Enabled; static FMonkeyHookSwitch sm_HookSwitch; CRef> m_TlsToken; CRef > > m_TlsRandList; CRef > m_TlsRandListPos; unsigned int m_Seed; + map m_NetworkDataCache; /* to remember fqdn and IP */ /** Remember registered tokens for threads to avoid collisions */ set m_RegisteredTokens; + /* In case of an unsuccessful connect a new socket descriptor is created, + * but to use rules we have to bind all socket descriptors to a SOCK + * under which descriptors were created */ + map m_SocketMemory; }; diff --git a/c++/include/connect/ncbi_namedpipe_connector.hpp b/c++/include/connect/ncbi_namedpipe_connector.hpp index 705210fc..8c340e3b 100644 --- a/c++/include/connect/ncbi_namedpipe_connector.hpp +++ b/c++/include/connect/ncbi_namedpipe_connector.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_NAMEDPIPE_CONNECTOR__HPP #define CONNECT___NCBI_NAMEDPIPE_CONNECTOR__HPP -/* $Id: ncbi_namedpipe_connector.hpp 447122 2014-09-22 18:33:27Z lavr $ +/* $Id: ncbi_namedpipe_connector.hpp 533755 2017-04-19 16:26:34Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -35,8 +35,8 @@ /// Implement CONNECTOR for a named pipe interprocess communication /// (based on the NCBI CNamedPipe). /// -/// See in "connectr.h" for the detailed specification of the underlying -/// connector("CONNECTOR", "SConnectorTag") methods and structures. +/// See in "ncbi_connector.h" for the detailed specification of the underlying +/// connector(CONNECTOR, SConnectorTag) methods and structures. #include diff --git a/c++/include/connect/ncbi_pipe_connector.hpp b/c++/include/connect/ncbi_pipe_connector.hpp index 270e052d..55fc380d 100644 --- a/c++/include/connect/ncbi_pipe_connector.hpp +++ b/c++/include/connect/ncbi_pipe_connector.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_PIPE_CONNECTOR__HPP #define CONNECT___NCBI_PIPE_CONNECTOR__HPP -/* $Id: ncbi_pipe_connector.hpp 447122 2014-09-22 18:33:27Z lavr $ +/* $Id: ncbi_pipe_connector.hpp 533755 2017-04-19 16:26:34Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -35,8 +35,8 @@ /// Implement CONNECTOR for a pipe interprocess communication /// (based on the NCBI CPipe). /// -/// See in "connectr.h" for the detailed specification of the underlying -/// connector("CONNECTOR", "SConnectorTag") methods and structures. +/// See in "ncbi_connector.h" for the detailed specification of the underlying +/// connector(CONNECTOR, SConnectorTag) methods and structures. #include diff --git a/c++/include/connect/ncbi_sendmail.h b/c++/include/connect/ncbi_sendmail.h index 0a06a575..ad3eeac2 100644 --- a/c++/include/connect/ncbi_sendmail.h +++ b/c++/include/connect/ncbi_sendmail.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_SENDMAIL__H #define CONNECT___NCBI_SENDMAIL__H -/* $Id: ncbi_sendmail.h 455154 2014-12-23 16:33:41Z lavr $ +/* $Id: ncbi_sendmail.h 534370 2017-04-26 19:29:20Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -29,7 +29,7 @@ * Author: Anton Lavrentiev * * File Description: - * @file + * @file ncbi_sendmail.h * Send mail (in accordance with RFC821 [protocol] and RFC822 [headers]) * */ @@ -52,10 +52,10 @@ extern "C" { * @sa SSendMailInfo */ enum ESendMailOption { - fSendMail_LogOn = eOn, /**< see: fSOCK_LogOn */ - fSendMail_LogOff = eOff, /**< fSOCK_LogDefault */ + fSendMail_LogOn = eOn, /**< see: fSOCK_LogOn */ + fSendMail_LogOff = eOff, /**< fSOCK_LogDefault */ fSendMail_NoMxHeader = (1 << 4), /**< Don't add standard mail header, - just use what user provided */ + just use what user provided */ fSendMail_Old822Headers = (1 << 6), /**< Form "Date:" and "From:" hdrs (usually they are defaulted) */ fSendMail_StripNonFQDNHost = (1 << 8), /**< Strip host part off the "from" @@ -64,6 +64,8 @@ enum ESendMailOption { least two domain name labels separated by a dot); leave only the username part */ + fSendMail_ExtendedErrInfo = (1 << 10) /**< Return extended error info that + must be free()'d by caller */ }; typedef unsigned short TSendMailOptions; /**< Bitwise OR of ESendMailOption*/ @@ -80,7 +82,7 @@ typedef struct { const char* mx_host; /**< Host to contact an MTA at */ short mx_port; /**< Port to contact an MTA at */ TSendMailOptions mx_options; /**< See ESendMailOption */ - unsigned int magic_cookie; /**< RO, filled in by SendMailInfo_Init */ + unsigned int magic; /**< RO, filled in by SendMailInfo_Init */ } SSendMailInfo; @@ -148,7 +150,8 @@ extern NCBI_XCONNECT_EXPORT SSendMailInfo* SendMailInfo_InitEx * @param body * The message body * @return - * 0 on success; otherwise, a descriptive error message. + * 0 on success; otherwise, a descriptive error message. The message is + * kept in a static storage and is not to be deallocated by the caller. * @sa * SendMailInfo_InitEx, CORE_SendMailEx */ @@ -196,7 +199,16 @@ extern NCBI_XCONNECT_EXPORT const char* CORE_SendMail * @param info * Communicational and additional protocol parameters * @return - * 0 on success; otherwise, a descriptive error message. + * 0 on success; otherwise, a descriptive error message. The message is + * not to be deallocated by the caller unless fSendMail_ExtendedErrInfo is + * specified in SSendMailinfo::mx_options, in which case the message contains + * an explanation string followed by ": " and possibly an RFC821-compliant + * error code (as received from the server) followed by additional error text + * (which in turn may begin with RFC3462-compliant status as + * "class.subject.detail") -- this extended message string must be free()'d by + * the caller when no longer necessary. If there was an allocation error, the + * string is returned empty ("") and must not be deallocated. The latter + * makes the caller still aware there was a problem. * @sa * SendMailInfo_InitEx */ diff --git a/c++/include/connect/ncbi_server_info.h b/c++/include/connect/ncbi_server_info.h index c120c76c..2f74398f 100644 --- a/c++/include/connect/ncbi_server_info.h +++ b/c++/include/connect/ncbi_server_info.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_SERVER_INFO__H #define CONNECT___NCBI_SERVER_INFO__H -/* $Id: ncbi_server_info.h 494171 2016-03-04 01:46:23Z lavr $ +/* $Id: ncbi_server_info.h 533755 2017-04-19 16:26:34Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -29,17 +29,21 @@ * Authors: Anton Lavrentiev, Denis Vakatov * * File Description: + * @file ncbi_server_info.h * NCBI server meta-address info - * Note that all server meta-addresses are allocated as - * single contiguous pieces of memory, which can be copied in whole - * with the use of 'SERV_SizeOfInfo' call. Dynamically allocated - * server infos can be freed with a direct call to 'free'. - * Assumptions on the fields: all fields in the server info come in - * host byte order except 'host', which comes in network byte order. + * + * Note that all server meta-addresses are allocated as single contiguous + * pieces of memory, which can be copied in whole with the use of + * 'SERV_SizeOfInfo' call. Dynamically allocated server infos can be freed + * with a direct call to 'free'. + * + * Assumptions on the fields: all fields in the server info come in host byte + * order except 'host', which comes in network byte order. * */ #include +#include /** @addtogroup ServiceSupport @@ -47,7 +51,7 @@ * @{ */ -#define SERV_DEFAULT_FLAG eSERV_Regular +#define SERV_DEFAULT_ALGO eSERV_Regular #define SERV_MINIMAL_RATE 0.001 #define SERV_MAXIMAL_RATE 100000.0 #define SERV_MINIMAL_BONUS 0.01 @@ -74,29 +78,29 @@ typedef enum { /* Flag to specify an algorithm for selecting the most preferred server from * a set of available servers (NB: binary properties of the enumerated values - * may be in use!). Should have been named ESERV_Algo, but since it's now - * adding the "Inter" feature (also misplaced, and to be moved away to the part - * of "locl" area, the mis-name is still retained. + * may be in use!). */ typedef enum { - eSERV_Regular = 0, /* Server either tied up to lavg or static */ - eSERV_Blast = 1, /* Server is tied up to an instant host load */ - eSERV_RegularInter = 2, /* Regular server shared between LBSM zones */ - eSERV_BlastInter = 3, /* ... same for Blast-type server */ -} ESERV_Flag; + eSERV_Regular = 0, /* Server either tied up to lavg or static */ + eSERV_Blast = 1 /* Server is tied up to an instant host load */ +} ESERV_Algo; +typedef unsigned char TSERV_Algo; typedef enum { - fSERV_Stateful = 1, - fSERV_Secure = 2 + fSERV_Stateful = 1, /* Server requires persistent connection */ + fSERV_Secure = 2 /* Server requires secure connection */ } ESERV_Mode; +typedef unsigned char TSERV_Mode; typedef enum { - fSERV_Local = 1, - fSERV_Private = 2, - fSERV_SiteMask = 0xF0 + fSERV_Local = 1, /* Server accessible only for NCBI local clients*/ + fSERV_Private = 2, /* Server accessible only by localhost clients */ + fSERV_Interzone = 4, /* Server record spans LB zones within the site */ + fSERV_ZoneMask = 0xF0 /* Local zone number for the server */ } ESERV_Site; +typedef unsigned char TSERV_Site; /* Verbal representation of a server type (no internal spaces allowed) @@ -107,9 +111,8 @@ extern NCBI_XCONNECT_EXPORT const char* SERV_TypeStr /* Read server info type. - * If successful, assign "type" and return pointer to the position - * in the "str" immediately following the type tag. - * On error, return NULL. + * If successful, assign "type" and return pointer to the position in the "str" + * immediately following the type tag. On error, return NULL. */ extern NCBI_XCONNECT_EXPORT const char* SERV_ReadType (const char* str, @@ -120,28 +123,27 @@ extern NCBI_XCONNECT_EXPORT const char* SERV_ReadType /* Meta-addresses for various types of NCBI servers */ typedef struct { - TNCBI_Size args; + TNCBI_Size args; #define SERV_NCBID_ARGS(ui) ((char*)(ui) + (ui)->args) } SSERV_NcbidInfo; typedef struct { - char dummy; /* placeholder, not used */ + char _pad; /* placeholder, not used */ } SSERV_StandaloneInfo; typedef struct { - TNCBI_Size path; - TNCBI_Size args; + TNCBI_Size path; + TNCBI_Size args; #define SERV_HTTP_PATH(ui) ((char*)(ui) + (ui)->path) #define SERV_HTTP_ARGS(ui) ((char*)(ui) + (ui)->args) } SSERV_HttpInfo; typedef struct { - ESERV_Type type; /* type of original server */ + ESERV_Type type; /* type of the original server */ } SSERV_FirewallInfo; typedef struct { - char/*bool*/ name; /* name presence flag */ - char pad[7]; /* reserved for the future use, must be zero */ + unsigned char/*bool*/ name; /* name presence flag */ } SSERV_DnsInfo; @@ -159,21 +161,23 @@ typedef struct { ESERV_Type type; /* type of server */ unsigned int host; /* host the server running on, network b.o. */ unsigned short port; /* port the server running on, host b.o. */ - unsigned char mode; /* connection mode (stateful, secure, etc) */ - unsigned char site; /* site info (LSB: local, private; MSB: @#) */ + TSERV_Mode mode; /* connection mode (stateful, secure, etc) */ + TSERV_Site site; /* site info (LSB: local, private; MSB: @#) */ TNCBI_Time time; /* relaxation period / expiration time */ double coef; /* bonus coefficient for server run locally */ double rate; /* rate of the server */ EMIME_Type mime_t; /* type, */ EMIME_SubType mime_s; /* subtype, */ EMIME_Encoding mime_e; /* and encoding for content-type */ - ESERV_Flag flag; /* rate algorithm for the server (NB: algo!) */ - unsigned char reserved[16]; /* zeroed reserved area - do not use! */ + TSERV_Algo algo; /* rate algorithm for the server */ + TNCBI_IPv6Addr addr; /* IPv6 address (for host == INADDR_NONE(-1))*/ + unsigned char vhost; /* extra (v)host name size if non-zero */ + unsigned short extra; /* extra data size if non-zero */ USERV_Info u; /* server type-specific data/params */ } SSERV_Info; -/* Constructors for the various types of NCBI server meta-addresses +/* Constructors for the various types of NCBI server meta-addressesr45 */ extern NCBI_XCONNECT_EXPORT SSERV_Info* SERV_CreateNcbidInfo (unsigned int host, /* network byte order */ @@ -201,7 +205,7 @@ extern NCBI_XCONNECT_EXPORT SSERV_Info* SERV_CreateFirewallInfo ); extern NCBI_XCONNECT_EXPORT SSERV_Info* SERV_CreateDnsInfo -(unsigned int host /* the only parameter */ +(unsigned int host /* network byte order, the only parameter */ ); @@ -219,10 +223,11 @@ extern NCBI_XCONNECT_EXPORT char* SERV_WriteInfo * * TYPE := { STANDALONE | NCBID | HTTP[{_GET|_POST}] | FIREWALL | DNS } * - * Host should be specified as either an IP address (in dotted notation), - * or as a host name (using domain notation if necessary). - * Port number must be preceded by a colon. - * Both host and port get their default values if not specified. + * Host must be specified as either an IP address (in dotted notation), as an + * IPv6 address (enclosed in square brackets), or as a host name (using domain + * notation if necessary). Port number must be preceded by a colon. Both host + * and port defaults to server-specific values if omitted. For null + * specification ":0" can be used. * * Server-specific parameters: * @@ -231,32 +236,32 @@ extern NCBI_XCONNECT_EXPORT char* SERV_WriteInfo * * NCBID servers: Arguments to CGI in addition to specified by application. * Empty additional arguments denoted as '' (two single - * quotes, back to back). Note that the additional - * arguments must not contain space characters. + * quotes, back to back). Note that the additional arguments + * must not contain space characters. * * HTTP* servers: Path (required) and args (optional) in the form * path[?args] (here brackets denote the optional part). * Note that no spaces are allowed within these parameters. * - * FIREWALL servers: Servers of this type are converted real servers of - * the above types, when only accessible via FIREWALL - * mode of NCBI dispatcher. The purpose of this fake - * server type is just to let the client know that - * the service exists. Additional parameter is optional - * and if present, is the original type of the server - * before conversion. Note that servers of this type - * cannot be configured in LBSMD. + * FIREWALL servers: Servers of this type are converted real servers of the + * above types, when only accessible via FIREWALL mode of + * NCBI dispatcher. The purpose of this fake server type + * is just to let the client know that the service exists. + * Additional parameter is optional and if present, is the + * original type of the server before conversion. Note + * that servers of this type cannot be configured in + * LBSMD. * - * DNS servers: Services for DNS and DB load-balancing, - * and dynamic ProxyPassing at the NCBI Web entry point. - * Never exported to the outside world. + * DNS servers: Services for DNS and DB load-balancing, and dynamic reverse- + * proxying (the ProxyPass directive of the Apache HTTP daemon) + * at the NCBI Web entry point. Never exposed to the outside. * - * Tags may follow in no particular order but no more than one instance - * of each flag is allowed: + * Tags may follow in no particular order but no more than one instance of each + * tag is allowed: * - * Load average calculation for the server: - * Regular (default) - * Blast + * Load average calculation algorithm for the server: + * A=R (Regular=default) + * A=B (Blast) * * Bonus coefficient: * B=double [0.0 = default] @@ -285,6 +290,12 @@ extern NCBI_XCONNECT_EXPORT char* SERV_WriteInfo * get proper content type, defined at service configuration. * This tag is not allowed in DNS server specifications. * + * (V)Host name: + * H=hostname (optional) + * specifies the host name to use when accessing the server. Can be + * implicitly set by server configuration if a hostname (instead of + * an IP) is provided as the connection point (the host:port pair). + * * Local server: * L={yes|no} [default is set by SERV_SetLocalServerDefault()] * Local servers are accessible only by local clients (from within @@ -302,8 +313,8 @@ extern NCBI_XCONNECT_EXPORT char* SERV_WriteInfo * * Reachability base rate: * R=double [0.0 = default] - * specifies availability rate for the server, expressed as - * a floating point number with 0.0 meaning the server is down + * specifies availability rate for the server, expressed as a + * floating point number with 0.0 meaning the server is down * (unavailable) and 1000.0 meaning the server is up and running. * Intermediate or higher values can be used to make the server less * or more favorable for choosing by LBSM Daemon, as this coefficient @@ -314,8 +325,8 @@ extern NCBI_XCONNECT_EXPORT char* SERV_WriteInfo * dynamically switches this rate to be the maximal specified when * the server is up, and to be zero when the server is down. * Note that negative values are reserved for LBSMD private use. - * To specify a server as inactive in LBSMD configuration file, - * one can use any negative number (note that value "0" in the config + * To specify a server as inactive in LBSMD configuration file, one + * can use any negative number (note that value "0" in the config * file means "default" and gets replaced with the value 1000.0). * Values less than 0.01 define standby server entries, which are * used by the clients only if there are no working entries with a @@ -338,15 +349,21 @@ extern NCBI_XCONNECT_EXPORT char* SERV_WriteInfo * protocol (HTTPS or SSL). * * Validity period: - * T=integer [0 = default] + * T=integer [0=default] * specifies the time in seconds that this server entry is valid for - * without an update. (If equal to 0 then defaulted by - * the LBSM Daemon to some reasonable value.) + * without an update. (If equal to 0 then defaulted to the LBSM + * Daemon to some reasonable value.) + * + * Interzone server: + * X=no (default) + * X=yes + * indicates that the server definition can span zones within the + * current site (by default, a server info is local to a zone). * * * Note that optional arguments can be omitted along with all preceding - * optional arguments; that is, the following 2 server specifications are - * both valid: + * optional arguments; that is, the following 2 server specifications are both + * valid: * * NCBID '' * and @@ -354,13 +371,13 @@ extern NCBI_XCONNECT_EXPORT char* SERV_WriteInfo * * but they are not equal to the following specification: * - * NCBID Regular + * NCBID A=R * - * because here 'Regular' is treated as an argument, not as a tag. - * To make the latter specification equivalent to the former two, one has - * to use the following form: + * because here 'A=R' is treated as an argument, not as a tag. To make the + * latter specification equivalent to the former two (since 'A=R' is the + * default tag), one has to use the following form: * - * NCBID '' Regular + * NCBID '' A=R */ diff --git a/c++/include/connect/ncbi_service.h b/c++/include/connect/ncbi_service.h index 48024c66..27b88b83 100644 --- a/c++/include/connect/ncbi_service.h +++ b/c++/include/connect/ncbi_service.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_SERVICE__H #define CONNECT___NCBI_SERVICE__H -/* $Id: ncbi_service.h 513292 2016-09-09 11:35:38Z ivanov $ +/* $Id: ncbi_service.h 533755 2017-04-19 16:26:34Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -29,7 +29,7 @@ * Authors: Anton Lavrentiev, Denis Vakatov * * File Description: - * @file + * @file ncbi_service.h * Top-level API to resolve NCBI service names into server meta-addresses. * */ @@ -77,9 +77,9 @@ typedef const SSERV_Info* SSERV_InfoCPtr; */ enum ESERV_TypeSpecial { fSERV_Any = 0, - fSERV_All = 0x0000FFFF, + fSERV_All = 0x0000FFFF, /**< Server type mask */ fSERV_Stateless = 0x00100000, /**< Stateless servers only */ - fSERV_Reserved = 0x00400000, + fSERV_Reserved = 0x00400000, /**< Reserved, MBZ */ fSERV_ReverseDns = 0x00800000, /**< LB-DNS translation */ /* The following allow to get currently inactive service instances */ fSERV_IncludeDown = 0x08000000, @@ -104,19 +104,20 @@ typedef unsigned short TSERV_TypeOnly; /**stateless" forces "types" to get the "fSERV_StatelessOnly" * bit set implicitly. @@ -243,7 +244,7 @@ extern NCBI_XCONNECT_EXPORT SSERV_InfoCPtr SERV_GetNextInfo * Preferred host to use the service at, nbo. * @param net_info * Connection information (NULL disables network dispatching via - * DISPD, still allowing use of LBOS). + * DISPD, still allowing use of LBOS/NAMERD). * @param skip[] * An array of servers NOT to select, see SERV_OpenEx() for notes. * @param n_skip diff --git a/c++/include/connect/ncbi_service_connector.h b/c++/include/connect/ncbi_service_connector.h index 223380dd..78a3b30a 100644 --- a/c++/include/connect/ncbi_service_connector.h +++ b/c++/include/connect/ncbi_service_connector.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_SERVICE_CONNECTOR__H #define CONNECT___NCBI_SERVICE_CONNECTOR__H -/* $Id: ncbi_service_connector.h 464976 2015-04-15 18:27:40Z lavr $ +/* $Id: ncbi_service_connector.h 532676 2017-04-07 14:32:22Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -62,8 +62,8 @@ typedef struct { FHTTP_Adjust adjust; /* Called when data source is HTTP(S)*/ FSERVICE_Cleanup cleanup; /* Called prior to connector destroy */ FHTTP_ParseHeader parse_header; /* Called when data source is HTTP(S)*/ - FSERVICE_GetNextInfo get_next_info; /* Called to get connection point */ - THTTP_Flags flags; /* fHTTP_Flushable|fHTTP_NoAutoRetry */ + FSERVICE_GetNextInfo get_next_info; /* Called to get connection point(s) */ + THTTP_Flags flags; /* fHTTP_Flushbl|NoAutoRy|AdjOnRedir */ } SSERVICE_Extra; diff --git a/c++/include/connect/ncbi_socket.h b/c++/include/connect/ncbi_socket.h index ad0bc744..de212592 100644 --- a/c++/include/connect/ncbi_socket.h +++ b/c++/include/connect/ncbi_socket.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_SOCKET__H #define CONNECT___NCBI_SOCKET__H -/* $Id: ncbi_socket.h 501319 2016-05-13 15:59:52Z vakatov $ +/* $Id: ncbi_socket.h 537331 2017-05-30 19:56:20Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -217,7 +217,7 @@ typedef struct TRIGGER_tag* TRIGGER; /* trigger: handle, opaque */ * (in most cases automatically) by CONNECT_Init() API: for C Toolkit it gets * always called before [Nlm_]Main(); in C++ Toolkit it gets called by * most of C++ classes' ctors, except for sockets; so if your application - * does not use any C++ classes besides sockets, it has to set CORE_LOCK + * does not use any C++ classes besides sockets, it has to set CORE_SetLOCK * explicitly, as described above. * * @sa @@ -241,7 +241,7 @@ typedef struct TRIGGER_tag* TRIGGER; /* trigger: handle, opaque */ * @note * This call, when used for the very first time in the application, enqueues * SOCK_ShutdownAPI() to be called upon application exit on plaftorms that - * provide this functionality. In any case, the application can opt for + * provide this functionality. In any case, the application can opt for * explicit SOCK_ShutdownAPI() call when it is done with all sockets. * @sa * SOCK_ShutdownAPI @@ -253,7 +253,10 @@ extern NCBI_XCONNECT_EXPORT EIO_Status SOCK_InitializeAPI(void); * @attention No function from the SOCK API should be called after this call! * @note * You can safely call it more than once; just, all calls after the first - * one will have no result. + * one will have no effect. + * @warning + * Once the API has been shut down with this call, it cannot be reactivated + * with SOCK_InitializeAPI() -- it will always return eIO_NotSupported. * @sa * SOCK_InitializeAPI */ @@ -261,9 +264,9 @@ extern NCBI_XCONNECT_EXPORT EIO_Status SOCK_ShutdownAPI(void); /** By default (on UNIX platforms) the SOCK API functions automagically call - * "signal(SIGPIPE, SIG_IGN)" on initialization. To prohibit this feature, - * you must call SOCK_AllowSigPipeAPI() before you call any other. - * function from the SOCK API. + * "signal(SIGPIPE, SIG_IGN)" on initialization. To prohibit this feature you + * must call SOCK_AllowSigPipeAPI() before you call any other function from the + * SOCK API. */ extern NCBI_XCONNECT_EXPORT void SOCK_AllowSigPipeAPI(void); @@ -2158,6 +2161,15 @@ extern NCBI_XCONNECT_EXPORT void SOCK_SetupSSL(FSSLSetup setup); extern NCBI_XCONNECT_EXPORT EIO_Status SOCK_SetupSSLEx(FSSLSetup setup); +/** Return an SSL vendor name (in a const static storage), with special + * considerations: return "" if SSL has not been properly initialized, + * NULL if SSL has not been properly set up. + * @note + * "NONE" is returned as a name if SSL has been explicitly disabled. + */ +extern NCBI_XCONNECT_EXPORT const char* SOCK_SSLName(void); + + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/c++/include/connect/ncbi_tls.h b/c++/include/connect/ncbi_tls.h new file mode 100644 index 00000000..50fdc3f5 --- /dev/null +++ b/c++/include/connect/ncbi_tls.h @@ -0,0 +1,88 @@ +#ifndef CONNECT___NCBI_SSL__H +#define CONNECT___NCBI_SSL__H + +/* $Id: ncbi_tls.h 531440 2017-03-24 17:43:17Z lavr $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * SSL (Secure Socket Layer) support in connection library + * + */ + +#include + + +/** @addtogroup Sockets + * + * @{ + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Setup a TLS (Transport Layer Security) provider library to support SSL + * in ncbi_socket.h[pp]. + * + * Currently we support mbedTLS and GNUTLS as the providers. This call selects + * the library, which is the default, or which is requested via the registry + * (aka .ini file), or through the process environment (takes precedence over + * the registry): + * + * [CONN] + * USESSL={1,0,MBEDTLS,GNUTLS} + * + * CONN_USESSL={1,0,MBEDTLS,GNUTLS} + * + * "Off", "No", "False", case-insensitively, are also accepted for "0"; and + * "On", "Yes", "True" -- for "1". + * + * If the provider is not present in the build, "0" is assumed. "1" selects + * the default provider as currently configured within the toolkit. With "0", + * SSL will not be availbale for sockets, and any secure session will fail. + * + * @note GNUTLS is only available as an external 3-rd party library, and must + * be so configured --with-gnutls at the configuration stage of the build. + * mbedTLS can also be used as an external installation, but the toolkit has + * an embedded private copy of the library, which can be used transparently + * without any additional dependencies. That embedded copy will be used as + * the default, if no other providers are explicitly present. + */ +extern NCBI_XCONNECT_EXPORT +SOCKSSL NcbiSetupTls(void); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +/* @} */ + +#endif /* CONNECT___NCBI_SSL_H */ diff --git a/c++/include/connect/ncbi_types.h b/c++/include/connect/ncbi_types.h index 0b2cb80f..b5631d56 100644 --- a/c++/include/connect/ncbi_types.h +++ b/c++/include/connect/ncbi_types.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_TYPES__H #define CONNECT___NCBI_TYPES__H -/* $Id: ncbi_types.h 501321 2016-05-13 16:00:05Z vakatov $ +/* $Id: ncbi_types.h 533755 2017-04-19 16:26:34Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -28,9 +28,9 @@ * * Author: Anton Lavrentiev * - * @file * File Description: - * Special types for core library. + * @file ncbi_types.h + * Special types for connect core library. * * Timeout: * struct STimeout diff --git a/c++/include/connect/ncbi_util.h b/c++/include/connect/ncbi_util.h index 323f3da5..dc74fac8 100644 --- a/c++/include/connect/ncbi_util.h +++ b/c++/include/connect/ncbi_util.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_UTIL__H #define CONNECT___NCBI_UTIL__H -/* $Id: ncbi_util.h 488838 2016-01-06 13:45:11Z elisovdn $ +/* $Id: ncbi_util.h 545592 2017-09-07 18:06:13Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -28,8 +28,8 @@ * * Authors: Denis Vakatov, Anton Lavrentiev * - * @file * File Description: + * @file ncbi_util.h * Auxiliaries (mostly optional core to back and complement "ncbi_core.[ch]") * @sa * ncbi_core.h @@ -50,6 +50,7 @@ * CORE_GetPlatform() * CORE_GetUsername[Ex]() * CORE_GetVMPageSize() + * CORE_Msdelay() * * 3. Checksumming support: * UTIL_CRC32_Update() @@ -267,16 +268,16 @@ extern NCBI_XCONNECT_EXPORT TLOG_FormatFlags CORE_SetLOGFormatFlags * * @note The returned string must be deallocated using "free()". * - * @param call_data - * Parts of the message - * @param format_flags - * Which fields of "call_data" to use + * @param mess + * Broken down message + * @param flags + * Which fields of "mess" to use * @sa * CORE_SetLOG, CORE_SetLOGFormatFlags */ extern NCBI_XCONNECT_EXPORT char* LOG_ComposeMessage -(const SLOG_Handler* call_data, - TLOG_FormatFlags format_flags +(const SLOG_Message* mess, + TLOG_FormatFlags flags ); @@ -464,6 +465,14 @@ extern NCBI_XCONNECT_EXPORT const char* CORE_GetUsername extern NCBI_XCONNECT_EXPORT size_t CORE_GetVMPageSize(void); +/** Delay execution of the current thread by the specified number of + * milliseconds + * @return + * 0 if the page size cannot be determined. + */ +extern NCBI_XCONNECT_EXPORT void CORE_Msdelay(unsigned long ms); + + /****************************************************************************** * Checksumming @@ -648,23 +657,21 @@ extern NCBI_XCONNECT_EXPORT char* UTIL_PrintableString * * NOTE: UTIL_ReleaseBufferOnHeap() must be used to free the buffers returned * from UTIL_TcharToUtf8OnHeap(), and UTIL_ReleaseBuffer() to free the - * ones returned from UTIL_TcharToUtf8(). + * ones returned from UTIL_TcharToUtf8()/UTIL_Utf8ToTchar(). + * + * NOTE: If you change these macros (here and in #else) you need to make + * similar changes in ncbi_strerror.c as well. */ - #if defined(NCBI_OS_MSWIN) && defined(_UNICODE) extern const char* UTIL_TcharToUtf8OnHeap(const wchar_t* str); extern const char* UTIL_TcharToUtf8 (const wchar_t* str); extern const wchar_t* UTIL_Utf8ToTchar (const char* str); -/* - * NOTE: If you change these macros (here and in #else) you need to make - * similar changes in ncbi_strerror.c as well. - */ -# define UTIL_ReleaseBuffer(x) UTIL_ReleaseBufferOnHeap(x) +# define UTIL_ReleaseBuffer(x) UTIL_ReleaseBufferOnHeap(x) #else -# define UTIL_TcharToUtf8OnHeap(x) (x) -# define UTIL_TcharToUtf8(x) (x) -# define UTIL_Utf8ToTchar(x) (x) -# define UTIL_ReleaseBuffer(x) /*void*/ +# define UTIL_TcharToUtf8OnHeap(x) (x) +# define UTIL_TcharToUtf8(x) (x) +# define UTIL_Utf8ToTchar(x) (x) +# define UTIL_ReleaseBuffer(x) /*void*/ #endif /*NCBI_OS_MSWIN && _UNICODE*/ #ifdef NCBI_OS_MSWIN diff --git a/c++/include/connect/services/grid_app_version_info.hpp b/c++/include/connect/services/grid_app_version_info.hpp index 1681e47a..fe6b3a16 100644 --- a/c++/include/connect/services/grid_app_version_info.hpp +++ b/c++/include/connect/services/grid_app_version_info.hpp @@ -1,4 +1,4 @@ -/* $Id: grid_app_version_info.hpp 421636 2013-12-12 21:07:18Z kazimird $ +/* $Id: grid_app_version_info.hpp 523682 2017-01-05 14:56:34Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,6 +37,9 @@ #include #include +#include + +#include #if defined(NCBI_PACKAGE) && NCBI_PACKAGE #define GRID_APP_VERSION "Grid " NCBI_PACKAGE_VERSION @@ -60,5 +63,24 @@ } \ } +namespace ncbi { +namespace grid { +namespace cgi { + +template +class CVersionReporting : public TBase +{ +public: + CVersionReporting() + { + auto& version = this->GetFullVersion(); + auto package_version = version.GetPackageVersion(); + this->SetVersion(package_version); + } +}; + +} +} +} #endif // CONNECT_SERVICES__APP_VERSION_INFO_HPP diff --git a/c++/include/connect/services/grid_client.hpp b/c++/include/connect/services/grid_client.hpp index 4ca9e87d..0bd8ce3e 100644 --- a/c++/include/connect/services/grid_client.hpp +++ b/c++/include/connect/services/grid_client.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES_GRID__GRID_CLIENT__HPP #define CONNECT_SERVICES_GRID__GRID_CLIENT__HPP -/* $Id: grid_client.hpp 492431 2016-02-17 17:05:04Z sadyrovr $ +/* $Id: grid_client.hpp 537172 2017-05-26 15:53:31Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,6 +37,7 @@ #include #include +#include #include @@ -103,8 +104,7 @@ private: vector m_Jobs; size_t m_JobIndex; bool m_HasBeenSubmitted; - auto_ptr m_Writer; - auto_ptr m_WStream; + SGridWrite m_GridWrite; /// The copy constructor and the assignment operator /// are prohibited @@ -159,10 +159,6 @@ public: ECleanUp cleanup, EProgressMsg progress_msg); - /// Get a job submitter - /// @deprecated Use the CGridClient object itself instead. - NCBI_DEPRECATED CGridClient& GetJobSubmitter() {return *this;} - /// Get a job's output string. /// /// This string can be used in two ways. @@ -233,7 +229,7 @@ public: /// Submit a job to the queue /// - CNetScheduleAPI::EJobStatus SubmitAndWait(unsigned wait_time); + CNetScheduleAPI::EJobStatus SubmitAndWait(unsigned wait_time, pair = {}); /// Wait for job to finish its execution (done/failed/canceled). /// @sa CNetScheduleAPI @@ -247,19 +243,6 @@ public: /// CGridJobBatchSubmitter& GetJobBatchSubmitter(); - /// Get a job status checker - /// - /// @deprecated Use SetJobKey() and the CGridClient object itself instead. - /// - /// @param job_key - /// Job key - /// - NCBI_DEPRECATED CGridClient& GetJobStatus(const string& job_key) - { - SetJobKey(job_key); - return *this; - } - void SetJobKey(const string& job_key); /// Cancel Job @@ -288,8 +271,8 @@ private: CNetCacheAPI m_NetCacheAPI; CNetScheduleJob m_Job; - auto_ptr m_Writer; - auto_ptr m_WStream; + SGridRead m_GridRead; + SGridWrite m_GridWrite; auto_ptr m_JobBatchSubmitter; @@ -303,7 +286,6 @@ private: size_t m_BlobSize; bool m_AutoCleanUp; bool m_UseProgress; - auto_ptr m_RStream; bool m_JobDetailsRead; /// The copy constructor and the assignment operator @@ -312,12 +294,6 @@ private: CGridClient& operator=(const CGridClient&); }; -/// @deprecated Use GetGridClient() instead. -NCBI_DEPRECATED typedef CGridClient CGridJobSubmitter; - -/// @deprecated Use GetGridClient() instead. -NCBI_DEPRECATED typedef CGridClient CGridJobStatus; - /// Grid Client exception /// class CGridClientException : public CException diff --git a/c++/include/connect/services/grid_globals.hpp b/c++/include/connect/services/grid_globals.hpp index 4ee42613..ef9ca0f3 100644 --- a/c++/include/connect/services/grid_globals.hpp +++ b/c++/include/connect/services/grid_globals.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES___GRID_GLOBALS__HPP #define CONNECT_SERVICES___GRID_GLOBALS__HPP -/* $Id: grid_globals.hpp 443514 2014-08-14 21:35:38Z kazimird $ +/* $Id: grid_globals.hpp 532685 2017-04-07 16:02:52Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -82,11 +82,9 @@ private: unsigned int m_InfiniteLoopTime; struct SJobActivity { CStopWatch elasped_time; - bool flag; - SJobActivity(CStopWatch elapsed_time_val, bool flag_val) : - elasped_time(elapsed_time_val), flag(flag_val) {} - SJobActivity() : - elasped_time(CStopWatch(CStopWatch::eStart)), flag(false) {} + bool is_stuck; + SJobActivity(CStopWatch et, bool is) : elasped_time(et), is_stuck(is) {} + SJobActivity() : elasped_time(CStopWatch(CStopWatch::eStart)), is_stuck(false) {} }; typedef map TActiveJobs; diff --git a/c++/include/connect/services/grid_rw_impl.hpp b/c++/include/connect/services/grid_rw_impl.hpp index efa49508..061ae51f 100644 --- a/c++/include/connect/services/grid_rw_impl.hpp +++ b/c++/include/connect/services/grid_rw_impl.hpp @@ -2,7 +2,7 @@ #define _GRID_RW_IMPL_HPP_ -/* $Id: grid_rw_impl.hpp 489744 2016-01-15 16:50:24Z sadyrovr $ +/* $Id: grid_rw_impl.hpp 537169 2017-05-26 15:43:05Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,14 +31,38 @@ * */ +#include #include #include #include +#include +#include + BEGIN_NCBI_SCOPE +class NCBI_XCONNECT_EXPORT CStringOrWriter : public IEmbeddedStreamWriter +{ +public: + using TWriterCreate = function; + + CStringOrWriter(size_t max_data_size, string& data_ref, TWriterCreate writer_create); + + ERW_Result Write(const void* buf, size_t count, size_t* bytes_written = 0) override; + ERW_Result Flush() override; + + void Close() override; + void Abort() override; + +private: + size_t m_MaxDataSize; + string& m_Data; + TWriterCreate m_WriterCreate; + unique_ptr m_Writer; +}; + /// String or Blob Storage Writer /// /// An implementation of the IWriter interface with a dual behavior. @@ -49,30 +73,24 @@ BEGIN_NCBI_SCOPE /// In this case "data_or_key" parameter holds a blob key for the written data. /// class NCBI_XCONNECT_EXPORT CStringOrBlobStorageWriter : - public IEmbeddedStreamWriter + public CStringOrWriter { public: CStringOrBlobStorageWriter(size_t max_string_size, SNetCacheAPIImpl* storage, string& job_output_ref); +}; - virtual ERW_Result Write(const void* buf, - size_t count, - size_t* bytes_written = 0); - - virtual ERW_Result Flush(void); - - virtual void Close(); - virtual void Abort(); +struct SGridWrite +{ + unique_ptr writer; + unique_ptr stream; -private: - CNetCacheAPI m_Storage; - auto_ptr m_NetCacheWriter; - string& m_Data; - size_t m_MaxBuffSize; + CNcbiOstream& operator()(CNetCacheAPI nc_api, size_t embedded_max_size, string& data); + CNcbiOstream& operator()(CNetCacheAPI nc_api, size_t embedded_max_size, bool direct_output, CNetScheduleJob& job); + void Reset(bool flush = false); }; - /// String or Blob Storage Reader /// /// An implementation of the IReader interface with a dual behavior. @@ -104,6 +122,13 @@ private: size_t m_BytesToRead; }; +struct SGridRead +{ + unique_ptr stream; + + CNcbiIstream& operator()(CNetCacheAPI nc_api, const string& data, size_t* data_size); + void Reset(); +}; class CStringOrBlobStorageRWException : public CException { diff --git a/c++/include/connect/services/grid_worker.hpp b/c++/include/connect/services/grid_worker.hpp index 6d099c2d..3da2445e 100644 --- a/c++/include/connect/services/grid_worker.hpp +++ b/c++/include/connect/services/grid_worker.hpp @@ -2,7 +2,7 @@ #define CONNECT_SERVICES__GRID_WORKER_HPP -/* $Id: grid_worker.hpp 491853 2016-02-09 18:08:45Z sadyrovr $ +/* $Id: grid_worker.hpp 513354 2016-09-09 16:24:02Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -55,6 +55,8 @@ #include #include +#include + BEGIN_NCBI_SCOPE /** @addtogroup NetScheduleClient @@ -416,7 +418,7 @@ public: /// Initialize a worker node factory /// - virtual void Init(const IWorkerNodeInitContext& context) {} + virtual void Init(const IWorkerNodeInitContext& /*context*/) {} /// Get the job version /// @@ -424,6 +426,8 @@ public: virtual string GetAppName() const {return GetJobVersion();} + virtual string GetAppVersion() const { return kEmptyStr; } + /// Get the Idle task /// virtual IWorkerNodeIdleTask* GetIdleTask() { return NULL; } @@ -577,7 +581,9 @@ class NCBI_XCONNECT_EXPORT CGridWorkerNode const string& GetClientName() const; string GetAppName() const; - const CVersion& GetAppVersion() const; + + typedef array TVersion; + TVersion GetAppVersion() const; const string& GetServiceName() const; diff --git a/c++/include/connect/services/grid_worker_app.hpp b/c++/include/connect/services/grid_worker_app.hpp index b8d8bc2c..47a64e66 100644 --- a/c++/include/connect/services/grid_worker_app.hpp +++ b/c++/include/connect/services/grid_worker_app.hpp @@ -2,7 +2,7 @@ #define CONNECT_SERVICES__GRID_WORKER_APP_HPP -/* $Id: grid_worker_app.hpp 491945 2016-02-10 18:01:31Z sadyrovr $ +/* $Id: grid_worker_app.hpp 540577 2017-07-07 18:37:12Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -187,7 +187,14 @@ inline void CGridWorkerApp::SetListener(IGridWorkerNodeApp_Listener* listener) # define GRID_WORKER_APP_BUILD_TAG kEmptyStr #endif -#define NCBI_WORKERNODE_MAIN_IMPL(TFactory, Version, SetListener) \ +#ifdef NCBI_WORKERNODE_CLASS +#error \ + NCBI_WORKERNODE_CLASS is not supported anymore. \ + Replace NCBI_WORKERNODE_* with corresponding NCBI_WORKERNODE_*_DERIVED providing app class. \ + Please be aware that your app class is required to accept SBuildInfo and pass it to CGridWorkerApp. +#endif + +#define NCBI_WORKERNODE_MAIN_IMPL(TFactory, CGridWorkerApp, Version, SetListener) \ int main(int argc, const char* argv[]) \ { \ GetDiagContext().SetOldPostFormat(false); \ @@ -199,20 +206,25 @@ inline void CGridWorkerApp::SetListener(IGridWorkerNodeApp_Listener* listener) } #define NCBI_WORKERNODE_MAIN(TWorkerNodeJob, Version) \ + NCBI_WORKERNODE_MAIN_DERIVED(TWorkerNodeJob, CGridWorkerApp, Version) + +#define NCBI_WORKERNODE_MAIN_DERIVED(TWorkerNodeJob, CGridWorkerApp, Version) \ NCBI_DECLARE_WORKERNODE_FACTORY(TWorkerNodeJob, Version); \ - NCBI_WORKERNODE_MAIN_IMPL(TWorkerNodeJob##Factory, Version, ) + NCBI_WORKERNODE_MAIN_IMPL(TWorkerNodeJob##Factory, CGridWorkerApp, Version, ) -#define NCBI_WORKERNODE_MAIN_WITH_LISTENER(TWorkerNodeJob, Version, \ - ListenerClass) \ +#define NCBI_WORKERNODE_MAIN_WITH_LISTENER(TWorkerNodeJob, Version, ListenerClass) \ + NCBI_WORKERNODE_MAIN_WITH_LISTENER_DERIVED(TWorkerNodeJob, CGridWorkerApp, Version, ListenerClass) + +#define NCBI_WORKERNODE_MAIN_WITH_LISTENER_DERIVED(TWorkerNodeJob, CGridWorkerApp, Version, ListenerClass) \ NCBI_DECLARE_WORKERNODE_FACTORY(TWorkerNodeJob, Version); \ - NCBI_WORKERNODE_MAIN_IMPL(TWorkerNodeJob##Factory, Version, \ - app.SetListener(new ListenerClass)) - -#define NCBI_WORKERNODE_MAIN_EX(TWorkerNodeJob, \ - TWorkerNodeIdleTask, Version) \ - NCBI_DECLARE_WORKERNODE_FACTORY_EX(TWorkerNodeJob, \ - TWorkerNodeIdleTask, Version); \ - NCBI_WORKERNODE_MAIN_IMPL(TWorkerNodeJob##FactoryEx, Version, ) + NCBI_WORKERNODE_MAIN_IMPL(TWorkerNodeJob##Factory, CGridWorkerApp, Version, app.SetListener(new ListenerClass)) + +#define NCBI_WORKERNODE_MAIN_EX(TWorkerNodeJob, TWorkerNodeIdleTask, Version) \ + NCBI_WORKERNODE_MAIN_EX_DERIVED(TWorkerNodeJob, TWorkerNodeIdleTask, CGridWorkerApp, Version) + +#define NCBI_WORKERNODE_MAIN_EX_DERIVED(TWorkerNodeJob, TWorkerNodeIdleTask, CGridWorkerApp, Version) \ + NCBI_DECLARE_WORKERNODE_FACTORY_EX(TWorkerNodeJob, TWorkerNodeIdleTask, Version); \ + NCBI_WORKERNODE_MAIN_IMPL(TWorkerNodeJob##FactoryEx, CGridWorkerApp, Version, ) #define NCBI_GRID_PKG_WORKER_NODE_MAIN(TWorkerNodeJob, \ TWorkerNodeJobFactoryClass, ListenerClass) \ diff --git a/c++/include/connect/services/impl/netschedule_api_int.hpp b/c++/include/connect/services/impl/netschedule_api_int.hpp index e4604f5d..db488f75 100644 --- a/c++/include/connect/services/impl/netschedule_api_int.hpp +++ b/c++/include/connect/services/impl/netschedule_api_int.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES_IMPL__NETSCHEDULE_API_INT__HPP #define CONNECT_SERVICES_IMPL__NETSCHEDULE_API_INT__HPP -/* $Id: netschedule_api_int.hpp 491948 2016-02-10 18:22:43Z sadyrovr $ +/* $Id: netschedule_api_int.hpp 537390 2017-05-31 15:32:22Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -47,11 +47,11 @@ NCBI_DECLARE_INTERFACE_VERSION(SNetScheduleAPIImpl, "xnetschedule_api", 1,0, 0); extern NCBI_XCONNECT_EXPORT const char* const kNetScheduleAPIDriverName; extern NCBI_XCONNECT_EXPORT -void g_AppendClientIPSessionIDHitID(string& cmd); +void g_AppendClientIPSessionIDHitID(string& cmd, bool = false); extern NCBI_XCONNECT_EXPORT int g_ParseNSOutput(const string& attr_string, const char* const* attr_names, - string* attr_values, int attr_count); + string* attr_values, size_t attr_count); void NCBI_XCONNECT_EXPORT NCBI_EntryPoint_xnetscheduleapi( CPluginManager::TDriverInfoList& info_list, @@ -87,7 +87,7 @@ public: // This method requires calling SubmitJob prior with wait_time set CNetScheduleAPI::EJobStatus WaitForJobCompletion(CNetScheduleJob& job, CDeadline& deadline, CNetScheduleAPI ns_api, - time_t* job_exptime = NULL); + time_t* job_exptime = NULL, pair = {}); bool RequestJobWatching(CNetScheduleAPI::TInstance ns_api, const string& job_id, @@ -130,6 +130,12 @@ public: CNetServer* server); protected: + bool CheckJobStatusNotification(CNetScheduleAPI ns_api, CNetScheduleJob& job, + time_t* job_exptime, CNetScheduleAPI::EJobStatus& job_status, pair = {}); + bool ReadOutput(CNetScheduleAPI::EJobStatus& job_status, + pair receiver, const string& worker_node_host, const string& worker_node_port, + const STimeout& timeout); + CDatagramSocket m_UDPSocket; unsigned short m_UDPPort; diff --git a/c++/include/connect/services/impl/netstorage_impl.hpp b/c++/include/connect/services/impl/netstorage_impl.hpp index 0362c2c1..d708dac6 100644 --- a/c++/include/connect/services/impl/netstorage_impl.hpp +++ b/c++/include/connect/services/impl/netstorage_impl.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES_IMPL__NETSTORAGE_IMPL__HPP #define CONNECT_SERVICES_IMPL__NETSTORAGE_IMPL__HPP -/* $Id: netstorage_impl.hpp 505978 2016-06-30 15:57:38Z sadyrovr $ +/* $Id: netstorage_impl.hpp 529966 2017-03-09 16:11:36Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -41,41 +41,202 @@ BEGIN_NCBI_SCOPE +struct SNetStorageObjectImpl; + /// @internal -struct NCBI_XCONNECT_EXPORT SNetStorageObjectImpl : - public CObject, - public IReader, - public IEmbeddedStreamWriter +struct NCBI_XCONNECT_EXPORT INetStorageObjectState : public IEmbeddedStreamReaderWriter { - /* IReader methods */ - virtual ERW_Result Read(void* buf, size_t count, size_t* bytes_read) = 0; - virtual ERW_Result PendingCount(size_t* count); - - /* IEmbeddedStreamWriter methods */ - virtual ERW_Result Write(const void* buf, size_t count, - size_t* bytes_written) = 0; - virtual ERW_Result Flush(); - virtual void Close() = 0; - virtual void Abort(); - - /* More overridable methods */ - virtual IReader& GetReader(); - virtual IEmbeddedStreamWriter& GetWriter(); - - virtual string GetLoc() = 0; - virtual void Read(string* data); + virtual string GetLoc() const = 0; virtual bool Eof() = 0; virtual Uint8 GetSize() = 0; virtual list GetAttributeList() const = 0; - virtual string GetAttribute(const string& attr_name) const = 0; - virtual void SetAttribute(const string& attr_name, - const string& attr_value) = 0; + virtual string GetAttribute(const string& name) const = 0; + virtual void SetAttribute(const string& name, const string& value) = 0; virtual CNetStorageObjectInfo GetInfo() = 0; - virtual void SetExpiration(const CTimeout&) = 0; - + virtual void SetExpiration(const CTimeout& ttl) = 0; virtual string FileTrack_Path() = 0; + virtual string Relocate(TNetStorageFlags flags, TNetStorageProgressCb cb) = 0; + virtual bool Exists() = 0; + virtual ENetStorageRemoveResult Remove() = 0; + + virtual pair GetUserInfo() + { + NCBI_THROW_FMT(CNetStorageException, eNotSupported, "INetStorageObjectState::GetUserInfo()"); + } + + virtual CNetStorageObjectLoc& Locator() + { + NCBI_THROW_FMT(CNetStorageException, eNotSupported, "INetStorageObjectState::Locator()"); + } + + virtual void CancelRelocate() + { + NCBI_THROW_FMT(CNetStorageException, eNotSupported, "INetStorageObjectState::CancelRelocate()"); + } + +protected: + void EnterState(INetStorageObjectState* state); + void ExitState(); + +private: + virtual SNetStorageObjectImpl& Fsm() = 0; +}; + +/// @internal +template +struct SNetStorageObjectState : TBase +{ + template + SNetStorageObjectState(SNetStorageObjectImpl& fsm, TArgs&&... args) : + TBase(std::forward(args)...), + m_Fsm(fsm) + { + } + +private: + SNetStorageObjectImpl& Fsm() final { return m_Fsm; } + + SNetStorageObjectImpl& m_Fsm; +}; + +/// @internal +struct NCBI_XCONNECT_EXPORT SNetStorageObjectIoState : public INetStorageObjectState +{ + Uint8 GetSize() final; + list GetAttributeList() const final; + string GetAttribute(const string& name) const final; + void SetAttribute(const string& name, const string& value) final; + CNetStorageObjectInfo GetInfo() final; + void SetExpiration(const CTimeout& ttl) final; + string FileTrack_Path() final; + string Relocate(TNetStorageFlags flags, TNetStorageProgressCb cb) final; + bool Exists() final; + ENetStorageRemoveResult Remove() final; +}; + +/// @internal +struct NCBI_XCONNECT_EXPORT SNetStorageObjectIState : public SNetStorageObjectIoState +{ + ERW_Result Write(const void* buf, size_t count, size_t* written) final; + ERW_Result Flush() final; +}; + +/// @internal +struct NCBI_XCONNECT_EXPORT SNetStorageObjectOState : public SNetStorageObjectIoState +{ + ERW_Result Read(void* buf, size_t count, size_t* read) final; + ERW_Result PendingCount(size_t* count) final; + bool Eof() final; }; +/// @internal +struct NCBI_XCONNECT_EXPORT SNetStorageObjectIoMode +{ + enum EApi { eAnyApi, eBuffer, eIoStream, eIReaderIWriter, eString }; + enum EMth { eAnyMth, eRead, eWrite, eEof }; + + bool Set(EApi api, EMth mth) + { + if (m_Api != eAnyApi && m_Api != api) return false; + + m_Api = api; + m_Mth = mth; + return true; + } + + void Reset() { m_Api = eAnyApi; } + bool IoStream() const { return m_Api == eIoStream; } + void Throw(EApi api, EMth mth, string object_loc); + +private: + static string ToString(EApi api, EMth mth); + + EApi m_Api = eAnyApi; + EMth m_Mth = eAnyMth; +}; + +/// @internal +struct NCBI_XCONNECT_EXPORT SNetStorageObjectImpl : public CObject +{ + ~SNetStorageObjectImpl(); + + void SetStartState(INetStorageObjectState* state); + + void SetIoMode(SNetStorageObjectIoMode::EApi api, SNetStorageObjectIoMode::EMth mth) + { + if (!m_IoMode.Set(api, mth)) m_IoMode.Throw(api, mth, m_Current->GetLoc()); + } + + IEmbeddedStreamReaderWriter& GetReaderWriter(); + CNcbiIostream* GetRWStream(); + + INetStorageObjectState* operator->() { _ASSERT(m_Current); return m_Current; } + const INetStorageObjectState* operator->() const { _ASSERT(m_Current); return m_Current; } + + void Close(); + + template + static SNetStorageObjectImpl* Create(TArgs&&... args) + { + return CreateAndStart([](TState&){}, std::forward(args)...); + } + + template + static SNetStorageObjectImpl* CreateAndStart(TStarter starter, TArgs&&... args) + { + unique_ptr fsm(new SNetStorageObjectImpl()); + auto state = new SNetStorageObjectState(*fsm, *fsm, std::forward(args)...); + fsm->SetStartState(state); + starter(*state); + return fsm.release(); + } + +private: + void EnterState(INetStorageObjectState* state); + void ExitState(); + + unique_ptr m_ReaderWriter; + unique_ptr m_IoStreamReaderWriter; + unique_ptr m_Start; + INetStorageObjectState* m_Previous = nullptr; + INetStorageObjectState* m_Current = nullptr; + SNetStorageObjectIoMode m_IoMode; + + friend struct INetStorageObjectState; +}; + +inline void SNetStorageObjectImpl::SetStartState(INetStorageObjectState* state) +{ + _ASSERT(state); + _ASSERT(!m_Start); + m_Start.reset(state); + m_Current = state; +} + +inline void SNetStorageObjectImpl::EnterState(INetStorageObjectState* state) +{ + _ASSERT(state); + m_Previous = m_Current; + m_Current = state; +} + +inline void SNetStorageObjectImpl::ExitState() +{ + _ASSERT(m_Previous); + m_Current = m_Previous; + m_Previous = nullptr; +} + +inline void INetStorageObjectState::EnterState(INetStorageObjectState* state) +{ + Fsm().EnterState(state); +} + +inline void INetStorageObjectState::ExitState() +{ + Fsm().ExitState(); +} + /// @internal struct NCBI_XCONNECT_EXPORT SNetStorage { @@ -109,6 +270,8 @@ struct NCBI_XCONNECT_EXPORT SNetStorage::SConfig string metadata; EDefaultStorage default_storage; EErrMode err_mode; + string ticket; + string hello_service; SConfig() : default_storage(eUndefined), err_mode(eLog) {} void ParseArg(const string&, const string&); @@ -169,7 +332,7 @@ struct NCBI_XCONNECT_EXPORT SNetStorage::SLimits { static string Name() { return "Attribute value"; } static size_t MaxLength() { return 900; } - static bool IsValid(char c) { return true; }; + static bool IsValid(char) { return true; }; }; struct SClientName @@ -215,15 +378,8 @@ struct NCBI_XCONNECT_EXPORT SNetStorageImpl : public CObject { typedef SNetStorage::SConfig TConfig; - virtual CNetStorageObject Create(TNetStorageFlags flags) = 0; - virtual CNetStorageObject Open(const string& object_loc) = 0; - virtual string Relocate(const string& object_loc, - TNetStorageFlags flags, TNetStorageProgressCb cb) = 0; - virtual bool Exists(const string& object_loc) = 0; - virtual ENetStorageRemoveResult Remove(const string& object_loc) = 0; -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - virtual void AllowXSiteConnections() {} -#endif + virtual SNetStorageObjectImpl* Create(TNetStorageFlags flags) = 0; + virtual SNetStorageObjectImpl* Open(const string& object_loc) = 0; }; /// @internal @@ -231,17 +387,7 @@ struct NCBI_XCONNECT_EXPORT SNetStorageByKeyImpl : public CObject { typedef SNetStorage::SConfig TConfig; - virtual CNetStorageObject Open(const string& unique_key, - TNetStorageFlags flags) = 0; - virtual string Relocate(const string& unique_key, - TNetStorageFlags flags, TNetStorageFlags old_flags, - TNetStorageProgressCb cb) = 0; - virtual bool Exists(const string& key, TNetStorageFlags flags) = 0; - virtual ENetStorageRemoveResult Remove(const string& key, - TNetStorageFlags flags) = 0; -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - virtual void AllowXSiteConnections() {} -#endif + virtual SNetStorageObjectImpl* Open(const string& unique_key, TNetStorageFlags flags) = 0; }; #define NETSTORAGE_CONVERT_NETCACHEEXCEPTION(message) \ diff --git a/c++/include/connect/services/impl/netstorage_int.hpp b/c++/include/connect/services/impl/netstorage_int.hpp index e754b99a..5b925627 100644 --- a/c++/include/connect/services/impl/netstorage_int.hpp +++ b/c++/include/connect/services/impl/netstorage_int.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES_IMPL__NETSTORAGE_INT__HPP #define CONNECT_SERVICES_IMPL__NETSTORAGE_INT__HPP -/* $Id: netstorage_int.hpp 498620 2016-04-18 16:34:28Z sadyrovr $ +/* $Id: netstorage_int.hpp 526283 2017-02-01 17:57:08Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -80,36 +80,13 @@ public: EFileTrackSite ft_site); CNetStorageObjectLoc(CCompoundIDPool::TInstance cid_pool, const string& object_loc); - CNetStorageObjectLoc(CCompoundIDPool::TInstance cid_pool, - const string& object_loc, TNetStorageAttrFlags flags); - - void SetObjectID(Uint8 object_id) - { - m_LocatorFlags &= ~(TLocatorFlags) fLF_NoMetaData; - m_LocatorFlags |= fLF_HasObjectID; - m_ObjectID = object_id; - if ((m_LocatorFlags & fLF_HasUserKey) == 0) { - m_ShortUniqueKey = MakeShortUniqueKey(); - m_UniqueKey = MakeUniqueKey(); - } - m_Dirty = true; - } - void SetServiceName(const string& service_name) - { - if (service_name.empty() || - strchr(service_name.c_str(), ':') != NULL) - ClearLocatorFlags(fLF_NetStorageService); - else { - m_ServiceName = service_name; - SetLocatorFlags(fLF_NetStorageService); - } - m_Dirty = true; - } + void SetServiceName(const string& service_name); bool HasServiceName() const {return m_LocatorFlags & fLF_NetStorageService;} string GetServiceName() const {return m_ServiceName;} + static string GetServiceName(CCompoundID cid); ENetStorageObjectLocation GetLocation() const {return m_Location;} @@ -129,17 +106,10 @@ public: // This contains both of the above string GetUniqueKey() const {return m_UniqueKey;} - void SetLocation_NetCache(const string& service_name, - bool allow_xsite_conn); + void SetLocation(const string& nc_service_name); string GetNCServiceName() const {return m_NCServiceName;} - bool IsXSiteProxyAllowed() const - { - return (m_NCFlags & fNCF_AllowXSiteConn) != 0; - } - - void SetLocation_FileTrack(EFileTrackSite ft_site); EFileTrackSite GetFileTrackSite() const; string GetLocator() const @@ -150,6 +120,7 @@ public: } TNetStorageAttrFlags GetStorageAttrFlags() const; + void SetStorageAttrFlags(TNetStorageAttrFlags flags); // Serialize to a JSON object. void ToJSON(CJsonNode& root) const; @@ -179,12 +150,8 @@ private: }; typedef unsigned TLocatorFlags; - enum ENetCacheFlags { - fNCF_AllowXSiteConn = (1 << 0), - }; - typedef unsigned TNetCacheFlags; - - void Parse(const string& object_loc); + CNetStorageObjectLoc() : m_CompoundIDPool(eVoid) {} + void Parse(CCompoundID cid, bool service_name_only); string MakeShortUniqueKey() const; string MakeUniqueKey() const { return m_AppDomain + '-' + m_ShortUniqueKey; } @@ -200,11 +167,12 @@ private: TLocatorFlags m_LocatorFlags; - Uint8 m_ObjectID; + // Not used, but still supported (for backward compatibility) + Uint8 m_ObjectID = 0; string m_ServiceName; string m_LocationCode; - ENetStorageObjectLocation m_Location; + ENetStorageObjectLocation m_Location = eNFL_Unknown; string m_AppDomain; @@ -216,7 +184,6 @@ private: // The same as above plus app domain string m_UniqueKey; - TNetCacheFlags m_NCFlags; string m_NCServiceName; mutable bool m_Dirty; @@ -275,14 +242,13 @@ class NCBI_XCONNECT_EXPORT CNetStorageAdmin CJsonNode ExchangeJson(const CJsonNode& request, CNetServer::TInstance server_to_use = NULL, CNetServerConnection* conn = NULL); -}; -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT -/// @internal -NCBI_XCONNECT_EXPORT -void g_AllowXSiteConnections(CNetStorage&); -void g_AllowXSiteConnections(CNetStorageByKey&); -#endif + CNetStorageAdmin GetServer(CNetServer::TInstance server); + + void SetEventHandler(INetEventHandler* event_handler); + + CNetStorageObject Open(const string& object_loc); +}; END_NCBI_SCOPE diff --git a/c++/include/connect/services/json_over_uttp.hpp b/c++/include/connect/services/json_over_uttp.hpp index a3350d41..fd4ba1dd 100644 --- a/c++/include/connect/services/json_over_uttp.hpp +++ b/c++/include/connect/services/json_over_uttp.hpp @@ -1,7 +1,7 @@ #ifndef JSON_OVER_UTTP__HPP #define JSON_OVER_UTTP__HPP -/* $Id: json_over_uttp.hpp 502215 2016-05-23 15:27:45Z sadyrovr $ +/* $Id: json_over_uttp.hpp 513823 2016-09-15 16:59:10Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -80,16 +80,16 @@ class NCBI_XCONNECT_EXPORT CJsonNode static CJsonNode NewArrayNode(); /// Create a new JSON string node. - static CJsonNode NewStringNode(const string& value); + static CJsonNode NewStringNode(const string& value) { return value; } /// Create a new JSON integer node. - static CJsonNode NewIntegerNode(Int8 value); + static CJsonNode NewIntegerNode(Int8 value) { return value; } /// Create a new JSON double node. - static CJsonNode NewDoubleNode(double value); + static CJsonNode NewDoubleNode(double value) { return value; } /// Create a new JSON boolean node. - static CJsonNode NewBooleanNode(bool value); + static CJsonNode NewBooleanNode(bool value) { return value; } /// Create a new JSON null node. static CJsonNode NewNullNode(); @@ -99,6 +99,20 @@ class NCBI_XCONNECT_EXPORT CJsonNode /// node with this value. static CJsonNode GuessType(const CTempString& value); + /// Create new JSON string node. + CJsonNode(const string& value); + CJsonNode(const char* value); + + /// Create new JSON integer node. + CJsonNode(int value); + CJsonNode(Int8 value); + + /// Create new JSON double node. + CJsonNode(double value); + + /// Create new JSON boolean node. + CJsonNode(bool value); + /// JSON node type. enum ENodeType { eObject, @@ -110,9 +124,15 @@ class NCBI_XCONNECT_EXPORT CJsonNode eNull }; + /// Create new JSON node (type depends on the argument) + CJsonNode(ENodeType type); + /// Return a ENodeType constant identifying the node type. ENodeType GetNodeType() const; + /// Return a string identifying the node type. + string GetTypeName() const; + /// Return true for a JSON object. Return false otherwise. bool IsObject() const; diff --git a/c++/include/connect/services/netcache_admin.hpp b/c++/include/connect/services/netcache_admin.hpp index ea821d67..a7ce8e9f 100644 --- a/c++/include/connect/services/netcache_admin.hpp +++ b/c++/include/connect/services/netcache_admin.hpp @@ -1,7 +1,7 @@ #ifndef CONN___NETCACHE_ADMIN__HPP #define CONN___NETCACHE_ADMIN__HPP -/* $Id: netcache_admin.hpp 450470 2014-10-27 18:24:02Z sadyrovr $ +/* $Id: netcache_admin.hpp 525552 2017-01-25 16:20:18Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/connect/services/netcache_api.hpp b/c++/include/connect/services/netcache_api.hpp index c04730b6..4cad150f 100644 --- a/c++/include/connect/services/netcache_api.hpp +++ b/c++/include/connect/services/netcache_api.hpp @@ -1,7 +1,7 @@ #ifndef CONN___NETCACHE_API__HPP #define CONN___NETCACHE_API__HPP -/* $Id: netcache_api.hpp 481318 2015-10-08 15:54:01Z sadyrovr $ +/* $Id: netcache_api.hpp 525579 2017-01-25 17:33:11Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -590,15 +590,6 @@ class NCBI_XCONNECT_EXPORT CNetCacheAPI /// @see nc_cache_name typedef CNamedParameter TCacheName; - /// @deprecated Please use PutData(key, buf, size, optional) instead. - NCBI_DEPRECATED string PutData(const string& key, - const void* buf, - size_t size, - int blob_ttl) - { - return PutData(key, buf, size, nc_blob_ttl = blob_ttl); - } - /// Extract one of the servers comprising this service /// as a separate CNetCacheAPI object. /// This method is for use by the grid_cli utility only. @@ -697,11 +688,6 @@ private: CBlobStorage_NetCache& operator=(CBlobStorage_NetCache&); }; -/// @internal -NCBI_XCONNECT_EXPORT -ERW_Result g_ReadFromNetCache(IReader* reader, - char* buf, size_t count, size_t* bytes_read); - /* @} */ END_NCBI_SCOPE diff --git a/c++/include/connect/services/netcache_search.hpp b/c++/include/connect/services/netcache_search.hpp index fd525cbd..b7f0b94f 100644 --- a/c++/include/connect/services/netcache_search.hpp +++ b/c++/include/connect/services/netcache_search.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES___NETCACHE_SEARCH__HPP #define CONNECT_SERVICES___NETCACHE_SEARCH__HPP -/* $Id: netcache_search.hpp 520438 2016-11-28 18:35:31Z ivanov $ +/* $Id: netcache_search.hpp 520145 2016-11-22 23:45:16Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/connect/services/netcomponent.hpp b/c++/include/connect/services/netcomponent.hpp index 24f58405..d843965c 100644 --- a/c++/include/connect/services/netcomponent.hpp +++ b/c++/include/connect/services/netcomponent.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES__NET_OBJECT_HPP #define CONNECT_SERVICES__NET_OBJECT_HPP -/* $Id: netcomponent.hpp 501217 2016-05-12 14:34:55Z vasilche $ +/* $Id: netcomponent.hpp 528566 2017-02-23 18:35:51Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -80,9 +80,15 @@ public: } }; +template +using CNetRef = CRef>; + +template inline S& operator--( CNetRef& r, int) { return r.GetObject(); } +template inline const S& operator--(const CNetRef& r, int) { return r.GetObject(); } + #define NCBI_NET_COMPONENT_DEF(Class, Impl) \ protected: \ - CRef > m_Impl; \ + CNetRef m_Impl; \ public: \ typedef Impl* TInstance; \ Class(EVoid) {} \ @@ -90,6 +96,8 @@ public: Class& operator =(Impl* impl) { m_Impl = impl; return *this; } \ operator Impl*() { return m_Impl.GetPointer(); } \ operator const Impl*() const { return m_Impl.GetPointer(); } \ + Impl& operator --(int) { return m_Impl.GetObject(); } \ + const Impl& operator --(int) const { return m_Impl.GetObject(); } \ Impl* operator ->() { return m_Impl.GetPointer(); } \ const Impl* operator ->() const { return m_Impl.GetPointer(); } diff --git a/c++/include/connect/services/neticache_client.hpp b/c++/include/connect/services/neticache_client.hpp index 35735908..56bb714b 100644 --- a/c++/include/connect/services/neticache_client.hpp +++ b/c++/include/connect/services/neticache_client.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES___NETICACHE_CLIENT__HPP #define CONNECT_SERVICES___NETICACHE_CLIENT__HPP -/* $Id: neticache_client.hpp 520437 2016-11-28 18:35:09Z ivanov $ +/* $Id: neticache_client.hpp 526445 2017-02-02 19:51:15Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -147,10 +147,6 @@ class NCBI_NET_CACHE_EXPORT CNetICacheClient : public ICache const string& subkey, string* owner); - /// Returns a list of subkeys for a given key - /// - list GetSubkeyList(const string& key); - typedef grid::netcache::search::CBlobInfo CBlobInfo; typedef grid::netcache::search::CExpression CExpression; typedef grid::netcache::search::CFields CFields; @@ -193,21 +189,6 @@ class NCBI_NET_CACHE_EXPORT CNetICacheClient : public ICache void* buf, size_t buf_size); - /// @deprecated Use GetReadStream() variant with optional argument list. - /// - /// Read a lengthy blob via the IReader interface. The Read() method - /// of the returned implementation is not blocking. The caller - /// must provide a reading completion loop for the Read() call. - /// @see CNetCacheAPI::GetReader() for an example. - NCBI_DEPRECATED - IReader* GetReadStream( - const string& key, - int version, - const string& subkey, - size_t* blob_size_ptr, - CNetCacheAPI::ECachingMode caching_mode, - CNetServer::TInstance server_to_use = NULL); - /// Read a lengthy blob via the IReader interface. The Read() method /// of the returned implementation is not blocking. The caller /// must provide a reading completion loop for the Read() call. @@ -361,6 +342,15 @@ class NCBI_NET_CACHE_EXPORT CNetICacheClient : public ICache /// This method is for use by the grid_cli utility only. /// @internal void SetEventHandler(INetEventHandler* event_handler); + + /// @deprecated Use Search() instead + NCBI_DEPRECATED list GetSubkeyList(const string& key) + { + using namespace ncbi::grid::netcache::search; + list r; + for (auto& i : Search(fields::key == key)) r.push_back(i[fields::subkey]); + return r; + } }; extern NCBI_NET_CACHE_EXPORT const char* const kNetICacheDriverName; diff --git a/c++/include/connect/services/netschedule_api.hpp b/c++/include/connect/services/netschedule_api.hpp index efb08ae5..236dfaa1 100644 --- a/c++/include/connect/services/netschedule_api.hpp +++ b/c++/include/connect/services/netschedule_api.hpp @@ -1,7 +1,7 @@ #ifndef CONN___NETSCHEDULE_API__HPP #define CONN___NETSCHEDULE_API__HPP -/* $Id: netschedule_api.hpp 507304 2016-07-18 16:15:49Z sadyrovr $ +/* $Id: netschedule_api.hpp 537163 2017-05-26 15:32:47Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -289,6 +289,7 @@ class NCBI_XCONNECT_EXPORT CNetScheduleAPI eWarnQueueAlreadyPaused, eWarnQueueNotPaused, eWarnCommandObsolete, + eWarnJobNotRead, }; static ENetScheduleWarningType ExtractWarningType(string& warn_msg); static const char* WarningTypeToString( @@ -377,6 +378,8 @@ struct CNetScheduleJob : CNetScheduleNewJob /// The server the job belongs to. CNetServer server; + + pair submitter; }; struct SNetScheduleSubmitterImpl; @@ -640,32 +643,6 @@ class NCBI_XCONNECT_EXPORT CNetScheduleExecutor unsigned wait_time, const string& affinity_list = kEmptyStr); - /// @deprecated - /// Use GetJob() instead. - /// - /// Wait for a new job in the queue. - /// - /// @param job - /// NetSchedule job description structure - /// - /// @param wait_time - /// Time in seconds function waits for new jobs to arrive. - /// If there are no jobs in the period of time, - /// the function returns FALSE. - /// - /// @param affinity_list - /// Comma-separated list of affinity tokens. - /// - /// @sa GetJob - /// - NCBI_DEPRECATED - bool WaitJob(CNetScheduleJob& job, unsigned wait_time, - const string& affinity_list = kEmptyStr) - { - return GetJob(job, wait_time, affinity_list); - } - - /// Put job result (job should be received by GetJob() or WaitJob()) /// /// @param job @@ -742,17 +719,6 @@ class NCBI_XCONNECT_EXPORT CNetScheduleExecutor time_t* job_exptime = NULL, ENetScheduleQueuePauseMode* pause_mode = NULL); - NCBI_DEPRECATED - CNetScheduleAPI::EJobStatus GetJobStatus( - const string& job_key, - time_t* job_exptime = NULL, - ENetScheduleQueuePauseMode* pause_mode = NULL) - { - CNetScheduleJob job; - job.job_id = job_key; - return GetJobStatus(job, job_exptime, pause_mode); - } - /// Switch the job back to the "Pending" status so that it can be /// run again on a different worker node. /// @@ -813,18 +779,6 @@ class NCBI_XCONNECT_EXPORT CNetScheduleJobReader { NCBI_NET_COMPONENT(NetScheduleJobReader); - /// @deprecated - /// Use GetJobReader(group, ...) instead. - /// - NCBI_DEPRECATED - void SetJobGroup(const string& group_name); - - /// @deprecated - /// Use GetJobReader(..., affinity) instead. - /// - NCBI_DEPRECATED - void SetAffinity(const string& affinity); - /// Possible outcomes of ReadNextJob() calls. enum EReadNextJobResult { eRNJ_JobReady, ///< A job is returned. diff --git a/c++/include/connect/services/netservice_api.hpp b/c++/include/connect/services/netservice_api.hpp index 4644f782..452a5b77 100644 --- a/c++/include/connect/services/netservice_api.hpp +++ b/c++/include/connect/services/netservice_api.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES___NETSERVICE_API__HPP #define CONNECT_SERVICES___NETSERVICE_API__HPP -/* $Id: netservice_api.hpp 484796 2015-11-16 14:47:31Z sadyrovr $ +/* $Id: netservice_api.hpp 514890 2016-09-26 19:05:36Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -136,8 +136,8 @@ class NCBI_XCONNECT_EXPORT CNetService CNetService Clone(const string& name); #ifdef NCBI_GRID_XSITE_CONN_SUPPORT - void AllowXSiteConnections(); - bool IsUsingXSiteProxy(); + static void AllowXSiteConnections(); + static bool IsUsingXSiteProxy(); #endif }; diff --git a/c++/include/connect/services/netstorage.hpp b/c++/include/connect/services/netstorage.hpp index 889bde93..0d56cf79 100644 --- a/c++/include/connect/services/netstorage.hpp +++ b/c++/include/connect/services/netstorage.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES__NETSTORAGE__HPP #define CONNECT_SERVICES__NETSTORAGE__HPP -/* $Id: netstorage.hpp 505855 2016-06-29 16:17:14Z sadyrovr $ +/* $Id: netstorage.hpp 530038 2017-03-09 20:41:02Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -155,13 +155,20 @@ typedef unsigned TNetStorageFlags; ///< Bitwise OR of ENetStorageFlags /// Sequential I/O only /// Can switch between reading and writing but only explicitly, using Close() /// +/// @warning Different I/O intefaces cannot be used at the same time. +/// E.g. calls to Write(buf) and Write(string) cannot be mixed. +/// Different IO can be used after calling Close(). +/// +/// @warning Once I/O started non-I/O methods cannot be called until Close() is called. +/// E.g. calls to Write() and GetSize() cannot be mixed. +/// class NCBI_XCONNECT_EXPORT CNetStorageObject { NCBI_NET_COMPONENT(NetStorageObject); /// Return object locator - string GetLoc(void); + string GetLoc(void) const; /// Read no more than 'buf_size' bytes of the object contents /// (starting at the current position) @@ -248,6 +255,8 @@ class NCBI_XCONNECT_EXPORT CNetStorageObject /// NetStorage object as well as storing data into this object. /// The returned iostream object must be deleted by the caller. /// + /// @warning Empty writes are ignored by the returned iostream instance! + /// CNcbiIostream* GetRWStream(); /// Write string to the object (starting at the current position) @@ -449,10 +458,6 @@ class NCBI_XCONNECT_EXPORT CNetStorage /// File to remove /// ENetStorageRemoveResult Remove(const string& object_loc); - - /// @deprecated To change flags use Relocate(object_loc, flags) instead. - NCBI_DEPRECATED - CNetStorageObject Open(const string& object_loc, TNetStorageFlags flags); }; diff --git a/c++/include/connect/services/ns_output_parser.hpp b/c++/include/connect/services/ns_output_parser.hpp index e88ad446..d2382fce 100644 --- a/c++/include/connect/services/ns_output_parser.hpp +++ b/c++/include/connect/services/ns_output_parser.hpp @@ -1,4 +1,4 @@ -/* $Id: ns_output_parser.hpp 502472 2016-05-24 21:38:49Z sadyrovr $ +/* $Id: ns_output_parser.hpp 526440 2017-02-02 19:21:30Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,31 +33,9 @@ #define CONNECT__SERVICES__NS_OUTPUT_PARSER__HPP #include "netschedule_api.hpp" -#include "json_over_uttp.hpp" BEGIN_NCBI_SCOPE - -// Deprecated, use corresponding static method of CJsonNode instead -class NCBI_DEPRECATED NCBI_XCONNECT_EXPORT CNetScheduleStructuredOutputParser -{ -public: - CJsonNode ParseObject(const string& ns_output) - { - return CJsonNode::ParseObject(ns_output); - } - - CJsonNode ParseArray(const string& ns_output) - { - return CJsonNode::ParseArray(ns_output); - } - - CJsonNode ParseJSON(const string& json) - { - return CJsonNode::ParseJSON(json); - } -}; - class NCBI_XCONNECT_EXPORT CAttrListParser { public: diff --git a/c++/include/connect/services/remote_app.hpp b/c++/include/connect/services/remote_app.hpp index 01f9ae63..8084506b 100644 --- a/c++/include/connect/services/remote_app.hpp +++ b/c++/include/connect/services/remote_app.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES__REMOTE_APP_MB_HPP #define CONNECT_SERVICES__REMOTE_APP_MB_HPP -/* $Id: remote_app.hpp 478906 2015-09-14 20:38:33Z sadyrovr $ +/* $Id: remote_app.hpp 537183 2017-05-26 17:52:46Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,6 +33,7 @@ */ #include +#include #include @@ -75,9 +76,8 @@ protected: private: CNetCacheAPI m_Storage; - auto_ptr m_IStream; - auto_ptr m_Writer; - auto_ptr m_OStream; + SGridRead m_GridRead; + SGridWrite m_GridWrite; string* m_Data; size_t* m_DataSize; }; diff --git a/c++/include/connect/services/srv_connections.hpp b/c++/include/connect/services/srv_connections.hpp index ae454270..e240e214 100644 --- a/c++/include/connect/services/srv_connections.hpp +++ b/c++/include/connect/services/srv_connections.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES__SERVER_CONN_HPP_1 #define CONNECT_SERVICES__SERVER_CONN_HPP_1 -/* $Id: srv_connections.hpp 485565 2015-11-23 19:43:31Z sadyrovr $ +/* $Id: srv_connections.hpp 533175 2017-04-13 16:36:32Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -46,7 +46,7 @@ struct SNetServerImpl; ///< @internal struct SNetServerConnectionImpl; ///< @internal struct SNetServerInfoImpl; ///< @internal struct SNetServerMultilineCmdOutputImpl; ///< @internal -class INetServerConnectionListener; ///< @internal +struct INetServerConnectionListener; ///< @internal /////////////////////////////////////////////////////////////////////////// // @@ -73,6 +73,12 @@ public: virtual void Abort() = 0; }; +/////////////////////////////////////////////////////////////////////////// +// +class NCBI_XCONNECT_EXPORT IEmbeddedStreamReaderWriter : public IReader, public IEmbeddedStreamWriter +{ +}; + /////////////////////////////////////////////////////////////////////////// // class NCBI_XCONNECT_EXPORT CNetServerInfo diff --git a/c++/include/connect/services/util.hpp b/c++/include/connect/services/util.hpp index 78433dd3..cb4ba9c9 100644 --- a/c++/include/connect/services/util.hpp +++ b/c++/include/connect/services/util.hpp @@ -1,4 +1,4 @@ -/* $Id: util.hpp 435870 2014-05-21 15:11:19Z kazimird $ +/* $Id: util.hpp 525330 2017-01-23 18:16:35Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -76,24 +76,6 @@ string g_NetService_gethostip(const string& ip_or_hostname); extern NCBI_XCONNECT_EXPORT string g_NetService_TryResolveHost(const string& ip_or_hostname); - -enum ECharacterClass { - eCC_Alphabetic, - eCC_Alphanumeric, - eCC_StrictId, - eCC_BASE64URL, - eCC_BASE64_PI, - eCC_RelaxedId -}; - -extern NCBI_XCONNECT_EXPORT -bool g_CheckAlphabet(const string& str, const CTempString& param_name, - ECharacterClass char_class, char* bad_char); - -extern NCBI_XCONNECT_EXPORT -void g_VerifyAlphabet(const string& str, const CTempString& param_name, - ECharacterClass char_class); - #define TEMP_STRING_CTOR(str) CTempString(str, sizeof(str) - 1) END_NCBI_SCOPE diff --git a/c++/include/corelib/error_codes.hpp b/c++/include/corelib/error_codes.hpp index 880a428a..53b8a15c 100644 --- a/c++/include/corelib/error_codes.hpp +++ b/c++/include/corelib/error_codes.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___ERROR_CODES__HPP #define CORELIB___ERROR_CODES__HPP -/* $Id: error_codes.hpp 473240 2015-07-17 16:27:42Z grichenk $ +/* $Id: error_codes.hpp 529123 2017-03-01 16:03:27Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -48,7 +48,7 @@ NCBI_DEFINE_ERRCODE_X(Corelib_Static, 104, 1); NCBI_DEFINE_ERRCODE_X(Corelib_System, 105, 13); NCBI_DEFINE_ERRCODE_X(Corelib_App, 106, 21); NCBI_DEFINE_ERRCODE_X(Corelib_Diag, 107, 29); -NCBI_DEFINE_ERRCODE_X(Corelib_File, 108, 4); +NCBI_DEFINE_ERRCODE_X(Corelib_File, 108, 89); NCBI_DEFINE_ERRCODE_X(Corelib_Object, 109, 15); NCBI_DEFINE_ERRCODE_X(Corelib_Reg, 110, 8); NCBI_DEFINE_ERRCODE_X(Corelib_Util, 111, 6); diff --git a/c++/include/corelib/impl/ncbi_dbsvcmapper.hpp b/c++/include/corelib/impl/ncbi_dbsvcmapper.hpp index d4b0a2c9..88f29ec5 100644 --- a/c++/include/corelib/impl/ncbi_dbsvcmapper.hpp +++ b/c++/include/corelib/impl/ncbi_dbsvcmapper.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___DB_SERVICE_MAPPER__HPP #define CORELIB___DB_SERVICE_MAPPER__HPP -/* $Id: ncbi_dbsvcmapper.hpp 501812 2016-05-18 22:51:45Z ucko $ +/* $Id: ncbi_dbsvcmapper.hpp 548840 2017-10-18 15:12:11Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -77,7 +77,7 @@ public: protected: virtual CObject* x_GetUserData(void) const = 0; - virtual void x_RecordServer(const CDBServer& server) { } + virtual void x_RecordServer(const CDBServer&) { } private: friend class IDBServiceMapper; @@ -115,6 +115,44 @@ private: }; typedef CRef TSvrRef; +/// CDBServerOption -- CDBServer extended with additional information +/// that helps maintain a balanced pool of connections. Rankings are +/// relative; what matters there is the ratios between rankings +/// obtained together. Some rankings may be zero as long as the total +/// isn't. +class CDBServerOption : public CDBServer +{ +public: + enum EState { + fState_Penalized = 1 << 0, ///< Penalized by the load balancer + fState_Excluded = 1 << 1, ///< Excluded by DBAPI + fState_Normal = 0 ///< Fully available + }; + DECLARE_SAFE_FLAGS_TYPE(EState, TState); + + CDBServerOption(const string& name, + Uint4 host, + Uint2 port, + double ranking, + TState state = fState_Normal, + unsigned int expire_time = 0) + : CDBServer(name, host, port, expire_time), + m_Ranking(ranking), m_State(state) + { } + + double GetRanking (void) const { return m_Ranking; } + TState GetState (void) const { return m_State; } + bool IsPenalized(void) const { return (m_State & fState_Penalized) != 0; } + bool IsExcluded (void) const { return (m_State & fState_Excluded) != 0; } + bool IsNormal (void) const { return m_State == fState_Normal; } + +private: + double m_Ranking; + TState m_State; +}; + +DECLARE_SAFE_FLAGS(CDBServerOption::EState); + /////////////////////////////////////////////////////////////////////////////// /// IDBServiceMapper /// @@ -123,6 +161,7 @@ class IDBServiceMapper : public CObject { public: typedef IDBServiceMapper* (*TFactory)(const IRegistry* registry); + typedef list > TOptions; struct SDereferenceLess { @@ -151,11 +190,17 @@ public: virtual void CleanExcluded(const string& service) = 0; /// Get list of all servers for the given service disregarding any exclusions - virtual void GetServersList(const string& service, list* serv_list) const + virtual void GetServersList(const string& /* service */, + list* serv_list) const { serv_list->clear(); } + /// Get an annotated list of all servers for the given service. + /// The default implementation just pads out the results of + /// calling GetServersList, which predates this method and as such + /// is likelier to be defined by derived classes. + virtual void GetServerOptions(const string& service, TOptions* options); /// Set up mapping preferences for a service /// preference - value between 0 and 100 @@ -172,7 +217,7 @@ public: /// low-level handle (if available); on success, pass the result /// to its x_RecordServer method to inform subsequent logging. /// @return true if successful, false otherwise. - virtual bool RecordServer(I_ConnectionExtra& extra) const { return false; } + virtual bool RecordServer(I_ConnectionExtra&) const { return false; } protected: static void x_RecordServer(I_ConnectionExtra& extra, CDBServer& server) @@ -201,6 +246,17 @@ string IDBServiceMapper::GetName(void) const return CDBServiceMapperTraits::GetName(); } +inline +void IDBServiceMapper::GetServerOptions(const string& name, TOptions* options) +{ + list servers; + GetServersList(name, &servers); + options->clear(); + for (const string& it : servers) { + options->emplace_back(new CDBServerOption(it, 0, 0, 1.0)); + } +} + /////////////////////////////////////////////////////////////////////////////// inline diff --git a/c++/include/corelib/impl/rwstreambuf.hpp b/c++/include/corelib/impl/rwstreambuf.hpp index 706cc903..278ee001 100644 --- a/c++/include/corelib/impl/rwstreambuf.hpp +++ b/c++/include/corelib/impl/rwstreambuf.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___RWSTREAMBUF__HPP #define CORELIB___RWSTREAMBUF__HPP -/* $Id: rwstreambuf.hpp 463752 2015-04-01 14:15:52Z lavr $ +/* $Id: rwstreambuf.hpp 530261 2017-03-13 17:05:56Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -101,7 +101,11 @@ protected: /// Note: setbuf(0, 0) has no effect virtual CNcbiStreambuf* setbuf(CT_CHAR_TYPE* buf, streamsize buf_size); - // only seekoff(0, IOS_BASE::cur, *) is permitted + /// Only seekoff(0, IOS_BASE::cur, *) to obtain current position, and input + /// skip-forward are permitted: + /// seekoff(off, IOS_BASE::cur or IOS_BASE::beg, IOS_BASE::in) when the + /// requested stream position is past the current input position (so the + // stream can read forward internally to reach that position). virtual CT_POS_TYPE seekoff(CT_OFF_TYPE off, IOS_BASE::seekdir whence, IOS_BASE::openmode which = IOS_BASE::in | IOS_BASE::out); @@ -119,10 +123,12 @@ protected: CT_POS_TYPE x_GetPPos(void) { return x_PPos + (CT_OFF_TYPE)(pbase() ? pbase() - pptr() : 0); } - int x_sync(void) + int x_Sync(void) { return pbase() < pptr() ? sync() : 0; } - ERW_Result x_pushback(void); + streamsize x_Read(CT_CHAR_TYPE* s, streamsize n); + + ERW_Result x_Pushback(void); protected: TFlags m_Flags; diff --git a/c++/include/corelib/ncbi_cookies.hpp b/c++/include/corelib/ncbi_cookies.hpp index e7039164..a22588b8 100644 --- a/c++/include/corelib/ncbi_cookies.hpp +++ b/c++/include/corelib/ncbi_cookies.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBI_COOKIES__HPP #define CORELIB___NCBI_COOKIES__HPP -/* $Id: ncbi_cookies.hpp 517040 2016-10-20 11:22:39Z ivanov $ +/* $Id: ncbi_cookies.hpp 516788 2016-10-18 13:03:49Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/corelib/ncbi_process.hpp b/c++/include/corelib/ncbi_process.hpp index 4682eab2..e310c876 100644 --- a/c++/include/corelib/ncbi_process.hpp +++ b/c++/include/corelib/ncbi_process.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBI_PROCESS__HPP #define CORELIB___NCBI_PROCESS__HPP -/* $Id: ncbi_process.hpp 486692 2015-12-09 12:49:29Z ivanov $ +/* $Id: ncbi_process.hpp 546770 2017-09-21 14:28:03Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -63,10 +63,14 @@ BEGIN_NCBI_SCOPE /// Infinite timeout in milliseconds. const unsigned long kInfiniteTimeoutMs = kMax_ULong; +// This workaround is obsolete now. LinuxThreads library has been replaced by NPTL +// which does not need it. +/* /// Turn on/off workaround for linux PID and PPID #if defined(NCBI_OS_LINUX) # define NCBI_THREAD_PID_WORKAROUND #endif +*/ /// Process identifier (PID) and process handle. #if defined(NCBI_OS_UNIX) @@ -536,8 +540,8 @@ public: private: string m_Path; //< File path to store PID. TPid m_PID; //< Sored PID. - auto_ptr m_MTGuard; //< MT-Safe protection guard. - auto_ptr m_PIDGuard; //< Guard to help with "PID reuse" problem. + unique_ptr m_MTGuard; //< MT-Safe protection guard. + unique_ptr m_PIDGuard; //< Guard to help with "PID reuse" problem. }; diff --git a/c++/include/corelib/ncbi_safe_static.hpp b/c++/include/corelib/ncbi_safe_static.hpp index 7831f798..fd92b3b8 100644 --- a/c++/include/corelib/ncbi_safe_static.hpp +++ b/c++/include/corelib/ncbi_safe_static.hpp @@ -1,7 +1,7 @@ #ifndef NCBI_SAFE_STATIC__HPP #define NCBI_SAFE_STATIC__HPP -/* $Id: ncbi_safe_static.hpp 488881 2016-01-06 16:49:31Z grichenk $ +/* $Id: ncbi_safe_static.hpp 530342 2017-03-14 15:08:00Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -108,9 +108,11 @@ public: ~CSafeStaticPtr_Base(void); protected: + typedef CGuard TInstanceMutexGuard; + /// Cleanup function type used by derived classes typedef void (*FSelfCleanup)(CSafeStaticPtr_Base* safe_static, - CMutexGuard& guard); + TInstanceMutexGuard& guard); /// Constructor. /// @@ -136,7 +138,42 @@ protected: /// Pointer to the data const void* m_Ptr; - DECLARE_CLASS_STATIC_MUTEX(sm_Mutex); + DECLARE_CLASS_STATIC_MUTEX(sm_ClassMutex); + +private: + friend struct SSimpleLock; + friend struct SSimpleUnlock; + + void Lock(void) + { + CMutexGuard guard(sm_ClassMutex); + if (!m_InstanceMutex || !m_MutexRefCount) { + m_InstanceMutex = new CMutex; + m_MutexRefCount = 1; + } + ++m_MutexRefCount; + guard.Release(); + m_InstanceMutex->Lock(); + } + + void Unlock(void) + { + m_InstanceMutex->Unlock(); + x_ReleaseInstanceMutex(); + } + + void x_ReleaseInstanceMutex(void) + { + CMutexGuard guard(sm_ClassMutex); + if (--m_MutexRefCount > 0) return; + // Workaround for over-optimization - member assignments done immediately + // before exiting destructor can be dropped, so mutex and counter should + // be set to 0 before deleting the mutex. + CMutex* tmp = m_InstanceMutex; + m_InstanceMutex = 0; + m_MutexRefCount = 0; + delete tmp; + } protected: friend class CSafeStatic_Less; @@ -145,6 +182,8 @@ protected: FUserCleanup m_UserCleanup; // User-provided cleanup function int m_LifeSpan; // Life span of the object int m_CreationOrder; // Creation order of the object + int m_MutexRefCount; // Mutex reference counter. + CMutex* m_InstanceMutex; // Mutex used to create/destroy value. static int x_GetCreationOrder(void); @@ -157,10 +196,15 @@ protected: // To be called by CSafeStaticGuard on the program termination friend class CSafeStaticGuard; - void x_Cleanup(CMutexGuard& guard) + void x_Cleanup(void) { - if ( m_SelfCleanup ) + // Note: x_Cleanup should always be called with sm_ClassMutex locked. + if ( m_SelfCleanup ) { + TInstanceMutexGuard guard(*this); m_SelfCleanup(this, guard); + } + // Delete instance mutex if it's not used by other threads. + x_ReleaseInstanceMutex(); } }; @@ -213,6 +257,9 @@ public: sm_Stack->insert(ptr); } + /// Disable checking on child thread(s) running during destruction + static void DisableChildThreadsCheck(); + private: // Initialize the guard, return pointer to it. static CSafeStaticGuard* x_Get(void); @@ -224,6 +271,9 @@ private: // Reference counter. The stack is destroyed when // the last reference is removed. static int sm_RefCount; + + // Whether to check on child thread(s) running during destruction + static bool sm_ChildThreadsCheck; }; @@ -410,7 +460,7 @@ private: CSafeStatic& operator=(const CSafeStatic&); void x_Init(void) { - CMutexGuard guard(sm_Mutex); + TInstanceMutexGuard guard(*this); if ( m_Ptr == 0 ) { // Create the object and register for cleanup T* ptr = 0; @@ -434,7 +484,7 @@ private: // "virtual" cleanup function static void sx_SelfCleanup(CSafeStaticPtr_Base* safe_static, - CMutexGuard& guard) + TInstanceMutexGuard& guard) { TThisType* this_ptr = static_cast(safe_static); if ( T* ptr = static_cast(const_cast(this_ptr->m_Ptr)) ) { @@ -548,7 +598,7 @@ private: // "virtual" cleanup function static void sx_SelfCleanup(CSafeStaticPtr_Base* safe_static, - CMutexGuard& guard) + TInstanceMutexGuard& guard) { CSafeStaticPtr* this_ptr = static_cast*>(safe_static); if ( T* ptr = static_cast(const_cast(this_ptr->m_Ptr)) ) { @@ -631,7 +681,7 @@ private: // "virtual" cleanup function static void sx_SelfCleanup(CSafeStaticPtr_Base* safe_static, - CMutexGuard& guard) + TInstanceMutexGuard& guard) { CSafeStaticRef* this_ptr = static_cast*>(safe_static); if ( T* ptr = static_cast(const_cast(this_ptr->m_Ptr)) ) { @@ -664,7 +714,7 @@ template inline void CSafeStaticPtr::Set(T* object) { - CMutexGuard guard(sm_Mutex); + TInstanceMutexGuard guard(*this); if ( m_Ptr == 0 ) { // Set the new object and register for cleanup if ( object ) { @@ -679,7 +729,7 @@ template inline void CSafeStaticPtr::x_Init(void) { - CMutexGuard guard(sm_Mutex); + TInstanceMutexGuard guard(*this); if ( m_Ptr == 0 ) { // Create the object and register for cleanup m_Ptr = new T; @@ -693,7 +743,7 @@ template inline void CSafeStaticPtr::x_Init(FUserCreate user_create) { - CMutexGuard guard(sm_Mutex); + TInstanceMutexGuard guard(*this); if ( m_Ptr == 0 ) { // Create the object and register for cleanup m_Ptr = user_create(); @@ -708,7 +758,7 @@ template inline void CSafeStaticRef::Set(T* object) { - CMutexGuard guard(sm_Mutex); + TInstanceMutexGuard guard(*this); if ( m_Ptr == 0 ) { // Set the new object and register for cleanup if ( object ) { @@ -724,7 +774,7 @@ template inline void CSafeStaticRef::x_Init(void) { - CMutexGuard guard(sm_Mutex); + TInstanceMutexGuard guard(*this); if ( m_Ptr == 0 ) { // Create the object and register for cleanup T* ptr = new T; @@ -740,7 +790,7 @@ template inline void CSafeStaticRef::x_Init(FUserCreate user_create) { - CMutexGuard guard(sm_Mutex); + TInstanceMutexGuard guard(*this); if ( m_Ptr == 0 ) { // Create the object and register for cleanup T* ptr = user_create(); diff --git a/c++/include/corelib/ncbi_stack.hpp b/c++/include/corelib/ncbi_stack.hpp index b9ed26c9..03cb19bb 100644 --- a/c++/include/corelib/ncbi_stack.hpp +++ b/c++/include/corelib/ncbi_stack.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBI_STACK__HPP #define CORELIB___NCBI_STACK__HPP -/* $Id: ncbi_stack.hpp 500861 2016-05-09 16:32:20Z grichenk $ +/* $Id: ncbi_stack.hpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -112,9 +112,8 @@ private: // Convert internal stack trace data (collected addresses) // to the list of SStackFrameInfo. void x_ExpandStackTrace(void) const; - - mutable auto_ptr m_Impl; - + + mutable unique_ptr m_Impl; mutable TStack m_Stack; mutable string m_Prefix; }; diff --git a/c++/include/corelib/ncbi_system.hpp b/c++/include/corelib/ncbi_system.hpp index 94e0e62c..1794e4a0 100644 --- a/c++/include/corelib/ncbi_system.hpp +++ b/c++/include/corelib/ncbi_system.hpp @@ -1,7 +1,7 @@ #ifndef NCBI_SYSTEM__HPP #define NCBI_SYSTEM__HPP -/* $Id: ncbi_system.hpp 419630 2013-11-27 13:33:28Z ivanov $ +/* $Id: ncbi_system.hpp 525410 2017-01-24 15:14:24Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -441,6 +441,12 @@ extern int GetProcessFDCount(int* soft_limit = NULL, int* hard_limit = NULL); NCBI_XNCBI_EXPORT extern int GetProcessThreadCount(void); + +/// Get process owner actual user name, doesn't use environment as it can be changed. +/// @return Actual process owner user name, or empty string if it cannot be determined. +NCBI_XNCBI_EXPORT +string GetProcessUserName(void); + END_NCBI_SCOPE #endif /* NCBI_SYSTEM__HPP */ diff --git a/c++/include/corelib/ncbi_tree.hpp b/c++/include/corelib/ncbi_tree.hpp index 83c19930..708c2452 100644 --- a/c++/include/corelib/ncbi_tree.hpp +++ b/c++/include/corelib/ncbi_tree.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBI_TREE__HPP #define CORELIB___NCBI_TREE__HPP -/* $Id: ncbi_tree.hpp 427051 2014-02-17 16:58:38Z mozese2 $ +/* $Id: ncbi_tree.hpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -857,7 +857,7 @@ CTreeNode::FindOrCreateNode(const TKeyList& node_path) } // for it if (!sub_level_found) { - auto_ptr node( new CTreeNode ); + unique_ptr node( new CTreeNode ); node->GetKey() = key; tr->AddNode( node.get() ); tr = node.release(); diff --git a/c++/include/corelib/ncbi_url.hpp b/c++/include/corelib/ncbi_url.hpp index 58025f26..38b129b6 100644 --- a/c++/include/corelib/ncbi_url.hpp +++ b/c++/include/corelib/ncbi_url.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBI_URL__HPP #define CORELIB___NCBI_URL__HPP -/* $Id: ncbi_url.hpp 470591 2015-06-17 14:55:49Z grichenk $ +/* $Id: ncbi_url.hpp 538305 2017-06-09 12:27:12Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -132,11 +132,11 @@ public: virtual string EncodeUser(const string& user) const { return NStr::URLEncode(user, NStr::eUrlEnc_URIUserinfo); } virtual string DecodeUser(const string& user) const - { return NStr::URLDecode(user); } + { return NStr::URLDecode(user, NStr::eUrlDec_Percent); } virtual string EncodePassword(const string& password) const { return NStr::URLEncode(password, NStr::eUrlEnc_URIUserinfo); } virtual string DecodePassword(const string& password) const - { return NStr::URLDecode(password); } + { return NStr::URLDecode(password, NStr::eUrlDec_Percent); } virtual string EncodePath(const string& path) const { return NStr::URLEncode(path, NStr::eUrlEnc_URIPath); } virtual string DecodePath(const string& path) const @@ -156,7 +156,7 @@ public: virtual string EncodeFragment(const string& value) const { return NStr::URLEncode(value, NStr::eUrlEnc_URIFragment); } virtual string DecodeFragment(const string& value) const - { return NStr::URLDecode(value, NStr::eUrlDec_All); } + { return NStr::URLDecode(value, NStr::eUrlDec_Percent); } private: NStr::EUrlEncode m_Encode; }; @@ -276,6 +276,12 @@ public: /// add a new argument. void SetValue(const string& name, const string& value); + /// Add new value even if an argument with the same name already exists. + void AddValue(const string& name, const string& value); + + /// Set value, remove any other values for the name. + void SetUniqueValue(const string& name, const string& value); + /// Get the const list of arguments. const TArgs& GetArgs(void) const { return m_Args; } @@ -327,6 +333,8 @@ private: /// URL parser. Uses CUrlArgs to parse arguments. /// +#define NCBI_SCHEME_SERVICE "ncbilb" + class NCBI_XNCBI_EXPORT CUrl { public: @@ -370,7 +378,7 @@ public: string GetScheme(void) const { return m_Scheme; } void SetScheme(const string& value) { m_Scheme = value; } - /// Generic schemes use '//' after scheme name and colon. + /// Generic schemes use '//' prefix (after optional scheme). bool GetIsGeneric(void) const { return m_IsGeneric; } void SetIsGeneric(bool value) { m_IsGeneric = value; } @@ -379,9 +387,13 @@ public: string GetPassword(void) const { return m_Password; } void SetPassword(const string& value) { m_Password = value; } - + string GetHost(void) const { return m_Host; } - void SetHost(const string& value) { m_Host = value; } + void SetHost(const string& value); + + bool IsService(void) const { return !m_Service.empty(); } + string GetService(void) const { return m_Service; } + void SetService(const string& value); string GetPort(void) const { return m_Port; } void SetPort(const string& value) { m_Port = value; } @@ -416,12 +428,37 @@ public: bool IsEmpty(void) const; + /// Flags controlling URL adjustment. + /// @sa CUrl::Adjust + enum EAdjustFlags { + fUser_Replace = 0x0001, ///< Replace user if set in 'other' + fUser_ReplaceIfEmpty = 0x0002, ///< Replace user only if not yet set + fPassword_Replace = 0x0004, ///< Replace password if set in 'other' + fPassword_ReplaceIfEmpty = 0x0008, ///< Replace password only if not yet set + fPath_Replace = 0x0010, ///< Replace path + fPath_Append = 0x0020, ///< Append new path to the existing one + fFragment_Replace = 0x0040, ///< Replace fragment if set in 'other' + fFragment_ReplaceIfEmpty = 0x0080, ///< Replace fragment only if not yet set + fArgs_Replace = 0x0100, ///< Discard all args, replace with args from 'other' + fArgs_Append = 0x0200, ///< Append args, allow duplicate names and values + fArgs_Merge = 0x0400 ///< Append new args; replace values of existing args, + ///< do not allow to set multiple values with the same name + }; + typedef int TAdjustFlags; + + /// Adjust this URL using information from 'other' URL. + /// Scheme, host and port are never changed. Other parts can be replaced or merged + /// depending on the flags. + /// Throw CUrlException if the flags are inconsistent (e.g. both fPath_Replace and fPath_Append are set). + void Adjust(const CUrl& other, TAdjustFlags flags); + private: // Set values with verification void x_SetScheme(const string& scheme, const IUrlEncoder& encoder); void x_SetUser(const string& user, const IUrlEncoder& encoder); void x_SetPassword(const string& password, const IUrlEncoder& encoder); void x_SetHost(const string& host, const IUrlEncoder& encoder); + void x_SetService(const string& service); void x_SetPort(const string& port, const IUrlEncoder& encoder); void x_SetPath(const string& path, const IUrlEncoder& encoder); void x_SetArgs(const string& args, const IUrlEncoder& encoder); @@ -432,11 +469,12 @@ private: string m_User; string m_Password; string m_Host; + string m_Service; string m_Port; string m_Path; string m_Fragment; string m_OrigArgs; - auto_ptr m_ArgsList; + unique_ptr m_ArgsList; }; @@ -452,13 +490,15 @@ class CUrlException : public CException public: enum EErrCode { eName, //< Argument does not exist - eNoArgs //< CUrl contains no arguments + eNoArgs, //< CUrl contains no arguments + eFlags //< Inconsistent flags passed to Adjust() }; virtual const char* GetErrCodeString(void) const { switch ( GetErrCode() ) { case eName: return "Unknown argument name"; case eNoArgs: return "Arguments list is empty"; + case eFlags: return "Inconsistent flags set"; default: return CException::GetErrCodeString(); } } @@ -503,6 +543,20 @@ public: // CUrl +inline +void CUrl::SetHost(const string& host) +{ + m_Service.clear(); + m_Host = host; +} + +inline +void CUrl::SetService(const string& service) +{ + m_Host.clear(); + m_Service = service; +} + inline void CUrl::x_SetScheme(const string& scheme, const IUrlEncoder& /*encoder*/) @@ -529,6 +583,13 @@ void CUrl::x_SetHost(const string& host, const IUrlEncoder& /*encoder*/) { m_Host = host; + m_Service.clear(); +} + +inline +void CUrl::x_SetService(const string& service) +{ + m_Service = NStr::URLDecode(service); } inline @@ -589,14 +650,18 @@ CUrlArgs::iterator CUrlArgs::FindFirst(const string& name) inline CUrlArgs::const_iterator CUrlArgs::FindNext(const const_iterator& iter) const { - return x_Find(iter->name, iter); + const_iterator next = iter; + ++next; + return x_Find(iter->name, next); } inline CUrlArgs::iterator CUrlArgs::FindNext(const iterator& iter) { - return x_Find(iter->name, iter); + iterator next = iter; + ++next; + return x_Find(iter->name, next); } /* @} */ diff --git a/c++/include/corelib/ncbiapp.hpp b/c++/include/corelib/ncbiapp.hpp index a7d49ac2..60b73018 100644 --- a/c++/include/corelib/ncbiapp.hpp +++ b/c++/include/corelib/ncbiapp.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBIAPP__HPP #define CORELIB___NCBIAPP__HPP -/* $Id: ncbiapp.hpp 518670 2016-11-07 15:25:48Z ivanov $ +/* $Id: ncbiapp.hpp 536051 2017-05-15 16:21:49Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -264,12 +264,20 @@ public: /// Check if the config file has been loaded bool HasLoadedConfig(void) const; - /// Check if the application has finished loading confing file + /// Check if the application has finished loading config file /// (successfully or not). bool FinishedLoadingConfig(void) const; - /// Get the application's cached configuration parameters. + /// Get the application's cached configuration parameters (read-only). + /// + /// Application also can use protected GetRWConfig() to get read-write + // access to the configuration parameters. + /// @sa + /// GetRWConfig const CNcbiRegistry& GetConfig(void) const; + + /// @deprecated Please use const version of GetConfig() or protected GetRWConfig() + //NCBI_DEPRECATED CNcbiRegistry& GetConfig(void); /// Get the full path to the configuration file (if any) we ended @@ -353,6 +361,13 @@ public: /// @deprecated NCBI_DEPRECATED virtual bool SetupDiag_AppSpecific(void); + /// Add callback to be executed from CNcbiApplication destructor. + /// @sa CNcbiActionGuard + template void AddOnExitAction(TFunc func) + { + m_OnExitActions.AddAction(func); + } + protected: /// Result of PreparseArgs() enum EPreparseArgs { @@ -507,6 +522,12 @@ protected: /// LoadConfig(reg, conf, IRegistry::fWithNcbirc). virtual bool LoadConfig(CNcbiRegistry& reg, const string* conf); + /// Get the application's cached configuration parameters, + /// accessible to read-write for an application only. + /// @sa + /// GetConfig + CNcbiRegistry& GetRWConfig(void); + /// Set program's display name. /// /// Set up application name suitable for display or as a basename for @@ -611,6 +632,7 @@ private: bool m_ConfigLoaded; ///< Finished loading config const char* m_LogFile; ///< Logfile if set in the command line int m_LogOptions; ///< logging of env, reg, args, path + CNcbiActionGuard m_OnExitActions; ///< Actions executed on app destruction }; @@ -676,11 +698,17 @@ inline const CNcbiRegistry& CNcbiApplication::GetConfig(void) const return *m_Config; } +/// @deprecated inline CNcbiRegistry& CNcbiApplication::GetConfig(void) { return *m_Config; } +inline CNcbiRegistry& CNcbiApplication::GetRWConfig(void) +{ + return *m_Config; +} + inline const string& CNcbiApplication::GetConfigPath(void) const { return m_ConfigPath; @@ -696,11 +724,9 @@ inline bool CNcbiApplication::FinishedLoadingConfig(void) const return m_ConfigLoaded; } -inline bool CNcbiApplication::ReloadConfig(CMetaRegistry::TFlags flags, - IRegistry::TFlags reg_flags) +inline bool CNcbiApplication::ReloadConfig(CMetaRegistry::TFlags flags, IRegistry::TFlags reg_flags) { - return CMetaRegistry::Reload(GetConfigPath(), GetConfig(), flags, - reg_flags); + return CMetaRegistry::Reload(GetConfigPath(), GetRWConfig(), flags, reg_flags); } inline const string& CNcbiApplication::GetProgramDisplayName(void) const diff --git a/c++/include/corelib/ncbiargs.hpp b/c++/include/corelib/ncbiargs.hpp index b21ea098..96979c51 100644 --- a/c++/include/corelib/ncbiargs.hpp +++ b/c++/include/corelib/ncbiargs.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBIARGS__HPP #define CORELIB___NCBIARGS__HPP -/* $Id: ncbiargs.hpp 497224 2016-04-05 12:11:44Z gouriano $ +/* $Id: ncbiargs.hpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -382,7 +382,12 @@ public: /// (e.g. '-arg') the argument can also be found by 'arg' name if there /// is no another argument named 'arg'. /// - /// Throw an exception if such argument does not exist. + /// Throw an exception if such argument does not exist (not described + /// in the CArgDescriptions). + /// + /// @attention CArgValue::operator bool() can return TRUE even if the + /// argument was not specified in the command-line -- if the + /// argument has a default value. /// @sa /// Exist() above. const CArgValue& operator[] (const string& name) const; @@ -1222,7 +1227,7 @@ public: x_PreCheck(); // Create new "CArgs" to fill up, and parse cmd.-line args into it - auto_ptr args(new CArgs()); + unique_ptr args(new CArgs()); // Special case for CGI -- a lone positional argument if (GetArgsType() == eCgiArgs && argc == 2) { diff --git a/c++/include/corelib/ncbidiag.hpp b/c++/include/corelib/ncbidiag.hpp index ec5fe112..3498a847 100644 --- a/c++/include/corelib/ncbidiag.hpp +++ b/c++/include/corelib/ncbidiag.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBIDIAG__HPP #define CORELIB___NCBIDIAG__HPP -/* $Id: ncbidiag.hpp 514369 2016-09-21 15:22:25Z ivanov $ +/* $Id: ncbidiag.hpp 513581 2016-09-13 12:02:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/corelib/ncbidll.hpp b/c++/include/corelib/ncbidll.hpp index d6de00ad..80f77cfb 100644 --- a/c++/include/corelib/ncbidll.hpp +++ b/c++/include/corelib/ncbidll.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBIDLL__HPP #define CORELIB___NCBIDLL__HPP -/* $Id: ncbidll.hpp 355803 2012-03-08 16:20:29Z ivanovp $ +/* $Id: ncbidll.hpp 515123 2016-09-28 15:09:06Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -241,6 +241,19 @@ public: /// Load the DLL using the name specified in the constructor's DLL "name". /// If Load() is called more than once without calling Unload() in between, /// then it will do nothing. + /// + /// @note If the DLL links against the core "xncbi" library, loading it may + /// result in reinvoking static initializers, with potential consequences + /// ranging from having to retune diagnostic settings to crashing at exit. + /// This problem could theoretically also affect other libraries linked + /// from both sides, but they haven't been an issue in practice. It can + /// help for both the program and the DLL to link "xncbi" dynamically, but + /// in some configurations that change still isn't entirely sufficient. As + /// such, on affected platforms, the C++ Toolkit's build system arranges to + /// filter "xncbi" out of the relevant makefile settings unless + /// specifically directed otherwise via KEEP_CORELIB = yes (which can be + /// useful when building plugins for third-party applications such as + /// scripting languages). NCBI_XNCBI_EXPORT void Load(void); /// Unload DLL. diff --git a/c++/include/corelib/ncbierror.hpp b/c++/include/corelib/ncbierror.hpp index 45313c9b..20142a2d 100644 --- a/c++/include/corelib/ncbierror.hpp +++ b/c++/include/corelib/ncbierror.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBIERROR__HPP #define CORELIB___NCBIERROR__HPP -/* $Id: ncbierror.hpp 511430 2016-08-22 15:25:37Z ivanov $ +/* $Id: ncbierror.hpp 510803 2016-08-16 13:57:32Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/corelib/ncbiexpt.hpp b/c++/include/corelib/ncbiexpt.hpp index 380227ab..2450e65d 100644 --- a/c++/include/corelib/ncbiexpt.hpp +++ b/c++/include/corelib/ncbiexpt.hpp @@ -1,7 +1,7 @@ #ifndef NCBIEXPT__HPP #define NCBIEXPT__HPP -/* $Id: ncbiexpt.hpp 487716 2015-12-21 16:13:26Z ivanov $ +/* $Id: ncbiexpt.hpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -953,7 +953,7 @@ private: mutable bool m_MainText; ///< Exception has main text static bool sm_BkgrEnabled; ///< Background reporting enabled flag - auto_ptr m_StackTrace; ///< Saved stack trace + unique_ptr m_StackTrace; ///< Saved stack trace TFlags m_Flags; ///< Flags, hints, attributes diff --git a/c++/include/corelib/ncbifile.hpp b/c++/include/corelib/ncbifile.hpp index bc218b5d..3da8ba8b 100644 --- a/c++/include/corelib/ncbifile.hpp +++ b/c++/include/corelib/ncbifile.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBIFILE__HPP #define CORELIB___NCBIFILE__HPP -/* $Id: ncbifile.hpp 515654 2016-10-04 18:38:59Z ivanov $ +/* $Id: ncbifile.hpp 546190 2017-09-14 16:01:12Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -189,7 +189,14 @@ public: class NCBI_XNCBI_EXPORT CFileAPI { public: - /// Enable or disable logging of errors. + /// Enable or disable logging of errors from the File API classes. + /// + /// Have the same effect as FileAPILogging global parameter: + /// Registry file: + /// [NCBI] + /// FileAPILogging = true/false + /// Environment variable: + /// NCBI_CONFIG__FILEAPILOGGING /// /// @param on_off_default /// Switch between logging enabled (eOn), disabled (eOff), @@ -199,17 +206,32 @@ public: /// Enable or disable honoring umask settings on Unix for /// newly created files/directories in the File API. /// + /// Have the same effect as FileAPIHonorUmask global parameter: + /// Registry file: + /// [NCBI] + /// FileAPIHonorUmask = true/false + /// Environment variable: + /// NCBI_CONFIG__FILEAPIHONORUMASK + /// /// @param on_off_default /// When set to eOn, allows read-only files to be deleted. /// Otherwise, an attempt to delete a read-only files will /// return an error (EACCES). /// @note - /// Unix only. + /// Unix only. On Windows umask affect only CRT function, + /// the part of API that use Windows API directly just ignore umask setting. static void SetHonorUmask(ESwitch on_off_default); /// Specify whether read-only files can be deleted via /// CDirEntry::Remove() on Windows. /// + /// Have the same effect as DeleteReadOnlyFiles global parameter: + /// Registry file: + /// [NCBI] + /// DeleteReadOnlyFiles = true/false + /// Environment variable: + /// NCBI_CONFIG__DELETEREADONLYFILES + /// /// @param on_off_default /// When set to eOn, allows read-only files to be deleted. /// Otherwise, an attempt to delete a read-only files will @@ -373,6 +395,25 @@ public: /// Note that the "path" can be for any OS (MSWIN, UNIX). static bool IsAbsolutePathEx(const string& path); + /// Given a path, gets the closest parent directory which actually exists. + /// + /// @param path + /// Some path to a directory entry. + /// @return + /// The closest parent directory which actually exists. + /// @throws + /// CFileException if no existing nearest parent directory was found. + /// @note + /// For relative not-existent path it always return ".". + /// To avoid this, you can always use absolute path for "path": + /// CDirEntry::GetNearestExistingParentDir(CDirEntry::CreateAbsolutePath(path)) + /// @note + /// On Unix, a non-empty path should always have some existing parent, + /// because '/' is a common path that should always exist. + /// @sa + /// GetDir, CreateAbsolutePath + static string GetNearestExistingParentDir(const string& path); + /// Create a relative path between two points in the file /// system specified by their absolute paths. /// @@ -483,36 +524,46 @@ public: virtual bool Exists(void) const; /// Copy flags. - /// Note that update modification time for directory depends on the OS. + /// Note that updating modification time for directory depends on the OS. /// Normally it gets updated when a new directory entry is added/removed. /// On the other hand, changing contents of files of that directory /// doesn't usually affect the directory modification time. enum ECopyFlags { - /// The following three flags define what to do when the + /// The following flags define what to do when the /// destination entry already exists: /// - Overwrite the destination - fCF_Overwrite = (1<< 1), - /// - Update older entries only (compare modification times). - fCF_Update = (1<< 2) | fCF_Overwrite, - /// - Backup destination if it exists. - fCF_Backup = (1<< 3) | fCF_Overwrite, + fCF_Overwrite = (1 << 1), + /// - Update older entries only (compare modification times) + fCF_Update = (1 << 2) | fCF_Overwrite, + /// - Backup destination (renames to ".bak" by default) + fCF_Backup = (1 << 3) | fCF_Overwrite, + + /// Safe copy (copy to temporary object and rename). + /// Be aware if used together with fCF_TopDirOnly for copying directories: + /// if specified -- full copy of the source directory will be created, + /// after successful copying it replaces the destination. + /// if not specified -- existing destination directory will be "upgraded" + /// with files from source directory, safe copying will be applied + /// for every copied entry inside. + fCF_Safe = (1 << 4) | fCF_Overwrite, + /// All above flags can be applied to the top directory only /// (not for every file therein), to process the directory /// as a single entity for overwriting, updating or backing up. - fCF_TopDirOnly = (1<< 6), + fCF_TopDirOnly = (1 << 6), + /// If destination entry exists, it must have the same type as source. - fCF_EqualTypes = (1<< 7), + fCF_EqualTypes = (1 << 7), /// Copy entries following their sym.links, not the links themselves. - fCF_FollowLinks = (1<< 8), - fCF_Verify = (1<< 9), ///< Verify data after copying - fCF_PreserveOwner = (1<<10), ///< Preserve owner/group - fCF_PreservePerm = (1<<11), ///< Preserve permissions/attributes - fCF_PreserveTime = (1<<12), ///< Preserve date/times - fCF_PreserveAll = fCF_PreserveOwner | fCF_PreservePerm | - fCF_PreserveTime, - fCF_Recursive = (1<<14), ///< Copy recursively (for dir only) + fCF_FollowLinks = (1 << 8), + fCF_Verify = (1 << 9), ///< Verify data after copying + fCF_PreserveOwner = (1 << 10), ///< Preserve owner/group + fCF_PreservePerm = (1 << 11), ///< Preserve permissions/attributes + fCF_PreserveTime = (1 << 12), ///< Preserve date/times + fCF_PreserveAll = fCF_PreserveOwner | fCF_PreservePerm | fCF_PreserveTime, + fCF_Recursive = (1 << 14), ///< Copy recursively (for dir only) /// Skip all entries for which we don't have Copy() method. - fCF_SkipUnsupported = (1<<15), + fCF_SkipUnsupported = (1 << 15), /// Default flags. fCF_Default = fCF_Recursive | fCF_FollowLinks }; @@ -529,7 +580,7 @@ public: /// @param buf_size /// Buffer size to use while copying the file contents. /// Zero value means using default buffer size. This parameter - /// have advisory status and can be overrided, depends from OS + /// have advisory status and can be override, depends from OS /// and size of copied file. /// @return /// TRUE if the operation was completed successfully; FALSE, otherwise. @@ -558,15 +609,15 @@ public: /// Rename flags enum ERenameFlags { /// Remove destination if it exists. - fRF_Overwrite = (1<<1), + fRF_Overwrite = (1 << 1), /// Update older entries only (compare modification times). - fRF_Update = (1<<2) | fCF_Overwrite, + fRF_Update = (1 << 2) | fCF_Overwrite, /// Backup destination if it exists before renaming. - fRF_Backup = (1<<3) | fCF_Overwrite, + fRF_Backup = (1 << 3) | fCF_Overwrite, /// If destination entry exists, it must have the same type as source. - fRF_EqualTypes = (1<<4), + fRF_EqualTypes = (1 << 4), /// Rename entries following sym.links, not the links themselves. - fRF_FollowLinks = (1<<5), + fRF_FollowLinks = (1 << 5), /// Default flags fRF_Default = 0 }; @@ -614,8 +665,8 @@ public: /// Backup modes enum EBackupMode { - eBackup_Copy = (1<<1), ///< Copy entry - eBackup_Rename = (1<<2), ///< Rename entry + eBackup_Copy = (1 << 1), ///< Copy entry + eBackup_Rename = (1 << 2), ///< Rename entry eBackup_Default = eBackup_Copy ///< Default mode }; @@ -628,8 +679,7 @@ public: /// be deleted (if possible). The current entry name components are /// changed to reflect the backed up copy. /// @param suffix - /// Extension to add to backup entry. If empty, GetBackupSuffix() - /// is be used. + /// Extension to add to backup entry. If empty, GetBackupSuffix() is be used. /// @param mode /// Backup mode. Specifies what to do, copy the entry or just rename it. /// @param copyflags @@ -673,7 +723,7 @@ public: // --- directory processing modes --------------------------- // "Enums", retained for backward compatibility. - /// Directory entry only, no any files or subdirestories + /// Directory entry only, no any files or subdirectories eOnlyEmpty = fDir_Self, eEntryOnly = fDir_Self, @@ -1120,7 +1170,7 @@ public: fModeAdd = 16, ///< Adds the argument permission mode to ///< the entry's current mode. fModeRemove = 32, ///< Removes the argument permission mode - ///< from the entriy's current mode. + ///< from the entry's current mode. fModeNoChange = 64 ///< Do not change permission mode. }; @@ -1149,7 +1199,7 @@ public: /// Adding one of the EModeRelative flags to mode change default /// behavior that replace modes with passed values and allow /// for relative mode change for any of user/group/other/special. - /// It is possble to keep it as is, or add/remove some permission + /// It is possible to keep it as is, or add/remove some permission /// modes specified in parameters. /// @note /// Passing fDefault will cause the corresponding mode @@ -1157,7 +1207,7 @@ public: /// @flags /// Entry processing flags. Affect directories only, /// see CDir::SetMode() for details. For other type entris - /// dont have any effect. + /// donut have any effect. /// @return /// TRUE if permission successfully set; FALSE, otherwise. /// @sa @@ -1479,6 +1529,7 @@ protected: TMode* group_mode, TMode* other_mode, TSpecialModeBits* special) const; + mode_t GetDefaultModeT(void) const; private: string m_Path; ///< Full path of this directory entry @@ -1541,6 +1592,10 @@ public: virtual EType GetObjectType(void) const { return eFile; }; /// Check existence of file. + /// @note + /// CDirEntry::Exists() could be faster on some platforms, + /// if you don't need to check that entry is a file. + /// @sa CDirEntry::Exists virtual bool Exists(void) const; /// Get size of file. @@ -1628,6 +1683,9 @@ public: virtual EType GetObjectType(void) const { return eDir; }; /// Check if directory "dirname" exists. + /// @note + /// CDirEntry::Exists() could be faster on some platforms, + /// if you don't need to check that entry is a directory. virtual bool Exists(void) const; /// Get user "home" directory. @@ -1659,7 +1717,8 @@ public: static bool SetCwd(const string& dir); /// Define a list of pointers to directory entries. - typedef list< AutoPtr > TEntries; + typedef AutoPtr TEntry; + typedef list< TEntry > TEntries; /// Flags for GetEntries() /// @sa GetEntries, GetEntriesPtr @@ -1690,6 +1749,7 @@ public: }; typedef int TGetEntriesFlags; ///< Binary OR of "EGetEntriesFlags" + /// Get directory entries based on the specified "mask". /// /// @param mask @@ -1817,17 +1877,48 @@ public: EGetEntriesMode mode, NStr::ECase use_case) const; + /// Flags for Create()/CreatePath() + /// @sa Create, CreatePath + enum ECreateFlags { + /// Default directory creation mode + /// - no error if directory already exists; + /// - don't change permissions if already exists; + /// - use default mode for created directory + /// see: SetDefaultMode(), SetDefaultModeGlobal(), CFileAPI::SetHonorUmask(). + fCreate_Default = 0, + /// Don't change permissions after creation, leave it for OS and umask control. + /// This flag have a priority over CFileAPI::SetHonorUmask(), that works with fCD_Default only. + fCreate_PermByUmask = (1 << 1), + /// Use same permissions as parent directory (umask ignored) + fCreate_PermAsParent = (1 << 2), + /// Error, if directory already exists. All other existent entry with + /// the same name (including symbolic links to directory) lead to an error by default. + fCreate_ErrorIfExists = (1 << 3), + /// Allow to "update" permissions for already existent directory + /// using default, umask or parent permissions as specified by previous flags. + /// Note: Create() only, ignored by CreatePath(). + fCreate_UpdateIfExists = (1 << 4) + }; + typedef unsigned int TCreateFlags; ///< Binary OR of "ECreateFlags" + /// Create the directory using "dirname" passed in the constructor. - /// + /// + /// Default directory creation mode: + /// - TRUE if directory already exists; + /// - don't change permissions if already exists; + /// - use default mode for created directory /// @return /// TRUE if operation successful; FALSE, otherwise. - bool Create(void) const; + /// @sa + /// SetDefaultMode, SetDefaultModeGlobal, CFileAPI::SetHonorUmask, CreatePath + bool Create(TCreateFlags flags = fCreate_Default) const; /// Create the directory path recursively possibly more than one at a time. /// /// @return /// TRUE if operation successful; FALSE otherwise. - bool CreatePath(void) const; + /// @sa Create + bool CreatePath(TCreateFlags flags = fCreate_Default) const; /// Copy directory. /// @@ -1879,7 +1970,7 @@ public: /// Adding one of the EModeRelative flags to mode change default /// behavior that replace modes with passed values and allow /// for relative mode change for any of user/group/other/special. - /// It is possble to keep it as is, or add/remove some permission + /// It is possible to keep it as is, or add/remove some permission /// modes specified in parameters. /// @note /// Passing "fDefault" will cause the corresponding mode @@ -2229,7 +2320,7 @@ public: /// Default constructor. /// - /// Automaticaly generate temporary file name. + /// Automatically generate temporary file name. CTmpFile(ERemoveMode remove_file = eRemove); /// Constructor. @@ -2705,24 +2796,24 @@ private: /// /// CMemoryFile -- /// -/// Define class for support file memory mapping. +/// Define class to support file memory mapping. /// -/// This is a simple version of the CMemoryFileMap class, supported one +/// This is a simple version of the CMemoryFileMap class supporting one /// mapped segment only. /// -/// Note, that the mapping file must exists or can be create/extended. +/// Note that the file being mapped must exist or can be created/extended. /// If file size changes after mapping, the effect of references to portions /// of the mapped region that correspond to added or removed portions of /// the file is unspecified. /// -/// Throws an exceptions on error. +/// Throws exceptions on errors. class NCBI_XNCBI_EXPORT CMemoryFile : public CMemoryFileMap { public: /// Constructor. /// - /// Initialize the memory mapping on file "file_name". + /// Initialize memory mapping for file "file_name". /// @param filename /// Name of file to map to memory. /// @param protect_attr @@ -2866,11 +2957,13 @@ private: /// File finding flags enum EFindFiles { - fFF_File = (1<<0), ///< find files - fFF_Dir = (1<<1), ///< find directories - fFF_Recursive = (1<<2), ///< descend into sub-dirs - fFF_Nocase = (1<<3), ///< case-insensitive name search - fFF_Default = fFF_File | fFF_Dir ///< default behavior + fFF_File = (1 << 0), ///< find files + fFF_Dir = (1 << 1), ///< find directories + fFF_All = fFF_File | fFF_Dir, ///< find files and directories + ///< (used automatically if fFF_File or fFF_Dir has not specified) + fFF_Recursive = (1 << 2), ///< descend into sub-dirs + fFF_Nocase = (1 << 3), ///< case-insensitive name search + fFF_Default = fFF_All ///< default behavior }; /// Bitwise OR of "EFindFiles" typedef int TFindFiles; @@ -2884,10 +2977,9 @@ void FindFilesInDir(const CDir& dir, TFindFunc& find_func, TFindFiles flags = fFF_Default) { - TFindFiles find_type = flags & (fFF_Dir | fFF_File); + TFindFiles find_type = flags & fFF_All; if ( find_type == 0 ) { - // nothing to find - return; + flags |= fFF_All; } unique_ptr contents(dir.GetEntriesPtr(kEmptyStr, CDir::fIgnoreRecursive | CDir::fIgnorePath)); @@ -2938,10 +3030,9 @@ void FindFilesInDir(const CDir& dir, TFindFunc& find_func, TFindFiles flags = fFF_Default) { - TFindFiles find_type = flags & (fFF_Dir | fFF_File); + TFindFiles find_type = flags & fFF_All; if ( find_type == 0 ) { - // nothing to find - return; + flags |= fFF_All; } unique_ptr contents(dir.GetEntriesPtr(kEmptyStr, CDir::fIgnoreRecursive | CDir::fIgnorePath)); @@ -3221,6 +3312,51 @@ void NCBI_XNCBI_EXPORT FindFiles(const string& pattern, TFindFiles flags); +/// Comparator for directory entries names. +/// +/// Compares two directory entries lexicographically, allow to sort +/// elements in ascending order. Could be used with a list of entries +/// obtained via CDir::GetEntries() or FindFiles(). +/// @param mode +/// Entries sorting mode. +/// @sa +/// CDir::GetEntries, FindFiles +/// @code +/// CDir::TEntries entries = CDir(dir).GetEntries("*.*"); +/// entries.sort(SCompareDirEntries()); +/// @endcode +/// @code +/// vector entries; +/// FindFiles(entries, ...); +/// std::sort(entries.begin(), entries.end(), SCompareDirEntries()); +/// @endcode + +struct SCompareDirEntries +{ + /// Sorting mode + enum ESort { + ePath, ///< Sort by full path (default) + eDir, ///< Directory name + eName, ///< Full file name + eBase, ///< Base file name + eExt ///< File extension + }; + /// You can sort by up to 3 path components. + /// If first components of both paths are equal, next one + /// will be used for comparison, and etc. + SCompareDirEntries(ESort s1 = ePath); + SCompareDirEntries(ESort s1, ESort s2); + SCompareDirEntries(ESort s1, ESort s2, ESort s3); + + /// Comparison operators + bool operator()(const CDir::TEntry& e1, const CDir::TEntry& e2); + bool operator()(const string& e1, const string& e2); + +private: + ESort m_Sort[3]; +}; + + ///////////////////////////////////////////////////////////////////////////// /// @@ -3320,15 +3456,15 @@ public: /// Read file. /// /// @return - /// The number of bytes read (zero indicates end of file, - /// or that 'count' is zero). + /// The number of bytes actually read. + /// Can be less than 'count', zero indicates end of file. size_t Read(void* buf, size_t count) const; /// Write file. /// /// Always write all 'count' bytes of data to the file. /// @return - /// The number of bytes written (equal to 'count'). + /// The number of bytes written; equal to 'count'. size_t Write(const void* buf, size_t count) const; /// Flush file buffers. @@ -3757,11 +3893,14 @@ bool CDirEntry::IsLink(void) const return GetType(eIgnoreLinks) == eLink; } +#if !defined(NCBI_OS_MSWIN) +// Default implementation. See Windows-specific implementation in the .cpp file inline bool CDirEntry::Exists(void) const { return GetType() != eUnknown; } +#endif inline bool CDirEntry::MatchesMask(const string& name, const string& mask, @@ -3804,6 +3943,14 @@ void CDirEntry::SetBackupSuffix(const char* suffix) m_BackupSuffix = const_cast(suffix); } +inline +mode_t CDirEntry::GetDefaultModeT() const +{ + return MakeModeT(m_DefaultMode[eUser], m_DefaultMode[eGroup], + m_DefaultMode[eOther], m_DefaultMode[eSpecial]); +} + + // CFile @@ -3914,6 +4061,15 @@ CDir::GetEntriesPtr(const CMask& masks, } +// SCompareDirEntries + +inline +bool SCompareDirEntries::operator()(const CDir::TEntry& e1, const CDir::TEntry& e2) +{ + return operator()(e1->GetPath(), e2->GetPath()); +} + + // CSymLink inline diff --git a/c++/include/corelib/ncbimisc.hpp b/c++/include/corelib/ncbimisc.hpp index 7aa31678..a60be6b6 100644 --- a/c++/include/corelib/ncbimisc.hpp +++ b/c++/include/corelib/ncbimisc.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBIMISC__HPP #define CORELIB___NCBIMISC__HPP -/* $Id: ncbimisc.hpp 500279 2016-05-03 17:12:04Z ivanov $ +/* $Id: ncbimisc.hpp 547815 2017-10-04 15:03:57Z fukanchi $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -318,105 +318,6 @@ private: -#ifdef HAVE_NO_AUTO_PTR - - -///////////////////////////////////////////////////////////////////////////// -/// -/// auto_ptr -- -/// -/// Define auto_ptr if needed. -/// -/// Replacement of STL's std::auto_ptr for compilers with poor "auto_ptr" -/// implementation. -/// -/// See C++ Toolkit documentation for limitations and use of auto_ptr. - -template -class auto_ptr -{ - // temporary class for auto_ptr copying - template - struct auto_ptr_ref - { - auto_ptr_ref(auto_ptr& ptr) - : m_AutoPtr(ptr) - { - } - auto_ptr& m_AutoPtr; - }; -public: - typedef X element_type; ///< Define element_type - - /// Explicit conversion to auto_ptr. - explicit auto_ptr(X* p = 0) : m_Ptr(p) {} - - /// Copy constructor with implicit conversion. - /// - /// Note that the copy constructor parameter is not a const - /// because it is modified -- ownership is transferred. - auto_ptr(auto_ptr& a) : m_Ptr(a.release()) {} - - /// Assignment operator. - auto_ptr& operator=(auto_ptr& a) { - if (this != &a) { - if (m_Ptr && m_Ptr != a.m_Ptr) { - delete m_Ptr; - } - m_Ptr = a.release(); - } - return *this; - } - - auto_ptr(auto_ptr_ref ref) - : m_Ptr(ref.m_AutoPtr.release()) - { - } - template - operator auto_ptr_ref() - { - return auto_ptr_ref(*this); - } - - /// Destructor. - ~auto_ptr(void) { - if ( m_Ptr ) - delete m_Ptr; - } - - /// Deference operator. - X& operator*(void) const { return *m_Ptr; } - - /// Reference operator. - X* operator->(void) const { return m_Ptr; } - - /// Equality operator. - int operator==(const X* p) const { return (m_Ptr == p); } - - /// Get pointer value. - X* get(void) const { return m_Ptr; } - - /// Release pointer. - X* release(void) { - X* x_Ptr = m_Ptr; m_Ptr = 0; return x_Ptr; - } - - /// Reset pointer. - void reset(X* p = 0) { - if (m_Ptr != p) { - delete m_Ptr; - m_Ptr = p; - } - } - -private: - X* m_Ptr; ///< Internal pointer implementation. -}; - -#endif /* HAVE_NO_AUTO_PTR */ - - - /// Functor template for allocating object. template struct Creater @@ -797,7 +698,7 @@ public: } /// Reset nullable to unassigned state. - CNullable& operator= (ENull null_value) + CNullable& operator= (ENull /*null_value*/) { m_IsNull = true; return *this; @@ -820,24 +721,6 @@ private: # undef max #endif -#if defined(HAVE_NO_MINMAX_TEMPLATE) -# define NOMINMAX - -/// Min function template. -template -inline -const T& min(const T& a, const T& b) { - return b < a ? b : a; -} - -/// Max function template. -template -inline -const T& max(const T& a, const T& b) { - return a < b ? b : a; -} -#endif /* HAVE_NO_MINMAX_TEMPLATE */ - // strdup() @@ -1221,6 +1104,230 @@ private: /// @sa NCBI_DEPRECATED_CTOR #define NCBI_DEPRECATED_CLASS NCBI_DEPRECATED_CTOR(class) +//#define NCBI_ENABLE_SAFE_FLAGS +#ifdef NCBI_ENABLE_SAFE_FLAGS +///////////////////////////////////////////////////////////////////////////// +/// Support for safe enum flags +///////////////////////////////////////////////////////////////////////////// +/// +/// The CSafeFlags enum is used to define flags with enum definition +/// so that they preserve type after bit-wise operations, +/// and doesn't allow to be used in context of another enum/flags/int type. +/// With the definition of enum, usually inside class that uses it: +/// class CMyClass { +// public: +/// enum EFlags { +/// fFlag1 = 1<<0, +/// fFlag2 = 1<<1, +/// fFlag3 = 1<<1, +/// fMask = fFlag1|fFlag2 +/// }; +/// you can add at the same level a macro declaration: +/// DECLARE_SAFE_FLAGS_TYPE(EFlags, TFlags); +/// }; +/// and then outside the class, or at the same level if it's not a class definition: +/// DECLARE_SAFE_FLAGS(EMyFlags::EFlags); +/// The first macro DECLARE_SAFE_FLAGS_TYPE() declares a typedef for safe-flags. +/// The second macro DECLARE_SAFE_FLAGS() marks the enum as a safe-flags enum, so that +/// bit-wise operations on its values will preserve the safe-flags type. +/// No other modification is necessary in code that uses enum flags correctly. +/// In case the enum values are used in a wrong context, like with a different enum type, +/// compilation error will occur. + +/// Safe enum flags template, not to be used explicitly. +/// Use macros DECLARE_SAFE_FLAGS_TYPE and DECLARE_SAFE_FLAGS instead. +template +class CSafeFlags { +public: + typedef Enum enum_type; + typedef typename underlying_type::type storage_type; + + CSafeFlags() + : m_Flags(0) + { + } + explicit + CSafeFlags(storage_type flags) + : m_Flags(flags) + { + } + CSafeFlags(enum_type flags) + : m_Flags(flags) + { + } + + storage_type get() const + { + return m_Flags; + } + + DECLARE_OPERATOR_BOOL(m_Flags != 0); + + bool operator==(const CSafeFlags& b) const + { + return get() == b.get(); + } + bool operator!=(const CSafeFlags& b) const + { + return get() != b.get(); + } + // the following operators are necessary to allow comparison with 0 + bool operator==(int v) const + { + return get() == storage_type(v); + } + bool operator!=(int v) const + { + return get() != storage_type(v); + } + + CSafeFlags operator~() const + { + return CSafeFlags(~get()); + } + + CSafeFlags operator&(const CSafeFlags& b) const + { + return CSafeFlags(get() & b.get()); + } + CSafeFlags& operator&=(const CSafeFlags& b) + { + m_Flags &= b.get(); + return *this; + } + + CSafeFlags operator|(const CSafeFlags& b) const + { + return CSafeFlags(get() | b.get()); + } + CSafeFlags& operator|=(const CSafeFlags& b) + { + m_Flags |= b.get(); + return *this; + } + + CSafeFlags operator^(const CSafeFlags& b) const + { + return CSafeFlags(get() ^ b.get()); + } + CSafeFlags& operator^=(const CSafeFlags& b) + { + m_Flags ^= b.get(); + return *this; + } + +private: + storage_type m_Flags; +}; +/// Macro DECLARE_SAFE_FLAGS_TYPE defines a typedef for safe-flags. +/// First argument is enum name, second argument is the new typedef name. +/// In place of old typedef: +/// typedef int TFlags; +/// put new macro: +/// DECLARE_SAFE_FLAGS_TYPE(EFlags, TFlags); +#define DECLARE_SAFE_FLAGS_TYPE(E, T) \ + typedef NCBI_NS_NCBI::CSafeFlags T + +/// Macro DECLARE_SAFE_FLAGS marks a enum as safe-flags enum. +/// The argument is the enum name. +/// If the enum is defined inside a class then DECLARE_SAFE_FLAGS() +/// must be placed outside the class definition: +/// DECLARE_SAFE_FLAGS(CMyClass::EFlags); +#define DECLARE_SAFE_FLAGS(E) \ +inline NCBI_NS_NCBI::CSafeFlags operator|(E a, E b) \ +{ return NCBI_NS_NCBI::CSafeFlags(a) | b; } \ +inline NCBI_NS_NCBI::CSafeFlags operator&(E a, E b) \ +{ return NCBI_NS_NCBI::CSafeFlags(a) & b; } \ +inline NCBI_NS_NCBI::CSafeFlags operator^(E a, E b) \ +{ return NCBI_NS_NCBI::CSafeFlags(a) ^ b; } \ +inline NCBI_NS_NCBI::CSafeFlags operator~(E a) \ +{ return ~NCBI_NS_NCBI::CSafeFlags(a); } + +/// Helper operators for safe-flags enums. +/// These operators will be used only for enums marked +/// as safe-flag enums by macro DECLARE_SAFE_FLAGS() +template inline CSafeFlags operator|(E a, CSafeFlags b) +{ + return b | a; +} +template inline CSafeFlags operator&(E a, CSafeFlags b) +{ + return b & a; +} +template inline CSafeFlags operator^(E a, CSafeFlags b) +{ + return b ^ a; +} +template inline +ostream& operator<<(ostream& out, const CSafeFlags& v) +{ + return out << v.get(); +} + +#else // NCBI_ENABLE_SAFE_FLAGS +// backup implementation of safe flag macros +# define DECLARE_SAFE_FLAGS_TYPE(Enum,Typedef) typedef underlying_type::type Typedef +# define DECLARE_SAFE_FLAGS(Enum) NCBI_EAT_SEMICOLON(safe_flags) +#endif // NCBI_ENABLE_SAFE_FLAGS + + +/// CNcbiActionGuard class +/// Executes registered callbacks on request or on destruction. +class CNcbiActionGuard +{ +public: + CNcbiActionGuard(void) {} + virtual ~CNcbiActionGuard(void) { ExecuteActions(); } + + template void AddAction(TFunc func) + { + m_Actions.push_back(unique_ptr(new CAction(func))); + } + + void ExecuteActions(void) + { + ITERATE(TActions, it, m_Actions) { + try { + (*it)->Execute(); + } + catch (exception& e) { + ERR_POST("Error executing action: " << e.what()); + } + } + m_Actions.clear(); // prevent multiple executions + } + +private: + CNcbiActionGuard(const CNcbiActionGuard&); + CNcbiActionGuard& operator=(const CNcbiActionGuard&); + + // Action wrapper + class CAction_Base + { + public: + CAction_Base(void) {} + virtual ~CAction_Base() {} + virtual void Execute(void) const = 0; + private: + CAction_Base(const CAction_Base&); + CAction_Base& operator=(const CAction_Base&); + }; + + template class CAction : public CAction_Base + { + public: + CAction(TFunc func) : m_Func(func) {} + virtual ~CAction(void) {} + void Execute(void) const override { m_Func(); } + private: + TFunc m_Func; + }; + typedef list > TActions; + + TActions m_Actions; +}; + + END_NCBI_NAMESPACE; BEGIN_STD_NAMESPACE; diff --git a/c++/include/corelib/ncbimtx.hpp b/c++/include/corelib/ncbimtx.hpp index 1b080ded..47c99540 100644 --- a/c++/include/corelib/ncbimtx.hpp +++ b/c++/include/corelib/ncbimtx.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBIMTX__HPP #define CORELIB___NCBIMTX__HPP -/* $Id: ncbimtx.hpp 469570 2015-06-05 16:05:18Z elisovdn $ +/* $Id: ncbimtx.hpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -126,6 +126,12 @@ typedef HANDLE TSystemMutex; #endif +#if defined(NCBI_NO_THREADS) +#define NCBI_NAMESPACE_MUTEX ncbi_namespace_mutex_st +#else +#define NCBI_NAMESPACE_MUTEX ncbi_namespace_mutex_mt +#endif + /// Get the current thread ID. static inline TThreadSystemID GetCurrentThreadSystemID(void) @@ -233,7 +239,11 @@ public: // class CFastMutex; - +class CAutoInitializeStaticMutex; +class CMutex; +class CAutoInitializeStaticFastMutex; +class CFastMutex; +class CSafeStaticPtr_Base; ///////////////////////////////////////////////////////////////////////////// @@ -245,6 +255,8 @@ class CFastMutex; /// Internal platform-dependent fast mutex implementation to be used by CMutex /// and CFastMutex only. +namespace NCBI_NAMESPACE_MUTEX { + struct SSystemFastMutex { TSystemMutex m_Handle; ///< Mutex handle @@ -347,12 +359,15 @@ protected: void DestroyHandle(void); friend struct SSystemMutex; - friend class CAutoInitializeStaticFastMutex; + friend class ::ncbi::CAutoInitializeStaticFastMutex; + friend class ::ncbi::CFastMutex; + friend class ::ncbi::CSafeStaticPtr_Base; +}; - friend class CFastMutex; +} // NCBI_NAMESPACE_MUTEX + +using NCBI_NAMESPACE_MUTEX::SSystemFastMutex; - friend class CSafeStaticPtr_Base; -}; /// typedefs for ease of use typedef CGuard TFastMutexGuard; @@ -374,6 +389,8 @@ class CMutex; /// Internal platform-dependent mutex implementation to be used by CMutex /// and CFastMutex only. +namespace NCBI_NAMESPACE_MUTEX { + struct SSystemMutex { SSystemFastMutex m_Mutex; ///< Mutex value @@ -437,10 +454,14 @@ protected: NCBI_XNCBI_EXPORT void Destroy(void); - friend class CAutoInitializeStaticMutex; - friend class CMutex; + friend class ::ncbi::CAutoInitializeStaticMutex; + friend class ::ncbi::CMutex; }; +} // NCBI_NAMESPACE_MUTEX + +using NCBI_NAMESPACE_MUTEX::SSystemMutex; + /// typedefs for ease of use typedef CGuard TMutexGuard; @@ -987,20 +1008,12 @@ private: fTrackReaders = 0x40000000 }; - TFlags m_Flags; ///< Configuration flags - - auto_ptr m_RW; ///< Platform-dependent RW-lock data - - volatile TThreadSystemID m_Owner; ///< Writer ID, one of the readers ID - - volatile long m_Count; ///< Number of readers (if >0) or - ///< writers (if <0) - - volatile unsigned int m_WaitingWriters; ///< Number of writers waiting; - ///< zero if not keeping track - - vector m_Readers; ///< List of all readers or writers - ///< for debugging + TFlags m_Flags; ///< Configuration flags + unique_ptr m_RW; ///< Platform-dependent RW-lock data + volatile TThreadSystemID m_Owner; ///< Writer ID, one of the readers ID + volatile long m_Count; ///< Number of readers (if >0) or writers (if <0) + volatile unsigned int m_WaitingWriters; ///< Number of writers waiting; zero if not keeping track + vector m_Readers; ///< List of all readers or writers for debugging bool x_MayAcquireForReading(TThreadSystemID self_id); @@ -1379,14 +1392,12 @@ private: # define NCBI_HAVE_CONDITIONAL_VARIABLE #endif -#if defined(NCBI_HAVE_CONDITIONAL_VARIABLE) - class NCBI_XNCBI_EXPORT CConditionVariable { public: CConditionVariable(void); ~CConditionVariable(void); - + static bool IsSupported(void); /// Release mutex and lock the calling thread until the condition @@ -1437,6 +1448,7 @@ public: /// @sa WaitForSignal, SignalSome void SignalAll(void); +#if defined(NCBI_THREADS) private: bool x_WaitForSignal(SSystemFastMutex& mutex, const CDeadline& timeout); @@ -1447,9 +1459,9 @@ private: #endif CAtomicCounter_WithAutoInit m_WaitCounter; SSystemFastMutex* volatile m_WaitMutex; +#endif }; -#endif /* NCBI_HAVE_CONDITIONAL_VARIABLE */ diff --git a/c++/include/corelib/ncbiobj.hpp b/c++/include/corelib/ncbiobj.hpp index 480f8211..d8f46501 100644 --- a/c++/include/corelib/ncbiobj.hpp +++ b/c++/include/corelib/ncbiobj.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBIOBJ__HPP #define CORELIB___NCBIOBJ__HPP -/* $Id: ncbiobj.hpp 502479 2016-05-24 22:41:09Z vasilche $ +/* $Id: ncbiobj.hpp 532235 2017-04-03 15:08:59Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -2025,12 +2025,9 @@ class CObjectFor : public CObject public: typedef T TObjectType; ///< Define alias for template parameter - CObjectFor(void) - { - } - - explicit CObjectFor(const TObjectType& data) - : m_Data(data) + template + explicit CObjectFor(Args&&... args) + : m_Data(std::forward(args)...) { } diff --git a/c++/include/corelib/ncbireg.hpp b/c++/include/corelib/ncbireg.hpp index dae0a6d7..24be28ac 100644 --- a/c++/include/corelib/ncbireg.hpp +++ b/c++/include/corelib/ncbireg.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBIREG__HPP #define CORELIB___NCBIREG__HPP -/* $Id: ncbireg.hpp 506965 2016-07-13 16:55:04Z elisovdn $ +/* $Id: ncbireg.hpp 540943 2017-07-12 15:49:26Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -101,6 +101,7 @@ public: fPlaintextAllowed = 0x10000,///< @sa GetEncryptedString() fInSectionComments = 0x20000,/**< Indicates that we want in-section comments from x_Enumerate */ + fInternalCheckedAndLocked = 0x40000, ///< @internal fCoreLayers = fTransient | fPersistent | fJustCore, fAllLayers = fTransient | fPersistent | fNotJustCore, fCaseFlags = fSectionCase | fEntryCase @@ -240,6 +241,45 @@ public: TFlags flags = 0, EErrAction err_action = eThrow) const; + /// Overloading of getters for generic programming + /// @{ + string GetValue(const string& section, + const string& name, + const string& default_value, + EErrAction = eReturn, + TFlags flags = 0) const + { + return GetString(section, name, default_value, flags); + } + + int GetValue(const string& section, + const string& name, + int default_value, + EErrAction err_action = eErrPost, + TFlags flags = 0) const + { + return GetInt(section, name, default_value, flags, err_action); + } + + bool GetValue(const string& section, + const string& name, + bool default_value, + EErrAction err_action = eErrPost, + TFlags flags = 0) const + { + return GetBool(section, name, default_value, flags, err_action); + } + + double GetValue(const string& section, + const string& name, + double default_value, + EErrAction err_action = eErrPost, + TFlags flags = 0) const + { + return GetDouble(section, name, default_value, flags, err_action); + } + /// @} + /// Get comment of the registry entry "section:name". /// /// @param section @@ -425,6 +465,45 @@ public: TFlags flags = 0, const string& comment = kEmptyStr); + /// Overloading of setters for generic programming + /// @{ + bool SetValue(const string& section, + const string& name, + const string& value, + TFlags flags = 0, + const string& comment = kEmptyStr) + { + return Set(section, name, value, flags, comment); + } + + bool SetValue(const string& section, + const string& name, + int value, + TFlags flags = 0, + const string& comment = kEmptyStr) + { + return Set(section, name, NStr::IntToString(value), flags, comment); + } + + bool SetValue(const string& section, + const string& name, + bool value, + TFlags flags = 0, + const string& comment = kEmptyStr) + { + return Set(section, name, NStr::BoolToString(value), flags, comment); + } + + bool SetValue(const string& section, + const string& name, + double value, + TFlags flags = 0, + const string& comment = kEmptyStr) + { + return Set(section, name, to_string(value), flags, comment); + } + /// @} + /// Fully unset the configuration parameter value, so that /// HasEntry returns false. /// @return diff --git a/c++/include/corelib/ncbistr.hpp b/c++/include/corelib/ncbistr.hpp index 5cc04312..b683b2d5 100644 --- a/c++/include/corelib/ncbistr.hpp +++ b/c++/include/corelib/ncbistr.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBISTR__HPP #define CORELIB___NCBISTR__HPP -/* $Id: ncbistr.hpp 511434 2016-08-22 15:26:41Z ivanov $ +/* $Id: ncbistr.hpp 536283 2017-05-17 12:36:53Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -569,7 +569,7 @@ public: /// Convert string to number of bytes. /// - /// String can contain "software" qualifiers: MB(megabyte), KB (kilobyte).. + /// String can contain "software" qualifiers: MB(megabyte), KB (kilobyte). /// Example: 100MB, 1024KB /// Note the qualifiers are power-of-2 based, aka kibi-, mebi- etc, so that /// 1KB = 1024B (not 1000B), 1MB = 1024KB = 1048576B, etc. @@ -2184,7 +2184,8 @@ public: /// @param where /// Which end of the string to truncate space from. Default is to /// truncate space from both ends (eTrunc_Both). - /// @sa TruncateSpaces_Unsafe + /// @sa + /// TruncateSpaces_Unsafe static string TruncateSpaces(const string& str, ETrunc where = eTrunc_Both); @@ -2198,13 +2199,14 @@ public: /// truncate space from both ends (eTrunc_Both). /// @attention /// The lifespan of the result string is the same as one of the source. - /// So, for example, if the source is temporary string, then the result - /// will be invalid right away (will point to already released memory). - /// @sa TruncateSpaces + /// So, for example, if the source is temporary string, or it changes somehow, + /// then the result will be invalid right away (will point to already released + /// or wrong range in the memory). + /// @sa + /// TruncateSpaces static CTempString TruncateSpaces_Unsafe(const CTempString str, ETrunc where = eTrunc_Both); - /// @deprecated Use TruncateSpaces_Unsafe() instead -- AND, do make sure /// that you indeed use that in a safe manner! inline @@ -2214,22 +2216,6 @@ public: return TruncateSpaces_Unsafe(str, where); } - /// Truncate spaces in a string. - /// It can be faster but it is also more dangerous than TruncateSpaces() - /// - /// @param str - /// String to truncate spaces from. - /// @param where - /// Which end of the string to truncate space from. Default is to - /// truncate space from both ends (eTrunc_Both). - /// @attention - /// The lifespan of the result string is the same as one of the source. - /// So, for example, if the source is temporary string, then the result - /// will be invalid right away (will point to already released memory). - /// @sa TruncateSpaces - //static CTempString TruncateSpaces_Unsafe(const char* str, - // ETrunc where = eTrunc_Both); - /// @deprecated Use TruncateSpaces_Unsafe() instead -- AND, do make sure /// that you indeed use that in a safe manner! inline @@ -2265,6 +2251,28 @@ public: static void TrimPrefixInPlace(CTempString& str, const CTempString prefix, ECase use_case = eCase); + /// Trim prefix from a string. + /// + /// "Unsafe" counterpart to TrimPrefixInPlace(). + /// @param str + /// String to trim from. + /// @param prefix + /// Prefix to remove. + /// If string doesn't have specified prefix, it doesn't changes. + /// @param use_case + /// Whether to do a case sensitive compare (default is eCase), or a + /// case-insensitive compare (eNocase) while checking for a prefix. + /// @attention + /// The lifespan of the result string is the same as one of the source. + /// So, for example, if the source is temporary string, or it changes somehow, + /// then the result will be invalid right away (will point to already released + /// or wrong range in the memory). + /// @sa + /// TrimPrefixInPlace + static CTempString TrimPrefix_Unsafe(const CTempString str, + const CTempString prefix, + ECase use_case = eCase); + /// Trim suffix from a string (in-place) /// /// @param str @@ -2274,12 +2282,34 @@ public: /// If string doesn't have specified suffix, it doesn't changes. /// @param use_case /// Whether to do a case sensitive compare (default is eCase), or a - /// case-insensitive compare (eNocase) while checking for a prefix. + /// case-insensitive compare (eNocase) while checking for a suffix. static void TrimSuffixInPlace(string& str, const CTempString suffix, ECase use_case = eCase); static void TrimSuffixInPlace(CTempString& str, const CTempString suffix, ECase use_case = eCase); + /// Trim suffix from a string. + /// + /// "Unsafe" counterpart to TrimSuffixInPlace(). + /// @param str + /// String to trim from. + /// @param suffix + /// Suffix to remove. + /// If string doesn't have specified suffix, it doesn't changes. + /// @param use_case + /// Whether to do a case sensitive compare (default is eCase), or a + /// case-insensitive compare (eNocase) while checking for a suffix. + /// @attention + /// The lifespan of the result string is the same as one of the source. + /// So, for example, if the source is temporary string, or it changes somehow, + /// then the result will be invalid right away (will point to already released + /// or wrong range in the memory). + /// @sa + /// TrimSuffixInPlace + static CTempString TrimSuffix_Unsafe(const CTempString str, + const CTempString suffix, + ECase use_case = eCase); + /// Replace occurrences of a substring within a string. /// /// @param src @@ -2298,6 +2328,8 @@ public: /// Replace no more than "max_replace" occurrences of substring "search" /// If "max_replace" is zero(default), then replace all occurrences with /// "replace". + /// @param num_replace + /// Optional pointer to a value which receives number of replacements occurred. /// @return /// Result of replacing the "search" string with "replace" in "src". This /// value is placed in "dst" as well. @@ -2308,7 +2340,8 @@ public: const string& replace, string& dst, SIZE_TYPE start_pos = 0, - SIZE_TYPE max_replace = 0); + SIZE_TYPE max_replace = 0, + SIZE_TYPE* num_replace = 0); /// Replace occurrences of a substring within a string and returns the /// result as a new string. @@ -2326,6 +2359,8 @@ public: /// Replace no more than "max_replace" occurrences of substring "search" /// If "max_replace" is zero(default), then replace all occurrences with /// "replace". + /// @param num_replace + /// Optional pointer to a value which receives number of replacements occurred. /// @return /// A new string containing the result of replacing the "search" string /// with "replace" in "src" @@ -2336,8 +2371,9 @@ public: const string& search, const string& replace, SIZE_TYPE start_pos = 0, - SIZE_TYPE max_replace = 0); - + SIZE_TYPE max_replace = 0, + SIZE_TYPE* num_replace = 0); + /// Replace occurrences of a substring within a string. /// /// On some platforms this function is much faster than Replace() @@ -2356,6 +2392,8 @@ public: /// Replace no more than "max_replace" occurrences of substring "search" /// If "max_replace" is zero(default), then replace all occurrences with /// "replace". + /// @param num_replace + /// Optional pointer to a value which receives number of replacements occurred. /// @return /// Result of replacing the "search" string with "replace" in "src". /// @sa @@ -2364,7 +2402,8 @@ public: const string& search, const string& replace, SIZE_TYPE start_pos = 0, - SIZE_TYPE max_replace = 0); + SIZE_TYPE max_replace = 0, + SIZE_TYPE* num_replace = 0); /// Flags for Split*() methods. /// @@ -2373,6 +2412,9 @@ public: /// its special meaning, as does escaping it if that's enabled too; /// unescaped trailing backslashes and unbalanced quotes result in /// exceptions. + /// @note + /// All escape symbols, single or double quotes became removed + /// if a corresponding fSplit_Can* flag is used. enum ESplitFlags { fSplit_MergeDelimiters = 1 << 0, ///< Merge adjacent delimiters fSplit_Truncate_Begin = 1 << 1, ///< Truncate leading delimiters @@ -2404,8 +2446,8 @@ public: /// Whether to merge adjacent delimiters. /// Used by some methods that don't need full functionality of ESplitFlags. enum EMergeDelims { - eMergeDelims = fSplit_MergeDelims, ///< Merge the delimiters - eNoMergeDelims = fSplit_NoMergeDelims ///< No merge the delimiters + eMergeDelims = fSplit_MergeDelimiters | fSplit_Truncate, + eNoMergeDelims = 0 }; /// Split a string using specified delimiters. @@ -2435,7 +2477,7 @@ public: static list& Split( const CTempString str, const CTempString delim, list& arr, - TSplitFlags flags, // required + TSplitFlags flags = 0, vector* token_pos = NULL); static vector& Split( @@ -2449,21 +2491,23 @@ public: const CTempString str, const CTempString delim, list& arr, - TSplitFlags flags, // required - vector* token_pos = NULL); + TSplitFlags flags = 0, + vector* token_pos = NULL, + CTempString_Storage* storage = NULL); static vector& Split( const CTempString str, const CTempString delim, vector& arr, TSplitFlags flags = 0, - vector* token_pos = NULL); + vector* token_pos = NULL, + CTempString_Storage* storage = NULL); static list& Split( const CTempString str, const CTempString delim, list& arr, - TSplitFlags flags, // required + TSplitFlags flags = 0, vector* token_pos = NULL, CTempString_Storage* storage = NULL); @@ -2475,51 +2519,6 @@ public: vector* token_pos = NULL, CTempString_Storage* storage = NULL); - /// Variation of Split() wihout flags -- for backward compatibility only. - /// @attention - /// Automatically use flags: fSplit_Tokenize - /// @deprecated Use Split() with TSplitFlags instead - inline - NCBI_DEPRECATED - static list& Split(const CTempString str, - const CTempString delim, - list& arr) { - return Split(str, delim, arr, fSplit_Tokenize); - } - - /// Variation of Split() wihout flags -- for backward compatibility only. - /// @attention - /// Automatically use flags: fSplit_Tokenize - /// @deprecated Use Split() with TSplitFlags instead - inline - NCBI_DEPRECATED - static list& Split( - const CTempString str, - const CTempString delim, - list& arr) { - return Split(str, delim, arr, fSplit_Tokenize); - } - - /// @deprecated Use Split() with TSplitFlags instead - inline - NCBI_DEPRECATED - static list& Split( const CTempString str, - const CTempString delim, - list& arr, - EMergeDelims merge, - vector* token_pos = NULL) { - return Split(str, delim, arr, (TSplitFlags)merge, token_pos); - } - - /// @deprecated Use Split() with TSplitFlags instead - NCBI_DEPRECATED - static list& Split( - const CTempString str, - const CTempString delim, - list& arr, - EMergeDelims merge = eMergeDelims, - vector* token_pos = NULL); - /// Split a string into two pieces using the specified delimiters /// /// @param str @@ -2558,7 +2557,8 @@ public: const CTempString delim, CTempString& str1, CTempString& str2, - TSplitFlags flags = 0); + TSplitFlags flags = 0, + CTempString_Storage* storage = NULL); static bool SplitInTwo(const CTempString str, const CTempString delim, @@ -2567,22 +2567,6 @@ public: TSplitFlags flags = 0, CTempString_Storage* storage = NULL); - /// @deprecated Use SplitInTwo() with TSplitFlags instead - NCBI_DEPRECATED - static bool SplitInTwo(const CTempString str, - const CTempString delim, - string& str1, - string& str2, - EMergeDelims merge); - - /// @deprecated Use SplitInTwo() with TSplitFlags instead - NCBI_DEPRECATED - static bool SplitInTwo(const CTempString str, - const CTempString delim, - CTempString& str1, - CTempString& str2, - EMergeDelims merge); - /// Variation of Split() wih fSplit_ByPattern flag applied by default @@ -2605,108 +2589,32 @@ public: const CTempString delim, list& arr, TSplitFlags flags = 0, - vector* token_pos = NULL); + vector* token_pos = NULL, + CTempString_Storage* storage = NULL); static vector& SplitByPattern( const CTempString str, const CTempString delim, vector& arr, TSplitFlags flags = 0, - vector* token_pos = NULL); + vector* token_pos = NULL, + CTempString_Storage* storage = NULL); static list& SplitByPattern( const CTempString str, const CTempString delim, list& arr, TSplitFlags flags = 0, - vector* token_pos = NULL); + vector* token_pos = NULL, + CTempString_Storage* storage = NULL); static vector& SplitByPattern( const CTempString str, const CTempString delim, vector& arr, TSplitFlags flags = 0, - vector* token_pos = NULL); - - /// Tokenize a string using the specified set of char delimiters. - /// - /// @param str - /// String to be tokenized. - /// @param delim - /// Delimiter(s) used to split string "str". The interpretation of - /// multi-character values depends on flags: by default, any of those - /// characters marks a split point (when unquoted), but with - /// fSplit_ByPattern, the entire string must occur. (Meanwhile, - /// an empty value disables splitting.) - /// @param arr - /// The tokens defined in "str" by using symbols from "delim" are added - /// to the vector "arr" and also returned by the function. - /// @param flags - /// Flags directing splitting, characterized under ESplitFlags. - /// @param token_pos - /// Optional array for the tokens' positions in "str". - /// @attention - /// Modifying source CTempString object or destroying it, - /// will invalidate results. - /// @return - /// The vector "arr" is also returned. - /// @sa - /// ESplitFlags, Split, SplitInTwo, SplitByPattern - - /// @deprecated Use Split() instead - NCBI_DEPRECATED - static vector& Tokenize(const CTempString str, - const CTempString delim, - vector& arr, - TSplitFlags flags = 0, - vector* token_pos = NULL); - - /// @deprecated Use Split() instead - NCBI_DEPRECATED - static vector& Tokenize(const CTempString str, - const CTempString delim, - vector& arr, - EMergeDelims merge, - vector* token_pos = NULL); - - /// @deprecated Use Split() instead - NCBI_DEPRECATED - static - vector& Tokenize(const CTempString str, - const CTempString delim, - vector& arr, - TSplitFlags flags = 0, - vector* token_pos = NULL, - CTempString_Storage* storage = NULL); - - /// @deprecated Use Split() instead - NCBI_DEPRECATED - static - vector& Tokenize( const CTempString str, - const CTempString delim, - vector& arr, - EMergeDelims merge = eNoMergeDelims, - vector* token_pos = NULL); - - /// @deprecated Use SplitByPattern() instead - NCBI_DEPRECATED - static - vector& TokenizePattern(const CTempString str, - const CTempString delim, - vector& arr, - EMergeDelims merge = eNoMergeDelims, - vector* token_pos = NULL); - - /// @deprecated Use SplitByPattern() instead - NCBI_DEPRECATED - static - vector& TokenizePattern( - const CTempString str, - const CTempString delim, - vector& arr, - EMergeDelims merge = eNoMergeDelims, - vector* token_pos = NULL); - + vector* token_pos = NULL, + CTempString_Storage* storage = NULL); /// Join strings using the specified delimiter. /// @@ -2763,8 +2671,7 @@ public: /// @sa /// ParseEscapes, CEncode, CParse, Sanitize static string PrintableString(const CTempString str, - TPrintableMode mode = - fNewLine_Quote | fNonAscii_Passthru); + TPrintableMode mode = fNewLine_Quote | fNonAscii_Passthru); /// Flags for Sanitize(). enum ESS_Flags { @@ -4403,6 +4310,13 @@ string NStr::NumericToString(char value, return NStr::IntToString(value, flags, base); } +template<> inline +string NStr::NumericToString(signed char value, + TNumToStringFlags flags, int base) +{ + return NStr::IntToString(value, flags, base); +} + template<> inline string NStr::NumericToString(unsigned char value, TNumToStringFlags flags, int base) @@ -4417,6 +4331,13 @@ void NStr::NumericToString(string& out_str, char value, NStr::IntToString(out_str, value, flags, base); } +template<> inline +void NStr::NumericToString(string& out_str, signed char value, + TNumToStringFlags flags, int base) +{ + NStr::IntToString(out_str, value, flags, base); +} + template<> inline void NStr::NumericToString(string& out_str, unsigned char value, TNumToStringFlags flags, int base) @@ -4447,6 +4368,29 @@ char NStr::StringToNumeric(const CTempString str, return (char) n; } +template<> inline +signed char NStr::StringToNumeric(const CTempString str, + TStringToNumFlags flags, int base) +{ + int n = StringToInt(str, flags, base); + if (n < numeric_limits::min() || n > numeric_limits::max()) { + if (flags & NStr::fConvErr_NoThrow) { +// if ((flags & fConvErr_NoErrno) == 0) { + if (flags & fConvErr_NoErrMessage) { + CNcbiError::SetErrno(errno = ERANGE); + } else { + CNcbiError::SetErrno(errno = ERANGE, str); + } +// } + return 0; + } else { + NCBI_THROW2(CStringException, eConvert, + "NStr::StringToNumeric(): overflow", 0); + } + } + return (signed char) n; +} + template<> inline unsigned char NStr::StringToNumeric(const CTempString str, TStringToNumFlags flags, int base) @@ -4498,6 +4442,34 @@ bool NStr::StringToNumeric(const CTempString str, return true; } +template<> inline +bool NStr::StringToNumeric(const CTempString str, + signed char* value, TStringToNumFlags flags, int base) +{ + int n = StringToInt(str, flags, base); + *value = 0; + if ( !n && errno ) { + return false; + } + if (n < numeric_limits::min() || n > numeric_limits::max()) { + if (flags & NStr::fConvErr_NoThrow) { +// if ((flags & fConvErr_NoErrno) == 0) { + if (flags & fConvErr_NoErrMessage) { + CNcbiError::SetErrno(errno = ERANGE); + } else { + CNcbiError::SetErrno(errno = ERANGE, str); + } +// } + return false; + } else { + NCBI_THROW2(CStringException, eConvert, + "NStr::StringToNumeric(): overflow", 0); + } + } + *value = (signed char) n; + return true; +} + template<> inline bool NStr::StringToNumeric(const CTempString str, unsigned char* value, TStringToNumFlags flags, int base) @@ -5885,6 +5857,8 @@ CUtf8::TruncateSpaces(const CTempString str, NStr::ETrunc side) { // deprecated CStringUTF8 is there #include + + ///////////////////////////////////////////////////////////////////////////// // PCase_Generic:: // diff --git a/c++/include/corelib/ncbistr_util.hpp b/c++/include/corelib/ncbistr_util.hpp index 631e8dbd..64c7dd7c 100644 --- a/c++/include/corelib/ncbistr_util.hpp +++ b/c++/include/corelib/ncbistr_util.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___STR_UTIL__HPP #define CORELIB___STR_UTIL__HPP -/* $Id: ncbistr_util.hpp 484553 2015-11-12 17:18:04Z ivanov $ +/* $Id: ncbistr_util.hpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,6 +37,8 @@ /// Algorithms for string processing #include +#include + BEGIN_NCBI_SCOPE @@ -105,8 +107,8 @@ private: SNode() { } SNode(const CTempString& s) : str(s) { } - CTempString str; - auto_ptr next; + CTempString str; + unique_ptr next; }; SNode m_FirstNode; @@ -238,8 +240,7 @@ public: /// each other are treated as separate delimiters - empty string(s) /// appear in the target output. /// - CStrTokenize(const TString& str, const TString& delim, TFlags flags, - CTempString_Storage* storage) + CStrTokenize(const TString& str, const TString& delim, TFlags flags, CTempString_Storage* storage) : CStrTokenizeBase(str, delim, flags, storage) { } diff --git a/c++/include/corelib/ncbistre.hpp b/c++/include/corelib/ncbistre.hpp index 31ac8d9e..ebea0a3c 100644 --- a/c++/include/corelib/ncbistre.hpp +++ b/c++/include/corelib/ncbistre.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBISTRE__HPP #define CORELIB___NCBISTRE__HPP -/* $Id: ncbistre.hpp 458676 2015-02-09 12:35:49Z lavr $ +/* $Id: ncbistre.hpp 535284 2017-05-08 13:25:16Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -84,16 +84,8 @@ # include # endif # include -# if defined(HAVE_NO_STD) -# define IO_PREFIX -# else -# define IO_PREFIX NCBI_NS_STD -# endif -# if defined HAVE_NO_IOS_BASE -# define IOS_BASE IO_PREFIX::ios -# else -# define IOS_BASE IO_PREFIX::ios_base -# endif +# define IO_PREFIX NCBI_NS_STD +# define IOS_BASE IO_PREFIX::ios_base # define IOS_PREFIX IO_PREFIX::ios # ifdef NO_PUBSYNC @@ -564,30 +556,6 @@ extern bool NcbiStreamCompareText(CNcbiIstream& is, const string& str, ECompareTextMode mode, size_t buf_size = 0); -// "char_traits" may not be defined(e.g. EGCS egcs-2.91.66) -#if defined(HAVE_NO_CHAR_TRAITS) -# define CT_INT_TYPE int -# define CT_CHAR_TYPE char -# define CT_POS_TYPE CNcbiStreampos -# define CT_OFF_TYPE CNcbiStreamoff -# define CT_EOF EOF -inline CT_INT_TYPE ct_not_eof(CT_INT_TYPE i) { - return i == CT_EOF ? 0 : i; -} -# define CT_NOT_EOF ct_not_eof -inline CT_INT_TYPE ct_to_int_type(CT_CHAR_TYPE c) { - return (unsigned char)c; -} -# define CT_TO_INT_TYPE ct_to_int_type -inline CT_CHAR_TYPE ct_to_char_type(CT_INT_TYPE i) { - return (unsigned char)i; -} -# define CT_TO_CHAR_TYPE ct_to_char_type -inline bool ct_eq_int_type(CT_INT_TYPE i1, CT_INT_TYPE i2) { - return i1 == i2; -} -# define CT_EQ_INT_TYPE ct_eq_int_type -#else /* HAVE_NO_CHAR_TRAITS */ # define CT_INT_TYPE NCBI_NS_STD::char_traits::int_type # define CT_CHAR_TYPE NCBI_NS_STD::char_traits::char_type # define CT_POS_TYPE NCBI_NS_STD::char_traits::pos_type @@ -597,7 +565,6 @@ inline bool ct_eq_int_type(CT_INT_TYPE i1, CT_INT_TYPE i2) { # define CT_TO_INT_TYPE NCBI_NS_STD::char_traits::to_int_type # define CT_TO_CHAR_TYPE NCBI_NS_STD::char_traits::to_char_type # define CT_EQ_INT_TYPE NCBI_NS_STD::char_traits::eq_int_type -#endif /* HAVE_NO_CHAR_TRAITS */ #ifdef NCBI_COMPILER_MIPSPRO @@ -673,9 +640,14 @@ public: } operator string(void) const; private: + friend NCBI_XNCBI_EXPORT CNcbiOstream& operator<<(CNcbiOstream& out, const CNcbiOstrstreamToString& s); + CNcbiOstrstream& m_Out; }; +NCBI_XNCBI_EXPORT +CNcbiOstream& operator<<(CNcbiOstream& out, const CNcbiOstrstreamToString& s); + inline Int8 GetOssSize(CNcbiOstrstream& oss) diff --git a/c++/include/corelib/ncbithr.hpp b/c++/include/corelib/ncbithr.hpp index 7c0b0ebe..e29c083f 100644 --- a/c++/include/corelib/ncbithr.hpp +++ b/c++/include/corelib/ncbithr.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBITHR__HPP #define CORELIB___NCBITHR__HPP -/* $Id: ncbithr.hpp 467434 2015-05-13 16:41:39Z sadyrovr $ +/* $Id: ncbithr.hpp 545524 2017-09-07 11:46:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -560,10 +560,17 @@ public: /// Otherwise, do nothing, and return FALSE. bool Discard(void); - /// Get ID of current thread (for main thread it is always zero). + /// Check if the thread has been terminated. + bool IsTerminated(void) const { return m_IsTerminated; } + + /// Get ID of current thread. When not using native threads, but CThread only, + /// the main thread is guaranteed to have zero id. With native threads the + /// main thread may have a non-zero id and it's more reliable to use IsMain(). typedef unsigned int TID; static TID GetSelf(void); + static bool IsMain(void); + /// Get current CThread object (or NULL, if main thread) static CThread* GetCurrentThread(void); diff --git a/c++/include/corelib/ncbiutil.hpp b/c++/include/corelib/ncbiutil.hpp index 5b0a348d..025c6b5c 100644 --- a/c++/include/corelib/ncbiutil.hpp +++ b/c++/include/corelib/ncbiutil.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___NCBI_UTILITY__HPP #define CORELIB___NCBI_UTILITY__HPP -/* $Id: ncbiutil.hpp 191081 2010-05-07 16:06:38Z lavr $ +/* $Id: ncbiutil.hpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -192,7 +192,7 @@ inline void DeleteElements(multimap& m) template inline Result& -AutoMap(auto_ptr& cache, const Source& source, const ToKey& toKey) +AutoMap(unique_ptr& cache, const Source& source, const ToKey& toKey) { Result* ret = cache.get(); if ( !ret ) { diff --git a/c++/include/corelib/perf_log.hpp b/c++/include/corelib/perf_log.hpp index 533abe3c..08165b27 100644 --- a/c++/include/corelib/perf_log.hpp +++ b/c++/include/corelib/perf_log.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___PERF_LOG__HPP #define CORELIB___PERF_LOG__HPP -/* $Id: perf_log.hpp 469371 2015-06-03 18:05:11Z grichenk $ +/* $Id: perf_log.hpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -159,11 +159,11 @@ private: friend class CPerfLogGuard; private: - auto_ptr m_StopWatchGuard; // Internal timer if auto-created. - CStopWatch* m_StopWatch; // Timer (internal or provided by user) - CStopWatch::EStart m_TimerState; // Internal timer state to save cycles - bool m_IsDiscarded; // TRUE if Post() or Discard() is already called - double m_Adjustment; // Accumulated elapsed time adjustment + unique_ptr m_StopWatchGuard; // Internal timer if auto-created. + CStopWatch* m_StopWatch; // Timer (internal or provided by user) + CStopWatch::EStart m_TimerState; // Internal timer state to save cycles + bool m_IsDiscarded; // TRUE if Post() or Discard() is already called + double m_Adjustment; // Accumulated elapsed time adjustment }; diff --git a/c++/include/corelib/request_ctx.hpp b/c++/include/corelib/request_ctx.hpp index 29fc93fa..2c381b8b 100644 --- a/c++/include/corelib/request_ctx.hpp +++ b/c++/include/corelib/request_ctx.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___REQUEST_CTX__HPP #define CORELIB___REQUEST_CTX__HPP -/* $Id: request_ctx.hpp 508071 2016-07-25 16:13:27Z grichenk $ +/* $Id: request_ctx.hpp 511451 2016-08-22 16:11:29Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -79,7 +79,7 @@ public: } /// Check if shared counter is used. - bool IsShared(void) const { return m_SharedSubHitId; } + bool IsShared(void) const { return !m_SharedSubHitId.Empty(); } /// Get hit id value. const string& GetHitId(void) const { return m_HitId; } diff --git a/c++/include/corelib/request_status.hpp b/c++/include/corelib/request_status.hpp index 1600b64b..834ceb8f 100644 --- a/c++/include/corelib/request_status.hpp +++ b/c++/include/corelib/request_status.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___REQUEST_STATUS__HPP #define CORELIB___REQUEST_STATUS__HPP -/* $Id: request_status.hpp 441525 2014-07-24 16:55:45Z grichenk $ +/* $Id: request_status.hpp 522984 2016-12-27 17:38:25Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -108,6 +108,8 @@ public: e504_GatewayTimeout = 504, e505_HTTPVerNotSupported = 505 }; + + static string GetStdStatusMessage(ECode code); }; diff --git a/c++/include/corelib/syslog.hpp b/c++/include/corelib/syslog.hpp index 51f7fd9f..0481e260 100644 --- a/c++/include/corelib/syslog.hpp +++ b/c++/include/corelib/syslog.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___SYSLOG__HPP #define CORELIB___SYSLOG__HPP -/* $Id: syslog.hpp 103491 2007-05-04 17:18:18Z kazimird $ +/* $Id: syslog.hpp 534306 2017-04-26 14:16:05Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -106,7 +106,7 @@ public: EFacility facility = eDefaultFacility); void Post(const string& message, EPriority priority, int facility); - void HonorRegistrySettings(IRegistry* reg = 0); + void HonorRegistrySettings(const IRegistry* reg = 0); static const char* kLogName_Syslog; string GetLogName(void) { return kLogName_Syslog; } diff --git a/c++/src/corelib/teamcity_messages.h b/c++/include/corelib/teamcity_messages.h similarity index 96% rename from c++/src/corelib/teamcity_messages.h rename to c++/include/corelib/teamcity_messages.h index e4326e3e..c52b3410 100644 --- a/c++/src/corelib/teamcity_messages.h +++ b/c++/include/corelib/teamcity_messages.h @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * $Id: teamcity_messages.h 500448 2016-05-04 18:16:16Z ucko $ + * $Id: teamcity_messages.h 536041 2017-05-15 15:43:58Z ivanov $ */ #ifndef H_TEAMCITY_MESSAGES @@ -28,11 +28,12 @@ std::string getFlowIdFromEnvironment(); bool underTeamcity(); class TeamcityMessages { - std::ostream *m_out; protected: - std::string escape(std::string s); + std::ostream *m_out; +public: + std::string escape(std::string s); void openMsg(const std::string &name); void writeProperty(std::string name, std::string value); void closeMsg(); diff --git a/c++/include/corelib/tempstr.hpp b/c++/include/corelib/tempstr.hpp index 6908365b..ab3e876b 100644 --- a/c++/include/corelib/tempstr.hpp +++ b/c++/include/corelib/tempstr.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___TEMPSTR__HPP #define CORELIB___TEMPSTR__HPP -/* $Id: tempstr.hpp 486329 2015-12-03 14:37:58Z ivanov $ +/* $Id: tempstr.hpp 528854 2017-02-27 16:06:03Z astashya $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -352,7 +352,6 @@ CTempString::const_iterator CTempString::end() const inline const char* CTempString::data(void) const { - _ASSERT(m_String); return m_String; } diff --git a/c++/include/corelib/test_boost.hpp b/c++/include/corelib/test_boost.hpp index 8bae11a3..379a309a 100644 --- a/c++/include/corelib/test_boost.hpp +++ b/c++/include/corelib/test_boost.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___TEST_BOOST__HPP #define CORELIB___TEST_BOOST__HPP -/* $Id: test_boost.hpp 489876 2016-01-19 15:33:56Z ucko $ +/* $Id: test_boost.hpp 534440 2017-04-27 12:05:00Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -44,6 +44,7 @@ #include #include #include +#include // Keep Boost's inclusion of from breaking under old WorkShop versions. @@ -635,6 +636,19 @@ void NcbiTestSetGlobalDisabled(void); void NcbiTestSetGlobalSkipped(void); +/// Return current application instance. Similar to CNcbiApplication::Instance(). +/// +CNcbiApplication* NcbiTestGetAppInstance(void); + + +/// Wrapper to get the application's configuration parameters, accessible to read-write. +/// We cannot use CNcbiApplication::GetConfig(), because it return read-only registry, +/// and protected CNcbiApplication::GetRWConfig() is not accessible for unit tests directly. +/// +CNcbiRegistry& NcbiTestGetRWConfig(void); + + + ////////////////////////////////////////////////////////////////////////// // All API from this line below is for internal use only and is not // intended for use by any users. All this stuff is used by end-user @@ -906,6 +920,7 @@ NcbiTestGenTestCases(void (*test_func)(ParamType), } + END_NCBI_SCOPE diff --git a/c++/include/corelib/version.hpp b/c++/include/corelib/version.hpp index eaaf9461..e742663d 100644 --- a/c++/include/corelib/version.hpp +++ b/c++/include/corelib/version.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB___VERSION__HPP #define CORELIB___VERSION__HPP -/* $Id: version.hpp 508153 2016-07-26 15:24:18Z elisovdn $ +/* $Id: version.hpp 523179 2016-12-29 14:03:50Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -104,6 +104,12 @@ public: /// Return empty string if major version is undefined (< 0). virtual string Print(void) const; + /// Print version information as XML (see ncbi_version.xsd) + virtual string PrintXml(void) const; + + /// Print version information as JSON + virtual string PrintJson(void) const; + /// Major version int GetMajor(void) const { return m_Major; } /// Minor version @@ -203,6 +209,12 @@ public: /// Print version information. virtual string Print(void) const; + /// Print version information ax XML. + virtual string PrintXml(void) const; + + /// Print version information as JSON. + virtual string PrintJson(void) const; + private: // default ctor CComponentVersionInfo(void); @@ -226,6 +238,9 @@ struct NCBI_XNCBI_EXPORT SBuildInfo SBuildInfo(); SBuildInfo(const string& d, const string& t = kEmptyStr) : date(d), tag(t) {} + + string PrintXml(void) const; + string PrintJson(void) const; }; @@ -291,10 +306,15 @@ public: }; typedef int TPrintFlags; ///< Binary OR of EPrintFlags - /// Print version data. + /// Print version data, plain text. string Print(const string& appname, TPrintFlags flags = fPrintAll) const; + /// Print version data, XML. + string PrintXml(const string& appname, TPrintFlags flags = fPrintAll) const; + /// Print version data, JSON. + string PrintJson(const string& appname, TPrintFlags flags = fPrintAll) const; private: + AutoPtr< CVersionInfo > m_VersionInfo; vector< AutoPtr< CComponentVersionInfo> > m_Components; SBuildInfo m_BuildInfo; diff --git a/c++/include/db/error_codes.hpp b/c++/include/db/error_codes.hpp new file mode 100644 index 00000000..d102c265 --- /dev/null +++ b/c++/include/db/error_codes.hpp @@ -0,0 +1,60 @@ +#ifndef DB_BDB___ERROR_CODES__HPP +#define DB_BDB___ERROR_CODES__HPP + +/* $Id: error_codes.hpp 173350 2009-10-16 11:02:20Z ivanovp $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Pavel Ivanov + * + */ + +/// @file error_codes.hpp +/// Definition of all error codes used in bdb library +/// (bdb.lib and ncbi_xcache_bdb.lib). +/// + + +#include + + +BEGIN_NCBI_SCOPE + + +NCBI_DEFINE_ERRCODE_X(Db_Bdb_Blob, 1001, 4 ); +NCBI_DEFINE_ERRCODE_X(Db_Bdb_RangeMap, 1002, 2 ); +NCBI_DEFINE_ERRCODE_X(Db_Bdb_Cursor, 1003, 2 ); +NCBI_DEFINE_ERRCODE_X(Db_Bdb_Checkpoint, 1004, 7 ); +NCBI_DEFINE_ERRCODE_X(Db_Bdb_Env, 1005, 9 ); +NCBI_DEFINE_ERRCODE_X(Db_Bdb_File, 1006, 5 ); +NCBI_DEFINE_ERRCODE_X(Db_Bdb_Util, 1007, 2 ); +NCBI_DEFINE_ERRCODE_X(Db_Bdb_Volumes, 1008, 2 ); +NCBI_DEFINE_ERRCODE_X(Db_Bdb_BlobCache, 1009, 31); +NCBI_DEFINE_ERRCODE_X(Db_Sqlite, 1010, 10); + + +END_NCBI_SCOPE + + +#endif /* DB_BDB___ERROR_CODES__HPP */ diff --git a/c++/include/db/sqlite/sqlitewrapp.hpp b/c++/include/db/sqlite/sqlitewrapp.hpp new file mode 100644 index 00000000..7f8bbb74 --- /dev/null +++ b/c++/include/db/sqlite/sqlitewrapp.hpp @@ -0,0 +1,948 @@ +#ifndef DB_SQLITE_SQLITEWRAPP__HPP +#define DB_SQLITE_SQLITEWRAPP__HPP +/* $Id: sqlitewrapp.hpp 532370 2017-04-04 17:33:28Z grichenk $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Pavel Ivanov + * + * File Description: + * Convenient wrappers for SQLite-related objects and most commonly used + * functions. Wrappers require SQLite 3.6.14 or higher with async vfs + * extension. All wrappers are written in assumption that no one else calls + * any sqlite3* functions except the wrapper itself. + */ + +#include +#include +#include +#include +#include +#include + +#include +#ifdef HAVE_SQLITE3ASYNC_H +# include +#endif + +#include + + +BEGIN_NCBI_SCOPE + + +class CSQLITE_Exception; +class CSQLITE_Connection; +class CSQLITE_Statement; +class CSQLITE_Blob; + + +/// Utility class for some global-purpose functions tuning SQLite as a whole +/// as opposed to tuning connection-by-connection. +class CSQLITE_Global +{ +public: + /// Install non-default cache for all SQLite databases. Can be useful + /// if default policy of working with cache is inappropriate for your + /// application. For more details on sqlite3_pcache_methods look into + /// comments before it in sqlite3.h. + /// Method can be called only before SQLite is initialized with + /// Initialize() method. + static void SetCustomPageCache(sqlite3_pcache_methods* methods); + /// Install non-default memory management for SQLite. For more details on + /// sqlite3_mem_methods look into comments before it in sqlite3.h. + /// Method can be called only before SQLite is initialized with + /// Initialize() method. + static void SetCustomMallocFuncs(sqlite3_mem_methods* methods); + + /// Initialization of SQLite and tuning some default parameters. + /// For these SQLite wrappers to work properly this method should be + /// called before any work with other classes. + static void Initialize(void); + /// Finish all SQLite operations. Method should be called at the end of + /// application execution. After it has been called any further attempts + /// to use wrapper classes will likely cause application crash. + static void Finalize(void); + + /// Enable use of the same cache by different connections to the same + /// database file. Setting can be changed at any time and will affect all + /// connections opened after changing. + static void EnableSharedCache(bool enable = true); + /// Get default virtual file system installed in SQLite. + /// Method can be called only after SQLite is initialized with + /// Initialize() method. + static sqlite3_vfs* GetDefaultVFS(void); + /// Register new virtual file system in SQLite. + /// If set_default is TRUE then all connections that will be opened after + /// call to this method will use this virtual file system. When + /// set_default is FALSE then connections will have to state explicitly + /// if they want to use this new vfs (although for now this functionality + /// is not yet implemented in CSQLITE_Connection). + /// Method can be called only after SQLite is initialized with + /// Initialize() method. + static void RegisterCustomVFS(sqlite3_vfs* vfs, bool set_default = true); + +#ifdef HAVE_SQLITE3ASYNC_H + /// Setup the option for asynchronous file system to do the actual locking + /// of database files on disk. If lock_files is TRUE then files will be + /// actually locked on hard disk, if it is FALSE files will not be locked + /// and so consistency of access to databases opened with asynchronous + /// writing flag set will be maintained only inside current process. + /// Method should be called only when there's no connections opened. + static void SetAsyncWritesFileLocking(bool lock_files); + /// Launch background thread doing all asynchronous writes to databases. + /// Method is no-op if background thread has already launched. + static void RunAsyncWritesThread(void); +#endif // HAVE_SQLITE3ASYNC_H + +private: + CSQLITE_Global(void); + CSQLITE_Global(CSQLITE_Global&); + CSQLITE_Global& operator= (CSQLITE_Global&); +}; + + +/// Object factory creating sqlite3* handles. +/// For internal use in CSQLITE_Connection's internal pool. +class CSQLITE_HandleFactory +{ +public: + CSQLITE_HandleFactory(CSQLITE_Connection* conn); + + /// Create new database handle + sqlite3* CreateObject(void); + + /// Destroy database handle + void DeleteObject(sqlite3* handle); + +private: + /// Connection object this factory is bound to + CSQLITE_Connection* m_Conn; +}; + + +/// Connection to SQLite database. +class CSQLITE_Connection +{ +public: + /// Flags controlling specifics of database connection operation. + /// Only one flag can be used in each group of flags (separated by + /// comments). + enum EOperationFlags { + // Mode of operation in multi-threaded environment + fInternalMT = 0x00, ///< Object and all statements and blobs created + ///< on top of it should support internal + ///< synchronization between different threads + fExternalMT = 0x01, ///< Object and all statements and blobs created + ///< on top of it will not be used from different + ///< threads simultaneously, thus performance is + ///< optimized, object creates only one low-level + ///< SQLite connection + /// Default value for multi-threading group of flags + fDefaultMT = fInternalMT, + eAllMT = fInternalMT + fExternalMT, + + // Mode of vacuuming and shrinking file size + fVacuumOn = 0x00, ///< Vacuuming is on, database file has always + ///< the minimum size possible + fVacuumOff = 0x02, ///< Vacuuming is off, database file can only + ///< grow + fVacuumManual = 0x04, ///< Vacuuming is only by request + /// Default value for vacuuming group of flags + fDefaultVacuum = fVacuumOn, + eAllVacuum = fVacuumOn + fVacuumOff + fVacuumManual, + + // Mode of journaling of all transactions + fJournalDelete = 0x00, ///< Journal on disk, journal file is + ///< deleted after each transaction + fJournalTruncate = 0x08, ///< Journal on disk, size of journal file + ///< is nullified after each transaction + fJournalPersist = 0x10, ///< Journal on disk, journal file can only + ///< grow, never shrinks + fJournalMemory = 0x20, ///< Journaling is entirely in-memory + fJournalOff = 0x40, ///< Journaling is completely off (not + ///< recommended - transactions cannot be + ///< rollbacked unless they consist of just + ///< one simple operation) + /// Default value for journaling group of flags + fDefaultJournal = fJournalDelete, + eAllJournal = fJournalDelete + fJournalTruncate + fJournalPersist + + fJournalMemory + fJournalOff, + + // Mode of reliable synchronization with disk database file + fSyncFull = 0x000, ///< Full synchronization, database cannot be + ///< corrupted + fSyncOn = 0x080, ///< Synchronization is on, there is a slight + ///< chance of database corruption when + ///< OS crashes + fSyncOff = 0x100, ///< Synchronization is off, database can be + ///< corrupted on OS crash or power outage + /// Default value for synchronization group of flags + fDefaultSync = fSyncFull, + eAllSync = fSyncOff + fSyncOn + fSyncFull, + + /// Mode of storing temporary data + fTempToMemory = 0x000, ///< Store all temporary tables in memory + fTempToFile = 0x200, ///< Use actual disk file for temporary + ///< storage + /// Default value for "temporary" group of flags + fDefaultTemp = fTempToMemory, + eAllTemp = fTempToMemory + fTempToFile, + + /// Mode of doing all writes to the database + fWritesSync = 0x000, ///< All writes are synchronous - when update + ///< has executed data is already in file + ///< (though @sa fSyncOff) +#ifdef HAVE_SQLITE3ASYNC_H + fWritesAsync = 0x400, ///< All writes are asynchronous - updates + ///< return as quick as they can, actual + ///< writes to database happen in background + ///< thread (@sa + ///< CSQLITE_Global::RunAsyncWritesThread) +#endif + /// Default value for writes mode group of flags + fDefaultWrites = fWritesSync, + eAllWrites = fWritesSync +#ifdef HAVE_SQLITE3ASYNC_H + + fWritesAsync +#endif + , + + fReadOnly = 0x8000, ///< The DB is read-only. Also forces fVacuumOff flag. + + /// Default value of all flags + eDefaultFlags = fDefaultMT + fDefaultVacuum + fDefaultJournal + + fDefaultSync + fDefaultTemp + fDefaultWrites + }; + /// Bit mask of EOperationFlags + typedef int TOperationFlags; + + /// Connect to SQLite database. + /// NOTE: Vacuuming flags have any value here only when new database is + /// created. When old database is opened with some data in it + /// then vacuuming flags are no-op, flags used at creation are in + /// effect. + /// NOTE: Connection should be destroyed after all statements or blobs + /// created on top of it. destroying statements after connection + /// was destroyed will result in segmentation fault. + /// + /// @param file_name + /// File name of SQLite database. If it doesn't exist it will be + /// created. If directory for file doesn't exist exception will be + /// thrown. If file name is empty connection to temporary file will be + /// open. This file will be deleted after connection is closed. If file + /// name is ":memory:" then connection to in-memory database will be + /// open. In both cases (temporary file and in-memory database) flag + /// fExternalMT should be set (it is not checked but you will get + /// malfunctioning otherwise). + /// @param flags + /// Flags for object operations + CSQLITE_Connection(CTempString file_name, + TOperationFlags flags = eDefaultFlags); + ~CSQLITE_Connection(void); + + /// Get database file name for the connection + const string& GetFileName(void) const; + /// Get flags controlling database connection operation + TOperationFlags GetFlags (void) const; + /// Change flags controlling database connection operation. + /// NOTE: Vacuuming flags cannot be changed here. New flags will be + /// applied only to newly created low-level SQLite connections. + /// Thus in fInternalMT mode it is recommended to destroy all + /// CSQLITE_Statement and CSQLITE_Blob objects before changing + /// flags. In fExternalMT mode this cleaning of statements is + /// mandatory - you will get memory and other resources leak + /// otherwise. + void SetFlags(TOperationFlags flags); + /// Set page size for the database (in bytes). Setting has any value only + /// if database is empty (has no tables) and no statements are created + /// yet. Page size should be power of 2 and be less than or equal to + /// 32768. If page size is not set default value is used. + void SetPageSize(unsigned int size); + /// Get page size used in the database (in bytes) + unsigned int GetPageSize(void); + /// Set recommended size of the database cache (number of pages). If value + /// is not set or set to 0 then default SQLite value is used. + void SetCacheSize(unsigned int size); + /// Get recommended size of the database cache. If cache size was not set + /// by SetCacheSize() method then this method returns 0, though actually + /// SQLite uses some default value. + unsigned int GetCacheSize(void); + + /// Try to shrink database and free up to max_free_size bytes of disk + /// space. Method is no-op when vacuum mode is other than fVacuumManual. + /// + /// @sa EOperationFlags + void Vacuum(size_t max_free_size); + /// Create statement for executing manual vacuuming. + /// Caller is responsible for deleting returned statement object. + /// + /// @sa Vacuum + CSQLITE_Statement* CreateVacuumStmt(size_t max_free_size); + + /// Execute sql statement without returning any results. + void ExecuteSql(CTempString sql); + /// Delete database under this connection. Method makes sure that journal + /// file is deleted along with database file itself. All CSQLITE_Statement + /// and CSQLITE_Blob objects on this connection should be deleted before + /// call to this method. Any use of connection after call to this method + /// will cause the database file to be created again. + void DeleteDatabase(void); + + /// Create a read-only copy of the database in memory. + /// The in-memory database is never synchronized with the original file. + /// If 'shared' is true, a single copy of in-memory database is used. + /// Otherwise each call to the function creates a new database and + /// the returned connection is the only way to access it. + /// On error return NULL. + static CSQLITE_Connection* CreateInMemoryDatabase(CTempString file_name, + bool shared = false); + +public: + // For internal use only + + /// Lock and return low-level connection handle + sqlite3* LockHandle(void); + /// Unlock unused low-level connection handle. This handle will be used + /// later by some other statement. Essentially no-op in eExternalMT mode. + /// + /// @sa EMultiThreadMode + void UnlockHandle(sqlite3* handle); + /// Setup newly created low-level connection handle. + /// Executes all necessary pragmas according to operation flags set. + void SetupNewConnection(sqlite3* handle); + +private: + CSQLITE_Connection(const CSQLITE_Connection&); + CSQLITE_Connection& operator=(const CSQLITE_Connection&); + + /// Check that only one flag in specific group of flags is given + void x_CheckFlagsValidity(TOperationFlags flags, EOperationFlags mask); + /// Execute sql statement on given low-level connection handle + void x_ExecuteSql(sqlite3* handle, CTempString sql); + + + typedef CObjPool THandlePool; + + /// File name of SQLite database + string m_FileName; + /// Flags for object operation + TOperationFlags m_Flags; + /// Page size inside the database + unsigned int m_PageSize; + /// Recommended size of cache for the database + unsigned int m_CacheSize; + /// Pool of low-level database connections + THandlePool m_HandlePool; + // In-memory database can not use handle pool. The only handle + // is locked for the whole database life. + sqlite3* m_InMemory; +}; + + +/// SQL statement executing on SQLite database +class CSQLITE_Statement +{ +public: + /// Create and prepare statement for given database connection. + /// If sql is empty nothing is prepared in the constructor. + CSQLITE_Statement(CSQLITE_Connection* conn, CTempString sql = kEmptyStr); + /// Create and prepare statement for particular low-level connection. + /// If sql is empty nothing is prepared in the constructor. + CSQLITE_Statement(sqlite3* conn_handle, CTempString sql = kEmptyStr); + ~CSQLITE_Statement(); + + /// Change sql text for the object and prepare new statement + void SetSql(CTempString sql); + + /// Bind integer value to parameter index. + /// Parameters' numbers start from 1. + void Bind (int index, int val); + /// Bind unsigned integer value to parameter index. + /// Parameters' numbers start from 1. + void Bind (int index, unsigned int val); + /// Bind integer value to parameter index. + /// Parameters' numbers start from 1. + void Bind (int index, long val); + /// Bind unsigned integer value to parameter index. + /// Parameters' numbers start from 1. + void Bind (int index, unsigned long val); +#if !NCBI_INT8_IS_LONG + /// Bind 64-bit integer value to parameter index. + /// Parameters' numbers start from 1. + void Bind (int index, Int8 val); + /// Bind unsigned 64-bit integer value to parameter index. + /// Parameters' numbers start from 1. + void Bind (int index, Uint8 val); +#endif + /// Bind double value to parameter index. + /// Parameters' numbers start from 1. + void Bind (int index, double val); + /// Bind text value to parameter index. + /// Parameters' numbers start from 1. Value of parameter is copied inside + /// the method so it may disappear after call. + void Bind (int index, CTempString val); + /// Bind text value to parameter index. + /// Parameters' numbers start from 1. Value of parameter is not copied, + /// pointer is remembered instead. So given value should exist until + /// statement is executed. + void Bind (int index, const char* data, size_t size); + /// Bind blob value to parameter index. + /// Parameters' numbers start from 1. Value of parameter is not copied, + /// pointer is remembered instead. So given value should exist until + /// statement is executed. + void Bind (int index, const void* data, size_t size); + /// Bind blob value of given size containing only zeros to parameter + /// index. Parameters' numbers start from 1. + void BindZeroedBlob(int index, size_t size); + /// Bind null value to parameter index. + void BindNull (int index); + + /// Execute statement without returning any result + void Execute(void); + /// Step through results of the statement. + /// If statement wasn't executed yet it starts executing. If statement + /// already returned some rows then it moves to the next row. Be aware + /// that when statement begins executing until it returns all rows or + /// is reseted the database is locked so that nobody else can write to it. + /// So it's recommended to step through all results as quick as possible. + /// + /// @return + /// TRUE if new row is available in the result. + /// FALSE if no more rows are available and thus statement finished + /// executing and released all locks held. + bool Step(void); + /// Reset the statement to release all locks and to be ready to execute + /// again. + void Reset(void); + /// Reset all bindings to the statement to their initial NULL values + void ClearBindings(void); + + /// Get number of columns in result set. Method should be executed only + /// after Step() returned TRUE, otherwise returned value is undefined. + int GetColumnsCount(void) const; + /// Get name of column at index col_ind in result set. The leftmost column + /// of result set has the index 0. Method should be executed only after + /// Step() returned TRUE, otherwise returned value is undefined. + CStringUTF8 GetColumnName(int col_ind) const; + + /// Get integer value from column col_ind in current row. The leftmost + /// column of result set has index 0. Method should be executed only + /// after Step() returned TRUE, otherwise returned value is undefined. + int GetInt (int col_ind) const; + /// Get 64-bit integer value from column col_ind in current row. + /// The leftmost column of result set has the index 0. Method should be + /// executed only after Step() returned TRUE, otherwise returned value is + /// undefined. + Int8 GetInt8 (int col_ind) const; + /// Get double value from column col_ind in current row. The leftmost + /// column of result set has the index 0. Method should be executed only + /// after Step() returned TRUE, otherwise returned value is undefined. + double GetDouble(int col_ind) const; + /// Get text value from column col_ind in current row. The leftmost + /// column of result set has the index 0. Method should be executed only + /// after Step() returned TRUE, otherwise returned value is undefined. + string GetString(int col_ind) const; + /// Get size of blob value from column col_ind in current row. The leftmost + /// column of result set has the index 0. Method should be executed only + /// after Step() returned TRUE, otherwise returned value is undefined. + size_t GetBlobSize(int col_ind) const; + /// Read blob value from column col_ind in current row. The leftmost + /// column of result set has the index 0. Method should be executed only + /// after Step() returned TRUE, otherwise returned value is undefined. + /// + /// @param col_ind + /// Index of column to read (left-most is 0) + /// @param buffer + /// Pointer to buffer where to write the data + /// @param size + /// Size of buffer available for writing + /// @return + /// Number of bytes read from result set and put into buffer + size_t GetBlob (int col_ind, void* buffer, size_t size) const; + + /// Get rowid of the row inserted in last statement execution. + /// If connection is working in eExternalMT mode then method should be + /// called after statement execution and before execution of any other + /// statement in the same connection. If last executed statement was not + /// insert then 0 is returned. + Int8 GetLastInsertedRowid(void) const; + /// Get number of rows changed during last insert, delete or update + /// statement. Number does not include rows changed by triggers or by + /// any other indirect means. If called when no insert, update or delete + /// statement was executed result is undefined. + int GetChangedRowsCount (void) const; + +private: + CSQLITE_Statement(const CSQLITE_Statement&); + CSQLITE_Statement& operator=(const CSQLITE_Statement&); + + /// Prepare new statement if it's not empty + void x_Prepare(CTempString sql); + /// Finalize current statement + void x_Finalize(void); + + + /// Connection this statement belongs to + CSQLITE_Connection* m_Conn; + /// Low-level connection handle provided for this statement + sqlite3* m_ConnHandle; + /// Low-level statement handle + sqlite3_stmt* m_StmtHandle; +}; + + +/// "Scoped" statement activity object. +/// Object binds to some statement and ensures that by the end of the scope +/// statement will be reseted and all database locks will be released. Besides +/// that object acts as smart pointer to the statement. +class CSQLITE_StatementLock +{ +public: + /// Bind activity control to the given statement + CSQLITE_StatementLock(CSQLITE_Statement* stmt); + + ~CSQLITE_StatementLock(void); + + /// Smart pointer's transformation + CSQLITE_Statement& operator* (void); + + /// Smart pointer's transformation + CSQLITE_Statement* operator-> (void); + + /// Smart pointer's transformation + operator CSQLITE_Statement* (void); + +private: + CSQLITE_StatementLock(const CSQLITE_StatementLock&); + CSQLITE_StatementLock& operator= (const CSQLITE_StatementLock&); + + /// Statement this object is bound to + CSQLITE_Statement* m_Stmt; +}; + + +// Structures for internal use only +template struct SSQLITE_BlobOpen; +struct SSQLITE_BlobClose; + +/// Object reading and writing blob directly (mostly without executing select +/// or update statements), can read and write blob incrementally. +/// Class assumes that from the moment of its creation till deletion nobody +/// else writes to the blob and/or changes its size. +class CSQLITE_Blob +{ +public: + /// Create object reading and writing blob + /// Identified row with blob should exist in database, exception is + /// thrown otherwise. + /// + /// @param conn + /// Connection which object will work over + /// @param table + /// Table name where blob is located + /// @param column + /// Column name where blob is located + /// @param rowid + /// Rowid of the row where blob is located + CSQLITE_Blob(CSQLITE_Connection* conn, + CTempString table, + CTempString column, + Int8 rowid); + /// Create object reading and writing blob + /// Identified row with blob should exist in database, exception is + /// thrown otherwise. + /// + /// @param conn + /// Connection which object will work over + /// @param db_name + /// Database name where blob is located + /// @param table + /// Table name where blob is located + /// @param column + /// Column name where blob is located + /// @param rowid + /// Rowid of the row where blob is located + CSQLITE_Blob(CSQLITE_Connection* conn, + CTempString db_name, + CTempString table, + CTempString column, + Int8 rowid); + ~CSQLITE_Blob(void); + + /// Set current position inside the blob to desired value + void ResetPosition(size_t position = 0); + /// Get current position inside the blob + size_t GetPosition (void); + /// Get size of the blob + size_t GetSize(void); + + /// Read from blob at current position + /// + /// @param buffer + /// Pointer to buffer where to write read data + /// @param size + /// Size of buffer available for writing + /// @return + /// Number of bytes read from blob. If current position is beyond end + /// of the blob then 0 is returned and buffer is unchanged. + size_t Read (void* buffer, size_t size); + /// Write to blob at current position + /// + /// @param data + /// Pointer to data to write + /// @param size + /// Number of bytes to write + void Write (const void* data, size_t size); + /// Set statement to use when appending to existing blob if necessary. + /// Statement should be of the form + /// "update ... set ... = ...||?2 where rowid=?1" + /// If not set object creates its own statement on the first append. + /// Created statement is destroyed together with this blob object. + /// Statement set by this method is not destroyed with blob object. + /// This method can be useful if one wants to cache statement between + /// different blob objects creation and deletion to not prepare it with + /// each blob object. + void SetAppendStatement(CSQLITE_Statement* stmt); + +private: + CSQLITE_Blob(const CSQLITE_Blob&); + CSQLITE_Blob& operator= (const CSQLITE_Blob&); + + /// Initialize the object + void x_Init (void); + /// Open low-level blob object + /// + /// @param readwrite + /// TRUE if there's need for write access, FALSE if read-only access is + /// sufficient + void x_OpenBlob (bool readwrite = false); + /// Close low-level blob object + void x_CloseBlob(void); + + template friend struct SSQLITE_BlobOpen; + friend struct SSQLITE_BlobClose; + + + /// Connection this blob object belongs to + CSQLITE_Connection* m_Conn; + /// Low-level connection handle provided for this blob object + sqlite3* m_ConnHandle; + /// Statement used for appending to existing blob value + AutoPtr m_AppendStmt; + /// Database name for blob + string m_Database; + /// Table name for blob + string m_Table; + /// Column name for blob + string m_Column; + /// Rowid for the row where blob is located + Int8 m_Rowid; + /// Low-level handle of the blob + sqlite3_blob* m_BlobHandle; + /// Size of the blob + size_t m_Size; + /// Current position inside the blob + size_t m_Position; +}; + + +/// Exception thrown from all SQLite-related objects and functions +class CSQLITE_Exception : public CException +{ +public: + enum EErrCode { + eUnknown, ///< Unknown error + eWrongFlags, ///< Incorrect set of flags in connection constructor + eDBOpen, ///< Error during database opening + eStmtPrepare, ///< Error preparing statement + eStmtFinalize, ///< Error finalizing statement + eStmtBind, ///< Error binding statement parameters + eStmtStep, ///< Error stepping through the statement + eStmtReset, ///< Error reseting statement + eBlobOpen, ///< Error opening blob object + eBlobClose, ///< Error closing blob object + eBlobRead, ///< Error reading directly from blob + eBlobWrite, ///< Error writing directly to blob + eConstraint, ///< Constraint violation during statement execution + eDeadLock, ///< SQLite detected possible deadlock between + ///< different threads + eBadCall ///< Method called when there's no enough capabilities + ///< to finish it successfully + }; + virtual const char* GetErrCodeString(void) const; + NCBI_EXCEPTION_DEFAULT(CSQLITE_Exception, CException); +}; + + + +////////////////////////////////////////////////////////////////////////// +// Inline functions +////////////////////////////////////////////////////////////////////////// + +inline +CSQLITE_Statement::CSQLITE_Statement(CSQLITE_Connection* conn, + CTempString sql) + : m_Conn(conn), + m_ConnHandle(NULL), + m_StmtHandle(NULL) +{ + x_Prepare(sql); +} + +inline +CSQLITE_Statement::CSQLITE_Statement(sqlite3* conn_handle, + CTempString sql) + : m_Conn(NULL), + m_ConnHandle(conn_handle), + m_StmtHandle(NULL) +{ + x_Prepare(sql); +} + +inline void +CSQLITE_Statement::SetSql(CTempString sql) +{ + x_Finalize(); + x_Prepare(sql); +} + +inline void +CSQLITE_Statement::Execute(void) +{ + while (Step()) + {} +} + +inline void +CSQLITE_Statement::Bind(int index, Uint8 val) +{ + // SQLite doesn't understand unsigned types anyway + Bind(index, static_cast(val)); +} + +#if !NCBI_INT8_IS_LONG + +inline void +CSQLITE_Statement::Bind(int index, long val) +{ + Bind(index, static_cast(val)); +} + +inline void +CSQLITE_Statement::Bind(int index, unsigned long val) +{ + Bind(index, static_cast(val)); +} + +#endif + +inline void +CSQLITE_Statement::Bind(int index, int val) +{ + Bind(index, static_cast(val)); +} + +inline void +CSQLITE_Statement::Bind(int index, unsigned int val) +{ + Bind(index, static_cast(val)); +} + +inline int +CSQLITE_Statement::GetColumnsCount(void) const +{ + _ASSERT(m_StmtHandle); + return sqlite3_column_count(m_StmtHandle); +} + +inline int +CSQLITE_Statement::GetInt(int col_ind) const +{ + _ASSERT(m_StmtHandle); + return sqlite3_column_int(m_StmtHandle, col_ind); +} + +inline Int8 +CSQLITE_Statement::GetInt8(int col_ind) const +{ + _ASSERT(m_StmtHandle); + return sqlite3_column_int64(m_StmtHandle, col_ind); +} + +inline double +CSQLITE_Statement::GetDouble(int col_ind) const +{ + _ASSERT(m_StmtHandle); + return sqlite3_column_double(m_StmtHandle, col_ind); +} + +inline Int8 +CSQLITE_Statement::GetLastInsertedRowid(void) const +{ + _ASSERT(m_ConnHandle); + return sqlite3_last_insert_rowid(m_ConnHandle); +} + +inline int +CSQLITE_Statement::GetChangedRowsCount(void) const +{ + _ASSERT(m_ConnHandle); + return sqlite3_changes(m_ConnHandle); +} + + +inline const string& +CSQLITE_Connection::GetFileName(void) const +{ + return m_FileName; +} + +inline CSQLITE_Connection::TOperationFlags +CSQLITE_Connection::GetFlags(void) const +{ + return m_Flags; +} + +inline unsigned int +CSQLITE_Connection::GetPageSize(void) +{ + return m_PageSize; +} + +inline void +CSQLITE_Connection::SetPageSize(unsigned int size) +{ + m_PageSize = size; + m_HandlePool.Clear(); +} + +inline unsigned int +CSQLITE_Connection::GetCacheSize(void) +{ + return m_CacheSize; +} + +inline void +CSQLITE_Connection::SetCacheSize(unsigned int size) +{ + m_CacheSize = size; + m_HandlePool.Clear(); +} + +inline sqlite3* +CSQLITE_Connection::LockHandle(void) +{ + if ( m_InMemory ) { + return m_InMemory; + } + sqlite3* result = m_HandlePool.Get(); + if ((m_Flags & eAllMT) == fExternalMT) { + m_HandlePool.Return(result); + } + return result; +} + +inline void +CSQLITE_Connection::UnlockHandle(sqlite3* handle) +{ + if (m_InMemory && handle == m_InMemory) { + return; + } + if ((m_Flags & eAllMT) == fInternalMT) { + m_HandlePool.Return(handle); + } +} + +inline void +CSQLITE_Connection::ExecuteSql(CTempString sql) +{ + CSQLITE_Statement stmt(this, sql); + stmt.Execute(); +} + +inline void +CSQLITE_Connection::Vacuum(size_t max_free_size) +{ + AutoPtr stmt(CreateVacuumStmt(max_free_size)); + stmt->Execute(); +} + + +inline +CSQLITE_StatementLock::CSQLITE_StatementLock(CSQLITE_Statement* stmt) + : m_Stmt(stmt) +{ + _ASSERT(stmt); +} + +inline CSQLITE_Statement& +CSQLITE_StatementLock::operator* (void) +{ + return *m_Stmt; +} + +inline CSQLITE_Statement* +CSQLITE_StatementLock::operator-> (void) +{ + return m_Stmt; +} + +inline +CSQLITE_StatementLock::operator CSQLITE_Statement* (void) +{ + return m_Stmt; +} + + +inline +CSQLITE_Blob::~CSQLITE_Blob(void) +{ + x_CloseBlob(); + if (m_ConnHandle) { + m_Conn->UnlockHandle(m_ConnHandle); + } +} + +inline size_t +CSQLITE_Blob::GetPosition(void) +{ + return m_Position; +} + +inline void +CSQLITE_Blob::ResetPosition(size_t position /* = 0 */) +{ + m_Position = position; +} + +inline void +CSQLITE_Blob::SetAppendStatement(CSQLITE_Statement* stmt) +{ + m_AppendStmt.reset(stmt, eNoOwnership); +} + +END_NCBI_SCOPE + +#endif /* DB_SQLITE_SQLITEWRAPP__HPP */ diff --git a/c++/include/dbapi/dbapi.hpp b/c++/include/dbapi/dbapi.hpp index b66c713f..52acf540 100644 --- a/c++/include/dbapi/dbapi.hpp +++ b/c++/include/dbapi/dbapi.hpp @@ -1,7 +1,7 @@ #ifndef DBAPI___DBAPI__HPP #define DBAPI___DBAPI__HPP -/* $Id: dbapi.hpp 501456 2016-05-16 15:12:46Z ivanov $ +/* $Id: dbapi.hpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -398,8 +398,8 @@ public: /// SQL statement to execute. /// @return /// Pointer to result set. Ownership of IResultSet* belongs to IStatement. - /// It is not allowed to use auto_ptr<> to manage life-time of - /// IResultSet*. + /// It is not allowed to use auto_ptr<> or other smart pointers to manage + /// life-time of IResultSet*. virtual IResultSet* ExecuteQuery(const string& sql) = 0; /// Executes the last command (with changed parameters, if any). diff --git a/c++/include/dbapi/driver/dbapi_conn_factory.hpp b/c++/include/dbapi/driver/dbapi_conn_factory.hpp index 575fc597..6a4ad8fd 100644 --- a/c++/include/dbapi/driver/dbapi_conn_factory.hpp +++ b/c++/include/dbapi/driver/dbapi_conn_factory.hpp @@ -1,7 +1,7 @@ #ifndef DBAPI_CONN_FACTORY_HPP #define DBAPI_CONN_FACTORY_HPP -/* $Id: dbapi_conn_factory.hpp 470851 2015-06-19 16:29:01Z ucko $ +/* $Id: dbapi_conn_factory.hpp 548536 2017-10-16 15:16:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -100,6 +100,9 @@ protected: const CRef& mapper); public: + typedef IDBServiceMapper::TOptions TServerOptions; + TServerOptions& GetServerOptions(const string& service_name, + bool force_refresh = false); // TSvrRef GetDispatchedServer(const string& service_name); void SetDispatchedServer(const string& service_name, @@ -135,12 +138,14 @@ protected: private: // Data types + typedef map TServerOptionsMap; typedef map TDispatchedSet; typedef map TExclusionSummaryMap; typedef map TServer2NumMap; const CDBConnectionFactory* m_Parent; CRef m_DBServiceMapper; + TServerOptionsMap m_ServerOptionsMap; TDispatchedSet m_DispatchedSet; TExclusionSummaryMap m_ExclusionSummaryMap; TServer2NumMap m_DispatchNumMap; @@ -165,6 +170,7 @@ private: IConnValidator::EConnStatus conn_status; impl::CDBHandlerStack handlers; list tried; + TSvrRef last_tried; // params deliberately left out (potentially call-specific) }; @@ -173,7 +179,8 @@ private: const CDBConnParams& params); CDB_Connection* MakeValidConnection(SOpeningContext& ctx, - const CDBConnParams& params); + const CDBConnParams& params, + CDB_Connection* candidate = NULL); virtual CDB_UserHandler::TExceptions* GetExceptions(void); diff --git a/c++/include/dbapi/driver/dbapi_driver_conn_mgr.hpp b/c++/include/dbapi/driver/dbapi_driver_conn_mgr.hpp index ef54d133..72ce36d6 100644 --- a/c++/include/dbapi/driver/dbapi_driver_conn_mgr.hpp +++ b/c++/include/dbapi/driver/dbapi_driver_conn_mgr.hpp @@ -2,7 +2,7 @@ #define DBAPI_DRIVER_CONN_MGR_HPP -/* $Id: dbapi_driver_conn_mgr.hpp 494417 2016-03-07 15:06:35Z ucko $ +/* $Id: dbapi_driver_conn_mgr.hpp 548536 2017-10-16 15:16:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -52,6 +52,7 @@ namespace impl class IRegistry; template class CSafeStatic_Allocator; +class CDBPoolBalancer; /////////////////////////////////////////////////////////////////////////////// @@ -115,6 +116,7 @@ protected: private: // Friends friend class impl::CDriverContext; + friend class CDBPoolBalancer; }; diff --git a/c++/include/dbapi/driver/dbapi_svc_mapper.hpp b/c++/include/dbapi/driver/dbapi_svc_mapper.hpp index 628c1f38..07971007 100644 --- a/c++/include/dbapi/driver/dbapi_svc_mapper.hpp +++ b/c++/include/dbapi/driver/dbapi_svc_mapper.hpp @@ -1,7 +1,7 @@ #ifndef DBAPI_SVC_MAPPER_HPP #define DBAPI_SVC_MAPPER_HPP -/* $Id: dbapi_svc_mapper.hpp 506715 2016-07-11 16:01:42Z ucko $ +/* $Id: dbapi_svc_mapper.hpp 548536 2017-10-16 15:16:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -98,6 +98,7 @@ public: double preference = 100.0); virtual void GetServersList(const string& service, list* serv_list) const; + virtual void GetServerOptions(const string& service, TOptions* options); virtual bool RecordServer(I_ConnectionExtra& extra) const; void Push(const CRef& mapper); diff --git a/c++/include/dbapi/driver/impl/dbapi_driver_utils.hpp b/c++/include/dbapi/driver/impl/dbapi_driver_utils.hpp index dd498083..5f303c4c 100644 --- a/c++/include/dbapi/driver/impl/dbapi_driver_utils.hpp +++ b/c++/include/dbapi/driver/impl/dbapi_driver_utils.hpp @@ -1,7 +1,7 @@ #ifndef DBAPI_DRIVER_IMPL___DBAPI_DRIVER_UTILS__HPP #define DBAPI_DRIVER_IMPL___DBAPI_DRIVER_UTILS__HPP -/* $Id: dbapi_driver_utils.hpp 503691 2016-06-07 15:44:43Z ucko $ +/* $Id: dbapi_driver_utils.hpp 548536 2017-10-16 15:16:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -255,6 +255,29 @@ private: NCBI_DBAPIDRIVER_EXPORT string ConvertN2A(Uint4 host); +typedef Uint8 TEndpointKey; + +inline +TEndpointKey MakeEndpointKey(Uint4 host, Uint2 port) +{ + return (static_cast(host) << 16) | port; +} + +inline +Uint4 GetHost(TEndpointKey key) +{ + _ASSERT(key >> 48 == 0); + return static_cast(key >> 16); +} + +inline +Uint2 GetPort(TEndpointKey key) +{ + return key & 0xFFFF; +} + + +///////////////////////////////////////////////////////////////////////////// // CUtf8::GetValidBytesCount tolerates mid-sequence truncation. NCBI_DBAPIDRIVER_EXPORT SIZE_TYPE GetValidUTF8Len(const CTempString& ts); diff --git a/c++/include/dbapi/driver/impl/dbapi_impl_cmd.hpp b/c++/include/dbapi/driver/impl/dbapi_impl_cmd.hpp index 6d1b6a6e..7a69fd54 100644 --- a/c++/include/dbapi/driver/impl/dbapi_impl_cmd.hpp +++ b/c++/include/dbapi/driver/impl/dbapi_impl_cmd.hpp @@ -1,7 +1,7 @@ #ifndef DBAPI_DRIVER_IMPL___DBAPI_IMPL_CMD__HPP #define DBAPI_DRIVER_IMPL___DBAPI_IMPL_CMD__HPP -/* $Id: dbapi_impl_cmd.hpp 497635 2016-04-08 13:52:30Z ucko $ +/* $Id: dbapi_impl_cmd.hpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -213,7 +213,7 @@ protected: return m_Recompile; } - void SetHasFailed(bool flag = true) + virtual void SetHasFailed(bool flag = true) { m_HasFailed = flag; } @@ -323,7 +323,7 @@ private: unsigned int m_RowsSent; unsigned int m_BatchesSent; - auto_ptr m_LastInParams; + unique_ptr m_LastInParams; }; diff --git a/c++/include/dbapi/driver/impl/dbapi_impl_connection.hpp b/c++/include/dbapi/driver/impl/dbapi_impl_connection.hpp index bd8f1315..50cb571e 100644 --- a/c++/include/dbapi/driver/impl/dbapi_impl_connection.hpp +++ b/c++/include/dbapi/driver/impl/dbapi_impl_connection.hpp @@ -2,7 +2,7 @@ #define DBAPI_DRIVER_IMPL___DBAPI_IMPL_CONNECTION__HPP -/* $Id: dbapi_impl_connection.hpp 510689 2016-08-15 15:29:39Z ivanov $ +/* $Id: dbapi_impl_connection.hpp 536338 2017-05-17 17:56:58Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -40,6 +40,7 @@ BEGIN_NCBI_SCOPE +class CDBConnectionFactory; class CDB_Connection; namespace impl @@ -62,6 +63,7 @@ class CCommand; class NCBI_DBAPIDRIVER_EXPORT CConnection : public I_ConnectionExtra { friend class impl::CDriverContext; + friend class ncbi::CDBConnectionFactory; friend class ncbi::CDB_Connection; // Because of AttachTo public: @@ -343,7 +345,7 @@ private: CTime m_CleanupTime; CRef m_UserData; unsigned int m_ReuseCount; - const bool m_Reusable; + bool m_Reusable; bool m_OpenFinished; bool m_Valid; const bool m_BCPable; //< Does this connection support BCP (It is related to Context, actually) diff --git a/c++/include/dbapi/driver/impl/dbapi_impl_context.hpp b/c++/include/dbapi/driver/impl/dbapi_impl_context.hpp index a80db1cf..1f61b3e2 100644 --- a/c++/include/dbapi/driver/impl/dbapi_impl_context.hpp +++ b/c++/include/dbapi/driver/impl/dbapi_impl_context.hpp @@ -1,7 +1,7 @@ #ifndef DBAPI_DRIVER_IMPL___DBAPI_IMPL_CONTEXT__HPP #define DBAPI_DRIVER_IMPL___DBAPI_IMPL_CONTEXT__HPP -/* $Id: dbapi_impl_context.hpp 516380 2016-10-13 11:32:10Z ivanov $ +/* $Id: dbapi_impl_context.hpp 548536 2017-10-16 15:16:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -78,6 +78,7 @@ struct NCBI_DBAPIDRIVER_EXPORT SDBConfParams fPoolWaitTimeSet = 0x10000, fPoolAllowTempSet= 0x20000, fContRaiserrorSet= 0x40000 + // , fPoolNameSet = 0x40000 }; typedef unsigned int TFlags; @@ -118,6 +119,7 @@ struct NCBI_DBAPIDRIVER_EXPORT SDBConfParams bool IsCancelTimeoutSet(void){ return IsFlagSet(fCancelTimeoutSet); } bool IsSingleServerSet(void) { return IsFlagSet(fSingleServerSet); } bool IsPooledSet(void) { return IsFlagSet(fIsPooledSet); } + // bool IsPoolNameSet(void) { return IsFlagSet(fPoolNameSet); } bool IsPoolMinSizeSet(void) { return IsFlagSet(fPoolMinSizeSet); } bool IsPoolMaxSizeSet(void) { return IsFlagSet(fPoolMaxSizeSet); } bool IsPoolIdleTimeSet(void) { return IsFlagSet(fPoolIdleTimeSet); } @@ -140,6 +142,7 @@ struct NCBI_DBAPIDRIVER_EXPORT SDBConfParams class NCBI_DBAPIDRIVER_EXPORT CDriverContext : public I_DriverContext { friend class impl::CConnection; + friend class CDBPoolBalancer; protected: CDriverContext(void); @@ -195,7 +198,8 @@ public: /// close reusable deleted connections for specified server and/or pool void CloseUnusedConnections(const string& srv_name = kEmptyStr, - const string& pool_name = kEmptyStr); + const string& pool_name = kEmptyStr, + unsigned int max_closings = kMax_UInt); const CDBHandlerStack& GetConnHandlerStack(void) const { @@ -234,6 +238,18 @@ public: void CloseOldIdleConns (unsigned int max_closings, const string& pool_name = kEmptyStr); + typedef map TCounts; // by server name + typedef map TCountsMap; // by pool or service name + + void GetCountsForPool(const string& pool_name, TCounts* counts) const + { + x_GetCounts(m_CountsByPool, pool_name, counts); + } + void GetCountsForService(const string& service, TCounts* counts) const + { + x_GetCounts(m_CountsByService, service, counts); + } + protected: typedef list TConnPool; @@ -243,7 +259,8 @@ protected: } // To allow children of CDriverContext to create CDB_Connection - CDB_Connection* MakeCDBConnection(CConnection* connection); + CDB_Connection* MakeCDBConnection(CConnection* connection, + int delta /* = 1 */); CDB_Connection* MakePooledConnection(const CDBConnParams& params); virtual CConnection* MakeIConnection(const CDBConnParams& params) = 0; void DestroyConnImpl(CConnection* impl); @@ -271,7 +288,7 @@ protected: private: mutable CMutex m_DefaultCtxMtx; - mutable CMutex m_PoolMutex; //< for m_PoolSem* and m_(Not)InUse + mutable CMutex m_PoolMutex; //< for m_PoolSem*, m_(Not)InUse, & m_Counts* CSemaphore m_PoolSem; string m_PoolSemSubject; CConnection* m_PoolSemConn; @@ -288,6 +305,9 @@ private: /// Used connections TConnPool m_InUse; + TCountsMap m_CountsByPool; + TCountsMap m_CountsByService; + /// Stack of `per-context' err.message handlers CDBHandlerStack m_CntxHandlers; /// Stacks of `per-connection' err.message handlers @@ -302,6 +322,10 @@ private: /// Return unused connection "conn" to the driver context for future /// reuse (if "conn_reusable" is TRUE) or utilization void x_Recycle(CConnection* conn, bool conn_reusable); + + void x_AdjustCounts(const CConnection* conn, int delta); + void x_GetCounts(const TCountsMap& main_map, const string& name, + TCounts* counts) const; }; diff --git a/c++/include/dbapi/driver/interfaces.hpp b/c++/include/dbapi/driver/interfaces.hpp index a39cafad..75a1cfe3 100644 --- a/c++/include/dbapi/driver/interfaces.hpp +++ b/c++/include/dbapi/driver/interfaces.hpp @@ -1,7 +1,7 @@ #ifndef DBAPI_DRIVER___INTERFACES__HPP #define DBAPI_DRIVER___INTERFACES__HPP -/* $Id: interfaces.hpp 501812 2016-05-18 22:51:45Z ucko $ +/* $Id: interfaces.hpp 536536 2017-05-19 16:16:00Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1063,8 +1063,12 @@ public: /// Server/Service name. /// @param pool_name /// Name of connection pool. + /// @param max_closings + /// Maximum number of connections to close now. virtual void CloseUnusedConnections(const string& srv_name = kEmptyStr, - const string& pool_name = kEmptyStr) = 0; + const string& pool_name = kEmptyStr, + unsigned int max_closings = kMax_UInt) + = 0; /// @brief /// Set application name. diff --git a/c++/include/dbapi/driver/odbc/interfaces.hpp b/c++/include/dbapi/driver/odbc/interfaces.hpp index bcd65f5a..7d6cf188 100644 --- a/c++/include/dbapi/driver/odbc/interfaces.hpp +++ b/c++/include/dbapi/driver/odbc/interfaces.hpp @@ -1,7 +1,7 @@ #ifndef DBAPI_DRIVER_ODBC___INTERFACES__HPP #define DBAPI_DRIVER_ODBC___INTERFACES__HPP -/* $Id: interfaces.hpp 497635 2016-04-08 13:52:30Z ucko $ +/* $Id: interfaces.hpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -539,7 +539,7 @@ private: bool m_HasMoreResults; impl::CResult* m_Res; - auto_ptr m_InParams; + unique_ptr m_InParams; }; @@ -566,7 +566,7 @@ protected: CODBC_LangCmd m_CursCmd; unsigned int m_FetchSize; - auto_ptr m_Res; + unique_ptr m_Res; }; @@ -625,7 +625,7 @@ protected: CDB_BlobDescriptor* x_GetBlobDescriptor(unsigned int item_num); protected: - auto_ptr m_LCmd; + unique_ptr m_LCmd; }; diff --git a/c++/include/dbapi/driver/public.hpp b/c++/include/dbapi/driver/public.hpp index 6eb1c52a..1e1f77ba 100644 --- a/c++/include/dbapi/driver/public.hpp +++ b/c++/include/dbapi/driver/public.hpp @@ -1,7 +1,7 @@ #ifndef DBAPI_DRIVER___PUBLIC__HPP #define DBAPI_DRIVER___PUBLIC__HPP -/* $Id: public.hpp 498292 2016-04-14 19:07:55Z ucko $ +/* $Id: public.hpp 532493 2017-04-05 17:37:13Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -374,6 +374,8 @@ private: m_ConnImpl = NULL;; } + bool x_IsAlive(void); + // The constructor should be called by "I_DriverContext" only! friend class impl::CDriverContext; friend class CAutoTrans; diff --git a/c++/include/dbapi/error_codes.hpp b/c++/include/dbapi/error_codes.hpp index 745ae4bb..a0c4846d 100644 --- a/c++/include/dbapi/error_codes.hpp +++ b/c++/include/dbapi/error_codes.hpp @@ -1,7 +1,7 @@ #ifndef DBAPI___ERROR_CODES__HPP #define DBAPI___ERROR_CODES__HPP -/* $Id: error_codes.hpp 516380 2016-10-13 11:32:10Z ivanov $ +/* $Id: error_codes.hpp 548536 2017-10-16 15:16:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -77,6 +77,7 @@ NCBI_DEFINE_ERRCODE_X(Dbapi_BulkInsert, 1136, 1); NCBI_DEFINE_ERRCODE_X(Dbapi_DrvrContext, 1137, 1); NCBI_DEFINE_ERRCODE_X(Dbapi_Sdbapi, 1138, 19); NCBI_DEFINE_ERRCODE_X(Dbapi_ConnMgr, 1139, 1); +NCBI_DEFINE_ERRCODE_X(Dbapi_PoolBalancer, 1140, 7); END_NCBI_SCOPE diff --git a/c++/include/dbapi/variant.hpp b/c++/include/dbapi/variant.hpp index 13eae804..cb1d6f22 100644 --- a/c++/include/dbapi/variant.hpp +++ b/c++/include/dbapi/variant.hpp @@ -1,7 +1,7 @@ #ifndef DBAPI___VARIANT__HPP #define DBAPI___VARIANT__HPP -/* $Id: variant.hpp 498292 2016-04-14 19:07:55Z ucko $ +/* $Id: variant.hpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -237,7 +237,7 @@ private: void x_Inapplicable_Method(const char* method) const; class CDB_Object* m_data; - mutable auto_ptr m_descr; + mutable unique_ptr m_descr; }; bool NCBI_DBAPI_EXPORT operator==(const CVariant& v1, const CVariant& v2); diff --git a/c++/include/html/html.hpp b/c++/include/html/html.hpp index ca2de499..ff14c3d4 100644 --- a/c++/include/html/html.hpp +++ b/c++/include/html/html.hpp @@ -1,7 +1,7 @@ #ifndef HTML___HTML__HPP #define HTML___HTML__HPP -/* $Id: html.hpp 415994 2013-10-23 12:49:27Z ivanov $ +/* $Id: html.hpp 534860 2017-05-03 12:47:52Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -816,7 +816,7 @@ public: protected: TIndex m_CurrentRow, m_CurrentCol; - mutable auto_ptr m_Cache; + mutable unique_ptr m_Cache; CHTML_table_Cache& GetCache(void) const; friend class CHTML_table_Cache; friend class CHTML_tr; diff --git a/c++/include/html/node.hpp b/c++/include/html/node.hpp index df27111b..77707974 100644 --- a/c++/include/html/node.hpp +++ b/c++/include/html/node.hpp @@ -1,7 +1,7 @@ #ifndef HTML___NODE__HPP #define HTML___NODE__HPP -/* $Id: node.hpp 103491 2007-05-04 17:18:18Z kazimird $ +/* $Id: node.hpp 534860 2017-05-03 12:47:52Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -63,7 +63,7 @@ public: #if NCBI_LIGHTWEIGHT_LIST typedef TChildren TChildrenMember; #else - typedef auto_ptr TChildrenMember; + typedef unique_ptr TChildrenMember; #endif struct SAttributeValue { @@ -269,7 +269,7 @@ protected: bool m_RepeatTag; // Attributes, e.g. href="link.html" - auto_ptr m_Attributes; + unique_ptr m_Attributes; private: // To prevent copy constructor. diff --git a/c++/include/ncbi_pch.hpp b/c++/include/ncbi_pch.hpp index 5f36f13b..f16a2a97 100644 --- a/c++/include/ncbi_pch.hpp +++ b/c++/include/ncbi_pch.hpp @@ -1,5 +1,5 @@ #if defined(NCBI_USE_PCH) && !defined(NCBI_PCH__HPP) -/* $Id: ncbi_pch.hpp 521318 2016-12-07 19:37:59Z blastadm $ +/* $Id: ncbi_pch.hpp 548943 2017-10-18 23:45:19Z blastadm $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/ncbi_source_ver.h b/c++/include/ncbi_source_ver.h index 291450b4..678bd3fa 100644 --- a/c++/include/ncbi_source_ver.h +++ b/c++/include/ncbi_source_ver.h @@ -1,4 +1,4 @@ -/* $Id: ncbi_source_ver.h 521318 2016-12-07 19:37:59Z blastadm $ +/* $Id: ncbi_source_ver.h 548943 2017-10-18 23:45:19Z blastadm $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/ncbiconf.h b/c++/include/ncbiconf.h index 87a6e18e..b943f2f3 100644 --- a/c++/include/ncbiconf.h +++ b/c++/include/ncbiconf.h @@ -1,7 +1,7 @@ #ifndef FORWARDING_NCBICONF_H #define FORWARDING_NCBICONF_H -/* $Id: ncbiconf.h 521318 2016-12-07 19:37:59Z blastadm $ +/* $Id: ncbiconf.h 548943 2017-10-18 23:45:19Z blastadm $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objects/general/Dbtag.hpp b/c++/include/objects/general/Dbtag.hpp index 7140c1b9..a0821ff1 100644 --- a/c++/include/objects/general/Dbtag.hpp +++ b/c++/include/objects/general/Dbtag.hpp @@ -1,4 +1,4 @@ -/* $Id: Dbtag.hpp 509625 2016-08-08 14:26:35Z ivanov $ +/* $Id: Dbtag.hpp 547025 2017-09-25 17:21:52Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -214,7 +214,11 @@ public: eDbtagType_VISTA, eDbtagType_BEI, eDbtagType_Araport, - eDbtagType_VGNC + eDbtagType_VGNC, + eDbtagType_RNAcentral, + eDbtagType_PeptideAtlas, + eDbtagType_EPDnew, + eDbtagType_Ensembl }; enum EDbtagGroup { diff --git a/c++/include/objects/general/Name_std.hpp b/c++/include/objects/general/Name_std.hpp index 36757ec7..953d0c4c 100644 --- a/c++/include/objects/general/Name_std.hpp +++ b/c++/include/objects/general/Name_std.hpp @@ -1,4 +1,4 @@ -/* $Id: Name_std.hpp 509242 2016-08-04 14:12:34Z ivanov $ +/* $Id: Name_std.hpp 508532 2016-07-28 17:21:31Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objects/genomecoll/GC_Assembly.hpp b/c++/include/objects/genomecoll/GC_Assembly.hpp index 7066c75b..ed3aa763 100644 --- a/c++/include/objects/genomecoll/GC_Assembly.hpp +++ b/c++/include/objects/genomecoll/GC_Assembly.hpp @@ -1,4 +1,4 @@ -/* $Id: GC_Assembly.hpp 504372 2016-06-14 18:01:03Z shchekot $ +/* $Id: GC_Assembly.hpp 526869 2017-02-07 19:31:53Z mozese2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -98,7 +98,7 @@ public: bool IsGenBank() const; /// Generate the internal up-pointers - void CreateHierarchy(); + void CreateHierarchy(CGC_Assembly *target_set = NULL); /// Generate the Seq-id index void CreateIndex(); @@ -141,6 +141,12 @@ public: void PreWrite() const; void PostRead(); + /// Access the top-level target set that this assemhly belongs to + CConstRef GetTargetSet() const; + + /// Is this assembly the reference assembly of the target set, or part of it? + bool IsTargetSetReference() const; + private: // Prohibit copy constructor and assignment operator CGC_Assembly(const CGC_Assembly& value); @@ -150,6 +156,8 @@ private: typedef map TSequenceIndex; TSequenceIndex m_SequenceMap; + CGC_Assembly* m_TargetSet; + /// indexing infrastructure void x_Index(CGC_Assembly& assm, CGC_Replicon& replicon); void x_Index(CGC_Assembly& assm, CGC_Sequence& seq); diff --git a/c++/include/objects/genomecoll/GC_AssemblyUnit.hpp b/c++/include/objects/genomecoll/GC_AssemblyUnit.hpp index 1f4793b7..d9d91c88 100644 --- a/c++/include/objects/genomecoll/GC_AssemblyUnit.hpp +++ b/c++/include/objects/genomecoll/GC_AssemblyUnit.hpp @@ -1,4 +1,4 @@ -/* $Id: GC_AssemblyUnit.hpp 346674 2011-12-08 18:37:59Z dicuccio $ +/* $Id: GC_AssemblyUnit.hpp 526869 2017-02-07 19:31:53Z mozese2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -74,6 +74,9 @@ public: /// knowing the unit is not always enough CConstRef GetFullAssembly() const; + /// Is this the primary unit of its full assembly? + bool IsPrimaryUnit() const; + protected: CGC_Assembly* m_Assembly; diff --git a/c++/include/objects/genomecoll/cached_assembly.hpp b/c++/include/objects/genomecoll/cached_assembly.hpp index e6d81103..8b48d53f 100644 --- a/c++/include/objects/genomecoll/cached_assembly.hpp +++ b/c++/include/objects/genomecoll/cached_assembly.hpp @@ -41,8 +41,6 @@ public: CCachedAssembly(const vector& blob); CRef Assembly(); - //@deprecated, Blob() will be used in the next release(SC18). This one will be removed in SC19. - const string& Blob(CCompressStream::EMethod neededCompression); //New assemblies are compressed with CCompressStream::eZip, existing returned as is. const string& Blob(); diff --git a/c++/include/objects/genomecoll/genomic_collections_cli.hpp b/c++/include/objects/genomecoll/genomic_collections_cli.hpp index 557746fe..1c44b14a 100644 --- a/c++/include/objects/genomecoll/genomic_collections_cli.hpp +++ b/c++/include/objects/genomecoll/genomic_collections_cli.hpp @@ -1,4 +1,4 @@ -/* $Id: genomic_collections_cli.hpp 517367 2016-10-24 17:52:09Z ivanov $ +/* $Id: genomic_collections_cli.hpp 547389 2017-09-28 17:14:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -39,15 +39,13 @@ #ifndef INTERNAL_GPIPE_OBJECTS_GENOMECOLL_GENOMIC_COLLECTIONS_CLI_HPP #define INTERNAL_GPIPE_OBJECTS_GENOMECOLL_GENOMIC_COLLECTIONS_CLI_HPP - -// generated includes #include #include #include #include #include +#include #include -// generated classes BEGIN_NCBI_SCOPE @@ -57,43 +55,23 @@ class CGCClient_AssemblyInfo; class CGCClient_AssemblySequenceInfo; class CGCClient_EquivalentAssemblies; -///////////////////////////////////////////////////////////////////////////// -class CGenomicCollectionsService : public CGenomicCollectionsService_Base +class CGCServiceException : public CException { public: - CGenomicCollectionsService(); - + CGCServiceException(const CDiagCompileInfo& diag, const objects::CGCClient_Error& srv_error); - typedef CGCClient_GetAssemblyRequest::ELevel ELevel; + //all error codes are taken from the CGCClient_Error_Base::EError_id, please refer to them + typedef objects::CGCClient_Error::EError_id EErrCode; - typedef EGCClient_AttributeFlags EAttributeFlags; - - /// @deprecated Use GetAssembly(const string& acc, const string& mode) - NCBI_DEPRECATED - CRef GetAssembly - (const string& acc, - int level = CGCClient_GetAssemblyRequest::eLevel_scaffold, - int asmAttrFlags = eGCClient_AttributeFlags_none, - int chrAttrFlags = eGCClient_AttributeFlags_biosource, - int scafAttrFlags = eGCClient_AttributeFlags_none, - int compAttrFlags = eGCClient_AttributeFlags_none); - - /// @deprecated Use GetAssembly(int releaseId, const string& mode) - NCBI_DEPRECATED - CRef GetAssembly - (int releaseId, - int level = CGCClient_GetAssemblyRequest::eLevel_scaffold, - int asmAttrFlags = eGCClient_AttributeFlags_none, - int chrAttrFlags = eGCClient_AttributeFlags_biosource, - int scafAttrFlags = eGCClient_AttributeFlags_none, - int compAttrFlags = eGCClient_AttributeFlags_none); + NCBI_EXCEPTION_DEFAULT(CGCServiceException, CException); + const char* GetErrCodeString(void) const override; +}; - /// @deprecated Use GetAssembly(const string& acc, const string& mode) - NCBI_DEPRECATED - CRef GetAssembly(const string& acc, CGCClient_GetAssemblyRequest::EAssemblyMode mode); - /// @deprecated Use GetAssembly(int releaseId, const string& mode) - NCBI_DEPRECATED - CRef GetAssembly(int releaseId, CGCClient_GetAssemblyRequest::EAssemblyMode mode); +///////////////////////////////////////////////////////////////////////////// +class CGenomicCollectionsService : public CGenomicCollectionsService_Base +{ +public: + CGenomicCollectionsService(); CRef GetAssembly(const string& acc, const string& mode); CRef GetAssembly(int releaseId, const string& mode); @@ -141,25 +119,6 @@ public: string ValidateChrType(const string& chrType, const string& chrLoc); - NCBI_DEPRECATED // Use FindOneAssemblyBySequences - CRef FindBestAssembly - (const string& seq_id, - int filter_type, - int sort_type = eGCClient_FindBestAssemblySort_default); - - NCBI_DEPRECATED // Use FindOneAssemblyBySequences - CRef FindBestAssembly - (const list& seq_id, - int filter_type, - int sort_type = eGCClient_FindBestAssemblySort_default); - - NCBI_DEPRECATED // Use FindAssembliesBySequences - CRef FindAllAssemblies - (const list& seq_id, - int filter_type, - int sort_type = eGCClient_FindBestAssemblySort_default); - - /// Find assembly by sequence accession /// /// @param sequence_acc diff --git a/c++/include/objects/id2/ID2_Reply_Data.hpp b/c++/include/objects/id2/ID2_Reply_Data.hpp new file mode 100644 index 00000000..5743c3ca --- /dev/null +++ b/c++/include/objects/id2/ID2_Reply_Data.hpp @@ -0,0 +1,107 @@ +/* $Id: ID2_Reply_Data.hpp 534721 2017-05-01 18:13:51Z grichenk $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + */ + +/// @file ID2_Reply_Data.hpp +/// User-defined methods of the data storage class. +/// +/// This file was originally generated by application DATATOOL +/// using the following specifications: +/// 'id2.asn'. +/// +/// New methods or data members can be added to it if needed. +/// See also: ID2_Reply_Data_.hpp + + +#ifndef OBJECTS_ID2_ID2_REPLY_DATA_HPP +#define OBJECTS_ID2_ID2_REPLY_DATA_HPP + + +#include + +// generated includes +#include + +// generated classes + +BEGIN_NCBI_SCOPE + +BEGIN_objects_SCOPE // namespace ncbi::objects:: + +///////////////////////////////////////////////////////////////////////////// +class NCBI_ID2_EXPORT CID2_Reply_Data : public CID2_Reply_Data_Base +{ + typedef CID2_Reply_Data_Base Tparent; +public: + // constructor + CID2_Reply_Data(void); + // destructor + ~CID2_Reply_Data(void); + +private: + // Prohibit copy constructor and assignment operator + CID2_Reply_Data(const CID2_Reply_Data& value); + CID2_Reply_Data& operator=(const CID2_Reply_Data& value); + +}; + + +class NCBI_ID2_EXPORT COctetStringSequenceWriter : public IWriter +{ +public: + typedef vector TOctetString; + typedef CID2_Reply_Data::TData TOctetStringSequence; + + COctetStringSequenceWriter(TOctetStringSequence& out); + virtual ERW_Result Write(const void* buffer, + size_t count, + size_t* written); + virtual ERW_Result Flush(void); + +private: + TOctetStringSequence& m_Output; +}; + + +/////////////////// CID2_Reply_Data inline methods + +// constructor +inline +CID2_Reply_Data::CID2_Reply_Data(void) +{ +} + + +/////////////////// end of CID2_Reply_Data inline methods + + +END_objects_SCOPE // namespace ncbi::objects:: + +END_NCBI_SCOPE + + +#endif // OBJECTS_ID2_ID2_REPLY_DATA_HPP +/* Original file checksum: lines: 86, chars: 2487, CRC32: bc64c4ad */ diff --git a/c++/include/objects/id2/id2processor.hpp b/c++/include/objects/id2/id2processor.hpp index c01d990e..463c05a6 100644 --- a/c++/include/objects/id2/id2processor.hpp +++ b/c++/include/objects/id2/id2processor.hpp @@ -1,6 +1,6 @@ #ifndef OBJECTS_ID2_ID2PROCESSOR_HPP #define OBJECTS_ID2_ID2PROCESSOR_HPP -/* $Id: id2processor.hpp 504899 2016-06-20 17:49:29Z vasilche $ +/* $Id: id2processor.hpp 528532 2017-02-23 17:27:58Z vasilche $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information @@ -59,6 +59,24 @@ public: }; +// CID2ProcessorContext is used to hold connection specific state +class NCBI_ID2_EXPORT CID2ProcessorContext : public CObject +{ +public: + CID2ProcessorContext(void); + virtual ~CID2ProcessorContext(void); +}; + + +// CID2ProcessorPacketContext is used to hold request packet specific state +class NCBI_ID2_EXPORT CID2ProcessorPacketContext : public CObject +{ +public: + CID2ProcessorPacketContext(void); + virtual ~CID2ProcessorPacketContext(void); +}; + + class NCBI_ID2_EXPORT CID2Processor : public CObject { public: @@ -67,11 +85,40 @@ public: typedef vector > TReplies; + // old interface, optional + virtual TReplies ProcessSomeRequests(CID2_Request_Packet& packet, - CID2ProcessorResolver* resolver = 0) = 0; + CID2ProcessorResolver* resolver = 0); virtual bool ProcessRequest(TReplies& replies, CID2_Request& request, - CID2ProcessorResolver *resolver = 0) = 0; + CID2ProcessorResolver* resolver = 0); + + // new interface, optional + + // return true if the processer need to process replies from server via ProcessReply() + virtual bool NeedToProcessReplies(void) const; + + // CID2ProcessorParameters holds parameters that control behavior of the processor. + // The same CID2Processor object can be used for all connections, but each connection should + // have its own CID2ProcessorContext object. + // It's allowed to return null if there's no connection specific data + virtual CRef CreateContext(void); + + // If CID2Processor needs to process replies too, it should create + // CID2ProcessorPacketContext object for later use in ProcessReply(). + // Otherwise it's allowed to return null. + // The context pointer should be the same returned from CreateContext() call. + virtual CRef ProcessPacket(CID2ProcessorContext* context, + CID2_Request_Packet& packet, + TReplies& replies); + + // Process reply from server + // The context pointer should be the same returned from CreateContext() call. + // The packet_context pointer should be the same returned from ProcessPacket() call. + virtual void ProcessReply(CID2ProcessorContext* context, + CID2ProcessorPacketContext* packet_context, + CID2_Reply& reply, + TReplies& replies); }; diff --git a/c++/include/objects/id2/id2processor_interface.hpp b/c++/include/objects/id2/id2processor_interface.hpp index fed6baef..12765d53 100644 --- a/c++/include/objects/id2/id2processor_interface.hpp +++ b/c++/include/objects/id2/id2processor_interface.hpp @@ -1,6 +1,6 @@ #ifndef OBJECTS_ID2_ID2PROCESSOR_INTERFACE__HPP_INCLUDED #define OBJECTS_ID2_ID2PROCESSOR_INTERFACE__HPP_INCLUDED -/* $Id: id2processor_interface.hpp 480290 2015-09-29 16:17:42Z vasilche $ +/* $Id: id2processor_interface.hpp 528537 2017-02-23 17:52:33Z vasilche $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information @@ -40,7 +40,7 @@ class CID2Processor; END_SCOPE(objects) -NCBI_DECLARE_INTERFACE_VERSION(objects::CID2Processor, "id2proc", 1, 0, 0); +NCBI_DECLARE_INTERFACE_VERSION(objects::CID2Processor, "id2proc", 2, 0, 0); template<> class NCBI_ID2_EXPORT CDllResolver_Getter diff --git a/c++/include/objects/macro/Location_constraint.hpp b/c++/include/objects/macro/Location_constraint.hpp index 03fe87b3..04d5d5be 100644 --- a/c++/include/objects/macro/Location_constraint.hpp +++ b/c++/include/objects/macro/Location_constraint.hpp @@ -1,4 +1,4 @@ -/* $Id: Location_constraint.hpp 436428 2014-05-28 13:28:28Z chenj $ +/* $Id: Location_constraint.hpp 539880 2017-06-28 14:56:36Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -62,13 +62,13 @@ public: ~CLocation_constraint(void); bool Match(const CSeq_feat& feat, CConstRef feat_to, CConstRef feat_bioseq) const; + bool IsEmpty() const; private: // Prohibit copy constructor and assignment operator CLocation_constraint(const CLocation_constraint& value); CLocation_constraint& operator=(const CLocation_constraint& value); - bool x_IsLocationConstraintEmpty() const; bool x_DoesStrandMatchConstraint(const CSeq_loc& loc) const; bool x_DoesBioseqMatchSequenceType(CConstRef bioseq, const ESeqtype_constraint& seq_type) const; diff --git a/c++/include/objects/macro/Search_func.hpp b/c++/include/objects/macro/Search_func.hpp index de47a7d9..d5b39a6d 100644 --- a/c++/include/objects/macro/Search_func.hpp +++ b/c++/include/objects/macro/Search_func.hpp @@ -1,4 +1,4 @@ -/* $Id: Search_func.hpp 450811 2014-10-30 17:34:54Z vasilche $ +/* $Id: Search_func.hpp 547096 2017-09-26 12:04:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -58,17 +58,13 @@ class CSearch_func : public CSearch_func_Base { typedef CSearch_func_Base Tparent; public: - // constructor - CSearch_func(void); - // destructor - ~CSearch_func(void); + CSearch_func() {} + ~CSearch_func() {} bool Empty() const; bool Match(const string& str) const; private: - string m_digit_str; - // Prohibit copy constructor and assignment operator CSearch_func(const CSearch_func& value); CSearch_func& operator=(const CSearch_func& value); @@ -106,23 +102,6 @@ private: bool x_ProductContainsTerm(const string& str, const string& pattern) const; }; -/////////////////// CSearch_func inline methods - -// constructor -inline -CSearch_func::CSearch_func(void) -{ - m_digit_str = "0123456789"; -} - - -/////////////////// end of CSearch_func inline methods - - END_objects_SCOPE // namespace ncbi::objects:: - END_NCBI_SCOPE - - #endif // OBJECTS_MACRO_SEARCH_FUNC_HPP -/* Original file checksum: lines: 86, chars: 2424, CRC32: f82e63c0 */ diff --git a/c++/include/objects/macro/String_constraint.hpp b/c++/include/objects/macro/String_constraint.hpp index c16c7241..2e5d3204 100644 --- a/c++/include/objects/macro/String_constraint.hpp +++ b/c++/include/objects/macro/String_constraint.hpp @@ -1,4 +1,4 @@ -/* $Id: String_constraint.hpp 494536 2016-03-08 14:06:47Z bollin $ +/* $Id: String_constraint.hpp 547096 2017-09-26 12:04:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -39,15 +39,11 @@ #ifndef OBJECTS_MACRO_STRING_CONSTRAINT_HPP #define OBJECTS_MACRO_STRING_CONSTRAINT_HPP -// generated includes #include #include #include -// generated classes - BEGIN_NCBI_SCOPE - BEGIN_objects_SCOPE // namespace ncbi::objects:: ///////////////////////////////////////////////////////////////////////////// @@ -55,10 +51,8 @@ class CString_constraint : public CString_constraint_Base { typedef CString_constraint_Base Tparent; public: - // constructor - CString_constraint(void); - // destructor - ~CString_constraint(void); + CString_constraint() {} + ~CString_constraint() {} // get all string type data from object template @@ -69,21 +63,19 @@ public: for (it = ConstBegin(obj); it; ++it) { strs.push_back(*static_cast(it.GetFoundPtr())); } - }; + } bool Match(const string& str) const; bool Empty() const; bool ReplaceStringConstraintPortionInString(string& val, const string& replace) const; private: - string m_digit_str, m_alpha_str; - // Prohibit copy constructor and assignment operator CString_constraint(const CString_constraint& value); CString_constraint& operator=(const CString_constraint& value); bool x_DoesSingleStringMatchConstraint (const string& str) const; - bool x_IsWeasel(const string& str) const; + bool x_IsWeasel(const CTempString& str) const; string x_SkipWeasel(const string& str) const; bool x_IsAllCaps(const string& str) const; bool x_IsAllLowerCase(const string& str) const; @@ -125,24 +117,8 @@ private: bool x_ReplaceContains(string& val, const string& replace) const; }; -/////////////////// CString_constraint inline methods - -// constructor -inline -CString_constraint::CString_constraint(void) -{ - m_digit_str = "0123456789"; - m_alpha_str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; -} - - -/////////////////// end of CString_constraint inline methods - END_objects_SCOPE // namespace ncbi::objects:: - END_NCBI_SCOPE - #endif // OBJECTS_MACRO_STRING_CONSTRAINT_HPP -/* Original file checksum: lines: 86, chars: 2538, CRC32: 9eb12277 */ diff --git a/c++/include/objects/macro/Suspect_rule.hpp b/c++/include/objects/macro/Suspect_rule.hpp index 5baa8ccf..edeb5014 100644 --- a/c++/include/objects/macro/Suspect_rule.hpp +++ b/c++/include/objects/macro/Suspect_rule.hpp @@ -1,4 +1,4 @@ -/* $Id: Suspect_rule.hpp 514101 2016-09-19 15:56:13Z ivanov $ +/* $Id: Suspect_rule.hpp 547096 2017-09-26 12:04:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -67,10 +67,8 @@ class CSuspect_rule : public CSuspect_rule_Base { typedef CSuspect_rule_Base Tparent; public: - // constructor - CSuspect_rule(void); - // destructor - ~CSuspect_rule(void); + CSuspect_rule() {} + ~CSuspect_rule() {} // C's MatchesSuspectProductRule() bool StringMatchesSuspectProductRule (const string& str) const; @@ -98,22 +96,7 @@ private: string SummarizeFieldType(const CField_type&) const; }; -/////////////////// CSuspect_rule inline methods - -// constructor -inline -CSuspect_rule::CSuspect_rule(void) -{ -} - - -/////////////////// end of CSuspect_rule inline methods - - END_objects_SCOPE // namespace ncbi::objects:: - END_NCBI_SCOPE - #endif // OBJECTS_MACRO_SUSPECT_RULE_HPP -/* Original file checksum: lines: 86, chars: 2443, CRC32: 48b7bd55 */ diff --git a/c++/include/objects/misc/sequence_util_macros.hpp b/c++/include/objects/misc/sequence_util_macros.hpp index 6474fd7c..7feb2a79 100644 --- a/c++/include/objects/misc/sequence_util_macros.hpp +++ b/c++/include/objects/misc/sequence_util_macros.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_MISC___SEQUENCE_UTIL_MACROS__HPP #define OBJECTS_MISC___SEQUENCE_UTIL_MACROS__HPP -/* $Id: sequence_util_macros.hpp 438547 2014-06-17 17:48:04Z kornbluh $ +/* $Id: sequence_util_macros.hpp 523854 2017-01-06 14:10:35Z kornbluh $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -534,6 +534,12 @@ DO_UNIQUE (CHAR_IN_STRING, Var, Func) #define GET_FIELD_OR_DEFAULT(Var, Fld, Dflt) \ ((Var).IsSet##Fld() ? (Var).Get##Fld() : Dflt ) + +/// GET_FIELD_CHOICE_OR_DEFAULT base macro + +#define GET_FIELD_CHOICE_OR_DEFAULT(Var, Fld, Dflt) \ + ((Var).Is##Fld() ? (Var).Get##Fld() : Dflt ) + /// GET_MUTABLE base macro diff --git a/c++/include/objects/pub/Pub.hpp b/c++/include/objects/pub/Pub.hpp index af2b49ef..aa1e12a9 100644 --- a/c++/include/objects/pub/Pub.hpp +++ b/c++/include/objects/pub/Pub.hpp @@ -1,4 +1,4 @@ -/* $Id: Pub.hpp 452468 2014-11-20 13:44:46Z bollin $ +/* $Id: Pub.hpp 548112 2017-10-10 17:31:15Z fukanchi $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -84,6 +84,7 @@ public: // convenience functions to get author list from underlying pub bool IsSetAuthors(void) const; const CAuth_list& GetAuthors(void) const; + CAuth_list& SetAuthors(void); typedef CConstRef TOneTitleRef; typedef vector TOneTitleRefVec; diff --git a/c++/include/objects/seq/Seq_inst.hpp b/c++/include/objects/seq/Seq_inst.hpp index d10cc3e1..4db4b674 100644 --- a/c++/include/objects/seq/Seq_inst.hpp +++ b/c++/include/objects/seq/Seq_inst.hpp @@ -1,4 +1,4 @@ -/* $Id: Seq_inst.hpp 518949 2016-11-09 16:44:19Z ivanov $ +/* $Id: Seq_inst.hpp 518811 2016-11-08 13:43:55Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objects/seq/seq_id_handle.hpp b/c++/include/objects/seq/seq_id_handle.hpp index a1a8cac8..59a56f96 100644 --- a/c++/include/objects/seq/seq_id_handle.hpp +++ b/c++/include/objects/seq/seq_id_handle.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR___SEQ_ID_HANDLE__HPP #define OBJECTS_OBJMGR___SEQ_ID_HANDLE__HPP -/* $Id: seq_id_handle.hpp 463550 2015-03-30 15:20:32Z vasilche $ +/* $Id: seq_id_handle.hpp 536335 2017-05-17 17:34:54Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -203,7 +203,7 @@ public: bool NCBI_SEQ_EXPORT operator== (const CSeq_id& id) const; /// Compare ids in a defined order (see CSeq_id::CompareOrdered()) - TIntId NCBI_SEQ_EXPORT CompareOrdered(const CSeq_id_Handle& id) const; + int NCBI_SEQ_EXPORT CompareOrdered(const CSeq_id_Handle& id) const; /// Predicate for sorting CSeq_id_Handles in a defined order. struct PLessOrdered { diff --git a/c++/include/objects/seq/seq_loc_mapper_base.hpp b/c++/include/objects/seq/seq_loc_mapper_base.hpp index 73c0be7d..1d65d0f0 100644 --- a/c++/include/objects/seq/seq_loc_mapper_base.hpp +++ b/c++/include/objects/seq/seq_loc_mapper_base.hpp @@ -1,7 +1,7 @@ #ifndef SEQ_LOC_MAPPER_BASE__HPP #define SEQ_LOC_MAPPER_BASE__HPP -/* $Id: seq_loc_mapper_base.hpp 505917 2016-06-29 20:22:14Z grichenk $ +/* $Id: seq_loc_mapper_base.hpp 543871 2017-08-15 12:17:04Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -420,6 +420,13 @@ public: CSeq_loc_Mapper_Base(const CSeq_align& map_align, const CSeq_id& to_id, CSeq_loc_Mapper_Options options = CSeq_loc_Mapper_Options()); + /// Mapping through an alignment using specific source and target ids. + /// If the alignment is not one of dense-seg, dense-diag or packed-seg, the source + /// id is ignored. + CSeq_loc_Mapper_Base(const CSeq_id& from_id, + const CSeq_id& to_id, + const CSeq_align& map_align, + CSeq_loc_Mapper_Options options = CSeq_loc_Mapper_Options()); /// @deprecated Use the version with CSeq_loc_Mapper_Options instead. NCBI_DEPRECATED CSeq_loc_Mapper_Base(const CSeq_align& map_align, @@ -433,6 +440,13 @@ public: CSeq_loc_Mapper_Base(const CSeq_align& map_align, size_t to_row, CSeq_loc_Mapper_Options options = CSeq_loc_Mapper_Options()); + /// Mapping through an alignment using specific source and target row numbers. + /// If the alignment is not one of dense-seg, dense-diag or packed-seg, the source + /// row is ignored. + CSeq_loc_Mapper_Base(size_t from_row, + size_t to_row, + const CSeq_align& map_align, + CSeq_loc_Mapper_Options options = CSeq_loc_Mapper_Options()); /// @deprecated Use the version with CSeq_loc_Mapper_Options instead. NCBI_DEPRECATED CSeq_loc_Mapper_Base(const CSeq_align& map_align, @@ -605,13 +619,16 @@ protected: // row containing the id and sets it as mapping target. All other // rows become mapping source. void x_InitializeAlign(const CSeq_align& map_align, - const CSeq_id& to_id); + const CSeq_id& to_id, + const CSeq_id* from_id = nullptr); // Recursive version of the above. void x_InitializeAlign(const CSeq_align& map_align, - const TSynonyms& to_ids); + const TSynonyms& to_ids, + const TSynonyms* from_ids = nullptr); // Initialize the mapper from an alignment, map to the specified row. void x_InitializeAlign(const CSeq_align& map_align, - size_t to_row); + size_t to_row, + size_t from_row = size_t(-1)); // Create dummy mapping from the whole destination location to itself. // This will prevent truncation of ranges already on the target. @@ -750,10 +767,10 @@ private: TSeqPos x_GetRangeLength(const CSeq_loc_CI& it); // Initialize the mapper from different alignment types. - void x_InitAlign(const CDense_diag& diag, size_t to_row); - void x_InitAlign(const CDense_seg& denseg, size_t to_row); + void x_InitAlign(const CDense_diag& diag, size_t to_row, size_t from_row); + void x_InitAlign(const CDense_seg& denseg, size_t to_row, size_t from_row); void x_InitAlign(const CStd_seg& sseg, size_t to_row); - void x_InitAlign(const CPacked_seg& pseg, size_t to_row); + void x_InitAlign(const CPacked_seg& pseg, size_t to_row, size_t from_row); void x_InitSpliced(const CSpliced_seg& spliced, const TSynonyms& to_ids); void x_InitSpliced(const CSpliced_seg& spliced, ESplicedRow to_row); diff --git a/c++/include/objects/seq/so_map.hpp b/c++/include/objects/seq/so_map.hpp new file mode 100644 index 00000000..8de52abe --- /dev/null +++ b/c++/include/objects/seq/so_map.hpp @@ -0,0 +1,127 @@ +/* $Id: so_map.hpp 536008 2017-05-15 14:05:40Z ludwigf $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Frank Ludwig + * + * File Description: Sequence Ontology Type Mapping + * + */ + +#ifndef OBJECTS___SOMAP__HPP +#define OBJECTS___SOMAP__HPP + +#include +#include + +BEGIN_NCBI_SCOPE +BEGIN_objects_SCOPE + +class CSeq_feat; + +// ============================================================================ +class CompareNoCase +// ============================================================================ +{ +public: + bool operator()(const string& x, const string& y) const; +}; + +// ============================================================================ +class NCBI_SEQ_EXPORT CSoMap +// ============================================================================ +{ +public: + static std::string SoTypeToId( + const std::string&); + static std::string SoIdToType( + const std::string&); + + static bool SoTypeToFeature( + const string&, + CSeq_feat&); + static bool FeatureToSoType( + const CSeq_feat&, + string&); + + static bool GetSupportedSoTerms( + vector&); + + static string ResolveSoAlias( + const string&); + +protected: + static bool xCompareNoCase(const string&, const string&); + + static bool xFeatureMakeGene(const string&, CSeq_feat&); + static bool xFeatureMakeCds(const string&, CSeq_feat&); + static bool xFeatureMakeRna(const string&, CSeq_feat&); + static bool xFeatureMakeMiscFeature(const string&, CSeq_feat&); + static bool xFeatureMakeMiscRecomb(const string&, CSeq_feat&); + static bool xFeatureMakeMiscRna(const string&, CSeq_feat&); + static bool xFeatureMakeNcRna(const string&, CSeq_feat&); + static bool xFeatureMakeImp(const string&, CSeq_feat&); + static bool xFeatureMakeProt(const string&, CSeq_feat&); + static bool xFeatureMakeRegion(const string&, CSeq_feat&); + static bool xFeatureMakeRegulatory(const string&, CSeq_feat&); + static bool xFeatureMakeRepeatRegion(const string&, CSeq_feat&); + + static bool xMapGeneric(const CSeq_feat&, string&); + static bool xMapGene(const CSeq_feat&, string&); + static bool xMapCds(const CSeq_feat&, string&); + static bool xMapMiscFeature(const CSeq_feat&, string&); + static bool xMapMiscRecomb(const CSeq_feat&, string&); + static bool xMapRna(const CSeq_feat&, string&); + static bool xMapNcRna(const CSeq_feat&, string&); + static bool xMapOtherRna(const CSeq_feat&, string&); + static bool xMapRegion(const CSeq_feat&, string&); + static bool xMapRegulatory(const CSeq_feat&, string&); + static bool xMapRepeatRegion(const CSeq_feat&, string&); + static bool xMapBond(const CSeq_feat&, string&); + + + using TYPEMAP = map; + using TYPEENTRY = TYPEMAP::const_iterator; + static TYPEMAP mMapSoTypeToId; + static TYPEMAP mMapSoIdToType; + + using FEATFUNC = bool(*)(const string&, CSeq_feat&); + using FEATFUNCMAP = map; + using FEATFUNCENTRY = FEATFUNCMAP::const_iterator; + static FEATFUNCMAP mMapFeatFunc; + + using TYPEFUNC = bool(*)(const CSeq_feat&, string&); + using TYPEFUNCMAP = map; + using TYPEFUNCENTRY = TYPEFUNCMAP::const_iterator; + static TYPEFUNCMAP mMapTypeFunc; + + using SOALIASMAP = map; + using ALIASENTRY = SOALIASMAP::const_iterator; + static SOALIASMAP mMapSoAliases; +}; + +END_objects_SCOPE +END_NCBI_SCOPE + +#endif // OBJECTS___SOMAP__HPP diff --git a/c++/include/objects/seq/sofa_map.hpp b/c++/include/objects/seq/sofa_map.hpp index 08c75172..ea9b1e55 100644 --- a/c++/include/objects/seq/sofa_map.hpp +++ b/c++/include/objects/seq/sofa_map.hpp @@ -1,4 +1,4 @@ -/* $Id: sofa_map.hpp 493092 2016-02-24 12:36:34Z ludwigf $ +/* $Id: sofa_map.hpp 533585 2017-04-18 13:44:28Z ludwigf $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,6 +32,7 @@ #ifndef OBJECTS___SOFAMAP__HPP #define OBJECTS___SOFAMAP__HPP +#include #include #include @@ -72,11 +73,19 @@ public: return m_Map; } + static std::string SofaTypeToId(const std::string&); + static std::string SofaIdToType(const std::string&); + protected: void x_Init(); map< CFeatListItem, SofaType > m_Map; SofaType m_default; + + using TYPEMAP = map; + using TYPEENTRY = TYPEMAP::const_iterator; + static TYPEMAP mMapSofaTypeToId; + static TYPEMAP mMapSofaIdToType; }; END_objects_SCOPE diff --git a/c++/include/objects/seqalign/Dense_seg.hpp b/c++/include/objects/seqalign/Dense_seg.hpp index 3d412ee4..54c99c21 100644 --- a/c++/include/objects/seqalign/Dense_seg.hpp +++ b/c++/include/objects/seqalign/Dense_seg.hpp @@ -1,4 +1,4 @@ -/* $Id: Dense_seg.hpp 348915 2012-01-05 17:03:37Z vasilche $ +/* $Id: Dense_seg.hpp 528859 2017-02-27 16:18:20Z astashya $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -179,7 +179,7 @@ private: NCBISER_HAVE_GLOBAL_READ_MEMBER_HOOK(CDense_seg, "starts,lens,strands", - new CDense_seg::CReserveHook); + new CDense_seg::CReserveHook) /////////////////// CDense_seg inline methods diff --git a/c++/include/objects/seqalign/Seq_align.hpp b/c++/include/objects/seqalign/Seq_align.hpp index d6553be5..034b7d79 100644 --- a/c++/include/objects/seqalign/Seq_align.hpp +++ b/c++/include/objects/seqalign/Seq_align.hpp @@ -1,4 +1,4 @@ -/* $Id: Seq_align.hpp 433851 2014-04-30 14:36:29Z mozese2 $ +/* $Id: Seq_align.hpp 522940 2016-12-26 16:05:34Z mozese2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -239,6 +239,10 @@ public: /// of gaps with a length that is not a multiple of 3. /// @throws CSeqalignException if alignment type is not supported TSeqPos GetNumFrameshifts(TDim row = -1) const; + TSeqPos GetNumFrameshiftsWithinRange(const TSeqRange &range, + TDim row = -1) const; + TSeqPos GetNumFrameshiftsWithinRanges(const CRangeCollection &ranges, + TDim row = -1) const; /// Retrieves the locations of aligned bases in the given row, excluding /// gaps and incontinuities diff --git a/c++/include/objects/seqfeat/BioSource.hpp b/c++/include/objects/seqfeat/BioSource.hpp index 4812637c..7f61937d 100644 --- a/c++/include/objects/seqfeat/BioSource.hpp +++ b/c++/include/objects/seqfeat/BioSource.hpp @@ -1,4 +1,4 @@ -/* $Id: BioSource.hpp 512289 2016-08-29 18:14:36Z ivanov $ +/* $Id: BioSource.hpp 547249 2017-09-27 17:35:12Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -135,7 +135,9 @@ public: bool RemoveLineageSourceNotes(); bool RemoveSubSource(int subtype); + bool RemoveSubSource(int subtype, const string& val); bool RemoveOrgMod(int subtype); + bool RemoveOrgMod(int subtype, const string& val); //If taxname starts with uncultured, set environmental-sample to true //If metagenomic, set environmental_sample @@ -172,6 +174,7 @@ public: bool HasSubtype(CSubSource::TSubtype subtype) const; CRef MakeCommon( const CBioSource& other) const; + CRef MakeCommonExceptOrg(const CBioSource& other) const; private: // Prohibit copy constructor and assignment operator diff --git a/c++/include/objects/seqfeat/Gb_qual.hpp b/c++/include/objects/seqfeat/Gb_qual.hpp index fb5710a7..c755ca89 100644 --- a/c++/include/objects/seqfeat/Gb_qual.hpp +++ b/c++/include/objects/seqfeat/Gb_qual.hpp @@ -1,4 +1,4 @@ -/* $Id: Gb_qual.hpp 514391 2016-09-21 15:38:23Z ivanov $ +/* $Id: Gb_qual.hpp 530452 2017-03-15 13:15:00Z dobronad $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -81,18 +81,22 @@ public: typedef CStaticArraySet TLegalRepeatTypeSet; static const TLegalRepeatTypeSet &GetSetOfLegalRepeatTypes(void); static bool IsValidRptTypeValue(const string& val); + static bool FixRptTypeValue(string& val); // for pseudogene qualifiers typedef CStaticArraySet TLegalPseudogeneSet; static const TLegalPseudogeneSet &GetSetOfLegalPseudogenes(void); static bool IsValidPseudogeneValue(const string& val); + static bool FixPseudogeneValue(string& val); // for misc_recomb qualifiers typedef CStaticArraySet TLegalRecombinationClassSet; static const TLegalRecombinationClassSet &GetSetOfLegalRecombinationClassValues(void); + static bool FixRecombinationClassValue(string& val); static bool IsLegalMobileElementValue(const string& val); static void GetMobileElementValueElements(const string& val, string& element_type, string& element_name); + static bool FixMobileElementValue(string& val); static bool IsIllegalQualName(const string& val); diff --git a/c++/include/objects/seqfeat/Genetic_code_table.hpp b/c++/include/objects/seqfeat/Genetic_code_table.hpp index deb62492..1cdeb656 100644 --- a/c++/include/objects/seqfeat/Genetic_code_table.hpp +++ b/c++/include/objects/seqfeat/Genetic_code_table.hpp @@ -1,4 +1,4 @@ -/* $Id: Genetic_code_table.hpp 103491 2007-05-04 17:18:18Z kazimird $ +/* $Id: Genetic_code_table.hpp 537787 2017-06-03 16:46:26Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -109,6 +109,7 @@ public: // lookup of amino acid translated for given codon (state) char GetCodonResidue (int state) const; char GetStartResidue (int state) const; + char GetStopResidue (int state) const; bool IsOrfStart (int state) const; bool IsAmbigStart (int state) const; @@ -129,6 +130,7 @@ private: // translation tables specific to each genetic code instance mutable char m_AminoAcid [4097]; mutable char m_OrfStart [4097]; + mutable char m_OrfStop [4097]; // initialize genetic code specific translation tables void x_InitFsaTransl (const string *ncbieaa, @@ -234,6 +236,13 @@ char CTrans_table::GetStartResidue (int state) const return (m_OrfStart [state]); } +inline +char CTrans_table::GetStopResidue (int state) const +{ + if (state < 0 || state > 4096) return 0; + return (m_OrfStop [state]); +} + inline bool CTrans_table::IsOrfStart (int state) const { @@ -255,7 +264,7 @@ bool CTrans_table::IsAnyStart (int state) const inline bool CTrans_table::IsOrfStop (int state) const { - return (GetCodonResidue (state) == '*'); + return (GetStopResidue (state) == '*'); } inline diff --git a/c++/include/objects/seqfeat/OrgMod.hpp b/c++/include/objects/seqfeat/OrgMod.hpp index 716a84bb..f08dd12c 100644 --- a/c++/include/objects/seqfeat/OrgMod.hpp +++ b/c++/include/objects/seqfeat/OrgMod.hpp @@ -1,4 +1,4 @@ -/* $Id: OrgMod.hpp 515540 2016-10-03 16:03:50Z ivanov $ +/* $Id: OrgMod.hpp 535708 2017-05-11 10:58:04Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -85,6 +85,7 @@ public: static bool HoldsInstitutionCode(const TSubtype stype); static bool ParseStructuredVoucher(const string& str, string& inst, string& coll, string& id); + static bool IsInstitutionCodeValid(const string& inst_coll, string &voucher_type, bool& is_miscapitalized, string& correct_cap, bool& needs_country, bool& erroneous_country); static string IsCultureCollectionValid(const string& culture_collection); static string IsSpecimenVoucherValid(const string& specimen_voucher); @@ -93,6 +94,7 @@ public: static string MakeStructuredVoucher(const string& inst, const string& coll, const string& id); static bool FixStructuredVoucher(string& val, const string& voucher_type); static bool AddStructureToVoucher(string& val, const string& voucher_type); + static bool RescueInstFromParentheses(string& val, const string& voucher_type); static string CheckMultipleVouchers(const vector&); //e.g. "DMNS:Bird" to "Denver Museum of Nature and Science, Ornithology Collections" @@ -120,11 +122,21 @@ public: static bool IsUnexpectedViralOrgModQualifier(TSubtype subtype); bool IsUnexpectedViralOrgModQualifier() const; + // for type material + static bool IsValidTypeMaterial(const string& type_material); + // note that the INSDC definition is currently lagging behind what is considered + // valid for taxonomy + static bool IsINSDCValidTypeMaterial(const string& type_material); + + typedef map TInstitutionCodeMap; private: // Prohibit copy constructor and assignment operator COrgMod(const COrgMod& value); COrgMod& operator=(const COrgMod& value); + static TInstitutionCodeMap::iterator FindInstitutionCode(const string& inst_coll, TInstitutionCodeMap& code_map, + bool& is_miscapitalized, string& correct_cap, bool& needs_country, bool& erroneous_country); + }; /////////////////// COrgMod inline methods diff --git a/c++/include/objects/seqfeat/OrgName.hpp b/c++/include/objects/seqfeat/OrgName.hpp index 71cd8647..55216176 100644 --- a/c++/include/objects/seqfeat/OrgName.hpp +++ b/c++/include/objects/seqfeat/OrgName.hpp @@ -1,4 +1,4 @@ -/* $Id: OrgName.hpp 452696 2014-11-24 15:23:55Z bollin $ +/* $Id: OrgName.hpp 542754 2017-08-02 14:33:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -72,8 +72,22 @@ public: bool IsUncultured() const; void SetUncultured( bool bUncultured ); + // Modifier forwarding flag. Used during org-ref lookup to enable/disable + // modifier forwarding. If set modifier forwarding is disabled. + // Flag is kept along with other flags in orgname.attrib field + // (see comments to x_SetAttribFlag() function) + bool IsModifierForwardingDisabled() const; + void DisableModifierForwarding(); + void EnableModifierForwarding(); + CRef MakeCommon(const COrgName& other) const; + // Nomenclature information stored in attrib field as string in following format: + // nomenclature=[BPVZ]*; + bool GetNomenclature( string& result ) const; + bool SetNomenclature( const string& nomenclature ); // False if value is unsupported + void ResetNomenclature(); + private: // Prohibit copy constructor and assignment operator COrgName(const COrgName& value); @@ -81,9 +95,12 @@ private: // The proposed format for orgname flags: flagname1;[flagname2;]... // where flagnameX consists of ascii alphanum characters only. Each value of flagnameX is unique. // Presence of flag name in the strings means 'true' value for the flag. - void x_SetAttribFlag( const string& name ); - void x_ResetAttribFlag( const string& name ); - bool x_GetAttribFlag( const string& name ) const; + void x_SetAttribFlag( const string& name, bool bStartsWith = false ); + void x_ResetAttribFlag( const string& name, bool bStartsWith = false ); + bool x_GetAttribFlag( const string& name, bool bStartsWith = false ) const; + // Getting attribute value for pairs like attrname=value; + // value cannot contain ';' + bool x_GetAttribValue( const string& name, string& sValue ) const; }; diff --git a/c++/include/objects/seqfeat/Org_ref.hpp b/c++/include/objects/seqfeat/Org_ref.hpp index 54f11207..93dd2180 100644 --- a/c++/include/objects/seqfeat/Org_ref.hpp +++ b/c++/include/objects/seqfeat/Org_ref.hpp @@ -1,4 +1,4 @@ -/* $Id: Org_ref.hpp 452696 2014-11-24 15:23:55Z bollin $ +/* $Id: Org_ref.hpp 542755 2017-08-02 14:33:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -51,6 +51,44 @@ class NCBI_SEQFEAT_EXPORT COrg_ref : public COrg_ref_Base { typedef COrg_ref_Base Tparent; public: + enum EOrgref_part { + eOrgref_nothing = 0, + eOrgref_taxname = 0x0010, // org-ref.taxname + eOrgref_common = 0x0040, // org-ref.common + eOrgref_mod = 0x0800, // org-ref.mod + + eOrgref_db = 0x2000, // org-ref.db + eOrgref_db_taxid = 0x0001, // org-ref.db[@dbtag='taxon'] + eOrgref_db_all = (eOrgref_db | eOrgref_db_taxid), + + eOrgref_syn = 0x4000, // org-ref.syn + + eOrgref_orgname = 0x0008, // org-ref.orgname + eOrgref_on_name = 0x0080, // org-ref.orgname.name + eOrgref_on_attr = 0x1000, // org-ref.orgname.attrib + eOrgref_on_attr_spec = 0x00010000, // org-ref.orgname.attrib[.='specified'] + eOrgref_on_attr_nom = 0x00020000, // org-ref.orgname.attrib[.='nomenclature'] + eOrgref_on_attr_nofwd= 0x00040000, // org-ref.orgname.attrib[.='nomodforward'] + eOrgref_on_attr_all = (eOrgref_on_attr | eOrgref_on_attr_spec | eOrgref_on_attr_nom | eOrgref_on_attr_nofwd), + eOrgref_on_mod = 0x0200, // org-ref.orgname.mod + eOrgref_on_lin = 0x0020, // org-ref.orgname.lineage + eOrgref_on_gc = 0x0002, // org-ref.orgname.gcode + eOrgref_on_mgc = 0x0004, // org-ref.orgname.mgcode + eOrgref_on_pgc = 0x0400, // org-ref.orgname.pgcode + eOrgref_on_div = 0x0100, // org-ref.orgname.div + eOrgref_on_all = (eOrgref_orgname | eOrgref_on_name | eOrgref_on_attr_all | eOrgref_on_mod | + eOrgref_on_lin | eOrgref_on_gc | eOrgref_on_mgc | eOrgref_on_pgc | eOrgref_on_div), + + eOrgref_all = (eOrgref_taxname | eOrgref_common | eOrgref_mod | eOrgref_db | eOrgref_syn | + eOrgref_on_all), + + eOrgref_all_but_syn = (eOrgref_all ^ eOrgref_syn), // all but synonyms + eOrgref_all_but_spec = (eOrgref_all ^ eOrgref_on_attr_spec), // all but orgname's 'specified' attribute + + eOrgref_default = eOrgref_all + }; + typedef unsigned int fOrgref_parts; + // constructor COrg_ref(void); // destructor @@ -90,6 +128,13 @@ public: CRef MakeCommon(const COrg_ref& other) const; + static CConstRef TableLookup(const string& taxname); + static const vector& GetTaxnameList(); + bool UpdateFromTable(); + + void CleanForGenBank(); + + void FilterOutParts( fOrgref_parts to_remain ); private: // Prohibit copy constructor and assignment operator COrg_ref(const COrg_ref& value); diff --git a/c++/include/objects/seqfeat/RNA_gen.hpp b/c++/include/objects/seqfeat/RNA_gen.hpp index c5db0311..faef4bc9 100644 --- a/c++/include/objects/seqfeat/RNA_gen.hpp +++ b/c++/include/objects/seqfeat/RNA_gen.hpp @@ -1,4 +1,4 @@ -/* $Id: RNA_gen.hpp 205706 2010-09-21 16:23:39Z dicuccio $ +/* $Id: RNA_gen.hpp 530446 2017-03-15 12:29:49Z dobronad $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -60,6 +60,9 @@ public: ~CRNA_gen(void); bool IsLegalClass() const; + static bool IsLegalClass(const string& val); + static vector GetncRNAClassList(); + static bool FixncRNAClassValue(string& val); private: // Prohibit copy constructor and assignment operator diff --git a/c++/include/objects/seqfeat/SeqFeatData.hpp b/c++/include/objects/seqfeat/SeqFeatData.hpp index 96c85f93..c6c101fe 100644 --- a/c++/include/objects/seqfeat/SeqFeatData.hpp +++ b/c++/include/objects/seqfeat/SeqFeatData.hpp @@ -1,4 +1,4 @@ -/* $Id: SeqFeatData.hpp 514392 2016-09-21 15:38:46Z ivanov $ +/* $Id: SeqFeatData.hpp 542865 2017-08-03 17:11:32Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -230,8 +230,9 @@ public: eSubtype_telomere = 101, eSubtype_assembly_gap = 102, eSubtype_regulatory = 103, - eSubtype_propeptide = 104, // Prot-ref propeptide - eSubtype_max = 105, + eSubtype_propeptide = 104, // use eSubtype_propeptide_aa + eSubtype_propeptide_aa = 105, // Prot-ref propeptide + eSubtype_max = 106, eSubtype_any = 255 }; ESubtype GetSubtype(void) const; @@ -312,6 +313,9 @@ public: /// eSubtype_bad on bad input static ESubtype SubtypeNameToValue(const string & sName); + + static bool CanHaveGene(ESubtype subtype); + /// List of available qualifiers for feature keys. /// For more information see: /// The DDBJ/EMBL/GenBank Feature Table: Definition @@ -486,6 +490,9 @@ public: static const string & GetRegulatoryClass(ESubtype subtype); static ESubtype GetRegulatoryClass(const string & class_name ); static vector GetRegulatoryClassList(); + static bool FixRegulatoryClassValue(string& val); + + static vector GetRecombinationClassList(); static bool IsDiscouragedSubtype(ESubtype subtype); static bool IsDiscouragedQual(EQualifier qual); @@ -511,6 +518,8 @@ public: static bool AllowXref(CSeqFeatData::ESubtype subtype1, CSeqFeatData::ESubtype subtype2); static bool ProhibitXref(CSeqFeatData::ESubtype subtype1, CSeqFeatData::ESubtype subtype2); + static bool FixImportKey(string& key); + // Internal structure to hold additional info struct SFeatDataInfo { diff --git a/c++/include/objects/seqfeat/Seq_feat.hpp b/c++/include/objects/seqfeat/Seq_feat.hpp index 1b27e25f..e2c87250 100644 --- a/c++/include/objects/seqfeat/Seq_feat.hpp +++ b/c++/include/objects/seqfeat/Seq_feat.hpp @@ -1,4 +1,4 @@ -/* $Id: Seq_feat.hpp 518385 2016-11-02 17:27:05Z ivanov $ +/* $Id: Seq_feat.hpp 518014 2016-10-31 12:23:17Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objects/seqfeat/SubSource.hpp b/c++/include/objects/seqfeat/SubSource.hpp index 3a3ce221..7286a667 100644 --- a/c++/include/objects/seqfeat/SubSource.hpp +++ b/c++/include/objects/seqfeat/SubSource.hpp @@ -1,4 +1,4 @@ -/* $Id: SubSource.hpp 502999 2016-05-31 15:35:13Z bollin $ +/* $Id: SubSource.hpp 541342 2017-07-17 15:58:04Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -116,7 +116,7 @@ public: static bool IsCollectionDateAfterTime(const CDate& collection_date, time_t t); static bool IsCollectionDateAfterTime(const CDate& collection_date, CTime& ctime); - static bool IsISOFormatTime(const string& orig_time, int& hour, int& min, int& sec); + static bool IsISOFormatTime(const string& orig_time, int& hour, int& min, int& sec, bool require_time_zone = true); static bool IsISOFormatDateOnly(const string& date); static bool IsISOFormatDate (const string& orig_date); static CRef GetDateFromISODate(const string& orig_date); @@ -180,6 +180,7 @@ public: double& lat_value, double& lon_value); static string FixLatLonFormat (string orig_lat_lon, bool guess = false); static string MakeLatLon(double lat_value, double lon_value); + static string FixLatLonPrecision(const string& orig); enum ELatLonCountryErr { eLatLonCountryErr_None = 0, @@ -222,6 +223,8 @@ private: static string x_ParseDateRangeWithDelimiter(const string& orig_date, CTempString delim); static vector x_GetDateTokens(const string& orig_date); static CLatLonCountryId * x_CalculateLatLonId(float lat_value, float lon_value, string country, string province); + static bool x_IsFixableIsoDate(const string& orig_date); + static string x_RemoveIsoTime(const string& orig_date); static int x_GetPrecision(const string& num_str); static string x_FormatWithPrecision(double val, int precision); diff --git a/c++/include/objects/seqloc/Seq_id.hpp b/c++/include/objects/seqloc/Seq_id.hpp index 306a098c..5eaaa003 100644 --- a/c++/include/objects/seqloc/Seq_id.hpp +++ b/c++/include/objects/seqloc/Seq_id.hpp @@ -1,4 +1,4 @@ -/* $Id: Seq_id.hpp 488743 2016-01-05 15:59:17Z ucko $ +/* $Id: Seq_id.hpp 542765 2017-08-02 14:41:08Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -285,6 +285,7 @@ public: eAcc_gb_wgs_prot = e_Genbank | eAcc_wgs | fAcc_prot, // EAA eAcc_gb_wgsm_nuc = e_Genbank | eAcc_wgs_master | fAcc_nuc, eAcc_gb_wgsm_prot = e_Genbank | eAcc_wgs_master | fAcc_prot, + eAcc_gb_chromosome = e_Genbank | eAcc_chromosome | fAcc_nuc, // CM eAcc_gb_sts = e_Genbank | eAcc_sts | fAcc_nuc, // G eAcc_gb_mga = e_Genbank | eAcc_mga | fAcc_nuc, // unused eAcc_gb_optical_map = e_Genbank | eAcc_optical_map| fAcc_nuc, // MAP_ @@ -297,6 +298,7 @@ public: eAcc_embl_patent = e_Embl | eAcc_div_patent | fAcc_nuc, // A eAcc_embl_tsa_nuc = e_Embl | eAcc_tsa | fAcc_nuc, // IAAA eAcc_embl_tsa_prot = e_Embl | eAcc_tsa | fAcc_prot, // unused + eAcc_embl_gss = e_Embl | eAcc_gss | fAcc_nuc, // AJ864682 eAcc_embl_genome = e_Embl | eAcc_genome | fAcc_nuc, // unused eAcc_embl_htgs = e_Embl | eAcc_htgs | fAcc_nuc, // unused eAcc_embl_con = e_Embl | eAcc_con | fAcc_nuc, // AN @@ -354,12 +356,14 @@ public: eAcc_ddbj_wgsm_nuc = e_Ddbj | eAcc_wgs_master | fAcc_nuc, eAcc_ddbj_wgsm_prot = e_Ddbj | eAcc_wgs_master | fAcc_prot, eAcc_ddbj_mga = e_Ddbj | eAcc_mga | fAcc_nuc, // AAAAA + eAcc_ddbj_targeted_nuc=e_Ddbj| eAcc_targeted | fAcc_nuc, // TAAA eAcc_prf = e_Prf | eAcc_other | fAcc_prot, eAcc_pdb = e_Pdb | eAcc_other, // not necessarily protein! - eAcc_gb_tpa_nuc = e_Tpg | eAcc_other | fAcc_nuc, // BK - eAcc_gb_tpa_prot = e_Tpg | eAcc_other | fAcc_prot, // DAA + eAcc_gb_tpa_nuc = e_Tpg | eAcc_other | fAcc_nuc, // BK + eAcc_gb_tpa_prot = e_Tpg | eAcc_other | fAcc_prot, // DAA + eAcc_gb_tpa_segset = e_Tpg | eAcc_segset | fAcc_nuc, // BL eAcc_gb_tpa_con = e_Tpg | eAcc_con | fAcc_nuc, // GJ eAcc_gb_tpa_wgs_nuc = e_Tpg | eAcc_wgs | fAcc_nuc, // DAAA eAcc_gb_tpa_wgs_prot = e_Tpg | eAcc_wgs | fAcc_prot, // HAA @@ -423,7 +427,7 @@ public: /// Compare() - more general E_SIC Compare(const CSeq_id& sid2) const; - TIntId CompareOrdered(const CSeq_id& sid2) const; + int CompareOrdered(const CSeq_id& sid2) const; bool operator<(const CSeq_id& sid2) const { return CompareOrdered(sid2) < 0; @@ -537,6 +541,10 @@ public: /// All rankings give a slight bonus to accessions that carry /// versions. + enum EMaxScore { + kMaxScore = 99999 + }; + int AdjustScore (int base_score) const; int BaseTextScore (void) const; int BaseBestRankScore (void) const; @@ -575,6 +583,13 @@ public: /// @sa GetMatchingIds void GetMatchingTextseqIds(TSeqIdHandles& matches) const; + /// Check if the option to prefer accession.version over GI is enabled + /// (SeqId/PreferAccessionOverGi or SEQ_ID_PREFER_ACCESSION_OVER_GI). + static bool PreferAccessionOverGi(void); + /// Check if the option to avoid GI ids is enabled + /// (SeqId/AvoidGi or SEQ_ID_AVOID_GI). + static bool AvoidGi(void); + private: // returns next type if determined along the way E_Choice x_Init(list& fasta_pieces, E_Choice type); diff --git a/c++/include/objects/seqloc/Seq_loc.hpp b/c++/include/objects/seqloc/Seq_loc.hpp index b8c7d3e1..f02fa3d3 100644 --- a/c++/include/objects/seqloc/Seq_loc.hpp +++ b/c++/include/objects/seqloc/Seq_loc.hpp @@ -1,4 +1,4 @@ -/* $Id: Seq_loc.hpp 495960 2016-03-22 19:19:34Z grichenk $ +/* $Id: Seq_loc.hpp 537696 2017-06-02 15:08:20Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -240,7 +240,9 @@ public: /// Invalidate id/range cache after deserialization. void PostRead(void) const; - /// Compare locations. + /// Compare locations by total range for each seq-id. + /// Compares seq-ids (@sa CSeq_loc::CompareOrdered()), then compares + /// total range starts (left to right) and lengths (longerst first). int Compare(const CSeq_loc& loc) const; /// Used as a helper for determining which pieces of a diff --git a/c++/include/objects/seqset/Bioseq_set.hpp b/c++/include/objects/seqset/Bioseq_set.hpp index c866e614..2b6ae598 100644 --- a/c++/include/objects/seqset/Bioseq_set.hpp +++ b/c++/include/objects/seqset/Bioseq_set.hpp @@ -1,4 +1,4 @@ -/* $Id: Bioseq_set.hpp 519216 2016-11-14 16:06:08Z ivanov $ +/* $Id: Bioseq_set.hpp 518925 2016-11-09 14:19:55Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objects/taxon1/taxon1.hpp b/c++/include/objects/taxon1/taxon1.hpp index d985b613..92c1c9af 100644 --- a/c++/include/objects/taxon1/taxon1.hpp +++ b/c++/include/objects/taxon1/taxon1.hpp @@ -1,7 +1,7 @@ #ifndef NCBI_TAXON1_HPP #define NCBI_TAXON1_HPP -/* $Id: taxon1.hpp 497983 2016-04-12 17:06:15Z domrach $ +/* $Id: taxon1.hpp 532449 2017-04-05 14:12:46Z domrach $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,12 @@ class CConn_ServiceStream; BEGIN_objects_SCOPE +/// Primitive types for some taxon1 object fields +typedef short int TTaxRank; +typedef short int TTaxDivision; +typedef short int TTaxGeneticCode; +typedef short int TTaxNameClass; + class COrgRefCache; class ITaxon1Node; class ITreeIterator; @@ -69,12 +76,15 @@ public: // Taxon1 server init // Returns: TRUE - OK // FALSE - Can't open connection to taxonomy service + // default parameters: 10 sec timeout, 5 reconnect attempts, + // cache for 1000 org-refs /// - bool Init(void); // default: 120 sec timeout, 5 reconnect attempts, - // cache for 10 org-refs + static const unsigned def_reconnect_attempts = 5; + static const unsigned def_cache_capacity = 1000; + bool Init(void); bool Init(unsigned cache_capacity); - bool Init(const STimeout* timeout, unsigned reconnect_attempts=5, - unsigned cache_capacity=10); + bool Init(const STimeout* timeout, unsigned reconnect_attempts=def_reconnect_attempts, + unsigned cache_capacity=def_cache_capacity); //--------------------------------------------- // Taxon1 server fini (closes connection, frees memory) @@ -82,17 +92,25 @@ public: void Fini(void); //--------------------------------------------- - // Get organism by tax_id + // Get organism data (including org-ref) by tax_id // Returns: pointer to Taxon2Data if organism exists // NULL - if tax_id wrong // // NOTE: - // Caller gets his own copy of Taxon2Data structure. + // Caller gets own copy of Taxon2Data structure. /// CRef< CTaxon2_data > GetById(TTaxId tax_id); + //-------------------------------------------------- + // Get scientific name for taxonomy id + // Returns: false if some error occurred (name_out not changed) + // true if Ok + // name_out contains scientific name of this node + /// + bool GetScientificName(TTaxId tax_id, string& name_out); + //---------------------------------------------- - // Get organism by OrgRef + // Get organism data by OrgRef // Returns: pointer to Taxon2Data if organism exists // NULL - if no such organism in taxonomy database // @@ -105,15 +123,22 @@ public: // 2. LookupMerge function modifies given OrgRef to correspond to the // found one and returns constant pointer to the Taxon2Data structure // stored internally. + // 3. If non-null pointer psLog specified, then lookup log string is returned. + // The latter has following format: each operation record begins with < + // and ends with >, fields inside record are delimited with |, first field + // is operation name (add,delete,update,hit,error,warning,consult,restart), + // second field is path to the component in orgref, third field is old value + // of the component, forth field is a new value for the component, + // fifth field is comment text. /// - CRef< CTaxon2_data > Lookup(const COrg_ref& inp_orgRef); - CConstRef< CTaxon2_data > LookupMerge(COrg_ref& inp_orgRef); + CRef< CTaxon2_data > Lookup(const COrg_ref& inp_orgRef, string* psLog = 0); + CConstRef< CTaxon2_data > LookupMerge(COrg_ref& inp_orgRef, string* psLog = 0); //----------------------------------------------- // Get tax_id by OrgRef // Returns: tax_id - if organism found // 0 - no organism found - // -1 - error during processing occured + // -1 - error occurred during processing // -tax_id - if multiple nodes found // (where tax_id > 1 is id of one of the nodes) // NOTE: @@ -123,21 +148,23 @@ public: enum EOrgRefStatus { eStatus_Ok = 0, - eStatus_WrongTaxId = 0x001, - eStatus_WrongGC = 0x002, - eStatus_WrongMGC = 0x004, - eStatus_NoOrgname = 0x008, - eStatus_WrongTaxname = 0x010, - eStatus_WrongLineage = 0x020, - eStatus_WrongCommonName = 0x040, - eStatus_WrongOrgname = 0x080, - eStatus_WrongDivision = 0x100, - eStatus_WrongOrgmod = 0x200, - eStatus_WrongPGC = 0x400 + eStatus_WrongTaxId = 0x0001, + eStatus_WrongGC = 0x0002, + eStatus_WrongMGC = 0x0004, + eStatus_NoOrgname = 0x0008, + eStatus_WrongTaxname = 0x0010, + eStatus_WrongLineage = 0x0020, + eStatus_WrongCommonName = 0x0040, + eStatus_WrongOrgname = 0x0080, + eStatus_WrongDivision = 0x0100, + eStatus_WrongOrgmod = 0x0200, + eStatus_WrongPGC = 0x0400, + eStatus_WrongOrgrefMod = 0x0800, + eStatus_WrongOrgnameAttr= 0x1000 }; typedef unsigned TOrgRefStatus; //----------------------------------------------- - // Checks whether OrgRef is valid + // Checks whether OrgRef is current // Returns: false on any error, stat_out filled with status flags // (see above) /// @@ -153,7 +180,7 @@ public: // Get tax_id by organism name // Returns: tax_id - if organism found // 0 - no organism found - // -1 - error during processing occured + // -1 - error during processing occurred // -tax_id - if multiple nodes found // (where tax_id > 1 is id of one of the nodes) /// @@ -163,7 +190,7 @@ public: // Get tax_id by organism "unique" name // Returns: tax_id - if organism found // 0 - no organism found - // -1 - error during processing occured + // -1 - error during processing occurred // -tax_id - if multiple nodes found // (where tax_id > 1 is id of one of the nodes) /// @@ -176,11 +203,11 @@ public: // Returns: tax_id - if organism found // 0 - no organism found // -1 - if multiple nodes found - // -2 - error during processing occured + // -2 - error during processing occurred /// TTaxId SearchTaxIdByName(const string& orgname, - ESearch mode = eSearch_TokenSet, - list< CRef< CTaxon1_name > >* name_list_out = NULL); + ESearch mode = eSearch_TokenSet, + list< CRef< CTaxon1_name > >* name_list_out = NULL); //---------------------------------------------- // Get ALL tax_id by organism name @@ -192,7 +219,7 @@ public: //---------------------------------------------- // Get organism by tax_id // Returns: pointer to OrgRef structure if organism found - // NULL - if no such organism in taxonomy database or error occured + // NULL - if no such organism in taxonomy database or error occurred // (check GetLastError() for the latter) // NOTE: // This function does not make a copy of OrgRef structure but returns @@ -290,11 +317,12 @@ public: // forma // Returns: tax_id of properly ranked accessor or // 0 - no such rank in the lineage - // -1 - invalid rank name - // -2 - any other error (use GetLastError for details) + // -1 - tax id is not found + // -2 - invalid rank name + // -3 - any other error (use GetLastError for details) /// TTaxId GetAncestorByRank(TTaxId id_tax, const char* rank_name); - TTaxId GetAncestorByRank(TTaxId id_tax, short rank_id); + TTaxId GetAncestorByRank(TTaxId id_tax, TTaxRank rank_id); //--------------------------------------------- // Get taxids for all children of specified node. @@ -306,22 +334,22 @@ public: //--------------------------------------------- // Get genetic code name by genetic code id /// - bool GetGCName(short gc_id, string& gc_name_out ); + bool GetGCName(TTaxGeneticCode gc_id, string& gc_name_out ); //--------------------------------------------- // Get taxonomic rank name by rank id /// - bool GetRankName(short rank_id, string& rank_name_out ); + bool GetRankName(TTaxRank rank_id, string& rank_name_out ); //--------------------------------------------- // Get taxonomic division name by division id /// - bool GetDivisionName(short div_id, string& div_name_out, string* div_code_out = NULL ); + bool GetDivisionName(TTaxDivision div_id, string& div_name_out, string* div_code_out = NULL ); //--------------------------------------------- // Get taxonomic name class name by name class id /// - bool GetNameClass(short nameclass_id, string& class_name_out ); + bool GetNameClass(TTaxNameClass nameclass_id, string& class_name_out ); //--------------------------------------------- // Get name class id by name class name @@ -350,7 +378,7 @@ public: // is an union of names having both 'common name' and 'genbank common // name' classes). /// - short GetNameClassId( const string& class_name ); + TTaxNameClass GetNameClassId( const string& class_name ); //--------------------------------------------- // Get the nearest common ancestor for two nodes @@ -383,7 +411,7 @@ public: // Returns: TRUE - success // FALSE - failure /// - bool DumpNames( short name_class, list< CRef< CTaxon1_name > >& out ); + bool DumpNames( TTaxNameClass name_class, list< CRef< CTaxon1_name > >& out ); //--------------------------------------------- // Find out is taxonomy lookup system alive or not @@ -545,20 +573,15 @@ private: bool m_bWithSynonyms; string m_sLastError; - typedef map TGCMap; + typedef map TGCMap; TGCMap m_gcStorage; void Reset(void); bool SendRequest(CTaxon1_req& req, CTaxon1_resp& resp, bool bShouldReconnect = true); void SetLastError(const char* err_msg); - void PopulateReplaced(COrg_ref& org, COrgName::TMod& lMods); - bool LookupByOrgRef(const COrg_ref& inp_orgRef, TTaxId* pTaxid, - COrgName::TMod& hitMods); - void OrgRefAdjust( COrg_ref& inp_orgRef, - const COrg_ref& db_orgRef, - TTaxId tax_id ); bool LoadSubtreeEx( TTaxId tax_id, int type, const ITaxon1Node** ppNode ); + TOrgRefStatus x_ConvertOrgrefProps( CTaxon2_data& data ); }; //------------------------------------------------- @@ -569,7 +592,7 @@ public: //------------------------------------------------- // Returns: taxonomy id of the node - virtual TTaxId GetTaxId() const = 0; + virtual TTaxId GetTaxId() const = 0; //------------------------------------------------- // Returns: scientific name of the node. This name is NOT unique @@ -583,20 +606,20 @@ public: //------------------------------------------------- // Returns: taxonomic rank id of the node - virtual short GetRank() const = 0; + virtual TTaxRank GetRank() const = 0; //------------------------------------------------- // Returns: taxonomic division id of the node - virtual short GetDivision() const = 0; + virtual TTaxDivision GetDivision() const = 0; //------------------------------------------------- - // Returns: genetic code for the node - virtual short GetGC() const = 0; + // Returns: genetic code id for the node + virtual TTaxGeneticCode GetGC() const = 0; //------------------------------------------------- - // Returns: mitochondrial genetic code for the node - virtual short GetMGC() const = 0; - + // Returns: mitochondrial genetic code id for the node + virtual TTaxGeneticCode GetMGC() const = 0; + //------------------------------------------------- // Returns: true if node is uncultured, // false otherwise diff --git a/c++/include/objects/taxon3/T3Data.hpp b/c++/include/objects/taxon3/T3Data.hpp index 8c856e38..42b27e79 100644 --- a/c++/include/objects/taxon3/T3Data.hpp +++ b/c++/include/objects/taxon3/T3Data.hpp @@ -1,4 +1,4 @@ -/* $Id: T3Data.hpp 431074 2014-04-01 15:57:25Z bollin $ +/* $Id: T3Data.hpp 542758 2017-08-02 14:34:21Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -43,6 +43,8 @@ // generated includes #include +#include + // generated classes BEGIN_NCBI_SCOPE @@ -62,6 +64,7 @@ public: void GetTaxFlags (bool& is_species_level, bool& force_consult, bool& has_nucleomorphs) const; bool HasPlastids (void) const; + void FilterOutDataParts( ITaxon3::fT3reply_parts to_remain ); private: // Prohibit copy constructor and assignment operator CT3Data(const CT3Data& value); diff --git a/c++/include/objects/taxon3/itaxon3.hpp b/c++/include/objects/taxon3/itaxon3.hpp index 72b5b683..9644388f 100644 --- a/c++/include/objects/taxon3/itaxon3.hpp +++ b/c++/include/objects/taxon3/itaxon3.hpp @@ -1,7 +1,7 @@ #ifndef NCBI_ITAXON3_HPP #define NCBI_ITAXON3_HPP -/* $Id: itaxon3.hpp 473749 2015-07-22 11:14:39Z holmesbr $ +/* $Id: itaxon3.hpp 542758 2017-08-02 14:34:21Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -35,11 +35,14 @@ */ -#include -#include +#include +#include +#include #include #include #include +#include +#include #include #include @@ -67,10 +70,36 @@ public: virtual void Init(const STimeout* timeout, unsigned reconnect_attempts=5) = 0; - // submit a list of org_refs - virtual CRef SendOrgRefList(const vector >& list) = 0; - virtual CRef< CTaxon3_reply > SendRequest(const CTaxon3_request& request) = 0; + enum ETaxon3_reply_part { + eT3reply_nothing = 0, + eT3reply_org = 0x0001, // data.org + eT3reply_blast_lin = 0x0002, // data.blast_name_lineage + eT3reply_status = 0x0004, // data.status + eT3reply_refresh = 0x0008, // data.refresh + eT3reply_all = (eT3reply_org | eT3reply_blast_lin | eT3reply_status | eT3reply_refresh), + eT3reply_default = eT3reply_all + }; + typedef unsigned int fT3reply_parts; + + // submit a list of org_refs + virtual CRef< CTaxon3_reply > SendOrgRefList(const vector< CRef< COrg_ref > >& list, + COrg_ref::fOrgref_parts result_parts = COrg_ref::eOrgref_default, + fT3reply_parts t3result_parts = eT3reply_default ) = 0; + + // Name list lookup all the names (including common names) regardless of their lookup flag + // By default returns scientific name and taxid in T3Data.org and old_name_class property with matched class name + virtual CRef< CTaxon3_reply > SendNameList(const vector& list, + COrg_ref::fOrgref_parts parts = (COrg_ref::eOrgref_taxname | + COrg_ref::eOrgref_db_taxid), + fT3reply_parts t3parts = (eT3reply_org|eT3reply_status) ) = 0; + // By default returns only scientific name and taxid in T3Data.org + virtual CRef< CTaxon3_reply > SendTaxidList(const vector& list, + COrg_ref::fOrgref_parts parts = (COrg_ref::eOrgref_taxname | + COrg_ref::eOrgref_db_taxid), + fT3reply_parts t3parts = eT3reply_org) = 0; + + virtual CRef< CTaxon3_reply > SendRequest(const CTaxon3_request& request) = 0; //-------------------------------------------------- // Get error message after latest erroneous operation // Returns: error message, or empty string if no error occurred diff --git a/c++/include/objects/taxon3/taxon3.hpp b/c++/include/objects/taxon3/taxon3.hpp index b994b168..3b865a1b 100644 --- a/c++/include/objects/taxon3/taxon3.hpp +++ b/c++/include/objects/taxon3/taxon3.hpp @@ -1,7 +1,7 @@ #ifndef NCBI_TAXON3_HPP #define NCBI_TAXON3_HPP -/* $Id: taxon3.hpp 473749 2015-07-22 11:14:39Z holmesbr $ +/* $Id: taxon3.hpp 542758 2017-08-02 14:34:21Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,14 +34,13 @@ */ +#include #include -#include +#include #include #include #include -#include - #include #include #include @@ -66,35 +65,46 @@ public: // Returns: TRUE - OK // FALSE - Can't open connection to taxonomy service /// - virtual void Init(void); // default: 120 sec timeout, 5 reconnect attempts, + virtual void Init(void); // default: 20 sec timeout, 5 reconnect attempts, - virtual void Init(const STimeout* timeout, unsigned reconnect_attempts=5); + virtual void Init(const STimeout* timeout, unsigned reconnect_attempts=5); // submit a list of org_refs - virtual CRef SendOrgRefList(const vector >& list); - virtual CRef< CTaxon3_reply > SendRequest(const CTaxon3_request& request); + virtual CRef< CTaxon3_reply > SendOrgRefList(const vector< CRef< COrg_ref > >& list, + COrg_ref::fOrgref_parts result_parts = COrg_ref::eOrgref_default, + fT3reply_parts t3result_parts = eT3reply_default); + + // Name list lookup all the names (including common names) regardless of their lookup flag + virtual CRef< CTaxon3_reply > SendNameList(const vector& list, + COrg_ref::fOrgref_parts parts = (COrg_ref::eOrgref_taxname | + COrg_ref::eOrgref_db_taxid), + fT3reply_parts t3parts = (eT3reply_org|eT3reply_status)); + + virtual CRef< CTaxon3_reply > SendTaxidList(const vector& list, + COrg_ref::fOrgref_parts parts = (COrg_ref::eOrgref_taxname | + COrg_ref::eOrgref_db_taxid), + fT3reply_parts t3parts = eT3reply_org); + + virtual CRef< CTaxon3_reply > SendRequest(const CTaxon3_request& request); //-------------------------------------------------- // Get error message after latest erroneous operation // Returns: error message, or empty string if no error occurred /// - virtual const string& GetLastError() const { return m_sLastError; } - - - + virtual const string& GetLastError() const { return m_sLastError; } private: - ESerialDataFormat m_eDataFormat; - const char* m_pchService; - STimeout* m_timeout; // NULL, or points to "m_timeout_value" - STimeout m_timeout_value; + ESerialDataFormat m_eDataFormat; + string m_sService; + STimeout* m_timeout; // NULL, or points to "m_timeout_value" + STimeout m_timeout_value; - unsigned m_nReconnectAttempts; + unsigned m_nReconnectAttempts; - string m_sLastError; + string m_sLastError; - void SetLastError(const char* err_msg); + void SetLastError(const char* err_msg); }; diff --git a/c++/include/objects/trackmgr/gridrpcclient.hpp b/c++/include/objects/trackmgr/gridrpcclient.hpp index e2d4a0fb..5ef701f9 100644 --- a/c++/include/objects/trackmgr/gridrpcclient.hpp +++ b/c++/include/objects/trackmgr/gridrpcclient.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_MISC_SERIAL___GRID_RPC_CLIENT__HPP #define OBJECTS_MISC_SERIAL___GRID_RPC_CLIENT__HPP -/* $Id: gridrpcclient.hpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: gridrpcclient.hpp 526845 2017-02-07 18:20:56Z meric $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -316,6 +316,7 @@ public: pair AskStream(CNcbiIstream& request, CNcbiOstream& reply) const { + CPerfLogGuard pl("CGridRPCBaseClient::AskStream"); CGridClient grid_cli(m_NS_api.GetSubmitter(), m_NC_api, CGridClient::eManualCleanup, @@ -370,12 +371,14 @@ public: } throw e; } + pl.Post(CRequestStatus::e200_Ok); return make_pair(job, timed_out); } template pair Ask(const TRequest& request, TReply& reply) const { + CPerfLogGuard pl("CGridRPCBaseClient::Ask"); CGridClient grid_cli(m_NS_api.GetSubmitter(), m_NC_api, CGridClient::eManualCleanup, @@ -432,6 +435,7 @@ public: } throw e; } + pl.Post(CRequestStatus::e200_Ok); return make_pair(job, timed_out); } @@ -450,6 +454,7 @@ protected: template CNetScheduleJob x_GetJobById(const string job_id, TReply& reply) const { + CPerfLogGuard pl("CGridRPCBaseClient::x_GetJobById"); CNetScheduleJob job; job.job_id = job_id; @@ -478,6 +483,7 @@ protected: "Unexpected status: " + CNetScheduleAPI::StatusToString(evt) ); } + pl.Post(CRequestStatus::e200_Ok); return job; } diff --git a/c++/include/objects/trackmgr/primary_snp.hpp b/c++/include/objects/trackmgr/primary_snp.hpp new file mode 100644 index 00000000..dc4c3e9d --- /dev/null +++ b/c++/include/objects/trackmgr/primary_snp.hpp @@ -0,0 +1,76 @@ +#ifndef OBJECTS_TRACKMGR__PRIMARY_SNP_HPP +#define OBJECTS_TRACKMGR__PRIMARY_SNP_HPP + +/* $Id: primary_snp.hpp 533347 2017-04-14 16:47:58Z meric $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Peter Meric + * + * File Description: TMS API for lookup of primary SNP track + * + */ + + +BEGIN_NCBI_SCOPE + + +///////////////////////////////////////////////////////////////////////////// +/// +/// CPrimarySNPTrack -- +/// +/// Collection of static functions to look up primary SNP track + +class CPrimarySNPTrack +{ +public: + using TTrackId = string; + +public: + /// Find the track-id for a specific sequence. + /// + /// @param gi + /// Sequence GI to search. + /// @return + /// TMS track-id + static TTrackId GetTrackId(TGi gi); + + /// Find the track-id for a specific sequence. + /// + /// @param seq_accver + /// Sequence accession.version to search. + /// @return + /// TMS track-id + static TTrackId GetTrackId(const string& seq_accver); + +private: + CPrimarySNPTrack() = delete; + ~CPrimarySNPTrack() = delete; +}; + + +END_NCBI_SCOPE + +#endif // OBJECTS_TRACKMGR__PRIMARY_SNP_HPP + diff --git a/c++/include/objects/trackmgr/trackmgr_client.hpp b/c++/include/objects/trackmgr/trackmgr_client.hpp index 9e5dfdbc..059acfb8 100644 --- a/c++/include/objects/trackmgr/trackmgr_client.hpp +++ b/c++/include/objects/trackmgr/trackmgr_client.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_TRACKMGR_OBJECTS_TRACKMGR_TRACKMGR_CLIENT_HPP #define OBJECTS_TRACKMGR_OBJECTS_TRACKMGR_TRACKMGR_CLIENT_HPP -/* $Id: trackmgr_client.hpp 488465 2015-12-30 23:55:06Z meric $ +/* $Id: trackmgr_client.hpp 542060 2017-07-25 17:13:57Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -49,6 +49,21 @@ public: TReply* reply = 0 ); + using TBatchId = Int8; + using TAlignId = Int8; + + struct SAlignIds + { + TBatchId batch_id; + vector align_ids; + }; + + using TAlignIDs = vector; + + // returns false if unable to parse external_id, else true + static bool ParseAlignId (const string& external_id, + TAlignIDs& parsed_ids); + // looks at application ini file with a section constructed like //[TrackMgr] diff --git a/c++/include/objects/valerr/ValidErrItem.hpp b/c++/include/objects/valerr/ValidErrItem.hpp index 73191d2a..2e768d1e 100644 --- a/c++/include/objects/valerr/ValidErrItem.hpp +++ b/c++/include/objects/valerr/ValidErrItem.hpp @@ -1,4 +1,4 @@ -/* $Id: ValidErrItem.hpp 519224 2016-11-14 16:08:42Z ivanov $ +/* $Id: ValidErrItem.hpp 547746 2017-10-03 17:56:09Z fukanchi $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -144,6 +144,8 @@ enum EErrType { eErr_SEQ_INST_WGSMasterLacksStrucComm, eErr_SEQ_INST_TSAMasterLacksStrucComm, eErr_SEQ_INST_AllNs, + eErr_SEQ_INST_FarLocationExcludesFeatures, + eErr_SEQ_INST_ProteinShouldNotHaveGaps, ERR_CODE_END(SEQ_INST), ERR_CODE_BEGIN(SEQ_DESCR) = 1000, @@ -252,6 +254,7 @@ enum EErrType { eErr_SEQ_DESCR_WrongOrganismFor16SrRNA, eErr_SEQ_DESCR_InconsistentWGSFlags, eErr_SEQ_DESCR_TitleNotAppropriateForSet, + eErr_SEQ_DESCR_StrainContainsTaxInfo, ERR_CODE_END(SEQ_DESCR), @@ -289,6 +292,8 @@ enum EErrType { eErr_GENERIC_BarcodeTestFails, eErr_GENERIC_BarcodeTestPasses, eErr_GENERIC_InvalidAsn, + eErr_GENERIC_ServiceError, + eErr_GENERIC_DuplicateIDs, ERR_CODE_END(GENERIC), ERR_CODE_BEGIN(SEQ_PKG) = 3000, @@ -539,6 +544,9 @@ enum EErrType { eErr_SEQ_FEAT_RefSeqInText, eErr_SEQ_FEAT_ColdShockProteinProblem, eErr_SEQ_FEAT_BadLocation, + eErr_SEQ_FEAT_GenCodeInvalid, + eErr_SEQ_FEAT_TranslExceptIsPartial, + eErr_SEQ_FEAT_GeneIdMismatch, ERR_CODE_END(SEQ_FEAT), ERR_CODE_BEGIN(SEQ_ALIGN) = 5000, @@ -622,7 +630,7 @@ public: EDiagSev GetSeverity (void) const; // Error code const string GetErrCode (void) const; - static unsigned int GetErrCount(void); + static size_t GetErrCount(void); // Error group (SEQ_FEAT, SEQ_INST etc.) const string GetErrGroup (void) const; // Verbose message @@ -630,6 +638,7 @@ public: // Offending object const CSerialObject& GetObject (void) const; bool IsSetObject (void) const; + void SetObject(const CSerialObject& obj); // Convert Severity from enum to a string representation static const string ConvertSeverity(EDiagSev sev); @@ -641,7 +650,11 @@ public: bool IsSetContext(void) const; const CSeq_entry& GetContext(void) const; + void SetContext(CConstRef ctx) { m_Ctx = ctx; } + // use previously populated fields to construct the "standard" description + void SetFeatureObjDescFromFields(); + private: friend class CValidError; diff --git a/c++/include/objects/valerr/ValidError.hpp b/c++/include/objects/valerr/ValidError.hpp index 70f09261..02ee3371 100644 --- a/c++/include/objects/valerr/ValidError.hpp +++ b/c++/include/objects/valerr/ValidError.hpp @@ -1,4 +1,4 @@ -/* $Id: ValidError.hpp 513779 2016-09-15 11:23:57Z ivanov $ +/* $Id: ValidError.hpp 538704 2017-06-13 16:56:44Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -69,6 +69,7 @@ public: const CSerialObject& obj, // offending object const string& acc, // accession of object. const int ver, // version of object. + const string& location = kEmptyStr, // formatted location of object const int seq_offset = 0); void AddValidErrItem(EDiagSev sev, // severity @@ -79,6 +80,7 @@ public: const string& acc, // accession of object. const int ver, // version of object. const string& feature_id, // feature ID for object + const string& location, // formatted location of object const int seq_offset = 0); void AddValidErrItem(EDiagSev sev, // severity @@ -95,6 +97,8 @@ public: unsigned int ec, // error code const string& msg); // specific error message + void AddValidErrItem(CRef item); + // Statistics SIZE_TYPE TotalSize(void) const; SIZE_TYPE Size(EDiagSev sev) const; diff --git a/c++/include/objmgr/align_ci.hpp b/c++/include/objmgr/align_ci.hpp index a4d210cf..e1c7025f 100644 --- a/c++/include/objmgr/align_ci.hpp +++ b/c++/include/objmgr/align_ci.hpp @@ -1,7 +1,7 @@ #ifndef ALIGN_CI__HPP #define ALIGN_CI__HPP -/* $Id: align_ci.hpp 439368 2014-06-27 17:33:59Z vasilche $ +/* $Id: align_ci.hpp 536422 2017-05-18 14:44:05Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -133,6 +133,18 @@ public: CAlign_CI(const CSeq_annot_Handle& annot, const SAnnotSelector& sel); + /// Iterate all alignments from the seq-annot that annotate the location + CAlign_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot); + + /// Iterate all alignments from the seq-annot that annotate the location + /// + /// @sa + /// SAnnotSelector + CAlign_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot, + const SAnnotSelector& sel); + /// Create an iterator that enumerates CSeq_align objects /// from the seq-entry regardless of their location explicit diff --git a/c++/include/objmgr/annot_selector.hpp b/c++/include/objmgr/annot_selector.hpp index b65edcc9..e4b3424e 100644 --- a/c++/include/objmgr/annot_selector.hpp +++ b/c++/include/objmgr/annot_selector.hpp @@ -1,7 +1,7 @@ #ifndef ANNOT_SELECTOR__HPP #define ANNOT_SELECTOR__HPP -/* $Id: annot_selector.hpp 519943 2016-11-21 15:34:20Z ivanov $ +/* $Id: annot_selector.hpp 539540 2017-06-23 13:16:53Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -715,6 +715,27 @@ struct NCBI_XOBJMGR_EXPORT SAnnotSelector : public SAnnotTypeSelector return *this; } + /// Collect cost of loading requested data. + /// If cost collection is requested no actual annotations are returned + /// by iterator, only the cost estimation. + /// The resulting cost can be queried via methods GetCostOfLoadingInBytes() + /// and GetCostOfLoadingInSeconds() of actual annotation iterator (CFeat_CI, + /// CAlign_CI, etc). + /// The cost of loading is estimated in two units: number of bytes to load + /// and expected time for loading them in seconds. + /// The estimation is dependent on data source of requested annotations. + /// In some cases it can be quite rough if the data source doesn't provide + /// necessary information. + /// The cost includes only data not-yet-loaded. Any annotations already + /// loaded into memory are excluded from this cost. + /// @sa CAnnotTypes_CI::GetCostOfLoadingInBytes() + /// @sa CAnnotTypes_CI::GetCostOfLoadingInSeconds() + SAnnotSelector& SetCollectCostOfLoading(bool value = true) + { + m_CollectCostOfLoading = value; + return *this; + } + /// Ignore strand when testing for range overlap SAnnotSelector& SetIgnoreStrand(bool value = true) { @@ -812,6 +833,7 @@ protected: bool m_CollectSeq_annots; bool m_CollectTypes; bool m_CollectNames; + bool m_CollectCostOfLoading; bool m_IgnoreStrand; TAdaptiveTriggers m_AdaptiveTriggers; TTSE_Limits m_ExcludedTSE; diff --git a/c++/include/objmgr/annot_types_ci.hpp b/c++/include/objmgr/annot_types_ci.hpp index 03e907cd..7b649a61 100644 --- a/c++/include/objmgr/annot_types_ci.hpp +++ b/c++/include/objmgr/annot_types_ci.hpp @@ -1,7 +1,7 @@ #ifndef ANNOT_TYPES_CI__HPP #define ANNOT_TYPES_CI__HPP -/* $Id: annot_types_ci.hpp 519943 2016-11-21 15:34:20Z ivanov $ +/* $Id: annot_types_ci.hpp 539540 2017-06-23 13:16:53Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -75,6 +75,12 @@ public: const CSeq_annot_Handle& annot, const SAnnotSelector* params = 0); + // Iterate annotations from the seq-annot that annotate the location + CAnnotTypes_CI(TAnnotType type, + const CSeq_loc& loc, + const CSeq_annot_Handle& annot, + const SAnnotSelector* params = 0); + // Iterate everything from the seq-entry CAnnotTypes_CI(TAnnotType type, const CSeq_entry_Handle& entry, @@ -102,6 +108,13 @@ public: typedef set TAnnotNames; const TAnnotNames& GetAnnotNames(void) const; + /// Get collected cost of loading requested data in bytes. + /// @sa SAnnotSelector::SetCollectCostOfLoading() + Uint8 GetCostOfLoadingInBytes(void) const; + /// Get collected cost of loading requested data in seconds. + /// @sa SAnnotSelector::SetCollectCostOfLoading() + double GetCostOfLoadingInSeconds(void) const; + protected: friend class CAnnot_CI; friend class CTableFieldHandle_Base; @@ -213,6 +226,20 @@ CScope& CAnnotTypes_CI::GetScope(void) const } +inline +Uint8 CAnnotTypes_CI::GetCostOfLoadingInBytes(void) const +{ + return m_DataCollector->x_GetCostOfLoadingInBytes(); +} + + +inline +double CAnnotTypes_CI::GetCostOfLoadingInSeconds(void) const +{ + return m_DataCollector->x_GetCostOfLoadingInSeconds(); +} + + END_SCOPE(objects) END_NCBI_SCOPE diff --git a/c++/include/objmgr/data_loader.hpp b/c++/include/objmgr/data_loader.hpp index 2838f42c..3768fd50 100644 --- a/c++/include/objmgr/data_loader.hpp +++ b/c++/include/objmgr/data_loader.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR___DATA_LOADER__HPP #define OBJECTS_OBJMGR___DATA_LOADER__HPP -/* $Id: data_loader.hpp 498345 2016-04-15 14:39:08Z vasilche $ +/* $Id: data_loader.hpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -434,6 +434,11 @@ public: virtual CObjectManager::TPriority GetDefaultPriority(void) const; + virtual Uint4 EstimateLoadBytes(const CTSE_Chunk_Info& chunk) const; + virtual double EstimateLoadSeconds(const CTSE_Chunk_Info& chunk, Uint4 bytes) const; + + virtual unsigned GetDefaultBlobCacheSizeLimit() const; + protected: /// Register the loader only if the name is not yet /// registered in the object manager @@ -464,7 +469,7 @@ private: END_SCOPE(objects) -NCBI_DECLARE_INTERFACE_VERSION(objects::CDataLoader, "xloader", 4, 2, 0); +NCBI_DECLARE_INTERFACE_VERSION(objects::CDataLoader, "xloader", 4, 4, 0); template<> class CDllResolver_Getter diff --git a/c++/include/objmgr/feat_ci.hpp b/c++/include/objmgr/feat_ci.hpp index 373b9a1b..77d0024f 100644 --- a/c++/include/objmgr/feat_ci.hpp +++ b/c++/include/objmgr/feat_ci.hpp @@ -1,7 +1,7 @@ #ifndef FEAT_CI__HPP #define FEAT_CI__HPP -/* $Id: feat_ci.hpp 439336 2014-06-27 16:08:17Z vasilche $ +/* $Id: feat_ci.hpp 536422 2017-05-18 14:44:05Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -115,6 +115,18 @@ public: CFeat_CI(const CSeq_annot_Handle& annot, const SAnnotSelector& sel); + /// Iterate all features from the seq-annot that annotate the location + CFeat_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot); + + /// Iterate all features from the seq-annot that annotate the location + /// + /// @sa + /// SAnnotSelector + CFeat_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot, + const SAnnotSelector& sel); + /// Iterate all features from the seq-entry regardless of their location explicit CFeat_CI(const CSeq_entry_Handle& entry); diff --git a/c++/include/objmgr/graph_ci.hpp b/c++/include/objmgr/graph_ci.hpp index 94b879d8..5db5270a 100644 --- a/c++/include/objmgr/graph_ci.hpp +++ b/c++/include/objmgr/graph_ci.hpp @@ -1,7 +1,7 @@ #ifndef GRAPH_CI__HPP #define GRAPH_CI__HPP -/* $Id: graph_ci.hpp 464897 2015-04-15 13:12:52Z grichenk $ +/* $Id: graph_ci.hpp 536422 2017-05-18 14:44:05Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -276,6 +276,18 @@ public: CGraph_CI(const CSeq_annot_Handle& annot, const SAnnotSelector& sel); + /// Iterate all graphs from the seq-annot that annotate the location + CGraph_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot); + + /// Iterate all graphs from the seq-annot that annotate the location + /// + /// @sa + /// SAnnotSelector + CGraph_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot, + const SAnnotSelector& sel); + /// Iterate all graphs from the seq-entry regardless of their location explicit CGraph_CI(const CSeq_entry_Handle& entry); diff --git a/c++/include/objmgr/impl/annot_collector.hpp b/c++/include/objmgr/impl/annot_collector.hpp index 8c114f4d..b82e2b05 100644 --- a/c++/include/objmgr/impl/annot_collector.hpp +++ b/c++/include/objmgr/impl/annot_collector.hpp @@ -1,7 +1,7 @@ #ifndef ANNOT_COLLECTOR__HPP #define ANNOT_COLLECTOR__HPP -/* $Id: annot_collector.hpp 519943 2016-11-21 15:34:20Z ivanov $ +/* $Id: annot_collector.hpp 538958 2017-06-15 17:46:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -489,6 +489,9 @@ private: const TAnnotNames& x_GetAnnotNames(void) const; + Uint8 x_GetCostOfLoadingInBytes(void) const; + double x_GetCostOfLoadingInSeconds(void) const; + void x_StopSearchLimits(void); bool x_MaxSearchSegmentsLimitIsReached(void) const { @@ -513,6 +516,9 @@ private: TAnnotTypesBitset m_UnseenAnnotTypes; TAnnotTypesBitset m_CollectAnnotTypes; mutable auto_ptr m_AnnotNames; + Uint8 m_LoadBytes; + double m_LoadSeconds; + typedef SAnnotSelector::TMaxSize TMaxSize; typedef SAnnotSelector::TMaxSearchSegments TMaxSearchSegments; CStopWatch m_SearchTime; diff --git a/c++/include/objmgr/impl/annot_object_index.hpp b/c++/include/objmgr/impl/annot_object_index.hpp index a4ac61c2..95bf7fa4 100644 --- a/c++/include/objmgr/impl/annot_object_index.hpp +++ b/c++/include/objmgr/impl/annot_object_index.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR_IMPL___ANNOT_OBJECT_INDEX__HPP #define OBJECTS_OBJMGR_IMPL___ANNOT_OBJECT_INDEX__HPP -/* $Id: annot_object_index.hpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: annot_object_index.hpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objmgr/impl/bioseq_set_info.hpp b/c++/include/objmgr/impl/bioseq_set_info.hpp index 2f9711e2..2d53d434 100644 --- a/c++/include/objmgr/impl/bioseq_set_info.hpp +++ b/c++/include/objmgr/impl/bioseq_set_info.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR_IMPL___BIOSEQ_SET_INFO__HPP #define OBJECTS_OBJMGR_IMPL___BIOSEQ_SET_INFO__HPP -/* $Id: bioseq_set_info.hpp 219679 2011-01-12 20:14:06Z vasilche $ +/* $Id: bioseq_set_info.hpp 521281 2016-12-07 16:40:59Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -133,7 +133,7 @@ public: // return first already loaded Seq-entry or null CConstRef GetFirstEntry(void) const; - CRef AddEntry(CSeq_entry& entry, int index = -1, + CRef AddEntry(CSeq_entry& entry, int index, // index == -1 -> at the end bool set_uniqid = false); void AddEntry(CRef entry, int index = -1, bool set_uniqid = false); @@ -160,6 +160,8 @@ public: void x_AttachEntry(CRef info); void x_DetachEntry(CRef info); + void x_SetChunkBioseqs(const list< CRef >& bioseqs, int chunk_id); + protected: friend class CDataSource; friend class CScope_Impl; @@ -206,6 +208,15 @@ private: // members TSeq_set m_Seq_set; + struct SChunkSeqSet { + SChunkSeqSet() : count(0) {} + + size_t count; + CBioseq_set::TSeq_set::iterator first_iter; + }; + typedef map TChunkSeqSets; + TChunkSeqSets m_ChunkSeqSets; + // TChunkIds m_BioseqChunks; diff --git a/c++/include/objmgr/impl/data_source.hpp b/c++/include/objmgr/impl/data_source.hpp index 070305d0..a005df7c 100644 --- a/c++/include/objmgr/impl/data_source.hpp +++ b/c++/include/objmgr/impl/data_source.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR_IMPL___DATA_SOURCE__HPP #define OBJECTS_OBJMGR_IMPL___DATA_SOURCE__HPP -/* $Id: data_source.hpp 493168 2016-02-24 19:28:38Z vasilche $ +/* $Id: data_source.hpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -283,6 +283,8 @@ public: TPriority GetDefaultPriority(void) const; void SetDefaultPriority(TPriority priority); + static unsigned GetDefaultBlobCacheSizeLimit(); + // get locks enum FLockFlags { fLockNoHistory = 1<<0, @@ -483,7 +485,8 @@ private: TBlob_Map m_Blob_Map; // TBlobId -> CTSE_Info mutable TBlob_Cache m_Blob_Cache; // unlocked blobs - mutable size_t m_Blob_Cache_Size;// list<>::size() is slow + mutable unsigned m_Blob_Cache_Size;// list<>::size() is slow + unsigned m_Blob_Cache_Size_Limit; // Prefetching thread and lock, used when initializing the thread CRef m_PrefetchThread; diff --git a/c++/include/objmgr/impl/scope_impl.hpp b/c++/include/objmgr/impl/scope_impl.hpp index efa3893d..5663366c 100644 --- a/c++/include/objmgr/impl/scope_impl.hpp +++ b/c++/include/objmgr/impl/scope_impl.hpp @@ -1,7 +1,7 @@ #ifndef OBJMGR_IMPL_SCOPE_IMPL__HPP #define OBJMGR_IMPL_SCOPE_IMPL__HPP -/* $Id: scope_impl.hpp 495071 2016-03-14 17:45:32Z grichenk $ +/* $Id: scope_impl.hpp 534487 2017-04-27 17:21:02Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -621,6 +621,9 @@ private: IScopeTransaction_Impl* m_Transaction; + int m_BioseqChangeCounter; + int m_AnnotChangeCounter; + friend class CScope; friend class CHeapScope; friend class CObjectManager; diff --git a/c++/include/objmgr/impl/scope_info.hpp b/c++/include/objmgr/impl/scope_info.hpp index 7cac7f60..61496b54 100644 --- a/c++/include/objmgr/impl/scope_info.hpp +++ b/c++/include/objmgr/impl/scope_info.hpp @@ -1,7 +1,7 @@ #ifndef SCOPE_INFO__HPP #define SCOPE_INFO__HPP -/* $Id: scope_info.hpp 467006 2015-05-08 11:59:52Z vasilche $ +/* $Id: scope_info.hpp 534487 2017-04-27 17:21:02Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -503,17 +503,24 @@ public: typedef CRef TTSE_ScopeInfo; typedef set TSeq_idSet; typedef vector< pair > TTSE_MatchSet; - typedef CObjectFor TTSE_MatchSetObject; - typedef CInitMutex TAnnotRefInfo; + struct SAnnotSetCache : public CObject { + volatile int m_SearchTimestamp; + TTSE_MatchSet match; + }; + typedef CInitMutex TAnnotRefInfo; typedef TIndexIds TIds; typedef int TBlobStateFlags; typedef CScopeInfo_Ref TBioseq_Lock; - explicit CBioseq_ScopeInfo(TBlobStateFlags flag); // no sequence + CBioseq_ScopeInfo(TBlobStateFlags flag, int timestamp); // no sequence explicit CBioseq_ScopeInfo(CTSE_ScopeInfo& tse); // unnamed CBioseq_ScopeInfo(CTSE_ScopeInfo& tse, const TIds& ids); ~CBioseq_ScopeInfo(void); - + + // update state + void SetUnresolved(TBlobStateFlags flag, int timestamp); + void SetResolved(CTSE_ScopeInfo& tse, const TIds& ids); + const CBioseq_Info& GetObjectInfo(void) const { return reinterpret_cast(GetObjectInfo_Base()); @@ -530,6 +537,10 @@ public: const TIndexIds* GetIndexIds(void) const; bool HasBioseq(void) const; + bool NeedsReResolve(int timestamp) const + { + return !HasBioseq() && m_UnresolvedTimestamp != timestamp; + } string IdString(void) const; @@ -563,11 +574,12 @@ private: // members TBlobStateFlags m_BlobState; // Cached information. + volatile int m_UnresolvedTimestamp; // Cache synonyms of bioseq if any. // All synonyms share the same CBioseq_ScopeInfo object. CInitMutex m_SynCache; // Cache TSEs with external annotations on this Bioseq. - CInitMutex m_BioseqAnnotRef_Info; + CInitMutex m_BioseqAnnotRef_Info; private: // to prevent copying CBioseq_ScopeInfo(const CBioseq_ScopeInfo& info); @@ -580,13 +592,22 @@ struct SSeq_id_ScopeInfo SSeq_id_ScopeInfo(void); ~SSeq_id_ScopeInfo(void); - typedef CBioseq_ScopeInfo::TTSE_MatchSetObject TTSE_MatchSetObject; - // Resolved Bioseq information. + // 1. initially: + // m_Bioseq_Info = null + // 2. resolve failed: + // m_Bioseq_Info = !HasBioseq() (state & no_data) != 0 + // 3. resolved: + // m_Bioseq_Info = HasBioseq() (state & no_data) == 0 + // State transitions: + // 1 -> 2 (sequence not found) + // 1 -> 3 (sequence found) + // 2 -> 3 (sequence found on next attempt) + // 3 -> 1 (sequence removed) CInitMutex m_Bioseq_Info; // Caches other (not main) TSEs with annotations on this Seq-id. - CInitMutex m_AllAnnotRef_Info; + CInitMutex m_AllAnnotRef_Info; }; diff --git a/c++/include/objmgr/impl/seq_entry_info.hpp b/c++/include/objmgr/impl/seq_entry_info.hpp index 188c27ce..641b5132 100644 --- a/c++/include/objmgr/impl/seq_entry_info.hpp +++ b/c++/include/objmgr/impl/seq_entry_info.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR_IMPL___SEQ_ENTRY_INFO__HPP #define OBJECTS_OBJMGR_IMPL___SEQ_ENTRY_INFO__HPP -/* $Id: seq_entry_info.hpp 518178 2016-11-01 11:46:07Z ivanov $ +/* $Id: seq_entry_info.hpp 517902 2016-10-28 16:56:25Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objmgr/impl/seq_table_setters.hpp b/c++/include/objmgr/impl/seq_table_setters.hpp index a447a84a..d1155727 100644 --- a/c++/include/objmgr/impl/seq_table_setters.hpp +++ b/c++/include/objmgr/impl/seq_table_setters.hpp @@ -1,7 +1,7 @@ #ifndef SEQ_TABLE_SETTERS__HPP #define SEQ_TABLE_SETTERS__HPP -/* $Id: seq_table_setters.hpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: seq_table_setters.hpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objmgr/impl/seq_vector_cvt_gen.hpp b/c++/include/objmgr/impl/seq_vector_cvt_gen.hpp index fce3a418..5ae22877 100644 --- a/c++/include/objmgr/impl/seq_vector_cvt_gen.hpp +++ b/c++/include/objmgr/impl/seq_vector_cvt_gen.hpp @@ -1,6 +1,6 @@ #ifndef SEQ_VECTOR_CVT_GEN__HPP #define SEQ_VECTOR_CVT_GEN__HPP -/* $Id: seq_vector_cvt_gen.hpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: seq_vector_cvt_gen.hpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objmgr/impl/tse_assigner.hpp b/c++/include/objmgr/impl/tse_assigner.hpp index 6ca3ec3e..0362c78d 100644 --- a/c++/include/objmgr/impl/tse_assigner.hpp +++ b/c++/include/objmgr/impl/tse_assigner.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR_IMPL___TSE_ASSIGNER__HPP #define OBJECTS_OBJMGR_IMPL___TSE_ASSIGNER__HPP -/* $Id: tse_assigner.hpp 471824 2015-07-01 17:23:26Z vasilche $ +/* $Id: tse_assigner.hpp 521281 2016-12-07 16:40:59Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -74,7 +74,11 @@ public: CRef annot, int chunk_id) = 0; virtual void LoadBioseq(CTSE_Info&, const TPlace& place, - CRef entry) = 0; + CRef entry, + int chunk_id) = 0; + virtual void LoadChunkBioseqs(CTSE_Info&, const TPlace& place, + const list< CRef >& bioseqs, + int chunk_id) = 0; virtual void LoadSequence(CTSE_Info&, const TPlace& place, TSeqPos pos, const TSequence& sequence) = 0; virtual void LoadAssembly(CTSE_Info&, const TBioseqId& seq_id, @@ -118,7 +122,11 @@ public: CRef annot, int chunk_id); virtual void LoadBioseq(CTSE_Info&, const TPlace& place, - CRef entry); + CRef entry, + int chunk_id); + virtual void LoadChunkBioseqs(CTSE_Info&, const TPlace& place, + const list< CRef >& bioseqs, + int chunk_id); virtual void LoadSequence(CTSE_Info&, const TPlace& place, TSeqPos pos, const TSequence& sequence); virtual void LoadAssembly(CTSE_Info&, const TBioseqId& seq_id, diff --git a/c++/include/objmgr/impl/tse_chunk_info.hpp b/c++/include/objmgr/impl/tse_chunk_info.hpp index 957d11a1..037f281b 100644 --- a/c++/include/objmgr/impl/tse_chunk_info.hpp +++ b/c++/include/objmgr/impl/tse_chunk_info.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR_IMPL___TSE_CHUNK_INFO__HPP #define OBJECTS_OBJMGR_IMPL___TSE_CHUNK_INFO__HPP -/* $Id: tse_chunk_info.hpp 411165 2013-08-26 19:00:47Z vasilche $ +/* $Id: tse_chunk_info.hpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -76,7 +76,13 @@ public: typedef CBlobIdKey TBlobId; typedef int TBlobVersion; typedef int TChunkId; - + + enum { + kMain_ChunkId = -1, // not a chunk, but main Seq-entry + kMasterWGS_ChunkId = kMax_Int-1, // chunk with master WGS descr + kDelayedMain_ChunkId= kMax_Int // main Seq-entry with delayed ext annot + }; + // contents place identification typedef int TBioseq_setId; typedef CSeq_id_Handle TBioseqId; @@ -199,13 +205,18 @@ public: // data attachment void x_LoadDescr(const TPlace& place, const CSeq_descr& descr); void x_LoadAnnot(const TPlace& place, const CSeq_annot& annot); + NCBI_DEPRECATED void x_LoadBioseq(const TPlace& place, const CBioseq& bioseq); + void x_LoadBioseqs(const TPlace& place, const list< CRef >& bioseqs); void x_LoadSequence(const TPlace& place, TSeqPos pos, const TSequence& seq); void x_LoadAssembly(const TBioseqId& seq_id, const TAssembly& assembly); void x_LoadSeq_entry(CSeq_entry& entry, CTSE_SetObjectInfo* set_info = 0); + // update in-memory size + void x_AddUsedMemory(size_t size); + ////////////////////////////////////////////////////////////////// // methods to find out what information is needed to be loaded ////////////////////////////////////////////////////////////////// @@ -238,6 +249,13 @@ public: return m_AssemblyInfos; } + Uint4 GetLoadBytes() const; + double GetLoadSeconds() const; + pair GetLoadCost() const; + + void x_SetLoadBytes(Uint4 bytes); + void x_SetLoadSeconds(double seconds); + protected: ////////////////////////////////////////////////////////////////// // interaction with CTSE_Info @@ -288,6 +306,9 @@ private: CTSE_Split_Info* m_SplitInfo; TChunkId m_ChunkId; + Uint4 m_LoadBytes; + float m_LoadSeconds; + bool m_AnnotIndexEnabled; bool m_ExplicitFeatIds; @@ -336,6 +357,20 @@ const CTSE_Split_Info& CTSE_Chunk_Info::GetSplitInfo(void) const } +inline +Uint4 CTSE_Chunk_Info::GetLoadBytes() const +{ + return m_LoadBytes; +} + + +inline +double CTSE_Chunk_Info::GetLoadSeconds() const +{ + return m_LoadSeconds; +} + + END_SCOPE(objects) END_NCBI_SCOPE diff --git a/c++/include/objmgr/impl/tse_info.hpp b/c++/include/objmgr/impl/tse_info.hpp index 8cc9b820..c3fb261c 100644 --- a/c++/include/objmgr/impl/tse_info.hpp +++ b/c++/include/objmgr/impl/tse_info.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR_IMPL___TSE_INFO__HPP #define OBJECTS_OBJMGR_IMPL___TSE_INFO__HPP -/* $Id: tse_info.hpp 518178 2016-11-01 11:46:07Z ivanov $ +/* $Id: tse_info.hpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -253,6 +253,7 @@ public: size_t GetUsedMemory(void) const; void SetUsedMemory(size_t size); + void AddUsedMemory(size_t size); // Annot index access bool HasAnnot(const CAnnotName& name) const; diff --git a/c++/include/objmgr/impl/tse_info_object.hpp b/c++/include/objmgr/impl/tse_info_object.hpp index 830af921..168f0800 100644 --- a/c++/include/objmgr/impl/tse_info_object.hpp +++ b/c++/include/objmgr/impl/tse_info_object.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR_IMPL___TSE_INFO_OBJECT__HPP #define OBJECTS_OBJMGR_IMPL___TSE_INFO_OBJECT__HPP -/* $Id: tse_info_object.hpp 516279 2016-10-12 13:41:47Z ivanov $ +/* $Id: tse_info_object.hpp 516051 2016-10-07 15:16:44Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objmgr/impl/tse_split_info.hpp b/c++/include/objmgr/impl/tse_split_info.hpp index bc451b95..744f9108 100644 --- a/c++/include/objmgr/impl/tse_split_info.hpp +++ b/c++/include/objmgr/impl/tse_split_info.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR_IMPL___TSE_SPLIT_INFO__HPP #define OBJECTS_OBJMGR_IMPL___TSE_SPLIT_INFO__HPP -/* $Id: tse_split_info.hpp 518178 2016-11-01 11:46:07Z ivanov $ +/* $Id: tse_split_info.hpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -148,13 +148,16 @@ public: // loading results void x_LoadDescr(const TPlace& place, const CSeq_descr& descr); void x_LoadAnnot(const TPlace& place, const CSeq_annot& annot, int chunk_id); - void x_LoadBioseq(const TPlace& place, const CBioseq& bioseq); + void x_LoadBioseqs(const TPlace& place, const list< CRef >& bioseqs, int chunk_id); void x_LoadSequence(const TPlace& place, TSeqPos pos, const TSequence& sequence); void x_LoadAssembly(const TBioseqId& seq_id, const TAssembly& assembly); void x_LoadSeq_entry(CSeq_entry& entry, CTSE_SetObjectInfo* set_info = 0); + // update in-memory size + void x_AddUsedMemory(size_t size); + void x_SetBioseqUpdater(CRef updater); protected: diff --git a/c++/include/objmgr/objmgr_exception.hpp b/c++/include/objmgr/objmgr_exception.hpp index 3e6e8275..0845bb3d 100644 --- a/c++/include/objmgr/objmgr_exception.hpp +++ b/c++/include/objmgr/objmgr_exception.hpp @@ -1,7 +1,7 @@ #ifndef OBJMGR_EXCEPTION__HPP #define OBJMGR_EXCEPTION__HPP -/* $Id: objmgr_exception.hpp 493168 2016-02-24 19:28:38Z vasilche $ +/* $Id: objmgr_exception.hpp 541890 2017-07-24 13:05:52Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -206,7 +206,8 @@ public: eNotUnique, eUnknownLength, eBadFeature, - eBadResidue + eBadResidue, + eBadAlignment }; virtual const char* GetErrCodeString(void) const; NCBI_EXCEPTION_DEFAULT(CObjmgrUtilException, CObjMgrException); diff --git a/c++/include/objmgr/seq_entry_ci.hpp b/c++/include/objmgr/seq_entry_ci.hpp index b197b03e..394031a2 100644 --- a/c++/include/objmgr/seq_entry_ci.hpp +++ b/c++/include/objmgr/seq_entry_ci.hpp @@ -1,7 +1,7 @@ #ifndef OBJMGR__SEQ_ENTRY_CI__HPP #define OBJMGR__SEQ_ENTRY_CI__HPP -/* $Id: seq_entry_ci.hpp 483569 2015-11-02 17:27:19Z vasilche $ +/* $Id: seq_entry_ci.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -150,7 +150,7 @@ private: CSeq_entry_Handle m_Current; TFlags m_Flags; CSeq_entry::E_Choice m_Filter; - auto_ptr m_SubIt; + unique_ptr m_SubIt; }; @@ -203,7 +203,7 @@ public: CSeq_entry_I& operator ++(void); const CSeq_entry_EditHandle operator*(void) const; - auto_ptr operator->(void) const; + unique_ptr operator->(void) const; CBioseq_set_EditHandle GetParentBioseq_set(void) const; @@ -308,9 +308,9 @@ const CSeq_entry_EditHandle CSeq_entry_I::operator*(void) const inline -auto_ptr CSeq_entry_I::operator->(void) const +unique_ptr CSeq_entry_I::operator->(void) const { - auto_ptr rval( new CSeq_entry_EditHandle( CSeq_entry_CI::operator*() ) ); + unique_ptr rval( new CSeq_entry_EditHandle( CSeq_entry_CI::operator*() ) ); return rval; } diff --git a/c++/include/objmgr/seq_loc_mapper.hpp b/c++/include/objmgr/seq_loc_mapper.hpp index 93040e39..11d304dd 100644 --- a/c++/include/objmgr/seq_loc_mapper.hpp +++ b/c++/include/objmgr/seq_loc_mapper.hpp @@ -1,7 +1,7 @@ #ifndef SEQ_LOC_MAPPER__HPP #define SEQ_LOC_MAPPER__HPP -/* $Id: seq_loc_mapper.hpp 505837 2016-06-29 15:06:52Z grichenk $ +/* $Id: seq_loc_mapper.hpp 543872 2017-08-15 12:17:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -121,6 +121,22 @@ public: size_t to_row, CScope* scope = 0, CSeq_loc_Mapper_Options options = CSeq_loc_Mapper_Options()); + /// Mapping through an alignment using specific source and target ids. + /// If the alignment is not one of dense-seg, dense-diag or packed-seg, the source + /// id is ignored. + CSeq_loc_Mapper(const CSeq_id& from_id, + const CSeq_id& to_id, + const CSeq_align& map_align, + CScope* scope = 0, + CSeq_loc_Mapper_Options options = CSeq_loc_Mapper_Options()); + /// Mapping through an alignment using specific source and target row numbers. + /// If the alignment is not one of dense-seg, dense-diag or packed-seg, the source + /// row is ignored. + CSeq_loc_Mapper(size_t from_row, + size_t to_row, + const CSeq_align& map_align, + CScope* scope = 0, + CSeq_loc_Mapper_Options options = CSeq_loc_Mapper_Options()); /// Mapping between segments and the top level sequence. /// @param target_seq diff --git a/c++/include/objmgr/seq_vector_ci.hpp b/c++/include/objmgr/seq_vector_ci.hpp index cc9b4fc6..ba95d8d4 100644 --- a/c++/include/objmgr/seq_vector_ci.hpp +++ b/c++/include/objmgr/seq_vector_ci.hpp @@ -1,7 +1,7 @@ #ifndef SEQ_VECTOR_CI__HPP #define SEQ_VECTOR_CI__HPP -/* $Id: seq_vector_ci.hpp 520631 2016-11-30 13:12:58Z ivanov $ +/* $Id: seq_vector_ci.hpp 537888 2017-06-05 19:13:54Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -485,7 +485,7 @@ const CSeqMap_CI& CSeqVector_CI::GetCurrentSeqMap_CI(void) const inline bool CSeqVector_CI::IsInGap(void) const { - return m_Seg.GetType() == CSeqMap::eSeqGap; + return *this && m_Seg.GetType() == CSeqMap::eSeqGap; } diff --git a/c++/include/objmgr/split/size.hpp b/c++/include/objmgr/split/size.hpp index 24c33562..38063c73 100644 --- a/c++/include/objmgr/split/size.hpp +++ b/c++/include/objmgr/split/size.hpp @@ -1,7 +1,7 @@ #ifndef NCBI_OBJMGR_SPLIT_SIZE__HPP #define NCBI_OBJMGR_SPLIT_SIZE__HPP -/* $Id: size.hpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: size.hpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objmgr/tse_handle.hpp b/c++/include/objmgr/tse_handle.hpp index 53ac4421..885ede6e 100644 --- a/c++/include/objmgr/tse_handle.hpp +++ b/c++/include/objmgr/tse_handle.hpp @@ -1,7 +1,7 @@ #ifndef OBJMGR_TSE_HANDLE__HPP #define OBJMGR_TSE_HANDLE__HPP -/* $Id: tse_handle.hpp 434022 2014-05-01 19:40:00Z vasilche $ +/* $Id: tse_handle.hpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -98,6 +98,9 @@ public: TBlobId GetBlobId(void) const; CDataLoader* GetDataLoader(void) const; + /// return estimated memory size occupied by this TSE + size_t GetUsedMemory(void) const; + bool Blob_IsSuppressed(void) const; bool Blob_IsSuppressedTemp(void) const; bool Blob_IsSuppressedPerm(void) const; diff --git a/c++/include/objmgr/util/autodef.hpp b/c++/include/objmgr/util/autodef.hpp new file mode 100644 index 00000000..af92abfc --- /dev/null +++ b/c++/include/objmgr/util/autodef.hpp @@ -0,0 +1,344 @@ +#ifndef OBJMGR_UTIL___AUTODEF__HPP +#define OBJMGR_UTIL___AUTODEF__HPP + +/* $Id: autodef.hpp 535882 2017-05-12 14:54:22Z bollin $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Colleen Bollin +* +* File Description: +* Creates unique definition lines for sequences in a set using organism +* descriptions and feature clauses. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) + +class NCBI_XOBJEDIT_EXPORT CAutoDef +{ +public: + + typedef set TAvailableModifierSet; + + CAutoDef(); + ~CAutoDef(); + + void AddSources(CSeq_entry_Handle se); + void AddSources(CBioseq_Handle bh); + CAutoDefModifierCombo* FindBestModifierCombo(); + CAutoDefModifierCombo* GetAllModifierCombo(); + CAutoDefModifierCombo* GetEmptyCombo(); + unsigned int GetNumAvailableModifiers(); + string GetOneSourceDescription(CBioseq_Handle bh); + string GetOneFeatureClauseList(CBioseq_Handle bh, unsigned int genome_val); + string GetOneDefLine(CAutoDefModifierCombo* mod_combo, CBioseq_Handle bh); + string GetOneDefLine(CBioseq_Handle bh); + + void SetOptionsObject(const CUser_object& user); + CRef GetOptionsObject() const { return m_Options.MakeUserObject(); } + + void SetFeatureListType(CAutoDefOptions::EFeatureListType feature_list_type); + void SetMiscFeatRule(CAutoDefOptions::EMiscFeatRule misc_feat_rule); + void SetProductFlag(CBioSource::EGenome product_flag); + void SetNuclearCopyFlag(CBioSource::EGenome product_flag); + void SetSpecifyNuclearProduct (bool specify_nuclear_product); + void SetAltSpliceFlag (bool alt_splice_flag); + void SetSuppressLocusTags(bool suppress_locus_tags); + void SetSuppressAllele(bool suppress_allele); + void SetGeneClusterOppStrand(bool gene_opp_strand); + void SetSuppressFeatureAltSplice (bool suppress_alt_splice); + void SuppressMobileElementAndInsertionSequenceSubfeatures(bool suppress); + void SuppressMiscFeatSubfeatures(bool suppress); + void SetKeepExons(bool keep); + void SetKeepIntrons(bool keep); + void SetKeepRegulatoryFeatures(bool keep); + void SetKeepLTRs(bool keep); + void SetKeep3UTRs(bool keep); + void SetKeep5UTRs(bool keep); + void SetKeepuORFs(bool keep); + void SetKeepOptionalMobileElements(bool keep); + void SetKeepPrecursorRNA(bool keep); + void SetKeepRepeatRegion(bool keep); + void SetKeepMiscRecomb(bool keep); + void SetUseNcRNAComment (bool use_comment); + void SetUseFakePromoters (bool use_fake); + void SetCustomFeatureClause(const string& custom_feature_clause); + + void SuppressFeature(objects::CFeatListItem feat); + void SuppressFeature(objects::CSeqFeatData::ESubtype subtype); + + typedef vector TModifierComboVector; + + void GetAvailableModifiers(TAvailableModifierSet &mod_set); + + void Cancel() { m_Cancelled = true; } + bool Cancelled() { return m_Cancelled; } + + static string GetKeywordPrefix(CBioseq_Handle bh); + + static bool RegenerateSequenceDefLines(CSeq_entry_Handle se); + static string RegenerateDefLine(CBioseq_Handle bh); + +private: + typedef vector TModifierIndexVector; + typedef vector TSeqEntryHandleVector; + + CAutoDefModifierCombo m_OrigModCombo; + + CAutoDefOptions m_Options; + + // feature clause specifications + bool m_Cancelled; + + void x_SortModifierListByRank + (TModifierIndexVector& index_list, + CAutoDefSourceDescription::TAvailableModifierVector& modifier_list); + void x_GetModifierIndexList + (TModifierIndexVector& index_list, + CAutoDefSourceDescription::TAvailableModifierVector& modifier_list); + + string x_GetNonFeatureListEnding(); + string x_GetFeatureClauses(CBioseq_Handle bh); + string x_GetFeatureClauseProductEnding(const string& feature_clauses, + CBioseq_Handle bh); + bool x_AddMiscRNAFeatures(CBioseq_Handle bh, + const CSeq_feat& cf, + const CSeq_loc& mapped_loc, + CAutoDefFeatureClause_Base& main_clause); + bool x_AddtRNAAndOther(CBioseq_Handle bh, + const CSeq_feat& cf, + const CSeq_loc& mapped_loc, + CAutoDefFeatureClause_Base& main_clause); + + void x_RemoveOptionalFeatures(CAutoDefFeatureClause_Base *main_clause, CBioseq_Handle bh); + + + bool x_IsOrgModRequired(unsigned int mod_type); + bool x_IsSubSrcRequired(unsigned int mod_type); + + bool x_IsFeatureSuppressed(CSeqFeatData::ESubtype subtype); + + void GetMasterLocation(CBioseq_Handle &bh, CRange& range); + bool IsSegment(CBioseq_Handle bh); + bool x_Is5SList(CFeat_CI feat_ci); + string x_GetHumanSTRFeatureClauses(CBioseq_Handle bh, const CUser_object& comment); + bool x_IsHumanSTR(const CUser_object& obj); + +}; // end of CAutoDef + + +inline +void CAutoDef::SetFeatureListType(CAutoDefOptions::EFeatureListType feature_list_type) +{ + m_Options.SetFeatureListType(feature_list_type); +} + + +inline +void CAutoDef::SetMiscFeatRule(CAutoDefOptions::EMiscFeatRule misc_feat_rule) +{ + m_Options.SetMiscFeatRule(misc_feat_rule); +} + + +inline +void CAutoDef::SetProductFlag(CBioSource::EGenome product_flag) +{ + m_Options.SetProductFlag(product_flag); +} + + +inline +void CAutoDef::SetNuclearCopyFlag(CBioSource::EGenome product_flag) +{ + m_Options.SetNuclearCopyFlag(product_flag); +} + + +inline +void CAutoDef::SetSpecifyNuclearProduct (bool specify_nuclear_product) +{ + m_Options.SetSpecifyNuclearProduct(specify_nuclear_product); +} + + +inline +void CAutoDef::SetAltSpliceFlag (bool alt_splice_flag) +{ + m_Options.SetAltSpliceFlag(alt_splice_flag); +} + + +inline +void CAutoDef::SetSuppressLocusTags (bool suppress_locus_tags) +{ + m_Options.SetSuppressLocusTags(suppress_locus_tags); +} + + +inline +void CAutoDef::SetGeneClusterOppStrand (bool gene_opp_strand) +{ + m_Options.SetGeneClusterOppStrand(gene_opp_strand); +} + + +inline +void CAutoDef::SetSuppressFeatureAltSplice (bool suppress_alt_splice) +{ + m_Options.SetSuppressFeatureAltSplice(suppress_alt_splice); +} + + +inline +void CAutoDef::SuppressMobileElementAndInsertionSequenceSubfeatures(bool suppress) +{ + m_Options.SetSuppressMobileElementSubfeatures(suppress); +} + + +inline +void CAutoDef::SuppressMiscFeatSubfeatures(bool suppress) +{ + m_Options.SetSuppressMiscFeatureSubfeatures(suppress); +} + + +inline +void CAutoDef::SetKeepExons(bool keep) +{ + m_Options.SetKeepExons(keep); +} + + +inline +void CAutoDef::SetKeepIntrons(bool keep) +{ + m_Options.SetKeepIntrons(keep); +} + + +inline +void CAutoDef::SetKeepRegulatoryFeatures(bool keep) +{ + m_Options.SetKeepRegulatoryFeatures(keep); +} + +inline +void CAutoDef::SetKeepLTRs(bool keep) +{ + m_Options.SetKeepLTRs(keep); +} + + +inline +void CAutoDef::SetKeep3UTRs(bool keep) +{ + m_Options.SetKeep3UTRs(keep); +} + + +inline +void CAutoDef::SetKeep5UTRs(bool keep) +{ + m_Options.SetKeep5UTRs(keep); +} + + +inline +void CAutoDef::SetKeepuORFs(bool keep) +{ + m_Options.SetKeepuORFs(keep); +} + + +inline +void CAutoDef::SetKeepOptionalMobileElements(bool keep) +{ + m_Options.SetKeepMobileElements(keep); +} + +inline +void CAutoDef::SetKeepPrecursorRNA(bool keep) +{ + m_Options.SetKeepPrecursorRNA(keep); +} + +inline +void CAutoDef::SetKeepRepeatRegion(bool keep) +{ + m_Options.SetKeepRepeatRegion(keep); +} + +inline +void CAutoDef::SetKeepMiscRecomb(bool keep) +{ + m_Options.SetKeepMiscRecomb(keep); +} + +inline +void CAutoDef::SetUseNcRNAComment(bool use_comment) +{ + m_Options.SetUseNcRNAComment(use_comment); +} + + +inline +void CAutoDef::SetUseFakePromoters(bool use_fake) +{ + m_Options.SetUseFakePromoters(use_fake); +} + + +inline +void CAutoDef::SetCustomFeatureClause(const string& custom_feature_clause) +{ + m_Options.SetCustomFeatureClause(custom_feature_clause); +} + +END_SCOPE(objects) +END_NCBI_SCOPE + +#endif //OBJMGR_UTIL___AUTODEF__HPP diff --git a/c++/include/objtools/edit/autodef_available_modifier.hpp b/c++/include/objmgr/util/autodef_available_modifier.hpp similarity index 93% rename from c++/include/objtools/edit/autodef_available_modifier.hpp rename to c++/include/objmgr/util/autodef_available_modifier.hpp index 66cb279a..596501d7 100644 --- a/c++/include/objtools/edit/autodef_available_modifier.hpp +++ b/c++/include/objmgr/util/autodef_available_modifier.hpp @@ -1,7 +1,7 @@ -#ifndef OBJTOOLS_EDIT___AUTODEF_AVAILABLE_MODIFIER__HPP -#define OBJTOOLS_EDIT___AUTODEF_AVAILABLE_MODIFIER__HPP +#ifndef OBJMGR_UTIL___AUTODEF_AVAILABLE_MODIFIER__HPP +#define OBJMGR_UTIL___AUTODEF_AVAILABLE_MODIFIER__HPP -/* $Id: autodef_available_modifier.hpp 136370 2008-08-04 13:15:27Z dicuccio $ +/* $Id: autodef_available_modifier.hpp 530276 2017-03-13 18:20:08Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -99,4 +99,4 @@ private: END_SCOPE(objects) END_NCBI_SCOPE -#endif //OBJTOOLS_EDIT___AUTODEF_AVAILABLE_MODIFIER__HPP +#endif //OBJMGR_UTIL___AUTODEF_AVAILABLE_MODIFIER__HPP diff --git a/c++/include/objtools/edit/autodef_feature_clause.hpp b/c++/include/objmgr/util/autodef_feature_clause.hpp similarity index 97% rename from c++/include/objtools/edit/autodef_feature_clause.hpp rename to c++/include/objmgr/util/autodef_feature_clause.hpp index 34d1024f..d0b9246e 100644 --- a/c++/include/objtools/edit/autodef_feature_clause.hpp +++ b/c++/include/objmgr/util/autodef_feature_clause.hpp @@ -1,7 +1,7 @@ -#ifndef OBJTOOLS_EDIT___AUTODEF_FEATURE_CLAUSE__HPP -#define OBJTOOLS_EDIT___AUTODEF_FEATURE_CLAUSE__HPP +#ifndef OBJMGR_UTIL___AUTODEF_FEATURE_CLAUSE__HPP +#define OBJMGR_UTIL___AUTODEF_FEATURE_CLAUSE__HPP -/* $Id: autodef_feature_clause.hpp 519214 2016-11-14 16:05:29Z ivanov $ +/* $Id: autodef_feature_clause.hpp 530276 2017-03-13 18:20:08Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,7 +33,7 @@ * descriptions and feature clauses. */ -#include +#include #include #include @@ -295,4 +295,4 @@ CAutoDefParsedtRNAClause *s_tRNAClauseFromNote(CBioseq_Handle bh, const CSeq_fea END_SCOPE(objects) END_NCBI_SCOPE -#endif //OBJTOOLS_EDIT___AUTODEF_FEATURE_CLAUSE__HPP +#endif //OBJMGR_UTIL___AUTODEF_FEATURE_CLAUSE__HPP diff --git a/c++/include/objtools/edit/autodef_feature_clause_base.hpp b/c++/include/objmgr/util/autodef_feature_clause_base.hpp similarity index 96% rename from c++/include/objtools/edit/autodef_feature_clause_base.hpp rename to c++/include/objmgr/util/autodef_feature_clause_base.hpp index ece2ba57..d152af55 100644 --- a/c++/include/objtools/edit/autodef_feature_clause_base.hpp +++ b/c++/include/objmgr/util/autodef_feature_clause_base.hpp @@ -1,7 +1,7 @@ -#ifndef OBJTOOLS_EDIT___AUTODEF_FEATURE_CLAUSE_BASE__HPP -#define OBJTOOLS_EDIT___AUTODEF_FEATURE_CLAUSE_BASE__HPP +#ifndef OBJMGR_UTIL___AUTODEF_FEATURE_CLAUSE_BASE__HPP +#define OBJMGR_UTIL___AUTODEF_FEATURE_CLAUSE_BASE__HPP -/* $Id: autodef_feature_clause_base.hpp 519214 2016-11-14 16:05:29Z ivanov $ +/* $Id: autodef_feature_clause_base.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -129,8 +129,8 @@ public: void ExpandExonLists(); virtual void ReverseCDSClauseLists(); - virtual bool OkToGroupUnderByType(CAutoDefFeatureClause_Base *parent_clause) { return false; } - virtual bool OkToGroupUnderByLocation(CAutoDefFeatureClause_Base *parent_clause, bool gene_cluster_opp_strand) { return false; } + virtual bool OkToGroupUnderByType(CAutoDefFeatureClause_Base * /*parent_clause*/) { return false; } + virtual bool OkToGroupUnderByLocation(CAutoDefFeatureClause_Base * /*parent_clause*/, bool /*gene_cluster_opp_strand*/) { return false; } virtual void SuppressMobileElementAndInsertionSequenceSubfeatures(); @@ -259,4 +259,4 @@ private: END_SCOPE(objects) END_NCBI_SCOPE -#endif //OBJTOOLS_EDIT___AUTODEF_FEATURE_CLAUSE_BASE__HPP +#endif //OBJMGR_UTIL___AUTODEF_FEATURE_CLAUSE_BASE__HPP diff --git a/c++/include/objtools/edit/autodef_mod_combo.hpp b/c++/include/objmgr/util/autodef_mod_combo.hpp similarity index 95% rename from c++/include/objtools/edit/autodef_mod_combo.hpp rename to c++/include/objmgr/util/autodef_mod_combo.hpp index 0c733017..53e62562 100644 --- a/c++/include/objtools/edit/autodef_mod_combo.hpp +++ b/c++/include/objmgr/util/autodef_mod_combo.hpp @@ -1,7 +1,7 @@ -#ifndef OBJTOOLS_EDIT___AUTODEF_MOD_COMBO__HPP -#define OBJTOOLS_EDIT___AUTODEF_MOD_COMBO__HPP +#ifndef OBJMGR_UTIL___AUTODEF_MOD_COMBO__HPP +#define OBJMGR_UTIL___AUTODEF_MOD_COMBO__HPP -/* $Id: autodef_mod_combo.hpp 500268 2016-05-03 16:31:45Z bollin $ +/* $Id: autodef_mod_combo.hpp 530276 2017-03-13 18:20:08Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -45,10 +45,10 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) @@ -343,4 +343,4 @@ CAutoDefOptions::EHIVCloneIsolateRule CAutoDefModifierCombo::GetHIVCloneIsolateR END_SCOPE(objects) END_NCBI_SCOPE -#endif //OBJTOOLS_EDIT___AUTODEF_MOD_COMBO__HPP +#endif //OBJMGR_UTIL___AUTODEF_MOD_COMBO__HPP diff --git a/c++/include/objmgr/util/autodef_options.hpp b/c++/include/objmgr/util/autodef_options.hpp new file mode 100644 index 00000000..fca8434e --- /dev/null +++ b/c++/include/objmgr/util/autodef_options.hpp @@ -0,0 +1,291 @@ +#ifndef OBJMGR_UTIL___AUTODEF_OPTIONS__HPP +#define OBJMGR_UTIL___AUTODEF_OPTIONS__HPP + +/* $Id: autodef_options.hpp 530276 2017-03-13 18:20:08Z bollin $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Colleen Bollin +* +* File Description: +* Creates unique definition lines for sequences in a set using organism +* descriptions and feature clauses. +*/ + +#include +#include +#include +#include +#include +#include +#include + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) + +class NCBI_XOBJEDIT_EXPORT CAutoDefOptions +{ +public: + CAutoDefOptions(); + ~CAutoDefOptions() {} + + CRef MakeUserObject() const; + void InitFromUserObject(const CUser_object& obj); + + enum EOptionFieldType { + eOptionFieldType_Unknown = 0, + eOptionFieldType_MaxMods, + eOptionFieldType_UseLabels, + eOptionFieldType_AllowModAtEndOfTaxname, + eOptionFieldType_LeaveParenthetical, + eOptionFieldType_DoNotApplyToSp, + eOptionFieldType_DoNotApplyToNr, + eOptionFieldType_DoNotApplyToCf, + eOptionFieldType_DoNotApplyToAff, + eOptionFieldType_IncludeCountryText, + eOptionFieldType_KeepAfterSemicolon, + eOptionFieldType_HIVRule, + eOptionFieldType_FeatureListType, + eOptionFieldType_MiscFeatRule, + eOptionFieldType_ProductFlag, + eOptionFieldType_NuclearCopyFlag, + eOptionFieldType_SpecifyNuclearProduct, + eOptionFieldType_AltSpliceFlag, + eOptionFieldType_SuppressLocusTags, + eOptionFieldType_SuppressAlleles, + eOptionFieldType_GeneClusterOppStrand, + eOptionFieldType_SuppressFeatureAltSplice, + eOptionFieldType_SuppressMobileElementSubfeatures, + eOptionFieldType_KeepExons, + eOptionFieldType_KeepIntrons, + eOptionFieldType_UseFakePromoters, + eOptionFieldType_KeepRegulatoryFeatures, + eOptionFieldType_KeepLTRs, + eOptionFieldType_Keep3UTRs, + eOptionFieldType_Keep5UTRs, + eOptionFieldType_KeepuORFs, + eOptionFieldType_KeepMobileElements, + eOptionFieldType_KeepPrecursorRNA, + eOptionFieldType_KeepRepeatRegion, + eOptionFieldType_KeepMiscRecomb, + eOptionFieldType_UseNcRNAComment, + eOptionFieldType_SuppressedFeatures, + eOptionFieldType_ModifierList, + eOptionFieldType_TargetedLocusName, + eOptionFieldType_SuppressMiscFeatureSubfeatures, + eOptionFieldType_CustomFeatureClause, + eOptionFieldMax + }; + + enum EFeatureListType { + eListAllFeatures = 0, + eCompleteSequence, + eCompleteGenome, + ePartialSequence, + ePartialGenome, + eSequence + }; + + typedef unsigned int TFeatureListType; + TFeatureListType GetFeatureListType() const { return m_FeatureListType; } + void SetFeatureListType(EFeatureListType list_type) { m_FeatureListType = list_type; } + + enum EMiscFeatRule { + eDelete = 0, + eNoncodingProductFeat, + eCommentFeat + }; + + typedef unsigned int TMiscFeatRule; + TMiscFeatRule GetMiscFeatRule() const { return m_MiscFeatRule; } + void SetMiscFeatRule(TMiscFeatRule rule) { m_MiscFeatRule = rule; } + + enum EHIVCloneIsolateRule { + ePreferClone = 0, + ePreferIsolate, + eWantBoth + }; + typedef unsigned int THIVRule; + THIVRule GetHIVRule() const { return m_HIVRule; } + void SetHIVRule(EHIVCloneIsolateRule rule) { m_HIVRule = rule; } + + bool GetUseFakePromoters() const { return m_BooleanFlags[eOptionFieldType_UseFakePromoters]; } + void SetUseFakePromoters(bool val = true) { + m_BooleanFlags[eOptionFieldType_UseFakePromoters] = val; + } + + CBioSource::TGenome GetProductFlag() const { return m_ProductFlag; }; + void SetProductFlag(CBioSource::EGenome val) { + m_ProductFlag = val; + m_BooleanFlags[eOptionFieldType_SpecifyNuclearProduct] = false; + m_NuclearCopyFlag = CBioSource::eGenome_unknown; + } + + CBioSource::TGenome GetNuclearCopyFlag() const { return m_NuclearCopyFlag; }; + void SetNuclearCopyFlag(CBioSource::EGenome val) { + m_NuclearCopyFlag = val; + m_BooleanFlags[eOptionFieldType_SpecifyNuclearProduct] = false; + m_ProductFlag = CBioSource::eGenome_unknown; + } + + bool GetSpecifyNuclearProduct() const { return m_BooleanFlags[eOptionFieldType_SpecifyNuclearProduct]; } + void SetSpecifyNuclearProduct(bool val) { + m_BooleanFlags[eOptionFieldType_SpecifyNuclearProduct] = val; + if (val) { + m_ProductFlag = CBioSource::eGenome_unknown; + m_NuclearCopyFlag = CBioSource::eGenome_unknown; + } + } + + int GetMaxMods() const { return m_MaxMods; } + void SetMaxMods(int val) { m_MaxMods = val; } + +#define AUTODEFBOOLFIELD(Fieldname) \ + bool Get##Fieldname() const { return m_BooleanFlags[eOptionFieldType_##Fieldname]; }; \ + void Set##Fieldname(bool val = true) { m_BooleanFlags[eOptionFieldType_##Fieldname] = val; } + + AUTODEFBOOLFIELD(UseLabels) + AUTODEFBOOLFIELD(LeaveParenthetical) + AUTODEFBOOLFIELD(AllowModAtEndOfTaxname) + AUTODEFBOOLFIELD(DoNotApplyToSp) + AUTODEFBOOLFIELD(DoNotApplyToNr) + AUTODEFBOOLFIELD(DoNotApplyToCf) + AUTODEFBOOLFIELD(DoNotApplyToAff) + AUTODEFBOOLFIELD(IncludeCountryText) + AUTODEFBOOLFIELD(KeepAfterSemicolon) + AUTODEFBOOLFIELD(AltSpliceFlag) + AUTODEFBOOLFIELD(SuppressLocusTags) + AUTODEFBOOLFIELD(SuppressAlleles) + AUTODEFBOOLFIELD(GeneClusterOppStrand) + AUTODEFBOOLFIELD(SuppressFeatureAltSplice) + AUTODEFBOOLFIELD(SuppressMobileElementSubfeatures) + AUTODEFBOOLFIELD(KeepExons) + AUTODEFBOOLFIELD(KeepIntrons) + AUTODEFBOOLFIELD(KeepRegulatoryFeatures) + AUTODEFBOOLFIELD(KeepLTRs) + AUTODEFBOOLFIELD(Keep3UTRs) + AUTODEFBOOLFIELD(Keep5UTRs) + AUTODEFBOOLFIELD(KeepuORFs) + AUTODEFBOOLFIELD(KeepMobileElements) + AUTODEFBOOLFIELD(KeepPrecursorRNA) + AUTODEFBOOLFIELD(KeepRepeatRegion) + AUTODEFBOOLFIELD(KeepMiscRecomb) + AUTODEFBOOLFIELD(UseNcRNAComment) + AUTODEFBOOLFIELD(SuppressMiscFeatureSubfeatures) + + bool IsFeatureSuppressed(CSeqFeatData::ESubtype subtype) const; + bool AreAnyFeaturesSuppressed() const { return !m_SuppressedFeatureSubtypes.empty(); } + void SuppressFeature(CSeqFeatData::ESubtype subtype); + void SuppressAllFeatures(); + void ClearSuppressedFeatures(); + + void AddSubSource(CSubSource::TSubtype subtype); + void AddOrgMod(COrgMod::TSubtype subtype); + typedef vector TOrgMods; + const TOrgMods& GetOrgMods() const { return m_OrgMods; } + typedef vector TSubSources; + const TSubSources& GetSubSources() const { return m_SubSources; } + void ClearModifierList(); + + string GetFeatureListType(TFeatureListType list_type) const; + TFeatureListType GetFeatureListType(const string& list_type) const; + + string GetMiscFeatRule(TMiscFeatRule list_type) const; + TMiscFeatRule GetMiscFeatRule(const string& list_type) const; + + string GetHIVRule(TMiscFeatRule list_type) const; + TMiscFeatRule GetHIVRule(const string& list_type) const; + + string GetProductFlag(CBioSource::TGenome value) const; + CBioSource::TGenome GetProductFlag(const string& value) const; + + string GetNuclearCopyFlag(CBioSource::TGenome value) const; + CBioSource::TGenome GetNuclearCopyFlag(const string& value) const; + + string GetTargetedLocusName() const { return m_TargetedLocusName; } + void SetTargetedLocusName(const string& tls) { m_TargetedLocusName = tls; } + + string GetCustomFeatureClause() const { return m_CustomFeatureClause; } + void SetCustomFeatureClause(const string& val) { m_CustomFeatureClause = val; } + +private: + + bool m_BooleanFlags[eOptionFieldMax]; + int m_MaxMods; + THIVRule m_HIVRule; + TFeatureListType m_FeatureListType; + TMiscFeatRule m_MiscFeatRule; + CBioSource::TGenome m_ProductFlag; + CBioSource::TGenome m_NuclearCopyFlag; + typedef vector TSuppressedFeatureSubtypes; + TSuppressedFeatureSubtypes m_SuppressedFeatureSubtypes; + string m_TargetedLocusName; + string m_CustomFeatureClause; + + TOrgMods m_OrgMods; + TSubSources m_SubSources; + + typedef unsigned int TFieldType; + string GetFieldType(TFieldType field_type) const; + TFieldType GetFieldType(const string& field_name) const; + + + + bool x_IsBoolean(TFieldType field_type) const; + CRef x_MakeBooleanField(TFieldType field_type) const; + + void x_MakeSuppressedFeatures(CUser_object& user) const; + void x_SetSuppressedFeatures(const CUser_field& field); + + void x_MakeModifierList(CUser_object& user) const; + void x_SetModifierList(const CUser_field& field); + + + CRef x_MakeMaxMods() const; + CRef x_MakeTargetedLocusName() const; + CRef x_MakeCustomFeatureClause() const; + +#define AUTODEFENUMFIELD(Fieldname) \ + CRef x_Make##Fieldname() const { \ + CRef field(new CUser_field()); \ + field->SetLabel().SetStr(GetFieldType(eOptionFieldType_##Fieldname)); \ + field->SetData().SetStr(Get##Fieldname(m_##Fieldname)); \ + return field; \ + } + + AUTODEFENUMFIELD(FeatureListType) + AUTODEFENUMFIELD(MiscFeatRule) + AUTODEFENUMFIELD(HIVRule) + AUTODEFENUMFIELD(ProductFlag) + AUTODEFENUMFIELD(NuclearCopyFlag) + + void x_Reset(); +}; + + + +END_SCOPE(objects) +END_NCBI_SCOPE + +#endif //OBJMGR_UTIL___AUTODEF_OPTIONS__HPP diff --git a/c++/include/objmgr/util/autodef_source_desc.hpp b/c++/include/objmgr/util/autodef_source_desc.hpp new file mode 100644 index 00000000..8695e760 --- /dev/null +++ b/c++/include/objmgr/util/autodef_source_desc.hpp @@ -0,0 +1,159 @@ +#ifndef OBJMGR_UTIL___AUTODEF_SOURCE_DESC__HPP +#define OBJMGR_UTIL___AUTODEF_SOURCE_DESC__HPP + +/* $Id: autodef_source_desc.hpp 530276 2017-03-13 18:20:08Z bollin $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Colleen Bollin +* +* File Description: +* Creates unique definition lines for sequences in a set using organism +* descriptions and feature clauses. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) + + +class NCBI_XOBJEDIT_EXPORT CAutoDefSourceModifierInfo +{ +public: + CAutoDefSourceModifierInfo(bool isOrgMod, int subtype, string value); + CAutoDefSourceModifierInfo(const CAutoDefSourceModifierInfo &other); + ~CAutoDefSourceModifierInfo(); + + unsigned int GetRank() const; + int Compare(const CAutoDefSourceModifierInfo& mod) const; + bool IsOrgMod () const; + int GetSubtype () const; + string GetValue () const; + + bool operator>(const CAutoDefSourceModifierInfo& mod) const + { + return Compare (mod) > 0; + } + + bool operator<(const CAutoDefSourceModifierInfo& mod) const + { + return Compare (mod) < 0; + } + + +private: + bool m_IsOrgMod; + int m_Subtype; + string m_Value; +}; + + +inline bool CAutoDefSourceModifierInfo::IsOrgMod() const +{ + return m_IsOrgMod; +} + + +inline int CAutoDefSourceModifierInfo::GetSubtype() const +{ + return m_Subtype; +} + + +inline string CAutoDefSourceModifierInfo::GetValue() const +{ + return m_Value; +} + + +class IAutoDefCombo +{ +public: + virtual ~IAutoDefCombo() { } + virtual string GetSourceDescriptionString(const CBioSource& biosrc) = 0; +}; + + +class NCBI_XOBJEDIT_EXPORT CAutoDefSourceDescription +{ +public: + CAutoDefSourceDescription(const CBioSource& bs, string feature_clauses = ""); + CAutoDefSourceDescription(CAutoDefSourceDescription *other); + ~CAutoDefSourceDescription(); + + typedef vector TStringVector; + typedef vector TAvailableModifierVector; + + const CBioSource& GetBioSource() const; + + void GetAvailableModifiers (TAvailableModifierVector &modifier_list); + + bool IsTrickyHIV(); + + string GetComboDescription(IAutoDefCombo *mod_combo); + + bool AddQual (bool isOrgMod, int subtype, bool keepAfterSemicolon); + bool RemoveQual (bool isOrgMod, int subtype); + int Compare(const CAutoDefSourceDescription& s) const; + bool operator>(const CAutoDefSourceDescription& src) const + { + return Compare (src) > 0; + } + + bool operator<(const CAutoDefSourceDescription& src) const + { + return Compare (src) < 0; + } + + typedef vector TModifierVector; + const TModifierVector& GetModifiers() const { return m_Modifiers; } + typedef list TDescString; + const TDescString& GetStrings() const { return m_DescStrings; } + const string& GetFeatureClauses() const { return m_FeatureClauses; } + +private: + const CBioSource& m_BS; + TModifierVector m_Modifiers; + TDescString m_DescStrings; + string m_FeatureClauses; +}; + + +END_SCOPE(objects) +END_NCBI_SCOPE + +#endif //OBJMGR_UTIL___AUTODEF_SOURCE_DESC__HPP diff --git a/c++/include/objtools/edit/autodef_source_group.hpp b/c++/include/objmgr/util/autodef_source_group.hpp similarity index 91% rename from c++/include/objtools/edit/autodef_source_group.hpp rename to c++/include/objmgr/util/autodef_source_group.hpp index 8e8bce69..9baa4a5b 100644 --- a/c++/include/objtools/edit/autodef_source_group.hpp +++ b/c++/include/objmgr/util/autodef_source_group.hpp @@ -1,7 +1,7 @@ -#ifndef OBJTOOLS_EDIT___AUTODEF_SOURCE_GROUP__HPP -#define OBJTOOLS_EDIT___AUTODEF_SOURCE_GROUP__HPP +#ifndef OBJMGR_UTIL___AUTODEF_SOURCE_GROUP__HPP +#define OBJMGR_UTIL___AUTODEF_SOURCE_GROUP__HPP -/* $Id: autodef_source_group.hpp 142615 2008-10-08 16:38:42Z bollin $ +/* $Id: autodef_source_group.hpp 530276 2017-03-13 18:20:08Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -45,8 +45,8 @@ #include #include -#include -#include +#include +#include BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) @@ -101,4 +101,4 @@ private: END_SCOPE(objects) END_NCBI_SCOPE -#endif //OBJTOOLS_EDIT___AUTODEF_SOURCE_GROUP__HPP +#endif //OBJMGR_UTIL___AUTODEF_SOURCE_GROUP__HPP diff --git a/c++/include/objmgr/util/create_defline.hpp b/c++/include/objmgr/util/create_defline.hpp index b5137042..84036115 100644 --- a/c++/include/objmgr/util/create_defline.hpp +++ b/c++/include/objmgr/util/create_defline.hpp @@ -39,6 +39,7 @@ #include #include #include +#include /** @addtogroup ObjUtilSequence * @@ -80,14 +81,15 @@ public: /// User-settable flags for tuning behavior enum EUserFlags { - fIgnoreExisting = 0x1, ///< Generate fresh titles unconditionally. - fAllProteinNames = 0x2, ///< List all relevant proteins, not just one. - fLocalAnnotsOnly = 0x4, ///< Never use related sequences' annotations. + fIgnoreExisting = 1 << 0, ///< Generate fresh titles unconditionally. + fAllProteinNames = 1 << 1, ///< List all relevant proteins, not just one. + fLocalAnnotsOnly = 1 << 2, ///< Never use related sequences' annotations. /// Refrain from anything that could add substantial overhead. fNoExpensiveOps = fLocalAnnotsOnly, - fGpipeMode = 0x8, ///< Use GPipe defaults. - fOmitTaxonomicName = 0x10, ///< Do not add organism suffix to proteins. - fDevMode = 0x20 ///< Development mode for testing new features. + fGpipeMode = 1 << 3, ///< Use GPipe defaults. + fOmitTaxonomicName = 1 << 4, ///< Do not add organism suffix to proteins. + fDevMode = 1 << 5, ///< Development mode for testing new features. + fShowModifiers = 1 << 8 ///< show key-value pair modifiers (e.g. "[organism=Homo sapiens]") }; typedef int TUserFlags; ///< Binary "OR" of EUserFlags @@ -97,13 +99,44 @@ public: TUserFlags flags = 0 ); + /// Main method + string GenerateDefline ( + const CBioseq_Handle& bsh, + CSeqEntryIndex& idx, + TUserFlags flags = 0 + ); + /// Main method string GenerateDefline ( const CBioseq& bioseq, CScope& scope, + CSeqEntryIndex& idx, TUserFlags flags = 0 ); + /// Main method + string GenerateDefline ( + const CBioseq_Handle& bsh, + feature::CFeatTree& ftree, + TUserFlags flags = 0 + ); + + /// Main method + string GenerateDefline ( + const CBioseq& bioseq, + CScope& scope, + TUserFlags flags = 0 + ); + + /// Main method + string GenerateDefline ( + const CBioseq& bioseq, + CScope& scope, + feature::CFeatTree& ftree, + TUserFlags flags = 0 + ); + + string x_GetModifiers(const CBioseq_Handle & handle); private: // Prohibit copy constructor & assignment operator CDeflineGenerator (const CDeflineGenerator&); @@ -151,6 +184,9 @@ private: void x_SetTitleFromProtein ( const CBioseq_Handle& bsh ); + void x_SetTitleFromProteinIdx ( + const CBioseq_Handle& bsh + ); void x_SetTitleFromSegSeq ( const CBioseq_Handle& bsh ); @@ -170,10 +206,14 @@ private: const CBioseq_Handle& bsh ); + bool x_IsComplete() const; private: + /// index with feature tree for each Bioseq + CRef m_Idx; + /// internal feature tree for parent mapping - CRef m_Feat_Tree; CSeq_entry_Handle m_TopSEH; + CRef m_Feat_Tree; bool m_ConstructedFeatTree; bool m_InitializedFeatTree; @@ -209,6 +249,7 @@ private: string m_MainTitle; string m_GeneralStr; + int m_GeneralId; string m_PatentCountry; string m_PatentNumber; diff --git a/c++/include/objmgr/util/feature_edit.hpp b/c++/include/objmgr/util/feature_edit.hpp new file mode 100644 index 00000000..6b9af7d3 --- /dev/null +++ b/c++/include/objmgr/util/feature_edit.hpp @@ -0,0 +1,90 @@ +/* $Id: feature_edit.hpp 546431 2017-09-18 17:09:40Z ivanov $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Justin Foley, NCBI + * + * File Description: + * Feature trimming code + */ + +#ifndef _FEATURE_EDIT_HPP_ +#define _FEATURE_EDIT_HPP_ + +#include +#include +#include +#include +#include + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) +BEGIN_SCOPE(sequence) + +// ---------------------------------------------------------------------------- +class NCBI_XOBJEDIT_EXPORT CFeatTrim +// ---------------------------------------------------------------------------- +{ +public: + static CRef Apply( + const CSeq_feat& feat, + const CRange& range); + + static CRef Apply( + const CSeq_loc& loc, + const CRange& range); + + static CRef Apply( + const CCode_break& code_break, + const CRange& range); + + static CRef Apply( + const CTrna_ext& trna_ext, + const CRange& range); + + static CCdregion::EFrame GetCdsFrame( + const CSeq_feat& cds_feature, + const CRange& range); + + +private: + static void x_TrimLocation(TSeqPos from, TSeqPos to, + bool set_partial, + CRef& loc); + static TSeqPos x_GetStartOffset(const CSeq_feat& feat, + TSeqPos from, TSeqPos to); + static TSeqPos x_GetFrame(const CCdregion& cdregion); + static CCdregion::EFrame x_GetNewFrame(TSeqPos offset, const CCdregion& region); + + static void x_UpdateFrame(TSeqPos offset, CCdregion& cdregion); + static void x_TrimTrnaExt(TSeqPos from, TSeqPos to, CTrna_ext& ext); + static void x_TrimCodeBreak(TSeqPos from, TSeqPos to, CCode_break& cod_break); +}; + +END_SCOPE(sequence) +END_SCOPE(objects) +END_NCBI_SCOPE + +#endif + diff --git a/c++/include/objmgr/util/indexer.hpp b/c++/include/objmgr/util/indexer.hpp new file mode 100644 index 00000000..0ff1f4e7 --- /dev/null +++ b/c++/include/objmgr/util/indexer.hpp @@ -0,0 +1,856 @@ +#ifndef FEATURE_INDEXER__HPP +#define FEATURE_INDEXER__HPP + +/* +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Jonathan Kans +* +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) + + +// look-ahead class names +class CSeqEntryIndex; +class CSeqMasterIndex; +class CSeqsetIndex; +class CBioseqIndex; +class CGapIndex; +class CDescriptorIndex; +class CFeatureIndex; + + +// CSeqEntryIndex +// +// CSeqEntryIndex is the public, top-level Seq-entry exploration organizer. A variable +// is created using the top-level sequence object, with the constructors taking optional +// fetch policy and feature collection flags, as well as an optional feature exploration +// depth parameter (for the default adaptive fetch policy): +// +// CSeqEntryIndex idx(*m_entry, CSeqEntryIndex::fAdaptive); +// +// A Seq-entry wrapper is created if the top-level object is a Bioseq or Bioseq-set. +// Bioseqs within the Seq-entry are then indexed and added to a vector of CBioseqIndex. +// +// Bioseqs are explored with IterateBioseqs, or selected individually by GetBioseqIndex +// (given an accession, index number, or subregion): +// +// idx.IterateBioseqs("U54469", [this](CBioseqIndex& bsx) { +// ... +// }); +// +// The embedded lambda function statements are executed for each selected Bioseq. +// +// Internal indexing objects (i.e., CSeqMasterIndex, CSeqsetIndex, CBioseqIndex, +// CDescriptorIndex, and CFeatureIndex) are generated by the indexing process, and +// should not be created by the application. +class NCBI_XOBJUTIL_EXPORT CSeqEntryIndex : public CObjectEx +{ +public: + + enum EPolicy { + // far feature fetch policy + fAdaptive = 0, + fInternal = 1, + fExternal = 2, + fExhaustive = 3 + }; + + enum EFlags { + fDefault = 0, + fHideImpFeats = 1, + fHideSNPFeats = 2, + fHideSTSFeats = 4, + fHideExonFeats = 8, + fHideIntronFeats = 16, + fHideMiscFeats = 32 + }; + typedef int TFlags; // Binary "OR" of EFlags + +public: + // Constructors take the top-level sequence object + + // The primary constructor uses an existing CScope created by the application + CSeqEntryIndex (CSeq_entry_Handle& topseh, EPolicy policy = fAdaptive, TFlags flags = fDefault, int depth = -1); + + // Alternative constructors take an object and create a new local default CScope + CSeqEntryIndex (CSeq_entry& topsep, EPolicy policy = fAdaptive, TFlags flags = fDefault, int depth = -1); + CSeqEntryIndex (CBioseq_set& seqset, EPolicy policy = fAdaptive, TFlags flags = fDefault, int depth = -1); + CSeqEntryIndex (CBioseq& bioseq, EPolicy policy = fAdaptive, TFlags flags = fDefault, int depth = -1); + CSeqEntryIndex (CSeq_submit& submit, EPolicy policy = fAdaptive, TFlags flags = fDefault, int depth = -1); + + // Specialized constructors are for streaming through release files, one component at a time + + // Submit-block obtained from top of Seq-submit release file + CSeqEntryIndex (CSeq_entry& topsep, CSubmit_block &sblock, EPolicy policy = fAdaptive, TFlags flags = fDefault, int depth = -1); + // Seq-descr chain obtained from top of Bioseq-set release file + CSeqEntryIndex (CSeq_entry& topsep, CSeq_descr &descr, EPolicy policy = fAdaptive, TFlags flags = fDefault, int depth = -1); + +private: + // Prohibit copy constructor & assignment operator + CSeqEntryIndex (const CSeqEntryIndex&) = delete; + CSeqEntryIndex& operator= (const CSeqEntryIndex&) = delete; + +public: + // Bioseq exploration iterator + template size_t IterateBioseqs (Fnc m); + + // GetBioseqIndex methods are provided for a variety of argument types + + // Get first Bioseq index + CRef GetBioseqIndex (void); + // Get Nth Bioseq index + CRef GetBioseqIndex (int n); + // Get Bioseq index by accession + CRef GetBioseqIndex (const string& accn); + // Get Bioseq index by handle + CRef GetBioseqIndex (CBioseq_Handle bsh); + // Get Bioseq index by mapped feature + CRef GetBioseqIndex (const CMappedFeat& mf); + + // Subrange processing creates a new CBioseqIndex around a temporary delta Bioseq + + // Get Bioseq index by sublocation + CRef GetBioseqIndex (const CSeq_loc& loc); + // Get Bioseq index by subrange + CRef GetBioseqIndex (const string& accn, int from, int to, bool rev_comp); + CRef GetBioseqIndex (int from, int to, bool rev_comp); + + // Seqset exploration iterator + template size_t IterateSeqsets (Fnc m); + + const vector>& GetBioseqIndices(void); + + const vector>& GetSeqsetIndices(void); + + // Check all Bioseqs for failure to fetch remote sequence components or feature annotation + bool IsFetchFailure(void); + +private: + // Implementation details are in a separate CSeqMasterIndex object wrapped in a CRef + CRef m_Idx; +}; + + +// CSeqMasterIndex +// +// CSeqMasterIndex holds the implementation methods and variables for the CSeqEntryIndex +class NCBI_XOBJUTIL_EXPORT CSeqMasterIndex : public CObjectEx +{ +public: + // Constructor is separate from Initializers so that CSeqEntryIndex can capture a CRef to + // its CSeqMasterIndex, making CWeakRef available to GetFeatureForProduct + CSeqMasterIndex (void) { } + +public: + // Initializers take the top-level sequence object + void x_Initialize (CSeq_entry_Handle& topseh, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth); + + void x_Initialize (CSeq_entry& topsep, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth); + void x_Initialize (CBioseq_set& seqset, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth); + void x_Initialize (CBioseq& bioseq, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth); + void x_Initialize (CSeq_submit& submit, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth); + + void x_Initialize (CSeq_entry& topsep, CSubmit_block &sblock, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth); + void x_Initialize (CSeq_entry& topsep, CSeq_descr &descr, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth); + +private: + // Prohibit copy constructor & assignment operator + CSeqMasterIndex (const CSeqMasterIndex&) = delete; + CSeqMasterIndex& operator= (const CSeqMasterIndex&) = delete; + +public: + // Bioseq exploration iterator + template size_t IterateBioseqs (Fnc m); + + // Get first Bioseq index + CRef GetBioseqIndex (void); + // Get Nth Bioseq index + CRef GetBioseqIndex (int n); + // Get Bioseq index by accession + CRef GetBioseqIndex (const string& accn); + // Get Bioseq index by handle + CRef GetBioseqIndex (CBioseq_Handle bsh); + // Get Bioseq index by feature + CRef GetBioseqIndex (const CMappedFeat& mf); + + // Subrange processing creates a new CBioseqIndex around a temporary delta Bioseq + // Get Bioseq index by sublocation + CRef GetBioseqIndex (const CSeq_loc& loc); + // Get Bioseq index by subrange + CRef GetBioseqIndex (const string& accn, int from, int to, bool rev_comp); + CRef GetBioseqIndex (int from, int to, bool rev_comp); + + // Seqset exploration iterator + template size_t IterateSeqsets (Fnc m); + + // Getters + CRef GetObjectManager (void) const { return m_Objmgr; } + CRef GetScope (void) const { return m_Scope; } + CSeq_entry_Handle GetTopSEH (void) const { return m_Tseh; } + CConstRef GetTopSEP (void) const { return m_Tsep; } + CConstRef GetSbtBlk (void) const { return m_SbtBlk; } + CConstRef GetTopDescr (void) const { return m_TopDescr; } + + const vector>& GetBioseqIndices(void); + + const vector>& GetSeqsetIndices(void); + + // Check all Bioseqs for failure to fetch remote sequence components or remote feature annotation + bool IsFetchFailure(void); + +private: + // Common initialization function called by each Initialize variant + void x_Init (void); + + // Recursive exploration to populate vector of index objects for Bioseqs in Seq-entry + void x_InitSeqs (const CSeq_entry& sep, CRef prnt); + + CRef x_MakeUniqueId(void); + + // Create delta sequence referring to location, using temporary local ID + CRef x_DeltaIndex(const CSeq_loc& loc); + + // Create location from range, to use in x_DeltaIndex + CConstRef x_SubRangeLoc(const string& accn, int from, int to, bool rev_comp); + +private: + CRef m_Objmgr; + CRef m_Scope; + CSeq_entry_Handle m_Tseh; + + CConstRef m_Tsep; + CConstRef m_SbtBlk; + CConstRef m_TopDescr; + + CSeqEntryIndex::EPolicy m_Policy; + CSeqEntryIndex::TFlags m_Flags; + int m_Depth; + + vector> m_BsxList; + + // map from accession string to CBioseqIndex object + typedef map > TAccnIndexMap; + TAccnIndexMap m_AccnIndexMap; + + // map from CBioseq_Handle to CBioseqIndex object via best Seq-id string + typedef map > TBestIdIndexMap; + TBestIdIndexMap m_BestIdIndexMap; + + vector> m_SsxList; + + mutable CAtomicCounter m_Counter; +}; + + +// CSeqsetIndex +// +// CSeqsetIndex stores information about an element in the Bioseq-set hierarchy +class NCBI_XOBJUTIL_EXPORT CSeqsetIndex : public CObjectEx +{ +public: + // Constructor + CSeqsetIndex (CBioseq_set_Handle ssh, + const CBioseq_set& bssp, + CRef prnt); + +private: + // Prohibit copy constructor & assignment operator + CSeqsetIndex (const CSeqsetIndex&) = delete; + CSeqsetIndex& operator= (const CSeqsetIndex&) = delete; + +public: + // Getters + CBioseq_set_Handle GetSeqsetHandle (void) const { return m_Ssh; } + const CBioseq_set& GetSeqset (void) const { return m_Bssp; } + CRef GetParent (void) const { return m_Prnt; } + + CBioseq_set::TClass GetClass (void) const { return m_Class; } + +private: + CBioseq_set_Handle m_Ssh; + const CBioseq_set& m_Bssp; + CRef m_Prnt; + + CBioseq_set::TClass m_Class; +}; + + +// CBioseqIndex +// +// CBioseqIndex is the exploration organizer for a given Bioseq. It provides methods to +// obtain descriptors and iterate through features that apply to the Bioseq. (These are +// stored in vectors, which are initialized upon first request.) +// +// CBioseqIndex also maintains a CFeatTree for its Bioseq, used to find the best gene for +// each feature. +// +// Descriptors are explored with: +// +// bsx.IterateDescriptors([this](CDescriptorIndex& sdx) { +// ... +// }); +// +// and are presented based on the order of the descriptor chain hierarchy, starting with +// descriptors packaged on the Bioseq, then on its parent Bioseq-set, etc. +// +// Features are explored with: +// +// bsx.IterateFeatures([this](CFeatureIndex& sfx) { +// ... +// }); +// +// and are presented in order of biological position along the parent sequence. +// +// Fetching external features uses SAnnotSelector adaptive depth unless explicitly overridden. +class NCBI_XOBJUTIL_EXPORT CBioseqIndex : public CObjectEx +{ +public: + // Constructor + CBioseqIndex (CBioseq_Handle bsh, + const CBioseq& bsp, + CBioseq_Handle obsh, + CRef prnt, + CSeq_entry_Handle tseh, + CRef scope, + CSeqMasterIndex& idx, + CSeqEntryIndex::EPolicy policy, + CSeqEntryIndex::TFlags flags, + int depth, + bool surrogate); + + // Destructor + ~CBioseqIndex (void); + +private: + // Prohibit copy constructor & assignment operator + CBioseqIndex (const CBioseqIndex&) = delete; + CBioseqIndex& operator= (const CBioseqIndex&) = delete; + +public: + // Gap exploration iterator + template size_t IterateGaps (Fnc m); + + // Descriptor exploration iterator + template size_t IterateDescriptors (Fnc m); + + // Feature exploration iterator + template size_t IterateFeatures (Fnc m); + + // Getters + CBioseq_Handle GetBioseqHandle (void) const { return m_Bsh; } + const CBioseq& GetBioseq (void) const { return m_Bsp; } + CBioseq_Handle GetOrigBioseqHandle (void) const { return m_OrigBsh; } + CRef GetParent (void) const { return m_Prnt; } + CRef GetScope (void) const { return m_Scope; } + feature::CFeatTree& GetFeatTree (void) { return m_FeatTree; } + CRef GetSeqVector (void) const { return m_SeqVec; } + + // Get master index + CWeakRef GetSeqMasterIndex (void) const { return m_Idx; } + + const string& GetAccession (void) const { return m_Accession; } + + // Seq-inst fields + bool IsNA (void) const { return m_IsNA; } + bool IsAA (void) const { return m_IsAA; } + CSeq_inst::TTopology GetTopology (void) const { return m_Topology; } + CSeq_inst::TLength GetLength (void) const { return m_Length; } + + bool IsDelta (void) const { return m_IsDelta; } + bool IsVirtual (void) const { return m_IsVirtual; } + bool IsMap (void) const { return m_IsMap; } + + // Most important descriptor fields + + const string& GetTitle (void); + + CConstRef GetMolInfo (void); + CMolInfo::TBiomol GetBiomol (void); + CMolInfo::TTech GetTech (void); + CMolInfo::TCompleteness GetCompleteness (void); + + CConstRef GetBioSource (void); + const string& GetTaxname (void); + + // Get sequence letters from Bioseq + string GetSequence (void); + void GetSequence (string& buffer); + // Get sequence letters from Bioseq subrange + string GetSequence (int from, int to); + void GetSequence (int from, int to, string& buffer); + + // Map from GetBestGene result to CFeatureIndex object + CRef GetFeatIndex (const CMappedFeat& mf); + + const vector>& GetGapIndices(void); + + const vector>& GetDescriptorIndices(void); + + const vector>& GetFeatureIndices(void); + + // Get feature (CDS, mRNA, Prot) with product pointing to this Bioseq (protein, cDNA, peptide) + CRef GetFeatureForProduct(void); + + // Get Bioseq index containing feature with product pointing to this Bioseq + CWeakRef GetBioseqForProduct (void); + + // Get best (longest) protein feature on this protein Bioseq + CRef GetBestProteinFeature(void); + + // Check if Bioseq has BioSource features + bool HasSourceFeats (void); + + // Flag to indicate failure to fetch remote sequence components or feature annotation + bool IsFetchFailure (void) const { return m_FetchFailure; } + + void SetFetchFailure (bool fails) { m_FetchFailure = fails; } + +private: + // Common gap collection, delayed until actually needed + void x_InitGaps (void); + + // Common descriptor collection, delayed until actually needed + void x_InitDescs (void); + + // Common feature collection, delayed until actually needed + void x_InitFeats (void); + +private: + CBioseq_Handle m_Bsh; + const CBioseq& m_Bsp; + CBioseq_Handle m_OrigBsh; + CRef m_Prnt; + CSeq_entry_Handle m_Tseh; + CRef m_Scope; + + CWeakRef m_Idx; + + bool m_GapsInitialized; + vector> m_GapList; + + bool m_DescsInitialized; + vector> m_SdxList; + + bool m_FeatsInitialized; + vector> m_SfxList; + feature::CFeatTree m_FeatTree; + + CRef m_FeatureForProduct; + CRef m_BestProteinFeature; + + // CFeatureIndex from CMappedFeat for use with GetBestGene + typedef map > TFeatIndexMap; + TFeatIndexMap m_FeatIndexMap; + + bool m_HasSourceFeats; + + CRef m_SeqVec; + + CSeqEntryIndex::EPolicy m_Policy; + CSeqEntryIndex::TFlags m_Flags; + int m_Depth; + + bool m_FetchFailure; + +private: + // Seq-id field + string m_Accession; + + // Seq-inst fields + bool m_IsNA; + bool m_IsAA; + CSeq_inst::TTopology m_Topology; + CSeq_inst::TLength m_Length; + + bool m_IsDelta; + bool m_IsVirtual; + bool m_IsMap; + + // Instantiated title + string m_Title; + + // MolInfo fields + CConstRef m_MolInfo; + CMolInfo::TBiomol m_Biomol; + CMolInfo::TTech m_Tech; + CMolInfo::TCompleteness m_Completeness; + + // BioSource fields + CConstRef m_BioSource; + string m_Taxname; + + // User object fields + bool m_ForceOnlyNearFeats; + + // true if this index is for a temporary subrange delta Bioseq + bool m_Surrogate; +}; + + +// CGapIndex +// +// CGapIndex stores information about an indexed descriptor +class NCBI_XOBJUTIL_EXPORT CGapIndex : public CObject +{ +public: + // Constructor + CGapIndex (TSeqPos start, + TSeqPos end, + TSeqPos length, + const string& type, + const vector& evidence, + bool isUnknownLength, + bool isAssemblyGap, + CBioseqIndex& bsx); + +private: + // Prohibit copy constructor & assignment operator + CGapIndex (const CGapIndex&) = delete; + CGapIndex& operator= (const CGapIndex&) = delete; + +public: + // Getters + + TSeqPos GetStart (void) const { return m_Start; } + TSeqPos GetEnd (void) const { return m_End; } + TSeqPos GetLength (void) const { return m_Length; } + const string GetGapType (void) const { return m_GapType; } + const vector& GetGapEvidence (void) const { return m_GapEvidence; } + bool IsUnknownLength (void) const { return m_IsUnknownLength; } + bool IsAssemblyGap (void) const { return m_IsAssemblyGap; } + + // Get parent Bioseq index + CWeakRef GetBioseqIndex (void) const { return m_Bsx; } + +private: + CWeakRef m_Bsx; + + TSeqPos m_Start; + TSeqPos m_End; + TSeqPos m_Length; + + string m_GapType; + vector m_GapEvidence; + + bool m_IsUnknownLength; + bool m_IsAssemblyGap; +}; + + +// CDescriptorIndex +// +// CDescriptorIndex stores information about an indexed descriptor +class NCBI_XOBJUTIL_EXPORT CDescriptorIndex : public CObject +{ +public: + // Constructor + CDescriptorIndex (const CSeqdesc& sd, + CBioseqIndex& bsx); + +private: + // Prohibit copy constructor & assignment operator + CDescriptorIndex (const CDescriptorIndex&) = delete; + CDescriptorIndex& operator= (const CDescriptorIndex&) = delete; + +public: + // Getters + const CSeqdesc& GetSeqDesc (void) const { return m_Sd; } + + // Get parent Bioseq index + CWeakRef GetBioseqIndex (void) const { return m_Bsx; } + + // Get descriptor type (e.g., CSeqdesc::e_Molinfo) + CSeqdesc::E_Choice GetType (void) const { return m_Type; } + +private: + const CSeqdesc& m_Sd; + CWeakRef m_Bsx; + + CSeqdesc::E_Choice m_Type; +}; + + +// CFeatureIndex +// +// CFeatureIndex stores information about an indexed feature +class NCBI_XOBJUTIL_EXPORT CFeatureIndex : public CObject +{ +public: + // Constructor + CFeatureIndex (CSeq_feat_Handle sfh, + const CMappedFeat mf, + CBioseqIndex& bsx); + +private: + // Prohibit copy constructor & assignment operator + CFeatureIndex (const CFeatureIndex&) = delete; + CFeatureIndex& operator= (const CFeatureIndex&) = delete; + +public: + // Getters + CSeq_feat_Handle GetSeqFeatHandle (void) const { return m_Sfh; } + const CMappedFeat GetMappedFeat (void) const { return m_Mf; } + CRef GetSeqVector (void) const { return m_SeqVec; } + + CConstRef GetMappedLocation(void) const { return m_Fl; } + + // Get parent Bioseq index + CWeakRef GetBioseqIndex (void) const { return m_Bsx; } + + // Get feature type (e.g. CSeqFeatData::e_Rna) + CSeqFeatData::E_Choice GetType (void) const { return m_Type; } + + // Get feature subtype (e.g. CSeqFeatData::eSubtype_mRNA) + CSeqFeatData::ESubtype GetSubtype (void) const { return m_Subtype; } + + TSeqPos GetStart (void) const { return m_Start; } + TSeqPos GetEnd (void) const { return m_End; } + + // Get sequence letters under feature intervals + string GetSequence (void); + void GetSequence (string& buffer); + // Get sequence letters under feature subrange + string GetSequence (int from, int to); + void GetSequence (int from, int to, string& buffer); + + // Map from feature to CFeatureIndex for best gene using CFeatTree in parent CBioseqIndex + CRef GetBestGene (void); + +private: + void SetFetchFailure (bool fails); + +private: + CSeq_feat_Handle m_Sfh; + const CMappedFeat m_Mf; + CConstRef m_Fl; + CRef m_SeqVec; + CWeakRef m_Bsx; + + CSeqFeatData::E_Choice m_Type; + CSeqFeatData::ESubtype m_Subtype; + + TSeqPos m_Start; + TSeqPos m_End; +}; + + +// CWordPairIndexer +// +// CWordPairIndexer generates normalized terms and adjacent word pairs for Entrez indexing +class NCBI_XOBJUTIL_EXPORT CWordPairIndexer +{ +public: + // Constructor + CWordPairIndexer (void) { } + +private: + // Prohibit copy constructor & assignment operator + CWordPairIndexer (const CWordPairIndexer&) = delete; + CWordPairIndexer& operator= (const CWordPairIndexer&) = delete; + +public: + void PopulateWordPairIndex (string str); + + template void IterateNorm (Fnc m); + template void IteratePair (Fnc m); + +public: + static string ConvertUTF8ToAscii(const string& str); + static string TrimPunctuation (const string& str); + static string TrimMixedContent (const string& str); + static bool IsStopWord(const string& str); + + const vector& GetNorm (void) const { return m_Norm; } + const vector& GetPair (void) const { return m_Pair; } + +private: + string x_AddToWordPairIndex (string item, string prev); + + vector m_Norm; + vector m_Pair; +}; + + +// Inline lambda function implementations + +// Visit CBioseqIndex objects for all Bioseqs +template +inline +size_t CSeqEntryIndex::IterateBioseqs (Fnc m) + +{ + return m_Idx->IterateBioseqs(m); +} + +template +inline +size_t CSeqMasterIndex::IterateBioseqs (Fnc m) + +{ + int count = 0; + for (auto& bsx : m_BsxList) { + m(*bsx); + count++; + } + return count; +} + +// Visit CSeqsetIndex objects for all Seqsets +template +inline +size_t CSeqEntryIndex::IterateSeqsets (Fnc m) + +{ + return m_Idx->IterateSeqsets(m); +} + +template +inline +size_t CSeqMasterIndex::IterateSeqsets (Fnc m) + +{ + int count = 0; + for (auto& ssx : m_SsxList) { + m(*ssx); + count++; + } + return count; +} + +// Visit CGapIndex objects for all gaps +template +inline +size_t CBioseqIndex::IterateGaps (Fnc m) + +{ + int count = 0; + try { + // Delay gap collection until first request + if (! m_GapsInitialized) { + x_InitGaps(); + } + + for (auto& sgx : m_GapList) { + count++; + m(*sgx); + } + } + catch (CException& e) { + LOG_POST(Error << "Error in CBioseqIndex::IterateGaps: " << e.what()); + } + return count; +} + +// Visit CDescriptorIndex objects for all descriptors +template +inline +size_t CBioseqIndex::IterateDescriptors (Fnc m) + +{ + int count = 0; + try { + // Delay descriptor collection until first request + if (! m_DescsInitialized) { + x_InitDescs(); + } + + for (auto& sdx : m_SdxList) { + count++; + m(*sdx); + } + } + catch (CException& e) { + LOG_POST(Error << "Error in CBioseqIndex::IterateDescriptors: " << e.what()); + } + return count; +} + +// Visit CFeatureIndex objects for all features +template +inline +size_t CBioseqIndex::IterateFeatures (Fnc m) + +{ + int count = 0; + try { + // Delay feature collection until first request + if (! m_FeatsInitialized) { + x_InitFeats(); + } + + for (auto& sfx : m_SfxList) { + count++; + m(*sfx); + } + } + catch (CException& e) { + LOG_POST(Error << "Error in CBioseqIndex::IterateFeatures: " << e.what()); + } + return count; +} + +template +inline +void CWordPairIndexer::IterateNorm (Fnc m) + +{ + for (auto& str : m_Norm) { + m(str); + } +} + +template +inline +void CWordPairIndexer::IteratePair (Fnc m) + +{ + for (auto& str : m_Pair) { + m(str); + } +} + + +END_SCOPE(objects) +END_NCBI_SCOPE + +#endif /* FEATURE_INDEXER__HPP */ diff --git a/c++/include/objmgr/util/obj_sniff.hpp b/c++/include/objmgr/util/obj_sniff.hpp index 6f1cbfa8..a823b867 100644 --- a/c++/include/objmgr/util/obj_sniff.hpp +++ b/c++/include/objmgr/util/obj_sniff.hpp @@ -1,7 +1,7 @@ #ifndef OBJ_SNIFF__HPP #define OBJ_SNIFF__HPP -/* $Id: obj_sniff.hpp 518485 2016-11-03 16:05:20Z ivanov $ +/* $Id: obj_sniff.hpp 518032 2016-10-31 14:47:01Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objmgr/util/objutil.hpp b/c++/include/objmgr/util/objutil.hpp index e6f901d5..a454d3a0 100644 --- a/c++/include/objmgr/util/objutil.hpp +++ b/c++/include/objmgr/util/objutil.hpp @@ -1,7 +1,7 @@ #ifndef OBJMGR_UTIL___OBJUTILS_HPP #define OBJMGR_UTIL___OBJUTILS_HPP -/* $Id: objutil.hpp 487384 2015-12-17 13:38:09Z ivanov $ +/* $Id: objutil.hpp 544493 2017-08-23 17:44:46Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -54,13 +54,19 @@ enum ETildeStyle { void ExpandTildes(string& s, ETildeStyle style); // convert " to ' +NCBI_XOBJEDIT_EXPORT void ConvertQuotes(string& str); + +NCBI_XOBJEDIT_EXPORT string ConvertQuotes(const string& str); +NCBI_XOBJEDIT_EXPORT void JoinString(string& to, const string& prefix, const string& str, bool noRedundancy=true); + +NCBI_XOBJEDIT_EXPORT string JoinString(const list& l, const string& delim, bool noRedundancy=true); @@ -68,13 +74,21 @@ string JoinString(const list& l, // Strips all spaces in string in following manner. If the function // meet several spaces (spaces and tabs) in succession it replaces them // with one space. Strips all spaces after '(' and before ')' +NCBI_XOBJEDIT_EXPORT void StripSpaces(string& str); +NCBI_XOBJEDIT_EXPORT bool TrimSpacesAndJunkFromEnds(string& str, bool allow_ellipsis = false); +NCBI_XOBJEDIT_EXPORT void TrimSpacesAndJunkFromEnds(string& result, const CTempString& str, bool allow_ellipsis = false); +NCBI_XOBJEDIT_EXPORT void TrimSpaces(string& str, size_t indent = 0); +NCBI_XOBJEDIT_EXPORT void CleanAndCompress (string& dest, const CTempString& instr); +NCBI_XOBJEDIT_EXPORT string &CompressSpaces( string& str, const bool trim_beginning = true, const bool trim_end = true ); +NCBI_XOBJEDIT_EXPORT bool RemovePeriodFromEnd(string& str, bool keep_ellipsis = true); +NCBI_XOBJEDIT_EXPORT void AddPeriod(string& str); enum EAccValFlag @@ -82,17 +96,19 @@ enum EAccValFlag eValidateAcc, eValidateAccDotVer }; - +NCBI_XOBJEDIT_EXPORT bool IsValidAccession(const string& accn, EAccValFlag flag = eValidateAcc); + // example: "10-SEP-2010" enum EDateToString { eDateToString_regular = 1, eDateToString_cit_sub, eDateToString_patent }; +NCBI_XOBJEDIT_EXPORT void DateToString(const CDate& date, string& str, EDateToString format_choice = eDateToString_regular ); -struct SDeltaSeqSummary +struct NCBI_XOBJEDIT_EXPORT SDeltaSeqSummary { string text; size_t num_segs; // total number of segments @@ -108,12 +124,14 @@ struct SDeltaSeqSummary {} }; +NCBI_XOBJEDIT_EXPORT void GetDeltaSeqSummary(const CBioseq_Handle& seq, SDeltaSeqSummary& summary); +NCBI_XOBJEDIT_EXPORT const string& GetTechString(int tech); -struct SModelEvidance +struct NCBI_XOBJEDIT_EXPORT SModelEvidance { typedef std::pair TSpanType; @@ -130,9 +148,10 @@ struct SModelEvidance {} }; +NCBI_XOBJEDIT_EXPORT bool GetModelEvidance(const CBioseq_Handle& bsh, SModelEvidance& me); - +NCBI_XOBJEDIT_EXPORT const char* GetAAName(unsigned char aa, bool is_ascii); ////////////////////////////////////////////////////////////////////////////// @@ -144,7 +163,7 @@ enum EResolveOrder eResolve_ProtFirst }; - +NCBI_XOBJEDIT_EXPORT EResolveOrder GetResolveOrder(CScope& scope, const CSeq_id_Handle& mrna, const CSeq_id_Handle& prot, @@ -158,23 +177,23 @@ EResolveOrder GetResolveOrder(CScope& scope, // ============================================================================ // Link locations: // ============================================================================ -extern const string strLinkBaseNuc; -extern const string strLinkBaseProt; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseNuc; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseProt; -extern const string strLinkBaseEntrezViewer; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseEntrezViewer; -extern const string strLinkBaseTaxonomy; -extern const string strLinkBaseTransTable; -extern const string strLinkBasePubmed; -extern const string strLinkBaseExpasy; -extern const string strLinkBaseNucSearch; -extern const string strLinkBaseGenomePrj; -extern const string strLinkBaseLatLon; -extern const string strLinkBaseGeneOntology; -extern const string strLinkBaseGeneOntologyRef; -extern const string strLinkBaseUSPTO; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseTaxonomy; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseTransTable; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBasePubmed; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseExpasy; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseNucSearch; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseGenomePrj; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseLatLon; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseGeneOntology; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseGeneOntologyRef; +extern NCBI_XOBJEDIT_EXPORT const char* strLinkBaseUSPTO; -extern const string strDocLink; +extern NCBI_XOBJEDIT_EXPORT const char* strDocLink; template void NcbiId(CNcbiOstream& os, const T& id, bool html = false) @@ -189,16 +208,22 @@ void NcbiId(CNcbiOstream& os, const T& id, bool html = false) // Like ConvertQuotes, but skips characters inside HTML tags // Returns true if it made any changes. +NCBI_XOBJEDIT_EXPORT bool ConvertQuotesNotInHTMLTags( string &str ); // We use the word "try" in the name because this is NOT airtight security, // but rather a net that catches the majority of cases. +NCBI_XOBJEDIT_EXPORT void TryToSanitizeHtml( std::string &str ); +NCBI_XOBJEDIT_EXPORT void TryToSanitizeHtml(std::string &result, const CTempString& str); +NCBI_XOBJEDIT_EXPORT void TryToSanitizeHtmlList(std::list &strs); - +NCBI_XOBJEDIT_EXPORT bool CommentHasSuspiciousHtml( const string &str ); + + END_SCOPE(objects) END_NCBI_SCOPE diff --git a/c++/include/objmgr/util/seq_align_util.hpp b/c++/include/objmgr/util/seq_align_util.hpp index 08419797..dca60895 100644 --- a/c++/include/objmgr/util/seq_align_util.hpp +++ b/c++/include/objmgr/util/seq_align_util.hpp @@ -1,7 +1,7 @@ #ifndef SEQ_ALIGN_UTIL__HPP #define SEQ_ALIGN_UTIL__HPP -/* $Id: seq_align_util.hpp 103491 2007-05-04 17:18:18Z kazimird $ +/* $Id: seq_align_util.hpp 541890 2017-07-24 13:05:52Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -77,6 +77,13 @@ CRef RemapAlignToLoc(const CSeq_align& align, CScope* scope = NULL); +/// Given a spliced-seg alignment with MismatchedBases user object, compose +/// product sequence data. Return empty string if the alignment is not a +/// spliced-seg or if it does not contain MismatchedBases. +NCBI_XOBJUTIL_EXPORT +string GetProductString(const CSeq_align& align, CScope& scope); + + /* @} */ diff --git a/c++/include/objmgr/util/sequence.hpp b/c++/include/objmgr/util/sequence.hpp index d9213f7a..19e1f2d2 100644 --- a/c++/include/objmgr/util/sequence.hpp +++ b/c++/include/objmgr/util/sequence.hpp @@ -1,7 +1,7 @@ #ifndef SEQUENCE__HPP #define SEQUENCE__HPP -/* $Id: sequence.hpp 520815 2016-12-01 18:50:10Z ivanov $ +/* $Id: sequence.hpp 540892 2017-07-12 11:35:04Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -756,6 +757,7 @@ public: fKeepUnknGapNomLen = 1 << 11, ///< Keep unknown gap's nominal length. That is, when a gap has an unknown length but nominal length, use that instead of just making it 100. fShowGapsOfSizeZero = 1 << 12, ///< Use this to show gaps of size zero as a lone hyphen at the end of a line. fEnableGI = 1 << 13, ///< Use this flag to enable GI output in the defline + fHideGenBankPrefix = 1 << 14, ///< Hide gb| prefix for genbank only seq_id's // historically misnamed as eFlagName eAssembleParts = fAssembleParts, eInstantiateGaps = fInstantiateGaps @@ -862,16 +864,16 @@ protected: virtual void x_WriteSeqIds ( const CBioseq& bioseq, const CSeq_loc* location); virtual void x_WriteAsFasta ( const CBioseq& bioseq ); - virtual void x_WriteModifiers ( const CBioseq_Handle & handle ); - virtual void x_WriteSeqTitle ( const CBioseq& bioseq, - CScope* scope, + virtual void x_GetBestId(CConstRef& gi_id, CConstRef& best_id, bool& hide_prefix, const CBioseq& bioseq); + //virtual void x_WriteModifiers ( const CBioseq_Handle & handle ); + virtual void x_WriteSeqTitle( const CBioseq_Handle & handle, const string& custom_title); + TFlags m_Flags; private: CConstRef m_SoftMask; CConstRef m_HardMask; TSeqPos m_Width; - TFlags m_Flags; EGapMode m_GapMode; TSeq_id_HandleSet m_PreviousWholeIds; // avoid recomputing for every sequence @@ -880,10 +882,10 @@ private: sequence::CDeflineGenerator::TUserFlags x_GetTitleFlags(void) const; - void x_PrintStringModIfNotDup( - bool *seen, const CTempString & key, const CTempString & value ); - void x_PrintIntModIfNotDup( - bool *seen, const CTempString & key, const int value ); + //void x_PrintStringModIfNotDup( + // bool *seen, const CTempString & key, const CTempString & value ); + //void x_PrintIntModIfNotDup( + // bool *seen, const CTempString & key, const int value ); CConstRef x_MapMask(CSeq_loc_Mapper& mapper, const CSeq_loc& mask, const CSeq_id* base_seq_id, CScope* scope); @@ -1071,6 +1073,7 @@ public: /// Find "best" frame for a coding region. "Best" frame has no /// internal stop codons. static CCdregion::EFrame FindBestFrame(const CSeq_feat& cds, CScope& scope); + static CCdregion::EFrame FindBestFrame(const CSeq_feat& cds, CScope& scope, bool& ambiguous); }; @@ -1323,10 +1326,13 @@ public: /// /// @param bioseq_handle /// The bioseq to trim. + /// @param trimmed_ranges + /// The ranges trimmed by DoTrim will be added to this. /// @return /// This returns how the trimming went. On error, an exception /// is thrown and the bioseq may be in an undefined state. - virtual EResult DoTrim( CBioseq_Handle &bioseq_handle ); + virtual EResult DoTrim( CBioseq_Handle &bioseq_handle, + CRangeCollection *trimmed_ranges = nullptr); protected: /// This holds the current interpretation for "ambiguous". For example, diff --git a/c++/include/objtools/align_format/align_format_util.hpp b/c++/include/objtools/align_format/align_format_util.hpp index 91aa89a9..38e95211 100644 --- a/c++/include/objtools/align_format/align_format_util.hpp +++ b/c++/include/objtools/align_format/align_format_util.hpp @@ -1,4 +1,4 @@ -/* $Id: align_format_util.hpp 520427 2016-11-28 18:24:56Z ivanov $ +/* $Id: align_format_util.hpp 548513 2017-10-16 11:11:13Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -69,15 +69,16 @@ static const char kDefaultProtocol[] = "https:"; static const char kEntrezUrl[] = "\" <@cssInf@>href=\"<@protocol@>//www.ncbi.nlm.nih.gov/<@db@>/<@gi@>?report=genbank&log$=<@log@>&blast_rank=<@blast_rank@>&RID=<@rid@>\" <@target@>>"; //.ncbirc alias: ENTREZ_TM -static const char kEntrezTMUrl[] = "//www.ncbi.nlm.nih.gov/<@db@>/<@gi@>?report=genbank&log$=<@log@>&blast_rank=<@blast_rank@>&RID=<@rid@>"; +static const char kEntrezTMUrl[] = "<@protocol@>//www.ncbi.nlm.nih.gov/<@db@>/<@gi@>?report=genbank&log$=<@log@>&blast_rank=<@blast_rank@>&RID=<@rid@>"; //.ncbirc alias: WGS -static const char kWGSUrl[] = "//www.ncbi.nlm.nih.gov/Traces/wgs/?val=<@wgsproj@>&page=1&display=contigs&search=<@wgsacc@>"; +static const char kWGSUrl[] = "<@protocol@>//www.ncbi.nlm.nih.gov/nuccore/<@wgsacc@>"; + ///trace db //.ncbirc alias: TRACE -static const char kTraceUrl[] = "\" <@cssInf@>href=\"//www.ncbi.nlm.nih.gov/Traces/trace.cgi?cmd=retrieve&dopt=fasta&val=<@val@>&RID=<@rid@>\">"; +static const char kTraceUrl[] = "\" <@cssInf@>href=\"<@protocol@>//www.ncbi.nlm.nih.gov/Traces/trace.cgi?cmd=retrieve&dopt=fasta&val=<@val@>&RID=<@rid@>\">"; ///genome button //.ncbirc alias: GENOME_BTN @@ -90,7 +91,7 @@ using the Entrez Genomes MapViewer

"; ///unigene // .ncbirc alias: UNIGEN -static const char kUnigeneUrl[] = "&cmd=Display&dopt=<@dopt@>_unigene&from_uid=<@gi@>&RID=<@rid@>&log$=unigene<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; +static const char kUnigeneUrl[] = "//www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=<@db@>&cmd=Display&dopt=<@dopt@>_unigene&from_uid=<@gi@>&RID=<@rid@>&log$=unigene<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; //substitues <@lnk_displ@> static const char kUnigeneImg[] = "\"UniGene\">"; @@ -99,22 +100,22 @@ static const string kUnigeneDispl = "

<@lnk@>-cluste ///structure // .ncbirc alias: STRUCTURE_URL -static const char kStructureUrl[] = "&blast_rep_gi=<@blast_rep_gi@>&hit=<@gi@>&<@cdd_params@>\ +static const char kStructureUrl[] = "//www.ncbi.nlm.nih.gov/Structure/cblast/cblast.cgi?blast_RID=<@rid@>&blast_rep_gi=<@blast_rep_gi@>&hit=<@gi@>&<@cdd_params@>\ &blast_view=<@blast_view@>&hsp=0&taxname=<@taxname@>&client=blast&log$=structure<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; //substitues <@lnk_displ@> -static const char kStructureImg[] = "\"Structure\">"; +static const char kStructureImg[] = "//www.ncbi.nlm.nih.gov/Structure/cblast/str_link.gif\" alt=\"Structure related to <@label@>\">"; //For text link <@lnk@> is substituted by formatted url static const string kStructureDispl = "
<@lnk@>-3D structure displays
"; ///structure overview -static const char kStructure_Overview[] = "//www.ncbi.nlm.nih.\ gov/Structure/cblast/cblast.cgi?blast_RID=%s&blast_rep_gi=%d&hit=%d&%s\ &blast_view=%s&hsp=0&taxname=%s&client=blast\">Related Structures"; ///Geo // .ncbirc alias: GEO -static const char kGeoUrl[] = "&RID=<@rid@>&log$=geo<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; +static const char kGeoUrl[] = "//www.ncbi.nlm.nih.gov/geoprofiles/?LinkName=nucleotide_geoprofiles&from_uid=<@gi@>&RID=<@rid@>&log$=geo<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; //substitues <@lnk_displ@> @@ -124,7 +125,7 @@ static const string kGeoDispl = "
<@lnk@>-microarray ///Gene // .ncbirc alias: GENE -static const char kGeneUrl[] = "[<@uid@>]&RID=<@rid@>&log$=gene<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; +static const char kGeneUrl[] = "//www.ncbi.nlm.nih.gov/gene?term=<@gi@>[<@uid@>]&RID=<@rid@>&log$=gene<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; //substitues <@lnk_displ@> static const char kGeneImg[] = "\"Gene\">"; @@ -133,13 +134,13 @@ static const string kGeneDispl = "
<@lnk@>-associate ///Bioassay for proteins // .ncbirc alias: BIOASSAY_PROT -static const char kBioAssayProtURL[] = "[PigGI]&RID=<@rid@>&log$=pcassay<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; +static const char kBioAssayProtURL[] = "//www.ncbi.nlm.nih.gov/entrez?db=pcassay&term=<@gi@>[PigGI]&RID=<@rid@>&log$=pcassay<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; //substitues <@lnk_displ@> static const char kBioAssayProtImg[] = "\"PubChem\">"; ///Bioassay for nucleotides // .ncbirc alias: BIOASSAY_NUC -static const char kBioAssayNucURL[] = "[RNATargetGI]&RID=<@rid@>&log$=pcassay<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; +static const char kBioAssayNucURL[] = "//www.ncbi.nlm.nih.gov/entrez?db=pcassay&term=<@gi@>[RNATargetGI]&RID=<@rid@>&log$=pcassay<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; static const char kBioAssayNucImg[] = "\"PubChem\">"; //For text link <@lnk@> is substituted by formatted url for both BioAssay Nuc and Prot @@ -147,7 +148,7 @@ static const string kBioAssayDispl = "
<@lnk@>-bioac ///mapviewer linkout // .ncbirc alias: MAPVIEWER -static const char kMapviwerUrl[] = "&THE_BLAST_RID=<@rid@>&log$=map<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; +static const char kMapviwerUrl[] = "//www.ncbi.nlm.nih.gov/mapview/map_search.cgi?direct=on&gbgi=<@gi@>&THE_BLAST_RID=<@rid@>&log$=map<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; //substitues <@lnk_displ@> static const char kMapviwerImg[] = "\"Genome\">"; //For text link <@lnk@> is substituted by formatted url @@ -155,19 +156,19 @@ static const string kMapviwerDispl = "
<@lnk@>-align ///mapviewer linkout //for used for NT/NW/NC -static const string kMapviewBlastHitUrl = "//www.ncbi.nlm.nih.gov/mapview/maps.cgi?maps=blast_set"; +static const string kMapviewBlastHitUrl = "<@protocol@>//www.ncbi.nlm.nih.gov/mapview/maps.cgi?maps=blast_set"; static const string kMapviewBlastHitParams = "&db=<@db@>&na=<@is_na@>&gnl=<@gnl@>&gi=<@gi@>&term=<@gi@>[gi]&taxid=<@taxid@>&RID=<@rid@>&QUERY_NUMBER=<@query_number@>&log$=nucl<@log@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; ///Repr microbial Genome linkout // .ncbirc alias: REPR_MICROBIAL_GENOMES -static const char kReprMicrobialGenomesUrl[] = "[gi]&RID=<@rid@>&log$=map<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; +static const char kReprMicrobialGenomesUrl[] = "//www.ncbi.nlm.nih.gov/genome?term=<@gi@>[gi]&RID=<@rid@>&log$=map<@log@>&blast_rank=<@blast_rank@>\"<@lnkTitle@><@lnkTarget@>><@lnk_displ@>"; //substitues <@lnk_displ@> static const char kReprMicrobialGenomesImg[] = "\"View\">"; //For text link <@lnk@> is substituted by formatted url static const string kReprMicrobialGenomesDispl = "
<@lnk@>-Genomic Sequence
"; -static const char kIdenticalProteinsUrl[] = "?report=ipg\" title=\"View proteins identical to <@label@>\" <@lnkTarget@>><@lnk_displ@>"; +static const char kIdenticalProteinsUrl[] = "//www.ncbi.nlm.nih.gov/protein/<@gi@>?report=ipg\" title=\"View proteins identical to <@label@>\" <@lnkTarget@>><@lnk_displ@>"; static const string kIdenticalProteinsDispl = "
<@lnk@>-Identical proteins to <@label@>
"; @@ -177,10 +178,10 @@ static const char kDownloadLink[] = "&segs=<@segs@>\"> //substitues <@lnk_displ@> static const char kDownloadImg[] = "\"Download spanning the HSP\">"; -static const char kSeqViewerUrl[] = "//www.ncbi.nlm.nih.gov/<@dbtype@>/<@gi@>?report=graph&rid=<@rid@>[<@gi@>]&<@seqViewerParams@>&v=<@from@>:<@to@>&appname=ncbiblast&link_loc=<@link_loc@>"; +static const char kSeqViewerUrl[] = "<@protocol@>//www.ncbi.nlm.nih.gov/<@dbtype@>/<@gi@>?report=graph&rid=<@rid@>[<@gi@>]&<@seqViewerParams@>&v=<@from@>:<@to@>&appname=ncbiblast&link_loc=<@link_loc@>"; static const string kSeqViewerParams = "tracks=[key:sequence_track,name:Sequence,display_name:Sequence,id:STD1,category:Sequence,annots:Sequence,ShowLabel:true][key:gene_model_track,CDSProductFeats:false][key:alignment_track,name:other alignments,annots:NG Alignments|Refseq Alignments|Gnomon Alignments|Unnamed,shown:false]"; -static const char kSeqViewerUrlNonGi[] = "//www.ncbi.nlm.nih.gov/projects/sviewer/?RID=<@rid@>&id=<@firstSeqID@>&<@seqViewerParams@>&v=<@from@>:<@to@>&appname=ncbiblast&link_loc=<@link_loc@>"; +static const char kSeqViewerUrlNonGi[] = "<@protocol@>//www.ncbi.nlm.nih.gov/projects/sviewer/?RID=<@rid@>&id=<@firstSeqID@>&<@seqViewerParams@>&v=<@from@>:<@to@>&appname=ncbiblast&link_loc=<@link_loc@>"; //to test ranges use: //static const char kSeqViewerUrl[] = "//www.ncbi.nlm.nih.gov/<@dbtype@>/<@gi@>?report=graph&rid=<@rid@>&tracks=[key:gene_model_track],[key:alignment_track]&v=<@from@>:<@to@>,<@fromTest@>:<@toTest@>&flip=<@flip@>"; @@ -195,10 +196,10 @@ static const char kGenericLinkMouseoverTmpl[] = "/<@gi@>?report=gbwithparts&from=<@from@>&to=<@to@>&RID=<@rid@>\">"; +static const char kEntrezSubseqUrl[] = "//www.ncbi.nlm.nih.gov/<@db@>/<@gi@>?report=gbwithparts&from=<@from@>&to=<@to@>&RID=<@rid@>\">"; // .ncbirc alias: ENTREZ_SUBSEQ_TM -static const char kEntrezSubseqTMUrl[] = "//www.ncbi.nlm.nih.gov/<@db@>/<@gi@>?report=gbwithparts&from=<@from@>&to=<@to@>&RID=<@rid@>"; +static const char kEntrezSubseqTMUrl[] = "<@protocol@>//www.ncbi.nlm.nih.gov/<@db@>/<@gi@>?report=gbwithparts&from=<@from@>&to=<@to@>&RID=<@rid@>"; ///Default linkout order //.ncbirc alias: LINKOUT_ORDER @@ -244,24 +245,24 @@ name=\"tree%s%d\" target=\"trv%s\"> \ // .ncbirc alias: GENE_INFO static const char kGeneInfoUrl[] = -"//www.ncbi.nlm.nih.gov/sites/entrez?db=gene&cmd=search&term=%d&RID=%s&log$=geneexplicit%s&blast_rank=%d"; +"<@protocol@>//www.ncbi.nlm.nih.gov/sites/entrez?db=gene&cmd=search&term=%d&RID=%s&log$=geneexplicit%s&blast_rank=%d"; // .ncbirc alias: TREEVIEW_CGI -static const char kGetTreeViewCgi[] = "//www.ncbi.nlm.nih.gov/blast/treeview/blast_tree_view.cgi"; +static const char kGetTreeViewCgi[] = "<@protocol@>//www.ncbi.nlm.nih.gov/blast/treeview/blast_tree_view.cgi"; // .ncbirc alias: ENTREZ_QUERY_CGI -static const char kEntrezQueryCgi[] = "//www.ncbi.nlm.nih.gov/entrez/query.fcgi"; +static const char kEntrezQueryCgi[] = "<@protocol@>//www.ncbi.nlm.nih.gov/entrez/query.fcgi"; // .ncbirc alias: TRACE_CGI -static const char kTraceCgi[] = "//www.ncbi.nlm.nih.gov/Traces/trace.cgi"; +static const char kTraceCgi[] = "<@protocol@>//www.ncbi.nlm.nih.gov/Traces/trace.cgi"; // .ncbirc alias: MAP_SEARCH_CGI -static const char kMapSearchCgi[] = "//www.ncbi.nlm.nih.gov/mapview/map_search.cgi"; +static const char kMapSearchCgi[] = "<@protocol@>//www.ncbi.nlm.nih.gov/mapview/map_search.cgi"; // .ncbirc alias: CBLAST_CGI -static const char kCBlastCgi[] = "//www.ncbi.nlm.nih.gov/Structure/cblast/cblast.cgi"; +static const char kCBlastCgi[] = "<@protocol@>//www.ncbi.nlm.nih.gov/Structure/cblast/cblast.cgi"; // .ncbirc alias: ENTREZ_VIEWER_CGI -static const char kEntrezViewerCgi[] = "//www.ncbi.nlm.nih.gov/entrez/viewer.fcgi"; +static const char kEntrezViewerCgi[] = "<@protocol@>//www.ncbi.nlm.nih.gov/entrez/viewer.fcgi"; // .ncbirc alias: BL2SEQ_WBLAST_CGI -static const char kBl2SeqWBlastCgi[] = "//www.ncbi.nlm.nih.gov/blast/bl2seq/wblast2.cgi"; +static const char kBl2SeqWBlastCgi[] = "<@protocol@>//www.ncbi.nlm.nih.gov/blast/bl2seq/wblast2.cgi"; // .ncbirc alias: ENTREZ_SITES_CGI -static const char kEntrezSitesCgi[] = "//www.ncbi.nlm.nih.gov/sites/entrez"; +static const char kEntrezSitesCgi[] = "<@protocol@>//www.ncbi.nlm.nih.gov/sites/entrez"; /// create map source of all static URL's using previously defined pairs @@ -390,10 +391,10 @@ public: /// Constructor - SSeqURLInfo(string usurl,string bt, bool isnuc,string db, string rid,int qn, - TGi gi, string acc, int lnk, int blrk,bool alnLink, bool nw, CRange range = CRange(0,0),bool flp = false, int txid = -1,bool addCssInf = false,string seqSegs = "",string resUrl = "",bool useTmpl = false, bool advView = false) - : user_url(usurl),blastType(bt), isDbNa(isnuc), database(db),rid(rid), - queryNumber(qn), gi(gi), accession(acc), linkout(lnk),blast_rank(blrk),isAlignLink(alnLink), + SSeqURLInfo(string usurl,string bt, bool isnuc,string db, string rid_in,int qn, + TGi gi_in, string acc, int lnk, int blrk,bool alnLink, bool nw, CRange range = CRange(0,0),bool flp = false, int txid = -1,bool addCssInf = false,string seqSegs = "",string resUrl = "",bool useTmpl = false, bool advView = false) + : user_url(usurl),blastType(bt), isDbNa(isnuc), database(db),rid(rid_in), + queryNumber(qn), gi(gi_in), accession(acc), linkout(lnk),blast_rank(blrk),isAlignLink(alnLink), new_win(nw),seqRange(range),flip(flp),taxid (txid),addCssInfo(addCssInf),segs(seqSegs), resourcesUrl(resUrl),useTemplates(useTmpl),advancedView(advView){} @@ -415,6 +416,7 @@ public: int raw_score; //raw score, read from the 'score' in first align in Seq Aln Set, not used list use_this_gi; //Limit formatting by these GI's, read from the first align in Seq Aln Set + list use_this_seq; //Limit formatting by these seqids, read from the first align in Seq Aln Set int sum_n; //sum_n in score block , read from the first align in Seq Aln Set int master_covered_length; //total query length covered by alignment - calculated, used calculate percent_coverage @@ -623,6 +625,23 @@ public: int& sum_n, int& num_ident, list& use_this_gi); + + ///Extract score info from blast alingment + ///@param aln: alignment to extract score info from + ///@param score: place to extract the raw score to + ///@param bits: place to extract the bit score to + ///@param evalue: place to extract the e value to + ///@param sum_n: place to extract the sum_n to + ///@param num_ident: place to extract the num_ident to + ///@param use_this_seqid: place to extract use_this_seqid to + /// + static void GetAlnScores(const objects::CSeq_align& aln, + int& score, + double& bits, + double& evalue, + int& sum_n, + int& num_ident, + list& use_this_seq); ///Extract score info from blast alingment /// Second version that fetches compositional adjustment integer @@ -644,8 +663,54 @@ public: list& use_this_gi, int& comp_adj_method); - + ///Extract score info from blast alingment + /// Second version that fetches compositional adjustment integer + ///@param aln: alignment to extract score info from + ///@param score: place to extract the raw score to + ///@param bits: place to extract the bit score to + ///@param evalue: place to extract the e value to + ///@param sum_n: place to extract the sum_n to + ///@param num_ident: place to extract the num_ident to + ///@param use_this_seq: place to extract use_this_seq to + ///@param comp_adj_method: composition based statistics method [out] + /// + static void GetAlnScores(const objects::CSeq_align& aln, + int& score, + double& bits, + double& evalue, + int& sum_n, + int& num_ident, + list& use_this_seq, + int& comp_adj_method); + + ///Extract use_this_gi info from blast alingment + ///@param aln: alignment to extract score info from + ///@param use_this_gi: place to extract use_this_gi to static void GetUseThisSequence(const objects::CSeq_align& aln,list& use_this_gi); + + ///Extract use_this_seq info from blast alingment + ///@param aln: alignment to extract score info from + ///@param use_this_seq: place to extract use_this_seq to + static void GetUseThisSequence(const objects::CSeq_align& aln,list& use_this_seq); + + ///Matches text seqID or gi with the list of seqIds or gis + ///@param cur_gi: gi to match + ///@param seqID: CSeq_id to extract label info to match + ///@param use_this_seq: list containg gi:sssssss or seqid:sssssssss + ///@param isGiList: bool= true if use_this_seq conatins gi list + ///@ret: bool=true if the match is found + static bool MatchSeqInSeqList(TGi cur_gi, CRef &seqID, list &use_this_seq,bool *isGiList = NULL); + + ///Check if use_this_seq conatins gi list + ///@param use_this_seq: list containg gi:sssssss or seqid:sssssssss + ///@ret: bool= true if use_this_seq conatins gi list + static bool IsGiList(list &use_this_seq); + + ///Convert if string gi list to TGi list + ///@param use_this_seq: list containg gi:sssssss + ///@ret: list containin sssssss + static list StringGiToNumGiList(list &use_this_seq); + ///Add the specified white space ///@param out: ostream to add white space ///@param number: the number of white spaces desired @@ -660,7 +725,8 @@ public: /// Tries to recreate behavior of GetLabel before a change that /// prepends "ti|" to trace IDs ///@param id CSeqId: to build label from - static string GetLabel(CConstRef id); + ///@param with_version bool: include version to the label + static string GetLabel(CConstRef id, bool with_version = false); ///format evalue and bit_score ///@param evalue: e value @@ -686,11 +752,18 @@ public: ///@param source_aln: the original alnset ///@param new_aln: the new alnset ///@param num: the specified number - /// + ///@return actual number of subject sequences static void PruneSeqalign(const objects::CSeq_align_set& source_aln, objects::CSeq_align_set& new_aln, unsigned int num = kDfltArgNumAlignments); + ///Calculate number of subject sequnces in alignment limitted by num + ///@param source_aln: the original alnset + ///@param num: the specified number of subj sequences to consider + ///@return actual number of subject seqs in alignment + static unsigned int GetSubjectsNumber(const objects::CSeq_align_set& source_aln, + unsigned int num); + ///Fill new alignset containing the specified number of alignments ///plus the rest of alignments for the last subget seq ///unique slave seqids. Note no new seqaligns were created. It just @@ -1030,6 +1103,16 @@ public: map > &linkout_map, ILinkoutDB* linkoutdb, const string& mv_build_name); + + ///Create map that holds all linkouts for one seqID + ///@param cur_id: CBioseq::TId + ///@param linkout_map: map that holds linkouts and corresponding CBioseq::TId for the whole list of blast deflines + /// + static void GetBdlLinkoutInfo(objects::CBioseq::TId& cur_id, + map > &linkout_map, + ILinkoutDB* linkoutdb, + const string& mv_build_name); + ///Get linkout membership for for the list of blast deflines ///@param bdl: list of CRef ///@param rid: blast rid @@ -1063,7 +1146,41 @@ public: string &preComputedResID, ILinkoutDB* linkoutdb, const string& mv_build_name); - + + ///Get linkout membership for one seqID + ///@param cur_id: CBioseq::TId seqID + ///@param rid: blast rid + ///@param cdd_rid: blast cdd_rid + ///@param entrez_term: entrez_term for building url + ///@param is_na: bool indication if query is nucleotide + ///@param first_gi: first gi in the list (used to contsruct structure url) + ///@param structure_linkout_as_group: bool used to contsruct structure url + ///@param for_alignment: bool indicating tif link is locted in alignment section + ///@param int cur_align: int current alignment/description number + ///@param linkoutOrder: string of letters separated by comma specifing linkout order like "G,U,M,E,S,B" + ///@param taxid: int taxid + ///@param database: database name + ///@param query_number: query_number + ///@param user_url: url defined as TOOL_URL for blast_type in .ncbirc + ///@return list of string containing all linkout urls for all of the seqs in the list of blast deflines + /// + static list GetFullLinkoutUrl(objects::CBioseq::TId& cur_id, + const string& rid, + const string& cdd_rid, + const string& entrez_term, + bool is_na, + bool structure_linkout_as_group, + bool for_alignment, + int cur_align, + string& linkoutOrder, + int taxid, + string &database, + int query_number, + string &user_url, + string &preComputedResID, + ILinkoutDB* linkoutdb, + const string& mv_build_name, + bool getIdentProteins); static int GetMasterCoverage(const objects::CSeq_align_set& alnset); static CRange GetSeqAlignCoverageParams(const objects::CSeq_align_set& alnset,int *masterCoverage,bool *flip); @@ -1083,10 +1200,6 @@ public: ///@return: URL format string defined in blastfmtutil.hpp static string GetURLDefault( const string url_name, int index = -1); - ///release memory allocated for the registry object by GetURLFromRegistry - /// - static void ReleaseURLRegistry(void); - ///Replace template tags by real data ///@param inpString: string containing template data ///@param tmplParamName:string with template tag name @@ -1127,6 +1240,10 @@ public: static string GetProtocol(void); + static void InitConfig(); + + static string MapProtocol(string url_link); + ///Create URL for seqid ///@param seqUrlInfo: struct SSeqURLInfo containing data for URL construction ///@param id: seqid CSeq_id @@ -1249,6 +1366,23 @@ public: static TGi GetDisplayIds(const list< CRef< objects::CBlast_def_line > > &bdl, const objects::CSeq_id& aln_id, list& use_this_gi); + + ///Scan the the list of blast deflines and find seqID to be use in display + ///@param handle: CBioseq_Handle [in] + ///@param aln_id: CSeq_id object for alignment seq [in] + ///@param use_this_seq: list list of seqids to use (gi:ssssss or seqid:sssss) [in] + ///@param gi: pointer to gi to be used for display if exists + ///@param taxid: pointer to taxid to be used for display if exists + ///@param textSeqID: pointer to textSeqID to be used for display if exists + ///@return: CSeq_id object to be used for display + static CRef GetDisplayIds(const objects::CBioseq_Handle& handle, + const objects::CSeq_id& aln_id, + list& use_this_seq, + TGi *gi = NULL, + int *taxid = NULL, + string *textSeqID = NULL); + + ///Check if accession is WGS ///@param accession: string accession [in] @@ -1257,6 +1391,8 @@ public: static bool IsWGSAccession(string &accession, string &wgsProj); ///Check if accession is WGS + + ///@param accession: string accession [in] ///@return: bool indicating if accession is WGS static bool IsWGSPattern(string &wgsAccession); @@ -1265,7 +1401,10 @@ public: ///@param giForGeneLookup: gi ///@return: string gene symbol static string GetGeneInfo(TGi giForGeneLookup); - static CNcbiRegistry *m_Reg; + + + static unique_ptr m_Reg; + static string m_Protocol; static bool m_geturl_debug_flag; static auto_ptr m_GeneInfoReader; diff --git a/c++/include/objtools/align_format/format_flags.hpp b/c++/include/objtools/align_format/format_flags.hpp index 85773fb1..cd614164 100644 --- a/c++/include/objtools/align_format/format_flags.hpp +++ b/c++/include/objtools/align_format/format_flags.hpp @@ -1,4 +1,4 @@ -/* $Id: format_flags.hpp 518046 2016-10-31 14:58:35Z ivanov $ +/* $Id: format_flags.hpp 516923 2016-10-19 14:23:23Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/align_format/showalign.hpp b/c++/include/objtools/align_format/showalign.hpp index f8ca315a..d2eaf91b 100644 --- a/c++/include/objtools/align_format/showalign.hpp +++ b/c++/include/objtools/align_format/showalign.hpp @@ -1,4 +1,4 @@ -/* $Id: showalign.hpp 513849 2016-09-15 17:36:45Z ivanov $ +/* $Id: showalign.hpp 520798 2016-12-01 17:44:42Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -561,8 +561,8 @@ protected: CRef < objects::CAlnVec > alnvec; int score; double bits; - double evalue; - list use_this_gi; + double evalue; + list use_this_seqid; int comp_adj_method; int sum_n; string id_label; @@ -949,8 +949,8 @@ protected: string x_FormatAlnHSPLinks(string &alignInfo); SAlnDispParams *x_FillAlnDispParams(const CRef< objects::CBlast_def_line > &iter, - const objects::CBioseq_Handle& bsp_handle, - list& use_this_gi, + const objects::CBioseq_Handle& bsp_handle, + list &use_this_seqid, TGi firstGi); diff --git a/c++/include/objtools/align_format/showdefline.hpp b/c++/include/objtools/align_format/showdefline.hpp index 4460efd4..2609c424 100644 --- a/c++/include/objtools/align_format/showdefline.hpp +++ b/c++/include/objtools/align_format/showdefline.hpp @@ -1,4 +1,4 @@ -/* $Id: showdefline.hpp 513849 2016-09-15 17:36:45Z ivanov $ +/* $Id: showdefline.hpp 524900 2017-01-17 16:47:33Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -94,7 +94,8 @@ public: eNewTargetWindow = (1 << 7), //open url link in a new window eShowNewSeqGif = (1 << 8), //show new sequence gif image eShowPercentIdent = (1 << 9), //show percent identity column - eLongSeqId = (1 << 10) //print long sequences id (with bars) + eLongSeqId = (1 << 10), //print long sequences id (with bars) + eRealtedInfoLinks = (1 << 11) //Related information links - Linkout links with descriptions + others }; ///Data Representing each defline @@ -111,6 +112,7 @@ public: bool was_checked; //was this sequence checked before? string fullDefline; //defline, containing all seq defines (PIG for example) int taxid; + string textSeqID; }; //Data representing templates for defline display @@ -360,8 +362,8 @@ public: protected: /// Internal data with score information for each defline. - struct SScoreInfo { - list use_this_gi; // Limit formatting by these GI's. + struct SScoreInfo { + list use_this_seqid; // Limit formatting by these seqids. string bit_string; //bit score string raw_score_string; //raw score string evalue_string; //e value @@ -499,9 +501,9 @@ protected: ///Internal function to return defline info ///@param id: seq-id we are working with [in] - ///@param use_this_gi: list of GI's to limit formatting by [in] + ///@param use_this_seqid: list of seqIds to limit formatting by [in] ///@return defline info - SDeflineInfo* x_GetDeflineInfo(CConstRef id, list& use_this_gi, int blast_rank); + SDeflineInfo* x_GetDeflineInfo(CConstRef id, list &use_this_seqid, int blast_rank); ///Internal function to return defline info ///@param aln: seqalign we are working on @@ -518,14 +520,18 @@ protected: ///Internal function to fill defline info ///@param handle: sequence handle for current seqalign ///@param aln_id: seqid from current seqalign - ///@param use_this_gi: gi from use_this_gi in seqalign + ///@param use_this_seqid: seqids from use_this_seqid in seqalign ///@param sdl: this is where is info is filled to void x_FillDeflineAndId(const objects::CBioseq_Handle& handle, - const objects::CSeq_id& aln_id, - list& use_this_gi, + const objects::CSeq_id& aln_id, + list &use_this_seqid, SDeflineInfo* sdl, int blast_rank); - + + void x_InitLinkOutInfo(SDeflineInfo* sdl, + objects::CBioseq::TId& cur_id, + int blast_rank, + bool getIdentProteins); ///Initialize defline params for regular output /// void x_InitDefline(void); diff --git a/c++/include/objtools/align_format/tabular.hpp b/c++/include/objtools/align_format/tabular.hpp index d69f1601..52ef5969 100644 --- a/c++/include/objtools/align_format/tabular.hpp +++ b/c++/include/objtools/align_format/tabular.hpp @@ -1,4 +1,4 @@ -/* $Id: tabular.hpp 503717 2016-06-07 17:51:40Z jianye $ +/* $Id: tabular.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -638,13 +638,13 @@ public: const CConstRef &ig_opts); ///Getter - const void GetIgInfo (string& v, - string& d, - string& j, - string& master_chain_to_show, - string& cdr3_nuc, - string& cdr3_aa, - string& productive) const { + void GetIgInfo (string& v, + string& d, + string& j, + string& master_chain_to_show, + string& cdr3_nuc, + string& cdr3_aa, + string& productive) const { v = m_VGene.sid; d = m_DGene.sid; j = m_JGene.sid; diff --git a/c++/include/objtools/align_format/taxFormat.hpp b/c++/include/objtools/align_format/taxFormat.hpp index ab830627..b1b21eec 100644 --- a/c++/include/objtools/align_format/taxFormat.hpp +++ b/c++/include/objtools/align_format/taxFormat.hpp @@ -1,4 +1,4 @@ -/* $Id: taxFormat.hpp 506577 2016-07-08 17:18:41Z zaretska $ +/* $Id: taxFormat.hpp 520798 2016-12-01 17:44:42Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -303,7 +303,7 @@ protected: const objects::CBioseq_Handle& bsp_handle, double bits, double evalue, - list& use_this_gi); + list& use_this_seqid); CTaxFormat::SSeqInfo *x_FillTaxDispParams(const objects::CBioseq_Handle& bsp_handle, double bits, diff --git a/c++/include/objtools/alnmgr/aln_stats.hpp b/c++/include/objtools/alnmgr/aln_stats.hpp index 058df116..c0d01fe6 100644 --- a/c++/include/objtools/alnmgr/aln_stats.hpp +++ b/c++/include/objtools/alnmgr/aln_stats.hpp @@ -1,6 +1,6 @@ #ifndef OBJTOOLS_ALNMGR___ALN_STATS__HPP #define OBJTOOLS_ALNMGR___ALN_STATS__HPP -/* $Id: aln_stats.hpp 359352 2012-04-12 15:23:21Z grichenk $ +/* $Id: aln_stats.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -177,10 +177,10 @@ public: /// Get a set of ids that are aligned to a particular id const TIdVec& GetAlignedIds(const TAlnSeqIdIRef& id) const { - typename TAlignedIdsMap::const_iterator it = m_AlignedIdsMap.find(id); - if (it != m_AlignedIdsMap.end()) { + typename TAlignedIdsMap::const_iterator aln_it = m_AlignedIdsMap.find(id); + if (aln_it != m_AlignedIdsMap.end()) { // get from cache - return it->second; + return aln_it->second; } else { TIdMap::const_iterator it = m_IdMap.find(id); diff --git a/c++/include/objtools/alnmgr/alnmatch.hpp b/c++/include/objtools/alnmgr/alnmatch.hpp index 26d3e9ba..c4f366bb 100644 --- a/c++/include/objtools/alnmgr/alnmatch.hpp +++ b/c++/include/objtools/alnmgr/alnmatch.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_ALNMGR___ALNMATCH__HPP #define OBJECTS_ALNMGR___ALNMATCH__HPP -/* $Id: alnmatch.hpp 355293 2012-03-05 15:17:16Z vasilche $ +/* $Id: alnmatch.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -129,7 +129,7 @@ public: m_Len(0), m_StrandsDiffer(false), m_DsIdx(0) {} CAlnMixMatch(const CAlnMixMatch& match) - : m_Score(0), m_ChainScore(0), + : CObject(), m_Score(0), m_ChainScore(0), m_AlnSeq1(0), m_AlnSeq2(0), m_Start1(0), m_Start2(0), m_Len(0), m_StrandsDiffer(false), m_DsIdx(0) diff --git a/c++/include/objtools/alnmgr/pairwise_aln.hpp b/c++/include/objtools/alnmgr/pairwise_aln.hpp index 874ca61b..e3a84dd9 100644 --- a/c++/include/objtools/alnmgr/pairwise_aln.hpp +++ b/c++/include/objtools/alnmgr/pairwise_aln.hpp @@ -1,6 +1,6 @@ #ifndef OBJTOOLS_ALNMGR___PAIRWISE_ALN__HPP #define OBJTOOLS_ALNMGR___PAIRWISE_ALN__HPP -/* $Id: pairwise_aln.hpp 489532 2016-01-13 16:57:35Z grichenk $ +/* $Id: pairwise_aln.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -273,7 +273,8 @@ public: /// NB: Copy constructor is deep on pairwise_alns so that /// pairwise_alns can be modified CAnchoredAln(const CAnchoredAln& c) - : m_AnchorRow(c.m_AnchorRow), + : CObject(), + m_AnchorRow(c.m_AnchorRow), m_Score(c.m_Score) { *this = c; diff --git a/c++/include/objtools/alnmgr/seqids_extractor.hpp b/c++/include/objtools/alnmgr/seqids_extractor.hpp index 43a01280..2c0603cd 100644 --- a/c++/include/objtools/alnmgr/seqids_extractor.hpp +++ b/c++/include/objtools/alnmgr/seqids_extractor.hpp @@ -1,6 +1,6 @@ #ifndef OBJTOOLS_ALNMGR___SEQIDS_EXTRACTOR__HPP #define OBJTOOLS_ALNMGR___SEQIDS_EXTRACTOR__HPP -/* $Id: seqids_extractor.hpp 445727 2014-09-08 13:02:39Z grichenk $ +/* $Id: seqids_extractor.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -256,10 +256,10 @@ public: bool nuc_prot_diag = (min_len == max_len / 3 || min_len - 1 == max_len / 3 ? true : false); - for (size_t i=0; i< seg_lens.size(); ++i) { + for (size_t i_lcl=0; i_lcl< seg_lens.size(); ++i_lcl) { if ( nuc_prot_diag ) { - id_vec[i]->SetBaseWidth( - seg_lens[i] == min_len ? 3 : 1); + id_vec[i_lcl]->SetBaseWidth( + seg_lens[i_lcl] == min_len ? 3 : 1); } } } diff --git a/c++/include/objtools/alnmgr/sparse_aln.hpp b/c++/include/objtools/alnmgr/sparse_aln.hpp index 0f57ed21..c4689d89 100644 --- a/c++/include/objtools/alnmgr/sparse_aln.hpp +++ b/c++/include/objtools/alnmgr/sparse_aln.hpp @@ -1,6 +1,6 @@ #ifndef OBJTOOLS_ALNMGR___SPARSE_ALN__HPP #define OBJTOOLS_ALNMGR___SPARSE_ALN__HPP -/* $Id: sparse_aln.hpp 519681 2016-11-17 15:42:28Z ivanov $ +/* $Id: sparse_aln.hpp 519526 2016-11-16 14:17:08Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/blast/blastdb_format/blastdb_dataextract.hpp b/c++/include/objtools/blast/blastdb_format/blastdb_dataextract.hpp index 52bc1d2e..b5e58495 100644 --- a/c++/include/objtools/blast/blastdb_format/blastdb_dataextract.hpp +++ b/c++/include/objtools/blast/blastdb_format/blastdb_dataextract.hpp @@ -1,4 +1,4 @@ -/* $Id: blastdb_dataextract.hpp 516398 2016-10-13 12:26:59Z ivanov $ +/* $Id: blastdb_dataextract.hpp 515237 2016-09-29 12:32:30Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/blast/blastdb_format/seq_writer.hpp b/c++/include/objtools/blast/blastdb_format/seq_writer.hpp index 4c70855a..b370487c 100644 --- a/c++/include/objtools/blast/blastdb_format/seq_writer.hpp +++ b/c++/include/objtools/blast/blastdb_format/seq_writer.hpp @@ -1,4 +1,4 @@ -/* $Id: seq_writer.hpp 516393 2016-10-13 12:26:14Z ivanov $ +/* $Id: seq_writer.hpp 514956 2016-09-27 15:27:02Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/blast/seqdb_reader/impl/seqdbatlas.hpp b/c++/include/objtools/blast/seqdb_reader/impl/seqdbatlas.hpp index 8d960e1e..4420cae6 100644 --- a/c++/include/objtools/blast/seqdb_reader/impl/seqdbatlas.hpp +++ b/c++/include/objtools/blast/seqdb_reader/impl/seqdbatlas.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBATLAS_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBATLAS_HPP -/* $Id: seqdbatlas.hpp 516398 2016-10-13 12:26:59Z ivanov $ +/* $Id: seqdbatlas.hpp 538604 2017-06-12 18:14:42Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,13 +34,8 @@ /// The SeqDB memory management layer. /// /// Defines classes: -/// CSeqDBFlushCB /// CSeqDBLockHold /// CSeqDBMemReg -/// CRegionMap -/// CSeqDBMemLease -/// CSeqDBMovingAverage -/// CSeqDBMapStrategy /// CSeqDB_AtlasRegionHolder /// CSeqDBAtlas /// CSeqDBAtlasHolder @@ -142,7 +137,7 @@ void seqdb_log(int cl, const char * s1, int s2); /// CSeqDBAtlas class - a collection of memory maps. class CSeqDBAtlas; // WorkShop needs this forward declaration. - +class CSeqDBFileMemMap; /// Return path with delimiters changed to platform preferred kind. /// @@ -157,44 +152,6 @@ class CSeqDBAtlas; // WorkShop needs this forward declaration. string SeqDB_MakeOSPath(const string & dbs); -/// CSeqDBFlushCB -/// -/// This abstract class defines an interface which can be called to -/// free unused regions of Atlas managed memory. If a class derived -/// from this interface is provide to the atlas constructor, it will -/// be called at the beginning of garbage collection. It is expected -/// to release reference counts on any sections of memory that should -/// be considered for garbage collection. - -class CSeqDBFlushCB { -public: - /// Flush held memory references. - /// - /// This class should be subclassed, and this method overloaded to - /// flush held memory that is not in use. Normally, this amounts - /// to calling the Clear() method on any CSeqDBMemLease objects - /// which hold references to regions of memory. Each open file - /// can have a memory lease which holds onto a slice of memory, if - /// that file has been accessed. Without this callback, these - /// slices can combine to exhaust the address space. This action - /// carries a performance penalty, because subsequent access to - /// the released slices will require searching for the correct - /// memory block. If that block was deleted, it will be remapped, - /// which may trigger another garbage collection. - - virtual void operator()() = 0; - - /// Destructor to avoid warnings. - virtual ~CSeqDBFlushCB() {} -}; - -/// Forward declaration for CRegionMap. -class CRegionMap; - -/// Forward declaration for CRegionMap. -class CSeqDBMemLease; - - /// CSeqDBLockHold /// /// This class is used to keep track of whether this thread holds the @@ -223,9 +180,7 @@ public: INIT_CLASS_MARK(); } - /// Get a hold a region of memory. - void HoldRegion(CSeqDBMemLease & lease); - + /// Destructor /// /// The class will unlock the atlas's lock on destruction (if it @@ -246,9 +201,6 @@ private: /// This reference allows unlock on exit. class CSeqDBAtlas & m_Atlas; - /// These are memory leases that should not flush during GC. - vector m_Holds; - /// If this is true, this thread owns the atlas lock. bool m_Locked; }; @@ -296,858 +248,6 @@ private: }; -/// CRegionMap -/// -/// This object stores data relevant to a mapped portion of a file. -/// The mapped area may be a memory map or an allocated buffer filled -/// with data read from a file. It also remembers some garbage -/// collection statistics, used to determine if and when to reclaim -/// this region. The atlas code manages a collection of these -/// objects. - -class CRegionMap { -public: - /// The type used for file offsets. - typedef CNcbiStreamoff TIndx; - - /// Constructor - /// - /// Initializes the object, storing the provided filename, file - /// id, and byte range. This object does not own the string - /// containing the filename, and does not map any memory or - /// do any filesystem operations during construction. - /// @param fname - /// Pointer to a string containing the name of the file. - /// @param fid - /// An integer uniquely identifying the file to the atlas. - /// @param begin - /// The offset of the beginning of the byte range. - /// @param end - /// The offset of the end of the byte range. - CRegionMap(const string * fname, - int fid, - TIndx begin, - TIndx end); - - /// Set the mmap strategy for index files - static void SetMmapStrategy_Index( - EMemoryAdvise strategy - ) - { - sm_MmapStrategy_Index = strategy; - } - - /// Set the mmap strategy for sequence files - static void SetMmapStrategy_Sequence( - EMemoryAdvise strategy - ) - { - sm_MmapStrategy_Sequence = strategy; - } - - /// Destructor - /// - /// Frees or unmaps any memory associated with this region. - ~CRegionMap(); - - /// Memory map a region of a file - /// - /// This uses CMemoryFile to map the file region associated with - /// this object. The range of memory may be rounded up to the - /// nearest slice boundary, and may trigger (atlas's) garbage - /// collection routine if the new memory area won't fit into the - /// memory bound provided. The mapping will be attempted even if - /// the memory bound requirements are not acheivable, but this - /// will probably result in performance degradation due to - /// thrashing atlas's garbage collector. - /// - /// @param atlas - /// Pointer to the atlas. - /// @return - /// Returns true if the mapping succeeded. - bool MapMmap(CSeqDBAtlas * atlas); - - /// Read a region of a file into memory - /// - /// This uses CNcbiIfstream to read the file region associated - /// with this object into an allocated memory block. The range of - /// memory may be rounded up (but only to the nearest block - /// boundary), and may trigger (atlas's) garbage collection - /// routine if the new memory area won't fit into the memory bound - /// provided. The read will be attempted even if the memory bound - /// requirements are not acheivable, but this will probably result - /// in performance degradation due to thrashing atlas's garbage - /// collector. - /// - /// @param atlas - /// Pointer to the atlas. - /// @return - /// Returns true if the read succeeded. - bool MapFile(CSeqDBAtlas * atlas); - - /// Increment this region's reference count. - /// - /// This increments the count of "users" associated with this - /// region. When too much memory is used, memory regions may be - /// freed. This process (garbage collection) will skip over any - /// regions in use at the time. This method is the way to - /// indicates that an operation is done using this memory region - /// and expects it to remain intact for the duration. - void AddRef() - { - CHECK_MARKER(); - _ASSERT(m_Ref >= 0); - m_Ref ++; - m_Clock = 0; - } - - /// Decrement this region's reference count. - /// - /// This decrements the count of "users" associated with this - /// region. If the count becomes zero, the region becomes - /// available for the next run of garbage collection. This method - /// indicates that an operation is done using this memory region. - void RetRef() - { - CHECK_MARKER(); -#ifdef _DEBUG - if (! (m_Ref > 0)) { - cout << "refcount non-positive = " << m_Ref << endl; - } -#endif - - _ASSERT(m_Ref > 0); - m_Ref --; - } - - /// Return true if memory region is in use. - /// - /// This returns true if any users (normally, CSeqMemLease - /// objects) are holding a reference on this memory region. - /// - /// @return - /// true if memory region has current users. - bool InUse() - { - CHECK_MARKER(); - return m_Ref != 0; - } - - /// Return true if memory region contains the pointer. - /// - /// This method returns true if the specified pointer points to a - /// character in the memory area managed by this object. It is - /// used to find the region to decrement when a user provides a - /// region to "give back". - /// - /// @return - /// true if this memory region contains the pointer - bool InRange(const char * p) const - { - CHECK_MARKER(); - _ASSERT(m_Data); - return ((p >= m_Data) && (p < (m_Data + (m_End - m_Begin)))); - } - - /// Return the name of the file. - /// - /// Provides the name of the file from which this data was - /// obtained. - /// - /// @return - /// A const reference to the file name string. - const string & Name() - { - CHECK_MARKER(); - return *m_Fname; - } - - /// Return the beginning offset of this region. - /// - /// Provides the file offset corresponding to the beginning of - /// this mapping. - /// - /// @return - /// The index of the beginning of this mapping. - TIndx Begin() - { - CHECK_MARKER(); - return m_Begin; - } - - /// Return the end offset of this region. - /// - /// Provides the file offset corresponding to the end of this - /// mapping. - /// - /// @return - /// The index of the end of this mapping. - TIndx End() - { - CHECK_MARKER(); - return m_End; - } - - /// Return the length of this mapping in bytes. - TIndx Length() - { - CHECK_MARKER(); - return m_End - m_Begin; - } - - /// Get a pointer to a section of this data. - /// - /// This method takes an offset range (start and end), and returns - /// a pointer to the data at the start offset. The offsets are - /// relative to the file, not the region. The end offset is only - /// used to check that the region contains the entire range. - /// - /// @param begin - /// The offset of the first required byte. - /// @param end - /// The offset of the last required byte, plus one. - /// @return - /// A pointer to the beginning of the requested data. - const char * Data(TIndx begin, TIndx end); - - /// Get a pointer to all data in this region. - /// - /// This method returns a pointer to the data at the start offset - /// of this region. - /// - /// @return - /// A pointer to the beginning of the region's data. - const char * Data() - { - CHECK_MARKER(); - return m_Data; - } - - /// Return the file id associated with this region. - /// - /// This method returns an integer used to identify this file - /// within the atlas code. The integer used here is uniquely - /// associated with the filename (but costs slightly fewer CPU - /// cycles during certain common operations). - /// - /// @return - /// An integer identifying the file this mapping is of. - int Fid() - { - CHECK_MARKER(); - return m_Fid; - } - - /// Get the garbage collection clock value. - /// - /// This method is used by the atlas code's garbage collection - /// routine. The clock concept is borrowed from certain operating - /// system paging techniques, and is described further in the - /// garbage collection. This function returns that clock value - /// plus a penalty, which is used to preferentially page out - /// regions with undesireable "shapes", e.g. that don't have a - /// size of exactly one (large) slice. - /// - /// @return - /// The clock value plus the penalty for this region. - int GetClock() - { - CHECK_MARKER(); - return m_Clock + m_Penalty; - } - - /// Increase the garbage collection clock count. - /// - /// This method increments the clock value, used by the atlas - /// code's garbage collection routine. This method should never - /// be called on an in-use region. The higher the clock value - /// gets, the closer this region is to being freed by the garbage - /// collection code. - void BumpClock() - { - CHECK_MARKER(); - _ASSERT(! m_Ref); - m_Clock++; - } - - /// Test and select this region if the arguments match. - /// - /// This method takes arguments describing a section of a file. - /// If this region has the same fid, and the byte range of this - /// region encompasses the specified range, then the reference - /// count is incremented, the input parameters are expanded to - /// reflect the entire region, and start is set to point to the - /// beginning of the requested portion of the region. This method - /// also returns a pointer to the beginning of the input range - /// (before adjusting begin and end). - /// - /// @param fid - /// The number identifying this file to the atlas code. - /// @param begin - /// The beginning offset of the selected area. - /// @param end - /// The ending offset of the selected area. - /// @param start - /// Returned pointer to the beginning of the mapped region. - /// @return - /// Pointer to the requested portion of the region. - inline const char * - MatchAndUse(int fid, - TIndx & begin, - TIndx & end, - const char ** start); - - /// In debugging / verbose code, dump information about this - /// memory region object. - void Show(); - - /// Get the data pointer and offset range of this region. - /// - /// This method returns a pointer to this region's data, and the - /// beginning and ending offsets of the region. - /// - /// @param region_start - /// Returns the address of the region data. - /// @param begin_offset - /// The beginning offset of the region data. - /// @param end_offset - /// The end offset of the region data. - void GetBoundaries(const char ** region_start, - TIndx & begin_offset, - TIndx & end_offset) - { - CHECK_MARKER(); - *region_start = m_Data; - begin_offset = m_Begin; - end_offset = m_End; - } - - /// Less-than operator. - /// - /// This method defines an partial ordering over CRegionMap - /// objects. The order defined here places the objects in - /// ascending order by fid, then start offset, then region size - /// (equivalently, end offset). The ordering is partial because - /// two region maps could have identical parameters. However, - /// this should never happen for the atlas code as defined. - /// - /// @param other - /// The other region map to compare with. - /// @return - /// True if this object is before "other" in the ordering. - inline bool operator < (const CRegionMap & other) const; - - /// Verify the marker values (only in debug mode). - void Verify() - { -#ifdef _DEBUG - // Cannot do too much, as the client code creates a CRegionMap - // to use as a key, and it will not be completely specified. - - CHECK_MARKER(); - _ASSERT(m_Begin < m_End); -#endif - } - -private: - CLASS_MARKER_FIELD("REGM") - - /// Compute the penalty and the expanded offset range. - /// - /// The files are normally divided into "slices". When a mapping - /// request asks for a specific range of offsets, we attempt to - /// expand the offset range to the entire slice that contains the - /// requested area. When memory mapping is selected, a large - /// slice size is used. For files, a smaller area is used. The - /// penalty value returned indicates how desireable the selected - /// mapping is thought to be. Mapping one whole slice gets a - /// value of zero. Partial slices, areas overlapping the ends of - /// two slices, and other anomalies get higher penalties. - /// - /// @param begin - /// The starting offset (this method may adjust it). - /// @param end - /// The ending offset (this method may adjust it). - /// @param penalty - /// The penalty for this mapping is returned. - /// @param file_size - /// The total size of the file. - /// @param use_mmap - /// Whether memory mapping will be used. - /// @param atlas - /// A pointer to the atlas object. - static void x_Roundup(TIndx & begin, - TIndx & end, - int & penalty, - TIndx file_size, - bool use_mmap, - CSeqDBAtlas * atlas); - - /// Pointer to allocated or mapped memory area. - const char * m_Data; - - /// The memory mapped file object. - CMemoryFileMap * m_MemFile; - - /// Pointer to the filename (this object does not own it). - const string * m_Fname; - - /// The file offset of the start of the region. - TIndx m_Begin; - - /// The file offset of the end of the region. - TIndx m_End; - - /// An integer identifying this object to the atlas code. - int m_Fid; - - /// Number of current users of this object. - int m_Ref; - - /// GC uses this to rank how recently this range was used. - int m_Clock; - - /// Adjustment to m_Clock to bias region collection. - int m_Penalty; - - /// Index file mmap strategy. - static EMemoryAdvise sm_MmapStrategy_Index; - - /// Sequence file mmap strategy. - static EMemoryAdvise sm_MmapStrategy_Sequence; -}; - - -/// CSeqDBMemLease -/// -/// This object holds a reference on a region of memory managed by the -/// atlas code, and prevent the region from being unmapped. This -/// allows for rapid access to that memory for the duration of the -/// transaction, and for subsequent transactions, without needing to -/// call GetRegion() until memory outside the region is needed. -/// Since these objects can prevent large slices of memory from being -/// unmapped, the SeqDB code uses a callback functor (CSeqDBFlushCB) -/// to allow the garbage collection code to break these holds, and -/// return the associated regions, if the memory bound is exceeded. - -class CSeqDBMemLease { -public: - /// The type used for file offsets. - typedef CRegionMap::TIndx TIndx; - - /// Constructor - /// - /// Initializes a memory lease object. - /// - /// @param atlas - /// The main atlas pointer. - CSeqDBMemLease(CSeqDBAtlas & atlas) - : m_Atlas(atlas), - m_Data (0), - m_Begin(0), - m_End (0), - m_RMap (0) - { - INIT_CLASS_MARK(); - } - - /// Destructor - /// - /// Verifies this object is not active at time of destruction. - ~CSeqDBMemLease() - { - CHECK_MARKER(); - _ASSERT(m_Data == 0); - BREAK_MARKER(); - } - - /// Clears the lease object. - /// - /// This method releases the reference count on the held region . - /// It assumes the lock is held. - inline void Clear(); - - /// Check whether the held area includes an offset range. - /// - /// This checks whether the region associated with this object - /// already encompasses the desired offset range. If so, there is - /// no need to call GetRegion, because you can already access it - /// from this object. It assumes the atlas lock is held. - /// - /// @param begin - /// Start of the offset range. - /// @param end - /// End of the offset range. - /// @return - /// Returns true if the held region includes the offset range. - inline bool Contains(TIndx begin, TIndx end) const; - - /// Get a pointer to the internal region map. - /// - /// @return - /// A pointer to the region map held here. - CRegionMap * GetRegionMap() const - { - return m_RMap; - } - - /// Get a pointer to the specified offset. - /// - /// Given an offset (which is assumed to be available here), this - /// method returns a pointer to the data at that offset. - /// - /// @param offset - /// The required offset relative to the start of the file. - /// @return - /// A pointer to the data at the requested location. - const char * GetPtr(TIndx offset) const - { - CHECK_MARKER(); - return (m_Data + (offset - m_Begin)); - } - - /// Return true if this object is inactive. - /// - /// An active object holds a reference to a region of a file. - /// This method returns true if this object is not active. - /// - /// @return - /// true, if this object does not hold a reference. - bool Empty() const - { - CHECK_MARKER(); - return m_Data == 0; - } - - /// Verify the integrity of this object. - void Verify() const - { - CHECK_MARKER(); - } - - /// Get another reference to the held CRegionMap object. - /// - /// To call this method, this object must be active (already hold - /// a reference to a CRegionMap object). This method gets an - /// additional hold on that object by incrementing the reference - /// count again. This is the mechanism that prevents the region - /// from being collected while the user works with it, even if - /// this lease object (which is probably stored somewhere under a - /// CSeqDBVolume) is released and garbage collection occurs. If - /// and when the user returns the pointer to the region to CSeqDB, - /// the atlas code will find the region and decrement the count. - inline void IncrementRefCnt(); - -private: - CLASS_MARKER_FIELD("LEAS") - - /// This method is declared private to prevent copy construction. - CSeqDBMemLease(const CSeqDBMemLease & ml); - - /// This method is declared private to prevent assignment. - CSeqDBMemLease & operator =(const CSeqDBMemLease & ml); - - /// Active the region, setting its data members. - /// - /// When the GetRegion call returns a region in a MemLease object, - /// it increments the reference count, and calls this method to - /// populate this object with the summary data it needs. This - /// method is private so that only the atlas object can call it. - /// - /// @param begin - /// The starting offset of the area this lease can access. - /// @param end - /// The ending offset of the area this lease can access. - /// @param data - /// The pointer to the data area this lease can access. - /// @param rmap - /// A pointer to the object that manages the file region. - void x_SetRegion(TIndx begin, - TIndx end, - const char * data, - CRegionMap * rmap) - { - CHECK_MARKER(); - Clear(); - - m_Data = data; - m_Begin = begin; - m_End = end; - m_RMap = rmap; - } - - /// Access to the private data is restricted to the atlas code. - friend class CSeqDBAtlas; - - /// The atlas associated with this object. - CSeqDBAtlas & m_Atlas; - - /// Points to the beginning of the data area. - const char * m_Data; - - /// Start offset of the data relative to the start of the file. - TIndx m_Begin; - - /// End offset of the data relative to the start of the file. - TIndx m_End; - - /// Points to the object that manages the file region. - class CRegionMap * m_RMap; -}; - - -/// CSeqDBMovingAverage -/// -/// This implements an exponentially smoothed moving average, which is -/// a technique for smoothing a noisy scalar measurement. - -class CSeqDBMovingAverage { -public: - /// Constructor. - /// - /// Specify a degree of smoothing between 0 and 1, along with a - /// starting value. Zero would mean that no smoothing is done, - /// the result is always the last measurement. Using 1.0 would - /// cause the average to never change. Note that the moving - /// average inevitably lags behind input value changes. - /// - /// @param ratio Amount of smoothing to do. - /// @param start Starting value to use for average. - CSeqDBMovingAverage(double ratio, double start) - : m_Ratio(ratio), - m_Average(start) - { - } - - /// Add a new measurement. - /// @param value The new measurement. - void AddData(double value) - { - // Each esma is a weighted average of the last esma and the - // new measurement. - - m_Average *= m_Ratio; - m_Average += (value * (1.0 - m_Ratio)); - } - - /// Get the current moving average. - double GetAverage() const - { - return m_Average; - } - -private: - /// Ratio of smoothness. - double m_Ratio; - - /// Current value. - double m_Average; -}; - - -/// CSeqDBMapStrategy -/// -/// Some SeqDB clients access OIDs in sequential order; others tend to -/// follow a random access pattern. This class attempts to implement -/// a kind of self-tuning for SeqDB based on client access patterns. -/// It also tries to detect and deal with memory shortage issues by -/// reducing the overall SeqDB footprint. - -class CSeqDBMapStrategy { -public: - /// The type used for file offsets. - typedef Int8 TIndx; - - /// Maximum memory: 256 GB for 64 bits. - static const Int8 e_MaxMemory64; - - enum { - // On Linux, malloc() uses mmap() for large requests, which - // means that the heap can shrink when free() is called. In - // this environment, SeqDB tries to probe the address space by - // using a large memory bound and handling map failures in - // certain routines. This can cause stack exhaustion on other - // platforms, so it is only currently enabled for Linux. - -#if defined(NCBI_OS_LINUX) - /// Probe address space with special allocations. - e_ProbeMemory = true, - - /// Maximum memory: 2 GB for non-WinOS, 32 bit systems. - e_MaxMemory32 = 768 << 20, -#else - /// Probe address space with special allocations. - e_ProbeMemory = false, - - /// Maximum memory: 1 GB for WinOS, 2 GB for other 32 bit. - e_MaxMemory32 = 768 << 20, -#endif - - // Up to the AppSpace setting, SeqDB will try to consume at - // most half of the available memory. Beyond this point, - // SeqDB will only leave the AppSpace amount for the - // application. - - /// Application space - maximum memory set aside for the app. - e_AppSpace = 256 << 20, - - /// Minimum memory bound. - e_MinMemory = 64 << 20, - - /// Maximum slice to map on a 32 bit system. - e_MaxSlice32 = 128 << 20, - - /// Maximum slice to map on a 64 bit system. - e_MaxSlice64 = 1 << 30, - - /// Minimum slice size to use. - e_MinSlice = 4 << 20, - - /// Maximum overhang. - e_MaxOverhang = 8 << 20, - - /// Minimum overhang. - e_MinOverhang = 256 << 10, - - /// Maximum open (mapped) regions at once. - eMaxOpenRegions = 500, - - /// Maximum new open regions between collections. - eOpenRegionsWindow = 100 - }; - - /// Constructor - CSeqDBMapStrategy(CSeqDBAtlas & atlas); - - /// Get current overhang amount. - /// - /// This returns the amount of memory to map past the end of the - /// (end-of-map) slice boundary. This should prevent most cases - /// where a memory map 'straddles' the boundary between slices. - /// - /// @return - /// Atlas will map this much data past the slice-end boundary. - TIndx GetOverhang() - { - return m_Overhang; - } - - /// Return the slice size for mmap requests. - TIndx GetSliceSize() - { - return m_SliceSize; - } - - /// Set the slice size for mmap requests. - void SetSliceSize(TIndx size) - { - m_SliceSize = min(m_SliceSize, size); - } - - /// Return the total memory bound. - /// - /// This returns the active memory bound. If SeqDB is done - /// mapping regions and is ready to return to the user, the value - /// used is smaller. The design goal here is to cause memory - /// allocation failures to happen in CSeqDBAtlas rather than in - /// user code, so that SeqDB can detect these failures and reduce - /// its memory bound to fix the problem. If user code allocates - /// very large arrays on a 32 bit system, they might still be the - /// one to get the allocation failures, in which case they might - /// consider reducing the bound via SetMemoryBound(). - /// - /// @param returning Specify true if returning from SeqDB. - TIndx GetMemoryBound(bool returning) - { - x_CheckAdjusted(); - return returning ? m_RetBound : m_MaxBound; - } - - /// An allocation this large will trigger a memory purge. - TIndx GetGCTriggerSize() - { - return m_SliceSize*3; - } - - /// Give this object an OID specified by the user. - /// @param oid The user tried to fetch data via this oid. - /// @param num_oids The total number of OIDs. - void MentionOid(int oid, int num_oids); - - /// Tell SeqDB that a memory mapping failed. - void MentionMapFailure(Uint8 current); - - /// Set the memory bound using a user specified value. - void SetMemoryBound(Uint8 max) - { - x_SetBounds(max); - } - - /// Set global default memory bound. - /// - /// This sets the default, global memory bound used for all SeqDB - /// objects. If zero is specified, an appropriate default will be - /// selected based on system information. - static void SetDefaultMemoryBound(Uint8 bytes); - -private: - /// Check if the global bound has been adjusted and use that value. - void x_CheckAdjusted(); - - /// Mention an ordered or out-of-order access. - void x_OidOrder(bool in_order); - - /// Restrict a number to a range. - /// - /// This method returns a number as close as possible to 'guess', - /// but restricted to the range [low,high]. The number that is - /// returned is always at least low and no higher than high, and - /// is always a multiple of the system virtual memory blocksize. - /// - /// @param low Lowest value to return. - /// @param high Highest value to return. - /// @param guess The preferred value. - Uint8 x_Pick(Uint8 low, Uint8 high, Uint8 guess); - - /// Set all parameters. - void x_SetBounds(Uint8 bound); - - /// The atlas object. - CSeqDBAtlas & m_Atlas; - - /// Maximum memory bound SeqDB may map. - Int8 m_MaxBound; - - /// Maximum memory bound when returning from Atlas code. - Int8 m_RetBound; - - /// Atlas will try to map files in blocks this size. - Int8 m_SliceSize; - - /// Mapped areas of files should overlap this much. - Int8 m_Overhang; - - /// Track sequentiality of OID accesses. - CSeqDBMovingAverage m_Order; - - /// True if SeqDB thinks user is accessing OIDs sequentially. - bool m_InOrder; - - /// True if mmap has failed at least once. - bool m_MapFailed; - - /// Last OID seen. - int m_LastOID; - - /// Block size for mapping. - long m_BlockSize; - - /// Global maximum memory bound. - static Int8 m_GlobalMaxBound; - - /// Has global memory bound been changed? - static bool m_AdjustedBound; -}; /// Hold a memory region refcount, return to atlas when destroyed. @@ -1196,7 +296,8 @@ private: class NCBI_XOBJREAD_EXPORT CSeqDBAtlas { public: /// The type used for file offsets. - typedef CRegionMap::TIndx TIndx; + //typedef CRegionMap::TIndx TIndx; + typedef CNcbiStreamoff TIndx; /// Constructor /// @@ -1209,6 +310,9 @@ public: /// The destructor unmaps and frees all associated memory. ~CSeqDBAtlas(); + + enum {e_MaxFileDescritors = 1000}; + /// Check if file exists. /// /// If the file exists, this method will return true, otherwise @@ -1244,63 +348,18 @@ public: return DoesFileExist(fname.GetPathS(), locked); } - /// Get mapping of an entire file. - /// - /// A file is mapped or read, in its entirety. The region is held - /// in memory until the pointer is returned with RetRegion(). The - /// atlas will be locked if necessary. - /// - /// @param fname - /// The filename of the file to get. - /// @param length - /// The length of the file is returned here. - /// @param locked - /// The lock hold object for this thread. - /// @return - /// A pointer to the beginning of the file's data. - const char * GetFile(const string & fname, - TIndx & length, - CSeqDBLockHold & locked); - - /// Get mapping of an entire file. - /// - /// A file is mapped or read, in its entirety. The region is held - /// in memory until the lease object is cleared. The atlas will - /// be locked if necessary. - /// - /// @param lease - /// The lease which owns the hold on the region. - /// @param fname - /// The filename of the file to get. - /// @param length - /// The length of the file is returned here. - /// @param locked - /// The lock hold object for this thread. - void GetFile(CSeqDBMemLease & lease, - const string & fname, - TIndx & length, - CSeqDBLockHold & locked); - - /// Get mapping of an entire file. - /// - /// This version is like the previous but takes CSeqDB_Path. - /// - /// @param lease - /// The lease which owns the hold on the region. - /// @param fname - /// The filename of the file to get. - /// @param length - /// The length of the file is returned here. - /// @param locked - /// The lock hold object for this thread. - void GetFile(CSeqDBMemLease & lease, - const CSeqDB_Path & fname, - TIndx & length, - CSeqDBLockHold & locked) + bool DoesFileExist(const string & fname) { - GetFile(lease, fname.GetPathS(), length, locked); + TIndx length(0); + return GetFileSizeL(fname, length); } + bool DoesFileExist(const CSeqDB_Path & fname) + { + TIndx length(0); + return GetFileSizeL(fname.GetPathS(), length); + } + /// Get size of a file. /// /// Check whether a file exists and get the file's size. @@ -1326,72 +385,14 @@ public: /// The filename of the file to get the size of. /// @param length /// The length of the file is returned here. - /// @return - /// true if the file exists. - bool GetFileSizeL(const string & fname, TIndx & length); - - /// Gets a partial mapping of the file. - /// - /// Part of a file is mapped or read. The region is held in - /// memory until the pointer is released with RetRegion(). This - /// method may read or map a larger section of the file than was - /// asked for. It may also return a pointer into an area that was - /// mapped by a previous call. The atlas will be locked if - /// necessary. - /// - /// @param fname - /// The filename of the file to get. - /// @param begin - /// The start offset of the area to map. - /// @param end - /// The end offset of the area to map. - /// @param locked - /// The lock hold object for this thread. - /// @return - /// A pointer to the beginning of the file's data. - const char * GetRegion(const string & fname, - TIndx begin, - TIndx end, - CSeqDBLockHold & locked); - - /// Gets a partial mapping of the file (assumes lock is held). - /// - /// Part of a file is mapped or read. The region is held in - /// memory until the lease object is cleared. This method may - /// read or map a larger section of the file than was asked for. - /// It may also return a pointer into an area that was mapped by a - /// previous call. The atlas is assumed to be locked. - /// - /// @param lease - /// The memory lease object to store the region hold. - /// @param fname - /// The name of the file to get. - /// @param begin - /// The starting file offset. - /// @param end - /// The ending file offset. - void GetRegion(CSeqDBMemLease & lease, - const string & fname, - TIndx begin, - TIndx end); - - /// Release a hold on a region of memory. - /// - /// This method releases holds kept by CSeqDBMemLease objects. It - /// release the reference count and resets the lease to an - /// inactive state. The atlas lock is assumed to be held. This - /// method assumes the lock is held. - /// - /// @param ml - /// The memory lease object holding the reference. - void RetRegion(CSeqDBMemLease & ml); + /// @return + /// true if the file exists. + bool GetFileSizeL(const string & fname, TIndx & length); - /// Release a mapping of the file, or free allocated memory. + /// Free allocated memory. /// - /// This method releases the holds that are gotten by the versions - /// of the GetRegion() and GetFile() methods that return pointers, - /// and by the Alloc() method. Each call to a hold-getting method - /// should be paired with a call to a hold-releasing method. With + /// This method releases the memory aquired + /// by the Alloc() method. With /// data known to have originated in Alloc(), it is faster to call /// the Free() method. This method assumes the lock is held. /// @@ -1399,54 +400,10 @@ public: /// Pointer to the data to release or deallocate. void RetRegion(const char * datap) { - Verify(true); - - for(int i = 0; iInRange(datap)) { - rec_map->RetRef(); - - if (i) { - x_AddRecent(rec_map); - } - - return; - } - } - - x_RetRegionNonRecent(datap); - - Verify(true); + x_RetRegion(datap); } - /// Clean up unreferenced objects - /// - /// This iterates over all file regions managed by the atlas code. - /// If the region has no users, it is a candidate for removal by - /// garbage collection. The lock will be acquired if necessary. - /// - /// @param locked - /// The lock hold object for this thread. - void GarbageCollect(CSeqDBLockHold & locked); - - /// Display memory layout. - /// - /// This method provides a way to examine the set of memory - /// objects in use by the Atlas code, for example when running an - /// application in a debugger. Some or all of the functionality - /// of this code is disabled in a normal compile; it may be - /// necessary to define certain compilation flags to make it - /// available again. - /// - /// @param locked - /// If this is set to false, the atlas lock will be acquired. - /// @param index - /// A value which will be inserted into the output messages. - void ShowLayout(bool locked, TIndx index); + /// Allocate memory that atlas will keep track of. /// @@ -1481,8 +438,7 @@ public: /// This method returns memory acquired from the Alloc() method. /// Dynamically allocated memory from other sources should not be /// freed with this method, and memory allocated via Alloc() - /// should not be freed by any means other than this method or - /// RetRegion(). + /// should not be freed by any means other than this method /// /// @param freeme /// A pointer to memory allocated via Alloc(). @@ -1555,71 +511,7 @@ public: } } - /// Adjust the atlas memory management boundaries. - /// - /// The memory bound determines the total amount of memory the - /// atlas will map before triggering garbage collection. Whenever - /// one of the GetRegion() or GetFile() methods is called, the - /// atlas checks whether the new allocation would bring the total - /// mapped memory over the memory bound. If so, it runs garbage - /// collection, which attempts to free enough regions to satisfy - /// the memory bound. The normal default memory bound is defined - /// at the top of the atlas code, and is something like 1 GB. The - /// second parameter is the slice size. This is (basically) how - /// much memory is acquired at one time for code that uses mmap(). - /// - /// Setting this to a smaller value should reduce page table - /// thrashing for programs that access the database in a - /// non-sequential pattern, and which only use a small portion of - /// the database. Setting it larger should reduce the amount of - /// time the atlas spends finding the next slice when the calling - /// code crosses a "slice boundary". The default is something - /// like 256MB. Both defaults used here should be good enough for - /// all but the worst cases. Note that the memory bound should - /// not be set according to how much memory the computer has, but - /// rather, how much address space the application can spare. - /// SeqDB does not prevent itself from going over the memory - /// bound, particularly if the user is holding onto mapped - /// sequence data for extended periods of time. Also note that if - /// the atlas code thinks these parameters are set to unreasonable - /// values, it will silently adjust them. - /// - /// @param mb - /// Total amount of address space the atlas can use. - void SetMemoryBound(Uint8 mb); - - /// Insure room for a new allocation. - /// - /// This method is used to insure that the atlas code has room for - /// a new address space purchase. When mapping new regions, this - /// method is called. If the memory bound would be exceeded by - /// the addition of the new element, garbage collection will run. - /// Otherwise, this just returns. This does not guarantee that - /// the new object will fit within the memory bound. Because a - /// slice is never collected if the user has a reference to it, it - /// is possible for the user to exhaust memory simply by calling - /// CSeqDB::GetSequence() once for each slice of a large database - /// without calling CSeqDB::RetSequence(). - /// - /// @param space_needed - /// The size in bytes of the new region or allocation. - /// @param returning - /// Specify true if we are about to return to user code. - void PossiblyGarbageCollect(Uint8 space_needed, bool returning); - - /// Return the current overhang amount. - /// - /// This returns the amount of memory to map past the end of the - /// (end-of-map) slice boundary. This should prevent most cases - /// where a memory map 'straddles' the boundary between slices. - /// - /// @return - /// Atlas will map this much data past the slice-end boundary. - Uint8 GetOverhang() - { - return m_Strategy.GetOverhang(); - } - + /// Get the current slice size. /// /// This returns the current slice size used for mmap() style @@ -1627,18 +519,14 @@ public: /// /// @return /// Atlas will try to map this much data at a time. + Uint8 GetSliceSize() - { - return m_Strategy.GetSliceSize(); + { + Uint8 max_slice = e_MaxSlice64; + Uint8 sliceSize = min(max_slice,m_MaxFileSize); + return sliceSize; } - - /// Set the MT slice size. - /// This sets the current slice size used for mmap() allocations. - void SetSliceSize() - { - m_Strategy.SetSliceSize(m_MaxFileSize); - } - + /// Return the current number of bytes allocated. /// /// This returns the number of bytes currently allocated by the @@ -1651,117 +539,7 @@ public: { return m_CurAlloc; } - - /// Verify the integrity of this object and subobjects. - /// @param locked - /// The lock hold object for this thread. [in] - void Verify(CSeqDBLockHold & locked) - { -#ifdef _DEBUG - Lock(locked); - Verify(true); -#endif - } - - /// Verify the integrity of this object and subobjects. - /// @param already_locked - /// True if the lock is already held, false if not. [in] - void Verify(bool already_locked) - { -#ifdef _DEBUG - CSeqDBLockHold locked(*this); - - if (! already_locked) { - Lock(locked); - } - - ITERATE(TNameOffsetTable, iter, m_NameOffsetLookup) { - CRegionMap & rmp = **iter; - rmp.Verify(); - } - - if (! already_locked) { - Unlock(locked); - } -#endif - } - - /// Report a user-specified OID for ordered-access detection. - /// - /// This class attempts to reduce thrashing by determining if the - /// user is accessing OIDs in a "mostly" sequential order. If the - /// user accesses OIDs in order, there should be no possibility of - /// "thrashing". If not, the severity of thrashing can be reduced - /// by selecting a smaller slice size. An OID is considered to be - /// a "sequential" access if it is greater than the last OID minus - /// the greater 10 or 10% of the database. (Multithreaded clients - /// of SeqDB typically assign "blocks" of OIDs, which results in a - /// "mostly" sequential access pattern.) - /// - /// @param oid Currently accessed OID. - /// @param num_oids Number of OIDs in the database. - /// @param locked Lock holder object for this thread. - void MentionOid(int oid, int num_oids, CSeqDBLockHold & locked) - { - Lock(locked); - m_Strategy.MentionOid(oid, num_oids); - } - - /// Add a garbage collection callback. - /// - /// Some classes in the SeqDB library keep holds on regions of - /// memory. This may represent a large subset of the collectable - /// memory, so in order for garbage collection to be effective, - /// these holds should be detached at the beginning of a garbage - /// collection run. To accomplish this, each SeqDB object creates - /// a callback functor that knows how to release its holds; it - /// adds this functor to the atlas using the interface shown here. - /// - /// @param flusher A callback functor to flush held regions. - /// @param flushp A pointer which is set when the flusher is added. - /// @param locked The lock holder object for this thread. - void AddRegionFlusher(CSeqDBFlushCB * flusher, - CSeqDBFlushCB ** flushp, - CSeqDBLockHold & locked) - { - Lock(locked); - m_Flushers.push_back(flusher); - *flushp = flusher; - } - - /// Remove a garbage collection callback. - /// - /// This removes a garbage collection callback from the list - /// stored in the atlas. It is called in preparation for - /// destruction of a CSeqDBImpl object. - /// - /// @param flusher A callback functor to flush held regions. - /// @param locked The lock holder object for this thread. - void RemoveRegionFlusher(CSeqDBFlushCB * flusher, CSeqDBLockHold & locked) - { - Lock(locked); - - _ASSERT(m_Flushers.size()); - - for(size_t i = 0; i < m_Flushers.size(); i++) { - if (m_Flushers[i] == flusher) { - m_Flushers[i] = m_Flushers.back(); - m_Flushers.pop_back(); - return; - } - } - _ASSERT(0); - } - - /// Set global default memory bound. - /// - /// This sets the default, global memory bound used for all SeqDB - /// objects. If zero is specified, an appropriate default will be - /// selected based on system information. - /// - /// @param bytes Number of bytes to use as the global memory bound. - static void SetDefaultMemoryBound(Uint8 bytes); - + /// Get BlastDB search path. const string GetSearchPath() const { @@ -1796,7 +574,34 @@ public: return path; } + map< string, CMemoryFile* > &GetFilesMemMap(void){return m_FileMemMap;} + enum EFilesCount{ + eFileCounterNoChange, + eFileCounterIncrement, + eFileCounterDecrement + }; + + int ChangeOpenedFilseCount(EFilesCount fc) + { + switch(fc) { + case eFileCounterIncrement: + m_OpenedFilesCount++; + break; + + case eFileCounterDecrement: + m_OpenedFilesCount--; + break; + + default: + break; + } + m_MaxOpenedFilesCount = max(m_MaxOpenedFilesCount,m_OpenedFilesCount); + return m_OpenedFilesCount; + } + + int GetOpenedFilseCount(void) { return m_OpenedFilesCount;} + private: /// Private method to prevent copy construction. CSeqDBAtlas(const CSeqDBAtlas &); @@ -1804,66 +609,6 @@ private: /// Iterator type for m_Pool member. typedef map::iterator TPoolIter; - /// Finds a matching region if any exists. - /// - /// This method searches the list of mapped regions to find one - /// with the same fid, and whose offset range includes the - /// specified range. If found, all of the input fields are - /// adjusted to reflect those in the region management object - /// (except fid, which is identical anyway). Also, a pointer to - /// the CRegionMap object is returned in *rmap, and a pointer to - /// the (pre-adjustment) begin offset is returned from the method. - /// If no region was found, NULL is returned and no changes are - /// made to the input parameters. - /// - /// @param fid - /// The number identifying this file to the atlas code. - /// @param begin - /// The beginning offset of the selected area. - /// @param end - /// The ending offset of the selected area. - /// @param startp - /// Returned pointer to the beginning of the mapped region. - /// @param rmap - /// Returned pointer to the CRegionMap object. - /// @return - /// Pointer to the requested portion of the region. - const char * x_FindRegion(int fid, - TIndx & begin, - TIndx & end, - const char ** startp, - CRegionMap ** rmap); - - /// Gets a partial mapping of the file. - /// - /// This method searches the list of mapped regions to find one - /// with the same fid, and whose offset range includes the - /// specified range. If found, it will be used. If not found, a - /// new region will be constructed and used. The parameters work - /// as in In either case, the input fields are adjusted to reflect - /// those in the region management object. Also, a pointer to the - /// CRegionMap object is returned in *rmap, and a pointer to the - /// (pre-adjustment) begin offset is returned from the method. If - /// no region could be found or created, an exception is thrown. - /// - /// @param fname - /// The name of the file to get a region of. - /// @param begin - /// The beginning offset of the selected area. - /// @param end - /// The ending offset of the selected area. - /// @param start - /// Returned pointer to the beginning of the mapped region. - /// @param rmap - /// Returned pointer to the CRegionMap object. - /// @return - /// Pointer to the requested portion of the region. - const char * x_GetRegion(const string & fname, - TIndx & begin, - TIndx & end, - const char ** start, - CRegionMap ** rmap); - /// Try to find the region and free it. /// /// This method looks for the region in the memory pool (m_Pool), @@ -1875,133 +620,23 @@ private: /// true, if the memory block was found and freed. bool x_Free(const char * freeme); - /// Clean up unreferenced objects (non-locking version.) - /// - /// This iterates over all file regions managed by the atlas code. - /// If the region has no users, it is a candidate for removal by - /// garbage collection. The lock is assumed to be already held. - /// If the amount of memory held is reduced to a number below - /// reduce_to, the routine will stop freeing memory and return. - /// - /// @param reduce_to - /// The maximum amount of allocated memory to keep. - void x_GarbageCollect(Uint8 reduce_to); - - /// Find the fid for the filename. - /// - /// Atlas maps filenames to fids. The filename is looked up and - /// the fid is returned. If the filename is not found, it is - /// added to the table and a newly generated fid is returned. The - /// existence of the file is not verified. The second field is - /// used to return a pointer to the internal filename string in - /// the map. This will not change for a given filename, and - /// provides a permanent (for the lifetime of CSeqDBAtlas) address - /// for the filename, which can be used by structures like - /// CRegionMap, so that they don't have to copy string data. - /// - /// @param fname - /// The filename to look up. - /// @param map_fname_ptr - /// The address of the filename key in the lookup table. - /// @return - /// The fid - int x_LookupFile(const string & fname, - const string ** map_fname_ptr); - + /// Releases or deletes a memory region. /// - /// The RetRegion method is called many times. The functionality - /// is split into a fast inlined part and a slow non-inlined part. - /// This is the non-inlined part. It searches for the region or - /// allocated block that owns the specified address, and releases - /// it, if found. This method assumes the lock is held. + /// It searches forallocated block that owns the specified address, + /// and releases it, if found. /// /// @param datap /// Pointer to the area to delete or release a hold on. - void x_RetRegionNonRecent(const char * datap); - - - /// Clear recent-region lookup table - /// - /// Functions which delete regions call this to flush the fast - /// lookup table for recently used region, on the grounds that it - /// may have been invalidated (it may contain dangling pointers). - /// This method carries a small performance cost because regions - /// will need to be looked up using the long process until the - /// table is repopulated. Currently this is only called by the - /// garbage collection code, which normally runs very seldom. - void x_ClearRecent() - { - for(int i = 0; i 0 && found_at < eNumRecent) { - m_Recent[found_at] = m_Recent[found_at - 1]; - --found_at; - } - - m_Recent[0] = r; - } - - /// Call all callbacks. - /// - /// This method calls all the GC callbacks in preparation for a - /// garbage collection run or similar processing. This method - /// assumes the lock is held. - void x_FlushAll() - { - for(size_t i = 0; i < m_Flushers.size(); i++) { - (*m_Flushers[i])(); - } - } - - // Data - + void x_RetRegion(const char * datap); + /// Protects most of the critical regions of the SeqDB library. CMutex m_Lock; - - /// Set to true if memory mapping is enabled. - bool m_UseMmap; - + /// Bytes of "data" currently known to SeqDBAtlas. This does not - /// include metadata, such as the region map class itself.. + /// include metadata TIndx m_CurAlloc; - /// All of the SeqDB region maps. - vector m_Regions; - /// Maps from pointers to dynamically allocated blocks to the byte /// size of the allocation. map m_Pool; @@ -2012,148 +647,29 @@ private: /// Lookup table of fids by filename. map m_FileIDs; - /// RegionMapLess - /// - /// This functor provides an ordering over CRegionMap objects. - - struct RegionMapLess - : public binary_function - { - /// Compare regions using less-than. - /// - /// This compares two CRegionMap objects using that class's - /// overloaded less-than operator. It provides a partial - /// ordering for the TNameOffsetTable. - /// - /// @param L - /// The first object. - /// @param R - /// The second object. - /// @return - /// Returns true if the first object comes before the second one. - inline bool operator()(const CRegionMap* L, const CRegionMap* R) const - { - _ASSERT(L); - _ASSERT(R); - return *L < *R; - } - }; - - /// Defines lookup of regions by fid, offset, and length. - typedef set TNameOffsetTable; - - /// Defines lookup of regions by starting memory address. - typedef map TAddressTable; - - /// Map to find regions for Getting (x_FindRegion). - TNameOffsetTable m_NameOffsetLookup; - - /// Map to find regions for Returning (x_RetRegionNonRecent). - TAddressTable m_AddressLookup; - - // Recent region lookup - - /// Number of recently-used-region slots. - enum { eNumRecent = 8 }; - - /// Table of recently used regions. - CRegionMap * m_Recent[ eNumRecent ]; - - /// Atlas will try to garbage collect if more than this many - /// regions are opened. - int m_OpenRegionsTrigger; - + enum {e_MaxSlice64 = 1 << 30}; + /// Cache of file existence and length. map< string, pair > m_FileSize; /// Maxium file size. Uint8 m_MaxFileSize; - /// Callbacks to flush memory leases before a garbage collection. - vector m_Flushers; - - /// Flexible memory allocation manager. - CSeqDBMapStrategy m_Strategy; - /// BlastDB search path. const string m_SearchPath; -}; - -// Assumes lock is held. - -inline void CSeqDBMemLease::Clear() -{ - CHECK_MARKER(); - m_Atlas.RetRegion(*this); -} - -// ASSUMES lock is held. -inline bool CSeqDBMemLease::Contains(TIndx begin, TIndx end) const -{ - CHECK_MARKER(); - return m_Data && (m_Begin <= begin) && (end <= m_End); -} - - -const char * -CRegionMap::MatchAndUse(int fid, - TIndx & begin, - TIndx & end, - const char ** start) -{ - CHECK_MARKER(); - _ASSERT(fid); - _ASSERT(m_Fid); - - if ((fid == m_Fid) && (m_Begin <= begin) && (m_End >= end)) { - AddRef(); - - const char * location = m_Data + (begin - m_Begin); - - begin = m_Begin; - end = m_End; - *start = m_Data; - _ASSERT(*start); - return location; - } - - return 0; -} - -bool CRegionMap::operator < (const CRegionMap & other) const -{ - CHECK_MARKER(); - // Sort ascending by fid - - if (m_Fid < other.m_Fid) - return true; - if (other.m_Fid < m_Fid) - return false; - - // Sort ascending by start order - - if (m_Begin < other.m_Begin) - return true; - if (other.m_Begin < m_Begin) - return false; - - // Sort ascending by size of mapping. + bool m_Alloc;//m_pool was used for mrmory allocation + map< string, CMemoryFile* > m_FileMemMap; + int m_OpenedFilesCount; + int m_MaxOpenedFilesCount; +}; - return m_End < other.m_End; -} inline CSeqDBMemReg::~CSeqDBMemReg() { m_Atlas.UnregisterExternal(*this); } -inline void CSeqDBMemLease::IncrementRefCnt() -{ - CHECK_MARKER(); - _ASSERT(m_Data && m_RMap); - m_RMap->AddRef(); -} /// Guard object for the SeqDBAtlas singleton. /// @@ -2172,7 +688,7 @@ public: /// @param flusher The garbage collection callback. /// @param locked The lock hold object for this thread (or NULL). CSeqDBAtlasHolder(bool use_mmap, - CSeqDBFlushCB * flusher, + //CSeqDBFlushCB * flusher, CSeqDBLockHold * lockedp); /// Destructor. @@ -2182,8 +698,6 @@ public: CSeqDBAtlas & Get(); private: - /// Garbage collection callback. - CSeqDBFlushCB * m_FlushCB; /// Lock protecting this object's fields DECLARE_CLASS_STATIC_FAST_MUTEX(m_Lock); @@ -2196,6 +710,217 @@ private: }; +class CSeqDBFileMemMap { +public: + + typedef CNcbiStreamoff TIndx; + /// Constructor + /// + /// Initializes a memory map object. + /// + /// @param filename + /// file to memory map + CSeqDBFileMemMap(class CSeqDBAtlas & atlas, const string filename) + : m_Atlas(atlas), + m_DataPtr (NULL), + m_MappedFile( NULL), + m_Mapped(false) + { + Init(filename); + } + + CSeqDBFileMemMap(class CSeqDBAtlas & atlas) + : m_Atlas(atlas), + m_DataPtr (NULL), + m_MappedFile( NULL), + m_Mapped(false) + { + + } + + /// Destructor + ~CSeqDBFileMemMap() + { + Clear(); + } + + /// Initializes a memory map object. + /// + /// @param filename + /// file to memory map + void Init(const string filename) { + if(!m_MappedFile || m_Filename != filename) + { + m_Filename = filename; + Init(); + } + } + + //m_Filename is set + void Init(void) { + + + map &fileMemMap = m_Atlas.GetFilesMemMap(); + if(IsIndexFile() && fileMemMap.count(m_Filename) > 0) { + m_MappedFile = fileMemMap[m_Filename]; + x_LogMessage(eMapExists); + } + else { + try { + if(IsIndexFile()) { + CSeqDBLockHold locked(m_Atlas); + m_Atlas.Lock(locked); + if(fileMemMap.count(m_Filename) == 0) { + m_MappedFile = new CMemoryFile(m_Filename); + fileMemMap.insert(map::value_type(m_Filename,m_MappedFile)); + m_Atlas.ChangeOpenedFilseCount(CSeqDBAtlas::eFileCounterIncrement); + x_LogMessage(eMapNewLocked); + } + else { + m_MappedFile = fileMemMap[m_Filename]; + x_LogMessage(eMapExistsLocked); + } + } + else { + m_MappedFile = new CMemoryFile(m_Filename); + m_Atlas.ChangeOpenedFilseCount(CSeqDBAtlas::eFileCounterIncrement); + x_LogMessage(eMapNew); + } + m_Mapped = true; + } + catch(...) { + x_LogMessage(eMapError); + NCBI_THROW(CSeqDBException, + eFileErr, + "Cannot memory map " + m_Filename + ". Number of files opened: " + NStr::IntToString(m_Atlas.GetOpenedFilseCount())); + } + } + + m_DataPtr = (char *) (m_MappedFile->GetPtr()); + } + + + /// Clears the memory mapobject. + /// + void Clear() + { + + if(m_MappedFile && m_Mapped && !IsIndexFile()) { + m_MappedFile->Unmap(); + m_Atlas.ChangeOpenedFilseCount(CSeqDBAtlas::eFileCounterDecrement); + x_LogMessage(eUnmap); + delete m_MappedFile; + m_MappedFile = NULL; + m_Mapped = false; + } + } + + bool IsMapped(){return m_Mapped;} + + /// Get a pointer to the specified offset. + /// + /// Given an offset (which is assumed to be available here), this + /// method returns a pointer to the data at that offset. + /// + /// @param offset + /// The required offset relative to the start of the file. + /// @return + /// A pointer to the data at the requested location. + const char *GetFileDataPtr(const string & fname,TIndx offset) + { + if(!m_MappedFile || m_Filename != fname) { + Init(fname); + } + + return(const char *)(m_DataPtr + offset); + } + + const char *GetFileDataPtr(TIndx offset) + { + return(const char *)(m_DataPtr + offset); + } + + bool IsIndexFile() { + bool isIndex = (NStr::Find(m_Filename,".pin") != NPOS || NStr::Find(m_Filename,".nin") != NPOS) ? true : false; + return isIndex; + } + +private: + enum ELogMessage { + eNone, + eMapNew, + eMapNewLocked, + eMapExists, + eMapExistsLocked, + eUnmap, + eMapError + }; + + void x_LogMessage(ELogMessage em,CSeqDBAtlas::EFilesCount fc = CSeqDBAtlas::eFileCounterNoChange) + { + //Disable logging + if(em != eMapError) return; + int openedFilesCount; + if(fc != CSeqDBAtlas::eFileCounterNoChange) + { + CSeqDBLockHold locked(m_Atlas); + m_Atlas.Lock(locked); + openedFilesCount = m_Atlas.ChangeOpenedFilseCount(fc); + } + else { + openedFilesCount = m_Atlas.GetOpenedFilseCount(); + } + int threadID = CThread::GetSelf(); + + string logMessage; + switch (em) { + case eMapNew: + logMessage = "Map new :"; + break; + + case eMapNewLocked: + logMessage = "Map new(l):"; + break; + + case eMapExists: + logMessage = "Map exists :"; + break; + + case eMapExistsLocked: + logMessage = "Map exists(l):"; + break; + + case eUnmap: + logMessage = "Unmap :"; + break; + + case eMapError: + logMessage = "Error memory mapping:"; + break; + + case eNone: + break; + + default: + break; + } + if(!logMessage.empty()) { + cerr << logMessage << m_Filename << " openedFilesCount=" << openedFilesCount << " threadID=" << threadID << endl; + } + } + CSeqDBAtlas & m_Atlas; + /// Points to the beginning of the data area. + const char * m_DataPtr; + + string m_Filename; + + CMemoryFile *m_MappedFile; + + bool m_Mapped; +}; + + + END_NCBI_SCOPE #endif // OBJTOOLS_READERS_SEQDB__SEQDBATLAS_HPP diff --git a/c++/include/objtools/blast/seqdb_reader/impl/seqdbcol.hpp b/c++/include/objtools/blast/seqdb_reader/impl/seqdbcol.hpp index 2bf50a80..c271c0db 100644 --- a/c++/include/objtools/blast/seqdb_reader/impl/seqdbcol.hpp +++ b/c++/include/objtools/blast/seqdb_reader/impl/seqdbcol.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBCOL_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBCOL_HPP -/* $Id: seqdbcol.hpp 398155 2013-05-03 11:37:45Z camacho $ +/* $Id: seqdbcol.hpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -50,52 +50,6 @@ USING_SCOPE(objects); #if ((!defined(NCBI_COMPILER_WORKSHOP) || (NCBI_COMPILER_VERSION > 550)) && \ (!defined(NCBI_COMPILER_MIPSPRO)) ) -/// CSeqDBColumnFlush class -/// -/// This object provides a call back to return memory holds to the -/// atlas from lease objects stored under CSeqDBColumn. - -class CSeqDBColumnFlush : public CSeqDBFlushCB { -public: - /// Constructor. - CSeqDBColumnFlush() - : m_Column(0) - { - } - - /// Destructor. - virtual ~CSeqDBColumnFlush() - { - } - - /// Specify the implementation layer object. - /// - /// This method sets the SeqDB implementation layer object - /// pointer. Until this pointer is set, this object will ignore - /// attempts to flush unused data. This pointer should not bet - /// set until object construction is complete enough to permit the - /// memory lease flushing to happen safely. - /// - /// @param col A pointer to the column object. - void SetColumn(class CSeqDBColumn * col) - { - m_Column = col; - } - - /// Flush any held memory leases. - /// - /// At the beginning of garbage collection, this method is called - /// to tell the column to release any held memory leases. If the - /// SetColumn() method has not been called, this method will do - /// nothing. This method assumes the atlas lock is held. - virtual void operator()(); - -private: - /// A pointer to the column object. - class CSeqDBColumn * m_Column; -}; - - /// CSeqDBColumn class. /// /// This code supports arbitrary user-defined data columns. These can @@ -240,7 +194,7 @@ private: /// This callback functor allows the atlas code to flush any /// cached region holds prior to garbage collection. - CSeqDBColumnFlush m_FlushCB; + //CSeqDBColumnFlush m_FlushCB; /// Insures that a copy of the atlas exists. CSeqDBAtlasHolder m_AtlasHolder; @@ -250,15 +204,15 @@ private: /// Index file. CSeqDBRawFile m_IndexFile; - - /// Index file lease. - CSeqDBMemLease m_IndexLease; - + /// Data file. CSeqDBRawFile m_DataFile; - + + /// Index file lease. + CSeqDBFileMemMap m_IndexLease; + /// Data file lease. - CSeqDBMemLease m_DataLease; + CSeqDBFileMemMap m_DataLease; /// Number of OIDs (Blobs) in this column. Int4 m_NumOIDs; diff --git a/c++/include/objtools/blast/seqdb_reader/impl/seqdbfile.hpp b/c++/include/objtools/blast/seqdb_reader/impl/seqdbfile.hpp index aed57578..04a8dd9b 100644 --- a/c++/include/objtools/blast/seqdb_reader/impl/seqdbfile.hpp +++ b/c++/include/objtools/blast/seqdb_reader/impl/seqdbfile.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBFILE_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBFILE_HPP -/* $Id: seqdbfile.hpp 351200 2012-01-26 19:01:24Z maning $ +/* $Id: seqdbfile.hpp 530763 2017-03-17 14:00:40Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -90,15 +90,15 @@ public: /// The lock holder object for this thread. /// @return /// true if the file was opened successfully. - bool Open(const CSeqDB_Path & name, CSeqDBLockHold & locked) + bool Open(const CSeqDB_Path & name) { _ASSERT(name.Valid()); // FIXME: should use path even in atlas code - bool success = m_Atlas.GetFileSize(name.GetPathS(), m_Length, locked); + bool success = m_Atlas.GetFileSizeL(name.GetPathS(), m_Length); if (success) { - m_FileName = name.GetPathS(); + m_FileName = name.GetPathS(); } return success; @@ -120,47 +120,17 @@ public: /// The lock holder object for this thread. /// @return /// A pointer to the file data at the start offset. - const char * GetRegion(CSeqDBMemLease & lease, + const char * GetFileDataPtr(CSeqDBFileMemMap & lease, // commented TIndx start, - TIndx end, - CSeqDBLockHold & locked) const + TIndx end) const { _ASSERT(! m_FileName.empty()); SEQDB_FILE_ASSERT(start < end); SEQDB_FILE_ASSERT(m_Length >= end); + + const char *p = (const char *)lease.GetFileDataPtr(m_FileName,start); - m_Atlas.Lock(locked); - - if (! lease.Contains(start, end)) { - m_Atlas.GetRegion(lease, m_FileName, start, end); - } - - return lease.GetPtr(start); - } - - /// Get a pointer to a section of the file. - /// - /// This method asks the atlas for a hold on the memory region - /// that includes the requested section of the file, and returns a - /// pointer to the start offset in that memory area. - /// - /// @param start - /// The starting offset for the first byte of the region. - /// @param end - /// The offset for the first byte after the region. - /// @param locked - /// The lock holder object for this thread. - /// @return - /// A pointer to the file data. - const char * GetRegion(TIndx start, - TIndx end, - CSeqDBLockHold & locked) const - { - _ASSERT(! m_FileName.empty()); - SEQDB_FILE_ASSERT(start < end); - SEQDB_FILE_ASSERT(m_Length >= end); - - return m_Atlas.GetRegion(m_FileName, start, end, locked); + return p; } /// Get the length of the file. @@ -189,14 +159,14 @@ public: /// The starting offset of the value in the file. /// @param value /// A pointer to the object. - /// @param locked + /// @param /// The lock holder object for this thread. /// @return /// The offset of the first byte after the object. - TIndx ReadSwapped(CSeqDBMemLease & lease, + TIndx ReadSwapped(CSeqDBFileMemMap & lease, TIndx offset, - Uint4 * value, - CSeqDBLockHold & locked) const; + Uint4 * value) const; + /// Read an eight byte numerical object from the file /// @@ -216,10 +186,10 @@ public: /// The lock holder object for this thread. /// @return /// The offset of the first byte after the object. - TIndx ReadSwapped(CSeqDBMemLease & lease, + TIndx ReadSwapped(CSeqDBFileMemMap & lease, TIndx offset, - Uint8 * value, - CSeqDBLockHold & locked) const; + Uint8 * value) const; + /// Read a string object from the file /// @@ -238,11 +208,11 @@ public: /// The lock holder object for this thread. /// @return /// The offset of the first byte after the string. - TIndx ReadSwapped(CSeqDBMemLease & lease, + TIndx ReadSwapped(CSeqDBFileMemMap & lease, TIndx offset, - string * value, - CSeqDBLockHold & locked) const; - + string * value) const; + + /// Read part of the file into a buffer /// /// Copy the file data from offsets start to end into the array at @@ -257,7 +227,7 @@ public: /// The starting offset for the first byte to read. /// @param end /// The offset for the first byte after the area to read. - inline void ReadBytes(CSeqDBMemLease & lease, + inline void ReadBytes(CSeqDBFileMemMap & lease, char * buf, TIndx start, TIndx end) const; @@ -268,7 +238,7 @@ private: /// The name of this file. string m_FileName; - + /// The length of this file. TIndx m_Length; }; @@ -310,14 +280,15 @@ public: /// The lock holder object for this thread. CSeqDBExtFile(CSeqDBAtlas & atlas, const string & dbfilename, - char prot_nucl, - CSeqDBLockHold & locked); + char prot_nucl); + /// Destructor virtual ~CSeqDBExtFile() { } - + + /// Release memory held in the atlas layer by this object. void UnLease() { @@ -325,50 +296,6 @@ public: } protected: - /// Get a region of the file - /// - /// This method is called to load part of the file into the lease - /// object. If the keep argument is set, an additional hold is - /// acquired on the object, so that the user will conceptually own - /// a hold on the object. Such a hold should be returned with the - /// top level RetSequence() method. - /// - /// @param start - /// The beginning offset of the region. - /// @param end - /// The offset for the first byte after the area to read. - /// @param keep - /// Specify true to get a returnable hold for the SeqDB client. - /// @param hold - /// Specify true to get a request-duration hold. - /// @param locked - /// The lock holder object for this thread. - const char * x_GetRegion(TIndx start, - TIndx end, - bool keep, - bool hold, - CSeqDBLockHold & locked, - bool in_lease = false) const - { - m_Atlas.Lock(locked); - - if (! m_Lease.Contains(start, end)) { - if (in_lease) { - return NULL; - } - m_Atlas.GetRegion(m_Lease, m_FileName, start, end); - } - - if (keep) { - m_Lease.IncrementRefCnt(); - } - - if (hold) { - locked.HoldRegion(m_Lease); - } - - return m_Lease.GetPtr(start); - } /// Read part of the file into a buffer /// @@ -408,12 +335,12 @@ protected: /// @return /// The offset of the first byte after the object. template - TIndx x_ReadSwapped(CSeqDBMemLease & lease, + TIndx x_ReadSwapped(CSeqDBFileMemMap & lease, TIndx offset, - T * value, - CSeqDBLockHold & locked) + T * value) + { - return m_File.ReadSwapped(lease, offset, value, locked); + return m_File.ReadSwapped(lease, offset, value); } /// Get the volume's sequence data type. @@ -444,14 +371,14 @@ protected: /// The memory layer management object. CSeqDBAtlas & m_Atlas; - /// A memory lease used by this file. - mutable CSeqDBMemLease m_Lease; - /// The name of this file. string m_FileName; /// Either 'p' for protein or 'n' for nucleotide. char m_ProtNucl; + + /// A memory lease used by this file. + mutable CSeqDBFileMemMap m_Lease; /// The raw file object. CSeqDBRawFile m_File; @@ -502,8 +429,8 @@ public: /// The lock holder object for this thread. CSeqDBIdxFile(CSeqDBAtlas & atlas, const string & dbname, - char prot_nucl, - CSeqDBLockHold & locked); + char prot_nucl); + /// Destructor virtual ~CSeqDBIdxFile() @@ -512,7 +439,7 @@ public: // deadlock in an error path, and destruction and construction // are necessarily single threaded in any case. - Verify(); + //Verify(); UnLease(); } @@ -641,21 +568,35 @@ public: /// Release any memory leases temporarily held here. void UnLease() { - Verify(); + //Verify(); x_ClrHdr(); x_ClrSeq(); x_ClrAmb(); } /// Verify the integrity of this object and subobjects. + /* void Verify() { m_HdrLease.Verify(); m_SeqLease.Verify(); m_AmbLease.Verify(); } - + */ private: + + /// A memory lease used by the header section of this file. + mutable CSeqDBFileMemMap m_HdrLease; + //mutable CMemoryFile *m_MmappedHdrIndex; + + /// A memory lease used by the sequence section of this file. + mutable CSeqDBFileMemMap m_SeqLease; + //mutable CMemoryFile* m_MmappedSeqIndex; + + /// A memory lease used by the ambiguity section of this file. + mutable CSeqDBFileMemMap m_AmbLease; + //mutable CMemoryFile *m_MmappedAmbIndex; + // Swapped data from .[pn]in file /// The volume title. @@ -685,64 +626,44 @@ private: /// Return header data (assumes locked). void x_ClrHdr() const { - if (! m_HdrLease.Empty()) { - m_HdrLease.Clear(); - } + m_HdrLease.Clear(); } /// Return sequence data (assumes locked). void x_ClrSeq() const { - if (! m_SeqLease.Empty()) { - m_SeqLease.Clear(); - } + m_SeqLease.Clear(); } /// Return ambiguity data (assumes locked). void x_ClrAmb() const { - if (! m_AmbLease.Empty()) { - m_AmbLease.Clear(); - } + m_AmbLease.Clear(); } /// Get header data (assumes locked). Uint4 * x_GetHdr() const { - if (m_HdrLease.Empty()) { - m_Atlas.GetRegion(m_HdrLease, m_FileName, m_OffHdr, m_EndHdr); - } - return (Uint4*) m_HdrLease.GetPtr(m_OffHdr); + + return (Uint4*) m_HdrLease.GetFileDataPtr(m_FileName, m_OffHdr); } /// Get sequence data (assumes locked). Uint4 * x_GetSeq() const { - if (m_SeqLease.Empty()) { - m_Atlas.GetRegion(m_SeqLease, m_FileName, m_OffSeq, m_EndSeq); - } - return (Uint4*) m_SeqLease.GetPtr(m_OffSeq); + + return (Uint4*) m_SeqLease.GetFileDataPtr(m_FileName, m_OffSeq); } /// Get ambiguity data (assumes locked). Uint4 * x_GetAmb() const { _ASSERT(x_GetSeqType() == 'n'); - if (m_AmbLease.Empty()) { - m_Atlas.GetRegion(m_AmbLease, m_FileName, m_OffAmb, m_EndAmb); - } - return (Uint4*) m_AmbLease.GetPtr(m_OffAmb); + + return (Uint4*) m_AmbLease.GetFileDataPtr(m_FileName, m_OffAmb); } - /// A memory lease used by the header section of this file. - mutable CSeqDBMemLease m_HdrLease; - - /// A memory lease used by the sequence section of this file. - mutable CSeqDBMemLease m_SeqLease; - - /// A memory lease used by the ambiguity section of this file. - mutable CSeqDBMemLease m_AmbLease; - + /// offset of the start of the header section. TIndx m_OffHdr; @@ -765,6 +686,7 @@ private: bool CSeqDBIdxFile::GetAmbStartEnd(int oid, TIndx & start, TIndx & end) const { + if(!m_Lease.IsMapped()) m_Lease.Init(); if ('n' == x_GetSeqType()) { start = SeqDB_GetStdOrd(& x_GetAmb()[oid]); end = SeqDB_GetStdOrd(& x_GetSeq()[oid+1]); @@ -778,6 +700,7 @@ CSeqDBIdxFile::GetAmbStartEnd(int oid, TIndx & start, TIndx & end) const void CSeqDBIdxFile::GetHdrStartEnd(int oid, TIndx & start, TIndx & end) const { + if(!m_Lease.IsMapped()) m_Lease.Init(); start = SeqDB_GetStdOrd(& x_GetHdr()[oid]); end = SeqDB_GetStdOrd(& x_GetHdr()[oid+1]); } @@ -785,6 +708,7 @@ CSeqDBIdxFile::GetHdrStartEnd(int oid, TIndx & start, TIndx & end) const void CSeqDBIdxFile::GetSeqStartEnd(int oid, TIndx & start, TIndx & end) const { + if(!m_Lease.IsMapped()) m_Lease.Init(); start = SeqDB_GetStdOrd(& x_GetSeq()[oid]); if ('p' == x_GetSeqType()) { @@ -797,6 +721,7 @@ CSeqDBIdxFile::GetSeqStartEnd(int oid, TIndx & start, TIndx & end) const void CSeqDBIdxFile::GetSeqStart(int oid, TIndx & start) const { + if(!m_Lease.IsMapped()) m_Lease.Init(); start = SeqDB_GetStdOrd(& x_GetSeq()[oid]); } @@ -838,9 +763,8 @@ public: /// The lock holder object for this thread. CSeqDBSeqFile(CSeqDBAtlas & atlas, const string & dbname, - char prot_nucl, - CSeqDBLockHold & locked) - : CSeqDBExtFile(atlas, dbname + ".-sq", prot_nucl, locked) + char prot_nucl) + : CSeqDBExtFile(atlas, dbname + ".-sq", prot_nucl) { } @@ -888,14 +812,11 @@ public: /// The lock holder object for this thread. /// @return /// A pointer into the file data. - const char * GetRegion(TIndx start, - TIndx end, - bool keep, - bool hold, - CSeqDBLockHold & locked, - bool in_lease = false) const + const char * GetFileDataPtr(TIndx start) const // commented { - return x_GetRegion(start, end, keep, hold, locked, in_lease); + const char *p = (const char *)m_Lease.GetFileDataPtr(start); + + return p; } }; @@ -929,9 +850,8 @@ public: /// The lock holder object for this thread. CSeqDBHdrFile(CSeqDBAtlas & atlas, const string & dbname, - char prot_nucl, - CSeqDBLockHold & locked) - : CSeqDBExtFile(atlas, dbname + ".-hr", prot_nucl, locked) + char prot_nucl) + : CSeqDBExtFile(atlas, dbname + ".-hr", prot_nucl) { } @@ -977,14 +897,13 @@ public: /// The lock holder object for this thread. /// @return /// A pointer into the file data. - const char * GetRegion(TIndx start, - TIndx end, - CSeqDBLockHold & locked) const + const char * GetFileDataPtr(TIndx start) const // commented { // Header data never requires the 'hold' option because asn.1 // processing is done immediately. - return x_GetRegion(start, end, false, false, locked); + const char *p = (const char *)m_Lease.GetFileDataPtr(start); + return p; } }; @@ -993,16 +912,13 @@ public: // Assumes locked. -void CSeqDBRawFile::ReadBytes(CSeqDBMemLease & lease, +void CSeqDBRawFile::ReadBytes(CSeqDBFileMemMap & lease, char * buf, TIndx start, TIndx end) const { - if (! lease.Contains(start, end)) { - m_Atlas.GetRegion(lease, m_FileName, start, end); - } + memcpy(buf, lease.GetFileDataPtr(m_FileName,start), end-start); - memcpy(buf, lease.GetPtr(start), end-start); } END_NCBI_SCOPE diff --git a/c++/include/objtools/blast/seqdb_reader/impl/seqdbgeneral.hpp b/c++/include/objtools/blast/seqdb_reader/impl/seqdbgeneral.hpp index 9c5b0618..3b6db23e 100644 --- a/c++/include/objtools/blast/seqdb_reader/impl/seqdbgeneral.hpp +++ b/c++/include/objtools/blast/seqdb_reader/impl/seqdbgeneral.hpp @@ -1,7 +1,7 @@ #ifndef CORELIB__SEQDB__SEQDBGENERAL_HPP #define CORELIB__SEQDB__SEQDBGENERAL_HPP -/* $Id: seqdbgeneral.hpp 514045 2016-09-19 12:26:51Z ivanov $ +/* $Id: seqdbgeneral.hpp 513874 2016-09-15 20:02:42Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/blast/seqdb_reader/impl/seqdbisam.hpp b/c++/include/objtools/blast/seqdb_reader/impl/seqdbisam.hpp index 81945a72..c988b68a 100644 --- a/c++/include/objtools/blast/seqdb_reader/impl/seqdbisam.hpp +++ b/c++/include/objtools/blast/seqdb_reader/impl/seqdbisam.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBISAM_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBISAM_HPP -/* $Id: seqdbisam.hpp 482066 2015-10-20 15:12:08Z rackerst $ +/* $Id: seqdbisam.hpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -200,10 +200,10 @@ public: /// The lock hold object for this thread. [in|out] /// @return /// true if the PIG was found - bool PigToOid(TPig pig, TOid & oid, CSeqDBLockHold & locked) + bool PigToOid(TPig pig, TOid & oid) { _ASSERT(m_IdentType == ePigId); - return x_IdentToOid(pig, oid, locked); + return x_IdentToOid(pig, oid); } /// GI or TI translation @@ -222,10 +222,10 @@ public: /// The lock hold object for this thread. [in|out] /// @return /// true if the GI was found - bool IdToOid(Int8 id, TOid & oid, CSeqDBLockHold & locked) + bool IdToOid(Int8 id, TOid & oid) { _ASSERT(m_IdentType == eGiId || m_IdentType == eTiId); - return x_IdentToOid(id, oid, locked); + return x_IdentToOid(id, oid); } /// Translate Gis and Tis to Oids for the given ID list. @@ -246,8 +246,8 @@ public: /// The lock holder object for this thread. [in|out] void IdsToOids(int vol_start, int vol_end, - CSeqDBGiList & ids, - CSeqDBLockHold & locked); + CSeqDBGiList & ids); + /// Compute list of included OIDs based on a negative ID list. /// @@ -276,8 +276,9 @@ public: /// The lock holder object for this thread. [in|out] void IdsToOids(int vol_start, int vol_end, - CSeqDBNegativeList & ids, - CSeqDBLockHold & locked); + CSeqDBNegativeList & ids); + + /// String translation /// @@ -312,8 +313,9 @@ public: void StringToOids(const string & acc, vector & oids, bool adjusted, - bool & version_check, - CSeqDBLockHold & locked); + bool & version_check); + + /// Seq-id translation /// @@ -328,7 +330,7 @@ public: /// The returned oid. [out] /// @param locked /// The lock hold object for this thread. [in|out] - bool SeqidToOid(const string & acc, TOid & oid, CSeqDBLockHold & locked); + bool SeqidToOid(const string & acc, TOid & oid);//does not exist /// Sequence hash lookup /// @@ -346,8 +348,9 @@ public: /// @param locked /// The lock hold object for this thread. [in|out] void HashToOids(unsigned hash, - vector & oids, - CSeqDBLockHold & locked); + vector & oids); + + /// Return any memory held by this object to the atlas. void UnLease(); @@ -364,8 +367,9 @@ public: /// @param locked Lock holder object for this thread. [in] void GetIdBounds(Int8 & low_id, Int8 & high_id, - int & count, - CSeqDBLockHold & locked); + int & count); + + /// Get String Bounds. /// @@ -379,8 +383,9 @@ public: /// @param locked Lock holder object for this thread. [in] void GetIdBounds(string & low_id, string & high_id, - int & count, - CSeqDBLockHold & locked); + int & count); + + /// Check if a given ISAM index exists. /// @@ -491,11 +496,12 @@ private: /// Load and extract all index samples into array at once template - void x_LoadIndex(CSeqDBMemLease & lease, + void x_LoadIndex(CSeqDBFileMemMap & lease, vector & keys, vector & offs) { - const char * keydatap = lease.GetPtr(m_KeySampleOffset); + const char * keydatap = lease.GetFileDataPtr(m_KeySampleOffset); + for (int index=0; index < m_NumSamples; ++index) { keys.push_back(x_GetNumericKey(keydatap)); @@ -509,13 +515,15 @@ private: /// Load and extract a data page into array at once template - void x_LoadData(CSeqDBMemLease & lease, + void x_LoadData(CSeqDBFileMemMap & lease, vector & keys, vector & vals, int num_keys, TIndx begin) { - const char * keydatap = lease.GetPtr(begin); + + const char * keydatap = lease.GetFileDataPtr(begin); + for (int index=0; index < num_keys; ++index) { keys.push_back(x_GetNumericKey(keydatap)); @@ -524,6 +532,7 @@ private: } } + /// GiList Translation /// /// Given a GI list, this routine finds the OID for each ID in the @@ -537,17 +546,17 @@ private: /// The lock holder object for this thread. template void x_TranslateGiList(int vol_start, - CSeqDBGiList & gis, - CSeqDBLockHold & locked) + CSeqDBGiList & gis) + { int gilist_size = gis.GetSize(); if (! gilist_size) return; gis.InsureOrder(CSeqDBGiList::eGi); - + x_InitLease();//Map files if needed if(m_Initialized == false) { - EErrorCode error = x_InitSearch(locked); + EErrorCode error = x_InitSearch(); if(error != eNoError) { // Most ordinary errors (missing GIs for example) are @@ -560,7 +569,7 @@ private: } } - CSeqDBMemLease lease(m_Atlas); + //CSeqDBMemLease lease(m_Atlas); vector sample_keys; vector page_offs; @@ -572,10 +581,8 @@ private: keys.reserve(m_PageSize); vals.reserve(m_PageSize); - m_Atlas.GetRegion(lease, m_IndexFname, 0, m_IndexFileLength); - x_LoadIndex(lease, sample_keys, page_offs); - m_Atlas.RetRegion(lease); - + x_LoadIndex(m_IndexLease, sample_keys, page_offs); + int gilist_index = 0; int sample_index = 0; @@ -597,14 +604,8 @@ private: if (sample_index + 1 == m_NumSamples) { num_keys = m_NumTerms - sample_index * m_PageSize; } - - m_Atlas.GetRegion(lease, - m_DataFname, - page_offs[sample_index], - page_offs[sample_index + 1]); - x_LoadData(lease, keys, vals, num_keys, page_offs[sample_index]); - m_Atlas.RetRegion(lease); - + x_LoadData(m_DataLease, keys, vals, num_keys, page_offs[sample_index]); + int index = 0; while ((gilist_index < gilist_size) && (index < num_keys)) { @@ -644,8 +645,8 @@ private: /// @return /// true if the identifier was found. bool x_IdentToOid(Int8 id, - TOid & oid, - CSeqDBLockHold & locked); + TOid & oid); + /// Index file search /// @@ -671,8 +672,8 @@ private: int * Data, Uint4 * Index, Int4 & SampleNum, - bool & done, - CSeqDBLockHold & locked); + bool & done); + /// Negative ID List Translation /// @@ -693,8 +694,15 @@ private: x_SearchNegativeMulti(int vol_start, int vol_end, CSeqDBNegativeList & gis, - bool use_tis, - CSeqDBLockHold & locked); + bool use_tis); + + + void + x_SearchNegativeMultiSeq(int vol_start, + int vol_end, + CSeqDBNegativeList & gis); + + /// Data file search /// @@ -717,8 +725,8 @@ private: x_SearchDataNumeric(Int8 Number, int * Data, Uint4 * Index, - Int4 SampleNum, - CSeqDBLockHold & locked); + Int4 SampleNum); + /// Numeric identifier lookup /// @@ -737,8 +745,8 @@ private: EErrorCode x_NumericSearch(Int8 Number, int * Data, - Uint4 * Index, - CSeqDBLockHold & locked); + Uint4 * Index); + /// String identifier lookup /// @@ -760,8 +768,8 @@ private: x_StringSearch(const string & term_in, vector & term_out, vector & value_out, - vector & index_out, - CSeqDBLockHold & locked); + vector & index_out); + /// Initialize the search object /// @@ -774,7 +782,7 @@ private: /// @return /// A non-zero error on failure, or eNoError on success. EErrorCode - x_InitSearch(CSeqDBLockHold & locked); + x_InitSearch(void); /// Determine the number of elements in the data page. /// @@ -808,8 +816,8 @@ private: /// true if results were found bool x_SparseStringToOids(const string & acc, vector & oids, - bool adjusted, - CSeqDBLockHold & locked); + bool adjusted); + /// Find the first character to differ in two strings /// @@ -838,13 +846,13 @@ private: /// The position of the first difference. int x_DiffCharLease(const string & term_in, - CSeqDBMemLease & lease, + CSeqDBFileMemMap & lease, const string & file_name, TIndx file_length, Uint4 at_least, TIndx KeyOffset, - bool ignore_case, - CSeqDBLockHold & locked); + bool ignore_case); + /// Find the first character to differ in two strings /// @@ -903,8 +911,7 @@ private: /// @return /// The offset of the sample in the index file. TIndx x_GetIndexKeyOffset(TIndx sample_offset, - Uint4 sample_num, - CSeqDBLockHold & locked); + Uint4 sample_num); /// Read a string from the index file. /// @@ -924,8 +931,8 @@ private: void x_GetIndexString(TIndx key_offset, int length, string & prefix, - bool trim_to_null, - CSeqDBLockHold & locked); + bool trim_to_null); + /// Find the first character to differ in two strings /// @@ -944,8 +951,8 @@ private: /// This thread's lock holder object. int x_DiffSample(const string & term_in, Uint4 SampleNum, - TIndx & KeyOffset, - CSeqDBLockHold & locked); + TIndx & KeyOffset); + /// Find matches in the given page of a string ISAM file. /// @@ -969,8 +976,8 @@ private: TIndx sample_index, vector & indices_out, vector & keys_out, - vector & data_out, - CSeqDBLockHold & locked); + vector & data_out); + /// Find matches in the given memory area of a string ISAM file. /// @@ -1019,8 +1026,8 @@ private: void x_LoadPage(TIndx SampleNum1, TIndx SampleNum2, const char ** beginp, - const char ** endp, - CSeqDBLockHold & locked); + const char ** endp); + /// Test a sample key value from a numeric index. /// @@ -1044,7 +1051,7 @@ private: /// If an exact match, the data found will be returned here. /// @return /// -1, 0 or 1 when key_in is less, equal greater than key_out. - int x_TestNumericSample(CSeqDBMemLease & index_lease, + int x_TestNumericSample(CSeqDBFileMemMap & index_lease, int index, Int8 key_in, Int8 & key_out, @@ -1065,7 +1072,7 @@ private: /// The key found will be returned here. /// @param data_out /// If an exact match, the data found will be returned here. - void x_GetNumericSample(CSeqDBMemLease & index_lease, + void x_GetNumericSample(CSeqDBFileMemMap & index_lease, int index, Int8 & key_out, int & data_out); @@ -1090,6 +1097,12 @@ private: Int8 key, bool use_tis); + inline bool + x_FindInNegativeList(CSeqDBNegativeList & ids, + int & index, + string key); + + /// Map a data page. /// /// The caller provides an index into the sample file. The page @@ -1105,8 +1118,8 @@ private: void x_MapDataPage(int sample_index, int & start, int & num_elements, - const void ** data_page_begin, - CSeqDBLockHold & locked); + const void ** data_page_begin); + /// Get a particular data element from a data page. /// @param dpage A pointer to that page in memory. [in] @@ -1118,18 +1131,23 @@ private: Int8 & key, int & data); + void x_GetDataElement(const void * dpage, + int index, + string & key, + int & data); + /// Find the least and greatest keys in this ISAM file. - void x_FindIndexBounds(CSeqDBLockHold & locked); + void x_FindIndexBounds(); /// Check whether a numeric key is within this volume's bounds. /// @param key The key for which to do the check. /// @param locked The lock holder object for this thread. - bool x_OutOfBounds(Int8 key, CSeqDBLockHold & locked); + bool x_OutOfBounds(Int8 key); /// Check whether a string key is within this volume's bounds. /// @param key The key for which to do the check. /// @param locked The lock holder object for this thread. - bool x_OutOfBounds(string key, CSeqDBLockHold & locked); + bool x_OutOfBounds(string key); /// Converts a string to lower case. static void x_Lower(string & s) @@ -1147,6 +1165,12 @@ private: : GI_TO(Int8, ids.GetGi(index))); } + static string x_GetId(CSeqDBNegativeList & ids, int index) + { + return (ids.GetSi(index)); + } + + /// Make filenames for ISAM file. /// /// @param dbname Base name of the database volume. [in] @@ -1160,6 +1184,11 @@ private: string & index_name, string & data_name); + void x_InitLease(void) { + if(!m_IndexLease.IsMapped()) m_IndexLease.Init(); + if(!m_DataLease.IsMapped()) m_DataLease.Init(); + } + // Data /// The memory management layer @@ -1169,10 +1198,12 @@ private: ESeqDBIdType m_IdentType; /// A persistent lease on the ISAM index file. - CSeqDBMemLease m_IndexLease; + CSeqDBFileMemMap m_IndexLease; + /// A persistent lease on the ISAM data file. - CSeqDBMemLease m_DataLease; + CSeqDBFileMemMap m_DataLease; + /// The format type of database files found (eNumeric or eString). int m_Type; @@ -1247,10 +1278,25 @@ private: else return((int) SeqDB_GetStdOrd(((Uint4 *)p)+1)); } + + void x_LoadStringData(const char *begin, + string & key, + int & data) + { + const char * keydatap = begin; + const char * key_begin = keydatap; + while (*keydatap != 0x02) ++keydatap; + key = string(key_begin, keydatap); + + key_begin = ++keydatap; + while (*keydatap != 0x0a) ++keydatap; + data = NStr::StringToUInt(string(key_begin, keydatap)); + } + }; inline int -CSeqDBIsam::x_TestNumericSample(CSeqDBMemLease & index_lease, +CSeqDBIsam::x_TestNumericSample(CSeqDBFileMemMap & index_lease, int index, Int8 key_in, Int8 & key_out, @@ -1261,7 +1307,9 @@ CSeqDBIsam::x_TestNumericSample(CSeqDBMemLease & index_lease, TIndx offset_begin = m_KeySampleOffset + (m_TermSize * index); - keydatap = index_lease.GetPtr(offset_begin); + + keydatap = index_lease.GetFileDataPtr(offset_begin); + key_out = x_GetNumericKey(keydatap); int rv = 0; @@ -1279,7 +1327,7 @@ CSeqDBIsam::x_TestNumericSample(CSeqDBMemLease & index_lease, } inline void -CSeqDBIsam::x_GetNumericSample(CSeqDBMemLease & index_lease, +CSeqDBIsam::x_GetNumericSample(CSeqDBFileMemMap & index_lease, int index, Int8 & key_out, int & data_out) @@ -1288,7 +1336,9 @@ CSeqDBIsam::x_GetNumericSample(CSeqDBMemLease & index_lease, TIndx offset_begin = m_KeySampleOffset + (m_TermSize * index); - keydatap = index_lease.GetPtr(offset_begin); + + keydatap = index_lease.GetFileDataPtr(offset_begin); + key_out = x_GetNumericKey(keydatap); data_out = x_GetNumericData(keydatap); } @@ -1296,16 +1346,16 @@ CSeqDBIsam::x_GetNumericSample(CSeqDBMemLease & index_lease, /// Load and extract all index samples into array at once template <> inline void CSeqDBIsam::x_LoadIndex( - CSeqDBMemLease & lease, + CSeqDBFileMemMap & lease, vector & keys, vector & offs ) { - const char * keydatap = lease.GetPtr(m_KeySampleOffset); - + + const char * keydatap = lease.GetFileDataPtr(m_KeySampleOffset); + for (int index=0; index < m_NumSamples; ++index) { - keys.push_back(GI_FROM(Uint8, x_GetNumericKey(keydatap))); - // vals.push_back(x_GetNumericData(keydatap)); + keys.push_back(GI_FROM(Uint8, x_GetNumericKey(keydatap))); offs.push_back(index * m_PageSize * m_TermSize); keydatap += m_TermSize; } @@ -1316,14 +1366,15 @@ inline void CSeqDBIsam::x_LoadIndex( /// Load and extract a data page into array at once template <> inline void CSeqDBIsam::x_LoadData( - CSeqDBMemLease & lease, + CSeqDBFileMemMap & lease, vector & keys, vector & vals, int num_keys, TIndx begin ) { - const char * keydatap = lease.GetPtr(begin); + + const char * keydatap = lease.GetFileDataPtr(begin); for (int index=0; index < num_keys; ++index) { keys.push_back(GI_FROM(Uint8, x_GetNumericKey(keydatap))); @@ -1333,28 +1384,29 @@ inline void CSeqDBIsam::x_LoadData( } template <> inline void -CSeqDBIsam::x_LoadIndex(CSeqDBMemLease & lease, +CSeqDBIsam::x_LoadIndex(CSeqDBFileMemMap & lease, vector & keys, vector & offs) { TIndx offset_begin = m_KeySampleOffset; TIndx sample_begin = offset_begin + sizeof(Uint4) * (m_NumSamples + 1); - // load offset array - const Uint4 * offset = (const Uint4 *) lease.GetPtr(offset_begin); + // load offset array + const Uint4 * offset = (const Uint4 *) lease.GetFileDataPtr(offset_begin); for (int index=0; index <= m_NumSamples; ++index, ++offset) { // Get the data_offsets offs.push_back(SeqDB_GetStdOrd((Uint4*) offset)); } - // load sample array - offset = (const Uint4 *) lease.GetPtr(sample_begin); + // load sample array + offset = (const Uint4 *) lease.GetFileDataPtr(sample_begin); for (int index=0; index < m_NumSamples; ++index, ++offset) { // Get the index_offsets offset_begin = SeqDB_GetStdOrd((Uint4*) offset); - // Lookup the samples - const char * keydatap = (const char *) lease.GetPtr(offset_begin) - 1; + // Lookup the samples + const char * keydatap = (const char *) lease.GetFileDataPtr(offset_begin) - 1; + const char * key_begin = ++ keydatap; while (*keydatap != 0x02) ++keydatap; @@ -1367,13 +1419,14 @@ CSeqDBIsam::x_LoadIndex(CSeqDBMemLease & lease, } template <> inline void -CSeqDBIsam::x_LoadData(CSeqDBMemLease & lease, +CSeqDBIsam::x_LoadData(CSeqDBFileMemMap & lease, vector & keys, vector & vals, int num_keys, TIndx begin) { - const char * keydatap = (const char *) lease.GetPtr(begin) - 1; + const char * keydatap = (const char *) lease.GetFileDataPtr(begin) - 1; + for (int index=0; index < num_keys; ++index) { const char * key_begin = ++keydatap; @@ -1386,7 +1439,6 @@ CSeqDBIsam::x_LoadData(CSeqDBMemLease & lease, } } - inline bool CSeqDBIsam::x_FindInNegativeList(CSeqDBNegativeList & ids, int & index, @@ -1396,8 +1448,7 @@ CSeqDBIsam::x_FindInNegativeList(CSeqDBNegativeList & ids, bool found = false; // Skip any that are less than key. - - int ids_size = use_tis ? ids.GetNumTis() : ids.GetNumGis(); + int ids_size = ids.ListSize(); while((index < ids_size) && (x_GetId(ids, index, use_tis) < key)) { index++; @@ -1421,29 +1472,52 @@ CSeqDBIsam::x_FindInNegativeList(CSeqDBNegativeList & ids, } +inline bool +CSeqDBIsam::x_FindInNegativeList(CSeqDBNegativeList & ids, + int & index, + string key) +{ + bool found = false; + + // Skip any that are less than key. + int ids_size = ids.ListSize(); + + while((index < ids_size) && (x_GetId(ids, index) < key)) { + index++; + + int jump = 2; + + while((index + jump) < ids_size && + x_GetId(ids, index + jump) < key) { + index += jump; + jump += jump; + } + } + + // Check whether the GI or TI was found. + + if ((index < ids_size) && (x_GetId(ids,index) == key)) { + found = true; + } + + return found; +} + + inline void CSeqDBIsam::x_MapDataPage(int sample_index, int & start, int & num_elements, - const void ** data_page_begin, - CSeqDBLockHold & locked) + const void ** data_page_begin) + { num_elements = x_GetPageNumElements(sample_index, & start); TIndx offset_begin = start * m_TermSize; - TIndx offset_end = offset_begin + m_TermSize * num_elements; - - m_Atlas.Lock(locked); - - if (! m_DataLease.Contains(offset_begin, offset_end)) { - m_Atlas.GetRegion(m_DataLease, - m_DataFname, - offset_begin, - offset_end); - } - - *data_page_begin = m_DataLease.GetPtr(offset_begin); + //TIndx offset_end = offset_begin + m_TermSize * num_elements; + + *data_page_begin = m_DataLease.GetFileDataPtr(m_DataFname,offset_begin); } inline void @@ -1456,8 +1530,17 @@ CSeqDBIsam::x_GetDataElement(const void * dpage, data = x_GetNumericData((char *)dpage + index * m_TermSize); } +inline void +CSeqDBIsam::x_GetDataElement(const void * dpage, + int index, + string & key, + int & data) +{ + x_LoadStringData((char *)dpage + index * m_TermSize, + key, + data); +} + END_NCBI_SCOPE #endif // OBJTOOLS_READERS_SEQDB__SEQDBFILE_HPP - - diff --git a/c++/include/objtools/blast/seqdb_reader/impl/seqdbtax.hpp b/c++/include/objtools/blast/seqdb_reader/impl/seqdbtax.hpp index e0c49fc0..56a42dc8 100644 --- a/c++/include/objtools/blast/seqdb_reader/impl/seqdbtax.hpp +++ b/c++/include/objtools/blast/seqdb_reader/impl/seqdbtax.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBTAX_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBTAX_HPP -/* $Id: seqdbtax.hpp 384579 2012-12-28 15:45:35Z maning $ +/* $Id: seqdbtax.hpp 524043 2017-01-09 16:10:06Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -47,61 +47,14 @@ BEGIN_NCBI_SCOPE /// Import definitions from the objects namespace. USING_SCOPE(objects); -/// CSeqDBTaxId class -/// -/// This is a memory overlay class. Do not change the size or layout -/// of this class unless corresponding changes happen to the taxonomy -/// database file format. This class's constructor and destructor are -/// not called; instead, a pointer to mapped memory is cast to a -/// pointer to this type, and the access methods are used to examine -/// the fields. - -class CSeqDBTaxId { -public: - /// Constructor - /// - /// This class is a read-only memory overlay and is not expected - /// to ever be constructed. - CSeqDBTaxId() - { - _ASSERT(0); - } - - /// Return the taxonomic identifier field (in host order) - Int4 GetTaxId() - { - return SeqDB_GetStdOrd(& m_Taxid); - } - - /// Return the offset field (in host order) - Int4 GetOffset() - { - return SeqDB_GetStdOrd(& m_Offset); - } - -private: - /// This structure should not be copy constructed - CSeqDBTaxId(const CSeqDBTaxId &); - - /// The taxonomic identifier - Uint4 m_Taxid; - - /// The offset of the start of the taxonomy data. - Uint4 m_Offset; -}; /// CSeqDBTaxInfo class /// /// This manages access to the taxonomy database. -class CSeqDBTaxInfo : public CObject { +class CSeqDBTaxInfo { public: - /// Constructor - CSeqDBTaxInfo(CSeqDBAtlas & atlas); - - /// Destructor - virtual ~CSeqDBTaxInfo(); /// Get the taxonomy names for a given tax id /// @@ -116,37 +69,9 @@ public: /// @param locked /// The lock holder object for this thread. /// @return true if the taxonomic id was found - bool GetTaxNames(Int4 tax_id, - SSeqDBTaxInfo & info, - CSeqDBLockHold & locked); - -private: - /// The memory management layer - CSeqDBAtlas & m_Atlas; - - /// A memory lease for the index file - CSeqDBMemLease m_Lease; - - /// The filename of the taxonomic db index file - string m_IndexFN; + static bool GetTaxNames(Int4 tax_id, SSeqDBTaxInfo & info); - /// The filename of the taxnomoic db data file - string m_DataFN; - - /// Total number of taxids in the database - Int4 m_AllTaxidCount; - - /// Memory map of the index file - CSeqDBTaxId * m_TaxData; - - /// Initialization status indicator - bool m_Initialized; - - /// Indicator if tax db files are missing - bool m_MissingDB; - /// Lazy initialization - void x_Init(CSeqDBLockHold & locked); }; END_NCBI_SCOPE diff --git a/c++/include/objtools/blast/seqdb_reader/impl/seqdbvol.hpp b/c++/include/objtools/blast/seqdb_reader/impl/seqdbvol.hpp index 1e3432f7..2784fbdd 100644 --- a/c++/include/objtools/blast/seqdb_reader/impl/seqdbvol.hpp +++ b/c++/include/objtools/blast/seqdb_reader/impl/seqdbvol.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBVOL_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBVOL_HPP -/* $Id: seqdbvol.hpp 481389 2015-10-09 14:40:20Z rackerst $ +/* $Id: seqdbvol.hpp 539178 2017-06-19 17:07:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -61,10 +61,11 @@ public: CSeqDBGiIndex(CSeqDBAtlas & atlas, const string & dbname, char prot_nucl) - : m_Atlas (atlas), - m_Lease (atlas), - m_Fname (dbname + '.' + prot_nucl + "og"), - m_NumOIDs (0) { } + : m_Lease (atlas), + //m_Fname (dbname + '.' + prot_nucl + "og"), + m_NumOIDs (0) { + m_Lease.Init(dbname + '.' + prot_nucl + "og"); + } ~CSeqDBGiIndex() { @@ -81,9 +82,8 @@ public: TGi GetSeqGI(TOid oid, CSeqDBLockHold & locked); private: - CSeqDBAtlas & m_Atlas; - CSeqDBMemLease m_Lease; - string m_Fname; + CSeqDBFileMemMap m_Lease; + //string m_Fname; Int4 m_Size; Int4 m_NumOIDs; }; @@ -102,11 +102,7 @@ public: /// Constructor. /// @param atlas The SeqDB memory management layer. [in] CSeqDBRangeList(CSeqDBAtlas & atlas) - : m_Atlas (atlas), - m_CacheData (false), - m_Sequence (0), - m_Length (0), - m_RefCount (0) + : m_CacheData (false) { // Sequence caching is not implemented yet. It would increase // performance further, but requires some consideration of the @@ -154,23 +150,11 @@ public: } private: - /// Memory management layer. - CSeqDBAtlas & m_Atlas; - /// Range of offsets needed for this sequence. TRangeList m_Ranges; /// True if caching of sequence data is required for this sequence. bool m_CacheData; - - /// Pointer to cached sequence data. - const char * m_Sequence; - - /// Length of sequence. - int m_Length; - - /// Number of user-held references to this sequence. - int m_RefCount; }; /// CSeqDBVol class. @@ -339,7 +323,6 @@ public: GetBioseq(int oid, TGi pref_gi, const CSeq_id * pref_seq_id, - CRef tax_info, bool seqdata, CSeqDBLockHold & locked); @@ -372,7 +355,7 @@ public: CSeqDBLockHold & locked, bool in_lease = false) const { - return x_GetSequence(oid, buffer, true, locked, false, in_lease); + return x_GetSequence(oid, buffer, true, false, in_lease); } /// Get a sequence with ambiguous regions. @@ -419,8 +402,7 @@ public: /// The lock holder object for this thread. [in] /// @return /// The list of Seq-id objects for this sequences. - list< CRef > GetSeqIDs(int oid, - CSeqDBLockHold & locked) const; + list< CRef > GetSeqIDs(int oid) const; /// Get the GI of a sequence /// This method returns the gi of the sequence @@ -469,6 +451,7 @@ public: /// reacquired (but not, for example, the index file data). void UnLease(); + /// Find the OID given a PIG. /// /// A lookup is done for the PIG, and if found, the corresponding @@ -900,26 +883,25 @@ private: Int8 ident, const string & str_id, bool simplified, - vector & oids, - CSeqDBLockHold & locked) const; + vector & oids) const; /// A set of GI lists. typedef vector< CRef > TGiLists; /// Returns true if this volume has a positive ID list. - bool x_HaveGiList() const + bool x_HaveGiList(void) const { return ! (m_UserGiList.Empty() && m_VolumeGiLists.empty()); } /// Returns true if this volume has a negative ID list. - bool x_HaveNegativeList() const + bool x_HaveNegativeList(void) const { return m_NegativeList.NotEmpty(); } /// Returns true if this volume has an ID list. - bool x_HaveIdFilter() const + bool x_HaveIdFilter(void) const { return x_HaveGiList() || x_HaveNegativeList(); } @@ -1010,7 +992,7 @@ private: bool match_type = false; bool found = L.FindId(id, match_type); - return (! found) && match_type; + return (! found) && match_type; } /// Get sequence header object. @@ -1034,8 +1016,7 @@ private: CRef x_GetHdrAsn1(int oid, bool adjust_oids, - bool * changed, - CSeqDBLockHold & locked) const; + bool * changed) const; /// Get sequence header binary data. /// @@ -1050,7 +1031,7 @@ private: /// The lock holder object for this thread. [in] /// @return /// The Blast-def-line-set describing this sequence. - CTempString x_GetHdrAsn1Binary(int oid, CSeqDBLockHold & locked) const; + CTempString x_GetHdrAsn1Binary(int oid) const; /// Get binary sequence header information. /// @@ -1065,8 +1046,8 @@ private: /// The lock holder object for this thread. [in] void x_GetFilteredBinaryHeader(int oid, - vector & hdr_data, - CSeqDBLockHold & locked) const; + vector & hdr_data) const; + /// Get sequence header information. /// @@ -1086,8 +1067,7 @@ private: /// The set of blast-def-lines describing this sequence. CRef x_GetFilteredHeader(int oid, - bool * changed, - CSeqDBLockHold & locked) const; + bool * changed) const; /// Get sequence header information structures. /// @@ -1102,8 +1082,7 @@ private: /// The lock holder object for this thread. [in] /// @return /// The CSeqdesc to include in the CBioseq. - CRef x_GetAsnDefline(int oid, - CSeqDBLockHold & locked) const; + CRef x_GetAsnDefline(int oid) const; /// Returns 'p' for protein databases, or 'n' for nucleotide. char x_GetSeqType() const; @@ -1126,8 +1105,7 @@ private: /// @param locked /// The lock holder object for this thread. [in] void x_GetAmbChar(int oid, - vector & ambchars, - CSeqDBLockHold & locked) const; + vector & ambchars) const; /// Get a sequence with ambiguous regions. /// @@ -1208,8 +1186,7 @@ private: /// The length of the sequence in bases. int x_GetSequence(int oid, const char ** buffer, - bool keep, - CSeqDBLockHold & locked, + bool keep, bool can_release, bool in_lease = false) const; @@ -1265,8 +1242,8 @@ private: CRef x_GetTaxDefline(int oid, TGi preferred_gi, - const CSeq_id * preferred_seq_id, - CSeqDBLockHold & locked); + const CSeq_id * preferred_seq_id); + /// Get taxonomic descriptions of a sequence. /// @@ -1293,9 +1270,8 @@ private: list< CRef > x_GetTaxonomy(int oid, TGi preferred_gi, - const CSeq_id * preferred_seq_id, - CRef tax_info, - CSeqDBLockHold & locked); + const CSeq_id * preferred_seq_id); + /// Returns the base-offset of the specified oid. /// @@ -1313,7 +1289,7 @@ private: /// The lock holder object for this thread. [in] /// @return /// The offset in the volume of that sequence in bytes. - Uint8 x_GetSeqResidueOffset(int oid, CSeqDBLockHold & locked) const; + Uint8 x_GetSeqResidueOffset(int oid) const; /// Find all columns for this volume. /// @@ -1343,17 +1319,17 @@ private: /// @param locked /// The lock holder object for this thread. [in] void x_CheckVersions(const string & acc, - vector & oids, - CSeqDBLockHold & locked) const; - - void x_OpenSeqFile(CSeqDBLockHold &locked) const; - void x_OpenHdrFile(CSeqDBLockHold &locked) const; - void x_OpenPigFile(CSeqDBLockHold &locked) const; - void x_OpenGiFile(CSeqDBLockHold &locked) const; - void x_OpenStrFile(CSeqDBLockHold &locked) const; - void x_OpenTiFile(CSeqDBLockHold &locked) const; - void x_OpenHashFile(CSeqDBLockHold &locked) const; - void x_OpenOidFile(CSeqDBLockHold &locked) const; + vector & oids) const; + + void x_OpenSeqFile(void) const; + void x_OpenHdrFile(void) const; + void x_OpenPigFile(void) const; + void x_OpenGiFile(void) const; + void x_OpenStrFile(void) const; + void x_OpenTiFile(void) const; + void x_OpenHashFile(void) const; + void x_OpenOidFile(void) const; + void x_UnLeaseIsam(void) const; /// The memory management layer. CSeqDBAtlas & m_Atlas; diff --git a/c++/include/objtools/blast/seqdb_reader/seqdb.hpp b/c++/include/objtools/blast/seqdb_reader/seqdb.hpp index 3e78b590..b2d02c25 100644 --- a/c++/include/objtools/blast/seqdb_reader/seqdb.hpp +++ b/c++/include/objtools/blast/seqdb_reader/seqdb.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_BLAST_SEQDB_READER___SEQDB__HPP #define OBJTOOLS_BLAST_SEQDB_READER___SEQDB__HPP -/* $Id: seqdb.hpp 516402 2016-10-13 12:28:06Z ivanov $ +/* $Id: seqdb.hpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -449,17 +449,6 @@ public: /// been returned by RetSequence(). ~CSeqDB(); - /// Sets mmap strategy to be used when mapping index or sequence files. - /// - /// This method sets internal flags of type EMemoryAdvise for a call to - /// MemoryAdvise in CRegionMap::MapMmap. - /// Note that these are only hints, the system may or may not - /// actually alter its behavior when mapping these files. - static void SetMmapStrategy( - EMmapFileTypes filetype, - EMmapStrategies strategy - ); - /// Returns the default BLAST database search path /// configured for this local installation of BLAST static string GenerateSearchPath(); @@ -983,24 +972,6 @@ public: /// @return A pointer to the attached ID set, or NULL. CSeqDBIdSet GetIdSet() const; - /// Set upper limit on memory and mapping slice size. - /// - /// This sets a (not precisely enforced) upper limit on memory - /// used by CSeqDB to memory map disk files (and for some large - /// arrays). Setting this to a low value may degrade performance. - /// Setting it to too high a value may cause address space - /// exhaustion. Normally, SeqDB will start with a large bound and - /// reduces it if memory exhaustion is detected. Applications - /// that use a lot of memory outside of SeqDB may want to call - /// this method to scale back SeqDB's demands. Note that slice - /// size is no longer externally adjustable and may be removed in - /// the future. Also note that if SeqDB detects a map failure, it - /// will reduce the memory bound. - /// - /// @param membound Maximum memory for SeqDB. - /// @param slice_size No longer used. - void SetMemoryBound(Uint8 membound, Uint8 slice_size = 0); - /// Translate a PIG to an OID. bool PigToOid(int pig, int & oid) const; @@ -1197,18 +1168,6 @@ public: TSeqPos begin, TSeqPos end) const; - /// Set global default memory bound for SeqDB. - /// - /// The memory bound for individual SeqDB objects can be adjusted - /// with SetMemoryBound(), but this cannot be called until after - /// the object is constructed. Until that time, the value used is - /// set from a global default. This method allows that global - /// default value to be changed. Any SeqDB object constructed - /// after this method is called will use this value as the initial - /// memory bound. If zero is specified, an appropriate default - /// will be selected based on system information. - static void SetDefaultMemoryBound(Uint8 bytes); - /// Get a sequence in a given encoding. /// /// This method gets the sequence data for the given OID, converts @@ -1400,9 +1359,6 @@ public: TSequenceRanges &ranges); #endif - /// Invoke the garbage collector to free up memory - void GarbageCollect(void); - /***********************************************************************/ /* BEGIN: support for partial sequence fetching */ @@ -1463,15 +1419,16 @@ public: /// @param num_threads Number of threads void SetNumberOfThreads(int num_threads, bool force_mt = false); - /// Retrieve the current slice size used for mmap - Int8 GetSliceSize() const; - /// Retrieve the disk usage in bytes for this BLAST database Int8 GetDiskUsage() const; /// Set the membership of all volumes void SetVolsMemBit(int mbit); + /// Dump debug information for this object + /// @sa CDebugDumpable + void DebugDump(CDebugDumpContext ddc, unsigned int depth) const; + protected: /// Implementation details are hidden. (See seqdbimpl.hpp). class CSeqDBImpl * m_Impl; @@ -1615,37 +1572,6 @@ CSeqDB::ESeqType ParseMoleculeTypeString(const string& str); NCBI_XOBJREAD_EXPORT bool DeleteBlastDb(const string& dbpath, CSeqDB::ESeqType seq_type); -/// Class to facilitate trimming down the list of WGS BLAST DBs so to those -/// relevant to the GIs provided. (WB-1206, WB-1069) -/// @note this class relies on the environment variable WGS_GILIST_DIR -class NCBI_XOBJREAD_EXPORT CWgsDbTrimmer { -public: - /// Constructor which takes a space separated list of WGS BLAST DBs - CWgsDbTrimmer(const string& wgs_db_list); - /// Add a gi that appears in the BLAST results, so that the resulting - /// WGS BLAST DB list can be trimmed on the basis of this - void AddGi(TGi gi) { m_Gis.insert(gi); } - /// Builds a space separated, trimmed list of WGS BLAST DBs which contain - /// all of the GIs, provided to this object until this method is called. - /// Those GIs that aren't found in the original list of WGS BLASTDBs - /// provided in the constructor are silently ignored. - /// @note the list of BLAST DBs will be returned in alphabetical order - string GetDbList(); - /// Returns the BLASTDB list originally provided in the constructor - string GetOrigDbList() const { return m_OrigWgsList; } -private: - typedef map > TGiLists; - /// Reads the gi lists for each of the BLAST DBs provided in the - /// constructor, ignoring those that can't be found - TGiLists x_ReadGiListsForDbs(); - /// Returns the WGS BLAST DBs provided in the constructor into a set - set x_ExtractOriginalWgsDbs(); - string m_OrigWgsList; - set m_Gis; - /// Path where the WGS GI list files are cached (pointed to by WGS_GILIST_DIR) - string m_Path; -}; - END_NCBI_SCOPE #endif // OBJTOOLS_BLAST_SEQDB_READER___SEQDB__HPP diff --git a/c++/include/objtools/blast/seqdb_reader/seqdbcommon.hpp b/c++/include/objtools/blast/seqdb_reader/seqdbcommon.hpp index c14a4afa..69dbbe3e 100644 --- a/c++/include/objtools/blast/seqdb_reader/seqdbcommon.hpp +++ b/c++/include/objtools/blast/seqdb_reader/seqdbcommon.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_BLAST_SEQDB_READER___SEQDBCOMMON__HPP #define OBJTOOLS_BLAST_SEQDB_READER___SEQDBCOMMON__HPP -/* $Id: seqdbcommon.hpp 484374 2015-11-10 16:37:43Z rackerst $ +/* $Id: seqdbcommon.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -359,7 +359,7 @@ public: } template - const T GetKey(int index) const + T GetKey(int index) const { return m_GisOids[index].gi; } @@ -383,6 +383,7 @@ public: void GetTiList(vector& tis) const; /// TODO Get the seqid list? + void GetSiList(vector& sis) const; /// Add a new GI to the list. void AddGi(TGi gi) @@ -414,6 +415,11 @@ public: m_TisOids.reserve(n); } + void ReserveSis(size_t n) + { + m_SisOids.reserve(n); + } + /// TODO Reserve space for seqids? protected: /// Indicates the current sort order, if any, of this container. @@ -450,7 +456,7 @@ inline int CSeqDBGiList::GetSize() const } template < > -inline const TTi CSeqDBGiList::GetKey(int index) const +inline TTi CSeqDBGiList::GetKey(int index) const { return m_TisOids[index].ti; } @@ -474,7 +480,7 @@ inline int CSeqDBGiList::GetSize() const } template < > -inline const string CSeqDBGiList::GetKey(int index) const +inline string CSeqDBGiList::GetKey(int index) const { return m_SisOids[index].si; } @@ -526,7 +532,7 @@ public: /// @param oid The OID in question. [in] void ClearBit(int oid) { - if (oid < m_Size) { + if (oid >= m_Size) { return; } x_ClearBit(oid); @@ -667,6 +673,9 @@ public: /// Test for existence of a TI. bool FindTi(TTi ti); + + bool FindSi(string si); + /// Test for existence of a TI or GI here and report whether the /// ID was one of those types. /// @@ -726,6 +735,33 @@ public: return (int) m_Sis.size(); } + bool IsGiList() const + { + return(GetNumGis() > 0); + } + + bool IsTiList() const + { + return(GetNumTis() > 0); + } + + bool IsSiList() const + { + return(GetNumSis() > 0); + } + + int ListSize() + { + int size = GetNumGis(); + if(size == 0) { + size = GetNumSis(); + } + if(size == 0) { + size = GetNumTis(); + } + return size; + } + /// Return false if there are elements present. bool Empty() const { @@ -790,6 +826,11 @@ public: m_Tis.reserve(n); } + void ReserveSis(size_t n) + { + m_Sis.reserve(n); + } + /// Build ID set for this negative list. const vector & GetGiList() { @@ -808,6 +849,12 @@ public: { return m_Tis; } + + const vector & GetSiList() + { + return m_Sis; + } + /// Get list size int Size(void) { @@ -1169,6 +1216,14 @@ public: } } + CSeqDBIdSet_Vector(const vector & ids) + { + ITERATE(vector, iter, ids) { + m_SeqIds.push_back((string) *iter); + } + } + + #ifdef NCBI_STRICT_GI /// Construct from a 'TGi' set when NCBI_STRICT_GI is in force. CSeqDBIdSet_Vector(const vector & ids) @@ -1190,17 +1245,35 @@ public: { return m_Ids; } + + /// Access the string set. + vector & SetSeqIDs() + { + return m_SeqIds; + } + + /// Access the string set. + const vector & GetSeqIDs() const + { + return m_SeqIds; + } /// Get the number of elements stored here. size_t Size() const { - return m_Ids.size(); + size_t n = m_Ids.size(); + if(n == 0) { + n = m_SeqIds.size(); + } + return n; } private: /// The actual list elements. vector m_Ids; + vector m_SeqIds; + /// Prevent copy construction. CSeqDBIdSet_Vector(CSeqDBIdSet_Vector &); @@ -1230,7 +1303,8 @@ public: /// Type of IDs stored here. enum EIdType { eGi, // Found in both X and Y - eTi // Found in X or Y, but not both + eTi, // Found in X or Y, but not both + eSi }; /// Construct a 'blank' CSeqDBIdSet object. @@ -1277,6 +1351,9 @@ public: /// @param positive True for a positive ID list, false for negative. CSeqDBIdSet(const vector & ids, EIdType t, bool positive = true); + + + #ifdef NCBI_STRICT_GI /// Build a computed ID list given an initial set of IDs. /// @@ -1291,6 +1368,8 @@ public: CSeqDBIdSet(const vector & ids, EIdType t, bool positive = true); #endif + CSeqDBIdSet(const vector & ids, EIdType t, bool positive = true); + /// Virtual destructor. virtual ~CSeqDBIdSet() { @@ -1401,6 +1480,8 @@ private: /// Sort and unique the internal set. static void x_SortAndUnique(vector & ids); + static void x_SortAndUnique(vector & ids); + /// Compute inclusion flags for a boolean operation. /// /// This takes a logical operator (AND, OR, or XOR) and a flag diff --git a/c++/include/objtools/blast/seqdb_writer/build_db.hpp b/c++/include/objtools/blast/seqdb_writer/build_db.hpp index 834d332f..1c66c901 100644 --- a/c++/include/objtools/blast/seqdb_writer/build_db.hpp +++ b/c++/include/objtools/blast/seqdb_writer/build_db.hpp @@ -1,4 +1,4 @@ -/* $Id: build_db.hpp 514245 2016-09-20 17:05:47Z ivanov $ +/* $Id: build_db.hpp 514136 2016-09-19 19:11:12Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/blast/seqdb_writer/impl/criteria.hpp b/c++/include/objtools/blast/seqdb_writer/impl/criteria.hpp index 08c1b8a0..91abadc5 100644 --- a/c++/include/objtools/blast/seqdb_writer/impl/criteria.hpp +++ b/c++/include/objtools/blast/seqdb_writer/impl/criteria.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_BLAST_SEQDB_WRITER_IMPL___CRITERIA__HPP #define OBJTOOLS_BLAST_SEQDB_WRITER_IMPL___CRITERIA__HPP -/* $Id: criteria.hpp 513036 2016-09-06 19:42:13Z fukanchi $ +/* $Id: criteria.hpp 512590 2016-09-01 14:57:04Z rackerst $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/blast/seqdb_writer/writedb.hpp b/c++/include/objtools/blast/seqdb_writer/writedb.hpp index 2ed03ec4..de39adaf 100644 --- a/c++/include/objtools/blast/seqdb_writer/writedb.hpp +++ b/c++/include/objtools/blast/seqdb_writer/writedb.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_BLAST_SEQDB_WRITER___WRITEDB__HPP #define OBJTOOLS_BLAST_SEQDB_WRITER___WRITEDB__HPP -/* $Id: writedb.hpp 513849 2016-09-15 17:36:45Z ivanov $ +/* $Id: writedb.hpp 513693 2016-09-14 15:53:17Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/blast/seqdb_writer/writedb_files.hpp b/c++/include/objtools/blast/seqdb_writer/writedb_files.hpp index a7a0e804..a9a2535d 100644 --- a/c++/include/objtools/blast/seqdb_writer/writedb_files.hpp +++ b/c++/include/objtools/blast/seqdb_writer/writedb_files.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_WRITERS_WRITEDB__WRITEDB_FILES_HPP #define OBJTOOLS_WRITERS_WRITEDB__WRITEDB_FILES_HPP -/* $Id: writedb_files.hpp 446657 2014-09-17 14:26:27Z rackerst $ +/* $Id: writedb_files.hpp 539178 2017-06-19 17:07:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -422,7 +422,9 @@ public: int & offset, int length) { +#ifdef _DEBUG _ASSERT(m_Protein); +#endif offset = WriteWithNull(sequence); m_Letters += length; } @@ -442,7 +444,9 @@ public: int & off_amb, int length) { +#ifdef _DEBUG _ASSERT(! m_Protein); +#endif off_seq = Write(sequence); off_amb = Write(ambig); m_Letters += length; @@ -458,7 +462,9 @@ private: Uint8 m_Letters; ///< Letters of sequence data added so far. Uint8 m_BaseLimit; ///< Limit on letters of sequence data. +#ifdef _DEBUG bool m_Protein; ///< True if this is a protein database. +#endif }; END_NCBI_SCOPE diff --git a/c++/include/objtools/cleanup/cleanup.hpp b/c++/include/objtools/cleanup/cleanup.hpp index 1c98ebd0..34c78951 100644 --- a/c++/include/objtools/cleanup/cleanup.hpp +++ b/c++/include/objtools/cleanup/cleanup.hpp @@ -1,7 +1,7 @@ #ifndef CLEANUP___CLEANUP__HPP #define CLEANUP___CLEANUP__HPP -/* $Id: cleanup.hpp 520817 2016-12-01 18:50:34Z ivanov $ +/* $Id: cleanup.hpp 541349 2017-07-17 16:05:30Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -224,6 +224,12 @@ public: /// @return Boolean return value indicates whether the feature was extended static bool ExtendToStopIfShortAndNotPartial(CSeq_feat& f, CBioseq_Handle bsh, bool check_for_stop = true); +/// Checks whether it is possible to extend the original location up to improved one. It is possible only if +/// the original location is less than improved +/// @param orig Seq-loc to check +/// @param improved Seq-loc original location may be extended to +/// @return Boolean return value indicates whether the extention is possible + static bool LocationMayBeExtendedToMatch(const CSeq_loc& orig, const CSeq_loc& improved); /// Extends a feature up to limit nt to a stop codon, or to the end of the sequence /// if limit == 0 (partial will be set if location extends to end of sequence but @@ -347,11 +353,24 @@ public: /// @return Boolean indicates whether anything changed static bool RemovePseudoProduct(CSeq_feat& cds, CScope& scope); +/// Expands gene to include features it cross-references +/// @param gene Seq-feat to adjust +/// @param tse Top-level Seq-entry in which to find other features +/// @return Boolean indicates whether anything changed + static bool ExpandGeneToIncludeChildren(CSeq_feat& gene, CTSE_Handle& tse); + /// Performs WGS specific cleanup /// @param entry Seq-entry to edit /// @return Boolean return value indicates whether object was updated static bool WGSCleanup(CSeq_entry_Handle entry); +/// For table2asn -c s +/// Adds an exception of "low-quality sequence region" to coding regions +/// and mRNAs that are not pseudo and have an intron <11bp in length +/// @param entry Seq-entry to edit +/// @return Boolean return value indicates whether object was updated + static bool AddLowQualityException(CSeq_entry_Handle entry); + /// Normalize Descriptor Order on a specific Seq-entry /// @param entry Seq-entry to edit /// @return Boolean return value indicates whether object was updated @@ -468,6 +487,31 @@ public: static bool ConvertDeltaSeqToRaw(CSeq_entry_Handle seh, CSeq_inst::EMol filter = CSeq_inst::eMol_not_set); +/// Parse string into code break and add to coding region. +/// @param feat feature that contains coding region - necessary to determine codon boundaries +/// @param cds coding region to which code breaks will be added +/// @param str string from which to parse code break +/// @param scope scope in which to find sequences referenced (used for location comparisons) +/// @return bool indicates string was successfully parsed and code break was added + static bool ParseCodeBreak(const CSeq_feat& feat, CCdregion& cds, const string& str, CScope& scope); + +/// Parses all valid transl_except Gb-quals into code-breaks for cdregion, +/// then removes the transl_except Gb-quals that were successfully parsed +/// @param feat feature that contains coding region +/// @param scope scope in which to find sequences referenced (used for location comparisons) +/// @return bool indicates changes were made + static bool ParseCodeBreaks(CSeq_feat& feat, CScope& scope); + + static size_t MakeSmallGenomeSet(CSeq_entry_Handle entry); + +/// From SQD-4329 +/// For each sequence with a source that has an IRD db_xref, create a misc_feature +/// across the entire span and move the IRD db_xref from the source to the misc_feature. +/// Create a suppressing gene xref for the misc_feature. +/// @param entry Seq-entry on which to search for sources and create features +/// @return bool indicates changes were made + static bool MakeIRDFeatsFromSourceXrefs(CSeq_entry_Handle entry); + private: // Prohibit copy constructor & assignment operator CCleanup(const CCleanup&); @@ -478,6 +522,9 @@ private: static bool x_MergeDupOrgNames(COrgName& on1, const COrgName& add); static bool x_MergeDupOrgRefs(COrg_ref& org1, const COrg_ref& add); + static bool x_HasShortIntron(const CSeq_loc& loc, size_t min_len = 11); + static bool x_AddLowQualityException(CSeq_feat& feat); + static bool x_AddLowQualityException(CSeq_entry_Handle entry, CSeqFeatData::ESubtype subtype); }; diff --git a/c++/include/objtools/cleanup/cleanup_change.hpp b/c++/include/objtools/cleanup/cleanup_change.hpp index bb50adc5..e3fe1289 100644 --- a/c++/include/objtools/cleanup/cleanup_change.hpp +++ b/c++/include/objtools/cleanup/cleanup_change.hpp @@ -1,7 +1,7 @@ #ifndef CLEANUP___CLEANUP_CHANGE__HPP #define CLEANUP___CLEANUP_CHANGE__HPP -/* $Id: cleanup_change.hpp 518386 2016-11-02 17:27:13Z ivanov $ +/* $Id: cleanup_change.hpp 544986 2017-08-30 14:29:22Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -160,6 +160,7 @@ public: eCleanOrgref, eTrimInternalSemicolons, eAddSeqFeatXref, + eConvertUnstructuredOrgrefModifier, // set when any other change is made. eChangeOther, diff --git a/c++/include/objtools/cleanup/newcleanup.hpp b/c++/include/objtools/cleanup/newcleanup.hpp index 8292bd1c..5f94a97c 100755 --- a/c++/include/objtools/cleanup/newcleanup.hpp +++ b/c++/include/objtools/cleanup/newcleanup.hpp @@ -36,6 +36,7 @@ #include #include +#include #include @@ -253,7 +254,6 @@ private: EAction x_GeneGBQualBC( CGene_ref& gene, const CGb_qual& gb_qual ); EAction x_SeqFeatCDSGBQualBC(CSeq_feat& feat, CCdregion& cds, const CGb_qual& gb_qual); EAction x_SeqFeatRnaGBQualBC(CSeq_feat& feat, CRNA_ref& rna, CGb_qual& gb_qual); - EAction x_ParseCodeBreak(const CSeq_feat& feat, CCdregion& cds, const string& str); EAction x_ProtGBQualBC(CProt_ref& prot, const CGb_qual& gb_qual, EGBQualOpt opt ); // publication-related cleanup diff --git a/c++/include/objtools/data_loaders/blastdb/blastdb_adapter.hpp b/c++/include/objtools/data_loaders/blastdb/blastdb_adapter.hpp index aad87b63..4e5c077e 100644 --- a/c++/include/objtools/data_loaders/blastdb/blastdb_adapter.hpp +++ b/c++/include/objtools/data_loaders/blastdb/blastdb_adapter.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_DATA_LOADERS_BLASTDB___BLASTDB_ADAPTER__HPP #define OBJTOOLS_DATA_LOADERS_BLASTDB___BLASTDB_ADAPTER__HPP -/* $Id: blastdb_adapter.hpp 468783 2015-05-28 13:00:08Z vasilche $ +/* $Id: blastdb_adapter.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -128,7 +128,7 @@ public: /// Retrieve the taxonomy ID for the requested sequence identifier /// @param idh The Seq-id for which to get the taxonomy ID /// @return taxonomy ID if found, otherwise kInvalidSeqPos - virtual int GetTaxId(const CSeq_id_Handle& idh) { + virtual int GetTaxId(const CSeq_id_Handle& /*idh*/) { return static_cast(kInvalidSeqPos); } }; diff --git a/c++/include/objtools/data_loaders/genbank/gbloader.hpp b/c++/include/objtools/data_loaders/genbank/gbloader.hpp index 626bbfa1..bd5c5ba6 100644 --- a/c++/include/objtools/data_loaders/genbank/gbloader.hpp +++ b/c++/include/objtools/data_loaders/genbank/gbloader.hpp @@ -1,7 +1,7 @@ #ifndef GBLOADER__HPP_INCLUDED #define GBLOADER__HPP_INCLUDED -/* $Id: gbloader.hpp 493171 2016-02-24 19:31:13Z vasilche $ +/* $Id: gbloader.hpp 534579 2017-04-28 20:53:10Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -165,12 +165,21 @@ public: { return m_Preopen; } + void SetHUPIncluded(bool include_hup = true) + { + m_HasHUPIncluded = include_hup; + } + bool HasHUPIncluded(void) const + { + return m_HasHUPIncluded; + } private: string m_ReaderName; CRef m_ReaderPtr; const TParamTree* m_ParamTree; EPreopenConnection m_Preopen; + bool m_HasHUPIncluded; }; class NCBI_XLOADER_GENBANK_EXPORT CGBDataLoader : public CDataLoader @@ -245,6 +254,11 @@ public: CObjectManager::TPriority priority = CObjectManager::kPriority_NotSet); static string GetLoaderNameFromArgs(CReader* reader = 0); + // enum to include HUP data + enum EIncludeHUP { + eIncludeHUP + }; + // Select reader by name. If failed, select default reader. // Reader name may be the same as in environment: PUBSEQOS, ID1 etc. // Several names may be separated with ":". Empty name or "*" @@ -257,6 +271,29 @@ public: CObjectManager::TPriority priority = CObjectManager::kPriority_NotSet); static string GetLoaderNameFromArgs(const string& reader_name); + // GBLoader with HUP data included. + // The reader will be chosed from default configuration, + // either pubseqos or pubseqos2. + // The default loader priority will be slightly lower than for main data. + static TRegisterLoaderInfo RegisterInObjectManager( + CObjectManager& om, + EIncludeHUP include_hup, + CObjectManager::EIsDefault is_default = CObjectManager::eNonDefault, + CObjectManager::TPriority priority = CObjectManager::kPriority_NotSet); + static string GetLoaderNameFromArgs(EIncludeHUP include_hup); + + // GBLoader with HUP data included. + // The reader can be either pubseqos or pubseqos2. + // The default loader priority will be slightly lower than for main data. + static TRegisterLoaderInfo RegisterInObjectManager( + CObjectManager& om, + const string& reader_name, // pubseqos or pubseqos2 + EIncludeHUP include_hup, + CObjectManager::EIsDefault is_default = CObjectManager::eNonDefault, + CObjectManager::TPriority priority = CObjectManager::kPriority_NotSet); + static string GetLoaderNameFromArgs(const string& reader_name, // pubseqos or pubseqos2 + EIncludeHUP include_hup); + // Setup loader using param tree. If tree is null or failed to find params, // use environment or select default reader. typedef TPluginManagerParamTree TParamTree; @@ -377,6 +414,13 @@ public: m_AddWGSMasterDescr = flag; } + bool HasHUPIncluded(void) const + { + return m_HasHUPIncluded; + } + + virtual CObjectManager::TPriority GetDefaultPriority(void) const; + protected: friend class CGBReaderRequestResult; @@ -412,6 +456,7 @@ private: bool m_AlwaysLoadExternal; bool m_AlwaysLoadNamedAcc; bool m_AddWGSMasterDescr; + bool m_HasHUPIncluded; // // private code @@ -419,8 +464,7 @@ private: void x_CreateDriver(const CGBLoaderParams& params); - string GetReaderName(const TParamTree* params) const; - string GetWriterName(const TParamTree* params) const; + pair GetReaderWriterName(const TParamTree* params) const; bool x_CreateReaders(const string& str, const TParamTree* params, CGBLoaderParams::EPreopenConnection preopen); diff --git a/c++/include/objtools/data_loaders/genbank/impl/reader_id2_base.hpp b/c++/include/objtools/data_loaders/genbank/impl/reader_id2_base.hpp index 2aa511aa..54cf9fea 100644 --- a/c++/include/objtools/data_loaders/genbank/impl/reader_id2_base.hpp +++ b/c++/include/objtools/data_loaders/genbank/impl/reader_id2_base.hpp @@ -1,7 +1,7 @@ #ifndef READER_ID2_BASE__HPP_INCLUDED #define READER_ID2_BASE__HPP_INCLUDED -/* $Id: reader_id2_base.hpp 504899 2016-06-20 17:49:29Z vasilche $ +/* $Id: reader_id2_base.hpp 529981 2017-03-09 16:30:29Z vasilche $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information @@ -65,11 +65,13 @@ class CID2S_Reply_Get_Chunk; class CID2S_Chunk_Id; class CID2S_Chunk; class CID2Processor; +class CID2ProcessorContext; class CId2ReaderProcessorResolver; class CReaderRequestResult; struct SId2LoadedSet; struct SId2PacketInfo; struct SId2PacketReplies; +struct SId2ProcessingState; class NCBI_XREADER_EXPORT CId2ReaderBase : public CReader { @@ -253,11 +255,16 @@ protected: friend class CId2ReaderProcessorResolver; - void x_DumpPacket(TConn conn, const CID2_Request_Packet& packet); - void x_DumpReply(TConn conn, const char* source, CID2_Reply& reply); + void x_DumpPacket(TConn conn, const CID2_Request_Packet& packet, const char* msg = "Sending"); + void x_DumpReply(TConn conn, CID2_Reply& reply, const char* msg = "Received"); void x_SetContextData(CID2_Request& request); void x_SendToConnection(TConn conn, CID2_Request_Packet& packet); + void x_SendID2Packet(CReaderRequestResult& result, + SId2ProcessingState& state, + CID2_Request_Packet& packet); CRef x_ReceiveFromConnection(TConn conn); + CRef x_ReceiveID2ReplyStage(SId2ProcessingState& state, size_t pos); + CRef x_ReceiveID2Reply(SId2ProcessingState& state); void x_AssignSerialNumbers(SId2PacketInfo& info, CID2_Request_Packet& packet); int x_GetReplyIndex(CReaderRequestResult& result, @@ -268,10 +275,6 @@ protected: int num, const CID2_Reply& reply); - void x_GetPacketReplies(CReaderRequestResult& result, - SId2PacketReplies& replies, - CID2_Request_Packet& packet); - private: CAtomicCounter_WithAutoInit m_RequestSerialNumber; @@ -286,7 +289,11 @@ private: typedef int TAvoidRequests; TAvoidRequests m_AvoidRequest; - typedef vector< CRef > TProcessors; + struct SProcessorInfo { + CRef processor; + CRef context; + }; + typedef vector TProcessors; TProcessors m_Processors; }; diff --git a/c++/include/objtools/data_loaders/genbank/reader.hpp b/c++/include/objtools/data_loaders/genbank/reader.hpp index 11949e80..dbd902aa 100644 --- a/c++/include/objtools/data_loaders/genbank/reader.hpp +++ b/c++/include/objtools/data_loaders/genbank/reader.hpp @@ -1,6 +1,6 @@ #ifndef READER__HPP_INCLUDED #define READER__HPP_INCLUDED -/* $Id: reader.hpp 493171 2016-02-24 19:31:13Z vasilche $ +/* $Id: reader.hpp 534193 2017-04-25 14:00:21Z vasilche $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information @@ -271,6 +271,8 @@ public: virtual void ConnectSucceeds(TConn conn); virtual void ConnectFailed(TConn conn); virtual void SetNewConnectionDelayMicroSec(unsigned long micro_sec); + + virtual void SetIncludeHUP(bool include_hup = true); class NCBI_XREADER_EXPORT CDebugPrinter : public CNcbiOstrstream { diff --git a/c++/include/objtools/data_loaders/genbank/reader_interface.hpp b/c++/include/objtools/data_loaders/genbank/reader_interface.hpp index 61579eb3..270968cc 100644 --- a/c++/include/objtools/data_loaders/genbank/reader_interface.hpp +++ b/c++/include/objtools/data_loaders/genbank/reader_interface.hpp @@ -1,6 +1,6 @@ #ifndef READER_INTERFACE__HPP_INCLUDED #define READER_INTERFACE__HPP_INCLUDED -/* $Id: reader_interface.hpp 493171 2016-02-24 19:31:13Z vasilche $ +/* $Id: reader_interface.hpp 534193 2017-04-25 14:00:21Z vasilche $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information @@ -38,7 +38,7 @@ class CReader; END_SCOPE(objects) -NCBI_DECLARE_INTERFACE_VERSION(objects::CReader, "xreader", 6, 1, 0); +NCBI_DECLARE_INTERFACE_VERSION(objects::CReader, "xreader", 7, 0, 0); template<> class CDllResolver_Getter diff --git a/c++/include/objtools/data_loaders/genbank/readers/id2/reader_id2.hpp b/c++/include/objtools/data_loaders/genbank/readers/id2/reader_id2.hpp index ccbefff4..1458491a 100644 --- a/c++/include/objtools/data_loaders/genbank/readers/id2/reader_id2.hpp +++ b/c++/include/objtools/data_loaders/genbank/readers/id2/reader_id2.hpp @@ -1,7 +1,7 @@ #if defined __GNUG__ # warning This file is deprecated and will be removed soon. \ Please, update the include directive to: \ - #include + #include #endif #include diff --git a/c++/include/objtools/edit/autodef.hpp b/c++/include/objtools/edit/autodef.hpp index 1fd07d69..90ecd379 100644 --- a/c++/include/objtools/edit/autodef.hpp +++ b/c++/include/objtools/edit/autodef.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_EDIT___AUTODEF__HPP #define OBJTOOLS_EDIT___AUTODEF__HPP -/* $Id: autodef.hpp 510717 2016-08-15 17:12:40Z ivanov $ +/* $Id: autodef.hpp 530276 2017-03-13 18:20:08Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -29,316 +29,10 @@ * Author: Colleen Bollin * * File Description: -* Creates unique definition lines for sequences in a set using organism -* descriptions and feature clauses. +* Extends CAutodef to include docsum titles (which require a call to taxonomy) */ #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -BEGIN_NCBI_SCOPE -BEGIN_SCOPE(objects) - -class NCBI_XOBJEDIT_EXPORT CAutoDef -{ -public: - - typedef set TAvailableModifierSet; - - CAutoDef(); - ~CAutoDef(); - - void AddSources(CSeq_entry_Handle se); - void AddSources(CBioseq_Handle bh); - CAutoDefModifierCombo* FindBestModifierCombo(); - CAutoDefModifierCombo* GetAllModifierCombo(); - CAutoDefModifierCombo* GetEmptyCombo(); - unsigned int GetNumAvailableModifiers(); - string GetOneSourceDescription(CBioseq_Handle bh); - string GetOneFeatureClauseList(CBioseq_Handle bh, unsigned int genome_val); - string GetOneDefLine(CAutoDefModifierCombo* mod_combo, CBioseq_Handle bh); - string GetOneDefLine(CBioseq_Handle bh); - static string GetDocsumOrgDescription(CSeq_entry_Handle se); - string GetDocsumDefLine(CSeq_entry_Handle se); - static bool NeedsDocsumDefline(const CBioseq_set& set); - - static bool RegenerateDefLines(CSeq_entry_Handle se); - - void SetOptionsObject(const CUser_object& user); - CRef GetOptionsObject() const { return m_Options.MakeUserObject(); } - - void SetFeatureListType(CAutoDefOptions::EFeatureListType feature_list_type); - void SetMiscFeatRule(CAutoDefOptions::EMiscFeatRule misc_feat_rule); - void SetProductFlag(CBioSource::EGenome product_flag); - void SetNuclearCopyFlag(CBioSource::EGenome product_flag); - void SetSpecifyNuclearProduct (bool specify_nuclear_product); - void SetAltSpliceFlag (bool alt_splice_flag); - void SetSuppressLocusTags(bool suppress_locus_tags); - void SetSuppressAllele(bool suppress_allele); - void SetGeneClusterOppStrand(bool gene_opp_strand); - void SetSuppressFeatureAltSplice (bool suppress_alt_splice); - void SuppressMobileElementAndInsertionSequenceSubfeatures(bool suppress); - void SuppressMiscFeatSubfeatures(bool suppress); - void SetKeepExons(bool keep); - void SetKeepIntrons(bool keep); - void SetKeepRegulatoryFeatures(bool keep); - void SetKeepLTRs(bool keep); - void SetKeep3UTRs(bool keep); - void SetKeep5UTRs(bool keep); - void SetKeepuORFs(bool keep); - void SetKeepOptionalMobileElements(bool keep); - void SetKeepPrecursorRNA(bool keep); - void SetKeepRepeatRegion(bool keep); - void SetKeepMiscRecomb(bool keep); - void SetUseNcRNAComment (bool use_comment); - void SetUseFakePromoters (bool use_fake); - void SetCustomFeatureClause(const string& custom_feature_clause); - - void SuppressFeature(objects::CFeatListItem feat); - void SuppressFeature(objects::CSeqFeatData::ESubtype subtype); - - typedef vector TModifierComboVector; - - void GetAvailableModifiers(TAvailableModifierSet &mod_set); - - void Cancel() { m_Cancelled = true; } - bool Cancelled() { return m_Cancelled; } - - static string GetKeywordPrefix(CBioseq_Handle bh); - -private: - typedef vector TModifierIndexVector; - typedef vector TSeqEntryHandleVector; - - CAutoDefModifierCombo m_OrigModCombo; - - CAutoDefOptions m_Options; - - // feature clause specifications - bool m_Cancelled; - - void x_SortModifierListByRank - (TModifierIndexVector& index_list, - CAutoDefSourceDescription::TAvailableModifierVector& modifier_list); - void x_GetModifierIndexList - (TModifierIndexVector& index_list, - CAutoDefSourceDescription::TAvailableModifierVector& modifier_list); - - string x_GetNonFeatureListEnding(); - string x_GetFeatureClauses(CBioseq_Handle bh); - string x_GetFeatureClauseProductEnding(const string& feature_clauses, - CBioseq_Handle bh); - bool x_AddMiscRNAFeatures(CBioseq_Handle bh, - const CSeq_feat& cf, - const CSeq_loc& mapped_loc, - CAutoDefFeatureClause_Base& main_clause); - bool x_AddtRNAAndOther(CBioseq_Handle bh, - const CSeq_feat& cf, - const CSeq_loc& mapped_loc, - CAutoDefFeatureClause_Base& main_clause); - - void x_RemoveOptionalFeatures(CAutoDefFeatureClause_Base *main_clause, CBioseq_Handle bh); - - - bool x_IsOrgModRequired(unsigned int mod_type); - bool x_IsSubSrcRequired(unsigned int mod_type); - - bool x_IsFeatureSuppressed(CSeqFeatData::ESubtype subtype); - - void GetMasterLocation(CBioseq_Handle &bh, CRange& range); - bool IsSegment(CBioseq_Handle bh); - bool x_Is5SList(CFeat_CI feat_ci); - -}; // end of CAutoDef - - -inline -void CAutoDef::SetFeatureListType(CAutoDefOptions::EFeatureListType feature_list_type) -{ - m_Options.SetFeatureListType(feature_list_type); -} - - -inline -void CAutoDef::SetMiscFeatRule(CAutoDefOptions::EMiscFeatRule misc_feat_rule) -{ - m_Options.SetMiscFeatRule(misc_feat_rule); -} - - -inline -void CAutoDef::SetProductFlag(CBioSource::EGenome product_flag) -{ - m_Options.SetProductFlag(product_flag); -} - - -inline -void CAutoDef::SetNuclearCopyFlag(CBioSource::EGenome product_flag) -{ - m_Options.SetNuclearCopyFlag(product_flag); -} - - -inline -void CAutoDef::SetSpecifyNuclearProduct (bool specify_nuclear_product) -{ - m_Options.SetSpecifyNuclearProduct(specify_nuclear_product); -} - - -inline -void CAutoDef::SetAltSpliceFlag (bool alt_splice_flag) -{ - m_Options.SetAltSpliceFlag(alt_splice_flag); -} - - -inline -void CAutoDef::SetSuppressLocusTags (bool suppress_locus_tags) -{ - m_Options.SetSuppressLocusTags(suppress_locus_tags); -} - - -inline -void CAutoDef::SetGeneClusterOppStrand (bool gene_opp_strand) -{ - m_Options.SetGeneClusterOppStrand(gene_opp_strand); -} - - -inline -void CAutoDef::SetSuppressFeatureAltSplice (bool suppress_alt_splice) -{ - m_Options.SetSuppressFeatureAltSplice(suppress_alt_splice); -} - - -inline -void CAutoDef::SuppressMobileElementAndInsertionSequenceSubfeatures(bool suppress) -{ - m_Options.SetSuppressMobileElementSubfeatures(suppress); -} - - -inline -void CAutoDef::SuppressMiscFeatSubfeatures(bool suppress) -{ - m_Options.SetSuppressMiscFeatureSubfeatures(suppress); -} - - -inline -void CAutoDef::SetKeepExons(bool keep) -{ - m_Options.SetKeepExons(keep); -} - - -inline -void CAutoDef::SetKeepIntrons(bool keep) -{ - m_Options.SetKeepIntrons(keep); -} - - -inline -void CAutoDef::SetKeepRegulatoryFeatures(bool keep) -{ - m_Options.SetKeepRegulatoryFeatures(keep); -} - -inline -void CAutoDef::SetKeepLTRs(bool keep) -{ - m_Options.SetKeepLTRs(keep); -} - - -inline -void CAutoDef::SetKeep3UTRs(bool keep) -{ - m_Options.SetKeep3UTRs(keep); -} - - -inline -void CAutoDef::SetKeep5UTRs(bool keep) -{ - m_Options.SetKeep5UTRs(keep); -} - - -inline -void CAutoDef::SetKeepuORFs(bool keep) -{ - m_Options.SetKeepuORFs(keep); -} - - -inline -void CAutoDef::SetKeepOptionalMobileElements(bool keep) -{ - m_Options.SetKeepMobileElements(keep); -} - -inline -void CAutoDef::SetKeepPrecursorRNA(bool keep) -{ - m_Options.SetKeepPrecursorRNA(keep); -} - -inline -void CAutoDef::SetKeepRepeatRegion(bool keep) -{ - m_Options.SetKeepRepeatRegion(keep); -} - -inline -void CAutoDef::SetKeepMiscRecomb(bool keep) -{ - m_Options.SetKeepMiscRecomb(keep); -} - -inline -void CAutoDef::SetUseNcRNAComment(bool use_comment) -{ - m_Options.SetUseNcRNAComment(use_comment); -} - - -inline -void CAutoDef::SetUseFakePromoters(bool use_fake) -{ - m_Options.SetUseFakePromoters(use_fake); -} - - -inline -void CAutoDef::SetCustomFeatureClause(const string& custom_feature_clause) -{ - m_Options.SetCustomFeatureClause(custom_feature_clause); -} - -END_SCOPE(objects) -END_NCBI_SCOPE +#include #endif //OBJTOOLS_EDIT___AUTODEF__HPP diff --git a/c++/include/objtools/edit/autodef_options.hpp b/c++/include/objtools/edit/autodef_options.hpp index ddd1f09e..8aa87cd3 100644 --- a/c++/include/objtools/edit/autodef_options.hpp +++ b/c++/include/objtools/edit/autodef_options.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_EDIT___AUTODEF_OPTIONS__HPP #define OBJTOOLS_EDIT___AUTODEF_OPTIONS__HPP -/* $Id: autodef_options.hpp 510717 2016-08-15 17:12:40Z ivanov $ +/* $Id: autodef_options.hpp 530273 2017-03-13 17:31:44Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -29,263 +29,10 @@ * Author: Colleen Bollin * * File Description: -* Creates unique definition lines for sequences in a set using organism -* descriptions and feature clauses. +* Extends CAutodef to include docsum titles (which require a call to taxonomy) */ #include -#include -#include -#include -#include -#include -#include - -BEGIN_NCBI_SCOPE -BEGIN_SCOPE(objects) - -class NCBI_XOBJEDIT_EXPORT CAutoDefOptions -{ -public: - CAutoDefOptions(); - ~CAutoDefOptions() {} - - CRef MakeUserObject() const; - void InitFromUserObject(const CUser_object& obj); - - enum EOptionFieldType { - eOptionFieldType_Unknown = 0, - eOptionFieldType_MaxMods, - eOptionFieldType_UseLabels, - eOptionFieldType_AllowModAtEndOfTaxname, - eOptionFieldType_LeaveParenthetical, - eOptionFieldType_DoNotApplyToSp, - eOptionFieldType_DoNotApplyToNr, - eOptionFieldType_DoNotApplyToCf, - eOptionFieldType_DoNotApplyToAff, - eOptionFieldType_IncludeCountryText, - eOptionFieldType_KeepAfterSemicolon, - eOptionFieldType_HIVRule, - eOptionFieldType_FeatureListType, - eOptionFieldType_MiscFeatRule, - eOptionFieldType_ProductFlag, - eOptionFieldType_NuclearCopyFlag, - eOptionFieldType_SpecifyNuclearProduct, - eOptionFieldType_AltSpliceFlag, - eOptionFieldType_SuppressLocusTags, - eOptionFieldType_SuppressAlleles, - eOptionFieldType_GeneClusterOppStrand, - eOptionFieldType_SuppressFeatureAltSplice, - eOptionFieldType_SuppressMobileElementSubfeatures, - eOptionFieldType_KeepExons, - eOptionFieldType_KeepIntrons, - eOptionFieldType_UseFakePromoters, - eOptionFieldType_KeepRegulatoryFeatures, - eOptionFieldType_KeepLTRs, - eOptionFieldType_Keep3UTRs, - eOptionFieldType_Keep5UTRs, - eOptionFieldType_KeepuORFs, - eOptionFieldType_KeepMobileElements, - eOptionFieldType_KeepPrecursorRNA, - eOptionFieldType_KeepRepeatRegion, - eOptionFieldType_KeepMiscRecomb, - eOptionFieldType_UseNcRNAComment, - eOptionFieldType_SuppressedFeatures, - eOptionFieldType_ModifierList, - eOptionFieldType_TargetedLocusName, - eOptionFieldType_SuppressMiscFeatureSubfeatures, - eOptionFieldType_CustomFeatureClause, - eOptionFieldMax - }; - - enum EFeatureListType { - eListAllFeatures = 0, - eCompleteSequence, - eCompleteGenome, - ePartialSequence, - ePartialGenome, - eSequence - }; - - typedef unsigned int TFeatureListType; - TFeatureListType GetFeatureListType() const { return m_FeatureListType; } - void SetFeatureListType(EFeatureListType list_type) { m_FeatureListType = list_type; } - - enum EMiscFeatRule { - eDelete = 0, - eNoncodingProductFeat, - eCommentFeat - }; - - typedef unsigned int TMiscFeatRule; - TMiscFeatRule GetMiscFeatRule() const { return m_MiscFeatRule; } - void SetMiscFeatRule(TMiscFeatRule rule) { m_MiscFeatRule = rule; } - - enum EHIVCloneIsolateRule { - ePreferClone = 0, - ePreferIsolate, - eWantBoth - }; - typedef unsigned int THIVRule; - THIVRule GetHIVRule() const { return m_HIVRule; } - void SetHIVRule(EHIVCloneIsolateRule rule) { m_HIVRule = rule; } - - bool GetUseFakePromoters() const { return m_BooleanFlags[eOptionFieldType_UseFakePromoters]; } - void SetUseFakePromoters(bool val = true) { - m_BooleanFlags[eOptionFieldType_UseFakePromoters] = val; - } - - CBioSource::TGenome GetProductFlag() const { return m_ProductFlag; }; - void SetProductFlag(CBioSource::EGenome val) { - m_ProductFlag = val; - m_BooleanFlags[eOptionFieldType_SpecifyNuclearProduct] = false; - m_NuclearCopyFlag = CBioSource::eGenome_unknown; - } - - CBioSource::TGenome GetNuclearCopyFlag() const { return m_NuclearCopyFlag; }; - void SetNuclearCopyFlag(CBioSource::EGenome val) { - m_NuclearCopyFlag = val; - m_BooleanFlags[eOptionFieldType_SpecifyNuclearProduct] = false; - m_ProductFlag = CBioSource::eGenome_unknown; - } - - bool GetSpecifyNuclearProduct() const { return m_BooleanFlags[eOptionFieldType_SpecifyNuclearProduct]; } - void SetSpecifyNuclearProduct(bool val) { - m_BooleanFlags[eOptionFieldType_SpecifyNuclearProduct] = val; - if (val) { - m_ProductFlag = CBioSource::eGenome_unknown; - m_NuclearCopyFlag = CBioSource::eGenome_unknown; - } - } - - int GetMaxMods() const { return m_MaxMods; } - void SetMaxMods(int val) { m_MaxMods = val; } - -#define AUTODEFBOOLFIELD(Fieldname) \ - bool Get##Fieldname() const { return m_BooleanFlags[eOptionFieldType_##Fieldname]; }; \ - void Set##Fieldname(bool val = true) { m_BooleanFlags[eOptionFieldType_##Fieldname] = val; } - - AUTODEFBOOLFIELD(UseLabels) - AUTODEFBOOLFIELD(LeaveParenthetical) - AUTODEFBOOLFIELD(AllowModAtEndOfTaxname) - AUTODEFBOOLFIELD(DoNotApplyToSp) - AUTODEFBOOLFIELD(DoNotApplyToNr) - AUTODEFBOOLFIELD(DoNotApplyToCf) - AUTODEFBOOLFIELD(DoNotApplyToAff) - AUTODEFBOOLFIELD(IncludeCountryText) - AUTODEFBOOLFIELD(KeepAfterSemicolon) - AUTODEFBOOLFIELD(AltSpliceFlag) - AUTODEFBOOLFIELD(SuppressLocusTags) - AUTODEFBOOLFIELD(SuppressAlleles) - AUTODEFBOOLFIELD(GeneClusterOppStrand) - AUTODEFBOOLFIELD(SuppressFeatureAltSplice) - AUTODEFBOOLFIELD(SuppressMobileElementSubfeatures) - AUTODEFBOOLFIELD(KeepExons) - AUTODEFBOOLFIELD(KeepIntrons) - AUTODEFBOOLFIELD(KeepRegulatoryFeatures) - AUTODEFBOOLFIELD(KeepLTRs) - AUTODEFBOOLFIELD(Keep3UTRs) - AUTODEFBOOLFIELD(Keep5UTRs) - AUTODEFBOOLFIELD(KeepuORFs) - AUTODEFBOOLFIELD(KeepMobileElements) - AUTODEFBOOLFIELD(KeepPrecursorRNA) - AUTODEFBOOLFIELD(KeepRepeatRegion) - AUTODEFBOOLFIELD(KeepMiscRecomb) - AUTODEFBOOLFIELD(UseNcRNAComment) - AUTODEFBOOLFIELD(SuppressMiscFeatureSubfeatures) - - bool IsFeatureSuppressed(CSeqFeatData::ESubtype subtype) const; - bool AreAnyFeaturesSuppressed() const { return !m_SuppressedFeatureSubtypes.empty(); } - void SuppressFeature(CSeqFeatData::ESubtype subtype); - void SuppressAllFeatures(); - void ClearSuppressedFeatures(); - - void AddSubSource(CSubSource::TSubtype subtype); - void AddOrgMod(COrgMod::TSubtype subtype); - typedef vector TOrgMods; - const TOrgMods& GetOrgMods() const { return m_OrgMods; } - typedef vector TSubSources; - const TSubSources& GetSubSources() const { return m_SubSources; } - void ClearModifierList(); - - string GetFeatureListType(TFeatureListType list_type) const; - TFeatureListType GetFeatureListType(const string& list_type) const; - - string GetMiscFeatRule(TMiscFeatRule list_type) const; - TMiscFeatRule GetMiscFeatRule(const string& list_type) const; - - string GetHIVRule(TMiscFeatRule list_type) const; - TMiscFeatRule GetHIVRule(const string& list_type) const; - - string GetProductFlag(CBioSource::TGenome value) const; - CBioSource::TGenome GetProductFlag(const string& value) const; - - string GetNuclearCopyFlag(CBioSource::TGenome value) const; - CBioSource::TGenome GetNuclearCopyFlag(const string& value) const; - - string GetTargetedLocusName() const { return m_TargetedLocusName; } - void SetTargetedLocusName(const string& tls) { m_TargetedLocusName = tls; } - - string GetCustomFeatureClause() const { return m_CustomFeatureClause; } - void SetCustomFeatureClause(const string& val) { m_CustomFeatureClause = val; } - -private: - - bool m_BooleanFlags[eOptionFieldMax]; - int m_MaxMods; - THIVRule m_HIVRule; - TFeatureListType m_FeatureListType; - TMiscFeatRule m_MiscFeatRule; - CBioSource::TGenome m_ProductFlag; - CBioSource::TGenome m_NuclearCopyFlag; - typedef vector TSuppressedFeatureSubtypes; - TSuppressedFeatureSubtypes m_SuppressedFeatureSubtypes; - string m_TargetedLocusName; - string m_CustomFeatureClause; - - TOrgMods m_OrgMods; - TSubSources m_SubSources; - - typedef unsigned int TFieldType; - string GetFieldType(TFieldType field_type) const; - TFieldType GetFieldType(const string& field_name) const; - - - - bool x_IsBoolean(TFieldType field_type) const; - CRef x_MakeBooleanField(TFieldType field_type) const; - - void x_MakeSuppressedFeatures(CUser_object& user) const; - void x_SetSuppressedFeatures(const CUser_field& field); - - void x_MakeModifierList(CUser_object& user) const; - void x_SetModifierList(const CUser_field& field); - - - CRef x_MakeMaxMods() const; - CRef x_MakeTargetedLocusName() const; - CRef x_MakeCustomFeatureClause() const; - -#define AUTODEFENUMFIELD(Fieldname) \ - CRef x_Make##Fieldname() const { \ - CRef field(new CUser_field()); \ - field->SetLabel().SetStr(GetFieldType(eOptionFieldType_##Fieldname)); \ - field->SetData().SetStr(Get##Fieldname(m_##Fieldname)); \ - return field; \ - } - - AUTODEFENUMFIELD(FeatureListType) - AUTODEFENUMFIELD(MiscFeatRule) - AUTODEFENUMFIELD(HIVRule) - AUTODEFENUMFIELD(ProductFlag) - AUTODEFENUMFIELD(NuclearCopyFlag) - - void x_Reset(); -}; - - - -END_SCOPE(objects) -END_NCBI_SCOPE +#include #endif //OBJTOOLS_EDIT___AUTODEF_OPTIONS__HPP diff --git a/c++/include/objtools/edit/autodef_source_desc.hpp b/c++/include/objtools/edit/autodef_source_desc.hpp index a5dafed2..05ea27cb 100644 --- a/c++/include/objtools/edit/autodef_source_desc.hpp +++ b/c++/include/objtools/edit/autodef_source_desc.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_EDIT___AUTODEF_SOURCE_DESC__HPP #define OBJTOOLS_EDIT___AUTODEF_SOURCE_DESC__HPP -/* $Id: autodef_source_desc.hpp 387372 2013-01-29 14:57:41Z bollin $ +/* $Id: autodef_source_desc.hpp 530250 2017-03-13 16:22:08Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -29,131 +29,10 @@ * Author: Colleen Bollin * * File Description: -* Creates unique definition lines for sequences in a set using organism -* descriptions and feature clauses. +* Extends CAutodef to include docsum titles (which require a call to taxonomy) */ #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -BEGIN_NCBI_SCOPE -BEGIN_SCOPE(objects) - - -class NCBI_XOBJEDIT_EXPORT CAutoDefSourceModifierInfo -{ -public: - CAutoDefSourceModifierInfo(bool isOrgMod, int subtype, string value); - CAutoDefSourceModifierInfo(const CAutoDefSourceModifierInfo &other); - ~CAutoDefSourceModifierInfo(); - - unsigned int GetRank() const; - int Compare(const CAutoDefSourceModifierInfo& mod) const; - bool IsOrgMod () const; - int GetSubtype () const; - string GetValue () const; - - bool operator>(const CAutoDefSourceModifierInfo& mod) const - { - return Compare (mod) > 0; - } - - bool operator<(const CAutoDefSourceModifierInfo& mod) const - { - return Compare (mod) < 0; - } - - -private: - bool m_IsOrgMod; - int m_Subtype; - string m_Value; -}; - - -inline bool CAutoDefSourceModifierInfo::IsOrgMod() const -{ - return m_IsOrgMod; -} - - -inline int CAutoDefSourceModifierInfo::GetSubtype() const -{ - return m_Subtype; -} - - -inline string CAutoDefSourceModifierInfo::GetValue() const -{ - return m_Value; -} - - -class IAutoDefCombo -{ -public: - virtual ~IAutoDefCombo() { } - virtual string GetSourceDescriptionString(const CBioSource& biosrc) = 0; -}; - - -class NCBI_XOBJEDIT_EXPORT CAutoDefSourceDescription -{ -public: - CAutoDefSourceDescription(const CBioSource& bs, string feature_clauses = ""); - CAutoDefSourceDescription(CAutoDefSourceDescription *other); - ~CAutoDefSourceDescription(); - - typedef vector TStringVector; - typedef vector TAvailableModifierVector; - - const CBioSource& GetBioSource() const; - - void GetAvailableModifiers (TAvailableModifierVector &modifier_list); - - bool IsTrickyHIV(); - - string GetComboDescription(IAutoDefCombo *mod_combo); - - bool AddQual (bool isOrgMod, int subtype, bool keepAfterSemicolon); - bool RemoveQual (bool isOrgMod, int subtype); - int Compare(const CAutoDefSourceDescription& s) const; - bool operator>(const CAutoDefSourceDescription& src) const - { - return Compare (src) > 0; - } - - bool operator<(const CAutoDefSourceDescription& src) const - { - return Compare (src) < 0; - } - - typedef vector TModifierVector; - const TModifierVector& GetModifiers() const { return m_Modifiers; } - typedef list TDescString; - const TDescString& GetStrings() const { return m_DescStrings; } - const string& GetFeatureClauses() const { return m_FeatureClauses; } - -private: - const CBioSource& m_BS; - TModifierVector m_Modifiers; - TDescString m_DescStrings; - string m_FeatureClauses; -}; - - -END_SCOPE(objects) -END_NCBI_SCOPE +#include #endif //OBJTOOLS_EDIT___AUTODEF_SOURCE_DESC__HPP diff --git a/c++/include/objtools/format/gff_gather.hpp b/c++/include/objtools/edit/autodef_with_tax.hpp similarity index 53% rename from c++/include/objtools/format/gff_gather.hpp rename to c++/include/objtools/edit/autodef_with_tax.hpp index e0b04ab6..0cab23e5 100644 --- a/c++/include/objtools/format/gff_gather.hpp +++ b/c++/include/objtools/edit/autodef_with_tax.hpp @@ -1,7 +1,7 @@ -#ifndef OBJTOOLS_FORMAT___GFF_GATHER__HPP -#define OBJTOOLS_FORMAT___GFF_GATHER__HPP +#ifndef OBJTOOLS_EDIT___AUTODEF_WITH_TAX__HPP +#define OBJTOOLS_EDIT___AUTODEF_WITH_TAX__HPP -/* $Id: gff_gather.hpp 431169 2014-04-01 23:33:35Z kans $ +/* $Id: autodef_with_tax.hpp 530196 2017-03-13 12:59:43Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -26,51 +26,34 @@ * * =========================================================================== * -* Author: Aaron Ucko, NCBI -* Mati Shomrat +* Author: Colleen Bollin * * File Description: -* +* Extends CAutodef to include docsum titles (which require a call to taxonomy) */ + #include -#include +#include BEGIN_NCBI_SCOPE -BEGIN_SCOPE(objects) +BEGIN_SCOPE(objects) -//class CBioseq; -// ============================================================================ -class NCBI_FORMAT_EXPORT CGFFGatherer : - public CFlatGatherer -// ============================================================================ +class NCBI_XOBJEDIT_EXPORT CAutoDefWithTaxonomy : public CAutoDef { public: - CGFFGatherer(); - - virtual void Gather( - CFlatFileContext& ctx, - CFlatItemOStream& os ) const; + CAutoDefWithTaxonomy() : CAutoDef() {}; + ~CAutoDefWithTaxonomy() {}; - virtual void x_DoSingleSection( - CBioseqContext& ctx ) const; + static string GetDocsumOrgDescription(CSeq_entry_Handle se); + string GetDocsumDefLine(CSeq_entry_Handle se); + static bool RegeneratePopsetTitles(CSeq_entry_Handle se); + static bool RegenerateDefLines(CSeq_entry_Handle se); -protected: - virtual CFeatureItem* x_NewFeatureItem( - const CMappedFeat& feat, - CBioseqContext& ctx, - const CSeq_loc* loc, - CRef ftree, - CFeatureItem::EMapped mapped = CFeatureItem::eMapped_not_mapped, - CConstRef parentFeatureItem = CConstRef() ) const - { - return new CFeatureItemGff( feat, ctx, loc, ftree, mapped ); - }; - -private: }; + END_SCOPE(objects) END_NCBI_SCOPE -#endif /* OBJTOOLS_FORMAT___GFF_GATHER__HPP */ +#endif //OBJTOOLS_EDIT___AUTODEF_WITH_TAX__HPP diff --git a/c++/include/objtools/edit/feattable_edit.hpp b/c++/include/objtools/edit/feattable_edit.hpp index 914f1b6a..d947647c 100644 --- a/c++/include/objtools/edit/feattable_edit.hpp +++ b/c++/include/objtools/edit/feattable_edit.hpp @@ -1,4 +1,4 @@ -/* $Id: feattable_edit.hpp 503729 2016-06-07 18:22:50Z ludwigf $ +/* $Id: feattable_edit.hpp 546402 2017-09-18 15:03:27Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -55,7 +55,8 @@ public: CFeatTableEdit( CSeq_annot&, const string& = "", - unsigned int = 1, + unsigned int = 1, //starting locus tag + unsigned int = 1, //starting feature id ILineErrorListener* =0); ~CFeatTableEdit(); @@ -77,6 +78,10 @@ public: unsigned int PendingLocusTagNumber() const { return mLocusTagNumber; } + unsigned int PendingFeatureId() const { + return mNextFeatId; + } + protected: void xGenerateLocusIdsUseExisting(); @@ -89,6 +94,9 @@ protected: string xNextTranscriptId( const CMappedFeat&); + void xPutError( + ILineError::EProblem, + const std::string&); void xPutErrorMissingLocustag( CMappedFeat); void xPutErrorMissingTranscriptId( @@ -100,11 +108,32 @@ protected: CMappedFeat, const std::string&, // qual key const std::string&); // qual value - void xFeatureAddProteinId( + void xFeatureRemoveQualifier( + CMappedFeat, // qual key + const std::string&); + void xFeatureSetQualifier( + CMappedFeat, + const std::string&, // qual key + const std::string&); // qual value + + void xFeatureAddProteinIdMrna( + CMappedFeat); + void xFeatureAddProteinIdCds( CMappedFeat); - void xFeatureAddTranscriptId( + void xFeatureAddProteinIdDefault( CMappedFeat); + void xFeatureAddTranscriptIdMrna( + CMappedFeat); + void xFeatureAddTranscriptIdCds( + CMappedFeat); + void xFeatureAddTranscriptIdDefault( + CMappedFeat); + + std::string xGenerateTranscriptOrProteinId( + CMappedFeat, + const std::string&); + CRef xMakeGeneForFeature( const CMappedFeat&); void xGenerateMissingGeneForSubtype( @@ -116,6 +145,11 @@ protected: bool xAdjustExistingParentGene( CMappedFeat); + static std::string xGetIdStr( + CMappedFeat); + std::string xGetCurrentLocusTagPrefix( + CMappedFeat); + CSeq_annot& mAnnot; CRef mpScope; CSeq_annot_Handle mHandle; diff --git a/c++/include/objtools/edit/field_handler.hpp b/c++/include/objtools/edit/field_handler.hpp index 950c1387..d4da276f 100644 --- a/c++/include/objtools/edit/field_handler.hpp +++ b/c++/include/objtools/edit/field_handler.hpp @@ -1,4 +1,4 @@ -/* $Id: field_handler.hpp 453160 2014-12-01 17:05:32Z asztalos $ +/* $Id: field_handler.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -59,8 +59,8 @@ public: virtual bool IsEmpty(const CObject& object) const = 0; virtual void ClearVal(CObject& object) = 0; virtual bool SetVal(CObject& object, const string& val, EExistingText existing_text) = 0; - virtual string IsValid(const string& val) { return ""; }; - virtual vector IsValid(const vector& values) { vector x; return x; };; + virtual string IsValid(const string& /*val*/) { return ""; }; + virtual vector IsValid(const vector& /*values*/) { vector x; return x; }; virtual CSeqFeatData::ESubtype GetFeatureSubtype() = 0; virtual CSeqdesc::E_Choice GetDescriptorSubtype() = 0; virtual void SetConstraint(const string& field, CConstRef string_constraint) = 0; diff --git a/c++/include/objtools/edit/gap_trim.hpp b/c++/include/objtools/edit/gap_trim.hpp new file mode 100644 index 00000000..ef0a2a52 --- /dev/null +++ b/c++/include/objtools/edit/gap_trim.hpp @@ -0,0 +1,156 @@ +#ifndef EDIT___GAP_TRIM__HPP +#define EDIT___GAP_TRIM__HPP + +/* $Id: gap_trim.hpp 533599 2017-04-18 14:28:05Z bollin $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Colleen Bollin + * + * File Description: + * Adjusting features for gaps + * ....... + * + */ + +#include + +#include +#include +#include +#include +#include + + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) + +class CSeq_entry; +class CBioseq; +class CBioseq_set; +class CSeq_annot; +class CSeq_feat; + + + +class CSeq_entry_Handle; +class CBioseq_Handle; +class CBioseq_set_Handle; +class CSeq_annot_Handle; +class CSeq_feat_Handle; + +BEGIN_SCOPE(edit) + +class NCBI_XOBJEDIT_EXPORT CFeatGapInfo : public CObject { +public: + CFeatGapInfo() {}; + CFeatGapInfo(CSeq_feat_Handle sf); + ~CFeatGapInfo() {}; + + void CollectGaps(const CSeq_loc& feat_loc, CScope& scope); + void CalculateRelevantIntervals(bool unknown_length, bool known_length, bool ns = false); + bool HasKnown() const { return m_Known; }; + bool HasUnknown() const { return m_Unknown; }; + bool HasNs() const { return m_Ns; }; + + bool Trimmable() const; + bool Splittable() const; + bool ShouldRemove() const; + + void Trim(CSeq_loc& loc, bool make_partial, CScope& scope); + typedef vector< CRef > TLocList; + TLocList Split(const CSeq_loc& orig, bool in_intron, bool make_partial); + + vector > AdjustForRelevantGapIntervals(bool make_partial, bool trim, bool split, bool in_intron); + CSeq_feat_Handle GetFeature() const { return m_Feature; }; + + static CRef AdjustProteinSeq(const CBioseq& seq, const CSeq_feat& feat, const CSeq_feat& orig_cds, CScope& scope); + + bool IsRelatedByCrossRef(const CFeatGapInfo& other) const; + +protected: + typedef enum { + eGapIntervalType_unknown = 0, + eGapIntervalType_known, + eGapIntervalType_n + } EGapIntervalType; + + typedef pair > TGapInterval; + typedef vector TGapIntervalList; + TGapIntervalList m_Gaps; + + typedef vector > TIntervalList; + TIntervalList m_InsideGaps; + TIntervalList m_LeftGaps; + TIntervalList m_RightGaps; + + TSeqPos m_Start; + TSeqPos m_Stop; + + bool m_Known; + bool m_Unknown; + bool m_Ns; + + CSeq_feat_Handle m_Feature; + + void x_AdjustOrigLabel(CSeq_feat& feat, size_t& id_offset, string& id_label, const string& qual); + CRef x_AdjustProtId(const CDbtag& orig_gen, size_t& id_offset); + CRef x_AdjustProtId(const CSeq_id& orig, size_t& id_offset); + static void x_AdjustFrame(CCdregion& cdregion, TSeqPos frame_adjust); + void x_AdjustCodebreaks(CSeq_feat& feat); + void x_AdjustAnticodons(CSeq_feat& feat); + bool x_UsableInterval(const TGapInterval& interval, bool unknown_length, bool known_length, bool ns); +}; + +typedef vector > TGappedFeatList; +NCBI_XOBJEDIT_EXPORT +TGappedFeatList ListGappedFeatures(CFeat_CI& feat_it, CScope& scope); + +NCBI_XOBJEDIT_EXPORT +void ProcessForTrimAndSplitUpdates(CSeq_feat_Handle cds, vector > updates); + +// for adjusting feature IDs after splitting + +// for fixing a list of features from a split: pass in entire list, feature IDs will be changed +// for features after the first starting with the value of next_id, which will be increased +// after each use +NCBI_XOBJEDIT_EXPORT +void FixFeatureIdsForUpdates(vector > updates, objects::CObject_id::TId& next_id); + +// adjust feature ID for a single feature (will increase next_id if feature had an ID to be adjusted) +NCBI_XOBJEDIT_EXPORT +void FixFeatureIdsForUpdates(CSeq_feat& feat, CObject_id::TId& next_id); + +// adjust two lists of features, that are the result of splitting two features that had cross-references +// to each other. Both features must have been split into the same number of pieces. +// The new cross-references pair the elements of the list in order. +NCBI_XOBJEDIT_EXPORT +void FixFeatureIdsForUpdatePair(vector >& updates1, vector >& updates2); + + +END_SCOPE(edit) +END_SCOPE(objects) +END_NCBI_SCOPE + +#endif /* EDIT___GAP_TRIM__HPP */ diff --git a/c++/include/objtools/edit/gaps_edit.hpp b/c++/include/objtools/edit/gaps_edit.hpp index 89c5e4fd..0711d61f 100644 --- a/c++/include/objtools/edit/gaps_edit.hpp +++ b/c++/include/objtools/edit/gaps_edit.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_EDIT_GAPS_EDITOR_HPP_INCLUDED #define OBJTOOLS_EDIT_GAPS_EDITOR_HPP_INCLUDED -/* $Id: gaps_edit.hpp 513301 2016-09-09 12:02:54Z ivanov $ +/* $Id: gaps_edit.hpp 512615 2016-09-01 18:00:49Z gotvyans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/edit/loc_edit.hpp b/c++/include/objtools/edit/loc_edit.hpp index 9eebad91..cc1f211c 100644 --- a/c++/include/objtools/edit/loc_edit.hpp +++ b/c++/include/objtools/edit/loc_edit.hpp @@ -1,4 +1,4 @@ -/* $Id: loc_edit.hpp 488678 2016-01-04 19:38:41Z asztalos $ +/* $Id: loc_edit.hpp 521623 2016-12-12 16:47:06Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -161,6 +161,12 @@ NCBI_XOBJEDIT_EXPORT const CSeq_id* seqid, unsigned int options = eSplitLocOption_make_partial | eSplitLocOption_split_in_exon); +/// Correct the order of consecutive intervals with the same +/// Seq-id on the same strand +NCBI_XOBJEDIT_EXPORT +bool CorrectIntervalOrder(CSeq_loc& loc); + + END_SCOPE(edit) END_SCOPE(objects) END_NCBI_SCOPE diff --git a/c++/include/objtools/edit/mail_report.hpp b/c++/include/objtools/edit/mail_report.hpp index 4ed2769b..de488232 100644 --- a/c++/include/objtools/edit/mail_report.hpp +++ b/c++/include/objtools/edit/mail_report.hpp @@ -1,4 +1,4 @@ -/* $Id: mail_report.hpp 519250 2016-11-14 18:26:30Z ivanov $ +/* $Id: mail_report.hpp 519061 2016-11-10 20:00:41Z filippov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/edit/rna_edit.hpp b/c++/include/objtools/edit/rna_edit.hpp index 1d65b18a..0eaf7136 100644 --- a/c++/include/objtools/edit/rna_edit.hpp +++ b/c++/include/objtools/edit/rna_edit.hpp @@ -1,4 +1,4 @@ -/* $Id: rna_edit.hpp 513140 2016-09-07 18:34:49Z fukanchi $ +/* $Id: rna_edit.hpp 512961 2016-09-06 15:09:13Z filippov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/edit/seq_entry_edit.hpp b/c++/include/objtools/edit/seq_entry_edit.hpp index 43f11c26..5ea4273a 100644 --- a/c++/include/objtools/edit/seq_entry_edit.hpp +++ b/c++/include/objtools/edit/seq_entry_edit.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_EDIT___SEQ_ENTRY_EDIT__HPP #define OBJTOOLS_EDIT___SEQ_ENTRY_EDIT__HPP -/* $Id: seq_entry_edit.hpp 499249 2016-04-25 12:22:22Z bollin $ +/* $Id: seq_entry_edit.hpp 516551 2016-10-14 10:46:23Z choi $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -216,7 +216,8 @@ typedef vector TCuts; enum EInternalTrimType { eTrimToClosestEnd = 0, // default eTrimTo5PrimeEnd, - eTrimTo3PrimeEnd + eTrimTo3PrimeEnd, + eDoNotTrimInternal }; /// Trim sequence data and all associated annotation diff --git a/c++/include/objtools/edit/source_edit.hpp b/c++/include/objtools/edit/source_edit.hpp index fe325ea6..a6bd0277 100644 --- a/c++/include/objtools/edit/source_edit.hpp +++ b/c++/include/objtools/edit/source_edit.hpp @@ -1,4 +1,4 @@ -/* $Id: source_edit.hpp 473823 2015-07-22 18:53:24Z asztalos $ +/* $Id: source_edit.hpp 538820 2017-06-14 14:20:44Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,7 +33,7 @@ #include #include #include - +#include BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) @@ -43,6 +43,7 @@ BEGIN_SCOPE(edit) /// resets the common name and removes the synonyms for taxname NCBI_XOBJEDIT_EXPORT bool CleanupForTaxnameChange( objects::CBioSource& src ); NCBI_XOBJEDIT_EXPORT bool RemoveOldName( objects::CBioSource& src ); +NCBI_XOBJEDIT_EXPORT bool RemoveMod( objects::CBioSource& src, objects::COrgMod::ESubtype subtype ); NCBI_XOBJEDIT_EXPORT bool RemoveTaxId( objects::CBioSource& src ); NCBI_XOBJEDIT_EXPORT CRef MakeCommonBioSource(const objects::CBioSource& src1, const objects::CBioSource& src2); diff --git a/c++/include/objtools/edit/string_constraint.hpp b/c++/include/objtools/edit/string_constraint.hpp index 39ad85e0..f24a5cf5 100644 --- a/c++/include/objtools/edit/string_constraint.hpp +++ b/c++/include/objtools/edit/string_constraint.hpp @@ -1,4 +1,4 @@ -/* $Id: string_constraint.hpp 515131 2016-09-28 15:33:44Z ivanov $ +/* $Id: string_constraint.hpp 514944 2016-09-27 13:52:53Z filippov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/error_codes.hpp b/c++/include/objtools/error_codes.hpp index a38a3e8b..6532175e 100644 --- a/c++/include/objtools/error_codes.hpp +++ b/c++/include/objtools/error_codes.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS___ERROR_CODES__HPP #define OBJTOOLS___ERROR_CODES__HPP -/* $Id: error_codes.hpp 504655 2016-06-16 21:18:41Z boratyng $ +/* $Id: error_codes.hpp 541337 2017-07-17 15:57:14Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -83,6 +83,7 @@ NCBI_DEFINE_ERRCODE_X(Objtools_Fmt_CIGAR, 1439, 1); NCBI_DEFINE_ERRCODE_X(Objtools_Fmt_SAM, 1440, 0); NCBI_DEFINE_ERRCODE_X(Objtools_LDS2, 1441, 10); NCBI_DEFINE_ERRCODE_X(Objtools_LDS2_Loader, 1442, 2); +NCBI_DEFINE_ERRCODE_X(Objtools_Fmt_Genbank, 1443, 2); END_NCBI_SCOPE diff --git a/c++/include/objtools/format/context.hpp b/c++/include/objtools/format/context.hpp index f5246029..abc5b480 100644 --- a/c++/include/objtools/format/context.hpp +++ b/c++/include/objtools/format/context.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_FORMAT___CONTEXT__HPP #define OBJTOOLS_FORMAT___CONTEXT__HPP -/* $Id: context.hpp 511385 2016-08-22 13:31:32Z ivanov $ +/* $Id: context.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -98,7 +98,7 @@ public: CBioseq_Handle& GetHandle(void) { return m_Handle; } const CBioseq_Handle& GetHandle(void) const { return m_Handle; } CBioseq_Handle& GetNextHandle(void) { return m_NextHandle; } - CScope& GetScope(void) { return m_Handle.GetScope(); } + CScope& GetScope(void) const { return m_Handle.GetScope(); } feature::CFeatTree& GetFeatTree(void) { return m_FeatTree; } // -- id information @@ -222,7 +222,7 @@ public: }; typedef Int8 TUnverified; TUnverified GetUnverifiedType(void) const; - bool ShowAnnotCommentAsCOMMENT(void) const { return m_ShowAnnotCommentAsCOMMENT; } + bool ShowAnnotCommentAsCOMMENT() const; bool IsHup(void) const { return m_IsHup; } // !!! should move to global? @@ -236,7 +236,7 @@ public: const SAnnotSelector* GetAnnotSelector(void) const; SAnnotSelector& SetAnnotSelector(void); const CSeq_loc* GetMasterLocation(void) const; - const bool GetSGS(void) const; + bool GetSGS(void) const; bool IsGenbankFormat(void) const; bool HasOperon(void) const; @@ -277,7 +277,7 @@ private: void x_SetMapper(const CSeq_loc& loc); void x_SetHasMultiIntervalGenes(void); void x_SetDataFromUserObjects(void); - void x_SetDataFromAnnot(void); + void x_CheckForShowComments() const; void x_SetTaxname(void); void x_SetFiletrackURL(const CUser_object& uo); void x_SetAuthorizedAccess(const CUser_object& uo); @@ -358,7 +358,8 @@ private: bool m_IsGenomeAssembly; bool m_IsCrossKingdom; TUnverified m_fUnverified; - bool m_ShowAnnotCommentAsCOMMENT; + mutable bool m_ShowAnnotCommentAsCOMMENT; + mutable bool m_ShowAnnotCommentAsCOMMENT_checked; CConstRef m_Encode; @@ -444,7 +445,7 @@ public: feature::CFeatTree* GetFeatTree(void) { return m_FeatTree; } void SetFeatTree(feature::CFeatTree* tree) { m_FeatTree.Reset(tree); } - const bool GetSGS(void) const { return m_SmallGenomeSet; } + bool GetSGS(void) const { return m_SmallGenomeSet; } void SetSGS(const bool sgs) { m_SmallGenomeSet = sgs; } void AddSection(TSection& section) { m_Sections.push_back(section); } @@ -680,7 +681,7 @@ const CSeq_loc* CBioseqContext::GetMasterLocation(void) const inline -const bool CBioseqContext::GetSGS(void) const +bool CBioseqContext::GetSGS(void) const { return m_FFCtx.GetSGS(); } @@ -738,7 +739,7 @@ inline SAnnotSelector& CFlatFileContext::SetAnnotSelector(void) { if ( m_Selector.get() == 0 ) { - m_Selector.reset(new SAnnotSelector); + m_Selector.reset(new SAnnotSelector(CSeq_annot::TData::e_Ftable)); } return *m_Selector; diff --git a/c++/include/objtools/format/flat_file_config.hpp b/c++/include/objtools/format/flat_file_config.hpp index 3942f53d..d3a13bd1 100644 --- a/c++/include/objtools/format/flat_file_config.hpp +++ b/c++/include/objtools/format/flat_file_config.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_FORMAT___FLAT_FILE_CONFIG__HPP #define OBJTOOLS_FORMAT___FLAT_FILE_CONFIG__HPP -/* $Id: flat_file_config.hpp 507549 2016-07-19 22:29:29Z kans $ +/* $Id: flat_file_config.hpp 544490 2017-08-23 17:44:11Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -77,11 +77,9 @@ struct SModelEvidance; // --- Flat File configuration class // NEW_HTML_FMT define enables new interceptor interface for HTML links generation -//#define NEW_HTML_FMT +#define NEW_HTML_FMT -#ifdef NEW_HTML_FMT - -class IHTMLFormatter: public CObject +class NCBI_FORMAT_EXPORT IHTMLFormatter: public CObject { public: virtual ~IHTMLFormatter() {}; @@ -96,7 +94,7 @@ public: virtual void FormatGeneralId(CNcbiOstream& os, const string& id) const = 0; }; -class CHTMLEmptyFormatter : public IHTMLFormatter +class NCBI_FORMAT_EXPORT CHTMLEmptyFormatter : public IHTMLFormatter { public: virtual ~CHTMLEmptyFormatter() {}; @@ -110,7 +108,6 @@ public: void FormatTranscript(string& str, const string& name) const; void FormatGeneralId(CNcbiOstream& os, const string& id) const; }; -#endif class NCBI_FORMAT_EXPORT CFlatFileConfig { @@ -123,8 +120,6 @@ public: eFormat_DDBJ, eFormat_GBSeq, eFormat_FTable, - eFormat_GFF, // version 2, w/GTF - eFormat_GFF3, eFormat_FeaturesOnly, eFormat_SAM, eFormat_AGP, @@ -186,7 +181,8 @@ public: enum ECustom { // additional customization flags fHideProteinID = 1, - fHideGI = 1 << 1 + fHideGI = 1 << 1, + fLongLocusNames = 1 << 2 }; enum EView { @@ -369,24 +365,33 @@ public: // this if you want only a single entry-point for // notifications. virtual EAction unified_notify( - string & block_text, - const CBioseqContext& ctx, - const IFlatItem & flat_item, - FGenbankBlocks which_block ) { return eAction_Default; } + string & /*block_text*/, + const CBioseqContext& /*ctx*/, + const IFlatItem & /*flat_item*/, + FGenbankBlocks /*which_block*/ ) { return eAction_Default; } }; // constructor - CFlatFileConfig(TFormat format = eFormat_GenBank, - TMode mode = eMode_GBench, - TStyle style = eStyle_Normal, - TFlags flags = 0, - TView view = fViewNucleotides, - TGffOptions gff_options = fGffGTFCompat, + NCBI_DEPRECATED + CFlatFileConfig(TFormat format, + TMode mode, + TStyle style, + TFlags flags, + TView view, + TGffOptions gff_options_OBSOLETE, TGenbankBlocks genbank_blocks = fGenbankBlocks_All, CGenbankBlockCallback* pGenbankBlockCallback = NULL, const ICanceled * pCanceledCallback = NULL, bool basicCleanup = false, TCustom custom = 0 ); + + // constructor + CFlatFileConfig(TFormat format = eFormat_GenBank, + TMode mode = eMode_GBench, + TStyle style = eStyle_Normal, + TFlags flags = 0, + TView view = fViewNucleotides); + // destructor ~CFlatFileConfig(void); @@ -409,8 +414,6 @@ public: bool IsFormatDDBJ (void) const { return m_Format == eFormat_DDBJ; } bool IsFormatGBSeq (void) const { return m_Format == eFormat_GBSeq; } bool IsFormatFTable (void) const { return m_Format == eFormat_FTable; } - bool IsFormatGFF (void) const { return m_Format == eFormat_GFF; } - bool IsFormatGFF3 (void) const { return m_Format == eFormat_GFF3; } bool IsFormatAGP (void) const { return m_Format == eFormat_AGP; } bool IsFormatLite (void) const { return m_Format == eFormat_Lite; } @@ -421,8 +424,6 @@ public: void SetFormatDDBJ (void) { m_Format = eFormat_DDBJ; } void SetFormatGBSeq (void) { m_Format = eFormat_GBSeq; } void SetFormatFTable (void) { m_Format = eFormat_FTable; } - void SetFormatGFF (void) { m_Format = eFormat_GFF; } - void SetFormatGFF3 (void) { m_Format = eFormat_GFF3; } void SetFormatAGP (void) { m_Format = eFormat_AGP; } void SetFormatLite (void) { m_Format = eFormat_Lite; } @@ -589,66 +590,108 @@ public: const TCustom& GetCustom(void) const { return m_Custom; } bool HideProteinID (void) const; bool HideGI (void) const; + bool LongLocusNames (void) const; // setters void SetCustom(const TCustom& custom) { m_Custom = custom; } CFlatFileConfig& SetHideProteinID (bool val = true); CFlatFileConfig& SetHideGI (bool val = true); + CFlatFileConfig& SetLongLocusNames (bool val = true); // adjust mode dependant flags for RefSeq void SetRefSeqConventions(void); // -- GffOptions // getters + NCBI_DEPRECATED bool GffGenerateIdTags (void) const { return (0 != (m_GffOptions & fGffGenerateIdTags)); }; + NCBI_DEPRECATED bool GffGTFCompat (void) const { return (0 != (m_GffOptions & fGffGTFCompat)); }; + NCBI_DEPRECATED bool GffGTFOnly (void) const { return (0 != (m_GffOptions & fGffGTFOnly)); }; + NCBI_DEPRECATED bool GffShowSeq (void) const { return (0 != (m_GffOptions & fGffShowSeq)); }; + NCBI_DEPRECATED bool GffForFlybase (void) const { return (0 != (m_GffOptions & fGffForFlybase)); }; // setters + NCBI_DEPRECATED void SetGffGenerateIdTags (bool val = true) { - m_GffOptions |= fGffGenerateIdTags; + if (val) { + m_GffOptions |= fGffGenerateIdTags; + } + else { + m_GffOptions &= ~fGffGenerateIdTags; + } }; + NCBI_DEPRECATED void SetGffGTFCompat (bool val = true) { - m_GffOptions |= fGffGTFCompat; + if (val) { + m_GffOptions |= fGffGTFCompat; + } + else { + m_GffOptions &= ~fGffGTFCompat; + } }; + NCBI_DEPRECATED void SetGffGTFOnly (bool val = true) { - m_GffOptions |= fGffGTFOnly; + if (val) { + m_GffOptions |= fGffGTFOnly; + } + else { + m_GffOptions &= ~fGffGTFOnly; + } }; + NCBI_DEPRECATED void SetGffShowSeq (bool val = true) { - m_GffOptions |= fGffShowSeq; + if (val) { + m_GffOptions |= fGffShowSeq; + } + else { + m_GffOptions &= ~fGffShowSeq; + } }; + NCBI_DEPRECATED void SetGffForFlybase (bool val = true) { - m_GffOptions |= fGffForFlybase; + if (val) { + m_GffOptions |= fGffForFlybase; + } + else { + m_GffOptions &= ~fGffForFlybase; + } + }; + + void SetGenbankBlocks(const TGenbankBlocks& genbank_blocks) + { + m_fGenbankBlocks = genbank_blocks; }; // check if the given section is shown @@ -722,8 +765,8 @@ private: TFormat m_Format; TMode m_Mode; TStyle m_Style; - TView m_View; TFlags m_Flags; // custom flags + TView m_View; bool m_RefSeqConventions; TGffOptions m_GffOptions; TGenbankBlocks m_fGenbankBlocks; @@ -820,6 +863,7 @@ CUSTOM_ARG_SET(x) CUSTOM_ARG_IMP(HideProteinID) CUSTOM_ARG_IMP(HideGI) +CUSTOM_ARG_IMP(LongLocusNames) #undef FLAG_ARG_IMP #undef FLAG_ARG_GET diff --git a/c++/include/objtools/format/flat_file_generator.hpp b/c++/include/objtools/format/flat_file_generator.hpp index cacb86a7..8acaaa76 100644 --- a/c++/include/objtools/format/flat_file_generator.hpp +++ b/c++/include/objtools/format/flat_file_generator.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_FORMAT___FLAT_FILE_GENERATOR__HPP #define OBJTOOLS_FORMAT___FLAT_FILE_GENERATOR__HPP -/* $Id: flat_file_generator.hpp 481472 2015-10-13 00:35:27Z kans $ +/* $Id: flat_file_generator.hpp 530483 2017-03-15 15:18:55Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -96,6 +96,9 @@ public: void Generate(const CSeq_id& id, const TRange& range, ENa_strand strand, CScope& scope, CFlatItemOStream& item_os); + // for use when generating a range of a Seq-submit + void SetSubmit(const CSubmit_block& sub) { m_Ctx->SetSubmit(sub); } + static string GetSeqFeatText(const CMappedFeat& feat, CScope& scope, const CFlatFileConfig& cfg); diff --git a/c++/include/objtools/format/gather_items.hpp b/c++/include/objtools/format/gather_items.hpp index 47397db4..d483cd85 100644 --- a/c++/include/objtools/format/gather_items.hpp +++ b/c++/include/objtools/format/gather_items.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_FORMAT___GATHER_ITEMS__HPP #define OBJTOOLS_FORMAT___GATHER_ITEMS__HPP -/* $Id: gather_items.hpp 494523 2016-03-08 01:22:14Z kans $ +/* $Id: gather_items.hpp 530957 2017-03-20 14:27:19Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -110,7 +110,7 @@ protected: // features void x_GatherFeatures (void) const; - void x_GetFeatsOnCdsProduct(const CSeq_feat& feat, const CSeq_loc& mapped_loc, CBioseqContext& ctx, + void x_GetFeatsOnCdsProduct(const CSeq_feat& feat, CBioseqContext& ctx, CRef slice_mapper, CConstRef cdsFeatureItem = CConstRef() ) const; static void x_GiveOneResidueIntervalsBogusFuzz(CSeq_loc & loc); @@ -119,6 +119,10 @@ protected: bool x_SkipFeature(const CSeq_feat& feat, const CBioseqContext& ctx) const; virtual void x_GatherFeaturesOnLocation(const CSeq_loc& loc, SAnnotSelector& sel, CBioseqContext& ctx) const; + void x_GatherFeaturesOnWholeLocation(const CSeq_loc& loc, SAnnotSelector& sel, + CBioseqContext& ctx) const; + void x_GatherFeaturesOnRange(const CSeq_loc& loc, SAnnotSelector& sel, + CBioseqContext& ctx) const; // source features typedef CRef TSFItem; diff --git a/c++/include/objtools/format/gff3_formatter.hpp b/c++/include/objtools/format/gff3_formatter.hpp deleted file mode 100644 index 8411986f..00000000 --- a/c++/include/objtools/format/gff3_formatter.hpp +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef OBJTOOLS_FORMAT___GFF3_FORMATTER__HPP -#define OBJTOOLS_FORMAT___GFF3_FORMATTER__HPP - -/* $Id: gff3_formatter.hpp 359060 2012-04-10 14:14:54Z ludwigf $ - * =========================================================================== - * - * PUBLIC DOMAIN NOTICE - * National Center for Biotechnology Information - * - * This software/database is a "United States Government Work" under the - * terms of the United States Copyright Act. It was written as part of - * the author's official duties as a United States Government employee and - * thus cannot be copyrighted. This software/database is freely available - * to the public for use. The National Library of Medicine and the U.S. - * Government have not placed any restriction on its use or reproduction. - * - * Although all reasonable efforts have been taken to ensure the accuracy - * and reliability of the software and data, the NLM and the U.S. - * Government do not and cannot warrant the performance or results that - * may be obtained by using this software or data. The NLM and the U.S. - * Government disclaim all warranties, express or implied, including - * warranties of performance, merchantability or fitness for any particular - * purpose. - * - * Please cite the author in any work or product based on this material. - * - * =========================================================================== - * - * Authors: Aaron Ucko - * - */ - -/// @file gff3_formatter.hpp -/// Flat formatter for Generic Feature Format version 3. -/// -/// See http://song.sourceforge.net/gff3-jan04.shtml . - - -#include -#include - - -/** @addtogroup Miscellaneous - * - * @{ - */ - - -BEGIN_NCBI_SCOPE -BEGIN_SCOPE(objects) - -class CDense_seg; - -// ============================================================================ -/// Flat file generator support for generating GFF3 output has been deprecated, -/// and therefore, class CGFF3_Formatter has been deprecated as well. DO NOT USE -/// this class for future projects as it is no longer maintained and produces -/// bad GFF. -/// For future projects (or to upgrade your existing project), use CGff3Writer -/// (or an appropriate derivative) instead. -// ============================================================================ -NCBI_DEPRECATED_CLASS NCBI_FORMAT_EXPORT CGFF3_Formatter : public CGFFFormatter -{ -public: - NCBI_DEPRECATED_CTOR( - CGFF3_Formatter() - { - m_CurrentId = 1; - }) - - void Start (IFlatTextOStream& text_os); - void EndSection (const CEndSectionItem& esec, IFlatTextOStream& text_os); - void FormatAlignment(const CAlignmentItem& aln, IFlatTextOStream& text_os); -protected: - string x_GetAttrSep(void) const { return ";"; } - string x_FormatAttr(const string& name, const string& value) const; - void x_AddGeneID(list& attr_list, const string& gene_id, - const string& transcript_id) const; - -private: - unsigned int m_CurrentId; - - /// Encodes according to GFF3's URL-like encoding rules. - /// - /// There are some 4 different subtly different encoding rules in GFF3: - /// - /// 1) General rules, which allow all characters except: - /// tab newline carriage-return control ; = % & , . \ " - /// - /// Note that the above is specified in 3 parts, confusingly. - /// "The following characters must be escaped" in one paragraph, - /// "The following characters have reserved meanings and - /// must be escaped" in a second paragraph, then a third - /// paragraph gives a few more that "are explicitly forbidden". - /// - /// 2) Seqid rules, which are more restrictive and apply only - /// to the first column, allowing only: - /// a-z A-Z 0-9 . : ^ * $ @ ! + _ ? - | - /// - /// 3) The attribute rules, which effectively clarify the general rule's - /// second paragraph about reserved meanings, but give a - /// reduced list: - /// , = ; - /// - /// Also, spaces are exlictly allowed, unescaped. - /// - /// 4) The Target tag rules, which are quite simply that spaces - /// must be escaped with %09 (and not with +). - /// - /// Wow! We'll forget about the more lax vs strict distinction - /// since stict should be compativle with lax, and concentrate - /// on the 3 different ways that spaces are represented. - /// - /// By prior versions of GFF3 specs (current is 1.14), - /// + had special meaning (as a space). Those older versions - /// of the GFF3 spcs discussed URL encoding, specifically mentionned - /// + as space, and used such encoding in examples. In subsequent - /// versions, + was explicitly listed amongst the allowable characters - /// for the Seqid column. I believe the issue arised from - /// confusion between URL encoding (which only does % escaping) - /// versus application/x-www-form-urlencoded which is similar, - /// but adds things like + to represent spaces. - /// - /// In general, we'll prefer "%09", but recommend " " be used for - /// the last column, attributes, but beweare the special exception - /// in rule 4 requiring "%09" for Target. If generating output for - /// older GFF3 parsers, we might get away with "+" as the escape - /// for a space, which reads better, but is now rather dangerous. - /// - /// @param os the destination stream - /// @param s the string to be encoded - /// @param space the representation of spaces, which should be - /// one of "+" (default), " ", or "%09". - static CNcbiOstream& x_AppendEncoded(CNcbiOstream& os, - const string& s, - const char* space = "%09"); - - /// Formats any pairwise alignment into GFF3 format with CIGAR notation. - /// - /// @param width_inverted See x_FormatDenseg(). - void x_FormatAlignment(const CAlignmentItem& aln, - IFlatTextOStream& text_os, const CSeq_align& sa, - bool first, bool width_inverted); - /// Formats a Dense-seg alignment into GFF3 format with CIGAR notation. - /// - /// @attention There is a disagreement in the meaning of widths - /// for a Dense-seg, as multiplier vs divisor relative to - /// the target sequence length. This function tries to - /// accommodate this problem. - /// @param width_inverted If false, as in most cases, the widths are - /// a multiplier, i.e. width 3 means every 1 unit (aa) in the - /// alignment corresponds to an alignment of 3 units (na) on - /// the sequence. If true, as is the case with - /// CSpliced_seg::s_ExonToDenseg, the widths act as divisors, - /// i.e. width 3 means every 3 units (na) in the alignment - /// correspond to 1 unit (aa) on the sequence. - void x_FormatDenseg(const CAlignmentItem& aln, - IFlatTextOStream& text_os, const CDense_seg& ds, - bool first, - bool width_inverted); - - friend class CGFF3_CIGAR_Formatter; -}; - - -END_SCOPE(objects) -END_NCBI_SCOPE - - -/* @} */ - -#endif /* OBJTOOLS_FORMAT___GFF3_FORMATTER__HPP */ diff --git a/c++/include/objtools/format/gff_formatter.hpp b/c++/include/objtools/format/gff_formatter.hpp deleted file mode 100644 index 6d558775..00000000 --- a/c++/include/objtools/format/gff_formatter.hpp +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef OBJTOOLS_FORMAT___GFF_FORMATTER__HPP -#define OBJTOOLS_FORMAT___GFF_FORMATTER__HPP - -/* $Id: gff_formatter.hpp 359060 2012-04-10 14:14:54Z ludwigf $ -* =========================================================================== -* -* PUBLIC DOMAIN NOTICE -* National Center for Biotechnology Information -* -* This software/database is a "United States Government Work" under the -* terms of the United States Copyright Act. It was written as part of -* the author's official duties as a United States Government employee and -* thus cannot be copyrighted. This software/database is freely available -* to the public for use. The National Library of Medicine and the U.S. -* Government have not placed any restriction on its use or reproduction. -* -* Although all reasonable efforts have been taken to ensure the accuracy -* and reliability of the software and data, the NLM and the U.S. -* Government do not and cannot warrant the performance or results that -* may be obtained by using this software or data. The NLM and the U.S. -* Government disclaim all warranties, express or implied, including -* warranties of performance, merchantability or fitness for any particular -* purpose. -* -* Please cite the author in any work or product based on this material. -* -* =========================================================================== -* -* Author: Aaron Ucko, NCBI -* Mati Shomrat -* -* File Description: -* -*/ - -/// @file flat_gff_formatter.hpp -/// Flat formatter for Generic Feature Format v2 (incl. Gene Transfer Format). -/// -/// These formats are somewhat loosely defined (for the record, at -/// http://www.sanger.ac.uk/Software/formats/GFF/GFF_Spec.shtml and -/// http://genes.cs.wustl.edu/GTF2.html respectively) so we default to -/// GenBank/DDBJ/EMBL keys and qualifiers except as needed for GTF -/// compatibility. -/// -/// There is a separate formatter (subclassing this one) for GFF 3. - -#include -#include -#include - -/** @addtogroup Miscellaneous - * - * @{ - */ - - -BEGIN_NCBI_SCOPE -BEGIN_SCOPE(objects) - - -class CFlatFeature; - -// ============================================================================ -/// Flat file generator support for generating GFF output has been deprecated, -/// and therefore, class CGFFFormatter has been deprecated as well. DO NOT USE -/// this class for future projects as it is no longer maintained and produces -/// bad GFF. -/// For future projects (or to upgrade your existing project), use CGff2Writer -/// (or an appropriate derivative) instead. -// ============================================================================ -NCBI_DEPRECATED_CLASS NCBI_FORMAT_EXPORT CGFFFormatter : public CFlatItemFormatter -{ -public: - - /// Most of these options don't belong here, where they would be - /// completely useless. There's already a set of flags via - /// CFlatFileConfig::EGffOptions, which are exposed via API, whereas - /// the following flags are not exposed, and cannot be changed. - /// - /// @deprecated Avoid these flags and use those from CFlatFileConfig. - /// @see CFlatFileConfig::EGffOptions - enum EGFFFlags { - fGTFCompat = 0x1, ///< @deprecated Represent CDSs (and exons) per GTF. - fGTFOnly = 0x3, ///< @deprecated Omit all other features. - fShowSeq = 0x4 ///< @deprecated Show the actual sequence in a "##" comment. - }; - typedef int TGFFFlags; ///< Binary OR of EGFFFlags - - NCBI_DEPRECATED_CTOR(CGFFFormatter(void)); - - void Start (IFlatTextOStream& text_os); - void StartSection(const CStartSectionItem&, IFlatTextOStream& text_os); - void EndSection (const CEndSectionItem&, IFlatTextOStream& text_os); - - void FormatLocus(const CLocusItem& locus, IFlatTextOStream& text_os); - void FormatDate(const CDateItem& date, IFlatTextOStream& text_os); - void FormatFeature(const CFeatureItemBase& feat, IFlatTextOStream& text_os); - void FormatBasecount(const CBaseCountItem& bc, IFlatTextOStream& text_os); - void FormatSequence(const CSequenceItem& seq, IFlatTextOStream& text_os); - -protected: - virtual string x_GetAttrSep(void) const { return " "; } - virtual string x_FormatAttr(const string& name, const string& value) const; - virtual void x_AddGeneID(list& attr_list, const string& gene_id, - const string& transcript_id) const; - - string x_GetSourceName(CBioseqContext& ctx) const; - void x_AddFeature(list& l, const CSeq_loc& loc, - const string& source, const string& key, - const string& score, int frame, const string& attrs, - bool gtf, CBioseqContext& ctx, - bool tentative_stop = false) const; - -private: - string x_GetGeneID(const CFlatFeature& feat, const string& gene_name, - CBioseqContext& ctx) const; - string x_GetTranscriptID(const CFlatFeature& feat, const string& gene_id, - CBioseqContext& ctx) const; - - //CRef m_Stream; - mutable string m_SeqType; - mutable string m_EndSequence; - /// Taken from head - mutable string m_Date; - mutable CSeq_inst::TStrand m_Strandedness; - - typedef vector TFeatVec; - mutable map m_Genes; - mutable map m_Transcripts; -}; - - -END_SCOPE(objects) -END_NCBI_SCOPE - - -/* @} */ - -#endif /* OBJTOOLS_FORMAT___GFF_FORMATTER__HPP */ diff --git a/c++/include/objtools/format/items/feature_item.hpp b/c++/include/objtools/format/items/feature_item.hpp index 078e044f..b6b5d5fe 100644 --- a/c++/include/objtools/format/items/feature_item.hpp +++ b/c++/include/objtools/format/items/feature_item.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_FORMAT_ITEMS___FLAT_FEATURE__HPP #define OBJTOOLS_FORMAT_ITEMS___FLAT_FEATURE__HPP -/* $Id: feature_item.hpp 512461 2016-08-31 11:22:40Z ivanov $ +/* $Id: feature_item.hpp 541705 2017-07-20 17:36:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -188,6 +188,7 @@ protected: void x_AddQualGeneXref( const CGene_ref*, const CConstRef& ); void x_AddQualOperon( CBioseqContext&, CSeqFeatData::ESubtype ); void x_AddQualsRegulatoryClass( CBioseqContext& ctx, CSeqFeatData::ESubtype subtype ); + void x_AddQualsRecombinationClass( CBioseqContext& ctx, CSeqFeatData::ESubtype subtype ); void x_AddQualPseudo( CBioseqContext&, CSeqFeatData::E_Choice, CSeqFeatData::ESubtype, bool ); @@ -238,6 +239,7 @@ protected: void x_AddRptUnitQual(const string& rpt_unit); void x_AddRptTypeQual(const string& rpt_type, bool check_qual_syntax); void x_AddRegulatoryClassQual(const string& regulatory_class, bool check_qual_syntax); + void x_AddRecombinationClassQual(const string& recombination_class, bool check_qual_syntax); void x_CleanQuals( const CGene_ref* ); const CFlatStringQVal* x_GetStringQual(EFeatureQualifier slot) const; CFlatStringListQVal* x_GetStringListQual(EFeatureQualifier slot) const; @@ -247,8 +249,10 @@ protected: void x_AddFTableQuals(CBioseqContext& ctx); bool x_AddFTableGeneQuals(const CSeqFeatData::TGene& gene); void x_AddFTableRnaQuals(const CMappedFeat& feat, CBioseqContext& ctx); + static string x_SeqIdWriteForTable(const CBioseq& seq, bool suppress_local, bool giOK); void x_AddFTableCdregionQuals(const CMappedFeat& feat, CBioseqContext& ctx); void x_AddFTableProtQuals(const CMappedFeat& prot); + void x_AddFTableProtQuals(const CProt_ref& prot_ref); void x_AddFTableRegionQuals(const CSeqFeatData::TRegion& region); void x_AddFTableBondQuals(const CSeqFeatData::TBond& bond); void x_AddFTableSiteQuals(const CSeqFeatData::TSite& site); @@ -365,26 +369,6 @@ inline void CFeatureItem::x_AddQualExt() } } -// ============================================================================= -class CFeatureItemGff: public CFeatureItem -// ============================================================================= -{ -public: - CFeatureItemGff( - const CMappedFeat& feat, - CBioseqContext& ctx, - const CSeq_loc* loc, - CRef ftree, - EMapped mapped ) - : CFeatureItem( feat, ctx, ftree, loc, mapped ) {}; - - virtual ~CFeatureItemGff() {}; - -protected: - virtual void x_AddQualsRna(const CMappedFeat& feat, CBioseqContext& ctx, - bool pseudo); -}; - // ============================================================================ class NCBI_FORMAT_EXPORT CSourceFeatureItem: public CFeatureItemBase diff --git a/c++/include/objtools/format/items/flat_qual_slots.hpp b/c++/include/objtools/format/items/flat_qual_slots.hpp index 1574fa00..60ad9dcd 100644 --- a/c++/include/objtools/format/items/flat_qual_slots.hpp +++ b/c++/include/objtools/format/items/flat_qual_slots.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_FLAT___FLAT_QUAL_SLOTS__HPP #define OBJTOOLS_FLAT___FLAT_QUAL_SLOTS__HPP -/* $Id: flat_qual_slots.hpp 514604 2016-09-22 18:31:56Z ivanov $ +/* $Id: flat_qual_slots.hpp 514263 2016-09-20 19:14:39Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/format/items/flat_seqloc.hpp b/c++/include/objtools/format/items/flat_seqloc.hpp index d9437b42..a0490027 100644 --- a/c++/include/objtools/format/items/flat_seqloc.hpp +++ b/c++/include/objtools/format/items/flat_seqloc.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_FORMAT_ITEMS___FLAT_SEQLOC__HPP #define OBJTOOLS_FORMAT_ITEMS___FLAT_SEQLOC__HPP -/* $Id: flat_seqloc.hpp 405740 2013-07-08 18:14:10Z kornbluh $ +/* $Id: flat_seqloc.hpp 533244 2017-04-13 20:40:43Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -79,7 +79,7 @@ public: typedef EType TType; CFlatSeqLoc(const CSeq_loc& loc, CBioseqContext& ctx, - TType type = eType_location); + TType type = eType_location, bool show_all_accns = false); const string& GetString(void) const { return m_String; } @@ -101,18 +101,25 @@ private: }; bool x_Add(const CSeq_loc& loc, CNcbiOstrstream& oss, - CBioseqContext& ctx, TType type, bool show_comp); + CBioseqContext& ctx, TType type, bool show_comp, + bool show_all_accns = false); bool x_Add(const CSeq_interval& si, CNcbiOstrstream& oss, - CBioseqContext& ctx, TType type, bool show_comp); + CBioseqContext& ctx, TType type, bool show_comp, + bool show_all_accns = false); bool x_Add(const CSeq_point& pnt, CNcbiOstrstream& oss, - CBioseqContext& ctx, TType type, bool show_comp); + CBioseqContext& ctx, TType type, bool show_comp, + bool show_all_accns = false); bool x_Add(TSeqPos pnt, const CInt_fuzz* fuzz, CNcbiOstrstream& oss, - EHTML html, EForce force = eForce_None, ESource source = eSource_Other ); + EHTML html, EForce force = eForce_None, ESource source = eSource_Other, + bool show_all_accns = false); void x_AddID(const CSeq_id& id, CNcbiOstrstream& oss, - CBioseqContext& ctx, TType type); + CBioseqContext& ctx, TType type, + bool show_all_accns = false); bool x_IsAccessionVersion( CSeq_id_Handle id ); + bool x_FuzzToDisplayed(const CSeq_interval& si) const; + // data string m_String; // whole location, as a GB-style string diff --git a/c++/include/objtools/format/items/item_base.hpp b/c++/include/objtools/format/items/item_base.hpp index 9f4708f2..f816bafc 100644 --- a/c++/include/objtools/format/items/item_base.hpp +++ b/c++/include/objtools/format/items/item_base.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_FORMAT_ITEMS___ITEM_BASE_ITEM__HPP #define OBJTOOLS_FORMAT_ITEMS___ITEM_BASE_ITEM__HPP -/* $Id: item_base.hpp 103491 2007-05-04 17:18:18Z kazimird $ +/* $Id: item_base.hpp 532040 2017-03-30 22:02:42Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -60,6 +60,8 @@ public: // should this item be skipped during formatting? bool Skip(void) const; + // is feature on external Seq-annot? + bool IsExternal(void) const; ~CFlatItem(void); @@ -72,6 +74,7 @@ protected: void x_SetContext(CBioseqContext& ctx); void x_SetSkip(void); + void x_SetExternal(void); private: @@ -81,6 +84,8 @@ private: CBioseqContext* m_Context; // should this item be skipped? bool m_Skip; + // is feature on external Seq-annot? + bool m_External; }; @@ -125,6 +130,13 @@ bool CFlatItem::Skip(void) const } +inline +bool CFlatItem::IsExternal(void) const +{ + return m_External; +} + + inline CFlatItem::~CFlatItem(void) { @@ -137,7 +149,8 @@ inline CFlatItem::CFlatItem(CBioseqContext* ctx) : m_Object(0), m_Context(ctx), - m_Skip(false) + m_Skip(false), + m_External(false) { } @@ -158,6 +171,14 @@ void CFlatItem::x_SetSkip(void) m_Context = 0; } + +inline +void CFlatItem::x_SetExternal(void) +{ + m_External = true; +} + + /////////////////////////////////////////////////////////// ////////////////// end of inline methods ////////////////// /////////////////////////////////////////////////////////// diff --git a/c++/include/objtools/format/items/reference_item.hpp b/c++/include/objtools/format/items/reference_item.hpp index 3062b9ca..878a8749 100644 --- a/c++/include/objtools/format/items/reference_item.hpp +++ b/c++/include/objtools/format/items/reference_item.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_FORMAT_ITEMS___REFERENCE_ITEM__HPP #define OBJTOOLS_FORMAT_ITEMS___REFERENCE_ITEM__HPP -/* $Id: reference_item.hpp 425391 2014-01-28 20:03:15Z gotvyans $ +/* $Id: reference_item.hpp 527372 2017-02-13 18:26:43Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -136,6 +136,7 @@ public: int GetPMID (void) const { return m_PMID; } int GetMUID (void) const { return m_MUID; } + const string& GetPII (void) const { return m_ELocationPII; } const string& GetTitle (void) const { return m_Title; } @@ -212,6 +213,7 @@ private: CConstRef m_Date; int m_PMID; int m_MUID; + string m_ELocationPII; int m_Serial; mutable string m_UniqueStr; bool m_JustUids; diff --git a/c++/include/objtools/format/text_ostream.hpp b/c++/include/objtools/format/text_ostream.hpp index c1236806..3fd4d650 100644 --- a/c++/include/objtools/format/text_ostream.hpp +++ b/c++/include/objtools/format/text_ostream.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_FORMAT___TEXT_OSTREAM_HPP #define OBJTOOLS_FORMAT___TEXT_OSTREAM_HPP -/* $Id: text_ostream.hpp 380048 2012-11-07 18:44:31Z kornbluh $ +/* $Id: text_ostream.hpp 541337 2017-07-17 15:57:14Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -77,6 +77,8 @@ public: _TROUBLE; } + virtual void Flush(void) {} + virtual ~IFlatTextOStream(void) {} }; diff --git a/c++/include/objtools/readers/agp_converter.hpp b/c++/include/objtools/readers/agp_converter.hpp index 79be3414..83f32cd2 100644 --- a/c++/include/objtools/readers/agp_converter.hpp +++ b/c++/include/objtools/readers/agp_converter.hpp @@ -1,4 +1,4 @@ -/* $Id: agp_converter.hpp 405093 2013-06-28 21:32:57Z kornbluh $ +/* $Id: agp_converter.hpp 530215 2017-03-13 14:35:50Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -93,7 +93,7 @@ public: /// Default is to print to cerr, but feel free to override in a subclass. /// In particular, it's reasonable to throw an exception here to halt /// the processing. - virtual void HandleError(EError eError, const string & sMessage ) const { + virtual void HandleError(EError /*eError*/, const string & sMessage ) const { cerr << "Error: " << sMessage << endl; } }; diff --git a/c++/include/objtools/readers/agp_util.hpp b/c++/include/objtools/readers/agp_util.hpp index 4dc147b8..d4ede270 100644 --- a/c++/include/objtools/readers/agp_util.hpp +++ b/c++/include/objtools/readers/agp_util.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS___AGP_UTIL__HPP #define OBJTOOLS_READERS___AGP_UTIL__HPP -/* $Id: agp_util.hpp 465301 2015-04-20 16:41:10Z sapojnik $ +/* $Id: agp_util.hpp 529955 2017-03-09 15:41:40Z sapojnik $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -423,6 +423,8 @@ protected: { // m_prev_row = the last line of the scaffold -- // usually component, but could be non-breaking gap (which generates a warning) + + // this function should not use m_this_row, which may be undefined (when at the end of the file), or not relevant (elsewhere) } virtual void OnObjectChange() diff --git a/c++/include/objtools/readers/aln_reader.hpp b/c++/include/objtools/readers/aln_reader.hpp index 0050f34a..a6ec0d2b 100644 --- a/c++/include/objtools/readers/aln_reader.hpp +++ b/c++/include/objtools/readers/aln_reader.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS___ALN_READER__HPP #define OBJTOOLS_READERS___ALN_READER__HPP -/* $Id: aln_reader.hpp 505117 2016-06-22 15:06:00Z foleyjp $ +/* $Id: aln_reader.hpp 534219 2017-04-25 15:59:05Z ludwigf $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,7 +34,11 @@ #include #include +#include #include +#include +#include + BEGIN_NCBI_SCOPE @@ -86,7 +90,6 @@ private: class NCBI_XOBJREAD_EXPORT CAlnReader { public: - // alphabets to try enum EAlphabet { eAlpha_Nucleotide, @@ -140,7 +143,7 @@ public: SetAllGap(".-"); }; // destructor - ~CAlnReader(void); + virtual ~CAlnReader(void); @@ -189,8 +192,6 @@ public: /// that would parse the alignment file and create the result data void Read(bool guess=false, bool generate_local_ids=false); - - /// Parsed result data accessors const vector& GetIds(void) const {return m_Ids;}; const vector& GetSeqs(void) const {return m_Seqs;}; @@ -200,9 +201,10 @@ public: const TErrorList& GetErrorList(void) const {return m_Errors;}; + using TFastaFlags = objects::CFastaDeflineReader::TFastaFlags; /// Create ASN.1 classes from the parsed alignment - CRef GetSeqAlign(void); - CRef GetSeqEntry(void); + CRef GetSeqAlign(TFastaFlags fasta_flags=0); + CRef GetSeqEntry(TFastaFlags fasta_flags=0); private: @@ -210,7 +212,11 @@ private: CAlnReader(const CAlnReader& value); CAlnReader& operator=(const CAlnReader& value); + int x_GetGCD(const int a, const int b) const; + bool x_IsReplicatedSequence(const char* sequence_data, + int sequence_length, + int repeat_interval) const; /// A bunch of strings listing characters with various /// meanings in an alignment file. @@ -242,6 +248,43 @@ private: vector m_SeqVec; vector m_SeqLen; TErrorList m_Errors; + + /// characters have different contexts, depending on + /// whether they are before the first non-gap character, + /// after the last non-gap character, or between the + /// first and last non-gap character. This must be + /// precalculated before gap characters can be converted. + typedef pair TAlignMiddleInterval; + typedef vector TAlignMiddles; + TAlignMiddles m_MiddleSections; + void x_CalculateMiddleSections(); + typedef objects::CDense_seg::TDim TNumrow; + bool x_IsGap(TNumrow row, TSeqPos pos, const string& residue); + void x_AssignDensegIds( + TFastaFlags fasta_flags, + objects::CDense_seg& denseg); +protected: + virtual CRef GenerateID(const string& fasta_defline, + const TSeqPos& line_number, + TFastaFlags fasta_flags); + + using SLineTextAndLoc = objects::CFastaDeflineReader::SLineTextAndLoc; + using TSeqTitles = objects::CFastaDeflineReader::TSeqTitles; + using SDeflineParseInfo = objects::CFastaDeflineReader::SDeflineParseInfo; + using TIgnoredProblems = objects::CFastaDeflineReader::TIgnoredProblems; + + void ParseDefline(const string& defline, + const SDeflineParseInfo& info, + const TIgnoredProblems& ignoredErrors, + list>& ids, + bool& hasRange, + TSeqPos& rangeStart, + TSeqPos& rangeEnd, + TSeqTitles& seqTitles, + objects::ILineErrorListener* pMessageListener); + +protected: + objects::CFastaIdHandler m_FastaIdHandler; }; diff --git a/c++/include/objtools/readers/bed_reader.hpp b/c++/include/objtools/readers/bed_reader.hpp index 6f56d800..1e1d5248 100644 --- a/c++/include/objtools/readers/bed_reader.hpp +++ b/c++/include/objtools/readers/bed_reader.hpp @@ -1,4 +1,4 @@ -/* $Id: bed_reader.hpp 515629 2016-10-04 17:46:33Z ivanov $ +/* $Id: bed_reader.hpp 532427 2017-04-05 12:45:59Z ludwigf $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -61,8 +61,8 @@ public: { m_pInterval.Reset(new CSeq_interval()); m_pInterval->SetId(id); - m_pInterval->SetFrom(start-1); - m_pInterval->SetTo(stop-2); + m_pInterval->SetFrom(start); + m_pInterval->SetTo(stop-1); m_pInterval->SetStrand(strand); }; diff --git a/c++/include/objtools/readers/fasta.hpp b/c++/include/objtools/readers/fasta.hpp index 72e2d90b..e5e22309 100644 --- a/c++/include/objtools/readers/fasta.hpp +++ b/c++/include/objtools/readers/fasta.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS___FASTA__HPP #define OBJTOOLS_READERS___FASTA__HPP -/* $Id: fasta.hpp 515641 2016-10-04 17:51:17Z ivanov $ +/* $Id: fasta.hpp 538706 2017-06-13 16:56:56Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -62,7 +63,7 @@ BEGIN_SCOPE(objects) class CSeq_entry; class CSeq_loc; -class CSeqIdGenerator; +//class CSeqIdGenerator; class ILineErrorListener; @@ -153,12 +154,13 @@ public: const CBioseq::TId& GetIDs(void) const { return m_CurrentSeq->GetId(); } const CSeq_id& GetBestID(void) const { return *m_BestID; } - const CSeqIdGenerator& GetIDGenerator(void) const { return *m_IDGenerator; } - CSeqIdGenerator& SetIDGenerator(void) { return *m_IDGenerator; } + const CSeqIdGenerator& GetIDGenerator(void) const { return m_IDHandler->GetGenerator(); } + CSeqIdGenerator& SetIDGenerator(void) { return m_IDHandler->SetGenerator(); } void SetIDGenerator(CSeqIdGenerator& gen); /// Re-allow previously seen IDs even if fUniqueIds is on. - void ResetIDTracker(void) { m_IDTracker.clear(); } + //void ResetIDTracker(void) { m_IDTracker.clear(); } + void ResetIDTracker(void) { m_IDHandler->ClearIdCache(); } const CSourceModParser::TMods & GetUnusedMods(void) const { return m_UnusedMods; } const CSourceModParser::TMods & GetBadMods(void) const { return m_BadMods; } @@ -190,27 +192,13 @@ public: void IgnoreProblem(ILineError::EProblem problem); - struct SLineTextAndLoc { - SLineTextAndLoc( - const string & sLineText, - TSeqPos iLineNum ) - : m_sLineText(sLineText), - m_iLineNum(iLineNum) { } - - string m_sLineText; - TSeqPos m_iLineNum; - }; + using SLineTextAndLoc = CFastaDeflineReader::SLineTextAndLoc; using TIgnoredProblems = vector; using TSeqTitles = vector; typedef CTempString TStr; - struct SDefLineParseInfo { - TReaderFlags fBaseFlags; - TFlags fFastaFlags; - size_t maxIdLength; - size_t lineNumber; - }; + using SDefLineParseInfo = CFastaDeflineReader::SDeflineParseInfo; static void ParseDefLine(const TStr& defLine, const SDefLineParseInfo& info, @@ -235,6 +223,12 @@ protected: virtual bool ParseIDs(const TStr& s, ILineErrorListener * pMessageListener); + virtual void PostProcessIDs(const CBioseq::TId& defline_ids, + const string& defline, + bool has_range=false, + TSeqPos range_start=kInvalidSeqPos, + TSeqPos range_end=kInvalidSeqPos); + static bool ParseIDs (const TStr& s, const SDefLineParseInfo& info, const TIgnoredProblems& ignoredErrors, @@ -266,15 +260,6 @@ protected: ILineError::EProblem _eProblem, CTempString _sFeature, CTempString _sQualName, CTempString _sQualValue) const; - static void PostWarning(ILineErrorListener* pMessageListener, - const size_t lineNumber, - const string& errMessage, - CObjReaderParseException::EErrCode errCode); - - static void PostError(ILineErrorListener* pMessageListener, - const size_t lineNumber, - const string& errMessage, - CObjReaderParseException::EErrCode errCode); typedef int TRowNum; typedef map TSubMap; @@ -288,7 +273,12 @@ protected: void x_AddMultiwayAlignment(CSeq_annot& annot, const TIds& ids); // inline utilities - void CloseGap(bool atStartOfLine=true, ILineErrorListener * pMessageListener = 0); + void CloseGap(bool atStartOfLine=true, ILineErrorListener * pMessageListener = 0) { + if (m_CurrentGapLength > 0) { + x_CloseGap(m_CurrentGapLength, atStartOfLine, pMessageListener); + m_CurrentGapLength = 0; + } + } void OpenMask(void); void CloseMask(void) { if (m_MaskRangeStart != kInvalidSeqPos) { x_CloseMask(); } } @@ -360,6 +350,14 @@ protected: SGap & operator = (const SGap & ); SGap(const SGap & rhs); }; + + CRef xCreateAlignment(CRef old_id, + CRef new_id, + TSeqPos range_start, + TSeqPos range_end); + + bool xSetSeqMol(const list>& ids, CSeq_inst_Base::EMol& mol); + typedef CRef TGapRef; typedef vector TGaps; typedef set TIDTracker; @@ -371,11 +369,12 @@ protected: TMask m_CurrentMask; TMask m_NextMask; TMasks * m_MaskVec; - CRef m_IDGenerator; + NCBI_DEPRECATED CRef m_IDGenerator; + CRef m_IDHandler; string m_SeqData; TGaps m_Gaps; TSeqPos m_CurrentPos; // does not count gaps - TSeqPos m_ExpectedEnd; + NCBI_DEPRECATED TSeqPos m_ExpectedEnd; TSeqPos m_MaskRangeStart; TSeqPos m_SegmentBase; TSeqPos m_CurrentGapLength; @@ -401,35 +400,6 @@ protected: }; -class NCBI_XOBJREAD_EXPORT CSeqIdGenerator : public CObject -{ -public: - typedef CAtomicCounter::TValue TInt; - CSeqIdGenerator(TInt counter = 1, const string& prefix = kEmptyStr, - const string& suffix = kEmptyStr) - : m_Prefix(prefix), - m_Suffix(suffix), - m_Counter(counter) - { } - - CRef GenerateID(bool advance); - /// Equivalent to GenerateID(false) - CRef GenerateID(void) const; - - const string& GetPrefix (void) { return m_Prefix; } - TInt GetCounter(void) { return m_Counter.Get(); } - const string& GetSuffix (void) { return m_Suffix; } - - void SetPrefix (const string& s) { m_Prefix = s; } - void SetCounter(TInt n) { m_Counter.Set(n); } - void SetSuffix (const string& s) { m_Suffix = s; } - -protected: - string m_Prefix, m_Suffix; - CAtomicCounter_WithAutoInit m_Counter; -}; - - enum EReadFastaFlags { fReadFasta_AssumeNuc = CFastaReader::fAssumeNuc, fReadFasta_AssumeProt = CFastaReader::fAssumeProt, @@ -444,7 +414,10 @@ enum EReadFastaFlags { typedef CFastaReader::TFlags TReadFastaFlags; -/// Traditional interface for reading FASTA files. +/// Traditional interface for reading FASTA files which is not +/// just deprecated but dangerous due to an unsafe reinterpret_cast that +/// occurs within and affects the caller's params. +/// /// @deprecated /// @sa CFastaReader NCBI_DEPRECATED @@ -520,9 +493,11 @@ TSeqPos CFastaReader::GetCurrentPos(EPosType pos_type) TSeqPos pos = m_CurrentPos; switch (pos_type) { case ePosWithGapsAndSegs: - pos += m_SegmentBase; // fall through + pos += m_SegmentBase; + // FALL THROUGH!! case ePosWithGaps: - pos += m_TotalGapLength; // fall through + pos += m_TotalGapLength; + // FALL THROUGH!! case eRawPos: return pos; default: diff --git a/c++/include/objtools/readers/fasta_reader_utils.hpp b/c++/include/objtools/readers/fasta_reader_utils.hpp new file mode 100644 index 00000000..ee783f89 --- /dev/null +++ b/c++/include/objtools/readers/fasta_reader_utils.hpp @@ -0,0 +1,220 @@ +#ifndef FASTA_READER_UTILS_HPP +#define FASTA_READER_UTILS_HPP + +/* $Id: fasta_reader_utils.hpp 541540 2017-07-19 13:48:25Z ivanov $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Authors: Justin Foley +* +*/ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) + +class NCBI_XOBJREAD_EXPORT CFastaDeflineReader : public CReaderBase { + +public: + + using TFastaFlags = int; + using TBaseFlags = CReaderBase::TReaderFlags; + using TIgnoredProblems = vector; + + struct SLineTextAndLoc { + SLineTextAndLoc( + const string& sLineText, + TSeqPos iLineNum) + : m_sLineText(sLineText), + m_iLineNum(iLineNum) {} + string m_sLineText; + TSeqPos m_iLineNum; + }; + + using TSeqTitles = vector; // No reason this couldn't just be a map + + struct SDeflineParseInfo { + TBaseFlags fBaseFlags; + TFastaFlags fFastaFlags; + TSeqPos maxIdLength; + TSeqPos lineNumber; + }; + + static bool ParseIDs( + const string& id_string, + const SDeflineParseInfo& info, + const TIgnoredProblems& ignoredErrors, + list>& ids, + ILineErrorListener* pMessageListener); + + static void ParseDefline(const string& defline, + const SDeflineParseInfo& info, + const TIgnoredProblems& ignoredErrors, + list>& ids, + bool& hasRange, + TSeqPos& rangeStart, + TSeqPos& rangeEnd, + TSeqTitles& seqTitles, + ILineErrorListener* pMessageListener); + + static TSeqPos ParseRange(const string& s, + TSeqPos& start, + TSeqPos& end, + ILineErrorListener* pMessageListener); + +private: + static void x_ProcessIDs( + const string& id_string, + const SDeflineParseInfo& info, + list>& ids, + ILineErrorListener* pMessageListener); + + static bool x_IsValidLocalID(const CSeq_id& id, + TFastaFlags fasta_flags); + + static bool x_IsValidLocalID(const string& id_string, + TFastaFlags fasta_flags); + + static void x_ConvertNumericToLocal( + list>& ids); + + static void x_PostWarning(ILineErrorListener* pMessageListener, + const TSeqPos lineNumber, + const string& errMessage, + const CObjReaderLineException::EProblem problem, + const CObjReaderParseException::EErrCode errCode); + + static void x_PostWarning(ILineErrorListener* pMessageListener, + const TSeqPos lineNumber, + const string& errMessage, + const CObjReaderParseException::EErrCode errCode); + + static void x_PostError(ILineErrorListener* pMessageListener, + const TSeqPos lineNumber, + const string& errMessage, + const CObjReaderParseException::EErrCode errCode); + + static bool x_ExcessiveSeqDataInTitle(const string& title, + TFastaFlags fasta_flags); + + static void x_CheckForExcessiveSeqDataInID( + const string& id_string, + const SDeflineParseInfo& info, + ILineErrorListener* pMessageListener); + + static bool x_ExceedsMaxLength(const string& title, + TSeqPos max_length); +}; + + +class NCBI_XOBJREAD_EXPORT CSeqIdGenerator : public CObject +{ +public: + typedef CAtomicCounter::TValue TCount; + CSeqIdGenerator(TCount count = 1, + const string& prefix = kEmptyStr, + const string& suffix = kEmptyStr) : + m_Prefix(prefix), + m_Suffix(suffix), + m_Counter(count) + {} + + + CRef GenerateID(const string& defline, bool advance); + CRef GenerateID(bool advance); + /// Equivalent to GenerateID(false) + CRef GenerateID(void) const; + + const string& GetPrefix (void) const { return m_Prefix; } + TCount GetCounter(void) const { return m_Counter.Get(); } + const string& GetSuffix (void) const { return m_Suffix; } + + void SetPrefix (const string& prefix) { m_Prefix = prefix; } + void SetCounter(TCount count) { m_Counter.Set(count); } + void SetSuffix (const string& suffix) { m_Suffix = suffix; } + +protected: + string m_Prefix; + string m_Suffix; + CAtomicCounter_WithAutoInit m_Counter; +}; + + +class NCBI_XOBJREAD_EXPORT CFastaIdHandler : public CObject +{ +public: + CFastaIdHandler(void) : mp_IdGenerator(new CSeqIdGenerator()) {} + + void SetGenerator(CSeqIdGenerator& generator) { + mp_IdGenerator.Reset(&generator); + } + + CSeqIdGenerator& SetGenerator(void) { + return *mp_IdGenerator; + } + + const CSeqIdGenerator& GetGenerator(void) const { + return *mp_IdGenerator; + } + + virtual CRef GenerateID(bool unique_id); + + virtual CRef GenerateID(const string& defline, bool unique_id=true); + + + void ClearIdCache(void) { + m_PreviousIdHandles.clear(); + } + + bool CacheIdHandle(CSeq_id_Handle idh) { + return m_PreviousIdHandles.insert(idh).second; + } + +protected: + + bool x_IsUniqueIdHandle(CSeq_id_Handle idh) { + return (m_PreviousIdHandles.find(idh) == m_PreviousIdHandles.end()); + } + + + using TIdHandleCache = set; + CRef mp_IdGenerator; + TIdHandleCache m_PreviousIdHandles; +}; + + +END_SCOPE(objects) +END_NCBI_SCOPE + +#endif diff --git a/c++/include/objtools/readers/gff2_data.hpp b/c++/include/objtools/readers/gff2_data.hpp index 1c4b42c8..97d214f8 100644 --- a/c++/include/objtools/readers/gff2_data.hpp +++ b/c++/include/objtools/readers/gff2_data.hpp @@ -1,4 +1,4 @@ -/* $Id: gff2_data.hpp 512392 2016-08-30 17:42:36Z ivanov $ +/* $Id: gff2_data.hpp 542725 2017-08-02 11:32:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -45,6 +45,8 @@ public: typedef map TAttributes; typedef TAttributes::iterator TAttrIt; typedef TAttributes::const_iterator TAttrCit; + using SeqIdResolver = CRef (*)(const string&, unsigned int, bool); + public: CGff2Record(); @@ -107,9 +109,11 @@ public: return false; }; CRef GetSeqId( - int ) const; + int, + SeqIdResolver = nullptr ) const; CRef GetSeqLoc( - int ) const; + int, + SeqIdResolver seqidresolve = nullptr) const; const TAttributes& Attributes() const { return m_Attributes; @@ -125,11 +129,13 @@ public: virtual bool InitializeFeature( int, - CRef ) const; + CRef, + SeqIdResolver = nullptr ) const; virtual bool UpdateFeature( int, - CRef ) const; + CRef, + SeqIdResolver = nullptr ) const; static void TokenizeGFF(vector& columns, const CTempStringEx& line); protected: @@ -162,24 +168,17 @@ protected: virtual bool x_InitFeatureLocation( int, - CRef ) const; + CRef, + SeqIdResolver = nullptr ) const; virtual bool xInitFeatureData( int, - CRef ) const; - virtual bool xInitFeatureDataBond( - int, - CRef ) const; - virtual bool xInitFeatureDataNcrna( - int, - CRef ) const; - virtual bool xInitFeatureDataSpecialImp( - int, - CRef ) const; + CRef) const; virtual bool xUpdateFeatureData( int, - CRef) const; + CRef, + SeqIdResolver = nullptr ) const; virtual bool x_MigrateAttributesSubSource( int, diff --git a/c++/include/objtools/readers/gff2_reader.hpp b/c++/include/objtools/readers/gff2_reader.hpp index 53f4248b..98b058b0 100644 --- a/c++/include/objtools/readers/gff2_reader.hpp +++ b/c++/include/objtools/readers/gff2_reader.hpp @@ -1,4 +1,4 @@ - /* $Id: gff2_reader.hpp 520506 2016-11-29 16:03:04Z ivanov $ + /* $Id: gff2_reader.hpp 542725 2017-08-02 11:32:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -61,7 +61,7 @@ class NCBI_XOBJREAD_EXPORT CGff2Reader public: typedef enum { fNormal = 0, - fNewCode = 0x1000, // for now don't clobber CGFFReader flags +// fNewCode = 0x1000, // for now don't clobber CGFFReader flags fGenbankMode = 0x2000, fRetainLocusIds = 0x4000, } TFlags; @@ -79,7 +79,8 @@ public: CGff2Reader( int iFlags, const string& name = "", - const string& title = "" ); + const string& title = "", + SeqIdResolver resolver = CReadUtil::AsSeqId); virtual ~CGff2Reader(); @@ -117,12 +118,6 @@ public: ILineReader&, ILineErrorListener* =0 ); - virtual void - ReadSeqAnnotsNew( - TAnnots&, - ILineReader&, - ILineErrorListener* =0 ); - // // class interface: // @@ -165,11 +160,6 @@ public: CRef&, const string& = ""); - virtual bool x_ParseDataGff( - const string&, - TAnnots&, - ILineErrorListener*); - virtual bool x_ParseFeatureGff( const string&, TAnnots&, @@ -182,13 +172,12 @@ public: void x_GetAlignmentScores( const CSeq_align& alignment, - TScoreValueMap& score_values); - // map>& score_values); + TScoreValueMap& score_values) const; void x_FindMatchingScores( const TScoreValueMap& scores_1, const TScoreValueMap& scores_2, - set& matching_scores); + set& matching_scores) const; virtual bool x_CreateAlignment( const CGff2Record& gff, @@ -197,6 +186,13 @@ public: bool x_MergeAlignments( const list>& alignment_list, CRef& processed); + + void x_InitializeScoreSums(const TScoreValueMap score_values, + map& summed_scores) const; + + void x_ProcessAlignmentScores(const CSeq_align& alignment, + map& summed_scores, + TScoreValueMap& common_scores) const; void x_ProcessAlignmentsGff( const list& id_list, @@ -227,10 +223,6 @@ public: CRef< CSeq_feat >, CRef< CSeq_annot > ); - virtual bool x_FeatureSetId( - const CGff2Record&, - CRef< CSeq_feat > ); - bool x_FeatureSetQualifiers( const CGff2Record&, CRef< CSeq_feat > ); @@ -252,35 +244,6 @@ public: const CGff2Record&, CRef< CSeq_feat > ); - bool x_FeatureSetGffInfo( - const CGff2Record&, - CRef< CSeq_feat > ); - - bool x_FeatureSetData( - const CGff2Record&, - CRef< CSeq_feat > ); - - virtual bool x_FeatureSetDataGene( - const CGff2Record&, - CRef< CSeq_feat > ); - - virtual bool x_FeatureSetDataRna( - const CGff2Record&, - CRef< CSeq_feat >, - CSeqFeatData::ESubtype ); - - virtual bool x_FeatureSetDataCDS( - const CGff2Record&, - CRef< CSeq_feat > ); - - bool x_FeatureSetDataExon( - const CGff2Record&, - CRef< CSeq_feat > ); - - bool x_FeatureSetDataMiscFeature( - const CGff2Record&, - CRef< CSeq_feat > ); - bool x_GetFeatureById( const string&, CRef< CSeq_feat >& ); @@ -308,12 +271,22 @@ public: bool xSetDensegStarts( const vector& gapParts, - bool oppositeStrands, - size_t targetStart, + ENa_strand identStrand, + ENa_strand targetStrand, + const TSeqPos targetStart, + const TSeqPos targetEnd, const CGff2Record& gff, CSeq_align::C_Segs::TDenseg& denseg); - virtual bool xReadInit(); + bool xGetStartsOnMinusStrand(TSeqPos offset, + const vector& gapParts, + bool isTarget, + vector& starts) const; + + bool xGetStartsOnPlusStrand(TSeqPos offset, + const vector& gapParts, + bool isTarget, + vector& starts) const; virtual bool xAnnotPostProcess( CRef); @@ -334,11 +307,18 @@ public: bool xGetTargetParts(const CGff2Record& gff, vector& targetParts) const; - bool xAlignmentSetSegment( const CGff2Record&, CRef ); + bool xAlignmentSetDenseg( + const CGff2Record&, + CRef ); + + bool xAlignmentSetSpliced_seg( + const CGff2Record&, + CRef ); + static CRef< CDbtag > x_ParseDbtag( const string& ); @@ -355,6 +335,9 @@ public: virtual bool xIsIgnoredFeatureType( const string&); + virtual bool xIsIgnoredFeatureId( + const string&); + static bool IsExon( CRef< CSeq_feat > ); @@ -388,6 +371,10 @@ protected: CSeq_feat&, CSeq_feat&); + void xSetXrefFromTo( + CSeq_feat&, + CSeq_feat&); + // data: // protected: diff --git a/c++/include/objtools/readers/gff3_reader.hpp b/c++/include/objtools/readers/gff3_reader.hpp index 233258e0..441d444b 100644 --- a/c++/include/objtools/readers/gff3_reader.hpp +++ b/c++/include/objtools/readers/gff3_reader.hpp @@ -1,4 +1,4 @@ - /* $Id: gff3_reader.hpp 506819 2016-07-12 14:49:11Z ludwigf $ + /* $Id: gff3_reader.hpp 542725 2017-08-02 11:32:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -86,7 +86,8 @@ public: CGff3Reader( unsigned int uFlags, const string& name = "", - const string& title = "" ); + const string& title = "", + SeqIdResolver resolver = CReadUtil::AsSeqId); virtual ~CGff3Reader(); diff --git a/c++/include/objtools/readers/gff3_sofa.hpp b/c++/include/objtools/readers/gff3_sofa.hpp index 771fdf2a..327ed2af 100644 --- a/c++/include/objtools/readers/gff3_sofa.hpp +++ b/c++/include/objtools/readers/gff3_sofa.hpp @@ -1,4 +1,4 @@ -/* $Id: gff3_sofa.hpp 520685 2016-11-30 18:53:22Z ivanov $ +/* $Id: gff3_sofa.hpp 520541 2016-11-29 18:22:27Z ludwigf $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/readers/gtf_reader.hpp b/c++/include/objtools/readers/gtf_reader.hpp index d1bcbcbf..955e0cb9 100644 --- a/c++/include/objtools/readers/gtf_reader.hpp +++ b/c++/include/objtools/readers/gtf_reader.hpp @@ -1,4 +1,4 @@ - /* $Id: gtf_reader.hpp 506324 2016-07-06 17:22:57Z ludwigf $ + /* $Id: gtf_reader.hpp 543903 2017-08-15 14:52:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -65,7 +65,11 @@ public: fGenerateChildXrefs = 1<<8, }; - CGtfReader( unsigned int =0, const string& = "", const string& = "" ); + CGtfReader( + unsigned int =0, + const string& = "", + const string& = "", + SeqIdResolver = CReadUtil::AsSeqId ); virtual ~CGtfReader(); @@ -84,6 +88,9 @@ public: protected: virtual CGff2Record* x_CreateRecord() { return new CGtfReadRecord(); }; + bool xNeedsNewSeqAnnot( + const string&); + virtual bool x_UpdateAnnotFeature( const CGff2Record&, CRef< CSeq_annot >, @@ -93,39 +100,7 @@ protected: const CGff2Record&, CRef< CSeq_annot > ); - virtual bool x_UpdateAnnotStartCodon( - const CGff2Record&, - CRef< CSeq_annot > ); - - virtual bool x_UpdateAnnotStopCodon( - const CGff2Record&, - CRef< CSeq_annot > ); - - virtual bool x_UpdateAnnot5utr( - const CGff2Record&, - CRef< CSeq_annot > ); - - virtual bool x_UpdateAnnot3utr( - const CGff2Record&, - CRef< CSeq_annot > ); - - virtual bool x_UpdateAnnotInter( - const CGff2Record&, - CRef< CSeq_annot > ); - - virtual bool x_UpdateAnnotInterCns( - const CGff2Record&, - CRef< CSeq_annot > ); - - virtual bool x_UpdateAnnotIntronCns( - const CGff2Record&, - CRef< CSeq_annot > ); - - virtual bool x_UpdateAnnotExon( - const CGff2Record&, - CRef< CSeq_annot > ); - - virtual bool x_UpdateAnnotMiscFeature( + virtual bool x_UpdateAnnotTranscript( const CGff2Record&, CRef< CSeq_annot > ); @@ -146,6 +121,10 @@ protected: const CGff2Record&, CRef< CSeq_feat > ); + bool x_CreateCdsXrefs( + const CGff2Record&, + CRef< CSeq_feat > ); + bool x_MergeFeatureLocationSingleInterval( const CGff2Record&, CRef< CSeq_feat > ); @@ -166,6 +145,14 @@ protected: const CGff2Record& record, CRef); + bool xFeatureSetQualifiersRna( + const CGff2Record& record, + CRef); + + bool xFeatureSetQualifiersCds( + const CGff2Record& record, + CRef); + bool x_CreateParentCds( const CGff2Record&, CRef< CSeq_annot > ); @@ -182,6 +169,11 @@ protected: const CGff2Record&, CRef< CSeq_feat > ); + virtual bool x_FeatureSetDataRna( + const CGff2Record&, + CRef< CSeq_feat >, + CSeqFeatData::ESubtype ); + bool x_FeatureSetDataMRNA( const CGff2Record&, CRef< CSeq_feat > ); @@ -210,6 +202,7 @@ protected: bool x_CdsIsPartial( const CGff2Record& ); + string m_CurrentSeqId; typedef map< string, CRef< CSeq_feat > > TIdToFeature; TIdToFeature m_GeneMap; TIdToFeature m_CdsMap; diff --git a/c++/include/objtools/readers/gvf_reader.hpp b/c++/include/objtools/readers/gvf_reader.hpp index 085d13dc..271e9a3c 100644 --- a/c++/include/objtools/readers/gvf_reader.hpp +++ b/c++/include/objtools/readers/gvf_reader.hpp @@ -1,4 +1,4 @@ - /* $Id: gvf_reader.hpp 515629 2016-10-04 17:46:33Z ivanov $ + /* $Id: gvf_reader.hpp 513672 2016-09-14 14:10:57Z ludwigf $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/readers/line_error.hpp b/c++/include/objtools/readers/line_error.hpp index 9d2c5ddf..cec5b91e 100644 --- a/c++/include/objtools/readers/line_error.hpp +++ b/c++/include/objtools/readers/line_error.hpp @@ -1,4 +1,4 @@ -/* $Id: line_error.hpp 472138 2015-07-07 16:07:55Z grichenk $ +/* $Id: line_error.hpp 543084 2017-08-07 15:24:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -87,6 +87,7 @@ public: eProblem_IgnoredResidue, eProblem_DiscouragedFeatureName, eProblem_DiscouragedQualifierName, + eProblem_InvalidQualifier, //vcf specific eProblem_BadInfoLine, @@ -247,6 +248,8 @@ public: return "Feature had invalid length, but this was automatically corrected."; case eProblem_IgnoredResidue: return "An invalid residue has been ignored"; + case eProblem_InvalidQualifier: + return "Invalid qualifier for feature"; case eProblem_BadInfoLine: return "Broken ##INFO line"; diff --git a/c++/include/objtools/readers/microarray_reader.hpp b/c++/include/objtools/readers/microarray_reader.hpp index 0814751a..03fa1ca1 100644 --- a/c++/include/objtools/readers/microarray_reader.hpp +++ b/c++/include/objtools/readers/microarray_reader.hpp @@ -1,4 +1,4 @@ -/* $Id: microarray_reader.hpp 515629 2016-10-04 17:46:33Z ivanov $ +/* $Id: microarray_reader.hpp 513672 2016-09-14 14:10:57Z ludwigf $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/readers/reader_base.hpp b/c++/include/objtools/readers/reader_base.hpp index c78a0a90..7d69a0c4 100644 --- a/c++/include/objtools/readers/reader_base.hpp +++ b/c++/include/objtools/readers/reader_base.hpp @@ -1,4 +1,4 @@ -/* $Id: reader_base.hpp 515629 2016-10-04 17:46:33Z ivanov $ +/* $Id: reader_base.hpp 542725 2017-08-02 11:32:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -40,6 +40,7 @@ #include #include #include +#include BEGIN_NCBI_SCOPE @@ -83,12 +84,15 @@ public: typedef TAnnots::iterator TAnnotIt; typedef TAnnots::const_iterator TAnnotCit; + using SeqIdResolver = CRef (*)(const string&, unsigned int, bool); + protected: /// Protected constructor. Use GetReader() to get an actual reader object. CReaderBase( TReaderFlags flags = 0, //flags const string& name = "", //annot name - const string& title = "" ); //annot title + const string& title = "", //annot title + SeqIdResolver seqresolver = CReadUtil::AsSeqId); public: @@ -324,10 +328,12 @@ protected: TReaderFlags m_iFlags; string m_AnnotName; string m_AnnotTitle; + string m_PendingLine; CTrackData* m_pTrackDefaults; ILineReader* m_pReader; ICanceled* m_pCanceler; + SeqIdResolver mSeqIdResolve; }; END_objects_SCOPE diff --git a/c++/include/objtools/readers/reader_exception.hpp b/c++/include/objtools/readers/reader_exception.hpp index 12cf2b38..58b5156a 100644 --- a/c++/include/objtools/readers/reader_exception.hpp +++ b/c++/include/objtools/readers/reader_exception.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS___READER_EXCEPTION__HPP #define OBJTOOLS_READERS___READER_EXCEPTION__HPP -/* $Id: reader_exception.hpp 434647 2014-05-09 12:28:25Z gotvyans $ +/* $Id: reader_exception.hpp 543881 2017-08-15 13:56:46Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -58,7 +58,8 @@ public: eUnusedMods, eIDTooLong, eNoResidues, - eWrongGap + eWrongGap, + eInvalidID }; virtual const char* GetErrCodeString(void) const { @@ -74,6 +75,7 @@ public: case eIDTooLong: return "eIDTooLong"; case eNoResidues: return "eNoResidues"; case eWrongGap: return "eWrongGap"; + case eInvalidID: return "eInvalidID"; default: return CException::GetErrCodeString(); } } diff --git a/c++/include/objtools/readers/reader_idgen.hpp b/c++/include/objtools/readers/reader_idgen.hpp index 30849364..5bbe2e53 100644 --- a/c++/include/objtools/readers/reader_idgen.hpp +++ b/c++/include/objtools/readers/reader_idgen.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS___READER_IDGEN__HPP #define OBJTOOLS_READERS___READER_IDGEN__HPP -/* $Id: reader_idgen.hpp 342960 2011-11-02 13:21:22Z dicuccio $ +/* $Id: reader_idgen.hpp 542550 2017-08-01 12:44:40Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -138,7 +138,7 @@ public: TId GenerateId() { CRef id(new CFeat_id); - id->SetLocal().SetId(m_Id.Add(1) - 1); + id->SetLocal().SetId((int)(m_Id.Add(1) - 1)); return id; } diff --git a/c++/include/objtools/readers/readfeat.hpp b/c++/include/objtools/readers/readfeat.hpp index ba431877..1a46dbce 100644 --- a/c++/include/objtools/readers/readfeat.hpp +++ b/c++/include/objtools/readers/readfeat.hpp @@ -69,7 +69,8 @@ public: fCreateGenesFromCDSs = (1<<4), ///< = 0x10 (If a CDS has a gene xref, create a gene with the same intervals if one doesn't already exist.) fCDSsMustBeInTheirGenes = (1<<5), ///< = 0x20 (If a CDS has a gene xref, it *must* be inside of that gene) fReportDiscouragedKey = (1<<6), ///< = 0x40 (Report discouraged keys into the error container) - fLeaveProteinIds = (1<<7) ///< = 0x80 (Leave all protein_id as a qualifiers) + fLeaveProteinIds = (1<<7), ///< = 0x80 (Leave all protein_id as a qualifiers) + fAllIdsAsLocal = (1<<8), ///< = 0xA0 (Do not attempt to parse accessions) }; typedef int TFlags; diff --git a/c++/include/objtools/readers/source_mod_parser.hpp b/c++/include/objtools/readers/source_mod_parser.hpp index b1ab343e..43289673 100644 --- a/c++/include/objtools/readers/source_mod_parser.hpp +++ b/c++/include/objtools/readers/source_mod_parser.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS___SOURCE_MOD_PARSER__HPP #define OBJTOOLS_READERS___SOURCE_MOD_PARSER__HPP -/* $Id: source_mod_parser.hpp 493669 2016-03-01 16:52:34Z gotvyans $ +/* $Id: source_mod_parser.hpp 542051 2017-07-25 16:55:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,6 +34,7 @@ /// Parser for source modifiers, as found in (Sequin-targeted) FASTA files. #include +#include #include #include @@ -111,7 +112,7 @@ public: // void ApplyMods(CSubmit_block& sb); void ApplyTPAMods(CUser_object& tpa); void ApplyGenomeProjectsDBMods(CUser_object& gpdb); - void ApplyPubMods(CSeq_descr& sd); + void ApplyPubMods(CBioseq& seq); static int CompareKeys(const CTempString& lhs, const CTempString& rhs); @@ -122,16 +123,24 @@ public: struct PKeyEqual { bool operator()(const CTempString& lhs, const CTempString& rhs) const - { return CompareKeys(lhs, rhs) == 0; } + { return EqualKeys(lhs, rhs); } }; + // more efficient than CompareKeys when you're just looking for equality. + static bool EqualKeys(const CTempString& lhs, const CTempString& rhs); + struct SMod { CConstRef seqid; string key; string value; - size_t pos; - bool used; + size_t pos = 0; + bool used = false; + + SMod(void) = default; + // This is usually used for making SMods as keys for searching maps + // and such. + explicit SMod(const CTempString & the_key) : key(the_key) { } bool operator < (const SMod& rhs) const; string ToString(void) const; @@ -166,19 +175,31 @@ public: const string & sAllowedValues ); }; + /// Used for passing an empty mod to some funcs without having to + /// constantly recreate an empty one. + static CSafeStatic kEmptyMod; + + const TMods & GetAllMods(void) const { return m_Mods; } + /// Return all modifiers matching the given criteria (if any) without - /// affecting their status (used vs. unused). + /// affecting their status (used vs. unused). If you want all mods, if + /// possible use GetAllMods since gives ref instead of copying underlying structure. TMods GetMods(TWhichMods which = fAllMods) const; /// If a modifier with either key is present, mark it as used and /// return it; otherwise, return NULL. - const SMod* FindMod(const CTempString& key, - CTempString alt_key = kEmptyStr); + const SMod* FindMod(const SMod & smod, + const SMod & alt_smod = kEmptyMod.Get()); /// Return all modifiers with the given key (e.g., db_xref), marking them /// as used along the way. TModsRange FindAllMods(const CTempString& key); + /// Return all modifiers with the given key (e.g., db_xref), marking them + /// as used along the way. + TModsRange FindAllMods(const SMod & smod, + const SMod & alt_smod = kEmptyMod.Get()); + /// Append a representation of the specified modifiers to s, with a space /// in between if s is not empty and doesn't already end with one. void GetLabel(string* s, TWhichMods which = fAllMods) const; @@ -297,10 +318,8 @@ int CSourceModParser::CompareKeys(const CTempString& lhs, while (it != lhs.end() && it2 != rhs.end()) { unsigned char uc1 = kKeyCanonicalizationTable[(unsigned char)*it++]; unsigned char uc2 = kKeyCanonicalizationTable[(unsigned char)*it2++]; - if (uc1 > uc2) { - return 1; - } else if (uc1 < uc2) { - return -1; + if( uc1 != uc2 ) { + return ((uc1 < uc2) ? -1 : 1); } } if (it == lhs.end()) { @@ -310,6 +329,19 @@ int CSourceModParser::CompareKeys(const CTempString& lhs, } } +inline +bool CSourceModParser::EqualKeys(const CTempString& lhs, + const CTempString& rhs) +{ + // optimization for cases where they obviously aren't equal + if( lhs.length() != rhs.length() ) { + return false; + } else { + // not in optimized case so fall back on using CompareKeys + return CompareKeys(lhs, rhs) == 0; + } +} + inline bool CSourceModParser::SMod::operator <(const SMod& rhs) const diff --git a/c++/include/objtools/readers/struct_cmt_reader.hpp b/c++/include/objtools/readers/struct_cmt_reader.hpp index 7537ef0b..7c66cbfc 100644 --- a/c++/include/objtools/readers/struct_cmt_reader.hpp +++ b/c++/include/objtools/readers/struct_cmt_reader.hpp @@ -24,18 +24,18 @@ class ILineReader; CStructuredCommentsReader reader(error_logger); - std::list comments; + std::list comments; ILineReader reader1(ILineReader::New(filename); reader.LoadComments(reader1, comments); - for (const CStructuredCommentsReader::TStructComment& cmt: comments) + for (const CStructuredCommentsReader::CStructComment& cmt: comments) { // do something } */ -class CStructuredCommentsReader +class NCBI_XOBJREAD_EXPORT CStructuredCommentsReader { public: // If you need messages and error to be logged @@ -43,22 +43,23 @@ public: CStructuredCommentsReader(objects::ILineErrorListener* logger); ~CStructuredCommentsReader(); - typedef struct { + class NCBI_XOBJREAD_EXPORT CStructComment + { + public: CRef m_id; vector > m_descs; - } TStructComment; + static const string& GetPrefix(const objects::CSeqdesc&); + }; -#if 0 template - size_t LoadComments(ILineReader& reader, _container& cont) + size_t LoadComments(ILineReader& reader, _container& cont, + objects::CSeq_id::TParseFlags seqid_flags = objects::CSeq_id::fParse_Default) { vector cols; _LoadHeaderLine(reader, cols); if (cols.empty()) return 0; - size_t loader = 0; - while (!reader.AtEOF()) { reader.ReadLine(); @@ -73,20 +74,41 @@ public: if (!values[0].empty()) { // try to find destination sequence - cont.push_back(TStructComment()); - TStructComment& cmt = cont.back(); - cmt.m_id.Reset(new objects::CSeq_id(values[0], objects::CSeq_id::fParse_AnyLocal)); + cont.push_back(CStructComment()); + CStructComment& cmt = cont.back(); + cmt.m_id.Reset(new objects::CSeq_id(values[0], seqid_flags)); _BuildStructuredComment(cmt, cols, values); } } + return cont.size(); } -#endif - objects::CUser_object* FindStructuredComment(objects::CSeq_descr& descr); + size_t LoadCommentsByRow(ILineReader& reader, CStructComment& cmt) + { + objects::CUser_object* user = 0; + + while (!reader.AtEOF()) + { + reader.ReadLine(); + // First line is a collumn definitions + CTempString current = reader.GetCurrentLine(); + if (current.empty()) + continue; + + CTempString commentname, comment; + NStr::SplitInTwo(current, "\t", commentname, comment); + + // create new user object + user = _AddStructuredComment(user, cmt, commentname, comment); + } + return cmt.m_descs.size(); + } + + protected: void _LoadHeaderLine(ILineReader& reader, vector& cols); - void _BuildStructuredComment(TStructComment& cmt, const vector& cols, const vector& values); - objects::CUser_object* _AddStructuredComment(objects::CUser_object* user_obj, TStructComment& cmt, const CTempString& name, const CTempString& value); + void _BuildStructuredComment(CStructComment& cmt, const vector& cols, const vector& values); + objects::CUser_object* _AddStructuredComment(objects::CUser_object* user_obj, CStructComment& cmt, const CTempString& name, const CTempString& value); objects::ILineErrorListener* m_logger; }; diff --git a/c++/include/objtools/readers/track_data.hpp b/c++/include/objtools/readers/track_data.hpp index 51d64263..32a62569 100644 --- a/c++/include/objtools/readers/track_data.hpp +++ b/c++/include/objtools/readers/track_data.hpp @@ -1,4 +1,4 @@ -/* $Id: track_data.hpp 515629 2016-10-04 17:46:33Z ivanov $ +/* $Id: track_data.hpp 513672 2016-09-14 14:10:57Z ludwigf $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/readers/vcf_reader.hpp b/c++/include/objtools/readers/vcf_reader.hpp index b09940bb..ae9fec93 100644 --- a/c++/include/objtools/readers/vcf_reader.hpp +++ b/c++/include/objtools/readers/vcf_reader.hpp @@ -1,4 +1,4 @@ -/* $Id: vcf_reader.hpp 503934 2016-06-09 14:44:15Z foleyjp $ +/* $Id: vcf_reader.hpp 539451 2017-06-22 14:57:32Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -45,6 +45,7 @@ BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) // namespace ncbi::objects:: class CVcfData; +class CDbtag; // ---------------------------------------------------------------------------- enum ESpecType @@ -272,6 +273,11 @@ protected: CRef, ILineErrorListener*); + void xAssignVariantSource( + CVcfData&, + CRef, + ILineErrorListener*); + virtual bool xProcessScore( CVcfData&, @@ -307,6 +313,12 @@ protected: // // data: // +private: + bool + xAssigndbSNPTag( + const vector& ids, + CRef pDbtag) const; + protected: CRef< CAnnotdesc > m_Meta; map m_InfoSpecs; diff --git a/c++/include/objtools/readers/wiggle_reader.hpp b/c++/include/objtools/readers/wiggle_reader.hpp index b39a8751..3283dece 100644 --- a/c++/include/objtools/readers/wiggle_reader.hpp +++ b/c++/include/objtools/readers/wiggle_reader.hpp @@ -1,4 +1,4 @@ -/* $Id: wiggle_reader.hpp 511582 2016-08-23 15:29:38Z ivanov $ +/* $Id: wiggle_reader.hpp 510709 2016-08-15 16:53:17Z ludwigf $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/objtools/seqmasks_io/mask_bdb_reader.hpp b/c++/include/objtools/seqmasks_io/mask_bdb_reader.hpp index 177b41d5..7705bd48 100644 --- a/c++/include/objtools/seqmasks_io/mask_bdb_reader.hpp +++ b/c++/include/objtools/seqmasks_io/mask_bdb_reader.hpp @@ -1,4 +1,4 @@ -/* $Id: mask_bdb_reader.hpp 140909 2008-09-22 18:25:56Z ucko $ +/* $Id: mask_bdb_reader.hpp 539178 2017-06-19 17:07:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -80,7 +80,6 @@ private: CRef< CSeqDB > seqdb_; /**< BLAST database object. */ CSeqDB::TOID oid_; /**< Current OID (to be read). */ - bool is_nucleotide_; /**< BLAST database contains nucleotide sequences */ }; END_NCBI_SCOPE diff --git a/c++/include/objtools/seqmasks_io/mask_fasta_reader.hpp b/c++/include/objtools/seqmasks_io/mask_fasta_reader.hpp index 7365f4c8..25c31173 100644 --- a/c++/include/objtools/seqmasks_io/mask_fasta_reader.hpp +++ b/c++/include/objtools/seqmasks_io/mask_fasta_reader.hpp @@ -1,4 +1,4 @@ -/* $Id: mask_fasta_reader.hpp 140380 2008-09-17 13:23:48Z morgulis $ +/* $Id: mask_fasta_reader.hpp 539178 2017-06-19 17:07:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -57,7 +57,6 @@ public: CMaskFastaReader( CNcbiIstream & newInputStream, bool is_nucl = true, bool parse_seqids = false ) : CMaskReader( newInputStream ), is_nucleotide_(is_nucl), - parse_seqids_(parse_seqids), fasta_reader_( newInputStream, CONST_FLAGS | (is_nucl ? objects::CFastaReader::fAssumeNuc @@ -95,7 +94,6 @@ private: objects::CFastaReader::fAllSeqIds; bool is_nucleotide_; /**< This object is reading nucleotide sequences */ - bool parse_seqids_; /**< Should the Seq-ids be parsed? */ objects::CFastaReader fasta_reader_; /**< Fasta reader object. */ }; diff --git a/c++/include/serial/impl/enumerated.hpp b/c++/include/serial/impl/enumerated.hpp index a0e89119..d47e5253 100644 --- a/c++/include/serial/impl/enumerated.hpp +++ b/c++/include/serial/impl/enumerated.hpp @@ -1,7 +1,7 @@ #ifndef ENUMERATED__HPP #define ENUMERATED__HPP -/* $Id: enumerated.hpp 515165 2016-09-28 17:51:10Z ivanov $ +/* $Id: enumerated.hpp 514702 2016-09-23 19:04:51Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/include/serial/impl/objectio.inl b/c++/include/serial/impl/objectio.inl index caff0040..c4a0dbf3 100644 --- a/c++/include/serial/impl/objectio.inl +++ b/c++/include/serial/impl/objectio.inl @@ -1,7 +1,7 @@ #if defined(OBJECTIO__HPP) && !defined(OBJECTIO__INL) #define OBJECTIO__INL -/* $Id: objectio.inl 107919 2007-07-30 18:51:04Z vasilche $ +/* $Id: objectio.inl 529139 2017-03-01 17:43:15Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -52,6 +52,11 @@ const CObjectTypeInfo& CIStreamContainerIterator::GetContainerType(void) const { return m_ContainerType; } +inline +const CObjectTypeInfo CIStreamContainerIterator::GetElementType(void) const +{ + return m_ElementTypeInfo; +} inline const CObjectTypeInfo& COStreamContainer::GetContainerType(void) const diff --git a/c++/include/serial/impl/objistrasnb.inl b/c++/include/serial/impl/objistrasnb.inl index da5e6767..b794863d 100644 --- a/c++/include/serial/impl/objistrasnb.inl +++ b/c++/include/serial/impl/objistrasnb.inl @@ -1,7 +1,7 @@ #if defined(OBJISTRASNB__HPP) && !defined(OBJISTRASNB__INL) #define OBJISTRASNB__INL -/* $Id: objistrasnb.inl 507795 2016-07-21 17:24:14Z gouriano $ +/* $Id: objistrasnb.inl 512957 2016-09-06 14:50:26Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -278,7 +278,7 @@ void CObjectIStreamAsnBinary::ExpectIndefiniteLength(void) { // indefinite length allowed only for constructed tags #if CHECK_INSTREAM_LIMITS - if ( !GetTagConstructed(m_Input.PeekChar()) ) + if ( !IsTagConstructed(m_Input.PeekChar()) ) ThrowError(fIllegalCall, "illegal ExpectIndefiniteLength call"); _ASSERT(m_CurrentTagLimit == 0); // save tag limit diff --git a/c++/include/serial/impl/objstack.hpp b/c++/include/serial/impl/objstack.hpp index 49869952..8a9085e8 100644 --- a/c++/include/serial/impl/objstack.hpp +++ b/c++/include/serial/impl/objstack.hpp @@ -1,7 +1,7 @@ #ifndef OBJSTACK__HPP #define OBJSTACK__HPP -/* $Id: objstack.hpp 507795 2016-07-21 17:24:14Z gouriano $ +/* $Id: objstack.hpp 534119 2017-04-24 17:07:34Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -158,8 +158,13 @@ public: const TFrame& FetchFrameFromBottom(size_t index) const; TTypeInfo GetRecentTypeInfo(void) const; + static TTypeInfo GetRealTypeInfo(TTypeInfo typeInfo); + static ETypeFamily GetRealTypeFamily(TTypeInfo typeInfo); + static TTypeInfo GetContainerElementTypeInfo(TTypeInfo typeInfo); + static ETypeFamily GetContainerElementTypeFamily(TTypeInfo typeInfo); + virtual void UnendedFrame(void); - const string& GetStackPath(void); + const string& GetStackPath(void) const; void WatchPathHooks(bool set=true); protected: diff --git a/c++/include/serial/impl/objstrasnb.hpp b/c++/include/serial/impl/objstrasnb.hpp index 1ee00a76..c45f8ca4 100644 --- a/c++/include/serial/impl/objstrasnb.hpp +++ b/c++/include/serial/impl/objstrasnb.hpp @@ -1,7 +1,7 @@ #ifndef OBJSTRASNB__HPP #define OBJSTRASNB__HPP -/* $Id: objstrasnb.hpp 447162 2014-09-23 13:15:30Z gouriano $ +/* $Id: objstrasnb.hpp 512957 2016-09-06 14:50:26Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -161,6 +161,7 @@ public: static ETagValue GetTagValue(TByte byte); static ETagValue StringTag(EStringType type); static ETagConstructed GetTagConstructed(TByte byte); + static bool IsTagConstructed(TByte byte); static ETagClass GetTagClass(TByte byte); static TByte GetTagClassAndConstructed(TByte byte); }; diff --git a/c++/include/serial/impl/objstrasnb.inl b/c++/include/serial/impl/objstrasnb.inl index b29c16eb..1c4d4cf6 100644 --- a/c++/include/serial/impl/objstrasnb.inl +++ b/c++/include/serial/impl/objstrasnb.inl @@ -1,7 +1,7 @@ #if defined(OBJSTRASNB__HPP) && !defined(OBJSTRASNB__INL) #define OBJSTRASNB__INL -/* $Id: objstrasnb.inl 500790 2016-05-09 11:30:33Z ivanov $ +/* $Id: objstrasnb.inl 512957 2016-09-06 14:50:26Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -81,6 +81,13 @@ CAsnBinaryDefs::GetTagConstructed(TByte tag_byte) return ETagConstructed(tag_byte & eTagConstructedMask); } +inline +bool +CAsnBinaryDefs::IsTagConstructed(TByte tag_byte) +{ + return (tag_byte & eTagConstructedMask) != ePrimitive; +} + inline CAsnBinaryDefs::ETagClass CAsnBinaryDefs::GetTagClass(CAsnBinaryDefs::TByte tag_byte) { diff --git a/c++/include/serial/impl/stltypes.hpp b/c++/include/serial/impl/stltypes.hpp index a6b5fb37..30c2bf46 100644 --- a/c++/include/serial/impl/stltypes.hpp +++ b/c++/include/serial/impl/stltypes.hpp @@ -1,7 +1,7 @@ #ifndef STLTYPES__HPP #define STLTYPES__HPP -/* $Id: stltypes.hpp 474629 2015-07-30 14:03:40Z ucko $ +/* $Id: stltypes.hpp 529139 2017-03-01 17:43:15Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -252,6 +252,7 @@ public: container.allocation_size(container.size()); #endif container.push_back(TElementType()); + in.SetDiscardCurrObject(false); containerType->GetElementType()->ReadData(in, &container.back()); if (in.GetDiscardCurrObject()) { container.pop_back(); diff --git a/c++/include/serial/objectio.hpp b/c++/include/serial/objectio.hpp index ce77a52e..d8466736 100644 --- a/c++/include/serial/objectio.hpp +++ b/c++/include/serial/objectio.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTIO__HPP #define OBJECTIO__HPP -/* $Id: objectio.hpp 107919 2007-07-30 18:51:04Z vasilche $ +/* $Id: objectio.hpp 529139 2017-03-01 17:43:15Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -169,6 +169,7 @@ public: ~CIStreamContainerIterator(void); const CObjectTypeInfo& GetContainerType(void) const; + const CObjectTypeInfo GetElementType(void) const; bool HaveMore(void) const; DECLARE_OPERATOR_BOOL(HaveMore()); @@ -176,6 +177,7 @@ public: void NextElement(void); CIStreamContainerIterator& operator++(void); + CObjectInfo ReadElement(TObjectPtr container); void ReadElement(const CObjectInfo& element); void SkipElement(const CObjectTypeInfo& elementType); void SkipElement(void); @@ -206,6 +208,8 @@ private: CObjectTypeInfo m_ContainerType; TTypeInfo m_ElementTypeInfo; EState m_State; + const CContainerTypeInfo* m_ContainerTypeInfo; + const CItemInfo* m_Container; }; template diff --git a/c++/include/serial/objhook.hpp b/c++/include/serial/objhook.hpp index 2dc5288d..c17ec486 100644 --- a/c++/include/serial/objhook.hpp +++ b/c++/include/serial/objhook.hpp @@ -1,7 +1,7 @@ #ifndef OBJHOOK__HPP #define OBJHOOK__HPP -/* $Id: objhook.hpp 502193 2016-05-23 12:28:12Z gouriano $ +/* $Id: objhook.hpp 529265 2017-03-02 16:00:11Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -626,7 +626,7 @@ private: }; NCBI_XSERIAL_EXPORT -void Serial_FilterSkip(CObjectIStream& in, CObjectTypeInfo& ctype); +bool Serial_FilterSkip(CObjectIStream& in, const CObjectTypeInfo& ctype); /// Scan input stream, finding objects of requested type (TObject) only template @@ -637,13 +637,8 @@ void Serial_FilterObjects(CObjectIStream& in, CSerial_FilterObjectsHook CObjectTypeInfo request = CType(); request.SetLocalSkipHook(in, hook); request.SetLocalReadHook(in, new CSerial_FilterReadObjectsHook(hook)); - do { - try { - Serial_FilterSkip(in,root); - } catch ( CEofException& ) { - return; - } - } while (readall); + while (Serial_FilterSkip(in,root) && readall) + ; } /// Scan input stream, finding objects that are not derived from CSerialObject @@ -654,13 +649,8 @@ void Serial_FilterStdObjects(CObjectIStream& in, CSerial_FilterObjectsHook(); CObjectTypeInfo request = CStdTypeInfo::GetTypeInfo(); request.SetLocalSkipHook(in, hook); - do { - try { - Serial_FilterSkip(in,root); - } catch ( CEofException& ) { - return; - } - } while (readall); + while (Serial_FilterSkip(in,root) && readall) + ; } diff --git a/c++/include/serial/objistrasn.hpp b/c++/include/serial/objistrasn.hpp index 894c47a4..59ae0910 100644 --- a/c++/include/serial/objistrasn.hpp +++ b/c++/include/serial/objistrasn.hpp @@ -1,7 +1,7 @@ #ifndef OBJISTRASN__HPP #define OBJISTRASN__HPP -/* $Id: objistrasn.hpp 477149 2015-08-26 18:15:22Z vasilche $ +/* $Id: objistrasn.hpp 538251 2017-06-08 18:32:10Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -260,6 +260,24 @@ private: }; +inline +const char* operator>> (const char* s, CSerialObject& obj) +{ + CNcbiIstrstream in(s, strlen(s)); + in >> MSerial_AsnText >> obj; + return s + in.tellg(); +} + + +inline +string operator>> (const string& s, CSerialObject& obj) +{ + CNcbiIstrstream in(s.c_str()); + in >> MSerial_AsnText >> obj; + return s.substr(in.tellg()); +} + + /* @} */ diff --git a/c++/include/serial/objistrjson.hpp b/c++/include/serial/objistrjson.hpp index 10d0e16d..d1929897 100644 --- a/c++/include/serial/objistrjson.hpp +++ b/c++/include/serial/objistrjson.hpp @@ -1,7 +1,7 @@ #ifndef OBJISTRJSON__HPP #define OBJISTRJSON__HPP -/* $Id: objistrjson.hpp 480247 2015-09-29 14:08:47Z gouriano $ +/* $Id: objistrjson.hpp 532474 2017-04-05 15:51:46Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -209,13 +209,15 @@ private: bool GetChar(char c, bool skipWhiteSpace = false); void Expect(char c, bool skipWhiteSpace = false); void UnexpectedMember(const CTempString& id, const CItemsInfo& items); + template + Type x_UseMemberDefault(void); int ReadEscapedChar(bool* encoded=0); - char ReadEncodedChar(EStringType type = eStringTypeVisible, bool* encoded=0); + char ReadEncodedChar(EStringType type, bool& encoded); TUnicodeSymbol ReadUtf8Char(char c); string x_ReadString(EStringType type); - string x_ReadData(EStringType type = eStringTypeUTF8); - string x_ReadDataAndCheck(EStringType type = eStringTypeUTF8); + void x_ReadData(string& data, EStringType type = eStringTypeUTF8); + bool x_ReadDataAndCheck(string& data, EStringType type = eStringTypeUTF8); void x_SkipData(void); string ReadKey(void); string ReadValue(EStringType type = eStringTypeVisible); @@ -238,6 +240,8 @@ private: string m_LastTag; string m_RejectedTag; EBinaryDataFormat m_BinaryFormat; + CStringUTF8 m_Utf8Buf; + CStringUTF8::const_iterator m_Utf8Pos; }; /* @} */ diff --git a/c++/include/serial/objistrxml.hpp b/c++/include/serial/objistrxml.hpp index 542ff100..c17b9842 100644 --- a/c++/include/serial/objistrxml.hpp +++ b/c++/include/serial/objistrxml.hpp @@ -1,7 +1,7 @@ #ifndef OBJISTRXML__HPP #define OBJISTRXML__HPP -/* $Id: objistrxml.hpp 459636 2015-02-20 14:45:49Z gouriano $ +/* $Id: objistrxml.hpp 534655 2017-05-01 13:02:07Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -208,10 +208,6 @@ protected: void EndArrayElement(void); void CheckStdXml(const CClassTypeInfoBase* classType); - TTypeInfo GetRealTypeInfo(TTypeInfo typeInfo); - ETypeFamily GetRealTypeFamily(TTypeInfo typeInfo); - TTypeInfo GetContainerElementTypeInfo(TTypeInfo typeInfo); - ETypeFamily GetContainerElementTypeFamily(TTypeInfo typeInfo); virtual void BeginClass(const CClassTypeInfo* classInfo); virtual void EndClass(void); @@ -261,10 +257,11 @@ private: bool UseSpecialCaseRead(void); int ReadEscapedChar(char endingChar, bool* encoded=0); - int ReadEncodedChar(char endingChar, EStringType type = eStringTypeVisible, bool* encoded=0); + int ReadEncodedChar(char endingChar, EStringType type, bool& encoded); TUnicodeSymbol ReadUtf8Char(char ch); bool ReadCDSection(string& s); void ReadTagData(string& s, EStringType type = eStringTypeVisible); + void ReadWord(string& s, EStringType type = eStringTypeVisible); CTempString ReadName(char c); CTempString RejectedName(void); @@ -285,7 +282,7 @@ private: template Type x_UseMemberDefault(void); int x_VerifyChar(int); - int x_ReadEncodedChar(char endingChar, EStringType type, bool* encoded); + int x_ReadEncodedChar(char endingChar, EStringType type, bool& encoded); enum ETagState { eTagOutside, diff --git a/c++/include/serial/objostrasn.hpp b/c++/include/serial/objostrasn.hpp index c1433c46..f9ca97d3 100644 --- a/c++/include/serial/objostrasn.hpp +++ b/c++/include/serial/objostrasn.hpp @@ -1,7 +1,7 @@ #ifndef OBJOSTRASN__HPP #define OBJOSTRASN__HPP -/* $Id: objostrasn.hpp 459636 2015-02-20 14:45:49Z gouriano $ +/* $Id: objostrasn.hpp 538251 2017-06-08 18:32:10Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -200,6 +200,16 @@ private: }; +inline +string& operator<<(string& s, const CSerialObject& obj) +{ + CNcbiOstrstream out; + out << MSerial_AsnText << obj; + s.append(CNcbiOstrstreamToString(out)); + return s; +} + + /* @} */ diff --git a/c++/include/serial/objostrjson.hpp b/c++/include/serial/objostrjson.hpp index 427247c2..1bc5287c 100644 --- a/c++/include/serial/objostrjson.hpp +++ b/c++/include/serial/objostrjson.hpp @@ -1,7 +1,7 @@ #ifndef OBJOSTRJSON__HPP #define OBJOSTRJSON__HPP -/* $Id: objostrjson.hpp 480245 2015-09-29 14:03:38Z gouriano $ +/* $Id: objostrjson.hpp 532474 2017-04-05 15:51:46Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -177,6 +177,9 @@ protected: TConstObjectPtr memberPtr); virtual bool WriteClassMember(const CMemberId& memberId, const CDelayBuffer& buffer); + virtual void WriteClassMemberSpecialCase( + const CMemberId& memberId, TTypeInfo memberType, + TConstObjectPtr memberPtr, ESpecialCaseWrite how); #endif // low level I/O @@ -234,6 +237,7 @@ private: void EndArray(void); void NameSeparator(void); + bool m_FileHeader; bool m_BlockStart; bool m_ExpectValue; string m_SkippedMemberId; diff --git a/c++/include/serial/objostrxml.hpp b/c++/include/serial/objostrxml.hpp index 87b5b6f8..b08d1344 100644 --- a/c++/include/serial/objostrxml.hpp +++ b/c++/include/serial/objostrxml.hpp @@ -1,7 +1,7 @@ #ifndef OBJOSTRXML__HPP #define OBJOSTRXML__HPP -/* $Id: objostrxml.hpp 507795 2016-07-21 17:24:14Z gouriano $ +/* $Id: objostrxml.hpp 534119 2017-04-24 17:07:34Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -353,10 +353,6 @@ protected: void EndArrayElement(void); void CheckStdXml(const CClassTypeInfoBase* classType); - TTypeInfo GetRealTypeInfo(TTypeInfo typeInfo); - ETypeFamily GetRealTypeFamily(TTypeInfo typeInfo); - TTypeInfo GetContainerElementTypeInfo(TTypeInfo typeInfo); - ETypeFamily GetContainerElementTypeFamily(TTypeInfo typeInfo); virtual void BeginClass(const CClassTypeInfo* classInfo); virtual void EndClass(void); diff --git a/c++/include/serial/rpcbase.hpp b/c++/include/serial/rpcbase.hpp index 4f81eb27..5112d023 100644 --- a/c++/include/serial/rpcbase.hpp +++ b/c++/include/serial/rpcbase.hpp @@ -1,7 +1,7 @@ #ifndef SERIAL___RPCBASE__HPP #define SERIAL___RPCBASE__HPP -/* $Id: rpcbase.hpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: rpcbase.hpp 541584 2017-07-19 16:03:23Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -166,8 +166,12 @@ void CRPCClient::x_Connect(void) x_extra.parse_header = sx_ParseHeader; x_extra.flags = fHTTP_NoAutoRetry; - x_SetStream(new CConn_ServiceStream(m_Service, fSERV_Any, net_info, - &x_extra, m_Timeout)); + auto_ptr stream(new CConn_ServiceStream( + m_Service, fSERV_Any, net_info, &x_extra, m_Timeout)); + if ( m_Canceler.NotNull() ) { + stream->SetCanceledCallback(m_Canceler.GetNonNullPointer()); + } + x_SetStream(stream.release()); ConnNetInfo_Destroy(net_info); } @@ -190,7 +194,7 @@ void CRPCClient::x_ConnectURL(const string& url) "Error sending retry context arguments"); } } - x_SetStream(new CConn_HttpStream(net_info, + auto_ptr stream(new CConn_HttpStream(net_info, kEmptyStr, // user_header sx_ParseHeader, // callback &m_RetryCtx, // user data for the callback @@ -198,6 +202,10 @@ void CRPCClient::x_ConnectURL(const string& url) 0, // cleanup callback fHTTP_AutoReconnect | fHTTP_NoAutoRetry, m_Timeout)); + if ( m_Canceler.NotNull() ) { + stream->SetCanceledCallback(m_Canceler.GetNonNullPointer()); + } + x_SetStream(stream.release()); } diff --git a/c++/include/serial/rpcbase_impl.hpp b/c++/include/serial/rpcbase_impl.hpp index df6ca695..14b7e259 100644 --- a/c++/include/serial/rpcbase_impl.hpp +++ b/c++/include/serial/rpcbase_impl.hpp @@ -1,7 +1,7 @@ #ifndef SERIAL___RPCBASE_IMPL__HPP #define SERIAL___RPCBASE_IMPL__HPP -/* $Id: rpcbase_impl.hpp 498886 2016-04-20 13:48:22Z grichenk $ +/* $Id: rpcbase_impl.hpp 541584 2017-07-19 16:03:23Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -81,6 +81,12 @@ public: const CTimeSpan GetRetryDelay(void) const { return m_RetryDelay; } void SetRetryDelay(const CTimeSpan& ts) { m_RetryDelay = ts; } + /// Set request canceler. The canceler is passed to CConn_IOStream and + /// must be be derived from CObject as its first superclass. + /// @sa CConn_IOStream::SetCanceledCallback + void SetCanceledCallback(const ICanceled* canceled) { m_Canceler = canceled; } + bool IsCanceled(void) const { return m_Canceler.NotNull() && m_Canceler->IsCanceled(); } + protected: void SetAffinity(const string& affinity); @@ -115,6 +121,7 @@ protected: string m_Affinity; unsigned int m_RetryLimit; CHttpRetryContext m_RetryCtx; + CConstIRef m_Canceler; // Retry policy; by default, just _TRACEs the event and returns // true. May reset the connection (or do anything else, really), diff --git a/c++/include/serial/serialbase.hpp b/c++/include/serial/serialbase.hpp index 84f8db36..17d06bbd 100644 --- a/c++/include/serial/serialbase.hpp +++ b/c++/include/serial/serialbase.hpp @@ -1,7 +1,7 @@ #ifndef SERIALBASE__HPP #define SERIALBASE__HPP -/* $Id: serialbase.hpp 498023 2016-04-12 18:53:26Z grichenk $ +/* $Id: serialbase.hpp 538251 2017-06-08 18:32:10Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -643,6 +643,9 @@ public: #define MSerial_Xml MSerial_Format_Xml() #define MSerial_Json MSerial_Format_Json() +/// Flat ASN text output - no indentation or line breaks. +#define MSerial_FlatAsnText MSerial_AsnText(fSerial_AsnText_NoIndentation | fSerial_AsnText_NoEol) + /// Reset all formatting flags for the I/O stream NCBI_XSERIAL_EXPORT CNcbiIos& MSerial_None(CNcbiIos& io); diff --git a/c++/include/serial/serialdef.hpp b/c++/include/serial/serialdef.hpp index b616378f..58c89fd6 100644 --- a/c++/include/serial/serialdef.hpp +++ b/c++/include/serial/serialdef.hpp @@ -1,7 +1,7 @@ #ifndef SERIALDEF__HPP #define SERIALDEF__HPP -/* $Id: serialdef.hpp 507795 2016-07-21 17:24:14Z gouriano $ +/* $Id: serialdef.hpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -200,6 +200,14 @@ enum ENsQualifiedMode { eNSQualified }; +enum class EDataSpec { + eUnknown, + eASN, + eDTD, + eXSD, + eJSON +}; + /// Type used for indexing class members and choice variants typedef size_t TMemberIndex; diff --git a/c++/include/serial/streamiter.hpp b/c++/include/serial/streamiter.hpp index 515b1b08..f703313a 100644 --- a/c++/include/serial/streamiter.hpp +++ b/c++/include/serial/streamiter.hpp @@ -1,7 +1,7 @@ #ifndef STREAMITER__HPP #define STREAMITER__HPP -/* $Id: streamiter.hpp 468542 2015-05-26 14:14:15Z gouriano $ +/* $Id: streamiter.hpp 538350 2017-06-09 18:10:10Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -26,7 +26,7 @@ * * =========================================================================== * -* Author: Andrei Gourianov +* Authors: Andrei Gourianov, Alexander Astashyn * * File Description: * Input stream iterators @@ -37,6 +37,13 @@ #include #include #include +#include + +#include +#include +#include +#include +#include /** @addtogroup ObjStreamSupport @@ -47,10 +54,1651 @@ BEGIN_NCBI_SCOPE +#if defined(NCBI_THREADS) + +namespace ns_ObjectIStreamFilterIterator { +template +TMemberIndex xxx_MemberIndex(const string& mem_name); +} +template +class CObjectIStreamAsyncIterator; + +///////////////////////////////////////////////////////////////////////////// +/// CObjectIStreamIterator +/// +/// Synchronously read multiple same-type data objects from an input stream +/// with optional filtering. +/// @sa CObjectIStreamAsyncIterator +/// +/// The algorithm assumes that the input stream on its top level consists +/// exclusively of one or more serial objects of type TRoot. +/// +/// There are two flavors of this template: +/// - CObjectIStreamIterator - iterate through the top-level serial +/// objects of type TRoot. +/// - CObjectIStreamIterator - iterate through serial objects +/// of type TChild which are contained within the top-level serial objects +/// of type TRoot. +/// +/// Usage: +/// @code +/// +/// CObjectIStream istr ....; +/// +/// for (CSeq_entry& obj : CObjectIStreamIterator(istr)) { +/// // ...do something with "obj" here... +/// } +/// +/// for (CBioseq& obj : CObjectIStreamIterator(istr)) { +/// // ...do something with "obj" here... +/// } +/// +/// +/// CObjectIStreamIterator it(istr); +/// CObjectIStreamIterator eos; +/// for_each (it, eos, [](CSeq_entry& obj) { ... }); +/// +/// CObjectIStreamIterator it(istr); +/// CObjectIStreamIterator eos; +/// for_each (it, eos, [](CBioseq& obj) { ... }); +/// +/// +/// for (CObjectIStreamIterator it(istr); it.IsValid(); ++it) { +/// CSeq_entry& obj = *it; +/// // ...do something with "obj" here... +/// } +/// +/// for (CObjectIStreamIterator it(istr); +/// it.IsValid(); ++it) { +/// CRef obj(&*it); +/// // ...do something with "obj" here... +/// } +/// +/// for (CObjectIStreamIterator it(istr); +/// it.IsValid(); ++it) { +/// string& obj = *it; +/// } +/// +/// with filtering (only CTaxon1_data objects with optional 'org' member set are valid): +/// CObjectIStreamIterator i(istr, eNoOwnership, +/// CObjectIStreamIterator::CParams().FilterByMember("org", +/// [](const CObjectIStream& istr, CTaxon1_data& obj, +/// TMemberIndex mem_index, CObjectInfo* mem, void* extra)->bool { +/// return mem != nullptr; +/// })); +/// +/// @endcode +/// +/// @attention +/// Input iterators only guarantee validity for single pass algorithms: +/// once an input iterator has been incremented, all copies of its previous +/// value may be invalidated. It is still possible to keep data objects +/// for future use by placing them into CRef containers, when applicable. + +template +class CObjectIStreamIterator +{ +public: + + /// Object member filtering function + /// + /// @param istr + /// Serial object stream + /// @param obj + /// Object being checked. It is being populated and is incomplete. + /// @param mem_index + /// Member index + /// @param mem + /// Member information. If mem is nullptr, the member is missing in the stream. + /// @param extra + /// Extra information provided by the caller when constructing iterator. + /// + /// @attention + /// When using filtering with CObjectIStreamAsyncIterator, please note + /// that the function may be called from different threads. + /// Synchronization of access to shared data, if required, is the responsibility of the client. + template + using FMemberFilter = function; + /// Filtering parameters + template + class CParams + { + public: + CParams(void) + : m_Index(kInvalidMember) + , m_FnFilter(nullptr) + , m_Extra(nullptr) { + } + /// Filter by member index + CParams& FilterByMember(TMemberIndex index, FMemberFilter fn, void* extra = nullptr) { + m_Index = index; m_FnFilter = fn; m_Extra = extra; return *this; + } + /// Filter by member name + CParams& FilterByMember(const string& mem_name, FMemberFilter fn, void* extra = nullptr) { + m_Index = ns_ObjectIStreamFilterIterator::xxx_MemberIndex(mem_name); + m_FnFilter = fn; m_Extra = extra; return *this; + } + + private: +// void xxx_MemberIndex(const string& mem_name); + TMemberIndex m_Index; + FMemberFilter m_FnFilter; + void* m_Extra; + template friend class CObjectIStreamIterator; + template friend class CObjectIStreamAsyncIterator; + }; + + /// Construct iterator upon an object serialization stream + /// + /// @param istr + /// Serial object stream + /// @param own_istr + /// eTakeOwnership means that the input stream will be deleted + /// automatically when the iterator gets destroyed + /// @param params + /// Filtering parameters (default is no filtering) + template + CObjectIStreamIterator( CObjectIStream& istr, + EOwnership deleteInStream = eNoOwnership, + const CParams& params = CParams()) = delete; + + /// Construct end-of-stream (invalid) iterator + /// @sa IsValid() + CObjectIStreamIterator(void) = delete; + + // Copy-ctor and assignment + CObjectIStreamIterator(const CObjectIStreamIterator&); + CObjectIStreamIterator& operator=(const CObjectIStreamIterator&); + + /// Advance to the next data object + CObjectIStreamIterator& operator++(void); + + // Comparison + bool operator==(const CObjectIStreamIterator&) const; + bool operator!=(const CObjectIStreamIterator&) const; + + /// Check whether the iterator points to a data + /// TRUE if the iterator is constructed upon a serialization stream AND + /// if it's not end-of-stream or error-in-stream + bool IsValid(void) const; + + /// Return the underlying serial object stream + const CObjectIStream& GetObjectIStream(void) const; + + /// Return data object which is currently pointed to by the iterator. + /// Throw an exception is the iterator does not point to a data, i.e. + /// if IsValid() is FALSE. + template TObj& operator*(); + + /// Return pointer to data object which is currently pointed to by the + /// iterator. + /// Return NULL is the iterator does not point to a data, i.e. + /// if IsValid() is FALSE. + template TObj* operator->(); + + /// Return self + CObjectIStreamIterator& begin(void); + + /// Construct and return end-of-stream iterator + CObjectIStreamIterator end(void); + + // dtor + ~CObjectIStreamIterator(); +}; + + +///////////////////////////////////////////////////////////////////////////// +/// CObjectIStreamAsyncIterator +/// +/// Asynchronously read multiple same-type data objects from an input stream +/// with optional filtering +/// @sa CObjectIStreamIterator +/// +/// The algorithm assumes that the input stream on its top level consists +/// exclusively of one or more serial objects of type TRoot. +/// +/// There are two flavors of this template: +/// - CObjectIStreamAsyncIterator - iterate through the top-level +/// serial objects of type TRoot. +/// - CObjectIStreamAsyncIterator - iterate through serial +/// objects of type TChild which are contained within the top-level serial +/// objects of type TRoot. +/// +/// @attention +/// This iterator supports only the TChild types that are derived from +/// CSerialObject class +/// +/// Usage: +/// @code +/// +/// CObjectIStream istr ....; +/// +/// for (CSeq_entry& obj : CObjectIStreamAsyncIterator(istr)) +/// { +/// // ...do something with "obj" here... +/// } +/// +/// for (CBioseq& obj : CObjectIStreamAsyncIterator(istr)) +/// { +/// // ...do something with "obj" here... +/// } +/// +/// +/// CObjectIStreamAsyncIterator it(istr); +/// CObjectIStreamAsyncIterator eos; +/// for_each (it, eos, [](CSeq_entry& obj) { ... }); +/// +/// CObjectIStreamAsyncIterator it(istr); +/// CObjectIStreamAsyncIterator eos; +/// for_each (it, eos, [](CBioseq& obj) { ... }); +/// +/// +/// for (CObjectIStreamAsyncIterator it(istr); +/// it.IsValid(); ++it) { +/// CSeq_entry& obj = *it; +/// // ...do something with "obj" here... +/// } +/// +/// for (CObjectIStreamAsyncIterator it(istr); +/// it.IsValid(); ++it) { +/// CRef obj(&*it); +/// // ...do something with "obj" here... +/// } +/// +/// @endcode +/// +/// To speed up reading, the iterator offloads data reading, pre-parsing and +/// parsing into separate threads. If the data stream contains numerous TRoot +/// data records CObjectIStreamAsyncIterator can give up to 2-4 times speed-up +/// (wall-clock wise) comparing to the synchronous processing (such as with +/// CObjectIStreamIterator) of the same data. +/// +/// The reader has to read the whole object into memory. If such objects are +/// relatively small, then there will be several objects read into a single +/// buffer, which is good. If data object is big it still goes into a single +/// buffer no matter how big the object is. +/// To limit memory consumption, use MaxTotalRawSize parameter. +/// +/// The iterator does its job asynchronously. It starts working immediately +/// after its creation and stops only when it is destroyed. +/// Even if you do not use it, it still works in the background, reading and +/// parsing the data. +/// +/// @attention +/// Input iterators only guarantee validity for single pass algorithms: +/// once an input iterator has been incremented, all copies of its previous +/// value may be invalidated. It is still possible to keep data objects +/// for future use by placing them into CRef containers, when applicable. + +template +class CObjectIStreamAsyncIterator +{ +public: + + /// Asynchronous parsing parameters + template + class CParams : public CObjectIStreamIterator<>::CParams + { + public: + using CParent = CObjectIStreamIterator<>::CParams; + template + using FMemberFilter = CObjectIStreamIterator<>::FMemberFilter; + + CParams(void) + : m_ThreadPolicy(launch::async) + , m_MaxParserThreads (16) + , m_MaxTotalRawSize (16 * 1024 * 1024) + , m_MinRawBufferSize (128 * 1024) + , m_SameThread(false) { + } + + /// Filter by member index + CParams& FilterByMember(TMemberIndex index, FMemberFilter fn, void* extra = nullptr) { + CParent::FilterByMember(index, fn, extra); return *this; + } + + /// Filter by member name + CParams& FilterByMember(const string& mem_name, FMemberFilter fn, void* extra = nullptr) { + CParent::FilterByMember(mem_name, fn, extra); return *this; + } + + /// Parsing thread launch policy + CParams& LaunchPolicy(launch policy) { + m_ThreadPolicy = policy; return *this; + } + + /// Maximum number of parsing threads + CParams& MaxParserThreads(unsigned max_parser_threads) { + m_MaxParserThreads = max_parser_threads; return *this; + } + + /// Total size of raw data buffers is allowed to grow to this value + CParams& MaxTotalRawSize(size_t max_total_raw_size) { + m_MaxTotalRawSize = max_total_raw_size; return *this; + } + + /// Single raw data memory buffer size should be at least this big + CParams& MinRawBufferSize(size_t min_raw_buffer_size) { + m_MinRawBufferSize = min_raw_buffer_size; return *this; + } + + /// Raw data read and its pre-parsing (storing the raw data pertaining + /// to a single object and putting it into the parsing queue) to be + /// done in the same thread. + /// @note + /// The default is to do these two tasks in two separate threads, + /// which in some cases can give an additional 10-20% performance + /// boost, wall-clock time wise. + CParams& ReadAndSkipInTheSameThread(bool same_thread) { + m_SameThread = same_thread; return *this; + } + + private: + launch m_ThreadPolicy; + unsigned m_MaxParserThreads; + size_t m_MaxTotalRawSize; + size_t m_MinRawBufferSize; + bool m_SameThread; + + template friend class CObjectIStreamAsyncIterator; + }; + + + /// Construct iterator upon an object serialization stream + /// + /// @param istr + /// Serial object stream + /// @param own_istr + /// eTakeOwnership means that the input stream will be deleted + /// automatically when the iterator gets destroyed + /// @param params + /// Parsing algorithm's parameters + /// @param params + /// Filtering and parsing parameters (default is no filtering) + template + CObjectIStreamAsyncIterator(CObjectIStream& istr, + EOwnership own_istr = eNoOwnership, + const CParams& params = CParams()) = delete; + + /// Construct end-of-stream (invalid) iterator + /// @sa IsValid() + CObjectIStreamAsyncIterator(void) = delete; + + // Copy-ctor and assignment + CObjectIStreamAsyncIterator(const CObjectIStreamAsyncIterator&); + CObjectIStreamAsyncIterator& operator=(const CObjectIStreamAsyncIterator&); + + /// Advance to the next data object + CObjectIStreamAsyncIterator& operator++(void); + + // Comparison + bool operator==(const CObjectIStreamAsyncIterator&) const; + bool operator!=(const CObjectIStreamAsyncIterator&) const; + + /// Check whether the iterator points to a data + /// TRUE if the iterator is constructed upon a serialization stream AND + /// if it's not end-of-stream or error-in-stream + bool IsValid(void) const; + + /// Return data object which is currently pointed to by the iterator. + /// Throw an exception is the iterator does not point to a data, i.e. + /// if IsValid() is FALSE. + template TObj& operator*(); + + /// Return pointer to data object which is currently pointed to by the + /// iterator. + /// Return NULL is the iterator does not point to a data, i.e. + /// if IsValid() is FALSE. + template TObj* operator->(); + + /// Return self + CObjectIStreamAsyncIterator& begin(void); + + /// Construct and return end-of-stream iterator + CObjectIStreamAsyncIterator end(void); + + // dtor + ~CObjectIStreamAsyncIterator(); +}; + + + +///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +/// template specializations and implementation + +///////////////////////////////////////////////////////////////////////////// +/// CObjectIStreamIterator + +template +class CObjectIStreamIterator + : public iterator< input_iterator_tag, TRoot, ptrdiff_t, TRoot*, TRoot& > +{ +public: + using CParams = CObjectIStreamIterator<>::CParams; + + CObjectIStreamIterator( CObjectIStream& istr, + EOwnership deleteInStream = eNoOwnership, + const CParams& params = CParams()); + + CObjectIStreamIterator(void); + CObjectIStreamIterator(const CObjectIStreamIterator&); + CObjectIStreamIterator& operator=(const CObjectIStreamIterator&); + ~CObjectIStreamIterator(); + + CObjectIStreamIterator& operator++(void); + bool operator==(const CObjectIStreamIterator&) const; + bool operator!=(const CObjectIStreamIterator&) const; + bool IsValid(void) const; + const CObjectIStream& GetObjectIStream(void) const; + + TRoot& operator*(); + TRoot* operator->(); + + CObjectIStreamIterator& begin(void); + CObjectIStreamIterator end(void); + +protected: + struct CData + { + CData(CObjectIStream& istr, EOwnership deleteInStream, + const CParams& params, TTypeInfo tinfo); + ~CData(void); + + void x_BeginRead(void); + void x_EndRead(void); + void x_AcceptData(CObjectIStream& in, const CObjectInfo& type); + void x_Next(void); + bool x_NextNoFilter(const CObjectInfo& objinfo); + bool x_NextSeqWithFilter(const CObjectInfo& objinfo); + bool x_NextChoiceWithFilter(const CObjectInfo& objinfo); + bool x_NextContainerWithFilter(const CObjectInfo& objinfo); + + CObjectIStream* m_Istr; + EOwnership m_Own; + CObjectTypeInfo m_ValueType; + CObjectInfo m_Value; + bool m_HasReader; + bool m_EndOfData; + CParams m_Params; + mutex m_ReaderMutex; + condition_variable m_ReaderCv; + thread m_Reader; + exception_ptr m_ReaderExpt; + enum EFilter { + eNone, + eOneSeq, + eOneRandom, + eAllSeq, + eAllRandom, + eOneChoice, + eAllChoice, + eOneContainer, + eAllContainer + } m_FilterType; + + template + class x_CObjectIStreamIteratorHook : public CSkipObjectHook + { + public: + x_CObjectIStreamIteratorHook( + typename CObjectIStreamIterator::CData* pthis) + : m_This(pthis) { + } + virtual void SkipObject(CObjectIStream& in, const CObjectTypeInfo& type) { + m_This->x_AcceptData(in,CObjectInfo(type.GetTypeInfo())); + } + private: + typename CObjectIStreamIterator::CData* m_This; + }; + }; + + CObjectIStreamIterator( CObjectIStream& istr, + const CParams& params, EOwnership deleteInStream); + void x_ReaderThread(void); + shared_ptr m_Data; +}; + +///////////////////////////////////////////////////////////////////////////// +/// CObjectIStreamIterator + +template +class CObjectIStreamIterator + : public CObjectIStreamIterator +{ +public: + using CParams = CObjectIStreamIterator<>::CParams; + + CObjectIStreamIterator( CObjectIStream& istr, + EOwnership deleteInStream = eNoOwnership, + const CParams& params = CParams()); + + CObjectIStreamIterator(void); + CObjectIStreamIterator(const CObjectIStreamIterator&); + CObjectIStreamIterator& operator=(const CObjectIStreamIterator&); + ~CObjectIStreamIterator(); + + CObjectIStreamIterator& operator++(void); + CObjectIStreamIterator& begin(void); + CObjectIStreamIterator end(void); + +protected: + using CParent = CObjectIStreamIterator; + void x_ReaderThread(void); + + template + class x_CObjectIStreamIteratorReadHook : public CReadObjectHook + { + public: + x_CObjectIStreamIteratorReadHook( + typename CObjectIStreamIterator::CData* pthis) + : m_This(pthis) { + } + virtual void ReadObject(CObjectIStream& in, const CObjectInfo& type) { + m_This->x_AcceptData(in,type); + } + private: + typename CObjectIStreamIterator::CData* m_This; + }; +}; + + +///////////////////////////////////////////////////////////////////////////// +// helpers + +namespace ns_ObjectIStreamFilterIterator { + +template +typename enable_if< is_base_of< CSerialObject, TRoot>::value, TTypeInfo>::type +xxx_GetTypeInfo(void) +{ + return TRoot::GetTypeInfo(); +} + +template +//typename enable_if< !is_base_of< CSerialObject, TRoot>::value, TTypeInfo>::type +typename enable_if< is_pod::value || is_convertible::value, TTypeInfo>::type +xxx_GetTypeInfo(void) +{ + return CStdTypeInfo::GetTypeInfo(); +} + +template +TMemberIndex xxx_MemberIndex(const string& mem_name) +{ + TTypeInfo tinfo = xxx_GetTypeInfo(); + ETypeFamily type = tinfo->GetTypeFamily(); + if (type == eTypeFamilyClass || type == eTypeFamilyChoice) { + const CClassTypeInfoBase* cinfo = CTypeConverter::SafeCast(tinfo); + return cinfo->GetItems().Find(mem_name); + } + return kInvalidMember; +} + +} // ns_ObjectIStreamFilterIterator + +#if 0 +template +template +void +CObjectIStreamIterator<>::CParams::xxx_MemberIndex(const string& mem_name) { + TTypeInfo tinfo = ns_ObjectIStreamFilterIterator::xxx_GetTypeInfo(); + ETypeFamily type = tinfo->GetTypeFamily(); + if (type == eTypeFamilyClass || type == eTypeFamilyChoice) { + const CClassTypeInfoBase* cinfo = CTypeConverter::SafeCast(tinfo); + return cinfo->GetItems().Find(mem_name); + } + return kInvalidMember; +} +#endif + + +///////////////////////////////////////////////////////////////////////////// +/// CObjectIStreamIterator implementation + +template +CObjectIStreamIterator::CObjectIStreamIterator(void) + : m_Data(nullptr) { +} + +template +CObjectIStreamIterator::CObjectIStreamIterator( + CObjectIStream& istr, const CParams& params, EOwnership deleteInStream) + : m_Data( new CData(istr, deleteInStream, params, + ns_ObjectIStreamFilterIterator::xxx_GetTypeInfo())) { +} + +template +CObjectIStreamIterator::CObjectIStreamIterator( + CObjectIStream& istr, EOwnership deleteInStream, const CParams& params) + : CObjectIStreamIterator(istr, params, deleteInStream) +{ + if (m_Data->m_FilterType != CData::eNone && !m_Data->m_EndOfData) { + m_Data->m_HasReader = true; + m_Data->m_Reader = thread( mem_fun >( + &CObjectIStreamIterator::x_ReaderThread), this); + } + ++(*this); +} + +template +CObjectIStreamIterator::CObjectIStreamIterator( + const CObjectIStreamIterator& v) : m_Data(v.m_Data) { +} + +template +CObjectIStreamIterator& +CObjectIStreamIterator::operator=(const CObjectIStreamIterator& v) { + m_Data = v.m_Data; + return *this; +} + +template +CObjectIStreamIterator::~CObjectIStreamIterator() { +} + +template +CObjectIStreamIterator::CData::CData( + CObjectIStream& istr, EOwnership deleteInStream, + const CParams& params, TTypeInfo tinfo) + : m_Istr(&istr), m_Own(deleteInStream) + , m_ValueType(tinfo), m_Value(tinfo), m_HasReader(false) + , m_EndOfData(m_Istr->EndOfData()), m_Params(params) +{ + ETypeFamily type = tinfo->GetTypeFamily(); + if (type != eTypeFamilyClass && type != eTypeFamilyChoice && type != eTypeFamilyContainer) { + m_Params.m_FnFilter = nullptr; + } + m_FilterType = eNone; + if (m_Params.m_FnFilter) { + if (type == eTypeFamilyClass) { + const CClassTypeInfo* cinfo = CTypeConverter::SafeCast(tinfo); + if (cinfo->Implicit()) { + const CItemInfo* itemInfo = + cinfo->GetItems().GetItemInfo(cinfo->GetItems().FirstIndex()); + if (itemInfo->GetTypeInfo()->GetTypeFamily() == eTypeFamilyContainer) { + m_FilterType = m_Params.m_Index != kInvalidMember ? eOneContainer : eAllContainer; + } + } + if (m_FilterType == eNone) { + bool is_random = cinfo->RandomOrder(); + if (m_Params.m_Index != kInvalidMember) { + m_FilterType = is_random ? eOneRandom : eOneSeq; + } else { + m_FilterType = is_random ? eAllRandom : eAllSeq; + } + } + } else if (type == eTypeFamilyChoice) { + m_FilterType = m_Params.m_Index != kInvalidMember ? eOneChoice : eAllChoice; + } else if (type == eTypeFamilyContainer) { + m_FilterType = m_Params.m_Index != kInvalidMember ? eOneContainer : eAllContainer; + } + } +} + +template +CObjectIStreamIterator::CData::~CData(void) { + if (m_Reader.joinable()) { + m_EndOfData = true; + m_ReaderCv.notify_all(); + m_Reader.join(); + } + if (m_Istr && m_Own == eTakeOwnership) { + delete m_Istr; + } +} + +template +void +CObjectIStreamIterator::CData::x_BeginRead(void) { + unique_lock lck( m_ReaderMutex); + while (m_Value.GetObjectPtr() != nullptr) { + m_ReaderCv.wait(lck); + } +} + +template +void +CObjectIStreamIterator::CData::x_EndRead(void) { + m_Value = CObjectInfo(); + m_EndOfData = true; + m_ReaderCv.notify_one(); +} + +template +void +CObjectIStreamIterator::x_ReaderThread() { + m_Data->x_BeginRead(); + try { + m_Data->m_ValueType.SetLocalSkipHook(*(m_Data->m_Istr), new typename CData::template x_CObjectIStreamIteratorHook(m_Data.get())); + while (Serial_FilterSkip(*(m_Data->m_Istr),m_Data->m_ValueType)) + ; + } catch (...) { + if (!m_Data->m_EndOfData) { + m_Data->m_ReaderExpt = current_exception(); + } + } + m_Data->x_EndRead(); +} + +template +void +CObjectIStreamIterator::x_ReaderThread() { + this->m_Data->x_BeginRead(); + try { + this->m_Data->m_ValueType.SetLocalSkipHook(*(this->m_Data->m_Istr), new typename CParent::CData::template x_CObjectIStreamIteratorHook(this->m_Data.get())); + this->m_Data->m_ValueType.SetLocalReadHook(*(this->m_Data->m_Istr), new x_CObjectIStreamIteratorReadHook(this->m_Data.get())); + while (Serial_FilterSkip(*(this->m_Data->m_Istr),CObjectTypeInfo(CType()))) + ; + } catch (...) { + if (!this->m_Data->m_EndOfData) { + this->m_Data->m_ReaderExpt = current_exception(); + } + } + this->m_Data->x_EndRead(); +} + +template +void +CObjectIStreamIterator::CData::x_AcceptData( + CObjectIStream& in, const CObjectInfo& objinfo) +{ + if (m_Istr->EndOfData()) { + m_EndOfData = true; + } else { + bool res = false; + switch ( m_FilterType) { + default: + case eNone: + res = x_NextNoFilter(objinfo); + break; + case eOneSeq: + case eOneRandom: + case eAllSeq: + case eAllRandom: + res = x_NextSeqWithFilter(objinfo); + break; + case eOneChoice: + case eAllChoice: + res = x_NextChoiceWithFilter(objinfo); + break; + case eOneContainer: + case eAllContainer: + res = x_NextContainerWithFilter(objinfo); + break; + } + if (res) { + unique_lock lck(m_ReaderMutex); + m_Value = objinfo; + m_ReaderCv.notify_one(); + while (m_Value.GetObjectPtr() != nullptr) { + if (m_EndOfData) { + NCBI_THROW( CEofException, eEof, + "CObjectIStreamIterator: abort data parsing"); + } + m_ReaderCv.wait(lck); + } + } else { + in.SetDiscardCurrObject(); + } + } +} + +template +void +CObjectIStreamIterator::CData::x_Next(void) { + unique_lock lck(m_ReaderMutex); + m_Value = CObjectInfo(); + m_ReaderCv.notify_one(); + while (m_Value.GetObjectPtr() == nullptr && !m_EndOfData) { + m_ReaderCv.wait(lck); + } + if (m_ReaderExpt) { + rethrow_exception(m_ReaderExpt); + } +} + +template +bool +CObjectIStreamIterator::CData::x_NextNoFilter(const CObjectInfo& objinfo) +{ + objinfo.GetTypeInfo()->DefaultReadData(*m_Istr, objinfo.GetObjectPtr()); + return true; +} + +template +bool +CObjectIStreamIterator::CData::x_NextSeqWithFilter(const CObjectInfo& objinfo) +{ + TMemberIndex mi = kInvalidMember; + set done; + bool checked = false; + bool valid = true; + TRoot& obj = *CTypeConverter::SafeCast(objinfo.GetObjectPtr()); + + for ( CIStreamClassMemberIterator i(*m_Istr, objinfo); i; ++i ) { + + TMemberIndex mi_now = (*i).GetMemberIndex(); + CObjectInfoMI minfo(objinfo, mi_now); + + if (valid) { +// before read - validate missing members + switch (m_FilterType) { + case eOneRandom: + case eAllRandom: + default: + break; + case eOneSeq: + if (mi_now > m_Params.m_Index && !checked) { + valid = m_Params.m_FnFilter( *m_Istr, obj, m_Params.m_Index, nullptr, m_Params.m_Extra); + checked = true; + } + break; + case eAllSeq: + for (++mi; valid && mi < mi_now; ++mi) { + valid = m_Params.m_FnFilter( *m_Istr, obj, mi, nullptr, m_Params.m_Extra); + } + break; + } + } + +// if still valid + if (valid) { +// read next member + i.ReadClassMember(objinfo); + +// after read - validate member + switch (m_FilterType) { + default: break; + case eOneSeq: + case eOneRandom: + if (mi_now == m_Params.m_Index) { + CObjectInfo oi = minfo.GetMember().GetTypeFamily() == eTypeFamilyPointer ? + minfo.GetMember().GetPointedObject() : minfo.GetMember(); + valid = m_Params.m_FnFilter( *m_Istr, obj, mi_now, &oi, m_Params.m_Extra); + checked = true; + } + break; + case eAllRandom: + done.insert(mi_now); + // no break + case eAllSeq: + { + CObjectInfo oi = minfo.GetMember().GetTypeFamily() == eTypeFamilyPointer ? + minfo.GetMember().GetPointedObject() : minfo.GetMember(); + valid = m_Params.m_FnFilter( *m_Istr, obj, mi_now, &oi, m_Params.m_Extra); + } + break; + } + } else { +// object invalid - skip remaining members + i.SkipClassMember(); + } + mi = mi_now; + } + +// finally - validate missing members + if (valid) { + switch (m_FilterType) { + default: break; + case eOneSeq: + case eOneRandom: + if (!checked) { + valid = m_Params.m_FnFilter( *m_Istr, obj, m_Params.m_Index, nullptr, m_Params.m_Extra); + } + break; + case eAllSeq: + { + TMemberIndex mi_last = objinfo.GetClassTypeInfo()->GetItems().LastIndex() + 1; + for (++mi; valid && mi < mi_last; ++mi) { + valid = m_Params.m_FnFilter( *m_Istr, obj, mi, nullptr, m_Params.m_Extra); + } + } + break; + case eAllRandom: + { + mi = objinfo.GetClassTypeInfo()->GetItems().FirstIndex(); + TMemberIndex mi_last = objinfo.GetClassTypeInfo()->GetItems().LastIndex() + 1; + for (; valid && mi < mi_last; ++mi) { + if (done.find(mi) == done.end()) { + valid = m_Params.m_FnFilter( *m_Istr, obj, mi, nullptr, m_Params.m_Extra); + } + } + } + break; + } + } + return valid; +} + +template +bool +CObjectIStreamIterator::CData::x_NextChoiceWithFilter(const CObjectInfo& objinfo) +{ + bool valid = true; + objinfo.GetTypeInfo()->DefaultReadData(*m_Istr, objinfo.GetObjectPtr()); + TRoot& obj = *CTypeConverter::SafeCast(objinfo.GetObjectPtr()); + CObjectInfoCV cv = objinfo.GetCurrentChoiceVariant(); + TMemberIndex i = cv.GetVariantIndex(); + if (i == m_Params.m_Index) { + CObjectInfo oi = cv.GetVariant().GetTypeFamily() == eTypeFamilyPointer ? + cv.GetVariant().GetPointedObject() : cv.GetVariant(); + valid = m_Params.m_FnFilter( *m_Istr, obj, i, &oi, m_Params.m_Extra); + } else { + valid = m_Params.m_FnFilter( *m_Istr, obj, m_Params.m_Index, nullptr, m_Params.m_Extra); + } + return valid; +} + +template +bool +CObjectIStreamIterator::CData::x_NextContainerWithFilter(const CObjectInfo& objinfo) +{ + TMemberIndex mi = kInvalidMember; + bool valid = true; + TRoot& obj = *CTypeConverter::SafeCast(objinfo.GetObjectPtr()); + + for ( CIStreamContainerIterator i(*m_Istr, objinfo); i; ++i ) { + if (valid) { + CObjectInfo oi(i.ReadElement(objinfo.GetObjectPtr())); + ++mi; + if (oi.GetObjectPtr()) { + if (m_FilterType == eAllContainer || (m_FilterType == eOneContainer && mi == m_Params.m_Index)) { + CObjectInfo oe = oi.GetTypeFamily() == eTypeFamilyPointer ? oi.GetPointedObject() : oi; + valid = m_Params.m_FnFilter( *m_Istr, obj, mi, &oe, m_Params.m_Extra); + } + } + } else { + i.SkipElement(); + } + } + return valid; +} + +template +CObjectIStreamIterator& +CObjectIStreamIterator::operator++(void) { + if (m_Data.get() != nullptr) { + if (!m_Data->m_HasReader) { + if (m_Data->m_Istr->EndOfData()) { + m_Data.reset(); + } else { + m_Data->m_Value = CObjectInfo(m_Data->m_ValueType); + m_Data->m_Istr->Read(m_Data->m_Value); + } + } else { + m_Data->x_Next(); + if (m_Data->m_EndOfData) { + m_Data.reset(); + } + } + } + return *this; +} + +template +bool +CObjectIStreamIterator::operator==( + const CObjectIStreamIterator& v) const { + return m_Data.get() == v.m_Data.get(); +} + +template +bool +CObjectIStreamIterator::operator!=( + const CObjectIStreamIterator& v) const { + return m_Data.get() != v.m_Data.get(); +} + +template +bool CObjectIStreamIterator::IsValid() const { + return m_Data.get() != nullptr && m_Data->m_Value.GetObjectPtr() != nullptr; +} + +template +const CObjectIStream& +CObjectIStreamIterator::GetObjectIStream(void) const { + return *(m_Data->m_Istr); +} + +template +TRoot& +CObjectIStreamIterator::operator*() { + return *(TRoot*)(m_Data->m_Value.GetObjectPtr()); +} + +template +TRoot* +CObjectIStreamIterator::operator->() { + return IsValid() ? (TRoot*)m_Data->m_Value.GetObjectPtr() : nullptr; +} + +template +CObjectIStreamIterator& +CObjectIStreamIterator::begin(void) { + return *this; +} + +template +CObjectIStreamIterator +CObjectIStreamIterator::end(void) { + return CObjectIStreamIterator(); +} + + +///////////////////////////////////////////////////////////////////////////// +/// CObjectIStreamIterator implementation + +template +CObjectIStreamIterator::CObjectIStreamIterator(void) + : CParent() { +} + +template +CObjectIStreamIterator::CObjectIStreamIterator( + CObjectIStream& istr, EOwnership deleteInStream, const CParams& params) + : CParent(istr, params, deleteInStream) +{ + if (!this->m_Data->m_EndOfData) { + this->m_Data->m_HasReader = true; + this->m_Data->m_Reader = thread( mem_fun >( + &CObjectIStreamIterator::x_ReaderThread), this); + } + ++(*this); +} + +template +CObjectIStreamIterator::CObjectIStreamIterator( + const CObjectIStreamIterator& v) : CParent(v) { +} + +template +CObjectIStreamIterator& +CObjectIStreamIterator::operator=( + const CObjectIStreamIterator& v) { + CParent::operator=(v); + return *this; +} + +template +CObjectIStreamIterator::~CObjectIStreamIterator() { +} + +template +CObjectIStreamIterator& +CObjectIStreamIterator::operator++(void) { + CParent::operator++(); + return *this; +} + +template +CObjectIStreamIterator& +CObjectIStreamIterator::begin(void) { + return *this; +} + +template +CObjectIStreamIterator +CObjectIStreamIterator::end(void) { + return CObjectIStreamIterator(); +} + + +///////////////////////////////////////////////////////////////////////////// +/// CObjectIStreamAsyncIterator + +template +class CObjectIStreamAsyncIterator + : public iterator< input_iterator_tag, TRoot, ptrdiff_t, TRoot*, TRoot& > +{ +public: + using CParams = CObjectIStreamAsyncIterator<>::CParams; + + CObjectIStreamAsyncIterator( CObjectIStream& istr, + EOwnership deleteInStream = eNoOwnership, + const CParams& params = CParams()); + CObjectIStreamAsyncIterator(void); + CObjectIStreamAsyncIterator(const CObjectIStreamAsyncIterator&); + CObjectIStreamAsyncIterator& operator=(const CObjectIStreamAsyncIterator&); + ~CObjectIStreamAsyncIterator(); + + CObjectIStreamAsyncIterator& operator++(void); + bool operator==(const CObjectIStreamAsyncIterator&) const; + bool operator!=(const CObjectIStreamAsyncIterator&) const; + bool IsValid(void) const; + + TRoot& operator*(); + TRoot* operator->(); + + CObjectIStreamAsyncIterator& begin(void); + CObjectIStreamAsyncIterator end(void); + + +protected: + typedef queue< CRef > TObjectsQueue; +#if NCBI_COMPILER_MSVC && _MSC_VER < 1900 + typedef function, ESerialDataFormat, const CParams&, TObjectsQueue)> FParserFunction; +#else + typedef function, ESerialDataFormat, const CParams&, TObjectsQueue&&)> FParserFunction; +#endif + CObjectIStreamAsyncIterator( CObjectIStream& istr, + EOwnership deleteInStream, + FParserFunction parser, + const CParams& params); +private: + static TObjectsQueue sx_ClearGarbageAndParse( + CRef bytesource, ESerialDataFormat format, + const CParams& params, +#if NCBI_COMPILER_MSVC && _MSC_VER < 1900 + TObjectsQueue garbage +#else + TObjectsQueue&& garbage +#endif + ); + + struct CData { + CData(CObjectIStream& istr, EOwnership deleteInStream, FParserFunction parser, + const CParams& params); + ~CData(void); + + using future_queue_t = future; + using futures_queue_t = queue; + + void x_UpdateObjectsQueue(); + void x_UpdateFuturesQueue(); + CRef< CByteSource > x_GetNextData(void); + void x_ReaderThread(void); + + TObjectsQueue m_ObjectsQueue; // current queue of objects + TObjectsQueue m_GarbageQueue; // popped so-far from objects-queue + futures_queue_t m_FuturesQueue; // queue-of-futures-of-object-queues + + CObjectIStream* m_Istr; + EOwnership m_Own; + FParserFunction m_Parser; + size_t m_ParserCount; + size_t m_RawBufferSize; + size_t m_MaxRawSize; + size_t m_CurrentRawSize; + launch m_Policy; + bool m_EndOfData; + CParams m_Params; + + mutex m_ReaderMutex; + condition_variable m_ReaderCv; + thread m_Reader; + queue< CRef< CByteSource > > m_ReaderData; + queue< size_t > m_ReaderDataSize; + }; + shared_ptr m_Data; +}; + + +///////////////////////////////////////////////////////////////////////////// +/// CObjectIStreamAsyncIterator + +template +class CObjectIStreamAsyncIterator + : public CObjectIStreamAsyncIterator +{ +public: + using CParams = CObjectIStreamAsyncIterator<>::CParams; + + CObjectIStreamAsyncIterator( CObjectIStream& istr, + EOwnership deleteInStream = eNoOwnership, + const CParams& params = CParams()); + CObjectIStreamAsyncIterator(void); + CObjectIStreamAsyncIterator(const CObjectIStreamAsyncIterator&); + CObjectIStreamAsyncIterator& operator=(const CObjectIStreamAsyncIterator&); + ~CObjectIStreamAsyncIterator(); + + CObjectIStreamAsyncIterator& operator++(void); + CObjectIStreamAsyncIterator& begin(void); + CObjectIStreamAsyncIterator end(void); + + +private: + using CParent = CObjectIStreamAsyncIterator; + using TObjectsQueue = typename CParent::TObjectsQueue; + + static TObjectsQueue sx_ClearGarbageAndParse( + CRef bytesource, ESerialDataFormat format, + const CParams& params, +#if NCBI_COMPILER_MSVC && _MSC_VER < 1900 + TObjectsQueue garbage +#else + TObjectsQueue&& garbage +#endif + ); +}; + +///////////////////////////////////////////////////////////////////////////// +/// CObjectIStreamAsyncIterator implementation + +template +CObjectIStreamAsyncIterator::CObjectIStreamAsyncIterator(void) + : m_Data(nullptr) +{ +} + +template +CObjectIStreamAsyncIterator::CObjectIStreamAsyncIterator( + CObjectIStream& istr, EOwnership deleteInStream, + const CParams& params) + : CObjectIStreamAsyncIterator( istr, deleteInStream, + &CObjectIStreamAsyncIterator::sx_ClearGarbageAndParse, params) +{ +} + +template +CObjectIStreamAsyncIterator::CObjectIStreamAsyncIterator( + CObjectIStream& istr, EOwnership deleteInStream, + FParserFunction parser, const CParams& params) + : m_Data(new CData(istr, deleteInStream, parser, params)) +{ + ++(*this); +} + +template +CObjectIStreamAsyncIterator::CObjectIStreamAsyncIterator( + const CObjectIStreamAsyncIterator& v) + : m_Data(v.m_Data) +{ +} + +template +CObjectIStreamAsyncIterator& +CObjectIStreamAsyncIterator::operator=( + const CObjectIStreamAsyncIterator& v) { + m_Data = v.m_Data; + return *this; +} + +template +CObjectIStreamAsyncIterator::~CObjectIStreamAsyncIterator() { +} + +template +CObjectIStreamAsyncIterator& +CObjectIStreamAsyncIterator::operator++() { + if (m_Data.get() != nullptr) { + do { + m_Data->x_UpdateFuturesQueue(); + m_Data->x_UpdateObjectsQueue(); + } while (!IsValid() && !m_Data->m_EndOfData); + if (!IsValid()) { + m_Data.reset(); + } + } + return *this; +} + +template +bool +CObjectIStreamAsyncIterator::operator==( + const CObjectIStreamAsyncIterator& v) const { + return m_Data.get() == v.m_Data.get(); +} + +template +bool +CObjectIStreamAsyncIterator::operator!=( + const CObjectIStreamAsyncIterator& v) const { + return m_Data.get() != v.m_Data.get(); +} + +template +bool CObjectIStreamAsyncIterator::IsValid() const { + return m_Data.get() != nullptr && !m_Data->m_ObjectsQueue.empty(); +} + +template +TRoot& +CObjectIStreamAsyncIterator::operator*() { + return m_Data->m_ObjectsQueue.front().GetObject(); +} + +template +TRoot* +CObjectIStreamAsyncIterator::operator->() { + return IsValid() ? m_Data->m_ObjectsQueue.front().GetPointer() : nullptr; +} + +template +CObjectIStreamAsyncIterator& +CObjectIStreamAsyncIterator::begin(void) { + return *this; +} + +template +CObjectIStreamAsyncIterator +CObjectIStreamAsyncIterator::end(void) { + return CObjectIStreamAsyncIterator(); +} + + +template +typename CObjectIStreamAsyncIterator::TObjectsQueue +CObjectIStreamAsyncIterator::sx_ClearGarbageAndParse( + CRef bytesource, + ESerialDataFormat format, + const CParams& params, +#if NCBI_COMPILER_MSVC && _MSC_VER < 1900 + TObjectsQueue garbage +#else + TObjectsQueue&& garbage +#endif + ) +{ + {{ + TObjectsQueue dummy; + swap(garbage, dummy); + // garbage now gets destroyed, if last-reference + }} + + // deserialize objects from bytesource + unique_ptr istr { CObjectIStream::Create(format, *bytesource) }; + + TObjectsQueue queue; + if (params.m_FnFilter) { + for (TRoot& object : CObjectIStreamIterator( *istr, eNoOwnership, params)) { + queue.push( CRef(&object)); + } + } else { + while(!istr->EndOfData()) { + CRef object(new TRoot); + istr->Read(&*object, object->GetThisTypeInfo()); + queue.push(object); + } + } + return queue; +} + +template +CObjectIStreamAsyncIterator::CData::CData( + CObjectIStream& istr, EOwnership deleteInStream, FParserFunction parser, + const CParams& params) + : m_Istr(&istr) + , m_Own(deleteInStream) + , m_Parser(parser) + , m_ParserCount( params.m_MaxParserThreads != 0 ? params.m_MaxParserThreads : 16) + , m_RawBufferSize( params.m_MinRawBufferSize) + , m_MaxRawSize( params.m_SameThread ? 0 : params.m_MaxTotalRawSize) + , m_CurrentRawSize(0) + , m_Policy(params.m_ThreadPolicy) + , m_EndOfData(m_Istr->EndOfData()) + , m_Params(params) +{ + if (m_MaxRawSize != 0 && !m_EndOfData) { + m_Reader = thread( + mem_fun::CData >( + &CObjectIStreamAsyncIterator::CData::x_ReaderThread), this); + } +} + +template +CObjectIStreamAsyncIterator::CData::~CData() { + if (m_Reader.joinable()) { + m_EndOfData = true; + m_ReaderCv.notify_all(); + m_Reader.join(); + } + if (m_Istr && m_Own == eTakeOwnership) { + delete m_Istr; + } +} + +// m_GarbageQueue processing: +// +// When the current object (the one returned by operator*()) +// goes out of scope, if it is the last reference, the +// destructor of the object will be called from main +// thread, which is an expensive operation, which +// we want to offload to a different thread - "here are some +// objects - just let them go out of scope" +// +// So before calling m_ObjectsQueue pop we'll save the +// current object in the garbage-queue to prevent it from being +// destructed at this time, and will pass the garbage +// queue to sx_ClearGarbageAndParse (executed asynchrously), +// where the destructors of the garbage-objects will be called +// (as apporpriate, as determined by CRefs going out of scope) + +template +void +CObjectIStreamAsyncIterator::CData::x_UpdateObjectsQueue() +{ + // bring the next objects up front; save the garbage + if(!m_ObjectsQueue.empty()) { + m_GarbageQueue.push( m_ObjectsQueue.front()); + m_ObjectsQueue.pop(); + } + + // unpack the next objects-queue from futures-queue if empty + if( m_ObjectsQueue.empty() + && !m_FuturesQueue.empty()) + { + m_ObjectsQueue = m_FuturesQueue.front().get(); + m_FuturesQueue.pop(); + } +} + +template +void +CObjectIStreamAsyncIterator::CData::x_UpdateFuturesQueue() +{ + // nothing to deserialize, or already full + if( m_FuturesQueue.size() >= m_ParserCount) { + return; + } + if (m_EndOfData || + // no raw data ready yet, but we still have work to do + (m_MaxRawSize != 0 && m_ReaderData.empty() && !m_FuturesQueue.empty())) { + return; + } + CRef< CByteSource > data = x_GetNextData(); + if (data.IsNull()) { + m_EndOfData = true; + return; + } + +#if 0 + // for reference / profiling: clearing the garbage-queue + // from this thread will make the processing considerably slower. + // Instead, we'll pass the garbage to the async call below. + if(false) { + TObjectsQueue dummy; + swap(m_GarbageQueue, dummy); + } +#endif + + // launch async task to deserialize objects + // from the skipped bytes in delay-buffer, and + // also pass the garbage queue for destruction + // of contents. + // note: we can't move m_GarbageQueue directly + // as it lacks ::clear() method that could restore + // it to a valid empty state after move. + + TObjectsQueue tmp_garbage_queue; + swap(m_GarbageQueue, tmp_garbage_queue); + + m_FuturesQueue.push( async( m_Policy, m_Parser, + data, m_Istr->GetDataFormat(), m_Params, move(tmp_garbage_queue))); +} + +template +CRef< CByteSource > +CObjectIStreamAsyncIterator::CData::x_GetNextData(void) +{ + if (m_MaxRawSize == 0) { + // read raw data in this (main) thread + if (m_Istr->EndOfData()) { + return CRef< CByteSource >(); + } + const CNcbiStreampos endpos = + m_Istr->GetStreamPos() + (CNcbiStreampos)(m_RawBufferSize); + CStreamDelayBufferGuard guard(*m_Istr); + do { + m_Istr->SkipAnyContentObject(); + } while( !m_Istr->EndOfData() && m_Istr->GetStreamPos() < endpos); + return guard.EndDelayBuffer(); + } + + // get raw data prepared by reader + unique_lock lck(m_ReaderMutex); + while (m_ReaderData.empty()) { + m_ReaderCv.wait(lck); + } + CRef< CByteSource > data = m_ReaderData.front(); + m_ReaderData.pop(); + m_CurrentRawSize -= m_ReaderDataSize.front(); + m_ReaderDataSize.pop(); + m_ReaderCv.notify_one(); + return data; +} + +template +void +CObjectIStreamAsyncIterator::CData::x_ReaderThread(void) +{ + // Skip over some objects in stream without parsing, up to buffer_size. + while (!m_Istr->EndOfData()) { + const CNcbiStreampos startpos = m_Istr->GetStreamPos(); + const CNcbiStreampos endpos = + startpos + (CNcbiStreampos)(m_RawBufferSize); + + CStreamDelayBufferGuard guard(*(m_Istr)); + try { + do { + m_Istr->SkipAnyContentObject(); + } while( !m_Istr->EndOfData() && m_Istr->GetStreamPos() < endpos); + } catch (...) { + } + + size_t this_buffer_size = m_Istr->GetStreamPos() - startpos; + CRef< CByteSource > data = guard.EndDelayBuffer(); + { + unique_lock lck(m_ReaderMutex); + // make sure we do not consume too much memory + while (!m_EndOfData && m_CurrentRawSize >= m_MaxRawSize) { + m_ReaderCv.wait(lck); + } + if (m_EndOfData) { + break; + } + m_ReaderData.push( data); + m_ReaderDataSize.push( this_buffer_size); + m_CurrentRawSize += this_buffer_size; + m_ReaderCv.notify_one(); + } + } + CRef< CByteSource > data; + m_ReaderMutex.lock(); + m_ReaderData.push( data); + m_ReaderDataSize.push(0); + m_ReaderMutex.unlock(); + m_ReaderCv.notify_one(); +} + + +///////////////////////////////////////////////////////////////////////////// +/// CObjectIStreamAsyncIterator implementation + +template +CObjectIStreamAsyncIterator::CObjectIStreamAsyncIterator(void) + : CParent() +{ +} + +template +CObjectIStreamAsyncIterator::CObjectIStreamAsyncIterator( + CObjectIStream& istr, EOwnership deleteInStream, + const CParams& params) + : CParent(istr, deleteInStream, + &CObjectIStreamAsyncIterator::sx_ClearGarbageAndParse, params) +{ +} + +template +CObjectIStreamAsyncIterator::CObjectIStreamAsyncIterator( + const CObjectIStreamAsyncIterator& v) + : CParent(v) +{ +} + +template +CObjectIStreamAsyncIterator& +CObjectIStreamAsyncIterator::operator=( + const CObjectIStreamAsyncIterator& v) { + CParent::operator=(v); + return *this; +} + +template +CObjectIStreamAsyncIterator::~CObjectIStreamAsyncIterator() { +} + +template +CObjectIStreamAsyncIterator& +CObjectIStreamAsyncIterator::operator++() { + CParent::operator++(); + return *this; +} + +template +CObjectIStreamAsyncIterator& +CObjectIStreamAsyncIterator::begin(void) { + return *this; +} + +template +CObjectIStreamAsyncIterator +CObjectIStreamAsyncIterator::end(void) { + return CObjectIStreamAsyncIterator(); +} + +template +typename CObjectIStreamAsyncIterator::TObjectsQueue +CObjectIStreamAsyncIterator::sx_ClearGarbageAndParse( + CRef bytesource, + ESerialDataFormat format, + const CParams& params, +#if NCBI_COMPILER_MSVC && _MSC_VER < 1900 + TObjectsQueue garbage +#else + TObjectsQueue&& garbage +#endif + ) +{ + {{ + TObjectsQueue dummy; + swap(garbage, dummy); + // garbage now gets destroyed, if last-reference + }} + + // deserialize objects from bytesource + unique_ptr istr { CObjectIStream::Create(format, *bytesource) }; + TObjectsQueue queue; + for (TChild& object : CObjectIStreamIterator( *istr, eNoOwnership, params)) { + queue.push( CRef(&object)); + } + return queue; +} + + + + +///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // Iterate over objects in input stream +// // IMPORTANT: the following API requires multi-threading -#if defined(NCBI_THREADS) +// +// IMPORTANT: this API is deprecated, use CObjectIStreamIterator instead (defined above) + template class CIStreamIteratorThread_Base; @@ -313,7 +1961,7 @@ public: } }; -#endif // _MT +#endif // NCBI_THREADS /* @} */ diff --git a/c++/include/serial/typeinfo.hpp b/c++/include/serial/typeinfo.hpp index 9427ef33..459146f9 100644 --- a/c++/include/serial/typeinfo.hpp +++ b/c++/include/serial/typeinfo.hpp @@ -1,7 +1,7 @@ #ifndef TYPEINFO__HPP #define TYPEINFO__HPP -/* $Id: typeinfo.hpp 507795 2016-07-21 17:24:14Z gouriano $ +/* $Id: typeinfo.hpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -270,6 +270,12 @@ public: size_t GetCodeVersion(void) const { return m_CodeVer; } + void DataSpec(EDataSpec spec) { + m_DataSpec = spec; + } + EDataSpec GetDataSpec(void) const { + return m_DataSpec; + } private: // private constructors to avoid copying CTypeInfo(const CTypeInfo&); @@ -282,6 +288,7 @@ private: string m_ModuleName; mutable CNamespaceInfoItem* m_InfoItem; size_t m_CodeVer; + EDataSpec m_DataSpec; protected: void SetCreateFunction(TTypeCreate func); diff --git a/c++/include/util/bitset/bm.h b/c++/include/util/bitset/bm.h index 7c45f166..d25bb465 100644 --- a/c++/include/util/bitset/bm.h +++ b/c++/include/util/bitset/bm.h @@ -33,14 +33,24 @@ For more information please visit: http://bmagic.sourceforge.net # include #endif +#include + #ifdef _MSC_VER #pragma warning( push ) #pragma warning( disable : 4311 4312 4127) #endif +#if defined(__x86_64) || defined(_M_AMD64) || defined(_WIN64) || \ + defined(__LP64__) || defined(_LP64) || ( __WORDSIZE == 64 ) +#ifndef BM64OPT +# define BM64OPT +#endif +#endif + #ifdef BMSSE42OPT -# ifdef BM64OPT +# if defined(BM64OPT) || defined(__x86_64) || defined(_M_AMD64) || defined(_WIN64) || \ + defined(__LP64__) || defined(_LP64) # undef BM64OPT # define BM64_SSE4 # endif @@ -94,17 +104,19 @@ namespace bm -//typedef bm::miniset mem_save_set; -/** @defgroup bmagic BitMagic C++ Library - * For more information please visit: http://bmagic.sourceforge.net +/** @defgroup bmagic BitMagic Library + BitMagic C++ Library + For more information please visit: http://bmagic.sourceforge.net + https://github.com/tlk00/BitMagic * */ -/** @defgroup bvector The Main bvector<> Group - * This is the main group. It includes bvector template: front end of the bm library. +/** @defgroup bvector bvector<> + The Main bvector<> Group + bvector<> template: front end of the BitMagic library. * @ingroup bmagic */ @@ -112,7 +124,8 @@ namespace bm /*! - @brief bitvector with runtime compression of bits. + @brief bitvector + Bit-vector container with runtime compression of bits @ingroup bvector */ @@ -343,8 +356,10 @@ public: typedef void pointer; typedef void reference; + insert_iterator() : bvect_(0), max_bit_(0) {} + insert_iterator(bvector& bvect) - : bvect_(bvect), + : bvect_(&bvect), max_bit_(bvect.size()) { } @@ -354,7 +369,13 @@ public: max_bit_(iit.max_bit_) { } - + insert_iterator& operator=(const insert_iterator& ii) + { + bvect_ = ii.bvect_; + max_bit_ = ii.max_bit_; + return *this; + } + insert_iterator& operator=(bm::id_t n) { BM_ASSERT(n < bm::id_max); @@ -362,13 +383,13 @@ public: if (n >= max_bit_) { max_bit_ = n; - if (n >= bvect_.size()) + if (n >= bvect_->size()) { - bvect_.resize(n + 1); + bvect_->resize(n + 1); } } - bvect_.set(n); + bvect_->set(n); return *this; } @@ -378,11 +399,9 @@ public: insert_iterator& operator++() { return *this; } /*! Returns *this. This iterator does not move (no-op)*/ insert_iterator& operator++(int) { return *this; } - private: - insert_iterator& operator=(const insert_iterator& ); protected: - bm::bvector& bvect_; + bm::bvector* bvect_; bm::id_t max_bit_; }; @@ -480,6 +499,8 @@ public: this->position_ += bits_in_block; continue; } + if (this->block_ == FULL_BLOCK_FAKE_ADDR) + this->block_ = FULL_BLOCK_REAL_ADDR; if (BM_IS_GAP(this->block_)) { @@ -612,6 +633,8 @@ public: this->position_ += bm::bits_in_block; continue; } + if (this->block_ == FULL_BLOCK_FAKE_ADDR) + this->block_ = FULL_BLOCK_REAL_ADDR; if (BM_IS_GAP(this->block_)) { @@ -791,6 +814,23 @@ public: friend class iterator_base; friend class enumerator; +public: + /*! @brief memory allocation policy + + Defualt memory allocation policy uses BM_BIT, and standard + GAP levels tune-ups + */ + struct allocation_policy + { + bm::strategy strat; + const gap_word_t* glevel_len; + + allocation_policy(bm::strategy s=BM_BIT, + const gap_word_t* glevels = bm::gap_len_table::_len) + : strat(BM_BIT), glevel_len(glevels) + {} + }; + public: #ifdef BMCOUNTOPT @@ -841,6 +881,7 @@ public: - bvector size (number of bits addressable by bvector), bm::id_max means "no limits" (recommended). bit vector allocates this space dynamically on demand. + \param alloc - alllocator for this instance \sa bm::gap_len_table bm::gap_len_table_min set_new_blocks_strat */ @@ -1375,7 +1416,7 @@ public: @sa optmode, optimize_gap_size */ - void optimize(bm::word_t* temp_block = 0, + void optimize(bm::word_t* temp_block = 0, optmode opt_mode = opt_compress, statistics* stat = 0); @@ -1820,6 +1861,8 @@ bool bvector::get_bit(bm::id_t n) const unsigned nblock = unsigned(n >> bm::set_block_shift); const bm::word_t* block = blockman_.get_block(nblock); + if (IS_FULL_BLOCK(block)) + return true; if (block) { @@ -1846,7 +1889,7 @@ bool bvector::get_bit(bm::id_t n) const // ----------------------------------------------------------------------- template -void bvector::optimize(bm::word_t* temp_block, +void bvector::optimize(bm::word_t* temp_block, optmode opt_mode, statistics* stat) { @@ -1862,14 +1905,11 @@ void bvector::optimize(bm::word_t* temp_block, stat); if (stat) { - stat->bit_blocks = stat->gap_blocks - = stat->max_serialize_mem - = stat->memory_used - = 0; + stat->bit_blocks = stat->gap_blocks = 0; + stat->max_serialize_mem = stat->memory_used = 0; ::memcpy(stat->gap_levels, blockman_.glen(), sizeof(gap_word_t) * bm::gap_levels); stat->max_serialize_mem = (unsigned)sizeof(id_t) * 4; - } for_each_nzblock(blk_root, blockman_.effective_top_block_size(), @@ -1877,12 +1917,16 @@ void bvector::optimize(bm::word_t* temp_block, if (stat) { - unsigned safe_inc = stat->max_serialize_mem / 10; // 10% increment + size_t safe_inc = stat->max_serialize_mem / 10; // 10% increment if (!safe_inc) safe_inc = 256; stat->max_serialize_mem += safe_inc; stat->memory_used += (unsigned)(sizeof(*this) - sizeof(blockman_)); stat->memory_used += blockman_.mem_used(); } + + // the expectation is that we don't need to keep temp block if we + // optimizing memory usage + blockman_.free_temp_block(); } // ----------------------------------------------------------------------- @@ -1935,8 +1979,7 @@ int bvector::compare(const bvector& bv) const for (unsigned i = 0; i < top_blocks; ++i) { const bm::word_t* const* blk_blk = blockman_.get_topblock(i); - const bm::word_t* const* arg_blk_blk = - bv.blockman_.get_topblock(i); + const bm::word_t* const* arg_blk_blk = bv.blockman_.get_topblock(i); if (blk_blk == arg_blk_blk) { @@ -1948,7 +1991,11 @@ int bvector::compare(const bvector& bv) const { const bm::word_t* arg_blk = arg_blk_blk ? arg_blk_blk[j] : 0; const bm::word_t* blk = blk_blk ? blk_blk[j] : 0; - if (blk == arg_blk) continue; + if (arg_blk == FULL_BLOCK_FAKE_ADDR) + arg_blk = FULL_BLOCK_REAL_ADDR; + if (blk == FULL_BLOCK_FAKE_ADDR) + blk = FULL_BLOCK_REAL_ADDR; + if (blk == arg_blk) continue; // If one block is zero we check if the other one has at least // one bit ON @@ -2054,9 +2101,10 @@ int bvector::compare(const bvector& bv) const template void bvector::calc_stat(struct bvector::statistics* st) const { - st->bit_blocks = st->gap_blocks - = st->max_serialize_mem - = st->memory_used = 0; + BM_ASSERT(st); + + st->bit_blocks = st->gap_blocks = 0; + st->max_serialize_mem = st->memory_used = 0; ::memcpy(st->gap_levels, blockman_.glen(), sizeof(gap_word_t) * bm::gap_levels); @@ -2122,7 +2170,7 @@ void bvector::calc_stat(struct bvector::statistics* st) const } } - unsigned safe_inc = st->max_serialize_mem / 10; // 10% increment + size_t safe_inc = st->max_serialize_mem / 10; // 10% increment if (!safe_inc) safe_inc = 256; st->max_serialize_mem += safe_inc; @@ -2218,7 +2266,7 @@ bool bvector::set_bit_conditional_impl(bm::id_t n, unsigned nblock = unsigned(n >> bm::set_block_shift); int block_type; - bm::word_t* blk = + bm::word_t* blk = blockman_.check_allocate_block(nblock, val, get_new_blocks_strat(), @@ -2298,7 +2346,7 @@ bool bvector::and_bit_no_check(bm::id_t n, bool val) unsigned nblock = unsigned(n >> bm::set_block_shift); int block_type; - bm::word_t* blk = + bm::word_t* blk = blockman_.check_allocate_block(nblock, val, get_new_blocks_strat(), @@ -2520,7 +2568,7 @@ bm::id_t bvector::check_or_next_extract(bm::id_t prev) template void bvector::combine_operation( - const bm::bvector& bv, + const bm::bvector& bv, bm::operation opcode) { /*typedef void (*block_bit_op)(bm::word_t*, const bm::word_t*); @@ -2532,7 +2580,7 @@ void bvector::combine_operation( unsigned top_blocks = blockman_.top_block_size(); unsigned bvect_top_blocks = bv.blockman_.top_block_size(); - if (size_ == bv.size_) + if (size_ == bv.size_) { BM_ASSERT(top_blocks >= bvect_top_blocks); } @@ -2612,7 +2660,7 @@ void bvector::combine_operation( bm::word_t* blk = blk_blk[j]; if (blk) { - const bm::word_t* arg_blk = bv.blockman_.get_block(i, j); + const bm::word_t* arg_blk = bv.blockman_.get_block(i, j); if (arg_blk) combine_operation_with_block(r + j, BM_IS_GAP(blk), blk, @@ -2630,7 +2678,7 @@ void bvector::combine_operation( for (j = 0; j < bm::set_array_size; ++j)//, ++block_idx) { bm::word_t* blk = blk_blk[j]; - const bm::word_t* arg_blk = bv.blockman_.get_block(i, j); + const bm::word_t* arg_blk = bv.blockman_.get_block(i, j); if (arg_blk || blk) combine_operation_with_block(r + j, BM_IS_GAP(blk), blk, arg_blk, BM_IS_GAP(arg_blk), @@ -3015,7 +3063,7 @@ void bvector::set_range_no_check(bm::id_t left, bool is_gap = BM_IS_GAP(block); - blockman_.set_block(nb, FULL_BLOCK_ADDR); + blockman_.set_block(nb, FULL_BLOCK_FAKE_ADDR); blockman_.set_block_bit(nb); if (is_gap) diff --git a/c++/include/util/bitset/bmalgo_impl.h b/c++/include/util/bitset/bmalgo_impl.h index 50d8f781..b02764f0 100644 --- a/c++/include/util/bitset/bmalgo_impl.h +++ b/c++/include/util/bitset/bmalgo_impl.h @@ -37,14 +37,18 @@ For more information please visit: http://bmagic.sourceforge.net namespace bm { -/*! \defgroup setalgo Set algorithms - * Set algorithms - * \ingroup bmagic +/*! + @defgroup setalgo Bitset algorithms + + Set algebra algorithms + @ingroup bvector */ -/*! \defgroup distance Distance metrics - * Algorithms to compute binary distance metrics - * \ingroup setalgo +/*! + @defgroup distance Binary-distance metrics + + Distance metrics and algorithms to compute binary distances + @ingroup setalgo */ @@ -113,14 +117,12 @@ struct distance_metric_descriptor */ inline -void combine_count_operation_with_block(const bm::word_t* blk, - //unsigned gap, - const bm::word_t* arg_blk, - //int arg_gap, +void combine_count_operation_with_block(const bm::word_t* blk, + const bm::word_t* arg_blk, distance_metric_descriptor* dmit, distance_metric_descriptor* dmit_end) -{ +{ gap_word_t* g1 = BMGAP_PTR(blk); gap_word_t* g2 = BMGAP_PTR(arg_blk); @@ -197,9 +199,7 @@ void combine_count_operation_with_block(const bm::word_t* blk, case bm::COUNT_SUB_BA: dmd.metric = bm::COUNT_SUB_AB; // recursive call to SUB_AB combine_count_operation_with_block(arg_blk, -// arg_gap, blk, -// gap, it, it+1); dmd.metric = bm::COUNT_SUB_BA; // restore status quo break; @@ -762,7 +762,7 @@ void distance_operation(const BV& bv1, for (j = 0; j < bm::set_array_size; ++j, ++block_idx) { - blk = blk_blk[j]; + blk = BLOCK_ADDR_SAN(blk_blk[j]); if (blk == 0 && is_all_and) continue; @@ -801,8 +801,6 @@ unsigned distance_and_operation(const BV& bv1, bm::word_t*** blk_root = bman1.get_rootblock(); bm::word_t*** blk_root_arg = bman2.get_rootblock(); -// unsigned i, j; - unsigned count = 0; BM_SET_MMX_GUARD @@ -822,40 +820,17 @@ unsigned distance_and_operation(const BV& bv1, for (unsigned j = 0; j < bm::set_array_size; j+=4) { (blk_blk[j] && blk_blk_arg[j]) ? - count += combine_count_and_operation_with_block(blk_blk[j],blk_blk_arg[j]) + count += combine_count_and_operation_with_block(BLOCK_ADDR_SAN(blk_blk[j]), BLOCK_ADDR_SAN(blk_blk_arg[j])) :0; (blk_blk[j+1] && blk_blk_arg[j+1]) ? - count += combine_count_and_operation_with_block(blk_blk[j+1],blk_blk_arg[j+1]) + count += combine_count_and_operation_with_block(BLOCK_ADDR_SAN(blk_blk[j+1]), BLOCK_ADDR_SAN(blk_blk_arg[j+1])) :0; (blk_blk[j+2] && blk_blk_arg[j+2]) ? - count += combine_count_and_operation_with_block(blk_blk[j+2],blk_blk_arg[j+2]) + count += combine_count_and_operation_with_block(BLOCK_ADDR_SAN(blk_blk[j+2]), BLOCK_ADDR_SAN(blk_blk_arg[j+2])) :0; (blk_blk[j+3] && blk_blk_arg[j+3]) ? - count += combine_count_and_operation_with_block(blk_blk[j+3],blk_blk_arg[j+3]) + count += combine_count_and_operation_with_block(BLOCK_ADDR_SAN(blk_blk[j+3]), BLOCK_ADDR_SAN(blk_blk_arg[j+3])) :0; -/* - if ((blk = blk_blk[j]) && (arg_blk = blk_blk_arg[j]) ) - { - count += - combine_count_and_operation_with_block(blk,arg_blk); - } - - if ((blk = blk_blk[j+1]) && (arg_blk = blk_blk_arg[j+1]) ) - { - count += - combine_count_and_operation_with_block(blk,arg_blk); - } - if ((blk = blk_blk[j+2]) && (arg_blk = blk_blk_arg[j+2]) ) - { - count += - combine_count_and_operation_with_block(blk, arg_blk); - } - if ((blk = blk_blk[j+3]) && (arg_blk = blk_blk_arg[j+3]) ) - { - count += - combine_count_and_operation_with_block(blk, arg_blk); - } -*/ } // for j } // for i @@ -896,7 +871,6 @@ void distance_operation_any(const BV& bv1, const typename BV::blocks_manager_type& bman2 = bv2.get_blocks_manager(); bool is_all_and = true; // flag is distance operation is just COUNT_AND - //bm::word_t* temp_blk = distance_stage(dmit, dmit_end, &is_all_and); bm::word_t*** blk_root = bman1.get_rootblock(); @@ -970,7 +944,7 @@ void distance_operation_any(const BV& bv1, for (j = 0; j < bm::set_array_size; ++j, ++block_idx) { - blk = blk_blk[j]; + blk = BLOCK_ADDR_SAN(blk_blk[j]); if (blk == 0 && is_all_and) continue; @@ -1196,7 +1170,7 @@ void combine_or(BV& bv, It first, It last) label1: int block_type; - bm::word_t* blk = + bm::word_t* blk = bman.check_allocate_block(nblock, true, bv.get_new_blocks_strat(), @@ -1275,7 +1249,7 @@ void combine_xor(BV& bv, It first, It last) label1: int block_type; - bm::word_t* blk = + bm::word_t* blk = bman.check_allocate_block(nblock, true, bv.get_new_blocks_strat(), @@ -1359,7 +1333,7 @@ void combine_sub(BV& bv, It first, It last) label1: int block_type; - bm::word_t* blk = + bm::word_t* blk = bman.check_allocate_block(nblock, false, bv.get_new_blocks_strat(), @@ -1523,7 +1497,7 @@ void export_array(BV& bv, It first, It last) size_t word_cnt = array_size / 4; for (unsigned i = 0; i < bm::set_total_blocks; ++i) { - bm::word_t* blk = + bm::word_t* blk = bman.check_allocate_block(i, false, BM_BIT, @@ -1577,7 +1551,7 @@ void export_array(BV& bv, It first, It last) size_t word_cnt = array_size / 2; for (unsigned i = 0; i < bm::set_total_blocks; ++i) { - bm::word_t* blk = + bm::word_t* blk = bman.check_allocate_block(i, false, BM_BIT, @@ -1625,7 +1599,7 @@ void export_array(BV& bv, It first, It last) size_t word_cnt = array_size; for (unsigned i = 0; i < bm::set_total_blocks; ++i) { - bm::word_t* blk = + bm::word_t* blk = bman.check_allocate_block(i, false, BM_BIT, diff --git a/c++/include/util/bitset/bmalloc.h b/c++/include/util/bitset/bmalloc.h index 6fc53d90..3f5fe7a6 100644 --- a/c++/include/util/bitset/bmalloc.h +++ b/c++/include/util/bitset/bmalloc.h @@ -33,11 +33,13 @@ namespace bm { -/*! @defgroup alloc Memory Allocation - * Memory allocation related units - * @ingroup bmagic - * - * @{ +/*! + @defgroup alloc Allocator + Memory allocation for bvector + + @ingroup bvector + + @{ */ /*! @@ -186,9 +188,10 @@ public: /*! @brief Allocates GAP block using bit block allocator (BA). GAP blocks in BM library belong to levels. Each level has a - correspondent length described in bm::gap_len_table<>. + correspondent length described in bm::gap_len_table<> @param level GAP block level. + @param glevel_len table of level lengths */ bm::gap_word_t* alloc_gap_block(unsigned level, const gap_word_t* glevel_len) diff --git a/c++/include/util/bitset/bmblocks.h b/c++/include/util/bitset/bmblocks.h index e7978cdc..6fcf0898 100644 --- a/c++/include/util/bitset/bmblocks.h +++ b/c++/include/util/bitset/bmblocks.h @@ -47,7 +47,7 @@ namespace bm @internal */ -template +template class blocks_manager { public: @@ -280,7 +280,7 @@ public: else if (gap_is_all_one(gap_blk, bm::gap_max_bits)) { - bman.set_block_ptr(idx, FULL_BLOCK_ADDR); + bman.set_block_ptr(idx, FULL_BLOCK_FAKE_ADDR); free_block: bman.get_allocator().free_gap_block(gap_blk, bman.glen()); @@ -343,7 +343,7 @@ public: } if (stat_) { - stat_->max_serialize_mem += (unsigned)sizeof(unsigned) + 1; + stat_->max_serialize_mem += (unsigned)(sizeof(unsigned) + 1); } } void on_empty_block(unsigned /* block_idx*/ ) { ++empty_; } @@ -377,7 +377,7 @@ public: else if (gap_is_all_one(gap_blk, bm::gap_max_bits)) { - bman.set_block_ptr(idx, FULL_BLOCK_ADDR); + bman.set_block_ptr(idx, FULL_BLOCK_FAKE_ADDR); this->free_block(gap_blk, idx); ++empty_; } @@ -414,7 +414,7 @@ public: if (b) { bman.get_allocator().free_bit_block(block); - bman.set_block_ptr(idx, FULL_BLOCK_ADDR); + bman.set_block_ptr(idx, FULL_BLOCK_FAKE_ADDR); ++empty_; } } @@ -448,7 +448,7 @@ public: } else if (gap_is_all_one(tmp_gap_blk, bm::gap_max_bits)) { - bman.set_block_ptr(idx, FULL_BLOCK_ADDR); + bman.set_block_ptr(idx, FULL_BLOCK_FAKE_ADDR); ++empty_; } else @@ -500,7 +500,7 @@ public: { if (!block) { - this->bm_.set_block(idx, FULL_BLOCK_ADDR); + this->bm_.set_block(idx, FULL_BLOCK_FAKE_ADDR); } else if (IS_FULL_BLOCK(block)) @@ -742,7 +742,10 @@ public: return 0; } bm::word_t** blk_blk = blocks_[block_idx]; - return blk_blk ? blk_blk[nb & bm::set_array_mask] : 0; + bm::word_t* ret = blk_blk ? blk_blk[nb & bm::set_array_mask] : 0; + if (ret == FULL_BLOCK_FAKE_ADDR) + ret = FULL_BLOCK_REAL_ADDR; + return ret; } /** @@ -764,8 +767,11 @@ public: } *no_more_blocks = 0; bm::word_t** blk_blk = blocks_[block_idx]; - return blk_blk ? blk_blk[nb & bm::set_array_mask] : 0; - } + bm::word_t* ret = blk_blk ? blk_blk[nb & bm::set_array_mask] : 0; + if (ret == FULL_BLOCK_FAKE_ADDR) + ret = FULL_BLOCK_REAL_ADDR; + return ret; + } /** Recalculate absolute block address into coordinates @@ -821,8 +827,11 @@ public: { if (i >= top_block_size_) return 0; const bm::word_t* const* blk_blk = blocks_[i]; - return (blk_blk == 0) ? 0 : blk_blk[j]; - } + const bm::word_t* ret = (blk_blk == 0) ? 0 : blk_blk[j]; + if (ret == FULL_BLOCK_FAKE_ADDR) + ret = FULL_BLOCK_REAL_ADDR; + return ret; + } /** \brief Function returns top-level block in 2-level blocks array @@ -847,7 +856,7 @@ public: void set_block_all_set(unsigned nb) { bm::word_t* block = this->get_block(nb); - set_block(nb, const_cast(FULL_BLOCK_ADDR)); + set_block(nb, const_cast(FULL_BLOCK_FAKE_ADDR)); // If we keep block type flag in pointer itself we dp not need // to clear gap bit @@ -950,7 +959,7 @@ public: { if (IS_FULL_BLOCK(block)) { - new_blk = FULL_BLOCK_ADDR; + new_blk = FULL_BLOCK_FAKE_ADDR; } else { @@ -972,7 +981,7 @@ public: initial_block_type and actual_block_type : 0 - bitset, 1 - gap */ - bm::word_t* check_allocate_block(unsigned nb, + bm::word_t* check_allocate_block(unsigned nb, unsigned content_flag, int initial_block_type, int* actual_block_type, @@ -1049,6 +1058,11 @@ public: { bm::word_t* old_block; + // never use real full block adress, it may be instantiated in another DLL + // (unsafe static instantiation on windows) + if (block == FULL_BLOCK_REAL_ADDR) + block = FULL_BLOCK_FAKE_ADDR; + // top block index register unsigned nblk_blk = nb >> bm::set_array_shift; @@ -1115,20 +1129,15 @@ public: { bm::word_t* old_block; + // never use real full block adress, it may be instantiated in another DLL + // (unsafe static instantiation on windows) + if (block == FULL_BLOCK_REAL_ADDR) + block = FULL_BLOCK_FAKE_ADDR; + if (block) { block = (bm::word_t*) (gap ? BMPTR_SETBIT0(block) : BMPTR_CLEARBIT0(block)); -/* - if (gap) - { - block = (bm::word_t*)BMPTR_SETBIT0(block); - } - else - { - block = (bm::word_t*)BMPTR_CLEARBIT0(block); - } -*/ } // top block index @@ -1168,6 +1177,11 @@ public: void set_block_ptr(unsigned nb, bm::word_t* block) { BM_ASSERT((nb >> bm::set_array_shift) < effective_top_block_size_); + // never use real full block adress, it may be instantiated in another DLL + // (unsafe static instantiation on windows) + if (block == FULL_BLOCK_REAL_ADDR) + block = FULL_BLOCK_FAKE_ADDR; + blocks_[nb >> bm::set_array_shift][nb & bm::set_array_mask] = block; } @@ -1290,23 +1304,6 @@ public: count = (IS_FULL_BLOCK(block)) ? bm::bits_in_block : bit_block_calc_count(block, block + bm::set_block_size); } -/* - if (IS_FULL_BLOCK(block)) - count = bm::bits_in_block; - else - { - if (BM_IS_GAP(block)) - { - count = gap_bit_count(BMGAP_PTR(block)); - } - else // bitset - { - count = - bit_block_calc_count(block, - block + bm::set_block_size); - } - } -*/ return count; } @@ -1443,6 +1440,16 @@ public: return temp_block_ ? temp_block_ : (temp_block_ = alloc_.alloc_bit_block()); } + + /*! deallocate temp block */ + void free_temp_block() + { + if (temp_block_) + { + alloc_.free_bit_block(temp_block_); + temp_block_ = 0; + } + } /*! Assigns new GAP lengths vector */ void set_glen(const gap_word_t* glevel_len) @@ -1474,21 +1481,21 @@ public: unsigned mem_used() const { - unsigned used = (unsigned)sizeof(*this); - used += (unsigned)(temp_block_ ? sizeof(word_t) * bm::set_block_size : 0); - used += (unsigned)(sizeof(bm::word_t**) * top_block_size_); + unsigned m_used = (unsigned)sizeof(*this); + m_used += (unsigned)(temp_block_ ? sizeof(word_t) * bm::set_block_size : 0); + m_used += (unsigned)(sizeof(bm::word_t**) * top_block_size_); #ifdef BM_DISBALE_BIT_IN_PTR - used += (unsigned)(gap_flags_.mem_used() - sizeof(gap_flags_)); + m_used += (unsigned)(gap_flags_.mem_used() - sizeof(gap_flags_)); #endif for (unsigned i = 0; i < top_block_size_; ++i) { - used += (unsigned) + m_used += (unsigned) (blocks_[i] ? sizeof(void*) * bm::set_array_size : 0); } - return used; + return m_used; } /** Returns true if second level block pointer is 0. diff --git a/c++/include/util/bitset/bmconst.h b/c++/include/util/bitset/bmconst.h index a56db57e..d78cb3f8 100644 --- a/c++/include/util/bitset/bmconst.h +++ b/c++/include/util/bitset/bmconst.h @@ -86,25 +86,21 @@ const unsigned bits_in_block = bm::set_block_size * (unsigned)(sizeof(bm::word_t const unsigned bits_in_array = bm::bits_in_block * bm::set_array_size; -#ifdef BM64OPT +#if defined(BM64OPT) || defined(BM64_SSE4) typedef id64_t wordop_t; const id64_t all_bits_mask = 0xffffffffffffffff; - -# define DECLARE_TEMP_BLOCK(x) bm::id64_t x[bm::set_block_size / 2]; const unsigned set_block_size_op = bm::set_block_size / 2; - #else typedef word_t wordop_t; const word_t all_bits_mask = 0xffffffff; - -# define DECLARE_TEMP_BLOCK(x) unsigned x[bm::set_block_size]; const unsigned set_block_size_op = bm::set_block_size; #endif +# define BM_DECLARE_TEMP_BLOCK(x) unsigned BM_ALIGN16 x[bm::set_block_size] BM_ALIGN16ATTR; /*! diff --git a/c++/include/util/bitset/bmdbg.h b/c++/include/util/bitset/bmdbg.h index 2d8fbe3b..684e2690 100644 --- a/c++/include/util/bitset/bmdbg.h +++ b/c++/include/util/bitset/bmdbg.h @@ -33,6 +33,7 @@ For more information please visit: http://bmagic.sourceforge.net #include #include #include +#include #include #include #include @@ -184,8 +185,10 @@ inline void SaveBlob(const char* name_prefix, unsigned num, const char* ext, const unsigned char* blob, unsigned blob_size) { - char fname[2048]; - sprintf(fname, "%s-%u.%s", name_prefix, num, ext); + std::strstream fname_str; + fname_str << name_prefix << "-" << num << ext; + + char* fname = fname_str.str(); ofstream bfile (fname, ios::out | ios::binary); if (!bfile.good()) { @@ -454,6 +457,45 @@ void print_stat(const BV& bv, unsigned blocks = 0) } + + +template +void print_svector_stat(const SV& svect) +{ + typename SV::statistics st; + svect.calc_stat(&st); + + std::cout << "size = " << svect.size() << std::endl; + std::cout << "Bit blocks: " << st.bit_blocks << std::endl; + std::cout << "Gap blocks: " << st.gap_blocks << std::endl; + std::cout << "Max serialize mem:" << st.max_serialize_mem << " " + << (st.max_serialize_mem / (1024 * 1024)) << "MB" << std::endl; + std::cout << "Memory used: " << st.memory_used << " " + << (st.memory_used / (1024 * 1024)) << "MB" << std::endl; + + std::cout << "Projected mem usage for vector:" << sizeof(int) * svect.size() << std::endl; + std::cout << "Projected mem usage for vector:" << sizeof(long long) * svect.size() << std::endl; + + std::cout << "Plains:" << std::endl; + + for (unsigned i = 0; i < svect.plains(); ++i) + { + const typename SV::bvector_type* bv_plain = svect.plain(i); + std::cout << i << ":"; + if (bv_plain == 0) + { + std::cout << "NULL"; + } + else + { + std::cout << bv_plain->count(); + } + std::cout << std::endl; + + } // for i +} + + #include "bmundef.h" diff --git a/c++/include/util/bitset/bmdef.h b/c++/include/util/bitset/bmdef.h index 332a27e7..7d31074c 100644 --- a/c++/include/util/bitset/bmdef.h +++ b/c++/include/util/bitset/bmdef.h @@ -6,6 +6,38 @@ #include +// Incorporate appropriate tuneups when the NCBI C++ Toolkit's core +// headers have been included. +// +#ifdef NCBI_ASSERT +# define BM_ASSERT _ASSERT + +# ifdef HAVE_RESTRICT_CXX +# define BM_HASRESTRICT +# define BMRESTRICT NCBI_RESTRICT +# endif + +# if defined(NCBI_FORCEINLINE) && \ + ( !defined(NCBI_COMPILER_GCC) || NCBI_COMPILER_VERSION >= 400 || \ + defined(__OPTIMIZE__)) +# define BM_HASFORCEINLINE +# define BMFORCEINLINE NCBI_FORCEINLINE +# endif + +# ifdef NCBI_SSE +# if NCBI_SSE >= 20 +# define BMSSE2OPT 1 +# endif +# if NCBI_SSE >= 40 +# define BMSSE2OPT 1 +# endif +# if NCBI_SSE >= 42 +# define BMSSE42OPT 1 +# endif +# endif +#endif + + // macro to define/undefine unaligned memory access (x86, PowerPC) // #if defined(__i386) || defined(__x86_64) || defined(__ppc__) || \ @@ -57,9 +89,13 @@ #endif -#define FULL_BLOCK_ADDR bm::all_set::_block._p -#define IS_VALID_ADDR(addr) bool(addr && (addr != FULL_BLOCK_ADDR)) -#define IS_FULL_BLOCK(addr) bool(addr == FULL_BLOCK_ADDR) +#define FULL_BLOCK_REAL_ADDR bm::all_set::_block._p +#define FULL_BLOCK_FAKE_ADDR bm::all_set::_block._p_fullp +#define BLOCK_ADDR_SAN(addr) (addr == FULL_BLOCK_FAKE_ADDR) ? FULL_BLOCK_REAL_ADDR : addr +//#define IS_VALID_ADDR(addr) bool(addr && (addr != FULL_BLOCK_ADDR) +#define IS_VALID_ADDR(addr) bm::all_set::is_valid_block_addr(addr) +//#define IS_FULL_BLOCK(addr) bool(addr == FULL_BLOCK_ADDR) +#define IS_FULL_BLOCK(addr) bm::all_set::is_full_block(addr) #define IS_EMPTY_BLOCK(addr) bool(addr == 0) // Macro definitions to manipulate bits in pointers diff --git a/c++/include/util/bitset/bmfunc.h b/c++/include/util/bitset/bmfunc.h index a9b5e543..7e638181 100644 --- a/c++/include/util/bitset/bmfunc.h +++ b/c++/include/util/bitset/bmfunc.h @@ -62,9 +62,9 @@ struct bv_statistics /// Number of GAP blocks. unsigned gap_blocks; /// Estimated maximum of memory required for serialization. - unsigned max_serialize_mem; + size_t max_serialize_mem; /// Memory used by bitvector including temp and service blocks - unsigned memory_used; + size_t memory_used; /// Array of all GAP block lengths in the bvector. gap_word_t gap_length[bm::set_total_blocks]; /// GAP lengths used by bvector @@ -92,17 +92,18 @@ struct bv_statistics }; -/*! @defgroup gapfunc GAP functions - * GAP functions implement different opereations on GAP compressed blocks - * and serve as a minimal building blocks. - * @ingroup bmagic - * +/*! + @defgroup gapfunc GAP functions + GAP functions implement different opereations on GAP compressed blocks (internals) + and serve as a minimal building blocks. + @ingroup bvector */ -/*! @defgroup bitfunc BIT functions - * Bit functions implement different opereations on bit blocks - * and serve as a minimal building blocks. - * @ingroup bmagic +/*! + @defgroup bitfunc BIT functions + Bit functions implement different opereations on bit blocks (internals) + and serve as a minimal building blocks. + @ingroup bvector */ @@ -312,15 +313,32 @@ template struct all_set { struct BM_ALIGN16 all_set_block { - bm::word_t _p[bm::set_block_size] BM_ALIGN16ATTR; + bm::word_t _p[bm::set_block_size] BM_ALIGN16ATTR; + bm::word_t* _p_fullp; all_set_block() { ::memset(_p, 0xFF, sizeof(_p)); + if (sizeof(void*) == 8) + { + const unsigned long long magic_mask = 0xFFFFfffeFFFFfffe; + ::memcpy(&_p_fullp, &magic_mask, sizeof(magic_mask)); + } + else + { + const unsigned magic_mask = 0xFFFFfffe; + ::memcpy(&_p_fullp, &magic_mask, sizeof(magic_mask)); + } } }; - static all_set_block _block; + BMFORCEINLINE + static bool is_full_block(const bm::word_t* bp) + { return (bp == _block._p || bp == _block._p_fullp); } + BMFORCEINLINE + static bool is_valid_block_addr(const bm::word_t* bp) + { return (bp && !(bp == _block._p || bp == _block._p_fullp)); } + static all_set_block _block; }; @@ -340,10 +358,10 @@ void xor_swap(W& x, W& y) //--------------------------------------------------------------------- /*! - \brief Lexicographical comparison of two words as bit strings. + \brief Lexicographical comparison of two words as bit strings (reference) Auxiliary implementation for testing and reference purposes. - \param buf1 - First word. - \param buf2 - Second word. + \param w1 - First word. + \param w2 - Second word. \return <0 - less, =0 - equal, >0 - greater. @ingroup bitfunc @@ -361,15 +379,6 @@ template int wordcmp0(T w1, T w2) } -/*! - \brief Lexicographical comparison of two words as bit strings. - Auxiliary implementation for testing and reference purposes. - \param buf1 - First word. - \param buf2 - Second word. - \return <0 - less, =0 - equal, >0 - greater. - - @ingroup bitfunc -*/ /* template int wordcmp(T w1, T w2) { @@ -377,6 +386,15 @@ template int wordcmp(T w1, T w2) return diff ? ((w1 & diff & (diff ^ (diff - 1)))? 1 : -1) : 0; } */ +/*! + \brief Lexicographical comparison of two words as bit strings. + Auxiliary implementation for testing and reference purposes. + \param a - First word. + \param b - Second word. + \return <0 - less, =0 - equal, >0 - greater. + + @ingroup bitfunc +*/ template int wordcmp(T a, T b) { @@ -398,7 +416,7 @@ template struct _copyright }; template const char _copyright::_p[] = - "BitMagic C++ Library. v.3.7.2 (c) 2002-2017 Anatoliy Kuznetsov."; + "BitMagic C++ Library. v.3.8.0 (c) 2002-2017 Anatoliy Kuznetsov."; /*! @@ -518,14 +536,16 @@ template unsigned gap_test(const T* buf, unsigned pos) if (buf[9] >= pos) return sv; BM_ASSERT(0); } - else - while ( start != end ) + else { - unsigned curr = (start + end) >> 1; - if ( buf[curr] < pos ) - start = curr + 1; - else - end = curr; + while (start != end) + { + unsigned curr = (start + end) >> 1; + if (buf[curr] < pos) + start = curr + 1; + else + end = curr; + } } return ((*buf) & 1) ^ ((--start) & 1); } @@ -765,6 +785,7 @@ unsigned gap_bit_count_range(const T* buf, T left, T right) D-Gap Functor is called for each element but last one. \param gap_buf - GAP buffer + \param func - functor object */ template @@ -827,6 +848,7 @@ T* gap_2_dgap(const T* gap_buf, T* dgap_buf, bool copy_head=true) GAP representation is GAP[N] = DGAP[N] + DGAP[N-1] \param dgap_buf - Delta-GAP buffer + \param gap_header - GAP header word \param gap_buf - GAP buffer \internal @@ -1806,11 +1828,12 @@ void gap_and_to_bitset(unsigned* dest, const T* buf) /*! - \brief Compute bitcount of bit block AND masked by GAP block. - \param dest - bitblock buffer pointer. - \param buf - GAP buffer pointer. + \brief Compute bitcount of bit block AND masked by GAP block + \param block - bitblock buffer pointer + \param buf - GAP buffer pointer + \return bitcount - cardinality of the AND product - @ingroup gapfunc bitfunc + @ingroup gapfunc */ template bm::id_t gap_bitset_and_count(const unsigned* block, const T* buf) @@ -1838,10 +1861,11 @@ bm::id_t gap_bitset_and_count(const unsigned* block, const T* buf) /*! \brief Bitcount test of bit block AND masked by GAP block. - \param dest - bitblock buffer pointer. - \param buf - GAP buffer pointer. + \param block - bitblock buffer pointer + \param buf - GAP buffer pointer + \return non-zero value if AND produces any result - @ingroup gapfunc bitfunc + @ingroup gapfunc */ template bm::id_t gap_bitset_and_any(const unsigned* block, const T* buf) @@ -1877,10 +1901,11 @@ bm::id_t gap_bitset_and_any(const unsigned* block, const T* buf) /*! \brief Compute bitcount of bit block SUB masked by GAP block. - \param dest - bitblock buffer pointer. + \param block - bitblock buffer pointer. \param buf - GAP buffer pointer. + \return bit-count result of AND NOT operation - @ingroup gapfunc bitfunc + @ingroup gapfunc */ template bm::id_t gap_bitset_sub_count(const unsigned* block, const T* buf) @@ -1909,11 +1934,12 @@ bm::id_t gap_bitset_sub_count(const unsigned* block, const T* buf) /*! - \brief Compute bitcount test of bit block SUB masked by GAP block. - \param dest - bitblock buffer pointer. - \param buf - GAP buffer pointer. + \brief Compute bitcount test of bit block SUB masked by GAP block + \param block - bitblock buffer pointer + \param buf - GAP buffer pointer + \return non-zero value if AND NOT produces any 1 bits - @ingroup gapfunc bitfunc + @ingroup gapfunc */ template bm::id_t gap_bitset_sub_any(const unsigned* block, const T* buf) @@ -1947,11 +1973,12 @@ bm::id_t gap_bitset_sub_any(const unsigned* block, const T* buf) /*! - \brief Compute bitcount of bit block XOR masked by GAP block. - \param dest - bitblock buffer pointer. - \param buf - GAP buffer pointer. + \brief Compute bitcount of bit block XOR masked by GAP block + \param block - bitblock buffer pointer + \param buf - GAP buffer pointer + \return bit count value of XOR operation - @ingroup gapfunc bitfunc + @ingroup gapfunc */ template bm::id_t gap_bitset_xor_count(const unsigned* block, const T* buf) @@ -1986,10 +2013,11 @@ bm::id_t gap_bitset_xor_count(const unsigned* block, const T* buf) /*! \brief Compute bitcount test of bit block XOR masked by GAP block. - \param dest - bitblock buffer pointer. - \param buf - GAP buffer pointer. + \param block - bitblock buffer pointer + \param buf - GAP buffer pointer + \return non-zero value if XOR returns anything - @ingroup gapfunc bitfunc + @ingroup gapfunc */ template bm::id_t gap_bitset_xor_any(const unsigned* block, const T* buf) @@ -2029,10 +2057,11 @@ bm::id_t gap_bitset_xor_any(const unsigned* block, const T* buf) /*! \brief Compute bitcount of bit block OR masked by GAP block. - \param dest - bitblock buffer pointer. + \param block - bitblock buffer pointer. \param buf - GAP buffer pointer. + \return bit count of OR - @ingroup gapfunc bitfunc + @ingroup gapfunc */ template bm::id_t gap_bitset_or_count(const unsigned* block, const T* buf) @@ -2075,11 +2104,12 @@ bm::id_t gap_bitset_or_count(const unsigned* block, const T* buf) } /*! - \brief Compute bitcount test of bit block OR masked by GAP block. - \param dest - bitblock buffer pointer. - \param buf - GAP buffer pointer. + \brief Compute bitcount test of bit block OR masked by GAP block + \param block - bitblock buffer pointer + \param buf - GAP buffer pointer + \return non zero value if union (OR) returns anything - @ingroup gapfunc bitfunc + @ingroup gapfunc */ template bm::id_t gap_bitset_or_any(const unsigned* block, const T* buf) @@ -2162,7 +2192,7 @@ void gap_convert_to_bitset(unsigned* dest, const T* buf) \brief GAP block to bitblock conversion. \param dest - bitblock buffer pointer. \param buf - GAP buffer pointer. - \param dest_size - length of the destination buffer. + \param dest_len - length/size of the destination buffer. @ingroup gapfunc */ @@ -2194,7 +2224,7 @@ template { if (buf[1] == set_max - 1) { - return (buf[0] & 1) ? FULL_BLOCK_ADDR : 0; + return (buf[0] & 1) ? FULL_BLOCK_REAL_ADDR : 0; } gap_convert_to_bitset(dest, buf); @@ -2238,6 +2268,7 @@ template unsigned gap_control_sum(const T* buf) \brief Sets all bits to 0 or 1 (GAP) \param buf - GAP buffer pointer. \param set_max - max possible bitset length + \param value - value to set @ingroup gapfunc */ @@ -2377,8 +2408,9 @@ template T gap_length(const T* buf) /*! - \brief Returs GAP block capacity. - \param buf - GAP buffer pointer. + \brief Returs GAP block capacity + \param buf - GAP buffer pointer + \param glevel_len - pointer on GAP header word \returns GAP block capacity. @ingroup gapfunc @@ -2850,6 +2882,8 @@ void bit_count_change32(const bm::word_t* block, Also calulates number of bits ON. @param bit_count - OUT total number of bits ON + @param block - bit-block start pointer + @param block_end - bit-block end pointer @return number of 1-0, 0-1 transitions @@ -2879,7 +2913,7 @@ bm::id_t bit_block_calc_count_change(const bm::word_t* block, #ifdef BM64OPT - bm::id_t count = 1; + bm::id64_t count = 1; *bit_count = 0; // 64-bit optimized algorithm. @@ -2922,7 +2956,7 @@ bm::id_t bit_block_calc_count_change(const bm::word_t* block, w_prev = (w0 >> w_shift); } } // for - return count; + return (bm::id_t) count; #else unsigned gap_count; @@ -4122,7 +4156,7 @@ bm::word_t* bit_operation_or(bm::word_t* BMRESTRICT dst, { // The source block is all set, because dst does not exist // we can simply replace it. - return const_cast(FULL_BLOCK_ADDR); + return const_cast(FULL_BLOCK_FAKE_ADDR); } } else @@ -4314,8 +4348,9 @@ bm::word_t* bit_operation_xor(bm::word_t* BMRESTRICT dst, /*! \brief Performs bitblock XOR operation and calculates bitcount of the result. - \param src1 - first bit block. - \param src2 - second bit block. + \param src1 - bit block start ptr + \param src1_end - bit block end ptr + \param src2 - second bit block \returns bitcount value @@ -4339,8 +4374,9 @@ bm::id_t bit_operation_xor_count(const bm::word_t* BMRESTRICT src1, /*! \brief Performs bitblock XOR operation test. - \param src1 - first bit block. - \param src2 - second bit block. + \param src1 - bit block start ptr + \param src1_end - bit block end ptr + \param src2 - second bit block ptr \returns non zero value if there are bits @@ -4367,7 +4403,7 @@ bm::id_t bit_operation_xor_any(const bm::word_t* BMRESTRICT src1, /** \brief Inspects block for full zero words - \param data - bit block pointer + \param blk - bit block pointer \param data_size - data size \return size of all non-zero words @@ -4897,7 +4933,6 @@ bool improve_gap_levels(const T* length, unsigned min_overhead = gap_overhead(length, length_end, glevel_len); bool is_improved = false; - gap_word_t prev_value = glevel_len[bm::gap_levels-1]; // main problem solving loop // @@ -4929,7 +4964,6 @@ bool improve_gap_levels(const T* length, } if (i == 0) break; - prev_value = glevel_len[i]; } // // Remove duplicates @@ -4963,7 +4997,7 @@ bool improve_gap_levels(const T* length, /** Bit-block get adapter, takes bitblock and represents it as a get_32() accessor function - /internal + \internal */ class bitblock_get_adapter { @@ -4979,7 +5013,7 @@ private: /** Bit-block store adapter, takes bitblock and saves results into it - /internal + \internal */ class bitblock_store_adapter { diff --git a/c++/include/util/bitset/bmgamma.h b/c++/include/util/bitset/bmgamma.h index 5baa5ef5..fb138e56 100644 --- a/c++/include/util/bitset/bmgamma.h +++ b/c++/include/util/bitset/bmgamma.h @@ -31,9 +31,16 @@ For more information please visit: http://bmagic.sourceforge.net namespace bm { +/*! + \defgroup gammacode Elias Gamma Code + Elias Gamma Encoder + \ingroup bvserial + + */ /** Elias Gamma decoder + \ingroup gammacode */ template class gamma_decoder diff --git a/c++/include/util/bitset/bmserial.h b/c++/include/util/bitset/bmserial.h index f2cdc2af..221942d5 100644 --- a/c++/include/util/bitset/bmserial.h +++ b/c++/include/util/bitset/bmserial.h @@ -11,7 +11,7 @@ publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, @@ -27,10 +27,11 @@ For more information please visit: http://bmagic.sourceforge.net */ -/*! \defgroup bvserial bvector serialization - * bvector serialization - * \ingroup bmagic - * +/*! + \defgroup bvserial bvector<> serialization + Serialization for bvector<> container + \ingroup bvector + */ #ifndef BM__H__INCLUDED__ @@ -137,9 +138,12 @@ enum serialization_header_mask { /** Bit-vector serialization class. - Class designed to convert sparse bit-vector into a block of memory + Class designed to convert sparse bit-vectors into a single block of memory ready for file or database storage or network transfer. + Reuse of this class for multiple serializations may offer some performance + advantage. + @ingroup bvserial */ template @@ -149,7 +153,16 @@ public: typedef typename BV::allocator_type allocator_type; typedef typename BV::blocks_manager_type blocks_manager_type; public: - serializer(const allocator_type& alloc = allocator_type()); + /** + Construct serializer + + \param alloc - memory allocator + \param temp_block - temporary block for various operations + (if NULL it will be allocated and managed by serializer class) + */ + serializer(const allocator_type& alloc = allocator_type(), + bm::word_t* temp_block = 0); + ~serializer(); /** @@ -241,6 +254,7 @@ private: bool byte_order_serial_; bm::word_t* temp_block_; unsigned compression_level_; + bool own_temp_block_; }; /** @@ -496,7 +510,9 @@ protected: /** Class deserializer, can perform logical operation on bit-vector and - serialized bit-vector. + serialized bit-vector. This utility class potentially provides faster + and/or more memory efficient operation than more conventional deserialization + into memory bvector and then logical operation \ingroup bvserial */ @@ -506,6 +522,17 @@ class operation_deserializer public: typedef BV bvector_type; public: + /** + \brief Deserialize bvector using buffer as set operation argument + + \param bv - target bvector + \param buf - serialized buffer as a logical argument + \param temp_block - temporary block to avoid re-allocations + \param op - set algebra operation (default: OR) + \param exit_on_one - quick exit if set operation found some result + + \return bitcount + */ static unsigned deserialize(bvector_type& bv, const unsigned char* buf, @@ -514,7 +541,13 @@ public: bool exit_on_one = false /// -serializer::serializer(const allocator_type& alloc) +serializer::serializer(const allocator_type& alloc, + bm::word_t* temp_block) : alloc_(alloc), gap_serial_(false), byte_order_serial_(true), - temp_block_(0), compression_level_(3) { - temp_block_ = alloc_.alloc_bit_block(); + if (temp_block == 0) + { + temp_block_ = alloc_.alloc_bit_block(); + own_temp_block_ = true; + } + else + { + temp_block_ = temp_block; + own_temp_block_ = false; + } + } template @@ -566,7 +609,8 @@ unsigned serializer::get_compression_level() const template serializer::~serializer() { - alloc_.free_bit_block(temp_block_); + if (own_temp_block_) + alloc_.free_bit_block(temp_block_); } @@ -1045,7 +1089,8 @@ enum serialization_flags { Function serializes content of the bitvector into memory. Serialization adaptively uses compression(variation of GAP encoding) when it is benefitial. - + + \param bv - source bvecor \param buf - pointer on target memory area. No range checking in the function. It is responsibility of programmer to allocate sufficient amount of memory using information from calc_stat function. @@ -1054,7 +1099,7 @@ enum serialization_flags { If you want to save memory across multiple bvectors allocate temporary block using allocate_tempblock and pass it to serialize. - (Of course serialize does not deallocate temp_block.) + (Serialize does not deallocate temp_block.) \param serialization_flags Flags controlling serilization (bit-mask) @@ -1066,7 +1111,7 @@ enum serialization_flags { \sa calc_stat, serialization_flags */ -/* +/*! Serialization format:
 
@@ -1083,10 +1128,10 @@ enum serialization_flags {
 template
 unsigned serialize(const BV& bv, 
                    unsigned char* buf, 
-                   bm::word_t*    /*temp_block*/,
+                   bm::word_t*    temp_block = 0,
                    unsigned       serialization_flags = 0)
 {
-    bm::serializer bv_serial;
+    bm::serializer bv_serial(bv.get_allocator(), temp_block);
     if (serialization_flags & BM_NO_BYTE_ORDER) 
         bv_serial.byte_order_serialization(false);
         
@@ -1103,26 +1148,24 @@ unsigned serialize(const BV& bv,
 /*!
    @brief Saves bitvector into memory.
    Allocates temporary memory block for bvector.
-   \ingroup bvserial 
-*/
+ 
+   \param bv - source bvecor
+   \param buf - pointer on target memory area. No range checking in the
+   function. It is responsibility of programmer to allocate sufficient 
+   amount of memory using information from calc_stat function.
 
+   \param serialization_flags
+   Flags controlling serilization (bit-mask) 
+   (use OR-ed serialization flags)
+ 
+   \ingroup bvserial
+*/
 template
 unsigned serialize(BV& bv, 
                    unsigned char* buf, 
                    unsigned  serialization_flags=0)
 {
-    bm::serializer bv_serial;
-    if (serialization_flags & BM_NO_BYTE_ORDER) 
-        bv_serial.byte_order_serialization(false);
-        
-    if (serialization_flags & BM_NO_GAP_LENGTH) 
-        bv_serial.gap_length_serialization(false);
-    else
-        bv_serial.gap_length_serialization(true);
-
-    bv_serial.set_compression_level(4);
-    
-    return bv_serial.serialize(bv, buf, 0);
+    return bm::serialize(bv, buf, 0, serialization_flags);
 }
 
 
@@ -1130,6 +1173,7 @@ unsigned serialize(BV& bv,
 /*!
     @brief Bitvector deserialization from memory.
 
+    @param bv - target bvector
     @param buf - pointer on memory which keeps serialized bvector
     @param temp_block - pointer on temporary block, 
             if NULL bvector allocates own.
@@ -1382,8 +1426,20 @@ deserializer::deserialize_gap(unsigned char btype, decoder_type& dec,
         {
         	unsigned arr_len = this->read_id_list(dec, btype, this->id_array_);
             gap_temp_block_[0] = 0; // reset unused bits in gap header
-            //unsigned gap_len =
+            unsigned gap_len =
               gap_set_array(gap_temp_block_, this->id_array_, arr_len);
+
+              int level = gap_calc_level(gap_len, bman.glen());
+              if (level == -1)  // Too big to be GAP: convert to BIT block
+              {
+                  gap_convert_to_bitset(temp_block_, gap_temp_block_);
+                  bv.combine_operation_with_block(i,
+                                                  temp_block_,
+                                                  0,
+                                                  BM_OR);
+                  return;
+              }
+
             break;
         }
     case set_block_gap_egamma:            
@@ -3227,7 +3283,7 @@ void iterator_deserializer::deserialize(
                         int is_gap = BM_IS_GAP(blk_mask);
                         bm::word_t* blk_target = 
                             bman_target.copy_bit_block(bv_block_idx, blk_mask, is_gap);
-                        bit_block_xor(blk_target, FULL_BLOCK_ADDR);
+                        bit_block_xor(blk_target, FULL_BLOCK_REAL_ADDR);
                     }
                     else
                     {
@@ -3479,14 +3535,14 @@ iterator_deserializer::deserialize(
                     {
                     case set_XOR:
                         blk = bman.deoptimize_block(bv_block_idx);
-                        bit_block_xor(blk, FULL_BLOCK_ADDR);
+                        bit_block_xor(blk, FULL_BLOCK_REAL_ADDR);
                         break;
                     case set_COUNT_XOR:
                         {
                         count += 
                             combine_count_operation_with_block(
                                                 blk,
-                                                FULL_BLOCK_ADDR,
+                                                FULL_BLOCK_REAL_ADDR,
                                                 bm::COUNT_XOR);
                         }
                         break;
@@ -3495,7 +3551,7 @@ iterator_deserializer::deserialize(
                         count += 
                             combine_count_operation_with_block(
                                                 blk,
-                                                FULL_BLOCK_ADDR,
+                                                FULL_BLOCK_REAL_ADDR,
                                                 bm::COUNT_SUB_BA);
                         }
                         break;
diff --git a/c++/include/util/bitset/bmsparsevec.h b/c++/include/util/bitset/bmsparsevec.h
new file mode 100644
index 00000000..5c36bcba
--- /dev/null
+++ b/c++/include/util/bitset/bmsparsevec.h
@@ -0,0 +1,721 @@
+#ifndef BMSPARSEVEC_H__INCLUDED__
+#define BMSPARSEVEC_H__INCLUDED__
+/*
+Copyright(c) 2017 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
+
+
+Permission is hereby granted, free of charge, to any person 
+obtaining a copy of this software and associated documentation 
+files (the "Software"), to deal in the Software without restriction, 
+including without limitation the rights to use, copy, modify, merge, 
+publish, distribute, sublicense, and/or sell copies of the Software, 
+and to permit persons to whom the Software is furnished to do so, 
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included 
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
+OTHER DEALINGS IN THE SOFTWARE.
+
+
+For more information please visit:   http://bmagic.sourceforge.net
+
+*/
+
+#include 
+#include 
+
+#include "bm.h"
+#include "bmdef.h"
+
+
+namespace bm
+{
+
+/** \defgroup svector Sparse vector
+    Sparse vector for integer types using bit transposition transform
+    \ingroup bmagic
+ */
+
+
+/*!
+   \brief sparse vector with runtime compression using bit transposition method
+   \ingroup svector
+*/
+template
+class sparse_vector
+{
+public:
+    typedef Val                                      value_type;
+    typedef bm::id_t                                 size_type;
+    typedef BV                                       bvector_type;
+    typedef bvector_type*                            bvector_type_ptr;
+	typedef const value_type&                        const_reference;
+    typedef typename BV::allocator_type              allocator_type;
+    typedef typename bvector_type::allocation_policy allocation_policy_type;
+    
+    /*! Statistical information about  memory allocation details. */
+    struct statistics : public bv_statistics
+    {};
+
+public:
+    /*!
+        \brief Sparse vector constructor
+        \param ap - allocation strategy for underlying bit-vectors
+        Default allocation policy uses BM_BIT setting (fastest access)
+        \param bv_max_size - maximum possible size of underlying bit-vectors
+        Please note, this is NOT size of svector itself, it is dynamic upper limit
+        which should be used very carefully if we surely know the ultimate size
+        \param alloc - allocator for bit-vectors
+        
+        \sa bvector<>
+        \sa bm::bvector<>::allocation_policy
+        \sa bm::startegy
+    */
+    sparse_vector(allocation_policy_type ap = allocation_policy_type(),
+                  size_type bv_max_size = bm::id_max,
+                  const allocator_type&   alloc  = allocator_type());
+    
+    /*! copy-ctor */
+    sparse_vector(const sparse_vector& sv);
+    
+    /*! Assignmment operator */
+    sparse_vector& operator = (const sparse_vector& sv)
+    {
+        clear();
+        resize(sv.size());
+        bv_size_ = sv.bv_size_;
+        alloc_ = sv.alloc_;
+    
+        for (size_type i = 0; i < sizeof(Val)*8; ++i)
+        {
+            const bvector_type* bv = sv.plains_[i];
+            if (bv)
+                plains_[i] = new bvector_type(*bv);
+        } // for i
+        return *this;
+    }
+    
+    
+    ~sparse_vector();
+    
+    /*!
+        \brief get specified element without bounds checking
+        \param idx - element index
+        \return value of the element
+    */
+    value_type operator[](size_type idx) const { return this->get(idx); }
+    
+    /*!
+        \brief Import list of elements from a C-style array
+        \param arr  - source array
+        \param size - source size
+        \param offset - target index in the sparse vector
+    */
+    void import(const value_type* arr, size_type size, size_type offset = 0);
+
+    /*!
+        \brief Bulk export list of elements to a C-style array
+        
+        For efficiency, this is left as a low level function, 
+        it does not do any bounds checking on the target array, it will 
+        override memory and crash if you are not careful with allocation
+        
+        This method uses cache-miss optimized algorithm which is by far faster 
+        than random element access functions.
+     
+        \param arr  - dest array
+        \param size - dest size
+        \param offset - target index in the sparse vector to export from
+     
+        \return number of exported elements
+    */
+    size_type extract(value_type* arr, size_type size, size_type offset = 0);
+
+    
+    
+    /*! \brief return size of the vector
+        \return size of sparse vector
+    */
+    size_type size() const;
+    
+    
+    /*! \brief resize vector
+        \param sz - new size
+    */
+    void resize(size_type sz);
+    
+    /*! \brief resize to zero, free memory
+    */
+    void clear();
+    
+    /*!
+        \brief access specified element with bounds checking
+        \param idx - element index
+        \return value of the element
+    */
+    value_type at(size_type idx) const;
+    
+    /*!
+        \brief get specified element without bounds checking
+        \param idx - element index
+        \return value of the element
+    */
+    value_type get(bm::id_t idx) const;
+    
+    /*!
+        \brief set specified element with bounds checking and automatic resize
+        \param idx - element index
+        \param v   - element value
+    */
+    void set(size_type idx, value_type v);
+
+    /*!
+        \brief push value back into vector
+        \param v   - element value
+    */
+    void push_back(value_type v);
+    
+    /*!
+        \brief check if another sparse vector has the same content and size
+        \return true, if it is the same
+    */
+    bool equal(const sparse_vector& sv) const;
+
+
+    /*!
+        \brief run memory optimization for all vector plains
+        \param temp_block - pre-allocated memory block to avoid unnecessary re-allocs
+        \param opt_mode - requested compression depth
+        \param stat - memory allocation statistics after optimization
+    */
+    void optimize(bm::word_t* temp_block = 0,
+                  typename bvector_type::optmode opt_mode = bvector_type::opt_compress,
+                  typename sparse_vector::statistics* stat = 0);
+    
+    /*!
+        \brief join all with another sparse vector using OR operation
+        \param sv - argument vector to join with
+        \return slf reference
+    */
+    sparse_vector& join(const sparse_vector& sv);
+
+
+    /*!
+       @brief Calculates memory statistics.
+
+       @param st - pointer on statistics structure to be filled in. 
+
+       Function fills statistics structure containing information about how 
+       this vector uses memory and estimation of max. amount of memory 
+       bvector needs to serialize itself.
+
+       @sa statistics
+    */
+    void calc_stat(struct sparse_vector::statistics* st) const;
+    
+
+    /*!
+        \brief get access to bit-plain, function checks and creates a plain
+    */
+    bvector_type_ptr get_plain(unsigned i);
+    
+    /*!
+        \brief get total number of bit-plains in the vector
+    */
+    static unsigned plains() { return unsigned(sizeof(Val)*8); }
+    
+    /*!
+        \brief get access to bit-plain as is (can return NULL)
+    */
+    bvector_type_ptr plain(unsigned i) { return plains_[i]; }
+    const bvector_type_ptr plain(unsigned i) const { return plains_[i]; }
+    
+    /*!
+        \brief free memory in bit-plain
+    */
+    void free_plain(unsigned i);
+    
+    /*!
+        \brief clear range (assign bit 0 for all plains)
+        \param left  - interval start
+        \param right - interval end (closed interval)
+    */
+    sparse_vector& clear_range(size_type left, size_type right);
+private:
+
+    /*! \brief free all internal vectors
+    */
+    void free_vectors();
+
+    /*! \brief set value without checking boundaries
+    */
+protected:
+    void set_value(size_type idx, value_type v);
+private:
+    
+    size_type                bv_size_;
+    allocator_type           alloc_;
+    allocation_policy_type   ap_;
+    
+    bvector_type_ptr    plains_[sizeof(Val)*8];
+    size_type           size_;
+};
+
+//---------------------------------------------------------------------
+
+
+template
+sparse_vector::sparse_vector(
+        allocation_policy_type  ap,
+        size_type               bv_max_size,
+        const allocator_type&   alloc)
+: bv_size_(bv_max_size),
+  alloc_(alloc),
+  ap_(ap),
+  size_(0)
+{
+    ::memset(plains_, 0, sizeof(plains_));
+}
+
+//---------------------------------------------------------------------
+
+template
+sparse_vector::sparse_vector(const sparse_vector& sv)
+: bv_size_ (sv.bv_size_),
+  alloc_(sv.alloc_),
+  ap_(sv.ap_),
+  size_(sv.size_)
+{
+    for (size_type i = 0; i < sizeof(Val)*8; ++i)
+    {
+        const bvector_type* bv = sv.plains_[i];
+        if (bv)
+            plains_[i] = new bvector_type(*bv);
+        else
+            plains_[i] = 0;
+    } // for i
+    
+}
+
+//---------------------------------------------------------------------
+
+
+template
+sparse_vector::~sparse_vector()
+{
+    free_vectors();
+}
+
+//---------------------------------------------------------------------
+
+template
+void sparse_vector::import(const value_type* arr,
+                                    size_type         size,
+                                    size_type         offset)
+{
+    if (size == 0)
+        throw std::range_error("sparse vector range error");
+    
+    // cleap all plains in the range to provide corrrect import of 0 values
+    this->clear_range(offset, offset + size - 1);
+    
+    size_type i;
+    for (i = 0; i < size; ++i)
+    {
+        value_type v = arr[i];
+        if (!v)
+            continue;
+        
+        unsigned b_list[sizeof(Val)*8];
+        unsigned bcnt = bm::bit_list_4(v, b_list);
+
+        for (unsigned j = 0; j < bcnt; ++j)
+        {
+            unsigned p = b_list[j];
+            bvector_type* bv = get_plain(p);
+            bv->set_bit(i + offset);
+        } // for j
+    } // for i
+    if (i > size_)
+        size_ = i;
+}
+
+//---------------------------------------------------------------------
+
+template
+typename sparse_vector::size_type
+sparse_vector::extract(value_type* arr,
+                                size_type   size,
+                                size_type   offset)
+{
+    if (size == 0)
+        return 0;
+    ::memset(arr, 0, sizeof(value_type)*size);
+    
+    size_type start = offset;
+    size_type end = start + size;
+    if (end > size_)
+        end = size_;
+    
+    for (size_type i = 0; i < sizeof(Val)*8; ++i)
+    {
+        const bvector_type* bv = plains_[i];
+        if (bv)
+        {
+            value_type mask = (1 << i);
+            bvector_type bv_mask;
+            
+            bv_mask.set_range(offset, end - 1);
+            bv_mask.bit_and(*bv);
+            
+            typename BV::enumerator en = bv_mask.first();
+            for (;en.valid();++en)
+            {
+                size_type idx = *en - offset;
+                if (idx >=  size)
+                    break;
+                arr[idx] |= mask;
+            }
+        }
+    } // for i
+    return 0;
+}
+
+//---------------------------------------------------------------------
+
+template
+typename sparse_vector::size_type
+sparse_vector::size() const
+{
+    return size_;
+}
+
+//---------------------------------------------------------------------
+
+template
+void sparse_vector::resize(typename sparse_vector::size_type sz)
+{
+    if (sz == size_)  // nothing to do
+        return;
+    
+    if (!sz) // resize to zero is an equivalent of non-destructive deallocation
+    {
+        clear();
+        return;
+    }
+    
+    if (sz < size_) // vector shrink
+    {
+        // clear the tails
+        this->clear_range(sz, size_-1);
+    }
+    
+    size_ = sz;
+}
+
+//---------------------------------------------------------------------
+
+
+template
+typename sparse_vector::bvector_type_ptr
+   sparse_vector::get_plain(unsigned i)
+{
+    BM_ASSERT(i < (sizeof(Val)*8));
+
+    bvector_type_ptr bv = plains_[i];
+    if (!bv)
+    {
+        bv = new bvector_type(ap_.strat, ap_.glevel_len,
+                              bv_size_,
+                              alloc_);
+        plains_[i] = bv;
+    }
+    return bv;
+}
+
+//---------------------------------------------------------------------
+
+template
+typename sparse_vector::value_type
+sparse_vector::at(typename sparse_vector::size_type idx) const
+{
+    if (idx >= size_)
+        throw std::range_error("sparse vector range error");
+    return this->get(idx);
+}
+
+//---------------------------------------------------------------------
+
+
+template
+typename sparse_vector::value_type
+sparse_vector::get(bm::id_t i) const
+{
+    BM_ASSERT(i < size_);
+    
+    value_type v = 0;
+    const bvector_type* bv;
+    for (unsigned j = 0; j < sizeof(Val)*8; ++j)
+    {
+        if ((bv = this->plains_[j]))   v |= ((bv->test(i))<plains_[++j])) v |= ((bv->test(i))<plains_[++j])) v |= ((bv->test(i))<plains_[++j])) v |= ((bv->test(i))<
+void sparse_vector::set(size_type idx, value_type v)
+{ 
+    if (idx >= size_)
+    {
+        size_ = idx+1;
+    }
+    set_value(idx, v);
+}
+
+//---------------------------------------------------------------------
+
+template
+void sparse_vector::push_back(value_type v)
+{
+    set_value(size_, v);
+    ++size_;
+}
+
+//---------------------------------------------------------------------
+
+template
+void sparse_vector::set_value(size_type idx, value_type v)
+{
+    // TODO: optimize to clear and set in just one pass
+
+    // clear the plains
+    for (unsigned i = 0; i < sizeof(Val) * 8; ++i)
+    {
+        bvector_type* bv = plains_[i];
+        if (bv)
+            bv->clear_bit(idx);
+    }
+
+    // set bits in plains
+    unsigned b_list[sizeof(Val) * 8];
+    unsigned bcnt = bm::bit_list_4(v, b_list);
+
+    for (unsigned j = 0; j < bcnt; ++j)
+    {
+        unsigned p = b_list[j];
+        bvector_type* bv = get_plain(p);
+        bv->set_bit(idx);
+    } // for j
+}
+
+
+
+//---------------------------------------------------------------------
+
+template
+void sparse_vector::clear()
+{
+    free_vectors();
+    size_ = 0;
+    ::memset(plains_, 0, sizeof(plains_));
+}
+
+//---------------------------------------------------------------------
+
+
+template
+void sparse_vector::free_vectors()
+{
+    for (size_type i = 0; i < sizeof(Val)*8; ++i)
+        delete plains_[i];
+}
+
+//---------------------------------------------------------------------
+
+
+template
+void sparse_vector::free_plain(unsigned i)
+{
+    BM_ASSERT(i < sizeof(Val)*8);
+    bvector_type* bv = plains_[i];
+    delete bv;
+    plains_[i] = 0;
+}
+
+//---------------------------------------------------------------------
+
+template
+sparse_vector&
+sparse_vector::clear_range(
+    typename sparse_vector::size_type left,
+    typename sparse_vector::size_type right)
+{
+    if (right < left)
+    {
+        return clear_range(right, left);
+    }
+    
+    for (unsigned i = 0; i < sizeof(Val) * 8; ++i)
+    {
+        bvector_type* bv = plains_[i];
+        if (bv)
+        {
+            bv->set_range(left, right, false);
+        }
+    } // for i
+    
+    return *this;
+}
+
+//---------------------------------------------------------------------
+
+template
+void sparse_vector::calc_stat(
+     struct sparse_vector::statistics* st) const
+{
+    BM_ASSERT(st);
+    
+	st->bit_blocks = st->gap_blocks = 0; 
+	st->max_serialize_mem = st->memory_used = 0;
+ 
+    for (unsigned j = 0; j < sizeof(Val)*8; ++j)
+    {
+        const bvector_type* bv = this->plains_[j];
+        if (bv)
+        {
+            typename bvector_type::statistics stbv;
+            bv->calc_stat(&stbv);
+            
+            st->bit_blocks += stbv.bit_blocks;
+            st->gap_blocks += stbv.gap_blocks;
+            st->max_serialize_mem += stbv.max_serialize_mem + 8;
+            st->memory_used += stbv.memory_used;
+            
+        }
+    } // for j
+    // header accounting
+    st->max_serialize_mem += 1 + 1 + 1 + 1 + 8 + (8 * sizeof(Val) * 8);
+
+}
+
+//---------------------------------------------------------------------
+
+template
+void sparse_vector::optimize(
+    bm::word_t*                                  temp_block, 
+    typename bvector_type::optmode               opt_mode,
+    typename sparse_vector::statistics* st)
+{
+    for (unsigned j = 0; j < sizeof(Val) * 8; ++j)
+    {
+        bvector_type* bv = this->plains_[j];
+        if (bv)
+        {
+            if (!bv->any())  // empty vector?
+            {
+                delete this->plains_[j];
+                this->plains_[j] = 0;
+                continue;
+            }
+            
+            typename bvector_type::statistics stbv;
+            bv->optimize(temp_block, opt_mode, &stbv);
+            
+            if (st)
+            {
+                st->bit_blocks += stbv.bit_blocks;
+                st->gap_blocks += stbv.gap_blocks;
+                st->max_serialize_mem += stbv.max_serialize_mem + 8;
+                st->memory_used += stbv.memory_used;
+            }
+
+        }
+    } // for j
+
+}
+
+//---------------------------------------------------------------------
+
+template
+sparse_vector&
+sparse_vector::join(const sparse_vector& sv)
+{
+    size_type arg_size = sv.size();
+    if (size_ < arg_size)
+    {
+        resize(arg_size);
+    }
+    for (unsigned j = 0; j < sizeof(Val) * 8; ++j)
+    {
+        bvector_type* arg_bv = sv.plains_[j];
+        if (arg_bv)
+        {
+            bvector_type* bv = this->plains_[j];
+            if (!bv)
+            {
+                bv = get_plain(j);
+            }
+            *bv |= *arg_bv;
+        }
+    } // for j
+    return *this;
+}
+
+
+//---------------------------------------------------------------------
+
+template
+bool sparse_vector::equal(const sparse_vector& sv) const
+{
+    size_type arg_size = sv.size();
+    if (size_ != arg_size)
+    {
+        return false;
+    }
+    for (unsigned j = 0; j < sizeof(Val) * 8; ++j)
+    {
+        const bvector_type* bv = plains_[j];
+        const bvector_type* arg_bv = sv.plains_[j];
+        if (!bv && !arg_bv)
+            continue;
+        // check if any not NULL and not empty
+        if (!bv && arg_bv)
+        {
+            if (arg_bv->any())
+                return false;
+        }
+        if (bv && !arg_bv)
+        {
+            if (bv->any())
+                return false;
+        }
+        // both not NULL
+        int cmp = bv->compare(*arg_bv);
+        if (cmp != 0)
+            return false;
+    } // for j
+    return true;
+}
+
+//---------------------------------------------------------------------
+
+
+} // namespace bm
+
+#include "bmundef.h"
+
+
+#endif
diff --git a/c++/include/util/bitset/bmsparsevec_algo.h b/c++/include/util/bitset/bmsparsevec_algo.h
new file mode 100644
index 00000000..a5e60073
--- /dev/null
+++ b/c++/include/util/bitset/bmsparsevec_algo.h
@@ -0,0 +1,142 @@
+#ifndef BMSPARSEVEC_ALGO__H__INCLUDED__
+#define BMSPARSEVEC_ALGO__H__INCLUDED__
+/*
+Copyright(c) 2002-2005 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
+
+Permission is hereby granted, free of charge, to any person 
+obtaining a copy of this software and associated documentation 
+files (the "Software"), to deal in the Software without restriction, 
+including without limitation the rights to use, copy, modify, merge, 
+publish, distribute, sublicense, and/or sell copies of the Software, 
+and to permit persons to whom the Software is furnished to do so, 
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included 
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information please visit:  http://bmagic.sourceforge.net
+
+*/
+
+#include "bmdef.h"
+#include "bmsparsevec.h"
+
+/** \defgroup svalgo Sparse vector algorithms
+    Sparse vector algorithms
+    \ingroup svector
+ */
+
+
+namespace bm
+{
+
+/*!
+    \brief Clip dynamic range for signal higher than specified
+    
+    \param  svect - sparse vector to do clipping
+    \param  high_bit - max bit (inclusive) allowed for this signal vector
+    
+    
+    \ingroup svalgo
+    \sa dynamic_range_clip_low
+*/
+template
+void dynamic_range_clip_high(SV& svect, unsigned high_bit)
+{
+    unsigned sv_plains = svect.plains();
+    
+    BM_ASSERT(sv_plains > high_bit && high_bit > 0);
+    
+    typename SV::bvector_type bv_acc;
+    unsigned i;
+    
+    // combine all the high bits into accumulator vector
+    for (i = high_bit+1; i < sv_plains; ++i)
+    {
+        typename SV::bvector_type* bv_plain = svect.plain(i);
+        if (bv_plain)
+        {
+            bv_acc.bit_or(*bv_plain);
+            svect.free_plain(i);
+        }
+    } // for i
+    
+    // set all bits ON for all low vectors, which happen to be clipped
+    for (i = high_bit; true; --i)
+    {
+        typename SV::bvector_type* bv_plain = svect.get_plain(i);
+        bv_plain->bit_or(bv_acc);
+        if (i == 0)
+            break;
+    } // for i
+}
+
+
+/*!
+    \brief Clip dynamic range for signal lower than specified (boost)
+    
+    \param  svect - sparse vector to do clipping
+    \param  low_bit - low bit (inclusive) allowed for this signal vector
+    
+    \ingroup svalgo
+    \sa dynamic_range_clip_high 
+*/
+template
+void dynamic_range_clip_low(SV& svect, unsigned low_bit)
+{
+    if (low_bit == 0) return; // nothing to do
+    BM_ASSERT(svect.plains() > low_bit);
+    
+    unsigned sv_plains = svect.plains();
+    typename SV::bvector_type bv_acc1;
+    unsigned i;
+    
+    // combine all the high bits into accumulator vector
+    for (i = low_bit+1; i < sv_plains; ++i)
+    {
+        typename SV::bvector_type* bv_plain = svect.plain(i);
+        if (bv_plain)
+            bv_acc1.bit_or(*bv_plain);
+    } // for i
+    
+    // accumulate all vectors below the clipping point
+    typename SV::bvector_type bv_acc2;
+    typename SV::bvector_type* bv_low_plain = svect.get_plain(low_bit);
+    
+    for (unsigned i = low_bit-1; true; --i)
+    {
+        typename SV::bvector_type* bv_plain = svect.plain(i);
+        if (bv_plain)
+        {
+            bv_acc2.bit_or(*bv_plain);
+            svect.free_plain(i);
+            if (i == 0)
+                break;
+        }
+    } // for i
+    
+    // now we want to set 1 in the clipping low plain based on
+    // exclusive or (XOR) between upper and lower parts)
+    // as a result high signal (any bits in the upper plains) gets
+    // slightly lower value (due to clipping) low signal gets amplified
+    // (lower contrast algorithm)
+    
+    bv_acc1.bit_xor(bv_acc2);
+    bv_low_plain->bit_or(bv_acc1);
+}
+
+
+    
+} // namespace bm
+
+#include "bmundef.h"
+
+#endif
diff --git a/c++/include/util/bitset/bmsparsevec_serial.h b/c++/include/util/bitset/bmsparsevec_serial.h
new file mode 100644
index 00000000..5279fe98
--- /dev/null
+++ b/c++/include/util/bitset/bmsparsevec_serial.h
@@ -0,0 +1,324 @@
+#ifndef BMSPARSEVEC_SERIAL__H__INCLUDED__
+#define BMSPARSEVEC_SERIAL__H__INCLUDED__
+/*
+Copyright(c) 2017 Anatoliy Kuznetsov(anatoliy_kuznetsov at yahoo.com)
+
+Permission is hereby granted, free of charge, to any person 
+obtaining a copy of this software and associated documentation 
+files (the "Software"), to deal in the Software without restriction, 
+including without limitation the rights to use, copy, modify, merge, 
+publish, distribute, sublicense, and/or sell copies of the Software, 
+and to permit persons to whom the Software is furnished to do so, 
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included 
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
+OTHER DEALINGS IN THE SOFTWARE.
+
+For more information please visit:  http://bmagic.sourceforge.net
+
+*/
+
+#include "bmsparsevec.h"
+#include "bmserial.h"
+#include "bmdef.h"
+
+namespace bm
+{
+
+/** \defgroup svserial Sparse vector serialization
+    Sparse vector serialization
+    \ingroup svector
+ */
+
+
+/*!
+    \brief layout class for serialization buffer structure
+    
+    Class keeps a memory block sized for the target sparse vector BLOB.
+    This class also provides acess to bit-plane memory, so it becomes possible
+    to use parallel storage methods to save bit-plains into
+    different storage shards.
+    
+    \ingroup svserial
+ 
+*/
+template
+struct sparse_vector_serial_layout
+{
+    typedef typename SV::value_type value_type;
+
+    sparse_vector_serial_layout()
+    : buffer_(0), capacity_(0), serialized_size_(0)
+    {
+    }
+    
+    ~sparse_vector_serial_layout()
+    {
+        if (buffer_)
+            ::free(buffer_);
+    }
+    
+    /*!
+        \brief resize capacity
+        \param capacity - new capacity
+        \return new buffer or 0 if failed
+    */
+    unsigned char* reserve(size_t capacity)
+    {
+        if (capacity == 0)
+        {
+            freemem();
+            return 0;
+        }
+        if (capacity <= capacity_)  // buffer reduction - avoid
+        {
+            serialized_size_ = 0;
+            return buffer_;
+        }
+        // buffer growth
+        freemem();
+        buffer_ = (unsigned char*) ::malloc(capacity);
+        if (buffer_)
+        {
+            capacity_ = capacity;
+        }
+        return buffer_;
+    }
+    
+    /// return current serialized size
+    size_t  size() const { return serialized_size_; }
+    
+    /// Set new serialized size
+    void resize(size_t ssize) { serialized_size_ = ssize; }
+    
+    /// return serialization buffer capacity
+    size_t  capacity() const { return capacity_; }
+    
+    /// free memory
+    void freemem()
+    {
+        if (buffer_)
+        {
+            ::free(buffer_);
+            buffer_ = 0; capacity_ = serialized_size_ = 0;
+        }
+    }
+    
+    /// Set plain output pointer and size
+    void set_plain(unsigned i, unsigned char* ptr, unsigned buf_size)
+    {
+        plain_ptrs_[i] = ptr;
+        plane_size_[i] = buf_size;
+    }
+    
+    /// Get plain pointer
+    const unsigned char* get_plain(unsigned i) const
+    {
+        return plain_ptrs_[i];
+    }
+    
+    /// Return serializatio buffer pointer
+    const unsigned char* buf() const { return buffer_; }
+    
+private:
+    sparse_vector_serial_layout(const sparse_vector_serial_layout&);
+    void operator=(const sparse_vector_serial_layout&);
+protected:
+    unsigned char* buffer_;                       ///< serialization buffer
+    size_t         capacity_;                     ///< buffer capacity
+    size_t         serialized_size_;              ///< serialized size
+
+    unsigned char* plain_ptrs_[sizeof(value_type)*8]; ///< pointers on serialized bit-palins
+    unsigned plane_size_[sizeof(value_type)*8];       ///< serialized plain size
+};
+
+// -------------------------------------------------------------------------
+
+
+/*!
+    \brief Serialize sparse vector into a buffer(s) structure
+ 
+ Serialization format:
+ 
+
+ | HEADER | BITVECTRORS |
+
+ Header structure:
+   BYTE+BYTE: Magic-signature 'BM'
+   BYTE : Byte order ( 0 - Big Endian, 1 - Little Endian)
+   BYTE : Number of Bit-vector plains (total)
+   INT64: Vector size
+   INT64: Offset of plain 0 from the header start (value 0 means plain is empty)
+   INT64: Offset of plain 1 from
+   ...
+   INT32: reserved
+
+ 
+ + \param sv - sparse vector to serialize + \param sv_layout - buffer structure to keep the result + \param temp_block - temporary buffer + (allocate with BM_DECLARE_TEMP_BLOCK(x) for speed) + \param bv_serialization_flags - bit-vector serialization flags + as defined in bm::serialization_flags + + \return "0" - success, "-1" memory allocation error + + \ingroup svserial + + @sa serialization_flags +*/ +template +int sparse_vector_serialize( + const SV& sv, + sparse_vector_serial_layout& sv_layout, + bm::word_t* temp_block = 0, + unsigned bv_serialization_flags = 0) +{ + typename SV::statistics sv_stat; + sv.calc_stat(&sv_stat); + + unsigned char* buf = sv_layout.reserve(sv_stat.max_serialize_mem); + if (!buf) // memory allocation error + { + return -1; + } + bm::encoder enc(buf, (unsigned)sv_layout.capacity()); + unsigned plains = sv.plains(); + + + // calculate header size in bytes + unsigned h_size = 1 + 1 + 1 + 1 + 8 + (8 * plains) + 4; + + // ptr where bit-vectors start + unsigned char* buf_ptr = buf + h_size; + + unsigned i; + for (i = 0; i < plains; ++i) + { + const typename SV::bvector_type_ptr bv = sv.plain(i); + if (!bv) // empty plain + { + sv_layout.set_plain(i, 0, 0); + continue; + } + unsigned buf_size = + bm::serialize(*bv, buf_ptr, temp_block, bv_serialization_flags); + sv_layout.set_plain(i, buf_ptr, buf_size); + buf_ptr += buf_size; + + } // for i + + sv_layout.resize(buf_ptr - buf); + + + // save header + ByteOrder bo = globals::byte_order(); + + enc.put_8('B'); + enc.put_8('M'); + enc.put_8((unsigned char)bo); + enc.put_8((unsigned char)plains); + enc.put_64(sv.size()); + + for (i = 0; i < plains; ++i) + { + const unsigned char* p = sv_layout.get_plain(i); + if (!p) + { + enc.put_64(0); + continue; + } + size_t offset = p - buf; + enc.put_64(offset); + } + + return 0; +} + +// ------------------------------------------------------------------------- + +/*! + \brief Deserialize svector<> + \param sv - target sparse vector + \param buf - source memory buffer + \param temp_block - temporary block buffer to avoid re-allocations + \ingroup svector +*/ +template +int sparse_vector_deserialize(SV& sv, + const unsigned char* buf, + bm::word_t* temp_block=0) +{ + typedef typename SV::bvector_type bvector_type; + + // TODO: implement correct processing of byte-order corect deserialization +// ByteOrder bo_current = globals::byte_order(); + + bm::decoder dec(buf); + unsigned char h1 = dec.get_8(); + unsigned char h2 = dec.get_8(); + + BM_ASSERT(h1 == 'B' && h2 == 'M'); + if (h1 != 'B' && h2 != 'M') // no magic header? issue... + { + return -1; + } + + //unsigned char bv_bo = + dec.get_8(); + unsigned plains = dec.get_8(); + + if (!plains || plains > sv.plains()) + { + return -2; // incorrect number of plains for the target svector + } + + sv.clear(); + bm::id64_t sv_size = dec.get_64(); + if (sv_size == 0) + { + return 0; // empty vector + } + sv.resize((unsigned)sv_size); + + unsigned i = 0; + for (i = 0; i < plains; ++i) + { + size_t offset = (size_t) dec.get_64(); + if (offset == 0) // null vector + { + continue; + } + const unsigned char* bv_buf_ptr = buf + offset; + bvector_type* bv = sv.get_plain(i); + BM_ASSERT(bv); + + bm::deserialize(*bv, bv_buf_ptr, temp_block); + if (!temp_block) + { + typename bvector_type::blocks_manager_type& bv_bm = + bv->get_blocks_manager(); + temp_block = bv_bm.check_allocate_tempblock(); + } + } // for i + return 0; +} + +// ------------------------------------------------------------------------- + + + +} // namespace bm + +#include "bmundef.h" + +#endif diff --git a/c++/include/util/bitset/bmsse2.h b/c++/include/util/bitset/bmsse2.h index 193abc7a..ef71f32b 100644 --- a/c++/include/util/bitset/bmsse2.h +++ b/c++/include/util/bitset/bmsse2.h @@ -188,10 +188,10 @@ bm::id_t sse2_bit_count_op(const __m128i* BMRESTRICT block, #define VECT_XOR_ARR_2_MASK(dst, src, src_end, mask)\ - sse2_xor_arr_2_mask((__m128i*)(dst), (__m128i*)(src), (__m128i*)(src_end), mask) + sse2_xor_arr_2_mask((__m128i*)(dst), (__m128i*)(src), (__m128i*)(src_end), (bm::word_t)mask) #define VECT_ANDNOT_ARR_2_MASK(dst, src, src_end, mask)\ - sse2_andnot_arr_2_mask((__m128i*)(dst), (__m128i*)(src), (__m128i*)(src_end), mask) + sse2_andnot_arr_2_mask((__m128i*)(dst), (__m128i*)(src), (__m128i*)(src_end), (bm::word_t)mask) #define VECT_BITCOUNT(first, last) \ sse2_bit_count((__m128i*) (first), (__m128i*) (last)) @@ -209,7 +209,7 @@ bm::id_t sse2_bit_count_op(const __m128i* BMRESTRICT block, sse2_bit_count_op((__m128i*) (first), (__m128i*) (last), (__m128i*) (mask), sse2_sub) #define VECT_INVERT_ARR(first, last) \ - sse2_invert_arr(first, last); + sse2_invert_arr((bm::word_t*)first, (bm::word_t*)last); #define VECT_AND_ARR(dst, src, src_end) \ sse2_and_arr((__m128i*) dst, (__m128i*) (src), (__m128i*) (src_end)) @@ -248,9 +248,9 @@ bm::id_t sse2_bit_block_calc_count_change(const __m128i* BMRESTRICT block, __m128i m2 = _mm_set_epi32 (mu2, mu2, mu2, mu2); __m128i m3 = _mm_set_epi32 (mu3, mu3, mu3, mu3); __m128i m4 = _mm_set_epi32 (mu4, mu4, mu4, mu4); - __m128i mcnt, ccnt; + __m128i mcnt;//, ccnt; mcnt = _mm_xor_si128(m1, m1); // bit_cnt = 0 - ccnt = _mm_xor_si128(m1, m1); // change_cnt = 0 + //ccnt = _mm_xor_si128(m1, m1); // change_cnt = 0 __m128i tmp1, tmp2; diff --git a/c++/include/util/bitset/bmsse4.h b/c++/include/util/bitset/bmsse4.h index 1c343360..bd79d7e5 100644 --- a/c++/include/util/bitset/bmsse4.h +++ b/c++/include/util/bitset/bmsse4.h @@ -33,6 +33,7 @@ For more information please visit: http://bmagic.sourceforge.net #include #include #include +#include #include "bmdef.h" #include "bmsse_util.h" @@ -40,8 +41,9 @@ For more information please visit: http://bmagic.sourceforge.net namespace bm { -/** @defgroup SSE4 Processor specific optimizations for SSE4.2 instructions - * @ingroup bmagic +/** @defgroup SSE4 SSE4.2 funcions + Processor specific optimizations for SSE4.2 instructions (internals) + * @ingroup bvector */ @@ -59,8 +61,8 @@ bm::id_t sse4_bit_count(const __m128i* block, const __m128i* block_end) const bm::id64_t* b_end = (bm::id64_t*) block_end; do { - count += _mm_popcnt_u64(b[0]) + - _mm_popcnt_u64(b[1]); + count += unsigned( _mm_popcnt_u64(b[0]) + + _mm_popcnt_u64(b[1])); b += 2; } while (b < b_end); #else @@ -119,8 +121,8 @@ bm::id_t sse4_bit_count_op(const __m128i* BMRESTRICT block, __m128i tmp1 = _mm_load_si128(mask_block); __m128i b = sse2_func(tmp0, tmp1); - count += _mm_popcnt_u64(_mm_extract_epi64(b, 0)); - count += _mm_popcnt_u64(_mm_extract_epi64(b, 1)); + count += (unsigned)_mm_popcnt_u64(_mm_extract_epi64(b, 0)); + count += (unsigned)_mm_popcnt_u64(_mm_extract_epi64(b, 1)); ++block; ++mask_block; } while (block < block_end); @@ -187,10 +189,10 @@ bm::id_t sse4_bit_count_op2(const __m128i* BMRESTRICT block, #define VECT_XOR_ARR_2_MASK(dst, src, src_end, mask)\ - sse2_xor_arr_2_mask((__m128i*)(dst), (__m128i*)(src), (__m128i*)(src_end), mask) + sse2_xor_arr_2_mask((__m128i*)(dst), (__m128i*)(src), (__m128i*)(src_end), (bm::word_t)mask) #define VECT_ANDNOT_ARR_2_MASK(dst, src, src_end, mask)\ - sse2_andnot_arr_2_mask((__m128i*)(dst), (__m128i*)(src), (__m128i*)(src_end), mask) + sse2_andnot_arr_2_mask((__m128i*)(dst), (__m128i*)(src), (__m128i*)(src_end), (bm::word_t)mask) #define VECT_BITCOUNT(first, last) \ sse4_bit_count((__m128i*) (first), (__m128i*) (last)) @@ -208,7 +210,7 @@ bm::id_t sse4_bit_count_op2(const __m128i* BMRESTRICT block, sse4_bit_count_op((__m128i*) (first), (__m128i*) (last), (__m128i*) (mask), sse2_sub) #define VECT_INVERT_ARR(first, last) \ - sse2_invert_arr(first, last); + sse2_invert_arr((bm::word_t*)first, (bm::word_t*)last); #define VECT_AND_ARR(dst, src, src_end) \ sse2_and_arr((__m128i*) dst, (__m128i*) (src), (__m128i*) (src_end)) @@ -244,7 +246,7 @@ bm::id_t sse4_bit_block_calc_count_change(const __m128i* BMRESTRICT block, unsigned* BMRESTRICT bit_count) { // __m128i mask1 = _mm_set_epi32(0x1, 0x1, 0x1, 0x1); - register int count = (block_end - block)*4; + register int count = (unsigned)(block_end - block)*4; register bm::word_t w0, w_prev; const int w_shift = sizeof(w0) * 8 - 1; diff --git a/c++/include/util/bitset/bmsse_util.h b/c++/include/util/bitset/bmsse_util.h index b83766dd..bd965df6 100644 --- a/c++/include/util/bitset/bmsse_util.h +++ b/c++/include/util/bitset/bmsse_util.h @@ -31,8 +31,9 @@ For more information please visit: http://bmagic.sourceforge.net namespace bm { -/** @defgroup SSE2 Processor specific optimizations for SSE2 instructions - * @ingroup bmagic +/** @defgroup SSE2 SSE2 functions + Processor specific optimizations for SSE2 instructions (internals) + @ingroup bvector */ @@ -44,6 +45,11 @@ namespace bm This class guards critical code fragments where SSE2 integer is used. + As of 2015 _mm_empty() is considered deprecated, and not even recognised + by some compilers (like MSVC) in 64-bit mode. + As MMX instructions gets old, we here deprecate and comment out + use of _mm_empty() + @ingroup SSE2 */ class sse_empty_guard @@ -51,12 +57,12 @@ class sse_empty_guard public: BMFORCEINLINE sse_empty_guard() { - _mm_empty(); + //_mm_empty(); } BMFORCEINLINE ~sse_empty_guard() { - _mm_empty(); + //_mm_empty(); } }; diff --git a/c++/include/util/bitset/bmtrans.h b/c++/include/util/bitset/bmtrans.h index d7fcb0f8..0067219c 100644 --- a/c++/include/util/bitset/bmtrans.h +++ b/c++/include/util/bitset/bmtrans.h @@ -679,6 +679,7 @@ void gap_2_bitblock(const GT* BMRESTRICT gap_buf, @param tmatrix - transposed matrix @param pc_vector - row content vector @param rstat - output row vector + @param effective_cols - effective columns @internal */ diff --git a/c++/include/util/bitset/bmundef.h b/c++/include/util/bitset/bmundef.h index 0bee6525..72dce8e0 100644 --- a/c++/include/util/bitset/bmundef.h +++ b/c++/include/util/bitset/bmundef.h @@ -51,8 +51,6 @@ #undef VECT_SET_BLOCK #undef BM_UNALIGNED_ACCESS_OK -#undef BM_ALIGN16 -#undef BM_ALIGN16ATTR #undef BM_x86 diff --git a/c++/include/util/bitset/encoding.h b/c++/include/util/bitset/encoding.h index 58d25656..e6309742 100644 --- a/c++/include/util/bitset/encoding.h +++ b/c++/include/util/bitset/encoding.h @@ -41,6 +41,8 @@ namespace bm Class for encoding data into memory. Properly handles aligment issues with integer data types. + + \ingroup gammacode */ class encoder { @@ -53,6 +55,7 @@ public: void put_16(const bm::short_t* s, unsigned count); void put_32(bm::word_t w); void put_32(const bm::word_t* w, unsigned count); + void put_64(bm::id64_t w); void put_prefixed_array_32(unsigned char c, const bm::word_t* w, unsigned count); void put_prefixed_array_16(unsigned char c, @@ -64,12 +67,13 @@ public: private: unsigned char* buf_; unsigned char* start_; - // unsigned int size_; // never actually checked + unsigned int size_; }; // ---------------------------------------------------------------- /** Base class for all decoding functionality + \ingroup gammacode */ class decoder_base { @@ -93,6 +97,7 @@ protected: /** Class for decoding data from memory buffer. Properly handles aligment issues with integer data types. + \ingroup gammacode */ class decoder : public decoder_base { @@ -100,6 +105,7 @@ public: decoder(const unsigned char* buf); bm::short_t get_16(); bm::word_t get_32(); + bm::id64_t get_64(); void get_32(bm::word_t* w, unsigned count); void get_16(bm::short_t* s, unsigned count); }; @@ -110,6 +116,7 @@ public: Properly handles aligment issues with integer data types. Converts data to big endian architecture (presumed it was encoded as little endian) + \ingroup gammacode */ typedef decoder decoder_big_endian; @@ -120,6 +127,7 @@ typedef decoder decoder_big_endian; Properly handles aligment issues with integer data types. Converts data to little endian architecture (presumed it was encoded as big endian) + \ingroup gammacode */ class decoder_little_endian : public decoder_base { @@ -135,6 +143,7 @@ public: /** Byte based writer for un-aligned bit streaming + @ingroup gammacode @sa encoder */ template @@ -327,6 +336,7 @@ private: /** Byte based reader for un-aligned bit streaming + @ingroup gammacode @sa encoder */ template @@ -435,6 +445,7 @@ private: /** Functor for Elias Gamma encoding + @ingroup gammacode */ template class gamma_encoder @@ -461,6 +472,7 @@ private: /** Elias Gamma decoder + @ingroup gammacode */ template class gamma_decoder @@ -506,13 +518,13 @@ private: \param buf - memory buffer pointer. \param size - size of the buffer */ -inline encoder::encoder(unsigned char* buf, unsigned /* size */) +inline encoder::encoder(unsigned char* buf, unsigned a_size) : buf_(buf), start_(buf) { - // size_ = size; + size_ = a_size; } /*! - \grief Encode 8-bit prefix + an array + \brief Encode 8-bit prefix + an array */ inline void encoder::put_prefixed_array_32(unsigned char c, const bm::word_t* w, @@ -523,7 +535,7 @@ inline void encoder::put_prefixed_array_32(unsigned char c, } /*! - \grief Encode 8-bit prefix + an array + \brief Encode 8-bit prefix + an array */ inline void encoder::put_prefixed_array_16(unsigned char c, const bm::short_t* s, @@ -641,6 +653,29 @@ BMFORCEINLINE void encoder::put_32(bm::word_t w) #endif } +/*! + \fn void encoder::put_64(bm::id64_t w) + \brief Puts 64 bits word into encoding buffer. + \param w - word to encode. +*/ +inline void encoder::put_64(bm::id64_t w) +{ +#if (BM_UNALIGNED_ACCESS_OK == 1) + *((bm::id64_t*) buf_) = w; + buf_ += sizeof(w); +#else + *buf_++ = (unsigned char) w; + *buf_++ = (unsigned char) (w >> 8); + *buf_++ = (unsigned char) (w >> 16); + *buf_++ = (unsigned char) (w >> 24); + *buf_++ = (unsigned char) (w >> 32); + *buf_++ = (unsigned char) (w >> 40); + *buf_++ = (unsigned char) (w >> 48); + *buf_++ = (unsigned char) (w >> 56); +#endif +} + + /*! \brief Encodes array of 32-bit words */ @@ -692,7 +727,7 @@ inline decoder::decoder(const unsigned char* buf) /*! \fn bm::short_t decoder::get_16() - \brief Reads 16bit word from the decoding buffer. + \brief Reads 16-bit word from the decoding buffer. */ BMFORCEINLINE bm::short_t decoder::get_16() { @@ -707,7 +742,7 @@ BMFORCEINLINE bm::short_t decoder::get_16() /*! \fn bm::word_t decoder::get_32() - \brief Reads 32 bit word from the decoding buffer. + \brief Reads 32-bit word from the decoding buffer. */ BMFORCEINLINE bm::word_t decoder::get_32() { @@ -721,6 +756,28 @@ BMFORCEINLINE bm::word_t decoder::get_32() return a; } +/*! + \fn bm::word_t decoder::get_64() + \brief Reads 64-bit word from the decoding buffer. +*/ +inline bm::id64_t decoder::get_64() +{ +#if (BM_UNALIGNED_ACCESS_OK == 1) + bm::id64_t a = *((bm::id64_t*)buf_); +#else + bm::word_t a = buf_[0]+ + ((bm::id64_t)buf_[1] << 8) + + ((bm::id64_t)buf_[2] << 16) + + ((bm::id64_t)buf_[3] << 24) + + ((bm::id64_t)buf_[4] << 32) + + ((bm::id64_t)buf_[5] << 40) + + ((bm::id64_t)buf_[6] << 48) + + ((bm::id64_t)buf_[7] << 56); +#endif + buf_+=sizeof(a); + return a; +} + /*! \fn void decoder::get_32(bm::word_t* w, unsigned count) @@ -797,7 +854,7 @@ inline decoder_little_endian::decoder_little_endian(const unsigned char* buf) BMFORCEINLINE bm::short_t decoder_little_endian::get_16() { - bm::short_t a = bm::short_t(((bm::short_t)buf_[0] << 8) + (bm::short_t)buf_[1]); + bm::short_t a = bm::short_t((bm::short_t)buf_[0] << 8) + ((bm::short_t)buf_[1]); buf_ += sizeof(a); return a; } @@ -842,7 +899,7 @@ inline void decoder_little_endian::get_16(bm::short_t* s, unsigned count) const bm::short_t* s_end = s + count; do { - bm::short_t a = bm::short_t(((bm::short_t)buf[0] << 8) + (bm::short_t)buf[1]); + bm::short_t a = bm::short_t((bm::short_t)buf[0] << 8) + ((bm::short_t)buf[1]); *s++ = a; buf += sizeof(a); } while (s < s_end); diff --git a/c++/include/util/bitset/ncbi_bitset.hpp b/c++/include/util/bitset/ncbi_bitset.hpp index 9ab8a98c..14facedf 100644 --- a/c++/include/util/bitset/ncbi_bitset.hpp +++ b/c++/include/util/bitset/ncbi_bitset.hpp @@ -2,7 +2,7 @@ #define UTIL___BITSET_BM__HPP -/* $Id: ncbi_bitset.hpp 177076 2009-11-24 22:14:02Z ucko $ +/* $Id: ncbi_bitset.hpp 546188 2017-09-14 16:00:00Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,22 +34,7 @@ /// @file ncbi_bitset.hpp /// Compressed bitset (entry point to bm.h) -#include - -#define BM_ASSERT _ASSERT - -#ifdef HAVE_RESTRICT_CXX -#define BM_HASRESTRICT -#define BMRESTRICT NCBI_RESTRICT -#endif - -#if defined(NCBI_FORCEINLINE) && \ - ( !defined(NCBI_COMPILER_GCC) || NCBI_COMPILER_VERSION >= 400 || \ - defined(__OPTIMIZE__)) -#define BM_HASFORCEINLINE -#define BMFORCEINLINE NCBI_FORCEINLINE -#endif - +#include // so bmdef.h can apply appropriate tuneups #include #endif /* UTIL___BITSET_BM__HPP */ diff --git a/c++/include/util/bytesrc.hpp b/c++/include/util/bytesrc.hpp index 0a92bfd9..22e91793 100644 --- a/c++/include/util/bytesrc.hpp +++ b/c++/include/util/bytesrc.hpp @@ -1,7 +1,7 @@ #ifndef UTIL___BYTESRC__HPP #define UTIL___BYTESRC__HPP -/* $Id: bytesrc.hpp 103491 2007-05-04 17:18:18Z kazimird $ +/* $Id: bytesrc.hpp 538188 2017-06-08 13:29:06Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -407,13 +407,8 @@ private: class NCBI_XUTIL_EXPORT CFileSourceCollector : public CSubSourceCollector { public: -#ifdef HAVE_NO_IOS_BASE - typedef streampos TFilePos; - typedef streamoff TFileOff; -#else typedef CNcbiIstream::pos_type TFilePos; typedef CNcbiIstream::off_type TFileOff; -#endif CFileSourceCollector(CConstRef source, TFilePos start, diff --git a/c++/include/util/cache/icache.hpp b/c++/include/util/cache/icache.hpp index bc0ec5a1..2dbbf9b7 100644 --- a/c++/include/util/cache/icache.hpp +++ b/c++/include/util/cache/icache.hpp @@ -1,7 +1,7 @@ #ifndef UTIL___ICACHE__HPP #define UTIL___ICACHE__HPP -/* $Id: icache.hpp 421534 2013-12-12 16:09:08Z vasilche $ +/* $Id: icache.hpp 534859 2017-05-03 12:47:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -344,11 +344,11 @@ public: { } - auto_ptr reader; - char* buf; - size_t buf_size; - size_t blob_size; - bool blob_found; + unique_ptr reader; + char* buf; + size_t buf_size; + size_t blob_size; + bool blob_found; /// Set to a non-zero value to return a version not older /// than the specified value. diff --git a/c++/include/util/compress/archive.hpp b/c++/include/util/compress/archive.hpp index a6aa9283..fc2e5fbc 100644 --- a/c++/include/util/compress/archive.hpp +++ b/c++/include/util/compress/archive.hpp @@ -1,7 +1,7 @@ #ifndef UTIL_COMPRESS__ARCHIVE__HPP #define UTIL_COMPRESS__ARCHIVE__HPP -/* $Id: archive.hpp 396780 2013-04-22 17:59:29Z ivanov $ +/* $Id: archive.hpp 534859 2017-05-03 12:47:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -157,7 +157,7 @@ public: /// names match the preset mask if any, or all entries otherwise. /// @sa /// SetMask - virtual auto_ptr List(void); + virtual unique_ptr List(void); /// Verify archive integrity. /// @@ -168,7 +168,7 @@ public: /// names match the preset mask if any, or all entries otherwise. /// @sa /// SetMask - virtual auto_ptr Test(void); + virtual unique_ptr Test(void); /// Extract the entire archive. /// @@ -179,7 +179,7 @@ public: /// A list of entries that have been actually extracted. /// @sa /// SetMask, SetBaseDir - virtual auto_ptr Extract(void); + virtual unique_ptr Extract(void); /// Extract single file entry to a memory buffer. /// @@ -250,9 +250,9 @@ public: /// created archive only, modifying existed archive is not allowed. /// @sa /// Create, AppendFileFromMemory, SetBaseDir, HaveSupport, Update - virtual auto_ptr Append(const string& path, - ELevel level = CCompression::eLevel_Default, - const string& comment = kEmptyStr); + virtual unique_ptr Append(const string& path, + ELevel level = CCompression::eLevel_Default, + const string& comment = kEmptyStr); /// Append a single file entry to the created archive using data from memory buffer. /// @@ -277,7 +277,7 @@ public: /// created archive only, modification existing archive is not allowed. /// @sa /// Create, Append - virtual auto_ptr + virtual unique_ptr AppendFileFromMemory(const string& name_in_archive, void* buf, size_t buf_size, ELevel level = CCompression::eLevel_Default, @@ -447,13 +447,13 @@ protected: void x_Open(EAction action); // Read the archive and do the requested "action" on current entry. - auto_ptr x_ReadAndProcess(EAction action); + unique_ptr x_ReadAndProcess(EAction action); // Append an entry from the file system to the archive. - auto_ptr x_Append(const string& path, - ELevel level, - const string& comment, - const TEntries* toc = NULL); + unique_ptr x_Append(const string& path, + ELevel level, + const string& comment, + const TEntries* toc = NULL); // Append a single entry from the file system to the archive. // Wrapper around AppendEntry(). // Return FALSE if entry should be skipped (via user Checkpoint()). @@ -472,7 +472,7 @@ protected: const CDirEntry* dst = NULL) const; protected: - auto_ptr m_Archive; ///< Pointer to interface to EFormat-specific archive support + unique_ptr m_Archive; ///< Pointer to interface to EFormat-specific archive support EFormat m_Format; ///< Archive format IArchive::ELocation m_Location; ///< Archive location (file/memory) TFlags m_Flags; ///< Bitwise OR of flags diff --git a/c++/include/util/compress/bzip2.hpp b/c++/include/util/compress/bzip2.hpp index 3dd5b033..1689c5bd 100644 --- a/c++/include/util/compress/bzip2.hpp +++ b/c++/include/util/compress/bzip2.hpp @@ -1,7 +1,7 @@ #ifndef UTIL_COMPRESS__BZIP2__HPP #define UTIL_COMPRESS__BZIP2__HPP -/* $Id: bzip2.hpp 404685 2013-06-26 14:57:14Z ivanov $ +/* $Id: bzip2.hpp 539121 2017-06-19 14:00:47Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -166,12 +166,13 @@ public: /// Size of data in source buffer. /// @param dst_buf /// Destination buffer. - /// @param dst_len + /// @param dst_size /// Size of destination buffer. + /// It must be large enough to hold all of the uncompressed data for the operation to complete. /// @param dst_len /// Size of decompressed data in destination buffer. /// @return - /// Return TRUE if operation was succesfully or FALSE otherwise. + /// Return TRUE if operation was successfully or FALSE otherwise. /// On success, 'dst_buf' contains decompressed data of dst_len size. /// @sa /// CompressBuffer @@ -294,7 +295,7 @@ public: /// Number of bytes to read. /// @return /// Number of bytes actually read (0 for end of file, -1 for error). - /// The number of really readed bytes can be less than requested. + /// The number of really read bytes can be less than requested. /// @sa /// Open, Write, Close virtual long Read(void* buf, size_t len); diff --git a/c++/include/util/compress/compress.hpp b/c++/include/util/compress/compress.hpp index 5f28c8e6..997e972f 100644 --- a/c++/include/util/compress/compress.hpp +++ b/c++/include/util/compress/compress.hpp @@ -1,7 +1,7 @@ #ifndef UTIL_COMPRESS__COMPRESS__HPP #define UTIL_COMPRESS__COMPRESS__HPP -/* $Id: compress.hpp 430126 2014-03-24 12:25:47Z ivanov $ +/* $Id: compress.hpp 539121 2017-06-19 14:00:47Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -286,6 +286,8 @@ public: /// Writes the given number of uncompressed bytes into the compressed file. /// Return the number of bytes actually written or -1 for error. + /// Returned value can be less than "len", especially if it exceed + /// numeric_limits::max(), you should repeat writing for remaining portion. virtual long Write(const void* buf, size_t len) = 0; /// Flushes all pending output if necessary, closes the compressed file. @@ -338,8 +340,8 @@ public: bool IsBusy(void) const; // Return number of processed/output bytes. - unsigned long GetProcessedSize(void); - unsigned long GetOutputSize(void); + size_t GetProcessedSize(void); + size_t GetOutputSize(void); protected: /// Initialize the internal stream state for compression/decompression. @@ -395,14 +397,13 @@ protected: void SetBusy(bool busy = true); // Increase number of processed/output bytes. - void IncreaseProcessedSize(unsigned long n_bytes); - void IncreaseOutputSize(unsigned long n_bytes); + void IncreaseProcessedSize(size_t n_bytes); + void IncreaseOutputSize(size_t n_bytes); private: - unsigned long m_ProcessedSize; //< The number of processed bytes - unsigned long m_OutputSize; //< The number of output bytes - bool m_Busy; //< Is true if compressor is ready to begin - //< next session + size_t m_ProcessedSize; //< The number of processed bytes + size_t m_OutputSize; //< The number of output bytes + bool m_Busy; //< Is true if compressor is ready to begin next session // Friend classes friend class CCompressionStream; friend class CCompressionStreambuf; @@ -526,25 +527,25 @@ void CCompressionProcessor::SetBusy(bool busy) } inline -void CCompressionProcessor::IncreaseProcessedSize(unsigned long n_bytes) +void CCompressionProcessor::IncreaseProcessedSize(size_t n_bytes) { m_ProcessedSize += n_bytes; } inline -void CCompressionProcessor::IncreaseOutputSize(unsigned long n_bytes) +void CCompressionProcessor::IncreaseOutputSize(size_t n_bytes) { m_OutputSize += n_bytes; } inline -unsigned long CCompressionProcessor::GetProcessedSize(void) +size_t CCompressionProcessor::GetProcessedSize(void) { return m_ProcessedSize; } inline -unsigned long CCompressionProcessor::GetOutputSize(void) +size_t CCompressionProcessor::GetOutputSize(void) { return m_OutputSize; } diff --git a/c++/include/util/compress/lzo.hpp b/c++/include/util/compress/lzo.hpp index 56f061d6..40c8d3f3 100644 --- a/c++/include/util/compress/lzo.hpp +++ b/c++/include/util/compress/lzo.hpp @@ -1,7 +1,7 @@ #ifndef UTIL_COMPRESS__LZO__HPP #define UTIL_COMPRESS__LZO__HPP -/* $Id: lzo.hpp 375225 2012-09-18 14:54:15Z ivanov $ +/* $Id: lzo.hpp 539121 2017-06-19 14:00:47Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,6 +37,13 @@ /// (de)compression in real-time. This means it favours speed /// over compression ratio. /// +/// LZO is good to compress some sort of data only, that have a limited +/// set of characters or many recurring sequences. It is not suitable +/// for a random data, that limits its usage. It is better to test +/// compression on yours own data before making decision to use LZO. +/// Use zlib if you need a more universal and robust solution, that is also +/// slower and needs more memory. + /// We don't support all possible algorithms, implemented in LZO. /// Only LZO1X is used in this API. Author of LZO says that it is /// often the best choice of all. @@ -134,6 +141,9 @@ public: ///< Use this flag with DecompressBuffer() to decompress data, ///< compressed using streams, or compress data with CompressBuffer(), ///< that can be decompressed using decompression stream. + ///< Also, this flag is reguired to compress data > 4GB. + ///< LZO default single block compression cannot handle such large + ///< amount of data on some platforms. fStreamFormat = (1<<3), ///< Store file information like file name and file modification date ///< of the compressed file into the file/stream. @@ -167,10 +177,10 @@ public: /// Get compression level. /// - /// NOTE: LZO library used only 2 compression levels for used in this API - /// LZO1X algorithm. So, all levels will be translated only to 2 real - /// value. We use LZO1X-999 for "eLevel_Best", and LZO1X-1 for - /// all other levels of compression. + /// NOTE: This API use only two compression levels for LZO method. + /// So, all compression levels will be translated only into 2 + /// real values. We use LZO1X-999 for "eLevel_Best", and + /// LZO1X-1 for all other levels of compression. virtual ELevel GetLevel(void) const; /// Returns default compression level for a compression algorithm. @@ -183,8 +193,6 @@ public: /// Compress data in the buffer. /// - /// Altogether, the total size of the destination buffer must be little - /// more then size of the source buffer. /// @param src_buf /// [in] Source buffer. /// @param src_len @@ -193,11 +201,17 @@ public: /// [in] Destination buffer. /// @param dst_size /// [in] Size of destination buffer. + /// The size of the destination buffer must be a little more + /// then size of the source buffer. /// @param dst_len /// [out] Size of compressed data in destination buffer. /// @return /// Return TRUE if operation was succesfully or FALSE otherwise. /// On success, 'dst_buf' contains compressed data of dst_len size. + /// @note + /// Use fStreamFormat flag to compress data > 4GB. + /// LZO default single block compression cannot handle such large + /// amount of data on some platforms. /// @sa /// EstimateCompressionBufferSize, DecompressBuffer virtual bool CompressBuffer( @@ -214,13 +228,17 @@ public: /// Size of data in source buffer. /// @param dst_buf /// Destination buffer. - /// @param dst_len + /// @param dst_size /// Size of destination buffer. + /// It must be large enough to hold all of the uncompressed data for the operation to complete. /// @param dst_len /// Size of decompressed data in destination buffer. /// @return - /// Return TRUE if operation was succesfully or FALSE otherwise. + /// Return TRUE if operation was successfully or FALSE otherwise. /// On success, 'dst_buf' contains decompressed data of dst_len size. + /// @note + /// Use fStreamFormat flag to decompress data, compressed using streams, + /// or CompressBuffer() with this flag. /// @sa /// CompressBuffer virtual bool DecompressBuffer( @@ -345,10 +363,10 @@ protected: size_t* processed /* out */); protected: - size_t m_BlockSize; ///< Block size for (de)compression. + size_t m_BlockSize; ///< Block size for (de)compression. // Compression parameters - AutoArray m_WorkMem; ///< Working memory for compressor. - auto_ptr m_Param; ///< Compression parameters. + AutoArray m_WorkMem; ///< Working memory for compressor. + unique_ptr m_Param; ///< Compression parameters. private: /// Private copy constructor to prohibit copy. @@ -373,15 +391,15 @@ public: CLZOCompressionFile( const string& file_name, EMode mode, - ELevel level = eLevel_Default, - size_t blocksize = kLZODefaultBlockSize + ELevel level = eLevel_Default, + size_t blocksize = kLZODefaultBlockSize ); /// Conventional constructor. /// For a special parameters description see CLZOCompression. CLZOCompressionFile( - ELevel level = eLevel_Default, - size_t blocksize = kLZODefaultBlockSize + ELevel level = eLevel_Default, + size_t blocksize = kLZODefaultBlockSize ); /// Destructor @@ -427,7 +445,7 @@ public: /// Number of bytes to read. /// @return /// Number of bytes actually read (0 for end of file, -1 for error). - /// The number of really readed bytes can be less than requested. + /// The number of really read bytes can be less than requested. /// @sa /// Open, Write, Close virtual long Read(void* buf, size_t len); @@ -442,6 +460,7 @@ public: /// Number of bytes to write. /// @return /// Number of bytes actually written or -1 for error. + /// Returned value can be less than "len". /// @sa /// Open, Read, Close virtual long Write(const void* buf, size_t len); @@ -493,7 +512,7 @@ protected: void ResetBuffer(size_t in_bufsize, size_t out_bufsize); private: - size_t m_Size; ///< Size of In/Out buffers. + size_t m_Size; ///< Size of in/out buffers. AutoArray m_Buf; ///< Buffer for caching (size of m_Size*2). char* m_InBuf; ///< Pointer to input buffer. size_t m_InSize; ///< Size of the input buffer. @@ -599,13 +618,13 @@ protected: bool DecompressCache(void); private: - size_t m_BlockLen; ///< Length of the compressed data in the block - string m_Cache; ///< Buffer to cache header. + size_t m_BlockLen; ///< Length of the compressed data in the block + string m_Cache; ///< Buffer to cache header. // Parameters read from header (used for compression). // See fStreamFormat flag description. - size_t m_HeaderLen; ///< Length of the header. - unsigned int m_HeaderFlags; ///< Flags used for compression. + size_t m_HeaderLen; ///< Length of the header. + TLZOFlags m_HeaderFlags; ///< Flags used for compression. }; diff --git a/c++/include/util/compress/reader_zlib.hpp b/c++/include/util/compress/reader_zlib.hpp index 6d939f2e..a9e5ab09 100644 --- a/c++/include/util/compress/reader_zlib.hpp +++ b/c++/include/util/compress/reader_zlib.hpp @@ -1,7 +1,7 @@ #ifndef READER_ZLIB__HPP_INCLUDED #define READER_ZLIB__HPP_INCLUDED -/* $Id: reader_zlib.hpp 103491 2007-05-04 17:18:18Z kazimird $ +/* $Id: reader_zlib.hpp 534859 2017-05-03 12:47:35Z ivanov $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information @@ -66,9 +66,9 @@ private: CNlmZipBtRdr(const CNlmZipBtRdr&); const CNlmZipBtRdr& operator=(const CNlmZipBtRdr&); - CRef m_Src; - EType m_Type; - auto_ptr m_Decompressor; + CRef m_Src; + EType m_Type; + unique_ptr m_Decompressor; }; @@ -145,14 +145,14 @@ private: CNlmZipReader(const CNlmZipReader&); const CNlmZipReader& operator=(const CNlmZipReader&); - IReader* m_Reader; - TOwnership m_Own; - EHeader m_Header; - CDynamicCharArray m_Buffer; - size_t m_BufferPos; - size_t m_BufferEnd; - auto_ptrm_Decompressor; - CDynamicCharArray m_Compressed; + IReader* m_Reader; + TOwnership m_Own; + EHeader m_Header; + CDynamicCharArray m_Buffer; + size_t m_BufferPos; + size_t m_BufferEnd; + unique_ptr m_Decompressor; + CDynamicCharArray m_Compressed; }; diff --git a/c++/include/util/compress/stream.hpp b/c++/include/util/compress/stream.hpp index 689111fc..7a15f3f5 100644 --- a/c++/include/util/compress/stream.hpp +++ b/c++/include/util/compress/stream.hpp @@ -1,7 +1,7 @@ #ifndef UTIL_COMPRESS__STREAM__HPP #define UTIL_COMPRESS__STREAM__HPP -/* $Id: stream.hpp 404685 2013-06-26 14:57:14Z ivanov $ +/* $Id: stream.hpp 539121 2017-06-19 14:00:47Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -65,31 +65,34 @@ BEGIN_NCBI_SCOPE // Notice that generally the input/output stream you pass to // CCompression[IO]Stream class constructor must be in binary mode, because // the compressed data always is binary (decompressed data also can be -// binary) and the conversions which happen in text mode will corrupt it. +// binary) and the conversions which happen in the text mode will corrupt it. // // Note: // CCompression[IO]Stream class objects must be finalized after use. // Only after finalization all data put into stream will be processed -// for sure. By default finalization called in the class destructor, however -// it can be done in any time by call Finalize(). After finalization you -// can only read from the stream (if it is derived from istream). -// If you don't read that some data can be lost. +// for sure. By default finalization is done in the class destructor, +// however it is better to call it directly by using Finalize() method. +// This allow to check result and be sure that you read/write all necessary +// data. You cannot do this if Finalize() is called in the destructor +// automatically. After finalization you can only read from the stream +// (if it is derived from istream). If you don't read that some data +// can be lost there. // // Note: -// The compression streams don't write nothing into output, if no input data -// is provided. This can be especially important for cases where output data -// should have any header/footer (like .gz files for example). So, for empty -// input, you will have empty output, that may not be acceptable to external -// tools like gunzip and etc. +// The compression streams write nothing into the output, if input data +// has not provided. This can be especially important for cases where +// the output data should have any header/footer (like .gz files for example). +// So, for empty input, you will have empty output, that may not be acceptable +/// to external tools like gunzip and etc. // // Note: -// There is one special aspect of CCompression[I]OStream class. Basically -// the compression algorithms works on blocks of data. They waits until -// a block is full and then compresses it. As long as you only feed data -// to the stream without flushing it this works normally. If you flush -// the stream, you force a premature end of the data block. This will cause -// a worse compression factor. You should avoid flushing an output buffer -// to get a better compression ratio. +// There is one special aspect of the output stream classes (CCompression[I]OStream). +// You should avoid flushing an output buffer if not necessary to get +// a better compression ratio. Basically, the compression algorithms works +// on blocks of data. They waits until a block is full and then compresses it. +// As long as you only feed data to the stream without flushing it works +// as expected. If you flush the stream, you force a premature end of the data block. +// This will cause a worse compression ratio. // // Accordingly, the using input stream with compression usually have worse // compression than output stream with compression. Because a stream needs @@ -172,9 +175,9 @@ protected: bool x_GetError(CCompressionStream::EDirection dir, int& status, string& description); /// Return number of processed bytes. - unsigned long x_GetProcessedSize(CCompressionStream::EDirection dir); + size_t x_GetProcessedSize(CCompressionStream::EDirection dir); /// Return number of output bytes. - unsigned long x_GetOutputSize(CCompressionStream::EDirection dir); + size_t x_GetOutputSize(CCompressionStream::EDirection dir); protected: @@ -292,7 +295,7 @@ public: /// and waiting to be compressed/decompressed. Usually, only after /// stream finalization by Finalize() it will be equal a number of /// bytes read from underlying stream. - unsigned long GetProcessedSize(void) { + size_t GetProcessedSize(void) { return CCompressionStream::x_GetProcessedSize(eRead); }; /// Get total number of bytes, that "stream_processor" returns. @@ -300,9 +303,14 @@ public: /// Some data can be still cashed in the internal buffer. /// Usually, only after stream finalization by Finalize() it /// will be equal a size of decompressed data in underlying stream. - unsigned long GetOutputSize(void) { + size_t GetOutputSize(void) { return CCompressionStream::x_GetOutputSize(eRead); }; + /// Auxiliary method to read from stream. + /// Read up to "len" bytes from the stream into the buffer "buf". + /// Returning value less than "n" mean EOF or error, check stream state bits for details. + /// @note Allow to read more than 4GB, that regular read() cannot handle on some platforms. + size_t Read(void* buf, size_t len); protected: /// Default constructor. @@ -361,7 +369,7 @@ public: /// and waiting to be compressed/decompressed. Usually, only after /// stream finalization by Finalize() it will be equal a number of /// bytes written into stream. - unsigned long GetProcessedSize(void) { + size_t GetProcessedSize(void) { return CCompressionStream::x_GetProcessedSize(eWrite); }; /// Get total number of bytes, that "stream_processor" returns. @@ -369,18 +377,22 @@ public: /// stream, some data can be still cashed in the internal buffer /// for better I/O performance. Usually, only after stream /// finalization by Finalize() these numvbers will be equal. - unsigned long GetOutputSize(void) { + size_t GetOutputSize(void) { return CCompressionStream::x_GetOutputSize(eWrite); }; /// Finalize stream's compression/decompression process for read/write. /// This function just calls a streambuf Finalize(). - virtual void Finalize(CCompressionStream::EDirection dir - = CCompressionStream::eWrite) { + virtual void Finalize(CCompressionStream::EDirection dir = CCompressionStream::eWrite) { if ( m_StreamBuf ) { CCompressionStream::Finalize(dir); flush(); } }; + /// Auxiliary method to write into stream. + /// Write up "len" bytes from the buffer "buf" into the stream. + /// Returning value less than "n" mean error, check stream state bits for details. + /// @note Allow to write more than 4GB, that regular write() cannot handle on some platforms. + size_t Write(const void* buf, size_t len); protected: /// Default constructor. @@ -439,23 +451,33 @@ public: } /// Get total number of bytes processed by specified "stream_processor". /// @sa CCompressionIStream, CCompressionOStream - unsigned long GetProcessedSize(CCompressionStream::EDirection dir) { + size_t GetProcessedSize(CCompressionStream::EDirection dir) { return CCompressionStream::x_GetProcessedSize(dir); }; /// Get total number of bytes, that "stream_processor" returns. /// @sa CCompressionIStream, CCompressionOStream - unsigned long GetOutputSize(CCompressionStream::EDirection dir) { + size_t GetOutputSize(CCompressionStream::EDirection dir) { return CCompressionStream::x_GetOutputSize(dir); }; /// Finalize stream's compression/decompression process for read/write. /// This function just calls a streambuf Finalize(). - virtual void Finalize(CCompressionStream::EDirection dir - = CCompressionStream::eReadWrite) { + virtual void Finalize(CCompressionStream::EDirection dir = CCompressionStream::eReadWrite) { if ( m_StreamBuf ) { CCompressionStream::Finalize(dir); flush(); } }; + /// Auxiliary method to read from stream. + /// Read up to "len" bytes from the stream into the buffer "buf". + /// Returning value less than "n" mean EOF or error, check stream state bits for details. + /// @note Allow to read more than 4GB, that regular read() cannot handle on some platforms. + size_t Read(void* buf, size_t len); + + /// Auxiliary method to write into stream. + /// Write up "len" bytes from the buffer "buf" into the stream. + /// Returning value less than "n" mean error, check stream state bits for details. + /// @note Allow to write more than 4GB, that regular write() cannot handle on some platforms. + size_t Write(const void* buf, size_t len); protected: /// Default constructor. @@ -468,6 +490,7 @@ protected: }; + ///////////////////////////////////////////////////////////////////////////// /// /// CTransparentProcessor -- memory-copy processor diff --git a/c++/include/util/compress/tar.hpp b/c++/include/util/compress/tar.hpp index 1fc4951c..bba44344 100644 --- a/c++/include/util/compress/tar.hpp +++ b/c++/include/util/compress/tar.hpp @@ -1,7 +1,7 @@ #ifndef UTIL_COMPRESS__TAR__HPP #define UTIL_COMPRESS__TAR__HPP -/* $Id: tar.hpp 431461 2014-04-03 18:13:05Z lavr $ +/* $Id: tar.hpp 534859 2017-05-03 12:47:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -71,21 +71,21 @@ BEGIN_NCBI_SCOPE enum ETarModeBits { // Special mode bits - fTarSetUID = 04000, // set UID on execution - fTarSetGID = 02000, // set GID on execution - fTarSticky = 01000, // reserved (sticky bit) + fTarSetUID = 04000, ///< set UID on execution + fTarSetGID = 02000, ///< set GID on execution + fTarSticky = 01000, ///< reserved (sticky bit) // File permissions - fTarURead = 00400, // read by owner - fTarUWrite = 00200, // write by owner - fTarUExecute = 00100, // execute/search by owner - fTarGRead = 00040, // read by group - fTarGWrite = 00020, // write by group - fTarGExecute = 00010, // execute/search by group - fTarORead = 00004, // read by other - fTarOWrite = 00002, // write by other - fTarOExecute = 00001 // execute/search by other + fTarURead = 00400, ///< read by owner + fTarUWrite = 00200, ///< write by owner + fTarUExecute = 00100, ///< execute/search by owner + fTarGRead = 00040, ///< read by group + fTarGWrite = 00020, ///< write by group + fTarGExecute = 00010, ///< execute/search by group + fTarORead = 00004, ///< read by other + fTarOWrite = 00002, ///< write by other + fTarOExecute = 00001 ///< execute/search by other }; -typedef unsigned int TTarMode; // Bitwise OR of ETarModeBits +typedef unsigned int TTarMode; ///< Bitwise OR of ETarModeBits ///////////////////////////////////////////////////////////////////////////// @@ -301,6 +301,10 @@ public: /// when extracting (the latter is the default POSIX requirement). fSkipUnsupported = (1<<15), + // --- Append --- + /// Always use OldGNU headers for long names (default:only when needed) + fLongNameSupplement = (1<<18), + // --- Debugging --- fDumpEntryHeaders = (1<<20), fSlowSkipWithRead = (1<<21), @@ -397,15 +401,14 @@ public: /// A list of entries appended. /// @sa /// Create, Update, SetBaseDir - auto_ptr Append(const string& name); + unique_ptr Append(const string& name); /// Append an entry from a stream (exactly entry.GetSize() bytes). /// @return /// A list (containing one entry) with full acrhive info filled in /// @sa /// Append - auto_ptr Append(const CTarUserEntryInfo& entry, - CNcbiIstream& is); + unique_ptr Append(const CTarUserEntryInfo& entry, CNcbiIstream& is); /// Look whether more recent copies of archive members are available in /// the file system, and if so, append them to the archive: @@ -428,7 +431,7 @@ public: /// A list of entries that have been updated. /// @sa /// Append, SetBaseDir, SetFlags - auto_ptr Update(const string& name); + unique_ptr Update(const string& name); /// Extract the entire archive (into either current directory or /// a directory otherwise specified by SetBaseDir()). @@ -438,7 +441,7 @@ public: /// A list of entries that have been actually extracted. /// @sa /// SetMask, SetBaseDir - auto_ptr Extract(void); + unique_ptr Extract(void); /// Get information about all matching archive entries. /// @@ -447,7 +450,7 @@ public: /// names match the pre-set mask. /// @sa /// SetMask - auto_ptr List(void); + unique_ptr List(void); /// Verify archive integrity. /// @@ -641,20 +644,20 @@ private: void x_Backspace(EAction action); // NB: m_ZeroBlockCount blocks back void x_Skip(Uint8 blocks); // NB: Can do by either skip or read - // Parse in extended entry information (POSIX) for the current entry. + // Parse in extended entry information (PAX) for the current entry. EStatus x_ParsePAXData(const string& buffer); // Read information about current entry in the archive. EStatus x_ReadEntryInfo(bool dump, bool pax); - // Pack either name or linkname into archive entry header. - bool x_PackName(STarHeader* header, const CTarEntryInfo& info, bool link); + // Pack current name or linkname into archive entry header. + bool x_PackCurrentName(STarHeader* header, bool link); // Write information for current entry into the archive. void x_WriteEntryInfo(const string& name); // Read the archive and do the requested "action" on current entry. - auto_ptr x_ReadAndProcess(EAction action); + unique_ptr x_ReadAndProcess(EAction action); // Process current entry from the archive (the actual size passed in). // If "extract" is FALSE, then just skip the entry without any processing. @@ -679,11 +682,10 @@ private: void x_WriteArchive(size_t n, const char* buffer = 0); // Append an entry from the file system to the archive. - auto_ptr x_Append(const string& name, const TEntries* toc = 0); + unique_ptr x_Append(const string& name, const TEntries* toc = 0); // Append an entry from an istream to the archive. - auto_ptr x_Append(const CTarUserEntryInfo& entry, - CNcbiIstream& is); + unique_ptr x_Append(const CTarUserEntryInfo& entry, CNcbiIstream& is); // Append data from an istream to the archive. void x_AppendStream(const string& name, CNcbiIstream& is); @@ -736,29 +738,28 @@ void CTar::Close(void) } inline -auto_ptr CTar::Append(const string& name) +unique_ptr CTar::Append(const string& name) { x_Open(eAppend); return x_Append(name); } inline -auto_ptr CTar::Append(const CTarUserEntryInfo& entry, - CNcbiIstream& is) +unique_ptr CTar::Append(const CTarUserEntryInfo& entry, CNcbiIstream& is) { x_Open(eAppend); return x_Append(entry, is); } inline -auto_ptr CTar::Update(const string& name) +unique_ptr CTar::Update(const string& name) { x_Open(eUpdate); return x_Append(name, x_ReadAndProcess(eUpdate).get()); } inline -auto_ptr CTar::List(void) +unique_ptr CTar::List(void) { x_Open(eList); return x_ReadAndProcess(eList); diff --git a/c++/include/util/compress/zlib.hpp b/c++/include/util/compress/zlib.hpp index a18502a1..12f210c6 100644 --- a/c++/include/util/compress/zlib.hpp +++ b/c++/include/util/compress/zlib.hpp @@ -1,7 +1,7 @@ #ifndef UTIL_COMPRESS__ZLIB__HPP #define UTIL_COMPRESS__ZLIB__HPP -/* $Id: zlib.hpp 380383 2012-11-13 13:35:10Z ivanov $ +/* $Id: zlib.hpp 539121 2017-06-19 14:00:47Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -114,7 +114,7 @@ public: /// if data source contains broken data and API cannot detect that /// it is compressed data, that you can get binary instead of /// decompressed data. By default this flag is OFF. - /// NOTE: zlib v1.1.4 and earlier have a bug in decoding. + /// Note: zlib v1.1.4 and earlier have a bug in decoding. /// In some cases decompressor can produce output data on invalid /// compressed data. So, it is not recommended to use this flag /// with old zlib versions. @@ -174,8 +174,6 @@ public: /// Compress data in the buffer. /// - /// Altogether, the total size of the destination buffer must be little - /// more then size of the source buffer. /// @param src_buf /// Source buffer. /// @param src_len @@ -184,11 +182,13 @@ public: /// Destination buffer. /// @param dst_size /// Size of destination buffer. + /// In some cases, small source data or bad compressed data for example, + /// it should be a little more then size of the source buffer. /// @param dst_len /// Size of compressed data in destination buffer. /// @return - /// Return TRUE if operation was succesfully or FALSE otherwise. - /// On success, 'dst_buf' contains compressed data of dst_len size. + /// Return TRUE if operation was successfully or FALSE otherwise. + /// On success, 'dst_buf' contains compressed data of 'dst_len' size. /// @sa /// EstimateCompressionBufferSize, DecompressBuffer virtual bool CompressBuffer( @@ -201,8 +201,8 @@ public: /// /// @note /// The decompressor stops and returns TRUE, if it find logical - /// end in the compressed data, even not all compressed data was processed. - /// Only for case of decompressing concatenated gzip files in memory. + /// end in the compressed data, even not all compressed data was processed. + /// Only for case of decompressing concatenated gzip files in memory /// it try to decompress data behind of logical end of recurrent gzip chunk, /// to check on next portion of data. See fCheckFileHeader, /// fAllowConcatenatedGZip and fGZip flags description. @@ -212,12 +212,13 @@ public: /// Size of data in source buffer. /// @param dst_buf /// Destination buffer. + /// It must be large enough to hold all of the uncompressed data for the operation to complete. /// @param dst_size /// Size of destination buffer. /// @param dst_len /// Size of decompressed data in destination buffer. /// @return - /// Return TRUE if operation was succesfully or FALSE otherwise. + /// Return TRUE if operation was successfully or FALSE otherwise. /// On success, 'dst_buf' contains decompressed data of dst_len size. /// @sa /// CompressBuffer, EFlags @@ -267,7 +268,7 @@ public: /// original file name and timestamp stored in the file. /// UNIX gunzip have -N option for this, but by default /// do not use it, and just creates a decompressed file with - /// the name of the compressed file without .gz extention. + /// the name of the compressed file without .gz extension. virtual bool CompressFile( const string& src_file, const string& dst_file, @@ -317,7 +318,7 @@ public: /// the compressed file. If fRestoreFileAttr flag is set, /// that original file name and time stamp, stored in /// the file header will be restored. If not, that destination - /// file will be named as archive name without extention. + /// file will be named as archive name without extension. virtual bool DecompressFileIntoDir( const string& src_file, const string& dst_dir, @@ -334,8 +335,8 @@ public: protected: /// Format string with last error description. - /// If pos equl to 0, that use internal m_Stream's position to report. - string FormatErrorMessage(string where, unsigned long pos = 0) const; + /// If pos == 0, that use internal m_Stream's position to report. + string FormatErrorMessage(string where, size_t pos = 0) const; protected: void* m_Stream; ///< Compressor stream. @@ -393,7 +394,7 @@ public: /// @param mode /// File open mode. /// @return - /// TRUE if file was opened succesfully or FALSE otherwise. + /// TRUE if file was opened successfully or FALSE otherwise. /// @sa /// CZipCompression, Read, Write, Close virtual bool Open(const string& file_name, EMode mode); @@ -410,7 +411,7 @@ public: /// that it will be used to get information about compressed file /// in the read mode, and set it in the write mode for gzip files. /// @return - /// TRUE if file was opened succesfully or FALSE otherwise. + /// TRUE if file was opened successfully or FALSE otherwise. /// @sa /// CZipCompression, Read, Write, Close virtual bool Open(const string& file_name, EMode mode, SFileInfo* info); @@ -425,7 +426,7 @@ public: /// Number of bytes to read. /// @return /// Number of bytes actually read (0 for end of file, -1 for error). - /// The number of really readed bytes can be less than requested. + /// The number of really read bytes can be less than requested. /// @sa /// Open, Write, Close virtual long Read(void* buf, size_t len); @@ -440,6 +441,7 @@ public: /// Number of bytes to write. /// @return /// Number of bytes actually written or -1 for error. + /// Returned value can be less than "len". /// @sa /// Open, Read, Close virtual long Write(const void* buf, size_t len); @@ -568,9 +570,9 @@ private: /// See util/compress/stream.hpp for details of stream processing. /// @note /// Compression/decompression flags (CZipCompression:EFlags) can greatly -/// affect CZipStreamCompressor behaviour. By default, compressor +/// affect CZipStreamCompressor behavior. By default, compressor /// produce plain zip data, that is not compatible with gzip/gunzip utility. -/// Please use appropriate flags in constructor to change default behaviour. +/// Please use appropriate flags in constructor to change default behavior. /// @sa CCompressionStreamProcessor class NCBI_XUTIL_EXPORT CZipStreamCompressor @@ -665,8 +667,8 @@ public: /// Opened input stream to scan (should be opened in binary mode). /// @param handler /// Call handler's IChunkHandler::OnChunk() method with positions -/// of each new gzip file insize stream and size of uncompressed data on -/// that moment. +/// of each new gzip file inside a stream and size of uncompressed data +/// on that moment. NCBI_XUTIL_EXPORT void g_GZip_ScanForChunks(CNcbiIstream& is, IChunkHandler& handler); diff --git a/c++/include/util/distribution.hpp b/c++/include/util/distribution.hpp index 03b20320..69911d4b 100644 --- a/c++/include/util/distribution.hpp +++ b/c++/include/util/distribution.hpp @@ -1,4 +1,4 @@ -/* $Id: distribution.hpp 448236 2014-10-03 14:05:43Z kazimird $ +/* $Id: distribution.hpp 511866 2016-08-25 03:53:47Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -43,48 +43,30 @@ BEGIN_NCBI_SCOPE class CRandom; -/// This class generates a random integer from a series of ranges -/// defined as follows: 5, 6 - 9, 10 - 50. -class NCBI_XUTIL_EXPORT CDiscreteDistribution +/// @warning do not use this internal class, it will be removed. +class NCBI_XUTIL_EXPORT CDiscreteDistributionImpl { public: - /// Initializes internal structures of this object using - /// the specified string. The string must be defined - /// in the following format: - /// R1, R2, ..., Rn - /// Where R1 ... Rn - integer ranges specified as either - /// stand-alone numbers or intervals defined as Nfrom - Nto. - /// Example: - /// 5, 6 - 9, 10 - 50, 65 - /// - /// @param parameter_name - /// Configuration parameter name. This argument is used - /// only for constructing a CInvalidParamException object - /// should there be a format error in parameter_value. - /// - /// @param parameter_value - /// Actual initialization string, which must conform - /// to the format described above. - /// - /// @param random_gen - /// Random number generator for use by this object. void InitFromParameter( const char* parameter_name, const char* parameter_value, CRandom* random_gen) { m_RandomGen = random_gen; - CRangeList::Parse(parameter_value, parameter_name, &m_RangeVector); + CRangeListImpl::Parse(parameter_value, parameter_name, &m_RangeVector); } - /// Returns a random value from the distribution. unsigned GetNextValue() const; private: CRandom* m_RandomGen; - CRangeList::TRangeVector m_RangeVector; + CRangeListImpl::TRangeVector m_RangeVector; }; +/// @deprecated +struct NCBI_DEPRECATED NCBI_XUTIL_EXPORT CDiscreteDistribution : + CDiscreteDistributionImpl {}; + END_NCBI_SCOPE #endif /* UTIL___DISTRIBUTION__HPP */ diff --git a/c++/include/util/format_guess.hpp b/c++/include/util/format_guess.hpp index 3eae209e..2c060e27 100644 --- a/c++/include/util/format_guess.hpp +++ b/c++/include/util/format_guess.hpp @@ -1,7 +1,7 @@ #ifndef FORMATGUESS__HPP #define FORMATGUESS__HPP -/* $Id: format_guess.hpp 513836 2016-09-15 17:32:16Z ivanov $ +/* $Id: format_guess.hpp 534229 2017-04-25 16:53:32Z foleyjp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -244,6 +244,7 @@ protected: EMode ); bool TestFormatAlignment( EMode ); + bool TestFormatCLUSTAL(void); bool TestFormatBinaryAsn( EMode ); bool TestFormatDistanceMatrix( @@ -366,6 +367,14 @@ private: // data: static const char* const sm_FormatNames[eFormat_max]; + + + bool x_TryProcessCLUSTALSeqData(const string& line, + string& id, + size_t& seg_length) const; + + bool x_LooksLikeCLUSTALConservedInfo(const string& line) const; + protected: static int s_CheckOrder[]; diff --git a/c++/include/util/mutex_pool.hpp b/c++/include/util/mutex_pool.hpp index f8a90ffa..e2cd637d 100644 --- a/c++/include/util/mutex_pool.hpp +++ b/c++/include/util/mutex_pool.hpp @@ -1,7 +1,7 @@ #ifndef UTIL___MUTEX_POOL__HPP #define UTIL___MUTEX_POOL__HPP -/* $Id: mutex_pool.hpp 350852 2012-01-24 19:50:51Z vasilche $ +/* $Id: mutex_pool.hpp 546079 2017-09-13 17:17:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -89,7 +89,7 @@ public: protected: friend class CInitGuard; - bool AcquireMutex(CInitMutex_Base& init, CRef& mutex); + bool AcquireMutex(CInitMutex_Base& init, CRef& mutex, bool force = false); void ReleaseMutex(CInitMutex_Base& init, CRef& mutex); private: @@ -222,6 +222,9 @@ public: class CInitGuard { public: + enum EForce { + force + }; CInitGuard(CInitMutex_Base& init, CInitMutexPool& pool) : m_Init(init), m_Guard(eEmptyGuard) { @@ -232,6 +235,13 @@ public: } } } + CInitGuard(CInitMutex_Base& init, CInitMutexPool& pool, EForce) + : m_Init(init), m_Guard(eEmptyGuard) + { + if ( pool.AcquireMutex(init, m_Mutex, true) ) { + m_Guard.Guard(m_Mutex->GetMutex()); + } + } ~CInitGuard(void) { Release(); @@ -244,6 +254,12 @@ public: } } + void ForceGuard(CInitMutex_Base& init, CInitMutexPool& pool) + { + pool.AcquireMutex(init, m_Mutex, true); + m_Guard.Guard(m_Mutex->GetMutex()); + } + // true means that this thread should perform initialization DECLARE_OPERATOR_BOOL(!m_Init); diff --git a/c++/include/util/ncbi_cache.hpp b/c++/include/util/ncbi_cache.hpp index 29518c9b..4e86744a 100644 --- a/c++/include/util/ncbi_cache.hpp +++ b/c++/include/util/ncbi_cache.hpp @@ -1,6 +1,6 @@ #ifndef CORELIB___NCBI_CACHE__HPP #define CORELIB___NCBI_CACHE__HPP -/* $Id: ncbi_cache.hpp 489095 2016-01-08 13:02:41Z ivanov $ +/* $Id: ncbi_cache.hpp 534859 2017-05-03 12:47:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -296,7 +296,7 @@ private: TCacheSet m_CacheSet; TCacheMap m_CacheMap; TOrder m_Counter; - auto_ptr m_Handler; + unique_ptr m_Handler; }; diff --git a/c++/include/util/rangelist.hpp b/c++/include/util/rangelist.hpp index 4acdcbd9..04516143 100644 --- a/c++/include/util/rangelist.hpp +++ b/c++/include/util/rangelist.hpp @@ -1,4 +1,4 @@ -/* $Id: rangelist.hpp 448236 2014-10-03 14:05:43Z kazimird $ +/* $Id: rangelist.hpp 511866 2016-08-25 03:53:47Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -41,36 +41,13 @@ BEGIN_NCBI_SCOPE -/// Parse and store a list of integer ranges. -class NCBI_XUTIL_EXPORT CRangeList +/// @warning do not use this internal class, it will be removed. +class NCBI_XUTIL_EXPORT CRangeListImpl { public: typedef std::pair TIntegerRange; typedef std::vector TRangeVector; - /// Parse a string of integer ranges and initialize this object. - /// - /// The string must be in the following format: - /// N1, R1, N2, ..., Rn, Nm - /// - /// Where: - /// N1 ... Nm - stand-alone numbers, which are saved as a - /// TIntegerRange with equal ends: [Nm, Nm]. - /// R1 ... Rn - integer ranges defined as intervals - /// in the form of Nfrom - Nto. - /// Example: - /// 4, 6 - 9, 16 - 40, 64 - /// - /// @param init_string - /// Actual initialization string, which must conform - /// to the format described above. - /// - /// @param config_param_name - /// Configuration parameter name. It is used only for - /// error reporting to specify the source of the error. - /// - /// @return A reference to the initialized range list. - /// const TRangeVector& Parse(const char* init_string, const char* config_param_name) { @@ -78,26 +55,8 @@ public: return m_RangeVector; } - /// Return the previously initialized list. const TRangeVector& GetRangeList() const {return m_RangeVector;} - /// A static variant of Parse(init_string, config_param_name). - /// This method can be used to parse the input string into an - /// external TRangeVector object. - /// - /// @param init_string - /// Initialization string. - /// - /// @param config_param_name - /// Configuration parameter name. It is used only for - /// error reporting to specify the source of the error. - /// - /// @param range_vector - /// A pointer to the TRangeVector instance for storing - /// the parsed integer ranges. - /// - /// @see Parse(init_string, config_param_name) - /// static void Parse(const char* init_string, const char* config_param_name, TRangeVector* range_vector); @@ -106,6 +65,9 @@ private: TRangeVector m_RangeVector; }; +/// @deprecated +struct NCBI_DEPRECATED NCBI_XUTIL_EXPORT CRangeList : CRangeListImpl {}; + END_NCBI_SCOPE #endif /* UTIL___RANGELIST__HPP */ diff --git a/c++/include/util/row_reader.hpp b/c++/include/util/row_reader.hpp new file mode 100644 index 00000000..3477a33c --- /dev/null +++ b/c++/include/util/row_reader.hpp @@ -0,0 +1,2053 @@ +#ifndef UTIL___ROW_READER__HPP +#define UTIL___ROW_READER__HPP + +/* $Id: row_reader.hpp 539687 2017-06-26 16:57:10Z ivanov $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Authors: Design and advice - Denis Vakatov +* Implementation and critique - Sergey Satskiy +* +* Special credits: Wratko Hlavina, Alex Astashin, Mike Dicuccio +* +* File Description: +* CRowReader - generic API to work with row streams +** =========================================================================== +*/ + +#include +#include + + +BEGIN_NCBI_SCOPE + + +/// Position in the data stream (zero based) +typedef Uint8 TStreamPos; + +/// Line number (in the data stream, zero based) +typedef Uint8 TLineNo; + +/// Field number (zero based) +typedef Uint4 TFieldNo; + + +/// Basic field data types +/// @note +/// The row reader does not perform any data conversion by itself. +/// It is up to the user to set a certain field type and how to use it +/// further. The row reader merely provides a storage for the user +/// provided field data types. +enum ERR_FieldType { + eRR_String, ///< string + eRR_Boolean, ///< bool + eRR_Integer, ///< int + eRR_Double, ///< double + eRR_DateTime ///< CTime +}; + + + +/// Basic or an extended field type with an added arbitrary string property. +/// The string property serves the purpose of special treatment of a field. +/// At the moment there is only one case supported: +/// if instantiated for ERR_FieldType and the field type is provided as +/// eRR_DateTime then the string stores a format string. +template +class CRR_FieldType +{ +public: + CRR_FieldType(TFieldType field_type, const string& field_props = string()) + : m_Type(field_type), + m_Props(field_props) + {} + + CRR_FieldType() + {} + +public: + TFieldType GetType(void) const + { + return m_Type; + } + + string GetProps(void) const + { + return m_Props; + } + +private: + TFieldType m_Type; + string m_Props; +}; + + + +/// Row type +enum ERR_RowType { + eRR_Data, ///< row contains data + eRR_Comment, ///< row contains a comment + eRR_Metadata, ///< row contains metadata + eRR_Invalid ///< row is invalid +}; + + +/// Whether to check validity of the fields (names and/or values) +enum ERR_FieldValidationMode { + eRR_NoFieldValidation, ///< don't validate fields' value and name + eRR_FieldValidation ///< check that the field's value (or name) is valid +}; + + +// Forward declarations +template class CRowReader; +template class CRR_Row; + + +#define UTIL___ROW_READER_INCLUDE__INL +#include "row_reader.inl" +#undef UTIL___ROW_READER_INCLUDE__INL + + +/// A single field in a row abstraction. +template +class CRR_Field +{ +public: + /// Get the converted field value + /// @return + /// Converted field value + /// @note + /// Available specializations: string, bool, ints, floats, CTime + /// @exception + /// Throws an exception if there is conversion problem or the field + /// value is NULL + template + TValue Get(void) const; + + /// Get the converted field value + /// @param default_value + /// Default value if the field was translated to NULL + /// @return + /// Converted field value or a default value + /// @note + /// Available specializations: string, bool, ints, floats, CTime + /// @exception + /// Throws an exception if there is conversion problem + template TValue + GetWithDefault(const TValue& default_value) const; + + /// Get the field value converted to CTime + /// @param fmt + /// CTime format + /// @return + /// Converted to CTime field value + /// @exception + /// Throws an exception if there is conversion problem or the field + /// value was translated to NULL + CTime Get(const CTimeFormat& fmt) const; + + /// Check if the field value is NULL + /// @return + /// true if the field value is NULL + bool IsNull(void) const; + + /// Get the field original data + /// @return + /// The field original data + const CTempString GetOriginalData(void) const; + + // Construct an empty field + CRR_Field(); + + // Copy constructor of a field + CRR_Field(const CRR_Field& field); + + // Moving coonstructor of a field + CRR_Field(const CRR_Field&& other_field); + + // Assignment + CRR_Field& operator=(const CRR_Field& other_field); + + // Moving assignment + CRR_Field& operator=(const CRR_Field&& other_field); + +private: + CTempString x_GetStringValue(void) const; + +private: + friend class CRowReader; + friend class CRR_Row; + + // Used only when copying is done + string m_OriginalDataCopy; + + bool m_IsNull; + bool m_Translated; + CTempString m_OriginalData; + string m_TranslatedValue; + + // Needs to provide a stream context in the exceptions if a row has not + // been copied yet. + CRowReader* m_RowReader; +}; + + + +/// Represents one row from an input stream +template +class CRR_Row +{ +public: + /// Construct an empty row + CRR_Row(); + + // Construct a copy + CRR_Row(const CRR_Row& other_row); + + // Moving constructor of a row + CRR_Row(const CRR_Row&& other_row); + + // Assignment + CRR_Row& operator=(const CRR_Row& other_row); + + // Moving assignment + CRR_Row& operator=(const CRR_Row&& other_row); + + /// Get a row field + /// @param field + /// 0-based field number + /// @return + /// A reference to the field + /// @exception + /// Throws an exception in case if the field does not exist + const CRR_Field& operator[](TFieldNo field) const; + + /// Get a row field + /// @param field + /// Field name + /// @return + /// A reference to the field + /// @exception + /// Throws an exception in case if the field name is unknown or + /// if the field does not exist + const CRR_Field& operator[](CTempString field) const; + + /// Get the row type + /// @return + /// Row type + ERR_RowType GetType(void) const; + + /// Get the number of fields in the row + /// @return + /// The number of fields in the row + TFieldNo GetNumberOfFields(void) const; + + /// Get the row original data + /// @return + /// The row original data + CTempString GetOriginalData(void) const; + + /// Get the number of a fields for which any kind of meta info is provided. + /// @return + /// Number of fields for which any kind of meta info is provided + TFieldNo GetDescribedFieldCount(void) const; + + struct SFieldMetaInfo { + public: + SFieldMetaInfo() : + field_no(0), is_name_initialized(false), + is_type_initialized(false), is_ext_type_initialized(false) + {} + + TFieldNo field_no; + + bool is_name_initialized; + string name; + + bool is_type_initialized; + CRR_FieldType type; + + bool is_ext_type_initialized; + CRR_FieldType ext_type; + }; + + /// Get the collected fields meta info. + /// @param from + /// Field number to start from + /// @param to + /// Field number to end with + /// @return + /// A vector of structures with a meta information about fields. + /// If a field has no meta information then the vector will not have a + /// corresponding structure. + /// The fields interval is inclusive. + vector GetFieldsMetaInfo + (TFieldNo from = 0, + TFieldNo to = numeric_limits::max()); + +private: + friend class CRowReader; + + void x_OnFreshRead(void); + void x_AdjustFieldsSize(size_t new_size); + void x_CopyFields(const CRR_Row& other_row); + void x_SetFieldName(TFieldNo field, const string& name, bool user_init); + void x_SetFieldType( + TFieldNo field, + const CRR_FieldType& type, + bool user_init); + void x_SetFieldTypeEx( + TFieldNo field, + const CRR_FieldType& type, + const CRR_FieldType& extended_type, + bool user_init); + void x_ClearFieldsInfo(void); + void x_ClearTraitsProvidedFieldsInfo(void); + void x_DetachMetaInfo(void); + TFieldNo x_GetFieldIndex(CTempString field) const; + +private: + string m_RawData; + ERR_RowType m_RowType; + CRef> m_MetaInfo; + mutable bool m_Copied; + + // The content of the vector is reused so there is a manual control + // over what the current size/capacity is + vector> m_Fields; + size_t m_FieldsSize; + size_t m_FieldsCapacity; + + // Needs to provide a stream context in the exceptions if a row has not + // been copied yet. + CRowReader* m_RowReader; +}; + + + +/// Callback style template to iterate over a row stream. +/// The template provides a framework while the data source specifics are +/// implemented via stream traits. The stream traits are supplied in the +/// template parameter and must meet certain interface requirements. +/// The requirements are described in the CRowReaderStream_Base +/// class vanilla implementation of the traits (see row_reader_base.hpp) +template +class CRowReader +{ +public: + typedef CRR_Field CField; + typedef CRR_Row CRow; + + + /// Construct a row reader + /// @param is + /// Input stream to read rows from + /// @param sourcename + /// Data source name + /// @param ownership + /// If set to eTakeOwnership then the stream will be owned by + /// CRowReader -- and automatically deleted when necessary + CRowReader(CNcbiIstream* is, + const string& sourcename, + EOwnership ownership = eNoOwnership); + + /// Construct a row reader out of a file + /// @param filename + /// File to read rows from + /// @note + /// The file will be opened immediately (and, using TTraits-specific mode) + /// @exception + /// Throws exceptions (in particular) if the file does not exist or there + /// are no read permissions + CRowReader(const string& filename); + + virtual ~CRowReader(); + + /// Switch to processing data from another stream + /// @note + /// The stream's row iterator will still point to the current row in the + /// previous data source. Next call to CRowReader::begin() or + /// to iterator's operator++ will retrieve the data from the new stream. + /// @param is + /// Input stream to read rows from + /// @param sourcename + /// Data source name + /// @param ownership + /// If set to eTakeOwnership then the stream will be owned by + /// CRowReader -- and automatically deleted when necessary + void SetDataSource(CNcbiIstream* is, + const string& sourcename, + EOwnership ownership = eNoOwnership); + + /// Switch to processing data from another file + /// @note + /// The stream's row iterator will still point to the current row in the + /// previous data source. Next call to CRowReader::begin() or + /// to iterator's operator++ will retrieve the data from the new file. + /// @param filename + /// File to read rows from + /// @note + /// The file will be opened immediately (and, using TTraits-specific mode) + /// @exception + /// Throws exceptions (in particular) if the file does not exist or there + /// are no read permissions + void SetDataSource(const string& filename); + + /// Read and validate-only the stream, calling + /// TTraits::Validate(row, validation_mode) on each row + void Validate(typename TTraits::ERR_ValidationMode validation_mode + = TTraits::eRR_ValidationMode_Default, + ERR_FieldValidationMode field_validation_mode + = eRR_FieldValidation); + + /// Get the number of the line that is currently being processed + /// @return + /// 0-based number of the currently processed line (in the current + /// data source) + /// @note + /// This method can also be safely used inside the TTraits methods + /// @exception + /// Throws an exception if called before any line was read + TLineNo GetCurrentLineNo(void) const; + + /// Get the absolute position (in the current data source) of the + /// beginning of the row that is currently being processed + /// @return + /// 0-based absolute position of the beginning of the currently processed + /// row + /// @note + /// This method can also be safely used in the TTraits methods + /// @exception + /// Throws an exception if called before any line was read + TStreamPos GetCurrentRowPos(void) const; + + /// Set the field name + /// @note + /// If the names are set then the fields can be referred to by their names + /// @param field + /// 0-based field number. The new name overrides the previously set if so. + /// @param name + /// The field name + void SetFieldName(TFieldNo field, const string& name); + + /// Set the (basic) data type of the field + /// @param field + /// 0-based field number. The new type overrides the previously set if so. + /// @param type + /// The field type + void SetFieldType + (TFieldNo field, + const CRR_FieldType& type); + + /// Set the (trait specific) data type of the field + /// @param field + /// 0-based field number. The new types override the previously set if so. + /// @param type + /// The field type + /// @param extended_type + /// The field extended type + void SetFieldTypeEx + (TFieldNo field, + const CRR_FieldType& type, + const CRR_FieldType& extended_type); + + /// Get the collected fields meta info. + /// @param from + /// Field number to start from + /// @param to + /// Field number to end with + /// @return + /// A vector of structures with a meta information about fields. + /// If a field has no meta information then the vector will not have a + /// corresponding structure. + /// The fields interval is inclusive. + vector::SFieldMetaInfo> GetFieldsMetaInfo + (TFieldNo from = 0, + TFieldNo to = numeric_limits::max()); + + /// Get the number of a fields for which any kind of meta info is provided. + /// @return + /// Number of fields for which any kind of meta info is provided + TFieldNo GetDescribedFieldCount(void) const; + + /// Clear the information about all field names, types and extended types + /// @note + /// SetDataSource() calls by themselves don't clear the info + /// (although it indeed may be changed, as usual, while reading new + /// metainfo from the data source) + void ClearFieldsInfo(void); + + /// Get the traits object + /// @return + /// A reference to the traits instance currently used + TTraits& GetTraits(void); + +public: + + /// A (forward-only) iterator to iterate over the rows from a stream + /// + /// All iterators related to the same instance of CRowReader + /// are in fact pointing to the one and the same row -- the (current) one + /// that the CRowReader has advanced to so far. + /// + /// @attention + /// The iterator's data is destroyed after the iterator is advanced. + class CRowIterator + { + public: + /// Get a row field + /// @param field + /// 0-based field number + /// @return + /// A reference to the field + /// @exception + /// Throws an exception in case if: + /// - the iterator has reached the end + /// - the field does not exist + const CRR_Field& operator[](TFieldNo field) const; + + /// Get a row field + /// @param field + /// Field name + /// @return + /// A reference to the field + /// @exception + /// Throws an exception in case if: + /// - the iterator has reached the end + /// - the field name is unknown + /// - the field does not exist + const CRR_Field& operator[](CTempString field) const; + + /// Get a reference to the current row + /// @return + /// A reference to the current row + /// @exception + /// Throws an exception if the iterator has reached the end + CRR_Row& operator* (void) const; + + /// Get a pointer to the current row + /// @return + /// A pointer to the current row + /// @exception + /// Throws an exception if the iterator has reached the end + CRR_Row* operator->(void) const; + + /// Compare this iterator with another + /// @attention + /// This and/or "iter" iterator must be "end()" + /// @param iter + /// RHS iterator to compare + /// @return + /// true if either of the following is true: + /// - this iterator points to the end of the same + /// underlying data source (SetDataSource() wise) as the + /// contemporary "end()" + /// - both iterators are "end()" + /// - both iterators are not at end + /// @exception + /// Throw if the compared iterators belong to different streams + bool operator==(const CRowIterator& iter) const; + + /// This is an exact negation of operator== + /// @sa operator== + bool operator!=(const CRowIterator& iter) const; + + // Iterator copy constructor + CRowIterator(const CRowIterator& iter); + + ~CRowIterator(); + + CRowIterator& operator=(const CRowIterator& iter); + + /// Advance the iterator to the next row + /// @note + /// The next row can be in the next data source (if set using + /// SetDataSource()). In this case the ++ operator can + /// be legally applied to an iterator that points to the "end()" of + /// the previous data source. + /// @return + /// A reference to self + /// @exception + /// Throws an exception if any of the following happens: + /// - the iterator has already reached the end of its current(!) + /// data source + /// - the iterator belongs to another instance of CRowReader + /// @attention + /// The data that was previously obtained through the iterator is + /// invalidated. + /// Because all iterators related to the same instance of + /// CRowReader are in fact pointing to the one and the same + /// row so advancing any iterator will advance all iterators that + /// belong to the same stream. + CRowIterator& operator++(void); + + private: + CRowReader* m_RowReader; + bool m_IsEndIter; + + friend class CRowReader; + + CRowIterator(CRowReader* s, bool is_end); + CRowIterator(const CRowReader* s, bool is_end); + void x_CheckDereferencing(void) const; + void x_CheckAdvancing(void) const; + void x_CheckFieldAccess(void) const; + }; + + /// It works exactly(!) like CRowIterator::operator++, except it creates + /// new iterator and therefore can also be used to create the very + /// first iterator. + CRowIterator begin(void); + + /// Get iterator pointing to the end of the current underlying data source + CRowIterator end(void) const; + + typedef CRowIterator iterator; + typedef CRowIterator const_iterator; + + /// Get basic context. It includes (if available) a data source name, + /// a position in the stream, the current line and the current row data. + /// @return + /// Basic context structure + CRR_Context GetBasicContext(void) const; + + /// Get traits context + /// @return + /// Traits current context + /// @note + /// Traits may extend the basic context (by deriving from it) or use + /// CRR_Context as is + typename TTraits::TRR_Context GetContext(void) const; + +private: + friend TTraits; + + bool x_GetRowData(size_t* phys_lines_read); + void x_ReadNextRow(void); + void x_OpenFile(SRR_SourceInfo& stream_info); + void x_Reset(void); + void x_ResetToEnd(void); + void x_UpdateCurrentLineNo(size_t phys_lines_read); + + // Three SetField...() methods are for the traits in opposite to the + // 'user' available methods SetField...(...) + void x_SetFieldName(TFieldNo field, const string& name); + void x_SetFieldType( + TFieldNo field, + const CRR_FieldType& type); + void x_SetFieldTypeEx( + TFieldNo field, + const CRR_FieldType& type, + const CRR_FieldType& extended_type); + + void x_ClearTraitsProvidedFieldsInfo(void); + + ERR_EventAction x_OnEvent(ERR_Event event); + CRR_Context* x_GetContextClone(void); + +private: + // Note: it was decided that when an underlying data stream is switched the + // original one must stay intact till the first iteration over the next + // stream. So two structures are introduced below. + // Each of the structures holds an information about a stream, an ownership + // on it and a file name if so. + SRR_SourceInfo m_DataSource; + SRR_SourceInfo m_NextDataSource; + + // End of the current stream flag + bool m_AtEnd; + + bool m_LinesAlreadyRead; + bool m_RawDataAvailable; + TLineNo m_CurrentLineNo; + size_t m_PreviousPhysLinesRead; + TStreamPos m_CurrentRowPos; + TTraits m_Traits; + CRR_Row m_CurrentRow; + + // if true => within the validate() loop + bool m_Validation; + + // Note: this member is needed in a very limited scope within one method to + // support the tokenization stage. So from the maintainability point of + // view the variable had to be right there. However it was decided to do an + // optimization (without having any profiling to see if this is a + // performance bottleneck) and to reuse the tokens vector. Thus the + // variable scope was extended to the class scope introducing a pollution. + vector m_Tokens; + + // Note: instead of having two booleans here it is is possible to use just + // one because they are always in oppisite states. However the code looks + // easier to read if there are separate variables. Bearing in mind that the + // state switching happens only at the moment a stream is switched it seems + // acceptable (from the performance POV) to have two variables. + bool m_NeedOnSourceBegin; + bool m_NeedOnSourceEnd; + +private: + // prohibit assignment and copy-ctor + CRowReader(const CRowReader&) = delete; + CRowReader(CRowReader&&) = delete; + CRowReader& operator=(const CRowReader&) = delete; + CRowReader& operator=(CRowReader&&) = delete; +}; + + + +// Begin of the CRR_Field implementation + +template +CTime CRR_Field::Get(const CTimeFormat& fmt) const +{ + if (m_RowReader == nullptr) + return CTime(x_GetStringValue(), fmt); + try { + return CTime(x_GetStringValue(), fmt); + } catch (CRowReaderException& exc) { + exc.SetContext(m_RowReader->GetBasicContext().Clone()); + throw exc; + } catch (const CException& exc) { + NCBI_RETHROW2(exc, CRowReaderException, eFieldConvert, + "Cannot convert field value to CTime using " + "format " + fmt.GetString(), + m_RowReader->GetBasicContext().Clone()); + } catch (const exception& exc) { + NCBI_THROW2(CRowReaderException, eFieldConvert, + exc.what(), m_RowReader->GetBasicContext().Clone()); + } catch (...) { + NCBI_THROW2(CRowReaderException, eFieldConvert, + "Unknown error while converting field value to " + "CTime using format " + fmt.GetString(), + m_RowReader->GetBasicContext().Clone()); + } +} + + +template +template +TValue CRR_Field::Get(void) const +{ + TValue val; + if (m_RowReader == nullptr) { + CRR_Util::GetFieldValueConverted(x_GetStringValue(), val); + } else { + try { + CRR_Util::GetFieldValueConverted(x_GetStringValue(), val); + } catch (CRowReaderException& exc) { + exc.SetContext(m_RowReader->GetBasicContext().Clone()); + throw exc; + } catch (const CException& exc) { + NCBI_RETHROW2(exc, CRowReaderException, eFieldConvert, + "Cannot convert field value to " + + string(typeid(TValue).name()), + m_RowReader->GetBasicContext().Clone()); + } catch (const exception& exc) { + NCBI_THROW2(CRowReaderException, eFieldConvert, + exc.what(), m_RowReader->GetBasicContext().Clone()); + } catch (...) { + NCBI_THROW2(CRowReaderException, eFieldConvert, + "Unknown error while converting field value to " + + string(typeid(TValue).name()), + m_RowReader->GetBasicContext().Clone()); + } + } + return val; +} + + +template +template TValue +CRR_Field::GetWithDefault(const TValue& default_value) const +{ + if (m_IsNull) + return default_value; + return Get(); +} + + +template +bool CRR_Field::IsNull(void) const +{ + return m_IsNull; +} + + +template +const CTempString CRR_Field::GetOriginalData(void) const +{ + return m_OriginalData; +} + + +template +CRR_Field::CRR_Field() : + m_IsNull(false), m_Translated(false), + m_OriginalData(nullptr, 0), m_RowReader(nullptr) +{} + + +template +CRR_Field::CRR_Field(const CRR_Field& other_field) : + m_OriginalDataCopy(other_field.m_OriginalData.data(), + other_field.m_OriginalData.size()), + m_IsNull(other_field.m_IsNull), + m_Translated(other_field.m_Translated), + m_OriginalData(m_OriginalDataCopy.data(), m_OriginalDataCopy.size()), + m_TranslatedValue(other_field.m_TranslatedValue), + m_RowReader(nullptr) +{} + + +template +CRR_Field::CRR_Field(const CRR_Field&& other_field) : + m_OriginalDataCopy(std::move(other_field.m_OriginalDataCopy)), + m_IsNull(other_field.m_IsNull), + m_Translated(other_field.m_Translated), + m_OriginalData(m_OriginalDataCopy.data(), m_OriginalDataCopy.size()), + m_TranslatedValue(std::move(other_field.m_TranslatedValue)), + m_RowReader(other_field.m_RowReader) +{} + + +template +CRR_Field& CRR_Field::operator=(const CRR_Field& other_field) +{ + if (this != &other_field) { + m_OriginalDataCopy.assign(other_field.m_OriginalData.data(), + other_field.m_OriginalData.size()); + m_IsNull = other_field.m_IsNull; + m_Translated = other_field.m_Translated; + m_OriginalData.assign(m_OriginalDataCopy.data(), + m_OriginalDataCopy.size()); + m_TranslatedValue = other_field.m_TranslatedValue; + m_RowReader = nullptr; + } + return *this; +} + + +template +CRR_Field& CRR_Field::operator=(const CRR_Field&& other_field) +{ + if (this != &other_field) { + m_OriginalDataCopy = std::move(other_field.m_OriginalDataCopy); + m_IsNull = other_field.m_IsNull; + m_Translated = other_field.m_Translated; + m_OriginalData.assign(m_OriginalDataCopy.data(), + m_OriginalDataCopy.size()); + m_TranslatedValue = std::move(other_field.m_TranslatedValue); + m_RowReader = other_field.m_RowReader; + } + return *this; +} + + +template +CTempString CRR_Field::x_GetStringValue(void) const +{ + if (m_IsNull) + NCBI_THROW2(CRowReaderException, eNullField, + "The field value is translated to NULL", nullptr); + if (m_Translated) + return m_TranslatedValue; + return m_OriginalData; +} + +// End of the CRR_Field implementation + + + +// Begin of the CRR_Row implementation + +template +CRR_Row::CRR_Row() : + m_RowType(eRR_Invalid), + m_MetaInfo(new CRR_MetaInfo()), + m_Copied(false), + m_FieldsSize(0), + m_FieldsCapacity(0), + m_RowReader(nullptr) +{} + + +template +CRR_Row::CRR_Row(const CRR_Row& other_row) : + m_RawData(other_row.m_RawData), + m_RowType(other_row.m_RowType), + m_MetaInfo(other_row.m_MetaInfo), + m_Copied(false), + m_FieldsSize(0), + m_FieldsCapacity(0), + m_RowReader(nullptr) +{ + x_CopyFields(other_row); + other_row.m_Copied = true; +} + + +template +CRR_Row& CRR_Row::operator=(const CRR_Row& other_row) +{ + if (this != &other_row) { + m_RawData = other_row.m_RawData; + m_RowType = other_row.m_RowType; + m_MetaInfo = other_row.m_MetaInfo; + m_Copied = false; + m_RowReader = nullptr; + + x_CopyFields(other_row); + other_row.m_Copied = true; + } + return *this; +} + + +template +CRR_Row::CRR_Row(const CRR_Row&& other_row) : + m_RawData(std::move(other_row.m_RawData)), + m_RowType(other_row.m_RowType), + m_MetaInfo(std::move(other_row.m_MetaInfo)), + m_Copied(other_row.m_Copied), + m_Fields(std::move(other_row.m_Fields)), + m_FieldsSize(other_row.m_FieldsSize), + m_FieldsCapacity(other_row.m_FieldsCapacity), + m_RowReader(other_row.m_RowReader) +{} + + +template +CRR_Row& CRR_Row::operator=(const CRR_Row&& other_row) +{ + m_RawData = std::move(other_row.m_RawData); + m_RowType = other_row.m_RowType; + m_MetaInfo = std::move(other_row.m_MetaInfo); + m_Copied = other_row.m_Copied; + m_Fields = std::move(other_row.m_Fields); + m_FieldsSize = other_row.m_FieldsSize; + m_FieldsCapacity = other_row.m_FieldsCapacity; + m_RowReader = other_row.m_RowReader; +} + + +template +const CRR_Field& CRR_Row::operator[](TFieldNo field) const +{ + if (field >= GetNumberOfFields()) { + CRR_Context* ctxt = nullptr; + if (m_RowReader != nullptr) + ctxt = m_RowReader->GetBasicContext().Clone(); + + NCBI_THROW2(CRowReaderException, eFieldNoOutOfRange, + "Field index " + NStr::NumericToString(field) + + " is out of range for the current row", ctxt); + } + return m_Fields[field]; +} + + +template +const CRR_Field& +CRR_Row::operator[](CTempString field) const +{ + TFieldNo index = x_GetFieldIndex(field); + if (index >= GetNumberOfFields()) { + CRR_Context* ctxt = nullptr; + if (m_RowReader != nullptr) + ctxt = m_RowReader->GetBasicContext().Clone(); + + NCBI_THROW2(CRowReaderException, eFieldNoOutOfRange, + "Field index " + NStr::NumericToString(index) + + " provided for the field name '" + field + + "' is out of range for the current row", ctxt); + } + return m_Fields[index]; +} + + +template +ERR_RowType CRR_Row::GetType(void) const +{ + return m_RowType; +} + + +template +TFieldNo CRR_Row::GetNumberOfFields(void) const +{ + return static_cast(m_FieldsSize); +} + + +template +CTempString CRR_Row::GetOriginalData(void) const +{ + return m_RawData; +} + + +template +void CRR_Row::x_OnFreshRead(void) +{ + m_RawData.clear(); + m_RowType = eRR_Invalid; + m_FieldsSize = 0; +} + + +template +void CRR_Row::x_AdjustFieldsSize(size_t new_size) +{ + m_FieldsSize = new_size; + while (m_FieldsCapacity < new_size) { + m_Fields.push_back(CRR_Field()); + ++m_FieldsCapacity; + } +} + + +template +void CRR_Row::x_CopyFields(const CRR_Row& other_row) +{ + // This is an optimization. + // Technically it would be possible to copy a vector of the fields + // however it will lead to creating copies of all strings for each field. + // On the other hand it seems that copying of the rows would be a likely + // case so the row raw data could be copied once and then the field are + // used by a reference. Thus the only temp string pointers need to be + // adjusted for each field. + ptrdiff_t raw_data_delta = m_RawData.data() - other_row.m_RawData.data(); + x_AdjustFieldsSize(other_row.m_FieldsSize); + for (size_t index = 0; index < m_FieldsSize; ++index) { + CRR_Field& to_field = m_Fields[index]; + const CRR_Field& from_field = other_row.m_Fields[index]; + + to_field.m_IsNull = from_field.m_IsNull; + to_field.m_Translated = from_field.m_Translated; + if (to_field.m_Translated) + to_field.m_TranslatedValue = from_field.m_TranslatedValue; + else + to_field.m_TranslatedValue.clear(); + + to_field.m_OriginalData = CTempString( + from_field.m_OriginalData.data() + raw_data_delta, + from_field.m_OriginalData.size()); + + m_Fields[index].m_RowReader = nullptr; + } +} + + +template +void CRR_Row::x_SetFieldName(TFieldNo field, const string& name, + bool user_init) +{ + x_DetachMetaInfo(); + m_MetaInfo->SetFieldName(field, name, user_init); +} + + +template +void CRR_Row::x_SetFieldType( + TFieldNo field, + const CRR_FieldType& type, + bool user_init) +{ + x_DetachMetaInfo(); + m_MetaInfo->SetFieldType(field, type, user_init); +} + + +template +void CRR_Row::x_SetFieldTypeEx( + TFieldNo field, + const CRR_FieldType& type, + const CRR_FieldType& extended_type, + bool user_init) +{ + x_DetachMetaInfo(); + m_MetaInfo->SetFieldTypeEx(field, type, extended_type, user_init); +} + + +template +TFieldNo CRR_Row::GetDescribedFieldCount(void) const +{ + return m_MetaInfo->GetDescribedFieldCount(); +} + + +template +vector::SFieldMetaInfo> +CRR_Row::GetFieldsMetaInfo(TFieldNo from, TFieldNo to) +{ + vector result; + + if (m_MetaInfo->m_FieldsInfo.empty()) + return result; + + size_t last_index = min(static_cast(to), + m_MetaInfo->m_FieldsInfo.size() - 1); + for (size_t index = from; index <= to && index <= last_index; ++index) { + const auto & field_info = m_MetaInfo->m_FieldsInfo[index]; + if (field_info.IsInitialized()) { + SFieldMetaInfo info; + + info.field_no = index; + info.is_name_initialized = + field_info.m_NameInit != CRR_MetaInfo::eNotInitialized; + if (info.is_name_initialized) + info.name = *field_info.m_FieldName; + info.is_type_initialized = + field_info.m_TypeInit != CRR_MetaInfo::eNotInitialized; + info.type = field_info.m_FieldType; + info.is_ext_type_initialized = + field_info.m_ExtTypeInit != CRR_MetaInfo::eNotInitialized; + info.ext_type = field_info.m_FieldExtType; + + result.push_back(info); + } + } + return result; +} + + +template +void CRR_Row::x_ClearFieldsInfo(void) +{ + x_DetachMetaInfo(); + m_MetaInfo->Clear(true); // true -> clears both user and + // traits provided meta info +} + + +template +void CRR_Row::x_ClearTraitsProvidedFieldsInfo(void) +{ + x_DetachMetaInfo(); + m_MetaInfo->Clear(false); // false -> clears only trits provided + // meta info +} + + +template +void CRR_Row::x_DetachMetaInfo(void) +{ + if (m_Copied) { + CRR_MetaInfo* old_meta = m_MetaInfo.GetPointer(); + CRR_MetaInfo* new_meta = new CRR_MetaInfo(*old_meta); + + m_MetaInfo.Reset(new_meta); + m_Copied = false; + } +} + + +template +TFieldNo CRR_Row::x_GetFieldIndex(CTempString field) const +{ + if (m_RowReader == nullptr) + return m_MetaInfo->GetFieldIndexByName(field); + try { + return m_MetaInfo->GetFieldIndexByName(field); + } catch (CRowReaderException& exc) { + exc.SetContext(m_RowReader->GetBasicContext().Clone()); + throw exc; + } catch (const CException& exc) { + NCBI_RETHROW2(exc, CRowReaderException, eFieldMetaInfoAccess, + "Cannot get field number by name ('" + + string(field) + "')", + m_RowReader->GetBasicContext().Clone()); + } catch (const exception& exc) { + NCBI_THROW2(CRowReaderException, eFieldMetaInfoAccess, + exc.what(), m_RowReader->GetBasicContext().Clone()); + } catch (...) { + NCBI_THROW2(CRowReaderException, eFieldMetaInfoAccess, + "Unknown error while getting field number by name ('" + + string(field) + "')", + m_RowReader->GetBasicContext().Clone()); + } +} + + +// End of the CRR_Row implementation + + + +// Begin of the CRowReader implementation + +template +CRowReader::CRowReader( + CNcbiIstream* is, + const string& sourcename, + EOwnership ownership) : + m_DataSource(is, sourcename, ownership == eTakeOwnership), + m_AtEnd(false), m_LinesAlreadyRead(false), m_RawDataAvailable(false), + m_CurrentLineNo(0), m_PreviousPhysLinesRead(0), + m_Validation(false), m_NeedOnSourceBegin(true), m_NeedOnSourceEnd(false) +{ + m_CurrentRowPos = NcbiStreamposToInt8(m_DataSource.m_Stream->tellg()); + m_Traits.x_SetMyStream(this); + m_CurrentRow.m_RowReader = this; +} + + +template +CRowReader::CRowReader(const string& filename) : + m_DataSource(nullptr, filename, false), + m_AtEnd(false), m_LinesAlreadyRead(false), + m_RawDataAvailable(false), m_CurrentLineNo(0), + m_PreviousPhysLinesRead(0), + m_Validation(false), m_NeedOnSourceBegin(true), m_NeedOnSourceEnd(false) +{ + CRR_Util::CheckExistanceAndPermissions(filename); + x_OpenFile(m_DataSource); + m_CurrentRowPos = NcbiStreamposToInt8(m_DataSource.m_Stream->tellg()); + m_Traits.x_SetMyStream(this); + m_CurrentRow.m_RowReader = this; +} + + +template +CRowReader::~CRowReader() +{} + + +template +void CRowReader::SetDataSource( + CNcbiIstream* is, + const string& sourcename, + EOwnership ownership) +{ + m_NextDataSource.Clear(); + m_NextDataSource.m_Stream = is; + m_NextDataSource.m_Sourcename = sourcename; + m_NextDataSource.m_StreamOwner = ownership == eTakeOwnership; +} + + +template +void CRowReader::SetDataSource(const string& filename) +{ + CRR_Util::CheckExistanceAndPermissions(filename); + m_NextDataSource.Clear(); + m_NextDataSource.m_Sourcename = filename; + + x_OpenFile(m_NextDataSource); +} + + +template +void CRowReader::Validate( + typename TTraits::ERR_ValidationMode validation_mode, + ERR_FieldValidationMode field_validation_mode) +{ + ERR_Action action = eRR_Interrupt; + size_t phys_lines_read; + + x_ResetToEnd(); + m_CurrentRowPos = NcbiStreamposToInt8(m_DataSource.m_Stream->tellg()); + + try { + m_Traits.SetValidationMode(validation_mode); + } catch (const CException& exc) { + CRR_Context* ctxt = x_GetContextClone(); + x_ResetToEnd(); + NCBI_RETHROW2(exc, CRowReaderException, eValidating, + "Set validation mode error", ctxt); + } catch (const exception& exc) { + CRR_Context* ctxt = x_GetContextClone(); + x_ResetToEnd(); + NCBI_THROW2(CRowReaderException, eValidating, exc.what(), ctxt); + } catch (...) { + CRR_Context* ctxt = x_GetContextClone(); + x_ResetToEnd(); + NCBI_THROW2(CRowReaderException, eValidating, + "Unknown set validation mode error", ctxt); + } + + for (;;) { + m_AtEnd = false; + m_Validation = true; + + // The beginning of the source + try { + if (m_NeedOnSourceBegin && m_NextDataSource.m_Stream == nullptr) { + if (x_OnEvent(eRR_Event_SourceBegin) == eRR_EventAction_Stop) { + x_ResetToEnd(); + goto onEnd; + } + } + } catch (...) { + // The x_OnEvent() has already attached the proper context to the + // generated exception so the only thing to to is to reset the + // stream state. + x_ResetToEnd(); + throw; + } + + for (;;) { + try { + if (!x_GetRowData(&phys_lines_read)) + break; + } catch (...) { + // The x_GetRowData() can also generate an exception... + x_ResetToEnd(); + throw; + } + x_UpdateCurrentLineNo(phys_lines_read); + + try { + action = m_Traits.Validate(CTempString(m_CurrentRow.m_RawData), + field_validation_mode); + if (action == eRR_Interrupt) + break; + } catch (const CException& exc) { + CRR_Context* ctxt = x_GetContextClone(); + x_ResetToEnd(); + NCBI_RETHROW2(exc, CRowReaderException, eValidating, + "Validation error", ctxt); + } catch (const exception& exc) { + CRR_Context* ctxt = x_GetContextClone(); + x_ResetToEnd(); + NCBI_THROW2(CRowReaderException, eValidating, exc.what(), ctxt); + } catch (...) { + CRR_Context* ctxt = x_GetContextClone(); + x_ResetToEnd(); + NCBI_THROW2(CRowReaderException, eValidating, + "Unknown validating error", ctxt); + } + } + + onEnd: + m_AtEnd = true; + + try { + if (m_NeedOnSourceEnd) { + if (x_OnEvent(eRR_Event_SourceEnd) == eRR_EventAction_Stop) { + x_ResetToEnd(); + return; + } + } + } catch (...) { + // The x_OnEvent() has already attached the proper context to the + // generated exception so the only thing to to is to reset the + // stream state. + x_ResetToEnd(); + throw; + } + + x_ResetToEnd(); + + // Test if there was a source switch in the Traits::onEvent(...) call. + // If there was then we continue reading. + if (m_NextDataSource.m_Stream == nullptr) + break; + } +} + + +template +TLineNo CRowReader::GetCurrentLineNo(void) const +{ + if (!m_LinesAlreadyRead) { + // Note: it was decided to make it a special case and return 0. + // i.e. it is impossible to distinguish two cases: + // - there ware no reads yet + // - it was the very first read + return 0; + } + return m_CurrentLineNo; +} + + +template +TStreamPos CRowReader::GetCurrentRowPos(void) const +{ + if (!m_LinesAlreadyRead) { + // Note: it was decided to make it a special case and return 0. + // i.e. it is impossible to distinguish two cases: + // - there ware no reads yet + // - it was the very first read + return 0; + } + return m_CurrentRowPos; +} + + +template +void CRowReader::SetFieldName(TFieldNo field, + const string& name) +{ + // true - user (not traits) setting + m_CurrentRow.x_SetFieldName(field, name, true); +} + + +template +void +CRowReader::SetFieldType( + TFieldNo field, + const CRR_FieldType& type) +{ + // true = user (not traits) setting + m_CurrentRow.x_SetFieldType(field, type, true); +} + + +template +void +CRowReader::SetFieldTypeEx( + TFieldNo field, + const CRR_FieldType& type, + const CRR_FieldType& extended_type) +{ + // true - user (not traits) setting + m_CurrentRow.x_SetFieldTypeEx(field, type, extended_type, true); +} + + +template +void CRowReader::x_SetFieldName(TFieldNo field, + const string& name) +{ + // false - traits (not user) setting + m_CurrentRow.x_SetFieldName(field, name, false); +} + + +template +void CRowReader::x_SetFieldType( + TFieldNo field, + const CRR_FieldType& type) +{ + // false - traits (not user) setting + m_CurrentRow.x_SetFieldType(field, type, false); +} + + +template +void CRowReader::x_SetFieldTypeEx( + TFieldNo field, + const CRR_FieldType& type, + const CRR_FieldType& extended_type) +{ + // false - traits (not user) setting + m_CurrentRow.x_SetFieldTypeEx(field, type, extended_type, false); +} + + +template +vector::SFieldMetaInfo> +CRowReader::GetFieldsMetaInfo(TFieldNo from, TFieldNo to) +{ + return m_CurrentRow.GetFieldsMetaInfo(from, to); +} + + +template +TFieldNo CRowReader::GetDescribedFieldCount(void) const +{ + return m_CurrentRow.GetDescribedFieldCount(); +} + + +template +void CRowReader::ClearFieldsInfo(void) +{ + m_CurrentRow.x_ClearFieldsInfo(); +} + + +template +void CRowReader::x_ClearTraitsProvidedFieldsInfo(void) +{ + m_CurrentRow.x_ClearTraitsProvidedFieldsInfo(); +} + + +template +TTraits& CRowReader::GetTraits(void) +{ + return m_Traits; +} + + +template +typename CRowReader::CRowIterator +CRowReader::begin(void) +{ + CRowIterator it(this, false); + ++it; + return it; +} + + +template +typename CRowReader::CRowIterator +CRowReader::end(void) const +{ + if (m_Validation) + NCBI_THROW2(CRowReaderException, eIteratorWhileValidating, + "It is prohibited to use iterators " + "during the stream validation", nullptr); + return CRowIterator(this, true); +} + + +template +CRR_Context CRowReader::GetBasicContext(void) const +{ + return CRR_Context(m_DataSource.m_Sourcename, m_LinesAlreadyRead, + m_CurrentLineNo, m_CurrentRowPos, + m_RawDataAvailable, m_CurrentRow.m_RawData, m_AtEnd); +} + + +template +typename TTraits::TRR_Context +CRowReader::GetContext(void) const +{ + return m_Traits.GetContext(GetBasicContext()); +} + + +// This member throws only exceptions which already have the attached context. +// I.e. the higher level needs to bother only about the stream state after an +// exception is generated. + +// true: the line is ready; a non-end iterator needs to be provided +// false: the stream is over; an end iterator needs to be provided + +// In case of the soft end iterator it is an upper level responsibility to +// update the stream state. +template +bool CRowReader::x_GetRowData(size_t* phys_lines_read) +{ + for (;;) { + // Switch the source stream if needed + if (m_NextDataSource.m_Stream != nullptr) { + + if (m_NeedOnSourceEnd) { + if (x_OnEvent(eRR_Event_SourceEnd) == eRR_EventAction_Stop) { + return false; // soft end iterator + } + } + + m_DataSource.Clear(); + m_DataSource = m_NextDataSource; + + m_NextDataSource.m_Stream = nullptr; + m_NextDataSource.m_Sourcename.clear(); + m_NextDataSource.m_StreamOwner = false; + + x_Reset(); + m_CurrentRowPos = NcbiStreamposToInt8( + m_DataSource.m_Stream->tellg()); + + if (m_NeedOnSourceBegin) { + if (x_OnEvent(eRR_Event_SourceBegin) == eRR_EventAction_Stop) { + // Note: there is no need to call eRR_Event_SourceEnd. When an + // upper level function gets an end iterator, it calls + // the eRR_Event_SourceEnd. + return false; // soft end iterator + } + } + } + + m_RawDataAvailable = false; + m_CurrentRow.x_OnFreshRead(); + + if (m_DataSource.m_Stream->bad() || + (m_DataSource.m_Stream->fail() && !m_DataSource.m_Stream->eof())) { + switch ( x_OnEvent(eRR_Event_SourceError) ) { + case eRR_EventAction_Stop: + return false; + case eRR_EventAction_Continue: + // Note: if traits return eRR_EventAction_Continue without + // switching the underlying data source or repairing the + // current stream then an infinite loop is possible + continue; + case eRR_EventAction_Default: + default: + NCBI_THROW2(CRowReaderException, eStreamFailure, + "Input stream failed before reaching the end", + x_GetContextClone()); + } + } + + m_CurrentRowPos = NcbiStreamposToInt8(m_DataSource.m_Stream->tellg()); + + try { + *phys_lines_read = m_Traits.ReadRowData(*m_DataSource.m_Stream, + &m_CurrentRow.m_RawData); + } catch (const CException& exc) { + NCBI_RETHROW2(exc, CRowReaderException, eRowDataReading, + "Reading row data error", x_GetContextClone()); + } catch (const exception& exc) { + NCBI_THROW2(CRowReaderException, eRowDataReading, exc.what(), + x_GetContextClone()); + } catch (...) { + NCBI_THROW2(CRowReaderException, eRowDataReading, + "Unknown reading row data error", x_GetContextClone()); + } + + m_RawDataAvailable = true; + return bool(*m_DataSource.m_Stream); + } +} + + +template +void CRowReader::x_ReadNextRow(void) +{ + if (m_NeedOnSourceBegin && m_NextDataSource.m_Stream == nullptr) { + m_CurrentRowPos = NcbiStreamposToInt8(m_DataSource.m_Stream->tellg()); + + try { + if (x_OnEvent(eRR_Event_SourceBegin) == eRR_EventAction_Stop) { + x_ResetToEnd(); + if (x_OnEvent(eRR_Event_SourceEnd) == eRR_EventAction_Stop) { + x_ResetToEnd(); + return; + } + } + } catch (...) { + x_ResetToEnd(); + throw; + } + } + + ERR_Action action = eRR_Interrupt; + size_t phys_lines_read; + + for (;;) { + m_AtEnd = false; + for (;;) { + try { + if (!x_GetRowData(&phys_lines_read)) + break; + } catch (...) { + // The x_GetRowData() can also generate an exception... + x_ResetToEnd(); + throw; + } + x_UpdateCurrentLineNo(phys_lines_read); + + // Call the user OnNextLine(). The line may need to be skipped + // or the stream processing needs to be interrupted. + try { + action = m_Traits.OnNextLine(m_CurrentRow.m_RawData); + + if (action == eRR_Skip) + continue; + if (action == eRR_Interrupt) { + break; // Leads to a 'soft end' return + } + + m_CurrentRow.m_RowType = CRR_Util::ActionToRowType(action); + + if (action == eRR_Continue_Data) { + // Need to do tokenize + m_Tokens.clear(); + action = m_Traits.Tokenize(m_CurrentRow.m_RawData, + m_Tokens); + if (action == eRR_Skip) + continue; + if (action == eRR_Interrupt) { + break; // Leads to a 'soft end' return + } + if (action != eRR_Continue_Data) { + NCBI_THROW2(CRowReaderException, + eInvalidAction, "Invalid action " + + CRR_Util::ERR_ActionToString(action) + + " in response to the Tokenize() call.", + nullptr); + } + + // The current row fields vector content is reused so + // adjust it to a new size + m_CurrentRow.x_AdjustFieldsSize(m_Tokens.size()); + + // Need to translate + for (TFieldNo field_index = 0; + field_index < m_Tokens.size(); ++field_index) { + CRR_Field& current_field = + m_CurrentRow.m_Fields[field_index]; + + switch (m_Traits.Translate( + field_index, m_Tokens[field_index], + current_field.m_TranslatedValue)) { + case eRR_UseOriginal: + current_field.m_IsNull = false; + current_field.m_Translated = false; + break; + case eRR_Translated: + current_field.m_IsNull = false; + current_field.m_Translated = true; + break; + case eRR_Null: + current_field.m_IsNull = true; + current_field.m_Translated = false; + } + current_field.m_OriginalData = m_Tokens[field_index]; + current_field.m_RowReader = this; + } + } + } catch (CRowReaderException& exc) { + exc.SetContext(x_GetContextClone()); + x_ResetToEnd(); + throw exc; + } catch (const CException& exc) { + CRR_Context* ctxt = x_GetContextClone(); + x_ResetToEnd(); + NCBI_RETHROW2(exc, CRowReaderException, + eLineProcessing, "Error processing line", ctxt); + } catch (const exception& exc) { + CRR_Context* ctxt = x_GetContextClone(); + x_ResetToEnd(); + NCBI_THROW2(CRowReaderException, eLineProcessing, exc.what(), + ctxt); + } catch (...) { + CRR_Context* ctxt = x_GetContextClone(); + x_ResetToEnd(); + NCBI_THROW2(CRowReaderException, eLineProcessing, + "Unknown line processing error", ctxt); + } + + // Data for an iterator has been prepared + return; + } + + m_AtEnd = true; + + try { + if (m_NeedOnSourceEnd) { + if (x_OnEvent(eRR_Event_SourceEnd) == eRR_EventAction_Stop) { + x_ResetToEnd(); + return; + } + } + } catch (...) { + // The x_OnEvent() has already attached the proper context to the + // generated exception so the only thing to to is to reset the + // stream state. + x_ResetToEnd(); + throw; + } + + x_ResetToEnd(); + + // Test if there was a source switch in the Traits::onEvent(...) call. + // If there was then we continue reading. + if (m_NextDataSource.m_Stream == nullptr) + return; + } +} + + +template +void CRowReader::x_OpenFile(SRR_SourceInfo& stream_info) +{ + ios_base::openmode open_mode = ios_base::in; + if (m_Traits.GetFlags() | fRR_OpenFile_AsBinary) + open_mode |= ios_base::binary; + stream_info.m_Stream = new CNcbiIfstream(stream_info.m_Sourcename.c_str(), + open_mode); + stream_info.m_StreamOwner = true; +} + + +template +void CRowReader::x_Reset(void) +{ + m_LinesAlreadyRead = false; + m_RawDataAvailable = false; + m_CurrentLineNo = 0; + m_PreviousPhysLinesRead = 0; + m_CurrentRowPos = 0; +} + + +template +void CRowReader::x_ResetToEnd(void) +{ + // Resetting to end happens in a few cases: + // - there was a normal end of the iterating over the rows + // - there was an exception in the traits calls + // - the traits instructed to stop the process + // In all these cases the row reader is reset to the original state and no + // data are available via iterators even if they were stored previously. + m_AtEnd = true; + m_Validation = false; + m_NeedOnSourceEnd = false; + m_NeedOnSourceBegin = true; + x_Reset(); + m_CurrentRow.x_OnFreshRead(); +} + + +template +CRR_Context* CRowReader::x_GetContextClone(void) +{ + // When a traits callback generates an exception, a context is required + // to attach it to a CRowReaderException. The context generation may + // generate an exception in turn... + try { + return m_Traits.GetContext(GetBasicContext()).Clone(); + } catch (const CException& exc) { + ERR_POST("Exception while getting traits context: " << exc.what()); + return GetBasicContext().Clone(); + } catch (const exception& exc) { + ERR_POST("Exception while getting traits context: " << exc.what()); + return GetBasicContext().Clone(); + } catch (...) { + ERR_POST("Unknown exception while getting traits context"); + return GetBasicContext().Clone(); + } +} + + +template +void CRowReader::x_UpdateCurrentLineNo(size_t phys_lines_read) +{ + if (m_LinesAlreadyRead) + m_CurrentLineNo += m_PreviousPhysLinesRead; + else + m_LinesAlreadyRead = true; + m_PreviousPhysLinesRead = phys_lines_read; +} + + +template +ERR_EventAction CRowReader::x_OnEvent(ERR_Event event) +{ + switch (event) { + case eRR_Event_SourceBegin: + m_NeedOnSourceEnd = true; + m_NeedOnSourceBegin = false; + break; + case eRR_Event_SourceEnd: + m_NeedOnSourceEnd = false; + m_NeedOnSourceBegin = true; + break; + default: ; + } + + try { + ERR_EventMode event_mode = eRR_EventMode_Iterating; + if (m_Validation) + event_mode = eRR_EventMode_Validating; + return m_Traits.OnEvent(event, event_mode); + } catch (const CException& exc) { + NCBI_RETHROW2(exc, CRowReaderException, eTraitsOnEvent, + "Traits error in handling the " + + CRR_Util::ERR_EventToString(event) + " event", + x_GetContextClone()); + } catch (const exception& exc) { + NCBI_THROW2(CRowReaderException, eTraitsOnEvent, exc.what(), + x_GetContextClone()); + } catch (...) { + NCBI_THROW2(CRowReaderException, eTraitsOnEvent, + "Unknown traits error in handling the " + + CRR_Util::ERR_EventToString(event) + " event", + x_GetContextClone()); + } +} + + +// End of the CRowReader implementation + +// Begin of the CRowReader::CRowIterator implementation + +template +const CRR_Field& +CRowReader::CRowIterator::operator[](TFieldNo field) const +{ + x_CheckFieldAccess(); + return m_RowReader->m_CurrentRow[field]; +} + + +template +const CRR_Field& +CRowReader::CRowIterator::operator[](CTempString field) const +{ + x_CheckFieldAccess(); + return m_RowReader->m_CurrentRow[field]; +} + + +template +CRR_Row& +CRowReader::CRowIterator::operator* (void) const +{ + x_CheckDereferencing(); + return m_RowReader->m_CurrentRow; +} + + +template +CRR_Row* +CRowReader::CRowIterator::operator->(void) const +{ + x_CheckDereferencing(); + return &m_RowReader->m_CurrentRow; +} + + +template +bool +CRowReader::CRowIterator::operator== +(const CRowIterator& i) const +{ + _ASSERT(m_RowReader == i.m_RowReader); + _ASSERT(m_IsEndIter || i.m_IsEndIter); + + if (m_RowReader != i.m_RowReader) + return false; + + if (!m_IsEndIter && !i.m_IsEndIter) + NCBI_THROW2(CRowReaderException, eNonEndIteratorCompare, + "Comparing two non end iterators is prohibited", nullptr); + + if (m_IsEndIter && i.m_IsEndIter) + return true; + + if ( m_IsEndIter ) + return i.m_RowReader->m_AtEnd + && (i.m_RowReader->m_NextDataSource.m_Stream == nullptr); + + return m_RowReader->m_AtEnd + && (m_RowReader->m_NextDataSource.m_Stream == nullptr); +} + + +template +bool +CRowReader::CRowIterator::operator!= +(const CRowIterator& end_iterator) const +{ + return !operator==(end_iterator); +} + + +template +CRowReader::CRowIterator::CRowIterator(const CRowIterator& i) + : m_RowReader(i.m_RowReader), m_IsEndIter(i.m_IsEndIter) +{} + + +template +CRowReader::CRowIterator::~CRowIterator() +{} + + +template +typename CRowReader::CRowIterator& +CRowReader::CRowIterator::operator=(const CRowIterator& i) +{ + m_RowReader = i.m_RowReader; + m_IsEndIter = i.m_IsEndIter; + return *this; +} + + +template +typename CRowReader::CRowIterator& +CRowReader::CRowIterator::operator++(void) +{ + x_CheckAdvancing(); + m_RowReader->x_ReadNextRow(); + return *this; +} + + +template +CRowReader::CRowIterator::CRowIterator( + CRowReader* s, + bool is_end) : + m_RowReader(s), m_IsEndIter(is_end) +{} + + +// Needed for the constness of the CRowReader::end() call +template +CRowReader::CRowIterator::CRowIterator( + const CRowReader* s, + bool is_end) : + m_RowReader(const_cast*>(s)), + m_IsEndIter(is_end) +{} + + +template +void CRowReader::CRowIterator::x_CheckDereferencing(void) const +{ + if (m_RowReader->m_Validation) + NCBI_THROW2(CRowReaderException, eIteratorWhileValidating, + "It is prohibited to use iterators " + "during the stream validation", nullptr); + if (m_IsEndIter || m_RowReader->m_AtEnd) + NCBI_THROW2(CRowReaderException, eDereferencingEndIterator, + "Dereferencing end iterator is prohibited", nullptr); + if (!m_RowReader->m_RawDataAvailable) + NCBI_THROW2(CRowReaderException, eDereferencingNoDataIterator, + "Dereferencing iterator when no data is available", + nullptr); +} + + +template +void CRowReader::CRowIterator::x_CheckAdvancing(void) const +{ + if (m_RowReader->m_Validation) + NCBI_THROW2(CRowReaderException, eIteratorWhileValidating, + "It is prohibited to use iterators " + "during the stream validation", nullptr); + if (m_IsEndIter || + (m_RowReader->m_AtEnd && m_RowReader->m_NextDataSource.m_Stream == nullptr)) + NCBI_THROW2(CRowReaderException, eAdvancingEndIterator, + "Advancing end iterator is prohibited", nullptr); +} + + +template +void CRowReader::CRowIterator::x_CheckFieldAccess(void) const +{ + if (m_RowReader->m_Validation) + NCBI_THROW2(CRowReaderException, eIteratorWhileValidating, + "It is prohibited to use iterators " + "during the stream validation", nullptr); + if (m_IsEndIter || m_RowReader->m_AtEnd) + NCBI_THROW2(CRowReaderException, eEndIteratorRowAccess, + "Accessing row field via end iterator", nullptr); +} + +// End of the CRowReader::CRowIterator implementation + + +END_NCBI_SCOPE + +#endif /* UTIL___ROW_READER__HPP */ diff --git a/c++/include/util/row_reader.inl b/c++/include/util/row_reader.inl new file mode 100644 index 00000000..30c75418 --- /dev/null +++ b/c++/include/util/row_reader.inl @@ -0,0 +1,782 @@ +#ifndef UTIL___ROW_READER__INL +#define UTIL___ROW_READER__INL + +/* $Id: row_reader.inl 539183 2017-06-19 17:23:17Z ivanov $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Authors: Design and advice - Denis Vakatov +* Implementation and critique - Sergey Satskiy +* +* Credits: Alex Astashyn +* (GetFieldValueConverted) +* +* File Description: +* CRowReader utility types, classes, functions +** =========================================================================== +*/ + + +#ifndef UTIL___ROW_READER_INCLUDE__INL +# error "The row_reader.inl must only be included in row_reader.hpp" +#endif + + +/// Delimited stream traits use the ERR_Action members to instruct what should +/// be done next. These values are returned by various trait callbacks. +enum ERR_Action { + /// Skip this line + eRR_Skip, + /// Continue processing this line, in full + eRR_Continue_Data, + /// Continue processing this line but skip Tokenize() and Translate() + /// @note + /// Not allowed for Tokenize() and Translate() returns + eRR_Continue_Comment, + /// Continue processing this line but skip Tokenize() and Translate() + /// @note + /// Not allowed for Tokenize() and Translate() returns + eRR_Continue_Metadata, + /// Continue processing this line but skip Tokenize() and Translate() + /// @note + /// not allowed for Tokenize() and Translate() returns + eRR_Continue_Invalid, + /// Stop processing the stream + eRR_Interrupt +}; + + +/// The Translate() callback result. It is used to translate field values. +enum ERR_TranslationResult { + eRR_UseOriginal, ///< No translation done + eRR_Translated, ///< The value has been translated to another string + eRR_Null ///< The value has been translated to NULL +}; + + + +/// Miscellaneous trait-specific flags +/// It is used when a row stream should be built on a file. The file will be +/// opened with the mode provided by the traits, see +/// TTraitsFlags GetFlags(void) const +/// member. +enum ERR_TraitsFlags { + fRR_OpenFile_AsBinary = (0 << 1), ///< open file in a binary mode + fRR_Default = 0 ///< open file in a text mode +}; +typedef int TTraitsFlags; ///< Bit-wise OR of ERR_TraitsFlags + + +/// CRowReader passes such events to the Traits via OnEvent() callback +enum ERR_Event { + eRR_Event_SourceBegin, ///< Data source has started or been switched + ///< (no reads yet though). + eRR_Event_SourceEnd, ///< Data source has hit EOF + eRR_Event_SourceError ///< Data source has hit an error on read +}; + + +/// Indicate whether the "ERR_Event" event (passed to the OnEvent() callback) +/// occured during regular read vs during validation +enum ERR_EventMode { + eRR_EventMode_Iterating, ///< We are iterating through the rows + eRR_EventMode_Validating ///< We are performing data validation +}; + + +/// How to react to the potentially disruptive events +/// @sa OnEvent() +enum ERR_EventAction { + eRR_EventAction_Default, ///< Do some default action + eRR_EventAction_Stop, ///< Stop further processing + eRR_EventAction_Continue ///< Resume processing +}; + + +/// The class represents the current delimited row stream context +class CRR_Context +{ +public: + virtual string Serialize() const + { + string context = "Row reader context: "; + if ( !m_SourceName.empty() ) + context += "Source name: " + m_SourceName + "; "; + + if (m_LinesAlreadyRead) { + context += "Last read line position in the stream: " + + NStr::NumericToString(m_CurrentLinePos) + "; " + "Last read line number: " + + NStr::NumericToString(m_CurrentLineNo) + "; "; + } else { + if (!m_ReachedEnd) + context += "Position in the stream: " + + NStr::NumericToString(m_CurrentLinePos) + "; " + "No lines read yet; "; + } + + if (m_RawDataAvailable) + context += "Raw line data: '" + m_RawData + "'; "; + else + context += "Raw line data are not available; "; + + if (m_ReachedEnd) + context += "Stream has reached end"; + else + context += "Stream has not reached end yet"; + return context; + } + + virtual ~CRR_Context() + {} + + CRR_Context() : + m_LinesAlreadyRead(false), + m_CurrentLineNo(0), m_CurrentLinePos(0), + m_RawDataAvailable(false), + m_ReachedEnd(false) + {} + + CRR_Context(const string& sourcename, + bool lines_already_read, + TLineNo line_no, + TStreamPos current_line_pos, + bool raw_data_available, + const string& raw_data, + bool reached_end) : + m_SourceName(sourcename), m_LinesAlreadyRead(lines_already_read), + m_CurrentLineNo(line_no), m_CurrentLinePos(current_line_pos), + m_RawDataAvailable(raw_data_available), m_RawData(raw_data), + m_ReachedEnd(reached_end) + {} + + // Deriving classes must implement their own version of this member to + // have the exceptions working properly + virtual CRR_Context* Clone(void) const + { + return new CRR_Context(m_SourceName, m_LinesAlreadyRead, + m_CurrentLineNo, m_CurrentLinePos, + m_RawDataAvailable, m_RawData, + m_ReachedEnd); + } + +public: + /// Name of the data source, such as: + /// - file name if the stream was constructed on a file using SetDataSource() + /// - URL if the stream was constructed on some other resource + /// - "User Stream" stream was passed in using SetDataSource() + string m_SourceName; + + // true if at least one line has been successfully read from the stream + bool m_LinesAlreadyRead; + TLineNo m_CurrentLineNo; // 0-based + TStreamPos m_CurrentLinePos; // 0-based + + // true if the raw data has been read successfully + bool m_RawDataAvailable; + string m_RawData; + + bool m_ReachedEnd; +}; + + +/// Exception to be used throughout API +class CRowReaderException : public CException +{ +public: + enum EErrCode { + eUnexpectedRowType, + eStreamFailure, + eFieldNoNotFound, + eDereferencingEndIterator, + eAdvancingEndIterator, + eDereferencingNoDataIterator, + eFileNotFound, + eNoReadPermissions, + eInvalidAction, + eLineProcessing, + eEndIteratorRowAccess, + eFieldNoOutOfRange, + eFieldAccess, + eFieldNameNotFound, + eFieldMetaInfoAccess, + eFieldConvert, + eNullField, + eValidating, + eNonEndIteratorCompare, + eIteratorWhileValidating, + eRowDataReading, + eTraitsOnEvent, + eFieldValueValidation + }; + + CRowReaderException( + const CDiagCompileInfo& info, + const CException* prev_exception, EErrCode err_code, + const string& message, CRR_Context* ctxt, + EDiagSev severity = eDiag_Error) : + CException(info, prev_exception, message, severity), + m_Context(ctxt) + NCBI_EXCEPTION_DEFAULT_IMPLEMENTATION(CRowReaderException, CException); + + virtual const char * GetErrCodeString(void) const + { + switch (GetErrCode()) { + case eUnexpectedRowType: + return "eUnexpectedRowType"; + case eStreamFailure: + return "eStreamFailure"; + case eFieldNoNotFound: + return "eFieldNoNotFound"; + case eDereferencingEndIterator: + return "eDereferencingEndIterator"; + case eAdvancingEndIterator: + return "eAdvancingEndIterator"; + case eDereferencingNoDataIterator: + return "eDereferencingNoDataIterator"; + case eFileNotFound: + return "eFileNotFound"; + case eNoReadPermissions: + return "eNoReadPermissions"; + case eInvalidAction: + return "eInvalidAction"; + case eLineProcessing: + return "eLineProcessing"; + case eEndIteratorRowAccess: + return "eEndIteratorRowAccess"; + case eFieldNoOutOfRange: + return "eFieldNoOutOfRange"; + case eFieldAccess: + return "eFieldAccess"; + case eFieldNameNotFound: + return "eFieldNameNotFound"; + case eFieldMetaInfoAccess: + return "eFieldMetaInfoAccess"; + case eFieldConvert: + return "eFieldConvert"; + case eNullField: + return "eNullField"; + case eValidating: + return "eValidating"; + case eNonEndIteratorCompare: + return "eNonEndIteratorCompare"; + case eIteratorWhileValidating: + return "eIteratorWhileValidating"; + case eRowDataReading: + return "eRowDataReading"; + case eTraitsOnEvent: + return "eTraitsOnEvent"; + case eFieldValueValidation: + return "eFieldValueValidation"; + default: + return CException::GetErrCodeString(); + } + } + + virtual void ReportExtra(ostream& out) const + { + if (m_Context) + out << m_Context->Serialize(); + else + out << "No context available"; + } + +public: + CRR_Context* GetContext(void) const + { + return m_Context.get(); + } + + void SetContext(CRR_Context* ctxt) + { + m_Context.reset(ctxt); + } + +protected: + virtual void x_Assign(const CException& src) + { + CException::x_Assign(src); + + const CRowReaderException& other = + dynamic_cast(src); + + if (other.m_Context) + m_Context.reset(other.m_Context->Clone()); + else + m_Context.reset(nullptr); + } + +private: + unique_ptr m_Context; +}; + + + + +// Utility class merely for a scope +class CRR_Util +{ +public: + // Converts a callback provided action to a string + static string ERR_ActionToString(ERR_Action action) + { + switch (action) { + case eRR_Skip: return "eRR_Skip"; + case eRR_Continue_Data: return "eRR_Continue_Data"; + case eRR_Continue_Comment: return "eRR_Continue_Comment"; + case eRR_Continue_Metadata: return "eRR_Continue_Metadata"; + case eRR_Continue_Invalid: return "eRR_Continue_Invalid"; + case eRR_Interrupt: return "eRR_Interrupt"; + } + return "unknown"; + } + + // Converts a framework event into a string + static string ERR_EventToString(ERR_Event event) + { + switch (event) { + case eRR_Event_SourceBegin: return "eRR_Event_SourceBegin"; + case eRR_Event_SourceEnd: return "eRR_Event_SourceEnd"; + case eRR_Event_SourceError: return "eRR_Event_SourceError"; + } + return "unknown"; + } + + // Converts a basic field type into a string + static string ERR_FieldTypeToString(ERR_FieldType type) + { + switch (type) { + case eRR_String: return "eRR_String"; + case eRR_Boolean: return "eRR_Boolean"; + case eRR_Integer: return "eRR_Integer"; + case eRR_Double: return "eRR_Double"; + case eRR_DateTime: return "eRR_DateTime"; + } + return "unknown"; + } + + // Converts the callback returned action to a row type + static ERR_RowType ActionToRowType(ERR_Action action) + { + switch (action) { + case eRR_Continue_Data: return eRR_Data; + case eRR_Continue_Comment: return eRR_Comment; + case eRR_Continue_Metadata: return eRR_Metadata; + case eRR_Continue_Invalid: return eRR_Invalid; + default: + NCBI_THROW2(CRowReaderException, eUnexpectedRowType, + "Unexpected action to convert to a row type", + nullptr); + } + } + + // Checks the file existance and read permissions + static void CheckExistanceAndPermissions(const string& sourcename) + { + CFile file(sourcename); + if ( !file.Exists() ) + NCBI_THROW2(CRowReaderException, eFileNotFound, + "File " + sourcename + " is not found", + nullptr); + if ( !file.CheckAccess(CDirEntry::fRead) ) + NCBI_THROW2(CRowReaderException, eNoReadPermissions, + "No read permissions for file " + sourcename, + nullptr); + } + + // Utility functions to implement field value conversions + static void GetFieldValueConverted(const CTempString& str_value, + CTime& converted) + { + converted = CTime(string(str_value.data(), str_value.size())); + } + + static void GetFieldValueConverted(const CTempString& str_value, + string& converted) + { + converted = string(str_value.data(), str_value.size()); + } + + static void GetFieldValueConverted(const CTempString& str_value, + bool& converted) + { + converted = NStr::StringToBool(str_value); + } + + static void GetFieldValueConverted(const CTempString& str_value, + CTempString& converted) + { + converted = str_value; + } + + // Conversion implementation respecting overflow + // and covering all the arithmetic types + template::value>::type> + static void GetFieldValueConverted(const CTempString& str_value, T& converted) + { + errno = 0; + try { + if (!NStr::StringToNumeric(str_value, &converted) + || errno != 0) + throw; + } catch (const CException& exc) { + NCBI_RETHROW2(exc, CRowReaderException, + eFieldConvert, "Cannot convert field value '" + + string(str_value.data(), str_value.size()) + + "' to " + typeid(T).name(), nullptr); + } catch (const exception& exc) { + NCBI_THROW2(CRowReaderException, eFieldConvert, + "Cannot convert field value '" + + string(str_value.data(), str_value.size()) + + "' to " + typeid(T).name() + ": " + + exc.what(), nullptr); + } catch (...) { + NCBI_THROW2(CRowReaderException, eFieldConvert, + "Unknown error while converting field value '" + + string(str_value.data(), str_value.size()) + + "' to " + typeid(T).name(), nullptr); + } + } + + // Validates a few basic type fields + static void ValidateBasicTypeFieldValue(const CTempString& str_value, + ERR_FieldType field_type, + const string& props) + { + try { + switch (field_type) { + case eRR_Boolean: + { + bool converted; + CRR_Util::GetFieldValueConverted(str_value, converted); + } + break; + case eRR_Integer: + { + Int8 converted_int8; + try { + CRR_Util::GetFieldValueConverted(str_value, + converted_int8); + } catch (...) { + Uint8 converted_uint8; + CRR_Util::GetFieldValueConverted(str_value, + converted_uint8); + } + } + break; + case eRR_Double: + { + double converted; + CRR_Util::GetFieldValueConverted(str_value, converted); + } + break; + case eRR_DateTime: + { + CTime(string(str_value.data(), str_value.size()), + props); + } + default: + break; + } + } catch (const CException& exc) { + NCBI_RETHROW2(exc, CRowReaderException, eFieldValueValidation, + "Error validating field value '" + + string(str_value.data(), str_value.size()) + + "' of type " + + CRR_Util::ERR_FieldTypeToString(field_type), + nullptr); + } catch (const exception& exc) { + NCBI_THROW2(CRowReaderException, eFieldValueValidation, + "Error validating field value '" + + string(str_value.data(), str_value.size()) + + "' of type " + + CRR_Util::ERR_FieldTypeToString(field_type) + + ": " + exc.what(), nullptr); + } catch (...) { + NCBI_THROW2(CRowReaderException, eFieldValueValidation, + "Unknown error while validating field value '" + + string(str_value.data(), str_value.size()) + + "' of type " + + CRR_Util::ERR_FieldTypeToString(field_type), nullptr); + } + } +}; + + +// Stores the fields meta information: field names and types +template +class CRR_MetaInfo : public CObject +{ +public: + CRR_MetaInfo() + { + m_FieldsInfo.reserve(64); + } + + CRR_MetaInfo(const CRR_MetaInfo& other) + { + Clear(true); // true -> clears both user and traits provided info + m_FieldNamesIndex = other.m_FieldNamesIndex; + + m_FieldsInfo.reserve(other.m_FieldsInfo.size()); + for (size_t k = 0; k < other.m_FieldsInfo.size(); ++k) { + m_FieldsInfo.push_back(other.m_FieldsInfo[k]); + if (other.m_FieldsInfo[k].m_NameInit != eNotInitialized) { + auto it = m_FieldNamesIndex.find( + *other.m_FieldsInfo[k].m_FieldName); + m_FieldsInfo[k].m_FieldName = &it->first; + } + } + } + +public: + void Clear(bool user_clear) + { + if (user_clear) { + m_FieldsInfo.clear(); + m_FieldNamesIndex.clear(); + return; + } + + // Non-user clear, i.e. the only traits provided meta information + // should be erased. + for (size_t index = 0; index < m_FieldsInfo.size(); ++index) { + if (m_FieldsInfo[index].m_ExtTypeInit == eTraitInitialized) + m_FieldsInfo[index].m_ExtTypeInit = eNotInitialized; + if (m_FieldsInfo[index].m_TypeInit == eTraitInitialized) + m_FieldsInfo[index].m_TypeInit = eNotInitialized; + if (m_FieldsInfo[index].m_NameInit == eTraitInitialized) { + if (x_UpdateNameRef(index) == 1) + m_FieldNamesIndex.erase(*m_FieldsInfo[index].m_FieldName); + m_FieldsInfo[index].m_NameInit = eNotInitialized; + m_FieldsInfo[index].m_FieldName = nullptr; + } + } + } + + void SetFieldName(TFieldNo field, const string& name, + bool user_init) + { + if (field >= m_FieldsInfo.size()) + m_FieldsInfo.resize(field + 1); + + // Traits provided name must be ignored if the user has already set it + if (m_FieldsInfo[field].m_NameInit == eUserInitialized && (!user_init)) + return; + + if (m_FieldsInfo[field].m_NameInit != eNotInitialized) { + if (name == *m_FieldsInfo[field].m_FieldName) { + x_UpdateInitField(&m_FieldsInfo[field].m_NameInit, user_init); + if (user_init) + m_FieldNamesIndex[name] = field; + return; + } + + if (x_UpdateNameRef(field) == 1) + m_FieldNamesIndex.erase(*m_FieldsInfo[field].m_FieldName); + } + + auto inserted = m_FieldNamesIndex.insert(make_pair(name, field)); + m_FieldsInfo[field].m_FieldName = &inserted.first->first; + x_UpdateInitField(&m_FieldsInfo[field].m_NameInit, user_init); + } + + void SetFieldType( + TFieldNo field, + const CRR_FieldType& type, + bool user_init) + { + if (field >= m_FieldsInfo.size()) + m_FieldsInfo.resize(field + 1); + + // Traits provided type must be ignored if the user has already set it + if (m_FieldsInfo[field].m_TypeInit == eUserInitialized && (!user_init)) + return; + + m_FieldsInfo[field].m_FieldType = type; + x_UpdateInitField(&m_FieldsInfo[field].m_TypeInit, user_init); + } + + void SetFieldTypeEx( + TFieldNo field, + const CRR_FieldType& type, + const CRR_FieldType& extended_type, + bool user_init) + { + if (field >= m_FieldsInfo.size()) + m_FieldsInfo.resize(field + 1); + + // Traits provided type must be ignored if the user has already set it. + // To avoid non-synced type updates the extended type is not set + // (updated) either even if it was not initialized. + if (m_FieldsInfo[field].m_TypeInit == eUserInitialized && (!user_init)) + return; + + m_FieldsInfo[field].m_FieldType = type; + m_FieldsInfo[field].m_FieldExtType = extended_type; + + x_UpdateInitField(&m_FieldsInfo[field].m_TypeInit, user_init); + x_UpdateInitField(&m_FieldsInfo[field].m_ExtTypeInit, user_init); + } + + TFieldNo GetFieldIndexByName(const string& field) const + { + auto it = m_FieldNamesIndex.find(field); + if (it == m_FieldNamesIndex.end()) + NCBI_THROW2(CRowReaderException, eFieldNoNotFound, + "Unknown field name '" + field + "'", nullptr); + return it->second; + } + + TFieldNo GetDescribedFieldCount(void) const + { + TFieldNo count = 0; + for (size_t index = 0; index < m_FieldsInfo.size(); ++index) + if (m_FieldsInfo[index].IsInitialized()) + ++count; + return count; + } + +private: + size_t x_UpdateNameRef(TFieldNo field) + { + const string* name_ptr = m_FieldsInfo[field].m_FieldName; + size_t use_count = 0; + TFieldNo candidate = 0; + + for (TFieldNo index = 0; index < m_FieldNamesIndex.size(); ++index) { + if (m_FieldsInfo[index].m_NameInit != eNotInitialized) { + if (m_FieldsInfo[index].m_FieldName == name_ptr) { + ++use_count; + if (index != field) + candidate = index; + } + } + } + + if (use_count > 1) + m_FieldNamesIndex[*name_ptr] = candidate; + return use_count; + } + +private: + friend class CRR_Row; + + enum ERR_FieldMetaInfoInit + { + eNotInitialized = 0, + eTraitInitialized = 1, + eUserInitialized = 2 + }; + + void x_UpdateInitField(ERR_FieldMetaInfoInit* field, bool user_init) + { + if (user_init) + *field = eUserInitialized; + else + *field = eTraitInitialized; + } + + struct SMetainfo + { + SMetainfo() : + m_FieldName(nullptr), + m_NameInit(eNotInitialized), + m_TypeInit(eNotInitialized), + m_ExtTypeInit(eNotInitialized) + {} + + const string * m_FieldName; + CRR_FieldType m_FieldType; + CRR_FieldType m_FieldExtType; + + ERR_FieldMetaInfoInit m_NameInit; + ERR_FieldMetaInfoInit m_TypeInit; + ERR_FieldMetaInfoInit m_ExtTypeInit; + + bool IsInitialized(void) const + { + return (m_NameInit != eNotInitialized) || + (m_TypeInit != eNotInitialized) || + (m_ExtTypeInit != eNotInitialized); + } + }; + + map m_FieldNamesIndex; + vector m_FieldsInfo; +}; + + +// Auxiliary structure to store a current stream info and a next stream info in +// case of SetDataSource() calls +struct SRR_SourceInfo +{ + SRR_SourceInfo(): + m_Stream(nullptr), m_StreamOwner(false) + {} + + SRR_SourceInfo(CNcbiIstream* s, const string& sourcename, bool owner) : + m_Stream(s), m_Sourcename(sourcename), m_StreamOwner(owner) + {} + + ~SRR_SourceInfo() + { + Clear(); + } + + void Clear(void) + { + if (m_StreamOwner) + delete m_Stream; + + m_Stream = nullptr; + m_Sourcename.clear(); + m_StreamOwner = false; + } + + CNcbiIstream* m_Stream; + string m_Sourcename; + bool m_StreamOwner; +}; + + + +/// This macro can be used in the traits class declaration to provide +/// standard typedefs and methods to bind to the traits' "parent stream" +#define RR_TRAITS_PARENT_STREAM(TTraits) \ +public: \ + /* Convenience stream type shorthand */ \ + typedef CRowReader TStreamType; \ +protected: \ + TStreamType& GetMyStream(void) const { return *m_MyStream; } \ +private: \ + friend TStreamType; \ + /* The CRowReader objects calls this function */ \ + void x_SetMyStream(TStreamType* my_stream) { m_MyStream = my_stream; } \ + TStreamType* m_MyStream + + + +#endif /* UTIL___ROW_READER__INL */ diff --git a/c++/include/util/row_reader_base.hpp b/c++/include/util/row_reader_base.hpp new file mode 100644 index 00000000..63922434 --- /dev/null +++ b/c++/include/util/row_reader_base.hpp @@ -0,0 +1,223 @@ +#ifndef UTIL___ROW_READER_BASE__HPP +#define UTIL___ROW_READER_BASE__HPP + +/* $Id: row_reader_base.hpp 539183 2017-06-19 17:23:17Z ivanov $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Authors: Denis Vakatov, Sergey Satskiy +* +* Credits: Alex Astashyn +* (the optimized version of NcbiGetlineEOL) +* +* File Description: +* Implementation of the CRowReaderStream_Base traits. This class can +* be used as a base class for the other traits implementations. +* +* =========================================================================== +*/ + +#include + + +BEGIN_NCBI_SCOPE + +/// General traits implementation recommendations: +/// +/// - Use IMessage API to communicate processing messages, errors and progress +/// to the upper-level code + + +/// Traits base class: +/// - Illustrates and explains the trait's API +/// - Can be used to derive more complex user-defined traits +/// - Does not split a row into fields. Treats the row content as one field. +/// (no header, comments, empty lines, etc.) +class CRowReaderStream_Base +{ +public: + // Can be extended and used in the derived (or alternative) implementations + typedef ERR_FieldType TExtendedFieldType; + + // Can be extended and used in the derived (or alternative) implementations + // Requirement: the TRR_Context must derive from CRR_Context if extended + typedef CRR_Context TRR_Context; + + /// Validation mode + /// Derived traits can override and extend this enum type. + /// @attention The overrides must have eRR_ValidationMode_Default variant! + enum ERR_ValidationMode { + eRR_ValidationMode_Default + }; + + /// Set the validation mode + /// @param validation_mode + /// validation mode + void SetValidationMode(ERR_ValidationMode validation_mode) + {} + + /// Called by CRowReader<>::Validate() for each line + /// @param raw_line + /// current stream line + /// @return + /// Instructions of what to do next e.g. interrupt validation or continue. + /// See ERR_Action in row_reader.inl + ERR_Action Validate(CTempString raw_line, + ERR_FieldValidationMode field_validation_mode) + { return eRR_Skip; } + + /// Called before any other processing of the next read line + /// @param raw_line + /// current stream line + /// @return + /// Instructions of what to do next e.g. interrupt looping or continue. + /// See ERR_Action in row_reader.inl + /// @example + /// return NStr::IsBlank(raw_line) || NStr::StartsWith(raw_line, "#") + /// ? eRR_Skip : eRR_Continue_Data; + ERR_Action OnNextLine(CTempString raw_line) + { return eRR_Continue_Data; } + + /// Tokenize the raw line and put the tokens into the tokens vector + /// @param raw_line + /// A raw line from an input stream + /// @param tokens + /// The storage where tokens should be stored + /// @return + /// Instructions of what to do next e.g. interrupt looping or continue. + /// See ERR_Action in row_reader.inl + ERR_Action Tokenize(const CTempString raw_line, + vector& tokens) + { + tokens.push_back(raw_line); + return eRR_Continue_Data; + } + + /// Translate the column value if necessary + /// usually used for special values such as null, empty, etc + /// @param field_no + /// Field index (zero based) + /// @param raw_value + /// Field raw value + /// @param translated_value + /// The translated value. Used only if "eRR_Translated" is returned. + /// @return + /// Translation action taken + ERR_TranslationResult Translate(TFieldNo field_no, + const CTempString raw_value, + string& translated_value) + { return eRR_UseOriginal; } + + + /// Get trait-specific flags + /// @return + /// Flags which tell how a file should be opened + TTraitsFlags GetFlags(void) const { return fRR_Default; } + + /// Traits can extend the stream CRR_Context the way they need and provide + /// it in this call. The context will be used to throw exceptions. + /// @param stream_ctx + /// Stream basic context. It contains information about a position in the + /// stream, the current line and the current data if so. + /// @return + /// Traits context constructed on the basic stream context. + /// @attention + /// The TRR_Context must derive from CRR_Context and must reimplement + /// x_Assign() member function. If these conditions are not met then the + /// exceptions in the client code may miss some information or the code is + /// not compiled at all. + TRR_Context GetContext(const CRR_Context& stream_ctx) const + { return stream_ctx; } + + + /// Handle potentially disruptive events. + /// Traits e.g. can repair (including resetting the underlying data source + /// using SetDataSource()) the situation described by the event + /// and then return "eRR_EventAction_Continue" + /// @param event + /// An event in the in input stream + /// @param event_mode + /// An event mode (to distinguish if it is a validiation or not) + /// @return + /// Instructions what to do next e.g. stop processing the stream. See + /// ERR_EventAction in row_reader.inl + ERR_EventAction OnEvent(ERR_Event /*event*/, + ERR_EventMode /*event_mode*/) + { return eRR_EventAction_Default; } + + /// Read data for one row. + /// @note + /// One row may consists of several raw lines + /// @param is + /// Input stream to read from + /// @param data + /// String to read to + /// @return + /// Number of raw lines read from the stream + size_t ReadRowData(CNcbiIstream& is, string* data) + { + data->clear(); + + // Optimized version of NcbiGetlineEOL + // This works for \n and \r\n but not for \r, but the latter was used + // in old MacOS which has been obsolete for 15 years. + std::getline(is, *data); + if(!data->empty() && data->back() == '\r') + data->pop_back(); + return 1; + } + + // Standard typedefs and methods to bind to the "parent stream" + RR_TRAITS_PARENT_STREAM(CRowReaderStream_Base); +}; + + + + +///////////////////////////////////////////////////////// +// USAGE +// +// +// +// typedef CRowReader TMyDelimitedStream; +// +// +// CNcbiIfstream my_file("file.tab"); +// TMyDelimitedStream delim_stream(my_file); +// +// +// delim_stream.SetFieldName(1, "one"); +// +// +// for (auto & row : delim_stream) { +// cout << "Value of the first field: " << row["one"] << endl; +// +// // Exception will be generated +// row[1]; +// } + + +END_NCBI_SCOPE + +#endif /* UTIL___ROW_READER_BASE__HPP */ diff --git a/c++/include/util/row_reader_char_delimited.hpp b/c++/include/util/row_reader_char_delimited.hpp new file mode 100644 index 00000000..e5b39c16 --- /dev/null +++ b/c++/include/util/row_reader_char_delimited.hpp @@ -0,0 +1,174 @@ +#ifndef UTIL___ROW_READER_CHAR_DELIMITED__HPP +#define UTIL___ROW_READER_CHAR_DELIMITED__HPP + +/* $Id: row_reader_char_delimited.hpp 532915 2017-04-11 13:32:21Z satskyse $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Authors: Denis Vakatov, Sergey Satskiy +* +* File Description: +* Implementation of the CRowReader<> traits for a single character +* separator between fields in rows. +* +* =========================================================================== +*/ + +#include +#include + + +BEGIN_NCBI_SCOPE + +/// General traits implementation recommendations: +/// +/// - Use IMessage API to communicate processing messages, errors and progress +/// to the upper-level code + + + +/// Trait that describes the very basic character(s) delimited format +/// - No header, comments, empty lines, etc. +/// - Illustrates and explains the trait's API +/// - Can be used to derive more complex user-defined traits +template +class CRowReaderStream_CharDelimited : public CRowReaderStream_Base +{ +public: + CRowReaderStream_CharDelimited() + { + join(Arguments...); + } + + /// Tokenize the raw line and put the tokens into the tokens vector + ERR_Action Tokenize(const CTempString raw_line, + vector& tokens) + { + NStr::Split(raw_line, m_Delimiters, tokens, SplitFlags); + return eRR_Continue_Data; + } + + // The RR_TRAITS_PARENT_STREAM accepts one parameter so the ',' character + // may not appear in its arguments. On the other hand the template has two + // parameters spearated by ',' so a typedef below comes handy. + typedef CRowReaderStream_CharDelimited TSelf; + + // Standard typedefs and methods to bind to the "parent stream" + RR_TRAITS_PARENT_STREAM(TSelf); + +private: + void join(char delim) + { + m_Delimiters += string(1, delim); + } + + template + void join(char delim, Args ... args) + { + m_Delimiters += string(1, delim); + join(args...); + } + + // Delimiters combined into one string + string m_Delimiters; +}; + + + +/// Partial specialization of the CRowReaderStream_CharDelimited<...> template +/// for the case when the data fields are delimited by a single character out +/// of the specified set of characters. +template +class CRowReaderStream_SingleCharDelimited : + public CRowReaderStream_CharDelimited<0, Arguments...> +{ + RR_TRAITS_PARENT_STREAM(CRowReaderStream_SingleCharDelimited); +}; + +/// Partial specialization of the CRowReaderStream_CharDelimited<...> template +/// for the case when the data fields are delimited by one or more characters +/// out of the specified set of characters. +template +class CRowReaderStream_MultiCharDelimited : + public CRowReaderStream_CharDelimited +{ + RR_TRAITS_PARENT_STREAM(CRowReaderStream_MultiCharDelimited); +}; + +/// Partial specialization of the CRowReaderStream_CharDelimited<...> template +/// for the case when the data fields are delimited by the specified string. +template +class CRowReaderStream_StringDelimited : + public CRowReaderStream_CharDelimited +{ + RR_TRAITS_PARENT_STREAM(CRowReaderStream_StringDelimited); +}; + + +/// An example of the traits where the data fields are delimited by single +/// character '\t' +typedef CRowReaderStream_SingleCharDelimited<'\t'> TRowReaderStream_SingleTabDelimited; +/// An example of the traits where the data fields are delimited by single +/// character ' ' +typedef CRowReaderStream_SingleCharDelimited<' '> TRowReaderStream_SingleSpaceDelimited; +/// An example of the traits where the data fields are delimited by single +/// character ',' +typedef CRowReaderStream_SingleCharDelimited<','> TRowReaderStream_SingleCommaDelimited; + +/// An example of the traits where the delimiters are '\t', ' ' and '\v' +typedef CRowReaderStream_MultiCharDelimited<'\t', ' ', '\v'> TRowReaderStream_MultiSpaceDelimited; + +/// An example of the traits where a delimiter is the "***" string +typedef CRowReaderStream_StringDelimited<'*', '*', '*'> TRowReaderStream_ThreeStarDelimited; + + + +///////////////////////////////////////////////////////// +// USAGE +// +// +// +// typedef CRowReader TMyDelimitedStream; +// +// +// CNcbiIfstream my_file("file.tab"); +// TMyDelimitedStream delim_stream(my_file); +// +// +// delim_stream.SetFieldName(1, "one"); +// delim_stream.SetFieldName(2, "two"); +// delim_stream.SetFieldName(3, "three"); +// +// +// for (auto & row : delim_stream) { +// cout << "Value of the first field: " << row["one"] << endl; +// +// // Exception will be generated +// row[4]; +// } + + +END_NCBI_SCOPE + +#endif /* UTIL___ROW_READER_CHAR_DELIMITED__HPP */ diff --git a/c++/include/util/row_reader_excel_csv.hpp b/c++/include/util/row_reader_excel_csv.hpp new file mode 100644 index 00000000..b328f7c7 --- /dev/null +++ b/c++/include/util/row_reader_excel_csv.hpp @@ -0,0 +1,372 @@ +#ifndef UTIL___ROW_READER_EXCEL_CSV__HPP +#define UTIL___ROW_READER_EXCEL_CSV__HPP + +/* $Id: row_reader_excel_csv.hpp 539640 2017-06-26 13:22:11Z ivanov $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Authors: Denis Vakatov, Sergey Satskiy +* +* File Description: +* Implementation of the CRowReader<> traits for MS EXCEL CSV +* +* =========================================================================== +*/ + +#include + + +BEGIN_NCBI_SCOPE + + +/// Note 1: Empty rows are allowed and treated as 0 fields rows +/// Note 2: Both CRLF and LF are allowed +/// Note 3: Number of fields is not enforced +/// Note 4: There is no formal MS Excel CSV spec. So the implementation is +/// based on experiments made on MS Excel 2013. +/// See the description in JIRA: CXX-9221 +/// Note 5: Two field cases in a data source +/// - empty, i.e. ,, +/// - "", i.e. ,"", +/// are translated to a Null field +/// Note 6: trailing Null fields in a data source are stripped + + +const CTempString kNullFieldRepresentation = CTempString("\"\"", 2); + + +/// MS Excel CSV traits. +class CRowReaderStream_Excel_CSV : public TRowReaderStream_SingleCommaDelimited +{ +public: + CRowReaderStream_Excel_CSV() + { + m_LineSeparator.reserve(2); + m_PreviousLineSeparator.reserve(2); + } + + // It could be more than one raw line in one row + size_t ReadRowData(CNcbiIstream& is, string* data) + { + data->clear(); + m_Tokens.clear(); + + size_t current_index= 0; + size_t token_begin_index = 0; + size_t lines_read = 0; + bool in_quotes = false; + for (;;) { + x_ReadOneLine(is, data, lines_read > 0); + ++lines_read; + + while (current_index < data->size()) { + auto current_char = (*data)[current_index]; + if (current_char == ',') { + if (!in_quotes) { + m_Tokens.emplace_back(token_begin_index); + token_begin_index = current_index + 1; + } + } else if (current_char == '"') { + if (token_begin_index == current_index) { + in_quotes = true; + } else { + if (in_quotes) { + if (current_index + 1 < data->size() && + (*data)[current_index + 1] == '"') { + ++current_index; + } else { + in_quotes = false; + } + } + } + } + + ++current_index; + } + + if (!in_quotes) + break; + + // Here: need to read one more line because of the double quotes. + // So check if we still can read. + if (!bool(is)) + break; + } + + m_Tokens.push_back(token_begin_index); + return lines_read; + } + + ERR_Action OnNextLine(CTempString raw_line) + { + return eRR_Continue_Data; + } + + + // The tokenization is actually done in the ReadRowData() member + ERR_Action Tokenize(const CTempString raw_line, + vector& tokens) + { + // Special case in accordance with CXX-9221: empty line => no fields + if (!raw_line.empty()) { + size_t field_size; + for (TFieldNo field_no = 0; + field_no < m_Tokens.size(); ++field_no) { + if (field_no + 1 < m_Tokens.size()) + field_size = m_Tokens[field_no + 1] - m_Tokens[field_no] - 1; + else + field_size = raw_line.size() - m_Tokens[field_no]; + tokens.emplace_back(raw_line.data() + m_Tokens[field_no], + field_size); + } + + x_StripTrailingNullFields(tokens); + } + return eRR_Continue_Data; + } + + ERR_Action Validate(CTempString raw_line, + ERR_FieldValidationMode field_validation_mode) + { + if (field_validation_mode == eRR_NoFieldValidation) + return eRR_Skip; + if (m_FieldsToValidate.empty()) + return eRR_Skip; + + if (raw_line.empty()) + return eRR_Skip; + + // Here: the field values need to be validated and there is some type + // information + m_ValidationTokens.clear(); + ERR_Action action = this->Tokenize(raw_line, m_ValidationTokens); + + if (action == eRR_Skip) + return eRR_Skip; + + for (const auto& info : m_FieldsToValidate) { + if (info.first < m_Tokens.size()) { + string translated; + ERR_TranslationResult translation_result = + this->Translate(info.first, m_ValidationTokens[info.first], + translated); + if (translation_result == eRR_UseOriginal) { + CRR_Util::ValidateBasicTypeFieldValue( + m_ValidationTokens[info.first], + info.second.first, info.second.second); + } else { + CRR_Util::ValidateBasicTypeFieldValue( + translated, + info.second.first, info.second.second); + } + } + } + + return eRR_Skip; + } + + ERR_TranslationResult Translate(TFieldNo field_no, + const CTempString raw_value, + string& translated_value) + { + if (x_IsNull(raw_value)) + return eRR_Null; + + if (raw_value[0] == '=') { + size_t dbl_quote_cnt = 0; + for (size_t index = 0; index < raw_value.size(); ++index) + if (raw_value[index] == '"') + ++dbl_quote_cnt; + + if (dbl_quote_cnt == 0) { + translated_value = string(raw_value.data() + 1, + raw_value.size() - 1); + return eRR_Translated; + } + + // Here: there are " in the field. They may need to be stripped + // together with = if: + // - " follows = immediately + // - " is the last character in a field + // - there is an even number of " + // If so then "" need to be translated into " inside the field + // as well + if (dbl_quote_cnt % 2 == 0) { + if (raw_value[1] == '"' && + raw_value[raw_value.size() - 1] == '"') { + // Balanced double quote and poperly surround the field + // value => strip the = and surrounding " plus replace + // "" with " + translated_value = string(raw_value.data() + 2, + raw_value.size() - 3); + NStr::ReplaceInPlace(translated_value, "\"\"", "\""); + return eRR_Translated; + } + } + + // Non balanced double quotes or they are not surrounding the + // value after = + // There is no translation for this case + return eRR_UseOriginal; + } + + if (raw_value[0] == '"') { + size_t match_index = 1; + for (; match_index < raw_value.size(); ++match_index) { + if (raw_value[match_index] == '"') { + if (match_index + 1< raw_value.size() && + raw_value[match_index + 1] == '"') + ++match_index; + else + break; + } + } + + // Here: match_index points beyond of the field or to a + // matching " + if (match_index < raw_value.size()) { + // matching " found + translated_value = string(raw_value.data() + 1, + match_index - 1); + NStr::ReplaceInPlace(translated_value, "\"\"", "\""); + if (match_index < raw_value.size() - 1) { + // tail of the field needs to ba attached as is + translated_value.append( + raw_value.data() + match_index + 1, + raw_value.size() - match_index - 1); + } + } else { + // Unbalanced " case + translated_value = string(raw_value.data() + 1, + raw_value.size() - 1); + } + + // This could be a case with a leading = which may need to be + // stripped as well... + if (!translated_value.empty()) { + if (translated_value[0] == '=') { + size_t dbl_quote_cnt = 0; + for (size_t index = 0; + index < translated_value.size(); ++index) + if (translated_value[index] == '"') + ++dbl_quote_cnt; + + if (dbl_quote_cnt > 0 && (dbl_quote_cnt % 2 == 0)) { + if (translated_value[1] == '"' && + translated_value[translated_value.size() - 1] == '"') { + translated_value = translated_value.substr(2, translated_value.size() - 3); + } + } + } + } + + return eRR_Translated; + } + return eRR_UseOriginal; + } + + ERR_EventAction OnEvent(ERR_Event event, + ERR_EventMode event_mode) + { + switch (event) { + case eRR_Event_SourceBegin: + GetMyStream().x_ClearTraitsProvidedFieldsInfo(); + + if (event_mode == eRR_EventMode_Validating) + x_GetFieldTypesToValidate(); + + // fall through + case eRR_Event_SourceEnd: + case eRR_Event_SourceError: + default: + ; + } + return eRR_EventAction_Default; + } + +private: + void x_ReadOneLine(CNcbiIstream& is, string* data, bool joining) + { + m_RawLine.clear(); + std::getline(is, m_RawLine); + m_LineSeparator = "\n"; + if(!m_RawLine.empty() && m_RawLine.back() == '\r') { + m_RawLine.pop_back(); + m_LineSeparator = "\r\n"; + } + + if (joining) + data->append(m_PreviousLineSeparator); + data->append(m_RawLine); + + m_PreviousLineSeparator = m_LineSeparator; + } + + void x_GetFieldTypesToValidate(void) + { + m_FieldsToValidate.clear(); + for (const auto& info : GetMyStream().GetFieldsMetaInfo()) { + if (info.is_type_initialized) { + auto field_type = info.type.GetType(); + if (field_type == eRR_Boolean || field_type == eRR_Integer || + field_type == eRR_Double || field_type == eRR_DateTime) + m_FieldsToValidate[info.field_no] = + make_pair(field_type, info.type.GetProps()); + } + } + } + + bool x_IsNull(const CTempString& raw_field_value) + { + return raw_field_value.empty() || + (raw_field_value == kNullFieldRepresentation); + } + + void x_StripTrailingNullFields(vector& tokens) + { + while (!tokens.empty()) { + if (x_IsNull(tokens.back())) + tokens.pop_back(); + else + break; + } + } + +private: + vector m_Tokens; + string m_LineSeparator; + string m_PreviousLineSeparator; + string m_RawLine; + + map> m_FieldsToValidate; + vector m_ValidationTokens; + + RR_TRAITS_PARENT_STREAM(CRowReaderStream_Excel_CSV); +}; + + + +END_NCBI_SCOPE + +#endif /* UTIL___ROW_READER_EXCEL_CSV__HPP */ diff --git a/c++/include/util/row_reader_iana_csv.hpp b/c++/include/util/row_reader_iana_csv.hpp new file mode 100644 index 00000000..018a85e5 --- /dev/null +++ b/c++/include/util/row_reader_iana_csv.hpp @@ -0,0 +1,361 @@ +#ifndef UTIL___ROW_READER_IANA_CSV__HPP +#define UTIL___ROW_READER_IANA_CSV__HPP + +/* $Id: row_reader_iana_csv.hpp 539183 2017-06-19 17:23:17Z ivanov $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Authors: Denis Vakatov, Sergey Satskiy +* +* File Description: +* Implementation of the CRowReader<> traits for IANA CSV +* https://tools.ietf.org/html/rfc4180 +* +* =========================================================================== +*/ + +#include + + +BEGIN_NCBI_SCOPE + + +/// Note 1: Empty rows are allowed and silently skipped +/// Note 2: Both CRLF and LF are allowed +/// Note 3: Number of fields is not enforced +/// Note 4: The row with names does not appear in the iteration loop + + +/// Exception specific to IANA CSV sources +class CCRowReaderStream_IANA_CSV_Exception : public CException +{ +public: + enum EErrCode { + eUnbalancedDoubleQuote, + eUnexpectedDoubleQuote + }; + + virtual const char * GetErrCodeString(void) const + { + switch (GetErrCode()) { + case eUnbalancedDoubleQuote: + return "eUnbalancedDoubleQuote"; + case eUnexpectedDoubleQuote: + return "eUnexpectedDoubleQuote"; + default: + return CException::GetErrCodeString(); + } + } + + NCBI_EXCEPTION_DEFAULT(CCRowReaderStream_IANA_CSV_Exception, CException); +}; + + + +/// IANA CSV traits. +/// It follows the specs at: +/// https://tools.ietf.org/html/rfc4180 +/// @note by default the source is considered as the one which has a header +/// line. If your source does not features a header then use the +/// CRowReaderStream_IANA_CSV_no_header traits or use the SetHasHeader() +/// member to switch between modes at runtime. +class CRowReaderStream_IANA_CSV : public TRowReaderStream_SingleCommaDelimited +{ +public: + CRowReaderStream_IANA_CSV() : + m_HasHeader(true) + { + m_LineSeparator.reserve(2); + m_PreviousLineSeparator.reserve(2); + } + + // It could be more than one raw line in one row + size_t ReadRowData(CNcbiIstream& is, string* data) + { + data->clear(); + m_Tokens.clear(); + + size_t current_index= 0; + size_t token_begin_index = 0; + size_t lines_read = 0; + bool in_quotes = false; + for (;;) { + x_ReadOneLine(is, data, lines_read > 0); + ++lines_read; + + while (current_index < data->size()) { + auto current_char = (*data)[current_index]; + if (current_char == ',') { + if (!in_quotes) { + m_Tokens.emplace_back(token_begin_index); + token_begin_index = current_index + 1; + } + } else if (current_char == '"') { + if (!in_quotes && token_begin_index != current_index) { + NCBI_THROW(CCRowReaderStream_IANA_CSV_Exception, + eUnexpectedDoubleQuote, + "Unexpected double quote. " + "If a field is not quoted then a " + "double quote may not appear " + "in the middle."); + } + if (!in_quotes) { + in_quotes = true; + } else { + if (current_index + 1 < data->size() && + (*data)[current_index + 1] == '"') { + ++current_index; + } else { + if (current_index + 1 < data->size() && + (*data)[current_index + 1] != ',') + NCBI_THROW(CCRowReaderStream_IANA_CSV_Exception, + eUnexpectedDoubleQuote, + "Unexpected double quote. " + "Closing double quote must be the " + "last in a line or be followed " + "by a comma character"); + + in_quotes = false; + } + } + } + + ++current_index; + } + + if (!in_quotes) + break; + + // Here: need to read one more line because of the quotes. + // So check if we still can read. + if (!bool(is)) { + NCBI_THROW(CCRowReaderStream_IANA_CSV_Exception, + eUnbalancedDoubleQuote, + "Unbalanced double quote detected"); + } + } + + m_Tokens.push_back(token_begin_index); + return lines_read; + } + + ERR_Action OnNextLine(CTempString raw_line) + { + if (raw_line.empty()) + return eRR_Skip; + return eRR_Continue_Data; + } + + + // The tokenization is actually done in the ReadRowData() member + ERR_Action Tokenize(const CTempString raw_line, + vector& tokens) + { + if (m_HasHeader) { + if (GetMyStream().GetCurrentLineNo() == 0) { + x_SetFieldNames(raw_line); + return eRR_Skip; + } + } + + size_t field_size; + for (TFieldNo field_no = 0; field_no < m_Tokens.size(); ++field_no) { + if (field_no + 1 < m_Tokens.size()) + field_size = m_Tokens[field_no + 1] - m_Tokens[field_no] - 1; + else + field_size = raw_line.size() - m_Tokens[field_no]; + tokens.emplace_back(raw_line.data() + m_Tokens[field_no], + field_size); + } + return eRR_Continue_Data; + } + + ERR_Action Validate(CTempString raw_line, + ERR_FieldValidationMode field_validation_mode) + { + if (field_validation_mode == eRR_NoFieldValidation) + return eRR_Skip; + if (m_FieldsToValidate.empty()) + return eRR_Skip; + + if (raw_line.empty()) + return eRR_Skip; + + // Here: the field values need to be validated and there is some type + // information + m_ValidationTokens.clear(); + ERR_Action action = this->Tokenize(raw_line, m_ValidationTokens); + + if (action == eRR_Skip) + return eRR_Skip; + + for (const auto& info : m_FieldsToValidate) { + if (info.first < m_Tokens.size()) { + string translated; + ERR_TranslationResult translation_result = + this->Translate(info.first, m_ValidationTokens[info.first], + translated); + if (translation_result == eRR_UseOriginal) { + CRR_Util::ValidateBasicTypeFieldValue( + m_ValidationTokens[info.first], + info.second.first, info.second.second); + } else { + CRR_Util::ValidateBasicTypeFieldValue( + translated, + info.second.first, info.second.second); + } + } + } + + return eRR_Skip; + } + + ERR_TranslationResult Translate(TFieldNo field_no, + const CTempString raw_value, + string& translated_value) + { + if (!raw_value.empty()) { + if (raw_value[0] == '"') { + translated_value = string(raw_value.data() + 1, + raw_value.size() - 2); + NStr::ReplaceInPlace(translated_value, "\"\"", "\""); + return eRR_Translated; + } + } + return eRR_UseOriginal; + } + + /// Tell if the source has a header. The new value will be taken into + /// account for the further sources which are read from the beginning. + /// @param has_header + /// flag for the following data sources + void SetHasHeader(bool has_header) + { m_HasHeader = has_header; } + + ERR_EventAction OnEvent(ERR_Event event, + ERR_EventMode event_mode) + { + switch (event) { + case eRR_Event_SourceBegin: + GetMyStream().x_ClearTraitsProvidedFieldsInfo(); + + if (event_mode == eRR_EventMode_Validating) + x_GetFieldTypesToValidate(); + + // fall through + case eRR_Event_SourceEnd: + case eRR_Event_SourceError: + default: + ; + } + return eRR_EventAction_Default; + } + +private: + void x_ReadOneLine(CNcbiIstream& is, string* data, bool joining) + { + m_RawLine.clear(); + std::getline(is, m_RawLine); + m_LineSeparator = "\n"; + if(!m_RawLine.empty() && m_RawLine.back() == '\r') { + m_RawLine.pop_back(); + m_LineSeparator = "\r\n"; + } + + if (joining) + data->append(m_PreviousLineSeparator); + data->append(m_RawLine); + + m_PreviousLineSeparator = m_LineSeparator; + } + + void x_SetFieldNames(const CTempString& raw_line) + { + string translated; + size_t field_size; + for (TFieldNo field_no = 0; field_no < m_Tokens.size(); ++field_no) { + if (field_no + 1 < m_Tokens.size()) + field_size = m_Tokens[field_no + 1] - m_Tokens[field_no] - 1; + else + field_size = raw_line.size() - m_Tokens[field_no]; + + CTempString raw_field_name(raw_line.data() + m_Tokens[field_no], + field_size); + + if (Translate(field_no, raw_field_name, translated) == eRR_UseOriginal) + GetMyStream().x_SetFieldName(field_no, + string(raw_field_name.data(), + raw_field_name.size())); + else + GetMyStream().x_SetFieldName(field_no, translated); + } + } + + void x_GetFieldTypesToValidate(void) + { + m_FieldsToValidate.clear(); + for (const auto& info : GetMyStream().GetFieldsMetaInfo()) { + if (info.is_type_initialized) { + auto field_type = info.type.GetType(); + if (field_type == eRR_Boolean || field_type == eRR_Integer || + field_type == eRR_Double || field_type == eRR_DateTime) + m_FieldsToValidate[info.field_no] = + make_pair(field_type, info.type.GetProps()); + } + } + } + +private: + bool m_HasHeader; + vector m_Tokens; + string m_LineSeparator; + string m_PreviousLineSeparator; + string m_RawLine; + + map> m_FieldsToValidate; + vector m_ValidationTokens; + + RR_TRAITS_PARENT_STREAM(CRowReaderStream_IANA_CSV); +}; + + + +/// IANA CSV traits which by default consider the source as the one without a +/// header (can be switched at runtime using the SetHasHeader() member). +/// It follows the specs at: +/// https://tools.ietf.org/html/rfc4180 +class CRowReaderStream_IANA_CSV_no_header : public CRowReaderStream_IANA_CSV +{ +public: + CRowReaderStream_IANA_CSV_no_header() + { SetHasHeader(false); } + +private: + RR_TRAITS_PARENT_STREAM(CRowReaderStream_IANA_CSV_no_header); +}; + + +END_NCBI_SCOPE + +#endif /* UTIL___ROW_READER_IANA_CSV__HPP */ diff --git a/c++/include/util/row_reader_iana_tsv.hpp b/c++/include/util/row_reader_iana_tsv.hpp new file mode 100644 index 00000000..da91fb8a --- /dev/null +++ b/c++/include/util/row_reader_iana_tsv.hpp @@ -0,0 +1,328 @@ +#ifndef UTIL___ROW_READER_IANA_TSV__HPP +#define UTIL___ROW_READER_IANA_TSV__HPP + +/* $Id: row_reader_iana_tsv.hpp 539183 2017-06-19 17:23:17Z ivanov $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Authors: Denis Vakatov, Sergey Satskiy +* +* File Description: +* Implementation of the CRowReader<> traits for IANA TSV +* https://www.iana.org/assignments/media-types/text/tab-separated-values +* +* =========================================================================== +*/ + +#include + + +BEGIN_NCBI_SCOPE + + +const size_t kReadBufferSize = 128 * 1024; + + +// Note 1: The row with names does not appear in the iteration loop +// Note 2: IANA TSV has two validation modes: +// - default; matches source reading iterations requirements +// - strict; follows the BNF strictly +// +// Check | Strict | Default validation/ +// | validation | reading iteraitons +// ------------------------------------------------------------------- +// empty source | exc | OK +// empty lines | exc | exc +// 0 data records | exc | OK +// empty field names | exc | exc +// empty field values | exc | exc +// no EOL in the last data record | exc | OK +// +// 'exc' -> exception is generated +// 'OK' -> no checking performed +// +// Note 3: If the validation is called with the eRR_FieldValidation flag then +// the field basic type information is taken into account. For each provided +// type except eRR_String a conversion is tried. In case of a conversion +// failure an exception is generated. + + +/// Exception specific to IANA TSV sources +class CCRowReaderStream_IANA_TSV_Exception : public CException +{ +public: + enum EErrCode { + eNumberOfFieldsMismatch = 1, + eEmptyDataSource = 2, + eNoTrailingEOL = 3, + eEmptyFieldName = 4, + eEmptyLine = 5, + eEmptyFieldValue = 6, + eValidateConversion = 7 + }; + + virtual const char * GetErrCodeString(void) const + { + switch (GetErrCode()) { + case eNumberOfFieldsMismatch: + return "eNumberOfFieldsMismatch"; + case eEmptyDataSource: + return "eEmptyDataSource"; + case eNoTrailingEOL: + return "eNoTrailingEOL"; + case eEmptyFieldName: + return "eEmptyFieldName"; + case eEmptyLine: + return "eEmptyLine"; + case eEmptyFieldValue: + return "eEmptyFieldValue"; + case eValidateConversion: + return "eValidateConversion"; + default: + return CException::GetErrCodeString(); + } + } + + NCBI_EXCEPTION_DEFAULT(CCRowReaderStream_IANA_TSV_Exception, CException); +}; + + + +/// IANA TSV traits. +/// It follows the specs at: +/// https://www.iana.org/assignments/media-types/text/tab-separated-values +class CRowReaderStream_IANA_TSV : public TRowReaderStream_SingleTabDelimited +{ +public: + enum ERR_ValidationMode { + eRR_ValidationMode_Default, + eRR_ValidationMode_Strict + }; + +public: + CRowReaderStream_IANA_TSV() : + m_FieldNamesExtracted(false), m_NumberOfFields(0), + m_ValidationMode(eRR_ValidationMode_Default), + m_LineHasTrailingEOL(true), + m_ReadBuffer(new char[kReadBufferSize]) + {} + + ~CRowReaderStream_IANA_TSV() + { + delete [] m_ReadBuffer; + } + + void SetValidationMode(ERR_ValidationMode validation_mode) + { + m_ValidationMode = validation_mode; + } + + // The only reason to have this method re-implemented is to detect if the + // last line in the stream has a trailing EOL. It makes difference if it is + // a strict validation mode. + size_t ReadRowData(CNcbiIstream& is, string* data) + { + data->clear(); + + // Note: the std::getline() does not affect the read bytes counter so a + // stream version is used. The stream version uses a character buffer + streamsize bytes_read = 0; + streamsize total_read = 0; + for (;;) { + is.getline(m_ReadBuffer, kReadBufferSize); + bytes_read = is.gcount(); + total_read += bytes_read; + + if (!is.fail()) { + // this is presumably the most common case + break; + } + + if (is.eof()) { + if (bytes_read == 0) + return 0; + break; + } + + // Here: the buffer size is not enough to read the whole line + data->append(m_ReadBuffer); + is.clear(); + } + + data->append(m_ReadBuffer); + m_LineHasTrailingEOL = + total_read != static_cast(data->size()); + if(!data->empty() && data->back() == '\r') + data->pop_back(); + return 1; + } + + ERR_Action Tokenize(const CTempString raw_line, + vector& tokens) + { + if (raw_line.empty()) + NCBI_THROW(CCRowReaderStream_IANA_TSV_Exception, + eEmptyLine, "Empty lines are not allowed"); + + if (!m_FieldNamesExtracted) { + x_ExtractNames(raw_line); + return eRR_Skip; + } + + // The field names have been extracted so tokenize and check the data + // consistency. + // Note: the only action Tokenize() returns is eRR_Continue_Data + TRowReaderStream_SingleTabDelimited::Tokenize(raw_line, tokens); + for (const auto& name : m_Tokens) { + if (name.empty()) + NCBI_THROW(CCRowReaderStream_IANA_TSV_Exception, + eEmptyFieldValue, + "Empty field values are not allowed"); + } + + if (tokens.size() != m_NumberOfFields) + NCBI_THROW(CCRowReaderStream_IANA_TSV_Exception, + eNumberOfFieldsMismatch, + "Unexpected number of fields. The first line declared " + + NStr::NumericToString(m_NumberOfFields) + + "fields while the current line has " + + NStr::NumericToString(tokens.size()) + " fields"); + + return eRR_Continue_Data; + } + + ERR_Action Validate(CTempString raw_line, + ERR_FieldValidationMode field_validation_mode) + { + m_Tokens.clear(); + ERR_Action action = this->Tokenize(raw_line, m_Tokens); + + if (m_ValidationMode == eRR_ValidationMode_Strict) { + if (!m_LineHasTrailingEOL) + NCBI_THROW(CCRowReaderStream_IANA_TSV_Exception, + eNoTrailingEOL, + "Strict validation requires " + "trailing EOL in the last line as well"); + } + + // Validate field values in accordance with the available + // basic field types. It is conditional: + // - the requested validation mode includes value checking + // - it is not a field names row + // - the user has provided some type information + if (field_validation_mode == eRR_FieldValidation && + action == eRR_Continue_Data && + !m_FieldsToValidate.empty()) { + for (const auto& info : m_FieldsToValidate) + if (info.first < m_Tokens.size()) + CRR_Util::ValidateBasicTypeFieldValue( + m_Tokens[info.first], + info.second.first, info.second.second); + } + + return eRR_Skip; + } + + ERR_EventAction OnEvent(ERR_Event event, + ERR_EventMode event_mode) + { + switch (event) { + case eRR_Event_SourceBegin: + GetMyStream().x_ClearTraitsProvidedFieldsInfo(); + m_FieldNamesExtracted = false; + m_NumberOfFields = 0; + + if (event_mode == eRR_EventMode_Validating) + x_GetFieldTypesToValidate(); + + return eRR_EventAction_Continue; + + case eRR_Event_SourceEnd: + if (event_mode == eRR_EventMode_Validating) { + if (m_ValidationMode == eRR_ValidationMode_Strict) { + if (GetMyStream().GetCurrentLineNo() < 1) { + NCBI_THROW(CCRowReaderStream_IANA_TSV_Exception, + eEmptyDataSource, + "Strict validation requires " + "non empty data source with at least " + "two lines (a nameline and a record)"); + } + } + } + case eRR_Event_SourceError: + default: + ; + } + return eRR_EventAction_Default; + } + +private: + bool m_FieldNamesExtracted; + TFieldNo m_NumberOfFields; + vector m_Tokens; + ERR_ValidationMode m_ValidationMode; + bool m_LineHasTrailingEOL; + + map> m_FieldsToValidate; + + char* m_ReadBuffer; + + void x_ExtractNames(const CTempString& raw_line) + { + m_Tokens.clear(); + TRowReaderStream_SingleTabDelimited::Tokenize(raw_line, m_Tokens); + for (const auto& name : m_Tokens) { + if (name.empty()) + NCBI_THROW(CCRowReaderStream_IANA_TSV_Exception, + eEmptyFieldName, + "Empty field names are not allowed"); + + GetMyStream().x_SetFieldName(m_NumberOfFields, + string(name.data(), name.length())); + ++m_NumberOfFields; + } + m_FieldNamesExtracted = true; + } + + void x_GetFieldTypesToValidate(void) + { + m_FieldsToValidate.clear(); + for (const auto& info : GetMyStream().GetFieldsMetaInfo()) { + if (info.is_type_initialized) { + auto field_type = info.type.GetType(); + if (field_type == eRR_Boolean || field_type == eRR_Integer || + field_type == eRR_Double || field_type == eRR_DateTime) + m_FieldsToValidate[info.field_no] = + make_pair(field_type, info.type.GetProps()); + } + } + } + + RR_TRAITS_PARENT_STREAM(CRowReaderStream_IANA_TSV); +}; + + +END_NCBI_SCOPE + +#endif /* UTIL___ROW_READER_IANA_TSV__HPP */ diff --git a/c++/include/util/row_reader_ncbi_tsv.hpp b/c++/include/util/row_reader_ncbi_tsv.hpp new file mode 100644 index 00000000..f25207f9 --- /dev/null +++ b/c++/include/util/row_reader_ncbi_tsv.hpp @@ -0,0 +1,218 @@ +#ifndef UTIL___ROW_READER_NCBI_TSV__HPP +#define UTIL___ROW_READER_NCBI_TSV__HPP + +/* $Id: row_reader_ncbi_tsv.hpp 539184 2017-06-19 17:23:42Z ivanov $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Authors: Denis Vakatov, Sergey Satskiy +* +* File Description: +* Implementation of the CRowReader<> traits for NCBI TSV +* +* =========================================================================== +*/ + +#include + + +BEGIN_NCBI_SCOPE + + +/// The following rules are going to be applied for the NCBI TSV sources: +/// - each line is processed independently (no line merging at all) +/// - line separators supported: CRLF and LF +/// - field separator is '\t' +/// - lines may have variable number of fields (not matching the number of +/// field names) +/// - empty lines are skipped +/// - lines which start with '##' are considered metadata and passed to the +/// user approprietely +/// - lines which start with '#': +/// - if it is a first non empty line then it is a comment line with field +/// names. The names are extracted and the line is not passed to the user +/// - otherwise the line is treated as a comment one and passed to the user +/// - empty column names are allowed +/// - empty values are allowed +/// - the last line EOL is not enforced +/// - the following translation is done: +/// - '-' is translated to '' +/// - 'na' is translated to Null value +/// - validation depends on the mode: +/// - no field validation: only reads the source and does not enforce +/// anything +/// - field validation: reads the source and if the basic type information is +/// supplied by the user then there is a try to convert the raw value to +/// the required typed value. In case of problems an exception is +/// generated. +/// Note: a custom format could be supplied for the eRR_DateTime fields. + + + +/// NCBI TSV traits. +/// It follows the specs outlined above +class CRowReaderStream_NCBI_TSV : public TRowReaderStream_SingleTabDelimited +{ +public: + CRowReaderStream_NCBI_TSV() : + m_NonEmptyLineFound(false) + {} + + ERR_Action OnNextLine(CTempString raw_line) + { + if (raw_line.empty()) + return eRR_Skip; + if (NStr::StartsWith(raw_line, "##")) { + m_NonEmptyLineFound = true; + return eRR_Continue_Metadata; + } + if (NStr::StartsWith(raw_line, "#")) { + if (m_NonEmptyLineFound) + return eRR_Continue_Comment; + x_ExtractNames(raw_line); + m_NonEmptyLineFound = true; + return eRR_Skip; + } + m_NonEmptyLineFound = true; + return eRR_Continue_Data; + } + + ERR_Action Validate(CTempString raw_line, + ERR_FieldValidationMode field_validation_mode) + { + if (field_validation_mode == eRR_NoFieldValidation) + return eRR_Skip; + if (m_FieldsToValidate.empty()) + return eRR_Skip; + + ERR_Action action = this->OnNextLine(raw_line); + if (action != eRR_Continue_Data) + return eRR_Skip; + + m_ValidationTokens.clear(); + this->Tokenize(raw_line, m_ValidationTokens); + + for (const auto& info : m_FieldsToValidate) { + if (info.first < m_ValidationTokens.size()) { + string translated; + ERR_TranslationResult translation_result = + this->Translate(info.first, m_ValidationTokens[info.first], + translated); + switch (translation_result) { + case eRR_UseOriginal: + CRR_Util::ValidateBasicTypeFieldValue( + m_ValidationTokens[info.first], + info.second.first, info.second.second); + break; + case eRR_Translated: + CRR_Util::ValidateBasicTypeFieldValue( + translated, + info.second.first, info.second.second); + break; + case eRR_Null: + default: + ; + } + } + } + + return eRR_Skip; + } + + ERR_EventAction OnEvent(ERR_Event event, + ERR_EventMode event_mode) + { + switch (event) { + case eRR_Event_SourceBegin: + GetMyStream().x_ClearTraitsProvidedFieldsInfo(); + m_NonEmptyLineFound = false; + + if (event_mode == eRR_EventMode_Validating) + x_GetFieldTypesToValidate(); + + return eRR_EventAction_Continue; + + case eRR_Event_SourceEnd: + case eRR_Event_SourceError: + default: + ; + } + return eRR_EventAction_Default; + } + + ERR_TranslationResult Translate(TFieldNo field_no, + const CTempString raw_value, + string& translated_value) + { + if (raw_value == "-") { + translated_value = ""; + return eRR_Translated; + } + if (raw_value == "na") + return eRR_Null; + return eRR_UseOriginal; + } + +private: + bool m_NonEmptyLineFound; + + void x_ExtractNames(const CTempString& raw_line) + { + vector tokens; + Tokenize(CTempString(raw_line.data() + 1, raw_line.size() - 1), + tokens); + + TFieldNo field_no = 0; + for (const auto& name : tokens) { + GetMyStream().x_SetFieldName(field_no, + string(name.data(), name.length())); + ++field_no; + } + } + +private: + vector m_ValidationTokens; + map> m_FieldsToValidate; + + void x_GetFieldTypesToValidate(void) + { + m_FieldsToValidate.clear(); + for (const auto& info : GetMyStream().GetFieldsMetaInfo()) { + if (info.is_type_initialized) { + auto field_type = info.type.GetType(); + if (field_type == eRR_Boolean || field_type == eRR_Integer || + field_type == eRR_Double || field_type == eRR_DateTime) + m_FieldsToValidate[info.field_no] = + make_pair(field_type, info.type.GetProps()); + } + } + } + + RR_TRAITS_PARENT_STREAM(CRowReaderStream_NCBI_TSV); +}; + + +END_NCBI_SCOPE + +#endif /* UTIL___ROW_READER_NCBI_TSV__HPP */ diff --git a/c++/include/util/static_set.hpp b/c++/include/util/static_set.hpp index 49bdd897..4e77ec5e 100644 --- a/c++/include/util/static_set.hpp +++ b/c++/include/util/static_set.hpp @@ -1,7 +1,7 @@ #ifndef UTIL___STATIC_SET__HPP #define UTIL___STATIC_SET__HPP -/* $Id: static_set.hpp 500279 2016-05-03 17:12:04Z ivanov $ +/* $Id: static_set.hpp 534859 2017-05-03 12:47:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -226,7 +226,7 @@ public: ECopyWarn warn); private: - auto_ptr m_Converter; + unique_ptr m_Converter; void* m_ArrayPtr; size_t m_ElementCount; @@ -398,10 +398,10 @@ public: } void Convert(void* dst_ptr, const void* src_ptr) const { - auto_ptr conv1 + unique_ptr conv1 (MakeConverter(static_cast(0), static_cast(0))); - auto_ptr conv2 + unique_ptr conv2 (MakeConverter(static_cast(0), static_cast(0))); DstType& dst = *static_cast(dst_ptr); diff --git a/c++/include/util/strbuffer.inl b/c++/include/util/strbuffer.inl index 19ee2cd3..76251d7b 100644 --- a/c++/include/util/strbuffer.inl +++ b/c++/include/util/strbuffer.inl @@ -1,7 +1,7 @@ #if defined(STRBUFFER__HPP) && !defined(STRBUFFER__INL) #define STRBUFFER__INL -/* $Id: strbuffer.inl 354576 2012-02-28 14:56:28Z gouriano $ +/* $Id: strbuffer.inl 511886 2016-08-25 14:24:12Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -84,13 +84,7 @@ bool CIStreamBuffer::SkipExpectedChar(char c, size_t offset) inline bool CIStreamBuffer::SkipExpectedChars(char c1, char c2, size_t offset) { - const char* pos = m_CurrentPos+offset+1; - if ( pos >= m_DataEndPos ) - pos = FillBuffer(pos); - if ( pos[-1] != c1 || pos[0] != c2 ) - return false; - m_CurrentPos = pos+1; - return true; + return SkipExpectedChar(c1, offset) && SkipExpectedChar(c2, 0); } inline diff --git a/c++/include/util/stream_source.hpp b/c++/include/util/stream_source.hpp index dafa0345..08bb2147 100644 --- a/c++/include/util/stream_source.hpp +++ b/c++/include/util/stream_source.hpp @@ -1,7 +1,7 @@ #ifndef UTIL___STREAM_SOURCE__HPP #define UTIL___STREAM_SOURCE__HPP -/* $Id: stream_source.hpp 500707 2016-05-06 18:14:09Z vakatov $ +/* $Id: stream_source.hpp 534859 2017-05-03 12:47:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -124,6 +124,8 @@ public: /// CInputStreamSource(const CArgs& args, const string& prefix = "input"); + virtual ~CInputStreamSource(); + /// Initialize from a stream /// No ownership is claimed by this class - lifetime management of the /// stream is the responsibility of the caller. @@ -152,7 +154,7 @@ public: /// Initialize from a set of arguments /// - void InitArgs(const CArgs& args, const string &prefix = "input"); + virtual void InitArgs(const CArgs& args, const string &prefix = "input"); /// Access the current stream /// @@ -187,13 +189,13 @@ public: /// /// If these conditions aren't met, throws an exception. /// - CInputStreamSource& operator++(); + virtual CInputStreamSource& operator++(); /// Determine if there are any more streams to be processed /// /// @return boolean, true if there are more streams /// - operator bool(); + operator bool() const; /// Resets the iterator to the first stream in the class /// @@ -211,16 +213,18 @@ public: /// the current file index size_t GetCurrentStreamIndex(size_t* count = nullptr) const; -private: +protected: CArgs m_Args; string m_Prefix; CNcbiIstream* m_Istr; - auto_ptr m_IstrOwned; + unique_ptr m_IstrOwned; + vector m_Files; size_t m_CurrIndex; string m_CurrFile; +private: /// forbidden CInputStreamSource(const CInputStreamSource&); CInputStreamSource& operator=(const CInputStreamSource&); diff --git a/c++/include/util/sync_queue.hpp b/c++/include/util/sync_queue.hpp index 50877ed9..f67b4e08 100644 --- a/c++/include/util/sync_queue.hpp +++ b/c++/include/util/sync_queue.hpp @@ -1,7 +1,7 @@ #ifndef UTIL___SYNC_QUEUE__HPP #define UTIL___SYNC_QUEUE__HPP -/* $Id: sync_queue.hpp 490388 2016-01-25 16:58:30Z satskyse $ +/* $Id: sync_queue.hpp 534859 2017-05-03 12:47:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1330,7 +1330,7 @@ void CSyncQueue::x_LockAndWait( const { // TODO: change to use CTimeout instead - auto_ptr real_timeout; + unique_ptr real_timeout; if (full_tmo) { real_timeout.reset(new CTimeSpan(*full_tmo)); diff --git a/c++/include/util/text_joiner.hpp b/c++/include/util/text_joiner.hpp index cbb43377..681b1b09 100644 --- a/c++/include/util/text_joiner.hpp +++ b/c++/include/util/text_joiner.hpp @@ -1,7 +1,7 @@ #ifndef UTIL___TEXT_JOINER__HPP #define UTIL___TEXT_JOINER__HPP -/* $Id: text_joiner.hpp 373291 2012-08-28 16:16:07Z ucko $ +/* $Id: text_joiner.hpp 534859 2017-05-03 12:47:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -67,9 +67,9 @@ public: void Join(TOut* result) const; private: - TIn m_MainStorage[num_prealloc]; - auto_ptr > m_ExtraStorage; - size_t m_MainStorageUsage; + TIn m_MainStorage[num_prealloc]; + unique_ptr > m_ExtraStorage; + size_t m_MainStorageUsage; }; diff --git a/c++/include/util/util_misc.hpp b/c++/include/util/util_misc.hpp index d0fb34ac..20a1643b 100644 --- a/c++/include/util/util_misc.hpp +++ b/c++/include/util/util_misc.hpp @@ -1,7 +1,7 @@ #ifndef UTIL___UTIL_MISC__HPP #define UTIL___UTIL_MISC__HPP -/* $Id: util_misc.hpp 209038 2010-10-22 15:48:02Z ucko $ +/* $Id: util_misc.hpp 530021 2017-03-09 19:06:46Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -94,6 +94,13 @@ extern string g_FindDataFile(const CTempString& name, NCBI_XUTIL_EXPORT extern void g_IgnoreDataFile(const string& pattern, bool do_ignore = true); +/// Check whether the given file (a full path, as returned by +/// g_FindDataFile) is older than a built-in version containing +/// the specified "$Id: ..." line. +NCBI_XUTIL_EXPORT +extern bool g_IsDataFileOld(const CTempString& path, + const CTempString& id_line); + END_NCBI_SCOPE diff --git a/c++/scripts/common/add_vdb.sh b/c++/scripts/common/add_vdb.sh index e6346b03..0fadeef1 100755 --- a/c++/scripts/common/add_vdb.sh +++ b/c++/scripts/common/add_vdb.sh @@ -1,5 +1,5 @@ #!/bin/sh -# $Id: add_vdb.sh 515777 2016-10-05 17:33:58Z ivanov $ +# $Id: add_vdb.sh 515345 2016-09-30 13:43:54Z ucko $ . "`dirname $0`/common.sh" set -e diff --git a/c++/scripts/common/check/check_add.sh b/c++/scripts/common/check/check_add.sh index 7ffcca1b..4bf28f65 100755 --- a/c++/scripts/common/check/check_add.sh +++ b/c++/scripts/common/check/check_add.sh @@ -1,5 +1,5 @@ #! /bin/sh -# $Id: check_add.sh 512371 2016-08-30 14:51:15Z ivanov $ +# $Id: check_add.sh 511484 2016-08-22 18:25:10Z ivanov $ # Author: Vladimir Ivanov, NCBI # ########################################################################### diff --git a/c++/scripts/common/check/check_make_cfg.sh b/c++/scripts/common/check/check_make_cfg.sh index 57f32a5c..7a675818 100755 --- a/c++/scripts/common/check/check_make_cfg.sh +++ b/c++/scripts/common/check/check_make_cfg.sh @@ -1,6 +1,6 @@ #! /bin/sh -# $Id: check_make_cfg.sh 499855 2016-04-28 17:06:32Z ivanov $ +# $Id: check_make_cfg.sh 544511 2017-08-23 18:50:29Z ivanov $ # Author: Vladimir Ivanov, NCBI # ########################################################################### @@ -133,6 +133,7 @@ if test -n "$NCBI_AUTOMATED_BUILD"; then msvc10 ) signature="MSVC_1000" ;; vs2012 ) signature="VS_2012" ;; vs2013 ) signature="VS_2013" ;; + vs2015 ) signature="VS_2015" ;; esac signature="$signature-${x_cfg}" case "$x_cfg" in @@ -323,6 +324,12 @@ if test -z "\$NCBI_TEST_DATA"; then esac export NCBI_TEST_DATA fi +# Add synonym for it, see: include/common/test_data_path.h (CXX-9239) +if test -z "\$NCBI_TEST_DATA_PATH"; then + NCBI_TEST_DATA_PATH=\$NCBI_TEST_DATA + export NCBI_TEST_DATA_PATH +fi + count_ok=0 count_err=0 @@ -404,7 +411,8 @@ RunTest() { esac if test -f \$x_applog_sh; then chmod a+x \$x_applog_sh 2>&1 - \$x_applog_sh >> "\$build_dir/test_stat_load_applog.log" 2>&1 + echo "\$x_path_app:" >> "\$build_dir/test_stat_load_applog.log" 2>&1 + \$x_applog_sh >> "\$build_dir/test_stat_load_applog.log" 2>&1 else echo "Error generating \$x_applog_sh " fi @@ -469,6 +477,13 @@ RunTest() { echo "Command line: \$x_run" echo fi + if test -n "\$NCBI_CHECK_ENV_SETTINGS"; then + echo "NCBI_CHECK_ENV_SETTINGS:" + for env in \$NCBI_CHECK_ENV_SETTINGS; do + echo " \$env = \`eval echo '$'\$env\`" + done + echo + fi ) > \$x_test_out 2>&1 @@ -582,9 +597,12 @@ saved_path="\$PATH" FEATURES="$x_features" export FEATURES -# Redirect output for C++ diagnostic framework to stderr -NCBI_CONFIG__LOG__FILE="-" -export NCBI_CONFIG__LOG__FILE +# Redirect output for C++ diagnostic framework to stderr, +# except if using under 'export_project' tool. +if test -z "\$NCBI_EXPORT_PROJECT"; then + NCBI_CONFIG__LOG__FILE="-" + export NCBI_CONFIG__LOG__FILE +fi # Export bin and lib paths export CFG_BIN="\${build_dir}/\${build_tree}/bin/\${build_cfg}" diff --git a/c++/scripts/common/check/check_make_unix.sh b/c++/scripts/common/check/check_make_unix.sh index b739524e..6094aa47 100755 --- a/c++/scripts/common/check/check_make_unix.sh +++ b/c++/scripts/common/check/check_make_unix.sh @@ -1,6 +1,6 @@ #! /bin/sh -# $Id: check_make_unix.sh 501272 2016-05-12 20:12:39Z vakatov $ +# $Id: check_make_unix.sh 544511 2017-08-23 18:50:29Z ivanov $ # Author: Vladimir Ivanov, NCBI # ########################################################################### @@ -322,6 +322,12 @@ if test -z "\$NCBI_TEST_DATA"; then fi export NCBI_TEST_DATA fi +# Add synonym for it, see: include/common/test_data_path.h (CXX-9239) +if test -z "\$NCBI_TEST_DATA_PATH"; then + NCBI_TEST_DATA_PATH=\$NCBI_TEST_DATA + export NCBI_TEST_DATA_PATH +fi + # Valgrind configuration VALGRIND_SUP="\${root_dir}/scripts/common/check/valgrind.supp" @@ -336,9 +342,12 @@ export top_srcdir FEATURES="$x_features" export FEATURES -# Redirect output for C++ diagnostic framework to stderr -NCBI_CONFIG__LOG__FILE="-" -export NCBI_CONFIG__LOG__FILE +# Redirect output for C++ diagnostic framework to stderr, +# except if using under 'export_project' tool. +if test -z "\$NCBI_EXPORT_PROJECT"; then + NCBI_CONFIG__LOG__FILE="-" + export NCBI_CONFIG__LOG__FILE +fi # Add additional necessaary directories to PATH: current, build, scripts, utility. PATH=".:\${build_dir}:\${root_dir}/scripts/common/impl:\$NCBI/bin/_production/CPPCORE:\${PATH}" @@ -431,12 +440,13 @@ fi if test "\$NCBI_CHECK_SETLIMITS" != "0"; then ulimit -c 1000000 + ulimit -n 8192 if [ \$cygwin = false ]; then if test "\$NCBI_CHECK_TOOLS" = "regular"; then - ulimit -v 4000000 + ulimit -v 48000000 else # Increase memory limits if run under check tool - ulimit -v 16000000 + ulimit -v 64000000 fi fi fi @@ -588,6 +598,13 @@ RunTest() echo "Command line: \$x_run" echo fi + if test -n "\$NCBI_CHECK_ENV_SETTINGS"; then + echo "NCBI_CHECK_ENV_SETTINGS:" + for env in \$NCBI_CHECK_ENV_SETTINGS; do + echo " \$env = \`eval echo '$'\$env\`" + done + echo + fi ) > \$x_test_out 2>&1 # Remove old core file if it exist (for clarity of the test) diff --git a/c++/scripts/common/check/check_run.sh b/c++/scripts/common/check/check_run.sh index 9c38f288..5b1e33b8 100755 --- a/c++/scripts/common/check/check_run.sh +++ b/c++/scripts/common/check/check_run.sh @@ -1,6 +1,6 @@ #! /bin/sh -# $Id: check_run.sh 401923 2013-06-04 13:11:35Z ivanov $ +# $Id: check_run.sh 544487 2017-08-23 17:42:50Z ivanov $ # Author: Vladimir Ivanov, NCBI # ########################################################################### @@ -90,7 +90,7 @@ esac $CHECK_RUN_FILE run result=$? -if test -n "$NCBI_AUTOMATED_BUILD"; then +if test -n "$NCBI_AUTOMATED_BUILD" -a -z "$TEAMCITY_VERSION"; then $CHECK_RUN_FILE load_to_db # Report test_stat_load errors if any if [ -f "$build_dir/test_stat_load.log" ]; then diff --git a/c++/scripts/common/check/inspxe-suppressions/_vs.sup b/c++/scripts/common/check/inspxe-suppressions/_vs.sup index c769d1e2..a7024682 100644 --- a/c++/scripts/common/check/inspxe-suppressions/_vs.sup +++ b/c++/scripts/common/check/inspxe-suppressions/_vs.sup @@ -205,15 +205,6 @@ suppression = { } } } -suppression = { - name = "gnutls_global_init() - memory leak" - stacks = { - allocation={ - ...; - func=gnutls_global_init; - } - } -} suppression = { name = "typename.cpp" type = {reachable_memory_leak} @@ -308,6 +299,25 @@ suppression = { } } } +suppression = { + name = "gnutls_global_init() - memory leak" + stacks = { + allocation={ + ...; + func=gnutls_global_init; + } + } +} +suppression = { + name = "Invalid memory access in libgnutls" + type = {invalid_memory_access} + stacks = { + allocation = { + ...; + func=gnutls_pkcs12_export2; + } + } +} suppression = { name = "False positive in operator<<()" type = {invalid_memory_access} @@ -331,3 +341,23 @@ suppression = { } } } +suppression = { + name = "False positive in gethostname()" + type = {invalid_memory_access_partial} + stacks = { + allocation={ + ...; + mod=WS2_32.dll,func=gethostname; + } + } +} +suppression = { + name = "SHELL32.dll -- SHGetPathFromIDList() -- invalid memory access" + type = {invalid_memory_access} + stacks = { + { + ...; + mod=SHELL32.dll,func=SHGetPathFromIDList; + } + } +} diff --git a/c++/scripts/common/check/inspxe-suppressions/connect.sup b/c++/scripts/common/check/inspxe-suppressions/connect.sup index 6dee664f..d2eda847 100644 --- a/c++/scripts/common/check/inspxe-suppressions/connect.sup +++ b/c++/scripts/common/check/inspxe-suppressions/connect.sup @@ -60,3 +60,14 @@ suppression = { } } } + +suppression = { + name = "gethostbyname()" + type = {invalid_memory_access_partial} + stacks = { + allocation={ + ...; + mod=WS2_32.dll,func=gethostbyname; + } + } +} diff --git a/c++/scripts/common/check/inspxe-suppressions/misc.sup b/c++/scripts/common/check/inspxe-suppressions/misc.sup index 130f9aba..f036b2b8 100644 --- a/c++/scripts/common/check/inspxe-suppressions/misc.sup +++ b/c++/scripts/common/check/inspxe-suppressions/misc.sup @@ -48,14 +48,4 @@ suppression = { } } } -suppression = { - name = "Invalid memory access in libgnutls" - type = {invalid_memory_access} - stacks = { - allocation = { - ...; - func=gnutls_pkcs12_export2; - } - } -} diff --git a/c++/scripts/common/impl/define_random_macros.sh b/c++/scripts/common/impl/define_random_macros.sh new file mode 100755 index 00000000..3166f304 --- /dev/null +++ b/c++/scripts/common/impl/define_random_macros.sh @@ -0,0 +1,13 @@ +#!/bin/sh +# $Id: define_random_macros.sh 518561 2016-11-04 15:01:06Z ucko $ + +cat < 0: + if status < 0: + status = 128 - status + os._exit(status) # continue in background + + target_type = command_info['target_type'] + mfname = 'Makefile.%s.%s' % (command_info['target_name'], target_type) + srcdir = os.path.realpath(self.get_srcdir(command_info, mfname)) + mf = self.read_makefile(os.path.join(srcdir, mfname), + command_info['target_name'], target_type) + target_name = expand_makefile_vars('$(%s)' % target_type.upper(), mf) + tcprops = self.read_teamcity_properties(wanted) + if 'vcs_type' in wanted or '*' in wanted: + vcs_info = self.get_vcs_info(srcdir) + else: + vcs_info = None + + self.info['name'] = target_name + if target_type == 'lib': + self.info['type'] = 'library' + else: + self.info['type'] = 'app' + if target_type == 'app' and False: + try: + cmd = [os.path.join('.', target_name), '-version'] + self.info['app_version'] = subprocess.check_output(cmd) + except subprocess.CalledProcessError: + pass + if 'contact' in wanted or '*' in wanted: + self.info['contact'] = self.get_contact(mf) + self.info['start_time'] = start_time + self.info['end_time'] = end_time + self.info['duration'] = (end_time - start_time).total_seconds() + self.info['succeeded'] = status == 0 + if 'teamcity.version' in tcprops: + self.info['build_type'] = 'standard' + else: + self.info['build_type'] = 'legacy' + if 'NCBI_AUTOMATED_BUILD' in os.environ: + self.info['execution_type'] = 'automated' + else: + self.info['execution_type'] = 'manual' + self.info['directory'] = os.getcwd() + self.info['source_directory'] = srcdir + if 'teamcity.build.id' in tcprops: + self.info['build_id'] = tcprops['teamcity.build.id'] + if 'build.number' in tcprops: + self.info['build_number'] = tcprops['build.number'] + if vcs_info is not None: + self.info.update(vcs_info) + self.info['artifact_name'] = target_name + if sc_version is not None and sc_version > 0: + self.info['artifact_version'] = 'SC-%d' % sc_version + else: + self.info['artifact_version'] = 'trunk' + self.info['command_line'] = ' '.join(command) + # deployment-regions -- needs clarification + # devops_step_name -- ??? + if 'env_vars' in wanted or '*' in wanted: + self.info['env_vars'] = dict(os.environ) + if 'teamcity.version' in tcprops: + self.info['tc_vars'] = tcprops + if 'teamcity.agent.name' in tcprops: + self.info['tc_agent_name'] = tcprops['teamcity.agent.name'] + elif 'build_config' in wanted or '*' in wanted: + bcfg = {} + with open(os.path.join(status_dir, 'config.log'), 'r') as f: + uid = os.fstat(f.fileno()).st_uid + try: + bcfg['user_id'] = pwd.getpwuid(uid)[0] + except: + bcfg['user_id'] = uid + for l in f: + if l.startswith(' $ '): + bcfg['command'] = l[4:].rstrip('\n') + elif l.startswith('hostname = '): + bcfg['host'] = l[11:].rstrip('\n') + elif ' configurables below ' in l: + bcfg['cwd'] = l[l.find(' below ') + 7:].rstrip('.\n') + self.info['build_config'] = bcfg + + def get_as_string(self, name): + v = self.info[name] + if isinstance(v, str): + return v + elif isinstance(v, bool): + if v: + return 'T' + else: + return 'F' + elif isinstance(v, date): + return v.isoformat() + else: + return repr(v) + + def parse_command(self, command): + if command[0].endswith('.sh'): + raise IrrelevantCommandError + + irrelevant_re = re.compile(r'(?:check|clean|export-headers' + + r'|mark-as-disabled|purge|requirements' + + r'|sources)(?:[._].+)?$') + template_re = re.compile(r'/Makefile\.(app|lib).tmpl$') + wrapper_re = re.compile(r'Makefile\.(.*)_(app|lib)$') + + info = {} + irrelevant_targets = [] + relevant_targets = [] + value_expected = False + for x in command[1:]: + if value_expected: + match_info = wrapper_re.match(x) + if match_info is not None: + (info['target_name'], info['target_type']) \ + = match_info.groups() + info['srcdir'] = '.' + else: + match_info = template_re.search(x) + if match_info is not None: + info['target_type'] = match_info.group(1) + value_expected = False + elif len(x) == 2 and x[0] == '-' and x[1] in 'CIWfo': + value_expected = True + elif irrelevant_re.match(x) is not None: + irrelevant_targets.append(x) + elif x.startswith('TMPL='): + info['target_name'] = x[5:] + elif x.startswith('srcdir='): + info['srcdir'] = x[7:] + elif x[0] != '-' and not '=' in x: + relevant_targets.append(x) + if len(info) < 3 \ + or (len(irrelevant_targets) > 0 and len(relevant_targets) == 0): + raise IrrelevantCommandError + return info + + def get_srcdir(self, command_info, mfname): + if 'srcdir' in command_info: + return command_info['srcdir'] + elif os.path.exists(mfname): + return '.' + elif os.path.exists('Makefile'): + mf = parse_makefile('Makefile') + return expand_makefile_vars('$(srcdir)', mf) + else: + return re.sub('/[^/]*/build/', '/src/', os.getcwd()) + + def read_makefile(self, mfpath, target_name, target_type): + try: + return parse_makefile(mfpath) + except IOError: + return { target_type.upper(): target_name } + + def read_teamcity_properties(self, wanted): + props = {} + if 'TEAMCITY_BUILD_PROPERTIES_FILE' in os.environ and \ + ('build_type' in wanted or 'build_id' in wanted + or 'build_number' in wanted or 'tc_vars' in wanted + or 'tc_agent_name' in wanted or '*' in wanted): + fname = os.environ['TEAMCITY_BUILD_PROPERTIES_FILE'] + try: + with open(fname, 'r') as f: + prop_re = re.compile(r'((?:(?![:=])\S|\\.)+)' + + r'(?:\s*[:=]\s*|\s+)(.*)') + for l in f: + l = l.lstrip() + if len(l) == 0 or l[0] in '#!': + continue + l = l.rstrip('\n') + while (l.endswith('\\')): + l = l.rstrip('\\') + f.next().lstrip().rstrip('\n') + mi = prop_re.match(l) + if mi is None: + warn('Malformed line in ' + fname + ': ' + l) + else: + k = ast.literal_eval("'''"+mi.group(1)+"'''") + v = ast.literal_eval("'''"+mi.group(2)+"'''") + props[k] = v + except Exception as e: + warn("Failed to open %s: %s" % (fname, e)) + pass + if len(props) == 0: + if 'NCBI_BUILD_SESSION_ID' in os.environ: + props['build.number'] = os.environ['NCBI_BUILD_SESSION_ID'] + # Synthesize anything else? + pass + return props + + def get_vcs_info(self, srcdir, rest = (), fallback = None): + if os.path.isdir(os.path.join(srcdir, '.svn')): + return self.get_svn_info(srcdir, rest) + elif os.path.isdir(os.path.join(srcdir, '.git')): + return self.get_git_info(srcdir, rest) + elif len(rest) == 0 and os.path.isdir(os.path.join(srcdir, 'CVS')): + return self.get_cvs_info(srcdir) + elif os.path.isfile(os.path.join(srcdir, + 'include/common/ncbi_package_ver.h')): + fallback = self.get_package_info(srcdir, rest) + + if srcdir != '/': + (d, b) = os.path.split(srcdir) + return self.get_vcs_info(d, (b,) + rest, fallback) + else: + return fallback + + def get_svn_info(self, srcdir, rest): + info = { 'vcs_type': 'svn' } + with subprocess.Popen(['svn', 'info', os.path.join(srcdir, *rest)], + stdout = subprocess.PIPE, + stderr = subprocess.DEVNULL, + universal_newlines = True) as svn: + for l in svn.stdout: + (k, v) = l.rstrip('\n').split(': ', 1) + if k == 'URL': + info['vcs_path'] = v + if '/trunk/' in v: + info['vcs_branch'] = 'trunk' + else: + match_info = re.search('/components/[^/]+/([0-9.]+)/', + v) + if match_info is not None: + info['vcs_branch'] = 'SC-' + match_info.group(1) + else: + match_info = re.search('/branches/([^/]+)/', v) + if match_info is not None: + info['vcs_branch'] = match_info.group(1) + break + if 'vcs_path' not in info: + # Maybe controlled by git after all, in a hybrid layout? + if os.path.isdir(os.path.join(srcdir, '.git')): + return self.get_git_info(srcdir, rest) + while srcdir != '/': + (srcdir, child) = os.path.split(srcdir) + if os.path.isdir(os.path.join(srcdir, '.git')): + return self.get_git_info(srcdir, (child,) + rest) + return None + return info + + def get_git_info(self, srcdir, rest): + info = { 'vcs_type': 'git' } + git = os.environ.get('TEAMCITY_GIT_PATH', 'git') + try: + cmd = [git, 'remote', 'get-url', 'origin'] + url = subprocess.check_output(cmd, stderr = subprocess.DEVNULL, + universal_newlines = True, + cwd = srcdir) + url = url.rstrip('\n') + if len(rest) > 0: + url = url + '#' + os.path.join(*rest) + info['vcs_path'] = url + except subprocess.CalledProcessError: + try: + cmd = [git, 'remote', 'show', 'origin'] + with subprocess.Popen(cmd, stdout = subprocess.PIPE, + stderr = subprocess.DEVNULL, + universal_newlines = True, + cwd = srcdir) as remote: + for l in remote.stdout: + (k, v) = l.strip().split(': ', 1) + if k == 'Fetch URL': + url = v + if len(rest) > 0: + url = url + '#' + os.path.join(*rest) + info['vcs_path'] = url + break + except subprocess.CalledProcessError: + pass + if 'vcs_path' not in info: + info['vcs_path'] = 'file://' + os.path.join(srcdir, *rest) + try: + cmd = [git, 'rev-parse', '--symbolic-full-name', 'HEAD'] + rev = subprocess.check_output(cmd, stderr = subprocess.DEVNULL, + universal_newlines = True, + cwd = srcdir) + rev = rev.rstrip('\n') + info['vcs_branch'] = re.sub(r'^refs/(?:heads|tags)/', '', rev) + except subprocess.CalledProcessError: + pass + if 'vcs_branch' not in info and info['vcs_path'].startswith('file://'): + # Maybe controlled by Subversion after all, in a hybrid layout? + # (No need to check for .svn at this level, because get_svn_info + # looks for it first.) + while srcdir != '/': + (srcdir, child) = os.path.split(srcdir) + if os.path.isdir(os.path.join(srcdir, '.svn')): + return self.get_svn_info(srcdir, (child,) + rest) + return None + return info + + def get_cvs_info(self, srcdir): + info = { 'vcs_type': 'cvs' } + cvs_dir = os.path.join(srcdir, 'CVS') + with open(os.path.join(cvs_dir, 'Root'), 'r') as f: + cvs_root = f.getline().rstrip('\n') + with open(os.path.join(cvs_dir, 'Repository'), 'r') as f: + cvs_path = f.getline().rstrip('\n') + if cvs_path.startswith('/'): + pos = cvs_root.find(':') + 1 + info['vcs_path'] = cvs_root[:pos] + cvs_path + else: + info['vcs_path'] = cvs_root + '/' + cvs_path + with open(os.path.join(cvs_dir, 'Entries'), 'r') as f: + l = f.getline().rstrip('\n') + match_info = re.match(r'/.*?/.*?/.*?/.*?/[^D](.+)', l) + if match_info is None: + info['vcs_branch'] = 'HEAD' + else: + info['vcs_branch'] = match_info.group(1) + return info + + def get_package_info(self, srcdir, rest): + filename = os.path.join(srcdir, 'include/common/ncbi_package_ver.h') + package_name = None + version = [None, None, None] + with open(filename) as f: + for l in f: + if l.startswith('#define NCBI_PACKAGE_'): + words = l.split() + if words[1] == 'NCBI_PACKAGE_NAME': + package_name = words[2].strip('"') + elif words[1] == 'NCBI_PACKAGE_VERSION_MAJOR': + version[0] = words[2] + elif words[1] == 'NCBI_PACKAGE_VERSION_MINOR': + version[1] = words[2] + elif words[1] == 'NCBI_PACKAGE_VERSION_PATCH': + version[2] = words[2] + if package_name is not None and version[0] is not None \ + and version[1] is not None and version[2] is not None: + base = 'https://svn.ncbi.nlm.nih.gov/repos/toolkit/release' + version = '.'.join(version) + url = '/'.join([base, package_name, version, 'c++'] + rest) + return { 'vcs_type': 'svn', + 'vcs_path': url, + 'vcs_branch': package_name + '-' + version } + return None + + def get_contact(self, mf): + next_dir = os.getcwd() + while mf is not None: + if 'WATCHERS' in mf: + return expand_makefile_vars('$(WATCHERS)', mf) + elif next_dir is None: + break + mfname = os.path.join(next_dir, 'Makefile') + if os.path.exists(mfname): + mf = parse_makefile(mfname) + else: + break + if next_dir == '/': + next_dir = None + else: + next_dir = os.path.dirname(next_dir) + + return '-' + # if 'LOGNAME' in os.environ: + # return os.environ['LOGNAME'] + # elif 'USER' in os.environ: + # return os.environ['USER'] + # else: + # uid = os.getuid() + # try: + # return pwd.getpwuid(uid)[0] + # except: + # return str(uid) diff --git a/c++/scripts/common/impl/update_configurable.sh b/c++/scripts/common/impl/update_configurable.sh index 90250b57..560e6df2 100755 --- a/c++/scripts/common/impl/update_configurable.sh +++ b/c++/scripts/common/impl/update_configurable.sh @@ -87,7 +87,7 @@ case $output in src=./src/build-system/Makefile.mk.in "$builddir/Makefile.mk" ;; - *.sh) + *.sh | *.py ) chmod +x $output ;; diff --git a/c++/scripts/common/impl/yaml.py b/c++/scripts/common/impl/yaml.py new file mode 100644 index 00000000..dff5e93d --- /dev/null +++ b/c++/scripts/common/impl/yaml.py @@ -0,0 +1,110 @@ +# $Id: yaml.py 541405 2017-07-18 13:19:07Z ivanov $ +# Barebones YAML dumper for run_cd_reporter.py(.in). +import datetime +import math +import numbers +import re + +yes_pattern = r'^(?:[Yy]|[Yy]es|YES|[Tt]rue|TRUE|[^Oo]n|ON)$' +no_pattern = r'^(?:[Nn]o?|NO|[Ff]alse|FALSE|[Oo]ff|OFF)$' +null_pattern = r'^(?:[Nn]ull|NULL|\~|)$' +float_pattern = r'^[-+]?(?:\d[0-9_]*(?:\.[0-9_]*)?|\.[0-9_]*)(?:[Ee][+-]?\d+)?$' +flt60_pattern = r'^[-+]?\d[0-9_]*(?::[0-5]?\d)+\.[0-9_]*$' +inf_pattern = r'^[-+]?\.(?:[Ii]nf|INF)$' +nan_pattern = r'^\.(?:nan|NaN|NAN)$' +int_pattern = r'^(?:0|[-+]?[1-9][0-9_]+)$' +int2_pattern = r'^[-+]?0b[01_]+$' +int8_pattern = r'^[-+]?0[0-7]+$' +int16_pattern = r'^[-+]?0x[0-9a-fA-F_]+$' +int60_pattern = r'^[-+]?[1-9][0-9_]*(?::[0-5]?\d)+$' +time_pattern = (r'^\d{4}-(?:\d\d-\d\d|\d\d?-\d\d?(?:[Tt]|\s+)\d\d?:\d\d?:\d\d?' + + r'(?:\.\d+)?(?:\s*(?:Z|[-+]\d\d?(?::\d\d)?))?)$') +special_patterns = (r'[^$()+./0-9;A-Z^_a-z]', + r'^\.\.\.$', + yes_pattern, + no_pattern, + null_pattern, + float_pattern, + flt60_pattern, + inf_pattern, + nan_pattern, + int_pattern, + int2_pattern, + int8_pattern, + int16_pattern, + int60_pattern, + time_pattern) + +special_re = re.compile('|'.join(special_patterns)) + +class Dumper(object): + def __init__(self, stream, indent = ''): + self.stream = stream + self.indent = indent + + def is_scalar(self, x): + return (isinstance(x, bool) or isinstance(x, str) + or isinstance(x, numbers.Real) or isinstance(x, datetime.date) + or len(x) == 0) + + def dump(self, x): + if x is None: + self.stream.write('~') + if isinstance(x, bool): + if x: + self.stream.write('y') + else: + self.stream.write('n') + elif isinstance(x, str): + if special_re.search(x) is None: + self.stream.write(x) + else: + self.stream.write('"' + re.escape(x) + '"') + elif isinstance(x, numbers.Real): + if math.isinf(x): + if x < 0: + self.stream.write('-') + self.stream.write('.inf') + elif math.isnan(x): + self.stream.write('.nan') + else: + self.stream.write(repr(x)) + elif isinstance(x, datetime.date): + self.stream.write(x.isoformat()) + elif len(x) == 0: + if isinstance(x, dict): + self.stream.write('{}') + else: # list or tuple + self.stream.write('[]') + else: + d = Dumper(self.stream, self.indent + ' ') + if isinstance(x, dict): + for k, v in x.items(): + self.stream.write(self.indent) + d.dump(k) + self.stream.write(':') + if self.is_scalar(v): + self.stream.write(' ') + d.dump(v) + self.stream.write("\n") + else: + self.stream.write("\n") + d.dump(v) + elif isinstance(x, list) or isinstance(x, tuple): + for v in x: + self.stream.write(self.indent + '-') + if self.is_scalar(v): + self.stream.write(' ') + d.dump(v) + self.stream.write("\n") + else: + self.stream.write("\n") + d.dump(v) + else: + raise TypeError(x) + +def dump(x, stream, Dumper=Dumper): + d = Dumper(stream) + d.dump(x) + if d.is_scalar(x): + stream.write("\n") diff --git a/c++/scripts/common/project_utilits.js b/c++/scripts/common/project_utilits.js index 448d66bc..64c1bd96 100644 --- a/c++/scripts/common/project_utilits.js +++ b/c++/scripts/common/project_utilits.js @@ -1,4 +1,4 @@ -// $Id: project_utilits.js 501454 2016-05-16 15:12:21Z elisovdn $ +// $Id: project_utilits.js 525933 2017-01-30 16:20:38Z gouriano $ //////////////////////////////////////////////////////////////////////////////////// // Shared part of new_project.wsf and import_project.wsf // global settings @@ -11,8 +11,8 @@ var g_def_branch = "toolkit/trunk/internal/c++"; var g_branch = "toolkit/trunk/internal/c++"; // valid: "120", "120x64", "140", "140x64" -var g_def_msvcver = "120"; -var g_msvcver = "120"; +var g_def_msvcver = "120x64"; +var g_msvcver = "120x64"; //////////////////////////////////////////////////////////////////////////////////// // Utility functions : diff --git a/c++/scripts/projects/blast/Manifest b/c++/scripts/projects/blast/Manifest index 566bafce..b8803d62 100644 --- a/c++/scripts/projects/blast/Manifest +++ b/c++/scripts/projects/blast/Manifest @@ -1,7 +1,7 @@ # # Filename: Manifest # -# $Id: Manifest 512796 2016-09-02 19:46:40Z camacho $ +# $Id: Manifest 548683 2017-10-17 14:38:19Z camacho $ # # Author: Christiam Camacho # @@ -42,8 +42,9 @@ DEFAULT_CONFIGURE_FLAGS: --without-debug --with-strip --with-openmp --with-mt -- # that. The build-root is needed so that rpmbuild can find the proper directories # to copy the binaries from Linux64-Centos : icc : ICC.sh --with-bin-release --with-strip --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-experimental=Int8GI --without-vdb --with-gnutls=/netopt/ncbi_tools64/gnutls-3.4.0 --without-gcrypt -#Linux64-Centos : gcc : GCC.sh --with-bin-release --with-strip --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-experimental=Int8GI --without-vdb -#Linux64-Centos : gcc-debug : GCC.sh --with-strip --with-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-experimental=Int8GI --without-vdb +#Linux64-Centos : gcc : GCC.sh --with-bin-release --with-strip --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-experimental=Int8GI --without-vdb --with-gnutls --without-gcrypt +#Linux64-Centos : gcc-debug : GCC.sh --with-strip --with-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-experimental=Int8GI --without-vdb --with-gnutls --without-gcrypt + DEFAULT_CONFIGURATIONS: Linux64-Centos:icc #DEFAULT_CONFIGURATIONS: Linux64-Centos:gcc @@ -53,6 +54,6 @@ Win64 : plain : static 64 ReleaseDLL NCBI_CONFIG____ENABLEDUSERRE #IntelMAC : gcc : GCC.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --without-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt #IntelMAC : clang : Clang.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --without-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt -IntelMAC-Clang36 : clang : Clang.sh 7.0.2 --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --without-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt +IntelMAC-Clang36 : clang : Clang.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --without-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt USE_COMPONENTS diff --git a/c++/scripts/projects/blast/components.link b/c++/scripts/projects/blast/components.link index 86d2dd20..33ba9b61 100644 --- a/c++/scripts/projects/blast/components.link +++ b/c++/scripts/projects/blast/components.link @@ -1,9 +1,9 @@ [components] -infrastructure 18.0 -core 18.0 -dbase 18.0 -web 18.0 -objects 18.0 -objtools 18.0 -algo 18.0 -app 18.0 +infrastructure 20.0 +core 20.0 +dbase 20.0 +web 20.0 +objects 20.0 +objtools 20.0 +algo 20.0 +app 20.0 diff --git a/c++/scripts/projects/blast/post_build/make_installers.py b/c++/scripts/projects/blast/post_build/make_installers.py index 11573872..b8f13fa0 100755 --- a/c++/scripts/projects/blast/post_build/make_installers.py +++ b/c++/scripts/projects/blast/post_build/make_installers.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """Driver program for post-build processing""" -# $Id: make_installers.py 512684 2016-09-01 22:19:28Z camacho $ +# $Id: make_installers.py 545489 2017-09-06 21:42:27Z camacho $ # # Author: Christiam Camacho # @@ -53,6 +53,8 @@ def main(): #IGNORE:R0911 shutil.copy(libdir + "libhogweed-4-2.dll", installdir + "bin") shutil.copy(libdir + "libnettle-6-2.dll", installdir + "bin") shutil.copy(libdir + "libp11-kit-0.dll", installdir + "bin") + shutil.copy(libdir + "msvcp120.dll", installdir + "bin") + shutil.copy(libdir + "msvcr120.dll", installdir + "bin") return launch_win_installer_build(installdir, blast_version) if platform.startswith("Linux64"): return launch_rpm_build(installdir, blast_version, srctarball) diff --git a/c++/scripts/projects/blast/post_build/rpm/make_rpm.py b/c++/scripts/projects/blast/post_build/rpm/make_rpm.py index 91827091..243aea85 100755 --- a/c++/scripts/projects/blast/post_build/rpm/make_rpm.py +++ b/c++/scripts/projects/blast/post_build/rpm/make_rpm.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """Script to create a source/binary RPM. """ -# $Id: make_rpm.py 496041 2016-03-23 14:47:36Z camacho $ +# $Id: make_rpm.py 548925 2017-10-18 21:56:59Z fukanchi $ from __future__ import print_function import sys, os, shutil @@ -120,7 +120,7 @@ def run_rpm(blast_version): dest = os.path.join(RPMBUILD_HOME, "SPECS", rpm_spec) shutil.copyfile(src, dest) update_blast_version(dest, blast_version) - cmd = "/usr/bin/rpmbuild -ba " + dest + cmd = "/usr/bin/rpmbuild -v -ba " + dest safe_exec(cmd) def move_rpms_to_installdir(installdir): diff --git a/c++/scripts/projects/blast/post_build/rpm/ncbi-blast.spec b/c++/scripts/projects/blast/post_build/rpm/ncbi-blast.spec index 61c7d626..21c980af 100644 --- a/c++/scripts/projects/blast/post_build/rpm/ncbi-blast.spec +++ b/c++/scripts/projects/blast/post_build/rpm/ncbi-blast.spec @@ -2,7 +2,7 @@ Name: ncbi-blast Version: BLAST_VERSION+ Release: 1 Source0: %{name}-%{version}.tgz -Summary: NCBI BLAST finds regions of similarity between biological sequences. +Summary: NCBI BLAST finds regions of similarity between biological sequences. Exclusiveos: linux Group: NCBI/BLAST License: Public Domain @@ -11,48 +11,49 @@ BuildRoot: /var/tmp/%{name}-buildroot Prefix: /usr AutoReqProv: no -Requires: /usr/bin/perl -Requires: ld-linux-x86-64.so.2()(64bit) -Requires: ld-linux-x86-64.so.2(GLIBC_2.3)(64bit) -Requires: libbz2.so.1()(64bit) -Requires: libc.so.6()(64bit) -Requires: libc.so.6(GLIBC_2.2.5)(64bit) -Requires: libc.so.6(GLIBC_2.3)(64bit) -Requires: libc.so.6(GLIBC_2.3.2)(64bit) -Requires: libc.so.6(GLIBC_2.7)(64bit) -Requires: libdl.so.2()(64bit) -Requires: libdl.so.2(GLIBC_2.2.5)(64bit) -Requires: libgcc_s.so.1()(64bit) -Requires: libgcc_s.so.1(GCC_3.0)(64bit) -Requires: libm.so.6()(64bit) -Requires: libm.so.6(GLIBC_2.2.5)(64bit) -Requires: libnsl.so.1()(64bit) -Requires: libpthread.so.0()(64bit) -Requires: libpthread.so.0(GLIBC_2.2.5)(64bit) -Requires: libpthread.so.0(GLIBC_2.3.2)(64bit) -Requires: librt.so.1()(64bit) -Requires: libstdc++.so.6()(64bit) -Requires: libstdc++.so.6(CXXABI_1.3)(64bit) -Requires: libstdc++.so.6(CXXABI_1.3.1)(64bit) -Requires: libstdc++.so.6(GLIBCXX_3.4)(64bit) -Requires: libstdc++.so.6(GLIBCXX_3.4.5)(64bit) -Requires: libz.so.1()(64bit) -Requires: libz.so.1(ZLIB_1.2.0)(64bit) -Requires: perl(Archive::Tar) -Requires: perl(Digest::MD5) -Requires: perl(File::Temp) -Requires: perl(File::stat) -Requires: perl(Getopt::Long) -Requires: perl(List::MoreUtils) -Requires: perl(Net::FTP) -Requires: perl(Pod::Usage) -Requires: perl(constant) -Requires: perl(strict) -Requires: perl(warnings) +Requires: /usr/bin/perl +Requires: ld-linux-x86-64.so.2()(64bit) +Requires: ld-linux-x86-64.so.2(GLIBC_2.3)(64bit) +Requires: libbz2.so.1()(64bit) +Requires: libc.so.6()(64bit) +Requires: libc.so.6(GLIBC_2.2.5)(64bit) +Requires: libc.so.6(GLIBC_2.3)(64bit) +Requires: libc.so.6(GLIBC_2.3.2)(64bit) +Requires: libc.so.6(GLIBC_2.7)(64bit) +Requires: libdl.so.2()(64bit) +Requires: libdl.so.2(GLIBC_2.2.5)(64bit) +Requires: libgcc_s.so.1()(64bit) +Requires: libgcc_s.so.1(GCC_3.0)(64bit) +Requires: libm.so.6()(64bit) +Requires: libm.so.6(GLIBC_2.2.5)(64bit) +Requires: libnsl.so.1()(64bit) +Requires: libpthread.so.0()(64bit) +Requires: libpthread.so.0(GLIBC_2.2.5)(64bit) +Requires: libpthread.so.0(GLIBC_2.3.2)(64bit) +Requires: librt.so.1()(64bit) +Requires: libstdc++.so.6()(64bit) +Requires: libstdc++.so.6(CXXABI_1.3)(64bit) +Requires: libstdc++.so.6(CXXABI_1.3.1)(64bit) +Requires: libstdc++.so.6(GLIBCXX_3.4)(64bit) +Requires: libstdc++.so.6(GLIBCXX_3.4.5)(64bit) +Requires: libz.so.1()(64bit) +Requires: libz.so.1(ZLIB_1.2.0)(64bit) +Requires: perl(Archive::Tar) +Requires: perl(Digest::MD5) +Requires: perl(File::Temp) +Requires: perl(File::stat) +Requires: perl(Getopt::Long) +Requires: perl(List::MoreUtils) +Requires: perl(Net::FTP) +Requires: perl(Pod::Usage) +Requires: perl(constant) +Requires: perl(strict) +Requires: perl(warnings) Requires: rpmlib(CompressedFileNames) <= 3.0.4-1 Requires: rpmlib(FileDigests) <= 4.6.0-1 Requires: rpmlib(PayloadFilesHavePrefix) <= 4.0-1 Requires: rpmlib(PayloadIsXz) <= 5.2-1 +BuildRequires: gnutls-devel >= 2.8 %description The NCBI Basic Local Alignment Search Tool (BLAST) finds regions of @@ -62,11 +63,11 @@ significance of matches. BLAST can be used to infer functional and evolutionary relationships between sequences as well as help identify members of gene families. -%prep +%prep %setup -q %build -./configure +./configure || ./configure --manifest-config=Linux64-Centos:gcc cd c++/*/build %__make -f Makefile.flat diff --git a/c++/scripts/projects/blast/post_build/win/make_win.py b/c++/scripts/projects/blast/post_build/win/make_win.py index 0d4b51b7..3737b833 100644 --- a/c++/scripts/projects/blast/post_build/win/make_win.py +++ b/c++/scripts/projects/blast/post_build/win/make_win.py @@ -1,6 +1,6 @@ #! /usr/bin/env python3 """Script to create the Windows installer for BLAST command line applications""" -# $Id: make_win.py 511374 2016-08-22 13:18:52Z camacho $ +# $Id: make_win.py 545489 2017-09-06 21:42:27Z camacho $ # # Author: Christiam camacho @@ -68,7 +68,9 @@ def main(): "libgnutls-30.dll", "libhogweed-4-2.dll", "libnettle-6-2.dll", - "libp11-kit-0.dll" + "libp11-kit-0.dll", + "msvcp120.dll", + "msvcr120.dll" ] cwd = os.getcwd() diff --git a/c++/scripts/projects/blast/post_build/win/ncbi-blast.nsi b/c++/scripts/projects/blast/post_build/win/ncbi-blast.nsi index 593b76fa..3e605aae 100755 --- a/c++/scripts/projects/blast/post_build/win/ncbi-blast.nsi +++ b/c++/scripts/projects/blast/post_build/win/ncbi-blast.nsi @@ -87,6 +87,8 @@ Section "DefaultSection" SecDflt File "libhogweed-4-2.dll" File "libnettle-6-2.dll" File "libp11-kit-0.dll" + File "msvcp120.dll" + File "msvcr120.dll" SetOutPath "$INSTDIR\doc" File "README.txt" @@ -136,6 +138,8 @@ Section "Uninstall" Delete "$INSTDIR\bin\libhogweed-4-2.dll" Delete "$INSTDIR\bin\libnettle-6-2.dll" Delete "$INSTDIR\bin\libp11-kit-0.dll" + Delete "$INSTDIR\bin\msvcp120.dll" + Delete "$INSTDIR\bin\msvcr120.dll" Delete "$INSTDIR\doc\README.txt" RmDir "$INSTDIR\bin" RmDir "$INSTDIR\doc" diff --git a/c++/scripts/projects/blast/project.lst b/c++/scripts/projects/blast/project.lst index 3c970875..3968fe7d 100644 --- a/c++/scripts/projects/blast/project.lst +++ b/c++/scripts/projects/blast/project.lst @@ -1,4 +1,6 @@ corelib$ +db$ +db/sqlite serial$ serial/impl$ serial/datatool @@ -11,6 +13,8 @@ algo/blast/composition_adjustment algo/blast/dbindex algo/blast/format algo/blast/unit_tests +algo/blast/proteinkmer +-algo/blast/proteinkmer/demo algo/blast/igblast algo/dustmask$ algo/winmask$ @@ -22,6 +26,7 @@ cgi$ cgi/impl$ html$ connect$ +connect/mbedtls connect/services -connect/services/test connect/ext$ diff --git a/c++/scripts/projects/clog.lst b/c++/scripts/projects/clog.lst new file mode 100644 index 00000000..7038da02 --- /dev/null +++ b/c++/scripts/projects/clog.lst @@ -0,0 +1,10 @@ +corelib$ +connect$ +./include/util/bitset$ +util$ +util/regexp$ +util/xregexp$ +misc$ +misc/clog +misc/third_party +misc/third_party_static diff --git a/c++/scripts/projects/cobalt/ChangeLog b/c++/scripts/projects/cobalt/ChangeLog index bce23fe2..67782393 100644 --- a/c++/scripts/projects/cobalt/ChangeLog +++ b/c++/scripts/projects/cobalt/ChangeLog @@ -19,3 +19,11 @@ Bug fixes: * Nexus alignment format * Segmentation fault on out-of-memory * Alignment problems with clustering input sequences + +January 31, 2017 +2.1.0 release +Improvements: +* More memory efficient sequence clustering +* No longer prints warning message about all sequences in one cluster +Bug fixes: +* Fixed clustering results for sequences with ambiguous amino acids diff --git a/c++/scripts/projects/cobalt/LICENSE b/c++/scripts/projects/cobalt/LICENSE index f3577c23..dd0d332f 100644 --- a/c++/scripts/projects/cobalt/LICENSE +++ b/c++/scripts/projects/cobalt/LICENSE @@ -17,3 +17,4 @@ purpose. Please cite the author in any work or product based on this material. + diff --git a/c++/scripts/projects/cobalt/Manifest b/c++/scripts/projects/cobalt/Manifest index ca069404..48b45239 100644 --- a/c++/scripts/projects/cobalt/Manifest +++ b/c++/scripts/projects/cobalt/Manifest @@ -1,7 +1,9 @@ # # Filename: Manifest # -# Author: Greg Boratyn +# $Id $ +# +# Author: Christiam Camacho, Greg Boratyn # # Purpose: This file holds all the supported configurations of a package # It is used by release configurator. @@ -17,6 +19,10 @@ # post_build/macosx/ncbi-blast.sh, and post_build/rpm/ncbi-blast.spec APP: cobalt +POSTBUILD: $srcdir/scripts/projects/cobalt/post_build/make_installers.py -v $version $platform $installdir "$tarball" + +DEFAULT_CONFIGURE_FLAGS: --without-debug --with-strip --with-openmp --with-mt --with-build-root=$srcdir/ReleaseMT --without-vdb + # Each line describes a single configuration # The format is as follows: # : : @@ -28,15 +34,17 @@ APP: cobalt # ICC gives us about 10% improvement in the core2 microarchitecture, so prefer # that. The build-root is needed so that rpmbuild can find the proper directories # to copy the binaries from -Linux32-Centos : icc : ICC.sh --with-strip --without-debug --without-pcre --with-mt --with-flat-makefile -Linux64-Centos : icc : ICC.sh --with-strip --without-debug --without-pcre --with-mt --with-flat-makefile +Linux64-Centos : icc : ICC.sh --with-bin-release --with-strip --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-experimental=Int8GI --without-vdb --without-gnutls --without-gcrypt +#Linux64-Centos : gcc : GCC.sh --with-bin-release --with-strip --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-experimental=Int8GI --without-vdb --without-gnutls --without-gcrypt +#Linux64-Centos : gcc-debug : GCC.sh --with-strip --with-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --without-vdb -DEFAULT_CONFIGURATIONS: Linux32-Centos:icc Linux64-Centos:icc +DEFAULT_CONFIGURATIONS: Linux64-Centos:icc +#DEFAULT_CONFIGURATIONS: Linux64-Centos:gcc -Win32_13 : plain : static 32 ReleaseMT -Win64_13 : plain : static 64 ReleaseMT +Win64 : plain : static 64 ReleaseDLL NCBI_CONFIG____ENABLEDUSERREQUESTS__NCBI-INT8-GI=1 -IntelMAC : gcc : GCC.sh --without-debug --without-pcre --with-mt --with-flat-makefile --with-ncbi-public +#IntelMAC : gcc : GCC.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --without-vdb --without-gnutls --without-gcrypt +#IntelMAC : clang : Clang.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --without-vdb --without-gnutls --without-gcrypt +IntelMAC-Clang36 : clang : Clang.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --without-vdb --without-gnutls --without-gcrypt USE_COMPONENTS - diff --git a/c++/scripts/projects/cobalt/components.link b/c++/scripts/projects/cobalt/components.link index 772d8895..33ba9b61 100644 --- a/c++/scripts/projects/cobalt/components.link +++ b/c++/scripts/projects/cobalt/components.link @@ -1,10 +1,9 @@ [components] -infrastructure 12.0 -core 12.0 -dbase 12.0 -web 12.0 -objects 12.0 -objtools 12.0 -algo 12.0 -blast 12.0 -app 12.0 +infrastructure 20.0 +core 20.0 +dbase 20.0 +web 20.0 +objects 20.0 +objtools 20.0 +algo 20.0 +app 20.0 diff --git a/c++/scripts/projects/cobalt/post_build/blast_utils.py b/c++/scripts/projects/cobalt/post_build/blast_utils.py new file mode 100644 index 00000000..2209bef5 --- /dev/null +++ b/c++/scripts/projects/cobalt/post_build/blast_utils.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 +""" Various utilities/tools for BLAST """ +from __future__ import print_function + +__all__ = ["safe_exec", "update_blast_version"] + +import os +import subprocess +import platform +import unittest +import tempfile +import re + + +def safe_exec(cmd): + """ Executes a command and checks its return value, throwing an + exception if it fails. + """ + try: + msg = "Command: '" + cmd + "' " + retcode = subprocess.call(cmd, shell=True) + if retcode < 0: + msg += "Termined by signal " + str(-retcode) + raise RuntimeError(msg) + elif retcode != 0: + msg += "Failed with exit code " + str(retcode) + raise RuntimeError(msg) + except OSError as err: + msg += "Execution failed: " + err + raise RuntimeError(msg) + + +class Tester(unittest.TestCase): + '''Testing class for this script.''' + def test_one(self): + ver = "2.3.0" + line1 = "Hello BLAST" + with tempfile.NamedTemporaryFile(mode='w+t') as fp: + print(line1, file=fp) + print("BLAST_VERSION", file=fp) + print(line1, file=fp, flush=True) + + update_blast_version(fp.name, ver) + + fp.seek(0) + line = fp.readline().rstrip() + self.assertEqual(line1, line) + line = fp.readline().rstrip() + self.assertEqual(ver, line) + line = fp.readline().rstrip() + self.assertEqual(line1, line) + + +def update_blast_version(config_file, ver): + """Updates the BLAST version in the specified file. + + Assumes the specified file contains the string BLAST_VERSION, which will + be replaced by the contents of the variable passed to this function. + """ + (fd, fname) = tempfile.mkstemp() + try: + with open(config_file, "r") as infile, open(fname, "w") as out: + for line in infile: + newline = re.sub("BLAST_VERSION", ver, line.rstrip()) + print(newline, file=out) + + with open(config_file, "w") as out, open(fname, "r") as infile: + for line in infile: + print(line.rstrip(), file=out) + finally: + os.close(fd) + os.remove(fname) + + +def create_new_tarball_name(platform, program, version): + """ Converts the name of a platform as specified to the prepare_release + framework to an archive name according to BLAST release naming conventions. + + Note: the platform names come from the prepare_release script conventions, + more information can be found in http://mini.ncbi.nih.gov/3oo + """ + + retval = "ncbi-" + program + "-" + version + if program == "blast": + retval += "+" + if platform.startswith("Win"): + retval += "-x64-win64" + elif platform.startswith("Linux32"): + retval += "-ia32-linux" + elif platform.startswith("Linux64"): + retval += "-x64-linux" + elif platform.startswith("IntelMAC"): + retval += "-x64-macosx" + elif platform == "SunOSSparc": + retval += "-sparc64-solaris" + elif platform == "SunOSx86": + retval += "-x64-solaris" + else: + raise RuntimeError("Unknown platform: " + platform) + return retval + + +def determine_platform(): + """ Determines the platform (as defined in prepare_release) for the current + hostname + """ + + p = platform.platform().lower() + print("PLATFORM = " + p) + if p.find("linux") != -1: + if p.find("x86_64") != -1: + return "Linux64" + else: + return "Linux32" + elif p.find("sunos") != -1: + if p.find("sparc") != -1: + return "SunOSSparc" + else: + return "SunOSx86" + elif p.find("windows") != -1 or p.find("cygwin") != -1: + if platform.architecture()[0].find("64") != -1: + return "Win64" + else: + return "Win32" + elif p.find("darwin") != -1: + return "IntelMAC" + else: + raise RuntimeError("Unknown platform: " + p) diff --git a/c++/scripts/projects/cobalt/post_build/macosx/large-Blue_ncbi_logo.tiff b/c++/scripts/projects/cobalt/post_build/macosx/large-Blue_ncbi_logo.tiff new file mode 100644 index 0000000000000000000000000000000000000000..9408bc3f6f6c27e6e3422777f05174acc47dba19 GIT binary patch literal 5536538 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�>DLQ== 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 DZbRBc literal 0 HcmV?d00001 diff --git a/c++/scripts/projects/cobalt/post_build/macosx/ncbi-cobalt.sh b/c++/scripts/projects/cobalt/post_build/macosx/ncbi-cobalt.sh new file mode 100755 index 00000000..d25b6482 --- /dev/null +++ b/c++/scripts/projects/cobalt/post_build/macosx/ncbi-cobalt.sh @@ -0,0 +1,86 @@ +#!/bin/sh -xe + +INSTALLDIR=$1 +SCRIPTDIR=$2 +BLAST_VERSION=$3 +PRODUCT="ncbi-cobalt-$BLAST_VERSION" + +INSTALL_LOCATION1=/usr/local/ncbi/cobalt +INSTALL_LOCATION2=/etc/paths.d +STAGE_DIR1=_stage1 +STAGE_DIR2=_stage2 +RESOURCES_DIR=Resources +ID=gov.nlm.nih.ncbi.cobalt + +if [ $# -ne 3 ] ; then + echo "Usage: ncbi-cobalt.sh [installation directory] [MacOSX post-build script directory] [COBALT version]"; + exit 1; +fi + +setup() +{ + rm -rf $PRODUCT.dmg $PRODUCT $STAGE_DIR1 $STAGE_DIR2 $INSTALLDIR/installer $RESOURCES_DIR + mkdir -p $STAGE_DIR1/bin $STAGE_DIR1/doc $STAGE_DIR2 $PRODUCT +} + +prep_binary_component_package() +{ + BLAST_BINS="cobalt" + ALL_BINS="$BLAST_BINS" + + cp $INSTALLDIR/README $STAGE_DIR1/doc/README.txt + + for bin in $ALL_BINS; do + cp -p $INSTALLDIR/bin/$bin $STAGE_DIR1/bin + done + + /usr/bin/pkgbuild --root $STAGE_DIR1 --identifier $ID.binaries --version \ + $BLAST_VERSION --install-location $INSTALL_LOCATION1 binaries.pkg +} + +prep_paths_component_package() +{ + echo /usr/local/ncbi/cobalt/bin > $STAGE_DIR2/ncbi_cobalt + /usr/bin/pkgbuild --root $STAGE_DIR2 --identifier $ID.paths --version \ + $BLAST_VERSION --install-location $INSTALL_LOCATION2 paths.pkg +} + +customize_distribution_xml() +{ + sed -i.bak '/options/i\ + NCBI COBALT Command Line Applications \ + \ + \ + \ +' Distribution.xml +} + +create_product_archive() +{ + /usr/bin/productbuild --synthesize --identifier $ID --version \ + $BLAST_VERSION --package binaries.pkg --package paths.pkg Distribution.xml + + customize_distribution_xml + + mkdir $RESOURCES_DIR + cp -p $INSTALLDIR/LICENSE $RESOURCES_DIR + for f in welcome.txt large-Blue_ncbi_logo.tiff ; do + cp -p $SCRIPTDIR/$f $RESOURCES_DIR + done + + /usr/bin/productbuild --resources Resources --distribution Distribution.xml $PRODUCT/$PRODUCT.pkg + cp -p $SCRIPTDIR/uninstall_ncbi_cobalt.zip $PRODUCT +} + +create_disk_image() +{ + /usr/bin/hdiutil create $PRODUCT.dmg -srcfolder $PRODUCT + mkdir $INSTALLDIR/installer + mv $PRODUCT.dmg $INSTALLDIR/installer +} + +setup +prep_binary_component_package +prep_paths_component_package +create_product_archive +create_disk_image diff --git a/c++/scripts/projects/cobalt/post_build/macosx/uninstall_ncbi_cobalt.zip b/c++/scripts/projects/cobalt/post_build/macosx/uninstall_ncbi_cobalt.zip new file mode 100644 index 0000000000000000000000000000000000000000..ee712bd475143c1e52ef6ab1443b1806a76650f5 GIT binary patch literal 58655 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 \ + \"\"") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="Show verbose output", dest="VERBOSE") + options, args = parser.parse_args() + if len(args) != 4: + parser.error("Incorrect number of arguments") + return 1 + + blast_version, platform, installdir, srctarball = args + + global VERBOSE #IGNORE:W0603 + VERBOSE = options.VERBOSE + if VERBOSE: + print("BLAST version", blast_version) + print("Platform:", platform) + print("Installation directory:", installdir) + print("Source tarball:", srctarball) + + if platform.startswith("Win"): + return launch_win_installer_build(installdir, blast_version) + if platform.startswith("Linux64"): + return launch_rpm_build(installdir, blast_version, srctarball) + if platform == "FreeBSD32" or platform.startswith("SunOS") or \ + platform.startswith("Linux32"): + return do_nothing(platform) + if platform.startswith("IntelMAC"): + return mac_post_build(installdir, blast_version) + + print("Unknown OS identifier:" + platform, file=sys.stderr) + print("Exiting post build script.", file=sys.stderr) + return 2 + +def launch_win_installer_build(installdir, blast_version): + '''Windows post-build: create installer''' + if VERBOSE: + print("Packaging for Windows...") + cmd = "python " + os.path.join(SCRIPTS_DIR, "win", "make_win.py") + " " + cmd += blast_version + " " + installdir + if VERBOSE: + cmd += " -v" + blast_utils.safe_exec(cmd) + return 0 + +def launch_rpm_build(installdir, blast_version, srctarball): + '''Linux post-build: create RPM''' + if VERBOSE: + print("Packing linux RPM...") + cmd = "python3 " + os.path.join(SCRIPTS_DIR, "rpm", "make_rpm.py") + " " + cmd += blast_version + " " + installdir + " " + srctarball + if VERBOSE: + cmd += " -v" + if len(srctarball) > 2: # Skip for local builds + blast_utils.safe_exec(cmd) + return 0 + +def mac_post_build(installdir, blast_version): + '''MacOSX post-build: create installer''' + if VERBOSE: + print("Packaging for MacOSX...") + script_dir = os.path.join(SCRIPTS_DIR, "macosx") + cmd = os.path.join(script_dir, "ncbi-cobalt.sh") + " " + cmd += installdir + " " + script_dir + " " + blast_version + blast_utils.safe_exec(cmd) + return 0 + +def do_nothing(platform): + '''No op function''' + print("No post-build step necessary for", platform) + return 0 + +# The script execution entry point +if __name__ == "__main__": + sys.exit( main() ) + diff --git a/c++/scripts/projects/cobalt/post_build/rpm/make_rpm.py b/c++/scripts/projects/cobalt/post_build/rpm/make_rpm.py new file mode 100755 index 00000000..1e3ee1b7 --- /dev/null +++ b/c++/scripts/projects/cobalt/post_build/rpm/make_rpm.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python3 +"""Script to create a source/binary RPM. +""" +# $Id: make_rpm.py 524481 2017-01-11 19:03:09Z boratyng $ + +from __future__ import print_function +import sys, os, shutil +from optparse import OptionParser +import subprocess +import tarfile +SCRIPT_DIR = os.path.dirname(os.path.abspath(sys.argv[0])) +sys.path.append(os.path.join(SCRIPT_DIR, "..")) +from blast_utils import * #IGNORE:W0401 + +VERBOSE = False + +# Name of the temporary rpmbuild directory +RPMBUILD_HOME = "rpmbuild" +PACKAGE_NAME = "" +# Name of the source TARBALL to create +TARBALL = "" +# Local RPM configuration file +RPMMACROS = os.path.join(os.path.expanduser("~"), ".rpmmacros") + +def setup_rpmbuild(): + """ Prepare local rpmbuild directory. """ + cleanup_rpm() + os.mkdir(RPMBUILD_HOME) + for directory in [ 'BUILD', 'SOURCES', 'SPECS', 'SRPMS', 'tmp', 'RPMS' ]: + os.mkdir(os.path.join(RPMBUILD_HOME, directory)) + cwd = os.getcwd() + os.chdir(os.path.join(RPMBUILD_HOME, 'RPMS')) + for subdir in [ 'i386', 'i586', 'i686', 'noarch', 'x86_64' ]: + os.mkdir(subdir) + os.chdir(cwd) + + # Create ~/.rpmmacros + with open(RPMMACROS, "w") as out: + print("%_topdir %( echo", os.path.join(cwd, RPMBUILD_HOME), ")", file=out) + print("%_tmppath %( echo", end=' ', file=out) + print(os.path.join(cwd, RPMBUILD_HOME, "tmp"), ")", file=out) + print(file=out) + print("%packager Christiam E. Camacho (camacho@ncbi.nlm.nih.gov)", file=out) + print("%debug_package %{nil}", file=out) + if VERBOSE: + print("Created", RPMMACROS) + +def cleanup_rpm(): + """ Delete rpm files """ + if os.path.exists(RPMBUILD_HOME): + shutil.rmtree(RPMBUILD_HOME) + + if os.path.exists(RPMMACROS): + os.remove(RPMMACROS) + +def cleanup_srctarball_contents(): + """ Remove unnecessary directories/files from svn checkout """ + import fnmatch + + cmd = "find " + PACKAGE_NAME + " -type d -name .svn | xargs rm -fr " + safe_exec(cmd) + + os.remove(os.path.join(PACKAGE_NAME, "Makefile")) + for path in ["builds", "scripts"]: + path = os.path.join(PACKAGE_NAME, path) + if os.path.exists(path): + shutil.rmtree(path) + if VERBOSE: + print("Deleting", path) + + projects_path = os.path.join(PACKAGE_NAME, "c++", "scripts", "projects") + for root, dirs, files in os.walk(projects_path): + for name in files: + name = os.path.join(root, name) + if fnmatch.fnmatch(name, "*blast/*") or fnmatch.fnmatch(name, "*/cobalt/*"): + continue + if VERBOSE: + print("Deleting file", name) + os.remove(name) + + for name in dirs: + name = os.path.join(root, name) + if fnmatch.fnmatch(name, "*blast*") or fnmatch.fnmatch(name, "*/cobalt"): + continue + if VERBOSE: + print("Deleting directory", name) + shutil.rmtree(name) + + +def decompress_src_tarball(srctarball): + """Decompreses the source tarball provided""" + tar = tarfile.open(srctarball) + os.mkdir(PACKAGE_NAME) + cwd = os.getcwd() + os.chdir(os.path.join(cwd, PACKAGE_NAME)) + tar.list() + tar.extractall() + os.chdir(cwd) + cleanup_srctarball_contents() + +def compress_sources(): + """Compress sources to be included in source RPM""" + tar = tarfile.open(TARBALL, "w:bz2") + tar.add(PACKAGE_NAME) + tar.close() + +def cleanup(): + """ Remove all files created. """ + if os.path.exists(TARBALL): + os.remove(TARBALL) + if os.path.exists(PACKAGE_NAME): + shutil.rmtree(PACKAGE_NAME) + +def run_rpm(blast_version): + """Run the rpmbuild command""" + shutil.rmtree(PACKAGE_NAME) + shutil.move(TARBALL, os.path.join(RPMBUILD_HOME, "SOURCES")) + rpm_spec = "ncbi-cobalt.spec" + src = os.path.join(SCRIPT_DIR, rpm_spec) + dest = os.path.join(RPMBUILD_HOME, "SPECS", rpm_spec) + shutil.copyfile(src, dest) + update_blast_version(dest, blast_version) + cmd = "/usr/bin/rpmbuild -ba " + dest + safe_exec(cmd) + +def move_rpms_to_installdir(installdir): + """Copy the resulting RPM files into the installation directory""" + installer_dir = os.path.join(installdir, "installer") + if not os.path.exists(installer_dir): + os.makedirs(installer_dir) + + args = [ "find", RPMBUILD_HOME, "-name", "*.rpm" ] + output = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()[0] + for rpm in output.split(): + rpm = rpm.decode('ascii') + if VERBOSE: + print("mv", rpm, installer_dir) + shutil.move(rpm, installer_dir) + + +def main(): + """ Creates RPMs for linux. """ + parser = OptionParser("%prog \ + \"\"") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="Show verbose output", dest="VERBOSE") + options, args = parser.parse_args() + if len(args) != 3: + parser.error("Incorrect number of arguments") + return 1 + + # N.B.: srctarball may be an empty argument (i.e.: "") in case of local + # builds, but this script shouldn't be invoked in that case + blast_version, installdir, srctarball = args + global VERBOSE, PACKAGE_NAME, TARBALL #IGNORE:W0603 + VERBOSE = options.VERBOSE + if VERBOSE: + print("Installing RPM to", installdir) + + PACKAGE_NAME = "ncbi-cobalt-" + blast_version + TARBALL = PACKAGE_NAME + ".tgz" + + setup_rpmbuild() + cleanup() + decompress_src_tarball(srctarball) + compress_sources() + run_rpm(blast_version) + move_rpms_to_installdir(installdir) + cleanup_rpm() + cleanup() + +if __name__ == "__main__": + sys.exit(main()) diff --git a/c++/scripts/projects/cobalt/post_build/rpm/ncbi-cobalt.spec b/c++/scripts/projects/cobalt/post_build/rpm/ncbi-cobalt.spec new file mode 100644 index 00000000..423ab6b3 --- /dev/null +++ b/c++/scripts/projects/cobalt/post_build/rpm/ncbi-cobalt.spec @@ -0,0 +1,43 @@ +Name: ncbi-cobalt +Version: BLAST_VERSION +Release: 1 +Source0: %{name}-%{version}.tgz +Summary: NCBI COBALT is a tool for multiple protein sequence alignment +Exclusiveos: linux +Group: NCBI/BLAST +License: Public Domain +BuildArch: i686 x86_64 +BuildRoot: /var/tmp/%{name}-buildroot +Prefix: /usr + +%description +NCBI Constrain-Based Alignment Tool (COBALT) aligns multiple protein +sequences. The program uses amino acid frequencies from conserved domain +database (CDD) and collection of pairwise constraints derived +from CDD, protein motifs, and local sequence similarity using RPS-BLAST, +BLASTP, and PHI-BLAST. The constraints are incorporated into the multiple +alignment. + +%prep +%setup -q + +%build +./configure +cd c++/*/build +%__make -f Makefile.flat + +%install +%__mkdir_p $RPM_BUILD_ROOT/%_bindir +%__install -m755 c++/*/bin/cobalt $RPM_BUILD_ROOT/%_bindir + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%_bindir/* + +%changelog +* Fri Aug 19 2016 +- See ChangeLog file + diff --git a/c++/scripts/projects/cobalt/post_build/win/EnvVarUpdate.nsh b/c++/scripts/projects/cobalt/post_build/win/EnvVarUpdate.nsh new file mode 100644 index 00000000..4148114a --- /dev/null +++ b/c++/scripts/projects/cobalt/post_build/win/EnvVarUpdate.nsh @@ -0,0 +1,568 @@ +; Obtained from http://nsis.sourceforge.net/Path_Manipulation on 08/14/08 +!ifndef ENVVARUPDATE_FUNCTION +!define ENVVARUPDATE_FUNCTION +!verbose push +!verbose 3 +!include "LogicLib.nsh" +!include "WinMessages.NSH" + +; ---------------------------------- Macro Definitions ---------------------------------------- +!macro _EnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString + Push "${EnvVarName}" + Push "${Action}" + Push "${RegLoc}" + Push "${PathString}" + Call EnvVarUpdate + Pop "${ResultVar}" +!macroend +!define EnvVarUpdate '!insertmacro "_EnvVarUpdateConstructor"' + +!macro _unEnvVarUpdateConstructor ResultVar EnvVarName Action Regloc PathString + Push "${EnvVarName}" + Push "${Action}" + Push "${RegLoc}" + Push "${PathString}" + Call un.EnvVarUpdate + Pop "${ResultVar}" +!macroend +!define un.EnvVarUpdate '!insertmacro "_unEnvVarUpdateConstructor"' + +!macro _StrTokConstructor ResultVar String Separators ResultPart SkipEmptyParts + Push "${String}" + Push "${Separators}" + Push "${ResultPart}" + Push "${SkipEmptyParts}" + Call ${UN}StrTok + Pop "${ResultVar}" +!macroend +!define StrTok '!insertmacro "_StrTokConstructor"' + +!macro _StrContainsConstructor OUT NEEDLE HAYSTACK + Push "${HAYSTACK}" + Push "${NEEDLE}" + Call ${UN}StrContains + Pop "${OUT}" +!macroend +!define StrContains '!insertmacro "_StrContainsConstructor"' + +!macro _strReplaceConstructor OUT NEEDLE NEEDLE2 HAYSTACK + Push "${HAYSTACK}" + Push "${NEEDLE}" + Push "${NEEDLE2}" + Call ${UN}StrReplace + Pop "${OUT}" +!macroend +!define StrReplace '!insertmacro "_strReplaceConstructor"' + +; ---------------------------------- Macro Definitions end------------------------------------- + +;----------------------------------- EnvVarUpdate start---------------------------------------- +!define hklm_all_users 'HKLM "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"' +!define hkcu_current_user 'HKCU "Environment"' + +!macro EnvVarUpdate UN + +Function ${UN}EnvVarUpdate + + Push $0 + Exch 4 + Exch $1 + Exch 3 + Exch $2 + Exch 2 + Exch $3 + Exch + Exch $4 + Push $5 + Push $6 + Push $7 + Push $8 + Push $9 + Push $R0 + + /* After this point: + ------------------------- + $0 = ResultVar (returned) + $1 = EnvVarName (input) + $2 = Action (input) + $3 = RegLoc (input) + $4 = PathString (input) + $5 = Orig EnvVar (read from registry) + $6 = Len of $0 (temp) + $7 = tempstr1 (temp) + $8 = Entry counter (temp) + $9 = tempstr2 (temp) + $R0 = tempChar (temp) */ + + ; Step 1: Read contents of EnvVarName from RegLoc + ; + ; Check for empty EnvVarName + ${If} $1 == "" + SetErrors + DetailPrint "ERROR: EnvVarName is blank" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Check for valid Action + ${If} $2 != "A" + ${AndIf} $2 != "P" + ${AndIf} $2 != "R" + SetErrors + DetailPrint "ERROR: Invalid Action - must be A, P, or R" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ${If} $3 == HKLM + ReadRegStr $5 ${hklm_all_users} $1 ; Get EnvVarName from all users into $5 + ${ElseIf} $3 == HKCU + ReadRegStr $5 ${hkcu_current_user} $1 ; Read EnvVarName from current user into $5 + ${Else} + SetErrors + DetailPrint 'ERROR: Action is [$3] but must be "HKLM" or HKCU"' + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Check for empty PathString + ${If} $4 == "" + SetErrors + DetailPrint "ERROR: PathString is blank" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Make sure we've got some work to do + ${If} $5 == "" + ${AndIf} $2 == "R" + SetErrors + DetailPrint "$1 is empty - Nothing to remove" + Goto EnvVarUpdate_Restore_Vars + ${EndIf} + + ; Step 2: Scrub EnvVar + ; + StrCpy $0 $5 ; Copy the contents to $0 + ; Remove spaces around semicolons (NOTE: spaces before the 1st entry or + ; after the last one are not removed here but instead in Step 3) + ${If} $0 != "" ; If EnvVar is not empty ... + ${Do} + ${StrContains} $7 " ;" $0 + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${StrReplace} $0 " ;" ";" $0 ; Remove ';' + ${Loop} + ${Do} + ${StrContains} $7 "; " $0 + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${StrReplace} $0 "; " ";" $0 ; Remove ';' + ${Loop} + ${Do} + ${StrContains} $7 ";;" $0 + ${If} $7 == "" + ${ExitDo} + ${EndIf} + ${StrReplace} $0 ";;" ";" $0 + ${Loop} + + ; Remove a leading or trailing semicolon from EnvVar + StrCpy $7 $0 1 0 + ${If} $7 == ";" + StrCpy $0 $0 "" 1 ; Change ';' to '' + ${EndIf} + StrLen $6 $0 + IntOp $6 $6 - 1 + StrCpy $7 $0 1 $6 + ${If} $7 == ";" + StrCpy $0 $0 $6 ; Change ';' to '' + ${EndIf} + ; DetailPrint "Scrubbed $1: [$0]" ; Uncomment to debug + ${EndIf} + + /* Step 3. Remove all instances of the target path/string (even if "A" or "P") + $6 = bool flag (1 = found and removed PathString) + $7 = a string (e.g. path) delimited by semicolon(s) + $8 = entry counter starting at 0 + $9 = copy of $0 + $R0 = tempChar */ + + ${If} $5 != "" ; If EnvVar is not empty ... + StrCpy $9 $0 + StrCpy $0 "" + StrCpy $8 0 + StrCpy $6 0 + + ${Do} + ${StrTok} $7 $9 ";" $8 "0" ; $7 = next entry, $8 = entry counter + + ${If} $7 == "" ; If we've run out of entries, + ${ExitDo} ; were done + ${EndIf} ; + + ; Remove leading and trailing spaces from this entry (critical step for Action=Remove) + ${Do} + StrCpy $R0 $7 1 + ${If} $R0 != " " + ${ExitDo} + ${EndIf} + StrCpy $7 $7 "" 1 ; Remove leading space + ${Loop} + ${Do} + StrCpy $R0 $7 1 -1 + ${If} $R0 != " " + ${ExitDo} + ${EndIf} + StrCpy $7 $7 -1 ; Remove trailing space + ${Loop} + ${If} $7 == $4 ; If string matches, remove it by not appending it + StrCpy $6 1 ; Set 'found' flag + ${ElseIf} $7 != $4 ; If string does NOT match + ${AndIf} $0 == "" ; and the 1st string being added to $0, + StrCpy $0 $7 ; copy it to $0 without a prepended semicolon + ${ElseIf} $7 != $4 ; If string does NOT match + ${AndIf} $0 != "" ; and this is NOT the 1st string to be added to $0, + StrCpy $0 $0;$7 ; append path to $0 with a prepended semicolon + ${EndIf} ; + + IntOp $8 $8 + 1 ; Bump counter + ${Loop} ; Check for duplicates until we run out of paths + ${EndIf} + + ; Step 4: Perform the requested Action + ; + ${If} $2 != "R" ; If Append or Prepend + ${If} $6 == 1 ; And if we found the target + DetailPrint "Target is already present in $1. It will be removed and" + ${EndIf} + ${If} $0 == "" ; If EnvVar is (now) empty + StrCpy $0 $4 ; just copy PathString to EnvVar + ${If} $6 == 0 ; If found flag is either 0 + ${OrIf} $6 == "" ; or blank (if EnvVarName is empty) + DetailPrint "$1 was empty and has been updated with the target" + ${EndIf} + ${ElseIf} $2 == "A" ; If Append (and EnvVar is not empty), + StrCpy $0 $0;$4 ; append PathString + ${If} $6 == 1 + DetailPrint "appended to $1" + ${Else} + DetailPrint "Target was appended to $1" + ${EndIf} + ${Else} ; If Prepend (and EnvVar is not empty), + StrCpy $0 $4;$0 ; prepend PathString + ${If} $6 == 1 + DetailPrint "prepended to $1" + ${Else} + DetailPrint "Target was prepended to $1" + ${EndIf} + ${EndIf} + ${Else} ; If Action = Remove + ${If} $6 == 1 ; and we found the target + DetailPrint "Target was found and removed from $1" + ${Else} + DetailPrint "Target was NOT found in $1 (nothing to remove)" + ${EndIf} + ${If} $0 == "" + DetailPrint "$1 is now empty" + ${EndIf} + ${EndIf} + + ; Step 5: Update the registry at RegLoc with the updated EnvVar and announce the change + ; + ClearErrors + ${If} $3 == HKLM + WriteRegExpandStr ${hklm_all_users} $1 $0 ; Write it in all users section + ${ElseIf} $3 == HKCU + WriteRegExpandStr ${hkcu_current_user} $1 $0 ; Write it to current user section + ${EndIf} + + IfErrors 0 +4 + MessageBox MB_OK|MB_ICONEXCLAMATION "Could not write updated $1 to $3" + DetailPrint "Could not write updated $1 to $3" + Goto EnvVarUpdate_Restore_Vars + + ; "Export" our change + SendMessage ${HWND_BROADCAST} ${WM_WININICHANGE} 0 "STR:Environment" /TIMEOUT=5000 + + EnvVarUpdate_Restore_Vars: + ; + ; Restore the user's variables and return ResultVar + Pop $R0 + Pop $9 + Pop $8 + Pop $7 + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Push $0 ; Push my $0 (ResultVar) + Exch + Pop $0 ; Restore his $0 + +FunctionEnd + +!macroend ; EnvVarUpdate UN +!insertmacro EnvVarUpdate "" +!insertmacro EnvVarUpdate "un." +;----------------------------------- EnvVarUpdate end---------------------------------------- + + +;-------------------------------------- StrTok start ------------------------------------------ +; Written by Diego Pedroso (deguix) +; +!macro StrTok UN + +Function ${UN}StrTok + +/*After this point: + ------------------------------------------ + $0 = SkipEmptyParts (input) + $1 = ResultPart (input) + $2 = Separators (input) + $3 = String (input) + $4 = SeparatorsLen (temp) + $5 = StrLen (temp) + $6 = StartCharPos (temp) + $7 = TempStr (temp) + $8 = CurrentLoop + $9 = CurrentSepChar + $R0 = CurrentSepCharNum */ + + ;Get input from user + Exch $0 + Exch + Exch $1 + Exch + Exch 2 + Exch $2 + Exch 2 + Exch 3 + Exch $3 + Exch 3 + Push $4 + Push $5 + Push $6 + Push $7 + Push $8 + Push $9 + Push $R0 + + ;Parameter defaults + ${IfThen} $2 == `` ${|} StrCpy $2 `|` ${|} + ${IfThen} $1 == `` ${|} StrCpy $1 `L` ${|} + ${IfThen} $0 == `` ${|} StrCpy $0 `0` ${|} + + ;Get "String" and "Separators" length + StrLen $4 $2 + StrLen $5 $3 + ;Start "StartCharPos" and "ResultPart" counters + StrCpy $6 0 + StrCpy $8 -1 + + ;Loop until "ResultPart" is met, "Separators" is found or + ;"String" reaches its end + ResultPartLoop: ;"CurrentLoop" Loop + + ;Increase "CurrentLoop" counter + IntOp $8 $8 + 1 + + StrSearchLoop: + ${Do} ;"String" Loop + ;Remove everything before and after the searched part ("TempStr") + StrCpy $7 $3 1 $6 + + ;Verify if it's the "String" end + ${If} $6 >= $5 + ;If "CurrentLoop" is what the user wants, remove the part + ;after "TempStr" and itself and get out of here + ${If} $8 == $1 + ${OrIf} $1 == `L` + StrCpy $3 $3 $6 + ${Else} ;If not, empty "String" and get out of here + StrCpy $3 `` + ${EndIf} + StrCpy $R0 `End` + ${ExitDo} + ${EndIf} + + ;Start "CurrentSepCharNum" counter (for "Separators" Loop) + StrCpy $R0 0 + + ${Do} ;"Separators" Loop + ;Use one "Separators" character at a time + ${If} $R0 <> 0 + StrCpy $9 $2 1 $R0 + ${Else} + StrCpy $9 $2 1 + ${EndIf} + + ;Go to the next "String" char if it's "Separators" end + ${IfThen} $R0 >= $4 ${|} ${ExitDo} ${|} + + ;Or, if "TempStr" equals "CurrentSepChar", then... + ${If} $7 == $9 + StrCpy $7 $3 $6 + + ;If "String" is empty because this result part doesn't + ;contain data, verify if "SkipEmptyParts" is activated, + ;so we don't return the output to user yet + + ${If} $7 == `` + ${AndIf} $0 = 1 ;${TRUE} + IntOp $6 $6 + 1 + StrCpy $3 $3 `` $6 + StrCpy $6 0 + Goto StrSearchLoop + ${ElseIf} $8 == $1 + StrCpy $3 $3 $6 + StrCpy $R0 "End" + ${ExitDo} + ${EndIf} ;If not, go to the next result part + IntOp $6 $6 + 1 + StrCpy $3 $3 `` $6 + StrCpy $6 0 + Goto ResultPartLoop + ${EndIf} + + ;Increase "CurrentSepCharNum" counter + IntOp $R0 $R0 + 1 + ${Loop} + ${IfThen} $R0 == "End" ${|} ${ExitDo} ${|} + + ;Increase "StartCharPos" counter + IntOp $6 $6 + 1 + ${Loop} + + /*After this point: + ------------------------------------------ + $3 = ResultVar (output)*/ + + ;Return output to user + Pop $R0 + Pop $9 + Pop $8 + Pop $7 + Pop $6 + Pop $5 + Pop $4 + Pop $0 + Pop $1 + Pop $2 + Exch $3 +FunctionEnd + +!macroend ; StrTok UN +!insertmacro StrTok "" +!insertmacro StrTok "un." + +;----------------------------------------- StrTok end ------------------------------------------- + + +;---------------------------------------- StrContains start ------------------------------------- +; StrContains +; This function does a case sensitive searches for an occurrence of a substring in a string. +; It returns the substring if it is found; otherwise, it returns null(""). +; Usage: ${StrContains} "$result_var" "Needle" "Haystack" +; Written by kenglish_hi +; Adapted from StrReplace written by dandaman32 + +Var STR_HAYSTACK +Var STR_NEEDLE +Var STR_CONTAINS_VAR_1 +Var STR_CONTAINS_VAR_2 +Var STR_CONTAINS_VAR_3 +Var STR_CONTAINS_VAR_4 +Var STR_RETURN_VAR + +!macro StrContains UN + +Function ${UN}StrContains + + Exch $STR_NEEDLE + Exch + Exch $STR_HAYSTACK + ; Uncomment to debug + ;MessageBox MB_OK 'STR_NEEDLE = $STR_NEEDLE STR_HAYSTACK = $STR_HAYSTACK ' + StrCpy $STR_RETURN_VAR "" + StrCpy $STR_CONTAINS_VAR_1 -1 + StrLen $STR_CONTAINS_VAR_2 $STR_NEEDLE + StrLen $STR_CONTAINS_VAR_4 $STR_HAYSTACK + loop: + IntOp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_1 + 1 + StrCpy $STR_CONTAINS_VAR_3 $STR_HAYSTACK $STR_CONTAINS_VAR_2 $STR_CONTAINS_VAR_1 + StrCmp $STR_CONTAINS_VAR_3 $STR_NEEDLE found + StrCmp $STR_CONTAINS_VAR_1 $STR_CONTAINS_VAR_4 done + Goto loop + found: + StrCpy $STR_RETURN_VAR $STR_NEEDLE + Goto done + done: + Pop $STR_HAYSTACK ;Prevent "invalid opcode" errors and keep the stack intact + Exch $STR_RETURN_VAR +FunctionEnd + +!macroend +!insertmacro StrContains "" +!insertmacro StrContains "un." +;--------------------------------------- StrContains end --------------------------------------- + + +;--------------------------------------- StrReplace start -------------------------------------- +; NOTE: Do not substitute 'StrReplaceV4' for this function. It will fail due to the way I call it. +; +; StrReplace +; Replaces all occurences of a given needle within a haystack with another string +; Usage: ${StrReplace} "$result_var" "SubString" "RepString" "String" +; Written by dandaman32 + +Var STR_REPLACE_VAR_0 +Var STR_REPLACE_VAR_1 +Var STR_REPLACE_VAR_2 +Var STR_REPLACE_VAR_3 +Var STR_REPLACE_VAR_4 +Var STR_REPLACE_VAR_5 +Var STR_REPLACE_VAR_6 +Var STR_REPLACE_VAR_7 +Var STR_REPLACE_VAR_8 + +!macro StrReplace UN + +Function ${UN}StrReplace + + Exch $STR_REPLACE_VAR_2 + Exch 1 + Exch $STR_REPLACE_VAR_1 + Exch 2 + Exch $STR_REPLACE_VAR_0 + StrCpy $STR_REPLACE_VAR_3 -1 + StrLen $STR_REPLACE_VAR_4 $STR_REPLACE_VAR_1 + StrLen $STR_REPLACE_VAR_6 $STR_REPLACE_VAR_0 + loop: + IntOp $STR_REPLACE_VAR_3 $STR_REPLACE_VAR_3 + 1 + StrCpy $STR_REPLACE_VAR_5 $STR_REPLACE_VAR_0 $STR_REPLACE_VAR_4 $STR_REPLACE_VAR_3 + StrCmp $STR_REPLACE_VAR_5 $STR_REPLACE_VAR_1 found + StrCmp $STR_REPLACE_VAR_3 $STR_REPLACE_VAR_6 done + Goto loop + found: + StrCpy $STR_REPLACE_VAR_5 $STR_REPLACE_VAR_0 $STR_REPLACE_VAR_3 + IntOp $STR_REPLACE_VAR_8 $STR_REPLACE_VAR_3 + $STR_REPLACE_VAR_4 + StrCpy $STR_REPLACE_VAR_7 $STR_REPLACE_VAR_0 "" $STR_REPLACE_VAR_8 + StrCpy $STR_REPLACE_VAR_0 $STR_REPLACE_VAR_5$STR_REPLACE_VAR_2$STR_REPLACE_VAR_7 + StrLen $STR_REPLACE_VAR_6 $STR_REPLACE_VAR_0 + Goto loop + done: + Pop $STR_REPLACE_VAR_1 ; Prevent "invalid opcode" errors and keep the + Pop $STR_REPLACE_VAR_1 ; stack as it was before the function was called + Exch $STR_REPLACE_VAR_0 + +FunctionEnd + +!macroend ; StrContains UN +!insertmacro StrReplace "" +!insertmacro StrReplace "un." + +;----------------------------------------- StrReplace end --------------------------------------- + +!verbose pop +!endif \ No newline at end of file diff --git a/c++/scripts/projects/cobalt/post_build/win/make_win.py b/c++/scripts/projects/cobalt/post_build/win/make_win.py new file mode 100644 index 00000000..60b1b004 --- /dev/null +++ b/c++/scripts/projects/cobalt/post_build/win/make_win.py @@ -0,0 +1,84 @@ +#! /usr/bin/env python3 +"""Script to create the Windows installer for BLAST command line applications""" +# $Id: make_win.py 544372 2017-08-22 17:51:41Z boratyng $ +# +# Author: Christiam camacho + +from __future__ import print_function +import os, sys, os.path +import shutil +from optparse import OptionParser +SCRIPT_DIR = os.path.dirname(os.path.abspath(sys.argv[0])) +sys.path.append(os.path.join(SCRIPT_DIR, "..")) +from blast_utils import safe_exec, update_blast_version + +VERBOSE = False + +# NSIS Configuration file +NSIS_CONFIG = os.path.join(SCRIPT_DIR, "ncbi-cobalt.nsi") + +def extract_installer(): + """Extract name of the installer file from NSIS configuration file""" + from fileinput import FileInput + + retval = "unknown" + for line in FileInput(NSIS_CONFIG): + if line.find("OutFile") != -1: + retval = line.split()[1] + return retval.strip('"') + +def main(): + """ Creates NSIS installer for BLAST command line binaries """ + global VERBOSE #IGNORE:W0603 + parser = OptionParser("%prog ") + parser.add_option("-v", "--verbose", action="store_true", default=False, + help="Show verbose output", dest="VERBOSE") + options, args = parser.parse_args() + if len(args) != 2: + parser.error("Incorrect number of arguments") + return 1 + + blast_version, installdir = args + VERBOSE = options.VERBOSE + + apps = [ "cobalt.exe", + ] + + cwd = os.getcwd() + for app in apps: + app = os.path.join(installdir, "bin", app) + if VERBOSE: + print("Copying", app, "to", cwd) + shutil.copy(app, cwd) + + + update_blast_version(NSIS_CONFIG, blast_version) + # Copy necessary files to the current working directory + shutil.copy(NSIS_CONFIG, cwd) + license_file = os.path.join(SCRIPT_DIR, "..", "..", "LICENSE") + shutil.copy(license_file, cwd) + + # Copy the README file from the parent directory + readme_file = os.path.join(SCRIPT_DIR, "..", "..", "README") + shutil.copy(readme_file, cwd) + + for aux_file in ("EnvVarUpdate.nsh", "ncbilogo.ico", "unix2dos.nsh"): + src = os.path.join(SCRIPT_DIR, aux_file) + if VERBOSE: + print("Copying", src, "to", cwd) + shutil.copy(src, cwd) + + # makensis is in the path of the script courtesy of the release framework + cmd = "makensis " + os.path.basename(NSIS_CONFIG) + safe_exec(cmd) + + installer_dir = os.path.join(installdir, "installer") + if not os.path.exists(installer_dir): + os.makedirs(installer_dir) + + installer = extract_installer() + shutil.copy(installer, installer_dir) + +if __name__ == "__main__": + sys.exit(main()) + diff --git a/c++/scripts/projects/cobalt/post_build/win/ncbi-cobalt.nsi b/c++/scripts/projects/cobalt/post_build/win/ncbi-cobalt.nsi new file mode 100755 index 00000000..3a96a4e8 --- /dev/null +++ b/c++/scripts/projects/cobalt/post_build/win/ncbi-cobalt.nsi @@ -0,0 +1,94 @@ +;NSIS Modern User Interface + +;-------------------------------- +;Include Modern UI + + !include "MUI.nsh" + !include "EnvVarUpdate.nsh" + !include "x64.nsh" + !include "unix2dos.nsh" + +;-------------------------------- +; Initialization function to properly set the installation directory +Function .onInit + ${If} ${RunningX64} + StrCpy $INSTDIR "$PROGRAMFILES64\NCBI\cobalt-BLAST_VERSION" + ${EndIf} +FunctionEnd + +;-------------------------------- +;General + + ;Name and file + Name "NCBI COBALT BLAST_VERSION" + OutFile "ncbi-cobalt-BLAST_VERSION.exe" + ; Install/uninstall icons + !define MUI_ICON "ncbilogo.ico" + !define MUI_UNICON "${NSISDIR}\Contrib\Graphics\Icons\nsis1-uninstall.ico" + + ;Default installation folder + InstallDir "$PROGRAMFILES\NCBI\cobalt-BLAST_VERSION" + + ;Get installation folder from registry if available + InstallDirRegKey HKCU "Software\NCBI\cobalt-BLAST_VERSION" "" + +;-------------------------------- +;Interface Settings + + !define MUI_ABORTWARNING + +;-------------------------------- +;Pages + + !insertmacro MUI_PAGE_LICENSE "LICENSE" + !insertmacro MUI_PAGE_DIRECTORY + !insertmacro MUI_PAGE_INSTFILES + ;!insertmacro MUI_PAGE_FINISH + + !insertmacro MUI_UNPAGE_CONFIRM + !insertmacro MUI_UNPAGE_INSTFILES + +;-------------------------------- +;Languages + + !insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Installer Sections + +Section "DefaultSection" SecDflt + + SetOutPath "$INSTDIR\bin" + + File "cobalt.exe" + + SetOutPath "$INSTDIR\doc" + File "README" + Push "$INSTDIR\doc\README" + Push "$INSTDIR\doc\README.txt" + Call unix2dos + + ;Store installation folder + WriteRegStr HKCU "Software\NCBI\cobalt-BLAST_VERSION" "" $INSTDIR + + ;Create uninstaller + WriteUninstaller "$INSTDIR\Uninstall-ncbi-cobalt-BLAST_VERSION.exe" + + ;Update PATH + ${EnvVarUpdate} $0 "PATH" "P" "HKCU" "$INSTDIR\bin" + +SectionEnd + +;-------------------------------- +;Uninstaller Section + +Section "Uninstall" + Delete "$INSTDIR\Uninstall-ncbi-cobalt-BLAST_VERSION.exe" + RMDir /r "$INSTDIR" + + DeleteRegKey /ifempty HKCU "Software\NCBI\cobalt-BLAST_VERSION" + + ; Remove installation directory from PATH + ${un.EnvVarUpdate} $0 "PATH" "R" "HKCU" "$INSTDIR\bin" + +SectionEnd diff --git a/c++/scripts/projects/cobalt/post_build/win/ncbilogo.ico b/c++/scripts/projects/cobalt/post_build/win/ncbilogo.ico new file mode 100644 index 0000000000000000000000000000000000000000..247e28fe95b615c6f1d1a8e603570404fda48714 GIT binary patch literal 25214 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 -IntelMAC : clang : Clang.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --without-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt -IntelMAC-Clang36 : clang : Clang.sh 7.0.2 --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --without-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt +#IntelMAC : clang : Clang.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --with-downloaded-vdb --with-static-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt +IntelMAC-Clang36 : clang : Clang.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --with-downloaded-vdb --with-static-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt USE_COMPONENTS diff --git a/c++/scripts/projects/igblast/README b/c++/scripts/projects/igblast/README index e3c476a9..dd8949a7 100644 --- a/c++/scripts/projects/igblast/README +++ b/c++/scripts/projects/igblast/README @@ -1,101 +1,3 @@ -There are two command line programs for igblast...igblastn and igblastp. The former is for nucleotide -sequence and the latter is for protein sequences. +Documents to set up and run IgBLAST can be found at: -igblastn: - -1. Required files. -1). Blast database files for searching germline V, D, and J genes. You can specify any germline -databases you like (using -germline_db_V, -germline_db_J and -germline_db_D options). -The NCBI mouse germline gene databases (i.e., mouse_gl_V, etc.) are supplied with igblastn program -(see http://www.ncbi.nlm.nih.gov/igblast/ about database details). - -To search IMGT germline sequences, you need to download them from IMGT web site -(http://www.imgt.org/IMGT_vquest/share/textes/ ). You need to download all V, D and J sequences for whatever -organisms you are interested in. Combine all V and all J sequences, respectively, into a separate file (i.e., -one file for all V sequences and one file all for J sequences). After you have downloaded the sequences, -invoke our utility tool edit_imgt_file.pl (download from the release/ directory) to process the sequences (to change - the long IMGT definition lines to germline gene names only). For example: - -./edit_imgt_file.pl imgt_file > my_seq_file - -Then you can use NCBI's makeblastdb tool to make the blast database from the output file. For example: - -makeblastdb -parse_seqids -dbtype nucl -in my_seq_file - -Now you can use my_seq_file as blast database file for igblast. - -2). Igblast internal data files (download from the release/ directory). This directory contains data internal to -igblast program only and users should NEVER add, delete, move, copy or edit any files in this directory. -Igblastn program expects the internal_data directory under current directory (i.e., where the igblast -program is) or a path pointed to by IGDATA environmental variable. Note that this directory does NOT contain - any germline gene databases you should search (see above for how you can obtain a germline gene database). - -2. Optional files (download from the release/ directory): -This is the file to indicate germline J gene coding frame start position (position is 0-based), the J gene type, -and the CDR3 end position for each sequence in the germline J sequence database (Fields are tab-delimited). - -Note that the supplied file contains only information for NCBI or IMGT germline gene sequence database -(including gene names as well as the sequences). If you search your own database and if it contains different -sequences or sequence identifiers, then you need to edit that file (or supply your own file) to reflect that -or you won't get proper frame status or CDR3 information (other results will still be shown correctly). -See human_gl.aux or mouse_gl.aux for examples. Enter -1 if the frame information is unknown. -You need to use -auxiliary_data option to specify your file. You can directly supply a path to this file or -put it under a path pointed to by IGDATA environmental variable. - -3. Some examples. -1). Searching germline gene database -a). To query one or more mouse Ig sequences (contained in myseq) against NCBI mouse germline gene -database with standard text alignment result format (you can type "./igblastn -help" to see details on all -input parameters and the default setting, particularly those under IgBLAST options): -./igblastn -germline_db_V mouse_gl_V -germline_db_J mouse_gl_J -germline_db_D mouse_gl_D - -organism mouse -domain_system kabat -query myseq -auxiliary_data optional_file/mouse_gl.aux - -show_translation -outfmt 3 - -b). To query one or more mouse T cell receptor sequences (contained in myseq) against imgt mouse -germline gene database: -./igblastn -germline_db_V imgt_tcr_db_v -germline_db_J imgt_tcr_db_j -germline_db_D imgt_tcr_db - -organism mouse -domain_system imgt -query myseq -ig_seqtype TCR -auxiliary_data -optional_file/mouse_gl.aux -show_translation -outfmt 3 - -c). To query one or human Ig sequences (contained in myseq) against custom database such as Andew -Collins IGH repertoire database: -./igblastn -germline_db_V UNSWIgVRepertoire_fasta.txt -germline_db_J UNSWIgJRepertoire_fasta.txt - -germline_db_D UNSWIgDRepertoire_fasta.txt -organism human -domain_system kabat -query myseq - -auxiliary_data optional_file/human_gl.aux -show_translation -Please be aware that you need to specify your own coding frame start and chain_type information (see -details on optional files above) if your custom database has different sequence entries from NCBI or -IMGT database. - -2). Searching other databases in addition to germline database. -Igblast allows you to search an additional database (such as NCBI nr database) as well as the germline -database at the same time. You'll get hits from germline sequences followed by hits from non-germline -database. -You MUST use -db option to specify the non-germline database which may not contain any sequences -identifiers that exist in germline databases. Note this option is ONLY for non-germline database -(germline databases MUST be used with -germline_db_V, -germline_db_D or -germline_db_J option). -a). To query one or more mouse Ig sequences (contained in myseq) against NCBI nr database: -./igblastn -germline_db_V mouse_gl_V -germline_db_J mouse_gl_J -germline_db_D mouse_gl_D - -organism mouse -domain_system kabat -query myseq -auxiliary_data optional_file/mouse_gl.aux - -show_translation -outfmt 3 -db nr -remote - -Note the -remote option used with this search...-remote option directs igblast to send nr database -searching to NCBI server which typically is much faster. - -igblastp: -The parameters are similar to those of igblastn except it does not need germline D database, germline J -database and optional file. igblastp only performs search against V gene database. - -Some examples: - -1). Searching mouse Ig sequence against mouse germline gene database - -./igblastp -germline_db_V mouse_gl_V -query myseq.prot -outfmt 3 -organism mouse - -2). Searching other databases in addition to germline database. - -./igblastp -germline_db_V mouse_gl_V -query myseq.prot -outfmt 3 -organism mouse -db nr –remote - - -Other notes: - -The V gene domain annotation only works for IMGT annotation system for TCR sequences. +https://ncbi.github.io/igblast/ diff --git a/c++/scripts/projects/igblast/components.link b/c++/scripts/projects/igblast/components.link index 86d2dd20..33ba9b61 100644 --- a/c++/scripts/projects/igblast/components.link +++ b/c++/scripts/projects/igblast/components.link @@ -1,9 +1,9 @@ [components] -infrastructure 18.0 -core 18.0 -dbase 18.0 -web 18.0 -objects 18.0 -objtools 18.0 -algo 18.0 -app 18.0 +infrastructure 20.0 +core 20.0 +dbase 20.0 +web 20.0 +objects 20.0 +objtools 20.0 +algo 20.0 +app 20.0 diff --git a/c++/scripts/projects/igblast/edit_imgt_file.pl b/c++/scripts/projects/igblast/edit_imgt_file.pl new file mode 100755 index 00000000..5b36f26d --- /dev/null +++ b/c++/scripts/projects/igblast/edit_imgt_file.pl @@ -0,0 +1,22 @@ +#!/usr/bin/perl -w + + +use strict; +my $inputfile=shift (@ARGV); + +open(in_handle, $inputfile); + +while(my $line=){ + #print ("line = $line\n"); + if ($line =~ /^>.*\|(TR.+)\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|/){ + print(">$1\n"); + } elsif ($line =~ /^>.*\|(IG.+)\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|.*\|/){ + print(">$1\n"); + } else { + $line =~ s/\.+//g; + #get rid of dot + print("$line"); + } +} + +close (in_handle); diff --git a/c++/scripts/projects/igblast/post_build/macosx/ncbi-igblast.sh b/c++/scripts/projects/igblast/post_build/macosx/ncbi-igblast.sh index ae19239b..928ba85d 100755 --- a/c++/scripts/projects/igblast/post_build/macosx/ncbi-igblast.sh +++ b/c++/scripts/projects/igblast/post_build/macosx/ncbi-igblast.sh @@ -5,12 +5,12 @@ SCRIPTDIR=$2 BLAST_VERSION=$3 PRODUCT="ncbi-igblast-$BLAST_VERSION+" -INSTALL_LOCATION1=/usr/local/ncbi/blast +INSTALL_LOCATION1=/usr/local/ncbi/igblast INSTALL_LOCATION2=/etc/paths.d STAGE_DIR1=_stage1 STAGE_DIR2=_stage2 RESOURCES_DIR=Resources -ID=gov.nlm.nih.ncbi.blast +ID=gov.nlm.nih.ncbi.igblast if [ $# -ne 3 ] ; then echo "Usage: ncbi-igblast.sh [installation directory] [MacOSX post-build script directory] [BLAST version]"; @@ -41,7 +41,7 @@ prep_binary_component_package() prep_paths_component_package() { - echo /usr/local/ncbi/igblast/bin > $STAGE_DIR2/ncbi_blast + echo /usr/local/ncbi/igblast/bin > $STAGE_DIR2/ncbi_igblast /usr/bin/pkgbuild --root $STAGE_DIR2 --identifier $ID.paths --version \ $BLAST_VERSION --install-location $INSTALL_LOCATION2 paths.pkg } diff --git a/c++/scripts/projects/igblast/post_build/make_installers.py b/c++/scripts/projects/igblast/post_build/make_installers.py index 4ac612f5..9394a315 100755 --- a/c++/scripts/projects/igblast/post_build/make_installers.py +++ b/c++/scripts/projects/igblast/post_build/make_installers.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """Driver program for post-build processing""" -# $Id: make_installers.py 517012 2016-10-19 21:23:41Z camacho $ +# $Id: make_installers.py 547285 2017-09-27 19:34:45Z boratyng $ # # Author: Christiam Camacho # @@ -53,6 +53,9 @@ def main(): #IGNORE:R0911 shutil.copy(libdir + "libhogweed-4-2.dll", installdir + "bin") shutil.copy(libdir + "libnettle-6-2.dll", installdir + "bin") shutil.copy(libdir + "libp11-kit-0.dll", installdir + "bin") + shutil.copy(libdir + "msvcp120.dll", installdir + "bin") + shutil.copy(libdir + "msvcr120.dll", installdir + "bin") + shutil.copy(libdir + "ncbi-vdb-md.dll", installdir + "bin") return launch_win_installer_build(installdir, blast_version) if platform.startswith("Linux64"): return launch_rpm_build(installdir, blast_version) diff --git a/c++/scripts/projects/igblast/post_build/rpm/ncbi-igblast.spec b/c++/scripts/projects/igblast/post_build/rpm/ncbi-igblast.spec index 3d6a25dc..6306cf7c 100644 --- a/c++/scripts/projects/igblast/post_build/rpm/ncbi-igblast.spec +++ b/c++/scripts/projects/igblast/post_build/rpm/ncbi-igblast.spec @@ -18,7 +18,7 @@ for the analysis of immunoglobulin sequence data. %setup -q %build -./configure +./configure || ./configure --manifest-config=Linux64-Centos:gcc cd c++/*/build %__make -f Makefile.flat diff --git a/c++/scripts/projects/igblast/post_build/win/make_win.py b/c++/scripts/projects/igblast/post_build/win/make_win.py index b6d882f7..99f01d46 100644 --- a/c++/scripts/projects/igblast/post_build/win/make_win.py +++ b/c++/scripts/projects/igblast/post_build/win/make_win.py @@ -1,6 +1,6 @@ #! /usr/bin/env python3 """Script to create the Windows installer for BLAST command line applications""" -# $Id: make_win.py 516804 2016-10-18 15:15:47Z camacho $ +# $Id: make_win.py 547285 2017-09-27 19:34:45Z boratyng $ # # Author: Christiam camacho @@ -47,7 +47,10 @@ def main(): "libgnutls-30.dll", "libhogweed-4-2.dll", "libnettle-6-2.dll", - "libp11-kit-0.dll" + "libp11-kit-0.dll", + "msvcp120.dll", + "msvcr120.dll", + "ncbi-vdb-md.dll" ] cwd = os.getcwd() diff --git a/c++/scripts/projects/igblast/post_build/win/ncbi-blast.nsi b/c++/scripts/projects/igblast/post_build/win/ncbi-blast.nsi index 4e6b7160..bfc7fd06 100755 --- a/c++/scripts/projects/igblast/post_build/win/ncbi-blast.nsi +++ b/c++/scripts/projects/igblast/post_build/win/ncbi-blast.nsi @@ -68,6 +68,9 @@ Section "DefaultSection" SecDflt File "libhogweed-4-2.dll" File "libnettle-6-2.dll" File "libp11-kit-0.dll" + File "msvcp120.dll" + File "msvcr120.dll" + File "ncbi-vdb-md.dll" SetOutPath "$INSTDIR\doc" File "README" diff --git a/c++/scripts/projects/igblast/project.lst b/c++/scripts/projects/igblast/project.lst index a206abea..f8bbaef3 100644 --- a/c++/scripts/projects/igblast/project.lst +++ b/c++/scripts/projects/igblast/project.lst @@ -1,4 +1,6 @@ corelib$ +db$ +db/sqlite serial$ serial/impl$ serial/datatool @@ -10,6 +12,9 @@ algo/blast/blastinput algo/blast/composition_adjustment algo/blast/dbindex algo/blast/format +algo/blast/proteinkmer +algo/blast/blast_sra_input +-algo/blast/proteinkmer/demo algo/blast/igblast algo/dustmask$ algo/winmask$ @@ -20,6 +25,7 @@ cgi$ cgi/impl$ html$ connect$ +connect/mbedtls connect/services$ connect/services/impl$ connect/ext$ @@ -44,10 +50,12 @@ objtools/readers$ objtools/seqmasks_io$ objtools/blast$ objtools/blast/seqdb_reader +-objtools/blast/seqdb_reader/seqdb2_info objtools/blast/gene_info_reader objtools/blast/services objtools/blast/blastdb_format objtools/blast/seqdb_writer +-objtools/blast/seqdb_writer/demo objtools/cleanup$ objtools/edit$ objtools/format$ @@ -82,6 +90,9 @@ objtools/simple$ -objects/.*/test -objects/.*/demo -objects/.*/unit_test +sra/readers/sra +sra/readers$ +sra$ misc$ misc/third_party misc/third_party_static diff --git a/c++/scripts/projects/magicblast/ChangeLog b/c++/scripts/projects/magicblast/ChangeLog index f1af1882..3562291b 100644 --- a/c++/scripts/projects/magicblast/ChangeLog +++ b/c++/scripts/projects/magicblast/ChangeLog @@ -1,11 +1,2 @@ -August 19, 2016 -* First release - -November 4, 2016 -* 1.1.0 release -Improvements: -* -sra option connects to NCBI via HTTPS -* Results are formatted with 'bare' accessions -* Tabular output includes a header with column titles -Bug fixes: -* Fixed SAM flag values +Magic-BLAST release notes can be found at +https://ncbi.github.io/magicblast/release/release.html diff --git a/c++/scripts/projects/magicblast/Manifest b/c++/scripts/projects/magicblast/Manifest index 73a93d8f..2c264e4f 100644 --- a/c++/scripts/projects/magicblast/Manifest +++ b/c++/scripts/projects/magicblast/Manifest @@ -44,7 +44,7 @@ DEFAULT_CONFIGURATIONS: Linux64-Centos:icc Win64 : plain : static 64 ReleaseDLL NCBI_CONFIG____ENABLEDUSERREQUESTS__NCBI-INT8-GI=1 #IntelMAC : gcc : GCC.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-downloaded-vdb --with-static-vdb -IntelMAC : clang : Clang.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --with-downloaded-vdb --with-static-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt -IntelMAC-Clang36 : clang : Clang.sh 7.0.2 --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --with-downloaded-vdb --with-static-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt +#IntelMAC : clang : Clang.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --with-downloaded-vdb --with-static-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt +IntelMAC-Clang36 : clang : Clang.sh --with-bin-release --without-debug --without-pcre --with-mt --with-openmp --with-flat-makefile --with-ncbi-public --with-experimental=Int8GI --with-downloaded-vdb --with-static-vdb --with-gnutls=/netopt/ncbi_tools/gnutls-3.4.0 --without-gcrypt USE_COMPONENTS diff --git a/c++/scripts/projects/magicblast/README b/c++/scripts/projects/magicblast/README index f2e4b061..f52a69f6 100644 --- a/c++/scripts/projects/magicblast/README +++ b/c++/scripts/projects/magicblast/README @@ -1,18 +1,10 @@ Magic-BLAST is a tool for mapping large next-generation RNA or DNA sequencing -runs against a whole genome or transcriptome. Each alignment optimizes -a composite score, taking into account simultaneously the two reads of -a pair, and in case of RNA-seq, locating the candidate introns and adding -up the score of all exons. This is very different from other versions of -BLAST, where each exon is scored as a separate hit and read-pairing is -ignored. +runs against a whole genome or transcriptome. Unlike other BLAST nucleotide search programs, such as BLASTN or Megablast, Magic-BLAST produces spliced alignments and optimizes alignment scores for paired reads. Magic-Blast incorporates within the NCBI BLAST code framework ideas developed in the NCBI Magic pipeline, in particular hit extensions by local walk and jump, which is faster than Smith-Waterman extension -(http://www.ncbi.nlm.nih.gov/pubmed/26109056), and recursive clipping of -mismatches near the edges of the reads, which avoids accumulating -artefactual mismatches near splice sites and is needed to distinguish -short indels from substitutions near the edges. +(http://www.ncbi.nlm.nih.gov/pubmed/26109056). We call the whole next generation run (from Illumina, Roche-454, ABI, or another sequencing platform excluding SOLiD), a query. The input reads may @@ -27,6 +19,9 @@ or AceView. The procedure for creating a BLAST database is described below. The full list of options is listed when you use -help option. +For more information, visit https://ncbi.github.io/magicblast/ + + =================== EXAMPLES: @@ -166,5 +161,4 @@ delimited fields: Thank you for testing this code and providing us with feedback. Please, let us know of any desired option, problem or difficulty. -E-mail boratyng@ncbi.nlm.nih.gov or blast-help@ncbi.nlm.nih.gov with -questions or comments. +E-mail blast-help@ncbi.nlm.nih.gov with questions or comments. diff --git a/c++/scripts/projects/magicblast/components.link b/c++/scripts/projects/magicblast/components.link index 86d2dd20..33ba9b61 100644 --- a/c++/scripts/projects/magicblast/components.link +++ b/c++/scripts/projects/magicblast/components.link @@ -1,9 +1,9 @@ [components] -infrastructure 18.0 -core 18.0 -dbase 18.0 -web 18.0 -objects 18.0 -objtools 18.0 -algo 18.0 -app 18.0 +infrastructure 20.0 +core 20.0 +dbase 20.0 +web 20.0 +objects 20.0 +objtools 20.0 +algo 20.0 +app 20.0 diff --git a/c++/scripts/projects/magicblast/post_build/macosx/ncbi-magicblast.sh b/c++/scripts/projects/magicblast/post_build/macosx/ncbi-magicblast.sh index 2d4bbcc1..16af85a8 100755 --- a/c++/scripts/projects/magicblast/post_build/macosx/ncbi-magicblast.sh +++ b/c++/scripts/projects/magicblast/post_build/macosx/ncbi-magicblast.sh @@ -3,17 +3,17 @@ INSTALLDIR=$1 SCRIPTDIR=$2 BLAST_VERSION=$3 -PRODUCT="ncbi-magicblast-$BLAST_VERSION+" +PRODUCT="ncbi-magicblast-$BLAST_VERSION" INSTALL_LOCATION1=/usr/local/ncbi/magicblast INSTALL_LOCATION2=/etc/paths.d STAGE_DIR1=_stage1 STAGE_DIR2=_stage2 RESOURCES_DIR=Resources -ID=gov.nlm.nih.ncbi.blast +ID=gov.nlm.nih.ncbi.magicblast if [ $# -ne 3 ] ; then - echo "Usage: ncbi-magicblast.sh [installation directory] [MacOSX post-build script directory] [BLAST version]"; + echo "Usage: ncbi-magicblast.sh [installation directory] [MacOSX post-build script directory] [Magic-BLAST version]"; exit 1; fi diff --git a/c++/scripts/projects/magicblast/post_build/make_installers.py b/c++/scripts/projects/magicblast/post_build/make_installers.py index c0d9b13a..bfed8205 100755 --- a/c++/scripts/projects/magicblast/post_build/make_installers.py +++ b/c++/scripts/projects/magicblast/post_build/make_installers.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """Driver program for post-build processing""" -# $Id: make_installers.py 513315 2016-09-09 13:58:57Z boratyng $ +# $Id: make_installers.py 523470 2017-01-03 22:23:49Z camacho $ # # Author: Christiam Camacho # @@ -55,6 +55,8 @@ def main(): #IGNORE:R0911 shutil.copy(libdir + "libhogweed-4-2.dll", installdir + "bin") shutil.copy(libdir + "libnettle-6-2.dll", installdir + "bin") shutil.copy(libdir + "libp11-kit-0.dll", installdir + "bin") + shutil.copy(libdir + "msvcp120.dll", installdir + "bin") + shutil.copy(libdir + "msvcr120.dll", installdir + "bin") return launch_win_installer_build(installdir, blast_version) if platform.startswith("Linux64"): return launch_rpm_build(installdir, blast_version, srctarball) diff --git a/c++/scripts/projects/magicblast/post_build/win/make_win.py b/c++/scripts/projects/magicblast/post_build/win/make_win.py index 86b3bad9..eb870da8 100644 --- a/c++/scripts/projects/magicblast/post_build/win/make_win.py +++ b/c++/scripts/projects/magicblast/post_build/win/make_win.py @@ -1,6 +1,6 @@ #! /usr/bin/env python3 """Script to create the Windows installer for BLAST command line applications""" -# $Id: make_win.py 513315 2016-09-09 13:58:57Z boratyng $ +# $Id: make_win.py 523470 2017-01-03 22:23:49Z camacho $ # # Author: Christiam camacho @@ -49,7 +49,10 @@ def main(): "libgnutls-30.dll", "libhogweed-4-2.dll", "libnettle-6-2.dll", - "libp11-kit-0.dll" ] + "libp11-kit-0.dll", + "msvcp120.dll", + "msvcr120.dll" + ] cwd = os.getcwd() for app in apps: diff --git a/c++/scripts/projects/magicblast/post_build/win/ncbi-blast.nsi b/c++/scripts/projects/magicblast/post_build/win/ncbi-blast.nsi index 04360961..3838f084 100755 --- a/c++/scripts/projects/magicblast/post_build/win/ncbi-blast.nsi +++ b/c++/scripts/projects/magicblast/post_build/win/ncbi-blast.nsi @@ -69,6 +69,8 @@ Section "DefaultSection" SecDflt File "libhogweed-4-2.dll" File "libnettle-6-2.dll" File "libp11-kit-0.dll" + File "msvcp120.dll" + File "msvcr120.dll" SetOutPath "$INSTDIR\doc" File "README" diff --git a/c++/scripts/projects/magicblast/project.lst b/c++/scripts/projects/magicblast/project.lst index 42d8d9c6..bdb7f316 100644 --- a/c++/scripts/projects/magicblast/project.lst +++ b/c++/scripts/projects/magicblast/project.lst @@ -1,4 +1,6 @@ corelib$ +db$ +db/sqlite serial$ serial/impl$ serial/datatool @@ -12,11 +14,16 @@ algo/blast/dbindex algo/blast/format algo/blast/unit_tests algo/blast/igblast +algo/blast/proteinkmer +-algo/blast/proteinkmer/demo algo/dustmask$ algo/winmask$ algo/segmask$ algo/blast/blastinput/unit_test -algo/blast/blastinput/demo +algo/sequence +-algo/sequence/demo +-algo/sequence/unit_test objects cgi$ cgi/impl$ @@ -24,6 +31,7 @@ html$ connect$ connect/services -connect/services/test +connect/mbedtls connect/ext$ util$ util/creaders$ @@ -45,10 +53,12 @@ objtools/readers$ objtools/seqmasks_io$ objtools/blast$ objtools/blast/seqdb_reader +-objtools/blast/seqdb_reader/seqdb2_info objtools/blast/gene_info_reader objtools/blast/services objtools/blast/blastdb_format objtools/blast/seqdb_writer +-objtools/blast/seqdb_writer/demo objtools/cleanup$ objtools/edit$ objtools/format$ diff --git a/c++/scripts/projects/ncbi_applog/ChangeLog b/c++/scripts/projects/ncbi_applog/ChangeLog index 1b8a3a64..539e1e72 100644 --- a/c++/scripts/projects/ncbi_applog/ChangeLog +++ b/c++/scripts/projects/ncbi_applog/ChangeLog @@ -1,3 +1,8 @@ +1.3.1 (09/18/17) + - Improved 'raw' command to allow multiple applications logs in the same file. CXX-9511 + - Added '-format' switch for "generate" command, to print out generated values in the shell-compatible formats. CXX-9511 + - Added 'health' health check command. CXX-8975 + 1.3.0 (11/29/16) - Switch to HTTPS protocol for CGI mode. - Added '-sid' option for 'generate' command. CXX-8809 diff --git a/c++/scripts/projects/ncbi_applog/Manifest b/c++/scripts/projects/ncbi_applog/Manifest index 7e5b2615..f03ba19f 100644 --- a/c++/scripts/projects/ncbi_applog/Manifest +++ b/c++/scripts/projects/ncbi_applog/Manifest @@ -1,7 +1,7 @@ # # Filename: Manifest # -# $Id: Manifest 519350 2016-11-15 14:55:24Z ivanov $ +# $Id: Manifest 544351 2017-08-22 15:08:34Z ivanov $ # # Author: Alexey Rafanovich # @@ -28,12 +28,12 @@ POSTBUILD: cp $srcdir/src/misc/clog/app/ncbi_applog_run_app.sh $installdir/bin # to it. So some standard options may be added by release configurator, such as --build-root-sfx, --with-projects, # --with-distcc, --with-action etc. -Linux64-Centos : plain : GCC.sh --without-debug --without-mt --with-static --without-runpath --with-flat-makefile -Linux64-Ubuntu : plain : GCC.sh --without-debug --with-mt --with-static --without-runpath --with-flat-makefile -FreeBSD64 : plain : Clang.sh --without-debug --without-mt --with-static --without-runpath --with-flat-makefile -IntelMAC : plain : GCC.sh --without-debug --without-mt --with-static --without-runpath --with-flat-makefile -Win64_13 : plain : static 64 ReleaseMT - +Linux64-Centos : plain : GCC.sh --without-debug --without-mt --with-static --without-runpath --with-flat-makefile +FreeBSD64 : plain : Clang.sh --without-debug --without-mt --with-static --without-runpath --with-flat-makefile +IntelMAC : plain : GCC.sh --without-debug --without-mt --with-static --without-runpath --with-flat-makefile +Win64_13 : plain : static 64 ReleaseMT +Linux64-Ubuntu : plain : GCC.sh --without-debug --without-mt --with-static --without-runpath --with-flat-makefile +Linux32-Ubuntu : plain : GCC.sh --without-debug --without-mt --with-static --without-runpath --with-flat-makefile #USE_COMPONENTS # diff --git a/c++/scripts/projects/ncbi_cpp.lst b/c++/scripts/projects/ncbi_cpp.lst index 69cc1c1e..6de642cb 100644 --- a/c++/scripts/projects/ncbi_cpp.lst +++ b/c++/scripts/projects/ncbi_cpp.lst @@ -18,6 +18,7 @@ internal/test/corelib internal/test/misc/xmlwrapp internal/demo/misc/xmlwrapp internal/ctoolkit +internal/util/flat2asn misc objects objmgr diff --git a/c++/scripts/projects/ncbi_cpp_dll.lst b/c++/scripts/projects/ncbi_cpp_dll.lst index 69cc1c1e..6de642cb 100644 --- a/c++/scripts/projects/ncbi_cpp_dll.lst +++ b/c++/scripts/projects/ncbi_cpp_dll.lst @@ -18,6 +18,7 @@ internal/test/corelib internal/test/misc/xmlwrapp internal/demo/misc/xmlwrapp internal/ctoolkit +internal/util/flat2asn misc objects objmgr diff --git a/c++/scripts/projects/ncbi_gui_base.lst b/c++/scripts/projects/ncbi_gui_base.lst index 913ebd1b..42a31eba 100644 --- a/c++/scripts/projects/ncbi_gui_base.lst +++ b/c++/scripts/projects/ncbi_gui_base.lst @@ -21,6 +21,7 @@ internal/gpipe/gencoll/src/gcaccess$ internal/gpipe/gencoll/src/gcstats$ internal/gpipe/gencoll/src/gc_load_utils$ internal/gpipe/gpinit/src/api$ +internal/gpipe/gpinit/src/asn_config/objects$ internal/gpipe/gpinit/src/gpinit_compare$ internal/gpipe/objects/gencoll_load$ internal/gpipe/objects/genomecoll$ @@ -31,6 +32,7 @@ misc/grid_cgi$ misc/xmlwrapp misc/eutils_client$ misc/hydra_client$ +misc/pmcidconv_client$ misc/discrepancy$ misc/discrepancy_report$ misc/biosample_util$ diff --git a/c++/scripts/projects/netcache/ChangeLog b/c++/scripts/projects/netcache/ChangeLog index 8ec5a0b8..a8f14d0f 100644 --- a/c++/scripts/projects/netcache/ChangeLog +++ b/c++/scripts/projects/netcache/ChangeLog @@ -194,8 +194,60 @@ Changed data separator in BLIST2 command output. Changed to treat cache and key names as precise matches in BLIST2 command. November 21, 2016 -version 6.11.2 (CXX-8749) +version 6.11.2 (CXX-8832) Corrected blob list separator and filters. +November 29, 2016 +version 6.11.3 (CXX-8842) +Introduced SoftFatal log severity + +December 14, 2016 +version 6.11.4 (CXX-8898) +Changed memory allocation algorithm. + +December 19, 2016 +version 6.11.5 (CXX-8912) +Added other memory managers + +January 11, 2017 +version 6.11.6 (CXX-8957) +Bug fixes + +February 01, 2017 +version 6.12.0 (CXX-9005) +Added option to purge all blobs with a given key in a cache. +Implemented delayed removal of purged blobs. +Switch to SC-18 +Switch to GCC 4.9.3 + +March 17, 2017 +version 6.12.1 (CXX-9128) +Added reporting of time consumed by different parts of command processing. +Added option to report and reload task_server settings. + +April 11, 2017 +version 6.13.0 (CXX-9179) +Modified reporting to add EXE path and command line. +Corrected re-initialization of periodic synchronization after disk space problems. + +May 08, 2017 +version 6.14.0 (CXX-9253) +Added noCreate flag, modified handling of noProlong one. + +May 11, 2017 +version 6.14.1 (CXX-9271) +Fixed calculation of blob coordinates. + +June 29, 2017 +version 6.14.2 (CXX-9380) +Corrected logic of blob mirroring between servers with different trust level. + +September 5, 2017 +version 6.14.3 (CXX-9548) +Added protection against failed memory allocations. +Corrected errors in handling missing database files. +Fixed error in thread synchronization. +Added prioritization of certain tasks to reduce CPU consumption and improve responce time. + diff --git a/c++/scripts/projects/netcache/Manifest b/c++/scripts/projects/netcache/Manifest index 0c015b9b..af390870 100644 --- a/c++/scripts/projects/netcache/Manifest +++ b/c++/scripts/projects/netcache/Manifest @@ -1,7 +1,7 @@ # # Filename: Manifest # -# $Id: Manifest 445512 2014-09-04 18:29:33Z gouriano $ +# $Id: Manifest 526222 2017-02-01 14:41:25Z gouriano $ # # Author: Sergey Satskiy # @@ -19,8 +19,16 @@ ETC: src/app/netcache/netcached.ini # Release configurator assumes that this script will eventually call standard configure script and pass all options # to it. So some standard options may be added by release configurator, such as --build-root-sfx, --with-projects, # --with-distcc, --with-action etc. -Linux64-Centos : O2 : GCC.sh 4.8.1 --without-debug --with-mt -Linux64-Centos : O2g : GCC.sh 4.8.1 --without-debug --with-symbols --with-mt -Linux64-Centos : d : GCC.sh 4.8.1 --without-debug --with-symbols --without-optimization --with-mt +Linux64-Centos : O2 : GCC.sh 4.9.3 --without-debug --with-mt +Linux64-Centos : O2g : GCC.sh 4.9.3 --without-debug --with-mt --with-symbols +Linux64-Centos : d : GCC.sh 4.9.3 --without-debug --with-mt --with-symbols --without-optimization + +Linux64-Centos : O2std : GCC.sh 4.9.3 NETCACHE_MEMORY_MAN_MODEL=-DNETCACHE_MEMORY_MAN_STD --without-debug --with-mt +Linux64-Centos : O2gstd : GCC.sh 4.9.3 NETCACHE_MEMORY_MAN_MODEL=-DNETCACHE_MEMORY_MAN_STD --without-debug --with-mt --with-symbols +Linux64-Centos : dstd : GCC.sh 4.9.3 NETCACHE_MEMORY_MAN_MODEL=-DNETCACHE_MEMORY_MAN_STD --without-debug --with-mt --with-symbols --without-optimization + +Linux64-Centos : O2tcm : GCC.sh 4.9.3 NETCACHE_MEMORY_MAN_MODEL=-DNETCACHE_MEMORY_MAN_TCM LIBS=-ltcmalloc --without-debug --with-mt +Linux64-Centos : O2gtcm : GCC.sh 4.9.3 NETCACHE_MEMORY_MAN_MODEL=-DNETCACHE_MEMORY_MAN_TCM LIBS=-ltcmalloc --without-debug --with-mt --with-symbols +Linux64-Centos : dtcm : GCC.sh 4.9.3 NETCACHE_MEMORY_MAN_MODEL=-DNETCACHE_MEMORY_MAN_TCM LIBS=-ltcmalloc --without-debug --with-mt --with-symbols --without-optimization USE_COMPONENTS diff --git a/c++/scripts/projects/netcache/README b/c++/scripts/projects/netcache/README index e87144c7..902f02c8 100644 --- a/c++/scripts/projects/netcache/README +++ b/c++/scripts/projects/netcache/README @@ -1 +1,6 @@ This is README file for NetCache application. + +http://ncbi.github.io/cxx-toolkit/pages/ch_app#ch_app.ncbi_netcache_service + +https://confluence.ncbi.nlm.nih.gov/pages/viewpage.action?pageId=63708023 + diff --git a/c++/scripts/projects/netcache/components.link b/c++/scripts/projects/netcache/components.link index 030537d7..33d657df 100644 --- a/c++/scripts/projects/netcache/components.link +++ b/c++/scripts/projects/netcache/components.link @@ -1,4 +1,4 @@ [components] -infrastructure 15.0 -core 15.0 -dbase 15.0 +infrastructure 18.0 +core 18.0 +dbase 18.0 diff --git a/c++/scripts/projects/netschedule/ChangeLog b/c++/scripts/projects/netschedule/ChangeLog index d6fba5a9..6ea88a18 100644 --- a/c++/scripts/projects/netschedule/ChangeLog +++ b/c++/scripts/projects/netschedule/ChangeLog @@ -1,3 +1,30 @@ +Release 4.30.1 cloned from 4.30.0 (2017-08-15) + +Improvements: + * NetSchedule: restore refuse submits and pause queue states after restart + (JIRA: CXX-9155) + * GRID debugging - send a job to a specific node (JIRA: CXX-5324) + +Release 4.30.0 cloned from 4.29.0 (2017-05-11) + +Improvements: + * Pass submitter's job status notification host and port to the WN. + (JIRA: CXX-9272) + + +Release 4.29.0 cloned from 4.28.3 (2017-05-10) + +Improvements: + * log timings for socket write errors (JIRA: CXX-9209) + * NetSchedule: qname to be replaced with _queue (JIRA: CXX-9241) + * NetSchedule -- allow to run in "memory-only" mode (JIRA: CXX-9245) + + +Release 4.28.3 cloned from 4.28.2 (2017-04-24) + +Improvements: + * Printing socket timing in case of socket write errors (JIRA: CXX-9209) + Release 4.28.2 cloned from 4.28.1 (2016-10-31) Improvements: diff --git a/c++/scripts/projects/netschedule/project.lst b/c++/scripts/projects/netschedule/project.lst index 5d799c29..cab6ecea 100644 --- a/c++/scripts/projects/netschedule/project.lst +++ b/c++/scripts/projects/netschedule/project.lst @@ -1,15 +1,22 @@ corelib$ +corelib/test$ util$ -util/regexp$ +util/regexp +util/xregexp util/compress util/fileblobstorage$ util/qparse$ +util/qparse/test$ util/bitset$ update-only util/cache$ update-only util/math$ update-only +util/test connect$ connect/services$ +connect/services/test$ connect/services/impl$ +connect/test$ +check db$ db/bdb$ app$ @@ -20,3 +27,4 @@ dll misc$ misc/third_party misc/third_party_static + diff --git a/c++/scripts/projects/netstorage/Manifest b/c++/scripts/projects/netstorage/Manifest index 2d4a4ad2..eb99f1ce 100644 --- a/c++/scripts/projects/netstorage/Manifest +++ b/c++/scripts/projects/netstorage/Manifest @@ -1,7 +1,7 @@ # # Filename: Manifest # -# $Id: Manifest 521097 2016-12-05 21:32:38Z fukanchi $ +# $Id: Manifest 523329 2016-12-30 21:38:54Z fukanchi $ # # Author: Sergey Satskiy # @@ -18,6 +18,7 @@ APP: netstoraged ETC: src/app/netstorage/netstoraged.ini APP: netstorage_gc ETC: src/app/netstorage/utils/netstorage_gc.ini +APP: test_netstorage DEFAULT_CONFIGURATIONS: Linux64-Centos:O2g @@ -32,5 +33,5 @@ Linux64-Centos : Release : GCC.sh 4.8.1 --without-debug --with-mt --with-flat-ma Linux64-Centos : Debug : GCC.sh 4.8.1 --with-debug --with-mt --with-flat-makefile Linux64-Centos : O2g : GCC.sh 4.8.1 --without-debug --with-mt --with-flat-makefile --with-symbols -USE_COMPONENTS +#USE_COMPONENTS diff --git a/c++/scripts/projects/netstorage/project.lst b/c++/scripts/projects/netstorage/project.lst index c0e52ca7..1201caec 100644 --- a/c++/scripts/projects/netstorage/project.lst +++ b/c++/scripts/projects/netstorage/project.lst @@ -1,6 +1,7 @@ corelib$ util$ util/regexp$ +util/xregexp util/compress util/qparse$ util/bitset$ update-only @@ -41,3 +42,4 @@ dbapi/driver/ftds95/impl update-only dbapi/driver/ftds95/freetds/replacements$ dbapi/driver/ftds-default dbapi/simple$ + diff --git a/c++/scripts/projects/netstorage_gc/project.lst b/c++/scripts/projects/netstorage_gc/project.lst index 3ae078cc..bc178705 100644 --- a/c++/scripts/projects/netstorage_gc/project.lst +++ b/c++/scripts/projects/netstorage_gc/project.lst @@ -9,6 +9,7 @@ util/math$ update-only connect$ connect/ext$ connect/services +connect/mbedtls db$ db/bdb$ app$ diff --git a/c++/scripts/projects/project_tree_builder/ChangeLog b/c++/scripts/projects/project_tree_builder/ChangeLog index d9c85eeb..e135a37c 100644 --- a/c++/scripts/projects/project_tree_builder/ChangeLog +++ b/c++/scripts/projects/project_tree_builder/ChangeLog @@ -310,3 +310,14 @@ Implemented library order analysis and generation. August 05, 2016 version 4.1.5, CXX-8435 Bug fixes. + +January 10, 2017 +version 4.2.0, CXX-8953 +Added random macro generation +Removed CMake file generation + +January 23, 2017 +version 4.2.1, CXX-8983 +Bug fix. + + diff --git a/c++/scripts/projects/project_tree_builder/Manifest b/c++/scripts/projects/project_tree_builder/Manifest index 050db130..8b248eb7 100644 --- a/c++/scripts/projects/project_tree_builder/Manifest +++ b/c++/scripts/projects/project_tree_builder/Manifest @@ -1,7 +1,7 @@ # # Filename: Manifest # -# $Id: Manifest 508788 2016-08-01 16:12:18Z fukanchi $ +# $Id: Manifest 524097 2017-01-09 19:36:13Z fukanchi $ # # Author: Sergey Satskiy # @@ -36,7 +36,7 @@ FreeBSD64 : plain : Clang.sh --without-debug --without-mt --with-stat IntelMAC : plain : GCC.sh --without-debug --without-mt --with-static --without-runpath --with-flat-makefile --without-ncbi-c -Win32_13 : msvc-13-static-32 : static 32 ReleaseMT +Win64_13 : static-64 : static 64 ReleaseMT XCode : plain : Xcode.sh 30 --without-debug --without-ncbi-c diff --git a/c++/scripts/projects/public/Manifest b/c++/scripts/projects/public/Manifest index 07a94854..22f012ce 100644 --- a/c++/scripts/projects/public/Manifest +++ b/c++/scripts/projects/public/Manifest @@ -1,7 +1,7 @@ # # Filename: Manifest # -# $Id: Manifest 521307 2016-12-07 18:54:25Z fukanchi $ +# $Id: Manifest 522269 2016-12-16 16:54:54Z fukanchi $ # # Author: # @@ -37,7 +37,7 @@ Linux64-Centos7 : Clang : Clang.sh 3.8.0 --with-debug --with-mt --with-flat-m Linux64-Ubuntu : plain-GCC : GCC.sh --without-debug --with-mt --with-flat-makefile --without-ncbi-c Linux32-Ubuntu : plain-GCC : GCC.sh --without-debug --with-mt --with-flat-makefile --without-ncbi-c -FreeBSD64 : plain : Clang.sh --without-debug --with-mt --with-flat-makefile --with-runpath --without-ncbi-c +FreeBSD64 : plain : Clang.sh --without-debug --with-mt --with-flat-makefile --with-runpath --without-ncbi-c --with-gnutls=/usr/local IntelMAC : Debug : GCC.sh --with-debug --with-dll --with-mt --with-flat-makefile --without-gcrypt --without-mysql --without-pcre --without-ncbi-c IntelMAC : Release : GCC.sh --without-debug --with-dll --with-mt --with-flat-makefile --without-gcrypt --without-mysql --without-pcre --without-ncbi-c diff --git a/c++/scripts/projects/public/project.lst b/c++/scripts/projects/public/project.lst index 21d6db7a..872046e8 100644 --- a/c++/scripts/projects/public/project.lst +++ b/c++/scripts/projects/public/project.lst @@ -43,7 +43,3 @@ misc/netstorage -objtools/data_loaders/genbank/pubseq2 -./scripts/internal -ctools/test --objects/seq/unit_test/Makefile.seq_c_compat_unit_test.app --objects/seq/unit_test/seq_c_compat_unit_test.cpp --objects/general/test/Makefile.test_userfield.app --objects/general/test/test_userfield.cpp diff --git a/c++/scripts/projects/python_ncbi_dbapi/ChangeLog b/c++/scripts/projects/python_ncbi_dbapi/ChangeLog index 736734e0..092ff009 100644 --- a/c++/scripts/projects/python_ncbi_dbapi/ChangeLog +++ b/c++/scripts/projects/python_ncbi_dbapi/ChangeLog @@ -1,3 +1,16 @@ +Version 1.19.2 (2017-09-06): +* Fix Python type object initialization code, addressing bogus + reported type names and more possible Python 3 crashes. + +Version 1.19.1 (2017-09-05): +* Avoid crashing at exit under Python 3. + +Version 1.19.0 (2017-08-31): +* Advance to version 20.0 of the stable C++ Toolkit components, with + mbed TLS favored over GNUTLS but the latter kept around for + compatibility (linked statically, as before). +* Log via the standard Python logging module. + Version 1.18.0 (2016-10-13): * Advance to version 18.0 of the stable C++ Toolkit components, with ftds95 as default ftds and support for contacting dispd over HTTPS. diff --git a/c++/scripts/projects/python_ncbi_dbapi/components.link b/c++/scripts/projects/python_ncbi_dbapi/components.link index 33d657df..1e2ab1dd 100644 --- a/c++/scripts/projects/python_ncbi_dbapi/components.link +++ b/c++/scripts/projects/python_ncbi_dbapi/components.link @@ -1,4 +1,4 @@ [components] -infrastructure 18.0 -core 18.0 -dbase 18.0 +infrastructure 20.0 +core 20.0 +dbase 20.0 diff --git a/c++/scripts/projects/python_ncbi_dbapi/project.lst b/c++/scripts/projects/python_ncbi_dbapi/project.lst index 6af5f98d..a7e5b18d 100644 --- a/c++/scripts/projects/python_ncbi_dbapi/project.lst +++ b/c++/scripts/projects/python_ncbi_dbapi/project.lst @@ -3,6 +3,7 @@ util$ util/bitset$ connect$ connect/ext$ +connect/mbedtls dll dbapi$ dbapi/driver$ diff --git a/c++/scripts/projects/test_ccpp_read/ChangeLog b/c++/scripts/projects/test_ccpp_read/ChangeLog index 7e509981..7b7430d5 100644 --- a/c++/scripts/projects/test_ccpp_read/ChangeLog +++ b/c++/scripts/projects/test_ccpp_read/ChangeLog @@ -10,5 +10,11 @@ Built using SC 9.0, r351635 Version 20120330.0.0 Built from trunk +version 20120605.10.0 +SC 10 + +version 20170112.0.0 +from trunk + diff --git a/c++/scripts/projects/test_ccpp_read/Manifest b/c++/scripts/projects/test_ccpp_read/Manifest index 8f2d5154..d2401373 100644 --- a/c++/scripts/projects/test_ccpp_read/Manifest +++ b/c++/scripts/projects/test_ccpp_read/Manifest @@ -1,7 +1,7 @@ # # Filename: Manifest # -# $Id: Manifest 483955 2015-11-05 15:16:36Z fukanchi $ +# $Id: Manifest 524619 2017-01-12 17:40:29Z gouriano $ # # Purpose: This file holds all the supported configurations of a package # It is used by release configurator. @@ -20,13 +20,13 @@ APP: test_ccpp_read # to it. So some standard options may be added by release configurator, such as --build-root-sfx, --with-projects, # --with-distcc, --with-action etc. -Linux32-Centos : plain : GCC.sh --without-debug --with-static --without-runpath --with-flat-makefile +#Linux32-Centos : plain : GCC.sh --without-debug --with-static --without-runpath --with-flat-makefile Linux64-Centos : plain : GCC.sh --without-debug --with-static --without-runpath --with-flat-makefile IntelMAC : plain : GCC.sh --without-debug --with-static --without-runpath --with-flat-makefile -Win32_13 : plain : static 32 ReleaseDLL +#Win32_13 : plain : static 32 ReleaseDLL Win64_13 : plain : static 64 ReleaseDLL -USE_COMPONENTS +#USE_COMPONENTS diff --git a/c++/scripts/projects/test_ccpp_read/project.lst b/c++/scripts/projects/test_ccpp_read/project.lst index 509708e3..f886e7a1 100644 --- a/c++/scripts/projects/test_ccpp_read/project.lst +++ b/c++/scripts/projects/test_ccpp_read/project.lst @@ -1,5 +1,6 @@ #define TAGS [perf] corelib$ +connect$ serial$ serial/datatool$ util$ @@ -19,8 +20,11 @@ objects/seqfeat$ objects/seqloc$ objects/seqres$ objects/seqset$ -objects/seqtable$ +objects/seqtable objects/misc$ +objtools$ +objtools/data_loaders$ +objtools/data_loaders/asn_cache db$ db/bdb$ internal$ diff --git a/c++/scripts/projects/testres-testapp/ChangeLog b/c++/scripts/projects/testres-testapp/ChangeLog new file mode 100644 index 00000000..eea80289 --- /dev/null +++ b/c++/scripts/projects/testres-testapp/ChangeLog @@ -0,0 +1 @@ +Jan 17, 2017 First release diff --git a/c++/scripts/projects/testres-testapp/LICENSE b/c++/scripts/projects/testres-testapp/LICENSE new file mode 100644 index 00000000..f3577c23 --- /dev/null +++ b/c++/scripts/projects/testres-testapp/LICENSE @@ -0,0 +1,19 @@ + PUBLIC DOMAIN NOTICE + National Center for Biotechnology Information + + This software/database is a "United States Government Work" under the + terms of the United States Copyright Act. It was written as part of + the author's official duties as a United States Government employee and + thus cannot be copyrighted. This software/database is freely available + to the public for use. The National Library of Medicine and the U.S. + Government have not placed any restriction on its use or reproduction. + + Although all reasonable efforts have been taken to ensure the accuracy + and reliability of the software and data, the NLM and the U.S. + Government do not and cannot warrant the performance or results that + may be obtained by using this software or data. The NLM and the U.S. + Government disclaim all warranties, express or implied, including + warranties of performance, merchantability or fitness for any particular + purpose. + + Please cite the author in any work or product based on this material. diff --git a/c++/scripts/projects/testres-testapp/Manifest b/c++/scripts/projects/testres-testapp/Manifest new file mode 100644 index 00000000..55c2adae --- /dev/null +++ b/c++/scripts/projects/testres-testapp/Manifest @@ -0,0 +1,24 @@ +# +# Filename: Manifest +# +# $Id: Manifest 524988 2017-01-18 10:52:07Z zakharov $ +# +# Author: Mikhail Zakharov (template by Sergey Satskiy) +# +# Purpose: This file holds all the supported configurations of a package +# It is used by release configurator. +# +USE_COMPONENTS + +APP: testres_example + +#ini file +COPY: $srcdir/src/internal/cppcore/testres/examples/exampleapp/testres_example.ini $installdir/bin + +Linux64-Centos : O2g : GCC.sh 4.9.3 --without-debug --with-symbols --with-mt --with-static --without-runpath --with-flat-makefile --without-ncbi-c + +Linux64-Centos : dbg : GCC.sh 4.9.3 --with-debug --with-symbols --with-mt --with-static --without-runpath --with-flat-makefile --without-ncbi-c +Linux64-Centos : O2 : GCC.sh 4.9.3 --without-debug --with-mt --with-static --without-runpath --with-flat-makefile --without-ncbi-c + + + diff --git a/c++/scripts/projects/testres-testapp/README b/c++/scripts/projects/testres-testapp/README new file mode 100644 index 00000000..4e1aa75e --- /dev/null +++ b/c++/scripts/projects/testres-testapp/README @@ -0,0 +1,2 @@ +Example command line application to be tested by TestRes CI + diff --git a/c++/scripts/projects/testres-testapp/components.link b/c++/scripts/projects/testres-testapp/components.link new file mode 100644 index 00000000..a601e50b --- /dev/null +++ b/c++/scripts/projects/testres-testapp/components.link @@ -0,0 +1,6 @@ +[components] +infrastructure 18.0 +core 18.0 +web 18.0 +misc 18.0 +app 18.0 diff --git a/c++/scripts/projects/testres-testapp/project.lst b/c++/scripts/projects/testres-testapp/project.lst new file mode 100644 index 00000000..fdf5b210 --- /dev/null +++ b/c++/scripts/projects/testres-testapp/project.lst @@ -0,0 +1,16 @@ +cgi$ +corelib$ +util$ +connect$ +connect/ext$ +connect/impl$ +connect/services$ +connect/daemons$ +html$ +misc$ +misc/xmlwrapp$ +misc/xmlwrapp/impl$ +boost +internal$ +internal/cppcore$ +internal/cppcore/testres/examples/exampleapp diff --git a/c++/scripts/projects/testres-testcgi/ChangeLog b/c++/scripts/projects/testres-testcgi/ChangeLog new file mode 100644 index 00000000..eea80289 --- /dev/null +++ b/c++/scripts/projects/testres-testcgi/ChangeLog @@ -0,0 +1 @@ +Jan 17, 2017 First release diff --git a/c++/scripts/projects/testres-testcgi/LICENSE b/c++/scripts/projects/testres-testcgi/LICENSE new file mode 100644 index 00000000..f3577c23 --- /dev/null +++ b/c++/scripts/projects/testres-testcgi/LICENSE @@ -0,0 +1,19 @@ + PUBLIC DOMAIN NOTICE + National Center for Biotechnology Information + + This software/database is a "United States Government Work" under the + terms of the United States Copyright Act. It was written as part of + the author's official duties as a United States Government employee and + thus cannot be copyrighted. This software/database is freely available + to the public for use. The National Library of Medicine and the U.S. + Government have not placed any restriction on its use or reproduction. + + Although all reasonable efforts have been taken to ensure the accuracy + and reliability of the software and data, the NLM and the U.S. + Government do not and cannot warrant the performance or results that + may be obtained by using this software or data. The NLM and the U.S. + Government disclaim all warranties, express or implied, including + warranties of performance, merchantability or fitness for any particular + purpose. + + Please cite the author in any work or product based on this material. diff --git a/c++/scripts/projects/testres-testcgi/Manifest b/c++/scripts/projects/testres-testcgi/Manifest new file mode 100644 index 00000000..ce518ad7 --- /dev/null +++ b/c++/scripts/projects/testres-testcgi/Manifest @@ -0,0 +1,24 @@ +# +# Filename: Manifest +# +# $Id: Manifest 524988 2017-01-18 10:52:07Z zakharov $ +# +# Author: Mikhail Zakharov (template by Sergey Satskiy) +# +# Purpose: This file holds all the supported configurations of a package +# It is used by release configurator. +# +USE_COMPONENTS + +APP: testres_example_cgi + +#ini file +COPY: $srcdir/src/internal/cppcore/testres/examples/examplecgi.ini $installdir/bin + +Linux64-Centos : O2g : GCC.sh 4.9.3 --without-debug --with-symbols --with-mt --with-static --without-runpath --with-flat-makefile --without-ncbi-c + +Linux64-Centos : dbg : GCC.sh 4.9.3 --with-debug --with-symbols --with-mt --with-static --without-runpath --with-flat-makefile --without-ncbi-c +Linux64-Centos : O2 : GCC.sh 4.9.3 --without-debug --with-mt --with-static --without-runpath --with-flat-makefile --without-ncbi-c + + + diff --git a/c++/scripts/projects/testres-testcgi/README b/c++/scripts/projects/testres-testcgi/README new file mode 100644 index 00000000..a5d8452f --- /dev/null +++ b/c++/scripts/projects/testres-testcgi/README @@ -0,0 +1,9 @@ +TestRes kernel - execution framework of the NCBI internal regression testing framework + +Started as testipub replacement (CXX-2091) + +Package includes: +1. TestRes kernel +2. Test templates specific to the version +3. TestRes kernel modules for foreign (TCeX and python) test import + diff --git a/c++/scripts/projects/testres-testcgi/components.link b/c++/scripts/projects/testres-testcgi/components.link new file mode 100644 index 00000000..a601e50b --- /dev/null +++ b/c++/scripts/projects/testres-testcgi/components.link @@ -0,0 +1,6 @@ +[components] +infrastructure 18.0 +core 18.0 +web 18.0 +misc 18.0 +app 18.0 diff --git a/c++/scripts/projects/testres-testcgi/project.lst b/c++/scripts/projects/testres-testcgi/project.lst new file mode 100644 index 00000000..fdf5b210 --- /dev/null +++ b/c++/scripts/projects/testres-testcgi/project.lst @@ -0,0 +1,16 @@ +cgi$ +corelib$ +util$ +connect$ +connect/ext$ +connect/impl$ +connect/services$ +connect/daemons$ +html$ +misc$ +misc/xmlwrapp$ +misc/xmlwrapp/impl$ +boost +internal$ +internal/cppcore$ +internal/cppcore/testres/examples/exampleapp diff --git a/c++/scripts/projects/xmlwrapp/Manifest b/c++/scripts/projects/xmlwrapp/Manifest index 0635797e..0916ed16 100644 --- a/c++/scripts/projects/xmlwrapp/Manifest +++ b/c++/scripts/projects/xmlwrapp/Manifest @@ -1,7 +1,7 @@ # # Filename: Manifest # -# $Id: Manifest 517162 2016-10-20 22:47:37Z fukanchi $ +# $Id: Manifest 535203 2017-05-05 21:37:57Z fukanchi $ # # Author: Sergey Satskiy # @@ -41,16 +41,13 @@ Linux32-Ubuntu : plain-GCC : GCC.sh --without-debug --with-mt Cygwin64 : GCC : GCC.sh --without-debug --with-mt --without-runpath --with-flat-makefile -IntelMAC : plain : GCC.sh --without-debug --with-mt --without-runpath --with-flat-makefile --with-3psw=system:netopt --without-ncbi-public -IntelMAC : GCC : GCC.sh --without-debug --with-mt --without-runpath --with-flat-makefile - -Win64_13 : 13-debug-64 : static 64 DebugDLL +Win64_13 : 13-debug-64 : static 64 DebugDLL Win64_13 : 13-static-64 : static 64 ReleaseDLL -XCode : plain : Xcode.sh 30 - - - IntelMAC-Clang36 : clang : Clang.sh --without-debug --with-mt --without-runpath --with-flat-makefile --with-3psw=system:netopt --without-ncbi-public +IntelMAC : plain : GCC.sh --without-debug --with-mt --without-runpath --with-flat-makefile --with-3psw=system:netopt --without-ncbi-public +IntelMAC : GCC : GCC.sh --without-debug --with-mt --without-runpath --with-flat-makefile +XCode : plain : Xcode.sh 30 Linux64-Centos7 : Release : GCC.sh --without-debug --with-mt --without-runpath --with-flat-makefile + diff --git a/c++/scripts/projects/xmlwrapp/project.lst b/c++/scripts/projects/xmlwrapp/project.lst index 9f2e0bf2..6c540243 100644 --- a/c++/scripts/projects/xmlwrapp/project.lst +++ b/c++/scripts/projects/xmlwrapp/project.lst @@ -28,3 +28,4 @@ util/bitset$ serial$ serial/datatool$ connect$ +connect/mbedtls diff --git a/c++/src/CMakeLists.txt b/c++/src/CMakeLists.txt new file mode 100644 index 00000000..1f2ee01e --- /dev/null +++ b/c++/src/CMakeLists.txt @@ -0,0 +1,40 @@ +############################################################################## +# CMakeLists.txt autogenerated from /net/nasan50/vol/gpipe_dev/dicuccio/cpp-toolkit/cpp-cmake/src/Makefile.in +# + +# We require at least cmake-3.0 +cmake_minimum_required(VERSION 3.0) + +project(CPP) + +include(build-system/cmake/CMakeMacros.cmake) +include(build-system/cmake/CMakeChecks.cmake) +# Include projects from this directory + +# Recurse subdirectories +add_subdirectory(corelib) +add_subdirectory(util) +add_subdirectory(connect) +add_subdirectory(cgi) +add_subdirectory(html) +add_subdirectory(build-system) +add_subdirectory(serial) +add_subdirectory(db) +add_subdirectory(dbapi) +add_subdirectory(objects) +add_subdirectory(objmgr) +add_subdirectory(objtools) +add_subdirectory(ctools) +add_subdirectory(algo) +add_subdirectory(misc) +add_subdirectory(sra) +add_subdirectory(app) + +add_subdirectory_optional(gui) +add_subdirectory_optional(sample) +add_subdirectory_optional(internal) + +## # Legacy targets from old build system +## add_custom_target(all_f DEPENDS all) +## add_custom_target(all_r DEPENDS all) +## add_custom_target(all_p DEPENDS all) diff --git a/c++/src/Makefile.in b/c++/src/Makefile.in index f44cbac1..fdb0ee9b 100644 --- a/c++/src/Makefile.in +++ b/c++/src/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in 521318 2016-12-07 19:37:59Z blastadm $ +# $Id: Makefile.in 548943 2017-10-18 23:45:19Z blastadm $ # Master (top-level) makefile for all NCBI C++ projects ################################################################## diff --git a/c++/src/algo/CMakeLists.txt b/c++/src/algo/CMakeLists.txt new file mode 100644 index 00000000..b5549530 --- /dev/null +++ b/c++/src/algo/CMakeLists.txt @@ -0,0 +1,24 @@ +############################################################################## +# CMakeLists.txt autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake/src/algo/Makefile.in +# + +# Include projects from this directory + +# Recurse subdirectories +add_subdirectory_optional(align) +add_subdirectory_optional(blast) +add_subdirectory_optional(cobalt) +add_subdirectory_optional(dustmask) +add_subdirectory_optional(gnomon) +add_subdirectory_optional(id_mapper) +add_subdirectory_optional(ms) +add_subdirectory_optional(phy_tree) +add_subdirectory_optional(primer) +add_subdirectory_optional(segmask) +add_subdirectory_optional(seqqa) +add_subdirectory_optional(sequence) +add_subdirectory_optional(structure) +add_subdirectory_optional(text) +add_subdirectory_optional(tree) +add_subdirectory_optional(volume_merge) +add_subdirectory_optional(winmask) diff --git a/c++/src/algo/blast/CMakeLists.txt b/c++/src/algo/blast/CMakeLists.txt new file mode 100644 index 00000000..33ff302e --- /dev/null +++ b/c++/src/algo/blast/CMakeLists.txt @@ -0,0 +1,19 @@ +############################################################################## +# +# + +# Include projects from this directory + +# Recurse subdirectories +add_subdirectory(composition_adjustment) +add_subdirectory(core) +add_subdirectory(dbindex) +add_subdirectory(dbindex_search) +add_subdirectory(api) +add_subdirectory(format) +add_subdirectory(blastinput) +add_subdirectory(igblast) +add_subdirectory(gumbel_params) +add_subdirectory(proteinkmer) +add_subdirectory(unit_tests) +add_subdirectory(blast_sra_input) diff --git a/c++/src/algo/blast/Makefile.blast_macros.mk b/c++/src/algo/blast/Makefile.blast_macros.mk index 7870c5ec..56c8e253 100644 --- a/c++/src/algo/blast/Makefile.blast_macros.mk +++ b/c++/src/algo/blast/Makefile.blast_macros.mk @@ -1,5 +1,5 @@ ################################# -# $Id: Makefile.blast_macros.mk 499473 2016-04-26 14:40:22Z camacho $ +# $Id: Makefile.blast_macros.mk 536799 2017-05-23 16:19:30Z madden $ # This file contains macro definitions for using libraries maintained by the # BLAST TEAM # Author: Christiam Camacho (camacho@ncbi.nlm.nih.gov) @@ -18,7 +18,8 @@ BLAST_INPUT_LIBS = blastinput \ BLAST_SRA_LIBS=blast_sra $(SRAXF_LIBS) vxf $(SRA_LIBS) # BLAST_FORMATTER_LIBS and BLAST_INPUT_LIBS need $BLAST_LIBS -BLAST_LIBS = xblast xalgoblastdbindex composition_adjustment \ - xalgodustmask xalgowinmask seqmasks_io seqdb blast_services xalnmgr \ - xobjutil $(OBJREAD_LIBS) xnetblastcli xnetblast blastdb scoremat tables +BLAST_LDEP = xalgoblastdbindex composition_adjustment \ + xalgodustmask xalgowinmask seqmasks_io seqdb blast_services xalnmgr \ + xobjutil $(OBJREAD_LIBS) xnetblastcli xnetblast blastdb scoremat tables +BLAST_LIBS = proteinkmer xblast $(BLAST_LDEP) # BLAST additionally needs xconnect $(SOBJMGR_LIBS) or $(OBJMGR_LIBS) diff --git a/c++/src/algo/blast/Makefile.in b/c++/src/algo/blast/Makefile.in index 054e7569..b5910ef4 100644 --- a/c++/src/algo/blast/Makefile.in +++ b/c++/src/algo/blast/Makefile.in @@ -1,10 +1,10 @@ -# $Id: Makefile.in 507884 2016-07-22 02:13:25Z ucko $ +# $Id: Makefile.in 536762 2017-05-23 14:52:38Z madden $ # Meta-makefile ("BLAST" project) ################################# -SUB_PROJ = composition_adjustment core dbindex dbindex_search api format \ - blastinput blast_sra_input igblast gumbel_params unit_tests +SUB_PROJ = composition_adjustment core dbindex dbindex_search api proteinkmer \ + format blastinput blast_sra_input igblast gumbel_params unit_tests WATCHERS = camacho madden diff --git a/c++/src/algo/blast/api/CMakeLists.txt b/c++/src/algo/blast/api/CMakeLists.txt new file mode 100644 index 00000000..64c53086 --- /dev/null +++ b/c++/src/algo/blast/api/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xblast.lib.txt) + diff --git a/c++/src/algo/blast/api/CMakeLists.xblast.lib.txt b/c++/src/algo/blast/api/CMakeLists.xblast.lib.txt new file mode 100644 index 00000000..dd09b16d --- /dev/null +++ b/c++/src/algo/blast/api/CMakeLists.xblast.lib.txt @@ -0,0 +1,91 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/api/Makefile.xblast.lib +# + +include (../core/CMakeLists.blast.objs.txt) + +add_library(xblast + ${SRC_C} + + blast_aux + blast_options_cxx + blast_options_local_priv + blast_options_builder + blast_setup_cxx + blast_seqalign + blast_options_handle + blast_nucl_options + disc_nucl_options + blast_prot_options + psiblast_options + blast_rps_options + blastx_options + tblastx_options + tblastn_options + rpstblastn_options + phiblast_nucl_options + phiblast_prot_options + pssm_engine + local_blast + remote_blast + seqinfosrc_seqvec + seqinfosrc_seqdb + seqinfosrc_bioseq + seqsrc_multiseq + seqsrc_seqdb + seqsrc_query_factory + bl2seq + blast_objmgr_tools + repeats_filter_cxx + blast_mtlock + psibl2seq + local_db_adapter + psiblast + psiblast_impl + psiblast_iteration + psi_pssm_input + msa_pssm_input + psiblast_aux_priv + blast_aux_priv + blast_advprot_options + blastp_kmer_options + version + dust_filter + rps_aux + search_strategy + setup_factory + prelim_stage + traceback_stage + uniform_search + local_search + blast_results + remote_search + query_data + objmgr_query_data + objmgrfree_query_data + bioseq_extract_data_priv + effsearchspace_calc + blast_seqinfosrc_aux + blast_dbindex + split_query_cxx + split_query_aux_priv + split_query_blk + winmask_filter + subj_ranges_set + rpsblast_local + seedtop + cdd_pssm_input + deltablast_options + deltablast + magicblast_options + magicblast +) + +target_link_libraries(xblast + xalgoblastdbindex xalgodustmask xalgowinmask + xnetblastcli +) +add_dependencies(xblast + seq xnetblast scoremat blastdb +) + diff --git a/c++/src/algo/blast/api/Makefile.xblast.lib b/c++/src/algo/blast/api/Makefile.xblast.lib index 52c95d77..2fa35c64 100644 --- a/c++/src/algo/blast/api/Makefile.xblast.lib +++ b/c++/src/algo/blast/api/Makefile.xblast.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.xblast.lib 504861 2016-06-20 15:45:40Z boratyng $ +# $Id: Makefile.xblast.lib 536799 2017-05-23 16:19:30Z madden $ include $(srcdir)/../core/Makefile.blast.lib @@ -45,6 +45,7 @@ msa_pssm_input \ psiblast_aux_priv \ blast_aux_priv \ blast_advprot_options \ +blastp_kmer_options \ version \ dust_filter \ rps_aux \ @@ -80,10 +81,7 @@ SRC = $(SRC_C:%=.core_%) $(SRC_CXX) LIB = xblast -DLL_LIB = xalgoblastdbindex composition_adjustment xalgowinmask \ - xalgodustmask seqmasks_io seqdb $(OBJREAD_LIBS) xobjutil \ - blastdb xnetblastcli xnetblast scoremat xconnect tables \ - $(SOBJMGR_LIBS) +DLL_LIB = $(BLAST_LDEP) $(SOBJMGR_LIBS) CFLAGS = $(FAST_CFLAGS) CPPFLAGS = -DNCBI_MODULE=BLAST $(ORIG_CPPFLAGS) diff --git a/c++/src/algo/blast/api/bioseq_extract_data_priv.hpp b/c++/src/algo/blast/api/bioseq_extract_data_priv.hpp index 35364bd7..034a2323 100644 --- a/c++/src/algo/blast/api/bioseq_extract_data_priv.hpp +++ b/c++/src/algo/blast/api/bioseq_extract_data_priv.hpp @@ -1,4 +1,4 @@ -/* $Id: bioseq_extract_data_priv.hpp 517499 2016-10-25 17:20:41Z ivanov $ +/* $Id: bioseq_extract_data_priv.hpp 516747 2016-10-17 19:00:07Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/api/bl2seq.cpp b/c++/src/algo/blast/api/bl2seq.cpp index a02dada6..8a37195c 100644 --- a/c++/src/algo/blast/api/bl2seq.cpp +++ b/c++/src/algo/blast/api/bl2seq.cpp @@ -1,4 +1,4 @@ -/* $Id: bl2seq.cpp 478658 2015-09-11 14:30:02Z madden $ +/* $Id: bl2seq.cpp 526381 2017-02-02 14:59:08Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -155,7 +155,6 @@ CBl2Seq::CSearchResultSet2TSeqAlignVector(CRef res) if (res.Empty()) { return TSeqAlignVector(); } - _ASSERT(res->GetResultType() == eSequenceComparison); TSeqAlignVector retval; retval.reserve(res->GetNumResults()); ITERATE(CSearchResultSet, r, *res) { @@ -210,7 +209,6 @@ CBl2Seq::RunEx() mi_pDiagnostics = Blast_DiagnosticsCopy(m_Blast->m_InternalData->m_Diagnostics->GetPointer()); } - _ASSERT(m_Results->GetResultType() == eSequenceComparison); return m_Results; } diff --git a/c++/src/algo/blast/api/blast_aux.cpp b/c++/src/algo/blast/api/blast_aux.cpp index 956d0b99..9c928135 100644 --- a/c++/src/algo/blast/api/blast_aux.cpp +++ b/c++/src/algo/blast/api/blast_aux.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_aux.cpp 509279 2016-08-04 16:02:34Z ivanov $ +/* $Id: blast_aux.cpp 519527 2016-11-16 14:19:45Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -232,6 +232,7 @@ CBlastHitSavingOptions::DebugDump(CDebugDumpContext ddc, unsigned int /*depth*/) ddc.Log("hitlist_size", m_Ptr->hitlist_size); ddc.Log("hsp_num_max", m_Ptr->hsp_num_max); + ddc.Log("max_hsps_per_subject", m_Ptr->max_hsps_per_subject); ddc.Log("total_hsp_limit", m_Ptr->total_hsp_limit); ddc.Log("culling_limit", m_Ptr->culling_limit); ddc.Log("expect_value", m_Ptr->expect_value); diff --git a/c++/src/algo/blast/api/blast_aux_priv.cpp b/c++/src/algo/blast/api/blast_aux_priv.cpp index 8e4be3e1..28abae4f 100644 --- a/c++/src/algo/blast/api/blast_aux_priv.cpp +++ b/c++/src/algo/blast/api/blast_aux_priv.cpp @@ -121,11 +121,11 @@ BlastErrorCode2String(Int2 error_code) CRef BlastSetupPreliminarySearch(CRef query_factory, CRef options, - bool is_multi_threaded /* = false */) + size_t num_threads /* = 1 */) { return BlastSetupPreliminarySearchEx(query_factory, options, CRef(), - NULL, is_multi_threaded); + NULL, num_threads); } CRef @@ -133,11 +133,12 @@ BlastSetupPreliminarySearchEx(CRef qf, CRef options, CConstRef pssm, BlastSeqSrc* seqsrc, - bool is_multi_threaded) + size_t num_threads) { CRef retval(new SBlastSetupData(qf, options)); TSearchMessages m; options->Validate(); + bool is_multi_threaded = num_threads > 1; // 0. Initialize the megablast database index. if (options->GetUseIndex()) { @@ -169,12 +170,11 @@ BlastSetupPreliminarySearchEx(CRef qf, // 4. Create the BlastScoreBlk BlastSeqLoc* lookup_segments = NULL; BlastScoreBlk* sbp = NULL; - bool is_mapper = (options->GetProgram() == eMapper); try { sbp = CSetupFactory::CreateScoreBlock(opts_memento.get(), query_data, &lookup_segments, retval->m_Messages, - (is_mapper ? NULL : &retval->m_Masks), + &retval->m_Masks, retval->m_InternalData->m_RpsData); } catch (CBlastException & e) { const string kCatchThisError (kBlastErrMsg_CantCalculateUngappedKAParams); @@ -209,7 +209,8 @@ BlastSetupPreliminarySearchEx(CRef qf, CSetupFactory::CreateLookupTable(query_data, opts_memento.get(), sbp, lookup_segments_wrap, retval->m_InternalData->m_RpsData, - seqsrc); + seqsrc, + num_threads); retval->m_InternalData->m_LookupTable.Reset (new TLookupTableWrap(lut, LookupTableWrapFree)); } diff --git a/c++/src/algo/blast/api/blast_aux_priv.hpp b/c++/src/algo/blast/api/blast_aux_priv.hpp index 994624c3..902838b5 100644 --- a/c++/src/algo/blast/api/blast_aux_priv.hpp +++ b/c++/src/algo/blast/api/blast_aux_priv.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_aux_priv.hpp 161402 2009-05-27 17:35:47Z camacho $ +/* $Id: blast_aux_priv.hpp 521162 2016-12-06 15:28:14Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -118,14 +118,16 @@ struct SBlastSetupData : public CObject { TSearchMessages m_Messages; }; + /// Set up internal data structures used by the BLAST CORE engine /// @param query_factory source of query sequence data structures [in] /// @param options BLAST options [in] -/// @param is_multi_threaded whether this search is multi-threaded or not [in] +/// @param num_threads number of threads [in] CRef BlastSetupPreliminarySearch(CRef query_factory, CRef options, - bool is_multi_threaded = false); + size_t num_threads = 1); + /// Extended interface to set up internal data structures used by the BLAST /// CORE engine @@ -133,13 +135,13 @@ BlastSetupPreliminarySearch(CRef query_factory, /// @param options BLAST options [in] /// @param pssm PSSM [in] /// @param seqsrc source of database/subject sequence data [in] -/// @param is_multi_threaded whether this search is multi-threaded or not [in] +/// @param num_threads number of threads to use [in] CRef BlastSetupPreliminarySearchEx(CRef qf, CRef options, CConstRef pssm, BlastSeqSrc* seqsrc, - bool is_multi_threaded); + size_t num_threads); /// Builds an CSearchResultSet::TAncillaryVector /// @param program BLAST program [in] diff --git a/c++/src/algo/blast/api/blast_dbindex.cpp b/c++/src/algo/blast/api/blast_dbindex.cpp index b9016454..b42337c3 100644 --- a/c++/src/algo/blast/api/blast_dbindex.cpp +++ b/c++/src/algo/blast/api/blast_dbindex.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_dbindex.cpp 412159 2013-09-04 21:12:36Z ucko $ +/* $Id: blast_dbindex.cpp 536746 2017-05-23 12:44:32Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1109,7 +1109,8 @@ std::string DbIndexInit( } catch( CException & e ) { ERR_POST( Info << "old style index failed to load" ); - result += '\n' + e.what(); + result += "\n"; + result += e.what(); } return result; diff --git a/c++/src/algo/blast/api/blast_objmgr_priv.hpp b/c++/src/algo/blast/api/blast_objmgr_priv.hpp index d0b7f0c9..afc8156a 100644 --- a/c++/src/algo/blast/api/blast_objmgr_priv.hpp +++ b/c++/src/algo/blast/api/blast_objmgr_priv.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_objmgr_priv.hpp 517499 2016-10-25 17:20:41Z ivanov $ +/* $Id: blast_objmgr_priv.hpp 516747 2016-10-17 19:00:07Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/api/blast_options_builder.cpp b/c++/src/algo/blast/api/blast_options_builder.cpp index e80995b6..a8831b4d 100644 --- a/c++/src/algo/blast/api/blast_options_builder.cpp +++ b/c++/src/algo/blast/api/blast_options_builder.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_options_builder.cpp 513039 2016-09-06 19:42:59Z fukanchi $ +/* $Id: blast_options_builder.cpp 512725 2016-09-02 14:13:18Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/api/blast_options_cxx.cpp b/c++/src/algo/blast/api/blast_options_cxx.cpp index 2f9f845f..17b7211c 100644 --- a/c++/src/algo/blast/api/blast_options_cxx.cpp +++ b/c++/src/algo/blast/api/blast_options_cxx.cpp @@ -41,6 +41,8 @@ #include #include +#include +#include #include /** @addtogroup AlgoBlast @@ -1356,6 +1358,66 @@ CBlastOptions::SetWindowMaskerDatabase(const char * value) } } +bool +CBlastOptions::GetReadQualityFiltering() const +{ + if (!m_Local) { + x_Throwx("Error: GetReadQualityFiltering() not available."); + } + + return m_Local->GetReadQualityFiltering(); +} + +void +CBlastOptions::SetReadQualityFiltering(bool val /* = true */) +{ + if (!m_Local) { + x_Throwx("Error: SetReadQualityFiltering() not available."); + } + + m_Local->SetReadQualityFiltering(val); +} + +double +CBlastOptions::GetReadMaxFractionAmbiguous() const +{ + if (!m_Local) { + x_Throwx("Error: GetReadMaxFractionAmbiguous() not available."); + } + + return m_Local->GetReadMaxFractionAmbiguous(); +} + +void +CBlastOptions::SetReadMaxFractionAmbiguous(double val) +{ + if (!m_Local) { + x_Throwx("Error: SetReadMaxFractionAmbiguous() not available."); + } + + m_Local->SetReadMaxFractionAmbiguous(val); +} + +int +CBlastOptions::GetReadMinDimerEntropy() const +{ + if (!m_Local) { + x_Throwx("Error: GetReadMinDimerEntropy() not available."); + } + + return m_Local->GetReadMinDimerEntropy(); +} + +void +CBlastOptions::SetReadMinDimerEntropy(int val) +{ + if (!m_Local) { + x_Throwx("Error: SetReadMinDimerEntropy() not available."); + } + + m_Local->SetReadMinDimerEntropy(val); +} + objects::ENa_strand CBlastOptions::GetStrandOption() const { @@ -1808,6 +1870,23 @@ CBlastOptions::SetCutoffScore(int s) } } +vector +CBlastOptions::GetCutoffScoreCoeffs() const +{ + if (! m_Local) { + x_Throwx("Error: GetCutoffScoreCoeffs() not available."); + } + return m_Local->GetCutoffScoreCoeffs(); +} +void +CBlastOptions::SetCutoffScoreCoeffs(const vector& c) +{ + if (!m_Local) { + x_Throwx("Error: SetCutoffScoreCoeffs() not available."); + } + m_Local->SetCutoffScoreCoeffs(c); +} + double CBlastOptions::GetPercentIdentity() const { @@ -1827,6 +1906,25 @@ CBlastOptions::SetPercentIdentity(double p) } } +int +CBlastOptions::GetMaxEditDistance() const +{ + if (! m_Local) { + x_Throwx("Error: GetMaxEditDistance() not available."); + } + return m_Local->GetMaxEditDistance(); +} +void +CBlastOptions::SetMaxEditDistance(int e) +{ + if (m_Local) { + m_Local->SetMaxEditDistance(e); + } + if (m_Remote) { + x_Throwx("Error: SetMaxEditDistance() not available."); + } +} + double CBlastOptions::GetQueryCovHspPerc() const { diff --git a/c++/src/algo/blast/api/blast_options_handle.cpp b/c++/src/algo/blast/api/blast_options_handle.cpp index 1845678c..84f526e8 100644 --- a/c++/src/algo/blast/api/blast_options_handle.cpp +++ b/c++/src/algo/blast/api/blast_options_handle.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_options_handle.cpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_options_handle.cpp 535507 2017-05-09 15:35:47Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -48,6 +48,7 @@ #include #include #include +#include /** @addtogroup AlgoBlast * @@ -191,6 +192,10 @@ CBlastOptionsFactory::Create(EProgram program, EAPILocality locality) retval = new CMagicBlastOptionsHandle(locality); break; + case eKBlastp: + retval = new CBlastpKmerOptionsHandle(locality); + break; + case eBlastNotSet: NCBI_THROW(CBlastException, eInvalidArgument, "eBlastNotSet may not be used as argument"); @@ -221,6 +226,7 @@ CBlastOptionsFactory::GetTasks(ETaskSets choice /* = eAll */) retval.insert("blastp"); retval.insert("blastp-short"); retval.insert("blastp-fast"); + // retval.insert("kblastp"); } if (choice == eAll) { @@ -236,6 +242,7 @@ CBlastOptionsFactory::GetTasks(ETaskSets choice /* = eAll */) retval.insert("tblastn-fast"); retval.insert("psitblastn"); retval.insert("tblastx"); + retval.insert("kblastp"); } if (choice == eMapping || choice == eAll) { @@ -318,6 +325,8 @@ CBlastOptionsFactory::GetDocumentation(const string& task_name) retval.assign("Map RNA-seq sequences to an mRNA database"); } else if (task == "mapg2g") { retval.assign("Map genomic reads to a genome"); + } else if (task == "kblastp") { + retval.assign("Kmer screenign followed by BLASTP"); } else { retval.assign("Unknown task"); } @@ -465,6 +474,10 @@ CBlastOptionsFactory::CreateTask(string task, EAPILocality locality) retval = opts; } + else if (!NStr::CompareNocase(task, "kblastp")) + { + retval = CBlastOptionsFactory::Create(eKBlastp, locality); + } else { abort(); // should never get here diff --git a/c++/src/algo/blast/api/blast_options_local_priv.cpp b/c++/src/algo/blast/api/blast_options_local_priv.cpp index 1c38b5ce..73d5ce23 100644 --- a/c++/src/algo/blast/api/blast_options_local_priv.cpp +++ b/c++/src/algo/blast/api/blast_options_local_priv.cpp @@ -137,6 +137,7 @@ void CBlastOptionsLocal::x_Copy_CQuerySetUpOptions( SSegOptions* segOptionsNew = NULL; SRepeatFilterOptions* repeatFilterOptionsNew = NULL; SWindowMaskerOptions* windowMaskerOptionsNew = NULL; + SReadQualityOptions* readQualityOptionsNew = NULL; if (queryOptsSrc->filtering_options->dustOptions) { @@ -178,11 +179,18 @@ void CBlastOptionsLocal::x_Copy_CQuerySetUpOptions( windowMaskerOptions->database); } } + if (queryOptsSrc->filtering_options->readQualityOptions) { + readQualityOptionsNew = + (SReadQualityOptions*)BlastMemDup( + queryOptsSrc->filtering_options->readQualityOptions, + sizeof(SReadQualityOptions)); + } blastFilterOptionsNew->dustOptions = dustOptionsNew; blastFilterOptionsNew->segOptions = segOptionsNew; blastFilterOptionsNew->repeatFilterOptions = repeatFilterOptionsNew; blastFilterOptionsNew->windowMaskerOptions = windowMaskerOptionsNew; + blastFilterOptionsNew->readQualityOptions = readQualityOptionsNew; querySetUpOptionsNew->filtering_options = blastFilterOptionsNew; } diff --git a/c++/src/algo/blast/api/blast_options_local_priv.hpp b/c++/src/algo/blast/api/blast_options_local_priv.hpp index 38e2277b..6a52999e 100644 --- a/c++/src/algo/blast/api/blast_options_local_priv.hpp +++ b/c++/src/algo/blast/api/blast_options_local_priv.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_options_local_priv.hpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_options_local_priv.hpp 544251 2017-08-21 14:19:11Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -151,6 +151,15 @@ public: int GetQueryGeneticCode() const; void SetQueryGeneticCode(int gc); + bool GetReadQualityFiltering(void) const; + void SetReadQualityFiltering(bool val = true); + + double GetReadMaxFractionAmbiguous(void) const; + void SetReadMaxFractionAmbiguous(double val); + + int GetReadMinDimerEntropy(void) const; + void SetReadMinDimerEntropy(int val); + /******************* Initial word options ***********************/ int GetWindowSize() const; void SetWindowSize(int w); @@ -216,9 +225,15 @@ public: int GetCutoffScore() const; void SetCutoffScore(int s); + vector GetCutoffScoreCoeffs() const; + void SetCutoffScoreCoeffs(const vector& c); + double GetPercentIdentity() const; void SetPercentIdentity(double p); + int GetMaxEditDistance() const; + void SetMaxEditDistance(int e); + double GetQueryCovHspPerc() const; void SetQueryCovHspPerc(double p); @@ -984,6 +999,73 @@ CBlastOptionsLocal::SetQueryGeneticCode(int gc) m_QueryOpts->genetic_code = gc; } +inline bool +CBlastOptionsLocal::GetReadQualityFiltering(void) const +{ + if (m_QueryOpts->filtering_options->readQualityOptions) { + return true; + } + else { + return false; + } +} + +inline void +CBlastOptionsLocal::SetReadQualityFiltering(bool val /* = true */) +{ + m_QueryOpts->filtering_options->readQualityOptions = + SReadQualityOptionsFree( + m_QueryOpts->filtering_options->readQualityOptions); + + if (val) { + SReadQualityOptionsNew( + &m_QueryOpts->filtering_options->readQualityOptions); + } +} + +inline double +CBlastOptionsLocal::GetReadMaxFractionAmbiguous(void) const +{ + if (m_QueryOpts->filtering_options->readQualityOptions == NULL) { + return -1.0; + } + + return m_QueryOpts->filtering_options->readQualityOptions->frac_ambig; +} + +inline void +CBlastOptionsLocal::SetReadMaxFractionAmbiguous(double val) +{ + if (m_QueryOpts->filtering_options->readQualityOptions == NULL) { + SReadQualityOptionsNew( + &m_QueryOpts->filtering_options->readQualityOptions); + } + + m_QueryOpts->filtering_options->readQualityOptions->frac_ambig = val; +} + +inline int +CBlastOptionsLocal::GetReadMinDimerEntropy(void) const +{ + if (m_QueryOpts->filtering_options->readQualityOptions == NULL) { + return -1; + } + + return m_QueryOpts->filtering_options->readQualityOptions->entropy; +} + +inline void +CBlastOptionsLocal::SetReadMinDimerEntropy(int val) +{ + if (m_QueryOpts->filtering_options->readQualityOptions == NULL) { + SReadQualityOptionsNew( + &m_QueryOpts->filtering_options->readQualityOptions); + } + + m_QueryOpts->filtering_options->readQualityOptions->entropy = val; +} + + /******************* Initial word options ***********************/ inline int CBlastOptionsLocal::GetWindowSize() const @@ -1308,6 +1390,22 @@ CBlastOptionsLocal::SetCutoffScore(int s) m_HitSaveOpts->cutoff_score = s; } +inline vector +CBlastOptionsLocal::GetCutoffScoreCoeffs() const +{ + vector retval(2); + retval[0] = (double)m_HitSaveOpts->cutoff_score_fun[0] / 100.0; + retval[1] = (double)m_HitSaveOpts->cutoff_score_fun[1] / 100.0; + return retval; +} + +inline void +CBlastOptionsLocal::SetCutoffScoreCoeffs(const vector& c) +{ + m_HitSaveOpts->cutoff_score_fun[0] = (int)(c[0] * 100.0); + m_HitSaveOpts->cutoff_score_fun[1] = (int)(c[1] * 100.0); +} + inline double CBlastOptionsLocal::GetPercentIdentity() const { @@ -1320,6 +1418,18 @@ CBlastOptionsLocal::SetPercentIdentity(double p) m_HitSaveOpts->percent_identity = p; } +inline int +CBlastOptionsLocal::GetMaxEditDistance() const +{ + return m_HitSaveOpts->max_edit_distance; +} + +inline void +CBlastOptionsLocal::SetMaxEditDistance(int e) +{ + m_HitSaveOpts->max_edit_distance = e; +} + inline double CBlastOptionsLocal::GetQueryCovHspPerc() const { diff --git a/c++/src/algo/blast/api/blast_results.cpp b/c++/src/algo/blast/api/blast_results.cpp index 3e06e358..d10179f0 100644 --- a/c++/src/algo/blast/api/blast_results.cpp +++ b/c++/src/algo/blast/api/blast_results.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_results.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: blast_results.cpp 542542 2017-08-01 12:44:33Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -147,6 +147,19 @@ CBlastAncillaryData::CBlastAncillaryData(pair lambda, m_SearchSpace = effective_search_space; } +CBlastAncillaryData::CBlastAncillaryData(const CBlastAncillaryData& rhs) +{ + do_copy(rhs); +} + +/// Assignment operator +CBlastAncillaryData& CBlastAncillaryData::operator=(const CBlastAncillaryData& rhs) +{ + do_copy(rhs); + return *this; +} + + CBlastAncillaryData::~CBlastAncillaryData() { Blast_KarlinBlkFree(m_UngappedKarlinBlk); @@ -466,7 +479,7 @@ s_ExtractSeqId(CConstRef align_set) } CSearchResultSet::CSearchResultSet(EResultType res_type /* = eDatabaseSearch*/) -: m_ResultType(res_type) +: m_ResultType(res_type), m_NumQueries(0), m_IsPhiBlast(false) {} CSearchResultSet::CSearchResultSet( diff --git a/c++/src/algo/blast/api/blast_seqalign.cpp b/c++/src/algo/blast/api/blast_seqalign.cpp index ce423ca3..508a22e6 100644 --- a/c++/src/algo/blast/api/blast_seqalign.cpp +++ b/c++/src/algo/blast/api/blast_seqalign.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_seqalign.cpp 520431 2016-11-28 18:26:12Z ivanov $ +/* $Id: blast_seqalign.cpp 532442 2017-04-05 13:47:44Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -400,16 +400,19 @@ void MakeSplicedSeg(CSpliced_seg& spliced_seg, CRef product_id, CRef genomic_id, int product_length, - const BlastHSPChain* chain) + const HSPChain* chain) { spliced_seg.SetProduct_id(*product_id); spliced_seg.SetGenomic_id(*genomic_id); - - _ASSERT(chain->num_hsps > 0); - _ASSERT(chain->hsp_array[0]); - ENa_strand product_strand = s_Frame2Strand(chain->hsp_array[0]->query.frame); + _ASSERT(chain->hsps); + int num_hsps = 0; + for (HSPContainer* h = chain->hsps; h; h = h->next) { + num_hsps++; + } + _ASSERT(num_hsps > 0); + ENa_strand product_strand = s_Frame2Strand(chain->hsps->hsp->query.frame); ENa_strand genomic_strand = s_Frame2Strand( - chain->hsp_array[0]->subject.frame); + chain->hsps->hsp->subject.frame); spliced_seg.SetProduct_type(CSpliced_seg::eProduct_type_transcript); spliced_seg.SetProduct_length(product_length); @@ -417,8 +420,8 @@ void MakeSplicedSeg(CSpliced_seg& spliced_seg, CSpliced_seg::TExons& exons = spliced_seg.SetExons(); const Uint1 kGap = 15; // Gap in BLASTNA - for (int k=0;k < chain->num_hsps;k++) { - BlastHSP* hsp = chain->hsp_array[k]; + for (HSPContainer* h = chain->hsps; h; h = h->next) { + BlastHSP* hsp = h->hsp; _ASSERT(hsp); _ASSERT(hsp->gap_info->size > 1 || diff --git a/c++/src/algo/blast/api/blast_seqalign.hpp b/c++/src/algo/blast/api/blast_seqalign.hpp index efcbf3ca..40a404d9 100644 --- a/c++/src/algo/blast/api/blast_seqalign.hpp +++ b/c++/src/algo/blast/api/blast_seqalign.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_seqalign.hpp 520431 2016-11-28 18:26:12Z ivanov $ +/* $Id: blast_seqalign.hpp 532442 2017-04-05 13:47:44Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -160,7 +160,7 @@ void MakeSplicedSeg(CSpliced_seg& spliced_seg, CRef product_id, CRef genomic_id, int product_length, - const BlastHSPChain* chain); + const HSPChain* chain); END_SCOPE(blast) diff --git a/c++/src/algo/blast/api/blast_seqinfosrc_aux.cpp b/c++/src/algo/blast/api/blast_seqinfosrc_aux.cpp index 941b0999..f6733f20 100644 --- a/c++/src/algo/blast/api/blast_seqinfosrc_aux.cpp +++ b/c++/src/algo/blast/api/blast_seqinfosrc_aux.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_seqinfosrc_aux.cpp 520431 2016-11-28 18:26:12Z ivanov $ +/* $Id: blast_seqinfosrc_aux.cpp 520163 2016-11-23 13:38:30Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/api/blast_setup.hpp b/c++/src/algo/blast/api/blast_setup.hpp index 36d5c503..5808efaf 100644 --- a/c++/src/algo/blast/api/blast_setup.hpp +++ b/c++/src/algo/blast/api/blast_setup.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_setup.hpp 517499 2016-10-25 17:20:41Z ivanov $ +/* $Id: blast_setup.hpp 516747 2016-10-17 19:00:07Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/api/blastp_kmer_options.cpp b/c++/src/algo/blast/api/blastp_kmer_options.cpp new file mode 100644 index 00000000..dd9327a7 --- /dev/null +++ b/c++/src/algo/blast/api/blastp_kmer_options.cpp @@ -0,0 +1,59 @@ +/* $Id: blastp_kmer_options.cpp 535510 2017-05-09 16:22:23Z madden $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Tom Madden + * + */ + +/// @file blastp_kmer_options.cpp +/// Implements the CBlastpKmerOptionsHandle class. + +#include +#include +#include "blast_setup.hpp" + +/** @addtogroup AlgoBlast + * + * @{ + */ + + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(blast) + +CBlastpKmerOptionsHandle::CBlastpKmerOptionsHandle(EAPILocality locality) + : CBlastAdvancedProteinOptionsHandle(locality) +{ + SetThresh(); + SetMinHits(); + SetCandidateSeqs(); + SetDefaults(); +} + +END_SCOPE(blast) +END_NCBI_SCOPE + + +/* @} */ diff --git a/c++/src/algo/blast/api/magicblast.cpp b/c++/src/algo/blast/api/magicblast.cpp index 2836779e..a0c11846 100644 --- a/c++/src/algo/blast/api/magicblast.cpp +++ b/c++/src/algo/blast/api/magicblast.cpp @@ -1,4 +1,4 @@ -/* $Id: magicblast.cpp 505553 2016-06-27 14:10:27Z boratyng $ +/* $Id: magicblast.cpp 548710 2017-10-17 16:02:42Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,7 +33,9 @@ #include #include +#include #include +#include #include #include "blast_seqalign.hpp" @@ -62,11 +64,46 @@ CMagicBlast::CMagicBlast(CRef query_factory, CRef CMagicBlast::Run(void) { - CRef prelim_search(new CBlastPrelimSearch(m_Queries, - m_Options, - m_LocalDbAdapter)); + x_Run(); - int status = prelim_search->CheckInternalData(); + // close HSP stream and create internal results structure + BlastMappingResults* results = Blast_MappingResultsNew(); + CRef< CStructWrapper > wrapped_results; + wrapped_results.Reset(WrapStruct(results, Blast_MappingResultsFree)); + + BlastHSPStreamMappingClose(m_InternalData->m_HspStream->GetPointer(), + results); + + // build and return results + return x_BuildSeqAlignSet(results); +} + + +CRef CMagicBlast::RunEx(void) +{ + x_Run(); + + // close HSP stream and create internal results structure + BlastMappingResults* results = Blast_MappingResultsNew(); + CRef< CStructWrapper > wrapped_results; + wrapped_results.Reset(WrapStruct(results, Blast_MappingResultsFree)); + + BlastHSPStreamMappingClose(m_InternalData->m_HspStream->GetPointer(), + results); + + // build and return results + return x_BuildResultSet(results); +} + + +int CMagicBlast::x_Run(void) +{ + m_PrelimSearch.Reset(new CBlastPrelimSearch(m_Queries, + m_Options, + m_LocalDbAdapter, + GetNumberOfThreads())); + + int status = m_PrelimSearch->CheckInternalData(); if (status != 0) { // Search was not run, but we send back an empty CSearchResultSet. @@ -118,15 +155,15 @@ CRef CMagicBlast::Run(void) ancill_vec.push_back(tmp_ancillary_data); } } - msg_vec.Combine(prelim_search->GetSearchMessages()); + msg_vec.Combine(m_PrelimSearch->GetSearchMessages()); // FIXME: Report search messages } try { - prelim_search->SetNumberOfThreads(GetNumberOfThreads()); + m_PrelimSearch->SetNumberOfThreads(GetNumberOfThreads()); // do mapping - m_InternalData = prelim_search->Run(); + m_InternalData = m_PrelimSearch->Run(); } catch( CIndexedDbException & ) { @@ -141,16 +178,7 @@ CRef CMagicBlast::Run(void) } - // close HSP stream and create internal results structure - BlastMappingResults* results = Blast_MappingResultsNew(); - CRef< CStructWrapper > wrapped_results; - wrapped_results.Reset(WrapStruct(results, Blast_MappingResultsFree)); - - BlastHSPStreamMappingClose(m_InternalData->m_HspStream->GetPointer(), - results); - - // create and return results as ASN.1 objects - return x_CreateSeqAlignSet(results); + return 0; } @@ -172,22 +200,25 @@ void CMagicBlast::x_Validate(void) // Compute BTOP string and percent identity from JumperEdits structure that // contains base mismatch infotmation -static void s_ComputeBtopAndIdentity(const BlastHSPChain* chain, +static void s_ComputeBtopAndIdentity(const HSPChain* chain, string& btop, + string& md_tag, double& perc_id) { _ASSERT(chain); - _ASSERT(chain->hsp_array[0]); + _ASSERT(chain->hsps->hsp); const Uint1 kGap = 15; int num_identical = 0; int len = 0; - for (int k=0;k < chain->num_hsps;k++) { - const BlastHSP* hsp = chain->hsp_array[k]; + int md_matches = 0; + HSPContainer* h = chain->hsps; + BlastHSP* prev = NULL; + for (; h; prev = h->hsp, h = h->next) { + const BlastHSP* hsp = h->hsp; const JumperEditsBlock* hsp_edits = hsp->map_info->edits; - if (k > 0) { - const BlastHSP* prev = chain->hsp_array[k - 1]; + if (prev) { int intron = hsp->subject.offset - prev->subject.end; if (intron > 0) { btop += (string)"^" + NStr::IntToString(intron) + "^"; @@ -228,6 +259,27 @@ static void s_ComputeBtopAndIdentity(const BlastHSPChain* chain, buff[1] = BLASTNA_TO_IUPACNA[(int)hsp_edits->edits[i].subject_base]; buff[2] = 0; btop += (string)buff; + + // assemble SAM MD tag + if (buff[1] != '-') { + if (i > 0 && hsp_edits->edits[i - 1].query_base == kGap && + buff[0] == '-' && num_matches == 0) { + + md_tag += (string)(&buff[1]); + } + else { + md_tag += NStr::IntToString(num_matches + md_matches); + if (buff[0] == '-') { + md_tag += "^"; + } + md_tag += (string)(&buff[1]); + md_matches = 0; + } + } + else { + md_matches += num_matches; + } + len++; if (hsp_edits->edits[i].query_base != kGap) { query_pos++; @@ -237,27 +289,40 @@ static void s_ComputeBtopAndIdentity(const BlastHSPChain* chain, num_identical += num_matches; if (num_matches > 0) { btop += NStr::IntToString(num_matches); + + if (hsp_edits->num_edits > 0) { + md_tag += NStr::IntToString(num_matches + md_matches); + md_matches = 0; + } + else { + md_matches += num_matches; + } } } + if (md_matches > 0) { + md_tag += NStr::IntToString(md_matches); + } len += num_identical; perc_id = (double)(num_identical * 100) / (double)len; } -static CRef s_CreateSeqAlign(const BlastHSPChain* chain, +static CRef s_CreateSeqAlign(const HSPChain* chain, CRef& qdata, - CRef& seqinfo_src) + CRef& seqinfo_src, + const BlastQueryInfo* query_info) { CRef align(new CSeq_align); align->SetType(CSeq_align::eType_partial); align->SetDim(2); - CConstRef query_loc = qdata->GetSeq_loc(chain->query_index); + int query_index = chain->context / NUM_STRANDS; + CConstRef query_loc = qdata->GetSeq_loc(query_index); CRef query_id(new CSeq_id); SerialAssign(*query_id, CSeq_loc_CI(*query_loc).GetSeq_id()); _ASSERT(query_id); - TSeqPos query_length = qdata->GetSeqLength(chain->query_index); + TSeqPos query_length = qdata->GetSeqLength(query_index); CRef subject_id; TSeqPos subj_length; @@ -279,39 +344,41 @@ static CRef s_CreateSeqAlign(const BlastHSPChain* chain, // for SAM // context is needed mostly for printing query sequences, mostly for // convinience and fast lookup - user_object->AddField("context", chain->hsp_array[0]->context); - user_object->AddField("num_hits", chain->multiplicity); + user_object->AddField("context", chain->context); + user_object->AddField("num_hits", chain->count); // for tabular string btop; + string md_tag; double perc_id; - s_ComputeBtopAndIdentity(chain, btop, perc_id); + s_ComputeBtopAndIdentity(chain, btop, md_tag, perc_id); user_object->AddField("btop", btop); + user_object->AddField("md_tag", md_tag); align->SetNamedScore(CSeq_align::eScore_PercentIdentity_Gapped, perc_id); + // to diffierentiate between the first and last segment of a paired read + // if sequence ids cannot be trusted + user_object->AddField("segment", + query_info->contexts[chain->context].segment_flags); + return align; } CRef CMagicBlast::x_CreateSeqAlignSet( - BlastMappingResults* results) + const HSPChain* chains, + CRef qdata, + CRef seqinfo_src, + const BlastQueryInfo* query_info) { CRef seq_aligns = CreateEmptySeq_align_set(); - CRef qdata = m_Queries->MakeLocalQueryData(m_Options); - - CRef seqinfo_src; - seqinfo_src.Reset(m_LocalDbAdapter->MakeSeqInfoSrc()); - _ASSERT(seqinfo_src); - seqinfo_src->GarbageCollect(); - - for (int i=0;i < results->num_results;i++) { - // single spliced alignment - BlastHSPChain* chain = results->chain_array[i]; + // single spliced alignment + for (const HSPChain* chain = chains; chain; chain = chain->next) { - // mate pairs are processed together when the first one is encountered, - // so skip the second of the pair - if (chain->pair && chain->query_index > chain->pair->query_index) { + // mate pairs are processed together when the first one is + // encountered, so skip the second of the pair + if (chain->pair && chain->context > chain->pair->context) { continue; } @@ -325,12 +392,13 @@ CRef CMagicBlast::x_CreateSeqAlignSet( align->SetDim(2); CSeq_align::TSegs::TDisc& disc = align->SetSegs().SetDisc(); - disc.Set().push_back(s_CreateSeqAlign(chain, qdata, seqinfo_src)); + disc.Set().push_back(s_CreateSeqAlign(chain, qdata, seqinfo_src, + query_info)); disc.Set().push_back(s_CreateSeqAlign(chain->pair, qdata, - seqinfo_src)); + seqinfo_src, query_info)); } else { - align = s_CreateSeqAlign(chain, qdata, seqinfo_src); + align = s_CreateSeqAlign(chain, qdata, seqinfo_src, query_info); } seq_aligns->Set().push_back(align); @@ -340,6 +408,214 @@ CRef CMagicBlast::x_CreateSeqAlignSet( } +CRef CMagicBlast::x_BuildSeqAlignSet( + const BlastMappingResults* results) +{ + TSeqAlignVector aligns; + aligns.reserve(results->num_queries); + + CSearchResultSet::TQueryIdVector query_ids; + query_ids.reserve(results->num_queries); + + CRef query_data = m_Queries->MakeLocalQueryData(m_Options); + BlastQueryInfo* query_info = m_InternalData->m_QueryInfo; + CRef seqinfo_src; + seqinfo_src.Reset(m_LocalDbAdapter->MakeSeqInfoSrc()); + _ASSERT(seqinfo_src); + + _ASSERT(results->num_queries == (int)query_data->GetNumQueries()); + + CRef retval(new CSeq_align_set); + for (int index=0;index < results->num_queries;index++) { + HSPChain* chains = results->chain_array[index]; + CRef seq_aligns(x_CreateSeqAlignSet(chains, query_data, + seqinfo_src, + query_info)); + + for (auto it: seq_aligns->Get()) { + retval->Set().push_back(it); + } + } + + return retval; +} + +// paired alignments go first +struct seq_align_pairs_first { + bool operator()(const CRef& a, const CRef& b) { + return a->GetSegs().IsDisc() && !b->GetSegs().IsDisc(); + } +}; + + +CRef CMagicBlast::x_BuildResultSet( + const BlastMappingResults* results) +{ + CRef query_data = m_Queries->MakeLocalQueryData(m_Options); + CRef seqinfo_src; + seqinfo_src.Reset(m_LocalDbAdapter->MakeSeqInfoSrc()); + _ASSERT(seqinfo_src); + + BlastQueryInfo* query_info = m_InternalData->m_QueryInfo; + _ASSERT(results->num_queries == (int)query_data->GetNumQueries()); + + const TSeqLocInfoVector& query_masks = m_PrelimSearch->GetQueryMasks(); + + CRef retval(new CMagicBlastResultSet); + retval->reserve(results->num_queries); + + for (int index=0;index < results->num_queries;index++) { + HSPChain* chains = results->chain_array[index]; + CConstRef query_id(query_data->GetSeq_loc(index)->GetId()); + CRef aligns(x_CreateSeqAlignSet(chains, query_data, + seqinfo_src, + query_info)); + + int query_length = + query_info->contexts[index * NUM_STRANDS].query_length; + CRef res; + + if (query_info->contexts[index * NUM_STRANDS].segment_flags == + eFirstSegment) { + + _ASSERT(query_info->contexts[(index + 1) * NUM_STRANDS] + .segment_flags == eLastSegment); + + CConstRef mate_id( + query_data->GetSeq_loc(index + 1)->GetId()); + + int mate_length = + query_info->contexts[(index + 1) * NUM_STRANDS].query_length; + + chains = results->chain_array[index + 1]; + CRef mate_aligns(x_CreateSeqAlignSet(chains, + query_data, + seqinfo_src, + query_info)); + + for (auto it: mate_aligns->Get()) { + aligns->Set().push_back(it); + } + + // sort results so that pairs go first + aligns->Set().sort(seq_align_pairs_first()); + + res.Reset(new CMagicBlastResults(query_id, mate_id, aligns, + &query_masks[index], + &query_masks[index + 1], + query_length, + mate_length)); + index++; + } + else { + res.Reset(new CMagicBlastResults(query_id, aligns, + &query_masks[index], + query_length)); + } + + retval->push_back(res); + } + + return retval; +} + + +CMagicBlastResults::CMagicBlastResults(CConstRef query_id, + CConstRef mate_id, + CRef aligns, + const TMaskedQueryRegions* query_mask /* = NULL */, + const TMaskedQueryRegions* mate_mask /* = NULL */, + int query_length /* = 0 */, + int mate_length /* = 0 */) + : m_QueryId(query_id), + m_MateId(mate_id), + m_Aligns(aligns), + m_Paired(true) +{ + x_SetInfo(query_length, query_mask, mate_length, mate_mask); +} + + +CMagicBlastResults::CMagicBlastResults(CConstRef query_id, + CRef aligns, + const TMaskedQueryRegions* query_mask /* = NULL */, + int query_length /* = 0 */) + : m_QueryId(query_id), + m_Aligns(aligns), + m_Paired(false) +{ + x_SetInfo(query_length, query_mask); +} + + +void CMagicBlastResults::x_SetInfo(int first_length, + const TMaskedQueryRegions* first_mask, + int last_length /* = 0 */, + const TMaskedQueryRegions* last_mask /* = NULL */) +{ + m_FirstInfo = 0; + m_LastInfo = 0; + + bool first_aligned = false; + bool last_aligned = false; + + if (!m_Paired) { + first_aligned = !m_Aligns->Get().empty(); + } + else { + + for (auto it: m_Aligns->Get()) { + if (it->GetSegs().IsDisc()) { + first_aligned = true; + last_aligned = true; + break; + } + else if (it->GetSeq_id(0).Match(*m_QueryId)) { + first_aligned = true; + } + else if (it->GetSeq_id(0).Match(*m_MateId)) { + last_aligned = true; + } + } + } + + if (!first_aligned) { + m_FirstInfo |= fUnaligned; + } + + if (!last_aligned) { + m_LastInfo |= fUnaligned; + } + + if (first_mask && !first_mask->empty()) { + TSeqRange first_range(*first_mask->front()); + if (first_range.GetLength() + 1 >= (TSeqPos)first_length) { + m_FirstInfo |= fFiltered; + } + } + + if (last_mask && !last_mask->empty()) { + TSeqRange last_range(*last_mask->front()); + if (last_range.GetLength() + 1 >= (TSeqPos)last_length) { + m_LastInfo |= fFiltered; + } + } +} + +CRef CMagicBlastResultSet::GetFlatResults(void) +{ + CRef retval(new CSeq_align_set); + + for (auto result: *this) { + for (auto it: result->GetSeqAlign()->Get()) { + retval->Set().push_back(it); + } + } + + return retval; +} + + END_SCOPE(blast) END_NCBI_SCOPE diff --git a/c++/src/algo/blast/api/magicblast_options.cpp b/c++/src/algo/blast/api/magicblast_options.cpp index dabfb74b..686a49a3 100644 --- a/c++/src/algo/blast/api/magicblast_options.cpp +++ b/c++/src/algo/blast/api/magicblast_options.cpp @@ -1,4 +1,4 @@ -/* $Id: magicblast_options.cpp 506101 2016-07-01 15:47:17Z boratyng $ +/* $Id: magicblast_options.cpp 544251 2017-08-21 14:19:11Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -149,8 +149,12 @@ CMagicBlastOptionsHandle::SetLookupTableDefaults() void CMagicBlastOptionsHandle::SetQueryOptionDefaults() { + SetReadQualityFiltering(true); m_Opts->SetDustFiltering(false); - m_Opts->SetMaskAtHash(false); + // Masking is used for filtering out poor quality reads which are masked + // for the full length. Setting mask at hash to true prevents additional + // memory allocation for unmasked queries. + m_Opts->SetMaskAtHash(true); m_Opts->SetStrandOption(objects::eNa_strand_both); SetLookupDbFilter(true); SetPaired(false); @@ -168,6 +172,9 @@ CMagicBlastOptionsHandle::SetGappedExtensionDefaults() m_Opts->SetMaxMismatches(5); m_Opts->SetMismatchWindow(10); SetSpliceAlignments(true); + // 0 means that the value will be set to max(-penalty, gap open + + // gap extend) + SetGapXDropoff(0); } @@ -197,7 +204,10 @@ CMagicBlastOptionsHandle::SetHitSavingOptionsDefaults() m_Opts->SetMaxNumHspPerSequence(0); m_Opts->SetMaxHspsPerSubject(0); SetCutoffScore(20); - SetLongestIntronLength(2000); + vector coeffs = {0.0, 0.0}; + SetCutoffScoreCoeffs(coeffs); + SetMaxEditDistance(INT4_MAX); + SetLongestIntronLength(500000); // do not compute each query's ungapped alignment score threshold to // trigger gapped alignment diff --git a/c++/src/algo/blast/api/msa_pssm_input.cpp b/c++/src/algo/blast/api/msa_pssm_input.cpp index 6887ab45..c3972d10 100644 --- a/c++/src/algo/blast/api/msa_pssm_input.cpp +++ b/c++/src/algo/blast/api/msa_pssm_input.cpp @@ -388,10 +388,10 @@ CPsiBlastInputClustalW::x_ExtractAlignmentData() } // find right flanking gaps - i = m_Msa->dimensions->query_length - 1; - while (i >= 0 && m_Msa->data[seq_index][i].letter == kGapResidue) { - m_Msa->data[seq_index][i].is_aligned = false; - i--; + int k = m_Msa->dimensions->query_length - 1; + while (k >= 0 && m_Msa->data[seq_index][k].letter == kGapResidue) { + m_Msa->data[seq_index][k].is_aligned = false; + k--; } } } diff --git a/c++/src/algo/blast/api/prelim_search_runner.hpp b/c++/src/algo/blast/api/prelim_search_runner.hpp index 98326448..8208a90b 100644 --- a/c++/src/algo/blast/api/prelim_search_runner.hpp +++ b/c++/src/algo/blast/api/prelim_search_runner.hpp @@ -1,4 +1,4 @@ -/* $Id: prelim_search_runner.hpp 516335 2016-10-12 17:31:18Z ivanov $ +/* $Id: prelim_search_runner.hpp 514950 2016-09-27 14:52:47Z rackerst $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/api/prelim_stage.cpp b/c++/src/algo/blast/api/prelim_stage.cpp index a357550d..d0e1a303 100644 --- a/c++/src/algo/blast/api/prelim_stage.cpp +++ b/c++/src/algo/blast/api/prelim_stage.cpp @@ -73,13 +73,18 @@ CBlastPrelimSearch::CBlastPrelimSearch(CRef query_factory, CBlastPrelimSearch::CBlastPrelimSearch(CRef query_factory, CRef options, - CRef db) + CRef db, + size_t num_threads) : m_QueryFactory(query_factory), m_InternalData(new SInternalData), m_Options(options), m_DbAdapter(db), m_DbInfo(NULL) { BlastSeqSrc* seqsrc = db->MakeSeqSrc(); - x_Init(query_factory, options, CRef(), seqsrc); + x_Init(query_factory, options, CRef(), seqsrc, + num_threads); m_InternalData->m_SeqSrc.Reset(new TBlastSeqSrc(seqsrc, 0)); + if (num_threads > 1) { + SetNumberOfThreads(num_threads); + } } CBlastPrelimSearch::CBlastPrelimSearch(CRef query_factory, @@ -120,11 +125,12 @@ void CBlastPrelimSearch::x_Init(CRef query_factory, CRef options, CConstRef pssm, - BlastSeqSrc* seqsrc ) + BlastSeqSrc* seqsrc, + size_t num_threads) { CRef setup_data = BlastSetupPreliminarySearchEx(query_factory, options, pssm, seqsrc, - IsMultiThreaded()); + num_threads); m_InternalData = setup_data->m_InternalData; copy(setup_data->m_Masks.begin(), setup_data->m_Masks.end(), back_inserter(m_MasksForAllQueries)); @@ -228,7 +234,7 @@ CBlastPrelimSearch::Run() CRef chunk_data = SplitQuery_CreateChunkData(chunk_qf, m_Options, m_InternalData, - IsMultiThreaded()); + GetNumberOfThreads()); CRef query_data( chunk_qf->MakeLocalQueryData( &*m_Options ) ); diff --git a/c++/src/algo/blast/api/remote_blast.cpp b/c++/src/algo/blast/api/remote_blast.cpp index a2bc58c6..e18a3856 100644 --- a/c++/src/algo/blast/api/remote_blast.cpp +++ b/c++/src/algo/blast/api/remote_blast.cpp @@ -1,4 +1,4 @@ -/* $Id: remote_blast.cpp 505424 2016-06-24 16:19:35Z merezhuk $ +/* $Id: remote_blast.cpp 542542 2017-08-01 12:44:33Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1626,7 +1626,7 @@ void CRemoteBlast::SetVerbose(EDebugMode verb) } /// The default timeout is 3.5 hours. -const int CRemoteBlast::x_DefaultTimeout(void) +int CRemoteBlast::x_DefaultTimeout(void) { return int(3600*3.5); } diff --git a/c++/src/algo/blast/api/seedtop.cpp b/c++/src/algo/blast/api/seedtop.cpp index cec7ec2c..b42a916d 100644 --- a/c++/src/algo/blast/api/seedtop.cpp +++ b/c++/src/algo/blast/api/seedtop.cpp @@ -1,4 +1,4 @@ -/* $Id: seedtop.cpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: seedtop.cpp 535495 2017-05-09 14:42:25Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -63,7 +63,7 @@ void CSeedTop::x_ParsePattern() { vector units; NStr::TruncateSpacesInPlace(m_Pattern); - NStr::Tokenize(NStr::ToUpper(m_Pattern), "-", units); + NStr::Split(NStr::ToUpper(m_Pattern), "-", units, 0); ITERATE(vector, unit, units){ if (*unit != "") { char ch = (*unit)[0]; diff --git a/c++/src/algo/blast/api/seqinfosrc_seqdb.cpp b/c++/src/algo/blast/api/seqinfosrc_seqdb.cpp index a2203814..388bd585 100644 --- a/c++/src/algo/blast/api/seqinfosrc_seqdb.cpp +++ b/c++/src/algo/blast/api/seqinfosrc_seqdb.cpp @@ -138,11 +138,6 @@ bool CSeqDbSeqInfoSrc::GetMasks(Uint4 index, return (retval.empty() ? false : true); } -void CSeqDbSeqInfoSrc::GarbageCollect() -{ - m_iSeqDb->GarbageCollect(); -} - END_SCOPE(blast) END_NCBI_SCOPE diff --git a/c++/src/algo/blast/api/seqsrc_seqdb.cpp b/c++/src/algo/blast/api/seqsrc_seqdb.cpp index e4b0a9a9..4e712ed8 100644 --- a/c++/src/algo/blast/api/seqsrc_seqdb.cpp +++ b/c++/src/algo/blast/api/seqsrc_seqdb.cpp @@ -1,4 +1,4 @@ -/* $Id: seqsrc_seqdb.cpp 510159 2016-08-11 11:28:47Z ivanov $ +/* $Id: seqsrc_seqdb.cpp 509955 2016-08-09 20:20:20Z rackerst $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/api/setup_factory.cpp b/c++/src/algo/blast/api/setup_factory.cpp index 80338d8a..8eaa8d67 100644 --- a/c++/src/algo/blast/api/setup_factory.cpp +++ b/c++/src/algo/blast/api/setup_factory.cpp @@ -202,7 +202,8 @@ CSetupFactory::CreateLookupTable(CRef query_data, BlastScoreBlk* score_blk, CRef< CBlastSeqLocWrap > lookup_segments_wrap, const CBlastRPSInfo* rps_info, - BlastSeqSrc* seqsrc) + BlastSeqSrc* seqsrc, + size_t num_threads) { BLAST_SequenceBlk* queries = query_data->GetSequenceBlk(); CBlast_Message blast_msg; @@ -210,15 +211,16 @@ CSetupFactory::CreateLookupTable(CRef query_data, BlastSeqLoc * lookup_segments = lookup_segments_wrap->getLocs(); - Int2 status = LookupTableWrapInit(queries, - opts_memento->m_LutOpts, - opts_memento->m_QueryOpts, - lookup_segments, - score_blk, - &retval, - rps_info ? (*rps_info)() : 0, - &blast_msg, - seqsrc); + Int2 status = LookupTableWrapInit_MT(queries, + opts_memento->m_LutOpts, + opts_memento->m_QueryOpts, + lookup_segments, + score_blk, + &retval, + rps_info ? (*rps_info)() : 0, + &blast_msg, + seqsrc, + num_threads); if (status != 0) { TSearchMessages search_messages; Blast_Message2TSearchMessages(blast_msg.Get(), diff --git a/c++/src/algo/blast/api/split_query_aux_priv.cpp b/c++/src/algo/blast/api/split_query_aux_priv.cpp index e8bbfa60..330fc97f 100644 --- a/c++/src/algo/blast/api/split_query_aux_priv.cpp +++ b/c++/src/algo/blast/api/split_query_aux_priv.cpp @@ -185,7 +185,7 @@ CRef SplitQuery_CreateChunkData(CRef qf, CRef options, CRef full_data, - bool is_multi_threaded /* = false */) + size_t num_threads /*=1 No Thread*/) { BlastSeqSrc* seqsrc = BlastSeqSrcCopy(full_data->m_SeqSrc->GetPointer()); @@ -193,7 +193,7 @@ SplitQuery_CreateChunkData(CRef qf, BlastSetupPreliminarySearchEx( qf, options, CRef(), - seqsrc, is_multi_threaded); + seqsrc, num_threads); BlastSeqSrcResetChunkIterator(seqsrc); setup_data->m_InternalData->m_SeqSrc.Reset(new TBlastSeqSrc(seqsrc, BlastSeqSrcFree)); diff --git a/c++/src/algo/blast/api/split_query_aux_priv.hpp b/c++/src/algo/blast/api/split_query_aux_priv.hpp index e3733233..3a9a8d89 100644 --- a/c++/src/algo/blast/api/split_query_aux_priv.hpp +++ b/c++/src/algo/blast/api/split_query_aux_priv.hpp @@ -1,4 +1,4 @@ -/* $Id: split_query_aux_priv.hpp 388133 2013-02-05 19:47:18Z maning $ +/* $Id: split_query_aux_priv.hpp 530949 2017-03-20 13:42:25Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -88,7 +88,7 @@ CRef SplitQuery_CreateChunkData(CRef qf, CRef options, CRef full_data, - bool is_multi_threaded = false); + size_t num_threaded =1); /// this might supercede the function below... void diff --git a/c++/src/algo/blast/api/traceback_stage.cpp b/c++/src/algo/blast/api/traceback_stage.cpp index 5032a037..ea83cdcb 100644 --- a/c++/src/algo/blast/api/traceback_stage.cpp +++ b/c++/src/algo/blast/api/traceback_stage.cpp @@ -263,7 +263,6 @@ CBlastTracebackSearch::Run() CRef qdata = m_QueryFactory->MakeLocalQueryData(m_Options); - m_SeqInfoSrc->GarbageCollect(); vector subj_masks; TSeqAlignVector aligns = LocalBlastResults2SeqAlign(hsp_results, diff --git a/c++/src/algo/blast/api/uniform_search.cpp b/c++/src/algo/blast/api/uniform_search.cpp index c1edc5ee..e4437e1e 100644 --- a/c++/src/algo/blast/api/uniform_search.cpp +++ b/c++/src/algo/blast/api/uniform_search.cpp @@ -251,12 +251,27 @@ CSearchDatabase::x_InitializeDb() const m_SeqDb.Reset(new CSeqDB(m_DbName, seq_type, m_GiList)); } else if (! m_NegativeGiList.Empty() && ! m_NegativeGiList->Empty()) { - vector gis; - m_NegativeGiList->GetGiList(gis); - CSeqDBIdSet idset(gis, CSeqDBIdSet::eGi, false); - m_SeqDb.Reset(new CSeqDB(m_DbName, seq_type, idset)); + + if(m_NegativeGiList->GetNumGis() > 0) { + vector gis; + m_NegativeGiList->GetGiList(gis); + CSeqDBIdSet idset(gis, CSeqDBIdSet::eGi, false); + m_SeqDb.Reset(new CSeqDB(m_DbName, seq_type, idset)); + } + else { + vector sis; + m_NegativeGiList->GetSiList(sis); + + CRef seqIds(new CSeqDBNegativeList); + seqIds->ReserveSis(sis.size()); + ITERATE(vector, iter, sis) { + seqIds->AddSi(*iter); + } + m_SeqDb.Reset(new CSeqDB(m_DbName, seq_type, seqIds)); + } - } else { + } + else { m_SeqDb.Reset(new CSeqDB(m_DbName, seq_type)); } diff --git a/c++/src/algo/blast/blastinput/CMakeLists.blastinput.lib.txt b/c++/src/algo/blast/blastinput/CMakeLists.blastinput.lib.txt new file mode 100644 index 00000000..78cca6fd --- /dev/null +++ b/c++/src/algo/blast/blastinput/CMakeLists.blastinput.lib.txt @@ -0,0 +1,18 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/blastinput/Makefile.blastinput.lib +# +add_library(blastinput + blast_input blast_fasta_input blast_scope_src blast_args cmdline_flags + blast_input_aux blastp_args blastn_args rmblastn_args blastx_args + tblastn_args tblastx_args psiblast_args rpsblast_args rpstblastn_args + igblastn_args igblastp_args deltablast_args magicblast_args kblastp_args + blast_asn1_input +) + +add_dependencies(blastinput + seqset xnetblast +) + +target_link_libraries(blastinput + align_format ncbi_xloader_blastdb_rmt xblast +) diff --git a/c++/src/algo/blast/blastinput/CMakeLists.txt b/c++/src/algo/blast/blastinput/CMakeLists.txt new file mode 100644 index 00000000..c91442c2 --- /dev/null +++ b/c++/src/algo/blast/blastinput/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.blastinput.lib.txt) + +# Recurse subdirectories +add_subdirectory(unit_test ) +add_subdirectory(demo ) diff --git a/c++/src/algo/blast/blastinput/Makefile.blastinput.lib b/c++/src/algo/blast/blastinput/Makefile.blastinput.lib index 4008d136..ed62be0d 100644 --- a/c++/src/algo/blast/blastinput/Makefile.blastinput.lib +++ b/c++/src/algo/blast/blastinput/Makefile.blastinput.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.blastinput.lib 514850 2016-09-26 17:23:32Z ivanov $ +# $Id: Makefile.blastinput.lib 513798 2016-09-15 14:53:16Z madden $ SRC_CXX = \ blast_input \ diff --git a/c++/src/algo/blast/blastinput/blast_args.cpp b/c++/src/algo/blast/blastinput/blast_args.cpp index 948c9221..68fd7742 100644 --- a/c++/src/algo/blast/blastinput/blast_args.cpp +++ b/c++/src/algo/blast/blastinput/blast_args.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_args.cpp 516396 2016-10-13 12:26:43Z ivanov $ +/* $Id: blast_args.cpp 546749 2017-09-21 11:22:02Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -36,6 +36,7 @@ Author: Jason Papadopoulos * arguments into blast options */ #include +#include #include #include #include @@ -1375,10 +1376,8 @@ CKBlastpArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) CArgDescriptions::eDouble, kDfltArgJDistance); arg_desc.AddDefaultKey(kArgMinHits, "minhits", "minimal number of LSH matches", CArgDescriptions::eInteger, kDfltArgMinHits); - arg_desc.AddDefaultKey(kArgKIndex, "dbk", "index of kmers", - CArgDescriptions::eString, kDfltArgKIndex); - arg_desc.AddDefaultKey(kArgTargetSeqs, "targetseqs", "Number of target sequences to process with BLAST", - CArgDescriptions::eInteger, kDfltArgTargetSeqs); + arg_desc.AddDefaultKey(kArgCandidateSeqs, "candidates", "Number of candidate sequences to process with BLAST", + CArgDescriptions::eInteger, kDfltArgCandidateSeqs); } void @@ -1389,10 +1388,8 @@ CKBlastpArgs::ExtractAlgorithmOptions(const CArgs& args, m_JDistance = args[kArgJDistance].AsDouble(); if (args.Exist(kArgMinHits)) m_MinHits = args[kArgMinHits].AsInteger(); - if (args.Exist(kArgKIndex)) - m_DbIndex = args[kArgKIndex].AsString(); - if (args.Exist(kArgTargetSeqs)) - m_TargetSeqs = args[kArgTargetSeqs].AsInteger(); + if (args.Exist(kArgCandidateSeqs)) + m_CandidateSeqs = args[kArgCandidateSeqs].AsInteger(); } @@ -1429,11 +1426,16 @@ CMappingArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) { arg_desc.SetCurrentGroup("Mapping options"); - arg_desc.AddOptionalKey(kArgScore, "num", "Cutoff score for accepting a " - "single non-spliced alignment", + arg_desc.AddDefaultKey(kArgScore, "num", "Cutoff score for accepting " + "alignments. Can be expressed as a number or a " + "function of read length: " + "L,b,a for a * length + b.", + CArgDescriptions::eString, "20"); + arg_desc.AddOptionalKey(kArgMaxEditDist, "num", "Cutoff edit distance for " + "accepting an alignment\nDefault = unlimited", CArgDescriptions::eInteger); - arg_desc.AddOptionalKey(kArgSplice, "TF", "Search for spliced alignments", - CArgDescriptions::eBoolean); + arg_desc.AddDefaultKey(kArgSplice, "TF", "Search for spliced alignments", + CArgDescriptions::eBoolean, "true"); arg_desc.AddDefaultKey(kArgRefType, "type", "Type of the reference: " "genome or transcriptome", CArgDescriptions::eString, "genome"); @@ -1441,9 +1443,9 @@ CMappingArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) &(*new CArgAllow_Strings, "genome", "transcriptome")); arg_desc.SetCurrentGroup("Query filtering options"); - arg_desc.AddOptionalKey(kArgLimitLookup, "TF", "Remove word seeds with " - "high frequency in the searched database", - CArgDescriptions::eBoolean); + arg_desc.AddDefaultKey(kArgLimitLookup, "TF", "Remove word seeds with " + "high frequency in the searched database", + CArgDescriptions::eBoolean, "true"); arg_desc.AddDefaultKey(kArgLookupStride, "num", "Number of words to skip " "after collecting one while creating a lookup table", CArgDescriptions::eInteger, "0"); @@ -1457,7 +1459,52 @@ CMappingArgs::ExtractAlgorithmOptions(const CArgs& args, CBlastOptions& opt) { if (args.Exist(kArgScore) && args[kArgScore]) { - opt.SetCutoffScore(args[kArgScore].AsInteger()); + + string s = args[kArgScore].AsString(); + // score cutoff may be defined as a liner function of query length: + // L,0.0,0.6 ... + if (s[0] == 'L') { + list tokens; + NStr::Split(s, ",", tokens); + vector coeffs; + if (tokens.size() < 3) { + NCBI_THROW(CInputException, eInvalidInput, + (string)"Incorrectly formatted score function: " + + s + ". It should be of the form 'L,b,a' for ax + b," + "a, b must be numbers"); + } + auto it = tokens.begin(); + ++it; + try { + for (; it != tokens.end(); ++it) { + coeffs.push_back(NStr::StringToDouble(*it)); + } + } + catch (CException& e) { + NCBI_THROW(CInputException, eInvalidInput, + (string)"Incorrectly formatted score function: " + + s + ". It should be of the form 'L,b,a' for ax + b," + " a, b must be real numbers"); + } + opt.SetCutoffScoreCoeffs(coeffs); + } + else { + // ... or a numerical constant + try { + opt.SetCutoffScore(NStr::StringToInt(s)); + } + catch (CException& e) { + NCBI_THROW(CInputException, eInvalidInput, + (string)"Incorrectly formatted score threshold: " + + s + ". It must be either an integer or a linear " + "function in the form: L,b,a for ax + b, a and b " + "must be real numbers"); + } + } + } + + if (args.Exist(kArgMaxEditDist) && args[kArgMaxEditDist]) { + opt.SetMaxEditDistance(args[kArgMaxEditDist].AsInteger()); } if (args.Exist(kArgSplice) && args[kArgSplice]) { @@ -1490,6 +1537,7 @@ CIgBlastArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) const static int df_num_align[3] = {3,3,3}; int num_genes = (m_IsProtein) ? 1 : 3; + for (int gene=0; genem_DomainSystem = args[kArgGLDomainSystem].AsString(); m_IgOptions->m_FocusV = args.Exist(kArgGLFocusV) ? args[kArgGLFocusV] : false; m_IgOptions->m_ExtendAlign = args.Exist(kArgExtendAlign) ? args[kArgExtendAlign] : false; + m_IgOptions->m_DetectOverlap = args.Exist(kArgDetectOverlap) ? args[kArgDetectOverlap] : false; m_IgOptions->m_MinVLength = args[kArgMinVLength].AsInteger(); - m_IgOptions->m_MinJLength = args[kArgMinJLength].AsInteger(); - + if (args.Exist(kArgMinJLength) && args[kArgMinJLength]) { + m_IgOptions->m_MinJLength = args[kArgMinJLength].AsInteger(); + } else { + m_IgOptions->m_MinJLength = 0; + } m_IgOptions->m_Translate = args.Exist(kArgTranslate) ? args[kArgTranslate] : false; if (!m_IsProtein) { string aux_file = (args.Exist(kArgGLChainType) && args[kArgGLChainType]) @@ -1697,7 +1760,10 @@ CIgBlastArgs::ExtractAlgorithmOptions(const CArgs& args, if (args.Exist(kArgDPenalty) && args[kArgDPenalty]) { m_IgOptions->m_D_penalty = args[kArgDPenalty].AsInteger(); } - + + if (args.Exist(kArgJPenalty) && args[kArgJPenalty]) { + m_IgOptions->m_J_penalty = args[kArgJPenalty].AsInteger(); + } CRef opts_hndl; if (m_IgOptions->m_IsProtein) { @@ -1868,6 +1934,11 @@ CMapperQueryOptionsArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) "subject defline(s) be parsed?", CArgDescriptions::eBoolean, "true"); + arg_desc.AddFlag(kArgEnableSraCache, "Enable SRA caching in local files"); + arg_desc.SetDependency(kArgEnableSraCache, CArgDescriptions::eRequires, + kArgSraAccession); + + arg_desc.SetCurrentGroup(""); } @@ -1912,7 +1983,7 @@ CMapperQueryOptionsArgs::ExtractAlgorithmOptions(const CArgs& args, } if (args.Exist(kArgQualityFilter) && args[kArgQualityFilter]) { - m_QualityFilter = args[kArgQualityFilter].AsBoolean(); + opt.SetReadQualityFiltering(args[kArgQualityFilter].AsBoolean()); } if (args.Exist(kArgQueryMate) && args[kArgQueryMate]) { @@ -1944,6 +2015,10 @@ CMapperQueryOptionsArgs::ExtractAlgorithmOptions(const CArgs& args, opt.SetPaired(true); m_IsPaired = true; } + + if (args.Exist(kArgEnableSraCache) && args[kArgEnableSraCache]) { + m_EnableSraCache = true; + } } @@ -1951,12 +2026,14 @@ CMapperQueryOptionsArgs::ExtractAlgorithmOptions(const CArgs& args, CBlastDatabaseArgs::CBlastDatabaseArgs(bool request_mol_type /* = false */, bool is_rpsblast /* = false */, bool is_igblast /* = false */, - bool is_mapper /* = false */) + bool is_mapper /* = false */, + bool is_kblast /* = false */) : m_RequestMoleculeType(request_mol_type), m_IsRpsBlast(is_rpsblast), m_IsIgBlast(is_igblast), m_IsProtein(true), m_IsMapper(is_mapper), + m_IsKBlast(is_kblast), m_SupportsDatabaseMasking(false) {} @@ -1992,6 +2069,7 @@ CBlastDatabaseArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) database_args.push_back(kArgGiList); database_args.push_back(kArgSeqIdList); database_args.push_back(kArgNegativeGiList); + database_args.push_back(kArgNegativeSeqidList); if (m_SupportsDatabaseMasking) { database_args.push_back(kArgDbSoftMask); database_args.push_back(kArgDbHardMask); @@ -2020,13 +2098,26 @@ CBlastDatabaseArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) "Restrict search of database to everything" " except the listed GIs", CArgDescriptions::eString); + + // Negative SeqId list + arg_desc.AddOptionalKey(kArgNegativeSeqidList, "filename", + "Restrict search of database to everything" + " except the listed SeqIDs", + CArgDescriptions::eString); + arg_desc.SetDependency(kArgGiList, CArgDescriptions::eExcludes, kArgNegativeGiList); arg_desc.SetDependency(kArgGiList, CArgDescriptions::eExcludes, kArgSeqIdList); + arg_desc.SetDependency(kArgGiList, CArgDescriptions::eExcludes, + kArgNegativeSeqidList); + arg_desc.SetDependency(kArgSeqIdList, CArgDescriptions::eExcludes, kArgNegativeGiList); + arg_desc.SetDependency(kArgSeqIdList, CArgDescriptions::eExcludes, + kArgNegativeSeqidList); + // For now, disable pairing -remote with either -gilist or // -negative_gilist as this is not implemented in the BLAST server arg_desc.SetDependency(kArgGiList, CArgDescriptions::eExcludes, @@ -2035,6 +2126,8 @@ CBlastDatabaseArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) kArgRemote); arg_desc.SetDependency(kArgNegativeGiList, CArgDescriptions::eExcludes, kArgRemote); + arg_desc.SetDependency(kArgNegativeSeqidList, CArgDescriptions::eExcludes, + kArgRemote); } // Entrez Query @@ -2070,7 +2163,7 @@ CBlastDatabaseArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) #endif // There is no RPS-BLAST 2 sequences - if ( !m_IsRpsBlast ) { + if ( !m_IsRpsBlast && !m_IsKBlast) { arg_desc.SetCurrentGroup("BLAST-2-Sequences options"); // subject sequence input (for bl2seq) arg_desc.AddOptionalKey(kArgSubject, "subject_input_file", @@ -2126,7 +2219,11 @@ CBlastDatabaseArgs::ExtractAlgorithmOptions(const CArgs& args, string fn(SeqDB_ResolveDbPath(args[kArgSeqIdList].AsString())); m_SearchDb->SetGiList(CRef (new CSeqDBFileGiList(fn, CSeqDBFileGiList::eMixList))); - } + } else if (args.Exist(kArgNegativeSeqidList) && args[kArgNegativeSeqidList]) { + string fn(SeqDB_ResolveDbPath(args[kArgNegativeSeqidList].AsString())); + m_SearchDb->SetNegativeGiList(CRef (new CSeqDBFileGiList(fn,CSeqDBFileGiList::eMixList))); + } + if (args.Exist(kArgEntrezQuery) && args[kArgEntrezQuery]) m_SearchDb->SetEntrezQueryLimitation(args[kArgEntrezQuery].AsString()); @@ -2461,54 +2558,95 @@ CFormattingArgs::ExtractAlgorithmOptions(const CArgs& args, return; } + void -CMTArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) +CMapperFormattingArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) +{ + arg_desc.SetCurrentGroup("Formatting options"); + string kOutputFormatDescription = string( + "alignment view options:\n" + "sam = SAM format,\n" + "tabular = Tabular format,\n" + "asn = text ASN.1\n"); + arg_desc.AddDefaultKey(align_format::kArgOutputFormat, "format", + kOutputFormatDescription, + CArgDescriptions::eString, + "sam"); -{ - if(m_IsRpsBlast) - { - x_SetArgumentDescriptionsRpsBlast(arg_desc); - return; - } + set allowed_formats = {"sam", "tabular", "asn"}; + arg_desc.SetConstraint(align_format::kArgOutputFormat, + new CArgAllowStringSet(allowed_formats)); + arg_desc.AddFlag(kArgNoReadIdTrim, "Do not trim '.1', '/1', '.2', " \ + "or '/2' at the end of read ids for SAM format and" \ + "paired runs"); + + arg_desc.AddFlag(kArgNoUnaligned, "Do report unaligned reads"); - // number of threads - arg_desc.SetCurrentGroup("Miscellaneous options"); -#ifdef NCBI_THREADS - const int kMinValue = static_cast(CThreadable::kMinNumThreads); - arg_desc.AddDefaultKey(kArgNumThreads, "int_value", - "Number of threads (CPUs) to use in the BLAST search", - CArgDescriptions::eInteger, - NStr::IntToString(kMinValue)); - arg_desc.SetConstraint(kArgNumThreads, - new CArgAllowValuesGreaterThanOrEqual(kMinValue)); - arg_desc.SetDependency(kArgNumThreads, - CArgDescriptions::eExcludes, - kArgRemote); - /* - arg_desc.SetDependency(kArgNumThreads, - CArgDescriptions::eExcludes, - kArgUseIndex); - */ -#endif arg_desc.SetCurrentGroup(""); } +void CMapperFormattingArgs::ExtractAlgorithmOptions(const CArgs& args, + CBlastOptions& opt) +{ + if (args.Exist(align_format::kArgOutputFormat)) { + string fmt_choice = args[align_format::kArgOutputFormat].AsString(); + if (fmt_choice == "sam") { + m_OutputFormat = eSAM; + } + else if (fmt_choice == "tabular") { + m_OutputFormat = eTabular; + } + else if (fmt_choice == "asn") { + m_OutputFormat = eAsnText; + } + else { + CNcbiOstrstream os; + os << "'" << fmt_choice << "' is not a valid output format"; + string msg = CNcbiOstrstreamToString(os); + NCBI_THROW(CInputException, eInvalidInput, msg); + } + } + + m_ShowGis = true; + m_Html = false; + + if (args.Exist(kArgNoReadIdTrim) && args[kArgNoReadIdTrim]) { + m_TrimReadIds = false; + } + + if (args.Exist(kArgNoUnaligned) && args[kArgNoUnaligned]) { + m_PrintUnaligned = false; + } + + // only the fast tabular format is able to show merged HSPs with + // common query bases + if (m_OutputFormat != eTabular) { + // FIXME: This is a hack. Merging should be done by the formatter, + // but is currently done by HSP stream writer. This is an easy + // switch until merging is implemented properly. + CNcbiEnvironment().Set("MAPPER_NO_OVERLAPPED_HSP_MERGE", "1"); + } +} + void -CMTArgs::x_SetArgumentDescriptionsRpsBlast(CArgDescriptions& arg_desc) +CMTArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) { // number of threads arg_desc.SetCurrentGroup("Miscellaneous options"); #ifdef NCBI_THREADS + const int kMinValue = static_cast(CThreadable::kMinNumThreads); + const int kMaxValue = static_cast(GetCpuCount()); + const int kDfltValue = m_NumThreads != CThreadable::kMinNumThreads + ? std::min(m_NumThreads, kMaxValue) : kMinValue; + arg_desc.AddDefaultKey(kArgNumThreads, "int_value", - "Number of threads to use in RPS BLAST search:\n " - "0 (auto = num of databases)\n " - "1 (disable)\n max number of threads = num of databases", - CArgDescriptions::eInteger, - NStr::IntToString(kDefaultRpsNumThreads)); - arg_desc.SetConstraint(kArgNumThreads, - new CArgAllowValuesGreaterThanOrEqual(0)); + "Number of threads (CPUs) to use in the BLAST search", + CArgDescriptions::eInteger, + NStr::IntToString(kDfltValue)); + arg_desc.SetConstraint(kArgNumThreads, + new CArgAllowValuesBetween(kMinValue, kMaxValue, true)); arg_desc.SetDependency(kArgNumThreads, CArgDescriptions::eExcludes, kArgRemote); @@ -2524,11 +2662,6 @@ CMTArgs::x_SetArgumentDescriptionsRpsBlast(CArgDescriptions& arg_desc) void CMTArgs::ExtractAlgorithmOptions(const CArgs& args, CBlastOptions& /* opts */) { - if(m_IsRpsBlast) - { - x_ExtractAlgorithmOptionsRpsBlast(args); - return; - } if (args.Exist(kArgNumThreads) && args[kArgNumThreads].HasValue()) { // could be cancelled by the exclusion in CRemoteArgs m_NumThreads = args[kArgNumThreads].AsInteger(); @@ -2543,16 +2676,6 @@ CMTArgs::ExtractAlgorithmOptions(const CArgs& args, CBlastOptions& /* opts */) } } -void -CMTArgs::x_ExtractAlgorithmOptionsRpsBlast(const CArgs& args) -{ - if (args.Exist(kArgNumThreads) && - args[kArgNumThreads].HasValue()) - { - m_NumThreads = args[kArgNumThreads].AsInteger(); - } -} - void CRemoteArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) { @@ -2733,7 +2856,16 @@ CStdCmdLineArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) arg_desc.AddDefaultKey(kArgQuery, "input_file", "Input file name", CArgDescriptions::eInputFile, kDfltArgQuery); - + // for now it's either -query or -sra + if( m_SRAaccessionEnabled ) { + arg_desc.AddOptionalKey(kArgSraAccession, "accession", + "Comma-separated SRA accessions", + CArgDescriptions::eString); + arg_desc.SetDependency(kArgSraAccession, + CArgDescriptions::eExcludes, + kArgQuery); + } + arg_desc.SetCurrentGroup("General search options"); // report output file diff --git a/c++/src/algo/blast/blastinput/blast_asn1_input.cpp b/c++/src/algo/blast/blastinput/blast_asn1_input.cpp index db1dfcea..b216bcba 100644 --- a/c++/src/algo/blast/blastinput/blast_asn1_input.cpp +++ b/c++/src/algo/blast/blastinput/blast_asn1_input.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_asn1_input.cpp 517499 2016-10-25 17:20:41Z ivanov $ +/* $Id: blast_asn1_input.cpp 539881 2017-06-28 14:57:30Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -48,42 +48,28 @@ USING_SCOPE(objects); CASN1InputSourceOMF::CASN1InputSourceOMF(CNcbiIstream& infile, - TSeqPos num_seqs, bool is_bin, - bool is_paired, - bool validate) - : m_NumSeqsInBatch(num_seqs), - m_InputStream(&infile), + bool is_paired) + : m_InputStream(&infile), m_SecondInputStream(NULL), m_IsPaired(is_paired), - m_Validate(validate), m_IsBinary(is_bin) {} CASN1InputSourceOMF::CASN1InputSourceOMF(CNcbiIstream& infile1, CNcbiIstream& infile2, - TSeqPos num_seqs, - bool is_bin, - bool validate) - : m_NumSeqsInBatch(num_seqs), - m_InputStream(&infile1), + bool is_bin) + : m_InputStream(&infile1), m_SecondInputStream(&infile2), m_IsPaired(true), - m_Validate(validate), m_IsBinary(is_bin) {} -void -CASN1InputSourceOMF::GetNextNumSequences(CBioseq_set& bioseq_set, - TSeqPos /* num_seqs */) +int +CASN1InputSourceOMF::GetNextSequence(CBioseq_set& bioseq_set) { - // preallocate memory for sequences to be read - m_Entries.clear(); - - // +1 in case we need to read one more sequence so that a pair is not - // broken - m_Entries.resize(m_NumSeqsInBatch + 1); + m_BasesAdded = 0; if (m_SecondInputStream) { x_ReadFromTwoFiles(bioseq_set); @@ -92,17 +78,16 @@ CASN1InputSourceOMF::GetNextNumSequences(CBioseq_set& bioseq_set, x_ReadFromSingleFile(bioseq_set); } - // detach CRefs in m_Entries from objects in bioseq_set for thread safety - m_Entries.clear(); + return m_BasesAdded; } -int +CRef CASN1InputSourceOMF::x_ReadOneSeq(CNcbiIstream& instream) { CTempString line; CTempString id; - int retval = -1; + CRef retval; CRef seq_entry(new CSeq_entry); try { @@ -115,20 +100,22 @@ CASN1InputSourceOMF::x_ReadOneSeq(CNcbiIstream& instream) } catch (...) { if (instream.eof()) { - return -1; + return retval; } NCBI_THROW(CInputException, eInvalidInput, "Problem reading ASN1 entry"); } - if (!m_Validate || - x_ValidateSequence(seq_entry->GetSeq().GetInst().GetSeq_data(), - seq_entry->GetSeq().GetInst().GetLength())) { - - m_Entries[m_Index] = seq_entry; - retval = m_Index; - m_Index++; + retval = seq_entry; + if (!seq_entry->GetSeq().GetInst().IsSetLength()) { + string message = "Sequence length not set"; + if (seq_entry->GetSeq().GetFirstId()) { + message += (string)" in the instance of " + + seq_entry->GetSeq().GetFirstId()->GetSeqIdString(); + } + NCBI_THROW(CInputException, eInvalidInput, message); } + m_BasesAdded += seq_entry->GetSeq().GetInst().GetLength(); return retval; } @@ -137,9 +124,6 @@ CASN1InputSourceOMF::x_ReadOneSeq(CNcbiIstream& instream) bool CASN1InputSourceOMF::x_ReadFromSingleFile(CBioseq_set& bioseq_set) { - int current_read = 0; - bool first_added = false; - // tags to indicate paired sequences CRef seqdesc_first(new CSeqdesc); seqdesc_first->SetUser().SetType().SetStr("Mapping"); @@ -149,49 +133,33 @@ CASN1InputSourceOMF::x_ReadFromSingleFile(CBioseq_set& bioseq_set) seqdesc_last->SetUser().SetType().SetStr("Mapping"); seqdesc_last->SetUser().AddField("has_pair", eLastSegment); - CRef seqdesc_first_partial(new CSeqdesc); - seqdesc_first_partial->SetUser().SetType().SetStr("Mapping"); - seqdesc_first_partial->SetUser().AddField("has_pair", - fFirstSegmentFlag | fPartialFlag); - - CRef seqdesc_last_partial(new CSeqdesc); - seqdesc_last_partial->SetUser().SetType().SetStr("Mapping"); - seqdesc_last_partial->SetUser().AddField("has_pair", - fLastSegmentFlag | fPartialFlag); - - m_Index = 0; - while (m_Index < (int)m_NumSeqsInBatch && !m_InputStream->eof()) { - int index = x_ReadOneSeq(*m_InputStream); - - if (index >= 0) { - - if (m_IsPaired && (current_read & 1) == 0) { - first_added = true; + CRef first; + CRef second; + first = x_ReadOneSeq(*m_InputStream); + + // if paired rest the next sequence and mark a pair + if (m_IsPaired) { + second = x_ReadOneSeq(*m_InputStream); + + if (first.NotEmpty()) { + if (second.NotEmpty()) { + first->SetSeq().SetDescr().Set().push_back(seqdesc_first); } + bioseq_set.SetSeq_set().push_back(first); + } - if (m_IsPaired && (current_read & 1) == 1) { - if (first_added) { - bioseq_set.SetSeq_set().back()->SetSeq().SetDescr().Set(). - push_back(seqdesc_first); - m_Entries[index]->SetSeq().SetDescr().Set().push_back(seqdesc_last); - } - else { - m_Entries[index]->SetSeq().SetDescr().Set().push_back( - seqdesc_last_partial); - } - first_added = false; + if (second.NotEmpty()) { + if (first.NotEmpty()) { + second->SetSeq().SetDescr().Set().push_back(seqdesc_last); } - - bioseq_set.SetSeq_set().push_back(m_Entries[index]); + bioseq_set.SetSeq_set().push_back(second); } - else { - if (first_added) { - bioseq_set.SetSeq_set().back()->SetSeq().SetDescr().Set(). - push_back(seqdesc_first_partial); - } - first_added = false; + } + else { + // otherwise just add the read sequence + if (first.NotEmpty()) { + bioseq_set.SetSeq_set().push_back(first); } - current_read++; } return true; @@ -210,154 +178,29 @@ CASN1InputSourceOMF::x_ReadFromTwoFiles(CBioseq_set& bioseq_set) seqdesc_last->SetUser().SetType().SetStr("Mapping"); seqdesc_last->SetUser().AddField("has_pair", eLastSegment); - CRef seqdesc_first_partial(new CSeqdesc); - seqdesc_first_partial->SetUser().SetType().SetStr("Mapping"); - seqdesc_first_partial->SetUser().AddField("has_pair", - fFirstSegmentFlag | fPartialFlag); - - CRef seqdesc_last_partial(new CSeqdesc); - seqdesc_last_partial->SetUser().SetType().SetStr("Mapping"); - seqdesc_last_partial->SetUser().AddField("has_pair", - fLastSegmentFlag | fPartialFlag); - - int index1; - int index2; - m_Index = 0; - while (m_Index < (int)m_NumSeqsInBatch && !m_InputStream->eof() && - !m_SecondInputStream->eof()) { - - index1 = x_ReadOneSeq(*m_InputStream); - index2 = x_ReadOneSeq(*m_SecondInputStream); - - // if both sequences were read, the pair in the first one - if (index1 >= 0 && index2 >= 0) { - m_Entries[index1]->SetSeq().SetDescr().Set().push_back( - seqdesc_first); - - m_Entries[index2]->SetSeq().SetDescr().Set().push_back( - seqdesc_last); - - bioseq_set.SetSeq_set().push_back(m_Entries[index1]); - bioseq_set.SetSeq_set().push_back(m_Entries[index2]); - } - else { - // otherwise mark incomplete pair for the sequence that was read - if (index1 >= 0) { - m_Entries[index1]->SetSeq().SetDescr().Set().push_back( - seqdesc_first_partial); - bioseq_set.SetSeq_set().push_back(m_Entries[index1]); - } - - if (index2 >= 0) { - m_Entries[index2]->SetSeq().SetDescr().Set().push_back( - seqdesc_last_partial); - bioseq_set.SetSeq_set().push_back(m_Entries[index2]); - } - } - } - - return true; -} + CRef first = x_ReadOneSeq(*m_InputStream); + CRef second = x_ReadOneSeq(*m_SecondInputStream); + // if both sequences were read, the pair in the first one + if (first.NotEmpty() && second.NotEmpty()) { + first->SetSeq().SetDescr().Set().push_back(seqdesc_first); + second->SetSeq().SetDescr().Set().push_back(seqdesc_last); -bool CASN1InputSourceOMF::x_ValidateSequence(const CSeq_data& seq_data, - int length) -{ - string sequence; - int entropy; - - switch (seq_data.Which()) { - - case CSeq_data::e_Ncbi2na: - // Ncbi2na format does not have ambiguous bases, hence only compute - // entropy and exit - entropy = x_FindDimerEntropy2NA(seq_data.GetNcbi2na().Get(), length); - return entropy > 16; - - - case CSeq_data::e_Ncbi4na: - // convert sequence to Iupac - CSeqConvert::Convert(seq_data.GetNcbi4na().Get(), - CSeqUtil::e_Ncbi4na, 0, length, - sequence, CSeqUtil::e_Iupacna); - break; - - case CSeq_data::e_Ncbi8na: - // convert sequence to Iupac - CSeqConvert::Convert(seq_data.GetNcbi8na().Get(), - CSeqUtil::e_Ncbi8na, 0, length, - sequence, CSeqUtil::e_Iupacna); - break; - - case CSeq_data::e_Iupacna: - sequence.resize(length); - memcpy(&sequence[0], seq_data.GetIupacna().Get().c_str(), - length * sizeof(Uint1)); - break; - - default: - NCBI_THROW(CInputException, eInvalidInput, "Encoding not handled " - "for input sequences"); - - }; - - // find number of ambiguous bases - const char* s = sequence.c_str(); - const int kNBase = (int)'N'; - const double kMaxFractionAmbiguousBases = 0.5; - int num = 0; - for (int i=0;i < length;i++) { - num += (toupper((int)s[i]) == kNBase); - } - - if ((double)num / length > kMaxFractionAmbiguousBases) { - return false; + bioseq_set.SetSeq_set().push_back(first); + bioseq_set.SetSeq_set().push_back(second); } - - // find dimer entropy - entropy = FindDimerEntropy(sequence.c_str(), length); - return entropy > 16; -} - - -int CASN1InputSourceOMF::x_FindDimerEntropy2NA(const vector& sequence, - int length) -{ - const int kNumDimers = 1 << 4; - int counts[kNumDimers]; - memset(counts, 0, kNumDimers * sizeof(int)); - int num = 0; - Uint1 mask = 0xc0; - Uint1 base; - int dimer; - int k = 0; - int i = 0; - - // count dimers - dimer = (sequence[i] & (mask >> k)) >> (2*(3 - k)); - k++; - num++; - while (num < length) { - _ASSERT(i < (int)sequence.size()); - for (;k < 4;k++) { - base = (sequence[i] & (mask >> k)) >> (2*(3 - k)); - dimer = ((dimer << 2) | base) & 0xf; - counts[dimer]++; - num++; + else { + // otherwise mark incomplete pair for the sequence that was read + if (first.NotEmpty()) { + bioseq_set.SetSeq_set().push_back(first); } - k = 0; - i++; - } - // compute amount of information in the sequence - double sum = 0.0; - for (int i=0;i < kNumDimers;i++) { - if (counts[i]) { - sum += (double)counts[i] * log((double)counts[i] / num); + if (second.NotEmpty()) { + bioseq_set.SetSeq_set().push_back(second); } } - return -sum * (1.0 /(log(16.0))) + 0.5; + return true; } diff --git a/c++/src/algo/blast/blastinput/blast_fasta_input.cpp b/c++/src/algo/blast/blastinput/blast_fasta_input.cpp index 90d49e71..793d6a4d 100644 --- a/c++/src/algo/blast/blastinput/blast_fasta_input.cpp +++ b/c++/src/algo/blast/blastinput/blast_fasta_input.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_fasta_input.cpp 517821 2016-10-27 19:13:57Z ivanov $ +/* $Id: blast_fasta_input.cpp 547030 2017-09-25 17:24:51Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -292,6 +292,11 @@ CBlastFastaInputSource::x_InitInputReader() CFastaReader::fAllSeqIds : (CFastaReader::fNoParseID | CFastaReader::fDLOptional); + + // Allow CFastaReader fSkipCheck flag to be set based + // on new CBlastInputSourceConfig property - GetSkipSeqCheck() -RMH- + flags += ( m_Config.GetSkipSeqCheck() ? CFastaReader::fSkipCheck : 0 ); + flags += (m_ReadProteins ? CFastaReader::fAssumeProt : CFastaReader::fAssumeNuc); @@ -471,29 +476,27 @@ CBlastFastaInputSource::GetNextSequence(CScope& scope) CShortReadFastaInputSource::CShortReadFastaInputSource(CNcbiIstream& infile, - TSeqPos num_seqs, CShortReadFastaInputSource::EInputFormat format, - bool paired, - bool validate) - : m_NumSeqsInBatch(num_seqs), - m_SeqBuffLen(550), + bool paired) + : m_SeqBuffLen(550), m_LineReader(new CStreamLineReader(infile)), m_IsPaired(paired), - m_Validate(validate), - m_NumRejected(0), - m_Format(format) + m_Format(format), + m_Id(1), + m_ParseSeqIds(false) { // allocate sequence buffer m_Sequence.reserve(m_SeqBuffLen + 1); // read the first line for FASTA input if (m_Format == eFasta) { + CTempString line; do { ++(*m_LineReader); - m_Line = **m_LineReader; - } while (m_Line.empty() && !m_LineReader->AtEOF()); + line = **m_LineReader; + } while (line.empty() && !m_LineReader->AtEOF()); - if (m_Line[0] != '>') { + if (line[0] != '>') { NCBI_THROW(CInputException, eInvalidInput, "FASTA parse error: " "defline expected"); } @@ -502,17 +505,14 @@ CShortReadFastaInputSource::CShortReadFastaInputSource(CNcbiIstream& infile, CShortReadFastaInputSource::CShortReadFastaInputSource(CNcbiIstream& infile1, CNcbiIstream& infile2, - TSeqPos num_seqs, - CShortReadFastaInputSource::EInputFormat format, - bool validate) - : m_NumSeqsInBatch(num_seqs), - m_SeqBuffLen(550), + CShortReadFastaInputSource::EInputFormat format) + : m_SeqBuffLen(550), m_LineReader(new CStreamLineReader(infile1)), m_SecondLineReader(new CStreamLineReader(infile2)), m_IsPaired(true), - m_Validate(validate), - m_NumRejected(0), - m_Format(format) + m_Format(format), + m_Id(1), + m_ParseSeqIds(false) { if (m_Format == eFastc) { m_LineReader.Reset(); @@ -550,27 +550,10 @@ CShortReadFastaInputSource::CShortReadFastaInputSource(CNcbiIstream& infile1, } } -void -CShortReadFastaInputSource::GetNextNumSequences(CBioseq_set& bioseq_set, - TSeqPos /* num_seqs */) +int +CShortReadFastaInputSource::GetNextSequence(CBioseq_set& bioseq_set) { - // preallocate and initialize objects for sequences to be read - m_SeqIds.clear(); - m_Entries.clear(); - - // +1 in case we need to read one more sequence so that a pair is not - // broken - m_SeqIds.resize(m_NumSeqsInBatch + 1); - m_Entries.resize(m_NumSeqsInBatch + 1); - - // allocate seq_id and seq_entry objects, they will be reused to minimize - // time spent on memory management - for (TSeqPos i=0;i < m_NumSeqsInBatch + 1;i++) { - m_SeqIds[i].Reset(new CSeq_id); - m_Entries[i].Reset(new CSeq_entry); - m_Entries[i]->SetSeq().SetInst().SetMol(CSeq_inst::eMol_na); - m_Entries[i]->SetSeq().SetInst().SetRepr(CSeq_inst::eRepr_raw); - } + m_BasesAdded = 0; // read sequernces switch (m_Format) { @@ -579,7 +562,7 @@ CShortReadFastaInputSource::GetNextNumSequences(CBioseq_set& bioseq_set, x_ReadFromTwoFiles(bioseq_set, m_Format); } else { - x_ReadFasta(bioseq_set); + x_ReadFastaOrFastq(bioseq_set); } break; @@ -588,7 +571,7 @@ CShortReadFastaInputSource::GetNextNumSequences(CBioseq_set& bioseq_set, x_ReadFromTwoFiles(bioseq_set, m_Format); } else { - x_ReadFastq(bioseq_set); + x_ReadFastaOrFastq(bioseq_set); } break; @@ -601,23 +584,13 @@ CShortReadFastaInputSource::GetNextNumSequences(CBioseq_set& bioseq_set, }; - // detach CRefs from in m_Entries and m_SeqIds from objects in bioseq_set - // for thread safety - m_Entries.clear(); - m_SeqIds.clear(); + return m_BasesAdded; } + void -CShortReadFastaInputSource::x_ReadFasta(CBioseq_set& bioseq_set) +CShortReadFastaInputSource::x_ReadFastaOrFastq(CBioseq_set& bioseq_set) { - TSeqPos index = 0; - int start = 0; - // parse the last read defline - CTempString id = x_ParseDefline(m_Line); - m_SeqIds[0]->Set(CSeq_id::e_Local, id); - int current_read = 0; - bool first_added = false; - // tags to indicate paired sequences CRef seqdesc_first(new CSeqdesc); seqdesc_first->SetUser().SetType().SetStr("Mapping"); @@ -627,136 +600,59 @@ CShortReadFastaInputSource::x_ReadFasta(CBioseq_set& bioseq_set) seqdesc_last->SetUser().SetType().SetStr("Mapping"); seqdesc_last->SetUser().AddField("has_pair", eLastSegment); - CRef seqdesc_first_partial(new CSeqdesc); - seqdesc_first_partial->SetUser().SetType().SetStr("Mapping"); - seqdesc_first_partial->SetUser().AddField("has_pair", - fFirstSegmentFlag | fPartialFlag); - - CRef seqdesc_last_partial(new CSeqdesc); - seqdesc_last_partial->SetUser().SetType().SetStr("Mapping"); - seqdesc_last_partial->SetUser().AddField("has_pair", - fLastSegmentFlag | fPartialFlag); - - while (index < m_NumSeqsInBatch && !m_LineReader->AtEOF()) { - ++(*m_LineReader); - m_Line = **m_LineReader; - - // ignore empty lines - if (m_Line.empty()) { - continue; - } - - // if defline - if (m_Line[0] == '>') { - - // set up sequence - if (!m_Validate || x_ValidateSequence(m_Sequence.data(), start)) { - CBioseq& bioseq = m_Entries[index]->SetSeq(); - bioseq.SetId().clear(); - bioseq.SetId().push_back(m_SeqIds[index]); - bioseq.SetInst().SetLength(start); - m_Sequence[start] = 0; - bioseq.SetInst().SetSeq_data().SetIupacna(CIUPACna( - &m_Sequence[0])); - - if (m_IsPaired && (current_read & 1) == 0) { - first_added = true; - } - - if (m_IsPaired && (current_read & 1) == 1) { - if (first_added) { - // set paired tags: both sequences of the pair passed - // validation - bioseq_set.SetSeq_set().back()->SetSeq().SetDescr(). - Set().push_back(seqdesc_first); - - m_Entries[index]->SetSeq().SetDescr().Set().push_back( - seqdesc_last); - } - else { - // only the second sequence of the pair passed - // validation - m_Entries[index]->SetSeq().SetDescr().Set().push_back( - seqdesc_last_partial); - } - first_added = false; - } + CRef first; + CRef second; + switch (m_Format) { + case eFasta: + first = x_ReadFastaOneSeq(m_LineReader); + break; - // add a sequence to the batch - bioseq_set.SetSeq_set().push_back(m_Entries[index]); + case eFastq: + first = x_ReadFastqOneSeq(m_LineReader); + break; - index++; - } - else { - if (first_added) { - // only the first sequence of the pair passed validation - bioseq_set.SetSeq_set().back()->SetSeq().SetDescr(). - Set().push_back(seqdesc_first_partial); - - } + default: + NCBI_THROW(CInputException, eInvalidInput, "Invalid input file " + "format x_ReadFastaOrFastq read either FASTA or FASTQ"); + } - m_NumRejected++; - first_added = false; - } - current_read++; - start = 0; + // if paired read the next sequence and mark a pair + if (m_IsPaired) { + switch (m_Format) { + case eFasta: + second = x_ReadFastaOneSeq(m_LineReader); + break; - // set sequence id for the new sequence - if (index < m_NumSeqsInBatch) { - id = x_ParseDefline(m_Line); - m_SeqIds[index]->Set(CSeq_id::e_Local, id); - } + case eFastq: + second = x_ReadFastqOneSeq(m_LineReader); + break; + + default: + NCBI_THROW(CInputException, eInvalidInput, "Invalid input file " + "format x_ReadFastaOrFastq read either FASTA or " + "FASTQ"); } - else { - // otherwise copy the sequence - // increase the sequence buffer if necessary - if (start + m_Line.length() + 1 > m_SeqBuffLen) { - string tmp; - m_SeqBuffLen = 2 * (start + m_Line.length() + 1); - tmp.reserve(m_SeqBuffLen); - memcpy(&tmp[0], &m_Sequence[0], start); - m_Sequence.swap(tmp); + + if (first.NotEmpty()) { + if (second.NotEmpty()) { + first->SetSeq().SetDescr().Set().push_back(seqdesc_first); } - memcpy(&m_Sequence[start], m_Line.data(), m_Line.length()); - start += m_Line.length(); + bioseq_set.SetSeq_set().push_back(first); } - } - if (!m_LineReader->AtEOF()) { - return; - } - - if (m_Validate && (!x_ValidateSequence(m_Sequence.data(), start))) { - m_NumRejected++; - if (m_IsPaired) { - if (first_added && (current_read & 1) == 1) { - bioseq_set.SetSeq_set().back()->SetSeq().SetDescr().Set(). - push_back(seqdesc_first_partial); + if (second.NotEmpty()) { + if (first.NotEmpty()) { + second->SetSeq().SetDescr().Set().push_back(seqdesc_last); } + bioseq_set.SetSeq_set().push_back(second); } - - return; - } - - if (m_IsPaired && (current_read & 1) == 1 && first_added) { - // add the tag for paired reads - bioseq_set.SetSeq_set().back()->SetSeq().SetDescr().Set(). - push_back(seqdesc_first); } - - // set up the last sequence read - CBioseq& bioseq = m_Entries[index]->SetSeq(); - bioseq.SetId().clear(); - bioseq.SetId().push_back(m_SeqIds[index]); - bioseq.SetInst().SetLength(start); - m_Sequence[start] = 0; - bioseq.SetInst().SetSeq_data().SetIupacna(CIUPACna(&m_Sequence[0])); - bioseq_set.SetSeq_set().push_back(m_Entries[index]); - - if (m_IsPaired && (current_read & 1) == 1) { - bioseq_set.SetSeq_set().back()->SetSeq().SetDescr().Set(). - push_back(first_added ? seqdesc_last : seqdesc_last_partial); + else { + // otherwise just add the read sequence + if (first.NotEmpty()) { + bioseq_set.SetSeq_set().push_back(first); + } } } @@ -764,8 +660,8 @@ CShortReadFastaInputSource::x_ReadFasta(CBioseq_set& bioseq_set) void CShortReadFastaInputSource::x_ReadFastc(CBioseq_set& bioseq_set) { - TSeqPos index = 0; string id; + CTempString line; // tags to indicate paired sequences CRef seqdesc_first(new CSeqdesc); @@ -776,164 +672,127 @@ CShortReadFastaInputSource::x_ReadFastc(CBioseq_set& bioseq_set) seqdesc_last->SetUser().SetType().SetStr("Mapping"); seqdesc_last->SetUser().AddField("has_pair", eLastSegment); - while (index < m_NumSeqsInBatch && !m_LineReader->AtEOF()) { - ++(*m_LineReader); - m_Line = **m_LineReader; - - // ignore empty lines - if (m_Line.empty()) { - continue; - } - - // if defline - if (m_Line[0] == '>') { - id = x_ParseDefline(m_Line); - } - else { - // otherwise sequence + if (m_LineReader->AtEOF()) { + return; + } - // make sure that a defline was read first - if (id.empty()) { - NCBI_THROW(CInputException, eInvalidInput, - (string)"Missing defline before line: " + - NStr::IntToString(m_LineReader->GetLineNumber())); - } + ++(*m_LineReader); + line = **m_LineReader; - // find '><' that separate reads of a pair - size_t p = m_Line.find('>'); - if (p == CTempString::npos || m_Line[p + 1] != '<') { + // ignore empty lines + while (!m_LineReader->AtEOF() && line.empty()) { + ++(*m_LineReader); + line = **m_LineReader; + } - NCBI_THROW(CInputException, eInvalidInput, - (string)"FASTC parse error: Sequence separator '><'" - " was not found in line: " + - NStr::IntToString(m_LineReader->GetLineNumber())); - } + if (m_LineReader->AtEOF()) { + return; + } - // set up reads, there are two sequences in the same line separated - char* first = (char*)m_Line.data(); - char* second = (char*)m_Line.data() + p + 2; - size_t first_len = p; - size_t second_len = m_Line.length() - p - 2; - - // FIXME: Both reads are rejected if only one fails validation - if (x_ValidateSequence(first, first_len) && - x_ValidateSequence(second, second_len)) { - - {{ - CBioseq& bioseq = m_Entries[index]->SetSeq(); - bioseq.SetId().clear(); - m_SeqIds[index]->Set(CSeq_id::e_Local, id + ".1"); - bioseq.SetId().push_back(m_SeqIds[index]); - bioseq.SetInst().SetLength(first_len); - first[first_len] = 0; - bioseq.SetInst().SetSeq_data().SetIupacna(CIUPACna(first)); - - bioseq.SetDescr().Set().push_back(seqdesc_first); - }} - // add a sequence to the batch - bioseq_set.SetSeq_set().push_back(m_Entries[index]); - index++; - - {{ - CBioseq& bioseq = m_Entries[index]->SetSeq(); - bioseq.SetId().clear(); - m_SeqIds[index]->Set(CSeq_id::e_Local, id + ".2"); - bioseq.SetId().push_back(m_SeqIds[index]); - bioseq.SetInst().SetLength(second_len); - second[second_len] = 0; - bioseq.SetInst().SetSeq_data().SetIupacna(CIUPACna(second)); - - bioseq.SetDescr().Set().push_back(seqdesc_last); - }} - // add a sequence to the batch - bioseq_set.SetSeq_set().push_back(m_Entries[index]); - index++; - } - else { - m_NumRejected++; - } - id.clear(); - } + if (line[0] != '>') { + NCBI_THROW(CInputException, eInvalidInput, + (string)"Missing defline before line: " + + NStr::IntToString(m_LineReader->GetLineNumber())); } -} + id = x_ParseDefline(line); -void -CShortReadFastaInputSource::x_ReadFastq(CBioseq_set& bioseq_set) -{ - int current_read = 0; - bool first_added = false; + if (m_LineReader->AtEOF()) { + NCBI_THROW(CInputException, eInvalidInput, + (string)"No sequence data for defline: " + id + + "\nTruncated file?"); + } - // tags to indicate paired sequences - CRef seqdesc_first(new CSeqdesc); - seqdesc_first->SetUser().SetType().SetStr("Mapping"); - seqdesc_first->SetUser().AddField("has_pair", eFirstSegment); + ++(*m_LineReader); + line = **m_LineReader; + while (line.empty() && !m_LineReader->AtEOF()) { + ++(*m_LineReader); + line = **m_LineReader; + } - CRef seqdesc_last(new CSeqdesc); - seqdesc_last->SetUser().SetType().SetStr("Mapping"); - seqdesc_last->SetUser().AddField("has_pair", eLastSegment); + if (line[0] == '>' || (line.empty() && m_LineReader->AtEOF())) { + NCBI_THROW(CInputException, eInvalidInput, + (string)"No sequence data for defline: " + line); + } - CRef seqdesc_first_partial(new CSeqdesc); - seqdesc_first_partial->SetUser().SetType().SetStr("Mapping"); - seqdesc_first_partial->SetUser().AddField("has_pair", - fFirstSegmentFlag | fPartialFlag); - CRef seqdesc_last_partial(new CSeqdesc); - seqdesc_last_partial->SetUser().SetType().SetStr("Mapping"); - seqdesc_last_partial->SetUser().AddField("has_pair", - fLastSegmentFlag | fPartialFlag); + // find '><' that separate reads of a pair + size_t p = line.find('>'); + if (p == CTempString::npos || line[p + 1] != '<') { - m_Index = 0; - while (m_Index < (int)m_NumSeqsInBatch && !m_LineReader->AtEOF()) { - int index = x_ReadFastqOneSeq(m_LineReader); + NCBI_THROW(CInputException, eInvalidInput, + (string)"FASTC parse error: Sequence separator '><'" + " was not found in line: " + + NStr::IntToString(m_LineReader->GetLineNumber())); + } - if (index >= 0) { + // set up reads, there are two sequences in the same line separated + char* first = (char*)line.data(); + char* second = (char*)line.data() + p + 2; + size_t first_len = p; + size_t second_len = line.length() - p - 2; - if (m_IsPaired && (current_read & 1) == 0) { - first_added = true; + {{ + CRef seq_entry(new CSeq_entry); + CBioseq& bioseq = seq_entry->SetSeq(); + bioseq.SetId().clear(); + if (m_ParseSeqIds) { + CRef seqid(new CSeq_id(id + ".1")); + bioseq.SetId().push_back(seqid); } - - if (m_IsPaired && (current_read & 1) == 1) { - if (first_added) { - // this field indicates that this sequence has a pair - bioseq_set.SetSeq_set().back()->SetSeq().SetDescr().Set(). - push_back(seqdesc_first); - - m_Entries[index]->SetSeq().SetDescr().Set().push_back( - seqdesc_last); - } - else { - m_Entries[index]->SetSeq().SetDescr().Set().push_back( - seqdesc_last_partial); - } - first_added = false; + else { + CRef title(new CSeqdesc); + title->SetTitle(id + ".1"); + bioseq.SetDescr().Set().push_back(title); + bioseq.SetId().push_back(x_GetNextSeqId()); } - - bioseq_set.SetSeq_set().push_back(m_Entries[index]); - } - else { - if (first_added) { - bioseq_set.SetSeq_set().back()->SetSeq().SetDescr().Set(). - push_back(seqdesc_first_partial); + bioseq.SetInst().SetMol(CSeq_inst::eMol_na); + bioseq.SetInst().SetRepr(CSeq_inst::eRepr_raw); + bioseq.SetInst().SetLength(first_len); + first[first_len] = 0; + bioseq.SetInst().SetSeq_data().SetIupacna(CIUPACna(first)); + bioseq.SetDescr().Set().push_back(seqdesc_first); + + // add a sequence to the batch + bioseq_set.SetSeq_set().push_back(seq_entry); + }} + + {{ + CRef seq_entry(new CSeq_entry); + CBioseq& bioseq = seq_entry->SetSeq(); + bioseq.SetId().clear(); + if (m_ParseSeqIds) { + CRef seqid(new CSeq_id(id + ".2")); + bioseq.SetId().push_back(seqid); } - - m_NumRejected++; - first_added = false; - } - current_read++; - } - + else { + CRef title(new CSeqdesc); + title->SetTitle(id + ".2"); + bioseq.SetDescr().Set().push_back(title); + bioseq.SetId().push_back(x_GetNextSeqId()); + } + bioseq.SetInst().SetMol(CSeq_inst::eMol_na); + bioseq.SetInst().SetRepr(CSeq_inst::eRepr_raw); + bioseq.SetInst().SetLength(second_len); + second[second_len] = 0; + bioseq.SetInst().SetSeq_data().SetIupacna(CIUPACna(second)); + bioseq.SetDescr().Set().push_back(seqdesc_last); + + // add a sequence to the batch + bioseq_set.SetSeq_set().push_back(seq_entry); + }} + + m_BasesAdded += first_len + second_len; + id.clear(); } - -int +CRef CShortReadFastaInputSource::x_ReadFastaOneSeq(CRef line_reader) { int start = 0; // parse the last read defline CTempString line = **line_reader; - CTempString id = x_ParseDefline(line); - m_SeqIds[m_Index]->Set(CSeq_id::e_Local, id); + string defline_id = x_ParseDefline(line); ++(*line_reader); line = **line_reader; while (line[0] != '>') { @@ -967,29 +826,41 @@ CShortReadFastaInputSource::x_ReadFastaOneSeq(CRef line_reader) } // set up sequence - if (!m_Validate || x_ValidateSequence(m_Sequence.data(), start)) { - - CBioseq& bioseq = m_Entries[m_Index]->SetSeq(); + if (start > 0) { + CRef seq_entry(new CSeq_entry); + CBioseq& bioseq = seq_entry->SetSeq(); bioseq.SetId().clear(); - bioseq.SetId().push_back(m_SeqIds[m_Index]); + if (m_ParseSeqIds) { + CRef seqid(new CSeq_id(defline_id)); + bioseq.SetId().push_back(seqid); + bioseq.SetDescr(); + } + else { + CRef title(new CSeqdesc); + title->SetTitle(defline_id); + bioseq.SetDescr().Set().push_back(title); + bioseq.SetId().push_back(x_GetNextSeqId()); + } + bioseq.SetInst().SetMol(CSeq_inst::eMol_na); + bioseq.SetInst().SetRepr(CSeq_inst::eRepr_raw); bioseq.SetInst().SetLength(start); m_Sequence[start] = 0; bioseq.SetInst().SetSeq_data().SetIupacna(CIUPACna(&m_Sequence[0])); - m_Index++; - return m_Index - 1; + m_BasesAdded += start; + return seq_entry; } - return -1; + return CRef(); } -int +CRef CShortReadFastaInputSource::x_ReadFastqOneSeq(CRef line_reader) { CTempString line; - CTempString id; - int retval = -1; + string defline_id; + CRef retval; // first read defline ++(*line_reader); @@ -1007,8 +878,7 @@ CShortReadFastaInputSource::x_ReadFastqOneSeq(CRef line_reader) NStr::IntToString(line_reader->GetLineNumber())); } - id = x_ParseDefline(line); - m_SeqIds[m_Index]->Set(CSeq_id::e_Local, id); + defline_id = x_ParseDefline(line); // read sequence ++(*line_reader); @@ -1020,16 +890,28 @@ CShortReadFastaInputSource::x_ReadFastqOneSeq(CRef line_reader) } // set up sequence - if (!m_Validate || x_ValidateSequence(line.data(), line.length())) { - - CBioseq& bioseq = m_Entries[m_Index]->SetSeq(); + if (line.length() > 0) { + CRef seq_entry(new CSeq_entry); + CBioseq& bioseq = seq_entry->SetSeq(); bioseq.SetId().clear(); - bioseq.SetId().push_back(m_SeqIds[m_Index]); + if (m_ParseSeqIds) { + CRef seqid(new CSeq_id(defline_id)); + bioseq.SetId().push_back(seqid); + bioseq.SetDescr(); + } + else { + CRef title(new CSeqdesc); + title->SetTitle(defline_id); + bioseq.SetDescr().Set().push_back(title); + bioseq.SetId().push_back(x_GetNextSeqId()); + } + bioseq.SetInst().SetMol(CSeq_inst::eMol_na); + bioseq.SetInst().SetRepr(CSeq_inst::eRepr_raw); bioseq.SetInst().SetLength(line.length()); bioseq.SetInst().SetSeq_data().SetIupacna(CIUPACna(line.data())); - m_Index++; - retval = m_Index - 1; + m_BasesAdded += line.length(); + retval = seq_entry; } // read and skip second defline @@ -1078,54 +960,30 @@ CShortReadFastaInputSource::x_ReadFromTwoFiles(CBioseq_set& bioseq_set, seqdesc_last->SetUser().SetType().SetStr("Mapping"); seqdesc_last->SetUser().AddField("has_pair", eLastSegment); - CRef seqdesc_first_partial(new CSeqdesc); - seqdesc_first_partial->SetUser().SetType().SetStr("Mapping"); - seqdesc_first_partial->SetUser().AddField("has_pair", - fFirstSegmentFlag | fPartialFlag); - - CRef seqdesc_last_partial(new CSeqdesc); - seqdesc_last_partial->SetUser().SetType().SetStr("Mapping"); - seqdesc_last_partial->SetUser().AddField("has_pair", - fLastSegmentFlag | fPartialFlag); - - int index1; - int index2; - m_Index = 0; - while (m_Index < (int)m_NumSeqsInBatch && !m_LineReader->AtEOF() && - !m_SecondLineReader->AtEOF()) { - - if (format == eFasta) { - index1 = x_ReadFastaOneSeq(m_LineReader); - index2 = x_ReadFastaOneSeq(m_SecondLineReader); - } - else { - index1 = x_ReadFastqOneSeq(m_LineReader); - index2 = x_ReadFastqOneSeq(m_SecondLineReader); - } + CRef first; + CRef second; - if (index1 >= 0) { - if (index2 >= 0) { - m_Entries[index1]->SetSeq().SetDescr().Set().push_back( - seqdesc_first); - } - else { - m_Entries[index1]->SetSeq().SetDescr().Set().push_back( - seqdesc_first_partial); - } - bioseq_set.SetSeq_set().push_back(m_Entries[index1]); + if (format == eFasta) { + first = x_ReadFastaOneSeq(m_LineReader); + second = x_ReadFastaOneSeq(m_SecondLineReader); + } + else { + first = x_ReadFastqOneSeq(m_LineReader); + second = x_ReadFastqOneSeq(m_SecondLineReader); + } + + if (first.NotEmpty()) { + if (second.NotEmpty()) { + first->SetSeq().SetDescr().Set().push_back(seqdesc_first); } + bioseq_set.SetSeq_set().push_back(first); + } - if (index2 >= 0) { - if (index1 >= 0) { - m_Entries[index2]->SetSeq().SetDescr().Set().push_back( - seqdesc_last); - } - else { - m_Entries[index2]->SetSeq().SetDescr().Set().push_back( - seqdesc_last_partial); - } - bioseq_set.SetSeq_set().push_back(m_Entries[index2]); + if (second.NotEmpty()) { + if (first.NotEmpty()) { + second->SetSeq().SetDescr().Set().push_back(seqdesc_last); } + bioseq_set.SetSeq_set().push_back(second); } return true; @@ -1143,23 +1001,13 @@ CTempString CShortReadFastaInputSource::x_ParseDefline(CTempString& line) } -bool CShortReadFastaInputSource::x_ValidateSequence(const char* sequence, - int length) +CRef CShortReadFastaInputSource::x_GetNextSeqId(void) { - const char* s = sequence; - const int kNBase = (int)'N'; - const double kMaxFractionAmbiguousBases = 0.5; - int num = 0; - for (int i=0;i < length;i++) { - num += (toupper((int)s[i]) == kNBase); - } - - if ((double)num / length > kMaxFractionAmbiguousBases) { - return false; - } + CRef seqid(new CSeq_id); + seqid->Set(CSeq_id::e_Local, NStr::IntToString(m_Id)); + m_Id++; - int entropy = FindDimerEntropy(sequence, length); - return entropy > 16; + return seqid; } END_SCOPE(blast) diff --git a/c++/src/algo/blast/blastinput/blast_input.cpp b/c++/src/algo/blast/blastinput/blast_input.cpp index 1b171509..f3702b2b 100644 --- a/c++/src/algo/blast/blastinput/blast_input.cpp +++ b/c++/src/algo/blast/blastinput/blast_input.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_input.cpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_input.cpp 543932 2017-08-15 16:50:39Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -53,9 +53,12 @@ CBlastInputSourceConfig::CBlastInputSourceConfig TSeqRange range /* = TSeqRange() */, bool retrieve_seq_data /* = true */, int local_id_counter /* = 1 */, - unsigned int seqlen_thresh2guess /* = numeric_limits::max()*/ ) + unsigned int seqlen_thresh2guess /* = numeric_limits::max()*/, + bool skip_seq_check /* = false -RMH- */ ) : m_Strand(strand), m_LowerCaseMask(lowercase), - m_BelieveDeflines(believe_defline), m_Range(range), m_DLConfig(dlconfig), + m_BelieveDeflines(believe_defline), + m_SkipSeqCheck(skip_seq_check), /* -RMH- */ + m_Range(range), m_DLConfig(dlconfig), m_RetrieveSeqData(retrieve_seq_data), m_LocalIdCounter(local_id_counter), m_SeqLenThreshold2Guess(seqlen_thresh2guess), @@ -276,10 +279,11 @@ CBlastBioseqMaker::IsEmptyBioseq(const CBioseq& bioseq) } -CBlastInputOMF::CBlastInputOMF(CRef source, - TSeqPos num_seqs) +CBlastInputOMF::CBlastInputOMF(CBlastInputSourceOMF* source, + TSeqPos batch_size) : m_Source(source), - m_NumSeqsInBatch(num_seqs), + m_BatchSize(batch_size), + m_MaxNumSequences(5000000), m_BioseqSet(new CBioseq_set) {} @@ -287,15 +291,27 @@ CBlastInputOMF::CBlastInputOMF(CRef source, void CBlastInputOMF::GetNextSeqBatch(CBioseq_set& bioseq_set) { - m_Source->GetNextNumSequences(bioseq_set, m_NumSeqsInBatch); + TSeqPos bases_added = 0; + TSeqPos num_sequences = 0; + while (bases_added < m_BatchSize && num_sequences < m_MaxNumSequences && + !m_Source->End()) { + + CBioseq_set one_seq; + bases_added += m_Source->GetNextSequence(one_seq); + + for (auto it: one_seq.GetSeq_set()) { + num_sequences++; + bioseq_set.SetSeq_set().push_back(it); + } + } } CRef CBlastInputOMF::GetNextSeqBatch(void) { - m_BioseqSet->SetSeq_set().clear(); - m_Source->GetNextNumSequences(*m_BioseqSet, m_NumSeqsInBatch); - return m_BioseqSet; + CRef bioseq_set(new CBioseq_set); + GetNextSeqBatch(*bioseq_set); + return bioseq_set; } diff --git a/c++/src/algo/blast/blastinput/blast_input_aux.cpp b/c++/src/algo/blast/blastinput/blast_input_aux.cpp index 07df8ce6..3015dc9a 100644 --- a/c++/src/algo/blast/blastinput/blast_input_aux.cpp +++ b/c++/src/algo/blast/blastinput/blast_input_aux.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_input_aux.cpp 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_input_aux.cpp 533238 2017-04-13 19:29:13Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -105,9 +105,11 @@ GetQueryBatchSize(EProgram program, bool is_ungapped /* = false */, retval = 500000; break; case eMegablast: - case eMapper: retval = 5000000; break; + case eMapper: + retval = 50000000; + break; case eTblastn: retval = 20000; break; @@ -426,36 +428,6 @@ CheckForEmptySequences(CRef sequences, string& warnings) } } -// compute enrtopy of 2-mers in a IUPACNA sequence -int FindDimerEntropy(const char* sequence, int length) -{ - const int kNumDimers = 1 << 4; - int counts[kNumDimers]; - memset(counts, 0, kNumDimers * sizeof(int)); - int num = 0; - // count dimers - for (int i=0;i < length - 1;i++) { - Uint1 base_1 = IUPACNA_TO_BLASTNA[toupper((int)sequence[i])]; - Uint1 base_2 = IUPACNA_TO_BLASTNA[toupper((int)sequence[i + 1])]; - if ((base_1 & 0xfc) == 0 && (base_2 & 0xfc) == 0) { - int dimer = (base_1 << 2) | base_2; - counts[dimer]++; - num++; - } - } - - // compute amount of information in the sequence - double sum = 0.0; - for (int i=0;i < kNumDimers;i++) { - if (counts[i]) { - sum += (double)counts[i] * log((double)counts[i] / num); - } - } - - return -sum * (1.0 /(log(16.0))) + 0.5; -} - - END_SCOPE(blast) END_NCBI_SCOPE diff --git a/c++/src/algo/blast/blastinput/cmdline_flags.cpp b/c++/src/algo/blast/blastinput/cmdline_flags.cpp index bf3659be..7c2cf7af 100644 --- a/c++/src/algo/blast/blastinput/cmdline_flags.cpp +++ b/c++/src/algo/blast/blastinput/cmdline_flags.cpp @@ -1,4 +1,4 @@ -/* $Id: cmdline_flags.cpp 514854 2016-09-26 17:24:36Z ivanov $ +/* $Id: cmdline_flags.cpp 546749 2017-09-21 11:22:02Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -58,6 +58,7 @@ const string kArgGiList("gilist"); const string kArgDbTitle("title"); const string kArgSeqIdList("seqidlist"); const string kArgNegativeGiList("negative_gilist"); +const string kArgNegativeSeqidList("negative_seqidlist"); const string kArgDbSoftMask("db_soft_mask"); const string kArgDbHardMask("db_hard_mask"); @@ -68,6 +69,7 @@ const string kArgDbGeneticCode("db_gencode"); const string kArgRemote("remote"); const string kArgNumThreads("num_threads"); +const size_t kDfltIgBlastNumThreads = 4; const string kArgMatrixName("matrix"); @@ -181,6 +183,7 @@ const string kArgGLOrigin("organism"); const string kArgGLDomainSystem("domain_system"); const string kArgGLFocusV("focus_on_V_segment"); const string kArgExtendAlign("extend_align5end"); +const string kArgDetectOverlap("allow_vdj_overlap"); const string kArgMinVLength("min_V_length"); const string kArgMinJLength("min_J_length"); const string kArgNumClonotype("num_clonotype"); @@ -188,9 +191,9 @@ const string kArgClonotypeFile("clonotype_out"); const string kArgTranslate("show_translation"); const string kArgMinDMatch("min_D_match"); const string kArgDPenalty("D_penalty"); +const string kArgJPenalty("J_penalty"); const string kArgIgSeqType("ig_seqtype"); const string kArgMaxHSPsPerSubject("max_hsps"); -const int kDfltArgMaxHSPsPerSubject = 0; const string kArgSumStats("sum_stats"); const string kArgPercentIdentity("perc_identity"); const string kArgNoGreedyExtension("no_greedy"); @@ -214,13 +217,11 @@ const string kArgDomainInclusionEThreshold("domain_inclusion_ethresh"); const string kArgShowDomainHits("show_domain_hits"); const string kArgJDistance("thresh"); -const string kDfltArgJDistance("0.05"); +const string kDfltArgJDistance("0.1"); const string kArgMinHits("min_hits"); const string kDfltArgMinHits("0"); -const string kArgKIndex("dbk"); -const string kDfltArgKIndex("nr"); -const string kArgTargetSeqs("target_seqs"); -const string kDfltArgTargetSeqs("5000"); +const string kArgCandidateSeqs("candidates"); +const string kDfltArgCandidateSeqs("1000"); const string kArgRid("rid"); const string kArgArchive("archive"); @@ -239,6 +240,10 @@ const string kArgQueryMate("query_mate"); const string kArgRefType("reftype"); const string kArgOutputGzip("gzo"); const string kArgSraAccession("sra"); +const string kArgNoReadIdTrim("no_query_id_trim"); +const string kArgNoUnaligned("no_unaligned"); +const string kArgEnableSraCache("sra_cache"); +const string kArgMaxEditDist("max_edit_dist"); END_SCOPE(blast) END_NCBI_SCOPE diff --git a/c++/src/algo/blast/blastinput/igblastn_args.cpp b/c++/src/algo/blast/blastinput/igblastn_args.cpp index 94a048b3..1dba5f44 100644 --- a/c++/src/algo/blast/blastinput/igblastn_args.cpp +++ b/c++/src/algo/blast/blastinput/igblastn_args.cpp @@ -1,4 +1,4 @@ -/* $Id: igblastn_args.cpp 514849 2016-09-26 17:23:09Z ivanov $ +/* $Id: igblastn_args.cpp 546749 2017-09-21 11:22:02Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -52,14 +52,6 @@ CIgBlastnAppArgs::CIgBlastnAppArgs() m_Args.push_back(arg); m_ClientId = kProgram + " " + CBlastVersion().Print(); - /* - static const string kDefaultTask = "blastn"; - SetTask(kDefaultTask); - set tasks - (CBlastOptionsFactory::GetTasks(CBlastOptionsFactory::eNuclNucl)); - arg.Reset(new CTaskCmdLineArgs(tasks, kDefaultTask)); - m_Args.push_back(arg); */ - m_IgBlastArgs.Reset(new CIgBlastArgs(false)); arg.Reset(m_IgBlastArgs); m_Args.push_back(arg); @@ -70,6 +62,7 @@ CIgBlastnAppArgs::CIgBlastnAppArgs() m_Args.push_back(arg); m_StdCmdLineArgs.Reset(new CStdCmdLineArgs); + m_StdCmdLineArgs->SetSRAaccessionEnabled(true); arg.Reset(m_StdCmdLineArgs); m_Args.push_back(arg); @@ -79,13 +72,6 @@ CIgBlastnAppArgs::CIgBlastnAppArgs() arg.Reset(new CNuclArgs); m_Args.push_back(arg); - /* - arg.Reset(new CDiscontiguousMegablastArgs); - m_Args.push_back(arg); - - arg.Reset(new CFilteringArgs(kQueryIsProtein)); - m_Args.push_back(arg); */ - arg.Reset(new CGappedArgs); m_Args.push_back(arg); @@ -99,9 +85,10 @@ CIgBlastnAppArgs::CIgBlastnAppArgs() arg.Reset(new COffDiagonalRangeArg); m_Args.push_back(arg); - /* - arg.Reset(new CMbIndexArgs); - m_Args.push_back(arg); */ + // Remove the search strategy as it's not needed in IgBLAST + TBlastCmdLineArgs::iterator new_end = remove(m_Args.begin(), m_Args.end(), m_SearchStrategyArgs); + m_Args.erase(new_end, m_Args.end()); + m_SearchStrategyArgs.Reset(new CSearchStrategyArgs); m_QueryOptsArgs.Reset(new CQueryOptionsArgs(kQueryIsProtein)); arg.Reset(m_QueryOptsArgs); @@ -111,7 +98,7 @@ CIgBlastnAppArgs::CIgBlastnAppArgs() arg.Reset(m_FormattingArgs); m_Args.push_back(arg); - m_MTArgs.Reset(new CMTArgs); + m_MTArgs.Reset(new CMTArgs(kDfltIgBlastNumThreads)); arg.Reset(m_MTArgs); m_Args.push_back(arg); diff --git a/c++/src/algo/blast/blastinput/igblastp_args.cpp b/c++/src/algo/blast/blastinput/igblastp_args.cpp index 401c268b..4972b1db 100644 --- a/c++/src/algo/blast/blastinput/igblastp_args.cpp +++ b/c++/src/algo/blast/blastinput/igblastp_args.cpp @@ -1,4 +1,4 @@ -/* $Id: igblastp_args.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: igblastp_args.cpp 546749 2017-09-21 11:22:02Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -54,14 +54,6 @@ CIgBlastpAppArgs::CIgBlastpAppArgs() m_Args.push_back(arg); m_ClientId = kProgram + " " + CBlastVersion().Print(); - /* - static const string kDefaultTask = "blastp"; - SetTask(kDefaultTask); - set tasks - (CBlastOptionsFactory::GetTasks(CBlastOptionsFactory::eProtProt)); - arg.Reset(new CTaskCmdLineArgs(tasks, kDefaultTask)); - m_Args.push_back(arg); */ - m_IgBlastArgs.Reset(new CIgBlastArgs(true)); arg.Reset(m_IgBlastArgs); m_Args.push_back(arg); @@ -78,6 +70,11 @@ CIgBlastpAppArgs::CIgBlastpAppArgs() arg.Reset(new CGenericSearchArgs(kQueryIsProtein, false, true, false, true)); m_Args.push_back(arg); + // Remove the search strategy as it's not needed in IgBLAST + TBlastCmdLineArgs::iterator new_end = remove(m_Args.begin(), m_Args.end(), m_SearchStrategyArgs); + m_Args.erase(new_end, m_Args.end()); + m_SearchStrategyArgs.Reset(new CSearchStrategyArgs); + arg.Reset(new CFilteringArgs(kQueryIsProtein, kFilterByDefault)); m_Args.push_back(arg); @@ -105,7 +102,7 @@ CIgBlastpAppArgs::CIgBlastpAppArgs() arg.Reset(m_FormattingArgs); m_Args.push_back(arg); - m_MTArgs.Reset(new CMTArgs); + m_MTArgs.Reset(new CMTArgs(kDfltIgBlastNumThreads)); arg.Reset(m_MTArgs); m_Args.push_back(arg); diff --git a/c++/src/algo/blast/blastinput/kblastp_args.cpp b/c++/src/algo/blast/blastinput/kblastp_args.cpp index 3bcbb559..68ec012e 100644 --- a/c++/src/algo/blast/blastinput/kblastp_args.cpp +++ b/c++/src/algo/blast/blastinput/kblastp_args.cpp @@ -1,4 +1,4 @@ -/* $Id: kblastp_args.cpp 514853 2016-09-26 17:24:14Z ivanov $ +/* $Id: kblastp_args.cpp 533962 2017-04-21 12:57:45Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -51,10 +51,14 @@ CKBlastpAppArgs::CKBlastpAppArgs() m_Args.push_back(arg); m_ClientId = kProgram + " " + CBlastVersion().Print(); - // m_BlastDbArgs.Reset(new CBlastDatabaseArgs); - // m_BlastDbArgs->SetDatabaseMaskingSupport(false); - // arg.Reset(m_BlastDbArgs); - // m_Args.push_back(arg); + m_BlastDbArgs.Reset(new CBlastDatabaseArgs(false, false, false, false, true)); + m_BlastDbArgs->SetDatabaseMaskingSupport(false); + arg.Reset(m_BlastDbArgs); + m_Args.push_back(arg); + + m_KBlastpArgs.Reset(new CKBlastpArgs); + arg.Reset(m_KBlastpArgs); + m_Args.push_back(arg); m_StdCmdLineArgs.Reset(new CStdCmdLineArgs); arg.Reset(m_StdCmdLineArgs); @@ -63,8 +67,17 @@ CKBlastpAppArgs::CKBlastpAppArgs() arg.Reset(new CGenericSearchArgs(kQueryIsProtein)); m_Args.push_back(arg); - // arg.Reset(new CFilteringArgs(kQueryIsProtein, kFilterByDefault)); - // m_Args.push_back(arg); + arg.Reset(new CFilteringArgs(kQueryIsProtein, kFilterByDefault)); + m_Args.push_back(arg); + + arg.Reset(new CMatrixNameArg); + m_Args.push_back(arg); + + arg.Reset(new CWordThresholdArg); + m_Args.push_back(arg); + + arg.Reset(new CWindowSizeArg); + m_Args.push_back(arg); m_QueryOptsArgs.Reset(new CQueryOptionsArgs(kQueryIsProtein)); arg.Reset(m_QueryOptsArgs); @@ -78,8 +91,7 @@ CKBlastpAppArgs::CKBlastpAppArgs() arg.Reset(m_MTArgs); m_Args.push_back(arg); - m_KBlastpArgs.Reset(new CKBlastpArgs); - arg.Reset(m_KBlastpArgs); + arg.Reset(new CCompositionBasedStatsArgs); m_Args.push_back(arg); m_DebugArgs.Reset(new CDebugArgs); diff --git a/c++/src/algo/blast/blastinput/magicblast_args.cpp b/c++/src/algo/blast/blastinput/magicblast_args.cpp index 3e6f5ec7..7c1960fb 100644 --- a/c++/src/algo/blast/blastinput/magicblast_args.cpp +++ b/c++/src/algo/blast/blastinput/magicblast_args.cpp @@ -1,4 +1,4 @@ -/* $Id: magicblast_args.cpp 517510 2016-10-25 17:24:24Z ivanov $ +/* $Id: magicblast_args.cpp 546023 2017-09-13 11:14:25Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -53,29 +53,30 @@ public: arg_desc.SetCurrentGroup("General search options"); - arg_desc.AddOptionalKey(kArgWordSize, "int_value", "Word size for " - "wordfinder algorithm (length of best perfect " - "match)", CArgDescriptions::eInteger); + arg_desc.AddDefaultKey(kArgWordSize, "int_value", "Minimum number of " + "consecutive bass matching exactly", + CArgDescriptions::eInteger, + NStr::IntToString(BLAST_WORDSIZE_MAPPER)); arg_desc.SetConstraint(kArgWordSize, new CArgAllowValuesGreaterThanOrEqual(12)); // gap open penalty - arg_desc.AddOptionalKey(kArgGapOpen, "open_penalty", - "Cost to open a gap", - CArgDescriptions::eInteger); + arg_desc.AddDefaultKey(kArgGapOpen, "open_penalty", + "Cost to open a gap", + CArgDescriptions::eInteger, "0"); // gap extend penalty - arg_desc.AddOptionalKey(kArgGapExtend, "extend_penalty", + arg_desc.AddDefaultKey(kArgGapExtend, "extend_penalty", "Cost to extend a gap", - CArgDescriptions::eInteger); + CArgDescriptions::eInteger, "4"); // FIXME: not sure if this one is needed arg_desc.SetCurrentGroup("Restrict search or results"); - arg_desc.AddOptionalKey(kArgPercentIdentity, "float_value", - "Percent identity", - CArgDescriptions::eDouble); + arg_desc.AddDefaultKey(kArgPercentIdentity, "float_value", + "Percent identity cutoff for alignments", + CArgDescriptions::eDouble, "0.0"); arg_desc.SetConstraint(kArgPercentIdentity, new CArgAllow_Doubles(0.0, 100.0)); } @@ -90,80 +91,15 @@ public: virtual void SetArgumentDescriptions(CArgDescriptions& arg_desc) { arg_desc.SetCurrentGroup("General search options"); // blastn mismatch penalty - arg_desc.AddOptionalKey(kArgMismatch, "penalty", - "Penalty for a nucleotide mismatch", - CArgDescriptions::eInteger); + arg_desc.AddDefaultKey(kArgMismatch, "penalty", + "Penalty for a nucleotide mismatch", + CArgDescriptions::eInteger, "-4"); arg_desc.SetConstraint(kArgMismatch, new CArgAllowValuesLessThanOrEqual(0)); arg_desc.SetCurrentGroup(""); } }; -/// Formatting args advertising only SAM and fast tabular formats -class CMapperFormattingArgs : public CFormattingArgs -{ -public: - - CMapperFormattingArgs(void) : CFormattingArgs() {} - - virtual void SetArgumentDescriptions(CArgDescriptions& arg_desc) { - arg_desc.SetCurrentGroup("Formatting options"); - string kOutputFormatDescription = string( - "alignment view options:\n" - "sam = SAM format,\n" - "tabular = Tabular format,\n" - "asn = text ASN.1\n"); - - arg_desc.AddDefaultKey(align_format::kArgOutputFormat, "format", - kOutputFormatDescription, - CArgDescriptions::eString, - "sam"); - - set allowed_formats = {"sam", "tabular", "asn"}; - arg_desc.SetConstraint(align_format::kArgOutputFormat, - new CArgAllowStringSet(allowed_formats)); - - arg_desc.SetCurrentGroup(""); - } - - virtual void ExtractAlgorithmOptions(const CArgs& args, CBlastOptions& opt) { - if (args.Exist(align_format::kArgOutputFormat)) { - string fmt_choice = args[align_format::kArgOutputFormat].AsString(); - if (fmt_choice == "sam") { - m_OutputFormat = eSAM; - } - else if (fmt_choice == "tabular") { - m_OutputFormat = eTabular; - } - else if (fmt_choice == "asn") { - m_OutputFormat = eAsnText; - } - else { - CNcbiOstrstream os; - os << "'" << fmt_choice << "' is not a valid output format"; - string msg = CNcbiOstrstreamToString(os); - NCBI_THROW(CInputException, eInvalidInput, msg); - } - } - - m_ShowGis = true; - m_Html = false; - - // only the fast tabular format is able to show merged HSPs with - // common query bases - if (m_OutputFormat != eTabular) { - // FIXME: This is a hack. Merging should be done by the formatter, - // but is currently done by HSP stream writer. This is an easy - // switch until merging is implemented properly. - CNcbiEnvironment().Set("MAPPER_NO_OVERLAPPED_HSP_MERGE", "1"); - } - } - - virtual bool ArchiveFormatRequested(const CArgs& args) const { - return false; - } -}; - /// Longest intron size with non-zero defalut value class CMapperLargestIntronSizeArgs : public CLargestIntronSizeArgs { @@ -176,7 +112,7 @@ public: "nucleotide sequence when linking multiple distinct " "alignments", CArgDescriptions::eInteger, - NStr::IntToString(2000)); + NStr::IntToString(500000)); arg_desc.SetConstraint(kArgMaxIntronLength, new CArgAllowValuesGreaterThanOrEqual(0)); arg_desc.SetCurrentGroup(""); @@ -270,7 +206,7 @@ int CMagicBlastAppArgs::GetQueryBatchSize() const { bool is_remote = (m_RemoteArgs.NotEmpty() && m_RemoteArgs->ExecuteRemotely()); - return blast::GetQueryBatchSize(ProgramNameToEnum(GetTask()), m_IsUngapped, is_remote, false); + return blast::GetQueryBatchSize(eMapper, false, is_remote, true); } END_SCOPE(blast) diff --git a/c++/src/algo/blast/blastinput/psiblast_args.cpp b/c++/src/algo/blast/blastinput/psiblast_args.cpp index ee7e91e1..df34d0fb 100644 --- a/c++/src/algo/blast/blastinput/psiblast_args.cpp +++ b/c++/src/algo/blast/blastinput/psiblast_args.cpp @@ -1,4 +1,4 @@ -/* $Id: psiblast_args.cpp 516795 2016-10-18 14:21:21Z ivanov $ +/* $Id: psiblast_args.cpp 516751 2016-10-17 19:04:46Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/blastinput/rpsblast_args.cpp b/c++/src/algo/blast/blastinput/rpsblast_args.cpp index 677f1b2b..110d6839 100644 --- a/c++/src/algo/blast/blastinput/rpsblast_args.cpp +++ b/c++/src/algo/blast/blastinput/rpsblast_args.cpp @@ -1,4 +1,4 @@ -/* $Id: rpsblast_args.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: rpsblast_args.cpp 546749 2017-09-21 11:22:02Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -41,6 +41,24 @@ BEGIN_NCBI_SCOPE BEGIN_SCOPE(blast) USING_SCOPE(objects); +void +CRPSBlastMTArgs::SetArgumentDescriptions(CArgDescriptions& arg_desc) +{ + arg_desc.SetCurrentGroup("Miscellaneous options"); +#ifdef NCBI_THREADS + const int kDfltRpsThreadingMode = 1; + arg_desc.AddDefaultKey(kArgNumThreads, "int_value", + "Number of threads to use in RPS BLAST search:\n " + "0 (auto = num of databases)\n " + "1 (disable)\n max number of threads = num of databases", + CArgDescriptions::eInteger, + NStr::IntToString(kDfltRpsThreadingMode)); + arg_desc.SetConstraint(kArgNumThreads, + new CArgAllowValuesGreaterThanOrEqual(0)); +#endif + arg_desc.SetCurrentGroup(""); +} + CRPSBlastAppArgs::CRPSBlastAppArgs() { const bool kQueryIsProtein = true; @@ -86,7 +104,7 @@ CRPSBlastAppArgs::CRPSBlastAppArgs() arg.Reset(m_FormattingArgs); m_Args.push_back(arg); - m_MTArgs.Reset(new CMTArgs(true)); + m_MTArgs.Reset(new CRPSBlastMTArgs()); arg.Reset(m_MTArgs); m_Args.push_back(arg); diff --git a/c++/src/algo/blast/blastinput/unit_test/CMakeLists.blastinput_unit_test.app.txt b/c++/src/algo/blast/blastinput/unit_test/CMakeLists.blastinput_unit_test.app.txt new file mode 100644 index 00000000..b25efd1f --- /dev/null +++ b/c++/src/algo/blast/blastinput/unit_test/CMakeLists.blastinput_unit_test.app.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/blastinput/unit_test/Makefile.blastinput_unit_test.app +# +add_executable(blastinput_unit_test-app + blastinput_unit_test blast_scope_src_unit_test +) + +set_target_properties(blastinput_unit_test-app PROPERTIES OUTPUT_NAME blastinput_unit_test) + + + +target_link_libraries(blastinput_unit_test-app + blastinput entrez2cli test_boost +) + diff --git a/c++/src/algo/blast/blastinput/unit_test/CMakeLists.txt b/c++/src/algo/blast/blastinput/unit_test/CMakeLists.txt new file mode 100644 index 00000000..44393e9a --- /dev/null +++ b/c++/src/algo/blast/blastinput/unit_test/CMakeLists.txt @@ -0,0 +1,8 @@ +############################################################################## +# +# +include_directories(SYSTEM ${BOOST_INCLUDE}) + +# Include projects from this directory +include(CMakeLists.blastinput_unit_test.app.txt) + diff --git a/c++/src/algo/blast/blastinput/unit_test/blast_input_unit_test_aux.hpp b/c++/src/algo/blast/blastinput/unit_test/blast_input_unit_test_aux.hpp index c3957432..9ba84cc8 100644 --- a/c++/src/algo/blast/blastinput/unit_test/blast_input_unit_test_aux.hpp +++ b/c++/src/algo/blast/blastinput/unit_test/blast_input_unit_test_aux.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_input_unit_test_aux.hpp 516396 2016-10-13 12:26:43Z ivanov $ +/* $Id: blast_input_unit_test_aux.hpp 534442 2017-04-27 12:27:34Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,6 +34,7 @@ #define ALGO_BLAST_BLASTINPUT_UNITTEST__BLAST_INPUT_UNIT_TEST_AUX__HPP #include +#include #include /** @addtogroup AlgoBlast @@ -47,6 +48,8 @@ USING_NCBI_SCOPE; /// directory for the purpose of testing the CBlastScopeSource configuration /// class via this file (and override any other installed NCBI configuration /// files) +/// @note Works with unit tests only (via corelib/test_boost). +/// class CAutoNcbiConfigFile { public: static const char* kSection; @@ -57,11 +60,11 @@ public: typedef blast::SDataLoaderConfig::EConfigOpts EConfigOpts; CAutoNcbiConfigFile(EConfigOpts opts = blast::SDataLoaderConfig::eDefault) - : m_App(CNcbiApplication::Instance()), m_Registry(0) + : m_App(NcbiTestGetAppInstance()), m_Registry(0) { _ASSERT(m_App); m_App->ReloadConfig(CMetaRegistry::fAlwaysReload); - m_Registry = &m_App->GetConfig(); + m_Registry = &NcbiTestGetRWConfig(); _ASSERT(m_Registry); string value; diff --git a/c++/src/algo/blast/blastinput/unit_test/blast_scope_src_unit_test.cpp b/c++/src/algo/blast/blastinput/unit_test/blast_scope_src_unit_test.cpp index 7039430b..d22f1e9a 100644 --- a/c++/src/algo/blast/blastinput/unit_test/blast_scope_src_unit_test.cpp +++ b/c++/src/algo/blast/blastinput/unit_test/blast_scope_src_unit_test.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_scope_src_unit_test.cpp 516396 2016-10-13 12:26:43Z ivanov $ +/* $Id: blast_scope_src_unit_test.cpp 534442 2017-04-27 12:27:34Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(RetrieveFromDefaultBlastDb_NoNcbirc) for (size_t i = 0; i < sv.size(); i++) { BOOST_CHECK_EQUAL((char)seq[i], (char)sv[i]); } - app->GetConfig().IncludeNcbircIfAllowed(); + NcbiTestGetRWConfig().IncludeNcbircIfAllowed(); } // Motivated by JIRA WB-235 diff --git a/c++/src/algo/blast/blastinput/unit_test/blastinput_unit_test.cpp b/c++/src/algo/blast/blastinput/unit_test/blastinput_unit_test.cpp index f7d01eee..73ac3284 100644 --- a/c++/src/algo/blast/blastinput/unit_test/blastinput_unit_test.cpp +++ b/c++/src/algo/blast/blastinput/unit_test/blastinput_unit_test.cpp @@ -1,4 +1,4 @@ -/* $Id: blastinput_unit_test.cpp 517499 2016-10-25 17:20:41Z ivanov $ +/* $Id: blastinput_unit_test.cpp 548107 2017-10-10 17:30:08Z fukanchi $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -118,6 +118,7 @@ BOOST_AUTO_TEST_CASE(ReadAccession_MismatchNuclProt) } BOOST_REQUIRE(caught_exception); BOOST_REQUIRE(source->End() == true); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadAccession_MismatchProtNucl) @@ -144,6 +145,7 @@ BOOST_AUTO_TEST_CASE(ReadAccession_MismatchProtNucl) } BOOST_REQUIRE(caught_exception); BOOST_REQUIRE(source->End() == true); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadGi_MismatchNuclProt) @@ -170,6 +172,7 @@ BOOST_AUTO_TEST_CASE(ReadGi_MismatchNuclProt) } BOOST_REQUIRE(caught_exception); BOOST_REQUIRE(source->End() == true); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadGi_MismatchProtNucl) @@ -196,6 +199,7 @@ BOOST_AUTO_TEST_CASE(ReadGi_MismatchProtNucl) } BOOST_REQUIRE(caught_exception); BOOST_REQUIRE(source->End() == true); + scope.GetObjectManager().RevokeAllDataLoaders(); } struct SDubiousShortSequence @@ -262,6 +266,7 @@ BOOST_AUTO_TEST_CASE(TestSmallDubiousSequences) TSeqPos length = sequence::GetLength(*ssl.seqloc, ssl.scope); BOOST_REQUIRE_EQUAL(itr->GetLength(), length); + scope.GetObjectManager().RevokeAllDataLoaders(); } // Now check that these sequences will be rejected as being the wrong @@ -294,7 +299,9 @@ BOOST_AUTO_TEST_CASE(TestSmallDubiousSequences) } BOOST_REQUIRE(caught_exception == true); BOOST_REQUIRE(source->End() == true); + scope.GetObjectManager().RevokeAllDataLoaders(); } + } BOOST_AUTO_TEST_CASE(ReadFastaWithDefline_MismatchProtNucl) @@ -317,6 +324,7 @@ BOOST_AUTO_TEST_CASE(ReadFastaWithDefline_MismatchProtNucl) } BOOST_REQUIRE(caught_exception); BOOST_REQUIRE(source->End() == true); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadFastaWithDefline_MismatchNuclProt) @@ -339,6 +347,7 @@ BOOST_AUTO_TEST_CASE(ReadFastaWithDefline_MismatchNuclProt) } BOOST_REQUIRE(caught_exception); BOOST_REQUIRE(source->End() == true); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadFastaWithDeflineProtein_Single) @@ -370,6 +379,7 @@ BOOST_AUTO_TEST_CASE(ReadFastaWithDeflineProtein_Single) BOOST_REQUIRE_EQUAL(CSeq_id::e_Local, ssl.seqloc->GetInt().GetId().Which()); BOOST_REQUIRE(!ssl.mask); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(RawFastaWithSpaces) @@ -402,6 +412,7 @@ BOOST_AUTO_TEST_CASE(RawFastaWithSpaces) BOOST_REQUIRE_EQUAL(CSeq_id::e_Local, ssl.seqloc->GetInt().GetId().Which()); BOOST_REQUIRE(!ssl.mask); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadProteinWithGaps) @@ -445,6 +456,7 @@ BOOST_AUTO_TEST_CASE(ReadProteinWithGaps) for (size_t i = 0; i < seq.size(); i++) { BOOST_CHECK_NE('-', (char)seq[i]); } + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(RawFastaNoSpaces) @@ -480,6 +492,7 @@ BOOST_AUTO_TEST_CASE(RawFastaNoSpaces) BOOST_REQUIRE(bioseqs.NotEmpty()); BOOST_REQUIRE(!ssl.mask); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(RawFastaNoSpaces_UpperCaseWithN_ReadDeltaSeq) @@ -504,6 +517,7 @@ BOOST_AUTO_TEST_CASE(RawFastaNoSpaces_UpperCaseWithN_ReadDeltaSeq) BOOST_REQUIRE(bioseqs->GetSeq_set().front()->GetSeq().GetInst().CanGetRepr()); BOOST_REQUIRE(bioseqs->GetSeq_set().front()->GetSeq().GetInst().GetRepr() == CSeq_inst::eRepr_delta); + s.GetObjectManager().RevokeAllDataLoaders(); } @@ -547,6 +561,7 @@ BOOST_AUTO_TEST_CASE(ReadGenbankReport) BOOST_REQUIRE_EQUAL(CSeq_id::e_Local, ssl.seqloc->GetInt().GetId().Which()); BOOST_REQUIRE(!ssl.mask); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadInvalidGi) @@ -571,6 +586,7 @@ BOOST_AUTO_TEST_CASE(ReadInvalidGi) } BOOST_REQUIRE(caught_exception); BOOST_REQUIRE(source->End() == true); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadInvalidSeqId) @@ -594,6 +610,7 @@ BOOST_AUTO_TEST_CASE(ReadInvalidSeqId) } BOOST_REQUIRE(caught_exception); BOOST_REQUIRE(source->End() == true); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadBadUserInput) @@ -629,7 +646,7 @@ BOOST_AUTO_TEST_CASE(ReadBadUserInput) CObjReaderParseException); BOOST_REQUIRE(query_vector.Empty()); } - + scope.GetObjectManager().RevokeAllDataLoaders(); } /// This unit test proves that if one input is bad, all of them are rejected. @@ -655,6 +672,7 @@ BOOST_AUTO_TEST_CASE(ReadMultipleGis_WithBadInput) blast::TSeqLocVector seqs; BOOST_REQUIRE_THROW(seqs = source->GetAllSeqLocs(scope), CObjReaderParseException); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadEmptyUserInput) @@ -700,6 +718,7 @@ BOOST_AUTO_TEST_CASE(ReadEmptyUserInput) } BOOST_REQUIRE(caught_exception); } + scope.GetObjectManager().RevokeAllDataLoaders(); } // Basic test case to ensure CFastaReader changes don't break basic @@ -729,7 +748,7 @@ BOOST_AUTO_TEST_CASE(ReadSingleFasta_WithTitle) } } BOOST_REQUIRE_EQUAL(kExpectedTitle, title); - + scope.GetObjectManager().RevokeAllDataLoaders(); } static @@ -804,6 +823,7 @@ void s_ReadAndTestQueryFromString(const string& input, TSeqPos expected_length, string msg = CNcbiOstrstreamToString(oss); BOOST_REQUIRE_MESSAGE(input[input_pos] == (*sv)[pos], msg); } + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(SingleSequenceString_NoNewLineAfterSeq) @@ -918,6 +938,7 @@ BOOST_AUTO_TEST_CASE(ReadEmptyUserInput_OnlyTitle) } BOOST_REQUIRE(caught_exception); } + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadSingleAccession) @@ -966,6 +987,7 @@ BOOST_AUTO_TEST_CASE(ReadSingleAccession) BOOST_REQUIRE_EQUAL(CSeq_inst::eRepr_raw, b.GetInst().GetRepr()); BOOST_REQUIRE(CSeq_inst::IsNa(b.GetInst().GetMol())); BOOST_REQUIRE_EQUAL(length, b.GetInst().GetLength()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadSingleAccession_RetrieveLargeSequence) @@ -1001,9 +1023,18 @@ BOOST_AUTO_TEST_CASE(ReadSingleAccession_RetrieveLargeSequence) BOOST_REQUIRE(ssl.seqloc->GetInt().IsSetTo() == true); BOOST_REQUIRE_EQUAL(kStop, ssl.seqloc->GetInt().GetTo()); + const string accession = "NC_000001"; + const int version = 11; BOOST_REQUIRE(ssl.seqloc->GetInt().IsSetId() == true); - BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, ssl.seqloc->GetInt().GetId().Which()); - BOOST_REQUIRE_EQUAL(GI_CONST(kGi), ssl.seqloc->GetInt().GetId().GetGi()); + if ( !CSeq_id::PreferAccessionOverGi() ) { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, ssl.seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(GI_CONST(kGi), ssl.seqloc->GetInt().GetId().GetGi()); + } + else { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Other, ssl.seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(accession, ssl.seqloc->GetInt().GetId().GetOther().GetAccession()); + BOOST_REQUIRE_EQUAL(version, ssl.seqloc->GetInt().GetId().GetOther().GetVersion()); + } BOOST_REQUIRE(!ssl.mask); @@ -1014,7 +1045,6 @@ BOOST_AUTO_TEST_CASE(ReadSingleAccession_RetrieveLargeSequence) BOOST_REQUIRE(bioseqs->GetSeq_set().front()->IsSeq()); const CBioseq& b = bioseqs->GetSeq_set().front()->GetSeq(); BOOST_REQUIRE(b.IsNa()); - const string accession("NC_000001"); bool found_gi = false, found_accession = false; ITERATE(CBioseq::TId, id, b.GetId()) { if ((*id)->Which() == CSeq_id::e_Gi) { @@ -1034,6 +1064,7 @@ BOOST_AUTO_TEST_CASE(ReadSingleAccession_RetrieveLargeSequence) BOOST_REQUIRE_EQUAL(CSeq_inst::eRepr_delta, b.GetInst().GetRepr()); BOOST_REQUIRE(CSeq_inst::IsNa(b.GetInst().GetMol())); BOOST_REQUIRE_EQUAL(kStop+1, b.GetInst().GetLength()); + scope->GetObjectManager().RevokeAllDataLoaders(); } #ifdef _DEBUG const int kTimeOutLargeSeq = 60; @@ -1094,6 +1125,7 @@ BOOST_AUTO_TEST_CASE(ReadSingleAccession_RetrieveLargeSequenceWithRange) BOOST_REQUIRE(CSeq_inst::IsNa(b.GetInst().GetMol())); const TSeqPos length(248956422); BOOST_REQUIRE_EQUAL(length, b.GetInst().GetLength()); + scope->GetObjectManager().RevokeAllDataLoaders(); } #ifdef _DEBUG const int kTimeOutLargeSeqWithRange = 60; @@ -1162,6 +1194,7 @@ BOOST_AUTO_TEST_CASE(ReadMultipleAccessions) /// Validate the data that would be retrieved by blast.cgi CRef bioseqs = TSeqLocVector2Bioseqs(query_vector); BOOST_REQUIRE_EQUAL(kNumQueries, bioseqs->GetSeq_set().size()); + scope.GetObjectManager().RevokeAllDataLoaders(); } // This test was created to test issues in jira/browse/CXX-82 @@ -1223,6 +1256,7 @@ BOOST_AUTO_TEST_CASE(ReadMultipleAccessionsFromMemory) /// Validate the data that would be retrieved by blast.cgi CRef bioseqs = TSeqLocVector2Bioseqs(query_vector); BOOST_REQUIRE_EQUAL(kNumQueries, bioseqs->GetSeq_set().size()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadSingleGi) @@ -1270,6 +1304,7 @@ BOOST_AUTO_TEST_CASE(ReadSingleGi) BOOST_REQUIRE_EQUAL(CSeq_inst::eRepr_raw, b.GetInst().GetRepr()); BOOST_REQUIRE(CSeq_inst::IsNa(b.GetInst().GetMol())); BOOST_REQUIRE_EQUAL(length, b.GetInst().GetLength()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadMultipleGis) @@ -1331,6 +1366,7 @@ BOOST_AUTO_TEST_CASE(ReadMultipleGis) BOOST_REQUIRE(CSeq_inst::IsNa(b.GetInst().GetMol())); BOOST_REQUIRE_EQUAL((long)gi_length[i].second, (long)b.GetInst().GetLength()); } + scope.GetObjectManager().RevokeAllDataLoaders(); } // This input file contains very short sequences (1-3 bases) which were product @@ -1349,6 +1385,7 @@ BOOST_AUTO_TEST_CASE(ReadMultipleSequencesFromSequencer) blast::TSeqLocVector query_vector = source->GetAllSeqLocs(scope); BOOST_REQUIRE_EQUAL(kNumQueries, query_vector.size()); BOOST_REQUIRE(blast::IsLocalId(query_vector.front().seqloc->GetId())); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadMultipleSequencesFromSequencerParseLocalIds) @@ -1371,6 +1408,7 @@ BOOST_AUTO_TEST_CASE(ReadMultipleSequencesFromSequencerParseLocalIds) BOOST_REQUIRE_EQUAL(query_vector[0].seqloc->GetId()->AsFastaString(), string("lcl|seq#474_A03_564_c_T3+40.ab1")); BOOST_REQUIRE_EQUAL(query_vector[1].seqloc->GetId()->AsFastaString(), string("lcl|seq#474_A01_564_a_T3+40.ab1")); BOOST_REQUIRE_EQUAL(query_vector[2].seqloc->GetId()->AsFastaString(), string("lcl|seq#474_A02_564_b_T3+40.ab1")); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadSequenceWithlclID) @@ -1387,6 +1425,7 @@ BOOST_AUTO_TEST_CASE(ReadSequenceWithlclID) BOOST_REQUIRE(blast::IsLocalId(query_vector.front().seqloc->GetId())); // Check that the local ID went through. BOOST_REQUIRE_EQUAL(query_vector[0].seqloc->GetId()->AsFastaString(), string("lcl|mylocalID555")); + scope.GetObjectManager().RevokeAllDataLoaders(); } // This input file contains several sequences in FASTA format, but one of them @@ -1425,6 +1464,7 @@ BOOST_AUTO_TEST_CASE(ReadMultipleSequences_OneEmpty) CheckForEmptySequences(bioseqs, warnings); BOOST_REQUIRE(warnings.find("following sequences had no sequence data:") != NPOS); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadMultipleTis) @@ -1477,6 +1517,7 @@ BOOST_AUTO_TEST_CASE(ReadMultipleTis) /// Validate the data that would be retrieved by blast.cgi CRef bioseqs = TSeqLocVector2Bioseqs(query_vector); BOOST_REQUIRE_EQUAL(kNumQueries, bioseqs->GetSeq_set().size()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadSingleTi) @@ -1529,6 +1570,7 @@ BOOST_AUTO_TEST_CASE(ReadSingleTi) BOOST_REQUIRE_EQUAL(CSeq_inst::eRepr_raw, b.GetInst().GetRepr()); BOOST_REQUIRE(CSeq_inst::IsNa(b.GetInst().GetMol())); BOOST_REQUIRE_EQUAL(length, b.GetInst().GetLength()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadAccessionsAndGisWithNewLines) @@ -1614,6 +1656,7 @@ BOOST_AUTO_TEST_CASE(ReadAccessionsAndGisWithNewLines) /// Validate the data that would be retrieved by blast.cgi CRef bioseqs = TSeqLocVector2Bioseqs(query_vector); BOOST_REQUIRE_EQUAL(kNumQueries, bioseqs->GetSeq_set().size()); + scope.GetObjectManager().RevokeAllDataLoaders(); } static string* @@ -1680,6 +1723,7 @@ BOOST_AUTO_TEST_CASE(ReadAccessionNucleotideIntoBuffer_Single) BOOST_REQUIRE_EQUAL(CSeq_inst::eRepr_raw, b.GetInst().GetRepr()); BOOST_REQUIRE(CSeq_inst::IsNa(b.GetInst().GetMol())); BOOST_REQUIRE_EQUAL(length, b.GetInst().GetLength()); + scope.GetObjectManager().RevokeAllDataLoaders(); } @@ -1714,9 +1758,20 @@ BOOST_AUTO_TEST_CASE(ReadGiNuclWithFlankingSpacesIntoBuffer_Single) BOOST_REQUIRE(ssl.seqloc->GetInt().IsSetId() == true); BOOST_REQUIRE( !blast::IsLocalId(ssl.seqloc->GetId()) ); - BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, ssl.seqloc->GetInt().GetId().Which()); const TGi gi = GI_CONST(1945386); - BOOST_REQUIRE_EQUAL(gi, ssl.seqloc->GetInt().GetId().GetGi()); + const string gb_name = "HSU93236"; + const string gb_accession = "U93236"; + const int gb_version = 1; + if ( !CSeq_id::PreferAccessionOverGi() ) { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, ssl.seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(gi, ssl.seqloc->GetInt().GetId().GetGi()); + } + else { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Genbank, ssl.seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(gb_name, ssl.seqloc->GetInt().GetId().GetGenbank().GetName()); + BOOST_REQUIRE_EQUAL(gb_accession, ssl.seqloc->GetInt().GetId().GetGenbank().GetAccession()); + BOOST_REQUIRE_EQUAL(gb_version, ssl.seqloc->GetInt().GetId().GetGenbank().GetVersion()); + } BOOST_REQUIRE(!ssl.mask); @@ -1729,11 +1784,20 @@ BOOST_AUTO_TEST_CASE(ReadGiNuclWithFlankingSpacesIntoBuffer_Single) CRef id = FindBestChoice(b.GetId(), CSeq_id::BestRank); BOOST_REQUIRE(id.NotNull()); - BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, id->Which()); - BOOST_REQUIRE_EQUAL(gi, id->GetGi()); + if ( !CSeq_id::PreferAccessionOverGi() ) { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, id->Which()); + BOOST_REQUIRE_EQUAL(gi, id->GetGi()); + } + else { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Genbank, id->Which()); + BOOST_REQUIRE_EQUAL(gb_name, id->GetGenbank().GetName()); + BOOST_REQUIRE_EQUAL(gb_accession, id->GetGenbank().GetAccession()); + BOOST_REQUIRE_EQUAL(gb_version, id->GetGenbank().GetVersion()); + } BOOST_REQUIRE_EQUAL(CSeq_inst::eRepr_raw, b.GetInst().GetRepr()); BOOST_REQUIRE(CSeq_inst::IsNa(b.GetInst().GetMol())); BOOST_REQUIRE_EQUAL(length, b.GetInst().GetLength()); + scope.GetObjectManager().RevokeAllDataLoaders(); } @@ -1767,9 +1831,19 @@ BOOST_AUTO_TEST_CASE(ReadAccessionNuclWithFlankingSpacesIntoBuffer_Single) BOOST_REQUIRE(ssl.seqloc->GetInt().IsSetId() == true); BOOST_REQUIRE( !blast::IsLocalId(ssl.seqloc->GetId()) ); - BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, ssl.seqloc->GetInt().GetId().Which()); - const string accession("X65215.1"); - BOOST_REQUIRE_EQUAL(GI_CONST(555), ssl.seqloc->GetInt().GetId().GetGi()); + + const TGi gi = GI_CONST(555); + const string accession = "X65215"; + const int version = 1; + if ( !CSeq_id::PreferAccessionOverGi() ) { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, ssl.seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(gi, ssl.seqloc->GetInt().GetId().GetGi()); + } + else { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Embl, ssl.seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(accession, ssl.seqloc->GetInt().GetId().GetEmbl().GetAccession()); + BOOST_REQUIRE_EQUAL(version, ssl.seqloc->GetInt().GetId().GetEmbl().GetVersion()); + } BOOST_REQUIRE(!ssl.mask); @@ -1797,7 +1871,7 @@ BOOST_AUTO_TEST_CASE(ReadAccessionNuclWithFlankingSpacesIntoBuffer_Single) BOOST_REQUIRE_EQUAL(CSeq_inst::eRepr_raw, b.GetInst().GetRepr()); BOOST_REQUIRE(CSeq_inst::IsNa(b.GetInst().GetMol())); BOOST_REQUIRE_EQUAL(length, b.GetInst().GetLength()); - + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadFastaWithDeflineProteinIntoBuffer_Single) @@ -1843,6 +1917,7 @@ BOOST_AUTO_TEST_CASE(ReadFastaWithDeflineProteinIntoBuffer_Single) BOOST_REQUIRE_EQUAL(CSeq_inst::eRepr_raw, b.GetInst().GetRepr()); BOOST_REQUIRE_EQUAL(CSeq_inst::eMol_aa, b.GetInst().GetMol()); BOOST_REQUIRE_EQUAL(length, b.GetInst().GetLength()); + scope.GetObjectManager().RevokeAllDataLoaders(); } @@ -1864,6 +1939,7 @@ BOOST_AUTO_TEST_CASE(RangeBoth) BOOST_REQUIRE_EQUAL(stop, ssl.seqloc->GetInt().GetTo()); BOOST_REQUIRE_EQUAL(start, ssl.seqloc->GetStart(eExtreme_Positional)); BOOST_REQUIRE_EQUAL(stop, ssl.seqloc->GetStop(eExtreme_Positional)); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(RangeStartOnly) @@ -1883,6 +1959,7 @@ BOOST_AUTO_TEST_CASE(RangeStartOnly) BOOST_REQUIRE_EQUAL(length-1, ssl.seqloc->GetInt().GetTo()); BOOST_REQUIRE_EQUAL(start, ssl.seqloc->GetStart(eExtreme_Positional)); BOOST_REQUIRE_EQUAL(length-1, ssl.seqloc->GetStop(eExtreme_Positional)); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(RangeInvalid_FromGreaterThanTo) @@ -1903,6 +1980,7 @@ BOOST_AUTO_TEST_CASE(RangeInvalid_FromGreaterThanTo) return; } BOOST_REQUIRE(false); // should never get here + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(RangeInvalid_FromGreaterThanSequenceLength) @@ -1922,6 +2000,7 @@ BOOST_AUTO_TEST_CASE(RangeInvalid_FromGreaterThanSequenceLength) return; } BOOST_REQUIRE(false); // should never get here + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(RangeInvalid_ToEqualThanSequenceLength) @@ -1947,6 +2026,7 @@ BOOST_AUTO_TEST_CASE(RangeInvalid_ToEqualThanSequenceLength) BOOST_REQUIRE(ssl.seqloc->GetInt().IsSetTo() == true); BOOST_REQUIRE_EQUAL(length-1, ssl.seqloc->GetInt().GetTo()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(RangeInvalid_ToGreaterThanSequenceLength) @@ -1972,6 +2052,7 @@ BOOST_AUTO_TEST_CASE(RangeInvalid_ToGreaterThanSequenceLength) BOOST_REQUIRE(ssl.seqloc->GetInt().IsSetTo() == true); BOOST_REQUIRE_EQUAL(length-1, ssl.seqloc->GetInt().GetTo()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ParseDefline) @@ -1984,12 +2065,29 @@ BOOST_AUTO_TEST_CASE(ParseDefline) CScope scope(*CObjectManager::GetInstance()); const TGi gi = GI_CONST(129295); + const string name = "OVAX_CHICK"; + const string accession = "P01013"; + const string release = "reviewed"; blast::SSeqLoc ssl = source->GetNextSeqLocBatch(scope).front(); - BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, ssl.seqloc->GetId()->Which()); - BOOST_REQUIRE_EQUAL(gi, ssl.seqloc->GetId()->GetGi()); - BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, ssl.seqloc->GetInt().GetId().Which()); - BOOST_REQUIRE_EQUAL(gi, ssl.seqloc->GetInt().GetId().GetGi()); BOOST_REQUIRE( !blast::IsLocalId(ssl.seqloc->GetId()) ); + + if ( !CSeq_id::PreferAccessionOverGi() ) { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, ssl.seqloc->GetId()->Which()); + BOOST_REQUIRE_EQUAL(gi, ssl.seqloc->GetId()->GetGi()); + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, ssl.seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(gi, ssl.seqloc->GetInt().GetId().GetGi()); + } + else { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Swissprot, ssl.seqloc->GetId()->Which()); + BOOST_REQUIRE_EQUAL(name, ssl.seqloc->GetId()->GetSwissprot().GetName()); + BOOST_REQUIRE_EQUAL(accession, ssl.seqloc->GetId()->GetSwissprot().GetAccession()); + BOOST_REQUIRE_EQUAL(release, ssl.seqloc->GetId()->GetSwissprot().GetRelease()); + BOOST_REQUIRE_EQUAL(CSeq_id::e_Swissprot, ssl.seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(name, ssl.seqloc->GetInt().GetId().GetSwissprot().GetName()); + BOOST_REQUIRE_EQUAL(accession, ssl.seqloc->GetInt().GetId().GetSwissprot().GetAccession()); + BOOST_REQUIRE_EQUAL(release, ssl.seqloc->GetInt().GetId().GetSwissprot().GetRelease()); + } + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(BadProtStrand) @@ -2012,6 +2110,7 @@ BOOST_AUTO_TEST_CASE(BadProtStrand) } BOOST_REQUIRE(caught_exception); BOOST_REQUIRE(source->End() == true); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadFastaWithDeflineNucl_Multiple) @@ -2052,6 +2151,7 @@ BOOST_AUTO_TEST_CASE(ReadFastaWithDeflineNucl_Multiple) BOOST_REQUIRE_EQUAL(length-1, ssl.seqloc->GetInt().GetTo()); BOOST_REQUIRE(blast::IsLocalId(ssl.seqloc->GetId())); BOOST_REQUIRE(!ssl.mask); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(NuclStrand) @@ -2092,6 +2192,7 @@ BOOST_AUTO_TEST_CASE(NuclStrand) BOOST_REQUIRE(blast::IsLocalId(ssl.seqloc->GetId())); } } + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(NuclLcaseMask_TSeqLocVector) @@ -2129,6 +2230,7 @@ BOOST_AUTO_TEST_CASE(NuclLcaseMask_TSeqLocVector) ssl = *++itr; BOOST_REQUIRE(ssl.mask); BOOST_REQUIRE(ssl.mask->IsNull()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(NuclLcaseMask_BlastQueryVector) @@ -2180,6 +2282,7 @@ BOOST_AUTO_TEST_CASE(NuclLcaseMask_BlastQueryVector) query = (*seqs)[1]; BOOST_REQUIRE(query->GetMaskedRegions().empty()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(MultiSeq) @@ -2193,6 +2296,7 @@ BOOST_AUTO_TEST_CASE(MultiSeq) blast::TSeqLocVector v = source->GetAllSeqLocs(scope); BOOST_REQUIRE(source->End()); BOOST_REQUIRE_EQUAL((size_t)19, v.size()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(MultiRange) @@ -2213,6 +2317,7 @@ BOOST_AUTO_TEST_CASE(MultiRange) BOOST_REQUIRE_EQUAL(start, itr->seqloc->GetInt().GetFrom()); BOOST_REQUIRE_EQUAL(stop, itr->seqloc->GetInt().GetTo()); } + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(MultiBatch) @@ -2231,27 +2336,79 @@ BOOST_AUTO_TEST_CASE(MultiBatch) BOOST_REQUIRE_EQUAL((size_t)7, v.size()); BOOST_REQUIRE_EQUAL((TSeqPos)530, v[0].seqloc->GetInt().GetTo()); gi = GI_CONST(1346057); + string name = "G11A_ORYSA"; + string accession = "P47997"; + string release = "reviewed"; BOOST_REQUIRE( !blast::IsLocalId(v[0].seqloc->GetId()) ); - BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetInt().GetId().GetGi()); - BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetId()->GetGi()); + if ( !CSeq_id::PreferAccessionOverGi() ) { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, v[0].seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetInt().GetId().GetGi()); + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, v[0].seqloc->GetId()->Which()); + BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetId()->GetGi()); + } + else { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Swissprot, v[0].seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(name, v[0].seqloc->GetInt().GetId().GetSwissprot().GetName()); + BOOST_REQUIRE_EQUAL(accession, v[0].seqloc->GetInt().GetId().GetSwissprot().GetAccession()); + BOOST_REQUIRE_EQUAL(release, v[0].seqloc->GetInt().GetId().GetSwissprot().GetRelease()); + BOOST_REQUIRE_EQUAL(CSeq_id::e_Swissprot, v[0].seqloc->GetId()->Which()); + BOOST_REQUIRE_EQUAL(name, v[0].seqloc->GetId()->GetSwissprot().GetName()); + BOOST_REQUIRE_EQUAL(accession, v[0].seqloc->GetId()->GetSwissprot().GetAccession()); + BOOST_REQUIRE_EQUAL(release, v[0].seqloc->GetId()->GetSwissprot().GetRelease()); + } v = source->GetNextSeqLocBatch(scope); BOOST_REQUIRE_EQUAL((size_t)8, v.size()); BOOST_REQUIRE_EQUAL((TSeqPos)445, v[0].seqloc->GetInt().GetTo()); gi = GI_CONST(1170625); + name = "KCC1_YEAST"; + accession = "P27466"; + release = "reviewed"; BOOST_REQUIRE( !blast::IsLocalId(v[0].seqloc->GetId()) ); - BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetInt().GetId().GetGi()); - BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetId()->GetGi()); + if ( !CSeq_id::PreferAccessionOverGi() ) { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, v[0].seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetInt().GetId().GetGi()); + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, v[0].seqloc->GetId()->Which()); + BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetId()->GetGi()); + } + else { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Swissprot, v[0].seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(name, v[0].seqloc->GetInt().GetId().GetSwissprot().GetName()); + BOOST_REQUIRE_EQUAL(accession, v[0].seqloc->GetInt().GetId().GetSwissprot().GetAccession()); + BOOST_REQUIRE_EQUAL(release, v[0].seqloc->GetInt().GetId().GetSwissprot().GetRelease()); + BOOST_REQUIRE_EQUAL(CSeq_id::e_Swissprot, v[0].seqloc->GetId()->Which()); + BOOST_REQUIRE_EQUAL(name, v[0].seqloc->GetId()->GetSwissprot().GetName()); + BOOST_REQUIRE_EQUAL(accession, v[0].seqloc->GetId()->GetSwissprot().GetAccession()); + BOOST_REQUIRE_EQUAL(release, v[0].seqloc->GetId()->GetSwissprot().GetRelease()); + } v = source->GetNextSeqLocBatch(scope); BOOST_REQUIRE_EQUAL((size_t)4, v.size()); BOOST_REQUIRE_EQUAL((TSeqPos)688, v[0].seqloc->GetInt().GetTo()); gi = GI_CONST(114152); + name = "ARK1_HUMAN"; + accession = "P25098"; + release = "reviewed"; BOOST_REQUIRE( !blast::IsLocalId(v[0].seqloc->GetId()) ); - BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetInt().GetId().GetGi()); - BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetId()->GetGi()); + if ( !CSeq_id::PreferAccessionOverGi() ) { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, v[0].seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetInt().GetId().GetGi()); + BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, v[0].seqloc->GetId()->Which()); + BOOST_REQUIRE_EQUAL(gi, v[0].seqloc->GetId()->GetGi()); + } + else { + BOOST_REQUIRE_EQUAL(CSeq_id::e_Swissprot, v[0].seqloc->GetInt().GetId().Which()); + BOOST_REQUIRE_EQUAL(name, v[0].seqloc->GetInt().GetId().GetSwissprot().GetName()); + BOOST_REQUIRE_EQUAL(accession, v[0].seqloc->GetInt().GetId().GetSwissprot().GetAccession()); + BOOST_REQUIRE_EQUAL(release, v[0].seqloc->GetInt().GetId().GetSwissprot().GetRelease()); + BOOST_REQUIRE_EQUAL(CSeq_id::e_Swissprot, v[0].seqloc->GetId()->Which()); + BOOST_REQUIRE_EQUAL(name, v[0].seqloc->GetId()->GetSwissprot().GetName()); + BOOST_REQUIRE_EQUAL(accession, v[0].seqloc->GetId()->GetSwissprot().GetAccession()); + BOOST_REQUIRE_EQUAL(release, v[0].seqloc->GetId()->GetSwissprot().GetRelease()); + } BOOST_REQUIRE(source->End()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(NoDeflineExpected) @@ -2265,6 +2422,7 @@ BOOST_AUTO_TEST_CASE(NoDeflineExpected) blast::TSeqLocVector v = source->GetAllSeqLocs(scope); BOOST_REQUIRE(source->End()); BOOST_REQUIRE_EQUAL((size_t)1, v.size()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(NoDeflineUnexpected) @@ -2277,6 +2435,7 @@ BOOST_AUTO_TEST_CASE(NoDeflineUnexpected) CScope scope(*CObjectManager::GetInstance()); BOOST_REQUIRE_THROW(source->GetAllSeqLocs(scope), CException); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(wb325_1) { string input("gb|ABZI01000088\ngb|ABZN01000067"); @@ -2293,6 +2452,7 @@ BOOST_AUTO_TEST_CASE(wb325_1) { BOOST_REQUIRE(source->End() == true); BOOST_REQUIRE_EQUAL(2u, seqs.size()); //blast::SSeqLoc ssl = seqs.front(); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(wb325_2) @@ -2311,6 +2471,7 @@ BOOST_AUTO_TEST_CASE(wb325_2) BOOST_REQUIRE(source->End() == true); BOOST_REQUIRE_EQUAL(2u, seqs.size()); //blast::SSeqLoc ssl = seqs.front(); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(wb325_single1) @@ -2330,6 +2491,7 @@ BOOST_AUTO_TEST_CASE(wb325_single1) BOOST_REQUIRE(source->End() == true); BOOST_REQUIRE_EQUAL(1u, seqs.size()); //blast::SSeqLoc ssl = seqs.front(); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(wb325_single2) @@ -2349,6 +2511,7 @@ BOOST_AUTO_TEST_CASE(wb325_single2) BOOST_REQUIRE(source->End() == true); BOOST_REQUIRE_EQUAL(1u, seqs.size()); //blast::SSeqLoc ssl = seqs.front(); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadSinglePdb) @@ -2400,6 +2563,7 @@ BOOST_AUTO_TEST_CASE(ReadSinglePdb) BOOST_REQUIRE_EQUAL(CSeq_inst::eRepr_raw, b.GetInst().GetRepr()); BOOST_REQUIRE(! CSeq_inst::IsNa(b.GetInst().GetMol())); BOOST_REQUIRE_EQUAL(length, b.GetInst().GetLength()); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ThrowOnEmptySequence) @@ -2413,6 +2577,7 @@ BOOST_AUTO_TEST_CASE(ThrowOnEmptySequence) CRef source(s_DeclareBlastInput(instream, iconfig)); CScope scope(*CObjectManager::GetInstance()); BOOST_REQUIRE_THROW(source->GetAllSeqLocs(scope), CInputException); + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(FetchSraID) @@ -2478,6 +2643,7 @@ BOOST_AUTO_TEST_CASE(FetchSraID) BOOST_CHECK_MESSAGE((char)sv[i] == kSeqData[i], msg); BOOST_CHECK_NE('-', (char)seq[i]); } + scope.GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(ReadSinglePdb_InDifferentFormats) @@ -2537,7 +2703,9 @@ BOOST_AUTO_TEST_CASE(ReadSinglePdb_InDifferentFormats) BOOST_REQUIRE_EQUAL(CSeq_inst::eRepr_raw, b.GetInst().GetRepr()); BOOST_REQUIRE(! CSeq_inst::IsNa(b.GetInst().GetMol())); BOOST_REQUIRE_EQUAL(length, b.GetInst().GetLength()); + scope.GetObjectManager().RevokeAllDataLoaders(); } + } BOOST_AUTO_TEST_CASE(RawFastaNoSpaces_UpperCaseWithN) @@ -2580,7 +2748,7 @@ BOOST_AUTO_TEST_CASE(RawFastaNoSpaces_UpperCaseWithN) BOOST_REQUIRE(bioseqs->GetSeq_set().front()->GetSeq().GetInst().CanGetRepr()); BOOST_REQUIRE_EQUAL(CSeq_inst::eRepr_raw, bioseqs->GetSeq_set().front()->GetSeq().GetInst().GetRepr()); - + scope.GetObjectManager().RevokeAllDataLoaders(); } template @@ -2632,7 +2800,7 @@ BOOST_AUTO_TEST_CASE(ParseSequenceRange_1BasedRange) { TSeqRange r = ParseSequenceRange("1-10"); BOOST_REQUIRE_EQUAL(0U, r.GetFrom()); BOOST_REQUIRE_EQUAL(9U, r.GetTo()); - BOOST_REQUIRE_EQUAL(10U, r.GetToOpen()); + BOOST_REQUIRE_EQUAL(10U, r.GetToOpen()); } BOOST_AUTO_TEST_CASE(CheckQueryBatchSize) { @@ -2643,7 +2811,8 @@ BOOST_AUTO_TEST_CASE(CheckQueryBatchSize) { // Test case for WB-1304: save GI (i.e.: best ranked Seq-id) if available BOOST_AUTO_TEST_CASE(FetchGiFromAccessionInput) { - const CSeq_id gi(CSeq_id::e_Gi, 568802206); + const CSeq_id id(CSeq_id::PreferAccessionOverGi() ? + "ref|NT_026437.13|" : "gi|568802206"); const string input("NT_026437.13"); typedef vector > TVecOpts; TVecOpts opts; @@ -2652,6 +2821,9 @@ BOOST_AUTO_TEST_CASE(FetchGiFromAccessionInput) ITERATE(TVecOpts, config, opts) { CAutoNcbiConfigFile acf(config->first); blast::SDataLoaderConfig dlconfig(false); + if(config->second == "BLASTDB") { + dlconfig.m_BlastDbName = "refseq_genomic"; + } dlconfig.OptimizeForWholeLargeSequenceRetrieval(); blast::CBlastInputSourceConfig input_config(dlconfig); // this needs to be omitted for this test to work @@ -2662,14 +2834,16 @@ BOOST_AUTO_TEST_CASE(FetchGiFromAccessionInput) CRef scope = CBlastScopeSource(dlconfig).NewScope(); TSeqLocVector query_loc = blast_input.GetAllSeqLocs(*scope); BOOST_REQUIRE_EQUAL(1U, query_loc.size()); - if (gi.AsFastaString() != query_loc[0].seqloc->GetId()->AsFastaString()) { - BOOST_CHECK_EQUAL(gi.AsFastaString(), - query_loc[0].seqloc->GetId()->AsFastaString()); - BOOST_CHECK_MESSAGE(gi.AsFastaString() == - query_loc[0].seqloc->GetId()->AsFastaString(), - "Failed using " + config->second + " data loader"); + string fasta_id = id.AsFastaString(); + string fasta_query = query_loc[0].seqloc->GetId()->AsFastaString(); + if (fasta_id != fasta_query) { + BOOST_CHECK_EQUAL(fasta_id, fasta_query); + BOOST_CHECK_MESSAGE(fasta_id == fasta_query, + "Failed using " + config->second + " data loader"); } + scope->GetObjectManager().RevokeAllDataLoaders(); } + } @@ -2703,30 +2877,53 @@ static int s_GetSegmentFlags(const CBioseq& bioseq) return retval; } -BOOST_AUTO_TEST_CASE(TestFlagsForPairedReadsFromFasta) { +static string s_GetSequenceId(const CBioseq& bioseq) +{ + string retval; + if (bioseq.IsSetDescr()) { + for (auto it: bioseq.GetDescr().Get()) { + if (it->IsTitle()) { + vector tokens; + NStr::Split(it->GetTitle(), " ", tokens); + retval = (string)"lcl|" + tokens[0]; + } + } + } + + if (retval.empty()) { + retval = bioseq.GetFirstId()->AsFastaString(); + } + + return retval; +} + + +BOOST_AUTO_TEST_CASE(TestPairedReadsFromFasta) { CNcbiIfstream istr("data/paired_reads.fa"); BOOST_REQUIRE(istr); unordered_map ref_flags = { {"lcl|pair1", eFirstSegment}, {"lcl|pair2", eLastSegment}, - {"lcl|incomplete1.1", fFirstSegmentFlag | fPartialFlag}, - {"lcl|incomplete2.2", fLastSegmentFlag | fPartialFlag} + {"lcl|incomplete1.1", eFirstSegment}, + {"lcl|incomplete1.2", eLastSegment}, + {"lcl|incomplete2.1", eFirstSegment}, + {"lcl|incomplete2.2", eLastSegment}, }; - CShortReadFastaInputSource input_source(istr, 1000, - CShortReadFastaInputSource::eFasta, - true, true); + + CShortReadFastaInputSource input_source(istr, + CShortReadFastaInputSource::eFasta, + true); + CBlastInputOMF input(&input_source, 1000); CRef queries(new CBioseq_set); - input_source.GetNextNumSequences(*queries, 0); - // input file contains six sequences, but two should have been rejected - // in screening - BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 4u); + input.GetNextSeqBatch(*queries); + BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 6u); size_t count = 0; for (auto it : queries->GetSeq_set()) { - string id = it->GetSeq().GetFirstId()->AsFastaString(); + string id = s_GetSequenceId(it->GetSeq()); int flags = s_GetSegmentFlags(it->GetSeq()); int expected = ref_flags.at(id); @@ -2740,7 +2937,7 @@ BOOST_AUTO_TEST_CASE(TestFlagsForPairedReadsFromFasta) { BOOST_REQUIRE_EQUAL(ref_flags.size(), count); } -BOOST_AUTO_TEST_CASE(TestPairedFlagsForPairedReadsFromTwoFastaFiles) { +BOOST_AUTO_TEST_CASE(TestPairedReadsFromTwoFastaFiles) { CNcbiIfstream istr1("data/paired_reads_1.fa"); CNcbiIfstream istr2("data/paired_reads_2.fa"); @@ -2749,23 +2946,24 @@ BOOST_AUTO_TEST_CASE(TestPairedFlagsForPairedReadsFromTwoFastaFiles) { unordered_map ref_flags = { {"lcl|pair1", eFirstSegment}, {"lcl|pair2", eLastSegment}, - {"lcl|incomplete1.1", fFirstSegmentFlag | fPartialFlag}, - {"lcl|incomplete2.2", fLastSegmentFlag | fPartialFlag} + {"lcl|incomplete1.1", eFirstSegment}, + {"lcl|incomplete1.2", eLastSegment}, + {"lcl|incomplete2.1", eFirstSegment}, + {"lcl|incomplete2.2", eLastSegment}, }; - CShortReadFastaInputSource input_source(istr1, istr2, 1000, - CShortReadFastaInputSource::eFasta, - true); + CShortReadFastaInputSource input_source(istr1, istr2, + CShortReadFastaInputSource::eFasta); + + CBlastInputOMF input(&input_source, 1000); CRef queries(new CBioseq_set); - input_source.GetNextNumSequences(*queries, 0); - // input file contains six sequences, but two should have been rejected - // in screening - BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 4u); + input.GetNextSeqBatch(*queries); + BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 6u); size_t count = 0; for (auto it : queries->GetSeq_set()) { - string id = it->GetSeq().GetFirstId()->AsFastaString(); + string id = s_GetSequenceId(it->GetSeq()); int flags = s_GetSegmentFlags(it->GetSeq()); int expected = ref_flags.at(id); @@ -2779,24 +2977,23 @@ BOOST_AUTO_TEST_CASE(TestPairedFlagsForPairedReadsFromTwoFastaFiles) { BOOST_REQUIRE_EQUAL(ref_flags.size(), count); } -BOOST_AUTO_TEST_CASE(TestPairedFlagsForSingleReadsFromFasta) { +BOOST_AUTO_TEST_CASE(TestSingleReadsFromFasta) { CNcbiIfstream istr("data/paired_reads.fa"); - CShortReadFastaInputSource input_source(istr, 1000, - CShortReadFastaInputSource::eFasta, - false, true); + CShortReadFastaInputSource input_source(istr, + CShortReadFastaInputSource::eFasta, + false); + CBlastInputOMF input(&input_source, 1000); CRef queries(new CBioseq_set); - input_source.GetNextNumSequences(*queries, 0); - // input file contains six sequences, but two should have been rejected - // in screening - BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 4u); + input.GetNextSeqBatch(*queries); + BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 6u); size_t count = 0; for (auto it : queries->GetSeq_set()) { if (it->GetSeq().IsSetDescr()) { - string id = it->GetSeq().GetFirstId()->AsFastaString(); + string id = s_GetSequenceId(it->GetSeq()); int flags = s_GetSegmentFlags(it->GetSeq()); int expected = 0; @@ -2809,33 +3006,34 @@ BOOST_AUTO_TEST_CASE(TestPairedFlagsForSingleReadsFromFasta) { count++; } - BOOST_REQUIRE_EQUAL(4u, count); + BOOST_REQUIRE_EQUAL(6u, count); } -BOOST_AUTO_TEST_CASE(TestFlagsForPairedReadsFromFastQ) { +BOOST_AUTO_TEST_CASE(TestPairedReadsFromFastQ) { CNcbiIfstream istr("data/paired_reads.fastq"); BOOST_REQUIRE(istr); unordered_map ref_flags = { {"lcl|pair1", eFirstSegment}, {"lcl|pair2", eLastSegment}, - {"lcl|incomplete1.1", fFirstSegmentFlag | fPartialFlag}, - {"lcl|incomplete2.2", fLastSegmentFlag | fPartialFlag} + {"lcl|incomplete1.1", eFirstSegment}, + {"lcl|incomplete1.2", eLastSegment}, + {"lcl|incomplete2.1", eFirstSegment}, + {"lcl|incomplete2.2", eLastSegment}, }; - CShortReadFastaInputSource input_source(istr, 1000, - CShortReadFastaInputSource::eFastq, - true, true); + CShortReadFastaInputSource input_source(istr, + CShortReadFastaInputSource::eFastq, + true); + CBlastInputOMF input(&input_source, 1000); CRef queries(new CBioseq_set); - input_source.GetNextNumSequences(*queries, 0); - // input file contains six sequences, but two should have been rejected - // in screening - BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 4u); + input.GetNextSeqBatch(*queries); + BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 6u); size_t count = 0; for (auto it : queries->GetSeq_set()) { - string id = it->GetSeq().GetFirstId()->AsFastaString(); + string id = s_GetSequenceId(it->GetSeq()); int flags = s_GetSegmentFlags(it->GetSeq()); int expected = ref_flags.at(id); @@ -2849,7 +3047,7 @@ BOOST_AUTO_TEST_CASE(TestFlagsForPairedReadsFromFastQ) { BOOST_REQUIRE_EQUAL(ref_flags.size(), count); } -BOOST_AUTO_TEST_CASE(TestPairedFlagsForPairedReadsFromTwoFastQFiles) { +BOOST_AUTO_TEST_CASE(TestPairedReadsFromTwoFastQFiles) { CNcbiIfstream istr1("data/paired_reads_1.fastq"); CNcbiIfstream istr2("data/paired_reads_2.fastq"); @@ -2858,23 +3056,23 @@ BOOST_AUTO_TEST_CASE(TestPairedFlagsForPairedReadsFromTwoFastQFiles) { unordered_map ref_flags = { {"lcl|pair1", eFirstSegment}, {"lcl|pair2", eLastSegment}, - {"lcl|incomplete1.1", fFirstSegmentFlag | fPartialFlag}, - {"lcl|incomplete2.2", fLastSegmentFlag | fPartialFlag} + {"lcl|incomplete1.1", eFirstSegment}, + {"lcl|incomplete1.2", eLastSegment}, + {"lcl|incomplete2.1", eFirstSegment}, + {"lcl|incomplete2.2", eLastSegment}, }; - CShortReadFastaInputSource input_source(istr1, istr2, 1000, - CShortReadFastaInputSource::eFastq, - true); + CShortReadFastaInputSource input_source(istr1, istr2, + CShortReadFastaInputSource::eFastq); + CBlastInputOMF input(&input_source, 1000); CRef queries(new CBioseq_set); - input_source.GetNextNumSequences(*queries, 0); - // input file contains six sequences, but two should have been rejected - // in screening - BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 4u); + input.GetNextSeqBatch(*queries); + BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 6u); size_t count = 0; for (auto it : queries->GetSeq_set()) { - string id = it->GetSeq().GetFirstId()->AsFastaString(); + string id = s_GetSequenceId(it->GetSeq()); int flags = s_GetSegmentFlags(it->GetSeq()); int expected = ref_flags.at(id); @@ -2889,26 +3087,24 @@ BOOST_AUTO_TEST_CASE(TestPairedFlagsForPairedReadsFromTwoFastQFiles) { } - - -BOOST_AUTO_TEST_CASE(TestFlagsForPairedReadsFromASN1) { +BOOST_AUTO_TEST_CASE(TestPairedReadsFromASN1) { CNcbiIfstream istr("data/paired_reads.asn"); BOOST_REQUIRE(istr); unordered_map ref_flags = { {"lcl|pair1", eFirstSegment}, {"lcl|pair2", eLastSegment}, - {"lcl|incomplete1.1", fFirstSegmentFlag | fPartialFlag}, - {"lcl|incomplete2.2", fLastSegmentFlag | fPartialFlag} + {"lcl|incomplete1.1", eFirstSegment}, + {"lcl|incomplete1.2", eLastSegment}, + {"lcl|incomplete2.1", eFirstSegment}, + {"lcl|incomplete2.2", eLastSegment}, }; - CASN1InputSourceOMF input_source(istr, 1000, false, true, true); - + CASN1InputSourceOMF input_source(istr, false, true); + CBlastInputOMF input(&input_source, 1000); CRef queries(new CBioseq_set); - input_source.GetNextNumSequences(*queries, 0); - // input file contains six sequences, but two should have been rejected - // in screening - BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 4u); + input.GetNextSeqBatch(*queries); + BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 6u); size_t count = 0; for (auto it : queries->GetSeq_set()) { @@ -2926,7 +3122,7 @@ BOOST_AUTO_TEST_CASE(TestFlagsForPairedReadsFromASN1) { BOOST_REQUIRE_EQUAL(ref_flags.size(), count); } -BOOST_AUTO_TEST_CASE(TestPairedFlagsForPairedReadsFromTwoASN1Files) { +BOOST_AUTO_TEST_CASE(TestPairedReadsFromTwoASN1Files) { CNcbiIfstream istr1("data/paired_reads_1.asn"); CNcbiIfstream istr2("data/paired_reads_2.asn"); @@ -2935,17 +3131,19 @@ BOOST_AUTO_TEST_CASE(TestPairedFlagsForPairedReadsFromTwoASN1Files) { unordered_map ref_flags = { {"lcl|pair1", eFirstSegment}, {"lcl|pair2", eLastSegment}, - {"lcl|incomplete1.1", fFirstSegmentFlag | fPartialFlag}, - {"lcl|incomplete2.2", fLastSegmentFlag | fPartialFlag} + {"lcl|incomplete1.1", eFirstSegment}, + {"lcl|incomplete1.2", eLastSegment}, + {"lcl|incomplete2.1", eFirstSegment}, + {"lcl|incomplete2.2", eLastSegment}, }; - CASN1InputSourceOMF input_source(istr1, istr2, 1000, false, true); - + CASN1InputSourceOMF input_source(istr1, istr2, false); + CBlastInputOMF input(&input_source, 1000); CRef queries(new CBioseq_set); - input_source.GetNextNumSequences(*queries, 0); + input.GetNextSeqBatch(*queries); // input file contains six sequences, but two should have been rejected // in screening - BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 4u); + BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 6u); size_t count = 0; for (auto it : queries->GetSeq_set()) { @@ -2963,6 +3161,44 @@ BOOST_AUTO_TEST_CASE(TestPairedFlagsForPairedReadsFromTwoASN1Files) { BOOST_REQUIRE_EQUAL(ref_flags.size(), count); } + +BOOST_AUTO_TEST_CASE(TestPairedReadsFromFastC) { + + CNcbiIfstream istr("data/paired_reads.fastc"); + BOOST_REQUIRE(istr); + unordered_map ref_flags = { + {"lcl|read1.1", eFirstSegment}, + {"lcl|read1.2", eLastSegment}, + {"lcl|read2.1", eFirstSegment}, + {"lcl|read2.2", eLastSegment}, + {"lcl|read3.1", eFirstSegment}, + {"lcl|read3.2", eLastSegment}, + }; + + CShortReadFastaInputSource input_source(istr, + CShortReadFastaInputSource::eFastc, true); + CBlastInputOMF input(&input_source, 1000); + CRef queries(new CBioseq_set); + input.GetNextSeqBatch(*queries); + BOOST_REQUIRE_EQUAL(queries->GetSeq_set().size(), 6u); + + size_t count = 0; + for (auto it : queries->GetSeq_set()) { + string id = s_GetSequenceId(it->GetSeq()); + int flags = s_GetSegmentFlags(it->GetSeq()); + int expected = ref_flags.at(id); + + BOOST_REQUIRE_MESSAGE(flags == expected, (string)"Segment flag for " + + id + " is different from expected " + + NStr::IntToString(flags) + " != " + + NStr::IntToString(expected)); + count++; + } + + BOOST_REQUIRE_EQUAL(ref_flags.size(), count); +} + + BOOST_AUTO_TEST_SUITE_END() // end of short_reads test suite diff --git a/c++/src/algo/blast/blastinput/unit_test/blastinput_unit_test.ini b/c++/src/algo/blast/blastinput/unit_test/blastinput_unit_test.ini index d4093f39..5318ab46 100644 --- a/c++/src/algo/blast/blastinput/unit_test/blastinput_unit_test.ini +++ b/c++/src/algo/blast/blastinput/unit_test/blastinput_unit_test.ini @@ -1,3 +1,4 @@ [UNITTESTS_DISABLE] RetrieveFromDefaultBlastDb_NoNcbirc = true ForceRemoteBlastDbLoader = true +FetchSraID = true diff --git a/c++/src/algo/blast/blastinput/unit_test/data/paired_reads.fastc b/c++/src/algo/blast/blastinput/unit_test/data/paired_reads.fastc new file mode 100644 index 00000000..da8021cc --- /dev/null +++ b/c++/src/algo/blast/blastinput/unit_test/data/paired_reads.fastc @@ -0,0 +1,6 @@ +>read1 +GAATGTCCGTCTGGGTCTCCTTGTGCTGCGGTCCTGGCAACTCGTAGAATTTCTTACCAAAGTATCGATCCGGGAGATAGTACGATGGATACTCCGCCCTCAGCCTCTCG>read2 +ATGTTTTCCGATCCCGCCCAGGAGTCGGTTGCCACGCAGACGGAGGCACAACCGGTTCCGTCGCCCATCTGCACCCCACTGCTGATGGTGGACGAGGATGGACGAAAGCG>read3 +CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC> #include #include "blast_gapalign_priv.h" +#include "jumper.h" /** Converts nucleotide coordinates to protein */ #define CONV_NUCL2PROT_COORDINATES(length) (length) / CODON_LENGTH NCBI_XBLAST_EXPORT const int kBlastMajorVersion = 2; -NCBI_XBLAST_EXPORT const int kBlastMinorVersion = 6; -NCBI_XBLAST_EXPORT const int kBlastPatchVersion = 0; -NCBI_XBLAST_EXPORT const char* kBlastReleaseDate = "January-09-2017"; +NCBI_XBLAST_EXPORT const int kBlastMinorVersion = 7; +NCBI_XBLAST_EXPORT const int kBlastPatchVersion = 1; +NCBI_XBLAST_EXPORT const char* kBlastReleaseDate = "October-23-2017"; /** Structure to be passed to s_BlastSearchEngineCore, containing pointers to various preallocated structures and arrays. */ @@ -1679,6 +1680,15 @@ BLAST_PreliminarySearchEngine(EBlastProgramType program_number, if (status != 0) break; + /* Do anchored search for mapping */ + if (Blast_ProgramIsMapping(program_number) && getenv("MAPPER_ANCHOR")) { + Int4 word_size = 12; + + DoAnchoredSearch(query, seq_arg.seq, word_size, + query_info, gap_align, score_params, + hit_params, hsp_stream); + } + if (hit_params->low_score) { for (query_index=0; query_indexresults->num_queries; query_index++) diff --git a/c++/src/algo/blast/core/blast_filter.c b/c++/src/algo/blast/core/blast_filter.c index 8b44c9c3..fb24dc85 100644 --- a/c++/src/algo/blast/core/blast_filter.c +++ b/c++/src/algo/blast/core/blast_filter.c @@ -1,4 +1,4 @@ -/* $Id: blast_filter.c 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_filter.c 533522 2017-04-17 15:50:34Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,6 +31,7 @@ #include #include #include +#include "jumper.h" /****************************************************************************/ /* Constants */ @@ -1158,6 +1159,13 @@ BlastSetUp_Filter(EBlastProgramType program_number, sparamsp = NULL; } + if (filter_options->readQualityOptions) { + status = FilterQueriesForMapping(sequence, length, offset, + filter_options->readQualityOptions, + seqloc_retval); + } + + return status; } diff --git a/c++/src/algo/blast/core/blast_gapalign.c b/c++/src/algo/blast/core/blast_gapalign.c index ea077452..5b00f49c 100644 --- a/c++/src/algo/blast/core/blast_gapalign.c +++ b/c++/src/algo/blast/core/blast_gapalign.c @@ -1,4 +1,4 @@ -/* $Id: blast_gapalign.c 516338 2016-10-12 17:32:04Z ivanov $ +/* $Id: blast_gapalign.c 546656 2017-09-20 14:03:34Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -44,7 +44,8 @@ static Int2 s_BlastDynProgNtGappedAlignment(BLAST_SequenceBlk* query_blk, const BlastScoringParameters* score_params, BlastInitHSP* init_hsp); static Int4 s_BlastAlignPackedNucl(Uint1* B, Uint1* A, Int4 N, Int4 M, Int4* pej, Int4* pei, BlastGapAlignStruct* gap_align, - const BlastScoringParameters* score_params, Boolean reverse_sequence); + const BlastScoringParameters* score_params, Boolean reverse_sequence, + Int4 x_dropoff); static Int2 s_BlastProtGappedAlignment(EBlastProgramType program, BLAST_SequenceBlk* query_in, BLAST_SequenceBlk* subject_in, @@ -330,6 +331,11 @@ BLAST_GapAlignStructNew(const BlastScoringParameters* score_params, } else { gap_align->jumper = JumperGapAlignNew(200); + if (ext_params->gap_x_dropoff == 0) { + gap_align->gap_x_dropoff = MAX(-score_params->penalty, + score_params->gap_open + + score_params->gap_extend); + } } if (!gap_align) @@ -2925,6 +2931,11 @@ s_BlastDynProgNtGappedAlignment(BLAST_SequenceBlk* query_blk, Uint1 offset_adjustment; Uint1* query = query_blk->sequence; Uint1* subject = subject_blk->sequence; + Int4 x_dropoff = gap_align->gap_x_dropoff; + + if(init_hsp->ungapped_data->score < x_dropoff) { + x_dropoff = init_hsp->ungapped_data->score; + } /* If subject offset is not at the start of a full byte, s_BlastAlignPackedNucl won't work, so shift the alignment start @@ -2950,7 +2961,7 @@ s_BlastDynProgNtGappedAlignment(BLAST_SequenceBlk* query_blk, /* perform extension to left */ score_left = s_BlastAlignPackedNucl(query, subject, q_length, s_length, &private_q_start, &private_s_start, gap_align, - score_params, TRUE); + score_params, TRUE, x_dropoff); if (score_left < 0) return -1; gap_align->query_start = q_length - private_q_start; @@ -2964,7 +2975,7 @@ s_BlastDynProgNtGappedAlignment(BLAST_SequenceBlk* query_blk, subject+(s_length+3)/COMPRESSION_RATIO - 1, query_blk->length-q_length, subject_blk->length-s_length, &(gap_align->query_stop), - &(gap_align->subject_stop), gap_align, score_params, FALSE); + &(gap_align->subject_stop), gap_align, score_params, FALSE, x_dropoff); if (score_right < 0) return -1; gap_align->query_stop += q_length; @@ -2999,7 +3010,7 @@ s_BlastAlignPackedNucl(Uint1* B, Uint1* A, Int4 N, Int4 M, Int4* b_offset, Int4* a_offset, BlastGapAlignStruct* gap_align, const BlastScoringParameters* score_params, - Boolean reverse_sequence) + Boolean reverse_sequence, Int4 x_dropoff) { Int4 i; /* sequence pointers and indices */ Int4 a_index, a_base_pair; @@ -3012,7 +3023,6 @@ s_BlastAlignPackedNucl(Uint1* B, Uint1* A, Int4 N, Int4 M, Int4 gap_open; /* alignment penalty variables */ Int4 gap_extend; Int4 gap_open_extend; - Int4 x_dropoff; Int4* *matrix; /* pointers to the score matrix */ Int4* matrix_row; @@ -3031,7 +3041,6 @@ s_BlastAlignPackedNucl(Uint1* B, Uint1* A, Int4 N, Int4 M, gap_open = score_params->gap_open; gap_extend = score_params->gap_extend; gap_open_extend = gap_open + gap_extend; - x_dropoff = gap_align->gap_x_dropoff; if (x_dropoff < gap_open_extend) x_dropoff = gap_open_extend; diff --git a/c++/src/algo/blast/core/blast_hits.c b/c++/src/algo/blast/core/blast_hits.c index b9b1abda..10b0e693 100644 --- a/c++/src/algo/blast/core/blast_hits.c +++ b/c++/src/algo/blast/core/blast_hits.c @@ -1,4 +1,4 @@ -/* $Id: blast_hits.c 516334 2016-10-12 17:30:52Z ivanov $ +/* $Id: blast_hits.c 532442 2017-04-05 13:47:44Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -3774,51 +3774,3 @@ Blast_HSPResultsFromHSPStreamWithLimitEx(BlastHSPStream* hsp_stream, } return retval; } - - -BlastHSPChain* Blast_HSPChainNew(void) -{ - BlastHSPChain* chain = calloc(1, sizeof(BlastHSPChain)); - return chain; -} - -BlastHSPChain* Blast_HSPChainFree(BlastHSPChain* ch) -{ - Int4 i; - - if (!ch) { - return NULL; - } - - for (i = 0;i < ch->num_hsps;i++) { - Blast_HSPFree(ch->hsp_array[i]); - } - sfree(ch->hsp_array); - sfree(ch); - - return NULL; -} - -BlastMappingResults* Blast_MappingResultsNew(void) -{ - BlastMappingResults* retval = calloc(1, sizeof(BlastMappingResults)); - return retval; -} - -BlastMappingResults* Blast_MappingResultsFree(BlastMappingResults* results) -{ - if (!results) { - return NULL; - } - - if (results->chain_array) { - Int4 i; - for (i = 0;i < results->num_results;i++) { - Blast_HSPChainFree(results->chain_array[i]); - } - sfree(results->chain_array); - } - sfree(results); - - return NULL; -} diff --git a/c++/src/algo/blast/core/blast_kappa.c b/c++/src/algo/blast/core/blast_kappa.c index 0368bf3c..4aac1a3e 100644 --- a/c++/src/algo/blast/core/blast_kappa.c +++ b/c++/src/algo/blast/core/blast_kappa.c @@ -1,4 +1,4 @@ -/* $Id: blast_kappa.c 516336 2016-10-12 17:31:41Z ivanov $ +/* $Id: blast_kappa.c 514951 2016-09-27 14:54:05Z rackerst $ * ========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/core/blast_lookup.c b/c++/src/algo/blast/core/blast_lookup.c index 5b7c43e3..d5c4b340 100644 --- a/c++/src/algo/blast/core/blast_lookup.c +++ b/c++/src/algo/blast/core/blast_lookup.c @@ -1,4 +1,4 @@ -/* $Id: blast_lookup.c 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_lookup.c 523540 2017-01-04 16:58:25Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -137,9 +137,6 @@ BackboneCell* BackboneCellFree(BackboneCell* cell) BackboneCell* b = cell; while (b) { BackboneCell* next = b->next; - if (b->offsets) { - free(b->offsets); - } sfree(b); b = next; } @@ -147,7 +144,8 @@ BackboneCell* BackboneCellFree(BackboneCell* cell) return NULL; } -BackboneCell* BackboneCellNew(Uint4 word, Int4 offset, Int4 size) + +BackboneCell* BackboneCellNew(Uint4 word, Int4 offset) { BackboneCell* cell = calloc(1, sizeof(BackboneCell)); if (!cell) { @@ -155,51 +153,32 @@ BackboneCell* BackboneCellNew(Uint4 word, Int4 offset, Int4 size) return NULL; } - cell->offsets = malloc(size * sizeof(Int4)); - if (!cell->offsets) { - BackboneCellFree(cell); - return NULL; - } - - cell->word = word; - cell->offsets[0] = offset; - cell->num_offsets = 1; - cell->allocated = size; - + BackboneCellInit(cell, word, offset); return cell; } -#define MAX_WORD_COUNT (10) -/* Test whether a word count is at least one and at most MAX_WORD_COUNT. - Counts are stored in 4 bits. */ -static Boolean s_TestCounts(Uint4 word, Uint1* counts) +Int4 BackboneCellInit(BackboneCell* cell, Uint4 word, Int4 offset) { - if (!(word & 1)) { - if ((counts[word / 2] >> 4) == 0 || - (counts[word / 2] >> 4) >= MAX_WORD_COUNT) { - return FALSE; - } - } - else { - if ((counts[word / 2] & 0xf) == 0 || - (counts[word / 2] & 0xf) >= MAX_WORD_COUNT) { - return FALSE; - } + if (!cell) { + return -1; } - return TRUE; + cell->word = word; + cell->offset = offset; + cell->num_offsets = 1; + + return 0; } -static Int2 s_AddWordHit(BackboneCell** backbone, Int4 wordsize, +static Int2 s_AddWordHit(BackboneCell* backbone, Int4* offsets, Int4 wordsize, Int4 charsize, Uint1* seq, Int4 offset, TNaLookupHashFunction hash_func, Uint4 mask, - Uint1* counts) + PV_ARRAY_TYPE* pv_array) { Uint4 large_index; Int8 index; Int4 i; - Int4 num_collisions = 0; /* convert a sequence from 4NA to 2NA */ large_index = 0; @@ -209,58 +188,54 @@ static Int2 s_AddWordHit(BackboneCell** backbone, Int4 wordsize, /* if filtering by database word count, then do not add words that do not appear in the database or appear to many times */ - if (counts && !s_TestCounts(large_index, counts)) { + if (pv_array && !PV_TEST(pv_array, large_index, PV_ARRAY_BTS)) { return 0; } index = (Int8)hash_func((Uint1*)&large_index, mask); - /* if the hash table entry is emtpy, create a new cell */ - if (!backbone[index]) { - Int4 size = 8; - backbone[index] = BackboneCellNew(large_index, offset, size); - if (!backbone[index]) { - return -1; - } + /* offset zero indicates end of offset list, so we are storing offset + 1 + values */ + offset++; + + /* if the hash table entry is emtpy, initialize a new cell */ + if (backbone[index].num_offsets == 0) { + BackboneCellInit(&backbone[index], large_index, offset); } else { - /* otherwiose check if the word was already added */ - - BackboneCell* b = backbone[index]; + /* otherwise check if the word was already added */ + BackboneCell* b = &backbone[index]; while (b->next && b->word != large_index) { b = b->next; } /* if word was already added, add the new offset to an existing cell */ if (b->word == large_index) { - if (b->num_offsets >= b->allocated) { - Int4 new_size = b->allocated * 2; - b->offsets = realloc(b->offsets, new_size * sizeof(Int4)); - if (!b->offsets) { - return -1; - } - b->allocated = new_size; - } - b->offsets[b->num_offsets++] = offset; + /* word offsets are all sored in a linear array where next offset = + offsets[current offset] until offset is zero (similarily to + next_pos array in MBLookupTable) */ + + ASSERT(offsets[offset] == 0); + offsets[offset] = b->offset; + b->offset = offset; + b->num_offsets++; } else { /* otherwise creare a new cell */ - - Int4 size = 8; ASSERT(!b->next); - b->next = BackboneCellNew(large_index, offset, size); + b->next = BackboneCellNew(large_index, offset); if (!b->next) { return -1; } - - num_collisions++; } } return 0; } -void BlastHashLookupIndexQueryExactMatches(BackboneCell **backbone, + +void BlastHashLookupIndexQueryExactMatches(BackboneCell *backbone, + Int4* offsets, Int4 word_length, Int4 charsize, Int4 lut_word_length, @@ -268,7 +243,7 @@ void BlastHashLookupIndexQueryExactMatches(BackboneCell **backbone, BlastSeqLoc* locations, TNaLookupHashFunction hash_func, Uint4 mask, - Uint1* counts) + PV_ARRAY_TYPE* pv_array) { BlastSeqLoc *loc; Int4 offset; @@ -296,11 +271,12 @@ void BlastHashLookupIndexQueryExactMatches(BackboneCell **backbone, if (seq >= word_target) { s_AddWordHit(backbone, + offsets, lut_word_length, charsize, seq - lut_word_length, offset - lut_word_length, hash_func, mask, - counts); + pv_array); } /* if the current word contains an ambiguity, skip all the @@ -311,12 +287,13 @@ void BlastHashLookupIndexQueryExactMatches(BackboneCell **backbone, /* handle the last word, without loading *seq */ if (seq >= word_target) { - s_AddWordHit(backbone, + s_AddWordHit(backbone, + offsets, lut_word_length, charsize, seq - lut_word_length, offset - lut_word_length, hash_func, mask, - counts); + pv_array); } } diff --git a/c++/src/algo/blast/core/blast_nalookup.c b/c++/src/algo/blast/core/blast_nalookup.c index 2e19c29a..62b7d9b9 100644 --- a/c++/src/algo/blast/core/blast_nalookup.c +++ b/c++/src/algo/blast/core/blast_nalookup.c @@ -1,4 +1,4 @@ -/* $Id: blast_nalookup.c 506275 2016-07-06 14:42:04Z boratyng $ +/* $Id: blast_nalookup.c 545120 2017-08-31 16:42:25Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -68,10 +68,10 @@ BlastChooseNaLookupTable(const LookupTableOptions* lookup_options, /* always use megablast lookup table and word size 16 for mapping */ if (Blast_ProgramIsMapping(lookup_options->program_number) && - lookup_options->word_size >= 16) { + lookup_options->word_size >= 16 && lookup_options->db_filter) { *lut_width = 16; - return eMBLookupTable; + return eNaHashLookupTable; } switch(lookup_options->word_size) { @@ -894,11 +894,15 @@ static Int2 s_RemovePolyAWords(BlastMBLookupTable* mb_lt) Int8 word; Int4 i, k; - ASSERT(word_size == 16); - /* remove As and Ts */ mb_lt->hashtable[0] = 0; - mb_lt->hashtable[(Int8)0xffffffff] = 0; + mb_lt->hashtable[(Int8)((1 << (2 * word_size)) - 1)] = 0; + + if (word_size < 16) { + return 0; + } + + ASSERT(word_size == 16); /* remove As with a single error */ for (i = 1;i < 4;i++) { @@ -1082,9 +1086,7 @@ s_FillContigMBTable(BLAST_SequenceBlk* query, } } - /* FIXME: should this be done only for spliced reads? */ - if (Blast_ProgramIsMapping(lookup_options->program_number) && - mb_lt->lut_word_length == 16) { + if (Blast_ProgramIsMapping(lookup_options->program_number)) { s_RemovePolyAWords(mb_lt); } @@ -1451,6 +1453,139 @@ s_NaHashLookupFillPV(BLAST_SequenceBlk* query, return 0; } +/* Get number of set bits (adapted + from http://graphics.stanford.edu/~seander/bithacks.html) + @param v Bit vector [in] + @return Number of set bits +*/ +static Uint4 s_Popcount(Uint4 v) +{ + if (v==0) return 0; // early bailout for sparse vectors + v = v - ((v >> 1) & 0x55555555); + v = (v & 0x33333333) + ((v >> 2) & 0x33333333); + v = ((v + (v >> 4)) & 0xF0F0F0F); + v = v * 0x1010101; + + return v >> 24; // count +} + +/** Sparse array of Uint1 implemented with a bitfield. The implementation + assumes that indices present are known beforehand and the array is used + only to access values with certain indices */ +typedef struct BlastSparseUint1Array +{ + Uint4* bitfield; /**< bitfield with bits set for present indices */ + Uint1* values; /**< array of values for present indices */ + Int4* counts; /**< cumulative number of bits set */ + Uint4 num_elements; /**< number of values present in the array */ + Uint4 length; /**< length of the bitfield */ +} BlastSparseUint1Array; + + +static BlastSparseUint1Array* +BlastSparseUint1ArrayFree(BlastSparseUint1Array* array) +{ + if (!array) { + return NULL; + } + + if (array->values) { + free(array->values); + } + + if (array->counts) { + free(array->counts); + } + + free(array); + + return NULL; +} + +static BlastSparseUint1Array* +BlastSparseUint1ArrayNew(Uint4* bitfield, Int8 len) +{ + Int4 i; + BlastSparseUint1Array* retval = calloc(1, sizeof(BlastSparseUint1Array)); + + if (!retval || !bitfield) { + return NULL; + } + + retval->bitfield = bitfield; + retval->length = len >> PV_ARRAY_BTS; + retval->counts = calloc(retval->length, sizeof(Int4)); + if (!retval->counts) { + BlastSparseUint1ArrayFree(retval); + return NULL; + } + + retval->counts[0] = s_Popcount(retval->bitfield[0]); + for (i = 1;i < retval->length;i++) { + retval->counts[i] = retval->counts[i - 1] + + s_Popcount(retval->bitfield[i]); + } + + Int4 num_elements = retval->counts[retval->length - 1]; + retval->num_elements = num_elements; + retval->values = calloc(num_elements, sizeof(Uint1)); + if (!retval->values) { + BlastSparseUint1ArrayFree(retval); + return NULL; + } + + return retval; +} + +/* Get index into array->values for a given vector index */ +static Int4 +BlastSparseUint1ArrayGetIndex(BlastSparseUint1Array* array, Int8 index) +{ + /* index into bitfield */ + Int4 idx = index >> PV_ARRAY_BTS; + + /* bit number within a bitfield cell (mod 32) */ + Int4 bit_number = index & PV_ARRAY_MASK; + + /* number of bits set before a specified bit */ + Int4 bit_count = 0; + + if (!array || idx >= array->length) { + return -1; + } + + /* get number of bits set up to idx */ + bit_count = (idx > 0) ? array->counts[idx - 1] : 0; + ASSERT(array->bitfield[idx] & (1 << bit_number)); + + /* add number of bits set up to bit number in the cell */ + bit_count += s_Popcount(array->bitfield[idx] & ((1 << bit_number) - 1)); + bit_count++; + + + ASSERT(bit_count > 0); + return bit_count - 1; +} + +/* Get a pointer to a non zero element in the sparse vector */ +static Uint1* +BlastSparseUint1ArrayGetElement(BlastSparseUint1Array* array, Int8 index) +{ + Int4 sparse_index; + + if (!array) { + return NULL; + } + + sparse_index = BlastSparseUint1ArrayGetIndex(array, index); + ASSERT(sparse_index < array->num_elements); + if (sparse_index < 0 || sparse_index > array->num_elements) { + return NULL; + } + + return array->values + sparse_index; +} + /** Scan a subject sequecne and update words counters, for 16-base words with * scan step of 1. The counters are 4-bit and counting is done up to 10. @@ -1462,18 +1597,19 @@ s_NaHashLookupFillPV(BLAST_SequenceBlk* query, static Int2 s_NaHashLookupCountWordsInSubject_16_1(const BLAST_SequenceBlk* sequence, BlastNaHashLookupTable* lookup, - Uint1* counts) + BlastSparseUint1Array* counts) { Uint1 *s; Int4 i; Int8 mask = (1ULL << (16 * BITS_PER_NUC)) - 1; - Int8 word, index, w; + Int8 word, w; const Int4 kNumWords = sequence->length - lookup->lut_word_length; PV_ARRAY_TYPE* pv = lookup->pv; Int4 pv_array_bts = lookup->pv_array_bts; Int4 shift; + Uint1* pelem; if (!sequence || !counts || !lookup || !pv) { return -1; @@ -1504,20 +1640,172 @@ s_NaHashLookupCountWordsInSubject_16_1(const BLAST_SequenceBlk* sequence, } /* update the counter */ - index = word / 2; - if (word & 1) { - if ((counts[index] & 0xf) < MAX_WORD_COUNT) { - counts[index]++; + pelem = BlastSparseUint1ArrayGetElement(counts, word); + if (*pelem < MAX_WORD_COUNT) { + (*pelem)++; + } + } + + return 0; +} + + +/* Thread local data for database word counting phase of lookup table + generation (for Magic-BLAST) */ +typedef struct NaHashLookupThreadData +{ + BlastSeqSrcGetSeqArg* seq_arg; + BlastSeqSrcIterator** itr; + BlastSeqSrc** seq_src; + BlastSparseUint1Array** word_counts; + Int4 num_threads; +} NaHashLookupThreadData; + + +static NaHashLookupThreadData* NaHashLookupThreadDataFree( + NaHashLookupThreadData* th) +{ + if (!th) { + return NULL; + } + + if (th->seq_arg) { + Int4 i; + for (i = 0;i < th->num_threads;i++) { + BlastSequenceBlkFree(th->seq_arg[i].seq); + } + free(th->seq_arg); + } + + if (th->itr) { + Int4 i; + for (i = 0;i < th->num_threads;i++) { + BlastSeqSrcIteratorFree(th->itr[i]); + } + free(th->itr); + } + + if (th->seq_src) { + Int4 i; + for (i = 0;i < th->num_threads;i++) { + BlastSeqSrcFree(th->seq_src[i]); + } + free(th->seq_src); + } + + if (th->word_counts) { + Int4 i; + for (i = 1;i < th->num_threads;i++) { + if (th->word_counts[i]) { + if (th->word_counts[i]->values) { + free(th->word_counts[i]->values); + } + free(th->word_counts[i]); + } + + + } + BlastSparseUint1ArrayFree(th->word_counts[0]); + free(th->word_counts); + } + + free(th); + + return NULL; +} + + +static NaHashLookupThreadData* NaHashLookupThreadDataNew(Int4 num_threads, + BlastNaHashLookupTable* lookup, + BlastSeqSrc* seq_src) +{ + Int4 i; + + if (num_threads < 1 || !lookup || !seq_src) { + return NULL; + } + + NaHashLookupThreadData* retval = calloc(1, sizeof(NaHashLookupThreadData)); + if (!retval) { + return NULL; + } + + retval->seq_arg = calloc(num_threads, sizeof(BlastSeqSrcGetSeqArg)); + if (!retval->seq_arg) { + NaHashLookupThreadDataFree(retval); + return NULL; + } + + retval->itr = calloc(num_threads, sizeof(BlastSeqSrcIterator*)); + if (!retval->itr) { + NaHashLookupThreadDataFree(retval); + return NULL; + } + + retval->seq_src = calloc(num_threads, sizeof(BlastSeqSrc*)); + if (!retval->seq_src) { + NaHashLookupThreadDataFree(retval); + return NULL; + } + + retval->word_counts = calloc(num_threads, sizeof(BlastSparseUint1Array*)); + if (!retval->word_counts) { + NaHashLookupThreadDataFree(retval); + return NULL; + } + + for (i = 0;i < num_threads;i++) { + + retval->seq_arg[i].encoding = eBlastEncodingProtein; + + retval->seq_src[i] = BlastSeqSrcCopy(seq_src); + if (!retval->seq_src[i]) { + NaHashLookupThreadDataFree(retval); + return NULL; + } + + /* each thread must have its own iterator, the small batch seems to + work better for work balansing between threads */ + retval->itr[i] = BlastSeqSrcIteratorNewEx(1); + if (!retval->itr[i]) { + NaHashLookupThreadDataFree(retval); + return NULL; + } + + if (i == 0) { + retval->word_counts[i] = BlastSparseUint1ArrayNew(lookup->pv, + 1LL << (2 * lookup->lut_word_length)); + + if (!retval->word_counts[i]) { + NaHashLookupThreadDataFree(retval); + return NULL; } } else { - if ((counts[index] >> 4) < MAX_WORD_COUNT) { - counts[index] += 1 << 4; + /* Make shallow copies of the counts array. We do not copy data + that are read only to save memory. */ + retval->word_counts[i] = malloc(sizeof(BlastSparseUint1Array)); + if (!retval->word_counts[i]) { + NaHashLookupThreadDataFree(retval); + return NULL; + } + memcpy(retval->word_counts[i], retval->word_counts[0], + sizeof(BlastSparseUint1Array)); + + retval->word_counts[i]->values = calloc( + retval->word_counts[i]->num_elements, + sizeof(Uint1)); + + if (!retval->word_counts[i]->values) { + NaHashLookupThreadDataFree(retval); + return NULL; } } } - return 0; + retval->num_threads = num_threads; + + return retval; } /** Scan database sequences and count query words that appear in the database. @@ -1526,106 +1814,163 @@ s_NaHashLookupCountWordsInSubject_16_1(const BLAST_SequenceBlk* sequence, * * @param seq_src Source for subject sequences [in] * @param lookup Hashed lookuptable [in|out] + * @param num_threads Number of threads to use [in] */ static Int2 s_NaHashLookupScanSubjectForWordCounts(BlastSeqSrc* seq_src, BlastNaHashLookupTable* lookup, - Uint1* counts) + Uint4 in_num_threads) { - BlastSeqSrcIterator* itr; - BlastSeqSrcGetSeqArg seq_arg; + Uint4 i; + Int4 k, b; + Int4 num_db_seqs, th_batch; + NaHashLookupThreadData* th_data = NULL; + Uint4 num_threads; - if (!seq_src || !lookup || !lookup->pv || !counts) { + if (!seq_src || !lookup || !lookup->pv) { return -1; } - memset(&seq_arg, 0, sizeof(seq_arg)); - seq_arg.encoding = eBlastEncodingProtein; + ASSERT(lookup->lut_word_length == 16); - /* scan subject sequences and update the counters for each */ - BlastSeqSrcResetChunkIterator(seq_src); - itr = BlastSeqSrcIteratorNewEx(MAX(BlastSeqSrcGetNumSeqs(seq_src)/100,1)); - while ((seq_arg.oid = BlastSeqSrcIteratorNext(seq_src, itr)) - != BLAST_SEQSRC_EOF) { + /* pv array must be one bit per word */ + ASSERT(lookup->pv_array_bts == 5); - BlastSeqSrcGetSequence(seq_src, &seq_arg); - s_NaHashLookupCountWordsInSubject_16_1(seq_arg.seq, lookup, counts); - BlastSeqSrcReleaseSequence(seq_src, &seq_arg); - } + num_db_seqs = BlastSeqSrcGetNumSeqs(seq_src); + num_threads = MIN(in_num_threads, num_db_seqs); + th_batch = BlastSeqSrcGetNumSeqs(seq_src) / num_threads; - BlastSequenceBlkFree(seq_arg.seq); - BlastSeqSrcIteratorFree(itr); + th_data = NaHashLookupThreadDataNew(num_threads, lookup, seq_src); + if (!th_data) { + return -1; + } - return 0; -} + /* reset database iterator */ + BlastSeqSrcResetChunkIterator(seq_src); + /* scan subject sequences and update the counters for each */ +#pragma omp parallel for if (num_threads > 1) num_threads(num_threads) \ + default(none) shared(num_threads, th_data, lookup, \ + th_batch) private(i) schedule(dynamic, 1) + + for (i = 0;i < num_threads;i++) { + Int4 j; + for (j = 0;j < th_batch;j++) { + +#pragma omp critical (get_sequence_for_word_counts) + { + th_data->seq_arg[i].oid = BlastSeqSrcIteratorNext( + th_data->seq_src[i], + th_data->itr[i]); + + if (th_data->seq_arg[i].oid != BLAST_SEQSRC_EOF) { + BlastSeqSrcGetSequence(th_data->seq_src[i], + &th_data->seq_arg[i]); + } + } -static void s_NaHashLookupRemoveWordFromThinBackbone( - BackboneCell** thin_backbone, - Uint4 word, - TNaLookupHashFunction hash_func, - Uint4 mask) -{ - BackboneCell* prev = NULL; - BackboneCell* next = NULL; - BackboneCell* b = NULL; - Int8 index = hash_func((Uint1*)&word, mask); + if (th_data->seq_arg[i].oid != BLAST_SEQSRC_EOF) { - if (!thin_backbone[index]) { - return; + s_NaHashLookupCountWordsInSubject_16_1(th_data->seq_arg[i].seq, + lookup, + th_data->word_counts[i]); + BlastSeqSrcReleaseSequence(th_data->seq_src[i], + &th_data->seq_arg[i]); + } + } } - /* if word present in the first enrty for the hashed value */ - if (thin_backbone[index]->word == word) { - next = thin_backbone[index]->next; - thin_backbone[index]->next = NULL; - BackboneCellFree(thin_backbone[index]); - thin_backbone[index] = next; + /* scan the last sequences */ + while ((th_data->seq_arg[0].oid = BlastSeqSrcIteratorNext(seq_src, + th_data->itr[0])) + != BLAST_SEQSRC_EOF) { - return; + BlastSeqSrcGetSequence(seq_src, &th_data->seq_arg[0]); + s_NaHashLookupCountWordsInSubject_16_1(th_data->seq_arg[0].seq, lookup, + th_data->word_counts[0]); + BlastSeqSrcReleaseSequence(seq_src, &th_data->seq_arg[0]); } - /* in case of a collision check the remaining words with the same hash - value */ - prev = thin_backbone[index]; - b = thin_backbone[index]->next; - for (; b; prev = prev->next, b = b->next) { - if (b->word == word) { - next = b->next; - b->next = NULL; - BackboneCellFree(b); - prev->next = next; + /* aggregate counts */ + for (i = 0;i < th_data->word_counts[0]->num_elements;i++) { + for (k = 1;k < num_threads;k++) { + th_data->word_counts[0]->values[i] = + MIN(th_data->word_counts[0]->values[i] + + th_data->word_counts[k]->values[i], + MAX_WORD_COUNT); + } + } + + /* iterate over word counts and clear bits for words that appear too + often or not at all */ + i = 0; + b = 1; + k = 0; + while (i < th_data->word_counts[0]->length) { + + /* skip bit field array elements with all bits cleared */ + if (th_data->word_counts[0]->bitfield[i] == 0) { + i++; + b = 1; + continue; + } + + if (th_data->word_counts[0]->bitfield[i] & b) { + ASSERT(k < th_data->word_counts[0]->num_elements); - break; + /* clear bit if word count is too low or too large */ + if (th_data->word_counts[0]->values[k] == 0 || + th_data->word_counts[0]->values[k] >= MAX_WORD_COUNT) { + + th_data->word_counts[0]->bitfield[i] &= ~b; + } + k++; + } + b <<= 1; + if (b == 0) { + i++; + b = 1; } } + + NaHashLookupThreadDataFree(th_data); + + return 0; } -static Int2 s_NaHashLookupRemovePolyAWords(BackboneCell** thin_backbone, - Int4 size, - TNaLookupHashFunction hash_func, - Uint4 mask) +static Int2 s_NaHashLookupRemovePolyAWords(BlastNaHashLookupTable* lookup) { - Int4 word_size = 16; Int8 word; + Int4 word_size; Int4 i, k; + PV_ARRAY_TYPE* pv = NULL; + Int4 pv_array_bts; - ASSERT(word_size == 16); + if (!lookup) { + return -1; + } + + ASSERT(lookup->lut_word_length == 16); + + /* a bit must represent a single word */ + ASSERT(lookup->pv_array_bts == 5); + + pv = lookup->pv; + pv_array_bts = lookup->pv_array_bts; + word_size = lookup->lut_word_length; /* remove As and Ts */ - s_NaHashLookupRemoveWordFromThinBackbone(thin_backbone, 0, hash_func, mask); - s_NaHashLookupRemoveWordFromThinBackbone(thin_backbone, 0xffffffff, - hash_func, mask); + pv[0] &= ~(PV_ARRAY_TYPE)1; + pv[0xffffffff >> pv_array_bts] &= + ~((PV_ARRAY_TYPE)1 << (0xffffffff & PV_ARRAY_MASK)); /* remove As with a single error */ for (i = 1;i < 4;i++) { word = i; for (k = 0;k < word_size;k++) { - s_NaHashLookupRemoveWordFromThinBackbone(thin_backbone, - word << (k * 2), - hash_func, - mask); + pv[word >> pv_array_bts] &= + ~((PV_ARRAY_TYPE)1 << (word & PV_ARRAY_MASK)); } } @@ -1633,8 +1978,9 @@ static Int2 s_NaHashLookupRemovePolyAWords(BackboneCell** thin_backbone, for (i = 0;i < 3;i++) { for (k = 0;k < word_size;k++) { word = ((0xffffffff ^ (3 << k*2)) | (i << k*2)) & 0xffffffff; - s_NaHashLookupRemoveWordFromThinBackbone(thin_backbone, word, - hash_func, mask); + + pv[word >> pv_array_bts] &= + ~((PV_ARRAY_TYPE)1 << (word & PV_ARRAY_MASK)); } } @@ -1647,7 +1993,8 @@ static Int2 s_NaHashLookupRemovePolyAWords(BackboneCell** thin_backbone, * @param thin_backbone structure containing indexed query offsets [in][out] * @param lookup the lookup table [in] */ -static void s_BlastNaHashLookupFinalize(BackboneCell** thin_backbone, +static void s_BlastNaHashLookupFinalize(BackboneCell* thin_backbone, + Int4* offsets, BlastNaHashLookupTable* lookup) { Int4 i; @@ -1656,6 +2003,7 @@ static void s_BlastNaHashLookupFinalize(BackboneCell** thin_backbone, Int4 longest_chain = 0; PV_ARRAY_TYPE *pv; const Int4 pv_array_bts = lookup->pv_array_bts; + const Int8 kNumWords = 1LL << (2 * lookup->lut_word_length); #ifdef LOOKUP_VERBOSE Int4 backbone_occupancy = 0; Int4 thick_backbone_occupancy = 0; @@ -1665,30 +2013,37 @@ static void s_BlastNaHashLookupFinalize(BackboneCell** thin_backbone, ASSERT(lookup->lut_word_length == 16); + if (!lookup->pv) { + + lookup->pv = (PV_ARRAY_TYPE*)calloc(kNumWords >> lookup->pv_array_bts, + sizeof(PV_ARRAY_TYPE)); + ASSERT(lookup->pv); + } + else { + /* reset PV array, it might have been set earlier to count database + words, and a few bits may need to be reset */ + memset(lookup->pv, 0, (kNumWords >> lookup->pv_array_bts) * + sizeof(PV_ARRAY_TYPE)); + } + pv = lookup->pv; + ASSERT(pv != NULL); + /* allocate the new lookup table */ lookup->thick_backbone = (NaHashLookupBackboneCell *)calloc( lookup->backbone_size, sizeof(NaHashLookupBackboneCell)); ASSERT(lookup->thick_backbone != NULL); - pv = lookup->pv; - ASSERT(pv != NULL); - /* reset PV array, it might have been set earlier to count database words, - and a few bits may need to be reset */ - memset(pv, 0, (lookup->backbone_size >> pv_array_bts) * PV_ARRAY_BYTES); - - /* remove polyA words from the lookup table */ - s_NaHashLookupRemovePolyAWords(thin_backbone, lookup->backbone_size, - lookup->hash_callback, lookup->mask); - /* find out how many cells are needed for the overflow array */ for (i = 0; i < lookup->backbone_size; i++) { - BackboneCell* b = thin_backbone[i]; + BackboneCell* b = &thin_backbone[i]; Int4 num_hits = 0; Int4 num_words = 0; - for (; b; b = b->next) { - num_hits += b->num_offsets; - num_words++; + if (b->num_offsets > 0) { + for (; b; b = b->next) { + num_hits += b->num_offsets; + num_words++; + } } if (num_words > NA_WORDS_PER_HASH || num_hits > NA_OFFSETS_PER_HASH) { @@ -1713,11 +2068,11 @@ static void s_BlastNaHashLookupFinalize(BackboneCell** thin_backbone, Int4 num_words = 0; Int4 num_offsets = 0; NaHashLookupBackboneCell* cell = lookup->thick_backbone + i; - BackboneCell* head = thin_backbone[i]; + BackboneCell* head = &thin_backbone[i]; BackboneCell* b = NULL; Boolean is_overflow = FALSE; - if (!head) { + if (head->num_offsets == 0) { continue; } @@ -1755,9 +2110,12 @@ static void s_BlastNaHashLookupFinalize(BackboneCell** thin_backbone, PV_SET(pv, (Int8)b->word, pv_array_bts); - for (j = 0;j < b->num_offsets;j++) { + j = b->offset; + while (j != 0) { ASSERT(n <= NA_OFFSETS_PER_HASH); - cell->offsets[n++] = b->offsets[j]; + /* offsets array stores 1-based offsets */ + cell->offsets[n++] = j - 1; + j = offsets[j]; } } } @@ -1784,18 +2142,22 @@ static void s_BlastNaHashLookupFinalize(BackboneCell** thin_backbone, Int4 j; lookup->overflow[overflow_cursor++] = *(Int4*)(&b->word); lookup->overflow[overflow_cursor++] = b->num_offsets; - for (j = 0;j < b->num_offsets;j++) { - lookup->overflow[overflow_cursor++] = b->offsets[j]; + + j = b->offset; + while (j != 0) { + /* offsets array stores 1-based offsets */ + lookup->overflow[overflow_cursor++] = j - 1; + j = offsets[j]; } + ASSERT(overflow_cursor <= overflow_cells_needed); PV_SET(pv, (Int8)b->word, pv_array_bts); } } /* done with this chain */ - thin_backbone[i] = BackboneCellFree(thin_backbone[i]); + BackboneCellFree(thin_backbone[i].next); } - lookup->offsets_size = overflow_cursor; #ifdef LOOKUP_VERBOSE @@ -1826,7 +2188,8 @@ BlastNaHashLookupTableDestruct(BlastNaHashLookupTable* lookup) sfree(lookup->overflow); if (lookup->masked_locations) lookup->masked_locations = BlastSeqLocFree(lookup->masked_locations); - sfree(lookup->pv); + if (lookup->pv) + sfree(lookup->pv); sfree(lookup); return NULL; @@ -1838,89 +2201,98 @@ Int4 BlastNaHashLookupTableNew(BLAST_SequenceBlk* query, BlastNaHashLookupTable** lut, const LookupTableOptions* opt, const QuerySetUpOptions* query_options, - BlastSeqSrc* seqsrc) + BlastSeqSrc* seqsrc, + Uint4 num_threads) { - BackboneCell **thin_backbone = NULL; + BackboneCell *thin_backbone = NULL; + Int4* offsets = NULL; BlastNaHashLookupTable *lookup = *lut = (BlastNaHashLookupTable*) calloc(1, sizeof(BlastNaHashLookupTable)); /* Number of possible 16-base words */ const Int8 kNumWords = (1ULL << 32); - Uint1* counts = NULL; - Int4 num_hash_bits = 24; - Int8 database_length = 0LL; - + Int4 num_hash_bits = 8; + Int4 i, num_unique_words = 0; + ASSERT(lookup != NULL); if (opt->db_filter && !seqsrc) { return -1; } - /* use more bits for hash function for larger databases to decrease number - of collisions */ - /* FIXME: number of bits may also depend on concatenated query length */ - if (seqsrc) { - database_length = BlastSeqSrcGetTotLen(seqsrc); - } - if (database_length > 500000000L) { - num_hash_bits = 25; - } - lookup->word_length = opt->word_size; lookup->lut_word_length = 16; - /* 16-base words are hashed to 24-bit or 25-bit values */ - lookup->backbone_size = 1 << num_hash_bits; - lookup->mask = lookup->backbone_size - 1; lookup->overflow = NULL; - lookup->scan_step = lookup->word_length - lookup->lut_word_length + 1; lookup->hash_callback = FNV_hash; - thin_backbone = (BackboneCell**)calloc(lookup->backbone_size, - sizeof(BackboneCell*)); - ASSERT(thin_backbone != NULL); + if (opt->db_filter) { + /* with database filtering some query words are not put in the lookup + table and neighboring query words would be missed with larger scan + step */ + lookup->scan_step = 1; + } + else { + lookup->scan_step = lookup->word_length - lookup->lut_word_length + 1; + } - /* PV array does not use hashing, and uses 64 words per bit */ - lookup->pv_array_bts = 11; - lookup->pv = (PV_ARRAY_TYPE*)calloc(kNumWords / 64 / PV_ARRAY_BYTES, + /* PV array does not use hashing */ + lookup->pv_array_bts = PV_ARRAY_BTS; + lookup->pv = (PV_ARRAY_TYPE*)calloc(kNumWords >> lookup->pv_array_bts, sizeof(PV_ARRAY_TYPE)); - ASSERT(lookup->pv); + if (!lookup->pv) { + return BLASTERR_MEMORY; + } - - /* allocate word counters, to save memory we are using 4 bits per word */ - if (opt->db_filter) { - ASSERT(lookup->word_length == 16); - counts = (Uint1*)calloc(kNumWords / 2, sizeof(Uint1)); - if (counts == NULL) { - sfree(thin_backbone); - BlastNaHashLookupTableDestruct(lookup); - return -1; - } - } + s_NaHashLookupFillPV(query, locations, lookup); + s_NaHashLookupRemovePolyAWords(lookup); /* count words in the database */ if (opt->db_filter) { - s_NaHashLookupFillPV(query, locations, lookup); - s_NaHashLookupScanSubjectForWordCounts(seqsrc, lookup, counts); + s_NaHashLookupScanSubjectForWordCounts(seqsrc, lookup, num_threads); + } + + /* find number of unique query words */ + for (i = 0;i < kNumWords >> lookup->pv_array_bts; i++) { + num_unique_words += s_Popcount(lookup->pv[i]); + } + + /* find number of bits to use for hash function */ + while (num_hash_bits < 32 && + (1LL << num_hash_bits) < num_unique_words) { + num_hash_bits++; + } + + lookup->backbone_size = 1 << num_hash_bits; + lookup->mask = lookup->backbone_size - 1; + + thin_backbone = calloc(lookup->backbone_size, sizeof(BackboneCell)); + if (!thin_backbone) { + return BLASTERR_MEMORY; + } + + /* it will store 1-based offsets, hence length + 1 */ + offsets = calloc(query->length + 1, sizeof(Int4)); + if (!offsets) { + return BLASTERR_MEMORY; } - BlastHashLookupIndexQueryExactMatches(thin_backbone, + offsets, lookup->word_length, BITS_PER_NUC, lookup->lut_word_length, query, locations, lookup->hash_callback, lookup->mask, - counts); + lookup->pv); + if (locations && lookup->word_length > lookup->lut_word_length && s_HasMaskAtHashEnabled(query_options)) { lookup->masked_locations = s_SeqLocListInvert(locations, query->length); } - s_BlastNaHashLookupFinalize(thin_backbone, lookup); + s_BlastNaHashLookupFinalize(thin_backbone, offsets, lookup); sfree(thin_backbone); - if (counts) { - sfree(counts); - } + sfree(offsets); return 0; } diff --git a/c++/src/algo/blast/core/blast_options.c b/c++/src/algo/blast/core/blast_options.c index f50d59e5..44bab419 100644 --- a/c++/src/algo/blast/core/blast_options.c +++ b/c++/src/algo/blast/core/blast_options.c @@ -1,4 +1,4 @@ -/* $Id: blast_options.c 506100 2016-07-01 15:46:25Z boratyng $ +/* $Id: blast_options.c 544251 2017-08-21 14:19:11Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -174,6 +174,33 @@ Int2 SWindowMaskerOptionsResetDB(SWindowMaskerOptions ** winmask_options, const return status; } +SReadQualityOptions* SReadQualityOptionsFree( + SReadQualityOptions* read_quality_options) +{ + if (read_quality_options) { + free(read_quality_options); + } + + return NULL; +} + +Int2 SReadQualityOptionsNew(SReadQualityOptions** read_quality_options) +{ + if (!read_quality_options) { + return 1; + } + + *read_quality_options = calloc(1, sizeof(SReadQualityOptions)); + if (!*read_quality_options) { + return 1; + } + + (*read_quality_options)->frac_ambig = 0.5; + (*read_quality_options)->entropy = 16; + + return 0; +} + SBlastFilterOptions* SBlastFilterOptionsFree(SBlastFilterOptions* filter_options) { if (filter_options) @@ -186,6 +213,8 @@ SBlastFilterOptions* SBlastFilterOptionsFree(SBlastFilterOptions* filter_options SRepeatFilterOptionsFree(filter_options->repeatFilterOptions); filter_options->windowMaskerOptions = SWindowMaskerOptionsFree(filter_options->windowMaskerOptions); + filter_options->readQualityOptions = + SReadQualityOptionsFree(filter_options->readQualityOptions); sfree(filter_options); } @@ -1371,7 +1400,7 @@ LookupTableOptionsValidate(EBlastProgramType program_number, return BLASTERR_OPTION_VALUE_INVALID; } - if (options->db_filter && options->word_size < BLAST_WORDSIZE_MAPPER) { + if (options->db_filter && options->word_size < 16) { Blast_MessageWrite(blast_msg, eBlastSevError, kBlastMessageNoContext, "The limit_lookup option can only be used with " "word size >= 16"); @@ -1424,6 +1453,8 @@ Int2 BlastHitSavingOptionsNew(EBlastProgramType program_number, (*options)->hsp_filt_opt = NULL; + (*options)->max_edit_distance = INT4_MAX; + return 0; } @@ -1445,6 +1476,7 @@ BLAST_FillHitSavingOptions(BlastHitSavingOptions* options, options->min_diag_separation = min_diag_separation; options->culling_limit = culling_limit; options->hsp_filt_opt = NULL; + options->max_edit_distance = INT4_MAX; return 0; diff --git a/c++/src/algo/blast/core/blast_parameters.c b/c++/src/algo/blast/core/blast_parameters.c index 360c31db..80c4e84d 100644 --- a/c++/src/algo/blast/core/blast_parameters.c +++ b/c++/src/algo/blast/core/blast_parameters.c @@ -1,4 +1,4 @@ -/* $Id: blast_parameters.c 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: blast_parameters.c 531703 2017-03-28 14:58:37Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -480,6 +480,10 @@ Int2 BlastExtensionParametersNew(EBlastProgramType program_number, params->gap_x_dropoff_final = options->gap_x_dropoff_final; } + if (program_number == eBlastTypeMapping) { + params->gap_x_dropoff = options->gap_x_dropoff; + } + return 0; } diff --git a/c++/src/algo/blast/core/blast_query_info.c b/c++/src/algo/blast/core/blast_query_info.c index cfe5a13f..1de6588c 100644 --- a/c++/src/algo/blast/core/blast_query_info.c +++ b/c++/src/algo/blast/core/blast_query_info.c @@ -1,4 +1,4 @@ -/* $Id: blast_query_info.c 517499 2016-10-25 17:20:41Z ivanov $ +/* $Id: blast_query_info.c 516747 2016-10-17 19:00:07Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/core/blast_seg.c b/c++/src/algo/blast/core/blast_seg.c index b8229fdb..9bbcd62c 100644 --- a/c++/src/algo/blast/core/blast_seg.c +++ b/c++/src/algo/blast/core/blast_seg.c @@ -1,4 +1,4 @@ -/* $Id: blast_seg.c 510159 2016-08-11 11:28:47Z ivanov $ +/* $Id: blast_seg.c 509955 2016-08-09 20:20:20Z rackerst $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/core/blast_traceback.c b/c++/src/algo/blast/core/blast_traceback.c index ed75f6e5..73790ecf 100644 --- a/c++/src/algo/blast/core/blast_traceback.c +++ b/c++/src/algo/blast/core/blast_traceback.c @@ -1,4 +1,4 @@ -/* $Id: blast_traceback.c 511802 2016-08-24 17:30:32Z ivanov $ +/* $Id: blast_traceback.c 525268 2017-01-23 15:04:37Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -662,6 +662,9 @@ Blast_TracebackFromHSPList(EBlastProgramType program_number, hsp_array[index] = Blast_HSPFree(hsp); } Blast_HSPListPurgeNullHSPs(hsp_list); + if(program_number == eBlastTypeBlastn) { + Blast_HSPListPurgeHSPsWithCommonEndpoints(program_number, hsp_list, TRUE); + } /* Sort HSPs by score again, as the scores might have changed. */ Blast_HSPListSortByScore(hsp_list); diff --git a/c++/src/algo/blast/core/blast_traceback_mt_priv.c b/c++/src/algo/blast/core/blast_traceback_mt_priv.c index bca2ad16..3b948d45 100644 --- a/c++/src/algo/blast/core/blast_traceback_mt_priv.c +++ b/c++/src/algo/blast/core/blast_traceback_mt_priv.c @@ -1,4 +1,4 @@ -/* $Id: blast_traceback_mt_priv.c 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: blast_traceback_mt_priv.c 513797 2016-09-15 14:43:46Z rackerst $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -191,7 +191,7 @@ BlastHSPResults* SThreadLocalDataArrayConsolidateResults(SThreadLocalDataArray* : MAX(thread_hitlist->worst_evalue, hits4query->worst_evalue); hits4query->low_score = !tid ? thread_hitlist->low_score - : MAX(thread_hitlist->low_score, hits4query->low_score); + : MIN(thread_hitlist->low_score, hits4query->low_score); } } diff --git a/c++/src/algo/blast/core/blast_util.c b/c++/src/algo/blast/core/blast_util.c index ae7ecd9f..0ec306c5 100644 --- a/c++/src/algo/blast/core/blast_util.c +++ b/c++/src/algo/blast/core/blast_util.c @@ -1,4 +1,4 @@ -/* $Id: blast_util.c 516334 2016-10-12 17:30:52Z ivanov $ +/* $Id: blast_util.c 511014 2016-08-17 18:42:49Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/algo/blast/core/hspfilter_culling.c b/c++/src/algo/blast/core/hspfilter_culling.c index 2912a962..6a905391 100644 --- a/c++/src/algo/blast/core/hspfilter_culling.c +++ b/c++/src/algo/blast/core/hspfilter_culling.c @@ -1,4 +1,4 @@ -/* $Id: hspfilter_culling.c 504861 2016-06-20 15:45:40Z boratyng $ +/* $Id: hspfilter_culling.c 545436 2017-09-06 17:13:21Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -618,20 +618,25 @@ s_BlastHSPCullingRun(void* data, BlastHSPList* hsp_list) BlastHSPCullingData * cull_data = data; BlastHSPCullingParams* params = cull_data->params; CTreeNode **c_tree = cull_data->c_tree; - + Boolean isBlastn = (params->program == eBlastTypeBlastn); if (!hsp_list) return 0; for (i=0; ihspcnt; ++i) { - /* wrap the hsp with a LinkedHSP structure */ A.hsp = hsp_list->hsp_array[i]; - A.cid = A.hsp->context; + A.cid = isBlastn ? (A.hsp->context - A.hsp->context % NUM_STRANDS) : A.hsp->context; A.sid = hsp_list->oid; A.merit = params->culling_max; - A.begin = A.hsp->query.offset; - A.end = A.hsp->query.end; + qlen = cull_data->query_info->contexts[A.hsp->context].query_length; + if(isBlastn && (A.hsp->context % NUM_STRANDS)) { + A.begin = qlen - A.hsp->query.end; + A.end = qlen - A.hsp->query.offset; + } + else { + A.begin = A.hsp->query.offset; + A.end = A.hsp->query.end; + } A.next = NULL; - qlen = cull_data->query_info->contexts[A.cid].query_length; if (! c_tree[A.cid]) { c_tree[A.cid] = s_CTreeNew(qlen); diff --git a/c++/src/algo/blast/core/hspfilter_mapper.c b/c++/src/algo/blast/core/hspfilter_mapper.c index 1eacbd33..58e0434d 100644 --- a/c++/src/algo/blast/core/hspfilter_mapper.c +++ b/c++/src/algo/blast/core/hspfilter_mapper.c @@ -1,4 +1,4 @@ -/* $Id: hspfilter_mapper.c 517510 2016-10-25 17:24:24Z ivanov $ +/* $Id: hspfilter_mapper.c 547624 2017-10-02 18:19:43Z fukanchi $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,6 +34,7 @@ #include #include #include +#include #include "jumper.h" /* Pair configurations, in the order of prefernece */ @@ -42,138 +43,6 @@ #define PAIR_PARALLEL 2 #define PAIR_NONE 3 -/* A container to create a list of HSPs */ -typedef struct HSPContainer -{ - BlastHSP* hsp; - struct HSPContainer* next; -} HSPContainer; - - -/* Create HSPContainer and take ownership of the HSP */ -static HSPContainer* HSPContainerNew(BlastHSP** hsp) -{ - HSPContainer* retval = calloc(1, sizeof(HSPContainer)); - if (!retval) { - return NULL; - } - retval->hsp = *hsp; - /* take ownership of this HSP */ - *hsp = NULL; - - return retval; -} - -/* Free the list of HSPs, along with the stored HSPs */ -static HSPContainer* HSPContainerFree(HSPContainer* hc) -{ - HSPContainer* h = hc; - while (h) { - HSPContainer* next = h->next; - if (h->hsp) { - Blast_HSPFree(h->hsp); - } - - sfree(h); - h = next; - } - - return NULL; -} - -/* Clone a list of HSP containers */ -static HSPContainer* HSPContainerDup(HSPContainer* inh) -{ - HSPContainer* retval = NULL; - HSPContainer* hi = NULL, *ho = NULL; - BlastHSP* new_hsp = NULL; - - if (!inh || !inh->hsp) { - return NULL; - } - - new_hsp = Blast_HSPClone(inh->hsp); - if (!new_hsp) { - return NULL; - } - retval = HSPContainerNew(&new_hsp); - if (!retval) { - Blast_HSPFree(new_hsp); - return NULL; - } - - hi = inh->next; - ho = retval; - for (; hi; hi = hi->next, ho = ho->next) { - new_hsp = Blast_HSPClone(hi->hsp); - if (!new_hsp) { - Blast_HSPFree(new_hsp); - HSPContainerFree(retval); - return NULL; - } - ho->next = HSPContainerNew(&new_hsp); - if (!ho->next) { - Blast_HSPFree(new_hsp); - HSPContainerFree(retval); - return NULL; - } - } - - return retval; -} - -/* A chain of HSPs: gene transcript sequence aligned to exons */ -typedef struct HSPChain -{ - Int4 context; /* query context */ - Int4 oid; /* subject oid */ - Int4 score; /* score for the whole chain */ - HSPContainer* hsps; /* list of HSPs that belong to this chain */ - Int4 compartment; /* compartment number for the chain (needed - for reporting results) */ - - Int4 count; /* number of chains with the same or larger score found - for the same query */ - struct HSPChain* pair; /* pointer to the pair (for paired reads) */ - Uint1 pair_conf; /* pair configuration */ - - Int4 adapter; /* adapter start position */ - Int4 polyA; /* start of polyA tail */ - struct HSPChain* next; -} HSPChain; - - -static HSPChain* HSPChainFree(HSPChain* chain_list) -{ - HSPChain* chain = chain_list; - while (chain) { - HSPChain* next = chain->next; - if (chain->pair) { - chain->pair->pair = NULL; - } - ASSERT(chain->hsps); - chain->hsps = HSPContainerFree(chain->hsps); - sfree(chain); - chain = next; - } - - return NULL; -} - -static HSPChain* HSPChainNew(Int4 context) -{ - HSPChain* retval = calloc(1, sizeof(HSPChain)); - if (!retval) { - return NULL; - } - retval->context = context; - retval->compartment = -1; - retval->adapter = -1; - - return retval; -} - - /* Insert a single chain into the list so that the list is sorted in decending order of chain scores. */ static Int4 s_HSPChainListInsertOne(HSPChain** list, HSPChain* chain, @@ -235,10 +104,48 @@ static Int4 s_HSPChainListInsertOne(HSPChain** list, HSPChain* chain, return 0; } + +static Boolean s_TestCutoffs(HSPChain* chain, Int4 cutoff_score, + Int4 cutoff_edit_dist) +{ + if (!chain) { + return FALSE; + } + + if (chain->score >= cutoff_score) { + + Int4 align_len = 0; + Int4 num_identical = 0; + HSPContainer* h = chain->hsps; + + if (cutoff_edit_dist < 0) { + return TRUE; + } + + for (; h; h = h->next) { + align_len += MAX(h->hsp->query.end - h->hsp->query.offset, + h->hsp->subject.end - h->hsp->subject.offset); + + num_identical += h->hsp->num_ident; + + ASSERT(h->hsp->num_ident <= + MAX(h->hsp->query.end - h->hsp->query.offset, + h->hsp->subject.end - h->hsp->subject.offset)); + } + + if (align_len - num_identical <= cutoff_edit_dist) { + return TRUE; + } + } + + return FALSE; +} + /* Insert chains into the list so that the list is sorted in descending order of chain scores. If chain is a list, each element is added separately. The list must be sorted before adding chain */ -static Int4 HSPChainListInsert(HSPChain** list, HSPChain* chain, +static Int4 HSPChainListInsert(HSPChain** list, HSPChain** chain, + Int4 cutoff_score, Int4 cutoff_edit_dist, Boolean check_for_duplicates) { HSPChain* ch = NULL; @@ -248,11 +155,16 @@ static Int4 HSPChainListInsert(HSPChain** list, HSPChain* chain, return -1; } - ch = chain; + ch = *chain; while (ch) { HSPChain* next = ch->next; ch->next = NULL; - status = s_HSPChainListInsertOne(list, ch, check_for_duplicates); + if (ch->score >= cutoff_score) { + status = s_HSPChainListInsertOne(list, ch, check_for_duplicates); + } + else { + HSPChainFree(ch); + } if (status) { return status; } @@ -260,6 +172,7 @@ static Int4 HSPChainListInsert(HSPChain** list, HSPChain* chain, } + *chain = NULL; return 0; } @@ -288,32 +201,6 @@ static Int4 HSPChainListTrim(HSPChain* list, Int4 margin) } -/* Clone a single HSP chain */ -static HSPChain* s_CloneChain(const HSPChain* chain) -{ - HSPChain* retval = NULL; - - if (!chain) { - return NULL; - } - - retval = HSPChainNew(chain->context); - if (!retval) { - return NULL; - } - retval->hsps = HSPContainerDup(chain->hsps); - if (!retval->hsps) { - HSPChainFree(retval); - return NULL; - } - retval->oid = chain->oid; - retval->score = chain->score; - retval->adapter = chain->adapter; - retval->polyA = chain->polyA; - - return retval; -} - /* Test that all pointers in the chain are set */ static Boolean s_TestChains(HSPChain* chain) { @@ -479,6 +366,7 @@ static Int4 s_ComputeAlignmentScore(BlastHSP* hsp, Int4 mismatch_score, Int4 last_pos = hsp->query.offset; Int4 score = 0; const Int4 kGap = 15; + Int4 num_identical = 0; for (i = 0;i < hsp->map_info->edits->num_edits;i++) { JumperEdit* e = &(hsp->map_info->edits->edits[i]); @@ -486,6 +374,7 @@ static Int4 s_ComputeAlignmentScore(BlastHSP* hsp, Int4 mismatch_score, ASSERT(num_matches >= 0); last_pos = e->query_pos; score += num_matches; + num_identical += num_matches; if (e->query_base == kGap) { ASSERT(e->subject_base != kGap); @@ -514,6 +403,8 @@ static Int4 s_ComputeAlignmentScore(BlastHSP* hsp, Int4 mismatch_score, } score += hsp->query.end - last_pos; + num_identical += hsp->query.end - last_pos; + hsp->num_ident = num_identical; return score; } @@ -775,27 +666,64 @@ static Int4 s_TrimHSP(BlastHSP* hsp, Int4 num, Boolean is_query, /* update the Jumper edit script */ if (is_start) { - Int4 pos = hsp->query.offset + delta_query; - i = 0; - while (i < hsp->map_info->edits->num_edits && - hsp->map_info->edits->edits[i].query_pos < pos) { - i++; + Int4 k = hsp->map_info->edits->num_edits - 1; + Int4 p = hsp->query.end - 1; + const Uint1 kGap = 15; + for (i = hsp->gap_info->size - 1;i >= 0;i--) { + if (hsp->gap_info->op_type[i] != eGapAlignDel) { + + p -= hsp->gap_info->num[i]; + while (k >= 0 && + hsp->map_info->edits->edits[k].query_pos > p && + hsp->map_info->edits->edits[k].query_base != kGap) { + + k--; + } + } + else { + Int4 j; + for (j = 0;j < hsp->gap_info->num[i];j++) { + ASSERT(k >= 0); + ASSERT(hsp->map_info->edits->edits[k].query_base == kGap); + k--; + } + } } - if (i > 0) { - for (k = 0;k < hsp->map_info->edits->num_edits - i;k++) { - hsp->map_info->edits->edits[k] = - hsp->map_info->edits->edits[k + i]; + k++; + if (k > 0) { + for (i = 0;i < hsp->map_info->edits->num_edits - k;i++) { + hsp->map_info->edits->edits[i] = + hsp->map_info->edits->edits[i + k]; } - hsp->map_info->edits->num_edits -= i; + hsp->map_info->edits->num_edits -= k; + ASSERT(hsp->map_info->edits->num_edits >= 0); } } else { - Int4 pos = hsp->query.end - delta_query - 1; - i = hsp->map_info->edits->num_edits - 1; - while (i >= 0 && hsp->map_info->edits->edits[i].query_pos > pos) { - i--; + Int4 k = 0; + Int4 p = hsp->query.offset; + const Uint1 kGap = 15; + + for (i = 0;i < hsp->gap_info->size;i++) { + if (hsp->gap_info->op_type[i] != eGapAlignDel) { + + p += hsp->gap_info->num[i]; + while (k < hsp->map_info->edits->num_edits && + hsp->map_info->edits->edits[k].query_pos < p && + hsp->map_info->edits->edits[k].query_base != kGap) { + + k++; + } + } + else { + Int4 j; + for (j = 0;j < hsp->gap_info->num[i];j++) { + ASSERT(hsp->map_info->edits->edits[k].query_base == kGap); + k++; + } + } } - hsp->map_info->edits->num_edits = i + 1; + hsp->map_info->edits->num_edits = k; } /* update HSP start positions */ @@ -1508,7 +1436,6 @@ static BlastHSP* s_MergeHSPs(const BlastHSP* first, const BlastHSP* second, score_opts->penalty, score_opts->gap_open, score_opts->gap_extend); - merged_hsp->num_ident += hsp->num_ident; merged_hsp->map_info->right_edge = hsp->map_info->right_edge; if (!merged_hsp->map_info->subject_overhangs) { @@ -1879,45 +1806,6 @@ static Int4 s_SortChains(HSPChain** saved, Int4 num_queries, return 0; } -/* Convert internal HSPChain structure to BlastHSPChain used to report results */ -static BlastHSPChain* s_HSPChainToBlastHSPChain(HSPChain* chain) -{ - BlastHSPChain* new_chain = NULL; - HSPContainer* h = NULL; - Int4 num_hsps = 0; - Int4 index = 0; - - if (!chain || !chain->hsps) { - return NULL; - } - - new_chain = Blast_HSPChainNew(); - if (!new_chain) { - return NULL; - } - - new_chain->query_index = chain->context / NUM_STRANDS; - new_chain->oid = chain->oid; - new_chain->score = chain->score; - new_chain->adapter = chain->adapter; - new_chain->polyA = chain->polyA; - - /* move hsps */ - for (h = chain->hsps; h; h = h->next) { - num_hsps++; - } - new_chain->num_hsps = num_hsps; - new_chain->hsp_array = calloc(num_hsps, sizeof(BlastHSP*)); - if (!new_chain->hsp_array) { - return NULL; - } - for (h = chain->hsps; h; h = h->next) { - new_chain->hsp_array[index++] = h->hsp; - h->hsp = NULL; - } - - return new_chain; -} /* Separate HSPs that overlap on the query to different chains (most output formats do not support query overlaps) */ @@ -1977,18 +1865,52 @@ static int s_RemoveOverlaps(HSPChain* chain, const ScoringOptions* score_opts, return 0; } + +/* Removes chains with scores below the cutoff */ +static int s_FilterChains(HSPChain** chains_ptr, Int4 cutoff_score, + Int4 cutoff_edit_distance) +{ + HSPChain* chain = *chains_ptr; + + while (chain && !s_TestCutoffs(chain, cutoff_score, cutoff_edit_distance) + /*chain->score < cutoff_score*/) { + HSPChain* next = chain->next; + chain->next = NULL; + HSPChainFree(chain); + chain = next; + } + *chains_ptr = chain; + + if (chain) { + while (chain && chain->next) { + if (!s_TestCutoffs(chain->next, cutoff_score, cutoff_edit_distance) + /*chain->next->score < cutoff_score*/) { + HSPChain* next = chain->next->next; + chain->next->next = NULL; + HSPChainFree(chain->next); + chain->next = next; + } + else { + chain = chain->next; + } + } + } + + return 0; +} + + /* Populate HSP data and save final results */ static int s_Finalize(HSPChain** saved, BlastMappingResults* results, const BlastQueryInfo* query_info, const BLAST_SequenceBlk* query_blk, const ScoringOptions* score_opts, - Boolean is_paired) + Boolean is_paired, + Int4 cutoff_score, + Int4 cutoff_edit_dist) { Int4 query_idx; - Int4 num_results = 0; - Int4 num = 0; const Int4 kPairBonus = 21; - Int4* num_unique_chains = NULL; /* remove poor scoring chains and find chain multiplicity */ if (!getenv("MAPPER_NO_PRUNNING")) { @@ -2009,34 +1931,6 @@ static int s_Finalize(HSPChain** saved, BlastMappingResults* results, /* FIXME: this may not be needed */ s_SortChains(saved, query_info->num_queries, s_CompareChainsByOid); - /* Compute number of results to store, and number of unique mappings for - each query (some chains may be copied to create pairs) */ - - num_unique_chains = calloc(query_info->num_queries, sizeof(Int4)); - if (!num_unique_chains) { - return -1; - } - - /* count number of unique mappings */ - for (query_idx = 0; query_idx < query_info->num_queries; query_idx++) { - HSPChain* chain = saved[query_idx]; - HSPChain* prev = chain; - - if (!chain) { - continue; - } - - num_unique_chains[query_idx]++; - - chain = chain->next; - for (; chain; chain = chain->next, prev = prev->next) { - if (prev->oid != chain->oid || - s_FindFragmentStart(prev) != s_FindFragmentStart(chain)) { - - num_unique_chains[query_idx]++; - } - } - } /* separate HSPs that overlap on the query into different chains */ if (getenv("MAPPER_NO_OVERLAPPED_HSP_MERGE")) { @@ -2056,74 +1950,43 @@ static int s_Finalize(HSPChain** saved, BlastMappingResults* results, } } - /* count number of chains to report */ - for (query_idx = 0; query_idx < query_info->num_queries; query_idx++) { - HSPChain* chain = saved[query_idx]; - for (; chain; chain = chain->next) { - num_results++; - } + /* remove chains with score below cutoff */ + for (query_idx = 0; query_idx < query_info->num_queries; query_idx++) { + s_FilterChains(&saved[query_idx], cutoff_score, cutoff_edit_dist); } - results->chain_array = calloc(num_results, sizeof(BlastHSPChain*)); - if (!results->chain_array) { - if (num_unique_chains) { - free(num_unique_chains); - } - return -1; - } - results->num_results = num_results; + /* Compute number of results to store, and number of unique mappings for + each query (some chains may be copied to create pairs) */ - /* iterate over queries */ - for (query_idx = 0;query_idx < query_info->num_queries;query_idx++) { + /* count number of unique mappings */ + for (query_idx = 0; query_idx < query_info->num_queries; query_idx++) { HSPChain* chain = saved[query_idx]; + HSPChain* prev = chain; + Int4 num_unique = 1; - /* skip queries for which there are no saved results */ if (!chain) { continue; } - for (; chain; chain = chain->next) { - BlastHSPChain* new_chain = NULL; - BlastHSPChain* pair = NULL; - - /* pairs are processed together so that we can store their pointers - so a chain whose pair's context is smaller was already processed - */ - if (chain->pair && chain->context > chain->pair->context) { - continue; - } - - new_chain = s_HSPChainToBlastHSPChain(chain); - ASSERT(new_chain); - if (!new_chain) { - return -1; - } - new_chain->multiplicity = num_unique_chains[new_chain->query_index]; - - results->chain_array[num++] = new_chain; - - if (chain->pair) { - pair = s_HSPChainToBlastHSPChain(chain->pair); - chain->pair->compartment = -1; + chain = chain->next; + for (; chain; chain = chain->next, prev = prev->next) { + if (prev->oid != chain->oid || + s_FindFragmentStart(prev) != s_FindFragmentStart(chain)) { - new_chain->pair = pair; - pair->pair = new_chain; - pair->multiplicity = num_unique_chains[pair->query_index]; - results->chain_array[num++] = pair; + num_unique++; } } + /* FIXME: for tabular output check count computed earlier */ + for (chain = saved[query_idx]; chain; chain = chain->next) { + chain->count = num_unique; + } } - ASSERT(num == results->num_results); - for (query_idx = 0; query_idx < query_info->num_queries; query_idx++) { - saved[query_idx] = HSPChainFree(saved[query_idx]); - } - if (num_unique_chains) { - sfree(num_unique_chains); - } + results->chain_array = saved; + results->num_queries = query_info->num_queries; return 0; } @@ -2141,12 +2004,11 @@ s_BlastHSPMapperFinal(void* data, void* mapping_results) if (spl_data->saved_chains) { s_Finalize(spl_data->saved_chains, results, spl_data->query_info, - spl_data->query, ¶ms->scoring_options, params->paired); + spl_data->query, ¶ms->scoring_options, params->paired, + params->cutoff_score, params->cutoff_edit_dist); } - if (spl_data->saved_chains) { - sfree(spl_data->saved_chains); - } + spl_data->saved_chains = NULL; return 0; } @@ -2221,7 +2083,7 @@ static HSPPath* HSPPathNew(void) } -#define NUM_SIGNALS 14 +#define NUM_SIGNALS 23 /* Find a split for HSPs overlapping on the query by finding splice signals in the subject sequence. The first HSP must have smaller query offset than the @@ -2237,23 +2099,32 @@ s_FindSpliceJunctionsForOverlaps(BlastHSP* first, BlastHSP* second, Uint1* query, Int4 query_len) { Int4 i, k; - /* splice signal pairs from PMC3167048 and spline output */ + /* splice signal pairs from include/algo/sequence/consensus_splice.hpp */ Uint1 signals[NUM_SIGNALS] = {0xb2, /* GTAG */ 0x71, /* CTAC (reverse complement) */ - 0x72, /* CTAG */ 0x92, /* GCAG */ - 0x9e, /* GCTG */ - 0x90, /* GCAA */ - 0x9a, /* GCGG */ + 0x79, /* CTGC */ + 0x31, /* ATAC */ + 0xb3, /* GTAT */ 0xbe, /* GTTG */ + 0x41, /* CAAC */ + 0xba, /* GTGG */ + 0x51, /* CCAC */ 0xb0, /* GTAA */ - 0x31, /* ATAC */ - 0x30, /* ATAA */ + 0xf1, /* TTAC */ + 0x82, /* GAAG */ + 0x7d, /* CTTC */ + 0xf2, /* TTAG */ + 0x70, /* CTAA */ 0x32, /* ATAG */ - 0x33, /* ATAT */ - - /*0x45, */ /* CACC */ - 0x1f /* ACTT */}; + 0x73, /* CTAT */ + 0xa2, /* GGAG */ + 0x75, /* CTCC */ + 0x33, /* ATAT (revese complemented is self) */ + 0x30, /* ATAA */ + 0xf3 /* TTAT */}; + + Boolean found = FALSE; Uint1* subject = NULL; Int4 overlap_len; @@ -2308,13 +2179,32 @@ s_FindSpliceJunctionsForOverlaps(BlastHSP* first, BlastHSP* second, Int4 num_edits = first->map_info->edits->num_edits; Int4 trim_by; - if (edits[num_edits - 1].query_pos == query_len - 1) { - edge >>= 2; - edge |= edits[num_edits - 1].subject_base << 2; + if (edits[num_edits - 1].query_pos >= first->query.end - 1) { + if (edits[num_edits - 1].subject_base != kGap) { + edge >>= 2; + edge |= edits[num_edits - 1].subject_base << 2; + } + } + else if (edits[num_edits - 1].query_pos == query_len - 2 && + edits[num_edits - 1].subject_base == kGap) { + + edge = (edge << 2) | query[query_len - 1]; } else { - edge = (edits[num_edits - 1].subject_base << 2) | - query[edits[num_edits - 1].query_pos + 1]; + if (edits[num_edits - 1].subject_base != kGap && + edits[num_edits - 1].query_base != kGap) { + + edge = (edits[num_edits - 1].subject_base << 2) | + query[edits[num_edits - 1].query_pos + 1]; + } + else if (edits[num_edits - 1].subject_base == kGap) { + edge = (query[edits[num_edits - 1].query_pos + 1] << 2 ) | + query[edits[num_edits - 1].query_pos + 2]; + } + else { + edge = (edits[num_edits - 1].subject_base << 2) | + query[edits[num_edits - 1].query_pos]; + } } trim_by = first->query.end - edits[ @@ -2342,12 +2232,25 @@ s_FindSpliceJunctionsForOverlaps(BlastHSP* first, BlastHSP* second, Int4 trim_by; if (edits[0].query_pos == 0) { - edge <<= 2; - edge |= edits[0].subject_base; + if (edits[0].subject_base != kGap) { + edge <<= 2; + edge |= edits[0].subject_base; + } + } + else if (edits[0].query_pos == 1 && + edits[0].subject_base == kGap) { + + edge = (edge << 2) | query[0]; } else { + edge = (query[edits[0].query_pos - 1] << 2) | edits[0].subject_base; + + if (edits[0].subject_base == kGap) { + edge = (query[edits[0].query_pos - 2] << 2) | + query[edits[0].query_pos - 1]; + } } trim_by = edits[0].query_pos - second->query.offset + 1; @@ -2371,6 +2274,9 @@ s_FindSpliceJunctionsForOverlaps(BlastHSP* first, BlastHSP* second, else { /* if the number of edits is the same we do not know how to divide the overlap */ + + first->map_info->right_edge &= ~MAPPER_SPLICE_SIGNAL; + second->map_info->left_edge &= ~MAPPER_SPLICE_SIGNAL; return 0; } } @@ -2384,6 +2290,8 @@ s_FindSpliceJunctionsForOverlaps(BlastHSP* first, BlastHSP* second, || (second->map_info->edits->num_edits > 0 && second->map_info->edits->edits[0].query_pos <= first->query.end)) { + first->map_info->right_edge &= ~MAPPER_SPLICE_SIGNAL; + second->map_info->left_edge &= ~MAPPER_SPLICE_SIGNAL; return 0; } @@ -2418,6 +2326,7 @@ s_FindSpliceJunctionsForOverlaps(BlastHSP* first, BlastHSP* second, first->subject.end -= d; first->gap_info->num[first->gap_info->size - 1] -= d; first->score -= d; + first->num_ident -= d; first->map_info->right_edge = (seq & 0xf0) >> 4; first->map_info->right_edge |= MAPPER_SPLICE_SIGNAL; @@ -2426,6 +2335,7 @@ s_FindSpliceJunctionsForOverlaps(BlastHSP* first, BlastHSP* second, second->subject.offset += d; second->gap_info->num[0] -= d; second->score -= d; + second->num_ident -= d; second->map_info->left_edge = seq & 0xf; second->map_info->left_edge |= MAPPER_SPLICE_SIGNAL; @@ -2701,6 +2611,14 @@ s_FindSpliceJunctionsForGap(BlastHSP* first, BlastHSP* second, Int4 q; Uint1 signal = 0; /* use only cannonical splice signals here */ + /* The procedure does not maximize score for unaligned bases of the query. + It only finds splice signals and then the best alignment it can find + for the unaligned bases. For limited number of unaligned query bases, + we can be sure of the splice site vs a continuous alignment, because a + continuous alignment would score better. But we do not compare + alignment scores between different splice sites, so we do not know + which splice site and signal is better; and many splice signals here + would lead to finding wrong splice sites. */ Uint1 signals[NUM_SIGNALS_CONSENSUS] = {0xb2, /* GTAG */ 0x71 /* CTAC */}; @@ -2923,18 +2841,19 @@ s_FindSpliceJunctionsForGap(BlastHSP* first, BlastHSP* second, /* Record subject bases pre and post alignment in HSP as possible splice signals and set a flag for recognized signals */ +/* Not used static Int4 s_FindSpliceSignals(BlastHSP* hsp, Uint1* query, Int4 query_len) { SequenceOverhangs* overhangs = NULL; - /* splice signals in the order of preference */ - Uint1 signals[NUM_SINGLE_SIGNALS] = {2, /* AG */ - 11, /* GT */ - 13, /* TC */ - 7, /* CT */ - 1, /* AC */ - 4, /* CA */ - 8, /* GA */ - 14 /* TG */}; + /--* splice signals in the order of preference *--/ + Uint1 signals[NUM_SINGLE_SIGNALS] = {2, /--* AG *--/ + 11, /--* GT *--/ + 13, /--* TC *--/ + 7, /--* CT *--/ + 1, /--* AC *--/ + 4, /--* CA *--/ + 8, /--* GA *--/ + 14 /--* TG *--/}; if (!hsp || !query) { return -1; @@ -2947,10 +2866,10 @@ static Int4 s_FindSpliceSignals(BlastHSP* hsp, Uint1* query, Int4 query_len) return -1; } - /* FIXME: check for polyA and adapters */ + /--* FIXME: check for polyA and adapters *--/ - /* search for a splice signal on the left edge, unless the query is aligned - from the beginning */ + /--* search for a splice signal on the left edge, unless the query is aligned + from the beginning *--/ if (hsp->query.offset == 0) { hsp->map_info->left_edge = MAPPER_EXON; } @@ -2982,10 +2901,10 @@ static Int4 s_FindSpliceSignals(BlastHSP* hsp, Uint1* query, Int4 query_len) hsp->map_info->left_edge = signal; hsp->map_info->left_edge |= MAPPER_SPLICE_SIGNAL; - /* trim alignment */ + /--* trim alignment *--/ s_TrimHSP(hsp, 1, TRUE, TRUE, -8, 0, -8); - /* update score at some point */ + /--* update score at some point *--/ found = TRUE; break; } @@ -2999,7 +2918,7 @@ static Int4 s_FindSpliceSignals(BlastHSP* hsp, Uint1* query, Int4 query_len) hsp->map_info->left_edge = signal; hsp->map_info->left_edge |= MAPPER_SPLICE_SIGNAL; - /* trim alignment */ + /--* trim alignment *--/ s_TrimHSP(hsp, i + 2, TRUE, TRUE, -8, 0, -8); found = TRUE; @@ -3009,8 +2928,8 @@ static Int4 s_FindSpliceSignals(BlastHSP* hsp, Uint1* query, Int4 query_len) } } - /* search for the splice signal on the right edge, unless the query is - aligned to the end */ + /--* search for the splice signal on the right edge, unless the query is + aligned to the end *--/ if (hsp->query.end == query_len) { hsp->map_info->right_edge = MAPPER_EXON; } @@ -3041,10 +2960,10 @@ static Int4 s_FindSpliceSignals(BlastHSP* hsp, Uint1* query, Int4 query_len) hsp->map_info->right_edge = signal; hsp->map_info->right_edge |= MAPPER_SPLICE_SIGNAL; - /* update HSP */ + /--* update HSP *--/ s_TrimHSP(hsp, 1, TRUE, FALSE, -8, 0, -8); - /* update score at some point */ + /--* update score at some point *--/ found = TRUE; break; } @@ -3059,7 +2978,7 @@ static Int4 s_FindSpliceSignals(BlastHSP* hsp, Uint1* query, Int4 query_len) hsp->map_info->right_edge = signal; hsp->map_info->right_edge |= MAPPER_SPLICE_SIGNAL; - /* update HSP */ + /--* update HSP *--/ s_TrimHSP(hsp, hsp->query.end - i, TRUE, FALSE, -8, 0, -8); found = TRUE; @@ -3071,6 +2990,7 @@ static Int4 s_FindSpliceSignals(BlastHSP* hsp, Uint1* query, Int4 query_len) return 0; } +*/ /* Search for splice signals between two HSPs in a chain. The HSPs in the @@ -3102,15 +3022,6 @@ s_FindSpliceJunctions(HSPChain* chains, query_info->contexts[context].query_offset; query_len = query_info->contexts[context].query_length; - - /* FIXME: check the overhangs of the first and last HSP and try finding - splice signal within a few bases in the HSP */ - if (!h->next) { - - s_FindSpliceSignals(h->hsp, query, query_len); - searched = TRUE; - } - while (h->next) { HSPContainer* next = h->next; ASSERT(next); @@ -3235,13 +3146,15 @@ s_FindSpliceJunctions(HSPChain* chains, a genome on a single strand, returns all top scoring chains */ static HSPChain* s_FindBestPath(HSPNode* nodes, Int4 num, HSPPath* path, Int4 oid, Boolean is_spliced, + Int4 longest_intron, + Int4 cutoff_score, const BLAST_SequenceBlk* query_blk, const BlastQueryInfo* query_info, const ScoringOptions* scoring_opts) { int i, k; Int4 best_score = 0; - const Int4 kMaxIntronLength = 900000; + const Int4 kMaxIntronLength = longest_intron; /* FIXME: use mismatch and/or gap extend penalty here */ HSPChain* retval = NULL; @@ -3409,6 +3322,11 @@ static HSPChain* s_FindBestPath(HSPNode* nodes, Int4 num, HSPPath* path, if (!node) { continue; } + + if (path->score < cutoff_score) { + continue; + } + ch->next = HSPChainNew((*node->hsp)->context); ASSERT(ch->next); if (!ch->next) { @@ -3779,6 +3697,7 @@ static Boolean s_FindBestPairs(HSPChain** first_list, pair_info[num_pairs].trim_first = 0; pair_info[num_pairs].trim_second = 0; pair_info[num_pairs].valid_pair = 0; + pair_info[num_pairs].distance = 0; /* if the chains align on the opposite strands */ ASSERT(first_frame != 0 && second_frame != 0); @@ -3960,7 +3879,7 @@ static Boolean s_FindBestPairs(HSPChain** first_list, } ASSERT(pair_info[i].second->pair); - pair = s_CloneChain(pair_info[i].second); + pair = CloneChain(pair_info[i].second); ASSERT(pair); ASSERT(s_TestChains(pair)); pair_info[i].second = pair; @@ -3968,7 +3887,7 @@ static Boolean s_FindBestPairs(HSPChain** first_list, pair->pair = ch; ch->pair_conf = pair->pair_conf = pair_info[i].conf; pair_info[i].valid_pair = TRUE; - HSPChainListInsert(second_list, pair, FALSE); + HSPChainListInsert(second_list, &pair, 0, -1, FALSE); } for (ch = *second_list; ch; ch = ch->next) { @@ -3990,7 +3909,7 @@ static Boolean s_FindBestPairs(HSPChain** first_list, } ASSERT(pair_info[i].first->pair); - pair = s_CloneChain(pair_info[i].first); + pair = CloneChain(pair_info[i].first); ASSERT(pair); ASSERT(s_TestChains(pair)); pair_info[i].first = pair; @@ -3998,7 +3917,7 @@ static Boolean s_FindBestPairs(HSPChain** first_list, pair->pair = ch; ch->pair_conf = pair->pair_conf = pair_info[i].conf; pair_info[i].valid_pair = TRUE; - HSPChainListInsert(first_list, pair, FALSE); + HSPChainListInsert(first_list, &pair, 0, -1, FALSE); } /* trim the alignments that overextend beyond the pair */ @@ -4057,6 +3976,67 @@ static Boolean s_FindBestPairs(HSPChain** first_list, } +HSPChain* FindPartialyCoveredQueries(void* data, Int4 oid, Int4 word_size) +{ + BlastHSPMapperData* spl_data = data; + BlastQueryInfo* query_info = spl_data->query_info; + HSPChain** saved = spl_data->saved_chains; + HSPChain* retval = NULL; + HSPChain* last; + Int4 i; + + for (i = 0;i < query_info->num_queries;i++) { + HSPChain* chain = saved[i]; + + for (chain = saved[i]; chain; chain = chain->next) { + HSPContainer* h; + + if (chain->oid != oid) { + continue; + } + + if (chain->score < 30) { + continue; + } + + h = chain->hsps; + + if (h->hsp->query.offset > word_size) { + + if (!retval) { + retval = CloneChain(chain); + last = retval; + } + else { + last->next = CloneChain(chain); + last = last->next; + } + + continue; + } + + while (h->next) { + h = h->next; + } + if (query_info->contexts[h->hsp->context].query_length - + h->hsp->query.end > word_size) { + + if (!retval) { + retval = CloneChain(chain); + last = retval; + } + else { + last->next = CloneChain(chain); + last = last->next; + } + } + } + } + + return retval; +} + + /** Perform writing task for paired reads * ownership of the HSP list and sets the dereferenced pointer to NULL. * @param data To store results to [in][out] @@ -4069,6 +4049,10 @@ s_BlastHSPMapperSplicedPairedRun(void* data, BlastHSPList* hsp_list) BlastHSPMapperParams* params = spl_data->params; const ScoringOptions* scoring_opts = ¶ms->scoring_options; Boolean is_spliced = params->splice; + const Int4 kLongestIntron = params->longest_intron; + Int4 cutoff_score = params->cutoff_score; + Int4* cutoff_score_fun = params->cutoff_score_fun; + Int4 cutoff_edit_dist = params->cutoff_edit_dist; BLAST_SequenceBlk* query_blk = spl_data->query; BlastQueryInfo* query_info = spl_data->query_info; const Int4 kDefaultMaxHsps = 1000; @@ -4185,12 +4169,14 @@ s_BlastHSPMapperSplicedPairedRun(void* data, BlastHSPList* hsp_list) parts of the query and the subject */ new_chains = s_FindBestPath(nodes, num_hsps, path, hsp_list->oid, is_spliced, + kLongestIntron, cutoff_score, query_blk, query_info, scoring_opts); ASSERT(new_chains); HSPChainListInsert(&chain_array[(context - first_context) / NUM_STRANDS], - new_chains, FALSE); + &new_chains, cutoff_score, cutoff_edit_dist, + FALSE); /* skip HSPs for the same context if there are more then max allowed per context */ @@ -4229,21 +4215,38 @@ s_BlastHSPMapperSplicedPairedRun(void* data, BlastHSPList* hsp_list) ASSERT(s_TestChains(second)); } + /* find cutoff score for the query */ + if (cutoff_score_fun[1] != 0) { + Int4 query_len = + query_info->contexts[query_idx * NUM_STRANDS].query_length; + cutoff_score = (cutoff_score_fun[0] + + cutoff_score_fun[1] * query_len) / 100; + } + /* save all chains and remove ones with scores lower than best score - kPairBonus */ if (first) { - HSPChainListInsert(&saved_chains[query_idx], first, TRUE); + HSPChainListInsert(&saved_chains[query_idx], &first, cutoff_score, + cutoff_edit_dist, TRUE); HSPChainListTrim(saved_chains[query_idx], kPairBonus); + + +#if _DEBUG + ASSERT(!saved_chains[query_idx] || + s_TestChainsSorted(saved_chains[query_idx])); +#endif } if (second) { - HSPChainListInsert(&saved_chains[query_idx + 1], second, TRUE); + HSPChainListInsert(&saved_chains[query_idx + 1], &second, + cutoff_score, cutoff_edit_dist, TRUE); HSPChainListTrim(saved_chains[query_idx + 1], kPairBonus); - } + #if _DEBUG - ASSERT(!chain_array[0] || s_TestChainsSorted(saved_chains[query_idx])); - ASSERT(!chain_array[1] || s_TestChainsSorted(saved_chains[query_idx + 1])); + ASSERT(!saved_chains[query_idx + 1] || + s_TestChainsSorted(saved_chains[query_idx + 1])); #endif + } /* make temporary lists empty */ chain_array[0] = chain_array[1] = NULL; @@ -4323,6 +4326,11 @@ BlastHSPMapperParamsNew(const BlastHitSavingOptions* hit_options, retval->hitlist_size = MAX(hit_options->hitlist_size, 10); retval->paired = hit_options->paired; retval->splice = hit_options->splice; + retval->longest_intron = hit_options->longest_intron; + retval->cutoff_score = hit_options->cutoff_score; + retval->cutoff_score_fun[0] = hit_options->cutoff_score_fun[0]; + retval->cutoff_score_fun[1] = hit_options->cutoff_score_fun[1]; + retval->cutoff_edit_dist = hit_options->max_edit_distance; retval->program = hit_options->program_number; retval->scoring_options.reward = scoring_options->reward; retval->scoring_options.penalty = scoring_options->penalty; diff --git a/c++/src/algo/blast/core/jumper.c b/c++/src/algo/blast/core/jumper.c index 7c47e74a..a0bbb355 100644 --- a/c++/src/algo/blast/core/jumper.c +++ b/c++/src/algo/blast/core/jumper.c @@ -1,4 +1,4 @@ -/* $Id $ +/* $Id: jumper.c 545586 2017-09-07 17:51:02Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,18 +33,20 @@ #include #include +#include #include "jumper.h" JUMP jumper_default [] = { {1, 1, 9, 0}, /* this was added for illumina */ - {2, 2, 10, 0}, /* try double mismatch before indels */ {1, 0, 10, 0}, /* insert in 1 */ {0, 1, 10, 0}, /* deletion in 1 */ - {1, 1, 6, 0}, - {1, 0, 7, 0}, - {0, 1, 7, 0}, + {2, 0, 10, 0}, + {0, 2, 10, 0}, + {3, 0, 13, 0}, + {0, 3, 13, 0}, + {2, 2, 12, 0}, /* try double mismatch */ {1, 0, 10, 2}, {0, 1, 10, 2}, {2, 0, 10, 2}, @@ -1113,7 +1115,8 @@ Int4 JumperExtendRightCompressedWithTracebackOptimal( int query_length, int subject_length, Int4 match_score, Int4 mismatch_score, Int4 gap_open_score, Int4 gap_extend_score, - int max_mismatches, int window, Uint4* table, + int max_mismatches, int window, + Int4 x_drop, Uint4* table, Int4* query_ext_len, Int4* subject_ext_len, JumperPrelimEditBlock* edit_script, Int4* best_num_identical, @@ -1142,6 +1145,7 @@ Int4 JumperExtendRightCompressedWithTracebackOptimal( cp = query; cpmax = cp + query_length; + cp1 = cpmax; /* or assume matches up to byte edge */ cq = 0; @@ -1200,11 +1204,15 @@ Int4 JumperExtendRightCompressedWithTracebackOptimal( i = jp->lng; cp1 = cp + jp->dcp; cq1 = cq + jp->dcq; - if (i + cp1 >= cpmax || i + cq1 >= cqmax) { + + if (cp1 >= cpmax || i + cq1 >= cqmax) { continue; } while (i--) { - if (cp1 >= cpmax || cq1 >= cqmax) { + if (cp1 >= cpmax) { + break; + } + if (/*cp1 >= cpmax ||*/ cq1 >= cqmax) { goto next_jp; } if (*cp1++ != UNPACK_BASE(subject, cq1)) { @@ -1247,6 +1255,10 @@ next_jp: *best_num_identical = num_identical; } + if (best_score - score > x_drop) { + break; + } + /* update recent errors */ if (jp->dcp == jp->dcq) { score += jp->dcp * mismatch_score; @@ -1307,7 +1319,7 @@ next_jp: cq += jp->dcq; /* we have already checked that these are matches */ - if (jp->ok == 0 && jp->lng) { + if (cp1 < cpmax && jp->ok == 0 && jp->lng) { cp += jp->lng; cq += jp->lng; ASSERT(edit_script->num_ops < edit_script->num_allocated); @@ -2089,7 +2101,8 @@ Int4 JumperExtendLeftCompressedWithTracebackOptimal( Int4 query_offset, Int4 subject_offset, Int4 match_score, Int4 mismatch_score, Int4 gap_open_score, Int4 gap_extend_score, - int max_mismatches, int window, Uint4* table, + int max_mismatches, int window, + Int4 x_drop, Uint4* table, Int4* query_ext_len, Int4* subject_ext_len, JumperPrelimEditBlock* edit_script, Int4* best_num_identical) @@ -2115,6 +2128,7 @@ Int4 JumperExtendLeftCompressedWithTracebackOptimal( cp = query + query_offset; cpmin = query; + cp1 = cpmin; /* or assume matches up to byte edge */ cq = subject_offset; @@ -2148,7 +2162,7 @@ Int4 JumperExtendLeftCompressedWithTracebackOptimal( jp = jumper; jp-- ; while (jp++) { /* 1, 1, 0, 0 = last always accepted */ - + if (!jp->lng) { break; } @@ -2170,11 +2184,15 @@ Int4 JumperExtendLeftCompressedWithTracebackOptimal( i = jp->lng; cp1 = cp - jp->dcp; cq1 = cq - jp->dcq; - if (cp1 - i < cpmin || cq1 - i < cqmin) { + + if (cp1 <= cpmin || cq1 - i < cqmin) { continue; } while (i--) { - if (cp1 < cpmin || cq1 < cqmin) { + if (cp1 < cpmin) { + break; + } + if (/*cp1 < cpmin ||*/ cq1 < cqmin) { goto next_jp; } if (*cp1-- != UNPACK_BASE(subject, cq1)) { @@ -2217,6 +2235,10 @@ next_jp: *best_num_identical = num_identical; } + if (best_score - score > x_drop) { + break; + } + /* update recent errors */ if (jp->dcp == jp->dcq) { score += jp->dcp * mismatch_score; @@ -2271,7 +2293,7 @@ next_jp: cq -= jp->dcq; /* we have already checked that these are matches */ - if (!jp->ok && jp->lng) { + if (cp1 > cpmin && !jp->ok && jp->lng) { cp -= jp->lng; cq -= jp->lng; ASSERT(edit_script->num_ops < edit_script->num_allocated); @@ -2539,6 +2561,7 @@ int JumperGappedAlignmentCompressedWithTraceback(const Uint1* query, -score_params->gap_extend, gap_align->max_mismatches, gap_align->mismatch_window, + gap_align->gap_x_dropoff, gap_align->jumper->table, &q_ext_len, &s_ext_len, *rev_prelim_block, @@ -2569,6 +2592,7 @@ int JumperGappedAlignmentCompressedWithTraceback(const Uint1* query, -score_params->gap_extend, gap_align->max_mismatches, gap_align->mismatch_window, + gap_align->gap_x_dropoff, gap_align->jumper->table, &q_ext_len, &s_ext_len, *fwd_prelim_block, @@ -2617,19 +2641,44 @@ Boolean JumperGoodAlign(const BlastGapAlignStruct* gap_align, Int4 num_identical, BlastContextInfo* context_info) { + Int4 align_len; + Int4 cutoff_score; + Int4 edit_dist; Int4 score = gap_align->score; - /* first check general score and coverage thresholds */ - if (score < hit_params->options->cutoff_score) { + align_len = MAX(gap_align->query_stop - gap_align->query_start, + gap_align->subject_stop - gap_align->subject_start); + + /* check percent identity */ + if (100.0 * (double)num_identical / (double)align_len + < hit_params->options->percent_identity) { + return FALSE; } - Int4 align_len = MAX(gap_align->query_stop - gap_align->query_start, - gap_align->subject_stop - gap_align->subject_start); + /* for spliced alignments thresholds apply to the final spliced + alignment */ + if (hit_params->options->splice) { + return TRUE; + } - if (100.0 * (double)num_identical / (double)align_len - < hit_params->options->percent_identity) { + cutoff_score = 0; + if (hit_params->options->cutoff_score_fun[1] != 0) { + cutoff_score = (hit_params->options->cutoff_score_fun[0] + + context_info->query_length * + hit_params->options->cutoff_score_fun[1]) / 100; + } + else { + cutoff_score = hit_params->options->cutoff_score; + } + /* for continuous alignments check score threshold here */ + if (score < cutoff_score) { + return FALSE; + } + + edit_dist = align_len - num_identical; + if (edit_dist > hit_params->options->max_edit_distance) { return FALSE; } @@ -3140,6 +3189,70 @@ static BlastHSP* s_CreateHSPForWordHit(Int4 q_offset, Int4 s_offset, return retval; } + +static BlastHSP* s_CreateHSP(Uint1* query_seq, + Int4 query_len, + Int4 context, + BlastQueryInfo* query_info, + BlastGapAlignStruct* gap_align, + BLAST_SequenceBlk* subject, + const BlastScoringParameters* score_params, + const BlastHitSavingParameters* hit_params) +{ + Int4 num_identical = 0; + Int4 status; + BlastHSP* new_hsp = NULL; + + if (!getenv("MAPPER_NO_GAP_SHIFT")) { + s_ShiftGaps(gap_align, query_seq, subject->sequence, + query_len, subject->length, + score_params->penalty, &num_identical); + } + + gap_align->edit_script = JumperPrelimEditBlockToGapEditScript( + gap_align->jumper->left_prelim_block, + gap_align->jumper->right_prelim_block); + + + status = Blast_HSPInit(gap_align->query_start, + gap_align->query_stop, + gap_align->subject_start, + gap_align->subject_stop, + gap_align->query_start, + gap_align->subject_start, + context, + query_info->contexts[context].frame, + subject->frame, + gap_align->score, + &(gap_align->edit_script), + &new_hsp); + + if (!new_hsp || status) { + return NULL; + } + new_hsp->map_info = BlastHSPMappingInfoNew(); + if (!new_hsp->map_info) { + return NULL; + } + + new_hsp->num_ident = num_identical; + new_hsp->evalue = 0.0; + new_hsp->map_info->edits = + JumperFindEdits(query_seq, subject->sequence, gap_align); + + if (hit_params->options->splice) { + /* FIXME: This is currently needed because these splice + sites are used in finding splice signals for overlapping + HSPs */ + JumperFindSpliceSignals(new_hsp, query_len, subject->sequence, + subject->length); + + s_SaveSubjectOverhangs(new_hsp, subject->sequence, query_len); + } + + return new_hsp; +} + /* for mapping this may only work if we hash genome and scan reads */ Int4 BlastNaExtendJumper(BlastOffsetPair* offset_pairs, Int4 num_hits, @@ -4023,3 +4136,427 @@ Int4 SubjectIndexIteratorPrev(SubjectIndexIterator* it) } +#define MAX_NUM_MATCHES 10 + +static Int4 DoAnchoredScan(Uint1* query_seq, Int4 query_len, + Int4 query_from, Int4 context, + BLAST_SequenceBlk* subject, + Int4 subject_from, Int4 subject_to, + BlastQueryInfo* query_info, + BlastGapAlignStruct* gap_align, + const BlastScoringParameters* score_params, + const BlastHitSavingParameters* hit_params, + BlastHSPList* hsp_list) + +{ + Int4 q = query_from; + BlastHSP* hsp = NULL; + Int4 num = 0; + const int kMaxNumMatches = MAX_NUM_MATCHES; + Int4 num_extensions = 0; + Int4 word_size = 12; + Int4 big_word_size = 0; + Int4 scan_step; + + Uint4 word[MAX_NUM_MATCHES]; + Int4 query_pos[MAX_NUM_MATCHES]; + Uint4 w; + Int4 i; + + Int4 scan_from = subject_from; + Int4 scan_to = MIN(subject_to, subject->length - 1); + + Uint4 mask = (1U << (2 * word_size)) - 1; + + Int4 best_score = 0; + Int4 num_matches = 0; + Uint1* s = NULL; + Int4 last_idx = 0; + Int4 num_bytes = 0; + Int4 num_words = 0; + + Boolean is_right = subject_from < subject_to; + if (is_right) { + big_word_size = MIN(MAX(query_len - query_from - 5, word_size), 24); + scan_step = big_word_size - word_size + 1; + + } + else { + big_word_size = MIN(MAX(query_from - 5, word_size), 24); + scan_step = -(big_word_size - word_size + 1); + } + + if ((is_right && (query_len - query_from + 1 < big_word_size || + scan_to - subject_from < big_word_size)) || + (!is_right && (query_from < big_word_size || + subject_from - scan_to < big_word_size))) { + + return 0; + } + + + + if (is_right) { + for (; q + big_word_size < query_len && num_words < MAX_NUM_MATCHES; q++) { + + /* skip over ambiguous bases */ + while (q + big_word_size <= query_len) { + for (i = 0;i < big_word_size;i++) { + if ((query_seq[q + i] & 0xfc) != 0) { + q = q + i + 1; + break; + } + } + + /* success */ + if (i == big_word_size) { + break; + } + + q++; + } + + /* not enough query left */ + if (q + big_word_size - 1 >= query_len) { + break; + } + + /* this is query word */ + word[num_words] = (query_seq[q] << 6) | (query_seq[q + 1] << 4) | + (query_seq[q + 2] << 2) | query_seq[q + 3]; + for (i = 4; i < word_size; i++) { + word[num_words] = (word[num_words] << 2) | query_seq[q + i]; + } + + /* do not search for PolyA words */ + if (word[num_words] == 0 || word[num_words] == 0xffffff) { + continue; + } + + query_pos[num_words] = q; + num_words++; + } + } + else { + q -= big_word_size; + for (; q >= 0 && num_words < MAX_NUM_MATCHES; q--) { + + /* skip over ambiguous bases */ + while (q >= 0) { + for (i = 0;i < big_word_size;i++) { + if ((query_seq[q + i] & 0xfc) != 0) { + q = q - big_word_size + i; + break; + } + } + + /* success */ + if (i == big_word_size) { + break; + } + + q--; + } + + /* not enough query left */ + if (q < 0) { + break; + } + + /* this is query word */ + word[num_words] = (query_seq[q] << 6) | (query_seq[q + 1] << 4) | + (query_seq[q + 2] << 2) | query_seq[q + 3]; + for (i = 4; i < word_size; i++) { + word[num_words] = (word[num_words] << 2) | query_seq[q + i]; + } + + /* do not search for PolyA words */ + if (word[num_words] == 0 || word[num_words] == 0xffffff) { + continue; + } + + query_pos[num_words] = q; + num_words++; + } + + } + + if (num_words == 0) { + return 0; + } + + for (i = scan_from; (scan_from < scan_to && i < scan_to) || + (scan_from > scan_to && i > scan_to); i += scan_step) { + + Int4 local_ungapped_ext; + Int4 shift; + /* subject word */ + Uint4 index; + + Int4 q_offset; + Int4 s_offset; + Int4 num_identical; + Int4 k; + + if (num_matches > kMaxNumMatches) { + break; + } + + s = subject->sequence + i / COMPRESSION_RATIO; + + w = (Int4)s[0] << 16 | s[1] << 8 | s[2]; + last_idx = 3; + num_bytes = word_size / COMPRESSION_RATIO; + ASSERT(num_bytes < 9); + for (; last_idx < num_bytes; last_idx++) { + w = w << 8 | s[last_idx]; + } + + if (i % COMPRESSION_RATIO != 0) { + w = (w << 8) | s[last_idx]; + shift = 2 * (COMPRESSION_RATIO - (i % COMPRESSION_RATIO)); + index = (w >> shift) & mask; + } + else { + index = w & mask; + } + + + for (k = 0;k < num_words; k++) { + if (index == word[k]) { + break; + } + } + + if (k >= num_words) { + continue; + } + + q_offset = query_pos[k]; + s_offset = i; + + for (k = word_size;k < big_word_size;k++) { + if (query_seq[q_offset + k] != UNPACK_BASE(subject->sequence, s_offset + k)) { + break; + } + } + if (k < big_word_size) { + continue; + } + + + num_matches++; + + num_extensions++; + + num_identical = 0; + JumperGappedAlignmentCompressedWithTraceback(query_seq, + subject->sequence, + query_len, + subject->length, + q_offset, + s_offset, + gap_align, + score_params, + &num_identical, + &local_ungapped_ext); + + + if (gap_align->score <= best_score) { + continue; + } + + best_score = gap_align->score; + + if (hsp) { + hsp = Blast_HSPFree(hsp); + } + + hsp = s_CreateHSP(query_seq, query_len, context, + query_info, gap_align, subject, + score_params, hit_params); + + + if (hsp->score >= query_len - query_from) { + break; + } + + + } + + if (hsp) { + Blast_HSPListSaveHSP(hsp_list, hsp); + num++; + } + + return num; +} + + +Int2 DoAnchoredSearch(BLAST_SequenceBlk* query, + BLAST_SequenceBlk* subject, + Int4 word_size, + BlastQueryInfo* query_info, + BlastGapAlignStruct* gap_align, + const BlastScoringParameters* score_params, + const BlastHitSavingParameters* hit_params, + BlastHSPStream* hsp_stream) +{ + HSPChain* chains = NULL; + HSPChain* ch = NULL; + BlastHSPList* hsp_list = NULL; + + if (!query || !subject || !query_info || !gap_align || !score_params || + !hit_params || !hsp_stream) { + + return -1; + } + + hsp_list = Blast_HSPListNew(MAX(query_info->num_queries, 100)); + if (!hsp_list) { + return BLASTERR_MEMORY; + } + hsp_list->oid = subject->oid; + + /* Collect HSPs for HSP chains with that cover queries partially */ + MT_LOCK_Do(hsp_stream->x_lock, eMT_Lock); + chains = FindPartialyCoveredQueries(hsp_stream->writer->data, + hsp_list->oid, word_size); + MT_LOCK_Do(hsp_stream->x_lock, eMT_Unlock); + + + /* Search uncovered parts of the queries */ + for (ch = chains; ch; ch = ch->next) { + HSPContainer* h = ch->hsps; + Int4 context = h->hsp->context; + Uint1* query_seq = + query->sequence + query_info->contexts[context].query_offset; + Int4 query_len = query_info->contexts[context].query_length; + Int4 num = 0; + + + if (h->hsp->query.offset >= 12) { + + num = DoAnchoredScan(query_seq, query_len, + h->hsp->query.offset - 1, + context, subject, + h->hsp->subject.offset - 1, + h->hsp->subject.offset - 1 - + hit_params->options->longest_intron, + query_info, gap_align, score_params, + hit_params, hsp_list); + } + + while (h->next) { + h = h->next; + } + + + if (query_len - h->hsp->query.end > 12) { + + num += DoAnchoredScan(query_seq, query_len, h->hsp->query.end, + context, subject, + h->hsp->subject.end, + h->hsp->subject.end + + hit_params->options->longest_intron, + query_info, gap_align, score_params, + hit_params, hsp_list); + } + + if (num) { + for (h = ch->hsps; h; h = h->next) { + Blast_HSPListSaveHSP(hsp_list, h->hsp); + h->hsp = NULL; + } + } + } + + BlastHSPStreamWrite(hsp_stream, &hsp_list); + HSPChainFree(chains); + Blast_HSPListFree(hsp_list); + + return 0; +} + +#define NUM_DIMERS (1 << 4) + +/* Compute enrtopy of 2-mers in a BLASTNA sequence */ +static Int4 s_FindDimerEntropy(Uint1* sequence, Int4 length) +{ + Int4 counts[NUM_DIMERS]; + Int4 num = 0; + Int4 i; + double sum = 0.0; + + memset(counts, 0, NUM_DIMERS * sizeof(Int4)); + // count dimers + for (i=0;i < length - 1;i++) { + Uint1 base_1 = sequence[i]; + Uint1 base_2 = sequence[i + 1]; + + if ((base_1 & 0xfc) == 0 && (base_2 & 0xfc) == 0) { + Int4 dimer = (base_1 << 2) | base_2; + counts[dimer]++; + num++; + } + } + + // compute amount of information in the sequence + for (i=0;i < NUM_DIMERS;i++) { + if (counts[i]) { + sum += (double)counts[i] * log((double)counts[i] / num); + } + } + + return -sum * (1.0 /(log(16.0))) + 0.5; +} + + +static Int2 s_MaskSequence(Int4 offset, Int4 length, BlastSeqLoc** seq_locs) +{ + BlastSeqLoc* loc = calloc(1, sizeof(BlastSeqLoc)); + if (!loc) { + return BLASTERR_MEMORY; + } + loc->ssr = calloc(1, sizeof(SSeqRange)); + if (!loc->ssr) { + free(loc); + return BLASTERR_MEMORY; + } + loc->ssr->left = offset; + loc->ssr->right = offset + length - 1; + *seq_locs = loc; + + return 0; +} + +Int2 FilterQueriesForMapping(Uint1* sequence, Int4 length, Int4 offset, + const SReadQualityOptions* options, + BlastSeqLoc** seq_loc) +{ + const double kMaxFractionOfAmbiguousBases = options->frac_ambig; + Int4 i; + Int4 num = 0; + Int4 entropy; + Int2 status = 0; + + for (i = 0;i < length;i++) { + if (sequence[i] & 0xfc) { + num++; + } + } + + if ((double)num / length > kMaxFractionOfAmbiguousBases) { + status = s_MaskSequence(offset, length, seq_loc); + return status; + } + + entropy = s_FindDimerEntropy(sequence, length); + if (entropy <= options->entropy) { + status = s_MaskSequence(offset, length, seq_loc); + } + + return status; +} + + diff --git a/c++/src/algo/blast/core/jumper.h b/c++/src/algo/blast/core/jumper.h index 9895ddba..af8bf513 100644 --- a/c++/src/algo/blast/core/jumper.h +++ b/c++/src/algo/blast/core/jumper.h @@ -1,4 +1,4 @@ -/* $Id: jumper.h 504946 2016-06-21 13:53:04Z madden $ +/* $Id: jumper.h 533522 2017-04-17 15:50:34Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,6 +37,8 @@ #include #include #include +#include +#include #ifdef __cplusplus @@ -273,6 +275,36 @@ typedef struct SequenceOverhangs SequenceOverhangs* SequenceOverhangsFree(SequenceOverhangs* overhangs); +/** Do a search against a single subject with smaller word size and with no + * database word frequency filtering, for queries that have partial hits. + * The subject is scanned only where one expects to find an exon. This is to + * find smaller and low complexity exons. + * @param query Concatenated query [in] + * @param subject Subject sequence [in] + * @param word_size Minimum word size to use in scanning [in] + * @param query_info Query information structure [in] + * @param gap_align Data for gapped alignment [in|out] + * @param score_params Alignment scoring parameters [in] + * @param hit_params Hit saving parameters [in] + * @param hsp_stream Queries will be selected based on hits in hsp_stream and + * new hits will be written to it [in|out] + * @return Status + */ +Int2 DoAnchoredSearch(BLAST_SequenceBlk* query, + BLAST_SequenceBlk* subject, + Int4 word_size, + BlastQueryInfo* query_info, + BlastGapAlignStruct* gap_align, + const BlastScoringParameters* score_params, + const BlastHitSavingParameters* hit_params, + BlastHSPStream* hsp_stream); + + +Int2 FilterQueriesForMapping(Uint1* sequence, Int4 length, Int4 offset, + const SReadQualityOptions* options, + BlastSeqLoc** seq_loc); + + #ifdef __cplusplus } #endif diff --git a/c++/src/algo/blast/core/lookup_wrap.c b/c++/src/algo/blast/core/lookup_wrap.c index a289778f..7d27925c 100644 --- a/c++/src/algo/blast/core/lookup_wrap.c +++ b/c++/src/algo/blast/core/lookup_wrap.c @@ -1,4 +1,4 @@ -/* $Id: lookup_wrap.c 506102 2016-07-01 15:48:06Z boratyng $ +/* $Id: lookup_wrap.c 544840 2017-08-28 16:54:47Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -51,6 +51,21 @@ Int2 LookupTableWrapInit(BLAST_SequenceBlk* query, LookupTableWrap** lookup_wrap_ptr, const BlastRPSInfo *rps_info, Blast_Message* *error_msg, BlastSeqSrc* seqsrc) +{ + return LookupTableWrapInit_MT(query, lookup_options, query_options, + lookup_segments, sbp, lookup_wrap_ptr, + rps_info, error_msg, seqsrc, 1); +} + + +Int2 LookupTableWrapInit_MT(BLAST_SequenceBlk* query, + const LookupTableOptions* lookup_options, + const QuerySetUpOptions* query_options, + BlastSeqLoc* lookup_segments, BlastScoreBlk* sbp, + LookupTableWrap** lookup_wrap_ptr, const BlastRPSInfo *rps_info, + Blast_Message* *error_msg, + BlastSeqSrc* seqsrc, + Uint4 num_threads) { Int2 status = 0; LookupTableWrap* lookup_wrap; @@ -102,6 +117,7 @@ Int2 LookupTableWrapInit(BLAST_SequenceBlk* query, case eSmallNaLookupTable: case eNaLookupTable: case eMBLookupTable: + case eNaHashLookupTable: { Int4 lut_width; Int4 max_q_off; @@ -131,6 +147,13 @@ Int2 LookupTableWrapInit(BLAST_SequenceBlk* query, lookup_options, query_options, lut_width); } } + else if (lookup_wrap->lut_type == eNaHashLookupTable) { + status = BlastNaHashLookupTableNew(query, lookup_segments, + (BlastNaHashLookupTable**) &(lookup_wrap->lut), + lookup_options, query_options, seqsrc, + num_threads); + + } else { BlastNaLookupTableNew(query, lookup_segments, (BlastNaLookupTable* *) &(lookup_wrap->lut), @@ -140,12 +163,6 @@ Int2 LookupTableWrapInit(BLAST_SequenceBlk* query, ASSERT( lookup_wrap->lut_type != eMixedMBLookupTable ); break; - case eNaHashLookupTable: - status = BlastNaHashLookupTableNew(query, lookup_segments, - (BlastNaHashLookupTable**) &(lookup_wrap->lut), - lookup_options, query_options, seqsrc); - break; - case ePhiLookupTable: case ePhiNaLookupTable: { diff --git a/c++/src/algo/blast/core/na_ungapped.c b/c++/src/algo/blast/core/na_ungapped.c index 1c3d5b36..10f6a6d2 100644 --- a/c++/src/algo/blast/core/na_ungapped.c +++ b/c++/src/algo/blast/core/na_ungapped.c @@ -1,4 +1,4 @@ -/* $Id: na_ungapped.c 505619 2016-06-27 18:51:47Z boratyng $ +/* $Id: na_ungapped.c 545406 2017-09-06 15:04:39Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -220,13 +220,16 @@ s_NuclUngappedExtendExact(BLAST_SequenceBlk * query, sum = 0; base = 3 - (s_off % COMPRESSION_RATIO); + /* X_current is used to break out of loop if score goes negative */ + Int4 X_current=X; while (s < sf || (s == sf && base > remainder)) { ch = *s; if ((sum += matrix[*q++][NCBI2NA_UNPACK_BASE(ch, base)]) > 0) { q_end = q; score += sum; + X_current = (-score > X) ? -score : X; sum = 0; - } else if (sum < X) + } else if (sum < X_current) break; if (base == 0) { base = 3; @@ -2018,6 +2021,11 @@ JumperNaWordFinder(BLAST_SequenceBlk * subject, ASSERT(scansub); + if (word_hits) { + memset(word_hits->last_pos, 0, + (query_info->last_context + 1) * sizeof(Int4)); + } + if (getenv("MAPPER_USE_SMALL_WORDS")) { s_index = SubjectIndexNew(subject, 10000, SUBJECT_INDEX_WORD_LENGTH); } @@ -2055,7 +2063,9 @@ JumperNaWordFinder(BLAST_SequenceBlk * subject, numer of word hits managable. The other check is still necessary, because depending on extension more word hits can be discarded. */ - if (last_d == diag && s_off - last_p < lut_word_length + 3) { + if (last_p != 0 && last_d == diag && + s_off - last_p < lut_word_length + 1) { + continue; } ASSERT(index < word_hits->num_arrays); @@ -2064,9 +2074,6 @@ JumperNaWordFinder(BLAST_SequenceBlk * subject, /* if the word hit list for the current word hit is full, then extend hits from this list */ if (word_hits->num[index] >= word_hits->array_size) { - Int4 range = word_hits->pair_arrays[index][ - word_hits->num[index] - 1].qs_offsets.s_off + - lut_word_length; hits_extended += BlastNaExtendJumper( word_hits->pair_arrays[index], word_hits->num[index], @@ -2077,7 +2084,7 @@ JumperNaWordFinder(BLAST_SequenceBlk * subject, query_info, gap_align, hsp_list, - range, + scan_range[2] + lut_word_length, s_index); word_hits->num[index] = 0; @@ -2117,9 +2124,6 @@ JumperNaWordFinder(BLAST_SequenceBlk * subject, /* extend word hits from all lists */ for (i = 0;i < word_hits->num_arrays;i++) { if (word_hits->num[i] > 0) { - Int4 range = word_hits->pair_arrays[i][ - word_hits->num[i] - 1].qs_offsets.s_off + - lut_word_length; hits_extended += BlastNaExtendJumper(word_hits->pair_arrays[i], word_hits->num[i], word_params, score_params, @@ -2129,7 +2133,7 @@ JumperNaWordFinder(BLAST_SequenceBlk * subject, query_info, gap_align, hsp_list, - range, + scan_range[2] + lut_word_length, s_index); } diff --git a/c++/src/algo/blast/core/spliced_hits.c b/c++/src/algo/blast/core/spliced_hits.c new file mode 100644 index 00000000..ee9de4de --- /dev/null +++ b/c++/src/algo/blast/core/spliced_hits.c @@ -0,0 +1,188 @@ +/* $Id: spliced_hits.c 532442 2017-04-05 13:47:44Z boratyng $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Greg Boratyn + * + * Implementaion of spliced alignment methods + * + */ + + +#include + + +/* Create HSPContainer and take ownership of the HSP */ +HSPContainer* HSPContainerNew(BlastHSP** hsp) +{ + HSPContainer* retval = calloc(1, sizeof(HSPContainer)); + if (!retval) { + return NULL; + } + retval->hsp = *hsp; + /* take ownership of this HSP */ + *hsp = NULL; + + return retval; +} + +/* Free the list of HSPs, along with the stored HSPs */ +HSPContainer* HSPContainerFree(HSPContainer* hc) +{ + HSPContainer* h = hc; + while (h) { + HSPContainer* next = h->next; + if (h->hsp) { + Blast_HSPFree(h->hsp); + } + + sfree(h); + h = next; + } + + return NULL; +} + +/* Clone a list of HSP containers */ +HSPContainer* HSPContainerDup(HSPContainer* inh) +{ + HSPContainer* retval = NULL; + HSPContainer* hi = NULL, *ho = NULL; + BlastHSP* new_hsp = NULL; + + if (!inh || !inh->hsp) { + return NULL; + } + + new_hsp = Blast_HSPClone(inh->hsp); + if (!new_hsp) { + return NULL; + } + retval = HSPContainerNew(&new_hsp); + if (!retval) { + Blast_HSPFree(new_hsp); + return NULL; + } + + hi = inh->next; + ho = retval; + for (; hi; hi = hi->next, ho = ho->next) { + new_hsp = Blast_HSPClone(hi->hsp); + if (!new_hsp) { + Blast_HSPFree(new_hsp); + HSPContainerFree(retval); + return NULL; + } + ho->next = HSPContainerNew(&new_hsp); + if (!ho->next) { + Blast_HSPFree(new_hsp); + HSPContainerFree(retval); + return NULL; + } + } + + return retval; +} + + +HSPChain* HSPChainFree(HSPChain* chain_list) +{ + HSPChain* chain = chain_list; + while (chain) { + HSPChain* next = chain->next; + if (chain->pair) { + chain->pair->pair = NULL; + } + ASSERT(chain->hsps); + chain->hsps = HSPContainerFree(chain->hsps); + sfree(chain); + chain = next; + } + + return NULL; +} + +HSPChain* HSPChainNew(Int4 context) +{ + HSPChain* retval = calloc(1, sizeof(HSPChain)); + if (!retval) { + return NULL; + } + retval->context = context; + retval->adapter = -1; + + return retval; +} + +/* Clone a single HSP chain */ +HSPChain* CloneChain(const HSPChain* chain) +{ + HSPChain* retval = NULL; + + if (!chain) { + return NULL; + } + + retval = HSPChainNew(chain->context); + if (!retval) { + return NULL; + } + retval->hsps = HSPContainerDup(chain->hsps); + if (!retval->hsps) { + HSPChainFree(retval); + return NULL; + } + retval->oid = chain->oid; + retval->score = chain->score; + retval->adapter = chain->adapter; + retval->polyA = chain->polyA; + + return retval; +} + +BlastMappingResults* Blast_MappingResultsNew(void) +{ + BlastMappingResults* retval = calloc(1, sizeof(BlastMappingResults)); + return retval; +} + +BlastMappingResults* Blast_MappingResultsFree(BlastMappingResults* results) +{ + if (!results) { + return NULL; + } + + if (results->chain_array) { + Int4 i; + for (i = 0;i < results->num_queries;i++) { + HSPChainFree(results->chain_array[i]); + } + sfree(results->chain_array); + } + sfree(results); + + return NULL; +} + + diff --git a/c++/src/algo/blast/dbindex/CMakeLists.txt b/c++/src/algo/blast/dbindex/CMakeLists.txt new file mode 100644 index 00000000..f256367e --- /dev/null +++ b/c++/src/algo/blast/dbindex/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xalgoblastdbindex.lib.txt) + +# Recurse subdirectories +add_subdirectory(makeindex) diff --git a/c++/src/algo/blast/dbindex/CMakeLists.xalgoblastdbindex.lib.txt b/c++/src/algo/blast/dbindex/CMakeLists.xalgoblastdbindex.lib.txt new file mode 100644 index 00000000..4018d6d4 --- /dev/null +++ b/c++/src/algo/blast/dbindex/CMakeLists.xalgoblastdbindex.lib.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/dbindex/Makefile.xalgoblastdbindex.lib +# +add_library(xalgoblastdbindex + sequence_istream_fasta sequence_istream_bdb dbindex dbindex_factory + dbindex_search +) +add_dependencies(xalgoblastdbindex + seqset +) + +target_link_libraries(xalgoblastdbindex + blast seqdb xobjread + xobjutil +) diff --git a/c++/src/algo/blast/dbindex/dbindex.cpp b/c++/src/algo/blast/dbindex/dbindex.cpp index a709801a..044c26a6 100644 --- a/c++/src/algo/blast/dbindex/dbindex.cpp +++ b/c++/src/algo/blast/dbindex/dbindex.cpp @@ -1,4 +1,4 @@ -/* $Id: dbindex.cpp 363884 2012-05-21 15:54:30Z morgulis $ +/* $Id: dbindex.cpp 542542 2017-08-01 12:44:33Z dicuccio $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -252,7 +252,7 @@ void CIndexSuperHeader< } //------------------------------------------------------------------------- -const size_t GetIdxVolNumOIDs( const std::string & fname ) +size_t GetIdxVolNumOIDs( const std::string & fname ) { std::ifstream is( fname.c_str() ); Uint4 t, start, end; diff --git a/c++/src/algo/blast/dbindex/dbindex_factory.cpp b/c++/src/algo/blast/dbindex/dbindex_factory.cpp index 88101745..2605045a 100644 --- a/c++/src/algo/blast/dbindex/dbindex_factory.cpp +++ b/c++/src/algo/blast/dbindex/dbindex_factory.cpp @@ -1,4 +1,4 @@ -/* $Id: dbindex_factory.cpp 506382 2016-07-07 13:47:26Z morgulis $ +/* $Id: dbindex_factory.cpp 539175 2017-06-19 17:06:43Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1306,7 +1306,6 @@ class COffsetData_Factory COffsetList::CDataPool * pool ) : subject_map_( subject_map ), hash_table_( 1<<(2*options.hkey_width) ), - report_level_( options.report_level ), total_( 0 ), hkey_width_( options.hkey_width ), last_seq_( 0 ), @@ -1388,7 +1387,6 @@ class COffsetData_Factory TSubjectMap & subject_map_; /**< Instance of subject map structure. */ THashTable hash_table_; /**< Mapping from Nmer values to the corresponding offset lists. */ - unsigned long report_level_; /**< Level of reporting requested by the user. */ TWord total_; /**< Current size of the structure in bytes. */ unsigned long hkey_width_; /**< Nmer width in bases. */ TSeqNum last_seq_; /**< Logical oid of last processed sequence. */ diff --git a/c++/src/algo/blast/dbindex/makeindex/CMakeLists.makeindex.app.txt b/c++/src/algo/blast/dbindex/makeindex/CMakeLists.makeindex.app.txt new file mode 100644 index 00000000..a33a7454 --- /dev/null +++ b/c++/src/algo/blast/dbindex/makeindex/CMakeLists.makeindex.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/dbindex/makeindex/Makefile.makeindex.app +# +add_executable(makembindex-app + main mkindex_app +) + +set_target_properties(makembindex-app PROPERTIES OUTPUT_NAME makembindex) + +target_link_libraries(makembindex-app + xalgoblastdbindex +) + diff --git a/c++/src/algo/blast/dbindex/makeindex/CMakeLists.txt b/c++/src/algo/blast/dbindex/makeindex/CMakeLists.txt new file mode 100644 index 00000000..2c6d2caf --- /dev/null +++ b/c++/src/algo/blast/dbindex/makeindex/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.makeindex.app.txt) + diff --git a/c++/src/algo/blast/dbindex/sequence_istream_fasta.cpp b/c++/src/algo/blast/dbindex/sequence_istream_fasta.cpp index a6d5ece4..09f2c12e 100644 --- a/c++/src/algo/blast/dbindex/sequence_istream_fasta.cpp +++ b/c++/src/algo/blast/dbindex/sequence_istream_fasta.cpp @@ -1,4 +1,4 @@ -/* $Id: sequence_istream_fasta.cpp 140978 2008-09-23 12:48:49Z morgulis $ +/* $Id: sequence_istream_fasta.cpp 539175 2017-06-19 17:06:43Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -54,7 +54,7 @@ static objects::CFastaReader::TFlags CFASTAREADER_FLAGS = //------------------------------------------------------------------------------ CSequenceIStreamFasta::CSequenceIStreamFasta( const std::string & name , size_t pos ) - : stream_allocated_( false ), istream_( 0 ), curr_seq_( 0 ), + : stream_allocated_( false ), istream_( 0 ), fasta_reader_( 0 ), name_( name ), cache_( null ), use_cache_( false ) { @@ -74,7 +74,7 @@ CSequenceIStreamFasta::CSequenceIStreamFasta( CSequenceIStreamFasta::CSequenceIStreamFasta( CNcbiIstream & input_stream, size_t pos ) : stream_allocated_( false ), istream_( &input_stream ), - curr_seq_( 0 ), fasta_reader_( 0 ), + fasta_reader_( 0 ), cache_( null ), use_cache_( false ) { if( !*istream_ ) { diff --git a/c++/src/algo/blast/format/CMakeLists.txt b/c++/src/algo/blast/format/CMakeLists.txt new file mode 100644 index 00000000..548335d3 --- /dev/null +++ b/c++/src/algo/blast/format/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xblastformat.lib.txt) + diff --git a/c++/src/algo/blast/format/CMakeLists.xblastformat.lib.txt b/c++/src/algo/blast/format/CMakeLists.xblastformat.lib.txt new file mode 100644 index 00000000..022d733b --- /dev/null +++ b/c++/src/algo/blast/format/CMakeLists.xblastformat.lib.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/format/Makefile.xblastformat.lib +# +add_library(xblastformat + blastfmtutil blastxml_format blastxml2_format blast_format + data4xmlformat data4xml2format build_archive vecscreen_run sam +) +add_dependencies(xblastformat + blastdb blastxml blastxml2 xnetblast +) + +target_link_libraries(xblastformat + align_format blastxml blastxml2 + xblast xformat +) diff --git a/c++/src/algo/blast/format/Makefile.xblastformat.lib b/c++/src/algo/blast/format/Makefile.xblastformat.lib index f8c7c033..bbf56951 100644 --- a/c++/src/algo/blast/format/Makefile.xblastformat.lib +++ b/c++/src/algo/blast/format/Makefile.xblastformat.lib @@ -1,9 +1,9 @@ -# $Id: Makefile.xblastformat.lib 473553 2015-07-21 14:41:00Z fongah2 $ +# $Id: Makefile.xblastformat.lib 529282 2017-03-02 18:19:27Z madden $ ASN_DEP = blastdb blastxml blastxml2 xnetblast LIB = xblastformat -SRC = blastfmtutil blastxml_format blastxml2_format blast_format data4xmlformat data4xml2format build_archive vecscreen_run sam +SRC = blastfmtutil blastxml_format blastxml2_format blast_format data4xmlformat data4xml2format build_archive vecscreen_run sam blast_async_format CPPFLAGS = -DNCBI_MODULE=BLASTFORMAT $(ORIG_CPPFLAGS) diff --git a/c++/src/algo/blast/format/blast_async_format.cpp b/c++/src/algo/blast/format/blast_async_format.cpp new file mode 100644 index 00000000..29a06208 --- /dev/null +++ b/c++/src/algo/blast/format/blast_async_format.cpp @@ -0,0 +1,133 @@ +/* $Id: blast_async_format.cpp 530618 2017-03-16 12:03:45Z madden $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Tom Madden + * + * File Description: + * Class to print results + * + */ + +#include +#include + + +// Global mutex +CFastMutex blastProcessGuard; + + +USING_NCBI_SCOPE; +USING_SCOPE(objects); +USING_SCOPE(blast); + +CBlastAsyncFormatThread::~CBlastAsyncFormatThread() +{ +} + +void +CBlastAsyncFormatThread::QueueResults(int batchNumber, + vector results) +{ + if (m_Done == true) + NCBI_THROW(CException, eUnknown, "QueueResults called after Finalize"); + if (m_ResultsMap.find(batchNumber) != m_ResultsMap.end()) + { + string message = "Duplicate batchNumber entered: " + NStr::NumericToString(batchNumber); + NCBI_THROW(CException, eUnknown, "message"); + } + blastProcessGuard.Lock(); + m_ResultsMap.insert(std::pair>(batchNumber, results)); + blastProcessGuard.Unlock(); + m_Semaphore.Post(); +} + + +void +CBlastAsyncFormatThread::Finalize() +{ + blastProcessGuard.Lock(); + m_Done=true; + blastProcessGuard.Unlock(); + m_Semaphore.Post(); +} + +void +CBlastAsyncFormatThread::Join() +{ + if(m_Done == false) + Finalize(); + + CThread::Join(); +} + + +void* CBlastAsyncFormatThread::Main(void) +{ + const int kVecSize=5000; // Large array so we should not wrap around. + vector> results_v; + results_v.resize(kVecSize); + int currNum=0; + int lastNum=0; + while (1) + { + m_Semaphore.Wait(); + blastProcessGuard.Lock(); + for(std::map>::iterator itr=m_ResultsMap.begin(); itr != m_ResultsMap.end(); itr++) + { + if (itr->first < currNum) + continue; + else if (itr->first > currNum) + break; + + results_v[currNum%kVecSize].swap(itr->second); + currNum++; + } + blastProcessGuard.Unlock(); + + for (int index=lastNum; index::iterator vecitr=results_v[index%kVecSize].begin(); + vecitr != results_v[index%kVecSize].end(); vecitr++) + { + ITERATE(CSearchResultSet, result, *((*vecitr).blastResults)) + (*vecitr).formatter->PrintOneResultSet(**result, (*vecitr).qVec); + } + results_v[index%kVecSize].clear(); + } + lastNum=currNum; + if (m_Done == true) // All worker threads done. + { + if (m_ResultsMap.size() != currNum) + { // More results that have been loaded but not printed. + m_Semaphore.Post(); + continue; + } + else + break; + } + } + return (void*) NULL; +} + diff --git a/c++/src/algo/blast/format/blast_format.cpp b/c++/src/algo/blast/format/blast_format.cpp index 774c14b7..abc57087 100644 --- a/c++/src/algo/blast/format/blast_format.cpp +++ b/c++/src/algo/blast/format/blast_format.cpp @@ -306,7 +306,7 @@ CBlastFormat::~CBlastFormat() static const string kHTML_Prefix = "\n" -"BLAST Search Results\n" +"BLAST Search Results\n" "\n" "
\n";
 
@@ -888,7 +888,7 @@ CBlastFormat::x_PrintIgTabularReport(const blast::CIgBlastResults& results,
     tabinfo.SetParseLocalIds(m_BelieveQuery);
 
     string strProgVersion =
-                "IG" + NStr::ToUpper(m_Program) + " " + blast::CBlastVersion().Print();
+        "IG" + NStr::ToUpper(m_Program);
     CConstRef subject_bioseq = x_CreateSubjectBioseq();
 
     if (m_IsHTML) {
diff --git a/c++/src/algo/blast/igblast/CMakeLists.igblast.lib.txt b/c++/src/algo/blast/igblast/CMakeLists.igblast.lib.txt
new file mode 100644
index 00000000..af7f42b9
--- /dev/null
+++ b/c++/src/algo/blast/igblast/CMakeLists.igblast.lib.txt
@@ -0,0 +1,13 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/igblast/Makefile.igblast.lib
+#
+add_library(igblast
+    igblast
+)
+target_link_libraries(igblast
+    xalnmgr xblast
+)
+add_dependencies(igblast
+    blastdb xnetblast
+)
+
diff --git a/c++/src/algo/blast/igblast/CMakeLists.txt b/c++/src/algo/blast/igblast/CMakeLists.txt
new file mode 100644
index 00000000..7f6498b0
--- /dev/null
+++ b/c++/src/algo/blast/igblast/CMakeLists.txt
@@ -0,0 +1,7 @@
+##############################################################################
+# 
+#
+
+# Include projects from this directory
+include(CMakeLists.igblast.lib.txt)
+
diff --git a/c++/src/algo/blast/igblast/igblast.cpp b/c++/src/algo/blast/igblast/igblast.cpp
index 8d9d1ba0..17c95798 100644
--- a/c++/src/algo/blast/igblast/igblast.cpp
+++ b/c++/src/algo/blast/igblast/igblast.cpp
@@ -37,6 +37,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -54,6 +55,8 @@ static int max_allowed_VJ_distance_with_D = 90;
 static int max_allowed_VJ_distance_without_D = 40;
 static int max_allowed_VD_distance = 55;
 static int extend_length = 30;
+static int max_allowed_V_end_to_J_end =150;
+static int max_v_j_overlap = 7;
 
 static void s_ReadLinesFromFile(const string& fn, vector& lines)
 {
@@ -89,7 +92,7 @@ CIgAnnotationInfo::CIgAnnotationInfo(CConstRef &ig_opt)
     int index = 0;
     ITERATE(vector, l, lines) {
         vector tokens;
-        NStr::Tokenize(*l, " \t\n\r", tokens, NStr::eMergeDelims);
+        NStr::Split(*l, " \t\n\r", tokens, NStr::fSplit_Tokenize);
         if (!tokens.empty()) {
             m_DomainIndex[tokens[0]] = index;
             for (int i=1; i<11; ++i) {
@@ -113,7 +116,7 @@ CIgAnnotationInfo::CIgAnnotationInfo(CConstRef &ig_opt)
     }
     ITERATE(vector, l, lines) {
         vector tokens;
-        NStr::Tokenize(*l, " \t\n\r", tokens, NStr::eMergeDelims);
+        NStr::Split(*l, " \t\n\r", tokens, NStr::fSplit_Tokenize);
         if (!tokens.empty()) {
             int frame = NStr::StringToInt(tokens[1]);
             if (frame != -1) {
@@ -135,7 +138,7 @@ void CIgBlast::x_ScreenByAlignLength(CRef & results, int lengt
             CSeq_align_set::Tdata & align_list = (*result)->SetSeqAlign()->Set();
             CSeq_align_set::Tdata::iterator it = align_list.begin();
             while (it != align_list.end()) {
-                if((*it)->GetAlignLength() - (*it)->GetTotalGapCount(0) < length){
+                if((int)((*it)->GetAlignLength()) - (int)((*it)->GetTotalGapCount(0)) < length){
                     it = align_list.erase(it);
                 } else {
                     ++it;
@@ -292,9 +295,26 @@ CIgBlast::Run()
                 break;
             }
         }
-        if (num_genes > 1){
-            x_AnnotateDJ(results[1], results[2], annots);
-        }
+        x_ProcessDJResult(results[0], results[1], results[2], annots);
+       
+        if (m_IgOptions->m_DetectOverlap && m_IgOptions->m_J_penalty == -3 && m_IgOptions->m_D_penalty == -4){
+            x_AnnotateDJ(results[1], results[2],  annots);
+        } else {
+            x_AnnotateJ(results[2],  annots);
+            //redo d gene search and not allow dj overlap
+            x_SetupNoOverlapDSearch(annots, results[1], qf, opts_hndl, 1);
+            CLocalBlast blast(qf, opts_hndl, m_IgOptions->m_Db[1]);
+            try {
+                blast.SetNumberOfThreads(m_NumThreads);
+                results[1] = blast.Run();
+                
+                x_ConvertResultType(results[1]);
+            } catch(...) {
+                cerr << "blast failed" << endl;
+            }
+            x_ProcessDGeneResult(results[0], results[1], results[2],annots);
+            x_AnnotateD(results[1], annots);
+        } 
     }
 
     /*** collect germline search results */
@@ -342,6 +362,31 @@ CIgBlast::Run()
     return final_results;
 };
 
+// Compare two seqaligns according to their evalue and coverage and name 
+//compare name since blast does not guarantee order of same score hits
+static bool s_CompareSeqAlignByScoreAndName(const CRef &x, const CRef &y)
+{
+    int sx, sy;
+    x->GetNamedScore(CSeq_align::eScore_Score, sx);
+    y->GetNamedScore(CSeq_align::eScore_Score, sy);
+    if (sx != sy) return (sx > sy);
+
+    sx = x->GetAlignLength();
+    sy = y->GetAlignLength();
+    if (sx != sy) {
+        return (sx >= sy);
+    }
+    
+    string x_id = NcbiEmptyString;
+    string y_id = NcbiEmptyString;
+    x->GetSeq_id(1).GetLabel(&x_id, CSeq_id::eContent);
+    y->GetSeq_id(1).GetLabel(&y_id, CSeq_id::eContent);
+    return (x_id < y_id);
+    
+};
+
+
+
 void CIgBlast::x_SetupVSearch(CRef       &qf,
                               CRef &opts_hndl)
 {
@@ -375,7 +420,7 @@ void CIgBlast::x_SetupDJSearch(const vector > &annots,
     opts.SetMatchReward(1);
     if (db_type == 2){ //J genes are longer so if can afford more reliable identification
         opts.SetWordSize(7);
-        opts.SetMismatchPenalty(-3);
+        opts.SetMismatchPenalty(m_IgOptions->m_J_penalty);
     } else {
         opts.SetWordSize(m_IgOptions->m_Min_D_match);
         opts.SetMismatchPenalty(m_IgOptions->m_D_penalty);
@@ -403,19 +448,25 @@ void CIgBlast::x_SetupDJSearch(const vector > &annots,
             mask_list.push_back(mask);
             m_Query->SetMaskedRegions(iq, mask_list);
         } else {
-            // Excluding the V gene except the last 7 bp for D and J gene search;
-            // also limit the J match to 150bp beyond V gene.
+            // Excluding the V gene except the last max_v_j_overlap bp for D and J gene search;
+            // also limit the J match to max_allowed_V_end_to_J_end beyond V gene.
+            int v_overlap;
+            if (m_IgOptions->m_DetectOverlap && m_IgOptions->m_J_penalty == -3 && m_IgOptions->m_D_penalty == -4) {
+                v_overlap = max_v_j_overlap;  
+            } else {
+                v_overlap = 0;
+            }
             bool ms = (*annot)->m_MinusStrand;
             int begin = (ms)? 
-              (*annot)->m_GeneInfo[0] - 150: (*annot)->m_GeneInfo[1] - 7;
+              (*annot)->m_GeneInfo[0] - max_allowed_V_end_to_J_end: (*annot)->m_GeneInfo[1] - 1 - v_overlap;
             int end = (ms)? 
-              (*annot)->m_GeneInfo[0] + 7: (*annot)->m_GeneInfo[1] + 150;
+              (*annot)->m_GeneInfo[0] + v_overlap: (*annot)->m_GeneInfo[1] + max_allowed_V_end_to_J_end;
             if (begin > 0) {
                 CRef mask(
-                  new CSeqLocInfo(new CSeq_interval(*q_id, 0, begin-1), 0));
+                  new CSeqLocInfo(new CSeq_interval(*q_id, 0, begin), 0));
                 m_Query->AddMask(iq, mask);
             }
-            if (end < len) {
+            if (end < len -1 && end > 0) {
                 CRef mask(
                   new CSeqLocInfo(new CSeq_interval(*q_id, end, len-1), 0));
                 m_Query->AddMask(iq, mask);
@@ -428,6 +479,69 @@ void CIgBlast::x_SetupDJSearch(const vector > &annots,
     qf.Reset(new CObjMgr_QueryFactory(*m_Query));
 };
 
+
+void CIgBlast::x_SetupNoOverlapDSearch(const vector > &annots,
+                                       CRef        &previous_d_results,
+                                       CRef           &qf,
+                                       CRef     &opts_hndl,
+                                       int db_type)
+{
+    // Only igblastn will search DJ
+    CBlastOptions & opts = opts_hndl->SetOptions();
+    opts.SetMatchReward(1);
+    opts.SetWordSize(m_IgOptions->m_Min_D_match);
+    opts.SetMismatchPenalty(m_IgOptions->m_D_penalty);
+    opts.SetGapOpeningCost(5);
+    opts.SetGapExtensionCost(2);
+    opts_hndl->SetEvalueThreshold(100000.0);
+    opts_hndl->SetFilterString("F");
+    opts_hndl->SetHitlistSize(max(max(50, 
+                                      m_IgOptions->m_NumAlign[1]), 
+                                  m_IgOptions->m_NumAlign[2]));
+    
+    // Mask query for D
+    int iq = 0;
+    ITERATE(vector >, annot, annots) {
+        CRef query = m_Query->GetBlastSearchQuery(iq);
+        CSeq_id *q_id = const_cast(&*query->GetQueryId());
+        int len = query->GetLength();
+        CRef align_d(0);
+        if ((*previous_d_results)[iq].HasAlignments()){
+            align_d =  (*previous_d_results)[iq].SetSeqAlign();
+        }
+        
+        if ((*annot)->m_GeneInfo[0] == -1 || !align_d || align_d.Empty() || align_d->IsEmpty()) {
+            // This is not a ig sequence or there is no d gene per previous search.  Mask it out
+            TMaskedQueryRegions mask_list;
+            CRef mask(
+                  new CSeqLocInfo(new CSeq_interval(*q_id, 0, len-1), 0));
+            mask_list.push_back(mask);
+            m_Query->SetMaskedRegions(iq, mask_list);
+        } else {
+            // Excluding the V gene and J gene
+            bool ms = (*annot)->m_MinusStrand;
+            int v_end_or_j_begin = (ms)? 
+                max((*annot)->m_GeneInfo[0] - max_allowed_V_end_to_J_end, (*annot)->m_GeneInfo[5] - 1): (*annot)->m_GeneInfo[1] -1;
+            int j_begin_or_v_end = (ms)? 
+                (*annot)->m_GeneInfo[0]: min((*annot)->m_GeneInfo[4], (*annot)->m_GeneInfo[1] + max_allowed_V_end_to_J_end);
+            if (v_end_or_j_begin > 0) {
+                CRef mask(
+                  new CSeqLocInfo(new CSeq_interval(*q_id, 0, v_end_or_j_begin), 0));
+                m_Query->AddMask(iq, mask);
+            }
+            if (j_begin_or_v_end < len-1 && j_begin_or_v_end > 0) {
+                CRef mask(
+                  new CSeqLocInfo(new CSeq_interval(*q_id, j_begin_or_v_end, len-1), 0));
+                m_Query->AddMask(iq, mask);
+            }
+        }
+        ++iq;
+    }
+
+    // Generate query factory
+    qf.Reset(new CObjMgr_QueryFactory(*m_Query));
+};
+
 void CIgBlast::x_SetupDbSearch(vector > &annots,
                                CRef           &qf)
 {
@@ -476,12 +590,10 @@ static bool s_IsSeqAlignAsGood(const CRef &x,
     x->GetNamedScore(CSeq_align::eScore_Score, ix);
     y->GetNamedScore(CSeq_align::eScore_Score, iy);
     if (ix > iy) return false;
-    x->GetNamedScore(CSeq_align::eScore_IdentityCount, ix);
-    y->GetNamedScore(CSeq_align::eScore_IdentityCount, iy);
     int dx, dy;
     dx = x->GetAlignLength();
     dy = y->GetAlignLength();
-    return (ix*dy <= iy*dx);
+    return (dx <= dy);
 }
 
 // Remove lcl| from seqid label
@@ -541,13 +653,12 @@ static bool s_CompareSeqAlignByEvalue(const CRef &x,
     x->GetNamedScore(CSeq_align::eScore_Score, ix);
     y->GetNamedScore(CSeq_align::eScore_Score, iy);
     if (ix != iy) return (ix > iy);
-    x->GetNamedScore(CSeq_align::eScore_IdentityCount, ix);
-    y->GetNamedScore(CSeq_align::eScore_IdentityCount, iy);
+
     int dx, dy;
     dx = x->GetAlignLength();
     dy = y->GetAlignLength();
-    if (ix*dy != iy*dx) {
-        return (ix*dy >= iy*dx);
+    if (dx != dy) {
+        return (dx >= dy);
     }
     string x_id = NcbiEmptyString;
     string y_id = NcbiEmptyString;
@@ -563,34 +674,14 @@ static bool s_CompareSeqAlignByScore(const CRef &x, const CRefGetNamedScore(CSeq_align::eScore_Score, sx);
     y->GetNamedScore(CSeq_align::eScore_Score, sy);
     if (sx != sy) return (sx > sy);
-    x->GetNamedScore(CSeq_align::eScore_IdentityCount, sx);
-    y->GetNamedScore(CSeq_align::eScore_IdentityCount, sy);
-    return (sx <= sy);
-};
-
-// Compare two seqaligns according to their evalue and coverage and name 
-//compare name since blast does not guarantee order of same score hits
-static bool s_CompareSeqAlignByScoreAndName(const CRef &x, const CRef &y)
-{
-    int sx, sy;
-    x->GetNamedScore(CSeq_align::eScore_Score, sx);
-    y->GetNamedScore(CSeq_align::eScore_Score, sy);
-    if (sx != sy) return (sx > sy);
-    x->GetNamedScore(CSeq_align::eScore_IdentityCount, sx);
-    y->GetNamedScore(CSeq_align::eScore_IdentityCount, sy);
-    if (sx != sy) {
-        return (sx <= sy);
-    }
-    
-    string x_id = NcbiEmptyString;
-    string y_id = NcbiEmptyString;
-    x->GetSeq_id(1).GetLabel(&x_id, CSeq_id::eContent);
-    y->GetSeq_id(1).GetLabel(&y_id, CSeq_id::eContent);
-    return (x_id < y_id);
+    sx = x->GetAlignLength();
+    sy = y->GetAlignLength();
+    return (sx >= sy);
     
 };
 
 
+
 // Test if D and J annotation not compatible
 static bool s_DJNotCompatible(const CSeq_align &d, const CSeq_align &j, bool ms, int margin)
 {
@@ -602,9 +693,9 @@ static bool s_DJNotCompatible(const CSeq_align &d, const CSeq_align &j, bool ms,
     //D gene needs to have minimal match in addition to overlap with J gene
     //D gene needs to end before J gene ends
     if (ms) {
-        if (ds < js + 3 || de < je + margin) return true;
+        if (ds < js || de < je + margin) return true;
     } else { 
-        if (ds > js - margin || de > je + 3) return true;
+        if (ds > js - margin || de > je) return true;
     }
     return false;
 };
@@ -812,16 +903,21 @@ void CIgBlast::x_FindDJAln(CRef& align_D,
                     } else ++it;
                 }
 
-                if (align_D.NotEmpty() && !align_D->IsEmpty()){
-                    it = al_J.begin();
-                    while (it != al_J.end()) {
-                        if (s_DJNotCompatible(**(al_D.begin()), **it, q_ms, m_IgOptions->m_Min_D_match)) {
-                            it = al_J.erase(it);
-                        } else ++it;
+                if (m_IgOptions->m_DetectOverlap && m_IgOptions->m_J_penalty == -3 &&
+                    m_IgOptions->m_D_penalty == -4) { 
+                    //deleting j only for overlap case otherwise it's handeled later
+                    if (align_D.NotEmpty() && !align_D->IsEmpty()){
+                        it = al_J.begin();
+                        while (it != al_J.end()) {
+                            if (s_DJNotCompatible(**(al_D.begin()), **it, q_ms, m_IgOptions->m_Min_D_match)) {
+                                it = al_J.erase(it);
+                            } else ++it;
+                        }
                     }
                 }
             } else {
                 it = al_J.begin();
+                
                 while (it != al_J.end()) {
                     if (s_DJNotCompatible(**(al_D.begin()), **it, q_ms, m_IgOptions->m_Min_D_match)) {
                         it = al_J.erase(it);
@@ -834,12 +930,12 @@ void CIgBlast::x_FindDJAln(CRef& align_D,
                             it = al_D.erase(it);
                         } else ++it;
                     }
-                    
+ 
                 }
             }
-        }
-                   
 
+        }
+            
 }
 
 
@@ -864,7 +960,7 @@ void CIgBlast::x_FindDJ(CRef& results_D,
             align_D.Reset(const_cast
                                            (&*(res_D.GetSeqAlign())));
             original_align_D->Assign(*align_D);
-;
+           
         }
 
         /* preprocess J */
@@ -877,7 +973,8 @@ void CIgBlast::x_FindDJ(CRef& results_D,
         } 
         //try as VA
         x_FindDJAln(align_D, align_J, q_ct, q_ms, q_st, q_ve, iq, false);
-        if (q_ct =="VA" || q_ct =="VD") {
+        if ((original_align_D.NotEmpty() && !original_align_D->Get().empty()) && (q_ct =="VA" || q_ct =="VD")) {
+            
             annot->m_ChainType[0] = "VA";
             //try as VD
             x_FindDJAln(original_align_D, original_align_J, q_ct, q_ms, q_st, q_ve, iq, true);
@@ -894,6 +991,8 @@ void CIgBlast::x_FindDJ(CRef& results_D,
             if (align_J.NotEmpty() && !align_J->Get().empty()){
                 align_J->Get().front()->GetNamedScore(CSeq_align::eScore_Score, as_light_chain_score);
             }
+
+           
             if (as_heavy_chain_score + d_score> as_light_chain_score){
                 if (align_D.NotEmpty() && original_align_D.NotEmpty()){
                     align_D->Assign(*original_align_D);
@@ -901,7 +1000,7 @@ void CIgBlast::x_FindDJ(CRef& results_D,
                 if (align_J.NotEmpty() && original_align_J.NotEmpty()){
                     align_J->Assign(*original_align_J);
                 }
-                
+              
                 annot->m_ChainType[0] = "VD";
             }
             
@@ -936,23 +1035,220 @@ void CIgBlast::x_FillJDomain(CRef & align, CRef  & an
     }
 }
 
-
-void CIgBlast::x_AnnotateDJ(CRef        &results_D,
-                            CRef        &results_J,
-                            vector > &annots)
-{
+void CIgBlast::x_ProcessDGeneResult(CRef& results_V, 
+                                    CRef& results_D,
+                                    CRef& results_J,
+                                    vector > &annots) {
+    
     int iq = 0;
-    NON_CONST_ITERATE(vector >, annot, annots) {
-
+    NON_CONST_ITERATE(vector >, annot, annots) { 
         string q_ct = (*annot)->m_ChainType[0];
         bool q_ms = (*annot)->m_MinusStrand;
         ENa_strand q_st = (q_ms) ? eNa_strand_minus : eNa_strand_plus;
         int q_ve = (q_ms) ? (*annot)->m_GeneInfo[0] : (*annot)->m_GeneInfo[1] - 1;
 
+        CRef align_D (0);
+        CSearchResults& res_D = (*results_D)[iq];
+        if (res_D.HasAlignments()) {
+            align_D = res_D.SetSeqAlign();
+        }
+
+        // preprocess D 
+        if (align_D && !align_D.Empty() && !align_D->IsEmpty()) {
+            CSeq_align_set::Tdata & align_list = align_D->Set();
+            CSeq_align_set::Tdata::iterator it = align_list.begin();
+            
+            //test compatability between V and D
+            it = align_list.begin();
+            while (it != align_list.end()) {
+                bool keep = true;
+                // chain type test 
+                if (q_ct!="N/A") {
+                    char s_ct = q_ct[1];
+                    string d_id;
+                    (*it)->GetSeq_id(1).GetLabel(&d_id, CSeq_id::eContent);
+                    string d_chain_type = m_AnnotationInfo.GetDJChainType(d_id);
+                    if (d_chain_type != "N/A"){
+                        if (d_chain_type[1] != q_ct[1]) keep = false;
+                    } else { //assume D gene id style 
+                        string sid = (*it)->GetSeq_id(1).AsFastaString();
+                        sid = NStr::ToUpper(sid);
+                        if (sid.substr(0, 4) == "LCL|") sid = sid.substr(4, sid.length());
+                        if ((sid.substr(0, 2) == "IG" || sid.substr(0, 2) == "TR")
+                            && sid[3] == 'D') {
+                            s_ct = sid[2];
+                        }
+                        if (s_ct!='B' && s_ct!='D') s_ct = q_ct[1];
+                        if (s_ct != q_ct[1]) keep = false;
+                    }
+                }
+                
+                //remove failed seq_align 
+                if (!keep) it = align_list.erase(it);
+                else ++it;
+            }
+
+            
+            //strand test 
+            bool strand_found = false;
+            ITERATE(CSeq_align_set::Tdata, it, align_list) {
+                if ((*it)->GetSeqStrand(0) == q_st) {
+                    strand_found = true;
+                    break;
+                }
+            }
+            if (strand_found) {
+                it = align_list.begin();
+                while (it != align_list.end()) {
+                    if ((*it)->GetSeqStrand(0) != q_st) {
+                        it = align_list.erase(it);
+                    } else ++it;
+                }
+            }
+            //v end test 
+            it = align_list.begin();
+            while (it != align_list.end()) {
+                bool keep = false;
+                int q_ds = (*it)->GetSeqStart(0);
+                int q_de = (*it)->GetSeqStop(0);
+                if (q_ms) keep = (q_de >= q_ve - max_allowed_VD_distance && q_ds <= q_ve - m_IgOptions->m_Min_D_match);
+                else      keep = (q_ds <= q_ve + max_allowed_VD_distance && q_de >= q_ve + m_IgOptions->m_Min_D_match);
+                if (!keep) it = align_list.erase(it);
+                else ++it;
+            }
+            // sort according to score 
+            align_list.sort(s_CompareSeqAlignByScoreAndName);
+
+            /* process J */
+            CRef align_J (0);
+            CSearchResults& res_J = (*results_J)[iq];
+            if (res_J.HasAlignments()) {
+                align_J = res_J.SetSeqAlign();
+            }
+            if (align_J && align_J.NotEmpty() && !align_J->IsEmpty() && !align_list.empty()) {
+                
+                CSeq_align_set::Tdata & al_J = align_J->Set();
+                CSeq_align_set::Tdata::iterator it = al_J.begin();
+                while (it != al_J.end()) {
+                    if (s_DJNotCompatible(*(align_list.front()), **it, q_ms, m_IgOptions->m_Min_D_match)) {
+                        it = al_J.erase(it);
+                    } else ++it;
+                }                
+            }
+        }
+                
+        iq ++;
+    }
+}
+
+void CIgBlast::x_ProcessDJResult(CRef& results_V, 
+                                 CRef& results_D,
+                                 CRef& results_J,
+                                 vector > &annots) {
+ 
+    int iq = 0;
+    NON_CONST_ITERATE(vector >, annot, annots) { 
+        string q_ct = (*annot)->m_ChainType[0];
+        bool q_ms = (*annot)->m_MinusStrand;
+        ENa_strand q_st = (q_ms) ? eNa_strand_minus : eNa_strand_plus;
+        int q_ve = (q_ms) ? (*annot)->m_GeneInfo[0] : (*annot)->m_GeneInfo[1] - 1;
+        
         CRef align_D, align_J;
 
         x_FindDJ( results_D, results_J, *annot, align_D, align_J, q_ct, q_ms, q_st, q_ve, iq); 
+        iq ++;
+    }
+}
+
+void CIgBlast::x_AnnotateD(CRef        &results_D,
+                           vector > &annots)
+{
+ 
+    int iq = 0;
+    NON_CONST_ITERATE(vector >, annot, annots) {
+      
+        string q_ct = (*annot)->m_ChainType[0];
+        CSearchResults& res_d = (*results_D)[iq];
+        CConstRef align_D = res_d.GetSeqAlign();
+        if (align_D && !align_D.Empty() && !align_D->IsEmpty()) {
+            const CSeq_align_set::Tdata& align_list = align_D->Get();
+            CRef align = align_list.front();
+            (*annot)->m_GeneInfo[2] = align->GetSeqStart(0);
+            (*annot)->m_GeneInfo[3] = align->GetSeqStop(0)+1;
+            (*annot)->m_TopGeneIds[1] = "";
+
+            int ii=0;
+            ITERATE(CSeq_align_set::Tdata, it, align_list) {
+                if (ii++ < m_IgOptions->m_NumAlign[1] && s_IsSeqAlignAsGood(align, (*it))) {
+                    if ((*annot)->m_TopGeneIds[1] != "") (*annot)->m_TopGeneIds[1] += ",";
+                    (*annot)->m_TopGeneIds[1] += s_RemoveLocalPrefix((*it)->GetSeq_id(1).AsFastaString());
+                } else break;
+            }
+        }
+
+     
+        /* next set of results */
+        ++iq;
+    }
+};
+
+void CIgBlast::x_AnnotateJ(CRef        &results_J,
+                           vector > &annots)
+{
+    int iq = 0;
+    NON_CONST_ITERATE(vector >, annot, annots) {
+      
+        string q_ct = (*annot)->m_ChainType[0];
+        bool q_ms = (*annot)->m_MinusStrand;
+
+        const CSearchResults& res_j = (*results_J)[iq];
+        CConstRef align_J = res_j.GetSeqAlign();
+       
+        /* annotate J */    
+        if (align_J.NotEmpty() && !align_J->IsEmpty()) {
+            const CSeq_align_set::Tdata & align_list = align_J->Get();
+            CRef align = align_list.front();
+            x_FillJDomain(align, *annot);
+            (*annot)->m_GeneInfo[4] = align->GetSeqStart(0);
+            (*annot)->m_GeneInfo[5] = align->GetSeqStop(0)+1;
+            string sid = s_RemoveLocalPrefix(align->GetSeq_id(1).AsFastaString());
+            int frame_offset = m_AnnotationInfo.GetFrameOffset(sid);
+            if (frame_offset >= 0) {
+                int frame_adj = (align->GetSeqStart(1) + 3 - frame_offset) % 3;
+                (*annot)->m_FrameInfo[2] = (q_ms) ?
+                                           align->GetSeqStop(0)  + frame_adj 
+                                         : align->GetSeqStart(0) - frame_adj;
+            } 
+            (*annot)->m_TopGeneIds[2] = "";
+
+            int ii=0;
+            ITERATE(CSeq_align_set::Tdata, it, align_list) {
+                if (ii++ < m_IgOptions->m_NumAlign[2] && s_IsSeqAlignAsGood(align, (*it))) {
+                    if ((*annot)->m_TopGeneIds[2] != "") (*annot)->m_TopGeneIds[2] += ",";
+                    (*annot)->m_TopGeneIds[2] += s_RemoveLocalPrefix((*it)->GetSeq_id(1).AsFastaString());
+                } else break;
+            }
+        }
+     
+        /* next set of results */
+        ++iq;
+    }
+};
+
+void CIgBlast::x_AnnotateDJ(CRef        &results_D,
+                            CRef        &results_J,
+                            vector > &annots)
+{
+    int iq = 0;
+    NON_CONST_ITERATE(vector >, annot, annots) {
+      
+        string q_ct = (*annot)->m_ChainType[0];
+        bool q_ms = (*annot)->m_MinusStrand;
 
+        const CSearchResults& res_j = (*results_J)[iq];
+        const CSearchResults& res_d = (*results_D)[iq];
+        CConstRef align_D = res_d.GetSeqAlign();
+        CConstRef align_J = res_j.GetSeqAlign();
        
         /* annotate D */    
         if (align_D.NotEmpty() && !align_D->IsEmpty()) {
diff --git a/c++/src/algo/blast/proteinkmer/CMakeLists.proteinkmer.lib.txt b/c++/src/algo/blast/proteinkmer/CMakeLists.proteinkmer.lib.txt
new file mode 100644
index 00000000..149b121c
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/CMakeLists.proteinkmer.lib.txt
@@ -0,0 +1,13 @@
+#
+#
+
+
+add_library(proteinkmer
+    blastkmer blastkmerindex blastkmeroptions blastkmerresults 
+    blastkmerutils mhfile pearson kblastapi
+)
+
+target_link_libraries(proteinkmer
+    xblast
+)
+
diff --git a/c++/src/algo/blast/proteinkmer/CMakeLists.txt b/c++/src/algo/blast/proteinkmer/CMakeLists.txt
new file mode 100644
index 00000000..48cbaca7
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/CMakeLists.txt
@@ -0,0 +1,7 @@
+##############################################################################
+# 
+#
+
+# Include projects from this directory
+include(CMakeLists.proteinkmer.lib.txt)
+
diff --git a/c++/src/algo/blast/proteinkmer/Makefile.in b/c++/src/algo/blast/proteinkmer/Makefile.in
new file mode 100644
index 00000000..850ec898
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/Makefile.in
@@ -0,0 +1,10 @@
+LIB_PROJ = proteinkmer
+SUB_PROJ = unit_test 
+#SUB_PROJ = unit_test demo
+
+REQUIRES = algo
+
+srcdir = @srcdir@
+include @builddir@/Makefile.meta
+
+WATCHERS = madden boratyng
diff --git a/c++/src/algo/blast/proteinkmer/Makefile.proteinkmer.lib b/c++/src/algo/blast/proteinkmer/Makefile.proteinkmer.lib
new file mode 100644
index 00000000..26d7ce01
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/Makefile.proteinkmer.lib
@@ -0,0 +1,13 @@
+LIB = proteinkmer
+SRC = blastkmer blastkmerindex blastkmeroptions blastkmerresults blastkmerutils mhfile pearson kblastapi
+
+CXXFLAGS = $(FAST_CXXFLAGS)
+LDFLAGS  = $(FAST_LDFLAGS)
+CPPFLAGS = $(ORIG_CPPFLAGS) $(BOOST_INCLUDE)
+DLL_LIB = xblast $(BLAST_LDEP) $(SOBJMGR_LIBS)
+
+ASN_DEP = seqset
+
+WATCHERS = boratyng madden
+USES_LIBRARIES =  \
+    $(DL_LIBS) $(SOBJMGR_LIBS)
diff --git a/c++/src/algo/blast/proteinkmer/blastkmer.cpp b/c++/src/algo/blast/proteinkmer/blastkmer.cpp
new file mode 100644
index 00000000..6fb2695e
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/blastkmer.cpp
@@ -0,0 +1,382 @@
+/*  $Id: blastkmer.cpp 536161 2017-05-16 14:36:47Z madden $
+ * ===========================================================================
+ *
+ *                            PUBLIC DOMAIN NOTICE
+ *               National Center for Biotechnology Information
+ *
+ *  This software/database is a "United States Government Work" under the
+ *  terms of the United States Copyright Act.  It was written as part of
+ *  the author's official duties as a United States Government employee and
+ *  thus cannot be copyrighted.  This software/database is freely available
+ *  to the public for use. The National Library of Medicine and the U.S.
+ *  Government have not placed any restriction on its use or reproduction.
+ *
+ *  Although all reasonable efforts have been taken to ensure the accuracy
+ *  and reliability of the software and data, the NLM and the U.S.
+ *  Government do not and cannot warrant the performance or results that
+ *  may be obtained by using this software or data. The NLM and the U.S.
+ *  Government disclaim all warranties, express or implied, including
+ *  warranties of performance, merchantability or fitness for any particular
+ *  purpose.
+ *
+ *  Please cite the author in any work or product based on this material.
+ *
+ * ===========================================================================
+ *
+ * Author: Tom Madden
+ *
+ * File Description:
+ *   BLAST-kmer searches
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+BEGIN_NCBI_SCOPE
+BEGIN_SCOPE(blast)
+
+
+CBlastKmer::CBlastKmer(TSeqLocVector& query_vector,
+                CRef options,
+                CRef seqdb,
+                string kmerfile)
+ : m_QueryVector(query_vector),
+   m_Opts (options),
+   m_SeqDB(seqdb),
+   m_GIList(NULL)
+{
+	if (kmerfile != "")
+		m_KmerFiles.push_back(kmerfile);
+	else
+		seqdb->FindVolumePaths(m_KmerFiles, false);
+
+	if(options->Validate() == false)
+		NCBI_THROW(CException, eUnknown, "ERROR: kmer options validation failed");
+
+}
+
+CBlastKmer::CBlastKmer(SSeqLoc& query,
+                CRef options,
+                const string& dbname)
+ : m_Opts (options),
+   m_GIList(NULL)
+{
+	m_QueryVector.push_back(query);
+
+	m_SeqDB = new CSeqDB(dbname, CSeqDB::eProtein);
+
+	m_SeqDB->FindVolumePaths(m_KmerFiles, false);
+
+	if(options->Validate() == false)
+		NCBI_THROW(CException, eUnknown, "ERROR: kmer options validation failed");
+}
+
+void 
+CBlastKmer::x_ProcessQuery(const string& query_seq, SOneBlastKmerSearch& kmerSearch, const SBlastKmerParameters& kmerParams, uint32_t *a, uint32_t *b, vector < vector >& kvector, vector badMers)
+{
+	
+	int num_bands = kmerParams.numHashes/kmerParams.rowsPerBand;
+
+	int do_seg=0; // FIXME
+
+        bool kmerFound = false; 
+	if (kmerParams.version < 3)
+		kmerFound = minhash_query(query_seq, kmerSearch.queryHash, kmerParams.numHashes, a, b, do_seg, kmerParams.kmerNum, kmerParams.alphabetChoice, kmerParams.chunkSize);
+	else
+		kmerFound = minhash_query2(query_seq, kmerSearch.queryHash, kmerParams.kmerNum, 
+			kmerParams.numHashes, kmerParams.alphabetChoice, badMers, kmerParams.chunkSize);
+
+	if (!kmerFound)
+		NCBI_THROW(CException, eUnknown, "WARNING: No KMERs in query");
+
+	if (kmerParams.version < 2)
+		get_LSH_hashes(kmerSearch.queryHash, kmerSearch.queryLSHHash, num_bands, kmerParams.rowsPerBand);
+	else  if (kmerParams.version == 2) // 2 and 30 should be variables
+		get_LSH_hashes2(kmerSearch.queryHash, kmerSearch.queryLSHHash, kmerParams.rowsPerBand, kmerParams.samples, kvector);
+	else
+		get_LSH_hashes5(kmerSearch.queryHash, kmerSearch.queryLSHHash, kmerParams.numHashes, kmerParams.rowsPerBand);
+}
+
+void
+CBlastKmer::x_RunKmerFile(const vector < vector  >& query_hash, const vector < vector  >& query_LSH_hash, CMinHashFile& mhfile, TBlastKmerPrelimScoreVector& score_vector, BlastKmerStats& kmer_stats)
+{
+
+        int num_hashes = mhfile.GetNumHashes();
+
+	// LSH parameters per http://infolab.stanford.edu/~ullman/mmds/ch3.pdf
+	
+	// populate LSH tables
+	uint64_t* lsh = mhfile.GetLSHArray();
+	int kmerVer = mhfile.GetVersion();
+
+	vector< set > candidates;
+	candidates.resize(query_hash.size());
+	get_LSH_match_from_hash(query_LSH_hash, lsh, candidates);
+	int minHits = m_Opts->GetMinHits();
+	if (minHits == 0)
+	{ // Choose value based upon alphabet
+		if (mhfile.GetAlphabet() == 0) 
+			minHits=1;
+		else
+			minHits=2;
+	}
+
+        neighbor_query(query_hash,
+                     lsh,
+                     candidates,
+                     mhfile,
+                     num_hashes,
+                     minHits,
+                     m_Opts->GetThresh(),
+		     score_vector,
+		     kmer_stats, 
+		     kmerVer);
+
+	kmer_stats.num_sequences = mhfile.GetNumSeqs();
+
+	return;
+}
+
+static void
+s_GetQuerySequence(const TSeqLocVector& query_vector, string& query_seq, CRef& seqid, int queryNum)
+{
+ 	query_seq.clear();
+	CSeqVector seqvect(*(query_vector[queryNum].seqloc), *(query_vector[queryNum].scope));
+	seqvect.SetCoding(CSeq_data::e_Ncbistdaa);
+	seqvect.GetSeqData(0, seqvect.size(), query_seq);
+	seqid.Reset(new CSeq_id());
+	seqid->Assign(*(query_vector[queryNum].seqloc->GetId()));
+}
+
+static void
+s_AdjustPrelimScoreVectorOID(TBlastKmerPrelimScoreVector& score_vector, int offset)
+{
+	for(TBlastKmerPrelimScoreVector::iterator iter=score_vector.begin(); iter != score_vector.end(); ++iter)
+	{
+		(*iter).first += offset;
+	}
+}
+
+bool 
+s_SortFinalResults(const pair& one, const pair& two)
+{
+	return one.second > two.second;
+}
+
+void 
+s_GetAllGis(vector& retvalue, TBlastKmerPrelimScoreVector results, CRef seqdb)
+{
+	for(TBlastKmerPrelimScoreVector::iterator itr=results.begin(); itr != results.end(); ++itr)
+	{
+		seqdb->GetGis((*itr).first, retvalue, true);
+	}
+}
+
+CRef
+CBlastKmer::x_SearchMultipleQueries(int firstQuery, int numQuery, const SBlastKmerParameters& kmerParams, uint32_t *a, uint32_t *b, vector < vector >& kValues, vector badMers)
+{
+	TQueryMessages errs;
+	int numThreads = (int) GetNumberOfThreads();
+	int numFiles = m_KmerFiles.size();
+	if (numThreads > numQuery)
+		numThreads = numFiles;
+
+	vector kmerSearchVector;
+	kmerSearchVector.reserve(numQuery);
+	for (int i=0; i qseqid; 
+			s_GetQuerySequence(m_QueryVector, query_seq, qseqid, i+firstQuery);
+			if (query_seq.length() < static_cast(kmerParams.kmerNum))
+				NCBI_THROW(CException, eUnknown, "WARNING: Query shorter than KMER length");
+
+			kmerSearch.qSeqid = qseqid;
+			x_ProcessQuery(query_seq, kmerSearch, kmerParams, a, b, kValues, badMers);
+		 } catch (const ncbi::CException& e) {
+			kmerSearch.status=1;
+			string msg = e.GetMsg();
+			kmerSearch.errDescription=msg;
+			if (msg.find("WARNING:") != std::string::npos)
+				kmerSearch.severity=eBlastSevWarning;
+			else
+				kmerSearch.severity=eBlastSevError;
+		} catch (const std::exception& e) {
+			kmerSearch.status=1;
+			kmerSearch.errDescription=string(e.what());
+			kmerSearch.severity=eBlastSevError;
+		} catch (...) {
+			kmerSearch.status=1;
+			kmerSearch.errDescription=string("Unknown error");
+			kmerSearch.severity=eBlastSevError;
+		}
+		kmerSearchVector.push_back(kmerSearch);
+	}
+
+#pragma omp parallel for num_threads(numThreads)
+for(int index=0; index kmerResultSet(new CBlastKmerResultsSet()); 
+        for (int i=0; i kmerResults;
+        	SOneBlastKmerSearch& kmerSearch = kmerSearchVector[i];
+        	if (kmerSearch.status)
+        	{
+        		kmerResults.Reset(MakeEmptyResults(m_QueryVector, i+firstQuery, kmerSearch.errDescription, kmerSearch.severity));
+        		kmerResultSet->push_back(kmerResults);
+        		continue;
+        	}
+	
+        	BlastKmerStats kmer_stats;
+
+        	TBlastKmerPrelimScoreVector final_results;
+        	size_t final_size=0;  // Total elements needed for all vectors.
+        	for (int index=0; index 1)
+        	   {
+        	   	s_AdjustPrelimScoreVectorOID(score_vector, offset);
+        		offset += kmerSearch.kmerStatsVector[index].num_sequences;
+        	   }
+        	   final_results.insert(final_results.end(), score_vector.begin(), score_vector.end());
+        
+                   // Sum the statistics.
+	           kmer_stats.hit_count += kmerSearch.kmerStatsVector[index].hit_count;
+	           kmer_stats.jd_count += kmerSearch.kmerStatsVector[index].jd_count;
+	           kmer_stats.oids_considered += kmerSearch.kmerStatsVector[index].oids_considered;
+	           kmer_stats.jd_oid_count += kmerSearch.kmerStatsVector[index].jd_oid_count;
+	           kmer_stats.total_matches += kmerSearch.kmerStatsVector[index].total_matches;
+	           kmer_stats.num_sequences += kmerSearch.kmerStatsVector[index].num_sequences;
+	        }
+
+	        // Sort by score
+	        sort(final_results.begin(), final_results.end(), s_SortFinalResults);
+	        if (m_Opts->GetNumTargetSeqs() > 0)
+	        {
+		        int vec_size = final_results.size();
+		        int num_matches = m_Opts->GetNumTargetSeqs();
+		        if (vec_size > num_matches)
+		         final_results.erase(final_results.begin()+num_matches, final_results.end());
+	        }
+
+	        CRef seqdb;
+	        if (m_GIList && !m_GIList.Empty())
+	        {
+		        vector myGis;
+		        s_GetAllGis(myGis, final_results, m_SeqDB);
+	        	CRef intersect( new CIntersectionGiList(*m_GIList, myGis));
+           		const string& dbname = m_SeqDB->GetDBNameList();
+           		if (intersect->Size() > 0)
+           			seqdb.Reset(new CSeqDB(dbname, CSeqDB::eProtein, intersect));
+           		else  // No matches that have proper GI
+           			final_results.erase(final_results.begin(), final_results.end());
+           	}
+           	else if (m_NegGIList && !m_NegGIList.Empty())
+           	{
+           		vector myGis;
+           		s_GetAllGis(myGis, final_results, m_SeqDB);
+           		CRef intersect( new CIntersectionGiList(*m_NegGIList, myGis));
+           		const string& dbname = m_SeqDB->GetDBNameList();
+           		if (intersect->Size() > 0)
+           			seqdb.Reset(new CSeqDB(dbname, CSeqDB::eProtein, intersect));
+           		else  // No matches that have proper GI
+           			final_results.erase(final_results.begin(), final_results.end());
+           	}
+           	if (seqdb.NotEmpty())
+           		kmerResults.Reset(new CBlastKmerResults(kmerSearch.qSeqid, final_results, kmer_stats, seqdb, errs)); 
+           	else
+           		kmerResults.Reset(new CBlastKmerResults(kmerSearch.qSeqid, final_results, kmer_stats, m_SeqDB, errs)); 
+           	kmerResultSet->push_back(kmerResults);
+        }
+	return kmerResultSet;
+}
+
+CRef 
+CBlastKmer::RunSearches() {
+	CRef retval = Run();
+	return retval;
+}
+
+CRef 
+CBlastKmer::Run() {
+	CMinHashFile mhfile(m_KmerFiles[0]);
+	int kmerVer = mhfile.GetVersion();
+        int num_hashes = mhfile.GetNumHashes();
+        int samples = mhfile.GetSegStatus();
+        int kmerNum = mhfile.GetKmerSize();
+        int alphabetChoice = mhfile.GetAlphabet();
+        uint32_t* random_nums = mhfile.GetRandomNumbers();
+        int rows_per_band = mhfile.GetRows();
+	vector badMers;
+	mhfile.GetBadMers(badMers);
+
+	// hash coefficients
+	vector a(num_hashes);
+	vector b(num_hashes);
+	
+	// obtain random coefficients for hashing
+	if (kmerVer == 3)
+	{
+		a[0] =random_nums[0];
+		b[0] =random_nums[1];
+	}
+	else
+	{
+		for(int i=0;i > kValues;
+	if (kmerVer == 2) 
+	{
+		int total=0;
+		unsigned char* kvaluesArray = mhfile.GetKValues();
+		for (int i=0; i temp;
+			for (int j=0; j 2)
+		kmerParams.chunkSize = mhfile.GetChunkSize();
+
+	int numQueries = m_QueryVector.size();
+
+	CRef kmerResultsSet = x_SearchMultipleQueries(0, numQueries, kmerParams, a.data(), b.data(), kValues, badMers);
+	
+	return kmerResultsSet;
+}
+
+END_SCOPE(blast)
+END_NCBI_SCOPE
+
diff --git a/c++/src/algo/blast/proteinkmer/blastkmerindex.cpp b/c++/src/algo/blast/proteinkmer/blastkmerindex.cpp
new file mode 100644
index 00000000..ce715140
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/blastkmerindex.cpp
@@ -0,0 +1,749 @@
+/*  $Id: blastkmerindex.cpp 536161 2017-05-16 14:36:47Z madden $
+ * ===========================================================================
+ *
+ *                            PUBLIC DOMAIN NOTICE
+ *               National Center for Biotechnology Information
+ *
+ *  This software/database is a "United States Government Work" under the
+ *  terms of the United States Copyright Act.  It was written as part of
+ *  the author's official duties as a United States Government employee and
+ *  thus cannot be copyrighted.  This software/database is freely available
+ *  to the public for use. The National Library of Medicine and the U.S.
+ *  Government have not placed any restriction on its use or reproduction.
+ *
+ *  Although all reasonable efforts have been taken to ensure the accuracy
+ *  and reliability of the software and data, the NLM and the U.S.
+ *  Government do not and cannot warrant the performance or results that
+ *  may be obtained by using this software or data. The NLM and the U.S.
+ *  Government disclaim all warranties, express or implied, including
+ *  warranties of performance, merchantability or fitness for any particular
+ *  purpose.
+ *
+ *  Please cite the author in any work or product based on this material.
+ *
+ * ===========================================================================
+ *
+ * Author: Tom Madden
+ *
+ * File Description:
+ *   Build index for BLAST-kmer searches
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+
+#ifdef _OPENMP
+#include 
+#endif
+
+#include "pearson.hpp"
+
+BEGIN_NCBI_SCOPE
+BEGIN_SCOPE(blast)
+
+
+
+CBlastKmerBuildIndex::CBlastKmerBuildIndex(CRef seqdb,
+                int kmerSize,
+		int numHashFct,
+                int samples,
+		int compress,
+		int alphabet,
+		int version,
+		int chunkSize)
+ : m_NumHashFct(numHashFct),
+   m_KmerSize(kmerSize),
+   m_SeqDB(seqdb),
+   m_DoSeg(0),
+   m_Samples(samples),
+   m_Compress(compress),
+   m_Alphabet(alphabet),
+   m_Version(version),
+   m_ChunkSize(chunkSize)
+{
+	if (m_Compress == 0)
+		m_Compress=4;
+
+	// Used for version one LSH
+	m_RowsPerBand = 2;
+	m_NumBands = m_NumHashFct/m_RowsPerBand;
+
+	if (m_Version < 2)
+		m_Samples=0; // Occupies the seg position in version 1
+}
+
+// universal hashing mod 1048583.
+inline uint32_t uhash(uint64_t x, uint64_t a, uint64_t b)
+{
+                uint32_t p=PKMER_PRIME;
+                        return ( (a*x + b) % p );
+}
+
+
+/// FNV Hash.  See http://www.isthe.com/chongo/tech/comp/fnv/index.html
+static Uint4 FNV_hash(uint32_t num)
+{
+     const Uint4 fnv_prime = 16777619u;
+     const Uint4 fnv_offset_basis = 2166136261u;
+     Int4 i;
+     Uint4 hash;
+
+     Uint1 key[4];
+     key[0] = num & 0xff;
+     key[1] = (num >> 8) & 0xff;
+     key[2] = (num >> 16) & 0xff;
+     key[3] = (num >> 24) & 0xff;
+     
+
+     hash = fnv_offset_basis;
+     for (i = 0;i < 4;i++) {
+         hash *= fnv_prime;
+         hash ^= key[i];
+     }
+
+     return hash;
+}
+
+// compute kmer set and minhash signature for a query
+void s_MinhashSequences(uint32_t q_oid,
+				   CSeqDB & db,
+				   vector < vector < vector < uint32_t > > > & seq_hash,
+				   uint32_t *dead,
+				   int num_hashes,
+				   const uint32_t *a,
+				   const uint32_t *b,
+				   bool do_seg,
+				   int kmerNum,
+				   int oidOffset,
+				   int alphabetChoice,
+				   int version,
+				   int chunkSize)
+{
+	int fullOID=q_oid+oidOffset; // REAL OID in full db, not just volume.
+	int seq_length = db.GetSeqLength(fullOID);
+	vector range_v;
+	int chunk_num = BlastKmerBreakUpSequence(seq_length, range_v, chunkSize);
+	seq_hash[q_oid].resize(chunk_num);  // chunk_num is max number that will be saved.
+
+	int chunk_iter=0;
+	int chunk_counter=0;
+	string query;
+	bool first_time=true;
+	db.GetSequenceAsString(fullOID, CSeqUtil::e_Ncbistdaa, query);
+	for(vector::iterator iter=range_v.begin(); iter != range_v.end(); ++iter, chunk_iter++)
+	{
+
+		set seq_kmer = BlastKmerGetKmerSet(query, do_seg, *iter, kmerNum, alphabetChoice);
+	
+		if (seq_kmer.empty())
+		{	
+			continue;
+		}
+
+	
+		vector idx_tmp(num_hashes);
+		vector hash_tmp(num_hashes);
+	
+		for(int h=0;h::iterator i=seq_kmer.begin(); i != seq_kmer.end(); ++i)
+		{
+			// compute hashes and track their minima
+			for(int h=0;h 1)
+			seq_hash[q_oid][chunk_counter][num_hashes] = q_oid;
+		else
+			seq_hash[q_oid][chunk_counter][num_hashes] = fullOID;
+	}
+
+	///	ERASE the end of the vector if not all chunks filled..
+	if (chunk_num > chunk_counter+1)
+		seq_hash[q_oid].erase(seq_hash[q_oid].begin()+chunk_counter+1, seq_hash[q_oid].end());
+	if (first_time == true)  // NOthing found at all.
+		seq_hash[q_oid].erase(seq_hash[q_oid].begin(), seq_hash[q_oid].end());
+
+}
+
+// compute kmer set and minhash signature for a query
+void s_MinhashSequences2(uint32_t q_oid,
+				   CSeqDB & db,
+				   vector < vector < vector < uint32_t > > > & seq_hash,
+				   uint32_t *dead,
+				   int num_hashes,
+				   int kmerNum,
+				   int oidOffset,
+				   int alphabetChoice,
+				   int version,
+				   vector badMers,
+				   int chunkSize)
+{
+	int fullOID=q_oid+oidOffset; // REAL OID in full db, not just volume.
+	int seq_length = db.GetSeqLength(fullOID);
+	vector range_v;
+	int chunk_num = BlastKmerBreakUpSequence(seq_length, range_v, chunkSize);
+	seq_hash[q_oid].resize(chunk_num);  // chunk_num is max number that will be saved.
+
+	int chunk_iter=0;
+	int chunk_counter=0;
+	string query;
+	bool first_time=true;
+	db.GetSequenceAsString(fullOID, CSeqUtil::e_Ncbistdaa, query);
+	for(vector::iterator iter=range_v.begin(); iter != range_v.end(); ++iter, chunk_iter++)
+	{
+
+		set seq_kmer = BlastKmerGetKmerSet2(query, *iter, kmerNum, alphabetChoice, badMers);
+	
+		if (seq_kmer.empty())
+		{	
+			continue;
+		}
+
+	
+		vector hash_values;
+		vector idx_tmp(num_hashes);
+	
+		// for each kmer in the sequence,
+		for(set::iterator i=seq_kmer.begin(); i != seq_kmer.end(); ++i)
+		{
+			uint32_t hashval = FNV_hash(*i);
+			hash_values.push_back(hashval);
+	
+		} // end each kmer
+		if (hash_values.size() < static_cast(num_hashes))
+		{
+			int rem = 1 + num_hashes - hash_values.size();
+			uint32_t hashval = 0xffffffff;  // Fill in empties
+			for (int i=0; i 1)
+			seq_hash[q_oid][chunk_counter][num_hashes] = q_oid;
+		else
+			seq_hash[q_oid][chunk_counter][num_hashes] = fullOID;
+	}
+
+	///	ERASE the end of the vector if not all chunks filled..
+	if (chunk_num > chunk_counter+1)
+		seq_hash[q_oid].erase(seq_hash[q_oid].begin()+chunk_counter+1, seq_hash[q_oid].end());
+	if (first_time == true)  // NOthing found at all.
+		seq_hash[q_oid].erase(seq_hash[q_oid].begin(), seq_hash[q_oid].end());
+
+}
+
+// LSH via Stanford PDF
+static void s_Get_LSH_index_hashes(vector < vector < vector  > >& seq_hash, vector< vector >& lsh, 
+		int q_oid, int numBands, int numRows, int& total_chunks, uint8_t* uniqueHash)
+{
+
+	int num_chunks = seq_hash[q_oid].size();
+	for (int n=0; n> 8) & 0xff;
+			key[2+r*4] = ((seq_hash[q_oid][n][b*numRows+r]) >> 16) & 0xff;
+			key[3+r*4] = ((seq_hash[q_oid][n][b*numRows+r]) >> 24) & 0xff;
+		}
+		key[8] = (unsigned char) b;
+		uint32_t foo = do_pearson_hash(key, 9);
+		uniqueHash[foo] = 1;
+		if (foo != 0)
+			lsh[foo].push_back(total_chunks);
+	  }
+	  total_chunks++;
+	}
+}
+
+// LSH via Buhler
+static void s_Get_LSH_index_hashes2(vector < vector < vector  > >& seq_hash, vector< vector >& lsh,
+			int q_oid, int num_k, int num_l, int array_size, int& total_chunks, uint8_t* uniqueHash,
+			vector < vector  >& kvector)
+{
+
+	int max=4*num_k+1;
+        vector key(max);
+	int num_chunks=seq_hash[q_oid].size();
+	int temp_index=0;
+	int temp_hash=0;
+	for (int n=0; n> 8) & 0xff;
+                    key[2+i*4] = ((temp_hash) >> 16) & 0xff;
+                    key[3+i*4] = ((temp_hash) >> 24) & 0xff;
+            }
+            key[max-1] = r;
+            uint32_t foo = do_pearson_hash(key.data(), max);
+            uniqueHash[foo] = 1;
+            if (foo != 0)
+                lsh[foo].push_back(total_chunks);
+        }
+        total_chunks++;
+	}
+}
+
+// One hash function LSH ala Stanford, but add extra rows
+static void s_Get_LSH_index_hashes5(vector < vector < vector  > >& seq_hash, vector< vector >& lsh, 
+		int q_oid, int numHashes, int numRows, int& total_chunks, uint8_t* uniqueHash)
+{
+
+	int num_chunks = seq_hash[q_oid].size();
+	int numHashMax = numHashes - numRows + 1;
+	uint32_t temp_hash = 0;
+	for (int n=0; n> 8) & 0xff;
+			key[2+r*4] = ((seq_hash[q_oid][n][b+r]) >> 16) & 0xff;
+			key[3+r*4] = ((seq_hash[q_oid][n][b+r]) >> 24) & 0xff;
+		}
+		uint32_t foo = do_pearson_hash(key, 4*numRows);
+		uniqueHash[foo] = 1;
+		if (foo != 0)
+			lsh[foo].push_back(total_chunks);
+	  }
+	  for(int b=0;b> 8) & 0xff;
+			key[2+r*4] = (temp_hash >> 16) & 0xff;
+			key[3+r*4] = (temp_hash >> 24) & 0xff;
+		}
+		uint32_t foo = do_pearson_hash(key, 4*numRows);
+		uniqueHash[foo] = 1;
+		if (foo != 0)
+			lsh[foo].push_back(total_chunks);
+	  }
+
+	  total_chunks++;
+	}
+}
+
+void
+CBlastKmerBuildIndex::Build(int numThreads)
+{
+	m_SeqDB->SetNumberOfThreads(numThreads);
+
+	vector paths;
+	int oid_offset=0;
+	CSeqDB::FindVolumePaths(m_SeqDB->GetDBNameList(), CSeqDB::eProtein, paths, NULL, false);
+	vector range_vec;
+	vector volname_vec;
+	int last=0;
+	for (vector::iterator iter=paths.begin(); iter != paths.end(); ++iter)
+	{
+		string base;
+		string ext;
+		CDirEntry::SplitPath((*iter), NULL, &base, &ext);
+		string volName = base + ext;
+		volname_vec.push_back(volName);	
+		CRef seqdb_vol(new CSeqDB(*iter, CSeqDB::eProtein));
+		oid_offset += seqdb_vol->GetNumSeqs();
+		TSeqRange range;
+               	range.SetFrom(last);
+               	range.SetTo(oid_offset);
+		range_vec.push_back(range);
+		last=oid_offset;
+	}
+
+	int numVols = paths.size();
+#pragma omp parallel for num_threads(numThreads)
+	for(int index=0; index
+s_BlastKmerLoadBadMers(int alphabet)
+{
+	char* loadBadMers = getenv("LOADBADMERS");
+	if (loadBadMers)
+	{
+        	CNcbiIfstream in("badMers.in");
+        	int badKmer;
+		vector badMers;
+        	while (in)
+        	{
+               	 in >> badKmer;
+               	 if (! in)
+                        break;
+               	 badMers.push_back(badKmer);
+cerr << badKmer << '\n';
+		}
+		return badMers;
+	}
+	char* noBadMers = getenv("NOBADMERS");
+	if (noBadMers)
+		return vector();
+
+	if (alphabet == 1)
+	{
+		const int kLength=10;
+		int array[] = {139810, 69905, 70161, 70177, 74257, 
+			69921, 69906, 74001, 135441, 69922};
+		vector badMers(array, array+kLength);
+		return badMers;
+	}
+
+	return vector();
+}
+
+void
+CBlastKmerBuildIndex::x_BuildIndex(string& name, int start, int stop)
+{
+	int StartLSH=0;
+	if (m_Version == 2)
+	{
+		int vectorRandNums=0;
+		vectorRandNums = m_Samples*m_RowsPerBand;
+		vectorRandNums += 8 - (m_Samples*m_RowsPerBand)%8;  // multiple of 8.
+		StartLSH=56+(2*4*m_NumHashFct)+vectorRandNums;  
+	}
+	else if (m_Version == 3)
+		StartLSH=56+(2*4*m_NumHashFct);  
+	else
+		StartLSH=48+(2*4*m_NumHashFct);  
+	const int kSizeLSH=KMER_LSH_ARRAY_SIZE; // 2**24 + 1 (sentinel at end)
+
+	string indexFile = name + ".pki";
+	string dataFile = name + ".pkd";
+	// Output files 
+    CNcbiOfstream index_file(indexFile.c_str(), IOS_BASE::out | IOS_BASE::binary);
+    CNcbiOfstream data_file(dataFile.c_str(), IOS_BASE::out | IOS_BASE::binary);
+
+	if (!index_file)
+		 NCBI_THROW(CFileException, eNotExists, "Cannot open " + indexFile);
+	if (!data_file)
+		 NCBI_THROW(CFileException, eNotExists, "Cannot open " + dataFile);
+
+	int num_seqs = 0;
+	if (stop != 0)
+		num_seqs = stop - start; 
+	else
+		num_seqs = m_SeqDB->GetNumSeqs();
+
+
+	index_file.write((char *) &(m_Version), 4);  // Add BLAST DB name?
+	index_file.write((char *) &(num_seqs), 4);  
+	index_file.write((char *) &(m_NumHashFct), 4);
+	index_file.write((char *) &(m_Samples), 4);
+	index_file.write((char *) &(m_KmerSize), 4);
+	index_file.write((char *) &(m_RowsPerBand), 4);
+	index_file.write((char *) &(m_Compress), 4);
+	index_file.write((char *) &(m_Alphabet), 4);
+	index_file.write((char *) &(StartLSH), 4);
+	index_file.write((char *) &(kSizeLSH), 4);
+	
+    // hash coefficients
+    vector a(m_NumHashFct);
+    vector b(m_NumHashFct);
+    GetRandomNumbers(a.data(), b.data(), m_NumHashFct);
+        
+	// sequences that contain no valid kmers
+    uint32_t* dead = new uint32_t[3*num_seqs];
+    _ASSERT(dead);
+	for(int q_oid=0;q_oid<3*num_seqs;q_oid++)
+		dead[q_oid]=0;
+
+    vector badMers = s_BlastKmerLoadBadMers(m_Alphabet);
+	
+	// mapping from a sequence (by oid) to 
+	// chunks of a sequence to the minhashes
+	vector < vector < vector < uint32_t > > > seq_hash(num_seqs);
+	
+	// compute minhash signatures for each sequence
+	for(int q_oid=0;q_oid > lsh(kSizeLSH);
+	int total_chunks=0;
+// cerr << "TEST " << m_RowsPerBand << " " << m_Samples << '\n';
+	vector < vector  > kvector;
+ 	if (m_Version == 2) 
+ 	{
+		GetKValues(kvector, m_RowsPerBand, m_Samples, m_NumHashFct);
+	}
+	for(int q_oid=0;q_oid 0)
+                        hashCount++;
+        }
+	delete [] uniqueHash;
+
+
+	uint64_t LSHMatchSize=0;
+        for(int index=0; index 2)
+		index_file.write((char *) &(m_ChunkSize), 4);
+	
+	if (m_Version > 1)
+	{
+		const int kFutureUse=0;
+		index_file.write((char *) &(kFutureUse), 4);
+		if (m_Version < 3)
+			index_file.write((char *) &(kFutureUse), 4);
+	}
+
+	if (m_Version < 3)
+	{
+		// Random numbers used for the hash functions.
+		for(int i=0;i (2*m_NumHashFct-1))
+			num = 2*m_NumHashFct-1;
+		index_file.write((char *) &(num), 4);
+		for(vector::iterator iter=badMers.begin(); iter != badMers.end() && i<2*m_NumHashFct; ++iter, ++i)
+			index_file.write((char *) &(*iter), 4);
+		if (i<2*m_NumHashFct)
+		{
+			const int kZero=0;
+			for (; i<2*m_NumHashFct; ++i)
+				index_file.write((char *) &(kZero), 4);
+		}
+		
+	}
+
+	
+	if (m_Version == 2)
+	{
+		for (int i=0; i temp = kvector[i];
+			for (int j=0; j::iterator i=lsh[index].begin(); i != lsh[index].end(); ++i)
+		{
+			index_file.write((char *) &(*i), 4);
+			lsh_hits++;
+		}
+	}
+	
+	index_file.flush();
+	index_file.close();
+	
+	x_WriteDataFile(seq_hash, num_seqs, data_file);
+	data_file.flush();
+	data_file.close();
+	
+
+        delete [] dead;
+
+	return;
+}	
+
+
+void
+CBlastKmerBuildIndex::x_WriteDataFile(vector < vector < vector < uint32_t > > > & seq_hash, int num_seqs, CNcbiOfstream& data_file)
+{
+	int width = m_Compress;
+	if (width == 0) 
+		width = 4;
+	for(int q_oid=0;q_oid tmp_hash;
+		    for(int b=0;b is internal; please use  instead!"
-#endif // __GNUC__ 
+#include 
+#include 
+
+BEGIN_NCBI_SCOPE
+
+CBlastKmerOptions::CBlastKmerOptions()	
+    : m_Thresh(0.10),
+      m_MinHits(1),
+      m_NumTargetSeqs(500)
+{
+}	
+
+bool
+CBlastKmerOptions::Validate() const
+{
+	if (m_Thresh <= 0.0 || m_Thresh > 1.0)
+		return false;
+
+	if (m_MinHits < 0)
+		return false;
+
+	if (m_NumTargetSeqs < 0) 
+		return false;
+
+	return true;
+}
 
-#include 
-#include 
+END_NCBI_SCOPE
 
-#endif  /* CONNECT_SERVICES__NETSTORAGE_IMPL__HPP */
diff --git a/c++/src/algo/blast/proteinkmer/blastkmerresults.cpp b/c++/src/algo/blast/proteinkmer/blastkmerresults.cpp
new file mode 100644
index 00000000..c5ee7c7c
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/blastkmerresults.cpp
@@ -0,0 +1,188 @@
+/*  $Id: blastkmerresults.cpp 536626 2017-05-22 12:07:12Z madden $
+ * ===========================================================================
+ *
+ *                            PUBLIC DOMAIN NOTICE
+ *               National Center for Biotechnology Information
+ *
+ *  This software/database is a "United States Government Work" under the
+ *  terms of the United States Copyright Act.  It was written as part of
+ *  the author's official duties as a United States Government employee and
+ *  thus cannot be copyrighted.  This software/database is freely available
+ *  to the public for use. The National Library of Medicine and the U.S.
+ *  Government have not placed any restriction on its use or reproduction.
+ *
+ *  Although all reasonable efforts have been taken to ensure the accuracy
+ *  and reliability of the software and data, the NLM and the U.S.
+ *  Government do not and cannot warrant the performance or results that
+ *  may be obtained by using this software or data. The NLM and the U.S.
+ *  Government disclaim all warranties, express or implied, including
+ *  warranties of performance, merchantability or fitness for any particular
+ *  purpose.
+ *
+ *  Please cite the author in any work or product based on this material.
+ *
+ * ===========================================================================
+ *
+ * Author: Tom Madden
+ *
+ * File Description:
+ *   Results for BLAST-kmer searches
+ *
+ */
+
+#include 
+#include 
+
+BEGIN_NCBI_SCOPE
+BEGIN_SCOPE(blast)
+
+CBlastKmerResults::CBlastKmerResults(CConstRef     query,
+                        TBlastKmerPrelimScoreVector& scores,
+                        BlastKmerStats& stats,
+			CRef seqdb,
+			const TQueryMessages& errs)
+    : m_QueryId(query), m_Stats(stats), m_SeqDB(seqdb), m_Errors(errs)
+{
+	x_InitScoreVec(scores);
+}
+
+void CBlastKmerResults::x_InitScoreVec(TBlastKmerPrelimScoreVector& scores) 
+{
+	m_Scores.reserve(scores.size());
+	for(TBlastKmerPrelimScoreVector::iterator iter=scores.begin(); iter != scores.end(); ++iter)
+	{
+		list< CRef > seqids = m_SeqDB->GetSeqIDs((*iter).first);
+		if (seqids.size() > 0) // Removed by GIList limit.
+		{
+			CRef id = FindBestChoice(seqids, CSeq_id::BestRank);
+			pair, double> retval(id, (*iter).second);
+			m_Scores.push_back(retval);
+		}
+	}
+}
+
+void
+CBlastKmerResults::GetTSL(TSeqLocVector& tsl, CRef scope) const
+{
+	const TBlastKmerScoreVector& scores = GetScores();
+
+        for(TBlastKmerScoreVector::const_iterator iter=scores.begin(); iter != scores.end(); ++iter)
+        {
+		  CRef seqloc(new CSeq_loc);
+    		  seqloc->SetWhole().Assign(*((*iter).first));
+		  auto_ptr ssl(new SSeqLoc(*seqloc, *scope));
+		  tsl.push_back(*ssl);
+        }
+	return;
+}
+
+TQueryMessages
+CBlastKmerResults::GetErrors(int min_severity) const
+{
+    TQueryMessages errs;
+    
+    ITERATE(TQueryMessages, iter, m_Errors) {
+        if ((**iter).GetSeverity() >= min_severity) {
+            errs.push_back(*iter);
+        }
+    }
+    errs.SetQueryId(m_Errors.GetQueryId());
+    
+    return errs;
+}
+
+bool
+CBlastKmerResults::HasErrors() const
+{
+    ITERATE(TQueryMessages, iter, m_Errors) {
+        if ((**iter).GetSeverity() >= eBlastSevError) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool
+CBlastKmerResults::HasWarnings() const
+{
+    ITERATE(TQueryMessages, iter, m_Errors) {
+        if ((**iter).GetSeverity() == eBlastSevWarning) {
+            return true;
+        }
+    }
+    return false;
+}
+
+void
+CBlastKmerResultsSet::x_Init(TQueryIdVector& ids,
+                             TBlastKmerPrelimScoreVectorSet& scores,
+                             TBlastKmerStatsVector& stats,
+                             CRef seqdb,
+                             TSearchMessages msg_vec)
+{
+	m_NumQueries = ids.size();
+
+	m_Results.resize(m_NumQueries);
+
+	for (size_t i=0; i seqdb,
+                                           TSearchMessages msg_vec)
+{
+	x_Init(ids, scores, stats, seqdb, msg_vec);
+}
+
+
+CBlastKmerResultsSet::CBlastKmerResultsSet()
+{
+	m_NumQueries=0;
+}
+
+
+void
+CBlastKmerResultsSet::push_back(CBlastKmerResultsSet::value_type& element)
+{
+	m_Results.push_back(element);
+	m_NumQueries++;
+}
+
+CRef
+CBlastKmerResultsSet::operator[](const objects::CSeq_id & ident)
+{
+	for (size_t i=0; iGetSeqId()) ) 
+			return m_Results[i];
+        }
+	return CRef();
+
+}
+
+CRef
+MakeEmptyResults(TSeqLocVector& queryVector, int queryNum, const string& errMsg, EBlastSeverity severity)
+{
+	CRef retval;
+	CRef seqid(new CSeq_id());
+	seqid->Assign(*(queryVector[queryNum].seqloc->GetId()));
+	CRef msg(new CSearchMessage(severity, -1, errMsg));
+	TQueryMessages errs;
+	errs.push_back(msg);
+	TBlastKmerPrelimScoreVector score_vec;
+	BlastKmerStats stats;
+	errs.SetQueryId(seqid->AsFastaString());
+	retval.Reset(new CBlastKmerResults(seqid, score_vec, stats, CRef(), errs));
+
+	return retval;
+}
+
+
+END_SCOPE(blast)
+END_NCBI_SCOPE
+
diff --git a/c++/src/algo/blast/proteinkmer/blastkmerutils.cpp b/c++/src/algo/blast/proteinkmer/blastkmerutils.cpp
new file mode 100644
index 00000000..80c90dac
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/blastkmerutils.cpp
@@ -0,0 +1,938 @@
+/*  $Id: blastkmerutils.cpp 536161 2017-05-16 14:36:47Z madden $
+ * ===========================================================================
+ *
+ *                            PUBLIC DOMAIN NOTICE
+ *               National Center for Biotechnology Information
+ *
+ *  This software/database is a "United States Government Work" under the
+ *  terms of the United States Copyright Act.  It was written as part of
+ *  the author's official duties as a United States Government employee and
+ *  thus cannot be copyrighted.  This software/database is freely available
+ *  to the public for use. The National Library of Medicine and the U.S.
+ *  Government have not placed any restriction on its use or reproduction.
+ *
+ *  Although all reasonable efforts have been taken to ensure the accuracy
+ *  and reliability of the software and data, the NLM and the U.S.
+ *  Government do not and cannot warrant the performance or results that
+ *  may be obtained by using this software or data. The NLM and the U.S.
+ *  Government disclaim all warranties, express or implied, including
+ *  warranties of performance, merchantability or fitness for any particular
+ *  purpose.
+ *
+ *  Please cite the author in any work or product based on this material.
+ *
+ * ===========================================================================
+ *
+ * Author: Tom Madden
+ *
+ * File Description:
+ *   Utilities for the BLAST kmer search.
+ *
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+
+#include "pearson.hpp"
+
+BEGIN_NCBI_SCOPE
+USING_SCOPE(objects);
+USING_SCOPE(blast);
+
+DEFINE_STATIC_MUTEX(randMutex);
+
+
+// universal hashing mod 1048583.
+inline uint32_t uhash(uint64_t x, uint64_t a, uint64_t b)
+{
+              uint32_t p=PKMER_PRIME;
+              return ( (a*x + b) % p );
+}
+
+
+/// FNV hash, see http://www.isthe.com/chongo/tech/comp/fnv/index.html
+static uint32_t FNV_hash(uint32_t num)
+{
+     const Uint4 fnv_prime = 16777619u;
+     const Uint4 fnv_offset_basis = 2166136261u;
+     Int4 i;
+     Uint4 hash;
+
+     Uint1 key[4];
+     key[0] = num & 0xff;
+     key[1] = (num >> 8) & 0xff;
+     key[2] = (num >> 16) & 0xff;
+     key[3] = (num >> 24) & 0xff;
+     
+
+     hash = fnv_offset_basis;
+     for (i = 0;i < 4;i++) {
+         hash *= fnv_prime;
+         hash ^= key[i];
+     }
+
+     return hash;
+}
+
+
+// estimate Jaccard similarity using minhashes
+inline double estimate_jaccard(vector& query_hash, vector& subject, int num_hashes)
+{
+	int score=0;
+	
+	// help the compiler vectorize
+	uint32_t *a=&(query_hash[0]);
+	uint32_t *b=&(subject[0]);
+	
+	for(int h=0;h& query_hash, vector& subject, int num_hashes)
+{
+	int score=0;
+	
+	// help the compiler vectorize
+	uint32_t *a=&(query_hash[0]);
+	uint32_t *b=&(subject[0]);
+
+	int bindex=0;
+	for(int h=0;h b[bindex])
+		{
+			bindex++;
+		}
+		if (bindex == num_hashes)
+			break;
+		if (a[h] == b[bindex])
+			score++;
+	}
+	
+	return (double) score / num_hashes;
+}
+
+set BlastKmerGetKmerSetStats(const string& query_sequence, int kmerNum, map& kmerCount, map& kmerCountPlus, int alphabetChoice, bool perQuery)
+{
+	// the set of unique kmers
+	set kmer_set;
+
+        vector trans_table;
+        BlastKmerGetCompressedTranslationTable(trans_table, alphabetChoice);
+	
+	int seq_length = query_sequence.length();
+	const char* query = query_sequence.c_str();
+
+	// bail out if the sequence is too short
+	if (seq_length < kmerNum)
+		return kmer_set;
+
+	map kmerCountPriv;
+	map kmerCountPlusPriv;
+
+	for(int i=0;i::iterator i=kmerCountPriv.begin(); i != kmerCountPriv.end(); ++i)
+                	kmerCount[(*i).first]++;
+		for (map::iterator i=kmerCountPlusPriv.begin(); i != kmerCountPlusPriv.end(); ++i)
+                	kmerCountPlus[(*i).first]++;
+	}
+	else
+	{
+		for (map::iterator i=kmerCountPriv.begin(); i != kmerCountPriv.end(); ++i)
+                	kmerCount[(*i).first] += (*i).second;
+		for (map::iterator i=kmerCountPlusPriv.begin(); i != kmerCountPlusPriv.end(); ++i)
+                	kmerCountPlus[(*i).first] += (*i).second;
+	}
+	
+	return kmer_set;
+}
+
+set BlastKmerGetKmerSet(const string& query_sequence, bool do_seg, TSeqRange& range, int kmerNum, int alphabetChoice)
+{
+	// the set of unique kmers
+	set kmer_set;
+
+        vector trans_table;
+        BlastKmerGetCompressedTranslationTable(trans_table, alphabetChoice);
+	
+	int seq_length = query_sequence.length();
+	const char* query = query_sequence.c_str();
+
+	// bail out if the sequence is too short
+	if (seq_length < kmerNum)
+		return kmer_set;
+
+	int chunk_length=range.GetLength();
+	char *query_private=(char*)malloc(chunk_length);
+	int private_index=0;
+	for (unsigned int i=range.GetFrom(); i<=range.GetTo(); i++, private_index++)
+		query_private[private_index] = query[i];
+
+	if (do_seg)
+	{
+		// filter the query to remove overrepresented regions
+		SegParameters *sp = SegParametersNewAa();
+		BlastSeqLoc* seq_locs = NULL;
+		SeqBufferSeg((unsigned char *)query_private, chunk_length, 0, sp, &seq_locs);
+		SegParametersFree(sp);
+	
+		// mask out low complexity regions with X residues
+		for(BlastSeqLoc *itr = seq_locs; itr; itr = itr->next)
+		{
+			for(int i=itr->ssr->left; i <= itr->ssr->right; i++)
+				query_private[i]=21;
+		}
+	
+		BlastSeqLocFree(seq_locs);
+	}
+	
+	for(int i=0;i BlastKmerGetKmerSet2(const string& query_sequence, TSeqRange& range, int kmerNum, int alphabetChoice, vector badMers)
+{
+	// the set of unique kmers
+	set kmer_set;
+
+        vector trans_table;
+        BlastKmerGetCompressedTranslationTable(trans_table, alphabetChoice);
+	
+	int seq_length = query_sequence.length();
+	const char* query = query_sequence.c_str();
+
+	// bail out if the sequence is too short
+	if (seq_length < kmerNum)
+		return kmer_set;
+
+	int chunk_length=range.GetLength();
+	char *query_private=(char*)malloc(chunk_length);
+	int private_index=0;
+	for (unsigned int i=range.GetFrom(); i<=range.GetTo(); i++, private_index++)
+		query_private[private_index] = query[i];
+
+	for(int i=0;i::iterator it;
+				it = std::find(badMers.begin(), badMers.end(), index);
+				if (it != badMers.end() && i < chunk_length-1)
+                        	{
+                               		index = (index << 4);
+                                	index += trans_table[query_private[i+kmerNum]];
+                        	}
+			}
+                        kmer_set.insert(index);
+		}
+	}
+	
+	// free the sequence
+	free(query_private);
+	
+	return kmer_set;
+}
+
+
+
+void BlastKmerGetCompressedTranslationTable(vector& trans_table, int alphabetChoice)
+{
+	const unsigned int kAlphabetLen = 28;
+        // Compressed alphabets taken from 
+        // Shiryev et al.(2007),  Bioinformatics, 23:2949-2951
+        const char* kCompAlphabets[] = {
+            // 23-to-15 letter compressed alphabet. Based on SE_B(14) 
+            "ST IJV LM KR EQZ A G BD P N F Y H C W",
+            // 23-to-10 letter compressed alphabet. Based on SE-V(10)
+            "IJLMV AST BDENZ KQR G FY P H C W"
+        };
+
+	// Use second alphabet only
+        const char* trans_string = kCompAlphabets[alphabetChoice];
+
+        Uint4 compressed_letter = 1; // this allows for gaps
+        trans_table.clear();
+        trans_table.resize(kAlphabetLen + 1, 0);
+        for (Uint4 i = 0; i < strlen(trans_string);i++) {
+            if (isspace(trans_string[i])) {
+                compressed_letter++;
+            }
+            else if (isalpha(trans_string[i])) {
+                Uint1 aa_letter = AMINOACID_TO_NCBISTDAA[(int)trans_string[i]];
+
+                _ASSERT(aa_letter < trans_table.size());
+
+                trans_table[aa_letter] = compressed_letter;
+            }
+        }
+}
+
+int BlastKmerBreakUpSequence(int length, vector& range_v, int ChunkSize)
+{
+	int numChunks=0;
+	const int kOverlap=50;
+	numChunks = 1 + length/ChunkSize;
+	// Adjust chunk size so chunks are all about same length.
+	ChunkSize = (length + (numChunks-1)*kOverlap + numChunks)/numChunks;
+	TSeqPos last=0;
+	for (int i=0; i& minhash1, const vector& minhash2)
+{
+
+        int distance=0;
+	int num_hashes = minhash1.size();
+
+        for (int index=0; index >& seq_hash,
+                     int num_hashes,
+                     uint32_t *a,
+                     uint32_t *b,
+		     int do_seg,
+		     int kmerNum,
+                     int alphabetChoice,
+                     int chunkSize)
+{
+	bool kmersFound=false; // return value;
+	int seq_length = query.length();
+	vector range_v;
+	int chunk_num = BlastKmerBreakUpSequence(seq_length, range_v, chunkSize);
+	seq_hash.resize(chunk_num);
+	bool seg = (do_seg > 0) ? true : false;
+
+	vector idx_tmp(num_hashes);
+	vector hash_tmp(num_hashes);
+	int chunk_iter=0;
+    for(vector::iterator iter=range_v.begin(); iter != range_v.end(); ++iter, chunk_iter++)
+    {
+	
+		seq_hash[chunk_iter].resize(num_hashes);
+
+		set seq_kmer = BlastKmerGetKmerSet(query, seg, *iter, kmerNum, alphabetChoice);
+	
+		if (seq_kmer.empty())
+			continue;
+	
+		kmersFound = true;
+	
+#pragma ivdep
+		for(int h=0;h::iterator i=seq_kmer.begin(); i != seq_kmer.end(); ++i)
+		{
+			// compute hashes and track their minima
+			for(int h=0;h >& seq_hash,
+		     int kmerNum,
+		     int numHashes,
+                     int alphabetChoice, 
+		     vector badMers,
+                     int chunkSize)
+{
+	bool kmersFound=false; // return value;
+	int seq_length = query.length();
+	vector range_v;
+	int chunk_num = BlastKmerBreakUpSequence(seq_length, range_v, chunkSize);
+	seq_hash.resize(chunk_num);
+
+	vector hash_values;
+	int chunk_iter=0;
+    for(vector::iterator iter=range_v.begin(); iter != range_v.end(); ++iter, chunk_iter++)
+    {
+		hash_values.clear();
+		seq_hash[chunk_iter].resize(numHashes);
+
+		set seq_kmer = BlastKmerGetKmerSet2(query, *iter, kmerNum, alphabetChoice, badMers);
+	
+		if (seq_kmer.empty())
+			continue;
+	
+		kmersFound = true;
+	
+		// for each kmer in the sequence,
+		for(set::iterator i=seq_kmer.begin(); i != seq_kmer.end(); ++i)
+		{
+			uint32_t hashval = FNV_hash(*i);
+			hash_values.push_back(hashval);
+				
+		} // end each kmer
+		
+		if (hash_values.size() < static_cast(numHashes))
+        {
+            int rem = 1 + numHashes - hash_values.size();
+            uint32_t hashval = 0xffffffff;  // Fill in empties
+            for (int i=0; i >& query_hash,
+		      vector < vector  >&lsh_hash_vec,
+                      int num_bands,
+                      int rows_per_band)
+{
+	int num_chunks=query_hash.size();
+	uint32_t temp_hash=0;
+	for (int n=0; n lsh_chunk_vec; 
+		for(int b=0;b> 8) & 0xff;
+               	         	key[2+r*4] = ((temp_hash) >> 16) & 0xff;
+               	         	key[3+r*4] = ((temp_hash) >> 24) & 0xff;
+			}
+			key[8] = (unsigned char) b;
+			uint32_t foo = do_pearson_hash(key, 9);
+			lsh_chunk_vec.push_back(foo);
+		}
+		std::sort(lsh_chunk_vec.begin(), lsh_chunk_vec.end());
+		lsh_hash_vec.push_back(lsh_chunk_vec);
+	}
+	
+	return;
+}
+
+void get_LSH_hashes5(vector < vector  >& query_hash,
+		      vector < vector  >&lsh_hash_vec,
+                      int numHashes,
+                      int numRows)
+{
+	int num_chunks=query_hash.size();
+	uint32_t temp_hash=0;
+	int numHashMax = numHashes - numRows + 1;
+	for (int n=0; n lsh_chunk_vec; 
+		for(int b=0;b> 8) & 0xff;
+               	         	key[2+r*4] = ((temp_hash) >> 16) & 0xff;
+               	         	key[3+r*4] = ((temp_hash) >> 24) & 0xff;
+			}
+			uint32_t foo = do_pearson_hash(key, 4*numRows);
+			lsh_chunk_vec.push_back(foo);
+		}
+		for(int b=0;b> 8) & 0xff;
+               	         	key[2+r*4] = ((temp_hash) >> 16) & 0xff;
+               	         	key[3+r*4] = ((temp_hash) >> 24) & 0xff;
+			}
+			uint32_t foo = do_pearson_hash(key, 4*numRows);
+			lsh_chunk_vec.push_back(foo);
+		}
+		std::sort(lsh_chunk_vec.begin(), lsh_chunk_vec.end());
+		lsh_hash_vec.push_back(lsh_chunk_vec);
+	}
+
+	return;
+}
+
+void GetRandomNumbers(uint32_t* a, uint32_t* b, int numHashes)
+{
+	CMutexGuard guard(randMutex);
+        CRandom random(1);  // Always have the same random numbers.
+        for(int i=0;i >& kvector, int k_value, int l_value, int array_size)
+{
+	CMutexGuard guard(randMutex);
+	CRandom random(10);
+	
+	for (int i=0; i ktemp;
+		for (int k=0; k >& query_hash,
+		      vector < vector  >& lsh_hash_vec,
+                      int num_k,
+                      int num_l,
+			vector< vector >& kvector)
+{
+	int max=4*num_k+1;
+	vector key(max);
+	int num_chunks=query_hash.size();
+	uint32_t temp_hash=0;
+	int temp_index=0;
+	for (int n=0; n lsh_chunk_vec; 
+		for (int r=0; r> 8) & 0xff;
+               		        key[2+i*4] = ((temp_hash) >> 16) & 0xff;
+               		        key[3+i*4] = ((temp_hash) >> 24) & 0xff;
+			}
+			key[max-1] = r;
+			uint32_t foo = do_pearson_hash(key.data(), max);
+			lsh_chunk_vec.push_back(foo);
+		}
+		std::sort(lsh_chunk_vec.begin(), lsh_chunk_vec.end());
+		lsh_hash_vec.push_back(lsh_chunk_vec);
+	}
+}
+
+// Find candidate matches with LSH (based on array in index)
+void get_LSH_match_from_hash(const vector< vector  >& query_LSH_hash,
+                     const uint64_t* lsh_array,
+		     vector< set >& candidates)
+{
+
+	int num=query_LSH_hash.size();
+	for (int i=0; i::const_iterator iter=query_LSH_hash[i].begin(); iter != query_LSH_hash[i].end(); ++iter)
+		{
+			if (lsh_array[*iter] != 0)
+				candidates[i].insert(*iter);
+		}
+	}
+	
+	return;
+}
+		     
+
+void
+s_HashHashQuery(const vector < vector  > & query_hash, vector < vector  >& query_hash_hash, int compress, int version)
+{
+    int hash_value=0;
+    int num_chunks=query_hash.size();
+    const uint32_t kBig=0xffffffff;
+    for (int n=0; n tmp_hash;
+        for(vector::const_iterator i = query_hash[n].begin(); i != query_hash[n].end(); ++i)
+        {
+            if (compress == 2)
+                hash_value = (int) pearson_hash_int2short(*i);
+            else if (compress == 1)
+                hash_value = (int) pearson_hash_int2byte(*i);
+            else
+                hash_value = *i;
+
+            if (version == 3 && *i == kBig)
+            {
+                if (compress == 2)
+                    tmp_hash.push_back(0xffff);
+                else if (compress == 1)
+                    tmp_hash.push_back(0xff);
+                else
+                    tmp_hash.push_back(kBig);
+            }
+            else
+                tmp_hash.push_back(hash_value);
+        }
+        if (version == 3)  // kBig et al gets sorted to the end anyway.
+            std::sort(tmp_hash.begin(), tmp_hash.end());
+        query_hash_hash.push_back(tmp_hash);
+    }
+}
+
+
+
+// find candidate matches with LSH
+void neighbor_query(const vector < vector  >& query_hash,
+		      const uint64_t* lsh,
+                      vector < set >& candidates,
+                      CMinHashFile& mhfile,
+                      int num_hashes,
+                      int min_hits,
+                      double thresh,
+		      TBlastKmerPrelimScoreVector& score_vector,
+		      BlastKmerStats& kmer_stats,
+		      int kmerVer)
+{
+	int num_chunks=query_hash.size();
+
+	vector< vector > candidate_oids;
+	candidate_oids.resize(num_chunks);
+
+	for (int num=0; num::iterator i=candidates[num].begin(); i != candidates[num].end(); ++i)
+		{
+			uint64_t offset = lsh[(*i)];
+			if(offset != 0)
+			{
+				int index=(*i)+1;
+				while (lsh[index] == 0)
+					index++;
+				uint64_t read_size = (lsh[index] - offset)/4;
+				int remaining = (int) read_size;
+				int* oid_offset = mhfile.GetHits(offset);
+				index=0;
+				while (index < remaining)
+				{
+					int oid = *(oid_offset+index);
+					candidate_oids[num].push_back(oid);
+					index++;
+				}
+			}
+		}
+	}
+
+	for (int index=0; index > query_hash_hash; 
+	s_HashHashQuery(query_hash, query_hash_hash, mhfile.GetDataWidth(), mhfile.GetVersion());
+
+	vector  subject_hash;
+	subject_hash.resize(num_hashes);
+
+	map< int, double > score_map;
+	typedef map< int, double >::value_type score_mapValType;
+	// for each candidate with hits estimate Jaccard distance.
+	for (int n=0; n::iterator i = candidate_oids[n].begin(); i != candidate_oids[n].end(); ++i)
+		{  	// check that min_hits criteria satisfied.
+			if (last_oid == *i)
+			{
+				oid_count++;
+				if (min_hits != oid_count)
+					continue;
+			}
+			else
+			{
+				last_oid = *i;
+				oid_count = 1;
+				if (min_hits > 1)
+					continue;
+			}
+				
+			kmer_stats.jd_oid_count++;
+	
+			int oid = *i;
+   			int subject_oid=0;
+			mhfile.GetMinHits(oid, subject_oid, subject_hash);
+			double current_score=0;
+			if (kmerVer < 3)
+				current_score = estimate_jaccard(query_hash_hash[n], subject_hash, num_hashes);
+			else
+				current_score = estimate_jaccard2(query_hash_hash[n], subject_hash, num_hashes);
+			kmer_stats.jd_count++;
+			if (current_score < thresh)
+				continue;
+  // cerr << "OID and score " << oid << " " << total_score << '\n';
+
+			if (!score_map.count(subject_oid))
+				score_map.insert(score_mapValType(subject_oid, current_score));
+			else if (current_score > score_map[subject_oid])
+					score_map[subject_oid] = current_score;
+		}
+	}
+
+	// Print out the score
+	for(map::iterator i = score_map.begin(); i != score_map.end(); ++i)
+	{
+		double total_score = (*i).second;
+		if (total_score > thresh)
+		{
+			score_vector.push_back((*i));
+			kmer_stats.total_matches++;
+		}
+	}
+}
+
+static int
+s_BlastKmerVerifyVolume(CMinHashFile& mhfile, string& error_msg, int volume)
+{
+	int num_hashes=mhfile.GetNumHashes();
+	if(num_hashes < 32)
+	{
+		error_msg = "Only " + NStr::NumericToString(num_hashes) + " hashes in volume " + NStr::NumericToString(volume); 
+		return 1;
+	}
+	int kmerNum = mhfile.GetKmerSize();
+	if (kmerNum < 4)
+	{
+		error_msg = "Kmer size is only " + NStr::NumericToString(kmerNum) + " in volume " + NStr::NumericToString(volume); 
+		return 1;
+	}
+	int numSeqs = mhfile.GetNumSeqs();
+	if (numSeqs < 1)
+	{
+		error_msg = "Only " + NStr::NumericToString(numSeqs) + " sequences in volume " + NStr::NumericToString(volume); 
+		return 1;
+	}
+	int lshSize = mhfile.GetLSHSize();
+	if (lshSize < 1000)
+	{
+		error_msg = "LSH size is only " + NStr::NumericToString(lshSize) + " in volume " + NStr::NumericToString(volume); 
+		return 1;
+	}
+	uint64_t* lsh_array = mhfile.GetLSHArray();
+	int i=0;
+	for (i=0; i 0)
+			break;
+	}
+	if (i == lshSize)
+	{
+		error_msg = "LSH array is empty in volume " + NStr::NumericToString(volume); 
+		return 1;
+	}
+	int subjectOid=0;
+	vector hits;
+	mhfile.GetMinHits(3, subjectOid, hits);
+	if (subjectOid < 0)
+	{
+		error_msg = "Subject OID is less than zero: " + NStr::NumericToString(subjectOid) + " in volume " + NStr::NumericToString(volume); 
+		return 1;
+	}
+	if (hits.size() != static_cast(num_hashes))
+	{
+		error_msg = "Signature array only has only " + NStr::NumericToString((int) hits.size()) + " entries in volume " + NStr::NumericToString(volume); 
+		return 1;
+	}
+	if (mhfile.GetVersion() == 3)
+	{
+		uint32_t last = 0;
+        	for(vector::iterator iter=hits.begin(); iter != hits.end(); ++iter)
+		{
+			if (last > *iter)
+			{
+				error_msg = "Signature array for version 3 index not in ascending order in volume " + NStr::NumericToString(volume);
+				return 1;
+			}
+			last = *iter;
+		}
+	}
+	return 0;
+}
+
+int
+BlastKmerVerifyIndex(CRef seqdb, string &error_msg)
+{
+	int status=0;
+	vector kmerFiles;
+	seqdb->FindVolumePaths(kmerFiles, false);
+	int numFiles = kmerFiles.size();
+	for (int i=0; i
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+USING_NCBI_SCOPE;
+USING_SCOPE(objects);
+USING_SCOPE(blast);
+
+/// Places all the needed subject sequences into a scope.  
+/// The database loader (or cache perhaps?) does not seem to be thread safe, so it
+/// is avoided.
+static void 
+s_GetSequencesIntoScope(CRef resultSet, CRef scope, CRef seqdb)
+{
+	int numSearches=resultSet->GetNumQueries();
+	CRef seqid_list(new CSeqDBGiList());
+	for (int index=0; index sid = (*iter).first;
+			if (sid->IsGi())
+				seqid_list->AddGi(sid->GetGi());
+			else
+                       		seqid_list->AddSi(sid->GetSeqIdString());
+                }
+	}
+	int totalSi=seqid_list->GetNumSis();
+	int totalGi=seqid_list->GetNumGis();
+	int total=totalSi+totalGi;
+        if (total <= 0) // Nothing to be loaded.
+                return;
+
+	// This CSeqDB is just for the lookups of IDs.
+	CRef privseqdb(new CSeqDB(seqdb->GetDBNameList(), CSeqDB::eProtein, seqid_list));
+
+	vector oid_v;
+        oid_v.reserve(total);
+        for (int index=0; indexGetSiOid(index);
+                oid_v.push_back(sOid.oid);
+        }
+        for (int index=0; indexGetGiOid(index);
+                oid_v.push_back(gOid.oid);
+        }
+
+        sort(oid_v.begin(), oid_v.end());
+
+        for(vector::iterator iter=oid_v.begin(); iter!=oid_v.end(); ++iter)
+        {
+                CRef bioseq = privseqdb->GetBioseq(*iter);
+                scope->AddBioseq(*bioseq);
+        }
+	return;
+}
+
+void s_AddNewResultSet(CRef resultSet, CRef myResultSet)
+{
+	for (CSearchResultSet::iterator iter=myResultSet->begin(); iter!=myResultSet->end(); ++iter)
+	{
+		resultSet->push_back(*iter);
+	}
+}
+
+CRef s_MakeEmptyResults(CRef qf,  const CBlastOptions& opts, 
+CRef dbAdapter, TSearchMessages& msg_vec) 
+{
+         // Search was not run, but we send back an empty CSearchResultSet.
+         CRef local_query_data = qf->MakeLocalQueryData(&opts);
+         vector< CConstRef > seqid_vec;
+         vector< CRef > ancill_vec;
+         TSeqAlignVector sa_vec;
+         size_t index;
+         EResultType res_type = eDatabaseSearch;
+         unsigned int num_subjects = 0;
+         if (dbAdapter.NotEmpty() && !dbAdapter->IsBlastDb() && !dbAdapter->IsDbScanMode()) {
+        	 res_type = eSequenceComparison;
+             IBlastSeqInfoSrc *  subject_infosrc = dbAdapter->MakeSeqInfoSrc();
+             if(subject_infosrc != NULL) {
+            	 num_subjects = subject_infosrc->Size();
+             }
+         }
+         for (index=0; indexGetNumQueries(); index++)
+         {
+              CConstRef query_id(local_query_data->GetSeq_loc(index)->GetId());
+              TQueryMessages q_msg;
+	      /// FIXME, PROBLEM??
+              // local_query_data->GetQueryMessages(index, q_msg);
+              // msg_vec.push_back(q_msg);
+              seqid_vec.push_back(query_id);
+              CRef tmp_align;
+              sa_vec.push_back(tmp_align);
+              pair tmp_pair(-1.0, -1.0);
+              CRef  tmp_ancillary_data(new CBlastAncillaryData(tmp_pair, tmp_pair, tmp_pair, 0));
+              ancill_vec.push_back(tmp_ancillary_data);
+
+              for(unsigned int i =1; i < num_subjects; i++)
+              {
+            	  TQueryMessages msg;
+                  msg_vec.push_back(msg);
+                  seqid_vec.push_back(query_id);
+                  CRef tmp_align;
+                  sa_vec.push_back(tmp_align);
+           	      CRef  tmp_ancillary_data(new CBlastAncillaryData(tmp_pair, tmp_pair, tmp_pair, 0));
+           	      ancill_vec.push_back(tmp_ancillary_data);
+              }
+         }
+	 msg_vec.resize(seqid_vec.size());  // FIXME
+         CRef result_set(new CSearchResultSet(seqid_vec, sa_vec, msg_vec, ancill_vec, 0, res_type));
+         return result_set;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+//  Perform a KMER search then a BLAST search.
+
+CRef CBlastKmerSearch::Run(void)
+{
+	CRef seqdb(new CSeqDB(m_Database->GetDatabaseName(), CSeqDB::eProtein));
+	seqdb->SetNumberOfThreads(1, true);
+
+	if (m_OptsHandle->GetDbLength() == 0)
+		m_OptsHandle->SetDbLength(seqdb->GetTotalLength());
+
+	CBlastpKmerOptionsHandle* kmerOptHndl = dynamic_cast (&*m_OptsHandle);
+	CRef opts(new CBlastKmerOptions()); // KMER specific options.
+	opts->SetThresh(kmerOptHndl->GetThresh());
+	opts->SetMinHits(kmerOptHndl->GetMinHits());
+	opts->SetNumTargetSeqs(kmerOptHndl->GetCandidateSeqs());
+
+	CObjMgr_QueryFactory* objmgr_qf = NULL;
+	TSeqLocVector tsl_v;
+	if ( (objmgr_qf = dynamic_cast(&*m_QueryFactory)) )
+    	{
+		tsl_v = objmgr_qf->GetTSeqLocVector();
+		_ASSERT(!tsl_v.empty());
+	}
+	CRef blastkmer(new CBlastKmer(tsl_v, opts, seqdb));
+	if (!m_GIList.Empty())
+		blastkmer->SetGiListLimit(m_GIList);
+	else if(!m_NegGIList.Empty())
+		blastkmer->SetGiListLimit(m_NegGIList);
+
+	CRef resultSet = blastkmer->RunSearches();
+
+	//FIXME: check if all are same or use all?
+	vector< CRef > scope_v = objmgr_qf->ExtractScopes();
+	s_GetSequencesIntoScope(resultSet, scope_v[0], seqdb);
+
+	int numSearches=resultSet->GetNumQueries();
+	CRef search_results(new CSearchResultSet());
+	for (int index=0; indexGetMessage() << '\n';
+			}
+		}
+		const TBlastKmerScoreVector& scores = results.GetScores();
+
+     		if (scores.size() > 0)
+     		{
+			TSeqLocVector subjectTSL;
+			results.GetTSL(subjectTSL, scope_v[0]);
+
+			TSeqLocVector query_vector_temp;
+			query_vector_temp.push_back(tsl_v[index]);
+			CRef qfactory(new CObjMgr_QueryFactory(query_vector_temp));
+
+			BlastSeqSrc* seq_src = MultiSeqBlastSeqSrcInit(subjectTSL, eBlastTypeBlastp, true);
+			CRef seqinfo_src(new CSeqVecSeqInfoSrc(subjectTSL));
+
+			CLocalBlast lcl_blast(qfactory, CRef (m_OptsHandle.GetPointer()), seq_src, seqinfo_src);
+			CRef my_blast_results = lcl_blast.Run();
+			s_AddNewResultSet(search_results, my_blast_results);
+			seq_src = BlastSeqSrcFree(seq_src);
+		}
+		else
+		{
+			TSeqLocVector query_vector_temp;
+			query_vector_temp.push_back(tsl_v[index]);
+			CRef qfactory(new CObjMgr_QueryFactory(query_vector_temp));
+			TSearchMessages msg;
+			if (results.HasErrors() || results.HasWarnings())
+			{
+				TQueryMessages qmsg = results.GetErrors(eBlastSevWarning);
+				msg.push_back(qmsg);
+			}
+			CRef my_blast_results=s_MakeEmptyResults(qfactory, m_OptsHandle->GetOptions(), CRef(NULL), msg);
+			s_AddNewResultSet(search_results, my_blast_results);
+		}
+     }
+	
+     return search_results;
+}
+  
diff --git a/c++/src/algo/blast/proteinkmer/mhfile.cpp b/c++/src/algo/blast/proteinkmer/mhfile.cpp
new file mode 100644
index 00000000..dcaa866f
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/mhfile.cpp
@@ -0,0 +1,173 @@
+/*  $Id: mhfile.cpp 536049 2017-05-15 16:07:54Z madden $
+ * ===========================================================================
+ *
+ *                            PUBLIC DOMAIN NOTICE
+ *               National Center for Biotechnology Information
+ *
+ *  This software/database is a "United States Government Work" under the
+ *  terms of the United States Copyright Act.  It was written as part of
+ *  the author's official duties as a United States Government employee and
+ *  thus cannot be copyrighted.  This software/database is freely available
+ *  to the public for use. The National Library of Medicine and the U.S.
+ *  Government have not placed any restriction on its use or reproduction.
+ *
+ *  Although all reasonable efforts have been taken to ensure the accuracy
+ *  and reliability of the software and data, the NLM and the U.S.
+ *  Government do not and cannot warrant the performance or results that
+ *  may be obtained by using this software or data. The NLM and the U.S.
+ *  Government disclaim all warranties, express or implied, including
+ *  warranties of performance, merchantability or fitness for any particular
+ *  purpose.
+ *
+ *  Please cite the author in any work or product based on this material.
+ *
+ * ===========================================================================
+ *
+ * Author: Tom Madden
+ *
+ * File Description:
+ *   Access minhash files.
+ *
+ */
+
+
+#include 
+#include 
+
+BEGIN_NCBI_SCOPE
+BEGIN_SCOPE(blast);
+
+
+
+/// Parameterized constructor
+CMinHashFile::CMinHashFile(const string& indexname) : m_IndexName(indexname)
+{
+	if (indexname == "")
+		NCBI_THROW(CMinHashException, eArgErr, "Indexname empty");
+	
+	m_MmappedIndex.reset(new CMemoryFile(indexname + ".pki")); 
+	m_MmappedData.reset(new CMemoryFile(indexname + ".pkd")); 
+	x_Init();
+}
+
+void 
+CMinHashFile::x_Init(void)
+{
+	m_Data = (MinHashIndexHeader*) m_MmappedIndex->GetPtr();
+	if (!m_Data)
+	{
+		string errmsg = m_IndexName + ".pki has zero length";
+		NCBI_THROW(CMinHashException, eFileEmpty, errmsg);
+	}
+	
+	m_MinHitsData = (unsigned char*) (m_MmappedData->GetPtr());
+	m_DataFileSize = m_MmappedData->GetFileSize();
+	if (!m_MinHitsData || m_DataFileSize == 0)
+	{
+		string errmsg = m_IndexName + ".pkd has zero length";
+		NCBI_THROW(CMinHashException, eFileEmpty, errmsg);
+	}
+}
+
+void 
+CMinHashFile::GetMinHits(int oid, int& subject_oid, vector& hits) const
+{
+	int width = GetDataWidth();
+	int numHashes = GetNumHashes();
+	if (hits.size() < numHashes)
+		hits.resize(numHashes);
+
+	uint32_t* a = &(hits[0]);
+	if (width == 4)
+	{
+		uint32_t* array = x_GetMinHits32(oid, subject_oid);
+#pragma ivdep
+		for (int index=0; index 1)
+		extraOffset = 2; // Two four-byte integers.
+
+	return ((uint32_t*)m_MmappedIndex->GetPtr()) + KMER_RANDOM_NUM_OFFSET/4 + extraOffset;
+}
+
+void
+CMinHashFile::GetBadMers(vector &badMers) const
+{
+	if (GetVersion() < 3)
+		return;
+
+	int extraOffset = 2;
+	
+	uint32_t* array = ((uint32_t*)m_MmappedIndex->GetPtr()) + KMER_RANDOM_NUM_OFFSET/4 + extraOffset;
+	int num = array[0];
+
+	for (int i=1; i<=num; i++)
+		badMers.push_back(array[i]);
+	return;
+}
+
+unsigned char* 
+CMinHashFile::GetKValues(void) const 
+{
+	int extraOffset=0;
+	if (GetVersion() > 1)
+		extraOffset = 8; // Eight bytes.
+
+	return ((unsigned char*)m_MmappedIndex->GetPtr()) + KMER_RANDOM_NUM_OFFSET + 2*4*GetNumHashes() + extraOffset;
+}
+
+inline uint32_t*
+CMinHashFile::x_GetMinHits32(int oid, int& subject_oid) const
+{
+	int num_hashes = GetNumHashes();
+	uint32_t* array = (uint32_t*) (m_MinHitsData + (uint64_t)(GetDataWidth()*num_hashes+4)*oid);
+	subject_oid = array[num_hashes];
+	
+	return array;
+}
+
+inline uint16_t*
+CMinHashFile::x_GetMinHits16(int oid, int& subject_oid) const
+{
+	int num_hashes = GetNumHashes();
+	uint16_t* array = (uint16_t*) (m_MinHitsData + (uint64_t)(GetDataWidth()*num_hashes+4)*oid);
+	subject_oid = *(uint32_t*) &(array[num_hashes]);
+	// subject_oid = *(uint32_t*) ((m_MinHitsData + (uint64_t)((num_hashes+2)*oid + num_hashes)));
+	
+	return array;
+}
+
+inline unsigned char*
+CMinHashFile::x_GetMinHits8(int oid, int& subject_oid) const
+{
+	int num_hashes = GetNumHashes();
+	unsigned char* array = (unsigned char*) (m_MinHitsData + (uint64_t)(GetDataWidth()*num_hashes+4)*oid);
+	subject_oid = *(uint32_t*) &(array[num_hashes]);
+	// subject_oid = *(uint32_t*) ((m_MinHitsData + (uint64_t)((num_hashes+4)*oid + num_hashes))/4);
+	
+	return array;
+}
+
+END_SCOPE(blast)
+END_NCBI_SCOPE
diff --git a/c++/src/algo/blast/proteinkmer/pearson.cpp b/c++/src/algo/blast/proteinkmer/pearson.cpp
new file mode 100644
index 00000000..1e2df2f3
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/pearson.cpp
@@ -0,0 +1,99 @@
+/*  $Id: pearson.cpp
+ * ===========================================================================
+ *
+ *                            PUBLIC DOMAIN NOTICE
+ *               National Center for Biotechnology Information
+ *
+ *  This software/database is a "United States Government Work" under the
+ *  terms of the United States Copyright Act.  It was written as part of
+ *  the author's official duties as a United States Government employee and
+ *  thus cannot be copyrighted.  This software/database is freely available
+ *  to the public for use. The National Library of Medicine and the U.S.
+ *  Government have not placed any restriction on its use or reproduction.
+ *
+ *  Although all reasonable efforts have been taken to ensure the accuracy
+ *  and reliability of the software and data, the NLM and the U.S.
+ *  Government do not and cannot warrant the performance or results that
+ *  may be obtained by using this software or data. The NLM and the U.S.
+ *  Government disclaim all warranties, express or implied, including
+ *  warranties of performance, merchantability or fitness for any particular
+ *  purpose.
+ *
+ *  Please cite the author in any work or product based on this material.
+ *
+ * ===========================================================================
+ *
+ * Author: Tom Madden
+ *
+ * File Description:
+ *   Calculate Pearson hash per:
+ *   http://portal.acm.org/citation.cfm?id=78978
+ *   http://cs.mwsu.edu/~griffin/courses/2133/downloads/Spring11/p677-pearson.pdf
+ *
+ * 	
+ */
+
+
+#include 
+#include "pearson.hpp"
+
+// Pearson hash takes a string of bytes and returns one byte key.
+unsigned char pearson_hash(unsigned char* key, int length, int init)
+{
+        unsigned char hash = init;
+        int i;
+        for (i=0; i> 8) & 0xff;
+	key[2] = (input >> 16) & 0xff;
+	key[3] = (input >> 24) & 0xff;
+	
+	/* return value */
+	unsigned char hash = pearson_hash(key, kLength, seed1);
+	return hash;
+}
+
+
+// Pearson hash for an integer to a short (two bytes)
+uint16_t pearson_hash_int2short(uint32_t input, int seed1, int seed2)
+{
+	unsigned char key[4];
+	const int kLength=4;
+	uint16_t foo; /* return value; */
+
+	key[0] = input & 0xff;
+	key[1] = (input >> 8) & 0xff;
+	key[2] = (input >> 16) & 0xff;
+	key[3] = (input >> 24) & 0xff;
+
+	unsigned char hash = pearson_hash(key, kLength, seed1);
+	foo = (hash << 8);
+        hash = pearson_hash(key, kLength, seed2);
+        foo = foo | hash;
+	return foo;
+}
+
+
diff --git a/c++/src/algo/blast/proteinkmer/pearson.hpp b/c++/src/algo/blast/proteinkmer/pearson.hpp
new file mode 100644
index 00000000..5e00d2fc
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/pearson.hpp
@@ -0,0 +1,72 @@
+/*  $Id: pearson.hpp
+ * ===========================================================================
+ *
+ *                            PUBLIC DOMAIN NOTICE
+ *               National Center for Biotechnology Information
+ *
+ *  This software/database is a "United States Government Work" under the
+ *  terms of the United States Copyright Act.  It was written as part of
+ *  the author's official duties as a United States Government employee and
+ *  thus cannot be copyrighted.  This software/database is freely available
+ *  to the public for use. The National Library of Medicine and the U.S.
+ *  Government have not placed any restriction on its use or reproduction.
+ *
+ *  Although all reasonable efforts have been taken to ensure the accuracy
+ *  and reliability of the software and data, the NLM and the U.S.
+ *  Government do not and cannot warrant the performance or results that
+ *  may be obtained by using this software or data. The NLM and the U.S.
+ *  Government disclaim all warranties, express or implied, including
+ *  warranties of performance, merchantability or fitness for any particular
+ *  purpose.
+ *
+ *  Please cite the author in any work or product based on this material.
+ *
+ * ===========================================================================
+ *
+ * Author: Tom Madden
+ *
+ * File Description:
+ *   Calculate Pearson hash per:
+ *   http://portal.acm.org/citation.cfm?id=78978
+ *   http://cs.mwsu.edu/~griffin/courses/2133/downloads/Spring11/p677-pearson.pdf
+ *
+ * 	
+ */
+#include 
+
+/* copied from wikipedia.  produce my own? */
+
+const unsigned char pearson_tab[256] = {
+// 256 values 0-255 in any (random) order suffices
+ 98,  6, 85,150, 36, 23,112,164,135,207,169,  5, 26, 64,165,219, //  1
+ 61, 20, 68, 89,130, 63, 52,102, 24,229,132,245, 80,216,195,115, //  2
+ 90,168,156,203,177,120,  2,190,188,  7,100,185,174,243,162, 10, //  3
+237, 18,253,225,  8,208,172,244,255,126,101, 79,145,235,228,121, //  4
+123,251, 67,250,161,  0,107, 97,241,111,181, 82,249, 33, 69, 55, //  5
+ 59,153, 29,  9,213,167, 84, 93, 30, 46, 94, 75,151,114, 73,222, //  6
+197, 96,210, 45, 16,227,248,202, 51,152,252,125, 81,206,215,186, //  7
+ 39,158,178,187,131,136,  1, 49, 50, 17,141, 91, 47,129, 60, 99, //  8
+154, 35, 86,171,105, 34, 38,200,147, 58, 77,118,173,246, 76,254, //  9
+133,232,196,144,198,124, 53,  4,108, 74,223,234,134,230,157,139, // 10
+189,205,199,128,176, 19,211,236,127,192,231, 70,233, 88,146, 44, // 11
+183,201, 22, 83, 13,214,116,109,159, 32, 95,226,140,220, 57, 12, // 12
+221, 31,209,182,143, 92,149,184,148, 62,113, 65, 37, 27,106,166, // 13
+3, 14,204, 72, 21, 41, 56, 66, 28,193, 40,217, 25, 54,179,117, // 14
+238, 87,240,155,180,170,242,212,191,163, 78,218,137,194,175,110, // 15
+43,119,224, 71,122,142, 42,160,104, 48,247,103, 15, 11,138,239  // 16
+};
+
+// Pearson hash takes a string of bytes and returns one byte key.
+unsigned char pearson_hash(unsigned char* key, int length, int init);
+              
+// Do three pearson hashes in a row on the key.
+uint32_t do_pearson_hash(unsigned char *key, int length);
+
+/// Do two pearson hashes in a row on the key.
+uint32_t do_pearson_hash2bytes(unsigned char *key, int length);
+
+/// Pearson hash an integer into one byte.
+unsigned char pearson_hash_int2byte(uint32_t input, int seed1=11); 
+
+/// Pearson hash an integer into two bytes.
+uint16_t pearson_hash_int2short(uint32_t input, int seed1=11, int seed2=101);
diff --git a/c++/src/algo/blast/proteinkmer/unit_test/Makefile.in b/c++/src/algo/blast/proteinkmer/unit_test/Makefile.in
new file mode 100644
index 00000000..c2171d81
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/unit_test/Makefile.in
@@ -0,0 +1,13 @@
+#
+# Makefile:  /export/home/madden/KMERS/SVN_READY/trunk/internal/c++/src/internal/blast/proteinkmer/unit_test/Makefile.in
+#
+# This file was originally generated by shell script "new_project" (r442644)
+# Tue Dec  9 12:02:21 EST 2014
+#
+
+# $Id: Makefile.in 454079 2014-12-10 19:02:49Z madden $
+
+APP_PROJ = proteinkmer_unit_test
+
+srcdir = @srcdir@
+include @builddir@/Makefile.meta
diff --git a/c++/src/algo/blast/proteinkmer/unit_test/Makefile.proteinkmer_unit_test.app b/c++/src/algo/blast/proteinkmer/unit_test/Makefile.proteinkmer_unit_test.app
new file mode 100644
index 00000000..2d4732a0
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/unit_test/Makefile.proteinkmer_unit_test.app
@@ -0,0 +1,31 @@
+# $Id: Makefile.proteinkmer_unit_test.app 538598 2017-06-12 17:24:29Z ivanov $
+
+###  BASIC PROJECT SETTINGS
+APP = proteinkmer_unit_test
+SRC = proteinkmer_unit_test
+# OBJ =
+
+CPPFLAGS = $(ORIG_CPPFLAGS) $(BOOST_INCLUDE)
+
+LIB_ = test_boost proteinkmer $(BLAST_DB_DATA_LOADER_LIBS) \
+       $(BLAST_LIBS) xobjsimple $(OBJMGR_LIBS)
+
+LIB = $(LIB_:%=%$(STATIC))
+
+LIBS = $(NETWORK_LIBS) $(CMPRS_LIBS) $(DL_LIBS) $(ORIG_LIBS)
+
+REQUIRES = Boost.Test.Included
+
+# Comment out if you do not want it to run automatically as part of
+# "make check".
+CHECK_CMD =
+# If your test application uses config file, then uncomment this line -- and,
+# remember to rename 'foo.ini' to '.ini'.
+#CHECK_COPY = foo.ini
+CHECK_COPY = data
+
+###  EXAMPLES OF OTHER SETTINGS THAT MIGHT BE OF INTEREST
+# PRE_LIBS = $(NCBI_C_LIBPATH) .....
+# CFLAGS   = $(FAST_CFLAGS)
+# CXXFLAGS = $(FAST_CXXFLAGS)
+# LDFLAGS  = $(FAST_LDFLAGS)
diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/129295.fsa b/c++/src/algo/blast/proteinkmer/unit_test/data/129295.fsa
new file mode 100644
index 00000000..372a4c89
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/unit_test/data/129295.fsa
@@ -0,0 +1,4 @@
+>gi|129295|sp|P01013.1|OVALX_CHICK RecName: Full=Ovalbumin-related protein X; AltName: Full=Gene X protein [Gallus gallus]
+QIKDLLVSSSTDLDTTLVLVNAIYFKGMWKTAFNAEDTREMPFHVTKQESKPVQMMCMNNSFNVATLPAEKMKILELPFA
+SGDLSMLVLLPDEVSDLERIEKTINFEKLTEWTNPNTMEKRRVKVYLPQMKIEEKYNLTSVLMALGMTDLFIPSANLTGI
+SSAESLKISQAVHGAFMELSEDGIEMAGSTGVIEDIKHSPESEQFRADHPFLFLIKHNPTNTIVYFGRYWSP
diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/129295.iupacaa b/c++/src/algo/blast/proteinkmer/unit_test/data/129295.iupacaa
new file mode 100644
index 00000000..9ac4ed9c
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/unit_test/data/129295.iupacaa
@@ -0,0 +1,28 @@
+Bioseq ::= {
+  id {
+    local id 1
+  },
+  descr {
+    user {
+      type str "CFastaReader",
+      data {
+        {
+          label str "DefLine",
+          data str ">gi|129295|sp|P01013.1|OVALX_CHICK RecName:
+ Full=Ovalbumin-related protein X; AltName: Full=Gene X protein [Gallus gallus]"
+        }
+      }
+    },
+    title "gi|129295|sp|P01013.1|OVALX_CHICK RecName: Full=Ovalbumin-related
+ protein X; AltName: Full=Gene X protein [Gallus gallus]"
+  },
+  inst {
+    repr raw,
+    mol aa,
+    length 232,
+    seq-data iupacaa "QIKDLLVSSSTDLDTTLVLVNAIYFKGMWKTAFNAEDTREMPFHVTKQESKPVQMM
+CMNNSFNVATLPAEKMKILELPFASGDLSMLVLLPDEVSDLERIEKTINFEKLTEWTNPNTMEKRRVKVYLPQMKIEE
+KYNLTSVLMALGMTDLFIPSANLTGISSAESLKISQAVHGAFMELSEDGIEMAGSTGVIEDIKHSPESEQFRADHPFL
+FLIKHNPTNTIVYFGRYWSP"
+  }
+}
diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/129295.ncbieaa b/c++/src/algo/blast/proteinkmer/unit_test/data/129295.ncbieaa
new file mode 100644
index 00000000..a174df11
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/unit_test/data/129295.ncbieaa
@@ -0,0 +1,28 @@
+Bioseq ::= {
+  id {
+    local id 1
+  },
+  descr {
+    user {
+      type str "CFastaReader",
+      data {
+        {
+          label str "DefLine",
+          data str ">gi|129295|sp|P01013.1|OVALX_CHICK RecName:
+ Full=Ovalbumin-related protein X; AltName: Full=Gene X protein [Gallus gallus]"
+        }
+      }
+    },
+    title "gi|129295|sp|P01013.1|OVALX_CHICK RecName: Full=Ovalbumin-related
+ protein X; AltName: Full=Gene X protein [Gallus gallus]"
+  },
+  inst {
+    repr raw,
+    mol aa,
+    length 232,
+    seq-data ncbieaa "QIKDLLVSSSTDLDTTLVLVNAIYFKGMWKTAFNAEDTREMPFHVTKQESKPVQMM
+CMNNSFNVATLPAEKMKILELPFASGDLSMLVLLPDEVSDLERIEKTINFEKLTEWTNPNTMEKRRVKVYLPQMKIEE
+KYNLTSVLMALGMTDLFIPSANLTGISSAESLKISQAVHGAFMELSEDGIEMAGSTGVIEDIKHSPESEQFRADHPFL
+FLIKHNPTNTIVYFGRYWSP"
+  }
+}
diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/129295.stdaa b/c++/src/algo/blast/proteinkmer/unit_test/data/129295.stdaa
new file mode 100644
index 00000000..7b2f2ba0
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/unit_test/data/129295.stdaa
@@ -0,0 +1,31 @@
+Bioseq ::= {
+  id {
+    local id 1
+  },
+  descr {
+    user {
+      type str "CFastaReader",
+      data {
+        {
+          label str "DefLine",
+          data str ">gi|129295|sp|P01013.1|OVALX_CHICK RecName:
+ Full=Ovalbumin-related protein X; AltName: Full=Gene X protein [Gallus gallus]"
+        }
+      }
+    },
+    title "gi|129295|sp|P01013.1|OVALX_CHICK RecName: Full=Ovalbumin-related
+ protein X; AltName: Full=Gene X protein [Gallus gallus]"
+  },
+  inst {
+    repr raw,
+    mol aa,
+    length 232,
+    seq-data ncbistdaa '0F090A040B0B1311111112040B0412120B130B130D010916060A07
+0C140A1201060D0105041210050C0E060813120A0F05110A0E130F0C0C030C0D0D11060D130112
+0B0E01050A0C0A090B050B0E06011107040B110C0B130B0B0E04051311040B051009050A12090D
+06050A0B120514120D0E0D120C050A1010130A13160B0E0F0C0A0905050A160D0B1211130B0C01
+0B070C12040B06090E11010D0B12070911110105110B0A09110F0113080701060C050B11050407
+09050C010711120713090504090A08110E0511050F06100104080E060B060B090A080D0E120D12
+0913160607101614110E'H
+  }
+}
diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/129296.ncbieaa b/c++/src/algo/blast/proteinkmer/unit_test/data/129296.ncbieaa
new file mode 100644
index 00000000..b3104696
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/unit_test/data/129296.ncbieaa
@@ -0,0 +1,19 @@
+Bioseq ::= {
+  id {
+    local id 2
+  },
+  descr {
+    title "RecName: Full=Ovalbumin-related protein Y; AltName: Full=Gene Y protein"
+  },
+  inst {
+    repr raw,
+    mol aa,
+    length 388,
+    seq-data ncbieaa "MDSISVTNAKFCFDVFNEMKVHHVNENILYCPLSILTALAMVYLGARGNTESQMKKVLHFDSI
+TGAGSTTDSQCGSSEYVHNLFKELLSEITRPNATYSLEIADKLYVDKTFSVLPEYLSCARKFYTGGVEEVNFKTAAEE
+ARQLINSWVEKETNGQIKDLLVSSSIDFGTTMVFINTIYFKGIWKIAFNTEDTREMPFSMTKEESKPVQMMCMNNSFN
+VATLPAEKMKILELPYASGDLSMLVLLPDEVSGLERIEKTINFDKLREWTSTNAMAKKSMKVYLPRMKIEEKYNLTSI
+LMALGMTDLFSRSANLTGISSVDNLMISDAVHGVFMEVNEEGTEATGSTGAIGNIKHSLELEEFRADHPFLFFIRYNP
+TNAILFFGRYWSP"
+  }
+}
diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.phr b/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.phr
new file mode 100644
index 0000000000000000000000000000000000000000..ccc877b88101251b52346cf0fc8b15622973af77
GIT binary patch
literal 124
zcmXqLFlboNAZ1celwXpXUyzYs48-XD3Izq}CJNC$shPzYxruq1i3*u{X^D9y
zrMU`T0nWaru?!3gfx1^WFtKoK4S2@DuoB2y*dWCd5fE=+U}$1yVPR&@z_7T1iII^3
K4i*8qP!0fzS|gSK

literal 0
HcmV?d00001

diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pin b/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pin
new file mode 100644
index 0000000000000000000000000000000000000000..21a4b6b7d56d2477ebf65471135bac695cc7bd59
GIT binary patch
literal 88
zcmZQzU|?ZjU|
Zqc2bfsK;L%OalpVe<-U4Bo5>U0stU&3f%wz

literal 0
HcmV?d00001

diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pnd b/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pnd
new file mode 100644
index 0000000000000000000000000000000000000000..84f3406b07c900fe3518ab369c8147a993cd791b
GIT binary patch
literal 8
Ncmd

literal 0
HcmV?d00001

diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pni b/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pni
new file mode 100644
index 0000000000000000000000000000000000000000..b5d93f26f0c83b4b1017a63ddbd0fb9ea00da3a6
GIT binary patch
literal 52
gcmZQzU|?i`01hApVgoTu2r98P;2DVZ9|%A+05>27`~Uy|

literal 0
HcmV?d00001

diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pog b/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.pog
new file mode 100644
index 0000000000000000000000000000000000000000..f9613a4535a201d6f9230ec1989b64056e9bd467
GIT binary patch
literal 36
acmZQzU|?i`02UwxV?%`)7&x{DJOcm(g8}*g

literal 0
HcmV?d00001

diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.psd b/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.psd
new file mode 100644
index 00000000..2a6220b3
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.psd
@@ -0,0 +1,2 @@
+xp_0014688670
+xp_001468867.10
diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.psi b/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.psi
new file mode 100644
index 0000000000000000000000000000000000000000..b17280b1fd9af1cfeabd687af50d776017c4302f
GIT binary patch
literal 67
xcmZQzU|?imU|<4b1t<;TJ1{T^04Wrp0OXkfv2#U1yn%tCiJ66knK_dI0{}uq1YZCE

literal 0
HcmV?d00001

diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.psq b/c++/src/algo/blast/proteinkmer/unit_test/data/XP_001468867.psq
new file mode 100644
index 0000000000000000000000000000000000000000..66289bb74c75a9614516add3557370816c193b45
GIT binary patch
literal 5969
zcmeHL+j8SD2rZ+VC9Dge@&AA7;>7L5&c>;m&Gs_YONM~Xfdi5~ei_MQZ_RM4wLk;_
zL<594q8JI%2*^4JjMk7eDS09QSL?uS^k^X_fLH*Tq_eTv8yHd$XIOXPAPuuvixLQn
zi^T7C45YpQ)JE6xgf%6xuFdSO2Mx(F31;Ms$~5x=DHb-wP!WN0Ms&;nnsiEt7AwY(
zljjg)sfy!92CT}e9y=K}QY!VxEs4{TCt|@6tZ|Xa8ZB6tLuYI#vG|D#*9t0O_UOQ;
zi6bjXL6wkILg{Xj!Ek{fAPN%Lc^^oMlLA(9A*T{jLhEUu(8UEe71By@RTD+601vL*-8=MIef^dFJIa3Vbp5RNrQg}te&2jXziSr0
z&5-L?O{ukF1N|ndYishWmjti9%U;&Kx4kp+zIWz*BU%ODLq2Eqws&J*RkTUt!)9D1
m`4{Q-kykoj3A?{{-+QTK4E`$kvb|T%Rr6=>qH93xFMj}W<}empty"
+            }
+          }
+        },
+        title "empty"
+      },
+inst {
+    repr raw,
+    mol aa,
+    length 38,
+    seq-data iupacaa "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
+  }
+}
diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/bad.asn b/c++/src/algo/blast/proteinkmer/unit_test/data/bad.asn
new file mode 100644
index 00000000..fbeff8d0
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/unit_test/data/bad.asn
@@ -0,0 +1,22 @@
+Bioseq ::= {
+      id {
+        local id 4
+      },
+      descr {
+        user {
+          type str "CFastaReader",
+          data {
+            {
+              label str "DefLine",
+              data str ">empty"
+            }
+          }
+        },
+        title "empty"
+      },
+      inst {
+        repr virtual,
+        mol aa,
+        length 0
+      }
+}
diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/manyXs.phr b/c++/src/algo/blast/proteinkmer/unit_test/data/manyXs.phr
new file mode 100644
index 0000000000000000000000000000000000000000..f74c590a13a38336c04cb51e8725bcdf799e5d0e
GIT binary patch
literal 65
ycmXqLFlboNAjPDhz`(E&$X*5EvxK+?hk!&DHb}AMCgxRE6f+=!MGZ`hP%Z#()(tB|blT@0UnWtNnnv+Bnbf~3?vH7`{m5-uO@o|uzUTC9)`reYZw76L6;-N3}m_)~y^VL8M$ZvQYxpU8M;
z4^L-rkP0cb00Tn3xu;9wDu3*{I<3{uX=aA>3g
zE+?>veYtg%fng0$E6_>~Cr4jHVR~Jv`5LXu~1>E5lshg9TovIM+n4Fkbl95@QSyGaykerc|UzAylNT@6t
XnF2P5Xo~u$~#9rt6
zZ+$W~A?E1L;5ILIm+qSna}F>7LGwD08T{|QIqhbt{mTCiWJdVhkC#lP(;4L_HT?FK
zydm^?;XEOw#hL%Fb6w|R{d4$lA7|#>kFs&SHy=)a0WxFFckw&jmtXeyU0SKW^Rt^7
zr@8w6*xw&7)-8{Fi!T8x%qOzbuRVo7x(A9JGwK@!;Af~`NjRG!kK_(D1HQ)0g4x&Mo_$H
z=sIqU{e5~eC|-7DEZLOz?uJll(LABklR;+Od~y*O;!hPb@6Om+uMRV#R7?Dh`ze<%
zlCq$9NoN$lvjeEg<%{^8bjDYOiLB3^E_3niT$}`omltnuKFK{YIbTTG{15k`mFj%v
z{3RfFfc(-W2k}e%bNqghn#=xl>0yLl>blsUGE>1XATuC-;eQA53;#P({Q@%M>cJ<~
zkT3;>2mia>HveA3!t{i}l1)E@eg;9p^z`HvdN-ehyT|_i#|sKmNO-V--SMP)r8+E3
z|MA9pK*BVo?`{?-Oy@L#!t{hFBuu%MB8O?qasCpJ8I|1AZqJzD_j&%k-7M)j?+xd_
zaoC`IeA?|>jPu{*SKiM}TAzNvf^Xux)=XagS3(y$HZ2khKDyJK`4%H6-%dZr3N&N0
zV3~S+%z+f4rw`(5zb*{|nNj~sQW#{0z?b{En---XC=JNFn(_{0#`FuD7S;c%|CM=n
zy4&r0Hy;Xo0h#gk*2ilPcfb4B`LR^%qF~ga!xwh!KOrP3Y+P9rvGS>6BPcxhcFsJO
gxoGBHy`@ZZ{U-k6_CDJ#@%50+k>mL`M?hu(0E9|F>;M1&

literal 0
HcmV?d00001

diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pki b/c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pki
new file mode 100644
index 0000000000000000000000000000000000000000..9b89032cead330b1a306de934e1930efcf15aae2
GIT binary patch
literal 134220152
zcmeFtJ&0UY7zW_?-n%n%ckbL7MQ3+N#w3WP3nCU`k-{IeNVAn-a197HiG>m&Q41B6
zu-o_tiiNCT5s}!K1WX}Y1tk_Xf+368NK7RvSZI?8m_9`aOXfM8kHdkFbH4W}lXPdb
zZ&rI|)tOcKf6a~@E0Syb*kbBy_v`Dqr6wO98RYRVk`r&%`D`>ywZF;RD@EQrTIS03
zFfYuSAG)`jhtDTxyTknP=O9n54|3PZUZxlOS-Zc<2cNcibYGD#9~)%zlYUpVYA&b?LT_jlU-w$;yQ(jAwJ)pAoUkJHv|mX@b?
zPnvN#nCzY`-P0Q_Oz&*>E>5bnRXe_8IOz4WcRVhNcDn1jp_2ds0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBnAZ-F<8)blMMJplp)2oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UATTciCyLbbl2uLu1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNA}y9m5n
zq`qCU$U%Sr0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAVA<&3v3ptZ}p%4BS3%v0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0ykUW^CI=le$#sd2oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t9x7z{w)@PMO6V1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C7Zd72aNPVNd`UnspK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oRVrf$xgc^Oaay0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNB!^96n=Qt$jJO-O(M0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7csfvfD?Arits3zh{009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C7MizKgdgOev5g<3lFbqY(OjIO-10aw{B!c^&3WKkxX{YPc&VNgQ009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0)q)`88z4>a|jS1K!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oRWDV9%(@6U-+-fB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72rMaZWYm)3q6rWnK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RoE&oEf!PvRncL2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7et|2aU=SccfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UxHF0Z0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PHVRo{VZ=
zxgbD*009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB=DBfj6Ui|L~pw0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0v|heXaqnA0|77-mBNrn1mgRz!)+qe)QK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5;&zQD++eu@MF1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB=D0
z1!hK_+D$J41PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+0D->1%BX&d1OfyI5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAn>NZ&Zsw+TTOrf0RjXF5FkK+009C72oNAZfB=EJ1wQ}XyAP;60RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB=D?eLKVf7zUvLN>Chga&iZltk|)4g_@>mc%A_Np&>wk009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+Kuduuqgng)uzCqRGz0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjYmcJ2@dfgpwgXj9eWBM=A#f+HZ12qXvKIOt7Q?rv!F
z#L-
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV6Safwz5(8;g35009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oRVm@X4sD-Si?rfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjY;0^f{UPMio3AV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RlgE?GOop7={99rZEvn
z1QN;p&xAxEkO%}~{m#x#GkvZVP5*zjB|v}x0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5;&zrb@uu^>Qz009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7e?3<9qaHA4;=2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U*aY4qYTH>6AV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72y_$pjHqsz*Nob6%nYzB0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0^=qlD}CIWB?1Hp5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0{aTwD!uQ5-w6;PK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk+XU{F-u8oQ0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7csff)oIm7bwf
zBLM;g2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009E)1)h~&f9;Y00RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C^fmfxMuU-fcAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZV3feS(xbNR5+Fc;009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!Ct}0-s9HSFM-;0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1kNV#t@PQN^bjCGfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7W)k>SdZu2j1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK;X}=9a7bH+@;2n2!xkO(9Kfj}TBj~cQOnQU$WfAi+*5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oRWG
z;FMAGU+F>u1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FpS);G9uC
zN>mUaK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5a=&($*BI73JDM(K!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5)G6S!v7x)-bo5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009DH0=JABTUrqyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV8ppz&)dSl&By;fB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyuwQ{kM(wv=IROF$2oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZU^{`Q|1h`1_hkYE2oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfWQF+UKw?OGo46)009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C`1l}3dBt-@R0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB=ET0-uapJTf3afB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0tBWK_-52p2RViS0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyKwwDVmr+AQBLV~n5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0Rja6?A;*_!axuO&`Aa{_dgE;i9jL|2qXf5L|`kM
zZPINr&$Y?U{{3%tQvw7C5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5NIQC&ZstJ6(vA`009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&w1TGo1c=bqt009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBn=P2lRk
zio010B0zuu0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkKcOyHJLW0R%`5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PE*wxM$S%UF<-B009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0tDs=JThudvQz>D2oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+KyQI(M)elZo&W&?1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PII%cxBYQbjbt=5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjY$E%45$W1rCJ2oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
z&|Bb>QN0DUCqRGz0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyKwz!FH>1|BwT=J*0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5(*
z3j8u^bk-aJ0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+0D-mwC*S3?y?ez85FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB=C%dv}P0FbqTi
zbj6C5NF)M*L?Vz#4uC`;xxZ!xSr?PE>64jB=Kp=sX$cS@K!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfWQg_Dx+3VLj?i^2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB=D&3mh_P
z@1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7csfk_0ezRx3$hC#44z3ENXhX4Tr
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7csfm>k6C=vt+5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1X==PMz!9|2@oJafB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfIzRnlu^A|
zIRXR-5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK%h@xcE8sLB}IS$0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB=D?3M?7*)77m_fB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBm#Rbb7i
zR||YjfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfWV``mQjx(
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!Cu90((Y%Sg)D@0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7csflJ`XC=dh)5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1Wxwt5D7pigaROe!2M5PFdB?TgV95If?u71*-YTQ9V!F}
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+z@GwJM*X?ZE&>Dy5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXFbQRb$
zs%v(+2@oJafB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C7)&fUHt*0gg2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RpFgOh-U~009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!Ctdfh(hi
zR#S@r0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXFj1jmqYD^hL2oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+KvRJyqnbt+n*ad<1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C78VS4^)hMp01PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72z>0&p$z~q2t`2zg8iqftgPq|9RX9vX~<9B5g+Ykq`!AD1b&ZGZ6?5fIuRVNF)-;{ZD{Ia)uS#?Y7VF
zqxvz?Xz0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk2Nn1(Q3oB}*aQd=AV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7dXXMx`m)j2|W
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0_zE6)Oul(2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5;&JqT1r?O_fx5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+0D%^PllSLZxSS0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZV0M9<|3uHeLj4mUK!5-N0t5&UAV7cs0RjXF5FkK+009Dx0(bW#
zjbe@yAV7cs0RjXF5FkK+009C72oNAZfB*pk1o{d*+~4#CR-FI=0t5&UAV7e?4h5c`
zBX+n|BM~4#fB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0Rkfh
zUKuqqUp4^(1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBly5b@3^4g?4gAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PJsM_+(Vy1l0);AV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72>jWh
zR~&=_7>a^5H|Zh~NF)M*Kq3(=nJpmRFR$a9wr2{zm0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5Liawp6X>b
z*+PH-0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7csff)jiRL>|?Nq_(W0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1kNw;O!fII6%rsofB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oU&B;FaqCCQT6_K!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U*k0hB>g}((NPqwV0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009Df3w%<&_Ydw9AV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UIGVsW)kpiuKLiL6AV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oU(OcZVnp1ThpqzX|02R8&+{tgNW4tn9IRfn8X$Fpy`H5PseqU@XT%`K!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C^2z)EOL=Yhe5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyKwwwkSLxk`A^`#f2oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZ;Li>n;s6N5Kme?1(*M5;fj}UU2p&O#K5@89Gq&v}-624L009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pkLxC-$
zh6_Ui1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBoL1on(VL4W`O0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z{{@bW`k#^@K!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV6RRfit64_`?qb2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!8ABfh(i>w$qFN0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7x(VDF
z)vc301PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72+RpQ88vt5iU0uu1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1YUON5D8!y1Ogx?45G6Ce`Q5veS9*^WF-jhSONqH5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk{RO@e)xV{N1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009E4z#LKQ
z&P;#+0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBmlDUeYudnrYL009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+0D;2-l~IQy#StJtfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7csf$IdGjJob=4-+6jfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV6TFz?)GU&pS0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&U7%Fi3Ya4nwu?Y|$K!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PII#xH4)^T1g2IAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0Rrm@+!?iAD~$*cAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0tC7OPeyfjm?uDh009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB=F21>TJM*tRvn$
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oPvo;G9v7M--0$0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+z+iz(Mhz}jNPqwV
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk%?e!YuW$C>2u6Sa0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5(bOW>AK+nUHU1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RmG9+%sy5K6(%!K!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7e?G6Ii`TIOcA
z5+Fc;009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5)GS>TybYtAn_0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7e?IDwaa7308E6Cgl<009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oRV+;GIzuw9$e90RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2=oekGOG8$M*;*05FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5;&rUbqj)l?v12oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7dXg95*dYA}{a1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0tEi-+#wPI
zF$_S_sBG?ksuc(X5`kEWKp+uZp{6s=U=lPZZ0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oPu^uxC`8SfK<6
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+0D;B=w~T6>FP#7Z0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+0D*}D_l%l&yrT&aAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1WqdO$f%R9W-S5)2oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RqDUPw#Grtqc+%
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+KtF+3
zM)j*!On?9Z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UxSqg~QP;?h^
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK%j@f7S$tEB>@5i2oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FjurP+QdKtT_S%2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7csfj|3phyx)M0|9hgD-p<*D>wuaiRAug*}VXc5XgVJNjvj=2@oJafB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+z$gM!rAO(iCjkNk2oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXFoD0mA
zKA)NpAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyKp^>4ngam>1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009E`3Vi+f-V5#;0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+0D*x8mP!v?Uv&Zm2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBngNMNn>MXRhKK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7csfd>d|m3}}B
z5eN_y2v#I2oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5;&HGwaq)+VG05FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyKwzi9?+5nQ@m*1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oSi6
zz^5x$>7oY#0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF%p>sa$~P>`#$E
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+0D*A??*4fn=dm;;K!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FoIaz$2B#
zCYwuu009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAh3YI
zGnEBqnn-{E0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZU?_ntm7xkNOMn0Y0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1pe&Mp$)(=3>rj{pGz1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5;&j=+&hXGBbZ009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+z@)&L%H#>_1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBly&=9y%X~ZG|1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkKcBY``Wjq0dEfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyKwwDVNo8okFaZJt2oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2rMn|rm}Pa&l4a(fB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7e?mI7ZYTNYD_009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNCfvqOhA0K-rW1r0q|
zVPQc*_n)IXB%egO0sLeg0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfWV@_)pT)cMt}eT0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNA}kigyapu4UTAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfWVNz({v~$Lx2DQ0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0tB`N-lp3T0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!CuYz}IvzCq;k&0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0Rlfe^lk(o2n7M~g;%D5fuW%V
z7+AJV05iZgaGxbWfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5EvwI
zq%x>V4FLiK2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!Csifisl>
zH7W=YAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5(bC2*y(
z)nR7|5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAkawQPNh+l7y<+c5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk-2|Rgx`hiSK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyKwv6?
zH9;009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5(56ga0c
z@e{`h5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7csfzAaksdOGuJOTs=5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAJtiUyuVaqE{fB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyKwu$(TPh2UHkJSZ0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t6-q+*6rw+))BQfroeFB@iG$fB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0tAK-c&0K$Q6&iwAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZplg9w
zDqRN@j=%;4-u|Nv+>(d{2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB=E{0-sdoPceZ20RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfWVg>
zI>bRB2Es5p0`X6RKp!
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK;V@EzdUaDSC)`YfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0Ro4>uaDdPc=bqt009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7UM29`<92^l0m%di
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5(rP~i8+?f$_a0R#vTAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C7
z2oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N
z0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+
z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly
zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF
z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk
z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs
z0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZ
zfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&U
zAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXFe3ZZ+kK6sD
z5(E<o0qF{2zbao_g4N_3NkguKL^BYM;HI=llAK?QH9%I$h;gCxd!iz3Pb%_V+`DtkqMTxz>$&@CRCj0EdS|Ma^V=?dJ*@vZ
z)${gmuKgCXUbfGfbA>&fcd@(ISA8s}zI(4${Tqv3owfSHIZyD0lVhtJtpg
z+urA%%P)8J&;85IVl}IC_PX_*r#@O=t?HKBRh{j(`2GDYe(QU$R_ECJ_4rh$9$R}?
z?c$qn@9p2*&fjy_+0V|r`0nR9*4H^#o#k!4@6=W8uI@YQVs}zq=-1od5pVitK
z=3M@4>bV;0shF)T@0xn5xA)z*cm0>&Ik#4wJkR&$_P(6H<@T0zlmbbT79!Q
a6xaJ1v$fSOrkdv-t@XZ`?3P!(;{O9<>He(%

literal 0
HcmV?d00001

diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pnd b/c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pnd
new file mode 100644
index 0000000000000000000000000000000000000000..728ed8b1228927846ebc0f4f8885c62205d66a3f
GIT binary patch
literal 48
xcmZQz{K?P2z`(-5_)`E#Gl+e;breW3N*!qZ0i>Da(yAMPG_yvgfDMpl1pxMn34Z_p

literal 0
HcmV?d00001

diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pni b/c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pni
new file mode 100644
index 0000000000000000000000000000000000000000..fdbd575abebe57b2bdac513362eeeb3071b1d0d0
GIT binary patch
literal 52
icmZQzU|?i`00SV!2E;%&*VV)+jQAQ1pDtOY{=

literal 0
HcmV?d00001

diff --git a/c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pog b/c++/src/algo/blast/proteinkmer/unit_test/data/nr_test.pog
new file mode 100644
index 0000000000000000000000000000000000000000..93df8ca529dd46672ad887063bb4d39fd0cb98a9
GIT binary patch
literal 56
scmZQzU|?i`02Uy{24y2C#-9RWUv3?hI?(z58P
z5sgR8-fvyiss^|WK<-R}GB#K%VqHRH6bx&Ei;$hP=Jpoe-SQqfFk9Zima%drB5xJX
zTj(IIdy#6(AU`!Si=xuW3dGf-_B;txpI-`m=E
z8$TXHkpILG=D&9cElB`Szz-6HV_yCw!43%&PZIizggrYlJV}5iEvG)6Z;dUKE_snq
z$iWyiNmvBBWM?RC4U$1y_!gXStXz-&B*Du3Lc(gj3gA!KE1xa=o3m%%W$&lRQC*k?
za9yB9iK*zLxr9yq$?$K1olwjR6ii6&5-woRZB=wqHZAVUcI!R{=a!*q$m3$soK`_$UB7Dg^XX00?v;>{Owr3Rm2v
bS!*f8qPZzUJ1Q(kga`jDkU}pJT8i)wl>=XY

literal 0
HcmV?d00001

diff --git a/c++/src/algo/blast/proteinkmer/unit_test/proteinkmer_unit_test.cpp b/c++/src/algo/blast/proteinkmer/unit_test/proteinkmer_unit_test.cpp
new file mode 100644
index 00000000..158b85c8
--- /dev/null
+++ b/c++/src/algo/blast/proteinkmer/unit_test/proteinkmer_unit_test.cpp
@@ -0,0 +1,1155 @@
+/*  $Id: proteinkmer_unit_test.cpp 538031 2017-06-07 14:41:55Z ivanov $
+* ===========================================================================
+*
+*                            PUBLIC DOMAIN NOTICE
+*               National Center for Biotechnology Information
+*
+*  This software/database is a "United States Government Work" under the
+*  terms of the United States Copyright Act.  It was written as part of
+*  the author's official duties as a United States Government employee and
+*  thus cannot be copyrighted.  This software/database is freely available
+*  to the public for use. The National Library of Medicine and the U.S.
+*  Government have not placed any restriction on its use or reproduction.
+*
+*  Although all reasonable efforts have been taken to ensure the accuracy
+*  and reliability of the software and data, the NLM and the U.S.
+*  Government do not and cannot warrant the performance or results that
+*  may be obtained by using this software or data. The NLM and the U.S.
+*  Government disclaim all warranties, express or implied, including
+*  warranties of performance, merchantability or fitness for any particular
+*  purpose.
+*
+*  Please cite the author in any work or product based on this material.
+*
+* ===========================================================================
+*
+* Author:  Tom Madden, NCBI
+*
+* File Description:
+*   Unit tests for proteinkmer library.
+*
+*
+* ===========================================================================
+*/
+
+#include 
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+// This header must be included before all Boost.Test headers if there are any
+#include 
+
+#include 
+
+
+USING_NCBI_SCOPE;
+USING_SCOPE(blast);
+USING_SCOPE(objects);
+
+BOOST_AUTO_TEST_SUITE(proteinkmers)
+
+
+BOOST_AUTO_TEST_CASE(KmerResults)
+{
+	const int kNumHits = 6;
+	// nr_test has GIs from array subjid in the order given.
+	const int subjid[kNumHits] = {129296, 385145541, 448824824, 510032768, 129295, 677974076};
+	const double scores[kNumHits] = {0.359375, 0.710938, 0.242188, 0.234375, 0.28125, 0.234375};
+	TBlastKmerPrelimScoreVector prelim_vector;
+	for (int index=0; index retval(index, scores[index]);
+		prelim_vector.push_back(retval);
+	}
+	CRef qid(new CSeq_id("gi|129296"));
+	CRef seqdb(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	// values in stats are: hit_count, jd_count, jd_oid_count, oids_considered, total_matches
+	BlastKmerStats stats( 3256, 506, 253, 77623, 27); 
+
+	CBlastKmerResults results(qid, prelim_vector, stats, seqdb, TQueryMessages());
+	
+        CRef scope(CSimpleOM::NewScope());
+	TSeqLocVector tsl;
+	results.GetTSL(tsl, scope);
+	int index=0;
+	for (TSeqLocVector::iterator iter=tsl.begin(); iter != tsl.end(); ++iter)
+	{
+		BOOST_REQUIRE_EQUAL((*iter).seqloc->GetId()->GetGi(), subjid[index]);
+		index++;
+	}
+
+	const TBlastKmerScoreVector kmerscores = results.GetScores();
+	index=0;
+	for (TBlastKmerScoreVector::const_iterator iter=kmerscores.begin(); iter != kmerscores.end(); ++iter)
+	{
+		CRef sid = (*iter).first;
+		BOOST_REQUIRE_EQUAL(sid->GetGi(), subjid[index]);
+		BOOST_REQUIRE_EQUAL((*iter).second, scores[index]);
+		index++;
+	}
+
+	const BlastKmerStats& newstats = results.GetStats();
+	BOOST_REQUIRE_EQUAL(newstats.hit_count, stats.hit_count);
+	BOOST_REQUIRE_EQUAL(newstats.jd_count, stats.jd_count);
+}
+
+BOOST_AUTO_TEST_CASE(KmerResultsSet)
+{
+	const int kNumQueries = 2;
+	const int kNumHits1 = 6;
+	const int kNumHits2 = 2;
+	// nr_test has GIs from array subjid in the order given by subjid1.
+	const int subjid1[kNumHits1] = {129296, 385145541, 448824824, 510032768, 129295, 677974076};
+	const int subjid2[kNumHits2] = {129295, 677974076};
+	const double scores1[kNumHits1] = {0.359375, 0.710938, 0.242188, 0.234375, 0.28125, 0.234375};
+	const double scores2[kNumHits1] = {0.359375, 0.710938};
+	TBlastKmerPrelimScoreVector prelim_vector1;
+	TBlastKmerPrelimScoreVector prelim_vector2;
+	for (int index=0; index retval(index, scores1[index]);
+		prelim_vector1.push_back(retval);
+	}
+        // Ordering of OID to GIs are off here.
+	for (int index=0; index retval(index+4, scores2[index]);
+		prelim_vector2.push_back(retval);
+	}
+	CBlastKmerResultsSet::TBlastKmerPrelimScoreVectorSet vec_set;
+	vec_set.push_back(prelim_vector1);
+	vec_set.push_back(prelim_vector2);
+	CRef qid1(new CSeq_id("gi|129296"));
+	CRef qid2(new CSeq_id("gi|129295"));
+	CBlastKmerResultsSet::TQueryIdVector id_vec;
+	id_vec.push_back(qid1);
+	id_vec.push_back(qid2);
+
+	CRef seqdb(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+
+	// values in stats are: hit_count, jd_count, jd_oid_count, oids_considered, total_matches
+	BlastKmerStats stats1( 3256, 506, 253, 77623, 27); 
+	BlastKmerStats stats2( 3255, 505, 255, 77625, 25); 
+	CBlastKmerResultsSet::TBlastKmerStatsVector stats_vec;
+	stats_vec.push_back(stats1);
+	stats_vec.push_back(stats2);
+	TSearchMessages errs;
+	errs.resize(kNumQueries);
+
+	CBlastKmerResultsSet result_set(id_vec, vec_set, stats_vec, seqdb, errs);
+
+	BOOST_REQUIRE_EQUAL(result_set.GetNumQueries(), kNumQueries);
+	
+	CBlastKmerResults results = result_set[0];
+
+	const TBlastKmerScoreVector kmerscores = results.GetScores();
+	int index=0;
+	for (TBlastKmerScoreVector::const_iterator iter=kmerscores.begin(); iter != kmerscores.end(); ++iter)
+	{
+		CRef sid = (*iter).first;
+		BOOST_REQUIRE_EQUAL(sid->GetGi(), subjid1[index]);
+		BOOST_REQUIRE_EQUAL((*iter).second, scores1[index]);
+		index++;
+	}
+
+	const BlastKmerStats& newstats = results.GetStats();
+	BOOST_REQUIRE_EQUAL(newstats.hit_count, stats1.hit_count);
+	BOOST_REQUIRE_EQUAL(newstats.jd_count, stats1.jd_count);
+
+	// Results from second query.
+	results = result_set[1];
+	const TBlastKmerScoreVector kmerscores2 = results.GetScores();
+	index=0;
+	for (TBlastKmerScoreVector::const_iterator iter=kmerscores2.begin(); iter != kmerscores2.end(); ++iter)
+	{
+		CRef sid = (*iter).first;
+		BOOST_REQUIRE_EQUAL(sid->GetGi(), subjid2[index]);
+		BOOST_REQUIRE_EQUAL((*iter).second, scores2[index]);
+		index++;
+	}
+
+	// ID in this search set
+	CRef resultsNotNULL = result_set[*qid1];
+	BOOST_REQUIRE(resultsNotNULL.IsNull() == false);
+
+	// ID not in this search set.
+	CRef qid_bogus(new CSeq_id("gi|555"));
+	CRef resultsNull = result_set[*qid_bogus];
+	BOOST_REQUIRE(resultsNull.IsNull() == true);
+}
+
+BOOST_AUTO_TEST_CASE(KmerResultsSetPushBack)
+{
+	const int kNumQueries = 2;
+	const int kNumHits1 = 6;
+	const int kNumHits2 = 2;
+	// nr_test has GIs from array subjid in the order given by subjid1.
+	const int subjid1[kNumHits1] = {129296, 385145541, 448824824, 510032768, 129295, 677974076};
+	const int subjid2[kNumHits2] = {129295, 677974076};
+	const double scores1[kNumHits1] = {0.359375, 0.710938, 0.242188, 0.234375, 0.28125, 0.234375};
+	const double scores2[kNumHits1] = {0.359375, 0.710938};
+	TBlastKmerPrelimScoreVector prelim_vector1;
+	TBlastKmerPrelimScoreVector prelim_vector2;
+	for (int index=0; index retval(index, scores1[index]);
+		prelim_vector1.push_back(retval);
+	}
+        // Ordering of OID to GIs are off here.
+	for (int index=0; index retval(index+4, scores2[index]);
+		prelim_vector2.push_back(retval);
+	}
+
+	CRef seqdb(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	TQueryMessages errs = TQueryMessages();
+
+	CRef qid1(new CSeq_id("gi|129296"));
+	BlastKmerStats stats1( 3256, 506, 253, 77623, 27); 
+	CRef results1;
+	results1.Reset(new CBlastKmerResults(qid1, prelim_vector1, stats1, seqdb, TQueryMessages()));
+
+	CRef qid2(new CSeq_id("gi|129295"));
+	BlastKmerStats stats2( 3255, 505, 255, 77625, 25); 
+	CRef results2;
+	results2.Reset(new CBlastKmerResults(qid2, prelim_vector2, stats2, seqdb, errs));
+
+	CBlastKmerResultsSet result_set;
+
+	result_set.push_back(results1);
+	result_set.push_back(results2);
+
+	BOOST_REQUIRE_EQUAL(result_set.GetNumQueries(), kNumQueries);
+	
+	CBlastKmerResults results = result_set[0];
+
+	const TBlastKmerScoreVector kmerscores = results.GetScores();
+	int index=0;
+	for (TBlastKmerScoreVector::const_iterator iter=kmerscores.begin(); iter != kmerscores.end(); ++iter)
+	{
+		CRef sid = (*iter).first;
+		BOOST_REQUIRE_EQUAL(sid->GetGi(), subjid1[index]);
+		BOOST_REQUIRE_EQUAL((*iter).second, scores1[index]);
+		index++;
+	}
+
+	const BlastKmerStats& newstats = results.GetStats();
+	BOOST_REQUIRE_EQUAL(newstats.hit_count, stats1.hit_count);
+	BOOST_REQUIRE_EQUAL(newstats.jd_count, stats1.jd_count);
+
+	// Results from second query.
+	results = result_set[1];
+	const TBlastKmerScoreVector kmerscores2 = results.GetScores();
+	index=0;
+	for (TBlastKmerScoreVector::const_iterator iter=kmerscores2.begin(); iter != kmerscores2.end(); ++iter)
+	{
+		CRef sid = (*iter).first;
+		BOOST_REQUIRE_EQUAL(sid->GetGi(), subjid2[index]);
+		BOOST_REQUIRE_EQUAL((*iter).second, scores2[index]);
+		index++;
+	}
+}
+
+BOOST_AUTO_TEST_CASE(SearchWithBadQuery)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/bad.asn");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*(bioseq.GetId().front()));
+
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+	CRef db(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	CRef options(new CBlastKmerOptions());
+
+	CBlastKmer kmersearch(query_vector, options, db);
+
+	CRef results = kmersearch.Run();
+	BOOST_REQUIRE((*results)[0].HasErrors() == false);
+	BOOST_REQUIRE((*results)[0].HasWarnings() == true);
+}
+
+BOOST_AUTO_TEST_CASE(SearchWithAllXQuery)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/allX.asn");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*(bioseq.GetId().front()));
+
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+	CRef db(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	CRef options(new CBlastKmerOptions());
+
+	CBlastKmer kmersearch(query_vector, options, db);
+
+	CRef results = kmersearch.Run();
+	BOOST_REQUIRE((*results)[0].HasErrors() == false);
+	BOOST_REQUIRE((*results)[0].HasWarnings() == true);
+	
+	
+}
+
+BOOST_AUTO_TEST_CASE(SearchWithBadDatabase)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/129295.stdaa");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*(bioseq.GetId().front()));
+
+	SSeqLoc ssl(*loc, *scope);
+	CRef options(new CBlastKmerOptions());
+
+	string dbname("JUNK");
+	BOOST_REQUIRE_THROW(CBlastKmer kmersearch(ssl, options, dbname), CSeqDBException);	
+}
+
+
+BOOST_AUTO_TEST_CASE(SearchWithSSeqLocQuery)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/129295.stdaa");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*(bioseq.GetId().front()));
+
+	SSeqLoc ssl(*loc, *scope);
+	CRef options(new CBlastKmerOptions());
+
+	string dbname("data/nr_test");
+	CBlastKmer kmersearch(ssl, options, dbname);	
+	CRef results = kmersearch.Run();
+
+	const TBlastKmerScoreVector& scores = (*results)[0].GetScores();
+	BOOST_REQUIRE_EQUAL(scores.size(), 5);
+}
+
+BOOST_AUTO_TEST_CASE(NcbieaaSearch)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/129295.ncbieaa");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*((bioseq).GetId().front()));
+
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+	CRef db(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	CRef options(new CBlastKmerOptions());
+
+	CBlastKmer kmersearch(query_vector, options, db);	
+	CRef results = kmersearch.Run();
+
+	const TBlastKmerScoreVector& scores = (*results)[0].GetScores();
+	BOOST_REQUIRE_EQUAL(scores.size(), 5);
+	CConstRef seqid = (*results)[0].GetSeqId();
+	string label;
+	seqid->GetLabel(&label, CSeq_id::eContent);
+ 	BOOST_REQUIRE(label == "1");
+}
+
+BOOST_AUTO_TEST_CASE(MultipleQuerySearch)
+{
+	CRef bioseq(new CBioseq);
+	CNcbiIfstream i_file("data/129295.ncbieaa");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> *bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(*bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*((*bioseq).GetId().front()));
+
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+
+	CNcbiIfstream i_file2("data/129296.ncbieaa");
+	auto_ptr is2(CObjectIStream::Open(eSerial_AsnText, i_file2));
+	
+	CRef bioseq2(new CBioseq);
+	*is2 >> *bioseq2;
+	CRef scope2(CSimpleOM::NewScope(false));
+	scope2->AddBioseq(*bioseq2);
+	CRef loc2(new CSeq_loc);
+    	loc2->SetWhole().Assign(*((*bioseq2).GetId().front()));
+
+	auto_ptr ssl2(new SSeqLoc(*loc2, *scope2));
+	query_vector.push_back(*ssl2);
+
+	CRef db(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	CRef options(new CBlastKmerOptions());
+
+	CBlastKmer kmersearch(query_vector, options, db);	
+	CRef resultSet = kmersearch.RunSearches();
+
+	// Retrieval of first result with array like access
+	CBlastKmerResults results = (*resultSet)[0];
+	const TBlastKmerScoreVector& scores = results.GetScores();
+	BOOST_REQUIRE_EQUAL(scores.size(), 5);
+
+	CConstRef seqid = results.GetSeqId();
+
+	// Retrieval of first result via CSeq_id
+	CRef results1 = (*resultSet)[*seqid];
+	const TBlastKmerScoreVector& scores1 = results1->GetScores();
+	BOOST_REQUIRE_EQUAL(scores1.size(), 5);
+
+	// Retrieval of second result with array like access
+	CBlastKmerResults results2 = (*resultSet)[1];
+	const TBlastKmerScoreVector& scores2 = results2.GetScores();
+	BOOST_REQUIRE_EQUAL(scores2.size(), 5);
+}
+
+BOOST_AUTO_TEST_CASE(IupacaaSearch)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/129295.iupacaa");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*(bioseq.GetId().front()));
+
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+	CRef db(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	CRef options(new CBlastKmerOptions());
+
+	CBlastKmer kmersearch(query_vector, options, db);	
+	CRef results = kmersearch.Run();
+
+	const TBlastKmerScoreVector& scores = (*results)[0].GetScores();
+	BOOST_REQUIRE_EQUAL(scores.size(), 5);
+}
+
+BOOST_AUTO_TEST_CASE(GIListLimitSearch)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/129295.iupacaa");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*(bioseq.GetId().front()));
+
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+	CRef db(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	CRef options(new CBlastKmerOptions());
+	options->SetThresh(0.15);
+
+	CBlastKmer kmersearch(query_vector, options, db);	
+	CRef seqdb_gilist(new CSeqDBGiList());
+	seqdb_gilist->AddGi(GI_CONST(3091));
+	seqdb_gilist->AddGi(GI_CONST(129296));
+	seqdb_gilist->AddGi(GI_CONST(448824824));
+	kmersearch.SetGiListLimit(seqdb_gilist);
+	CRef results = kmersearch.Run();
+
+	const TBlastKmerScoreVector& scores = (*results)[0].GetScores();
+	BOOST_REQUIRE_EQUAL(scores.size(), 2);
+}
+
+BOOST_AUTO_TEST_CASE(NegativeGIListLimitSearch)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/129295.iupacaa");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*(bioseq.GetId().front()));
+
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+	CRef db(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	CRef options(new CBlastKmerOptions());
+	options->SetThresh(0.15);
+
+	CBlastKmer kmersearch(query_vector, options, db);	
+	CRef seqdb_gilist(new CSeqDBNegativeList());
+	seqdb_gilist->AddGi(GI_CONST(3091));
+	seqdb_gilist->AddGi(GI_CONST(129296));
+	seqdb_gilist->AddGi(GI_CONST(448824824));
+	kmersearch.SetGiListLimit(seqdb_gilist);
+	CRef resultSet = kmersearch.RunSearches();
+	CBlastKmerResults results = (*resultSet)[0];
+
+	const TBlastKmerScoreVector& scores = results.GetScores();
+	BOOST_REQUIRE_EQUAL(scores.size(), 3);
+}
+
+BOOST_AUTO_TEST_CASE(GIListLimitSearch_NoMatches)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/129295.iupacaa");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*(bioseq.GetId().front()));
+
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+	CRef db(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	CRef options(new CBlastKmerOptions());
+
+	CBlastKmer kmersearch(query_vector, options, db);	
+	CRef seqdb_gilist(new CSeqDBGiList());
+	seqdb_gilist->AddGi(GI_CONST(3091));
+	kmersearch.SetGiListLimit(seqdb_gilist);
+	CRef results = kmersearch.Run();
+
+	const TBlastKmerScoreVector& scores = (*results)[0].GetScores();
+	BOOST_REQUIRE_EQUAL(scores.size(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(NoMatches)
+{
+	TGi query_gi(GI_CONST(1945387));
+	CRef id(new CSeq_id(CSeq_id::e_Gi, query_gi));
+	CRef scope(CSimpleOM::NewScope(true));
+	
+	CRef loc(new CSeq_loc());
+    	loc->SetWhole(*id);
+
+	auto_ptr ssl(new SSeqLoc(loc, scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+
+	CRef db(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	CRef options(new CBlastKmerOptions());
+
+	CBlastKmer kmersearch(query_vector, options, db);	
+	CRef results = kmersearch.Run();
+
+	const TBlastKmerScoreVector& scores = (*results)[0].GetScores();
+	BOOST_REQUIRE_EQUAL(scores.size(), 0);
+}
+
+void s_GetRandomNumbers(uint32_t* a, uint32_t* b, int numHashes)
+{
+        CRandom random(1);  // Always have the same random numbers.
+        for(int i=0;i > seq_hash;
+	
+	minhash_query(queryseq_stdaa, seq_hash, kNumHashes, a, b, kDoSeg, kKmerNum, kAlphabet, kChunkSize);
+
+	BOOST_REQUIRE_EQUAL(seq_hash.size(), 2);
+	BOOST_REQUIRE_EQUAL(seq_hash[0].size(), kNumHashes);
+	BOOST_REQUIRE_EQUAL(seq_hash[0][0], 529895);
+	BOOST_REQUIRE_EQUAL(seq_hash[0][1], 798115);
+	BOOST_REQUIRE_EQUAL(seq_hash[0][63], 90979);
+	BOOST_REQUIRE_EQUAL(seq_hash[0][83], 336201);
+	
+	// Expected (correct) values.
+	const int lsh_hash_length = 13;
+	const int lsh_hash_vals[lsh_hash_length] = { 973119,1097197,1157729,1681152,1913970,1933659,2018075,2123893,2355301,2800673,2940688,2941967,3535701};
+
+	const int kRowsPerBand=2;
+	const int kNumBands = kNumHashes/kRowsPerBand;
+	vector< vector  > lsh_hash_vec;
+	get_LSH_hashes(seq_hash, lsh_hash_vec, kNumBands, kRowsPerBand);
+	int index=0;
+	int numChunks = lsh_hash_vec.size();
+	for (int i=0; i::iterator iter=lsh_hash_vec[i].begin(); iter != lsh_hash_vec[i].end(); ++iter)
+		{
+  			BOOST_REQUIRE_EQUAL(*iter, lsh_hash_vals[index]);
+			index++;
+			if (index == lsh_hash_length)
+				break;
+		}
+	}
+}
+
+BOOST_AUTO_TEST_CASE(CheckQueryHashesVersion3)
+{
+	string queryseq_eaa = 
+	"MDSISVTNAKFCFDVFNEMKVHHVNENILYCPLSILTALAMVYLGARGNTESQMKKVLHFDSITGAGSTTDSQCGSSEYV"
+	"HNLFKELLSEITRPNATYSLEIADKLYVDKTFSVLPEYLSCARKFYTGGVEEVNFKTAAEEARQLINSWVEKETNGQIKD"
+	"LLVSSSIDFGTTMVFINTIYFKGIWKIAFNTEDTREMPFSMTKEESKPVQMMCMNNSFNVATLPAEKMKILELPYASGDL";
+
+	string queryseq_stdaa;
+	CSeqConvert::Convert(queryseq_eaa, CSeqUtil::e_Ncbieaa, 0, queryseq_eaa.length(), 
+		queryseq_stdaa, CSeqUtil::e_Ncbistdaa);
+
+	const int kNumHashes=32;
+	const int kKmerNum=5;
+	const int kAlphabet=0; // 15 letters
+	vector badMers;
+	const int kChunkSize=150;
+
+	vector < vector  > seq_hash;
+	
+	minhash_query2(queryseq_stdaa, seq_hash, kKmerNum, kNumHashes, kAlphabet, badMers, kChunkSize);
+
+	BOOST_REQUIRE_EQUAL(seq_hash.size(), 2);
+	BOOST_REQUIRE_EQUAL(seq_hash[0].size(), kNumHashes);
+	BOOST_REQUIRE_EQUAL(seq_hash[0][0], 2683052);
+	BOOST_REQUIRE_EQUAL(seq_hash[0][1], 26519505);
+	BOOST_REQUIRE_EQUAL(seq_hash[0][2], 45619224);
+	BOOST_REQUIRE_EQUAL(seq_hash[0][15], 396863844);
+        // Values are ordered from smallest to largest
+	BOOST_REQUIRE(seq_hash[1][0] < seq_hash[0][1]);
+	BOOST_REQUIRE(seq_hash[1][1] < seq_hash[0][2]);
+	BOOST_REQUIRE(seq_hash[1][3] < seq_hash[0][kNumHashes-1]);
+	
+	// Expected (correct) values.
+	const int lsh_hash_length = 13;
+	const int lsh_hash_vals[lsh_hash_length] = { 700168,1293774,1377419,1712432,1819660,2314660,2484152,2944352,2951476,3273866,3625878,3709806,3714709};
+
+	const int kRowsPerBand=2;
+	vector< vector  > lsh_hash_vec;
+	get_LSH_hashes5(seq_hash, lsh_hash_vec, kNumHashes, kRowsPerBand);
+	int index=0;
+	int numChunks = lsh_hash_vec.size();
+	for (int i=0; i::iterator iter=lsh_hash_vec[i].begin(); iter != lsh_hash_vec[i].end(); ++iter)
+		{
+ 			BOOST_REQUIRE_EQUAL(*iter, lsh_hash_vals[index]);
+			index++;
+			if (index == lsh_hash_length)
+				break;
+		}
+	}
+}
+
+int s_GetNumLSHHits(uint64_t* lsh, int lshSize)
+{
+	int count=0;
+	for (int index=0; index seqdb(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+
+        const int kHashFct=32;
+	const int kKmerSize=5;
+
+        CBlastKmerBuildIndex build_index(seqdb, kKmerSize, kHashFct);
+
+	string index_name("nr_test");
+	CFileDeleteAtExit::Add(index_name + ".pki");
+	CFileDeleteAtExit::Add(index_name + ".pkd");
+        build_index.Build();
+
+	CMinHashFile mhfile(index_name);
+
+	BOOST_REQUIRE_EQUAL(kHashFct, mhfile.GetNumHashes());
+	BOOST_REQUIRE_EQUAL(2, mhfile.GetDataWidth());
+	BOOST_REQUIRE_EQUAL(kKmerSize, mhfile.GetKmerSize());
+
+	uint64_t* lsh_array = mhfile.GetLSHArray();
+	int lsh_size = mhfile.GetLSHSize();
+	BOOST_REQUIRE_EQUAL(0x1000001, lsh_size);
+
+	int lsh_counts = s_GetNumLSHHits(lsh_array, lsh_size-1);
+	BOOST_REQUIRE_EQUAL(166, lsh_counts);
+}
+
+BOOST_AUTO_TEST_CASE(BuildIndexRepeats)
+{
+        CRef seqdb(new CSeqDB("data/XP_001468867", CSeqDB::eProtein));
+
+        const int kHashFct=32;
+	const int kKmerSize=5;
+
+        CBlastKmerBuildIndex build_index(seqdb, kKmerSize, kHashFct);
+
+	string index_name("XP_001468867");
+	CFileDeleteAtExit::Add(index_name + ".pki");
+	CFileDeleteAtExit::Add(index_name + ".pkd");
+        build_index.Build();
+
+	CMinHashFile mhfile(index_name);
+	BOOST_REQUIRE_EQUAL(kHashFct, mhfile.GetNumHashes());
+	BOOST_REQUIRE_EQUAL(2, mhfile.GetDataWidth());
+	BOOST_REQUIRE_EQUAL(kKmerSize, mhfile.GetKmerSize());
+
+	uint64_t* lsh_array = mhfile.GetLSHArray();
+	int lsh_size = mhfile.GetLSHSize();
+	BOOST_REQUIRE_EQUAL(0x1000001, lsh_size);
+
+	int lsh_counts = s_GetNumLSHHits(lsh_array, lsh_size-1);
+ 	BOOST_REQUIRE_EQUAL(168, lsh_counts);
+
+}
+
+BOOST_AUTO_TEST_CASE(BuildIndexNotValidSequence)
+{
+        CRef seqdb(new CSeqDB("data/manyXs", CSeqDB::eProtein));
+
+        const int kHashFct=32;
+	const int kKmerSize=5;
+
+        CBlastKmerBuildIndex build_index(seqdb, kKmerSize, kHashFct);
+
+	string index_name("manyXs");
+	CFileDeleteAtExit::Add(index_name + ".pki");
+	CFileDeleteAtExit::Add(index_name + ".pkd");
+        build_index.Build();
+	// data file is empty/missing.  Should there be an exception for that?
+
+	BOOST_REQUIRE_THROW(CMinHashFile mhfile(index_name), CMinHashException);	
+}
+
+BOOST_AUTO_TEST_CASE(BuildIndexWidth4Kmer4)
+{
+
+
+        CRef seqdb(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+
+        const int kHashFct=32;
+	const int kKmerSize=4;
+	const int kWidth=4;
+
+        CBlastKmerBuildIndex build_index(seqdb, kKmerSize, kHashFct, 0, kWidth);
+
+	string index_name("nr_test");
+	CFileDeleteAtExit::Add(index_name + ".pki");
+	CFileDeleteAtExit::Add(index_name + ".pkd");
+        build_index.Build();
+
+	CMinHashFile mhfile(index_name);
+	BOOST_REQUIRE_EQUAL(kHashFct, mhfile.GetNumHashes());
+	BOOST_REQUIRE_EQUAL(kWidth, mhfile.GetDataWidth());
+	BOOST_REQUIRE_EQUAL(kKmerSize, mhfile.GetKmerSize());
+
+	uint64_t* lsh_array = mhfile.GetLSHArray();
+	int lsh_size = mhfile.GetLSHSize();
+	BOOST_REQUIRE_EQUAL(0x1000001, lsh_size);
+
+	int lsh_counts = s_GetNumLSHHits(lsh_array, lsh_size-1);
+	BOOST_REQUIRE_EQUAL(159, lsh_counts);
+}
+
+BOOST_AUTO_TEST_CASE(BuildIndexFewerBands)
+{
+
+        CRef seqdb(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+
+        const int kHashFct=64;
+	const int kKmerSize=4;
+	const int kWidth=2;
+
+        CBlastKmerBuildIndex build_index(seqdb, kKmerSize, kHashFct, 0, kWidth);
+
+	string index_name("nr_test");
+	CFileDeleteAtExit::Add(index_name + ".pki");
+	CFileDeleteAtExit::Add(index_name + ".pkd");
+        build_index.Build();
+
+	CMinHashFile mhfile(index_name);
+	BOOST_REQUIRE_EQUAL(kHashFct, mhfile.GetNumHashes());
+	BOOST_REQUIRE_EQUAL(kWidth, mhfile.GetDataWidth());
+	BOOST_REQUIRE_EQUAL(kKmerSize, mhfile.GetKmerSize());
+
+	uint64_t* lsh_array = mhfile.GetLSHArray();
+	int lsh_size = mhfile.GetLSHSize();
+	BOOST_REQUIRE_EQUAL(0x1000001, lsh_size);
+
+	int lsh_counts = s_GetNumLSHHits(lsh_array, lsh_size-1);
+	BOOST_REQUIRE_EQUAL(312, lsh_counts);
+}
+
+BOOST_AUTO_TEST_CASE(BuildIndex10letterAlphabet)
+{
+
+        CRef seqdb(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+
+        const int kHashFct=32;
+	const int kKmerSize=5;
+	const int kWidth=2;
+	const int kAlphabet=1;
+
+        CBlastKmerBuildIndex build_index(seqdb, kKmerSize, kHashFct, 0, kWidth, kAlphabet);
+
+	string index_name("nr_test");
+	CFileDeleteAtExit::Add(index_name + ".pki");
+	CFileDeleteAtExit::Add(index_name + ".pkd");
+        build_index.Build();
+
+	CMinHashFile mhfile(index_name);
+	BOOST_REQUIRE_EQUAL(kHashFct, mhfile.GetNumHashes());
+	BOOST_REQUIRE_EQUAL(kWidth, mhfile.GetDataWidth());
+	BOOST_REQUIRE_EQUAL(kKmerSize, mhfile.GetKmerSize());
+	BOOST_REQUIRE_EQUAL(kAlphabet, mhfile.GetAlphabet());
+
+	uint64_t* lsh_array = mhfile.GetLSHArray();
+	int lsh_size = mhfile.GetLSHSize();
+	BOOST_REQUIRE_EQUAL(0x1000001, lsh_size);
+
+	int lsh_counts = s_GetNumLSHHits(lsh_array, lsh_size-1);
+	BOOST_REQUIRE_EQUAL(155, lsh_counts);
+}
+
+BOOST_AUTO_TEST_CASE(BuildIndex10letterVersion3)
+{
+
+        CRef seqdb(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+
+        const int kHashFct=32;
+	const int kKmerSize=5;
+	const int kSamples=30;
+	const int kWidth=2;
+	const int kAlphabet=1;
+	const int kVersion=3;
+	const int kLSHStart=312;
+
+        CBlastKmerBuildIndex build_index(seqdb, kKmerSize, kHashFct, kSamples, kWidth, kAlphabet, kVersion);
+
+	string index_name("nr_test");
+	CFileDeleteAtExit::Add(index_name + ".pki");
+	CFileDeleteAtExit::Add(index_name + ".pkd");
+        build_index.Build();
+
+	CMinHashFile mhfile(index_name);
+	BOOST_REQUIRE_EQUAL(kHashFct, mhfile.GetNumHashes());
+	BOOST_REQUIRE_EQUAL(kWidth, mhfile.GetDataWidth());
+	BOOST_REQUIRE_EQUAL(kKmerSize, mhfile.GetKmerSize());
+	BOOST_REQUIRE_EQUAL(kAlphabet, mhfile.GetAlphabet());
+	BOOST_REQUIRE_EQUAL(kVersion, mhfile.GetVersion());
+	BOOST_REQUIRE_EQUAL(kLSHStart, mhfile.GetLSHStart());
+
+	uint64_t* lsh_array = mhfile.GetLSHArray();
+	int lsh_size = mhfile.GetLSHSize();
+	BOOST_REQUIRE_EQUAL(0x1000001, lsh_size);
+
+	int lsh_counts = s_GetNumLSHHits(lsh_array, lsh_size-1);
+	BOOST_REQUIRE_EQUAL(526, lsh_counts);
+
+	int chunkSize = mhfile.GetChunkSize();
+	BOOST_REQUIRE_EQUAL(150, chunkSize);
+}
+
+BOOST_AUTO_TEST_CASE(CheckVerify_nr_test)
+{
+	// Build this index, then run BlastKmerVerifyIndex on it.
+	// The index should pass
+        CRef seqdb(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+
+	string error_msg="";
+	int status  = BlastKmerVerifyIndex(seqdb, error_msg);
+
+	BOOST_REQUIRE_EQUAL(0, status);
+	BOOST_REQUIRE_EQUAL(0, error_msg.size());
+}
+
+BOOST_AUTO_TEST_CASE(CheckEmptyIndexName)
+{
+
+	string index_name="";
+	BOOST_REQUIRE_THROW(CMinHashFile mhfile(index_name), CMinHashException);	
+}
+
+
+BOOST_AUTO_TEST_CASE(CheckNoIndex)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/129295.ncbieaa");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*(bioseq.GetId().front()));
+
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+        CRef seqdb(new CSeqDB("data/XP_001468867", CSeqDB::eProtein));
+	CRef options(new CBlastKmerOptions());
+
+	CBlastKmer kmersearch(query_vector, options, seqdb);
+	BOOST_REQUIRE_THROW(kmersearch.Run(), CFileException);
+}
+
+BOOST_AUTO_TEST_CASE(CheckOptionValidation)
+{
+	CRef  opts(new CBlastKmerOptions());
+
+	double myThresh=0.1;
+	opts->SetThresh(myThresh);
+	BOOST_REQUIRE_EQUAL(opts->GetThresh(), myThresh);
+
+	int hits=373;
+	opts->SetMinHits(hits);
+	BOOST_REQUIRE_EQUAL(opts->GetMinHits(), hits);
+
+	int targetSeqs=234;
+	opts->SetNumTargetSeqs(targetSeqs);
+	BOOST_REQUIRE_EQUAL(opts->GetNumTargetSeqs(), targetSeqs);
+
+	BOOST_REQUIRE_EQUAL(opts->Validate(), true);
+
+	opts->SetMinHits(0);
+	BOOST_REQUIRE_EQUAL(opts->Validate(), true);
+
+	opts->SetThresh(-0.707);
+	BOOST_REQUIRE_EQUAL(opts->Validate(), false);
+
+	opts->SetMinHits(-1);
+	BOOST_REQUIRE_EQUAL(opts->Validate(), false);
+}
+
+BOOST_AUTO_TEST_CASE(BadOptionsThrow)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/129295.stdaa");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*(bioseq.GetId().front()));
+
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+	CRef db(new CSeqDB("data/nr_test", CSeqDB::eProtein));
+	CRef options(new CBlastKmerOptions());
+	options->SetThresh(1.3); // Value should be one or less.
+	BOOST_REQUIRE_THROW(CBlastKmer kmersearch(query_vector, options, db), CException);	
+}
+
+BOOST_AUTO_TEST_CASE(BlastKmerSearch)
+{
+	CBioseq bioseq;
+	CNcbiIfstream i_file("data/129295.stdaa");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	
+	*is >> bioseq;
+	CRef scope(CSimpleOM::NewScope(false));
+	scope->AddBioseq(bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*(bioseq.GetId().front()));
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	TSeqLocVector query_vector;
+	query_vector.push_back(*ssl);
+	CRef qf(new CObjMgr_QueryFactory(query_vector));
+
+	CRef blOpts(new CBlastpKmerOptionsHandle());
+
+	CSearchDatabase search_db("data/nr_test", CSearchDatabase::eBlastDbIsProtein);
+	CRef ldb(new CLocalDbAdapter(search_db));
+	CRef search(new CBlastKmerSearch(qf, blOpts, ldb));
+	CRef results = search->Run();
+	BOOST_REQUIRE(results->GetNumQueries() == 1);
+	BOOST_REQUIRE(results->GetNumResults() == 1);
+}
+
+
+BOOST_AUTO_TEST_CASE(BlastKmerMultipleQuerySearch)
+{
+	CRef scope(CSimpleOM::NewScope(false));
+	TSeqLocVector query_vector;
+
+	CNcbiIfstream i_file("data/allX.asn");
+	auto_ptr is(CObjectIStream::Open(eSerial_AsnText, i_file));
+	CRef bioseq(new CBioseq);
+	*is >> *bioseq;
+	scope->AddBioseq(*bioseq);
+	CRef loc(new CSeq_loc);
+    	loc->SetWhole().Assign(*((*bioseq).GetId().front()));
+	auto_ptr ssl(new SSeqLoc(*loc, *scope));
+	query_vector.push_back(*ssl);
+
+	CNcbiIfstream i_file2("data/129296.ncbieaa");
+	auto_ptr is2(CObjectIStream::Open(eSerial_AsnText, i_file2));
+	CRef bioseq2(new CBioseq);
+	*is2 >> *bioseq2;
+	scope->AddBioseq(*bioseq2);
+	CRef loc2(new CSeq_loc);
+    	loc2->SetWhole().Assign(*((*bioseq2).GetId().front()));
+	auto_ptr ssl2(new SSeqLoc(*loc2, *scope));
+	query_vector.push_back(*ssl2);
+
+	CNcbiIfstream i_file3("data/129295.ncbieaa");
+	auto_ptr is3(CObjectIStream::Open(eSerial_AsnText, i_file3));
+	CRef bioseq3(new CBioseq);
+	*is3 >> *bioseq3;
+	scope->AddBioseq(*bioseq3);
+	CRef loc3(new CSeq_loc);
+    	loc3->SetWhole().Assign(*((*bioseq3).GetId().front()));
+	auto_ptr ssl3(new SSeqLoc(*loc3, *scope));
+	query_vector.push_back(*ssl3);
+	CRef qf(new CObjMgr_QueryFactory(query_vector));
+
+	CSearchDatabase search_db("data/nr_test", CSearchDatabase::eBlastDbIsProtein);
+	CRef ldb(new CLocalDbAdapter(search_db));
+	CRef blOpts(new CBlastpKmerOptionsHandle());
+	CRef search(new CBlastKmerSearch(qf, blOpts, ldb));
+	CRef results = search->Run();
+	BOOST_REQUIRE(results->GetNumQueries() == 3);
+	BOOST_REQUIRE(results->GetNumResults() == 3);
+	BOOST_REQUIRE((*results)[0].HasAlignments() == false);
+	BOOST_REQUIRE((*results)[1].HasAlignments() == true);
+	BOOST_REQUIRE((*results)[2].HasAlignments() == true);
+}
+
+BOOST_AUTO_TEST_CASE(BlastKmerNoQueryCtor)
+{
+	CRef scope(CSimpleOM::NewScope(false));
+
+	TSeqLocVector query_vector1;
+	CNcbiIfstream i_file1("data/129296.ncbieaa");
+	auto_ptr is1(CObjectIStream::Open(eSerial_AsnText, i_file1));
+	CRef bioseq1(new CBioseq);
+	*is1 >> *bioseq1;
+	scope->AddBioseq(*bioseq1);
+	CRef loc1(new CSeq_loc);
+    	loc1->SetWhole().Assign(*((*bioseq1).GetId().front()));
+	auto_ptr ssl1(new SSeqLoc(*loc1, *scope));
+	query_vector1.push_back(*ssl1);
+	CRef qf1(new CObjMgr_QueryFactory(query_vector1));
+
+	TSeqLocVector query_vector2;
+	CNcbiIfstream i_file2("data/129295.ncbieaa");
+	auto_ptr is2(CObjectIStream::Open(eSerial_AsnText, i_file2));
+	CRef bioseq2(new CBioseq);
+	*is2 >> *bioseq2;
+	scope->AddBioseq(*bioseq2);
+	CRef loc2(new CSeq_loc);
+    	loc2->SetWhole().Assign(*((*bioseq2).GetId().front()));
+	auto_ptr ssl2(new SSeqLoc(*loc2, *scope));
+	query_vector2.push_back(*ssl2);
+	CRef qf2(new CObjMgr_QueryFactory(query_vector2));
+
+	CSearchDatabase search_db("data/nr_test", CSearchDatabase::eBlastDbIsProtein);
+	CRef ldb(new CLocalDbAdapter(search_db));
+	CRef blOpts(new CBlastpKmerOptionsHandle());
+	CRef search(new CBlastKmerSearch(blOpts, ldb));
+
+        search->SetQuery(qf1);
+	CRef results = search->Run();
+	BOOST_REQUIRE(results->GetNumQueries() == 1);
+	BOOST_REQUIRE(results->GetNumResults() == 1);
+	BOOST_REQUIRE((*results)[0].HasAlignments() == true);
+	string idstr = (*results)[0].GetSeqId()->AsFastaString();
+	BOOST_REQUIRE(idstr.find("lcl|2") != std::string::npos);
+
+        search->SetQuery(qf2);
+	CRef results2 = search->Run();
+	BOOST_REQUIRE(results2->GetNumQueries() == 1);
+	BOOST_REQUIRE(results2->GetNumResults() == 1);
+	BOOST_REQUIRE((*results2)[0].HasAlignments() == true);
+	idstr = (*results2)[0].GetSeqId()->AsFastaString();
+	BOOST_REQUIRE(idstr.find("lcl|1") != std::string::npos);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/c++/src/algo/blast/unit_tests/CMakeLists.txt b/c++/src/algo/blast/unit_tests/CMakeLists.txt
new file mode 100644
index 00000000..8432b4ed
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/CMakeLists.txt
@@ -0,0 +1,12 @@
+##############################################################################
+# 
+#
+
+# Include projects from this directory
+include_directories(SYSTEM ${BOOST_INCLUDE})
+
+# Recurse subdirectories
+add_subdirectory(blast_format)
+add_subdirectory(blastdb)
+add_subdirectory(seqdb_reader)
+add_subdirectory(api)
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.aalookup_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.aalookup_unit_test.app.txt
new file mode 100644
index 00000000..3c131ce9
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.aalookup_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.aalookup_unit_test.app
+#
+add_executable(aalookup_unit_test-app
+    aalookup_unit_test
+)
+
+set_target_properties(aalookup_unit_test-app PROPERTIES OUTPUT_NAME aalookup_unit_test)
+
+
+
+target_link_libraries(aalookup_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.aascan_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.aascan_unit_test.app.txt
new file mode 100644
index 00000000..2d1ba793
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.aascan_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.aascan_unit_test.app
+#
+add_executable(aascan_unit_test-app
+    aascan_unit_test
+)
+
+set_target_properties(aascan_unit_test-app PROPERTIES OUTPUT_NAME aascan_unit_test)
+
+
+
+target_link_libraries(aascan_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.bl2seq_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.bl2seq_unit_test.app.txt
new file mode 100644
index 00000000..822402db
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.bl2seq_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.bl2seq_unit_test.app
+#
+add_executable(bl2seq_unit_test-app
+    bl2seq_unit_test
+)
+
+set_target_properties(bl2seq_unit_test-app PROPERTIES OUTPUT_NAME bl2seq_unit_test)
+
+
+
+target_link_libraries(bl2seq_unit_test-app
+    blast_unit_test_util blastinput xobjsimple
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.blast_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.blast_unit_test.app.txt
new file mode 100644
index 00000000..f64b5436
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.blast_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.blast_unit_test.app
+#
+add_executable(blast_unit_test-app
+    blast_unit_test
+)
+
+set_target_properties(blast_unit_test-app PROPERTIES OUTPUT_NAME blast_unit_test)
+
+
+
+target_link_libraries(blast_unit_test-app
+    blast test_boost
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.blast_unit_test_util.lib.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.blast_unit_test_util.lib.txt
new file mode 100644
index 00000000..f6ee5fff
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.blast_unit_test_util.lib.txt
@@ -0,0 +1,17 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.blast_unit_test_util.lib
+#
+add_library(blast_unit_test_util
+    test_objmgr blast_test_util
+)
+include_directories(SYSTEM ${BOOST_INCLUDE} ${CMAKE_CURRENT_SOURCE_DIR}/../../api)
+
+add_dependencies(blast_unit_test_util
+    blastdb xnetblast
+)
+
+target_link_libraries(blast_unit_test_util
+    blast ncbi_xloader_genbank test_boost
+    xobjutil
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.blastdiag_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastdiag_unit_test.app.txt
new file mode 100644
index 00000000..c885930a
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastdiag_unit_test.app.txt
@@ -0,0 +1,14 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.blastdiag_unit_test.app
+#
+add_executable(blastdiag_unit_test-app
+    blastdiag_unit_test
+)
+
+set_target_properties(blastdiag_unit_test-app PROPERTIES OUTPUT_NAME blastdiag_unit_test)
+
+
+target_link_libraries(blastdiag_unit_test-app
+    blast test_boost
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.blastengine_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastengine_unit_test.app.txt
new file mode 100644
index 00000000..06019db4
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastengine_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.blastengine_unit_test.app
+#
+add_executable(blastengine_unit_test-app
+    blastengine_unit_test
+)
+
+set_target_properties(blastengine_unit_test-app PROPERTIES OUTPUT_NAME blastengine_unit_test)
+
+
+
+target_link_libraries(blastengine_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.blastextend_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastextend_unit_test.app.txt
new file mode 100644
index 00000000..62f289d4
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastextend_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.blastextend_unit_test.app
+#
+add_executable(blastextend_unit_test-app
+    blastextend_unit_test
+)
+
+set_target_properties(blastextend_unit_test-app PROPERTIES OUTPUT_NAME blastextend_unit_test)
+
+
+
+target_link_libraries(blastextend_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.blastfilter_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastfilter_unit_test.app.txt
new file mode 100644
index 00000000..234f3ae1
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastfilter_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.blastfilter_unit_test.app
+#
+add_executable(blastfilter_unit_test-app
+    blastfilter_unit_test
+)
+
+set_target_properties(blastfilter_unit_test-app PROPERTIES OUTPUT_NAME blastfilter_unit_test)
+
+
+
+target_link_libraries(blastfilter_unit_test-app
+    blast_unit_test_util xblast xobjsimple
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.blasthits_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.blasthits_unit_test.app.txt
new file mode 100644
index 00000000..0e4b8221
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.blasthits_unit_test.app.txt
@@ -0,0 +1,17 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.blasthits_unit_test.app
+#
+add_executable(blasthits_unit_test-app
+    blasthits_unit_test
+)
+
+set_target_properties(blasthits_unit_test-app PROPERTIES OUTPUT_NAME blasthits_unit_test)
+
+include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/../../api
+                    ${CMAKE_CURRENT_SOURCE_DIR}/../../core
+)
+
+target_link_libraries(blasthits_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.blastoptions_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastoptions_unit_test.app.txt
new file mode 100644
index 00000000..9eb44590
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastoptions_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.blastoptions_unit_test.app
+#
+add_executable(blastoptions_unit_test-app
+    blastoptions_unit_test
+)
+
+set_target_properties(blastoptions_unit_test-app PROPERTIES OUTPUT_NAME blastoptions_unit_test)
+
+
+
+target_link_libraries(blastoptions_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.blastsetup_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastsetup_unit_test.app.txt
new file mode 100644
index 00000000..f895cf3e
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.blastsetup_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.blastsetup_unit_test.app
+#
+add_executable(blastsetup_unit_test-app
+    blastsetup_unit_test
+)
+
+set_target_properties(blastsetup_unit_test-app PROPERTIES OUTPUT_NAME blastsetup_unit_test)
+
+
+
+target_link_libraries(blastsetup_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.delta_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.delta_unit_test.app.txt
new file mode 100644
index 00000000..6fc6cb4c
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.delta_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.delta_unit_test.app
+#
+add_executable(delta_unit_test-app
+    delta_unit_test
+)
+
+set_target_properties(delta_unit_test-app PROPERTIES OUTPUT_NAME delta_unit_test)
+
+
+
+target_link_libraries(delta_unit_test-app
+    seqalign_util test_boost xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.gapinfo_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.gapinfo_unit_test.app.txt
new file mode 100644
index 00000000..e21bc291
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.gapinfo_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.gapinfo_unit_test.app
+#
+add_executable(gapinfo_unit_test-app
+    gapinfo_unit_test
+)
+
+set_target_properties(gapinfo_unit_test-app PROPERTIES OUTPUT_NAME gapinfo_unit_test)
+
+
+
+target_link_libraries(gapinfo_unit_test-app
+    blast test_boost
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.gencode_singleton_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.gencode_singleton_unit_test.app.txt
new file mode 100644
index 00000000..62c1d3d8
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.gencode_singleton_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.gencode_singleton_unit_test.app
+#
+add_executable(gencode_singleton_unit_test-app
+    gencode_singleton_unit_test
+)
+
+set_target_properties(gencode_singleton_unit_test-app PROPERTIES OUTPUT_NAME gencode_singleton_unit_test)
+
+
+
+target_link_libraries(gencode_singleton_unit_test-app
+    test_boost xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.hspfilter_besthit_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.hspfilter_besthit_unit_test.app.txt
new file mode 100644
index 00000000..b44abc02
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.hspfilter_besthit_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.hspfilter_besthit_unit_test.app
+#
+add_executable(hspfilter_besthit_unit_test-app
+    hspfilter_besthit_unit_test
+)
+
+set_target_properties(hspfilter_besthit_unit_test-app PROPERTIES OUTPUT_NAME hspfilter_besthit_unit_test)
+
+
+
+target_link_libraries(hspfilter_besthit_unit_test-app
+    blast test_boost
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.hspfilter_culling_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.hspfilter_culling_unit_test.app.txt
new file mode 100644
index 00000000..ee11da1c
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.hspfilter_culling_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.hspfilter_culling_unit_test.app
+#
+add_executable(hspfilter_culling_unit_test-app
+    hspfilter_culling_unit_test
+)
+
+set_target_properties(hspfilter_culling_unit_test-app PROPERTIES OUTPUT_NAME hspfilter_culling_unit_test)
+
+
+
+target_link_libraries(hspfilter_culling_unit_test-app
+    blast test_boost
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.hspstream_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.hspstream_unit_test.app.txt
new file mode 100644
index 00000000..3de7bcbc
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.hspstream_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.hspstream_unit_test.app
+#
+add_executable(hspstream_unit_test-app
+    hspstream_unit_test hspstream_test_util
+)
+
+set_target_properties(hspstream_unit_test-app PROPERTIES OUTPUT_NAME hspstream_unit_test)
+
+
+
+target_link_libraries(hspstream_unit_test-app
+    test_boost xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.linkhsp_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.linkhsp_unit_test.app.txt
new file mode 100644
index 00000000..a43f8fb3
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.linkhsp_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.linkhsp_unit_test.app
+#
+add_executable(linkhsp_unit_test-app
+    linkhsp_unit_test
+)
+
+set_target_properties(linkhsp_unit_test-app PROPERTIES OUTPUT_NAME linkhsp_unit_test)
+
+
+
+target_link_libraries(linkhsp_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.magicblast_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.magicblast_unit_test.app.txt
new file mode 100644
index 00000000..fae867d2
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.magicblast_unit_test.app.txt
@@ -0,0 +1,9 @@
+add_executable(magicblast_unit_test-app
+    magicblast_unit_test 
+)
+
+set_target_properties(magicblast_unit_test-app PROPERTIES OUTPUT_NAME magicblast_unit_test)
+
+target_link_libraries(magicblast_unit_test-app
+    test_boost xblast
+)
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.msa2pssm_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.msa2pssm_unit_test.app.txt
new file mode 100644
index 00000000..4546b58d
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.msa2pssm_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.msa2pssm_unit_test.app
+#
+add_executable(msa2pssm_unit_test-app
+    msa2pssm_unit_test
+)
+
+set_target_properties(msa2pssm_unit_test-app PROPERTIES OUTPUT_NAME msa2pssm_unit_test)
+
+
+
+target_link_libraries(msa2pssm_unit_test-app
+    test_boost xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.ntlookup_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.ntlookup_unit_test.app.txt
new file mode 100644
index 00000000..0fe2718c
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.ntlookup_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.ntlookup_unit_test.app
+#
+add_executable(ntlookup_unit_test-app
+    ntlookup_unit_test
+)
+
+set_target_properties(ntlookup_unit_test-app PROPERTIES OUTPUT_NAME ntlookup_unit_test)
+
+
+
+target_link_libraries(ntlookup_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.ntscan_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.ntscan_unit_test.app.txt
new file mode 100644
index 00000000..dee23041
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.ntscan_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.ntscan_unit_test.app
+#
+add_executable(ntscan_unit_test-app
+    ntscan_unit_test
+)
+
+set_target_properties(ntscan_unit_test-app PROPERTIES OUTPUT_NAME ntscan_unit_test)
+
+
+
+target_link_libraries(ntscan_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.optionshandle_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.optionshandle_unit_test.app.txt
new file mode 100644
index 00000000..d3e374a7
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.optionshandle_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.optionshandle_unit_test.app
+#
+add_executable(optionshandle_unit_test-app
+    optionshandle_unit_test
+)
+
+set_target_properties(optionshandle_unit_test-app PROPERTIES OUTPUT_NAME optionshandle_unit_test)
+
+
+
+target_link_libraries(optionshandle_unit_test-app
+    test_boost xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.phiblast_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.phiblast_unit_test.app.txt
new file mode 100644
index 00000000..2c38856e
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.phiblast_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.phiblast_unit_test.app
+#
+add_executable(phiblast_unit_test-app
+    phiblast_unit_test
+)
+
+set_target_properties(phiblast_unit_test-app PROPERTIES OUTPUT_NAME phiblast_unit_test)
+
+
+
+target_link_libraries(phiblast_unit_test-app
+    test_boost xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.prelimsearch_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.prelimsearch_unit_test.app.txt
new file mode 100644
index 00000000..8cc982fa
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.prelimsearch_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.prelimsearch_unit_test.app
+#
+add_executable(prelimsearch_unit_test-app
+    prelimsearch_unit_test
+)
+
+set_target_properties(prelimsearch_unit_test-app PROPERTIES OUTPUT_NAME prelimsearch_unit_test)
+
+
+
+target_link_libraries(prelimsearch_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.psibl2seq_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.psibl2seq_unit_test.app.txt
new file mode 100644
index 00000000..96d47741
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.psibl2seq_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.psibl2seq_unit_test.app
+#
+add_executable(psibl2seq_unit_test-app
+    psibl2seq_unit_test
+)
+
+set_target_properties(psibl2seq_unit_test-app PROPERTIES OUTPUT_NAME psibl2seq_unit_test)
+
+
+
+target_link_libraries(psibl2seq_unit_test-app
+    test_boost xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.psiblast_iteration_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.psiblast_iteration_unit_test.app.txt
new file mode 100644
index 00000000..d14f5c5e
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.psiblast_iteration_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.psiblast_iteration_unit_test.app
+#
+add_executable(psiblast_iteration_unit_test-app
+    psiblast_iteration_unit_test
+)
+
+set_target_properties(psiblast_iteration_unit_test-app PROPERTIES OUTPUT_NAME psiblast_iteration_unit_test)
+
+
+
+target_link_libraries(psiblast_iteration_unit_test-app
+    test_boost xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.psiblast_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.psiblast_unit_test.app.txt
new file mode 100644
index 00000000..8bbd1035
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.psiblast_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.psiblast_unit_test.app
+#
+add_executable(psiblast_unit_test-app
+    psiblast_unit_test
+)
+
+set_target_properties(psiblast_unit_test-app PROPERTIES OUTPUT_NAME psiblast_unit_test)
+
+
+
+target_link_libraries(psiblast_unit_test-app
+    blastinput seqalign_util test_boost
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.pssmcreate_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.pssmcreate_unit_test.app.txt
new file mode 100644
index 00000000..2fe1d05d
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.pssmcreate_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.pssmcreate_unit_test.app
+#
+add_executable(pssmcreate_unit_test-app
+    pssmcreate_unit_test pssm_test_util pssmcreate_cdd_unit_test
+)
+
+set_target_properties(pssmcreate_unit_test-app PROPERTIES OUTPUT_NAME pssmcreate_unit_test)
+
+
+
+target_link_libraries(pssmcreate_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.pssmenginefreqratios_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.pssmenginefreqratios_unit_test.app.txt
new file mode 100644
index 00000000..eedd089f
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.pssmenginefreqratios_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.pssmenginefreqratios_unit_test.app
+#
+add_executable(pssmenginefreqratios_unit_test-app
+    pssmenginefreqratios_unit_test
+)
+
+set_target_properties(pssmenginefreqratios_unit_test-app PROPERTIES OUTPUT_NAME pssmenginefreqratios_unit_test)
+
+
+
+target_link_libraries(pssmenginefreqratios_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.querydata_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.querydata_unit_test.app.txt
new file mode 100644
index 00000000..fa063e7c
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.querydata_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.querydata_unit_test.app
+#
+add_executable(querydata_unit_test-app
+    querydata_unit_test
+)
+
+set_target_properties(querydata_unit_test-app PROPERTIES OUTPUT_NAME querydata_unit_test)
+
+
+
+target_link_libraries(querydata_unit_test-app
+    blast_unit_test_util xblast xobjsimple
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.queryinfo_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.queryinfo_unit_test.app.txt
new file mode 100644
index 00000000..1284dde5
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.queryinfo_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.queryinfo_unit_test.app
+#
+add_executable(queryinfo_unit_test-app
+    queryinfo_unit_test
+)
+
+set_target_properties(queryinfo_unit_test-app PROPERTIES OUTPUT_NAME queryinfo_unit_test)
+
+
+
+target_link_libraries(queryinfo_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.redoalignment_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.redoalignment_unit_test.app.txt
new file mode 100644
index 00000000..17e2de5a
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.redoalignment_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.redoalignment_unit_test.app
+#
+add_executable(redoalignment_unit_test-app
+    redoalignment_unit_test
+)
+
+set_target_properties(redoalignment_unit_test-app PROPERTIES OUTPUT_NAME redoalignment_unit_test)
+
+
+
+target_link_libraries(redoalignment_unit_test-app
+    blast_unit_test_util blastinput
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.remote_blast_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.remote_blast_unit_test.app.txt
new file mode 100644
index 00000000..15f1fece
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.remote_blast_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.remote_blast_unit_test.app
+#
+add_executable(remote_blast_unit_test-app
+    remote_blast_unit_test
+)
+
+set_target_properties(remote_blast_unit_test-app PROPERTIES OUTPUT_NAME remote_blast_unit_test)
+
+
+
+target_link_libraries(remote_blast_unit_test-app
+    blast_services blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.rps_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.rps_unit_test.app.txt
new file mode 100644
index 00000000..c7b36e4c
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.rps_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.rps_unit_test.app
+#
+add_executable(rps_unit_test-app
+    rps_unit_test
+)
+
+set_target_properties(rps_unit_test-app PROPERTIES OUTPUT_NAME rps_unit_test)
+
+
+
+target_link_libraries(rps_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.scoreblk_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.scoreblk_unit_test.app.txt
new file mode 100644
index 00000000..613d8094
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.scoreblk_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.scoreblk_unit_test.app
+#
+add_executable(scoreblk_unit_test-app
+    scoreblk_unit_test
+)
+
+set_target_properties(scoreblk_unit_test-app PROPERTIES OUTPUT_NAME scoreblk_unit_test)
+
+
+
+target_link_libraries(scoreblk_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.search_strategy_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.search_strategy_unit_test.app.txt
new file mode 100644
index 00000000..19725d28
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.search_strategy_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.search_strategy_unit_test.app
+#
+add_executable(search_strategy_unit_test-app
+    search_strategy_unit_test
+)
+
+set_target_properties(search_strategy_unit_test-app PROPERTIES OUTPUT_NAME search_strategy_unit_test)
+
+
+
+target_link_libraries(search_strategy_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.seqalign_util.lib.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.seqalign_util.lib.txt
new file mode 100644
index 00000000..851e66d5
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.seqalign_util.lib.txt
@@ -0,0 +1,13 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.seqalign_util.lib
+#
+add_library(seqalign_util
+    seqalign_cmp seqalign_set_convert
+)
+add_dependencies(seqalign_util
+    blastdb xnetblast
+)
+
+target_link_libraries(seqalign_util
+    seq
+)
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.seqinfosrc_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.seqinfosrc_unit_test.app.txt
new file mode 100644
index 00000000..95c17d73
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.seqinfosrc_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.seqinfosrc_unit_test.app
+#
+add_executable(seqinfosrc_unit_test-app
+    seqinfosrc_unit_test
+)
+
+set_target_properties(seqinfosrc_unit_test-app PROPERTIES OUTPUT_NAME seqinfosrc_unit_test)
+
+
+
+target_link_libraries(seqinfosrc_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.seqsrc_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.seqsrc_unit_test.app.txt
new file mode 100644
index 00000000..11cbc36b
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.seqsrc_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.seqsrc_unit_test.app
+#
+add_executable(seqsrc_unit_test-app
+    seqsrc_unit_test seqsrc_mock mockseqsrc1_unit_test mockseqsrc2_unit_test
+)
+
+set_target_properties(seqsrc_unit_test-app PROPERTIES OUTPUT_NAME seqsrc_unit_test)
+
+
+
+target_link_libraries(seqsrc_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.setupfactory_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.setupfactory_unit_test.app.txt
new file mode 100644
index 00000000..701bf267
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.setupfactory_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.setupfactory_unit_test.app
+#
+add_executable(setupfactory_unit_test-app
+    setupfactory_unit_test
+)
+
+set_target_properties(setupfactory_unit_test-app PROPERTIES OUTPUT_NAME setupfactory_unit_test)
+
+
+
+target_link_libraries(setupfactory_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.split_query_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.split_query_unit_test.app.txt
new file mode 100644
index 00000000..c2707764
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.split_query_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.split_query_unit_test.app
+#
+add_executable(split_query_unit_test-app
+    split_query_unit_test
+)
+
+set_target_properties(split_query_unit_test-app PROPERTIES OUTPUT_NAME split_query_unit_test)
+
+
+
+target_link_libraries(split_query_unit_test-app
+    blast_unit_test_util xblast xobjsimple
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.stat_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.stat_unit_test.app.txt
new file mode 100644
index 00000000..472fc7a7
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.stat_unit_test.app.txt
@@ -0,0 +1,9 @@
+add_executable(stat_unit_test stat_unit_test)
+
+include_directories(SYSTEM ${CMAKE_CURRENT_SOURCE_DIR}/../../api)
+
+add_definitions(-DNCBI_MODULE=BLAST)
+
+target_link_libraries(stat_unit_test
+    blast test_boost
+)
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.subj_ranges_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.subj_ranges_unit_test.app.txt
new file mode 100644
index 00000000..77cb7918
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.subj_ranges_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.subj_ranges_unit_test.app
+#
+add_executable(subj_ranges_unit_test-app
+    subj_ranges_unit_test
+)
+
+set_target_properties(subj_ranges_unit_test-app PROPERTIES OUTPUT_NAME subj_ranges_unit_test)
+
+
+
+target_link_libraries(subj_ranges_unit_test-app
+    test_boost xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.traceback_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.traceback_unit_test.app.txt
new file mode 100644
index 00000000..ddd7a1b8
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.traceback_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.traceback_unit_test.app
+#
+add_executable(traceback_unit_test-app
+    traceback_unit_test
+)
+
+set_target_properties(traceback_unit_test-app PROPERTIES OUTPUT_NAME traceback_unit_test)
+
+
+
+target_link_libraries(traceback_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.tracebacksearch_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.tracebacksearch_unit_test.app.txt
new file mode 100644
index 00000000..fc54910e
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.tracebacksearch_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.tracebacksearch_unit_test.app
+#
+add_executable(tracebacksearch_unit_test-app
+    tracebacksearch_unit_test
+)
+
+set_target_properties(tracebacksearch_unit_test-app PROPERTIES OUTPUT_NAME tracebacksearch_unit_test)
+
+
+
+target_link_libraries(tracebacksearch_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.txt
new file mode 100644
index 00000000..58edf67b
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.txt
@@ -0,0 +1,57 @@
+##############################################################################
+# 
+#
+
+include_directories(SYSTEM ${BOOST_INCLUDE})
+
+# Include projects from this directory
+include(CMakeLists.blast_unit_test_util.lib.txt)
+include(CMakeLists.seqalign_util.lib.txt)
+include(CMakeLists.blast_unit_test.app.txt)
+include(CMakeLists.aalookup_unit_test.app.txt)
+include(CMakeLists.seqsrc_unit_test.app.txt)
+include(CMakeLists.delta_unit_test.app.txt)
+include(CMakeLists.ntlookup_unit_test.app.txt)
+include(CMakeLists.seqinfosrc_unit_test.app.txt)
+include(CMakeLists.setupfactory_unit_test.app.txt)
+include(CMakeLists.search_strategy_unit_test.app.txt)
+include(CMakeLists.redoalignment_unit_test.app.txt)
+include(CMakeLists.queryinfo_unit_test.app.txt)
+include(CMakeLists.querydata_unit_test.app.txt)
+include(CMakeLists.pssmenginefreqratios_unit_test.app.txt)
+include(CMakeLists.blastsetup_unit_test.app.txt)
+include(CMakeLists.blastextend_unit_test.app.txt)
+include(CMakeLists.blastdiag_unit_test.app.txt)
+include(CMakeLists.pssmcreate_unit_test.app.txt)
+include(CMakeLists.psiblast_iteration_unit_test.app.txt)
+include(CMakeLists.hspfilter_besthit_unit_test.app.txt)
+include(CMakeLists.hspfilter_culling_unit_test.app.txt)
+include(CMakeLists.optionshandle_unit_test.app.txt)
+include(CMakeLists.msa2pssm_unit_test.app.txt)
+include(CMakeLists.tracebacksearch_unit_test.app.txt)
+include(CMakeLists.traceback_unit_test.app.txt)
+include(CMakeLists.psibl2seq_unit_test.app.txt)
+include(CMakeLists.psiblast_unit_test.app.txt)
+include(CMakeLists.prelimsearch_unit_test.app.txt)
+include(CMakeLists.phiblast_unit_test.app.txt)
+include(CMakeLists.split_query_unit_test.app.txt)
+include(CMakeLists.scoreblk_unit_test.app.txt)
+include(CMakeLists.hspstream_unit_test.app.txt)
+include(CMakeLists.rps_unit_test.app.txt)
+include(CMakeLists.gapinfo_unit_test.app.txt)
+include(CMakeLists.blasthits_unit_test.app.txt)
+include(CMakeLists.linkhsp_unit_test.app.txt)
+include(CMakeLists.blastengine_unit_test.app.txt)
+include(CMakeLists.subj_ranges_unit_test.app.txt)
+include(CMakeLists.version_reference_unit_test.app.txt)
+include(CMakeLists.ntscan_unit_test.app.txt)
+include(CMakeLists.aascan_unit_test.app.txt)
+include(CMakeLists.remote_blast_unit_test.app.txt)
+include(CMakeLists.uniform_search_unit_test.app.txt)
+include(CMakeLists.blastfilter_unit_test.app.txt)
+include(CMakeLists.blastoptions_unit_test.app.txt)
+include(CMakeLists.gencode_singleton_unit_test.app.txt)
+include(CMakeLists.bl2seq_unit_test.app.txt)
+include(CMakeLists.stat_unit_test.app.txt)
+include(CMakeLists.magicblast_unit_test.app.txt)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.uniform_search_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.uniform_search_unit_test.app.txt
new file mode 100644
index 00000000..5ed3013c
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.uniform_search_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.uniform_search_unit_test.app
+#
+add_executable(uniform_search_unit_test-app
+    uniform_search_unit_test
+)
+
+set_target_properties(uniform_search_unit_test-app PROPERTIES OUTPUT_NAME uniform_search_unit_test)
+
+
+
+target_link_libraries(uniform_search_unit_test-app
+    blast_unit_test_util xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/CMakeLists.version_reference_unit_test.app.txt b/c++/src/algo/blast/unit_tests/api/CMakeLists.version_reference_unit_test.app.txt
new file mode 100644
index 00000000..dfc77e04
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/api/CMakeLists.version_reference_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/api/Makefile.version_reference_unit_test.app
+#
+add_executable(version_reference_unit_test-app
+    version_reference_unit_test
+)
+
+set_target_properties(version_reference_unit_test-app PROPERTIES OUTPUT_NAME version_reference_unit_test)
+
+
+
+target_link_libraries(version_reference_unit_test-app
+    test_boost xblast
+)
+
diff --git a/c++/src/algo/blast/unit_tests/api/Makefile.bl2seq_unit_test.app b/c++/src/algo/blast/unit_tests/api/Makefile.bl2seq_unit_test.app
index 258b96c3..0c717582 100644
--- a/c++/src/algo/blast/unit_tests/api/Makefile.bl2seq_unit_test.app
+++ b/c++/src/algo/blast/unit_tests/api/Makefile.bl2seq_unit_test.app
@@ -1,4 +1,4 @@
-# $Id: Makefile.bl2seq_unit_test.app 505858 2016-06-29 16:55:21Z elisovdn $
+# $Id: Makefile.bl2seq_unit_test.app 546569 2017-09-19 17:15:20Z ivanov $
 
 APP = bl2seq_unit_test
 SRC = bl2seq_unit_test
@@ -13,4 +13,4 @@ CHECK_REQUIRES = MT in-house-resources
 CHECK_CMD = bl2seq_unit_test
 CHECK_COPY = bl2seq_unit_test.ini
 
-WATCHERS = boratyng madden camacho fongah2
+WATCHERS = boratyng madden camacho fongah2 
diff --git a/c++/src/algo/blast/unit_tests/api/Makefile.gapinfo_unit_test.app b/c++/src/algo/blast/unit_tests/api/Makefile.gapinfo_unit_test.app
index d8af43d2..ede5a0d4 100644
--- a/c++/src/algo/blast/unit_tests/api/Makefile.gapinfo_unit_test.app
+++ b/c++/src/algo/blast/unit_tests/api/Makefile.gapinfo_unit_test.app
@@ -1,10 +1,10 @@
-# $Id: Makefile.gapinfo_unit_test.app 505858 2016-06-29 16:55:21Z elisovdn $
+# $Id: Makefile.gapinfo_unit_test.app 533242 2017-04-13 20:03:50Z boratyng $
 
 APP = gapinfo_unit_test
 SRC = gapinfo_unit_test 
 
 CPPFLAGS = -DNCBI_MODULE=BLAST $(ORIG_CPPFLAGS) $(BOOST_INCLUDE)
-LIB = test_boost $(BLAST_LIBS) xncbi
+LIB = test_boost $(BLAST_LIBS) xconnect xncbi
 
 CHECK_REQUIRES = MT in-house-resources
 CHECK_CMD = gapinfo_unit_test
diff --git a/c++/src/algo/blast/unit_tests/api/bl2seq_unit_test.ini b/c++/src/algo/blast/unit_tests/api/bl2seq_unit_test.ini
index 12cb45ed..8cce4d75 100644
--- a/c++/src/algo/blast/unit_tests/api/bl2seq_unit_test.ini
+++ b/c++/src/algo/blast/unit_tests/api/bl2seq_unit_test.ini
@@ -1,4 +1,4 @@
-; $Id: bl2seq_unit_test.ini 454210 2014-12-11 18:20:43Z camacho $
+; $Id: bl2seq_unit_test.ini 521603 2016-12-12 14:39:15Z camacho $
 [UNITTESTS_DISABLE]
 GLOBAL = OS_Solaris
 BlastnWithWindowMasker_Db = PLATFORM_BigEndian
@@ -7,3 +7,7 @@ BlastnWithWindowMasker_DbAndTaxid = PLATFORM_BigEndian
 Alex = true
 ; This isn't supported 
 testInterruptBlastSetup = true
+
+; SB-1842
+BlastnWithWindowMasker_InvalidDb = OS_MacOSX
+BlastnWithWindowMasker_InvalidTaxid = OS_MacOSX
diff --git a/c++/src/algo/blast/unit_tests/api/blastengine_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/blastengine_unit_test.cpp
index e8bc6d8f..f27f1d9f 100644
--- a/c++/src/algo/blast/unit_tests/api/blastengine_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/blastengine_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: blastengine_unit_test.cpp 507726 2016-07-21 14:42:04Z grichenk $
+/*  $Id: blastengine_unit_test.cpp 531968 2017-03-30 17:34:38Z grichenk $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
@@ -404,9 +404,20 @@ BOOST_AUTO_TEST_CASE(testDiscMegaBlastPartialRun)
     BOOST_REQUIRE(second_hit->GetNamedScore("num_ident", num_ident));
     BOOST_REQUIRE_EQUAL(kNumIdent[1], num_ident);
 
-    BOOST_REQUIRE_EQUAL(GI_FROM(TIntId, kGis[0]), first_hit->GetSeq_id(1).GetGi());
-    BOOST_REQUIRE_EQUAL(GI_FROM(TIntId, kGis[1]), second_hit->GetSeq_id(1).GetGi());
-
+    if ( !CSeq_id::PreferAccessionOverGi() ) {
+        BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, first_hit->GetSeq_id(1).Which());
+        BOOST_REQUIRE_EQUAL(GI_FROM(TIntId, kGis[0]), first_hit->GetSeq_id(1).GetGi());
+        BOOST_REQUIRE_EQUAL(CSeq_id::e_Gi, second_hit->GetSeq_id(1).Which());
+        BOOST_REQUIRE_EQUAL(GI_FROM(TIntId, kGis[1]), second_hit->GetSeq_id(1).GetGi());
+    }
+    else {
+        BOOST_REQUIRE_EQUAL(CSeq_id::e_Ddbj, first_hit->GetSeq_id(1).Which());
+        BOOST_REQUIRE_EQUAL("BP722565", first_hit->GetSeq_id(1).GetDdbj().GetAccession());
+        BOOST_REQUIRE_EQUAL(1, first_hit->GetSeq_id(1).GetDdbj().GetVersion());
+        BOOST_REQUIRE_EQUAL(CSeq_id::e_Ddbj, second_hit->GetSeq_id(1).Which());
+        BOOST_REQUIRE_EQUAL("BP723807", second_hit->GetSeq_id(1).GetDdbj().GetAccession());
+        BOOST_REQUIRE_EQUAL(1, second_hit->GetSeq_id(1).GetDdbj().GetVersion());
+    }
 }
 
 BOOST_AUTO_TEST_CASE(testBlastpPrelimSearch) 
diff --git a/c++/src/algo/blast/unit_tests/api/blastfilter_unit_test.ini b/c++/src/algo/blast/unit_tests/api/blastfilter_unit_test.ini
index 1f0437cb..a7889b4e 100644
--- a/c++/src/algo/blast/unit_tests/api/blastfilter_unit_test.ini
+++ b/c++/src/algo/blast/unit_tests/api/blastfilter_unit_test.ini
@@ -1,6 +1,9 @@
-; $Id: blastfilter_unit_test.ini 454176 2014-12-11 16:00:59Z camacho $
+; $Id: blastfilter_unit_test.ini 521603 2016-12-12 14:39:15Z camacho $
 [UNITTESTS_DISABLE]
 GLOBAL = OS_Solaris
 WindowMasker = PLATFORM_BigEndian
 WindowMaskerAndDustFilter = PLATFORM_BigEndian
 WindowMasker_OnSeqInterval = PLATFORM_BigEndian
+
+; SB-1843
+WindowMaskerWithMissingParameter = OS_MacOSX
diff --git a/c++/src/algo/blast/unit_tests/api/blasthits_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/blasthits_unit_test.cpp
index 1e11c091..e0884c3b 100644
--- a/c++/src/algo/blast/unit_tests/api/blasthits_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/blasthits_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: blasthits_unit_test.cpp 514847 2016-09-26 17:22:13Z ivanov $
+/*  $Id: blasthits_unit_test.cpp 513591 2016-09-13 14:45:34Z rackerst $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
diff --git a/c++/src/algo/blast/unit_tests/api/blastoptions_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/blastoptions_unit_test.cpp
index c0ca089d..ba67d8b6 100644
--- a/c++/src/algo/blast/unit_tests/api/blastoptions_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/blastoptions_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: blastoptions_unit_test.cpp 504861 2016-06-20 15:45:40Z boratyng $
+/*  $Id: blastoptions_unit_test.cpp 518804 2016-11-08 04:18:18Z ucko $
  * ===========================================================================
  *
  *                            PUBLIC DOMAIN NOTICE
@@ -39,6 +39,8 @@
 #include 
 #include "test_objmgr.hpp"
 #include 
+#include 
+#include 
 
 #ifndef SKIP_DOXYGEN_PROCESSING
 
diff --git a/c++/src/algo/blast/unit_tests/api/blastsetup_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/blastsetup_unit_test.cpp
index c25e5c5f..2409cfd3 100644
--- a/c++/src/algo/blast/unit_tests/api/blastsetup_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/blastsetup_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: blastsetup_unit_test.cpp 512603 2016-09-01 16:55:07Z ivanov $
+/*  $Id: blastsetup_unit_test.cpp 512532 2016-08-31 18:44:10Z boratyng $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
diff --git a/c++/src/algo/blast/unit_tests/api/delta_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/delta_unit_test.cpp
index 967c2454..b7f020a7 100644
--- a/c++/src/algo/blast/unit_tests/api/delta_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/delta_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: delta_unit_test.cpp 507726 2016-07-21 14:42:04Z grichenk $
+/*  $Id: delta_unit_test.cpp 531968 2017-03-30 17:34:38Z grichenk $
  * ===========================================================================
  *
  *                            PUBLIC DOMAIN NOTICE
@@ -157,18 +157,40 @@ struct CDeltaBlastTestFixture {
     {
         int num_ids = 0;
         TGi last_id = INVALID_GI;
-        ITERATE(CSeq_align_set::Tdata, itr, sas->Get()){
+        string last_acc;
+        CTextseq_id::TVersion last_ver = -1;
+        ITERATE(CSeq_align_set::Tdata, itr, sas->Get()) {
             const CSeq_id& seqid = (*itr)->GetSeq_id(1);
+            if ( !CSeq_id::PreferAccessionOverGi() ) {
+                BOOST_REQUIRE(seqid.IsGi() || seqid.IsGeneral());
+            }
+            else {
+                BOOST_REQUIRE(seqid.IsOther() ||
+                    seqid.IsGeneral() ||
+                    seqid.IsGenbank());
+            }
 
-            BOOST_REQUIRE(seqid.IsGi() || seqid.IsGeneral());
-
-            if (seqid.IsGi()) {
+            const CTextseq_id* txt_id = seqid.GetTextseq_Id();
+            if (CSeq_id::PreferAccessionOverGi() && txt_id) {
+                string acc = txt_id->GetAccession();
+                CTextseq_id::TVersion ver = txt_id->IsSetVersion() ?
+                    txt_id->GetVersion() : -1;
+                if (acc != last_acc || ver != last_ver) {
+                    num_ids++;
+                    last_acc = acc;
+                    last_ver = ver;
+                }
+                last_id = INVALID_GI;
+            }
+            else if (!CSeq_id::PreferAccessionOverGi() && seqid.IsGi()) {
                 TGi new_gi = seqid.GetGi();
             
                 if (new_gi != last_id) {
                         num_ids++;
                         last_id = new_gi;
                 }
+                last_acc.clear();
+                last_ver = -1;
             }
             else {
                 BOOST_REQUIRE(seqid.GetGeneral().IsSetTag());
@@ -178,6 +200,8 @@ struct CDeltaBlastTestFixture {
                     num_ids++;
                     last_id = GI_FROM(int, new_tag);
                 }
+                last_acc.clear();
+                last_ver = -1;
             }
             
         }
diff --git a/c++/src/algo/blast/unit_tests/api/magicblast_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/magicblast_unit_test.cpp
index 98964308..61bf6797 100644
--- a/c++/src/algo/blast/unit_tests/api/magicblast_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/magicblast_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: magicblast_unit_test.cpp 517506 2016-10-25 17:22:36Z ivanov $
+/*  $Id: magicblast_unit_test.cpp 546023 2017-09-13 11:14:25Z ivanov $
  * ===========================================================================
  *
  *                            PUBLIC DOMAIN NOTICE
@@ -119,6 +119,8 @@ BOOST_AUTO_TEST_CASE(MappingNoPairs)
 
     CRef query_factory(new CObjMgrFree_QueryFactory(m_Queries));
     CRef db_adapter(new CLocalDbAdapter(*m_Db));
+    m_OptHandle->SetMismatchPenalty(-8);
+    m_OptHandle->SetGapExtensionCost(8);
     CMagicBlast magicblast(query_factory, db_adapter, m_OptHandle);
     CRef results = magicblast.Run();
 
@@ -335,7 +337,7 @@ BOOST_AUTO_TEST_CASE(MappingPaired)
     CMagicBlast magicblast(query_factory, db_adapter, m_OptHandle);
     CRef results = magicblast.Run();
 
-    const size_t kExpectedNumResults = 1;
+    const size_t kExpectedNumResults = 3;
     BOOST_REQUIRE_EQUAL(results->Get().size(), kExpectedNumResults);
 
     SExon exon;
@@ -344,10 +346,71 @@ BOOST_AUTO_TEST_CASE(MappingPaired)
     // expected HSPs
 
     int results_idx = 0;
+
     // HSP #1
     expected_hits[results_idx].score = 68;
     expected_hits[results_idx].prod_length = 75;
 
+    exon.prod_start = 0;
+    exon.prod_end = 67;
+    exon.gen_start = 9925;
+    exon.gen_end = 9992;
+    exon.prod_strand = eNa_strand_minus;
+    exon.gen_strand = eNa_strand_plus;
+    exon.acceptor = "";
+    exon.donor = "AG";
+    expected_hits[results_idx].exons.push_back(exon);
+
+    // HSP #2
+    results_idx++;
+    expected_hits[results_idx].score = 74;
+    expected_hits[results_idx].prod_length = 75;
+
+    exon.prod_start = 1;
+    exon.prod_end = 74;
+    exon.gen_start = 9842;
+    exon.gen_end = 9915;
+    exon.prod_strand = eNa_strand_plus;
+    exon.gen_strand = eNa_strand_plus;
+    exon.acceptor = "";
+    exon.donor = "";
+    expected_hits[results_idx].exons.push_back(exon);
+
+    // HSP #3
+    results_idx++;
+    expected_hits[results_idx].score = 68;
+    expected_hits[results_idx].prod_length = 75;
+
+    exon.prod_start = 0;
+    exon.prod_end = 67;
+    exon.gen_start = 20795;
+    exon.gen_end = 20862;
+    exon.prod_strand = eNa_strand_minus;
+    exon.gen_strand = eNa_strand_plus;
+    exon.acceptor = "";
+    exon.donor = "AG";
+    expected_hits[results_idx].exons.push_back(exon);
+
+    // HSP #4
+    results_idx++;
+    expected_hits[results_idx].score = 74;
+    expected_hits[results_idx].prod_length = 75;
+
+    exon.prod_start = 1;
+    exon.prod_end = 74;
+    exon.gen_start = 20712;
+    exon.gen_end = 20785;
+    exon.prod_strand = eNa_strand_plus;
+    exon.gen_strand = eNa_strand_plus;
+    exon.acceptor = "";
+    exon.donor = "";
+    expected_hits[results_idx].exons.push_back(exon);
+
+    // HSP #5
+    results_idx++;
+    expected_hits[results_idx].score = 68;
+    expected_hits[results_idx].prod_length = 75;
+
     exon.prod_start = 7;
     exon.prod_end = 74;
     exon.gen_start = 2443260;
@@ -358,19 +421,19 @@ BOOST_AUTO_TEST_CASE(MappingPaired)
     exon.donor = "";
     expected_hits[results_idx].exons.push_back(exon);
 
-    // HSP #2
+    // HSP #6
     results_idx++;
-    expected_hits[results_idx].score = 71;
+    expected_hits[results_idx].score = 74;
     expected_hits[results_idx].prod_length = 75;
 
     exon.prod_start = 0;
-    exon.prod_end = 70;
+    exon.prod_end = 73;
     exon.gen_start = 2443337;
-    exon.gen_end = 2443407;
+    exon.gen_end = 2443410;
     exon.prod_strand = eNa_strand_minus;
     exon.gen_strand = eNa_strand_plus;
     exon.acceptor = "";
-    exon.donor = "CA";
+    exon.donor = "";
     expected_hits[results_idx].exons.push_back(exon);
 
     // compare computed HSPs with the expected ones
diff --git a/c++/src/algo/blast/unit_tests/api/magicblast_unit_test.ini b/c++/src/algo/blast/unit_tests/api/magicblast_unit_test.ini
index 7bd19f9b..cf7fad4c 100644
--- a/c++/src/algo/blast/unit_tests/api/magicblast_unit_test.ini
+++ b/c++/src/algo/blast/unit_tests/api/magicblast_unit_test.ini
@@ -1,3 +1,3 @@
-; $Id: magicblast_unit_test.ini 517501 2016-10-25 17:21:06Z ivanov $
+; $Id: magicblast_unit_test.ini 516750 2016-10-17 19:01:43Z boratyng $
 [UNITTESTS_DISABLE]
 GLOBAL = OS_Solaris | PLATFORM_Bits32
diff --git a/c++/src/algo/blast/unit_tests/api/ntlookup_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/ntlookup_unit_test.cpp
index fc4ea035..f94af2d5 100644
--- a/c++/src/algo/blast/unit_tests/api/ntlookup_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/ntlookup_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: ntlookup_unit_test.cpp 506102 2016-07-01 15:48:06Z boratyng $
+/*  $Id: ntlookup_unit_test.cpp 544841 2017-08-28 16:55:02Z ivanov $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
@@ -494,27 +494,25 @@ BOOST_AUTO_TEST_CASE(testHashLookupTableWordSize16) {
 	LookupTableOptionsNew(eBlastTypeMapping, &lookup_options);
 	BLAST_FillLookupTableOptions(lookup_options, eBlastTypeMapping,
                                  FALSE, 0, 0);
+    lookup_options->word_size = 16;
 
     QuerySetUpOptions* query_options = NULL;
     BlastQuerySetUpOptionsNew(&query_options);
-	LookupTableWrap* lookup_wrap_ptr;
- 	BOOST_REQUIRE_EQUAL((int)LookupTableWrapInit(query_blk, 
-                             lookup_options, query_options, lookup_segments, 
-                             0, &lookup_wrap_ptr, NULL, NULL, NULL), 0);
+
+    BlastNaHashLookupTable* lookup = NULL;
+    BOOST_REQUIRE_EQUAL((int)BlastNaHashLookupTableNew(query_blk,
+                              lookup_segments, &lookup, lookup_options,
+                              query_options, NULL, 1), 0);
+
     query_options = BlastQuerySetUpOptionsFree(query_options);
     BOOST_REQUIRE(query_options == NULL);
-	BOOST_REQUIRE_EQUAL(eNaHashLookupTable,
-                        (ELookupTableType)lookup_wrap_ptr->lut_type);
 
-	BlastNaHashLookupTable* lookup =
-        (BlastNaHashLookupTable*)lookup_wrap_ptr->lut;
 	BOOST_REQUIRE_EQUAL(16, (int)lookup->lut_word_length); 
 	BOOST_REQUIRE_EQUAL(1, lookup->scan_step);
-	BOOST_REQUIRE_EQUAL(10, lookup->longest_chain);
-    BOOST_REQUIRE_EQUAL(16777216, lookup->backbone_size);
-    BOOST_REQUIRE_EQUAL(24, lookup->offsets_size);
-    BOOST_REQUIRE_EQUAL(11, lookup->pv_array_bts);
-	BOOST_REQUIRE_EQUAL(11, lookup->pv_array_bts);
+	BOOST_REQUIRE_EQUAL(11, lookup->longest_chain);
+    BOOST_REQUIRE_EQUAL(32768, lookup->backbone_size);
+    BOOST_REQUIRE_EQUAL(1494, lookup->offsets_size);
+    BOOST_REQUIRE_EQUAL(5, lookup->pv_array_bts);
     BOOST_REQUIRE(lookup->hash_callback);
 
     Uint4 pv_array_size = 1u << (32 - 10);
@@ -522,7 +520,7 @@ BOOST_AUTO_TEST_CASE(testHashLookupTableWordSize16) {
             EndianIndependentBufferHash((char*) lookup->pv,
                                         pv_array_size * sizeof(PV_ARRAY_TYPE),
                                         sizeof(PV_ARRAY_TYPE));
-	BOOST_REQUIRE_EQUAL(-1839333193, pv_array_hash);
+	BOOST_REQUIRE_EQUAL(1515308782, pv_array_hash);
 
     TNaLookupHashFunction hash_func =
         (TNaLookupHashFunction)lookup->hash_callback;
@@ -544,8 +542,8 @@ BOOST_AUTO_TEST_CASE(testHashLookupTableWordSize16) {
     // ... at position zero
     BOOST_REQUIRE_EQUAL(0, lookup->thick_backbone[hashed_word].offsets[0]);
 
-	lookup_wrap_ptr = LookupTableWrapFree(lookup_wrap_ptr);
-        BOOST_REQUIRE(lookup_wrap_ptr == NULL);
+    lookup = BlastNaHashLookupTableDestruct(lookup);
+        BOOST_REQUIRE(lookup == NULL);
 	lookup_options = LookupTableOptionsFree(lookup_options);
         BOOST_REQUIRE(lookup_options == NULL);
 }
@@ -584,10 +582,9 @@ BOOST_AUTO_TEST_CASE(testHashLookupTableWordSize16WithDbFilter) {
 	BOOST_REQUIRE_EQUAL(16, (int)lookup->lut_word_length); 
 	BOOST_REQUIRE_EQUAL(1, lookup->scan_step);
 	BOOST_REQUIRE_EQUAL(10, lookup->longest_chain);
-    BOOST_REQUIRE_EQUAL(16777216, lookup->backbone_size);
+    BOOST_REQUIRE_EQUAL(256, lookup->backbone_size);
     BOOST_REQUIRE_EQUAL(12, lookup->offsets_size);
-    BOOST_REQUIRE_EQUAL(11, lookup->pv_array_bts);
-	BOOST_REQUIRE_EQUAL(11, lookup->pv_array_bts);
+    BOOST_REQUIRE_EQUAL(5, lookup->pv_array_bts);
     BOOST_REQUIRE(lookup->hash_callback);
 
     Uint4 pv_array_size = 1u << (32 - 10);
@@ -595,7 +592,7 @@ BOOST_AUTO_TEST_CASE(testHashLookupTableWordSize16WithDbFilter) {
             EndianIndependentBufferHash((char*) lookup->pv,
                                         pv_array_size * sizeof(PV_ARRAY_TYPE),
                                         sizeof(PV_ARRAY_TYPE));
-	BOOST_REQUIRE_EQUAL(2116636124, pv_array_hash);
+	BOOST_REQUIRE_EQUAL(130150681, pv_array_hash);
 
 
     TNaLookupHashFunction hash_func =
diff --git a/c++/src/algo/blast/unit_tests/api/optionshandle_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/optionshandle_unit_test.cpp
index 2ae1fafa..6df65e3c 100644
--- a/c++/src/algo/blast/unit_tests/api/optionshandle_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/optionshandle_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: optionshandle_unit_test.cpp 436114 2014-05-23 14:32:59Z madden $
+/*  $Id: optionshandle_unit_test.cpp 535507 2017-05-09 15:35:47Z madden $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
@@ -42,6 +42,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "test_objmgr.hpp"
@@ -309,6 +310,16 @@ BOOST_AUTO_TEST_CASE(TblastxTest) {
        delete handle;
 }
 
+BOOST_AUTO_TEST_CASE(KBlastpTest) {
+       CBlastOptionsHandle* handle = CBlastOptionsFactory::CreateTask("kblastp"); 
+       CBlastpKmerOptionsHandle* opts =
+             dynamic_cast (handle);
+       BOOST_REQUIRE(opts != NULL);
+       BOOST_REQUIRE_EQUAL(1, opts->GetMinHits());
+       BOOST_REQUIRE_EQUAL(1000, opts->GetCandidateSeqs());
+       BOOST_REQUIRE(!strcmp("BLOSUM62", opts->GetMatrixName()));
+       delete handle;
+}
 
 struct ProteinOptiosHandleFixture {
     ProteinOptiosHandleFixture() {
diff --git a/c++/src/algo/blast/unit_tests/api/psiblast_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/psiblast_unit_test.cpp
index 3dfcb761..593b9893 100644
--- a/c++/src/algo/blast/unit_tests/api/psiblast_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/psiblast_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: psiblast_unit_test.cpp 498248 2016-04-14 15:42:26Z boratyng $
+/*  $Id: psiblast_unit_test.cpp 531968 2017-03-30 17:34:38Z grichenk $
  * ===========================================================================
  *
  *                            PUBLIC DOMAIN NOTICE
@@ -134,13 +134,20 @@ struct CPsiBlastTestFixture {
     {
         int num_gis = 0;
         TGi last_gi = INVALID_GI;
+        CSeq_id last_id;
         ITERATE(CSeq_align_set::Tdata, itr, sas->Get()){
             const CSeq_id& seqid = (*itr)->GetSeq_id(1);
-            TGi new_gi = seqid.GetGi();
-            if (new_gi != last_gi)
-            {
-                 num_gis++;
-                 last_gi = new_gi;
+            if ( !CSeq_id::PreferAccessionOverGi() ) {
+                TGi new_gi = seqid.GetGi();
+                if (new_gi != last_gi)
+                {
+                     num_gis++;
+                     last_gi = new_gi;
+                }
+            }
+            else if ( !seqid.Equals(last_id) ) {
+                num_gis++;
+                last_id.Assign(seqid);
             }
         }
         return num_gis;
diff --git a/c++/src/algo/blast/unit_tests/api/subj_ranges_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/subj_ranges_unit_test.cpp
index f591eeb2..5b380b4e 100644
--- a/c++/src/algo/blast/unit_tests/api/subj_ranges_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/subj_ranges_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: subj_ranges_unit_test.cpp 171622 2009-09-25 15:08:10Z avagyanv $
+/*  $Id: subj_ranges_unit_test.cpp 527083 2017-02-09 13:45:44Z madden $
  * ===========================================================================
  *
  *                            PUBLIC DOMAIN NOTICE
@@ -115,7 +115,7 @@ BOOST_AUTO_TEST_CASE(TestCSubjectRangesSetApplyRanges)
     CSubjectRangesSet srs;
     const int kQueryId(0);
     const int kSubjectId(1);
-    const TSeqPos kSeqLength(129189614);
+    const TSeqPos kSeqLength(db.GetSeqLength(1));
     const int kPadSize = CSubjectRangesSet::kHspExpandSize;
     TSeqRange range1(500, 2000), range2(10000, 12000), range3(130000, 400000);
     TSeqRange range4(kSeqLength - kPadSize - 10, kSeqLength - kPadSize - 1);
diff --git a/c++/src/algo/blast/unit_tests/api/traceback_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/traceback_unit_test.cpp
index 025ece1a..0efacb11 100644
--- a/c++/src/algo/blast/unit_tests/api/traceback_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/traceback_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: traceback_unit_test.cpp 516338 2016-10-12 17:32:04Z ivanov $
+/*  $Id: traceback_unit_test.cpp 516161 2016-10-11 12:49:44Z madden $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
diff --git a/c++/src/algo/blast/unit_tests/api/tracebacksearch_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/tracebacksearch_unit_test.cpp
index 7dc6ed21..914c04e9 100644
--- a/c++/src/algo/blast/unit_tests/api/tracebacksearch_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/tracebacksearch_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: tracebacksearch_unit_test.cpp 520431 2016-11-28 18:26:12Z ivanov $
+/*  $Id: tracebacksearch_unit_test.cpp 531968 2017-03-30 17:34:38Z grichenk $
  * ===========================================================================
  *
  *                            PUBLIC DOMAIN NOTICE
@@ -415,7 +415,12 @@ BOOST_AUTO_TEST_CASE(TracebackEntrez) {
     x_FindUsedGis(*rset[0].GetSeqAlign(), use_these);
     
     BOOST_REQUIRE_EQUAL((int)use_these.size(), 1);
-    BOOST_REQUIRE(*(use_these.begin()) == "gi:158292535");
+    if ( !CSeq_id::PreferAccessionOverGi() ) {
+        BOOST_REQUIRE(*(use_these.begin()) == "gi:158292535");
+    }
+    else {
+        BOOST_REQUIRE(*(use_these.begin()) == "seqid:XP_558472.3");
+    }
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/c++/src/algo/blast/unit_tests/api/version_reference_unit_test.cpp b/c++/src/algo/blast/unit_tests/api/version_reference_unit_test.cpp
index f4f29d60..ae27136e 100644
--- a/c++/src/algo/blast/unit_tests/api/version_reference_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/api/version_reference_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: version_reference_unit_test.cpp 521263 2016-12-07 15:18:43Z ivanov $
+/*  $Id: version_reference_unit_test.cpp 548814 2017-10-18 14:11:31Z ivanov $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
@@ -43,8 +43,8 @@ BOOST_AUTO_TEST_SUITE(version_reference)
 
 BOOST_AUTO_TEST_CASE(testVersion) {
     const int kMajor = 2;
-    const int kMinor = 6;
-    const int kPatch = 0;
+    const int kMinor = 7;
+    const int kPatch = 1;
     blast::CBlastVersion v;
     BOOST_REQUIRE_EQUAL(kMajor, v.GetMajor());
     BOOST_REQUIRE_EQUAL(kMinor, v.GetMinor());
diff --git a/c++/src/algo/blast/unit_tests/blast_format/CMakeLists.blast_format_unit_test.app.txt b/c++/src/algo/blast/unit_tests/blast_format/CMakeLists.blast_format_unit_test.app.txt
new file mode 100644
index 00000000..028cb7ef
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/blast_format/CMakeLists.blast_format_unit_test.app.txt
@@ -0,0 +1,16 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/blast_format/Makefile.blast_format_unit_test.app
+#
+add_executable(blast_format_unit_test-app
+    seqalignfilter_unit_test blastfmtutil_unit_test build_archive_unit_test
+    vecscreen_run_unit_test
+)
+
+set_target_properties(blast_format_unit_test-app PROPERTIES OUTPUT_NAME blast_format_unit_test)
+
+
+
+target_link_libraries(blast_format_unit_test-app
+    blastinput test_boost xblastformat
+)
+
diff --git a/c++/src/algo/blast/unit_tests/blast_format/CMakeLists.txt b/c++/src/algo/blast/unit_tests/blast_format/CMakeLists.txt
new file mode 100644
index 00000000..f221d480
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/blast_format/CMakeLists.txt
@@ -0,0 +1,9 @@
+##############################################################################
+# 
+#
+
+include_directories(SYSTEM ${BOOST_INCLUDE})
+
+# Include projects from this directory
+include(CMakeLists.blast_format_unit_test.app.txt)
+
diff --git a/c++/src/algo/blast/unit_tests/blast_format/Makefile.blast_format_unit_test.app b/c++/src/algo/blast/unit_tests/blast_format/Makefile.blast_format_unit_test.app
index 4927ae82..af050af2 100644
--- a/c++/src/algo/blast/unit_tests/blast_format/Makefile.blast_format_unit_test.app
+++ b/c++/src/algo/blast/unit_tests/blast_format/Makefile.blast_format_unit_test.app
@@ -1,7 +1,7 @@
-# $Id: Makefile.blast_format_unit_test.app 500512 2016-05-05 13:14:49Z gouriano $
+# $Id: Makefile.blast_format_unit_test.app 528464 2017-02-23 14:10:40Z madden $
 
 APP = blast_format_unit_test
-SRC = seqalignfilter_unit_test blastfmtutil_unit_test build_archive_unit_test vecscreen_run_unit_test
+SRC = seqalignfilter_unit_test blastfmtutil_unit_test build_archive_unit_test vecscreen_run_unit_test blast_format_unit_test
 
 CPPFLAGS = -DNCBI_MODULE=BLASTFORMAT $(ORIG_CPPFLAGS) $(BOOST_INCLUDE)
 CXXFLAGS = $(FAST_CXXFLAGS) 
diff --git a/c++/src/algo/blast/unit_tests/blast_format/blast_format_unit_test.cpp b/c++/src/algo/blast/unit_tests/blast_format/blast_format_unit_test.cpp
new file mode 100644
index 00000000..b6c8822d
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/blast_format/blast_format_unit_test.cpp
@@ -0,0 +1,198 @@
+/*  $Id: blast_format_unit_test.cpp 536697 2017-05-22 18:43:51Z madden $
+* ===========================================================================
+*
+*                            PUBLIC DOMAIN NOTICE
+*               National Center for Biotechnology Information
+*
+*  This software/database is a "United States Government Work" under the
+*  terms of the United States Copyright Act.  It was written as part of
+*  the author's official duties as a United States Government employee and
+*  thus cannot be copyrighted.  This software/database is freely available
+*  to the public for use. The National Library of Medicine and the U.S.
+*  Government have not placed any restriction on its use or reproduction.
+*
+*  Although all reasonable efforts have been taken to ensure the accuracy
+*  and reliability of the software and data, the NLM and the U.S.
+*  Government do not and cannot warrant the performance or results that
+*  may be obtained by using this software or data. The NLM and the U.S.
+*  Government disclaim all warranties, express or implied, including
+*  warranties of performance, merchantability or fitness for any particular
+*  purpose.
+*
+*  Please cite the author in any work or product based on this material.
+*
+* ===========================================================================
+*
+* Author:  Tom Madden
+*
+* File Description:
+*   Unit test module for CBlastFormat and associated classes.
+*
+* ===========================================================================
+*/
+
+#include 
+#include 
+#include 
+#include 
+
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+
+#include 
+
+#define NCBI_BOOST_NO_AUTO_TEST_MAIN
+#include 
+#include 
+#include 
+
+
+using namespace ncbi;
+using namespace ncbi::blast;
+using namespace ncbi::objects;
+
+
+BOOST_AUTO_TEST_SUITE(blast_format)
+
+BOOST_AUTO_TEST_CASE(BlastFormatTest)
+{
+    // First read in the data to use.
+    const char* fname = "data/archive.asn";
+    ifstream in(fname);
+    CRemoteBlast rb(in);
+
+    rb.LoadFromArchive();
+
+    CRef queries = rb.GetQueries();
+ 
+    CConstRef bss_ref(&(queries->SetBioseq_set()));
+    CRef query_factory(new CObjMgrFree_QueryFactory(bss_ref));
+    const CBioseq& bs = bss_ref->GetSeq_set().front()->GetSeq();
+
+    CBlastNucleotideOptionsHandle nucl_opts(CBlastOptions::eBoth);
+
+    const bool kIsProtein = false;
+    SDataLoaderConfig dlconfig("refseq_rna", kIsProtein);
+    CRef scope(CBlastScopeSource(dlconfig).NewScope());
+    scope->AddBioseq(bs);
+    CRef target_db( new CSearchDatabase("refseq_rna", CSearchDatabase::eBlastDbIsNucleotide));
+    CRef db_adapter(new CLocalDbAdapter(*target_db));
+    CRef loc(new CSeq_loc);
+    CRef id(new CSeq_id);
+    id->Assign(*(bs.GetFirstId()));
+    loc->SetWhole(*id);
+    CRef query(new CBlastSearchQuery(*loc, *scope));
+    CRef q_vec(new CBlastQueryVector);
+    q_vec->push_back(query);
+    CRef blast_results = rb.GetResultSet();
+
+    
+    CNcbiOstrstream streamBuffer;
+    CBlastFormat formatter(nucl_opts.GetOptions(), *db_adapter,
+                          ncbi::blast::CFormattingArgs::EOutputFormat::ePairwise, 
+			  false, streamBuffer, 10, 10, *scope);
+
+    BOOST_REQUIRE(formatter.GetDbTotalLength() > 0);
+
+    formatter.PrintOneResultSet((*blast_results)[0], q_vec);
+    string myReport = CNcbiOstrstreamToString(streamBuffer);
+
+    BOOST_REQUIRE(myReport.length() > 0);
+    BOOST_REQUIRE(myReport.find("Query=") != std::string::npos);
+}
+
+#ifdef NCBI_THREADS
+BOOST_AUTO_TEST_CASE(BlastAsyncFormatTest)
+{
+    // First read in the data to use.
+    const char* fname = "data/archive.asn";
+    ifstream in(fname);
+    CRemoteBlast rb(in);
+
+    rb.LoadFromArchive();
+
+    CRef queries = rb.GetQueries();
+ 
+    CConstRef bss_ref(&(queries->SetBioseq_set()));
+    CRef query_factory(new CObjMgrFree_QueryFactory(bss_ref));
+    const CBioseq& bs = bss_ref->GetSeq_set().front()->GetSeq();
+
+    CBlastNucleotideOptionsHandle nucl_opts(CBlastOptions::eBoth);
+
+    const bool kIsProtein = false;
+    SDataLoaderConfig dlconfig("refseq_rna", kIsProtein);
+    CRef scope(CBlastScopeSource(dlconfig).NewScope());
+    scope->AddBioseq(bs);
+    CRef target_db( new CSearchDatabase("refseq_rna", CSearchDatabase::eBlastDbIsNucleotide));
+    CRef db_adapter(new CLocalDbAdapter(*target_db));
+    CRef loc(new CSeq_loc);
+    CRef id(new CSeq_id);
+    id->Assign(*(bs.GetFirstId()));
+    loc->SetWhole(*id);
+    CRef query(new CBlastSearchQuery(*loc, *scope));
+    CRef q_vec(new CBlastQueryVector);
+    q_vec->push_back(query);
+    CRef blast_results = rb.GetResultSet();
+
+    CBlastAsyncFormatThread* formatThr = new CBlastAsyncFormatThread();
+    formatThr->Run();
+    
+    CNcbiOstrstream streamBuffer;
+    CRef formatter(new CBlastFormat(nucl_opts.GetOptions(), *db_adapter,
+                          ncbi::blast::CFormattingArgs::EOutputFormat::ePairwise, 
+			  false, streamBuffer, 10, 10, *scope));
+
+    vector results_v;
+    results_v.push_back(SFormatResultValues(q_vec, blast_results, formatter));
+    formatThr->QueueResults(0, results_v);
+    formatThr->Join();
+    
+    string myReport = CNcbiOstrstreamToString(streamBuffer);
+
+    BOOST_REQUIRE(myReport.length() > 0);
+    BOOST_REQUIRE(myReport.find("Query=") != std::string::npos);
+}
+
+// Insert results after call to Finalize.
+BOOST_AUTO_TEST_CASE(BlastAsyncFormatFinalizeThrow)
+{
+    CBlastAsyncFormatThread* formatThr = new CBlastAsyncFormatThread();
+    formatThr->Run();
+    
+    formatThr->Finalize();
+    vector results_v;
+    BOOST_REQUIRE_THROW(formatThr->QueueResults(0, results_v), CException);
+    formatThr->Finalize();
+    formatThr->Join();
+}
+
+// Attempt to insert the same batch number twice.
+BOOST_AUTO_TEST_CASE(BlastAsyncFormatDuplicateThrow)
+{
+    CBlastAsyncFormatThread* formatThr = new CBlastAsyncFormatThread();
+    formatThr->Run();
+    
+    vector results_v;
+    formatThr->QueueResults(0, results_v);
+    BOOST_REQUIRE_THROW(formatThr->QueueResults(0, results_v), CException);
+    formatThr->Finalize();
+    formatThr->Join();
+}
+#endif // NCBI_THREADS
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/c++/src/algo/blast/unit_tests/blast_format/blastfmtutil_unit_test.cpp b/c++/src/algo/blast/unit_tests/blast_format/blastfmtutil_unit_test.cpp
index b8df80b1..e5478ece 100644
--- a/c++/src/algo/blast/unit_tests/blast_format/blastfmtutil_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/blast_format/blastfmtutil_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: blastfmtutil_unit_test.cpp 507726 2016-07-21 14:42:04Z grichenk $
+/*  $Id: blastfmtutil_unit_test.cpp 531968 2017-03-30 17:34:38Z grichenk $
 * ===========================================================================
 *
 *                            PUBLIC DOMAIN NOTICE
@@ -124,15 +124,22 @@ BOOST_AUTO_TEST_CASE(GetBlastDeflineFromBlastDb)
     
     scope->AddDataLoader(name);
     TGi gi = sequence::GetGiForAccession("NM_001256", *scope);
-    CSeq_id id;
-    id.SetGi(gi);
-    const CBioseq_Handle& handle = scope->GetBioseqHandle(id);
+    CBioseq_Handle handle;
+    if ( !CSeq_id::AvoidGi() ) {
+        CSeq_id id;
+        id.SetGi(gi);
+        handle = scope->GetBioseqHandle(id);
+    }
+    else {
+        CSeq_id id("NM_001256");
+        handle = scope->GetBioseqHandle(id);
+    }
     const CRef bdls = CSeqDB::ExtractBlastDefline(handle);
     const list< CRef< CBlast_def_line > >& bdl = bdls->Get();
     ITERATE(list< CRef< CBlast_def_line > >, iter, bdl){
         const CBioseq::TId& cur_id = (*iter)->GetSeqid();
         TGi cur_gi =  FindGi(cur_id);
-        BOOST_REQUIRE (gi==cur_gi);
+        BOOST_REQUIRE (CSeq_id::AvoidGi() || gi==cur_gi);
 
         BOOST_WARN_MESSAGE((*iter)->IsSetLinks(), "Links are not set, test is inactive");
         if ((*iter)->IsSetLinks()){
diff --git a/c++/src/algo/blast/unit_tests/blast_format/data/archive.asn b/c++/src/algo/blast/unit_tests/blast_format/data/archive.asn
index c69abf7b..8ebb600a 100644
--- a/c++/src/algo/blast/unit_tests/blast_format/data/archive.asn
+++ b/c++/src/algo/blast/unit_tests/blast_format/data/archive.asn
@@ -1,99 +1,133 @@
 Blast4-archive ::= {
   request {
-  ident "tom",
-  body queue-search {
-    program "blastn",
-    service "megablast",
-    queries bioseq-set {
-      seq-set {
-        seq {
-          id {
-            local id 1
-          },
-          descr {
-            title "gi|18860846|ref|NM_130799.1| Homo sapiens multiple
- endocrine neoplasia I (MEN1), transcript variant 2, mRNA
- >gi|1945386|gb|U93236.1|HSU93236 Human menin (MEN1) mRNA, complete cds",
-            user {
-              type str "CFastaReader",
-              data {
-                {
-                  label str "DefLine",
-                  data str ">gi|18860846|ref|NM_130799.1| Homo sapiens
- multiple endocrine neoplasia I (MEN1), transcript variant 2, mRNA
- >gi|1945386|gb|U93236.1|HSU93236 Human menin (MEN1) mRNA, complete cds"
+    ident "2.6.0+",
+    body queue-search {
+      program "blastn",
+      service "megablast",
+      queries bioseq-set {
+        seq-set {
+          seq {
+            id {
+              local str "U93236.1"
+            },
+            descr {
+              user {
+                type str "CFastaReader",
+                data {
+                  {
+                    label str "DefLine",
+                    data str ">U93236.1 Human menin (MEN1) mRNA, complete cds"
+                  }
                 }
-              }
+              },
+              title "Human menin (MEN1) mRNA, complete cds"
+            },
+            inst {
+              repr raw,
+              mol na,
+              length 2772,
+              seq-data ncbi2na 'AED6896685C88D520944992695A5651CFD4A779AA4AA59
+6545959653AA78296548219EF56799D4D861BAE65EFE79627A962289685EB9D7F5FAE7A9F6E893
+FDE9ED059B4D5C506F562745F52549565561597A69745C7F56E9617B734D965773959F45952358
+A65B617B57735D882AAEDD496E27AE082B758ED33A049749675C7D0A36A544D4B577D27D344A45
+03E849D6BBA5FE7BAFAA5E5295EADD6A3B517657B78A34E5EACBBFA950EA8921278AD17A4690A9
+0628592A9484B4396BBA789A27A7B1780A34C4E67B85908E8AE9BD3AEEE53415F53E1791161D9E
+89F79279248279DE9E77385EA137A02B154E97CA817A48DC8A27A25455E9694854745771442A4F
+974942171CDA8E044DC55C4EC5E9E9C51ED90590EE6A095E4A5EA6846947B4D4A1C41C796A0862
+88DC428BDFE0B250E3B4D54179E0A292527E7A29A98A2696AA24094A9152250AF595D4A15E2E7D
+95179E63DC61A4DE40EA28A92D5197B9E46EA7A945FDFB92D5CA5BFE2A12B9A482B9932E2588A5
+8A6962962896EA98A095A82969A6A951A6A2D4252289559654209491E842A5EA45A52AE4BB4A15
+55A0975EA1ED9E91256295E0AE92469D2B94915924D145968AB52E747F522E208E0A938289E7AE
+94508D076265342790746912D90B9238209202ED455CB8711DEDFD742692640A5DE071EA87DA16
+7EEA854A7597CB5541DE254EF79552540AA129745DC540572BD5AD58B12DECD01518FF75274815
+2A77954B6F20CCADDF754835496943A017467AB5C3C52DFC0A54957201509D75DA059D17225214
+1BC74A9D7549FB289E2BF457C150A8912B545D495AA25CA147495728B33F591F483D4CDF983509
+D5E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A3489
+285D5F58577A817548AD495376893568A037922ABCA2EAE108978DDF5EFFB1323F3FF4BD420238
+313FEF00000000'H
             }
-          },
-          inst {
-            repr raw,
-            mol na,
-            length 2772,
-            seq-data ncbi2na 'AED6896685C88D520944992695A5651CFD4A779AA4AA5965
-45959653AA78296548219EF56799D4D861BAE65EFE79627A962289685EB9D7F5FAE7A9F6E893FD
-E9ED059B4D5C506F562745F52549565561597A69745C7F56E9617B734D965773959F45952358A6
-5B617B57735D882AAEDD496E27AE082B758ED33A049749675C7D0A36A544D4B577D27D344A4503
-E849D6BBA5FE7BAFAA5E5295EADD6A3B517657B78A34E5EACBBFA950EA8921278AD17A4690A906
-28592A9484B4396BBA789A27A7B1780A34C4E67B85908E8AE9BD3AEEE53415F53E1791161D9E89
-F79279248279DE9E77385EA137A02B154E97CA817A48DC8A27A25455E9694854745771442A4F97
-4942171CDA8E044DC55C4EC5E9E9C51ED90590EE6A095E4A5EA6846947B4D4A1C41C796A086288
-DC428BDFE0B250E3B4D54179E0A292527E7A29A98A2696AA24094A9152250AF595D4A15E2E7D95
-179E63DC61A4DE40EA28A92D5197B9E46EA7A945FDFB92D5CA5BFE2A12B9A482B9932E2588A58A
-6962962896EA98A095A82969A6A951A6A2D4252289559654209491E842A5EA45A52AE4BB4A1555
-A0975EA1ED9E91256295E0AE92469D2B94915924D145968AB52E747F522E208E0A938289E7AE94
-508D076265342790746912D90B9238209202ED455CB8711DEDFD742692640A5DE071EA87DA167E
-EA854A7597CB5541DE254EF79552540AA129745DC540572BD5AD58B12DECD01518FF752748152A
-77954B6F20CCADDF754835496943A017467AB5C3C52DFC0A54957201509D75DA059D172252141B
-C74A9D7549FB289E2BF457C150A8912B545D495AA25CA147495728B33F591F483D4CDF983509D5
-E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
-5D5F58577A817548AD495376893568A037922ABCA2EAE108978DDF5EFFB1323F3FF4BD42023831
-3FEF00000000'H
           }
         }
-      }
-    },
-    subject database "refseq_rna",
-    algorithm-options {
-      {
-        name "EvalueThreshold",
-        value cutoff e-value { 1, 10, 1 }
-      },
-      {
-        name "MaskAtHash",
-        value boolean TRUE
-      },
-      {
-        name "DustFilteringLevel",
-        value integer 20
-      },
-      {
-        name "DustFilteringWindow",
-        value integer 64
-      },
-      {
-        name "DustFilteringLinker",
-        value integer 1
-      },
-      {
-        name "UngappedMode",
-        value boolean FALSE
-      },
-      {
-        name "ForceMbIndex",
-        value boolean FALSE
       },
-      {
-        name "MbIndexName",
-        value string "refseq_rna"
+      subject database "refseq_rna",
+      algorithm-options {
+        {
+          name "EvalueThreshold",
+          value cutoff e-value { 1, 10, 1 }
+        },
+        {
+          name "MaskAtHash",
+          value boolean TRUE
+        },
+        {
+          name "DustFilteringLevel",
+          value integer 20
+        },
+        {
+          name "DustFilteringWindow",
+          value integer 64
+        },
+        {
+          name "DustFilteringLinker",
+          value integer 1
+        },
+        {
+          name "UngappedMode",
+          value boolean FALSE
+        },
+        {
+          name "HitlistSize",
+          value integer 10
+        },
+        {
+          name "EffectiveSearchSpace",
+          value big-integer 113759551572226
+        }
       },
-      {
-        name "HitlistSize",
-        value integer 500
+      program-options {
+        {
+          name "LCaseMask",
+          value query-mask {
+            locations {
+              packed-int {
+                {
+                  from 1483,
+                  to 1555,
+                  id local str "U93236.1"
+                },
+                {
+                  from 1483,
+                  to 1555,
+                  id local str "U93236.1"
+                },
+                {
+                  from 1649,
+                  to 1655,
+                  id local str "U93236.1"
+                },
+                {
+                  from 1649,
+                  to 1655,
+                  id local str "U93236.1"
+                },
+                {
+                  from 2756,
+                  to 2771,
+                  id local str "U93236.1"
+                },
+                {
+                  from 2756,
+                  to 2771,
+                  id local str "U93236.1"
+                }
+              }
+            },
+            frame plus1
+          }
+        }
       }
     }
-  }
-},
+  },
   results {
     alignments {
       {
@@ -102,7 +136,11 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
         score {
           {
             id str "score",
-            value int 256
+            value int 2750
+          },
+          {
+            id str "blast_score",
+            value int 2750
           },
           {
             id str "e_value",
@@ -110,52 +148,66 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
           },
           {
             id str "bit_score",
-            value real { 473223670352335, 10, -11 }
+            value real { 507940683816287, 10, -11 }
           },
           {
             id str "num_ident",
-            value int 2577
+            value int 2767
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 1, 10, 2 }
           }
         },
         segs denseg {
           dim 2,
-          numseg 9,
+          numseg 13,
           ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 167466174
+            local str "U93236.1",
+            gi 210031700
           },
           starts {
-            6,
-            75,
+            0,
+            0,
+            -1,
+            1985,
+            1985,
+            1986,
+            2332,
+            -1,
+            2333,
+            2333,
+            2358,
             -1,
-            1505,
-            1436,
-            1507,
+            2359,
+            2358,
+            2460,
             -1,
-            1508,
-            1437,
-            1509,
+            2461,
+            2459,
+            2665,
             -1,
-            2269,
-            2197,
-            2270,
-            2198,
+            2666,
+            2663,
             -1,
-            2199,
-            2271
+            2761,
+            2764,
+            2762
           },
           lens {
-            1430,
-            2,
+            1985,
             1,
+            347,
             1,
-            760,
+            25,
             1,
+            101,
             1,
+            204,
             1,
-            386
+            98,
+            1,
+            8
           },
           strands {
             plus,
@@ -175,6 +227,14 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
             plus,
             plus,
             plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
             plus
           }
         }
@@ -185,7 +245,11 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
         score {
           {
             id str "score",
-            value int 2517
+            value int 2655
+          },
+          {
+            id str "blast_score",
+            value int 2655
           },
           {
             id str "e_value",
@@ -193,70 +257,60 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
           },
           {
             id str "bit_score",
-            value real { 464913746916814, 10, -11 }
+            value real { 490397512119077, 10, -11 }
           },
           {
             id str "num_ident",
-            value int 2577
+            value int 2672
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 971089466089466, 10, -13 }
           }
         },
         segs denseg {
           dim 2,
-          numseg 15,
+          numseg 11,
           ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 167466176
+            local str "U93236.1",
+            gi 1034573766
           },
           starts {
-            6,
-            75,
+            86,
+            167,
             -1,
-            1077,
-            1008,
-            1080,
+            2066,
+            1985,
+            2067,
+            2332,
             -1,
-            1083,
-            1011,
-            1084,
+            2333,
+            2414,
+            2358,
             -1,
-            1085,
-            1012,
-            1098,
+            2359,
+            2439,
+            2460,
             -1,
-            1099,
-            1013,
-            1100,
+            2461,
+            2540,
+            2665,
             -1,
-            1521,
-            1434,
-            1524,
-            -1,
-            2287,
-            2197,
-            2288,
-            2198,
-            -1,
-            2199,
-            2289
+            2666,
+            2744
           },
           lens {
-            1002,
-            3,
-            3,
-            1,
-            1,
-            13,
+            1899,
             1,
+            347,
             1,
-            421,
-            3,
-            763,
+            25,
             1,
+            101,
             1,
+            204,
             1,
-            386
+            98
           },
           strands {
             plus,
@@ -280,13 +334,54 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
             plus,
             plus,
             plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
+            plus
+          }
+        }
+      },
+      {
+        type partial,
+        dim 2,
+        score {
+          {
+            id str "score",
+            value int 50
+          },
+          {
+            id str "blast_score",
+            value int 50
+          },
+          {
+            id str "e_value",
+            value real { 839264515491141, 10, -29 }
+          },
+          {
+            id str "bit_score",
+            value real { 934527768506114, 10, -13 }
+          },
+          {
+            id str "num_ident",
+            value int 52
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 241197691197691, 10, -14 }
+          }
+        },
+        segs denseg {
+          dim 2,
+          numseg 1,
+          ids {
+            local str "U93236.1",
+            gi 1034573766
+          },
+          starts {
+            35,
+            0
+          },
+          lens {
+            53
+          },
+          strands {
             plus,
             plus
           }
@@ -298,7 +393,11 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
         score {
           {
             id str "score",
-            value int 1694
+            value int 2655
+          },
+          {
+            id str "blast_score",
+            value int 2655
           },
           {
             id str "e_value",
@@ -306,94 +405,60 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
           },
           {
             id str "bit_score",
-            value real { 312934480529408, 10, -11 }
+            value real { 490397512119077, 10, -11 }
           },
           {
             id str "num_ident",
-            value int 1876
+            value int 2672
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 971089466089466, 10, -13 }
           }
         },
         segs denseg {
           dim 2,
-          numseg 23,
+          numseg 11,
           ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514673
+            local str "U93236.1",
+            gi 1034573765
           },
           starts {
-            14,
-            22767378,
-            -1,
-            22767384,
-            20,
-            22767385,
-            1188,
-            -1,
-            1191,
-            22768553,
-            1202,
-            -1,
-            1204,
-            22768564,
-            -1,
-            22768796,
-            1436,
-            22768798,
-            -1,
-            22768800,
-            1438,
-            22768801,
-            -1,
-            22769114,
-            1751,
-            22769115,
-            1752,
+            86,
+            468,
             -1,
-            1753,
-            22769116,
-            1780,
+            2367,
+            1985,
+            2368,
+            2332,
             -1,
-            1781,
-            22769143,
+            2333,
+            2715,
+            2358,
             -1,
-            22769242,
-            1880,
-            22769243,
-            1881,
+            2359,
+            2740,
+            2460,
             -1,
-            1882,
-            22769244,
-            1899,
+            2461,
+            2841,
+            2665,
             -1,
-            1900,
-            22769261
+            2666,
+            3045
           },
           lens {
-            6,
-            1,
-            1168,
-            3,
-            11,
-            2,
-            232,
-            2,
-            2,
-            1,
-            313,
-            1,
-            1,
-            1,
-            27,
+            1899,
             1,
-            99,
+            347,
             1,
+            25,
             1,
+            101,
             1,
-            17,
+            204,
             1,
-            71
+            98
           },
           strands {
             plus,
@@ -417,29 +482,54 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
             plus,
             plus,
             plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
+            plus
+          }
+        }
+      },
+      {
+        type partial,
+        dim 2,
+        score {
+          {
+            id str "score",
+            value int 85
+          },
+          {
+            id str "blast_score",
+            value int 85
+          },
+          {
+            id str "e_value",
+            value real { 293431052950854, 10, -48 }
+          },
+          {
+            id str "bit_score",
+            value real { 158085514682437, 10, -12 }
+          },
+          {
+            id str "num_ident",
+            value int 87
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 367460317460317, 10, -14 }
+          }
+        },
+        segs denseg {
+          dim 2,
+          numseg 1,
+          ids {
+            local str "U93236.1",
+            gi 1034573765
+          },
+          starts {
+            0,
+            20
+          },
+          lens {
+            88
+          },
+          strands {
             plus,
             plus
           }
@@ -451,7 +541,11 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
         score {
           {
             id str "score",
-            value int 1694
+            value int 2654
+          },
+          {
+            id str "blast_score",
+            value int 2654
           },
           {
             id str "e_value",
@@ -459,131 +553,83 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
           },
           {
             id str "bit_score",
-            value real { 312934480529408, 10, -11 }
+            value real { 490212847153843, 10, -11 }
           },
           {
             id str "num_ident",
-            value int 1876
+            value int 2671
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 970728715728716, 10, -13 }
           }
         },
         segs denseg {
           dim 2,
-          numseg 21,
+          numseg 11,
           ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157811953
+            local str "U93236.1",
+            gi 1034573768
           },
           starts {
-            1899,
-            16675824,
-            1898,
-            -1,
-            1882,
-            16675896,
-            1881,
-            -1,
-            1880,
-            16675912,
-            -1,
-            16675913,
-            1781,
-            16675914,
-            1780,
-            -1,
-            1753,
-            16676013,
-            1752,
-            -1,
-            1749,
-            16676040,
+            87,
+            71,
             -1,
-            16676043,
-            1434,
-            16676044,
+            1969,
+            1985,
+            1970,
+            2332,
             -1,
-            16676359,
-            1203,
-            16676362,
-            1201,
+            2333,
+            2317,
+            2358,
             -1,
-            1186,
-            16676593,
-            1183,
+            2359,
+            2342,
+            2460,
             -1,
-            20,
-            16676608,
+            2461,
+            2443,
+            2665,
             -1,
-            16677771,
-            14,
-            16677772
+            2666,
+            2647
           },
           lens {
-            72,
-            1,
-            16,
-            1,
-            1,
+            1898,
             1,
-            99,
+            347,
             1,
-            27,
+            25,
             1,
-            3,
+            101,
             1,
-            315,
-            3,
-            231,
-            2,
-            15,
-            3,
-            1163,
+            204,
             1,
-            6
+            98
           },
           strands {
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
+            plus,
             plus
           }
         }
@@ -594,7 +640,11 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
         score {
           {
             id str "score",
-            value int 1691
+            value int 2614
+          },
+          {
+            id str "blast_score",
+            value int 2614
           },
           {
             id str "e_value",
@@ -602,181 +652,93 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
           },
           {
             id str "bit_score",
-            value real { 312380485633706, 10, -11 }
+            value real { 482826248544492, 10, -11 }
           },
           {
             id str "num_ident",
-            value int 1877
+            value int 2659
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 971089466089466, 10, -13 }
           }
         },
         segs denseg {
           dim 2,
-          numseg 31,
+          numseg 13,
           ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157698039
+            local str "U93236.1",
+            gi 1034089344
           },
           starts {
-            1882,
-            408254,
-            1881,
-            -1,
-            1880,
-            408343,
-            -1,
-            408344,
-            1868,
-            408345,
-            -1,
-            408357,
-            1753,
-            408358,
-            1752,
-            -1,
-            1751,
-            408473,
-            -1,
-            408474,
-            1465,
-            408475,
-            -1,
-            408761,
-            1460,
-            408762,
-            1459,
+            86,
+            167,
             -1,
-            1438,
-            408767,
+            2066,
+            1985,
+            2067,
             -1,
-            408788,
-            1436,
-            408789,
+            2161,
+            2079,
+            2162,
+            2332,
             -1,
-            408791,
-            1233,
-            408793,
-            1232,
+            2333,
+            2415,
+            2358,
             -1,
-            1231,
-            408996,
-            1230,
+            2359,
+            2440,
+            2460,
             -1,
-            1229,
-            408997,
-            1228,
+            2461,
+            2541,
+            2665,
             -1,
-            614,
-            408998,
-            -1,
-            409612,
-            612,
-            409613,
-            611,
-            -1,
-            20,
-            409615,
-            -1,
-            410206,
-            14,
-            410207
+            2666,
+            2745
           },
           lens {
-            89,
-            1,
-            1,
-            1,
-            12,
-            1,
-            115,
-            1,
-            1,
-            1,
-            286,
-            1,
-            5,
-            1,
-            21,
-            1,
-            2,
-            2,
-            203,
-            1,
-            1,
+            1899,
             1,
+            94,
             1,
+            253,
             1,
-            614,
+            25,
             1,
-            2,
+            101,
             1,
-            591,
+            204,
             1,
-            6
+            98
           },
           strands {
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
             plus
           }
         }
@@ -787,144 +749,129 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
         score {
           {
             id str "score",
-            value int 1679
+            value int 50
+          },
+          {
+            id str "blast_score",
+            value int 50
           },
           {
             id str "e_value",
-            value real { 0, 10, 0 }
+            value real { 839264515491141, 10, -29 }
           },
           {
             id str "bit_score",
-            value real { 310164506050901, 10, -11 }
+            value real { 934527768506114, 10, -13 }
           },
           {
             id str "num_ident",
-            value int 1872
+            value int 52
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 241197691197691, 10, -14 }
           }
         },
         segs denseg {
           dim 2,
-          numseg 27,
+          numseg 1,
           ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157702221
+            local str "U93236.1",
+            gi 1034089344
           },
           starts {
-            14,
-            542489,
-            -1,
-            542495,
-            20,
-            542497,
-            326,
-            -1,
-            327,
-            542803,
-            -1,
-            543132,
-            656,
-            543133,
-            658,
-            -1,
-            659,
-            543135,
-            771,
-            -1,
-            772,
-            543247,
-            -1,
-            543692,
-            1217,
-            543693,
-            1219,
-            -1,
-            1220,
-            543695,
+            35,
+            0
+          },
+          lens {
+            53
+          },
+          strands {
+            plus,
+            plus
+          }
+        }
+      },
+      {
+        type partial,
+        dim 2,
+        score {
+          {
+            id str "score",
+            value int 2614
+          },
+          {
+            id str "blast_score",
+            value int 2614
+          },
+          {
+            id str "e_value",
+            value real { 0, 10, 0 }
+          },
+          {
+            id str "bit_score",
+            value real { 482826248544492, 10, -11 }
+          },
+          {
+            id str "num_ident",
+            value int 2659
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 971089466089466, 10, -13 }
+          }
+        },
+        segs denseg {
+          dim 2,
+          numseg 13,
+          ids {
+            local str "U93236.1",
+            gi 1034089343
+          },
+          starts {
+            86,
+            391,
             -1,
-            543893,
-            1418,
-            543894,
+            2290,
+            1985,
+            2291,
             -1,
-            543901,
-            1425,
-            543902,
-            1460,
+            2385,
+            2079,
+            2386,
+            2332,
             -1,
-            1461,
-            543937,
+            2333,
+            2639,
+            2358,
             -1,
-            543940,
-            1464,
-            543941,
+            2359,
+            2664,
+            2460,
             -1,
-            544357,
-            1880,
-            544358,
-            1881,
+            2461,
+            2765,
+            2665,
             -1,
-            1882,
-            544359
+            2666,
+            2969
           },
           lens {
-            6,
-            2,
-            306,
-            1,
-            329,
-            1,
-            2,
-            1,
-            112,
-            1,
-            445,
-            1,
-            2,
-            1,
-            198,
-            1,
-            7,
+            1899,
             1,
-            35,
+            94,
             1,
-            3,
+            253,
             1,
-            416,
+            25,
             1,
+            101,
             1,
+            204,
             1,
-            89
+            98
           },
           strands {
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
             plus,
             plus,
             plus,
@@ -960,7 +907,11 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
         score {
           {
             id str "score",
-            value int 1665
+            value int 2613
+          },
+          {
+            id str "blast_score",
+            value int 2613
           },
           {
             id str "e_value",
@@ -968,111 +919,93 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
           },
           {
             id str "bit_score",
-            value real { 307579196537628, 10, -11 }
+            value real { 482641583579258, 10, -11 }
           },
           {
             id str "num_ident",
-            value int 1867
+            value int 2658
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 970728715728716, 10, -13 }
           }
         },
         segs denseg {
           dim 2,
-          numseg 17,
+          numseg 13,
           ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157698078
+            local str "U93236.1",
+            gi 1034089345
           },
           starts {
-            1434,
-            112799,
+            87,
+            133,
             -1,
-            113336,
-            1253,
-            113339,
+            2031,
+            1985,
+            2032,
             -1,
-            113520,
-            1252,
-            113521,
-            1251,
+            2126,
+            2079,
+            2127,
+            2332,
             -1,
-            659,
-            113522,
-            658,
+            2333,
+            2380,
+            2358,
             -1,
-            656,
-            114114,
+            2359,
+            2405,
+            2460,
             -1,
-            114116,
-            614,
-            114117,
+            2461,
+            2506,
+            2665,
             -1,
-            114159,
-            612,
-            114160,
-            611,
-            -1,
-            20,
-            114162,
-            -1,
-            114753,
-            14,
-            114755
+            2666,
+            2710
           },
           lens {
-            537,
-            3,
-            181,
-            1,
+            1898,
             1,
+            94,
             1,
-            592,
+            253,
             1,
-            2,
+            25,
             1,
-            42,
+            101,
             1,
-            2,
+            204,
             1,
-            591,
-            2,
-            6
+            98
           },
           strands {
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
             plus
           }
         }
@@ -1083,7 +1016,11 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
         score {
           {
             id str "score",
-            value int 1663
+            value int 2611
+          },
+          {
+            id str "blast_score",
+            value int 2611
           },
           {
             id str "e_value",
@@ -1091,151 +1028,93 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
           },
           {
             id str "bit_score",
-            value real { 30720986660716, 10, -10 }
+            value real { 482272253648791, 10, -11 }
           },
           {
             id str "num_ident",
-            value int 1868
+            value int 2658
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 971089466089466, 10, -13 }
           }
         },
         segs denseg {
           dim 2,
-          numseg 25,
+          numseg 13,
           ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157701491
+            local str "U93236.1",
+            gi 675790374
           },
           starts {
-            1882,
-            25150,
-            1881,
-            -1,
-            1880,
-            25239,
-            -1,
-            25240,
-            1468,
-            25241,
+            86,
+            172,
             -1,
-            25653,
-            1461,
-            25654,
-            1460,
+            2071,
+            1985,
+            2072,
             -1,
-            1438,
-            25661,
+            2166,
+            2079,
+            2167,
+            2332,
             -1,
-            25683,
-            1436,
-            25684,
+            2333,
+            2420,
+            2358,
             -1,
-            25686,
-            1419,
-            25688,
-            1418,
+            2359,
+            2445,
+            2462,
             -1,
-            750,
-            25705,
+            2463,
+            2548,
+            2665,
             -1,
-            26373,
-            749,
-            26374,
-            748,
-            -1,
-            551,
-            26375,
-            -1,
-            26572,
-            20,
-            26574,
-            -1,
-            27105,
-            19,
-            27106,
-            -1,
-            27107,
-            14,
-            27108
+            2666,
+            2750
           },
           lens {
-            89,
-            1,
-            1,
-            1,
-            412,
-            1,
-            7,
-            1,
-            22,
-            1,
-            2,
-            2,
-            17,
-            1,
-            668,
+            1899,
             1,
+            94,
             1,
+            253,
             1,
-            197,
-            2,
-            531,
+            25,
             1,
+            103,
             1,
+            202,
             1,
-            5
+            98
           },
           strands {
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
+            plus,
             plus
           }
         }
@@ -1246,89 +1125,45 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
         score {
           {
             id str "score",
-            value int 1654
+            value int 55
+          },
+          {
+            id str "blast_score",
+            value int 55
           },
           {
             id str "e_value",
-            value real { 0, 10, 0 }
+            value real { 13944860598311, 10, -30 }
           },
           {
             id str "bit_score",
-            value real { 305547881920056, 10, -11 }
+            value real { 102686025112301, 10, -12 }
           },
           {
             id str "num_ident",
-            value int 1860
+            value int 57
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 259235209235209, 10, -14 }
           }
         },
         segs denseg {
           dim 2,
-          numseg 11,
+          numseg 1,
           ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514650
+            local str "U93236.1",
+            gi 675790374
           },
           starts {
-            1650,
-            12456,
-            1648,
-            -1,
-            1461,
-            12777,
-            1460,
-            -1,
-            1437,
-            12964,
-            -1,
-            12987,
-            1436,
-            12988,
-            -1,
-            12989,
-            20,
-            12991,
-            -1,
-            14407,
-            14,
-            14408
+            30,
+            0
           },
           lens {
-            321,
-            2,
-            187,
-            1,
-            23,
-            1,
-            1,
-            2,
-            1416,
-            1,
-            6
+            58
           },
           strands {
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
             plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
             plus
           }
         }
@@ -1339,7 +1174,11 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
         score {
           {
             id str "score",
-            value int 1654
+            value int 2611
+          },
+          {
+            id str "blast_score",
+            value int 2611
           },
           {
             id str "e_value",
@@ -1347,81 +1186,142 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
           },
           {
             id str "bit_score",
-            value real { 305547881920056, 10, -11 }
+            value real { 482272253648791, 10, -11 }
           },
           {
             id str "num_ident",
-            value int 1860
+            value int 2658
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 971089466089466, 10, -13 }
           }
         },
         segs denseg {
           dim 2,
-          numseg 11,
+          numseg 13,
           ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157703081
+            local str "U93236.1",
+            gi 675790372
           },
           starts {
-            1650,
-            941,
-            1648,
+            86,
+            473,
+            -1,
+            2372,
+            1985,
+            2373,
             -1,
-            1461,
-            1262,
-            1460,
+            2467,
+            2079,
+            2468,
+            2332,
             -1,
-            1437,
-            1449,
+            2333,
+            2721,
+            2358,
             -1,
-            1472,
-            1436,
-            1473,
+            2359,
+            2746,
+            2462,
             -1,
-            1474,
-            20,
-            1476,
+            2463,
+            2849,
+            2665,
             -1,
-            2892,
-            14,
-            2893
+            2666,
+            3051
           },
           lens {
-            321,
-            2,
-            187,
+            1899,
+            1,
+            94,
             1,
-            23,
+            253,
             1,
+            25,
             1,
-            2,
-            1416,
+            103,
             1,
-            6
+            202,
+            1,
+            98
           },
           strands {
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
             plus,
-            minus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus,
+            plus
+          }
+        }
+      },
+      {
+        type partial,
+        dim 2,
+        score {
+          {
+            id str "score",
+            value int 80
+          },
+          {
+            id str "blast_score",
+            value int 80
+          },
+          {
+            id str "e_value",
+            value real { 17660002317605, 10, -44 }
+          },
+          {
+            id str "bit_score",
+            value real { 148852266420748, 10, -12 }
+          },
+          {
+            id str "num_ident",
+            value int 82
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 349422799422799, 10, -14 }
+          }
+        },
+        segs denseg {
+          dim 2,
+          numseg 1,
+          ids {
+            local str "U93236.1",
+            gi 675790372
+          },
+          starts {
+            5,
+            30
+          },
+          lens {
+            83
+          },
+          strands {
+            plus,
             plus
           }
         }
@@ -1432,7 +1332,11 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
         score {
           {
             id str "score",
-            value int 1609
+            value int 2610
+          },
+          {
+            id str "blast_score",
+            value int 2610
           },
           {
             id str "e_value",
@@ -1440,124 +1344,66 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
           },
           {
             id str "bit_score",
-            value real { 297237958484536, 10, -11 }
+            value real { 482087588683557, 10, -11 }
           },
           {
             id str "num_ident",
-            value int 1848
+            value int 2657
+          },
+          {
+            id str "hsp_percent_coverage",
+            value real { 970728715728716, 10, -13 }
           }
         },
         segs denseg {
           dim 2,
-          numseg 33,
+          numseg 13,
           ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157702226
+            local str "U93236.1",
+            gi 675790376
           },
           starts {
-            14,
-            224013,
-            -1,
-            224019,
-            20,
-            224020,
-            181,
-            -1,
-            182,
-            224181,
-            668,
-            -1,
-            669,
-            224667,
-            671,
-            -1,
-            672,
-            224669,
-            673,
-            -1,
-            676,
-            224670,
-            677,
-            -1,
-            680,
-            224671,
-            681,
-            -1,
-            682,
-            224672,
-            684,
-            -1,
-            687,
-            224674,
-            771,
-            -1,
-            772,
-            224758,
-            -1,
-            225404,
-            1418,
-            225405,
+            87,
+            84,
             -1,
-            225412,
-            1425,
-            225413,
-            1469,
+            1982,
+            1985,
+            1983,
             -1,
-            1470,
-            225457,
+            2077,
+            2079,
+            2078,
+            2332,
             -1,
-            225737,
-            1750,
-            225738,
-            1751,
+            2333,
+            2331,
+            2358,
             -1,
-            1752,
-            225739,
+            2359,
+            2356,
+            2462,
             -1,
-            225867,
-            1880,
-            225868,
-            1881,
+            2463,
+            2459,
+            2665,
             -1,
-            1882,
-            225869
+            2666,
+            2661
           },
           lens {
-            6,
-            1,
-            161,
-            1,
-            486,
-            1,
-            2,
-            1,
-            1,
-            3,
-            1,
-            3,
-            1,
-            1,
-            2,
-            3,
-            84,
-            1,
-            646,
-            1,
-            7,
-            1,
-            44,
-            1,
-            280,
+            1898,
             1,
+            94,
             1,
+            253,
             1,
-            128,
+            25,
             1,
+            103,
             1,
+            202,
             1,
-            89
+            98
           },
           strands {
             plus,
@@ -1585,2834 +1431,40 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
             plus,
             plus,
             plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 1604
-          },
-          {
-            id str "e_value",
-            value real { 0, 10, 0 }
-          },
-          {
-            id str "bit_score",
-            value real { 296314633658367, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 1839
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 17,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 51477765
-          },
-          starts {
-            1905,
-            736673,
-            1904,
-            -1,
-            1438,
-            736739,
-            -1,
-            737205,
-            1436,
-            737206,
-            -1,
-            737208,
-            1414,
-            737210,
-            1413,
-            -1,
-            1121,
-            737232,
-            -1,
-            737524,
-            1120,
-            737525,
-            1119,
-            -1,
-            1015,
-            737526,
-            1014,
-            -1,
-            512,
-            737630,
-            511,
-            -1,
-            21,
-            738132
-          },
-          lens {
-            66,
-            1,
-            466,
-            1,
-            2,
-            2,
-            22,
-            1,
-            292,
-            1,
-            1,
-            1,
-            104,
-            1,
-            502,
-            1,
-            490
-          },
-          strands {
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 1603
-          },
-          {
-            id str "e_value",
-            value real { 0, 10, 0 }
-          },
-          {
-            id str "bit_score",
-            value real { 296129968693133, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 1847
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 31,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157701949
-          },
-          starts {
-            1882,
-            136558,
-            1881,
-            -1,
-            1880,
-            136647,
-            -1,
-            136648,
-            1495,
-            136649,
-            1494,
-            -1,
-            1492,
-            137034,
-            -1,
-            137036,
-            1438,
-            137037,
-            -1,
-            137091,
-            1436,
-            137092,
-            -1,
-            137094,
-            1233,
-            137096,
-            1232,
-            -1,
-            1231,
-            137299,
-            1230,
-            -1,
-            1229,
-            137300,
-            1228,
-            -1,
-            760,
-            137301,
-            759,
-            -1,
-            758,
-            137769,
-            -1,
-            137770,
-            537,
-            137771,
-            536,
-            -1,
-            203,
-            137992,
-            -1,
-            138325,
-            99,
-            138326,
-            98,
-            -1,
-            20,
-            138430,
-            -1,
-            138508,
-            14,
-            138509
-          },
-          lens {
-            89,
-            1,
-            1,
-            1,
-            385,
-            1,
-            2,
-            1,
-            54,
-            1,
-            2,
-            2,
-            203,
-            1,
-            1,
-            1,
-            1,
-            1,
-            468,
-            1,
-            1,
-            1,
-            221,
-            1,
-            333,
-            1,
-            104,
-            1,
-            78,
-            1,
-            6
-          },
-          strands {
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 1569
-          },
-          {
-            id str "e_value",
-            value real { 0, 10, 0 }
-          },
-          {
-            id str "bit_score",
-            value real { 289851359875184, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 1826
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 19,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157698036
-          },
-          starts {
-            1905,
-            652646,
-            1904,
-            -1,
-            1438,
-            652712,
-            -1,
-            653178,
-            1436,
-            653179,
-            -1,
-            653181,
-            1414,
-            653183,
-            1413,
-            -1,
-            1121,
-            653205,
-            -1,
-            653497,
-            1120,
-            653498,
-            1119,
-            -1,
-            1015,
-            653499,
-            1014,
-            -1,
-            512,
-            653603,
-            511,
-            -1,
-            122,
-            654105,
-            -1,
-            654494,
-            21,
-            654499
-          },
-          lens {
-            66,
-            1,
-            466,
-            1,
-            2,
-            2,
-            22,
-            1,
-            292,
-            1,
-            1,
-            1,
-            104,
-            1,
-            502,
-            1,
-            389,
-            5,
-            101
-          },
-          strands {
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 1397
-          },
-          {
-            id str "e_value",
-            value real { 0, 10, 0 }
-          },
-          {
-            id str "bit_score",
-            value real { 258088985854973, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 1791
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 41,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514641
-          },
-          starts {
-            1872,
-            140145,
-            1871,
-            -1,
-            1868,
-            140244,
-            -1,
-            140247,
-            1760,
-            140248,
-            -1,
-            140356,
-            1759,
-            140357,
-            -1,
-            140358,
-            1757,
-            140359,
-            -1,
-            140361,
-            1617,
-            140363,
-            1616,
-            -1,
-            1615,
-            140503,
-            -1,
-            140504,
-            1435,
-            140505,
-            -1,
-            140685,
-            1434,
-            140686,
-            -1,
-            140687,
-            974,
-            140689,
-            973,
-            -1,
-            972,
-            141149,
-            -1,
-            141150,
-            965,
-            141151,
-            -1,
-            141158,
-            963,
-            141160,
-            -1,
-            141162,
-            609,
-            141165,
-            -1,
-            141519,
-            608,
-            141520,
-            -1,
-            141521,
-            532,
-            141523,
-            -1,
-            141599,
-            376,
-            141601,
-            -1,
-            141757,
-            375,
-            141758,
-            -1,
-            141759,
-            374,
-            141760,
-            -1,
-            141761,
-            20,
-            141762,
-            -1,
-            142116,
-            14,
-            142117
-          },
-          lens {
-            99,
-            1,
-            3,
-            1,
-            108,
-            1,
-            1,
-            1,
-            2,
-            2,
-            140,
-            1,
-            1,
-            1,
-            180,
-            1,
-            1,
-            2,
-            460,
-            1,
-            1,
-            1,
-            7,
-            2,
-            2,
-            3,
-            354,
-            1,
-            1,
-            2,
-            76,
-            2,
-            156,
-            1,
-            1,
-            1,
-            1,
-            1,
-            354,
-            1,
-            6
-          },
-          strands {
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 1368
-          },
-          {
-            id str "e_value",
-            value real { 0, 10, 0 }
-          },
-          {
-            id str "bit_score",
-            value real { 252733701863193, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 1747
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 27,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 239747132
-          },
-          starts {
-            58,
-            0,
-            -1,
-            318,
-            376,
-            321,
-            -1,
-            555,
-            610,
-            558,
-            -1,
-            915,
-            967,
-            916,
-            -1,
-            917,
-            968,
-            919,
-            -1,
-            923,
-            972,
-            924,
-            974,
-            -1,
-            975,
-            926,
-            -1,
-            1385,
-            1434,
-            1387,
-            -1,
-            1388,
-            1435,
-            1389,
-            -1,
-            1569,
-            1615,
-            1570,
-            1616,
-            -1,
-            1617,
-            1571,
-            -1,
-            1710,
-            1756,
-            1713,
-            -1,
-            1825,
-            1868,
-            1826,
-            1871,
-            -1,
-            1872,
-            1829
-          },
-          lens {
-            318,
-            3,
-            234,
-            3,
-            357,
-            1,
-            1,
-            2,
-            4,
-            1,
-            2,
-            1,
-            459,
-            2,
-            1,
-            1,
-            180,
-            1,
-            1,
-            1,
-            139,
-            3,
-            112,
-            1,
-            3,
-            1,
-            99
-          },
-          strands {
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 584
-          },
-          {
-            id str "e_value",
-            value real { 0, 10, 0 }
-          },
-          {
-            id str "bit_score",
-            value real { 107956369119904, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 700
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 17,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157702408
-          },
-          starts {
-            14,
-            5437,
-            -1,
-            5443,
-            20,
-            5444,
-            181,
-            -1,
-            182,
-            5605,
-            -1,
-            5996,
-            573,
-            5997,
-            576,
-            -1,
-            577,
-            6000,
-            673,
-            -1,
-            677,
-            6096,
-            678,
-            -1,
-            681,
-            6097,
-            682,
-            -1,
-            686,
-            6098,
-            687,
-            -1,
-            688,
-            6099
-          },
-          lens {
-            6,
-            1,
-            161,
-            1,
-            391,
-            1,
-            3,
-            1,
-            96,
-            4,
-            1,
-            3,
-            1,
-            4,
-            1,
-            1,
-            78
-          },
-          strands {
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 521
-          },
-          {
-            id str "e_value",
-            value real { 0, 10, 0 }
-          },
-          {
-            id str "bit_score",
-            value real { 96322476310175, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 568
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 3,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 239758106
-          },
-          starts {
-            27,
-            0,
-            328,
-            -1,
-            329,
-            301
-          },
-          lens {
-            301,
-            1,
-            289
-          },
-          strands {
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 521
-          },
-          {
-            id str "e_value",
-            value real { 0, 10, 0 }
-          },
-          {
-            id str "bit_score",
-            value real { 96322476310175, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 568
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 3,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 239750228
-          },
-          starts {
-            27,
-            0,
-            328,
-            -1,
-            329,
-            301
-          },
-          lens {
-            301,
-            1,
-            289
-          },
-          strands {
-            plus,
-            plus,
-            plus,
-            plus,
-            plus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 214
-          },
-          {
-            id str "e_value",
-            value real { 75311203830971, 10, -120 }
-          },
-          {
-            id str "bit_score",
-            value real { 396303319834023, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 214
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            1757,
-            10488666
-          },
-          lens {
-            214
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 212
-          },
-          {
-            id str "e_value",
-            value real { 974211974571071, 10, -120 }
-          },
-          {
-            id str "bit_score",
-            value real { 392610020529347, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 212
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            1226,
-            10493744
-          },
-          lens {
-            212
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 212
-          },
-          {
-            id str "e_value",
-            value real { 974211974571071, 10, -120 }
-          },
-          {
-            id str "bit_score",
-            value real { 392610020529347, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 212
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            688,
-            10508430
-          },
-          lens {
-            212
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 173
-          },
-          {
-            id str "e_value",
-            value real { 466266270621617, 10, -98 }
-          },
-          {
-            id str "bit_score",
-            value real { 32059068408817, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 173
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            1434,
-            10493369
-          },
-          lens {
-            173
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 159
-          },
-          {
-            id str "e_value",
-            value real { 282612336584999, 10, -90 }
-          },
-          {
-            id str "bit_score",
-            value real { 29473758895544, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 159
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            2288,
-            10473961
-          },
-          lens {
-            159
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 158
-          },
-          {
-            id str "e_value",
-            value real { 101645475669756, 10, -89 }
-          },
-          {
-            id str "bit_score",
-            value real { 292890939303102, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 158
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            531,
-            10508746
-          },
-          lens {
-            158
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 154
-          },
-          {
-            id str "e_value",
-            value real { 170088832415117, 10, -87 }
-          },
-          {
-            id str "bit_score",
-            value real { 28550434069375, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 154
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            1606,
-            10490255
-          },
-          lens {
-            154
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 151
-          },
-          {
-            id str "e_value",
-            value real { 791346362502315, 10, -86 }
-          },
-          {
-            id str "bit_score",
-            value real { 279964391736737, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 151
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            159,
-            10523433
-          },
-          lens {
-            151
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 138
-          },
-          {
-            id str "e_value",
-            value real { 133360369247848, 10, -78 }
-          },
-          {
-            id str "bit_score",
-            value real { 255957946256344, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 138
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            2447,
-            10472397
-          },
-          lens {
-            138
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 126
-          },
-          {
-            id str "e_value",
-            value real { 624870513129795, 10, -72 }
-          },
-          {
-            id str "bit_score",
-            value real { 23379815042829, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 126
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            309,
-            10521434
-          },
-          lens {
-            126
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 123
-          },
-          {
-            id str "e_value",
-            value real { 290723970867983, 10, -70 }
-          },
-          {
-            id str "bit_score",
-            value real { 228258201471276, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 128
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 5,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            2199,
-            10480910,
-            2198,
-            -1,
-            2197,
-            10480926,
-            -1,
-            10480927,
-            2086,
-            10480928
-          },
-          lens {
-            16,
-            1,
-            1,
-            1,
-            111
-          },
-          strands {
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 121
-          },
-          {
-            id str "e_value",
-            value real { 376075217639751, 10, -69 }
-          },
-          {
-            id str "bit_score",
-            value real { 2245649021666, 10, -10 }
-          },
-          {
-            id str "num_ident",
-            value int 121
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            1967,
-            10483772
-          },
-          lens {
-            121
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 117
-          },
-          {
-            id str "e_value",
-            value real { 629306855490851, 10, -67 }
-          },
-          {
-            id str "bit_score",
-            value real { 217178303557249, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 117
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            898,
-            10506189
-          },
-          lens {
-            117
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 115
-          },
-          {
-            id str "e_value",
-            value real { 814059851804831, 10, -66 }
-          },
-          {
-            id str "bit_score",
-            value real { 213485004252573, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 115
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            1013,
-            10503323
-          },
-          lens {
-            115
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 101
-          },
-          {
-            id str "e_value",
-            value real { 493416254475992, 10, -58 }
-          },
-          {
-            id str "bit_score",
-            value real { 187631909119843, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 101
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            434,
-            10509721
-          },
-          lens {
-            101
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 100
-          },
-          {
-            id str "e_value",
-            value real { 177464050208996, 10, -57 }
-          },
-          {
-            id str "bit_score",
-            value real { 185785259467505, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 102
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            1126,
-            10495399
-          },
-          lens {
-            103
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 80
-          },
-          {
-            id str "e_value",
-            value real { 232835461766962, 10, -46 }
-          },
-          {
-            id str "bit_score",
-            value real { 148852266420748, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 80
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            6,
-            10540662
-          },
-          lens {
-            80
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 79
-          },
-          {
-            id str "e_value",
-            value real { 837425271312324, 10, -46 }
-          },
-          {
-            id str "bit_score",
-            value real { 14700561676841, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 79
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            2213,
-            10475401
-          },
-          lens {
-            79
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 79
-          },
-          {
-            id str "e_value",
-            value real { 837425271312324, 10, -46 }
-          },
-          {
-            id str "bit_score",
-            value real { 14700561676841, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 79
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 224514953
-          },
-          starts {
-            82,
-            10533079
-          },
-          lens {
-            79
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 214
-          },
-          {
-            id str "e_value",
-            value real { 75311203830971, 10, -120 }
-          },
-          {
-            id str "bit_score",
-            value real { 396303319834023, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 214
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            1757,
-            460527
-          },
-          lens {
-            214
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 212
-          },
-          {
-            id str "e_value",
-            value real { 974211974571071, 10, -120 }
-          },
-          {
-            id str "bit_score",
-            value real { 392610020529347, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 212
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            1226,
-            465605
-          },
-          lens {
-            212
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 212
-          },
-          {
-            id str "e_value",
-            value real { 974211974571071, 10, -120 }
-          },
-          {
-            id str "bit_score",
-            value real { 392610020529347, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 212
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            688,
-            480348
-          },
-          lens {
-            212
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 173
-          },
-          {
-            id str "e_value",
-            value real { 466266270621617, 10, -98 }
-          },
-          {
-            id str "bit_score",
-            value real { 32059068408817, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 173
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            1434,
-            465230
-          },
-          lens {
-            173
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 159
-          },
-          {
-            id str "e_value",
-            value real { 282612336584999, 10, -90 }
-          },
-          {
-            id str "bit_score",
-            value real { 29473758895544, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 159
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            2288,
-            444974
-          },
-          lens {
-            159
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 158
-          },
-          {
-            id str "e_value",
-            value real { 101645475669756, 10, -89 }
-          },
-          {
-            id str "bit_score",
-            value real { 292890939303102, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 158
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            531,
-            480664
-          },
-          lens {
-            158
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 154
-          },
-          {
-            id str "e_value",
-            value real { 170088832415117, 10, -87 }
-          },
-          {
-            id str "bit_score",
-            value real { 28550434069375, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 154
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            1606,
-            462116
-          },
-          lens {
-            154
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 151
-          },
-          {
-            id str "e_value",
-            value real { 791346362502315, 10, -86 }
-          },
-          {
-            id str "bit_score",
-            value real { 279964391736737, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 151
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            159,
-            495356
-          },
-          lens {
-            151
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 135
-          },
-          {
-            id str "e_value",
-            value real { 62046544507216, 10, -76 }
-          },
-          {
-            id str "bit_score",
-            value real { 250417997299331, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 137
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            2447,
-            443411
-          },
-          lens {
-            138
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 126
-          },
-          {
-            id str "e_value",
-            value real { 624870513129795, 10, -72 }
-          },
-          {
-            id str "bit_score",
-            value real { 23379815042829, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 126
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            309,
-            493357
-          },
-          lens {
-            126
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 123
-          },
-          {
-            id str "e_value",
-            value real { 290723970867983, 10, -70 }
-          },
-          {
-            id str "bit_score",
-            value real { 228258201471276, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 128
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 5,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            2199,
-            451938,
-            2198,
-            -1,
-            2197,
-            451954,
-            -1,
-            451955,
-            2086,
-            451956
-          },
-          lens {
-            16,
-            1,
-            1,
-            1,
-            111
-          },
-          strands {
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 121
-          },
-          {
-            id str "e_value",
-            value real { 376075217639751, 10, -69 }
-          },
-          {
-            id str "bit_score",
-            value real { 2245649021666, 10, -10 }
-          },
-          {
-            id str "num_ident",
-            value int 121
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            1967,
-            455631
-          },
-          lens {
-            121
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 117
-          },
-          {
-            id str "e_value",
-            value real { 629306855490851, 10, -67 }
-          },
-          {
-            id str "bit_score",
-            value real { 217178303557249, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 117
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            898,
-            478107
-          },
-          lens {
-            117
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 101
-          },
-          {
-            id str "e_value",
-            value real { 493416254475992, 10, -58 }
-          },
-          {
-            id str "bit_score",
-            value real { 187631909119843, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 104
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 3,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            1028,
-            475187,
-            -1,
-            475287,
-            1024,
-            475288
-          },
-          lens {
-            100,
-            1,
-            4
-          },
-          strands {
-            minus,
-            plus,
-            minus,
-            plus,
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 101
-          },
-          {
-            id str "e_value",
-            value real { 493416254475992, 10, -58 }
-          },
-          {
-            id str "bit_score",
-            value real { 187631909119843, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 101
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            434,
-            481643
-          },
-          lens {
-            101
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 100
-          },
-          {
-            id str "e_value",
-            value real { 177464050208996, 10, -57 }
-          },
-          {
-            id str "bit_score",
-            value real { 185785259467505, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 102
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            1126,
-            467260
-          },
-          lens {
-            103
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 80
-          },
-          {
-            id str "e_value",
-            value real { 232835461766962, 10, -46 }
-          },
-          {
-            id str "bit_score",
-            value real { 148852266420748, 10, -12 }
-          },
-          {
-            id str "num_ident",
-            value int 80
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
-            },
-            gi 157697786
-          },
-          starts {
-            6,
-            512575
-          },
-          lens {
-            80
-          },
-          strands {
-            minus,
             plus
           }
         }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 79
-          },
-          {
-            id str "e_value",
-            value real { 837425271312324, 10, -46 }
-          },
-          {
-            id str "bit_score",
-            value real { 14700561676841, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 79
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
+      }
+    },
+    masks {
+      {
+        locations {
+          packed-int {
+            {
+              from 1483,
+              to 1555,
+              id local str "U93236.1"
             },
-            gi 157697786
-          },
-          starts {
-            2213,
-            446413
-          },
-          lens {
-            79
-          },
-          strands {
-            minus,
-            plus
-          }
-        }
-      },
-      {
-        type partial,
-        dim 2,
-        score {
-          {
-            id str "score",
-            value int 79
-          },
-          {
-            id str "e_value",
-            value real { 837425271312324, 10, -46 }
-          },
-          {
-            id str "bit_score",
-            value real { 14700561676841, 10, -11 }
-          },
-          {
-            id str "num_ident",
-            value int 79
-          }
-        },
-        segs denseg {
-          dim 2,
-          numseg 1,
-          ids {
-            genbank {
-              accession "u00001"
+            {
+              from 1649,
+              to 1655,
+              id local str "U93236.1"
             },
-            gi 157697786
-          },
-          starts {
-            82,
-            504991
-          },
-          lens {
-            79
-          },
-          strands {
-            minus,
-            plus
+            {
+              from 2756,
+              to 2771,
+              id local str "U93236.1"
+            }
           }
-        }
+        },
+        frame plus1
       }
     },
     ka-blocks {
       {
-        lambda { 133271, 10, -5 },
-        k { 620991, 10, -6 },
-        h { 112409, 10, -5 },
+        lambda { 133270576282382, 10, -14 },
+        k { 620991117264207, 10, -15 },
+        h { 112409184650115, 10, -14 },
         gapped FALSE
       },
       {
@@ -4423,305 +1475,9 @@ E550307D2D79F520FE80D72FD775F6CD58B7A84401D65549738935E25595DF5E1807A55A348928
       }
     },
     search-stats {
-      "Matrix: blastn matrix:1 -2",
-      "Gap Penalties: Existence: 0, Extension: 0",
-      "Number of Sequences: 47542",
-      "Number of Hits to DB: 0",
-      "Number of extensions: 0",
-      "Number of successful extensions: 0",
-      "Number of sequences better than 10: 21",
-      "Number of HSP's better than 10 without gapping: 0",
-      "Number of HSP's gapped: 60",
-      "Number of HSP's successfully gapped: 58",
-      "Length of query: 2592",
-      "Length of database: 5860289005",
-      "Length adjustment: 32",
-      "Effective length of query: 2560",
-      "Effective length of database: 5858767661",
-      "Effective search space: 14998445212160",
-      "Effective search space used: 14998445212160",
-      "A: 0",
-      "X1: 18 (34.6 bits)",
-      "X2: 32 (59.1 bits)",
-      "X3: 54 (99.7 bits)",
-      "S1: 18 (34.4 bits)",
-      "S2: 22 (41.7 bits)",
-      ""
-    },
-    pssm {
-      pssm {
-        isProtein FALSE,
-        numRows 16,
-        numColumns 16,
-        finalData {
-          scores {
-            1,
-            -2,
-            -2,
-            -2,
-            -1,
-            -2,
-            -1,
-            -2,
-            -1,
-            -2,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -2,
-            1,
-            -2,
-            -2,
-            -2,
-            -1,
-            -1,
-            -2,
-            -2,
-            -1,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -2,
-            -2,
-            1,
-            -2,
-            -1,
-            -2,
-            -2,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1073741824,
-            -2,
-            -2,
-            -2,
-            1,
-            -2,
-            -1,
-            -2,
-            -1,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -2,
-            -1,
-            -1073741824,
-            -1,
-            -2,
-            -1,
-            -2,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -2,
-            -1,
-            -2,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -1,
-            -1,
-            -2,
-            -2,
-            -1,
-            -1,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -2,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -1,
-            -2,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -2,
-            -1,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -1,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -1,
-            -1,
-            -1,
-            -2,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824,
-            -1073741824
-          },
-          lambda { 0, 10, 0 },
-          kappa { 0, 10, 0 },
-          h { 0, 10, 0 }
-        }
-      },
-      params {
-        rpsdbparams {
-          matrixName "blastn matrix:1 -2"
-        }
-      }
+      "Effective search space: 113759551572226",
+      "Effective search space used: 113759551572226",
+      "Length adjustment: 35"
     }
   }
 }
diff --git a/c++/src/algo/blast/unit_tests/blastdb/CMakeLists.bdbloader_unit_test.app.txt b/c++/src/algo/blast/unit_tests/blastdb/CMakeLists.bdbloader_unit_test.app.txt
new file mode 100644
index 00000000..2107dc90
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/blastdb/CMakeLists.bdbloader_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/blastdb/Makefile.bdbloader_unit_test.app
+#
+add_executable(bdbloader_unit_test-app
+    bdbloader_unit_test
+)
+
+set_target_properties(bdbloader_unit_test-app PROPERTIES OUTPUT_NAME bdbloader_unit_test)
+
+
+
+target_link_libraries(bdbloader_unit_test-app
+    ncbi_xloader_blastdb_rmt test_boost xobjutil
+)
+
diff --git a/c++/src/algo/blast/unit_tests/blastdb/CMakeLists.txt b/c++/src/algo/blast/unit_tests/blastdb/CMakeLists.txt
new file mode 100644
index 00000000..92c75559
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/blastdb/CMakeLists.txt
@@ -0,0 +1,9 @@
+##############################################################################
+# 
+#
+
+include_directories(SYSTEM ${BOOST_INCLUDE})
+
+# Include projects from this directory
+include(CMakeLists.bdbloader_unit_test.app.txt)
+
diff --git a/c++/src/algo/blast/unit_tests/blastdb/bdbloader_unit_test.cpp b/c++/src/algo/blast/unit_tests/blastdb/bdbloader_unit_test.cpp
index f61d57c6..9a362004 100644
--- a/c++/src/algo/blast/unit_tests/blastdb/bdbloader_unit_test.cpp
+++ b/c++/src/algo/blast/unit_tests/blastdb/bdbloader_unit_test.cpp
@@ -1,4 +1,4 @@
-/*  $Id: bdbloader_unit_test.cpp 426601 2014-02-11 21:59:18Z fongah2 $
+/*  $Id: bdbloader_unit_test.cpp 548109 2017-10-10 17:30:35Z fukanchi $
  * ===========================================================================
  *
  *                            PUBLIC DOMAIN NOTICE
@@ -246,7 +246,7 @@ void RetrievePartsOfLargeChromosome(bool is_remote)
     const TSeqRange kRange(15100, 15500); 
     CRef sl(new CSeq_loc(*id, kRange.GetFrom(), kRange.GetTo()));
 
-    const string db("nucl_dbs");
+    const string db("refseq_genomic");
     const bool is_protein = false;
     const bool use_fixed_slice_size = true;
     CAutoRegistrar reg(db, is_protein, use_fixed_slice_size, is_remote);
@@ -316,7 +316,7 @@ void RetrieveLargeChromosomeWithTimeOut(bool is_remote)
 {
     const string kAccession("NC_000001");
 
-    const string db("nucl_dbs");
+    const string db("refseq_genomic");
     const bool is_protein = false;
     const bool use_fixed_slice_size = false;
     CAutoRegistrar reg(db, is_protein, use_fixed_slice_size, is_remote);
diff --git a/c++/src/algo/blast/unit_tests/seqdb_reader/CMakeLists.seqdb_unit_test.app.txt b/c++/src/algo/blast/unit_tests/seqdb_reader/CMakeLists.seqdb_unit_test.app.txt
new file mode 100644
index 00000000..6bd1d67e
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/seqdb_reader/CMakeLists.seqdb_unit_test.app.txt
@@ -0,0 +1,15 @@
+#
+# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/blast/unit_tests/seqdb_reader/Makefile.seqdb_unit_test.app
+#
+add_executable(seqdb_unit_test-app
+    seqdb_unit_test
+)
+
+set_target_properties(seqdb_unit_test-app PROPERTIES OUTPUT_NAME seqdb_unit_test)
+
+
+
+target_link_libraries(seqdb_unit_test-app
+    seqdb test_boost xobjutil
+)
+
diff --git a/c++/src/algo/blast/unit_tests/seqdb_reader/CMakeLists.txt b/c++/src/algo/blast/unit_tests/seqdb_reader/CMakeLists.txt
new file mode 100644
index 00000000..6d7286f3
--- /dev/null
+++ b/c++/src/algo/blast/unit_tests/seqdb_reader/CMakeLists.txt
@@ -0,0 +1,9 @@
+##############################################################################
+# 
+#
+
+include_directories(SYSTEM ${BOOST_INCLUDE})
+
+# Include projects from this directory
+include(CMakeLists.seqdb_unit_test.app.txt)
+
diff --git a/c++/src/algo/blast/unit_tests/seqdb_reader/Makefile.seqdb_unit_test.app b/c++/src/algo/blast/unit_tests/seqdb_reader/Makefile.seqdb_unit_test.app
index 89086b65..74fbb1c7 100644
--- a/c++/src/algo/blast/unit_tests/seqdb_reader/Makefile.seqdb_unit_test.app
+++ b/c++/src/algo/blast/unit_tests/seqdb_reader/Makefile.seqdb_unit_test.app
@@ -1,4 +1,4 @@
-# $Id: Makefile.seqdb_unit_test.app 505858 2016-06-29 16:55:21Z elisovdn $
+# $Id: Makefile.seqdb_unit_test.app 535575 2017-05-10 10:14:35Z camacho $
 
 APP = seqdb_unit_test
 SRC = seqdb_unit_test
@@ -7,7 +7,7 @@ CPPFLAGS = -DNCBI_MODULE=BLASTDB $(ORIG_CPPFLAGS) $(BOOST_INCLUDE)
 CXXFLAGS = $(FAST_CXXFLAGS)
 LDFLAGS  = $(FAST_LDFLAGS)
 
-LIB = test_boost seqdb xobjutil blastdb $(SOBJMGR_LIBS)
+LIB = test_boost seqdb writedb xobjutil blastdb $(OBJREAD_LIBS) $(SOBJMGR_LIBS)
 LIBS = $(DL_LIBS) $(ORIG_LIBS)
 
 CHECK_REQUIRES = in-house-resources
diff --git a/c++/src/algo/blast/unit_tests/seqdb_reader/data/empty-mask-data-db.naa b/c++/src/algo/blast/unit_tests/seqdb_reader/data/empty-mask-data-db.naa
new file mode 100644
index 0000000000000000000000000000000000000000..6201425a1345cdd850abc11822b9716575e600d6
GIT binary patch
literal 228
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

|;UO^Y`;+ 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 z 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ˊG7fCEVz^cgr8C3p>$l-?|?WJVm^gL<#L# zO-QkcBr}O9( zSS$*&DOsx?tYQU6BiQ_mQ3s@H36lk7NESA@M=@-AUtFs(M;cnry&KBG zSM>(PSchZQM};;L2Y;P*e2J=4qXmC8tbI2>^d1_DZk7C2VnUyKdl*TeUZT_CcY4pd z@o!ROq_P~xnBEpc9HA!#5==(aS2_OI0?&qdiLBY%ET$KgU*X%C^I&)pFUCu4E^6jX z(QhKamSQc4jp8boZ4-QXxCE2~*lygwwX_*x5M9r>HIN{c>>pSaP(BTLc9tMw`PZAs zf>^tG08_OyMMG+=kuOAH86qa`ZNONgw_l-@Zy38UqxQH>$Y63pF%3T8wOfR};vjC| zxow#VljE5jCNZvv@MB4EQeKC)fV#i&GBRx{A%*osuK77)2CtRVhG6my8k=O!Td^+{ zBK_Wb0TAZJowe!0J&tNUmiP6Q2^>GpsQIDKy`z4U!VSP9qL|xER=F1uM*IFXkgd`v zc;ZE?T)3WYOjCIIEBIv*O)V0U!ZW?O;5MS%eJEl{f+ad9q}0-Qmc8h%MQ>j}aCZea zvM5#imLfl6qy_C4Co{m2rUIYuNn`8BvU*gPeeTnY7ZOM=lgYDJ^k8TByc=%8@Z*_2 zBq>%3dQEiMSyxZg=Vn4xqts5PT<V+fOEmK(W8uI+ZP zozqH198T`@2H=jO|27kA&T#&lPdF>>@|xz-dAp89nnhmfGqIU%6Zh^udDr3Q`KBN} z$ngiOuBvw?7?}!T4f%Bq@o<6IlU{>o6u|il6xK4Y%Dkp9WF82x^&v)$QIsLIS5W@M zDNy=nxx<8M1vm4KRi zW<`Q@HjuQKjB& z($i~2ahR!@Tca=}G$J%-UUk*bntky$@a0hRR*8;ZV7Vi4SzOBT_g9ywpBoEcw(iQzYipN9qqgE`K^ArNs1WFCRZk0g(^ zQzlJ@IGBWcdg}d8MbdCD0~huamm(n`h+Z|j_(k?QGe8R}k`s4gMB&?8+&-YdoYZFe z>=;_BDG&E}%J(GLO95?@Q1!7<`mhyK@vHoPjX2PBIK+w35MXIi zCLeqL+xpqdcL_|KbPbtL;AEyBCM+#1gH&MWp3^Wc)saxI4-EI(v|&nw>k;n#p@7ZJ zTJ-AC*SpcURf73x16uj zdW{L(+%;0`7&pm1F+7v^0Vb>;#pWxoItN$5a!!9oQXHm;?sn8U4sMkM zLITPj07)nXCfoDCHo`hW`7uClUclLBK6a_*U@mVa)@Y;dW+Rr8J-^IKGr2a?(hPD(*#({vB_Es;$Sm_0|+#)SlShg@P-#kuB>%uTyQfQedw z(PhrndXdQfn2UZGd~?VOx6mCoz*Ijnw)4RHY{fZOqWeYG702@$DQcL{@8|6PKn9VM z_--HWyM$xH&~ry)y7MrSB-q7K(5?|^pt?x0V~wPv%ZvWfI-b$$YE~%@Bt6ITrN?$S z%IQ2WQ@q(yF6@(oPXrbyh`r*&|2esJ?Ma0%9z3ZL_Ds6CR=JpI>oo-A691nb^`I2? ztbov?-K{O)!fU-4O$LIPK{`QJp&|7SSc@Ysia<1RW-JsGZIuFNzQ~>+%~;9ILFHE2 ztgGdkJ0`m^AceZFuqOs+Me_K#*th?TersKM%mGOkAM9KbDi>SBS>4Mj{>PkSR~ufR zwp3m@YAI2{XX!`R6x$v(T+QMc^u9^XbAjs;A(dJ?@d`Ax3L|&SbT55ANmm$BXU_A~ zR>HqI8E$%eY#uq4i4_C<5QmAaM3&1Hn@rF`$&{s0%lJq`V0SqzOw3*+%Vb-A>;*D3Hx-lUe7QH6D?$&!?Cm`fHXH{H z@;x8$2+RG#ZhEvwoSe)Uj*as$T9f=(gl@o~i~FC2jI z^L)K}mf~{KxqFcK^R1etMSzV{TnoCeQx3zZ>#~T}z_q1YR}~1#MQ^JoEUya*xEZJ< z(Lu=ek3?tb#d;}XK3idR$9LC>SV+s@gUqeNRXt*jZ(EC>t9=hiCRV^ae@~wwD0q05 zYV8PC@th;k@w0Y8DKOYSh?ChuZ!$-xuKJ%i1z=F>FovE>HvGExOAirXj6-(aB9VKP zmwvX`7XiiYH5}A%Sp`i^&zFTy_#&oGds1-m!j;v)2MOIhHz>5d%j1%eE>PLe4i!!@=3Z}Zb4jzjpa-RK=5R;?^BGq zrQbJ7?$WWD-sfXgAdPbFmc>K5Ic^zea0tX{q^cQ2(Jg*CUR^nX8U|TihYIbz1ULnhYy<2@LG}{KRfK6~^;gkRDt{Bji0cNI1G_@;!8=`QPP@WEjerPR*zO8?i1E09avsZ&D>Od zI%{^`P5_vq&y6)Ia?X6TCVy{JD^6hdC}-54(}eTk=moBk^+}W}&30iIiY}`7I`>9^ zY+Me7A%Jq|dn3({P*c25CZxhBeh6kGUx$oc{9$p+?>!M8eo&JQpCb#Zmu3#7JWFdO zhvP`fJMaygEju(h2+B>QIo@|n^^9Vdtxq$$KtJ|*<_uaCXCbnuLLiJ*k@$8F4w|B6%*A>B(jCpAz335a40Z`J23H>lH4 z0qGsf3w?T~-_-2&w+36rbW1FoL(I5=Oh7NT;Q9-!PLkq1ET;h?Nn`{akZQ;5>CQNQ zmzBU#9H)|2f{Mks>7E9k%VQ-R#%#otNy;Gj0AnB34lZ>CVFPskH4j{RJXpGh}Ab@(F8 zq1ycS6ZtiF=Z6^Pwed>IWixe#=?$|f+^DOV(P;wzfoj!;PRy|bS4K4kaWQ=?B|OE7 z>rK5e7^;1!;J?Lmq1-8gZzdHbBKSnC8tSZ1@)a=GoA%uH?L4}yVILAo@>lRDtuqa| z$W$7;J(FQ=mhGJfdW#t)*Fm7RuG;kV_>E;-j@;Ai;TI8JD7#3378~T53>)}hPjCeZ z5DN^D5u7Q8zX&0N24HFD#due$RfYcQXE1sbr?9ptI-4}!rN5k9EyHS(g9^5$4l$c7rGve9F|!NYHdZ+p)bLt5%)GP{r+xQXzumgg~%AU5ez@bbt z8uqGUGLrj~w|~^S6Gi*zAb^_utM`>FUQRG-dfB2dVm>cSq3{lAf~* zalN-u#{h6M(SNCojP6f=@BZ~F@1!Y*p!FUy^eo2S^J4o*MTx_OE(l{8(7HAiWdq$G zw9&w(j)2@IO?$q$Jx`HE_i}vO*zX%eWS49V8`H+y&el!CzlSkVkwPb=KWp|-4har@Z-r}H(B*fLpckY@o54cx(>#HJj>w2oO_{1TG|QAZrxfaP0d-A3dy_K zft?72w(v}2;kR1ZidTkuO%8PhrXn)S8_y3H7)wD!B!dvn=O@R@!qK<$GA6ygNf60T z0KEPz{Y1V_Ar6C3e)038MYBw%PoGtLwK09h-*QI6x!w=c?_Y&)K^fk}F&dYv7b_ih z$_nyWM|)m!fK>>3I#A^rbP|NCf^}myD_p;!i@7jAWhZL2tF--Px^!pX`}#5)99f_G z#1(os2w~;Djefe|9g6W|feXrLN)SeVbW=@dW>;!tV(x5VKz!ovWb;y@P2i*+!4=ya z*slBu-|%!k_C<=n#4q>^giK=05hG#;c`K<+P9rPeW(3lC;IL&dMXGS@lgt2cz^myi z4yjMvnz^E2VFK&ZW>_3$;)Ithf4dVn8fD|rq#C#<9Cvk#cP9+%jNQi(!8(L$A(co> zmXWnQERvEd8VKhSnjWYuN+~cGEWoV72cb;HphFm#k)w540PY-WU-RqjJmF56!(Uu$ zQUhv!H0@%Sz!;2AgByER_RutpRRjI{@ua)oa%1CKL>2Lb;RG4a(hKhuiZ~0QLV(a! z)AJN940b~6 z^DjcXF12eGSz(!R5EJSNn*uoZ6oTtVmP%g|SI543m%VYRbPh>7Jgc4`pS5=Z4!jy$5)o#Y&uw%k82v1p};%M z6BM;BVO@nw>?(|MqBnl}bmbnZk;O$K-b&0Z2IN`EJmlq9y0WVfD3tx5!<)jiEY+A} z=?Mr|jeB@I7#u*`>aM}~ZG=ujTfYFr3L*rOA8_Tk-h%UMG)TZJ36Zv#B6FJ)UJfEo zn-oQRsi4+L-wWe`s1POiyUQld7{d4g9&F0`VkRt@z*bbE?Gopmc*1;&tLNKIN9JO4 zQ-MRLG6`{+Rz128h~VD@P4_>NANLrP0dwFa)9C{lI-K%Ht0ob>2P>P>p{#rqsM+Y= z;*u7;Fer`M z_sI4}a(J-9OWt8)Lnd?pn?#ttp)a_pp|ea!#9GfEe&5#or3-HC9geKRP3a2?O`@&9 z`_Zz@gvA&0j) zL9()cmR;uKDA^RL-yDoMpAmV5{@r8{my{pja7A2|AWWi?>wbO4AQOg||A3Pn~6Gb{&EoeV z>ndJvFb{B3`kJdoV(OxxWfB7G+&?B$WDOL6`c&zHu6?vi)PjJ&M$mi4Xg z+(uI5dIiu)M2V`(aQi#1Ozaf}hXW5BQ_I+;Bev-u0eLy;*DLV2iVJLLH>JmH%LAqf z4T8fOQ*f^*A4o}xw*FdXb7Z^EcbY|NLT+?ZXmh0?{Iu2s_fdU1z<7f&%=BALttIm( zOlchAae!!+b0lnpRl9pW`m@6)+g#j&ruPp((eJ>iLD2*6)JZ z;Zhr(S#ih+#D;_vxBYuOERTHwP1~*?e#&DX#m}yI4qZ0Nh|FC)Gw#`fS*AxKWk`Sd zC3H*z=4Kyg65#0tB9q7xsHzSuV>h`VX9?TT+5^{4*|!z1qeUFJhp^*FgvliX7iD;- zK2V}VX))sP3*6L_j&WdbpHB?Wa$HL%e&LD2NXbH9&CEF?(LC6TGi5APj)x0EeVALI zhPb*lIYEK$j4(M46rwHb_Y=<20`Qj=hnt7a>M8 zKRh93M8T>a4<(G*YGhsR7|^S@Uc>cYHX)6yoYPcF!CrA2dw>}IQCW+dGza*|We`vg z0cHO3qVs{PaCxOny4FKfg|AMql|()Iwzmxpf)!q_Ch%*>?4t#vp>aZ+S9qj7wsmg+ zV|6MkI~38w(!u(Eb1;Lzu$6AOwG^M>W(WiKvr6EUD+_7MuBiIlwERtP*3MOVoPd75 z>W%=!%ApLM66WN&>lSUE4FnOb`^oo}MZW2{oqU_vyoG#O2)cPh8NaPqz184-yQd1U z1b5UBf8GYW^paOG14u&dk8~VhUFB$l*=HxhZ8J){Gb^P0QYOK|N_ts=q8!lJDT0Z5 z%r;Z07xhS^Y;U}=tms060(*nu^%~gS2LRhS4S2D4oZwfcdvgW+u>FA5oqYGwd^{A8 zVv!QeH&cZnEJlt05_BvK6)C559>(NH_V9X+^PgDGkwOg%!M7A6!Ya&mdfe9AWWOoq zihW{KWJg~|!)AF!Chs*`Yo_4%B4hhgBd3h^^1MHQXXL<3rJo&&y!=wJ)r+I2&esiJ z`XWE)doZ{m`nHQFdv50!3RY)}V0Ej~-~2&Vge|{WzZ?4SX!YD6Sv~fHRd3tTeF0_v z6`(Qw_e_N8s7W@Jj1ZSyesmD=@fcDAlBR^<)#pvM9eB=vhiRh@9lG~tLzgj^X=>J^ zE?Q+QvEAS0!dHmQT08!P95?I8|~fkO8V%~0ime9yBU>I z#*P1+%{3U5&LvRh`Jud%Yb1HYcSfJ`t8CiZ<mV%Szq) z$Aw6XlOXC7dE3^^TfM29x$GZZj^aVaS_`;sAzJJC?0A@#R*2t283Hyd~bQ|xf2L&7*Qcd$d&;bXyRM0Nfxf}KfTk(m@8l*2oyf-wR z!*(JTIEg~0W^N%K8osM91aU_MlFX~)a64JiB1Td`v65y`ygDeqYW{?7n!Kgeb(Ge5 z+u*mW22$gn%3#2porJH-Q?ug#!)lhIu1292m2&G%H&1wiv}&JyTe_-7OSCk8Gw+2S zNzO&R@Jt=Iv3BwZ-Jg|EKr_UaGbGB@*$-x4%%hd0Z#6frjCGv}Wgvqv`+Z=2B#<)& zV;fpz4?n5JSFB6#?-7wW833I93+rIr{Ae0#nfpBNIC+{x|%4hPNpA97O3M0+&L5s3Dc|NXkrot=w?u#S(}N|J4&Dy4b5Nq0>`g zQcCh5`XF4!(WSjSXXKU&VNUMXXr-E&vAIaaRdc#%;@rC@~jI|)HAzo~iHv>b+Y z;u!0qpgjq7NCihasbNj{s!@~lKfDZm)s%B$Wy{~RryR=hY++{v0W1T(q8J1zhgb?7 zK8ch?!#gDR32Rd0i;{8Nw&n<>SayZl3M=%h9ovgK^l7-4(vj4%5lmmI8@nH}qg(Sr zSen>#j!f8uB^cKhDunyHud&dqX4)1sU19b=WhVeuTpUIg+?q*@y_K-^>_(4Te91G2 zDP2O{<5Kh+-@sRYE%`{zG7|(FPYk5POs&Gz{&1duZvx+3KSTSPsJ>}VE^8ir1>+{* z^JjmEY74u9zQ_Mwi+zGZP7zOLCNg;~A6BYdUM6C03~e%2J{2w(L}JlrmpPDnpL~M+ zu;SM`qd?*p40JlqweIgGI)vA84t$GPS%b?aw~gy_HmZWg2Se*&-cU&7B_reEuw4pO z9FAR2pQ@2~G1oF*7^VwQHTThwbKdtQ@%p``OJdd=74uwDuDs*&1K}{6Q132< zyRhL@up=CSYO^S>n8NwTpewXH5NQD*g<_tl|!+Of--SvUfufUqkD za)iZ2!Cjkn;KvThVjI+DKIh%?26-i(-S#T;{uK2h2x<}!+6lZ45sJrG6gMygfiAZ7 zK&rl#AL;@y4*oBs@^QVqquM4B;uhoEt!{s8(-A}J;Ja3b6WR6tVp~8to{PVhN_F+z z^dA-ym0~v8g@8-y#=Cbr&pq7fK+(${BmoY$V2AIotNS`fmhXt2QJgX9S+^LuwmoW> z(X@Zo&YDjcUh&Z!Bih!&-68b)L^I7_2?S-}l_9i!TdriD z-4ap5n@q~eM|Ky%v{mBYwhB3&@1valg=M3@;s(t^D1(1_G`I`#`q2$tJz`5 zXU4Le7?RAnJ#mWjV@7ZG9OoQ!(wL{>Eo1PPO;!)j(Aclt$$Um3Lj<4)M|2XIF4lug zMnUKMEALX79CX}q)bil(bA~SHDu-ury}no4rFX-1xf5eh;Ux0N zA#yjjIL&hAd#EYnY;nXJsQw+*n3#6>l@#-c6d8ezw*%iJ?IfLPaw8VW=$+ikOdFzL_3wh3?L{Y8B=2X0Y!&hKzSzIJwS94-&81N5*9%@lqr5 z<#|N`3$@5TW{s`d^#ruI+MGsg5LSeCPgQO%8DMym?<0JMPCGxeg@?=n@O=-RJfxP7 z*)Zmr+){|v%JME`$ADH` zI(O}x5375Z^lzLK+MU*zP)uDM#fpflM)5r)uI=anN#;+eRSzH~r83x4QTf~**Z01O zg;~|8%qB&VZYZhsxg!FSlS+=&4C}QglK<#kKIHU>UF;Y>y8lSb#tAh%Y&c#DGnUWW z@UhB%xM&ig#vmHeHypU-HMTP`yF)5h9w$|R=cR6wvDCR7atNOAZfxFfr}e*8#rDX_ z7Hn=G%|$u!o9R^Pxu!&$k4uZ{JP1g&_VCXq2nFl!PWS%kfBfOv&b1*bxHodpy?Xp+ z`H1QxT|@`{%wzS-{~xof2lS^fsr{(X3>YpCEOze9T(P>B_j?>|;`4RgY5NPIrhc`d zrCH}~(N*U$fkf`;}_<*?K!~`|)ye?WNNSnt_5%_5iTreR9dlmc@j6Klc?n6L#Q}Xl3dZ(ilBlY$?HwGNHSai`gN5_SU7e88qP=`h~ zc92sJcy*8%tIS&JT_Eq7W9s?SP6lkY+C`uHVB|&lu(Ht_^x{`5RDr)Ao>yq@Yx|aM zp?ji}=$1-BjqG^HF?WES{3~{C2Wn5K1*x}~`!_|@&U@49h_#EEkjr+Fh_3ehmp5gL44MMqOb zl^daXS3M&uV4kKbd8Ec@F%)x#Aa>GH8v5jSH->_hYa<@Fm81?z^V?P$=zo?7h^Sb# zkRj6QDqf7Y|F2P{Wq-^@TAt-R@YFsHh^7hc8H9TUlM6tc1OWxZWdjAkQNgi<4ZI?A zvwa8+?yU$EOD#kZ0{B-&fb1f4yNj~(64!`glaTZzsIvQVfKti1exBGU6pFZDeG;A} zN`*9fv4XKBf&qt4EP;Q)P~Q?azx3Fj5;{9UX?xaA5_277_7xt?3FCTerdRD)rz0SM z;ceSaK~AjjOTuE}KUpbVw8FliU})^p7Z^GUO|<+ zcOfk(oEz{})3jXk02%1jzZVQ&g&9rT;Usm>D^r$yjXtSX1%C=1vK=n91mXYz1KzWSGR0sZ0 zRT&5en}f_w^>vYsHv}WBPL&TrCJ`8Lm+x#ffSgBt2*~C@QXHY@#VTTjUth_bg*iXQ zrW2cnN=8%W z)z-{O+XS{Rwqrm44vgteK$9X<=WCuEehW{tzrBNEIwrqrXi9!!oESH&1Zq7sN)!mS_G2g{de;y@ie z(Fq_y8 zD1X%=F0K`%@{k_2FR~(_7$M`MM--ub4J8K^I&}^-=GIsj#?s zt#(<+_rg#N+x69G>L&huvuMPI6#ASHnt^o(B}+KXbgoR(;PLYBN>?7nLGvyT9#BSf zXkAsE+C50a)pd#(gDvD$y_UD}MP(+Ygsui%dFs&n>z|KZ1sR)93<~q7Q}Pd_jFnZ` z`Bn87bW)xJLOAjnUl1wVl*wXiNgSmJJsX;(7%sw;2Kq>=^xd9fIMsWo@<9RB9)*KF z-tbST^YIG%WB$(b?`-mQ;O`9R^4lhf;=pBctdAuLYr31ZMT+(mh+8ku^f_#@Eq>>^ z3AZ|~=Pr1;4I%Vyb_$I9i!~ps0|8(IoLpXkl zz3i&*kL1clSZ#{|{wOlg+!xmOM1Q$O6EsS}o-J>P-xTnqJh*WE5#?)PM0DhgR?WIoyF|Bo)pg)295*Gq9q>V8Se0d}}{VV*Fokiy^1B5aje+ z*!6tZwMAm|SVhQ7^2BR-$0!U$wy-<<(!~B1lkbBPuVn)*Jv;vZ^@Ksipk6FI0X!c< zryr}N+a>W9VgoON#(-S*NSE|-maQYwIbxxz!2_aX9t1Y60g*=;Ya$2nNaax&gB-^Y z6>Auqeu)&5`;hC1hoA57;2ohzP?nP}Hlbj#U9+?^$UMh+PUKG?C*!;8$ zgQ9o#QpnoYQ_=!aOfuTUlxi{geT*Rth!f0^Qzk4_E1%ge$j`#mIj5^e7}UNhu^47Np?>nZp`cewBPmD!;o#h>a zNM=D{JqgpV6-|pBo}oJ)eVt}fit*RA3)nW>l*%iEaeVGpF)1HyE0Yr6We+~EiKAiF zH6JiJrDPVL){LX@46!n%(j$ejiw&sDbmA8|T1aJye+B0nTie|90mx_8#2=}z2N*=R zgcQUG$~Y4rZyhz-H4jfg8rBhvGRJc4`#}#~Eb*iAItV|K$p`^r43cMSrYq_J2`?&W zAV5HvqFem3(%%f)+*aY!jVv_TGAE++Xd}7+NT+Debm!7h8_{xhg;hm4s~Ot&XN%rf z2>Hx>2NA-W$F3!S?2V+|)d2jJdtXjP2qesBSI7OjL-bwg*2N{0K?-{hw^JAqq!i*P z;>=u4*jPyLLV*(_+FBa+s%pVvfEE&6uTlrFw1=dzNxi;5Nlj?}qP1%zbE+2$gC=RN z)v@4r0WqXI@rriIV%pqSV%euk0^e1cPm6;wrk9b=G|E?rn|{jHnB+=DpY21~U5Ui> zg=mc@twQ?LfytGr8MV~-ji*;hqe29h@GAO`VozZ5T-UBP&3;y+;)+9tRwH*kbbwGk zwVd5)v=@GC^D~Y|Dfw+tsuTzROn(YDd54ajFv7Lj-p?f}{K@Cyb?AcEDI)&11kmnvB7CKI zTpdO5Pb^lw9$5YG<~u=^#cGkQM@E+b%gLSp=S3yZ#}ofyqrroDUjJ_cY_q z{)jOt6)r{U83A7V|oMUR$`CV?_Hv9EGZAbitS`%~fppa+OOvxfKZ39_yY+(qDQy-fO-AEXo5NnLgJ=`^@WjR25)Vqk|G?q( zgu4$B*@OJ!(b+%v?C+{4FJQ#>!!6edf(`Rs06QH5a+a{OCcYyL3oWy5fXi36K%5D? zh(I%s;UqC8D;-9@znZJ%U~L=swkTJp);vF^c*XvN>I&@FUF>vpVc*074k%rmlTH|D z5*%%BtLiQA0uDr*eV?uir+O66sVM7gW7KR2-;xN<{dWqDK&v80E18E7)it)H!)`7v}Zq=4elpLM~0dr(ILJMS>rMUg}j z<_OWR=a{(tU!Wj@(Jv09lE38?6Ep>(@%$C?a1wF&am%+%!{Kvo)Q+@N6K0|BUyCIu z`qSdIOPXe!&<$Uarap}fx1*cYL1k3bdNJG6(8CGo0#5NXTkH&sJENaWKA++)^^tFk zW5Sq_ZO%jfUqDs6|5QHeXw#3xGqwHqM|T~A8MUJ`J~hBIN1bGywi;M@TYYCuI1^=P zUZk+*^dQ636RFV+WI(eHBnL~$TH@X*F}YX{w8DmWjL+lZ>^xaT?p8@7Or5VFZai9J zUV1REr3*cBWnSE{Fvag^io#t&yp_*J7w2`=Wb&vhu~XM3?&V{#Y3-&H!u4(>vi zb3`aMA;O(44M|Zz+J(z;B#iC_c={;H+?48d>!?DoBC44>wM66+6AdFsJ4PHF?EDax5f z0Wi^NMt1Px9r$b#&!x1hp`SAB+UnFClH3HJt^1rVQeH@le$2(z2ZYD-yrAw>{oRV| zQeNS0!Y_#`P=)vZQS_}J(FpLPCT>GbPu9SD&P$_%;*n6=SLWVEwJY_LEaxj(mI1?! zOKPcTJU)s(ZMh~PsZ=W_EvN$rgqF*ytlTbW6l@$LvwBC0)TrgX#>@N@H`Q?|H^O>C zy+iE!p1+6$8h7|GFljOk9T`HCLu%k;E&h3|6LixZ<#%C_QTAQirr-|&jC@y>_>T2H zf{9Q?>_?A=u~G)I-;-ZdR6AC&v57!6cdp{i2kR437q6UjIGxcV=r1qFMJ^^8GJs7z zaazRVk|G-;B-x7c@9Hu`v-k6CWV%=S%0{YL{)8xLB=4{vW|BeU?TcvgJAQ!5hQi39 zGL4vi0oQ@Ju|t6fnCHE(M=;mN&=|6dHHIt4Bi2)#s9?^ z{^SRnK5&--&)>oovOudn0};Q)AU_`mLyv92E806))_tvI)h*XZe84(ndR5Xauyl&H zdxzl_4i>lI6HoAo7IBY3kOGWGRX>4cv*E~&O^v|p+$d=lntJt-fwzA31a2y&Pvp4F zdO3;v-6&i-Rgr85ERht&zP?OgcDrF7$w$_Xep9;=3O~7FT6T9DUm2h;9mSQ2#5rmECnvEgJ869NR`TTyZwPW>S*DPclG;;J+fpk85 znkWl9Dp1LkdbnuZrLrl5N+i0~=Sn}>u|*Nmju-P);td(BA`B-HJBbeIFUGSEGeZ)3 zTZIl*tz&9A@3`F^NlYHx+U2Wy%e~Ph(JiC``2=T3`7kk*l_(&$Im)BjUr{;49 zZ$Xp+O)s1fVvA}R@lky+Z2cOYJDT!}{_FH3^pN#nprjQc*Ew~K_jhFV2c(ar7Vv^{ z@yfGhM;JNnLVV|W?9ABrfPyBzY`CI?&KNGAEhV35d^!<^#m&TzQopBlTq#a^9{)#> z!rM2Vd5E;KQllw&b|_0aABu$1|0ouEPWJ$pD9Srkf;*K}MAQ>HX@ava^`g)F!qZ#3 zr9W<)4@`KzylVFWDp22L15R2287j0N%5j-<(yYz+n$MATWL#XxIfv$7|IDiG@l0UD zPR}b!?^*w-rtYBoBY&y3^itKR5J3T9j#%D`o&@&u;e(@E%WA_e!quQgCo-0Sd>Y7M zjB>rhZ=&Yo3xyOmxGlC8*$>LI?fJ@l@Ucy)7lE13>_dxERgyZ*Y@SgsjLF7QNmM!6 zG!3WXk-o;;x$xhn&|_*Y_6Ck-I=gcPD_vmVQO4BOi%4E-=adh=2jTK7aS@rg886z5 z7eCdb!8{UYP!mpk^)AzfAGv^5*sG0{p^b$x)lWZ~Pc9hm4JG%b*aUBVz)=_(oOTC}SvRbPeHt8G%`xJyqOV*q3N3ARvB{&M|WN z2xN)oh@zDodX9Ni0fx&+Oc8u!2#uT2GHMVdnCEONHDQm2j+nTqCq|h*a0q$Eo9q|i zhX=;eXXv>_TmM1}MT+bqv}V|E@6?9FW;$jdMNg^0cxegOdy*UubD=^4ws;7vZt8!V z8!05=5%ia9NBk7YFmfat?R5+8onLUR11V`ceeN6fyImA5qP&eIUN(+inm>! zcQ2p`ai;21x`A*o{e`xNAI%NJBcY+KzZvWs?ECs)p_LRb z(R1}obXJrU&G7<4PE~r;gpT&b_7l(Mwc>Ujr6ERQHJWum57nZWvW_!xr?mvb&GGQh zl^L+vb(vy}9G}bya29L)7{0F+e63#&K5}Y6`-0~^tQA%}Fhx6yctd+x?C%sA79|uL z@VpN;V2DQF9(=llWL)xq+RL8T%lf5KAR7xYG|Y9C_)|AJR{a~w>0gXUC|*?fg6Q2c zun*R+XMe64csft@*KVadX{6nY-qIU3jxWH)bF}wqOu5QHiXXx_*WUbv)ic%eajfXg zkhbLHIn-l5>3X@NSkrLguPT<)o$5gx(qHMRej&@2vBi_tj36gS+JD{##Bn9j77pGOVa^|ZU4wLJw@new!n@Ku?9;QUZ z40BJTlXyxM?JiUxW4Bw86kU0ZBRh30M2ulq*IC{8gN`nn`7W!Q+2;LN=MO;Mr;U7YO{c0;Y6 zXAWN8&?}-V)9YTZq7g%)yi2?WK4W5McPez>MQI;uYfh`pq3}0$#@%;hBZ}75S1iLK z!`6K^4pxmz3RLb77>pxS<)X}tZl-(fqBeS4m1VgE?!*Q+t7~e)(Mz#0Iffek*3@kE!+3-IN2SINDj(x@l#&i5t_E^6C-D%26vezo zI~!HLkJpN{L%D){O%-vxWjc@KUibxqhk(FZH?A8kh^F{>>RO~RID)!dT67E&A8?~u z9Dxk7PCtkCyo)=i}gK3z}LSTi4F3tB1k_{K2AaF)MG6OdAQ@Hq(rhbCk{ z3gk`_8r>d}b^Npv^3YEa0zx853_PI(Pl(B(Ax(jrV*+IL9Vt<{)+jfo%}X)ehemV` zRR7b+U6oU6`h$*q_XOhykJ#XUB>r29-bmWkTO|ubfFQ(`-VS#Kqt*9KEc|Q;SHOSd zJ5SXO2#>g%dnWCYiSsr7XdGtbdS7#}E_X~cC zSEOj;mgvWX59<6l>?I7@2}!X{Np{jioW?!7LmAd#E@o7zX`FB4uAo7|^LI-mwR`Pd zii9>ek6U$i1%9d=etl4AZJ@E9cZ|QM`bXLoZsnjbXZgaS1?j+nmp`Blj1sp;si?Uv zj&~$LcOXAhdzhXs@GO>970CD;Gdd{I1I#8zKgTck1&RhzEpl(P9rJxZNZ3JKrdyo>W z|3$QOY(*4D3?_cx(5(2y`gh&pf*xy@@@JU&K5oPy8xP|!4p)5(o1Q+R_7Hpjs=vWLyJ!u8F!xdq&bJNE_tfP@18hME)I_1FGJnOQRq~c(#Q151q*nF>fgeYOR3Y zx4ZrCbZ46ZwvfD(ax~c8>Y5f`wi1cd{zMALa>f%C;2H<*<~F|$^`$^$qV2USC5oQY zN-h>0f$J{W98y2Zb;Y>{v~vuft}sGqZDCywchi$A&wL$nsQWQsA=_hA+!mot7IMOf5j=#U#O++&j0Rk9OEbfc5@J90&;%qkn|I)8jo2 z<(nX6FRl1^QlgM1J`WEkSE!-WWve%qJnO;3#~KaVlDR6>Q$RFMbiADcL;FJG zThEggfRd#g`e`cwI$~*2h9IsXi?bHS0)d%a#s(PT6)IBLPbo|bUzysO^*r@(QqzLF z=3uK8pq}-{>;+qlX^LD=8KkwPLy!Dpr6hJkn*2}lRcXy7JnpPN%<*!3e}^_6)CuDN z9a)Z!%VFDd(9J_zp(qT90yc8idFqIaihqxnDJe%OXzi*q^{~P{*SmCwfusgOvn$we4I52|8n zS?STINnY}4?fc%O912yfO#?4DhZ$E%Rn_SiTYcKJAg|Po&45+hX*@hRzJCy+wg)%3 z{AlAR$GL{z>5HSYQ^2IQ(WiM95Zec8`YNgOPpmzyRn@_P1RHaxn*kb10hxYk zh#%ZAlv!B6wQA$~e~%H0jW647)|sr-6{73y-5gSBNW1|FR!3Ij@HDs&R?H<)Yz9JV z)&P*n?mKMM?1y@84dsf4&+Qqm93;>begxj@b4SteZ=xhD6t?d1$zMJB$OQeOlKk5mef7 zU`YXDtC^2BGIb5qcPW_KRyVrKo}}36f49`mfKxe}W2-FOPw&A+fSM>*1#!g^{A3Qr z8eis)M-rw63P8FcA>%a(`(2>=FObU#R@Ewl4Q|tctST!D+0uKL-=uuHtb@2*)Q2Mz znCPPVZyrWp>6@@*{6ltH$) zt?|!F5ko&Adw4i3Qd7nt;*5qf%ZX09>H?1kvO!@=8yN9aqTTI!Iz39$r^VwpbN3%m zmiZhaN&x_Ow(?=-9vHo$W1H}ndU62v`FHt~_)GNbj0)u!{D?9p(hf8EPqX^iP<;o& zt}U(-pL)e-bqKIk<@$z$4&< zF>}Ate8!IZF+W+b-pdc6as$KshhnlCI6QWFZ1pHFmAwpax8}Hgm^mvs+Qr=mWx6q$aOKcaw0xe zI_%cyN3l7pZuMV9g9jhVn6(ObK?6~S>+z=tfUTt!(G~7BHIn9%oX;O1Oe})O{u6Y! zrxXrau$yDb-;p*MfMZ`5pN|4+11(`yt~*xs6P(GJ9`HZF@Zut7OnB6g3L>nlYqebd z;}fRh-o^}~X-C0B1)|XH_r>pxwwG5};+7rT!Z;X~x4XIHuDDL!OUX3`!(X$P zy{&Zym>_*m_qU*bL+~mm=_hf;9mq(~Xq(VTZ6;t3P_y^yH#cfadW>q&vy0)5 zOvz-Psp`mPHFr*t8^;L#kwRY_}Esy}!jcHXavz=HT3WwffV@XDsD+`Denca>$^n ztU=lWZRM!7(0fz(sRASixTM;sQ+hKNh^5aMJzYWt_DS$Fo`7s*;i^hB4F;85xew{9 zLVLg~_%rkr5sS$J96mvrL-G`mK*02NKq}((TBxsQdtpIKBRh$an7a9dCU^s_z;0Qg zP;jU}jB=4nV6eT{13TGPmKSi^Nt*2E+c3rWUT5V1Pq{%&@##tYjXaOCysb0Z3XAHm z9nt5C2JF}=er|9*7zZ_tV3_b{tO3?eXq%6t!80v`7Vbx(yWQiCxFm3jXV9LBqb$Bk zVc@lTk@S5w#aDg<`3Tbt2Z^qMk@=J-e+Zy|Dpzy^V3RE;K3o>eZ*59ZmgU{mkq+1R zr7t0#ya?G^D^3&be}?{{YmY1iKB)Zr@ZR+ef)u}=f)i9A`yGvT%}Um1Oi0Wv zl2L%ocY<=I1Rx1OW#TOJiH9-+x&#Z}bEktWhoQ;jv>RFEH2%D{8KLvcW@}zHEHgPv zC0Hd!EmaWN9_}-!GSPlA4+b1*4SS`--Rd_Dx!A4VYEkiB!t+j~MrY<^%4KM*s^H+a z`+>LB&(-amqa1+YcGYvRk|WF<)@WejvZ4F8t<(k3(W$cGL6Z5%Y}lUDieDmB{tmdK zVR0~ROV9a=n@aBeVXA4m%xM)PW~0(K8`8!?jTuCJ4F$~8@w!^bvFGIwCM)W{rXZ*x zg`mP51-PvVk3)0j(L3Nfp_$sH>$Fj{nM#z;nN|k_d*FG^o^!=3s;N|7!6C%@Bi}%u zXBko!NZU3L9Esgf!{^(yMak@8zoqPH0 zY8c4)?M(P$s;~;xmzJY)j~VV1D;z%NX94hU%5ztHYMBZlWZs=50STLk+o?vs>gU0! z@0-il?Q5nHfxvbZD`&6XeP6*)-Oe-W4%6?~uPQ;MNdyoVEZ>!Ig(^`eQOF`8R6=Z? z9nzvx@VXzI>v03knUSEiRFm31{`cQ3S(IQ%Q{TwyCf~Fh|5BK_-5JY%0!DGJ$Rp~Fh)X=3fCt^f zXT?LzQIV!deOn^WYAxM(mx&jdhz%*dX(*&Hsc1$;q*(f;JxKfAyF}&35KE)KOug7p zBUJq7v|3~F9(^mkh@86~s`)}m+_$`Yhn{Xj8nnOBUdCVNw?Np{Bl3OML zznzj<8#-UcDoPe?)qpPM?y7$RpYz;Zr(L2hdQ^U){^G#)7DY)d%nHb1#{+7;G#p)3 zc-Uk4cN4;*66&xJkmnU0epDTy+G1g}WRp)h|OjXISQ_VQP7 z-_vn?Vp!zlit*Wjl*n0MWRi(FisYcVLQTNl_32-misly8Cj7}iZK%+lv#=Js#Bh=n zNWhA`Ar6C$k>%0@afBs|#d4RnImYJgXWATgaP@}=iWfxx5e{61Az3naT8uFJ`%->O zuMV&2y^K}C3gznv)S2XUcp_J9al1e%_}rgGLq?%r53hcad%PW`zy1gi3B3q!$~~F( zf`PxkRzDRIZ*}0hqBr9$RfaHg$_mB0*W>$w>U>h!1q@&z`lL|c`d0yV18HHn1TA7; ziz4p~&hi_UUQ?W#hg7VGXurw)(T8efIQ2`uF|@T7?=P!bM;FKHe7KNxgZbWCT9Lk^ z#2Md9nb0G?Bojl#Z%w1Rnphr-`N-Irn%#>hFwWpo)I zPP9@KH=&DBy8|iX0iv4Jhi0={odii7rugGCA${H-xH62c#m;U79h5OX>QCoOmTulL zK?X%4XDI&`9=%r2I3xeVk6H$!kcn565<6?GaySg~f}O@&v;WoDTv)g1_SmDd+CItc z$aGUK0H=xjYdliXj}2CxnNYjhx9vy(Evi30$44H489gik%xKimTyRe$k1GBb-J6xX zMx*MRZ(UCZD9iX@%7K6LYE7!}Tg9I% z8CBMLXeRbx&jQY!Ub!IetqJR1snjpwY)K<7$j-v6i zlUQ-yaYJYm#k>$C_+{fl%aj%S(;ugWd4lVR6mg9Edc&l=wZ%>=AH#6sAzoNQT2}0W z9S(+@83$qJ6dNlm$V-xMm+O(d?Djy0Bag-B-tG<5GiEAz%moqX4Q=$D%6@OCpW+t^ zD^YE+`x7DokCE$)B0i{y?p|2yoKd040}RAUrUkp-#clKhG5@Z&EHl~&2qI~t0Hz{_ zE5JJ@^*4cD#FbHglA<&F8le{z0PRIW@%fc;&XBExP-ev>NfmUm8D^f-Z}`DCKw02K zEjAHJUfP;uu^??upN;hl&-GhEP&EzYFmRvTq#<^q1Z|A8K(Btes3r|dS*k5?fWXss z$DX9!#M*08q<+2ZO_9PU%}gX~c5RDRinZVUN)8<)A#nZoufFhP_X$L5?L60nxHK{~ zv`_L5J^F)On1h3*zaLpL`Nk}loL=~6!S9gS5)1HMawHE@0fB(qj4d_C&;60*o}-79 zTbvF|9)O97TGzo)Z>BTSymhGaBnSNctjJlbI~!H~ zeZ)cabJhZj0Wr5doF-2d$=o6`>H%+j2hZn?YD#-0lR|<^Dl;IHB$$O;{Gl%3;ccl; z2U41O&HlxMJx0e~fc#X^`(~vPO4VA1;6DoeU3kIt%0F|h(k|=ey*7zfhAGdQ^{_<3 z4XkIXcU7x9!t4|o#COX{i zWk$`9>OSh>SlcM|?S-c!x17V+LPaGtY3%sANQ}7beN`q6^lYtU zI((Lm*Z_{7PO^x0((*7Ek1VA;bC%x{#ZL0Ue_=Nunw&(I!YQJ8tk17Z;H5Z1(0Sd$_G*SJo70uYs z{7$YHl-m2)B8`!bSeg<@BPaT6Uld+y&C!@14=WliN)GL10)Zb3^TxdeG7rTAf1~3q zIZL^oF54eN@D}qEjUtHfG^D7)2xF4I70re9@p%#32@nb z2GXkAt~W8s!f@H@g!eYnVQRVp`W*R#aKhNV$!JEb<7G&%eDyUit>2zVtc+q z{a-Gxv#LhCRrIU;S-?#3hD=r*rG}Oj#s%9ns+(ru7h2-R{cegYTy+A3jGF_kIo&(& zmSFq9*P%Wvff)7Bzt!}r755iCSh{>nqX^V1R1lTqVdrBO0ubuWoM($Dt!D7ryqVN> zO^(S$-jv2b_)r2*OS-_a*oZAg#O1}E>{D`xmBkZC>0GYZc&R=yP?G1%caS|2n@Q$H5m_eNQ3ytp)_!{pD^55v_LXTci6@A5CM6X;s918L?+jE@jCN0 zlZJCOo!)sNo4?s72RYYSArZ)d1wCd|$eqX%Y5i>@ZGXDoH5$(aUEiR~F(S5spAbxG zgj=`8O{Ktjo?81P<=Z+3sZcziO+n_7JD%WX_Q*pLz{h-vuYz|xP>!2BUrJk|>bg#J zL3L#K$2)=F-aX9a{XN;@Gcu_4KjmY$br?s=(aIiC4;i`zdz=*VCkt8{9J$+ov^4gx zkr)!yU;(1^C8M>zu;IvFb(-|}2dQ8fcY?DI;Z`3GVrOh$mOYxJ6u>|z)tr2;XdgJB zcp(HfrbOR?uMZ)4XsJ;;fmav)uP+1nZ&kwvushP4Rf*PS4nR#RB|(oP&@<}}i5qgN zI@nR3R9Z7U<#OO$;op-tY%q21bU`m#`$yn4Z_Pz6eI_)SAhEa zzSFj6u1MmEeXNh^R`ufd2$YbxdXZY6XM3Cb{aXN{ERxPe)5TF-NqEZRm-7q=&Jl3y zc?mt;MZ?ESA2%IJ9!LY4Rn6_^JIPAmSAyeD?t3y|qrCykm);M4?`{+6z0b8l%$!?+TZ|KERsB)aG>Eo~QT)Mr5aplh)6&-u;n z7D*ejK}1vE)~b2Z4lhi0y}9q#?efG3+uwaF?@Rmr$nwg(Cq!v9Lk9D+%8kZz_cBPC z^L13ridKOX!F}5!ean1NqAH6dmJpOW;JmDH0HZQbko&&zf6Gkorp?w>&L?zhVvLV+ z)9Cqvhn<7HSRNU+q-w#5V7DZ>%hQt700n+7w*#{hz%5fhq!g>|xnd7FF@)tipGM80 zAL7W|br1?2Jp4!fnze`0UnSVr7MZA|C_B?z~gnN88Q*tS}&kS5=ezomKx z9alMP^tZHf@G|Pg`P5&UArM_U$4FLJTV1FnL_8km<=)eRgoEcA>3q9d{7-{+i9bJd z&l0g5WnAlYIAFZ!LL@kwgjNO|CJKckWVXprIyJ>c zYHq;(l?`q7>Ei9B-3s)eI3=fRuI{=P;}5$|3!@u|HMUO>Ln*boUX{&1{`M z};oK_p(_>m%V!P89D+NBd^qS z;WLrF8P8NxYgGtFTe2pvhh8c2YG?IzN|77Rf8U`f28@g`Kh`LQ$1Om;76z%N0&)7h z(f98GApz;}HYVite*bU|>)U zPRyes2m}#=Q1@I=ywqG@i2&+4Z$Fj3?j>b;6lF88fXN2FyISu`_N^lvMILhG@kjB; zV=x_2`Bee$Ee(G!{-6jaV}eznoIPti)H_gKA<%wDX&Gkz&y9)!xun_Y>D8F}qs(E` zDNUOB`xS~M)li{2Vluad{T#-(8fzzj2^u;nmr>5NoTOb$`%x%5x7 z3=%;(rp;XycU#q)KX|!Nd+`Zzi!8sl*4r}$T$u3#ieS?7v>@)za@n2Y9(Vl0ggdH~fwxf+&lWD! zLogs^*xeId*8$vLH+ox;5LPQ2(qx>N-8j7cHpEtEq*t^gR-Rs>O{kTbbBQ{{LaCQW z`WGB;reScpM$sj$UD5YN3g#N=z|ZIbv15zdh|#R$RkPZQ4lBv~QyyTthEm)gXujV# z%m{UQC_Di~asqy;N~)^h_IebQEj*uqc(HacH>jij^axl!A3Q5Ud z`~;TFg#-7%G#EsI{lRJDja*67hEk3hNB8B$(oWDi zFn09)K^(A?z&VlsVyKw>ZXi@fkb^gr3yRJoMw3Q{wzCi>eW>a^1eSwNwF=p2fS5Wn zgG@7eGdI`>{e@r3El{P2LyEQ&ZS}1Q%}(t1D(Gnm>8bvBW#yz_q=!a#J_^RxYm$aE zrz1a}X7fZAmF)msz&-SNp`?;ets~7fu`Ff$B4K_>^p>mWF){_7x%L8BdCV7e;j^92 zei}(^4*oK84n}SskPAmK#bQ|W&6v*rr$`0X!FOqFcC1)J8>9Z-^;XTD7+WGelU*{4 zT4HLE{I1~P{t(j8^Bf>FGmJ9y&;z+K41rAW6jL5XYbWrQ1JLLdPBig!0pW;6kK+Qo z2t3UbZYuYlPbGluP*+akmAl#zSLTV`U`ez6lxh8=s> zQu;Y(-$AFSWYoE0>He~$RpN(z;@n8l$V-(DURtxno(^ zL%AaSOp$?<1p}`9XWY}i^mK+SX5_#4W_|C}sNodkLDXQ$uMl^T)l%>$zi=yu#$Hj* zMzncCUa|DX4cbrR%|A6D9&;Z*j{=Bq1asbi^S2TQQ!(G!oLGy;BPGQpJdD+)k`juA$$Pat^kE0SK~$X|-CEyjN^MX@2`tzdqx~H!v*H@)ugMu)snqtTDc~wZX&+D!)L<}0wGVp6hQ5o1*5;iZT zQQa?j3&dqRNnM5Pr51sw8~2Ja)+->MP`L>pV+=qKmp*|m*QZ>yj+TPE9*IHp!o?l0 zL@J05dJ{(WRU03q6_5Jz^mVkBQh?Av9RYnQ6#q_E0%IZC-uD&>4P8pM+S6h*_ao4r zez@};+sOZ2U75#PnPbI$tQWvCzYP7#dNd-MI2+c@k+O@*>!s&84Vis%+%$JM2)om|7CD_`NlIs>F;n*7EWd4X={$Hu;PkKgoNq`tDtk5hm80?Mv3VSlSeA6R%t zZoWIcVo(WbuCL_tOctjy2tI&Hwf-LO$;_nFz z8;(jbUkO8&1$T4~pqy7uq-L$Gv7UT9%&4YX7K|l;lOvA4T|%V9L~+o(u!Y4fGfls! z&rusnP$qr9Ib))n;UPCy3YmdvqNv*qY}_;TpSB|>H2=lAQ=cbZvGs||(iJ?LBDh34 zVwa7-twFr$C;{E&?~9nRXy#Lgu!@HXc(wNZL-SVX zdddSb1HI8o`RCJ)36mGm7k{`UT>{VBiB6#Fcj&p3td7j#J$)zRHmGmK>1KK&COFr- zG){O)nOF-z7Zq+7JE6;-EjM!k8@M(qXE~`7x)fVhxjAhrP4!%$;Lak4^x;{g+lXyJBd5*w)M}sL9emOO|oGm2i zW(TylDdcLvQlDKheGzKkX#JWdo2t`Uu=hANlce!_S}AFhK5$T3BCoByrgTGpCb+jG zhl<(!s}N}S`N-obsPQ3}>bg<&#E`X`ADcQf6eFsyfQ+SWB_cK8IIK~nVQuD=WmWmI zv4)vJy3c}+Zvho6BLpgISk5dQ|40GJv;+BIKb)v>Kq|`U8I{md^?rvZkqbWg|1K;A z?+MK2K6 zRJQpf_8tuxSnTkhB(vv0LgmafLSsANxOXgjK2zAVg3#zcfRgde1aW2B6gdl%j%JO_F72@|Udiej`Q>kkj}a>|zH8fQ7R+7)VZw0x;5zLsqf| zl_|9pn=;|2Ve^VDQ=%~Pv^ml=mk=5iVFCHpX)<^(mD6?`(i#>2d&vk;ro^dKkJy(q z@7niV)nm!>P^9X3AD3K2dCW_=clWU_+h3lM<&Z#x+bG1EH);#6%t-C3)4}LpV@wV* zM>G1Ul-=p}#5QXmW6m)}VTmXoJ35D47Q{W{QcYG{?0g=5)0fkucjUVDfgoyQmczD_;5q(5BkXbQqbjHT17zPw0sTw=gDc{)%6C4Zy~&UZBr*bJ ztM>hPwz%Gg)bK3;YPNg06N)uR`77YuQmU|~mHN?`LLLWsDgQ>{Q)qc2P)Z$4c3rJj zXnEY}I2uu)oVM>Cd%my6!h~px55Ukst|@(x7jJf?9WwP;hUal9VdTUu`&8OL-$#ySyJ0zC1bCqK73zS*nhmA zntlqqL7hp*3E{(R43{ZzBsRaIX_BbB+}T7_%=wQV;gwmPR6vGlm_{s#rkDfp*cEgXVmBJZv&+IZ z4sk;;%m%RhfP6#Y4kcKAxnVO_n8iDWpO!62oV=_AlFXcT))F*|sXZ0D#o6oQ?7BTA z@4>KRs9KjJPF6MRf0NUs_gQ9ZvVDSvj5f+S>J9GOB6(y-#NAD2Gwr9{xKIj*(D}-* zXqKsn*{G1AKnl{b3Et4Uhxd{le=m5sXphD&zW7y&1vFC$=)>fhu?9OoxW0tZSmLq~ z=8Pq6^)dJL^&s|ywYef5*nsd?4PKpw35QYJbbA?o+$Uox*5-`CZMe)4km$ErMN0)$ ziu*!z&oW3Tf^!U#k=SuvFpNOZy%GRv>usto^3J= zbU-D4bfnvD1_#lcV(nQY`71CXQg^P9TOo8VEb8Jv9e^0l=rI39!(Z34o$(vBy;;%= zIiLjlhg)K|;Bl_zJ`I5=d%U98YrEAE$dSC{{tE6x@RR@PBe7*D+)Z`it38#V^0c*h z$0+kz`!anlaGL-ebp)K7ANJ#~%EUgA1xJv#vJ;3rwrcv%zpJG9w`~X%$J$JIDuu;c8hEwOZ0*hawYSnNeFJtF%yQ|8j&wD2XW(Du?R>hRYQ zU?Pap^ByU&ABWC=U4|)hq-zXB{vex+atx;aj2Y{;YL-skT>sIe6=?{F z{e9+?V1wie9~65n9s+~nM5Zz&v0 zv6C+6GlBfx-P1oTFzhyTuXSAF-Htf`OJAoBS_zTor8^_2(Mk?}JHl6G^yi()wAa@+ zV(*|1<L<#4YQS-tSLgdD;RpEevmy-A-w<9@%%VsiAQSFVml5o)0zkAAu2HSI7|) zb@YfO10)TUmVJaS<0={*>|*FbfNwI+2U`6PZ4jU71^IP>2BAa?>4RSzu}>TBN+!Ztb;Dc)$6T?CA(3^; zStV1*1-K7$^h_YX5UMYb+uHD9x|Waz?_Z6Bbyd{f3<&4rAD=G%X3Dfec|h0=`M9iK z_xqty#bi7kWwqwIuZ60?Ufj zP%q*DPj6;~;F|#IQCdpiq^0Vy)xowm}$JNX-6N+WnQ(mPITTkIg zCy)O@HO`3Byg}!`o$Ny27GUh5bEY`M?iy><(zmxHRHu{*5kl{grjUtiJhRc`g;<(9 z5k_)wGUK+&fj&<>TMVd$V`;S%>@aT~RN*w6Ac;MncXaUgr5<=(QF{YH2M1!56((ib z+MW*EtQia)x$2hCA?W)blz6$B7F1AJyCN_^4N)XkvI5b(l+5^gpT36%5TO5)&+ApR zf6Z9)q8!mh()XvKm8~7O-0&BiR;?>?UwhJf=TO*%YsA*{s?DQI$yv*MyybN9KcIdZ z#}wDS03FNP`A6$nkunr2{?-9O-OT2VF0LS-E(;uM3BTgyCwg(Cocj<^x00YmkDJwZ z!>#(#S|DlQdGWe~!{)m!%j-4LtA^us6SAtghD&BX7WE}(-Ya5rPlXmJln+z&)3q|r z#!Q!P7sDhpWmqEg*!^|~6t~HOBkjFe%~%A}?+KF)GP@9PRflxwt$+SYWL$5M)vG^OA)M4I}FW1HI6#~3FdQ~&;nZMM5paaw?Kt<5ywt~7?d@cB?W!{w|LcO~C1eGHR^(QR*3hcLmG^)FJ=p{eiM`clS z!(Q8~cuYQe#M1y<($En?H3=ZoH_bU=O^uL8Fc)AHR10l89uOwTnOjY88JCr`PdiMn z5H!qTTn^~J2ecm9Fa|wq!gyh~8yV;kiv%2xh}vx?WLQnOG!^wno`j$Ut}b%;ay^-$wBdK6RkGr>N#y@K4qJL*^$XWK1xT2g zjA+;{--RKW0aB??%SfA8Q+j-7jIJ}ae_DB@_VwxC$Up@c4YKfdF3eI5vT%QmXO8z7 zUs}>OELRFmXp{%n>?((jP{t%)DTDNB$?nsY^4XF`^sEY!SBS_bUl|{Nm?gpQ;5N?3 z8ND^+X^aJB;K?EQ%hF;CATFm6(QD9)ApWbR~Wx3@%ID z)SE}X_1HmSXa+3_zdcg78C57mumz=#3-jrd-29GOvC}}%KMxdHc77dT@UbM4$qU=o< zPQ0bz$dF6-_x=_sZK>!<8)lc#Vb5+ViJ(80aZa!%@dOlA(PZ&W)xA`TlfGZ{QSuTt z(6A74FmT`+ffO2y(G#0`=_}AFem(4I39`e8xC0q^QYXSTr@%z}1e)?fk8Gi#=uXti zvy30q8Ww5=CVrF-p)1;Yheb1>xyqBc)43`k%(!eVXZb-9J+q%iwUJ@rqqHA+TW@C0 zGq(F$b4jm2Vi=C@Qt{WMggeQd*M6KH&E@sxt_bX|0$`NNFsM1Vx~7BdCXU6oU0Tkb zpCS~&tQ)Y-t+ceOlqbg2uwJJI__DGz39vT9-zgkG*rXk%?A`5%DNuD|&j5oF%6Ji) zO~giL_phE4N@`r7DYu8+COr2A4VVd)vv?_f&K0W5%h?Zht@mB!Q~Te8odA zia{}v|9pq$c>d>|i{wOAX_3^ndD=0~pyF%CM+JDUNIhU-s+eYDi?;SQ(IUh}$|CXQyATZRw zyV}(6GqE5$ihl6jn^=FL_^MQ4LAxtBnDmo>O+%HEchZb#nDfAjowS9$gDr1HZuJ5R z5ewOs?W3jn>^mTwbtTU=uzD~dq;UMN-q}T`HZcQOBOn;1vwsxx}Y__O+$~(1q+1~jOfwCPx$>${U25Pje`mf=t)ObHTW>U=9+A-$l(+sdDX1!-$ee z$gxR*5imq1zdl&Q6XOBSSCiF+sO=@)j4ddHrFFhgfTr#dMg$|}p=F@`sw#IAIjSj>^8E1QNeXryYHP*^ti^ z0{38K^F0Uw&&=42Eb(DWb4W!09TAun5Hu!-z>UZCr+)X!gWMxw5$BaQ>6w+1>YfQV zT_mDAGtUf3i%5Iyp250y(lD=Yvzs+}T3vN5b8{H3Vp+5o<~a+{7T6IEV}gZD`Wu_Q z9*RJwoEpzVSrw%JC~vag?I95QM_=kllXBJ)VMu-|cIZD95^m7WH8T%FkZW1z=Mp)I zsFXC2-o>J78&a36+a^~`PpL!>oEp?hX`f@+%igO%P0gqUu^y{EtLbKICeZ=Z-a3z- zM;9l@$xBhC^PVCumFis1=DxTv02G%r{=lz0^(-g8cKym>V(Z73v;Dh%brJdrJ{#{ zUPN&q{&eZz;E#|rQn3q*S+T~~aNY;M3GN+t2fN>}tuA9o7`KJ;NI3+cL1WHL>iyLh zgN+Dx?)^p#Q$WEX%cI%x{Kla7V}K_`Q#!dtmX2C>_fR_?d9GP6ByUxW>OMhx?vMH zL!aQ*!B9=TG&U4NvFS4l^hsFF&WulTkTN2hd_VQ?qx$!Porv8YOXBo$U*7{CM!a(jEoD%Ds^bd*|yE;4oyMi{LPD>{gys1KmKJt5no3u5AtcgF&1!*v6 zb#7FEZQyJ$33rkrbReXe3UI_|4AHsGrYGKnXA0(K7Q~p`g^Iu-z@4_Bqpj&fbO^jTxA9?qm?a|88dkp4vilN`< zdNwj^EM(5H=lvqXM)>1>R(!NE~3>%VH(916)!xn3<(D~-w- zO_>3!d?V~puN`Q?l49#k^NlHB1me;Vbd&;RYB*jJ*m#6YWb7xM?i9pIo+&6!G0za+ z+fIGeP{TP-=B@H>|7=yl!MyB9-vcLibtwh!eFik>9>;ugOdOet4wntDHO5UN@HGop z&akCFSSpRE%@0R@74LuJY95`X2<|jG(EzdDf+z95eLPqK|F7`twhtWQ4*ukcSUB}g zjp)pgj6Gqt|H53*5Ti_Wlz^~ZC{g$ogot2i@}?~bUS z38`bJkvo*wO;1n#G#-$18}#6{K0lRPg_2Irqh6H$^a|c>u1j%hOy13IZb2vEXH0M4 zs_!w@0PjF}5l`BA)9!vkJnmZ>aE(zsuRtOFd@I1)B7{B%{04I6*#We~KfaxaQs>V_ zh~Kq1_r@-pjy3EC^9(c7_TqIKZ!zL7AuD z@m=20XX?@brrZ17&!lVj0?fboCj`X$hUIBrwirm;Cyz}Kj8;}A(s*h3jV!~s|Bf_i z(gX_YhYoBHU*QZTw(hcaI?)IyYY@o4SE1 z_#z@V{$?!&1e3|mVCS&Q@x$T1h%rl$ID*lslJK|)x?cK3`zp@>$*P zK%MEpRg?WWc+&OGS z3)D>l{h`|Gt~<)>3Lfl;E(Q>>Lkpy`4QrvVx~c%nDeBuLWGzWc!I&AjzYT!F$Hq3F zP@KmEROXI|0fvwPM&Y9~_?n>qcMzwUvkyaSprrGTMZ6)zIv@OEy z@!Dc_Qec$j(8D z4u;beVCPl4eM{4js^Y#>OU+95+0HBok$O>)z!&d>DHXLY#iKKlA`t<{cIh#(HqiaD zL8Z9OrqeE!2r$4wcI4|b|2I6}YI!c!Nd$3*7^1?q-{V1VP8A)-sUw6f+`bkS$KrFvJsD~>d1$lIgcf!lGqW!45=mG^Ul*8ydS zHJU!{8&eRd5i0q=(1KtdDAuv%>5Rs5={gAH#PWWPr`aN+=XEz7M>7xkdaXNQ_zIgS zoDLNKafj08Ni;sq9blyVK4(7u>>Jg$K~5-4%D}{IL`2ds7o?3`%0Nqw)i@H&yp+Mt zn!a~ci-HBxM=Zu?DbX4-)*XQ!UF4b*FS_&&ap!gjXp z9{)Vf%Npox$z|3d%X>13%o!KRL>JGqg!LxVAD(BhgqL-dIkEpLO<|WfmVr6rbElD- z4n*)jZWiZF2p-IhE;O7QA1d|d0zO>ELY|_^Xgfxqo_HUoGy%FW_c(*rOE6O&3DzgK z*M;`Eqp~Chk#9~CvyTqGS1wK(cd}UtacvRi43srT`nWo=IuS_l)^5USZ{;tk8u$6Tt4&#Ba> z8%Rf}h5KJh1nJ|e8>aGa8ky&q5$*YT>xqIY}#o9P1;%j zjm=tM28d&Um5(<4U}J|2eL#$htUm|38WkR>e1dNZt84`X=OG;XW*$Epj7UkI>y{@> zRh#0u;F2c`Iq$w{qr(#_|1h;lG~OBn<5sUu60c=dkgoj)uU8v9KJ9;8QY4w=$extN z2rd}QJ-L_g{9uAD8;#n-HZWFoMe}y1@xy?Dy!YsW*DqfyGi*Kv;k$q4j zF>La^|47G6(n#J{(iN7Lc?764HLr4V^<9RFRLH&|tad31qPcA)#dO24^_~YtrQQ*h za46?(;9y^#WFFjLu!AfExf8fMpu)xJ-t`o5R&{~Q&>{5zozAeEXXKMA5SOQ_^VZIG zd6>F%=F<>{0y+a>w*;JCf#H|9m1hAtIz8kmu!73FZ#~!HIHs%V@Mbe5RHa}aS*3&D zzD+~prM(=G8s>D*Qpk45wZ|MB3U(Fnj`}b*upN@vHqv(+Ae1Uja*k|LYw#j@i0dY{ z#Py{QT$fpKn!}2BlPW+}RO)E5o>aZ~>J`ZrImdAMYhrAySIGAl z3B_zFS_*etg~M&@hF-+?c;(4N+Qr8tgKj%@4FC=dVA>Jobp(0foe=zx(y%sche6r} z#nOV^Wk4zFf_~~}^b6A@;y|;4jxLpGuz7n8z13*8mT13d^-y46{iZU7nh?HucbFQ& z2#VhwLz&sYrB&zPr5tWqU~RxeHH#>diV|q^fyg%qP=Z)Q0K^i)MPvu2nM3VXA^=)p zCT3TXQYFq{(+Dl-Tal@*=`6SKUBMQE`hbn9hhwh+hg&m?ch#DqS~z4lTLNId8Wu>v zpHhhunk&}Ut(h16$OEvX?-R4;#_Xo+qWxB;d<=pG@9!26M#QL+IML|?6*y}7$pbaA z6$pB8z*1RUndD`%X)VJce!0>31c0x}e}yZJ<9g07IaC$B-P7Ja0!YB@1*9&GD&5d^ zw9yz0e)+pN8&VKSGXs1I2eX#bD5gW)u1uJpnG=iIZ*km%w)?`D3Xtp~L8bUPFVZzb zMf-yjg``CS3tuosg*Ij}&umD9xL>;JinfTu%!=P>fFya5_&nbQa6BBaeghXA+|bJu zL$aFG6xz4S2ANbgt4r!xQ=RBlP8`GO>(?+(NK;qHj>`Wwgu{}P7n=~0hxOS8f*1vr zB=Vbztb8X7R5hhI<#b2*b8i${!4ouZQI*jD)x7xJGgoVSnl%g>-B{c~c!ZObl)l(S zdFOU>p7;he7`mI%22k}5+8iZo1d&$&n%K=uco(GZJ5zcs^3Y(k1MvHcII_;`J%9AQ zDcY{U0mg1DyU`+^^tl2w2sFmF`W)>$mIOdUKc^cGk4NK!kdmgWhe}d`wzvt$U(v?2 z67QgPUZ7qutd3{}hB8#{w78YNU!m}iMs5TQF0PC|csh*kNlKfY;owVS&SXxO#Yl%; z0lGFeBj2xINLf%{o?OnlWd+BqB*faZihCZ-m-wXu(6>ithR^dMD;=3vq}fHWKv>e{ z|0>R_T7{oL;2}ez(ghzxxlb|H%Z<5H!MzY=?Q6G>P7QY~`lqBVxM)-*Rn8-voznO{ z$?b;~Z<=#v6xa$%o#a1!GeO;+cj2;l^gIGknE3I4D?4G5@YhuBf1?w(r8>3{omEJ{ zew?kBijDWG>)uQb`hHBJUpzF)|15do>0 zbNv)|^M!X34M+*BPWQCeJbVi#Zoj9Ddideg1(z@7vqj;O)9rk16fHyQg9rw@L>T|b zrZVt{ow6L2MMIHtcR}N_A&AuI{KaxFiq8BfudG($nS>{-o$vskbA5Z zZI9N#8DWBnj_nn_hg;LNMQ?MBxT2Q`Nx+`*o)Z-|rgd=@G0+~0?a=@I zwR7^%#3lcrW{afBSMqHQ#yMzY;|B112Ro!H_pi5$xVwzyn2zQJ-IQc}iwK3IHby}h zgHvZ&p?+tte|?3q1iZyK`rWTv#75K)062Q)|12-Qn+5tGyas}cr(xk>_qq6!heljI z!m)W&K_fXM_-d8_I`NK1YI-(rnF%^~=@~D9EtxJD9FEQFuGN8I{E*wJ&!|e988@il zjgStNI-Fm2hD+>L?4D>u$S4U%u_@~^xIxbR{fQ>~%vt`g7M=!T zXh6$wn#>QJ2_w}Wzod#n@2Z79hEHK}8nQ8g4j%~9*?;h7pL5vXg8}3Ev0wUvx{f zkox8P#a3P3d4l}iQNYUB5|SZ1Jq)mMM}(x`tY{bXYxWlcl#|t0GP2r`0p6KqGeQg? z)%K!}iFhNchec9AgR|($jf+=6f`W<{6ToVf)rtqsCW6@_)zleu{-(o+E+ywx^x{Px zGaiglG@G@M;;_d|`B%MDfmlVeL1q{vIoT>}Mw1=dr+K_HufV_^SRLc#R>9K>lf$8yE{I1c)&(q-rSNvQ550mN$gUhOlg(L zD3Dg>hc6<~MeK@>+5KxjOqT6-tLE!vjh{gL&W`EW(%lzetMo!#@`NeGi}XVJDT1{8 zLs|olUEoc|S@!X^!1;aQz?kWsmn4FcIR}#Q_N|@KDdZgXrmm3QF%detEjCB8%GEw> zJcuao;EYCqE(59tx!Ix)PWZVH7*V{|r|A&kJZNWeu)|=+8`zcwN8>yDC)GsqzU8Xy8Ue%bbNX)f<%98P|2B1WoDv8sfd9az&gn zz2{04mUHYOJ8;^^@q(!Mqjn(KiT&JcmjRGiCX-1J%96PRtrHWhw|GWx_NG&nhhhu) zhATn}>#0Cw3)jkRF^FN4x?h&6H}AZoeN`^hvnI#{?e0NhUA^68PiI$v_} z14h)ZBM3Ki64F9%jAE7j9BIJbI#{Xs>2bbp8p6Wy>df2GHl}6$<5*=ZQ-UN%7@s~- zd;cA8@hTQTlyIkg4P#-`e)V1Y{JaO`I*t%|U*j(f_N#|T{h8VSlMo%Y^Qn;kj%WfM z3M)HJs#Or}=fd_$8UxlsI;9O9^AI_VL$|V2*`T9kNXE7IH_2v}5LyQEAa~U*k;u&8 z`V8)RVpN35#KX$>NJO3lM;CXF ztMb}w4NGgM$i}Zo_4>RfES#ZUAXf5%k(8MK?Fg@5_DuQcOHENFo#c4!Sp7`gQjG-< z1$@`_W7IyJ_gmQOKdd=o)X)Q?^ZVu%qv4eRv>-jQV8@XiZu~;G7ZFhiAH!#~h21f5 zzCdNju}t!KevGGrk4VrCKG!&J6x|=hviST2v?f&EHA5$!eZqK>4esq`);Rl`PIYbQ z6Bcy(R6B;u0;(N8KY=Vh;NgSBw?H^Ni3h*ae!K@7&O)K6Z$xX|gsNQ2GNcK#%53l< zSDH??DuA$x-Yx5~!ruvFE=q%^!yBj= zfqAFR9wVJv=mEcJR44KKu>9G#P%v2n=mxqc)vBCHB&56oBZjA%Duw}yX=Ts6;~-<2 zlW|o*#2skYs3uN&3Z~@ugNJ~Bqe;}+^H%1Iv6$2nlghmZp2BzQB|utBH<}>0|J*Q* zu;QyqC#}<|N3c;Or9XkhkjzDW98iC>2txB-SCr;<_X!z5TPt0&x7DIP%VLt=wpuSK z1XFMIf^Bpv*<$8rxDe{;`&Ki@v%&AGE*z$LpxxO5j`?X#+FgalMkB}|K1ON1A`%`z z#1$`GQo~!MrSBljPka@~$b5ToGVRgMxl@gLpjy%!@yTTl>TEYWL~|9ChHYjs>1BbF zd-%PYDRhf2FWlzgu}az}>1wi~y3QXry6$?0B@QK5Z2;qW%D-2adKMk1`yvk$mPJTk z!yA^k`+Cd)f`#=CoE!4DW?t$U3cR=fbo6zUfA~h)$PRl8N+Vt+!rlI;U9_Y7- zlZ73iIQ>N|6gGlk3zO;1?fVzgfUU0+rm2mcN}hrmObR(RR3Ysv+kV6|V7Yfv&?rgp z766JFG;EamT(wXdYojZPf8=^mMD}h6NI{=waZz9`CTV^WHlW?qGLeA6F$^fNkG?=q zJJT*I6t^0xJC9-nbj4Kkzcj_X8e_0Cx2b&yE#xi-Ci2l3xBXtTwE!S9Vf0XRDpVE+ zVRDuAXFqe=rzu?4AR@s}p?D58sKQ$8~ zbom$n{Q!jb-V?O+vn>)Xv&dwf@6~TIRTYJJkvM<~(;e z3BwGqE>Ahdkv}m&R&Otd{|BxR7jjSMm|&1<9>J--Rzg5;R1iTiS)m+mJxD0asbYHZ z>maviqIGDP#}Y%_AR%2YeOTW@QZr=l8z3(0Y==X_`>6Y5u`lV|#gMVeRAepK8go;H zF)`?}LdG<4{mDz4631uJJX;DO8iSE~@A^=4a5VI8#5=Fe8YS#qI(0ri(8S7%e4p*E znCMvr)j2$z;YAI7mffmI?2F+_N38fa)*J;#Sm;dCFPAkKzreZF%%ilvi$k{PCo2=8XykfE8I5|Yh9WeC zg6vPqXsf@=N>;+beA-_Q#dt#@ss~>w10w1OA_!K}!_q%;{0-$W!y(JeM?q+Az!F(w z6}O`--QZqO4X}L6lt)Q<5pr&NF{o_YuV;;QRvD>SZZ`#K=2Y;Xti9wxR2~g@@2;Cj z0jW}MWdJ>^PfcyTRM!Ip?0c6Q=i8P_{_{kEDb&U2A)#0(qRTsD zx+ZS*vI)C2edL(Pm84wav_KNCHDUe<1&@X(V14Z`GziUV6)IzjR^Li}TAP523H&W*FoLfQd)r6ani zXpkyo&PGd_tG3|75e<^6xdB%0M3mor(@P|;qdqRX@R@h#!dP%_f;OaCO*1B{>{Zdf@Ohjpz z47Vo*{O%Z*3ZwEs==T~gzjC*8#+sIRMR7kN5%q22j`+8$@>+2uHVS7aemq(w*rX#o z^wiOZYaObU!C#%yJ*tu*>ichQIdQ)SN7>k^MTbQqGMm5V_Y983PsLpfZYO4m7>f3Z z4t9Ux(6MILZ|49|F7UpM2i0I^!NfHavj&j%an(-L5fE7h&`Xdh8aNz>0~y)d2mpHU zz|it$#ys>svmpxwO5Of#BRlB|Tz#=Fmu>;;Zm-%SOw9=m%jr4#j(xo5!5T~cDJ>fJ z``8buyiY9{!M#S>%d|oD-M`=d(vZ*b>t3TJTO0@ye$~8`*mEZetAA~b!sjXS5Sj-& z8asqCLd$`kw5|o|ymubLy5e=!C$3ESRSV17h?zz0d*dnro9*GA8X@iBJ)i-Y7BHIFx>)*qP`oFrQlF8T{i- zyC1382~~d9^dhh03;Y*%XbyCS#YtvTY+NDun45^Yy~Q@#XJBN9bX#v!zo-5Tiot64 zp95%i;+}LhN?qi9UmU0q8O^;BMkcOe6gtSRZFQ*hR%EjPVYw;>a}(`s-4@~X z;eBO*lb+a79|CTt)mkAm=*8DWx}yFCZhCvvEjQZ@yB>eAqq^AzR>c$Oim7W{zRFZ;58;m_}YY(?yjQU z>fThZ<9x$!1*EL$5&CN^KQQ771!h=SWtR`z<|#}JleELy+PVd`f?{nO4tC2t@(QO$ zRW?IVc@ur_*%`>5p^Ng+Bs2RwcoMv14>Yo}Y%HJI9eY*XXTytzw zD>aiZA+eV1CNdudRp%c&F(o@EQ`!vKnYC%Z0l-iyA2D~W4YmiV+vbl-Sl z=txDFtVD4`i!NbRHmPBqoghE>g{cOF&55k-N71-4^XM&4ux6vP1lL0~}o% zqvtV+z0FEEqAVh`rv~ftX#w;EYCgNhD(`NKm0KLv+)vGA^aUKE z#a7$OlE`(;V`J*dyl8{dBK)pS8b-6aSsThF9D^ny`vXe*2QzzGKBDyrsd+3t*(11w zqIs!w#G*J7P#tdJ2y+HjpcL(3hZq|6z6+`J=lnyeo0EXk(VPUH3F^eUBIzUVII?W) z^bvC;14vLi&slD`*EzRCy>lyGL4!y~6JpATS>f#C8M~;7G85djq7KTb5 zCC!48sb9d2<3OCRMf3Q!xvC&~Rl za06Bh$%j5hz0am%aY~nM@zn7I!A|DL&;G7->^la&J-kL3YaCbgLP5^f`Uab8(MJk; z&qD!8l@Sp0_Z7?!Dz`_*Tbd!Iyd^p;-!KzgJ5DB*2UV#R<9W{Q9260WP1mBzxc;`> zPU2jVCc=^Z!yOV-4D~vWZUN^ZkfsL5v=S=0c%whh#SnULk~dfDLm9+tzVrW;jDi|@ z&o)^oEVs<5kc^D3I!y1R_bSL`L_z>MO-lW#vxDktb4d#KJ~Cu#DQ{>5Dp#8jFEO48 z#t3LNiWZ?H_bXFBC|zd*1Q3{<-#vWyoM0!~AJhTxnJIM`%>zqsx)?cNwT>#uO+oyq zy^^4vw>VZu?TJe6&m5dZj)r6ERBRpQN~pp}KO32JWK2=3650SI&(|H=y}A0No+rFo zC<#O(Cf?^0J-8JMD~$h+?p^r#tzBtK&h5;u5{hx#5nJW&+FKhqURbxDNVMs!K#WE7 zfdXepP`LL&AAPMQ=S6l&B`EpBv)|2seLYzZKT2{Mt>4)?GQ`>g7-_cvm(us;ij)>3 z%E<<(&?c{p`x$VQ`c;4}&?Z+|2WmP=4wq*Z_Ty6z_(|D^k1jRhwXfpNO0!H4NqhT3 zAX=k~kTK!*;Hi5Z)yY1r!^xZ!Rkp?>@{_zAp(1OW*tZva}kJQZa915WArI9*SD_wDN zJhYn;XZjSXN}>>F#zLOkGaL%lw4-Pj+ z0GxEnoVjPFu1xotHXlDXE?x?uB?V_j4Ly@B3pi#@%L{y@@zuQ^H}o?8>Qw)@#TR z0pO!xEwYLLU>dC84hNgZnJHM)jo9jxTyXmf^JMr@>|Yl>!=BAaBZe0T6@73gmocBF zf$}=(5lY@7^5+IC@gp%r#d%V@3Y~6KrKRaaEAFVDk;82@dV}Y+L@BhMSi$UbQE`6z zGEer|XBx%WgAgN{E*@7sr)tMTk~L+c>oDqyptS$d*Zcq5TNvfqJSQP_--3p!qpD{0 zE{#&+3qCgcVM4ZuaqFPm8`^+s547J$Nith$ff*eLgAVPAMdN$64d!fQzsxd>UAclY+UvzXcpGKkrHbX4l7% zbolz6N9UD!#?wp~#fa-e*RS*Y*dFDYJWvvO+Yd{qLMHC={7z1#GZ_*1MrYl+){3_G zgEp`pwhpiwbE)ExOaD+5OTTi){f|b3fsB2TF1`imk041`L$MYL4?(09;02Dl!86DD zbi*AFp%Vbs(ee2A7_$C9)$jcx0UtOII63kLp0k6uYT_weUne{9lzK;qC0o4ti}{Zb z`^KYaQ(Ai1(2pX|H=aUp=(AM1>dC$asYsW^$d?iD&l*wTH2OTbEm8Bck*aG0q3(Q$ zAoaM&)uzr@ajftTk!80zCB({16y~y{K@Wf-hXlcuYMqvH?rv<*w z*2lgenylxkP^-nzU0kg_uR<{Ij$xn-T{Z7+EE6+|7zr6ⅈ2cDaTe}lXP5k z+ePw@bqR;6NOC4|uE;(S02~exzJ-V5;iUg?gq%GY&}elO3p7wgK|W%YUX{tD^}aFE z@*$@dwuC{^9+<8O6N!>|I@6rTG$foDPTZ#e3f?nip(IGm?o-oCn^sgZ^E zSj_8k9$yW_ee-MUH(|Oy=bKqzr>=*nVN|@Ze#VaV+4PuGN!zzys4Mx-*dQEA<4)b{ zO1wfeDC012&Tl-t(ey6`aF*Ol9pM?+gn#J(B4U?*zQC0)xV`PU&g)aYlmHgTbAXk* zg(i2FWlhRAaEltX`(^Jxrm4Y()C$?Iz0D_A}o1 zyF4>c`N)r}9PTEYCHRS>F&QGJANGqZz32ppJ^qBtZYy*7h7Vs;YM!Kp#XQ9c6_x*X zo4VfgBiQKWXwRZ!d|<23E*YKxS%Zg`f~`ZyDB0b zG%1B-G%MD?L_gAM3I9VkT+^|Ax+^b#ZS(sk?zPm0bfF(w)8Px%Mt?bX1Gb#DPBQE4 zk(ZtU^q_xaOmw`^ibn_g;T{?7Wg7?wJ_Uz1+qa*`sI?Qc&?1rM4)bBIm-PNaJgaCXgNFq)?CTpf zuKV7kr7olPq88yszxVxUWw63(%k4$j(ebCB;uQrx$-Sjk8#1QRz6Bnz2LlGSZ-eDK z=D7oEIb?&(Mw0{UA{p;YFN?M8Yd`$dpWsc*K_5!D!Y#oSHH0~wTdiaH+uBSd*6ws zaQx=p$t+gi*hH*phi7x-!|mY?7y%!TG(Q*+(aKBIL+-m2?Ce|Y3(aNA>QIESmK83}V(TA{hOh-(^!pp#pR&Ze+V3&C->Ki0tm2`?qe7$|d)2Iu9Y~$at=Ov14tbUV zd7P`wCb$*K_-tH#V6hO3s&94m<2iw9r2A(oX4on-A2^ncr<<)N>E&)7(>WvZA{s6fqqbE(xo^fJbE8ohMlVa9WV*lK12%=H7LVAtW3$YL zv6I(}aix;|)s18qGqP@f5&q~3PgNeGD#K2#49iWN?%!r1?*u4Nv{|8Z9TeE~v5)K?KR(p0>(nECgvU^bXo_m}Lx@7Q3^q4B zQLodrD)njw)wYQeryrv)cok_EuM$17mVvkKTOoGxp*`7C(SPP-H#pytf`gF>?y|OA z907YpyZV0d@vq8V#qlHV=&-&Ho?F;c0Mj!=pH_$enbp6x9CVLH^Hn@uSXeeUmebkD z8`*q-tI+0X`|RZ+(f)A`c}qzq${y7LQOgpYFpC+Cb_6GZ%_z2#XRq!_E;YX|CPueg z7&2F$tZy+$M2! zh2F43uC}lUkJG*fqnSPW#RDk7$Fjkw(@!Tiva3o4C~>K`7_EtryUvmOfE|w%SxiSQO^>Vypu0G6|#!S_A?O z4T3CzwoG9m5`4#LJiy|Mc#G4tZ79{b6c<(^ARoTwi1b2hwI_LI=nH8@?;vA=vmT4F zKCARB#;~dFD8M8^BIZxC^Mm#sDP|TY7G<_c)4Lb_vtAkg3$!s!2@~b929~Ih>n<*4 z2rM(VHN<6Rz!X-l)|;@-7UcviF6Zbv0;faUpk3_h*A(8XtxD1*3wgZgx$(ZI{y7-s zsIpWP*bqx2Vm@u%g`Y(^53Clq2xw0XSvtgk0N+E`30|f%SDc)R=DLh_bA~XppDNSv zT2**@^ zn9`!kIv{4RE)5V(Qp_m-PReuQ#vd}QmU1*54M4~0wcSggwxTKM20fVisNS^TH7ITf z^$vd}P}blkBFmJO1}dFOLsdt$8XJ)07P^WvFeG60UWT93ZT!sCf{>`xLslde^*%46 zZ%|>JQDpA?Am5a43x5_(*Z8$ufH)YlbM#3w-5f#_6TzAh=c$$b@>QYm&QjHWzzWAK zK}CFT!JWvzcY}H)pfNlL8ZYdCqX%y~#A3CP0d9W}$)|i4swa?nd=e^9t_Mv<5ZBun zEO*sek?II8f$TgspLxLYzUw>fUf63x7QvtV$Jxcg`{9>u>0b!y#mHp*$vWa!H z4T*w$!V~RbhaI^6%i`*aDnZP)!aS!E1-S>V-ps&@FrK5Unjb0zN9}Dp-rfXxhTYQp={bCEKb5wxZjT| z{`O8sUxu`ipdPpR-cnm{{GD{EZt?MAYg47QZ)Vw}U`_%>Zkh+PzmRQwGydK9-d{yR zlflc<=f#@YX%_Sz|8IFRArtzX1c^aSzSL2|wl;taC>j@j^Abb659V;vW?+zpdS~laGp5t&bVB4}oKnG& zrG(M71PI-!tE66sYE`8$FhWMjt5$CQR#Ea+=Fto$#|2Q>;`BypbjtswBeK^TSu zu4&B5FZCB2nA0`XgTDUefup(_NR2TI$D}NGcy3uN$iG5g`Ri#lxcVM3=)qRBo>MTR z4h(*6rsHQqcvv$fPqdR`cs|sdUZYN+w$g0}Pcsyc>3zBnaw?SnMDSTq2$1H z1|-(FS~tf=j()}sp+0my?<|1IGjGqEL%PNSdx*4ww#$+2U5iwApI8AODPk?>d~JFY z;i?}ZHLe;36Z`}~czD*6Vj!s~n>4VFrsNIapU_kqZI4CMTZLK}NXA=N2X|{r>?$Ri#$8EGQC4^O)uI!hf&=9EB^7t+>o?pZrRn@E?T2hJst`{ zf+RQzl$DUhMLthsptL<1PD<7&zLJGy_e9S3{Fh<`W2vy!rBcoMtXZp^f4^3mO6$#a zmZBmEIx=-w;WggANb?NjB^+$1<^=gOi$YY~$tN*RD4g|;6?ZS?>+a{NecGW#tWe4U zV`M3+FfLsUV{BQoXKnK+BS#%*s@{enzjA}Q3l~ocAoHT8zOA^eCt3p{u`4Ub*PL;^ zho&VGp1hy}48h3+*Bxm!M~c6a*JD5OIjvt~+%uG;ia>MvM<~<2=!nl{!#T|#bdiR( zRc{-zQ`)&Kv*=hCQNCc(^_qYH0KRnkAd=k&ugMRohISA@lS21EX52E89PCk75zJAj z_8-4POCIz%@G6Pjyq0vha>|4Dca4thKGQZChof zJvM=;RQ5B!iOEa|SdoMA#-+g1{y}i#(^Le8fRTQz*fgjV ztqx^^wU$b!OyM#x)uA4e2*30W6;+EV)IqmNmA7y+rtE3^&`S>RJG#q!mcXu+vc(q* znmYMgDleOeeWYArC$A1GHYn~D(-KAg#TaKcy3t?WC9Tj`#ptNG^g&WW#?HUrpuY=z z+;zI^$%;sgS-+0lEd>R7r|fj>@tCe`Wpfy#3tc3J_;r8AD5 z(_DgxOl*<%Pdi?5-R`jA4{Fcf4lhtY%A&HSYb$-3_;^DBP0x?7d@ zhVKX-mYC_%3*k0}UgNKeK9hfNI7i1U;FXpXWJk8p8N%AjNta(nyF^PIr$^iVf6Kw5 z+kqZsb9GI$hc~hQZTW)qQ*l~DXNAN@^$lneC_hD*ybz2tk1pL7=KEx}UXb9}5#}FZ z%_{)9LVDqB4f0!Uz+gk)Sd59TS9^;{puzD|g-SMrdi~vUUCJ3WKr+Rw-17rXp zU)-Vt>m5UNY6tn+NP&j0dm~i@TK3|yk92k5|b-PxYzV6J?g1ts>1`&54NDO{?`b-5j_a44w4~`%y%~D|K$jPd~#0MZqXXgI2|*rs4BWT>(Ha zsoi+_3Z9=rjT$cA$Szt!>)2l*WL{qFfl1CduZj_p0_U3!kc33ZwTsv+$J;F+BWW@K z$Tpi#1$|#ePEdDZTB$5&I?yYd3ZOCQYp`(qzqxx=^gHpXDVnt(kgEevVJEy3F3QB- zPW#rEwPzR9=yST<{Wo~5C$rvdXWtqmv8TL;vXbXzkm9se zwlkbG}myvulvHr`zDQ<;9VCff=+Fh%&z*qPYyQ3f}||ZJQ}@xW=UoY zonLNqU}^PhK9C}BOcT^9*J(x^sg-yj+GJU|vwX~X)rc^o-zysdKXeSI!OA1>y;VF3 zMZS&=Ui8mp!lHP?KMZ4(2e5Q;tKcM1Ip$#+mq1Lp(n!0y2lD;AG+s&Tlu{;8A)F_& z7+q=`UyXybwYzttHT(>!SYbPV<-OA5!GQLU8E6-eN~zs(tj<+S!9T_v>*W}TxrWf8 zpM7qH`TQ1UmeAk^@@rZZKT3^|UwL|{8Y~H_uiW$z&b3zA6$zl3vDSOn``j(i5WT|9 z-6zWHLEY+u>bFv0u^7^fJdt$N0HZ3PWaGsHJn9N(1G-8;sn`?qcPB%l;|A<$({%0} zSqwicx9q~9&9mz|NufV}pRa|bxmu_>IYB?G{*gdABJfEftG4W=DQ7sAGyk0BH9Y%r z%jtu!NUZ6up74v3P7dDAb~BN2AGg!?dU2vU7X@;1ul)2SaKdFRn^bgvVGZ>Yxk6G2 zEad->Cr?L9YRlcZyOunBynVt=eimM8q^1u@vzHzqPEw?>A2wUj&A{WfZ%hfCMJmhFW&an=d zW=K7U2CJo~u)Aaq?{Fy4xhM^7@f=m8rC+FYhb=OS;FCy&MVfv0(y$NZK50exUd?eG z|LT;k-6ebawG?NF`BDt*!NmaLqm+o3)}v|e0JE93(N8z*;OWv;e#c@*slo+AoN{Qj z_sZ{$ri6Ki-q0DB9jA9F5P=MB=d370Gb&RT0Kdb~>$-^izK$=`s%4iIg~d%)8|c4C zSZpC^t~0gzlk~U#)v1^u&J-o?I&+eSk9n%wSoT_Ytzh(>BRk3#?t5ABiLPI?jn%!z*_{2 z%~_XVhI^d^(mAFKpfsj!F{m)iMhP6K&*3H}$;i;0W$bX0?oKGKs4_R6w;aC3ZEHRc z^v3RENWq&@{#SzsXV7QjaITzg^{XLi_w>y~dRiW2$3U4v@3`j>-^%M(xm3>LNHHdN zDw3SCdf;U%vav1+J~x|*X+~+-kQZFmZ)nWj@-@nF6by`cL!nXpAy;lHwS(U1s9aIt z@U&y5M{hmK2k44xNIF^&j9jPr^&~{{s3d7wx07dCLlf-gB9H=K^vFZzy14yuYb|UO zrO7ij*hD0{I!msL1U#!FiOAzXb2rb_zhUjqq$BO0G$QQgs4{|Y(BmhrZK zyDu4Upn~;x4tOIPdMI=MO|Hk)$qNR35iATo`BA_Lng0Q0=@rd+=&l}vQpwjc>0Cn| zE0YYCUKTd4K(cDJuoFASlPTKJ5ha0VoXlI0~~e)s*{RY^_+A|-3hlC%<+CXFVnLa`3Wg5XIa77>2C@dGxlomFg+=-}W%Wv8xkJ#gU zc*Mo$RO?~nM9pqW$boAsHc1g*0BNm`*ZKPhvV$ za-}jR_;A3otl4QGp>}vh^uegQU9`BUpAtX;U-CYE(^D`+D~PR@C;u_4_5VR4^p6D> z+&mRLj3@wP%@Y&9cOK*B_RP&(T=vr(>UZ~npej@^Fe3DSIzN$uC3$F=^CQjJ)S# z{6h`Ecm8?hs;&s?^u2`Ug&ez^@JUzZ_m~t@l3Qur1B|$2hw$)KeB3i+B={B{O*oXi zgi|1?t5#1%H>jCs5cn;Yc;Q&+{XsQh<9V)P$-CLgmVntY7EnU>4e+B+wY(r+ZgoGe zO1mTFc2zZWcQ_RXSenluFn-NW;+4j5qD&8e52Qd}#iJ&`FY>@1?b*z4aV(3|H&i$j zv6Uy`ViE>kuqGU3QA?WZ|1Uk%9}-)!hf=@R8*@*hO{YhMFTSwkzS-K$y&^AUXAKP5 z{@cC<%&ydCS1a@yJ=MFE%Q%yGNvS-CCydm6Qv60vzz! z*S|h|hX|z)MAQOp7S@27R;4!l{=zI_)o@ktOO*#IYMtZ8^&K*J-6O{6`ZUUjwR(`7 zNF@|ODx|bvOFEGw6b)(J5+onMUkVC}3K*%f+2|q|IF78YnGqu>hNy7}08q-#HJFbN zW=JuNUt@+F^>cz8ponCy-*(%2_N3_L92c(=vp@otBn5y?tuPY-#RXtht<)(it60+i zJ#MxNF>ty#9CbW}s+$Aksoew!o#X=HPgvAj?ld^Lv{==hW|tAqIq4J6BEo zQWV{4lgTa93e3A47u*hsx%P~4vQ{6?H#Ab2E$MoCJ6ob)U03F%6O57E`gtwq(>`7+ z$sy4wFazC&!ZVc$i1l{Iy&YO@=~F20LrsxuNw^TrJ{MP}SV#SZTyaYcqGP|F@6R=R zE0sOHT|Q{07JO*n@>zl<8~>9|IDT_PVT`%^EjHYTxwI(C$LYZvwD7DlzX_(y19Z!mvVg6x=mU9bRrH0HWJr4p^ZW5EEN0+ zZJtur;@zOS!h`lD7-Z#SiJc0py<3oUxesH7Zf=QXwc%k7fZ#FyRdk2c!Wr?e8=g(S z7b&kGj9zO_7*Gn1H&r=pn^vmDqQA`W!jzV=&cR<}p!f|$VY8$(1=LJaQGX86U^Rz) z;jo{)gmewf1*2v>iRO<{jtjo-rDQ5ixQUPH+ql5SNMcY(PqG3)bD3!_^*YExT4`?G z7nLbhOW>@muz30Fa}6`cBv-urjA~9 zygeGNJn>oO)v57FrKqG=pM#M$$_}QNXNiecP~rYL1sx!k-*k{g60cdQ z60=T~;CgtIraSje$K1Y^oT_Jbs7(1BdKKL3EJ`IGEDyT%&-@04wg6082hSH`om%g` z*M6`8a>9=bHBNsGzaL^Qz&j>)s@!FvCsbnAzmJXwDYc$|*al8?+swd`wgL1yhb%wE zB%Cft#M7bTzTa>$qyXg7psc{8MKx0e<$U&&U{3j+h{;gL%BQat2pJu7^(=d~i4Y*p zF-Hw)!xW-$f_ZOy-(B`o_uN0rs?s2iqJJ)0Nq;V}_h)Aldo+xSO33(EoH#Vaos2Jd z1_tjkHR{w`dq$n>U)?Y1kr-ay8QSu2>H?#!1}>-3u_>Hai|_u{S2f-0^DZSJoQA)i zop!A3@QkL=hK3U;ou@OXT5WFZjl8w}w63-NQhLSNdP z6{0ia`4_ICN&qAZk6!9XB}$tZ@_CGoq_T-`7!11Us0tXd#Dx#*OHoYo1%Xe9b0;wj znrx!PsPT=t6FW!6izB^Ey{LP}f4 zSlhf_2ED05GHid-DZ5h}>TlJeQX?>GLYv<>dQ8qGW0{Q_F!FUuNVBoztr!P+*e<)T zGU4f(;z7}4tSyoa^Y!$E)OAL=O#}Z;GA@#L1rMFULh%cN0S95ihL4E0s!ux3E*n2k`MjBWJqaa>>X3O*_MThWmd_TbJd(&z6u zXLtSQfuvx*cI6tzt)R|^#jNXd!lKVr8tMa5YbZpo9Ehu!`SCavGi)q&$#+|~>8|L< zE!W4SY;0#p(w@idzK9ThrmMhE1yUGL{cOZjT!owKU9#)zGngHUy=UlERh=2P2A>ob zJ$+2<9Qwcsz0Xx@M%N0U&^1j?p2QUlwFZ+-C?({LH_DqVIR8LxxPtv)TaloY*w4K~R>Qc;r!E}{oiuHg=F{oB+c$a`HbQ)SN0{lW;EVOg z1CXdHkO;>W0@d$IS$V^o-{u{OPt}$+tR4i7s)~f?$)t`IgMlVq*0RPr4UyLt-4VAj z$A&RRl)%4baU5x`C<=yCZzS$=KstV8)>VPRC4S5jK?G#Q+GU`6I=N(z(Bnt~hJ9Iq zgI+dZg&6KZrXC^jq|Ud=U17S@u~Aa)zpT|$mr3YdeGv$!c@>l4psat9HINB<%_(hE zi2qb@qaSB|`N^P4T0i(<`FwC(;+PQy;8T%bTuNIMTKcWILX9vbg*&j%-cPgqFlv}{ z&2{+iUPPYbKy>EF;GUVJ$M=??<;YG}pv-KJL|91z(heu$uy(J-2!Hlm4ni`pax@riQV4lU^ym{BOt!v&oE~t$HQu&U@*WwnXmN0LHIno;}4V zk7nZdOn3iUe8i3k0ern?>K(Xv1iCs}lmYRx0b1%;%euuL;@AESXW2B|Zo(p)8MF8L zw|%zY-aOVgomDSf~yqGaOpQ<&}EPJnY9b@I+Y-w><{(p#|w ziR5iyEujdFp1XdJ>O0{b@mdnx01|IUaqVV9Pi`onr@?Z%gLgEDH@?5DPkE#<*c7NC z6vc6Zv{H_xS&;Si!U517=IB7@E0C?hE|P$;Z%Igx8TN-Kh<6*&BQsS2zA_gO#F42% zfF>mMp`UPq6M==g^s5rXfgDy0g7eWG7=GJG8E zE3l3vD6-r!c2grJo;ZBx+p{&llS_Ktgt~Bn!*BldJ?>gRyKYNZ+R12vTxPR54;~eu zE1tyFJ9)aMX^nW|o64e_N3t$;XfGr^^&baoH{1a z`z=tDqLQs#(`N4&fggRec(mBz4tW=#xMD6=Zxz~u;GQT!zF$VqT=hxkZ028@9Dp@F zJ9g3`k(I@upbp)kWayc(5+x(8)^Y)%6b;~DNC=#YOEy~S@06XHx8eBMa}-%}CeNS$ zoVdaOx1e{~oIB_AE8@!W9K3ZfCdK}>$XmMpA7kreO3=5BJN4-o5AJ8;NrofWWP?J1 zvT=D4rM@Hz%T}EFKf<@oVs}?cD3wpTz5K9!20?CbJlFKvc0yicpNUEtzv3zQ-)M}@ zI_tTJy||Gcte+(r5+`fRbj`aHwCk>)#~Q)Kqpld=tW4(^i`1M|+;#$eJazI=K}r!{j034SU6g`i8%-!s1XqQz&b}I+BD9b zHHN3!3fjDT_soZw?rUZ6&Wb< zXB#xE$V7H;uG3i7x9bu#rATL9{L`BZ9W~e<{Ce$vQ8AOI&4U2lE@(;SI> zT7GJl2VINMIq^=T@ircyOY_gZtPEmP5eY~0=}-kvDMzHX3q2y{m6?)~IVAjd{$h1d zR^~${WjSW;Q^Fh_S;1`Hh)epZr6Mt%?w?iF%^mTZvg11u=mrF!?K$@IgibxlOWD5y zl#he!ah7GA4!8?BN^6&e-GlRWvX=5r*xZamkcEu6lxGb&{^6lnok14ijQ!C1QiZb( z0bh82?|*x~6D7H$ut_(|mKGcyqLoowUn<$^Vl3Y8Uj02C2gZ8Hm5?xz(|LY}2(u}T6qt_YBoDLc zM8X-`{)Q82#)(kp9m%nwqaKWri_t`y92AzUc-hP_jzlq}F0ltR5Yy*yKb0-W=}&7HU;hmj=29PiXmg_9 znS4*NDle2hZE;=**59Wv12quB@;}{p!?5NcT=c)CEzc4Yit?k&_uIE|lv#Bb(*PoY zDK7ql4|Axq8X?$bTL$;D+X)uWWLjYL$Xd4H@3RD@F58O3E#5&TzD8^BT@6@VuIHiC zj4O)zC7hP=1|w2GRXe0XoN@T#;kepGAT<`{sAM=q^0MJ*Uc)^Td zG*m6+G(X&x2nZqjPYWSAK+1}b2Bd2P{S2aB0EMlP-0Dq=zJQ9u*Bk&8cCb5*QqkaU zf#oGb&dr(16Woi{rjc8yXbH*BcovGZAF%ItiabM4!~6?^ox<>YBzqjGvOAYbM>Cc9 zDR)!Y?v>c4uY>Yl9HGvjgBMh|Nc~Z|5E(bNDNHfs*B7=TPdvrQ@%9|`z(XUlT?Jr) zvAOsOF~6H^i$Dco9BeWkNgRdhig50x1*gpR)b5^TcnnC3 zxCw=Otzn?aI%<&Yaqv?Q&hKmLh#C%M^*U!~?5|irlo0v<|5gFtK7^rqZ1K__JL#_+ zQI|WLC$tTW!K7{0BK5T^u8L7zI#RTRydU;=K|%`ke1&T0@vAtgy6g)>NEY~S`@N!V|*PZqR(@7~Hh%JS;GXS>;;v^%L zNy)+xtNww^9n!FvUt5+(>KcCCo?=+|Ln(=eE&jwck9%Xm)k|S^@wz2!lN&H`vTByJ zvae}82V@|w`R4{XdfJOcWZRP4Kwc!WVE@n_z{}jMj^f;AIHk|m{5Yv z3N^{ub6RK2Bxf~DWurOFao0S*PABOCrEdU)YE9c-c+H!$O*tl}7Eshao=BJ$j zAO_jhN*@@a)5o6aQ+|DYQ&2YEDCiT}Uf9FhaC`bfVPMcs}HzaE_8Dw*1w z0XYfy3FPpoI=iS$pc7A0264Wi#Gre{t-5T(U$X<$2YyU8;*Sw-pwsHPteK*-gIsD} z4?O=rv%}SMLxhjqjT5YY705okQAC;~8dR9I>bC>)qgB!c4AMm~(0ahRt)zqJVNPlW z`oN)Qn0w%7hgp-}L^)W9r6KZGOOs zr)rn};_zdi)goM^^#cXuHc8AXgM-WI?nOCu1wTUzhGiUn8j|mXMF1ph3$21D$o0Yr ze;g+iwKg^2*+6yseyaEjoX#&2-XU_euU{oEOI53LJWZ(^ArJhR9?o2ud*;zZJZJPF ztET+BB#7I>Nbh5@@XF#LfwQC>nA?x;Y7daDkJnwRm^LX-SOi%`zg^weMvo8WU>(+t$S9+b+KUGduTcOS1pUMmIz7ldz?bdk3a zJ`e989qcB{wuyPU=7wkMLO2Bu_onH1y)|!s&oG9~`)dNxVB)_!4fG*E*w2 z_@J(nq2*AEXM9OQw@9R%y!bXxuMmjN;~X#>t^g(4eZWG|8_={ z8rhdHtK`s?f2v9t)ldE!qL~z8o0P|BLDwHB7`-^q53u{%;wdq#iaAy!H{8Z$<&5w1 zt?%J+p&LsWE(yMy@3M5g=ObI+vw}p(DOnW$b0v(9!}evYNmhyh#h)sebsrS&wP^Aa zXm?4$x-4Mgr6n5Kr_I8mSh?>Fn|d?OVg5RAk(ei!@^rITu|nU498}F2@lXjZ*cW^F zL1X+|&hQ|ujFH!M*X7l$C|R7>iy(hV0%10JyH%+@6*HLQ>$sCOBW1I(!wSJMOPQ!Y z7HQ7`=oM?V%HSL_A_!Jxz|Ea}yX9qvDM*AGd@FDK!71Ge=6)Gvkj&k-se|Ldl<4O| zk!^@%e3%mN&R;3WqAW+#dbGX`#;2hscSdC)0tPUO9$mlR=V2(ZDo$ zDb8ZCXUXlPII8ilu&d zj%dMw*`S=_3%)2L65=5IKWDWIl3L2wp-fVGJGu=6ht_0&Lv-UHj_px@NHIsMEXh6= z#Yoqi*(f5sKVOvLi6bzX%*?@wdmOn^v$d zLf!bv8AqO-A!;Fe?b$|ekLwc-p$bqlGC~C3IK#^i3_?Km62b3Ba9^U?n_TTgvkp0u zdQqS6uxGVEr*ZTU{YK%BdxV_Q+;ptgJINTbbz=yE)`Vx3KB2pBQQzRb@>N*`ZHYY! zp46o1kXyC3x>81zh^InNglJ?|2y*2iF_)21_cap5NvT!mrxLwd7S*dWZ!)VbQCxNq zF4-d&%9GMd^QzjhnI2H|Grpv#1?-M8xXxvSG{jKZ(*%#1-XQv^{LG0Jw!5fhi$ z&}ZoOz+&o;z>`|xr0zD!JK;q3QJMM*p(ZEQ-Y*~tBNB^o3n`R9Mmd7v&1&seZ#KnK z49gEB$;^6&G7Ml<^@}s!<4hmj3}vuJ(K8fi(;l`3yDdhv|5OgVFv<+6K20PD&I zu0WeVqG8@1s$? z_zzmo`p;J#t<>4;Bjyi-5%d~P3jY#fa|V(uLlcm^Rppb=O(~c@U!P!0IumutD76n* z>(``w55{igKTT3v5*jT&!CsUa-#eZ5PC6o`HHS>fFj4v?q2FAZ@cWQ9RvX~EGUmd` z5;m%`NmCs_*hTx3-^))D^{83B4> zwbI8XdIncFF3wMYQ4o6355X5S1c@89c6uXfpQ{`|M^V}9dt41K`K28-_P%Kb3imTEDzWmiZA(J!7S5NEUD{l1oEKKzC8N{x^Oiry|)hv!? znleDiaT^jg=s+F0eMxfI+-yY*O(UK(>+3Y$3I^*RyI_DKYo)Snmq`1r zXx9rNs?hfV0ycsi=UIUHTK(f0v`!~zWi$fZs}nK7?n!X(y(I@9u+vZ%(;Y_m=Z1zd z)npxKMkM-Oepi~LcCV+Q_fC`M>`$U+O^Xef>CzsP81;8JH<3~C>QRX_;RcapyGXli z%6xxIx$X?Lc^*A{H45Kq+&WppOVlTAtP6dc(9vVhUs}%!&!ie=jok=w>NpYuEl$|CGgf7*TT zX&2)%P_J9e1sJ={8y1B*#^-1t^Q^gk7^iuUCAD27=ZzPrsHT3iVt(QCg_X-recn&Y zB=m8ZjYIX}DepwRZZ+A1$FT)0H_pC&uuI&eFSdxL8h{+{t09@gPR6v)TWVPsxd$TM zC(;StlM{a&4ZxLl)#+(`d5dtY)CRRg9M2(cD9JP*MSKq_8Fd6nE}#(-?v;g_>=|qS zzVj^tD-N%9;wP271E|*CR{w4Ezp-Mbb;oedP{><7kB94Kb?GmysVLDiC$5L!0sHKb zbkc>zIox<+L;}9jPU3>>8Q@ln2+jh1Hu<3Ma9oIMl&nYGHzeg0t`Sz^!5^Xda(ssb z4|J(s4m5knX08aeR1@2~UyQmi3yL?Q>xjHrxsc4j2^k}+0ZjSSmRM977G!XXgQf@OJ}L>mdTabwCUuuII{>&4 ziHm*jt)FG@NjnA!B`9n47-YW4Q+e3I5KLe?d**P?alZ?iIr~Gg3QxXe9a*U}l{qWE zf{+UASxmw5H>AEa%(DKktyPDlL`_w>I=h@C%=cbictLxY09d$Npg*vV!}1P>*n>@# zkc0TumLA29=%F3IP0Q^9{Lqx@2V~*Flq_an$n%3Ik?Z1rEhKYRZ;Z9~L<~F^+TtQ`S=*Z%C|;gdIoY_7OtpyR>*QE(2{U>7i-bV=qhQ$A`s4-Z z(%HN!VAUMPJ;_|v%ba*~VvMj2(!&vvSZje+QcxZE`XOFG9Pg_|HKHW$Z-fzeF0ABo zGTIO;@ozB5+jh2miTGa-WaM?IFH3PBFWFFKJu2yf0j#v$s%PPfT^CQz@2uE|luEMS1$cg=s4eZZl^QxJunZ+I|ZpA z45~}?{}DimXr`dpO3-Il2FK2=2YShkk}t$G%iVCD-c)XL}uD)Y(w3_re4P2@dFbs9e zR-|ZYr735dFEafhB?ggiNMQ>ap@VzyGA2ILBJ6^NxT!4C^Yav49{-+uYnNv&EQIdq z`y5ks0yV_?2sKh)LDIz@_p+Elyc&h0v_TH>PexJrzNEgNIQ%;~D(mU}v?Y2gK*V$m zURqwEYKXO6iMQ&?`>f-^36<}}*AnUF2GgJdsqKp3xz>N#CdOKz=vuVf2vH-8ZuC zS!tu2PNmbD1CI`N@_fNk9}_1~bW{j&+{)!kAI^{yCYJpesAK9b;Zt}1e&wnrVg6T0 z&J#R{Tt2kv0%6HwpuPE`Z_3*Dnw9HM3~Wh!F^ARPAk39#e})eN?Skb1Kc2(DQsBK* zw89x71U_flY>9Z&qnVA8eUb8j3=$J((LK`rK0?q`vL>KCEhHf2?=!jiLfUeXN)s$Nn1wKp0 zH1xz$^L)2$Xj;f`#!YmHDx{QET7+hFsIr1HauL@)l_khGKw$WSlqz% z^pmw9j@3ylB1a`fuzs_*R6eIFdxd7WwqytUWby~MDjP1eU-UjOw1P;QI8Px?4ea5y z#T+HT)ka!^ z(4pXM(l|y7GCBLy_c_*&i}M|q`GT5VLStIFMg|n*(H+C4lmUL;HPY*5+PY*dEY5{s zwGZNS%J@D@>q47H0#MwOPREL%b+(^1JtY4tW|^(#BB7;*a?gkcJ4mU)+j6N2$U=M9)R@zrV}++%VAUQf$6yRDK=7e z?ce*U{X0&``UY&|%ofR^b2Gq3|MiFD4sEFv2WzG}*>U9mQ3DiG`xR2@t(1RH)8IF5 zBVsmd-L}`x1d7{>aLW4K7#Hlt5PqE(`Z?KaOxL-;$QI#a3;sA@kQ4%ZGUmH2rZUQlkjf^eivrr zeTjpdy*0g;7|n(GAMe?$z3SYV&2HV=w>{~^K7u51O+-h)T(Nm4v+P=&4hAxeZMV74 zZErt%XDPf0k+#k@I(g{8_S>VnFp5;X9}5dIPvB9q%-3#zgn*+BlO3M-q)V0fy6DlH zlL}uG;7$1=^g!RT$OazzznA4tSpF)6o^M);p}{B#ry4=*`#fkaS@6x=Rhq+G2? z7%p9(V5(j&EuK>UKfVG+YUd>dbf^J7^tl8+Pj3Srg#HNNo}D=ANO`=9aRzLQ)2cz{ zdezXdc^-^c6=X>vWR)v!>d-0j%`E#*@uJy0=skJK`-kcI81;>~Y)~jgS~o<16!0nvFKb_nq)NX8P*N;td6#MJnW0{8}XrG4;{D)*oIPmiU zyB(c;5o1f#x1}g}{iFQwg`{?TRCP)LKfA5o_w|`Q4FG1w{R`L1!8r(G`NYj_A#vVO z%H)Th@=aO*(F~#6|GUg{({eaEi>y7upV&U~rRuoZ?V&N`!L}zh)gcMuc1nHm98M?27&dz3FPPhd);_Bwa0fD4}efj4Mpq;kSkhuNhbv4p$pIT6%D?QYpzp7 zFxNb=xNyfGZ=14ZR@Je4vWmzEnT8FelIOWSIN*qBs4Rn-NqaY$h~4FF|C0 zyHf2rQ%je){QXtBM<+*r$-poi!PeLVC*};mDfOyKIujE9&UV!TTRlYuaxV7V9e4#q zuE@^b^-}c0zb`izbWw8AwI08tovY-$A3TCetHg|EX|RBgN8`Y##MtldgctH@mNy0>f5z@w0T2ph5XH zjNV>LpR3Sh9qa6sQjzIxtKkA%4CoGOP&?`<4IqiB-E2|vUR+ZB%45T#BZmM-6j;IW zqS8Ehy`c`BbQ$d_ zj{ZRYNS1otm03$siLp}*5HRERVNR%_5W_0{ovk)SK;ijC<6=*vp0(5P65^-ZSckb=o%DR z-ZBIPw}*x>C2buFNHt?#7pEHsdk`L?N$g`+2He*Zwcrtb5v$53vigK9fj8m*G$9TQ#%`+AH{i9ha7$y(I zwD^Z>fGVAlB+*4z)tEeKpfhXn@-h2H_wJS(hK0s`pA3UMv5^3ai&IkJF*rD`AQS&|fC(Q6%8S0kf-U#rz8{+} zXJG_|hsDb%pAH)YAVf3PbklpDJTK?4)GhuP%X+^O!|OA4D5`yqnuRZPD`B{4zt2^C z`t7+0)*e?t@eDt{b&_;pP~0apzCn1C3ORtl49DIBFEPnjIs4-5l)AY2_}usP9BW&#Ma|j{x=mV6=;UHV>&<^!3^7ZAoMv4Lz}`u_dYv76}>Mug~o|HM)QRiBvdj7HEt`_;epiQl0Up5t?jT`#zS`N6QQ=yppd_ zHJPXz0iLauV9wuOFxr12Uc-EAe8IMqhaGVUlZ>y5!Qy`MY=4(|j}fZeU$tH0K_8Y2 zT87yUHTgIL0Ppq}h%3V)&g-@`SSNkoxK>bXD4ynW(T^aHe*dYvAX+Eu;WeNZ1%HD} zODzlASlz0%#UbxEU#=%`839|s6g|1(0=g-qHln@8#z3{Fmp)8Nmw{P!f^FsKb zzEvaiK^ePEVelIjKu91Xes~U`;t{YkWBLs6Dhrqg+SSD7^YinK8Tk;bG~R0a_hs`~D8L%bwb z35SdlGJ;)_CiNJN4d%C}@-8p$$}we|c+l?E_P5WVPwU`>cV^V~=zsN}X@}U$>(cKX zj@XJ-Z08Jbn0a}7wMP*&IO3aJ)x@i^PZC3BJ;LyBz;LUMn{Qu@%kv6RQ`v8HDM!$r zrmAwgu;|DgFOjEC-*0~h*0V0e6P7^9+5pWcgcRBrytafT z59dF`l9{shP;N0QQXI8^(I$F^e4aWQdE#E`f-({y+dc8=!q8C$C8r;*LI$&!0?Lf5xN?f+To7n|B4)Ai?4X8< zW%>>YrM#yPG*^a0a!iTSkvAE19aT?%Ih~O&dcK;eec8j7P$OGDmk0w+R!F5)JO7m} zKznheXp0Y_axJvA5nnMZ<43p}RYAhhNKsN$s-)VU_)5$KI4B3U^%GpOS1m1ab&zwp z`P3%b!hM5Y362VQQFRib}ZeP(Nyc_K@* z1BHVrjHp-)>j!i3AjbknP5GkYx~~ylux+LY1}5n*c_uJZJz=dTF0*M z$WD88B>?om1_0k4*>~~xp1feIQMDHV0U+3`9aFD_r6AV>4^F6{`0^gZKbjik(DQJl z__E;VAf(0OXC2^zkD*c+aU1eHDwNZVfxoZsrA;7-aI47#!v>8e9hp1WRu5&K8hoON zq_2BG{cZf6L}meD1>1*ohx%T61I=@7;97phmY&^A9Lhhqn<7z#&x-63*hA>oLzwI& zSPSq^C(;VS%h9ZXy&tkKHj(1t)4Wvwtc`b9R|xvV=^Y-=97g_#5Ax-*$BNh!;dhNG z4w1}9ZOrfywxPGaaGV&_K(A8&`}_6d&KL}GbUg{x^2kJp4;^JhH_Kxq!J`oZW%evp zE#ujr!6Pok#4~r)!4|Nwwz&FNok|Q(x)@qa2{w#v3fr=lc9#6{dGax@^Op}ibw5tNPy68-xS2`@Sd@(%t z77euVUT%9uTpcn)U)Mjh2*N3o$4oPy(LJs$0Xml_2OuR#2wV5e7rM+_;FZU(DkECZ zaLeg8$#M{8X}81I936h`oxFQ3ViG39`{a+s2KRdPYs>5lcVrMwGdc>Nn_KJkQ?zh6 zfadwpL2Fb}dft-O*Unm*of#Y03w2neaHwy>XebxA7H`OgW%y@y0HBYev10Lk*ra}L zg{KGn-z(0}Xc)0cJu3k|(8_GevC;DH>|#>+^vLVv{Q^z7vX)dSpz7(?W*^F<@AwjI zRF97R?wz;7_)wQAUyOGbU193&?Nw>F=BT3~QKvPQ(rZn8?l~BoGTb(3 z{?F|av%f+{+eb;tLH!aT;T5jBC6?ns?g2a23GlH}=d6>iX;8=F%^1*M++0MXmX}}% zS?>@+ENbYAaPju6^hXgBtuV1deLiH>l)B{w z10*nSB6`so-@Q{_ry@x2Gkss9cwdUy7rq&7&6#>7>v|7{P3Ausr(H(cX4(N<-&gdi zbD*p9-^{8WU&5|a?fX2#v=Sla}cB5pt z)vH_TcYc$*0M3E>!N1a8AUJpSzJ2yX7kjRTd3N3|5Op|GMcc;X221`Cmr)gKTdwMQ-7b|ATw~@p@+?NqMG?9`^|kPb|1YPMabY zcEh8+M}z0qeQn-*=od?`k!cch07;^&H?s0ttj;n8{b)@R^+Uii%o|_#vm~x4cr8*0 zBwek5C8qR`Vt|f#xkw95db9HAnhuHe9Udw^c?m7cik|slG0dm_VVtSp- z?~i_P&w_Lm+fC4h(iDQZ|MTKpaJ~1sS}EshmsJE*XxmQUsI>V%2Qgy0Cv};~o^y(V z6|>66Lyk~%WiZo=5En<~6CLd;pKu#o6y9D#nq!)Yq3JgGEa_0XQr~+5zr+~HRk_U- z%`{7;l0jUl6Oc`99HXwitcs5$N1+IeTJ(NG&NtSR)MkfCm@e1L@QzcSM$nl=WC`i~r|wmH#H-ZsL#&amY)%}< zV{a8RV%Px9PTR=blcaYSJ%IQ2MAyoj@F$bK+S#obcAzQ<9>D2I&6cR~Xc{)Cwc-I9 zht|Lk)BTqVTpEMg`d=H3Zp=UdefP>ggmK^HYoMzYnsz)N>!)I~4`nM0(`TAc+|1MY z=fR-OD_bixAC5IQDPtFyT(omg_hji4>=%&JGVv}%t6aGr;F{hE3`(rmik+x&H;Bh` zft5!6qBE^DYyh5@Y~zh6KqqbW)BsVx6deaLctOz0)p$cjDIf*7!kkXQEokwkN|Q+f z?v7CSl=kDRqFsH{aV4)keG)B#{T!^TxZrk1HFnp@wBb6H5%2>B^s${o6B23XWt zgotrJAhK{1UC$5_c<|Mhz@$0&v^%3xzQWQOoq}%*3=2j|X>vJeABn1I)dk*mG69N$tV=nrJqM%~F;J#j3sEe}&& z&LARFlZ$AJ6{0$A3~aG+;6)k}P*I>ET)9Hq_INHi;U&^Cb^?bRIO=*zhhHiNfT_lX;|-aiXHA*<7$%VJQhQy(AkozG$k)VT%{fA^d_`#Fz?4atFm$~(4HRJJ zL1ii8*pEQ4hb?AVL3nC>Pu1k56@)j?LGms-g8hqSkCI{iL5rN*bI|>Dom3MJtkN zupc{XSOm{}p*EWGC+DnG(K)-Z7Zj9Q%42nJ-IjdL=O+xnu_TXQ^Ej96>TlY@M6i`e z8_fucKw?Md5_Yo(QX8|;=MSh9cK{N%e$2SQ%M%XpX2^Mh_r()qQh>PujAvijqf6e$aot$b?fIy6(<#W~sXy z$Q5=%p8Ni4VDRTGm;1JlM(x?$tY8$&>Wrizi!wowwlhvCBA*(dfQNg!sX^faL0KY? z{g~SW#z{y}QM3vaAE4JC%u~g*9GR2K)xD?JW=~y@1$Kz~CNjk=LC)z8JUYO}UgN9U zHzaocP==OTqhg>Je4Vawk23^mtK@aYT$wJsI3-}5gGXqCpVNuXI?qhBj zEGG+^a9Xhu(&Yvo1)C?u-f}kn9V2*nvwoYKQX+)n=>S$AL^z=VXwKruawAr{i*qyK@(K3vp<;vTq-H@`h^nCIbJzF(Idk*8U%|$ z1#W>3T{2;0j^_$u01hSTCNenH5Rv}Az5G4Uvm>ONXA~gb|;a8g_@pHbsMag3*@#`00c*!P-WFH$Rb3-qwrwD9~pf9xs+ zBzL@*Ev9TpqUrq&ag-l!O}z%!`=`8xc?xFJJhD^ZdgpE2=gr@g(K(dR z2N`cB&Z#5!>kP^VG5xy8uIRa+OcK{g)4 zlG$~DN1p42k1TSB9rs)4kdexj@4tH`)AoDXD0+lPLtf*GZHhzaHg{$(WP4kOTVuMB zr8s&DR41%CW+_Q*s5{ zf_gq>rdunccBOZB0^roBTAp+xWJWRcCnL%Q)yEB@PRlM3CrDIbVT9A*YscLu9V9`I zpwT8F%hIUPoUgtAnUmHYn=E3{?R}~K@ghfHu;4apv{fs$aYFj%4Z{SifDxwY$Ju*r z)}lb{8b*cP$4bYo)dPsBwy~@P(W~Pghg3ec$)=Tw4|}aFPz2$2fYvzd8P79Q)WKH# zHpF|;W)2Aij5nXunyX7^&ENd!Sy{+GMf&>>K)^BF1$yGZbNszS{EpphKVn8-hp-9= z>)s>Iq@*@GQ1lkamM*`ekeKaO2=_5>)#5@L|BXV%q>T|T-Z$@LCmJn)z6D#viWy0R zq0_gSmtX{nuy)Twb4$|Bf6_9nfL~mY6y@lx(nzWg#~t55+l z!~9GNS?34RDe%XQ!m8vcB`G^7y5+Md@}>j_gnn(S3voXKy;@jVRc28d2rB55pTqfS zLNvg&pfMP-ox?4Js061Ls9D|1Jak`?_bnT*hLiG^(f2D~5^vL~A0eS?oC6Pzhl>dN zRRaCBSW;39BHqwa%u`!Pj`+QXZffwC&&!pZu&T*dlViESrkKSn5snv9%)|fI?cWeFNhc zpvbF3l4_Xga^+DiUGDBpiy`ExFQlgHTQT7L1W^==>H?eQ)xQsyRZvfk$$qkHV8N-s z@`l?+d8QBj6)<6H8ig6PCc=5sdq4U+32!JiC6@SCC)V5>zSywwj1r?|;4d|$YQn)I zD2oOocyS0P)?wOBc0G8WLf3OVNR=<>AyM z;nRS8Lk*S)e3@b@HyrR^<|1sf24Wc1K@ZVz5lq%fr$k2i)nKE?_4(4Pr=5nb;FI4| z(dso{<`i>W>y$X_xY0uT!4=ZU}rJ>htWn#7a53844Dl@RTNBs7M$> z4?G$sr4^t01S0SX;WcKa!ci5nOvZ*dp>@zn;bpVNcD`k^=jPa|N)fXTei?SPDB<1- zgvsy2NN_h`y$k@~5gaj`V^3=Xrya~46B8W-{*T2n>$L|z*yOx6r`STMsU3wk{1ly4 zENZ*N#-r7n=gh#WF|FL<5H~oZi6w994P>>e3ub}&Sjk(k03%F(QURiLz@%UdvDmM@ zXGAwx{dDmjrp-WqVeixT8h0-skjm8wTMY6PSgrh}%tKB~vS zLsgp2kjx-t1l>%qt3x$F<-nsQo6Lu{_>t9jPBe~;I|SsbpoU6Ye^Zb4yZ}!z-0QC( zmFVB%?k%Hpt&-QH+&los_jIP^fH}EU3kX8{V=m|+33(U{Djm881-#dRX}M18@4l>< z3DtJEEIbuH9g3JSY2`wu{IU$Vhx~Gjen=(xu*i-M&9Thkm|+_wkFz|hLg#IrDD)zs z!Lf6f=Z@h~6Xc<7qtC;=JE_!_M>N?y8!YiC82U^?aauvwXu`znfXmJm$R~Tf>CB$< zwk%4B#YUB_4lKU$xO@`EZ;zY=4gv+R7-0iTE5TDH`fv(NR`>hfYf8y2_b)XdQm^`B z)V5^}1~GmqaeWi4ti(5=O>7{0aycBh9iAo@0~g4y$X1~@m2Eu19+aGbPO_jE;{hny zVMbrnsYy3S6_|6eSZ%pVV0~&u*%Xo z3hpIU=Zo3*VZHV(lx&XDAWq=`biiPNxhtHnSK9>n5DU?;*#0dbbKNm`>3i9Cf2r*$ z<%K-fJSuF)gZR9bdS#4{Ivoxp65K22ae@q(Xa-=%9{7MQh$54x0}{#0YW~)$jFHo*x#)+CFx+pJYU-goje*B3Mxy4?%wzP zc?3=mc!~^;e82`S(j!XOD8jZuq&i|B)Qu%oNJswK*532m#?7H?B_9UAG;zmU7PQx4 zZvh=GiQs$=ljBxDDqWk|IBuKC(m5$Q+)?m#T*{ZBwY_Az@=Jr1|4%*{OkJim6FG_6 zE_R$0(Q;&K*DHd`K0FAPKnTSHjr@Yt%p&Kv`z6hz`AZR>42`C1?Yo{Xea7)+I4V8H z*3A9R{x<&nGA_G+HY-X zrF_B8hBag-W~6#a3Y+Ulypt@xXRg(6%b8Z)b1*39zTiSq#O&^`)}y;h9@WVrYu|Qk zdP5DCFSavM{~edmjsijSKU9*(HKY+bbQxw21cJv8zW5xnKR4Y@s9{>hrxT?(b1{_7 zWjz^~YXYAMD)I%qmQvE^-!Km%;g?Kt9G@Q_uPoL#0vJTsZQLrDdyTsTyOqm?_Ynil zqbVT`%MHgdC_e<WtabpxSa@!SH6$_p5E_Q*!!Cxe1E)xO8lAi?XBFOiOX~UF13Yzls9wd&3s z!S)i1+Rj#apaK@#_B0Di<^xxMeN!Ip5lBr_A!{FV?iu4BPL_)EY$W8a7_NzO!sv#Z zdyyg!n9vpTyqDBn26c&0y{%>QLT-~tbqW8hh!RM2$R-v1O7?a68d0OFcY0v^y zhGqe=v-qsRBe1Zf814Z#b8%_K(oq7ja2&^;zs4sE4UjOV!~M3mzrm^1WERr;;AG_P zVm_}L2=UL!iO!m2!I#M5$0E`X_}Ovl=o#X9^m6Z~#<3+p*;NbE3hq5pq0pCHI^0uI zA6fZc(BgYd!(knVP*2RaLz{60iZ1|PU-ly;A4i!gq>}=3FOhNqPIN^qSoN2hLB`A5 zN3SpYO9-r#)5rWK!;K)87dhaLvuk+8U+8JKmf(BV3Eiqcr!gabWFIGZYuC4RG%k`zDHiA`ue6EZa%K?`4t)UT*1`DZ;N+G zHr^Kkk7uoM)^E{8dX0JS86_hZnD0{^{SpH)I*Zj2-Z|88$kfGmsK0~u5*7XtZo0f|aJXR_hzr18)Dk9g6E0FzGulLGN`us+EgfMT+nG#^?UuMgUqNGr-@Z(TLUeh8Q2O(=-x>UuT6v-O!Y}CM zQAARK6{B8Gj40<2Pm!CVL|_tTEA9Mam{$>eoX?I7*7S!!p%JsIdFl)9QpXgILqDNQ zqgpG=W>uPhzIYX#XX=gQl|6z;2(a;qp#~xE zL#TH{25wk9YfLEXkde*z0z*eSdBt+u0qj?f6-GZeAqNxq#~Dh`-jH;nrPq2XD2A6} zirVLB{n~uQ)K;&+0Nq0dEv0CGZbD<2FZB%;h|}FfKcvt>ODP1W$|@bw>{7On);K(R zH6x2LO>E0;)JnNAVfBJ{wsJc;I1FwZ?5jYvWYahw@A%jiS1QL@@xRz|vAoSfm|qt2 zgD|Wxqd(D=udz&P#4gSjV{hc5h%l&hl<~#_?s2+=wQ3Tv!c^MPwv2t**Q99e7P(5e z*E@tPKu=x11l0_P1ylK~731qDNdmZfN!rO=R5tZ6lk@(6()b84rqBEIXKXwbF#q>D z2!siXZZaR`4z&28M7qBVZ3z7H<0;#^k@VitCOzvUAmqTYbHA1v=+m~EK#fZpomR6M z=FcQQ79acD{BHaX9X9>C42Ic)A-!Sc zi_PkOdzCxK3q5F|t}td;Lge8%(6nccO@kZWSm4chi&qdTd+<5i>y~ zG(}}i55+N|f^CBH8e;e(I0d+R$Tx_N%kWK%ejE`#HNa9lPv3){uu%UiXXfg#S&yq6 zc%y#$4t`Zf?Y=E#KN|0yy(e?Eg_2bigx(R(ROr;(TPeB)kYvYN?>IDlCKgN|ah?P# ztOnZR9oY%a9fRc$=zqZ}k`P1WzAve1FRrRF#$l$L)Id$KL9B%~TrpAeP`_;vve%fX zNx|`2(BU}V4*sVVXO%-tr~`N}S@)aeSLTbHkJHKA8LKJjjlL<`a^yV6*n7Mzt5gOb zk1S&DA>oJ*Un(z7Lh~_~gNFRKb$IPUKiCYYlbsQ?V>_TW@{d6oi=r-nWIDWGyhoq9 zIx$I-YqMB%t5a-FezfJNhus1+g8qt%-Bltqbu=&Y^=vpwWJ@YZ-x8dbVT$i6_I^ zjbhafl)@*>Q_*EtSzX_nYikei?IvU0Uv(>7r!cCa|+kjsH13_wQshy+q<)Htjo zY&;O9fC2<)+ngR#M+6z`IO%bg%K$?_yuVRv{L)nmnHLs3FgYMz;La#Se}!5iYDojD zp&|fe5)xhFpwsxVc(=ET#nIrNhgHN!N4ZJJPc*Y&uF5Z2!Bp}Hz3y4{t0=AbDN+Ep zzK#eP>DJ0u6j3J&PQJ9Hps`{rKR74k<|R_FL=vUiK4Ob6t)^fdiz7e_D6U4V(LhGJ(Foqk&qPeD=Zm z=~2Nf^I`j|lGh(Ep|3f@40AV5^fjU4+;j;>k57s3Mm)JAV(~izP0Hdc4kX2wXm{O^ zEWKH5^zPf3Eijpm|?$V(C|0zEULJ+7@rYbKp?h|UQ2iHo2^ z1Srz}DOOjS7Tnr2GFxKu8;r73@3U;TqPhxvsiI~_1Upk)WH4;%%~{V@V}I;|o&l41 zD0A5=vv%)_)Qglnj)JL*=!Pns_y-ieFhl}6u4F(+M;-&3l zX}I45*4;Y|fvg849P|ekooEJZoqn7sGCfO|;_Zy{x9*ODqgun%vul`;w)m71nmj7X zsI=7Y)3q^YhiOmTj(jsod=_E?DI|=Tq$R(p*QDB80)O(Wz}1{bHuueEZRD}&Hk~P3 zez$f7{y@utZ=bQ*61-$7_YFFy1nGhgbRf-k%{q>DTf2LtjXhB3 z&4nRIg@>jpAx_fTaORUHviD9V3D_-I(zPXxJin`wAVe+bTqh9Ag4sDLi9`<2LbdZ+ z1HtJuz}NlO#pAC&sO4XwR2jcV;f%gq-R4>rP}z`Ux&%48fX;1jaxeQOnbhq7!m={?(($FVtjRg1W;(*h>ZU&vHcffH zN&D`nKT0<)aR0J){(>HQ4DyZ~s{=}iL(c)&>4XHBh4A`UX0Mme$QAuZ?$$cGr_<>^ zuW!v2wWmL<#M+uhSHN7n^$Ep}=OuR3_MR*U57o zwW~k3U%fh;2&iGa@i(fL3>3XDF{x%{?OwF@5X(v(Z6!2_-GA_k_Bn5#vG$P9DrQ=( zxdT&C3az?1#jcW7`Va6pz-OYxhkI>r-rxgd+3uxXJ{4CKzuaPSa*;8W$1rgXShSD- zUhmHu!QkbiU!-4|nUB!IH=PGy389QKCI(JYg#7!Vw6jaajm_^Hp_i2Dg(#snGD2cD z!P4pea0iPuV)tI6TWC2rqq|jrbgy!s1iE-NJN4NivS8L}CMO(%DPL9;oRUaH zuIVSdk*$7pLeD((s%gh(?sd)AaKx^(L z$BaSY8uvs_qVXrxGRnqZ8ZFTKhvu)ij4~Eo?Q%aEPm53IYBPD9?~FR|x|&)=tw!S~ zj~-vJE+kaIY1qp*a=+8ig)inVD`ap^`m5MEV2oaCoxM%vw{lF#u>V12ZLKI-RCeaB zWZ~hzO-bd7@1mOK`}p(Rbrf2M^uVpK4sCLNS2%ca`y1J(~yv(Kkk%tsv4LCB7;-X~0>(>F9t!Th#h2`o? zq0oZDRciWYLgKnW4Fn#UQNIM_Z$dq>Br73v5uDg0tbE0E*H}|BJtOhhL4r!$@84r# z*EnwJ$=*W>scz{IiT&i@)qt{!LYv#1n<~?UY8va!?QnNoc9TsU6E9HTCA`KAXAGAd zh(N@ldGHMpUSqXS=3SC~?)|xnr16V%cP%(fpt?c!dzkyK&KP*?5%eYC{LES=ctgj^ z4B*5Gh6eK|0Hiw7PtPEjwCJ(tZ_U{Rs zFp&UFQur0VPAR{l9_r!Z83NS4#B7%?oo29uAGZpQL2D1S9jyQ6_(i;{RMr)Oqo&`3 z{-|Xi0>b*GY!rf{%Hd{f!(Yo-iE1p!3RB?a#saZmk^lfL@_@I5l&&ExYb<07>;Q{$ zYU$?KqKTCCI3u?3U`!PTZ4E95SZazJvGKue0$L3UazFMv1A`4lu#OHYCtyk1cs2DD zhFM#eAg5MB3Tq~4lj38vdt#=j{Ze+=V`USD#HfBZ1Le`NdT)#9YnVPpai()dLw4+8 zZQ!UZ2+M+ANhtlDNG%5?o{Kq-#l@g{nBN%Hv^cIyq#ji+aF=5*-rrC^0Ld4h=J~rg zb6o@TjQ$&~3tB6Gg|<@k_k0_xE%LB^xlB<6DnLC|{$6R!oqB(`$|7`PtmvmnEumv$ z!&dReEY-=7=?Bnj8U0Nvb>u(fKS~TmtoU3MIp)+~)SxRmYjAL_g*71~*A!ITYNLNv zos~YHbLU32Tt?{r?Q`5@pv8kHyuFR|RA7-F_XDQ>74nnJJ!z=A)2D`aBoFlKho!KaL~TaicKRQj61#7Yq;KLq8zwu2I>u%Re^QB((+~}I7u5VcX~Pbv zHMErohgLz$*Zo*`>_4q)0G6Ph?e`DD{^V?uAw=hW%%=8NrQVW=r=4$uoQ{N597Jqq z#eTlll8lV8VSby<#0KJRS=W9QrrbR+-f&yE^~vqJrN?kfzfWBWeH1TkA=K_bgKUNc?+tY2~^s#u&a{d(7RwF@z5J{sQ{@W#f5JvUW`xyRBB0Wno!>)Q?a z_78`J`In%ml55-51SqX&FR~oXE{-duzIJ?`)jq9msx{`pM~EM&NYp3BhU@r?oZ~B$ z*+iEaG+~S;4)Ah?{UpGM2%&zXtCX3@>jI6Esz^)NjM7<0lQ>|i?Es7!B>f(6wu}5A z|LRkV(kthdxhVa z-*}xSXxNQ>IsHad#Yco)pB!ZP^=j_{zJJ+XogLnHqtj4-TNp#5?!~>whb2Oa@B+^5 z;&{y34s)eG#Cwjrk$*>X-Shup5DKYL#nwX!&XTyt))2z?_mmhf--|n7tf1c_-|2@> z5lYs832z0_Usvio+fhS$C?$mi&o-gXgtDaP9A=RUzk&OhyH{FlaEH~x4~qtF&hkv- zPlf%eQ2Y774&S3`4;F>D$QcQUSqH~+0}C!96dAdd$1E&4Ob%%Huwr>?tC8W@1c1Ps z&(vNe`gplejpwZBr@0ui&A-Q~g`Xfz)@Q&F`Wp-lKUl*q@#xiL}_LYt)3eS3)2UI(=a2q$sjz#k=Eg zi}v?;BJax6nd5P_bVpOs`v8F7Ej161zXQY4n>{y0ssVu#CNIUBCAG!@>io5kcuJYl zSQU}_S9a71WBO)?hh|peB0~|Xaozs}e9V=3gIUQX=3#!v{4(PNwE!)jKS%GK{(JtS zTFjG5@3Nf}LKbMVF-Fr6GC6K|UbzC>`rgfmify8lh2IrJRh@`?M5fd+&)jZKlyDfK zjLCC1lxf4wdUFgPaoKx}h3cj#2NT%z={%;iTg4OiH^b&p8%4sB3md735qniE@Sjc+Hb6o(sSV# zMnEn3l&dD|`)#o-JeCCY&{&MJU5pHb3+9p;k77J_I~E^ zhvxcv=1B`F@C&%gySzlG8xsTwrtA|#{oIlLT%UI&))4(<7$P0#bbc}q|Fb2;NO5GoEMDLebyEfX^Ln}eIJyRUKjIf zkTbuHBXHjmaWJ%xmB|;n-jdswn&fJLEWZ{Y!G4m|o4|UmAmdiCOYfy|kjN41VX=`WMk<$j1XKFNwZUP+V9Z-!x_n5j^D! zGWKhOvK1LVLGTr@Y>K0nv*hj!z!@vq@-Qv`fDN|heEPA=?yQ_(3nH{|vjqe=6A7yk zB5xH&pU3}bIYz8s^;yE3VUiu}A?dunLzA)#{8sJS$KUQpxGJVuKz5E8JGnfNPMC+*pdT=d7iI+dL4?nVt)C!Bu1>&-w3)Zj1<#*F0kR@TN8ri5MWkMn zPR!d5#Z%W6Cusi(OGmdG8n-po^PUqj{U(Xvg<1Ul!NjiUQcdO)!>YV%!VXt-vrl+C zgPo(j1bB{5{>J#8@`wfiQMV31-EqK2aGlUw-jGHFL3#Oh1>&zpSos4Z&$wrRKv!Vc z1iN1$e(02j`$P14Aa_Hli=d=@a5nGuV_+A%BnD;r?Xq`OC9b}=(#s0n`#KWu!ZwMg z&us0gi-^d}(aAj?)opgG4};}aSpcFu6U;?fMPYL6Z6DZeln!_88qlq7?JhK8jWGub z_lQrGl3yk#5&M|AlS%hIrl_Gu9?On`+g*sqn$h7#Y9EA%d8KQ7@EyD#5rm$QUMj;M zPbMmK+yPGh)EGHJIzp#81+NU%xm~3N&IvmkSjP0fubU23h_^mYgVFshmO&iHM2$*hY@U@WGSnXLeay3Wxi+Ka6pa zWwIALt7P5-B2xvLznWQZqiY-vd9BvvLj!P-Za1BP-KRWXa7g++30F#4GT@NQ%6b7r z+cRd)Qt~=nq2}2DZ4_-VjW#h`+dzJzfe)xpa$j5~=P+xBdirk}P zi#)fW;gA8;M#ED1ta!4VFOYk+4=By|!PiTkw4LVK*REMa$j4v86mrAnWvz7iVXw(bJb$ zxxT-|lhfJ@))g(P{c{j~1zlGE!liT1{-X(MY;USc)>4qqFaPP8p-&2&8oixp#JU*R zG%}r+PJt{1tw*HIVM%^kiu}Kk#C<~qjm#{>pcX>uCDXA>Tqff}LhZ2PLuIvKebj^p z)%t!ONzvt`daJ~d40TbcE5a*2GnXU!|A=&Ze#RDwEN9P|;mtg6O0!F#IdUsgB zU2C3l*5-#*1@(1=U6-0DSjouwAxztx*O-O^^79-G<*haS*Es@-JF73bT!}9AY+|%I zZ;yq=e)-Z_#v8k~(U>6)n~otvSmIeJl8VBJbi6cIL$8){`M|2v1kze<^4fyox1=8R z75N>_n=H4`5Su)ANR~Q^IpBS(PI2{hTBc~dd?s0}Pyq2aUpXf}=1KcDX$(eXIHS}{ zhIAmh8!*$At;Ib_Hw#K4Jx2%Ko`;$5d^bIVVQ>}%D-%$DoiGq|M#$kTCUj3$qmltL z?GaqSAUL!{#bIS3P-JChN@BC#F}1)I^9Z6RPFeZY0x)99Z~owoKL|_ySAwlcL-h1oO)>- zUK51n{{eBRmk8NA*-ION(P+28O_pdhBiJ-L-Pcy5l*(7U|DDK-l&-wvOV7%2Hh=J*UE|f!z#K~ zzibEE*vn80oxB5`5i-k)Cm!Z}Px(#pM_Tpl<$KPhtc4cR8j!0a4+{ZzNThe(=o9zE z+S=0XEVyVmB#iQaY9G23oX)ny88lyra0*k61mXKI6ntRhZ4h_VSvlPgR*P-gv=*xD z>Ig$@FC}%dGv7^H{@AB0a_pHRX4rL5f`p1`e$=<4mW~RK{&bDovWECikV`TeGNC}9 zOrkfYq$PQb8FuXN_VGm=vaT~!R5&VGYUL6yj)K8S`f1iRc@}-_vnB2AC%ne78~PNz z2cR7;FTug5G8k+N9@ug$LYJcwsBh6CYh5s2y_e7H|JHWGQ1Y{0`%z(TcvbYV!x40k zqO)wo+^?P{13+N$#{px4 z<}&N1mLEKe{EMihhkhgznyWqxo01(QO`-v~d7?s;zQxsE4 z-+2T|XBujMIi&2+^3BfMO_{D2W9s!!n&6IWK-mX3*!k>0-l0_hQd9dV%bG88I$w)O zg~VC@@Tp-=3yG$|UPs90C!kgdPxe4bwn-=N;Wk*xu5^E3A*LCFU1~mDb^T^-kv$5pItS=~#tEz4$c$2Pq9Jbg2Cm zYxc>J%bZlVJ;IYGqD$V{Q8yZGb!kq+?wxu=@uc8j6`*$I6nCOsRsf*R271^O<2NEW zPF4UZj!we;rwTlyH6EFG>}c5#*SYFL)s)5wTHgrkxMyo@Z;janjZa@nYx+em9U&go z7BL5mhsigZI|(O!<3Cs)iPTWNt`qfgCnBJwCoI;bQSm{2g&2Vgnp~DLG<&Vj@v>Bj z>9Yx{X(Io*vM8*E5p(TwxUzSQpz7Lmm69*ST(M}O0lu>abJ$z8H*!f1ZADgelO;T- zP@Qse3mMz5+G#sN7(fbP%9thsIa!8QgvZ}C{0c4wvyF5)9&d%j_mG}@X#Q{vEU-42 z`#45@**&S)`87w4v#m*{)tri$*V_1=yWs@@El18`{QDWtHB@qyzzT2U5A4KfZ*!r; zlh<-S%&2GJ&ccMgBaAq3;XA#*nC%Wp7|B zOiVDy=~UWuI0czJe~fXg?JbRZRuX#rzvUl^P6&Jt;?#?p)u8e95Taiz?#wqO_a<#L zu?kA|zh4CC#{-P6Z-)5A;!e<0dsdUr4K!rv8~>j6|0IW{)7^j}XDKQ+J_7B;DR#ey z*e_ix0wC$8ay1O(FIF<$v z>SQFl8-KG!hIK1nQ&zL~Ha&MxQ(|-hRT!NvUjO8q&_4-(rhP@FPFd=t1i|kG(9J*X1%Dy}fXvTWa6{j$wC3wG35v71kJgnh_s8UzRPK*l>6E}M zesAg`ffM-qQ$;15L5&hm3nkbk>7|azJ1F%>K&Q1sXS-fLzC38dSoGIXtnedi2071} z<)h*QExO08m)Y0){gZE3ih&NCALl~dm_Rz-6!%vQVD-(9f^7t&;7(s3^KumA#FX6h zAp^s5aTUXfj~P;M&pO$cFp2=z~p@B3W9c=pvH$Ha}iZAJx2Y-|y_|4=WsheZCsS?@UBX zu6>kP%QQ4Vq?vj=R3C{cEESZ-8ff6m;eAv&(eFolvn(SkOhntQ{r=~94vN4o5&yK7 zkB^nAYfx9eboImtmkAfpuRELLv52iW%F76y&{mSfRm0 z@v41F{Dgzd9ZFwm0rbiGvQW0g(4O-)e_`YsSb_I7zzcs4ppVMIE|}p=ND3YSOH|pzyY)3*`i@5q(wd(GIwu zhsn7ZChhQHoIkd$6jT?TcmRPpmPSWO@1ZlfPThZD|1=aC5Q$P8ohF%S&4i-+M4=Eb zShZ(R{&6XKa%87)#Dx}5&F+YgX_I(*7Zr@SpNGgYdbe+ggovOmjD^!t0#^J;1mH^5 zc;{eYI{+&4A9P6L8`45{{B5)6-cU+Z2Rgy}fdpLzf+4|^Xz@!Mof>uv5XuqC)y~X! zccGFGU6%skGPvE}LRdFh*1O86PerFC3e@}P)W9GHW_~iD#77tM1M1jlUN_liJqpw{b7QEgpp5m}l%^yoT zs!DGD5gtK;Eh76i4K`ii#M3s<_X-vzz{y85>|jB0NCM&>_<)i}Q`uzbhRHy1o8>-h5GoFqT`AIo);&#t` zOTu1mxF8F98uMWh8_`A~PTosWIvR|NVX zi@>BQ8T&NOtbu5uX2j-<7%BNLQ}2L#{_BWFQl2v6rZ!u;Q8{W2=NlC#nn%-R&ic~0 zkV#WLLBe##ScxVcLwRj=U zX%==mBKwB>6((Cl!2t2D1$8~4L64OGC3AXVpgq2q2)lDymK-q(NjhJ2<6hZ{W%2fA zcmM$W?LcUN{$6w{j_py9rtk4E8hepyhhGXl-K=BH3E=e&|5R8n7g96@15;>QuC9m$(Ql zDU-(mE}w$@zC~c{*v}uPA6PYl$V?|+mha#dDhMAfYmb0$d15b?=4zFIr2gx|qySaU zZc*t^K2Nv;DsoC4TQOmlhUD~U0|{bjpcU701vGSPr4moY1>DbDV0UGSQXF9_Uo|5& zQP0(%3iGdz!5XDk1QtD^HpSADc8Vhf>^XMa+dn_|cgjjcy^C27S*DtZ}_oT6>pXXH*r@v$ZhmzL$ja5fr#x_E)?e+YF ze)xcPrEN%wCd^W%7;pRNlw!_~l8T;^%d-~|l&Gx9oXhkpSKB4j8UHg46tawpBkul4 z44XkA|A@!V;Us|cwbnk+?Zv1hlAp!go+h0=;SN2cc1X_{&O(J-ZF7~8Pjv;ksGS3z zMp0z{{(W=eE#LySJDmA;Z)#mMRC{~2rKoT=voG68un;e4;{1>AD@gEm#a@vF3^5=-e#iXI+Rncn}X0z_nfp5=s z;BSQOi#`57dsbk@2b*jRu)NcT)r!m5nh5M!3r$X_LN>k$IHc4xI})1jJE_Rnz$C&jpt?%e>ruyIM0M+K!kVRi0( zZaBoJ)}By7{~|$UzI6R?$;2#3oRuDP6ttTp080&=6yQw`I3YsjK}?v_(SAj}@AN@@ z;jipeljLP{=5Gl#g-3z1iO?cpGt_b(~Q-<#s|$(cG6k=>QpjbC$M_-)}y(Z zA&;>6WJDayZKmG^@|DDIjGmvcS6D85^=>lRV3PjlRm%yB%I4B+P9|w~zW~uT)V zw|rKWU)}R|5DVfyS)j3X^2I4k5-{ef68ZQ zmA-RJI-YBki1u;t`!L(rGb2?v$I)>1uq6UJOE??PYD_njVax2>NJ=xfdq1TCp3A@y zjlcb;l6@)YKD9MuLg=GTwU#W)wEctv+SpH(DZ z^KM|cK7Mx=NOWDi7_-R>zTZ|)`NBaxTnA9<{6&g7X>gN(%Qh0dSI~ns=I%l0%tUJZ zUcww*prkF^47x^Nhcx;{pOZ7t@? zrTGIH35z`N+&z3bQL@cYQ-a`DG}wqC4#KfmO_F#R=U$>i=L};1_%9buFof$r+;Y^H zoR(a&?WB>M91T7rilm@LtUpjUElnlZ`-B>MsFf5gQ!5SQ@Z`PsPW3PwX^A3BG4|fW zOV#~ghWN~pOes^SE5jKh0KkyC3fSNZMmT2AO~dOE!L=SEaJP5Ro_af=YU{<$-B10W zdZiQ%9Ocid2iPoxI&fg=5zj$&zHO#e-KIQ46TN%+GQtiDA4l=Y#U>Hr? zNw3%BGe6jNku4T&M*vP@bXwgcXhc}Dt}USO;d%lT^$YDOdIihZvV^>L|GbZ2%YesB zkR9{h5 zt5vE&!x6;I??ze60jlHh(N30UQ_lv3=U@hwtng+SIUNb*Jelth(u(e-IH>FCxsY+qW;r z#5pjznPyzQ-qC+i-sEUz?1E%at41y}Oz&Ce5v%b)Ip->L4lr6!i(gWV*I?i#f9~{}Srdri2mc z+{hp(9I6hzUb3iNw}6(&H-Z=x9cF5_s(&!Ak|nl6Bg|~Kmyt?FZ~>{g_CkQ)ETEk! zR=4ViWz&XNie67atk;3eBzFQDL^fx@N4l_-f9{XZ2u)MuE<MB65&NfO9axL3hcy_%EK9z@_klej@E93@+UXd>2pljNnG&9 zflb5~b%b?}L12*8HAVuh;pmWVv_+^GTG2W#6>s8;ZD8zT(Lww?1wk_nory$32GYFX~U@r_Hg`Scm@X{Cv@l%Jzr{z5jGwV_Th zm*WYW)h>mxyjmi`2*(kkT;Jdewf)LP0;Ntyi;l;0BpxqrrEgevB5#p^czktf_+7{2$xI^$*xr2>HY`#;V4J1Fo3DPm|#qf)H4a-quNUgdy>Eg0A`a$ zCyYhPXMP)cRH^^O^9sAlSHv!h?actH2yr$b$Nb1FeFB7+MO+&ga*Ag$bL_?z*OMM{ z1&-YY)ms%2*ChM*PE@id$~pI-UBcL$cW{;U=UL-W;|Tp~Kh=^~?KadA$ZBa9)z|v@ z^b`oP`bX+~4*#7meYG)aV9$Ni&N;D37H=-OnpWGj+77kh~hB{^%_}M*owy#D&6w`#H&?@BuJff6AdP1h_8*a zZ}PcdU&RY|h(AjT7K0IHgTp&xNp9Rb_+-e7`&pIvkVAYH&arzv(0-bE-a_az#FgSt znavs^AZYa)FnozfmpET&jw1O%?R;kea^Z5Ulc2gFO{dl(=Lo6#z|pi3K0BC1%Yeo z^6%x(IT?<$^4eFRblVTQcS&<~|C6j5afy?8od|`g?t{V=2QsFw2T5C27Z!djhGNn7 zU46|SOwa$##tI_1Qj1*#)0NGZI?+hat#@Kf*ij)h|CUt)+o^~%8V8aJdxP+rx=kM} zEhmI7Cvi?i*R66)U?}75Pa_8-(GN7El7%hcW{P=nS3j4{==#C}$`T;Xu z3a?%KnrFZH8;ZfT$O%{=NHn;Qe=)Y_E^3r3d9i0lWaDytm`TogELzv7G(Qf+2I8fxmh(Mxb-#o%7aY3@BNIRM68atMw?BhZq zGLmuRUxW#xZR*4UL6R1Td_Q9!Q#^>a+amS7oJoO&lqlYSVHLo=t9};V`wBPNELgw( z(BZjjbG3DxQB}cjG7+dVn9sa%{A0FD@*RH2@_106N}F?4r>f~pxe+h(tsWHv9gzt+ zA`FG5234!T-74X1$PThL3g=0|y&faU!vhK-{syPnXsyaB1 zq)4J4c%}jUf|6M0a=*G<&z31E@j4{KeQvuJh$vE$)~{Di4d3T$IaIHm*sq`f^tHwIw_hBf0Pt;o*)AfUkM#aNV|qt?eS*)P_)U0CGQPqy z9fRuH{8lD7*!{G)s%H@` znsfVghMf%^UEcvm*ux`t;a5U43y)kt6Y&|qdc~a^}vgT812I4WuTva zuVMowA?*AcCdZnB&26uRQ0T|>xri0dwoGK&y?Z?3OP&#hh7&AV7o*#!4SS^7poQoG zTdW;5co(xbjT@C6WqdLXIgyI*)!ejR^6L|^e-8;_k9}Z|IveIzWt8o` zV7(;mx$Yy`gQq`O8#Zr`-;R)t>7zfY?DLMRW(c*jIvD`8 zUj_@b!vrB66wSpZCjwE-1(&dzKCHX{{F9i`;E^IH)2(pm6L3PFfcx{RGmQISQ!Ir4 zi_|%~$pugSBUC!3hlBi`D8OOo);MU`#7+*b#0~MMHBbCxz|KZ#%-}^yI1nV%ba4u! zT9%>Dvb2Fnw1&!D(JaJPq!NTNI4C_(q(nJ2Uj&J)`ZHyF)7pG5;A;>X5C7rIr^9>y zvx%friy7js=NiC`w0B#@il|{h$2B%$KPRBKczuC;H9#YAzE?boQZH+C_oJv^d~z+QNn;UZClJuE7EB>t=*&x&G_mc_mTFeY zE3xg)!O_KH&Rv7zN2O`)SnaD$$N(wnRsoS@GGtSGE|fA9rq$W^eAu~A6O)Ruv)GEj zItEgz?M|30T_=-$1vf!U6e>EPOUp^5_bBJq7%Ye5H0vR=vBOf74IXZPBinOw#Z$K& zP|(vLrA(&mXC0%~@w@IPNRK7gpC>JB+v*Ugoq-`wmUkD-v?Y6d?k|x#q&=BQHZ2B- zBuxctV9c0$2uV=c>PIX{AlYgTVC!0{Gsy59N-7zM3UqEov(Z=H`XUZPBzqY2MHm`+3#**ByA^gE5hFl-sP#03p<&0164Sm`#RsnBMSld zFJ3{H99C*D>}?QT-dU~pj&t?L$3vMegmW~~&5;`V)l+}z%LjchMk5;wK8KzQ!mLHJ zriTD%QEM-7GpL*z@<9QN>~2bZ$6^zdz@N9wRJwP{Ua*`>wL!11D+>?UuM`o(kH#>m z-9av=H$5unHk$EjV~>y$tV@9Px`PpNAJz=8V{;*7Q?clD^at5mS(4nRX0+cwH*a$G zpnb4+>~|?-wbk`|EJ{@rf6B6|zRrK}k4>10Le{-Zr9-t_;A8R&0SsdnJ0OJ&n4q6K z=OZtD?k6@jvV}-{>DwDb(`PdSkOPW_HIKbQ2k! z<*kSuGz)GHxN_m59s6_!8ST0+{@GalIE|Uc-rR?x@c;th$M>meZ7Q0_$W&ViY+#nLj*>w`POFtJ~0TUbj8j*n+HRK(5zw5qscNviD^%B-v(ND^+Om-1vh8GCT zRNS|3Sfi@NechfX8G~bYzg#tBnQb!n1{1m)zB$uaPx!H_nYx~NPNDm`57|Ky2KlmM z@)PJV3Tb$nM$_z}wn0XNCdFGZ-z#0)he+J*3H`$OYy#l}hU9=>fFO)9>Fg|B8v{l| z4oI8k)H=#q%>ej##yHG}4R8}4UXnV5WE!;`ngRiYsfQnKL`PWjI5hB@p91`sj))b- z1;zZP5Z!JDgpB-)>vnp3ezBPiT65j-Yp3IxKSZ9$_{?h2bNipp=-SC*R&0NS1w~Yu zCh#^djh@`bp))=sEGIwwp$Pim4Lfu`st`F6$4Ftkc-(4|>G-|XNK;e$juPo47SA2` zQ%g5q*nOV&@CkZ=w0YZ_+jK-${x6G_eY5tV-?U2{IZlA5mQH)9uI`IKT{dGrbOUZ~ zR1_mnqe<_uXM82?^xL8;54(f<8|RuFcz~qMw$s(&m(^8NBFzhM)CVPt3P|9RlsfGM zz!`oN=vfSZ28L=zo4nDntkw3(m>9Q)eiI%Y@7nMfK``2-ZyJWIXRWF&$2R5BY<%IU1IA;+9JeSvZNKMBGS`?Jz!Cp~(eRi0JUS_S^2b5$ zJ>K!!V=e~6M#L>dNyF2FLS_FVsK2~U{6$W5yH80mPxG(s+Pj&uJ(35uns0!@R!Fk4 zH1|!i!ev+;8iN+H5mGXXo?vT(9Ad1gGc$B7gDIm*3M8Y6s^ShjItaHsES64+a2C&7 z43%ZIv2NUQTB&9;2cR$>bGBR7i7f|q%9a8OdmDZVZ^xK&}Q)}A^mBy zAfwz8q#~}x0Dxpf$rAbFh@VCWSs6b9c%zXY@;-u$S&Ua%FW|cB&OzUX+b<6wx>G+7 z55~gZ-$b&u)Y4sO`)PNpk5PU)(q-6QeF|n7_98e$SHZg5VdgaHkBwB>yPxxA2A@B7 z!sCsZ{YGL8Q3PhY{AxOKFCVEXvhdXSc=*&}`}TYWt2@PGqP1|J^yx99%+igt4B zx=E+0fcAFSUo+qRJS2@V5brcIcFH3j#)p)Sey6Ku8%xfmZkR-1DC5htKvX_0BQ$w6 z;x~x%#o!M8t$ZbeP;WQ_ zvKbBBnyNA@1_Rv%>s{XTs5D?}d*e+@(j9NkQ3r!N1!xtqB1!=UV;)EK4+^hUCc1%Q6i|DdZMaLIBRclu73-eia`7b?akFWJjYh7eZp(L!kuFMsq5yphwPw&w zu>^mwz!22ktr6>w zG=CWNN)D$1T)Bo&eDFRjP;Kd`Drb3tt>xd9x4?tJZ<#ARLwfJPWnMbeWLPoEEThZ; zGR9nk4ZqXFt93`poV=#1$_6{2B<=;{?E*X3O7(hAWS$*@H8H*rDMA}+9TGMRj_m~f zKgPVmlqQ9cl~UIg$jV|5fYsLKpmimYFw!3n#@@W#kwF~CIr{SvW+ zLEJ(U;$A?wO1d2W9qhum&SDk$%o?LN~uOy=(16xJ`TBLy2|ZFeR}`oxGi9Ro2TBN z$Nu~frC9rnTj^gK6aDaH0eWG^(ubjrp*H*3@(_}oJY^;FmEB+nb8(xPa@s#qhHE;9 zrf?v=L6SN#UR#8-<{ImE84a?gIpPyv^2aw-LkVpsz6e@{(iAwpWQ;L7RK-YujHc;celp^v~H{s2ipw!i8B zVN#!on^IVk;P1;?U50J=-I6TL3+bA@@tP-p43zILD#{%e;{E0Xr1pg@&gqwS}2Cs_VK=Wf+hdib}JDp>rJ|>Jmh~yBmNH~3%D1P zYcXWjjtDxGn9Khgl6}C6vS!j^O&7@W;alVZHGVUB$kK+& zTQ)>p(-4FmTJPz3|GrOyK}wn~&XHPBbfpTEndbPrMyG6dj0B&~(u|9RLNn9=Fr*{# zdeos)vH`4^)7?&(lhh6iE%wrFRc)Hr5|=G(`Xc?eT@W-sc9yz2NaxtC##@EVG#Vx( zcOzJN-d-8>b6Mbr~uC_~|Tv2BucQM84k%6!aBvt2PohU-Ca zmh`E5-jFiT$+@0P;R~PqaRpMWdD}zDf)xwTleCAcL8dr|UT6lrZfYrfZ4q3$)A6JO z*S=fRlTscjnsXc)ahRSKn6pi({5ehZ;IlwiTOMcw@U{@qz)YTT&k+@OHB>>Fh}5sY zGI0MQ{$L}oRFoF3<&xu236dG9-RjmGcr6KZe!a%xxp@2dzMU_Z0ovogQ7>nS2t#Uq zmU%322amNFguBf>AeL;x2D#_VCSHy`6b&?Z4bZX9y)V4EP7?}(GYXID5hS^2 z72)~(%(q%eV;;@K$K42n02PoiHXBlHme~(tGX<;{CoP1cM<;-nlBi3}IO~@)?oaNj z?ear+XEW5dcVV&aqs}yRB|Y^2VE*T_*Mj4 zT4ZdH$9$#-p@OK*QFa{WHRq79o^`h!8kVnS*)%qJgrf;QpC3pDB+kRsrgxWWCnQcz z;_yU9b=q_+G6@(RAB>Pg@3vO*Aw=ZZ2-e8*@xUeGw+`!_e>?nytG?LHKC$kghZYhL z5McbQdBLyOMRz3lZ#h-~pSDdB1g)+C4^$I~RxeqV536Zm|CTS1Byqn{O8{Iq*&}$1 zo33{Ap4LjmUr7(cwfIt>#pf!a7C5~qb5sPl8qWzpgO`y)FIW=a_U)eyGC9jPeEB5O zddFs)fXDCD+-=U8`(a*l&u+|CNl0lf2I2db3Y`DSWT!lT?4nMovG{enDK$NC>iN2r zbnD=`WoC%}y4*L&%vMx>vj`YcF)OK?=j?dFcT^gH&i(!)89;-kM6Vbb?G`E&)}fm` zC+JCz;EINOE1aw?Qwpr+j6xKuxJ!YTu>}6d?+u|Gtf_+7(IDTuWE~HKJDAt0k34z< z$?>|}uPK43_^gDb6FW)%`N^Hvh9U=CcfdYEk(VNWvbmal7K>!iLq}Vq7Im@tp$KSE zJ1d{&ca7S`Z9rrM?Z`*?ilGNHle6B^(^L6yjH*+Y-e{vk$wQ=+M{rKzk7H6v>7=3J zjPO7)YI$geaY`}RykCG^qcYH6`;Yg+%erWZsd*o2&>~>gv-^2>V&?VD7Hb`na!u0D z)ZRxfgD^i6fisq??4hai8TJ)yB>ly?GOi=nu=FNMxv*bTNI>qS{+GPNcmFGP>Tig? zWu5hU;>CQY8@84pRTkGy7*=#nKI6z8 z?n=rmW|Iv19967OA{^KHOByMnjty;55gp$B>I%k!1_&!X_=vpXqpdQeCVqthG)bK2 zE5n-#efTAbG&u+l+VD+O`5l{bdDider_LYsP0VBn7zm2+R$+-7pJa4o;-*V}P;2 z^m6;HuEL31ZNk9wnd(FO$ zo0Qt{gXZglA79r;_x?++^J(l&izlU7b+eA4!ni?(3vm!C4B{K{x?(VOXtrQzvx%K}kiQJoDI4VbON zx>AEDC&n-dlTf35-5pqVuPQlqGQp#rA2)H-iAsw7b2wRdg%(`5@{jLBx zUaysQCmh{}8lx6hafyt5Xxq^*0vf8*9Nl;i`{3$g{37lqLG_kkBj8XHjcbGULoehvwQ#zqKvHtsG5FACUr6-{o@lnbE&rHF(tI=1m%E$C60yyRK^{aA7(R65 zZ{&&`4=o@#5&X+Ln(^T;V}*~EJ^N9 z3&+z=xXTX>^ss~g&STf|1rhFrw*Xceg<8%6@N=3sy?i`i&m2CyrdqEtmA=TpLxS}Vo*qy~frmlGj9kH|61$P*J2(#ci>G?{JC?UcK)}mQ*ujsH;)? zNuz;wD}%*5)IW(UXRa3<&SRywUt+T<8x4uJG08|n|zxi=xF1G40pXa)G&R6 z%XdS8k}dzmxe3A!=llPw7=9W>#c@p=7H-H^$iigA^)#bG|0rp_H&;X+RoE@?u5SsnD>w9R3F_ z; zRr*KC#`4kI!6FEvy?&7qPvFLTSBwT8GWoLPI?5Uymg{@Y{oA%t))4JKu`E>3KwOgCHPk1{GL&l`~rVxf3|G^n491K0hCt( zOG~>Q(-SB(7MTCZ8uPeEwUAuXs)N=GfmznreHDA2Dd89lNROSxsZ+P9X26Zg-gjJG zDoZ!`8LomEp#o4BM*p>ECq6FDtU7Hm$7aj*fV@PkVd~k%nvq6MjGG0}NvYMc$(U{H zxOMLekI~*Kl7RAe0N}t&Y?TjX`A^MEDk!Jd^mw=sD5O2l>KSeRjBtA6#*xD;2u$X> z(ca#_d56_Z6)nc$RhMq0Y7*bV-Pni_kgB`Xp(NBiZ4CJgvey!N}4%8hy7IP4g2+;FX)JZIb9v`-#%YwS?V1FzC+iAXD?)_w|d_W zG*9T{eT1y;?mFS1sohs${^LNW<6BOE0gHe+TDBcFy(Mkxob)~5m_&eFgb@;HI;Fc& z%5p8p8eoy$&cM#$w#%TPVOVH|!^qiL3z%$U7YYv>0cPUa9(pz!U)w$k30*@3`UZ^r z1IACm|6pKh+1a|Qu{W~D_aYn{q{Q}G^7UP^W{6oV9+T2=K3cOzsR4<0PsI6gTXK%0 zzfr3=ItG2WZF85IYj$zBr1?_AL?H}vB~D;DV33Vyt+VoFx#0c8V4E$XKr>gtCHVic z(mV2G)Gve*zhg8t-NfR1(a@VUs95zl-eP1h_OCvB-diX1gQ1ACob=_8BGQ&5Tcg8% zAY?#6Ao;*2wn`fD>ahGkO^%k6ngWydr^jOrq-kd-vkIcWID+()+`P?`>J!o5xYK3= z<5EN~vW3*VSslC`bHIqW2Bk>_HCAA2R&{tM+T-HfjfKH!6f8sdE^;DK;fJLsXhqdy zT9ySbe4_ko{t%mXR}M(y@+MM=Zd-7JMwPU){R2E45n!MtRA~fQFPc99JEjH^;cFBK zSnh+WWBTu!(Bg-#z+6(B%MA;ew^jScgh4ZeeGwzvI#@IBu~7rllIHNAmH>3wWXGaS z7Hz$I;9NFHS(wdW9#>lCs5q(j0lyP^+QRtrK^-x#`TW)E4|w(~jcoiW9?drmW~lyS z?fxbEgd?g+2NoE=wvxt7b(z&&n@QgDXPOarh*yAL?uMHbfQY4c z>5ugMgYOh_;%M2YzAi5NGZFA5qc?ySim9^i!YW_-cmWy(@Z1z`f(21w@|%*225I^p z8qjYfO7%CDGsZ9l!#Pe>3IGvN+Aov6>ZrU?U8~GDq*;9Z zYPIgGMqV`mEh@X=Tyb@mRGR~idEEfR31;!7=W!!U*b?ugm7$ zvPiALI_WL(*4byNFw-%-X|sgDspUOIQ>z1&0XZO*qI2a9+y~oOYJ!}t*QMPb2iH32 zE~ouYYM>nur=bH#cIeij;}Pgf6(mb-u^K_X3)!)n6XN#gdSDfF5dF%5$quE1N0rur zD6~rI&iL;TG!)vjw4{{fCMq)~sHN_sclIQfXSPv6x>4DOJrngGqEWpGqoZ@LfuIT| zfGU|->cUiqAl%0uA)#pbaE&Yz@9cp+-Uf;|pEr9UKwod(dZd9?`E-0`E3|pv zZ)-v@5RIFE3O&D0mtS>2l~|1Q%f`x6*2stRpb~C;`3a2bE2n}c*kk#ylb0O6U)<^Q zEZ=bEj>Iz`crcLHuaz>cz(}8_$q8vGGiYulNSW7}V*?H15+&_>(mP!&7M$~wTfVa6#|AOUia3iOr31vQ;zjL>qE_F2mZ^=sW`M_SucfXti;g*ml(B2aNkIbO5e zlSC6rUt7MK{=BMc-x1gzY9e&{z2~lsHpSEvkf9x^x?)lVFiG3lW$M&s-BlfAVVr$n);-X39 zfH*Gmwzm!zjSb8bEZhf8nt?`YYe?9A2-a-qkF6~}DSg|4a}hYNQmS2q_FumgtA$-l z-Yz}Ol30h71#9XWeGj>D-_cO;^iXxL3+!{|U)00(3k@`D#aWy`5k zZc7=fFEjxk*w+mZ{EV1#)mz^^g6AQyFCP~MCw_|Q*L8DxW-ELX54ez>gzp2T`>(;G z2|8ikV8iWy)|`BpDdjH1zaXFy0#Z-(b6Y83 zYF_9E^pVR2KGus&VulhKED9wa8Y*^A_b zDU&{Cnk_8)RTrQDIcLY%-t{f&61YAm+AUbDUv#A$#vAn8=1UZ8NEq2AvLYj zSC)nn?c)FM4Uk-v-$Ri8(+m=s_S9N=Y88|H_bJlb5&G(|zi}av(6`%t*bsBeF8JoNFn!Fv+U-_#k%#DkRY9Vbfze}RQ zcx2m}bkvSPLr8{pZx;M(RZV=NI~14Ho`nDpZxwaS=svSf7GZ4kla|@{Y7c}5r-rv0 z`z))!q0flo?dcY#SGY@oX-Q@CD?3i=6lTQr*MGn-Wy!e4rw;L@*zTKWm8DfepH23B zxSH{PiA6xkG>)h4h%VO@;wl7&c`Z>twrXyfG%`WrtVD^ zte(@qoO42Xx5q*lrR-L>l-6-;F2}F5S{=D;j?i}vo|G<*g#Wx@Qb16|Mnv5y<&;xv zcBS4c7nq)(hr!xwwH&=rB;Sjp;3daR6M6A0hI#xj;t70n_xX=G_vIOxra*;c&Fa%t z-~`tXjp_(e0cl#f%8VdKCt_!7OFRmYZ*&N`nDKKbta$N;?ZOv;W&;1TS z#`Zq`pt{ZoQ)~@`b72!-><}6o(9+My|F`sk(&3{gw??+k1}Q6AXBb0BM4B1*zlmPH z^LZlbx+={LI!=r9JuIz`g}TMBe*8i{98WMV?t2(IQP#@P@Cy@|mrp7}^kO<}Yy(jl#`&EqW`1{{B-5_99FzcMh*FK_Hsjmg+72O2AUsTAmGo z_A_R=4;5!f#~_Lmi|6gdKC@H9Qjx0#cwl#ppI?m?ChwTkU!84L5pZ(eBS85ku8-W=F0$$0>C0ml=|rxF77 ziScnH6&1xIR;5efxxWj&%{2iXPVPuTML?&l`qT>G8NyQH$+Ru9^fe#+&#db&t zP2~lOy3+KlhxVw1TN08DHIXWAeoj9w-5^2_+oT?itW2=#$<+=a+>^ComJ^%)Kg*fh zD1ID;nt9ipR8VSmdZ@!e{}k)Zpy2a4WCA!CXtr_`cbo$g{VtSnXhzqu(XjJG%v2>4FO zo-lkX4hkJ{>H~PRLv5tJLGAf*i$%3fCe)3U+cnaa2I<7=>@sd#jRFN7KaK7Z#>)ou zJ+SnE9jx)OW>{KDnX#USxjFkx<(_ul5!>ZdZ!F@1Pi|@S=b>e-du1`0!X*4#)WlL) zA)bOCS&^Sq`(?)^*xY!%_AT`V z595pU<$Z2@t^@w)mvwviT!C~4Lsxnb%~x)C8v&w1_i~{3aS*~>sGpN7X&TN|J>aMxX4J|t;s&A+`YYfhMlQQ z+eLy=x5xgl_<-DkLG|BoYiGkcsXj7xRaH)q{O=@*jS{xVN0fgv6;o+G@|=6Q|AN>} zP#R$dv3&RQrvpSfZ7d5%B*U}UpCt6e#xdUJvoN}y{p#BJ)K?^fq zyUo7`gRai|g<{#`IBn~EIFdoP@~hX24 z37GL1yluA=*@G}RUl*twybi`WCbp$dh^Wx5u+qW2+nP`v1C6(!j( zr$s!kJMuhZCTvtNWzmZve){cOm+ZB@My%JQOzhi!jGe$tHfsghJ>;fhhqP(eJV29I zvcc~be@y9cv#x|OcCa?8$S4TDSMMn>ZNN@8*$zkYTGbpEE5@qEL@za((Z1Yf{EpV) z=g=%db9#mZM`es5bv?b_oOG(As-*`K0iNzC4i(7P1(mHxW$=^_JxZ%0Xx8nT#TmhQ z+GkGGrs6~G{@~5c1ax1-LObHeV~?}5J82Ozsiad zcCzKdORLfrc$GpPyE?dYsE2H>-_^x~pOSkHTSG85grM7CkH@7fV#0p$kWf~jEQvdZ zMp8C?udf|R%$wiNj^6t9=G35R6rafQou^dsuKDhpRgizd!-*@_yW+rJC}OR=wv*p6 zZ_H=9-M-;>x@c<10!b@fd=c@^1kTD?PPf9AFXI;-8=|!9U}f{;TohH&;Xm*oV)7A8 zavH@bw_3d7 zqBW`Jx=a|BID?!wk9G$YYq6+T+y~bAYmyXin1;=edsyuz{22V#Q3Whr@J$9`=Z51! z9h(*3oVx$JVbZeGPv?(U!~%uk1U;BV({z0F)5%Vc^)Vco-wj zl0YScZUcDAD8D;8_Dvq>XC&gY(d@vMR1qW&%+}EB>wj^ox@IW9BeUVxj&}N==WMtkPhjA!BH?ng2#K-P0vtUZ(BZ)sF*agaj=|N0hI3N5u%_A4rr zSV0jh9u5GwRiUC^eCsGV3?gRM*MonvBiFTYe~oKPuLJx?Z=Y+blB(6Ua$Gk?3-pHX z3ADw~?C(~y$upfNMD8C=>d>~gRTVI#zwic#!AI^{eW#l}T06Jw*&2~C=rS!KLftT( zE=azI;^XZs^Id1Hj{&2r{XYk%uE7G9V2@^T-c9V-KWg8r4OS8bP;NCoDiX&C+}NLX z{pdoyZ3coUJlmSCK{y*)i3q(3B6&n#J&-a2t*h0)HYt2fB8AlGZvTZUH$uPr?`q#Q zmxQ=e-1N)zk`voFyE8o7;Db5G56V3Cs;v8)YV2~?)%T#U1XMS6+Isq}V}rDHr+ACN zCexi49=3G5suI;ROA_h8t`6m=p?%X>yEj8ereg;Gwu3{DS#0n^be!aT`h*BWGAa$* z$RtU^#hAnN6gkgEjHSX{KaSQNLa+DhrkrnV`+|t%iAe?iOkv@TKgzVeMzvS;>YxBY*Ku`&b;PV$#-YCy(Ca`)eVEr>hjv)vx^4 zfa&^_ua%%(g_1$WkBXYM1Ii7;k)hWC=y*WuvV35z8D>0uHXbJ_$=69vMrqk=$gem8 zxRiRu*LA#kd_XwNMcZC4mFJbzizp54uSguAFy1SBZfW5&*L=!@wwUQ@nAJ?n;x%{z z5cDMEK+(56aM?!I+j2U=|jCN-asEW%2&A!jekZw0()vh z%_(+IO6zHJc@U{>7N8-KcTAq-D2%awK*MuMI>YnX5bTB)b)j`Y>_kPd@41bP*|2a@ zSpG-#A^r|g(Xu5XsL9JdW|B$a9>BUo34&%i^bM&_!Q1FFAj!5HqSJgNe9flO*xg5S z5>z#K+c5LO(19`o76`n$cVB7}nXRLQ^gqwBrWzDlvw_7}S;y!p-Ku+PmCI6!=_cAMT1v#{cyDjWGNcC^ATNYPPSAswGHb6#UssUtc z4Jj*FHS9esK?YM3&v=dxYOf@5FZcMGOawwyw zA&(I7KTc)jsQ5k?JtH1CV#Up!e7ir{Hhd}c`ZPH43hf5J<0%Mh8HuL-nXw0zrlU^S-ap3}=$V$FTJc%krhVAerQ%E6mT@f__46rZRaT&% z($(!9&Yb*asNhlUYxrh!R05$4URr6hdz#cPISZ2OZOSau@fz%A9_f+0W~$}mZ6Mq_ z5|X$4bN1&RK_OsVR0W*aqOVSTyy5Z@QQN2IQ4u9r+`oV9^H&5$$owFAC><|fwRRH= zn~Mp_-(NO1`K*uZp7yoiD+pV{>4Tl-zNt^2Aj8gapP4L5?s&lnG1iF^;eB)pUzXw9 zt;mz=#mQpl8JeEF*X8)*yx^ZtE-gX#XGm1+nw(2lapC$0QsR)ggy31{%+B53QSXh- zE7B(NNb#S+wi|lc7~0teP&_XSQ4V+|*O?Fmx`&@P)`}4~ktHFq1OM>Nqcwbl4GP^i z>UEsooVBhb)HM7o;3;CoPgSg10-~OrWo5D!W-0` z^LrU{4vYcjAK!D+hJVFc6Qm+|i)I@n5APK85m@(Ziqc{6sjBiGRy3PsGND7eG+VbHyOOwj6Vv)6HO0 zVIL&_yo`tQ%Vmizv{9*T1~9qI?J}7{jUsZ=v*;QzT8|vh1HA=I2H+|HNHqdt4*a46 zjb;Q)+%QXv^J`-t-RRY&W)A@zc6zvWCm|jU)zKkGJrI;axmlRc6{-{!+1PJo4?$jp z7Mi#oHBXx^q)B${pRHd1fM&^90bQz(J97~b+#9Zz1pBJRVIf>H4M8d}t%BEUsUMt)R;?=ch|UC`LLY%*gLQ_cGF z-g;GgV?>=x>#)i9oGb4*H>djXid|i1WmA`slS|pAU2HPelWL>5Rb7X{D-aB;Crm&79bo{3%uGJ-lpTsug09 z0E@p}NN_X8T`rt{sjypH#9evJy}w1l9O#br6;49+*N&YcX!h6_qG_lgFr?2y!HGJF zerJ&{8XC&9;SWKxRc79Dfi}F%Q#I${VY*jaa#9b7{QXD48#aR^`JZbpsg!GUlYOV} zdd|YDmruu>pV=(Wf3JRaPHaW5IXYSo98JX ze#A6WC-&YAnK{gR7cIp^KEH)oV7!a!dX1mpIFcGTvLzuD%Wcd2_xm(*Af--s77kn1 z55EK)^+l=T)D}LtGSJkBDLbvSPE%8Ht`@kJ zxP7lVBKF8Q7>%aDZ`UGa`0w)X0^)R8=7iJrWvp6rmGpq3hEIPzgb447pvv)NQ@%m= zOM>a^#c3Kp_-6(+%PYXnw9UaPbvizr>w*_`O~Y))f4jDLJrZR+(|0X{*$??Lc#9X# z)da0E?+O8Gx7Km(EMm)%^=Cw+&^f3ad$ZIu5%XjZOZN2O_Wl7pO>+1fNhyb2Uj0Q` zO`pgrx@}(t`^vLKT?Zu8zqq0N25CihxqNmhT&vrm!~y#IWRzfnS}d*rPz{(wmF+p@ zlbw)t2-915R_A)KI+!oV*;U z5E}(qsyvxMfGJ^iWY=&x71~zQABsf5C)8kYUnBDHVp`jR-j(uDWJCBKD zLcPD#Ef3dI7gPhv+=HiI<<8fu=9SQlV&{}HVqUSl?-dX`T`TGWalaMn2M-`oZ#3C~ zj`cWq1PB8qVZ8^YAyer^tSO=ag1nA_)+yLE{^2a|F427i^9PA{$X2K@5wGr18Qn5M zc&l3`d(=3BSZgv;59s7w!Dz($G^dx3~zkaM~yyN)O}N1Nzd0IHo1`&mAL z*QE!!R99*BPq4l{F)>xSp8-nZ43fbvOR${^tWWmlp_$z70Y>C``4dKE2r>d(dIWT& z0~z_05dVTLJm&TEGU;81`AidQU%o9g=^KH;8H_lWT0q5D=2cVPul49Wrq56uUV(iQ z*~2KhOM80eK@vdD=5Ed-Kld2^XJMixrzM|MV?RxyB$&@{4)W?N37q}eC$H=isU9;N zooBu)1T#j|GcS?W$l(VhGzhM9u@v66QZ|JlefE6#!C0Sop-`zBl(B8IM6Zh*%nlJy z(62W79}F_v_auXCfaBMe=8naHgX$Fupf&f*E-OSyCf`$d&Ti}i5F+GLJ3)-oRDZ4c z>HDp21I9uQI}U3lfJ<87td#=cNn=jRK*;k*P?e^KwOgLEYstxYlY|9?$n%p-5Y^CS zCvgoJ&~(dArp^-YtI?{tUEL!eEpRS&qe9kftHqbMZADgMdl~_M?a{PD(sPhgM;Ni; zySNdvzs^i6QB58+4t6YAWhzm+=>$Hl8ta8~-24g`Yv+Vx=c$Z%qfzI_1 z4x(Gh2?n#;K?F#Khfs}Is9gEnIzW9`{QTrlb1B=)Kr0Jgly=9s9zI|Rzi`jzP! zb31hp{YJS#t*I@lRhY%)&6u&B|3g@$13U$53L!8%i5m<|6-ZwLHEEaJU$@@t`VAkV zs$j1WM*2(o6fV|X7+@tdkq|bEnpwCb`tu2$QdGiFgsfVKfA5l`9L)Y@4(h%8y`E~c zx)2Olqjs>0`*3lTG%3+9xIkAE9TNx+cG4M9c-|(GfDS6iUcEcJ15Idh_w|}vv35Mj z%6XO9ez);m?@GC?JzE#!&ev8N@o0}^36!J6(st0opBZdbI^>CRA>`+syXV&au`Z}Y zsguT)#W_zxWVn(uZ)4xPX3^7CUkr>g*qeY)dEhoK<1=fEs{;RFNJyeV$o&iojbT4C zntBiPJ=i$ND5$o?c4vr%#@Yf+von0 zc+iQ`J1Zk1Rm|(j{qT-A#bWojhb|niyx*Ca=&k7y%3&&`f@agH-vA`+^rpWTY<~jM z2q_~=(O1^E+cV}EutK|wMrxl|w)b#=LS~osyAqjBT$k zWz=cOn_TRQZLE07g5o|x1Lm)X86#|4*@Ur|C$wJv4QhaDRY8qc>xEa-ja=7LgSS=Z;9=%awkn2(DAVx$>kPw zJ#zU%UhA46wMIL>BzTntdv*g2TAuXV!AiD+xBwl{@Kw^B1GuVn+Dr!C(C?iAes@K} z0oWu3!l%}tDl4%M`c^nv?-auN^VJN3Y(!yI%?*^08oGU3-QK$xc??ov2Aewsuo33D zRo`qTXD@R%90#b(>Y>B*bAhK1+tEYwz%Ul`0{P7RZjUgFqfcSi`g=j_wxa-&W}@{0 z#U%h%6DWhkIH@rZt_!5tjKFed8=`ag+sxjK_1{46X@f3~UQTm@YCNks7P^`#NhRZVSXpXRovr{Q%7ON z_Y-L$*sEZtSDf=69TwcIA6_R8Ufz1Xx?yyoZ^5=YlFHkF31%IDJw?_pQ{GQ>G9UuP zoi_pWN{M}diJf3yb^c;8UGvnc4Pf>U?`?_IUb$}0_aJFY`SZh?*PPDEF7#o1N=N@_7(y7 z#eaPY+)xwY1yhT}3&!>Ta{^I;$3^YzqC3w>|B*>&%+XnfCp)+1fz=Pu&JmF~G^w2d zYWt+ri@=y-3XnCshW$i60y#+jV-8H4LlLyhP+@}(=qN0zA`@C$KP=tlL%dujuHQZ6 z2f9oPRYu(olVKL-t=25+8B>2h|3HW3R(6O{Om;O0a$4kI<(k&Kf(#fq$at`wKCd}h z+8J|N#mJG@q^^>HoYs_R;>`c3mLN|&z=As38cT_hg4W{}OA4p>l?D3AYiUuee5#d#Kun1Hei)E{76&~yU4dohCF*zzUH+d81szdC+tW9; z^#MW6M+AI+ew=Iq^w<-L#jDD3NCrPyaJ_@X(h`C7;snG9+TNX3gVD3yUh^6ehAV%FMFWi2ndr2L?L1YlMp@e!cNg>@9U zNr_j1Q=%n9e=nu8AJHXOg8+U^!~+Y@x*-DW z#UN9SC!r_A*^$N7y%~;NxReBtfJlV5a0V~*CEeaO2f0N~>xhO2bHmd=ey03fMSmac zDr~kP__&WHDE{UGX`820;M78RjCw~n#+Kfkg_Sh#X5#XFs?iu>P5*@crD<}4shm-! z9Bzgufdriz#C|6_{|X{8aF+#Mk;C61fZ5r*s-_{b$&QoY8cjg52E)KfwnTDCB8-P? zz_R8>WgNC+Hw^(^Sch~!FPx7ON&)5VPaIlXmY2^Q__x}`$7^8p#5&`qGehxG zb|SZkR5fFSG9={L1~eBGXji&(8-8Wej3V9>liKnFEDCFUr%X$(o>6gjvNNxjBeOCUNJwmV+xOmk6WO}a=qrE89?@+3E>g+) z+a`u(fkhvagbbBVba&RV&h&zUN)1&%@&}#OXWh=P1@lWy1&IRabG=OO zEU`#(I6ZHM$9DscT+cdmp_^?B{mV>Dn>p&Fz4>?!P#C&CAzA5&`+b3lWVV^OD{+Ep zB|&_+T5C?M)HC)IBZy>R+a}76fmDdNPwT9LT08=PqWW7{5Fr-yU^D|RK?n^EnoL73 zB$FG+PF2DxE>ui;^z>i%^!eP+XkZqH$uQ*g77;S`c8s@*^r0?#`8vB?JIW&1tj19O zGm5uz$)ct0G)vW5fGz*qMO~~X$8tpEt@KbeZsFcQq@eX?ccy?X5{NaOGb_hePFE8* zA;Pkq195L1l#8R-qPYz$(`F>ra*VGXrqKe*f7WyY>^FOf#9*s+avv zI6pP_rKUW1>x$cZh|{V3GKl6XRUu%&RLUuzhtiMH8j?=wMORuCn|>4!Fxno0tWssK zP=M}qiw`PFls<_zEpb~a@lklm@2f-sW;I@01Px~aXy+U3I>i*i+rIXF?SIg#!jsoe z?*WGqu-U$REpPC{_abjh!{U!H>S$-lo55x>?&Fnx@0FzYU?tKwurBu9Bew6wjlyo) zxJYeZaY+9{{0;BI@0sjdk&0cJ8H(Xp2HGmO_$U=c2>T!J?9Dt(ae3Cr6{P(Xd0NYm zXxrm&5MN5TE!1WrI&4}vmPqHV5P-rG1%kc3=+9sN@OxStNClaVv2;Zue-ffTFg4x8 z*f`m;iZhVZv*s&FUkb`d;%gY%;e_N$X~)&wEo*FD;0V~SO-#e~-$US@qaP$zdYavZ z0(vTCJRl70SfTa5cX@sU;CJ#@DvIGun}rX&tnp_`6FO02`GMig={E<4J0cl92EYtr zf7qYiH=D-Qb*G#VI^8w1z^YRPBnu9v^7%e~^i6LokQNnlvZdsvO@6;GctthzpqSa` z@CUX%J;Q;ta577qOU8x+&8`xe4M|%AQN2id?(m?$K}fwm&6s4~Mr#+`O>4{w>xl<# z@!yJ$ErH-x-LK0Q=2AYA2>Mn;w<#=6;f7TkB94vDjr8|W^#dhS~u*i z7Ko43c)aX6Vcj83L3dA*wgxQy)#ct97sLW|Cb_`C=OS>10zX!;gsnLOtH~t?6JWpv zw&qHrak`w5i(rNtq)cgnLE=#t61P(*&RnjvTZOUQAoHK*1IQNl`Z86d3`=f+%x5)h zDAO|PdltLp50>@)vv%289IwanhmNQBYJjfFLf#uqO*hT~-DU?HtlqV6tNQG$rLM?u z0c?kSu~>~gSG#Z^&mw4k9eL}3jWWJ6z&ZMmA-YGz9-l9$?`gZ}-NC^wZ%U<61}cTf z5p&pC(R{n6RKDM@R|g6HTH)e>O*vwY)WF*nQ+00lQcI-T_l8a@wIXBJ_DMu^f10_( z;5?E=9tuCS`;GyOCP)AJkFI{g;Vgf4>NmN5c_wPBG#f=2lpE}W$Nj+v)JHif61}>H zq>ppsWQ!Jhi{*M+f_+;LJpdk2@Rt63@c)vKsNECwGqaK42kZPkHrwOH_p|JHd2R;W zgl=v>HuC{Mt?&Ei1Z%w^aVB;O8mE2E`X$T^AKmYEb?^b4bN8O=N)x*E(VtQ7^_UrI z+IcSR3!%Z8p3bq;HI$?$iJY}&B!hE?!Z+T^O4mbkI-P)gHR}J`G!iGM0y9+y3Ej%5 zNAkZ?veH@x#eyw~z%%sq{T{fH`>G*tTF?3V;pq0)4570Qq?Y|2^rxeIg3XG1EQ_|5 zMv)6|V`TY3s?w5nOnr;vy4F#92;+>t8f5d(TO_A(kHg3t2DpEc0ne6-Fq6Gtq%KX{ zg!d9k77QW#p*073#=z#|U3ST_&NEd%lQR7Qe0wRH_r@U&0GCPT;)gLiA>tfy;3V0$ z!EW)5l(kiYlCj;}!BLx3{L%<YfMEI+FU>hLVOr9(WxBv`qDGHcqSo;yG<|1Zb3@9jw0m|;~J;dB{6>;wGnL+ z-ItSkhBztpL1Q9r373`pwE=gu!m@^=iShM=tlAZW=<%Lv+npcQ-E&+H#=1soQsHgX zEd|Pv*6stVvcVig<<61U9~8JK@~y66uOY@^^x5zgT{L#=`UB)M+cp_({}vE?yHTKa zQ!bICAOu5HrW^eCv>e&sDPZ}Tpy*WPvVFFZ#Bjap{fG>vu1DdO2#-WOV=mZ)E z!>%J>7K$F4Vs0*AkS-sZlM-$WJmwbRorzcHtxmsF_QEOaTj|-pRs~zL8IQO) zbYNh~-h1pps{=V`IG6%nLBvt|b3aZaV*ue+T=yhk6^%ezHjUrarPc+1@?gTEGG%$+ zRwrwX26KM2VN`oNma5rC!V9CntAbKLQC4fPGk$Q3qvpJb^?vdY2WclG8>DoK>+5eq zyzuS9rtwdCXhYV@xv{}{_E1yraPeO0c}zB z#tI|N!qZE==}>fO)Pd*_TAm>-*r|a|J;&?XyU-T>Kt`nozg|{uB(^Zxh>(jpt`AF{ zCile~*mV?{R`=W6W5YZG8hrM+YvOGhzAAJMkV%^VvFsS{-xOYQrH+%37J2)UN8MO< zJu!@D-5P%Y!P_GpDPE#WN8X#HLis`BOk3Z1CSo$NFOs7vEihI)i#aCvN`=FmLvk#S z?kJa^t}(vKbmg0b&>{?{*|>w3Q*5;Ijf+r4JFh-|OCo2d3P7k`BIckWdpKgH2f+o3 z0t0$2!Hyh~_XqMsHXsxw1;+UjLIz3M64c;`MT&t(rWHvGma*eDNx={lW%O~^AB@e& z`D~7`9>bq@?+*PJ$1ga~c8#JEkT*ix+Jhc{1ORV$`@7Uly!m=K=sCApYFl9$f!3!s zfIpSye;*QAx4^uXOycflRd2Mv>eZS<550XNmC>#_2MXDVXX=jENTDxras_kMQ+PZi zKAdSV3p7s)2!+$g%aFIY z?N>UYN1};O;5!{qli)gc;0%>PXVFsUtXGmhZkW?lLK(T!Z3Sq&QQV144`Z!v{1Unz zOLlH4n4@Is`sR@}+?-Z@k%9x_r?&wFK_C&$@!>O#Oo-=#Ze<`!EN%;HvKtmYP0$T) zP?=B@^~@JY%PVRI`$>j?057_M`Mky6Z+HMffoJrjj<`d-OStIQerZLO#haP7fy0z;)_BbXY&(wWT(Ac_nR2n zf8*ifIi51`$4I29oK2<|06VVhrTW)y5A(t~m2Lxk+kMZ4F^h2@WxKYDs~k=tt$k@3 z`7KrU@}!IM=Xp`*NXw?AcdZBp=TwkNP6Dcb{DvhJnsb@>Xj0HV!Nhe;v|@Q1>oa4W7!icMZSD%7ISNLO9>_5-j87Rt+H_p;e0TP*gHF#Ze$BM^lQ8YC8|sBL zo~?9GVn^^5v{aIC?YT&Bi>EY>5Nom2IEFH9<(hP^w7$1Am;+l4?FDUhr(7o~4oVh~ z_*|j+TE6%G?S$9mw~%TWUyHcG50e_oIHYX8eEi`Jxg}do6oKD_Li~8=@IGvvA4V}u zjfguN_S`}Yr$deZjb~q`v$TxcjCk6JzSEUeXY-55ADY)(f2H-#;8!SLAm@NMq4fw4 zHoM@_WuDzi{2v3;5V`fypT@a+#HkoVhGI-`U-348Z7Nb zwYl$9Ve%Yq+Tv13h0zu`>+&Lr-TmnCWhS-zyx6qZPo|Jfg_=C8b!Cq1&WcAFf9fUH zDJ#ZImH!>8HBB2GwDHb_y22#l-TG@4SPG6(wjD0A*^W<23>R8&`#CGkjgN)Rp* zbjcPO*^OONj7ixwSeDSLl!{UFM9tvHl%Cd6^rQiN4rjrb$LVHG%Hv0ru8T9e(Rja_ zb%NqZ)XM(bgWn^v{61JQ?^(ncQGBQ%+s(On*S@tq(OjvANXfz-dW+%Da4O?hlpf7h z=l;$f(6%?qX1HN36LkbOXCPG&4C97C!l|Wot&u+aROuHYVW}4eKaU4Tcq=B8g{i5A zIAD4v{j}rk?*zrPa8ha41DmE{_VHq(uroq*c|hj3`~`AIAFPO_sxx)?fXGo9Sdb%x z1v>Rtl#*_iHRTiI9(hA)8;Ku2whpdm^@i#OEyO>Jdl3+k}HugNg;U@qVmVJ~XLx~eBzbv8qBYkO5Ns}dacBUaZG|4B$asyBcyh{9R@T4Qfrd&_-^6lXaoYrGYB zFcMvd9&%p);&Pr%sg(o#fIG^az$TPu%57%n@ zD;Iu#$bqG7E-ojQdF~GBb_zoR5DP&If`TRs1wHEgsuV(hrE^mQG3<<5BNy{L`)CsN6?Gu%%*eCu!z z`qL7;K>mwU?N*tlrIyQbY{zo&o&hfN8%#-Z_L8eAeo5Ht59^T1MRsJ1ZGhVe@l#ln zY&#m6ej9mrQS29b#?P(7OHz5DN&y2>78!Ewl-&OcxV0Y{R(in~Jnfi~OfaOF3lNAV z8*gH)*^tRR{>c=UrM(#BTEs&?8c!AQ94G+n@IVcNR%Mg3@EklBa_*wUYw!GDhid>$DJ3&0_KI)u0*;R(%WZk-D}A?Qe;;@&2No8 zuXs>*j$r&U$IW1lqTmwrc?ZRPDtVXpsph^pvk50^xUzLPS+9re#@?8JiOuotVB_6n z>Sl>y;i^xCP-s)&g1$?|^XLUA-mEAjC-6%{Bl+6__cPKS#G=Y_rcXdE0Q`yFlz|6u zV2looMPniTWaxf87;8&HXW0K3$OWX*t{*dfg&lQe?hqA5=18u>&F_i8C2*_#-;$m8 zEyPr|vFR!q2eZXj32UE3o4}HLvVVetvXPVvQSjnK z>8$p640(!>1eu|eB}R&EVwCf|Zk<7+{Pm@t1r3WjK5r!E83t?$>!3w*O$a_LPUJ@+}#@SMR3EdWeWdHf4ador6rdz&4_Bi~#=f=v;t^neO`RONN z;@Q9|Ai6_PrUn!v8nc+{g|xi6Ba6XuM;?E_1AU+nyl;~WAMh&A7#5p_%u?v)+k>B1 z6Z>5KWQW!+CAY7+_6Vo>50;fZ5-X$v$fUe66cctBK7lR%rB6vCZgZ1IH8q9k)v`EtMuB8>X1SXt4;oV3-!j?! zk9fnD!2p==WA#7&p^w#*OQNIAK;NYK1=X4`#i_MptCIe=6&A`JY*ush-qLTn51@a2 z)01i-VHH_IX)gg5PzjqPtfGm0{Is$)L_{yF4P+RMsuwN-)ey#%Z}*^_Vjxt$m&V78 z$vrqNxq$Z;_V5RA8)5eXv3mb&8|VP zW3`(Q_xq@GR)~g~pWi`1h_-QsKu1BLGyV9z43GclZ>nTAI=sxaw(0wCMcLZ^m;LE* zjIffff#cB(YtUr!Wl`YSZ!uFxRj3Znwa>@01Rvux@H?{Dk0ZYDHR+i2U1Qjjl`McR}p=0V+e-sjxrGK*m8m67gJ;2m(XY_McM=v-^ou0{^GOPj}sjY4HjGQR*lLlESn z5S8r!wF7wxL;#JEEn@?jsle5ri%mC$evQ_$LIwG;(B6{N$2sGjGOtVVn4Bd^V4x%w zUNBCj)I6rUVx{tOBYTM^w@bA;T8}K;Os*tRy(lB6T_a-uyCS!Tujz?qlq>dH@u&2~ zAN%gvY9ObZ4BMT#P;84j9u%b|*)VG~2jAw3E_S#`l2r?aAlyURE4ejmwn2K68aUz{ zYlzYRq_(GUdrZKIj2+8=Q9;l4^NVbcwl7laclJU2+iL*qr}BtZCV1s=^yU5nat?_o z{FwH?_plCk+iHqs$4=PJiHwm8koz^~pe=1W?^O%njY<%G32I$GN%qt2zur!+mE13! zlMcIsWYPQZ9X+1wC|mTl9SDE{7&|?4l?}Zmm8}S}Oo30_M*ej%0==Vm@z-iNwRPtD z3A021SwD@z9S;IWWgl=#ixbxetw^0Z@cVatCT}yx1Urt=M|-dX)9d4C2#U4_)|X9B ztHA)TX5~6PQ-9BYsc0T`uNF)?qv}Nk5n9oPK7aDf&;mG>j~UVD3UoK;00S;L!eoyw zS!aSIjk@UW^vB;eAW?X;g`d;n?9ED>)U|Hyq)N@-7p%^_06`wN6>i+2Ux%;s=Qm(c zAi6v?8%Wxk8W19Y9vYUZNq*z@Qa)yW-Q)*!&75}5+E%br#ltaW=aKbZnXY5crF?u0 z@pqdq1~J#r{KKmD@@M04gzUGj`?jM>64NtpV(oM4e+BwxndLg21rO2Q<}R@i%E!SbXLWw#gM6(a&Q-l!D$HAy52sFCn+HVq(2`>2+bNo*hN%S7erf` zS35sy!;m~$ISCb{HZ5gWS(~0er+(Bjq2Kc-P|I@AoY-1b9pJX|y0qZYCsz<0d&vkrx}1CP4pLUnf9H z17HnnFUTs{N7DJbjG$yydESGF7K}I=@p8MKl?~>v50wR{iov2yuniQ3Scr* z0`6%8p);lL3{(*WJ%BEECs2|O(@35YuREzabG%^@R@yI+26p^K<29)q&IiW<`Hm`v zQVWt<@dq5;+DaeD-pIBq=#K%Y7Iv3|M}*`{>V~(fMo!bCNh(Fi+ac!?uCrCyqLHI4 zAJoygE!>7uy5`8uFeM<+#EN?it3wmnE)unJ(Z!V*aFu^lb4;y_Z z0?&n2^5-D6K6nq5&b_T{I>}q(p#datPWxlqrWil=mC2S^Tj-I)U{>5{l66+2C^WmY?qK@j7A7jn<@KWTFTSeD^%~@S2=p>Kd4R&4`OPsX{wtCg`;B8q> zMDWDTG)P69qh3^B5u|75~komGB@^EVB@dXt~0@A4YbnkQTJ5W{lAq*Nf4(pNuvM7e_S({VV!*14ZF4$wt zE8}F9vp_K)?(`Ad-6TVPFpU%U7LCo&ZRx4{qP-Wc+30ZI;=D*x5m+S4-slj^ zvTA$YjR?!pF33i65o6A{lV#8Jor|E=n(?Gl*NZ&r1b1{1qr}33ViH}4V1#0L zxtt+fKPj)R`Of3Pa)(=Y-vvgi9rApUH(j~+tDXtYFqV<}&rdw(U*wSiX!iqy!MVf$ zg=4_M7%yg)XfajJf?W&+ZBJK@H>om?Hk^5UB>0=W%Z>R>{JeQu9l?O+?@vd~RzVO? z4;bOHAC0u8vNIys6T9Pnn{<~L;S>G`>WHfR>#l3Nkx9fudkZXTK`S#mb+2y^+O7@b!>4&lx-8z zIjjI5TpUQtkx4e_B|x1&1$Br>TEhiZavt|?nJt(*m+HIyoaPc?E>r|B4u79~M_Vp`?DTQa{PR5Ee2(rC!>>;s&XG)-ttT3Ysq=ZyFWMv%X-o!{Ce zMOw8zeGoO&nNt#Fqezy~G)j2dx@=z(*kxku_%p)tvdPq2ta8R{%pl*zHxpymx8UfW zHUH0c9IMN^`(d4nU!4@OQ4y229}70~RzcAA7dHBF)&sz139*+F)#bR(&)SuDtJ90x zXOvj?j}G6KSX|75`tqBn7m4WQtoE-^0!j`!35+IIqwf?dd1V(PH9XD78BMm19K4q} z;Y2Ik6eS$PcGNq-zeG15uCoD~i;;8X&pEl-tpb7+w`22H2MmcuEczZ$|3|iwTo|)j(!oJc8VQnb&keK>dfW;ivV;`st%7W0JR;;v^rk()&rPCRlB$ zONBhSuF(aB$|JmN=VNKA8e#>m(U~#d=_K?K{*Y9nQ(k490zG(m6D6mw8T2*Ku^R2i zNF+~2X;nzeXPW`8d|AnjBNSlckz#5GkgT5E&wn1Vv+jrF>TtZ5$QsJ4JPz3oY-t2n!=qhiDa z27iAmc&B^cD!qe%c}}v@DGSwVtrYeg&#-(+M^H}`$3N6VUCm?MU{vUAC~adsBdzsU zAw>Ph?H2A#P7KdLdUZ>#tkv6l1H&P#U-6OUyd-ssED4q{p>LT^BIL9M)rjPX>h=>m z;wB5~vp-I*hgd0Vx79g>R#0evanD&jRBD-F<`q7;+LZuO-^o)Y_&Hfp_5}EL&v{_i zOYS55YE~2P+;d*zFC-nS;<(ae5Y#rx(FrN?fveq{L@u7aHMA0O`;i6NQ zjfgJeu6GQKOmTmU_vo=4**TKrJ07M&%IEbsgthmApZ1>N-+<*8L?!PIA4+OL3E7!@zr`}3CoGwU2TtrehD($4+;Ril?%XavwhR@~j zA%{95!hUiroBc+vqwF^)Ej$`xD?QpnhV`0CHzC9wsxE2y1Xtimb9cCo9s}Q{+`yNr z^rhWaV5my6*E<)>mM_6YJiiuw#Y{|+t~2>J0S-~*>mVn%h)Hr^NhF-SYjsPlub9r3 zJk0lIs^`oPH1-VJ*GTE~-)GG&f`M_Zn`SGmc`5|9@LQ)>Wgu7j^gNe`Bx3friHL{8 zC^=zk{JM*;_^mfoCvUXjl>~V^OXX|JFPzK;wfI~gHu?r0+y9!0$Ymq-p9kX>bHNQs zS5XTZU^W)}Qkwm%ez@#PN6~`&ht8?!~Sb1xc7MSE*FDv^ZjIgbGh zd1#NXySjpMbrGm1HcCOS0 zkm|h#*B1JQY4jc6BiQw6TxxBa)=gu>_Hv70K{a5+dL)-7o~BWxw;qn?x(E#itQX{@ z<9ld%$=uspZ_w=dCa*AWc7OxhIp~7c3xM@>u4{eV7|&#o8>29O?)>zSveo1dAtXHD zX0)XkX<|`UVgbJ2s`<9zct2FtvkWu<*)sh+O^pb33hR?fypT*ql*}QcyL53M543o#i^4 z`^UE@DHcn7Fh_{S+a!lk);7myGkX4!KsXgD%hWj=1qfdZ^w`Zq^mTWP8dKs|QPuLa zxX@*{$e-y`0q(6mEzUOIF!&z}b$3%i9n$0l0>;&4^y(fqCqwl&c@snTC5T2vYQ{0A_3j`kV)e4dr zfTf9$Q{Wt$+$>oeZ_Y{mrs{#9K~xG)vbZ!xNmaZ&@U^=c3^C6%p=kzl}wO)f^5L4{6G(j zaGTQiqS&#DLRJ?-eLMX96M(c7f4cz=Vxer_v^DqamL>)qCXxU($qA16iw8chG+hfz zc0{gqUO&?{SViUMX!tSLgdL(9Et-P;N3<8$Wov4LtB0o(x-*_ks+4%*K(5m?5g8ji z>urNK+^0jc6R1srl07j{M=NA?epFqfrX4ZH648V#o+(R}4$2Ek*$6aWk-yc4)jMv; zayn;zcPpwN)}$=JHo+Q@r6a6bMW0wUj2`s0m=N=Gq<5JHbLz3UpuGU8i#p1UCY|GC z)iz6%iwQ2v_k<9V7uIh#qKOd!CpjAy`sE7#!VvOBGPdK(Ej<5N-9Ts z+y9-=FMwjeYR6Pg_=zuXI0&uby-Bk-5O3%_M+m6iigxYou6~hIeKErZv=3#$-X-vK zCw%IO1GC?e`I6Gy^i*omQ;sOh-J@B1ytd>mAmJXC*Pt%FATuKUv81;Qu_=$6>X;L~ zl1?5PO=*ixzV%iz0PpTon`9}XT{RGEV-XN>ThUN#j4YfyZQExfrXV2XlYYYBv^caI zCJc&2?0n8~)bhR-XZy7!WZC)NpC};xS3Y@&vt+7RE+!yu=3+4qkO|oTyU&kq*WnJN z+XhI@c8f#$)R9c2wK4hIF_ziof-<<)Ndv3Pp=Ye#>nQGdqd<0JOV^WaEwm`peE%5h zcVINds|fc{oXO!NXgjt)G1K$~j{olOdn2UpYnbDLv;dBj8U?QBB5SB|+^cu(=DXoV z5z}%!y?S&_lG5+@pv79tY1=8sZp?>CNms0cELsMgbmm^Z@%bzhh;i6KiJ@Pr3UeH$ zJ}gY7U99Z9CWbyDH2SmbH(hpykXv3~5bN-^p3^Zpi1s>+kTP##uf$sl)e>z&;7Ddl zh>T6%Ft5&er!tPiHd<;%{yu6 zEC||PLUe5kq$)*y+CFE5W#B_(uAg$r`~`vpEZ3fmVCd5x1#0dvrlIiQIfkQ(N);a7 zlcgV4h{zcgraXvGE)i7>?$KciPu-XjjX zT~4Zpu@%PDL7|P4QW3kL2792w+v1yUto6 zGOnHSidF(Tu1|CxJWcTag{60y6i zi4FC82idsj)b3|MJWoS470YI3eJE*I%t&vEp^`YVRGfFTLvd?7qJ7-OuR~iZ_;E46 zbX)tc#<-0>881wMa^%@9uNU{lv znFQqX)MdUGysXaH+z8Q${UA}{PbRT~1mtwdSl6DmhS0vC8YEAndfVH!xW6z~IdTiD z%B`jcW`+avQ#%%wmu4jry+;iIyQt1)Re)F(Ld-PnL}6W4tOt_PR`3Yw8w1{cRcGCg zBeYvrc4LVEP?J{b@nLNIV1LDuiwVEd8cL<>L2Q|X(X`uQK3)Dji`}vcw!{7?)8h8G zS#GIpk5k0KstB5~<@;T2sA)~cL){rG9c-C+E837j{r?Avw)9ti=s}%Wa?xw=E^96w zx_{nfmr+sa0w*!q?x2pL_^5QCQH2YQuWbE8|7@e*GQ;95tk9s|@RV7PwxOX9O*RF3CUF=4QjeNUetQ$r{@FKIOc z?p<2O9xOh`Lej^9I|$%|PN}ezy5h621DsXLrkyGt;o`htG1!3K8v)EyR$Dpgph%DNMx!=oRnflI)=;}~{ z5EGYn|KDMgOWhf-W(hY#$*Tj*IB# znU)6gL?dR)uQE4RorU6Q2s9U0^k)r6Yur|^us&;j~Ubr`!}c6_iD&U?4T~j;BotvDko_DT(%okEenbBLea( z;8|`>o*NwDPU%DQ-X??Z*eXl1{Tp0oNZs$hvb}=EewXMDLYkuj^#T8k5Y-WACS9EsKL<&>Z7ox^FIkQtR<@|lOxqor4L<@Ef>?oh&>n4VI zM5wU|(DmcOUSjMO4YYnR@b?EXeLgSPOSHt_IDEc@E!ffn07w6ETp|D$*p=~;xU}S? z&|Z~TwuXRKmAAV5nqMC~IB=**GR+kVep0-y;2vShqAcBz1A06|cLzr@(yT~?Mbz@% z>6eO|w;Ps`d@TMJ}-mXOboBp$%Vhco+_{@UgNVZ9ID}}PM z2T4BO*f7%)jT;mu_`wZ_m9P1n5z;7(3t%im=#|%{kiyc0JmTb7&>udLisW0F<%igSvvR^Z=Z?4aHhX$Y7td3@w54$bHW>PRV^`~G5`Dzev<5%7MH(&^V2A*9#75Nis+2wZ<{jhqVeR?GAu_pj z)YX`_jiZaruGc11B{6r&q{EB;3N8si;DR#bvj+=&`SM%0SZA-H7Z<)GtMp@nGv15@ zolzOY;0e_^W|@JDo?@#Z;v6WhYU9z9;CpZ5s6(s{&H3(o6iam&l?%OtSHV47<=$}_ z2uzWb7+dv7WDvKG3U{0k=IdhFc%^DnQxR=T6L6?mq3>b7Jh(;GMqLfOQf*9$DK=uI zQDn%s(|`G0V@pQ4hM-vVG$g~Ts@%=kv^Zwh>5QZ-Oe-OTG%HF38Yqcmhbefo0n`r} zRvr*>NBLkR10RkpRG!mbBzwCMXTeAyjcw-VWIf9fZk{p3e4D4#eN06_V+RQl+)`DC zY*r&5Nu5|TGH8{PxLAuT()sKunNBG!6g0C;V0>9nP#1CM5&KUVL)79*iKk+8y^e;l z!OnQzQvIYf{OFrAj-oZ-r?;;4fP)ICNv}bVoAfbE!(=yS{L0l%GD2KskCu-1vI7A1 zOQyQ&b% zR#oX~@K7#ds@(!G<5k3ff8=G@;qIg;my#1(+zh<^B*TDj=i@f@asF**BtsWQZ7^uz z1uFd`=KE6N!!LCBuuH<^f{R8T-XlkC>42#H*QVSI6W2Wldi3-ivi1V4OFpETXeO#M zTcstuGeQ-}dv3gmlL-6F5eXbW%7XC`cJ9EGyK9fz&5%{R51gASEml zwTLJIY6D19vNRIx=g3M8p0A7Fkkl1>n5=x=!$dgFw`D_+Ng?A#^#UPLme7qhF=y4# zvZ+{kCcne-i(UeaP%l#euJ2Ha&m8-+;-#?OSR^5G^`(j6|7&nqhdFgw&1WJ-de$zW z51f@9ib__~Vttt`{l(m;3C3RuV8l8_H?uSYIL=aEd~jgX8VHD5 zQ9m!3LQT~xH}M6d!O-10G2oBnC|m86k|RVe!YlIC?zu;D9@~jIA&j3C=iTUgGo3NP z+&Ah`37sMHu7xL0B)l6n)~i+oqwt&MAsJjBvAm8*RRmI|=TNl=Qx}WOsX(_salY3(?`Ep)PGd%}>W%e>iTc@w!-txsW(T z5UA&6$(#m+uM!4w%l-1-f}Fl=TqvD;_ObKuC_ z6lK8lYB+omgJpDX=h!B_7uNl3a-mSW;SK2nU((ewtoXM01>zu0lRbsI?ctKINkz_T{J7qRG>ZD-)dpOtHk zJfoX@gO4Q_V&-e7?S1!rD<);H7;5OTUNXRbRTFWsQV^IJm+w_fzd% zQq@P$@@A|3onfh72WCKH%;>Whi#k=x{hVKL71ee}B=EGEagwv`A>7rz!(PZ}Z{+}YX={(= zVVrqoF=RY7v7#Tfq}(WaW22FF0q9ho)BV`NK&={gpE1Db9B+J~4xd?hx;-sM&ptcN zDG5ri!5t;Aou9vsCo(wY;PL1ywRV)|g^{DX5w(N;&V(0UWnwo(j4tZ-k-|E)Q-&AS zh5EC?f=+dnG|R$$r;{y?A^ji}q%FW%le3?C)#46|oNr08oKD~sI)~@36bM(FfXc6n z_o)k$im*?WS31-GLF`!rAohi)%u8inFV zLIW78#%EFjshEbr*ZxTLnfPATqsABIS2N7YW$^TZf%?#+*Web`SwJq27Wbuk6AD!% zhXQhcgr6a52#DrUz+7C8nF?rr!mehMP1`>r=Vwu3tqT`p%#*DPgE|Ymy{49731b>P zyKgWy8dS#t^URESd9@QB={G0Et12}vu+ITfS)S4E!}kcpKy{{=jaOwAs^+fDo$*L$ zn#_TfmTZKNy^sSz+M6*|LS>a?&&U}>MxVBBmy@mb`A#lX^>2Kt*&^W!wZIVvHca|Y zjDMRU8F|OqJ)D?Ssc=TzthCuY1Vfg zuJSfzowI^qM4ejeO0rvi{<$G0K;`dmspS_l$xb)PIrcXTZyb|~29dv4aAP_CnP!^1 zWxs3$#US*PQCQCwOMCLV=L4N`Qi4c!8B*{PENqt4-nn5sC7^J=T)MmBBnH&zm6Mn) z;^(|(q8C4-&3KCl#)+|{YOpJ)9&!8Ezv zAopj-aTec0&9UvIc)aW)B9wC>w+rxPN>w!;@(eeb<(6Z-;UDPk{4ax>Fl&(ah3_JV zH_}NDrrAqMLq=c|x(=4HAhtM6$Px9TTwC_$Rl)21$DFw8cwVqsltXb}z9aAf?cCgt zQoP{Q7jG#kueowv<0oCRB(eD%Rd+A4+V>jG(-3+QPMcf88>-$4Ia*YH+)TqYok~}O z)uhp~ord*C7UqQ}EXD@t_Bt3w6^D`xU$zw`V&`G&fVIpib?DaADiY)oA~!kyhm$m= zEK2movyuLmFHKUoPdwT5M#X`!z;9A*EQJfJ5?TIl-CP;1E0~rcuDQ;Vd<~5A z{dKNSxoh(31sT#1V4g(6wHK%|T@BrY?YK__!d7%qjQA^IE}yDk3)G_80nA(&am;Rl zGfTU|?j6iuKoRkUzc-L_k?2gtrrgza8+>d>1cL@1X04OzxJ0}m{)TWR5A7seW+w+r9i+KI8TXVSHyXqsC4a_GU#yN6+R;XM?kp0Z;Jve8r8*4jAtNiAC5?uf~!9JF76B=TW$xy z);P00&^JvaGM#11+gDWs(RitLQ9L5lFlOJGt@G|6h|qtjZ+s%O2NtI@^8wmjT?CQrGH{Hx#5gzKo0{jtYqZUc!{yl^ z!xu}Fb;utXqRf;GKvxFpy+p6Cu}%F}|BOtRk7H0chld?Ufzu}LRq8`08^ne}S6?7r zt&KQ4#1$6A?4Om9eh<*0_M$N$6p-f|xaGw?e&nTQ!<_hn*L2<=pmBYXQfLuj= zxlv!PbgDQgMADr&hK&txfOr0G0&W`Hi;%K;bhi-@&%9xt2z4vQ0W}Hd&zywhr*3;! z%CYwAi9`hV1EFhr%CFO`d!Pa6nyW6(wezslQ;WcqPb?A$-{x{@$(x__S?o=%sdZi( zw~p0B83v`uZiwhbjjIu3 zqArnCufiE~m;&?6ByM|7u9Gf%F7h z?bxUr+G__0K|AOcFhCoRF+iTe;S07~4g$S%2<=Xk`qKoPhWvF$snHV57W3SeT4-rW zpNd6{cq@HueX%KiNC<-Ikt-x9%zxuj4q$CAPfJ zm1_;xlP%;Yy@Sai1c`x5-hdE4@;9$fa7fhK&a&Qvc!`?O;leAJ9{32mrn2;tqbp__ zvvza9hE~bv0Zhg4u$J$cCJNWNuiBLjKPNbOaj>)BxHh%;S=pM&5Mv+qJ~>l825r-R z7V{uc@ncB~?m`OOz#Bz&{$<~Cje4&9-Zb*VELtx{83Y}6SsB!4$jclIgbhhLF+di8 zaRl;j&QP3Juw(&u%#^Ui0(mxFL3X!QT|Xl4<0UAK9M${I?KgRHyvu7WxLOSsMX?-MPOX(xIECC0Fy5+_F^kwxqWZs$ z%EF~rm?!X+OMH%}u{dSIoaCnr>1XJA@H01$Hd@*nLb6BjX=`GgZgqGEr>N0y~@Hj0uSF0__&~D@WZn(SL#?RAl(TX#4^j<)Hm4aw=XIv;VLvTy~vU`Ij>|IN4!UCH)Zxet+38)Fse%)WgFu zD*16&Cruj39l*}4c@zDB%P(Wu8C;>Ji8n!1!)K0~du(^(3+J0;N4+=Qt#+wFqek5y zJ;3fCn8`YB!N0->M&`_@IUm}L6mKFg77u-Nl_zEF4_F7R_)f59CUS0I+p08Ab1JH2 zJW&@C;U9iMLgUpWUqDl3LBBNrC7sx6H<8r5uBcTuCkcY6D$4&$ zKfN-gCc;!3f3b(PCDC(FL^v?AN3}>{zFb&aCG&J4m|z~b(r|k{@+$-1vRu`#$GlAfM$l2i1;s<9$-hg`%ER5B1D5w0>U-yf z?yp`w(q%{`z{%V*w!mH|D50 zDcaif%9Z|uFQpc>8}8WV@>5P)+R6yOZ(0v+OmSJhBrGmaUQ|AI9tPBFmefg83OPo%^annv$4Lv`jDvz%QL+_C9Hlavef=xpa&tJsD>-_0D(heR z1(ggQ|2^JmjI152roz#45T8?G%tTDg8aK<{J;&FAdqR>yY}Hjehc+TbRIxVG0ZK4Y ztEiFQu6o1s^lQ{~u|v%qQOP)AQ{u~?%;7c5Ts0uN{Bdg`<68iimE3%->^1mZ;_)+6 z5Tr^3b~UBw!znl>9QpgRphpimZb{6}w3`7hNd==P61tB{l6hl7Rkp%E;1`r#!Xh-cLSHD7Xwc&>)%?z0UJfq>nTRWth z$-&+*R&k~~Lz(iN%gM~W#wBRf_!wkachYP_BCaXkHGdzT7jI(uSSxZpgX>%F033t^ zXW!P4i}{8kn;1e0B;Ml&nZ6+;DZKK_#alZ%Ts`^<{DhEtxMPeki@;zoQY7zSyX@dP z-?27K+60R+M8a9%CRd-;=GRN&gKM8v6KSh`dIYm01@|_Pn@)iKknZ?MEnTxl$Y)Q% z5GN58$lVzud!Gyx7Wa!yONEk`_Tfj23PV(+jZI6&RU(GIZ}bgVMvL@}Ij$q1NGg^B z7!Vk4RvoYv8DLmlA)0qVxasC{cH=E!*2UG;4(&|u?7(bnM}lhz+ltu&Gp5=?+>}c9 zqB~=_GXDI{R5}YY4nBA?)SQoX>aKfw9I-u6rspF!apetUQ^*z8j(&vv^k6Wei>Qj7 z7Yd+ZVS)<(sexO<__}f}#5~b4y%N~wxwbLth`{0KqM7zmL}A>>Fd1*5l&4>0CE0M{ zsC5HF7xrxO7o@ONqTQ^h2vkNSy~N=Kb4^p$^NIe=G7rZA52pR2ud3ML8fcPMgS*y&m=$6T8QiX0c|_1WA% zmH!Z&s5@#o;002zERu1BU6J+vBUT?RIO}-&_M@?QCf6u5CT99)k|SgCm7!`50V12c z?GAPN1J)2=EXU<`vG37@clBGkYJ!qDjZ)Oj?-iT%;ZQa=zH;VjV zjpB}FMnwd=u+EJ(KroWNsTUvj>A=yI>rE*niH}W3nWC&eO3L0hWZz`u)l00hYv1*Q z=>rVb+PdcJl=*qu_4wl_6LuRuO29XpbQ)-wlv-!c;Gdl%7&#GzHfRLJY!9}Hfp@b} zwd}FqpM4X%c!SPC2f`R&f~F6!FL!2F{dN?eSW@t-$H}bNm_wor!K&{jT+6W*V;B5Y zSnk2AhjkSSBSG@wfeiv8-w^n3q;Xqi!y3m(tidI~U=Q;9KkWAp&_Ta)-zph)zLtnf zSZLKCiQ4-x4V3juM`zug7#U=l*D@Kb1BkF{8~B_p|HWrTcLX$*G5>QBjGe)VccVVx zTQ}*n+M+qW|4Sy=*kS=;i((Pz&Y;R$8p>)srE-nW5)sOS@s0p5WEn|*@`3M%dVMoF zAN+P?nyA$w?eSH>lh0~wD@Oc(^={=H(>XFnH~Q0l;&xjKT7XMo9q(dE&V1kx)@1L8$cEm<796N5bqkFS$EIn!cGyiJ zX!z2&*#Gg4Me3J-ZIF+8_F1%ya)AOWA?xR>R%w4<5`~TOM*53oauYp>W_iHk>oxn` z*2rgmZQB`6yLGI2WS!vrffiOy@43k4-?xqjRe|@;=Ps5?tkn-&{|bvudejneVB3Ey zKtR&0X)1Q$8m_FOf#HQIbJ+2CS7nc1DHaeIT3%)PQQq^KSqFU3)k3h?=KaAfv4rGf zUbR^g8i!4ubd8D8<-k|m%`_Hw_Iab^o#pj4Cvn*=+h_>^z;ii z_jZc`4x<7N zgZ-9pBTDIS!lk@ip-s(m1K9f)-c2+|lQR#h^HXPyxRtX+l`yK*?+?+)_%vAabm`zv zG`T7H|3K{Iu3bT+CT^zuLsO`WYKpqm=2`6mnw@0Ji1tWWmvw(D|45j@%QIX^ zxaKr2Yf9g!%&c@fwl9I3yU26=ub1CV#HIgi0Z@YDi5WM!SCJkbmdXHA2V_`;e#oIP zck!Y=7}}=;1EwfLuf55uuN&dZt(Txd9InW<2HVL|Io-yq^ebEeL{7H*0H;L&y5!-U zxe*AXW(yDitqf8F9F|DO4AB)wJ8C2Fn*1?$eHRs*Xmn#c=$?Zt@x2iG6>O7DheH@p zW^Fv_`5*8?Tt{DyOd9W?nu*WW26k;}v<-?Hq~M*HdS$US2GmOke!^s)n_Vu*74Vo4H2@OG4Rnw^6R|W;`M$ zsO<4l!24VZl@5OW@QH@Lm!NtO6g(y2py7t?a%{AS^jSmXX73t%q}(Ex47YDl%HGi1 zc9p@k*XPk|mzjoF~R3~x`p2AnpNb`^)X+Qj(kPk>lX z=7%1m0k^*6=8aELV~nuSn1e^ke6a3=LK|_yRXJ!iUeVpe39*O+vnqF9$o)FDFGN0G zL<%7?iCS9)H>FC+OQZ!LCn}n}89?A)ZSwkda?XXIN*x!x5cy1T5Z6&74c414x$mDQ zIvBG>a94>Hqhw(UCVe2!^c74Gj_z9*bgNYD3XP2id|6knaSbQ)1Ak*k>a2Pl(EZ(g*<)Mq6}A)N9#*hxf-+K3)-6czF(3oemg47rm@EpK*` z8VCrL$z3zn84vjDvH^Cb2Ax-Xm*zN5Iw5#%Z3mTp-@WP1H~SPAVWE6aItl2&pW<9f zwiQUN{0fduzjX0dNKf=3e~JX4aM9T)M<@$@)_Mj1?@N8k2x;^E#RHn-68tH%;En^N z=RD_D_ZU`M4AGBOqABnG32z=~v`qonrrbKilrHceAR_^I;mg}UPCt_^wyX|s#(M{EjaUuWeOoCwYK+tcBhd+9qpTe>R zQg2@i{)c{yHD-3)S#yK6T|G(~QLbh|f+RC0UT0Ed$)45wKMzNg@;Fy_!b3`Co0p^CT6u+|F&hA|7*kGS)D>*e3~$Hp zjQc{@f$Mvl9SFL7B3NnuS(#ZOZ|I|!T~9bKyR{&Yu&d%E1)9YrLYsEpt1~p`5Mahj zhQVCwgrg`h$+}l5%)Nns5|7}H)9X;czIXT^0;KD}l$Wn4_E5m?xhB$hMi`C=AZRz1 zD}cyJ{TL7s-8eQzxj@;bRB)zex_W~LV7%(4$;b(FP9a*jI)tolu(xdrJG^?8k9%;T znEy7-Z~ru7sjkTi2W zP$(aH56w2)hljfVAg%en7#|5T4?4^4LAAOp;VC)e+N-C1)*uz#8vuTGD69^pj}?N>ADV%<5Z!SS6R1O`Ldhc_?v&8FWt)FKN~I+=gEKylwPZ z5^kyUwz0YMAU4-E>JlibO^2^huWW8XZ%DX5Irb)Ah+DF~&|M@Oxt}6go73N@(i^9X z{GFPWAN*b^s(SF#)vF7G#88~&&4K?D5l1infGa9#&l^=PYTprH=89oJcmq_b4Y#rr zzdTt5PO~lBi-w3J1VaON@}_X~x~%c|XPL?d!0oXw01~-D^_7hEHKd!K)?8Pj(0<;l zfl9oX#>$$TQuGnavbH2bwKo+XDQ3+dIt>g3N}TYSWxr{fzCluz>9CKT%d%~>EUN*_Vx|ccl(ZJuTUJ&Va3_XLdn8_3wI8z`Gje zPSs#x*qSFnc0XvQ@%^Gq$@gv>=@#xvcjSE#pkP0ar8UkjX-kGl`!3P-WyT&mtWz>r zeK8%GH(MstF%|z}gAtV&f$D)g-gTsn&6k6|T#W>_Q>qbjai^^f{ecI|0IHe;ncKmb zHtxuQUF77scCg)n^KDt1Xu?`Ly=~CKA*F{0#fUcI>Zj>=TNqoCeDj{^2C3X7bz}U; zsikG$x3V-Zhv#7}=7q#@LN4^1@E%(jYaMWWz-OU1Gq9Q4+z%6Q&!G2d<2;fC&K$nU zKP%?UI(^dd+A?MNiZr6q!?Ybf9MGpbq{k9u_4v2^7jCnY#o7U^NLa`=#B`3_F9x*) zvbu1SrEP&ech2jE?9oy7kpwqY_%SK}u+Mmbp(?7^XPra&587GvgGqrNA{s6B=9!`W zF77soAtxG$fW0q*Xn^Jj0a*&=>|>_N9Y66ryU8e=b&2FzOe6g8IUU2IMuAsz1W zT9=O>tttao+$Fe*;H0ua+$H{1f>f~p%qF~)x-|l?yj}*;F#`4HFOdIyFuz@P=8H&K zzCG!LM;bii;`ZM(j(JF1M$C<(0F{q{>4l_Yql#XsSg=t>G0< zoG5ydE0o>Ij6F=-nnY<7@D-(EJNsh5F6}B)c64lkn8K?10W`(n<0jLliNW96XnbmP zu}TEeEszdWK$02+uj;_O%9Nq=j1ug^HXJBDY7X{F5j5z7o4S%ja^;A9Ul6zT(ApnE zNlP)zhBEv1p1`@=rRwme(rg6!aJ;IvldFvoE%VN`*Hc zoe8jnpv_|c7pmJT)2UK(qdo$ngKqFVhmX&hL&~C`6HAt>V%I}|dg8EkL=hq^)ATD= z4pJQsh(Jkqlcv!pT-0nJ+Q5xKM-_W158mpN#Dl`PW2YF5s^-vzk!|Nharad{p)9yb zXPe}d4g?2M>gR!<{jp@n*2fWCpdqYT{oLDvlRppo3N|5PWlI}}5Jzbp?r04dUt}$+ z0Fi0OI3q|UiT6~e4B^YjTECY+uH8-9%|BRjYE5qp#@3br4+QH20<5(_`|pbmyH4#h z9bztrJ6aeDnjVP5sWkTXDDU)TWjYJS)rq2xi{@cdZu|Vd9H{#!0jRYvB3E_NmV1&cT6$QDGbGCk z6P#%3V-qNDh^--*@C+;mqGMeih1QO<9yoIvJVB;A+vKYFL_658FuwtNO%4$H4D&MW z&kql+QvavV?zr-k@~=&=R((``OYrW=h1Udphp`us5xS})Q%cUb=HUpkOeCWX0+0c` zHwj100y*@ok3US-0G)Eb3K&j1S~l8ogMF{=q3LcknkM<)GUT5MkgR;`q?H}0nQn$1 zafaHrM-2{C9JC9t{sMf3$G9UN-ON*zr1tInpe|6&Ai=)08D??`mW}P!rIf)dijaXP z4n?|JN5i-3#Bvk|txE2Z!;3zFjU5=*%P8=VInjqRz@4mEzW&V7%l4cLb(W~uu5aurUwN={nPoeoxd)) z8Z%g9=XDcn*TC$}y$H8;HxdXyBfx#x4cGLOeZ4nD@3O*EyWbJBVxZ8hTkqpShoHoa z{`eaYFYoaxCVD|hrkft4FOqmF4KNKT1nbxvi82K!LAwAZ3{1-&C!L3at8~+CY8(hU zA>Vgnja1q$Ep3!jI{FSpHQM%(0550JR0DQ8faF+NpCQj$IWkso?qaAA*8T z3)s&5{nQ_V`})%FE)5n zWzFbNJ2avas#r3gKT(CpuYeV&!1NokMPB*^VBl|S^V*UyC$se6V@vv&_iJ_ zn2o{j6jTEZ%VbBYo+kf#`$X?)d9+nH>*jUP7y3y+^qcKrYxz2^>!4=VatAXvKcp70 zc8YA?Z9q75ZLH)D!%0%k?!T?REQzx_ncTGn4jkbPX>Wbo+EQYAJ|k)Jv$6y_Ye^-> zekJnh6HfDmZbfau6)P-fl2~CG*i#Ka{8qSeOtR3oAIXc;1wy#~7o43*q_;e!rlL)Y z68$YM)bJYAF|qMS(YRM?YH?QhL9oO6#*F}PhpY>)SfMNJ*&_K}Uz?o*C?N9PpXOid zv#;uxPoq4Igr?cbJzp`diRsed`JZ%Y)d!C4Lk2{ucIF8L34j)8^1fMpq4rQRX*81c z`BFi;{?S8t;<#>?DUUgnoM?QE;D0ThHr8{z?XRa__?}~#A2W{{y2hSBG-tB|w~=eT zC3DLOd6pP@t`f{?6XfiYQ2dwgaNgqZh@_?2^&IalW)$Fn@^BmbC7UYgQ_1;B2YSGxKWArQw;ZIa6`5vIxSLfJt#2PSUrv zRKE?FKX(KyC*aDX`_OImJ;QM8E|38T<8Uq_*YAk;=e~4Bkx28F8z{D?FMs9iQLt3~ zXW-?;0hLC7vQ5PulbV?Gk~LvF;STWVXF5h#x6lF?!4Dc)ZNApf6E%A36um47X9aA- zR(6QjCSy!Gu5Ij)RlxgK+?5O;I)E{kmm#z$iyj7Bs7?dnMMq8NJM#Iu4bKhCG5q~{ z@^4=Mrvj@tOfis8r};T3|c*#(#Z zI;f!boN7>~RSpIN=bISUxCOdz`v6hrz9r{(cRBGE>c##=5-%32yE0(RqSb6+QRS>=gY7NY(RD>Dl$c51Z@M7y{t})xI5#6sT1%?BKylJX*RoPnrMma;B4i_eS?$7oHP0qpI)uxx~nwv zosgF-Q{R*Uni(}ct1xhSHjbNR`!S?W}U#z&Kq z=N^5VHGE2?#MVUE$Lt8ID0jHL4wWr>JXLtBDfD6#$THVi#^&$JtG8!;B0^d^3$vGP zB(|-~uSZw&8#Y%oq-WL|-?AG(29t%0E6(KFH7y%20eN)x8S>uJ!A zY>XEWD&Gh>5Ap*S#y7;z%&oKZ=<2R1DU;?jZ{swfGcn@X=P^T(87y4+u+UxrdtR6r zGoC7e!CeY=kTn+weW?_v4nlmz?=^N&!0jVpq6sGO^04^T$bi1?9Ehd4Pzg%Unz5`< z@M))`49Wu(Zl5mqrpYm`i8C`(W=;@s0m0Z5O2v*M^4I>hi(w2pg!uUmoEC?nrr+nO zUjAP*)JnCiXL6G$s(vOs2}=i`342G`@|d6Z%4LuPu`OS54xh68dXHM@}_6b@UOfbfp!f?^HEIE+w5K&+90rbKwV;W-Bw=hn~|tumMHwVG_B zLKlsXB1#J2rU$HyO1Yt$hw4p$$UTXqtyuVZyreu&@pu87ZHoZ&2Ix}?36s|WLnB24d=(of(NiD zMO8Zk^}y^qK}<}M3_~1E@D?(WMXYRflu((?Xs7@V43b;h0(^oqJcjNeP=z+Tr(m)~{djsshvvQVDEV3&TpVRrjSH)~Y5n)_Z_lB%No1-CAlbULg!hNzbsHDD zr}B?d&FP+9(^oc4L`yp4M%Q}e#_YSU&69~NWm#pw#k~@EMVc!@TPYMU8?S~MP45q^ zaqifX3hgUthxJXFf6J_PXOwOKKn@n}m~O(+>$5!}Q|9>yAX*JUdP&Zmt5s{eAm}b* zQQYFQKR2gWkt_mL2hC0wsGG@8ccr3IgI-EApnoK=gPgML!w+>_Gq7{F+%LKc2b$xq z>GOqo{ny4C>@BOsN}uBtF843^4}a&y)@q3(olQ2Rgxec_-6a?-dVI|}26%u-xwA#6 zv13k7MgyQb{4f!Yp2Q30Yz{H{>pe`TXOpD|UbKl})7KR-)hSXpD z`nW@U&&B5dWjqW-&tf9bWN4?KtrHl|#D4 z*f_0Vb9)Aj0NjeKQ}AfF09^oUYXBhkfE+>k-Ox&ZR{z!PD?cmZ`XNTZ&oFqX#k~KGQ zB!(bVNlB9Kn@V^4;O`e>otJ6W9l<(m80TSsyb0}h6kui`^c(Yw+XVZ6KLC%Rw;<*` zi^=ZFA2+K4@2ER1ZriaKEr*2CxK|-05os<+`CM9iYi!kN8Ch)5JvTm8gCXHq*R>If z0SubjwAA{{^>W#x`KxQ8ST(Ri7vY68e|j6UebuI;zSw|8e<{8r0^~@WtXF z2R*U%_-&>37$u$edw!Y^QS<6W3dK7GN&36z@e>QNntVzlPg;t<2r<1%-$67Il1Xs- zNi2Vspo_56A2U!+GxfcUu z#+DwEga~wcH?!g~QTnQ~`&Ly8c?0-*KGWmQLU_Hd8Iw~+#A5yEuNM#acIatD(bFa3 zg|kNTP)W7Svx!8QMq@ybw1Ra*aW*9Is;Qd0dgCYB(qw28Yl6+3RSbP;EzioXR0WDG zNTGd=jjX}yc^HZPrAcFy@zUFSkrX!FadBxnMBhk6Lvm|ht%bld;BhbQ4SP%QLrWR@K`b1Dr|o@ zS0T*{hYDe`mr$Q8iRMxc6K%FaiKiqn?VxH4%R@*$2znU-%w|?|=%ZFUXf79K^1bdm zc6V2%32;?VEutwf{?<`L%+1#Z8rf{RE}L>`XFe89eT8Hh$SJ%9oFvd7=Z%^ z^tO0(qrP3~n6Su07#;U~Zki2yXp6||NmRYk(a>p}*( zE;(o6^lEwEk{Fzv_dc;?pe9TYI$yshu;f|q_pK(!hjYg)nw&t?SnTTEZLP;leQep% zqHU!}_P|798Tf(KXpoj-s!+Jx?gAK>D{2${!3DOJ2sbKneq8-A)i?{q*_G_JueCE+ zBk>M3S1idt(C*H1P`}dS6YncjPbrC;f?hqv>P3*8fj^^CxxNU2Pt6TCZLZ%q%Vte~ zu{*-6e408c!^}$_jx<#&eZ-hn(W5E?_z0$lhC-`h0;usJNR8qyW7CHa8^JuCNd(0j zSK*b24yI#C4na4um-<8p4Iy8@{ZV}U7w1yoq-Ylu6aLzO)PSWvG~_WYE-bXhL>4|6 zkVc~w1C$+^=S|Ub0A0Q~K`l z0Ve}guKrw<^BgtN?zjt~s>S7=Ip?Kjqnm;cVHs^9?mZ~`RE<>~YthYAnp3N(?yef0 zjT&7Ejz0v~?gWTE@U6^o(!@T4?I+U*&1KC~Q2Yp%?wFO&x)gB$4DxAm8*iz`+S}U( zIE}0S+3d0R^-q_%1sof`0acX0m-r!se_e(;xEzMVCd3g(9}Gjc$bscR_XuFx@eFSP zd@9&Q_w{&v43&Y9k`nSW2a)_G$TPM+&XN1M)_RL2KBTu#&D_yNd%twL z@2o^>1;P05`xOk;hO=W>n~@b*1>z#qlW@y^-Fjzfa%IRnOwE+7K+aiS!iu=7#;uJ+ z7}5NF<=20Th|?0jZAnUgFh^4>s3sV7g{S2&69(N9Vk~jjj~zH`T*YQs&|T3^>Sd`6 z!F{(!2|5b}ejQ?bNtRtB@g9&%RSKmYKI|x-KuCbwou7Qp_bpSiqPx2*EUF&2(lU$w zSB!FU*Qq{azb^Irag@4sMEMJk+N;q(%i^Zdt`lgBw}P8d2x_me_eeq(Bra@acy28d zkcQmxbB>FUl!I6iK(?j?L!ML>H@CCi{exMBt+Nd;++!Xja3e@m|LfSb%Kkh@uDRC) z(BOa>t@cflg%(6-k=$)h=mPw^#SX{Cx z_`dUm0@Kcl;?pi}w0}w;%Zg7)PvWK4?n~H7^{$Vi5&^E;J<}DZIYyDN9N8jaFrEyl zZnb0M?!S1^_PAXpS+f+L+GjfaGj2p9O*+P2N=P)CVVjgZ^t%WYx+FR&yC{gWv(B0E}Of$nTgzG>5$q%ExAR_K~`}&66cd9Ng)O9Fmt00x3y>g?8w{XXX3qnm` zJ%3H$-sj {mtOBRh{x1;rEdWQHb4rlimWL`lN<|;A2laM?p-Gzr!8A;UKMVeLh zI47cV8d7n<(v?}1IO_3#K4Ik`mt#1Dl$Kgy3V&8(vHL$nv1_-81{l5L;&m08-pfHR zZ>@lFQzk6mkY}4TeXoc@4Ey?k2^B(D$WB96X4y3^bgdX-u=rLdi#^Z#t8Elx$^c93 zZz((@xZGOS4$v`}k}!Ck0D>d71WEYhmT$HK8T0eJRY#ne)DzYuEe33D`lHPEqjbpg z3z{Q5f>r$xmlDh%=md9;X4O)W|EjTGa}nz?a}a2wQ7)6vlxfZm;<_trfRqmNt>HHE zSa$ydH0x4%+#w2d$w*nCWEye6$SM zgL*?Rt-Z?KUjQ2}>#;dvFhX8Oj&STd91E6Y;e~-aB&Ii05iU3u1gFAT;Xfd~9O2X1 zaPz--bL0ZUMKElmXaFpm)r)@JIMcFW`3`I0f}WH-;pv$m-r4SQuI2LM?Bgd#qjF7< z$A~S$is!_~s+R~a2fN7jh*$r)*V)}>Scn9GSooJ?lmsosCpA`KqGyxs6QK+o6&dS1 zjwV7T&f3SarFwiK!4ZjE?Y!bM?|d&##%suOfsz|=B`l8>=vPZeA6fN?0a7p(8&kHW zC^0rqhhcn55}cnGMEn#Zv#21k%Qqo=spn?LtCqeskkn??-2V{pWBLY;VS#9bcm%h- znT<7DeNMBEiO(zqULWoDWh*$^T|w@|DuI7}G_MBECSlH0=4)E$BYr8a1Q0zt9UBBM z$I2Q%g~&koAQphv=F&ws&6e#YE^``%k0@-Y5vT06h=nv*HMZR<-=v$$=96W^8}g>K zWevMo6&imcZ!RWo4BvWB&Xp*NG`&15-XMZi1rO1QhI~Ty(W7G4iEEW#&J8bkA(ew) zB=b|JML8Me1VRBi;m&~Nfq?n%=x*Qhi0A7W;08$~r}o%^Z2#?exE zE0=V3mO)`Kt34ezVJE3rV5Qkv_P;!XxA|HJJHd?qo?TI7QU&=?XvV2yML&xsRnv3+ z1{ysLfu{CXHz=&^*D8Qn=)$``PAl58#O79 z|IDb4_2+8bWXYa5tes@9Fi1~YN((IdPTc`!1;P-szzd*CfLND+$|Q&cDmW_ou#>E@ zKV>$`Npfk9t8@G)ZcC6#IIzux3&j}_b8?G;9+M`^@Rbmps4486`fa;W@njE^SE>T( zSL(h#pH&|nD-CwVb}|G|#z0~7EtEdcXWyJgvl(0v+z;yrue}*B(nT`1xG47~{*DDH zUe9+NE{v5z_LMz9t?spW;pax|vQFQNy+N9z%^8Wm7PV+nvD)F@#TI8#V~U3FkoG|K0ih_UBJ@DThn7 zo=m-P*-RtUw%gEp=m%DBFH1uiND-SY12o$T6MiI5A67|)S#9d79}hg_8di6#7+j_^ zDZW{uWvW6MAj24;Sv)^|rz5bQeXEUQ}|uinvNKCdqmQjU2o?==!UlH?h0;J}}B6`a#tA7snm-c|e` zsYNxSN#@s;Bg!_Qkj7ogc}34Qc5qd|Dte>HD+C*U$dGrmBJU&DdhFA?x2&e3wUnG& zLIOW{A>cJGOo7*-IKJuDzN)HAG=&HMMUfRHf zo=)gN<~+b^;)IaR>a$}|RC&k*R4&>%9EAKuMmCGz0f*wzvU(a5p6h*I8hPD{u^}<{ zPTJ%#7coeNpUK*@J2U=2W3BRZ^*Kqo8ab-dyY$8gGmkj+&iF3!y6d~2>R9r-G3H38 zBqdd+$&dKoXv;`6;Bosu=d9f}&;Yx$`N|MGDug|zlYQ-`mE2^`8|7}}QjUe!Dq4)T zYFCcjpL!<*XdbYQE_%5bbh-=cQ@%s5oT!aUG9e+vIBlNatFnwrss|P;t%`V0e zp>mVhQ}1V(6Df-N-Wi9Tk1Gisa#ZDa^z$DvoN4v2)P7*Xa-(keuI2|A2`-(yq7fkO zhJ%v~jc5xl%cH+?&j#O0uuzVCm*58UR27`0DlaO_o!`~WPJKy%LxvgC@DYa~lmbqg z!IZ~%O9gGUL5)%_K_w&pnX3~$`VI#=HSdC0wPPpyZ0~2wZZ{hFyjXWp$j0e#=mw+aX)j)C7td_v_dr zkP z#A|WU6|-Of(I@Pv&L=lB{RW2?uq%RW^&vR&=v3TA0*_yD8R!#Rzo-4nKV`O&_y&{g z%yLxdik6<*se=oULVH_>1P1rD5lg@-6Y;llG_#C{w39=Lp}>KSEfhB?y?y$Qmb2i0 z%Lhr8tFj%nl0^f}KP+~Bck_KCe@nN@gFh~9C0i7Sk1cHc6%^O z@c(_HnXM#*7j!*tgKCh1?}a1MK_Z!e!$+v(adVS=Ooho@P0l;+g8V7>j(G^0GyX9N zo*IE&7H`vs4t`M<(0@H?-d_HQTZ*l0RX)b_QkNNHz5&@-ncG-SA)A)(j2lk!k9koW zv0rLf_N4EGMP9q7fCtclB1?`Tb1<=u1ik{@xJ{FdWI%AtzC2sc)F#a2D1Q(Az{s+0 z40~Emj~V|yMM>pg@;{3|8~}7sJec;%Jw1$*TbUA6VbJvq3e%UD%o^h|NG-Cr|8f?O zZh_xEw(HNd**;K-k3e^mR14lKo7m&ZXDbX#{Ie}kA%z4+qiN$6kar9$FU zC-SVamdm6)dzQ9)jvsgK(Z*yF5F8SWh_yKA1if1h@k8|zOI z2Daiiqhej`X))uJC=j@H9&SZ=rKPwwtTm(dCV?26AB0|jZinX$be`t@LRx4O-H-C|={2*{7Ce za5w@2@M>iSrpYzM@nC#ReipP^7C=B{b;}nph~I zNfiPFLrKUNfA`++td*?!Yt}h)_SyS+_OoY?9J$zTJMkJx?YZMPrMW5J@I=QJ-^}ac zx`;&?p=o)!(`R&kc!xyFAm`#7JvVQkZYArJ+6@{r8q?)kM!MyfoZnZu-SWbX=_%r& z9Prca&x2=BWq-X_mTM0X8=xj9=Nreb-FKGwxIG@(>W-kb4FxrPd zie?t{=X?iGZ_oy2+zcD~>W?Tby&rb}nX`gQOVc)M7iD%14vOmh(UO$gBOWqGu*S{*>svxaxQ63{P*`jZR-I zM4El+&#j|DSG{<19J0>8x4*N9xt;Z*vYPco{VSiwz*(bb;<&4c=*t?@-p5Z=XO&{q z*)lJSiXA@4^_`V}UOk!q_VVYWzEG?$>sbwP!%vDY;cX6Kl%8oMLq00L$SD5c_k1Z$ zQptgMklXUD=!*w~Y615y3bhLaw8>aLI=@BN>%K{v*vd|5{$;c$5>rOP(8+r!snbs*wiS}?%compR$W%=JCGpzYgUj zVq{^19p(&LOE&P+uVRAb>mn1eKZ*s16kDSEiZ!0915eb5q-e03!X?sgKJ(g>*Tbp_ zk`DV4*Z3}8=P$a)i>jVHSmyj!gYw*;ugSNEO%Y273Q6wi6s>hS$ox=Ka+fzM&6uzG z&E(&>7gop<3G8oxP-f5J_SHRZwg}BHWH!Yof1b2sdrC^N%Fn=C4v{@VXKYd)m>P?M)NN{;NNtQZicQr8n`(XG2GR4?fQ?H+P%x35H$a#cUXUIl8RYx`OxITRb&1i zH;%vMQY%PfqV(K7EhFobChLPAvP;JDq@Dl%`i==7JQ-^Df)2Y> zu~-a!sRk@oPw z^~~uX5@k2oxRQJRvK^Ph1nF$89lwEitpexf`SPM)^DWOc-p0Q6k}5Lni#~s2`xTA( z#L1FtTi?*xF>Z;_tJkQF)^!eN>ckk zap}CUS9f)Yk>#GkB2seC9r^i>h-2(y^8uS$Y6cH8 zgE!z*;9R|GtcwjZWydJpCwdWSz033fk^y^ zuh$-n(`4l(i?ypC4LoZZdojgZ;wARuW zOH`6TLZ=lR)`u#Y9e1s{Iu9UM14bTD6bez=wI2i0-UQ~n-Fy5=&cSG%g-v_fo`77H zvXwWq+--m9*WP%f`A2Z!e<`iS7j6(Y*mmpBY7X#RZ*V%$Kl1WpC`?qPE!2- zkUioVef9n6;NJpUhrcU474u)vNn5ck#PUi&sBP^Oq6rIYkQ?JgNmWduF#TIwMyIoW_W_jik>r~# zkFGL1#wH$I{bgXGaLfXm`GW7RR{!+Z;cWbYDgsO6^zZK;iZ;WD4<@_d;U4ZCDanOl zjK*h-mC3hw&a?ed13SI@Qn zdnol!PNBMx%}(CK_r2OL49Oqaz4cb>g0$sew7RsK>x55Yq4eLGNngirdI!(zVTfY^ z&x7CkDq9i`(i?F<6~{*%P|n#^Sunwv2kI>qr3c`E?bA9)6#P>wQriFlf~3E z^Iq4lS(b6%&xRC(&j68k|f5^5N2w>m3GM#Q5K~j6Tj!qGi5(B zw4ARI)6d7Jr62#&c8n8iALC=xSGv6_BFRoq~Wh;{K z3WD8{`&b+)9(H2AQncQ#UL*gxlBUq9IlIQQi_7mls}0e5ZC&{mKKZXjk6hP0qH(Si z@1uR>M|`&QhN1a}FIZlo;rKiC+-1W0#vy1n>hY;Mj{26$Uk5eVp?NG(~PRk5MYpc&Sjwi~GHpa>w8NSh9_ID@`f1MG# z9_jvF>-{`?)Euv++=2S2u*yZ+s63~!nBJY8<3gBmX)R4SOaR4P^y@bI7L)wgpmA8x z>2mI_$7p#5pI%b$H&Gw&@2Q50r_#r6N&FIn^IkjlBNbd<*t~VOP{_-&#G_w#zaD9S zN=jJ1a@rI(aU?c8_gdbS?A5x;blr}KoVT?L= zYipWv-8en`%cCPhUxW_V&#ac0Jduq^^*zwU6BJ&ev!+bjp6wS4EKSTh_3Yr0)*ORj zhn%{CQwKTyN`w%VH@Zd=6Y2^<=4S$F1}SqOT8|LZ?+VeWt>;iU;pM``@3%aKq9RT5 zo4y(AkxqAZ9baZmE(xh%4(f*12Bj}NH4M@&TB|^KEscz(uE;7o_~YVC|1K5VA30in zSzoQnQ}Uy^dKeVG9tnd8a>8Dy_73RO}m!C=8YR*iulzE)#?at5m z&7G$Cc)!y{0aXi3onqKc*6tI3Hg&ZXBGkKf>wWKxrn)dLR9efwzMFL^kg)uX&+XK& zyu0dIH^=#s*3|cIyXdGg=%)2?`O7!n&F?~PjMlH0T`b;44ZYp=A)jo<@`6o3z}*@p&9KS*cO-MA8aA`_U@8b^hWip7P52qNR- zbzJRZ(EvgFI%-AhKE~IKbq}k4t4~yIm0`n(;{q*XSXNPEX+9;KMk^VapLTjK%lAf> zy#Mj5JlW8wOD|gGTKe$Z!OGJqe|O#IX?jCWeLA;-LyDS@UTbhuu!%DGrKsxI{M4jz zoLl9@F={F{>XJpy3^Gy5F|>hn9Qu z-0UH9ZU4wZBBV@HFzAHx_0g$813n2+&%KBjH9|!Jcb+O6lgut9sYPA408};eOs~hB zdsloxI83hKm>l?El3XlYiFvW~kl0RoBAZ^-KUN z_`163XZtZdlFBMFoN2LArj|RSsFdWJvq(%ujq;q7VqORfgT101m~NYVQn8%&n)5D= zlwL{kTwcq~n~`Y$wz(ub)2NwsvaHs9ugqt$&(>-ZK!{=8>o=Eq@9Z<&4xDUhDUtUp zw?CiLVoB|Z==P~TKl`Mk!^3@2)8S@l^a|})Kw{RixzCkuYSM^4&Hi9%|HX0ae+Qx; z=zh5r4^`s{v|PFSfnWUg&>ShG@TGqU1cghxoO2(-#~4L z!Vjw-?C!7Ah0!|rG^d!Y4a;Z^zrbUr;X$4!Zppgd$h=g#SN`E!b#q_a1 zo~mXS%yrl^Q%jN}~?w%#$|!=4;d1UO-AW_}eJxQ9UKUlrErbKIY`wm*Y%ZamTJ^I zuJY>{u2YzwAk%6C$~$oY`_w&d>dfs--KXyQ{N8`pMV_7%kd+G#Wqyq|WhrY~Z(#y@YftQAn|WVQ z)$2bcNS9@#VJa=EB$$-fxXBLe{9^a+wBxtD0Vkt1 zwbJ+J-_yj;|6L*c=K}qGQ+sMbqiI)Lz+tEMr{>f4uD~_PVf3w|`xj|@Uw zrz0L7y}#wQe{|i;Oq%OmCEst_C<}YxzddF z0Rck~^44iyrlK8b$NoQ(!}XS+c(O?v z%fKx`dSqglsVyzsvb|?uXv75qCkHraN*DI?SP}AX6`FM!eM$?WkKc-_&~2%;Q94#q zAoBw9IO-LNuKFKa9-Cgo(sX<$?%jW(J zqVD4-#dZp!CoMyR>q|4x8+E^Io;nBRLH1nIAE|Fqc#W*y%t#$oZ?nu+J^Zf4p={u< zY*;4tmR+p5%$MrsJ?#O<7Ey8qfq5?P{hyPfRtKa*x4%r$j2|$btH1PS$lX)TRW8}o zpOLc6u&;4Pczl1h-$o+sgnUDGa#}VfOsg(S3Uwc!J04RTcI(;x=Fc$+z~L4)-F{OwHPM;ML!aw;Bx&ho4kMG48G#x; zV|&%T>UD+_Q_M%jyP$AszU`=Y*paTze(X97&N)G>TtJEf~M`GSI-QBIsdtIeH=Bs@rCbHukC1 zH6ygHqtDDijj(U#=i;q}7H=AKU%BZdWqQXY2DSE~#g3ahASr}j+}QQ2S`hTdiENt# zkr&*eSvCJLcWUvP&%azf_(y3IZ(H?P-dil77HeZzyRqf^`}!z7hYtxe;`z z-ZI_Y(Em67p-r&9q~WKhw{WOK2l%VzvzB*uQhX&2#Wwh6!<4TbSo-Vy$XNOdY2zfs zX~ezyttrDO9``$d(wQ*6bE6Xdsb_b=&_ zHTQppsQdg1lR1ZX7P;8vGSIgWUu`M6bx)VmUWWaygQEZP$Dt=<+fwBtA#YB%of#iU z;C_Vh-_<5j?Bo2khMq2Cwq8km@G1Ev^!-_aNC=me#K1U#hdpS;Z1M9oboem!8tuQyl%GI zz7x$jKrHTw?l}tZirp}}Low*;0UUCuojv0B84(qyloYhZs zMcb85n4Pi6Kk>n|$9M^H$x&0|ztQ#I*#OF9u3~$dvaeg7zj|G^?4E^3cl=r%>`?e@ z@IDHg3_h(g*nBW(hWmoQf#kUxxTW0UxV2c!*QLuvXWE`qrpLH)pRFfLg#3Q;cWs(# ze|-I;^c8n@(NQ%^JCQ;&ExFStUlup+y)JfgwC~%0q&5=&{Mn-siBiqkXybuX12Y4E zP7)g5n|lmd-Dv%+2l5R(xC|ri@m#Y#XfEcG@=Z>!?r`&`ONuHI#n4YYCyND?$gqcy~8s;*$X{g{5ntv=pDRntgU_#q8DdZrjK_ z>lw#wlc@*u4_ED9{$#*AyXOG{N{UCd4@XJziM>42_V(O|tB*+7k(4V>B6|6re=LB;Y{#Bg zNaF4Q)uW$uzGDJa}f)efa{)!zejLJqwh`_%pbAVt&blpI@$HvRXxcw*TB7f z+VhbkJ2(Fp#TS<#pr7zVXM^i@WRmeCtv!V&SyywqAAQ^7``)^AQR0q3YqS3Hk64Qj z=LS|mYQ^q*8>c>&ON#16bEPN057+$=J${_Hk|kGd zDs}b}0`5E|B9rPRps<%LxPJdltm-J?)Rte$xWsI`@^5<;^|{SpTEXYgvu<5?xsPBb zS4S1i4P`{MBO@NHJexyL$H_>4SHT`TrjEz^OSnq$xQ($JMKXB{ zt{4s7l9(Bf5^Dp$tnOJ2{&01*Re!hW`>%41!lf-yYL2Y_z4orlAwScWk0^$`awGNl z>|)LdWkM5zdshsrUkdg&`xl!Sa!iHLBj%Iz^uG75!gyOz)@9>?!M|^_Q(N?Z5JS&a zR6SihinbV7(3ZG#4|Mxk{jxgah`{%voA0O0HFhn}-K!xpE)v}EBte0g56XNO*L<;8 zbrH6>$e|W0+%{gmyHXqkW1h7RSROZtf?nyYK^UE`l5poP1<1wSS>PAW*rXH)1Z5jEIWw* zBuwpdl;&_65R6L{l%$adG-tL!RrFaB{LZ!@TpOYFrKyj?G+g|C zJ`B#!g&m0weYp54ZTe)=5!*+@nZMmBF8kjW*yiQct8{x4I#CKko>{|UJYO&bD zu41bL*Bfsc{jmw1d@%Ze5DLc!#O^Z&yZ=GQ#3K<7#)0T3)v&!*;h3Xk8J!0+>srTbWqN+H*z6_DaVlZ3cpJn{0rrPRqD3owN5Fo^87tXVEYU@;=h%;RHH zTVl~I1d$;TO1dYMt0jh_E__5^m&Z@66;k8uBc+*}ZI@R%CNvgH(byGN3Uw1%;H*vE zqv+q-FqvgTUl_c)xu{_WE4XOb$0_(~aB%9&fOe67UF~f@V?#SfGKP)ra0a3DH{c$s zR)Q#HB0I4g$OX#53eYAekS8Q^p#fw$9-3a7We_IlV!0b1{H8QX=HZ|Kglh#**J9fpU*?ThNr$pGiCb0Pu1q=LqGmcz3()C@wt$ zO^fxjJIbql!BF28D2j|K$AADRC`T0p0@<$!0z>8H=1KVQX_4_iOo<&?vgJ7`8Ah~M zN3}21EQpPTp?0|d<+o(b`$(;6U|c?K7Tyo}rB3omDw0jsTm%zPNEi(~bZ5Xp9 z7`NuZrVF@ywh8Y?3;M2ghC^vh5T-Gik!5x$kBu6IGDq=rP^(3YPMSZ7UsN|9AYl+( zEHGw|iUqLJq){*wobV2XHrtmY@{&I&%MpMW(7r<){$aFW-1UO~t~%8v<)VkWBrwF} zGfj4;s9Bz2_(Cp#-Q-ih2+*9H(dxs=apPAa0LBX z2=J&w7!4}8_S@+=8Ra0{!5?*H&71K?Ih}U+6k{bM2qqvUWNd-XjgABy4aif-mvML% zbIYm}*G&wR600Dn6o;(De%Y}p%jGq!SYk<+B6&Vjv59pT%A&RCXlWroYM2lfTngWO zzY0eaQHXefcs_uHBgJU&#^D3a-9{^m={Z(F9;xFYuVAwPl&S=JSjwBHVzRg{jv7~p zDk^}PEevdzsD6%j@y-w_1)Rp)NkW{b!?8JYj@y1o%*|F&zHdqO&aG6Nt;vvYbDj-U zT$++2NcB>nFcJw_q^xQf|Bj#EAy+jfrU>~?RasR|_1{odQC3k=L8fBMLGt-I`Gqm~ z4YC~PRT#l;fNA3$3m^@eD5yAdki>g{tj53XZZ;~cB)rjDB&US80C7H>Se_C5(C0Hi zN`(OWy8pt6gXh06lAFP&mS-{jA$MEW{@?Kv`!j}z;^7$zGx??eCVV_MTL?+GLUqeY z<4ibP{__7Od`|AX)GZ1E4~Xl*P|y}rGv(-3C!{b*dX34k1DDfGaWwT_)b$nE zWU$*DjL_wBke7@Qa<$P3>jWTx6_=#ZFNO3qa~-Gn9*Cl*8^VeTknv&fd+hKDZe?wSkjd`L%nx;Haqwvq zeYf%OY+Es{7@r8wR7?Bnu#`f^gH;9LdmT<+75=+1apksTy zP+BSZ${otBgl%#=;Y$ny0!n8>9EGYBSAu78lg?$AKU z2w2U>r?e2EYxcleqmv`5T@TnG<1vHi0Z0$fDBf>`>!-nJO*o*n1#Q&&4#0<#vAsu9 zeA&!CJc5TG3Y}}GfVK3^?;mNt7p2=5U{>BE9zTfW9_Y|~Mdf%H6tDcKXuM3dxUDYR z7)%ysBPcS2Ngz!b=r*dsE$i{;Nk$U_-_8iDV!~u{F#EC9jU*#e)%;7w{8f-O8cLuM z48}R8I5IKmqRl=;0W6I36ZB*Ci>9pa=c=>poaoI*T0G-)LdS7EM1J3&*xe zJHySvJ_CV`ETdOjO&XX)1*M@xR0z+QshgN%c@5OfH`c~do4;2CC+=uo2gTwA`vkP~ z?T5d^*X18_{gqO{3cw4jgyf@=%-u@wicl_Q$@7Sa)aZ!ZV~2Do^IY2-$i1f`A^ zx7d|_<(M)Y4Lt_lgy+oJ0XqQ+azltDhY%&_$5Nl5SOY2NXbW`KqTgTl_)TSlY}EwWU4Tz6rh8L zSGb+o7}zG$!|=s~_=qRQnL7oX1;t(EGp#8 z?dWWnM&Htq#>C|CPhxtH?6Vu!wv!Y72C*NjEY!kI3H~I8a8G2pd=^LvoE!AYsPs<} zN_b>(__Xgo02aU0XmMoGCX~fBe{Zm6_{9GMV3>@M%(pFcI}ViFm(3l|{^63HkhX{z zSF%jYy6nF6`LN^G+@NOi$6)pXJ(Pp@T$GA|es(}$S`5FrbYbqvWo_ABSZfy!i(NNX5g7if2q zkMm>TJ~Gf-_LIG>4x}iWGu;pfctt@eB#-eS_uNeVC7Xa10qR$20U!>fxZeX6b z2}uHj)mb(z@F2Avl#aMeelVXTt$&9eRl)*9e9X((%WKS^EnVBet=!=+8*yB|XdIcz z0^6ndj%5&H;ag57T1`r1G<*#J1ZeM90M-;sjNFVH>ZDk~THt!&>f@Gf7W&Q_7*WrU zcZjgjl2Ziah+stIo;!EgBR}yB@^X$bw^BfKPEqb-H@6^RlFVayKV@-uA;d%B{Kv9G zAB02AVQ^t=IAH)~dCv^mMEJvtN8z-LMG)xWeJYuS{-s|fEIj7$7xj@jy{b z4G7{0Gy3IZloACA(A|4?!-FxUHipSl{IRnG7}lAOo{`{-Rc(2P7mIz>-sn zW0V!i$KxGmxFBGhxiRq2MubNg!5u0L;;@K4uzI5$)S6GGeMV>3vUnZ&ut%+Ux|*6- zm=k5VsT(glOjlM!bz)3NwTOMBQ4E(u_rmaW#A`))Y5VQ_oLEU09b#zvM$B?C(B=J; zfKNMIfLmdGg&CsGXa{Ed-57#Hf_Qohks*j7d34}C;rww73dBvcA&8<$dAeNt#lE;Wq=SEU)nO34Cd?4hiK(YsPD^b zhb)@Ti;3U&hPCWb`u9`I5nL_(0T4$|y~ym4)hz=sT)F}hL&P$L9D6oNlmK-I7LP24 zHc;_}uG%=GZCwi+A!7)H>OnNtPw0p88Y8qu{_HEXbOrebLP}`ahd|V4393*<=_V30G9B<2WnSh>~~_XP1E=+v4%1bs?IH z@p~CNQk|ixW(r&rZ@m-F`M|jHg3Tu%C{bg~jes_X^_$ zR4GV-QZiIK1-nO$BD0w^fWEzvn#DziM)QWzyw-Lf>?-H-D(hB#=14f;@_DENzfFgv z=?E@kpCsUg4*|WRp(y~sMGa^O2eg{UO~az4@k+uXeDs8N-2oiofoHsUO-?;~f+TLX z(;r5OppX%$XrEn#6(A@4YKfo6u4xcOrGQD{B7dl&2q-WH7L?N^I&S+K@sg(vl|9~W zXbsWX%QH9CS}++hu@gP>zyktxOx8tG|1>r|NqcO4oLU&V>x_-w(}FG_VcCW6RrPZ+ z77;nt9}rr;N=&?(OoA^D4Je+JU}6D zFnLVZj>|Wl@N&RP5%1R?+AzRF*D?BoGXH-g2u&6G(@*2KDQ1%4c4c{h6-vv0tGTqQ zA4)Z`taX9r6WM}Hg6k&AxPM+eF|;Ro-h?+rCSRB+KsK45dA-FBk3@=2^Xf~d=i`Jn z9GA;uElZ8%mEKZ;UH~sD6B*H-rWGfG;$zz3A~rz*?Hw;6045f_t~*GpG+JvS3r!H( z$yBJaMw$w5P_wK;L%3j*ELlDs)8hz&(pHp_Sb|vsm2)C|(f#{TLw1_#G#5IH9)yI% z=&s!l4-H1K6cMS|JOEDWA;5UXJ~pGk54R=R=647RV{n8pke)Llf37zCqjf@>T<)xP5zb-e(5R!c|5#FFuCxkoEQclK z*2&M-h{`Jr^tf|q9Y~nNlK%Nr(6kRUwXdtvm|r=ce2-UtlHJ0_ZU2{WH{gp~VeV|* z34LqRIPp_~HgpT)(M;<=v(6<+n@g8OFIl&+dl=nv5@iFc8!pM!7Xqh!}d46X(x@*@ICA$jKExMym{2Dy$Wj%|jz@!o2+ZZlxRC{dcL_4V@q{+B?i1Q2Gz zej2Rrx|^8O*jJXm%5VZa*P2JU-987z)VRvza9Uwnt=!cDra$bL7WfVuJzkN^`8*}8 zAmor2*JYEEJM}z-&n)((a@`+wLhTsb^#f(ZUl1hcaKc$C>X;IR^S|2@s9x zf@*LEz$Opr&JF02CkZJQ5VtZY10JQgh}CLCwdpZO`+|k&L=ElV0e;xHu64#pE8b_) zF5QPX7OUK<&PWOr6Lcms^ssbfneA@iM+Y{1y8fwlj|@_{WY0#UHn7Bb?V$M+&8$2W~db6Mzt2s&Sc zZE}Kw)jeHpCx`5+sNp=&M8#oG7_erpE(^zwjyg}e14bL#E!qSIi_O}%QGHUeQv9x_ zL>(2Gp#i{W?KE+3pxBAxttvaphPWgY|oZ*PiV#Ie!p z2II)wwp^fBgA0V%aIysqBTCDs&m_w9f;R|5QgWY#ZU}Bxued8fp(;ynMDqI^Qz4{>|MmRpzRwv4s?X~JDz5R+J@X7%{ z7#eSwwW#F*@Vw&HI0YTxS4-pVGK~ z=#haqvK`k^?K4Q!YX>-4-2)3}@*V1cqD5Kk901Uta3uk=a026lB*)2pCif4r0Z~CD zEDKD6>(CK>M4#?g8&7quMpM24iV^RreT*^QRWtiIq!KAUg>AFgVP`j>*Y7nCX`Qxl zdenN4C6`6cz>lv~ZzqErqPqXI&u@Vz1Nq%1nc+=5PJQOSxLy`zRK{^4!pG_bZ{#GK zk?F@6(zgwg5({t|8rLSS5A#B^Ce4Vx)Xz&iU?Pgmj_PK|+g4u*v#<%(tWA>UaK?SF z&}RZkffj>aC;db3>pT*%JnZ7j9%JvxA<70Ec3fUnQv;WX3VNd61tZP#MNKN0tgy!g zYb4!Gwa?gQfRah?8luVJ4QbEUePe{FWA}RUV&CORkMf(^tX+V=+Qm3fXxtr}%K_?- z!O@;k^0`GYI6tb<9-YpXZ)LFAlN|0Df3?~&>=I{6w(kl1S<+^Kncig%t|KAD%oFO_ z(XFMo{W!9S(SAR(QuZC|;F_ZHa;Uzy_)Y!Cnb!jGwM$r=+lnVHT_bNA(;(z1&vMpG z+6J^h!S9dGH|yAcj$Fo)55EZ(?c zV$c_-c}@T#JkTMAC{m>SOSlB}Gp*^l{{m2Ht8=7VHjY7qvo}R@Cts~SmR%--y_L)^ zc!k`3Oo4@_=%hbruMKtTXE$*HKt8x%8vfo`yBR0d`< zo&UFoBVyL>)0|0}tp;W&!CAfRr)Jd_MsplthHvCGrG_KS6pRD&@77h&86jc?j3GKt z$a-XKy{qxEu$5tcEf!QU3}uUvF?f1I5Cq?^g6h>`kfT(<X4G=`4FysJ&83HVb zGn?H<;al3#9o+`g^F{UzBCRj!?F)C`=f^#7R+!r8F`2b6}_t4Pvq$jv_khcuCDGqhq5+Cc3n`d!3csy@5 zOG~H);{@;#I3A@OF&vG1z!=Oa#Ni#`E!S%N(jXJtxFbZ31qsecPOjc|JnKaR*I(HZ zwj|}l&AiEfmizJHn(t>@hz>Mnqeyzl1a&^9oxS}B(LiyEaqMGb(tDUPtthaiwFzY^ z)w~>!YlnN#6}+;??su}k1Di{I&31c-GKg1B= zjIwq8rpXGL_4HJzE*!%6e7DL=NZwOJN3Ajj4hEA&5Rk}T%?TmlW=A|2*P!30JH%9q z?k59l>Pw~`n@i+DIAcb7HiH{n4(76I?+R@mi&#UW{NdL1>@8Y#KMvWnNH=S;1ep4E z;6@q`S<<$%iA(g;OI~;*1tB?tO&Wp_k{BY4p$_yUs-B?~yJ>hE>$LIE%4r5;+KWvV z$X^wDwCbNJ0#X`alLbAYdi+T3&(6$_9xm!DRWRPn+Nn|4Nd4V{uqB>Y(tBDRHRw zVvShQn+H3Zio8EELZqxipIQ~&cO`OCXq*m_BqV<+02=PW2Mzax<8@y;PU|o5*)j=M zfS`0Io4lg#(4Rru_cH}h5yJwT)+xMk=KV5z-DQk%GfOs;7ypcJEzeHv zy&A`ExrGRhpBGK{Un0xO>RsW|GdC87r2n0CZvwDmdcYrOE%ggYZ&qfUGJ_Y4ECK*T z?1v~C+FCG4KbpEO8S~(DN8|5^w)lU3MiHMvWI^T=BAYOUvSUoAvmVXJ)~Zdy0iwDm)RkCu&cf z&aOOlOYGKw%KRM`$&^TRnbw}89%U-ScnBTrR%IK7U#1|;CywAON zs-&APGfgwW$iW`?{XL|5*TUlTlIYN241R8w1lYrAW?Y)Rau}ZIfYCqfh#h)d6B95A zzf!&7tRLaV<1Ed1!F)0f=5TCYw<$q-{puv^>yTg+lW#hR-S~GrDu@%z|BY1%jUN;L zOD69iSR5ZHWifJulE&Z!bT@_Uyw*1pE;c7#;`WR-I{vGtyY6QcmIO=vbATr}4)9-P zfLcw4vtB_&R8TVpZ1S1C)oQMs|Gz88%$9zvQ9BleZc!J3HS9;|i=zkBi~s~d0cC?i zk|D7W9eER9D>Ai_XU9m!hwTfma`Me97vycPXTo^iqBbY@8+sO2!nFE3Z9LjF6IbsW zyG-u%;I&3q?RwC!c5I8I6gpTvu)H-jd@&Gh)W1h#WWe3&U1haed&WZ63al_jh~hW_ zN!`N-cC5{VFBlcUHu3dZoK^o1#&DvkmTh4`WR|okBh#(SY=-0c#l1P6-#lN}`M5V{ z)$omuxZ=OAUpTA&&RI2gucgILuT;(8M&a}a_n*1=*y^yWHly|kF$*GW3TAfpD?)uU zCagKOj<;v3&nSjk1EkK9zgX83wu$E28!;8xxZ z*B7M*|H=#eb{_`EIW1{3 zJNLf|lX{N8alX+4%@H^zqet&;)J%AL&2j7~hZ9KiPdzRPhcDptG&^_=_28TJZO+00 zE@AQ}Eld_plgG`XeGJqESV{w4(pnz>VL&Jwl1zU2S&068YWA;Xo19M|E_`gGd;~auw4hqP~E7|^s0>1rEomu-I3OMz+ zKxEBzvjwn%jSU(9@iltgYzTA<&umS92<2qZbUG~S<_G-sJY2HXvZNkc&c>{jc^MK- zK_gz%N?8uT>ky*5K(deflC9t8+ujZ6cPyRE0=HgDoCLp&TUN&_Z+?Yr`O?%dx=o1F zXk%2n59eL!VL2Z+b;Z%T9DP?}MHt)0)G1tExB!+iLblB!`z!AB9rGpyC>m9V zW2_Q=f=RP`U4;Fi3B0|IW_v5eGr3;rzL1c(mQi9$z`SPxLcBsDMY=s!x{I(P1a+!n zu1rEw$hevw5gLvi#b&eE933mt^27fxJ*9g687ZbbWt`-wR0>0V=hk&X1Mg|KPv; z8&<|zf$DOkex&%So|yPQ_`iU)SyjwFcg>u0)3)DT73&GPkv7sXI}@cEnwm8=MlqSn zKGLmwJ@+@c6ner7MVgr$DDGnmh4XKO2k@}rL)L6CixxFCxu>o}2@8_qDRkKgo9bq>P$j4Y}TelGhaidNbZ^I02l*w+St{Z zTl7?0w{tSrb^Iog+)EGSz7QTvAG7#ZZ}UdysI2!m;Dq1?sEK%@`G#jfm(7Pf`<~&@ z5mX9l;mg~9Qs>-?fi(venWd!>&wj`?`G<;*|DQ9d1AseiR_m57uY5FZzs|R+q8$5% zdLs9^(rnFR`P-bD0`8@Aa%LL;A9MEs)z+Erjee^T1PDn85mG2ZKoDKDp(6p35gmju ziDSehnM~Tm!3ITiiQ*t+n@*S{24f7N8H{Z_U@%4oJYbt%!bw6iC4guG#1RGw-7TC+ zX6`rNx#z6=t-J1C3omTER2Hz`^8A0#yFDTVS1sUvnMY6MA!>iP)W&`LtAQfFJJkCg z@xj{U_Vwg?Gfz5TdNgRyUo?y9c<@3uLwDj%R%W|pMOIt?z|gbs?Tft7t6TS7)HPHC zzW)AXB^9ZR%MlxHoC4!=?}KqUc;Lx~ISd1MeEt3U_urp=#=Ob~-*+M3?VQS|=9OvZ z-r|p*%+-qN`Ps>_Z~zKESfoz>*#yVTMDku>sz-neJk(Y-%;jAB&wU!1%N;mxB?0UC3fS-%Tzt83hb*(-^H2cK=Y%BNUA*3~n|)1QuY#h8 z)igU)5E2v$iF_3{Xel1CQvi#@4qg#lm}S@E+*vvr*pRfVQo8`DyEIodHZ*LzblOCf zR~}HB1U;qITH1|fcjc%y>{M?t>(o{A@mIhaEh@+=k6K0G!u&`c&zWM7nA zgSiHFxRHXy~eyA&{rUOKd6sSwW)AQ)Rgm0rwi-y-@ z^Auc1DKDwZ85w#xGzfNxXld7=65n=sp)a>VF(|Wp6F&+6F#M3i5^p-};qQhJmtj|d z)m&#QJ>Dd(u#!qWJHrZ&^=;cyR8X^aRmU@qRUcZ*!-|46{!TVW_8P#7#>Yc~s(h)! z!2)1tG99l&xD9BN{f?j-$$XeSr|rmItBXbIJqSGozvJasc-$K*?g~Y3M>t9~_ z2&IeJ1J~RTx%_iRGX@=sb{aADRV5eZ7=*J04=>Av3=*ohH3s| z=W_pv!c^VL%7!wt;^lJIhqQPajTuQ}(sN&Eos9{eiprTN&FzS02YwxVTu>c#D?w

z?b6H})c?GwUsPGuPK zg|+sVh3_RsTUIH2#w*oVo2-*Us?BE38L|ROY#Jy1sM#MftCMON)wAW%Yg4n;g78ll z7~ia!&^Tps-LfOq`-xIk)dluj+4HbsmW7Xdj;GY3NDI#s6%yLt@{gK4G#w)>u@1v6 zd8@4#4a$B}Z?c%+YvQYFUqKW>8`1<9v3ScWSVLj`rGWT|>d6&$L$pZir;uvF@>FDe zGQ)j_-N6zyR1+Ffja0nV1*+{Oy64$Cqg#(yrpwVxe#JuaHkZ7kKsXww#r?pn@?)M~ z|DgTStZrG%tnOOiSa^)N>iWgVGOS>fny{R{yHs`hZ$&6vxfI%(>OJLqcI9f}WYiR^ zZe}W#lhZhPJC#|R6JkD=^!0Ay`fO5?|Gs5eY&|3E65pcTcG>dt$WhaXXp^$&s0Q|u z;bA~TeDOQSk!t%Z<^JpAPeikc)&{KJZ`e|5qglEAx8aE^mz#?JlDO2QV~J|5DNi(- zHJz(TH49H98nK!ds{ueBBsp?tqPqL}@}&HNNLIR=b!xadClIVsSp43$zFV)DZBN0E4J+o01!GC5-ZnL{9aZ zZsa7Qru=j?BWmtO{pu|+ObQ;bDrG&H+Ig`OmT2=unl!X?mCiSDEDR4{D(6Sy(>fB_ zAq67!By-DtU^H@O5*wZrAFwRTctj3asL@)EkO@RQO7+KePX!kKcXBJQ%xp|+mVPaR zzy6EMnew>ws-o9d+|r=<3cU8r$JdD!2GpqVQI1K}@wHj`(e{c|o=n7NV9in(_2vXO zYCbUrTa~vi{;|QYfKx(<-eDVa1Mbil?^N$6SLi-WIFHCBEQRp5lOw4e z2_>_JF>{fQ2Kk{<`SReQ?(rmveY~tXGkz;&h8e+}s*jYku@|ds%B9?U>-#bMq#FWY z1UHz}!LpJ0n}_sScxZ!*Qn=y^dRd}8t3I4m^4@Oh7Vhpsa!0)h%cR0?iyB|3O|*0)%_&P70^ZNcog6^bEWj+ z_>~Wr52M3uF63dqtD|Y1i8aMb9|h`|+;hUrAv~humSgH7H<=l%mSUq(Cq{dcHx1v; zjj#19K31^yw?ASfsa~k*k`_D6iIZ0mgg|8cf=WwCqN#Q?7pv%nY3*nQFN&YzFz;fT zj;QgnwuFql%i}e8Fy5l>Ymj~n8JkOBtIb*-hh_Sk71xHT5DG2v8W0bws)}USko8?_ zJEze%lb^NW@8fQBD4c1g+?X816S8#F;^hQF&CR|P-q|gK@hA=L@h-kcNoHBTXZnwv&kIeJo;uvS~=aXkegDn7v2Gt!DN+ z2v*a_0N4WXh3LDsGd3{Tpsy)G;YOJrk9x_IA5Bpo<#0T|) z3~GZ&$1JAub$<+=S=)H=psG+%SrwRQQhP7J8g~ym%D9pJy@jZ>CZ^IQCycKE4p`PW5>FXrn-MvRc-jA>R*ZXdw~^0v+gcY_Rla3o zN)Y@7SI4}A`q;j%JqE>Ai&*#NBj(ki_2-ItgUV(@U0dd533*<<18?RunYu?qhMn zW%?8eR)GpCx|ZwVVv_AJ=0v~wfbtMPc)tuFsX_&wav+=E0|fd+FKTEaggnD}KD26}IAngv z6|e!gTFyK082sHES=*uDzypRP=gKy9USGX$^WBxh_(ZiIqR(_Olt^I%OY=HyRk2=-RlSf17V)uA@20WffQHwaZO+Lz%Xb&q= z0%ZWz%U$Y7&K3gV^Z_yYv5BB^zJjWzD(SN5QPh#JRr#CXjXYJh%b1_oG7E)05c`i! z_f%FP5!oA!7)vk1gE5VX`oCtNR8=F2<`mn7LZn2NnYC{N(^kAvE_J8YK0-g2V+@AJ-o!LY6uF4{dH#)J`gQy z6j!O29-}BKDQ9ytjZE^#H{rUxf#FNG%oQUKeh^|Q!#udOyMi>?X$0fjd2P5{o!KKI z<}YgEu(-?#2T533kH^01Ose*%SQ?aLg}ZdT&6O%RbEygi0M|(4{*Bp?vGnj4=l7JA zGp9`a?>hapUCXk zw7qO>esH|Ap5js`Yc!#mqn_F(Wk0AjPgv!-p>~t53Hcg$k1GcC7B}4i_`W5AcYoKX z8yZY;=-0s2GzHcub%atQm}}hdn=h`EDEIS*+EkL2zgy7VPm7w0(i1_{c2u8KBS^^P z%(E)6phx)Hm>Rxx-c;lb#^yFh0O7o_8>D2wN^eD~3Pv&4X<#p$w#Q3u?4|h4leY~# z5`ew)YC7n)u3jFiHNe&dhmbH<*@d=}D^a}h`%hQ0ixf$Ot39_Ql37mVwS0q6r)g1G+A~NuSuVzv%`>6bs`AA1c&Iw#7yhtSVzWE$FfJw5d;`JS5VhoDu z`YHFVMPXZhU24q5*WGV?ga-egkLKNa4Wad5x%3EtbJ6@k@Yh-D4t|TLNVGG9m?mS zj#lZfG#tWu8%pelxzpVTuWGpo17I*YK*n_2%9XN9H zk^V4_WYc5kfkocrHP4N|2GN5u5ai5bH0kQ1c$e3^lMIJF%*w{_-rz0y%y|MB7o^L= z)6UmQw^b9jB4jSB=e>jr?+nRIg^k;SMGZwddO~Sgt$(wubkMRIrj3vPi)FoHd-PY( zvTEw&sQhkOGpsEPh^i`#3p*Z5E(@W?r0g~%aNwTRXdbQ~=?+p>9w+KAAY~0vZQfjI zmgf8aPFW$q@voFsOG#P1exs~?FDdI^UQ$+vWOq-p5KrFG1iE5RD66BAvfk%f{YqIe zAZ7LZ&9d4aET9#!2XIu|LzncW_`|l%rR~;=9$$CeXZ{MZEG7j8iEF2Y2ms2MK0(7U zfajhF#wlZi=t$39m_%z&_##3`PSLhg6=vv~qwlDiOz9?&pdQb}8k*#JnDd>>UOZE$ zNt}12k8%JwN5g#tCgpY%8+=jgM=oF;BPM4m3+^=O40_JQUpxY4O$}(vn}c%_gik!o z@Bp5GQ;bXtt&nc#=`u$*7~t-RDfUoAA)iw)`@?t&9`2_L=nQa$_7EBJnv4CY;xRA< z!`!AWM;O7QsJAVrW&p`8X~3u-<9?)#VOFv(9jD_Q@l{c5Rruy(Na}q9j5{-UDS2e# zZg@ZS`JkFMa!AWnLjcE+hbdy^U|fl9bW-cjvH8aOhxkNP^qDdZO}6hC7%V!IeW#;? zrj-<{*ibwJuwahmh*1vaSQg?9oJ(}Uw*zKIo}M!`7+y;u@5z9jNbEs_fFD>QYTg~^ zhAcm0J&10;bMZ2!_i@ofF~U*ZSTkgacRRG>ZC~wjl$DvDSf)pYsW9i;+|E;XP11$r zr3WdJ|2#;N9VN5>gTc&jaxo_+JALq>!E;?Bo3xyQpNe8(4H;#?appZkke`x!X6uJCiote8esj6yAJ<^n2}%x(iLeuPpnnH-x=y_xmZzE4K9g<*v-HVfco z=1{LA9rGZn1?qs;W?C;1OD}e8OyMjYto#>*QU>d6!koYVsuM+Qtzr$Y9z7p!=N~gCtW+DW zgc|MUXF_@G;bOx$oFiG2>`59xA#nWBfY1dP#6%1Yz%B9+HoEzph|Bn1_i@cwMQ4m+ z#5!Q#e9vRRsi(_S?9c;u5KCdRY{WvItmmx5UNme(!vUnt|G!tLcK^o|YR~eli1jhd3Pb-AWd28 zcnB_0ygpRcc&b2CJv{>mR}oP4jEw8G^%WJhA`1%wfoOps5{Vw*2T}RSKRMK@mk!kh zeU|TgK}g1yRtOQ$*m$_ndElu4K!6UF{nDWd`9@|G_HPa~4WM8^hl(q2`mBa};!x|0 z)f!GJxe}#AePdqt^Am?!UiGU(O{**iLH9=>oK-s1uZ>TEHKVt{n$i3EnkNbCL(21m z3%b&#6RdLLYRDWSQ}&EFzlZK zRLr|R*H+3=((iKA{a@uMOese%O-V%%Z}70YU*#wRl%v=GRgP|ga&+=nIr{fs<>+Zp zj{c4Kn;iAmLH|RJz6;9HZ+?}dU%E>`IeJqmM|XTqU?F+3EYgRm z+N4)xF&Z8l3bN3B5iWyiBL}wKY9SC35a+n%38vLeAVBQh^Ab|e;H1%0@%5NNhpQtu z9aI)t_>eD?G-?jr@B}0jvHzH$y7_o)P&po|cJ(@{j3^%2)C2Il9X+zUVfA+XI4P^# zj&LKp^Cwu|s(W$*tfjD$7BP00bV>mOn`ziNNDd^5o*cU%Qz_-HaK$@R7jWv6dN9a+ zFZj)&_^$>?nU7QUgrQQ%l$Tt`LBa^iKzi)q5~-dTO)l*Rg=C901$SH^3f+P$40Bkf6FN3F@fr($xvd3P?~ZK!WNHYX(jT zs~z28 zefdJJKE*H5_k*kOg)jshP)(rhhnPJ^T|^v(L3=zI#HRqvxxZntwRB_?OILYe``Gwm zAT-@u2XlH~yUrHP7+vIB0F9e_mq*E9fsrQBHP-(*b#kIVUl)iIxU2d$gm=fkWoS@ zuDya-$!ZU0uU|C9#Z&yDeDSrK0L#dnx%edOE5DfdZDXM06VB^gI+~O+@xq74BY`2l zTs%azoENIiN5bh3-ZMiiWFa6PoE9w#k_~n7GmJZmiSvw~kxfsmswyCcz7?vja)=Lo zQ&@;@rRo|FU{I7!r1xqwf&z`%5DG^)^kF`fs-ksbPI){3Y);QcQzi!h^?c2zu(rM^ zK=I;{yQ19LmuvJAopwJO!SmEXbQ<<=(dnBp=doRiTU~p8XpQHKB%R$P85sE+P{4L1 zn)aT37s63U@+9S;3w{j{k{^Ic02vsOA}4TZ&7?fZZafy&+%p)X;T%4x6+96bqM~d4 z?hNeS`suKKC*PQuhm+o{rL(kUlG`fU+kblgV+&$+q>g@Xh3YbWIzR<1sS&d3OzH9E zcz18JD$4wh@o=xFHavleAHaEyWWiv&N27Ky&(JL-dffAFvYnB2@Ad~8F+)y|=TS-h zOAd-6itJUl_3iP&E%2oQh6hz-VeaMGe+N&Yzrs@ods5GyLg*+*U!Ls&gx4rM*eG+V zrcYss{`<5CPtq#EIK-_yURLie8ydOaU2g|<0J40~D*SVv%hyGS1&sEA&<7YEMN*Kd`Fz`_8Q`yIaJL;krjR(ZFe#0S;K>~v2sje1eAA+v1 z2_lo}sCiz*okJ%V@E99{7keTo* zb(*-$1}Y0I)jcLlv*B?#_nt}1BiK8jYDR{@FN6Sk*`n;-%{8H zn|bYSDBRnbM(EUin>9v7G1MR{QUrCNqC5N5B94Jy!j^&|yFnydtz{#J^icr6%l4QD zk2MV*5V~#-_QN19PJqsimlQ&c-DbLE;Q{P;W)BuHCIbi{qqqs|({VBo5x%x;IBEB! z%&+vW^P)iTiKM`uSe$GBl(up2B(|g6byg99@s+?F${#*gN`NhJN(XvR7}(QBs0ToW z_(I_W7y)V3j#?NxtW47I!N3LC{ixt=1ytA<>cq?!-W}KnvhewUK6ZUqLwifbg+0<4 zVFT8U*sMSg4C}c?z_oY5kQ%eZbUnu=Dj`u?Isy+S=w%ub7Dqkq8&^VduP>OX&szGJ zuc<_zD{4omS+!-*%k@10dVPgzzkXoG$2RKp3X2y;gip;XT#Z~!DD#9T*Act`s7F>a zX*j_Jma>#L<{Su}_8vW=-Yu}n6aKbw*^Cn`@(h?N*SEZ9*gOm4V_*l| zuHx*NIf#OmWD9#Q-qO{0pfa+z z*B$M_2ki#TmuBRN8{3;Y$n88{i4$w1H};=hU1khVI`RO3C|l`P5hLI(7bvkLB+p9I zMnfGzguwQHG_oJ5djd_><4p1qAx2x;kSQ`OXxF+P0lV@zOW49j z6=hjt0OP=n_cZ|qgcy_rTyDCI^enktaTy0q>L2!iJ^i_Blr}Ao4IwV$8FB!RomwZ~;1Ol%#w~|vw2dgWktj~dbwW_Miqt&!!8 z(6N@vlaw#0pp?#{7uaPaJ!?{SF}nI?M!7jYb7g^5>2}gpDFj>`8i9+$F`dnkk)PNJ@0LULab z8+oi~@VXfVz;#t{DDoR(1V%y>YmSu+MIpjh5pJY@Ser{0xk!ki+Iw4}ds2_R-Xr*c z3(~7sU$4hr(;}&$sqFQW9%q8Ers6B$di)AMf^}7^33B>me+jl-f37|0L*>o;{`^4!s*f@V0*Do2K$#pIzBuP5JDIi1Mr2O^`o>&#w9TbSwm;(H{T~A0KWw zD8QVb7DWgUB_z~cbi3zc!T!_NpR#HH@x6am{o8_SlajFF zl0RR#w95Z;)H|t@I%=R=tg8$Br4m|Kukvm5Y@OL8mo3s4(LUNQ`H>Y_TwQ$nukkUc z7fp3-Uw^VymLz3m*sBGq{&ZYAe>!V5ct2YA%%>LLRH&P7zWsG_$k*@D%DK;1uDOuCNTWIGOqoT#QMZZ*`xO+-VQMTmi@WfpSplLc!6KZJC93i z)ypFvzjOND&mTtXrbLcL(V|s8`R4SWX`kGG=jxfn$SKZq22H;F-UmsO`=k1QP5PFK z3*&VB)79z@{^edW)8hNJQSe5L1qaP#$JrSTXLL7b8Xri}85k3XZhQV&Y_Kmb-&xYlt zhq$OvbkiXqrgpmmT}J|~%zV6B(#6F*zjE{iN~kbH6&V(z1IY`65!5Y^X_R;=w#HUy`LaG%0<(-+OWm|fq;6?h+aNp46O?@;Lt_EIea{kco-bCqJSQF#3GZY9}%uBfQ zY6q)5#QvUWl1<-wo|e^QxPN?cZ1e1_4PO0Qk$^t8F#T2s{_D@@)q>*dCanFntQi3% zRh7kcChEbKOx>6$Zb{h~j@aouQ<=Ewovi<6Jq|pdyyDU)gaB&$pI^&OEV_MaB}3r% ziQ`Z2Ici=YI1VY5;tyk^}DtNbBoEf$Z|Ek z7i<3JqXlV~9c47?zNsa})g*!sw($*ESDEeZ&5-A)CGfOccRTmu zm8Oph!i7HvKk>RbIEjjjij0n=g~RVLY!*ACraB@zX1pYx;c=Jv4&QFCE4I@+tl4<;aa%~&KasTGyzkz+XHt|m zaPRnL5VKk2mehi}E497glu+>_H6fMicA(dVoy1``pxbZDCxST)+IAPqP`tS8`Dnc@ z*P-m1l*5|iB+6&JmrXTm0(>SWoxspaNz{S9kiI{aI%c%b4J$3JtLfY_tZHX7ODM%9 zQRB(k&*HYfT}Yr#G(G>K97tP^oLzT~D%rjObH><3*g5CcQVcN-G+f*t6wXD?VDY*Qd7Et0-(Dv#s_O9+mO6 z$=w=Q#NGr906VP`{}zm^Eq>0Nq)kmFpItE_k-C`0l%8QsG&|zH|Aemp(;+R3_9&g% zOgkV(%Lud8d#2*kY8`*mb5S3zhufNlZzggQNEwxpEDPXaToa+Yz9=A?4S{%1FrwGy zU~tFrU^@C~wm++-p-R2At93u3pWb-HI)BznShp-vZ@P2cZLNvVt`3(nuB~L%v$$Z- zkiCiL3L#YUUDY``iK}Sljw6%heMgg+E=93-7Z~}UBylB?B(BUU$WW|#)G0&2(}Erh zVz|vP9(6B%S4P3xv}Ai z_q1nZzUUy;o3Qa|yy_YZ;9g(#Dw0YQ6<;tTq*7TQb~s1@Y>PeQ_)x?XTWv*;tpf-U z^kp!pf&dxVyJ3+a3zdLPHpaNOcFpn>iqKh}$5@vp%utN-*wbEi7Te!F_T2B~ji81D zE8+vi=(w(gc@BIZ^&+*KlAyM{XMiFSsK_tNQI>z87%eSvE1`y$hFf~c5p%L@aMTPEUyO7dsSpw8@<83*zUgdz;4Vy}7Zk5B{;y^TOyN*|7m=vmtw5 zhCV*_MGvBejUfy))pVx+{>FT5p)47DH^J+Vgpr5X1-dLEgc4Yj}I{H zUQ$59>v}bB`#tdZI+WblO_s~XXCWflw4IloCkeeu7+bZ*T>sJLjEj`$4t z+3Uqja!Ao0 z(e^c2l^rPo6&f1sYG0tK4fCSH+)u-KOhGRYBsbhZ*lyvGk7n05`cKIddbFQ=zJ>`j zUP`pxpei&Z!qllnIn;i@F1Qb1E4D}C;)8~52k_g|3YkXNgaq7C_^-Wz_3z#wPU#Io z=fC`4yg~iH^#+P?XY9xa|Hd02fAa=3&>MWD^acc_H%O!Y7v2Ed3&D`aFI|carBpP#cx_aAfL`a;92p>|nUo*9tmn#RQl)FAYGD-8 znwH7K#IVwavZQs^sXvr2-MQ966gW+;aboHSf`vxiQ;4}$e(m?QvnGMHC7?Grf8q_a z{ttSC^54Bd-b-)bDJtRQ{);!@EL$D8yrnVMCI8hMjQxM+4XXd)4c3+3VC=u?4Ql>3 z-k|TFyn*R|*BfM){4d^s^Iv%b%ip}gJ1@Nf5A+6Zzj=eI-@U@)tH_-ak8-VM)fAt3E|L5M|?f;oKSU&LvJs><3C~%?GmW%PKr@>{|oDwo?l;0Sr zQubrNt8Th&@7J0d)pl4nu{>RVBiEgw%dceCJ*LT^W9G!S@Yo-TiL6iWZ?!N$4yv|1 zt6LQv#Uzv`zQgv9Ny}}h?0T0ii7qyqNj8h=TPgEi>L@#!@seIA;4x$VG{3?mBWC*H z=JKSQU#3kRq4lIuk5L`Z?Nnc^C?PNsozzX{U3FVZx**ss2h&q34ZNh zu)Hq%I6;(^kd=@f%72dd@?G{C)|nfX7_Sx+5gyJ?s^X~8;{Br+i|?&48(saGb2`qq zj%`Y`^-2e$pS#yL`S<z`TvB1*CWD5h1DwA{f{&Aw&b=4b9hzA*R&DETwqJ1r! zNO8c`x~EJB%$F_A#y&;+{_i%fD}Z#Y@L~FO3zX4+nEA5A)rNtGsl@8WMnh~lWSWq$ed z+lAj^8TStLrOgY3gWS3>B0DNWw?(7)Rz@ziiJ8ZYq1;X2zd5mW+wxtqZM1x2(YN)+ zf$kw68kT>5o}dnec>W;33Lr}~w!ZEKHun?x=FG!mE_doq2GNMXd2CTxXk6uw$XaG* z7Kbe}vZ`qz*8}zfs*~&8nlcmW!Ly&3HMQ++Um1x?@3vklVXF9ByZ=Ib1$JsjI#KRE zktUZulyB8uqI9>dHdIG>Pwz7vE53aiP)&3r3#&9{j7TE*AI}Im(Q1?GSmJTx@gaAa z3g$ik0bJn!1YFFv$oLcB;@6k+rdu%xT&VwZ;8OcP11_ikEpVZMzy+ZMF4oz3vX8&` zH^7B2=;y!o^ZyRGu>ZTj#hW}QEp=XvIbuGVIx05ggmmt)!-FGObx~u_r*iY#lV^^n zZcU~ciE@cBN`#YWGofS0q}pAtRvZL)BQegQ!c>f#2G18BJ#1&(1|^iBEH8M!IIHOp zWs+lDX-<@=&^^Hg;IR>5u1tv*_Pn`Park#NC}m!c z0Os}1iGSjrsw;VPsyuzVaa+C&wrVmsgdz%iJYCX1H$Cf5)s5-x+5vh~s1XS= z7aH84*Ye@0KH0_qe`C>ctsemJ(EPp%EKokzX9no%db5r>oj81ms2{264aS2~AdslxK64#a-eby>8 zL?KOc_Q8+Ts^+HRjqg!qQ|*3~+hMo(JuVe_J{>-iE~atZ1l>3X7N1JMB_t3pB~9WZ zD$)2M%Su%`fD&uYtZLv(Yk4?LNW{$evJSy+6Q#H`UZ1g1BM<)^KHFWnP{>N>tekC( zu%6hDVI;wh%AeCK7?ApfS5oQ?8k-xT#jQ)tpV;a(Ww!-mLc^z6f2$WeZK!8~|7F3Hk`rF( zXeRnLz*taX<@Q!ZNr1JE4s?{&koUcXPj=nPN=8F{LITBbz5Wi<{M80gEn}jiG{D-y zXtuB+ZJb{3+@AE%;_CAYzbGCn=4uMVj*lMN&LxHxHr3WvG>D4*O<+t?`UgIxjM4J} z{#(x%7{u=%1(XEhf627?u3EejR^rv-!pjAZn)rT=?*G;%y^ggust!$jx9U|6ShDUW z)C!`*XEX4Enwn!Sa7}0^ggJEFH5?e&+6>y-nBJC8JlT}&F;a(oT3r;?1B!8O9<~?Q z3G|3j<@a8R1Kfb6C$0yJJsI>kj|uH*(q)(?W>LyL=AqOni9~dj-Vhk^2+94Sz zfO17i_iexfIna#k1OKq5m)pg^ZdSi+T&sS@y{WJ;*?LUbQUg3!Mms%HunHz$!mhab zf#=H9_2wYh&b~b-myiUApCR(M;80g24BZdI=!t=T1(3G%nl;3v_%+yFot-z2#86+c zN9Ywl$WtI64hQOaJ>9zM03PCJECz&n>O`poYG90nSgUa^TR9p-0d59fy~sY?J=0|g zXoJY8bG=$A8AG|+on!@gDO-U5-*ijTKj{|CiEdGrXh7YP)gU?1Ez>8Bt4^XEVBZ!a zrEYOj>J}OPY~bI4<^+5@Zs8ZcETP*R=h& zDp_-A)cJ7yGRlbkUI^~tb1JYoaam6JJc3vS(@(VJc_cUEuJleBr|_We(A2Q_lBLIK zcJn0v6m}DRd%4?3a%991ULK-dia1#oO5+NZK3S)QDby=ynT-1%vmg9$7Ad z+7+k=o^B>;aP`$jiyH=bA3^NwB-T3#+SwnU_5SV1toH27RYvo0zBpg)j6I$z$Ck`% z86-tI$3XB*lUD|5WBGh{V_7i0V)f2ABO-Lj%bS>GOt?{b8MB+|Z|4~$ygGK^Ggpnl zvweLPWHQ(_QF$$38(+-*$at7pm|3{yG6ptgk5-wg8_AziidPM@+C<}qmT+A&@cVZJ zb!!|QdJ(4Ax&StNvvHa<{ESU0SnzndWs0Ny#17;>)8$ZxP;jI=iU-vT7y}C{?#Y_( zC>wBr6pLjkvSr}1FTz)OlVIckNkyC0wLj4Ychi3j?j|1Su2u<-noJR+jz{|b7xI1H zf{2t|kO8P3Wl;^@Z|@+kFqZ*5q!ERrhX*{wcpv_<1wIRLm*SX8GBRv)@CX@z0KP6H zUJpG3uuVxHFAF}rw9ZDE+OansH{-LagCndpMTe2_c&^GoQF}j1Yn8Qc8C%+|$|_`& zldmPIQIPn<^Qnh;yc%_${{tb{`05g$SFP=%i8D93xOEd@+DZ=vd9KMsF794}UzduO z4Iz=TfGY$HCa#tQ^h98P&bpkHyV3PD;;EvxXT94SiNryG6pbP51QNDCZ_T@mNABYj zU}7M&ANeMKz-T0k&WE8s zna;4JJ~!BbURmYUMy>4mo#8OXuTd3#b6RtwF4pMYixcA|yGGn2q%_Mm$vt@1?-=8` z8~Et9df+4S(df-5{m@1SeIx`%#+gVC+7ZInF(y3&Ft8PEh#efJfL_BQpO8XuYJh!r zHq=6(&U5g0F+e_NAX*n2johK`UR4d<4HYf*)JBT}&t3}vo6wuVf;QV!<>=lfavm>Z z->>rhhRcBazxAi$YEhwuV?4ZoUQ;w>DE(o?XF~DCgD$p23nGTVYSLdPVk%Ug&u8+# z08%Vs8d%CYVUqGJBmuptkt`U0d1lcY^ExL*I<+TYk?zcg8{~g;y^=O){L%^_jBb1Pxxeo5TYgO;Wu z>5JE%ugebZ6s(LzVKd+mP7>VTWdHf3p};(r@eDl20wrjJ_T^0gI=o z!BxMKYLvhiD7z|RlBHjYYaFx4xR9oS-6Z$jdaM|qdb(lcd-^ZuFyDxqt zbYVCZ6R#>|2Pfwi6BJVk?^Pwl=nPUE(w&QLP2Hj#DV#hv+cGKZW4NUPPEz)aM$Gh; zc|Xrt6(}ZE)btp}4#lHAjD6f?x-xzF2nLD%Vuow5Cqs`Qsh97z0zyXu3ah|VRoi=x z0V*{1qMk?N&?-$MoT}To$*$*=yv~hUUhqs^nbO&Zl@Cv{G7O82{9;+unTUz2IQ8JP zTiFnwy<@shQLNU!L4Vw63h8LLEz}c9LRmmHq9sl#QJ)yp>0n^ zEdmyc061Yhv3?!Y(=87m@6BxuF7ES!cr!EMQ$kj_D3*VBgYHl;`dm!+NOv;VH!wa< zrM?=kabf(~_@zfUzvrp2W8TVFcd*xwjw^^()H~YSIxb9HI8Dxls)WzQbU&oG(lu)F zMBC#~Nh9#b+vNKy+9>9dy8J*>NHxOWk(xwPf##c5s`3;EExAdNw=U3rz|~9EL&JI{ ziZ=U>3G`nQ<~AoRIuqxI`GNC!di4N0h4dd*#PQf0$YpIiBkU-7jEm72+oL?}&DR=? zz4q2zK~FO>643~X->jqoVEr!7zVjomH_?N%|W z*N_g*_)*NtGw$n;gpTi%J7i;l!fHAtGe(!wBncE2i@B=<#bgH;f*q#%-uHK zOYcmcod56%@yCPAwmdp`GJwl?@jGA)FQ49)*Xj#{X~2|MCJfd-J+br#G7i`Slks?b z$)uf2=zJbXvb3+5j|rDUO!G4eU>r~e6iMv3o-^X%VxC=W8VxXee@K0LBt8|Vt0 z@xkYJ_N#uO58oJ;Y4sIs^!3_Yb-0P%d$_zuBW=r|>bJJ!F<-QeMkxHoLJti2^5nO= z`f^x-k89}eY+Oup%$-6lg}?J~-49!7u3{VQO6}sbgbWI=3fh(^PYTXer}HhG!Aj7u zT964Tslcj$2OmhNoxrxjp5ABY6xez&QU4dmxq>#GS~1*%)|}NnRw$E)t(?0 zFvQ)52_89PJD-9xmD1~3>%3E~%4w@YvG8%%M`;Si)k|GJw7xg`XRzDtXHVB>5@SnQ zHsv>#z)iXku%&TRm*Tkhs|M-255KOtGE$Zh-Eif@4}XYeH6`U0ewRc0CbH3Y_Yqwk zd8K--{mJ;Xwn?kx>(x2me(=G<+3Wj8pCsjS-u!T;9 zJ1E4uX25luB}cCR9}pJh4zJ9O24@epjPDH2Q(xPyo6Tcc{QaeuC2(Zai=pg57laK= z$*KB7qQWX;!5XB|S+B#$F|inOyAcqJC%=O z35Y-+ZiAQImVFV6P-y{FM+tL^=R)q&!6bfCQjgu5!IHMVeLvGlKjUWugs?4yeGQWt=Qcl?L_N+OAVf*K> zm&o@#Ei8ssyQ~^|q$p1}>fJ|2wM=S^(i;x?i^hEPRe0hmTPd6M7C4;_7K*@GY%^iWb%xAFdfl(t~%q6#(QQ{^6O79s{Sw$Skh|i{WX4qLOLeD$IvMp65mZm#dC6+Q=?z!R>hc+#BT z-})vx-&fLRh}$u(mdwN-__U-xx7R6hrkl2wXyfE8@{ovb+$q9p;7XVGOuFo}D!YAG z;bG}0(9giY0K2|4zpf{C`S(^)Rhu3_B8EEV6>_(`dt+KqC~PhZg%PbIvAG2(O>jLK z1;)tIeiPEzaBo;$Za}UO7IcXNbhiGRe_0d*sk5+ev|*6<5C-*%fiaTr_u;`iX}_p? zy`v$cmIb8h{n#5aYQ@nyAYmB)ynX=?!%+sd6*w4U#vIpkq*O(H5TucW$tdLkhB2wb?MfhH=*L-dDBJLqQP~oBBZ+39T(gB1B0+mqQHs$A zO3Nu7PL7||U)>Y*4S4WDv#RGCurtiwZYj%G_h8fGm`V=53??_E$i2o@7Y9RBmkts$ z9WN^nwBLt^I7!hsS9a8j@N{UHzph&Fk)NJnpjw#`+vlY@Hk8*Z5`|coM(t6C4LkjI znZfdBYY>A{Zf=iG{nMKh42u&XO9-;z-W$DGxp@swW5E&Q!R6L>1^7L+i zG78VNso~KlKcCy#+U%CgS-;QG2(YvG8}ul-t*N!oo!IL@P*y6;7lU9+eG!$?u`4!6 zp3SRk*-0?JIY3DcKJ;$}6!ajC5UJAe@`-SGom>zw zpT28o;I)O@)m6A66foiiv1(ei>l<0HWFg7Fc{CuJ)WE!e3x{lAlc&1Ikh1=Gr$G_g zn*tjx^k)gfJ75;m5$@ELvdh#m85mON5tRL8N2KubZ_X_E!{8;4%NE8h@;}FhgnUnb zYFFrHc3U#14K$!NDq_V?Q?De+JU?}!*$-5J`)J<+XC z16gcySqjn>-qCTg3w{`{tRCM>Fu(oX1=T3v)TRFqSc07WI+_Cyd@hAzYt2w_t`vx{ zHJZe;TTVXsYo|J%_1Zh?r?mOjZ*JL^{+}k3KA26|V<+Ta zPL0yd)a2~ns2#VzY=r-8c)L`vqVJxmmduuw+sZ4~cuP?BqC!La4;mXLx{9kZ$3LfP z`Hq@#uwUa>j=o*6dFZ23`8-y{FCu+EtUd{pvMWjmGpT)7!j1x>1ho_()Zs-IDR~@$ zA_^yIh4g!efn#3;!s2fS;T_^byI4f zs`V1zB%SfaFEa5m1-Kt~`#7e~OjrwJ#&70C(Np3wVvG|)(%_3klBDJ^-DdFv^aYQ! zG@j5+ML+WU(CMJNTEGZ1)eFl>teogM8>1PI#;3R2yPip=VlJg4FFwZ6%nfp@L;Y#* zxgz@}>oD7bq~WZ-c=Ms51#u0@@R85q=>D&e(JZRu2-Y#sSgM&@ktnZnj)aZ4Hp&~CgZD9T{Q(SH^Gs7*+Z>i@tL1%wA(7w4Q? zJ?kt#IgcE@Y;j)WetD;(V`CK6e>K(OMb>qrTy0cPO#f9&N2{DJL{|nGi6@k%hW88r zjsx)5P6O9*ukDfA#_3Ot72P)P(YZeI4^e);u-C4+b@r08Jgolcby9{ed$L7eZ10I< z;gi7zWcQhANtO=e{4lPdHnkr6w2+K^yUauY*%Jfq5kb&KZTXNmag}?UG5LN9kg|8d zUYq2+8BEL4$-V~=6tOV$O^S3zIBQ2}xT;*ac%MWX5wiykkruIL)GV=1GF(Tiqv%>G zBCEcMeFx_EY$jF0l}>X)L&sR5JEeP^z3oXaAEhc;;BMM@V+O=u1f>Htd$>w3Ld%yef_qkpjBwc=U z5rE-4FIhALs<0q2LJ!8gIV~?-wDgZ7!>{82pDlQW~pWZ(;Q8k#+s?IL9_?N(?Q5Q zF;?mz=Rs)fulXj)km&&mVpN+R9=TR(N6lVKSE{(KFEECNiqaHF`44rEhqD26xr)&J zDmiHX+CzSSwET(7+panAANwQ{>0xbsO;8YM-4p`7rsRL1T&I zK$xuy;sYYBHnc_iqE!ZMjh@g)y7{%Axg_oz&BGJJq|+*!QzJ``OjJ_hi>d`hGB%Ji zV*isxcTEtL)bnJl!hE%Rgmpq&}s18b|8do2Rdcy)jAYFQ)bZr{<-boeDL(UZ)d+z2Slx;Eq%9= z5&PZwjGuizL%%=1(6FHEy*SGv;jSmRsx-8MLB*rPs8*{liC_ruD1MHM&vMJG92Sj@1v+ zLf*A#DM~w>O)gs6J+jycDzdf`-0Rc{3&-iL)?WJ9;H|V(eH;IYKer+6mhE-gk7L{@ z#to9AyIbGfnz#LxMAjVpsj!C{U$l3p=AO09(lR8U&z;dUN^QtBwr242i)Va_>XMl4 zsYCI`d3@W11(R5lt(fYFuxqxIRzpTkegU=8zC7H)e&D{H&f!j5XW^P#!FF#&#n#Th zTD`{2Xq^|L4Hbv6LgR?Tlq~*6iDgZVA+f`>X>g!DVs%ilJs{`^%P@*}bzX0$CfLo| zQuKrk;+i&M<)K042ce4m6)`*n)$JWXmjMqjk#$M?>`1*?MpB})j=nzi1u(mp#4io? zxSOg}x=lb78%Jx2U+W!cu**u=RkTw+NYv-e zeVz&bht*zIeQUcgtD1SzX=kx>Xicq5_+EJ!oai1K@1j4ei`CaQm~GcLO1NhgcW6EL zWyNB4c&>E$HaoZ0KELfcy$2{doS;2l6Pnd^2$ta)he>BOLrFFT=#IZtp?h@{Z5NVz z3gc`#dn}6zT2k+aeY9p_2f-|LmWR`CyLCPaHR$)O4yw6rRSTW6s5!yb5p4_$pALRa z+PHuC-Hyz{)w1+>gN*F_HOuxbR(^2eg4px+93S;S6RuOY<#oa439WtXW-I@`iMCCP z=)P6;m(vy%H$y$_0uqB7=IM>rUxsAZ+K1a&bq3p3J`ZxJMjd<9TH3ws+^|;~VQ0T- zQ+wr$@JnHo;NWF`;-!q4%$~omXI2X#J9$x2{l;G?eRWl*ZB1P;L1E^{l#2M{F!$IC z#%b2^mGdi!ak2C1)Cv{7)&!)bg?~ru*%Qnz(u>pRhuUj=x>vd~(cQdd`=HJyD;mu^x&&cn!#|+J%QNIv zwR4@q^@J9Bn4mtgZZ5;A(I5kRFCbjFr~Kr;@O|%u@2zsvH~zp7lZ>BT)>wI;5*sE6 zs`ZHb*xM#8liKe#_@Fbi-FP6iHT{)*m=W?J}JEuLT!)x+I}%| z@6UUoogM3iMGlpXDjs8Tye9oc!LCJPTuVroqds~*IOzU_ahfnUOlW`olHn7J)%LpG zurC`LdtxeHT$sC(_(0?aVUn8HfH17dE)xkzUprqk}e?g+PRgRNU z%a+5f^oT4c=Dgv_%2$^ii|$(7#hIeS1Ct}|8->@>eKt*I?bFf5Xx!ODN^ZfH;daM` z4g1&x+oy;;fOEsThhz-UnAcw&%)%zbKYCQ}^ZobY;4_y{^h`TTfO)ZD4WDlqn(WEC zp#^B7Sdq~qxsVY{tx8!m*}Y(Q)bDf~S{O2;v%`gj&5SXkT+f{c|SVWP@4nuzgXQT~5Xqpy7}&cTchF zQU9Q{f)T!c#lEV+!U@;>-cZ%UrwQTJ!KpK8sdWzpYX z?84SdetZL8{>rI${r|$3Uw>`?dh)YYepzNU-k`I*-So@a-I`jvgqFaasfqJWaN zS`#dIp5d{Wwq6yM%E*|nWI%J~RZ-fTD<#w@MPf#pA#`P0q=+u4FSJ?ANPA2D?T65Ap&Or`-%>y3hsPcl{Lu)=QY`ree2`+g=O2jo7n0Vf;;-E)U0Ekn# zu#zN35JBx2lV!h^`S9@Sz*7Qf6+*F9cyAe9*SUaDg^5}l6RE*hJ?AIlS|}fQw^A?1 zcVyVq)74K zKkJ)GxT-P=G7A0Ora$W*wLz*I)LBtgkZV}Hwp<_Y*)tIQ{q2eRgnoTbSQf4(HLlk9 zaeVN+RWPJxX`$Yj_X|Fx3f_92WpHTz)7$fl%xA>!d`w9btVg=xu2#)Oj&*-Fx{kaX zQj%scY?5d)Gi#hLNwp)!RC_NHhg4@!$3dYGoo@nxD2d5rByk0bg!TFU!yKmiLsT!S zSE-II&T3EBGBce5I|IL~HG+y1T3J9KRHPI`IW~~!buTsuD!6wcsTS1Vjy{@O=oP1@ z3vNzj*8n(#6l3BGpwUE1D54!*pwY~T)xslM&{n?!EN8SYvSx5TXdtiv%#fOg!97VE z_6@W`;k=}?F;eq-pz5ma=#im92?&4)C7CF=hFD-sVaVh^Z}pqB+AEIN-cs#>PuM zAsS`fHCb9j>+`tICoKm)198Xb8)3w2Ibq>JRj%O{Z#xVM;ulXDfl2d{3|=OB#q^0? z1oxZr@^_TsWrtgsITy5$>#TJ!^mF+zP9qIifuircb!A|0WZUkX?xX0s%F;BSU0V|< zvRqWEIQ*z}CedIKxoNq;WKS!nBY{D{3JVqd%bS4I5@Zt2crm{F0B(<%#BpoOl@NI{ z*^nU=MJi&d1l`@#omLB*nfWzQ5o?YLeyMwVj8qrzF|P!Fk%pYhLtHP-IYs;!r9O7? z7vFoXjfsC#+1xa!y#3M(8hfY}b#LF_k2*1+^^)jIsTLkjYc}7cCPrJEu5D&T$`k-G zB435kWh?#mm(mwOnq;&@L^;yo3bOPJZnGO)kdBIj0YWT0wrMeL=jp+PxhO0Bf$OIe z(WJvIO1yrWcn-dmYj2R1l{BiIV_8enJ%Wv0o^T;FclGnkrYMgY2~56%`S&9fqM#OB zl5TNuxMt5%tNU_i3pqkMx3Qgnzr1DvS!NmlPnYR&A{^Wfc8(+nuw%>Do7*RIEqIIe z{F>I(&+zeKQ$(H1rsnt&+RwfX-W)mR!JiIq#3E5EfCSU27a@M-vhv)NOPtbF?VSaH zY&`s^4GwdQM=-7e8%7fVvqG!=*Ds?!5A&XJ3hzw}v*Xeqin8iv52=5?98eD?Ulys@ zoui;!zJRm9YWa2>E(0^ZA)K5YI0<1U*6q;NLXSTm^V`jiW6JhomJYeJjFis%g{x>H zQ$Q{gdqpcpUD#>VT=JGuwMF;i2CSrH&1#3Z5m&et!O70L>`^F1R8>Ig{f_=7wD=q1 z7qeoUSjhhSCbamR#T)#o@uy#mLLr=?>d@lzniL8x{%&P3<4r+0*1Y`wC$uU@zcb$^ z-|nN0nj6fe1x=EI>ygZ0J9}bfH)nR(K4IY8)$C9|5mA8p$05<(?~x)6qIao=Cf$=o z(D@4TAw$Ros1vaYb=CYYr`@Es21F$7r}jc!wR=IG(ZlLD`3`t&;rVd(e~)A9dPxvJ z(J8Y~P^gaRI(8^9$`CXU3G|ZaGUm>Ukk;vKuI97B(P4Xh1}f9=Oyrj?f;SCab)Mx# zM|+2Xt(M)RdLg!500xIAh(R~BXu*)s*bvvPQjGSl8a42YZXG)I$?efLyuQ;rk;Hk^ zb)RFmYjJr6#e;)NpOw!r9rBZo*hV2Jg6Tqfe|u~aAwu}^t~Q0C|e378ox z7%2&aBCr-pPjEij`YW!I2bbJWZ zSpaj*wH7Zz3!Rl5%{S4bZuv&KN~qy90vQ;pEQv$qw%eo5*Z=@(>a`ne@@mw*A$9xM zR^4P&Bk-t@<(|5$P&XN&#O|Ke#L?8dsf`daVD`wkt+Ob@$p%{f9jjS15TrXL6$g!I zP;Hi{lb80KWA%IjBBclc`*8FnNE3l0mD9@v$5w~EL z4TBN-U_p*CV=EgG{8}tW$6JodCeI=2of+%(3@c)kjYLen1=$SE?(WKGRhmsCp!YN> zNVQ?MpPq~Y%9JoJ#?}IG`Tapq5Qn?BGv3|%*0@4*6nPa=t35mD)3dq=kd4?EWm?!w zBrDxp*T9d6Pako$3M6LVB8if(Vhppcu#ne*2gD-V1}A#j;tXa#+Zh~RK=vo_7;bri z9&Biau6QfTZ9fY9Hc=tUQn6nrlIJW=w20pcQ|^KE?Za;br~eK<7H08@F9@t2hfsH3 zNP%gq>TkF5j*o_F7fsB<{bz$Ch5CnrL^^`;T0pCsOWYM|xQn9GBn%T_lPQ7WaVk&F z@Y}FC1x|Xv@1nCT|+tqC;tiFsKvnjRKUm*arnV9a=ys({6(9RZ4#(EIz z8wsxBgCxY1X2zJzB_vKX%X`+-^l$?blzQ@^B-(iZnqH6nxE%Ys`JI_kk8VdF~&q|orn7y?gtmej~ zL(6*YsEW)?CJ_YT5z0qF<(NX8<2w=a1pO=2posYMe{|zh^sl4_MZC+;x*Q)wae7RA z#!i8`nCkn=LP+kea+PMSw}v98{sf)w`R_0+TB9WRs`8 zN?ZS@X55i(k}{w~cYP->JCDhBdZ#;3&#`Mo#3a`dwlO;jx*}EdxYjE(*FhGjRDQb$ zzfyk!zJO>Ikmeo${e1`v#L6axYEQv%kosqd7PUn>t8b6WWWG|x_$g{SGE}qpE?cG= z38{ZIb^$-MQp^F9tK{k|4H z<{M`HZEE?6k$QGRnsmBIY;?r9fz234-y%GaYvQwKvkrcZ&7&*+J?cqC;AeRgb( z?+$g2@nbrPBq#KLW-<(N7FRO_k$t^`%m^Mo9cJ@nc3r6%z{E$Cx|U3sJ6b7Xl9I)P z_sIh72%G4-%_&M&Z_Oe9NwhraTAGSh_g*c9vly*yGDR-+Rjpn8##76VT~Mc6)ZxdB z*FJG^oI@81yDl*j8g=N84CR3jO;ij;xt*uI$61@=B_84Z@v}^OYk`&~Bh6~)8Df`6 z9=aE3bIndrC)75i+bQRcorGsE7r_azV|!{ht76rkcXuHu@AZsv&_kWu_DMi{TB^$2 z?QTGLV+SK#U*9Y}Ci5yh({lbIH5JpOuX#Ly589t&Y41E69ec*X+wSPuQetqpUmrYh zI4CkM2>QceeWGo^Y+~jo|Ja+lNNunRUS@n#r3<>RAk`)Se^k+Pxp;h((R=@N6|_?jP8vE!t8GfLqpx z(Qz-N^@SY8QASyg%rkjvtC0dQhs7%F*jepAc2P3D{mV`iu3=DRbLnh)mf7xFI`YIO zC51>o(iUKDEaSXi5)%g4u}7wJqvOZLzRuh7+K^@ei8hCafx+pw>`v?zL6EBRXX z*a<1>O$}UK8`rIq&I6J%ux%RT)4hNYxk%IziSoOPW6sLQI`B2z^MZx-R@2m={biFV-f}~}RzfOwh;u3*k1!sBL#Q&CjxKA)+|GK_2%49*Y|-AW zfnA$q>uE-t;okLm8Cf=0xx>bBJv9?*C0TO%4WoWf4H~aI{vXE>pyviNNbGSS>8qCN zl(J55{{vUsq_lIauk)IB&Vwfi7B2s^yXNbpzG(`UAq7r!Zdhs*}L*|We ze}s2;3tJDf`aHW1*(F9%4d*2J%Hm{IZG|QjF;nYp^RV z{o-X`bf`y$aO>Ao$X~UYO&=Z_ou68dV`9N4O8dvA_V zdD`39+|g+o(q)dxmqqtsq@h7c_Uv0HHX*jeL~ks5tFbbd$jf;Zb#RbNvM&lhi@xAY zt=Ci~eIZ>wtE3WSDrQjpsJmaR;dAQH724s(PESpuh1+^ftw02%Lxb)9AG^-!!Ll-^hV{~Qn@E$L0dEfn$neoYI2;WcE7YQSNtajteul?aj0JnaglsAg%c814Q4$RfO!zgo0A5kLyFC1GV2q?Eg!dcc9v<|Z?e!nk zHOO{-!6fHHKy;+*%lW4-)A^=tO3Z2rc;6!sz`Vn|H|0pkjukuVk{!VSr5o1*hM~Yx zVS%$arGV`xNu1!*x5^P&zVb(lp}>TZN6Ex%^~YG)t5+|lb`}X~B38J?Vfy@4gHr#2 z!PY2A#+slOmJr?8X7x#aTjy(=j)0J}o0;)%y(D-K^k-;NwfO^;z7ZzM+BJ^~qiiQB zCAB~CaZPVQrH`f=eLBiyYvv6D^f3F4t-_5W=Ze=_D-3$$S=IbNj8G91 z7jLa${GHF-TY^PJnj#}OLll#cA<8(-rQJJu#Ict*+P8ae#pqnNxnB;m^~{BrVx%)G%H~5EK4JTb(kIB|LG(PbgC81FroR_#(>`J={rlq_4O|OD`6+W{jtW zUJ+|{-o`|vKZVy67#TRB`!tPui(|~wABS6d?v6A!==xA=b#RuLRR+CUAxXJbGb6s% zx3(5^w%mN{^fX00<1)(JK}jOce5L=N9r=gh+9A`v~CnhX~B7<5~~!EO{0=M!pw6QiAP~2-nu-1l2AW z>OASWCwRb7ojr<7IVs`76k?$h_g_-dS%c4h+_Z=^&J3fbGt)#2s>vTwQb`k2;@{in zoWY)VhM3A>0g-t(&yNg} zNARF>|HufO&OAOtNP0^AF8e&<&PtFo>Br1nV&FV6p+DynQ06PK)!R}K4bPOsNo_x4 zuxT#(1L2L)Bil2RtNBEXy!Y55MLATj1W-JFX6uzq)k-6S+7z+7vp6CaZ`}OwN_cZ| zeL{=wZU2Zqzodlzq(}Wui`%(H%g0a8w&0is=cY4gX??dpQA4M`&ES4RqwN#(Cph$A zYREQA*8M3s23mSWd`_0gu_aPqzq%KnXDBe?R>K zohUVL?JDv-fj0cp|3);avtG|5nm+y|ccg02rBw#nzjd*gA40dHZX1x%C<4xvlGB(n7tQNZ5%DEl(_3RuGLg$O4{+c+{iB z`?du*jE;`Q8XMaTD9te=n^7?d$C6nj(`O#?INLoQ>o-jbZ6TfIo1h z-nP3k3t5rgyBSC=PcaJ&i43W;mun8r;G5AgwBbNXmSR7Z8K@ZSVJ0bdIb=zCTu~HF zm!9rX2N5rGQhhOT(lcEZh&q*0Vw?iRd-hRybK;0TVBiNhbNo#CkvBC|GvSZP&1d%; zB9gux)H>n^9XqT~K0S(y3PDsoAupzVnD2rOqmnoB`*&vPj|w!rcUS~J0Eg1s(gJi! zMzjt3%1hk(oX3@y*fIcbjAz5x9<1S?N?Fe!O_gm!qlGR|dAD(qIK}znD`Dvj&*w?X zARd9YbiK}w99QX*aV(5;8@3Bg2^$vQviF3N5|EV;?y|DQuI?P4_NJ-`RaX`K8}6G> zRbl+?0_i;G_xIb)&1!s_y6{)y)BbdhPy62T=W}(@RR|;>H3ML=Sis45nn@&;B4jsR ztPsFS34o^obF6Tj!2(hV_K9jRLXfNX3(LY|lYO3#+5*+%}KuNa$Hy%Y)UY5F3 z@n*<?oXG5^GrMigg(f(1UA#hrAg*x&= zP4|Vtu_T>QV#A};V&9VzvL}4qij41`+kZsVm65gn#W8+zeaZAH)qVF&$4Vn|%Mn=G zoKMThG446L^m3E~gV}?+XBymup6&ZMJ-v&;J4!Zo4p{_&lFu-dSVK0J%H_cHaG?!a z(M0i~wU@8|9{F|9thDACf~Vxar)|a=XMdDZOEh?tRe3AJy-Tw|1DRK3fQHtsn)1Bo zhpJSs$cWR5x%88C_$B9~KdjW#QYDky2f3*Sr77PPEDHyopoE@u9nubiVbh7hETV1( z9)sh(%>*iU)jMfM{}_cBNDUe@es)J}0rPVsll=I|Wve>$x-`Gr813SbqDl~C2a?A^ zIm-?RpCO#%0WY%jCBKI+N3)~5P^&p(L{3UzvFnpQ#N-PKfFV(UbX`}#1>~NRSsFw( zp7XCKD8Mfo#ffIi3<-Ti%qiOe(<}^>ulDM)sBG5WG{ROJ2~Qm+vVB=|egKtsiz_91 zq##w8f=HOYa?G$Mgvdo!-keua-D8X-)P>+!D%E6`&Oadgk|IH@2PdZf&~yu%HwJ-!g-tT_@{ z4~^+BYEG1^UY9ogBYokEYPhVLX=ug#94a%uZyUzwU%Zy&FBVcGQ$wBs*0|_#=S8 zhaUIJFJ17G?+5HvJr7oBGhIkWnNNm%#X?CAU-PQ(jept}&s+qOmq%6!WB#zVazo6_ zll({^t1U*Wq4;(cS`jEjwC0EjDSa@rfE!`}Ky(6cBaH>CFinaxnqs4HgSq>R{QCpA zAMO^~pjd|m(=j|-e*G(sXF^3d?qiD%En9Tapl;si(vIN}6yjw*SV~e!CrRIWA*a3Y zc{?eo7*M)rxp=f@#@oNDuaB@I%@Pb~SRC_O)m zsWq~VKi>My!~bez)n_q%0BVr@70Mv^5XvB!J9lDN-g~!TqyEnFd$;<}o!I$>1!?XH zBsg>`gUy2zS|Zs@b__;(9M}-5VMQ9z+%dc0fbAm&-ek!;$jRk-&Vh~>J;+2k$kmNh z%6LvIiYOgtB61C=iK9!e^~x&k(Mm@?$ZbNNsFQ*?$)dk7lA=dJ5xoVx;d*{i7vB4(LBpVW$Juxp*VI|hK z+uwQ64EH>~f0La1*rCq|>Y6oW=lhNQD@(ipeaU^4Tndij@Yl1iD=5&yGODO5JMQ4xLB^&@7XgvP=k}9rgh)VILJv0u<h501#&*6j$~{uBiYRC{$^a zlcO>Ts!RfhK*=7>aP4xIo%%|W9L}UeIRUSaxJ>9ZB=sm-PIukU;tuVN2V%y$P}~WB znav|#*2K`&l)WLTBW;_~?sWd*zj*>7bAP;L25J5w9`&os-XB3;SQ0_aqyA>#otHZr zh2xucBey5~85*zc8eU8m26(LT)tdkR@XqnNHG^JG&2p^kDHIAQ)i^3!N7MsUIDkNb zBLIP|M;zuPZTO98EcX^`~{)N7JuAz>UGK9p_=dY1#C%2vc+7GRL-y9Q= zmDe+iLY*uAdrUy8=?pOl03bq)W~FzSE0>NL35xW1M(lO;-zl`(D^2=uIvcah{8X}HI3C}bZdWt|)k zV=VI)Em%m|b^GDB`Y-{`}hNxt1T-ECaV21sUStKAOC|J$7Uy+t{ zEPT%{6Y}$2aa=#?E~^2u^8y>Bo1WJyWjc%u zfF(>WF&&lf+uh9;!_B!~{?oKwU`p0SWpg+SDYxSQUw|lu`;1@To}N5=1}M2o&KyL3 zTp&FgEBD_I(e+?LDbV1==e?h0G1T|1`HwlZrm#cfcOC`AsrBK|R2I5#-^2#}WcCJ< zGkJa&p_yddi=LYgH`I3#GBlox#LHYEK6F1NMt>w~q13yqaa50}P@JBn^bey^Tw)$d z(^Lmw+G6CT`_5xP*U_lAkSky-+2pPTPBx0oG**s?qyWKsa&%tXZg)!iKnTcser<%^=EMSx`%#%)7R7 zm!Mp9KSHvQ%11}6NObvfH`m8M@?@7v@*}*^UoeT;^WkoEK4dm@9Xz+3p3!j)rt;bj z)_iku=Jsw(COz3q-#|+z1=4#;b1Sm0hK6f3CH^|U&!eI;=jOaM|N0)z#pgpwZfuNj zg{XJRsYtTc)C%7o8&s`JAL7egSup8f$}NTy^bnU3*>&SA!}X>WKV5^DAv5FcKS?gK zyWBa12Ouj-nrsVG?hdC#=DJF7BVrb=R{5JXD9CHw1HkL{D`UME&F}+-Ba?$J`UZP> zsQgUxIjydufubT$7I*SKcHeibQ)~YsoT@n+qK}%2z79l~btiDgNK8mH=hPk^J&>w4 zTB(5>ckZ}-tj<0T%S;X$bbmu)_pSR8TF9xZtAC$YSIy8uZa@vEHeZeX`LXpDsqtg= zLJkF>PzY#$lS&wTf5_uBJ8535vSI#AL|_&FrbjzhToM(&@~zheV`vS>d(}`gnY1X6 z%HpfQ)k8@W2VfI0`l(WQgW*cF4TcH&Ga|2M;G#gO7UonbWh!MHVASxTF98cW_+gar zeEbOS*6g*TW>bcYxT$}9NRTY-zM2RPPn|9qx&g(x%E%eYsnZo<5Wy{bj#jqOud!oxQ!()%fBO=%!nH+X0$uv?tQah4x(n3p4AFz$_O)F$-a5v{H*~vpGr8^7d?JAe#$YRX=+7}-Q9IZtr8Urq)IK+ zPQbx?0eNG3K-{k^jTri|uf4N0;O6=m?BI5Z&ppJ(1>XMpSpx@ccfo7}7PZ+chd)Ce zbBtDg2p(JL1U4TW6*y&LFx-mWF$8d1$~Rd@#yoOk|OK&r8rwi5PJVV z1JciHinc<}H4M7mp zmF7W$R)ol0Ep33aihE+hN4c8KpgawbW>Z0rEH*udqS$*bT;(K|ml@vfSw@mH8J(Hv+m!lvw&bei?a3e*>RaqY`iRyz}DBJJl0u@keCkKAWgJo;T)U zFSx73$OXg^#EIwA16vqOT#hFM&A>2Gc3Yneq<;41u(9klkecHV?!0VN(}LV)K~Q@r zy#{zz*SzhdPJVtP$0!aF(~6*BQ;+2yH0rh9T!LF%n3{p^2edW+V+_#DhSoI;@-wUBH_ z4HBu}!XGIeL_q7nX{;-I503(*04fGGQ*Q`A)?BQ#PWH}lbj$<{A60E@VrWn5qYgz6 zH09EDqwN>bdO3G^-mQXCSD+~zBOiK-4I5!Jp?b-G zcJkNGAH3Adxh-{xhpJb{%sqliy!?K0B?Q|-;yyBws2`X{GZ_ZaXlF5okS=O^U36Ui z3;YHN_h@;riKrspR4wi4fPJmq0uZQ8{^cNkL46Q^r=miA5cfBa%1nL-3fbGQ5M%9`RA-xG_$a#$U*!<=gqS14GeLd8lc5uqY$VGiAn=S&PIq* z4&4>?aJ-X;*<2P;$$x<7dV`>}Pn(*K#Q;I?kQ_Bf%KOF`)-uIJ${gSq`V8i0!&7qB zt-M}gE{!ha1+J^OQUaV!VEb~;@+C*aSBHr+@jS4YUxM1x)F1Z5UQ0DVYZ}hpoxBj* zXNEXoT{KgabX|2sR7SETe^lDCVpHgSteE01AVBB>tQdh}ldszU6)DgWJL8>m-Qek& zG}wIBBSB;@TRlFN7d%l4L-fl8Ce6rVwpjr~4^X#_@+UT3!YK zf*dX#vFiKYoL|$LalroY{s0lzJg&H+!I(zwFy5U{e(vb}(gb6&2zx1-sRs%#dOd=z zDd)}p^7Xr+K{q%2v%i`A@R{OpY-8(G<-ESy zt;kn>IA%zrS5-3XNsl^eti$HtE`NNnHQVg7U3!Kc?LC|LOx62uyZ4?iVxdA{ekl2GfKw$@U+z*g8%tt^$$N}gjReSR9#5DNvZzy zd+OI=KettUOR;M)`1EcaMvy;G5S=bphAIghr|tSKK< zC;sr+os6HqD*9LcC4=Ogg!iise;aK3cGy=n-&KB*YnSuEuYaHdVwFjfGd874WJaKye3-O4t({Vx@_2SL-o7VuV%DYT)o#@mPTOE=c~P@=P;Zu?Ttz zr*fopK6uExviw+y1pQDZ(q`g5CWS`;vLdY{r^PHx^4Vymn-fqIF&FYR0g~X!JV(2< zP+(B>s~OL->}S!ChMy@?Ko!RFTadiy_*z|Y#b)_p>v(zX+WdW96{J-^2d?cqR9D4T z{~|B?awur!i-?-^p_ zQWQ9G`r4LZNX#qd>aJi@&R8g4-qbiks*hJLg*nfJ=F>{$b0v9A8`^v>`Lg}GK0wkz z!%UyzBT;3uh;pzP3e*7*h+j`L$Q*IL*6ToD5AR{0g7kFeqSah-VLHH7ZS}L^YnDm` z@i9R*T=vZYKw&Ca!?YOmQ3c%VW1$LD^rqxz>W*b#v8<)pr0QpAE%bl{&S|Hgby{Sv?3)6^vA(kf^4JK#> zXp0sNNqxQ`CgjBDHAk ztrxPa(zsPEQR#CCK4mqFuadZAeHueF(jYdmP3A^!2<@lyD^(jCI5BER1iuTF46UD178}BQYz_$bYP}Oo?(O+EadTtToU@#f2Oc zz4vw}#7>wio-?YsfplPvtIxb2p{*VM(^GP|Ul5Lid@$G_i~1d{3;wC@DSg)`{!4yb z7eInGHi2l1;G+H?Q*R!Y=9%yRKLV*l5frp`rbY>B#T~_r#tq!6;zC?fJ8jfC?ew(M zo=G+8;0`W1u2JJsJDsS+Wz=ZYL^E!Q5HX`sBZ^vPrV(&E?uvrN1$cfBcFy_!?!R(f zxh^i$hnxF;f8Ouc8xMHHzC~W)yPF~a9sJoVr|cdMW%aVYitiW;Rd8&?q%>ZiV5?A^kW|ZU`$uyJx&^y)voj)vgifCQG*}{T=}*AKh+Q< zu%u$^`=!>vin=crJLaG#Hq253iAl7M`Na_Ti~9FS_3nWcaVOa|&h_@Sn*Kke_(N^z z5R%65i$Cb=W*+QwM}hlHmPx=Enmv;T5Pfgh&g1}GTrLdntfkL4nf7z$^(x_Rz?T+U z7UThaq<0Cx!>hF{{L&;Sf0({W6D76IRLS$q@gM_4*s>Dd|ESu6?3{f_;g2CW%mN!d z3>VB$vv?%3t4vt{)&rbOl+s7pq~|cELQQ+z0%oy^RC=D|#j=d#q7DU8=eda91PT4@ zCQ2&RX02KrUgnl#W|uv_^`W1H{>F?nnt&;w$nyEi32p@7vf9K;dMFkddb{6vDN$0W zQK|z9kI4-O%>=9Ss+V5QH!Nw48rSp0OgCnq_t|t{dnS;5ApY3X)6Fh#BXg1y`pPqw zN*FuR^<+7%Qb<^`EOS+#aL0o}5;1~w$<;=mZnQ}UuI2}4Z z9R{66cX6;%DV>-h-Qzh^>STu_Qikn7`N47B_V zj+rh1Co1vqQNT>%z64-Qz!0`J{5eOvy!Vkx5p8-K`5dwrWlTMTkK(C7CWP8} z!^}S$!KtJL>m)4kjjqDC@5KZgfQzRAWo`H_Rz;6~jmDi!(|gIh^t`fBFW+g(8wYKl z@zrs8rV{n`1^PU4%X?GVNqJ>$`2r&fRB&ppa{i}g4KM&prIang1&|5yshDrh% z=A(NAC_>SVTfC~PsH$b=y>RHPuPhCX1#oA56wJVrX>ENsUEnf2V}~+kb)1ysq_&x=@%r!1(fEsJ%8QWcOad~+-z0C~T=`Vn%yBhDegWw({nrkh@ zr@t@=`*%3J0Q&<}U7Jn?HB!=lcW654n%W`R+&Io?-^;jmD~qaOIqe7h5dtj5eb>m8 zNE6uJ`lv#;6xl#r5S+3<|5GRZ4Ounay_@tr%Pb-9A9gQbk+gzNzH_M3__B7w<(I4* zy@^`N>esJaaJgunHE?ivT{0SIieZo`>JTLb=rws>s&aLT>$M}n1>_B%;>%}iDbQ&zsajrvQS8u#l;s1hYkVmc zwZ!!c5hb`M1sC`HM^JSpBHxC_x7xO*1r5FgC<{x z%Fu$-zJ9%JLi^$i!!OcS!T$oMuKsTtLX*%x`0a0@G(-ucinSI6{y8qDO~hA?POggH z@K_j^Ot>7*nL0m!dWUuoL0I}@#mr#j1J?r-I4z_1X13H_UMB@P1r>COeGDj^(@0l_U^OC0iK)VU$~*;;Ty7)C9Zm@;oDHte4ku9Cl|o z)0LuSMWQ-|V!FzmD<&`pFR%(iGyB=Ztiz|sk%5P4iq-kNb=R!8u;lCkoo2$)k8KR) z=vu;}ms|VWPs3gHVqy{=N2I}B=G}+KRET=a*`q)gc|SIAK<^g$Gmt3-4dUD8sQbeUE%Bqy`iJ9x{V3w^A3cCy1cY3EYuu7qhEk(o=N@jWfDckT z53Gc7QCjDLOtLjRsDQwkfZ;+s7N&JQOdo#qqgZ7)O$up{P8qjtZLbYwe$gX@P!cW0 zHpKa2LE%5Nu5IytEx7`bH{l3q^wK`E)qVlZ+iWfV1aCcH)TSA|e31W>=4+Dny=L@s z5f{~ZwT&y4B)cWaBogU~KIb|Tlh5@;oM*{griT*&6UWjZ*X{vO`)sF)cVs6ROUHCd0|ms$PN}ImsM+dgvG}p`+p`^{Kx9bKr^wq3ugPsreM34bX73lcZ!w}*Bx3YZ{)f+_sxr_ z^*fOTVtI`f7;~I_%}OXv0sT9B7Hk4z>>$VTg5JhB0dejkSv6G5!reQWC9FotH||I* zv$F()pRl?zb~bX|&As#}m;01@q9v5Wka-aB)xz9vq&+>O?A}Ea;&yRDStB%55|l$j zr5(SgpBV*+xd3`<(~5wqLI8v=%7i)49gRi2uV&}fv3eed*1)Ja zLAT8&)tW#q^e0ibS*5;YbZ%AA#H>Pp066sYB;?+^;u7sSIjWqr**1L;>OQ$@HY4QA zr3BO-7zaqqhd6lz$7c8$pD*#QlAYy}c00870w-1-Jx#btPiW(((_~o1CUB$NFPoAt zd`ZFX4Q*IipSFriNN%E4aamRVj2J&gl4$AV#05m?x|p{l z-ybd3eXfRuA4sOwly4DvU|`&C`PLbxi=R%98sXkQ>B=OK&(6Mvc;5yYsK~%0osYXl zE>4L5xS(rYP-o!=+R&u!jCLV1eQmw+L#cN*R8C2NL?&OToRS`Ss||~|`gRFm0bC%r zuvFbcN^REJ#G{5qG;=C%I2VrsK$td=N8{(t+7`A4vgN>-N1iqo`NrjVwb(CjXfVOE z1k%3wxuixH*sxAy*NF#ZjruGiXge^xsakGjfWp;Tp(Nt@H$i9|Zm?UFP9}`CM*t|KhR3|%~ z9LpE9rf5Z(Jaf*N)NWr0CU!aekUH?a)qDm8nZNND0fu|~0DSLQ|B`+7b*j$U!@xTJl05MUFH$TduO{kvqE%XszG5o5SIy1F zC|UD!b_;y6Qk{m5aiT;|Ul->&f%;i?X0Mp0db6UX1=Z4$g&vnm(DL|?^9MT#9_RfD znD7Hurt6J0XFjq_hl$@et+Y&*Yod$A)%9iy(W$x00s>U&a?#4fQti zv+Si;B4UF~SNz}#&h*Gz%(cDIVNho0k@s*^KO0!HH4H%Mvr)+h=aAjWiCX#v#&nuG zy$&Dggqw|VWuDiT5yrVsoeuh|q~^u%Kg!1FYQLOw4ZF_Wf~A*JW9sZ5F1obV9mPH8 zpWu;>LE3LZ^S5Y|)g_Tvvl}{Ms)sj}*7Q)FE%LoRC z3mZW5KqY{YzSws1sQmA>?gN~y)^OiW_l8lDPg1}nsB<$s(28JcE|2OTbk1uyG(Fo!bC2YP=j{C9X0HU~t(+k5D0y_nl2>}K(>#$3 zrzcIjA$UD-k3IFKdTO={rqXp5gOBrYIMde5>Vf z_PWQCp7K^iOkBMB*io1{zni*W_>xsf4(zLr45?KSkQLjx@RcBHb>2S6;!KBisO2^1O2;=4?*S;q zdZXNvow-+b+W@6;rc!VScO1o%Ud0O!tfZ?Ybl|)Q&F7!6O~Av^au8JJDObc)(j7ny zJ1|7#Zqj*L#y(1?L%bd(w|-8T-aCysihT?Znxk2d=}MBk;~f{Uj$)xi%Gs`7P82Fh zNc}N==Xp0h`uRFfAMSlZcteuAM^8_~`-5TkWqmxsI1%j?PxDQQxv1EN4C|+&(~DD< zVT|UE7+~BnS9=~8YcISg;1K>lRfEO}7`_at8uv7+#us0l#YQ?nq@*e+W%0?)MLI@j z1&)K4xlhsmJHYWh|9_$9#<~=Y9h{*g#x1WV_J+?KuGs(}?!CG4>I3+||@7xe_ZXQ4e3R(O{Uk7$? zH;jaL54x{xL+uRYvj|mSNf|J%=bjKa_L|~7Gh1~y>}e`1OQv6nEEd$dFtNEx3$s*| z)K8r1oh2Hep$Px9tMWPJ>Ppdr0+bH_a04t%J_oi=(Bkz}*R+r}OjF4Q487^;xc~$n zkrm8d8-9FS!%o0yoC zBWG`Hc_|R0uX~T0CX>pXDUn$erc@8~Qf$zV!MH{4L&v3L4l(N(tP{JagP5N# zS>j{k&+qU0WGtJ`IaX)8oSMUmbuGL$-G?%l&X}ZhD3SL--p2s>?pHlj+rWmQr1Gxb z!V8^O;_?If4U5H$NsLYMJ@?11Ub}X%dVQGaP@X0pJL)9AM6(uNc%ig(|K>)Rz0wJ% zj9!(AEa7egQO)57mI;m5RuH$NZ6DjLJ$97glx_JdI6vx`5^vzm=?>EQT3>$IX6VtN z%6hsJ!=)c%O1(!M_qdm~U36fjdo<|-nD^!@9fe3YbE>uG$Q)IsPd?@c#RFY;%o2GD zL3vyI84|cRH8VR=&ct3PKa1A430Bh#Rltls-mKxQ6AmhwS?W2`!S$fN@(Mdkx9Q2} zD0o!r3TEc{)3)Wspqodeyt4`vphw8;pVQ^D5N;1{fD{T@EZE6Hbk(_enN#v9ya5zu zlq}cx3!Ma}OHp_eF2+fv#f)Jf{dW#imki9k5n~jL63zpYnRxAHaq%bjHN_l|t2w>+ z<7UVYc2Cpe3^fCP`|lwNyoh%DhwXJui?oeq8U(qTY1WMpEVS`A8>WGRxMu7J=1|!= zvuhkuUr{7-p3O)Ry$vp3SJXuu_-iSiE$qsbew^3Yt#_Ra>*Z96ha}Z4 z@OQIZE*p4+$ZfMg;Nr7zWtBR3CjzyQbv24~$>rW$;T4m)!pdOx4n$2cq>$f8ZeT+T@6P7hA@$Tt9=Og|E+mO5 z(R{9v-8WYsY>go&7!H(5LMre%6Z+<+qAI+7h$qrNw`NSe&|`W1M7n;a6<3(ms`rr(rG0xC)E`QS|D~<#(J2}ifE6`kA6@P(?i2zjYmkb*FzsC!vdCRpH|I1H zJSa!E(~Q2T>t>r;;|sq09TXsgMw{PhXqF7iZU4f;ntm#Z!~;ke3n-Qj$fa;NiA*6o zQTTKeoGzQ?x_Nm{^YZe5U2x&3NvdOUMuKcOYABxqpfJ2LzPjK90s;6bMWdmpBlr~p z{3wVx8b;Z5^TX)cq>+Y@?l{tQCZrTeer^9V<8RTejcdgluGi;wtu%%0v0jSW;FO13 zJ0`UCfYx#-a15orn&ctRqnjSjLNVrnA3ypdbcTd_aW2wcmgXRMOsI?9t+@=*2>+}R zoGgEg{RComXauJOjZ5?X{lH&+s$q8UG%Z-+XSbRjpNP!<=vq^o#(>l&Puho;?*{+j zKg^XX*B-|t^!yxT1u^$ryQBqx)usDRCSwzDOqELyizK4VqoDt8-L4hOx0r@Z^i3v=Qs zwOS1pf7QRP@oCwF{PpucLHa{V?T`P~A0i>b#NQ$PAw2E@Mb!&tKE0|Dr6EgdwriZ( zZRn@{gGO7^h|(W@5$w-c17(}7schS{TIIcQB{J{|QK6XX!JO@TVs1H`2LfeGz55-W!5ae7~fVPPcmXWK* zxqvZ(K*iR^J;zpNZV+h#fBFw&;$MqTA&^AGg(p`d3}qyqz9Zt41p zE1B#!i!d~R>(|G}x)E9jJ-tx#l0g-4X%YF?8b;Lv-`37tn$R&$ANCaGhqxZb>Q zfUe6zM;ZWoIIn51@oCBRNWemGx-iJrJfyt((H-dap#N}-hs>u@z>#yoDoZBHJ9Y4U zMT&hoDpr67QjwSkC!eCKwC3iaNNDl=*Hw(pRvmI3+YZ|0taxq!D zA>17$O0|`U(C>z)d6c@l#+W)ym@ImxYSERY+%0P}q-Pc-Zs!FP@KaH-6|Nf$29qI$ zy~H+9q>dG{i2P3ADIi4~xwP&{G1{gi{@L_i@(lP6AEc=v<9>otUvGsvA8`yOykSmf z49jpsvOMw&{ecd$6V3pK8!nv4pA2fwXEhf(-(ihd`APXbGSu1zh3n0vi!c+xWPCQs z$7A2%;JS8Azhxh zBozD>ea$P(6(Lpjm>+T%6&d<2p!2;IZfQul#Y|<)9y5Onsm~NrW{XaGMRPp!1nq0O zhv_$%$C=uq*!V*r3jp#KFud>#E|xOqviS6nWD}BdlswLLc?0^ymv|r2jj5l9z8>$F zcYEoNk<_R)AOMTuN_4f~2}oQ_24W3O&SgGtA#i>$D;&tRNj~^pE1H|9H);3qLLdX zF_U$kW*b`WnAaQ-Fv(QOlR)x~-YW_^M6{=h11`tZB-#_FFud8S7>R|aa^uTN_+$@d zWG7k)rkih-<9bk(oQBfUf>4zDxsxu8*4AP@^nZSD*e{TbkMFu}9YTC6-GMlTSx6lm&HZ`sghs6u_tCM8tkTdzw z!R|3&5Nmn-<_?I)cy_QtNrhjPeDz?A^>{p}i}@lpLv$Q)B~cYXM`=+)U}r(SF}PXiu@Zb z`@7mbI`!(oG*yCQ|GoI+XSP|XR$FGN_QnbpPSlezv3S1wKt7`w?$*+ghqMQ5G1=Mm z$ktkcTzJ#yQxy>2y|DlDIeb!!6vbI-2xaNNpZ?gumfM&^mEV73s_<%V_S&u$4kveK zn2e~1%r>sS_O-NFo2Jpet}*l#-uKPcoASX;LUENbBC*X2Mnt>h726Qp`;Oakvut1$ zbctKR8DXW7({A2GAg)={*tRFttiFbJ-Kq|Va!)oyVg_w>cY0p!kzZwh%%)vs2*gGY9ytDJQ!ltJ> zy7>gW}(=hN)BaV{~ml3%PmlnJ~wXXId;SUZD zLw}UC*fK`U^9`OYMXrZb;gMsBqx1&Gb#68iydJ52o7$88K_WhhX$A&G1U0+AMhooP(z%;mz_D(NzOsHU)dLD9jxBF`-fZD>%Vz0 zfXC;{wR=YBA8udP$4k8cKNg(;R5eNwK6ru0A%BVT(qvHmbruhHeuZW|Y6=VlIsi}U ztSR9H>}flKZdzr{*}x;TyC5wi-}^kTJAZ)||3MNij%9^`4$ zF!;4Q9PU>j60hihOB=EK?o!P|4-wu={=|5uxta}q;rfTUHLEn}YIZR`PVs%cZAV-G zp9hqEzVeQxEtHg~ZhHKWrPTO=g^&K1!vPg2)dXm)Um&QNM_)8fK(BgWpA{SOx6M*- z7Fk&Y=*krF+2^lea2Xh%Et73!7lsDFt>}pg7RXsWPLH|yo}J44wT=B{Z;?nO;gaR8 z4X32(aK^flFn0x)wWA(2piSfgew*BYv$O8bRKoT z>Bj7HsQIN-sQ~n!pN^4us3bcwKY>?zgaXoK+$Y=+i5_=vPG>gB!fx99XTJUYK0tPj zq>IM6X*u#sgQoS#+FJXmXucE$zfL9d%iNevWxcOVY~>i#F!n6Yu9<0c3peDV+ z`f1*&V3iuE<7n(L>XC=S%up$Ax=*~h`6TUQPfQn^SO?sy@AC2l(PnW>Q>rl|%d6{b z>cl8xv~)7rFE?u%Bf2Y^udf>JQ^ZfA-5O0Hp&=04;%{4)@OII*s!aS8#xOWh1(5^q$zTh$F~|HpUJEHWp>_`XZDFTUyNvrQbG`Yy@CFNCKzmm0i+`2^$HMN~ zog+KrwSnD=UF%870Q22g`msDL#(I4DKn39j4Gc6>gJdZr@ds>CY}GDG@ap_AzV3v zFk5scWK9$vGlkVb&%Vs~A|%}*_=Bj>I@5?dm%kpcxF(DW<i&iMao)F%0+vk2wT6 z094ZOfKRabI`2*MLK{6k+tC$*5*k< zMYjp&;n#otruD-(zv%msjXzko_Xa}t=s%f5rI{ZVUivh{5I|{BJ?k}{O=)_O1{b;8 zOU7EC6mPctu=0<)ztZGxE8h7)YvIBRaMeL&_-&2#H|e^!TKzu%;?Mv3G{P?Zo_{BHfW3{m8HV=*2iqeth);7so(Xa z*(CQ|dO(9GJ5sMp27v8V|MzUP^o_DW05>x*dLO~181gO6dU~;IPY(bxZp7|A&K>QI zr89i0wsXX^kM>Op<62yUyVj*TzJilfa+09RN!TU8cY`VY=L6fRDvSem=XxmlNtY&8y*crXi`W{tDmE<9@5@L8*tpmEi{A zaiu?tMZ2aWcx+owNUql7Bb44wekC%`Ex&wl4jZ5AuxzKciKsu%EXiFdG`_!cHWkj^ zB(m`yth(O}1@*yOcbHFSKObGuA$q2#X6EVw??{|J2mJMZDnAnZ7c!x0fAwuC-_wF~ z5XqNa3l-lmO3eo1HR^uvSR}-?{h$hsxgzc12?u5%2c8juaN>Lm-cyed2r(S(vHR*h? z@kIONrG&YAS%O~P7ftV1c?u_1!OVCZ9I}0oGcFPjA5na@m{skb`y>A7@t@Sjtm}YTyf~Vf zT99^0N+fK*Q0l;jcDg&lJN5U*ht1*_0pG>FSAA8-fLdpExJ#NWNm!m>7IhC@29_Kg z;>r}5j8VbL8b3pSobftx%U0UBO)yt@{LB(K>EpQ=<+X4<^+%38#byb}oB)|I3sSSg zBiJ(}~Tw+le7@v;DCR+sQ(m+sUrf(Gyg(>D+EE`luL-=pNe49*%G}#yIr928UI^p+9H% zt=68GxLl?z9f#&65(@CrP6z)Ug>tY0a|F79uoE$g^47gjJ!llEyQh9ZK=lh;@x*NW zv!LRQs>hP36UB#EbSdC>V#qdJE0gojoI7npzWXVNt+mwRLUS)vfP&M4#19y@L^0c!m>rhElW=W8^F(#~|zuKFkhRWX&^8 z_d}VPJzMWz^;TN2c}s;n^^A(C0!N?rZf`cy$xu9|0&&|D%;b4tcB5^QjvR>RkG|lY&W|)_=Jat!nCFEc+kJsD z4&FRTxeC5Cb*;}>sk;8{`DAReL*r;(ea4HRV(`WBZo8y%ecTU-oWD(Fts56mn=c0q zT5VR~J3&u8h|>x+CoB18|6{2T_Ag5nU}4_89Hj5;s1yhK=J%#qWPC3Y&Mi$yu@t`?ftW^@7jJnCi?Rh@xkVK~hcyj>ZEpYd#X$S}rS8DWTe0H& zXQJo27xey*pQd84fBpkx-@L=zzW|lb-G(6k{Thfr+Q>Lf1Hksu^l+{dqpjn0mG37j z1OkrmAnvxjS`Ch>4{{5&5%0kto-eamcI>s<^bJnQz1a20+SWfqzuZlo-=Ej~bHB2u zByOyWQDgQ>Wv%E9K2XI!MX$#h55^QM+?2-Dpu&{lBE#8&tnGO($M97CaaKyK^4TF@ z&3x=JljOB)sRY20Hy*S`6iAXa?0+lE3iQis=tQYOZ@U>I@J`aZ5-M7nmi>2W+9+lZ z7$mrb1)25bc~W(jMw?d~`+L02!X<=V`~ZBwVtKRZs{w9BM~ou!n);=~{6MV2oSusG ztFB|;Vp}W>and{{cV@56zcxNsiDDf$#s&_OpJrg{MPdnmln#Oub2iiabR}r$aD-7Z zYR}t6-BxC;oUk6WXC+H}7+QZG?o~R9F&#U&9z$i0LtGl!e=*EX{>LTq+Zg|BZ)bJ3 z=YOdtPnsZjZJt~=qy9YWWytNJ-_?dk#W~KM%c=?#G3zPb;&~OQJjcSap1rl)?Nf{rS&XgNJx|5CtMd?eF=DNB49d1Zp zTl#$Zb*P~vufOmQio*!owDmKdxNM8bNOKOGkNuZxmPe~fwSe!e_L70E3%UNR&HBg^ zu}&c)Qxje0ip+JtOs@+cL3pYku>tcC>k8xMM;NC}xyXGUa^E zfehC(E%)71N(R7E#(CD_mTUYAB?(j=DZ$4w$e?Md%0#_Ycx=3(Jk>nQkP|sl1u^$0 z)9w7qRi=bkQ2GANdYCk`=P}54M?&HxM13T?HQ!$qgc+c z2amm&lowv)lfupfWO~tO!(DX-NqT~fv%-%ZAlqJ1WYKJ%+dkJNFP3QM`xo%$KjGaqS zLU7l8KXc4OCJyXXco!uB_8KDHITgNZRqE^)h*{Z|7S3%2_TG$5f5F z5_j+I9AbGY?aC6$y3qZ<)vPz0`QUz^&rbN?8vE(ZilL`A=tJ)Me;@*oIkEmoPf-o( z4eE5IOy6rqO1_~kcI!W99xFtlXG=k<2!-HK@n5Es3dkynU^aDp|Nr>C(7{#XnbnZC zpvvF9w+YpdHhC1O;nQS5e42k1pENh3&o$x22B@L!p5~nVmkte|rXTwI0np3sU2{_C z9Q2qE!@xkWDpVf6HNDPUlIyCJ;&L;W;%rmUbIBfL<;5}`Wgz$M5GYnLkB^3VP&u1g z4K^H49c|9;Qs5h)me#ONFHSX5pK-z*@pqK!@j(=)SH+bnPhHh=dfg!(sx#wVEU41# zRP@W{>n6T%6aA}WzVF`|slr67+UkgFEf>al2vG1TWSrMryER^%?pxMMf085lB0o zb};Jko>_AiYVwAjv+>%5RTCN+JW~jSmiqf|Lcw5euK|t>ayi@vsRb}NyvV;jcJsruy{!*#GGpZ8C2vFbhDN$hL`~9<^u+C&oxjI2T0{JU z*LQ3S8f#a-5qmeO)Ann8;$vf@W4_WCgW0V{5me5ey=6p~& zDbYVQ1{Z9G4=%eeE`DU#Si(LS*uyT|>Ph?7)Yr83B>uhVXSY631boWqj@|LU4?nhI zKSCEKwcTp;wOwef4U8EpJNc#!b}Mi(DrXjP65^UZlsN%~R zD=q{8A=%ArTeip9Dv-T~cb7!);_U8cViCz}Ra&T%mbLEo5VuOwJt-dV3KaV%1l?XK zn=!eBYaV-%mMA?KSG^L&?x>%o2XB;TS6mWUZT97w+Rr*h@@qjRsCpev_KQ#MOK=;` zH^?3vIotEpGw<4U;GYBa+{Tfu-AAe4EV(6(*9ngi&ta&uARy>g$wFmG4iU@JcMrLi znqQsuO?P#5T-(0=S!!fM`a_!*-*!}Sk7Cq&b2Dvwyc_AYrG$#ITRx2A-Ma7HSbf#H zDcqK3{+Xe$8}SWfbI{B$5l0b!>4JbU(1%o@liEx`4@1D1&4$V?U(fY-A;n(x+#iG z&95;q3cmH;PfKrOm!eZPB2t8ms{6@BpH|~P3$ai4dgn*3o_#?sB8n>BK|bs1xVgIU zW%ae~6vxHv_Bf!WAs>tE|TH)eN5x6Gy67zI^ThSw?7X|d{$A)0+qK-{0~vl9(! zwnt7G+qoN-%R75IHUFhrcauL$P%};x4=)ESG0*CTj|s(7B`!Kk2UdTwU!lNiKFMPn z(;nEQ?CmiZgygh+E%YPmI{K7%j|Ys;?~ivwZL@ z-%VWbCcfu34w7E=a_uty-{=SL3?S1s& zlXOYd0=1hO(n(rIk$f!3Z&n%UwHdF2r?o?pk25}9FdH8hOSOU`+PC4gt4z~(9ecf7 zUf-%Y&}q&Xg4b9t1)XRwU6Dsco=2uxT*hG?8jmcVB@!d=Z?Fcf@@XraA8l+r*bmE$ zXj?RkE@I@eWmZDgezan3M8}@uqkZEDW?nKV37sGowtuqaQtZ}){wJ}^JT*peGn#I0 z8`#85ugUiBgUH!fNd6-~j$zjQ1 zG0Xzl{^_2jQRN1c!5UQOnm&k1A1v1MtX!#fTq#N|wi>J^6mt}+&-8*?GG%GUYC)>e z>CMKQ!45I0knVIpmCe2bHG&k@(V`y%`U3yarPO!7_eBY%@56AVvRUcNZA>KQW`EzMbCqoz5xszK-?nbI zsLgI{>x%3v4nDTrZtXG*Hi~YyPb=X3DJzXppw!uZ9oHHw=zr)kAN`;>yy&JLwvB+@ zAkk7}hEP{|_$^-aeKjp}PPenke-zhQkF|_&i22fpk8TNaWgAvU48|HnK0aRS zDv}iWS_|ygDuaXOUv1B&Sv(nvND8*-`tFt>csZkx_}2_<@41n4l#~7=-89ojok{k ziOv725h2PScvNg{931tX!y@7CW|56`_&{yJ%`_v*y0IeTajdTq^Sb!k#dSsb(q>FR z{KrKhkFOf4jE8Q}))=WRH`;9Kzl>m{MXMCU*JJQ`b-3&p+7?A_|7GKybsE0%zN3DT zEvtyowNd@&^yH6*Vq1cU)y2U%*u3+!b*v&0;eH>FiTf@s;!@gb(I*RyH?3|G8y+Q^Uv}RqA;i$W9;&R& zwP}ZniGmitSX^2_if`NAO^#*M=n$&gnqq~^mlM~5Kfg^gj4U#;KCATE7_OG7&l*~* z@wtWEFvEFj@P;oOgd;EM&UEln#{A|FkJad-D_7iP=bQxPl$1m1fk}}i9sNU$z%n_b zS$ITOfl?Le+?H;!_NL@C{{5~-Il>tRAiQ>Qm|2ThfSYTmB`-JUE{2xm%V_T0_jPtSm}mSrNW*+E?77nwGfC+k6t#vU`BmZ2Grh(DKflY>X`rOCCAN#d zImu`m0^)^M6IDOC>Q93(fn)e#hSG&*5`NRpAJ&|HM$eM&DhJF%@z<1}$ZR`+kMt>)!b$)E3@Cj92*$!bFzG8rq?p3haFMF%$!VYmb0T3cz? z{zl9X+vRVc-*H)@E33}Jl2^@=;BIt8qlNz8DX+@%5ak=q@>Jv?-0N}n^0DcaW4KbX zJG*;CGIA84NqFGkDwX#`f;6P_^K;AF-Q4SDFyV`TGWm*}(=XL@W{E(F3>lXeQMfT* z-+_M>aiC|32{gUGqu% z@|D4)ChnZU7Fk-aBM?Co1rvS&>(v$YZl`*cEM@(Qi*$$YE~CtJnJKWfwSM*I#`NIN z_`3`tJ%q$=5U4YAE9mS4f?S~GjFFnI9Gjx((!E`F9@QX8YTisH@#s=rO1V!07zt+q zfJ+_M@baphMPYfsgKsVHoKO#Q8x zWisWd!!OOKxV{~pT~){%mV;wDyJYR_x|~b{q!M_(?FoZEJS^RrCIHQS=e!xv-e*J3 zwGdBE;y;C|2CywfdgNK{)Je7#j|ntV|kY!B8d24K4pdkHOi%<>Y{@p{89TJCFsDxv4IVf zKO%5})+jdpMv5m7dOzTac1bp5E$)Wq*B`pJL-T7*8Qd3|`1A3~lqUWhVEDxr@0WM9 z{fkW&VmFxGwyeGA@!Qf=k(z$d9({#Q61(4ZD4kf1Gg_zJYDMom?uzM9O<4E&8CXc` z|1#+!3)}@cg1mhgbs9%de8dG;@alBee#A`N18|-K_E#l?YmN_1+oy5`e-q(5DiB-};!$#-qU9;9bArbIwZAxIVEDCS_58dN&N<=scPb z4~fJ&Pza5y9JU;t-r$hzr}cM3bcEJfxVgE&z=D9FimZ@0-;^t)C%1mz30LavfA_bL zRtROa0389ovu$tkxAismHH>LNY_Y!h#WHHuKD2Yc)>#Nu&$br-3;)j(qqh9wQ@j7Q zY%N20C5S){J-B#)0)PI7MB$30rJ<?geL7GsI%OIo|3x7P%Hg|tWyCpFSl}1*v zcMEC=xmAJN1I>?_^Nqnvghyrv1Jx@zK4xjUk3L%o5X2R?z3sYe7}9T|=yHx8h$ZTo zLY)g@dw=Ca{ERbB!QrFOIq0pg|7R%qi`{EJkhgZ_hrj#+6a0lk^$Sc8;v4_9>d#5` zk!ct3E9h$aiB1rtAANk!Kr?53^oxGP{l9ghzc1SKsBXD)*}-cP;R1Fa;(;p<6V$L% zeHSssmsUpO+6r=O)RhLx%~TZ@Ui_d-8}XJ1E8CB{vtd8Aubhh!7a6m;!J1yYp2s` zP1L#zQ8TV_&)9D#QKP1sO-)S3T~N$u6h%eLEDFSB+<^!VD$DsF)A>I6p9hLhc)h@L z-{-oo>+|`%$(W0Hl>p0U>rU3rT~NFVKj%_+kKvi8L*+kwpkgnxe9e3U!8CVxI)j*; z#wkKPQE6Oj+;AHzYkt9}B*B2>imcVgt95l@4lXbcHiGc1VBWtwoy#`32(v*Z(&23T zdl)tw=}vx?rsKx6-;{4LSSz6OIAaO~cyhH`&Ql!+LPG`!HD=VX_vJ;OEA{hLx5e+3 z^!2xrsy8kHKJkrR#&1)VA3_6bh&2D5KHZYK`RP*8+jVonFAJAzc{20SFg0~7M9pQJ zRP!j6Ypsa_V6D({>{OJ+V_ASado9aS8LS4ysL9EB+Tp_dTKtFHI2VU$f~iQ}yaPro zDPp|&gu<{BS)_u4J?d+0q={kDc*Q9h$)3{T=0QPmf6d%J)Q`me+vT&tVefG_iq~h* z_X(|?i*^MG`aWHT4{Do-A#5|$;-x}s$FjS#7>Ynf&NSsf#d94bxBm2^U7>HP#nV>J z-v=CY*V?rv3T1G4R|C$BxzjRIVxnKKmm+?M*~7_9Q08OcC9S2dFOADw+ks!QsWTvO z7s8zNwcI*nUWrH8e1y9z{SHdsY-)u&K}O=`x4md=Q+HAA8{gye%a~)Bp^H5IL!Xm~SZpu>#kDZLV$oLUT=~Pov#~xJe%Ldfox5ZK{21p#kre zzjOOdh-UavxnyJx(P#w@^vmA&Ag}*pE%M`{4pzZ@9Fs!O2Ht8RD$42%oTz^}^B6L^ zf}Hr{?k5KOS*uS3zlihIjcd(yYD)do_CGYy$JT<(-#jYRs<0TrFH!c2#&Dk(Nyzk* zu!>)g#fRLl9Ce$9Eq^OC&d>B3h}kdv`bMuP+U~yM`^e9}W8%I-c@3y}0`l}=pwOk^ zc@K}Rr`GLX{WuAhmsWhkh?yy9RY-RpoqalW^*h~`lzxpb?I}bTdcldM5iyxc1T)+D9y`*u+orihO-xv2PmjKH57JurFGSpTYcK>VF zy{>q-+^^I79p*KPY=E{aI9!oU^d>Zgm)aXV9W=mY4bh>*C_wGgBY`x%)@X8vl7m- zqUNu`IXt#esZt7_Bsqhdv~uP+6IN z#wJ>ku5B{|T8f&EE`!}s2oUVALTngNhEc(|@l)yfff(-!h&KR^Q*IcCib<5f@GWR| zqZ&lWhtkyxPfzBs?Iw5d7}Vd+prJvaMh5dND#z(rnHZrY+alu@Ja)HO4vs$~%l1&Q z(^G2Lov2z+7|gb5U9rzZzuMGJa(C^t++7A3o~G1*X;5Kwq3p~0*>pAh|NQo#%ILy$ z^>bzP7LyAF!-PYX(II5J`cudMO&M}8Y*!FH5`NIV2idN2t?z^3t-3fJX)|lt!`?QB zRn>BG>DrW#UDVaes$HEd^pX?so^4-i1iSL%4#@FjAX=DBsrUS9A|OH(!>JzU`q}orHHCPny;R*{Crmw*O`{VFCeY z(FOS&&npl zE?Yhaw-xOv*#!;-8CKH+8mB3O3c=ZJ>M4S^9kT(cjr1?H(twQvFqq9XVsir^915!N z{B%N9x(IVGbWl(l0*E?nS?mUB>t)2G7G+VYrWRpdYCQAX-ZKScmH$Do*{&GJ!eHbD?0s1k9`(!C~O zIlO>$p5)lw26F_=_Mx;@mg)eTt3f+YDTI6GD{cmMT12toCqtf%0r`3fwA0FudOD4< zRS6Zcn-JtLaKrMb4mkrmF8aYC;=)->y}u9PU5Xs3ZtX2m6@{;;OmQ)?$^anefp%VO zocF0rmm^)YsPk9*WpYMgJa7Uu2iR(k$~q{awnS}|z^OuvGM8W&t#Z`EOEI<}R%+w* zDY8CpPC=ZakE6wcDis^XyYFK5ir-A~2tp zPPd+|3u9%fxW&b;mUZ)b)oEA5M#kM>Nc8S-4gm@+jzmlo!Y+gxoJ_Ai_SA~eJfcrQ zt1=*B8o=YzT=x zN6lN;5!_rJT%#8{LKJD|3u9z{OLNe~*0TPzvyq%NiQ+))(yxBboVvKBJ8Lg)X-XRX zj;ZH=ofb5ws^M3^w0w5*_7FgA+Y9*Ft4$7mX#5yVEqK}?0O2PNCw7m;&c zT~K^{iaw{hz{jI1Jl_w8%8WtE_ZLHSm=y#RF|gPCC@k4Biawzl`)By^4}n-qETor# zm9dVzEQRdJ7W3tJNjNIqzSPzy-WB?Pn;oU!_c9# zySjmC1$Q5W^@HVNYHulXq12%g)iJoRu+~I}8Lw-cAoNX9m}tf}TJf^D3;fd9S-AO+bOS5HjcAoP zg9Fkw5;dFWAln83;4(P=-lr5y$r%8~HXtDvEsS|U;H~jn*%*%Nv>FrpLay|2m-nGz zh>=Nou}RhD zBm{EQ4k2eVJvlS|y70?tZK#gOXd5;iLXraj1@Cz)P~6+>Ckz)z2>-sPoQwizZ*1Eo zDU(`&#^MMqJk#vB9ts9v--#H{ri=1&;>{F?vg$%LcHNn%EO_kMC(|#g!_SGq#q@9G zt_WYv=X0z(eKFB60 zp&bvVNnPD}KG@tEG!tEvTeyjhW5`F`au5`DjRF{HGk`DXr`I|hfVe3hn_J#R0P>Vd ziNevCXkYx;3M`W>*x)Az7SYq@@A72XLZ0H=y_Gfmdum02eZmIH{+>gfsDT62|5{XN zYgAk+Mjk13DR6_ok*K-uPi;l-leU%#2gt*58p#YJWp6P3@|6lheSa7IQRa9*DJS(( zd`i^++|JrU!jN#p0b$Nh2RLu5YA>$Fs|t$5G==)Xh()cO&a}5^l0FI!T$fy1S=x2c zBHc>-_348IB(vNWe%RhO{D&kk(9LY~O#ME5N@ET;@V7Z2HiJC{24;D1?>{Yk!!}}n zKWDN=oZK;IIFO?eBW!1;S8~T8Y5AUtTh=OZWpg}xgn~^j zpwvzcHPjrBsMl>HME_eq-@>tlW%9A zMA7FIqf0;k^h4O|S;QR1f9oekFP~ti(XDs7Z}P*04E{muWWl>y#7#eWs#?&SKNv() zu9<~fom{`X+&U54do5dVEr#n;%Hsc(YrnSs^@w~+HQiTIcmZH){bfGp0wZ|Apz;5| zvgGX^jwHY^P$TE(P`J0cBizBDC8Xh2d3BZl^R4%;E*d(QWy07P7~EKSzzE0^h}V+M zgEJ=YVxh+ll-np2LB^QIPId@rQcT#e>hPlwDenO;t#U}WbUSAyJWk7Ov~JD;sJ zS`Jug@);HS$BR}{09Ywy@Mt?z8S+iMR9zUemLrl~27`vOfW+RSR4++_bU{^m#+jPUKMY7$lzE^GnS`~y@No!LV>j}*jf_R14r5cF%)2?D zO62&!V0JBRW1E*(?-{D#p)Q9Pv|ZPi3qfDK1&o?~iJm4ymF6o5o|6Aw@>25*vDe^4 zg8MUVmvHb^aKJHZVRI%X$9Kp3jo+gTr(s5LK22J(F`hs?szjTbGDOY&jDUC1Jr>R-+RgK#gV!(0 zJ2S5{(Rfmq-Bw`Og|(_F9!lnX4}eYyWHV1iX@bpiRb87%{ZcPoxLg%|F z^Z2Y9g=dfodV8qz4fVC5w~yq2{TJ0E5PnfTYW3;OA)y~%w5<^~9aDeWSn8qwxs;|h zDzn|XJ%e|`5+ja@cwW~ELZiNe4kvr9x%KvgKY`J~Ftqqc*oKv07$kgV4W|4NpEZs? z%KJ+#IU3E~ZC3I1foajdFf6ONO$7%ZC`Di@l;bbmN!r*OW|5ADwa&!R8T>IQo!*8K z#N;#Pm(vk*l}FhLmFld`(4BFQKa_4_Ud@^2M5-BbtHJ%_UqC9Rs{obg_uw8%)Qha-6c ze~`9z&tME0CFy57qzv`6%n&xSAn7N?9`LktOYdJcST=mVZl}op{4n!;R}Z*lLzTq+ zXapV$c1J!bei(^Q)Gt5Mn!Q@o5#)QW_QjnP^UJSa0x%Vl_rNIt=7ip%j7CdLY= z`dC|3fJgy}n>`#g;zVlK()ow3g$o7LF~l){)E=>s*{*I78OHJ!fv-U$AiGCBjkhreG4aZ^sb<+7LxKUY{FrFhOr`4ZsWQu7=p?y!q4vvsV!lPv`+gZY`tF>s!2Eyq@E z`d|cG=k7@c$AaBL5ttpnwAkab4C;`$)YE4X^OS(oo49^O?N#9XVeL6eO#|M{Eytwz zF$daq5;kbcQ}fux%Q6FPt+v7!$LP}7pQDp3``^g)SG*RK*H;mDl_g~#ABl8@46U^Q z+u>&%>H?4tEnkFCb~W1Eod9~cjxOV+gta=qEblZPJMq98ko5u=eNRu8G(ua8BTnK> zNzocM7qpvS(ZA`HnK6w$iBP7G9r}QgDV=vlE~oyxnK!x7Qd0%OJAx+N42 zYi&XjWiF+FI_y+hp+y!UO`Xk}*8KDet4Qk)<}HNc)%o%Q54I+04OP-digum^4z52< z%1yG;imAyCl;;(uW(b~4wy3evOeelxdgLi&VQRC+I+ zv&dR3p4mbhC>Iafj87jkt+f?7yucawQtmW=(E3tgsLW(C+WQJV0T)+hRaR%2|}z>m^L?=$-_`Zr?a$H-R+&WMateKb(!J>z4DBiyivcx)&} zuoUIpjHTp7YaIYpu4~06@~$lV+qcESY=eRz+onBl5{i?^^7O~yab{6h;nn&G6b4rA zU*f;(rvI{75^3(>{Mnsb*~+j6_gHBkxoA;uHe~~IN4J5$t1H3jvT}@;5T!S~;jEmc z%bqMmXs@bhaH=&+``j2>w|}^+ z$v&JhY9!kW@)d`RK2Oqd6pvW`pxq+jpiTo{Y;1p%$`py<{%!RML7wPBk=wN?7Tydg z@~dg`GCV1&@hda-=l1D&_2I7sHY$Z32;E0%&NqFSm4?la$-P;yn2axBnWSr1jCAtt zRhY+UIrh2i5M@+_dHnj!dGjf8PUS@PS51c6pRJuDSTu0yFyzWHAXk}?3bmjJ9T*Dg zr~%&Ky3C>S7&2bG7DArAx12fy0oC9PGSIF-2z$L88yIB{s>}Jt!}g>At%;%5oNC@@A8=nqbBu@01M1>cjF_rnkOT@K}^MHossv@a!_;` zHd9U9(dW1EHkh0KMg#YT+%02U3zv@Mh(5f1IuCO&&(X!AqHi3}P!uXX%V967;<_V%t{zd*Pt}c$ zVw2(!1N#c!K_u+yKHTNJ5GHnsJ>nxuvu#?Ayl4;P@-k)6j*!A6O%Qb3j3|-XG1IOWZtAP}A@8T!QTr|Dz2j-HvEwp6<7oY5 zP;lx=wzvh}IuiyX>k!t8Pst=hNxtWxuzsAgVdLC`#+tYPHPETpb$u4`d@jUI6@ZgG zJhjXJA?u*LGh%)}z+=CP{(Wa_eC}@hgRg#YLjJqb^>zKL^{9V*D!Bjps)bA9|Kz&} zzRFGhLzNj=^Uv@8O#k@GN3{pR399Y~FLq#pjbWGl=cR@L&$^G%+B?gW-LCFA-R;4L zV?M@qzh|{{lnNS`Jxg8Tf%ff={~BmcNIUT<*{VI0>Nr_1XP?`Ju()f(*J1ZTMgt5N zT-gr;REj=l^aqeTBPn%dH8It_7)>g!Wc}|S=x>MPuUeszU-!e|x5-n`DD)=kfSKH! zagjXb_~=~q0MZfu+(Co_>MXl2bc7z|dq1B(Lp(1$&p%(T+K@lz<~VGv=zeS9H2m19 zt^=(o0vpUPdFxyOcB!YyNmr@YWm(zb7P(o8K@(ZH{K-10gE`7O)cXNnxV;xF(6N@q z^0va7!%UK4kI@W_-=|tiJ2R)dDCM^ik;JYF9i2@5OOf_l4|dm_%{7G#>iguc&xvR3 z9JGcWACY7!s8DXI1_Wiv^kb}i)y}3(FC-wskCBP!t7G-@q{owX?RJ~R$5m(wcDenU zp)(ufKX~KwpvdctOx%`kWy$W#EgO)9N)v|GWH&qP>Q9;&=m`viv~Tp%ggr0*ZgC~g zb3BH`Ih2P5f24Apcc0P@sD;$i&?hS$Pu3Fe2%Bxdu1;Z1SpszYz5U6hoKFTQ4%I7_ zxr&3)-MaI}ZI=%{OMIQeU1E(@53btLiu>P4lr^kk&9@F90>#^kSU0&+FgdfWmZyLk zyGjENh%CFN;rE^}3YDgwYtaSKQ{iD7R+ECk3Rlbdc@E#{S+YY)JzDq_Kf4pkf$DU$ zp~Kq9ycH68tVf9@Y6KB2e#=bN^JVW`#>V2dqk9qCt`K&3m<)P*!~#<_dg_SYs)aQ+Yk_j506?rX%hMlU+8jZ38Hv{V;QxWSw982MyV` z*|lK0W|{0rCIStozDX zHgI*`UAXJ&fBE$(FsI?!a7{?@h~p?lSR-G~+W_Nts9py@kVck=UQ>GhRn!uB_CgeQ zchp7NS+b(V5DxEcoG`L?x}G;#7$j%jJ$Ctgd3-WHppfs>){a_N53G?meG9%2ZgAB< zO=GX?YD37B2PIJVjnAtJuVebHUd{UJOu%7tarW4UWL*;!toad`G|-*ac?yj84BP^O zh*fhuRyaRVent}Qgk|OIV3KnvVY~f>(a9_3o9Yg=s#woxAFc*DQZqPeibI$usOM1m zK?j2Xd8)v?r(h#YFL>GZQpssRq=GM>M!hcT^up?=OcY9A9Y1nbV6A5hqX1T^!d=d|I8Hyn%{9#kTp3D|7%B<}&_YG#0pOTZ}W z+o|65z58moY;5Jh^3J1pWq~FYlkJDS#pkb|W``y!_YTTFksfLs!!(*RLZZtXtKjtD z1lDiqK&GBW+Eqs>cUhzyKva2N-FX$gKu*7W&Hd6TnB^0}Zw^(v0{~6E&h{nNY4UTG z*-qD1bd#TiT#g~;#a3w%p9}P3PIlImo5`BmF$EQAR>fv$oJaM=MluVYCqL`i8%*Ls z*XsK(bMOeg!n0V*cRJ#o5*Ghuox&LVfR>kB74}K$N%&%yk7;mC#}#z@oyF8df#g+{ z!YDj~QrSYcNgk+jxSB%C9*@d`BD*0Nyd6|=T)jx-8M;X1fhg;rjQxXlk>8p0ma-11 z2S0(-gRHl}m`_KW>6YL4uD;djLH&$x9Gi|J8KBH5(E(J^xIQYC=1eY~Uyo=zbV{tu z@M|U6&+^6KwTb;*;1D!Wv3DjBK`WzEfNVHVC@YEgD?ou3HtW!M0kuUf!$7 ztb=b+t&;~|Je+aR#_6tOj4t@9Zl?K<9nJC2XKiY{dOl8E++tKXyPNWg*$OSKWTbto`F6ko*F( zW(i@|pnTA`%_ZUmXYJ=i@|b@@oHeM;d%G`e4 z-Tu|t(m@t7`VRU|{-OLT&IIphVYBkkCa7JH*s>8=A?hBzaUe;^iKq!o>$rdJ@2iJH z@B9a(m`^w@_aSFZQ9}B*TTgp9CeW z4A+Icrz2d)K~P^j>RX0-!p7ztO9q#Y5q6gh63>g)MfmPiaq`&JAJQ zKWDe+dZvDH7WSyq?CgZLQS(EOfliVBv+jsbm0cd|!l+$l!&Zy6e5A+pzF=ves-*^fh`QkbYYPfr5<;B8wLqitj`RX^v2VK?quET*(F75C0%1x;C>7|AV zkg}vC9?s0GHolK@F4n`@+a3Dr7$Q8C<*p3}FKw1@Ig~#!XU@Sa@N);mStkzFm!To&!~SUm|j2q@~gx!kmpd4JCQil-Awe z^VCPIy86R(rK9CK1~!QbK_eR04sXG3u}5OGYapRW?ahHWL&ed0GbRWe%8%nJeTb0{nkposU9%}7WLSwT zI14aAi}4cUlQ?{+D#X}C1D|s_=B()s{&U6;!kl89RiYBD7!3Wu)1Ki$OGD^NtVFmY zxT`5n-(J@`2V-=0xTkLwoZU1ow3)#RB#0nvM&NiwUf)1P(g?tBdwyNdzR!1Gc^zkF zVy1^G>9@1B^#a&cdwl%64_oTSVcJPEoARPgyHk$VLtOg8?#~z?O;KqX#aNg9Q89Sz z?-BmB+zy(JDA{8+0D_dsK&6E-jpxQ&{g+Jgo^r7+9|kjlY+!M3HEB4Hx+DK)n8>m6oAqCBCZ z>&^r$D69+`bxpuoK-k!BSGNZ&t|yOjGL+YDyCbNL?r9P64;9dux5myX`(dh*lo)p2 zF=z5l4*&Fj*)W!B&?!4-TQDvlPwgk)cZuVGP=BO&2hMo^UVTqt}@HlVQ%s? zLw`X8y^A(}S*ZeA8IF7jrt@^O64}};h_KxN>H_M`=C}U=N`!OGwuT9H`0xk>Fs`F_ z7Ol-HLO2Fn=9DIc>|2lU5*BNH9shHMh#=%SfPd&rF8)u3_~nx8e+}JG)+8js35ERJdGGf8Q2*8{dI6(FH{M8i>*xOH*3erCj&4PH z_P`BY$l{b|A6=ni!QD)8K$INBpA46dCV^MM)a0Y&$^X=c2c$(V1g|GfwG0nkHCTwu zd^9F~w!c%h?|P-%I612S&Or`QHE@-pSUBD0T(t>xmmy~d&L7p<7P%H)dV}a**)9;< zHB}n$&(c;t?Y?1F{$*2srSARA1XJ7^H9{u3cM_R&MdE-5BBfjN*eC1}aH@fhzKM() zDk3B!tjfXTHghLAsJ$w@YQo5OR>VG(-V3yar`PZ6d5^J;3+%aeC)F{d?LMPd4?>9n#=>rc0n?u0A3+x)<(NE2W;4wk`Cj~(oUqL_N z|9AEGpSbl6GrG@_bJ3zjk|J=N|s=!YE(hn{-|DW12>tcq3uGDQB*@Ds@VrYTDuHf0|9HaJ1J-A+SInQ%^sb=B45Ir zH>MY;5ACyjIx`AEJxx^csD4g@bMSl8DW*@`t{KL5N0U6gYMo{ldlLNgbil4L!L6@E zPsfB@>)iM25lw*S$Csii_w&*XiPhwsd1^@~vi;RQeTAPr@1Gf&#xlf+2i!WC-7z{c zbacy=Ycn%W<(IgUTP_|}d0tf45<}YklyX}i$|AO6rm)EQt68FbHB!+^jY4|Dn9&Sb z!h#es){gEMxA!!(b#*k#y8ar+f(XbC!p^A9*a5;c_4Z^Y9d|b}t8gprwi#O47qNa+ zL}Ab7CK5$B#9N=b81gD@S&& zpZuk#HQ-Z-8Sz$GcMA#^tGx((g_L#l^^0_RXoMZO_rUTQq^E|w2vB@%IW)qq*z1BH>VJKmL&oip3vz>_*w6vZJEo|*JvA(V;2tDsmm!bs2Tat#mc@Z|x$F6!d zj~RiC#&Sw;U{0G^LR0&l=G$AvNe?XrHHnP81+&bC=8-D~^bc6~kP=U;cQx7VkL3gQyZ5xaTq8qqcf-I8$#^kq6ONTfwR4RobEJ zkMde}sh<%o8yeaVBG1;Hw(UPH%lXVs9%X6fB%nv;UW-p?66HiRhmIuPrBauDQd5I^ zcVi4~CF0jHj_WG}m*D->`A92eO}Rr~RmHV}TRc<+e>twr&{toN@_K3`y+oWm1PZ`H{%TLBf;>$ze#p4umzg=Rp4VE!eL|-h6C~+ zFA53lyEA^>c42i+FJHf2$>3^BIxyv20RFgyAX=N)f@?GM!{E#*#0JOn+_|`z%;Ty2 ztR!)!>O&Q$C7vJGA&rfxieEnjNcy%~FV zrb`716T>3D?8fXr#!l8`1mX*%%RI0^T#Yw48urmJ@hGI~*!XGqOmz|?66hjoPCTT_ zAye;XAlqlE&riJ$atjFD#TyyP1h&rz1~`7TCHLhKSOJ-UwE=L3xDVKYD=gm_ys6Wo zI9j{K{#G(Iu!&gT?9;NiokBkhrZ{hR8#R07fs@&{`R!TO4q}7dr{C7>OG5 zXIR)ZFNOi{mBTY<+tW_3_VOCT_8l!3)9#b1?~T!~pd0PtDvQzIm$yILs+9bJ3eY+C zEqaDxw!eBuOU&+}+I?BEU*69#JP3Qwt+stT=rXaJ=Jg=EPexzdjP>gIK%$k*{Lofz zKieXMAem6WE*IL`7vuy}Lcck|oS+N+S<>0cE9VB8TTKP&0&s3<-$h7V*qr+!Xb9pjiEKSnQJe>&ZX(chgr@PR;n|6+$42gX zEx5dGF{nfbueD4@b!U2=nz{HF!}fsWhQOAWP7Q@d3ENP>WPALoiuSqrHJd9fEFvW% zMr+;qT6c(W>Jp<9T78_x`jxtcNyv&l@Sa50i?x^>r*J!I{Oh^Q2h)S~2^*eG8*Zf$ z^+weCU7vlEntKK1#3CU*6^MR@L%Y!J`n(El4Eeu|VOIyLN_d!EH;`waVaW}%DwIXFqsyy#5E3IX^%o7Z>3~PCAqUop_Yqk9HFN_ zPmL&G2fEO5ub7Vn>#jpsj}kM(8zFFJ`klmVeX4zBm?0(5IVhE$|71U*CuQF;GTZsd z3X79j?I$RjqZO_SQx*g4$L*_h()L;B{xHU3?bK`Fym#nY9BhEQZXVG*gT}yz0AHU6 zVJ8KM`t(;eIvCu9SqB~E8<2g3#DLH&NXs@WELa(r&dFu(EcrCfDtq@?APBHnM&D^( zV}sir62UDM$W7S1lV_(7yCCR)!YyNK47Asd8t1lmhwKUSCSJh?c6|XYK}&*n{yYcg*FJ zVT3bE&>76}jiD6?%xAv*MJpuY!x{yt)Rc|qQ+M2ITtb6%78~<|skzwGf5fger*gx0 zaz4`bFMW_?cPGa*2er4iJHGjJ&7FPCG(}r%wm^oX*hbmsp(5_$8=}~sb502EU}H!a zjv_+|Vzox)wlkqJj0w>zS_!2|N7`guh5~j8c-JyqPUd}GIT(W)n`2`Rc0GG)+IowV zKz6m)0ZU$TIx5*wE`6#_9C?H++XiGM6r6Ifhqp44KjN9|G*HpM-Cm!iEt7Tr`ivj( z!qiE1zxi~)k1>I#RSEA>h4t`Lj=m=qB4vdEcxI>_04VAeHA4WvT*!M zJz!=YIBZn9*~XbV3HkJCoU!EkP3z?Qo?lu#aq204AVhaYwj|u%wvNwS^~LS4n0nFE zljp-yGcD$>dRn%oN(>TOY>Eeyuiz|}?HG^peyoHRdgdQ`L_M-2zwx_{LBWOVC+T-{ z?X%S1X=EeLPJU?}El;dS?81!3H+k8;d&y`KPe`W*^S6Vqf@zlBmrAE|<;fd)VF?fE zC4%um4=V<;WIh3rI(ddjp*mDq#mbH&Xg*T+a;KN%woP+qddBn98+L9FGkfz){EzT` zBVNn!Vt>zehCQbJhgmvz*P`aSU6MyM6nPlNlB~>Ue&l;4+#=p9!}nW2gTm*$Tr6;k z7hYOUZ{h-xND>?Gr8YD%uPCsb!`lWNr$v*`LQc#0ia*uiji$uy=|*?X5HES+UojLq zxok!FdOD&tVx<<~o%gCnh@+K{9%>JuOnK5MCb|Qr)z^|Y*pXxt(=V2x;_dRg8i5v8 zSGO}szFYv8rNbF(2p#=g)vfg4dtrw)VkeUT&jA$yy?lu0L@z#T@hK?KH zvG1J!L#9J9lxI@HGznmYn4o?__wuy`!Z>Q?CCtpaz~r9uTvOAdf!k-lU)XP0mAG1T z{aR6h>xj5c&ZRcp7A9AQEQ*ig6!rEvzCfkPB*g_tcFrF~91*LIagypYU3PMK5Ia(4 zg~^|O=v=We$no_{@7LjtK%F+yzAZvo_|x^BSiiz>7ZY=eM7ppW4ZcW`?^YNHHgMhY z7JBU=R_X$e#q#E~m>TEK9H~3(F5<;T@_6RuOkJwQX1IwM5#Y?{{O7I|GbD9JpI-N7 zI^21e-@e0p*Wz)`V+YXOZ2q?@-&K>w(bcbHhV3Q$FFft{-4<}GW|BReq)eRoAjO1g zz=fx3xv-&ijpRvYpFaXlaWi_10p>kl;|$E2aW?SKDyGDA7yMUk%K**nLWR5OYHgnept_6l2+{!wV&MI6GnO1n0|RHx$5SwzJK{uw@bfqqg|Vj zwCvuE};H7Z$TL9#9z;3rt@Aanl6f{T$=$%FhM294yb4t% zn&L;jdP$L1Lh&^}$KU$!|AeW~Z|Ts(%03LPyolQDQooMj^(*9U&f1PLoNVIQ(9^9H zY0lOUj@h?R6WmnLbpfZxZr{F8H$dtCid?<5thoPrYjU2QLrDd>`534-&V*17es6`B z0zK8O@Xv)8y>Xg1gmS3=BuP#1lKYn2R$mt4rt+su59esrCsC*uWO;~gr%|+$o-cD( zrx5v`%pidbJ&H0u73uu8HR_gl+MF5r?)n- z+fd#6o)6>}sZ^zP4@n=kN_9Unx#>Sl#qY!c{TE6lE%`OZJZDH>z8x59g7bKZ z2CCO8juARejgR9%64wB(=KkW!et{1EJOqOPR@6#6bI@)(Fu#WxjWY0Aa;B0 z(W!3`De#kX9xFAAKDDQMO9o(B%(`I6<~pK4ZB5*2O2)(qj<6AQujMP&$G96xjxtN{ zm3AsnsLZfP%sAp+L(z!)sCoIqv<-yk^9byVyN*V_V^wZ;V?ne85dX-nPyd>9HWfwO zF>4nk-k%Y6*<-WT!falfZuiqiX+A@wD|?4;phJ#InQ>#mj?!!{&r>YDPMx!Kq=K~s zk|Z;L0NV4UNJY0^`^W;k*vNsAHNSyY&vf(r9f7WAZV0DDgry8%e<6iJOQ$uDV9OFUOaTrXw zwSWDx66(!O8K4n(E}Bg?`Q9Y%@6zUyA0EuKEmI!bA2B9J^<|4;^(KyXn{`K6N;$%R zm1?@-=i#rkLGg4op%0mGiSdVO2K4NucjJ3({h7HN~+b zQY~cYCLaZuQp3U8K8RCycrN@p++USE+m>H7+?9HixjWw1&lIfT{Dt{X@?dSPv5s<_ z)bN@i9KOPoMbjQj^$+ytU?KAM8Lu(<($0t$!r1oyXJNq>YXm%oY{W*+hGrPR0iCyx zKb7U5Mn}Nd6M-b;DAvRqCPVtKpqJ;cIj(iT)o!Vat8vUF!!|bB#IMX8L4tiPbwF5g z+$~BLt!;JpVLSyhptQ*_t&u@GM2uZVY$9P1%oAjzj*e3p8%ILSAqd^}z|F`5W4QSu zN(UN%Ax=qkIAb=ZR>8i6F4{n!!Nz%fV5cRpfPMb*UtpUqtMf8y5dt4e<&IiQcc4tz zwkD{A$yN}7FdAY2CO&6IAO^y`yU%3{D)&g*J+{6%R8zij_O^|UB<~`3B!wuMH==}q zb!Q|0_DVOnD$0}$8ueDNy{Y)9n{tK*FJVOH19^d=+b5dSB#+#Sr;McA(ry$T?yM-aWee^QL;9nX9)__|N}ts;3vuk^0>5fV}Ha z2`vTPE52gUE=1>|`eP{3;UCw&YyF*3OK2&i8l=*1L+@9#*#g}RpjkD+M4Q&%hF>_0 zA`Y-}^$|*)WV=pWqCyR>uZA@khCKl35<+tcB6u9Z5ue$FLc#4psSU$Uv4+@4;8EK7 z72mj+Vam8o`IVsbd+Nas>f@xFS%~Bp(l#A8-Rf;^Z<5$(zjfEy7#B3*bBD}JVybv6 z${NSmL+#|uzF`{>Gy}-}?@AP<;bF7D>RCwZv{E^emB#1}4!|nw&!!oWSnjmc=)3&q zZ!swnzk~X%FFwwq{uh(-vzdC^A`3E8zg63RRU7%14rDC2$*&2|`tP{)UlkGm`w2Z_ z#~MV#yLB0$KofgeUzo$<44mtGc}Z%01M*et-<|SHpPR3l9R>K9es&x)pKhElKYu`V z>)f|Pc2JQ{y@p6PF|Z;X3-Aq(IC&X?PP9W04!1^3{nWY<`MPLWR^@qjCcDhCYSEgy zNS9c$Lu9h}|GZq(6llqTZnWVNHk-6^XaKx23x8$i?wliW!xd5)zKZFxw$X4ak54#x`KUWg9UZ zFkr+GRnmYYR@sOlMGTGKjnnV>J4@vTuj})Ezg`SOtrP64bJuoH2e@OM z1|nS}a5>2jm;G!mCJb$!Tq{QPjs%#dTY$V=wFrC%*;73emz!a`&eKgnGad52^cp@G zGlhffoG1{@d_+)9wmnWi1?v)!ISXgc zErvVWFMK+gP}3o-g8g-PM!?bYfYLp~jea?Ipe**bQDvxg5|EbyE6-h6dP$R-1n6SQ zvL3g@b5!RVP8o~ssT(2rCm5a^+Xw0p>#`Qj7Mi3=?sU$^C@n;VIlj3jKH7+gChrWW z_4t5G>J>>3?h4V@y=IxsnX8@7t~eS~^_wuzoZuo0Cv?{Kh5NZuNf;WgpB z1PXmTAHy|SmnSb)Z#@_4`oyOvG-5-s>4@iE zAj)ORm$m!|t=4+q(&XPVa%KJNjTI;R`1GRjSO^NQeG2W1*eI*XUpWitA_&lf0cq}s zqbIIz=``qe;m0S9mkWBdRhhx7{fYZn8aw-$*ml%^IsaJ@2T8H$i}9B{M5&l8zpbjf`9i%88xdi~O7%n!hth%M9mz%|e*0h& zVoVFEbP4~^CHCB?ihB01e0*9gC|G-}b8`hX*h$!+KcO=F)|*<^f_y5qu?XPw1kC!8 zb%iesZRfgICx}KNvj<_JrY~X9DOkhnDU{otE99PK>eH=xo5Mu|Pp;BvK)SIq^H?#5 znI+Q@+7*f`I_{!O8tNZ!X=*CRl!cof$ z#c0Sjg1dN|(6n%v0@2BfUiRbVQZ}tm7f;Va&#)YC=cc`?3yX6oWfk$0LUM!0DcVMi z*Vw^X-O+lFF1f{V9c~Q`1k#@W;lW9WaYzhdF=)7B%uRDYXTd)fw~7Z@j4wS(4P9EK zn7gs$R5-pGZbdeCZkZKIgnPTO-s0+Aj7}@e1UDd<_l0-%$9^x|#^ZZ?@#XG(vqYO* z?(;>e$d(dN>62V`xHvpaHu)@OKVT=Ja%UsN$ zy0pqq8}A5ZV@-`G!w@i^hDGV%`kh{bFA(-?x`Akgb_Z0fl#L%w!Aafh)kqV%Ip>$@7L{a}Jvy=x~=wsfII&HV!|GRzNYNvzj_d zY{g-!_rh$Llg9&}t*26Uz1z~;XQikr23}9&`bltY$l~z-*_Rhpw+8X-5!;s9oj9vl z%_8%G=Caml8$+BEv|_ZVGK8sgXwk{Foe#I0(!)ZbMQmEPLvOF0woUk6(|XaaJs#pk zU!dlC<(|QE4GGjp7(YEX{9ZWzp~l;S#g)U{+#leyJeQRPiNIgQr(jboC%tfUz5oY# zVij~7r!Sd&srC>C%}OS?IZp)=o}6NOGnR{%2=}u$n2*T^#Ijc@{ z^*sym)qVoAO=@ph){G;{1%xq0eU$GXC`Os}KxG7`^#5Z==x5md>kKTTH! z8W8+`Lt6CC{rtwj)L6?kC>}rN7{Eg#Bd*Pi=}*HP-A`9Z6YkY_l9!R`9U_0-&B(mP z6$^eTMlUR{r4Cn9YeOpBCFI91(lW3U$6DfXSsHz@nNpjQBp7(|oL7AF507>>WtMt} ztK+eIw+(`to0G;jZH>)tC`d<{YZ8J50(h|kSR+AQ6s&&UMCs86gNw;pTV4ZpVpv16oOjbE^1D4R#$zENu0{!;7R={3GmYW~iK zJzbsY^jTIpqWleG3dA5lVPh_4ha9H5HM_%InDNsbedIdKHIh>5eN2|Ru9wsi@$1Ut zf2E0plnIvtx&LUO%TlH!?G(IV1E;5MGmhKRZJFx^&u<^}Uur(*s;c{nGv?|=a+$i| zLHeTltU`XOTunJim#sg%%FPkk8?XHxB*s}rX`W}kAzdQJ|JZnRD@DV|%p zDG9bYxPq|TUS~y!lh_&+E2YY1{Pn zTvCRoZCI!n?lT^Ru=Gtd&V4^QzIMc@_U96LW_pAAdnsA_I_XX)W-ZY$$a7H;$XL(R z$)v9&|A7ZvKV1r33$w!3y$UxUP(SIk6U+-MJ`rq8uf1r(x>xO^D*K<59f`jH@Zwtk z3(5guP6kU00bF}dbspG~8__RjG$qMK`NF*e75I8{e92u3MLzJsJXJBisLZeefH_y! zD=glP8^P7lp2->X%v^_2Nj81PD+tq~D=GBtDUoB-&ul_`hZ*DLhuiQRl4k!1HsRj8 z#_$m(Ju^^8z2l;Q4w>-)-O80V&fk#cXddt#N+`d8YARs)T(xMFj*%%xn1~C^HLbyx|DFT z{Z^&$RaxqFzHA7mw|_2+UpRc=p4Eyj>gl<+WG|eG-DPOrHSnqmTIRyT3?cS9b(&SR zVKB`zoPSF>Vhyivfm%uHqO0?2Y%JG1bSJE`kt$VowpfvAccLDNjBUQBJ*ByqdW}zc zHL-Zj`8@rvkhuf&xvHN3m@rcnXi?(q;SeWG;b*-(o+jHTRo_g^RR}#wp}QF1dVKcy z95WqiLasqlDxS^Rn42o3Ol#+)yXizii`OIPj?0Js;>W6J&!<>yE~0H)ot0?4 zAPBobGSrr7B|O_)1xQS^VUY6s4|OmoMdCJGSAEvt0x#y-56kz;40D4(RR>x7IrPa` zzo;nR1LMz2&7VV(#*V|`pPjj9+=5?6pk**b`RZ!4F4DqQY%zAQoSPLNClDsw31{8* znJ=4KRR58ky8aR@;ndx?MBnE&D(E(I$_zA4JBM|`z&s8)i)X*q5hclYBgYZ(@~AjS z)WenSvr*}x zZ;jx4hPUU2AHrHZB-DX>FN3I?foqro@8H z-D;eh25>uea=#QD(kHPz4Nqdie9 z0i~X#2kZ7SIl^b>t05w-ebJ!%**6mbUOaC2X+C`{owp7-Gf97)p+Nhw)Eq9)6b=)* z-%V(piZ;qdl|Wf)KQ)YyQi@71Z@bLf@eNVJdWz6nA(yE1oAlld(SC99pOfdyqW<>E z33CXAtGHW`g<(oERfX`)oTmpm`GlQHcLT8*CcTDcl!&O7v#Rp2vbx`^M#k&ubh;Yc zbb}nPzh7~@9&Ge~{Kn7;Zarn2AmQ}-m7&u#>|wCc|A1T1t6sp{|4&gbCiR!19@x|R zH0ge*Tt1_g#PK*y7D4$CFFr)gQs-`M!A#X1E_27zKX@9XySlk|O)^;=7{SaB^Aa8f zU6&U7IGuF^#0SamGIQywTo)B;RSb$C*F!$MF~(ZS=|Eo9Ojl3~keD z514+=sCl>joi|kpP|*wu@Zztki3G5__{_5P7wGHXy}&TJ*F6((l-KtrO#bUnK8t63 zBpM>ng;qUXGzn?OfEeSWmPjN@?165?a$o^F%T@A%$P_NcsmW_4IDRn{Q=0l4NQ__7 zNlmCv&fz=zdc_I7_)uT@_~h7Z39&L8WTWtU=6{Ws*Q-+eScrP{a9+Ct*6UTi9s&B{ z#RqU#XrQUsZh?>&exx@*Yk$VOi0eNxe)~h7HhE2#Gr^7syZv-*k!=BG{vxwy z41)L83aIjNk*lE;S4@!n@@P^&$qVgX(uL>4UAKBI^q%hdEm4lGp5(82`@=)n-%AaQ zE?AM)u-GU>&n?{Ot5kvvj?{B2V(9fhNsA~u($2x6e^ZSd8|d%hZ3ylVLHX!{A^6Nv z>}ZZuKUtp}7!UX3`J}0j5cf{Krb>`!ehTtB{@{W@2gYLeobhc%)eW58lF6|^^XhTh zh=iHdZ9lQ=LU|^i5vf(@YW3w+m1Vu_s>%}5ww_-5>+2aNN$r6jt$^Lq_mN4Pyo5Q5Y;)Rj*hWZi>irVpBnv_W#EF|G;h zsM)f2j55tbQ+fmci@DM#LUyuX*1p?;ok+X!(Yo!RUQRW@Y12czSkm6I*Rd|T`%VK! zcW3v0|9bx9G;_hZj>)zs2si)?r#acwpx>auKQT1J*d>dEdc~o;ksB43*v9khN83f+ z#{#eL+!(zK+aj+s4U9v(+k8AbYC9ib;`Z)WkgBDEviv3UZBlhzVS1sHf%RHZ`?$|j z|4A%L@JG@8EH)cvB`F@h89LktjY~|3&&-9c&G&`PhtYbLTXsazzQYF5R+WwleK_A+-X^vSvi8GX(TxvB??xrJXc_yJC1Pl=OJ2rr}qRMDkKvHmQ-cch^*> zIy0}jwV=TU2Wvr}f()pCRyT!%(o#@6pzh^YJ3O)qK72ztphZXZYQ|Abq2u6a3HCZH zssH0QK`gLSxNsH3`m+NE#Cv_=^GU!}5X-fY0s5Gb;03cfu*K#tic&L+AKMq9+ff$O zob?3tfS~_&OqIo=;gb06rm+(2@$yWBe(nDF<>C=KApxzJ6jz@$eOVTFXM|{$ZrTAJ z2j-shJOqgq%24_PibfuarjQK>MPxa^&S0Uhw++W15aCr@!|XXWQN7mAL{34M~gyL z&G|>F3KL|WBIne-FI{Th?pm9t712D9t`;doC8CONZ|d72T{FevwJ0AwHT1U;&<+og z<>7b{qmA`)#bU2TK|VXwIfU=6=+MDlE{N9#^|a(H=kTVF{{CiNOZxA+_D1a493MkU zx=#St`mw9E{vB0iY0sNZ?tAZnpy{hpHn`UR=iPgAJ<>^!>P}7Ldb-fbJl*-<(+kW4 zZBntI8oA=KRbjN+-iMbeP8tl2O22sUFmpaqn=ITVldE>+b-U`w+s-m7Ev`k2v>RTj z9kFDSYu**L)qmaQqH)p?W6}x)f`D;CH3h#4 zb9{Zq=;YCvi8PyCwUOb?=R1g>Tk4-lBhoE|N^Xm`<#Ke5`k_a2tqi!#T0I(YV3Fa6 zcVV(EU_7dQ2L&*EJCQq97dvFFch|H7ADRQF5vDU82*{ZX_Q(+D>4R~3VoC5BAVoF{ zwPSRkm2E0wS>B}4K^|&X0puLzjGhCGX8I)5_Wr0(oeKt%5*l~Y&0J3&pu+pkZaU^) zu4_?pKOk$krd=~+5Rs~}W<}+WX1+<0vt?C|s|{sa(`{82qkUi^kl@niOX3z!7Z<`c zUu%2$&u+rZZQX?rc8haTuw96m=GOL%5_Iv%nfzvB^pMD7Hir!DsV z$~IJQ4;@x8N}|(JOhN!nlLH!rC0hZjA1ASW;HCA=U$hhvs?PS2yHT#Ek4N4p*1XYg^n*g zUeZXiF*3Tgm;F?NGk@rhmw9*U+(0mk zS@x!l(c1D|7ULlio5|JuZQwGO1WYHiMMLTkG3&Po{F#i_ZM`;FegHR(%`1mIT!%qF8L~@yLgeZpDs+n5E0cFPe;-OwrptF)bdITr@ z#$Pr83%cd5_Q>QZTs!C@A)ruNY(^&w*F`M_7(b2FznoVEuJn zMBrfEKY$>|k9^nYqROC(3vKG8flq`F4=-Jg*r5sb?vz4XG<2k+EFy`CvxQiwu>eGL zRG-?tK<*kDsl1s&sM>Y&h}b72kBNdbvJ0jn2`dso$vwo2I4bn~r1N5LEvJ-7_E!cQ zgqL+|>}Cfx$0$ax>hOEGUiHAR)rJO$&pA@hds9HLes}PnYf>Ke=sjm!UxKLzd~U; zO^`kh*$(L?kw>S#4#LxAswlcN_C7`vc&!}Q_dIG}!Wclu+9(7<4u|m4m#3(7jyg^< zu#12k&&w~KuCcmBy;*9*2F=&48!y6T*tLaCkMoSW(}msL3a~Myw?!?BDS(XLDayFn z9KK(6)|}_EAdg;?IRG1s*y^U}o&T-5Al9~5&Trs`*x=m{-DVlT@;#V|_Z#Q~ne(?U zifGQ?JtY*T7R^02T+6;YA5u|WQ`d$awKAzrCbA$3DC5wG-nb_KaLk83Qr6pwO-9>P~5oHy->cJ#4T5T+%9Bre z8LMBIJh*6l^eLjd@xffd{VemColgx^Y|Yg0Y0)1@L$@5hYy{j8q4tdRBFijmy322* zW;TbZ4-Fs8VT-gaEmooei*FGqOvE9-3f*xFsSUUnV8$@oWIG|Ip}q+8#7m8sSnd9N zc~L_{A)@@Zz38@{{@JZiL0vOZQq^aOq1ZMUE!0(rgY7Ge8|&|<*KK61_=@D{f$}ro z?7`Xp@PMz)=JQ~poc=(6HPvd>nOuu@^vIL|le{U@$w957Ym`w=UG{6St4bsa07>e` zOG~09!P1gUMpr6jKVKmFA+8@j7TzC7a(Hq7iKe{a{HJQHQN=X^)t)&nK>3pj_}lZs z`<0Fr8^GfC1hty1Be|uj*W*VSVdgEydyXEZ#czd%$i`t`eEkKZspK$t*LK+|Nl0xj z4Zn?@Cu>k^BX=#M*>}A-bzNBx47Sh*;n7Z!wwFq!aQ-*?9q{5#2*f-raPVeNGQ&Y8 zn`qXQnrJh;Z9l5jd{QQtQch>0HfFR@E62QcQ8M)|H3M2fQu5gY&xxChJ#V|v%h6+& zuy&UjZUwq)ixy$s+YldqOpuC1M^F}9w~Jruslj{edu^sOyT!;#j40!(Zqs|KorxFw zfl|s{1(Rd_Xtd6XD|=&a_gA2i*1uETf?j=h*>E(U9RxQK#0z{%);( zcV%`+eZ;H7%{)t|YZ@z)k+$+k1q4G3ax7PN6c0L}V3T82t~NgnKOr4;9C7VJju`v< z<0S9`zg&*p90ia%gVVmeh(HYQ+C+|KiCWB3xE_2Aj1k?ZjtIaYQp=0yZWt-2QmJ$* zX*>%2M(|I>I4RBbL>m_8{>hX0y&2i@TnUcTRF2Oz4Ml06{%c<;*C3tlcSHVNj; zt`Le`b|4chDOZx|$)K1tGEwwel=xaCk|h&F87ngI7h0asr(;Hls6Wsme03O;@Q;_| zUU%p<*V}*j{L?qbS7D%h`D}RW`)j|F{;6Z+mDL?`OzWVNek>L$5z_s!_@w*M* z+HUlIW%X&y#&es0{|`3M?2}*CasV+tYHa-_jc0i*IXyhd2p3Zwmp2M%5}rd%6P;9e zsmSpU^)klv54<*#&0Mo;XG!m2>$xw-*3b*Nqb-gLtYe{t;Lab0zM#uO`pBkd*~~KE zc^7fbJbm3fq@v$(HVEch#h5B*?H}ts7mqCRXOeh3@XJ_~H0qrVb({fCv)%5R2{~+m z96`#7u+LLbXjf~ z{rLG<*jxagav7miBGhU`gq0fBzV9n0&<~z_)A)%QiRtn-_#*eowoE64;OULN?LJJh zCV2A{vx+oeJi_PowTYQUVW>>4J_5A7(uUWlzFc>}OBW?NeKq@vu<6bM#^kff88fQ0 zZ3^OY9DXg&6jj&mH9ILzKxq-};@X4T4(6 zd(1m*Q7ex}P7#1q&cgE*=3QsheWXN@<8d0Om^zwJ%TJ(9;|}3`^L_1l9$n!%8)z8u z*PcvNW4>*N8-3&MC|5IgSzAOLlt-JiI^GkVEQF!+wKDfaT;j3Go5JKgbgtFbrnNd*-fN(a| zQWGZEiY)X{`!Me%b$^47VfguPcQK(m{A;#*ZOuQ>%)5U~=~C@0*I&L~3A1@;Ezq!M zu5L&#gOY8hsc#M{3s#S=YnHJCxP3N14Ec6KHoYn!0EPWvlrUP7vhk%rR1Xqek;}^8 z3gA_#lM+#V?v0VJ?m#gBFqN&`%Tf;uoOCQ;-?u3{y6EeT(o2;>`H#sULxWs*nY@!I zQbI+P)qdJ`T~DRg#+MS5>YY0$xo{HX_@QVmKS&*x!q&&@4Apx545XbtyLkO)-+~LZ z!9P2PFK?oRoWb1m<=-mQNf!P+XS2638i_x~?nva+o*XOG6r7oSNA>pNiP~TA?&=ct znVDhB!>_8c>Yy5V-+tX-{kU85ondX}&col?eBvz;~3As@e|*-yOIBv zpe<|1`kO5Br|;%`{pf3_u=mK{;Hus?x&P0vXqn%Bc%FxS8rOI6-FtOUcfS+0enM&Z z*XI}3|6+UM4>weQSo*NHl${mWRQRWXg_z$le*LTdj(-_uwtfE1!>spO`Co%lP?DXc z(K~0&-2Fewp_LyucXs}jb%P&z-Vj**%D%Ye39mIfSg`f5;q=mS z{LcFb!?&v6Td8k4&u#p;Hsj*)z0ixl@izYxTf6gR_xsh~wY2>CGl$zY!fYl?@Xfu3 z>;yf^yH8nvytOGy{QIxXK3HkanIt1a)BiEm4lE@ez5OqHa?xsV$&-M)f;vVajP~u} zr$R7q@v~K1Y{3V#Be++9MCWmcy;|!a_Cb8HbA57Fwt@a268R5I(NT#pCAAIrT(p>A zpL=78zM@t!i(0DKJ!`Fv&(y^7298w@M$_GYe)EP_;PQxL8==f}Wt+QWJ{NGr(ReR46h zpqk?jeiN5t=g?Zvf6~%s9!k{!nv538`(E07A^Ip&8znzc!)K|JDB?3XN4Bfa)>ZRJ zhj4KT(ajY!OuaIbqPjLtfC&CseD-KT#qI&}f%70PNwRytgte>CtgCCbGu)Z~^)F-r zZQP&dX-`{*3SyIt&>YyiU=7&-G{sl7^?7INzS(s(HK6Jlpeeq+e=WY`8%huoBqr0xZ;ZbH{MB zc@7Efr1Jba_69jR*1j`jqegeqBNrM9mZY2Yes5dtTbH^i70L#4JG;hrz-Qn!&^3h! zVJv~JDG;!Bb$D%8Oz5>YTYCri`I@7RzSCd1r};fbnUHrfd`ttwP*vldK3Nqqd&JB!Rcy#l29P;wzJ< z(mQK*lBuC%II$If=QQ!$-k(-RTb-D&0nVgo z8IqM0GFf%$WD&y?d9Pu{&JMiO#0N@leOV-qLyOgktFRgDsYo+gYL~Q&o8Zp z&CZraIp$18Ro!HfN&TARp&+ZknZ;l?V#~1rwBM?A&7!W~@Ei)Hud`hv(Q+}9W=<*P zys*Qn0H(XSkOF52N56$ggx^TQUtfWXuNTq3O`lvgnm}pTpv2bRGDjz@W6&=J#NM3 zIS1%B_LJ}J@zYo{L&r%u*&$Jrm8pk`*pNCojY)g@!x<${XK&boN^{kB*wG|M9wQx7 ztkg_oy8^%iXem9;7O8ux!oi-Y>EPojG)XwWe4E}p>0oCt?*_p*9T1N+!5i)BmXVDY=t1JFW$tXl4(P%ILW4S*fj|U`aJE$3HjYpo!X7N(Yr6&Qh%y%+ znfKZexZX^?XVeZ4e0zlJV%0HGJ!74e+!q#7)X|1_y|;M%z;co|5d<$4>qRpeF2$}G zo1+&)SQv0l__?H1vHkm+SqI4F&5d3(ddbCUA)qF^RNoByG;6uxG3zqRjv{U7YG9f_ za;s^Li{H->(DYi$X#tW`#oeFz7Azyi&tj7m*t{w4>^6>Bn}-RAF&BAGQ#r5&LD!7= zcgjVbdi7OMbmp4EC95QAgVpD7IX*S>&Zf`a`9}O){NgRYCrW|dt%RjlH-Zxj9>z-6 zhY}J7;s#a%q-HUv#q6qYC3{LqlEh_;jo(u@FUCC2gcgX?1!|v6H(p%Z%wY_n{&jd7 zrPMmFy*aw)oQF@H_?jEFKYO6yVb)J|=?-bej&5a1Phn4#d&_t8a92NJ%&%T(qQ*0V z;R8UGfRKSsko#gQ9F zAdB0Qs1}C15esi$S`DZ7#DNMt*m!B~SMNbW`~Y76PUmb0RWarVkoFFp+O zy9ZV&x&;Zyc@&U8$q2NDqlmWFOnt`4s7E1&hAUx{0AnfOfj7q0f!lO7!)lB%nfZ#C z!fgQ9OkJ2IvLFa>cC{~=54jtIxdwUZ!M-*FPyC+9O$9EPutu~Xzsevn`VJ%v;lfH_ zSq52yD{WCY%CW}C2+)eXZD}=c!(5Ja(8m@|8_DF1G(Ox7z&sEnXi`p#Vk14*jUZX% zg6pmT$KNivO8yE`(;)y4e?5nEE#}SY8ym*Hz9!x!+H$IvRKR;A+^Rf1M&J*h z2w=(|+6RUO>btty^N3T3A|2u-b+{5A6)>Y<7)N@AM(YYjX`|Prr1w`UDK#8mMabxNtPZ>UO z=J62JOj%I%Ql!>PbBkmWYZB13;40lYGywblOtt0RlyWGbwQaq4KgoiaW*T@u91eu~ z%yfajkw*w(ha*A#;^GMesNLWe+WYRK4OWS5923I}YbMQ?bQ=0E%^9C%=!C=A3r1-l zgaP(BS46}z$hA7SKU^OAyoYPK(@S7vdIkUt&kO^Ft30DGe#hE5 zXDa!Ay4Dd_o18@R7|Zk;K`xPbJr&>~j}pA(S51YLS|{VHrouOGP;)}FUqrPhW}v7x z1QgYVT%qQ!=*Cw6&r#1;@j}pk2D10B>}U5LqQL)CCxsdEJPZe;p9qC^a_R;(Spm#u z3RZ%ZiSmCX%X?~$UoO$mb9s|kS@Meb++UjO4;~#-dwi5>>VtM!dZJ14p!%FLg!afx zUNCk~&0UR)8H?LACHPx!M#Y_ub-16SErwou$Ek18xtHz+mgru5gwj+2?F4+?zjy{+ zN3Xp;j2{lfvvk;PTIp-^-8bL4b)fW*+<3NWKxlW#K-J9$pg+9u%KzQVUG@iEdtT>9 zKF$PltiCgvj#zLDJl=>c{5n}MEE!%B&UxqVW#GLsWN18BkJuAoEe%~@CfZH!vZ3Y; z!|&tpPSirI!`Nb8Hb8U(MrDae=UtAXp_kgn^E*;=kLcBs%bq1_c73vF8vhlk z#-Obsp*};@YP|JT9nBuV*e_{sdfuomu!|+((+e#ZevGe7stwa<{q~{uw@sN*@3u7b zZ9lg`Jk0d{vatLb?RS=YnBZPFlmi<^rO!|#x z(z5nr_l%0eTi8Q$X?0+*3*-2V{55J+F2-^pS(x9tWNST{Nsv$c!*?boVx9b$=2jxCf* ztuyWDml#rWY3>?SB%3C{^P_tWag4QqSm^qQ>Z^0zE#gfBA`RktZ8hYkd9dSr))~4`2yYpmV%;X7s-`@T9l2UP) zPHUvK8cT46Zjt!?lkCOJiT1_^u4((G(yrq@J97c;$l~Edlh3V_vb&=Xp&O4M=PNEP zwpD{B!=k_>2gM9AgLX{>HiB{&5>um}&yM*3#E?o0w)Djx=9;r8rCi?CQ33C=lW~Q|DmA9roQ1Rgr;2vgwJR5(*m?+x6jPd8| zb1Sgh3O{R-UP=>7We@ghpd3scun!@{HZb(i3mVpN8i6Vq9udYMyiq@mG~jbwnkvU~ z)wud+q@IlkXR@kR2Z~Xq8;nS^N<1q6YMKC4d89^TIqun_oa`F+QPXFz{zFkTox<>r zSbpiQ_}R%EzmK0$OHXGyk?Ps<64hRw$4eeCRt=AKXDQa7Ssdn7aWQ}aI*BP9y;Mug zr@$j4?7lPL)xd5<@w5B&#M4}{&g`JV7v+}=OWq6VRciSv)hl%OJ965KCIqI=;McR4 zlOT4uyA=Y6ZikAaL`hE0NxBO4QGlN8$YF$#V(mT(wctt!+m^?rQ8UC3URmkkQ>7&C zbG0_uLc>G1xn%UI&RrM1n^>{q5U)TsSE6vgzH!<$E6mX)0B;jnGm~jWFV7FBaAN!7 zb*DujMO7cD#Cvt5qQ;cQL3(m`8&wMS`WTFR6Rb}S6!r}dTucw8HWh7GHddTQaax`* zu&73xL$8Z%f2y=-E00yt+RuJ(P_wi zMx{7swr8S0XfB zvV^BMpiV0pu9|w7Lw%UlT<)oD7HmXZI#aG9SDnr=5Gh{Sh34x4Bj={n$fZPnEy<0} zhz`v}8HshRdzz|g4h5`+3l}=^IptNyd3}{{w^;7Lo zWz@^&n%1!{_=^@TR5J{);o_JeIF7JrZz0y=>kM85rJ6^3ySm+pi@S%*uJm4DXaqu& zwN@+wX`&)(g;s>4HmlO5J0R*?=d*#DP=5n##s&FKJBwEqJ#fbH9MDgjT%FL+!diqs zH_#`-3@yf4(+fcNkv>NMIwYw@&+vN>4R4=>nyP+QqNh#-Jp~;B+=GBfpDb#+6Jf!q z9rxv0<_Za@iCP0`kP+0p#{(Ua9zCI65Td#bEfo!WTRk@loe_W!lscN z5oItfU6|$)2BQ_NXzUqT9~&%pKfvVVnusNdl z_j;>4P3@07H7}Bz*pE#S!B5ctUf@56F2)8hFs^!pAca-ISitP0ZVCr1?50iLzlK*@ zJ8U%S--VBta4-GGL-z525a9Y@kQK?|X%Bz}j86i-a84g0Yy1p?gajM`3RomCxs8Nm z5BcB$6#RUdEWL)xnbVE!&%p%f4|;O_T^VQEcS&y1NG~pwz}4B#pSMUFjzAlPWmUBe zdB{vVUrmk2 zSFxij2Xo-i_&RV6eARJ=|NpDL6c)*C?SsHq&4KDfl1~5z*Hwv-yL^jvmtEdxRv~ z2%%r1D`e2_&G-QYXMoi2=$*QcVpq+c)$fgScO_)XB5zv0LDj?3BRtHF9sB= zxJY<|ewi+)NDIn8vviNGyQOz|iu$<}j{1 z;*cd6p2NVSg`Nl-;!{_kcL{nkEaFt>z;lwpK#Epk6CCVSwv=eHbPFw+E0R)ZcW;;R7lO~U0-$eqCCiC&opMH3}` zeP%teA;7tMhFnJUoCy@}dPjuzO-J<$oO)w-bH_ESCIC5R?khE;xfQm^Ct-BUt-&m|!jujpRvT70~3 zdBn?s-E)6Q>|LIeZg|EKbz^r3r^gsKq(9f+ix~qH;9d1Syu?t1zHLL*OfF3cyv~F^ zbM$~XN{p(Y`UZwZZg3XXHWaS=1#-OG9DNbg7F}iL+yE=_%7yC<>;g3R7;kW8xiEfx zY6Q%s!y0+qeaka=hvrQtmyCrf@sxWPL1l~2T(1Ka4oHBAEYN%Ka?TGnoM}k>pX*|= zc2F9JZ25K@njNDm_h8lfQ+9&!7ix@;1v4F?6^G;{BUH%AW)7oFEn1nv2cEhkZT24` zg;}A&%GfR+yrvhkR4c>Z5LmG7utzj{uCvtg?X&6wakq`8O2>2N*{S>19vtOOBskUs z*CAehE8Ya!Ov#k9sn_H7tZo*y&3V7cp}Vs+6XgZ1uW8M)tWfIhJ)7^(-rIf%>zg9h zM3I!jQ3kQD-lDa#Os!sW8Ir=7%J=wAv9a#GKu~fe+?Z!Qw1HDkX>`5P5rhkZee1r86_Jos74|1y9$R!qD{7TP;48nc^L%fw; zO~%!on@VMW6U0lYF<#Mvrprv#@g-Mt{pZPZ1q`9DH*rRaBuMsF{0M6pJH#Z9yP80l zegd~;oVbE_uo}HYe6Na5=T4lkeJ>hER}f>`<=u>HnlBI3^f^uS8m7_pKilBpKm?)7 z`fUH6zy5Ngy5#${@Th+0r4rr?Re)a*G$zWu zryB+=HB8zH_ZqB|8WN7DOCfnMMFucokSmfKm6# zlxl^=MOHXtcu8zE+Sv>w3kc;AK3e4bj~iHX*AWHQe6m>hTg{yT-% zuTY0t$zvFk*CFoPtm6Erg=r$IF1m2}(0v(6_H^G25K@wt@2DHrSkr|s#)@>z9RnEd z5>)@61fun=9vZxd0n<%O`kU&b%f%Ueyc0IAuTHslSaQU8s6erzmU*h5RjRAH!PXmd zM$mUxv1uZ;CcZsz{i<#N)fxt9fOP|hyPrgYi~;-D zJBA?dr!O|HOJ6Zwa8&M}`U92}V6r9ElKC-!{XGP6S)v#r`mnXN40M#5za_MpIn4*G zUz9_zbFRw0avJ=|E^Fk{<}iO%IEZS zWPgf&9!j1S1G;}F>nHe?TX$G9b=QyZ$Y2=RH#c|LiHfI3#vZwx3Z7rCS0)`i(zW{1 zF3@FNDwV(R5tkBQi{rf_<5n?G^r|jk8ETdAI#y(MVC*#6r#EnSA^kIrxs|XXEmX$l zS|aU@KGq-v^hT-PcuKC`?fcE(yM2+UbvI=5$CWGdfOc15NMCq{!q00#JYkM+lA43& zI?4`cB1(6@3wfs?;0EH*W-ApF?D9wJ255WW3Nq4HX&ySen&+tNlPikk$#b`{Q{42j zha>(x7*{9x76c;+C?t-2oUL6LRvGeKI&o5puqljg<$pNAvAMj{-T;R1v+s~sXpwTS zt3VWZJlLrolD~1SeD@KkPas~&&%&&(J~3bt42;p|&0huW!B5Pk+X)B*{5J>#1cUbJ zZJzhMb~1ALP~@%7~>_Dnh{yp6e0y0fiHmz=pd zP`UpfWp5tM*q-nGZ%G^>kwmC=P9H^xYBM3Kg@m0l9J3hP?QX;A>34fLPq!+xF_J^ zwetP$&*$@gy=X;hw>NtG!WWY=Ngfp{fFc0(nqOI|-QvO?%|9keTVZ)0I8pU-p5=4P zj-sASwCmOocSx%eotm9rc9*6qbb&hyeh+I66&Ac-c?`T9Ly|ikx2=5I-#vZ=*iRlvX;xI}_LD@!h zV|MXuf4M=cMaXQa_-zS=GvwaYjhisk2a&AE>xhBx*)<_V$jV2X?kUC^T&lAKF8;FF zf$Vg49-N-jZ)|L^Ki=iA*$|Y{fZr})G{u`_w(n7}`)mCMX!J0XhkT>giCX62aX7%9 zfHQR{K4U=43d7j<6TcXC%iKE3Z*1!nJ)xDiXUJykbHXl86*r|YU{=G&FQAzu zCSLdy?DWgL?9-obOH^|QgL)NTbx$H-0aRFK=6F%S{w{l3-s+=hd_DbG+p; zb=tRO!0QA@JwE{X{w57yuIo-Oo`0!~&Bs-gjRvH|<3nX!t$8xFW^~%E_P`bI7Dtjk z6oot=-_`NRmJu_OrLQ<)ewEZp53j)o83@<4Nm7Q5>{V*&{R_Lqs}UwcT%J%kYMPsr zF96%Y_iSb?JlS?XneN>EEbG8+^hMm>-kRthng4K2-0k)IJnZ`fbn^!#;`+XIln{73?F=GVU+4*SK?o5)0%)Bu+Tns5K8DgsVL{nR(?J8&wh zjp%7F{)a{lnel*~x{-da(QKqHvBN0CM%T6;|7XNbcj2zT_9(K56jI3?hr1FK-<+l> zVUnOO6k$JZ#4_}L?1n&48}adyc-=>NLFtjN&xha6J74#+JE6|~9mRE5CtW2=FZqW7U zf^tGUK?;=Jhlx9y647hp1HyT%%buPOWGWRdzfx@kqkaOlQC_jUSgA#E27MTMq(L4N z!VpWxAyCiB(ofj&IUA>pb6Z9`I}kPI$*AOG>sf5c`^60esbyIxV%?y~LS`>@(h1=_ zxk0r)`Vt}3vlxN29q4)uba2-(n;=zZ) z0YQBZcnT>=CCs9Y&|%01v|L3IkAf9z`jyz$;6w1jx0WG<(k4C_oYMOP4~6EL1C{QhbyWSvb$QPy+fLEb zpDBArYSG!%Y%iT8jgB7f%1aI?+F%Ulp?%03X|0Cor9JY|2Q0W0*YYGHz5%Q?EX+CA zJYOGe;mE$JUK!OmCaI*A*__q6{`-YthDGGPrK4_ntwP+B7pO>3#2qUHyY5NNP>;>b z#vH|fiQ-e&5}`o2YweTW8F(PM?75_Xvq6v+%qzu-4#90_FubgYEW7A~x!@=&Uy`bm z#vwrs2ptZJH8O4W-?edhtj$wN<9Brchf$#fM4ZESfeNi1Unr8KY7K!Cig$)}kfTo- z?}OgW_-ER3E62?`D{swYR5)N6@q~A$w zb-W`kbV~<3(rvJm=LSybZP-|*eg`4{x@Fh&jUOsz0K7B;``;=ZF1HjT>w=?Nx1Xu_ zaU-JpH#J)P#$V*t1MhM}M-KKOv3^YuDAWs)fetpij2J9H!;j8u?qNzZwfrGZjS$Cg zfg}h4#}lhOdNhxpt?yhOVnTTaxmL}1#8VaL2u{HMPK5%PPsT(sE%KZi| zFJi4EQx#<@f0If_U#K{IDl~ZVhC6VpYLa%{6Ts4!U)nf6aQ|}{Y4T_p;)OU`F>iNx zsr_z3HFA9o&|@=^4^HZ*x6r6lQ?JTDID5Xzb*8m7hzsCcGP1Mnl|oa(T`M!%`tUa~ z>+Gg+tYy{VFkWLxiKRy02Sy{HHr6tuOLn7(aznDMqjR9t_9kVm3K}ia=X>$T{r#MW zK+c-Vwxs7T_3V7V56%7tj@JbWYFtcxM0Glu5^KZz(autmJHzbsD5s-;wFP zCh>U;4wz*qLZz)e1L0+LD*#57EG3HX*6-KBRO$bLDp|eZ)OA8`YP9%>D*1Ld{Qsu& ze-CSPzfEkGeN1frHsj&-16FZR`&0vTp(VlPjd<|kk)J*Qik9pG`Vfu?+Q>kin{GQT zE-W^^r5m(Cj*2y#K#{2SgT7>;P`4)EB!NOH^6>JKNO#_32+||Wf@IB?D;*^c;n)0L z{%5h?Ia>-A1eG(%rsp*DKjrqhx=!vZ92`aU5o>M!&gF6&F)AXMl%T_I4u>56vJ}n#2`R~|h z?lJFfG}|d_B;=_i8Cy1TdW1{OOnNN){7 z)*)6ru~>}l<+HJATLgCF$}Q*ba-WiQ2Lc$CcJL#3xeT69^BkYHXIFFo%kwI}`wK z%64vHM#d`h;SS(H2_LX~xt<{HJP%uTk!050nd+ZO(tjqaM#p5>Z&_MT=tK7p|CCNz z`nqk%EPT|myFQqNs6wwGB8)RASFCFPT3MWv9Y>n^F89vUA8aq5zOr!Vc3aPzX@4!$S|v1yRujnG3b?Im*TM#AyOfo zLTH$Z7k%t4&MT55%W^dQ!Yar9A-&Dn)c`EsGUTN@QYwla{I7z5z5kV6c}mE&~H!?L-;0Gp*Af<#d?4X zXeec}te4S-+USmTdPC_`&q_PqpiUn{3kj|3MjS-`tgx#Lytdq~GL~oeNEOGKStfBx zFaGX_F?VJ4fwi(~yDGctaroK60mJ`D3Ost6Qj#ujsu2G;fBQkO+1f6-`9U0YkG*_# zI_Q+JqgM#<4+EF`#V5`dz*kwQn$rubWwwuv4t=YR+<%qv$kEl6C+V?|s3A+z4&NSv z`ocG=@|CCSsiCuqUiEE)HI}Yr;!c0XX_s&oNptIEU@mRC-(cqOy+QnTSy@u_o-60+ z=`q^;KeFdoX^b}BZM zrBl5|Mt^wEzADiHyeZMeIkH^GQ(vVuXd?{-Jks9?IgR}af~Q@&fJx~Jt%V`uVOPnRJ`Kb;f+Y9*`t$gynW%UWy=Ey)3SK4FM8^|AD0qe zdW>4DjUc`tkCw$@`^Is1J1EFZni@0O^nj!s0N*$!ki6hw1wi~~ajZ|_=8wd50_f|2 zYvRu-Um~+B@s%#Ou%wifgdZgPNnm3k!oFW0D^a!UIp@lutsz;tGT6m~7(J2`*O}Q( z{N>|}l~0yiDFsEp=B3)rl&aJ;kJ`miX3SZOpBjvjX;2xAl&lr=G=7Vx#G&t69F7_@`H7yZ&=oG^0f+ z31PEs6f(NOt1Sjp@p`@vq2Gn(!08LE(iJ1oDR-vw&dBK4nN9Z>F(;~~1LQ>6PKW@{ z$6vVLna^}1rvPb&dc_WJZCQTrv#ncTakK{9r36E-~med{J$w|n_2q`wr2 zhWs1|?;1*f$~7Z{6g3mIj_f6?acjCa#f7Dg{dmJdw$U2o?U%;mipv(wOFlQ9nK073L?{ho33m{1bCKmw3>}@ z=qY#!F`n2v^GL|j9PHS3%ey)qP!1X?RKPM-DcoD84p%)l%ceq4v}@3Sz;p#)tKxis z1tkiAwHzDsL3pIPd-2&6ML0KABXn4hbouR1t(jNy?#mWogyGkQa z+^zB>yG3s6Jzpgb(2LKFe5bkex>c7DQzYjhz>CpqAH^>H?cpi#ok^UX-&ETO-zq)^ z3S_gr^wHXrNO!S`9&|<}N#fqBxWuYmXXKjwlAT!j|oa za*k?c$zpx4=WSzZ?vQF;Z{UXfj7r*+y_0l1^oA5?8rRCd!NRrtUrcb%sAQIW|({$ye1(UH0mZ>}bM~ z$J@<|=c2l@e48R>(VJxuhrP_IvPWEAV#a%l?@ifwxQ!H^`a8}T9Zu!y=a$<#{coWf zi%kpmo#n+&jkty%_@?J2a=jwfGH%+Uf^&$hQ&(RoxG9kVk#B3x2tlGvj;-UO!3&_d z$d_*nPh9Mkv^|ea^rr2+fF)2Qere!t!0`zxE7tq_HY4Rm;clAvf9dEjJ~vEbUqZIb z(Yd0fS(-U>xLJ5Swt*a1J?t;+-cTtu&#d zO&xirT3M*0U2vvuU`LVp`xfn}?D(&1A~{}(j8A%(6v&C*Nt{Of=`?Idy3kTov3<5y zQ7>Wr-gJ{u>%8z*raswQSCJalsydsS>l>~gpk+~E`EaW}Ted;kQcIAyk5|&P=UA7-CMl(H^9R|z}HL9T;hs0MT zhk~NpSdCrl=(_TV!C{>pIa@>G)MdzE$-9@qzCN|&pB))IuoWd6`oNOq9`BhnWpo|9 zdgJuKgBUv2XY#AR&7*DvC99>siO2EW9`824lDsjsi0^!RzT7_nJ3 zHTw=7Ae24JDJJ9}n`Ab;w0pnOUaH#{9v$aj_z!u@YMZs}nwZ)3rv5w_pl+$)QHjrI@G98S?V7r^1>L5YY1JHaOOi{Rlc zT>j{f@Nb#>w~&>u^K3b(rV=l|hq*Vi!-{hg0Rn-$I2IXl^Tx!=y3u!=PT~@~2la5V z^0FMAYI5m$viKzRFRPP=$3X#j2V63#S_%Ls!WG(LNxccYh224R)mYWe<<;ZrF{`z^ z0rZ7D(Z)~Nxy$yuT14xU0Ly{{^jD;bD93OMlI4?>fO)yaY-woB@WWNNgOHq}KlG`oZTk>gv!vBsiG=?gXw7%PVTC-_85ccuR_(fZ zRPe%8URom!7~kX>Mt!-P*&nc77@9R&>`H#2HM`Yx6x!WEHg;*T6+FlH}8hj%ssgMVq0!5ZqGW z-gx~x6fYUakt$b~L(Y)4$WcA6M8#8^XPu6ew&bvoRSv>H%aR;sN+4w(?Vd4Zn>T850%tF3)-tw6Q)cX6#)p5O=)iDw}_ zi;1MFr~;kfq#vX*gaYB`l$bF~74;i|CFf>Dj z-||F7T@ZMKRGT9{{2mJeDwYMmCH>=5{C}SRKToQEKKlRT{ExT(zi(sU-$)jVYsF7OMnF}52SJx5yZOd-X!-PN27(F)wse|T-Uqv zv1n%PT9!H4q4)6UPKh)o%P4%r6H}cfUnn~YSDFoh3)J4g`Nau42B21|8>;)Yld*35 z$X>!JL1;2M)L!2eP`Yd38E!`6UaWuU*~c#Sns6IlU;XBqFI?2^s*XqCDMSkgPWW&L zwQiAXLL{WoeBPs8R4r0ZT)=u>Kyb@08>-C77)c#D#NaYGCm2)uI zeqhDP81vJ1SVg$n%vBks-eGn+UG)Cw;LXu;G%?r3<)u#qg>EVfIx)mW`%e`8nF1lD z$rBUh>tdl`p*l21>aIrGPot+o@S^G}m5f9#EG2E)*75y=r$Lsg2+IbQc7OzdUGS&# zy(n5Y&(?+RZU1?Q3V}+zgo$JWb4WXcpYK(B5WvbHb{rcCP>YMH{Lm>yhj@H{Yvwdh zb(*E{#>;pXmZ$vWjf~{D(BF9xq-slv-CNso3L|jpLv)wvH9syc_LJ{)`Y&j!YgL;_ z+rERu>zy&3ed2h{UXkx?ARzIFp6p{oatj2;(I=|nO!b`z@#WFq=ll3V%sz_tu(P-S)jHawKB z^yq!`RIO7jrWoZ6aLHHA65{EPu(~gf{T2kZ@zuqM`Op(Xa&Toz*hVSyCdn^JheO!^KKYR?59+VQdUZJplwl9O< zUsZPpc)OP-8yAGru(7`#Gb$ilr(0*>s{tl}HB$wIWD?L|E7ciJCC@t`0D&+ki1K+( zFWvxf{PcNRmha9&ZdRM>;94SY64M-SKUIaW!1UI%dV0{)x8I-Nl2jCtKG=>G{%8bF zBL7pN+wFOu=0X0_YONC$U6$ha6F7*BoQaSRAAD?4PDOn*=mz}O_}BmYIXpntOqPEf z--QRretK2$Pml>*EyRAne7&z{P1nxmCMbN;{S2+w7CNSeTh^maUA&#@vwS`9>atr& zMV0xjuY)B*&Ss#y-gb24D7YRy#T6}JF0n*Riwe3!Y~Kn^j9;weZBg5}2lbSD?_Fdk zS2;_~HkenoGXxnw^{HdG0N$of~{y9x6CMFrfyJzqq z*WJk1d;(ZP?MLbpHnc4aPGax-@r*6s#N&M=k@&!~D`KU_*j~;ZKX{O&(&WXMMbtKh z>KWT2o$in$E;E#PrPhj5{Y^BubwfI*MLDA`<1(;!=T#G#O#$px6TWzJhhYcpJ@1K? z#r|H;;Uud+_Zzu=M5q|BerI>qn>W7TKidtP&yK$N2EP5raRe`60(egW8K!I8;NhC& z&R2_9^RJqkhwUz>$Ge}_5=Ts9O%n+&<0_CM1)M>b?TW9(PaxBV)?E^ znGy7K-G9nSi9n=UJxY7+xyfVr{_sC??$hbo?f6C|hTnOC45}x%!0Ln0vo2~+9HOD5 z)q-|^Gg3e;%Toem9X0%SkI-l`5U>sec)yety}jXv+tqnE?h?7jUud!rvoxMb=^Ino zgYYLOX*gbao4PD7i?`zdZ-!|_%Sg*7w`n|PYaG+a60$1H83^3Ze#L1$EHl&pwjVGP zKFuj2hi337w46k-O)}N#d_7S#?@DAZIAUqx#fQ0U5*HJJctLewo6)dLGf%8K*N}97 zZKp+=H4y6({J;!r>0@`$5XIfsoab;KW0wMS`=E5XG|2VF=r%{oayiLIO&>Boi*YT| zVP)#7>V5f2j>hSnDg2a^lib6-$iIur&Gp7j9!R3MPa*&Kt?1YG~4NJ?5utf2GM1L@Ah!Om z)H{#&zhjkN)Rg?nYiZ^hjYqVq=k}Ia)g$=Doil5wFp{oGi4i7VG;}|q6`9oDs8j0 zo7J=4i{l@4;qLv3=)W;Ox_$PTS!Hm!h-s9rnE55Z8WF9Lk<{JW15I@LItU76nV9P@ z#i(Opo|5@US$i6IQD7SO@3H0B zDJr$q$V^5gp)fClEsq$IThFp<=Xnl@U4a!23s{*ma0HW5Z+GKlq`2}MpPbOzHUyjI z9M(Uy$b(kOyhI*H^LCXnu-i_Mw7?Vk%;_)=OBOr)a{Vg=(K==!;4pdo9ltFH&T9wWZcLN3{d`iT4?tq zxGquI3Ux)+dbzGzF+IVY3{ntOf$q`9yRY5OuZ^Q_z1#J^HY>-tOeEcchbS!8`R^a# zXy(=^|IwU~{vX^@4t){$je@6qyMu?(mGnAqLS>=*9n-6bDpMj*T7TMnJql~Fv%MDo z8GU&v@l6wlp4}H8=-0fs8!6IH@qD8&Q6EZ41?Z*xht8u}cAcg7ZCbk*H@0&TX&JBS zM(Fl#)8GcxI5*1zkZWZHvEqY!S|EX}wO%FtG@orfw& zD`ZPI@__7u)9yFh3y(Y{Ii{;eEeT-eo=CeEfAz$wk<7;Bsi}!Y|GroDAST$t5lw6v zNh^h|H!&uUkSMQKsnVO*{uPPqf9#MP1w0Cb7_MaXZSW>3W3_y^pG}m^aM?O`~b00#aUar^1oqd|-wgRwV{J)e7%XVta3j2vVdi^Z2 zZxASHYud-TRd<`pfw==40;?e>8u}v==BRzU{RoD`Qz#_BWHNy(fYFR+9qIJc%)_sC`IIZS@R&pSh4_2r z%GOSKtyWu-8CT2Bzrvl{)f5**yv;OVy%1yE@>?XsVu92GidEnSr;w5NLK_z27f+Z zoL}DBCO`ZXXr;8$K1Z@Rut%u0)y%$iyJgwIHNHwN7}Xi$t_uQBydbanyj+#2L#P9H zYUbeC-j?TB$5E9~4st%?3Lyk>qLMC$?bl8hDk5^Xu>`{~*jFF@E$2 zI{n8!pt1A**=O)bb8J}HU;dk*4kz4;Byz?k?ot&!D|ybE8XW;2kdpMsAzdq;Il76* zyLJZ&8LprbY3juBe22pZiBL&##bXHud+O?@49zA-a@r3S2u+cIk)Gvy{;4W8p=`)+ zuS5Zdl@qe@;R*E0|Kmm9NceGDD@8vQR?>0HL^KM5_QtcN6qPk0s=&zZ0R@rE~@78N10n@;91BN;< zGO;s{V!fxTj_rjBIo{;EFb8*3J|Rm2jD{q^D9c&juMa!pKC;dYZH@3ssMtzwGuXq6 zWz10dkMjsf012Gl>hJcqD1srb%d;@MvbN=JV%1`2{djimpW_~^HxfX$( z{!X-(EOG$1ZlNFhEV1}&EwT9%6A+PJ{{5chA<9r;GC6c6g#Uc_`Eb;bD-V|eMQ$9g zyn=M$j~xpv14&)uq^`mmwk?A8X4~p{KS0|#vvl$S!@>z! zSO_k-mKM!lE}(bR8~96K6Wmdb)Wq7<8Nm~VS*0Pzay^?cUTO;s$l7x+QxZ@k`Z%Ma z)HCFx*V_`jKBV^S!6`hEFVF$Xp$~ZdcIB$k9Hdp@Eqs?pRfcy`2-LMdyyVxYK5XPG z=003h3xA`1jt~SH38>6@2DWAqWs3Jvq=Q&4K2d2XhOGEyBehvk2veTlX+*?ryD@|| z{Ipidy|OoN>ZRZvZr#I9@Za*mVhbX;X6!F(N<{hzulX)=B5E#mFG$vh_hWM+8ai90 zFH)qoU(!mA0awY;D_Ux=>xWUIr?kFKO)R+L?C2l*$q)7q%pJUsLFp51yH)xE@hU-Y z@H1K8CZh6`@-m`IO+<^vsE82$uD0lqqfne$L9-8o%dt~twlbz))e)c_XF9zOj7l!* zI!;VCJKD>rs<&-?oZSqeeT08sAf0K5Mk-y49q$=$e7oZr+UDTmZ7_IR3#k>1#h+yB z7eiihHe}0?9~D|YPte@YXI0FK#%jL zJRvhFmGQz&P9G#u8Ak$%_Ur^9ErYX|s@7wdoTyWt8~G8RD-h|6|FsGa4Q3{Yp|VD; zAXbs!+&72LFd&uJXds2wNV0Hmh^k8BOcVFmqubIneFmOv&^DG?n|i75t!dpn#M!X%U0^ zs=0eRR~u$;Xo-!-{?+zUZL~w|d(I8Oxj77R&u`culct}yH$RWomMDams0gR$k9|(0 zqd~lMlDSaE%s0dXdv>*5vW$*cRT0J9@rbW|KGN6w$;Q1)N$leFALp&g*x-V0=)~V_ zZ_{FPr(x!M1MjOJ2etC~MNGvKV2Va2t*=49j+yGbG`|?|&1v9Nw*R(Y42YEw2kP(WnNh_xN@(3mF(MlXFf6bv2AFg zO~%tz(`)Pt7n_!yI$fl}B!rWalM*%=-xTV^+NIUqwnHNCr0Qo!_DswXQMl&D9^qA7 zp08M49^C^$Bg07<*nB8!@2W85>mc40>EqwosM=yUv7(Khpblz(&Nw)4sg95q@wZnF zzF~Y#j&HuZ^LT3&hEU4HyfS1FgoE)_wgX+@{;C%PVat_|?{PaQ1@3;uu2+Q=jgdD+ zQ3?F0w6$zFk!`Or^7U0gLoWvmXG-zlrl6tAo6_f?qNL5Do(6(x z%z-Go>44I*6X(tIc!o$fy9q?x*+Ul%vjQ{vdY%>HqgL~wBCf2cKqnEOiymVwTtIX= z(&PPPLZ;SkI<$K&{bLn8Y6Sg2?LMYr~#dW#DQ7EmuuBzP5PYkZq zVdqL$-d(oD-L@`I-}lY9cPnVi7gkxWbw{f!>A{|0_lI+02Fb`WHdp@iKcM8RynH9) zpw!H!ywvC5(944JlZ_0-bCLxQ@aE~S!MZOw)M`U=^fZ=4kmB7#E0U`MGFtYpI=0v& zC>|}rxLwu7j~;k_EX>>rzo`0`ue)PEedT<=GAZMcWwTK-%&j9B0Y-4ci2xvl@T}Kt z*v`|)@F>%N6le}y97>|^CffeOHY73QYa-76FB#6fso5kZD{3Lg47(UGnA9?AE?S3Q6wl2JJCvT3yJ&L8GhYx8Zonu z?99QRqR;gFG{vD#V5bM;n739pQ}r7%il!*vFc0yU<1Hb?L^GB_y6DI?%>1lqswWze7kbM)w;VnGEYEl;o~; zOE7N1lKZH_dMVWO3+`u|#w6Y5YA(?U_eFj5-yi0Fc96nZTMjnQ2l}V+o7W#kIF)Hf zpKe-x{_t|!TtaWI(F-i>-_GfFE=yZmP_tOK5C?n0)hr{Qq*hhVsB~LMo289^0aj86 zU!OAHqDwNv&h=IeIzQn{Ms%0sGqj>3L+bd9-0|b=ECTxBd>siKZ6MVTc?+b;=JoUNaQ1?$t3!gVjrA)N z6r5*IHLD>NY}dN26b^gh-X{&s3oGy4y^AI{l^$%;{BD!(i{0KQ+ZA@<-*`7KbS#uV zWUq!vWA-9bH_|dvE>+mI^l7ImgeBHP@?x-#KX#zp^Gy`?c8Y)Rf4S zuoTqOMEUmnWSIX}v|$VL-?HyjTGqq-x8suSkNmeeZKvqRF#oMXTAT_k*v9m)9QM;2 zSz3PLhG_c<*m=0(VaS$a--c4CmT#$kD))w3!F9t+!AkFeZ{Yy0U+Z=2`dRBzXc0R! z;LHZJScUm-e}?&Q7VMRVkNh{t^ZPLW?Ox^K$UpdRVp`&MjU%L%uU`~=%YXCy2mkHw zF#qi%{tc4IYYV9}naAW8GQg#3=aHvloM+gge7v8D|tcw!g6?3@?bEQzM6TJ$D&+!Z#Z{+D~lL7 zFhBqKR8ztg;zOuo(A6~QiDaM*2gSHep^?$mS=Aw8^Uxl&HC?hk%UG<^g9pP}onUQa z!nc&lP*J(w;W^<->h;djbixv&pbP0J1>?xlluce!>Yh!|j*z#xl-|Lw*4wk2 z;h_=)r3>Q5UV#|K`)LU$^GBP8x_9sFnX)-yQ|xh4B{9jm@6~&c!ScH>XErYwhO`AUR6N8JmJkrwwJIt?E_Z5d7C%KYU zi_|rZ(|_(eH5Hb8FZ}LX%e{8agL6fCUSWCa9isS)fXC^!tf~#i()qQGNKG#Vos_zJ z)mM^sGd02D%6iJAM&py29GT~5jj9Obq|--zcL@1()AhEFdbV|^OxrwD95ijTFHj&t zSf|Cnj^KjgB;%p0r#dxKfI~gSN@JW5=(DOUMZc9Q57{Tso46aP3=ow^Q@4mP4Xo4p z@0!LnK8uB##q^Y|yO5 zH)0Uki*REo?}j|EjW80s>bek5)vY)Z_mr%puksD4M-dZ0~wy8yCIX869z^YB^zgNhx9u3V z-QQmZmXx`+*Hk|S4zQH_ljjJT+-8ev`-z;)zqPqZt?AH^_OF3K>le37k&pV8rfzZa zITvy7mVk2$luUbyQ;*5ieS|W@2Ni1}$4EBh|V0b1Iuf;?x95V75WS*^vzAt_^tx#h`_J= ztw=7ST)Rw38@^;cW!IUQ<6NNLH^92Gd!|Y?GOFB zI(mbol;>vEt{3i-w0_A%boK-XI~kzc%dqTu$%~KrjHoPy#{eVOnG0<{8j^kDj54eE zcQO0(uD^)s_l84$rvZz(*MBSz*En;TvJ)$!3-OEm*jCqoOeJfJ#3e)s_pC;TcJ4{8 zoPZkbOWAH*)u;0%g_1Nc#^_qlu#{2i>8n31il`gOYOd+^Ds``F%-90ON0@h89|Y*Q zqTu(pj$ZWDuDr5qGRyL;a5iy)x)GBYMET{w&8yNXNyGq;0s!XGJmpXQ_df^TQSn%M=*tdt(mjUzECI?{$ z&DtALZ`5LwdQ=3WcFR<#jn*W2TZVO6uH)99;No*mEO7N?*XU1+12Zjr&X7ZIw(1t` z2t&nuh6iW?dAn>)W%_Y&sh>c8`-#TNoX9G>7=bncDizKF=YiRB8HN8*Gmfwpk-h{C`08H$I66lLfF0s<}v-%4X9{uP2U2Q*oP&_R^VJ3+%qkkHL{oPUd4%PV`)_ihIN zX;`3O%l@pP$U#R-7q2W#cc)b*Rt z`@EK-zLg=5bX)=9W|2S1vZUpw+eCkSW({T=9ZktJJ{Q*xbDK)C@ex-fY=sRvNq0$1|DGR@qS!{Kz1Ia7C zrcB+k^a#IJQR1&Nvj6RK_>V*r4^`$US-7_4;ibSu;!|nhikEk+);@_ks4QM$VM{m3 zg9e^Il<5VkBZTWHN1*^ofx^ez@!k|aFtb+)@C7mEMVd?8dgfqq;|3W2YqP;SD#Fw$ z28=qUyBhKGeA0c@<@FY+*HkWd$KwUuFrckUL* zzi@V9>k|oigRx4M<1Mk-(VUjsv3K(+Bw4gOQsasroK;Y)-F3YG8oQLK_=lDB1Yo4> z(y=Gb5%bcgIZg+GLWW8Ro|S(qN3DRTTL1P>IqI*~tAVTkJ=MDVi~ljzy87GG#G1jM zeVl47_#w=O_=hkr>HqmbQ^P3Cp_cIa6l|a_j|Gk8%z$$?)#^Gw1OgEzdIv)MRxW1a z#*Fr2Gz;+!vDo%HyEoL=Hq}UOrp1}j!d(H=4vn{t;iZTk%_)sc$CU)W zb43~1vsQ!suKDM-_eN4QY^%nZ2^(_!6Axp43&nj98}f99xEwTm*xkF`O|x8*PDT4i z$!JqZiQ9VkFoU@FM^g>vG0Se<<}Cb0w1PhjPbKI@*+_2hwnG~0Cr*8Qo&){TO!lj| z2Zf=h%3klEEl@TmeY5eL-jyMiOdiQ8>B*4Vn->i22#G|V@PW`ZRPhCuLc5qox>f*vUCjfuyqdLHR_Hx9?0 zA%z|sJw1n{+~+wusyPW^gsLgJaB-@4*$KR#A!;220!$OrFoIs1>sn8Bfu9mPNz!(Qk2q8j{ zy0mSq;;cg6HcjGx<(^c6+C zaWN#^X+za3;}5fJRk9S6P^C0?YXnjO_}z7+>I1XiZRMb==Q|BGf$|^%TywS zHf-5QSD)!6oHeYk?qfER`Kt@Hf`h+qT={hK@;iFOTUB!r6i~P{rqgyT3}5_$7I*J9 zD9FGg_Jo^W;$?*TE&?xqg4Uf=b^nK}`+#ceF#pD{MG+t*5I8gmLkK8h?=pqN3StqmbO7itg?|nP%$+A7vJCS z{NM9(Y(BQ^!{H#1uI_!F?|0^rUbgIFLV0!;2*L2aQ6%GB(8kV8$Qg`+gL}q%C*y{v*+dR&jp2~*YSlz0|B+Baqf|mkCJb*SC-ObinU3mFAW_J9~_aM7j?c`47k^U88Q6blMT$^AyfsCmHUL3UA|Gv>qDu^T}Vrw zs`@S;6Y=PWQmP!oTZP)e7vM&xhpIXsZBjX_>(67cHYnutpGYIdK+4bHwsQHzM|zIw zEe=y&i3iv_yx@L#Cq)IkuvHA3X`5ZY!%ve(8q2y4>9iNT^#z$KX+ATn&EYxqE4ix7 z!-ZrvlHej$jwwzf>+2rM8K+5SL#lzYAn2homvko2QX)3sD<(=qM;D1Za4@D)nsJ4- zhc`mAtiu|w+rs?l2ETgYA0XI@zCMI50wSb?JfoBUceD2lf}36V|-P;qKII#bqG7pkNMK{`+N!JHd9!Hs%8ZBVWvMfuF? z!s|y>K5g5Q7`_zVb+Is&bTJksTQ*xzsEb&mCjPklM`i~9(`XSYn#;KVu0*g}uNC^M zgt6-q!D^tVZ!>XZ^C69M-P8AxD3;q}bKO0)S+SXJmDNq@F3AqOJ|hS*yZ@t4n{cHm zbC3qZj42k5!W3|A9e|kG*}18qw87E@Tg;h_CM{U<(^-cd_y=;bM38f48vb^ks>;7E3_F zMT*r8{g@gDjPN?{+tga|f!Kmz^R5uwt;PU|^SLerKe90X!xy(5R(|3?(Dm=Bf!W+# zrFbxjbMU`P7jf$K@KfllgJdva&WSjKm5qwet5h&jo4yV@*|uC|C=EvuB6>z$hp2M6 zK8e?u)&qsz5?LCasYhhloXp+GS}dsl>Y2#`k!dTN!-eMlM?KJn)4211n~hjDCWkkh z23{h1Yck0e-nB^#Y?mXts<#Y|R2Xa3v7&Sxm=Q&LrIi8I(SBz3BQI}#g>Tl}1A6Bn z?w50YK#G7=GIV5{CV}~V7^}#2ihxCSJ$SP7JvUZ&UxBYR6Y4#uPkvu-5LnV+=B8J0 zPC3@IK{N2Gb3FwP%a>!M7n%@s&it-c=-W=QpKqs+;0AFccsqNkI*Tq$r}L&xn<5{7 zMmH78+~s(k=Rl4~YTaGze)()uFgGCp$PwvYjsQf#`bKduQ$5KA$ZjzmkNpH_b@ z62R%Mv+2-LnV&0Aln__Do$t2h;hY^^u;_D^;ky!pAS=%ld8>8?VQ}+*QiG8jWP@g9 zZMy2Edi>YCMPfE%C6}pZcTRM3QpM0nQ6X82X0@c#L`#z}_2ua?Wx^4ae>fVVh8tn< z^a|SN`xw+?xKPrx+>U}r692q#|MW>>d}~+Du)(`I*St`ApiAEp0C`BlBgc zSRwN~n=-D=jW&UI&WTe5@pQSCjci1}Mi@elS3lEHj!Xr#jPbV_hr(|!My4F553?7F zfIOze3fn|o;|w|(-Nb?`R*sWSFQ~WpP7YmzgiCs&;n&^w6wg!q=OviYlo};$?f6NBt1zHa0#j`rVirFLz8>ni~%)WFa8x@o?CmnFE zG%YsG+VW01y`dAH7F;x8-x7xx3viS5v4MxkC&|0p!a2>JJ@!ZIo%T!E*l|{fAe7yM zq(?u_Jo)qiy9ry36}6rtgW3NiCO(C{zm-uo%tmr_s$tKzDe9%nCnKHnu4*u*gkW|e zLOy|DwPAOnIp3NFNY5bTxi(?e<;g2%#BvXf4eJO)EJ}Y2y)d;R!|5_HdI$9L%cO= z>`8PNXQ*r8QV0bUZu4pLu6Ke}_ST2#K1~@e-%C}_>5K@(i(WRxPI{(!$}qNn5IrYc z#4$^mKKqfCjQ18-IFVd*mO)5xkR>mhI%BSb_7(048mp$yD;_zK>kZB-{&ivNeb@iJ@bd9z*MW-6lf>^^zpJ>u!2j>-IA8SlB|w~SedYS+W#0x@ zT$fV^B2v7%F{%PcHvW*@HfN!R)lxfv6qAWL>0`og*qDVBr!1r=5=3TD(svTn)kj9A zI99_+oPJ)d_mWTz9E*m;z&POMcrynxLhRfzL3DKfZ_S?5S z7nCAvd@Z>VDxBVKj6dLS>;4k0>Rd`CAcI>=%L_U?u8uFw@s*v*P6`cPe&nxCQExDZ zF4n+VWKt5nUZA-`cR-yV7#5;p9m$w2Pt=qRPjn(w`1VrSgv&o^WNaB*$(_{(L|5u<1*Zo=G|0Rg4=I)*GAU7 z&SexwE0QrU=&#d!BP^L!UY^=|i)IG={eg~0d*N5KdL0cEL6(uer5(YW6CP(vtcQu+ z-5gY(AOGr&`P5K^%q7)XJy+|om|%fuwBcqH(Q2AZdU}7yihKv+XbThp@kD)> zF3cf#A=d|y@q+kPE#l?;2OCw z?l04pS{MPG1o4GwRa2f}Vb+yWpYwKTvMQE4b%4`INc;!kn}rAwEnLKGWzL?o5Grp! z&f<#wC(Au<^1f+c9vGb7Z+=2pw9toi*$;Lkkb`dNr)e)$=g{=&cK#LQTM=1AN#b%@ z@p97eoU@z7&Gl1K0;3HL#67)M(5zMRQxE34%h;r=`tG`|#L;_V#78xzQk@sJ{5QK( z|9W+G#{CN*zba_CVYd5!pWU6T44P0MZ=+m(7C7ytami9mL2aJqd4(x8J1(}j#&w(R z@9x_9(+D-87S@bPtIekbt=^v2<`>T{oL^a6X?qmKnFey;j3dsZ#-&cXAv=xbD3~{0 z({Ws+ZKB-C1(iv_0mh0+hHSVL>D}_wGkd9ZewgRJ+QaEkqLgH2KbjtCUp%hf7~LT2 zHF$t?vSw(HR(t2G+UOF*0(I5eghKB>cy1o8uQOG$+&w2P6X`+c>qTM-^hSre*MJ-{ zF?9>(z+cqMh(J>>enINnM0rhEBf~`y>YdzKi{Cd$wv`fD!J^&U7hQur2Ruhqnr9}> zWO>!YvQ0_mril|~>f~)Xr?hb_}MT&7OA$XRj*_) zv1O7XO76FuB#29(*KX%7{wByMIz-He*BD2n0?}Wx!xgUu(pzt8!dT(MC>eev-k?pU zI3Wy=!#_lGd!E8yoC^ac+cMr3!UBC1aS2jHPJ!O}IiW zqHp>K7Hi$jUAyJ6;#d>l^U8@(YOWXCQc@BY?7#Fyq*mJwV{m2=T_~?}fV2#0W$4N> z)Hc}D{x?-JR#%J&1r$lCukx5T+?h_4QZ>tZ)vXMp6Y@s#6N#>mW)x;NcgNMaQ4_rv zekw-+i&^Q!W5H#Ax?_!LPB5hLVeXu92tmcx|5wtX`&{A;*-esSLx4-jqVgAs4%uf4 zeIuL6^}0K$5s9kKu?&$0oG07ahXT7Txrh709S8>E!(Ww5t3mh$F|>wwAR7^3c@MfZ zv5?bgkV_BT@8wWTo-bY2huN0<5^PO#e8Pt!6hSF{wc@xfMxa7tYnID|Qz$%LD5Q{y zy*vAaH(TW6e71-{sufi)MAnLLjtG+k;(Co_OlXl72{wTdZ5))nI$ zA7L9hV;@*H|9EJX5!E(lX5^vMtYONhjCw#fLmIMT#Z|{^M0~yNR-W7-P1c*uFpg?~oyKHfz zd;d~%aB$Yyd#0rSGJvtoyG6BF;ADMMtzl)-YZU=!ZCJMI zZJBung+>|?;d9UxSohW$o$VcIr(>aB^}}GZ7uiIjp?bD}8I#Mo_c|N`Rq3iZn-zI4 zb*eo86E0JqkSCZMDVA~=leCwk=wC%J(xcUilfqSkc*_p&9C9Ad!y8`Erhb+**oxFC zcDmu4XFe)OuoDPX@`7?(6+>bo(H0>rEoLN+;e(Nu`LE|LEy5JrvrbT*+>GG(R!*?7 z^5?4?;U>k>~75QmN)ux@(w)MPES{JMfM-wjd_gO%|Lv>Up$! z`kPRK)%i*A-5o+w@#D#qEQL|+|?ZLrMtH*DUs+NX2`sb`!lN6zt z+`8YBs41kEF0_W;-`j8fTe!9ChuW-`A9}(HlIcHS*JOFXr!M5X)Zf2}vzvX9RzWMj zW$)N%-S1^=mtjFalCv*a9=PZnt}nqehBeMMg%tNaN;b!FRRJ;7jgYAo&t+z72~zbv zW$JC0yofW|RhFw#&`N0GlV<8u=nM~?3`l`(_vIWO-SAo<#w69aVm)KxpFs9-rqiS- zJKA!VRx`W+%!&)l?Chig%v;n;XC?FJ?B2`~n>{fBVs?ANsP~)Sj5( z!YatZ-=0INGxaoExa@5<6AMdYvMS%7ea{BThWNlfw`L$YMx%<+t`|nk|AHV*b~?zT0aVnO3XI>AUF` zM+bhop1+Y;{6_K%ZX-mHsorvD^(utagwce#yh$;md*;0wTdwtic*#AOkl9A8HW~O4 zODC^qc!V_#ME@)g;at}J5i&!Y=jVZQzikm>7b~T0Z+>#`6{OVOqbugByu!S4(JE2b z!q7K%HBTN`gZEn7A%`uTi8&juZFHsI z$pUjPAK?wr&I9H~N2V!;hM}VwxNN8MJ!`X+_mVpu?_mBxI?KLGB2`-G`Id*{48IqV z<8j@hxt!hSI^(nLyV$VTIy)AlDr2A7r_H6i=6JN>>gU#5GB&O zZod`Z$ky25Fn3joonm`Jawo8jv_On5w(yv7;ftmx7C)`!E0Sm_<7Nl0zv>9lo4uEE z`_7R07TJI%*bF!R6M2p2%BUwJN-TSsjVgS^9x*Vm(IL8l#>#uB=(msLmYWr0D}Uk@hc!*oind;*!pMWcmGG6@(u(~qW3zb9X;?g7#%lbU=OW~7Tt zb-^tY#hNAc{^h`Z*RY?O5l&WPiV5km(Ck6py{j0>j1uR9H-!X-4UW)CT-uM8c34`p zsYPpTB9+8zYdTPvZA4`u4qTxN`EnQdVp*0#nnt?JccebMr;cGl_@~|*C-5e@p<iA(o8?|bQXj2&jtg-Yc!(GF4u)BIBaXD|kMj5ayZ*34%E|_6o_lR|@%BVQ z0UMsE$b#!HF0)F0#6=_S9jJh;MqP>7R6vX(wb7isA13DsON+Gpd9c`2NlCQJZBrfh z;-9(tJbG{6@^I1YmFqnH>@3s!s!o=A{=se+(I^R$Wn9#qyNbZBb&D64?3MU?98$7E zmBgWLhe9lD4G(Zl>c+SAV;-)V(;(I1osfr-e@;DN+Hw1ji})>e7Wh-nX1-f(4FmaTdvjjz97oL@@d4n5_tB8e<1-DpZ~LE4?aE1~WbTJ}LCB^HOWIc?NJG zyUrTUjjYAlShJsmMgZ*r2W~?^dw~CUm9B|4Uz&Ycz5E!l^X||P|f@ohic#l_OAnKeS=dI8+Gn7>0M+b69Sys)_lt~J2x`BDwn~c6XjC7B|?!7 z1>wQeQNqm1)q;`=a$+CN++CDh93npB#4Gezv^y9b$rg5@NXL*FxrJxtIKW_j_utoZ znK=n~o8vbAOHnnlz=g-ow~tHYu*^y1amLB6V)Xd<+{I`6*0@iaPr%qmQ6xTp-k-VW zwdql7-}ueo3sOJr?ruUO;>u94GEEFzTTd`S ztNl6S)M{Qa%iDpGWmMvlwpe6-cdvJ}TM{;{87pz<^O^kNG>viQs+!=lL%XgTVhIbq z7Y+gQA;C7!T*PIU6A@b7EAs|5LO4hI(k*A&)vQg5bCjC!T-s17OgCi8Er;h2Q|10F zNn+wTvXYY|UGW)>FcgxddX8k2R@ZY0MLR@F^v&Iss&H%(%u`SOOa_rYeziIY$B?S? z)OYkV`Jcw@4f9CZW$H3^Y<7nEs$xb2f(03^XEX zMtT^Tv!G5N`zSThkoyXXZ{bxYGp%E4$lGT#Ks}aKKH4g&RrrWlIztD%S-e)>hPiMf zAh;BgR6Ti!bc5mSds3?%kGmU5uImVWX?ZE77L@@^dE}t-<~E7)Ar8366pPD&CvCz5$2BEA zqS)S91Do8nQ*&~yz>rFrlR$N-(xdpFMv&RQfjKy(1plmH;i0W;3^D>4n3)-e*j`9h zeAJkrL8#f{LjhbfpP!pOd$@4J+ zA%Zygxn?YkGdHy%QD`%LK~xyU>-Rh@e<-RnYrT%b3`H|Wv-g|5;ghp5M=b2o-_B+m zQq>$isX(4Y?D4+K4Op3@tL));X++?k#Qe%&($6PgCY;DvbnN+t=?;(S{VaSchBM}= z<_KvhS$MVVpdjlQdZ0y`-9!iz0;^Ohfzwq;Y#%7T7u2~2)c-YTbT{bjF3{A!gR)+M zR(67NJ3!mpL5E+0&bNWCzW_aHeWwQOIVkoSD82>M`6;OX6VT{p(Az*!2Jrc6r2YWP zdJJ0G2+C~$ZRdgxKLVZSfUehrp47cl6IKg~eF%#G9@P0eQ2%d1qyGka`vGX`UqM+l zpq162+$zv^@aw8MTmk-lz8rMD4D_V*om#N_pxAq$_!3a(Vo?9PpwVp5+eM(M-+;32 zfL0cQatlD)S)jxDpz}=7b)ftJ`1)y`IG%LT>efa0@3owGpwGeM&>KyTAQQ~v_W z0vaKJkB6$HfpXJ8+fzY@Q$Xi|veoPVxBfNg$ye{xhW!~7`zKKRA3>eJ1oi&{H2QPU z+n<4^{vS}*A3!TV1?B!8wEZ^d@F$@2zXM%Q0zFB5CmNOjij4=we+=sUTTuVsfJXls z^mZI*>aRdqw?HdnLAf!Y?a`paQK0jYpzBo7lZba>U^hXr;h^|1Q0Guk{}9k<3h3=% z(A1AWSwWzcfuP&~&~|^&VL#A$GUz%9^u+g_Ixr$A)&~^t4eIO#>hB2}?E!k*9W?cq zpe#4gN>@;>3uwDD=&%#$yd&tk1L%qUJ9S}ppjcZ_ybY+cHK@N8Xfy%zwk2rlFF;uq zpq1vJTr<#iJm|0~=sXT|-30W+_?=jo5h&IW6#pTp^9P{*?}JAF9Q3vUXzF{QtQ(+} z`k-7r&~_~7urBDl4(K`t^aTA*J(xBq76ppe0(I5|_16H6MuOf}2TlDMC`%2r5&_DE zgSNv!hoPYJ5YROh=&|yh`cMU^t{l|#3e@Qm)b9c`>KybF8EDFXLG#Z*D^5WlNkLzp zfDRpl&PhPm#GuDV@4Nv$1l2tNHQfhw+5`351&!JP{bU<7&-y3DoJ|pnm@Xjru3(C(EEI{{YQj0o7bd3*sJo8Qi=rpMA6sYMWsMA|ezX{N&anMi3KvRAM&3^-0F$(%<1oY)F=+F@8 z91nDD5cGK9oj-^6gX;Eyn)ZS^^?>@l294?l{iF*tRuRtq0K_7L1zHA2_dI>t$ z2DOKQCZ2@(93hMU+G^!c&lP1uVA3*aTgH|+xK577c$psyH1Ukn7 zU8@H@u6ySP&{|O4hoGk4gF1Z&>h~>Z)Zaiqc>tR7SJ3<#(28o%M^&IND?x`UKKR5u6IG#k_@3)C+YG%5r16FO+hU!?KC^SNPuy5#qOM*a~oxN=gjcT2Nj z1Box*D`oJpZ5k-!aMkm5Z<1mR1s|~jI^8ycP9eHFs?QwI(Ovh=sV81uUgut&UhQ69 zm%txAxW)Ts4K@WWHVrK;4J{1~4XyUA&q_;M?Mq<;_NA?@+@7AihYo~`H*#2b`95O2 zZNpUmb<1SL2KwLoU4Jt!mvZ_V7MEiwcTBOsX}HisOOF47hVU}<$V8SE z8oWC26dV26?JasOPu9oGe%O08+a)!88`ok;epivTfE-YCB(5WOK& z3a~n`0uAWQm4Cj2^blAiv-gmQE@4vS){10KmFzL#aA6)I!kjC7R|PtVfAKfR~CFnim3cz{I0#AK$y!&Yz7;J>8XedOan^~oZh zPB@0|I%5`TC-SQIpO|&k>Z)wQBxPAGR&rJqnKFERig#Y^2lTUlBvGo%|Fw0bT5$y@FgkB8g6*lNh?S&iBz^QHNrb6wTnK`>ip)O2~k1D<(tmUhgd4M=~=L1 ze#xIte2lz=iP*9hFVc|NXs58@!6Gw52Hlpc76^z~o!}~*&%JbB4=Fzka*_@IrG{hj zi^(p5^6kh~WgJ4WMCazzjS@$KjrZxb_K$xF)M{xM*B{0oS#CQx+=~dc-+w&c?1d2u zv!ynZmmG+9Z*Ol4@cZ4{F;F70u&SL36!h$RELa9tCf$)enJvE_tXa~se3D|NtDp9u z2_r{e7xV~LfLMqPrFveM{|0d7!97+hv0$`yJ?bdF8p40=qS7!Ps2WyUA6q9QU>;@1 zqmcYdE8z*IVV04bImJ#h+uo3t-X@jhdf&Y8!~SM-K-iaV$+%%YHdsA?md;kQl;sG< zvjB(-2}weznpD1%zP8O?%#+9sLdx4Ny?-K2q~-yPeRcl+`Zr^69mj>9g3I-^XC5x! ztb63*OD-Hfwq;X3I$*jTTncmZ&Of$iggxC9_~Z|4?CI(BXe#91S!dz@Ue~jb97qL} zr{tK(BGR}IAun^aFRwFuop5xC)-zZ0DD_ftpss(lbs#;XKi~lmFc3&aHIGk*DQ5!n zbuf`^AEhECo;#~GIEWkRMGofNs);VsCo&M8N&KUm_Ni}y*~WP|=5qb3mCZor#29j6 zgv1|!g~^4EbEJiHv3zhfSD**4YW*j>(VwprjJN~C6Oz}&gDWLJ5bkgesb@>NF$ZF~ z{-mm>5c4C$o$+G)Xh6@`)0-&dXIm*$%j0ORz|(e#6L*=PRZaarE)r8|{Jk*RBj2iDgw>>RJ zUXXYXdHEz{n>Pp1QAx^ysY4nJs!!d_Zv>N`t;A{~SwBt9LUl9Wcdj=kLx?(=Fc;20 zDg4Hi0t{Mi!3npTW_>3v-hOZk84G)$oQRjk5zy=J$zdIsUtr8Z*x} zt(@@tj^j%9U;Ovj-)TNuZ-AKU`9AY|X)h`DdTsbKTG4#)%lexi4UyGMUeaJ`z(sMW zBLWV?O--bnoeWNOYUpRk3zDsXt8W>yhYY>!?xZJL^dWjieWq+A8~BFOa8wH2u9U85 zv_lqiaj~wmNBg7yn1^V_|D06!{&GfCYA)6bh<`NDiM{b*rvH+Kf*PdIWI=KlI(9U$ zTPv^Wj6B~@BZA6So43W5Y^#uHTvF=?rd>xw^4JW`xC2U%icm=Xq{XMjKw04 z<_^8iUAR!2ng^eIr9^fT9z`~xckX<+9LIh0^rW&$wEp@RR)1s$R=)YLYi7>1eDnFY zKLr*l%(z({Q)hO-Rb;QZAalz1%a8Z#RtK|Cp)pB`E-M+bK?gMHQCAA?Du1oQ>7uEY7M{*z4V%`K}iSr4Lnk)3k_6 zeBfOxVM+RlX2o#qX#voDiRzm7_C-tcVLE$^2y~hqjoYpu8FNJ*Nhkc#2->M9M z?v=S=@!rvSX4LBTTJ1KzRxa+6EC+T<&mg2FS37RZ% zt5yP@Rs1vZ&X$IaE(G5-kET7@j`okg6O?(D zS)CsJcsoizmTYD9$ex8rx4LB+X*KWso5M~h?a*pfC0v#%fMlNk>zzz4l>u+SNp%%_ z$9+5R0%%yn?s^Cuf^-tzENRS^s}d6|ujfzKY^tiGfCupZ89!YVKeyVasV5qI1&p7D zfa9mPE#34$f}o!cJtMTzOJHGVEs-c949+r#%-Q-+o-mffMl!=)hItPMhxu>mXiUt@ z;ft(n#fV;?61WluxsbYUKNRcad#OI6X3Z4zdT)2;$Q?)QbR_emDEV%@Z5(^`;(YW_ zM7`93S%vi!dfa;;cg7P{^dYpn_29psLUnH>rT_BL?~Lh(Ux~8=|5S=-I@QfIE|a3E zEtk?mpDUIAAc^R+|FD`|@9DYz)r(mY@S+S#M1I8DyNT^wm-XNCI5h5z71y8VwILx_ zCInb!f(sBCGXp%TzOvJ-8^%V?YhTIWPrPN&{j}0;bYX##x&z;GCDYfFVuaAJP3!tM z&^2jvA7x6XKidXfyI@#UK6rhH0Cx$cD>!@WdYP^b;6oj8-{Lf zy|=YCq5_WBRbtg7-s{C|{PkMh^$d5b+hbsX=y$J=d_p5E;{NajZEQh2^^1e73SW^f zw14TwVJth{fzlFPkV*PxGw90~$xWmy{RJh?$-|OF4o+}9#MsG_vg0|aj#9qxDpH%# zFh$;!x^pW>hUt%Yqg3f;TDlu={`>Xv=yN}XA7mkTuzvaEfo{JlL9B~j)q;@AR)x!_ z;+Nh>hETl+p#r;UiSa&P$a5pTnZgCYzR$H%@e+qHyuwRhvrs&gW$c83@brf4M5;mL zxcWrG)$+5WPfkT@{)&e=T9t<4mC4g*Oz9>3Wkluy6biApG5jmOEa|E+6EAgG47~T# zgUZKpR>bah(`g**mFe~)VaOlqgK`sA^D=jpEqm_uvGl~7Yp;bds`Rj!h&JL?uFJAO z7MmnqwX8L`d&J!|Zn$Z#ik!8lPs{F`!_{tL;Y9@_MRZe#68hrTO4lcu3qUk&9x%6G zFYWirUedthA6A`8f0;eA8MC1rx!N{Z$(e*dk8pBCVrJ$o6<86EPr#w5;{iBM<$)J_xpJYS z_iMf^)3M5C zRy#ehKK^QOhi8S1-u+vigFyvIwQ2$YaQAWf>U__A3=zHnD5gdb>ko_Qo zq{J!uEInkFC``Zy<>lQ%B-ldc1Gi$RPBp^9h=S!B<68!Sy}>OP8P5e#|7X+wZK>e2 z-~4NL_0Y4Ak;(N{RC9jFm$Zh?La* zf*O%s)jn@?M5=0XX_WOv6zB$LjZ-4mZbTpt|FlF*e3@P3J#m&n<{H|JwxW=e$m4~8 zEx~5Bt76rYFIG^UcBI|#Rj0Sf6XGE+cQmRjX63P^vm7#pWiZa$lupU0Zc`fPZcKvG z^y7Tu)@#4R%Pi{lQVzy)IdKmEB*xIcuE%2yel8Pfi#10!;fu7vxMsL|O6DYPE(EA# zLQmaUnWM{X#W(K1fjuCZEV{;T$yFJzg`b;;8(3U|IdLIFj3X zUk4mmuG0nfK?Fq*xX!x}y&t&OA$l}!ogE?n2Vf!OJ0QdN?`G!jLiE;v5_rG=$?!$O zATZ#AY9Y9rQr@C9#M8}+#%0>xgm}Rsi!G_y^z-_hBxTZ}a9cqX?ysr|#uk=ovNrd6 z{_>@^JjkW7vO&3#Ivq{4f0 zLuFkBV<&(_<&)cuEhrkuCA(T*HPn#Q~E6#j5HIX4|bZLbgx*TYK8e zW{tCJ<}3YN?Yw7r&gHqd{zz{U8}_!xEp&Zx{aYuF^%2)1i~ZoPz3Hpm#fah$TMILz zoAFO>R1WrLdB4Y`HYIE?CYO3_lur5hMlb));fc)<*~cVVB69q|W}w-odF_|Ns385D zF-ukZ+w;OzSW~TK&HI^lt6}`Wogb=377YGVJxz5>r`-xREZ4a4xh>5f3R|<&;Sj3+ z(%i$WzqPHUSH3OX`F+XTSHfC9WLDnSiwPkiz9QhYW*y0;BVor!t}%@)q67wUc1^>bK7mv+HjCemh#2zWMY>_?FOgdHxe~At8X4yUp!Rm%Ub=E!YO1sbJNr0pZ&lhhD*5kA=D?YXT#jlnRhaMHJFBx^Q89Mrzq;E+-(C9zvCpazxER(P!Q!l4EOG*@XMRy)J#J!l8DBh(d}MkNF=t(FEmjGcSj|+6XnfPLC!`r@ zFIXy!e}1r*JCD*8H=%?pSDw+Bkg+B6H$lcx(S>&wkK!B|wG?=Nb3dO!OB)$GzYL1P4Y zz9qxEs4464im^gk?_Zzl#CPWki%xemaI?!s1qwvJdZPbHu~vrnQw#XGn9K^~TW-qK zMe0>)b^8agKK|Kuw>t+6W}7pb9~Xc5`M)&h*^)cN-61d0jl-2> zXC2^_$Vqf>SaJ6~QkTfi*B72XlmnhU0X`$Y!oSN=r0y z$cHpd++Qd_D!VrN#d0r2Ucspl@%=gHQ2ogf&iAWeo9zS9q<#kSY}*cNQVMw@RVYNK zt#GDg9md=&`B<9tI4gQXu>^yR8K5{GWd&hvjBLw6aqS1rLKC?|GAu=KP>Ru-DlKJ+j*A6K;-V~d+2nVTCa=s%h16smV}wx(nUWt|_^vP{ zkGmFD5=gt3$HNy6-W5~$16j1;=nlpH6{GS_9Es^w_u=zRd}gZ_JeE~m zG^A_Te+^+$kFyn01t$Y~DKM{o`F$y7*;LvtoVX#cJX|b^qX%snU2MKawg`5tjiIS1 z!rS$WXc7Ak0iFlVLlYkEKyVrvR`$Ptf*a_D@9LQ!B?G&lq-Sx=afkbQ4ZtcgjI&W# zY{Jce$=xRRE{SOC;ewNFmL@D6xfVZGX}2%kBXFrU7djf7h!NC0QE~oE?=r?V6tZT) zs^5zeHL_YM)}t^^@}%W#L9^KdM)2T)@I@X8&YW3M)|2?l{JFWkL7{jcTSchr;SMEy zT8!ZkoC7v9uc%oInadl0Huz(B?wbCyY$EXzQvUaB3L9C4InE1E$+XlBe8NejGk+O| zmR3FEg4#bN@i0`Wx3Wwes3jizkmGq7&W9XJb>^fC_4n0zg+1Y@kus^v={PY9c>ZfC z7=}oJGrQuFZbJg=HSg`1G3waSmKS~K=uYF{kin2e3eG@>JbG^`BG}i~0)~6d=bjhi z@Nfnh=McfRvHg?Q6Uk27K7nLg&F*>Y)6B+MDC2pKBhHqOymqC)_pvSGX;JZ)Au(rbkRm^gw+IgN=BY`c?WzbGIWgfn z#xiFa!^3`)e1}lluG7#@jE;CH*PFVuUa5YRKN;;Z`=uQI#m8NPz1oB4T)` zMokjzx^D-j;}r=D7a_O(Tu&c_c6-3db7;7Ju3pqz4=GX~K_KBpehZ}F#{gS@;6b#WEg#?N)u8-u|u6aM( z^V)e)xqg2CHMQ#9-rsn-d$QyI|K?pf6du4CO9*a*6|gMtM`R;Jk~oe@U~)IXYS&RS z%H?3=w7|+N4)4qySMF}NJu808hBG&|QO`sq2J0!17B1r`o%ioW%ovGLQWrTSxZq$^ z0`oALap@-AT#-CnS31JHn01%UO#7j%D9CF{c(QL2#H3d}5?>!`-v1>Y|8=Dxv-@xL zU!m_}FR~D>O~pj*u=;=+0^)vR&^B}4Bl^Yo)2wDrCM)BD0x7N3NDqU}1mk@_!MFw`O#n7);DNnNMTPt5@ zYtN_57iR#~B6(_|R``LiySIP&2jk%AL}0t|ZZ<6vc#?zI7w~qsKCjOSVjc!olD`|k zMZem+ahR?#3v9FdhgoEH2|fyJ?)kzheQB}6yza)9`3f~mcwwRG7g(7PmuZVA_H?M@ z&;uY!sbjc*30Z#tQK<%uuD;fwQ?glDs^rv}xj>G-ftOfY)% zuKnC!u(+))#N7}NkEJF;9WLE-c*_)b#AKUQzdVc3II;VPSLo?o&c#I8_D=iQLU?wt z%GQ1Eg8_$LGkfOto$)8@ZvXPHENNQ&t;inc5f+w<=)o=8wS63zTjhPBYk&T_KP8e{ zAERt1IpBOpyz5mExUFjThsUg{2XD;(q!iirXT1r1oK$`5 z2vH9MU3fFohojEbn;{(!lqVsh{l6h@aCE;i5d5(^ z;InV`o^y;s2>&KkG4H;t-I_ir?yuIdGr*h))O zF2YUuuA{fM`?JF_`PQ~l<}%n_7Cyi~@f~{@OOnL%8>XeD@8rYsZ`xjaK zep1a|Rp#pY@{{F{9{>+BnZGD1YS=67O<8pn>Ef@Hb(z0^7$rt4w#a=ZeNH2{ja$>; z_&Ul4(P!g1S+BV`W*yO>x6En!iHkP(X=Xs~-4DZiA))Kmu$a3EPYa8&tJR!=ou|>g z&yjuBI3Uz)BH$@L@ot56V%fT}dUEcX6s5XR(BQI=Tb%^JX{_?_!u*k-; zu-YD%L)c<#Qw%+G%eCY0IuQeFO$+tGe+c|ERI{`&JpUwbQ(%&C=tV#cuG;o9{F?v6R zn1@&kD>(0zNqnL3+@(cWamgx{xPW7hygl|!8H%4Q*;L!KFrf~^z;lcK zq4hja6_qg-x`x+flhi5u?uF+calJ1cULPCsWUZA*8-5R6F7P@3AY8brZzHbPv*fW>c zvv+w3Z)QF|C;X@VA;h!hRuBYY=YOT0cRzb%P$+#2dHO)PJ1VKlKo|SOO-=`J63`og zN3tm#$FZQkTXjG!yK-AM*=AixLnK_%UdA_GFJxv=ZSOyCBANrvbLooYbEhQ!vLG|# zBC$IE43Rc~;_kDHtKzzjqE+N(&oc*Q>}kin%j}k`@O!mV{yFN;F#!e`K6~&aLUZ7p zbO`DB8zBNwm^+IEW|}P^hzKN_wh;W-m3`fk2P8S(oYU_sXmpjp=9zvrb?k=kaL)NA z$Htd?#=O*1{VPsq?+-*;^Gg0WD&{=4ddVlN!zq%G29L;`LI!SrG$X%gOq)ZMn_jA^ zkq`aQ&cEVbJOFe25zKy>MA@cq`{zXWccT zFjSK>t-IQs-P-ac_i6FHsy#EO) z5E~N6eF%pEt6|h?#*aNQU89YSFm&({`#vreox_TG9g@Vk<6&H=lU@C3X5wo4*%nb} z&n_aXHkDSp@>D0TC|^u? zrU}}sz7!RRqhk0={N{@PkEu70W<1aL|07`pkszwwo5CsG(F9s;En$B$gVgEI}A|W@NFo*piT#Aj{{Q>bdv+ejkqG z9RD~c`Q-C{zhBSC<7pWtR*@T8Mm1eS5Du)v;&l4Cx3DbwC-T0mKo|T7K~{^7C2|ll zVaOZ->jg4fgmECpCt5^hdzknA7C4f!p7YFwRS};y_L=X4_bUjqKgIs1b_GGZ`@XxV z8_`+%)2f_5*hT;Esb*lz_otd@D2R!M!lZbUIb+6h0FbpX`g-2{kqd{_Gh@)xkijw@{za*ZCeM zddq&CwU;}KVl_5?f=N^pu*9OPpg{I_snd~yH!whr zngj8;q&cHg0JNrqywH_r$^j`brn z-{=^JF4I+0D$v0km=k2ZL{_e5l9nI^bcKE<@H}BACW)Vz6y{@oH$BlJXNIa?NOnvp zmCONsi6r)(?x7KZk>BERuD%RVqjcx)Z?dSd$^*EGFO>?2J7CW@l_MXSa}=@!ZvOs5 z%O^*h#WktI_^FXFs&=x{<;4%)g+XohvkG!rcvDO(HNS zk}XQEma8Ru**F}(NV=t@h?Z_3L@R3klXE~{xi8ti5mTjEg!(vT0?>JSsLAkpda=d? z-Yl7&=h>*#7tlueeOM?@v@U&TfDGl*tv=j($JtlnK4y&5l55(tNcQ$fE&tKW^vCd1Q&|S z*{Q(15v}2{X@40}x}X50?_GzeS-^Q-O#Y~eH5Gj}FHY!~oDPf8`z_J_a>O^~!}v0`3K%!8IHV1I`!LZqvEX^yr<&uvyf?Eqx};aY8&%=9`d>E*aQ)5q z(#7{ahEIHdzJB2NY4)%Fr%L?mwC2OKixOHIZ%=Rsnp|mQo#q;UWF4S-9QSy8DZ-`7IG1wEx(YOm zBtIcsLPoc2@7)*SA7||f(q8Q-thN8=O2`c~^h%&8Ox@02YjOs=@$NY`bR4yvXoOY! z4UJp3@rfPzS@)*JTXB=t?R#;>_HpIkMIxFM-?iBss*O08_i5$~2lB*TXGi76>-eMo z)u^q~KIc51d-ltT(%n5p+s8L5`Z%c}yjt!D-ZEQ1P$aj8gisW@*lgICKHJ+6G|{2ZT(s0-d{<_9!s0X%Jnz;(qy_BDS8nJ4?7lu4 zi(w)>Lp{$-jOK-689kgXhZwJMcJBMH<(%p>^SkVIVxM9LQu2+AF2Pe2Kf@grnS*Fn z5G)(WQ9=m7^n|D`H;NobO<)J*PwE$S(0;n$I7F{|PlnVI+L>!YLR$(#{(k_Jk8hdb z0~}3n9)!}-5>OyrtCjZ%6t36?B?m*PtGgjOI40<|_qq!e3~BJzA>(T@vvNJq`}F~! z(Jm8;q8lTwfOUmy!lx%nhw-oV0z@|MlKNCbU-UhQx#o_857qkVa-!iBo4b=~XzGU= zVFg86%0um;Ma98!ehHydxDP(*9%+_Xit95XnN?cwP#pzdG`9ck-BJIST2EQ zg`KDthEyQ^8=akty~%lx&Z`Co8v32Rs2JwT+zb54^@+H_JfSysIc3?@qA~Cwc7>+T zp0otPU~meN$}?4Tca&_}g-k{`->ObaccG^KQKUa{`uTH26cR=|`1%{ciGT9gn;A2{ zBIn1Xdh#|8hqb3t!|x`#B%ytSGnYq#*WARuF&-4FIO2>oBu2OgR6Auo_S{S~Fp={Y zCg>IV-7Y$2OZ~rE?kSsEq!!6R{Y*nQ%h#k}1!Uv4%bMyUbGj{c-FBu&@{{wbW7G<6 zX>VtR(y`h@WsM;5C2lCW&LlNd%DX-3z zHPt+m+EWSJ{Wp!-^c%IBmmfwT8@{@^O21N=@1J>WzhCnl6pP&uI=@#3urFvl7Y~M6 z)OhLRIkVpeJE$~j&n@1z+ASn6ly%n*8z?Q!?I~Pc<@N^#Qf-X-3h&hyE-uJ z;Pg9a2ed-m4Xc>Qos;;@F;1RhA+JfQXRiJS!F=5XP=Z)#qk=#1kUbS6WOSI}In)rQ z@8Yb33(ou$XG|zrcWHzFT0a~Nip&)*1BPl3&UQ}*)ZfJrS>g;|PTwE7R+SV$z|oeW ziX|>ooP#~8LwW2Z$gyA!p&W57@mugvEM{KY5K5JX=uT-3!j&hs0hY^V`PJA22yEeU z#>D2}0%T;s^fUlB+5sTa5uLjRh3gmlvN|56+agPD>QgLr(1xHDgC&3FViA}$v&7wZ z)kcfZPy_rLqrwQJt?Ho;+dkhtqbknY>Gtbd@jMY8%JT_^O#!R|>dADS)nbKOUICM6 z&VXu27UK+BQT;l(oZON7NoV?JbZ0=kT4y(vkk!7M*~9f0hUP}~M@i*f@79bHUAX@H zH#V={oT?C9$&PQ4|9o=|Tcwc8YS24B>GG8XD+8TsMIirMmNo*X(&{u8Lln)j2RWmLxWKn;LybnXU1-*0FFeLgog4u}zNA zRJjquc=qkC?eH0OVK#Slq9@W8%U%fz|E0~c0cvr2L$--%H!(o-%)o+&g1i?*fyCUg zS{dc|W=A`fZf?!Ce{l4x{eG2tNqtHLaTZIeH{q{0y8ug-2`;Cr-_U6fauYzljsFdF z_^x-ZoxHj2!tbdtlg6Qmg_t_LEBwH9gEt-Eo8P*20?~#WM(p zS01y5(CbDtVOw&23~HV*DrcMiBj3EBSGN-n7J9eX4arHk5ys^}bQYz$;gwAnBqb zJqnQ)Jwj(_OxCQS?o&|8F{a;%q>k}f8(l0f*=W@5?i0D3s__-HC&=!tL!tf??lbhG z4eyvc!~y2x%{It=bDK+5rNqJp%>(7;JPZqte8ht$7NdsCN(zEQ^i1pp6dj)=tUWU> z(Gd%54KA#*2vOu>-m~Gbe@Jp(CNJmYT(Mo(xK;BYdju;AB zVi*Wv7rPPzG{9#1m`osn9e>0IY|RsHYrJ)p`i__;r;fFJ1&eTzT~&GA3iSG3A1 z3-1-d0UnRxd;HcxplzJlPAd&fPGl6Qy!eIDmysr|lGKf)m$|Eo+Q7i0+be7Oc;|>= zI#03D7vZlF5qihc4$lL4cJ;TVrKEkG(9*>fkJ49=%9wZa6_4!4Sp}G~%DLIH>e%f* zp{N0$S@FCoj=4s?cCiw%&ecRyK}h4U~Tm#BiE5bx??MnFA$XBc1ya%Ja} zxUR`jiLgbSezn(8=wNyeoW1x*G`fg2G}pK)|IeS+v`5d6O4eacVb`M(foH@uXzo0D zIGI=@xAh+NGr@S`8GIA9D{<6>b_dkOj5GRX4wQJ{XZ<9lgux_o7VC+DnM&F4wr;6H z!BXfQnt8BIK~iWh{PnrvTCwg+(8n_l=pY@aZrL02vTGPgm)ySCl0)b^AeXI%ZCr*y z*At_g$Y#uZA)aa7Ef9hT4f{lUL8i2-scRV9obt4WkU$ZSy20kFJOlwFV@qIcrX@Ic zSYo>UJD`Sz0GYu)4X3=o=h>N7f3fckA$jTfH> zDluF?EAcIKhZch5yFYfC70sSj(_a4bAO!h~t=QB%@oL!6lY4VF^k1rzG%Xb8+WAVL zV=2bF-dll(O!_{BL^96&C2c>p-z2xKOZOm8a)sZVGbUS7X*S;KzYaJ~4BlJ@W6Ta7 z|8S3yo}O(YpeAV)MRdkz?Wo}Rk*k2@X?>}t9&%S*v^qcp zR64rFp!w+miWBa&$)WgGK7-v+D-cg|V1Y)>30-w>Vp7SEj1KKn({8eZ@{i`#zBlp- zSh#R#CF_x`zRca*=$^c`h_Q^tKciHwjWhTzwikZM_x~wetNJ$Ieln`kG-8RQTvTTIU{J+iiW;JPhs?wFJ{#{T2+J4cBv zIHS}yxvO;Q*&<=7DC5rQNmrbn!Jdv*GkpQlHjtxiluxx4T<-Q!S}_|(J8~-dNpEj$ zXDO}p`jNwl4ng=)n2N3QHX`=KBJX?mW7Qt!Sl-tEEHZaUf0)~HV->9Z!2aX?d=d!k zuFrU?Sgblv ze;H&mk@<>7fwVdto^c~(ZGqU`u!GlZQCj-xG^SI4+2^I6!RNzEbTs)TGa;uZTcr7+ z{abgSD+POHWr|OZxJtJG09nD6AVpU}FZ^_iT@~uc9>=?)4)DTXj>!;18WYdu>h%Nw zfW;eSOwRiDg9GkD5-_qX$qUE+y>xWIrLI&iAFcrQ4#|`DWr&VPq>sn{sF91T)tCD= z*iz0N^Z1w*^Sfc*QQ3l2?Kd)PlpBqV@z(B(W8|{J6UoA4f#baga9%X=kBFuy5 z@mJIfyAqu}o->CzbG^1=;&JBMfXLD4z2oy)GMzV>{2Iu{SX!JKXh?URqD~UE39ffn z#U2#wO*l}(I1Zl?Hhx>Tr6Po}CCMmiAy`F%d{_uUVi>`TK*Y2B|}ddL5O{4U;J zJAU8Qj^DpONds%o(ZHa-@VxfaHQQIFTj+^(`x|=P$j#>UaG=a$YDTa5pir8A>yR!^ z;6L1?J9q3?aBeRIl6g@aH?1$}IAKe`Bi_UBBN}|e6uEK94OXd%+v!;yI)~_rPK@c6 z_4cTBTd?(~$AYvltN0%$9e$b^xtpJRevsu0E+*H7|6=_jr;9t^)S9i{${;HFoWA-L zZZT6lw#~aJFx9b$S$m0WJv{zD=&g31#1w^I-EJW&9nXd~++X8Q*7+ zc_ivJJzai$@KtuvWOlZj%tMMxr7qM3W*`YMHadk`)iLFK&xRPPvY7LY8;eS>-%8XW z!L&WM#$lQ9dg}erX@3y$g|4Ha#oDMqw!=_l#Kim5#z2j8BlzhQ(~nwx-e!MPrx}ce zCG?gbd%v{m9_sFUxYlal6lwT@(@u78s*7d2OGCF|Pv?{J0TFSImB9dwm2QWq*JY`w zv+SG!2qG*obn2-x6Te?A58P>ov|m*&hl?sIDh9;gU+3DNu^a2hb614;gOLJi*t!q5 z)&8#cc2Y2X-6rW5t=3uuCav|ycQ(&AtmgOgFL*gw+~b(7D78RGlk&B`Ky)K7*%UCg zXzuM7UUgTBmk!~-$mad~X3>6l%4mFAtc-D`@@P*9yx}JycLjMs4=>Z_ASYRK;Wgzt z$61B5vrT&Xe;>nFs>(Mqt+%6eFmOk)>+I&i-xUd~ zZ{16F_Coc4-9`AvJ5Gglzp!P{cDgb~^e~qBrzhg7g?8K2zdJ(*p#7gzo$r;1NBeub zD^Pboi61ozX{vyUiCO_Ha`9!enXCTjPe42C39) z33%Ar$z+}g08#@Yu~Nr95FgarPNEqNQacM%Jw- zYkyRvX@SKh$NmeKM)UPH$M?KTlUBE$$Z2;vEqc$p__k`X3ex0B07dMe?PZ}&A!IUE zgPiOVGF1>h?-YEj;T2&Nmu)H(N*ZHn9*$T(hTIVZnM#^0mzE6MV5 zwWY-r8a_+T-Wp4#tq6LWn%cT^t|^Y~9gp^Bl(}y=dn<2K%@Y6Go}0b(RdQ3T9JQ2# z8}u?4cQi)$W?SFvmsHRINa46Lo`1vp$H znr!F5TfcV>KQ)WU_la$3dMNLAP3(H?^v_vmYf1Je?R)N;ie}w$?zNk?$U*zqB>&?q z9d48kh3P_uWkd6~XL?%XM$H4Jx$TC3v$&F0*g9+|^Qf3R#sqpf@gGfW-%5W&C3jZ)f40^ldmH+7q}7RtJqs{?wtTDxeEDinU`_o zlby7cm}C;A9s5lnROt(s5U9?o8`zY+4y<{Y+x110-1>F)dRR)CwJt|81F* zI?hi?y>9_N>c4n0-jdMz$jU#JWB$9e7LJSH*il(7J1P{Yg<4r~42s@KG0Ku|$9CQ) zc?R_`9K!!*+ff(3{aKEIt?lI4NmK71 zh=t_%j+cd$!F-q0!?S1f#}9X2XXJ?XJ05*1smqnh=WZXajpaIR=Cz*rxN_#-SivfdCd$+Hp_70Cux@~BRX+@-A&SqIzh3@L zG@uq3fqSyVcCQJ*)k4nfB88LfLiHSC(fZfrPD$~yuQRLp>ea`G z%0~{Tj6%b;cF>x`Nz=DLZeDOxR%?U<`99{LTLYk${(6M~Rp(T0jQfN(o^@zi4ae(q z|9zWr>2A=x0Zo)%+HhhDb-$>Q$J*zFnX8mpQwS8fI$h6yCimSK0^xlf1CU~BEd&S{ z$Y%YT_s`*+#@{B7XRQft;_c7Z<)&J>x1ABc$hwTz()G)j&zNO@c8VFhYnB+T zA_?O1{2%$CO`Y(LgcOmB^)Z9ZIhm~Crj0Q+Q;dJSwVjX}liwWPpNjul#oPD-b!6Un zAfU50A*M4X$j)dpcB(-aSlL3t0Zo zu5_(q+lF3!H(j`5rmy}@YrMKiJ z$!t&m(y^M@^i4kB?(~I)0`}KNO_b0d@ik-O9LQP`EDakyWr`PJHE(@;g7!P?hw?h5 zckHe}vxj=?zIBC%)$M7;w3Pc}Mb9vTd>#*)B;#(SDspg|o>U>ci{2F;M&WNRTgVT*#wicRE;OJczKMc~Yz1#lfMu^O zVZl%1q+?v?YgB12oXIa)5gX#mOp{#33X}Shzouu|MbNS?4_YVg`hY))NG-~B0~%U- zw@XGN(67W#z;zzy_OE_?e0b6>eC%M?Eq1(NY|;pv1&${Fts*>;r(==VNLmoOvc~^P zDnq1TjdCEMx#>K#?6#%=ESa2MnVCEq1QL)54?2pvZa!C3MXHKm`Pmw00Y2@4_a9 z4BSFMm)(bmH;x_OT?WHjB_C%e4iyGC{t}XIl@^p$8*f*64{8(u-$6sk$UvhEFhM~K zzwQfRCvJV3ETM0C3(^mRD(@nGOYu=>ZwaowUtX6rgGzM4*%m7aU-?*!%`XUxF(p`R zU90^mRe?~6`il_44@|?$$GNSv=%01hUupUhd+XnYTnXrHf7oT9y*D$&0{QM$VZ@XN ztys!axfAo_v}dJ;KGB3XAZSMI=IKsHOfZ}s$$k-2ROzddGqAWC@X>?86azkSst(n^ z4sO7fIVvsARF&wb94UeA@FNCMb}j1|$nhNxQ+kC(8U;+b!(%C5h9QS&;QG9VtXDeT zH4Q6qKEe786etA4w5!k@e))>9FMWqtgMu)>6}M<>dku2c+q||geqN!d-Si*pzu(^a z$7bSHCV!&l(+>t^)yN3$HHU0|b<{UFl1-dn#pstzG5g?{b)&4~rO{bi$|@?dh|eQA z{FCr7CCq0YGx&PPr(f8v6r=&$>MSI_N6Ck7M1gqLhSN?;)eqb#mUhF5FsAP4FeJVt z`^zmsf$lMFH)->XXTO@n; z9PF~MJyr{0sNWf6-yUh68Q>YNaD?Y{jWbs>D~!YMV~nWuR!`X=H{Za_qJi<*P*g?E z{k#{ith^&r&AN#k_B9zAgthG8}HiyJ$Aml?A() z(UC`$#h5~BH)8JTvwbnbRmCz9n=wO}Lb4^uRO3M(n+^o7lxa^GB+j?fZ#zNKho( zP}K#UKE}~>_9?iY+X9CJdFJx7380LMS+ zKC78{&<#e85LkV;0~+NJ0K6}|(%9Gv+C5sG*st8*uY^#EL!?liU)H}?LcQO`$Nu>H zmC#~%&sBmplk#j+n@Q1DxrSZyzOQnftPKD5r)kTp0Nf3=6AhZuMC!T!s%jRFa)M+l zRM^h$O_Pw5&)0R#&GILo)BG^brsyuPskN@A(f(DCgR}L9V|B+#>M7h@YGRs8fugcE z^Xh|P{hnEyV-|tKi=mhANWR)V6BNB7triWfBZHO&2sx%MWuKsc3IH`d4+gs@EFcm? zpq_S(bawPzPpjxLiVrjwl6}s`;HQY!V9L1N)GpRw86+nO2dFZ~ zOMR&3?p&NKaZYV7xez~DNQE~Lw)V()|Jbj-esDh?Y7~;K(IZcG3T7DO)TlfA<+pAkBs*CXILzZ2?-CG$&I^o6Wr4*coyo3rfv30zQwpy zp!+9JLsQXUeN1Ft^Y@K28`|u7;`DSas%oS9TJJqYD!lVQN$E(!;J3~H$~j&4J~Sp4 z|GjE)sA-l~uk(Jz(_dCyk?k7?LW4lssFUrz8iZX;pjiZN9X3K@Lo}d8EWs}UU5ulLsP`>GAF=-}wC=1q#>J8ew)#{B?Y{=NvQ3Pgx zpz6cv^Br!lcZngoMlrh4H6Z-J{=^oBqx4Rv6?%DHpmltUcm0p%_k!X*Y9cmZ5e%VG zMkl)Izl%)_!QhJVr$yzJRU#KyX(B9WNDuNM9C5YoX<%&YWiC+30FF#sFX8q#-uqf9 zt^J1gWa0g0(nY(O%+2cjeyOjmy(OmwykF`s*8NXc@qfR6gU5trYawxWtyN#!Rct_` zd71CX`rNsPS+KQ-w9b33PhJOSHFC=SdEc&{F&*L9Dh_{96PuQNH-7EVzA--RFZm#E z<`@mR1$mif+Y5*l8yOO0|U=y6V^w!|$){8&bJF zCWg*QX}>nHKc?ObZ%uC7=_Xf?jW-@NC0>!3dF}b!z)zfv3hsMNwl%G9BAQ?3y6?3h zX9X3arr#kR1r^xxY;fUK;>L614AGPf1d@q?3x2XwpMkrlHXpV zheNpT#(Xs$mt>w8my}qWV7koR+@WwbR>ddJGHmo*Vy#9v7BMMIuiJ@17>0^w=VE1@Vz{#I$)w$D(G_RlS z@$j|#LsD=*E4?v_uPFK;H+m1*rb>^G4BBf;a`>n#-zbiqss=`_zZ^SR6|C5|G5sw) zT@g=dixa)MLg!q!GPEhZSBSL7oHpFHlIA$0wy$bO;VZwQl38U39W)aC*>o$1? z_o__XS%c+|X+yC`lT9i8MX%D%X}g;p$3p)^4_i&&i$dGMkR+p`jzaQjkb`)TT(VYr z!s@rky+@?jjdYpj`O%t;ZVm=cTDjeN{CmBVU0v{#>B=9QqPG?X!rMNsTt-*5o`*i_*umuZJlAp{9DS z15!PUI(c~1?}Wbvm}2`_yW6Th=LtBj{+Pe@ue_}GRZb#|o?uY!-Qz;pz{J?qclkTx zZy`omC%#oIwqdtAEzFV5Q|2BLD!xu%FFYF0e;*x*Ek1J#)d^bwKsPjAHG$#XBz_;4 zMd7CrC*wq5m`}!MjeE$x4DU9d{#J3*nF}eb;XyY2)%)CZ#Q8*qBsF7!tO4 znLXcp8F}S*@g{U%tKez5Qp;05Az0jZ0t(J7^PCJ%=tb7x@VsJE#BF>u9LX*HDxV+($YyLrlw>G(?N<1@hZ1g#ZeUqcl_NW7a;v{KA zFYGW|*Ti*O)dBa(y_pHZ6VZgRjqB8f@BmZHit8oeeKRxb)<1+ zFy!01-H}>iCA9HK(P9wdur|k0>A$!fsn?bmSDTdD>4((*VD(`JunG#uKIaM;f|t6r z0l{$wYj1GdBtHmyp)CvIpq6Gpe2ip_dBnRY?MI*u=+|&2&TK^sD+4#;(g#uml69?r z&YA!qsm6W*DL6k|-b+6>@I~x3wEo899eB1DOSlwDJ4|#q37WZsQi^4_HShXv9(2q5^_V*kB zYaN%-6`2`~R~=IauhVNS`oRA{jRJJ*nR!5!B-mMaB@kiUEDzqMqPj&+aJoWJ(e#wR zh_L8VY_66N$E>yzWHKVr7aMSXEOs%Hc`rDNa5I3to|ejgiN=3qCav(g$Z$V34V*IndtGnB-V?xdNFR zUx;E+jke>kaR4}2!4+_Out(rOf$Zw;;8ujTAY?s{K`(&J`r>3Y4Mveiysa<*-BB=E z>s(_=DfxxBu3CM-hyVkegVCjZ8$wS>1OMzoYf>( zwE3Ko$_>2d51OxVz7z<{Z*9jlpbY}M>)<3BVgE3YMC-d2>&|Y-#=Dv#L+l@ls#ta0 ztT=9b9Gl782u^+^9&PcR%pv^9+ZDUCaa1tg)iS;>LH1?Bq%{y_5?Yek`D9JDt*O+f zc>BVD0i!aOy!IA@E|AU9vlHbg1hYE39<3Eo5O!LF`I#e}Bc%aYcS?UOczO9xnOF4J zg(;hlZ|Qh&@PAv~6h_?Ev^yvXl(TuyI zBFLkoMR#Im4sGoRATLs;-BY@m&^Q8`c5sf$%|^Xi40JMeOSH70bZM9bw^L!CRz%r2 zx5$X=^zK|NLBpEu)T^>?_Vh9i=0{-q$&63o$5=?|6pjIyU=8~bqf4YF zK3GmfLzqZxf~P*hbdEJV7l?gJGHNhMgwJcv{B>ow2_So{woTy(`QSG>QkE9uGFyj~ zn=Ho$GM0sz8}=1e%M=Qve`%-_eKP3WJkWr4_wqKH?b!w@6cxA~$lR*`$w4e%_!p@S z6(SCo2H}HNUzP6g;06*9-f#}r%$dU0aP!5+cAP%*Y)VKVU|O)&)=Eo?ld>A2&6X~Gc@6g;gx{(gbmv%S5)97x9x>loi0rS zy2InQpY*ygTR)7I>>(nWhS3DzCTN@^yIj&`1ZMns!K3^f4w)~e4r8^Sz6bVjw0#HI zx(jSq&ssVM8M1fYS-!^RkpdT6R9H_VLK^#9O-$a51!A~m9+pkq*5~Y0cn9nkB)H28 z%oxiIlF*+Rs1qT7Ku|jM5DjB8<+w22(LsL)I+T0I(FmgS|NLwIX8pU6BU`;gL>e@L~-F?&IrrwMvcLTXEGqxY$XV*fDZ%P>!_!lv}U-e zcZTD2KD$+ubs}Wi!W*VQbLDfXMC1W}Nu%`g`DpUsPCbSZEHv2z5zhvwcbH zrt?N!-r~7_XLm@9@4LE&*B5(+_(DHXs&Z(v@~jSqkZ)aI&q08_GSJdaeMO*KK)KD@ z0MhDRne~ZHbh%Akr@*4A7z0WuL@1w~I9ngihE`x9COe8C&@)w~&y}k$XtFE`V!9;Y zaukAex-88g-RSO`46T;4cV*5AKu4Dd4uxk; zZb1GMH!H}Cdziip3OM5?QU6NNb?H$JOtV-jLMy@;2%79CNh&fzpg@mNkFM{R$;jmN z*a7&gxc)w=sd#5V*zj!58|-KVZ@nOw(By({dpkr7k+nqQ)6N_YYXqHNjduY$pJbuThye8dF-K%rH zP-B@qU=h0^^8Ru}nXWAF z%!s;nNZhr8BAf~!o$z_Eu076FNiT#m7pK(XJvWIZHNR^j&sLSzY2qfi_D|!2G}M#w zyssPO;L(-@p2#zHUsOU-UR`m!=Fam|(Hk=W@k5BRzi-E4sN zhL7scLvjU-9JBqdEN$VHs`usDk%dtV zzKj77g+AO>$q|m(XbyQ1YwDJoz-)q>`ge8d;5VJ~Do#tlN7WPNE-|RKe8;3?Odj$@ zRajzF6p=Wna1mjb#zD zWUd)z7vw7x3PsZ}d%bsNgCdt=?ohN5W#N|U?&6d`GCs2Yp$97;HBvE^A*o&34N|?n z7Y#G=*8buQg{r(lx34(Q*Q5M~?&^%w;; zrf$Qlb?kl=-Y^xa*8RstO4w$?-))=dFt}aQ{(aR?vp?|4gzV)Yx4a*il@)Ur%1eUo z)}`<65uQ^)!lU%?-+)5L&OSxo-}j?Z>oua?d35k+;D8Rd3$erlvKnX?suTbf)%$=% z09mw9e$jg%!XZZM=U?vEhZNN47F|J*>|y=oO{t|D1}FuqUg9FcsG8*+Ycvko6b9^-V4jKjOjUnHPvcX~_#??-oCz?{T)=@Z0t zj8n!`Rvo`vnLISa&zK2#vHeY<=Vhb?Y*3G~`g(3u^9!qrCs+e!$C>ry)T3^cfOs!o>7Iz;60y1xB2j=^gJ&QeYuBV3 z+O)Nt33CbLSc8N%2QJ{5qb$&e2mbZwxWMiDI0y7p6lJ7-L?N3EFpA*WH-Q5nuzM=B zT^A8GmWAMOu8`Q5wiCwl`NSiYAVKY`VXRz1*E29C@D92oEg>45o_3G23dU4DT=Co4 zQe)_yi$jeE3;bpWH*tdl+e;hyrvRe3c6G4vdHRQWj=<<=;_EZt+cj1`Jt8woEE7f+UF8KD)`)w zdEQOnwP8OR67cnyLZ1PsH8$OX_VZ7jM6cZcv-a9-E#n?iaSQCY>NfhjsP(+UviRzF{>V0ko`@|z6n zh#%+M7Seuu6zPy$d@fI$515!-?fN>5-HYv07ed=%>q`xEri5t-$tUQ^szkNaH` z>5fI-pZot-n8T%Y8~8d&u19mX!|zv96Ww3sT8ly)k=HYQtH9Y+hQTcLnLjl|fVQ0E* znH5*9_Q~;NBb&3qXM)7}%}8DD8Q( zofQR~14u=I|Du1k0LZUd&6J0l<^??R7&&{CeQ?!yopYmBR-MWtRXcNIsF$%phCmU@HiHJfar&z_tQVia7j`{U&!m-J&rB__xSDlaI$GIRW0O3e$_~ zT{i`Du$WhfHG80$v?zI_YvANqnm)#o%9hl2vqt;gORMq+A_&AosWs|r_Es#fi;fha zGkN|PH>{?a!#HL2oM$lZ``adMR!u2hDo3Yw{K(ZEXIPVr;6jS27tD<)C#7}VMxG8i z>&K5|9q+$d_otcC@(9QKdG2k6xA;7Jt076DAEUN#`*Eb{BCVM<7TfR^ooEXV*~}lV z1ZKk=ez8-K!$~*{-FYeIJ1mawfgb%5bmlymD!1Tf+NKv zS3BaOYR*$5PPNI?@gb@Wee$w^0raVrtqCM=@?MSi(M~Ii`w(<5M7*TY#iEg?+d()* z9Z9aWwx|%&9Adgs$u4`6MW0G^?EY?o?ERK|&_>GM%R>8Hp(5yeE81Iw^v3*6#0&u8 z0N1uZbUR+XNyq>;+Sjb|+6_3_Z@#DW>%5wa!yEJX@XdWT{DcS4&nS?BcJ1@&hX@u? z(6v8S(Fo74*Zrm68?%hnDE-mZfDLtk5v6z{gM6A`4%=z6-+CVOei9Q684F@bSdvL? zMLp|C@H~^s14Ozh=?ViJ&ks_)P`e;)f|KVID(ZIFSmvawx(KJ`yTnmEtX7}b^FkJT z^BiEqxYa5XJ+>aYiqWf%ZCnqGSUAUb$uR0_bPB3i51Vog3}k@dow<1v59%l$7sT2&o$bVka%>8TeI0x9 zci9o!7zWWjs(Xi))Yh&|Dc=~mgu1kF}OM}!gjwAqLsb#4E! zOg?=9v4TDG+@Y`=oGjxBNu+V(gQc?xk(pbqhEWY3HN_YkZRy|RM~{mH;w#?rc_ zRQPtAJ~eVsR5}h_dK3rbFvxot2k_@}?uZ@Cys^3k%^q3fASw9$hfx+FrSymEz$&{t zWWOMZp}w78|7KUCSj*F;eK1<{o7Nob$DP)+Y4jCoDX|`30+b3-)AnZHoAwZ4+XBVm z;UbNf{)O2q#lxq^1iTT^p+7;z`R)9Rr9OON(ZCT5)K7`bsz3`pDlmpVR&ZufB{q`- zv`F+{ph~y7-h?=Q`Ozn_u1zS@(N0#etF%d0;@4!_*|$)^eeZzN za}V*>_kamiEvgJ?(g8(f+uD`zA|DWC`@7f=j+;#rDV?bGLeIQ_YM38Sl5f(h#kb9r zAbqM{@kt9s9oJ%JH%@}iBx_j(;VautMkv-?vTZhEH3VV&7Gbbyjzs8h%ZG1N;jwiO z^WeN$`Y)PDQ$Sq7Ydnn{i&<(WEr4Ug?w}sgkRPW^ur23gv`0-jf>Er>UoW5P&8GfaE7a2zMZW?%tqNVCo9$l+0>H4%A88K0R7=xuB7 z-<_``EnZSeP^_)l)AGx5mmem+pwJsf=Fu7;z+w2xZrsC2NMQj14!0n{p`)y~8Vrh- zrPe-qReD*mc$vS4Uy^4OGZ;iWk3Mw#{hVV~KH-|z1MKu34P0u%W6F>&JOup}7V!{} zL-AKq3p&7iP7(nFgh4Qez+}4!Q?_jZq@fR|6vn1*xLspf^8m<66j5;=@P^5w+Hpsd zI{AB8H-EMdGOYhIaex=T8Z=W|$X;Wuo{mPM&_dBtH=O*!w0qDh)aqZ5hCZ^u{{}TS zu0HIp%GTgXbaVhgMmITU!nA*s0ViOJkx55M}&($iQQG$1u+oAHEfI z=7cad-l_9*D*3Xbq{x(o^hn;?e5`&qzW(I1^lC;l*ZofKhs(^AS>?Owx3Emp#Gt+F zcr^&TK>^6SKml-{6c(z4M>*PkZgl8q1_wyrrnf_kK+GHK)I(TgZw#`O&m3ZSOB^q? zTzV<6Eu%>#6ZBQ$h0h@wDN~3e10w=$3^Q&N;E7QM%2_^-G8xFf0_KwNLSs+fcA&fr z!?2<2xToAh9d>n6k1C&s2`%6Ht!AM=$5Pk3M#FL4*l+m##*Z=#4q2MX0aE_1sYt(( zV=cjsJe^eNFWKnf00#_%C$j{JpwL%Xrbdu3@FoHr<3po~0lcsLH$ z)X>#fG*qZQ0vW>yaoEX>ok8N{Z3gHQd>+=sdymICr)MT51m!Fy+dcC}UR$wV&A>m$ z-BYUY0(R~g6HlZk(SvME9^vo>ugpy9HVqfqBC})92n*GW!a9vajb=x{7&U;q$x!?d zw|Out!)=iqB($cE3gy$fWx=|Dd+@R^wN`4r-ig5@S5;}F?t!N2fIF1PLL*Pil@tx) zS2ysy4=_n}I{nYWyfd#ZwL#7-9LVvGInSZde5XJnL`- zvD9=RhJ^PF0DyvFGjdX-r?d*JYXND-B+wt-y6v+uYmt0n$1Q3rVdBqD>uq~@F^OoL zmCfPuC{GR0YFl<&_5D<4KUw_m_tVB6cS<` zJw=JyQLhrc;pb}83@|XyBQ=Xg2?UDt=8+>Zk4zkjtw4Kzqh1GAXCjgd@a@(K)--4K zGyu?ohZVjU3S8-}*?8;659AR9OWx~hb|($$y-RT4p>Ak6H!2i|zi7&}*q{c$=T zWKuCyvg$szuCzH?G92xi2@ny_k%9;R^+g@OxosY!?84Lf1l27vP~~z%s$$aL-75g;Fs_^_;;l z4)x}w?jgn&4@=uHY7Z;=hJINuo+6K2TXn})^n+EHZU-oht@_ zcmz-_8BfFMK?0W<8DBb+I@cZ~1YSq3MXkxoRGU1JpJ#+=_V`~(YdJH1V^xd^S(z}L zL94uxU>weloIeRG7;Y5l;5=VIpyZJ~icH5Sv0XcWNJOTF<m>B6MTq5$sAf6gZJd z9|6(&NbtS}5e^$Epoi~JalrBs7&tCOoFI7c9R`VHMxjrF$N*@pcb{TweP~59UZKc9 zV2)s>8;#5I%l8;IJO%CCj%_QXilSv-%kzx`_&zCG$0Owq4-ghfaV?O`!4C}K@}KW^ z2IN8vVNQO7BeEbw5?6i65dNAF89RE(5JvXu|Aqkw0Un=^=ks|y9um%LvMp(9FR?9Z zazZu{?cl2~=tm4f7rww3itn@|2$DXL!kJ=sO@`qA`NFd|Z`d9g>SL+!wP2#xNt0MB zqOl8lHv8}ySOvg@{vIM>SvXow(jS1o_C)Tw1hjEF0me7>ewj8|i=CF>Y66&HszEV;}xfxEjIEud*&v^OVX`;Gxftod~Ek zBXD>^Pj{w2`SvaBuumfdu*uj>GO8-a3aqTYdO|H-J(Lq1*nx!mxq_iaB!Y)tn?Kbm zB`!xSKqx`bgM|?X`o|&p+~zKIxHrkAviyVDegy@qRQP#V&udbJ&>?@cnwmYMb+#f)0 zjcTE6icXCM0L5;%LVH7}IcPdiFZ z6!o>1(qEjy)iEu5b=IT9>@R>f#8UD4P~@&oWu35U;*M7?G4t?56RFh}Rf2O@S*@b; zs{p^@vGl{WnvJePiM*cljEPltRA7Y*iq@G%raHdwbE z1z-Q>fdh8vLO1l1;IwQB85v&c0>=UZ6Ed|B8SLxk(N<~n-e1famBMWr;q)N#+X3XX z2v1(y8W@c-!U~IMrdq9Z6bRSHZx%NZi}}YRCn}5$uJVgj(BC(2*F)uX9$Hz(5DNiRYwFKVPA) zy;^rT+?#_pi+utI2Io_G|Ken;$e2K`CL4UkU0BeOOcleyAl2lCk1y>+Gvi=-=q-L_ zas?3Pf@r@T}B(!HW+2J5Pon7BO7ixufLJ0G-sI$ba{ zUu@`u?=;{XL_0Nn1s!%T(-%Zp%V#;9wRP4(`ZB#>AwR45f(a79< zlBiDyKIP5xM6>8FEl%{g;$MGoJ#8$_-HWrK6|7LI+g)A(gtiOgAQvxb7e=q-g!>wnmP?u_x zt!qCCIo6ddEY9b1sP?i&TWPi9HCxWeXjMtb@AH-rGeVGY!y!big$nB`X7Ro^Ek?Ol zbTFI_d_@%<4MnCYkm>sff?b4yvCSP6QN0dynq)u{9fY2mf5z}D*A{APea<*1!q@W! zIsP31a;Q-MznJz?*k}ca1mXji08{QR>VJSgp zdmTLKBxv^(nu-4P6H?}7M%oumAGt{f=)20*86ebVLls2n?ke6Z9Q*`a%`XBCKNAU| zq8AsHpQ4e<;-=9RJqL$JBdQCvU$zcoiA5}7z;4ZwLw8c{(Bw#X#W)@M2(!`wD9%|E z2l0x+(Jd~D@i<7?hs2RSBx=XZO7vqe+frKIf8VoSRp%(t`q5isYwO=T7X+J@p`M~Bt~8)9VZUHeQ|bJMdmm7dLRIwXBa zI#%)-PTQosnSE7N-kYF{BBPf<`aQd}6%l)7Md+JYo_=vX<&{FITh8iXK1okc*Xg+X znu{CU<>gH7ie_y2Xq13w!VJmkY_2Go`_9xRl0K$`Z%G><>mQx(wA zWLzqm%-&anUOd~c{|+_$Z>eg7^W)|q=i}l_2}hvMnt8<153T_>p^}Rq|KbP6{Zoi> z@3Y|tG44A}KK~ zpWP?TChH@B3H|me)j?TTLqfW|(IH02TK}f*ktlg!5v~)Dx2=S5_XOLdTE*jp@`Zt^Xq-1^52tLWRs2mcygAPfe zN%}EJ)uy;yh#)saIL1YB=!bZ#CP=VU1Whe;n~GJ?A+EJZZK6)Btf#=Fx z>}la!GCE>-cn=XF3=cvugq1HGlsdf54Jy`vl<~hEg1knf8cM6S|GIq1UijitE~Dfm z*o#4kz2I013E$hWx^A6I5o;*e9X1=N016w*0~GWOhTo%thw*#>R}C7I-?65GF2x68Bu=WI2&L&U?LZE!FhRUwHd2Jm3A1`4iBrY z)-3DJ+dJ>;#LBu0JDvfclix8W5Gw1Xse~14+FfbuTV1lLf~!(j()^S(I}Ls0$Nd>z z^mmw;Ey7Jt;Vy^Kh!f77Px;b@!j1vh#ny^QJ)hd8@ttp&NSZ$rYfr#=)01?qEgq6= z`AK{kMk_b)RG(rgKY*EEL8LT=ZFRyQ!IvdHx{s>~Zhs{wT^yxLwp!>K4WLu-8}Iaq z_+32_+>Y^{I%Twn_XFR!1-#KW=UW<$x=qwMJ8V->?h2I6b<>9c<-8Zz7 zu>1R0=a7lq*js+O(xRA@ms?ea4^lTgllg{?{}ZRT&<-e>54jc_$yf$MFFUDu7ui1c zWd^VCg1%HsvvR!>^xaFuL@fwl&P0(TH1s!JdTTdvX zj}=CK5C3$A7;WS2@5%637no{&4n_#2YcO-e^ElF6v?oqWyn-5bSEsfIP=mca11uI} z`UeVh#k=Elc=RnU5!COB8iqf)z&}MQU_eA+f2Q&(OCtAi&c>p`+D>guirk(LA9=D| z3f2+1jUg8=90~1*xQUcED^GNvTG#vZ+fo@yUIwPU2vOPV!ZU+pKm6g_GG}tN8(Sa! zhOBkX{&R0KUJSePtr8N5nt@5gD{_aqF@=aOyn+Wx4uPbj;aQW6_v=?PiY2ca_a_$g zLDAB^8dIaty}I2$Rx6Mn8XW)N%eKPvYk#doWDSzDN@Llkp0@_lwpuOO8_5{t9YPi2 z^wp64NG){ngginrf*P)J_@8AdoyUuQ%~|J6HwDr`&UN?=CdM`l<$_IJ6ds%HHnU$B<<3UUU}O z+$-J1Md(JULLUZf4LS(Sz;No)z=EG%XdSE4E zSRaqh2jDoaW*%Lj)<|H<;Uc%g{})=H`U6_u07C1Zgu+Bsk07+Z+5ay#|IuHw~)`Gt}7s-)MbUCiVLt(E5g?5i|&>0VBpf03;71rVghcq60wkG!)`! zR)f*Pcc-qv7LUB33`F8U65N_0TrtgC$oE4Sz$OW~$KWZ924K6cMF>hkjotFRE2bMpoHjC9SuqNFZE&dXi9Pc$v_qCQ z09HkGUVcs>3D9Zh1wy#HbkQ>S4bCje(=Vz^z03LnxuyL(&dG zwRJq*2*ZOX&QAf#YDFVw;nQ@X4tvOJ0Vix=kaXq9i1pSGXqsH|Uq@kc7^n9E8xTbE zC^(QlPOCRE$k0P2a);WnW#PrJK_YdaLZ@Yi_}xF3qQ(?YPqEr*HcSaUH#=syXz3#mn%{Z&~C%3oNN! ze7PenupsDrQ;6KvZk(r)vI2qg#kU_OKi)9eJ(I=F#LeEOwQIzfl=%3g_~`4=j&a?T zgX@d(1-UBljecCVbQmEQoC3dgvpzGcLx)!`YHj{9Ks!yEl%pw#C=?TihAj}$xFdY} zK!u@ij6=BS6<={U9=AD7$vdnivBCs@=+X%qtmh;iPt2HDFAEZ6bwxCty7)1qHXL&BtuIRVfx zE1~lxHl0vz_MBkG!~=ld4QyBSdo<5d4GTaZdAZQ$x;(pmw8NXiZuofeWa7MVkZG82 z3*?g!`dTEKl0na5XuI&Kq$}Y_5RJo6lV%3838jVTJgN1m{Sc1rp|PF9%Vw z`PbSK(=AFl9isBI2#xozjt-6nn}A-afRK%(cRR-1o`J^N`Q=H)cS;p))pIH3#v%9P z>K-EsiXc1+0Kv^Yps1Sw-5@6?k&}g!!tl#`k+KM6hSB|Mg*V11ylf}K)vYcb)|e?V z99@buK{@xaFeK_eV!HPEc|WLoiFMO=;{sDT+-3MPE=UrRUppj7_Pip8t+O&LE)vsW zR;GMcU=o_C=JF$t^;KJeu2myo#uC|SD@DI>2wqqzCbPY78!TqKi<>GH^aCLgxj-9E zNf}t8kC1FUXi!0z4*tJV?%0rXRK~rQN{f;?h{J2qin!oKdu0mILN`5U%I@R3fknIe zOAasYe@@MbvXZk~`bG1#nO8y~tYh!J-(*9dKS04$9u`f;Mww3p^1LM5lZPS#Fz$~+ zA2HE*o@gFJB6bbY@b`v|k_p|_ci6?FryK5-M+GLVxcGTk?g8u( zlsmsif=GEAF!L)vQ$bD8?0g^|yziS{dcPN;jB&X~ZfK<;uFg!J!7F$QoXY_h!DHM3 z1I>7#7k_WH%#U}93)cwWf}xCjm}F09SimD0pvesSPpAFif!6SLI+?3KNFHByQ0AcZ zi2&hHFY1K}(&M-o?`avtGXbdM03{|%w*~hk85tp~2pAsVSr}DiN+W3t$smsj7fWn# zE=O*`Zb-C?MS(@Lp8$<5_@|rDKAJ4Nf{MddhO7rJMVTtPcoSy6GDh|>&I8$$Po_s< z*{e=rw0NFS4+b|B;?c063e&~;JQHu=+6;sI9+WQNCWWY{?w)`C?R!OBP1W<~Z)v<4 z+#cObR9J~j2CC4eMqYtnHDIU3V`1*TG@*V*l_hVSgcSkvyn zhfEMPR~CoCo{`_9J!xoY?s+nDOg%kn;7OY>O=>66ap)a}SN95#39uV%L187NXy672 zj;@U4!&!lJr0~NbFbPs=Z#E1Pc4pa=%q4|gCEM2-#UAYT01R+N8u@` z(_%V{iMK74p^}PxA~&|r)Xk4+_9rK-rq6oS;aXdt_}0311801zRhR_}jtP2qjC+FV-+|+Ky9;`vQ)gJ% z9jcRDXyOFNBi{$OttI;hB=5Y5o{}Q@@Bx-Xlc2rdCI8u6_6hr*v^(}RBw(~+uBrMw z23MD_bY?B|J(=rYX=^eqcvFyIZ}WZR(6JunUNa*4PQJ8g0X-v@hD5QM^+*^Be;;^H zf$RO;$(hKr>!b)i$&Yz))hVaMrRd%>FG0XCF;ogpn;tWIdoteU;!Cmpr~Nyfwvi^) zrH2It#3sPUzy~iHIKco*O3T6M63b}@+XNtzyiaUV z`9LH)JYuiE^u8|xp_9O|+vpo=x{%&wrOYw!C#Nip0&*bQlihKgj#P$jW7QGJwdPjop>uUeG?C7zLul)2P>Y(MsUsjDUuv9fJ)BQEx za)gywb1*2{g~}Oa2Yc4WyXCV7y#Cj$@IJ|ly$R3c$4E!{M@c?-OoWzTpv`XapMP@D zN_mY@OJ)MezG&yyhj6$t3E?~?DyQEA4#w{|&k!9xI_*gtxAReUM^DHi^<9N%llzy9Kq!xs4W&;Ihd)<6C0h3Efv#JSWAyFNShwu0{tz12yH8I}+V@J&&`_V(6?=QQQlkUr0{iQCIy-l!wXa2<1GWKYP)SD>lsdfwrJWR$ z@>Tq?6mV9-$N|n$w+p=CneJ^PovYHEEidVGD+Ipg%EiWI=UW4FA6h|nK5g`RRi6w;+hrTp+oe1Pf`(}^p&WDT<*AAb_#rGUbnD-2?wa}33OiF=$2gdd?ThL=%H~&FVB7)$vD+GPo<3) zaE*RZZ2mjf=B6$w`!|dDItI?w*-!NeX3h4=V)bu&|AGAb=AF6ShTRp}I!+ZGqWVWp z%pbGPk$s8Hai?aySS^XbJ`+}4RmS$)ak5}U3kfM+74q0_X{xjTpAu=T#JUHId(|?V%EL)jZ zD7&djZ6Kg~DthwHDg+v$fHzX&*#Bga6h^Co>5b_Z8yk!=jy3-k+Vg|bDfOfxH6~@K zu~aVvmMzQl+Nxbm>@?rWftb|2PQQzi>^r25=CB~nQL%~3;OBeqShbbI^;3b$b4=-a zbDb$~E-SZsd*-EKDY6kV_1xJ-@}xZG{BY^9G3XMC5Eqe3C49n=;h}DvT(dK^nlrDM zv-Arbn4-tM(bm|E9BLPIlNZb}MqxW^RlS^&b=`vbC?@Dh`S+vh7gENgc305tyZqbh z$A5GWa5oB2NuZjcXkdB-;G+}VdeLI^&lV0ucfkH~?~(W3IXG}fCMnMy zH&E~Ob~-Aasyi)K!{2iO=ONw{*3$(mh1ux^YC?1Y2{slU1H%(F9Ly<*Ms&-yqUmk3 zn#rLm`KD+zI$P((Ag~kD;5G<(GG$1lP>%}f;ijsv7uJbrRW3MuY`VpJkJZr+wLlil zatw_G&az=(ck;1a?WS(>v`n-HQV<%(vbMd1hok~BMRGYEAdgsUZVOY?Rb+|jy=_Y2s>kwTm*=6a*>`IiS4YUQck3^t3<-4<5P^E zYJxex;hN{Edd86W?lZie5!3|TiSSxrP#8Nb4A?mx%~(+jv*t+|h;TilFOQGTLTc== z*P=}A8j%cts^_BH3g;gnr{3^AQ7lV+k~4|4k-u^-{I0F~%&Vy0qJ!Ae7*+2S*?G!( z0M?4fE1qZ0iHq`mw3$-wd<*~Fz)dMy2UV83#MoQCZ#?YTXUoHnyzUOa;AeLc0WBzQKWc{jHm%puA^GGM@CgXp2Yg;gsF z(n%>~UbU*aoIlm+b~~4^K)Gi~UGYu%f2U^ZEk?u)A}iD0%_U{Lyu&uR|Lb65pJZsi z)56l!^jA0j?Q<0hiTk3{SV~vlI!N3X@P3E3^Kr0QFeL8l);%4EW?HGcA2`b}@w@rc zg)h}4C51p_A)%tSZ z>Z9G&m5?42dkyD-1t%|TJ?b0H=A-;N89PBL97|J^LVvcLBSnQZ=h^QEn_Jm19UkOZCFaY-_hUmn(+rXnzicj8 z6r^7BkI-=c`YSq#v>W56dsUO0XgZMo{xedm{<8ea(WsO*13vT2&`GEQjj2QSeax*e z<%pHU2n?V4ShWK?5Vjd)bye>XFd6c;#KjAn&AP;kf{Yl*s}fE)Sh?W0S~Xso0cCyyLR_q?f^ZhUp^_{ zy?k<~T>e5p7F@2MhK_SV=WaK&ar$z7w}1q#hg#TiotA2!bYCt&&+VLe^Ftd?rzbBL zy9I)dy<3-U3gl3u@;)-usZRNYK+r4K$_4#`p9v~1U+Mzd4DCf0KnvZ1^F8gJTzd20 zow;ln+N1N};)j>pg_if^f(xj#7Xs?j%eNrtzI<=f(@+Cmf+2yxRW3gm+@9zt*lJd1 zCx-flHs5yEIxCw$Tm5IZgO*v-i&krwy`63YwvA`T*J4aM3~x~Gdi%0I`DIwslYLTu z*u`s#mUthJNQgI^jSFfIZjjFAjO?c0KKadq*k5v1g1%`rS?8`j0a^d)^_$GsKguLc zRD6}1mTCK-B)TZkJSfe0AtW;@y23&w&=0H6c%8#gKIZ1lcP6F9 zcD_dj`0^!p=uVw0+{nr;X-1|{D;DFhr)7T*IVkGgZ7O{ncG@l|-zqGqDt|PkBDOZ+vLg2cN|s36+V^WO@=&j{#VaX4JJc* zsLzKwN+^l>#&f%kADkXR>|;V)dn$|AR08+yaQbHl$~^wHm+YHk#E#PrjaQuMgDf%l z)I6h@l_=|M;-DVE7Mg4}J6U!O4W6iKsVXgWY*Tq$(CT@CnJ8(( zTrsrfpsWU!zQ23PiJf|xdc2Lbp0k-Tz@o?F22xv9c?g=LhpocCPllQ8}0E9 zr83vvH@S$xD8J5M=RR9@wXVCf_2D>R$IgafXhe`|zgW2}A2; zOZW~Uzr88X+ext+wQUucxi>NghU@b|dtaR)zUgz5?GF)G!o3{QEQ%4gn2iCBD_AZk zlUZg)8%5&5OqT3_jm38y10ZAZ|7&)H*ydgLy5s_5?HzrfNfy$q!xiG)qD#z#d3#IA zwyQ(YMQx_#uQ^o#cChc30U=~(fCN^lnxj>|gf|`VEufSZ{p)4-o%BkuQiLZJOz>u+ zb;C!12)7=lwg`@YAdw_r=(3Ah!>t>BRgL#^-JFiyUP))XLnFmG8`ph09>8TyYqmra zN5W&f_KJHgPZRf3StH->`zCDds`BLgv^Y7tq6t~sQuJ|GQ;XX*>fPgJ>kfuXo8EV_ zU=9N00!76p$fBZR>y1BA9)x=qMtj9!?d~T%UukJ8J^7C>n%X~5f8I+9L#6>U{oOrZ zdDW$-#g9U+T|q&SLE#W;CL4M*mX;PjdATBpje!2y^~aN%wA*Qi+`E1_x+;CxFxSyF z=_g)g*{^#cBv_0|JjCx}Ait-7Mj_~6YHOk-|nrY0@z=b2yHCOW-Fm4;aaqUhy*6{y%PTjC~db3VItR_8DJEi2;tMui71d*Mv0SplnO7bx87U3p(&g zzw9fwV)B`-wL372>Q5tnPHcd0vZjFiY9z9nfwBc&nL>3PHy2e6CI&e%8=}8O=OoK5 zmhM=MOY-5T8f zZ|(*qFIjlok;<%vr3V*p(d`p5|Bh!RWY(m`Bn3UkFn(nfSclr|7m-VuuDJvEo6}H*O*Yu^Q z{&4-3VlFFQ3v(potb|1_dD|gj2*Gt(C+pryT~R20u0LK-ubBHi-^(X5y*JNQ3Au&+`nDhO z8wjn%(k*6FQ~veYza-{FJ1w4w6S7W*bLKdW%zc!Gle1wRtcp0!40#l8r*Yn7E-(Iw zL9#Y~cj4*DvJ8=!zTQ#4`5@zgRacgEYh1Jm z(uLus|i8ce9mh6 z_aVWYs%#6(|D$ge(bf(%qK)ggAcP059a;O>_I8`0}gxy8qZ}@~WZy>-(Tg zsWHXEAK|!I6SRE5vB>yK=bVM0AuFxpqw&WHHYReJl~=@@RM|R7cbI30lZW;SbT)IYx3$ zbVCxWH)+{5YOX8wBrww==Z1Mw!=gofPQq;ZV{Y|-9>izv*d->USy==PF8(AbCP7)v zN_w=wa&3!ycPl9F=3SGJhM($wrO8Ywy?%ee$y(}t=-jqr+EyOqVgKK}so%xQz(-$P zH;?_B#_89Kj&fJE99}w9`$c{GA0jw`#SYauEc!c@P?mFGAdeh&&RRJ|Yhr9P?!zUG zq5+{un8>Y;`JZoTsr7g}8KVw5{ePCY>HCYiR2|qOuAEWBKVO}EOU9|KHIUSC@BM`C zjm&r2;qdO(ICsx%HVE53oo62#90jDs*KdmFTI|!(%-~_$hre88&owa4sQtjSW^pb!vAzF@Y5tohX8O_idV{(T zLXW-flN7ztAn|v5xnRW7bL*EzAZ`zn(gnX*%JR$Rlh%-c*L~{TXhm=YcXjobM!NN+ z&NocC_w?># zllA!rB*+Y#2;~lliqj+jxL7&0_Dd>aHgV&cTj@6vKS^+i`=87t?`YwFd0zovYgV)v6LS^G%&9CoU_gZXPN}h--WG=k||_W3I2a#KsCX|8gyB zdHguJmWQ=pzexTjGxnw~er&_?qpKPH-1@!)aWuy(Dcxc}bhmspHU>P*xhj79WfjLq+VL~RW6Rp$E$48IXBGLMTS5t*Avy7Y8K8I=K1Ji{dp11l zs5wzGh~Ed;o;K%RT{EzCZp^))dm8*JWhB1(nd?W9bLscz#0??;*h&w!eT7O1ofT_W z%)E0u8`2{(avi{(^-PYeg#~Tp6NN>zH$4J-@{2*BLXV>)?z2iVTaeFM@2V1NWQdAGT;;I`VsXAe^ z_P*nVcqXK?sOaOY2*)ViSlwboO8hgc&R;SGaV1VpPUZ_7C8ln0j!+%=D52L~k}(p= zZ?dWvH!sdtCP>#X>uk?=iRMKmRa@-G&Wt_79LjU;;TrkOc=2!KB;H*A8d<7~mu!m?bd5!(YV^6F5(%v@2 zC+KPBA~D}`mGTUzu#NjXsEb*k)dE;nWqz}t>5DtF5mQ$p=86pmbJK5G?{n5nuo1cA z(MOsS7N=U(rezE&=aSV|Hz6r;Y^G${H(2N0B8dK;o9X&f@Y(2_kXGbw%Te^t+H&o7 z3i>%KIN}xT-q7mEo~Jc%^cd1T8(=cXhri1q(5p?-Z!AQp>sGg8euWb# z%e~VdiB&zHSbuI3`6_;XHuadC;X?V7%P;&~u&x-ioIbJ|Buu#Wek9={M?IYJTst&v zwY7un@U|^`6cF%VBGuvBpvB;WMYnb!NUw79FHfT<6qBTiQ3DinEitUDy7`&)P)k88 zt0`jXYmHG9?|$wRTZ#P>Zo*d)oAq?zc^;S=UWUF?x> zmhJxb^0i=E%a*)EK6C)k8(MYp@Jn}*?x5k~bh`8~{f9{pOubQmYKGoILd+lx3pqL@ z{P#;vrAbX+u<<9!x_|Q|(x|&E&T`)3-MQZHQj=O2;hVf8M@nt<1N*WR-54VZm{k3> zt9K#GD>N44lTb*cRMdury^7&Mr~d{JE3ym1B@o^j5wTu{dgb+>8In-gxMGdL~Iz?Kr(eN%S7i`X+18Y1a1B6;v@%TDY?T zU91x~(;Hscpz1maPxGAqc3alJVet*orrpc6eTUWRxTxj+z9p_ctTo|k%x%IWEg@r# zxRNy$o!;#K_t=Qe>kjsI6+1C5j;EZ3NU^GI*m!g5G_}2mh{;FddHLRSApD4tyg@Oh zVCIrePtrEfzyD6X(6@Fp7oX>C_V@JPx3CJVb|2Y(!heui-|salZs6VRBY9AVJmquM zg}2g7c)g!H!wcK1oJxB-N`A`vs`^pOmR)~b^-qWaujSWDoO)ROP9{yPm|G9SYAP0* zi(yUcLwVGQo4{>jr|No>Xx(DydTvhoK$Ka0ph-fNm7NK(BM+DSF7}+o$#6W#huQIh zca3scUzj_7-`bQF`N)9S#@}jaZYLT$MmQ`w#(jwupyz|CpEf^`I|aXW9`s~K*qz;o z`rYU12uG5)+q?TKQvD8^N7}Q{aaE;wm)KN|xNn+kh5m(1SMwb0E4AZ0Scr+Uwhm(| z&9_Eczzk8*tWH7>RNh}TmS@e-B0r@IIl#TZ(4B_52$l zBG@c{CU%v+@v#V#asp)jDs=YA%O}TAQhalduNa6WPur5|8ISM!Qr(~J7qM&VMTLZ(Z2pKo-+QeMj*xD!NBrcDa zgi=gwa2t=C4>A(#W6T{{txod2;TEkZW1HJQq}GeN@H~YOV(hODE0s#0^=37=kr}xo z7=x$ED^OXIKgd@$gE*O5Zj!jJ@Qd`=ocQH0p;SQpzPPqAfx8kCnjNoN%-$5M+S3?u zR-4CoTk)frKRAIk4+P@6&AO%ZyQldBlJuP%_F2TTL0IW{Y%}lfgKHmXLQYquY({=n z8B)PXb3V~5WED#fVap<7i^kOK;?t5H5aG*aZy4eYlIm8UvqNq9h6W%0)WYB9(yNGV zeW_Wi{=|)u(s6pJ-S!SNqwt5lYhl(O9HoD&_6&H{r2XHr@GO-jFbaVy9euVPEl7}k z^5xL$az=sJQgQ^@C(D05nzjKsB!2pnh#3IyJe^=NxaRB9d}h5{qvO6H>7_1PA0zr) zvaK~N+Eb|4}!_N0>o&(+S@65}p;l{>muR;eRYWvUQ2fVvvoTE`YS?ve88cW%|%{%ayNxeQ} z8vj~ik#|hte=qNmaF=4kl9p7;yy*tUdyp%<;K0DDF9}ESgVLrh^7%)5qgijK1QZvs zpNI#M-jix@(e+Y4xH0|(=?;J@eCdrj%)Rueu%K={_z5({G1w30BO?}P`ejI)7lSHS6S@!*_CUw4oxcPq16c~+)NE=<(@cOTC z4}Ae_%p#YQl+UU*w(<&o;b{SDeZQkN?ALYcGZjl)mgmI4-z(jp zv}~~Nd3PoDskBBB-B{Q#DCk05YYcGewDF9A=q&@(YCmO4#S8Yf%rTu!DA_xi&U{=o zX#J9T5)_{M;{K)ZnR&o1H^Fakqd03KzV|Jq)K!}QvYDl?{V<^*Ll3&xL7udCml%v~ zn!g3wQ`pLW-Ehrw?3VcSUxCdRDD=bFh{qn!{xWFH+9mVfVYC{(SQy83Vhh)S^dG4v z>|fVVR|?tc2-0_sHpYKAPBpx;j<$p#C@D$2Qy5S$HL8UO@JAOR((j%Bku*1zd^)du zEAPmh{Vi+$Vk9&>d?n}B^;=g{?H`^@wrbOJ&!UxuhBfWYRTolf61NSSzHH_`BJB-s z_NAtn}8#kUOWXqXB_Pfnj zRo2KVqh!CT)oF$|GD?4gS>6Mc8Aww1IovBdSIprUm}1t5-otPgVy}gc{_OICC#)%s z9qOPuT(m)FYF6!Mwulu**gEmkn#D>yG$~EWH0by!RwtXiCjz@)SHnBo#>&}Z5$zmA zubR{ti_@t$m&j6YW7k%^0s|!BQnklN%<99EZsN+tfzZt3wF&zzHg{P{U&f}7(!98d zBe&1r8+k56F+GiH+HG||UQtqn1X0bKX~fa4Hoh#>(OmFJzmMiCrZ1BK#CT4+S}BIw z%+o|uc@F&CwFweN#;8p$db;f+BuCE}q1#c;M|8os6?>y}Z|`xOdF0Pe(b)-p(56U} z>9`Fw!!sHac!$cxWbqx8bo25BuvX5-0w^yv7z$QIBKt5TYN@s9=g>^nbNBs-zX&}; z){Lddn(?jw7Lt|85+k}s5Vynxm#5N>MHMSo0yGAI%UjC z=FO!mdc>|G@KxEpzxWhCMHD;NJ#Fqf zfuA(9wlCDb<%|@JW&&|*m~;}R*@xN=lmUl%-Y4~cW5iHPy?s$>76exQ$*fU~H(4ol zB#X4gDbm8m$`yTYs8@3meR~-~14(Ut$GeS~lx$Eq>8@E-;Jc_CJ3HHT(FkV7Khu^& zJ-Ddi%zI$Mk^@1+(f-_lxLnd8RPV%2dIwM)ndn^%a1hkC?*7VM)ADDTl-l3}o-4M; zHs&TBd}Ir?oBVuutFQaU5Ix0*^G^)3GwSe3S{u9=dv+AMaIF8UF{u2YGD0lMiSI6l zy!%_+p!0~!6AjjvGi>#}=SjfMJwa}Jz2XkJvcg`jk;!i1NcZA2{ODO8BU&u z>M=G84o4LTjz(K%`B^k;zCWMNiwwiv>I4+}gz9pEqJ zpAscVuS#88SjKW92=Io z4gR(VKMq!-5a0Cf_{Pqy$W-w5U<#C)u$?3Ex)!d2Vq|U{qKtI&|iNA z^lyE6&qQw3d5^@Y%3#ArWt<{_lzK9vgd)o;xV=EwiPlS$8S?k&I$7auc(wN? zb@K$IJ&1$U89VB|Bk>8}{v)D)X7|Z<#F~gTu55C0O!I0-0EE1S?A2f?wtgJm~VNYB|V^OPmdp zZ}utKmls6nX!ZXph81aHL|zbV;!9+l(TOG9adVe!hj(u7A9)O}<8{z>NLW|D(8N+I zw%NkP-J~b<>1|o#_IgMa&k%Wc#0aq`_zJ>6Vc`>9fiOVuS*`#t9rnyCh4q)RnW~Kn z?>1epN9!vSPmq+VEKzsH)O^qFbBWs!pielWuu-d|Iu+~7Y$JVcNTl46AJKl9$}?M}uteQJ!% zfp-jgJU1Tus|9k7c|lS`JW|*oQk3VgUVmJ`U+j+2R2zhEgo$mRq0PZ%#(-k=ERndv zlHLV(xL^l*Qtby7o{&!wf6k=0)LTXoEaVpGpmiyfC-gu1=)XcV@Y!oX#;rr64wk)w zQ^l#VpL&dj%ytIMb3+e#IN zF@u=FW!9?IP&Z$rHf1cc5pFW>{#(v!#j*dK zSn)|5Z7EmRmQ8L82fL`C_wq++)g>c@?FbJYRGP(bwc$iH$z5@Ge!PFR5{9)Vmiz<* z7KO6G-R!e7bLwuyWG+6zZtqp0~Wb8 z2@(bT=7eo)9^qaF^u9}i^EQRs&_>O@w?n+p!mdk0Il4^^<;hpA*37-lvdCi{CJ$28 z&fxX8l8PnUql1$8hJP<#F8N($o?_6c#UwsDsBlnji!@FrwIwl%GyPzn`iJ*J4R4`x zFqe3$e0B!;9#=!T&D2~RchhySz?8LKiL;AgCJ&ylW0$jp(t$n}>jy>%7W1p5sccY) z+pDyZQ1hgvy5IbMO1Gd`t!yX$T+W3P);dRx%E}$f!N}!VVq`UF!a^S*9mpl678@VA zHyMN>P7-*6+Di7g)IDviX$kmD}BfwB6y>xG8T>6t^ zu3^F<&#Y6n7Hq@ZDemHq{YLLqrFQqs@mD_k)xp^F17%*$p_eGD=4n<&ckFZMBnfm8*b^k{!Yo(MSRbF7x{}8d51K)^Vt*Qt#jT2an>OF3-x%Ql z_}qk#8)w?+BW;pVF1vc;_SrA@^UBf^Su7bmEDDQn#PTVzs7)jRDB7*bV3Mj4{>Q>cZOeY?flc&j@aBDcp1qC{1+VL zj0~+&+bzh@IxFwl4n~QHp~oNm;Gt!8Dv>c4x0C2eIwqsW zDPj;$zqB!`ZHXlf<3$1M0Kch~@Nun3#j_$uDpp65S+KVo5QK+&w50n?zjy+tCQydq z@G!LZR8S38bnrkYPs_cc&4bRcOf_~zeGY22-(@;X^(H(jqes$G$X+9W7sfFQ% zNGXi8vq*N3_q-w&@qem7+E_*A%w+FP7A6J!V`zHT!>p^x_75}1m4A12e=`7LO%th4JCKF;W_2qRY{CXbv#+UQ- zPJL;Y6`8#sdT+*A`iFWV4Rh9)hPmk0)mZzj_%Cbrcny~~up+7WlgbmO9H4(~!hi7s% z#jV38xOcy%_`*nU$uz{6`wRyR#0hyR6_@uYT>XCkgpfT5?Yx2`VBh@IIVnH0ibyo` ze24m9Y;qG!^Q%1%xLcl?YTl>Xye(EA7y2vnnn(QdX|uvXD7jHQt<2mj2rV}cB{|Bu zO8Ic!h=5zOF`OD+BsWO)6;D3v_kQ&V)@#+(W*iw#gT_hzjNz(?C$Dv(LqQIANX6+{ zHWsykkx+u;O}m0k%;(s}Lq98VVLJ_|Cede6D`L0U4>qW!Yu>8b!a|fhYW~o&`ieZ4 zKreeo`Rgzr62&9ZjEZWob+b**u#r6JTJxM7zJW1#=7*|A0+noYpbXYo2ip>x>wDVk@pu5+K-vhh!vkTwZ>cxG z8xqf%w{+YfE!x@@|1S(`33C@qXeQ>=CC3#-J74kkn6Z)I{{?T~vc@>X2S-$-rJ?;3 z9b4<`enGqw|2n$S@^xmnWLB8AwgfcR=44+3SA7zKx0}Fd zEMDLdin-YtyN0gX%xuBE)NCDxTbF4@u3};^!<$_wQkom!m`WGpTjSB)I%cGWokk8^ zTjO1f?7c`91AL2~ozJNB>v)k1;VEzzJDn%9d>U=<@ld=Tm#uN|*W)A)UJ`x0YdE}D zkwkB_w?F1A*Bt*hVFv15;1)xCof*ou+Ox9UV2&jQ0&AyC8`~~vprdVk{C%dVsd_8Y z_ELkb1r|QpM4el=${rW54OrSbCalRQ*eABO5m<*!dFt!_+L&M&;lbiV>p4JZbj^1i z5l$vs3os_{X5W1d-vSM-B_-Tgy3Vc+ZXE-;D;wY)#p$>~BfJ!c4yWa-EJ0P+3K+!$ zgxL3M;M08eXrdtW8QuA_fD~k;gEq#wx~nQyR#12(Q+NE z+J}j^Gfr*OFlu$z8K&L0eM48xdMF_C@R3G7;gn${V(P0_w}a-EVnVK`sE9l6W?@2- zG1^v?9~s(@{DPrE_LdRD+W9Qp0-aL}1oZh56rfg@0HPW^nO>8^95E8YS+tOfP6zMP zT+7nJ(hc?Kf7*5SnFgiugNR*)p1o4|*}(L8-kY+w9%*gOL|UU41rMI4oI%FuA=SIe z4V2>sU{dg;V7KMcw!Sp4H~I;qpYG|ti^8gfx!G=f!h3oyuG%54Pq;~pI;U?U=6sks z^GBkWUD%v6S?LaQmtav)C{94hE+pVn;wFg zlce7eD{IGQJgwD6-n%n%hem|KNMn?s*K3N4YKSGAJDyjbOMkb)!xL6lywQl+-zk3H zkz%_NGfzXu&Myj)uq_NxPlkz@C%j>fC3RVfW^|N=uk6<*9yr2Gz7ft3VnWb0F|7 zr#~PB{E43o=nZ2f&bTCl6ZJ_C2!O(lrDTSaFrb5Vb3P^?!_}Igi5zWMmAVnZoQ*^| zyXMmPQvl!*)uNAKt_N2g)Qr>cBqM=&ic($yaisM_`aC#dTr@azjezng`%WFoB^fpQ zpK2IPk~Z(hLKcAtEYRnydq?Ugp=Ve99#u-AofS}85DW{4%k<0zq$MBX)JDW}QzwjY zMeXQirFq|MgOf~S`f1n2-k0T%O3yb$t+PIn46sij&b53LTile6Hz^8JpYm(3t@g`m zqHCY_$HJM^$)eoc*yJMmmSg?;B@jzwCS!zHu*N~`c^_|sn|NON!`R0gzjMq8UA6t| z2YGvS@b$TB7zh%^uW^_`Xj0D=>7l`9P^cmrDQub2V)Pmmb=ac1<0FJkW?cO_8hW&x z7Q5dps2~TUiF6Yar||nWequ0b=0F{smj-)J7eFG&RYTpWSXaO*FBN9gn3;_Dp*9}| zPo{aMqC&hcSWH4{@C!&Q0)7m9Yf+QFy>&bh=T17B1z~T|LhLIIjS7%Wh>7Ab3w!7vF#zB{ z6i*t3p9nKD)_E?IXU7L{Hwg`yh@sjnC355c!C`a?p(l{<<+^IJA|eJ zf|H?(zu*y(U@1{Q=#h3vTJ`Xm=K~EtT-xO5(D?rJGw(T-76txBdb|}L%kJx6+NV}# z!`rv6L3uaOHWhDtpIb%kY-|i>Tcb$KkN5z=Qo9Hi#LoYl$&mh~gF+1MRsP^Ep8lgBdHhFg5)9A5dex?~J5#V$(o zOKY!HZWzCL@p>82J0Yml+tbZE-#v%E@M#;-X{Lr&g#FuiP>lT2;pouyl#zv5CHfhi zVN7m+w+_Gglrooec=~eZzTDA`PPZYuCun!}^e!AKCzbPrXb^eYp0wHu*W5+FMSQt1OQ>%tUhNc2aq9!L6NJ3nV`Ajs^PlH)kPP zT%a(sK7<09m?p|U?~MhO$8R4j=I*IX%dD+6_C6G;nqR55(}Ja#%M!7%yTnyvmp7u; z625W9@k(VlPsgl9wpm?%nGxH8jh$~z{_};nqP%!5Mmm?w>2Ly5j0a--6!4dRY`Y6n zA%$@%(~MiW1X)t9s%=2dCyqKYT4_so%9Dv`GjzdmeQme^*Fk;VUTu5ZMd(b}6%AS9 z<@*#GpT~-tB|-;mnJY=IyV1sdBLzB4WlSUfHQOX+@gc}4hRw+wbw@~+fUCR&kpikR z0%R2S znn11m_QeDMBQ8^ zYsw^&c;`n3q|Urs6R?$W{e-uvM1k*I^1Sf&YwEIB4|Y*!yZj_V_@mf3S_eP(A1!YL zYd%@yUT@+Z){p#Zv)+SvulqLC0<6^Tf9$MKS6~hy-<08WxzZ)J!E^-5S4gD z4oj|EH|-~T5>Jw6G|C4srgpVz(Y|Z7f|17~NSQ?HYUF7?0iYXb_GlEzq4U^*s$0%L zVM0TAo?%#`iU=Lr02DGf(=>-hUyFUg!79{j`Hrq&{=f=r^`MgpcUrvNNH8>DvKk5k z?z^h6#InlZd^tNJw$Tw@ZbsQtMr2pZK+cm+U?wS_)^E6|rOsj0nlvLIh$Zf|4h8ST z0RBdxM~naSxj-(WJ-I%H|jvd-(!?ymZ#Ty^Z z-?}+8G8+f1a8y?xFON68jaxK!`FK3JGjqy8s$u2NhRzsfwml0Ue4CW}df~GtzeL_! z_HRe4vP_W?*IY|0n4f^{ZfgSXJnh{7#~vQt)$Oy%e}`oP^GasYul{@ghVvud=Zp5; zzD#I)f|GxmlpkL(hfzwX8`&(#RKZ|nE;{U3fLbUIi5QDC@j2gCayIycN zSPD5&ePBQ*WaH@CY+|6@msdw%V63OvqhT!N(b<-d?nA(Xd-{q}OG!?~BW#O2ZX;)H zxb&WVhuuneSw8nvXmF1}mP(g*d&ky_jtjlQot)N-<`C`nr_}3?2S<>o+c+FrtByg@ z9q~{5$T3D4#lDK!0t7noX!P}!HOsz;yEIq}U*fTd^SXlttU6l?hGTcmD~7J_8LzD} zzyfyP-Yu)qh=|OYCql6{Jx6*=9wNT#gtEI<5`|W>MS>qpg)OS6tofQ9OBwt!`zMPW z!H}PJsWLKjhb9Z+0L~O_eM(#>2g|gzAbDGxjS7Q|lunk$hYGRo-gQ+N>VxbdK4b0! zvzf4}o0a+CL+j>tNR|%-VIy#HnqXE{Rm*TmsI>R=)84#l%I+R(yRyBX5YSJWcelMK z`jD#4AdEG1@j6p3ukY2Yyx2Yms)doU8Y6TKI(+Pxaxd3!j@XRHOa%xc+*~c^nOVJN z8+V|gmWc*P9~mXzNXydQ_Yx`3Asu%`dys!7MrJZ%MQ)d1oGfz6y}EK16SdmI+V3ak zG}V9F7nz88+p!Q=K!w>g{L$x&^Bj*kyrIUUN{}Z?i%e#SE7Yt-gHUWTi7_+><35}m zX7+ei(UC7)V+ywcW{W@UaK(Oes@;ZUgVzZHg?8lnx?%{F_nLr7*3vs6;=hNdKyPfr zEGKs9@CTyE#8)bNhJyfm1AMyJq7D=|(oiDN@=g$3wxkV)5#QHLmGm=@(6=a5YEg%B zn9GI^&gaWAu4vv7bV0bc1BWYB@bt3u2FFt~runJgo^$U8Rv;0Vc?PNh%U5$55xSO4OgKw|wUmD|uKit!$TQSjT{YSXb ztnVDUcar#~{OaOw0}dr6Q94A5c~4WXz~G5H2I;|7qGH^v_I&UO;73*p78Wjd$wvEH z4+e1s1hunfl_HE0*Vd-7xncneb8FF?=J%%sG7W=+QE#N0Z`0J)&H4@gnR-HbVy=!J zl0VNR?MiUSkQu#-P~w8NJ-SJoPtz}jIKS`-t*&B0<=(!qA0T51@Xd)+8lf*(sS4{m zc?FxK%-YKzXe2~4;t0m$Zt|VjQwzp0U+~MpYxw3*Q^qd`=Tn1h6hi{An3WrIL_Bq6 z!xfY<@^=s)t%N`LXw8;7DE`|=3$fCo@I#*i+z^vW7>sx9(Q84*juI|52}OLZ+fJyO zwWVDL!^DE-EyXE%OsfmAaX$Fkyk$Rq56~?eL@Rr*NCk5>G$sI+U3` z*uueGp&B#gHHe=iGo=L~=X`a&{qzda*vK6`v~h8!Dq!Au-hSknl3gj)d6f%2x=;*T z<5@DLH#FKDJavay2~%u{;H-&dz+9pN9c|o61iboPW^t01QZUOM6)HCupLB?~VL4Bz z-bZXYqXTy-eM>_?EF?JJj}(r^){19IjAVy@;q6CK*XUyM6hNCCA3@0+Qrj-fW`ntJ z{7L*K9#^?0Fi)>aRYL)zg3#gHS9u2#FW^Nj#v+(CF^e5?{Ct*?R>oT`%#J%V@#s~1 zcf?L6)d8d7JJV#-9rTI@dZH^aXwRDYs;YyXtpadusT8xcgEa@YCBphihgXvyu$%_c z;@T@#IajOfVo`zbrPA`N3yYVVZOJXE<56K^O$l0?8D(-FcBSvA_L9eHSwi(Pk^0eK zvXh5-&~s6zd^L)cXmq(|4>>&l)~B%F)mHShX8Z>FQ%dprjRfz8`{-{id*_SS95;#; z6is1ys#`+D3(JQYrkI;sj&E}EswbYzGaU32k6o^#k}vqN7$s;#HV#tr5z%Xa{E5XO ztSsV2RO(!e{S<5Hl{ZfgvXz8TaHE+r@j=qg&TN{eu~#H8%z(MVV6~xMg%?IqRrtQn z0wGIxy0G(L3+Aebd>a^~LGsQRKu47uJ~H!J#V|I2Y(qRX>WGds#9w+xC~y_)EZ~K6 zvq8y#SThJ8CLjB?XDntcxhSP*H2XCw3b4Ll}I={XU;nl#bP`Z~4VXcQPKV$|vh;u8T8h9*^E zLe4ep@0e`Kh8EdK2trkj09+?wgH5%jOe(@zCF0#T2&G z%0t$aNJ!Gj;af)Y@mtHSyk01ky1NUfdX!|UaFd?wTlU43Me?%pFt-n-+MJuvgU_er zZR^U6%)Z?D?g`8BQ94Qri7*REg|E4Wpylz}$4Jw7S7&zN8myn}P4dp1Gh-omv?)sc z0p_d16uIw%ut34nEs{BGSHl4=D@pB`b>2`QMOZ_hF^1T<^9}sxW?w`GJ!B{3)T}9e8eN}R8A{>Av`3_-#}`+b;Bbm%MT(G;vhzeaqO_wlVKAZF{R#dS(7I}OH7G^IG2k&gi&p1i zldiR^svLoD7Ur)NOk1}U9bDw34d~kdMpzmQXhw2P!t3QGX@?^DFN%mp$-X4-_Oek} zGe?4XVoRE78=sD?AXzZhtSkC#QXGhRb1O?raT6@0^;Uz8Kcn7Duxc+en zZ!rl>{`U|bs)q^4CfsGB;ZURE>TbY>u>!4TT8_jsfK_>=AK}``OKBfOX7d$)_GuDh zZZVabq!V2iate6+j-6Z={yx5~Z1u}-(}l~d4n=mGqTj3Eec5eV3{HD(o-zWE-Dad} zyJ?5p)}a_{sN+uYp-7X%n2|_f+wp`uG)yb_v|07Ry@X55 zeZ8%;gt$LzIpfa+{R53Z_KjLN`C<%LZ15_*H)jD6l-iMdQF9~02;gV$N}MjW4^ zo~+exkB+onl&Q^kFLe9d$~$?jW9P)9NVxOp#AQZnN;Q7aY6gmpFMY~R>M+F#VE5RN zHw+eOD*F3;k8}!*gv+7BY%Fb8_$=!Ol}845lbqB1B8>(f+g#tfYSI#0x)Qb2OBT=OW!D{rn|ysuI3 zyk5K50bwRrRcX#U(ShmZUOyQ&|GC7f5-Ri$#<7Y*ybPPjYSXK0QSUwAb4?DTO-XR6 z8P;a9C*V+5WVP8kej0xapA6ITBxXIF7mf11ov{B#Ibgo)o4$Fk{IYB$>U$HVq@=gK zOZG|6hb?|}bXx7+tlz7w?JceN?PeLyoa5ef)oZfx%>N*}?AwDavJZ6p=Eham2{-=( zR$xi8UF?;b&60zXTkaEX^NsO|IaOX0$3<7k1Bfhq#^@Y; zT_5xG>8-7doZj`SB%Rnz{^6rdfScqv`EgEk#s{n*R5JMhzW7ED{BOUDw*#Nk;EWGv zXII(mdT;CMtLAy}#s-ePu(0!pctw8*h`5^pXLYc?!XdZ7DtN{B5`ja=!_)~DSn^T=O@DzyU_And^dfM`$133$IOJp4 zfeQkM99^`v^@qPy!h@M%uDoGbODwNJi%z`u8Y5Vo5zKHzLAlvm@M7rSM^9hyH0)nc<1aXg}FUDS3YR-P#tla$)NU&8yWHbcm+>q(8F zAVK909+$L63_>1(Hnhrpix)Av%3@Q#E<8`TEiNrF6*_nV-N@K2JS^JVMYg@q3cciJGy2^1=qlCD_2Jzs<{lX zizds+>&ki|d+6E{aX805R9qgKxerFnx+ieg-gL0HFp`ICSp}2Dbk+WLRh&}sO;YN(4Mn0p$;MQSLi zb|g~y#~QjSsdBxkhtEREx*}FmVTbkEcEN+&6z(-yTB^24;>dkC+TD2$HI=TpTWwTF z-d5e)k#0H}8sznAk#goFEm+TBB7u<0@0p*f!yW^E(t_P;bX9{V&KRpIggfLm*G$`` z>qIDVlvn2l=T$-}r`d2QP+)y#*%Nh^2OLgeh=SU@U=J*JUqEBP49b+yT#L8}P#5{H zsk%thX=Dh${MPk|W^u&z!!TcgfY*-oBe`nRMEc~xow?|{X$=V%D9e$iLEHzL$K+({ zZTRA?Pg)n#C?!4o=@h6~{e{PXzoQ}i1BDWV*U5Rl3f4%4%<5-k;|*zAA5}$WuL!Y8 zLZW&-j55wk3ul8U`i{-V;I=M{hJ=bO+H=l8Kp&}ZotR}QLW4COVZj(uc53zzMod>x zSNvrvTnSODl(Itboga&mnmX-_dbkclRSE6Z@EVs?0tO!0w}6bid-lNG4b0<^1wel}%hiFZA09vW?c?C8k`mqg2(lpRtPauu^~ zqy&PuIiK0iT3Vbc17ZdsY6gV0jxl*GxnrMWJx?R$$r0eWPhlCE=mJy;WJ4-bIPs&S zBz|9QiUiaY-Ml4_ae*1>5- z{2=H*dja0<;itysme>TI#*eL8mb;y!VL|*Q+ANIBOb4+c>38H=v%U45o-sB>A+FfCxg6TZL*vHS!ukk8jH(4|e~S1H?yW`!k2h@g<58iL=DL$Yj}=7a zU-hbWckS)*w3A2pmN-&>8rI>^zHi1dnmoY7n>K&?LnU;oqIa_5#Gh~IP++gUhdpB+ zL%X``m13L~5I%u}Mk0)vgr(=S5oqPd*weDSIQck%Jlf!CEBLH*Vk2>K7KpQ!D3(JP zT&Gn=L^p6AQ~(S-om+y(u!rK?KuStsfjZ*OSrso&i^O>Fcw*Ol90iB(1c-N^8_J2x z*@;Zb=tpAy8F;}Y`G=D?9Mq~3*6Qni?#(3|RqZ$`Y)+I3v8(1^gDpm}U8SAI?l8>X zyby|#op^sAjY4nuY&526k{WuNF*l=~3FX4-IlU)nQ3BU(VDrhTG2n_4jrFq4m2+&( zu0~8u-*QVb+eqLQJh%Pr$%3WiVikU$+$~(YxzX(9`OLwHLDR&vE-oN6d-*na@o0la zG*vpO8=#9>MmevI$7nM01T{d@7-rY633qrZiWmWVOe zgwc0Nl>s%LiH$NFTz3uH$1dq!WPdi(2dz6MTm;5`>pmCgK4k65;TKv@XF#PTTh5NJ zM=POnTkm@(zS62zA}44(;pffy|LWC{wC}Ug4cOsU2+hvP72&&A7o4^}#+Td%;z@@! zaZnA4iOi9)7E6nD7Zg*BHxG$8{g2sTcB=KZUu>T?H8!Rw^tt$LVPX7Droh%g*N@I6 zxVhP4W&y%a@VmA;i=Y6D0gQo36q030BIdR6AqKX$by2N_BM~vcqWP)pPBDt?l;dO~)Z96= zS!zZ_qsf%R5R&DMYxp@&A9TMq+CpX(&3wzVA943|8FNdrN89{^=TW{aO5#G%=U+|c zxCrgT`Tc}>q(@=+#R5UK?dV3{K|J7hilqqo0A&?{oTqGs^UGPm_WOW_9t^BC-|hEk z_o4IgOb#<-Z6>x1n}8w+Y6qw~qC3lP)s;l6jYJ>aa_+x!^IFOJt-q_oG-3wzuoY|= zHTLOH)UH|=6)^V^BvGCa(+Zrx#d98hcFnwcH->IY45kVxz_25{*3>tSQgehnL1BJ$ zCufHS&!7dm20z{pKoMvwC|6-$IGAGuINs`N<^`#{cB9C;k~xRL5Ef#POC{WnqN}-% z*dP?fmNbMVQN^wnk?V~08zj7i!L(Cu=U`gK2Y)bi={d-x>%a74gB+`_fd=)&%;+My2 zakr;U0x&vEfKIWbEtrgCOy(!3H?( z#K=IG>I1nxB=;C>mp!ANLH^c6KpP$zocZu%nw-md;rzaW!}DibmXSCt0iZWi4ebS= z;ZK3-B4JzJmNp`-c+Yfp9wnCyA+{-P=I+Z&Qi>PWt0B|9`6&L7aAL^V5h)*k0lNLn z1q%F!A5k3s?8BdpsXe>e1nH(C7YaC zGlX7b-UH|08Al<;ORcjKns}b<_Q?53g*3WBb7)Pmz1`N_T+E!mC#je!}nxSKXwUi;v**=T8vPN~1G|X#5N-WmI7wTg_E!-Blb{A^1tH_7ZS(6u(8| z96;c(7EGp<-Qo+;g?*IhH<7d=hCKthC31INC0EGtAc6c7HxE6QdJzDIgh?)fcP6awf39xy_l2wB%Y~+%ipm`3+$jQr+&5;0y0^hp$mW zTkJS~@dD2&Kg&kU?AiV~SCuS-H_<$9{0$Gz8vZJi>QI#|RINH|2E6(Mu|Xwho$}N= z@Upnmn}Dm~C3v*k=dQ?7Zbg-Pj6J>!v{^Qc)a7YPn!;`x36l0|qGQ>e6d}9hvD|6A zO;k#Wc47C7-b1v_+gm_|BslZR8BOB0p@p!#MiN{LF7lIo~(i8nwWHtkHi{u1PaV&jLWc= z-;T_>|Ker*Xzqm7v1iQ7^0NM?_n9>w!*>O(;fuTW_UNbmcG-PJmD+=1;o2lrXviS< zJB}x!-*URhtNj~AVLjFEHJCl#OU$e2wkJPf#Y`Tfyh(0>81+K9!{oa6=sb=BkbJPq zdmWe%SU5oamhi2?dngP}><|2 z%xe(3CGoGE6T0&!*CwUwNQ=?)mT4W1$QfstevBk@{W!=I37nrZW2Hg@@af7FE6M?W z5XPA^8?~ohK?h{Gyr(sXgWk+cm z%{867-Y~wJaIEYk)hddi8OQLy-+y{Z{(X38N}IeX5Q>+D!4IDNC%QDC#Vx_}-k(^E zXI4wiA8`7-7Xj>nN+{`vfxBg*o8-|`eiY1F*TiHvaQ1$yM0PjW=<&EUf~^@AYDOQ0 zJ2#G1pf~(gkoX}z-vZJ&RX@hn!7z*BVXlPFK5m-h?V>;-V zW`X@Le*KSsjB@*h&#Nb?zKI?`bliS!;mf%-_QhQgpd&~8`q#OOSv^1hieCL%_D%n< zyuKt2|1N$1edkv9%ewmwMPp2)dqX^un+3K}Af05?;@9k%T8nVNHfC}4@2>FnqASMx zJ%yZJ2OpW!i{kk;yNfh#|2_e*(s>hk9~LuYv7{3$4hhmc-(z@__xB=#g700i6K>C? zUFZM6({1OPB1v-i*3YsNi#Fnx?Wd;025UGqT}6~+VBe!A0noGHdfqU@)5!T?QN<~M66y?pi@0IJCW4+r5 zkT|4tmXg9My`I`)-3)#-88m7YXC7|+s}FA<{VzmY9H(#m{;z-C@+WV+TN*OI=|R0k z{rqc&Gx7S%;iH$`h{WIZOF9PWX#DDnU*AV0{ta7S(=mP-|I7Lx6n_0&0a75iTlS%~ zufssR8@SP!|8}6hudx6db}wW%DrndBY{wCgMPoTu@sB)x|Urd=f`gYGalH#Ih=6Hh%WNH zx8G^+R6kn7akjNb*Lwa_9P?i0_kC|#toblsKedSkj%KWTwYpb~{I>2{Hrk`D+WEdMr$poj?CJxFz znN&IMIUl`%?ab-@l`S3r-Yqlf!|CS0wb0n7*x2MZ0Pn?8zjDC}(@z2bPj?+YUmOF(vr$p@!Du(& zB|SNU_hN0oz1GVz1PO}S&kFSJ$e>d^y(${AnGJA#){iL5FY0AC)6ejC?SpOWI279_ zk=|9736gub$N9XJ`D*dav|xMuJS6tZ362xyyWVpk_77PUZ7>fp1dizcu=VcIjQ)AP z?~^?7OGG3gYRv9-38CEyNwrHtf@pD#LbZK*TzYrUSu>}5*0d^&yF{pwLZMK{tl5eb zs;SElRn$;QNr)PX5ZBH=JxJWPJ0a0=N%EYhe$%t}{IQ>9S=RDrNWS0C=ly=YP?(|I zN7g%Z0y(!+1LWqS7ttiK1IqS!LC}Lk={TV760qx_D>FPuwXuUklg*~dA=J3amUV?t>;uwQmcb^0! za{x^QA$>Aw9O3K=Ci z%h=Y5?~ZH`6o02kG1uB7S0HQVtc53N`ESiOiNuCO0cBMo1AA`-j;+lTT!h-;QC8M} zDfw&ULN4XaWR>*TNn<0me277eG<=zJkMBBUS1k_#QRL?P0( zmZt?fmcTtc#b!M?ZZ>3_2l%+7tb&iLSskFe6=bET>-al@ADcIVi5vN~G9qF6F9o}- zM=_QuQ#}S*DwZi-UdusR1zXW1VKH_(HVRW#o{&UKk=0gp0=UyAz$&rAZl_s_tn*7$ zUVD-{g*S+V&?R=xU&Dgci0G!zi^~>0V<`6u(kttZo+eI|XXef8o1T#o+`miOd*S`s zM;BKcSkmsuKp}R1S4eu7TA{(g;T52{?(F4h`mDUQ%(>0oy)#<9)?xC1)ig)*aD>?& zhUz#6CZ>Zx5C#(;eTCKjq8A(O-PH4xHrHa9VJM*7geyl6dsNux*#&5$Uq-4 z_sZiU=r)FB=vNq+Ud5y{Xp^|dKoDAjg<0PGy1mGA7jzT33HQ2X$CKG}?erW#_LztXklmBiH_#8aOTaG}r?K{_BF) zD4)bI2`ho>_D(95Mk5hQa90}G^!Ka9#anF>w|(A?U(8gy0KqI0)J}3ZnJPwC-v_}f z-7dh|du6M3rre#U_yj~YFrmrf*7>sy_;a*X3G&4&sbm1;g2RL%i+k!N`Dk$tW-7g# zOJF>AuQm7Alj*Na`eZ>g_Mwa&gu+He3PV%8fWpg({j=@8-1a<(vCMzKL8j`9yNuMn z)*wUi5vB3*Lu~aV7xR%-0=}=5PQyaZlawi4i2!hCu-4f;eV@(#;@ZASpR>^A=8)3@ zM|xohGdX2)j(6YUMR3|@^k9MaQq4RK|FO4+SiQcp8R4cF5vZ+{5^At=DP^72yy$t{ zw9&3Sx;@A~t$VE5%UZnnb|7K+b$pHp~IjudoB%6OxP{<^VJn>InlY3sJ6Sm1)`g~D8{QO})4sc|)K zg&W-1+iXVRQhtmx`3q;{eV$6)^?l&>P)iLqcknfTzI(}2=y_6bu@cMWb-m;QPrdze z^S?hWKQKGE@1c8nH#QyH(;of$&K-VAa`|m(-nfk>^Il4C^T8dDlhcKf-AUKPq(SBE z{ZiNU)!^m0=XjmyO+-_S$I+*7hqT8*Pi9}-F3cta;d7T$^mixRgW`#?7pY}31FSF3^ zduXSzaG}!mFA5Xx>@EIR=XZhV=8IZx6z>>7NszT}aU?UD8tDQboa zx|6RN_ip^Q`__8N0yaeK81>%40+zGQNGj}EqvEP8L)EBHr>&3A7Bl;?1h8zrI!+2> zx^WJM*WR^v%Q|$O6K}HWFuOTj?qmy*b3}Y+Xo#ogc9xKDqMW&HeJC*K^562`JXgMn z?C3YrC8;lTf8#BySg6QZ8Rkv>zca@I;iLq+x*B?vE)pZf;*Wg#i;2~uF|Ydvz|FZa*bs~N6=82 z6GdOW3*l(I6X*fI%>C2%%C1OZh$5%OH*3p3YtyYoz4eM0nBVaY*QX)X(p%$1b137dLFtS$6q*x37`X?1(EGWpu`O7b_A_w+XN^iyDmssj- zvFvhNY`77n-V|4(Rs7_D18h@A6&XRhu=JLmq5D=%C7~9NmW2%$C9Pv9<4Kh0@o9b} ze(|EW`Px4-%ld9vKGEH=I0Y$Q8~U_9@!Dwe%GhX*HAOQs{}jX1xn;ob#nsq-ac^7S zOm$@+yyEtQwygcGRd6(@;~SU9W07N9n)e%>bEp#L@@&ESkJ!XrI2|p^`X*XFWR?Da z%tWkOEcKgGRWLGBFM^SoZ5^+?ROlBwbr~`j^DD)cFy@5k>TI8d3HK}JXh-U#M-$pr z-l$_h>5<((xj7V~TRIxsnw1w1*bC3gO5V0KIux{aEj7QHc1-pS&C1$vqEgfetGphk z3AesEb08BUd>`-(a^3ixG%5}m`ntQd$Y<8kepKhiihh?ekYeTnX3FkN-_0Pj*Gb-B z0r!rO_9y&OTi>+4H27TkXl80r?Yc?+uPxJ%AnT$1*>_}b^5e3?(gKk&ckC6>y`p(7 z{ubbyZP#O~BAn^Wpp#v8?BUBm?%je>E1zji(WkPp>iS$fn?2Pt_-1%s(*0@m4v?#= zIR5-sbE&6CJ?;-jC};_67X6Zv8MxuBzR)LvSHCsL#Fxs&8D3WY{k;#T*fD-#d|9lq z;N@ye{Jz6hgT}s;f9!Y1XQ^Cy?(zu}V(0Ho5VyTQ{4aYAo%R5J-^Fp?amj09$zx{R z$9eRH-~Ov5CwIz-Kq4-E=zOa_Fww!bfbB4n^n=It$QlKp_LSX}PxpI8mpyDU-A_y- z2acex97Q78h4;n?hOpq~z`Hl&HH#6% z-v}6a*u*7Dsq=K&&xsyI<_}LP_38fp(_!YJn(Kpc@VcqUAEMB!2SUJ>?hjsMR$Ht~O-2YgW6v{g1j|0H z;XZp{oxmyTDJ|M>+rq>}53STCTZs z+DJI}*!B|lKjaT_4;`n=s!V?PB40lY|MjB~!S9bwp^8&XCgn!>(sKk)t3Nosty3{rv8+=eW9O!ubx;ZKH2WmV*B6`?13?K{km|MhDns{ zURrOTdgP_tgVTzie@ajp4bt%JPR##|;IrGIkZ>~Cqbjk?r_CK~iR2s+iii@7vp`r^x z$NMKG7M(>lpL)Y!c#$M+>tm8*(J1XG&+bhJ;IyIY_$zG4!D_%`c23$el+f>$(SvC~ zHr608eX9wRt+$}1* zANoFaoIxvlonLL*%8Y2vnQnQ&*B=|8d}zNkFETAm?G$mdXmsz(NA3mo-nyQdV*aG8 zT{Qn9lp(ZPvGlQ3T@hUz;QXom3-+F)t8oS!*P~C6rJa273@Mu>h`MLjKA0v_AD$*= zBF~gYULJ2T`t^O5r!witfd-}AP`fkoR}bvwDMYt~RB(My)!1v>ei7FdKYttPtC);m*kMv3%)^$Ez5#nPDXnuXGfnsM7;2F)=^Ybr#amjBOLXiOQ z8p`6AZkNoh_!Vu2Hh%nXi5(HAwu>pk-&Du9HdfqSSbW&%I+0PhM`m4pPJeV;Jh(sa zGM*P2$P?a?H`|n6%YvV@|wF z8{+gutTF?E6$yGi9P-|vUyfsUS21ERl5DwptebW`t7;?FR>LAqVu^2TM~_!ahrk@} z)is2CE=9dY0{;+pepk7-MxN%Hh214g=5IeTXYWKmNR}~IwaD7h79v{ujK}PW`^quOsG5edTMjewi^$B15{fBF%}OX``}CKyWFk&zr-)P zD-S=NEyk$LOuKP|S-TNXyGP-nPJhSo<$=d(+4JD3m-~6ag%Mq@UX8w@o}I14h{V^b zl|pM*kKlt{Qdd_ihvTvjpP?JNM~ZBEcd3n~(XXE-mfsxQQMY$o$C_EYCXss=UEwpd z{lk{v)nC5)yKiUc!S&MR=!WCr#y6jI&(7x0-JqDCrz{;RYg8W+SHv=lnb?T^H;=Ju z{GN7elN__eeZ(2L$W!f9et&mc^udkO=qyT)d*zm~5*vG)Nh(Yl>aI!d+c+%s>_B$y z5l%Q=&8O^C0V>C0-SM~g$VD-Q_XX&=Xb6Oo&$LMDa>h^b2fxhQ?mCB!1PMjGL~(U~piy82K8+O%lTateB`I zqibhUm^$Iwm!;U)c<^_La_RK-2}_mjH*xk=Ct2vy^n1r>pxOEbdOr{%Kmt^$P$-an z2j9`8D6L6U_B9q@&Di^}Z^G(f;}D z2s$hKwcnH|=e8Ki?MrY2|3(Q!`I5d-%V1)elZ_!5k`y@eziP{U3JK zcM4$m7`&?vx%!V?^;yz?-c?`ozHv`#|2OxfHt2_4^-Up_@dJEp@}%_7@G(=F)MWDG zy${`2xbg?>0j=BB?=r^5pb7Y;@-k(YXIzqez$^va zQW(G2>Z{w0f99UN`^G&vntGr0{s->KX>gv~e{fHRA!y6f^?GA5d84NBfVjRF-H;Kr z>a{Qo!EX@C8sGArF3uvyrZsc{3d6AJU-uh~CTX@rQKDt_Z7X)vpS{U4-nfUyy2_~G z4P8&$8cW;*F&DNHvfE8+v%79%@3=N|p5Rxp0kJ`H*<^lo*Sis_nTNI#^QtFpf#k2mYQ>eDU=a%Gf zLPxk|u6pt?Kc)J!+RwOlS@+I-&EgB$QLCx3+L_(>x?PJOlOvxXrKIT7IwFGk!YN4V zM2rxaMvbQf){%yIswt2v@~C+GVxDOIO4G+W^80fgPA%AcE9ef-fZ_$~0xRp3f)_gF8$AGi#g4 z&=}YPeYwn_(hy#j#N?iGGA@^9(>ww^CAfCk#!2m$O29)lC2OM!!bpS$9pkV+jV;9ZmY>$86 zN4MnkCBof`ciYa%V>E)4**Vf6tIz3C=pYe`$Wlp?Tjb@QQQ49eh8?35|jp($qbqr zi%8ZI0FCKg36Qe_P-tlEJC-Uz71fw8lQ%m)0UM!9YN*PLAOk@hlvHaN8=xs<7xJuWJt*I_faER)V~Ju4R#yfX4E2r}#3^lAF{@Zn5KQBR zpsp9n^d>`C4V7jZgDzL7@W$cR$TUOIrpHNIHes^=N$A;4Ti-mJC50-psB_m&ESVg^ z+m0k<6QxaU#6STlpP)4)#cLYcA%LRQ49=s~=7F!Y=Nf*Hzw!bykG%PE`;y2Bw=zQz zVY(!OWFG8)M@uA9QezklBu>e$6^3`Uf28mY{-18_Y34B$%5U_lyH z0-F@5$lD8*sl4yVRDRVhWUawKLLC?=27-e~W^$4m7MOuwkPd90z;cZ_-+Wfjl++SR z_y!mFCAiheS#SHj7xO4x@zVI|L~C1Taudx^FJ~Q>WkQCsEXU~_S^l>CEaihV@(k^P z9%MD;A)BgZ)Wo*}1}Qg$Q(6CHf<5R}JTK*&%ZD!0u}WXbA4Qd--4cLNuab^Qjr_m# zHZU#f>#t(Bvoxl59%ZWgqPK=WQSO-}XljIJ>Jf>Ks!;GFh_LWVdoO#$%9Q3```D-d z`1twqJ)V_S1idal{vA@mf4j(b1;Gdzafgh0eEet&lYb{DUv1C9n3EG$A}BR)d5VHD zgXd5Uk217ABY_}goCD?n=x`Uzj9g)G-yu;fjX*GLO{V*vN=}TB+WN4OoLPS6kiWrUph(r!E`{`PUR7Aip{ll%S#PMQz;vZR>N<=El#nIM1 zWpbmywq@x^{4dP{_s^3J-ewnp;ate2 z-ZONgTD+I~a*2Iga$|C(Qe0z0zL>8Di2i=TE4Dc!n)|tw_q`2MV1pbe5DZ0v7ZzG5 zsSiuKPZp8r`*f~F@sramBRh<_)xDsQ_5g?KY9!Wkj=GX~jumjNg}A}dW8K-uCF#c0 zEwz?X9^lfNxnFCrHEevH+nYhbgVOeYNVIp;shC;_GBx=UUa!tVd|O>2fLzEVgNhW@ z=%|p*fo2Wi!DyOM70LKS9mvrG0S|!K3Aq8?uVE1; zX?caRsLme(PzZocL@WSi%M)MqkQSmrARsdw=T0vX!ai$9>lNDJet-a&j*l!@lQ^Is zn);LuQr4!E(y>5pHWeCI_-)YfvTid>%}&`H??JBuJ=x0WH=(}|qH71a^bCf+r5J}3 z2r4;0JZz%)MC~1~U13`oz67BsS_Ib@qUC9ZOp#&Bt8b?VgDw~h6Cxlxgy3n`d>dm! zPL}O1kC)`o?W2}Yu?y4?7Q?Y%kV`X6nuj6J))XvBjg%lo-3161xLLUr&eyW#{>#h4z)@HQV%eCX?4v7Zi0#nPkg>7XM?jJ6^0i!rI^28 zs?Tg;NH^mfc#?Dw+DDBlm0_Cve1Y_;sT{*IGRJ%JBQ;#YAeJgjIl6!_-Q|1rV8%Yg zo{Q&>ho}0Fv*@x|0t3~4#Osh+SK91k?M*hk)gQ0n0Wxo6W@j5(9s)s#09Zl>F7g~} zJvsb&(ceMwTgXm39(a5)|IU#f9$6k4_JFA!mj*iNboHhwecE?6Q1MDds_8L`N4mI8 zTra8GJS?u1(8)6Ih{xSl=0Fe*=RfRH6`=&9Hf2k3uqTop11EcX6$&13u5ATqvmEYOi59ZC)N*B zy$-G#(M5zL`+Mti3Qn13+O5x`L1nr{66W!tz~qUhTf_`|1Q+@eeN9h7*RJ@E26U%E zEYo-D0(gc#LDjq!MSL=TjvJ$|Oyq&2XiPa37eaK#ox5Yg4#@9&Mvf0V;EcM!U}8@% z_ynvHNz%{hRTn}j#KPP{7RR?c4-MeuZ7HSQcP&U%=?*-k((v?s3%jUPI`4O{P^CZZgjj9=}S-SgpBPnNQemkeQCB-01114&z)3$+rI#~dOW#avC>)R*| z0bOt=dqlGs4Krw`Q~}`=Z`(^^j5-t3E@Joh+_=%y)1q=mtQa_Sx0N|Pqo$F zIJ00HRV5|GES)L(wd4N3_Abh%emCuH1`3@6OQ^{07b{N>PVCV8eI=;1qn^jUidKGX zGZ!4oK0Bi$X@<=LXcIz`UtHZL$L<-mtlrb3Yjcc1j-Q-lnI<0u%TX{k-cxI7C!8}} zBCjvO-Z@A@EFMs67o7pTdU8R7k{OrN>=xNLu@#5QI;;BuhJMlVv_-lOGTvP(^i(Zi}>r8Uua%D=3cd938;t8yMt4 zqq74N%x9@5cuOpq)fz!dqmUc}NE8Z1)d4a~?gYpkgALLxh&ey!QoGYPRnA%xfG*$w z%~{kSbszT*ay-r_S%ZW@!51|@RHjpnlsZ{X&*c~ECF>U66&-@$Nqm!3N~2W045a3H zGyQVOp}T}!KSM{s`LD`&8&k_=C1v+Fc*%P_m)!eX-d$qAOQ1Wkv<%{@2+#L;>##jU zT^-U%P6*qUPvZo*m`fLVOc1TlJ~6TE>Rk|4?q#x~CaL>Js*UbG50MsPV_18W5#p~K zU<3}>#!@WIcnNWf_#-8-Js=K6I?*rf7DNB)gUq|LwVS4;YS2i@iXz9Z z5tmVzYnyBF%@r|m51;z7n8aGly{Ziu15-pNzPW^p=Sg4}qkhUCe>=1To$wSv^2y~G zIeEW6?2@PTy8zX#-U_KqyXH(G?06Sh;HckEFP9jwzz#o9-l&6*`^-@w(Ncq_3}5-n zN}y%df^|YpimI4Tby!j5=%5v2a7G&2!ckb7dmFc$^gWGn;c!SUsP12G=B8RKYwgbZE7lG_zK|FNPumG5F;nxgBN%mXljG#R|C2lg`$hXKm zx#9+tB;k68aimHU{aIqDAMHWW`fAYpVf|s}e9t){BB&mQLLifD=I+qp@g5xtPNZt( zITMydpCE{;ry6x6?bqNreLwlDF=PDaMIaV|BC;z2^(71QXvZ`ANq0hj5YSI`rv__s zjD-QN1l`2rQ>CNh+NMkdF$~ZrgF(@5f^wlm8B?0O4@qA98w(RaP_zQo0~hZA17bWy zyYXOsN&vqceX@Sl15 zYifC#N~vWTfa3{>cSRul#vmo_fVg)^!UkTs8gp5I5|tdz-`JcsWQn{P(P(VIY(Hk- zJ@9A)&)gr&X&rNqDa>+HNk&8hwLNtDmBKoNa&SBUv)e~i;t-teq~{n`c|ptT#DrUy zJ;_uPi)Cc&oG;^`Lo9)@0R|-OE8?@?XBix|#M}20E5{8pwxthsNuDM@M&+bh2A0@W z*xH_E36?&!Zz|&4qK1A12NI~E>56QKZlEvfj^tkDUi*ZwNX>*)T3qQIzy_d^_0S`c zydst<2r!)JpBhS>vQSR#Iq*4@seWmn(-1`sh#b1|$37 ztZ*BoF&CN=HpX2rmLyiVW^K2?`dV6N&e1~irdi;lWXt7o#>I6>TpPfvQpH21f zCQ;A$~wpP;$qN4~*&ggj=y#65v1G>u{U_g&x zNpcM-A8%yu)u`)n7B!%phM%U9B&*BUv&JlFFw%VfxS>{3L*RW<>2glpVnPIL-vG&F zXwK>a-o5ozS?|SmktFR)(hZmpdLhl(ac2YUsBftyuO0_fP&w&^wXlc8$$#x|`&wQ7 z+B1OXUO6Xg#RrYTsii0vIJHD#pv`uE_mT829ij1tQ%g7yjF;7N;b!K2Ixy1UK98y_ zUBEc8f?ZMYAqiiy9Q{30gl8|95w}9(rb8lmNH~vWO;uMjIso^lkkwgl$FagM{D(YN zq%z{kw2j~koX46=new9DLDp00db{bWM9$xxDMq40iC>Y9;-rTaLDZJbUyHLy$kYvR<%gvoRB$VUHoPExl*QiCS!&&`h`3TYeB$M?NU;AA`#kmAgsO9g;~p}_O?T#5s< zGc9h#DrBR0U!im{GYGF?NNqH~8&}oE*l~T^Tvt$^>OTz(RjNsKdhv1xGVK$aiSiV@ zXYAUD&~dr=`bNZ-SO_#aSVjvA9oBw~qrY2B>SlrJc)S9*pb}&X9%q+iNX!k1pmm2l znAGHQ1E`@q_KGiK)IkBHsBdurqKv_t1~0&n=sC(WzlBCXtN0Kpg=ukm z=<;|@sZ`o(fD zUrWVU0JKzTPu}gR4z13@Ph(ps6-IA z6p13S5xe_1P$_tc13UpAS*SKIDgXU=8L${@3ZHym4A{NT3VXVbMAgr@WdO}F$wW;) z^A6M%>M)VVTJk$Km~5-KZE9Tb-0HC7AOJ?79Ms{&f`ZYedB4}1@PlnB$aY6ufw+@+ zPseR=g+wa?A6hIofQ^x&>c4HMEhnRsDJOaNGNnnQMC}74fXj*}CxO_lXij-HgkGi> zV7va-Ia`4GpkCZ=zQ6h)>GvZCjJ@Wj{5Nf{J=Gk+Z8fiaVeiA4^E4Kb?1B#8Yk6kv z>0-dSKK!{SV(&@vL4jk<^99G$^t;HtV!j1JgN?gbnLsz>&O|7&1$Hl|D=!>g_4J%} z)DG8bYLg#UHhX?olyE0+?N022fZPKe=FvBSK!N!9eQHaWLB&SmE58TU_H z&u&*9{VI>UDS2ph=P=nq7;UTW>`A@cbula!j;m`RuQpsG<&KxXgJ)Kq>xR?y|D)@r zEOE}wPe&ejvh7OGwtz-=q|{S&a&0^F1y#uD^?q#QTUGWZtv;!0Q`OmJoX$+~;=W$} zQNFO(C%L(jv>4@9HQ`kDk}4v_;fBQiO1Vw-0lqbMxbogEBoKPyM}$>PW!uA_V{Qs@ zab&X}JL!bb=IkAG5&o&ZGd0=g@P)3h3@bpzX12BO+Kz>BpT)Lp0r7(YNx~yk7VjECme^IFgbjKCnkOUG-9geh*?OF4w6Kz1Uq1B%DUXtqE{K}BE*n9wHZMlt0{df}5E)&a>5fH1$L3j0wiu>dkjF?O$#z%HsTAm!ZR2Y2) zkacB;^8u#TU@?jT#!Z3KNcma=cvt5_?LZ=tj(>0hHULQiF3I-8G?_8c^+`t;2!Tae zH4eutuvkD%iQiAi*#PGebKGHk>r=m7{#^EZBooE7VFHophHxl(AlN&6T8e_fsD6OU zn@Wobu|x~As@iWQ5_8a3Gpe1@;6g?x{1rQ{%WrLABX4{}Hv)wN8U)$&aho16LAUAd z;ZDV1FhZMf1Q!9~z^;x7W%L}5s;KA>v2$F3@54^v;(cj0@lk^1SqrhBQ))|fvO+q5 z$OzF*rEF$wpI!2&8aPE~~A6LWse1QX>sGIAD)}1NJ0p5H4rB zRV13o10wBOMOnD}tYqE`3ZKgb!?ES`Dp{e;v^2=eyOv90t~fs+PxAOHaZR1PTz75? zV|o#YfB+Ui5Xk5*s{E>keJYyFq(->2a0FrnNz6o%+KPgT4wuvdjS#p3La$H+>V9Q; zK)LNmZ4A&jh3WB&ubtSP)F4HGBU>7oz1?KMv|Fh@ zEAG6EW`p2LD-}`zAfta|LyNA%UF`^z<-nAS8K{mVO=Ff*=52gCwP|lUJNv>1h=X)m zZ36ArWa$9lGEX-W>I(3@Z9qrTFCPQ<*@#2AP~e|yg+r#$Dl0jy0~~IM8liSA&Btt% z6C>(Ui=#HQ3-M3)eR7gr=#|bO4f$w=Aa*AY;_hm%w`(aSihUrx<{kz?01BkKez&?> zHl0KS<6Ml#C%9oMUO=P+{g(k$AEG}2v?VhgEs++2Cu=gmMrsAW3fM|EVjss#`4A9R zZHX(EGE(ePEk4VifN;(o_*cA@iX$L{1qAuN4cAHa&%&h_zd%(#>K5MX5~8HDLRMm> z;o>rh=?_tj=e9%VJAnmFpfAQ4Lej!3ZJxcBpbReNJ67b&e!g7V-{$`Iq$SqsYWq}E zNDPBd`=5r&aq7FT?x>NdPSigsV#~3DagJ9(;qB{Rbf9YDA(aCctZ*05xuH<%uy{OE zED8-xcJH3AE8OVVJ<&E^Q82Y&aOO~E+_U8N*3KDF*V0RPxb)M{8+vuxP^PBNu&{|w z{X2H^pb?t7tIm7byQFL0UgcHdLF0=TPQvvo0Cw;bJ8LGtYVn8dnXb`GO0Z)qr4)r$EEBlK;1(0){ zllz4Rz{O8|J<<`RK3T9++ug%}VLjkoci#7h?0Qu>?mqdchZ&NcD8P4e;DT>^fi=5^ zn4}(cCg%3TT?1Bw-M#!uPxyZgC3k<0K<9V?mNLt2Hoglfsc>Q$0U^mM1c;4SW4FK1 zx&Oxf)-`y5r!dz;y4b4e5r9P#|N?vpdnbN80i*DF3Ic!P0Na@>uVG91Y!JpMwf zkMp^=*GaPn1R#BYj;Y;ApG*S3NBi1k`dSBRe?7e@p>_f}X_j zCW(pl<@otlUhvtN}L|fvBXhtX$FLuv|`}K&osW^KDoCfR)0xZPh_;SI8b87oRqixE>|j_ zEXjFy4}dhFLIbV=_~obW`J@k?MUP{W1vP3+1}iuHXtT^~qrk?n%m^+I^!x+4v0^I>7inRS3Yin!Nc)655 zO-8cV5Zpu#ymuGl7LHi)tw2a!?pl@67J3&RvnxdvVPGK!IJKugh^;K65^!yfbU`>Q z*=;7*9JfcnFaq(}*j_UPgTq-L6lT&V}?o+91 zpDDLk1nX4gwECn+VG8{c_MYCxufi&}A^~CL5oi*zz9JkxnaaYQC;EsavnnlM3g;0sO zBiaLE5M*kWjY;V+)g1^}yVJ;Q)~Uv>31kw6q!P|848|p2kyN13tQdBXLc;Y^* zm-J4AuakfOwRAk&Ko@Tn20rX;Jxg19Kw2f83GA;4NhmHEmlt?*zcYqUGn^?~x+@$} zQ}3S_1b#g~(!pNbjLe28ykad-L&yPXW#DG2Sy>Rzk-%1JuRu2@NQ#dP8~3rOBFTbv zY6hP`6jSsAv(gZpLk<&#PEu^wOKm3o6wg@0&5 z>by3Zs6giDTox=}7%utpNqTlz)4~TW7ymtFgw zCB(r7mWj%O%D5yS#`iei5GUq2sM*K?Q}+ye+Nk89^@(+8NskLGAOzD$3Yah$$uL?j zvlY=b1n+y5-qIt0>q|_52jSne%HfkeKZm8stt=S( z>@E6@B9KAt1vAK zWVtjMaZN0Z1+*Mfyl;KtqQ^*<;!((2Vqm1Xno_x1aPl1&ti7QL*9#mcmG#oUd32p? zr@d`IGRoKU{M8iE3!;d*7+J}Z!~!E{$DqxIxjmRm_nEzoZkELqY>yQIxpFO3P}=~L z(dTTQ@-{+QY}#>_4(>xk-WXqfk+BTy3TC@Ax*LeE&HZ?Aof4g~ z>os3Ex)sae+k|%v^Br7^uP!N(xy-f+1b+voHLoY=RwN@4}pBT(KX3U zWxkC-|JlC;6Gzqtl%Y1{*a%p_q^&4lzMjxHb_yIM1}Awl0z&b$RU8_1#WPwH$mWU#a5=;mAf`^YI$37-BT?v% zhJ@hD@IRsaCp{+n8&FNhH#T#$1kCjK%$BiwSi6oc9XzjZr1m2kJStw`iB z+C0w%)vPC3Dl5Yzpvk3lO5tuN0=^I-@|^{N9=MdH%9+G2j4?=!8#WI!GKR+5;=l1B z&Hv1Ytb23z4G_taRH=RdL}tK%NXid@$b7F|1q_JvQ{A5a?GJ#+)&B*E{3Z|m@Mn4G z|2+eRegi~a4546oXlS5X!(W^Dgb%Td)3q{iq{fxG)O8th1488Q@=fHT#v&X)Y#&3AYQc~KnU#HTKrO3Z>2~!{XMJKYl^Cd&f zo1F=K**5evjCHIO@!LxL+Uf0Bim6+){Tj-l5jBGw?AS_Hm6ER{RNR59K+2Z-4+mVw zq-chE#&=ls>TYq_E&5^s6ce5>2k+{Id;L7Lbej(^-XS&4a&@ zpb*Itk0e7kdI_zq{>R$wYucEZ>-F7Oy!nHx<=$F1sBW)~P<$Q7nyO}9|CF&DTYCe` z0U^`r>H4mRZXh;j@8vSEbG{|JU(3!8~$L_cN%B6Z{K@K0u-=?&ZOAb4;$IOn>EKWTnDo1 zOV^>&>)G#Nedso<4_(UJ{{atqW;$70|LpgFsRCsRRm;XhzWUUZKeaxq(%jZv^e&uH z_?i6t(=NkDIbn5;Q)s}SBvUp9#?DN7Uf%*aVbr**gGP^2-!Csc_BxBZr1{nKX+G&? znSKvVVfiB)&ekR^VGV|9?^XN$&M_(HDAH76F?@Qxg<;U<3ruf1`idz-%olq{jczpy zclYP`=deDsbGKs5`tZ~EQ0lfq@&jSl>j%Ov;V?Q~@oIp^^8Tg|z51pPg$cWy|EL~Y z!K3cq!7DK`%KGCzJn9BL-@&8qz8A;nZ=-IDxRGt;Z=Ous{V?iINST7E#PF!Qd9PK9 zO60_!O~IpXJ9yMx9-hreiiDfT6Tsg;1^?VU1`gm+H}tJ}T=ehFV~#r;5fMd#XZU{q zX@(yKH;-={4|}RRJ6+B(@^l7RNx;MC{Kyc_+2prDx8o^Co<@cT-BN&s6aq4V7^*}{ z@o)({$zT`s?P5e_E*+yPZLRSg!1AV(*WS9*XP!mZRiz`9A#R%#J}a2YF#kn9Vv{|MJ^ zWj&uj_+4p1dnyb#9W*XDJ@g>^^EQ(sQ_nr+U({qd;jV&eL8|}6Sk^sNa01xPJ#-te zg~^;Q3?P38ZzJrsX!5V|Wbqb#j^FqqB*aVH3}v{Wk&P&U4XTi_?ntdJSBC?n5v!1D zA!_Pz+0|fA&ttl{!VO<{(~e7r>)3%GUCe9_tXOaz+iWMHkTj55uE8Ov0U`$PH5M9{ z-VKTcq&QWPvj4Q5xHh&^ctEcoz6&ZP}$H zIAG#duR2j(&t6*SoyC}=RvT{r<$_e95R`);ZdphLucuSbzPI^h9h;R&vVk|lfh7Te zLfW4bA*8b01sbxmA~rtp3|svqhC-1mqZV@=xtJ-KrfnAXe0pm8iSY!ipWi0S)>7s{ z$aw%KtRAda`Dr=*$h)3b`)OazEOKi|x`pMT8>q2G+r64_fE(4a>B z;2!Azoi3P9UZp6i47bsW2XLeisn4WmX+CRZd zBM&7F(wvebZ}4l4*G@;IFUA*!g&${@$ioWe%J5Nv$W@!+z^iIQ0_SyAqL0g1RsGyU z)3u}|&r}jU+Bb7iEkEtB6swpKvgFO&CDZZb$*uSjJosI5_@w;xyIZPioL=PSj z3s6ned6#Vzt(Ti7&9S>rhSNjh^emq%Q*yw$8Q)9z+!EaUq>QJ@$pfocpJv-p2tiMRfHG{_Qqe((q=H(M$1UjozH&`;j zYV;R9ocBseEt#};tt)Xwqf5HP86A_W87%qy3!C3>#E+}AbT2S`H87*rX8J_(wrP&q z60RZ2YBYIRSLNe1O{iGkF3yd;MH5#ERjKy1D%LcgVr1nh!oh%5wP}zuy&{M+=`H6s zt55wdWtLwNRu;0^_7+vF4N;O_PO!vPUVCATxrEz>9EWYxxV7*;z(OAj|JA)=>c(!% zV~c<$=>%Psll)a9gYwt1F3PEC$CQcmHuL6Y04ioOX|qI5bk877o-^oZsL(RB#~Go# z(h)S>vcs<0-U*cE*&;Wq9hF|_Z`u{AEIzyoJjqVGsc@30m52SCX$T9KLZt=e&?E%2 zUin^SjyC1v=XS3Jh=+BI&$~Gr?Q+v`m2T8z9NN54{n9Ya+5%r{D=VW>m%{(-J8u%W z)^8=ic$s5Vw&BHDgr0#;&Stu@dY5@&%JLB{Dhr=Co!k!W7;?CjJ7DZn#hlfQFNtJB z1;-38y&1bT11EG!!E&xTosFd zmHq8EpC<8?^P6uybZJeid&#*m zf9sl!_fH5v4naggOoN`1i{iR(xcoPgj(6{&Iudfd#tX?NVjo zc|9Ao&*fdm<=$o)M=H=W{%8I!d*}g0Ge!uN(1r7U&3CdFmdxJHgzDtZC+Ntqn{sJ< zR|BSJ{@q${&I%>$~%KJDRROGyMwW!3c^{Mx1r7AJi`UWvhvZxR7YR` zeFQ+6kI0ip5JU_ zz{^DGi$>7+^8V)h39RuYxJ=~r=`v9$Y<$`BUE|BNmYGkNiJa$Q<4fg!k#EWFhu!t>k#ES%j9=Mln?C>QI_owQO2^73E*lQtwWU0VndXl zC3$}DGEr1&g!a>AqMtQ*fFa8Ca?{@oQN9a?C`aW!JpMtf`B^km`##loogvRK8bjr3 zjlN;iNGs5LznK3`?$esO^X({8uBbN(S_VDBElVBvKnjz~VGBT5veBY91At{;E3mp3$hWG`gA!|p7Wj+j6?Quiy6j)*}z61<;|$j#{X z54ktLYga#BaUvUC#M;&SN51ic?drQIi93$ln>p1e+T89F1+o!gg8Qdzq}bFmeiURQ zPfd$vosW4!y%+pgxC^rpvskvVpN(9`vXLpY)U+$V-LNP@hr-N=qhC%Prw*;?MEk)< zzDY9fwo0vgue;r>X9(|n)LqhPcZgFE>5z5u^%Rjb?k>fHumGcq|edX*%FT4lE16J!YjRG zo%=zDb3fdMv}o$CK!5MZhl`O^k5MWd#M-gmk(x71NxwJ?TxP4ISGg=O5)7YMLfCBN zP3g*(ny=gG6>9EG`BWR;a7UuK8u@I&6ieJDl^BLPO}qldVhD=nWiS;wMhPm*(1hK$ z{lVTw)kLK0o`daSj}PebUc#WUY0xAu>GNcSsZhmGN$&cF(88P4>9@;{Sv)uCA523X z&C2N-^RavO`Afb98$~A<4~*Y$PX{e+1{de^174qA>tAmv?9e8i{a|xa7WrW9F5=6K0;W$`JB>cc@^d_KPPlI2PeJzlNuuX_}v zToEu==MtV-d@FB!@DhmH>Kc6yjn-T{O?{V8JGJDUr!%t>y58-+x-3Pd-u~Y#ax#1! zG(4Wxwv{~VzIx;QmS4Is*-R~v^V->_J2R^v_KvZ7Q!9U`@EJ^vBKK%L-MxEWn^y(x z9vWeNS9@dT^=xnRQFW}5W6L_hX5<7oueR9cp!$poiYP4b7{O5$jSK2R7{|qVPjH_9 z{*=(*ea4aU``wlxU!|5R>>Z)#UCtrxc$?QNdrn83sNDyacg6YWfXA!?6_2PcG>=%K zf@f=}bx2fg`+?!@St^0H)gL|j&^PW2F_A4+p~!tRUU?*cm>#>Q4*EDSiMo6gD@R6n zwvLmdD{4maGuIm=!3c6#!HToOUBykd-0ilSRiGDV}^>JDVW#Zgaubb&MrW(`gL zae8uVBsuxlzuwxJOdgs3ADD@Xz4y-}~R>v|}uNNscJJc`o9xr#h2g2+2&* z*v&WbG7E!{NwHHsdF^t0@}W9iDe+AtVpDU3WgOXfJ3L}hs&}7q>C+o4HJ8ABPJ1th zD8wd)g7Bw|6`UH%^I@CFW!n#;7MJyy`Kx)fxl%=gH(_*2;Y)59-T{*!jte-GM4v~g zNUMZe=C}fE_?v&v;syw;witE6A=3aCjUf@|?{M01kd-qV{;|AmIKeN*l@5=I< zFSWX#IdcQ`uwOqKbH=7-+x35wCwyB1y*C;NH&_1$|1>>6CM-Ta%KOTV*Eg!Jr(}G= zj?Ya0^0dr(+|f1Er_xk))@h!6G65u2hf35wRmhHu*ADrePh0|W=1NseJwE+Q`RGBr zXx_Vs`0TR_XV2v_&}XvY{@I)%&TYX{c2MR8J5k<(*ei)5sywmVEjgL?G1(ThEfR_; z+)}Re#bPg6m3Gb*O>>Ni3^HV}hefZVwkL$UwZX0f?Vg);Zb#)oTxXu1f$RR4CQpXuFPX=6+6TCE~cXH}l)9k#PwrZHORaq4|IKPc|k_t`oiPm zb$#U?|J-#fL9*qZ&U(&tM{D$PS?o76)Tij5E=!P_r z@YMb!VbaNSY1S>NUUH~>w$7Fq&vwf{l*-pTWfv&ki66UuMyTi|*(!Pbw4d78vI%Yi z?t?g!UEo$#h3V}fa%K$Gx5eiI`HDMfhJuujRmAw(aM*sn74`gAuS2c@8z)u9AqO;w zL^0A@jOy_rPL!H24%J^J*@9LUlHijh#7Xpse)N_u*^+B0 zo>!7j7sMPo;7=WL+#!8Ia`8}j9wkKuN2R49C(gLl*2Vn?c1=`^EogH2qGZqK$_i|9nK_sLC9-tc zuf~^^h+s`FUn2h)6MvbM_UbU!pDhK#1n0MO+!_9pCdNzRqW#jYc_c`ozQ6>R?(uJ0XU&mRF@E{l(a5Mh_g zQPAa5#12k%23;<_={~T_<&od<=R#nY%N6dG1Md**mk_MWWf|Y)_RVR9AHO)X^zvz) z6G0@Y1z(=H4tybU6CJo{dvdq_4bwmQ%0>+Aa`^`N{RdxsI@aYm@8B6FSa4>R)dhD}8GrDmxRX<-o>+@o;E z>|Zz>h(xBJbD920Ed;W3Q>(z2U!JZ%zVQ#rjzs2}_$QJx0`tOeJS~qqA4LCE*Ry%| z{a{9UR>MS`(2}d2HOsuTvl-b7uJ^uC7tUobXf78>vr80|*dAi~J4-Wpw_t5btus4$ z|I6ssoqs-(_B`%O{|x%c+e{r#;+}qjNWOE%jp+2(^TV<;(sL>Cv*-St-LEugXVYgb z8E0pITPk}~s)<|w*W)4Slcj6fu?KnioP6!}yK^(ypZ`gH(X~#y?UmQ$k&^I!v<#<- zu(_H)&-j|Wh6 zq-w@=89lr~MC*xz?=qKsO|jp++3chq9o{=SdtvA*xp8qI|7zmQ(LV*5Ehp7qQgD_C zx!W(Dp0Yc(mi;z@!vE>u(NhIV`Nua=HUV*k(QgXTU3PQ~L&-m}Eerq8CVO##<&V2O z1^Fi#)lbRKeRVI$PL%g6sR2Vd$zpt};))^UN@mP$Y2S^bsrDyh*~RA$G10Qhmy;oD zrwnr*RKjYBh$!-#_q%@z7nv5Zb~|t4Y@evz#&G+oF<#YOBU(R@<;Heh%1k{oTh;uFHlGX%{J@ z?nK@#mHOP7C!RM=+4iQsTOC~$cjvR$@PgCKlbiV}U0un_6;)L9_IvvR<-F!z;0ekd zO7q7z!y#aneC6x#zN`lu1-`xbo0koT7?edD&&-_Dbh@Mk5mxmC)}-IBH7i-!6Y6_9 z>3vbk*;kQQk9Qc5CjY=`?>LkE)@pHP?Q=qV>}(bxHBHNLls)!lc|IdQY9b6XlV8b$ z*D^yI!`E?@&o7md?YQ|tzB#n4IWwhjSwOK8rIm*SSWWt%4w?6HjEZdu^_@^rO$cIy>!c%k3 zt?j-MQSL1Tt5+_A8?qX4^N7e0tsv~7o})cc$n3QucV$SV?WpvOpo#S5NZ8HBX@k>C zv)kacG;QX+Nws=Xzrq?``!cOiBp6n1g;4Z2O9m3|w~cV__=}h}UwD*ADC6Y5IUGfN zDxaXC_*Y8xI1|~6O|-PT4vSyAdyR_=)5f#OYx$%FOG1wm?zd)k(Tc*Z%Ea99sXpl% z=g_(2LzgZJKju7U{?P1Z$R_(_f~69p6E4uqE@@GKJKi1|A3?cm90M%%lb;u=54ExC z%x*#1_I{aQGIc_b6E0v6wlyXdzPTfE-O;v=|0 zh;wLLqS3%f)j8csZ?!s_NqStorheynEB4xd5MHnv$XAdgVY+8w6do@m8Y>l=gqfHm zU4nxVES1@cjcDS9=Gfi^p8<6Pa|D?Xrg;{I~yt ze)yfVfQ&inI@{(ywYUHQn@Ur0dxt=s&&gMqU(?9BgiaOLXn2~8?S$|_Cq{;my2-Zb z*8(|+{3&2*Eh(4Q-$P*lGOtCRPJhB9@2n1dD`}ZqY_Hliq$v? zJ}JMZIoG-=y2QEn^}7Q0HYZNdg5b!^gd&B+mi*MiyO-e{f;5duIDC^*yMkcfkp1f3Jk)6Dj~0A5pQQ&LG?jhn$cs1vSfLHmFl z0n^Lu`XLUyCS%US2fQXcdmEeTqmS>cC9kHy*W`QgE}~Nk65R4=euPIFJ!{5ik!{0( zugRwdsJQjL5#U69=Jb=Lr4wlAMo`#6^v}F|l4W@M)$$fTUOA669Y~XegCYbPT;JE7k^?^3EyW|2Ufc}M@b*IDKUOMM-^}2XxRrJ~ofia;4m};*$mw4sgqFIP z|A@p2&yowH2zVZm3vdRc3cv%FVmO0KZ^h31iEw}maaN6{MMInki6xbatvGP;7vM~% z1M_-q#qrqEhYPsS(uNZnLQ+o}87vJ(DPZZ{&)}}b<7No-2XN^S0Qv$U=PZt_?Iw&5BFb=Azf#8ZPms5naP^_q8VWG9Z1J}{8HHS(j3rrxI0@$o5PzPsIF znRZjz=WbdEhh%Lr)xPApX<;>L3qM$^!Y|Pe)~YZZhXks^`fsbk%;UgRXA9j0V>0xD}_F+ndBpqodVHx)@q#@ zaZzRxYwbzpov&t>!y{ati-ydz!Gjot=?mx#$BJNOT=iE-x^kY<=ZNq-U&+8yuMqaW z{h?vyz^LB=`&%nWp304@yNEcvz?=#}NG!6IZ2cT+u<#A0!7Gz%Xnf$U*gq@~LWK<; zBfwRGrM-B*koXXwEqMm{74$y}nrW^@yoR2Rz7?COA-o86!Mqx_s|yC9RnihZL07ql zIl#M0F8YB5aUlQ>Fj9p}H7kllDqDNip&bktcC>7&pB$J_p%3V5=>`KqCTaeYwIwPP z`z8boBT$%G10ZApUQG+V8gPJY`rMxtl31H&E$&ZH0IGOBu%T?|87i82B`Au@NMfB5 z;C;9pyjST^H1w+%Fu%$IB0!woVSE_|_704=jWWCq{hKKnu`kgeobkAoo4I1$%a5#RLy@SL4Rd~6*Q+^2zU8c`q+WN2nL%?n& zkZYc2QOLf%L5Funmu9Ck@!kOh$j$EK*~fWVQA?UJ;BQi=Fn?ojvcrUxYDe4l37B8x zs%xLInwj;6?BgI7X*5_YG7WQq3wAJNZ}|usUE}_qwnX(o7kNOgVL+~9*)~9~@1b06 z`Zdm*;HbyIQ9EkEQLUy~hKdz+z+1=MlWbT+z(pijIZtdNLSPk*feiA=0?@Du0@xIwbsB7%w)(|I9RBlpN>eI< zPkS{DmU@J+CEK%+;A;Tjo2{bS#a#2x1&4tRXuz(YfbATjXfR92z~O0R4j@{d4z3=) z0kq0%V6Ixx3ZrEYa815(0If!VRt?J}e*nU%!uBfqsw*JoMs6*FN4sXyvxOzmwd1(TN^7lkz( z8nI=^;-l~*A#;k5gn_hvG?Y2qc6IGGucskQ8~fFb-d?asueAxpqX)vXI}E{43To=5l!jm>%WF?05oQf9m}IYunY1X>U6|>m8UE$cd|JqmuDOKQRczj>HO>~T_{we>8txzz zylS|qF6pl9%wV#PcREYgxkqe5f9lO-n&bP*q|3za2XBtM3Q1a5Z-n9JU3Rot045E!*mGt>f?f zRRz*;+hxHs&IgB$-+0yp^ZexV?Galtj^bt&$7Wd-tq7bi851{7T=ltrgjJU{D{;uF z2T#_9yL_lkEAb!0`HZGE2KYx@ zn%<_TNw%|&v-A!;G8(&*<;wVI-nl{UI>GW}oTm79bxk-b(C4jr6x?PnU&2}q40#n@ zX=Bp&J@jQi3z?tn4cc~|QqvfJMZqYNc3))6MP_qhuv&9woS{w zvR-Nlxx6`**~^@<;OfE&X)U?E%FVg6racC_$W2l$lm*UHnIqYwgu!~2Wg?0$xl4VX zN~0Iz?;e{^C{VWK?j0M46dx=e5#Pg%nIwcbv3>Yy~spor`^^TTvRrG>HPI> zvq_(oBs=?lCym|3i|~2#r;{lzx84OwE-;!GWWmo98glCYQs=8dxvo{EMUDp#-&JLQcdVJGF;mHXc7t*NO#DC~*Jy;SMNdA3wqFqaajz-#Tt z!ri_&>-B;&kX2i{e6sm+{@F*-Jlkh;{n?2V^PJKHLt+2h&Asiv?q!r$-z+Qq!ms*F zW!8bDj!XVgwxD|%f3jl7?t$a6p17V_znU+T6U1-g#YCI>kf#=oFwZB7LPWZ=Qd`20 zMLwtC1rCocsfv7CQ>FMDKEFtHg;6DfXWOa!^4OVlf%Hwj_V}APFxjy8c4A66{drPT zLXFXIj|TpmzFB8@Tvl)@K*IoJ3CoRaVH#D-huNY(mT-Xh4-&fz;;CXj$QE;9VtIj) zvBzF#U+Du&`E08H1#a)Zli9y<@f8;Gg}hxzfTFRCtN)Hdower*GA_8QfY0xQ1b}e^ zp2eC2d*#mf+p27;wKzWkLfzD3TrDN& zuJA6unFEu!07RGo1bq7dReU`rfIwk>JC@mQ5N3pctIRHI6F_b#Xydym zCB!B$POB4)yAO}}_=#DMLRu+BPkXz^z6>RVa==JaFr znz1~V_9_!_C1;JO&+HNn@>p}ohPt11BsvTbYsw4ew;UYMO4JPfH)O>AMGA{ZJwZwYQV!J z0Msi&x)7lo+!f}LYLG{U@k|z5x$f)uu3H?)z)JstIf73@=ZW=XgfDy}yA=Ks7ouuF zXM;;GPMAWE0bZx)+?!v1hJbQui&P{CNsis2TLPCg$Jy}Ss5r@ zhsJj`vme5fdOO0GLO>di*h2~^02J^5P4+DStvSe5Pz}-~>kx=)F@aBIsJPTxa;BqG zAd6emoIPQRz#h+gDA|RN|M~voWmD|^B+NOavcWWqXF>+tO4p*!zrF`jJGMBtfN~LW z=>#VwAr+mX+2x=J*N_D4rGTx3ZTNfu#fdK@?+Qd8IGKX45SO)i!fycsrhu2Sjc^WP zca_fKFPlfA=@}6Y-G*+*jXW)vO9auA#Gv-q|1#}_P>QWyMjYt6$BSgQ}A{)d^s zT0xBsOPA=)W)H(1P>v%@K|PFZ178b=AWEyQ+(Z@T*Y;2XJ+QVUX@4SFzX;9>(om|m za^9vX8He0|C3_bhfeUwN2AfJ}g}bT1SkRk>^H`A$CN@w5v|%>&sDwKJ+yPRm5P>9T zX%$NzCt$q~rfwD=me_m<)aHnwHaDLfiQof1;?{uTey9euB1%Gv(-GElelz!yGFwrD z#&=8EFwHGXXOWPkAuM;r3&{~xid7q!5rf1*+lhv5s%OwWYo0yDi{pPqa>m3a!n26Q z`^Er^Dq2^Qr|qb5OZyb5bEJV zjzfM09Y-i0XMz@vVFA?6fPyPr&FG)cw@X?zh#1S=U6dmSfPyQ8ub?xU31QDd1v4>Q zm_a|llU{^1Ej|T7Y@8CowxF(tus~Udy~8Iz#zFvRfLvjbeC&A|N9zpwzH|fvgV<6U7Q^ zAG&AJnWTGjvs!S5I6h3?=I!q|A|kMK*$KSaex7;J{0gXmr%4CpISmUm( ztts%mkD%Twj@Y*3vj&yA)dq`dp#BC6t~$_s4A$R@L6U20l27j!4?yJ5c}RfU02PT~ zZtRx}1RbyOZi`gmnWLi)zF?&Djt6u7kkAOF*I07YmyRH9*4sJ&Z-JAQ)e% z%e{c6>IcO+DBOo(2@<(sGZ*j6<9i({KXu$bafK=B21wKJ^L$QHII1N1h2-ZSlcw@u z?Ft_CHh3%4z4!qvh~pj5glh#l8vJ1ZI1P2SCjiO}^}#+DNrnt391HMASo!>`yl3cJ z6F{B?6p9&l(z>&jV4)b3KPVI{dVs1xG2}-=O&!JsN@_-PHH;6J!Pw~`ccKpI(NN+4sHzNnZ3KFw<QAx%mJni22s27}ccRi6qFco>$-jjFQn4k!VtP{S7j;*=e91?7E{apHH3B{rQq+}BosTKUS^&RAzh)+AQ(R7tAVM9%teWo$F|Knq^jZh>_Sb^IeLp)p}Ev}l{~>z{g|JpjGXHXc0kZu2!%PM(h#1Kr-* z8h)NWjdgpwAd6$%U>p>A;U|NJNeB)6dIiX>EsU(9LDw&UI-PxVCgEI8H^j3(``QSw zJow%m7^6b$@hk$y!lW=pz0&GBK{T0MGZ#ePkFCV2i(@o3TmK zBoMXWHv+k>2#ZlaJ3H?XiZ(DOVaY6~P=og#0KdGbw&G;_MhapSU%aMEiRz3k2L}Mv zy%Ai}AP6R52srBcCmm5)d8I6~qK1Q!Yh$wrkZZqB1||5{{3N$g#mLGqhU{> zlQP{?S$|&|yoiV9To#Q8>Rv%70=EGUIJVPc*EOCNH+ki0$({LW{-6T-A6_?y`v zv7Zm@ehI$4olZ(KP1}n{f!n_odt<>BK9f?yc5WH$#h?>5D9ZN8f+;_ zm9Za)Hv)N8=O_5KgfMK^!@5eMa0@IAi>rR^F4x1Qqe5e&Oaaj9$EiyDH$(t;#f?1( zbL0CpuQR@4hQ(Kla^)IbH#~r`MXmt5hH$FRukgnluw89^q%Am|u{MxX`qA6et+OzF zg)N7bW~r_>(#ddbWjUlzfde(z8i%dcio8O8(d!jP<4pc~`#`RIHpxKnLW3Q5>}$T^ z|5kr}y4Q(MFZDr=BS?UZ>dEWfS=B7fdf|9HC0L51S;oTj$LN-#x#e3C3Lhjza|qeR zJ8rEUSTok{a8hQxgWRQN_LnNvh~%JRPxeKfWM=^!uoi-^>gb{XP=ZR+7dBk({i z32f?#Ze0h@H+%c)?}>X6KK(a7$RU0guaIA8S?O<{%TIWEz>L;SQ4}`d9vX9%eAV)J zZuw?p3*jf=rED(Q+ifr7q}cQ4yjAW}6MVk2(lQxV4~}|`v2rU?fyYm2_((B=13ys0 zqn4)LIIMEVMD^5JX_^P3ay49=dv`PP0uWU?w(Ha~ZcShDTTbZ=RVCFedHAAm*Rjy3 zW8D_Pt=1l}D6* z^p`B4R(`BlquRxmDganU*8_oCH~H%TEJ64&TORLKy{T}ZEC3cKeg#lgk!6K(11JkF?L6hPZc{u46=1mLwM>jue1=S^YLG6xof$|K z>S}7n`>B`I68a;ktD(1W>FzbxWuU8IWJ*ioUvjZKxjd{i)-H2W76Mg2)R~!X!WI{$ z1?s91=n5dfhtTpiy#^_@x0{;9jbgk0*;_@_egp`h66=gq88jAO4*&KhW`aRDMN6~H z3BY=MO|uk91EN}yOh5!GIVFNN)`RBgqcIK0G155zR;QMlStkYRR3*P59JfUHo< zxE0r~Kh4^ItEw?uKY$gA3?MKx?yZP}s?*2*f;*0Gd+d;FEUg8m`!$vPdU{$L@`H+s z*h2n6UM~mOb-EJa@#ba|#&KkHtF7pD8wI@8Q98s5m=WUOgkc3O+!--h1<>Y_qzAIv z7GDHd`EU?3Y+uU4y2!195B$o%S=5hQ=kntQ4ovAdiL7;-9|HmW)xKu8_1F6X$OeuD zU?l-yW!XV6R{*i1s{^t+U{xytQ)?gFmI_P|0fs&0jSIsJd&XN81`q%Y8wX5~*!vH3 zz1`eTpa~MDG&M*C{wTl|0L#|rzy|@tW-@(;_|6|JbGlx8*J%hA`z^d;YPJShc9T(^ ztbVQHIH3-_KX5@!=$4@5bsH<;<)x!mttJ3lQ9xS(OBI?WZ<-y%N|GKAZKXu;6>I&R zr*mv8;!D!{i;}1pJ(s!Bc!p#nDDg?_EP06^uzxoBvBB$D#-Cj*4f|EpD~*z-Nn z9RarjJm2|~t+GWn@2Fnj`KTVcU>7Bh#ha6WqXt4-r2|_XjE2vzr)PE|UNKPq7cDE@ zjlclg516AkK&Zf0yAA*VTH4M*`HP;?OVz-!R)A6-u+{#?uc56nFQ+8>t=s$zIQEyv z=$gvr<>p8co3YN}u>yHH) z9tf6ik$__bTII*!?M&X7w`l%$>F3Y~0~c_NuByJZ+-z@MiW{?ClTlr`y*qK3u?mGS zvOx_%W2LNrNj{oai}-_XP{YK-)J~ZKC~JEZh?Rn%MJN<2rq(M!tRP;oEBM}|On(sx zUy)JB|D|R5r4xeqVNqDqYT;)J`;WuezIi02KX;Sw0Q$}c;VLl`gznlL0)l{(tK6t@ zv9RNtAzI48wich*R=zLvtVDXtQ=nKDz<_DVnPr8G0pX%g9arsuxw`2?fx7_Oaz#8p zdDi~MISueEz+EKL^fpHH1#=ZBwkyu`#OhgK!~~uNDY7WBh&h0m%`B_GE?~YV-$q;g z_4k0b6wt5+?d_($ai24wYyG4xUW>DzFXls;vq~Gf+W)?GAtEUg;-J#rP&PtR;a4&kA(0BRuw#*%#dfLRWWh1`!e zKo+vwnhA}?28f?-l__5jjb$$Xe}&`Bz_EK_c69=XA8qv=yEg(IyP1Go`t<(&Ok!O1 zFb{-l7nC0-G-m859*Q@9#DU}z(!d~`Em&&x7SF9N;A?uQmgbY!H<1Q@iMYJuVM2u4CMR1*MQm{xgx z-Va@%lRtu5z2&E)`rn8?dZ7bR00oGM-q`bby<2OV85b|=Add#jsvKh$vG<}@I92Rc zB#^XVDq~Tt2gT~Xs=L|+<$rP)c4H~B^ef_CJH>BYs4~SvaxL7^#Ybi56s#}rkc>W}C zVqH#l%-1-bu68Ho)QtCltIiS)oS3J)Oda+#nr^rYNPm^Wo)9(@bYLvO1{j8X=ZAKH z9oB$ULa%Ss@#A?$U)k$*@dgOEc^!QJNjXUbFx?agC=Ncy5>v66IKVGHv`M?*BB~W#hVe*{_K!_8n6>_;j-+;nb zrp~`!r#$$Bg;ql517{qkqWHAjkWsy0ID|2_9ObPnCz)~Xz;72jfTM1zggbpIcvL<- zYCeo{{f&~#2}1|WyqasYbrLx0^eVo_a!tN`E4UC}frS`vgud*^Evfx2CuIp9)e`M1 zR5&kLCPJU~F`%d}8(SRc&~4kYebrV`dD#3@wE~!}zM%{rl?1rEc>PPu;XFSWH{z_? z**~hhi}nmSqva$E&I5)Rc+}ItZ5WXj*K8=&wYeoeD)QP zLuiKzI9^l1DTE5ZA~$%eZx!GO-|AuW@+}5Xz#A(7Sn#Om%TnNB6rX?6s*!3=0!RIW z#hmAdNmWDvK$1}p!2kn%fs&6M^&9M{djtWiV@>~JClXP>=eu3$0#XIf2U5*X03*P` z6i6`qOg&0B(RSNYS7ZAhPfSivo_Qakd$~HV`ki!_6F@Hz-Tu=;*1=Pmi6^qEdzD$* zosk_KXOMFK{PHqsr{9Pg<-Mb?mdWAfSk3(V^Xzxw9wDguej`a6894pkb-z3_y<^cj z@CHf*foGF#Mz;3LGbebU%}ro5D9;RI<(XXnFj$_!4-si2FHYNZvl&tr*EM_oMu}2- zRZNb~SoG|#REBZ-(7M%+vdGz$4r~(S_de76W*&T|Cq#8y6tsE{HjmW#7 z?FJX!oS!DDjtfzVu9tcux~nX*?XDp#2)nz@(X2!>b#GE_))`80cl)3c-rY7DX=S!g zO8+iP0a{4~?6;B{r+`*cYuxUhA;Z>dd)^BAESj|lTS+;rP5Hg9L?13YtqB)vMnbm3 z>RrB~ywl3H!-_XNW^Tdz;rGSq#Chjweekso?_()BIWLpU_!j9r2w=0*^bb3o+rf0M z7&Vc8^W$N6intQ|Vq-s~XKmwenO7I}H6c4fBd>E)9kKqA70v3WE7EftGao3v^tv9o z{+g%XDO$G(Z+4sXZD?ccV2Ho?iHHf>XZ3Txv|inIPbO54S243KGVJR1vB)(%Xl z+i^_U%(==l7+&YCh;PPfu9t|Ph!g5g>7<<#Wvw04+f|e)j{Fj9QON4|?l&ISfwo{< z=AE`*bHQ+d0kKQ zzuKEr$Ua@!9)MT2%dsolskh|t%C@py)FYho_G}wDSj7AG%66{Wa$2&KQ9k>(c~TC!dM(Y#9piy-aTD2cx(7edYD6fu7p?3zm&n zf0w%`Ys#8pnM+xxEWKe@qITr1d-8n$ZeE{~+pSf|$cCKUrn*NCOaBryRphPI5;x~{ z|N5MFW+ZL)hdu_mHu*)e*>KdNG3&%U^CEFU7eA-bnBC`RRt|#SUTOu2(yG!`-CUP0 zCilMPPKqDzb^OwnLA^LIVp(LN5}L+~cgtX*NORuK9v5B@tB{+sZBp=aODTyKbf|c_ zd{t}d^RJ38LdQUV0vT6m&Xn&6r^J>X{Ypo_XQa@uRV&pE?V`CC63#fM7X_583vXA= z7aY#95|B0hy^$saBOo>)s$=o*C8!)E z3;~7>2*^4lAXBT;HE3eA&hc)#3;)tyg90s$M7Q{kGZe8H{A!H zPe&H7RK(}=d9VO;YCcd;)R}jW03IbZQa#}t{{c|ff9L<5l^h|>b5t7G^sj*NK$119swWBJ3`8N?fUYqXe;G}1qkK> ztZaklgFF?oY{=sNET}?b0sutLrh@bQJ9cz{i79{xfJDX43fNg6 zc2*Kn41n|}?5twk3|<2`r?)Sl$55|M;H-YUsvHO;>;NJNB1`L^%p8UEOMto{#RNN5)Vg<4&=+6Z!vifK(U60G)K^a4P^3 z2=xZ~_>XvxfOV4T`vBl35MZ(F8}}Hc0OU>(fQR-`RSh&1*}gA+wy!3^VgK<21qhdT z>!xF24Sn=IkR7CL+S*gX=ECtHkwFs<%zZkkJXb$f0TZcBsw^GL4rqB>R+$nHD_oa= z0TcqteaMA|X9AOVfZ4$|Apuy`SHIBT|K=~a2UyP4@|u(1Qeg1`lv|SkJpighzipMo zc^R;&nVyV!AF=szHS5ZGiQ0(W~bi( z2>0(NJ}#3ZAmQFV&;F_q5^lf7{VYeiBFXq2@OHzZ5Xn=4lbrveT7xT^c@5Ky8kA3QvG^F_d zxEC{Uy%Cfsrdh6b^dJE z_eZb)-*;fQBmrRD=2)46|J?9azfs$$kcmE)wRGQO&D7|1(u3iREy_}ka!bk+OP7;6 zw+5w(D(OsUiNm^fT&!NQ*im{T1v7JXAC{Ec%IN+eL31y<#i=ufE_!Qz6 zWeT-36fsAu2G@-V<>3aYA&S}$ygKLHEmrpZ|*m3HMV`PX{#hI!UCJNPInJ%TXdhp zrmZH>wAK8nY3o{&)<^?!u($4V=(3KsvRd+F*@vbKGAnr_mcmxQk6H)D6N-Vs>Ob4NlGO(1<7TJp}k{q;)81?5#khw8*alxk<=#OtMR#+PQV`l$uKdnxVS z`0J#2EO?iz9HLy$9f{hG%;oj)R(M0*c$qn*5_CyA_a3#N8GD8?d3Fjix+;;H2*7pE+R#Bx~}!{c|mz+crmpxDkG4Jihy7Wf-s|C!HA;K+_b-H@HXi$y-iwQ zAO(Xk1DFPZh)VLaX7-e20*;>_etALLbUJEuEX7V=(??tavDgYDda@I2mZXp8W< zGyd+brd=nT^@qN4mLe6fxCk))PzVJl)@ts>j0{8CA+G#zrf7y!W z{r~on&M?)}^Nrmc7=QY6 zwdXbCAMZpyQ8_a2{ogLjGTrzeMfK}>&p!-a7dgkT``z2u{_^tOJppTOY7rTzVgiL&p(e$1ku_l4-j5M&O8)+aA5eB-$_OF z82Ht~9d8+PN=5Nyb9#e2^Sg&cewhlDL(+PRiNI@+H?heBM4-Z&nF8|b-sucH%v1>c z21FoI_t*7z)n)Ry@1tjlJk?~4wKEkoW(_ur>f52NrALjHHBQfhWc{5M5P?ZV1=X6u z-ugqx+0IE0V+QfdSNQoYtsiFfP9^c_9+7W_FP?u}*wv~d^)I&58RKR!w=-?U^TCs| zbk);Rkck!P=@GVOO7Gid5Eacr(&Xp&mms~5@1#uJ9HY2LDk`OSc@q|x!0*&~;CC@$ z2FnvBr-eQWTZh2!b|YzboW$~i8*!%Fn)fubQ&*5qM}ww<-Ezk|&RcDEk;sK2=%l>pLN`WCPu}|0Q zMV;>b+G{!K$-%u6H^rVHQ>G;~%- zO*c&yRsv=O&cpYUq^h9r9|36!NweQ-twAYL7z0VQ1m92U@B5f4!z9NzyDFwi)n~16 z77-I~#`ou7s%re;RhJTXSvM_%tI|}38TtcQr>)f-c-eB~!5!sMO_H*4`i@=RIr`Uy zUDh->_3+frQIQEcnlx^-mQpsS$HV`Et%+mjE|F7rO8%FxZlzM_HwdcZ`nj|a z;w=@w@vxLe$&$9{e_;2K6~_@&?@KdgFI5t(qdJ!o;9b#?l@kMtL)2ApdXJ@w!m)37pC%obl~Tu5iAILS)PwUh)irTFb?6#}6oeCof~2 zyt#&p|LU%#9{l~f2Ab6MlBeML$NL_12L|hP+04XgQrCLljQ#iptOWiK)t5@y&-HqW zKiFTl8ry{7+v7`a~`C&|azGf;H|Fophy0qDN-8V)O=81dw;I3tm`i7ds};myg6^7=zs4y zW~Wj^n!P#DSdnHpIioM4!hu0g6jo0waltRW>0|JFjb|#t2~TaN^`>Lh;VR4&kg}s& zO-jHI!@hx0jk7G0|Dh}5q(qylx6$x z0MiM5nq^x8DN$S!Z8~?Hqwg$$^1(OmWYejlPnX!b= zlo9W0O~@-)vL#2Qb=ZH6exagNdj9RmemuW-Upzk_i3&O8f5hh(ar76)K(mlhqSEv8 z%Q2@Rl^bI5OR~N#AL_#L^9ophSi(sU&FZ?R?uQkYt$&r&74kl_^gD zKcuJFGr!Q4X608;`wVj`^FZ{YWc_pE7BQvjr0BP)X-?Znh&iUW`{*+0`4=&#o8qm# zl>M&ibd93-_18Z1uGNGLkPt&g4V3vb6&v%kTZG5FKTKf7g7vhi@P4H9O5~~OrNye8 ziUQ}w`dV|&vkmeQ2kB7HWN{{0>d5Yr{aq^IHl5xT!SUi!@ocdRNOihjRW~po0{cZs#L!#bB@{ufs^6q5Ug3&6LJIDOZT0sdDbzcW~d| zGjPV_!e)um;Z?0s=iA|bW6qc<2J@3-)sN~8_rt-y<}vzULHQ5t|7cug^da^Y2=uKV zOJe_r{~@LSk^CP^k8IVWoYF-~lkZ$W=>L#X`YQ>N{~@KPmSp~gQo5LZ!uVB(++G)I zR`y#ftZ$ln-!fSyS37KIu1P;Y=nG1f?EY*W(Eq!p-!Z27JC<5h&3|+LICM-O?*msw z8^Xozi0K8A5P4qnXjb|8Bt%w`{|CuF5Eqn%n}$j`A;s-Nj(-72v6_$~t1N2(m`eW7 zMim*&=Jbyyea-%lh8^;Mzy9+52dfDFjMUu}IA4T6Yo@%tcYNkpj|3|4e}Z(OY{T7X zm!9k=LOT4vRPz5?T6#9KQ8ze0fl*&o38`l9SsP2bHwHUDtAD>^d%9sl2R58c0{l7& z{#szEM=51wh*OHcD^xh8_@9ogAxcA%aW;Wkx&&&ADE%Nd70yRFD$i zFOn}q%4#^3+d~t@KX`I6D2>YbX7K&DIxKF7Y#q@Af8T<9oFPmP)PT{w1gB<3I|A|@ zGTZXG2tSPJI%0Ge!RYcZY8{>*IM9eX zEo4QHV#a_O>FhlwX=yLhs%;0$E^odA_1t$STLwK#Ja_P=W& zp48wrLX$e|Dn7>%e)~EslTX;%c~Zqh-A3AGkz*(&e>3X}SZg*_#xAU3*x zM+r|V$MlK@A0E_>CXF*Rsl#Ra2jJjWIBPcVrL48_F(yJ?nY?^J)kSZL)ANY|E9L^6 z^){#o)YFp%DH0V~>AY#%V@4q)2Wk|#uo!buE>aP#NJXf;1i%#!=wb zHQ;Pv$VK3cO_<XAs2N1gesY2}Y)#47rFb z98VVhjHuAe2`W^N^&=EQf)7ud;Uv*ZCzaPG`{aWYSfB*K=}BAO?u}R&ZRDC^Og&Ca z@IB`zU=8G8yWMAPtm=tgkDB?q4b`1gGoR-^FR+FKHmKL5@^lTJ@6T9>SV%-JDm~*i za!$koT?4R?%KMOg)3ihdU1594dzW=!DH2TFurtPoH4CgQ{#Wd19AaS;6O1MT*kN90 zfe_IQ*5p{cGio)m763M)V)4!@v&1iH&>2bBiY|RGaskEyw-aUtxV`n@0-2>uFv$L> zZpXN0`zgsCZAh6LMAl@GSlbLH7#mFlh8l$+ zP;)XS_4L^^pk^jg;a&lgYKK$bGg^qXB%&QGM=MKo6rPRhPw}B4W+ZoPLZ@^Bz#sEw!XKI}7J0 z(LeiN%m0%5U+az>_~EU+Kkn}SIBoZxY|u3FqFh4MqasX+UexG*K&mHNshp2GPl$R2 z?>0aM1)^AoD0a$^)&fzfNW-%4OcWFVpO45ko>7DoH9qj-#XE!VNR09uSvC;WEVl`M zPDC-%w8{W2grKmR@Fd@0}>-50=A;bQ4EBPgmd zR}A=%&<6g{qh2-VWBc#v`DCi;JN}xPQ{kdX=iEd_=awzhlAhpv+Z3|zd!k81J_9`# zqeYLl0TAFw%9~P`c+{b=2+eo(DfJ^u zfuyQC(I3ZrdaskiEo#&)cMKS!s2Kkw*o7hK92q_GTZoK5!KHv9;~efig^j1EMzjK$ zbk%>S#bR0k6csX>(vm?osfI`z^NFVSY%UDdyFaP!=)uN`Jc`Vq2@ECXyNxh3*Z$_n zsJxEgW_ptzBt409NKWZTlO5obo1nWmh)*8F_xDcqY*F|ShW;+lcM<0>YZhL0J5it1 zQ{!aR=vUEo9dkswRC!iaY~g&tK1~-#t>D{Af+x z@+8+i&r;pvJx8i0@Ac&X`;b9zfI-M;_U)7wgCV7JL`|ec!sX@gKKGG{WHWpB>DWeB;2h3eppAMrz=k2Cm}wAJA)5G_V8;YKUumL6j^a8AA_E6Kf`{y zl`5os%u|00k;yH`pic@JTK8GiRo!aJ^^DRb$+^UPkwN-Up_OQga)(h&%Ih4%EfaXk z#dN)SeZfm&uIaBORuYDnzL7xmdK|1f#CW%4K$&vo|yc zm1%jSzZ(_O;5n4N{{YRy35>D zwLkS3CCNDx>zpl=^^B>ppP+-`Xtbln^Yw7+LpOtl+(U$ESwvo;ZOyzR5HxJl%p9uqcsX>LX3<8 zFQ7-$c&fSvXtI4L&~$FOh^7$_z%wo&K~j+Dbgzc|wiTA@KlE71X^uTN-G^MCBo8hm z{vcH+OtXFaLLg1UQcv|wK6FtmIVWU93|gQI4OwBudRxn-5%&_!TvR7Nu$M}U2*q1w z@|>n>IG$8?UmGnVB=?bw7?|)K9A&&;A=YshS;hqJU=gWzg`oc}*Dig=JD_>G8ofnT z5G(g!8HWg=h!G+}rWqD9A15qFH;YeeP9vsNj`R#eIcf9buqgPM1A*nSs0|-Z)s=$} zKgGFhFkP)M?Y*dYsr7P!l^g zlarZON!(AA%zWS|-;*}b;gXvvmtwiCL9B;19pqHLHIRH?==iGYI!ePyUl;Jx(^&8D z0X;Z)svcl=kKL5@jw|5!^mKQ4RG7vrCz5#*sWb{AW`TOz6?(c4iJ0zarr9xI>HdF54(5&v=Gn>opHF1=_|M z2+U^dlZ2EQiN}q2)oNm1vH!raS3r|rBvr;l$17>_S;HQ{Ax3rmT-l13$rdwk~4T;>8M2wqMM4OMh2}W3I90A?H$_(7}R509B z0@IOn_x2wW_awWg=9^PD+@)nfS2bv-!ogWRSA!^(gz3Ai;UGOz=nI%9s^RN3Asr!x{=EDv4-hFlcNoz3DdQJXk^akvqu-I6aq$vG)UQIwI(cOre|)8Vl%A zZ(`^>wm^E-FZEj=a6p$g$N+uP62jHnps`07`X;+HBn+yla~`HLqR1hwJ5n)Ib3}#V(E?JKp%)Q_3b#JixlnjED^t%Bde@HP z%87JRD&m>9B`mi_m1?a>ep9gS``(VPcZn@Qy4qIp>kD+*m{Lh=Y}vkZf7^a>siPH7 zCvKQFw(CwNeSI*#J_3xV$9bV==^fg;GT)`jVolP(^K`E-53<~OQS0`^nqd7y6;#>V z|8ry&zCM<}o;`Y8T4+T>F3KI6(#I5}8gcK)^i&05Gz3&GaNSTE!1@bZ?U}^5X!%U4 z%y1fo2_TttDYer4eAZo$y)_6Blp0AE zq+~vgU7E@r&!qeEOLu^$`2K|?U@zp-vaB zI{%?xPqElOK&J8|A}0#i1@S-jrT&+E#8!dkR0t6$j5zB9ckOXO0t1*iBUpzaW(4V2UuuxJb1*om>zwG z3a*VRNDLam6(npXRgil3AEjcO7JAyEFr|diuoEe5VhI=Dd;y_Pc9IwL$S>U`JN*=5 z&*FKy1~0uBr~fq8;VuyC@C$_|={`$ag6&wzm{D{YkPgGZe~N)0EOx({@C0=s37uek z=Sf{);3wz98$A*Dxm_1M86Iuga2Lr_O556JJWjHy9>Sr+XDpPe}IXb+#erGQw;HxyR1@K`?seb1S zRqy<<_NNg5{&dBd>>;(gV58M50R{Bhk)8-nP|M{+&`Rph3^_5sUh^TOWgK#pLA745UMKCZ#CqbWS*oa}LyKwUGc ztHW{t%J+*TUQv*adv8;I7I*L^(yo+8Yc~YSBC4sufRgS`D9|i4ut_yYI*bu_rc!?R zUkbF8AJ7UDQArAPI;j_zp@8mxq+LaW9RVThDCyob(P{wiE-1k{rf zImc5`!Gr*gc={Ne1MNLEGVE9+y6-CWkaHEBb=(Z*J*L*n8oglwHO*w*RV&0scWxS) zen%|!Tmr27ikLB6|75IlZZ>ug5SVph!)SUAb`Pi^U7d4JRSpItlk7E!9(4gxdLD1u50467 zZFW0Qy}wJ11o1FQg~z9@u{VE2K_WKy5jC99?Wlynb`{o52X+#eT)|4Pjqork9l}zsUm;y|3)n8qSY|&mJm`1GR<#(x{K!ib14Uo)>Yfbv z3_+j@s;TA3MSf9nnsW48rAl}IFCD@$q$d);jeRpA+??oR5_J{nsfL%#F5ZWoCebv_ z;JD94zZ^U149BbjDC(L5jjS-xO_b>)jZ5T(_PEZG`!r2i!WYJ_sKrQ6QWF@`Q_O^y z4lG#{GX678Px@DMcSDl_rp=$YvU3v!eh?KK^;RZa=XtYEgAA&53VlAYeH&Vf;*fMA zb|}QiudizSlGEdkol$KbSh1$Xb$&jYJE~VwdJOOpnW6Q>lJ-zurf_-GXOKh^BruI@ z-wgBnoN87ETc3J}AT@Luk#(xZA+gy3rq(O;s)+pf2orMpN+f{V)Al6+lvq46D+WNh2rL2An&(tWZCsLaNvP~Bd`^7LrZ_6! zn8FRRyeiJU2`6j-Awr_`=dxZ3VXDs=7wrIPSOwr`}J*$H!U~HP~O#{FQUjmI!^g8?EbuL(vH*z4ci3^5C$iEDq&H zbsJ&7=Y!sT3mJ4X08ruBGcy7y3|NA`hRz2byh0;^-iM-cfmTtyhS@I%$&f`|JzWm& zel$5Ri#>%nTwy@%ml6^7b~oY9=wW*Tj__yejc`I7(G_h(xxrluCqy$u=pBq6{w* zjw+NI#hIJ2z0Dvx3Rc~s;isuO8&WPYc*i`6#Wco6tE)Dsr)v(?c3{!7!F|NkUp~P3 zfs~ukDY}MW7}aRXSRgg^fbAieD?#ADOBd5PEdjMOzwcs38I5jiQ%d6?9CEl+0bbN0 zPZAf)ieIw7iFmfq3eeUN@1(XRkGT}{oduMg-l;#tRGSx8c*&D{I$9~?rd4)8UKN*o zAI@SdU5_@^!bV!1Bs&4iHQ?`=OS+@b`|6-ZC9JNwdS8nrDUkiN6YHqsiKiRjrzcT7 zrMC;!Y4z04dnJ4)2^V7Xk5oJ9?4k%>{*~DJ&b6aQC_|~3$dDg)G1ql4Ml>7VbaI*J z7ALi|0LtG*^UuMnBQpJcu}{wxQOZvG{Ed&j>8H~N$W5xMrPT^@6AhL?xXis$P2r7(q2LOyluMMeo%dhn&}Ol?BV zg>wpYcSBZCh&TB4B|t^hop~`zT^35kZ1Yj-+QwI6lBLEu_!xTOWj&Ws_mh$o)A&2p z_ZP{-Rj=!H1cf56Vb396L;Mqi7GqFa*QQBE= zVJwe{)rT$~ls*s(vfnmv*Q{wAD}raTIcHd_y?8}%M;RDBm@@SW;H)X0WTL;9X`Sf; zI?>6;@J;@BJkehj$IY_u2Wh2+$dX|!!kJQ=#FASLY1l!aKt#VK)nR$V!jUZ0sNA$q zyCW6b`yV%5X@@RW*d9$gtrV{-g}QWXWumPdD|KI960X=8iInSH*H>9riHb z7z`HDvPejpE2<76rw6B2@QP$Us}6yz;zD%@G6}G00(CX)%GzWOEE;*N!|%_1BP3)! zDiSNHNTiSQsgZ3YQZ1Hg|BmOs55<)=r?0RL+UDx&2<|PRUO1*pK+XHqt3a;vJ5mR0 zTxA;1spiucMKr)NEAj71qN6mGaRbUh;iO3aj~f55!MO-c<7nH%P6UzJ6>@gxS6xes zcN-w&xmH_5%?+0{%X>FOsQXfAbPTZSHW>mA%$K;V2Yiy1xxDvs%JXT<8lp z&`ZSf#)Hv-qnd*6X;Lw0CZo{=TODlgq(L9XPC(q$b{V+(HwA5;Mq1{iEvc1KR|gjr z@cuQN-rx8aRu3Xz4;EQ{Q4e*EAroejJe5#sT%~oNFY?-IRufbc)sK^T-C1!xTCC{q zyLjb2CKn{5qGf-E@aKuIU-t-$VSUv^n5uM$C{PCU^iYuw5gR=<%A-l-()wc6T79gT zG=MOf_A7i|&%=#E3~11k&L6ROr)rUCP`8Yd22`JrsBciELhtsS(I<9Tz@tV+8$lUz zae!yBFd+@kg_I+-APn@W@a->l+pBRrFI#6(iDSsFG+ z)8`knitT{vWX@S3b~wx@=zC7(TI)e48h1E6H`62OzEWT}{n>1(RAF)Q8d(OB0v?t1f=kJBwQYE=?bqWxF0fF! z`Wkt(U6Ortx?bAbH9-R*Sd(H0nrmd}F8P-#@uJVj;VMDN#kgwYMO(3l|u58$He zEE8+7_GH=R63Z?jy3%ysn7u;xo$}#|LrDjg*$;rhl(Pm_N-u6A3-dN|krkz7jYT__ zHX6}uBNolrli)UM7BNlDX<|iOjCP>Rkcf8N!A)bIV^6{{VnqX-2asIi_E?6~8&s$= zb_+XL+5vk-uK%N}*#%7m?21yZ-OgKjiFHREBQ2gye{j9%Vx(5? zpmF8;Z20$k4$qVbfLoTR!jLP}S>fLy)M$S*@QTY7;^>Sm+o&v@UKG7f1AoyM^xUjp zI|xQRS!&>c04a9tVVBJWwiDHvghtn%U&#puZQ_O$U@L7+Clat;Q1i)bP`1GI2wjM1 zmJgaFnk)8N#U6a+JFZ%#=NogXU5i8w=Ya&!w5b#q^(vEV^Tq|pFrG@p2dw~ZMaVm#DX$`$OtLpjI^1HA!uibSQ@u_*S0K3b$f!Z;;u z-4Zfb3NW0!N&@VA!RJLOU@!v(K62|UIG-~!jShU^j!p3FaakN%BQ8(Xm6|rGrEVWB z5e7nn@fp{M=7+lAg}08qVt?AoQUu^-qGOVtPp8vX>5T3}qysG!R=AI|4z$d*nkgxZh(!?n{9|-7AE;)i zk?6E@Qg#LB zRy~(FRFU~wayU*hdC;VRelHsI;O%Cb|IcXt!(4&Fi-ZmGTO!qFDdw@@KR?)l;Ad?w zVV70I!H?|bQZ2Babs-rWl7`e?L2>PiWm{d1S(3EbSr{93j!nf$gBqPFy8<+)|CK%p z{)a6I>qs>bcbVmKCd#0W)%Tg|vlK-3cXx4{*`3Lco)7!a)_vObD)Uu!5px?}eu4j& zJhuEIE-FAZ5!G^>Ovn;6nrod@yb6zP^Z*U1=H}wbXC&oBFD>WR*P_vzUv=kfd+I4H zyWfi3(XjLV-hHFwDx5StHRLLOTs+3(Bx8EjNdj0fB~6_7k@YIo+3lMVsz+@r-Aw}= zswH$X2iN&JoBA4c5dpSqQ9!his}NH4Pu0~&BB~T8iU2AHkzYO(`j|5u#KQNz23~pA zlej6KHN zxv~Z@je`0_F&^&Ee zeVRK;C=wYyc+>emlaCR%OKCp{P#cXo+@O9!;36c5b~#EXqaeZADWhAGJh2>=NCNSuS%D`ilCCeO2Ai5o%kyMu;E|R^Kss11~P@oa(S;^|AN3O zQzpcdIr*4WJipmJ)Qt2aHg^Z(`7?BA4QnN+gueO`9ioDsd?hJ&jiAB0*JTtcD41wa z-Z~5!Je14#_mb!E$~$=qoZ7LG2eo6V3}?6;pz}sHhzZ^>@B#)M)tfOWaci97gHwdW zW!eP}p>$`aoel@)sUrMChl=*#sk6qys4dt+s^xJUcZ*krcytI#gRT@_)y?+r6}_q}Wt-}*ic%%-UPua( zt%Loai7s&7<(6sZWIhcFJ)BN{)p7EwL<@VB8_IyBy?E6mG5)CWB!XX6jK5#%yl^y( z7w_F{{=+XMuR`aA_svX6XRH671?Hnfn;NipwnMaP`^sQw!F>eP>?&ARTrc!rJk6+z zSB;_gi-lG7na^OG>CO7x$SMt!?zs+b?7O%v|B&X3+x8<)Y#FH4twqHI0IZ}0Ol2^A z)mzfZl~?=x#;vqqQ@L#~PR=ZKXDytdqVV&fp51*s%g3#y+lRH0TN3@uPT(*=|!)0n(M2~+qDhQ;!&}|s~v3BQF4Gpi%i_+4^;VC zyD)~%Of0P-R^b5q%}*GeMoNIAw5t0^l5>MqK|olAFux!$s?m}St*%(0wGaS<;lfwL z9^+pFEXifks{+-$LxXWP&XM6W2!NIBs~Mat$~(+C+J;H!jQv{VD)7}*-rZ1RK_!-> z)&GvT0vrIZid^-bm@Ds#T;)vdC@pZ@t)5n4O4W-AV2T85t~xwmKF7*|;Di6K{eY96 zFUAV02JDDt2W)V62vGR#ZaTV4pe)uoVklc5Rjp8>O9lYs22{-g0rMqTeUXmiBw5Ir z5x1{S?7M;kddH36r$m2kz=~}w3Q8w;LY6w#qaA2vtdLIboTR3cI}z3wI95usbw+Tj5APTq^=lU;^z~C|%#o1mL8+B@ekmWrY3Dxg!A(s;7(3 z&nw6Ce?R;t4kXx3tw&p@;hPq85~`hV548u|aBy6MKEPPt8MiwocGOQ-man4vF14|X z^MAqk#rmo)1ofK^-3ij!v3LAxpS5Cy424640hJlD`$5>~xqzV3h%R0`4vtF}Wf(d* zPPEkBlT!W#RMOu4??Kg9(Q&xq-f>~9n$8ZuwuD6@s;|SIG+EWe-f@3Tk%mqHPG+NS zp_6-GuzxJhDI%p9AEjidhWm?=ildP`(Rx$@OZ`IkEN04+@DIKIu0h9V%#7M8(4ZDb zou6mZalpF~el6l@d`eN8tw z`#l%vaqilJ+(h_v(KQ98pAJLR2LxmK{W(x}z4nbr|3E(ps7*L~7`<2J7xDcT1}gFU z?X)ZAxL(a`C-O)Db*8SgwI5T(>F5HO3!?q;{1|*c5|w?|Oxj#T-=BukB>^RFoWP>7l>Rpo`mV1)qO2&u!eQ05?diL4 z+#V%Ls#F0KXMs~U_w9Az6!uy3(G8Ktl{Z59`C*3VAfR7~t3ne!_C>(`ABA73NGj>v zN~C|+Y1BRF0by6QQcbU=EumHSVl@+qg6v<;jh`p;m4^}!W)34#=oG^MlI&;$lk;W? zH3>Gzafrpv0lU^ks(=*xL8>rSR8-0Es&s@tyQ)fb)d~MQ?fes;+iXm2RLoKrk*2_* zG8qRl5dY?LqiauJIi%SOP9cW>JR)_Rs9>r`=Vsdbay7{5$19w5`+G4}GUciEXwT;K z3|pznWa*{zIHHKulT#-N{pH9L$y8Igjyr_?GuKrV+!yuwWUMb&db0hCTPaWAZiuM> z>f)=Y)VcG~6Yvu$#$Rr-GfY6D=#k=2SC(^EKL?3IhD0eHGIJX1``#i{IAzlJ4_HpO zF4`<*Klp#GRUKSd*PAnuQ}ReMMM_HmRD4X|@1bT_!S}B_RzQb=z9hmQ{J&amYPH4b z6X@`SGENjYk7ogn#-uGgt?|pjsdk#55)-vM;@`PSWU4xmsdM~)J1@9^a#|AkKN8h! zi)_aD03l@}xoXQUTILK={(RSkRXO@X?7rtXY0eA_N{gim*BqsM%; z33#A6#W_~9OT+_j-NVqHj5?$BY0W6MB~B7S2B$yPxtzS-Tq)S?A35ptNBs1d(Hdqb zoq1P}qg1+yxZtJ+jnF{%Z}{0yF>>ri7rHTd_q-l+)W>k%C{603fdV)cE)ptT z8?rAnT2XR!xKjIuBE*59;s@Rcu}>NLsdvSg>`!Cx6c{mm&rEVMs z>9_aN@R193TC{WfD-hH|onFHRPsK7n5v2i36Xb`azRNqDy*KUuDVd7mKLhw9+&sha z|1@(di#sV5eXGRtkVO2UQ1zw_lrWWXWgC`3_^Xa8vYbsXrXRg(MPFZ+MSod3L^HgT zq4En+(Z#|2&ka()n17G{C>%~#zK*^swmtlOdV2Uz$ST%EN77WFI zB;}s(=;i_*^;v#_U0rwe&x#%|!OEgVi{ny58^swYiV%)fZi_jjiEnUX^7n4dZ|OoM<-h!Nc=+D6s1ht4_O4ijJ2GnKn>7^<@BO_s35WPt0Ozgg3@G-!!aRRG+%scvE#T_(I<}@ z&EeTz>rMD6ooCgYu7RUKBrb2C>Jt7c&TS@6lacHpvyNW-y z{>_K;*BhRkl=>1y{0KG;4__0irSPHZ`4fIVkwUq;$|>Q;Ra}vw69i_3^M#em`pPO^ z>?NtE)aT@aBoqbYi!#i>>8g%}-VO45g3(iDiLeP@_~NHyZ;@HmIM8l*J!U{L9{_6K z)nB=C&A;12$!&Difmm^k+x@9>khYHCCN`P@nyhoZ)Y8ebm^>yj1TMo5<&X%rW3>h87KuqDrjwHF5SuUqju<(a_294Itzx<-T?{|vtH?UOyl~9T z=^Aw_W+20P%?f6a$IO7}HfDgB0Vnavc!6@<*_3ahpJG&X^O5Fe`e|s}%)c4(N--!d zR9OdIZZUa4zl;+j{jx6)&sXSiy0ml|;oYHC%wbRBhQZ|7hUyOo3K==aO7>g#C7Km2 zQV0Nq?vAZOxq*8NgG6RR%ph(r-CG!pXlVm8u~lSj6`9Epn5i#7;2jDqO?5yde)>1y zu_NfvzIx&tBR;DL1$))EX$@iJ8ug$zk2*MG;2hK@uUNXXXkWr0{j@^6RT%<$E%KfA z7@UNSQEM^keY|V<(5MDK>*|DRaY$)GO&H@ya zH+!*P_2a+cG?B^ z6w@&TeL3Jp$QTrZZ;@Zow1)IGAL(ajNs)gitG`rEy)1auWmn8=jkr_DiC2YRo5AA0 zT!mEx_Uiy5xSgdX`}-lyKZCDA!54qcskfbTAOymVm&1%@{ruDG3lJ>^oJ-4ui|!Ok za?C^;;<>{8Qm`rxHZwzSrU?jCI(ui8;E0Zu8<2)zRWIBzxn_VS06zs@nx@gT<^Tf} zJCSB@k5#m0X5#8lZ17Hyt`4Q24wvu0wlAK33KY({JTX@obr7Rc9^5kE5M2-y`&5Ei zhEo!GREJslaji(P^Q52dCBMSE+BH?hADp34;Q{vp7dh^$FXpmeg$!1S-U`1G-?hBT z+&PneI^v_4#kll7;+Xej;qh6+KPG8k~%j4Rj zFJiKWj!mkBHcI#A$uzowwpYjGGj(72;^uKDs?%M#x2-OAUA1ibs^W`$ZyO@}FB#(m zLd&E2HbZ)c!c(Z=cs-7z?8_E;r<6I}dzqu5m2a)CrhCi68x?KU?;KbEEW571Z`f3N7VDUq z%Ln)}INwokLYDA1fo%HN?Q~k}1t8mRaUm$f6=ZC_H!e@uOZQ<4xDD^fZT4#=gJ8No zUo5iHD{KzIutY_xGq~X|0i$N~tKy#7QrT9w*|&k$SjS6>doD^@C|<@kP3W&&wCYeC z-y3%v7w4H|TU*Ji2J&%L*RuA=lX1C@i%)B+1BD+-@{2!-KKgC){On>`gde2&ICJ%f zt#lu%sN$+{i_FrfF+BZT5?vgLidVW{5HE_gDWLW6%`v_>5*sg!OJ>uH;znNj>A3x{ zl|CQmdIGH(*h7&6a?{U3Mek_C4R3UuP=0XKmK2~H4rO))$#X33yRU`~`a=}S{`u*C83z;nkaC7fc z9E1@uFRs)behTCF5ma8M>v*Rc#%2|U{AcUv)0q$)rK=#Dqd%s+Dsj8UEF<3t&4($; z4r>13iCYUBs50TZDCvGbXaP0|9s{y0ov|$u-rtEUK2tu{+@G$ZgqoA+aS&JReTCEe==$_B^;%+ zarVSduaM#*H^8T^&`e2poNk~OkXd~?!yDajZC{sqq2Wxc2%j5PwC!9 z#D9+cX~aJ+IXxtszO;BVUvgT%Z)hux>Tq3h>f1^Vu-1O$zw4BIA_N>TH?I*wBB0`V z{PZWfkoWE+ya2hiaInw*)@5cEaDW|p_=@YI>9bU{6p1g8j2CFd3ml0ogInVT)-Np{ z%F{PWp?cO00JLJj9+t_MoFL!+nb|Adb}jg?8dWqUE*+PNai;*pPAJNe?^9Q#*(rLx_L>kjFImzHGb=`m^@ zt`1MfM*p9-6RpARJDRiMxQY=3ByrG7Mwjt!4Rpi15~S*gRTzQ(d+#gAr|h^l_h>-O z9B;Y`vK=>}wiV%yX{^lQeoNDFjU1i|pHi}?Di3J-j>G*9%aZxh)Znsc#TL6n7jx3< z$o$KBruO>Lr0!i02Yd(z1pY?o4;p|~1OPY0mLIy184gGZ@O7|)5|Y8`g3dJH><>Qh zo*et<_|&7CbtST-ReVc2Q`kasG@bMybIC)+Clo)k^7%e(z}LJ#)*tWo%=djRZM1Cl z;lpqL{9JfNY4(dB1RaG>wV#y&*L__kNw8OGEGDhm| zHHA#DJnl5QJQgp+PtRjDlXJ^2;0gF< zw^FcX_;xVg;QarP(_nh>&Eu71u@0Dr;;<$UC*bXteSn|JrxzF3VpLZcC|u?N5jhKj zTV8dIk}EvHN45o+eM5dbf7kKMWw<^QtBKDLzls76*jQ)0CQ^oS?murt-2%|0!ik(l zFb&&)ukHrhYFphK!S~t0)fhF8`&gKhLH#f*4d^$ZE zRS|S6>GZ!Gy;F&w4hGwj7tssAYbnA;i--s`;!<4lT7~yGd+nbKR$dDkd}_#$YRupR3*C<+;+uu)oD^(<494z^G5qsFbwIs}4>@i1UT#V%EC7!jCKv za+2Pae!2;x;=b<(-`vC<%38(I*yleZyKafsuepz`*@&zO|4v&T(dhONam%2UI_kRX zS3P|%5^Mz(ITW{yL`!sbk1^-FNu!vp5P+7VROTPM?k28=R>Y!mlIk(ag_YZ)`rPP0 z(d<88f$#H;x8hkk(-mUsh99)$q;6N@=bjun@PnCeQJ5U@E7jM*Z_#^| z{4zaS))YQFPA~ENrk#zJ&f#GQ*=dFjwF%VmPS`-{^t+87%3ofChEuAvl}?(`g=vE@7VW74A_!ELngUDJ-zG_zT8F7QDW6a}=g5=lJ?UVuY5r|2HFC z+jFzLmQ`rjRs88biZ6lV%U|Z7xb8DI(GRxa2){;hpP9}Z|NA9D8o1tEr8+er~=ndte!0N#|ndxU|D`S(A=ZT2(g zWS_vj?*r*B`k<+^-eyjKMd+T}c5gxryz2e`WalCmI6(%;j+cp0KuDRKDIw*3k&~tJ ztlU!<*1+Yd&* z*`m4=q$_*Qs`pervowCzFr20I>tH(YFK!*KWV_Tvq%2Jk>x@q$SK%;7y@xXKg1^W~ zWk?D0s{Sdagv#YAT3ZDEV*IRzt4%~-)}dd+MPIZfx;MDDsA_FaDe-4G3#G3KQgpUBlG^V9S^snm&(M3hT(G0C6A&G^rRKSJ1HWP?sG za|nuEzi7zMj$Yr}W2-JGeN}stnq=jgCEI%1%KXM>SffgI$EJEm_4wcJ88-~og=(^F zPdz>C`C((rr9RafSxCCi`73%IvTa>$UVg&?)+l{I zP^w2%k9wr1)6inx(XP>|fA1gil`@Gw%B|ecICI&;kdm+B@cdgoH0q8;xu;HyTRn`O zj@Ftf+V{Gqw-oAs@>fJUqA{qO*We8E?AkrSsqXW7qHp$?47Q(#YS!AOTrQBm938tR zLD{ACs2Y~v&fXY4uPwK(!7p{CzuJ&jV#<#ZVvCi(a%hY9X%*Lfh6~eeQxsNyQ;*4m zPgpkQEX~k#Tjk%+aeVxOZi| z)x-CxVK1*W3h&jiYaWK;@#Xks{?c%7e!O<2e}o|~#k6g!@DtBe;N=a9S2o86{G`0D z^{5{%x}B|6&u&aP`;lL2=58OnX=VOap-Wxi(2cL1lQZeV#;cbsJ_WK6BTs7ei6uR~ z!;Ab+X^Zdm;Q8KozF*LY!mB_wf3@+F`Ry&Tn1SowZ(sG;IIv{OeS4yEVMdMPh9BNk zP?f}D`d|C1?PuAci-LDA$dKXr@&PSs1xpSEb7?CD11#iuL3kcAAixqom~A*+~_U21+g z^@gIEJmnNS$|=X!aFpdAv`i_~U-DN3I{dfwTfDr6XY|@V1HRN2lTEEx#{ZjaI+<;{ z@Gt2$f2f4yQDyL`<54Hs`Au;C^*Yh{e|CAp1(vPtcW0v75Oj+?3i$5Z32;i})hIoa!ZEvB@crqm5~ z`T=$d?au1!}t3U zH?QYC#E9A=3%t}$VXCi`TYK{s1%#y_OnsBA7lrKN*z>}c41{SKjDN_tNmgpW=YQv= z7@lDb)$a*f<^wks;HJhK`gYCIjYs@Lo>4xtVQ*5ptQ=u_YN0~WAD8cmfPSbj+IGZ0 zI2DX2z0~RWI&h!%H(h?$SLrXU_KJW_+rs_)hJBq;C3_I112kxdA=9kCX3&}s?4~GL zPu5pBWR9*bKuMz+5Hg!N%4Sii1eG8_ulFUcf_Hdj2< zbp_1Jnf&+0t7#VBE!q$bIkddmu*Bz}-Sfsmaq?XOMUy{ob?k3ApkRH9lF-K2X-cp9 zN9f4Dr_mzxSG9Q=cuegHc_uslNCe;JiA_1?Tlqfb)f! zT|eKs8o>L^49+G7ZE)_w5Iy~J@MRHr<8Aw*#;wy^IvwY0-fjF%mrqlnc7%Xe_M5Kn z61;{3F0-F_YX~EI47R+`}Iz_#G{5dfnMPwp$UoodSBNA3Pe_EIQRIv?u6=p00)=3uQ9|G-KpLWu-#no6Fwia|F*dWv;Py%etVL>x_(K|eQEalR2vv0eSbSL*=vJr((2eY zDWH|Nvr_=Pub)0Q;iq|91)#*k0vgosJ@QiwTB9aEg-dCT1X2sNr4sP_F-T2=pUPs_ zpmjtRUZ3rI`=zDfiES^`Hu!1br+}XQ@Y7a?p5HFYSv0+|C52M-tbxXvxeH~=v+ipt zOxwJWP2(ku>~wq+^Zrtp|N1ZW2tKt#mWSB)9xrGW!xXU}*W-_5s{huodgGBc*;f~n zf@w}m5&OBPg8atabIZ*yzuX?eDVk#+85+QwGH1Ha^}o=dz|+?;sMoOX@lgGTVul`q zOE;PI?S{=5lpH0thQfpf{W7E^$=$nL-6uLqqOBf|LK%8l&A!d=xg2HYI3X{R$%@S% z`MpLHm9977^ZW7nSzT-A>=L`ksPpmhGv-4LZT{E_sW44TedB2R6Z4V0)+q%NCD5jBwiJ29dZ6jAG1 zt`~X?`%{X#y>@ATBH@|jd>7gI8Y>;T^}qGZkQrm` z8P@$fG3H|?1(5?gl>O)S=ovIm9_54bTiNFD*`Q~~6{+M=d2&tK+IO;r))zTPFk_l3@puVbpTPr~et#wAO+;}{P03c%5~KmHInJqL{Lu1doJWH5R<82Quif_J+Q;nBiE+o z#s-m1<7)@yw`;ZGQA;W9`nz(uJH>Mr%7`5Gd~IeHLQfqt(B@5JMg{Eewa*EdqG!@` z@2-%qM{Sawa%6BC;(0nIUuFmL3q-e-5gM=(vA$k?(a>YF`5B`O0S`crWM? zJ2a{YN@iwYR3NH|1rnMv@M&Kaea~MGDkCzfZmR}ND%Ar4brG{KBq|NPX<+nGBtmmW2P0Pd#jX{a^WKuS9J3V+c#iCjw3yJD* z|ImnuDgur7T(D4kkh4iM(ZhL6dBut9p}dErQgQ!GxYaOn!HbXZ09oHZs{Hv{W@ap zN5YAj-xOYnae6;{rS8`C{R6rm?^nKcch?_tg}c{V-3R|Kw*mj>zuX3F{MXxn3onc& zy-_=E(-o&!{SFT2+#Jo#AIl#&-lD#3)r!G<}`?c-im7^cc^83t@-cquv zW1D=gzcYA)us+%6g`pAKi(Sbt98ni6nLbbwex^6%@VEEI-Z8Yz^($B*yqgqpGx?)C z&W_O8+lQRWr`EN7eQ~HaYP_o0(4ZRAek^QT*k!L+Xf@b$ALkD(vizh;(A3A8pUbLR zchvlD@Y@NN3)uU%%`$9wr*_I|L)Oz`IU~f*5Yf{zl~fwwAEd` zAoIp^Yp48lr=>}Ipv8C5rIWLQ_B@q1^h1>~HAefEWy;T#U%ACMzp+^D_hZn4DV7DT z%QIy0y~Fo(H3t&nRn-eSx+C0wxztTI#cf+`_l%e`CFYch_JjcS+>(W9Z+vb&bNth? zPv^#D9`R>1yD8V+;Fh{FwjbKN5jAp`xgVT1i}=^g z^MJN(J|R&Uv{k{J)*SXLmMCT*xKVh1xvA~vVp?AoR+){o{x|mzyFIFJr}S7kt;ab2 z9ckS=PNV0-_pP?DQ_3%b4<)54{pgzpk=8T&=Ut?4QuWAg_TZvjf@|B9h9Iz|KonET7Ba_oNxS^hN2ec_8`Il7BL8pC^;WETGsr!n9 zsEV*zb);+BZGtw)E>{fcGhbhz(0}3nYPp$sx~fN=Z349Q>CX#V)N=~TfK>oN529c3 zAt~qF7}_3|kU(NPr5d+-(>&Ge)4to|*Hi!;XT0iZ3r`pfq7<~2Qy`_F@pxrY*6_m7 z4e~Utn1Vcph80wMM17ZAFQyftAxNG(CBJ_8%nww^8lsb!5p8}WPp<6pr3 zVx1)Gc|Be&rk2|x{q=zNjrSA%y$bvPlj0<0#6K`{1U@BG6aPc)C)Fu=n+4O$6<2j# z`A_Cd{*cNv@+qU}Q}j_>QYc2+U0PBwX-RTQ0%IDGmHOfTWmHIcq~(keQ~g@l5^==; z7rA8ABsOYKu4vR!QOY|7fo8}2?0EH}P1oap%#qDcF)r(4fo6EY?XJe^xsAHh28w8s z6FRyfrPYz@1+pUhl*r10b(_II&)=?vr(6SDP^7-*uU13(FoAyuQAwvPekX%Uy6vPA zL^>iyy1w&NfPzJp1R$npRH_qMOT(zj!%TtJgMy8KgCJkF<>I(@qCn(-`OgWlyOhfu z#A=I)0%1@kC*f;lOaiF(#-Ln#U#z1*b!lmK2tPjcP4Y`yQn^lq{WGR7#-LCM3{-yT zOl#-FJp|2K7_UtdDcDSLQfrbx!PryX*E(bg8yc08n&eRr zwnU##B8kgWbRu2YrZcYn4;qxv2X7j|o}wREfc2%%!$Ive*}ehHW=|;Tvmv(bHbc+< z;qCncqAaui;d^FKMrMEkOl?IO!B$Ljz`?)}=LV+0Pyw@bdy?YW+_(1Whaj|Ih>T!Q zrWRoN*zRVM>DKeq=Fe73aYn&31sQ~*HhxS>X@!CTjV8mqpL4Ez(B0?ze*b*`hkNe( zy3TdZ=X}oRoQqRRd{c&NonjpbDQ8lyv25@~MMJSK0;}4IHYFt{}6(hn04GdAG2ZtuVoRkXdy0*_-fT zLs_}MH)sU$n?=sDpxvR>^`#wt6Q=EE>r@}jou4ZVxPl{YwkDx{#NZD5o0KI_L z+EGMOHWRe2{y3@~7Kjh)Pl=ug4^SH$jwZj6>FkYWH{o9w3f~9pUEM<2pnShlj zt^XjzSWaned+z2drLCIjE5K4VrCqj=u`13&ehelM1`k*ZV})H^)sA9PqYoYsEM>Ut zS3+)`67Z7iFjhentxQbuE;oWHaS{yON+%%m-;EShb3C?Py^n5kS^b&=&JJ$Iwg!97 zCDZ{h&)*@qd}0c)P&e9L8-rT6_i)*PbD*wHyFkHXAM_D5t?Ak$*C`1wnvgF1cJ7oo zVm`4~%x4aIldX5T#uaJiTIiuODXj$W3s(_UQQg7?0{1Vnz2O__b1(8bgNF0EIjzzW zgoEtTW=a!Dy<&+G9ai=Px*o`S>$}7*^Zz}t_MLF#bqwNlRmb}|(-m956 zzdFfJ*eXbcmE_ckRM?+Hu3Cq@j?l-#cW_iyoYqqO>%^%lKbBU!$<=E8TpdhYI)ds1 zUV|sVSH5ET}5g)3HheH^soG~R`p&X>n z+y2mfR7rxF_^-y#gD7cImnSj$U`k~}(oMYRVS3Rw@S^v~jRbxaE7k7pO+Am}uZtrx zI|x+1H{a)|A`4Y>!mIA6r!D2LPl8XmP`|!eEx9+uy5qx#u1;tI`dAksFKC_F`f7Ta zA(Fj+*V$W{&NU^|Y5TU}UostCS>UtCbZ*9ccw!x8I`03^Ovn65=KmqnSy1*bna(E4 zbcU@}TK}=7Ho6(7Bg4ChpWkhuK4VKYY8#-;|vB zi7w-lC)ysYJRNR3X?bbEqK8hsZ@xqQQcT>XHy!I2Tc7D|`Xn>S@Ul9hCTnR>tKnko z5L3-^XMYYkFXh_$J(@XQav>w==Jm#sDb zRx=Z&);!CA0u@; z9F7LA3<)B?5NPJ;DqCgA5=4`R@t#q$?Q%6olT%fySsqO>Sc>RA7#?{Y5zJS4LHaKB zq=NU_IG}HRR3HQ#Cg(aLNi?4d2@|woY={bueV&Ww=3UY4Fuw{^6x*=daaV&`e`dL6_BM$%Y}dn)$UkGrRQHPW>2oC6`oFf^i;wEUM`;rg z#Y*Jp#AdKg`t(IrL7o#c7hO3;F6Uv8Zlj#vJ+GN#S`y(v^)?IKFynX~Dt#al-R~v1 zi%eKkpo7nUs!Tx=3CIC-5J^VjQg0jx2RN(_leNA7sBw3OW9w(&^Y!@rmH7N&;^&SG z=n=)h4WGMkJuxIsfU_x0c&O&LD0Joo&B!{CQySGpe@Q?Bd^_PNIhlfJ>W-rQO~kju zejfzuCL;e{@T=j5dXWc}3?ip%QH+)UhcwY5#dQ%bb^1(TN?R;K< zGvf|m)1nfuS8I%Y5b-_-@jgbO(&`Dv`F?+qGz;MHU#K)E80X+Zk#3JwJ8H)%K93FM zNW_|}+6MSM+jtntJo0&=?DD|*^-X%tvThxpks4&CWs04Am!vAfLj9x(mUZ@A`X-y5 zlE`j+Q*c{4M-i&XX1Ts)4j(A4ReB#^UltR&N$_KS&1wYEx$gLxLl?A7UHJM#NcR1# z!?N3;_3?d&Db=0L0i23wQHWrhcRLZlpC@A0!PVe#vneS@vavo}T{pM^TzfAPsFPkQ zN>KeEV$1A$>84$pTmo)x`*=!V{bH$Zj0D!?!4aVZ_RtDA5-v2sk&t`PZp;hs@u#!| zyl~8qa1SCWH$3R$P&<|4nG3};_j_vr-@=5?Nk*(Ct{nlKEBsHnCBiSOJDelLEN3Nk z{LnDVa`*U8A49HrAbU6%hPUY`wiCHdbJ2T8)z(r8NqKyy>sFz~xD}{aB!%*(B&Is(=u0Jm zyq)||!erW}LwzUDY?J@n5DXKISMd9n0rw4rz>kg~oou4TorH7@Mm*GnH#LZdPC@!g z@JWB3cAk(9E$OmBcwE)Wynd#owF)gwhiN}0CDC-43SJ=hJH)7*^d&InY-uOEUqZxP z?0yA@*)fr59#A5>hh;8tZ%CFV_jZvhwE+_Tq);Lk0_Qz@hO0MR;?{!g4cnPCHD-e) zFRk`u%{wNBPm%D?Nf%5d4|@A)M{j91P(4XvGr7ge>rCeiy&c5MhOsBjQD^4Wg?M~g z07|rMx3mD{N!{ROk-a5?V&}D4e^sH(e+$mF#>WIZFYbu3jz0?PI-gyrP@RT`O<}r2EDylrkqsN zE+3jvDD9x_*Jo2sNPY+C`Q{i`ZW?hyW{t*CYWx=f?$ zs!Cc4UuxywUo(m%4t~u+Ki<-pv^J72f292$;mbv$t37j_DE#WM6(mFgdiUy)4_dOG zsdXM#>PO_DCy9^3n?7lE(vglQH-*!;%yaT5oIc-?j--^}G}R@}nNqVy@{D8H)IScX zfOj4Q-kG0XWKiGDmdZu$Jr&s0M35J4gm-9Df5zz}yc0sYiJ83o$em;cQHyB#HJL{W zg>C}mg>}@&gvtG2sU{TVQ)XS$pfuzMvW4qSGLbFhE87yH=5@KpD!%d)&2m|9rYK3i zGF1s^uNGH!-Au8V%caFsmrP+_nLa+0ePz3ILJ%=H>#8Th2s^+FwR_zHqdb^1hTiu& z1?hqT_4|AXmVI)R>*to@in7%O-Y%D(Gzrnge*aDH3qj0TTG@DY`N#elmCSYOlw=2* zgq2_rTeWXH8kcbnaRo`~aoE5j&YD=N;JC@moN(ZnCFLE{jv6(vFP<1lEe8IOTe$ z>nB}}Ah+tz*3w$J5JmA?NhFZ))svWOg9#FQ{`96^+F2}r_@ytrl`UY<%H02TE=L`; z<~BVNR?4JmcNEVJn<}rmaUnSA3S6M=0D|g@|8$O91_qB<;R*{5*1dx1uAzXAm8x|g z+|!@ng2ZaVlsVEI`Y6B|C02lzQL7GT9FRxCrT&@xoN0$PY_h>2h?C@-YXFC#F$+WJ=~<4&sgoyF(7 z=c~(0{cj39qiZ9D8P)Ic`ER^kh_KR-iO(leIvb;ekbR(!Yv4Fw>W;NSUuBCpb|XgAXQwlQ1a7US#_H@8Phz$DQWG8hS%h zZ$+ql8MrSBVZ}z|5#vsT75h*(IpFN+))%WK1)$eqO{v_M-1!YMm3Vpo;P0@e8VV~Q zZ|=*HGO`Xde=lG!6e;A^mnob);Z8VUyy;@n&g5-u^&?KyDJU7|hLN&#VsNLSt{vJL zjun#^=Y&2fo2$=I0DOO7%%vhcR4VG@Sb?Cvud-x6xfM@YgJA~g)|yuG?w@n|?|^hD zX%x;08DAY8(}OFq`eU9z2^T?Kn{PP$oLMD#7xLcpzre= zSX;rUpAa2fB~ZT&CrTSdkcugp5WAeW+c5iM)+05LMUN}It%UpY*`oCcUKWDZeLH+= z%Qnh4LCFX`5*{jH_y4)hA-t5~g$^pU=OF$%ZWn^q25o2zudx?z>MD7fR)5)m`YE5x z1c1^$5O}d5StCrUI;>ET*R1ovf%b!|UIw6a9sZ1=?`Q}i{S&cJ^5>B_rSshfqkdvD zMXg(!B4uXY;zXqNu>EhZPhg(qLSPbPCR`Bu2;}XrQiD|yHS@8iUL1Ycz6W?ZcPhe< zZkQOMJ^fl^T(5J&Oh3O@-qIX&)?IJzFEU-{qyHKF85Qmp zBSr)S4bkf3n6Q&HF!a6H*`wfTB}TwYz@3k167DCOpO1;nD~vBiF+P23sd7x7Z*L9= z8YY&XJzobC@;{OB4f+DlFPd{Q+H{o1n!xkd(m`REev>3IslV~0*6fhgzlEhJkG(-s z2Sn;iBa)b5C*GBgbojX(-CtwEu>Rq)wsIg@#4}9U!$Yagv#zT|ri1bu7S2&TKZ8>DDxRa z<}+Y>xs083s>r3tNt2g~GxeV~#;b7V5WbWTC}+_PmQ}@A38IdC8xxB$Glp%5Vxo5B6tmlTnU(GA}ZOV3PKK zP`MJ=oBf#{dtV37J9PfS2ZLUC-on92TsZ+p#DJbX@43rVIp7)(X!8cGN=VEC@l7l6 zO_3hwcuG?2s(|m2q>QBy6=(tM;A5J@q`qPNBWZ)|%Yv+fx25@$VNPQMj0 zVEp`edT6m7c_&B6lE1h+hg9De4?O{QoW5iO}wy^=dt@-wV!GY)%f4s z>_L46yFZpS3;Nnr%6n*|pxABD+PsvZ-O$`Cui^slChtuq8=pbdoHoiJ3cQr}XpRPB zqo!IzRA=1}BA1`#If0EDIyrfpZCsXrY zs5@0eWjLfw8zB*Ln*LtWAJxZUGg?$n=U`|(X zta3^vb@@jO&+l*3=-lhE{Cnt4Sve+6!7;^3`QbpnlyjTDK;G+_!le+MufhP64guTu zfb=qZDUJH5U&)vl+S9Y{%@f>-y)fysWYVbb!1~I_`tHF;E&np$ZfaGjs2;yuzmhXV zd&33F5EX@?iHb%#IwvuRruWcaitM1}3#WGw=S3y2*`2j2Yv*kwZ_20oh@DB!yG3lhw?R zA)NY}s$`(4$d_RL8(9YRHJks8p{vo%PHvOmAlSKK(3c!*wG2D=g$XqEvtTF74v}c$ z!#rjG`&(7rEbSkE_(N=!F}9MRywhvmFOd?sQm~UxEaii8sUVp^|MgdWGIYcPNZgTYw>b{~hR!AnK zOT+D64yPnV9SwXOLg$nV)*_txsHEcKi_8!O(m`e2Vztzm);AYLI~Yod68XBj7krM; z69Wi zyu=BAhLRiq93aw@ls~+#6eZN;(R@PWYI8asI@R6TfHc8KT72tGEf^KFTCYg|v)ZKlJ)I(Qzx=6}gSCV*aKSA zd9*4)2TsN>=iT+N1iB}@oOa(UhjTomhQe-r%NBu;X`|}eu2BCIrAOS?66w*y_I03f zhxzE06<4I;=pi-!rOZVNkUzopDK(yrPNlaN5tN(^Vx;-+$qXesK#ZIYg1VR(5f97yv_Ebtaf)vyVA1R|tuM9piH|eAg zqU=nXCOn^7cL?wtsrh{(n%^(|O~lBNhaUAW*wja@cjP187J_oyh6jHVb%|2A$be9f zo=iVrpo23Gg&7rMiOrI6w-GM#j)*NExdLW+5X_V!Td>?nb%BB%CHpPsTptXxwwbt| z%&Gp##>hPY(jKYqC=;`gH4u`7i}IW!Sqccqn}>%fa*0g9DiXHj@~v6^iZIF#YO5zv z`ipX;p_E*>U_uWnpP40jv?relf5dyDBONu_8N+)aH(E!`b`zB#CJv~fHk#)AC$$l_ z#J%@eAjvY?znL|Hgi9AeK~-<8}9LnhB#KG!No2m zt(V~6B9z`Wf`TLsCo`)B|Mn_<)98S(a>U~7@1w*+FBPTCID%TuFw6{W@uP^vFL)bV zo7a#kt$55^js~ks$!x_TA3jk`-Am_*f9t68=9Qb>e8@vl_YK1#S4SgTcN0!PfgXmiUfz}Ybp0Tza{!)!Iq4mYsi`%QEr zm|55Z3MONf_W)?EVdw{09kBK^qP8gi1q5?;VMw%U&}P>=tfYbN@xVe9w@xE&B`9q9 zG)JL`TRnEs7(ukw+6LA1ym4;A7qQ)Rc0!3$MRt=xPG&Zjs1KPSOKVy-JZg4jD)6m) zt&O`a;AALnZog`J2aa1(l5jW~gc#TE7HUfg-|0(44$en3z=8bEk1HUtZu@hbUAglY zLTFq_P?YIst}6r`C8le`)6sSB394=eIk9ln@89OpzMt zNtNg8$@0}7C+Ekoczctp2fzO`)l_{wS=4LuGCfo-LInoVsFN7DoU5iyp?Ij}yzx|L zds+V{QAv*uswFIHwt2~YQ--BB1K}r{lsuYKBWvQiUOZ^6{=8r?e%xVU7phSM#={rE)qyOl!pj=Tb+fl@2r2+P`V>%=fb&%Fb zgd_X?F#mm1;^hDITtLdox&x;@!8OV`^?6NU)Xv}mY11Je3xV~Ad<|92_u|}@7Os)U zk3CbXej?AD%uxJ@JMdDf%#yrgK@Y(9978WQJc@-6YWbn`7a-8^F;LikW+4E@!>HNE z$l{b5;(v(&d@?TC2kNMxiF6S7)uu3abais6kVjy^qBdq$Qb_$F1--WDTUVPhkH0mhWX&c`2aiveZBG_rs;V ziih?%==*yt_$b3cft(6<03CDN=dgvACgBErEG(_q}9BDFC3lT<^{589^ zsJ)pZsw@bT0$}R^G6=UhfrU4K1oII_`(G#ZZk@; zcT?zw@lXz@Gs*TS3q6kxYi3o2a$bKstNIVL*i;LQ0+A~g3iCqV6Y2W>g+y$5iB)yj zR;mI>V=q|MdGIF+tIDaZuu|I*d2%ARZpX9JexQW=ZzWdvh?vl2)wCqXQRlS!JSYy z0B{FRe(Ha-a9^|-n8=+FK81=+MGqai5M1`Rv-8eq1IGi*HEUl%b^%_?7`f8v_c!9T z7GR&|;N)%bd^33jpyoaEqBAHxICj3m=+ie*lk3Pg2`v+e=;F>4`*q+rDBg>egv~<6+3NL4%buYTXvT~8;N zWoEF9US!?-IqzG#h9D8b$0J;nR3H(er}5Oy=e=Y^B-$LWh&Ia%m~Bgcs=b>E&E+DO zub~CMi4uwloL^E9=(!F7G&s<*7I6NnFb(4&s!DO7{ml?m77IT?pk1X^`bs;UpU^N5 zQ^gx$)-m+^T^>>HC>nRV6siyc8V!WARc!@w%!~#A4gCX)!qHJ*v4fN850Zehzb{mg z5qIOXGmnh$)#O7@wn6fWeA*wU(FZ4H01~WLl81MZ(9NYl8zfsPp~FK_6V4^{QouPX zAX${Mg*~U zjyprfacySOv*bloAjsD2{_%;$tRkh1>t7rZiV& ztn_P4$=J~tP}M_;)?6JCA1+!eQ5>O8wOI!N-)#|A^}YOAMl*&yaR8fFwzQ%W@U_*r z8B$!-n@(<*J;>fxlMh!qu*uyjUZnKOO5qt3rZ1zajxq75u^J&>%-{$Ha-7PNOR-KOe49K(5_nFkl{rp= zN0k;hsZ9=+Y7;(Ga(^*Y$+XMD++BvqziZ|^z9k8WT!h7nS`B_)RGh$Pl$UyRw5ZQx z^2%=KG%93>PBp4wk|gIQ0EEc1qun3vag)r*OH4Wvz3g9tA%#9LFy==vsX8aL$N_Y! zz^8Pfr;lsBPz5U5C4!Gc5cZL7_V$?ypxqKoqNh!@KF=Kciw2;uWB^KwTpj>GDQPII z8i~e_Lub+h69?3~Z1wai&R#Th{w@^|okN(^)o7Smo0qzyB%dnCSpO0}Dvq@J#%yC` zu#4cMt2x%SiJvWKV1!Rr^%xYb8rS=+HwmrWdNf&}DoZoXw{XZ))2k zofl=apHM|ix?&n$%+04EsH3+W)rseEp!%H1s+@6{w3 zws`8bFqJN%{g9ELb)|{XC(thWb2}FmXKa59*PrClV5G+=NGf4}ek31pcl6lV{!kh; zL~h05e{E8|5v`YXx9$Hg-d-jaN z7vHR-aWYs_67SHOswQ7lHtIrfj>ivcs(SPW=0l|fgP;A(xLgiEnsus70R}<$FEWm` zfDl2Nx%|RrFYci5dN2Iyp07H;TJqMWE#JS_@orkx_TPX0e)H?@$8zraTsQ5#{ONbR zp1<|oVDAC%%nkoxzu*4Zf85vcO52NHzw-NU|B;h5>xIhDzr1|^pZ;wLp4LYo?+xxG z727Ug#_;W4huwY{U`91(;&Y?gQ=>U)eK2~y(|!0=z1&E?1h$;wJy%29{^*p#F>tz= z4-#TPCnMSNW)wP4T%Vgp{*iM5_K*E&I&%Fwe&i^RWa5Iu&2VqFxJm0phP?$Tl&7)r zEJVD7xUGLRj4NPo-5_O@;U9tdlIE11bro7eg8bdKr2c~@FZnB|0?{h0nP(ZP`o>TP z?hC*GV9trrEutPI8a@SYpT$QdcLtx)S1DHgQz1itR!SugvkurfV~|( zmnznUtkBp=Ge<$Me~!0Qs8J?G)L4*;Tc8NISH%gQLj=7INo}m!il;*F!_u>I)5<@C zv*PV13ynW~%pa~qKv!9Tu3@mLKa+n_T#2wLUnFBFK@Avz69b!*dDm2!Sfme@_$i)Yc3gOE%RTv^h;srdl0M+v{CM|xSmw^7% zbg`(kQ|_4UL4}JX%n*ZvTB4Av|2`!zqzJD37xOU7w%i3q!I>b%WQ+FVOd~vQ!Ox=& z!pTv8y|n279n?@LMk(qqq*k4m<98)!1!Ae-c;xp3Y7_51 z+Q|ZYMe)2Bx}o-VBst{KzMe}Sjkv{ZDe4kWozcvrQqw?M^@*EB8xCXInK!`%$TjwE zUuQ{suHH<&+1*%DGCmA%6t(*Y6~wV|n^mZ#p@xC+&4uw{Gy)I@W@ynEBUto-_MXa* zi3AtS{%QJoN(MiL7>MK;Q~eY%&>_<`A%R93GYMyJM7IMcv67*wh7fl%^M%Y=tcH^S zin`ZS6YGcR+t^VQ`Y3CL4)MGq+A`HCqdQ5s())b3Jzu&TdVp$CYVrwJT)+n8Pa-Z- z4ZwiG6sR(fsh8Fxjy_MRIEw7fsYs)I*&yCDQzTrrb6hnfPdrD{Hoo}b`d0`x`#s+UCVA>S;1>{U*6cRYw2g=w4^=N+ z6l*Z+4(+y67xF{rxb1|EDT}jjl^HRKQIb# zm+;;jn2I9UohH!=tob>OmkE!;hW;cgUXfO29Ye*=3~O8`v%0lz)1+;u^3KNi@-x=W)Z)48^#q?U`?;o zOT1C{YHS|=7hZ96%gtIcl%hfrzZE^eskEsIZ7_+fPuu1Cg@Wnd8JYeF0enBo%ruRb zHwqP~4TyUgWPO6J{9HXlN%zG$xr}rlvZ?w^Cb#^zHU=eurQPu7)qCL=f4?};Lbx4`0)Ex_M1`>$_}dw+8J^Dj}li|K~$wXSzAeJ5X)S9-k!7AG`2axnq0V0!@rIG^)W6-f@0xMwK&sU&|hC zd>ZuL;frm>hR2?FeRJxaFh5QC7L7Ww%QbewI(3NONn^(kcg_jTIHInx%uds6HEb9Y zt!>qObI0+xREKeuRQ0kd%sJ*W<1S-NUSMSUX9v=?ohetoJ#(-ZJcT=o-7)Ae%xqDXzdYJ7fGOt>xHXuIqfyl$;8S~|tCq+I9f z=sTTtJo+uo)vCJGX(vZXk*#m1M-OD=y5lz1N5B2T$)r+O_+X&krhRYD=f_)yF1-F) zX7Ne&zipXPB}*GDr?VQ@CWKwA(&XqhldJp!7ff9wO>4YA!THIKMUTBx_3oZjb5&eS zV&DR^Dsssb$#3zz4*jd?(zfezlHZ*Jm!wHf+fN5BzV}R$)S`W}{To&GUHX>ELA#_E z#w0!N^52yb`p!ok&1uUA!e;%X>wJCJyj?p3G|~qH^J=s;2ZR4!a%0N+i#>s-RZDLc zZk0OLOxrv)Vu89jx?YpIPl`*)TvMNQe2OaaF3sXu{!0f^FF7Oin(@(d{2g~EmcP=K zvLRf~zLa8f7&ptZYhBXf!XM6P-EySpX`zq|yhG#Jt^kVu2m-;^NlyzdH6A1-`pP_h2EC zM*pYn+-Z`3ZntwZ0um<6LG);m5D)^&YgHvjoZSnrsS}wj2_~{+1(792Mf1s{5-0<< zXduqL(?C%M9-y5V50=otHF&xk}8b z60{mKzSLk&nZWEJ%CG7yA`@8nE@cAyETBq&unYjW7?iP~o5V!*3Tob=pyrJ^m^(+P zxm^NPB4#>qT8}8>V&}2MYe}j20&V!?bE$d{)GpstQh_K5@n|&0>GptC%*2`sRw4EK z!qK0ARg6X|FgqH9st`J*SYH7t7#TPXs)F!_1ZRnT1G^TWRaz!af# zSl85r>U}B7r?W$DXvX?fXEi2A8d$CSMJht&1{4LoWzLrG3jWeZ`y8Rh^ z6OfhiO+lNu*h6sOj+Fzmzb_Js-#ucZ*iMOkq=a_1=fWh9m}pY#jRmKLhsLrr8@o>` zYEA7lLSvf=;PU79gH)z~w9Ho*%2Ln5pbkv`L?+ZTt))8bL7mB)p5Wa#!_&xritgd3 z-}G}btHJ^?*3e%tRlH5rd!q5%YsK={?2@3;nG-gWC39cEkxku~3Ayys@AnDG zqb^lSRRj?b(LXc4!8gwhxOKUOY^sa%8%*DVO=0>GMw+?{vN*q3ON(keI)MYyfeIEf zZnK^Ek^>U>ACg=W7-srSMA?g1+hM2_kPOJgcEzxv$_bo_*dC=}a*8a)0*HHkZWh;&C}sDQu*@d?MH-|&DxyYJFVRp_!D@|Ssw_=> z{{!Aw6h#};%eOgVehbAl<%~agNRfi3n6W>IIkD5;!lk$koQYyl9~|j4PSWax4?N5StAh(T{j5Rw)%7>?mQoKjY32XX^)_QFk_zY+DAaQ&hrOnK<76TO^YG*paewq6e2 zC#fT{5KnA1JE+(;!o8bL4>=ORSV&NV;i1G>5W>dSKS=R}zP`!FSoAl!HV=aZyJsM9 zBuLTMH)@DYI*~AU(hW7^Hnh5&OK03hLxL8LEvv(jGTPAw64M3tOtUqIF~p>4$_*FS zU$e_L@Ra*Bv2@=7k2B%|Ci$LQJY@vX7`ur!auX+6o;b^srJSe_=$QJk>mMc>;%z`o zX@kgFU(n#A?D(hyRAx_m^Y3i@aQ&T5`(|*jo-Eg0E>cG#V^)6tAgQ4cqgEijI_utG zMkX|PE}G^(5%+%-XK%CH0A_;>ijV#<1`iu*yxfk6qy+}WgNL2W0w`V1=Wk(QU2kV7 z%P|f=VR^hgWP03~Hy!=({OAi1k;hc7lo6?)GPMe6i)J-$#7P2^*q1QX4|(8JE;d`od^nPew+cxFXSk}kT%tkC#O%F6Z`M=3*=uCf zGzeuBDjM;R>bkrAP9pdL-o2Khv}pDL4HQ`c^8J0-Uk8V&!9%@Xw0nrWsk&Kdv%KJuVSmQnx&o>_B}+5Q z;8BZXNE9H_Mv~4vd0C$-6yM5>#={gQFc}oPC?GW{hDs%2vQ9X)Pv2+Gi zQn^tAvt73XYDDlrNj#$uJWxX>CK{6{!T&8va8(V=P)n-_&UG-HJBe;&W+LKfmRuEy zvtJ;EEV{vGR5V9eB|F;YOO9J`0G9DU3P6w6YvfaeRkJGKLtoZDf~Q&^x`#CxY=M}3 zUBaqcQPAKk7u+2~$0(j3kZUfHh=0!bB}u2K+k`jj6|(>B(>u#b!%W8_6WTz-k<_8#GR+9j{qJ`2e)ADdagT$3 zu-%0Ll_4FyG@x=5{<5WWvJy^dp`K$f?S#Oz5Z*5(T-3<28V%q~5w&P)PZyW% zP%fk9Ac@Ft(je`?xFTc-CphvKY``p-PeZri6j6E)%{5QG`z^u*PrbvM&N`>0_x_}Y z+Lpoy{RzdQXgXjYBXr>>GZUeM&fWZd*_Wx)*C?XlV(G#?qU_B5W2)={MGbWpZH|En zd@aok4t;RG*rzVYuq`woE=X<^q3>xvCf>64e}h7!%hB*s4-Nk2&?nj8B|c->MTSCI zoX}=I=_L{USK^z_^C>}z7=k^F2ZWu7n@OB;pDvo8mvbDHba7Z5)$%Spfk4!l|0V2!F4d6Wzvhy)S;}zNL)?51w)9k6<7f9g zud0%8)eeb!k;nlbLk=|=nG~QTu~4-bM6+0jnzuUOVQ9)szyg%q-k9=v3iAV+b4 zX2-V!!7M|l!7MaxQ_V9_FvC-gH>Et*L~Dxne#8=-d^5!oY6$#K(zbq43?CJWq5|ds zF_?OXnz#H-5uEb4ufs*QVGhu2ICK7a)SNY!^5_bav;%Ji`8~_$nZOjeNN@Y`>G`84 zaV(9MX}HecAO)lrWNE(xHVd%mJy=YEE>FDmp37p&;>fgYhq2$jI1fo5T)U7*HOY1AGOyUvf76b z`%_(JzUrq?pt;H;3OCV^HFDL@$Pnds_8b>es8nKHiB5>nKgI1$0S0sP>ZhS^1U`N@ z&xQb@LH%xZ=$XRvGt#VDXjB&q5v(c&Q(E0yzqOqpe_kZBMVIsA~m2 zADgnN6&Z(1NLvS@E12!zjKgaKkO-#Bi&nbFoq1S#rQz&a`I=LG7nvTV@OSb|o%N(k zqq$mbB02{w!mKb#;ag>YWv)Y13-0;Bf*OrSu=Qm~;wn@RQzVl$twC-O)l?)iuI_Q+ zp_8x9SVtZ*s#8M9x4Y+4$ZtLKSj@Y5VgLRK5m>ONHk3&)EJBD~n8Eq~H|Ws}2*{fM z??KP`e+_!nG~BNKLcpj<@bqF$Cv|cL?+*fpK7WY3J|?wIh>W|9z=@|u>@=klwGspp zM6f=<_d3Pg`o$7AVjJn9XRe34E>YCcPUFI(&`-I?Zp=2qOtNVvHb_Awi;KrZV(TK6 zk_lG7pj?d_l&3rV6$|f$i1}t;gasaK|C}W z&eRPcf#Wpu5FL^-=LC|PO_=^0DNt^DvU@Y#M8{s=R;fmx$eqd!XSKeGz@!*O+u}zM zGFWX2dx{zz&;bb<#37-44{6z#)2(u^+~DuR$wP#{DQYH+Q9LtIG|a? zCx|mB+koZ)3<4mB(&G0sLBp6tBycn+%>gs@X&yXfZ$31AKvyf#J&ZY8^utlmV+Ns^ z-0pt#Vc%-;qilm({AzqHe)pk7N&2}F9}%|_^IuT+BpnAB=^|Rwvz!<(6%)GRiGuZ6=+Zp`ibvUP;_>W~(&qbsyED z_U+R={}LSp$&_gyPH`vSqoq-PM*0Kj&z()5)JN>tM6vQzGjYnMe^Rb+xwaMr_F=sQ& zc?2_}z;Y&{3z_o*lfC$f9jW^%*Ks3#z6&fTF!b%sgm%^BpM*gVBYnQ|cZ;t+j4?UE zWY7?VTGE4xF!`@mkNkDSpbzbVK!&}#GV8{`(x`*aEP$;E&vj}FK z6}oJv#I0#KP)q3dXU(EJ^Q2ebr0~2;d1(BhX`XYMrZngg|00*XssCIVVvABT8{bu2 z9yIZOKRmRpt91`BJdE#&-BlkRG|Y(z4J19R1406LbF?9MBkJOQH^A-n5k7C;LjB_1 zYvu1F5h2waBChi|E6BlxH|MOhYj7-hz7-sHeMCbI9Pcvh6lOB}(s#ssP9Vixf%GgM6un6eivjCMbzxG7J3GiwIDOarS0B82aJv+}VPI|@6Mf_HPoGBUHR+?nBZL-U6v51HUpsYZQz$ibY8x~KH zzUgz%$w%%<+ zXeE`mrl^E3C-@~qF9S#3kbeD5J+^MMsLwq+`a^EV7FBjs7 zi!@7f0Abgy)E6gAf8d{$h7B8xl?$Fj(;@1MTatu+(_C&I^5%Vj6UFVRmK9RD_WXrgRfT_c3fOy=lg92Y3q^3xW&|$#I<{0FK2q&lnXEbo!ZX3mT~_VJP6PYc&>Jg$F~KMu0z_cPh#`;SW~r2QnJJDp#mC9E#~I8Zg$?jw(5F zTRFf7`VR2aI|s{HcHSUEAq8Cy@fUPsB;pCC|8P8^8zZy9$=tghVZk2ik z_Ya?_hw&rw!T7hAp%R%&8Ekc&tR~~XinQDhC+c1y3_E_~odyitETn}(;RG>Sv_~co zZw}G=t9a<6cMqWL@1#FJ)I^|D#`ttpBB>U}+J$MDcAHjF74ZP^T$~(;)bLCxDCXJl z5_&b2jC%`mwKJSy*AY${`5Fpnm=Mvn?&M{E$8mZIQ6HK_4Zf(QhYh;OPCNP;j$cGb?qf_S&j-6BQDGFqZ}q3SEQRfeFC2FY5EeUi6<0c zlA8AR&KkfIbT)|7^m`uoSGfg~Avaah0D;Kc@^`UI0}AHZCWkoao4Ntb`~2T%l#D;B zA{2(xZ9@^NmplYbdEX{K6|PLZ;_&DU&20q3 zc4%JqH-h1*Cgz%lQ~DG#W&uLCv;4uONh6_At` zYC6>=bIk*C3T~fGLS2!rO0ncasxl6DRMSWf_IgEs*OYJf$1EeLN>X%)B!k7&U4X%i zD60#pN@c$6Ym{55TGGuF-?0&|$5RAfbpEPHhwwB9DocV<_s&))Q35@+;h$4&mv2H4 z#XOv+Q*@q~wiMF~Fy{fcX^-DY%o$?dv?6~VPUqVw^%`Hv0BbrAPTz9|w(q5p6i9ba z206v-30-JRWe{wXu24Ix!{zSGvSXvZp^YL=V$E8hSg4;cox}N`@Vc3%byb{}ve)gq zPUO+#vpK4w+2(3!ig?UF(HFYDh+ZLT>4k?H#vR?D7?%-srpf?{{y{S{9h?X>`?t8@ zDq{rU80}Ca8UHAFsKhMtP|y^SD~AHXBo!W>?QdO-*~v-;miH8pzE|tpEw zL;kN&|50-1PTo__;ZRpy%*Ry3hq@b4nDH%wj!)JgYCFUQgXDX>ZSp^S#37z}2rc<& zAU8Rd#=OPk4Zf)o8dK3ym>5SU$ zB50T|M>R1tWStHJuAL*Kb>K1)Ngfh{wh2ne9jPkMv-@UTzbZy(x)__~CixN75W(0C ztKT;jhzBRC_7J*>l*D9(-!6p5?w3SfS_|V}nM~szB?OaRPE48-UnS#zW_R;cHw)bT zC^4bDRD&&LYzFCHbb=dqA7e`qNkhlWk2v-9$9UvdAfm~2z^GXldf7`wp=APBubIm+ zl@u*y(xxnP2VLfcm4cay%f!$m`x&hic&0qXp)3<}N^5tfLDKN|lSMCMIyQz=xWsdm z!abIhTz-gBxIQR~)TkK{c@=FD-3=uDgGJ-oa}4eor22c|G@b??gc=})z3VuoqnKzp z?Mt8?B8A!Q-0)Ea8u|h;>Xg5JwtAj_Nk!BOYYV$m2p@$(r{U;-Pwo_9PsI;)255cm z)NyM|1@&bx;LVja0V>dM;5@*8}iC{4-inib#=rsPoeHP9+}7H|ml` z?k!wp-ba^V$Y6wc9z-nz(;$S>bs%rf5-_EtJP|KC^c`)}=d)jztJ?JqYvq#$%`gXj zq0yslBEUms5U&6{4?cc;MGS`hRbZd`X-RXVXS5V`-^!m8Nzeo?T!pzMsyuTlhX@6o ze3v|Y{`z!ex;$dz+qzpF6VQ?pd!o!+yq(e3QFebC>x1{S-{>*ilEhz_3m;U1csxOX!fL?7c`*WS0gteSLd? zdcbluTnVMo?w@$vS}PSmm#PK?zpaX*kC#by$7TAl)XD9uL7B;(xIz8$LIvy|M+FcQ z34WpcNjNk1kkqLN4~g4Jo1>Uwl*mXGjaFlVuzV_1ABCQSg~WBSlSL=-t%G*~S%H+n zDfyFRdVoCer3;`X9JaZ~s>4h1OPn9{&D`d}@K$-ca!5eN8tF~7;u-?8)ej_}yYtJ+%`V%uTDpe7$Ob*h zI+AJ8H3a`VeXKvWgNL_rrZt%jdIF11eFl9Sf`8B_Bu1_DH8`FFE_5Lj9-MrO5K<3^ zZPAS5;ttgeyr*%TnLKERIys4KFJ>Wb(KR;Hjh~03j**^&xadR_A}~Gl$iSUAB^U!n z=b6$1IG(Q6tL$i$6LPWuj7Pv2Fe4a|n$^pxsVw|M6V2hLOEY?zi$*MK2gm8-_eBOF zuH9zq3q_`) z5kbhbFduY}DuhqIC|H3x;~E_Gk>}%^gzyFJ8Z(@K#5eh&4nhwtTZQR1!K1H8+NEM* zkutF#ImB%eIXZe>?JeT=EAZ>|O}JYC6&up>@qm}-_r5g?y1S|N!>JWdDFsmC*hcMe zHCj(+(urcnM>UHd1w5$5l{NRwgY4?cql0?g!;-Gp+)OP%emBK26#+6`ylE3h-Gw*G z!o%QAM`TyfljJm&6XqbqJHW>j*|P#OIc4+>g}Qc1wDy% z7pBIjdokYzi1&R+DJk2+LuUi=e(kkMn>)%L&mJ?N+{2UYQ|H1>v;uS}H`bIYH`Y+k zbyi?jL9;;I6d(m1S?e2xlZiR-?YXugOGEbbxPVDR1SR%Sb3A^ZffRkzLHvG8Qz?Cv zgpPmqJy{~|P;>mHMGjjpz3H8JQ!a0a8P5p%Pcj=xKANU7t{Cfv-v1b5b1V1X-R36V z@*!UMo|&GihsZ}`U=@wH_DPf|H90BBXi6dfJg;7UiH3lURfgQISjg~%`XoKGv`yn{ zkH`3iGn_I6+)XDM)`vROFsl#9`X0?k+%cz7vr@{&dVRfO(uTQgeRTI)mD!qLddzSM zt!n**4&DF2WhIyLV#02yV0|URP%zqR?~Y)128xmhIon3pA?VkS1K1Vh{R(MBB-%$W3N}0d&!9D#qe~ z4YLR0=f#*%EPn0>0Eh6AqrY-A6pgT9i)6U7uP7KEj4hA8z&df|{8t zzCvO1Mc}y9xQHztbT8pAdGo35xjM|IHBr~Kf%0b{ncUqjX;1+j!k{qyuIw-_wDTDh z)+rL7#OpNCq5onSqy2gDA>!2WH9>q+Szbji1;~wP%22ICQwGK7bg;`5^jlpUXL0%t zZ=#D}7`aAxlY1eMI)!A9)d!mfs&OH3)Q^rL+gti?I{rCun`PsXIzeYn7?C!MKG!LT zNA-=?>%sY2D0Vg5X*ic^m}|3g-z~-N=jcKBn{!E##!b8i9I}gQvrG{?t}i6snRE$M zo5d)3iD++SU6g!HI_mcV=10QK0A7naq8=$Yjc5iKYh!pFNzFQN-9upvuXz}NyK^}$ zHUu0-an)YLmKa=#NNErc<$M$;OML#qm2ZbZBkH`d&1%5l;Mj4X@S6tHOYce+VbR%%mmCAKuf?sc| zcFcf}DO0|QR2f~ap%C;V?-fj$r=Z+?k`)XA(>M)lAhKW_m@-jx09kOKjxEXp`YmZ? zYxwjywy2%4_3FLfdavnGS@=ErVQlCy1meKLNxSU)jTmOimxcpz1i|loimqFg$)$|r zg6!!@f-&`U7S?AQaF-UmKC1}7Dr@hbKA>oQv2Z5Gh=Eg981OQ^4sjPQn&t><|Jm*< zY1YbYMRG|Y+@tcm@kviyt61yL!>pb9V{G94OcahLg6k; zN};$txnE>Et}g=~C1vMBM2kfmhs;P5Jh`w3on)pD2kcive zgVhfkCdy{#_ZMM|K<1|kQr=7KdK`svxp6!+;TjYmJwa$QDDC+J2Iwf=U{Yk1W7PI5 zWMZGY`tFR4%c2t0BrZWE!tF2o$T=ZRqO*9#QeI_#075(ITaXL=9}pf3!A)Z;v&d7l z=ZXVh19W;mFP!FI(Ezwg44~TVT!>Tk=zsHvq`3lx!nXRH&9;)ZeC}&;>8~cyshWZD zXGyqfaeAQxY#j+MG?7<%7zUL`FBDFMG-S!h+X=SJ8Ja4grxk;q>d3z{P0*mA#gNZ( zg37Y`L(Zs`kXev|w{uhebw9I7G#w4cbFd7T78VLv4*@Kdx@vLeL8ggi7IBy_q9oqy zjx2Oj5L(O%Fgb%2KX&2toh)4WDKH7wsOP8n-fkI8*F|R@9=8P3O+O}VGZoX$`FI{x zxV#DXz>o1QD|0AhqB)g{r^`MgdsLkrI0GXOCTKNL*kc#<=Kw9vD^;!T5pkGjEUHbN zxI5y65?vJqD3%dvIvk!eTHDugC2HN)FrJs&(n&W~Ma?hkACECPFQ$}1IDmPayk!Lf|8G8$g$0rU;H0@lMcfcD(8BxS8*L(^&%QouepkV=&raSPasNUh~>6f8}(M7czTh2F$hYp3oi!!ny*Q~)E z8-#2YbpAlDIpsFEgc=S;qd_(FFe95pd{aJ?Gzqmh4N{N2I2os*>s%jUiS3y!$8U#aVus&|HI)5@(rC1AKSM#5h}1MirTzhSl&ZW4;T5&xN!y1pF`J6u;a;Z@ z?zi&u)7oqaBbwyy%6%A32Fkh7!A8uw|G`qhV*@Sz5S;HoDDc~U#byLr{0?h6C#(D#p~WUM80RvQ!f2nBz&O8x z)$bjNwvfVz^5tkm+a@tm_DL^l=2LTGxt>>FDzB{oETV^saA#_P2yqW;>{beQ;Y%p@ zJtjA>`;5fQddjRZxPxQ4e8Tfna4B7lpbgX^vwld8v6CS;846P`@dk{)A`hU{W=Eg| z)sp@nA<9T+iDNvU)<5_@ZZqnry|}V-AwCY#gRk$=yeZ)tQtmx^pW0sag*nc>Ajy3b zGlnIcEVWbLNrxcef7cu_%I_w#6|mQm>1AUk>Ge+xH07|;gV>5aI>A=ps&v%n7X3)& z!8VTvKc5{g_-x|;#H}PmDprpjsiP_p5s-7A0y$9|<_$aQ|LDuNDJ`PN1Bq|CKV0v( z)>dYq9<}Ygq}==TLIT$uYcE(z&t=e(;tY3wY;hR)S>J;jM` zoDmCw?_3Pw$-PZ$fu*WMDB-)y;4k2;&w3B2ea`yH+fN|?nuipwQ?1p21aBl=5`~vu z=Y;PeU&^>m5ZI_S_OdJj5kT}^k{}Ronv7#Wx&#)*P%hGgrW$0I<14C_8xH>g(K4s3 zh6nE$X?^o$mrOwF5lLh0hby`=QfgyJ2`!huxK!crbWnon z&g`YqOcc|;1Lod@kqhoQxP=1c6ql8&)9*2M!Yvd6JE5F{n=lbAB1KP8Kw*dA{z;Em zgp}hMBqv^3zAHS6nc^gBRN~?Cbk_<6z|J5co$K{{8gNyZU$#Ntc1)u3EN+c#u7&)?9cAzrltzike5iK9rkzw#cy5NR%IrrIuv)(0c0sUb2nx1I~*!s^2RZcM(D%HHxX!)g~+xh@Rh0wqa8%)@k zAHZ;st$B6VMMXz<)gu*AAAk!kZC$e=Ss)M%VY)gyn80(F$+Ra<8iwy$CD&qE}ER<<-!QGxC*Q_#wIUzM(szb3#|JN{7-FORs_&l#Dy zJ0V(Da?U*Ih!-aX5e+5MO@gmguL^DdC1^0|;(eN(|D%3ym2sz0Yt1lxq)ItqIsRDY z+upYf-r3&Zy2uwjzdV2aw4~}T&a)JD29K{;HrTTK-tSHIobUUd{C@R^-}`&( z-Jbit?(4el=Q(iSH3D#MxBr+~C|P{5ZnTuV*KITP)K8j(*ND&>=8@`IaS>!7HU`tH z13Ud$Chkxhr_F030vDP%H@tXp6DUK({D6+%so4PQK3#_Tuw1t_?jgX7$enerokMS@ z+_cPc%*NJR_R-U;DBPIvyN+A%$;dO{AZhVbTjy*&ULm?%c$5A>gbqS=Z<5l$2D6-5 zQ<$&F1VMzU)5_}l)(8>AW=4tl>hd%ilmIB0LdBj1q*Gpy0Odg8>e6M|KpfzzJ&F9d z(vz>#R8|;ap4(J+M!SO_jb7?-nZBu;oNyJ-b(#oqv1t8%cfP87*__q#NPX{%`P9cP zFHrQjN}Wzv-0B$M1e~M~bv|>?(4^n~XJM*&1Gef8z3_{!a#6&+3fldps#c__$nfhW z7&HJ?Lx(lv0h0hnN3Ap4oZdHbUy-^<>)IDbHpap-a8Cic)}zoGzGEV=bRcJ=fJmo4pVn_Ko!KSDlhqZ#${CVukbf%ECm z(Y`+z$Q|Tx5<5b3a_es_DZusQ0{+`&0S#~#2)AV;g%QT@44k{23Wop}LlYx(S& zsJL<$KVaLL5SulKl35nun70EaM)=rC|H!`SdYg-;AS|o~ciXFaRxJ%V&4pC_?torU zXTimzxv3XyMZiC9Y%r^mK1`FMC)fR6jYUxSh zx<)s8gX;Yd=;wYD=5JyXn5B$f-|(XFxXCsaQ$IK}m3CQM?6rK}mT@$G)g}(MUT#e> zTq&WesieeX2Ye`)nxL;MG0W-olX9SzC@3irh2qSSjRIB*Y_c4a*^ zF((QzMpZVo+d}(*=)75!@W*voZvGuQtK_+Kj*;hDL$&_X^wov*oS#hNN`;Ic`tL^Q zN%IXXBDa@=X>p!}2PT8B2xgpz{zVL#ujX&g_kpUaJMWiVSR|Acgws9|H@ zCHM_;RKN0>)Bj!J-wU&{ZeOJuxY#Yk&%w*XgmdKpY6!fZ%m!+fI7Z`XnoFy59GPr& zS-oz~qk%^88_$WL@d^wLjv^i$Ee^_Ax4{UX7*0j>L5dc)7ElNcEOExwr}Xa4#yvm1Rknkr|U+XeI#2WNgGE;=`;IB ztOq##We!n!fx#ZlRg?Z9oyIkCHP@)!taE1is(w~>w9%cjJ@Z()@ zI6T&EhUYEcKmrWd~ggTAt8mU3G!^qHKceHEOYGe1MfYCdHa2i?UXO3@yqGtvPm zwUUd1A^7~lGt?U1*0M`toRk`VZEQq6R3_C~(Sd6<~(0|-w?5e8u; zzl{xT!}puJ>kd7cD!o=eHe-g0(f|`HD|cIcV~}u!S%`j_dmha4S~wU-gb?G7uZUWP z>hMPf+CfE~tP1YS*byyro%nEW^ig+%XOQQ$z)?5TD|)}tc}`Zj0t?<7%dNy~cUq|S zR$ln$^f_qqqOyzn1V;iCCVru(d2T|5QZRjPo? z9Uw2E4noV;Pg1~X<$9M6t-Xf3mTr?O0l?P3#jn;E_@V{n3{Hg;{2xa;YXO?f#kjas zomA}nh-r=SbJc|tJ7g1kLOA6`a=8kj%{;K>N+V+E0d)$ ztD@~|8^?cOM1JsLH5nWML2%j>*EJt@Nw4h}Ca-62L`Hs7#n6C`X%a<#5cgoaoh8pp zWsjE&eNDCMvcd2>GOxv!Hkb(-g~vVmTAAy$_~uzquK&`?Y)iy6)rB(nF8ikb6Rs10 zwXpKo*Qs*cvNUXIR&&nX7Jk@JX0ti)SF_I|HVjUeFi9FhwDSeFQhRwlo*WLL|{j}tL=C8e$4Y!typs0+0Q5pHb z(qWbdc5t$E#Sg6ZGgad(eW4r4u433gH_~aL>)Vu+IU5qvdDKQ{(wg^>Wxen9XGJ7i zy3c4@uP|=EHX4>x$b+?m2#<{j>>OWR&Z!7S@mYgwJ<1s2x)t&I#?LUCfS)c5P|=2~ z66c~k?`d7fl0pjW+tc^E_Ago7D_0iJHPR?jM;ov$EPfusZ^sH@{)qWBfY@D;f8eCc zYEji%)CFOzhP6&F4;Z|3zCg<{4%HkG$Wv69B6@0kG3&dgnKC@%v3`HpMxTI5-cQn- z#!U-=RK0VTOveY#xzVC79uN@K_57wDL(hk?{1H4$csXfc)5fS@D_zljL4TfP;2!u` zls|uIa{G{;yJt>i)i2;I+c#?_Dl=7d?k_6^_> zSFBJ1bZFx5U1#{cl#zI>4)|O1nZ&Q6d4eTQfDTkp* zb9kO=$I*;mJT?c=x~7Ry#XOcmXt*eLq&;8i;jT`R3&r1Y_z z_k+wLGOC8Kq;N<>Supa;U3%nYbLJP~%v)I|`A(kxS6EnRXy~}Ve-QGOf8edSj60e~ z{?-GgmdH3xAnuywvtZLd5}{{Y>KdSym0%d|#(A)(b88t-ZZa5DN9Fl4HY>9I(_luv z^qV}Y-t)Y)!myjud(>CiaeRJc{3^wRe@CQWp0?~V8}A=NULAk%MkAE8)D@@ARdrZE zAS|m9esekqOHKLC{o~p3ri{H!R^-rYY48v zONQDu@W`s@%UjX0w8eDuTjC{C0zL78MHVZM78|@>^;BA~?QsVT@SMx~RaRCfE3ge8 z_a~3Q?M>f?Xh|!xwm)j`Je&|5eRvRIZ`R!s6Q)~Er)&x&>apXcYo-KpUF0&Ks%a4) z^8HlbG9&qnA7!kbQtsPKiT+$smN5`tpb_{o#Mvd}Oqzn->veRzqxyB`9r3_#ia66{ z-L{~%>Bkj4+z7v1+dA6mq95j08=ZrD*4*s;Km4N_?i&z)Gv#Ko@4>Dp@;`R+!vEyb zT-b@BrmTJc6|?>$YDg#FGGM3e$2MU(dCjBcu^((aKZTXy6uCg1Wv70#OSw~78y0(0 z-GUJORCg=R(BYpXQL*2TG`@n)>@%QZ0J-klJO@u#;z+q>X z$JRvOfA7cpbCrt#g_T}+^V z=ksMLTcDPEXKczv@~tm_Oo^>6uRRuZTC2s==@(yFq?&xc+xBIfd236D{Wo7mOUj+# zHO=Cy@fTjakN*0_cfbDYw^WnwzH@)@pMRx){4wL^a`N&gEu6D=wwFsDC#d9awd9l~ z-}H%(Q;FfH#LG^f#ohg=k$>6T@aX>gBNGuB7pe-_$7O4EyJWWRHO!`MxTU!=Fd+SN zf97W&eD>Klw;m-_#k?E+Wk~ZQtHZ~77GLiFc}aE+pHgUHpc#O*=Nrs9kGwM4K^^1gzNH<_BMg+H4f zd|~4St)hD`_BH6Ul@@Gjl&)u|>H6SHrbAr$BaX#S`4b;MA`}yrZ?%4}^WZ1`4D-0(jiw*6F6ba!p}2b&-A*moJPa5=Tn%LqfJrqyozb>;P_ekK z>>S?vEihw8`!YwaDvc;W_wWo9^=$8YXGP1YgRSib_DxFs%AFHnwrS#O=n919!T!hz zY*0{l$gphK?D@u^*8Al*s%v+B{bC}SRdKd!xid}Sk>QN$5gxb!9^~z{t;UE;q2$R_ zjcfLeh)reIK`5YorbHAO8aHC)Gy-!0;k2I4q!mjve6+CSe0x>U@+Qa#SoWq3i`M{k zn|$n<2dl2r^p0XR7`(=ptvp5xgN-RVh&Qm`-Z!I1EMVs9TSphqjU`<-r9k0kgKN^5uZC{7pO&L#G>Q(xDKXT2H&u5SAzqZMcE=V6M@ldgCX z;A}McP8R&NZ!P_r>b|@dcJ}4|NWgyL+0nAePR^;7sq^Y;QbfE^-%l5ax)UBh)NmBw zgu4<6&xJ#ILho}&4>#L&H|!AlNdJ6EE#!pURSC21m6EzTeQmv|VCC^O1}Km^c+v)J zORrOJxT5&Bvb%@#@@k=?Y+N?nfWRaHuU=lO9Usgt{MW#dL)!>A(xrGiKn^7(Fe8kb zZXeS5yKn9r`9N^%RdnFOQyvO()5fQJwQWguH~F&uEaTAx0wjYZjo%Tv**|LI1eE~FLc;b>0(OKf0Z9#ST zM7PQcxepNsNytzN;==c6AS~dZKX`&_CCVxE&bA1$`Ls5p;Ei{H_XItr31|K=ZWTZS zTo^FA))dn09|y4zrwx@RR%U@h=kimN;Pi;_0hOo}17I9Dq5pU1eQhP%HC33}WQwhW z*sdLj?fT@Nd*FkmDx17uR5IBQfj|H}#L+r-=S~`U_Rm*>k|be35H1m(0Mtup|P38m<&+%wlY)S0Fn{zhuNfTXLO^ zr@~gr%N*SML;9?ltK=}%D+;lLbjKqz1=?>~CVX0Qrh1PBEA za;g3jk|w!Zpc^svG7uzQ3I$F(G2yD4^5bi?H<~DyrFxzrq!I!8skhrnX)3-Mc!@nY z=>#_pO>r=~+#p^Jz#xbdQQd>Sx`jf6k-6Em5>%J(y2}D9B_(Aj+lzm3coD0&8aX~* z@>oWv)7iz<)xN>E-IlsuYtkds&8`h_g>1qNym3ehS`E8!CF&@g?60c(X)w#*Q5$OD zR9Ot(8uN`Sw^y|Cr`WN-v1#Y0nFyTslfg6xefWzHu)Z^cMd#O=@HG2j=IHVSVZV{+(oLo?ZOC$r|SVdF2o$&|wgjNSQ2N@0Q#bR!6ta1Z}=hmO(_>7sI+ zKwKFp-~{zIXJmv0K~wby8ned8C#5R8**7W{3dGUqTDx&uf2h)`9=RebCjX+Gs*L8x z=N^Jwe(O@%8e?^98NS^jwQ{Tc-2;nYtU>{DUb_Zn1Srpz=NDdM5S$D}Y>J=qY>dzv z3*3F}mp+iYMh;$B8`;gzUeIf0!sOjk3$Nv>*ksBR5y|(!LN{z31kaYtz4%qZXQJRe z5;b5;cPn@dJOI%_=_6sDyVUg6JN*2)fh9(k1#|(NV>P$R3jIg8^myowpmE~ID}@=8 z4^`uP9&R)R8^E>CZU#i${Gz@}pFu7@N8*8dw%Of}F}Qj?n^%K`u*IoD^4Jy3gN7%; zx4chK}Hw4q|&RHnYq9cKJtfOzA~k>FP?sHD`o zm?IMhyUv02e-{7B+_hoNTz@;b?mlOxapf7y1j?F-dIFeh%PU2Q?y4F=&sqK^FoVH!eEIInC zlYQcA7?^q?-n_v%0N)tg*Vfk2COQ$j*c8?xI|}P^y%#rcU-O=lp-beiR?1oOSgrBB2V`Xi7LSulqfqI

EsXeDv9O%PKX;*2_preKS_-(*{SWh1H$DF|2m`^L=e-pnBY zVYj;)49*Q(l#0aTo>j;+9gVuVEw9CMez^9Gjal`w_!x15u~{&EZY!untvk|rL2*}s zoP>wIy5daTjOv*z8V|do6W#shRZ^Fv3899*n5MUyD9eFt6>UlzF#>^P2oV>z~F#!{>fLs6srdosp z#23iLY1$2Fg9?N{p*V6TERZ0Y0YQmdE)sJo!cf@fD$MbV9Zm**zbEa8joS<1`)N=@ z8z*}6U(+J_HbkO35|TYSH<2pFPXNzFd^gP>7vY81j_{23YaBB}Aikej8h1lW=b`{S z-Zpi7n-U6BIfr=<45A2#GE^k-VB<6SEaEACin0`htal>yTv07^aE11S{hCZ`X^R|e zX(Pd3>=^uIaHH!!QkpB}ZX4MVjmJGC9t|LQW)9Q`PUQf=hP0La`TjCU5`vicuLu`c zPw`4gsEKHAk^xH4Gc#joti*{(1VuQzvo$DSK?Ho+>RpJn@?W+Q4k-8K<8v%qBo0-T zkyXuD#q=-x@O-Yfdt;!mui+FQoIdwQ_V4I1s6bN`1X z2pH65H#Edq5pq8l(xG^|@a+;K&0^Vnn{aHE`oMz8v6HIIEF>H8eL@jMZWla~&4R&PZ!H8mI2h2n{yL;)1!MDmaZ*%Lu*Yv_ssDTk5Wr;YuQ6hJ8;S% z;Ae#}JdX8fn(S|GGcmJuMz6&M=p#wK>`|sDO=6)~q$W;t81PQzHZ& zpQBNV-Z#pzqQ*u!KnT79v`LE=%P5h$}`nMdz&|%tHlym z@ftQDJ%|Q#;+I!Kc=g}kZLJldK5(J3LGjS%n~3mkmC%*9*LN`h_XR zx}}LPDiE3w%33J%xKcs6V)nI|%bivHE-foAUDvWzy`!zE_FbPbX|6j)rK&M+2r}--kb{VhT1w+ zckd4W?|bzG7eos!+(~rV)Gl*fzuY(qT{LU2Vbze)tllvV_PYN*5aI>Ol-qwQ%o!E=bOqkg8fQx} z#gnTF;ux*!y`s{xV*K#Fx?(G!IA>|>nSJKOW>WB4~(f58+|zrBac z$Cb3QCD>{=hku6C`c7ZEz9HnbpBI>@*sW8rJgXLR?9(x|^n&U=yS+McSWNJF6o9D= z@NJ6%3mMVWztB=-)Z()X5#V_G58i6j1<2096Pq*s&Zv3!`vr&5=c|GjamWj?3&^@w z-wL`WiYfl#DO#7C&)?H@ral#Y8yc3pkol<_m1IiNfNNC{Fk0;{-YxcyLlta+zl-OB z$!52Sl_OgU^p0KDCvXqL;bg6)ud}v1vMe6Qe!ci2HR~hfc#G}R5aYd8-`YW!YqN7eXZ~L#2)muM`j?y!m}O_GYam#S+o_gxT&iRq)AHxP7~L&p6TV7xqRCf7N)a1dML>*6Yq z41*(*0nIbih)X7#i$N$1Y=PM$P|n6gL}{7!;zX!+7ng~!g|pQqbsvXm@qKdq(39&? z;@akZTTqnhNxX~Gz8|1XPXO7aa;Rv}PJ$|du5-imSeP9%@G`bcx$|u8OO~bX45ijb zV|aYKPAs(S^${d!y-w=Zwi4f=I7rBx?IL{c9BfZ9oH=qC`Z5+w9!D3K3a%FyH=?2z zr9KGqUirf8mbERYQR{u2Y#l@N-{y^~*%Uwa%k8&I8I+#rleE=7@X*i}2IxM(}J8mOjMJ)+5oC&ZCPZ8KwC*|6VM(6a^q z?(k>0k@C2DAFDS}KuqUBPwg4m1{@eN{As8R5V6;8XXwa+bn>IWRx3F$niw_Nnl%M+ z($gn%g2o};oVG=oJ4!k?A-4ytY()$$PiOgg)$z(?F}p(Y^5vx1m5Rv`@oy;3B&QeS zL^1EGP6F`8&IG0M2;bRJ73?Lm_ksqlglrO*uAL8D<`5*<8Xk?W*gzplQw`6Ks>~|7 z*0e~T&n0LheK)q|ku!~^MOUpiOPa)%j?X=Cm1@TK(^$r9@-0P#G1tvjQQH~P{5K_E zplGPHvT6(zJ?}X+3HiT#fj>ZkkVT$<#2DjwwsJDD9fao%-$Rm_k=a*~2he2lHT5+N z<09n%7s*B=xD#W4-Vm=|$>Q%mT(ex{EUb%G6f1uRQ!=WM;XTiUFL|B0(#xo4(o#xj zLI+~{N+Kkwvi+c`>un2DqlUL_-aN<;ep@&cy5JcNr&b65UAb`-E8Goywp0~_d)JD& zDh1GL6hAE65nb(Ir)Ljv8`O}yQ!%1zIVfE^pF&=zS*WwSy~rb&CPbl6!0BX`h)qqv zcyDJozJVhKIC_p;3~tRy50M|gm}!!2GO~$ryh<5gOm^$QgDFwHss*>T9LOy0Q{Tnr z4uxixew>+S_wx!zXWDZN0WjwNvq@uCq3dkAVo9?$4mwr?ycljm4!V9Py@gD5gk>y% z`ZFL#=NhdjsX~=t@6I7<>6q^a;+|0)@o(0BXK0Kzj3ZZXGM(dj3VJiJ;q23>AMU|G zw4%?iCCp2*p=ViceYE`rd6BPwReh3M3rambv2sIzcIHv@E ze1o;VFwvK47wYI@+)FG475{82DN?vX8tKk`%(Hu!%-aD=vFR@~N}&KG_+58)DenG9 zf$ya!Ks3NxRXF@|L8%IhPCH%ns=iF7JQI{Lfug2TZn>v_2apS(bZe&$7R*nUcoUa7c;+kKma6ejXy4vMol#(#5fNkHWXR+jf zrpp2kL6U;@2iFOA)QRyw2?l(%fiV%4#;#iQS^#?bm(BAeI;&|`*8YRc zY%68%ta^kDQM!~Uz%hmRdhgGJAJmS;)MeLqDwC%$&Qv+yE6t7~H_t3~kp)VdlCpN^ zh9>WzbrkZH2zQBQO5VRby~MpBe`-;V9=krv5}cmNQgq~v?*dFoR%senf;}n%3$U!G zE9h-h?h#;Mt{Cm4SN9vMBmC@HbyjkD=;;3bSd(V$Oa^cI71=sJGh-yRhY}{INY%pEIj^>R;Iy{!{DD;pVkv&xEHI<;uEWMNV)=usc${qO*dn{90@$8&A*?^Hk) zDUZCky->fsJn!v*vAj+NejXN?DOkeeh|L0>HG5KFbBq~KKc5-|(^fn?$#JOkAmm=Q znjc@UgW)5@%Y}qSiBz`ewE^FX6;6y<1g76U2YCXnrZOBTE-wc=f8lE`3sXyKHT4S@ ziq0Xv#?OOd2!jyz9OCt-;e%h@I&gWdq?gOt&ciBHEBJ6otM6}aL3~Z@54aypmLR?c zK*U4m+rx9x3(bWDvRIWj+HxlpcKGI1C@A$}&5R8>$}<);+%B)lh|o@$s zsFucoJp?n1#o{O_Ta;kI2!4GpY2ok2LEG92MPo?H@Ind4JEtiTUP^`e=j4maGZGUx z8}+phC&|K2_zVG4$ljk??eJg~?}QWZB~p=UJ2;ZJ-@ryL&8falJ(EtdE$r|oJ2vW& z><+@&A*UPH1mMnBNx;ULO6j6gJ1Gvty-(u2av1Jwo=fH{PL}< z4@n8aTC@)CwpR5(q|6upw)M6AP;g;y!TGTg;#|@>UwnJ_cT5WO`~XDfPhJ|%+4ssk zwpTSqat0)7#$uV;*IZuoB_dm5NUme3vQi{)0^HF!SQL9WC#swH!z996x0Yt{XF=9% z-wg-jCF`6D5BYl0`po3cuDb4h(+PvcZm5p&r+yYV4XlkT#k%Nyht zUq>Ue(J`mnCbHb#SMvUO6;d9aCsizgWo|*vu+s;dZzzY`k5Y~^Dnb)|!YDptGcxEc zgM~W~EDTV>!ln%+K`g6ajA)eJgkWK64+Q!uzMFXO^_aMKB{xde%Mw6(0mxEb z?D^fIZ&I95pv_F7^rz@Vkr?KtYS^W5IAl3JE zd7!VHs?ZUCws<#SFLsEv@*+_qVEpVddpDZDa@(0DOSw2JpLdJ7PKgQOt{QGH2^?Fo z-N&wb3`TJlVeBl5X&SFO=D))22P+RWkf+pBYf0X2Sa_QhEVwD&b^YNEZW6UE-$dUFHl+5I3Gt8@ljqqDC%OKf7bB}-%Ls@q3xrFBWG+xVpBMyascPz!W-N~BWsYTuFJu*-`DiXpE{1%*Q(Jo}dP!z$ zUU<9d#-zF#W8JvQN59BH+6vP=o0j`x5u^S5-h(Nh{}AdOu0#L}kQnrxc7`4OHoY*l zv*Dh8L2ARG)%HN`#s`t75V-UCbiqAr4w&rzm1CLeag&%`9ps&4ic+QiCik2(z?i}x zhawI)U#e(t%fGJ544R{$%N%6ngieqb%F}U>Aic#BQqJpZYj1a(>Ay6XLfT4vT(S-$ zp2YVCSKa9+V4FTucGuCELtY!%klZ&W+0^GgY zJqjPp3{cXqI~Ij|kR$prUdev`V&t9xgaE0wX}_rxnyl5?rnTCH+-)wS;d>1zbvevN zQr96Dw;dPCT2SgjjSM?HPeA$H_IA4yao3up?wUQa--O!RzqpKPP*{ZwmW28&dPt2+YHZ8aV+A!n9 z@;No%p#P$g57t(S_lP*hmoR;fd1lg6YT%2}!26ygo!%kmRWerYt0DV-WI)GbnxuxevIYmM(Y?F7h zu36INT=bcDQ_U+V@iR{8=bOB}{WD`l^Bqn!zqhnuu zbqv;dO2nhE*{VFb1!_$_mF=Y7O|S;UN#!CSa#}X@^X$H>7T!^M01hRnM3$k4-oV*w zOV`p8N6#u9|H_W4vxp;AHZO^TeNI6lA`Fy`0KQu0=I@xp7^>;f&-=$G+Yh#Z!*GK$ znb)Cg?b_Vo&HH}k=8nA0es)#xnu1ox$i)o(Q|LiJXll<@im(0LuWy2fh$BhYm8YlY z$ny2<_O-nTXKs7CzE*zv;D3f~{hhp@yQr_HwF?cu-c%3Xe4?V;MEX5xG^(iE($q|K z1^$3i1R7^H&+4*IcXdWVh#i{3FJJk`CuEK4Y;xG1RB}oq+g29QYww7qXUQ^*C8Y>d zOUomx^0y?uvLB&PIG=itF#PYY_(O=phXmTo_RhiYlmabel5T3i#NVOk1VI9A`n~r8 z?=R`Mq6$#St`xY_9OM*#X>IL2IJ4F|JJLA#XT_=y;#ADObfJrSj#@ffv-fO98pAn3 zGdS6H3KdgIW755crEq$Q7ggcnI{$uuCqrSp8sMpLSEX2FCh9goOx(XSomFFF!07Xa zpCJYrQjXtAf2$ljSP(Av+uzC$EzKW)g`YpyZ~39{!rtD@KT2ty{KORUPNF`cL?GeO zukZ#fdGzRK+q1!G_>2NBH`Y~(c;& z{xxd|?M7o_#T%FBYleXao4;$f()mkJoUIW@J$za0KXA!p?}fjPsBH|#R~3M@a63Zb ztCX|DuD<5#1f8t4XX@<_4i9jgTsS4D5Kh%I^}y%aSA;ES5-O{=^J2#HFLf2hqx3Ow zO+3=rQvYIGrz`^ST1T9;22g73rz>-S9WXfwRACs4m4rMf2KW90vaMdwmx{{QTOe+( zGWOPXH^WDviJZblpk2dsaxSk4Vg*Z|c;i`UD6neYQQ72U>Ax}-^GwmuXM$?{T*PQl zm<7|z{J+hQO3|8g1R!}Ve6Vv%V3(K-z2CPn_v0c7q}C*r3_$O#fnZ?_7{Ik#Z_!*(2Id5ed8}IE^leCh`qd7wtBe z3E;cYjZx+c$S@t}tjqYzgnQHF=rA3}(PCSooI5fS)iHzQ&dmCc9~3X`4D=TtY&`*A z9=(XGw&Yq0{#9YzcqSh$0mHZi0MO6@L+RZ1fL*T;-$cfrOR5@Iv>ev9MAAE2v}^I< znRZ~oD_gCiXJCD^qEWDy%YL@Wb++5jkT!OoWjru-ZhU6+$5axnB2`9Htr`Gtrn_{l zZh@(!jQbwxS)Y~GSfnqeVT&TSGiLPMH_1g0qnvZZClxTS!?9BM!)0hmmu;4*15ejE zsb0OfbVD{8$04Zg_-PE0BJ>Y7YX6z)eVsh#PV`nY&`X&0p4e%zQlOehHlYoDqn+(B z?r6mRBN+~-VlBPL6*%Ps4pX0cSy&Du1o`IX|e zoE$t|n>>sxL)B4h*ow+73Zer+wI41{j zeGmxHoINW*q!C+Yi?$M)V@3U|vxL23RE2^qJ_{@!`C#(to@LulZEg@IG4W59`mmXePf z6O~f43Bxu1^nDZirWw+K0>MThW@m*{1N}KILvVVgi9fg?J&aU8pZc_f6w^;geVd`MD+rjB7jzrV?p3g z#mZ+J?s{2eg)-idrshtknVwAxN)56ErJ~DtO3}Hqd9B*jU0QU~6xt(U)NcyqP15Nv zh;IZCmKrxu6567;`lzbtG}9}NLh#RJMVl2~!+jswIiL2Mf@+@hve+!3@wjXBw|7IezcTR^EB5DXo6z(Tx{^Nbx| zz47aIpXGAFSHvqdo_?1pLJ3?;jC$ZlKveXE`Q8!T5WNh~D&u^)wCGRk;-$HQ8*dEE35dfJvAR!;LElwW^c>l{O55YbD zovZwSTbFOuFkD3eBpgMYr(U0&UlomUt#o*)y=(T5xTlM?1<^mlAK4mzu+wrKm%OIY z=?=T~H%`On!Rji5k67k^H4ma$=Jl1~2ieU2DWq>MMOIdkbw2L2-Y3kS=c<7|FmOi24|=qN~8#hSPF>^^MnK7&+wWdV2vrNt&FEn1)! ztCa=dKu~v422)x8L9w4gujnj)mZV8fx-86WX@J~U>4p2H%3eeFuc2PU_B=ICNqJN;|GP zc>W>vfobOMh}^JEQYgi&h2IV<7--}2>?;ZM0P}KZ=V8eyv`x6DxMIaI8<2RhFf_W9iG!<>;wp*J@{bCwwE)=d7$) zKKsZpl_3n|j3F|HLA43LE8FttwDQS!UgE5$O7IQU>AfO**+{mlO-bJew!E>c90l*# z7O`8TYm}PBUtb`jZZ-^isqneZ@po zm-xR8$4=3oa5MLADFmbKKd}F7_-je)h_)Q9h*hX zZ_*;V8lYr%6?$8TNF#hbfjwC`>JZ>NH1dJ~^h(F+G?@f&N2&n&<~YHe*(+d-MABN6 z;51>X3y9eOt^*hA!snv3Zf~{z8{>^Y7>^n>pX$)^f|D3$pwj^RaCJi2a|#t+PrQ^M z59&E>Qho$LnI}Tq zv~?ta{Q$`$<>zE^Wv0ZLe#Pa zRIM|yzf4%L<_d~j_I^JsX2;h0WL16GmE*Sx_2b0Z)-{fIY`!&XDv3@HCA}3{`NE$I$Err#K|z!mZ}TD1vi`PNcV(n5 zWUdf{J$BaDP#=xM<2j?$8nt`Le}cp*OnT{!ih?uuk7G%hpqwNCQ;!k7p*pre(hf2R z9!kTT!&Bl%Q=LI9Qfe_Hn?VqXsyaq98;dhs8hMwyve+P#IgWYSm^lP`B6_9A5v$UT zlVJytl_^xMyqG9)2@eeeJF?}^uQMB?_&^UW`!RsztRv*5F(FlAha=EX5~8+hb@GtL zQw({(O7pmCwRT>W+AOC8-ZYNV1B1ak8X^O@$7$F3TS7%iD4xB2+<*AFM%U-e_`@z= zzct9pR@4kxFWhybsw`>0xCLZUO1Hp248M)lxwmyoX^p*7T4O)|E}a3L>jcQTynK_{ zf3kzVu=zhbpPP4DQPtyNaZ!{Oa?SDo= zW%D=xTQ(D+vbl4=vlH@;RDaX(t`%WyTNw9N;rXlCPj8!|)=hnl!{+cnQCW;VHzyw7 zR=ek0c7NTVZlp^i`urrH2&YKL8eX|AUK{NQ*Mwp;Mlpn9uX_97Zd|MIw>0Y7vWIT3 zu*D>C?)oeW4K3*Sn)=xw^Vawa$Vg=&`d;0IRk%lAfdOH8h)1r z5fczd?rJNkyTd4iilDuq(r1C+EmgJTg>a(#BcPCKuWFGP*wIK;aXv7!v?Kb<@Sb%c zF;VAQGQug$-)!u$e1ixs?XfYyp`~uoisOWQ(Qnb*bzxgvhNt zV34HMJ(xoW9-9bHTAN6Ru>_5I#WOXNSm5T3=Q?ZSBd1U)4RK>3-=y@t?POb84Gb*H z+Typ*xj~+wSCF{Kxv+Tv_2k-M6;NiJ#zT!_|7&!P*MJn3g)rrZiyKl4c$WT;3CKHT zR2E(lIdvby7H8%(3#ZS5SPkqrV`9BpstpI?^k{>-@R+HAI$=cNpnKe9cu)MuScVXP z({MA#{x$xne75;Xpy?Dn=aCM|&K!ZEO{gPw0~~Xfr!Q+EU&a6OmR439fuhQWx4K^F z0P^2H;E4P7zjVDryl_(&R-vM>-Kn5)Rw>|k#%KTzp)YqVR>r(z!6}mbER0MxK1QAnLP<*^pe;Xfj(+fZ8 z`hNX9?0(>rrK&GV3e;1Y0giH5;eFX`A4GIEi@DZ5wPsn%VOt(wy0KFoE_m+ampWH= zsfg0&x6eJn26w7oT3pHLaJ#iS;E%&&g~eri4Q^!P_ze9wun4A{R5_BI1iML!>Nesn zNZpYl$2f1?#?g@>={bAF%}lV3rw__l54l0w`#SAu<_mB1TWS*#<%aYJZ|KJFhuPL4 z&2CaRqTF>RN7&})3VcHE$T*lhNd@?U=drd|Ez#^9LJfYAvu1HSO;PA z7|}G#ov~rA)vS9Tc#R?y!)k0c0{-E1fQ(kzN0Lk676!qmzZ=dd%P1-AJq!t8<)SaPE-H43JuKKM; zE!3SMiu^O9(iY1i*PB;(f(p;>M&)c!4mrC4TO;m9qUN8h8*_$TJA%(5E$ zdcvIWq@ure@6)oWqI^|s)YSz-);?t^E7VzkBk{a;5u!n0UoItZ(I^fl^?Fh+-4=)y zQn3OoqV@+e8O@!WgMW60oLM!I$>~g#%d);w!4uxT@$7zp=f|m#f_L>cv0c!OAU$!9 zX>M87zncs^+g0j`x`Be7{!LuA263p4|Kj|$>gGeWHB=6JExVL!=4CH(3YtpSD4m5B zt%|R>I;bmg)a64KksY)(mV^inNVByz%L4(f^ynT{0~l(&g8;n+=@kT|z`1Wt@$lZ+ z&5}$>i}!$tUG#}VMk3;Bbv?oNKA)<<-T8GncF_3D^2!(fdF{nW`{@Yf;3=aJwsT@T z(&G^Hms}mG!*CZEFZ&{!F_GzS`tbOJ4Lv- z9BJ`@SkCf|qsZ|ri#;d>7#@OsN(@_%R}RGK)wL&0aCfA5WbMX6!UnBBO`rW&-_z5B z(@S|boEP|V&BHWD$0I$G{(QPbK4ay+B=8;4VwAN-A#gKGh`bIjgxd?B4MmOsq@AE> znq7tGrgF{C$!U0SX2pA>_Di#pB1V|bID*Ic)lka_X z+4{#A>%x2Q^{nUl-S^t}L~zX*oA-ilXUT78{xaWy>eI(v500Cz^R#M zuXO%#Yw=8Y>H8L5J(VdaWeS6?cX!27s(4<2mig(JABa{H)<{-WwC4ed=?AO&nzwIM z2lp-UEMgYgXpZL;h#-k_LGD!nn4w9Axp-IC?D;TRYbp%CPYSd4^QmgbFSG2B=iEXcL(vwB3#$^C{~1~Hao&5l-FJCr`XIkjzsW8%AvsTH z1#p%Hv%)v&);5QlRe_17Fx{uaz>$TXaIuI=GDvK+hw@JLJzZa%?IAgv1%b)!voz_u z{awq`9I(`R8M z%LY)_$g;RLh!eW{ybsd?odZGOOOu_m9E$y($*eX9Lztf?!k@j)iIy> zVBAZ`pzZWagBv!SzMcfT#Oyd5zt=h?tgF>IUo5Ryoeka7IG>zx-=5f-vkvTWdX#G& zt$}fOsBaCQf#)HyjafD(i(8o~lqq4_^;=~``QA8~a_L6v{wn67c?dwwx&UZ$T?7w3 zn&~RIts<6A@yd6#RYlaPb$~&bfeQ47WcMn4MYWKFZR=%X#sN%pK0`DroHNwzs)lIq zO3MA$GP#Ti4L2uDdQ!jbfvly+?N5(vYy|dm*4R!~Qfs+1e27t~XWzeOFYVFT7uof4 zbdr9p$z`kA9z>XQ;(I2qifgH)4Na-Qd@?*Vp~3e$+I} z=TswcayPdJH&W%#G|O{4Hp+LEHcvtxHmF^yn1VO*A>P)Cl~Al*H<(f-)s^WZcSG`6 z`*K?by_FINPY1t>I$nl;zgK3(DmmHg{asGQY>&TgjhViCWhYCw?ns$edMbAnpI6Vh zM&eU=3m%iu7{JMqR>H~nJysEJqSJQAebK0=Mp-x1y7VK@XIBL3=3rEYJDoY*&YyI9 zp}cer@Xr5(y8z*AsTWG;9WJ*ER%R@ii%>+Ny%w0s03zeGI+u^lCe)YDX z&aG@zfgcbo2eKnWL*#dL!hUFZ5BJd%aguaR@}o`e!_{2a7e{1nTVyVAR!2$R3RmJ5 zHRF_I>9=fWH_@fMM|fyg7`EC#|*|tQzJ7U+}_w&PfT1$aoLjXdW&AW zy^I&mZ&(f6*J)^?3BTY~~$3Zr5-7awlRXdG*fVbaGSDJhL!oFV`!< zCbjGdOCY4Btc@p)vjfEs6V7xh44*Ms3OM5ru6vc92VS<>Nv|&vWuhVpETGAud0$)P zNTO>LtnMGVSnQTlx(0)(;SjQra?yqB+3EO*Q@-zd(;%^^esAwGTH5{Wi7q!sk#X}% zQNTTgFxVqghJ=&-Zmpz7Hz5=#Esli?9eURZkq=vF7w-oq?{kBE5B($JY}#U@75miX z`*(71$ng7Tn?azMx~SF3p{nv*Gh@F|WspoLxu1$rV1J=8TV>mEW^Zg1^1v3OU@E6> zs)6@|{D%MqNJ>);twa|5(!Ax!~=xhUv*Khb4 zo#Xa9J?jk6s36(w{{qW51LZeRRWNZWf$@4u&V zT?(?vj)t|k9P&c#d1j4awf3*P*K63Cr>_2rT?K=I^cMD1!^PY69z|zsF~qmCnDa1V zAmx&<&`+}1CT8Bo`vjJ5$xx`?4QUEq)h&^u@`m@AAfz_w@=*;76wk`^#7QJZm6H95 zDh|=`(=dJV04#tPuE(c9T{6x~*Qts9H7Kt8z@Pv1zVQ>V+xyzy`I7tpI8ZXfB#t2H z{aL#4rpg=Q=nH6)ehfSa+a1z&aYs>PZsc{S;)~3(O-m4}xH*#i(+4)m@t2?BI|za}BqiVwNOH;;yIQ6JUz)hV$Bj#P1|Fa}b}omMfLcMD(_p zM$A&+)eH5#z~VFcTUTO5dwKv@9;qH;MjWpi71IK|oHo42nqG}5Lhv&_gpf7{Q*aC~ z%Jy|n*0W3Zunw5Ehw4I?UfPMHYkWW|#UXIk^H>pUJ?;}dj8FC9wz72bL*PHZA_}lQ zVHqG%)4d&MW*+&4QSuW|Yh1JMZI43xz6XGjHoPcMj;ebGZtE6RNCiNd+xe>*EomzK zO()RbBtIW|3)jgBTa9BKNB9tT7&9Z^3Vhb64CM})&v0gznR2@%iXjfK+$%jfi91oG zazzVrZ_J9Wlth9%44f}N&`bv-?7eWk^j}L=puy+q8mjB>rTr-AT$H0>5mTgirQfG8 z2HQnp5m47eg-}#1r%o$S*YFcUlUpm8&M*w9z#TM9b(AH_sIr)tz*B)h4;?D{%L?9$ zB+t)z3|A4|oE2$A?Nff~Y7&imzIePKFMuWR+Ib;)U0EgKj*c86eeoC(b;hMt46|*r z&*?W#lqoLw60nZN{016d6XQ#>@lWy01f6Ud72Js6r40K+!`_7m+PdP5blnV7B4Mg{ z+)>?3@?PSZX~k1!z`Q~nx-{mk3 zPUu1)iwm9#{?LF0V+h*OJS=HMc!mbIt%}3<9d{z1L_~K!{nSYoO)beUKtLr3D08rk z!7U{5%uquLf}X zxMtAx@WC;7Y|LLZeE6kl%RSHUh7ZL+Xf$?U*fJpbjfJYyjQz)j@l!B-5ZItDuhVDs zzx<&VX9YqeDK-=*ig~+qR~ai#+}P3Qy_DAO@F#EKT2`y)Qw10F2b>k0e-3^!9)Oo=ppuK6R@xS0K4b0C`6juk|m3J~V^{Hh#O2Y2cfQ zHggg~=FcDB$K8t}XVE<>mhJQp+)1zYpKkW}!RLF3o9m4?pJXc2|5q?L{CH${-#p01 zySw>Ih*$6BgYvwK>>P7Gy=BL_n;#?55sf(M1sVm)ZxZ=rrqn+#X+7;$YA?B6h<)RZ z)^n%`et0HI*+C1>gL1jTETb_vglfIJa>Jz4wGN8B+%Ga`xpMqn`uRRDQ1~X;(>2Y- zjNe9H=}E8%*7cWSXUdWa^6^fFfCU&rdw9fka}~CHq?_tG0PNr8=WC#w-FWmT6_&$R z_4)n;)?piPxAf*%@7#`2rOG}KUP&3v*P8>NGuRCSPkom=*PDYslR5}vAg+h+ovAocyS2yh1lUpAKWK}Uv zk+4xmg_{<+L^^Fjp^^;auuAJ$>98zD!Q`VWgMxM$W`qhmlxq_U7rR^I9UX^2tR+VD zAjq$EmbuGc80}-_aKv#@YT6CUNQ*o2wntK@(iLbt-L-1`XsyLf1x{*cTkfv{d^Ca zqY_Ipfp7~sZQg!xF)1&8Wy7zxogU5F!883u*S}hE?P0xcC5$KSVse^gV|{;`<5g6kiaQ+a zI&0l6vCo8+6}|MLBKTbwOvdaiu6jQ-Ob!m#JR;2hA#%l1DIKIVu2pJ>>%ldLt}Dhr zwCZyp+|-H+E?(x<_xUQ8R+@+Sl|MfGDJ!Z-Noz2WO6#BRRCZ*ScermHS{AE6vr5X} z49i`*#D9FHl!QO2EckVdU47UlX>;n>*ekQkK-|&j6`I=P_q~ziINfJWkD@GltTV9v zv(G7$As(}gF1V@#4Lw!*sKHrzC$VtnX4R22+GGd1%h-)A~mw{V7Ds`2o zi~UQXOG)g(UapJDsTvkj<8h#uFXTJ({=HDHv+A`~N3f;`(7EZ;ODtYdhtOQTpgdBp zj6OXi4ut)elL$RXnIZT$KRNnJa2@aafOYY{=xl6sJRWJYin|UV1wkX4O*s$)?Z)t) zm^EF`G<+U7-HoiE8xD16G`P*|MVEG!WDCU$&O>Xlo@=q*%)##2KuMroK9=tB-h9Xr zuda09F5FXiM({D*ksp}Hsi?GORXVZ$8l)-x4KK8_@%aw; z^gCe80)~E;zhuY81KX_(S^MpC*}fO0b25r;(qM`V*gO%GP|16D3J~`Vv#41TXE_%` z2adYr?`7gj30i$*6^)T`wvEfiZMv&5JCb^&vEI9(|Bzyni& z$D7j!Fc;WZ^U9v5q{lw6*?;QNaO0n#Q2#nTQ8h7CJ(Ar)&atT>%=ZxV)bLjTXH#s0 z$4TFZj!xL_KMUhs@<6FxTg0(CEMuVDI~p02Ec${k!R%Phw3dP;qpV_wDXlpUihUOsIE9? zNAmDPOOHxgnzqR{vbeO&2fbFEr`<^k^{$9Ig5*~1USS?sr(;a@4}y_1D;E@lfC$`N zV+nr3%Kc&lp8Na-r^@`f^2#~2XZ^AJr$`$+ROfwu-W)nE#XE(u!tysKionVNp9Lzg ztrPM~mPTQ^nL_eD11}qOKt5e5)LO0@TX_-S6Ot}rDOl``lI+I^9`~Z<4}5g_Xd8=p z*S0KIc}KfQaYolJTRzzK+mxJ0HdEL4)YpcaZ>!gHN0P=US_Y*p9c--O0SEZ4!|#TC zU7tYCy(!(rRibQ6Wm!g}mM|sruQ^cDW@z=yqO3j9txg8?D#MVQ5}C)o6$=wzS-SNa zC|rl9^8E?fIcggRr|Rw$FxBf8H}e{glB zDaRoO9qc$RKeWH0j5@zPQ=C^mM=5ri+S079igA)-u(5&KwU)VvPu+Dp`zjyVqlzDi z(ruz>r`}O67sSKnY8=^*lEITz2o$zM)ryCKfq}`^Zfb zK2mHf%4gIUmlqd9(J`lsGoK#|J;n`bcxlYy;xQAxiC~+ZeE+||=WeMn$jP@^AwP7y z2BW}kyWH>3zSm6ZF?IgfWwk%RZwvFwjp_Wu9$>zDRgk5!yUiP5I* z|Ft)(tR_*rsu{}uZz>~H_U7yGt4+nKs;nvc3Rq3P-U4#+?|pJG=H!y|IFM%tykUpN zYpc`o+7Kp^XImBLtEJf@h9|TB;vQ*5??(}ShTi<<}x^b4jso>Us zzAx?&eE)4OMVcI$52uLH7dB#@SY?IwO!>)M$MJN{D}tLvmP_DGSxzVM3sCXQ@({v-;|8FO!q(5Zkbn(7}Hiyh@pEQ9vx`%}ov9gmLkrb=~Jhq1nr zvd$ISLDc^!)R&nzy-=M<{`A7>^e;J8tPyR_6Dv1m=jmgQ$F*{;xSKqzf4tqrIKJ32 zqT|Qi_bxO~9T8Jc_dg%Y**o?MvN*Kkj}=dWaa6ycE&M*y`;B?(&oYL0L7FN)tVtfqp3xH5X{)U&< z*?3K?9VYCmAO?rv0MMj@pg=b?!Z`3{$a4}(u5k5cUSddx6K=GeVMV;R9&%w&B62nM zyi!B%wMkrYfxd2`g+^*Wdw*)ZlB9sCTyR6Fa&GWL#RD)I1M3SbCl}mN5tBMKq#YoR z9stGYX!@^xuW3aF{yTqd4j>gx>{Ucq;5&iM_jiArLgRW2ZGRiFQ}JnA_tQi2h;+-_ zwR36TSy)Y5Az#o>w{rGhl@6HS7`4&Dp$vTxjG1hg;|`SLAv2?=6dzqEPA_Ub!;Uy0 z%R6Yjn8q};UPXvvVbl@|X}<6}B&IK{Mdz@+bpvfKGV|K(qym;!C~bzwi9%E3+a=m4 zj8Y+O6LKQ^*K?wD()>AgYHv-eq43imSP}}IVwxPQXwPO%QAxm?JUa3e$mZ5ai6p(0ZX!g6#?&8m@w(bTC8+jda*M`2gx7CkON zU7}*hI8UyfKWGT)ftOc=j_=`jqx@9F&^H6zj6xe}6;2+56nhR}L@0sY(8lV@csLvz zPp@$mxq9fYy)?AN0bl}$8~5<`@X+@_;?(pxFT{heCcK^PG&@(U`(yW1`xWAAnSn%Xfk^SScbqAGW2;ybaHE6aht=%<30W-9benejILIB>jEE)%XeOk5KX_g<_r0{N z$*M{j2pSIVhz=QE=-tm%tTPQMQSun!)SX$FNzA$YH*?MDlf`%ZMCwKmdLS( zecby;{Q9E|TR$UsbY*rau^I+iC`VErhixoPVZ2)BY1-bCWLUo2o+D)@TE5;`%&0_^ zmgrmh2BW-7kT;9yk`!BJ^10_*>Para;@3gPoOoU7teR7!bs&bs9Vjqk0z z$M42X-HnM8)8fkHi&P)fErV@VIE2+($xeT40a3w5+|#jfMMX8;Mz z6iQ07N(}VUwXI6>qZjigeT8f*k9sY9@~UB65U;Bf`2@MSZ{UNPW&Lc_1$g2SiA3Ou zukEVwc>#8jA3&aD#jKhtk@S^J5Ccl(>Z{Hvd#BQFUh=i3+1%>$1|V>_QjMcOTY*rs zE7m=hc>;C-ZeZupiT}-_&pb}Y((xj0X6Gw6x8SDp`DI)IW4mP8jiu|!L{Koy7s13) zR>+xJ0Gozka6=n6J$idR@bd)~M0=A%LN&2>V1(EFh-JJmUM?$bGuw+a=^Un@MP07S$f|fa&Dwaw7tFk9{k?s8}v7TOkAzb z&@YTY)1fi*-iG7KpST(6&M7*!JwcA+&9}|FF&v>Pr2!8yH*5}aG}F3ELayD?I<2Ma zef*@aGX8oO5B=U*JIR=k8gDOIx{5)NT?Eh5f=vWT<=I1|+<^3SM}v@$TQUv3)L1VR ztICsHqmGEFir_llB8CQcxM(8}5f%H|h_80jZ8VK3Pc>^+BoC@D{YD%v(RR zMd{AtY3(wF((hprOi@$2DtY%3gKR45?K7=^``WD>Z6qY|+Ey1w?bWdAcGl{l@kMmx zx-P>;Z&VQV`jnyFGf{Gp)1U4C_Rtw|-!@lUr|h4$r5s(KuF791<7+fWU?VT(l}MM7 zJcPAgG(CCC;L^Qp#8zX~H@rk}nz}USzQCs+W)~i{lX5dtH#Rm&IT7=azhi%9ncESv z=D&6C`&3rJ?Nb0Y2e0;v>Z)%^D%^fl_hs!rbJ%LCl2A)CcX#C)>~wGXbL@YC7?28U zj;7@TIY1uw?#4Y9uWKW(ywF=*9{w~OM zt((-J1Ba{p6)fK}Oyb!Gnu!Yn&%utJZP8l6Kid61h>?Az_rsgX053)q_(nh&SmA)w zsaWo^aI5HXliDFUaufgNVNVpchI0_ur^fBwHQe$tv^m#)xazw$F)%bG>O_pfGo0YI z)}dc%Vdz404JNn9Uf8xwE6R`LN|QZc-^GbdQP$#~KCrT-!sAoeY}+(?z`5A1naxU@2t-8j~rPtB)>!rn7 za`hR(bEY=Hx}Z#LcN-(|ULz_3E;4Swy|RJPT{=$(rk=wnU4h8{(@(x57FEKyzjy`@ zb^hpPEIA9vIDdYPRDovM^_d_bchgf27R@77RSDo>jql*$`ihbAgd9-1KtMJ+L2qK| zPk2!MXGM!KX0Sr3EZNwj+7KJ;HK*LvV}?})is}U>4YQQpcVN=c8$x>M5()gP-N8V| znAcKt-1cbZD^;{t&sBtnU)euXHmfcM4UzMyVq5AnA^yZI*TNmGzGYQhckzZ0NP~pt zr9?XYeCBjn+ZErqt)+qE0wYN=vNvyu!snsw`rUO!vsQI1c%YVfsq<I)#&c?ZW;a^DC2-|;&U6Lu#?~Ggvg;%y>`6Vt#e>!x>Gw= zb566=YK(@AKW*Ax{9T;Jnl4T`@B`GsAoRQbB!oY`(+83;TLMj6PGfZ&bcts1G(Se$ zxSHDSPbdq=bc;wsJ<)(ujQa&ct=w?7e~vlx*oOgZV-^3aBC#t$My1c{3qWG4eggJ4 zR6EOfFnYv}Hw2k|s5r0lY=^4Bo!9CYE~E!02f2jX*B{q>_dqP&Du`Kx+@^+~srEUd zAJ<~B(`^Xr(bCJ9JzDC zD!)387AaR*Zv2>+KY4cuZ>O7aGbl+J5S2cFcbU%`HxMrB+;$o_SoM0B87j_6SpCQQ zRTkRfj~lxxMD?tSikum4%XT}&b7GFQu}w`jM?PzCVkiXAK3WoKV1vuC?YPU z*n-y7KV+l!eUN`Ojfq$*zFCjejTI9cU#^_v@maHx&B-DAb|{BC>Zh(-%Dsww&3WdW zEB?(*Nv=z=x|)OA9i_z!SVWTG)eJl`WYs1Y;i8#?PX^rH>=wWSLL2g#L72aPo*^`) z1CO|CBPW!Y%)RHU({heOQQsi)D^!K&#gss~YN_+!r$*4UhRuz`=CNYj`#@ArGlSLB+!`9^C)%q%16o0x*T`FU)|4pe4CK_*W`S;bY*G zUhGOs(EaE25N76&&&A&b=krn=Ya&&8Dod~VjC9c(J#rAn2|2j$pP$hTPSxhX)Fq)_yiOUupgrPdZS>>Nrto zD>myVc!Omk@_0rIP8C0rO`CA!3KZ6c#UEYXVBfl2$fd^USy~q8S-N%>=IAYWAYqzF zSwQs@k(kV4H)-9Dd>h?>C^`w!<&3t5-x1ahw zalAfZD{XHC{*amkhNMgG-#)elt=j+NO(21XDoJ%&g>b*StY)5NBt&KO;)|{uW2%e| z3bb=GjG`VV#DXJSuFs<31%)O*2+gj!FibXS)Ep^>0v2gL{%KQVOj$)@lx_KSu>M&!rqz1SQf#6r?0nlby^7J5v4E}IDz;ECm%3< zrw2E#NcmwLRdrUUYF|e*s&XVvZ&fz7@AN~CRE`UfAw_;i<=7Z)|2DzLP_f*^ zRI_xt#NGV}qQ`Z~88oIMyU$Zg7&2)1`x)FV?~>)><&csR2pOAz%t^_N2wgRcs!!r# zwvkdQoQ;7z7Q^{o3;Mp8OAR5Ooz-upENWP}5gX|PGimo`uAV3qNtC$f2SL~q4FQJK zi=@T-5LkN3vC2SSht6lcJ;ztQ&rm(J+9lD`C6#fVmWhs=g?is-_Pik9ditZuqI%nX z8)JX(<6Kf(``&$n1i?0A#GUaX@3lEH<#Qi{;xhFiDO@3i7p>wa_21aN3Jmlw5KpO< zt_0>Mr)<97OxcJfDM$~Zu)F~JB#XK!w&DT=!-s7_Iy;8jE@2WaOgb9&(}diMg=Qs> zjwl6j+|0d8MAQ_~md)Tql9+6wvLFBCbxR9s(8+`(r`+~f;& z^Bbw2oo-0!)mLYnpymP!|XIsXSAyUmD^$DJ6pgA`k zZQ%FMe3vuBCJiRts!Zg-((=cd8Jys0X0!Y=sW@D#RqOK?_DE)9Bcsu@7OHl@1nTTe)>CN*g?@-kcq*b>vmBY*~Zd{de{v z{3uZzDK&1a5Z_o!BASo0eAjoEnd(KsGkyq1t}tL8s5kuBxP+iub(5)p>Lf>MVZ!naATa*-im%}G7Rh94$r26 zldvVx(unui4(aS*=*Bwd!e1TP)cgQeH;*<&ywE8f(vAz%RPX^XUww80{dPWRlm^5M#c zySc09$2hoBy#C}zaZ66D*)@)zFv{386%!E*C_;v4i44F#K4mkrCRLAz+!(>#S0HVQlEzkakn8r0^2@QQ4}Eh5Ma-Dube8f zJ+udd@caB9?Ye-qzRSP~^tB;94BBGa=dQI@fridA=fdfCq2n2r=AqQ7mJwU^ybu)9 zfFZ6uT{SG#M;s0;yJHE9E`7EZD+})sE!h>eF=E?_3|+V2yFte*HJq-$dTCj9ROB_^ z+_BkljnaTZhA7<~EAYWG(P4Oay9!smw}R)B;9zcli8l*ozjth zj%EDoeJ5?lou719AT76vqxzG6#$i?y<>j4o(M>y^mv7eiCqO?o9cMu>W883a%`3)r zdcNN(Gdx3?$Mhkbt%ker&AXB=H7m6fno&-UXI}Pv3x#DuWmR9Fvn8@NE)jJj6Xj2V zR`#!;Jb%CLXXf(LkYWHkD^iEq{1E?=?21ZjACEYm9XNi@sKyXkXV}U4-b1(k9X?N( z{5NS|wK{cT(<(gAt>_6_J36L7fhbGz?9Xy(S-}Sq1to7a`>^x)kt>CbuXfd)GZcec z{mkG+yqC0HNY@I?^K7~hSG`0pTF77+Y3ez6pb4hwkc&=>9Rv@u@rW!p13x6zzhr!! ziw{x2k_4ttG`;vod1?!Ub%>d6D1y^lsvw0W(B2@6E$B}E@PJGSAqa06=#RDtF*c~19eXNGvD5)1$Q6q&_1I0S6uf2j1fv1{Hu7#RAX1;Cqwl2R40 z89T5y8Aw-cv9+%wUp-|i-duZi{R40Qr@ClW&%g@uM*B-FE*I%ghG6kn9!e;6TP~hh zir3{cVh!(%O$Y43BK#U&vB+Cy;$M0^>!?s;xYb*q!&%4XjIvWPCX0UNKgnP`Ck!7f zs@FCI*uip0fo?yXV)QE~;{J${x%?@Bk7qQjg#|~y44e(eIm2E#Iq3=Pc+JOoby<=|y&8t4fo6VjEr$Qi~vuwfS+n7vL^?Zrhs~CA_x6Tt7;l z%de@+Z_LPrRW;$Ddb;*nj#q~Ht|SwsqSb#LZ9g(|Jd!Ud!v*D|-EO$?rt!>E4_yzc zSm{)q_UbT@{3Bg=Z;Ny3MF%^E0*6-0O!0;rM)k*t%+yPxn9!_PCJjUpKr;ca z-Qatj`X3OBqRbt8Pt1?x7D>{)ZAR@y6TF6#af!!EQY99by(Up6Q!ft7a;#uT+j7MZ z^9Da=sdL}qv?C#^sang}p|yitLV0WaN*__Lt=kc&h-i6+D0=$dF6k?~{ipo0%8rJ# z_DyMO+Hg=J&*uEWCaU`hI2g344^?j$QaTRCe5G1~yhuXj!aUDI>qkT(=u#t^HT8qF9I|BeR_~@GFwn~Sncv6 z&N%RCcmxezw;PEozXQ<+Ng`2{=FsEi)8S5Plx^pEV?pQc8+bLNtVKEEv1`5G1Ks6W zbrh>doj)#PtTg1MS~r*6As9!*3PqzqNQE-pV}e?_s941m=S63jx@&CUI@=r=))Q50 z0@B}wG6g;$8*O}!LaHzOUlLzCs;Ti`S~>K zcMz0K3lJE6@339$xMshp8&`uSltox|1RTVzI8$=8Hq;`lvK;js%SCiYmp~iSyXpw0 z<|(xJ#{EmMfeg)LB)1u;W^$lBHaRLjwPb2)n}BDf^4B^+_uk=AX`3=1;ED-1J9 zPoqlP_DA_URkc458orY31|FEX6G{e0gISqo;bz2qpoMh{{*?06cbd>PY_{k4cLyzp zuAZ@;YAnG%urv9gqkwH1U-3(F^PaUe4v%aK-;?^&{vvjOkeXRV?E``{gAC*Igw)fA zp1jGpWHU}!(nF3^(3nG>@Y>5{$5ock#Cov{-(S5{kj`S0H`n!zr7t9h1C*9~#@kWp zIFnqL1y@5%SAn5OG~zb$=46vF7kwX|M)zcIfL!(EDvZR_;R(#5?m{biNjc{;g7We6 z^Fdb%&7F=7y0$zq4q74K!zEJpmIB#nt9Oz|FDkwkWi`H(LU66}t@9TUcOs;*aGN#9 zsp!nG;u25IZ^vyb?f0Gpck3&i>dOo27Y$wOD?R4FwZ7%)^SJ%$Qb)Tu#fsolPyo3- zuVY>!OYA9Sbsgfe5OMr)B8f&Ckrs{a=3cpMD)7oSi_F?Fg3pqzBJ#vA*Q0ms&ORC$ z%S?&<422kWKD~{3|K@yR>F`xwXNQs@y2|^*Fut`t!sS%~^Y#4UX6;LZ(UpM>Z$ajB za4bR`GE_Y#?p{%5aBSGS#v`^S`RC^tlOBwmuvoiQcZ}4L95&vI-;Sr9qQK#xTew%J z-FD6LG__mO@D$6+#|mMJL$iEk$M?z>fAy~)8$oBY)fQJm)4ZjHj-ys}w%bkw#D-I5 z2&LgqPjxTm10DJ5Mc$T=P(o~?NHnU;{4^%-9TXbvuHgs&k{XygjZyF171Dp;x>-_W zmZ9SwAhFpWdl4NwCuHQ&|CYbqI7Vvx{%HjZ3at&tT;+o2Mg4*1M&bWHxGGxf)e&uvHeMNQ z1aoktyVQWiS8x5o|q+$k;GSZhl3|Q~WLKe5;#3#%rjS{ z-T9=~8vjzjU~z)stM|?_P=A}dME@}f*xh4uOq0WW@0`NI52@uf5P*waF(>Ez(95_P za2_8-e+Iw)?b9MT^)Wcxbs`Jd2;-ddI zQmd^xCC!oF8ht-}1!0j*D?{}jO1pziT<>G$+8of1)ECcb zXs9tp0ue|X9kLFNjCyI~nCoEL2bn`g4Q9wloz=@kGxkGvT4B00eJyv@i@h^JV-|9w zcV@cN_b%29D-w-z&Di+q@bYg8Iue~Z&hf@bDTJ)mZ$H|L8{qJ zHy1wxCucroIUo|N2@>_5$NS|KeV$hYn^^Vwrv`iX&7T{IBA~T)m63UQ6yb zh*r0=Dzn>su-Tc)ysb+JULnR4f*1KgmWB9SU6hqVtksE}SKoH;bARG6R??5(-nDSq zoIJU8Kyb=ZbBV7z;^vDG+D)ie&JnoHoq)~dqP5z0k1?I~rd!+|GPWWpiu5cY^Vkel z-pwW;NLAethRxwWsR`TV1a?2mNYl4h_UKr49FKv6W5a~uD^z>Z9CbszdwpNqS5uSK zHTjv*W`w#P`DabN4-LSI6Mj{jSJv@@tBT~@v)K=F=Nrea6Ts1N{>?5&T{GrCO>Qf? zcHCJ!C0Bma&EhB3J^+q8*s-h%=sO6O;M8|@y{tWkM{5^u3qfsfY`dOLs8FGj=J5&@ zDr70S8GWZdbfi3qHE8@4*uHrMtaE9jR3J*ENmRKhqIk;N6a5b5v$g$ zgtrg}3L3M!q}aWVc|#~XuI#ET(FRmTNSuo-ET~9s7dXskTcRqh-02Tct{GbS)6P4g z){h$wy>#w5u0+1-$xMl%^hAQj-YEZ(XM<-?WMG1C0=DUy-EkH9e!3^R^-kk~1ZCO0 zU4PfGOTX{Q=bP>CY@bKkSJv{<-zV7rR?Ym8%gl79H}46h-e_EoV+u3xbnMyZh0N^Z zgVKDk4kL>>>+iGan?y;N7Fnq9r^qA7D5RBg7l&NFp!u<7Jz7z10Xda8`K~k3n*T(! zeK!OVx7kcAD(y(m60b1=91&rr#Mo^`?&kxSLWUI2w6R)17Iof|t#=)N0ku@uzQ;zJKE*x^ch(wlJ`BE)b=^uuc9pD`>ni-;f%nD{I{Y3 zEVqyf7p5!HS3`=7`5WY7ffv?~pMb5eK>HOZ-$Bwy<*hzm4l9E_y5E*k%Kz$^!ymV@ z$o|IlhptidJH@``@c}q0H@czz*V~oU+oKZe*r!YE@!jjI}EZh}pKK@lX)&SABe!RofT;>=5tYlvu`{FBf$; zzd_74n)I~?p^7iyoM_JdJ39YcgCcf4I+CW@lipqyMjXUSQ^yNGdLbc=;3$(`$Xu>J ztBk+uSLa|9x@VtS{8u2GX}Hc`wyE zZ2BL_y7XKaZ=HO+@?_2hi#SSZB;@Phd46}C=L9&cHMX2@dY{wrl(*J7EQ{rzTJ?n3 z8+Mk;yDV#No%$PAZ=n+Qo;H=XTk|&?eVw`8L#t~Bk9-36`$it4tu}VzDtQw;P3rO7 zUb4b#75Qd;(jc$6-JWIXZfDU>)K0McCEMxi`<{Y`AqsjiqLM|D7L*%y_>*=EK}^Y#^QN*Ak<`2G|{NSKV-)#I?9M&ke2 zVW9L=gDEGpV5^(sI~7Kx`nqbSVvYG+s0a!d3$hE>sEUtYE7vp>8;EX)HcmPD7O~7K zRIc!*oa|)oyiU}_pG+HgVm+lqU$#%-i~?hqh^jr`W^X+?h|DXy&kDTl@^Lz8^+dkF zVO!)Fo3n$Zq?Y%D;kx_DR;54!5J{dMs6UrpG320n%AIh}T_Nn0n4v228=vxLXO>un)#P_u+m3B9@qso)L}V)tF~?*iq4WoGJ*5le^s!sJrClDe_h zUyp7}vQ1*^x#bcXYikir+BMv~MHVnY@jD?eMTAX?ZnAqjTjVwK~j*Z&l_|~d;Q-u9_o$O>OF4iD53N=x2)8rgw({P&jmgY-&5V1A=Z6dcaFj?wQGDeA!)#`(Y-Fnn74ESo(?c(^bFtJ7R z(7#=59_%~Sk!|18P4OL8R&zQ@xuHM5{T z@|-4Y_V`r#xKSb?o~9=vX5TGsky1VV5JR2h=r}FnTNEj=H!dK;tqy2?p{3JtF3LIT zB*?!*Uwy}JjKR96Z4i_txt(H^Vv?H>mb{^naMSgwy?2I6j*UPwN!5$UIfDy4bMRC% zQt82=OSd`g_=kHrH?~&(tI(Ab|Nk*{F7S-z_x^t*Q9+1Xs_nXDFm)${4H6Q>x?jen z*|x+v+wN(1d%A}~g&=V|ZZjBTjDidF3W~p5O2L`+VQ;uZsHL%+1*rdZLR4qZk{ek!LeNkx{MFE?OW`X`ZAC z8c#A}cXa6ywlHLKZy30`2-Ae$#bPBeOD&zO%WXBdnmRij+IOAA9XGLD#6Bw+vvoiF zj#w;}U%z7-sX}B-)}EhU9^so_TV<;>j0d6*$K?rJPClU)^E)mME>4*1K7wNX%+Cnb9KPPBI+@y?y?&h&LM%T?73PQdTvw(f)_+xTVi^n122*jQ z%(gEDuCa4w!)!kb58FAwsdf_0^ExrE)K1M(TsuWNJB+##h5jZ6-dn1Z$hDDa=HI;j-zykvGo#2O;D>- zOQer|$HGPMmG}+sQ3K89A7*O*&J>8&M}-37gMhL zA%XRQ#!USHIg5cJT5L}Ua%OYmTpa&+=i|_Lt5%~5Aaj6nQ#`>B5BEX;-z-7l@#zch z#r5&5GZM?Q$Uxq1maZ9uSWx?J@V3Uwj(coNLF4Mb$~Quh;$@lL!&SDT5)uP}bs$%I zdZ7RhMbr8PsYj0FbC{?FESv8yJR-3K;0mPx?wdZ1*t9-YUjVqK;VTsH+;$YH%2Bz% zBA|E}0jTbZ8P5-2vgy^lI8M?-lHJ46A|T*n&xAV8>b(x~y#PqmcJJ^5`0WuigobEP zZJWtZz35Zr4Gror!w3ON;qR|vK1`(oKXBcONYGU3^fPFgV*cY;tBeGC7ZmWJA9Jxt zc*=-c84b3r+Nw#ix>B3dJYY@w`fPkw;8KtYnT4@dIl_?;qh zI&S5RIn%UVkZ`e)TC~Gqyp@NJTK=9EIx}Yb_By z{8Z4(`8=;!{v^ieMXpLTg3suW-a!Q2*PEl-^}wLDba^Vs5;qJUgc+CYpWm^-!0X)J~^AGKDF=_ z?xngfM&k^HW}*Dz6CayjA6m@EJvi-6SMjHGf>j;{S>uND&cx_(gMb7TSIK5{GFs&Q zc@{`&$SK@A2b=x)!kd6wG1-wAd+t0n?cEVSvZL0TN~cdq(Bj00)8Ob(`t(O_H%tka@-I0docCY)t>0fQ{m1>!KffVM-ed|YLjLrN zU)BVu1AtiTlXK)~UD)H5K)*F_#x0Uqa7G?7EAEZy)G5C*4CY(|==Jl}L&PBE#H}jD zG#4C-As^2B?(hD`-ET&g>sQ{plV6DfQRXU~`ARydQRE>`Gj_Lq9BAbrr0W1HAOzhU z#^L0x+gk$-)SUNC%3_l~IrIA{TbaoN(-7a>boKu-M=uwlC|ef9ps;Ufc>jHE;;Y+M zAz#pKN65jaEI6mvuF2vgzHko}re|P`Em=`OGE8ET->&7wS(2IwyJlS;as`P`Qnb}~ z2dM*sgh20avr@9F3udHyebkD71XUK?m@k>1jxf2(tR`7e@lO-IvU$TDOGTCiF&*7J|*c&eUJ4ink3qHtRT4 zXmn4Ua2w$6`o+GYlhbGfp61S8?xQusD?(qp)wq!z`6>1A$;ICG@y0PlO#^+Nn)UOZ zRXz{7`yf-KgEmdq)2>-YIa3vth@y8dGPcR6IDLx zdht(c%Jn^avz9E}H!xqaW_ffRa6Ly43|-T$pHU}|%`nyUjrJ>~yk^Hgw?BrJ)c&~Y zy#EQWlUEmDGu_!y`NjkZ%)CA{t8>hZax1yTxHBSWZEaKj?C(K1b3MI&zjLx4o z@w^a+uP?LxZ7#BOQq9W8Bkd3LkCNRdD$Ws!b4j6^SpIhGGWdYPx~nTZTT%u+St^I! z3fPf8knt?NWD0muJ)FJO-!>2IW>nsVV$Y5@C6aF{KkfR<{U5z@Fep!;KQ`{tg1UjZ zfH4+IMnCNO^PiZmcfLme8-7&yi^{#Gy3J4T{|Ty*G`yJ5MP}WowxA~tumSj==7D|+ ze%IHg`i|26u5It)MANJAeX|g`beZkbi+(s{ZTikoH!gP~_o3mChEiaC?w@mX{_HTq zf4O|3Fwh|u-$(rCA?)U0_900@x@o|hfPSddnkhVt1EmkFl@RKT*`M52czTm{SQ48j zWJTO$9sX(43EKW%AJ+$VmQy*O6L-G+!;SKIaZvuVf2w~VG5j5jJyJI+9cdvK`7I)e+I-BFT@2D)D(XujCTj|F+Ish2Abz7kIkF7<;>mtjU%E#s# z3V+9ZotlT0iPTu9-)1o7nQyH)@OS3Xn<%C-4xjrl;dxGwlFB8Kgb605tvrI4NnvO> z5NS9nh1?+IR2~|u?d5BIpS3HFAzlG~1{wenvd?Rhir80^>G9Vyy{Ah@r-yznK`49E zY&4o9){UNzT6=He&Vs(TiY`&YzgS@1l+`laLzs?(kN7tQ@57v$5n;{4Lw@_-sv?PN zL4Jl|<`W*y*KIzfF1g1Gn9yj;w#K-Cmw~GSNY+G7JR>Co%CZ0_wpM37+obE<{k?u> zndWp#veYeh9rL>Hkrp?G(-V+~{Qi@2%RK5@u%6bDvRZRg{ORVY4D4>;9Tau2y9TR) zc1L>i$L6BM@^Bx$UMGUTuelGXgRb@^r`eCTi$`mBOJ?^N z#;6*vBlq!O#$a%Xi&4=NF`q44F0Zy?7q@^9a5e@eVOj6dgSJ0`fzftGiGkM1oUG6g zR>f4QDAmle;DUB1GZvm?b;;Vv=)FD9?4ZdMRAbD?8>@pk@$CnCZnki}QgLV>`%Yf> zkfpZ<*|V(=W3bNgMKi7l)(^QV#>4da-!y|*4`N#^P0Tbn^sG;0cPUx&-Nx3&Y?Z>) z1SlSY`S|@i>fu(v$%#hu;>gBtFdydkue8%W@|x8x`>&d>fV}J^ukV!P2wkUei!8jW zewh4ZyvW2cXUcwbxheS7-CV~AdG#a2$jpIcGs#K+t<|Y$m9x4Sa>}@U0R^nuXBln> zMT>6Ud zbiCzYT3HYj?rBrA$RfPv9OKFCT3fM0xEQz|BQsm5j z8|(7}b<%=Au9c`CpBBbeA^Qku!3CR$JP#eLg8SW*oXaDr)8iuxE=V#{wCsxor`mB| z?t%P#zB>Ekm9=S$G5n8J9K!Orj_6%(69^W_YK%NnV@)r$xXV>nuGbISY76=Vv!rVQ zYGSv�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
7f;=+DpuNmJFQ_s)-Mv3&{O)m% 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

6= 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

<^xE*LjN0&k3^HXD-)Nh; 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ℑ%Jf7^{*#t?)R;^J4ejukTxWP(#jCIm4k=)@qS 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

  • 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

    G(-+EH2aCP>^E)w>i#gOAbXD|+m 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%0Aw;{D6SehEG-^M2ef^Y-{5cH~GS?$%V0`~f zhY?O{9sQLi_D$&$L9?HF`P4adIa+z27S<{?pc~x%#7RhQ2R7+h`C=u2=MO=%Oe@?3 z*2#Nxf@B+Z_|>G*h>#Yn=B$u??l0kakS4+d$CD;NxrIiy9(OdTELl324dzmt;M5$g zQAy~5YpF~p8}T5Qy9KQ(z`CfHi)l>}3M=X=B73xcd%7bhk9@BAaceY~TcVB`WI1 z_!Rj?bX?p#yyAWg0RZ2~viXWp=|RE^%lVW|bfuiEdraV>N-EaX^tzfVTd(sJPgHg& zf>k+W32bQpa%lOION>2mey*sXOFGtS9{7%xwHI_0=?fE0U_s{AA{`^Ytt|Tdy&9>dN4K_ zVojv4(2!VltO$HKxs;U&hhu2s;P8|yN;54WU@)(^2Oa$wjA}MSum)DBj%-I$Jpd1a z-J1QH)N7}YffCc0UClvPoyVh#>l*H~U;hX}3RlZpq;{;vEK2PHszAnuQou47^r@8| z9tmeLe@piTpW<*>+jL2$Mkt(I(;BN)2z2To z*eYCOBc=oC5z^x3%-9fZVp$A!Rom^_b6`!VDeglRG75L}nDy8)@yKin+~~GnBASh` zE#KH;STpi4fAKtgpq_Z7O?OuAj;~@_@H^}n;-ujP*PTWqayxlI zyvLbdB0VELmF=$x_w)vrHi8z?!V2z#;`u|r!mcEIci8%W*d4EYbANhS1pg2wIcUot@xA}O0}qpo zxK(-<50i|rhTxo}lmI5&|hAz5A811N~o3O;>fxSttF!MS<;=I~BD2;Pc7w4g6#L&p&jt@j#o;Up~gg#~<)+cFN!U;KwjwAA)|=b(H;w&#+Ry zmirgK`NL=ET+RLIpS9IZTM$|dD4TqL&C|dokBu$$^{7INjO?#zC zMq(x~mx1a6EHhe*kVA7axRbWLNGwZC9!q2icjqlaaN zvJcJQcy9nGv;-nC^CSMpPFepZleHa292nsjMr3eSeeZuw+EHBUlOZ(RJ9B4X=gCtp zj?oEw){JK^IsBgg+s&h>(-h~uBUU=j(CM$2lmI*)9+L!H6!!o{Osfcaj=yUrXs3bN zJ4g^A@CF_S+I)i$Mxzwd1uW2*%a7gXH(T_@(KZn=DR_&mJ|HTHNwJf6A66w1B)HyY zCe72qqt^oENI^36j+yporzhXS4YS+{knmTv{tZnuieaAybk`;DJDSEIZuGE>a8}nu z1d#Y(@tb=@WIXD^(GargO0bJf)Ji z4`@TYkP;yeVDIpfeM4HUmar-+N^%3a4C5$wnn2*IrF8N>L#QRgC~fUp8%wT zI?hHv`K4~wPjQ2Nlu6#p)=fo>K)tpW{D;-;H9>oo(-}wqjzX2MfG-_Gh5idB#rSIK zWN~#It>gj^$PsbIY&u8-w`d+J5I;Z$$S^bGz-sRn|Gha8A41;ZC9L~xkju1@z+_LQ z)m1H;`wHao+r(=S55A-$XUSsAuyAdxHjxo>NZS!*1%RfqUle2J>LOEAG! zQ_EGv1J6JbVewQemY{{_d87C))L!>z$H^y9M;7;>8XZN25X4hOm@NG1J^Oxf>hvaT zomR18**2TC_;2x_Fs5X*lB;>9HP|C7SqXv)mBKQC@tje5x$}+0+UMFXb!ZFTAtbg6@{Jr(hH1 zQF)*(Rjl{-_I0`EpBEUv%ktJ8>Te6}MS3tn@OB}l%EIe`zdkAbz)g_3+*g(yQOhoM zwO{FEbyV`6X?@||l5ZtWB_fx+O}Sj0osp88otyEayUK^HseRYd3GWMK_j1?ydr9=_ zl-y5=?+S8G)05XPl0FAI9-SBS=Ds#w^>*aMlSxgBX#w*&z*vw;T6xb||L~MI^+x>g zM(?#GL6rO{DL>cvZm;)FAiH$#oB3H1r@%Mw+cZK@#iPpir}H>L6X|)44)6`+So)|pW;gNOHOROyJnBdZ*DS<=^ z{T@aO^CdT}(aV9VYcx1H25RjY3nv*c4n9ok1px){ zYkF&*r)TFaKSsof{EXsjr?7N(!18H!gF+ScxczfN>ep5zZFbEEDAv(zkIMb)YJBNm zj|IoZkW2jmMq~7_{emg`?(0SH?|(^vO1ilKt^7iC(z;AN>m%lZY`*vS@5@hRNhUU- zefmZromIhQAfl&i5|rsI%vY>{?N?b} zxS2#(*aZ03T!4S|LZJq@9__Ju8uTRP7uY0127u?XscGq7*qNba+|?Ea>6$T!-(Y1h z1VGOWPVN${qBy4EQM@3u!&ko)Lgput6uu;!0T~c8pfpMvyyLyY&Rpjw|K(HjK-Y`k zK7ant$nbk_kzY7hq$40*!vO%B?8QPhi(8Do(npp7L5jiH_C+vUsfo9N5&+ zl=XE5(xU$($_CJPL;}R*I{Hen#owbP-A8N`>Cy=+Cnl6^1^0J^y$k1w_h|D<8Ie5Z z0f@OpBE=1&!uaPKO8`#hypxlZWdu`_XZLYFlX&q2W0iMu$$O60W<{vtU{Z61YJ>s= z(d3%chXYDQ0(?4g*Mqa8#d|M6JeiLJntnjZuT#DNn(_f&9Dz5?$Df2;RV|aPzDzHe z%RFT!;((@T?`+UN`5rixBiswVSM`oPYnk&c~RFpdY@ms{`k?>=Dn?;8{9;r zeWuWW=Ob|!hVXo(1|clOcT>HCE{?@OLdh8-&oPwxQk-ukYx2mk2@FXKT;1$EJJUxJdZ@Vo8MQPF4T zEw}s|cTvAV`*hAjc+0)=)hBaSO3_73v48+071*7USC9B-!r0dGh0Nl-^EisL6b376wvo@0zXGnE)Nv%_{J3guLQ%+6#^nO`*lTNX8M&Z+vM`Cxi)e9Ycz%}y3Op*a2bwH zm(Qr?Iu&@`yw0nMe6qA&v=>Ti=vclSY!Ysrp|z|npH4A$*PeD;;;X!CtlS_{#--SO zHhnrtQZ(#r?f+9%yR-_lUEZYhWFuv+gaYcbwoTI6^7WOVn?zY=;SO^15uB@bN!DkS zNkk9wb5XT-h}U@SDKoU?&f8yD@+?pxdz|IY;&oyk{9v{4AKJNzBl2}zy|Hl68}yuQ z#i4*B5cuHI-l(D$JSr`@RNTU3oMAh$Z>j1U0l@RY*;X;BgCj*jvw~92QMJbSji>wq zwj3SxtUAtTF0r51=ibj=GBzjRkdytVxcoOz$U*et(&)#Z0I8{GCzu0EF( zF775PPJaw59P9*3^tZClN8OYR{q41qu4sE4h|oZNScpg)bgWh7Nvn<4sw|{xI94T4 zYE+=3BX*+2EatU8q|qQ+PuvF|)B2wI?%<%Xhr6Z1X!|n%xH4eK%b`gPN=lqR=~Ljy zjXRwYBUcU-5I{Y6Xe3!1u#q*)=?c9Nns{Kw|3zu7mER{Z?1r4ZZ_ap#BR1a`N`sKe zqXe#iCMHJq&=N=>d`(WPT4ll~5Hti!>^$r1DncNWHU|*h>->k#Uw$!dlstYI9;Qq+ zmOO6#!L;!TH*JJ|S9gO_+J{e-W;8a{1Xyxdg!p3LpIjxBH;t})PwiwaR5-U5l!R;W z75#Zu+3z`9t{WjC4^M1ch9ual0_Jlk!4}mQ`g!LZUO|zc`=k$hzxNy!P^P;fW>^SZaK!W>528La4d$b66y82Np`&R~$``~rHV z=Xmt+n0A`Ar>%edUbcC&_^;gG^!-qKcaG=o{n@>?19(5j&CavArMrim zKIgZ~-%S`0V4G;6Wao`8KU!=a(#W1l-N_hXEghU_RX}M0U>A8^q#lZ-RwDt6%h(c% zEnk)^zuF5@d~lD;c1E56C6(5P-V$9G>oIJ0S$!SrR zgL+}lYoW+Y)V~ce--DiMBI%+Mv8DSQ*lyz_BWSl_2L!knV4VWQ{)*3Tr72_rvktWT zh%lb}$_5)AAI#|LJfBRoQeG2sasakUJ}OjVDqxfOk2(%;C2-m+ZM%5-D(K!&>M1(4c2ra*)K1(iC-NT2O_afLm8>=NRY{ZO9 zoy_n{vBeD70H6R53%w!Snk5fj3{D7xK5pXmTHo`Q+OK|cT5$JXbwGMWtD145vIIa7 zWPHLzf5Lpg;=(2vFaTCJq>OB?ITluQW0G-V7k@^<94ZF)8oTr|z)V^Wn(LMvZ7cw2 z_#}m)TpWt#+Pg>0s6`RfZ6#Xq-c>Du8rGp|4Q6@rYK5@#3}D3v#9XYW<4mk+1H{fD zujzrKC^4v`=Q)r}%@IoJeU;Q~Zr2{zff~aSH6{)YkR>X5tosHUs0kXzA*r&jcNg41 z=>g2EskO0=^WN!y;D@~{d9OK_&cY#K+y?iEM+PT}c0Zgn)nND211tbUM00g(oqLx* zUVd5iI4~kCcw@ETPH*_S<3@7eUj#}k3hR8%oT^zu#9tQR4Jciq?#iB2_;==|PZ;oY zRWQ4>L`Dsvg<}TSvP)$i*(%=vHuN=7i;QmVArMPmb1%r-?RvPJ?-G)qlb7N+jK_N3 z(lt%Vdxv*Gp=n3eODody&#u@brjhOHd{6eB*}x3Uuz~5lsN)36C==B+iLO30Xd~?P zEEb!90$rYRjl;xonU0)9gTtCybD19LZ(TGufg?#pmJ~Pl$5#Lyx$5jP`IL3?1&i;Y z5nDu+Hy!K+7o$2;ttZU)r1<52ssX;2^Y>(9s=|#Sj?XiPt&tI2wMg0W4Y-yWTbIL{ z8cTjQZTor^$YSUs{jUh>W=L<>E#PE>4eiFHlJd7|doW})PfzcKF1TdUUN9}A%Ta{6 z!I5ISb+l_gs952Lxt6e1*+Kn;;<%f{4W4i<>5Hf5TO0(lq@d!PSa{>;y!S?%hbEKn zTXd=Tn=}5uQ{3FnT1~XP%f!wIpinU@hfhhGNcx^zQuqB*;9V619nMLec@*{%jN@DV7O{A=?gIH% zki`tBTe$Ug*MkiQASD^%GWv-5_d3HYeYwdIUT5^e^>wpZ5+_XJU-=bHy-+wdg-mGC zdneC1V{^m4$yg8c*^b8h+87A~@$44)m&}*{UI%B7+_QiAu<_0o!_Xydy^^xfuIsla zT{-&+3~ksCj~&W?`3!cNN1X7Sy6!uhY~)_u6Px*)@SPg4Fg9uJFRqoe7vSXbiC3%p z$psHz6JqP_i~sP{C&4u2t(RR~)18_T?9+r99f2#e20Nojy?x<$g(UhDqR3YzM~ERb z^Gz}|=4d*bSaDS7e4-vG%`rVAI^Gs3W`r-F{Wx#*TEPI|8yJTM@j?>wc|+cdFJ

  • !6j%rwz@HMr$$ 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%0Afn2Q7o?K)4R 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 IR$-| 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

    OhQmf7uu*bDNcsw^$CnLW(5lt1*? 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 #include #include -#include +#include +#include +#include +#include #include @@ -80,6 +83,7 @@ static void s_TestPartialAmbigRange(CSeqDB & db, int oid, int begin, int end) sliceL = db.GetAmbigSeq(oid, & slice, kSeqDBNuclNcbiNA8, begin, end); wholeL = db.GetAmbigSeq(oid, & whole, kSeqDBNuclNcbiNA8); + (void) wholeL; // not actually used, mute warning string op = s_ToString("Checking NcbiNA8 subsequence range [", begin, ",", end, "]."); @@ -395,24 +399,42 @@ BOOST_AUTO_TEST_CASE(SummaryDataN) int seq1(0); localN.GetTotals(CSeqDB::eFilteredRange, & seq1, & vol1); - localN.SetIterationRange(1,0); + int oid_values[] = { 0, 100000 }; + for (auto end_oid : oid_values) { + localN.SetIterationRange(1, end_oid); - Uint8 vol2(0); - int seq2(0); + Uint8 vol2(0); + int seq2(0); - localN.GetTotals(CSeqDB::eFilteredRange, & seq2, & vol2); + localN.GetTotals(CSeqDB::eFilteredRange, & seq2, & vol2); - BOOST_REQUIRE(vol2 < vol1); - BOOST_REQUIRE_EQUAL(seq2, seq1 - 1); + BOOST_REQUIRE(vol2 < vol1); + BOOST_REQUIRE_EQUAL(seq2, seq1 - 1); - localN.SetIterationRange(2,0); + localN.SetIterationRange(2, end_oid); - Uint8 vol3(0); - int seq3(0); - localN.GetTotals(CSeqDB::eFilteredRange, & seq3, & vol3); + Uint8 vol3(0); + int seq3(0); + localN.GetTotals(CSeqDB::eFilteredRange, & seq3, & vol3); - BOOST_REQUIRE(vol3 < vol2); - BOOST_REQUIRE_EQUAL(seq3, seq2 - 1); + BOOST_REQUIRE(vol3 < vol2); + BOOST_REQUIRE_EQUAL(seq3, seq2 - 1); + } + + // Try negative values + { + Uint8 vol4(0); + int seq4(0); + localN.SetIterationRange(0, -1); + localN.GetTotals(CSeqDB::eFilteredRange, & seq4, & vol4); + BOOST_CHECK_EQUAL(0U, vol4); + BOOST_CHECK_EQUAL(0, seq4); + + localN.SetIterationRange(-2, 10); + localN.GetTotals(CSeqDB::eFilteredRange, & seq4, & vol4); + BOOST_CHECK_EQUAL(10, seq4); + BOOST_CHECK(vol4 > 0); + } } BOOST_AUTO_TEST_CASE(SummaryDataP) @@ -827,15 +849,15 @@ BOOST_AUTO_TEST_CASE(NrAndSwissProt) nr.GetTotals(CSeqDB::eUnfilteredAll, & nr_oids, & nr_vlen); sp.GetTotals(CSeqDB::eUnfilteredAll, & sp_oids, & sp_vlen); - BOOST_REQUIRE(nr_seqs == nr_oids); - BOOST_REQUIRE(nr_tlen == nr_vlen); + BOOST_REQUIRE_EQUAL(nr_seqs, nr_oids); + BOOST_REQUIRE_EQUAL(nr_tlen, nr_vlen); - BOOST_REQUIRE(nr_seqs > sp_seqs); - BOOST_REQUIRE(nr_oids != sp_oids); - BOOST_REQUIRE(nr_tlen > sp_tlen); - BOOST_REQUIRE(nr_vlen != sp_vlen); + BOOST_REQUIRE_GT(nr_seqs, sp_seqs); + BOOST_REQUIRE_NE(nr_oids, sp_oids); + BOOST_REQUIRE_GT(nr_tlen, sp_tlen); + BOOST_REQUIRE_NE(nr_vlen, sp_vlen); - BOOST_REQUIRE(nr.GetMaxLength() >= sp.GetMaxLength()); + BOOST_REQUIRE_GE(nr.GetMaxLength(), sp.GetMaxLength()); } BOOST_AUTO_TEST_CASE(TranslateIdents) @@ -1015,7 +1037,7 @@ BOOST_AUTO_TEST_CASE(StringIdentSearch) int oid1(-1); bool worked = nr.GiToOid(*gip, oid1); - BOOST_REQUIRE_MESSAGE(worked, "Failed to find GI " << *gip + BOOST_REQUIRE_MESSAGE(worked, "Failed to find GI " << *gip << " in " << kDb); gi_oids.insert(oid1); @@ -1025,7 +1047,7 @@ BOOST_AUTO_TEST_CASE(StringIdentSearch) vector oids; nr.AccessionToOids(*strp, oids); - BOOST_REQUIRE_MESSAGE(! oids.empty(), "Failed to find accession " + BOOST_REQUIRE_MESSAGE(! oids.empty(), "Failed to find accession " << *strp << " in " << kDb); ITERATE(vector, iter, oids) { @@ -2454,35 +2476,6 @@ BOOST_AUTO_TEST_CASE(ResolveDbPath) } } -BOOST_AUTO_TEST_CASE(TestMTSliceSize) -{ - const Int8 kSliceDefaultSize = 1073741824L; - const Int8 kSliceNTSize = 900000000L; - CSeqDB db("nt", CSeqDB::eNucleotide); - - // skip this test for 32 bit or low-memory machines - if (kSliceDefaultSize > db.GetSliceSize()) return; - - db.SetNumberOfThreads(4); - Int8 new_size = db.GetSliceSize(); - BOOST_REQUIRE(kSliceDefaultSize >= new_size); - BOOST_REQUIRE(kSliceNTSize < new_size); - - db.SetNumberOfThreads(1); - BOOST_REQUIRE_EQUAL(new_size, db.GetSliceSize()); -} - -BOOST_AUTO_TEST_CASE(GlobalMemoryBound) -{ - - // No real way to test what this does, so I just check that I can - // call the method and build a SeqDB object. - const Int8 kSliceSmallerSize = 134217728L; - - CSeqDB::SetDefaultMemoryBound(512 << 20); - CSeqDB db("wgs", CSeqDB::eNucleotide); - BOOST_REQUIRE_EQUAL(kSliceSmallerSize, db.GetSliceSize()); -} class CSimpleGiList : public CSeqDBGiList { public: @@ -2847,7 +2840,7 @@ BOOST_AUTO_TEST_CASE(SharedMemoryMaps) seqdb2.GetSequence(0, & s2); try { - BOOST_REQUIRE(s1 == s2); + BOOST_REQUIRE(string(s1) == string(s2)); } catch(...) { if (s1) @@ -2898,7 +2891,7 @@ BOOST_AUTO_TEST_CASE(SeqIdList) { "EAL14780.1", "BAB38329.1", "P66272", - "NP_854766.1", + "WP_003405746.1", "NP_688815.1", "BAB37428.1", "WP_002211004.1", @@ -3176,7 +3169,6 @@ CSeqDBException); BOOST_REQUIRE_NO_THROW(db.ResetInternalChunkBookmark()); BOOST_REQUIRE_EQUAL((string)db.GetDBNameList(), string("data/empty")); BOOST_REQUIRE_EQUAL(db.GetGiList(), (CSeqDBGiList*)NULL); - BOOST_REQUIRE_NO_THROW(db.SetMemoryBound(1024*1024*512)); int pig(123); TGi gi = 129295; @@ -3778,9 +3770,8 @@ BOOST_AUTO_TEST_CASE(ProtTest) s_CheckIdLookup(db, "2202317B", 1, 628); s_CheckIdLookup(db, "tr|Q4QBU6|Q4QBU6_LEIMA", 1, 609); s_CheckIdLookup(db, "Q4QBU6", 1, 609); - s_CheckIdLookup(db, "15127771", 1, 341); - s_CheckIdLookup(db, "aaa15484", 1, 341); - s_CheckIdLookup(db, "bbm|301338", 1, 341); + s_CheckIdLookup(db, "15127771", 1, 345); + s_CheckIdLookup(db, "aaa15484", 1, 345); } BOOST_AUTO_TEST_CASE(NuclOldTest) @@ -3987,6 +3978,21 @@ BOOST_AUTO_TEST_CASE(CheckColumnFailureCleanup) vector lst; BOOST_REQUIRE_THROW(db.GetAvailableMaskAlgorithms(lst), CSeqDBException); } + +BOOST_AUTO_TEST_CASE(EmptyMaskData) +{ + CSeqDB db("data/empty-mask-data-db", CSeqDB::eNucleotide); + + vector algos; + db.GetAvailableMaskAlgorithms(algos); + + BOOST_REQUIRE_EQUAL(algos.size(), 1U); + BOOST_REQUIRE_EQUAL(11, algos.front()); + + CSeqDB::TSequenceRanges ranges; + db.GetMaskData(0, algos.front(), ranges); + BOOST_REQUIRE(ranges.empty()); +} #endif struct SDbSumInfo { @@ -4260,112 +4266,6 @@ BOOST_AUTO_TEST_CASE(TestSpaceInDbName) BOOST_REQUIRE_EQUAL((string) dbs_sum.CompareSelf(), "+A+B=C+a+b=c"); } -// For this test case, all GIs are found in the GI lists, so both WGS DBs are -// kept -BOOST_AUTO_TEST_CASE(CWgsTrimmerShortExampleNoRemove) -{ - const string wgs_dbs = "WGS/AB/D/wgs.ABDC WGS/AA/D/wgs.AADN"; - const string gis_in_wgs_results = "data/wb1206.gis.txt"; - vector gis; - SeqDB_ReadGiList(gis_in_wgs_results, gis); - - CAutoEnvironmentVariable env_var("WGS_GILIST_DIR", "data"); - CWgsDbTrimmer trimmer(wgs_dbs); - ITERATE(vector, gi, gis) { - trimmer.AddGi(*gi); - } - const string kExpectedResult = "WGS/AA/D/wgs.AADN WGS/AB/D/wgs.ABDC"; - const string kActualResult = trimmer.GetDbList(); - BOOST_REQUIRE_EQUAL(kExpectedResult, kActualResult); -} - -// In this test case, all GIs are in 1 database, so the other one is removed -BOOST_AUTO_TEST_CASE(CWgsTrimmerShortExampleRemove) -{ - const string wgs_dbs = "WGS/AB/D/wgs.ABDC WGS/AA/D/wgs.AADN"; - const string gis_in_wgs_results = "data/wb1206.gis.txt"; - vector gis; - SeqDB_ReadGiList(gis_in_wgs_results, gis); - gis.erase(gis.begin()+10, gis.end()); - - CAutoEnvironmentVariable env_var("WGS_GILIST_DIR", "data"); - CWgsDbTrimmer trimmer(wgs_dbs); - ITERATE(vector, gi, gis) { - trimmer.AddGi(*gi); - } - const string kExpectedResult = "WGS/AB/D/wgs.ABDC"; - const string kActualResult = trimmer.GetDbList(); - BOOST_REQUIRE_EQUAL(kExpectedResult, kActualResult); -} - -// In this test case, all GIs are in 1 database, so the other one is removed, -// but there's also a non-WGS BLAST DB for which we have no GI lists (which -// should be kept -BOOST_AUTO_TEST_CASE(CWgsTrimmerShortExampleWithNtRemove) -{ - const string wgs_dbs = "nt WGS/AB/D/wgs.ABDC WGS/AA/D/wgs.AADN"; - const string gis_in_wgs_results = "data/wb1206.gis.txt"; - vector gis; - SeqDB_ReadGiList(gis_in_wgs_results, gis); - gis.erase(gis.begin()+10, gis.end()); - - CAutoEnvironmentVariable env_var("WGS_GILIST_DIR", "data"); - CWgsDbTrimmer trimmer(wgs_dbs); - ITERATE(vector, gi, gis) { - trimmer.AddGi(*gi); - } - const string kExpectedResult = "WGS/AB/D/wgs.ABDC nt"; - const string kActualResult = trimmer.GetDbList(); - BOOST_REQUIRE_EQUAL(kExpectedResult, kActualResult); -} - -// Auxiliary function for CWgsTrimmerLongExample -static string s_ReadWgsDbs(const char* fname) -{ - ifstream in(fname); - if (!in) { - return kEmptyStr; - } - string line, retval; - while (getline(in, line)) { - retval += NStr::TruncateSpaces(line); - } - return NStr::TruncateSpaces(retval); -} -// In this case, none of the WGS BLAST DBs have GI lists, so we don't trim the -// WGS BLAST DB list, as we don't have enough information to do this safely. -BOOST_AUTO_TEST_CASE(CWgsTrimmerLongExample) -{ - const string wgs_dbs = s_ReadWgsDbs("data/wgs_dblist.txt"); - const string gis_in_wgs_results = "data/wb1206.long.gis.txt"; - //const string wgs_dbs = s_ReadWgsDbs("dbs.txt"); - //const string gis_in_wgs_results = "gis.out"; - vector tokens; - NStr::Split(wgs_dbs, " ", tokens, NStr::fSplit_NoMergeDelims); - const int orig_num_dbs = tokens.size(); - tokens.clear(); - - vector gis; - SeqDB_ReadGiList(gis_in_wgs_results, gis); - - CAutoEnvironmentVariable env_var("WGS_GILIST_DIR", "data"); - CWgsDbTrimmer trimmer(wgs_dbs); - ITERATE(vector, gi, gis) { - trimmer.AddGi(*gi); - } - - const int kExpectedNumDbs = 7511; - //const string kExpectedResult = wgs_dbs; - const string kExpectedResult = trimmer.GetDbList(); - const string kActualResult = trimmer.GetDbList(); - NStr::Split(kActualResult, " ", tokens, NStr::fSplit_NoMergeDelims); - const int actual_num_dbs = tokens.size(); - BOOST_CHECK_EQUAL(kExpectedNumDbs, actual_num_dbs); - BOOST_CHECK_GE(orig_num_dbs, actual_num_dbs); - - BOOST_REQUIRE_EQUAL(kExpectedResult, kActualResult); -} - BOOST_AUTO_TEST_CASE(MultiTaxidBlastDefLine) { CBlast_def_line bdl; @@ -4433,7 +4333,6 @@ BOOST_AUTO_TEST_CASE(CSeqDBIsam_32bit_GI) // Open database for reading. CSeqDBAtlas atlas(true); - CSeqDBLockHold lock(atlas); CRef rdb( new CSeqDBIsam( atlas, @@ -4461,7 +4360,7 @@ BOOST_AUTO_TEST_CASE(CSeqDBIsam_32bit_GI) new CSeq_id(CSeq_id::e_Gi, GI_TO(TIntId, gi)) ); int oid; - rdb->IdToOid(GI_TO(long, seqid->GetGi()), oid, lock); + rdb->IdToOid(GI_TO(long, seqid->GetGi()), oid); BOOST_REQUIRE(oid == oids[i]); } catch (...) { BOOST_FAIL("CSeq_id constructor threw exception"); diff --git a/c++/src/algo/blast/unit_tests/seqdb_reader/seqdb_unit_test.ini b/c++/src/algo/blast/unit_tests/seqdb_reader/seqdb_unit_test.ini index b4ed4aab..67b8852e 100644 --- a/c++/src/algo/blast/unit_tests/seqdb_reader/seqdb_unit_test.ini +++ b/c++/src/algo/blast/unit_tests/seqdb_reader/seqdb_unit_test.ini @@ -1,4 +1,4 @@ -; $Id: seqdb_unit_test.ini 520559 2016-11-29 19:17:28Z ivanov $ +; $Id: seqdb_unit_test.ini 536658 2017-05-22 15:48:20Z zaretska $ [UNITTESTS_DISABLE] ; TestOidNotFoundWithUserAliasFileAndGiList = true @@ -8,13 +8,9 @@ ; PdbIdWithChain = true ; Temporarily disable due to wgs transition -GlobalMemoryBound = true DeltaSequenceHash = true FilteredHeaders = OS_Windows && PLATFORM_Bits32 -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; FIXME: this is a temporary workaround for SB-1826 -OidAndGiLists=true -NrAndSwissProt=true -NegativeListNr=true +; Temporarily disable due to data problem +TwoGiListsOneVolume = true diff --git a/c++/src/algo/dustmask/CMakeLists.txt b/c++/src/algo/dustmask/CMakeLists.txt new file mode 100644 index 00000000..519c1982 --- /dev/null +++ b/c++/src/algo/dustmask/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xalgodustmask.lib.txt) + diff --git a/c++/src/algo/dustmask/CMakeLists.xalgodustmask.lib.txt b/c++/src/algo/dustmask/CMakeLists.xalgodustmask.lib.txt new file mode 100644 index 00000000..b4cb9a4b --- /dev/null +++ b/c++/src/algo/dustmask/CMakeLists.xalgodustmask.lib.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/dustmask/Makefile.xalgodustmask.lib +# +add_library(xalgodustmask + symdust +) +add_dependencies(xalgodustmask + seqset +) + +target_link_libraries(xalgodustmask + xobjmgr +) diff --git a/c++/src/algo/segmask/CMakeLists.txt b/c++/src/algo/segmask/CMakeLists.txt new file mode 100644 index 00000000..5072f618 --- /dev/null +++ b/c++/src/algo/segmask/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xalgosegmask.lib.txt) + diff --git a/c++/src/algo/segmask/CMakeLists.xalgosegmask.lib.txt b/c++/src/algo/segmask/CMakeLists.xalgosegmask.lib.txt new file mode 100644 index 00000000..fe751de7 --- /dev/null +++ b/c++/src/algo/segmask/CMakeLists.xalgosegmask.lib.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/segmask/Makefile.xalgosegmask.lib +# +add_library(xalgosegmask + segmask +) +add_dependencies(xalgosegmask + seqset +) + +target_link_libraries(xalgosegmask + blast xobjmgr +) diff --git a/c++/src/algo/winmask/CMakeLists.txt b/c++/src/algo/winmask/CMakeLists.txt new file mode 100644 index 00000000..33aebc24 --- /dev/null +++ b/c++/src/algo/winmask/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xalgowinmask.lib.txt) + diff --git a/c++/src/algo/winmask/CMakeLists.xalgowinmask.lib.txt b/c++/src/algo/winmask/CMakeLists.xalgowinmask.lib.txt new file mode 100644 index 00000000..dea44bbe --- /dev/null +++ b/c++/src/algo/winmask/CMakeLists.xalgowinmask.lib.txt @@ -0,0 +1,23 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/algo/winmask/Makefile.xalgowinmask.lib +# +add_library(xalgowinmask + seq_masker seq_masker_score_mean seq_masker_score_mean_glob + seq_masker_score_min seq_masker_util seq_masker_window + seq_masker_window_ambig seq_masker_window_pattern + seq_masker_window_pattern_ambig seq_masker_ostat_factory + seq_masker_ostat seq_masker_ostat_ascii seq_masker_istat_ascii + seq_masker_uset_simple seq_masker_istat_factory seq_masker_ostat_bin + seq_masker_uset_array seq_masker_istat_bin seq_masker_ostat_opt + seq_masker_ostat_opt_ascii seq_masker_uset_hash seq_masker_istat_oascii + seq_masker_ostat_opt_bin seq_masker_istat_obinary seq_masker_cache_boost + win_mask_counts_converter win_mask_dup_table win_mask_gen_counts + win_mask_util win_mask_config seq_masker_istat +) +add_dependencies(xalgowinmask + seqset +) + +target_link_libraries(xalgowinmask + seqmasks_io +) diff --git a/c++/src/app/CMakeLists.txt b/c++/src/app/CMakeLists.txt new file mode 100644 index 00000000..98e8c311 --- /dev/null +++ b/c++/src/app/CMakeLists.txt @@ -0,0 +1,54 @@ +############################################################################## +# CMakeLists.txt autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake/src/app/Makefile.in +# + +# Include projects from this directory + +# Recurse subdirectories +add_subdirectory_optional(agp_validate) +add_subdirectory_optional(agpconvert) +add_subdirectory_optional(annotwriter) +add_subdirectory_optional(asn2asn) +add_subdirectory_optional(asn2fasta) +add_subdirectory_optional(asn2flat) +add_subdirectory_optional(asn_cache) +add_subdirectory_optional(asn_cleanup) +add_subdirectory_optional(asnval) +add_subdirectory_optional(bdb_env_keeper) +add_subdirectory_optional(biosample_chk) +add_subdirectory_optional(blast) +add_subdirectory_optional(blastdb) +add_subdirectory_optional(compart) +add_subdirectory_optional(convert_seq) +add_subdirectory_optional(discrepancy_report) +add_subdirectory_optional(dustmasker) +add_subdirectory_optional(formatguess) +add_subdirectory_optional(gap_stats) +add_subdirectory_optional(gi2taxid) +add_subdirectory_optional(grid) +add_subdirectory_optional(hfilter) +add_subdirectory_optional(id1_fetch) +add_subdirectory_optional(id2_fetch) +add_subdirectory_optional(idfetch) +add_subdirectory_optional(idmapper) +add_subdirectory_optional(igblast) +add_subdirectory_optional(lds2_indexer) +add_subdirectory_optional(multireader) +add_subdirectory_optional(ncbi_encrypt) +add_subdirectory_optional(netschedule) +add_subdirectory_optional(netstorage) +add_subdirectory_optional(nmer_repeats) +add_subdirectory_optional(nw_aligner) +add_subdirectory_optional(objextract) +add_subdirectory_optional(objmgr) +add_subdirectory_optional(read_blast_result) +add_subdirectory_optional(segmasker) +add_subdirectory_optional(speedtest) +add_subdirectory_optional(splign) +add_subdirectory_optional(srcchk) +add_subdirectory_optional(ssub_fork) +add_subdirectory_optional(streamtest) +add_subdirectory_optional(table2asn) +add_subdirectory_optional(tableval) +add_subdirectory_optional(vecscreen) +add_subdirectory_optional(winmasker) diff --git a/c++/src/app/Makefile.in b/c++/src/app/Makefile.in index fb347bb3..c1e4e311 100644 --- a/c++/src/app/Makefile.in +++ b/c++/src/app/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in 507812 2016-07-21 17:53:16Z boratyng $ +# $Id: Makefile.in 532504 2017-04-05 18:39:45Z dobronad $ # Miscellaneous applications ################################# @@ -12,7 +12,8 @@ SUB_PROJ = asn2asn asn2fasta asn2flat asnval asn_cleanup \ multireader read_blast_result splign hfilter \ annotwriter compart streamtest lds2_indexer \ discrepancy_report biosample_chk gap_stats table2asn \ - srcchk tableval ncbi_encrypt ssub_fork asn_cache magicblast + srcchk tableval ncbi_encrypt ssub_fork asn_cache magicblast \ + pub_report prot_match gff_deconcat sub_fuse EXPENDABLE_SUB_PROJ = split_cache wig2table netcache rmblastn dblb tls idfetch diff --git a/c++/src/app/blast/CMakeLists.blast_app_util.lib.txt b/c++/src/app/blast/CMakeLists.blast_app_util.lib.txt new file mode 100644 index 00000000..97b6657d --- /dev/null +++ b/c++/src/app/blast/CMakeLists.blast_app_util.lib.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.blast_app_util.lib +# +add_library(blast_app_util + blast_app_util +) +add_dependencies(blast_app_util + blastdb xnetblast +) + +target_link_libraries(blast_app_util + blastinput xblastformat +) diff --git a/c++/src/app/blast/CMakeLists.blast_formatter.app.txt b/c++/src/app/blast/CMakeLists.blast_formatter.app.txt new file mode 100644 index 00000000..94821ba3 --- /dev/null +++ b/c++/src/app/blast/CMakeLists.blast_formatter.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.blast_formatter.app +# +add_executable(blast_formatter-app + blast_formatter +) + +set_target_properties(blast_formatter-app PROPERTIES OUTPUT_NAME blast_formatter) + +target_link_libraries(blast_formatter-app + blast_app_util +) + diff --git a/c++/src/app/blast/CMakeLists.blastn.app.txt b/c++/src/app/blast/CMakeLists.blastn.app.txt new file mode 100644 index 00000000..9919c04c --- /dev/null +++ b/c++/src/app/blast/CMakeLists.blastn.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.blastn.app +# +add_executable(blastn-app + blastn_app +) + +set_target_properties(blastn-app PROPERTIES OUTPUT_NAME blastn) + +target_link_libraries(blastn-app + blast_app_util +) + diff --git a/c++/src/app/blast/CMakeLists.blastp.app.txt b/c++/src/app/blast/CMakeLists.blastp.app.txt new file mode 100644 index 00000000..b93d8aec --- /dev/null +++ b/c++/src/app/blast/CMakeLists.blastp.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.blastp.app +# +add_executable(blastp-app + blastp_app +) + +set_target_properties(blastp-app PROPERTIES OUTPUT_NAME blastp) + +target_link_libraries(blastp-app + blast_app_util +) + diff --git a/c++/src/app/blast/CMakeLists.blastx.app.txt b/c++/src/app/blast/CMakeLists.blastx.app.txt new file mode 100644 index 00000000..dfdc4678 --- /dev/null +++ b/c++/src/app/blast/CMakeLists.blastx.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.blastx.app +# +add_executable(blastx-app + blastx_app +) + +set_target_properties(blastx-app PROPERTIES OUTPUT_NAME blastx) + +target_link_libraries(blastx-app + blast_app_util +) + diff --git a/c++/src/app/blast/CMakeLists.deltablast.app.txt b/c++/src/app/blast/CMakeLists.deltablast.app.txt new file mode 100644 index 00000000..11902008 --- /dev/null +++ b/c++/src/app/blast/CMakeLists.deltablast.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.deltablast.app +# +add_executable(deltablast-app + deltablast_app +) + +set_target_properties(deltablast-app PROPERTIES OUTPUT_NAME deltablast) + +target_link_libraries(deltablast-app + blast_app_util +) + diff --git a/c++/src/app/blast/CMakeLists.legacy_blast.txt b/c++/src/app/blast/CMakeLists.legacy_blast.txt new file mode 100644 index 00000000..f4af026b --- /dev/null +++ b/c++/src/app/blast/CMakeLists.legacy_blast.txt @@ -0,0 +1,7 @@ +set(SCRIPT_NAME legacy_blast.pl) + +add_custom_command(OUTPUT ${EXECUTABLE_OUTPUT_PATH}/${SCRIPT_NAME} + COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/${SCRIPT_NAME} ${EXECUTABLE_OUTPUT_PATH} +) + +add_custom_target(legacy_blast.pl ALL DEPENDS ${EXECUTABLE_OUTPUT_PATH}/${SCRIPT_NAME}) diff --git a/c++/src/app/blast/CMakeLists.psiblast.app.txt b/c++/src/app/blast/CMakeLists.psiblast.app.txt new file mode 100644 index 00000000..3ee52b4a --- /dev/null +++ b/c++/src/app/blast/CMakeLists.psiblast.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.psiblast.app +# +add_executable(psiblast-app + psiblast_app +) + +set_target_properties(psiblast-app PROPERTIES OUTPUT_NAME psiblast) + +target_link_libraries(psiblast-app + blast_app_util +) + diff --git a/c++/src/app/blast/CMakeLists.rpsblast.app.txt b/c++/src/app/blast/CMakeLists.rpsblast.app.txt new file mode 100644 index 00000000..3b556050 --- /dev/null +++ b/c++/src/app/blast/CMakeLists.rpsblast.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.rpsblast.app +# +add_executable(rpsblast-app + rpsblast_app +) + +set_target_properties(rpsblast-app PROPERTIES OUTPUT_NAME rpsblast) + +target_link_libraries(rpsblast-app + blast_app_util +) + diff --git a/c++/src/app/blast/CMakeLists.rpstblastn.app.txt b/c++/src/app/blast/CMakeLists.rpstblastn.app.txt new file mode 100644 index 00000000..fe96d510 --- /dev/null +++ b/c++/src/app/blast/CMakeLists.rpstblastn.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.rpstblastn.app +# +add_executable(rpstblastn-app + rpstblastn_app +) + +set_target_properties(rpstblastn-app PROPERTIES OUTPUT_NAME rpstblastn) + +target_link_libraries(rpstblastn-app + blast_app_util +) + diff --git a/c++/src/app/blast/CMakeLists.seedtop.app.txt b/c++/src/app/blast/CMakeLists.seedtop.app.txt new file mode 100644 index 00000000..2b684e4d --- /dev/null +++ b/c++/src/app/blast/CMakeLists.seedtop.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.seedtop.app +# +add_executable(seedtop-app + seedtop_app +) + +set_target_properties(seedtop-app PROPERTIES OUTPUT_NAME seedtop) + +target_link_libraries(seedtop-app + blast_app_util +) + diff --git a/c++/src/app/blast/CMakeLists.tblastn.app.txt b/c++/src/app/blast/CMakeLists.tblastn.app.txt new file mode 100644 index 00000000..bfb6fc94 --- /dev/null +++ b/c++/src/app/blast/CMakeLists.tblastn.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.tblastn.app +# +add_executable(tblastn-app + tblastn_app +) + +set_target_properties(tblastn-app PROPERTIES OUTPUT_NAME tblastn) + +target_link_libraries(tblastn-app + blast_app_util +) + diff --git a/c++/src/app/blast/CMakeLists.tblastx.app.txt b/c++/src/app/blast/CMakeLists.tblastx.app.txt new file mode 100644 index 00000000..9de69971 --- /dev/null +++ b/c++/src/app/blast/CMakeLists.tblastx.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blast/Makefile.tblastx.app +# +add_executable(tblastx-app + tblastx_app +) + +set_target_properties(tblastx-app PROPERTIES OUTPUT_NAME tblastx) + +target_link_libraries(tblastx-app + blast_app_util +) + diff --git a/c++/src/app/blast/CMakeLists.txt b/c++/src/app/blast/CMakeLists.txt new file mode 100644 index 00000000..7e47b514 --- /dev/null +++ b/c++/src/app/blast/CMakeLists.txt @@ -0,0 +1,19 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.blast_app_util.lib.txt) +include(CMakeLists.blastp.app.txt) +include(CMakeLists.blastn.app.txt) +include(CMakeLists.blastx.app.txt) +include(CMakeLists.tblastn.app.txt) +include(CMakeLists.tblastx.app.txt) +include(CMakeLists.psiblast.app.txt) +include(CMakeLists.rpsblast.app.txt) +include(CMakeLists.rpstblastn.app.txt) +include(CMakeLists.blast_formatter.app.txt) +include(CMakeLists.deltablast.app.txt) +include(CMakeLists.seedtop.app.txt) +include(CMakeLists.legacy_blast.txt) +include(CMakeLists.update_blastdb.txt) diff --git a/c++/src/app/blast/CMakeLists.update_blastdb.txt b/c++/src/app/blast/CMakeLists.update_blastdb.txt new file mode 100644 index 00000000..87232c34 --- /dev/null +++ b/c++/src/app/blast/CMakeLists.update_blastdb.txt @@ -0,0 +1,8 @@ +set(SCRIPT_NAME update_blastdb.pl) + +add_custom_command(OUTPUT ${EXECUTABLE_OUTPUT_PATH}/${SCRIPT_NAME} + COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/${SCRIPT_NAME} ${EXECUTABLE_OUTPUT_PATH} +) + +add_custom_target(update_blastdb.pl ALL DEPENDS ${EXECUTABLE_OUTPUT_PATH}/${SCRIPT_NAME}) + diff --git a/c++/src/app/blast/Makefile.blast_formatter.app b/c++/src/app/blast/Makefile.blast_formatter.app index 214e433a..440fedae 100644 --- a/c++/src/app/blast/Makefile.blast_formatter.app +++ b/c++/src/app/blast/Makefile.blast_formatter.app @@ -2,7 +2,7 @@ WATCHERS = camacho madden fongah2 APP = blast_formatter SRC = blast_formatter -LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) $(OBJMGR_LIBS) +LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) xregexp $(PCRE_LIB) $(OBJMGR_LIBS) LIB = blast_app_util $(LIB_:%=%$(STATIC)) # De-universalize Mac builds to work around a PPC toolchain limitation diff --git a/c++/src/app/blast/Makefile.blastp.app b/c++/src/app/blast/Makefile.blastp.app index 15383714..87f2a3f1 100644 --- a/c++/src/app/blast/Makefile.blastp.app +++ b/c++/src/app/blast/Makefile.blastp.app @@ -1,10 +1,10 @@ -# $Id: Makefile.blastp.app 457276 2015-01-21 20:17:49Z boratyng $ +# $Id: Makefile.blastp.app 536927 2017-05-24 16:00:07Z ucko $ WATCHERS = camacho madden fongah2 APP = blastp SRC = blastp_app -LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) $(OBJMGR_LIBS) +LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) xregexp $(PCRE_LIB) $(OBJMGR_LIBS) LIB = blast_app_util $(LIB_:%=%$(STATIC)) # De-universalize Mac builds to work around a PPC toolchain limitation diff --git a/c++/src/app/blast/Makefile.blastx.app b/c++/src/app/blast/Makefile.blastx.app index 96402ff7..8af169a0 100644 --- a/c++/src/app/blast/Makefile.blastx.app +++ b/c++/src/app/blast/Makefile.blastx.app @@ -1,10 +1,10 @@ -# $Id: Makefile.blastx.app 457276 2015-01-21 20:17:49Z boratyng $ +# $Id: Makefile.blastx.app 536927 2017-05-24 16:00:07Z ucko $ WATCHERS = camacho madden fongah2 APP = blastx SRC = blastx_app -LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) $(OBJMGR_LIBS) +LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) xregexp $(PCRE_LIB) $(OBJMGR_LIBS) LIB = blast_app_util $(LIB_:%=%$(STATIC)) # De-universalize Mac builds to work around a PPC toolchain limitation diff --git a/c++/src/app/blast/Makefile.deltablast.app b/c++/src/app/blast/Makefile.deltablast.app index 44fc9844..d931a926 100644 --- a/c++/src/app/blast/Makefile.deltablast.app +++ b/c++/src/app/blast/Makefile.deltablast.app @@ -1,7 +1,7 @@ APP = deltablast SRC = deltablast_app -LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) $(OBJMGR_LIBS) +LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) xregexp $(PCRE_LIB) $(OBJMGR_LIBS) LIB = blast_app_util $(LIB_:%=%$(STATIC)) # De-universalize Mac builds to work around a PPC toolchain limitation diff --git a/c++/src/app/blast/Makefile.psiblast.app b/c++/src/app/blast/Makefile.psiblast.app index 3970aa30..aabee09d 100644 --- a/c++/src/app/blast/Makefile.psiblast.app +++ b/c++/src/app/blast/Makefile.psiblast.app @@ -2,7 +2,7 @@ WATCHERS = camacho madden fongah2 APP = psiblast SRC = psiblast_app -LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) $(OBJMGR_LIBS) +LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) xregexp $(PCRE_LIB) $(OBJMGR_LIBS) LIB = blast_app_util $(LIB_:%=%$(STATIC)) # De-universalize Mac builds to work around a PPC toolchain limitation diff --git a/c++/src/app/blast/Makefile.rpsblast.app b/c++/src/app/blast/Makefile.rpsblast.app index 6c19b58c..dad41bb4 100644 --- a/c++/src/app/blast/Makefile.rpsblast.app +++ b/c++/src/app/blast/Makefile.rpsblast.app @@ -2,7 +2,7 @@ WATCHERS = camacho madden fongah2 APP = rpsblast SRC = rpsblast_app -LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) $(OBJMGR_LIBS) +LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) xregexp $(PCRE_LIB) $(OBJMGR_LIBS) LIB = blast_app_util $(LIB_:%=%$(STATIC)) # De-universalize Mac builds to work around a PPC toolchain limitation diff --git a/c++/src/app/blast/Makefile.rpstblastn.app b/c++/src/app/blast/Makefile.rpstblastn.app index c0252bd7..f10ccc41 100644 --- a/c++/src/app/blast/Makefile.rpstblastn.app +++ b/c++/src/app/blast/Makefile.rpstblastn.app @@ -2,7 +2,7 @@ WATCHERS = camacho madden fongah2 APP = rpstblastn SRC = rpstblastn_app -LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) $(OBJMGR_LIBS) +LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) xregexp $(PCRE_LIB) $(OBJMGR_LIBS) LIB = blast_app_util $(LIB_:%=%$(STATIC)) # De-universalize Mac builds to work around a PPC toolchain limitation diff --git a/c++/src/app/blast/Makefile.seedtop.app b/c++/src/app/blast/Makefile.seedtop.app index 9de45491..b28cb80f 100644 --- a/c++/src/app/blast/Makefile.seedtop.app +++ b/c++/src/app/blast/Makefile.seedtop.app @@ -2,7 +2,7 @@ WATCHERS = camacho madden fongah2 APP = seedtop SRC = seedtop_app -LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) $(OBJMGR_LIBS) +LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) xregexp $(PCRE_LIB) $(OBJMGR_LIBS) LIB = blast_app_util $(LIB_:%=%$(STATIC)) # De-universalize Mac builds to work around a PPC toolchain limitation diff --git a/c++/src/app/blast/Makefile.tblastn.app b/c++/src/app/blast/Makefile.tblastn.app index 51d8c857..16ebf63c 100644 --- a/c++/src/app/blast/Makefile.tblastn.app +++ b/c++/src/app/blast/Makefile.tblastn.app @@ -1,10 +1,10 @@ -# $Id: Makefile.tblastn.app 457276 2015-01-21 20:17:49Z boratyng $ +# $Id: Makefile.tblastn.app 536927 2017-05-24 16:00:07Z ucko $ WATCHERS = camacho madden fongah2 APP = tblastn SRC = tblastn_app -LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) $(OBJMGR_LIBS) +LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) xregexp $(PCRE_LIB) $(OBJMGR_LIBS) LIB = blast_app_util $(LIB_:%=%$(STATIC)) # De-universalize Mac builds to work around a PPC toolchain limitation diff --git a/c++/src/app/blast/Makefile.tblastx.app b/c++/src/app/blast/Makefile.tblastx.app index d8f0dd9c..5113f4b7 100644 --- a/c++/src/app/blast/Makefile.tblastx.app +++ b/c++/src/app/blast/Makefile.tblastx.app @@ -1,10 +1,10 @@ -# $Id: Makefile.tblastx.app 457276 2015-01-21 20:17:49Z boratyng $ +# $Id: Makefile.tblastx.app 536927 2017-05-24 16:00:07Z ucko $ WATCHERS = camacho madden fongah2 APP = tblastx SRC = tblastx_app -LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) $(OBJMGR_LIBS) +LIB_ = $(BLAST_INPUT_LIBS) $(BLAST_LIBS) xregexp $(PCRE_LIB) $(OBJMGR_LIBS) LIB = blast_app_util $(LIB_:%=%$(STATIC)) # De-universalize Mac builds to work around a PPC toolchain limitation diff --git a/c++/src/app/blast/blast_app_util.cpp b/c++/src/app/blast/blast_app_util.cpp index 0b348992..392720db 100644 --- a/c++/src/app/blast/blast_app_util.cpp +++ b/c++/src/app/blast/blast_app_util.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_app_util.cpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: blast_app_util.cpp 509107 2016-08-03 14:09:45Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/app/blast/blast_app_util.hpp b/c++/src/app/blast/blast_app_util.hpp index 59c6881d..3743a3dc 100644 --- a/c++/src/app/blast/blast_app_util.hpp +++ b/c++/src/app/blast/blast_app_util.hpp @@ -1,4 +1,4 @@ -/* $Id: blast_app_util.hpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: blast_app_util.hpp 527685 2017-02-15 14:00:17Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -132,11 +132,6 @@ InitializeSubject(CRef db_args, blast::SDataLoaderConfig InitializeQueryDataLoaderConfiguration(bool query_is_protein, CRef db_adapter); -/// Create a CSeqDB object from the command line arguments provided -/// @param db_args BLAST database arguments [in] -/// @throw CSeqDBException in case of not being able to properly build a CSeqDB -/// object -CRef GetSeqDB(CRef db_args); /// Register the BLAST database data loader using the already initialized /// CSeqDB object diff --git a/c++/src/app/blast/blast_formatter.cpp b/c++/src/app/blast/blast_formatter.cpp index 2d093722..4a279887 100644 --- a/c++/src/app/blast/blast_formatter.cpp +++ b/c++/src/app/blast/blast_formatter.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_formatter.cpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: blast_formatter.cpp 509107 2016-08-03 14:09:45Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/app/blast/blastn_app.cpp b/c++/src/app/blast/blastn_app.cpp index 08d4fd63..eada6d9e 100644 --- a/c++/src/app/blast/blastn_app.cpp +++ b/c++/src/app/blast/blastn_app.cpp @@ -1,4 +1,4 @@ -/* $Id: blastn_app.cpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: blastn_app.cpp 529178 2017-03-01 19:10:55Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -71,9 +71,7 @@ void CBlastnApp::Init() // formulate command line arguments m_CmdLineArgs.Reset(new CBlastnAppArgs()); - // read the command line - HideStdArgs(fHideLogfile | fHideConffile | fHideFullVersion | fHideXmlHelp | fHideDryRun); SetupArgDescriptions(m_CmdLineArgs->SetCommandLine()); } diff --git a/c++/src/app/blast/blastp_app.cpp b/c++/src/app/blast/blastp_app.cpp index 6251d9a7..366036c3 100644 --- a/c++/src/app/blast/blastp_app.cpp +++ b/c++/src/app/blast/blastp_app.cpp @@ -1,4 +1,4 @@ -/* $Id: blastp_app.cpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: blastp_app.cpp 529178 2017-03-01 19:10:55Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -71,9 +71,7 @@ void CBlastpApp::Init() // formulate command line arguments m_CmdLineArgs.Reset(new CBlastpAppArgs()); - // read the command line - HideStdArgs(fHideLogfile | fHideConffile | fHideFullVersion | fHideXmlHelp | fHideDryRun); SetupArgDescriptions(m_CmdLineArgs->SetCommandLine()); } diff --git a/c++/src/app/blast/blastx_app.cpp b/c++/src/app/blast/blastx_app.cpp index 2e9fcca4..8e0e1d51 100644 --- a/c++/src/app/blast/blastx_app.cpp +++ b/c++/src/app/blast/blastx_app.cpp @@ -1,4 +1,4 @@ -/* $Id: blastx_app.cpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: blastx_app.cpp 509107 2016-08-03 14:09:45Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/app/blast/deltablast_app.cpp b/c++/src/app/blast/deltablast_app.cpp index 1162ea42..88e43192 100644 --- a/c++/src/app/blast/deltablast_app.cpp +++ b/c++/src/app/blast/deltablast_app.cpp @@ -1,4 +1,4 @@ -/* $Id: deltablast_app.cpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: deltablast_app.cpp 509107 2016-08-03 14:09:45Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/app/blast/psiblast_app.cpp b/c++/src/app/blast/psiblast_app.cpp index c4dde7d6..17084724 100644 --- a/c++/src/app/blast/psiblast_app.cpp +++ b/c++/src/app/blast/psiblast_app.cpp @@ -1,4 +1,4 @@ -/* $Id: psiblast_app.cpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: psiblast_app.cpp 509107 2016-08-03 14:09:45Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/app/blast/rpsblast_app.cpp b/c++/src/app/blast/rpsblast_app.cpp index b2f7a5cd..32a44717 100644 --- a/c++/src/app/blast/rpsblast_app.cpp +++ b/c++/src/app/blast/rpsblast_app.cpp @@ -1,4 +1,4 @@ -/* $Id: rpsblast_app.cpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: rpsblast_app.cpp 509107 2016-08-03 14:09:45Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/app/blast/rpstblastn_app.cpp b/c++/src/app/blast/rpstblastn_app.cpp index 1586abd3..d891c82f 100644 --- a/c++/src/app/blast/rpstblastn_app.cpp +++ b/c++/src/app/blast/rpstblastn_app.cpp @@ -1,4 +1,4 @@ -/* $Id: rpstblastn_app.cpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: rpstblastn_app.cpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -86,10 +86,6 @@ int CRPSTBlastnApp::Run(void) CBlastAppDiagHandler bah; try { - // Limit the amount of memory used by CSeqDB so that the RPS-BLAST - // files not managed by it can be opened without problems - CSeqDB::SetDefaultMemoryBound(200000000); - // Allow the fasta reader to complain on invalid sequence input SetDiagPostLevel(eDiag_Warning); SetDiagPostPrefix("rpstblastn"); diff --git a/c++/src/app/blast/tblastn_app.cpp b/c++/src/app/blast/tblastn_app.cpp index d163d190..929cb3a2 100644 --- a/c++/src/app/blast/tblastn_app.cpp +++ b/c++/src/app/blast/tblastn_app.cpp @@ -1,4 +1,4 @@ -/* $Id: tblastn_app.cpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: tblastn_app.cpp 509107 2016-08-03 14:09:45Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/app/blast/tblastx_app.cpp b/c++/src/app/blast/tblastx_app.cpp index 91af1530..6959528f 100644 --- a/c++/src/app/blast/tblastx_app.cpp +++ b/c++/src/app/blast/tblastx_app.cpp @@ -1,4 +1,4 @@ -/* $Id: tblastx_app.cpp 509280 2016-08-04 16:03:11Z ivanov $ +/* $Id: tblastx_app.cpp 509107 2016-08-03 14:09:45Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/app/blastdb/CMakeLists.blastdb_aliastool.app.txt b/c++/src/app/blastdb/CMakeLists.blastdb_aliastool.app.txt new file mode 100644 index 00000000..20ae1911 --- /dev/null +++ b/c++/src/app/blastdb/CMakeLists.blastdb_aliastool.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blastdb/Makefile.blastdb_aliastool.app +# +add_executable(blastdb_aliastool-app + blastdb_aliastool +) + +set_target_properties(blastdb_aliastool-app PROPERTIES OUTPUT_NAME blastdb_aliastool) + +target_link_libraries(blastdb_aliastool-app + blastinput writedb +) + diff --git a/c++/src/app/blastdb/CMakeLists.blastdbcheck.app.txt b/c++/src/app/blastdb/CMakeLists.blastdbcheck.app.txt new file mode 100644 index 00000000..16cc6fa6 --- /dev/null +++ b/c++/src/app/blastdb/CMakeLists.blastdbcheck.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blastdb/Makefile.blastdbcheck.app +# +add_executable(blastdbcheck-app + blastdbcheck +) + +set_target_properties(blastdbcheck-app PROPERTIES OUTPUT_NAME blastdbcheck) + +target_link_libraries(blastdbcheck-app + align_format xblast +) + diff --git a/c++/src/app/blastdb/CMakeLists.blastdbcmd.app.txt b/c++/src/app/blastdb/CMakeLists.blastdbcmd.app.txt new file mode 100644 index 00000000..a7e85fd9 --- /dev/null +++ b/c++/src/app/blastdb/CMakeLists.blastdbcmd.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blastdb/Makefile.blastdbcmd.app +# +add_executable(blastdbcmd-app + blastdbcmd +) + +set_target_properties(blastdbcmd-app PROPERTIES OUTPUT_NAME blastdbcmd) + +target_link_libraries(blastdbcmd-app + blastdb_format blastinput +) + diff --git a/c++/src/app/blastdb/CMakeLists.blastdbcp.app.txt b/c++/src/app/blastdb/CMakeLists.blastdbcp.app.txt new file mode 100644 index 00000000..0c3e0742 --- /dev/null +++ b/c++/src/app/blastdb/CMakeLists.blastdbcp.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blastdb/Makefile.blastdbcp.app +# +add_executable(blastdbcp-app + blastdbcp +) + +set_target_properties(blastdbcp-app PROPERTIES OUTPUT_NAME blastdbcp) + +target_link_libraries(blastdbcp-app + blastinput writedb +) + diff --git a/c++/src/app/blastdb/CMakeLists.convert2blastmask.app.txt b/c++/src/app/blastdb/CMakeLists.convert2blastmask.app.txt new file mode 100644 index 00000000..50163a18 --- /dev/null +++ b/c++/src/app/blastdb/CMakeLists.convert2blastmask.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blastdb/Makefile.convert2blastmask.app +# +add_executable(convert2blastmask-app + convert2blastmask +) + +set_target_properties(convert2blastmask-app PROPERTIES OUTPUT_NAME convert2blastmask) + +target_link_libraries(convert2blastmask-app + blast seqmasks_io +) + diff --git a/c++/src/app/blastdb/CMakeLists.makeblastdb.app.txt b/c++/src/app/blastdb/CMakeLists.makeblastdb.app.txt new file mode 100644 index 00000000..4437368a --- /dev/null +++ b/c++/src/app/blastdb/CMakeLists.makeblastdb.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blastdb/Makefile.makeblastdb.app +# +add_executable(makeblastdb-app + makeblastdb masked_range_set +) + +set_target_properties(makeblastdb-app PROPERTIES OUTPUT_NAME makeblastdb) + +target_link_libraries(makeblastdb-app + blastinput writedb +) + diff --git a/c++/src/app/blastdb/CMakeLists.makeprofiledb.app.txt b/c++/src/app/blastdb/CMakeLists.makeprofiledb.app.txt new file mode 100644 index 00000000..6fc16e05 --- /dev/null +++ b/c++/src/app/blastdb/CMakeLists.makeprofiledb.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/blastdb/Makefile.makeprofiledb.app +# +add_executable(makeprofiledb-app + makeprofiledb +) + +set_target_properties(makeprofiledb-app PROPERTIES OUTPUT_NAME makeprofiledb) + +target_link_libraries(makeprofiledb-app + blastinput writedb +) + diff --git a/c++/src/app/blastdb/CMakeLists.txt b/c++/src/app/blastdb/CMakeLists.txt new file mode 100644 index 00000000..0f0e5fa0 --- /dev/null +++ b/c++/src/app/blastdb/CMakeLists.txt @@ -0,0 +1,13 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.blastdbcmd.app.txt) +include(CMakeLists.makeblastdb.app.txt) +include(CMakeLists.blastdb_aliastool.app.txt) +include(CMakeLists.blastdbcheck.app.txt) +include(CMakeLists.convert2blastmask.app.txt) +include(CMakeLists.blastdbcp.app.txt) +include(CMakeLists.makeprofiledb.app.txt) + diff --git a/c++/src/app/blastdb/blastdb_aliastool.cpp b/c++/src/app/blastdb/blastdb_aliastool.cpp index 5827a7bc..2bd93eee 100644 --- a/c++/src/app/blastdb/blastdb_aliastool.cpp +++ b/c++/src/app/blastdb/blastdb_aliastool.cpp @@ -1,4 +1,4 @@ -/* $Id: blastdb_aliastool.cpp 519975 2016-11-21 18:09:00Z ivanov $ +/* $Id: blastdb_aliastool.cpp 521686 2016-12-12 19:34:10Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -358,7 +358,7 @@ CBlastDBAliasApp::CreateAliasFile() const args[kArgDb].AsString(), seq_type, gilist, title, alias_type); - } else { + } else if (args[kArgDb].HasValue()) { CWriteDB_CreateAliasFile(args[kOutput].AsString(), args[kArgDb].AsString(), seq_type, seqid_list, diff --git a/c++/src/app/blastdb/blastdbcheck.cpp b/c++/src/app/blastdb/blastdbcheck.cpp index 802b7c25..88097a79 100644 --- a/c++/src/app/blastdb/blastdbcheck.cpp +++ b/c++/src/app/blastdb/blastdbcheck.cpp @@ -1,4 +1,4 @@ -/* $Id: blastdbcheck.cpp 492284 2016-02-16 16:55:37Z camacho $ +/* $Id: blastdbcheck.cpp 539176 2017-06-19 17:06:50Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -717,7 +717,7 @@ public: if (NStr::IsBlank(*line)) continue; // ignore empty lines vector tokens; - NStr::Tokenize(*line, " \t\n\r", tokens, NStr::eMergeDelims); + NStr::Split(*line, " \t\n\r", tokens, NStr::fSplit_Tokenize); if (tokens.size() <= 1) { Log(name, e_Brief) << " [ERROR] no value(s) found for keyword " @@ -938,7 +938,7 @@ bool CDbTest::Test(CTestActionList & action) int tot_faults = 0; vector dbs; - NStr::Tokenize(m_Db, " ", dbs, NStr::eMergeDelims); + NStr::Split(m_Db, " ", dbs, NStr::fSplit_Tokenize); CSeqDB::ESeqType seqtype = ParseMoleculeTypeString(m_DbType); @@ -1022,7 +1022,6 @@ public: bool recurse) : CTestData(outp, dbtype), m_Dir (dir), - m_Threads (threads), m_Recurse (recurse) { } virtual bool Test(CTestActionList & action); @@ -1031,7 +1030,6 @@ private: string m_Dir; vector m_DBs; - int m_Threads; bool m_Recurse; int x_GetVolumeList(CSeqDB::ESeqType stype, set &vlist, set &alist) const; diff --git a/c++/src/app/blastdb/blastdbcmd.cpp b/c++/src/app/blastdb/blastdbcmd.cpp index 282c0eef..da02e85d 100644 --- a/c++/src/app/blastdb/blastdbcmd.cpp +++ b/c++/src/app/blastdb/blastdbcmd.cpp @@ -1,4 +1,4 @@ -/* $Id: blastdbcmd.cpp 518486 2016-11-03 16:05:31Z ivanov $ +/* $Id: blastdbcmd.cpp 536284 2017-05-17 12:39:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -247,7 +247,7 @@ CBlastDBCmdApp::x_ProcessBatchEntry(CBlastDB_Formatter & fmt) NcbiGetlineEOL(input, line); if ( !line.empty() ) { vector tmp; - NStr::Split(line, " \t", tmp, NStr::fSplit_MergeDelims); + NStr::Split(line, " \t", tmp, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); if(tmp.empty()) { continue; } diff --git a/c++/src/app/blastdb/blastdbcp.cpp b/c++/src/app/blastdb/blastdbcp.cpp index bf09b926..1eac3fc3 100644 --- a/c++/src/app/blastdb/blastdbcp.cpp +++ b/c++/src/app/blastdb/blastdbcp.cpp @@ -1,4 +1,4 @@ -/* $Id: blastdbcp.cpp 492284 2016-02-16 16:55:37Z camacho $ +/* $Id: blastdbcp.cpp 539176 2017-06-19 17:06:50Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -57,8 +57,6 @@ private: /* Private Methods */ CSeqDB::ESeqType seq_type) const; private: /* Private Data */ - bool m_bCheckOnly; - typedef map TMemBitMap; TMemBitMap m_MembershipMap; @@ -72,8 +70,7 @@ private: /* Private Data */ // Constructor BlastdbCopyApplication::BlastdbCopyApplication() - : m_bCheckOnly(false), - kTargetOnly("target_only"), + : kTargetOnly("target_only"), kMembershipBits("membership_bits"), kCopyOnly("copy_only") { diff --git a/c++/src/app/blastdb/makeblastdb.cpp b/c++/src/app/blastdb/makeblastdb.cpp index 3cac9dba..ded9e270 100644 --- a/c++/src/app/blastdb/makeblastdb.cpp +++ b/c++/src/app/blastdb/makeblastdb.cpp @@ -1,4 +1,4 @@ -/* $Id: makeblastdb.cpp 516397 2016-10-13 12:26:46Z ivanov $ +/* $Id: makeblastdb.cpp 515237 2016-09-29 12:32:30Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/app/blastdb/makeprofiledb.cpp b/c++/src/app/blastdb/makeprofiledb.cpp index 9635f864..db298369 100644 --- a/c++/src/app/blastdb/makeprofiledb.cpp +++ b/c++/src/app/blastdb/makeprofiledb.cpp @@ -1,4 +1,4 @@ -/* $Id: makeprofiledb.cpp 492284 2016-02-16 16:55:37Z camacho $ +/* $Id: makeprofiledb.cpp 536289 2017-05-17 13:09:51Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -521,7 +521,7 @@ vector CMakeProfileDBApp::x_GetSMPFilenames(void) string line; vector tmp; NcbiGetlineEOL(*m_InPssmList, line); - NStr::Split(line, " \t\r", tmp, NStr::eMergeDelims); + NStr::Split(line, " \t\r", tmp, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); if(tmp.size() > 0) filenames.insert(filenames.end(), tmp.begin(), tmp.end() ); diff --git a/c++/src/app/dustmasker/CMakeLists.dustmasker.app.txt b/c++/src/app/dustmasker/CMakeLists.dustmasker.app.txt new file mode 100644 index 00000000..b9bf766c --- /dev/null +++ b/c++/src/app/dustmasker/CMakeLists.dustmasker.app.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/dustmasker/Makefile.dustmasker.app +# +add_executable(dustmasker-app + main dust_mask_app +) + +set_target_properties(dustmasker-app PROPERTIES OUTPUT_NAME dustmasker) + +target_link_libraries(dustmasker-app + seqmasks_io xalgodustmask +) + +add_dependencies(dustmasker-app + seq +) + diff --git a/c++/src/app/dustmasker/CMakeLists.txt b/c++/src/app/dustmasker/CMakeLists.txt new file mode 100644 index 00000000..1f52f9e7 --- /dev/null +++ b/c++/src/app/dustmasker/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.dustmasker.app.txt) + diff --git a/c++/src/app/dustmasker/dust_mask_app.cpp b/c++/src/app/dustmasker/dust_mask_app.cpp index e8aec29e..7a25dd94 100644 --- a/c++/src/app/dustmasker/dust_mask_app.cpp +++ b/c++/src/app/dustmasker/dust_mask_app.cpp @@ -1,4 +1,4 @@ -/* $Id: dust_mask_app.cpp 413106 2013-09-12 14:17:50Z morgulis $ +/* $Id: dust_mask_app.cpp 545435 2017-09-06 17:13:04Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -178,6 +178,90 @@ CMaskReader * CDustMaskApplication::x_GetReader() return 0; } +CSymDustMasker::TMaskList s_FindSegmentWithLongNs(const unsigned int MAX_Ns, objects::CSeqVector & seq) +{ + //Always trim Ns at start and end of seq + CSymDustMasker::TMaskList NsRange; + unsigned int pos = 0; + unsigned int Ns = 0; + for(objects::CSeqVector_CI itr=seq.begin();itr!=seq.end(); ++itr) { + if ((*itr) == 78) { + Ns++; + } + else { + if (Ns > 0) { + if((Ns > MAX_Ns ) || (pos == 0)) { + CSymDustMasker::TMaskedInterval r(pos, pos+Ns-1); + NsRange.push_back(r); + } + pos += Ns; + Ns = 0; + } + pos++; + } + } + + if (Ns > 0) { + CSymDustMasker::TMaskedInterval r(pos, pos+Ns-1); + NsRange.push_back(r); + } + return NsRange; +} + +void s_InsertMerge(CSymDustMasker::TMaskList & list, CSymDustMasker::TMaskedInterval & new_mask, Uint4 linker) +{ + if ((!list.empty()) && (list.back().second + linker == new_mask.first)) { + list.back().second = new_mask.second; + return; + } + + list.push_back(new_mask); +} + +std::auto_ptr< CSymDustMasker::TMaskList > +GetDustMasks_SkipNs(objects::CSeqVector & seq, Uint4 level, Uint4 window, Uint4 linker) +{ + CSymDustMasker duster(level, window, linker); + CSymDustMasker::TMaskList NsRange = s_FindSegmentWithLongNs(window, seq); + + if(NsRange.empty()){ + return duster(seq); + } + std::auto_ptr< CSymDustMasker::TMaskList > rv(new CSymDustMasker::TMaskList); + TSeqPos seq_start =0; + NON_CONST_ITERATE(CSymDustMasker::TMaskList, itr, NsRange) { + if(itr->first == 0) { + seq_start = itr->second + 1; + rv->push_back(*itr); + continue; + } + else { + std::auto_ptr< CSymDustMasker::TMaskList > s_mask = duster(seq, seq_start, itr->first -1); + if(s_mask->size() > 0) { + s_InsertMerge(*rv, s_mask->front(), linker); + if( s_mask->size() > 1) { + rv->insert(rv->end(), ++(s_mask->begin()), s_mask->end()); + } + s_InsertMerge(*rv, *itr, linker); + } + else { + rv->push_back(*itr); + } + seq_start = itr->second + 1; + } + } + if(seq_start < seq.size()){ + std::auto_ptr< CSymDustMasker::TMaskList > s_mask = duster(seq, seq_start, seq.size() -1); + if(s_mask->size() > 0) { + s_InsertMerge(*rv, s_mask->front(), linker); + if( s_mask->size() > 1) { + rv->insert(rv->end(), ++(s_mask->begin()), s_mask->end()); + } + } + } + return rv; +} + //------------------------------------------------------------------------- int CDustMaskApplication::Run (void) { @@ -214,7 +298,7 @@ int CDustMaskApplication::Run (void) CSeqVector data = bsh.GetSeqVector( CBioseq_Handle::eCoding_Iupac ); - std::auto_ptr< duster_type::TMaskList > res = duster( data ); + std::auto_ptr< duster_type::TMaskList > res = GetDustMasks_SkipNs(data, level, window, linker); if (res.get()) { writer->Print(bsh, *res, GetArgs()["parse_seqids"] ); } diff --git a/c++/src/app/segmasker/CMakeLists.segmasker.app.txt b/c++/src/app/segmasker/CMakeLists.segmasker.app.txt new file mode 100644 index 00000000..eaca09c6 --- /dev/null +++ b/c++/src/app/segmasker/CMakeLists.segmasker.app.txt @@ -0,0 +1,18 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/segmasker/Makefile.segmasker.app +# +add_executable(segmasker-app + segmasker +) + +set_target_properties(segmasker-app PROPERTIES OUTPUT_NAME segmasker) + +target_link_libraries(segmasker-app + xobjsimple seqmasks_io xalgosegmask ${BLAST_LIBS} ${OBJMGR_LIBS} + +) + +add_dependencies(segmasker-app + seq +) + diff --git a/c++/src/app/segmasker/CMakeLists.txt b/c++/src/app/segmasker/CMakeLists.txt new file mode 100644 index 00000000..0995c037 --- /dev/null +++ b/c++/src/app/segmasker/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +#include(CMakeLists.segmasker.app.txt) + diff --git a/c++/src/app/winmasker/CMakeLists.txt b/c++/src/app/winmasker/CMakeLists.txt new file mode 100644 index 00000000..f1e92ade --- /dev/null +++ b/c++/src/app/winmasker/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.winmasker.app.txt) +include(CMakeLists.windowmasker_2.2.22_adapter.txt) diff --git a/c++/src/app/winmasker/CMakeLists.windowmasker_2.2.22_adapter.txt b/c++/src/app/winmasker/CMakeLists.windowmasker_2.2.22_adapter.txt new file mode 100644 index 00000000..b7a03a26 --- /dev/null +++ b/c++/src/app/winmasker/CMakeLists.windowmasker_2.2.22_adapter.txt @@ -0,0 +1,8 @@ +set(SCRIPT_NAME windowmasker_2.2.22_adapter.py) + +add_custom_command(OUTPUT ${EXECUTABLE_OUTPUT_PATH}/${SCRIPT_NAME} + COMMAND cp ${CMAKE_CURRENT_SOURCE_DIR}/${SCRIPT_NAME} ${EXECUTABLE_OUTPUT_PATH} +) + +add_custom_target(windowmasker_2.2.22_adapter.py ALL DEPENDS ${EXECUTABLE_OUTPUT_PATH}/${SCRIPT_NAME}) + diff --git a/c++/src/app/winmasker/CMakeLists.winmasker.app.txt b/c++/src/app/winmasker/CMakeLists.winmasker.app.txt new file mode 100644 index 00000000..efb40815 --- /dev/null +++ b/c++/src/app/winmasker/CMakeLists.winmasker.app.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/app/winmasker/Makefile.winmasker.app +# +add_executable(windowmasker-app + main win_mask_app win_mask_sdust_masker +) + +set_target_properties(windowmasker-app PROPERTIES OUTPUT_NAME windowmasker) + +target_link_libraries(windowmasker-app + ncbi_xloader_genbank xalgodustmask xalgowinmask +) + +add_dependencies(windowmasker-app + seq +) + diff --git a/c++/src/app/winmasker/win_mask_sdust_masker.cpp b/c++/src/app/winmasker/win_mask_sdust_masker.cpp index e65ea361..a8f71b22 100644 --- a/c++/src/app/winmasker/win_mask_sdust_masker.cpp +++ b/c++/src/app/winmasker/win_mask_sdust_masker.cpp @@ -1,4 +1,4 @@ -/* $Id: win_mask_sdust_masker.cpp 143045 2008-10-14 19:56:23Z camacho $ +/* $Id: win_mask_sdust_masker.cpp 539176 2017-06-19 17:06:50Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -65,8 +65,7 @@ static inline char iupacna_to_blastna( char c ) //------------------------------------------------------------------------------ CSDustMasker::CSDustMasker( Uint4 arg_window, Uint4 arg_level, Uint4 arg_linker ) -: window( arg_window ), level( arg_level ), linker( arg_linker ), - duster_( arg_level, arg_window, arg_linker ) + : window( arg_window ), duster_( arg_level, arg_window, arg_linker ) {} //------------------------------------------------------------------------------ diff --git a/c++/src/app/winmasker/win_mask_sdust_masker.hpp b/c++/src/app/winmasker/win_mask_sdust_masker.hpp index f1f372d6..3994661d 100644 --- a/c++/src/app/winmasker/win_mask_sdust_masker.hpp +++ b/c++/src/app/winmasker/win_mask_sdust_masker.hpp @@ -1,4 +1,4 @@ -/* $Id: win_mask_sdust_masker.hpp 103491 2007-05-04 17:18:18Z kazimird $ +/* $Id: win_mask_sdust_masker.hpp 539176 2017-06-19 17:06:50Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -85,8 +85,6 @@ public: private: Uint4 window; /**<\internal dust window in base pairs */ - Uint4 level; /**<\internal dust level */ - Uint4 linker; /**<\internal dust linker length in base pairs */ CSymDustMasker duster_; /**<\internal symmetric dust masker */ }; diff --git a/c++/src/build-system/CMakeLists.txt b/c++/src/build-system/CMakeLists.txt new file mode 100644 index 00000000..319a91aa --- /dev/null +++ b/c++/src/build-system/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory + +# Recurse subdirectories +add_subdirectory(project_tree_builder) +#add_subdirectory(helpers) diff --git a/c++/src/build-system/Makefile.app.in b/c++/src/build-system/Makefile.app.in index 27768b04..05224614 100644 --- a/c++/src/build-system/Makefile.app.in +++ b/c++/src/build-system/Makefile.app.in @@ -1,6 +1,6 @@ # -*- makefile-gmake -*- ################################# -# $Id: Makefile.app.in 492189 2016-02-12 20:50:52Z ucko $ +# $Id: Makefile.app.in 537310 2017-05-30 17:03:22Z ucko $ # Author: Denis Vakatov (vakatov@ncbi.nlm.nih.gov) ################################# # This can be used to build/install/clean @@ -53,10 +53,15 @@ ifneq "" "$(wildcard Makefile.$(TMPL).app.libdep)" endif endif -CMD_BASE = $(LINK_WRAPPER) $(LINK) $(LDFLAGS) $(APP_LDFLAGS) $(XOBJ) $(XOBJ2) $(PRE_LIBS) +include $(builddir)/Makefile.$(Rules) + +CMD_BASE = $(LINK_WRAPPER) $(LINK) +CMD_BASEARGS = $(LDFLAGS) $(APP_LDFLAGS) $(XOBJ) $(XOBJ2) $(PRE_LIBS) CMD_TAIL = @f_outexe@$(XAPP) $(LINK_FILTER) -CMD = $(CMD_BASE) $(XLIB) $(XAPP_LIBS) $(CMD_TAIL) -CMD2 = $(CMD_BASE) $(XLIB2) $(XAPP_LIBS2) $(CMD_TAIL) +CMD_ARGS = $(CMD_BASEARGS) $(XLIB) $(XAPP_LIBS) +CMD_ARGS2 = $(CMD_BASEARGS) $(XLIB2) $(XAPP_LIBS2) +CMD = $(CMD_BASE) $(call regroup_runpaths,$(CMD_ARGS)) $(CMD_TAIL) +CMD2 = $(CMD_BASE) $(call regroup_runpaths,$(CMD_ARGS2)) $(CMD_TAIL) ifeq "$(CMD)" "$(CMD2)" OR_CMD2 = @@ -65,8 +70,6 @@ else OR_CMD2 = || (echo $(NOTE); echo $(CMD2); $(CMD2)) endif -include $(builddir)/Makefile.$(Rules) - ASK_REBUILD = \ base=`echo $$l | $(SED) -e 's,.*/\.\([^.]*\)\.dep$$,\1,'`; \ if (cd "$$builddir" && $(MAKE) $(MFLAGS) -q \ diff --git a/c++/src/build-system/Makefile.configurables.real b/c++/src/build-system/Makefile.configurables.real index 8fc2dddc..84dd5121 100644 --- a/c++/src/build-system/Makefile.configurables.real +++ b/c++/src/build-system/Makefile.configurables.real @@ -1,4 +1,4 @@ -# $Id: Makefile.configurables.real 442076 2014-07-30 14:06:45Z ucko $ +# $Id: Makefile.configurables.real 541406 2017-07-18 13:19:21Z ivanov $ ALL_SUB_PROJ = $(SUB_PROJ) $(POTENTIAL_SUB_PROJ) $(EXPENDABLE_SUB_PROJ) LOCAL_CONFIGURABLES = Makefile $(ALL_SUB_PROJ:%=%/Makefile) $(EXTRA_CONFIGURABLES) @@ -10,7 +10,8 @@ COPY = /bin/cp -p # XXX - we have to wildcard under $(builddir) rather than # $(abs_top_srcdir), so explicitly list any new root configurables to # ensure they get picked up properly. -ROOT_CONFIGURABLES = $(builddir)/Makefile* $(builddir)/*.sh +ROOT_CONFIGURABLES = $(builddir)/Makefile* $(builddir)/*.sh \ + $(builddir)/run_with_cd_reporter.py CONFIGURABLES = $(ROOT_CONFIGURABLES) $(LOCAL_CONFIGURABLES) UPDATE_CONFIGURABLE = $(abs_top_srcdir)/scripts/common/impl/update_configurable.sh $(build_root) @@ -47,6 +48,9 @@ $(builddir)/Makefile%: $(build_sys_dir)/Makefile%.in $(config_status) $(builddir)/%.sh: $(build_sys_dir)/%.sh.in $(config_status) $(UPDATE_CONFIGURABLE) $@ +$(builddir)/%.py: $(build_sys_dir)/%.py.in $(config_status) + $(UPDATE_CONFIGURABLE) $@ + $(builddir)/%: $(abs_top_srcdir)/src/%.in $(config_status) $(UPDATE_CONFIGURABLE) $@ diff --git a/c++/src/build-system/Makefile.dll.in b/c++/src/build-system/Makefile.dll.in index 09311755..8d45ac19 100644 --- a/c++/src/build-system/Makefile.dll.in +++ b/c++/src/build-system/Makefile.dll.in @@ -1,6 +1,6 @@ # -*- makefile-gmake -*- ################################# -# $Id: Makefile.dll.in 474937 2015-08-03 15:51:23Z ucko $ +# $Id: Makefile.dll.in 537281 2017-05-30 12:27:12Z ucko $ # Author: Denis Vakatov (vakatov@ncbi.nlm.nih.gov) ################################# # This can be used to build/install/clean @@ -68,8 +68,16 @@ ifneq "" "$(wildcard Makefile.$(TMPL).dll.libdep)" endif endif +ifeq "" "$(KEEP_CORELIB)" + ifneq "$(ALLOW_UNDEF)" "$(FORBID_UNDEF)" + ifeq "$(DLL_UNDEF_FLAGS)" "$(FORBID_UNDEF)" + KEEP_CORELIB := 1 + endif + endif +endif + ifeq "" "$(filter-out 0 N% n% F% f% OFF Off off, $(KEEP_CORELIB))" - ifneq "" "$(filter @OSTYPE@, darwin freebsd)" + ifneq "" "$(filter @OSTYPE@, darwin freebsd)$(filter @LIB_OR_DLL@, lib)" XDLL_LIB := $(filter-out @lib_l_pre@xncbi%@lib_l_ext@, $(XDLL_LIB)) endif endif @@ -136,12 +144,14 @@ ifeq "$(JUST_TOUCH)" "1" $(MAKE) -f $(MAKEFILE) $(MFLAGS) retouch; \ fi else + ARGS = $(LDFLAGS_DLL) $(DLL_LDFLAGS) $(XDLLOBJ) $(XOBJ) $(XDLL_LIB) $(LIBS) + TAIL = $(call regroup_runpaths,$(ARGS)) $(LINK_FILTER) $(XDLL): $(XDLLOBJ) $(XOBJ) $(XDLL_LIBDEP) -$(RM) $(XDLL) .$(XDLL).stamp @has_dll_loadable@-$(RM) $(XDLL_LOADABLE) - $(LINK_WRAPPER) $(LINK_DLL) $(XDLL) $(LDFLAGS_DLL) $(DLL_LDFLAGS) $(XDLLOBJ) $(XOBJ) $(XDLL_LIB) $(LIBS) $(LINK_FILTER) + $(LINK_WRAPPER) $(LINK_DLL) $(XDLL) $(TAIL) $(POST_LINK) $(XDLL) - @has_dll_loadable@$(LINK_WRAPPER) $(LINK_LOADABLE) $(XDLL_LOADABLE) $(LDFLAGS_DLL) $(DLL_LDFLAGS) $(XDLLOBJ) $(XOBJ) $(XDLL_LIB) $(LIBS) $(LINK_FILTER) + @has_dll_loadable@$(LINK_WRAPPER) $(LINK_LOADABLE) $(XDLL_LOADABLE) $(TAIL) @has_dll_loadable@$(POST_LINK) $(XDLL_LOADABLE) ifeq "$(wildcard $(XDLLDEP))" "" @echo $(srcdir) $(CURDIR) $(TMPL) > $(XDLLDEP) diff --git a/c++/src/build-system/Makefile.in.top b/c++/src/build-system/Makefile.in.top index 1abe44fd..dda06af8 100644 --- a/c++/src/build-system/Makefile.in.top +++ b/c++/src/build-system/Makefile.in.top @@ -1,4 +1,4 @@ -# $Id: Makefile.in.top 451817 2014-11-12 16:41:55Z ucko $ +# $Id: Makefile.in.top 526269 2017-02-01 16:52:02Z ucko $ # Top-level meta-makefile that simplifies building even further. # include @builddir@/Makefile.mk @@ -49,9 +49,10 @@ install-toolkit: for x in *.a; do \ $(LN_S) "$$x" "`$(BASENAME) \"$$x\" .a`-static.a"; \ done - cd $(includedir0) && find * -name CVS -prune -o -print |\ - cpio -pd $(pincludedir) - $(INSTALL) -m 644 $(incdir)/* $(pincludedir) + for d in $(includedir0) $(incdir); do \ + cd $$d && find * -name .svn -prune -o -print | \ + cpio -pd $(pincludedir) ; \ + done ## set up appropriate build and status directories somewhere under $(libdir)? install-gbench: diff --git a/c++/src/build-system/Makefile.meta.gmake=yes b/c++/src/build-system/Makefile.meta.gmake=yes index e5d3b362..89cf9044 100644 --- a/c++/src/build-system/Makefile.meta.gmake=yes +++ b/c++/src/build-system/Makefile.meta.gmake=yes @@ -1,5 +1,5 @@ # -*- makefile-gmake -*- -# $Id: Makefile.meta.gmake=yes 470602 2015-06-17 16:00:59Z ucko $ +# $Id: Makefile.meta.gmake=yes 545912 2017-09-12 14:25:34Z ivanov $ ifeq "" "$(findstring /,$(MAKE))" ABSMAKE := $(word 1,$(wildcard $(patsubst %,%/$(MAKE),$(subst :, ,$(PATH))))) @@ -29,6 +29,14 @@ ifneq "" "$(findstring :,$(LD_LIBRARY_PATH))" endif endif +ifeq "" "$(NCBI_BUILD_SESSION_ID)" + ifeq "" "$(filter-out @%@, $(UUIDGEN))" + UUIDGEN = uuidgen 2>/dev/null + endif + NCBI_BUILD_SESSION_ID := $(shell $(UUIDGEN)) + export NCBI_BUILD_SESSION_ID +endif + # Work around GNU Make's tendency to double its automatic # --jobserver-fds=* flag's usage with each level of recursion, by # constructing an alternate MFLAGS_NR variable that limits its @@ -52,6 +60,7 @@ ifdef abs_top_srcdir endif include $(top_srcdir)/src/build-system/Makefile.requirements else + export NCBI_USING_FLAT_MAKEFILE = 1 ifndef builddir include $(top_srcdir)/src/build-system/Makefile.flat_tuneups endif diff --git a/c++/src/build-system/Makefile.meta.in b/c++/src/build-system/Makefile.meta.in index 69757970..95edea86 100644 --- a/c++/src/build-system/Makefile.meta.in +++ b/c++/src/build-system/Makefile.meta.in @@ -1,5 +1,5 @@ ################################# -# $Id: Makefile.meta.in 442076 2014-07-30 14:06:45Z ucko $ +# $Id: Makefile.meta.in 541932 2017-07-24 15:26:58Z ivanov $ # Author: Denis Vakatov (vakatov@ncbi.nlm.nih.gov) ################################# # Meta-makefile(to be configured into "Makefile") @@ -46,6 +46,9 @@ EGREP = @EGREP@ EGREP_Q = @EGREP_Q@ SED = @SED@ OSTYPE = @OSTYPE@ +UUIDGEN = @UUIDGEN@ +CD_REPORTER = @CD_REPORTER@ +PYTHON3 = @PYTHON3@ deactivate = unlink @IF_DEACTIVATING@ deactivate = deactivate diff --git a/c++/src/build-system/Makefile.meta_l b/c++/src/build-system/Makefile.meta_l index db20437e..98d7791e 100644 --- a/c++/src/build-system/Makefile.meta_l +++ b/c++/src/build-system/Makefile.meta_l @@ -1,5 +1,5 @@ # -*- makefile-gmake -*- -# $Id: Makefile.meta_l 507305 2016-07-18 16:19:28Z ucko $ +# $Id: Makefile.meta_l 545914 2017-09-12 14:26:06Z ivanov $ ### Rules for building within a single directory @@ -24,6 +24,12 @@ endif ### Protect against two MAKE processes running in the same dir +ifneq "" "$(filter-out @*@, $(CD_REPORTER))" + ifneq "" "$(wildcard $(PYTHON3))" + RUN_WITH_CD_REPORTER = $(build_root)/build/run_with_cd_reporter.py + endif +endif + ifeq "$(wildcard $(build_root)/bin/run_with_lock)" "" RWL = $(abs_top_srcdir)/scripts/common/impl/run_with_lock.sh else @@ -51,7 +57,8 @@ endif check_run = $(abs_top_srcdir)/scripts/common/check/check_run.sh check_add = $(abs_top_srcdir)/scripts/common/check/check_add.sh -ifeq "" "$(filter 0 1,$(words $(wildcard $(srcdir)/Makefile.*.???)))" +proj_count := $(words $(wildcard $(srcdir)/Makefile.*.???)) +ifeq "1:" "$(NCBI_USING_FLAT_MAKEFILE):$(filter 0 1,$(proj_count))" MAKE_LOCK_MAP = @cd $(abs_srcdir) && $(RWL) \ $(top_srcdir)/scripts/common/impl/make_lock_map.sh \ -bd $(builddir) -sd $(rel_srcdir:src/%=%) @@ -80,14 +87,15 @@ endif # 1: proj_name, 2: lock_map?, 3: command, 4: target, 5: ext, 6: cleanup, # 7: error_status, 8: is_expendable? -define make_one_leaf_proj +define do_make_one_leaf_proj NCBICXX_TESTING_REQS=1 $(3) -q requirements REQUIRES= && \ $(if $(8),NCBI_BUT_EXPENDABLE=$(but_exp);,) \ if NCBICXX_TESTING_REQS=1 $(3) -q requirements; then \ if $(3) -q depend >/dev/null 2>&1 && $(3) -q $(4) >/dev/null 2>&1; then \ $(echo_unless_silent) "$(make_tag) (Makefile.$(1)$(5)): Nothing to be done for \`$(4)'."; \ elif $(echo_unless_silent) $(3) $(4) && \ - $(RWL) -base "make_$(1)" -log "make_$(1).log" $(2) ! $(3) $(4) ; then \ + $(RWL) -base "make_$(1)" -log "make_$(1).log" $(2) \ + ! $(RUN_WITH_CD_REPORTER) $(3) $(4) ; then \ echo "FAILED$$NCBI_BUT_EXPENDABLE: $(rel_srcdir)/Makefile.$(1)$(5)" ; \ $(6) ; \ exit $(7) ; \ @@ -96,10 +104,22 @@ else \ echo "NOTE: skipping project \"$(1)\" due to unmet requirements"; \ [ "$(5)" = .app ] || $(3) mark-as-disabled || true ; \ fi +endef + +# 1: proj_name, 2: target, 3: ext +define warn_one_leaf_proj +$(if $(filter-out export-headers,$(2)),/bin/echo Warning: non-existent $(3:.%=%) project '"$(1)"') +endef + +# 1: proj_name, 2: lock_map?, 3: command, 4: target, 5: ext, 6: cleanup, +# 7: error_status, 8: is_expendable? +define make_one_leaf_proj +$(if $(wildcard $(srcdir)/Makefile.$(1)$(5) Makefile.$(1)$(5)),$(call do_make_one_leaf_proj,$(1),$(2),$(3),$(4),$(5),$(6),$(7),$(8)),$(call warn_one_leaf_proj,$(1),$(4),$(5))) endef # The blank line before endef keeps foreach from running commands together. + MAKE_USR = $(MAKE) -f "$$x_mfile" builddir="$(builddir)" \ srcdir="$(abs_srcdir)" $(MFLAGS_NR) ANY_USR_PROJ = $(USR_PROJ)$(XUNIX_USR_PROJ)$(EXPENDABLE_USR_PROJ) @@ -234,7 +254,13 @@ has_usr_nonusr = $(has_usr:%_l=%.nonusr) has_usr_usr = $(has_usr:%_l=%.usr) has_usr_locked = $(has_usr:%_l=%.usr.locked) -$(has_usr_l_real): %_l.real: %.nonusr ; +ifeq ":" "$(NCBI_USING_FLAT_MAKEFILE):$(filter 0 1,$(proj_count))" + $(has_usr_l_real): %_l.real: + @$(RWL) -base make__$(notdir $(CURDIR))_common \ + $(MAKE) $(MFLAGS_NR) $*.nonusr +else + $(has_usr_l_real): %_l.real: %.nonusr ; +endif $(has_usr_real): %.real: %_l.real ; @@ -259,7 +285,7 @@ else all.usr.locked: sources.usr.locked ; $(filter-out all.usr.locked,$(has_usr_locked)): %.usr.locked: - @$(RWL) $(MAKE) $(MFLAGS_NR) $*.usr + @$(RWL) -base make_user_projects $(MAKE) $(MFLAGS_NR) $*.usr $(has_usr_nonusr): %.nonusr: %.usr.locked endif diff --git a/c++/src/build-system/Makefile.mk.in b/c++/src/build-system/Makefile.mk.in index e05b5c39..25ae72bb 100644 --- a/c++/src/build-system/Makefile.mk.in +++ b/c++/src/build-system/Makefile.mk.in @@ -1,5 +1,5 @@ ################################# -# $Id: Makefile.mk.in 512372 2016-08-30 14:51:36Z ivanov $ +# $Id: Makefile.mk.in 542634 2017-08-01 17:40:39Z ivanov $ # Author: Denis Vakatov (vakatov@ncbi.nlm.nih.gov) ################################# # @@ -245,6 +245,15 @@ COLOR_DIAGNOSTICS = @COLOR_DIAGNOSTICS@ # Refrain from optimizations that assume no aliasing. NO_STRICT_ALIASING = @NO_STRICT_ALIASING@ +# Do/do not discard shared libraries that appear unnecessary. +AS_NEEDED = @AS_NEEDED@ +NO_AS_NEEDED = @NO_AS_NEEDED@ + +# Do/do not link static archives in their entirety, even if some portions +# appear unnecessary. +WHOLE_ARCHIVE = @WHOLE_ARCHIVE@ +NO_WHOLE_ARCHIVE = @NO_WHOLE_ARCHIVE@ + ### For platform-specific includes COMPILER = @COMPILER@ OSTYPE = @OSTYPE@ @@ -310,6 +319,11 @@ NETWORK_PURE_LIBS = @NETWORK_PURE_LIBS@ # $(RESOLVER_LIBS). RESOLVER_LIBS = @RESOLVER_LIBS@ +# Specialized call stack examination library; normally added to +# baseline LIBS if present for the sake of corelib, but potentially +# still useful with C_LIBS. +LIBUNWIND_INCLUDE = @LIBUNWIND_INCLUDE@ +LIBUNWIND_LIBS = @LIBUNWIND_LIBS@ ################################# # Optional variables that may be needed to build some projects @@ -329,6 +343,9 @@ XCONNEXT = @XCONNEXT@ BDB_LIB = @BDB_LIB@ BDB_CACHE_LIB = @BDB_CACHE_LIB@ +# NCBI C++ API for SQLite 3.x +SQLITE3_WRAPPER = @SQLITE3_WRAPPER@ + # Possibly absent DBAPI drivers (depending on whether the relevant # 3rd-party libraries are present, and whether DBAPI was disabled altogether) DBAPI_DRIVER = @DBAPI_DRIVER@ @@ -363,8 +380,10 @@ PCRE_LIBS = @PCRE_LIBS@ PCREPOSIX_LIBS = @PCREPOSIX_LIBS@ PCRE_LIB = @PCRE_LIB@ -# OpenSSL, GnuTLS, and potential supporting packages: headers and libs. -# TLS_* points to GNUTLS_* by preference. +# mbedTLS, OpenSSL, GNUTLS, and potential supporting packages: headers and libs. +# TLS_* covers *both* GNUTLS and mbedTLS. +MBEDTLS_INCLUDE = @MBEDTLS_INCLUDE@ +MBEDTLS_LIBS = @MBEDTLS_LIBS@ GMP_INCLUDE = @GMP_INCLUDE@ GMP_LIBS = @GMP_LIBS@ GCRYPT_INCLUDE = @GCRYPT_INCLUDE@ @@ -376,8 +395,8 @@ GNUTLS_LIBS = @GNUTLS_LIBS@ OPENSSL_INCLUDE = @OPENSSL_INCLUDE@ OPENSSL_LIBS = @OPENSSL_LIBS@ OPENSSL_STATIC_LIBS = @OPENSSL_STATIC_LIBS@ -TLS_INCLUDE = @TLS_INCLUDE@ -TLS_LIBS = @TLS_LIBS@ +TLS_INCLUDE = $(GNUTLS_INCLUDE) $(MBEDTLS_INCLUDE) +TLS_LIBS = $(GNUTLS_LIBS) $(MBEDTLS_LIBS) # Kerberos 5 (via GSSAPI) KRB5_INCLUDE = @KRB5_INCLUDE@ @@ -654,11 +673,16 @@ CEREAL_INCLUDE = @CEREAL_INCLUDE@ SASL2_INCLUDE = @SASL2_INCLUDE@ SASL2_LIBS = @SASL2_LIBS@ -# MongoDB +# MongoDB (deprecated legacy interface) MONGODB_INCLUDE = @MONGODB_INCLUDE@ MONGODB_LIBS = @MONGODB_LIBS@ MONGODB_STATIC_LIBS = @MONGODB_STATIC_LIBS@ +# MongoDB 3.x +MONGODB3_INCLUDE = @MONGODB3_INCLUDE@ +MONGODB3_LIBS = @MONGODB3_LIBS@ +MONGODB3_STATIC_LIBS = @MONGODB3_STATIC_LIBS@ + # Google Mock GMOCK_INCLUDE = @GMOCK_INCLUDE@ GMOCK_LIBS = @GMOCK_LIBS@ @@ -667,9 +691,37 @@ GMOCK_LIBS = @GMOCK_LIBS@ LAPACK_INCLUDE = @LAPACK_INCLUDE@ LAPACK_LIBS = @LAPACK_LIBS@ -# LMDB +# LMDB; the LIBS version goes in LIBS, and the LIB version goes in LIB. LMDB_INCLUDE = @LMDB_INCLUDE@ LMDB_LIBS = @LMDB_LIBS@ +LMDB_LIB = @LMDB_LIB@ + +# libuv +LIBUV_INCLUDE = @LIBUV_INCLUDE@ +LIBUV_LIBS = @LIBUV_LIBS@ +LIBUV_STATIC_LIBS = @LIBUV_STATIC_LIBS@ + +# libssh2 +LIBSSH2_INCLUDE = @LIBSSH2_INCLUDE@ +LIBSSH2_LIBS = @LIBSSH2_LIBS@ +LIBSSH2_STATIC_LIBS = @LIBSSH2_STATIC_LIBS@ + +# Datastax Cassandra driver +CASSANDRA_INCLUDE = @CASSANDRA_INCLUDE@ +CASSANDRA_LIBS = @CASSANDRA_LIBS@ +CASSANDRA_STATIC_LIBS = @CASSANDRA_STATIC_LIBS@ + +# libxlsxwriter +LIBXLSXWRITER_INCLUDE = @LIBXLSXWRITER_INCLUDE@ +LIBXLSXWRITER_LIBS = @LIBXLSXWRITER_LIBS@ +LIBXLSXWRITER_STATIC_LIBS = @LIBXLSXWRITER_STATIC_LIBS@ + +# GRPC +GRPC_INCLUDE = @GRPC_INCLUDE@ +GRPC_LIBS = @GRPC_LIBS@ +GRPC_UNSECURE_LIBS = @GRPC_UNSECURE_LIBS@ +GRPC_REFLECTION_LIBS = @GRPC_REFLECTION_LIBS@ +GRPC_BIN = @GRPC_BIN@ # Compress COMPRESS_LDEP = $(CMPRS_LIB) @@ -707,14 +759,14 @@ GENBANK_READER_GICACHE_LIBS = ncbi_xreader_gicache \ # Interdependent sequence libraries + seqcode. Does not include seqset. SEQ_LIBS = seq seqcode sequtil -SOBJMGR_LDEP = genome_collection seqedit seqsplit seqset $(SEQ_LIBS) \ +SOBJMGR_LDEP = genome_collection seqedit seqsplit submit seqset $(SEQ_LIBS) \ pub medline biblio general xser xutil xncbi SOBJMGR_LIBS = xobjmgr $(SOBJMGR_LDEP) OBJMGR_LIBS = $(GENBANK_LIBS) # Overlapping with qall is poor, so we have a second macro to make it # easier to stay out of trouble. -QOBJMGR_ONLY_LIBS = xobjmgr id2 seqsplit id1 genome_collection seqset \ +QOBJMGR_ONLY_LIBS = xobjmgr id2 seqsplit id1 genome_collection submit seqset \ $(SEQ_LIBS) pub medline biblio general xcompress $(CMPRS_LIB) QOBJMGR_LIBS = $(QOBJMGR_ONLY_LIBS) qall QOBJMGR_STATIC_LIBS = $(QOBJMGR_ONLY_LIBS:%=%$(STATIC)) qall @@ -727,7 +779,7 @@ EUTILS_LIBS = eutils egquery elink epost esearch espell esummary linkout \ OBJREAD_LIBS = xobjread variation creaders submit # formatting code -XFORMAT_LIBS = xformat xcleanup gbseq submit mlacli mla medlars pubmed valid taxon3 +XFORMAT_LIBS = xformat xcleanup gbseq mlacli mla medlars pubmed valid taxon3 # object editing library OBJEDIT_LIBS = xobjedit $(OBJREAD_LIBS) taxon3 diff --git a/c++/src/build-system/Makefile.module b/c++/src/build-system/Makefile.module index 839955af..c44df32f 100644 --- a/c++/src/build-system/Makefile.module +++ b/c++/src/build-system/Makefile.module @@ -1,10 +1,12 @@ # -# $Id: Makefile.module 310797 2011-07-06 11:58:19Z dicuccio $ +# $Id: Makefile.module 536550 2017-05-19 16:49:53Z ucko $ # # Generate source files and makefiles from ASN.1 spec or XML DTD or schema. # (NOTE: hard-wired for the C++ Toolkit directory structure.) # +-include $(builddir)/Makefile.mk + SRCDIR = $(top_srcdir)/src/$(MODULE_PATH) INCLUDEDIR = $(top_srcdir)/include/$(MODULE_PATH) @@ -38,6 +40,8 @@ purge_all_files: .NO_PARALLEL: $(FILES): $(SPEC) $(DATATOOL) $(MODULE).def $(MODULE).module $(IMPDEPS) $(DATATOOL) -oR $(top_srcdir) -opm $(MODULE_SEARCH) -m $(SPEC) -M "$(IMPFILES)" -oA -oc $(MODULE) -or $(MODULE_PATH) -odi -od $(MODULE).def -oex '' -ocvs -pch 'ncbi_pch.hpp' -fd $(MODULE).dump $(EXTRA_DATATOOL_FLAGS) + @[ -f .gitignore ] || $(LN_S) .cvsignore .gitignore + @cd $(INCLUDEDIR); [ -f .gitignore ] || $(LN_S) .cvsignore .gitignore makefiles: Makefile.in Makefile.$(MODULE).lib diff --git a/c++/src/build-system/Makefile.rules.in b/c++/src/build-system/Makefile.rules.in index 3d5a2798..42dd557e 100644 --- a/c++/src/build-system/Makefile.rules.in +++ b/c++/src/build-system/Makefile.rules.in @@ -1,5 +1,5 @@ ################################# -# $Id: Makefile.rules.in 497672 2016-04-08 18:34:20Z ucko $ +# $Id: Makefile.rules.in 537548 2017-06-01 15:33:41Z ucko $ # Author: Denis Vakatov (vakatov@ncbi.nlm.nih.gov), # Aaron Ucko (ucko@ncbi.nlm.nih.gov) ################################# @@ -9,6 +9,19 @@ ifeq "$(ALT_GOALS)" "" +ifeq "$(RUNPATH_FLAG)" "-L" +regroup_runpaths = $(1) +else +non_runpaths = $(filter-out $(RUNPATH_FLAG)%,$(1)) +extract_runpaths = $(filter $(RUNPATH_FLAG)%,$(1)) +extract_rpargs = $(patsubst $(RUNPATH_FLAG)%,%,$(call extract_runpaths,$(1))) +extract_rpdirs = $(subst :, ,$(call extract_rpargs,$(1))) +remote_last = $(filter-out /net%,$(1)) $(filter /net%,$(1)) +regrouped_rpdirs = $(call remote_last,$(call extract_rpdirs,$(1))) +regrouped_runpaths=$(patsubst %,$(RUNPATH_FLAG)%,$(call regrouped_rpdirs,$(1))) +regroup_runpaths = $(call regrouped_runpaths,$(1)) $(call non_runpaths,$(1)) +endif + # Requirements checking XREQLIB=$(patsubst %$(FORCE_STATIC),%,$(patsubst %$(DLL),%,$(XAPP_LIB) $(XDLL_LIBS))) include $(wildcard $(XREQLIB:%=$(status_dir)/.%.disabled)) diff --git a/c++/src/build-system/cmake/CMakeChecks.BerkeleyDB.cmake b/c++/src/build-system/cmake/CMakeChecks.BerkeleyDB.cmake new file mode 100644 index 00000000..7418de7f --- /dev/null +++ b/c++/src/build-system/cmake/CMakeChecks.BerkeleyDB.cmake @@ -0,0 +1,19 @@ +include(CheckFunctionExists) +include(CheckIncludeFile) + +set(CMAKE_FIND_FRAMEWORK "FIRST") + +find_package(BerkeleyDB) +if (BERKELEYDB_FOUND) + set(BERKELEYDB_INCLUDE ${BerkeleyDB_INCLUDE_DIR}) + set(BERKELEYDB_LIBS ${BerkeleyDB_LIBRARIES}) +endif() + +if (BERKELEYDB_FOUND) + set(HAVE_BDB 1) + set(HAVE_BERKELEY_DB 1) + set(HAVE_BERKELEY_DB_CXX 1) + +endif (BERKELEYDB_FOUND) + + diff --git a/c++/src/build-system/cmake/CMakeChecks.basic-checks.cmake b/c++/src/build-system/cmake/CMakeChecks.basic-checks.cmake new file mode 100644 index 00000000..ff83d0f9 --- /dev/null +++ b/c++/src/build-system/cmake/CMakeChecks.basic-checks.cmake @@ -0,0 +1,189 @@ +# +# Basic checks +# + +include(CheckIncludeFile) +check_include_file(arpa/inet.h HAVE_ARPA_INET_H) +check_include_file(atomic.h HAVE_ATOMIC_H) +check_include_file(dlfcn.h HAVE_DLFCN_H) +check_include_file(errno.h HAVE_ERRNO_H) +check_include_file(ieeefp.h HAVE_IEEEFP_H) +check_include_file(inttypes.h HAVE_INTTYPES_H) +check_include_file(libgen.h HAVE_LIBGEN_H) +check_include_file(limits.h HAVE_LIMITS_H) +check_include_file(locale.h HAVE_LOCALE_H) +check_include_file(malloc.h HAVE_MALLOC_H) +check_include_file(memory.h HAVE_MEMORY_H) +check_include_file(netdb.h HAVE_NETDB_H) +check_include_file(netinet/in.h HAVE_NETINET_IN_H) +check_include_file(netinet/tcp.h HAVE_NETINET_TCP_H) +check_include_file(odbcss.h HAVE_ODBCSS_H) +check_include_file(paths.h HAVE_PATHS_H) +check_include_file(poll.h HAVE_POLL_H) +check_include_file(signal.h HAVE_SIGNAL_H) +check_include_file(stddef.h HAVE_STDDEF_H) +check_include_file(stdint.h HAVE_STDINT_H) +check_include_file(stdlib.h HAVE_STDLIB_H) +check_include_file(string.h HAVE_STRING_H) +check_include_file(strings.h HAVE_STRINGS_H) +check_include_file(sys/ioctl.h HAVE_SYS_IOCTL_H) +check_include_file(sys/mount.h HAVE_SYS_MOUNT_H) +check_include_file(sys/select.h HAVE_SYS_SELECT_H) +check_include_file(sys/socket.h HAVE_SYS_SOCKET_H) +check_include_file(sys/sockio.h HAVE_SYS_SOCKIO_H) +check_include_file(sys/stat.h HAVE_SYS_STAT_H) +check_include_file(sys/statvfs.h HAVE_SYS_STATVFS_H) +check_include_file(sys/sysinfo.h HAVE_SYS_SYSINFO_H) +check_include_file(sys/time.h HAVE_SYS_TIME_H) +check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(sys/vfs.h HAVE_SYS_VFS_H) +check_include_file(unistd.h HAVE_UNISTD_H) +check_include_file(wchar.h HAVE_WCHAR_H) +check_include_file(windows.h HAVE_WINDOWS_H) +check_include_file(sys/epoll.h HAVE_SYS_EPOLL_H) + +include(CheckIncludeFileCXX) +check_include_file_cxx(fstream HAVE_FSTREAM) +check_include_file_cxx(fstream.h HAVE_FSTREAM_H) +check_include_file_cxx(iostream HAVE_IOSTREAM) +check_include_file_cxx(iostream.h HAVE_IOSTREAM_H) +check_include_file_cxx(limits HAVE_LIMITS) +check_include_file_cxx(strstrea.h HAVE_STRSTREA_H) +check_include_file_cxx(strstream HAVE_STRSTREAM_H) + +include(CheckFunctionExists) +check_function_exists(alarm HAVE_ALARM) +check_function_exists(asprintf HAVE_ASPRINTF) +check_function_exists(atoll HAVE_ATOLL) +check_function_exists(basename HAVE_BASENAME) +check_function_exists(erf HAVE_ERF) +check_function_exists(euidaccess HAVE_EUIDACCESS) +check_function_exists(freehostent HAVE_FREEHOSTENT) +check_function_exists(fseeko HAVE_FSEEKO) +check_function_exists(fstat HAVE_FSTAT) +check_function_exists(getaddrinfo HAVE_GETADDRINFO) +check_function_exists(gethostent_r HAVE_GETHOSTENT_R) +check_function_exists(getipnodebyaddr HAVE_GETIPNODEBYADDR) +check_function_exists(getipnodebyname HAVE_GETIPNODEBYNAME) +check_function_exists(getloadavg HAVE_GETLOADAVG) +check_function_exists(getlogin_r HAVE_GETLOGIN_R) +check_function_exists(getnameinfo HAVE_GETNAMEINFO) +check_function_exists(getopt HAVE_GETOPT) +check_function_exists(getpagesize HAVE_GETPAGESIZE) +check_function_exists(getpass HAVE_GETPASS) +check_function_exists(getpassphrase HAVE_GETPASSPHRASE) +check_function_exists(getpwuid HAVE_GETPWUID) +check_function_exists(getrusage HAVE_GETRUSAGE) +check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) +check_function_exists(getuid HAVE_GETUID) +check_function_exists(inet_ntoa_r HAVE_INET_NTOA_R) +check_function_exists(inet_ntop HAVE_INET_NTOP) +check_function_exists(lchown HAVE_LCHOWN) +#TODO return type check_function_exists(localtime_r HAVE_LOCALTIME_R) +check_function_exists(lutimes HAVE_LUTIMES) +check_function_exists(memrchr HAVE_MEMRCHR) +check_function_exists(nanosleep HAVE_NANOSLEEP) +check_function_exists(pthread_atfork HAVE_PTHREAD_ATFORK) +check_function_exists(pthread_condattr_setclock HAVE_PTHREAD_CONDATTR_SETCLOCK) +check_function_exists(pthread_setconcurrency HAVE_PTHREAD_SETCONCURRENCY) +check_function_exists(putenv HAVE_PUTENV) +check_function_exists(readpassphrase HAVE_READPASSPHRASE) +check_function_exists(readv HAVE_READV) +check_function_exists(sched_yield HAVE_SCHED_YIELD) +check_function_exists(select HAVE_SELECT) +check_function_exists(setenv HAVE_SETENV) +check_function_exists(socketpair HAVE_SOCKETPAIR) +check_function_exists(statfs HAVE_STATFS) +check_function_exists(statvfs HAVE_STATVFS) +check_function_exists(strdup HAVE_STRDUP) +check_function_exists(strlcat HAVE_STRLCAT) +check_function_exists(strlcpy HAVE_STRLCPY) +check_function_exists(strndup HAVE_STRNDUP) +check_function_exists(strsep HAVE_STRSEP) +check_function_exists(strtok_r HAVE_STRTOK_R) +check_function_exists(timegm HAVE_TIMEGM) +check_function_exists(utimes HAVE_UTIMES) +check_function_exists(vasprintf HAVE_VASPRINTF) +check_function_exists(vprintf HAVE_VPRINTF) +check_function_exists(vsnprintf HAVE_VSNPRINTF) +check_function_exists(writev HAVE_WRITEV) + +# TODO Need to check the number of arguments for gethostbyaddr_r, gethostbyname_r, getservbyname_r +check_function_exists(gethostbyaddr_r HAVE_GETHOSTBYADDR_R) +check_function_exists(gethostbyname_r HAVE_GETHOSTBYNAME_R) +check_function_exists(getservbyname_r HAVE_GETSERVBYNAME_R) + +check_include_file_cxx(cxxabi.h HAVE_CXXABI_H) +if (${HAVE_CXXABI_H}) + include(CheckCXXSymbolExists) + check_cxx_symbol_exists(abi::__cxa_demangle cxxabi.h HAVE_CXA_DEMANGLE) +endif () + +include(CheckLibraryExists) +check_library_exists(dl dlopen "" HAVE_LIBDL) + +check_library_exists(jpeg jpeg_start_decompress "" HAVE_LIBJPEG) +check_library_exists(gif EGifCloseFile "" HAVE_LIBJPEG) +check_library_exists(tiff TIFFClientOpen "" HAVE_LIBJPEG) +check_library_exists(png png_create_read_struct "" HAVE_LIBPNG) + +include(CheckSymbolExists) +check_symbol_exists(FIONBIO "sys/ioctl.h" BSD_COMP) + +include(CheckTypeSize) +check_type_size(char SIZEOF_CHAR) +check_type_size(double SIZEOF_DOUBLE) +check_type_size(float SIZEOF_FLOAT) +check_type_size(int SIZEOF_INT) +check_type_size(long SIZEOF_LONG) +check_type_size("long double" SIZEOF_LONG_DOUBLE) +check_type_size("long long" SIZEOF_LONG_LONG) +check_type_size(short SIZEOF_SHORT) +check_type_size(size_t SIZEOF_SIZE_T) +check_type_size(void* SIZEOF_VOIDP) +#check_type_size(__int64 SIZEOF___INT64) + +set(CMAKE_EXTRA_INCLUDE_FILES_BACKUP CMAKE_EXTRA_INCLUDE_FILES) +set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h) +check_type_size(socklen_t HAVE_SOCKLEN_T) +set(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES_BACKUP}) + +set(CMAKE_EXTRA_INCLUDE_FILES_BACKUP CMAKE_EXTRA_INCLUDE_FILES) +set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h) +check_type_size(socklen_t SOCKLEN_T) +set(CMAKE_EXTRA_INCLUDE_FILES CMAKE_EXTRA_INCLUDE_FILES_BACKUP) + +set(CMAKE_EXTRA_INCLUDE_FILES_BACKUP CMAKE_EXTRA_INCLUDE_FILES) +set(CMAKE_EXTRA_INCLUDE_FILES sys/sem.h) +check_type_size(semun_t SEMUN) +set(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES_BACKUP}) + +option(USE_LOCAL_BZLIB "Use a local copy of libbz2") +option(USE_LOCAL_PCRE "Use a local copy of libpcre") + +if (HAVE_WCHAR_H) + set(HAVE_WSTRING 1) +endif (HAVE_WCHAR_H) + +# +# Threading libraries +find_package(Threads REQUIRED) +## message("CMAKE_THREAD_LIBS_INIT: ${CMAKE_THREAD_LIBS_INIT}") +## message("CMAKE_USE_SPROC_INIT: ${CMAKE_USE_SPROC_INIT}") +## message("CMAKE_USE_WIN32_THREADS_INIT: ${CMAKE_USE_WIN32_THREADS_INIT}") +## message("CMAKE_USE_PTHREADS_INIT: ${CMAKE_USE_PTHREADS_INIT}") +## message("CMAKE_HP_PTHREADS_INIT: ${CMAKE_HP_PTHREADS_INIT}") +if (CMAKE_USE_PTHREADS_INIT) + add_definitions(-D_MT -D_REENTRANT -D_THREAD_SAFE) + set(NCBI_POSIX_THREADS 1) +endif (CMAKE_USE_PTHREADS_INIT) + + +if(HAVE_LIBDL) + set(DL_LIBS -ldl) +else(HAVE_LIBDL) + if (UNIX) + message(FATAL_ERROR "dl library not found") + endif(UNIX) +endif(HAVE_LIBDL) + diff --git a/c++/src/build-system/cmake/CMakeChecks.boost.cmake b/c++/src/build-system/cmake/CMakeChecks.boost.cmake new file mode 100644 index 00000000..06f19875 --- /dev/null +++ b/c++/src/build-system/cmake/CMakeChecks.boost.cmake @@ -0,0 +1,38 @@ +# Boost: headers and libs [use as ${BOOST_LIBPATH} ${BOOST_*_LIBS} ${RT_LIBS}] + +if (BUILD_SHARED_LIBS) + set(Boost_USE_STATIC_LIBS OFF) + set(Boost_USE_STATIC_RUNTIME OFF) + add_definitions(-DBOOST_LOG_DYN_LINK) +else() + set(Boost_USE_STATIC_LIBS ON) + set(Boost_USE_STATIC_RUNTIME ON) +endif() +set(Boost_USE_MULTITHREADED ON) + +#Hints for FindBoost + +set(_foo_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH}) + +if(WIN32) + set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${BOOST_ROOT}) +# set(WINDOWS_BOOST_DIR "${WIN32_PACKAGE_ROOT}/boost_1_57_0") +# set(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} ${WINDOWS_BOOST_DIR}) +# set(BOOST_ROOT "${WINDOWS_BOOST_DIR}") +# set(BOOST_LIBRARYDIR "${BOOST_ROOT}/stage/lib") +else() + set(BOOST_ROOT ${NCBI_TOOLS_ROOT}/boost-1.57.0-ncbi1 ) +endif() + + +#set(Boost_DEBUG ON) +#include(FindBoost) +#set(CMAKE_LIBRARY_PATH ${NCBI_TOOLS_ROOT}/boost-1.41.0/lib) +find_package(Boost + COMPONENTS filesystem regex system unit_test_framework + REQUIRED) + +set(BOOST_INCLUDE ${Boost_INCLUDE_DIRS}) +set(BOOST_LIBPATH -L${Boost_LIBRARY_DIRS} -Wl,-rpath,${Boost_LIBRARY_DIRS}) + +set(CMAKE_PREFIX_PATH ${_foo_CMAKE_PREFIX_PATH}) diff --git a/c++/src/build-system/cmake/CMakeChecks.cmake b/c++/src/build-system/cmake/CMakeChecks.cmake old mode 100755 new mode 100644 index d5f70d18..a8eab32c --- a/c++/src/build-system/cmake/CMakeChecks.cmake +++ b/c++/src/build-system/cmake/CMakeChecks.cmake @@ -1,191 +1,261 @@ -if (${CMAKE_BUILD_TYPE} STREQUAL "Debug") - add_definitions(-D_DEBUG) -ELSE() - add_definitions(-DNDEBUG) -ENDIF() -add_definitions(-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) -#set(XYY -I) -set(XYY ) - -include(CheckIncludeFile) -check_include_file(arpa/inet.h HAVE_ARPA_INET_H) -check_include_file(atomic.h HAVE_ATOMIC_H) -check_include_file(dlfcn.h HAVE_DLFCN_H) -check_include_file(errno.h HAVE_ERRNO_H) -check_include_file(ieeefp.h HAVE_IEEEFP_H) -check_include_file(inttypes.h HAVE_INTTYPES_H) -check_include_file(malloc.h HAVE_MALLOC_H) -check_include_file(memory.h HAVE_MEMORY_H) -check_include_file(netdb.h HAVE_NETDB_H) -check_include_file(netinet/in.h HAVE_NETINET_IN_H) -check_include_file(netinet/tcp.h HAVE_NETINET_TCP_H) -check_include_file(odbcss.h HAVE_ODBCSS_H) -check_include_file(paths.h HAVE_PATHS_H) -check_include_file(poll.h HAVE_POLL_H) -check_include_file(signal.h HAVE_SIGNAL_H) -check_include_file(sqlite3async.h HAVE_SQLITE3ASYNC_H) -check_include_file(stdint.h HAVE_STDINT_H) -check_include_file(stdlib.h HAVE_STDLIB_H) -check_include_file(string.h HAVE_STRING_H) -check_include_file(strings.h HAVE_STRINGS_H) -check_include_file(sys/ioctl.h HAVE_SYS_IOCTL_H) -check_include_file(sys/mount.h HAVE_SYS_MOUNT_H) -check_include_file(sys/select.h HAVE_SYS_SELECT_H) -check_include_file(sys/socket.h HAVE_SYS_SOCKET_H) -check_include_file(sys/sockio.h HAVE_SYS_SOCKIO_H) -check_include_file(sys/stat.h HAVE_SYS_STAT_H) -check_include_file(sys/statvfs.h HAVE_SYS_STATVFS_H) -check_include_file(sys/sysinfo.h HAVE_SYS_SYSINFO_H) -check_include_file(sys/time.h HAVE_SYS_TIME_H) -check_include_file(sys/types.h HAVE_SYS_TYPES_H) -check_include_file(sys/vfs.h HAVE_SYS_VFS_H) -check_include_file(unistd.h HAVE_UNISTD_H) -check_include_file(wchar.h HAVE_WCHAR_H) -check_include_file(windows.h HAVE_WINDOWS_H) - -include(CheckIncludeFileCXX) -check_include_file_cxx(fstream HAVE_FSTREAM) -check_include_file_cxx(fstream.h HAVE_FSTREAM_H) -check_include_file_cxx(iostream HAVE_IOSTREAM) -check_include_file_cxx(iostream.h HAVE_IOSTREAM_H) -check_include_file_cxx(limits HAVE_LIMITS) -check_include_file_cxx(strstrea.h HAVE_STRSTREA_H) -check_include_file_cxx(strstream HAVE_STRSTREAM_H) - -include(CheckFunctionExists) -check_function_exists(asprintf HAVE_ASPRINTF) -check_function_exists(atoll HAVE_ATOLL) -check_function_exists(basename HAVE_BASENAME) -check_function_exists(erf HAVE_ERF) -check_function_exists(euidaccess HAVE_EUIDACCESS) -check_function_exists(freehostent HAVE_FREEHOSTENT) -check_function_exists(fseeko HAVE_FSEEKO) -check_function_exists(getaddrinfo HAVE_ASPRINTF) -check_function_exists(gethostent_r HAVE_GETHOSTENT_R) -check_function_exists(getipnodebyaddr HAVE_GETIPNODEBYADDR) -check_function_exists(getipnodebyname HAVE_GETIPNODEBYNAME) -check_function_exists(getloadavg HAVE_GETLOADAVG) -check_function_exists(getlogin_r HAVE_GETLOGIN_R) -check_function_exists(getnameinfo HAVE_GETNAMEINFO) -check_function_exists(getpagesize HAVE_GETPAGESIZE) -check_function_exists(readpassphrase HAVE_READPASSPHRASE) -check_function_exists(getpassphrase HAVE_GETPASSPHRASE) -check_function_exists(getpass HAVE_GETPASS) -check_function_exists(getpwuid HAVE_GETPWUID) -check_function_exists(getrusage HAVE_GETRUSAGE) -check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) -check_function_exists(getuid HAVE_GETUID) -check_function_exists(inet_ntoa_r HAVE_INET_NTOA_R) -check_function_exists(inet_ntop HAVE_INET_NTOP) -check_function_exists(lchown HAVE_LCHOWN) -check_function_exists(localtime_r HAVE_LOCALTIME_R) -check_function_exists(lutimes HAVE_LUTIMES) -check_function_exists(nanosleep HAVE_NANOSLEEP) -check_function_exists(pthread_atfork HAVE_PTHREAD_ATFORK) -check_function_exists(pthread_setconcurrency HAVE_PTHREAD_SETCONCURRENCY) -check_function_exists(readpassphrase HAVE_READPASSPHRASE) -check_function_exists(readv HAVE_READV) -check_function_exists(sched_yield HAVE_SCHED_YIELD) -check_function_exists(select HAVE_SELECT) -check_function_exists(sqlite3_unlock_notify HAVE_SQLITE3_UNLOCK_NOTIFY) -check_function_exists(statfs HAVE_STATFS) -check_function_exists(statvfs HAVE_STATVFS) -check_function_exists(strdup HAVE_STRDUP) -check_function_exists(strlcat HAVE_STRLCAT) -check_function_exists(strlcpy HAVE_STRLCPY) -check_function_exists(strndup HAVE_STRNDUP) -check_function_exists(strtok_r HAVE_STRTOK_R) -check_function_exists(utimes HAVE_UTIMES) -check_function_exists(vasprintf HAVE_VASPRINTF) -check_function_exists(vprintf HAVE_VPRINTF) -check_function_exists(vsnprintf HAVE_VSNPRINTF) -check_function_exists(writev HAVE_WRITEV) - -include(CheckLibraryExists) -check_library_exists(dl dlopen "" HAVE_LIBDL) -check_library_exists(pcre pcre_study "" HAVE_LIBPCRE) - -include(CheckTypeSize) -check_type_size(char SIZEOF_CHAR) -check_type_size(double SIZEOF_DOUBLE) -check_type_size(float SIZEOF_FLOAT) -check_type_size(int SIZEOF_INT) -check_type_size(long SIZEOF_LONG) -check_type_size("long double" SIZEOF_LONG_DOUBLE) -check_type_size("long long" SIZEOF_LONG_LONG) -check_type_size(short SIZEOF_SHORT) -check_type_size(size_t SIZEOF_SIZE_T) -check_type_size(void* SIZEOF_VOIDP) -check_type_size(__int64 SIZEOF___INT64) - -option(USE_LOCAL_BZLIB "Use a local copy of libbz2") -option(USE_LOCAL_PCRE "Use a local copy of libpcre") - -if (HAVE_WCHAR_H) - set(HAVE_WSTRING 1) -endif (HAVE_WCHAR_H) - -# -# Threading libraries -find_package(Threads) -if (CMAKE_USE_PTHREADS_INIT) - add_definitions(-D_MT -D_REENTRANT -D_THREAD_SAFE) - set(NCBI_POSIX_THREADS 1) -endif (CMAKE_USE_PTHREADS_INIT) - - -if(HAVE_LIBDL) - set(DL_LIBS -ldl) -endif(HAVE_LIBDL) - -set(ORIG_LIBS -lrt -lm -lpthread) -set(ORIG_C_LIBS -lm -lpthread) -set(C_LIBS ${ORIG_C_LIBS}) +############################################################################ +# +# Note: +# This file is included before everything else +# Anything related to the initial state should go early in this file! -if (HAVE_LIBPCRE AND NOT USE_LOCAL_PCRE) - set(PCRE_LIBS -lpcre) -else(HAVE_LIBPCRE AND NOT USE_LOCAL_PCRE) - set(USE_LOCAL_PCRE 1 CACHE INTERNAL "Using local PCRE due to system library absence") -endif(HAVE_LIBPCRE AND NOT USE_LOCAL_PCRE) +if (WIN32) + if ("${CMAKE_BUILD_TYPE}" STREQUAL "") + set(CMAKE_BUILD_TYPE Debug) + endif() + if ("${BUILD_SHARED_LIBS}" STREQUAL "") + set(BUILD_SHARED_LIBS OFF) + endif() +endif() +cmake_policy(SET CMP0054 OLD) -if (UNIX) - SET(NCBI_OS_UNIX 1 CACHE INTERNAL "Is Unix") - SET(NCBI_OS \"UNIX\" CACHE INTERNAL "Is Unix") - if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") - SET(NCBI_OS_LINUX 1 CACHE INTERNAL "Is Linux") - endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") -endif(UNIX) +############################################################################ +# +# Hunter packages for Windows +# if (WIN32) - SET(NCBI_OS_MSWIN 1 CACHE INTERNAL "Is Windows") - SET(NCBI_OS \"WINDOWS\" CACHE INTERNAL "Is Windows") -endif(WIN32) + #set(HUNTER_STATUS_DEBUG TRUE) + hunter_add_package(wxWidgets) + hunter_add_package(Boost COMPONENTS filesystem regex system test) + hunter_add_package(ZLIB) + hunter_add_package(BZip2) + hunter_add_package(Jpeg) + hunter_add_package(PNG) + hunter_add_package(TIFF) + #hunter_add_package(freetype) +endif() + +############################################################################ +# +# Basic Setup +# -if (CYGWIN) - SET(NCBI_OS_CYGWIN 1 CACHE INTERNAL "Is CygWin") - SET(NCBI_OS \"CYGWIN\" CACHE INTERNAL "Is Cygwin") -endif(CYGWIN) -if (APPLE) - if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") - SET(NCBI_OS_DARWIN 1 CACHE INTERNAL "Is Mac OS X") - endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") -endif(APPLE) +set(top_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/..) +set(abs_top_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/..) + +get_filename_component(top_src_dir "${top_src_dir}" ABSOLUTE) +get_filename_component(abs_top_src_dir "${abs_top_src_dir}" ABSOLUTE) + +set(build_root ${CMAKE_BINARY_DIR}) +set(builddir ${CMAKE_BINARY_DIR}) +set(includedir0 ${top_src_dir}/include) +set(includedir ${includedir0}) +set(incdir ${build_root}/inc) +set(incinternal ${includedir0}/internal) + +# NOTE: +# We conditionally set a package config path +# The existence of files in this directory switches find_package() +# to automatically switch between module mode vs. config mode +# +set(NCBI_TOOLS_ROOT $ENV{NCBI}) +if (EXISTS ${NCBI_TOOLS_ROOT}) + set(_NCBI_DEFAULT_PACKAGE_SEARCH_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build-system/cmake/ncbi-defaults") + set(CMAKE_PREFIX_PATH + ${CMAKE_PREFIX_PATH} + ${_NCBI_DEFAULT_PACKAGE_SEARCH_PATH} + ) + message(STATUS "NCBI Root: ${NCBI_TOOLS_ROOT}") + message(STATUS "CMake Prefix Path: ${CMAKE_PREFIX_PATH}") +else() + message(STATUS "NCBI Root: ") +endif() + +if(WIN32) + # Specific location overrides for Windows packages + # Note: this variable must be set in the CMake GUI!! + #set(WIN32_PACKAGE_ROOT "C:/Users/dicuccio/dev/packages") + set(GIF_ROOT "${WIN32_PACKAGE_ROOT}/giflib-4.1.4-1-lib") + set (ENV{GIF_DIR} "${GIF_ROOT}") + + set(PCRE_PKG_ROOT "${WIN32_PACKAGE_ROOT}/pcre-7.9-lib") + set(PCRE_PKG_INCLUDE_DIRS "${PCRE_PKG_ROOT}/include") + set(PCRE_PKG_LIBRARY_DIRS "${PCRE_PKG_ROOT}/lib") + + set(GNUTLS_ROOT "${WIN32_PACKAGE_ROOT}/gnutls-3.4.9") + set(PC_GNUTLS_INCLUDEDIR "${GNUTLS_ROOT}/include") + set(PC_GNUTLS_LIBDIR "${GNUTLS_ROOT}/lib") + + set(FREETYPE_ROOT "${WIN32_PACKAGE_ROOT}/freetype-2.3.5-1-lib") + set(ENV{FREETYPE_DIR} "${FREETYPE_ROOT}") + + set(FTGL_ROOT "${WIN32_PACKAGE_ROOT}/ftgl-2.1.3_rc5") + set(LZO_ROOT "${WIN32_PACKAGE_ROOT}/lzo-2.05-lib") + + set(CMAKE_PREFIX_PATH + ${CMAKE_PREFIX_PATH} + "${PCRE_PKG_ROOT}" + "${GNUTLS_ROOT}" + "${LZO_ROOT}" + "${GIF_ROOT}" + "${WIN32_PACKAGE_ROOT}/libxml2-2.7.8.win32" + "${WIN32_PACKAGE_ROOT}/libxslt-1.1.26.win32" + "${WIN32_PACKAGE_ROOT}/iconv-1.9.2.win32" + "${FREETYPE_ROOT}" + "${WIN32_PACKAGE_ROOT}/glew-1.5.8" + "${FTGL_ROOT}" + "${WIN32_PACKAGE_ROOT}/sqlite3-3.8.10.1" + "${WIN32_PACKAGE_ROOT}/db-4.6.21" + ) +endif() + +############################################################################ +# +# Build revision stuff +# This is needed for some use cases +if (EXISTS ${top_src_dir}/.svn) + include(FindSubversion) + Subversion_WC_INFO(${top_src_dir} TOOLKIT) + Subversion_WC_INFO(${top_src_dir}/src/corelib CORELIB) +else() + set(TOOLKIT_WC_REVISION 0) + set(TOOLKIT_WC_URL "") + set(CORELIB_WC_REVISION 0) + set(CORELIB_WC_URL "") +endif() + +set(NCBI_SUBVERSION_REVISION ${TOOLKIT_WC_REVISION}) +message(STATUS "SVN revision = ${TOOLKIT_WC_REVISION}") +message(STATUS "SVN URL = ${TOOLKIT_WC_URL}") + +if ("$ENV{NCBI_TEAMCITY_BUILD_NUMBER}" STREQUAL "") + set(NCBI_TEAMCITY_BUILD_NUMBER 0) + message(STATUS "TeamCity build number = ${NCBI_TEAMCITY_BUILD_NUMBER}") +endif() + +set(NCBI_SC_VERSION 0) +if (NOT "${CORELIB_WC_URL}" STREQUAL "") + string(REGEX REPLACE ".*/([0-9]+)\\.[0-9]+/.*" "\\1" "${CORELIB_WC_URL}" _SC_VER) + string(LENGTH "${_SC_VER}" _SC_VER_LEN) + if (${_SC_VER_LEN} LESS 10 AND NOT "${_SC_VER}" STREQUAL "") + set(NCBI_SC_VERSION ${_SC_VER}) + message(STATUS "Stable Components Number = ${NCBI_SC_VERSION}") + endif() +endif() + +# +# Initial messaging about some important stuff +# +message(STATUS "CMake Build Type: ${CMAKE_BUILD_TYPE}") +message(STATUS "Build shared libraries: ${BUILD_SHARED_LIBS}") + +# pass these back for ccache to pick up +set(ENV{CCACHE_UMASK} 002) +set(ENV{CCACHE_BASEDIR} ${top_src_dir}) + +if (NOT buildconf) + set(buildconf "${CMAKE_BUILD_TYPE}MT64") + set(buildconf0 ${CMAKE_BUILD_TYPE}) +endif (NOT buildconf) + +get_filename_component(top_src_dir "${top_src_dir}" REALPATH) +get_filename_component(abs_top_src_dir "${abs_top_src_dir}" REALPATH) +get_filename_component(build_root "${build_root}" REALPATH) +get_filename_component(includedir "${includedir}" REALPATH) + +get_filename_component(EXECUTABLE_OUTPUT_PATH "${build_root}/../bin" REALPATH) +get_filename_component(LIBRARY_OUTPUT_PATH "${build_root}/../lib" REALPATH) + +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/build-system/cmake/" ${CMAKE_MODULE_PATH}) + +# Establishing compiler definitions +include(${top_src_dir}/src/build-system/cmake/CMakeChecks.compiler.cmake) + +# Establishing sane RPATH definitions +# use, i.e. don't skip the full RPATH for the build tree +SET(CMAKE_SKIP_BUILD_RPATH FALSE) + +# when building, use the install RPATH already +SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) + +SET(CMAKE_INSTALL_RPATH "/$ORIGIN/../lib") + +#this add RUNPATH to binaries (RPATH is already there anyway), which makes it more like binaries built by C++ Toolkit +SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--enable-new-dtags") + +# add the automatically determined parts of the RPATH +# which point to directories outside the build tree to the install RPATH +SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH true) + + +############################################################################ +# +# Testing +enable_testing() + + +# +# Basic checks +# +include(${top_src_dir}/src/build-system/cmake/CMakeChecks.basic-checks.cmake) + +# +# Framework for dealing with external libraries +# +include(${top_src_dir}/src/build-system/cmake/FindExternalLibrary.cmake) + +############################################################################ +# +# PCRE additions +# +include(${top_src_dir}/src/build-system/cmake/CMakeChecks.pcre.cmake) + +############################################################################ +# +# Compression libraries +include(${top_src_dir}/src/build-system/cmake/CMakeChecks.compress.cmake) + + + +############################################################################ +# +# OS-specific settings +include(${top_src_dir}/src/build-system/cmake/CMakeChecks.os.cmake) ################################# # Some platform-specific system libs that can be linked eventually -set(THREAD_LIBS -lpthread) -set(NETWORK_LIBS -lnsl) -set(MATH_LIBS -lm) -set(KSTAT_LIBS ) -set(RPCSVC_LIBS ) -set(CRYPT_LIBS -lcrypt) -set(RT_LIBS -lrt) -set(DEMANGLE_LIBS ) -set(ICONV_LIBS ) -set(UUID_LIBS -luuid) +set(THREAD_LIBS ${CMAKE_THREAD_LIBS_INIT}) +if (WIN32) + set(KSTAT_LIBS "") + set(RPCSVC_LIBS "") + set(DEMANGLE_LIBS "") + set(UUID_LIBS "") + set(NETWORK_LIBS "ws2_32.lib") + set(RT_LIBS "") + set(MATH_LIBS "") + set(CURL_LIBS "") + set(MYSQL_INCLUDE_DIR "") +endif() + +find_library(UUID_LIBS NAMES uuid) +find_library(CRYPT_LIBS NAMES crypt) +find_library(MATH_LIBS NAMES m) + +if (APPLE) + find_library(NETWORK_LIBS c) + find_library(RT_LIBS c) +else (APPLE) + find_library(NETWORK_LIBS nsl) + find_library(RT_LIBS rt) +endif (APPLE) + +# +# Basic Library Definitions +# FIXME: get rid of these +# + +set(ORIG_LIBS ${RT_LIBS} ${MATH_LIBS} ${CMAKE_THREAD_LIBS_INIT}) +set(ORIG_C_LIBS ${MATH_LIBS} ${CMAKE_THREAD_LIBS_INIT}) +set(C_LIBS ${ORIG_C_LIBS}) # ############################################################ @@ -197,251 +267,228 @@ set(UUID_LIBS -luuid) set(LIBS ${LIBS} ${DL_LIBS} ${CMAKE_THREAD_LIBS_INIT}) +# +# NCBI-specific library subsets +# NOTE: +# these should be eliminated or simplified; they're not needed +# set(LOCAL_LBSM ncbi_lbsm ncbi_lbsm_ipc ncbi_lbsmd) -set(NCBI_CRYPT ncbi_crypt) - -# non-public (X)CONNECT extensions -set(CONNEXT connext) -set(XCONNEXT xconnext) - -# NCBI C++ API for BerkeleyDB -set(BDB_LIB bdb) -set(BDB_CACHE_LIB ncbi_xcache_bdb) - -# Possibly absent DBAPI drivers (depending on whether the relevant -# 3rd-party libraries are present, and whether DBAPI was disabled altogether) -set(DBAPI_DRIVER dbapi_driver) -set(DBAPI_CTLIB ncbi_xdbapi_ctlib) -set(DBAPI_DBLIB ncbi_xdbapi_dblib) -set(DBAPI_MYSQL ncbi_xdbapi_mysql) -#DBAPI_ODBC +############################################################################ +# +# OS-specific settings +if (UNIX) + find_library(GMP_LIB LIBS gmp HINTS "$ENV{NCBI}/gmp-6.0.0a/lib64/") + find_library(IDN_LIB LIBS idn HINTS "/lib64") + find_library(NETTLE_LIB LIBS nettle HINTS "$ENV{NCBI}/nettle-3.1.1/lib64") + find_library(HOGWEED_LIB LIBS hogweed HINTS "$ENV{NCBI}/nettle-3.1.1/lib64") +elseif (WIN32) + set(GMP_LIB "") + set(IDN_LIB "") + set(NETTLE_LIB "") + set(HOGWEED_LIB "") +endif() -# Compression libraries -include(FindZLIB) -find_package(ZLIB) -include(FindBZip2) -find_package(BZip2) -FIND_PATH(LZO_INCLUDE_DIR lzo/lzoconf.h - ${LZO_ROOT}/include/lzo/ - ${NCBI_TOOLS_ROOT}/lzo-2.05/include/ - /usr/include/lzo/ - /usr/local/include/lzo/ - /sw/lib/lzo/ - /sw/local/lib/lzo/ - ) -FIND_LIBRARY(LZO_LIBRARIES NAMES lzo2 - PATHS - ${LZO_ROOT}/lib - ${NCBI_TOOLS_ROOT}/lzo-2.05/lib64/ - ${NCBI_TOOLS_ROOT}/lzo-2.05/lib/ - /sw/lib - /sw/local/lib - /usr/lib - /usr/local/lib - ) - -set(Z_INCLUDE ${ZLIB_INCLUDE_DIRS}) -set(Z_LIBS ${ZLIB_LIBRARIES}) -set(Z_LIB) -set(BZ2_INCLUDE ${BZIP2_INCLUDE_DIRS}) -set(BZ2_LIBS ${BZIP2_LIBRARIES}) -set(BZ2_LIB) -set(LZO_INCLUDE ${LZO_INCLUDE_DIR}) -set(LZO_LIBS ${LZO_LIBRARIES}) - - -set(CMPRS_INCLUDE ${Z_INCLUDE} ${BZ2_INCLUDE} ${LZO_INCLUDE}) -set(CMPRS_LIBS ${Z_LIBS} ${BZ2_LIBS} ${LZO_LIBS}) -set(COMPRESS_LIBS xcompress ${CMPRS_LIBS}) - - -# Perl-Compatible Regular Expressions (PCRE) -include(FindPCRE) -find_package(PCRE) -set(PCRE_INCLUDE ${PCRE_INCLUDE_DIR}) -set(PCRE_LIBS ${PCRE_LIBRARIES}) -set(PCRE_LIB) -set(PCREPOSIX_LIBS -lpcreposix -lpcre) -set(PCRE_LIB) - -# OpenSSL, GnuTLS: headers and libs; TLS_* points to GNUTLS_* by preference. -set(GCRYPT_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/libgcrypt-1.4.3/include - ${XYY}${NCBI_TOOLS_ROOT}/libgpg-error-1.6/include) -set(GCRYPT_LIBS -L${NCBI_TOOLS_ROOT}/libgcrypt-1.4.3/GCC401-ReleaseMT64/lib -Wl,-rpath,/opt/ncbi/64/libgcrypt-1.4.3/GCC401-ReleaseMT64/lib:${NCBI_TOOLS_ROOT}/libgcrypt-1.4.3/GCC401-ReleaseMT64/lib -lgcrypt -L${NCBI_TOOLS_ROOT}/libgpg-error-1.6/GCC401-ReleaseMT64/lib -Wl,-rpath,/opt/ncbi/64/libgpg-error-1.6/GCC401-ReleaseMT64/lib:${NCBI_TOOLS_ROOT}/libgpg-error-1.6/GCC401-ReleaseMT64/lib -lgpg-error -lz) -set(OPENSSL_INCLUDE) -set(OPENSSL_LIBS -lssl -lcrypto) -set(OPENSSL_STATIC_LIBS -lssl -lcrypto) -set(TLS_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/libgcrypt-1.4.3/include - ${XYY}${NCBI_TOOLS_ROOT}/libgpg-error-1.6/include - ${XYY}${NCBI_TOOLS_ROOT}/gnutls-2.4.2/include) -set(TLS_LIBS -L${NCBI_TOOLS_ROOT}/gnutls-2.4.2/GCC401-ReleaseMT64/lib -Wl,-rpath,/opt/ncbi/64/gnutls-2.4.2/GCC401-ReleaseMT64/lib:${NCBI_TOOLS_ROOT}/gnutls-2.4.2/GCC401-ReleaseMT64/lib -lgnutls -L${NCBI_TOOLS_ROOT}/libgcrypt-1.4.3/GCC401-ReleaseMT64/lib -Wl,-rpath,/opt/ncbi/64/libgcrypt-1.4.3/GCC401-ReleaseMT64/lib:${NCBI_TOOLS_ROOT}/libgcrypt-1.4.3/GCC401-ReleaseMT64/lib -lgcrypt -L${NCBI_TOOLS_ROOT}/libgpg-error-1.6/GCC401-ReleaseMT64/lib -Wl,-rpath,/opt/ncbi/64/libgpg-error-1.6/GCC401-ReleaseMT64/lib:${NCBI_TOOLS_ROOT}/libgpg-error-1.6/GCC401-ReleaseMT64/lib -lgpg-error -lz) - -#include(FindGnuTLS) find_package(GnuTLS) -set(GNUTLS_INCLUDE ${GNUTLS_INCLUDE_DIR}) -set(GNUTLS_LIBS ${GNUTLS_LIBRARIES}) +if (GnuTLS_FOUND) + set(GNUTLS_LIBRARIES ${GNUTLS_LIBRARIES} ${ZLIB_LIBRARIES} ${IDN_LIB} ${RT_LIBS} ${HOGWEED_LIB} ${NETTLE_LIB} ${GMP_LIB}) + set(GNUTLS_LIBS ${GNUTLS_LIBRARIES}) +endif() +############################################################################ +# # Kerberos 5 (via GSSAPI) -set(KRB5_INCLUDE) -set(KRB5_LIBS -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err) +# FIXME: replace with native CMake check +# +find_external_library(KRB5 INCLUDES gssapi/gssapi_krb5.h LIBS gssapi_krb5 krb5 k5crypto com_err) + +############################################################################ # # Sybase stuff -set(SYBASE_INCLUDE ${XYY}/export/home/sybase/clients/12.5-64bit/include) -set(SYBASE_LIBS -L/export/home/sybase/clients/12.5-64bit/lib64 -Wl,-rpath,/export/home/sybase/clients/12.5-64bit/lib64 -lblk_r64 -lct_r64 -lcs_r64 -lsybtcl_r64 -lcomn_r64 -lintl_r64) -set(SYBASE_DLLS) -set(SYBASE_DBLIBS -L/export/home/sybase/clients/12.5-64bit/lib64 -Wl,-rpath,/export/home/sybase/clients/12.5-64bit/lib64 -lsybdb64) +#find_package(Sybase) +if (WIN32) + find_external_library(Sybase + DYNAMIC_ONLY + INCLUDES sybdb.h + #LIBS libsybblk + LIBS libsybblk libsybdb64 libsybct libsybcs + INCLUDE_HINTS "${WIN32_PACKAGE_ROOT}\\sybase-15.5\\include" + LIBS_HINTS "${WIN32_PACKAGE_ROOT}\\sybase-15.5\\lib") +else (WIN32) + find_external_library(Sybase + DYNAMIC_ONLY + INCLUDES sybdb.h + LIBS sybblk_r64 sybdb64 sybct_r64 sybcs_r64 sybtcl_r64 sybcomn_r64 sybintl_r64 sybunic64 + HINTS "/opt/sybase/clients/15.7-64bit/OCS-15_0/") +endif (WIN32) + +if (NOT SYBASE_FOUND) + message(FATAL "no sybase found." ) +endif (NOT SYBASE_FOUND) + +set(SYBASE_DBLIBS "${SYBASE_LIBS}") + +############################################################################ # # FreeTDS -set(ftds64 ftds) -set(FTDS64_CTLIB_LIBS ${ICONV_LIBS} ${KRB5_LIBS}) -set(FTDS64_CTLIB_LIB ct_ftds64 tds_ftds64) -set(FTDS64_CTLIB_INCLUDE ${XYY}${includedir}/dbapi/driver/ftds64/freetds) -set(FTDS64_LIBS ${FTDS64_CTLIB_LIBS}) -set(FTDS64_LIB ${FTDS64_CTLIB_LIB}) +# FIXME: do we need these anymore? +# +set(ftds64 ftds64) +set(FTDS64_CTLIB_INCLUDE ${includedir}/dbapi/driver/ftds64/freetds) set(FTDS64_INCLUDE ${FTDS64_CTLIB_INCLUDE}) -set(FTDS_LIBS ${FTDS64_LIBS}) -set(FTDS_LIB ${FTDS64_LIB}) -set(FTDS_INCLUDE ${FTDS64_INCLUDE}) - -# MySQL: headers and libs -set(MYSQL_INCLUDE ${XYY}/usr/include/mysql) -set(MYSQL_LIBS -rdynamic -L/usr/lib64/mysql -Wl,-rpath,/usr/lib64/mysql -lmysqlclient_r -lz -lpthread -lcrypt -lnsl -lm -lpthread -lssl -lcrypto) - +set(ftds95 ftds95) +set(FTDS95_CTLIB_LIBS ${ICONV_LIBS} ${KRB5_LIBS}) +set(FTDS95_CTLIB_LIB ct_ftds95 tds_ftds95) +set(FTDS95_CTLIB_INCLUDE ${includedir}/dbapi/driver/ftds95/freetds) +set(FTDS95_LIBS ${FTDS95_CTLIB_LIBS}) +set(FTDS95_LIB ${FTDS95_CTLIB_LIB}) +set(FTDS95_INCLUDE ${FTDS95_CTLIB_INCLUDE}) + +set(ftds ftds95) +set(FTDS_LIBS ${FTDS95_LIBS}) +set(FTDS_LIB ${FTDS95_LIB}) +set(FTDS_INCLUDE ${FTDS95_INCLUDE}) + +#OpenSSL +find_package(OpenSSL) +if (OpenSSL_FOUND) + set(OpenSSL_LIBRARIES ${OpenSSL_LIBRARIES} ${Z_LIBS} ${DL_LIBS}) + set(OPENSSL_LIBS ${OpenSSL_LIBRARIES}) +endif() + +#EXTRALIBS were taken from mysql_config --libs +find_external_library(Mysql INCLUDES mysql/mysql.h LIBS mysqlclient EXTRALIBS ${Z_LIBS} ${CRYPT_LIBS} ${NETWORK_LIBS} ${MATH_LIBS} ${OPENSSL_LIBS}) + +############################################################################ # # BerkeleyDB -set(BERKELEYDB_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/BerkeleyDB/include) -set(BERKELEYDB_LIBS -L"${NCBI_TOOLS_ROOT}/BerkeleyDB/${CMAKE_BUILD_TYPE}" -ldb) -set(BERKELEYDB_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/BerkeleyDB-4.6.21.1/${buildconf0} -ldb-static) -set(BERKELEYDB_CXX_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/BerkeleyDB-4.6.21.1/${buildconf0} -ldb_cxx-static -ldb-static) -set(BERKELEYDB_CXX_LIBS -L${NCBI_TOOLS_ROOT}/BerkeleyDB-4.6.21.1/${buildconf0} -Wl,-rpath,/opt/ncbi/64/BerkeleyDB-4.6.21.1/${buildconf0}:${NCBI_TOOLS_ROOT}/BerkeleyDB-4.6.21.1/${buildconf0} -ldb_cxx -ldb) +include(${top_src_dir}/src/build-system/cmake/CMakeChecks.BerkeleyDB.cmake) # ODBC -set(ODBC_INCLUDE ${XYY}${includedir}/dbapi/driver/odbc/unix_odbc - ${XYY}${includedir0}/dbapi/driver/odbc/unix_odbc) +# FIXME: replace with native CMake check +# +set(ODBC_INCLUDE ${includedir}/dbapi/driver/odbc/unix_odbc + ${includedir0}/dbapi/driver/odbc/unix_odbc) set(ODBC_LIBS) -# PYTHON: headers and libs (default + specific versions) -set(PYTHON_INCLUDE ${XYY}/opt/python-2.5.1/include/python2.5 - ${XYY}/opt/python-2.5.1/include/python2.5) -set(PYTHON_LIBS -L/opt/python-2.5/lib -L/opt/python-2.5/lib/python2.5/config -Wl,-rpath,/opt/python-2.5/lib:/opt/python-2.5/lib/python2.5/config -lpython2.5 -lpthread -ldl -lutil -lm) -set(PYTHON23_INCLUDE) -set(PYTHON23_LIBS) -set(PYTHON24_INCLUDE) -set(PYTHON24_LIBS) -set(PYTHON25_INCLUDE ${XYY}/opt/python-2.5.1/include/python2.5 - ${XYY}/opt/python-2.5.1/include/python2.5) -set(PYTHON25_LIBS -L/opt/python-2.5/lib -L/opt/python-2.5/lib/python2.5/config -Wl,-rpath,/opt/python-2.5/lib:/opt/python-2.5/lib/python2.5/config -lpython2.5 -lpthread -ldl -lutil -lm) - -# Perl: executable, headers and libs -set(PERL /opt/perl-5.8.8/bin/perl) -set(PERL_INCLUDE ${XYY}/opt/perl-5.8.8/lib/5.8.8/x86_64-linux/CORE - ${XYY}/usr/include/gdbm) -set(PERL_LIBS -L/opt/perl-5.8.8/lib/5.8.8/x86_64-linux/CORE -Wl,-rpath,/opt/perl-5.8.8/lib/5.8.8/x86_64-linux/CORE -lperl -lnsl -lgdbm -ldb -ldl -lm -lcrypt -lutil -lc) - -# Java -set(JDK_INCLUDE) -set(JDK_PATH) - - -# Boost: headers and libs [use as ${BOOST_LIBPATH} ${BOOST_*_LIBS} ${RT_LIBS}] -include(FindBoost) -set(CMAKE_INCLUDE_PATH ${NCBI_TOOLS_ROOT}/boost-1.41.0/include) -set(CMAKE_LIBRARY_PATH ${NCBI_TOOLS_ROOT}/boost-1.41.0/lib) -find_package(Boost) -if (NOT Boost_FOUND) - message(WARNING "BOOST not found...") -endif (NOT Boost_FOUND) -#set(BOOST_INCLUDE ${Boost_INCLUDE_DIRS}) -set(BOOST_INCLUDE ${XYY}/netopt/ncbi_tools64/boost-1.53.0-ncbi1/include/boost-1_53) -set(BOOST_LIBPATH -L${NCBI_TOOLS_ROOT}/boost-1.53.0-ncbi1/lib -Wl,-rpath,/opt/ncbi/64/boost-1.53.0-ncbi1/lib:${NCBI_TOOLS_ROOT}/boost-1.53.0-ncbi1/lib) -set(BOOST_TAG -gcc48-mt-d-1_53-64) -set(BOOST_FILESYSTEM_LIBS -lboost_filesystem-gcc48-mt-d-1_53-64 -lboost_system-gcc48-mt-d-1_53-64) -set(BOOST_FILESYSTEM_STATIC_LIBS -lboost_filesystem-gcc48-mt-d-1_53-64-static -lboost_system-gcc48-mt-d-1_53-64-static) -set(BOOST_REGEX_LIBS -lboost_regex-gcc48-mt-d-1_53-64) -set(BOOST_REGEX_STATIC_LIBS -lboost_regex-gcc48-mt-d-1_53-64-static) -set(BOOST_SYSTEM_LIBS -lboost_system-gcc48-mt-d-1_53-64) -set(BOOST_SYSTEM_STATIC_LIBS -lboost_system-gcc48-mt-d-1_53-64-static) -set(BOOST_TEST_PEM_LIBS -lboost_prg_exec_monitor-gcc48-mt-d-1_53-64-static) -set(BOOST_TEST_PEM_STATIC_LIBS -lboost_prg_exec_monitor-gcc48-mt-d-1_53-64-static) -set(BOOST_TEST_TEM_LIBS -lboost_test_exec_monitor-gcc48-mt-d-1_53-64-static) -set(BOOST_TEST_TEM_STATIC_LIBS -lboost_test_exec_monitor-gcc48-mt-d-1_53-64-static) -set(BOOST_TEST_UTF_LIBS -lboost_unit_test_framework-gcc48-mt-d-1_53-64-static) -set(BOOST_TEST_UTF_STATIC_LIBS -lboost_unit_test_framework-gcc48-mt-d-1_53-64-static) -set(BOOST_THREAD_LIBS -lboost_thread-gcc48-mt-d-1_53-64 -lboost_system-gcc48-mt-d-1_53-64) -set(BOOST_THREAD_STATIC_LIBS -lboost_thread-gcc48-mt-d-1_53-64-static -lboost_system-gcc48-mt-d-1_53-64-static) -set(BOOST_TEST_LIBS ${BOOST_LIBPATH} ${BOOST_TEST_UTF_LIBS}) -set(BOOST_TEST_STATIC_LIBS ${BOOST_LIBPATH} ${BOOST_TEST_UTF_STATIC_LIBS}) -# Temporary, for backward compatibility, to be removed later: -set(BOOST_LIBS ${BOOST_TEST_LIBS}) -set(BOOST_STATIC_LIBS ${BOOST_TEST_STATIC_LIBS}) +# Python +find_external_library(Python + INCLUDES Python.h + LIBS python2.7 + INCLUDE_HINTS "/opt/python-2.7env/include/python2.7/" + LIBS_HINTS "/opt/python-2.7env/lib/") -# NCBI C Toolkit: headers and libs -set(NCBI_C_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/include64) -set(NCBI_C_LIBPATH "-L${NCBI_TOOLS_ROOT}/lib64") -set(NCBI_C_ncbi ncbi) +############################################################################ +# +# Boost settings +include(${top_src_dir}/src/build-system/cmake/CMakeChecks.boost.cmake) +############################################################################ +# +# NCBI C Toolkit: headers and libs +string(REGEX MATCH "DNCBI_INT8_GI|NCBI_STRICT_GI" INT8GI_FOUND "${CMAKE_CXX_FLAGS}") +if (NOT "${INT8GI_FOUND}" STREQUAL "") + if (EXISTS "${NCBI_TOOLS_ROOT}/ncbi/ncbi.gi64/") + set(NCBI_CTOOLKIT_PATH "${NCBI_TOOLS_ROOT}/ncbi/ncbi.gi64/") + elseif (EXISTS "${NCBI_TOOLS_ROOT}/ncbi.gi64") + set(NCBI_CTOOLKIT_PATH "${NCBI_TOOLS_ROOT}/ncbi.gi64/") + else () + set(NCBI_CTOOLKIT_PATH "${NCBI_TOOLS_ROOT}/ncbi/") + endif () +else () + set(NCBI_CTOOLKIT_PATH "${NCBI_TOOLS_ROOT}/ncbi/") +endif () + +if (EXISTS "${NCBI_CTOOLKIT_PATH}/include64" AND EXISTS "${NCBI_CTOOLKIT_PATH}/lib64") + set(NCBI_C_INCLUDE "${NCBI_CTOOLKIT_PATH}/include64") + set(NCBI_C_LIBPATH "${NCBI_CTOOLKIT_PATH}/lib64") + set(NCBI_C_ncbi "ncbi") + if (APPLE) + set(NCBI_C_ncbi ${NCBI_C_ncbi} -Wl,-framework,ApplicationServices) + endif () + set(HAVE_NCBI_C true) +elseif (WIN32) + set(NCBI_CTOOLKIT_WIN32 "//snowman/win-coremake/Lib/Ncbi/C_Toolkit/vs2015.64/c.current") + if (EXISTS "${NCBI_CTOOLKIT_WIN32}") + set(NCBI_C_INCLUDE "${NCBI_CTOOLKIT_WIN32}/include") + set(NCBI_C_LIBPATH "${NCBI_CTOOLKIT_WIN32}/lib") + set(NCBI_C_ncbi "ncbi.lib") + set(HAVE_NCBI_C true) + else() + set(HAVE_NCBI_C false) + endif() +else () + set(HAVE_NCBI_C false) +endif () + +message(STATUS "HAVE_NCBI_C = ${HAVE_NCBI_C}") +message(STATUS "NCBI_C_INCLUDE = ${NCBI_C_INCLUDE}") +message(STATUS "NCBI_C_LIBPATH = ${NCBI_C_LIBPATH}") + +############################################################################ +# # OpenGL: headers and libs (including core X dependencies) for code # not using other toolkits. (The wxWidgets variables already include # these as appropriate.) -set(OPENGL_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/include) -set(OPENGL_LIBS -L${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/lib64 -Wl,-rpath,/opt/ncbi/64/Mesa-7.0.2-ncbi2/lib64:${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/lib64 -lGLU -lGL -lXmu -lXt -lXext -lSM -lICE -lX11 ) -set(OPENGL_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/lib64 -Wl,-rpath,/opt/ncbi/64/Mesa-7.0.2-ncbi2/lib64:${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/lib64 -lGLU-static -lGL-static -lXmu -lXt -lXext -lSM -lICE -lX11 ) -set(OSMESA_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/include) -set(OSMESA_LIBS -L${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/lib64 -Wl,-rpath,/opt/ncbi/64/Mesa-7.0.2-ncbi2/lib64:${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/lib64 -lOSMesa -lGLU -lGL -lXmu -lXt -lXext -lSM -lICE -lX11 ) -set(OSMESA_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/lib64 -Wl,-rpath,/opt/ncbi/64/Mesa-7.0.2-ncbi2/lib64:${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/lib64 -lOSMesa-static -lGLU-static -lGL-static -lXmu -lXt -lXext -lSM -lICE -lX11 ) -set(GLUT_INCLUDE ) -set(GLUT_LIBS ) -set(GLEW_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/glew-1.5.8/GCC401-Debug64/include) -set(GLEW_LIBS -L${NCBI_TOOLS_ROOT}/glew-1.5.8/GCC401-Debug64/lib64 -Wl,-rpath,/opt/ncbi/64/glew-1.5.8/GCC401-Debug64/lib64:${NCBI_TOOLS_ROOT}/glew-1.5.8/GCC401-Debug64/lib64 -lGLEW) -set(GLEW_STATIC_LIBS ${NCBI_TOOLS_ROOT}/glew-1.5.8/GCC401-Debug64/lib/libGLEW-static.a) - +find_package(OpenGL) +if (WIN32) + set(GLEW_INCLUDE ${WIN32_PACKAGE_ROOT}/glew-1.5.8/include) + set(GLEW_LIBRARIES ${WIN32_PACKAGE_ROOT}/glew-1.5.8/lib/glew32mx.lib) +else() + find_package(GLEW) +endif() +find_package(OSMesa) +if (${OPENGL_FOUND}) + set(OPENGL_INCLUDE "${OPENGL_INCLUDE_DIR}") + set(OPENGL_LIBS "${OPENGL_LIBRARIES}") + + set(OPENGL_INCLUDE ${OPENGL_INCLUDE_DIRS}) + set(OPENGL_LIBS ${OPENGL_LIBRARIES}) + set(GLEW_INCLUDE ${GLEW_INCLUDE_DIRS}) + set(GLEW_LIBS ${GLEW_LIBRARIES}) + set(OSMESA_INCLUDE ${OSMesa_INCLUDE_DIRS} ${OPENGL_INCLUDE_DIRS}) + set(OSMESA_LIBS ${OSMesa_LIBRARIES} ${OPENGL_LIBRARIES}) + +endif() + +############################################################################ +# # wxWidgets -set(foo "${CMAKE_PREFIX_PATH}") -#set(CMAKE_PREFIX_PATH "${NCBI_TOOLS_ROOT}/wxwidgets/${CMAKE_BUILD_TYPE}/bin") -set(CMAKE_PREFIX_PATH "${NCBI_TOOLS_ROOT}/wxGTK/DebugMT64/bin") -FIND_PACKAGE(wxWidgets - COMPONENTS core gl base - OPTIONAL) -set(WXWIDGETS_INCLUDE "${wxWidgets_INCLUDE_DIRS}") -set(WXWIDGETS_LIBS "${wxWidgets_LIBRARIES}") -set(CMAKE_PREFIX_PATH "${foo}") -set(foo) -set(WXWIDGETS_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib -pthread ${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib/libwx_gtk2_xrc-2.9.a ${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib/libwx_gtk2_qa-2.9.a ${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib/libwx_base_net-2.9.a ${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib/libwx_gtk2_html-2.9.a ${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib/libwx_gtk2_adv-2.9.a ${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib/libwx_gtk2_core-2.9.a ${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib/libwx_base_xml-2.9.a ${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib/libwx_base-2.9.a -pthread -lgthread-2.0 -lX11 -lSM -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -lpng -ljpeg -ltiff -lexpat -lz -ldl ) -set(WXWIDGETS_GL_LIBS -L${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib -pthread -lwx_gtk2_gl-2.9 -lwx_base-2.9 ) -set(WXWIDGETS_GL_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib -pthread ${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib/libwx_gtk2_gl-2.9.a ${NCBI_TOOLS_ROOT}/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib/libwx_base-2.9.a -L${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/lib64 -Wl,-rpath,/opt/ncbi/64/Mesa-7.0.2-ncbi2/lib64:${NCBI_TOOLS_ROOT}/Mesa-7.0.2-ncbi2/lib64 -lGLU-static -lGL-static -lXmu -lXt -lXext -lSM -lICE -lX11 -lz -ldl -lm ) - -set(WXWIDGETS_INCLUDE ${XYY}/usr/include/gtk-2.0 - ${XYY}/usr/lib64/gtk-2.0/include - ${XYY}/usr/include/atk-1.0 - ${XYY}/usr/include/cairo - ${XYY}/usr/include/pango-1.0 - ${XYY}/usr/include/glib-2.0 - ${XYY}/usr/lib64/glib-2.0/include - ${XYY}/usr/include/pixman-1 - ${XYY}/usr/include/freetype2 - ${XYY}/usr/include/libpng12 - ${XYY}/netopt/ncbi_tools64/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib/wx/include/gtk2-ansi-2.9 - ${XYY}/netopt/ncbi_tools64/wxWidgets-2.9.5-ncbi1/include/wx-2.9) -set(WXWIDGETS_LIBS -L/netopt/ncbi_tools64/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib -Wl,-rpath,/opt/ncbi/64/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib:/netopt/ncbi_tools64/wxWidgets-2.9.5-ncbi1/GCC442-DebugMT64/lib -pthread -lwx_gtk2_richtext-2.9 -lwx_gtk2_aui-2.9 -lwx_gtk2_xrc-2.9 -lwx_gtk2_html-2.9 -lwx_gtk2_qa-2.9 -lwx_gtk2_adv-2.9 -lwx_gtk2_core-2.9 -lwx_base_xml-2.9 -lwx_base_net-2.9 -lwx_base-2.9 -pthread -lgthread-2.0 -lX11 -lSM -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangocairo-1.0 -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 -lglib-2.0 -lpng -ljpeg -ltiff -lexpat -lz -ldl) - - - - +include(${top_src_dir}/src/build-system/cmake/CMakeChecks.wxwidgets.cmake) # Fast-CGI -set(FASTCGI_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/fcgi-current/include64) -set(FASTCGI_LIBS -L${NCBI_TOOLS_ROOT}/fcgi-2.4.0/altlib64 -Wl,-rpath,/opt/ncbi/64/fcgi-2.4.0/altlib64:${NCBI_TOOLS_ROOT}/fcgi-2.4.0/altlib64 -lfcgi -lnsl) +if (APPLE) + find_external_library(FastCGI + INCLUDES fastcgi.h + LIBS fcgi + HINTS "${NCBI_TOOLS_ROOT}/fcgi-2.4.0") +else () + if ("${BUILD_SHARED_LIBS}" STREQUAL "OFF") + find_external_library(FastCGI + INCLUDES fastcgi.h + LIBS fcgi + INCLUDE_HINTS "${NCBI_TOOLS_ROOT}/fcgi-2.4.0/include" + LIBS_HINTS "${NCBI_TOOLS_ROOT}/fcgi-2.4.0/lib" + EXTRALIBS ${NETWORK_LIBS}) + else () + find_external_library(FastCGI + INCLUDES fastcgi.h + LIBS fcgi + INCLUDE_HINTS "${NCBI_TOOLS_ROOT}/fcgi-2.4.0/include" + LIBS_HINTS "${NCBI_TOOLS_ROOT}/fcgi-2.4.0/shlib" + EXTRALIBS ${NETWORK_LIBS}) + endif() +endif() + # Fast-CGI lib: (module to add to the "xcgi" library) set(FASTCGI_OBJS fcgibuf) - # NCBI SSS: headers, library path, libraries -set(NCBI_SSS_INCLUDE ${XYY}${incdir}/sss) +set(NCBI_SSS_INCLUDE ${incdir}/sss) set(NCBI_SSS_LIBPATH ) set(LIBSSSUTILS -lsssutils) set(LIBSSSDB -lsssdb -lssssys) @@ -461,139 +508,147 @@ set(LIBOB ) # LIBIMR should be empty for single-threaded builds set(LIBIMR ) - # IBM's International Components for Unicode -set(ICU_CONFIG ${NCBI_TOOLS_ROOT}/icu-49.1.1/GCC442-DebugMT/bin/icu-config) -set(ICU_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/icu-49.1.1/include ) -set(ICU_LIBS -L${NCBI_TOOLS_ROOT}/icu-49.1.1/GCC442-DebugMT/lib -Wl,-rpath,/opt/ncbi/64/icu-49.1.1/GCC442-DebugMT/lib:${NCBI_TOOLS_ROOT}/icu-49.1.1/GCC442-DebugMT/lib -licui18n -licuuc -licudata ) -set(ICU_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/icu-49.1.1/GCC442-DebugMT/lib -lsicui18n -lsicuuc -lsicudata ) - - -# XML/XSL support: -set(EXPAT_INCLUDE ) -set(EXPAT_LIBS -L${NCBI_TOOLS_ROOT}/expat-1.95.8/lib64 -Wl,-rpath,/opt/ncbi/64/expat-1.95.8/lib64:${NCBI_TOOLS_ROOT}/expat-1.95.8/lib64 -lexpat ) -set(EXPAT_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/expat-1.95.8/lib64 -Wl,-rpath,/opt/ncbi/64/expat-1.95.8/lib64:${NCBI_TOOLS_ROOT}/expat-1.95.8/lib64 -lexpat ) -set(SABLOT_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/Sablot-1.0.2/include) -set(SABLOT_LIBS -L${NCBI_TOOLS_ROOT}/Sablot-1.0.2/lib64 -Wl,-rpath,/opt/ncbi/64/Sablot-1.0.2/lib64:${NCBI_TOOLS_ROOT}/Sablot-1.0.2/lib64 -lsablot -L${NCBI_TOOLS_ROOT}/expat-1.95.8/lib64 -Wl,-rpath,/opt/ncbi/64/expat-1.95.8/lib64:${NCBI_TOOLS_ROOT}/expat-1.95.8/lib64 -lexpat ) -set(SABLOT_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/Sablot-1.0.2/lib64 -Wl,-rpath,/opt/ncbi/64/Sablot-1.0.2/lib64:${NCBI_TOOLS_ROOT}/Sablot-1.0.2/lib64 -lsablot -L${NCBI_TOOLS_ROOT}/expat-1.95.8/lib64 -Wl,-rpath,/opt/ncbi/64/expat-1.95.8/lib64:${NCBI_TOOLS_ROOT}/expat-1.95.8/lib64 -lexpat ) -set(LIBXML_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/include/libxml2 - ${XYY}${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/include) -set(LIBXML_LIBS -L${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/lib -Wl,-rpath,/opt/ncbi/64/libxml-2.7.8/${buildconf}/lib:${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/lib -lxml2 ) -set(LIBXML_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/lib -lxml2-static) -set(LIBXSLT_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/include/libxml2 - ${XYY}${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/include - ${XYY}${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/include) -set(LIBXSLT_MAIN_LIBS -L${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/lib -Wl,-rpath,/opt/ncbi/64/libxml-2.7.8/${buildconf}/lib:${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/lib -lxslt ) -set(LIBXSLT_MAIN_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/lib -lxslt-static) -set(XSLTPROC ${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/bin/xsltproc) -set(LIBEXSLT_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/include/libxml2 - ${XYY}${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/include - ${XYY}${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/include - ${XYY}${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/include) -set(LIBEXSLT_LIBS -L${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/lib -Wl,-rpath,/opt/ncbi/64/libxml-2.7.8/${buildconf}/lib:${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/lib -lexslt ) -set(LIBEXSLT_STATIC_LIBS=-L${NCBI_TOOLS_ROOT}/libxml-2.7.8/${buildconf}/lib -lexslt-static) -set(LIBXSLT_LIBS ${LIBEXSLT_LIBS} ${LIBXSLT_MAIN_LIBS}) -set(LIBXSLT_STATIC_LIBS ${LIBEXSLT_STATIC_LIBS} ${LIBXSLT_MAIN_STATIC_LIBS}) -set(XERCES_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/xerces-3.1.1/GCC442-DebugMT64/include) -set(XERCES_LIBS -L${NCBI_TOOLS_ROOT}/xerces-3.1.1/GCC442-DebugMT64/lib -Wl,-rpath,/opt/ncbi/64/xerces-3.1.1/GCC442-DebugMT64/lib:${NCBI_TOOLS_ROOT}/xerces-3.1.1/GCC442-DebugMT64/lib -lxerces-c) -set(XERCES_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/xerces-3.1.1/GCC442-DebugMT64/lib -lxerces-c-static -lcurl ) -set(XALAN_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/xalan-1.11~r1302529/GCC442-DebugMT64/include) -set(XALAN_LIBS -L${NCBI_TOOLS_ROOT}/xalan-1.11~r1302529/GCC442-DebugMT64/lib -Wl,-rpath,/opt/ncbi/64/xalan-1.11~r1302529/GCC442-DebugMT64/lib:${NCBI_TOOLS_ROOT}/xalan-1.11~r1302529/GCC442-DebugMT64/lib -lxalan-c -lxalanMsg) -set(XALAN_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/xalan-1.11~r1302529/GCC442-DebugMT64/lib -Wl,-rpath,/opt/ncbi/64/xalan-1.11~r1302529/GCC442-DebugMT64/lib:${NCBI_TOOLS_ROOT}/xalan-1.11~r1302529/GCC442-DebugMT64/lib -lxalan-c -lxalanMsg) -set(ZORBA_INCLUDE ) -set(ZORBA_LIBS ) -set(ZORBA_STATIC_LIBS ) - - -# OpenEye OEChem library: -set(OECHEM_INCLUDE ) -set(OECHEM_LIBS ) +find_external_library(ICU + INCLUDES unicode/ucnv.h + LIBS icui18n icuuc icudata + HINTS "${NCBI_TOOLS_ROOT}/icu-49.1.1") + + +############################################################################## +## LibXml2 / LibXsl +## +find_library(GCRYPT_LIBS NAMES gcrypt HINTS "$ENV{NCBI}/libgcrypt/${CMAKE_BUILD_TYPE}/lib") +find_library(GPG_ERROR_LIBS NAMES gpg-error HINTS "$ENV{NCBI}/libgpg-error/${CMAKE_BUILD_TYPE}/lib") +if (NOT GCRYPT_LIBS STREQUAL "GCRYPT_LIBS-NOTFOUND") + set(GCRYPT_FOUND True) + set(GCRYPT_LIBS ${GCRYPT_LIBS} ${GPG_ERROR_LIBS}) +else() + set(GCRYPT_FOUND False) +endif() + +# ICONV +# Windows requires special handling for this +if (WIN32) + find_external_library(iconv + INCLUDES iconv.h + LIBS iconv) +endif() + +find_package(LibXml2) +if (LIBXML2_FOUND) + set(LIBXML_INCLUDE ${LIBXML2_INCLUDE_DIR}) + set(LIBXML_LIBS ${LIBXML2_LIBRARIES}) + if (WIN32) + set(LIBXML_INCLUDE ${LIBXML_INCLUDE} ${ICONV_INCLUDE}) + set(LIBXML_LIBS ${LIBXML_LIBS} ${ICONV_LIBS}) + endif() +endif() + +find_package(LibXslt) +if (LIBXSLT_FOUND) + set(LIBXSLT_INCLUDE ${LIBXSLT_INCLUDE_DIR}) + set(LIBXSLT_LIBS ${LIBXSLT_EXSLT_LIBRARIES} ${LIBXSLT_LIBRARIES} ${LIBXML_LIBS}) + set(LIBEXSLT_INCLUDE ${LIBXSLT_INCLUDE_DIR}) + set(LIBEXSLT_LIBS ${LIBXSLT_EXSLT_LIBRARIES}) + if (GCRYPT_FOUND) + set(LIBXSLT_LIBS ${LIBXSLT_LIBS} ${GCRYPT_LIBS}) + set(LIBEXSLT_LIBS ${LIBEXSLT_LIBS} ${GCRYPT_LIBS}) + endif() +endif() + + +find_external_library(xerces + INCLUDES xercesc/dom/DOM.hpp + LIBS xerces-c + HINTS "${NCBI_TOOLS_ROOT}/xerces-3.1.1/GCC442-DebugMT64") + +find_external_library(xalan + INCLUDES xalanc/XalanTransformer/XalanTransformer.hpp + LIBS xalan-c xalanMsg + HINTS "${NCBI_TOOLS_ROOT}/xalan-1.11~r1302529/GCC442-DebugMT64") # Sun Grid Engine (libdrmaa): -set(SGE_INCLUDE ${XYY}/netopt/uge/include) -set(SGE_LIBS -L/netopt/uge/lib/lx-amd64 -Wl,-rpath,/netopt/uge/lib/lx-amd64 -ldrmaa ) +# libpath - /netmnt/uge/lib/lx-amd64/ +find_external_library(SGE + INCLUDES drmaa.h + LIBS drmaa + INCLUDE_HINTS "/netmnt/uge/include" + LIBS_HINTS "/netmnt/uge/lib/lx-amd64/") # muParser -set(MUPARSER_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/muParser-1.30/include) -set(MUPARSER_LIBS -L${NCBI_TOOLS_ROOT}/muParser-1.30/GCC-Debug64/lib -lmuparser ) +find_external_library(muparser + INCLUDES muParser.h + LIBS muparser + INCLUDE_HINTS "${NCBI_TOOLS_ROOT}/muParser-1.30/include" + LIBS_HINTS "${NCBI_TOOLS_ROOT}/muParser-1.30/GCC-Debug64/lib/") # HDF5 -set(HDF5_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/hdf5-1.8.3/GCC401-Debug64/include) -set(HDF5_LIBS -L${NCBI_TOOLS_ROOT}/hdf5-1.8.3/GCC401-Debug64/lib -Wl,-rpath,/opt/ncbi/64/hdf5-1.8.3/GCC401-Debug64/lib:${NCBI_TOOLS_ROOT}/hdf5-1.8.3/GCC401-Debug64/lib -lhdf5_cpp -lhdf5) - -# SQLite 3.x -set(SQLITE3_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/sqlite-3.7.13-ncbi1/include) -set(SQLITE3_LIBS -L${NCBI_TOOLS_ROOT}/sqlite-3.7.13-ncbi1/GCC-DebugMT64/lib -Wl,-rpath,/opt/ncbi/64/sqlite-3.7.13-ncbi1/GCC-DebugMT64/lib:${NCBI_TOOLS_ROOT}/sqlite-3.7.13-ncbi1/GCC-DebugMT64/lib -lsqlite3 ) -set(SQLITE3_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/sqlite-3.7.13-ncbi1/GCC-DebugMT64/lib -lsqlite3-static) -#set(SQLITE3_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/sqlite3/include) -#set(SQLITE3_LIBS -L"${NCBI_TOOLS_ROOT}/sqlite3/lib" -lsqlite3) +find_external_library(hdf5 + INCLUDES hdf5.h + LIBS hdf5 + HINTS "${NCBI_TOOLS_ROOT}/hdf5-1.8.3/GCC401-Debug64/") +############################################################################ +# +# SQLite3 +include(${top_src_dir}/src/build-system/cmake/CMakeChecks.sqlite3.cmake) +############################################################################ +# # Various image-format libraries -include(FindJPEG) -find_package(JPEG) +include(${top_src_dir}/src/build-system/cmake/CMakeChecks.image.cmake) -include(FindPNG) -find_package(PNG) +############################################################################# +## MongoDB -include(FindTIFF) -find_package(TIFF) +find_library(SASL2_LIBS sasl2) -include(FindGIF) -find_package(GIF) +if (NOT WIN32) + find_package(MongoCXX) +endif() +if (MONGOCXX_FOUND) + set(MONGOCXX_INCLUDE ${MONGOCXX_INCLUDE_DIRS} ${BSONCXX_INCLUDE_DIRS}) + set(MONGOCXX_LIB ${MONGOCXX_LIBPATH} ${MONGOCXX_LIBRARIES} ${BSONCXX_LIBRARIES} ${OPENSSL_LIBS} ${SASL2_LIBS}) +endif() +message(STATUS "MongoCXX Includes: ${MONGOCXX_INCLUDE}") -set(IMAGE_INCLUDE_DIR ${JPEG_INCLUDE_DIR} ${PNG_INCLUDE_DIR} ${TIFF_INCLUDE_DIR} ${GIF_INCLUDE_DIR}) -set(IMAGE_LIBS ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${TIFF_LIBRARIES} ${GIF_LIBRARIES}) +############################################################################## +## +## LevelDB -set(JPEG_INCLUDE ) -set(JPEG_LIBS -ljpeg ) -set(PNG_INCLUDE ) -set(PNG_LIBS -lpng -lz ) -set(TIFF_INCLUDE ) -set(TIFF_LIBS -ltiff -lz ) -set(GIF_INCLUDE ) -set(GIF_LIBS -lungif -lX11) -set(UNGIF_INCLUDE ) -set(UNGIF_LIBS -lungif -lX11) -set(XPM_INCLUDE ) -set(XPM_LIBS -lXpm -lX11) - -set(IMAGE_LIBS ${TIFF_LIBS} ${JPEG_LIBS} ${PNG_LIBS} ${GIF_LIBS} ${XPM_LIBS}) - - -# FreeType, FTGL -set(FREETYPE_INCLUDE ${XYY}/usr/include/freetype2) -set(FREETYPE_LIBS -lfreetype) -set(FTGL_INCLUDE ${XYY}/usr/include/freetype2 - ${XYY}${NCBI_TOOLS_ROOT}/ftgl-2.1.3-rc5/include) -set(FTGL_LIBS -L${NCBI_TOOLS_ROOT}/ftgl-2.1.3-rc5/GCC401-Debug64/lib -Wl,-rpath,/opt/ncbi/64/ftgl-2.1.3-rc5/GCC401-Debug64/lib:${NCBI_TOOLS_ROOT}/ftgl-2.1.3-rc5/GCC401-Debug64/lib -lftgl -lfreetype) +find_package(LEVELDB + PATHS + /panfs/pan1/gpipe/ThirdParty/leveldb-1.20 + /usr/local + /usr + NO_DEFAULT_PATH +) # libmagic (file-format identification) -set(MAGIC_INCLUDE ) -set(MAGIC_LIBS -lmagic ) +find_library(MAGIC_LIBS magic) # libcurl (URL retrieval) -set(CURL_INCLUDE ) -set(CURL_LIBS -lcurl ) +find_library(CURL_LIBS curl) # libmimetic (MIME handling) -set(MIMETIC_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/mimetic-0.9.7-ncbi1/include) -set(MIMETIC_LIBS -L${NCBI_TOOLS_ROOT}/mimetic-0.9.7-ncbi1/GCC481-Debug64/lib -Wl,-rpath,/opt/ncbi/64/mimetic-0.9.7-ncbi1/GCC481-Debug64/lib:${NCBI_TOOLS_ROOT}/mimetic-0.9.7-ncbi1/GCC481-Debug64/lib -lmimetic ) +find_external_library(mimetic + INCLUDES mimetic/mimetic.h + LIBS mimetic + HINTS "${NCBI_TOOLS_ROOT}/mimetic-0.9.7-ncbi1/") # libgSOAP++ -set(GSOAP_PATH ${NCBI_TOOLS_ROOT}/gsoap-2.8.15) -set(GSOAP_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/gsoap-2.8.15/include) -set(GSOAP_LIBS -L${NCBI_TOOLS_ROOT}/gsoap-2.8.15/GCC442-DebugMT64/lib -Wl,-rpath,/opt/ncbi/64/gsoap-2.8.15/GCC442-DebugMT64/lib:${NCBI_TOOLS_ROOT}/gsoap-2.8.15/GCC442-DebugMT64/lib -lgsoapssl++ -lssl -lcrypto -lz ) +find_external_library(gsoap + INCLUDES stdsoap2.h + LIBS gsoapssl++ + INCLUDE_HINTS "${NCBI_TOOLS_ROOT}/gsoap-2.8.15/include" + LIBS_HINTS "${NCBI_TOOLS_ROOT}/gsoap-2.8.15/GCC442-DebugMT64/lib/" + EXTRALIBS ${Z_LIBS}) + set(GSOAP_SOAPCPP2 ${NCBI_TOOLS_ROOT}/gsoap-2.8.15/GCC442-DebugMT64/bin/soapcpp2) set(GSOAP_WSDL2H ${NCBI_TOOLS_ROOT}/gsoap-2.8.15/GCC442-DebugMT64/bin/wsdl2h) -# MongoDB -set(MONGODB_INCLUDE ${XYY}${NCBI_TOOLS_ROOT}/boost-1.53.0-ncbi1/include/boost-1_53 -Wno-unused-local-typedefs - ${XYY}${NCBI_TOOLS_ROOT}/mongodb-2.4.6/include) -set(MONGODB_LIBS -L${NCBI_TOOLS_ROOT}/mongodb-2.4.6/lib -Wl,-rpath,/opt/ncbi/64/mongodb-2.4.6/lib:${NCBI_TOOLS_ROOT}/mongodb-2.4.6/lib -lmongoclient -L${NCBI_TOOLS_ROOT}/boost-1.53.0-ncbi1/lib -Wl,-rpath,/opt/ncbi/64/boost-1.53.0-ncbi1/lib:${NCBI_TOOLS_ROOT}/boost-1.53.0-ncbi1/lib -lboost_filesystem-gcc48-mt-d-1_53-64 -lboost_thread-gcc48-mt-d-1_53-64 -lboost_system-gcc48-mt-d-1_53-64) -set(MONGODB_STATIC_LIBS -L${NCBI_TOOLS_ROOT}/mongodb-2.4.6/lib -Wl,-rpath,/opt/ncbi/64/mongodb-2.4.6/lib:${NCBI_TOOLS_ROOT}/mongodb-2.4.6/lib -lmongodb -L${NCBI_TOOLS_ROOT}/boost-1.53.0-ncbi1/lib -Wl,-rpath,/opt/ncbi/64/boost-1.53.0-ncbi1/lib:${NCBI_TOOLS_ROOT}/boost-1.53.0-ncbi1/lib -lboost_filesystem-gcc48-mt-d-1_53-64-static -lboost_thread-gcc48-mt-d-1_53-64-static -lboost_system-gcc48-mt-d-1_53-64-static) - # Compress set(COMPRESS_LDEP ${CMPRS_LIB}) set(COMPRESS_LIBS xcompress ${COMPRESS_LDEP}) @@ -604,40 +659,10 @@ set(COMPRESS_LIBS xcompress ${COMPRESS_LDEP}) ################################# -set(SEQ_LIBS seq seqcode sequtil) -set(SOBJMGR_LDEP genome_collection seqedit seqset ${SEQ_LIBS} pub medline - biblio general-lib xser xutil xncbi) -set(SOBJMGR_LIBS xobjmgr ${SOBJMGR_LDEP}) +set(SOBJMGR_LIBS xobjmgr) set(ncbi_xreader_pubseqos ncbi_xreader_pubseqos) set(ncbi_xreader_pubseqos2 ncbi_xreader_pubseqos2) - -set(GENBANK_READER_LDEP ${XCONNEXT} xconnect id1 id2 seqsplit ${COMPRESS_LIBS} ${SOBJMGR_LIBS}) -set(GENBANK_READER_LIBS ncbi_xreader ${GENBANK_READER_LDEP}) -set(GENBANK_READER_PUBSEQOS_LDEP ${XCONNEXT} xconnect ${DBAPI_DRIVER} ${GENBANK_READER_LIBS}) -set(GENBANK_READER_PUBSEQOS_LIBS ${ncbi_xreader_pubseqos} ${GENBANK_READER_PUBSEQOS_LDEP}) -set(GENBANK_LDEP - ncbi_xreader_id1 ncbi_xreader_id2 ncbi_xreader_cache - ${GENBANK_READER_PUBSEQOS_LIBS}) -set(GENBANK_LIBS ncbi_xloader_genbank ${GENBANK_LDEP}) - - - -set(GENBANK_READER_ID1_LDEP xconnect id1 ${GENBANK_READER_LIBS}) -set(GENBANK_READER_ID1_LIBS ncbi_xreader_id1 ${GENBANK_READER_ID1_LDEP}) - -set(GENBANK_READER_ID2_LDEP xconnect id2 seqsplit ${GENBANK_READER_LIBS}) -set(GENBANK_READER_ID2_LIBS ncbi_xreader_id2 ${GENBANK_READER_ID2_LDEP}) - -set(GENBANK_READER_CACHE_LDEP ${GENBANK_READER_LIBS}) -set(GENBANK_READER_CACHE_LIBS ncbi_xreader_cache ${GENBANK_READER_CACHE_LDEP}) - -set(GENBANK_READER_GICACHE_LDEP ${GENBANK_READER_LIBS}) -set(GENBANK_READER_GICACHE_LIBS ncbi_xreader_gicache - ${GENBANK_READER_GICACHE_LDEP}) - - -# Interdependent sequence libraries + seqcode. Does not include seqset. -set(OBJMGR_LIBS ${GENBANK_LIBS}) +set(OBJMGR_LIBS ncbi_xloader_genbank) # Overlapping with qall is poor, so we have a second macro to make it @@ -651,30 +676,39 @@ set(QOBJMGR_STATIC_LIBS ${QOBJMGR_ONLY_LIBS} qall) set(EUTILS_LIBS eutils egquery elink epost esearch espell esummary linkout einfo uilist ehistory) -# Object readers -set(OBJREAD_LIBS xobjread variation creaders submit) - -# formatting code -set(XFORMAT_LIBS xformat gbseq submit mlacli mla medlars pubmed valid) - - - -set(SRA_INCLUDE ${XYY}${includedir}/../src/sra/sdk/interfaces - ${XYY}${top_srcdir}/src/sra/sdk/interfaces) - -# For internal use; ${NO_STRICT_ALIASING} technically belongs in C(XX)FLAGS, -# but listing it here is more convenient and should be safe. -set(SRA_INTERNAL_CPPFLAGS " -D_GNU_SOURCE ${D_SFX} -DLIBPREFIX=lib -DSHLIBEXT=${DLL}${dll_ext} ${NO_STRICT_ALIASING}") - -set(SRA_SDK_SYSLIBS ${CURL_LIBS} ${NETWORK_LIBS} ${BZ2_LIBS} ${Z_LIBS} ${DL_LIBS}) - -set(SRA_SDK_LIBS ncbi-vdb-read ${BZ2_LIB} ${Z_LIB}) -set(SRAXF_LIBS ${SRA_SDK_LIBS}) -set(SRA_LIBS ${SRA_SDK_LIBS}) -set(BAM_LIBS ${SRA_SDK_LIBS}) -set(SRAREAD_LDEP ${SRA_SDK_LIBS}) -set(SRAREAD_LIBS sraread ${SRA_SDK_LIBS}) +# +# SRA/VDB stuff +if (WIN32) + find_external_library(VDB + INCLUDES sra/sradb.h + LIBS ncbi-vdb + INCLUDE_HINTS "\\\\snowman\\trace_software\\vdb\\vdb-versions\\2.8.0\\interfaces" + LIBS_HINTS "\\\\snowman\\trace_software\\vdb\\vdb-versions\\2.8.0\\win\\release\\x86_64\\lib") +else (WIN32) + find_external_library(VDB + INCLUDES sra/sradb.h + LIBS ncbi-vdb + INCLUDE_HINTS "/opt/ncbi/64/trace_software/vdb/vdb-versions/2.8.0/interfaces" + LIBS_HINTS "/opt/ncbi/64/trace_software/vdb/vdb-versions/2.8.0/linux/release/x86_64/lib") +endif (WIN32) + +if (${VDB_FOUND}) + if (WIN32) + set(VDB_INCLUDE "${VDB_INCLUDE}" "${VDB_INCLUDE}\\os\\win" "${VDB_INCLUDE}\\cc\\vc++\\x86_64" "${VDB_INCLUDE}\\cc\\vc++") + else (WIN32) + set(VDB_INCLUDE "${VDB_INCLUDE}" "${VDB_INCLUDE}/os/linux" "${VDB_INCLUDE}/os/unix" "${VDB_INCLUDE}/cc/gcc/x86_64" "${VDB_INCLUDE}/cc/gcc") + endif(WIN32) + set(SRA_INCLUDE ${VDB_INCLUDE}) + set(SRA_SDK_SYSLIBS ${VDB_LIBS}) + set(SRA_SDK_LIBS ${VDB_LIBS}) + set(SRAXF_LIBS ${SRA_SDK_LIBS}) + set(SRA_LIBS ${SRA_SDK_LIBS}) + set(BAM_LIBS ${SRA_SDK_LIBS}) + set(SRAREAD_LDEP ${SRA_SDK_LIBS}) + set(SRAREAD_LIBS sraread ${SRA_SDK_LIBS}) + set(HAVE_NCBI_VDB 1) +endif () # Makefile.blast_macros.mk set(BLAST_DB_DATA_LOADER_LIBS ncbi_xloader_blastdb ncbi_xloader_blastdb_rmt) @@ -686,7 +720,7 @@ set(BLAST_INPUT_LIBS blastinput set(BLAST_FORMATTER_LIBS ${BLAST_INPUT_LIBS}) # Libraries required to link against the internal BLAST SRA library -set(BLAST_SRA_LIBS=blast_sra ${SRAXF_LIBS} vxf ${SRA_LIBS}) +set(BLAST_SRA_LIBS blast_sra ${SRAXF_LIBS} vxf ${SRA_LIBS}) # BLAST_FORMATTER_LIBS and BLAST_INPUT_LIBS need $BLAST_LIBS set(BLAST_LIBS xblast xalgoblastdbindex composition_adjustment @@ -696,42 +730,109 @@ ${OBJREAD_LIBS} xnetblastcli xnetblast blastdb scoremat tables xalnmgr) # SDBAPI stuff -set(SDBAPI_LIB sdbapi ncbi_xdbapi_ftds ${FTDS_LIB} dbapi dbapi_driver ${XCONNEXT}) -set(SDBAPI_LIBS ${FTDS_LIBS}) +set(SDBAPI_LIB sdbapi) # ncbi_xdbapi_ftds ${FTDS_LIB} dbapi dbapi_driver ${XCONNEXT}) set(VARSVC_LIBS varsvcutil varsvccli varsvcobj) -set(GPIPE_COMMON_LIBS gpipe_attr gpipe_property gpipe_common) -set(GPIPE_LOADER_LIBS ncbi_xloader_asn_cache asn_cache cache_blob -ncbi_xloader_lds2 lds2 sqlitewrapp -ncbi_xloader_lds lds bdb -${BLAST_DB_DATA_LOADER_LIBS} ${BLAST_LIBS} -${ncbi_xreader_pubseqos2} -submit -ncbi_xloader_csra ncbi_xloader_wgs -${SRAREAD_LIBS}) -set(GPIPE_LOADER_THIRDPARTY_LIBS ${SQLITE3_LIBS} ${BERKELEYDB_LIBS} - ${SRA_SDK_SYSLIBS} ${CMPRS_LIBS}) - -set(GPIPE_GENCOLL_LIBS xgencoll gpipe_objutil ncbi_xloader_wgs aligndb_reader - gencoll_client taxon1) -set(GPIPE_ALL_LIBS ${GPIPE_GENCOLL_LIBS} - ${GPIPE_COMMON_LIBS} - ${GPIPE_LOADER_LIBS}) -set(GPIPE_DBAPI_LIB_STATIC ncbi_xdbapi_ftds dbapi dbapi_driver) -set(GPIPE_DBAPI_LIB ${GPIPE_DBAPI_LIB_STATIC} ${FTDS_LIB}) -set(GPIPE_DBAPI_LIBS ${FTDS_LIBS}) - -set(GPIPE_SDBAPI_LIB_STATIC sdbapi ${GPIPE_DBAPI_LIB_STATIC}) -set(GPIPE_SDBAPI_LIB ${GPIPE_SDBAPI_LIB_STATIC} ${FTDS_LIB}) -set(GPIPE_SDBAPI_LIBS ${GPIPE_DBAPI_LIBS}) - - # Entrez Libs set(ENTREZ_LIBS entrez2cli entrez2) set(EUTILS_LIBS eutils egquery elink epost esearch espell esummary linkout einfo uilist ehistory) +#GLPK +find_external_library(glpk + INCLUDES glpk.h + LIBS glpk + HINTS "/usr/local/glpk/4.45") + +find_external_library(samtools + INCLUDES bam.h + LIBS bam + HINTS "${NCBI_TOOLS_ROOT}/samtools") + +#LAPACK +check_include_file(lapacke.h HAVE_LAPACKE_H) +check_include_file(lapacke/lapacke.h HAVE_LAPACKE_LAPACKE_H) +check_include_file(Accelerate/Accelerate.h HAVE_ACCELERATE_ACCELERATE_H) +#find_external_library(LAPACK LIBS lapack blas) +find_package(LAPACK) +if (LAPACK_FOUND) + set(LAPACK_INCLUDE ${LAPACK_INCLUDE_DIRS}) + set(LAPACK_LIBS ${LAPACK_LIBRARIES}) +else () + find_library(LAPACK_LIBS lapack blas) +endif () + +#LMBD +find_external_library(LMDB INCLUDES lmdb.h LIBS lmdb HINTS "${NCBI_TOOLS_ROOT}/lmdb-0.9.18" EXTRALIBS pthread) + +find_external_library(libxlsxwriter + INCLUDES xlsxwriter.h + LIBS xlsxwriter + HINTS "${NCBI_TOOLS_ROOT}/libxlsxwriter-0.6.9" + EXTRALIBS ${Z_LIBS}) + +find_external_library(LIBUNWIND INCLUDES libunwind.h LIBS unwind HINTS "${NCBI_TOOLS_ROOT}/libunwind-1.1") +set(HAVE_LIBUNWIND ${LIBUNWIND_FOUND}) + +# +# Final tasks +# + +# This file holds information about the build version +message(STATUS "Generating ${build_root}/inc/ncbi_build_ver.h...") +configure_file(${includedir}/common/ncbi_build_ver.h.in ${includedir}/common/ncbi_build_ver.h) +# OS-specific generated header configs +if (UNIX) + message(STATUS "Generating ${build_root}/inc/ncbiconf_unix.h...") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/build-system/cmake/config.cmake.h.in ${build_root}/inc/ncbiconf_unix.h) +endif(UNIX) + +if (WIN32) + message(STATUS "Generating ${build_root}/inc/ncbiconf_msvc.h...") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/build-system/cmake/config.cmake.h.in ${build_root}/inc/ncbiconf_msvc.h) + message(STATUS "Generating ${includedir}/common/config/ncbiconf_msvc_site.h...") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/build-system/cmake/ncbiconf_msvc_site.h.in ${includedir}/common/config/ncbiconf_msvc_site.h) +endif (WIN32) + +if (APPLE AND NOT UNIX) #XXX + message(STATUS "Generating ${build_root}/inc/ncbiconf_xcode.h...") + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/build-system/cmake/config.cmake.h.in ${build_root}/inc/ncbiconf_xcode.h) +endif (APPLE AND NOT UNIX) + +# +# write ncbicfg.c.in +# +# FIXME: +# We need to set these variables to get them into the cfg file: +# - c_ncbi_runpath +# - SYBASE_LCL_PATH +# - SYBASE_PATH +# - FEATURES +set(c_ncbi_runpath "$ORIGIN/../lib") +set(SYBASE_LCL_PATH ${SYBASE_LIBRARIES}) +set(SYBASE_PATH "") +set(FEATURES "") +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/corelib/ncbicfg.c.in ${CMAKE_BINARY_DIR}/corelib/ncbicfg.c) + +ENABLE_TESTING() +include_directories(${incdir} ${includedir0} ${incinternal}) + +if (WIN32) + set(win_include_directories + "${PCRE_PKG_INCLUDE_DIRS}" + "${PC_GNUTLS_INCLUDEDIR}" + "${WIN32_PACKAGE_ROOT}/sqlite3-3.8.10.1/include" + "${WIN32_PACKAGE_ROOT}/db-4.6.21/include" + "${WIN32_PACKAGE_ROOT}/libxml2-2.7.8.win32/include" + "${WIN32_PACKAGE_ROOT}/libxslt-1.1.26.win32/include" + "${WIN32_PACKAGE_ROOT}/iconv-1.9.2.win32/include" ) + include_directories(${win_include_directories}) +endif (WIN32) + +# +# Dump our final diagnostics +include(${top_src_dir}/src/build-system/cmake/CMakeChecks.final-message.cmake) diff --git a/c++/src/build-system/cmake/CMakeChecks.compiler.cmake b/c++/src/build-system/cmake/CMakeChecks.compiler.cmake new file mode 100644 index 00000000..f36ac8b5 --- /dev/null +++ b/c++/src/build-system/cmake/CMakeChecks.compiler.cmake @@ -0,0 +1,129 @@ +# +# This config is designed to capture all compiler and linker definitions and search parameters +# + +# +# See: +# http://stackoverflow.com/questions/32752446/using-compiler-prefix-commands-with-cmake-distcc-ccache +# +# There are better ways to do this +option(CMAKE_USE_CCACHE "Use 'ccache' as a preprocessor" OFF) +option(CMAKE_USE_DISTCC "Use 'distcc' as a preprocessor" OFF) + +if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + add_definitions(-D_DEBUG) + if (NOT WIN32) + add_definitions(-gdwarf-3) + endif() +ELSE() + add_definitions(-DNDEBUG) + if ((NOT "${CMAKE_DEBUG_SYMBOLS}" STREQUAL "") AND (NOT WIN32)) + add_definitions(-gdwarf-3) + endif() +ENDIF() + + +if (APPLE) + add_definitions(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64) +elseif (UNIX) + add_definitions(-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) +endif (APPLE) + +if (CMAKE_COMPILER_IS_GNUCC) + add_definitions(-Wall -Wno-format-y2k ) +endif() + +include(CheckCXXCompilerFlag) +include(CheckCCompilerFlag) + +macro(set_cxx_compiler_flag_optional) + foreach (var ${ARGN}) + CHECK_CXX_COMPILER_FLAG("${var}" _COMPILER_SUPPORTS_FLAG) + if (_COMPILER_SUPPORTS_FLAG) + message(STATUS "The compiler ${CMAKE_CXX_COMPILER} supports ${var}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${var}") + break() + endif() + endforeach() + if (_COMPILER_SUPPORTS_FLAG) + else() + message(WARNING "The compiler ${CMAKE_CXX_COMPILER} has no support for any of ${ARGN}") + endif() +endmacro() + +macro(set_c_compiler_flag_optional) + foreach (var ${ARGN}) + CHECK_C_COMPILER_FLAG(${var} _COMPILER_SUPPORTS_FLAG) + if (_COMPILER_SUPPORTS_FLAG) + message(STATUS "The compiler ${CMAKE_C_COMPILER} supports ${var}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${var}") + break() + endif() + endforeach() + if (_COMPILER_SUPPORTS_FLAG) + else() + message(WARNING "The compiler ${CMAKE_C_COMPILER} has no support for any of ${ARGN}") + endif() +endmacro() + +# Check for appropriate C++11 flags +if (UNIX) + set_cxx_compiler_flag_optional("-std=gnu++11" "-std=c++11" "-std=c++0x") + set_c_compiler_flag_optional ("-std=gnu11" "-std=c11" "-std=gnu99" "-std=c99") +endif() + +find_program(CCACHE_EXECUTABLE ccache + PATHS /usr/local/ccache/3.2.5/bin/) +find_program(DISTCC_EXECUTABLE distcc) + + +set(NCBI_COMPILER_WRAPPER "") +if (CMAKE_USE_DISTCC AND DISTCC_EXECUTABLE AND + CMAKE_USE_CCACHE AND CCACHE_EXECUTABLE) +set(NCBI_COMPILER_WRAPPER "CCACHE_BASEDIR=${top_src_dir} CCACHE_PREFIX=${DISTCC_EXECUTABLE} ${CCACHE_EXECUTABLE} ${NCBI_COMPILER_WRAPPER}") +elseif (CMAKE_USE_DISTCC AND DISTCC_EXECUTABLE) + set(NCBI_COMPILER_WRAPPER "${DISTCC_EXECUTABLE} ${NCBI_COMPILER_WRAPPER}") +elseif(CMAKE_USE_CCACHE AND CCACHE_EXECUTABLE) + set(NCBI_COMPILER_WRAPPER "CCACHE_BASEDIR=${top_src_dir} ${CCACHE_EXECUTABLE} ${NCBI_COMPILER_WRAPPER}") + # pass these back for ccache to pick up + set(ENV{CCACHE_BASEDIR} ${top_src_dir}) + message(STATUS "Enabling ccache: ${CCACHE_EXECUTABLE}") + message(STATUS " ccache basedir: ${top_src_dir}") +endif() + +set(CMAKE_CXX_COMPILE_OBJECT + "${NCBI_COMPILER_WRAPPER} ${CMAKE_CXX_COMPILE_OBJECT}") + +set(CMAKE_C_COMPILE_OBJECT + "${NCBI_COMPILER_WRAPPER} ${CMAKE_C_COMPILE_OBJECT}") + +message(STATUS "NCBI_COMPILER_WRAPPER = ${NCBI_COMPILER_WRAPPER}") + + +if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU") + set(NCBI_COMPILER_GCC 1) + set(NCBI_COMPILER "GCC") +elseif(MSVC) + set(NCBI_COMPILER "MSVC") + set(NCBI_COMPILER_GCC 0) +endif() + + +# +# NOTE: +# uncomment this for strict mode for library compilation +# +#set(CMAKE_SHARED_LINKER_FLAGS_DYNAMIC "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--export-dynamic") + +set(CMAKE_SHARED_LINKER_FLAGS_RDYNAMIC "${CMAKE_SHARED_LINKER_FLAGS}") # for smooth transition, please don't use +set(CMAKE_SHARED_LINKER_FLAGS_ALLOW_UNDEFINED "${CMAKE_SHARED_LINKER_FLAGS}") +if ((NOT DEFINED ${APPLE}) OR (NOT ${APPLE})) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined") +endif () + + +if (BUILD_SHARED_LIBS) + set(NCBI_DLL_BUILD 1) + set(NCBI_DLL_SUPPORT 1) +endif() + diff --git a/c++/src/build-system/cmake/CMakeChecks.compress.cmake b/c++/src/build-system/cmake/CMakeChecks.compress.cmake new file mode 100644 index 00000000..f211d95e --- /dev/null +++ b/c++/src/build-system/cmake/CMakeChecks.compress.cmake @@ -0,0 +1,34 @@ +############################################################################ +# +# Compression libraries + +set(_foo_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH}) +if (WIN32) + set(CMAKE_PREFIX_PATH ${ZLIB_ROOT}) +endif() + +find_package(ZLIB) +find_package(BZip2) +find_package(LZO) + +# For backward compatibility +set(Z_INCLUDE ${ZLIB_INCLUDE_DIR}) +set(BZ2_INCLUDE ${BZIP2_INCLUDE_DIR}) + +set(Z_LIBS ${ZLIB_LIBRARIES}) +set(BZ2_LIBS ${BZIP2_LIBRARIES}) + +set(CMPRS_INCLUDE ${Z_INCLUDE} ${BZ2_INCLUDE}) +set(CMPRS_LIBS ${Z_LIBS} ${BZ2_LIBS} ${LZO_LIBS}) + +if (LZO_FOUND) + set(LZO_INCLUDE ${LZO_INCLUDE_DIR}) + set(LZO_LIBS ${LZO_LIBRARIES}) + set(CMPRS_INCLUDE ${CMPRS_INCLUDE} ${LZO_INCLUDE}) + set(CMPRS_LIBS ${CMPRS_LIBS} ${LZO_LIBS}) +endif() + +set(COMPRESS_LIBS xcompress ${CMPRS_LIBS}) + +set(CMAKE_PREFIX_PATH ${_foo_CMAKE_PREFIX_PATH}) + diff --git a/c++/src/build-system/cmake/CMakeChecks.final-message.cmake b/c++/src/build-system/cmake/CMakeChecks.final-message.cmake new file mode 100644 index 00000000..be429c08 --- /dev/null +++ b/c++/src/build-system/cmake/CMakeChecks.final-message.cmake @@ -0,0 +1,67 @@ + +# +# Config to dump diagnostic information at the completion of configuration +# + +get_directory_property(Defs COMPILE_DEFINITIONS) +foreach (d ${Defs} ) + set(DefsStr "${DefsStr} -D${d}") +endforeach() + +list(REMOVE_DUPLICATES NCBI_MODULES_FOUND) +foreach (mod ${NCBI_MODULES_FOUND}) + set(MOD_STR "${MOD_STR} ${mod}") +endforeach() + +#STRING(SUBSTRING "${EXTERNAL_LIBRARIES_COMMENT}" 1 -1 EXTERNAL_LIBRARIES_COMMENT) + +function(ShowMainBoilerplate) + message("") + message("------------------------------------------------------------------------------") + message("CMake exe: ${CMAKE_COMMAND}") + message("CMake version: ${CMAKE_VERSION}") + message("Build Target: ${CMAKE_BUILD_TYPE}") + message("Shared Libs: ${BUILD_SHARED_LIBS}") + message("Top Source Dir: ${top_src_dir}") + message("Build Root: ${build_root}") + message("Executable Dir: ${EXECUTABLE_OUTPUT_PATH}") + message("Library Dir: ${LIBRARY_OUTPUT_PATH}") + message("C Compiler: ${CMAKE_C_COMPILER}") + message("C++ Compiler: ${CMAKE_CXX_COMPILER}") + + if (CMAKE_USE_DISTCC AND DISTCC_EXECUTABLE) + message(" distcc: ${DISTCC_EXECUTABLE}") + endif() + if (CMAKE_USE_CCACHE AND CCACHE_EXECUTABLE) + message(" ccache: ${CCACHE_EXECUTABLE}") + endif() + + message("CFLAGS: ${CMAKE_C_FLAGS}") + message("CXXFLAGS: ${CMAKE_CXX_FLAGS}") + message("Compile Flags: ${DefsStr}") + message("DataTool Ver: ${_datatool_version}") + message("DataTool Path: ${NCBI_DATATOOL}") + message("") + message("Modules Found: ${MOD_STR}") + + message("------------------------------------------------------------------------------") + message("") +endfunction() + +ShowMainBoilerplate() + +add_custom_target(NAME show-config + COMMAND ${CMAKE_COMMAND} -e echo "ShowMainBoilerplate()" + COMMAND ${CMAKE_COMMAND} -e echo "PCRE: ${PCRE_LIBRARIES}" + COMMAND ${CMAKE_COMMAND} -e echo "Boost: ${Boost_INCLUDE_DIRS}" + COMMAND ${CMAKE_COMMAND} -e echo "wxWidgets:" + COMMAND ${CMAKE_COMMAND} -e echo " include: ${wxWidgets_INCLUDE_DIRS}" + COMMAND ${CMAKE_COMMAND} -e echo " lib: ${wxWidgets_LIBRARIES}" + COMMAND ${CMAKE_COMMAND} -e echo " definitions: ${wxWidgets_DEFNITIONS}" + COMMAND ${CMAKE_COMMAND} -e echo " flags: ${wxWidgets_CXX_FLAGS}" + COMMAND ${CMAKE_COMMAND} -e echo "GnuTLS: ${GNUTLS_COMMENT}" + COMMAND ${CMAKE_COMMAND} -e echo "GnuTLS include: ${GNUTLS_INCLUDE}" + COMMAND ${CMAKE_COMMAND} -e echo "${EXTERNAL_LIBRARIES_COMMENT}" + ) + + diff --git a/c++/src/build-system/cmake/CMakeChecks.image.cmake b/c++/src/build-system/cmake/CMakeChecks.image.cmake new file mode 100644 index 00000000..8ebce767 --- /dev/null +++ b/c++/src/build-system/cmake/CMakeChecks.image.cmake @@ -0,0 +1,41 @@ +############################################################################ +# +# Various image-format libraries +set(_foo_CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH}) + +if (WIN32) + set(CMAKE_PREFIX_PATH ${JPEG_ROOT} ${PNG_ROOT} ${TIFF_ROOT}) +endif() + +find_package(JPEG) +find_package(PNG) +find_package(TIFF) +find_package(GIF) +find_package(Freetype) +if (FREETYPE_FOUND) + find_package(FTGL) +endif() + +# +# For backward compatibility + +set(IMAGE_INCLUDE_DIR + ${JPEG_INCLUDE_DIR} + ${PNG_INCLUDE_DIR} + ${TIFF_INCLUDE_DIR} + ${GIF_INCLUDE_DIR}) +set(IMAGE_LIBS + ${JPEG_LIBRARIES} + ${PNG_LIBRARIES} + ${TIFF_LIBRARIES} + ${GIF_LIBRARIES}) + + +# FreeType, FTGL +set(FREETYPE_INCLUDE ${FREETYPE_INCLUDE_DIRS}) +set(FREETYPE_LIBS ${FREETYPE_LIBRARIES}) +set(FTGL_INCLUDE ${FTGL_INCLUDE_DIR} ${FREETYPE_INCLUDE_DIRS}) +set(FTGL_LIBS ${FTGL_LIBRARIES} ${FREETYPE_LIBRARIES}) + +set(CMAKE_PREFIX_PATH ${_foo_CMAKE_PREFIX_PATH}) + diff --git a/c++/src/build-system/cmake/CMakeChecks.os.cmake b/c++/src/build-system/cmake/CMakeChecks.os.cmake new file mode 100644 index 00000000..1ac1f464 --- /dev/null +++ b/c++/src/build-system/cmake/CMakeChecks.os.cmake @@ -0,0 +1,48 @@ +# +# OS-specific settings +# + +if (UNIX) + SET(NCBI_OS_UNIX 1 CACHE INTERNAL "Is Unix") + SET(NCBI_OS "UNIX" CACHE INTERNAL "Is Unix") + set(HOST_OS "unix") + if (${CMAKE_SYSTEM_NAME} MATCHES "Linux") + SET(NCBI_OS_LINUX 1 CACHE INTERNAL "Is Linux") + set(HOST_OS "linux-gnu") + set(HOST_CPU "x86_64") + endif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") +endif(UNIX) + +if (WIN32) + SET(NCBI_OS_MSWIN 1 CACHE INTERNAL "Is Windows") + SET(NCBI_OS "WINDOWS" CACHE INTERNAL "Is Windows") + set(HOST_OS "pc-x64") + set(HOST_CPU "i386") +endif(WIN32) + +if (CYGWIN) + SET(NCBI_OS_CYGWIN 1 CACHE INTERNAL "Is CygWin") + SET(NCBI_OS "CYGWIN" CACHE INTERNAL "Is Cygwin") +endif(CYGWIN) + +if (APPLE) + if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") + SET(NCBI_OS_DARWIN 1 CACHE INTERNAL "Is Mac OS X") + endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") +endif(APPLE) + + +# +# Host and system definition information +# + +cmake_host_system_information(RESULT _local_host_name QUERY HOSTNAME) +set(HOST "${HOST_CPU}-unknown-${HOST_OS}") +set(NCBI_SIGNATURE "${CMAKE_C_COMPILER_ID}_${MSVC_VERSION}-${HOST}-${_local_host_name}") + +if (WIN32) + set(HOST "${HOST_CPU}-${HOST_OS}") + set(NCBI_SIGNATURE "${CMAKE_C_COMPILER_ID}_${MSVC_VERSION}-${HOST}-${_local_host_name}") +endif() + + diff --git a/c++/src/build-system/cmake/CMakeChecks.pcre.cmake b/c++/src/build-system/cmake/CMakeChecks.pcre.cmake new file mode 100644 index 00000000..e7ea7a2c --- /dev/null +++ b/c++/src/build-system/cmake/CMakeChecks.pcre.cmake @@ -0,0 +1,22 @@ +############################################################################ +# +# PCRE additions +# +# Perl-Compatible Regular Expressions (PCRE) +find_package(PCRE) +set(PCRE_INCLUDE ${PCRE_INCLUDE_DIR}) +set(PCRE_LIBS ${PCRE_LIBRARIES}) +if (PCRE_FOUND) + set(HAVE_LIBPCRE 1) +endif() + +if (WIN32 AND HAVE_LIBPCRE) + set(USE_LOCAL_PCRE TRUE) +endif() + +if (HAVE_LIBPCRE AND NOT USE_LOCAL_PCRE) + set(PCRE_LIBS -lpcre) +else(HAVE_LIBPCRE AND NOT USE_LOCAL_PCRE) + set(USE_LOCAL_PCRE 1 CACHE INTERNAL "Using local PCRE due to system library absence") +endif(HAVE_LIBPCRE AND NOT USE_LOCAL_PCRE) + diff --git a/c++/src/build-system/cmake/CMakeChecks.sqlite3.cmake b/c++/src/build-system/cmake/CMakeChecks.sqlite3.cmake new file mode 100644 index 00000000..9da314bb --- /dev/null +++ b/c++/src/build-system/cmake/CMakeChecks.sqlite3.cmake @@ -0,0 +1,22 @@ +include(CheckFunctionExists) +include(CheckIncludeFile) + +find_package(Sqlite3) + +if (SQLITE3_FOUND) + set(CMAKE_REQUIRED_LIBRARIES_OLD "${CMAKE_REQUIRED_LIBRARIES}") + set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES} ${SQLITE3_LIBRARY}") + check_symbol_exists(sqlite3_unlock_notify ${SQLITE3_INCLUDE_DIR}/sqlite3.h HAVE_SQLITE3_UNLOCK_NOTIFY) + set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES_OLD}") + + check_include_file(sqlite3async.h HAVE_SQLITE3ASYNC_H -I${SQLITE3_INCLUDE_DIR}) + if (HAVE_SQLITE3ASYNC_H) + message(STATUS " SQLite3: Found sqlite3async.h") + endif() +endif(SQLITE3_FOUND) + +set(SQLITE3_INCLUDE ${SQLITE3_INCLUDE_DIR}) +set(SQLITE3_LIBS ${SQLITE3_LIBRARY}) +set(SQLITE3_STATIC_LIBS ${SQLITE3_LIBS}) + + diff --git a/c++/src/build-system/cmake/CMakeChecks.wxwidgets.cmake b/c++/src/build-system/cmake/CMakeChecks.wxwidgets.cmake new file mode 100644 index 00000000..62d9c6e7 --- /dev/null +++ b/c++/src/build-system/cmake/CMakeChecks.wxwidgets.cmake @@ -0,0 +1,52 @@ +# wxWidgets +set(_foo_CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH}") +if (WIN32) + set(CMAKE_PREFIX_PATH ${WXWIDGETS_ROOT}) +else() + set(CMAKE_PREFIX_PATH "${NCBI_TOOLS_ROOT}/wxWidgets-3.0.1-ncbi1/${CMAKE_BUILD_TYPE}/bin") +endif() + +set(wxWidgets_USE_UNICODE ON) +set(wxWidgets_USE_SHAREED_LIBS ${BUILD_SHARED_LIBS}) + +if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") + set(wxWidgets_CONFIG_OPTIONS "--debug=yes") + set(wxWidgets_USE_DEBUG ON) +elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "Release") + set(wxWidgets_USE_DEBUG OFF) +endif() + +if (EXISTS ${NCBI_TOOLS_ROOT}/wxWidgets-3.0.1-ncbi1) + + set(WXWIDGETS_INCLUDE ${NCBI_TOOLS_ROOT}/wxWidgets-3.0.1-ncbi1/include) + set(WXWIDGETS_LIBS "${NCBI_TOOLS_ROOT}/wxWidgets-3.0.1-ncbi1/${CMAKE_BUILD_TYPE}MT64/libs") + set(WXWIDGETS_STATIC_LIBS "${NCBI_TOOLS_ROOT}/wxWidgets-3.0.1-ncbi1/${CMAKE_BUILD_TYPE}MT64/libs") + set(WXWIDGETS_GL_LIBS -lwx_gtk2_gl-2.9 -lwx_base-2.9) + +else (EXISTS ${NCBI_TOOLS_ROOT}/wxWidgets-3.0.1-ncbi1) + + include(FindwxWidgets) + FIND_PACKAGE(wxWidgets + COMPONENTS gl core base ) + set(WXWIDGETS_INCLUDE "${wxWidgets_INCLUDE_DIRS}") + set(WXWIDGETS_LIBS "${wxWidgets_LIBRARIES}") + set(WXWIDGETS_STATIC_LIBS ${WXWIDGETS_LIBS}) + set(WXWIDGETS_GL_LIBS -lwx_gtk2_gl-2.9 -lwx_base-2.9) + +endif (EXISTS ${NCBI_TOOLS_ROOT}/wxWidgets-3.0.1-ncbi1) + +set(CMAKE_PREFIX_PATH "${_foo_CMAKE_PREFIX_PATH}") + + +#FIXME: this is broken +#include( ${wxWidgets_USE_FILE} ) + +## message(STATUS "wxWidgets: CONFIG_OPTIONS = ${wxWidgets_CONFIG_OPTIONS}") +## message(STATUS "wxWidgets: DEBUG = ${wxWidgets_USE_DEBUG}") +## message(STATUS "wxWidgets: SHARED_LIBS = ${wxWidgets_USE_SHAREED_LIBS}") +## message(STATUS "wxWidgets: CXX_FLAGS = ${wxWidgets_CXX_FLAGS}") +## message(STATUS "wxWidgets: DEFINITIONS = ${wxWidgets_DEFINITIONS}") +## message(STATUS "wxWidgets: LIBRARIES = ${wxWidgets_LIBRARIES}") +## message(STATUS "wxWidgets: USE_FILE = ${wxWidgets_USE_FILE}") + + diff --git a/c++/src/build-system/cmake/CMakeLists.defaults.cmake b/c++/src/build-system/cmake/CMakeLists.defaults.cmake deleted file mode 100755 index 86ec23e7..00000000 --- a/c++/src/build-system/cmake/CMakeLists.defaults.cmake +++ /dev/null @@ -1,48 +0,0 @@ -set(CMAKE_C_COMPILER /usr/local/gcc/4.8.1/bin/gcc) -set(CMAKE_CXX_COMPILER /usr/local/gcc/4.8.1/bin/g++) - - - -set(top_srcdir ${NCBI_TREE_ROOT}) -set(build_root ${NCBI_BUILD_ROOT}/..) -set(builddir ${NCBI_BUILD_ROOT}) -set(includedir0 ${top_srcdir}/include) -set(includedir ${includedir0}) -set(incdir ${build_root}/inc) -set(incinternal ${includedir0}/internal) - -set(buildconf GCC401-DebugMT64) -set(buildconf0 GCC401-DebugMT) - -set(CONF_CFLAGS " -Wall -Wno-format-y2k -pthread -fPIC -gdwarf-3") -set(CONF_CXXFLAGS " -Wall -Wno-format-y2k -pthread -fPIC -gdwarf-3 -std=gnu++11 -Wno-unused-local-typedefs") -set(CONF_CPPFLAGS ) -set(STD_INCLUDE " -I${incdir} -I${includedir0} -I${incinternal}") -set(ORIG_CPPFLAGS " ${CONF_CXXFLAGS} ${CONF_CPPFLAGS} ${STD_INCLUDE}") - -#set(CMAKE_CXX_FLAGS "${CONF_CXXFLAGS} ${CONF_CPPFLAGS} ${STD_INCLUDE}") -#set(CMAKE_C_FLAGS "${CONF_CFLAGS} ${STD_INCLUDE}") - -set(NCBI_TOOLS_ROOT $ENV{NCBI}) - -#set (ARCHIVE_OUTPUT_DIRECTORY ${NCBI_BUILD_ROOT}/../lib) -#set (LIBRARY_OUTPUT_DIRECTORY ${NCBI_BUILD_ROOT}/../lib) -#set (RUNTIME_OUTPUT_DIRECTORY ${NCBI_BUILD_ROOT}/../bin) -#set (PDB_OUTPUT_DIRECTORY ${NCBI_BUILD_ROOT}/../bin) - -#set (LIBRARY_OUTPUT_PATH ${NCBI_BUILD_ROOT}/../lib) -#set (EXECUTABLE_OUTPUT_PATH ${NCBI_BUILD_ROOT}/../bin) -set (LIBRARY_OUTPUT_PATH ${NCBI_CMAKE_ROOT}/lib) -set (EXECUTABLE_OUTPUT_PATH ${NCBI_CMAKE_ROOT}/bin) - -set (NCBI_BUILD_BIN ${EXECUTABLE_OUTPUT_PATH}) - -#set (NCBI_DATATOOL $NCBI/bin/datatool) -set (NCBI_DATATOOL /netopt/ncbi_tools64/bin/datatool) - -ENABLE_TESTING() - -include(CMakeChecks) -#include_directories(${incdir} ${includedir0} ${incinternal}) - - diff --git a/c++/src/build-system/cmake/CMakeMacros.cmake b/c++/src/build-system/cmake/CMakeMacros.cmake new file mode 100644 index 00000000..4caee2db --- /dev/null +++ b/c++/src/build-system/cmake/CMakeMacros.cmake @@ -0,0 +1,304 @@ +############################################################################## +## +## General wrapper for find_package() +## This wrapper implements some overrides to search for NCBI-specific package +## overrides. We maintain a directory of configs that indicate the specific +## layout of libraries for development at NCBI. +## + +macro(find_package arg_mod) + # uncomment this for extensive logging + #set(_NCBI_MODULE_DEBUG True) + set(_MOD_CONF1 "NCBI-${arg_mod}Config.cmake") + string(TOLOWER "NCBI-${arg_mod}-config.cmake" _MOD_CONF2) + #message(STATUS "Checking for config: ${_NCBI_DEFAULT_PACKAGE_SEARCH_PATH}/${_MOD_CONF1}") + #message(STATUS "Checking for config: ${_NCBI_DEFAULT_PACKAGE_SEARCH_PATH}/${_MOD_CONF2}") + if (EXISTS "${_NCBI_DEFAULT_PACKAGE_SEARCH_PATH}/${_MOD_CONF1}" + OR EXISTS "${_NCBI_DEFAULT_PACKAGE_SEARCH_PATH}/${_MOD_CONF2}") + _find_package(${arg_mod} ${ARGN} + NAMES NCBI-${arg_mod} + ) + if (${${arg_mod}_FOUND}) + message(STATUS "Found ${arg_mod} (NCBI config): ${${arg_mod}_LIBRARIES} (found version \"${${arg_mod}_VERSION_STRING}\")") + endif() + else() + _find_package(${arg_mod} ${ARGN}) + if (${${arg_mod}_FOUND}) + message(STATUS "Found ${arg_mod} (CMake): ${${arg_mod}_LIBRARIES} (found version \"${${arg_mod}_VERSION_STRING}\")") + endif() + endif() + + if (${${arg_mod}_FOUND}) + list(APPEND NCBI_MODULES_FOUND ${arg_mod}) + + # + # everything below is an insulation layer + # this is designed to make the standard C++ toolkit-type macros work + # + + string(TOUPPER ${arg_mod} _arg_mod_upper) + if (DEFINED ${arg_mod}_LIBRARIES) + set(${_arg_mod_upper}_LIBS ${${arg_mod}_LIBRARIES}) + elseif(DEFINED ${arg_mod}_LIBRARY) + set(${_arg_mod_upper}_LIBS ${${arg_mod}_LIBRARY}) + elseif (DEFINED ${_arg_mod_upper}_LIBRARIES) + set(${_arg_mod_upper}_LIBS ${${_arg_mod_upper}_LIBRARIES}) + elseif(DEFINED ${_arg_mod_upper}_LIBRARY) + set(${_arg_mod_upper}_LIBS ${${_arg_mod_upper}_LIBRARY}) + endif() + + if (DEFINED ${arg_mod}_INCLUDE_DIRS) + set(${_arg_mod_upper}_INCLUDE ${${arg_mod}_INCLUDE_DIRS}) + elseif(DEFINED ${arg_mod}_INCLUDE_DIR) + set(${_arg_mod_upper}_INCLUDE ${${arg_mod}_INCLUDE_DIR}) + elseif (DEFINED ${_arg_mod_upper}_INCLUDE_DIRS) + set(${_arg_mod_upper}_INCLUDE ${${_arg_mod_upper}_INCLUDE_DIRS}) + elseif(DEFINED ${_arg_mod_upper}_INCLUDE_DIR) + set(${_arg_mod_upper}_INCLUDE ${${_arg_mod_upper}_INCLUDE_DIR}) + endif() + + if (_NCBI_MODULE_DEBUG) + message(STATUS " FindPackage(): ${_arg_mod_upper}_INCLUDE = ${${_arg_mod_upper}_INCLUDE}") + message(STATUS " FindPackage(): ${_arg_mod_upper}_LIBS = ${${_arg_mod_upper}_LIBS}") + endif() + endif() +endmacro() + + +############################################################################## +## +## Recurse a directory, but only if the directory actually exists +## This is useful for marking optional elements that may or may not be present +## in meta-trees +## + +macro( add_subdirectory_optional SUBDIR) + if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIR}/CMakeLists.txt ) + add_subdirectory(${SUBDIR}) + endif() +endmacro(add_subdirectory_optional) + + + + +############################################################################## +## +## Macros for woring with 'datatool' +## + +############################################################################## +## +## Parse the module spec file, whcih includes definitions of how to build +## datatool-derived code +## + + +if (WIN32) + set(NCBI_DATATOOL_BASE "//snowman/win-coremake/App/Ncbi/cppcore/datatool/msvc") +else() + #FIXME: Not just Linux! + # However, we only use CMake on Linux for now, so ok to hard code + set(NCBI_DATATOOL_BASE "/net/snowman/vol/export2/win-coremake/App/Ncbi/cppcore/datatool/Linux64") +endif() + +if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../src/build-system/datatool_version.txt") + FILE(READ "${CMAKE_CURRENT_SOURCE_DIR}/../src/build-system/datatool_version.txt" _datatool_version) + string(REGEX MATCH "[0-9][0-9.]*[0-9]" _datatool_version "${_datatool_version}") +else() + set(_datatool_version "2.17.0") + message(WARNING "Failed to find spec file for datatool (${CMAKE_CURRENT_SOURCE_DIR}/../src/build-system/datatool_version.txt), defaulting to version ${_datatool_version})") +endif() + +message(STATUS "Datatool version required by software: ${_datatool_version}") +if (EXISTS "${NCBI_DATATOOL_BASE}/${_datatool_version}/datatool") + set (NCBI_DATATOOL "${NCBI_DATATOOL_BASE}/${_datatool_version}/datatool") + message(STATUS "Datatool location: ${NCBI_DATATOOL}") +else() + set (NCBI_DATATOOL $) + message(STATUS "Datatool location: ") +endif() + + + +macro( ReadModuleSpec MODULE_DEFS_FILE ) + if (EXISTS "${MODULE_DEFS_FILE}") + #message("Processing module file: ${MODULE_DEFS_FILE}") + FILE(READ "${MODULE_DEFS_FILE}" contents) + + #STRING(REGEX MATCH "MODULE_PATH *=[^\n]*[^ \n]" MODULE_DIRECTORY "${contents}") + #STRING(REGEX REPLACE "MODULE_PATH *= *" " " MODULE_DIRECTORY "${MODULE_DIRECTORY}") + + STRING(REGEX MATCH "MODULE_IMPORT *=[^\n]*[^ \n]" _TMP "${contents}") + STRING(REGEX REPLACE "MODULE_IMPORT *= *" "" _TMP "${_TMP}") + STRING(REGEX REPLACE " *$" "" _TMP_LIST "${_TMP}") + STRING(REGEX REPLACE " " ";" _TMP_LIST "${_TMP}") + #message("list=${_TMP_LIST}") + set(MODULE_IMPORT "") + + foreach(mod ${_TMP_LIST}) + #message("MODULE_IMPORT=|${MODULE_IMPORT}| mod=|${mod}|") + set(MODULE_IMPORT "${MODULE_IMPORT} ${mod}.asn") + endforeach(mod) + + #message("module path = ${MODULE_PATH}") + #message("module import = ${MODULE_IMPORT}") + else() + #message("No module file: ${MODULE_DEFS_FILE}") + endif() +endmacro( ReadModuleSpec ) + + +############################################################################## +## +## Test whether a file is maintained under version control +## Note: This is not currently used +## +function( CheckVersionControl generated) + set(local_generated) + foreach (f IN LISTS ARGV) + set(retcode) + execute_process( + COMMAND /usr/bin/svn info "${f}" + RESULT_VARIABLE retcode + OUTPUT_VARIABLE _foo_output + ERROR_VARIABLE _foo_error + ) + if (NOT retcode EQUAL 0) + list(APPEND local_generated ${f}) + endif() + endforeach(f) + set(generated_files ) + list(APPEND generated_files ${local_generated}) + set(${generated_files} ${${generated_files}} PARENT_SCOPE) +endfunction(CheckVersionControl) + + + +############################################################################## +## +## Extract the name of the client (file names for the client code) for +## datatool-generated RPC clients +## The client name is a field in the definitions +## +macro( GetClientName MODULE ) + if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}.def") + + FILE(READ "${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}.def" contents) + STRING(REGEX MATCH "clients *=[^\n]*[^ \n]" CLIENT "${contents}") + STRING(REGEX REPLACE "clients *= *" "" CLIENT "${CLIENT}") + if ("${CLIENT}" STREQUAL "") + else() + set(client1 "${CMAKE_CURRENT_SOURCE_DIR}/${CLIENT}.cpp") + set(client2 "${CMAKE_CURRENT_SOURCE_DIR}/${CLIENT}_.cpp") + get_filename_component(client1 "${client1}" REALPATH) + get_filename_component(client2 "${client2}" REALPATH) + + # test if our files are under version control + # if they are, then these + #set(CLIENT ${client1} ${client2}) + set(CLIENT ${client2}) + if (NOT EXISTS "${client1}") + set(CLIENT ${CLIENT} ${client1}) + endif() + #message("client is ${CLIENT}") + endif() + endif() +endmacro( GetClientName ) + +############################################################################## +## +## The main driver for executing datatool +## + +macro( RunDatatool MODULE MODULE_SEARCH ) + if ("${MODULE_EXT}" STREQUAL "") + set(MODULE_EXT "asn") + endif() + + if ("${MODULE_PATH_RELATIVE}" STREQUAL "") + #set(MODULE_PATH_RELATIVE "objects/${MODULE}") + get_filename_component(MODULE_PATH_RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" REALPATH) + get_filename_component(tmp "${top_src_dir}/src" REALPATH) + string(REPLACE "${tmp}/" "" MODULE_PATH_RELATIVE "${MODULE_PATH_RELATIVE}") + endif() + + foreach(mod ${MODULE_IMPORT}) + set(LOCAL_MODULE_IMPORT ${LOCAL_MODULE_IMPORT} ${mod}.${MODULE_EXT}) + endforeach(mod) + + + #message(" searching for: ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}.${MODULE_EXT}") + set(MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}.${MODULE_EXT}) + set(MODULE_DEFS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}.module) + if (NOT EXISTS "${MODULE_PATH}") + #message(" searching for: ${CMAKE_CURRENT_SOURCE_DIR}/../${MODULE}/${MODULE}.${MODULE_EXT}") + set(MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../${MODULE}/${MODULE}.${MODULE_EXT}) + set(MODULE_DEFS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../${MODULE}/${MODULE}.module) + endif() + if (NOT EXISTS "${MODULE_PATH}") + #message(" searching for: ${CMAKE_CURRENT_SOURCE_DIR}/../../${MODULE_PATH_RELATIVE}/${MODULE}.${MODULE_EXT}") + set(MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../${MODULE_PATH_RELATIVE}/${MODULE}.${MODULE_EXT}) + set(MODULE_DEFS_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../../${MODULE_PATH_RELATIVE}/${MODULE}.module) + endif() + if (NOT EXISTS "${MODULE_PATH}") + message(SEND_ERROR "The requested module '${MODULE}' cannot be found") + endif() + + get_filename_component(MODULE_PATH "${MODULE_PATH}" REALPATH) + get_filename_component(MODULE_DEFS_FILE "${MODULE_DEFS_FILE}" REALPATH) + + ReadModuleSpec( "${MODULE_DEFS_FILE}") + GetClientName("${MODULE}") + + get_filename_component(SOURCE_PATH "${MODULE_PATH}" PATH) + get_filename_component(tmp__cpp "${SOURCE_PATH}/${MODULE}__.cpp" REALPATH) + get_filename_component(tmp___cpp "${SOURCE_PATH}/${MODULE}___.cpp" REALPATH) + + set(generated) + list(APPEND generated ${tmp__cpp} ${tmp___cpp} ${CLIENT}) + CheckVersionControl(${generated}) + + #message("module = ${MODULE}") + #message(" module_path = ${MODULE_PATH}") + #message(" relative module_path = ${MODULE_PATH_RELATIVE}") + #message(" source_path = ${SOURCE_PATH}") + #message(" generated files = ${generated}") + + + SET_SOURCE_FILES_PROPERTIES(${tmp__cpp} ${tmp___cpp} ${CLIENT} PROPERTIES GENERATED 1) + #SET_TARGET_PROPERTIES(${MODULE} PROPERTIES LINKER_LANGUAGE CXX) + SET(NEW_MODULE_FILES ${SOURCE_PATH}/${MODULE}__.cpp ${SOURCE_PATH}/${MODULE}___.cpp) + + if (WIN32) + add_custom_command( + OUTPUT ${generated} + COMMAND ${NCBI_DATATOOL} -oR "${top_src_dir}" -opm "${MODULE_SEARCH}" -m "${MODULE_PATH}" -M "${MODULE_IMPORT}" -oA -oc "${MODULE}" -or "${MODULE_PATH_RELATIVE}" -odi -od "${SOURCE_PATH}/${MODULE}.def" -ocvs -pch "ncbi_pch.hpp" -fd ${MODULE}.dump VERBATIM + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Generating module: ${MODULE}" + DEPENDS ${NCBI_DATATOOL} ${MODULE_PATH} + VERBATIM + ) + else() + add_custom_command( + OUTPUT ${generated} + COMMAND ${NCBI_DATATOOL} -oR \"${top_src_dir}\" -opm \"${MODULE_SEARCH}\" -m \"${MODULE_PATH}\" -M \""${MODULE_IMPORT}"\" -oA -oc \"${MODULE}\" -or \"${MODULE_PATH_RELATIVE}\" -odi -od \"${SOURCE_PATH}/${MODULE}.def\" -ocvs -pch \"ncbi_pch.hpp\" -fd ${MODULE}.dump + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Generating module: ${MODULE}" + DEPENDS ${NCBI_DATATOOL} ${MODULE_PATH} + ) + endif() + +endmacro( RunDatatool ) + +############################################################################## +## +## only add executables if not running in Windows +## + +if (WIN32) + macro( include ) + if (NOT ${ARGV0} MATCHES ".app.txt$") + _include(${ARGN}) + endif (NOT ${ARGV0} MATCHES ".app.txt$") + endmacro(include) +endif (WIN32) diff --git a/c++/src/build-system/cmake/FindBerkeleyDB.cmake b/c++/src/build-system/cmake/FindBerkeleyDB.cmake new file mode 100644 index 00000000..57a6f1db --- /dev/null +++ b/c++/src/build-system/cmake/FindBerkeleyDB.cmake @@ -0,0 +1,38 @@ +# Find Berkley DB + +if (APPLE) + set(BUILD_PREFIX "Clang320-") +endif (APPLE) + +set(BerkeleyDB_FOUND NO) + +FIND_PATH( BERKELEYDB_INCLUDE_DIR db.h + PATHS ${NCBI_TOOLS_ROOT}/BerkeleyDB/include/ + /usr/local/include + /usr/include + ) + +IF (BERKELEYDB_INCLUDE_DIR) + FIND_LIBRARY( BERKELEYDB_LIBRARY NAMES db + PATHS ${CMAKE_PREFIX_PATH} + "${NCBI_TOOLS_ROOT}/BerkeleyDB/${BUILD_PREFIX}${CMAKE_BUILD_TYPE}/" + /usr/local/lib + /usr/lib + ) + + IF (BERKELEYDB_LIBRARY) + set(BerkeleyDB_FOUND Yes) + get_filename_component(BERKELEYDB_LIBDIR ${BERKELEYDB_LIBRARY} DIRECTORY) + get_filename_component(BERKELEYDB_LIBNAME ${BERKELEYDB_LIBRARY} NAME) + get_filename_component(BERKELEYDB_LIBDIR ${BERKELEYDB_LIBDIR} REALPATH) + set(BERKELEYDB_LIBRARY ${BERKELEYDB_LIBDIR}/${BERKELEYDB_LIBNAME}) + + set(BERKELEYDB_LIBRARIES ${BERKELEYDB_LIBRARY} -Wl,-rpath,${BERKELEYDB_LIBDIR}) + ELSE (BERKELEYDB_LIBRARY) + MESSAGE(WARNING "Include ${BERKELEYDB_INCLUDE}/db.h found, but no library in ${NCBI_TOOLS_ROOT}/BerkeleyDB/${BUILD_PREFIX}${CMAKE_BUILD_TYPE}/ ") + ENDIF (BERKELEYDB_LIBRARY) + + MESSAGE(STATUS "Found BerkeleyDB: ${BERKELEYDB_LIBRARY}") + MESSAGE(STATUS " BerkeleyDB Libraries: ${BERKELEYDB_LIBRARIES}") + MESSAGE(STATUS " BerkeleyDB INCLUDE: ${BERKELEYDB_INCLUDE_DIR}") +ENDIF (BERKELEYDB_INCLUDE_DIR) diff --git a/c++/src/build-system/cmake/FindExternalLibrary.cmake b/c++/src/build-system/cmake/FindExternalLibrary.cmake new file mode 100644 index 00000000..1e925b46 --- /dev/null +++ b/c++/src/build-system/cmake/FindExternalLibrary.cmake @@ -0,0 +1,251 @@ +include(CMakeParseArguments) + +function(update_final_message) + list(GET ARGN 0 ARG_LIBNAME_ORIG) + if (${ARGC} GREATER 1) + list(GET ARGN 1 ARG_PRINT_NAME) + else() + set(ARG_PRINT_NAME ${ARG_LIBNAME_ORIG}) + endif() + string(TOUPPER ${ARG_LIBNAME_ORIG} ARG_LIBNAME) + if ("${ARG_LIBNAME}_DISABLED" STREQUAL "yes") + set(EXTERNAL_LIBRARIES_COMMENT "${EXTERNAL_LIBRARIES_COMMENT}\n${ARG_PRINT_NAME}: disabled" PARENT_SCOPE) + elseif(${${ARG_LIBNAME}_FOUND}) + set(EXTERNAL_LIBRARIES_COMMENT "${EXTERNAL_LIBRARIES_COMMENT}\n${ARG_PRINT_NAME}: ${${ARG_LIBNAME}_LIBS}\n${ARG_PRINT_NAME} include: ${${ARG_LIBNAME}_INCLUDE}" PARENT_SCOPE) + else() + set(EXTERNAL_LIBRARIES_COMMENT "${EXTERNAL_LIBRARIES_COMMENT}\n${ARG_PRINT_NAME}: not found" PARENT_SCOPE) + endif() +endfunction() + +function(find_external_library) + cmake_parse_arguments(ARG "DYNAMIC_ONLY" "PACKAGE_NAME" "EXTRALIBS" ${ARGN}) + #list(LENGTH "${ARG_EXTRALIBS}" COUNT) + #message("EXTRALIBS: ${ARG_EXTRALIBS} COUNT: ${COUNT}") + list(GET ARGN 0 ARG_LIBNAME_ORIG) + string(TOUPPER ${ARG_LIBNAME_ORIG} ARG_LIBNAME) + if ("${BUILD_SHARED_LIBS}" STREQUAL "OFF" AND NOT ${ARG_DYNAMIC_ONLY}) + set(CMAKE_FIND_LIBRARY_SUFFIXES_OLD "${CMAKE_FIND_LIBRARY_SUFFIXES}") + set(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_STATIC_LIBRARY_SUFFIX}") + set("LINKER_FLAG_PREFIX" "-Wl,-Bstatic") + set("LINKER_FLAG_SUFFIX" "-Wl,-Bdynamic") + find_external_library_impl("${ARGN}") + unset(LINKER_FLAG_PREFIX) + unset(LINKER_FLAG_SUFFIX) + set(CMAKE_FIND_LIBRARY_SUFFIXES "${CMAKE_FIND_LIBRARY_SUFFIXES_OLD}") + if (${${ARG_LIBNAME}_FOUND}) + else () + #message("STATIC NOT FOUND, LOOKING FOR DYNAMIC") + find_external_library_impl("${ARGN}") + endif () + else () + find_external_library_impl("${ARGN}") + endif () + if (${${ARG_LIBNAME}_FOUND}) + set("${ARG_LIBNAME}_FOUND" ${${ARG_LIBNAME}_FOUND} PARENT_SCOPE) + set("${ARG_LIBNAME}_INCLUDE" ${${ARG_LIBNAME}_INCLUDE} PARENT_SCOPE) + #set(LIBS "") + #list(APPEND LIBS ${${ARG_LIBNAME}_LIBS}) + #list(APPEND LIBS ${ARG_EXTRALIBS}) + #set("${ARG_LIBNAME}_LIBS" ${LIBS} PARENT_SCOPE) + + list(APPEND ${ARG_LIBNAME}_LIBS ${ARG_EXTRALIBS}) + set("${ARG_LIBNAME}_LIBS" "${${ARG_LIBNAME}_LIBS}" PARENT_SCOPE) + + #list(APPEND ARG_EXTRALIBS ${${ARG_LIBNAME}_LIBS}) + #set("${ARG_LIBNAME}_LIBS" "${ARG_EXTRALIBS}" PARENT_SCOPE) + + #set(LIBS "${${ARG_LIBNAME}_LIBS};${ARG_EXTRALIBS}") + #string (REPLACE ";" " " LIBS_STR "${LIBS}") + #set("${ARG_LIBNAME}_LIBS" "${LIBS}" PARENT_SCOPE) + list(APPEND NCBI_MODULES_FOUND "${ARG_LIBNAME_ORIG}") + endif () +endfunction() + +function(convert_link_string FILES) + foreach(PATH ${FILES}) + get_filename_component(D "${PATH}" DIRECTORY) + get_filename_component(FFULL "${PATH}" NAME) + #set(SUBSTRING "${FFULL}" 3 -1 F) + string(REGEX MATCH ".a$" ISSTATIC ${FFULL}) + string(REGEX REPLACE "^lib" "" F0 ${FFULL}) + string(REGEX REPLACE ".(so|a)$" "" F ${F0}) + if (NOT ("${D}" STREQUAL "/usr/lib" OR "${D}" STREQUAL "/usr/lib64")) + if ("${RES}" STREQUAL "") + set(RES "-L${D}" "-l${F}") + else () + set(RES ${RES} "-L${D}" "-l${F}") + endif() + else () + if ("${RES}" STREQUAL "") + set(RES "-l${F}") + else () + set(RES ${RES} "-l${F}") + endif() + endif() + endforeach() + if (NOT "${ISSTATIC}" STREQUAL "") + set(CONVERTED_LIB_STRING ${LINKER_FLAG_PREFIX} ${RES} ${LINKER_FLAG_SUFFIX} PARENT_SCOPE) + else () + set(CONVERTED_LIB_STRING ${RES} PARENT_SCOPE) + endif() +endfunction() + +function(find_libraries) + cmake_parse_arguments(ARG "NO_DEFAULT_PATH;NO_CMAKE_ENVIRONMENT_PATH;NO_CMAKE_PATH;NO_SYSTEM_ENVIRONMENT_PATH;NO_CMAKE_SYSTEM_PATH" "PATH" "NAMES;HINTS" ${ARGN}) + list(GET ARGN 0 OUT_VARIABLE_NAME) + foreach (LIBNAME ${ARG_NAMES}) + unset(LIB_OUT CACHE) + find_library(LIB_OUT NAMES ${LIBNAME} + HINTS ${ARG_HINTS} + ${ARG_NO_DEFAULT_PATH} + ${ARG_NO_CMAKE_ENVIRONMENT_PATH} + ${ARG_NO_CMAKE_PATH} + ${ARG_NO_SYSTEM_ENVIRONMENT_PATH} + ${ARG_NO_CMAKE_SYSTEM_PATH}) + if ("${LIB_OUT}" STREQUAL "LIB_OUT-NOTFOUND") + set(${${OUT_VARIABLE_NAME}} "${OUT_VARIABLE_NAME}-NOTFOUND" PARENT_SCOPE) + return () + endif() + set(RES ${RES} ${LIB_OUT}) + endforeach() + #message("OUT: " ${RES}) + set("${OUT_VARIABLE_NAME}" ${RES} PARENT_SCOPE) +endfunction() + +function(find_external_library_impl) + list(GET ARGN 0 ARG_LIBNAME_ORIG) + string(TOUPPER ${ARG_LIBNAME_ORIG} ARG_LIBNAME) + cmake_parse_arguments(ARG "DO_NOT_UPDATE_MESSAGE" "INCLUDES;HINTS;INCLUDE_HINTS;LIBS_HINTS;EXTRAFLAGS;PRINT_NAME;PACKAGE_NAME" "LIBS" ${ARGN}) + #message("LIBNAME: ${ARG_LIBNAME}") + + if (NOT "${ARG_HINTS}" STREQUAL "") + set(ARG_INCLUDE_HINTS "${ARG_HINTS}/include") + set(ARG_LIBS_HINTS "${ARG_HINTS}/lib") + endif() + + if ("${ARG_PACKAGE_NAME}" STREQUAL "") + set(ARG_PACKAGE_NAME "${ARG_LIBNAME_ORIG}") + endif () + string(TOUPPER ${ARG_PACKAGE_NAME} ARG_PACKAGE_NAME_UPPER) + + #debug + #message("ARG_LIBNAME_ORIG ${ARG_LIBNAME_ORIG} LIBNAME ${ARG_LIBNAME} VALUE ${${ARG_LIBNAME}}") + #message("HINTS ${ARG_HINTS} INCLUDE_HINTS ${ARG_INCLUDE_HINTS} LIBS_HINTS ${ARG_LIBS_HINTS}") + #message("INCLUDES ${ARG_INCLUDES} LIBS ${ARG_LIBS} EXTRAFLAGS ${ARG_EXTRAFLAGS}") + + if (NOT ARG_LIBNAME) + message(FATAL_ERROR "find_external_library: library name not provided") + endif() + + if ("${ARG_LIBNAME}_DISABLED" STREQUAL "yes") + set("${ARG_LIBNAME}_FOUND" false) + return() + endif() + + #find_library and find_path declare their output variables as cached (see cmake type system) + #so, we need to reset them + unset(EXT_LIBRARY CACHE) + unset(EXT_INCLUDE_DIR CACHE) + + if (NOT "${${ARG_LIBNAME}}" STREQUAL "") + find_libraries(EXT_LIBRARY NAMES ${ARG_LIBS} + PATH "${${ARG_LIBNAME}}/lib" + NO_DEFAULT_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_CMAKE_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + #if (NOT "${EXT_INCLUDE_DIR}" STREQUAL "") + find_path(EXT_INCLUDE_DIR NAMES ${ARG_INCLUDES} + PATH "${${ARG_LIBNAME}}/include" + NO_DEFAULT_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_CMAKE_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + #endif() + + elseif (NOT "${ARG_LIBS_HINTS}" STREQUAL "") + set(CMAKE_PREFIX_PATH_OLD "${CMAKE_PREFIX_PATH}") + set(CMAKE_PREFIX_PATH "${ARG_HINTS}") + find_package(${ARG_PACKAGE_NAME} QUIET) + set(CMAKE_PREFIX_PATH "${CMAKE_PREFIX_PATH_OLD}") + + if (${${ARG_PACKAGE_NAME_UPPER}_FOUND}) + if (NOT "${${ARG_PACKAGE_NAME_UPPER}_INCLUDE_DIRS}" STREQUAL "") + set(EXT_INCLUDE_DIR "${${ARG_PACKAGE_NAME_UPPER}_INCLUDE_DIRS}") + endif () + if (NOT "${${ARG_PACKAGE_NAME_UPPER}_INCLUDE_DIR}" STREQUAL "") + set(EXT_INCLUDE_DIR "${${ARG_PACKAGE_NAME_UPPER}_INCLUDE_DIR}") + endif () + set("${ARG_LIBNAME}_FOUND" true PARENT_SCOPE) + set("${ARG_LIBNAME}_INCLUDE" "${EXT_INCLUDE_DIR}" PARENT_SCOPE) + if ("${ARG_EXTRAFLAGS}" STREQUAL "") + set("${ARG_LIBNAME}_LIBS" ${${ARG_PACKAGE_NAME_UPPER}_LIBRARIES} PARENT_SCOPE) + else () + convert_link_string("${${ARG_PACKAGE_NAME_UPPER}_LIBRARIES}") + set("${ARG_LIBNAME}_LIBS" ${CONVERTED_LIB_STRING} ${ARG_EXTRAFLAGS} PARENT_SCOPE) + endif () + message(STATUS "Found ${ARG_PACKAGE_NAME}: ${${ARG_PACKAGE_NAME_UPPER}_LIBRARIES}") + return() + else () + #message("${ARG_LIBNAME_ORIG} NOT FOUND AS PACKAGE") + #message("ARG_LIBS: ${ARG_LIBS} LIB_HINTS: ${ARG_LIBS_HINTS}") + find_libraries(EXT_LIBRARY NAMES ${ARG_LIBS} + HINTS + ${ARG_LIBS_HINTS}) + find_path(EXT_INCLUDE_DIR NAMES ${ARG_INCLUDES} + HINTS + ${ARG_INCLUDE_HINTS}) + endif() + + else() + find_package(${ARG_PACKAGE_NAME} QUIET) + if (${${ARG_PACKAGE_NAME_UPPER}_FOUND}) + if (NOT "${${ARG_PACKAGE_NAME_UPPER}_INCLUDE_DIRS}" STREQUAL "") + set(EXT_INCLUDE_DIR "${${ARG_PACKAGE_NAME_UPPER}_INCLUDE_DIRS}") + endif () + if (NOT "${${ARG_PACKAGE_NAME_UPPER}_INCLUDE_DIR}" STREQUAL "") + set(EXT_INCLUDE_DIR "${${ARG_PACKAGE_NAME_UPPER}_INCLUDE_DIR}") + endif () + #convert_link_string("${${ARG_PACKAGE_NAME_UPPER}_LIBRARIES}") + set("${ARG_LIBNAME}_FOUND" true PARENT_SCOPE) + set("${ARG_LIBNAME}_INCLUDE" "${EXT_INCLUDE_DIR}" PARENT_SCOPE) + #set("${ARG_LIBNAME}_LIBS" "${${ARG_PACKAGE_NAME_UPPER}_LIBRARIES}" "${ARG_EXTRAFLAGS}" PARENT_SCOPE) + if ("${ARG_EXTRAFLAGS}" STREQUAL "") + set("${ARG_LIBNAME}_LIBS" ${${ARG_PACKAGE_NAME_UPPER}_LIBRARIES} PARENT_SCOPE) + else () + convert_link_string("${${ARG_PACKAGE_NAME_UPPER}_LIBRARIES}") + set("${ARG_LIBNAME}_LIBS" ${CONVERTED_LIB_STRING} ${ARG_EXTRAFLAGS} PARENT_SCOPE) + endif() + message(STATUS "Found ${ARG_PACKAGE_NAME}: ${${ARG_PACKAGE_NAME_UPPER}_LIBRARIES}") + return() + else () + #message("${ARG_LIBNAME_ORIG} NOT FOUND AS PACKAGE") + find_libraries(EXT_LIBRARY NAMES ${ARG_LIBS}) + find_path(EXT_INCLUDE_DIR NAMES ${ARG_INCLUDES}) + endif() + endif() + + #message(FATAL_ERROR "EXT_LIBRARY: ${EXT_LIBRARY} EXT_INCLUDE_DIR: ${EXT_INCLUDE_DIR}") + FIND_PACKAGE_HANDLE_STANDARD_ARGS("${ARG_LIBNAME}" + REQUIRED_VARS EXT_LIBRARY EXT_INCLUDE_DIR) + unset(FINAL_LIBS) + if (${${ARG_LIBNAME}_FOUND}) + set("${ARG_LIBNAME}_INCLUDE" "${EXT_INCLUDE_DIR}" PARENT_SCOPE) + if ("${ARG_EXTRAFLAGS}" STREQUAL "") + set("${ARG_LIBNAME}_LIBS" ${EXT_LIBRARY} PARENT_SCOPE) + else () + convert_link_string("${EXT_LIBRARY}") + set("${ARG_LIBNAME}_LIBS" ${CONVERTED_LIB_STRING} ${ARG_EXTRAFLAGS} PARENT_SCOPE) + endif() + #set("${ARG_LIBNAME}_LIBS" ${LINKER_FLAG_PREFIX} ${CONVERTED_LIB_STRING} ${LINKER_FLAG_SUFFIX} PARENT_SCOPE) + #set("${ARG_LIBNAME}_LIBS" ${CONVERTED_LIB_STRING} ${ARG_EXTRAFLAGS} PARENT_SCOPE) + #set("${ARG_LIBNAME}_LIBS" "${EXT_LIBRARY}" "${ARG_EXTRAFLAGS}" PARENT_SCOPE) + endif() + set("${ARG_LIBNAME}_FOUND" ${${ARG_LIBNAME}_FOUND} PARENT_SCOPE) + if (NOT ${${ARG_LIBNAME}_FOUND}) + message(STATUS "Could NOT find ${ARG_PACKAGE_NAME}") + endif() + +endfunction() diff --git a/c++/src/build-system/cmake/FindFTGL.cmake b/c++/src/build-system/cmake/FindFTGL.cmake new file mode 100644 index 00000000..2045e398 --- /dev/null +++ b/c++/src/build-system/cmake/FindFTGL.cmake @@ -0,0 +1,146 @@ +# - Find FTGL +# Find the native FTGL headers and libraries. +# from project OpenFlipper +# +# FTGL_INCLUDE_DIR - where to find FTGL.h, etc. +# FTGL_LIBRARIES - List of libraries when using FTGL. +# FTGL_FOUND - True if FTGL found. + +GET_FILENAME_COMPONENT(module_file_path ${CMAKE_CURRENT_LIST_FILE} PATH ) + +# Look for the header file. +FIND_PATH(FTGL_INCLUDE_DIR NAMES FTGL/ftgl.h + PATH_SUFFIXES include + PATHS /usr + /usr/local + ../../External + "C:\\libs\\ftgl\\ftgl" + ${FTGL_ROOT} + ${module_file_path}/../../../External) +#MARK_AS_ADVANCED(FTGL_INCLUDE_DIR) + +if ( WIN32 ) + # Look for the library. + FIND_LIBRARY(FTGL_LIBRARY_RELEASE NAMES ftgl ftgl_dynamic_MTD + PATH_SUFFIXES lib64 lib Build + PATHS /usr + /usr/local + /usr + /usr/local + ../../External + ${FTGL_ROOT} + "C:\\libs\\ftgl\\msvc" + ${module_file_path}/../../../External) + + FIND_LIBRARY(FTGL_LIBRARY_DEBUG NAMES ftgl_d ftgld + PATH_SUFFIXES lib64 lib Build + PATHS /usr + /usr/local + /usr + /usr/local + ../../External + ${FTGL_ROOT} + "C:\\libs\\ftgl\\msvc" + ${module_file_path}/../../../External) + + set( FTGL_LIBRARY optimized;${FTGL_LIBRARY_RELEASE};debug;${FTGL_LIBRARY_DEBUG} ) + + # Get paths to libraries. Required to link to libs and copy dlls from there + GET_FILENAME_COMPONENT( FTGL_LIBRARY_DIR_RELEASE ${FTGL_LIBRARY_RELEASE} PATH ) + GET_FILENAME_COMPONENT( FTGL_LIBRARY_DIR_DEBUG ${FTGL_LIBRARY_DEBUG} PATH ) + list(APPEND FTGL_LIBRARY_DIRS ${FTGL_LIBRARY_DIR_DEBUG} ${FTGL_LIBRARY_DIR_RELEASE} ) + +else(WIN32) + FIND_LIBRARY(FTGL_LIBRARY NAMES ftgl ftgl_dynamic_MTD + PATHS /usr/lib64 + /usr/local/lib64 + /usr/lib + /usr/local/lib + ../../External/lib + ${FTGL_ROOT} + "C:\\libs\\ftgl\\msvc\\Build" + ${module_file_path}/../../../External/lib) + + +endif(WIN32) + + +#MARK_AS_ADVANCED(FTGL_LIBRARY) + +IF( WIN32 AND PREFER_STATIC_LIBRARIES ) + SET( FTGL_STATIC_LIBRARY_NAME ftgl_static_MTD ) + IF( MSVC80 ) + SET( FTGL_STATIC_LIBRARY_NAME ftgl_static_MTD_vc8 ) + ELSEIF( MSVC90 ) + SET( FTGL_STATIC_LIBRARY_NAME ftgl_static_MTD_vc9 ) + ENDIF( MSVC80 ) + + FIND_LIBRARY( FTGL_STATIC_LIBRARY NAMES ${FTGL_STATIC_LIBRARY_NAME} + PATHS /usr/lib64 + /usr/local/lib64 + /usr/lib + /usr/local/lib + ../../External/lib + ${module_file_path}/../../../External/lib ) + MARK_AS_ADVANCED(FTGL_STATIC_LIBRARY) + + FIND_LIBRARY( FTGL_STATIC_DEBUG_LIBRARY NAMES ${FTGL_STATIC_LIBRARY_NAME}_d + PATHS /usr/lib64 + /usr/local/lib64 + /usr/lib + /usr/local/lib + ../../External/lib + ${module_file_path}/../../../External/lib ) + MARK_AS_ADVANCED(FTGL_STATIC_DEBUG_LIBRARY) + + IF( FTGL_STATIC_LIBRARY OR FTGL_STATIC_DEBUG_LIBRARY ) + SET( FTGL_STATIC_LIBRARIES_FOUND 1 ) + ENDIF( FTGL_STATIC_LIBRARY OR FTGL_STATIC_DEBUG_LIBRARY ) +ENDIF( WIN32 AND PREFER_STATIC_LIBRARIES ) + +IF( FTGL_LIBRARY OR FTGL_STATIC_LIBRARIES_FOUND ) + SET( FTGL_LIBRARIES_FOUND 1 ) +ENDIF( FTGL_LIBRARY OR FTGL_STATIC_LIBRARIES_FOUND ) + +# Copy the results to the output variables. +IF(FTGL_INCLUDE_DIR AND FTGL_LIBRARIES_FOUND) + SET(FTGL_FOUND 1) + + IF( WIN32 AND PREFER_STATIC_LIBRARIES AND FTGL_STATIC_LIBRARIES_FOUND ) + IF(FTGL_STATIC_LIBRARY) + SET(FTGL_LIBRARIES optimized ${FTGL_STATIC_LIBRARY} ) + ELSE(FTGL_STATIC_LIBRARY) + SET(FTGL_LIBRARIES optimized ${FTGL_STATIC_LIBRARY_NAME} ) + MESSAGE( STATUS, "FTGL static release libraries not found. Release build might not work." ) + ENDIF(FTGL_STATIC_LIBRARY) + + IF(FTGL_STATIC_DEBUG_LIBRARY) + SET(FTGL_LIBRARIES ${FTGL_LIBRARIES} debug ${FTGL_STATIC_DEBUG_LIBRARY} ) + ELSE(FTGL_STATIC_DEBUG_LIBRARY) + SET(FTGL_LIBRARIES ${FTGL_LIBRARIES} debug ${FTGL_STATIC_LIBRARY_NAME}_d ) + MESSAGE( STATUS, "FTGL static debug libraries not found. Debug build might not work." ) + ENDIF(FTGL_STATIC_DEBUG_LIBRARY) + + SET( FTGL_LIBRARY_STATIC 1 ) + ELSE( WIN32 AND PREFER_STATIC_LIBRARIES AND FTGL_STATIC_LIBRARIES_FOUND ) + SET(FTGL_LIBRARIES ${FTGL_LIBRARY}) + ENDIF( WIN32 AND PREFER_STATIC_LIBRARIES AND FTGL_STATIC_LIBRARIES_FOUND ) + + SET(FTGL_INCLUDE_DIR ${FTGL_INCLUDE_DIR}) +ELSE(FTGL_INCLUDE_DIR AND FTGL_LIBRARIES_FOUND) + SET(FTGL_FOUND 0) + SET(FTGL_LIBRARIES) + SET(FTGL_INCLUDE_DIR) +ENDIF(FTGL_INCLUDE_DIR AND FTGL_LIBRARIES_FOUND) + +# Report the results. +IF(NOT FTGL_FOUND) + SET(FTGL_DIR_MESSAGE + "FTGL was not found. Make sure FTGL_LIBRARY and FTGL_INCLUDE_DIR are set to the directories containing the include and lib files for FTGL. If you do not have the library you will not be able to use the Text node.") + IF(FTGL_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "${FTGL_DIR_MESSAGE}") + ELSEIF(NOT FTGL_FIND_QUIETLY) + MESSAGE(STATUS "${FTGL_DIR_MESSAGE}") + ELSE(NOT FTGL_FIND_QUIETLY) + ENDIF(FTGL_FIND_REQUIRED) +ENDIF(NOT FTGL_FOUND) diff --git a/c++/src/build-system/cmake/FindLZO.cmake b/c++/src/build-system/cmake/FindLZO.cmake new file mode 100644 index 00000000..8ef721d8 --- /dev/null +++ b/c++/src/build-system/cmake/FindLZO.cmake @@ -0,0 +1,43 @@ +# Find liblzo2 +# LZO_FOUND - system has the LZO library +# LZO_INCLUDE_DIR - the LZO include directory +# LZO_LIBRARIES - The libraries needed to use LZO + +if (LZO_INCLUDE_DIR AND LZO_LIBRARIES) + # in cache already + SET(LZO_FOUND TRUE) +else (LZO_INCLUDE_DIR AND LZO_LIBRARIES) + FIND_PATH(LZO_INCLUDE_DIR lzo/lzo1x.h + ${LZO_ROOT}/include/ + /usr/include/ + /usr/local/include/ + /sw/lib/ + /sw/local/lib/ + ) + + if(WIN32 AND MSVC) + FIND_LIBRARY(LZO_LIBRARIES NAMES liblzo + PATHS + ${CMAKE_PREFIX_PATH} + ${LZO_ROOT}/lib + ) + endif(WIN32 AND MSVC) + + if (LZO_INCLUDE_DIR AND LZO_LIBRARIES) + set(LZO_FOUND TRUE) + endif (LZO_INCLUDE_DIR AND LZO_LIBRARIES) + + if (LZO_FOUND) + if (NOT LZO_FIND_QUIETLY) + message(STATUS "Found LZO: ${LZO_LIBRARIES}") + endif (NOT LZO_FIND_QUIETLY) + else (LZO_FOUND) + if (LZO_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find LZO") + else() + message(STATUS "Could NOT find LZO") + endif (LZO_FIND_REQUIRED) + endif (LZO_FOUND) + + MARK_AS_ADVANCED(LZO_INCLUDE_DIR LZO_LIBRARIES) +endif (LZO_INCLUDE_DIR AND LZO_LIBRARIES) diff --git a/c++/src/build-system/cmake/FindMongoCXX.cmake b/c++/src/build-system/cmake/FindMongoCXX.cmake new file mode 100644 index 00000000..29314532 --- /dev/null +++ b/c++/src/build-system/cmake/FindMongoCXX.cmake @@ -0,0 +1,46 @@ +# Mike DiCuccio (dicuccio@ncbi.nlm.nih.gov) +# +# Find the Mongo-CXX driver +# +# This will set: +# MONGOCXX_FOUND +# MONGOCXX_INCLUDE_DIRS +# MONGOCXX_LIBRARIES +# BSONCXX_LIBRARIES +# BSONCXX_INCLUDE_DIRS +# +# Use as: ${MONGOCXX_LIBPATH} ${MONGOCXX_LIBRARIES} ${BSONCXX_LIBRARIES} + + +find_package(LIBMONGOCXX REQUIRED + PATHS $ENV{NCBI}/mongodb-3.0.2/ + NO_DEFAULT_PATH +) + +find_package(LIBBSONCXX REQUIRED + PATHS $ENV{NCBI}/mongodb-3.0.2/ + NO_DEFAULT_PATH +) + + + +if (LIBMONGOCXX_FOUND AND LIBBSONCXX_FOUND) + set(MONGOCXX_FOUND TRUE) + + set(MONGOCXX_INCLUDE_DIRS ${LIBMONGOCXX_INCLUDE_DIRS}) + set(MONGOCXX_LIBRARIES ${LIBMONGOCXX_LIBRARIES}) + set(MONGOCXX_VERSION_STRING ${LIBMONGOCXX_VERSION}) + + set(BSONCXX_INCLUDE_DIRS ${LIBBSONCXX_INCLUDE_DIRS}) + set(BSONCXX_LIBRARIES ${LIBBSONCXX_LIBRARIES}) + set(BSONCXX_VERSION_STRING ${LIBBSONCXX_VERSION}) + + set(MONGOCXX_LIBPATH -L${LIBMONGOCXX_LIBRARY_DIRS} -Wl,-rpath,${LIBMONGOCXX_LIBRARY_DIRS}) + + message(STATUS "Found MongoDB: ${MONGOCXX_LIBRARIES} ${BSONCXX_LIBRARIES} (found version \"${MONGOCXX_VERSION_STRING}\")") +else() + set(MONGOCXX_FOUND FALSE) + message(STATUS "Cannot find MongoDB") +endif() + + diff --git a/c++/src/build-system/cmake/FindMysql.cmake b/c++/src/build-system/cmake/FindMysql.cmake new file mode 100644 index 00000000..b9dd4eac --- /dev/null +++ b/c++/src/build-system/cmake/FindMysql.cmake @@ -0,0 +1,73 @@ +# Find MySQL + +# Find the native MySQL includes and library +# +# MYSQL_INCLUDE_DIR - where to find mysql.h, etc. +# MYSQL_LIBRARIES - List of libraries when using MySQL. +# MYSQL_FOUND - True if MySQL found. + +if(MYSQL_INCLUDE_DIR OR MYSQL_) + # Already in cache, be silent + SET(MYSQL_FIND_QUIETLY TRUE) +endif() + +if(NOT WIN32) + find_program(MYSQL_CONFIG_EXECUTABLE mysql_config + /usr/bin/ + /usr/local/bin + $ENV{MYSQL_DIR}/bin + ) +endif() + +if(MYSQL_CONFIG_EXECUTABLE) + execute_process(COMMAND ${MYSQL_CONFIG_EXECUTABLE} --cflags OUTPUT_VARIABLE MYSQL_CFLAGS OUTPUT_STRIP_TRAILING_WHITESPACE) + separate_arguments(MYSQL_CFLAGS) + string( REGEX MATCH "-I[^;]+" MYSQL_INCLUDE_DIR "${MYSQL_CFLAGS}" ) + string( REPLACE "-I" "" MYSQL_INCLUDE_DIR "${MYSQL_INCLUDE_DIR}") + string( REGEX REPLACE "-I[^;]+;" "" MYSQL_CFLAGS "${MYSQL_CFLAGS}" ) + execute_process(COMMAND ${MYSQL_CONFIG_EXECUTABLE} --libs OUTPUT_VARIABLE MYSQL_LIBRARIES OUTPUT_STRIP_TRAILING_WHITESPACE) +else() + find_path(MYSQL_INCLUDE_DIR mysql.h + /usr/local/mysql/include + /usr/local/include/mysql + /usr/local/include + /usr/include/mysql + /usr/include + /usr/mysql/include + $ENV{MYSQL_DIR}/include + ) + set(MYSQL_NAMES mysqlclient mysqlclient_r) + find_library(MYSQL_LIBRARY NAMES ${MYSQL_NAMES} + PATHS /usr/local/mysql/lib /usr/local/lib /usr/lib $ENV{MYSQL_DIR}/lib $ENV{MYSQL_DIR}/lib/opt + ) + set(MYSQL_LIBRARIES ${MYSQL_LIBRARY}) +endif() + +if(MYSQL_INCLUDE_DIR AND MYSQL_LIBRARIES) + set(MYSQL_FOUND TRUE) + if(WIN32) + string(REPLACE mysqlclient libmysql libmysql ${MYSQL_LIBRARY}) + set(MYSQL_LIBRARIES ${libmysql} ${MYSQL_LIBRARIES}) + endif() +else() + set(MYSQL_FOUND FALSE) + set(MYSQL_LIBRARIES ) +endif() + +if(MYSQL_FOUND) + if(NOT MYSQL_FIND_QUIETLY) + message(STATUS "Found MySQL libraries: ${MYSQL_LIBRARIES}") + message(STATUS "Found MySQL includes: ${MYSQL_INCLUDE_DIR}") + endif() +else() + if(MYSQL_FIND_REQUIRED) + message(STATUS "Looked for MySQL libraries named ${MYSQL_NAMES}.") + message(FATAL_ERROR "Could NOT find MySQL library") + endif() +endif() + +mark_as_advanced( + MYSQL_CONFIG_EXECUTABLE + MYSQL_LIBRARY + MYSQL_INCLUDE_DIR +) diff --git a/c++/src/build-system/cmake/FindOSMesa.cmake b/c++/src/build-system/cmake/FindOSMesa.cmake new file mode 100644 index 00000000..6e3c3611 --- /dev/null +++ b/c++/src/build-system/cmake/FindOSMesa.cmake @@ -0,0 +1,47 @@ +# Try to find Mesa off-screen library and include dir. +# Once done this will define +# +# OSMESA_FOUND - true if OSMesa has been found +# OSMESA_INCLUDE_DIR - where the GL/osmesa.h can be found +# OSMESA_LIBRARY - Link this to use OSMesa + + +if(NOT OSMESA_INCLUDE_DIR) + + # If we have a root defined look there first + if(OSMESA_ROOT) + find_path(OSMESA_INCLUDE_DIR GL/osmesa.h PATHS ${OSMESA_ROOT}/include + NO_DEFAULT_PATH + ) + endif() + + if(NOT OSMESA_INCLUDE_DIR) + find_path(OSMESA_INCLUDE_DIR GL/osmesa.h PATHS + /usr/openwin/share/include + /opt/graphics/OpenGL/include + ) + endif() +endif() + +# This may be left blank if OSMesa symbols are included +# in the main Mesa library +if(NOT OSMESA_LIBRARY) + # If we have a root defined look there first + if(OSMESA_ROOT) + find_library(OSMESA_LIBRARY OSMesa PATHS ${OSMESA_ROOT}/lib + NO_DEFAULT_PATH + ) + endif() + + if(NOT OSMESA_LIBRARY) + find_library(OSMESA_LIBRARY OSMesa PATHS + /opt/graphics/OpenGL/lib + /usr/openwin/lib + ) + endif() +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(OSMesa DEFAULT_MSG OSMESA_LIBRARY OSMESA_INCLUDE_DIR) + +mark_as_advanced(OSMESA_INCLUDE_DIR OSMESA_LIBRARY) diff --git a/c++/src/build-system/cmake/FindPCRE.cmake b/c++/src/build-system/cmake/FindPCRE.cmake old mode 100755 new mode 100644 index c338946e..3f7f3bbe --- a/c++/src/build-system/cmake/FindPCRE.cmake +++ b/c++/src/build-system/cmake/FindPCRE.cmake @@ -12,7 +12,7 @@ if(PCRE_INCLUDE_DIR AND PCRE_LIBRARIES) # in cache already - set(LIBUSB_FOUND TRUE) + set(PCRE_FOUND TRUE) else(PCRE_INCLUDE_DIR AND PCRE_LIBRARIES) if(NOT WIN32) # use pkg-config to get the directories and then use these values @@ -31,16 +31,27 @@ else(PCRE_INCLUDE_DIR AND PCRE_LIBRARIES) /usr/local/include ) - find_library(PCRE_LIBRARY - NAMES - pcre - HINTS - ${PCRE_PKG_LIBRARY_DIRS} - PATHS - /usr/lib - /usr/local/lib - ) - + if (WIN32) + find_library(PCRE_LIBRARY + NAMES + libpcre + HINTS + ${PCRE_PKG_LIBRARY_DIRS} + PATHS + ${CMAKE_PREFIX_PATH} + ${PCRE_PKG_ROOT}/lib + ) + else (WIN32) + find_library(PCRE_LIBRARY + NAMES + pcre + HINTS + ${PCRE_PKG_LIBRARY_DIRS} + PATHS + /usr/lib + /usr/local/lib + ) + endif (WIN32) set(PCRE_LIBRARIES ${PCRE_LIBRARY}) # handle the QUIETLY AND REQUIRED arguments AND set PCRE_FOUND to TRUE if diff --git a/c++/src/build-system/cmake/FindSqlite3.cmake b/c++/src/build-system/cmake/FindSqlite3.cmake new file mode 100644 index 00000000..2e59b6cf --- /dev/null +++ b/c++/src/build-system/cmake/FindSqlite3.cmake @@ -0,0 +1,105 @@ +# Find Sqlite3 +# ~~~~~~~~~~~~ +# Try NCBI layout first + +#message("FindSqlite3 SQLITE3_INCLUDE_DIR ${SQLITE3_INCLUDE_DIR}") +if (APPLE) + set(SQLITE3_NAME "sqlite-3.6.14.2-ncbi1") +else (APPLE) + set(SQLITE3_NAME "sqlite-3.7.13-ncbi1") +endif (APPLE) + +IF( SQLITE3_INCLUDE_DIR AND SQLITE3_LIBRARY_RELEASE AND SQLITE3_LIBRARY_DEBUG ) + SET(SQLITE3_FIND_QUIETLY TRUE) +ENDIF( SQLITE3_INCLUDE_DIR AND SQLITE3_LIBRARY_RELEASE AND SQLITE3_LIBRARY_DEBUG ) + +FIND_PATH( SQLITE3_INCLUDE_DIR sqlite3.h + PATHS ${NCBI_TOOLS_ROOT}/${SQLITE3_NAME}/include + NO_DEFAULT_PATH ) + +IF (SQLITE3_INCLUDE_DIR) + FIND_LIBRARY( SQLITE3_LIBRARY NAMES sqlite3 + PATHS ${NCBI_TOOLS_ROOT}/${SQLITE3_NAME}/${CMAKE_BUILD_TYPE}64MT/lib/ + NO_DEFAULT_PATH ) + + IF ("${SQLITE3_LIBRARY}" STREQUAL "") + MESSAGE(FATAL_ERROR "Include ${SQLITE3_INCLUDE_DIR}/sqlite3.h found, but no library in ${NCBI_TOOLS_ROOT}/${SQLITE3_NAME}/${CMAKE_BUILD_TYPE}64MT/lib/ ") + ELSE () + SET(SQLITE3_FOUND TRUE) + RETURN() + ENDIF () +ENDIF (SQLITE3_INCLUDE_DIR) + +# ~~~~~~~~~~~~ +# Copyright (c) 2007, Martin Dobias +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. +# +# CMake module to search for Sqlite3 library +# +# If it's found it sets SQLITE3_FOUND to TRUE +# and following variables are set: +# SQLITE3_INCLUDE_DIR +# SQLITE3_LIBRARY + + +# FIND_PATH and FIND_LIBRARY normally search standard locations +# before the specified paths. To search non-standard paths first, +# FIND_* is invoked first with specified paths and NO_DEFAULT_PATH +# and then again with no specified paths to search the default +# locations. When an earlier FIND_* succeeds, subsequent FIND_*s +# searching for the same item do nothing. + +# try to use framework on mac +# want clean framework path, not unix compatibility path +IF (APPLE) + IF (CMAKE_FIND_FRAMEWORK MATCHES "FIRST" + OR CMAKE_FRAMEWORK_PATH MATCHES "ONLY" + OR NOT CMAKE_FIND_FRAMEWORK) + SET (CMAKE_FIND_FRAMEWORK_save ${CMAKE_FIND_FRAMEWORK} CACHE STRING "" FORCE) + SET (CMAKE_FIND_FRAMEWORK "ONLY" CACHE STRING "" FORCE) + #FIND_PATH(SQLITE3_INCLUDE_DIR SQLite3/sqlite3.h) + FIND_LIBRARY(SQLITE3_LIBRARY SQLite3) + IF (SQLITE3_LIBRARY) + # FIND_PATH doesn't add "Headers" for a framework + SET (SQLITE3_INCLUDE_DIR ${SQLITE3_LIBRARY}/Headers CACHE PATH "Path to a file.") + ENDIF (SQLITE3_LIBRARY) + SET (CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK_save} CACHE STRING "" FORCE) + ENDIF () +ENDIF (APPLE) + +FIND_PATH(SQLITE3_INCLUDE_DIR sqlite3.h + "$ENV{LIB_DIR}/include" + "$ENV{LIB_DIR}/include/sqlite" + #mingw + c:/msys/local/include + NO_DEFAULT_PATH + ) +FIND_PATH(SQLITE3_INCLUDE_DIR sqlite3.h) + +FIND_LIBRARY(SQLITE3_LIBRARY NAMES sqlite3 sqlite3_i PATHS + $ENV{LIB} + /usr/lib + "$ENV{LIB_DIR}/lib" + #mingw + c:/msys/local/lib + NO_DEFAULT_PATH + ) +FIND_LIBRARY(SQLITE3_LIBRARY NAMES sqlite3) + +IF (SQLITE3_INCLUDE_DIR AND SQLITE3_LIBRARY) + SET(SQLITE3_FOUND TRUE) +ENDIF (SQLITE3_INCLUDE_DIR AND SQLITE3_LIBRARY) + + +IF (SQLITE3_FOUND) + + MESSAGE(STATUS "Found Sqlite3: ${SQLITE3_LIBRARY}") + +ELSE (SQLITE3_FOUND) + + IF (SQLITE3_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find Sqlite3") + ENDIF (SQLITE3_FIND_REQUIRED) + +ENDIF (SQLITE3_FOUND) diff --git a/c++/src/build-system/cmake/FindwxWidgets.cmake b/c++/src/build-system/cmake/FindwxWidgets.cmake new file mode 100644 index 00000000..5e6f3a5c --- /dev/null +++ b/c++/src/build-system/cmake/FindwxWidgets.cmake @@ -0,0 +1,1044 @@ +# - Find a wxWidgets (a.k.a., wxWindows) installation. +# This module finds if wxWidgets is installed and selects a default +# configuration to use. wxWidgets is a modular library. To specify the +# modules that you will use, you need to name them as components to +# the package: +# +# find_package(wxWidgets COMPONENTS core base ...) +# +# There are two search branches: a windows style and a unix style. For +# windows, the following variables are searched for and set to +# defaults in case of multiple choices. Change them if the defaults +# are not desired (i.e., these are the only variables you should +# change to select a configuration): +# +# wxWidgets_ROOT_DIR - Base wxWidgets directory +# (e.g., C:/wxWidgets-2.6.3). +# wxWidgets_LIB_DIR - Path to wxWidgets libraries +# (e.g., C:/wxWidgets-2.6.3/lib/vc_lib). +# wxWidgets_CONFIGURATION - Configuration to use +# (e.g., msw, mswd, mswu, mswunivud, etc.) +# wxWidgets_EXCLUDE_COMMON_LIBRARIES +# - Set to TRUE to exclude linking of +# commonly required libs (e.g., png tiff +# jpeg zlib regex expat). +# +# For unix style it uses the wx-config utility. You can select between +# debug/release, unicode/ansi, universal/non-universal, and +# static/shared in the QtDialog or ccmake interfaces by turning ON/OFF +# the following variables: +# +# wxWidgets_USE_DEBUG +# wxWidgets_USE_UNICODE +# wxWidgets_USE_UNIVERSAL +# wxWidgets_USE_STATIC +# +# There is also a wxWidgets_CONFIG_OPTIONS variable for all other +# options that need to be passed to the wx-config utility. For +# example, to use the base toolkit found in the /usr/local path, set +# the variable (before calling the FIND_PACKAGE command) as such: +# +# set(wxWidgets_CONFIG_OPTIONS --toolkit=base --prefix=/usr) +# +# The following are set after the configuration is done for both +# windows and unix style: +# +# wxWidgets_FOUND - Set to TRUE if wxWidgets was found. +# wxWidgets_INCLUDE_DIRS - Include directories for WIN32 +# i.e., where to find "wx/wx.h" and +# "wx/setup.h"; possibly empty for unices. +# wxWidgets_LIBRARIES - Path to the wxWidgets libraries. +# wxWidgets_LIBRARY_DIRS - compile time link dirs, useful for +# rpath on UNIX. Typically an empty string +# in WIN32 environment. +# wxWidgets_DEFINITIONS - Contains defines required to compile/link +# against WX, e.g. WXUSINGDLL +# wxWidgets_DEFINITIONS_DEBUG- Contains defines required to compile/link +# against WX debug builds, e.g. __WXDEBUG__ +# wxWidgets_CXX_FLAGS - Include dirs and compiler flags for +# unices, empty on WIN32. Essentially +# "`wx-config --cxxflags`". +# wxWidgets_USE_FILE - Convenience include file. +# +# Sample usage: +# # Note that for MinGW users the order of libs is important! +# find_package(wxWidgets COMPONENTS net gl core base) +# if(wxWidgets_FOUND) +# include(${wxWidgets_USE_FILE}) +# # and for each of your dependent executable/library targets: +# target_link_libraries( ${wxWidgets_LIBRARIES}) +# endif() +# +# If wxWidgets is required (i.e., not an optional part): +# find_package(wxWidgets REQUIRED net gl core base) +# include(${wxWidgets_USE_FILE}) +# # and for each of your dependent executable/library targets: +# target_link_libraries( ${wxWidgets_LIBRARIES}) + +#============================================================================= +# Copyright 2004-2009 Kitware, Inc. +# Copyright 2007-2009 Miguel A. Figueroa-Villanueva +# +# Distributed under the OSI-approved BSD License (the "License"); +# see accompanying file Copyright.txt for details. +# +# This software is distributed WITHOUT ANY WARRANTY; without even the +# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the License for more information. +#============================================================================= +# (To distribute this file outside of CMake, substitute the full +# License text for the above reference.) + +# +# FIXME: check this and provide a correct sample usage... +# Remember to connect back to the upper text. +# Sample usage with monolithic wx build: +# +# find_package(wxWidgets COMPONENTS mono) +# ... + +# NOTES +# +# This module has been tested on the WIN32 platform with wxWidgets +# 2.6.2, 2.6.3, and 2.5.3. However, it has been designed to +# easily extend support to all possible builds, e.g., static/shared, +# debug/release, unicode, universal, multilib/monolithic, etc.. +# +# If you want to use the module and your build type is not supported +# out-of-the-box, please contact me to exchange information on how +# your system is setup and I'll try to add support for it. +# +# AUTHOR +# +# Miguel A. Figueroa-Villanueva (miguelf at ieee dot org). +# Jan Woetzel (jw at mip.informatik.uni-kiel.de). +# +# Based on previous works of: +# Jan Woetzel (FindwxWindows.cmake), +# Jorgen Bodde and Jerry Fath (FindwxWin.cmake). + +# TODO/ideas +# +# (1) Option/Setting to use all available wx libs +# In contrast to expert developer who lists the +# minimal set of required libs in wxWidgets_USE_LIBS +# there is the newbie user: +# - who just wants to link against WX with more 'magic' +# - doesn't know the internal structure of WX or how it was built, +# in particular if it is monolithic or not +# - want to link against all available WX libs +# Basically, the intent here is to mimic what wx-config would do by +# default (i.e., `wx-config --libs`). +# +# Possible solution: +# Add a reserved keyword "std" that initializes to what wx-config +# would default to. If the user has not set the wxWidgets_USE_LIBS, +# default to "std" instead of "base core" as it is now. To implement +# "std" will basically boil down to a FOR_EACH lib-FOUND, but maybe +# checking whether a minimal set was found. + + +# FIXME: This and all the DBG_MSG calls should be removed after the +# module stabilizes. +# +# Helper macro to control the debugging output globally. There are +# two versions for controlling how verbose your output should be. +macro(DBG_MSG _MSG) +# message(STATUS +# "${CMAKE_CURRENT_LIST_FILE}(${CMAKE_CURRENT_LIST_LINE}): ${_MSG}") +endmacro() +macro(DBG_MSG_V _MSG) +# message(STATUS +# "${CMAKE_CURRENT_LIST_FILE}(${CMAKE_CURRENT_LIST_LINE}): ${_MSG}") +endmacro() + +# Clear return values in case the module is loaded more than once. +set(wxWidgets_FOUND FALSE) +set(wxWidgets_INCLUDE_DIRS "") +set(wxWidgets_LIBRARIES "") +set(wxWidgets_LIBRARY_DIRS "") +set(wxWidgets_CXX_FLAGS "") + +# Using SYSTEM with INCLUDE_DIRECTORIES in conjunction with wxWidgets on +# the Mac produces compiler errors. Set wxWidgets_INCLUDE_DIRS_NO_SYSTEM +# to prevent UsewxWidgets.cmake from using SYSTEM. +# +# See cmake mailing list discussions for more info: +# http://www.cmake.org/pipermail/cmake/2008-April/021115.html +# http://www.cmake.org/pipermail/cmake/2008-April/021146.html +# +if(APPLE OR CMAKE_CXX_PLATFORM_ID MATCHES "OpenBSD") + set(wxWidgets_INCLUDE_DIRS_NO_SYSTEM 1) +endif() + +# DEPRECATED: This is a patch to support the DEPRECATED use of +# wxWidgets_USE_LIBS. +# +# If wxWidgets_USE_LIBS is set: +# - if using , then override wxWidgets_USE_LIBS +# - else set wxWidgets_FIND_COMPONENTS to wxWidgets_USE_LIBS +if(wxWidgets_USE_LIBS AND NOT wxWidgets_FIND_COMPONENTS) + set(wxWidgets_FIND_COMPONENTS ${wxWidgets_USE_LIBS}) +endif() +DBG_MSG("wxWidgets_FIND_COMPONENTS : ${wxWidgets_FIND_COMPONENTS}") + +# Add the convenience use file if available. +# +# Get dir of this file which may reside in: +# - CMAKE_MAKE_ROOT/Modules on CMake installation +# - CMAKE_MODULE_PATH if user prefers his own specialized version +set(wxWidgets_USE_FILE "") +get_filename_component( + wxWidgets_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_FILE} PATH) +# Prefer an existing customized version, but the user might override +# the FindwxWidgets module and not the UsewxWidgets one. +if(EXISTS "${wxWidgets_CURRENT_LIST_DIR}/UsewxWidgets.cmake") + set(wxWidgets_USE_FILE + "${wxWidgets_CURRENT_LIST_DIR}/UsewxWidgets.cmake") +else() + set(wxWidgets_USE_FILE UsewxWidgets) +endif() + +#===================================================================== +#===================================================================== +if(WIN32 AND NOT CYGWIN AND NOT MSYS) + set(wxWidgets_FIND_STYLE "win32") +else() + if(UNIX OR MSYS) + set(wxWidgets_FIND_STYLE "unix") + endif() +endif() + +#===================================================================== +# WIN32_FIND_STYLE +#===================================================================== +if(wxWidgets_FIND_STYLE STREQUAL "win32") + # Useful common wx libs needed by almost all components. + set(wxWidgets_COMMON_LIBRARIES png tiff jpeg zlib regex expat) + + # DEPRECATED: Use find_package(wxWidgets COMPONENTS mono) instead. + if(NOT wxWidgets_FIND_COMPONENTS) + if(wxWidgets_USE_MONOLITHIC) + set(wxWidgets_FIND_COMPONENTS mono) + else() + set(wxWidgets_FIND_COMPONENTS core base) # this is default + endif() + endif() + + # Add the common (usually required libs) unless + # wxWidgets_EXCLUDE_COMMON_LIBRARIES has been set. + if(NOT wxWidgets_EXCLUDE_COMMON_LIBRARIES) + list(APPEND wxWidgets_FIND_COMPONENTS + ${wxWidgets_COMMON_LIBRARIES}) + endif() + + #------------------------------------------------------------------- + # WIN32: Helper MACROS + #------------------------------------------------------------------- + # + # Get filename components for a configuration. For example, + # if _CONFIGURATION = mswunivud, then _UNV=univ, _UCD=u _DBG=d + # if _CONFIGURATION = mswu, then _UNV="", _UCD=u _DBG="" + # + macro(WX_GET_NAME_COMPONENTS _CONFIGURATION _UNV _UCD _DBG) + string(REGEX MATCH "univ" ${_UNV} "${_CONFIGURATION}") + string(REGEX REPLACE "msw.*(u)[d]*$" "u" ${_UCD} "${_CONFIGURATION}") + if(${_UCD} STREQUAL ${_CONFIGURATION}) + set(${_UCD} "") + endif() + string(REGEX MATCH "d$" ${_DBG} "${_CONFIGURATION}") + endmacro() + + # + # Find libraries associated to a configuration. + # + macro(WX_FIND_LIBS _UNV _UCD _DBG) + DBG_MSG_V("m_unv = ${_UNV}") + DBG_MSG_V("m_ucd = ${_UCD}") + DBG_MSG_V("m_dbg = ${_DBG}") + + # FIXME: What if both regex libs are available. regex should be + # found outside the loop and only wx${LIB}${_UCD}${_DBG}. + # Find wxWidgets common libraries. + foreach(LIB ${wxWidgets_COMMON_LIBRARIES} scintilla) + find_library(WX_${LIB}${_DBG} + NAMES + wx${LIB}${_UCD}${_DBG} # for regex + wx${LIB}${_DBG} + PATHS ${WX_LIB_DIR} + NO_DEFAULT_PATH + ) + mark_as_advanced(WX_${LIB}${_DBG}) + endforeach() + + # Find wxWidgets multilib base libraries. + find_library(WX_base${_DBG} + NAMES + wxbase29${_UCD}${_DBG} + wxbase28${_UCD}${_DBG} + wxbase27${_UCD}${_DBG} + wxbase26${_UCD}${_DBG} + wxbase25${_UCD}${_DBG} + PATHS ${WX_LIB_DIR} + NO_DEFAULT_PATH + ) + mark_as_advanced(WX_base${_DBG}) + foreach(LIB net odbc xml) + find_library(WX_${LIB}${_DBG} + NAMES + wxbase29${_UCD}${_DBG}_${LIB} + wxbase28${_UCD}${_DBG}_${LIB} + wxbase27${_UCD}${_DBG}_${LIB} + wxbase26${_UCD}${_DBG}_${LIB} + wxbase25${_UCD}${_DBG}_${LIB} + PATHS ${WX_LIB_DIR} + NO_DEFAULT_PATH + ) + mark_as_advanced(WX_${LIB}${_DBG}) + endforeach() + + # Find wxWidgets monolithic library. + find_library(WX_mono${_DBG} + NAMES + wxmsw${_UNV}29${_UCD}${_DBG} + wxmsw${_UNV}28${_UCD}${_DBG} + wxmsw${_UNV}27${_UCD}${_DBG} + wxmsw${_UNV}26${_UCD}${_DBG} + wxmsw${_UNV}25${_UCD}${_DBG} + PATHS ${WX_LIB_DIR} + NO_DEFAULT_PATH + ) + mark_as_advanced(WX_mono${_DBG}) + + # Find wxWidgets multilib libraries. + foreach(LIB core adv aui html media xrc dbgrid gl qa richtext + stc ribbon propgrid webview) + find_library(WX_${LIB}${_DBG} + NAMES + wxmsw${_UNV}29${_UCD}${_DBG}_${LIB} + wxmsw${_UNV}28${_UCD}${_DBG}_${LIB} + wxmsw${_UNV}27${_UCD}${_DBG}_${LIB} + wxmsw${_UNV}26${_UCD}${_DBG}_${LIB} + wxmsw${_UNV}25${_UCD}${_DBG}_${LIB} + PATHS ${WX_LIB_DIR} + NO_DEFAULT_PATH + ) + mark_as_advanced(WX_${LIB}${_DBG}) + endforeach() + endmacro() + + # + # Clear all library paths, so that FIND_LIBRARY refinds them. + # + # Clear a lib, reset its found flag, and mark as advanced. + macro(WX_CLEAR_LIB _LIB) + set(${_LIB} "${_LIB}-NOTFOUND" CACHE FILEPATH "Cleared." FORCE) + set(${_LIB}_FOUND FALSE) + mark_as_advanced(${_LIB}) + endmacro() + # Clear all debug or release library paths (arguments are "d" or ""). + macro(WX_CLEAR_ALL_LIBS _DBG) + # Clear wxWidgets common libraries. + foreach(LIB ${wxWidgets_COMMON_LIBRARIES} scintilla) + WX_CLEAR_LIB(WX_${LIB}${_DBG}) + endforeach() + + # Clear wxWidgets multilib base libraries. + WX_CLEAR_LIB(WX_base${_DBG}) + foreach(LIB net odbc xml) + WX_CLEAR_LIB(WX_${LIB}${_DBG}) + endforeach() + + # Clear wxWidgets monolithic library. + WX_CLEAR_LIB(WX_mono${_DBG}) + + # Clear wxWidgets multilib libraries. + foreach(LIB core adv aui html media xrc dbgrid gl qa richtext + stc ribbon propgrid) + WX_CLEAR_LIB(WX_${LIB}${_DBG}) + endforeach() + endmacro() + # Clear all wxWidgets debug libraries. + macro(WX_CLEAR_ALL_DBG_LIBS) + WX_CLEAR_ALL_LIBS("d") + endmacro() + # Clear all wxWidgets release libraries. + macro(WX_CLEAR_ALL_REL_LIBS) + WX_CLEAR_ALL_LIBS("") + endmacro() + + # + # Set the wxWidgets_LIBRARIES variable. + # Also, Sets output variable wxWidgets_FOUND to FALSE if it fails. + # + macro(WX_SET_LIBRARIES _LIBS _DBG) + DBG_MSG_V("Looking for ${${_LIBS}}") + if(WX_USE_REL_AND_DBG) + foreach(LIB ${${_LIBS}}) + DBG_MSG_V("Searching for ${LIB} and ${LIB}d") + DBG_MSG_V("WX_${LIB} : ${WX_${LIB}}") + DBG_MSG_V("WX_${LIB}d : ${WX_${LIB}d}") + if(WX_${LIB} AND WX_${LIB}d) + DBG_MSG_V("Found ${LIB} and ${LIB}d") + list(APPEND wxWidgets_LIBRARIES + debug ${WX_${LIB}d} optimized ${WX_${LIB}} + ) + else() + DBG_MSG_V("- not found due to missing WX_${LIB}=${WX_${LIB}} or WX_${LIB}d=${WX_${LIB}d}") + set(wxWidgets_FOUND FALSE) + endif() + endforeach() + else() + foreach(LIB ${${_LIBS}}) + DBG_MSG_V("Searching for ${LIB}${_DBG}") + DBG_MSG_V("WX_${LIB}${_DBG} : ${WX_${LIB}${_DBG}}") + if(WX_${LIB}${_DBG}) + DBG_MSG_V("Found ${LIB}${_DBG}") + list(APPEND wxWidgets_LIBRARIES ${WX_${LIB}${_DBG}}) + else() + DBG_MSG_V( + "- not found due to missing WX_${LIB}${_DBG}=${WX_${LIB}${_DBG}}") + set(wxWidgets_FOUND FALSE) + endif() + endforeach() + endif() + + DBG_MSG_V("OpenGL") + list(FIND ${_LIBS} gl WX_USE_GL) + if(NOT WX_USE_GL EQUAL -1) + DBG_MSG_V("- is required.") + list(APPEND wxWidgets_LIBRARIES opengl32 glu32) + endif() + + list(APPEND wxWidgets_LIBRARIES winmm comctl32 rpcrt4 wsock32) + endmacro() + + #------------------------------------------------------------------- + # WIN32: Start actual work. + #------------------------------------------------------------------- + + # Look for an installation tree. + find_path(wxWidgets_ROOT_DIR + NAMES include/wx/wx.h + PATHS + ENV wxWidgets_ROOT_DIR + ENV WXWIN + "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\wxWidgets_is1;Inno Setup: App Path]" # WX 2.6.x + C:/ + D:/ + ENV ProgramFiles + PATH_SUFFIXES + wxWidgets-2.9.4 + wxWidgets-2.9.3 + wxWidgets-2.9.2 + wxWidgets-2.9.1 + wxWidgets-2.9.0 + wxWidgets-2.8.9 + wxWidgets-2.8.8 + wxWidgets-2.8.7 + wxWidgets-2.8.6 + wxWidgets-2.8.5 + wxWidgets-2.8.4 + wxWidgets-2.8.3 + wxWidgets-2.8.2 + wxWidgets-2.8.1 + wxWidgets-2.8.0 + wxWidgets-2.7.4 + wxWidgets-2.7.3 + wxWidgets-2.7.2 + wxWidgets-2.7.1 + wxWidgets-2.7.0 + wxWidgets-2.7.0-1 + wxWidgets-2.6.4 + wxWidgets-2.6.3 + wxWidgets-2.6.2 + wxWidgets-2.6.1 + wxWidgets-2.5.4 + wxWidgets-2.5.3 + wxWidgets-2.5.2 + wxWidgets-2.5.1 + wxWidgets + DOC "wxWidgets base/installation directory?" + ) + + # If wxWidgets_ROOT_DIR changed, clear lib dir. + if(NOT WX_ROOT_DIR STREQUAL wxWidgets_ROOT_DIR) + set(WX_ROOT_DIR ${wxWidgets_ROOT_DIR} + CACHE INTERNAL "wxWidgets_ROOT_DIR") + set(wxWidgets_LIB_DIR "wxWidgets_LIB_DIR-NOTFOUND" + CACHE PATH "Cleared." FORCE) + endif() + + if(WX_ROOT_DIR) + # Select one default tree inside the already determined wx tree. + # Prefer static/shared order usually consistent with build + # settings. + if(MINGW) + set(WX_LIB_DIR_PREFIX gcc) + else() + set(WX_LIB_DIR_PREFIX vc) + endif() + if(BUILD_SHARED_LIBS) + find_path(wxWidgets_LIB_DIR + NAMES + msw/wx/setup.h + mswd/wx/setup.h + mswu/wx/setup.h + mswud/wx/setup.h + mswuniv/wx/setup.h + mswunivd/wx/setup.h + mswunivu/wx/setup.h + mswunivud/wx/setup.h + PATHS + ${WX_ROOT_DIR}/lib/${WX_LIB_DIR_PREFIX}_dll # prefer shared + ${WX_ROOT_DIR}/lib/${WX_LIB_DIR_PREFIX}_lib + DOC "Path to wxWidgets libraries?" + NO_DEFAULT_PATH + ) + else() + find_path(wxWidgets_LIB_DIR + NAMES + msw/wx/setup.h + mswd/wx/setup.h + mswu/wx/setup.h + mswud/wx/setup.h + mswuniv/wx/setup.h + mswunivd/wx/setup.h + mswunivu/wx/setup.h + mswunivud/wx/setup.h + PATHS + ${WX_ROOT_DIR}/lib/${WX_LIB_DIR_PREFIX}_lib # prefer static + ${WX_ROOT_DIR}/lib/${WX_LIB_DIR_PREFIX}_dll + DOC "Path to wxWidgets libraries?" + NO_DEFAULT_PATH + ) + endif() + + # If wxWidgets_LIB_DIR changed, clear all libraries. + if(NOT WX_LIB_DIR STREQUAL wxWidgets_LIB_DIR) + set(WX_LIB_DIR ${wxWidgets_LIB_DIR} CACHE INTERNAL "wxWidgets_LIB_DIR") + WX_CLEAR_ALL_DBG_LIBS() + WX_CLEAR_ALL_REL_LIBS() + endif() + + if(WX_LIB_DIR) + # If building shared libs, define WXUSINGDLL to use dllimport. + if(WX_LIB_DIR MATCHES ".*[dD][lL][lL].*") + set(wxWidgets_DEFINITIONS WXUSINGDLL) + DBG_MSG_V("detected SHARED/DLL tree WX_LIB_DIR=${WX_LIB_DIR}") + endif() + + # Search for available configuration types. + foreach(CFG mswunivud mswunivd mswud mswd mswunivu mswuniv mswu msw) + set(WX_${CFG}_FOUND FALSE) + if(EXISTS ${WX_LIB_DIR}/${CFG}) + list(APPEND WX_CONFIGURATION_LIST ${CFG}) + set(WX_${CFG}_FOUND TRUE) + set(WX_CONFIGURATION ${CFG}) + endif() + endforeach() + DBG_MSG_V("WX_CONFIGURATION_LIST=${WX_CONFIGURATION_LIST}") + + if(WX_CONFIGURATION) + set(wxWidgets_FOUND TRUE) + + # If the selected configuration wasn't found force the default + # one. Otherwise, use it but still force a refresh for + # updating the doc string with the current list of available + # configurations. + if(NOT WX_${wxWidgets_CONFIGURATION}_FOUND) + set(wxWidgets_CONFIGURATION ${WX_CONFIGURATION} CACHE STRING + "Set wxWidgets configuration (${WX_CONFIGURATION_LIST})" FORCE) + else() + set(wxWidgets_CONFIGURATION ${wxWidgets_CONFIGURATION} CACHE STRING + "Set wxWidgets configuration (${WX_CONFIGURATION_LIST})" FORCE) + endif() + + # If release config selected, and both release/debug exist. + if(WX_${wxWidgets_CONFIGURATION}d_FOUND) + option(wxWidgets_USE_REL_AND_DBG + "Use release and debug configurations?" TRUE) + set(WX_USE_REL_AND_DBG ${wxWidgets_USE_REL_AND_DBG}) + else() + # If the option exists (already in cache), force it false. + if(wxWidgets_USE_REL_AND_DBG) + set(wxWidgets_USE_REL_AND_DBG FALSE CACHE BOOL + "No ${wxWidgets_CONFIGURATION}d found." FORCE) + endif() + set(WX_USE_REL_AND_DBG FALSE) + endif() + + # Get configuration parameters from the name. + WX_GET_NAME_COMPONENTS(${wxWidgets_CONFIGURATION} UNV UCD DBG) + + # Set wxWidgets lib setup include directory. + if(EXISTS ${WX_LIB_DIR}/${wxWidgets_CONFIGURATION}/wx/setup.h) + set(wxWidgets_INCLUDE_DIRS + ${WX_LIB_DIR}/${wxWidgets_CONFIGURATION}) + else() + DBG_MSG("wxWidgets_FOUND FALSE because ${WX_LIB_DIR}/${wxWidgets_CONFIGURATION}/wx/setup.h does not exists.") + set(wxWidgets_FOUND FALSE) + endif() + + # Set wxWidgets main include directory. + if(EXISTS ${WX_ROOT_DIR}/include/wx/wx.h) + list(APPEND wxWidgets_INCLUDE_DIRS ${WX_ROOT_DIR}/include) + else() + DBG_MSG("wxWidgets_FOUND FALSE because WX_ROOT_DIR=${WX_ROOT_DIR} has no ${WX_ROOT_DIR}/include/wx/wx.h") + set(wxWidgets_FOUND FALSE) + endif() + + # Find wxWidgets libraries. + WX_FIND_LIBS("${UNV}" "${UCD}" "${DBG}") + if(WX_USE_REL_AND_DBG) + WX_FIND_LIBS("${UNV}" "${UCD}" "d") + endif() + + # Settings for requested libs (i.e., include dir, libraries, etc.). + WX_SET_LIBRARIES(wxWidgets_FIND_COMPONENTS "${DBG}") + + # Add necessary definitions for unicode builds + if("${UCD}" STREQUAL "u") + list(APPEND wxWidgets_DEFINITIONS UNICODE _UNICODE) + endif() + + # Add necessary definitions for debug builds + set(wxWidgets_DEFINITIONS_DEBUG _DEBUG __WXDEBUG__) + + endif() + endif() + endif() + +#===================================================================== +# UNIX_FIND_STYLE +#===================================================================== +else() + if(wxWidgets_FIND_STYLE STREQUAL "unix") + #----------------------------------------------------------------- + # UNIX: Helper MACROS + #----------------------------------------------------------------- + # + # Set the default values based on "wx-config --selected-config". + # + macro(WX_CONFIG_SELECT_GET_DEFAULT) + execute_process( + COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}" + ${wxWidgets_CONFIG_OPTIONS} --selected-config + OUTPUT_VARIABLE _wx_selected_config + RESULT_VARIABLE _wx_result + ERROR_QUIET + ) + if(_wx_result EQUAL 0) + foreach(_opt_name debug static unicode universal) + string(TOUPPER ${_opt_name} _upper_opt_name) + if(_wx_selected_config MATCHES ".*${_opt_name}.*") + set(wxWidgets_DEFAULT_${_upper_opt_name} ON) + else() + set(wxWidgets_DEFAULT_${_upper_opt_name} OFF) + endif() + endforeach() + else() + foreach(_upper_opt_name DEBUG STATIC UNICODE UNIVERSAL) + set(wxWidgets_DEFAULT_${_upper_opt_name} OFF) + endforeach() + endif() + endmacro() + + # + # Query a boolean configuration option to determine if the system + # has both builds available. If so, provide the selection option + # to the user. + # + macro(WX_CONFIG_SELECT_QUERY_BOOL _OPT_NAME _OPT_HELP) + execute_process( + COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}" + ${wxWidgets_CONFIG_OPTIONS} --${_OPT_NAME}=yes + RESULT_VARIABLE _wx_result_yes + OUTPUT_QUIET + ERROR_QUIET + ) + execute_process( + COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}" + ${wxWidgets_CONFIG_OPTIONS} --${_OPT_NAME}=no + RESULT_VARIABLE _wx_result_no + OUTPUT_QUIET + ERROR_QUIET + ) + string(TOUPPER ${_OPT_NAME} _UPPER_OPT_NAME) + if(_wx_result_yes EQUAL 0 AND _wx_result_no EQUAL 0) + option(wxWidgets_USE_${_UPPER_OPT_NAME} + ${_OPT_HELP} ${wxWidgets_DEFAULT_${_UPPER_OPT_NAME}}) + else() + # If option exists (already in cache), force to available one. + if(DEFINED wxWidgets_USE_${_UPPER_OPT_NAME}) + if(_wx_result_yes EQUAL 0) + set(wxWidgets_USE_${_UPPER_OPT_NAME} ON CACHE BOOL ${_OPT_HELP} FORCE) + else() + set(wxWidgets_USE_${_UPPER_OPT_NAME} OFF CACHE BOOL ${_OPT_HELP} FORCE) + endif() + endif() + endif() + endmacro() + + # + # Set wxWidgets_SELECT_OPTIONS to wx-config options for selecting + # among multiple builds. + # + macro(WX_CONFIG_SELECT_SET_OPTIONS) + set(wxWidgets_SELECT_OPTIONS ${wxWidgets_CONFIG_OPTIONS}) + foreach(_opt_name debug static unicode universal) + string(TOUPPER ${_opt_name} _upper_opt_name) + if(DEFINED wxWidgets_USE_${_upper_opt_name}) + if(wxWidgets_USE_${_upper_opt_name}) + list(APPEND wxWidgets_SELECT_OPTIONS --${_opt_name}=yes) + else() + list(APPEND wxWidgets_SELECT_OPTIONS --${_opt_name}=no) + endif() + endif() + endforeach() + endmacro() + + #----------------------------------------------------------------- + # UNIX: Start actual work. + #----------------------------------------------------------------- + # Support cross-compiling, only search in the target platform. + find_program(wxWidgets_CONFIG_EXECUTABLE wx-config + ONLY_CMAKE_FIND_ROOT_PATH + ) + + if(wxWidgets_CONFIG_EXECUTABLE) + set(wxWidgets_FOUND TRUE) + + # get defaults based on "wx-config --selected-config" + WX_CONFIG_SELECT_GET_DEFAULT() + + # for each option: if both builds are available, provide option + WX_CONFIG_SELECT_QUERY_BOOL(debug "Use debug build?") + WX_CONFIG_SELECT_QUERY_BOOL(unicode "Use unicode build?") + WX_CONFIG_SELECT_QUERY_BOOL(universal "Use universal build?") + WX_CONFIG_SELECT_QUERY_BOOL(static "Link libraries statically?") + + # process selection to set wxWidgets_SELECT_OPTIONS + WX_CONFIG_SELECT_SET_OPTIONS() + DBG_MSG("wxWidgets_SELECT_OPTIONS=${wxWidgets_SELECT_OPTIONS}") + + # run the wx-config program to get cxxflags + execute_process( + COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}" + ${wxWidgets_SELECT_OPTIONS} --cxxflags + OUTPUT_VARIABLE wxWidgets_CXX_FLAGS + RESULT_VARIABLE RET + ERROR_QUIET + ) + if(RET EQUAL 0) + string(STRIP "${wxWidgets_CXX_FLAGS}" wxWidgets_CXX_FLAGS) + separate_arguments(wxWidgets_CXX_FLAGS) + + DBG_MSG_V("wxWidgets_CXX_FLAGS=${wxWidgets_CXX_FLAGS}") + + # parse definitions from cxxflags; + # drop -D* from CXXFLAGS and the -D prefix + string(REGEX MATCHALL "^-D[^;]+" + wxWidgets_DEFINITIONS "${wxWidgets_CXX_FLAGS}") + string(REGEX REPLACE "^-D[^;]+(;|$)" "" + wxWidgets_CXX_FLAGS "${wxWidgets_CXX_FLAGS}") + string(REGEX REPLACE ";$" "" + wxWidgets_CXX_FLAGS "${wxWidgets_CXX_FLAGS}") + string(REPLACE "-D" "" + wxWidgets_DEFINITIONS "${wxWidgets_DEFINITIONS}") + + # parse include dirs from cxxflags; drop -I prefix + string(REGEX MATCHALL "-I[^;]+" + wxWidgets_INCLUDE_DIRS "${wxWidgets_CXX_FLAGS}") + string(REGEX REPLACE "-I[^;]+;" "" + wxWidgets_CXX_FLAGS "${wxWidgets_CXX_FLAGS}") + string(REPLACE "-I" "" + wxWidgets_INCLUDE_DIRS "${wxWidgets_INCLUDE_DIRS}") + + DBG_MSG_V("wxWidgets_DEFINITIONS=${wxWidgets_DEFINITIONS}") + DBG_MSG_V("wxWidgets_INCLUDE_DIRS=${wxWidgets_INCLUDE_DIRS}") + DBG_MSG_V("wxWidgets_CXX_FLAGS=${wxWidgets_CXX_FLAGS}") + + else() + set(wxWidgets_FOUND FALSE) + DBG_MSG_V( + "${wxWidgets_CONFIG_EXECUTABLE} --cxxflags FAILED with RET=${RET}") + endif() + + # run the wx-config program to get the libs + # - NOTE: wx-config doesn't verify that the libs requested exist + # it just produces the names. Maybe a TRY_COMPILE would + # be useful here... + string(REPLACE ";" "," + wxWidgets_FIND_COMPONENTS "${wxWidgets_FIND_COMPONENTS}") + execute_process( + COMMAND sh "${wxWidgets_CONFIG_EXECUTABLE}" + ${wxWidgets_SELECT_OPTIONS} --libs ${wxWidgets_FIND_COMPONENTS} + OUTPUT_VARIABLE wxWidgets_LIBRARIES + RESULT_VARIABLE RET + ERROR_QUIET + ) + if(RET EQUAL 0) + string(STRIP "${wxWidgets_LIBRARIES}" wxWidgets_LIBRARIES) + separate_arguments(wxWidgets_LIBRARIES) + string(REPLACE "-framework;" "-framework " + wxWidgets_LIBRARIES "${wxWidgets_LIBRARIES}") + string(REPLACE "-arch;" "-arch " + wxWidgets_LIBRARIES "${wxWidgets_LIBRARIES}") + string(REPLACE "-isysroot;" "-isysroot " + wxWidgets_LIBRARIES "${wxWidgets_LIBRARIES}") + + # extract linkdirs (-L) for rpath (i.e., LINK_DIRECTORIES) + string(REGEX MATCHALL "-L[^;]+" + wxWidgets_LIBRARY_DIRS "${wxWidgets_LIBRARIES}") + string(REPLACE "-L" "" + wxWidgets_LIBRARY_DIRS "${wxWidgets_LIBRARY_DIRS}") + + DBG_MSG_V("wxWidgets_LIBRARIES=${wxWidgets_LIBRARIES}") + DBG_MSG_V("wxWidgets_LIBRARY_DIRS=${wxWidgets_LIBRARY_DIRS}") + + else() + set(wxWidgets_FOUND FALSE) + DBG_MSG("${wxWidgets_CONFIG_EXECUTABLE} --libs ${wxWidgets_FIND_COMPONENTS} FAILED with RET=${RET}") + endif() + endif() + +#===================================================================== +# Neither UNIX_FIND_STYLE, nor WIN32_FIND_STYLE +#===================================================================== + else() + if(NOT wxWidgets_FIND_QUIETLY) + message(STATUS + "${CMAKE_CURRENT_LIST_FILE}(${CMAKE_CURRENT_LIST_LINE}): \n" + " Platform unknown/unsupported. It's neither WIN32 nor UNIX " + "find style." + ) + endif() + endif() +endif() + +# Debug output: +DBG_MSG("wxWidgets_FOUND : ${wxWidgets_FOUND}") +DBG_MSG("wxWidgets_INCLUDE_DIRS : ${wxWidgets_INCLUDE_DIRS}") +DBG_MSG("wxWidgets_LIBRARY_DIRS : ${wxWidgets_LIBRARY_DIRS}") +DBG_MSG("wxWidgets_LIBRARIES : ${wxWidgets_LIBRARIES}") +DBG_MSG("wxWidgets_CXX_FLAGS : ${wxWidgets_CXX_FLAGS}") +DBG_MSG("wxWidgets_USE_FILE : ${wxWidgets_USE_FILE}") + +#===================================================================== +#===================================================================== +#include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(wxWidgets DEFAULT_MSG wxWidgets_FOUND) +# Maintain consistency with all other variables. +set(wxWidgets_FOUND ${WXWIDGETS_FOUND}) + +#===================================================================== +# Macros for use in wxWidgets apps. +# - This module will not fail to find wxWidgets based on the code +# below. Hence, it's required to check for validity of: +# +# wxWidgets_wxrc_EXECUTABLE +#===================================================================== + +# Resource file compiler. +find_program(wxWidgets_wxrc_EXECUTABLE wxrc + ${wxWidgets_ROOT_DIR}/utils/wxrc/vc_msw + ) + +# +# WX_SPLIT_ARGUMENTS_ON( ...) +# +# Sets and to contain arguments to the left and right, +# respectively, of . +# +# Example usage: +# function(WXWIDGETS_ADD_RESOURCES outfiles) +# WX_SPLIT_ARGUMENTS_ON(OPTIONS wxrc_files wxrc_options ${ARGN}) +# ... +# endfunction() +# +# WXWIDGETS_ADD_RESOURCES(sources ${xrc_files} OPTIONS -e -o file.C) +# +# NOTE: This is a generic piece of code that should be renamed to +# SPLIT_ARGUMENTS_ON and put in a file serving the same purpose as +# FindPackageStandardArgs.cmake. At the time of this writing +# FindQt4.cmake has a QT4_EXTRACT_OPTIONS, which I basically copied +# here a bit more generalized. So, there are already two find modules +# using this approach. +# +function(WX_SPLIT_ARGUMENTS_ON _keyword _leftvar _rightvar) + # FIXME: Document that the input variables will be cleared. + #list(APPEND ${_leftvar} "") + #list(APPEND ${_rightvar} "") + set(${_leftvar} "") + set(${_rightvar} "") + + set(_doing_right FALSE) + foreach(element ${ARGN}) + if("${element}" STREQUAL "${_keyword}") + set(_doing_right TRUE) + else() + if(_doing_right) + list(APPEND ${_rightvar} "${element}") + else() + list(APPEND ${_leftvar} "${element}") + endif() + endif() + endforeach() + + set(${_leftvar} ${${_leftvar}} PARENT_SCOPE) + set(${_rightvar} ${${_rightvar}} PARENT_SCOPE) +endfunction() + +# +# WX_GET_DEPENDENCIES_FROM_XML( +# +# +# +# +# +# ) +# +# FIXME: Add documentation here... +# +function(WX_GET_DEPENDENCIES_FROM_XML + _depends + _match_patt + _clean_patt + _xml_contents + _depends_path + ) + + string(REGEX MATCHALL + ${_match_patt} + dep_file_list + "${${_xml_contents}}" + ) + foreach(dep_file ${dep_file_list}) + string(REGEX REPLACE ${_clean_patt} "" dep_file "${dep_file}") + + # make the file have an absolute path + if(NOT IS_ABSOLUTE "${dep_file}") + set(dep_file "${${_depends_path}}/${dep_file}") + endif() + + # append file to dependency list + list(APPEND ${_depends} "${dep_file}") + endforeach() + + set(${_depends} ${${_depends}} PARENT_SCOPE) +endfunction() + +# +# WXWIDGETS_ADD_RESOURCES( +# OPTIONS [NO_CPP_CODE]) +# +# Adds a custom command for resource file compilation of the +# and appends the output files to . +# +# Example usages: +# WXWIDGETS_ADD_RESOURCES(sources xrc/main_frame.xrc) +# WXWIDGETS_ADD_RESOURCES(sources ${xrc_files} OPTIONS -e -o altname.cxx) +# +function(WXWIDGETS_ADD_RESOURCES _outfiles) + WX_SPLIT_ARGUMENTS_ON(OPTIONS rc_file_list rc_options ${ARGN}) + + # Parse files for dependencies. + set(rc_file_list_abs "") + set(rc_depends "") + foreach(rc_file ${rc_file_list}) + get_filename_component(depends_path ${rc_file} PATH) + + get_filename_component(rc_file_abs ${rc_file} ABSOLUTE) + list(APPEND rc_file_list_abs "${rc_file_abs}") + + # All files have absolute paths or paths relative to the location + # of the rc file. + file(READ "${rc_file_abs}" rc_file_contents) + + # get bitmap/bitmap2 files + WX_GET_DEPENDENCIES_FROM_XML( + rc_depends + "]*>" + rc_file_contents + depends_path + ) + + # get url files + WX_GET_DEPENDENCIES_FROM_XML( + rc_depends + "]*>" + rc_file_contents + depends_path + ) + + # get wxIcon files + WX_GET_DEPENDENCIES_FROM_XML( + rc_depends + "]*class=\"wxIcon\"[^<]+" + "^]*>" + rc_file_contents + depends_path + ) + endforeach() + + # + # Parse options. + # + # If NO_CPP_CODE option specified, then produce .xrs file rather + # than a .cpp file (i.e., don't add the default --cpp-code option). + list(FIND rc_options NO_CPP_CODE index) + if(index EQUAL -1) + list(APPEND rc_options --cpp-code) + # wxrc's default output filename for cpp code. + set(outfile resource.cpp) + else() + list(REMOVE_AT rc_options ${index}) + # wxrc's default output filename for xrs file. + set(outfile resource.xrs) + endif() + + # Get output name for use in ADD_CUSTOM_COMMAND. + # - short option scanning + list(FIND rc_options -o index) + if(NOT index EQUAL -1) + math(EXPR filename_index "${index} + 1") + list(GET rc_options ${filename_index} outfile) + #list(REMOVE_AT rc_options ${index} ${filename_index}) + endif() + # - long option scanning + string(REGEX MATCH "--output=[^;]*" outfile_opt "${rc_options}") + if(outfile_opt) + string(REPLACE "--output=" "" outfile "${outfile_opt}") + endif() + #string(REGEX REPLACE "--output=[^;]*;?" "" rc_options "${rc_options}") + #string(REGEX REPLACE ";$" "" rc_options "${rc_options}") + + if(NOT IS_ABSOLUTE "${outfile}") + set(outfile "${CMAKE_CURRENT_BINARY_DIR}/${outfile}") + endif() + add_custom_command( + OUTPUT "${outfile}" + COMMAND ${wxWidgets_wxrc_EXECUTABLE} ${rc_options} ${rc_file_list_abs} + DEPENDS ${rc_file_list_abs} ${rc_depends} + ) + + # Add generated header to output file list. + list(FIND rc_options -e short_index) + list(FIND rc_options --extra-cpp-code long_index) + if(NOT short_index EQUAL -1 OR NOT long_index EQUAL -1) + get_filename_component(outfile_ext ${outfile} EXT) + string(REPLACE "${outfile_ext}" ".h" outfile_header "${outfile}") + list(APPEND ${_outfiles} "${outfile_header}") + set_source_files_properties( + "${outfile_header}" PROPERTIES GENERATED TRUE + ) + endif() + + # Add generated file to output file list. + list(APPEND ${_outfiles} "${outfile}") + + set(${_outfiles} ${${_outfiles}} PARENT_SCOPE) +endfunction() diff --git a/c++/src/build-system/cmake/HunterGate.cmake b/c++/src/build-system/cmake/HunterGate.cmake new file mode 100644 index 00000000..f41345b0 --- /dev/null +++ b/c++/src/build-system/cmake/HunterGate.cmake @@ -0,0 +1,529 @@ +# Copyright (c) 2013-2017, Ruslan Baratov +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This is a gate file to Hunter package manager. +# Include this file using `include` command and add package you need, example: +# +# cmake_minimum_required(VERSION 3.0) +# +# include("cmake/HunterGate.cmake") +# HunterGate( +# URL "https://github.com/path/to/hunter/archive.tar.gz" +# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d" +# ) +# +# project(MyProject) +# +# hunter_add_package(Foo) +# hunter_add_package(Boo COMPONENTS Bar Baz) +# +# Projects: +# * https://github.com/hunter-packages/gate/ +# * https://github.com/ruslo/hunter + +option(HUNTER_ENABLED "Enable Hunter package manager support" ON) +if(HUNTER_ENABLED) + if(CMAKE_VERSION VERSION_LESS "3.0") + message(FATAL_ERROR "At least CMake version 3.0 required for hunter dependency management." + " Update CMake or set HUNTER_ENABLED to OFF.") + endif() +endif() + +include(CMakeParseArguments) # cmake_parse_arguments + +option(HUNTER_STATUS_PRINT "Print working status" ON) +option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) + +set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki") + +function(hunter_gate_status_print) + foreach(print_message ${ARGV}) + if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) + message(STATUS "[hunter] ${print_message}") + endif() + endforeach() +endfunction() + +function(hunter_gate_status_debug) + foreach(print_message ${ARGV}) + if(HUNTER_STATUS_DEBUG) + string(TIMESTAMP timestamp) + message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}") + endif() + endforeach() +endfunction() + +function(hunter_gate_wiki wiki_page) + message("------------------------------ WIKI -------------------------------") + message(" ${HUNTER_WIKI}/${wiki_page}") + message("-------------------------------------------------------------------") + message("") + message(FATAL_ERROR "") +endfunction() + +function(hunter_gate_internal_error) + message("") + foreach(print_message ${ARGV}) + message("[hunter ** INTERNAL **] ${print_message}") + endforeach() + message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_wiki("error.internal") +endfunction() + +function(hunter_gate_fatal_error) + cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}") + string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki) + if(have_no_wiki) + hunter_gate_internal_error("Expected wiki") + endif() + message("") + foreach(x ${hunter_UNPARSED_ARGUMENTS}) + message("[hunter ** FATAL ERROR **] ${x}") + endforeach() + message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_wiki("${hunter_WIKI}") +endfunction() + +function(hunter_gate_user_error) + hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data") +endfunction() + +function(hunter_gate_self root version sha1 result) + string(COMPARE EQUAL "${root}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("root is empty") + endif() + + string(COMPARE EQUAL "${version}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("version is empty") + endif() + + string(COMPARE EQUAL "${sha1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("sha1 is empty") + endif() + + string(SUBSTRING "${sha1}" 0 7 archive_id) + + if(EXISTS "${root}/cmake/Hunter") + set(hunter_self "${root}") + else() + set( + hunter_self + "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked" + ) + endif() + + set("${result}" "${hunter_self}" PARENT_SCOPE) +endfunction() + +# Set HUNTER_GATE_ROOT cmake variable to suitable value. +function(hunter_gate_detect_root) + # Check CMake variable + string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable") + return() + endif() + + # Check environment variable + string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by environment variable") + return() + endif() + + # Check HOME environment variable + string(COMPARE NOTEQUAL "$ENV{HOME}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable") + return() + endif() + + # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only) + if(WIN32) + string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using SYSTEMDRIVE environment variable" + ) + return() + endif() + + string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using USERPROFILE environment variable" + ) + return() + endif() + endif() + + hunter_gate_fatal_error( + "Can't detect HUNTER_ROOT" + WIKI "error.detect.hunter.root" + ) +endfunction() + +macro(hunter_gate_lock dir) + if(NOT HUNTER_SKIP_LOCK) + if("${CMAKE_VERSION}" VERSION_LESS "3.2") + hunter_gate_fatal_error( + "Can't lock, upgrade to CMake 3.2 or use HUNTER_SKIP_LOCK" + WIKI "error.can.not.lock" + ) + endif() + hunter_gate_status_debug("Locking directory: ${dir}") + file(LOCK "${dir}" DIRECTORY GUARD FUNCTION) + hunter_gate_status_debug("Lock done") + endif() +endmacro() + +function(hunter_gate_download dir) + string( + COMPARE + NOTEQUAL + "$ENV{HUNTER_DISABLE_AUTOINSTALL}" + "" + disable_autoinstall + ) + if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL) + hunter_gate_fatal_error( + "Hunter not found in '${dir}'" + "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'" + "Settings:" + " HUNTER_ROOT: ${HUNTER_GATE_ROOT}" + " HUNTER_SHA1: ${HUNTER_GATE_SHA1}" + WIKI "error.run.install" + ) + endif() + string(COMPARE EQUAL "${dir}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("Empty 'dir' argument") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_SHA1 empty") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_URL empty") + endif() + + set(done_location "${dir}/DONE") + set(sha1_location "${dir}/SHA1") + + set(build_dir "${dir}/Build") + set(cmakelists "${dir}/CMakeLists.txt") + + hunter_gate_lock("${dir}") + if(EXISTS "${done_location}") + # while waiting for lock other instance can do all the job + hunter_gate_status_debug("File '${done_location}' found, skip install") + return() + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(MAKE_DIRECTORY "${build_dir}") # check directory permissions + + # Disabling languages speeds up a little bit, reduces noise in the output + # and avoids path too long windows error + file( + WRITE + "${cmakelists}" + "cmake_minimum_required(VERSION 3.0)\n" + "project(HunterDownload LANGUAGES NONE)\n" + "include(ExternalProject)\n" + "ExternalProject_Add(\n" + " Hunter\n" + " URL\n" + " \"${HUNTER_GATE_URL}\"\n" + " URL_HASH\n" + " SHA1=${HUNTER_GATE_SHA1}\n" + " DOWNLOAD_DIR\n" + " \"${dir}\"\n" + " SOURCE_DIR\n" + " \"${dir}/Unpacked\"\n" + " CONFIGURE_COMMAND\n" + " \"\"\n" + " BUILD_COMMAND\n" + " \"\"\n" + " INSTALL_COMMAND\n" + " \"\"\n" + ")\n" + ) + + if(HUNTER_STATUS_DEBUG) + set(logging_params "") + else() + set(logging_params OUTPUT_QUIET) + endif() + + hunter_gate_status_debug("Run generate") + + # Need to add toolchain file too. + # Otherwise on Visual Studio + MDD this will fail with error: + # "Could not find an appropriate version of the Windows 10 SDK installed on this machine" + if(EXISTS "${CMAKE_TOOLCHAIN_FILE}") + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}") + else() + # 'toolchain_arg' can't be empty + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=") + endif() + + string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make) + if(no_make) + set(make_arg "") + else() + # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM + set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}") + endif() + + execute_process( + COMMAND + "${CMAKE_COMMAND}" + "-H${dir}" + "-B${build_dir}" + "-G${CMAKE_GENERATOR}" + "${toolchain_arg}" + ${make_arg} + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error("Configure project failed") + endif() + + hunter_gate_status_print( + "Initializing Hunter workspace (${HUNTER_GATE_SHA1})" + " ${HUNTER_GATE_URL}" + " -> ${dir}" + ) + execute_process( + COMMAND "${CMAKE_COMMAND}" --build "${build_dir}" + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error("Build project failed") + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}") + file(WRITE "${done_location}" "DONE") + + hunter_gate_status_debug("Finished") +endfunction() + +# Must be a macro so master file 'cmake/Hunter' can +# apply all variables easily just by 'include' command +# (otherwise PARENT_SCOPE magic needed) +macro(HunterGate) + if(HUNTER_GATE_DONE) + # variable HUNTER_GATE_DONE set explicitly for external project + # (see `hunter_download`) + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() + + # First HunterGate command will init Hunter, others will be ignored + get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET) + + if(NOT HUNTER_ENABLED) + # Empty function to avoid error "unknown function" + function(hunter_add_package) + endfunction() + elseif(_hunter_gate_done) + hunter_gate_status_debug("Secondary HunterGate (use old settings)") + hunter_gate_self( + "${HUNTER_CACHED_ROOT}" + "${HUNTER_VERSION}" + "${HUNTER_SHA1}" + _hunter_self + ) + include("${_hunter_self}/cmake/Hunter") + else() + set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_LIST_DIR}") + + string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name) + if(_have_project_name) + hunter_gate_fatal_error( + "Please set HunterGate *before* 'project' command. " + "Detected project: ${PROJECT_NAME}" + WIKI "error.huntergate.before.project" + ) + endif() + + cmake_parse_arguments( + HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV} + ) + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1) + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url) + string( + COMPARE + NOTEQUAL + "${HUNTER_GATE_UNPARSED_ARGUMENTS}" + "" + _have_unparsed + ) + string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global) + string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath) + + if(_have_unparsed) + hunter_gate_user_error( + "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}" + ) + endif() + if(_empty_sha1) + hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory") + endif() + if(_empty_url) + hunter_gate_user_error("URL suboption of HunterGate is mandatory") + endif() + if(_have_global) + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)") + endif() + endif() + if(HUNTER_GATE_LOCAL) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)") + endif() + endif() + if(_have_filepath) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)") + endif() + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)") + endif() + endif() + + hunter_gate_detect_root() # set HUNTER_GATE_ROOT + + # Beautify path, fix probable problems with windows path slashes + get_filename_component( + HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE + ) + hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}") + if(NOT HUNTER_ALLOW_SPACES_IN_PATH) + string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces) + if(NOT _contain_spaces EQUAL -1) + hunter_gate_fatal_error( + "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." + "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" + "(Use at your own risk!)" + WIKI "error.spaces.in.hunter.root" + ) + endif() + endif() + + string( + REGEX + MATCH + "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*" + HUNTER_GATE_VERSION + "${HUNTER_GATE_URL}" + ) + string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty) + if(_is_empty) + set(HUNTER_GATE_VERSION "unknown") + endif() + + hunter_gate_self( + "${HUNTER_GATE_ROOT}" + "${HUNTER_GATE_VERSION}" + "${HUNTER_GATE_SHA1}" + _hunter_self + ) + + set(_master_location "${_hunter_self}/cmake/Hunter") + if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter") + # Hunter downloaded manually (e.g. by 'git clone') + set(_unused "xxxxxxxxxx") + set(HUNTER_GATE_SHA1 "${_unused}") + set(HUNTER_GATE_VERSION "${_unused}") + else() + get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE) + set(_done_location "${_archive_id_location}/DONE") + set(_sha1_location "${_archive_id_location}/SHA1") + + # Check Hunter already downloaded by HunterGate + if(NOT EXISTS "${_done_location}") + hunter_gate_download("${_archive_id_location}") + endif() + + if(NOT EXISTS "${_done_location}") + hunter_gate_internal_error("hunter_gate_download failed") + endif() + + if(NOT EXISTS "${_sha1_location}") + hunter_gate_internal_error("${_sha1_location} not found") + endif() + file(READ "${_sha1_location}" _sha1_value) + string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal) + if(NOT _is_equal) + hunter_gate_internal_error( + "Short SHA1 collision:" + " ${_sha1_value} (from ${_sha1_location})" + " ${HUNTER_GATE_SHA1} (HunterGate)" + ) + endif() + if(NOT EXISTS "${_master_location}") + hunter_gate_user_error( + "Master file not found:" + " ${_master_location}" + "try to update Hunter/HunterGate" + ) + endif() + endif() + include("${_master_location}") + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() +endmacro() + diff --git a/c++/src/build-system/cmake/Sqlite3Config.cmake b/c++/src/build-system/cmake/Sqlite3Config.cmake new file mode 100644 index 00000000..80e70fd8 --- /dev/null +++ b/c++/src/build-system/cmake/Sqlite3Config.cmake @@ -0,0 +1,25 @@ +# - find Sqlite 3 +# SQLITE3_INCLUDE_DIR - Where to find Sqlite 3 header files (directory) +# SQLITE3_LIBRARIES - Sqlite 3 libraries +# SQLITE3_LIBRARY_RELEASE - Where the release library is +# SQLITE3_LIBRARY_DEBUG - Where the debug library is +# SQLITE3_FOUND - Set to TRUE if we found everything (library, includes and executable) + +IF( SQLITE3_INCLUDE_DIR AND SQLITE3_LIBRARY_RELEASE AND SQLITE3_LIBRARY_DEBUG ) + SET(SQLITE3_FIND_QUIETLY TRUE) +ENDIF( SQLITE3_INCLUDE_DIR AND SQLITE3_LIBRARY_RELEASE AND SQLITE3_LIBRARY_DEBUG ) + +FIND_PATH( SQLITE3_INCLUDE_DIR sqlite3.h + PATHS /netopt/ncbi_tools/sqlite-3.6.14.2-ncbi1/include + NO_DEFAULT_PATH ) + +IF (SQLITE3_INCLUDE_DIR) + FIND_LIBRARY( SQLITE3_LIBRARY NAMES sqlite3 + PATHS /netopt/ncbi_tools/sqlite-3.6.14.2-ncbi1/lib/ + NO_DEFAULT_PATH ) + + IF (NOT SQLITE3_LIBRARY) + MESSAGE(FATAL_ERROR "Include ${SQLITE3_INCLUDE_DIR}/sqlite3.h found, but no library in /netopt/ncbi_tools/sqlite-3.6.14.2-ncbi1/GCC-Debug64MT/lib/ ") #XXX choose build type + ENDIF (NOT SQLITE3_LIBRARY) +ENDIF (SQLITE3_INCLUDE_DIR) + diff --git a/c++/src/build-system/cmake/cmake-configure b/c++/src/build-system/cmake/cmake-configure new file mode 100755 index 00000000..7232aa2d --- /dev/null +++ b/c++/src/build-system/cmake/cmake-configure @@ -0,0 +1,522 @@ +#!/bin/sh + +# This script is based on "Autotools-style wrapper for CMake", +# Modifications made: +# 1. configuration parameters specific for C++ toolkit and Gpipe +# 2. --without- arguments support +# 3. custom root directory +# etc + +# Autotools-style (./configure) wrapper for CMake +# +# +# *** IMPORTANT *** +# +# You must include the GNUInstallDirs module (which comes with +# CMake) in your project. Just put "include (GNUInstallDirs)" in +# you CMakeLists.txt and you should be good. +# +# This script was originally written for Squash +# by Evan Nemerson +# , but has been spun off into a separate +# repository. Please feel free to copy it into your own repository, +# though I would appreciate it if you would post improvements, bugs, +# feature requests, etc. to the issue tracker at +# . +# +# To the extent possible under law, the author(s) hereby waive all +# copyright and related or neighboring rights to this work. For +# details, see + +TOP_SRCDIR="$(dirname $0)" + +if [ "${CMAKE_CMD}" = "" ]; then + CMAKE_CMD="cmake" +fi + +if [ -z "$CC" ]; then + CC=`which gcc` +fi +if [ -z "$CXX" ]; then + CXX=`which g++` +fi +BUILD_TYPE="Debug" +BUILD_SHARED_LIBS=ON +PREFIX=/usr/local +LIBDIR= +CMAKE_ARGS= + +if [ -e "${TOP_SRCDIR}/configure-custom.sh" ]; then + . "${TOP_SRCDIR}/configure-custom.sh" +fi + +quote() { + echo "$1" | sed -e "s|'|'\\\\''|g; 1s/^/'/; \$s/\$/'/" +} + +extract_var_string() { + VAR_NAME=$1 + VAR_NAME=$(echo $1 | sed -e 's/[ \t]*$//') + if [ "x$2" != "x" ]; then + VAR_VALUE=$2 + else + VAR_VALUE=yes + fi + + if [ "x$3" != "x" ]; then + VAR_UC_NAME=$3 + else + VAR_UC_NAME=$(echo "$1" | tr '[:lower:]' '[:upper:]' | tr -c '[:alnum:]' '_' | sed 's/_$//g') + fi +} + +set_config_var() { + is_with=n + case "$1" in + "--enable-"*) + name="${1#--enable-}" + cfg="${ENABLE_VARS}" + ;; + "--disable-"*) + name="${1#--disable-}"; + cfg="${DISABLE_VARS}"; + ;; + "--with-"*) + # IFS="=" read -ra WITHARGS <<< "${1}" + name="${1#--with-}" + cfg="${WITH_VARS}" + is_with=y + ;; + "--without-"*) + # IFS="=" read -ra WITHARGS <<< "${1}" + name="${1#--without-}" + cfg="${WITH_VARS}" + is_without=y + ;; + esac + + found=n + for varstring in $cfg; do + extract_var_string $(echo "${varstring}" | tr '|' ' ') + if [ "x$VAR_NAME" = "x$name" ]; then + found=y + break; + fi + done + + if [ "$found" = "y" ]; then + if [ "x$is_without" = "xy" ]; then + CMAKE_ARGS="$CMAKE_ARGS -D${VAR_UC_NAME}_DISABLED=yes" + elif [ "x$is_with" = "xy" ]; then + CMAKE_ARGS="$CMAKE_ARGS -D${VAR_UC_NAME}=$(quote "$2")" + else + CMAKE_ARGS="$CMAKE_ARGS -D${VAR_UC_NAME}=$(quote "${VAR_VALUE}")" + fi + else + echo "Unknown parameter: ${1}" + exit 1 + fi +} + +prefix_to_offset() { + expr $(echo "${1}" | awk '{ print length }') + 1 +} + +print_help() { + cat <&2 + echo "Try \`$0 --help' for more information" >&2 + exit -1 + esac; + shift +done + +if [ "x${LIBDIR}" = "x" ]; then + LIBDIR="${PREFIX}/lib" +fi + +# Unlike CFLAGS/CXXFLAGS/CC/CXX, LDFLAGS isn't handled by CMake, so we +# need to parse it here. +if [ "x${LDFLAGS}" != "x" ]; then + for varname in EXE MODULE SHARED; do + CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_${varname}_LINKER_FLAGS=$(quote "$LDFLAGS")" + done +fi + +if [ -z "$ROOT" ]; then + if [ -z "$GPIPEROOT" ]; then + ROOT="CMake-$BUILD_TYPE" + if [ "$BUILD_SHARED_LIBS" == "ON" ]; then + ROOT="$ROOT"DLL + fi + else + ROOT=`cd "${TOP_SRCDIR}/../../../" && /bin/pwd` || exit 1 + ROOT=`/usr/bin/dirname "$ROOT"` || exit 1 + ROOT=$ROOT/$GPIPEROOT + fi +fi + +if [ ! -z "$MAX_DEBUG" ]; then + CXXFLAGS="${CXXFLAGS:-}${CXXFLAGS:+ }-D_GLIBCXX_DEBUG" +fi + +if [ ! -z "$EXPERIMENTAL" ]; then + for x in `echo $EXPERIMENTAL | tr , ' '`; do + case "$x" in + ChaosMonkey ) + CPPFLAGS="$CPPFLAGS -DNCBI_MONKEY" + ;; + Int8GI ) + CPPFLAGS="$CPPFLAGS -DNCBI_INT8_GI" + NCBI_C_PATH_TAGS="/ncbi.gi64 .gi64" + ;; + StrictGI ) + CPPFLAGS="$CPPFLAGS -DNCBI_STRICT_GI" + NCBI_C_PATH_TAGS="/ncbi.gi64 .gi64" + ;; + * ) + echo "cmake-configure: error: unrecognized experimental feature \"$x\"." >&2 + exit 1;; + esac + done +fi + +CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_CXX_COMPILER=$(quote "$CXX")" +CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_C_COMPILER=$(quote "$CC")" +CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_C_FLAGS=$(quote "$CFLAGS")" +CXXFLAGS="${CXXFLAGS:-}${CXXFLAGS:+ }${CPPFLAGS:-}${CPPFLAGS:+ }" +CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_CXX_FLAGS=$(quote "$CXXFLAGS")" + +mkdir -p $ROOT/build +ROOT_SOURCE_PATH=`pwd` +cd $ROOT/build + +#we need to do this because CMake caches configuration parameters, and if you run ./cmake-configure for existing build directory +#but with another parameters, CMake will use old values for paramers you omit (not default ones) +if [ -e CMakeCache.txt ]; then + rm CMakeCache.txt +fi + +eval "${CMAKE_CMD}" ${TRACE_CMAKE} ${NINJA_FLAGS} "${TOP_SRCDIR}/../../" -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" -DCMAKE_INSTALL_PREFIX="${PREFIX}" -DCMAKE_INSTALL_LIBDIR="${LIBDIR}" ${CMAKE_ARGS} diff --git a/c++/src/build-system/cmake/config.cmake.h.in b/c++/src/build-system/cmake/config.cmake.h.in new file mode 100644 index 00000000..25570139 --- /dev/null +++ b/c++/src/build-system/cmake/config.cmake.h.in @@ -0,0 +1,948 @@ +/* /net/snowman/vol/export4/gbench/gbench/builds/gpipe/devel-make-test/GCC401-ReleaseMTDLL64/inc/ncbiconf_unix.h. Generated by configure. */ +/* src/build-system/config.h.in. Generated from src/build-system/configure.ac by autoheader. */ + +/* Define to 1 if necessary to get FIONBIO (e.g., on Solaris) */ +#cmakedefine BSD_COMP 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ACCELERATE_ACCELERATE_H 1 + +/* Define to 1 if you have the `alarm' function. */ +#cmakedefine HAVE_ALARM 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the `asprintf' function. */ +#cmakedefine HAVE_ASPRINTF 1 + +/* Define to 1 if you have the `atoll' function. */ +#cmakedefine HAVE_ATOLL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ATOMIC_H + +/* Define to 1 if your C compiler supports __attribute__((destructor)) */ +#define HAVE_ATTRIBUTE_DESTRUCTOR 1 + +/* define for posix threads */ +#cmakedefine NCBI_POSIX_THREADS + +/* Define to 1 if your compiler supports + __attribute__((visibility("default"))) */ +/* #undef HAVE_ATTRIBUTE_VISIBILITY_DEFAULT */ + +/* Define to 1 if you have the `basename' function. */ +#cmakedefine HAVE_BASENAME 1 + +/* Define to 1 if NCBI C++ API for BerkeleyDB is available. */ +#cmakedefine HAVE_BDB 1 + +/* Define to 1 if NCBI C++ API for BerkeleyDB based data cache is available. + */ +#cmakedefine HAVE_BDB_CACHE 1 + +/* Define to 1 if Berkeley DB libraries are available. */ +#cmakedefine HAVE_BERKELEY_DB 1 + +/* Define to 1 if the Berkeley `db_cxx' library is available. */ +#cmakedefine HAVE_BERKELEY_DB_CXX 1 + +/* Define to 1 if the `Boost.Regex' library is available. */ +#define HAVE_BOOST_REGEX 1 + +/* Define to 1 if the `Boost.Spirit' headers are available. */ +#define HAVE_BOOST_SPIRIT 1 + +/* Define to 1 if the `Boost.Test' libraries are available. */ +#define HAVE_BOOST_TEST 1 + +/* Define to 1 if the `Boost.Threads' library is available. */ +#define HAVE_BOOST_THREAD 1 + +/* Define to 1 if the preprocessor supports GNU-style variadic macros. */ +#define HAVE_CPP_GNU_VARARGS 1 + +/* Define to 1 if the preprocessor supports C99-style variadic macros. */ +#define HAVE_CPP_STD_VARARGS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_CPUID_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_DLFCN_H 1 + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +/* #undef HAVE_DOPRNT */ + +/* Define to 1 if you have the `erf' function. */ +#cmakedefine HAVE_ERF 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ERRNO_H 1 + +/* Define to 1 if you have the `euidaccess' function. */ +#cmakedefine HAVE_EUIDACCESS 1 + +/* Define to 1 if you have the `FCGX_Accept_r' function. */ +#define HAVE_FCGX_ACCEPT_R 1 + +/* Define to 1 if you have the `freehostent' function. */ +#cmakedefine HAVE_FREEHOSTENT 1 + +/* Define to 1 if FreeType is available. */ +#define HAVE_FREETYPE 1 + +/* Define to 1 if you have the `fseeko' function. */ +#cmakedefine HAVE_FSEEKO 1 + +/* Define to 1 if you have the `fstat' function. */ +#cmakedefine HAVE_FSTAT 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_FSTREAM 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_FSTREAM_H 1 + +/* Define to 1 if your localtime_r returns a int. */ +/* #undef HAVE_FUNC_LOCALTIME_R_INT */ + +/* Define to 1 if your localtime_r returns a struct tm*. */ +#define HAVE_FUNC_LOCALTIME_R_TM 1 + +/* Define to 1 if you have the `getaddrinfo' function. */ +#cmakedefine HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `getgrouplist' function. */ +#undef HAVE_GETGROUPLIST + +/* If you have the `gethostbyaddr_r' function, define to the number of + arguments it takes (normally 7 or 8). */ +#cmakedefine HAVE_GETHOSTBYADDR_R 8 + +/* If you have the `gethostbyname_r' function, define to the number of + arguments it takes (normally 5 or 6). */ +#cmakedefine HAVE_GETHOSTBYNAME_R 6 + +/* Define to 1 if you have the `gethostent_r' function. */ +#cmakedefine HAVE_GETHOSTENT_R 1 + +/* Define to 1 if you have the `getipnodebyaddr' function. */ +#cmakedefine HAVE_GETIPNODEBYADDR 1 + +/* Define to 1 if you have the `getipnodebyname' function. */ +#cmakedefine HAVE_GETIPNODEBYNAME 1 + +/* Define to 1 if you have the `getloadavg' function. */ +#cmakedefine HAVE_GETLOADAVG 1 + +/* Define to 1 if you have the `getlogin_r' function */ +#cmakedefine HAVE_GETLOGIN_R 1 + +/* Define to 1 if you have the `getnameinfo' function. */ +#cmakedefine HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the `getopt' function. */ +#cmakedefine HAVE_GETOPT 1 + +/* Define to 1 if you have the `getpagesize' function. */ +#cmakedefine HAVE_GETPAGESIZE 1 + +/* Define to 1 if you have the `getpass' function. */ +#cmakedefine HAVE_GETPASS 1 + +/* Define to 1 if you have the `getpassphrase' function. */ +#cmakedefine HAVE_GETPASSPHRASE 1 + +/* Define to 1 if you have the `getpwuid' function. */ +#cmakedefine HAVE_GETPWUID 1 + +/* Define to 1 if you have the `getrusage' function. */ +#cmakedefine HAVE_GETRUSAGE 1 + +/* If you have the `getservbyname_r' function, define to the number of + arguments it takes (normally 5 or 6). */ +#cmakedefine HAVE_GETSERVBYNAME_R 6 + +/* Define to 1 if you have the `gettimeofday' function. */ +#cmakedefine HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the `getuid' function. */ +#cmakedefine HAVE_GETUID 1 + +/* Define to 1 if ICU libraries are available. */ +#define HAVE_ICU 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_IEEEFP_H 1 + +/* Define to 1 if you have the `inet_ntoa_r' function. */ +#cmakedefine HAVE_INET_NTOA_R 1 + +/* Define to 1 if you have the `inet_ntop' function. */ +#cmakedefine HAVE_INET_NTOP 1 + +/* Define to 1 if the system has the type `intptr_t'. */ +#define HAVE_INTPTR_T 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_IOSTREAM 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_IOSTREAM_H 1 + +/* Define to 1 if you have `ios(_base)::register_callback'. */ +#define HAVE_IOS_REGISTER_CALLBACK 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LAPACKE_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LAPACKE_LAPACKE_H 1 + +/* Define to 1 if you have the `lchown' function. */ +#cmakedefine HAVE_LCHOWN 1 + +/* Define to 1 if libbz2 is available. */ +#define HAVE_LIBBZ2 1 + +/* Define to 1 if non-public CONNECT extensions are available. */ +#define HAVE_LIBCONNEXT 1 + +/* Define to 1 if CRYPT is available, either in its own library or as part of + the standard libraries. */ +#define HAVE_LIBCRYPT 1 + +/* Define to 1 if libcurl is available. */ +#define HAVE_LIBCURL 1 + +/* Define to 1 if DEMANGLE is available, either in its own library or as part + of the standard libraries. */ +/* #undef HAVE_LIBDEMANGLE */ + +/* Define to 1 if DL is available, either in its own library or as part of the + standard libraries. */ +#cmakedefine HAVE_LIBDL 1 + +/* Define to 1 if libexpat is available. */ +#define HAVE_LIBEXPAT 1 + +/* Define to 1 if libexslt is available. */ +#define HAVE_LIBEXSLT 1 + +/* Define to 1 if FastCGI libraries are available. */ +#define HAVE_LIBFASTCGI 1 + +/* Define to 1 if FreeTDS libraries are available. */ +#define HAVE_LIBFTDS 1 + +/* Define to 1 if libftgl is available. */ +#undef HAVE_LIBFTGL + +/* Define to 1 if libgcrypt is available. */ +#undef HAVE_LIBGCRYPT + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIBGEN_H 1 + +/* Define to 1 if libgif is available. */ +#cmakedefine HAVE_LIBGIF 1 + +/* Define to 1 if GLEW is available, either in its own library or as part of + the standard libraries. */ +#define HAVE_LIBGLEW 1 + +/* Define to 1 if you have libglut. */ +/* #undef HAVE_LIBGLUT */ + +/* Define to 1 if libgnutls is available. */ +#define HAVE_LIBGNUTLS 1 + +/* Define to 1 if libgsoapssl++ is available. */ +#undef HAVE_LIBGSOAP + +/* Define to 1 if libhdf5_cpp is available. */ +#define HAVE_LIBHDF5 1 + +/* Define to 1 if ICONV is available, either in its own library or as part of + the standard libraries. */ +#define HAVE_LIBICONV 1 + +/* Define to 1 if libjpeg is available. */ +#cmakedefine HAVE_LIBJPEG 1 + +/* Define to 1 if libgssapi_krb5 is available. */ +#define HAVE_LIBKRB5 1 + +/* Define to 1 if KSTAT is available, either in its own library or as part of + the standard libraries. */ +/* #undef HAVE_LIBKSTAT */ + +/* Define to 1 if liblzo2 is available. */ +#define HAVE_LIBLZO 1 + +/* Define to 1 if libmagic is available. */ +#define HAVE_LIBMAGIC 1 + +/* Define to 1 if libmimetic is available. */ +#define HAVE_LIBMIMETIC 1 + +/* Define to 1 if libmongoclient is available. */ +#undef HAVE_LIBMONGODB + +/* Define to 1 if libmuparser is available. */ +#define HAVE_LIBMUPARSER 1 + +/* Define to 1 if liboechem is available. */ +/* #undef HAVE_LIBOECHEM */ + +/* Define to 1 if libssl is available. */ +#define HAVE_LIBOPENSSL 1 + +/* Define to 1 if you have libOSMesa. */ +#define HAVE_LIBOSMESA 1 + +/* Define to 1 if libpcre is available. */ +#cmakedefine HAVE_LIBPCRE 1 + +/* Define to 1 if libpng is available. */ +#cmakedefine HAVE_LIBPNG 1 + +/* Define to 1 if RPCSVC is available, either in its own library or as part of + the standard libraries. */ +/* #undef HAVE_LIBRPCSVC */ + +/* Define to 1 if RT is available, either in its own library or as part of the + standard libraries. */ +#define HAVE_LIBRT 1 + +/* Define to 1 if libsablot is available. */ +#define HAVE_LIBSABLOT 1 + +/* Define to 1 if libdrmaa is available. */ +#define HAVE_LIBSGE 1 + +/* Define to 1 if the SP SGML library is available. */ +#define HAVE_LIBSP 1 + +/* Define to 1 if libsqlite3 is available. */ +#define HAVE_LIBSQLITE3 1 + +/* Define to 1 if the NCBI SSS DB library is available. */ +/* #undef HAVE_LIBSSSDB */ + +/* Define to 1 if the NCBI SSS UTILS library is available. */ +/* #undef HAVE_LIBSSSUTILS */ + +/* Define to 1 if SYBASE libraries are available. */ +#cmakedefine HAVE_LIBSYBASE 1 + +/* Define to 1 if SYBASE DBLib is available. */ +#define HAVE_LIBSYBDB 1 + +/* Define to 1 if libtiff is available. */ +#cmakedefine HAVE_LIBTIFF 1 + +/* Define to 1 if libungif is available. */ +#define HAVE_LIBUNGIF 1 + +/* Define to 1 if libxml2 is available. */ +#define HAVE_LIBXML 1 + +/* Define to 1 if libXpm is available. */ +#define HAVE_LIBXPM 1 + +/* Define to 1 if libxslt is available. */ +#define HAVE_LIBXSLT 1 + +/* Define to 1 if libz is available. */ +#define HAVE_LIBZ 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIMITS 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIMITS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LOCALE_H 1 + +/* Define to 1 if you have the `localtime_r' function. */ +#cmakedefine HAVE_LOCALTIME_R 1 + +/* Define to 1 if local LBSM support is available. */ +#define HAVE_LOCAL_LBSM 1 + +/* Define to 1 if you have the `lutimes' function. */ +#cmakedefine HAVE_LUTIMES 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MALLOC_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memrchr' function. */ +#cmakedefine HAVE_MEMRCHR 1 + +/* Define to 1 if MySQL is available. */ +#cmakedefine HAVE_MYSQL 1 + +/* Define to 1 if you have the `nanosleep' function. */ +#cmakedefine HAVE_NANOSLEEP 1 + +/* Define to 1 if the NCBI C toolkit is available. */ +#cmakedefine HAVE_NCBI_C 1 + +/* Define to 1 if the real version of ncbi_crypt support is available. */ +#define HAVE_NCBI_CRYPT 1 + +/* Define to 1 if you have NCBI's SRA/VDB SDK/Toolkit. */ +#cmakedefine HAVE_NCBI_VDB 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETINET_TCP_H 1 + +/* Define to 1 if ODBC libraries are available. */ +/* #undef HAVE_ODBC */ + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ODBCSS_H 1 + +/* Define to 1 if you have OpenGL (-lGL). */ +#define HAVE_OPENGL 1 + +/* Define to 1 if the ORBacus CORBA package is available. */ +#define HAVE_ORBACUS 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_PATHS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_POLL_H 1 + +/* Define to 1 if you have the `pthread_atfork' function. */ +#cmakedefine HAVE_PTHREAD_ATFORK 1 + +/* Define to 1 if you have the `pthread_condattr_setclock' function. */ +#cmakedefine HAVE_PTHREAD_CONDATTR_SETCLOCK 1 + +/* Define to 1 if pthread mutexes are available. */ +#define HAVE_PTHREAD_MUTEX 1 + +/* Define to 1 if you have the `pthread_setconcurrency' function. */ +#cmakedefine HAVE_PTHREAD_SETCONCURRENCY 1 + +/* Define to 1 if libunwind is available. */ +#cmakedefine HAVE_LIBUNWIND 1 + +/* Define to 1 if abi::__cxa_demangle exists in cxxabi.h. */ +#cmakedefine HAVE_CXA_DEMANGLE 1 + +/* Define to 1 if the PUBSEQ service is available. */ +#define HAVE_PUBSEQ_OS 1 + +/* Define to 1 if you have the `putenv' function. */ +#cmakedefine HAVE_PUTENV 1 + +/* Define to 1 if Python libraries are available. */ +#define HAVE_PYTHON 1 + +/* Define to 1 if Python 2.5 libraries are available. */ +#define HAVE_PYTHON25 1 + +/* Define to 1 if Python 2.6 libraries are available. */ +#define HAVE_PYTHON26 1 + +/* Define to 1 if Python 2.7 libraries are available. */ +#define HAVE_PYTHON27 1 + +/* Define to 1 if you have the `readpassphrase' function. */ +#cmakedefine HAVE_READPASSPHRASE 1 + +/* Define to 1 if you have the `readv' function. */ +#cmakedefine HAVE_READV 1 + +/* Define to 1 if your C compiler supports some variant of the C99 `restrict' + keyword. */ +#define HAVE_RESTRICT_C 1 + +/* Define to 1 if your C++ compiler supports some variant of the C99 + `restrict' keyword. */ +#define HAVE_RESTRICT_CXX 1 + +/* Define to 1 if you have the `sched_yield' function. */ +#cmakedefine HAVE_SCHED_YIELD 1 + +/* Define to 1 if you have the `select' function. */ +#cmakedefine HAVE_SELECT 1 + +/* Define to 1 if you have `union semun'. */ +#cmakedefine HAVE_SEMUN 1 + +/* Define to 1 if you have the `setenv' function. */ +#cmakedefine HAVE_SETENV 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SIGNAL_H 1 + +/* Define to 1 if `sin_len' is a member of `struct sockaddr_in'. */ +/* #undef HAVE_SIN_LEN */ + +/* Define to 1 if you have the `socketpair' function. */ +#cmakedefine HAVE_SOCKETPAIR 1 + +/* Define to 1 if the system has the type `socklen_t'. */ +#cmakedefine HAVE_SOCKLEN_T 1 + +/* Define to 1 if you have the `SQLGetPrivateProfileString' function. */ +/* #undef HAVE_SQLGETPRIVATEPROFILESTRING */ + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SQLITE3ASYNC_H 1 + +/* Define to 1 if you have the `sqlite3_unlock_notify' function. */ +#cmakedefine HAVE_SQLITE3_UNLOCK_NOTIFY 1 + +/* Define to 1 if the system has the type `SQLLEN'. */ +#define HAVE_SQLLEN 1 + +/* Define to 1 if the system has the type `SQLSETPOSIROW'. */ +#define HAVE_SQLSETPOSIROW 1 + +/* Define to 1 if you have the `statfs' function. */ +#cmakedefine HAVE_STATFS 1 + +/* Define to 1 if you have the `statvfs' function. */ +#cmakedefine HAVE_STATVFS 1 + +/* Define to 1 if you have the `stddef.h' function. */ +#cmakedefine HAVE_STDDEF_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strcasecmp' function. */ +#cmakedefine HAVE_STRCASECMP 1 + +/* Define to 1 if strcasecmp treats letters as lowercase. */ +#define HAVE_STRCASECMP_LC 1 + +/* Define to 1 if you have the `strdup' function. */ +#cmakedefine HAVE_STRDUP 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcat' function. */ +#cmakedefine HAVE_STRLCAT 1 + +/* Define to 1 if you have the `strlcpy' function. */ +#cmakedefine HAVE_STRLCPY 1 + +/* Define to 1 if you have the `strndup' function. */ +#cmakedefine HAVE_STRNDUP 1 + +/* Define to 1 if you have the `strsep' function. */ +#cmakedefine HAVE_STRSEP 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRSTREAM 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRSTREAM_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRSTREA_H 1 + +/* Define to 1 if you have the `strtok_r' function. */ +#cmakedefine HAVE_STRTOK_R 1 + +/* Define to 1 if `tm_zone' is member of `struct tm'. */ +#define HAVE_STRUCT_TM_TM_ZONE 1 + +/* Define to 1 if `__tm_zone' is member of `struct tm'. */ +/* #undef HAVE_STRUCT_TM___TM_ZONE */ + +/* Define to 1 if SYBASE has reentrant libraries. */ +#define HAVE_SYBASE_REENTRANT 1 + +/* Define to 1 if Linux-like 1-arg sysinfo exists. */ +#define HAVE_SYSINFO_1 1 + +/* Define to 1 if you have the `sysmp' function. */ +/* #undef HAVE_SYSMP */ + +/* Define to 1 if you have SysV semaphores. */ +#define HAVE_SYSV_SEMAPHORES 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_EPOLL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_IOCTL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_MOUNT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKIO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STATVFS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SYSINFO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_VFS_H 1 + +/* Define to 1 if you have the `timegm' function. */ +#cmakedefine HAVE_TIMEGM 1 + +/* Define to 1 if the system has the type `uintptr_t'. */ +#define HAVE_UINTPTR_T 1 + +/* Define to 1 if your system permits reading integers from unaligned + addresses. */ +#define HAVE_UNALIGNED_READS 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/* Define to 1 if you have the `usleep' function. */ +#define HAVE_USLEEP 1 + +/* Define to 1 if you have the `utimes' function. */ +#cmakedefine HAVE_UTIMES 1 + +/* Define to 1 if you have the `vasprintf' function. */ +#cmakedefine HAVE_VASPRINTF 1 + +/* Define to 1 if your C compiler supports SIMD vector calculations. */ +#undef HAVE_VECTOR_MATH + +/* Define to 1 if you have the `vprintf' function. */ +#cmakedefine HAVE_VPRINTF 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#cmakedefine HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_WCHAR_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_WINDOWS_H 1 + +/* Define to 1 if you have the header file. */ +#undef HAVE_WINTERNL_H + +/* Define to 1 if you have the `writev' function. */ +#cmakedefine HAVE_WRITEV 1 + +/* Define to 1 if the system has the type `wstring'. */ +#cmakedefine HAVE_WSTRING 1 + +/* Define to 1 if wxWidgets is available. */ +#define HAVE_WXWIDGETS 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_X86INTRIN_H 1 + +/* Define to 1 if Xalan-C++ is available. */ +#define HAVE_XALAN 1 + +/* Define to 1 if Xerces-C++ is available. */ +#define HAVE_XERCES 1 + +/* Define to 1 if Zorba is available. */ +#undef HAVE_ZORBA + +/* Full GNU-style system type */ +#cmakedefine HOST "@HOST@" + +/* CPU type only */ +#cmakedefine HOST_CPU "@HOST_CPU@" + +/* System OS only */ +#cmakedefine HOST_OS "@HOST_OS@" + +/* System vendor only */ +#define HOST_VENDOR "unknown" + +/* Define as const if the declaration of iconv() needs const. */ +#define ICONV_CONST + +/* Define to 0xffffffff if your operating system doesn't. */ +/* #undef INADDR_NONE */ + +/* Define to 1 when building binaries for public release. */ +/* #undef NCBI_BIN_RELEASE */ + +/* Compiler name */ +#cmakedefine NCBI_COMPILER "@NCBI_COMPILER@" + +/* Compiler name */ +/* #undef NCBI_COMPILER_COMPAQ */ + +/* Compiler name */ +/* #undef NCBI_COMPILER_CRAY */ + +/* Compiler name */ +#cmakedefine NCBI_COMPILER_GCC @NCBI_COMPILER_GCC@ + +/* Compiler name */ +/* #undef NCBI_COMPILER_ICC */ + +/* Compiler name */ +/* #undef NCBI_COMPILER_KCC */ + +/* Compiler name */ +/* #undef NCBI_COMPILER_MIPSPRO */ + +/* Compiler name */ +/* #undef NCBI_COMPILER_MSVC */ + +/* Compiler name */ +/* #undef NCBI_COMPILER_UNKNOWN */ + +/* Compiler version as three-digit integer */ +#define NCBI_COMPILER_VERSION 401 + +/* Compiler name */ +/* #undef NCBI_COMPILER_VISUALAGE */ + +/* Compiler name */ +/* #undef NCBI_COMPILER_WORKSHOP */ + +/* This is the NCBI C++ Toolkit. */ +#define NCBI_CXX_TOOLKIT 1 + +/* Define to whatever syntax, if any, your compiler supports for marking + functions as deprecated. */ +#define NCBI_DEPRECATED __attribute__((__deprecated__)) + +/* Define to 1 if building dynamic libraries by default. */ +#cmakedefine NCBI_DLL_BUILD @NCBI_DLL_BUILD@ + +/* Define to 1 if building dynamic libraries at all (albeit not necessarily by + default). */ +#cmakedefine NCBI_DLL_SUPPORT @NCBI_DLL_SUPPORT@ + +/* Define to whatever syntax your compiler supports for marking functions as + to be inlined even if they might not otherwise be. */ +#define NCBI_FORCEINLINE inline __attribute__((always_inline)) + +/* Rename DBLIB symbols in FTDS to avoid name clash with Sybase DBLIB. */ +#define NCBI_FTDS_RENAME_SYBDB 1 + +/* If you have the `getpwuid_r' function, define to the number of arguments it + takes (normally 4 or 5). */ +#define NCBI_HAVE_GETPWUID_R 5 + +/* If you have the `readdir_r' function, define to the number of arguments it + takes (normally 2 or 3). */ +#define NCBI_HAVE_READDIR_R 3 + +/* Define to 1 if building Java Native Interface bindings. */ +#undef NCBI_JNI + +/* Define to whatever syntax, if any, your compiler supports for marking + functions that never return. */ +#cmakedefine NCBI_NORETURN + +/* Operating system name */ +#cmakedefine NCBI_OS "@NCBI_OS@" + +/* Define to 1 on AIX. */ +/* #undef NCBI_OS_AIX */ + +/* Define to 1 on *BSD. */ +/* #undef NCBI_OS_BSD */ + +/* Define to 1 on Cygwin. */ +#cmakedefine NCBI_OS_CYGWIN @NCBI_OS_CYGWIN@ + +/* Define to 1 on Mac OS X. */ +#cmakedefine NCBI_OS_DARWIN @NCBI_OS_DARWIN@ + +/* Define to 1 on IRIX. */ +/* #undef NCBI_OS_IRIX */ + +/* Define to 1 on Linux. */ +#cmakedefine NCBI_OS_LINUX @NCBI_OS_LINUX@ + +/* Define to 1 on Windows. */ +#cmakedefine NCBI_OS_MSWIN @NCBI_OS_MSWIN@ + +/* Define to 1 on Tru64 Unix. */ +/* #undef NCBI_OS_OSF1 */ + +/* Define to 1 on Solaris. */ +#cmakedefine NCBI_OS_SOLARIS @NCBI_OS_SOLARIS@ + +/* Define to 1 on Unix. */ +#cmakedefine NCBI_OS_UNIX @NCBI_OS_UNIX@ + +/* Define to whatever syntax, if any, your compiler supports for marking types + as packed to save memory. */ +#undef NCBI_PACKED + +/* Define to the architecture size. */ +#define NCBI_PLATFORM_BITS 64 + +/* Define to 1 if the plugin manager should load DLLs by default. */ +#define NCBI_PLUGIN_AUTO_LOAD 1 + +/* Define to whatever syntax, if any, your C compiler supports for marking + pointers as restricted in the C99 sense. */ +#define NCBI_RESTRICT_C __restrict__ + +/* Define to whatever syntax, if any, your C++ compiler supports for marking + pointers as restricted in the C99 sense. */ +#define NCBI_RESTRICT_CXX __restrict__ + +/* Build signature: compiler-name '_' compiler-version '-' configuration '--' + platform-name '-' hostname */ +#cmakedefine NCBI_SIGNATURE "@NCBI_SIGNATURE@" + +/* Define to 1 if SQLColAttribute's last argument is an SQLLEN * */ +#define NCBI_SQLCOLATTRIBUTE_SQLLEN 1 + +/* Define to whatever syntax your compiler supports for declaring thread-local + variables, or leave undefined if it doesn't. */ +#undef NCBI_TLS_VAR + +/* Define to 1 if building universal (multi-architecture) binaries. */ +/* #undef NCBI_UNIVERSAL_BUILD */ + +/* Define to 1 if building plugins as bundles, as Mac OS X traditionally + required. */ +#undef NCBI_USE_BUNDLES + +/* Define to 1 if prototypes can use exception specifications. */ +#define NCBI_USE_THROW_SPEC 1 + +/* Define to whatever syntax, if any, your compiler supports for marking + functions whose (status) result is important to check. */ +#undef NCBI_WARN_UNUSED_RESULT + +/* Define to 1 if the BSD-style netdb interface is reentrant. */ +/* #undef NETDB_REENTRANT */ + +/* Define as the return type of signal handlers (`int' or `void'). */ +#define RETSIGTYPE void + +/* Define to 1 if the `select' function updates its timeout when interrupted + by a signal. */ +#define SELECT_UPDATES_TIMEOUT 1 + +/* The size of a `char', as computed by sizeof. */ +#cmakedefine SIZEOF_CHAR @SIZEOF_CHAR@ + +/* The size of a `double', as computed by sizeof. */ +#cmakedefine SIZEOF_DOUBLE @SIZEOF_DOUBLE@ + +/* The size of a `float', as computed by sizeof. */ +#cmakedefine SIZEOF_FLOAT @SIZEOF_FLOAT@ + +/* The size of a `int', as computed by sizeof. */ +#cmakedefine SIZEOF_INT @SIZEOF_INT@ + +/* The size of a `long', as computed by sizeof. */ +#cmakedefine SIZEOF_LONG @SIZEOF_LONG@ + +/* The size of a `long double', as computed by sizeof. */ +#cmakedefine SIZEOF_LONG_DOUBLE @SIZEOF_LONG_DOUBLE@ + +/* The size of a `long long', as computed by sizeof. */ +#cmakedefine SIZEOF_LONG_LONG @SIZEOF_LONG_LONG@ + +/* The size of a `short', as computed by sizeof. */ +#cmakedefine SIZEOF_SHORT @SIZEOF_SHORT@ + +/* The size of a `size_t', as computed by sizeof. */ +#cmakedefine SIZEOF_SIZE_T @SIZEOF_SIZE_T@ + +/* The size of a `void*', as computed by sizeof. */ +#cmakedefine SIZEOF_VOIDP @SIZEOF_VOIDP@ + +/* The size of a `__int64', as computed by sizeof. */ +#cmakedefine SIZEOF___INT64 @SIZEOF___INT64@ + +/* Define to 1 if the stack grows down. */ +#define STACK_GROWS_DOWN 1 + +/* Define to 1 if the stack grows up. */ +/* #undef STACK_GROWS_UP */ + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to 1 if you can safely include both and . */ +#define TIME_WITH_SYS_TIME 1 + +/* Define to 1 to indicate that the generated build version header is present */ +#define HAVE_COMMON_NCBI_BUILD_VER_H 1 + +/* Define to 1 if using a local copy of bzlib. */ +#cmakedefine USE_LOCAL_BZLIB 1 + +/* Define to 1 if using a local copy of PCRE. */ +#cmakedefine USE_LOCAL_PCRE 1 + +/* Define to 1 if your processor stores words with the most significant byte + first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to 1 if the X Window System is missing or not being used. */ +/* #undef X_DISPLAY_MISSING */ + +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE 1 +# define __USE_GNU +#endif + +/* Define to 1 if type `char' is unsigned and you are not using gcc. */ +#ifndef __CHAR_UNSIGNED__ +/* # undef __CHAR_UNSIGNED__ */ +#endif + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `unsigned' if does not define. */ +/* #undef size_t */ + diff --git a/c++/src/build-system/cmake/configure-custom.sh b/c++/src/build-system/cmake/configure-custom.sh new file mode 100755 index 00000000..56efb8f2 --- /dev/null +++ b/c++/src/build-system/cmake/configure-custom.sh @@ -0,0 +1,42 @@ +#!/bin/sh + +WITH_VARS="libsxslt|DIR gnutls|DIR boost|DIR libxlsxwriter|DIR z|DIR bz2|dir lzo|DIR samtools|DIR glpk|DIR curl|dir sge|DIR +Python|DIR +opengl|DIR mesa|DIR glew|DIR odbc|DIR +mimetic|DIR gsoap|DIR Sybase|DIR" + +WITH_LIBXSLT_DOC="use libexslt installation in DIR" +WITH_GNUTLS_DOC="use GNUTLS installation in DIR" #- +WITH_BOOST_DOC="use Boost installation in DIR" +WITH_LIBXLSXWRITER_DOC="use libxlsxwriter installation in DIR" +WITH_Z_DOC="use zlib installation in DIR" #- +WITH_BZ2_DOC="use bzlib installation in DIR" #- +WITH_LZO_DOC="use LZO installation in DIR (requires 2.x or up)" #- +WITH_SAMTOOLS_DOC="use SAMtools installation in DIR" +WITH_GLPK_DOC="use GNU Linear Programming Kit installation in DIR" +WITH_CURL_DOC="use libcurl installation in DIR" #- +WITH_SGE_DOC="use Sun/Univa Grid Engine installation in DIR" +WITH_OPENGL_DOC="use OpenGL installation in DIR" +WITH_MESA_DOC="use MESA installation in DIR" +WITH_GLEW_DOC="use GLEW installation in DIR" + +WITH_MIMETIC_DOC="use libmimetic installation in DIR" +WITH_GSOAP_DOC="use gSOAP++ installation in DIR" + +#WITHOUT_VARS="libsxslt gnutls boost libxlsxwriter z bz2 lzo" +WITHOUT_LIBXSLT_DOC="don not use libxslt" +WITHOUT_BOOST_DOC="don not use Boost" +WITHOUT_LIBXLSXWRITER_DOC="don not use libxlsxwriter" +WITHOUT_Z_DOC="use internal copy of zlib" +WIHTOUT_BZ2_DOC="use internal copy of bzlib" +WIHTOUT_LZO_DOC="don not use LZO" +WITH_SAMTOOLS_DOC="do not use SAMtools" +WITHOUT_GLPK_DOC="do not use GNU Linear Programming Kit" +WIHTOUT_CURL_DOC="do not use libcurl" +WITHOUT_SGE_DOC="do not use Sun/Univa Grid Engine" +WITHOUT_OPENGL_DOC="do not use OpenGL" +WITHOUT_MESA_DOC="do not use MESA off-screen OpenGL" +WITHOUT_GLEW_DOC="do not use GLEW" + +WITHOUT_MIMETIC_DOC="do not use libmimetic" +WITHOUT_GSOAP_DOC="don not use gSOAP++" diff --git a/c++/src/build-system/cmake/ncbi-defaults/ncbi-berkeleydb-config.cmake b/c++/src/build-system/cmake/ncbi-defaults/ncbi-berkeleydb-config.cmake new file mode 100644 index 00000000..c92ba85f --- /dev/null +++ b/c++/src/build-system/cmake/ncbi-defaults/ncbi-berkeleydb-config.cmake @@ -0,0 +1,66 @@ +# Config file for NCBI-specific libxml layout +# + +############################################################################# +## +## Standard boilerplate capturing NCBI library layout issues +## + +if (BUILD_SHARED_LIBS) + set(_NCBI_LIBRARY_SUFFIX .so) +else() + set(_NCBI_LIBRARY_SUFFIX -static.a) +endif() + + +############################################################################# +## +## Module-specific checks +## + +set(_BDB_VERSION "BerkeleyDB-4.6.21.1") + +get_filename_component(BerkeleyDB_CMAKE_DIR "$ENV{NCBI}/${_BDB_VERSION}" REALPATH) +string(REGEX REPLACE ".*-([0-9].*)" "\\1" BerkeleyDB_VERSION_STRING "${BerkeleyDB_CMAKE_DIR}") + +set(BerkeleyDB_FOUND True) +set(BERKELEYDB_INCLUDE_DIR + ${BerkeleyDB_CMAKE_DIR}/include + ) + + +if (CMAKE_BUILD_TYPE STREQUAL "Debug") + + set(BERKELEYDB_LIBRARY + ${BerkeleyDB_CMAKE_DIR}/${CMAKE_BUILD_TYPE}MT64/libdb${_NCBI_LIBRARY_SUFFIX} + ) + set(BERKELEYDB_LIBRARIES + -Wl,-rpath,${BerkeleyDB_CMAKE_DIR}/${CMAKE_BUILD_TYPE}MT64 ${BERKELEYDB_LIBRARY} + ) + +else() + # release-mode binaries are in /opt + + set(BERKELEYDB_LIBRARY + ${BerkeleyDB_CMAKE_DIR}/${CMAKE_BUILD_TYPE}MT64/libdb${_NCBI_LIBRARY_SUFFIX} + ) + set(BERKELEYDB_LIBRARIES + -Wl,-rpath,/opt/ncbi/64/${_BDB_VERSION}/${CMAKE_BUILD_TYPE}MT64 ${BERKELEYDB_LIBRARY} + ) +endif() + + +############################################################################# +## +## Logging +## + +set(BerkeleyDB_LIBRARIES ${BERKELEYDB_LIBRARY}) + +if (_NCBI_MODULE_DEBUG) + message(STATUS "BerkeleyDB (NCBI): FOUND = ${BerkeleyDB_FOUND}") + message(STATUS "BerkeleyDB (NCBI): VERSION = ${BerkeleyDB_VERSION_STRING}") + message(STATUS "BerkeleyDB (NCBI): INCLUDE = ${BERKELEYDB_INCLUDE_DIR}") + message(STATUS "BerkeleyDB (NCBI): LIBRARIES = ${BERKELEYDB_LIBRARY}") +endif() + diff --git a/c++/src/build-system/cmake/ncbi-defaults/ncbi-ftgl-config.cmake b/c++/src/build-system/cmake/ncbi-defaults/ncbi-ftgl-config.cmake new file mode 100644 index 00000000..11ebc229 --- /dev/null +++ b/c++/src/build-system/cmake/ncbi-defaults/ncbi-ftgl-config.cmake @@ -0,0 +1,43 @@ +# Config file for NCBI-specific libxml layout +# + +############################################################################# +## +## Standard boilerplate capturing NCBI library layout issues +## + +if (BUILD_SHARED_LIBS) + set(_NCBI_LIBRARY_SUFFIX .so) +else() + set(_NCBI_LIBRARY_SUFFIX -static.a) +endif() + + +############################################################################# +## +## Module-specific checks +## + +get_filename_component(FTGL_CMAKE_DIR "$ENV{NCBI}/ftgl-2.1.3-rc5" REALPATH) +string(REGEX REPLACE ".*-([0-9].*)" "\\1" FTGL_VERSION_STRING "${FTGL_CMAKE_DIR}") + +set(FTGL_FOUND True) +set(FTGL_INCLUDE_DIR + ${FTGL_CMAKE_DIR}/include + ) + +set(FTGL_LIBRARIES + ${FTGL_CMAKE_DIR}/${CMAKE_BUILD_TYPE}64/lib/libftgl${_NCBI_LIBRARY_SUFFIX} + ) + +############################################################################# +## +## Logging +## + +if (_NCBI_MODULE_DEBUG) + message(STATUS "FTGL (NCBI): FOUND = ${FTGL_FOUND}") + message(STATUS "FTGL (NCBI): INCLUDE = ${FTGL_INCLUDE_DIR}") + message(STATUS "FTGL (NCBI): LIBRARIES = ${FTGL_LIBRARIES}") +endif() + diff --git a/c++/src/build-system/cmake/ncbi-defaults/ncbi-glew-config.cmake b/c++/src/build-system/cmake/ncbi-defaults/ncbi-glew-config.cmake new file mode 100644 index 00000000..c6a82c67 --- /dev/null +++ b/c++/src/build-system/cmake/ncbi-defaults/ncbi-glew-config.cmake @@ -0,0 +1,44 @@ +# Config file for NCBI-specific libxml layout +# + +############################################################################# +## +## Standard boilerplate capturing NCBI library layout issues +## + +if (BUILD_SHARED_LIBS) + set(_NCBI_LIBRARY_SUFFIX .so) +else() + set(_NCBI_LIBRARY_SUFFIX -static.a) +endif() + + +############################################################################# +## +## Module-specific checks +## + +get_filename_component(GLEW_CMAKE_DIR "$ENV{NCBI}/glew" REALPATH) +string(REGEX REPLACE ".*-([0-9].*)" "\\1" GLEW_VERSION_STRING "${GLEW_CMAKE_DIR}") + +set(GLEW_FOUND True) +set(GLEW_INCLUDE_DIRS + ${GLEW_CMAKE_DIR}/include + ) + +set(GLEW_LIBRARIES + ${GLEW_CMAKE_DIR}/${CMAKE_BUILD_TYPE}/lib/libGLEW${_NCBI_LIBRARY_SUFFIX} + ) + + +############################################################################# +## +## Logging +## + +if (_NCBI_MODULE_DEBUG) + message(STATUS "GLEW (NCBI): FOUND = ${GLEW_FOUND}") + message(STATUS "GLEW (NCBI): INCLUDE = ${GLEW_INCLUDE_DIRS}") + message(STATUS "GLEW (NCBI): LIBRARIES = ${GLEW_LIBRARIES}") +endif() + diff --git a/c++/src/build-system/cmake/ncbi-defaults/ncbi-gnutls-config.cmake b/c++/src/build-system/cmake/ncbi-defaults/ncbi-gnutls-config.cmake new file mode 100644 index 00000000..7aa69619 --- /dev/null +++ b/c++/src/build-system/cmake/ncbi-defaults/ncbi-gnutls-config.cmake @@ -0,0 +1,48 @@ +# Config file for NCBI-specific libxml layout +# + +############################################################################# +## +## Standard boilerplate capturing NCBI library layout issues +## + +if (BUILD_SHARED_LIBS) + set(_NCBI_LIBRARY_SUFFIX .a) +else() + set(_NCBI_LIBRARY_SUFFIX -static.a) +endif() + + +############################################################################# +## +## Module-specific checks +## + +get_filename_component(GnuTLS_CMAKE_DIR "$ENV{NCBI}/gnutls-3.4.0" REALPATH) +string(REGEX REPLACE ".*-([0-9].*)" "\\1" GnuTLS_VERSION_STRING "${GnuTLS_CMAKE_DIR}") + +set(GNUTLS_FOUND True) +set(GNUTLS_INCLUDE_DIR + ${GnuTLS_CMAKE_DIR}/include + ) + +set(GNUTLS_LIBRARIES + ${GnuTLS_CMAKE_DIR}/${CMAKE_BUILD_TYPE}64MT/lib/libgnutls${_NCBI_LIBRARY_SUFFIX} + ) + + +############################################################################# +## +## Logging +## + +set(GnuTLS_LIBRARIES ${GNUTLS_LIBRARIES}) + +if (_NCBI_MODULE_DEBUG) + message(STATUS "GnuTLS (NCBI): FOUND = ${GNUTLS_FOUND}") + message(STATUS "GnuTLS (NCBI): DIRECTORY = ${GnuTLS_CMAKE_DIR}") + message(STATUS "GnuTLS (NCBI): VERSION = ${GnuTLS_VERSION_STRING}") + message(STATUS "GnuTLS (NCBI): INCLUDE = ${GNUTLS_INCLUDE_DIR}") + message(STATUS "GnuTLS (NCBI): LIBRARIES = ${GNUTLS_LIBRARIES}") +endif() + diff --git a/c++/src/build-system/cmake/ncbi-defaults/ncbi-libxml2-config.cmake b/c++/src/build-system/cmake/ncbi-defaults/ncbi-libxml2-config.cmake new file mode 100644 index 00000000..6ee2f48e --- /dev/null +++ b/c++/src/build-system/cmake/ncbi-defaults/ncbi-libxml2-config.cmake @@ -0,0 +1,54 @@ +# Config file for NCBI-specific libxml layout +# + +############################################################################# +## +## Standard boilerplate capturing NCBI library layout issues +## + +if (BUILD_SHARED_LIBS) + set(_NCBI_LIBRARY_SUFFIX .so) +else() + set(_NCBI_LIBRARY_SUFFIX -static.a) +endif() + + +############################################################################# +## +## Module-specific checks +## + +get_filename_component(LibXml2_CMAKE_DIR "$ENV{NCBI}/libxml-2.7.8" REALPATH) +string(REGEX REPLACE ".*-([0-9].*)" "\\1" LIBXML2_VERSION_STRING "${LibXml2_CMAKE_DIR}") + +set(LIBXML2_FOUND True) +set(LIBXML2_INCLUDE_DIR + ${LibXml2_CMAKE_DIR}/include/libxml2 + ) + +set(LIBXML2_LIBRARIES + ${LibXml2_CMAKE_DIR}/${CMAKE_BUILD_TYPE}64MT/lib/libxml2${_NCBI_LIBRARY_SUFFIX} + ) +set(LIBXML2_DEFINITIONS + ) +set(LIBXML2_XMLLINT_EXECUTABLE + ${LibXml2_CMAKE_DIR}/${CMAKE_BUILD_TYPE}64MT/bin/xmllint + ) + +############################################################################# +## +## Logging +## + +set(LibXml2_VERSION_STRING ${LIBXML2_VERSION_STRING}) +set(LibXml2_LIBRARIES ${LIBXML2_LIBRARIES}) + +if (_NCBI_MODULE_DEBUG) + message(STATUS "LibXml2 (NCBI): FOUND = ${LIBXML2_FOUND}") + message(STATUS "LibXml2 (NCBI): INCLUDE = ${LIBXML2_INCLUDE_DIR}") + message(STATUS "LibXml2 (NCBI): LIBRARIES = ${LIBXML2_LIBRARIES}") + message(STATUS "LibXml2 (NCBI): DEFINITIONS = ${LIBXML2_DEFINITIONS}") + message(STATUS "LibXml2 (NCBI): XMLLINT = ${LIBXML2_XMLLINT_EXECUTABLE}") + message(STATUS "LibXml2 (NCBI): VERSION = ${LIBXML2_VERSION_STRING}") +endif() + diff --git a/c++/src/build-system/cmake/ncbi-defaults/ncbi-libxslt-config.cmake b/c++/src/build-system/cmake/ncbi-defaults/ncbi-libxslt-config.cmake new file mode 100644 index 00000000..8d81df6c --- /dev/null +++ b/c++/src/build-system/cmake/ncbi-defaults/ncbi-libxslt-config.cmake @@ -0,0 +1,57 @@ +# Config file for NCBI-specific libxml layout +# + +############################################################################# +## +## Standard boilerplate capturing NCBI library layout issues +## + +if (BUILD_SHARED_LIBS) + set(_NCBI_LIBRARY_SUFFIX .so) +else() + set(_NCBI_LIBRARY_SUFFIX -static.a) +endif() + + +############################################################################# +## +## Module-specific checks +## + +get_filename_component(LibXslt_CMAKE_DIR "$ENV{NCBI}/libxml-2.7.8" REALPATH) +string(REGEX REPLACE ".*-([0-9].*)" "\\1" LibXslt_VERSION_STRING "${LibXslt_CMAKE_DIR}") + +set(LIBXSLT_FOUND True) +set(LIBXSLT_INCLUDE_DIR + ${LibXslt_CMAKE_DIR}/include/libxslt + ) + +set(LIBXSLT_LIBRARIES + ${LibXslt_CMAKE_DIR}/${CMAKE_BUILD_TYPE}64MT/lib/libxslt${_NCBI_LIBRARY_SUFFIX} + ) +set(LIBXSLT_DEFINITIONS + ) +set(LIBXSLT_XSLTPROC_EXECUTABLE + ${LibXslt_CMAKE_DIR}/${CMAKE_BUILD_TYPE}64MT/bin/xsltproc + ) +set(LIBXSLT_EXSLT_LIBRARIES + ${LibXslt_CMAKE_DIR}/${CMAKE_BUILD_TYPE}64MT/lib/libexslt${_NCBI_LIBRARY_SUFFIX} + ) + +############################################################################# +## +## Logging +## + +set(LIBXSLT_VERSION_STRING ${LibXslt_VERSION_STRING}) +set(LibXslt_LIBRARIES ${LIBXSLT_LIBRARIES}) + +if (_NCBI_MODULE_DEBUG) + message(STATUS "LibXslt (NCBI): FOUND = ${LIBXSLT_FOUND}") + message(STATUS "LibXslt (NCBI): INCLUDE = ${LIBXSLT_INCLUDE_DIR}") + message(STATUS "LibXslt (NCBI): LIBRARIES = ${LIBXSLT_LIBRARIES}") + message(STATUS "LibXslt (NCBI): DEFINITIONS = ${LIBXSLT_DEFINITIONS}") + message(STATUS "LibXslt (NCBI): XSLTPROC = ${LIBXSLT_XSLTPROC_EXECUTABLE}") + message(STATUS "LibXslt (NCBI): VERSION = ${LIBXSLT_VERSION_STRING}") +endif() + diff --git a/c++/src/build-system/cmake/ncbi-defaults/ncbi-lzo-config.cmake b/c++/src/build-system/cmake/ncbi-defaults/ncbi-lzo-config.cmake new file mode 100644 index 00000000..77a16a9e --- /dev/null +++ b/c++/src/build-system/cmake/ncbi-defaults/ncbi-lzo-config.cmake @@ -0,0 +1,44 @@ +# Config file for NCBI-specific libxml layout +# + +############################################################################# +## +## Standard boilerplate capturing NCBI library layout issues +## + +if (BUILD_SHARED_LIBS) + set(_NCBI_LIBRARY_SUFFIX -dll.so) +else() + set(_NCBI_LIBRARY_SUFFIX -static.a) +endif() + + +############################################################################# +## +## Module-specific checks +## + +get_filename_component(LZO_CMAKE_DIR "$ENV{NCBI}/lzo-2.05" REALPATH) +string(REGEX REPLACE ".*-([0-9].*)" "\\1" LZO_VERSION_STRING "${LZO_CMAKE_DIR}") + +set(LZO_FOUND True) +set(LZO_INCLUDE_DIR + ${LZO_CMAKE_DIR}/include + ) + +set(LZO_LIBRARIES + ${LZO_CMAKE_DIR}/lib/liblzo2${_NCBI_LIBRARY_SUFFIX} + ) + + +############################################################################# +## +## Logging +## + +if (_NCBI_MODULE_DEBUG) + message(STATUS "LZO (NCBI): FOUND = ${LZO_FOUND}") + message(STATUS "LZO (NCBI): INCLUDE = ${LZO_INCLUDE_DIR}") + message(STATUS "LZO (NCBI): LIBRARIES = ${LZO_LIBRARIES}") +endif() + diff --git a/c++/src/build-system/cmake/ncbi-defaults/ncbi-opengl-config.cmake b/c++/src/build-system/cmake/ncbi-defaults/ncbi-opengl-config.cmake new file mode 100644 index 00000000..4f01c6ca --- /dev/null +++ b/c++/src/build-system/cmake/ncbi-defaults/ncbi-opengl-config.cmake @@ -0,0 +1,55 @@ +# Config file for NCBI-specific libxml layout +# + +############################################################################# +## +## Standard boilerplate capturing NCBI library layout issues +## + +if (BUILD_SHARED_LIBS) + set(_NCBI_LIBRARY_SUFFIX .so) +else() + set(_NCBI_LIBRARY_SUFFIX -static.a) +endif() + + +############################################################################# +## +## Module-specific checks +## + +get_filename_component(OpenGL_CMAKE_DIR "$ENV{NCBI}/MesaGL" REALPATH) +string(REGEX REPLACE ".*-([0-9].*)" "\\1" OpenGL_VERSION_STRING "${OpenGL_CMAKE_DIR}") + +set(OPENGL_FOUND True) +set(OPENGL_GLU_FOUND True) +set(OPENGL_INCLUDE_DIR + ${OpenGL_CMAKE_DIR}/include + ) + +set(OPENGL_glu_LIBRARIES + ${OpenGL_CMAKE_DIR}/lib/libGLU${_NCBI_LIBRARY_SUFFIX} + ) +set(OPENGL_gl_LIBRARIES + ${OpenGL_CMAKE_DIR}/lib/libGL${_NCBI_LIBRARY_SUFFIX} + ) +set(OPENGL_LIBRARIES + ${OPENGL_glu_LIBRARIES} + ${OPENGL_gl_LIBRARIES} + -lXmu -lXt -lXext -lSM -lICE -lX11 + ) + + +############################################################################# +## +## Logging +## + +set(OpenGL_LIBRARIES ${OPENGL_LIBRARIES}) + +if (_NCBI_MODULE_DEBUG) + message(STATUS "OpenGL (NCBI): FOUND = ${OPENGL_FOUND}") + message(STATUS "OpenGL (NCBI): INCLUDE = ${OPENGL_INCLUDE_DIR}") + message(STATUS "OpenGL (NCBI): LIBRARIES = ${OPENGL_LIBRARIES}") +endif() + diff --git a/c++/src/build-system/cmake/ncbi-defaults/ncbi-osmesa-config.cmake b/c++/src/build-system/cmake/ncbi-defaults/ncbi-osmesa-config.cmake new file mode 100644 index 00000000..69fb6f22 --- /dev/null +++ b/c++/src/build-system/cmake/ncbi-defaults/ncbi-osmesa-config.cmake @@ -0,0 +1,44 @@ +# Config file for NCBI-specific libxml layout +# + +############################################################################# +## +## Standard boilerplate capturing NCBI library layout issues +## + +if (BUILD_SHARED_LIBS) + set(_NCBI_LIBRARY_SUFFIX .so) +else() + set(_NCBI_LIBRARY_SUFFIX -static.a) +endif() + + +############################################################################# +## +## Module-specific checks +## + +get_filename_component(OSMesa_CMAKE_DIR "$ENV{NCBI}/MesaGL" REALPATH) +string(REGEX REPLACE ".*-([0-9].*)" "\\1" OSMesa_VERSION_STRING "${OSMesa_CMAKE_DIR}") + +set(OSMesa_FOUND True) +set(OSMesa_INCLUDE_DIR + ${OSMesa_CMAKE_DIR}/include + ) + +set(OSMesa_LIBRARIES + ${OSMesa_CMAKE_DIR}/lib/libOSMesa${_NCBI_LIBRARY_SUFFIX} + ) + + +############################################################################# +## +## Logging +## + +if (_NCBI_MODULE_DEBUG) + message(STATUS "OSMesa (NCBI): FOUND = ${OSMesa_FOUND}") + message(STATUS "OSMesa (NCBI): INCLUDE = ${OSMesa_INCLUDE_DIR}") + message(STATUS "OSMesa (NCBI): LIBRARIES = ${OSMesa_LIBRARIES}") +endif() + diff --git a/c++/src/build-system/cmake/ncbiconf_msvc_site.h.in b/c++/src/build-system/cmake/ncbiconf_msvc_site.h.in new file mode 100644 index 00000000..76f3222f --- /dev/null +++ b/c++/src/build-system/cmake/ncbiconf_msvc_site.h.in @@ -0,0 +1,46 @@ +#define HAVE_BDB 1 +#define HAVE_BDB_CACHE 1 +#define HAVE_BERKELEY_DB 1 +#define HAVE_BOOST_SPIRIT 1 +#define HAVE_BOOST_TEST 1 +#define HAVE_FCGX_ACCEPT_R 1 +#define HAVE_FREETYPE 1 +/* #undef HAVE_ICU */ +#define HAVE_LIBCONNEXT 1 +#define HAVE_LIBEXSLT 1 +#define HAVE_LIBFASTCGI 1 +#define HAVE_LIBFTGL 1 +#define HAVE_LIBGIF 1 +#define HAVE_LIBGLEW 1 +#define HAVE_LIBGNUTLS 1 +#define HAVE_LIBJPEG 1 +#define HAVE_LIBLMDB 1 +#define HAVE_LIBLZO 1 +#define HAVE_LIBMIMETIC 1 +/* #undef HAVE_LIBMONGODB */ +/* #undef HAVE_LIBMUPARSER */ +#define HAVE_LIBOPENSSL 1 +#define HAVE_LIBPNG 1 +#define HAVE_LIBSQLITE3 1 +#define HAVE_LIBSYBASE 1 +#define HAVE_LIBTIFF 1 +#define HAVE_LIBXML 1 +#define HAVE_LIBXSLT 1 +/* #undef HAVE_LOCAL_LBSM */ +#define HAVE_NCBI_VDB 1 +#define HAVE_ODBC 1 +#define HAVE_ODBCSS_H 1 +#define HAVE_OPENGL 1 +#define HAVE_PUBSEQ_OS 1 +/* #undef HAVE_PYTHON */ +#define HAVE_SQLITE3ASYNC_H 1 +#define HAVE_SQLITE3_UNLOCK_NOTIFY 1 +/* #undef HAVE_SWIG */ +#define HAVE_XALAN 1 +#define HAVE_XERCES 1 +/* #undef NCBI_INT8_GI */ +/* #undef NCBI_JNI */ +/* #undef USE_LOCAL_BZLIB */ +/* #undef USE_LOCAL_PCRE */ +/* #undef USE_LOCAL_ZLIB */ + diff --git a/c++/src/build-system/config.h.in b/c++/src/build-system/config.h.in index ff0e35b8..481b6a75 100644 --- a/c++/src/build-system/config.h.in +++ b/c++/src/build-system/config.h.in @@ -83,6 +83,12 @@ /* Define to 1 if you have the header file. */ #undef HAVE_CPUID_H +/* Define to 1 if `abi::__cxa_demangle' is available from . */ +#undef HAVE_CXA_DEMANGLE + +/* Define to 1 if you have the header file. */ +#undef HAVE_CXXABI_H + /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H @@ -227,6 +233,9 @@ /* Define to 1 if libbz2 is available. */ #undef HAVE_LIBBZ2 +/* Define to 1 if libcassandra is available. */ +#undef HAVE_LIBCASSANDRA + /* Define to 1 if non-public CONNECT extensions are available. */ #undef HAVE_LIBCONNEXT @@ -285,6 +294,9 @@ /* Define to 1 if libgnutls is available. */ #undef HAVE_LIBGNUTLS +/* Define to 1 if libgrpc++ is available. */ +#undef HAVE_LIBGRPC + /* Define to 1 if libgsoapssl++ is available. */ #undef HAVE_LIBGSOAP @@ -317,12 +329,18 @@ /* Define to 1 if libmagic is available. */ #undef HAVE_LIBMAGIC +/* Define to 1 if libmbedtls is available. */ +#undef HAVE_LIBMBEDTLS + /* Define to 1 if libmimetic is available. */ #undef HAVE_LIBMIMETIC /* Define to 1 if libmongoclient is available. */ #undef HAVE_LIBMONGODB +/* Define to 1 if libmongocxx is available. */ +#undef HAVE_LIBMONGODB3 + /* Define to 1 if libmuparser is available. */ #undef HAVE_LIBMUPARSER @@ -367,6 +385,9 @@ /* Define to 1 if libsqlite3 is available. */ #undef HAVE_LIBSQLITE3 +/* Define to 1 if libssh2 is available. */ +#undef HAVE_LIBSSH2 + /* Define to 1 if the NCBI SSS DB library is available. */ #undef HAVE_LIBSSSDB @@ -385,6 +406,15 @@ /* Define to 1 if libungif is available. */ #undef HAVE_LIBUNGIF +/* Define to 1 if libunwind is available. */ +#undef HAVE_LIBUNWIND + +/* Define to 1 if libuv is available. */ +#undef HAVE_LIBUV + +/* Define to 1 if libxlsxwriter is available. */ +#undef HAVE_LIBXLSXWRITER + /* Define to 1 if libxml2 is available. */ #undef HAVE_LIBXML @@ -448,18 +478,6 @@ /* Define to 1 if you have the header file. */ #undef HAVE_NETINET_TCP_H -/* Define to 1 if `auto_ptr' is missing or broken. */ -#undef HAVE_NO_AUTO_PTR - -/* Define to 1 if `std::char_traits' is missing. */ -#undef HAVE_NO_CHAR_TRAITS - -/* Define to 1 if new C++ streams lack `ios_base::'. */ -#undef HAVE_NO_IOS_BASE - -/* Define to 1 if `min'/`max' templates are not implemented. */ -#undef HAVE_NO_MINMAX_TEMPLATE - /* Define to 1 if ODBC libraries are available. */ #undef HAVE_ODBC @@ -603,6 +621,9 @@ /* Define to 1 if you have the `strndup' function. */ #undef HAVE_STRNDUP +/* Define to 1 if you have the `strnlen' function. */ +#undef HAVE_STRNLEN + /* Define to 1 if you have the `strsep' function. */ #undef HAVE_STRSEP @@ -835,9 +856,6 @@ functions that never return. */ #undef NCBI_NORETURN -/* Define to 1 if `string::compare()' is non-standard. */ -#undef NCBI_OBSOLETE_STR_COMPARE - /* Operating system name */ #undef NCBI_OS @@ -972,6 +990,9 @@ /* Define to 1 if using a local copy of bzlib. */ #undef USE_LOCAL_BZLIB +/* Define to 1 if using a local copy of LMDB. */ +#undef USE_LOCAL_LMDB + /* Define to 1 if using a local copy of PCRE. */ #undef USE_LOCAL_PCRE diff --git a/c++/src/build-system/configure b/c++/src/build-system/configure index b5294eae..ba006d1f 100755 --- a/c++/src/build-system/configure +++ b/c++/src/build-system/configure @@ -708,9 +708,13 @@ GREP EGREP VALGRIND_PATH LDD +UUIDGEN +CD_REPORTER CXXCPP TCHECK_CL AMQ +LIBUNWIND_INCLUDE +LIBUNWIND_LIBS Z_INCLUDE Z_LIBS BZ2_INCLUDE @@ -719,6 +723,8 @@ LZO_INCLUDE LZO_LIBS PCRE_INCLUDE PCRE_LIBS +MBEDTLS_INCLUDE +MBEDTLS_LIBS GMP_INCLUDE GMP_LIBS LIBGCRYPT_CONFIG @@ -803,10 +809,10 @@ PNG_INCLUDE PNG_LIBS TIFF_INCLUDE TIFF_LIBS -UNGIF_INCLUDE -UNGIF_LIBS GIF_INCLUDE GIF_LIBS +UNGIF_INCLUDE +UNGIF_LIBS XPM_INCLUDE XPM_LIBS freetype_config @@ -827,12 +833,24 @@ SASL2_INCLUDE SASL2_LIBS MONGODB_INCLUDE MONGODB_LIBS +MONGODB3_INCLUDE +MONGODB3_LIBS GMOCK_INCLUDE GMOCK_LIBS LAPACK_INCLUDE LAPACK_LIBS LMDB_INCLUDE LMDB_LIBS +LIBUV_INCLUDE +LIBUV_LIBS +LIBSSH2_INCLUDE +LIBSSH2_LIBS +CASSANDRA_INCLUDE +CASSANDRA_LIBS +LIBXLSXWRITER_INCLUDE +LIBXLSXWRITER_LIBS +GRPC_INCLUDE +GRPC_LIBS signature build_root top_srcdir @@ -873,6 +891,10 @@ CFLAGS_DLL CXXFLAGS_DLL ALLOW_UNDEF FORBID_UNDEF +AS_NEEDED +NO_AS_NEEDED +WHOLE_ARCHIVE +NO_WHOLE_ARCHIVE OPT_GROUPS local_lbsm ncbi_crypt @@ -910,6 +932,7 @@ f_runpath f_outexe BDB_LIB BDB_CACHE_LIB +SQLITE3_WRAPPER DBAPI_DRIVER DBAPI_CTLIB DBAPI_DBLIB @@ -942,8 +965,6 @@ BZ2_LIB PCREPOSIX_LIBS PCRE_LIB OPENSSL_STATIC_LIBS -TLS_INCLUDE -TLS_LIBS SYBASE_PATH SYBASE_LCL_PATH SYBASE_INCLUDE @@ -1053,6 +1074,15 @@ GSOAP_PATH AVRO_STATIC_LIBS CEREAL_INCLUDE MONGODB_STATIC_LIBS +MONGODB3_STATIC_LIBS +LMDB_LIB +LIBUV_STATIC_LIBS +LIBSSH2_STATIC_LIBS +CASSANDRA_STATIC_LIBS +LIBXLSXWRITER_STATIC_LIBS +GRPC_UNSECURE_LIBS +GRPC_REFLECTION_LIBS +GRPC_BIN ncbi_xreader_pubseqos ncbi_xreader_pubseqos2 UNLESS_PUBSEQOS @@ -1090,6 +1120,8 @@ COMPILER OSTYPE NCBI_PLATFORM_BITS NCBI_TEAMCITY_BUILD_NUMBER +NCBI_TEAMCITY_PROJECT_NAME +NCBI_TEAMCITY_BUILDCONF_NAME NCBI_SUBVERSION_REVISION NCBI_SC_VERSION LIBOBJS @@ -1606,22 +1638,24 @@ esac #### Check the passed arguments against the list of available ones x_with_list="\ -debug max-debug symbols optimization profiling tcheck dll static static-exe \ +debug max-debug symbols optimization profiling code-coverage \ +tcheck dll static static-exe \ plugin-auto-load bundles bin-release mt 64 exe runpath hard-runpath \ lfs limited-linker openmp \ autodep suffix hostspec version execopy bincopy lib-rebuilds lib-rebuilds=ask \ deactivation makefile-auto-update projects flat-makefile configure-dialog \ check ncbi-public strip pch caution ccache distcc \ ncbi-c wxwidgets wxwidgets-ucs fastcgi sss sssdb sssutils included-sss \ -geo included-geo vdb downloaded-vdb static-vdb \ -z bz2 lzo pcre gmp gcrypt nettle gnutls static-gnutls openssl krb5 \ +geo included-geo vdb downloaded-vdb static-vdb libunwind \ +z bz2 lzo pcre mbedtls gmp gcrypt nettle gnutls static-gnutls openssl krb5 \ sybase sybase-local sybase-new ftds mysql \ orbacus freetype ftgl opengl mesa glut glew glew-mx \ bdb python perl jni sqlite3 icu boost boost-tag \ sp expat sablot libxml libxslt libexslt xerces xalan zorba \ oechem sge muparser hdf5 \ gif jpeg tiff png xpm \ -magic curl mimetic gsoap avro cereal sasl2 mongodb gmock lapack lmdb 3psw \ +magic curl mimetic gsoap avro cereal sasl2 mongodb mongodb3 gmock lapack lmdb \ +libuv libssh2 cassandra libxlsxwriter grpc 3psw \ local-lbsm ncbi-crypt connext \ serial objects dbapi app ctools gui algo internal gbench" @@ -1675,8 +1709,9 @@ for x_arg in "$@" ; do --with-vdb=rc ) ;; --srcdir=* | --x-includes=* | --x-libraries=* | --with-tcheck=* \ - | --with-ncbi-c=* | --with-sss=* | --with-vdb=* | --with-z=* \ - | --with-bz2=* | --with-lzo=* | --with-pcre=* \ + | --with-ncbi-c=* | --with-sss=* | --with-vdb=* | --with-libunwind=* \ + | --with-z=* | --with-bz2=* | --with-lzo=* \ + | --with-pcre=* | --with-mbedtls=* \ | --with-gmp=* | --with-gcrypt=* | --with-nettle=* \ | --with-gnutls=* | --with-openssl=* | --with-krb5=* \ | --with-sybase-local=* | --with-ftds=*/* | --with-mysql=* \ @@ -1690,8 +1725,11 @@ for x_arg in "$@" ; do | --with-sge=* | --with-muparser=* | --with-hdf5=* | --with-gif=* \ | --with-jpeg=* | --with-png=* | --with-tiff=* | --with-xpm=* \ | --with-magic=* | --with-curl=* | --with-mimetic=* | --with-gsoap=* \ - | --with-avro=* | --with-cereal=* | --with-sasl2* | --with-mongodb=* \ - | --with-gmock=* | --with-lapack=* | --with-lmdb=* ) + | --with-avro=* | --with-cereal=* | --with-sasl2=* \ + | --with-mongodb=* | --with-mongodb3=* \ + | --with-gmock=* | --with-lapack=* | --with-lmdb=* | --with-libuv=* \ + | --with-libssh2=* | --with-cassandra=* | --with-libxlsxwriter=* \ + | --with-grpc=* ) # Confirm that the specified directory exists and is readable. dir=`echo $x_arg | sed -e 's/^[^=]*=//'` case "$x_arg" in @@ -1715,6 +1753,8 @@ for x_arg in "$@" ; do | --silent | --cache-file=* | -C | --config-cache | -n | --no-create \ | --no-recursion | --prefix=* | --exec-prefix=* | --bindir=* \ | --libdir=* | --includedir=* | --build=* | --host=* | --target=* \ + | --mandir=* | --infodir=* | --docdir=* | --htmldir=* \ + | --datadir=* | --sysconfdir=* | --localstatedir=* \ | --with-runpath=* | --with-relative-runpath=* \ | --with-experimental=* | --with-extra-action=* | --with-build-root=* \ | --with-fake-root=* | --with-build-root-sfx=* | --with-check=* \ @@ -1825,7 +1865,9 @@ Optional Packages: --with-max-debug enable extra runtime checks (esp. of STL usage) --with-symbols retain debugging symbols in non-debug mode --without-optimization turn off optimization flags in non-debug mode + --without-sse42 don't enable SSE 4.2 when optimizing --with-profiling build profiled versions of libs and apps + --with-code-coverage track which code blocks have been exercised --with-tcheck(=DIR) build for Intel Thread Checker (in DIR) --with-dll build all libraries as DLLs --with-static build all libraries statically even if --with-dll @@ -1881,6 +1923,7 @@ Optional Packages: --without-vdb do not use the NCBI SRA/VDB Toolkit --with-downloaded-vdb download and build SRA/VDB from GitHub --with-static-vdb always link statically against SRA/VDB + --with-libunwind(=DIR) use libunwind (in DIR) --with-z=DIR use zlib installation in DIR --without-z use internal copy of zlib --with-bz2=DIR use bzlib installation in DIR @@ -1889,6 +1932,7 @@ Optional Packages: --without-lzo do not use LZO --with-pcre=DIR use PCRE installation in DIR --without-pcre use internal copy of PCRE + --with-mbedtls(=DIR) use external mbedTLS installation (in DIR) --with-gmp=DIR use GMP installation in DIR --without-gmp do not use GMP --with-gcrypt=DIR use gcrypt installation in DIR @@ -1998,26 +2042,34 @@ Optional Packages: --without-cereal do not use USC Cereal --with-sasl2=DIR use SASL 2 installation in DIR --without-sasl2 do not use SASL 2 - --with-mongodb=DIR use MongoDB installation in DIR - --without-mongodb do not use MongoDB + --with-mongodb=DIR use legacy MongoDB installation in DIR + --without-mongodb do not use legacy MongoDB + --with-mongodb3=DIR use MongoDB 3 installation in DIR + --without-mongodb3 do not use MongoDB 3 --with-gmock=DIR use Google Mock installation in DIR --without-gmock do not use Google Mock --with-lapack=DIR use LAPACK installation in DIR --without-lapack do not use LAPACK --with-lmdb=DIR use LMDB installation in DIR - --without-lmdb do not use LMDB + --without-lmdb use internal copy of LMDB + --with-libuv=DIR use libuv installation in DIR + --without-libuv do not use libuv + --with-libssh2=DIR use libssh2 installation in DIR + --without-libssh2 do not use libssh2 + --with-cassandra=DIR use Datastax Cassandra driver installation in DIR + --without-cassandra do not use Datastax Cassandra driver + --with-libxlsxwriter=DIR use libxlsxwriter installation in DIR + --without-libxlsxwriter do not use libxlsxwriter + --with-grpc=DIR use GRPC installation in DIR + --without-grpc do not use GRPC --with-3psw=std:netopt favor standard (system) builds of the above pkgs. --without-3psw do not use any of the above packages --without-local-lbsm turn off support for IPC with locally running LBSMD --without-ncbi-crypt use a dummy stubbed-out version of ncbi_crypt --without-connext do not build non-public CONNECT library extensions - --without-serial do not build the serialization library and tools - --without-objects do not generate/build serializeable objects from ASNs - --without-dbapi do not build database connectivity libraries --without-app do not build standalone applications like ID1_FETCH --without-ctools do not build NCBI C Toolkit based projects --without-gui do not build most graphical projects - --without-algo do not build CPU-intensive algorithms --with-internal always try to build internal projects --without-internal never build internal projects --with-gbench ensure that Genome Workbench can be built @@ -2199,6 +2251,12 @@ case "$with_3psw" in else with_vdb=no fi + if test "${with_libunwind-no}" != "no"; then + { echo "$as_me: error: incompatible options: --with-libunwind but --without-3psw" >&2 + { (exit 1); exit 1; }; } + else + with_libunwind=no + fi if test "${with_z-no}" != "no"; then { echo "$as_me: error: incompatible options: --with-z but --without-3psw" >&2 { (exit 1); exit 1; }; } @@ -2223,6 +2281,12 @@ case "$with_3psw" in else with_pcre=no fi + if test "${with_mbedtls-no}" != "no"; then + { echo "$as_me: error: incompatible options: --with-mbedtls but --without-3psw" >&2 + { (exit 1); exit 1; }; } + else + with_mbedtls=no + fi if test "${with_gmp-no}" != "no"; then { echo "$as_me: error: incompatible options: --with-gmp but --without-3psw" >&2 { (exit 1); exit 1; }; } @@ -2541,6 +2605,12 @@ case "$with_3psw" in else with_mongodb=no fi + if test "${with_mongodb3-no}" != "no"; then + { echo "$as_me: error: incompatible options: --with-mongodb3 but --without-3psw" >&2 + { (exit 1); exit 1; }; } + else + with_mongodb3=no + fi if test "${with_gmock-no}" != "no"; then { echo "$as_me: error: incompatible options: --with-gmock but --without-3psw" >&2 { (exit 1); exit 1; }; } @@ -2553,6 +2623,36 @@ case "$with_3psw" in else with_lapack=no fi + if test "${with_libuv-no}" != "no"; then + { echo "$as_me: error: incompatible options: --with-libuv but --without-3psw" >&2 + { (exit 1); exit 1; }; } + else + with_libuv=no + fi + if test "${with_libssh2-no}" != "no"; then + { echo "$as_me: error: incompatible options: --with-libssh2 but --without-3psw" >&2 + { (exit 1); exit 1; }; } + else + with_libssh2=no + fi + if test "${with_cassandra-no}" != "no"; then + { echo "$as_me: error: incompatible options: --with-cassandra but --without-3psw" >&2 + { (exit 1); exit 1; }; } + else + with_cassandra=no + fi + if test "${with_libxlsxwriter-no}" != "no"; then + { echo "$as_me: error: incompatible options: --with-libxlsxwriter but --without-3psw" >&2 + { (exit 1); exit 1; }; } + else + with_libxlsxwriter=no + fi + if test "${with_grpc-no}" != "no"; then + { echo "$as_me: error: incompatible options: --with-grpc but --without-3psw" >&2 + { (exit 1); exit 1; }; } + else + with_grpc=no + fi $as_unset NCBI || test "${NCBI+set}" != set || { NCBI=; export NCBI; } ;; @@ -2921,21 +3021,21 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu ## Title -# Check whether --with-title0 was given. -if test "${with_title0+set}" = set; then - withval=$with_title0; +# Check whether --with-_ was given. +if test "${with__+set}" = set; then + withval=$with__; fi -# Check whether --with-title1 was given. -if test "${with_title1+set}" = set; then - withval=$with_title1; +# Check whether --with-_ was given. +if test "${with__+set}" = set; then + withval=$with__; fi -# Check whether --with-title2 was given. -if test "${with_title2+set}" = set; then - withval=$with_title2; +# Check whether --with-_ was given. +if test "${with__+set}" = set; then + withval=$with__; fi @@ -2965,12 +3065,24 @@ if test "${with_optimization+set}" = set; then fi +# Check whether --with-sse42 was given. +if test "${with_sse42+set}" = set; then + withval=$with_sse42; +fi + + # Check whether --with-profiling was given. if test "${with_profiling+set}" = set; then withval=$with_profiling; fi +# Check whether --with-code-coverage was given. +if test "${with_code_coverage+set}" = set; then + withval=$with_code_coverage; +fi + + # Check whether --with-tcheck was given. if test "${with_tcheck+set}" = set; then withval=$with_tcheck; @@ -3141,9 +3253,9 @@ if test "${with_lib_rebuilds+set}" = set; then fi -# Check whether --with-lib-rebuilds2 was given. -if test "${with_lib_rebuilds2+set}" = set; then - withval=$with_lib_rebuilds2; +# Check whether --with-lib-rebuilds was given. +if test "${with_lib_rebuilds+set}" = set; then + withval=$with_lib_rebuilds; fi # Check whether --with-deactivation was given. @@ -3218,9 +3330,9 @@ if test "${with_caution+set}" = set; then fi -# Check whether --with-caution2 was given. -if test "${with_caution2+set}" = set; then - withval=$with_caution2; +# Check whether --with-caution was given. +if test "${with_caution+set}" = set; then + withval=$with_caution; fi @@ -3244,9 +3356,9 @@ if test "${with_ncbi_c+set}" = set; then fi -# Check whether --with-ncbi-c2 was given. -if test "${with_ncbi_c2+set}" = set; then - withval=$with_ncbi_c2; +# Check whether --with-ncbi-c was given. +if test "${with_ncbi_c+set}" = set; then + withval=$with_ncbi_c; fi @@ -3256,9 +3368,9 @@ if test "${with_sss+set}" = set; then fi -# Check whether --with-sss2 was given. -if test "${with_sss2+set}" = set; then - withval=$with_sss2; +# Check whether --with-sss was given. +if test "${with_sss+set}" = set; then + withval=$with_sss; fi @@ -3286,9 +3398,9 @@ if test "${with_vdb+set}" = set; then fi -# Check whether --with-vdb2 was given. -if test "${with_vdb2+set}" = set; then - withval=$with_vdb2; +# Check whether --with-vdb was given. +if test "${with_vdb+set}" = set; then + withval=$with_vdb; fi @@ -3306,15 +3418,21 @@ fi ## Third-party and system packages +# Check whether --with-libunwind was given. +if test "${with_libunwind+set}" = set; then + withval=$with_libunwind; +fi + + # Check whether --with-z was given. if test "${with_z+set}" = set; then withval=$with_z; fi -# Check whether --with-z2 was given. -if test "${with_z2+set}" = set; then - withval=$with_z2; +# Check whether --with-z was given. +if test "${with_z+set}" = set; then + withval=$with_z; fi @@ -3324,9 +3442,9 @@ if test "${with_bz2+set}" = set; then fi -# Check whether --with-bz2b was given. -if test "${with_bz2b+set}" = set; then - withval=$with_bz2b; +# Check whether --with-bz2 was given. +if test "${with_bz2+set}" = set; then + withval=$with_bz2; fi @@ -3336,9 +3454,9 @@ if test "${with_lzo+set}" = set; then fi -# Check whether --with-lzo_ was given. -if test "${with_lzo_+set}" = set; then - withval=$with_lzo_; +# Check whether --with-lzo was given. +if test "${with_lzo+set}" = set; then + withval=$with_lzo; fi @@ -3348,9 +3466,15 @@ if test "${with_pcre+set}" = set; then fi -# Check whether --with-pcre2 was given. -if test "${with_pcre2+set}" = set; then - withval=$with_pcre2; +# Check whether --with-pcre was given. +if test "${with_pcre+set}" = set; then + withval=$with_pcre; +fi + + +# Check whether --with-mbedtls was given. +if test "${with_mbedtls+set}" = set; then + withval=$with_mbedtls; fi @@ -3360,9 +3484,9 @@ if test "${with_gmp+set}" = set; then fi -# Check whether --with-gmp2 was given. -if test "${with_gmp2+set}" = set; then - withval=$with_gmp2; +# Check whether --with-gmp was given. +if test "${with_gmp+set}" = set; then + withval=$with_gmp; fi @@ -3372,9 +3496,9 @@ if test "${with_gcrypt+set}" = set; then fi -# Check whether --with-gcrypt2 was given. -if test "${with_gcrypt2+set}" = set; then - withval=$with_gcrypt2; +# Check whether --with-gcrypt was given. +if test "${with_gcrypt+set}" = set; then + withval=$with_gcrypt; fi @@ -3384,9 +3508,9 @@ if test "${with_nettle+set}" = set; then fi -# Check whether --with-nettle2 was given. -if test "${with_nettle2+set}" = set; then - withval=$with_nettle2; +# Check whether --with-nettle was given. +if test "${with_nettle+set}" = set; then + withval=$with_nettle; fi @@ -3396,9 +3520,9 @@ if test "${with_gnutls+set}" = set; then fi -# Check whether --with-gnutls2 was given. -if test "${with_gnutls2+set}" = set; then - withval=$with_gnutls2; +# Check whether --with-gnutls was given. +if test "${with_gnutls+set}" = set; then + withval=$with_gnutls; fi @@ -3414,9 +3538,9 @@ if test "${with_openssl+set}" = set; then fi -# Check whether --with-openssl2 was given. -if test "${with_openssl2+set}" = set; then - withval=$with_openssl2; +# Check whether --with-openssl was given. +if test "${with_openssl+set}" = set; then + withval=$with_openssl; fi @@ -3426,9 +3550,9 @@ if test "${with_krb5+set}" = set; then fi -# Check whether --with-krb5b was given. -if test "${with_krb5b+set}" = set; then - withval=$with_krb5b; +# Check whether --with-krb5 was given. +if test "${with_krb5+set}" = set; then + withval=$with_krb5; fi @@ -3456,9 +3580,9 @@ if test "${with_ftds+set}" = set; then fi -# Check whether --with-ftds2 was given. -if test "${with_ftds2+set}" = set; then - withval=$with_ftds2; +# Check whether --with-ftds was given. +if test "${with_ftds+set}" = set; then + withval=$with_ftds; fi @@ -3474,9 +3598,9 @@ if test "${with_mysql+set}" = set; then fi -# Check whether --with-mysql2 was given. -if test "${with_mysql2+set}" = set; then - withval=$with_mysql2; +# Check whether --with-mysql was given. +if test "${with_mysql+set}" = set; then + withval=$with_mysql; fi @@ -3486,9 +3610,9 @@ if test "${with_opengl+set}" = set; then fi -# Check whether --with-opengl2 was given. -if test "${with_opengl2+set}" = set; then - withval=$with_opengl2; +# Check whether --with-opengl was given. +if test "${with_opengl+set}" = set; then + withval=$with_opengl; fi @@ -3498,9 +3622,9 @@ if test "${with_mesa+set}" = set; then fi -# Check whether --with-mesa2 was given. -if test "${with_mesa2+set}" = set; then - withval=$with_mesa2; +# Check whether --with-mesa was given. +if test "${with_mesa+set}" = set; then + withval=$with_mesa; fi @@ -3510,9 +3634,9 @@ if test "${with_glut+set}" = set; then fi -# Check whether --with-glut2 was given. -if test "${with_glut2+set}" = set; then - withval=$with_glut2; +# Check whether --with-glut was given. +if test "${with_glut+set}" = set; then + withval=$with_glut; fi @@ -3522,9 +3646,9 @@ if test "${with_glew+set}" = set; then fi -# Check whether --with-glew2 was given. -if test "${with_glew2+set}" = set; then - withval=$with_glew2; +# Check whether --with-glew was given. +if test "${with_glew+set}" = set; then + withval=$with_glew; fi @@ -3540,9 +3664,9 @@ if test "${with_wxwidgets+set}" = set; then fi -# Check whether --with-wxwidgets2 was given. -if test "${with_wxwidgets2+set}" = set; then - withval=$with_wxwidgets2; +# Check whether --with-wxwidgets was given. +if test "${with_wxwidgets+set}" = set; then + withval=$with_wxwidgets; fi @@ -3552,9 +3676,9 @@ if test "${with_wxwidgets_ucs+set}" = set; then fi -# Check whether --with-wxwidgets-ucs2 was given. -if test "${with_wxwidgets_ucs2+set}" = set; then - withval=$with_wxwidgets_ucs2; +# Check whether --with-wxwidgets-ucs was given. +if test "${with_wxwidgets_ucs+set}" = set; then + withval=$with_wxwidgets_ucs; fi @@ -3564,9 +3688,9 @@ if test "${with_freetype+set}" = set; then fi -# Check whether --with-freetype_ was given. -if test "${with_freetype_+set}" = set; then - withval=$with_freetype_; +# Check whether --with-freetype was given. +if test "${with_freetype+set}" = set; then + withval=$with_freetype; fi @@ -3576,9 +3700,9 @@ if test "${with_ftgl+set}" = set; then fi -# Check whether --with-ftgl2 was given. -if test "${with_ftgl2+set}" = set; then - withval=$with_ftgl2; +# Check whether --with-ftgl was given. +if test "${with_ftgl+set}" = set; then + withval=$with_ftgl; fi @@ -3588,15 +3712,15 @@ if test "${with_fastcgi+set}" = set; then fi -# Check whether --with-fastcgi2 was given. -if test "${with_fastcgi2+set}" = set; then - withval=$with_fastcgi2; +# Check whether --with-fastcgi was given. +if test "${with_fastcgi+set}" = set; then + withval=$with_fastcgi; fi -# Check whether --with-fastcgi3 was given. -if test "${with_fastcgi3+set}" = set; then - withval=$with_fastcgi3; +# Check whether --with-fastcgi was given. +if test "${with_fastcgi+set}" = set; then + withval=$with_fastcgi; fi @@ -3630,9 +3754,9 @@ if test "${with_orbacus+set}" = set; then fi -# Check whether --with-orbacus2 was given. -if test "${with_orbacus2+set}" = set; then - withval=$with_orbacus2; +# Check whether --with-orbacus was given. +if test "${with_orbacus+set}" = set; then + withval=$with_orbacus; fi @@ -3648,9 +3772,9 @@ if test "${with_python+set}" = set; then fi -# Check whether --with-python2 was given. -if test "${with_python2+set}" = set; then - withval=$with_python2; +# Check whether --with-python was given. +if test "${with_python+set}" = set; then + withval=$with_python; fi @@ -3660,9 +3784,9 @@ if test "${with_perl+set}" = set; then fi -# Check whether --with-perl2 was given. -if test "${with_perl2+set}" = set; then - withval=$with_perl2; +# Check whether --with-perl was given. +if test "${with_perl+set}" = set; then + withval=$with_perl; fi @@ -3678,9 +3802,15 @@ if test "${with_boost+set}" = set; then fi -# Check whether --with-boost2 was given. -if test "${with_boost2+set}" = set; then - withval=$with_boost2; +# Check whether --with-boost was given. +if test "${with_boost+set}" = set; then + withval=$with_boost; +fi + + +# Check whether --with-boost-tag was given. +if test "${with_boost_tag+set}" = set; then + withval=$with_boost_tag; fi @@ -3690,9 +3820,9 @@ if test "${with_boost_tag+set}" = set; then fi -# Check whether --with-boost-tag2 was given. -if test "${with_boost_tag2+set}" = set; then - withval=$with_boost_tag2; +# Check whether --with-sqlite3 was given. +if test "${with_sqlite3+set}" = set; then + withval=$with_sqlite3; fi @@ -3702,9 +3832,9 @@ if test "${with_sqlite3+set}" = set; then fi -# Check whether --with-sqlite3b was given. -if test "${with_sqlite3b+set}" = set; then - withval=$with_sqlite3b; +# Check whether --with-icu was given. +if test "${with_icu+set}" = set; then + withval=$with_icu; fi @@ -3714,9 +3844,9 @@ if test "${with_icu+set}" = set; then fi -# Check whether --with-icu2 was given. -if test "${with_icu2+set}" = set; then - withval=$with_icu2; +# Check whether --with-expat was given. +if test "${with_expat+set}" = set; then + withval=$with_expat; fi @@ -3726,9 +3856,9 @@ if test "${with_expat+set}" = set; then fi -# Check whether --with-expat2 was given. -if test "${with_expat2+set}" = set; then - withval=$with_expat2; +# Check whether --with-sablot was given. +if test "${with_sablot+set}" = set; then + withval=$with_sablot; fi @@ -3738,9 +3868,9 @@ if test "${with_sablot+set}" = set; then fi -# Check whether --with-sablot2 was given. -if test "${with_sablot2+set}" = set; then - withval=$with_sablot2; +# Check whether --with-libxml was given. +if test "${with_libxml+set}" = set; then + withval=$with_libxml; fi @@ -3750,9 +3880,9 @@ if test "${with_libxml+set}" = set; then fi -# Check whether --with-libxml_ was given. -if test "${with_libxml_+set}" = set; then - withval=$with_libxml_; +# Check whether --with-libxslt was given. +if test "${with_libxslt+set}" = set; then + withval=$with_libxslt; fi @@ -3762,9 +3892,9 @@ if test "${with_libxslt+set}" = set; then fi -# Check whether --with-libxslt2 was given. -if test "${with_libxslt2+set}" = set; then - withval=$with_libxslt2; +# Check whether --with-libexslt was given. +if test "${with_libexslt+set}" = set; then + withval=$with_libexslt; fi @@ -3774,9 +3904,9 @@ if test "${with_libexslt+set}" = set; then fi -# Check whether --with-libexslt2 was given. -if test "${with_libexslt2+set}" = set; then - withval=$with_libexslt2; +# Check whether --with-xerces was given. +if test "${with_xerces+set}" = set; then + withval=$with_xerces; fi @@ -3786,9 +3916,9 @@ if test "${with_xerces+set}" = set; then fi -# Check whether --with-xerces2 was given. -if test "${with_xerces2+set}" = set; then - withval=$with_xerces2; +# Check whether --with-xalan was given. +if test "${with_xalan+set}" = set; then + withval=$with_xalan; fi @@ -3798,9 +3928,9 @@ if test "${with_xalan+set}" = set; then fi -# Check whether --with-xalan2 was given. -if test "${with_xalan2+set}" = set; then - withval=$with_xalan2; +# Check whether --with-zorba was given. +if test "${with_zorba+set}" = set; then + withval=$with_zorba; fi @@ -3810,9 +3940,9 @@ if test "${with_zorba+set}" = set; then fi -# Check whether --with-zorba2 was given. -if test "${with_zorba2+set}" = set; then - withval=$with_zorba2; +# Check whether --with-oechem was given. +if test "${with_oechem+set}" = set; then + withval=$with_oechem; fi @@ -3822,9 +3952,9 @@ if test "${with_oechem+set}" = set; then fi -# Check whether --with-oechem2 was given. -if test "${with_oechem2+set}" = set; then - withval=$with_oechem2; +# Check whether --with-sge was given. +if test "${with_sge+set}" = set; then + withval=$with_sge; fi @@ -3834,9 +3964,9 @@ if test "${with_sge+set}" = set; then fi -# Check whether --with-sge2 was given. -if test "${with_sge2+set}" = set; then - withval=$with_sge2; +# Check whether --with-muparser was given. +if test "${with_muparser+set}" = set; then + withval=$with_muparser; fi @@ -3846,9 +3976,9 @@ if test "${with_muparser+set}" = set; then fi -# Check whether --with-muparser2 was given. -if test "${with_muparser2+set}" = set; then - withval=$with_muparser2; +# Check whether --with-hdf5 was given. +if test "${with_hdf5+set}" = set; then + withval=$with_hdf5; fi @@ -3858,9 +3988,9 @@ if test "${with_hdf5+set}" = set; then fi -# Check whether --with-hdf5b was given. -if test "${with_hdf5b+set}" = set; then - withval=$with_hdf5b; +# Check whether --with-gif was given. +if test "${with_gif+set}" = set; then + withval=$with_gif; fi @@ -3870,9 +4000,9 @@ if test "${with_gif+set}" = set; then fi -# Check whether --with-gif2 was given. -if test "${with_gif2+set}" = set; then - withval=$with_gif2; +# Check whether --with-jpeg was given. +if test "${with_jpeg+set}" = set; then + withval=$with_jpeg; fi @@ -3882,9 +4012,9 @@ if test "${with_jpeg+set}" = set; then fi -# Check whether --with-jpeg2 was given. -if test "${with_jpeg2+set}" = set; then - withval=$with_jpeg2; +# Check whether --with-png was given. +if test "${with_png+set}" = set; then + withval=$with_png; fi @@ -3894,9 +4024,9 @@ if test "${with_png+set}" = set; then fi -# Check whether --with-png2 was given. -if test "${with_png2+set}" = set; then - withval=$with_png2; +# Check whether --with-tiff was given. +if test "${with_tiff+set}" = set; then + withval=$with_tiff; fi @@ -3906,9 +4036,9 @@ if test "${with_tiff+set}" = set; then fi -# Check whether --with-tiff2 was given. -if test "${with_tiff2+set}" = set; then - withval=$with_tiff2; +# Check whether --with-xpm was given. +if test "${with_xpm+set}" = set; then + withval=$with_xpm; fi @@ -3918,9 +4048,9 @@ if test "${with_xpm+set}" = set; then fi -# Check whether --with-xpm2 was given. -if test "${with_xpm2+set}" = set; then - withval=$with_xpm2; +# Check whether --with-magic was given. +if test "${with_magic+set}" = set; then + withval=$with_magic; fi @@ -3930,9 +4060,9 @@ if test "${with_magic+set}" = set; then fi -# Check whether --with-magic2 was given. -if test "${with_magic2+set}" = set; then - withval=$with_magic2; +# Check whether --with-curl was given. +if test "${with_curl+set}" = set; then + withval=$with_curl; fi @@ -3942,9 +4072,9 @@ if test "${with_curl+set}" = set; then fi -# Check whether --with-curl2 was given. -if test "${with_curl2+set}" = set; then - withval=$with_curl2; +# Check whether --with-mimetic was given. +if test "${with_mimetic+set}" = set; then + withval=$with_mimetic; fi @@ -3954,9 +4084,9 @@ if test "${with_mimetic+set}" = set; then fi -# Check whether --with-mimetic2 was given. -if test "${with_mimetic2+set}" = set; then - withval=$with_mimetic2; +# Check whether --with-gsoap was given. +if test "${with_gsoap+set}" = set; then + withval=$with_gsoap; fi @@ -3966,9 +4096,9 @@ if test "${with_gsoap+set}" = set; then fi -# Check whether --with-gsoap2 was given. -if test "${with_gsoap2+set}" = set; then - withval=$with_gsoap2; +# Check whether --with-avro was given. +if test "${with_avro+set}" = set; then + withval=$with_avro; fi @@ -3978,9 +4108,9 @@ if test "${with_avro+set}" = set; then fi -# Check whether --with-avro2 was given. -if test "${with_avro2+set}" = set; then - withval=$with_avro2; +# Check whether --with-cereal was given. +if test "${with_cereal+set}" = set; then + withval=$with_cereal; fi @@ -3990,9 +4120,9 @@ if test "${with_cereal+set}" = set; then fi -# Check whether --with-cereal2 was given. -if test "${with_cereal2+set}" = set; then - withval=$with_cereal2; +# Check whether --with-sasl2 was given. +if test "${with_sasl2+set}" = set; then + withval=$with_sasl2; fi @@ -4002,9 +4132,9 @@ if test "${with_sasl2+set}" = set; then fi -# Check whether --with-sasl2b was given. -if test "${with_sasl2b+set}" = set; then - withval=$with_sasl2b; +# Check whether --with-mongodb was given. +if test "${with_mongodb+set}" = set; then + withval=$with_mongodb; fi @@ -4014,9 +4144,15 @@ if test "${with_mongodb+set}" = set; then fi -# Check whether --with-mongodb2 was given. -if test "${with_mongodb2+set}" = set; then - withval=$with_mongodb2; +# Check whether --with-mongodb3 was given. +if test "${with_mongodb3+set}" = set; then + withval=$with_mongodb3; +fi + + +# Check whether --with-mongodb3 was given. +if test "${with_mongodb3+set}" = set; then + withval=$with_mongodb3; fi @@ -4026,9 +4162,9 @@ if test "${with_gmock+set}" = set; then fi -# Check whether --with-gmock2 was given. -if test "${with_gmock2+set}" = set; then - withval=$with_gmock2; +# Check whether --with-gmock was given. +if test "${with_gmock+set}" = set; then + withval=$with_gmock; fi @@ -4038,9 +4174,9 @@ if test "${with_lapack+set}" = set; then fi -# Check whether --with-lapack2 was given. -if test "${with_lapack2+set}" = set; then - withval=$with_lapack2; +# Check whether --with-lapack was given. +if test "${with_lapack+set}" = set; then + withval=$with_lapack; fi @@ -4056,15 +4192,75 @@ if test "${with_lmdb+set}" = set; then fi +# Check whether --with-libuv was given. +if test "${with_libuv+set}" = set; then + withval=$with_libuv; +fi + + +# Check whether --with-libuv was given. +if test "${with_libuv+set}" = set; then + withval=$with_libuv; +fi + + +# Check whether --with-libssh2 was given. +if test "${with_libssh2+set}" = set; then + withval=$with_libssh2; +fi + + +# Check whether --with-libssh2 was given. +if test "${with_libssh2+set}" = set; then + withval=$with_libssh2; +fi + + +# Check whether --with-cassandra was given. +if test "${with_cassandra+set}" = set; then + withval=$with_cassandra; +fi + + +# Check whether --with-cassandra was given. +if test "${with_cassandra+set}" = set; then + withval=$with_cassandra; +fi + + +# Check whether --with-libxlsxwriter was given. +if test "${with_libxlsxwriter+set}" = set; then + withval=$with_libxlsxwriter; +fi + + +# Check whether --with-libxlsxwriter was given. +if test "${with_libxlsxwriter+set}" = set; then + withval=$with_libxlsxwriter; +fi + + +# Check whether --with-grpc was given. +if test "${with_grpc+set}" = set; then + withval=$with_grpc; +fi + + +# Check whether --with-grpc was given. +if test "${with_grpc+set}" = set; then + withval=$with_grpc; +fi + + # Check whether --with-3psw was given. if test "${with_3psw+set}" = set; then withval=$with_3psw; fi -# Check whether --with-3psw2 was given. -if test "${with_3psw2+set}" = set; then - withval=$with_3psw2; +# Check whether --with-3psw was given. +if test "${with_3psw+set}" = set; then + withval=$with_3psw; fi @@ -4088,24 +4284,6 @@ if test "${with_connext+set}" = set; then fi -# Check whether --with-serial was given. -if test "${with_serial+set}" = set; then - withval=$with_serial; -fi - - -# Check whether --with-objects was given. -if test "${with_objects+set}" = set; then - withval=$with_objects; -fi - - -# Check whether --with-dbapi was given. -if test "${with_dbapi+set}" = set; then - withval=$with_dbapi; -fi - - # Check whether --with-app was given. if test "${with_app+set}" = set; then withval=$with_app; @@ -4124,21 +4302,15 @@ if test "${with_gui+set}" = set; then fi -# Check whether --with-algo was given. -if test "${with_algo+set}" = set; then - withval=$with_algo; -fi - - # Check whether --with-internal was given. if test "${with_internal+set}" = set; then withval=$with_internal; fi -# Check whether --with-internal2 was given. -if test "${with_internal2+set}" = set; then - withval=$with_internal2; +# Check whether --with-internal was given. +if test "${with_internal+set}" = set; then + withval=$with_internal; fi @@ -4148,9 +4320,9 @@ if test "${with_gbench+set}" = set; then fi -# Check whether --with-gbench2 was given. -if test "${with_gbench2+set}" = set; then - withval=$with_gbench2; +# Check whether --with-gbench was given. +if test "${with_gbench+set}" = set; then + withval=$with_gbench; fi @@ -4216,12 +4388,12 @@ echo "$as_me: error: incompatible options: --without-algo but --with-gbench" >&2 else : ${with_algo:=yes} fi - if test "$with_glew_mx" = "no"; then - { { echo "$as_me:$LINENO: error: incompatible options: --without-glew_mx but --with-gbench" >&5 -echo "$as_me: error: incompatible options: --without-glew_mx but --with-gbench" >&2;} + if test "$with_glew" = "no"; then + { { echo "$as_me:$LINENO: error: incompatible options: --without-glew but --with-gbench" >&5 +echo "$as_me: error: incompatible options: --without-glew but --with-gbench" >&2;} { (exit 1); exit 1; }; } else - : ${with_glew_mx:=yes} + : ${with_glew:=yes} fi if test "$with_wxwidgets" = "no"; then { { echo "$as_me:$LINENO: error: incompatible options: --without-wxwidgets but --with-gbench" >&5 @@ -4300,6 +4472,8 @@ if test "$with_bin_release" = "yes" ; then : ${with_local_lbsm=no} : ${with_ncbi_crypt=no} : ${with_connext=no} + : ${with_pcre=no} # Too much variation across distributions. + : ${with_sse42=no} cat >>confdefs.h <<\_ACEOF #define NCBI_BIN_RELEASE 1 @@ -4370,6 +4544,32 @@ echo "$as_me: error: incompatible options: --without-gnutls but --with-static-gn ;; esac +if test -n "$with_serial"; then + { echo "$as_me:$LINENO: WARNING: --with(out)-serial is deprecated" >&5 +echo "$as_me: WARNING: --with(out)-serial is deprecated" >&2;} + { echo "$as_me:$LINENO: WARNING: please simply pass an appropriate project list" >&5 +echo "$as_me: WARNING: please simply pass an appropriate project list" >&2;} + fi + if test -n "$with_objects"; then + { echo "$as_me:$LINENO: WARNING: --with(out)-objects is deprecated" >&5 +echo "$as_me: WARNING: --with(out)-objects is deprecated" >&2;} + { echo "$as_me:$LINENO: WARNING: please simply pass an appropriate project list" >&5 +echo "$as_me: WARNING: please simply pass an appropriate project list" >&2;} + fi + if test -n "$with_dbapi"; then + { echo "$as_me:$LINENO: WARNING: --with(out)-dbapi is deprecated" >&5 +echo "$as_me: WARNING: --with(out)-dbapi is deprecated" >&2;} + { echo "$as_me:$LINENO: WARNING: please simply pass an appropriate project list" >&5 +echo "$as_me: WARNING: please simply pass an appropriate project list" >&2;} + fi + if test -n "$with_algo"; then + { echo "$as_me:$LINENO: WARNING: --with(out)-algo is deprecated" >&5 +echo "$as_me: WARNING: --with(out)-algo is deprecated" >&2;} + { echo "$as_me:$LINENO: WARNING: please simply pass an appropriate project list" >&5 +echo "$as_me: WARNING: please simply pass an appropriate project list" >&2;} + fi + + #### Check for special options if test "$with_extra_action" = "yes" ; then { { echo "$as_me:$LINENO: error: --with-extra-action must have a value after =" >&5 @@ -4474,6 +4674,8 @@ if test -n "$TEAMCITY_VERSION" -a -n "$BUILD_NUMBER"; then { echo "$as_me:$LINENO: result: $BUILD_NUMBER" >&5 echo "${ECHO_T}$BUILD_NUMBER" >&6; } NCBI_TEAMCITY_BUILD_NUMBER=$BUILD_NUMBER + NCBI_TEAMCITY_PROJECT_NAME=$TEAMCITY_PROJECT_NAME + NCBI_TEAMCITY_BUILDCONF_NAME=$TEAMCITY_BUILDCONF_NAME else { echo "$as_me:$LINENO: result: none" >&5 echo "${ECHO_T}none" >&6; } @@ -7879,7 +8081,7 @@ fi case "$host_os:$compiler" in solaris2.10:GCC ) : ${THREAD_LIBS:="-lposix4"} ;; solaris* ) : ${THREAD_LIBS:="-lpthread -lposix4"} ;; - freebsd* ) ;; # -pthread already substitutes libc_r for libc + freebsd* ) : ${THREAD_LIBS:="-pthread"} ;; # for LMDB in ST builds * ) : ${THREAD_LIBS:="-lpthread"} ;; esac @@ -8162,6 +8364,9 @@ echo "$as_me: WARNING: No dlfcn.h in /usr/include or /sw/include." >&2;} OBJCXX_CXXFLAGS='-x objective-c++' OBJCXX_LIBS='-lobjc' + + # New in macOS 10.12; don't attempt to use on older versions + ac_cv_search_clock_gettime=no ;; esac @@ -8702,6 +8907,176 @@ echo "${ECHO_T}$ncbi_cv_prog_cc_new_dtags" >&6; } ;; esac +{ echo "$as_me:$LINENO: checking whether $CC has an option to discard unneeded shared libraries" >&5 +echo $ECHO_N "checking whether $CC has an option to discard unneeded shared libraries... $ECHO_C" >&6; } +if test "${ncbi_cv_prog_cc_as_needed+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + orig_LDFLAGS=$LDFLAGS + ncbi_cv_prog_cc_as_needed=no + for x in -Wl,--as-needed; do + LDFLAGS="$orig_LDFLAGS $x" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_prog_cc_as_needed=$x +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + test "x$ncbi_cv_prog_cc_as_needed" = "xno" || break + done + LDFLAGS=$orig_LDFLAGS +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_prog_cc_as_needed" >&5 +echo "${ECHO_T}$ncbi_cv_prog_cc_as_needed" >&6; } +case "$ncbi_cv_prog_cc_as_needed" in + -Wl,--as-needed ) + AS_NEEDED=-Wl,--as-needed + NO_AS_NEEDED=-Wl,--no-as-needed + ;; + no ) + AS_NEEDED= + NO_AS_NEEDED= + ;; +esac + +{ echo "$as_me:$LINENO: checking whether $CC has an option to link in whole static archives" >&5 +echo $ECHO_N "checking whether $CC has an option to link in whole static archives... $ECHO_C" >&6; } +if test "${ncbi_cv_prog_cc_whole_archive+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + orig_LDFLAGS=$LDFLAGS + ncbi_cv_prog_cc_whole_archive=no + for x in -Wl,--whole-archive; do + LDFLAGS="$orig_LDFLAGS $x `echo $x | sed -e 's/--/--no-/'`" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_prog_cc_whole_archive=$x +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + test "x$ncbi_cv_prog_cc_whole_archive" = "xno" || break + done + LDFLAGS=$orig_LDFLAGS +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_prog_cc_whole_archive" >&5 +echo "${ECHO_T}$ncbi_cv_prog_cc_whole_archive" >&6; } +case "$ncbi_cv_prog_cc_whole_archive" in + -Wl,--whole-archive ) + WHOLE_ARCHIVE=-Wl,--whole-archive + NO_WHOLE_ARCHIVE=-Wl,--no-whole-archive + ;; + no ) + WHOLE_ARCHIVE= + NO_WHOLE_ARCHIVE= + ;; +esac + if $CXX -v 2>&1 | grep -q clang; then CFLAGS="$CFLAGS -Wno-deprecated-register" CXXFLAGS="$CXXFLAGS -Wno-deprecated-register" @@ -9024,6 +9399,88 @@ rm -f core conftest.err conftest.$ac_objext \ fi { echo "$as_me:$LINENO: result: $ncbi_cv_prog_c_99" >&5 echo "${ECHO_T}$ncbi_cv_prog_c_99" >&6; } + +: ${with_sse42=no} +if test "${with_sse42-$with_optimization}" = yes; then + { echo "$as_me:$LINENO: checking whether $CC supports -msse4.2" >&5 +echo $ECHO_N "checking whether $CC supports -msse4.2... $ECHO_C" >&6; } +if test "${ncbi_cv_prog_c_sse42+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + orig_CC=$CC + CC="$CC -msse4.2" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +__m128i v; _mm_cmpgt_epi64(v, v); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_prog_c_sse42=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_prog_c_sse42=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_prog_c_sse42" >&5 +echo "${ECHO_T}$ncbi_cv_prog_c_sse42" >&6; } + if test $ncbi_cv_prog_c_sse42 = yes; then + orig_CC=$CC + elif test "$with_sse42" = yes; then + { { echo "$as_me:$LINENO: error: SSE 4.2 support explicitly requested but unavailable." >&5 +echo "$as_me: error: SSE 4.2 support explicitly requested but unavailable." >&2;} + { (exit 1); exit 1; }; } + else + CC=$orig_CC + fi +fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -9032,6 +9489,87 @@ ac_compiler_gnu=$ac_cv_cxx_compiler_gnu test "$ncbi_cv_prog_c_99" = no || CC="$CC $ncbi_cv_prog_c_99" +if test "${with_sse42-$with_optimization}" = yes; then + { echo "$as_me:$LINENO: checking whether $CXX supports -msse4.2" >&5 +echo $ECHO_N "checking whether $CXX supports -msse4.2... $ECHO_C" >&6; } +if test "${ncbi_cv_prog_cxx_sse42+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + orig_CXX=$CXX + CXX="$CXX -msse4.2" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +__m128i v; _mm_cmpgt_epi64(v, v); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_prog_cxx_sse42=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_prog_cxx_sse42=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_prog_cxx_sse42" >&5 +echo "${ECHO_T}$ncbi_cv_prog_cxx_sse42" >&6; } + if test $ncbi_cv_prog_cxx_sse42 = yes; then + orig_CXX=$CXX + elif test "$with_sse42" = yes; then + { { echo "$as_me:$LINENO: error: SSE 4.2 support explicitly requested but unavailable." >&5 +echo "$as_me: error: SSE 4.2 support explicitly requested but unavailable." >&2;} + { (exit 1); exit 1; }; } + else + CXX=$orig_CXX + fi +fi + case "$host_os:$compiler" in solaris*:GCC ) # On Solaris, GCC defaults to setting _XOPEN_SOURCE (to 500) only @@ -10730,6 +11268,88 @@ echo "${ECHO_T}no" >&6; } fi fi +# Extract the first word of "uuidgen", so it can be a program name with args. +set dummy uuidgen; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_UUIDGEN+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $UUIDGEN in + [\\/]* | ?:[\\/]*) + ac_cv_path_UUIDGEN="$UUIDGEN" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_UUIDGEN="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +UUIDGEN=$ac_cv_path_UUIDGEN +if test -n "$UUIDGEN"; then + { echo "$as_me:$LINENO: result: $UUIDGEN" >&5 +echo "${ECHO_T}$UUIDGEN" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +# Extract the first word of "cd_reporter", so it can be a program name with args. +set dummy cd_reporter; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_CD_REPORTER+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $CD_REPORTER in + [\\/]* | ?:[\\/]*) + ac_cv_path_CD_REPORTER="$CD_REPORTER" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy="/am/ncbiapdata/bin:$PATH" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_CD_REPORTER="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +CD_REPORTER=$ac_cv_path_CD_REPORTER +if test -n "$CD_REPORTER"; then + { echo "$as_me:$LINENO: result: $CD_REPORTER" >&5 +echo "${ECHO_T}$CD_REPORTER" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + #### Check if "${build_root}" is defined; provide a default one if test -n "${with_build_root}" ; then build_root=${with_build_root} @@ -10813,6 +11433,24 @@ else fi +#### Code coverage +if test "$with_code_coverage" = "yes"; then + case "$compiler" in + GCC ) # including Clang + COVFLAGS="--coverage" + ;; + * ) + { { echo "$as_me:$LINENO: error: --with-code-coverage not implemented for $compiler" >&5 +echo "$as_me: error: --with-code-coverage not implemented for $compiler" >&2;} + { (exit 1); exit 1; }; } + ;; + esac + CFLAGS="$CFLAGS $COVFLAGS" + CXXFLAGS="$CXXFLAGS $COVFLAGS" + LDFLAGS="$LDFLAGS $COVFLAGS" +fi + + #### Determine whether this is implicitly a 64-bit platform ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' @@ -14977,34 +15615,31 @@ _ACEOF fi -## gethostbyname_r() -- 2 different variants: 5-arg (Solaris), 6-arg (Linux). -{ echo "$as_me:$LINENO: checking for gethostbyname_r" >&5 -echo $ECHO_N "checking for gethostbyname_r... $ECHO_C" >&6; } -if test "${ncbi_cv_func_gethostbyname_r+set}" = set; then +for ac_header in cxxabi.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } else - ncbi_cv_func_gethostbyname_r="no" - cat >conftest.$ac_ext <<_ACEOF + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include -int -main () -{ - - void* dummy = (void*) &gethostbyname_r; - char buf[1024]; - int err; - struct hostent* hp = 0; - hp = gethostbyname_r("", hp, buf, sizeof(buf), &err); - - ; - return 0; -} +$ac_includes_default +#include <$ac_header> _ACEOF rm -f conftest.$ac_objext if { (ac_try="$ac_compile" @@ -15040,35 +15675,136 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 - ncbi_cv_func_gethostbyname_r="5" + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_cxx_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_cxx_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ---------------------------------------- ## +## Report this to cpp-core@ncbi.nlm.nih.gov ## +## ---------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if test "$ncbi_cv_func_gethostbyname_r" = "no" ; then - cat >conftest.$ac_ext <<_ACEOF +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +if test "$ac_cv_header_cxxabi_h" = "yes"; then + { echo "$as_me:$LINENO: checking whether abi::__cxa_demangle is declared" >&5 +echo $ECHO_N "checking whether abi::__cxa_demangle is declared... $ECHO_C" >&6; } +if test "${ac_cv_have_decl_abi____cxa_demangle+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include +#include + int main () { - - void* dummy = (void*) &gethostbyname_r; - char buf[1024]; - int err; - struct hostent* hp = 0; - err = gethostbyname_r("", hp, buf, sizeof(buf), &hp, &err); +#ifndef abi::__cxa_demangle + char *p = (char *) abi::__cxa_demangle; + return !p; +#endif ; return 0; @@ -15108,62 +15844,215 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - - ncbi_cv_func_gethostbyname_r="6" - - + ac_cv_have_decl_abi____cxa_demangle=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - + ac_cv_have_decl_abi____cxa_demangle=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - fi fi -{ echo "$as_me:$LINENO: result: $ncbi_cv_func_gethostbyname_r" >&5 -echo "${ECHO_T}$ncbi_cv_func_gethostbyname_r" >&6; } +{ echo "$as_me:$LINENO: result: $ac_cv_have_decl_abi____cxa_demangle" >&5 +echo "${ECHO_T}$ac_cv_have_decl_abi____cxa_demangle" >&6; } +if test $ac_cv_have_decl_abi____cxa_demangle = yes; then -if test "$ncbi_cv_func_gethostbyname_r" != "no" ; then - -cat >>confdefs.h <<_ACEOF -#define HAVE_GETHOSTBYNAME_R $ncbi_cv_func_gethostbyname_r +cat >>confdefs.h <<\_ACEOF +#define HAVE_CXA_DEMANGLE 1 _ACEOF fi +fi -## gethostbyaddr_r() -- 2 different variants: 7-arg (Solaris), 8-arg (Linux). +## gethostbyname_r() -- 2 different variants: 5-arg (Solaris), 6-arg (Linux). -{ echo "$as_me:$LINENO: checking for gethostbyaddr_r" >&5 -echo $ECHO_N "checking for gethostbyaddr_r... $ECHO_C" >&6; } -if test "${ncbi_cv_func_gethostbyaddr_r+set}" = set; then +{ echo "$as_me:$LINENO: checking for gethostbyname_r" >&5 +echo $ECHO_N "checking for gethostbyname_r... $ECHO_C" >&6; } +if test "${ncbi_cv_func_gethostbyname_r+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - ncbi_cv_func_gethostbyaddr_r="no" + ncbi_cv_func_gethostbyname_r="no" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ - - #include - #include - #include - +#include int main () { - void* dummy = (void*) &gethostbyaddr_r; + void* dummy = (void*) &gethostbyname_r; char buf[1024]; int err; - unsigned int host; struct hostent* hp = 0; - hp = gethostbyaddr_r((char *) &host, sizeof(host), AF_INET, - hp, buf, sizeof(buf), &err); + hp = gethostbyname_r("", hp, buf, sizeof(buf), &err); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + + ncbi_cv_func_gethostbyname_r="5" + + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test "$ncbi_cv_func_gethostbyname_r" = "no" ; then + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ + + void* dummy = (void*) &gethostbyname_r; + char buf[1024]; + int err; + struct hostent* hp = 0; + err = gethostbyname_r("", hp, buf, sizeof(buf), &hp, &err); + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + + ncbi_cv_func_gethostbyname_r="6" + + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_func_gethostbyname_r" >&5 +echo "${ECHO_T}$ncbi_cv_func_gethostbyname_r" >&6; } + +if test "$ncbi_cv_func_gethostbyname_r" != "no" ; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_GETHOSTBYNAME_R $ncbi_cv_func_gethostbyname_r +_ACEOF + +fi + + +## gethostbyaddr_r() -- 2 different variants: 7-arg (Solaris), 8-arg (Linux). + +{ echo "$as_me:$LINENO: checking for gethostbyaddr_r" >&5 +echo $ECHO_N "checking for gethostbyaddr_r... $ECHO_C" >&6; } +if test "${ncbi_cv_func_gethostbyaddr_r+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ncbi_cv_func_gethostbyaddr_r="no" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + + #include + #include + #include + +int +main () +{ + + void* dummy = (void*) &gethostbyaddr_r; + char buf[1024]; + int err; + unsigned int host; + struct hostent* hp = 0; + hp = gethostbyaddr_r((char *) &host, sizeof(host), AF_INET, + hp, buf, sizeof(buf), &err); ; return 0; @@ -16220,14 +17109,15 @@ done + for ac_func in alarm asprintf atoll basename euidaccess fseeko fstat \ getgrouplist getopt getpagesize getpass getpassphrase \ getpwuid getrusage gettimeofday getuid lchown lutimes memrchr \ putenv readpassphrase readv select setenv statfs statvfs \ - strcasecmp strdup strlcat strlcpy strndup strsep strtok_r \ - sysmp timegm usleep utimes vasprintf vsnprintf writev + strcasecmp strdup strlcat strlcpy strndup strnlen strsep \ + strtok_r sysmp timegm usleep utimes vasprintf vsnprintf writev do as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` { echo "$as_me:$LINENO: checking for $ac_func" >&5 @@ -23551,9 +24441,9 @@ _ACEOF fi -{ echo "$as_me:$LINENO: checking for obsolete string::compare() syntax" >&5 -echo $ECHO_N "checking for obsolete string::compare() syntax... $ECHO_C" >&6; } -if test "${ncbi_cv_func_string_compare_obsolete+set}" = set; then +{ echo "$as_me:$LINENO: checking for ios(_base)::register_callback" >&5 +echo $ECHO_N "checking for ios(_base)::register_callback... $ECHO_C" >&6; } +if test "${ncbi_cv_func_ios_register_callback+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF @@ -23562,11 +24452,11 @@ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include +#include int main () { -std::string s; int i = 0; i = s.compare("aaa", 0, 2); +std::cout.register_callback(0, std::ios::erase_event); ; return 0; } @@ -23605,30 +24495,30 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ncbi_cv_func_string_compare_obsolete=yes + ncbi_cv_func_ios_register_callback=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ncbi_cv_func_string_compare_obsolete=no + ncbi_cv_func_ios_register_callback=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi -{ echo "$as_me:$LINENO: result: $ncbi_cv_func_string_compare_obsolete" >&5 -echo "${ECHO_T}$ncbi_cv_func_string_compare_obsolete" >&6; } -if test "$ncbi_cv_func_string_compare_obsolete" = yes; then +{ echo "$as_me:$LINENO: result: $ncbi_cv_func_ios_register_callback" >&5 +echo "${ECHO_T}$ncbi_cv_func_ios_register_callback" >&6; } +if test "$ncbi_cv_func_ios_register_callback" = yes; then cat >>confdefs.h <<\_ACEOF -#define NCBI_OBSOLETE_STR_COMPARE 1 +#define HAVE_IOS_REGISTER_CALLBACK 1 _ACEOF fi -{ echo "$as_me:$LINENO: checking whether the auto_ptr template class works" >&5 -echo $ECHO_N "checking whether the auto_ptr template class works... $ECHO_C" >&6; } -if test "${ncbi_cv_type_auto_ptr_works+set}" = set; then +{ echo "$as_me:$LINENO: checking for SysV semaphores" >&5 +echo $ECHO_N "checking for SysV semaphores... $ECHO_C" >&6; } +if test "${ncbi_cv_sys_semaphores+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat >conftest.$ac_ext <<_ACEOF @@ -23637,484 +24527,94 @@ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include +#include +#include +int +main () +{ +struct sembuf buf; int id = semget(0x1234, 0, IPC_CREAT); + buf.sem_op = SEM_UNDO; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_sys_semaphores=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_sys_semaphores=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_sys_semaphores" >&5 +echo "${ECHO_T}$ncbi_cv_sys_semaphores" >&6; } +if test "$ncbi_cv_sys_semaphores" = yes; then + +cat >>confdefs.h <<\_ACEOF +#define HAVE_SYSV_SEMAPHORES 1 +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for union semun" >&5 +echo $ECHO_N "checking for union semun... $ECHO_C" >&6; } +if test "${ac_cv_type_union_semun+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + +typedef union semun ac__type_new_; int main () { -int *ip = 0; std::auto_ptr ap(ip); *ip = *ap; ap.reset(ip); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ncbi_cv_type_auto_ptr_works=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ncbi_cv_type_auto_ptr_works=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ncbi_cv_type_auto_ptr_works" >&5 -echo "${ECHO_T}$ncbi_cv_type_auto_ptr_works" >&6; } -if test "$ncbi_cv_cxx_auto_ptr_works" = no; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_NO_AUTO_PTR 1 -_ACEOF - -fi - - -{ echo "$as_me:$LINENO: checking for min/max templates" >&5 -echo $ECHO_N "checking for min/max templates... $ECHO_C" >&6; } -if test "${ncbi_cv_func_min_max+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ - - #include - #ifdef min - #undef min - #endif - #ifdef max - #undef max - #endif - -int -main () -{ -int a=0, b=1; a = std::min(a, b); b = std::max(a, b); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ncbi_cv_func_min_max=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ncbi_cv_func_min_max=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ncbi_cv_func_min_max" >&5 -echo "${ECHO_T}$ncbi_cv_func_min_max" >&6; } -if test "$ncbi_cv_func_min_max" = no; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_NO_MINMAX_TEMPLATE 1 -_ACEOF - -fi - - -{ echo "$as_me:$LINENO: checking whether new C++ streams have ios_base::" >&5 -echo $ECHO_N "checking whether new C++ streams have ios_base::... $ECHO_C" >&6; } -if test "${ncbi_cv_type_ios_base+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -int -main () -{ -(void)(std::ios_base::out != std::ios_base::beg); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ncbi_cv_type_ios_base=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ncbi_cv_type_ios_base=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ncbi_cv_type_ios_base" >&5 -echo "${ECHO_T}$ncbi_cv_type_ios_base" >&6; } -if test "$ncbi_cv_type_ios_base" = no; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_NO_IOS_BASE 1 -_ACEOF - -fi - - -{ echo "$as_me:$LINENO: checking for ios(_base)::register_callback" >&5 -echo $ECHO_N "checking for ios(_base)::register_callback... $ECHO_C" >&6; } -if test "${ncbi_cv_func_ios_register_callback+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -int -main () -{ -std::cout.register_callback(0, std::ios::erase_event); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ncbi_cv_func_ios_register_callback=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ncbi_cv_func_ios_register_callback=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ncbi_cv_func_ios_register_callback" >&5 -echo "${ECHO_T}$ncbi_cv_func_ios_register_callback" >&6; } -if test "$ncbi_cv_func_ios_register_callback" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_IOS_REGISTER_CALLBACK 1 -_ACEOF - -fi - - -{ echo "$as_me:$LINENO: checking for std::char_traits::" >&5 -echo $ECHO_N "checking for std::char_traits::... $ECHO_C" >&6; } -if test "${ncbi_cv_type_char_traits+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -int -main () -{ -using namespace std; - char_traits::int_type i = char_traits::eof(); - i = char_traits::not_eof(i); - char_traits::char_type c = '\0'; - char_traits::pos_type p = 0; - char_traits::off_type o = 1; - - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext -if { (ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_compile") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest.$ac_objext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ncbi_cv_type_char_traits=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ncbi_cv_type_char_traits=no -fi - -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ncbi_cv_type_char_traits" >&5 -echo "${ECHO_T}$ncbi_cv_type_char_traits" >&6; } -if test "$ncbi_cv_type_char_traits" = no; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_NO_CHAR_TRAITS 1 -_ACEOF - -fi - - - -{ echo "$as_me:$LINENO: checking for SysV semaphores" >&5 -echo $ECHO_N "checking for SysV semaphores... $ECHO_C" >&6; } -if test "${ncbi_cv_sys_semaphores+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#include -int -main () -{ -struct sembuf buf; int id = semget(0x1234, 0, IPC_CREAT); - buf.sem_op = SEM_UNDO; - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ncbi_cv_sys_semaphores=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ncbi_cv_sys_semaphores=no -fi - -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ncbi_cv_sys_semaphores" >&5 -echo "${ECHO_T}$ncbi_cv_sys_semaphores" >&6; } -if test "$ncbi_cv_sys_semaphores" = yes; then - -cat >>confdefs.h <<\_ACEOF -#define HAVE_SYSV_SEMAPHORES 1 -_ACEOF - -fi - -{ echo "$as_me:$LINENO: checking for union semun" >&5 -echo $ECHO_N "checking for union semun... $ECHO_C" >&6; } -if test "${ac_cv_type_union_semun+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -#include -#include - -typedef union semun ac__type_new_; -int -main () -{ -if ((ac__type_new_ *) 0) - return 0; -if (sizeof (ac__type_new_)) - return 0; +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; ; return 0; } @@ -27892,6 +28392,185 @@ esac usr_lib='[/usr]*/lib/*[amdsprcv]*[23469]*' no_usr_lib="s,-L$usr_lib ,,g; s,-L/usr/lib/$multiarch ,,g" +: ${with_libunwind:=no} +if test "$with_libunwind" != "no"; then + case "$with_libunwind" in + yes | "" ) ;; + * ) LIBUNWIND_PATH=$with_libunwind ;; + esac + if test "$LIBUNWIND_PATH" != /usr -a -d "$LIBUNWIND_PATH"; then + in_path=" in $LIBUNWIND_PATH" + if test -z "$LIBUNWIND_INCLUDE" -a -d "$LIBUNWIND_PATH/include"; then + LIBUNWIND_INCLUDE="-I$LIBUNWIND_PATH/include" + fi + if test -n "$LIBUNWIND_LIBPATH"; then + : + elif test -d "$LIBUNWIND_PATH/lib${bit64_sfx}"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LIBUNWIND_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LIBUNWIND_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LIBUNWIND_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LIBUNWIND_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + elif test -d "$LIBUNWIND_PATH/lib"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LIBUNWIND_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LIBUNWIND_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LIBUNWIND_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LIBUNWIND_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + fi + LIBUNWIND_LIBS="$LIBUNWIND_LIBPATH -lunwind " + else + LIBUNWIND_INCLUDE="" + LIBUNWIND_LIBS="-lunwind " + in_path= + fi + { echo "$as_me:$LINENO: checking for libunwind$in_path" >&5 +echo $ECHO_N "checking for libunwind$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_libunwind+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + CPPFLAGS=" $LIBUNWIND_INCLUDE $orig_CPPFLAGS" + LIBS="$LIBUNWIND_LIBS $orig_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include +int +main () +{ +_Unwind_Trace_Fn f; _Unwind_Backtrace(f, NULL); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_lib_libunwind=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_lib_libunwind=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_libunwind" >&5 +echo "${ECHO_T}$ncbi_cv_lib_libunwind" >&6; } + if test "$ncbi_cv_lib_libunwind" = "no"; then + if test "${with_libunwind:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-libunwind explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-libunwind explicitly specified, but no usable version found." >&2;} + { (exit 1); exit 1; }; } + fi + fi + fi + if test "$with_libunwind" = "no"; then + LIBUNWIND_PATH="No_LIBUNWIND" + LIBUNWIND_INCLUDE= + LIBUNWIND_LIBS= + else + WithPackages="$WithPackages${WithPackagesSep}LIBUNWIND"; WithPackagesSep=" " + LIBUNWIND_INCLUDE=" $LIBUNWIND_INCLUDE" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBUNWIND 1 +_ACEOF + + fi + + + +LIBS="$LIBUNWIND_LIBS $LIBS" +orig_LIBS="$LIBUNWIND_LIBS $orig_LIBS" + if test "$with_z" != "no"; then case "$with_z" in yes | "" ) ;; @@ -28661,6 +29340,219 @@ else fi ## SSL/TLS libraries (and supporting libraries) +if test "x${with_mbedtls-no}" != xno; then + case "$with_mbedtls" in + yes ) ;; + * ) MBEDTLS_PATH=$with_mbedtls ;; + esac + d="$MBEDTLS_PATH/${DEBUG_SFX}${mt_sfx}${bit64_sfx}" + if test -d "$d"; then + MBEDTLS_PATH=$d + fi + if test -d "$MBEDTLS_PATH"; then + ncbi_fix_dir_tmp=`if cd $MBEDTLS_PATH; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` + case "$ncbi_fix_dir_tmp" in + /.*) ncbi_fix_dir_tmp2=`cd $MBEDTLS_PATH && $smart_pwd 2>/dev/null` + if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then + MBEDTLS_PATH=$ncbi_fix_dir_tmp2 + else + case "$MBEDTLS_PATH" in + /*) ;; + * ) MBEDTLS_PATH=$ncbi_fix_dir_tmp ;; + esac + fi + ;; + /*) MBEDTLS_PATH=$ncbi_fix_dir_tmp ;; + esac + fi + if test "$with_mbedtls" != "no"; then + case "$with_mbedtls" in + yes | "" ) ;; + * ) MBEDTLS_PATH=$with_mbedtls ;; + esac + if test "$MBEDTLS_PATH" != /usr -a -d "$MBEDTLS_PATH"; then + in_path=" in $MBEDTLS_PATH" + if test -z "$MBEDTLS_INCLUDE" -a -d "$MBEDTLS_PATH/include"; then + MBEDTLS_INCLUDE="-I$MBEDTLS_PATH/include" + fi + if test -n "$MBEDTLS_LIBPATH"; then + : + elif test -d "$MBEDTLS_PATH/lib${bit64_sfx}"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $MBEDTLS_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + MBEDTLS_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $MBEDTLS_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + MBEDTLS_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + elif test -d "$MBEDTLS_PATH/lib"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $MBEDTLS_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + MBEDTLS_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $MBEDTLS_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + MBEDTLS_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + fi + MBEDTLS_LIBS="$MBEDTLS_LIBPATH -lmbedtls -lmbedx509 -lmbedcrypto $Z_LIBS" + else + MBEDTLS_INCLUDE="" + MBEDTLS_LIBS="-lmbedtls -lmbedx509 -lmbedcrypto $Z_LIBS" + in_path= + fi + { echo "$as_me:$LINENO: checking for libmbedtls$in_path" >&5 +echo $ECHO_N "checking for libmbedtls$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_mbedtls+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + CPPFLAGS=" $MBEDTLS_INCLUDE $orig_CPPFLAGS" + LIBS="$MBEDTLS_LIBS $orig_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +mbedtls_ssl_context ssl; mbedtls_ssl_init(&ssl); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_lib_mbedtls=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_lib_mbedtls=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_mbedtls" >&5 +echo "${ECHO_T}$ncbi_cv_lib_mbedtls" >&6; } + if test "$ncbi_cv_lib_mbedtls" = "no"; then + if test "${with_mbedtls:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-mbedtls explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-mbedtls explicitly specified, but no usable version found." >&2;} + { (exit 1); exit 1; }; } + fi + fi + fi + if test "$with_mbedtls" = "no"; then + MBEDTLS_PATH="No_MBEDTLS" + MBEDTLS_INCLUDE= + MBEDTLS_LIBS= + else + WithPackages="$WithPackages${WithPackagesSep}MBEDTLS"; WithPackagesSep=" " + MBEDTLS_INCLUDE=" $MBEDTLS_INCLUDE" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBMBEDTLS 1 +_ACEOF + + fi + + + + if test -n "$MBEDTLS_LIBS" -a -f "$MBEDTLS_PATH/lib/libmbedtls-static.a" \ + -a "x$with_static_mbedtls" = xyes; then + MBEDTLS_LIBS="-L$MBEDTLS_PATH/lib -lmbedtls-static -lmbedx509-static -lmbedcrypto-static $Z_LIBS" + fi +fi +if test -z "$MBEDTLS_LIBS"; then + mbedtls_local=connect/mbedtls + { echo "$as_me:$LINENO: using local mbedTLS copy in $mbedtls_local" >&5 +echo "$as_me: using local mbedTLS copy in $mbedtls_local" >&6;} + MBEDTLS_INCLUDE="" + MBEDTLS_LIBS="$Z_LIBS" + WithPackages="$WithPackages${WithPackagesSep}MBEDTLS"; WithPackagesSep=" " +fi + if test "x$with_gmp" != xno; then case "$with_gmp" in yes | '' ) ;; @@ -29833,7 +30725,7 @@ if test "x$with_gnutls" != xno -a -n "$GNUTLS_CONFIG_LIBS"; then static_libs=$static_libs$sep$x sep=' ' done - GNUTLS_LIBS=$static_libs + GNUTLS_LIBS="$static_libs $ICONV_LIBS" fi fi @@ -30023,15 +30915,7 @@ for d in `echo " $OPENSSL_LIBS" | fmt -w 1 | sed -ne 's/^ *-L//p'` \ fi done -if test -n "$GNUTLS_LIBS"; then - TLS_INCLUDE=$GNUTLS_INCLUDE - TLS_LIBS=$GNUTLS_LIBS -else - TLS_INCLUDE=$OPENSSL_INCLUDE - TLS_LIBS=$OPENSSL_LIBS -fi - -NETWORK_LIBS="$TLS_LIBS $NETWORK_LIBS" +NETWORK_LIBS="$GNUTLS_LIBS $MBEDTLS_LIBS $NETWORK_LIBS" case "$with_krb5" in no ) ac_cv_path_KRB5_CONFIG=no ;; @@ -37245,7 +38129,8 @@ echo "$as_me: error: --with-glut explicitly specified, but no usable version fou fi glew_config="eval PKG_CONFIG_PATH=\"$GLEW_LIBDIR/pkgconfig\" pkg-config" if pkg-config --version >/dev/null 2>&1; then - if $glew_config glewmx --exists >/dev/null 2>&1 \ + if test "$with_glew_mx" != no \ + && $glew_config glewmx --exists >/dev/null 2>&1 \ && test -n "`$glew_config glewmx --libs 2>/dev/null`"; then glew_config="$glew_config glewmx" elif $glew_config glew --exists >/dev/null 2>&1 \ @@ -37422,8 +38307,8 @@ echo "$as_me: error: --with-glew-mx explicitly specified, but no usable version WithPackages="$WithPackages${WithPackagesSep}GLEW"; WithPackagesSep=" " CPPFLAGS="$orig_CPPFLAGS $GLEW_INCLUDE $OPENGL_INCLUDE" LIBS="$GLEW_LIBS $OPENGL_LIBS $orig_LIBS" - { echo "$as_me:$LINENO: checking for GLEW multi-context (MX) support (recommended)" >&5 -echo $ECHO_N "checking for GLEW multi-context (MX) support (recommended)... $ECHO_C" >&6; } + { echo "$as_me:$LINENO: checking for GLEW multi-context (MX) support" >&5 +echo $ECHO_N "checking for GLEW multi-context (MX) support... $ECHO_C" >&6; } if test "${ncbi_cv_lib_glew_mx+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else @@ -37491,7 +38376,17 @@ fi { echo "$as_me:$LINENO: result: $ncbi_cv_lib_glew_mx" >&5 echo "${ECHO_T}$ncbi_cv_lib_glew_mx" >&6; } if test $ncbi_cv_lib_glew_mx = yes; then - GLEW_INCLUDE="$GLEW_INCLUDE -DGLEW_MX" + if test "$with_glew_mx" = no; then + GLEW_INCLUDE= + GLEW_LIBS= + if test "${with_glew:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-glew explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-glew explicitly specified, but no usable version found." >&2;} + { (exit 1); exit 1; }; } + fi + else + GLEW_INCLUDE="$GLEW_INCLUDE -DGLEW_MX" + fi else if test "${with_glew_mx:=no}" != no; then { { echo "$as_me:$LINENO: error: --with-glew-mx explicitly specified, but no usable version found." >&5 @@ -37622,7 +38517,7 @@ fi libsed="$basesed; s%\$% $deps%" ;; esac - case "`"$wxconf" $wxcfflags --version`" in + test -x "$wxconf" && case "`"$wxconf" $wxcfflags --version`" in 1.* | 2.[0-7].* ) wxlibs=std ;; * ) wxlibs=std,richtext,aui,propgrid ;; esac @@ -41061,6 +41956,9 @@ _ACEOF fi done + SQLITE3_WRAPPER=sqlitewrapp +else + SQLITE3_WRAPPER= fi if test -n "$SQLITE3_LIBS" -a -f "$SQLITE3_LIBDIR/libsqlite3-static.a"; then SQLITE3_STATIC_LIBS="-L$SQLITE3_LIBDIR -lsqlite3-static" @@ -41074,13 +41972,15 @@ VDB_POST_LINK=: VDB_REQ=VDB if test "$with_vdb" != "no" ; then # CURL? - vdb_deps="$LIBXML_LIBS $NETWORK_LIBS $BZ2_LIBS $Z_LIBS $DL_LIBS" + vdb_deps="$NETWORK_LIBS $BZ2_LIBS $Z_LIBS $DL_LIBS" # In MT builds, ORIG_LIBS already contains THREAD_LIBS. However, # VDB is always threaded, and may need explicit THREAD_LIBS when # used statically. if test "$with_mt" = no; then vdb_deps="$vdb_deps $THREAD_LIBS" fi + vdb_static_deps="$LIBXML_STATIC_LIBS $vdb_deps" + vdb_deps="$LIBXML_LIBS $vdb_deps" if test "${with_vdb:-yes}" != "yes" -a -d "$with_vdb"; then VDB_PATH=$with_vdb fi @@ -41291,9 +42191,9 @@ echo "${ECHO_T}$ncbi_cv_lib_ncbi_vdb" >&6; } if test "$ncbi_cv_lib_ncbi_vdb" = yes; then WithPackages="$WithPackages${WithPackagesSep}VDB"; WithPackagesSep=" " if test -f "$VDB_LIBDIR/libncbi-vdb-static.a"; then - VDB_STATIC_LIBS="-L$VDB_LIBDIR -lncbi-vdb-static $vdb_deps" + VDB_STATIC_LIBS="-L$VDB_LIBDIR -lncbi-vdb-static $vdb_static_deps" if test "$with_static_vdb" = yes; then - VDB_LIBS=$VDB_STATIC_LIBS + VDB_LIBS="-L$VDB_LIBDIR -lncbi-vdb-static $vdb_deps" fi else VDB_STATIC_LIBS=$VDB_LIBS @@ -42723,184 +43623,7 @@ _ACEOF # Paths? with_ungif=$with_gif -if test "$with_ungif" != "no"; then - case "$with_ungif" in - yes | "" ) ;; - * ) UNGIF_PATH=$with_ungif ;; - esac - if test "$UNGIF_PATH" != /usr -a -d "$UNGIF_PATH"; then - in_path=" in $UNGIF_PATH" - if test -z "$UNGIF_INCLUDE" -a -d "$UNGIF_PATH/include"; then - UNGIF_INCLUDE="-I$UNGIF_PATH/include" - fi - if test -n "$UNGIF_LIBPATH"; then - : - elif test -d "$UNGIF_PATH/lib${bit64_sfx}"; then - ncbi_rp_L_flags= - ncbi_rp_L_sep=$CONF_f_libpath - if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then - for x in $UNGIF_PATH/lib${bit64_sfx}; do - case "$x" in - /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) - continue - ;; - esac - ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" - ncbi_rp_L_sep=" $CONF_f_libpath" - done - UNGIF_LIBPATH="${ncbi_rp_L_flags}" - else - ncbi_rp_R_flags= - ncbi_rp_R_sep=" $CONF_f_runpath" - for x in $UNGIF_PATH/lib${bit64_sfx}; do - case "$x" in - /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) - continue - ;; - esac - ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" - ncbi_rp_L_sep=" $CONF_f_libpath" - x=`echo $x | sed -e "$ncbi_rpath_sed"` - ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" - ncbi_rp_R_sep=: - done - UNGIF_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" - fi - elif test -d "$UNGIF_PATH/lib"; then - ncbi_rp_L_flags= - ncbi_rp_L_sep=$CONF_f_libpath - if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then - for x in $UNGIF_PATH/lib; do - case "$x" in - /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) - continue - ;; - esac - ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" - ncbi_rp_L_sep=" $CONF_f_libpath" - done - UNGIF_LIBPATH="${ncbi_rp_L_flags}" - else - ncbi_rp_R_flags= - ncbi_rp_R_sep=" $CONF_f_runpath" - for x in $UNGIF_PATH/lib; do - case "$x" in - /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) - continue - ;; - esac - ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" - ncbi_rp_L_sep=" $CONF_f_libpath" - x=`echo $x | sed -e "$ncbi_rpath_sed"` - ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" - ncbi_rp_R_sep=: - done - UNGIF_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" - fi - fi - UNGIF_LIBS="$UNGIF_LIBPATH -lungif $X_LIBS -lX11" - else - UNGIF_INCLUDE="" - UNGIF_LIBS="-lungif $X_LIBS -lX11" - in_path= - fi - { echo "$as_me:$LINENO: checking for libungif$in_path" >&5 -echo $ECHO_N "checking for libungif$in_path... $ECHO_C" >&6; } -if test "${ncbi_cv_lib_ungif+set}" = set; then - echo $ECHO_N "(cached) $ECHO_C" >&6 -else - CPPFLAGS=" $UNGIF_INCLUDE $orig_CPPFLAGS" - LIBS="$UNGIF_LIBS $orig_LIBS" - cat >conftest.$ac_ext <<_ACEOF -/* confdefs.h. */ -_ACEOF -cat confdefs.h >>conftest.$ac_ext -cat >>conftest.$ac_ext <<_ACEOF -/* end confdefs.h. */ -extern "C" { - #include - } -int -main () -{ -GifFileType* fp = DGifOpenFileName("foo"); - ; - return 0; -} -_ACEOF -rm -f conftest.$ac_objext conftest$ac_exeext -if { (ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_link") 2>conftest.er1 - ac_status=$? - grep -v '^ *+' conftest.er1 >conftest.err - rm -f conftest.er1 - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); } && - { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; } && - { ac_try='test -s conftest$ac_exeext' - { (case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - (exit $ac_status); }; }; then - ncbi_cv_lib_ungif=yes -else - echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ncbi_cv_lib_ungif=no -fi - -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_ungif" >&5 -echo "${ECHO_T}$ncbi_cv_lib_ungif" >&6; } - if test "$ncbi_cv_lib_ungif" = "no"; then - if test "${with_ungif:=no}" != no; then - { { echo "$as_me:$LINENO: error: --with-ungif explicitly specified, but no usable version found." >&5 -echo "$as_me: error: --with-ungif explicitly specified, but no usable version found." >&2;} - { (exit 1); exit 1; }; } - fi - fi - fi - if test "$with_ungif" = "no"; then - UNGIF_PATH="No_UNGIF" - UNGIF_INCLUDE= - UNGIF_LIBS= - else - WithPackages="$WithPackages${WithPackagesSep}UNGIF"; WithPackagesSep=" " - UNGIF_INCLUDE=" $UNGIF_INCLUDE" - -cat >>confdefs.h <<\_ACEOF -#define HAVE_LIBUNGIF 1 -_ACEOF - - fi - - - -if test "$with_ungif" = "no"; then - if test "$with_gif" != "no"; then +if test "$with_gif" != "no"; then case "$with_gif" in yes | "" ) ;; * ) GIF_PATH=$with_gif ;; @@ -42995,8 +43718,8 @@ cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ extern "C" { - #include - } + #include + } int main () { @@ -43076,34 +43799,24 @@ _ACEOF -else - -cat >>confdefs.h <<\_ACEOF -#define HAVE_LIBGIF 1 -_ACEOF - - GIF_INCLUDE=$UNGIF_INCLUDE - GIF_LIBS=$UNGIF_LIBS -fi - -case "$x_libraries" in */*) : ${XPM_PATH=`dirname "$x_libraries"`} ;; esac -if test "$with_xpm" != "no"; then - case "$with_xpm" in +if test "$with_gif" = "no"; then + if test "$with_ungif" != "no"; then + case "$with_ungif" in yes | "" ) ;; - * ) XPM_PATH=$with_xpm ;; + * ) UNGIF_PATH=$with_ungif ;; esac - if test "$XPM_PATH" != /usr -a -d "$XPM_PATH"; then - in_path=" in $XPM_PATH" - if test -z "$XPM_INCLUDE" -a -d "$XPM_PATH/include"; then - XPM_INCLUDE="-I$XPM_PATH/include" + if test "$UNGIF_PATH" != /usr -a -d "$UNGIF_PATH"; then + in_path=" in $UNGIF_PATH" + if test -z "$UNGIF_INCLUDE" -a -d "$UNGIF_PATH/include"; then + UNGIF_INCLUDE="-I$UNGIF_PATH/include" fi - if test -n "$XPM_LIBPATH"; then + if test -n "$UNGIF_LIBPATH"; then : - elif test -d "$XPM_PATH/lib${bit64_sfx}"; then + elif test -d "$UNGIF_PATH/lib${bit64_sfx}"; then ncbi_rp_L_flags= ncbi_rp_L_sep=$CONF_f_libpath if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then - for x in $XPM_PATH/lib${bit64_sfx}; do + for x in $UNGIF_PATH/lib${bit64_sfx}; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -43112,11 +43825,11 @@ if test "$with_xpm" != "no"; then ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" ncbi_rp_L_sep=" $CONF_f_libpath" done - XPM_LIBPATH="${ncbi_rp_L_flags}" + UNGIF_LIBPATH="${ncbi_rp_L_flags}" else ncbi_rp_R_flags= ncbi_rp_R_sep=" $CONF_f_runpath" - for x in $XPM_PATH/lib${bit64_sfx}; do + for x in $UNGIF_PATH/lib${bit64_sfx}; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -43128,13 +43841,13 @@ if test "$with_xpm" != "no"; then ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" ncbi_rp_R_sep=: done - XPM_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + UNGIF_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" fi - elif test -d "$XPM_PATH/lib"; then + elif test -d "$UNGIF_PATH/lib"; then ncbi_rp_L_flags= ncbi_rp_L_sep=$CONF_f_libpath if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then - for x in $XPM_PATH/lib; do + for x in $UNGIF_PATH/lib; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -43143,11 +43856,11 @@ if test "$with_xpm" != "no"; then ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" ncbi_rp_L_sep=" $CONF_f_libpath" done - XPM_LIBPATH="${ncbi_rp_L_flags}" + UNGIF_LIBPATH="${ncbi_rp_L_flags}" else ncbi_rp_R_flags= ncbi_rp_R_sep=" $CONF_f_runpath" - for x in $XPM_PATH/lib; do + for x in $UNGIF_PATH/lib; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -43159,34 +43872,221 @@ if test "$with_xpm" != "no"; then ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" ncbi_rp_R_sep=: done - XPM_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + UNGIF_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" fi fi - XPM_LIBS="$XPM_LIBPATH -lXpm $X_LIBS -lX11" + UNGIF_LIBS="$UNGIF_LIBPATH -lungif $X_LIBS -lX11" else - XPM_INCLUDE="" - XPM_LIBS="-lXpm $X_LIBS -lX11" + UNGIF_INCLUDE="" + UNGIF_LIBS="-lungif $X_LIBS -lX11" in_path= fi - { echo "$as_me:$LINENO: checking for libXpm$in_path" >&5 -echo $ECHO_N "checking for libXpm$in_path... $ECHO_C" >&6; } -if test "${ncbi_cv_lib_xpm+set}" = set; then + { echo "$as_me:$LINENO: checking for libungif$in_path" >&5 +echo $ECHO_N "checking for libungif$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_ungif+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - CPPFLAGS="$X_CFLAGS $XPM_INCLUDE $orig_CPPFLAGS" - LIBS="$XPM_LIBS $orig_LIBS" + CPPFLAGS=" $UNGIF_INCLUDE $orig_CPPFLAGS" + LIBS="$UNGIF_LIBS $orig_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include +extern "C" { + #include + } int main () { -XpmImage image; XpmInfo info; - XpmReadFileToXpmImage("foo", &image, &info); +GifFileType* fp = DGifOpenFileName("foo"); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_lib_ungif=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_lib_ungif=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_ungif" >&5 +echo "${ECHO_T}$ncbi_cv_lib_ungif" >&6; } + if test "$ncbi_cv_lib_ungif" = "no"; then + if test "${with_ungif:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-ungif explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-ungif explicitly specified, but no usable version found." >&2;} + { (exit 1); exit 1; }; } + fi + fi + fi + if test "$with_ungif" = "no"; then + UNGIF_PATH="No_UNGIF" + UNGIF_INCLUDE= + UNGIF_LIBS= + else + WithPackages="$WithPackages${WithPackagesSep}UNGIF"; WithPackagesSep=" " + UNGIF_INCLUDE=" $UNGIF_INCLUDE" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBUNGIF 1 +_ACEOF + + fi + + + +else + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBUNGIF 1 +_ACEOF + + UNGIF_INCLUDE=$GIF_INCLUDE + UNGIF_LIBS=$GIF_LIBS +fi + +case "$x_libraries" in */*) : ${XPM_PATH=`dirname "$x_libraries"`} ;; esac +if test "$with_xpm" != "no"; then + case "$with_xpm" in + yes | "" ) ;; + * ) XPM_PATH=$with_xpm ;; + esac + if test "$XPM_PATH" != /usr -a -d "$XPM_PATH"; then + in_path=" in $XPM_PATH" + if test -z "$XPM_INCLUDE" -a -d "$XPM_PATH/include"; then + XPM_INCLUDE="-I$XPM_PATH/include" + fi + if test -n "$XPM_LIBPATH"; then + : + elif test -d "$XPM_PATH/lib${bit64_sfx}"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $XPM_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + XPM_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $XPM_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + XPM_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + elif test -d "$XPM_PATH/lib"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $XPM_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + XPM_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $XPM_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + XPM_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + fi + XPM_LIBS="$XPM_LIBPATH -lXpm $X_LIBS -lX11" + else + XPM_INCLUDE="" + XPM_LIBS="-lXpm $X_LIBS -lX11" + in_path= + fi + { echo "$as_me:$LINENO: checking for libXpm$in_path" >&5 +echo $ECHO_N "checking for libXpm$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_xpm+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + CPPFLAGS="$X_CFLAGS $XPM_INCLUDE $orig_CPPFLAGS" + LIBS="$XPM_LIBS $orig_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +XpmImage image; XpmInfo info; + XpmReadFileToXpmImage("foo", &image, &info); ; return 0; } @@ -45080,7 +45980,7 @@ _ACEOF -# MongoDB +# legacy MongoDB case "$with_mongodb" in yes | no | '' ) ;; * ) MONGODB_PATH=$with_mongodb ;; @@ -45322,98 +46222,82 @@ else fi -# Google Mock -case "$with_gmock" in +# MongoDB 3.x +case "$with_mongodb3" in yes | no | '' ) ;; - * ) GMOCK_PATH=$with_gmock ;; + * ) MONGODB3_PATH=$with_mongodb3 ;; esac -if test -d "$GMOCK_PATH"; then - ncbi_fix_dir_tmp=`if cd $GMOCK_PATH; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` - case "$ncbi_fix_dir_tmp" in - /.*) ncbi_fix_dir_tmp2=`cd $GMOCK_PATH && $smart_pwd 2>/dev/null` - if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then - GMOCK_PATH=$ncbi_fix_dir_tmp2 - else - case "$GMOCK_PATH" in - /*) ;; - * ) GMOCK_PATH=$ncbi_fix_dir_tmp ;; - esac - fi - ;; - /*) GMOCK_PATH=$ncbi_fix_dir_tmp ;; - esac - for d in "$GMOCK_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx$bit64_sfx/lib" \ - "$GMOCK_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx$bit64_sfx/lib" \ - "$GMOCK_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx/lib" \ - "$GMOCK_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx/lib" \ - "$GMOCK_PATH/lib$bit64_sfx" "$GMOCK_PATH/lib"; do - if test -d "$d"; then - GMOCK_LIBDIR=$d - ncbi_fix_dir_tmp=`if cd $GMOCK_LIBDIR; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` +if test -d "$MONGODB3_PATH"; then + ncbi_fix_dir_tmp=`if cd $MONGODB3_PATH; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` case "$ncbi_fix_dir_tmp" in - /.*) ncbi_fix_dir_tmp2=`cd $GMOCK_LIBDIR && $smart_pwd 2>/dev/null` + /.*) ncbi_fix_dir_tmp2=`cd $MONGODB3_PATH && $smart_pwd 2>/dev/null` if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then - GMOCK_LIBDIR=$ncbi_fix_dir_tmp2 + MONGODB3_PATH=$ncbi_fix_dir_tmp2 else - case "$GMOCK_LIBDIR" in + case "$MONGODB3_PATH" in /*) ;; - * ) GMOCK_LIBDIR=$ncbi_fix_dir_tmp ;; + * ) MONGODB3_PATH=$ncbi_fix_dir_tmp ;; esac fi ;; - /*) GMOCK_LIBDIR=$ncbi_fix_dir_tmp ;; + /*) MONGODB3_PATH=$ncbi_fix_dir_tmp ;; esac - break - fi - done fi -ncbi_rp_L_flags= - ncbi_rp_L_sep=$CONF_f_libpath - if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then - for x in $GMOCK_LIBDIR; do - case "$x" in - /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) - continue - ;; - esac - ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" - ncbi_rp_L_sep=" $CONF_f_libpath" - done - GMOCK_LIBPATH="${ncbi_rp_L_flags}" +if test -d $MONGODB3_PATH/lib${bit64_sfx}; then + MONGODB3_LIBDIR=$MONGODB3_PATH/lib${bit64_sfx} +else + MONGODB3_LIBDIR=$MONGODB3_PATH/lib +fi +m3pc="env PKG_CONFIG_PATH=$MONGODB3_LIBDIR/pkgconfig pkg-config libmongocxx" +if $m3pc --exists >/dev/null 2>&1; then + MONGODB3_FULL_INCLUDE=`$m3pc --cflags` + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + MONGODB3_FULL_LIBS=`$m3pc --libs --static | sed -e "$no_usr_lib"` else + MONGODB3_FULL_LIBS= + ncbi_rp_L_sep= ncbi_rp_R_flags= ncbi_rp_R_sep=" $CONF_f_runpath" - for x in $GMOCK_LIBDIR; do + for x in `$m3pc --libs --static | sed -e "$no_usr_lib"`; do case "$x" in - /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + -L/lib | -L/usr/lib | -L/usr/lib32 | -L/usr/lib64 \ + | -L/usr/lib/$multiarch ) continue ;; + -L*) + MONGODB3_FULL_LIBS="$MONGODB3_FULL_LIBS${ncbi_rp_L_sep}$x" + x=`echo $x | sed -e "s/^-L//; $ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + ;; + *) + MONGODB3_FULL_LIBS="$MONGODB3_FULL_LIBS${ncbi_rp_R_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + ;; esac - ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" - ncbi_rp_L_sep=" $CONF_f_libpath" - x=`echo $x | sed -e "$ncbi_rpath_sed"` - ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" - ncbi_rp_R_sep=: + ncbi_rp_L_sep=" " done - GMOCK_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + MONGODB3_FULL_LIBS="$MONGODB3_FULL_LIBS${ncbi_rp_R_flags}" fi -if test "$with_gmock" != "no"; then - case "$with_gmock" in +fi +if test "$with_mongodb3" != "no"; then + case "$with_mongodb3" in yes | "" ) ;; - * ) GMOCK_PATH=$with_gmock ;; + * ) MONGODB3_PATH=$with_mongodb3 ;; esac - if test "$GMOCK_PATH" != /usr -a -d "$GMOCK_PATH"; then - in_path=" in $GMOCK_PATH" - if test -z "$GMOCK_INCLUDE" -a -d "$GMOCK_PATH/include"; then - GMOCK_INCLUDE="-I$GMOCK_PATH/include" + if test "$MONGODB3_PATH" != /usr -a -d "$MONGODB3_PATH"; then + in_path=" in $MONGODB3_PATH" + if test -z "$MONGODB3_INCLUDE" -a -d "$MONGODB3_PATH/include"; then + MONGODB3_INCLUDE="-I$MONGODB3_PATH/include" fi - if test -n "$GMOCK_LIBPATH"; then + if test -n "$MONGODB3_LIBPATH"; then : - elif test -d "$GMOCK_PATH/lib${bit64_sfx}"; then + elif test -d "$MONGODB3_PATH/lib${bit64_sfx}"; then ncbi_rp_L_flags= ncbi_rp_L_sep=$CONF_f_libpath if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then - for x in $GMOCK_PATH/lib${bit64_sfx}; do + for x in $MONGODB3_PATH/lib${bit64_sfx}; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -45422,11 +46306,11 @@ if test "$with_gmock" != "no"; then ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" ncbi_rp_L_sep=" $CONF_f_libpath" done - GMOCK_LIBPATH="${ncbi_rp_L_flags}" + MONGODB3_LIBPATH="${ncbi_rp_L_flags}" else ncbi_rp_R_flags= ncbi_rp_R_sep=" $CONF_f_runpath" - for x in $GMOCK_PATH/lib${bit64_sfx}; do + for x in $MONGODB3_PATH/lib${bit64_sfx}; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -45438,13 +46322,13 @@ if test "$with_gmock" != "no"; then ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" ncbi_rp_R_sep=: done - GMOCK_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + MONGODB3_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" fi - elif test -d "$GMOCK_PATH/lib"; then + elif test -d "$MONGODB3_PATH/lib"; then ncbi_rp_L_flags= ncbi_rp_L_sep=$CONF_f_libpath if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then - for x in $GMOCK_PATH/lib; do + for x in $MONGODB3_PATH/lib; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -45453,11 +46337,11 @@ if test "$with_gmock" != "no"; then ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" ncbi_rp_L_sep=" $CONF_f_libpath" done - GMOCK_LIBPATH="${ncbi_rp_L_flags}" + MONGODB3_LIBPATH="${ncbi_rp_L_flags}" else ncbi_rp_R_flags= ncbi_rp_R_sep=" $CONF_f_runpath" - for x in $GMOCK_PATH/lib; do + for x in $MONGODB3_PATH/lib; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -45469,35 +46353,296 @@ if test "$with_gmock" != "no"; then ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" ncbi_rp_R_sep=: done - GMOCK_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + MONGODB3_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" fi fi - GMOCK_LIBS="$GMOCK_LIBPATH -lgmock -lgtest" + MONGODB3_LIBS="$MONGODB3_LIBPATH -lmongocxx " else - GMOCK_INCLUDE="" - GMOCK_LIBS="-lgmock -lgtest" + MONGODB3_INCLUDE="" + MONGODB3_LIBS="-lmongocxx " in_path= fi - { echo "$as_me:$LINENO: checking for libgmock$in_path" >&5 -echo $ECHO_N "checking for libgmock$in_path... $ECHO_C" >&6; } -if test "${ncbi_cv_lib_gmock+set}" = set; then + { echo "$as_me:$LINENO: checking for libmongocxx$in_path" >&5 +echo $ECHO_N "checking for libmongocxx$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_mongodb3+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - CPPFLAGS=" $GMOCK_INCLUDE $orig_CPPFLAGS" - LIBS="$GMOCK_LIBS $orig_LIBS" + CPPFLAGS="$MONGODB3_FULL_INCLUDE $BOOST_INCLUDE $MONGODB3_INCLUDE $orig_CPPFLAGS" + LIBS="$MONGODB3_LIBS $MONGODB3_FULL_LIBS $orig_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include +#include int main () { -int my_argc; - char** my_argv; - testing::InitGoogleMock(&my_argc, my_argv); +mongocxx::client mongo_client; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_lib_mongodb3=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_lib_mongodb3=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_mongodb3" >&5 +echo "${ECHO_T}$ncbi_cv_lib_mongodb3" >&6; } + if test "$ncbi_cv_lib_mongodb3" = "no"; then + if test "${with_mongodb3:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-mongodb3 explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-mongodb3 explicitly specified, but no usable version found." >&2;} + { (exit 1); exit 1; }; } + fi + fi + fi + if test "$with_mongodb3" = "no"; then + MONGODB3_PATH="No_MONGODB3" + MONGODB3_INCLUDE= + MONGODB3_LIBS= + else + WithPackages="$WithPackages${WithPackagesSep}MONGODB3"; WithPackagesSep=" " + MONGODB3_INCLUDE="$MONGODB3_FULL_INCLUDE $BOOST_INCLUDE $MONGODB3_INCLUDE" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBMONGODB3 1 +_ACEOF + + fi + + + +if test -n "$MONGODB3_LIBS"; then + MONGODB3_INCLUDE=$MONGODB3_FULL_INCLUDE + MONGODB3_LIBS=$MONGODB3_FULL_LIBS + if test -f $MONGODB3_LIBDIR/libmongocxx-static.a; then + MONGODB3_STATIC_LIBS=`echo "$MONGODB3_LIBS" | \ + sed -e 's/-lmongo[^ ]*/&-static/g; s/-lbson[^ ]*/&-static/g'` + else + MONGODB3_STATIC_LIBS=$MONGODB3_LIBS + fi +fi + + +# Google Mock +case "$with_gmock" in + yes | no | '' ) ;; + * ) GMOCK_PATH=$with_gmock ;; +esac +if test -d "$GMOCK_PATH"; then + ncbi_fix_dir_tmp=`if cd $GMOCK_PATH; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` + case "$ncbi_fix_dir_tmp" in + /.*) ncbi_fix_dir_tmp2=`cd $GMOCK_PATH && $smart_pwd 2>/dev/null` + if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then + GMOCK_PATH=$ncbi_fix_dir_tmp2 + else + case "$GMOCK_PATH" in + /*) ;; + * ) GMOCK_PATH=$ncbi_fix_dir_tmp ;; + esac + fi + ;; + /*) GMOCK_PATH=$ncbi_fix_dir_tmp ;; + esac + for d in "$GMOCK_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx$bit64_sfx/lib" \ + "$GMOCK_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx$bit64_sfx/lib" \ + "$GMOCK_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx/lib" \ + "$GMOCK_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx/lib" \ + "$GMOCK_PATH/lib$bit64_sfx" "$GMOCK_PATH/lib"; do + if test -d "$d"; then + GMOCK_LIBDIR=$d + ncbi_fix_dir_tmp=`if cd $GMOCK_LIBDIR; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` + case "$ncbi_fix_dir_tmp" in + /.*) ncbi_fix_dir_tmp2=`cd $GMOCK_LIBDIR && $smart_pwd 2>/dev/null` + if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then + GMOCK_LIBDIR=$ncbi_fix_dir_tmp2 + else + case "$GMOCK_LIBDIR" in + /*) ;; + * ) GMOCK_LIBDIR=$ncbi_fix_dir_tmp ;; + esac + fi + ;; + /*) GMOCK_LIBDIR=$ncbi_fix_dir_tmp ;; + esac + break + fi + done +fi +ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $GMOCK_LIBDIR; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + GMOCK_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $GMOCK_LIBDIR; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + GMOCK_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi +if test "$with_gmock" != "no"; then + case "$with_gmock" in + yes | "" ) ;; + * ) GMOCK_PATH=$with_gmock ;; + esac + if test "$GMOCK_PATH" != /usr -a -d "$GMOCK_PATH"; then + in_path=" in $GMOCK_PATH" + if test -z "$GMOCK_INCLUDE" -a -d "$GMOCK_PATH/include"; then + GMOCK_INCLUDE="-I$GMOCK_PATH/include" + fi + if test -n "$GMOCK_LIBPATH"; then + : + elif test -d "$GMOCK_PATH/lib${bit64_sfx}"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $GMOCK_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + GMOCK_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $GMOCK_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + GMOCK_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + elif test -d "$GMOCK_PATH/lib"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $GMOCK_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + GMOCK_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $GMOCK_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + GMOCK_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + fi + GMOCK_LIBS="$GMOCK_LIBPATH -lgmock -lgtest" + else + GMOCK_INCLUDE="" + GMOCK_LIBS="-lgmock -lgtest" + in_path= + fi + { echo "$as_me:$LINENO: checking for libgmock$in_path" >&5 +echo $ECHO_N "checking for libgmock$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_gmock+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + CPPFLAGS=" $GMOCK_INCLUDE $orig_CPPFLAGS" + LIBS="$GMOCK_LIBS $orig_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +int my_argc; + char** my_argv; + testing::InitGoogleMock(&my_argc, my_argv); ; return 0; } @@ -46007,62 +47152,1204 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ncbi_cv_lib_lapack=yes + ncbi_cv_lib_lapack=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_lib_lapack=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_lapack" >&5 +echo "${ECHO_T}$ncbi_cv_lib_lapack" >&6; } + if test "$ncbi_cv_lib_lapack" = "no"; then + if test "${with_lapack:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-lapack explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-lapack explicitly specified, but no usable version found." >&2;} + { (exit 1); exit 1; }; } + fi + fi + fi + if test "$with_lapack" = "no"; then + LAPACK_PATH="No_LAPACK" + LAPACK_INCLUDE= + LAPACK_LIBS= + else + WithPackages="$WithPackages${WithPackagesSep}LAPACK"; WithPackagesSep=" " + LAPACK_INCLUDE=" $LAPACK_INCLUDE" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBLAPACK 1 +_ACEOF + + fi + + + + +# LMDB +if test "$with_lmdb" != "no"; then + case "$with_lmdb" in + yes | "" ) ;; + * ) LMDB_PATH=$with_lmdb ;; + esac + if test "$LMDB_PATH" != /usr -a -d "$LMDB_PATH"; then + in_path=" in $LMDB_PATH" + if test -z "$LMDB_INCLUDE" -a -d "$LMDB_PATH/include"; then + LMDB_INCLUDE="-I$LMDB_PATH/include" + fi + if test -n "$LMDB_LIBPATH"; then + : + elif test -d "$LMDB_PATH/lib${bit64_sfx}"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LMDB_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LMDB_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LMDB_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LMDB_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + elif test -d "$LMDB_PATH/lib"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LMDB_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LMDB_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LMDB_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LMDB_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + fi + LMDB_LIBS="$LMDB_LIBPATH -llmdb $THREAD_LIBS" + else + LMDB_INCLUDE="" + LMDB_LIBS="-llmdb $THREAD_LIBS" + in_path= + fi + { echo "$as_me:$LINENO: checking for liblmdb$in_path" >&5 +echo $ECHO_N "checking for liblmdb$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_lmdb+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + CPPFLAGS=" $LMDB_INCLUDE $orig_CPPFLAGS" + LIBS="$LMDB_LIBS $orig_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +MDB_env *env; return mdb_env_create(&env); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_lib_lmdb=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_lib_lmdb=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_lmdb" >&5 +echo "${ECHO_T}$ncbi_cv_lib_lmdb" >&6; } + if test "$ncbi_cv_lib_lmdb" = "no"; then + if test "${with_lmdb:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-lmdb explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-lmdb explicitly specified, but no usable version found." >&2;} + { (exit 1); exit 1; }; } + fi + fi + fi + if test "$with_lmdb" = "no"; then + LMDB_PATH="No_LMDB" + LMDB_INCLUDE= + LMDB_LIBS= + else + WithPackages="$WithPackages${WithPackagesSep}LMDB"; WithPackagesSep=" " + LMDB_INCLUDE=" $LMDB_INCLUDE" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBLMDB 1 +_ACEOF + + fi + + + +if test -z "$LMDB_LIBS"; then + lmdblocal=util/lmdb + { echo "$as_me:$LINENO: using local LMDB copy in $lmdblocal" >&5 +echo "$as_me: using local LMDB copy in $lmdblocal" >&6;} + LMDB_PATH="<$lmdblocal>" + LMDB_INCLUDE="-I\$(includedir)/$lmdblocal -I\$(includedir0)/$lmdblocal" + # In MT builds, ORIG_LIBS already contains THREAD_LIBS. However, + # LMDB is always threaded, and may need explicit THREAD_LIBS when + # used statically. + LMDB_LIBS="$THREAD_LIBS" + # LMDB_LIBS="-llmdb $THREAD_LIBS" + LMDB_LIB="lmdb" + +cat >>confdefs.h <<\_ACEOF +#define USE_LOCAL_LMDB 1 +_ACEOF + + WithPackages="$WithPackages${WithPackagesSep}LMDB"; WithPackagesSep=" " + WithPackages="$WithPackages${WithPackagesSep}LocalLMDB"; WithPackagesSep=" " +fi + +# libuv +case "$with_libuv" in + yes | no | '' ) ;; + * ) LIBUV_PATH=$with_libuv ;; +esac +if test -d "$LIBUV_PATH"; then + ncbi_fix_dir_tmp=`if cd $LIBUV_PATH; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` + case "$ncbi_fix_dir_tmp" in + /.*) ncbi_fix_dir_tmp2=`cd $LIBUV_PATH && $smart_pwd 2>/dev/null` + if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then + LIBUV_PATH=$ncbi_fix_dir_tmp2 + else + case "$LIBUV_PATH" in + /*) ;; + * ) LIBUV_PATH=$ncbi_fix_dir_tmp ;; + esac + fi + ;; + /*) LIBUV_PATH=$ncbi_fix_dir_tmp ;; + esac + for d in "$LIBUV_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx$bit64_sfx/lib" \ + "$LIBUV_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx$bit64_sfx/lib" \ + "$LIBUV_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx/lib" \ + "$LIBUV_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx/lib" \ + "$LIBUV_PATH/lib$bit64_sfx" "$LIBUV_PATH/lib"; do + if test -d "$d"; then + LIBUV_LIBDIR=$d + ncbi_fix_dir_tmp=`if cd $LIBUV_LIBDIR; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` + case "$ncbi_fix_dir_tmp" in + /.*) ncbi_fix_dir_tmp2=`cd $LIBUV_LIBDIR && $smart_pwd 2>/dev/null` + if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then + LIBUV_LIBDIR=$ncbi_fix_dir_tmp2 + else + case "$LIBUV_LIBDIR" in + /*) ;; + * ) LIBUV_LIBDIR=$ncbi_fix_dir_tmp ;; + esac + fi + ;; + /*) LIBUV_LIBDIR=$ncbi_fix_dir_tmp ;; + esac + break + fi + done +fi +ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LIBUV_LIBDIR; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LIBUV_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LIBUV_LIBDIR; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LIBUV_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi +if test "$with_libuv" != "no"; then + case "$with_libuv" in + yes | "" ) ;; + * ) LIBUV_PATH=$with_libuv ;; + esac + if test "$LIBUV_PATH" != /usr -a -d "$LIBUV_PATH"; then + in_path=" in $LIBUV_PATH" + if test -z "$LIBUV_INCLUDE" -a -d "$LIBUV_PATH/include"; then + LIBUV_INCLUDE="-I$LIBUV_PATH/include" + fi + if test -n "$LIBUV_LIBPATH"; then + : + elif test -d "$LIBUV_PATH/lib${bit64_sfx}"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LIBUV_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LIBUV_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LIBUV_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LIBUV_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + elif test -d "$LIBUV_PATH/lib"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LIBUV_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LIBUV_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LIBUV_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LIBUV_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + fi + LIBUV_LIBS="$LIBUV_LIBPATH -luv " + else + LIBUV_INCLUDE="" + LIBUV_LIBS="-luv " + in_path= + fi + { echo "$as_me:$LINENO: checking for libuv$in_path" >&5 +echo $ECHO_N "checking for libuv$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_libuv+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + CPPFLAGS=" $LIBUV_INCLUDE $orig_CPPFLAGS" + LIBS="$LIBUV_LIBS $orig_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +uv_mutex_t m; return uv_mutex_init(&m); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_lib_libuv=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_lib_libuv=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_libuv" >&5 +echo "${ECHO_T}$ncbi_cv_lib_libuv" >&6; } + if test "$ncbi_cv_lib_libuv" = "no"; then + if test "${with_libuv:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-libuv explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-libuv explicitly specified, but no usable version found." >&2;} + { (exit 1); exit 1; }; } + fi + fi + fi + if test "$with_libuv" = "no"; then + LIBUV_PATH="No_LIBUV" + LIBUV_INCLUDE= + LIBUV_LIBS= + else + WithPackages="$WithPackages${WithPackagesSep}LIBUV"; WithPackagesSep=" " + LIBUV_INCLUDE=" $LIBUV_INCLUDE" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBUV 1 +_ACEOF + + fi + + + +if test "$with_libuv" != no -a -f "$LIBUV_LIBDIR/libuv-static.a"; then + LIBUV_STATIC_LIBS="-L$LIBUV_LIBDIR -luv-static" +else + LIBUV_STATIC_LIBS=$LIBUV_LIBS +fi + +# libssh2 +if test -d "$LIBSSH2_PATH"; then + ncbi_fix_dir_tmp=`if cd $LIBSSH2_PATH; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` + case "$ncbi_fix_dir_tmp" in + /.*) ncbi_fix_dir_tmp2=`cd $LIBSSH2_PATH && $smart_pwd 2>/dev/null` + if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then + LIBSSH2_PATH=$ncbi_fix_dir_tmp2 + else + case "$LIBSSH2_PATH" in + /*) ;; + * ) LIBSSH2_PATH=$ncbi_fix_dir_tmp ;; + esac + fi + ;; + /*) LIBSSH2_PATH=$ncbi_fix_dir_tmp ;; + esac + for d in "$LIBSSH2_PATH/$compiler_vpfx$DEBUG_SFX$bit64_sfx/lib" \ + "$LIBSSH2_PATH/$compiler_pfx$DEBUG_SFX$bit64_sfx/lib" \ + "$LIBSSH2_PATH/$compiler_vpfx$DEBUG_SFX/lib" \ + "$LIBSSH2_PATH/$compiler_pfx$DEBUG_SFX/lib" \ + "$LIBSSH2_PATH/lib$bit64_sfx" "$LIBSSH2_PATH/lib"; do + if test -d "$d"; then + LIBSSH2_LIBDIR=$d + ncbi_fix_dir_tmp=`if cd $LIBSSH2_LIBDIR; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` + case "$ncbi_fix_dir_tmp" in + /.*) ncbi_fix_dir_tmp2=`cd $LIBSSH2_LIBDIR && $smart_pwd 2>/dev/null` + if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then + LIBSSH2_LIBDIR=$ncbi_fix_dir_tmp2 + else + case "$LIBSSH2_LIBDIR" in + /*) ;; + * ) LIBSSH2_LIBDIR=$ncbi_fix_dir_tmp ;; + esac + fi + ;; + /*) LIBSSH2_LIBDIR=$ncbi_fix_dir_tmp ;; + esac + break + fi + done +fi +ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LIBSSH2_LIBDIR; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LIBSSH2_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LIBSSH2_LIBDIR; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LIBSSH2_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi +if test "$with_libssh2" != "no"; then + case "$with_libssh2" in + yes | "" ) ;; + * ) LIBSSH2_PATH=$with_libssh2 ;; + esac + if test "$LIBSSH2_PATH" != /usr -a -d "$LIBSSH2_PATH"; then + in_path=" in $LIBSSH2_PATH" + if test -z "$LIBSSH2_INCLUDE" -a -d "$LIBSSH2_PATH/include"; then + LIBSSH2_INCLUDE="-I$LIBSSH2_PATH/include" + fi + if test -n "$LIBSSH2_LIBPATH"; then + : + elif test -d "$LIBSSH2_PATH/lib${bit64_sfx}"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LIBSSH2_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LIBSSH2_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LIBSSH2_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LIBSSH2_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + elif test -d "$LIBSSH2_PATH/lib"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LIBSSH2_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LIBSSH2_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LIBSSH2_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LIBSSH2_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + fi + LIBSSH2_LIBS="$LIBSSH2_LIBPATH -lssh2 $OPENSSL_LIBS" + else + LIBSSH2_INCLUDE="" + LIBSSH2_LIBS="-lssh2 $OPENSSL_LIBS" + in_path= + fi + { echo "$as_me:$LINENO: checking for libssh2$in_path" >&5 +echo $ECHO_N "checking for libssh2$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_libssh2+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + CPPFLAGS=" $LIBSSH2_INCLUDE $orig_CPPFLAGS" + LIBS="$LIBSSH2_LIBS $orig_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +return libssh2_init(LIBSSH2_INIT_NO_CRYPTO); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_lib_libssh2=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_lib_libssh2=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_libssh2" >&5 +echo "${ECHO_T}$ncbi_cv_lib_libssh2" >&6; } + if test "$ncbi_cv_lib_libssh2" = "no"; then + if test "${with_libssh2:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-libssh2 explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-libssh2 explicitly specified, but no usable version found." >&2;} + { (exit 1); exit 1; }; } + fi + fi + fi + if test "$with_libssh2" = "no"; then + LIBSSH2_PATH="No_LIBSSH2" + LIBSSH2_INCLUDE= + LIBSSH2_LIBS= + else + WithPackages="$WithPackages${WithPackagesSep}LIBSSH2"; WithPackagesSep=" " + LIBSSH2_INCLUDE=" $LIBSSH2_INCLUDE" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBSSH2 1 +_ACEOF + + fi + + + +if test "$with_libssh2" != no -a -f "$LIBSSH2_LIBDIR/libssh2-static.a"; then + LIBSSH2_STATIC_LIBS="-L$LIBSSH2_LIBDIR -lssh2-static $OPENSSL_LIBS" +else + LIBSSH2_STATIC_LIBS=$LIBSSH2_LIBS +fi + +# Datastax Cassandra driver +if test -d "$CASSANDRA_PATH"; then + ncbi_fix_dir_tmp=`if cd $CASSANDRA_PATH; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` + case "$ncbi_fix_dir_tmp" in + /.*) ncbi_fix_dir_tmp2=`cd $CASSANDRA_PATH && $smart_pwd 2>/dev/null` + if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then + CASSANDRA_PATH=$ncbi_fix_dir_tmp2 + else + case "$CASSANDRA_PATH" in + /*) ;; + * ) CASSANDRA_PATH=$ncbi_fix_dir_tmp ;; + esac + fi + ;; + /*) CASSANDRA_PATH=$ncbi_fix_dir_tmp ;; + esac + for d in "$CASSANDRA_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx$bit64_sfx" \ + "$CASSANDRA_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx$bit64_sfx" \ + "$CASSANDRA_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx" \ + "$CASSANDRA_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx"; do + if test -d "$d"; then + CASSANDRA_PATH=$d + ncbi_fix_dir_tmp=`if cd $CASSANDRA_PATH; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` + case "$ncbi_fix_dir_tmp" in + /.*) ncbi_fix_dir_tmp2=`cd $CASSANDRA_PATH && $smart_pwd 2>/dev/null` + if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then + CASSANDRA_PATH=$ncbi_fix_dir_tmp2 + else + case "$CASSANDRA_PATH" in + /*) ;; + * ) CASSANDRA_PATH=$ncbi_fix_dir_tmp ;; + esac + fi + ;; + /*) CASSANDRA_PATH=$ncbi_fix_dir_tmp ;; + esac + break + fi + done +fi +if test "$with_cassandra" != "no"; then + case "$with_cassandra" in + yes | "" ) ;; + * ) CASSANDRA_PATH=$with_cassandra ;; + esac + if test "$CASSANDRA_PATH" != /usr -a -d "$CASSANDRA_PATH"; then + in_path=" in $CASSANDRA_PATH" + if test -z "$CASSANDRA_INCLUDE" -a -d "$CASSANDRA_PATH/include"; then + CASSANDRA_INCLUDE="-I$CASSANDRA_PATH/include" + fi + if test -n "$CASSANDRA_LIBPATH"; then + : + elif test -d "$CASSANDRA_PATH/lib${bit64_sfx}"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $CASSANDRA_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + CASSANDRA_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $CASSANDRA_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + CASSANDRA_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + elif test -d "$CASSANDRA_PATH/lib"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $CASSANDRA_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + CASSANDRA_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $CASSANDRA_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + CASSANDRA_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + fi + CASSANDRA_LIBS="$CASSANDRA_LIBPATH -lcassandra $LIBSSH2_LIBS $LIBUV_LIBS" + else + CASSANDRA_INCLUDE="" + CASSANDRA_LIBS="-lcassandra $LIBSSH2_LIBS $LIBUV_LIBS" + in_path= + fi + { echo "$as_me:$LINENO: checking for libcassandra$in_path" >&5 +echo $ECHO_N "checking for libcassandra$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_cassandra+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + CPPFLAGS=" $CASSANDRA_INCLUDE $orig_CPPFLAGS" + LIBS="$CASSANDRA_LIBS $orig_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +CassCluster* c = cass_cluster_new(); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_lib_cassandra=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ncbi_cv_lib_cassandra=no +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_cassandra" >&5 +echo "${ECHO_T}$ncbi_cv_lib_cassandra" >&6; } + if test "$ncbi_cv_lib_cassandra" = "no"; then + if test "${with_cassandra:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-cassandra explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-cassandra explicitly specified, but no usable version found." >&2;} + { (exit 1); exit 1; }; } + fi + fi + fi + if test "$with_cassandra" = "no"; then + CASSANDRA_PATH="No_CASSANDRA" + CASSANDRA_INCLUDE= + CASSANDRA_LIBS= + else + WithPackages="$WithPackages${WithPackagesSep}CASSANDRA"; WithPackagesSep=" " + CASSANDRA_INCLUDE=" $CASSANDRA_INCLUDE" + +cat >>confdefs.h <<\_ACEOF +#define HAVE_LIBCASSANDRA 1 +_ACEOF + + fi + + + +if test "$with_cassandra" != no -a \ + -f "$CASSANDRA_PATH/lib/libcassandra_static.a"; then + CASSANDRA_STATIC_LIBS="-L$CASSANDRA_PATH/lib -lcassandra_static $LIBSSH2_STATIC_LIBS $LIBUV_STATIC_LIBS" +else + CASSANDRA_STATIC_LIBS=$CASSANDRA_LIBS +fi + +if test "$with_libxlsxwriter" != "no"; then + case "$with_libxlsxwriter" in + yes | "" ) ;; + * ) LIBXLSXWRITER_PATH=$with_libxlsxwriter ;; + esac + if test "$LIBXLSXWRITER_PATH" != /usr -a -d "$LIBXLSXWRITER_PATH"; then + in_path=" in $LIBXLSXWRITER_PATH" + if test -z "$LIBXLSXWRITER_INCLUDE" -a -d "$LIBXLSXWRITER_PATH/include"; then + LIBXLSXWRITER_INCLUDE="-I$LIBXLSXWRITER_PATH/include" + fi + if test -n "$LIBXLSXWRITER_LIBPATH"; then + : + elif test -d "$LIBXLSXWRITER_PATH/lib${bit64_sfx}"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LIBXLSXWRITER_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LIBXLSXWRITER_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LIBXLSXWRITER_PATH/lib${bit64_sfx}; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LIBXLSXWRITER_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + elif test -d "$LIBXLSXWRITER_PATH/lib"; then + ncbi_rp_L_flags= + ncbi_rp_L_sep=$CONF_f_libpath + if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then + for x in $LIBXLSXWRITER_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + done + LIBXLSXWRITER_LIBPATH="${ncbi_rp_L_flags}" + else + ncbi_rp_R_flags= + ncbi_rp_R_sep=" $CONF_f_runpath" + for x in $LIBXLSXWRITER_PATH/lib; do + case "$x" in + /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) + continue + ;; + esac + ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" + ncbi_rp_L_sep=" $CONF_f_libpath" + x=`echo $x | sed -e "$ncbi_rpath_sed"` + ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" + ncbi_rp_R_sep=: + done + LIBXLSXWRITER_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + fi + fi + LIBXLSXWRITER_LIBS="$LIBXLSXWRITER_LIBPATH -lxlsxwriter " + else + LIBXLSXWRITER_INCLUDE="" + LIBXLSXWRITER_LIBS="-lxlsxwriter " + in_path= + fi + { echo "$as_me:$LINENO: checking for libxlsxwriter$in_path" >&5 +echo $ECHO_N "checking for libxlsxwriter$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_libxlsxwriter+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + CPPFLAGS=" $LIBXLSXWRITER_INCLUDE $orig_CPPFLAGS" + LIBS="$LIBXLSXWRITER_LIBS $Z_LIBS $orig_LIBS" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +lxw_workbook* wb = workbook_new("conftest.xlsx"); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_cxx_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ncbi_cv_lib_libxlsxwriter=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ncbi_cv_lib_lapack=no + ncbi_cv_lib_libxlsxwriter=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi -{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_lapack" >&5 -echo "${ECHO_T}$ncbi_cv_lib_lapack" >&6; } - if test "$ncbi_cv_lib_lapack" = "no"; then - if test "${with_lapack:=no}" != no; then - { { echo "$as_me:$LINENO: error: --with-lapack explicitly specified, but no usable version found." >&5 -echo "$as_me: error: --with-lapack explicitly specified, but no usable version found." >&2;} +{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_libxlsxwriter" >&5 +echo "${ECHO_T}$ncbi_cv_lib_libxlsxwriter" >&6; } + if test "$ncbi_cv_lib_libxlsxwriter" = "no"; then + if test "${with_libxlsxwriter:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-libxlsxwriter explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-libxlsxwriter explicitly specified, but no usable version found." >&2;} { (exit 1); exit 1; }; } fi fi fi - if test "$with_lapack" = "no"; then - LAPACK_PATH="No_LAPACK" - LAPACK_INCLUDE= - LAPACK_LIBS= + if test "$with_libxlsxwriter" = "no"; then + LIBXLSXWRITER_PATH="No_LIBXLSXWRITER" + LIBXLSXWRITER_INCLUDE= + LIBXLSXWRITER_LIBS= else - WithPackages="$WithPackages${WithPackagesSep}LAPACK"; WithPackagesSep=" " - LAPACK_INCLUDE=" $LAPACK_INCLUDE" + WithPackages="$WithPackages${WithPackagesSep}LIBXLSXWRITER"; WithPackagesSep=" " + LIBXLSXWRITER_INCLUDE=" $LIBXLSXWRITER_INCLUDE" cat >>confdefs.h <<\_ACEOF -#define HAVE_LIBLAPACK 1 +#define HAVE_LIBXLSXWRITER 1 _ACEOF fi +if test "$with_libxlsxwriter" != no -a \ + -f "$LIBXLSXWRITER_PATH/lib/libxlsxwriter-static.a"; then + LIBXLSXWRITER_STATIC_LIBS="-L$LIBXLSXWRITER_PATH/lib -lxlsxwriter-static" +else + LIBXLSXWRITER_STATIC_LIBS=$LIBXLSXWRITER_LIBS +fi -# LMDB -if test "$with_lmdb" != "no"; then - case "$with_lmdb" in +if test -d "$GRPC_PATH"; then + ncbi_fix_dir_tmp=`if cd $GRPC_PATH; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` + case "$ncbi_fix_dir_tmp" in + /.*) ncbi_fix_dir_tmp2=`cd $GRPC_PATH && $smart_pwd 2>/dev/null` + if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then + GRPC_PATH=$ncbi_fix_dir_tmp2 + else + case "$GRPC_PATH" in + /*) ;; + * ) GRPC_PATH=$ncbi_fix_dir_tmp ;; + esac + fi + ;; + /*) GRPC_PATH=$ncbi_fix_dir_tmp ;; + esac + for d in "$GRPC_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx$bit64_sfx" \ + "$GRPC_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx$bit64_sfx" \ + "$GRPC_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx" \ + "$GRPC_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx"; do + if test -d "$d"; then + GRPC_PATH=$d + ncbi_fix_dir_tmp=`if cd $GRPC_PATH; then $as_unset PWD || test "${PWD+set}" != set || { PWD=; export PWD; }; /bin/pwd; fi` + case "$ncbi_fix_dir_tmp" in + /.*) ncbi_fix_dir_tmp2=`cd $GRPC_PATH && $smart_pwd 2>/dev/null` + if test -n "$ncbi_fix_dir_tmp2" -a -d "$ncbi_fix_dir_tmp2"; then + GRPC_PATH=$ncbi_fix_dir_tmp2 + else + case "$GRPC_PATH" in + /*) ;; + * ) GRPC_PATH=$ncbi_fix_dir_tmp ;; + esac + fi + ;; + /*) GRPC_PATH=$ncbi_fix_dir_tmp ;; + esac + break + fi + done +fi +if test "$with_grpc" != "no"; then + case "$with_grpc" in yes | "" ) ;; - * ) LMDB_PATH=$with_lmdb ;; + * ) GRPC_PATH=$with_grpc ;; esac - if test "$LMDB_PATH" != /usr -a -d "$LMDB_PATH"; then - in_path=" in $LMDB_PATH" - if test -z "$LMDB_INCLUDE" -a -d "$LMDB_PATH/include"; then - LMDB_INCLUDE="-I$LMDB_PATH/include" + if test "$GRPC_PATH" != /usr -a -d "$GRPC_PATH"; then + in_path=" in $GRPC_PATH" + if test -z "$GRPC_INCLUDE" -a -d "$GRPC_PATH/include"; then + GRPC_INCLUDE="-I$GRPC_PATH/include" fi - if test -n "$LMDB_LIBPATH"; then + if test -n "$GRPC_LIBPATH"; then : - elif test -d "$LMDB_PATH/lib${bit64_sfx}"; then + elif test -d "$GRPC_PATH/lib${bit64_sfx}"; then ncbi_rp_L_flags= ncbi_rp_L_sep=$CONF_f_libpath if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then - for x in $LMDB_PATH/lib${bit64_sfx}; do + for x in $GRPC_PATH/lib${bit64_sfx}; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -46071,11 +48358,11 @@ if test "$with_lmdb" != "no"; then ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" ncbi_rp_L_sep=" $CONF_f_libpath" done - LMDB_LIBPATH="${ncbi_rp_L_flags}" + GRPC_LIBPATH="${ncbi_rp_L_flags}" else ncbi_rp_R_flags= ncbi_rp_R_sep=" $CONF_f_runpath" - for x in $LMDB_PATH/lib${bit64_sfx}; do + for x in $GRPC_PATH/lib${bit64_sfx}; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -46087,13 +48374,13 @@ if test "$with_lmdb" != "no"; then ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" ncbi_rp_R_sep=: done - LMDB_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + GRPC_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" fi - elif test -d "$LMDB_PATH/lib"; then + elif test -d "$GRPC_PATH/lib"; then ncbi_rp_L_flags= ncbi_rp_L_sep=$CONF_f_libpath if test "x${CONF_f_runpath}" = "x${CONF_f_libpath}"; then - for x in $LMDB_PATH/lib; do + for x in $GRPC_PATH/lib; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -46102,11 +48389,11 @@ if test "$with_lmdb" != "no"; then ncbi_rp_L_flags="${ncbi_rp_L_flags}${ncbi_rp_L_sep}$x" ncbi_rp_L_sep=" $CONF_f_libpath" done - LMDB_LIBPATH="${ncbi_rp_L_flags}" + GRPC_LIBPATH="${ncbi_rp_L_flags}" else ncbi_rp_R_flags= ncbi_rp_R_sep=" $CONF_f_runpath" - for x in $LMDB_PATH/lib; do + for x in $GRPC_PATH/lib; do case "$x" in /lib | /usr/lib | /usr/lib32 | /usr/lib64 | /usr/lib/$multiarch ) continue @@ -46118,33 +48405,33 @@ if test "$with_lmdb" != "no"; then ncbi_rp_R_flags="${ncbi_rp_R_flags}${ncbi_rp_R_sep}$x" ncbi_rp_R_sep=: done - LMDB_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" + GRPC_LIBPATH="${ncbi_rp_L_flags}${ncbi_rp_R_flags}" fi fi - LMDB_LIBS="$LMDB_LIBPATH -llmdb " + GRPC_LIBS="$GRPC_LIBPATH -lgrpc++ -lgrpc -lgpr -lprotobuf$D_SFX -lcares" else - LMDB_INCLUDE="" - LMDB_LIBS="-llmdb " + GRPC_INCLUDE="" + GRPC_LIBS="-lgrpc++ -lgrpc -lgpr -lprotobuf$D_SFX -lcares" in_path= fi - { echo "$as_me:$LINENO: checking for liblmdb$in_path" >&5 -echo $ECHO_N "checking for liblmdb$in_path... $ECHO_C" >&6; } -if test "${ncbi_cv_lib_lmdb+set}" = set; then + { echo "$as_me:$LINENO: checking for libgrpc++$in_path" >&5 +echo $ECHO_N "checking for libgrpc++$in_path... $ECHO_C" >&6; } +if test "${ncbi_cv_lib_grpc+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else - CPPFLAGS=" $LMDB_INCLUDE $orig_CPPFLAGS" - LIBS="$LMDB_LIBS $orig_LIBS" + CPPFLAGS=" $GRPC_INCLUDE $orig_CPPFLAGS" + LIBS="$GRPC_LIBS $OPENSSL_LIBS $Z_LIBS $orig_LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include +#include int main () { -MDB_env *env; return mdb_env_create(&env); +return grpc::Version().size(); ; return 0; } @@ -46183,43 +48470,51 @@ eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); }; }; then - ncbi_cv_lib_lmdb=yes + ncbi_cv_lib_grpc=yes else echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 - ncbi_cv_lib_lmdb=no + ncbi_cv_lib_grpc=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi -{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_lmdb" >&5 -echo "${ECHO_T}$ncbi_cv_lib_lmdb" >&6; } - if test "$ncbi_cv_lib_lmdb" = "no"; then - if test "${with_lmdb:=no}" != no; then - { { echo "$as_me:$LINENO: error: --with-lmdb explicitly specified, but no usable version found." >&5 -echo "$as_me: error: --with-lmdb explicitly specified, but no usable version found." >&2;} +{ echo "$as_me:$LINENO: result: $ncbi_cv_lib_grpc" >&5 +echo "${ECHO_T}$ncbi_cv_lib_grpc" >&6; } + if test "$ncbi_cv_lib_grpc" = "no"; then + if test "${with_grpc:=no}" != no; then + { { echo "$as_me:$LINENO: error: --with-grpc explicitly specified, but no usable version found." >&5 +echo "$as_me: error: --with-grpc explicitly specified, but no usable version found." >&2;} { (exit 1); exit 1; }; } fi fi fi - if test "$with_lmdb" = "no"; then - LMDB_PATH="No_LMDB" - LMDB_INCLUDE= - LMDB_LIBS= + if test "$with_grpc" = "no"; then + GRPC_PATH="No_GRPC" + GRPC_INCLUDE= + GRPC_LIBS= else - WithPackages="$WithPackages${WithPackagesSep}LMDB"; WithPackagesSep=" " - LMDB_INCLUDE=" $LMDB_INCLUDE" + WithPackages="$WithPackages${WithPackagesSep}GRPC"; WithPackagesSep=" " + GRPC_INCLUDE=" $GRPC_INCLUDE" cat >>confdefs.h <<\_ACEOF -#define HAVE_LIBLMDB 1 +#define HAVE_LIBGRPC 1 _ACEOF fi +if test -n "$GRPC_LIBS"; then + GRPC_UNSECURE_LIBS=`echo $GRPC_LIBS | sed -e 's/\(-lgrpc+*\)/\1_unsecure/g'` + GRPC_LIBS="$GRPC_LIBS $OPENSSL_LIBS" + GRPC_REFLECTION_LIBS="$WHOLE_ARCHIVE $NO_AS_NEEDED $GRPC_LIBPATH" + GRPC_REFLECTION_LIBS="$GRPC_REFLECTION_LIBS -lgrpc++_reflection" + GRPC_REFLECTION_LIBS="$GRPC_REFLECTION_LIBS $NO_WHOLE_ARCHIVE $AS_NEEDED" + GRPC_BIN=$GRPC_PATH/bin +fi ### Restore original compiler/linker flags LIBS="$orig_LIBS" @@ -46512,12 +48807,12 @@ else echo "$as_me: error: --with-internal: Cannot build INTERNAL projects: missing $reason" >&2;} { (exit 1); exit 1; }; } else - { echo "$as_me:$LINENO: WARNING: --with-internal: Cannot build all INTERNAL projects: missing $reason" >&5 -echo "$as_me: WARNING: --with-internal: Cannot build all INTERNAL projects: missing $reason" >&2;} + { echo "$as_me:$LINENO: WARNING: --with-internal: Cannot build some INTERNAL projects: missing $reason" >&5 +echo "$as_me: WARNING: --with-internal: Cannot build some INTERNAL projects: missing $reason" >&2;} OPT_GROUPS="$OPT_GROUPS internal" internal="internal" fi - elif test -n "$reason"; then + elif test -n "$reason" -a -z "$with_projects"; then NoConfProjects="$NoConfProjects internal" internal= else @@ -46543,8 +48838,8 @@ if test "$with_gbench" != "no" -a -d "$real_srcdir/src/app/gbench"; then reason="$reason${sep}OpenGL" sep=", " fi - if test "$with_glew_mx" = "no"; then - reason="$reason${sep}GLEWmx" + if test "$with_glew" = "no"; then + reason="$reason${sep}GLEW" sep=", " fi if test "$with_ftgl" = "no"; then @@ -46673,7 +48968,7 @@ for x in ChaosMonkey Int8GI StrictGI GCC KCC ICC VisualAge CompaqCompiler Cray W ;; esac done - for x in UUID FUSE Iconv Z LocalZ BZ2 LocalBZ2 LZO PCRE LocalPCRE GMP GCRYPT NETTLE GNUTLS OPENSSL KRB5 CURL Sybase DBLib FreeTDS MySQL BerkeleyDB BerkeleyDB++ ODBC PYTHON PYTHON25 PYTHON26 PYTHON27 PYTHON3 PERL Boost.Filesystem Boost.Iostreams Boost.Program-Options Boost.Regex Boost.Spirit Boost.System Boost.Test Boost.Test.Included Boost.Thread C-Toolkit OpenGL MESA GLUT GLEW wxWidgets wx2.8 Fast-CGI LocalSSS LocalMSGMAIL2 SSSUTILS LocalNCBILS NCBILS2 SSSDB SP ORBacus ICU EXPAT SABLOT LIBXML LIBXSLT LIBEXSLT Xerces Xalan Zorba SQLITE3 SQLITE3ASYNC VDB OECHEM SGE MUPARSER HDF5 JPEG PNG TIFF UNGIF GIF XPM FreeType FTGL MAGIC MIMETIC GSOAP AVRO Cereal SASL2 MONGODB GMOCK LAPACK LMDB; do + for x in UUID FUSE Iconv LIBUNWIND Z LocalZ BZ2 LocalBZ2 LZO PCRE LocalPCRE MBEDTLS GMP GCRYPT NETTLE GNUTLS OPENSSL KRB5 CURL Sybase DBLib FreeTDS MySQL BerkeleyDB BerkeleyDB++ ODBC PYTHON PYTHON25 PYTHON26 PYTHON27 PYTHON3 PERL Boost.Filesystem Boost.Iostreams Boost.Program-Options Boost.Regex Boost.Spirit Boost.System Boost.Test Boost.Test.Included Boost.Thread C-Toolkit OpenGL MESA GLUT GLEW wxWidgets wx2.8 Fast-CGI LocalSSS LocalMSGMAIL2 SSSUTILS LocalNCBILS NCBILS2 SSSDB SP ORBacus ICU EXPAT SABLOT LIBXML LIBXSLT LIBEXSLT Xerces Xalan Zorba SQLITE3 SQLITE3ASYNC VDB OECHEM SGE MUPARSER HDF5 JPEG PNG TIFF GIF UNGIF XPM FreeType FTGL MAGIC MIMETIC GSOAP AVRO Cereal SASL2 MONGODB MONGODB3 GMOCK LAPACK LMDB LocalLMDB LIBUV LIBSSH2 CASSANDRA LIBXLSXWRITER GRPC; do case " $WithPackages " in *" $x "*) ;; *) WithoutPackages="$WithoutPackages$WithoutPackagesSep$x" @@ -47051,6 +49346,20 @@ c_ncbi_runpath=`echo "$ncbi_runpath" | sed -e 's:\\$\\$:\\$:g'` + + + + + + + + + + + + + + @@ -47638,7 +49947,7 @@ cat >>$CONFIG_STATUS <<_ACEOF # INIT-COMMANDS # -PATH='/bin:/usr/bin:\$PATH' +PATH="$HOME/bin:/bin:/usr/bin:\$PATH" status_dir='$status_dir' builddir='$builddir' build_root='$build_root' @@ -47884,9 +50193,13 @@ for ac_last_try in false false false false false :; do EGREP!$EGREP$ac_delim VALGRIND_PATH!$VALGRIND_PATH$ac_delim LDD!$LDD$ac_delim +UUIDGEN!$UUIDGEN$ac_delim +CD_REPORTER!$CD_REPORTER$ac_delim CXXCPP!$CXXCPP$ac_delim TCHECK_CL!$TCHECK_CL$ac_delim AMQ!$AMQ$ac_delim +LIBUNWIND_INCLUDE!$LIBUNWIND_INCLUDE$ac_delim +LIBUNWIND_LIBS!$LIBUNWIND_LIBS$ac_delim Z_INCLUDE!$Z_INCLUDE$ac_delim Z_LIBS!$Z_LIBS$ac_delim BZ2_INCLUDE!$BZ2_INCLUDE$ac_delim @@ -47895,6 +50208,8 @@ LZO_INCLUDE!$LZO_INCLUDE$ac_delim LZO_LIBS!$LZO_LIBS$ac_delim PCRE_INCLUDE!$PCRE_INCLUDE$ac_delim PCRE_LIBS!$PCRE_LIBS$ac_delim +MBEDTLS_INCLUDE!$MBEDTLS_INCLUDE$ac_delim +MBEDTLS_LIBS!$MBEDTLS_LIBS$ac_delim GMP_INCLUDE!$GMP_INCLUDE$ac_delim GMP_LIBS!$GMP_LIBS$ac_delim LIBGCRYPT_CONFIG!$LIBGCRYPT_CONFIG$ac_delim @@ -47972,12 +50287,6 @@ SGE_LIBS!$SGE_LIBS$ac_delim MUPARSER_INCLUDE!$MUPARSER_INCLUDE$ac_delim MUPARSER_LIBS!$MUPARSER_LIBS$ac_delim HDF5_INCLUDE!$HDF5_INCLUDE$ac_delim -HDF5_LIBS!$HDF5_LIBS$ac_delim -JPEG_INCLUDE!$JPEG_INCLUDE$ac_delim -JPEG_LIBS!$JPEG_LIBS$ac_delim -PNG_INCLUDE!$PNG_INCLUDE$ac_delim -PNG_LIBS!$PNG_LIBS$ac_delim -TIFF_INCLUDE!$TIFF_INCLUDE$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then @@ -48019,11 +50328,17 @@ _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +HDF5_LIBS!$HDF5_LIBS$ac_delim +JPEG_INCLUDE!$JPEG_INCLUDE$ac_delim +JPEG_LIBS!$JPEG_LIBS$ac_delim +PNG_INCLUDE!$PNG_INCLUDE$ac_delim +PNG_LIBS!$PNG_LIBS$ac_delim +TIFF_INCLUDE!$TIFF_INCLUDE$ac_delim TIFF_LIBS!$TIFF_LIBS$ac_delim -UNGIF_INCLUDE!$UNGIF_INCLUDE$ac_delim -UNGIF_LIBS!$UNGIF_LIBS$ac_delim GIF_INCLUDE!$GIF_INCLUDE$ac_delim GIF_LIBS!$GIF_LIBS$ac_delim +UNGIF_INCLUDE!$UNGIF_INCLUDE$ac_delim +UNGIF_LIBS!$UNGIF_LIBS$ac_delim XPM_INCLUDE!$XPM_INCLUDE$ac_delim XPM_LIBS!$XPM_LIBS$ac_delim freetype_config!$freetype_config$ac_delim @@ -48044,12 +50359,24 @@ SASL2_INCLUDE!$SASL2_INCLUDE$ac_delim SASL2_LIBS!$SASL2_LIBS$ac_delim MONGODB_INCLUDE!$MONGODB_INCLUDE$ac_delim MONGODB_LIBS!$MONGODB_LIBS$ac_delim +MONGODB3_INCLUDE!$MONGODB3_INCLUDE$ac_delim +MONGODB3_LIBS!$MONGODB3_LIBS$ac_delim GMOCK_INCLUDE!$GMOCK_INCLUDE$ac_delim GMOCK_LIBS!$GMOCK_LIBS$ac_delim LAPACK_INCLUDE!$LAPACK_INCLUDE$ac_delim LAPACK_LIBS!$LAPACK_LIBS$ac_delim LMDB_INCLUDE!$LMDB_INCLUDE$ac_delim LMDB_LIBS!$LMDB_LIBS$ac_delim +LIBUV_INCLUDE!$LIBUV_INCLUDE$ac_delim +LIBUV_LIBS!$LIBUV_LIBS$ac_delim +LIBSSH2_INCLUDE!$LIBSSH2_INCLUDE$ac_delim +LIBSSH2_LIBS!$LIBSSH2_LIBS$ac_delim +CASSANDRA_INCLUDE!$CASSANDRA_INCLUDE$ac_delim +CASSANDRA_LIBS!$CASSANDRA_LIBS$ac_delim +LIBXLSXWRITER_INCLUDE!$LIBXLSXWRITER_INCLUDE$ac_delim +LIBXLSXWRITER_LIBS!$LIBXLSXWRITER_LIBS$ac_delim +GRPC_INCLUDE!$GRPC_INCLUDE$ac_delim +GRPC_LIBS!$GRPC_LIBS$ac_delim signature!$signature$ac_delim build_root!$build_root$ac_delim top_srcdir!$top_srcdir$ac_delim @@ -48090,32 +50417,14 @@ CFLAGS_DLL!$CFLAGS_DLL$ac_delim CXXFLAGS_DLL!$CXXFLAGS_DLL$ac_delim ALLOW_UNDEF!$ALLOW_UNDEF$ac_delim FORBID_UNDEF!$FORBID_UNDEF$ac_delim +AS_NEEDED!$AS_NEEDED$ac_delim +NO_AS_NEEDED!$NO_AS_NEEDED$ac_delim +WHOLE_ARCHIVE!$WHOLE_ARCHIVE$ac_delim +NO_WHOLE_ARCHIVE!$NO_WHOLE_ARCHIVE$ac_delim OPT_GROUPS!$OPT_GROUPS$ac_delim local_lbsm!$local_lbsm$ac_delim ncbi_crypt!$ncbi_crypt$ac_delim CONNEXT!$CONNEXT$ac_delim -XCONNEXT!$XCONNEXT$ac_delim -serial!$serial$ac_delim -bdb!$bdb$ac_delim -dbapi!$dbapi$ac_delim -objects!$objects$ac_delim -gui!$gui$ac_delim -algo!$algo$ac_delim -app!$app$ac_delim -internal!$internal$ac_delim -check!$check$ac_delim -CHECK_ARG!$CHECK_ARG$ac_delim -CHECK_TOOLS!$CHECK_TOOLS$ac_delim -CHECK_TIMEOUT_MULT!$CHECK_TIMEOUT_MULT$ac_delim -CHECK_OS_NAME!$CHECK_OS_NAME$ac_delim -FEATURES!$FEATURES$ac_delim -script_shell!$script_shell$ac_delim -make_shell!$make_shell$ac_delim -obj_ext!$obj_ext$ac_delim -lib_pre!$lib_pre$ac_delim -lib_l_pre!$lib_l_pre$ac_delim -lib_ext!$lib_ext$ac_delim -dll_ext!$dll_ext$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then @@ -48157,6 +50466,28 @@ _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +XCONNEXT!$XCONNEXT$ac_delim +serial!$serial$ac_delim +bdb!$bdb$ac_delim +dbapi!$dbapi$ac_delim +objects!$objects$ac_delim +gui!$gui$ac_delim +algo!$algo$ac_delim +app!$app$ac_delim +internal!$internal$ac_delim +check!$check$ac_delim +CHECK_ARG!$CHECK_ARG$ac_delim +CHECK_TOOLS!$CHECK_TOOLS$ac_delim +CHECK_TIMEOUT_MULT!$CHECK_TIMEOUT_MULT$ac_delim +CHECK_OS_NAME!$CHECK_OS_NAME$ac_delim +FEATURES!$FEATURES$ac_delim +script_shell!$script_shell$ac_delim +make_shell!$make_shell$ac_delim +obj_ext!$obj_ext$ac_delim +lib_pre!$lib_pre$ac_delim +lib_l_pre!$lib_l_pre$ac_delim +lib_ext!$lib_ext$ac_delim +dll_ext!$dll_ext$ac_delim loadable_ext!$loadable_ext$ac_delim lib_l_ext!$lib_l_ext$ac_delim exe_ext!$exe_ext$ac_delim @@ -48168,6 +50499,7 @@ f_runpath!$f_runpath$ac_delim f_outexe!$f_outexe$ac_delim BDB_LIB!$BDB_LIB$ac_delim BDB_CACHE_LIB!$BDB_CACHE_LIB$ac_delim +SQLITE3_WRAPPER!$SQLITE3_WRAPPER$ac_delim DBAPI_DRIVER!$DBAPI_DRIVER$ac_delim DBAPI_CTLIB!$DBAPI_CTLIB$ac_delim DBAPI_DBLIB!$DBAPI_DBLIB$ac_delim @@ -48200,8 +50532,6 @@ BZ2_LIB!$BZ2_LIB$ac_delim PCREPOSIX_LIBS!$PCREPOSIX_LIBS$ac_delim PCRE_LIB!$PCRE_LIB$ac_delim OPENSSL_STATIC_LIBS!$OPENSSL_STATIC_LIBS$ac_delim -TLS_INCLUDE!$TLS_INCLUDE$ac_delim -TLS_LIBS!$TLS_LIBS$ac_delim SYBASE_PATH!$SYBASE_PATH$ac_delim SYBASE_LCL_PATH!$SYBASE_LCL_PATH$ac_delim SYBASE_INCLUDE!$SYBASE_INCLUDE$ac_delim @@ -48233,27 +50563,6 @@ BOOST_SYSTEM_STATIC_LIBS!$BOOST_SYSTEM_STATIC_LIBS$ac_delim BOOST_TEST_PEM_LIBS!$BOOST_TEST_PEM_LIBS$ac_delim BOOST_TEST_PEM_STATIC_LIBS!$BOOST_TEST_PEM_STATIC_LIBS$ac_delim BOOST_TEST_TEM_LIBS!$BOOST_TEST_TEM_LIBS$ac_delim -BOOST_TEST_TEM_STATIC_LIBS!$BOOST_TEST_TEM_STATIC_LIBS$ac_delim -BOOST_TEST_UTF_LIBS!$BOOST_TEST_UTF_LIBS$ac_delim -BOOST_TEST_UTF_STATIC_LIBS!$BOOST_TEST_UTF_STATIC_LIBS$ac_delim -BOOST_THREAD_LIBS!$BOOST_THREAD_LIBS$ac_delim -BOOST_THREAD_STATIC_LIBS!$BOOST_THREAD_STATIC_LIBS$ac_delim -NCBI_C_INCLUDE!$NCBI_C_INCLUDE$ac_delim -NCBI_C_LIBPATH!$NCBI_C_LIBPATH$ac_delim -OPENGL_INCLUDE!$OPENGL_INCLUDE$ac_delim -OPENGL_LIBS!$OPENGL_LIBS$ac_delim -OPENGL_STATIC_LIBS!$OPENGL_STATIC_LIBS$ac_delim -OSMESA_INCLUDE!$OSMESA_INCLUDE$ac_delim -OSMESA_LIBS!$OSMESA_LIBS$ac_delim -OSMESA_STATIC_LIBS!$OSMESA_STATIC_LIBS$ac_delim -GLUT_INCLUDE!$GLUT_INCLUDE$ac_delim -GLUT_LIBS!$GLUT_LIBS$ac_delim -GLEW_INCLUDE!$GLEW_INCLUDE$ac_delim -GLEW_LIBS!$GLEW_LIBS$ac_delim -GLEW_STATIC_LIBS!$GLEW_STATIC_LIBS$ac_delim -WXWIDGETS_INCLUDE!$WXWIDGETS_INCLUDE$ac_delim -WXWIDGETS_LIBS!$WXWIDGETS_LIBS$ac_delim -WXWIDGETS_STATIC_LIBS!$WXWIDGETS_STATIC_LIBS$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then @@ -48295,6 +50604,27 @@ _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +BOOST_TEST_TEM_STATIC_LIBS!$BOOST_TEST_TEM_STATIC_LIBS$ac_delim +BOOST_TEST_UTF_LIBS!$BOOST_TEST_UTF_LIBS$ac_delim +BOOST_TEST_UTF_STATIC_LIBS!$BOOST_TEST_UTF_STATIC_LIBS$ac_delim +BOOST_THREAD_LIBS!$BOOST_THREAD_LIBS$ac_delim +BOOST_THREAD_STATIC_LIBS!$BOOST_THREAD_STATIC_LIBS$ac_delim +NCBI_C_INCLUDE!$NCBI_C_INCLUDE$ac_delim +NCBI_C_LIBPATH!$NCBI_C_LIBPATH$ac_delim +OPENGL_INCLUDE!$OPENGL_INCLUDE$ac_delim +OPENGL_LIBS!$OPENGL_LIBS$ac_delim +OPENGL_STATIC_LIBS!$OPENGL_STATIC_LIBS$ac_delim +OSMESA_INCLUDE!$OSMESA_INCLUDE$ac_delim +OSMESA_LIBS!$OSMESA_LIBS$ac_delim +OSMESA_STATIC_LIBS!$OSMESA_STATIC_LIBS$ac_delim +GLUT_INCLUDE!$GLUT_INCLUDE$ac_delim +GLUT_LIBS!$GLUT_LIBS$ac_delim +GLEW_INCLUDE!$GLEW_INCLUDE$ac_delim +GLEW_LIBS!$GLEW_LIBS$ac_delim +GLEW_STATIC_LIBS!$GLEW_STATIC_LIBS$ac_delim +WXWIDGETS_INCLUDE!$WXWIDGETS_INCLUDE$ac_delim +WXWIDGETS_LIBS!$WXWIDGETS_LIBS$ac_delim +WXWIDGETS_STATIC_LIBS!$WXWIDGETS_STATIC_LIBS$ac_delim WXWIDGETS_GL_LIBS!$WXWIDGETS_GL_LIBS$ac_delim WXWIDGETS_GL_STATIC_LIBS!$WXWIDGETS_GL_STATIC_LIBS$ac_delim WXWIDGETS_POST_LINK!$WXWIDGETS_POST_LINK$ac_delim @@ -48352,6 +50682,15 @@ GSOAP_PATH!$GSOAP_PATH$ac_delim AVRO_STATIC_LIBS!$AVRO_STATIC_LIBS$ac_delim CEREAL_INCLUDE!$CEREAL_INCLUDE$ac_delim MONGODB_STATIC_LIBS!$MONGODB_STATIC_LIBS$ac_delim +MONGODB3_STATIC_LIBS!$MONGODB3_STATIC_LIBS$ac_delim +LMDB_LIB!$LMDB_LIB$ac_delim +LIBUV_STATIC_LIBS!$LIBUV_STATIC_LIBS$ac_delim +LIBSSH2_STATIC_LIBS!$LIBSSH2_STATIC_LIBS$ac_delim +CASSANDRA_STATIC_LIBS!$CASSANDRA_STATIC_LIBS$ac_delim +LIBXLSXWRITER_STATIC_LIBS!$LIBXLSXWRITER_STATIC_LIBS$ac_delim +GRPC_UNSECURE_LIBS!$GRPC_UNSECURE_LIBS$ac_delim +GRPC_REFLECTION_LIBS!$GRPC_REFLECTION_LIBS$ac_delim +GRPC_BIN!$GRPC_BIN$ac_delim ncbi_xreader_pubseqos!$ncbi_xreader_pubseqos$ac_delim ncbi_xreader_pubseqos2!$ncbi_xreader_pubseqos2$ac_delim UNLESS_PUBSEQOS!$UNLESS_PUBSEQOS$ac_delim @@ -48362,36 +50701,6 @@ JDK_INCLUDE!$JDK_INCLUDE$ac_delim ncbi_java!$ncbi_java$ac_delim NCBI_C_ncbi!$NCBI_C_ncbi$ac_delim BINCOPY!$BINCOPY$ac_delim -APP_NOCOPY!$APP_NOCOPY$ac_delim -APP_OR_NULL!$APP_OR_NULL$ac_delim -IF_REBUILDING_LIBS!$IF_REBUILDING_LIBS$ac_delim -IF_REBUILDING_CONDITIONALLY!$IF_REBUILDING_CONDITIONALLY$ac_delim -IF_DEACTIVATING!$IF_DEACTIVATING$ac_delim -configurables_mfname!$configurables_mfname$ac_delim -CC_FILTER!$CC_FILTER$ac_delim -CXX_FILTER!$CXX_FILTER$ac_delim -AR_FILTER!$AR_FILTER$ac_delim -LINK_FILTER!$LINK_FILTER$ac_delim -CC_WRAPPER!$CC_WRAPPER$ac_delim -CXX_WRAPPER!$CXX_WRAPPER$ac_delim -AR_WRAPPER!$AR_WRAPPER$ac_delim -LINK_WRAPPER!$LINK_WRAPPER$ac_delim -KeepStateTarget!$KeepStateTarget$ac_delim -Rules!$Rules$ac_delim -serial_ws50_rtti_kludge!$serial_ws50_rtti_kludge$ac_delim -ncbicntr!$ncbicntr$ac_delim -UNIX_SRC!$UNIX_SRC$ac_delim -UNIX_USR_PROJ!$UNIX_USR_PROJ$ac_delim -compiler!$compiler$ac_delim -compiler_root!$compiler_root$ac_delim -compiler_version!$compiler_version$ac_delim -COMPILER!$COMPILER$ac_delim -OSTYPE!$OSTYPE$ac_delim -NCBI_PLATFORM_BITS!$NCBI_PLATFORM_BITS$ac_delim -NCBI_TEAMCITY_BUILD_NUMBER!$NCBI_TEAMCITY_BUILD_NUMBER$ac_delim -NCBI_SUBVERSION_REVISION!$NCBI_SUBVERSION_REVISION$ac_delim -NCBI_SC_VERSION!$NCBI_SC_VERSION$ac_delim -LIBOBJS!$LIBOBJS$ac_delim _ACEOF if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 97; then @@ -48433,10 +50742,42 @@ _ACEOF ac_delim='%!_!# ' for ac_last_try in false false false false false :; do cat >conf$$subs.sed <<_ACEOF +APP_NOCOPY!$APP_NOCOPY$ac_delim +APP_OR_NULL!$APP_OR_NULL$ac_delim +IF_REBUILDING_LIBS!$IF_REBUILDING_LIBS$ac_delim +IF_REBUILDING_CONDITIONALLY!$IF_REBUILDING_CONDITIONALLY$ac_delim +IF_DEACTIVATING!$IF_DEACTIVATING$ac_delim +configurables_mfname!$configurables_mfname$ac_delim +CC_FILTER!$CC_FILTER$ac_delim +CXX_FILTER!$CXX_FILTER$ac_delim +AR_FILTER!$AR_FILTER$ac_delim +LINK_FILTER!$LINK_FILTER$ac_delim +CC_WRAPPER!$CC_WRAPPER$ac_delim +CXX_WRAPPER!$CXX_WRAPPER$ac_delim +AR_WRAPPER!$AR_WRAPPER$ac_delim +LINK_WRAPPER!$LINK_WRAPPER$ac_delim +KeepStateTarget!$KeepStateTarget$ac_delim +Rules!$Rules$ac_delim +serial_ws50_rtti_kludge!$serial_ws50_rtti_kludge$ac_delim +ncbicntr!$ncbicntr$ac_delim +UNIX_SRC!$UNIX_SRC$ac_delim +UNIX_USR_PROJ!$UNIX_USR_PROJ$ac_delim +compiler!$compiler$ac_delim +compiler_root!$compiler_root$ac_delim +compiler_version!$compiler_version$ac_delim +COMPILER!$COMPILER$ac_delim +OSTYPE!$OSTYPE$ac_delim +NCBI_PLATFORM_BITS!$NCBI_PLATFORM_BITS$ac_delim +NCBI_TEAMCITY_BUILD_NUMBER!$NCBI_TEAMCITY_BUILD_NUMBER$ac_delim +NCBI_TEAMCITY_PROJECT_NAME!$NCBI_TEAMCITY_PROJECT_NAME$ac_delim +NCBI_TEAMCITY_BUILDCONF_NAME!$NCBI_TEAMCITY_BUILDCONF_NAME$ac_delim +NCBI_SUBVERSION_REVISION!$NCBI_SUBVERSION_REVISION$ac_delim +NCBI_SC_VERSION!$NCBI_SC_VERSION$ac_delim +LIBOBJS!$LIBOBJS$ac_delim LTLIBOBJS!$LTLIBOBJS$ac_delim _ACEOF - if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 1; then + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 33; then break elif $ac_last_try; then { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 @@ -48885,6 +51226,7 @@ echo "$as_me: executing $ac_file commands" >&6;} find "$build_root/." -name '*.sh' -print | while read x_file ; do chmod a+x "$x_file" done +chmod a+x "$build_root/build/run_with_cd_reporter.py" if test -f config.cache -a -f config.log ; then test -d "$status_dir" || mkdir -p "$status_dir" @@ -48958,6 +51300,9 @@ done (cd $builddir/build-system/helpers && $MAKE -k) +random_macro="$build_root/inc/ncbi_random_macro.h" +rm -f $random_macro + if test "$with_configure_dialog" = yes; then if test "$with_flat_makefile" = no; then { { echo "$as_me:$LINENO: error: incompatible options: --without-flat-makefile but --with-configure-dialog." >&5 @@ -48999,6 +51344,10 @@ echo "$as_me: error: flat makefile generation failed." >&2;} fi fi +if test ! -f "$random_macro"; then + $real_srcdir/scripts/common/impl/define_random_macros.sh >$random_macro +fi + if test -n "$with_extra_action" ; then with_extra_action=`echo "$with_extra_action" | sed "s%{}%$build_root%g"` echo diff --git a/c++/src/build-system/configure.ac b/c++/src/build-system/configure.ac index 73537f01..4df14936 100644 --- a/c++/src/build-system/configure.ac +++ b/c++/src/build-system/configure.ac @@ -1,5 +1,5 @@ ############################################################################# -# $Id: configure.ac 521038 2016-12-05 16:02:28Z ivanov $ +# $Id: configure.ac 548844 2017-10-18 15:21:39Z ivanov $ # Derived from configure.in version 1.173. # ========================================================================== # @@ -64,14 +64,17 @@ case "$with_3psw" in else with_ncbi_c=no fi - m4_foreach(X, [sss, sssutils, sssdb, vdb, z, bz2, lzo, pcre, + m4_foreach(X, [sss, sssutils, sssdb, vdb, libunwind, + z, bz2, lzo, pcre, mbedtls, gmp, gcrypt, nettle, gnutls, openssl, krb5, boost, lmdb, sybase, ftds, mysql, opengl, mesa, glut, glew, wxwidgets, freetype, ftgl, fastcgi, bdb, orbacus, odbc, python, perl, jni, sqlite3, mimetic, sge, icu, sp, expat, sablot, libxml, libxslt, libexslt, xerces, xalan, zorba, oechem, muparser, hdf5, gif, jpeg, png, tiff, xpm, magic, - curl, gsoap, avro, cereal, sasl2, mongodb, gmock, lapack], + curl, gsoap, avro, cereal, sasl2, + mongodb, mongodb3, gmock, lapack, + libuv, libssh2, cassandra, libxlsxwriter, grpc], [if test "${[with_]X-no}" != "no"; then AC_MSG_ERROR([incompatible options: --with-]X[ but --without-3psw]) else @@ -109,11 +112,11 @@ AC_CONFIG_SRCDIR(src/build-system/Makefile.mk.in) #### Describe all "--with-*" arguments -- for the usage printout on "--help" ## Title -AC_ARG_WITH(title0, +AC_ARG_WITH(_, [===============================================================================]) -AC_ARG_WITH(title1, +AC_ARG_WITH(_, [=============== NCBI C++ Toolkit specific configuration flags =================]) -AC_ARG_WITH(title2, +AC_ARG_WITH(_, [===============================================================================]) ## Code generation @@ -125,8 +128,12 @@ AC_ARG_WITH(symbols, [ --with-symbols retain debugging symbols in non-debug mode]) AC_ARG_WITH(optimization, [ --without-optimization turn off optimization flags in non-debug mode]) +AC_ARG_WITH(sse42, + [ --without-sse42 don't enable SSE 4.2 when optimizing]) AC_ARG_WITH(profiling, [ --with-profiling build profiled versions of libs and apps]) +AC_ARG_WITH(code-coverage, + [ --with-code-coverage track which code blocks have been exercised]) AC_ARG_WITH(tcheck, [ --with-tcheck(=DIR) build for Intel Thread Checker (in DIR)]) AC_ARG_WITH(dll, @@ -185,7 +192,7 @@ AC_ARG_WITH(bincopy, [ --with-bincopy populate lib and bin with copies, not hard links]) AC_ARG_WITH(lib-rebuilds, [ --with-lib-rebuilds ensure that apps use up-to-date libraries]) -AC_ARG_WITH(lib-rebuilds2, +AC_ARG_WITH(lib-rebuilds, [ --with-lib-rebuilds=ask ask whether to update each app's libraries])dnl' AC_ARG_WITH(deactivation, [ --without-deactivation keep old copies of libraries that no longer build]) @@ -211,7 +218,7 @@ AC_ARG_WITH(pch, [ --with-pch use precompiled headers if possible]) AC_ARG_WITH(caution, [ --with-caution cancel configuration unconditionally when in doubt]) -AC_ARG_WITH(caution2, +AC_ARG_WITH(caution, [ --without-caution proceed without asking when in doubt]) AC_ARG_WITH(ccache, [ --without-ccache do not automatically use ccache if available]) @@ -221,11 +228,11 @@ AC_ARG_WITH(distcc, ## NCBI packages AC_ARG_WITH(ncbi-c, [ --with-ncbi-c=DIR use NCBI C Toolkit installation in DIR]) -AC_ARG_WITH(ncbi-c2, +AC_ARG_WITH(ncbi-c, [ --without-ncbi-c do not use NCBI C Toolkit]) AC_ARG_WITH(sss, [ --with-sss=DIR use NCBI SSS installation in DIR]) -AC_ARG_WITH(sss2, +AC_ARG_WITH(sss, [ --without-sss do not use NCBI SSS libraries]) AC_ARG_WITH(sssutils, [ --without-utils do not use NCBI SSS UTIL library]) @@ -235,7 +242,7 @@ AC_ARG_WITH(included-sss, [ --with-included-sss use the in-tree copy of SSS]) AC_ARG_WITH(vdb, [ --with-vdb=DIR use NCBI SRA/VDB Toolkit installation in DIR]) -AC_ARG_WITH(vdb2, +AC_ARG_WITH(vdb, [ --without-vdb do not use the NCBI SRA/VDB Toolkit]) AC_ARG_WITH(downloaded-vdb, [ --with-downloaded-vdb download and build SRA/VDB from GitHub]) @@ -243,47 +250,51 @@ AC_ARG_WITH(static-vdb, [ --with-static-vdb always link statically against SRA/VDB]) ## Third-party and system packages +AC_ARG_WITH(libunwind, + [ --with-libunwind(=DIR) use libunwind (in DIR)]) AC_ARG_WITH(z, [ --with-z=DIR use zlib installation in DIR]) -AC_ARG_WITH(z2, +AC_ARG_WITH(z, [ --without-z use internal copy of zlib]) AC_ARG_WITH(bz2, [ --with-bz2=DIR use bzlib installation in DIR]) -AC_ARG_WITH(bz2b, +AC_ARG_WITH(bz2, [ --without-bz2 use internal copy of bzlib]) AC_ARG_WITH(lzo, [ --with-lzo=DIR use LZO installation in DIR (requires 2.x or up)]) -AC_ARG_WITH(lzo_, +AC_ARG_WITH(lzo, [ --without-lzo do not use LZO]) AC_ARG_WITH(pcre, [ --with-pcre=DIR use PCRE installation in DIR]) -AC_ARG_WITH(pcre2, +AC_ARG_WITH(pcre, [ --without-pcre use internal copy of PCRE]) +AC_ARG_WITH(mbedtls, + [ --with-mbedtls(=DIR) use external mbedTLS installation (in DIR)]) AC_ARG_WITH(gmp, [ --with-gmp=DIR use GMP installation in DIR]) -AC_ARG_WITH(gmp2, +AC_ARG_WITH(gmp, [ --without-gmp do not use GMP]) AC_ARG_WITH(gcrypt, [ --with-gcrypt=DIR use gcrypt installation in DIR]) -AC_ARG_WITH(gcrypt2, +AC_ARG_WITH(gcrypt, [ --without-gcrypt do not use gcrypt]) AC_ARG_WITH(nettle, [ --with-nettle=DIR use Nettle installation in DIR]) -AC_ARG_WITH(nettle2, +AC_ARG_WITH(nettle, [ --without-nettle do not use Nettle]) AC_ARG_WITH(gnutls, [ --with-gnutls=DIR use GNUTLS installation in DIR]) -AC_ARG_WITH(gnutls2, +AC_ARG_WITH(gnutls, [ --without-gnutls do not use GNUTLS]) AC_ARG_WITH(static-gnutls, [ --with-static-gnutls link GNUTLS statically if possible]) AC_ARG_WITH(openssl, [ --with-openssl=DIR use OpenSSL installation in DIR]) -AC_ARG_WITH(openssl2, +AC_ARG_WITH(openssl, [ --without-openssl do not use OpenSSL]) AC_ARG_WITH(krb5, [ --with-krb5=DIR use Kerberos 5 installation in DIR]) -AC_ARG_WITH(krb5b, +AC_ARG_WITH(krb5, [ --without-krb5 do not use Kerberos 5]) AC_ARG_WITH(sybase, [ --without-sybase do not use SYBASE libraries]) @@ -293,53 +304,53 @@ AC_ARG_WITH(sybase-new, [ --with-sybase-new use newer SYBASE install (12.5 rather than 12.0)]) AC_ARG_WITH(ftds, [ --without-ftds do not use FreeTDS libraries]) -AC_ARG_WITH(ftds2, +AC_ARG_WITH(ftds, [ --with-ftds=DIR use FreeTDS installation in DIR]) AC_ARG_WITH(ftds-renamed, [ --without-ftds-renamed do not rename Sybase DBLIB symbols in built-in FTDS]) AC_ARG_WITH(mysql, [ --without-mysql do not use MySQL]) -AC_ARG_WITH(mysql2, +AC_ARG_WITH(mysql, [ --with-mysql=DIR use MySQL installation in DIR]) AC_ARG_WITH(opengl, [ --without-opengl do not use OpenGL]) -AC_ARG_WITH(opengl2, +AC_ARG_WITH(opengl, [ --with-opengl=DIR use OpenGL installation in DIR]) AC_ARG_WITH(mesa, [ --without-mesa do not use MESA off-screen OpenGL]) -AC_ARG_WITH(mesa2, +AC_ARG_WITH(mesa, [ --with-mesa=DIR use MESA installation in DIR]) AC_ARG_WITH(glut, [ --without-glut do not use GLUT]) -AC_ARG_WITH(glut2, +AC_ARG_WITH(glut, [ --with-glut=DIR use GLUT installation in DIR]) AC_ARG_WITH(glew, [ --without-glew do not use GLEW]) -AC_ARG_WITH(glew2, +AC_ARG_WITH(glew, [ --with-glew=DIR use GLEW installation in DIR]) AC_ARG_WITH(glew-mx, [ --with-glew-mx insist on a multi-context-ready GLEW installation]) AC_ARG_WITH(wxwidgets, [ --without-wxwidgets do not use wxWidgets (2.6+)]) -AC_ARG_WITH(wxwidgets2, +AC_ARG_WITH(wxwidgets, [ --with-wxwidgets=DIR use wxWidgets installation in DIR]) AC_ARG_WITH(wxwidgets-ucs, [ --with-wxwidgets-ucs use Unicode builds of wxWidgets]) -AC_ARG_WITH(wxwidgets-ucs2, +AC_ARG_WITH(wxwidgets-ucs, [ --without-wxwidgets-ucs do not use Unicode builds of wxWidgets]) AC_ARG_WITH(freetype, [ --without-freetype do not use FreeType]) -AC_ARG_WITH(freetype_, +AC_ARG_WITH(freetype, [ --with-freetype=DIR use FreeType installation in DIR]) AC_ARG_WITH(ftgl, [ --without-ftgl do not use FTGL]) -AC_ARG_WITH(ftgl2, +AC_ARG_WITH(ftgl, [ --with-ftgl=DIR use FTGL installation in DIR]) AC_ARG_WITH(fastcgi, [ --without-fastcgi do not use Fast-CGI library]) -AC_ARG_WITH(fastcgi2, +AC_ARG_WITH(fastcgi, [ --with-fastcgi=VERSION use Fast-CGI installation in \$NCBI/fcgi-VERSION]) -AC_ARG_WITH(fastcgi3, +AC_ARG_WITH(fastcgi, [ --with-fastcgi=DIR use Fast-CGI installation in DIR]) AC_ARG_WITH(bdb, [ --without-bdb do not use Berkeley DB library]) @@ -351,151 +362,175 @@ AC_ARG_WITH(sp, [ --without-sp do not use SP libraries]) AC_ARG_WITH(orbacus, [ --without-orbacus do not use ORBacus CORBA libraries]) -AC_ARG_WITH(orbacus2, +AC_ARG_WITH(orbacus, [ --with-orbacus=DIR use ORBacus installation in DIR]) AC_ARG_WITH(odbc, [ --with-odbc=DIR use ODBC installation in DIR]) AC_ARG_WITH(python, [ --with-python=DIR use Python installation in DIR]) -AC_ARG_WITH(python2, +AC_ARG_WITH(python, [ --without-python do not use Python]) AC_ARG_WITH(perl, [ --with-perl=DIR use Perl installation in DIR]) -AC_ARG_WITH(perl2, +AC_ARG_WITH(perl, [ --without-perl do not use Perl]) AC_ARG_WITH(jni, [ --with-jni(=JDK-DIR) build Java bindings (against the JDK in JDK-DIR)]) AC_ARG_WITH(boost, [ --with-boost=DIR use Boost installation in DIR]) -AC_ARG_WITH(boost2, +AC_ARG_WITH(boost, [ --without-boost do not use Boost]) AC_ARG_WITH(boost-tag, [ --with-boost-tag=TAG use TAG as the tag appended to Boost library names]) -AC_ARG_WITH(boost-tag2, +AC_ARG_WITH(boost-tag, [ --without-boost-tag use untagged Boost library names]) AC_ARG_WITH(sqlite3, [ --with-sqlite3=DIR use SQLite 3.x installation in DIR]) -AC_ARG_WITH(sqlite3b, +AC_ARG_WITH(sqlite3, [ --without-sqlite3 do not use SQLite 3.x]) AC_ARG_WITH(icu, [ --with-icu=DIR use ICU installation in DIR]) -AC_ARG_WITH(icu2, +AC_ARG_WITH(icu, [ --without-icu do not use ICU]) AC_ARG_WITH(expat, [ --with-expat=DIR use Expat installation in DIR]) -AC_ARG_WITH(expat2, +AC_ARG_WITH(expat, [ --without-expat do not use Expat]) AC_ARG_WITH(sablot, [ --with-sablot=DIR use Sablotron installation in DIR]) -AC_ARG_WITH(sablot2, +AC_ARG_WITH(sablot, [ --without-sablot do not use Sablotron]) AC_ARG_WITH(libxml, [ --with-libxml=DIR use libxml2 installation in DIR]) -AC_ARG_WITH(libxml_, +AC_ARG_WITH(libxml, [ --without-libxml do not use libxml2]) AC_ARG_WITH(libxslt, [ --with-libxslt=DIR use libxslt installation in DIR]) -AC_ARG_WITH(libxslt2, +AC_ARG_WITH(libxslt, [ --without-libxslt do not use libxslt]) AC_ARG_WITH(libexslt, [ --with-libexslt=DIR use libexslt installation in DIR]) -AC_ARG_WITH(libexslt2, +AC_ARG_WITH(libexslt, [ --without-libexslt do not use libexslt]) AC_ARG_WITH(xerces, [ --with-xerces=DIR use Xerces-C++ installation in DIR]) -AC_ARG_WITH(xerces2, +AC_ARG_WITH(xerces, [ --without-xerces do not use Xerces-C++]) AC_ARG_WITH(xalan, [ --with-xalan=DIR use Xalan-C++ installation in DIR]) -AC_ARG_WITH(xalan2, +AC_ARG_WITH(xalan, [ --without-xalan do not use Xalan-C++]) AC_ARG_WITH(zorba, [ --with-zorba=DIR use Zorba installation in DIR]) -AC_ARG_WITH(zorba2, +AC_ARG_WITH(zorba, [ --without-zorba do not use Zorba]) AC_ARG_WITH(oechem, [ --with-oechem=DIR use OpenEye OEChem installation in DIR]) -AC_ARG_WITH(oechem2, +AC_ARG_WITH(oechem, [ --without-oechem do not use OEChem]) AC_ARG_WITH(sge, [ --with-sge=DIR use Sun/Univa Grid Engine installation in DIR]) -AC_ARG_WITH(sge2, +AC_ARG_WITH(sge, [ --without-sge do not use Sun/Univa Grid Engine]) AC_ARG_WITH(muparser, [ --with-muparser=DIR use muParser installation in DIR]) -AC_ARG_WITH(muparser2, +AC_ARG_WITH(muparser, [ --without-muparser do not use muParser]) AC_ARG_WITH(hdf5, [ --with-hdf5=DIR use HDF5 installation in DIR]) -AC_ARG_WITH(hdf5b, +AC_ARG_WITH(hdf5, [ --without-hdf5 do not use HDF5]) AC_ARG_WITH(gif, [ --with-gif=DIR use lib(un)gif installation in DIR]) -AC_ARG_WITH(gif2, +AC_ARG_WITH(gif, [ --without-gif do not use lib(un)gif]) AC_ARG_WITH(jpeg, [ --with-jpeg=DIR use libjpeg installation in DIR]) -AC_ARG_WITH(jpeg2, +AC_ARG_WITH(jpeg, [ --without-jpeg do not use libjpeg]) AC_ARG_WITH(png, [ --with-png=DIR use libpng installation in DIR]) -AC_ARG_WITH(png2, +AC_ARG_WITH(png, [ --without-png do not use libpng]) AC_ARG_WITH(tiff, [ --with-tiff=DIR use libtiff installation in DIR]) -AC_ARG_WITH(tiff2, +AC_ARG_WITH(tiff, [ --without-tiff do not use libtiff]) AC_ARG_WITH(xpm, [ --with-xpm=DIR use libXpm installation in DIR]) -AC_ARG_WITH(xpm2, +AC_ARG_WITH(xpm, [ --without-xpm do not use libXpm]) AC_ARG_WITH(magic, [ --with-magic=DIR use libmagic installation in DIR]) -AC_ARG_WITH(magic2, +AC_ARG_WITH(magic, [ --without-magic do not use libmagic]) AC_ARG_WITH(curl, [ --with-curl=DIR use libcurl installation in DIR]) -AC_ARG_WITH(curl2, +AC_ARG_WITH(curl, [ --without-curl do not use libcurl]) AC_ARG_WITH(mimetic, [ --with-mimetic=DIR use libmimetic installation in DIR]) -AC_ARG_WITH(mimetic2, +AC_ARG_WITH(mimetic, [ --without-mimetic do not use libmimetic]) AC_ARG_WITH(gsoap, [ --with-gsoap=DIR use gSOAP++ installation in DIR]) -AC_ARG_WITH(gsoap2, +AC_ARG_WITH(gsoap, [ --without-gsoap do not use gSOAP++]) AC_ARG_WITH(avro, [ --with-avro=DIR use Apache Avro installation in DIR]) -AC_ARG_WITH(avro2, +AC_ARG_WITH(avro, [ --without-avro do not use Apache Avro]) AC_ARG_WITH(cereal, [ --with-cereal=DIR use USC Cereal installation in DIR]) -AC_ARG_WITH(cereal2, +AC_ARG_WITH(cereal, [ --without-cereal do not use USC Cereal]) AC_ARG_WITH(sasl2, [ --with-sasl2=DIR use SASL 2 installation in DIR]) -AC_ARG_WITH(sasl2b, +AC_ARG_WITH(sasl2, [ --without-sasl2 do not use SASL 2]) AC_ARG_WITH(mongodb, - [ --with-mongodb=DIR use MongoDB installation in DIR]) -AC_ARG_WITH(mongodb2, - [ --without-mongodb do not use MongoDB]) + [ --with-mongodb=DIR use legacy MongoDB installation in DIR]) +AC_ARG_WITH(mongodb, + [ --without-mongodb do not use legacy MongoDB]) +AC_ARG_WITH(mongodb3, + [ --with-mongodb3=DIR use MongoDB 3 installation in DIR]) +AC_ARG_WITH(mongodb3, + [ --without-mongodb3 do not use MongoDB 3]) AC_ARG_WITH(gmock, [ --with-gmock=DIR use Google Mock installation in DIR]) -AC_ARG_WITH(gmock2, +AC_ARG_WITH(gmock, [ --without-gmock do not use Google Mock]) AC_ARG_WITH(lapack, [ --with-lapack=DIR use LAPACK installation in DIR]) -AC_ARG_WITH(lapack2, +AC_ARG_WITH(lapack, [ --without-lapack do not use LAPACK]) AC_ARG_WITH(lmdb, [ --with-lmdb=DIR use LMDB installation in DIR]) AC_ARG_WITH(lmdb, - [ --without-lmdb do not use LMDB]) + [ --without-lmdb use internal copy of LMDB]) +AC_ARG_WITH(libuv, + [ --with-libuv=DIR use libuv installation in DIR]) +AC_ARG_WITH(libuv, + [ --without-libuv do not use libuv]) +AC_ARG_WITH(libssh2, + [ --with-libssh2=DIR use libssh2 installation in DIR]) +AC_ARG_WITH(libssh2, + [ --without-libssh2 do not use libssh2]) +AC_ARG_WITH(cassandra, + [ --with-cassandra=DIR use Datastax Cassandra driver installation in DIR]) +AC_ARG_WITH(cassandra, + [ --without-cassandra do not use Datastax Cassandra driver]) +AC_ARG_WITH(libxlsxwriter, + [ --with-libxlsxwriter=DIR use libxlsxwriter installation in DIR]) +AC_ARG_WITH(libxlsxwriter, + [ --without-libxlsxwriter do not use libxlsxwriter]) +AC_ARG_WITH(grpc, + [ --with-grpc=DIR use GRPC installation in DIR]) +AC_ARG_WITH(grpc, + [ --without-grpc do not use GRPC]) AC_ARG_WITH(3psw, [ --with-3psw=std:netopt favor standard (system) builds of the above pkgs.]) -AC_ARG_WITH(3psw2, +AC_ARG_WITH(3psw, [ --without-3psw do not use any of the above packages]) ## Optional projects @@ -505,27 +540,27 @@ AC_ARG_WITH(ncbi-crypt, [ --without-ncbi-crypt use a dummy stubbed-out version of ncbi_crypt]) AC_ARG_WITH(connext, [ --without-connext do not build non-public CONNECT library extensions]) -AC_ARG_WITH(serial, - [ --without-serial do not build the serialization library and tools]) -AC_ARG_WITH(objects, - [ --without-objects do not generate/build serializeable objects from ASNs]) -AC_ARG_WITH(dbapi, - [ --without-dbapi do not build database connectivity libraries]) +dnl AC_ARG_WITH(serial, +dnl [ --without-serial do not build the serialization library and tools]) +dnl AC_ARG_WITH(objects, +dnl [ --without-objects do not generate/build serializeable objects from ASNs]) +dnl AC_ARG_WITH(dbapi, +dnl [ --without-dbapi do not build database connectivity libraries]) AC_ARG_WITH(app, [ --without-app do not build standalone applications like ID1_FETCH]) AC_ARG_WITH(ctools, [ --without-ctools do not build NCBI C Toolkit based projects]) AC_ARG_WITH(gui, [ --without-gui do not build most graphical projects]) -AC_ARG_WITH(algo, - [ --without-algo do not build CPU-intensive algorithms]) +dnl AC_ARG_WITH(algo, +dnl [ --without-algo do not build CPU-intensive algorithms]) AC_ARG_WITH(internal, [ --with-internal always try to build internal projects]) -AC_ARG_WITH(internal2, +AC_ARG_WITH(internal, [ --without-internal never build internal projects]) AC_ARG_WITH(gbench, [ --with-gbench ensure that Genome Workbench can be built]) -AC_ARG_WITH(gbench2, +AC_ARG_WITH(gbench, [ --without-gbench do not build Genome Workbench]) ## Manuals @@ -539,22 +574,24 @@ dnl to which AC_MSG_ERROR normally copies its output, to be available. m4_rename([AS_MESSAGE_LOG_FD], [NCBI_ORIG_ASMLFD]) #### Check the passed arguments against the list of available ones x_with_list="\ -debug max-debug symbols optimization profiling tcheck dll static static-exe \ +debug max-debug symbols optimization profiling code-coverage \ +tcheck dll static static-exe \ plugin-auto-load bundles bin-release mt 64 exe runpath hard-runpath \ lfs limited-linker openmp \ autodep suffix hostspec version execopy bincopy lib-rebuilds lib-rebuilds=ask \ deactivation makefile-auto-update projects flat-makefile configure-dialog \ check ncbi-public strip pch caution ccache distcc \ ncbi-c wxwidgets wxwidgets-ucs fastcgi sss sssdb sssutils included-sss \ -geo included-geo vdb downloaded-vdb static-vdb \ -z bz2 lzo pcre gmp gcrypt nettle gnutls static-gnutls openssl krb5 \ +geo included-geo vdb downloaded-vdb static-vdb libunwind \ +z bz2 lzo pcre mbedtls gmp gcrypt nettle gnutls static-gnutls openssl krb5 \ sybase sybase-local sybase-new ftds mysql \ orbacus freetype ftgl opengl mesa glut glew glew-mx \ bdb python perl jni sqlite3 icu boost boost-tag \ sp expat sablot libxml libxslt libexslt xerces xalan zorba \ oechem sge muparser hdf5 \ gif jpeg tiff png xpm \ -magic curl mimetic gsoap avro cereal sasl2 mongodb gmock lapack lmdb 3psw \ +magic curl mimetic gsoap avro cereal sasl2 mongodb mongodb3 gmock lapack lmdb \ +libuv libssh2 cassandra libxlsxwriter grpc 3psw \ local-lbsm ncbi-crypt connext \ serial objects dbapi app ctools gui algo internal gbench" @@ -607,8 +644,9 @@ for x_arg in "$@" ; do --with-vdb=rc ) ;; --srcdir=* | --x-includes=* | --x-libraries=* | --with-tcheck=* \ - | --with-ncbi-c=* | --with-sss=* | --with-vdb=* | --with-z=* \ - | --with-bz2=* | --with-lzo=* | --with-pcre=* \ + | --with-ncbi-c=* | --with-sss=* | --with-vdb=* | --with-libunwind=* \ + | --with-z=* | --with-bz2=* | --with-lzo=* \ + | --with-pcre=* | --with-mbedtls=* \ | --with-gmp=* | --with-gcrypt=* | --with-nettle=* \ | --with-gnutls=* | --with-openssl=* | --with-krb5=* \ | --with-sybase-local=* | --with-ftds=*/* | --with-mysql=* \ @@ -622,8 +660,11 @@ for x_arg in "$@" ; do | --with-sge=* | --with-muparser=* | --with-hdf5=* | --with-gif=* \ | --with-jpeg=* | --with-png=* | --with-tiff=* | --with-xpm=* \ | --with-magic=* | --with-curl=* | --with-mimetic=* | --with-gsoap=* \ - | --with-avro=* | --with-cereal=* | --with-sasl2* | --with-mongodb=* \ - | --with-gmock=* | --with-lapack=* | --with-lmdb=* ) + | --with-avro=* | --with-cereal=* | --with-sasl2=* \ + | --with-mongodb=* | --with-mongodb3=* \ + | --with-gmock=* | --with-lapack=* | --with-lmdb=* | --with-libuv=* \ + | --with-libssh2=* | --with-cassandra=* | --with-libxlsxwriter=* \ + | --with-grpc=* ) # Confirm that the specified directory exists and is readable. dir=`echo $x_arg | sed -e 's/^[[^=]]*=//'` case "$x_arg" in @@ -645,6 +686,8 @@ for x_arg in "$@" ; do | --silent | --cache-file=* | -C | --config-cache | -n | --no-create \ | --no-recursion | --prefix=* | --exec-prefix=* | --bindir=* \ | --libdir=* | --includedir=* | --build=* | --host=* | --target=* \ + | --mandir=* | --infodir=* | --docdir=* | --htmldir=* \ + | --datadir=* | --sysconfdir=* | --localstatedir=* \ | --with-runpath=* | --with-relative-runpath=* \ | --with-experimental=* | --with-extra-action=* | --with-build-root=* \ | --with-fake-root=* | --with-build-root-sfx=* | --with-check=* \ @@ -662,7 +705,7 @@ AC_DIVERT_POP if test "$with_gbench" = "yes" ; then - m4_foreach(OPT, [dll,mt,gui,exe,serial,objects,algo,glew_mx,wxwidgets,ftgl,sqlite3,bdb,boost,xslt,gnutls], + m4_foreach(OPT, [dll,mt,gui,exe,serial,objects,algo,glew,wxwidgets,ftgl,sqlite3,bdb,boost,xslt,gnutls], [if test "$[with_]OPT" = "no"; then AC_MSG_ERROR([incompatible options: --without-]OPT[ but --with-gbench]) else @@ -688,6 +731,8 @@ if test "$with_bin_release" = "yes" ; then : ${with_local_lbsm=no} : ${with_ncbi_crypt=no} : ${with_connext=no} + : ${with_pcre=no} # Too much variation across distributions. + : ${with_sse42=no} AC_DEFINE(NCBI_BIN_RELEASE, 1, [Define to 1 when building binaries for public release.]) fi @@ -744,6 +789,13 @@ case "$with_static_gnutls:$with_gnutls" in ;; esac +m4_foreach(OPT, [serial,objects,dbapi,algo], + [if test -n "[$with_]OPT"; then + AC_MSG_WARN([--with(out)-]OPT[ is deprecated]) + AC_MSG_WARN([please simply pass an appropriate project list]) + fi + ]) + #### Check for special options if test "$with_extra_action" = "yes" ; then AC_MSG_ERROR([--with-extra-action must have a value after =]) @@ -826,6 +878,8 @@ AC_MSG_CHECKING([TeamCity build number]) if test -n "$TEAMCITY_VERSION" -a -n "$BUILD_NUMBER"; then AC_MSG_RESULT($BUILD_NUMBER) NCBI_TEAMCITY_BUILD_NUMBER=$BUILD_NUMBER + NCBI_TEAMCITY_PROJECT_NAME=$TEAMCITY_PROJECT_NAME + NCBI_TEAMCITY_BUILDCONF_NAME=$TEAMCITY_BUILDCONF_NAME else AC_MSG_RESULT(none) NCBI_TEAMCITY_BUILD_NUMBER=0 @@ -1212,7 +1266,7 @@ fi case "$host_os:$compiler" in solaris2.10:GCC ) : ${THREAD_LIBS:="-lposix4"} ;; solaris* ) : ${THREAD_LIBS:="-lpthread -lposix4"} ;; - freebsd* ) ;; # -pthread already substitutes libc_r for libc + freebsd* ) : ${THREAD_LIBS:="-pthread"} ;; # for LMDB in ST builds * ) : ${THREAD_LIBS:="-lpthread"} ;; esac @@ -1494,6 +1548,9 @@ case "$host_os:$compiler" in OBJCXX_CXXFLAGS='-x objective-c++' OBJCXX_LIBS='-lobjc' + + # New in macOS 10.12; don't attempt to use on older versions + ac_cv_search_clock_gettime=no ;; esac @@ -1733,6 +1790,50 @@ case "$host_os:$compiler" in ;; esac +AC_CACHE_CHECK([whether $CC has an option to discard unneeded shared libraries], + ncbi_cv_prog_cc_as_needed, + [orig_LDFLAGS=$LDFLAGS + ncbi_cv_prog_cc_as_needed=no + for x in -Wl,--as-needed; do + LDFLAGS="$orig_LDFLAGS $x" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [ncbi_cv_prog_cc_as_needed=$x]) + test "x$ncbi_cv_prog_cc_as_needed" = "xno" || break + done + LDFLAGS=$orig_LDFLAGS]) +case "$ncbi_cv_prog_cc_as_needed" in + -Wl,--as-needed ) + AS_NEEDED=-Wl,--as-needed + NO_AS_NEEDED=-Wl,--no-as-needed + ;; + no ) + AS_NEEDED= + NO_AS_NEEDED= + ;; +esac + +AC_CACHE_CHECK([whether $CC has an option to link in whole static archives], + ncbi_cv_prog_cc_whole_archive, + [orig_LDFLAGS=$LDFLAGS + ncbi_cv_prog_cc_whole_archive=no + for x in -Wl,--whole-archive; do + LDFLAGS="$orig_LDFLAGS $x `echo $x | sed -e 's/--/--no-/'`" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [ncbi_cv_prog_cc_whole_archive=$x]) + test "x$ncbi_cv_prog_cc_whole_archive" = "xno" || break + done + LDFLAGS=$orig_LDFLAGS]) +case "$ncbi_cv_prog_cc_whole_archive" in + -Wl,--whole-archive ) + WHOLE_ARCHIVE=-Wl,--whole-archive + NO_WHOLE_ARCHIVE=-Wl,--no-whole-archive + ;; + no ) + WHOLE_ARCHIVE= + NO_WHOLE_ARCHIVE= + ;; +esac + if $CXX -v 2>&1 | grep -q clang; then CFLAGS="$CFLAGS -Wno-deprecated-register" CXXFLAGS="$CXXFLAGS -Wno-deprecated-register" @@ -1790,9 +1891,50 @@ AC_CACHE_CHECK([how to enable C '11 or at least '99 features in $CC], test "x$ncbi_cv_prog_c_99" = "xno" || break done CC=$orig_CC]) + +: ${with_sse42=no} +if test "${with_sse42-$with_optimization}" = yes; then + AC_CACHE_CHECK([whether $CC supports -msse4.2], + ncbi_cv_prog_c_sse42, + [orig_CC=$CC + CC="$CC -msse4.2" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [#include ], + [__m128i v; _mm_cmpgt_epi64(v, v);])], + [ncbi_cv_prog_c_sse42=yes], + [ncbi_cv_prog_c_sse42=no])]) + if test $ncbi_cv_prog_c_sse42 = yes; then + orig_CC=$CC + elif test "$with_sse42" = yes; then + AC_MSG_ERROR([SSE 4.2 support explicitly requested but unavailable.]) + else + CC=$orig_CC + fi +fi AC_LANG_POP(C) test "$ncbi_cv_prog_c_99" = no || CC="$CC $ncbi_cv_prog_c_99" +if test "${with_sse42-$with_optimization}" = yes; then + AC_CACHE_CHECK([whether $CXX supports -msse4.2], + ncbi_cv_prog_cxx_sse42, + [orig_CXX=$CXX + CXX="$CXX -msse4.2" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM( + [#include ], + [__m128i v; _mm_cmpgt_epi64(v, v);])], + [ncbi_cv_prog_cxx_sse42=yes], + [ncbi_cv_prog_cxx_sse42=no])]) + if test $ncbi_cv_prog_cxx_sse42 = yes; then + orig_CXX=$CXX + elif test "$with_sse42" = yes; then + AC_MSG_ERROR([SSE 4.2 support explicitly requested but unavailable.]) + else + CXX=$orig_CXX + fi +fi + case "$host_os:$compiler" in solaris*:GCC ) # On Solaris, GCC defaults to setting _XOPEN_SOURCE (to 500) only @@ -2467,6 +2609,9 @@ if test -n "$LDD"; then fi fi +AC_PATH_PROG(UUIDGEN, uuidgen) +AC_PATH_PROG(CD_REPORTER, cd_reporter, [], [/am/ncbiapdata/bin:$PATH]) + #### Check if "${build_root}" is defined; provide a default one if test -n "${with_build_root}" ; then build_root=${with_build_root} @@ -2550,6 +2695,22 @@ else fi +#### Code coverage +if test "$with_code_coverage" = "yes"; then + case "$compiler" in + GCC ) # including Clang + COVFLAGS="--coverage" + ;; + * ) + AC_MSG_ERROR([--with-code-coverage not implemented for $compiler]) + ;; + esac + CFLAGS="$CFLAGS $COVFLAGS" + CXXFLAGS="$CXXFLAGS $COVFLAGS" + LDFLAGS="$LDFLAGS $COVFLAGS" +fi + + #### Determine whether this is implicitly a 64-bit platform AC_TYPE_SIZE_T AC_CHECK_SIZEOF(size_t) @@ -3203,6 +3364,14 @@ AC_CHECK_HEADERS(arpa/inet.h errno.h libgen.h locale.h malloc.h netdb.h \ valgrind/memcheck.h wchar.h) AC_HEADER_TIME +AC_CHECK_HEADERS(cxxabi.h) +if test "$ac_cv_header_cxxabi_h" = "yes"; then + AC_CHECK_DECL(abi::__cxa_demangle, + [AC_DEFINE(HAVE_CXA_DEMANGLE, 1, + [Define to 1 if `abi::__cxa_demangle' is available from .])], + [], [[#include ]]) +fi + ## gethostbyname_r() -- 2 different variants: 5-arg (Solaris), 6-arg (Linux). AC_CACHE_CHECK([for gethostbyname_r], ncbi_cv_func_gethostbyname_r, @@ -3420,8 +3589,8 @@ AC_CHECK_FUNCS(alarm asprintf atoll basename euidaccess fseeko fstat \ getgrouplist getopt getpagesize getpass getpassphrase \ getpwuid getrusage gettimeofday getuid lchown lutimes memrchr \ putenv readpassphrase readv select setenv statfs statvfs \ - strcasecmp strdup strlcat strlcpy strndup strsep strtok_r \ - sysmp timegm usleep utimes vasprintf vsnprintf writev) + strcasecmp strdup strlcat strlcpy strndup strnlen strsep \ + strtok_r sysmp timegm usleep utimes vasprintf vsnprintf writev) AC_LANG_POP(C) AC_TYPE_SIGNAL @@ -3558,62 +3727,6 @@ if test "$ncbi_cv_cxx_throw_spec" = yes; then fi -AC_CACHE_CHECK([for obsolete string::compare() syntax], - ncbi_cv_func_string_compare_obsolete, - [AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]], - [[std::string s; int i = 0; i = s.compare("aaa", 0, 2);]])], - [ncbi_cv_func_string_compare_obsolete=yes], - [ncbi_cv_func_string_compare_obsolete=no])]) -if test "$ncbi_cv_func_string_compare_obsolete" = yes; then - AC_DEFINE(NCBI_OBSOLETE_STR_COMPARE, 1, - [Define to 1 if `string::compare()' is non-standard.]) -fi - - -AC_CACHE_CHECK([whether the auto_ptr template class works], - ncbi_cv_type_auto_ptr_works, - [AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]], - [[int *ip = 0; std::auto_ptr ap(ip); *ip = *ap; ap.reset(ip);]])], - [ncbi_cv_type_auto_ptr_works=yes], [ncbi_cv_type_auto_ptr_works=no])]) -if test "$ncbi_cv_cxx_auto_ptr_works" = no; then - AC_DEFINE(HAVE_NO_AUTO_PTR, 1, - [Define to 1 if `auto_ptr' is missing or broken.]) -fi - - -AC_CACHE_CHECK([for min/max templates], ncbi_cv_func_min_max, - [AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[ - #include - #ifdef min - #undef min - #endif - #ifdef max - #undef max - #endif - ]], - [[int a=0, b=1; a = std::min(a, b); b = std::max(a, b);]])], - [ncbi_cv_func_min_max=yes], [ncbi_cv_func_min_max=no])]) -if test "$ncbi_cv_func_min_max" = no; then - AC_DEFINE(HAVE_NO_MINMAX_TEMPLATE, 1, - [Define to 1 if `min'/`max' templates are not implemented.]) -fi - - -AC_CACHE_CHECK([whether new C++ streams have ios_base::], - ncbi_cv_type_ios_base, - [AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]], - [[(void)(std::ios_base::out != std::ios_base::beg);]])], - [ncbi_cv_type_ios_base=yes], [ncbi_cv_type_ios_base=no])]) -if test "$ncbi_cv_type_ios_base" = no; then - AC_DEFINE(HAVE_NO_IOS_BASE, 1, - [Define to 1 if new C++ streams lack `ios_base::'.]) -fi - - AC_CACHE_CHECK([for ios(_base)::register_callback], ncbi_cv_func_ios_register_callback, [AC_COMPILE_IFELSE([AC_LANG_PROGRAM( @@ -3627,24 +3740,6 @@ if test "$ncbi_cv_func_ios_register_callback" = yes; then fi -AC_CACHE_CHECK([for std::char_traits::], ncbi_cv_type_char_traits, - [AC_COMPILE_IFELSE([AC_LANG_PROGRAM( - [[#include ]], - [[using namespace std; - char_traits::int_type i = char_traits::eof(); - i = char_traits::not_eof(i); - char_traits::char_type c = '\0'; - char_traits::pos_type p = 0; - char_traits::off_type o = 1; - ]])], - [ncbi_cv_type_char_traits=yes], [ncbi_cv_type_char_traits=no])]) -if test "$ncbi_cv_type_char_traits" = no; then - AC_DEFINE(HAVE_NO_CHAR_TRAITS, 1, - [Define to 1 if `std::char_traits' is missing.]) -fi - - - AC_CACHE_CHECK([for SysV semaphores], ncbi_cv_sys_semaphores, AC_LINK_IFELSE([AC_LANG_PROGRAM([#include #include ], @@ -4196,6 +4291,14 @@ esac usr_lib=['[/usr]*/lib/*[amdsprcv]*[23469]*'] no_usr_lib="s,-L$usr_lib ,,g; s,-L/usr/lib/$multiarch ,,g" +: ${with_libunwind:=no} +NCBI_CHECK_THIRD_PARTY_LIB_EX(libunwind, LIBUNWIND, unwind, + [[AC_LANG_PROGRAM([#include + #include ], + [[_Unwind_Trace_Fn f; _Unwind_Backtrace(f, NULL);]])]]) +LIBS="$LIBUNWIND_LIBS $LIBS" +orig_LIBS="$LIBUNWIND_LIBS $orig_LIBS" + NCBI_CHECK_THIRD_PARTY_LIB(z, [[AC_LANG_PROGRAM([#include ], [[gzFile fp; char buf[1024]; int n = gzread(fp, buf, sizeof(buf))]])]]) @@ -4257,6 +4360,35 @@ else fi ## SSL/TLS libraries (and supporting libraries) +if test "x${with_mbedtls-no}" != xno; then + case "$with_mbedtls" in + yes ) ;; + * ) MBEDTLS_PATH=$with_mbedtls ;; + esac + d="$MBEDTLS_PATH/${DEBUG_SFX}${mt_sfx}${bit64_sfx}" + if test -d "$d"; then + MBEDTLS_PATH=$d + fi + if test -d "$MBEDTLS_PATH"; then + NCBI_FIX_DIR(MBEDTLS_PATH) + fi + NCBI_CHECK_THIRD_PARTY_LIB(mbedtls, + [[AC_LANG_PROGRAM([#include ], + [[mbedtls_ssl_context ssl; mbedtls_ssl_init(&ssl);]])]], + [[-lmbedx509 -lmbedcrypto $Z_LIBS]]) + if test -n "$MBEDTLS_LIBS" -a -f "$MBEDTLS_PATH/lib/libmbedtls-static.a" \ + -a "x$with_static_mbedtls" = xyes; then + MBEDTLS_LIBS="-L$MBEDTLS_PATH/lib -lmbedtls-static -lmbedx509-static -lmbedcrypto-static $Z_LIBS" + fi +fi +if test -z "$MBEDTLS_LIBS"; then + mbedtls_local=connect/mbedtls + AC_MSG_NOTICE([using local mbedTLS copy in $mbedtls_local]) + MBEDTLS_INCLUDE="" + MBEDTLS_LIBS="$Z_LIBS" + NCBI_PACKAGE(MBEDTLS) +fi + if test "x$with_gmp" != xno; then case "$with_gmp" in yes | '' ) ;; @@ -4438,7 +4570,7 @@ if test "x$with_gnutls" != xno -a -n "$GNUTLS_CONFIG_LIBS"; then static_libs=$static_libs$sep$x sep=' ' done - GNUTLS_LIBS=$static_libs + GNUTLS_LIBS="$static_libs $ICONV_LIBS" fi fi @@ -4458,15 +4590,7 @@ for d in `echo " $OPENSSL_LIBS" | fmt -w 1 | sed -ne 's/^ *-L//p'` \ fi done -if test -n "$GNUTLS_LIBS"; then - TLS_INCLUDE=$GNUTLS_INCLUDE - TLS_LIBS=$GNUTLS_LIBS -else - TLS_INCLUDE=$OPENSSL_INCLUDE - TLS_LIBS=$OPENSSL_LIBS -fi - -NETWORK_LIBS="$TLS_LIBS $NETWORK_LIBS" +NETWORK_LIBS="$GNUTLS_LIBS $MBEDTLS_LIBS $NETWORK_LIBS" case "$with_krb5" in no ) ac_cv_path_KRB5_CONFIG=no ;; @@ -5920,7 +6044,8 @@ else fi glew_config="eval PKG_CONFIG_PATH=\"$GLEW_LIBDIR/pkgconfig\" pkg-config" if pkg-config --version >/dev/null 2>&1; then - if $glew_config glewmx --exists >/dev/null 2>&1 \ + if test "$with_glew_mx" != no \ + && $glew_config glewmx --exists >/dev/null 2>&1 \ && test -n "`$glew_config glewmx --libs 2>/dev/null`"; then glew_config="$glew_config glewmx" elif $glew_config glew --exists >/dev/null 2>&1 \ @@ -5953,7 +6078,7 @@ else NCBI_PACKAGE(GLEW) CPPFLAGS="$orig_CPPFLAGS $GLEW_INCLUDE $OPENGL_INCLUDE" LIBS="$GLEW_LIBS $OPENGL_LIBS $orig_LIBS" - AC_CACHE_CHECK([for GLEW multi-context (MX) support (recommended)], + AC_CACHE_CHECK([for GLEW multi-context (MX) support], ncbi_cv_lib_glew_mx, [AC_LINK_IFELSE([AC_LANG_PROGRAM( [[#define GLEW_MX 1 @@ -5961,7 +6086,13 @@ else [[glewContextInit(NULL);]])], [ncbi_cv_lib_glew_mx=yes], [ncbi_cv_lib_glew_mx=no])]) if test $ncbi_cv_lib_glew_mx = yes; then - GLEW_INCLUDE="$GLEW_INCLUDE -DGLEW_MX" + if test "$with_glew_mx" = no; then + GLEW_INCLUDE= + GLEW_LIBS= + NCBI_MISSING_PACKAGE(glew) + else + GLEW_INCLUDE="$GLEW_INCLUDE -DGLEW_MX" + fi else NCBI_MISSING_PACKAGE(glew-mx) fi @@ -6048,7 +6179,7 @@ if test "$with_wxwidgets" != "no" ; then libsed="$basesed; s%\$% $deps%" ;; esac - case "`"$wxconf" $wxcfflags --version`" in + test -x "$wxconf" && case "`"$wxconf" $wxcfflags --version`" in 1.* | 2.[[0-7]].* ) wxlibs=std ;; * ) wxlibs=std,richtext,aui,propgrid ;; esac @@ -6814,6 +6945,9 @@ if test -n "$SQLITE3_LIBS"; then NCBI_PACKAGE(SQLITE3ASYNC)]) LIBS="$SQLITE3_LIBS $orig_LIBS" AC_CHECK_FUNCS(sqlite3_unlock_notify) + SQLITE3_WRAPPER=sqlitewrapp +else + SQLITE3_WRAPPER= fi if test -n "$SQLITE3_LIBS" -a -f "$SQLITE3_LIBDIR/libsqlite3-static.a"; then SQLITE3_STATIC_LIBS="-L$SQLITE3_LIBDIR -lsqlite3-static" @@ -6827,13 +6961,15 @@ VDB_POST_LINK=: VDB_REQ=VDB if test "$with_vdb" != "no" ; then # CURL? - vdb_deps="$LIBXML_LIBS $NETWORK_LIBS $BZ2_LIBS $Z_LIBS $DL_LIBS" + vdb_deps="$NETWORK_LIBS $BZ2_LIBS $Z_LIBS $DL_LIBS" # In MT builds, ORIG_LIBS already contains THREAD_LIBS. However, # VDB is always threaded, and may need explicit THREAD_LIBS when # used statically. if test "$with_mt" = no; then vdb_deps="$vdb_deps $THREAD_LIBS" fi + vdb_static_deps="$LIBXML_STATIC_LIBS $vdb_deps" + vdb_deps="$LIBXML_LIBS $vdb_deps" if test "${with_vdb:-yes}" != "yes" -a -d "$with_vdb"; then VDB_PATH=$with_vdb fi @@ -6929,9 +7065,9 @@ if test "$with_vdb" != "no" ; then if test "$ncbi_cv_lib_ncbi_vdb" = yes; then NCBI_PACKAGE(VDB) if test -f "$VDB_LIBDIR/libncbi-vdb-static.a"; then - VDB_STATIC_LIBS="-L$VDB_LIBDIR -lncbi-vdb-static $vdb_deps" + VDB_STATIC_LIBS="-L$VDB_LIBDIR -lncbi-vdb-static $vdb_static_deps" if test "$with_static_vdb" = yes; then - VDB_LIBS=$VDB_STATIC_LIBS + VDB_LIBS="-L$VDB_LIBDIR -lncbi-vdb-static $vdb_deps" fi else VDB_STATIC_LIBS=$VDB_LIBS @@ -7104,21 +7240,21 @@ NCBI_CHECK_THIRD_PARTY_LIB(tiff, # Paths? with_ungif=$with_gif -NCBI_CHECK_THIRD_PARTY_LIB(ungif, +NCBI_CHECK_THIRD_PARTY_LIB(gif, AC_LANG_PROGRAM([extern "C" { #include }], [GifFileType* fp = DGifOpenFileName("foo");]), $X_LIBS -lX11) -if test "$with_ungif" = "no"; then - NCBI_CHECK_THIRD_PARTY_LIB(gif, +if test "$with_gif" = "no"; then + NCBI_CHECK_THIRD_PARTY_LIB(ungif, AC_LANG_PROGRAM([extern "C" { #include }], [GifFileType* fp = DGifOpenFileName("foo");]), $X_LIBS -lX11) else - AC_DEFINE(HAVE_LIBGIF, 1, [Define to 1 if libgif is available.]) - GIF_INCLUDE=$UNGIF_INCLUDE - GIF_LIBS=$UNGIF_LIBS + AC_DEFINE(HAVE_LIBUNGIF, 1, [Define to 1 if libungif is available.]) + UNGIF_INCLUDE=$GIF_INCLUDE + UNGIF_LIBS=$GIF_LIBS fi case "$x_libraries" in */*) : ${XPM_PATH=`dirname "$x_libraries"`} ;; esac @@ -7360,7 +7496,7 @@ NCBI_CHECK_THIRD_PARTY_LIB(sasl2, [[sasl_client_init(NULL);]])]]) -# MongoDB +# legacy MongoDB case "$with_mongodb" in yes | no | '' ) ;; * ) MONGODB_PATH=$with_mongodb ;; @@ -7391,6 +7527,42 @@ else fi +# MongoDB 3.x +case "$with_mongodb3" in + yes | no | '' ) ;; + * ) MONGODB3_PATH=$with_mongodb3 ;; +esac +if test -d "$MONGODB3_PATH"; then + NCBI_FIX_DIR(MONGODB3_PATH) +fi +if test -d $MONGODB3_PATH/lib${bit64_sfx}; then + MONGODB3_LIBDIR=$MONGODB3_PATH/lib${bit64_sfx} +else + MONGODB3_LIBDIR=$MONGODB3_PATH/lib +fi +m3pc="env PKG_CONFIG_PATH=$MONGODB3_LIBDIR/pkgconfig pkg-config libmongocxx" +if $m3pc --exists >/dev/null 2>&1; then + MONGODB3_FULL_INCLUDE=`$m3pc --cflags` + NCBI_RPATHIFY_OUTPUT(MONGODB3_FULL_LIBS, [$m3pc --libs --static], + [$no_usr_lib]) +fi +NCBI_CHECK_THIRD_PARTY_LIB_EX(mongodb3, MONGODB3, mongocxx, + [AC_LANG_PROGRAM([#include ], + [mongocxx::client mongo_client;])], + [], [$MONGODB3_FULL_LIBS], + [$MONGODB3_FULL_INCLUDE $BOOST_INCLUDE]) +if test -n "$MONGODB3_LIBS"; then + MONGODB3_INCLUDE=$MONGODB3_FULL_INCLUDE + MONGODB3_LIBS=$MONGODB3_FULL_LIBS + if test -f $MONGODB3_LIBDIR/libmongocxx-static.a; then + MONGODB3_STATIC_LIBS=`echo "$MONGODB3_LIBS" | \ + sed -e ['s/-lmongo[^ ]*/&-static/g; s/-lbson[^ ]*/&-static/g']` + else + MONGODB3_STATIC_LIBS=$MONGODB3_LIBS + fi +fi + + # Google Mock case "$with_gmock" in yes | no | '' ) ;; @@ -7449,7 +7621,140 @@ NCBI_CHECK_THIRD_PARTY_LIB(lapack, # LMDB NCBI_CHECK_THIRD_PARTY_LIB(lmdb, [AC_LANG_PROGRAM([[#include ]], - [[MDB_env *env; return mdb_env_create(&env);]])]) + [[MDB_env *env; return mdb_env_create(&env);]])], + [$THREAD_LIBS]) +if test -z "$LMDB_LIBS"; then + lmdblocal=util/lmdb + AC_MSG_NOTICE([using local LMDB copy in $lmdblocal]) + LMDB_PATH="<$lmdblocal>" + LMDB_INCLUDE="-I\$(includedir)/$lmdblocal -I\$(includedir0)/$lmdblocal" + # In MT builds, ORIG_LIBS already contains THREAD_LIBS. However, + # LMDB is always threaded, and may need explicit THREAD_LIBS when + # used statically. + LMDB_LIBS="$THREAD_LIBS" + # LMDB_LIBS="-llmdb $THREAD_LIBS" + LMDB_LIB="lmdb" + AC_DEFINE(USE_LOCAL_LMDB, 1, [Define to 1 if using a local copy of LMDB.]) + NCBI_PACKAGE(LMDB) + NCBI_PACKAGE(LocalLMDB) +fi + +# libuv +case "$with_libuv" in + yes | no | '' ) ;; + * ) LIBUV_PATH=$with_libuv ;; +esac +if test -d "$LIBUV_PATH"; then + NCBI_FIX_DIR(LIBUV_PATH) + for d in "$LIBUV_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx$bit64_sfx/lib" \ + "$LIBUV_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx$bit64_sfx/lib" \ + "$LIBUV_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx/lib" \ + "$LIBUV_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx/lib" \ + "$LIBUV_PATH/lib$bit64_sfx" "$LIBUV_PATH/lib"; do + if test -d "$d"; then + LIBUV_LIBDIR=$d + NCBI_FIX_DIR(LIBUV_LIBDIR) + break + fi + done +fi +NCBI_RPATHIFY(LIBUV_LIBPATH, $LIBUV_LIBDIR) +NCBI_CHECK_THIRD_PARTY_LIB_EX(libuv, LIBUV, uv, + [AC_LANG_PROGRAM([[#include ]], + [[uv_mutex_t m; return uv_mutex_init(&m);]])]) +if test "$with_libuv" != no -a -f "$LIBUV_LIBDIR/libuv-static.a"; then + LIBUV_STATIC_LIBS="-L$LIBUV_LIBDIR -luv-static" +else + LIBUV_STATIC_LIBS=$LIBUV_LIBS +fi + +# libssh2 +if test -d "$LIBSSH2_PATH"; then + NCBI_FIX_DIR(LIBSSH2_PATH) + for d in "$LIBSSH2_PATH/$compiler_vpfx$DEBUG_SFX$bit64_sfx/lib" \ + "$LIBSSH2_PATH/$compiler_pfx$DEBUG_SFX$bit64_sfx/lib" \ + "$LIBSSH2_PATH/$compiler_vpfx$DEBUG_SFX/lib" \ + "$LIBSSH2_PATH/$compiler_pfx$DEBUG_SFX/lib" \ + "$LIBSSH2_PATH/lib$bit64_sfx" "$LIBSSH2_PATH/lib"; do + if test -d "$d"; then + LIBSSH2_LIBDIR=$d + NCBI_FIX_DIR(LIBSSH2_LIBDIR) + break + fi + done +fi +NCBI_RPATHIFY(LIBSSH2_LIBPATH, $LIBSSH2_LIBDIR) +NCBI_CHECK_THIRD_PARTY_LIB_EX(libssh2, LIBSSH2, ssh2, + [AC_LANG_PROGRAM([[#include ]], + [[return libssh2_init(LIBSSH2_INIT_NO_CRYPTO);]])], + [$OPENSSL_LIBS]) +if test "$with_libssh2" != no -a -f "$LIBSSH2_LIBDIR/libssh2-static.a"; then + LIBSSH2_STATIC_LIBS="-L$LIBSSH2_LIBDIR -lssh2-static $OPENSSL_LIBS" +else + LIBSSH2_STATIC_LIBS=$LIBSSH2_LIBS +fi + +# Datastax Cassandra driver +if test -d "$CASSANDRA_PATH"; then + NCBI_FIX_DIR(CASSANDRA_PATH) + for d in "$CASSANDRA_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx$bit64_sfx" \ + "$CASSANDRA_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx$bit64_sfx" \ + "$CASSANDRA_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx" \ + "$CASSANDRA_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx"; do + if test -d "$d"; then + CASSANDRA_PATH=$d + NCBI_FIX_DIR(CASSANDRA_PATH) + break + fi + done +fi +NCBI_CHECK_THIRD_PARTY_LIB(cassandra, + [AC_LANG_PROGRAM([[#include ]], + [[CassCluster* c = cass_cluster_new();]])], + [$LIBSSH2_LIBS $LIBUV_LIBS]) +if test "$with_cassandra" != no -a \ + -f "$CASSANDRA_PATH/lib/libcassandra_static.a"; then + CASSANDRA_STATIC_LIBS="-L$CASSANDRA_PATH/lib -lcassandra_static $LIBSSH2_STATIC_LIBS $LIBUV_STATIC_LIBS" +else + CASSANDRA_STATIC_LIBS=$CASSANDRA_LIBS +fi + +NCBI_CHECK_THIRD_PARTY_LIB_EX(libxlsxwriter, LIBXLSXWRITER, xlsxwriter, + [AC_LANG_PROGRAM([[#include ]], + [[lxw_workbook* wb = workbook_new("conftest.xlsx");]])], + [], [$Z_LIBS]) +if test "$with_libxlsxwriter" != no -a \ + -f "$LIBXLSXWRITER_PATH/lib/libxlsxwriter-static.a"; then + LIBXLSXWRITER_STATIC_LIBS="-L$LIBXLSXWRITER_PATH/lib -lxlsxwriter-static" +else + LIBXLSXWRITER_STATIC_LIBS=$LIBXLSXWRITER_LIBS +fi + +if test -d "$GRPC_PATH"; then + NCBI_FIX_DIR(GRPC_PATH) + for d in "$GRPC_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx$bit64_sfx" \ + "$GRPC_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx$bit64_sfx" \ + "$GRPC_PATH/$compiler_vpfx$DEBUG_SFX$mt_sfx" \ + "$GRPC_PATH/$compiler_pfx$DEBUG_SFX$mt_sfx"; do + if test -d "$d"; then + GRPC_PATH=$d + NCBI_FIX_DIR(GRPC_PATH) + break + fi + done +fi +NCBI_CHECK_THIRD_PARTY_LIB_EX(grpc, GRPC, grpc++, + [AC_LANG_PROGRAM([[#include ]], + [[return grpc::Version().size();]])], + [-lgrpc -lgpr -lprotobuf$D_SFX -lcares], [$OPENSSL_LIBS $Z_LIBS]) +if test -n "$GRPC_LIBS"; then + GRPC_UNSECURE_LIBS=`echo $GRPC_LIBS | sed -e 's/\(-lgrpc+*\)/\1_unsecure/g'` + GRPC_LIBS="$GRPC_LIBS $OPENSSL_LIBS" + GRPC_REFLECTION_LIBS="$WHOLE_ARCHIVE $NO_AS_NEEDED $GRPC_LIBPATH" + GRPC_REFLECTION_LIBS="$GRPC_REFLECTION_LIBS -lgrpc++_reflection" + GRPC_REFLECTION_LIBS="$GRPC_REFLECTION_LIBS $NO_WHOLE_ARCHIVE $AS_NEEDED" + GRPC_BIN=$GRPC_PATH/bin +fi ### Restore original compiler/linker flags LIBS="$orig_LIBS" @@ -7709,11 +8014,11 @@ else if test -z "$with_projects"; then AC_MSG_ERROR([--with-internal: Cannot build INTERNAL projects: missing $reason]) else - AC_MSG_WARN([--with-internal: Cannot build all INTERNAL projects: missing $reason]) + AC_MSG_WARN([--with-internal: Cannot build some INTERNAL projects: missing $reason]) OPT_GROUPS="$OPT_GROUPS internal" internal="internal" fi - elif test -n "$reason"; then + elif test -n "$reason" -a -z "$with_projects"; then NoConfProjects="$NoConfProjects internal" internal= else @@ -7739,8 +8044,8 @@ if test "$with_gbench" != "no" -a -d "$real_srcdir/src/app/gbench"; then reason="$reason${sep}OpenGL" sep=", " fi - if test "$with_glew_mx" = "no"; then - reason="$reason${sep}GLEWmx" + if test "$with_glew" = "no"; then + reason="$reason${sep}GLEW" sep=", " fi if test "$with_ftgl" = "no"; then @@ -8007,6 +8312,10 @@ AC_SUBST(CFLAGS_DLL) AC_SUBST(CXXFLAGS_DLL) AC_SUBST(ALLOW_UNDEF) AC_SUBST(FORBID_UNDEF) +AC_SUBST(AS_NEEDED) +AC_SUBST(NO_AS_NEEDED) +AC_SUBST(WHOLE_ARCHIVE) +AC_SUBST(NO_WHOLE_ARCHIVE) AC_SUBST(OPT_GROUPS) AC_SUBST(local_lbsm) @@ -8048,6 +8357,7 @@ AC_SUBST(f_outexe) AC_SUBST(BDB_LIB) AC_SUBST(BDB_CACHE_LIB) +AC_SUBST(SQLITE3_WRAPPER) AC_SUBST(DBAPI_DRIVER) AC_SUBST(DBAPI_CTLIB) AC_SUBST(DBAPI_DBLIB) @@ -8081,8 +8391,6 @@ AC_SUBST(BZ2_LIB) AC_SUBST(PCREPOSIX_LIBS) AC_SUBST(PCRE_LIB) AC_SUBST(OPENSSL_STATIC_LIBS) -AC_SUBST(TLS_INCLUDE) -AC_SUBST(TLS_LIBS) AC_SUBST(SYBASE_PATH) AC_SUBST(SYBASE_LCL_PATH) AC_SUBST(SYBASE_INCLUDE) @@ -8192,6 +8500,15 @@ AC_SUBST(GSOAP_PATH) AC_SUBST(AVRO_STATIC_LIBS) AC_SUBST(CEREAL_INCLUDE) AC_SUBST(MONGODB_STATIC_LIBS) +AC_SUBST(MONGODB3_STATIC_LIBS) +AC_SUBST(LMDB_LIB) +AC_SUBST(LIBUV_STATIC_LIBS) +AC_SUBST(LIBSSH2_STATIC_LIBS) +AC_SUBST(CASSANDRA_STATIC_LIBS) +AC_SUBST(LIBXLSXWRITER_STATIC_LIBS) +AC_SUBST(GRPC_UNSECURE_LIBS) +AC_SUBST(GRPC_REFLECTION_LIBS) +AC_SUBST(GRPC_BIN) AC_SUBST(ncbi_xreader_pubseqos) AC_SUBST(ncbi_xreader_pubseqos2) AC_SUBST(UNLESS_PUBSEQOS) @@ -8237,6 +8554,8 @@ AC_SUBST(OSTYPE) AC_SUBST(NCBI_PLATFORM_BITS) AC_SUBST(NCBI_TEAMCITY_BUILD_NUMBER) +AC_SUBST(NCBI_TEAMCITY_PROJECT_NAME) +AC_SUBST(NCBI_TEAMCITY_BUILDCONF_NAME) AC_SUBST(NCBI_SUBVERSION_REVISION) AC_SUBST(NCBI_SC_VERSION) @@ -8276,6 +8595,7 @@ dnl make all shell scripts *.sh be executable find "$build_root/." -name '*.sh' -print | while read x_file ; do chmod a+x "$x_file" done +chmod a+x "$build_root/build/run_with_cd_reporter.py" dnl save cache and log files to the build tree dir "status/" dnl (alongside config.status, which is now directly created there to @@ -8360,6 +8680,11 @@ done dnl Try to build simple helpers (cd $builddir/build-system/helpers && $MAKE -k) +dnl Generated header containing random compile-time values, produced by +dnl either project_tree_builder (alongside Makefile.flat) or fallback logic. +random_macro="$build_root/inc/ncbi_random_macro.h" +rm -f $random_macro + dnl Create Makefile.flat if requested if test "$with_configure_dialog" = yes; then if test "$with_flat_makefile" = no; then @@ -8396,6 +8721,10 @@ if test "$with_flat_makefile" != "no"; then fi fi +if test ! -f "$random_macro"; then + $real_srcdir/scripts/common/impl/define_random_macros.sh >$random_macro +fi + dnl execute extra-action if test -n "$with_extra_action" ; then with_extra_action=`echo "$with_extra_action" | sed "s%{}%$build_root%g"` @@ -8458,7 +8787,7 @@ $build_flat ******* CONFIGURATION SUCCESSFUL ******* EOCONF ], [ -PATH='/bin:/usr/bin:\$PATH' +PATH="$HOME/bin:/bin:/usr/bin:\$PATH" status_dir='$status_dir' builddir='$builddir' build_root='$build_root' diff --git a/c++/src/build-system/helpers/run_with_lock.c b/c++/src/build-system/helpers/run_with_lock.c index f0159b0a..883e1716 100644 --- a/c++/src/build-system/helpers/run_with_lock.c +++ b/c++/src/build-system/helpers/run_with_lock.c @@ -1,4 +1,4 @@ -/* $Id: run_with_lock.c 520549 2016-11-29 18:58:00Z ivanov $ +/* $Id: run_with_lock.c 520482 2016-11-29 00:22:51Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/build-system/install.sh.in b/c++/src/build-system/install.sh.in index 4fd31d79..b3d9e985 100644 --- a/c++/src/build-system/install.sh.in +++ b/c++/src/build-system/install.sh.in @@ -1,6 +1,6 @@ @script_shell@ -# $Id: install.sh.in 117476 2008-01-16 16:44:07Z ucko $ +# $Id: install.sh.in 541934 2017-07-24 15:27:24Z ivanov $ # Author: Denis Vakatov, NCBI # ########################################################################### @@ -17,8 +17,8 @@ echo "[`date`]" -svn_location=`echo '$HeadURL: https://svn.ncbi.nlm.nih.gov/repos/toolkit/release/blast/2.6.0/c++/src/build-system/install.sh.in $' | sed "s%\\$[H]eadURL: *\\([^$][^$]*\\) \\$.*%\\1%"` -svn_revision=`echo '$Revision: 117476 $' | sed "s%\\$[R]evision: *\\([^$][^$]*\\) \\$.*%\\1%"` +svn_location=`echo '$HeadURL: https://svn.ncbi.nlm.nih.gov/repos/toolkit/release/blast/2.7.1/c++/src/build-system/install.sh.in $' | sed "s%\\$[H]eadURL: *\\([^$][^$]*\\) \\$.*%\\1%"` +svn_revision=`echo '$Revision: 541934 $' | sed "s%\\$[R]evision: *\\([^$][^$]*\\) \\$.*%\\1%"` script_name=`basename $0` script_dir=`dirname $0` @@ -202,11 +202,11 @@ status/config.cache" install_builddir="$install_dir/build" mkdir "$install_builddir" || Usage "Failed to create dir: $install_builddir" -(cd $script_dir && for f in Makefile.* *.sh *.cfg; do +(cd $script_dir && for f in Makefile.* *.sh *.py *.cfg; do case $f in reconfigure.sh) continue ;; # skip (inappropriate) Makefile.*) type=makefile ;; - *.sh) type=script ;; + *.sh | *.py) type=script ;; *.cfg) type=config ;; esac cp -p $f "$install_builddir/" || \ diff --git a/c++/src/build-system/library_relations.txt b/c++/src/build-system/library_relations.txt index 279fae5b..c37f47b0 100644 --- a/c++/src/build-system/library_relations.txt +++ b/c++/src/build-system/library_relations.txt @@ -1,4 +1,4 @@ -# $Id: library_relations.txt 507530 2016-07-19 20:26:26Z syncbot $ +# $Id: library_relations.txt 537719 2017-06-02 17:39:24Z syncbot $ # Pregenerated summary of library relations, for use by project_tree_builder. $(ORIG_LIBS) needs3party 16S_common needs seqset @@ -7,7 +7,7 @@ $(ORIG_LIBS) needs3party 16S_summaries needs gpipe_xmlutil 16S_summaries needs xregexp Assembly2Fscreen needs fscreen -Assembly2Fscreen needs xid_utils +Assembly2Fscreen needs idload_utils BlastCgiUtils needs $(CONNEXT) BlastCgiUtils needs connect BlastCgiUtils needs xhtml @@ -15,6 +15,7 @@ BlastOptsTools needs $(BLAST_LIBS) BlastOptsTools needs xcgi BlastOptsTools needs xhtml BoostTestXML needs xser +EntrezCache_cgi includes EntrezCache_g EntrezCache_g needs $(EUTILS_LIBS) EntrezCache_g needs dbloadb EntrezCache_g needs entrez2cli @@ -28,12 +29,8 @@ GLEW needs3party $(ORIG_LIBS) GLU needs3party $(ORIG_LIBS) GLU needs3party X11 GLU needs3party Xext -GMC needs $(CONNEXT) -GMC needs softparse -GMC needs xgridcgi OSMesa needs3party $(OPENGL_LIBS) OSMesa needs3party $(ORIG_LIBS) -TxPubmedBackend needs txserv VDBUtils needs bdbasncli VDBUtils needs ncbi_xloader_csra VDBUtils needs ncbi_xloader_wgs @@ -50,6 +47,8 @@ ads needs pub affy needs3party $(CURL_LIBS) affy needs3party $(ORIG_LIBS) affy needs3party $(XERCES_LIBS) +agp_db needs agp_lookup +agp_db needs dbapi_util_blobstore agp_lookup needs $(GPIPE_COMMON_LIBS) agp_lookup needs gpipe_objutil agp_lookup needs xhtml @@ -73,15 +72,16 @@ alndb_query needs $(SEQ_LIBS) alndb_query needs pub alndbaccess needs alndb_query alndbaccess needs generic_db_core -an_core needs $(GPIPE_COMMON_LIBS) +an_core needs $(GPIPE_GENCOLL_LIBS) an_core needs 16S_common -an_core needs gc_util_sdbapi an_core needs gpinit_bag_util an_core needs gpipe_an_base +an_core needs gpipe_fileutils an_core needs gpipe_kmer +an_core needs gpipe_xmlutil an_core needs pathogen_connection an_core needs reftrack_access -an_euk_pipeline needs $(GPIPE_COMMON_LIBS) +an_euk_pipeline needs $(GPIPE_GENCOLL_LIBS) an_euk_pipeline needs bag_access an_euk_pipeline needs gpipe_an_base an_euk_pipeline needs gpipe_val @@ -90,8 +90,10 @@ an_euk_pipeline needs3party $(BOOST_FILESYSTEM_LIBS) an_euk_pipeline needs3party $(BOOST_SYSTEM_LIBS) an_prok_pipeline needs gpipe_an_base an_prok_pipeline needs gpipe_asn_proc +an_prok_pipeline needs gpipe_fileutils an_prok_pipeline needs pathogen_connection an_prok_pipeline needs tax_xml +an_prok_pipeline needs xalgophytree an_prok_pipeline needs xobjwrite an_worker_nodes needs gpipe_an_base asn_cache needs $(COMPRESS_LIBS) @@ -111,13 +113,9 @@ auxcomm_g needs splitdbasncpp_g auxcomm_g needs tea_crypt auxcommcpp_g needs muxex_g auxnet_g needs generic_db_utils -bacterial_pipeline_proc needs attr_cd bacterial_pipeline_proc needs gencoll_client bacterial_pipeline_proc needs gpipe_alnutil -bacterial_pipeline_proc needs xalgoalignutil -bag_access needs $(SEQ_LIBS) bag_access needs gpipe_common -bag_access needs pub bamread needs $(COMPRESS_LIBS) bamread needs seqset bamread needs3party $(VDB_LIBS) @@ -128,6 +126,7 @@ bdb2ez needs xser bdbasncli needs bdb2ez bdbasncli needs xconnect biblio needs general +biocollect needs ncbi_xdbapi_ftds biosample needs $(SDBAPI_LIB) biosample needs xmlwrapp biosample needs xregexp @@ -142,8 +141,7 @@ blast needs tables blast_app_util needs $(BLAST_INPUT_LIBS) blast_app_util needs $(BLAST_LIBS) blast_services needs xnetblastcli -blast_sra_input needs $(BLAST_INPUT_LIBS) -blast_sra_input needs $(BLAST_LIBS) +blast_sra_input needs $(SOBJMGR_LIBS) blast_sra_input needs $(SRAREAD_LIBS) blast_unit_test_util needs $(BLAST_LIBS) blast_unit_test_util needs $(OBJMGR_LIBS) @@ -173,9 +171,7 @@ boost_unit_test_framework-gcc48-mt-d-64 needs3party $(ORIG_LIBS) build_config needs $(GPIPE_GENCOLL_LIBS) build_config needs bacterial_pipeline_proc build_config needs build_config_base -build_config needs gpipe_xmlutil build_config needs reftrack_access -build_config needs simple_asm build_config_base needs gencoll_client build_config_base needs gpinit_bag_util build_config_base needs gpinit_register @@ -183,6 +179,8 @@ bz2 needs3party $(ORIG_LIBS) cache_g needs generic_db_utils cdd needs cn3d cdd needs scoremat +cdd_access needs id2 +cdd_access needs xconnect clog needs3party $(ORIG_LIBS) cluster_assignment needs xser cluster_utils needs gpipe_objutil @@ -201,7 +199,8 @@ config_access needs gpipe_common connect needs3party $(NETWORK_LIBS) connect needs3party $(ORIG_LIBS) connext needs connect -connssl needs connect +connssl needs3party $(NETWORK_LIBS) +connssl needs3party $(ORIG_LIBS) creaders needs3party $(ORIG_LIBS) crypto needs $(Z_LIB) crypto needs3party $(ORIG_LIBS) @@ -209,6 +208,7 @@ crypto needs3party $(Z_LIBS) ct_ftds64 needs tds_ftds64 ct_ftds95 needs tds_ftds95 ctransition needs xncbi +ctutils needs3party $(LMDB_LIBS) ctutils needs3party $(SYBASE_DLLS) ctutils needs3party $(SYBASE_LIBS) ctutils needs3party $(VDB_LIBS) @@ -291,6 +291,8 @@ eutils needs espell eutils needs esummary eutils needs uilist eutils needs xconnect +eutils_client needs $(SEQ_LIBS) +eutils_client needs pub eutils_client needs xmlwrapp eutilsapp includes eueid eutilsapp needs ncqhst @@ -305,10 +307,6 @@ fbsdstd_g needs3party $(ORIG_LIBS) fcgi needs3party $(ORIG_LIBS) featdef needs xser filter_snps needs xalnmgr -flatfile needs $(OBJMGR_LIBS) -flatfile needs ncbi_xcache_netcache -flatfile needs ncbi_xloader_wgs -flatfile needs xobjwrite freetype needs3party $(ORIG_LIBS) fscreen needs agp_lookup fscreen needs dbapi_util_blobstore @@ -318,20 +316,17 @@ ftgl needs3party $(ORIG_LIBS) gbproj needs submit gbproj needs xconnect gbseq needs xser -gc_assm_rpt needs gcaccess_utils -gc_common needs xser +gc_asn_access needs $(GPIPE_GENCOLL_LIBS) +gc_assm_rpt needs $(GPIPE_GENCOLL_LIBS) +gc_common needs xutil gc_load_utils needs $(GPIPE_COMMON_LIBS) gc_load_utils needs gc_common gc_load_utils needs gc_organism gc_load_utils needs gc_utils gc_organism needs gpipe_attr gc_organism needs taxon1 -gc_schedule needs xconnserv -gc_util_sdbapi needs gencoll_client -gc_util_sdbapi needs gpipe_common +gc_schedule needs ncbi_xcache_netcache gc_utils needs gpipe_objutil -gcaccess_utils needs $(GPIPE_GENCOLL_LIBS) -gcaccess_utils needs simple_asm gcedit needs agp_lookup gcedit needs gc_load_utils gcrypt needs3party $(ORIG_LIBS) @@ -346,6 +341,7 @@ gene_info needs xncbi gene_info_writer needs gene_info gene_info_writer needs seqdb genemark_proc needs bacterial_pipeline_proc +genemark_proc needs xalgoseq general needs xser generic_db_asn needs xser generic_db_core needs $(CONNEXT) @@ -365,15 +361,20 @@ gensvc_g needs xser geodataset needs biblio gif needs3party $(ORIG_LIBS) gif needs3party X11 +gmap needs xlinear_prog gmap needs xmlwrapp gmp needs3party $(ORIG_LIBS) -gnomon_access needs sqlitewrapp +gnomon_access needs $(SQLITE3_WRAPPER) gnomon_access needs xalgognomon gnomon_access needs xqueryparse +gnomon_access needs3party $(SQLITE3_LIBS) gnomon_asn_proc needs xobjutil gnutls needs3party $(GMP_LIBS) gnutls needs3party $(NETTLE_LIBS) gnutls needs3party $(ORIG_LIBS) +gp_assm2xml needs $(SDBAPI_LIB) +gp_assm2xml needs gencoll_client +gp_assm2xml needs xmlwrapp gpcgi needs $(SDBAPI_LIB) gpcgi needs xcgi gpcgi needs xmlwrapp @@ -381,10 +382,10 @@ gpcgi needs xregexp gpexec_query needs gpipe_common gpexec_query needs monitor_buildrun gpg-error needs3party $(ORIG_LIBS) -gpinit includes gpinit_obj gpinit needs entrez2cli gpinit needs gc_organism gpinit needs gpinit_access +gpinit needs gpinit_obj gpinit needs gpipe_objutil gpinit_access needs $(SDBAPI_LIB) gpinit_access needs xconnect @@ -395,6 +396,9 @@ gpinit_obj needs general gpinit_register needs gc_organism gpinit_reports needs xmlwrapp gpinit_reports needs xregexp +gpipe_advanced_cleanup needs gpipe_best_placement +gpipe_advanced_cleanup needs prosplign +gpipe_advanced_cleanup needs xalgoalignsplign gpipe_align_format needs $(BLAST_FORMATTER_MINIMAL_LIBS) gpipe_align_format needs gpipe_objutil gpipe_align_format needs prosplign @@ -420,7 +424,8 @@ gpipe_blast needs $(BLAST_INPUT_LIBS) gpipe_blast needs $(BLAST_LIBS) gpipe_blast needs gpipe_alnutil gpipe_clean_prot_names needs gpipe_attr -gpipe_clean_prot_names needs xdiscrepancy_report +gpipe_clean_prot_names needs macro +gpipe_common needs $(COMPRESS_LIBS) gpipe_common needs $(SDBAPI_LIB) gpipe_common needs eutils_client gpipe_common needs xcgi @@ -428,13 +433,15 @@ gpipe_common needs xregexp gpipe_curl needs xncbi gpipe_curl needs3party $(CURL_LIBS) gpipe_dateutil needs xregexp -gpipe_ftp needs gcaccess_utils +gpipe_fileutils needs $(COMPRESS_LIBS) +gpipe_fileutils needs xutil +gpipe_ftp needs $(GPIPE_GENCOLL_LIBS) gpipe_ftp needs gpinit gpipe_ftp needs gpipe_alnutil gpipe_ftp needs xalgoalignutil gpipe_ftp needs xobjwrite gpipe_ftp needs xrepeatdb -gpipe_ftp_new needs gcaccess_utils +gpipe_ftp_new needs $(GPIPE_GENCOLL_LIBS) gpipe_ftp_new needs gpinit gpipe_ftp_new needs gpipe_alnutil gpipe_ftp_new needs xalgoalignutil @@ -447,12 +454,10 @@ gpipe_jira needs3party $(GSOAP_LIBS) gpipe_kmer needs gpipe_objutil gpipe_kmer needs sampling gpipe_kpi needs xmlwrapp -gpipe_meta_access needs $(SDBAPI_LIB) -gpipe_meta_access needs xconnect -gpipe_meta_access needs xutil +gpipe_meta_access needs xncbi +gpipe_minhash needs xncbi gpipe_object_edit needs xalgoalignutil gpipe_objutil needs $(DATA_LOADERS_UTIL_LIB) -gpipe_objutil needs $(DATA_LOADERS_UTIL_LIBS) gpipe_objutil needs $(OBJEDIT_LIBS) gpipe_objutil needs $(OBJMGR_LIBS) gpipe_objutil needs $(XFORMAT_LIBS) @@ -460,8 +465,10 @@ gpipe_objutil needs gpipe_attr gpipe_objutil needs taxon1 gpipe_objutil needs writedb gpipe_objutil needs xalnmgr +gpipe_objutil needs xid_wgsdb +gpipe_objutil needs3party $(DATA_LOADERS_UTIL_LIBS) gpipe_objutil needs3party $(UUID_LIBS) -gpipe_prodigal needs bacterial_pipeline_proc +gpipe_prodigal needs prok_cluster_data gpipe_property needs gpipe_common gpipe_remap needs xobjreadex gpipe_resource_req needs xncbi @@ -471,13 +478,15 @@ gpipe_sadb needs taxon1 gpipe_sadb needs xmlwrapp gpipe_sqlite needs $(SDBAPI_LIB) gpipe_sqlite needs $(SEQ_LIBS) +gpipe_sqlite needs $(SQLITE3_WRAPPER) gpipe_sqlite needs pub -gpipe_sqlite needs sqlitewrapp gpipe_sqlite needs xconnect gpipe_sqlite needs xregexp +gpipe_sqlite needs3party $(SQLITE3_LIBS) gpipe_standalone needs gpipe_an_base gpipe_teamcity needs gpipe_common gpipe_teamcity needs gpipe_curl +gpipe_test_boost needs test_boost gpipe_tree needs gpipe_common gpipe_tree needs xalgophytree gpipe_type_verifier needs gpipe_asn_cleanup @@ -487,22 +496,20 @@ gpipe_val needs $(SEQ_LIBS) gpipe_val needs pub gpipe_val needs valerr gpipe_val needs xmlwrapp -gpipe_xml needs $(SEQ_LIBS) +gpipe_xlsx needs $(Z_LIB) +gpipe_xlsx needs xncbi +gpipe_xlsx needs3party $(LIBXLSXWRITER_LIBS) +gpipe_xlsx needs3party $(Z_LIBS) gpipe_xml needs gpipe_attr gpipe_xml needs gpipe_dateutil -gpipe_xml needs pub -gpipe_xmlutil needs xutil -gpipe_xmlutil needs3party $(LIBXML_LIBS) -gpipe_xmlutil needs3party $(LIBXSLT_LIBS) +gpipe_xmlutil needs xmlwrapp gpxapi needs general gpxapi needs xconnect -gpxlib needs $(COMPRESS_LIBS) gpxlib needs gpipe_common gpxlib needs gpxapi gpxlib needs xgp_manifest +grid_wrapper needs gpipe_common grid_wrapper needs gpipe_resource_req -grid_wrapper needs xconnect -grid_wrapper needs xutil grid_wrapper needs3party $(SGE_LIBS) gsoapssl++ needs $(Z_LIB) gsoapssl++ needs3party $(KRB5_LIBS) @@ -545,8 +552,8 @@ gui_opengl needs ximage gui_opengl needs3party $(FTGL_LIBS) gui_opengl needs3party $(GLEW_LIBS) gui_opengl needs3party $(OPENGL_LIBS) -gui_print needs $(COMPRESS_LIBS) gui_print needs gui_opengl +gui_utils needs $(COMPRESS_LIBS) gui_utils needs tables gui_utils needs xconnect gui_utils needs xutil @@ -584,15 +591,15 @@ id2_split needs $(SOBJMGR_LIBS) id2cli needs id2 id2cli needs xconnect ideo needs xmvdatacache +ideo_gridcli needs ideo +ideo_gridcli needs trackmgrgridcli ideochr needs3party vibrant ideocli needs ideo ideocoord needs $(SDBAPI_LIB) -ideocoord needs ideocli +ideocoord needs ideo_gridcli idgen needs dbassist idload needs3party ctutils -idload_utils needs gpipe_common -idload_utils needs xid_utils -idload_utils needs xobjutil +idload_utils needs gpipe_objutil igblast needs $(BLAST_LIBS) insdseq needs xser jiracli needs jirasvc @@ -614,11 +621,14 @@ lapackwrapp needs3party $(ORIG_LIBS) lbsmdapi needs connect lds2 needs $(COMPRESS_LIBS) lds2 needs $(OBJREAD_LIBS) -lds2 needs sqlitewrapp +lds2 needs $(SQLITE3_WRAPPER) +lds2 needs3party $(SQLITE3_LIBS) linkos_utils needs xid_utils linkout needs xser +linkoutdb needs $(SQLITE3_WRAPPER) linkoutdb needs seqdb -linkoutdb needs sqlitewrapp +linkoutdb needs3party $(SQLITE3_LIBS) +lmdb needs3party $(ORIG_LIBS) ls_cli needs $(NCBILS2_LIB) ls_cli needs dbloadb lzo2 needs3party $(ORIG_LIBS) @@ -696,6 +706,12 @@ ncbiCacc includes3party ncbiacc ncbiCacc needs3party netentr ncbiNacc includes3party ncbiacc ncbiNacc needs3party netentr +ncbi_id2proc_cdd needs $(COMPRESS_LIBS) +ncbi_id2proc_cdd needs cdd_access +ncbi_id2proc_snp needs $(COMPRESS_LIBS) +ncbi_id2proc_snp needs $(SOBJMGR_LIBS) +ncbi_id2proc_snp needs $(SRAREAD_LIBS) +ncbi_id2proc_snp needs id2 ncbi_id2proc_wgs needs $(COMPRESS_LIBS) ncbi_id2proc_wgs needs $(SOBJMGR_LIBS) ncbi_id2proc_wgs needs $(SRAREAD_LIBS) @@ -758,6 +774,7 @@ ncbi_xreader needs id2 ncbi_xreader needs xconnect ncbi_xreader_cache needs ncbi_xreader ncbi_xreader_gicache needs ncbi_xreader +ncbi_xreader_gicache needs3party $(LMDB_LIBS) ncbi_xreader_id1 needs ncbi_xreader ncbi_xreader_id2 needs ncbi_xreader ncbi_xreader_pubseqos needs $(XCONNEXT) @@ -837,13 +854,13 @@ odbc_ftds64 needs tds_ftds64 odbc_ftds95 needs tds_ftds95 omssa needs $(SEQ_LIBS) omssa needs pub -osutils needs3party $(RT_LIBS) osutils needs3party ctutils pathogen_cluster_loader needs $(SDBAPI_LIB) pathogen_cluster_loader needs xasmcompare pathogen_cluster_loader needs xconnect pathogen_connection needs gpipe_common pathogen_connection needs gpipe_dateutil +pathogen_connection needs taxon1 pathogen_ctl needs $(GPIPE_COMMON_LIBS) pathogen_ctl needs bag_access pathogen_ctl needs gpipe_kmer @@ -857,29 +874,33 @@ pcassay needs pcsubstance pcre needs3party $(ORIG_LIBS) pcsubstance needs pub pepXML needs xser -phytree_format needs taxon1 +phytree_format needs align_format phytree_format needs xalgophytree -pn_ctl needs $(GPIPE_GENCOLL_LIBS) pn_ctl needs bacterial_pipeline_proc pn_ctl needs ec_hmm_relation_cd pn_ctl needs gpipe_clean_prot_names pn_ctl needs gpipe_jira pn_ctl needs idload_utils -pn_ctl needs simple_asm png needs $(Z_LIB) png needs3party $(ORIG_LIBS) png needs3party $(Z_LIBS) process_annotation_stats needs xser proj needs pubmed proj needs seqset +prok_cluster_data needs attr_cd +prok_cluster_data needs bacterial_pipeline_proc +prok_cluster_data needs gpipe_sqlite +prok_cluster_data needs xalgoalignutil prosplign needs xalgoalignutil +protein_match needs xobjutil +proteinkmer needs $(BLAST_LIBS) proxsort needs taxoscli pstub needs3party $(ORIG_LIBS) pub needs medline pubmed needs medline python2.7 needs3party $(ORIG_LIBS) python_ncbi_dbapi needs $(Z_LIB) -python_ncbi_dbapi needs connssl +python_ncbi_dbapi needs connect python_ncbi_dbapi needs dbapi python_ncbi_dbapi needs3party $(PYTHON_LIBS) python_ncbi_dbapi needs3party $(Z_LIBS) @@ -891,19 +912,14 @@ refseq_aln_source needs xalgoalignsplign refseq_ctl needs bacterial_pipeline_proc refseq_ctl needs bag_access refseq_ctl needs gpinit_access -refseq_ctl needs process_annotation_stats -refseq_ctl needs xid_utils -reftrack_access needs $(SDBAPI_LIB) -reftrack_access needs xconnect -reftrack_access needs xutil -reftrack_admin needs $(SDBAPI_LIB) -reftrack_admin needs xconnect -reftrack_admin needs xutil +refseq_ctl needs idload_utils +refseq_ctl needs validation_results +reftrack_access needs xncbi +reftrack_admin needs xncbi remap needs $(SEQ_LIBS) remap needs pub remapcli needs remap remapcli needs xconnect -rt needs3party $(ORIG_LIBS) sage_mappings needs xser sample_asn needs general sampling needs3party $(ORIG_LIBS) @@ -918,6 +934,7 @@ sdbapi needs xutil sdncbiauth needs generic_db_core sdncbiauth needs muxex_g sdncbiauth needs xmyncbi +searchbyrsid needs trackmgr seq needs pub seq needs seqcode seq needs sequtil @@ -941,6 +958,7 @@ seqtest needs $(SEQ_LIBS) seqtest needs pub sequtil needs xncbi simple_asm needs gc_load_utils +simple_asm needs seqgapscan smartasn_g needs submit smartnet needs3party vibrant smartnetclient needs xconnect @@ -951,9 +969,9 @@ softparse needs $(COMPRESS_LIBS) softparse needs affy softparse needs taxon1 softparse needs xmlwrapp -spcgi needs $(CONNEXT) spcgi needs softparse -spcgi needs xgridcgi +spcgi needs xcgi +spcgi needs xhtml spellsrvbase needs txserv splitdbasn_g needs gendefasn_g splitdbasn_g needs3party ncbiobj @@ -972,10 +990,8 @@ ssl needs3party $(Z_LIBS) ssparse needs3party ncbiid1 ssparse needs3party ncbimla ssparse needs3party ncbitxc2 -ssrvcmn needs $(LIBSSSUTILS) -ssrvcmn needs xconnect +ssrvcmn needs ssssys ssscli needs ssrvcmn -ssscli needs ssssys sssdb needs ssssys sssdb needs3party $(SYBASE_DLLS) sssdb needs3party $(SYBASE_LIBS) @@ -1019,7 +1035,7 @@ sybtcl64 needs3party sybunic64 sybunic64 needs3party $(ORIG_LIBS) tables needs3party $(ORIG_LIBS) tax_xml needs $(GPIPE_GENCOLL_LIBS) -tax_xml needs simple_asm +tax_xml needs bacterial_pipeline_proc taxon needs xser taxon1 needs $(SEQ_LIBS) taxon1 needs pub @@ -1037,7 +1053,6 @@ tds_ftds64 needs3party $(ORIG_LIBS) tds_ftds95 needs3party $(KRB5_LIBS) tds_ftds95 needs3party $(NETWORK_LIBS) tds_ftds95 needs3party $(ORIG_LIBS) -tds_ftds95 needs3party $(RT_LIBS) tea_crypt needs generic_db_utils test_boost includes3party $(BOOST_TEST_LIBS) test_boost needs xncbi @@ -1057,7 +1072,7 @@ tinyseq needs xser tiol needs $(Z_LIB) tiol needs3party $(ORIG_LIBS) tiol needs3party $(Z_LIBS) -tracking_utils needs gpipe_attr +tracking_utils needs gpipe_common trackmgr needs $(SEQ_LIBS) trackmgr needs pub trackmgr_objtools needs $(OBJMGR_LIBS) @@ -1073,15 +1088,16 @@ trackmgrgridcli needs xconnserv tv_objects needs biotree tvlib needs $(OBJMGR_LIBS) tvlib needs gui_glmesa +tvlib needs ncbi_xcache_netcache tvlib needs tv_objects tvlib needs uudutil tvlib needs w_phylo_tree txclient needs xconnect +txcscu needs txclient +txcscu needs xregexp txserv needs xmlwrapp -txserv needs3party $(RT_LIBS) txserv14 needs txxmldoc txserv14 needs xconnect -txserv14 needs3party $(RT_LIBS) txxmldoc needs $(COMPRESS_LIBS) txxmldoc needs xutil txxmldoc needs3party $(LIBXML_LIBS) @@ -1096,7 +1112,6 @@ u2tl needs3party $(Z_LIBS) uilist needs xser unicoll_dump_access needs gpipe_sqlite univ_prot_access needs gpipe_common -univ_prot_access needs xser uudutil needs $(COMPRESS_LIBS) uudutil needs gbproj uudutil needs xconnserv @@ -1104,8 +1119,12 @@ uuid needs3party $(ORIG_LIBS) valerr needs xser valid needs general valid needs xregexp -validate_regions needs $(GPIPE_GENCOLL_LIBS) -validate_regions needs simple_asm +validate_regions needs gc_asn_access +validation_details needs xmlwrapp +validation_details needs xobjwrite +validation_results needs $(SEQ_LIBS) +validation_results needs pub +validation_results needs xmlwrapp variation needs $(SEQ_LIBS) variation needs pub variation_utils needs variation @@ -1155,21 +1174,19 @@ w_phylo_tree needs w_data w_phylo_tree needs w_gl w_phylo_tree needs xalgophytree w_seq needs w_text_widget +w_seq_desktop needs w_wx w_seq_graphic needs genesbyloc w_seq_graphic needs gui_config w_seq_graphic needs gui_graph -w_seq_graphic needs gui_objects -w_seq_graphic needs hgvs w_seq_graphic needs ncbi_xcache_netcache -w_seq_graphic needs trackmgr w_seq_graphic needs w_aln_score w_seq_graphic needs w_gl +w_seq_graphic needs w_loaders w_seq_graphic needs w_seq w_seq_text needs gui_config w_seq_text needs w_gl -w_seq_tree needs w_gl w_snp_bins needs w_seq_graphic -w_snp_filter needs w_wx +w_snp_filter needs xncbi w_snp_ld needs w_seq_graphic w_snp_track needs w_seq_graphic w_snp_track needs w_snp_filter @@ -1182,6 +1199,12 @@ w_wx needs gui_print w_wx needs3party $(WXWIDGETS_GL_LIBS) w_wx needs3party $(WXWIDGETS_LIBS) we_cpp needs xser +wgmlst needs xncbi +wgmlst needs3party $(BOOST_SYSTEM_LIBS) +wgmlst_genome_pairwise_distance needs $(COMPRESS_LIBS) +wgmlst_genome_pairwise_distance needs wgmlst_store +wgmlst_store needs $(SEQ_LIBS) +wgmlst_store needs pub writedb needs $(OBJREAD_LIBS) writedb needs seqdb wx_base-3.0 needs $(Z_LIB) @@ -1274,14 +1297,12 @@ xaligndb needs dbapi xaligndb needs xalgoalignsplign xalnmgr needs tables xalnmgr needs xobjutil -xalntool needs xhtml -xalntool needs xobjutil +xalntool needs align_format xannot_builder needs gpipe_asn_proc xasmcompare needs $(SEQ_LIBS) xasmcompare needs pub xasn needs xhtml xasn needs3party $(NCBI_C_ncbi) -xassembly_svc needs gcaccess_utils xassembly_svc needs xgencollstats xbiosample_util needs $(OBJEDIT_LIBS) xbiosample_util needs $(XFORMAT_LIBS) @@ -1310,13 +1331,13 @@ xcddalignview needs ncbimime xcgi needs xutil xcgi_redirect needs xcgi xcgi_redirect needs xhtml -xcleanup needs submit xcleanup needs taxon3 xcleanup needs valid xcleanup needs xobjutil xcompress needs $(CMPRS_LIB) xcompress needs xutil xcompress needs3party $(CMPRS_LIBS) +xconnect includes connect xconnect includes connssl xconnect needs xncbi xconnext includes $(CONNEXT) @@ -1344,18 +1365,17 @@ xformat needs gbseq xformat needs mlacli xformat needs xalnmgr xformat needs xcleanup -xgencoll needs aligndb_reader xgencoll needs gencoll_client -xgencoll needs ncbi_xcache_netcache xgencoll needs simple_asm -xgencollstats needs $(GPIPE_GENCOLL_LIBS) +xgencollstats needs gc_asn_access xgencollstats needs gencoll_stats -xgencollstats needs simple_asm xgp_manifest needs xser -xgpgcreport needs $(GPIPE_GENCOLL_LIBS) +xgpgcreport needs gc_asn_access xgpgcreport needs gencoll_release_report -xgpgcreport needs simple_asm +xgpp_console needs $(XCONNEXT) xgpp_console needs dbapi +xgpp_console needs ncbi_xdbapi_ftds +xgpp_console needs xconnect xgpp_console_access needs xgpp_console_commands xgpp_console_commands needs gpipe_common xgpp_console_commands needs xgpp_console @@ -1390,6 +1410,10 @@ xid_wgs needs3party $(VDB_LIBS) xid_wgsdb needs xid_utils ximage needs xncbi ximage needs3party $(IMAGE_LIBS) +xlinear_prog needs xncbi +xlsxwriter needs $(Z_LIB) +xlsxwriter needs3party $(ORIG_LIBS) +xlsxwriter needs3party $(Z_LIBS) xmergetree needs $(SOBJMGR_LIBS) xml2 needs3party $(ORIG_LIBS) xmlreaders needs xmlwrapp @@ -1423,6 +1447,7 @@ xobjreadex needs $(OBJREAD_LIBS) xobjreadex needs xobjutil xobjsimple needs $(OBJMGR_LIBS) xobjutil needs $(SOBJMGR_LIBS) +xobjutil needs submit xobjwrite needs $(OBJREAD_LIBS) xobjwrite needs $(XFORMAT_LIBS) xobjwrite needs variation_utils @@ -1467,21 +1492,22 @@ xstruct_dp needs xncbi xstruct_thread needs xutil xstruct_util needs $(BLAST_LIBS) xstruct_util needs xstruct_dp -xsubmit2id needs sqlitewrapp -xsubmit2id needs xid_utils +xsubmit2id needs idload_utils xsvcgi needs $(DBAPI_CTLIB) xsvcgi needs $(OBJMGR_LIBS) xsvcgi needs $(ncbi_xreader_pubseqos2) -xsvcgi needs gui_objects +xsvcgi needs gui_objutils xsvcgi needs ncbi_xcache_netcache xsvcgi needs ncbi_xloader_bam xsvcgi needs ncbi_xloader_csra +xsvcgi needs ncbi_xloader_snp xsvcgi needs ncbi_xloader_vdbgraph xsvcgi needs ncbi_xloader_wgs xsvcgi needs uudutil xsvcgi needs3party $(SYBASE_DLLS) xsvcgi needs3party $(SYBASE_LIBS) xsvdata needs $(BLAST_INPUT_LIBS) +xsvdata needs gui_objects xsvdata needs hgvs xsvdata needs sv_objects xsvdata needs trackmgr diff --git a/c++/src/build-system/ncbi_package b/c++/src/build-system/ncbi_package index 56a6051c..d00491fd 100644 --- a/c++/src/build-system/ncbi_package +++ b/c++/src/build-system/ncbi_package @@ -1 +1 @@ -1 \ No newline at end of file +1 diff --git a/c++/src/build-system/ncbi_package_name b/c++/src/build-system/ncbi_package_name index 865e56f1..a5ac534c 100644 --- a/c++/src/build-system/ncbi_package_name +++ b/c++/src/build-system/ncbi_package_name @@ -1 +1 @@ -blast \ No newline at end of file +blast diff --git a/c++/src/build-system/ncbi_package_version b/c++/src/build-system/ncbi_package_version index 914ec967..860487ca 100644 --- a/c++/src/build-system/ncbi_package_version +++ b/c++/src/build-system/ncbi_package_version @@ -1 +1 @@ -2.6.0 \ No newline at end of file +2.7.1 diff --git a/c++/src/build-system/new_module.sh.in b/c++/src/build-system/new_module.sh.in index 49953686..821dcee4 100644 --- a/c++/src/build-system/new_module.sh.in +++ b/c++/src/build-system/new_module.sh.in @@ -1,6 +1,6 @@ @script_shell@ # -# $Id: new_module.sh.in 484944 2015-11-17 16:42:34Z ucko $ +# $Id: new_module.sh.in 536530 2017-05-19 15:51:02Z ucko $ # Authors: Eugene Vasilchenko, NCBI; Aaron Ucko, NCBI top_srcdir="@abs_top_srcdir@" @@ -208,9 +208,11 @@ case "$MAKE" in echo $MAKE -f "$makemodule" "MODULE=$module" "MODULE_PATH=$mp" \ "MODULE_ASN=$spec" "MODULE_IMPORT='$imports'" \ "IMPDEPS='$impdeps'" "IMPFILES='$impfiles'" "top_srcdir=$p" \ - "DATATOOL=$datatool" "MODULE_SEARCH=$search" "$@" + "builddir=$build_root/build" "DATATOOL=$datatool" \ + "MODULE_SEARCH=$search" "$@" ;; esac $MAKE -f "$makemodule" "MODULE=$module" "MODULE_PATH=$mp" "MODULE_ASN=$spec" \ "MODULE_IMPORT=$imports" "IMPDEPS=$impdeps" "IMPFILES=$impfiles" \ - "top_srcdir=$p" "DATATOOL=$datatool" "MODULE_SEARCH=$search" "$@" + "top_srcdir=$p" "builddir=$build_root/build" "DATATOOL=$datatool" \ + "MODULE_SEARCH=$search" "$@" diff --git a/c++/src/build-system/project_tree_builder.ini b/c++/src/build-system/project_tree_builder.ini index bf6c052f..a904074f 100644 --- a/c++/src/build-system/project_tree_builder.ini +++ b/c++/src/build-system/project_tree_builder.ini @@ -1,4 +1,4 @@ -# $Id: project_tree_builder.ini 520070 2016-11-22 14:36:17Z ivanov $ +# $Id: project_tree_builder.ini 546202 2017-09-14 17:22:02Z ivanov $ ############################################################################### @@ -35,6 +35,7 @@ ProvidedRequests = CXX_Toolkit \ LocalBZ2 \ LocalPCRE \ LocalZ \ + LocalLMDB \ MT # These requiremenst are also met @@ -133,7 +134,7 @@ Defines = HAVE_BERKELEY_DB \ # The definition of the following macros used in project makefiles # depends on availability of Components # Each macro on the list has the section with the same name in this file -Macros = BDB_LIB BDB_CACHE_LIB NCBI_CRYPT CONNEXT XCONNEXT \ +Macros = BDB_LIB BDB_CACHE_LIB SQLITE3_WRAPPER NCBI_CRYPT CONNEXT XCONNEXT \ ncbi_xreader_pubseqos ncbi_xreader_pubseqos2 UNLESS_PUBSEQOS \ FASTCGI_OBJS DBAPI_DRIVER DBAPI_CTLIB DBAPI_DBLIB \ DBAPI_ODBC LOCAL_LBSM ncbi_java VDB_REQ bamread sraread \ @@ -146,8 +147,8 @@ Macros = BDB_LIB BDB_CACHE_LIB NCBI_CRYPT CONNEXT XCONNEXT \ # Depending on the availability of 3rd party library, # the toolkit will use either external or internal one # See section in this file with the name of the latter entry in each pair -LibChoices = z/Z bz2/BZ2 regexp/PCRE lzo/LZO -ComponentChoices = LocalZ/Z LocalBZ2/BZ2 LocalPCRE/PCRE +LibChoices = z/Z bz2/BZ2 lzo/LZO regexp/PCRE lmdb/LMDB +ComponentChoices = LocalZ/Z LocalBZ2/BZ2 LocalPCRE/PCRE LocalLMDB/LMDB #---------------------------------------------------------------------------- # Some toolkit applications require 3rd party DLLs @@ -186,8 +187,7 @@ ThirdPartyLibsToInstall = BerkeleyDB \ # Macros used here should be defined either in this section, or in compiler specific section. ThirdParty_BerkeleyDB = $(ThirdPartyBasePath)\\berkeleydb\\$(msvc_3rd)\\4.6.21.NC -ThirdParty_Boost_Test = $(ThirdPartyBasePath)\\boost\\$(msvc_3rd)\\1.56.0 -ThirdParty_Boost_Spirit = $(ThirdPartyBasePath)\\boost\\$(msvc_3rd)\\1.56.0 +ThirdParty_Boost = $(ThirdPartyBasePath)\\boost\\$(msvc_3rd)\\1.61.0 ThirdParty_BZ2 = $(ThirdPartyBasePath)\\bzip2\\$(msvc_3rd)\\1.0.6 ThirdParty_fastcgi = $(ThirdPartyBasePath)\\fastcgi\\$(msvc_3rd)\\2.4.0 ThirdParty_FreeType = $(ThirdPartyBasePath)\\freetype\\$(msvc_3rd)\\2.4.10 @@ -206,17 +206,17 @@ ThirdParty_muParser = $(ThirdPartyBasePath)\\muparser\\$(msvc_3rd)\\1.30 ThirdParty_OpenSSL = $(ThirdPartyBasePath)\\openssl\\$(msvc_3rd)\\1.0.1g ThirdParty_PCRE = $(ThirdPartyBasePath)\\pcre\\$(msvc_3rd)\\7.9 ThirdParty_PNG = $(ThirdPartyBasePath)\\png\\$(msvc_3rd)\\1.2.7 -ThirdParty_SQLITE3 = $(ThirdPartyBasePath)\\sqlite\\$(msvc_3rd)\\3.6.14.2 +ThirdParty_SQLITE3 = $(ThirdPartyBasePath)\\sqlite\\$(msvc_3rd)\\3.8.10.1 ThirdParty_Sybase = $(ThirdPartyBasePath)\\sybase\\$(msvc_3rd)\\15.5 ThirdParty_TIFF = $(ThirdPartyBasePath)\\tiff\\$(msvc_3rd)\\3.6.1 -ThirdParty_wxWidgets = $(ThirdPartyBasePath)\\wxwidgets\\$(msvc_3rd)\\3.1.0_no28 +ThirdParty_wxWidgets = $(ThirdPartyBasePath)\\wxwidgets\\$(msvc_3rd)\\3.1.0_no28-ncbi1 ThirdParty_Xalan = $(ThirdPartyBasePath)\\xalan\\$(msvc_3rd)\\1.10.0-20080814 ThirdParty_Xerces = $(ThirdPartyBasePath)\\xerces\\$(msvc_3rd)\\2.8.0 ThirdParty_XML = $(ThirdPartyBasePath)\\xml\\$(msvc_3rd)\\2.7.8 ThirdParty_XSLT = $(ThirdPartyBasePath)\\xslt\\$(msvc_3rd)\\1.1.26 ThirdParty_Z = $(ThirdPartyBasePath)\\z\\$(msvc_3rd)\\1.2.8 ThirdParty_JDK = $(ThirdPartyBasePath)\\jdk\\1.6.0_25 -ThirdParty_VDB = $(ThirdPartyVDBBasePath)\\vdb\\vdb-versions\\2.8.0 +ThirdParty_VDB = $(ThirdPartyVDBBasePath)\\vdb\\vdb-versions\\2.8.2 PYTHON_PATH = $(ThirdPartyAppsBasePath)\\Python252\\$(msvc_3rd) @@ -475,19 +475,19 @@ DefinesPath = common/config/ncbiconf_xcode_site.h ThirdParty_BerkeleyDB = $(XCode_ThirdPartyBasePath)/BerkeleyDB -ThirdParty_Boost_Test = $(XCode_ThirdPartyBasePath)/boost-1.53.0-ncbi1 +ThirdParty_Boost = $(XCode_ThirdPartyBasePath)/boost-1.62.0-ncbi1 ThirdParty_JPEG = $(XCode_ThirdPartyBasePath)/safe-sw ThirdParty_PNG = /opt/X11 ThirdParty_TIFF = $(XCode_ThirdPartyBasePath)/safe-sw ThirdParty_LZO = $(XCode_ThirdPartyBasePath)/lzo-2.05 -ThirdParty_SQLITE3 = $(XCode_ThirdPartyBasePath)/sqlite-3.6.14.2-ncbi1 +ThirdParty_SQLITE3 = $(XCode_ThirdPartyBasePath)/sqlite-3.8.10.1-ncbi1 ThirdParty_XML = $(XCode_ThirdPartyBasePath)/libxml-2.7.8 ThirdParty_XSLT = $(XCode_ThirdPartyBasePath)/libxml-2.7.8 ThirdParty_GLEW = $(XCode_ThirdPartyBasePath)/glew-1.5.8 ThirdParty_wxWidgets = $(XCode_ThirdPartyBasePath)/wxWidgets-3.1.0-ncbi2 ThirdParty_FreeType = /opt/X11 ThirdParty_FTGL = $(XCode_ThirdPartyBasePath)/ftgl-2.1.3-rc5 -ThirdParty_VDB = $(XCode_ThirdPartyVDBBasePath)/vdb/vdb-versions/2.8.0 +ThirdParty_VDB = $(XCode_ThirdPartyVDBBasePath)/vdb/vdb-versions/2.8.2 ThirdParty_GMP = $(Xcode_ThirdPartyBasePath)/gmp-6.0.0a ThirdParty_Nettle = $(Xcode_ThirdPartyBasePath)/nettle-3.1.1 ThirdParty_GNUTLS = $(Xcode_ThirdPartyBasePath)/gnutls-3.4.0 @@ -539,6 +539,7 @@ Z_INCLUDE = z util/compress/zlib/ BZ2_INCLUDE = bz2 util/compress/bzip2/ LZO_INCLUDE = lzo . PCRE_INCLUDE = regexp util/regexp/ +LMDB_INCLUDE = lmdb util/lmdb/ util/lmdbxx/ #============================================================================ @@ -561,6 +562,7 @@ BZ2_LIB = bz2 Z_LIB = z LZO_LIB = lzo PCRE_LIB = regexp +LMDB_LIB = lmdb FTDS64_INCLUDE = dbapi/driver/ftds64/ dbapi/driver/ftds64/freetds/ FTDS64_LIB = ct_ftds64 tds_ftds64 @@ -574,8 +576,10 @@ FTDS_INCLUDE = dbapi/driver/ftds95/ dbapi/driver/ftds95/freetds/ FTDS_LIB = ct_ftds95 tds_ftds95 FTDS_LIBS = -TLS_INCLUDE = $(ThirdParty_OpenSSL)/include +TLS_INCLUDE = $(ThirdParty_GNUTLS)/include GNUTLS_INCLUDE = $(ThirdParty_GNUTLS)/include +MBEDTLS_INCLUDE = +OPENSSL_INCLUDE = $(ThirdParty_OpenSSL)/include LIBXML_INCLUDE = $(ThirdParty_XML)/include LIBXSLT_INCLUDE = $(ThirdParty_XSLT)/include @@ -658,6 +662,9 @@ Component=GNUTLS [NETWORK_LIBS] Component=GNUTLS +[NETWORK_PURE_LIBS] +Component=GNUTLS + [LIBS] Component= @@ -731,6 +738,8 @@ Component = LocalZ Component = LocalBZ2 [USE_LOCAL_PCRE] Component = LocalPCRE +[USE_LOCAL_LMDB] +Component = LocalLMDB [HAVE_BOOST_TEST] Component=Boost.Test @@ -828,6 +837,15 @@ Component=Sybase [HAVE_LIBSQLITE3] Component=SQLITE3 +[sqlitewrapp] +Component = SQLITE3 sqlitewrapp +FILES = src\\db\\sqlite\\Makefile.sqlitewrapp.lib +CONFS = DebugMT DebugDLL ReleaseMT ReleaseDLL + +[SQLITE3_WRAPPER] +Component = SQLITE3 sqlitewrapp +Value = sqlitewrapp + [FTDS64_CTLIB_LIBS] Component=Iconv, KRB5, GNUTLS [ICONV_LIBS] @@ -1673,44 +1691,54 @@ LIBPATH = $(ThirdParty_XSLT)/lib$(sfx64) #---------------------------------------------------------------------------- [Boost.Test] -INCLUDE = $(ThirdParty_Boost_Test)\\include +INCLUDE = $(ThirdParty_Boost)\\include LIB = libboost_unit_test_framework.lib DEFINES = BOOST_AUTO_LINK_NOMANGLE CONFS = DebugMT DebugDLL ReleaseMT ReleaseDLL [Boost.Test.debug.DebugMT] -LIBPATH = $(ThirdParty_Boost_Test)\\lib_static\\debugmt +LIBPATH = $(ThirdParty_Boost)\\lib_static\\debugmt [Boost.Test.debug.DebugDLL] -LIBPATH = $(ThirdParty_Boost_Test)\\lib_static\\debugdll +LIBPATH = $(ThirdParty_Boost)\\lib_static\\debugdll [Boost.Test.release.ReleaseMT] -LIBPATH = $(ThirdParty_Boost_Test)\\lib_static\\releasemt +LIBPATH = $(ThirdParty_Boost)\\lib_static\\releasemt [Boost.Test.release.ReleaseDLL] -LIBPATH = $(ThirdParty_Boost_Test)\\lib_static\\releasedll +LIBPATH = $(ThirdParty_Boost)\\lib_static\\releasedll [Boost.Test.xcode] -INCLUDE = $(ThirdParty_Boost_Test)/include +INCLUDE = $(ThirdParty_Boost)/include LIB = -lboost_unit_test_framework-clang-darwin CONFS = Debug DebugMT DebugDLL Release ReleaseMT ReleaseDLL -LIBPATH = $(ThirdParty_Boost_Test)/lib +LIBPATH = $(ThirdParty_Boost)/lib #---------------------------------------------------------------------------- [Boost.Test.Included] -INCLUDE = $(ThirdParty_Boost_Test)\\include +INCLUDE = $(ThirdParty_Boost)\\include DEFINES = BOOST_TEST_NO_LIB CONFS = DebugMT DebugDLL ReleaseMT ReleaseDLL [Boost.Test.Included.xcode] -INCLUDE = $(ThirdParty_Boost_Test)/include +INCLUDE = $(ThirdParty_Boost)/include CONFS = DebugMT DebugDLL ReleaseMT ReleaseDLL #---------------------------------------------------------------------------- [Boost.Spirit] -INCLUDE = $(ThirdParty_Boost_Spirit)\\include +INCLUDE = $(ThirdParty_Boost)\\include +DEFINES = BOOST_AUTO_LINK_NOMANGLE +LIB = libboost_thread.lib CONFS = DebugMT DebugDLL ReleaseMT ReleaseDLL +[Boost.Spirit.debug.DebugMT] +LIBPATH = $(ThirdParty_Boost)\\lib_static\\debugmt +[Boost.Spirit.debug.DebugDLL] +LIBPATH = $(ThirdParty_Boost)\\lib_static\\debugdll +[Boost.Spirit.release.ReleaseMT] +LIBPATH = $(ThirdParty_Boost)\\lib_static\\releasemt +[Boost.Spirit.release.ReleaseDLL] +LIBPATH = $(ThirdParty_Boost)\\lib_static\\releasedll [Boost.Spirit.xcode] -INCLUDE = $(ThirdParty_Boost_Test)/include +INCLUDE = $(ThirdParty_Boost)/include CONFS = DebugMT DebugDLL ReleaseMT ReleaseDLL @@ -1839,7 +1867,7 @@ LIB = -framework Kerberos [UUID] INCLUDE = LIBPATH = -LIB = uuid.lib +LIB = uuid.lib rpcrt4.lib CONFS = DebugMT DebugDLL ReleaseMT ReleaseDLL [UUID.xcode] LIB = diff --git a/c++/src/build-system/project_tree_builder/CMakeLists.project_tree_builder.app.txt b/c++/src/build-system/project_tree_builder/CMakeLists.project_tree_builder.app.txt new file mode 100644 index 00000000..a16250fd --- /dev/null +++ b/c++/src/build-system/project_tree_builder/CMakeLists.project_tree_builder.app.txt @@ -0,0 +1,19 @@ +# +# Autogenerated from /net/nasan50/vol/gpipe_dev/dicuccio/cpp-toolkit/cpp-cmake/src/build-system/project_tree_builder/Makefile.project_tree_builder.app +# +add_executable(project_tree_builder-app + file_contents msvc_configure msvc_makefile msvc_masterproject_generator + msvc_prj_generator msvc_prj_utils msvc_project_context msvc_site + msvc_sln_generator proj_builder_app proj_datatool_generated_src + proj_item proj_tree proj_tree_builder proj_src_resolver proj_utils + resolver msvc_configure_prj_generator proj_projects msvc_dlls_info + msvc_prj_files_collector configurable_file ptb_gui ptb_registry + mac_prj_generator prj_file_collector +) + +set_target_properties(project_tree_builder-app PROPERTIES OUTPUT_NAME project_tree_builder) + +target_link_libraries(project_tree_builder-app + xregexp xutil +) + diff --git a/c++/src/build-system/project_tree_builder/CMakeLists.txt b/c++/src/build-system/project_tree_builder/CMakeLists.txt new file mode 100644 index 00000000..a446a334 --- /dev/null +++ b/c++/src/build-system/project_tree_builder/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.project_tree_builder.app.txt) + +# Recurse subdirectories +add_subdirectory(msbuild) diff --git a/c++/src/build-system/project_tree_builder/msbuild/CMakeLists.txt b/c++/src/build-system/project_tree_builder/msbuild/CMakeLists.txt new file mode 100644 index 00000000..4644f8d1 --- /dev/null +++ b/c++/src/build-system/project_tree_builder/msbuild/CMakeLists.txt @@ -0,0 +1,6 @@ +############################################################################## +# +# + +# Include projects from this directory + diff --git a/c++/src/build-system/project_tree_builder/msvc_configure.cpp b/c++/src/build-system/project_tree_builder/msvc_configure.cpp index 249366f7..f160099a 100644 --- a/c++/src/build-system/project_tree_builder/msvc_configure.cpp +++ b/c++/src/build-system/project_tree_builder/msvc_configure.cpp @@ -1,4 +1,4 @@ -/* $Id: msvc_configure.cpp 474851 2015-07-31 19:50:36Z gouriano $ +/* $Id: msvc_configure.cpp 525287 2017-01-23 16:13:37Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -30,6 +30,7 @@ #include #include "msvc_configure.hpp" #include "proj_builder_app.hpp" +#include "util/random_gen.hpp" #include "ptb_err_codes.hpp" #ifdef NCBI_XCODE_BUILD @@ -141,8 +142,7 @@ void CMsvcConfigure::Configure(CMsvcSite& site, InitializeFrom(site); site.ProcessMacros(configs); - if (CMsvc7RegSettings::GetMsvcPlatform() >= CMsvc7RegSettings::eUnix || - GetApp().IsCMakeMode()) { + if (CMsvc7RegSettings::GetMsvcPlatform() >= CMsvc7RegSettings::eUnix) { return; } _TRACE("*** Creating Makefile.third_party.mk files ***"); @@ -164,8 +164,10 @@ void CMsvcConfigure::CreateConfH( const list& configs, const string& root_dir) { - if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix || - GetApp().IsCMakeMode()) { + ITERATE(list, p, configs) { + WriteExtraDefines( site, root_dir, *p); + } + if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) { return; } _TRACE("*** Creating local ncbiconf headers ***"); @@ -239,6 +241,44 @@ bool CMsvcConfigure::ProcessDefine(const string& define, return true; } +void CMsvcConfigure::WriteExtraDefines(CMsvcSite& site, const string& root_dir, const SConfigInfo& config) +{ + string cfg = CMsvc7RegSettings::GetConfigNameKeyword(); + string cfg_root_inc(root_dir); + if (!cfg.empty()) { + NStr::ReplaceInPlace(cfg_root_inc,cfg,config.GetConfigFullName()); + } + string extra = site.GetConfigureEntry("ExtraDefines"); + string filename = CDirEntry::ConcatPath(cfg_root_inc, extra); + int random_count = NStr::StringToInt(site.GetConfigureEntry("RandomValueCount"), NStr::fConvErr_NoThrow); + + if (extra.empty() || random_count <= 0 || CFile(filename).Exists()) { + return; + } + + string dir; + CDirEntry::SplitPath(filename, &dir); + CDir(dir).CreatePath(); + + CNcbiOfstream ofs(filename.c_str(), IOS_BASE::out | IOS_BASE::trunc ); + if ( !ofs ) + NCBI_THROW(CProjBulderAppException, eFileCreation, filename); + + WriteNcbiconfHeader(ofs); + + CRandom rnd(CRandom::eGetRand_Sys); + string prefix("#define NCBI_RANDOM_VALUE_"); + ofs << prefix << "TYPE Uint4" << endl; + ofs << prefix << "MIN 0" << endl; + ofs << prefix << "MAX " << std::hex + << std::showbase << rnd.GetMax() << endl << endl; + for (int i = 0; i < random_count; ++i) { + ofs << prefix << std::noshowbase << i + << setw(16) << std::showbase << rnd.GetRand() << endl; + } + ofs << endl; +} + void CMsvcConfigure::AnalyzeDefines( CMsvcSite& site, const string& root_dir, const SConfigInfo& config, const CBuildType& build_type) @@ -331,14 +371,8 @@ void CMsvcConfigure::AnalyzeDefines( } } -void CMsvcConfigure::WriteNcbiconfMsvcSite( - const string& full_path, const string& signature) const +CNcbiOfstream& CMsvcConfigure::WriteNcbiconfHeader(CNcbiOfstream& ofs) const { - CNcbiOfstream ofs(full_path.c_str(), - IOS_BASE::out | IOS_BASE::trunc ); - if ( !ofs ) - NCBI_THROW(CProjBulderAppException, eFileCreation, full_path); - ofs << endl; ofs <<"/* $" << "Id" << "$" << endl; @@ -377,7 +411,18 @@ void CMsvcConfigure::WriteNcbiconfMsvcSite( ofs <<"*/" << endl; ofs << endl; ofs << endl; + return ofs; +} + +void CMsvcConfigure::WriteNcbiconfMsvcSite( + const string& full_path, const string& signature) const +{ + CNcbiOfstream ofs(full_path.c_str(), + IOS_BASE::out | IOS_BASE::trunc ); + if ( !ofs ) + NCBI_THROW(CProjBulderAppException, eFileCreation, full_path); + WriteNcbiconfHeader(ofs); ITERATE(TConfigSite, p, m_ConfigSite) { if (p->second == '1') { diff --git a/c++/src/build-system/project_tree_builder/msvc_configure.hpp b/c++/src/build-system/project_tree_builder/msvc_configure.hpp index 8ba24b04..2e2cbb5e 100644 --- a/c++/src/build-system/project_tree_builder/msvc_configure.hpp +++ b/c++/src/build-system/project_tree_builder/msvc_configure.hpp @@ -1,7 +1,7 @@ #ifndef PROJECT_TREE_BULDER__MSVC_CONFIGURE__HPP #define PROJECT_TREE_BULDER__MSVC_CONFIGURE__HPP -/* $Id: msvc_configure.hpp 162507 2009-06-08 13:22:14Z gouriano $ +/* $Id: msvc_configure.hpp 510073 2016-08-10 17:39:54Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -66,9 +66,12 @@ private: const string& root_dir, const SConfigInfo& config, const CBuildType& build_type); + void WriteExtraDefines(CMsvcSite& site, + const string& root_dir, + const SConfigInfo& config); + CNcbiOfstream& WriteNcbiconfHeader(CNcbiOfstream& ofs) const; void WriteNcbiconfMsvcSite(const string& full_path, const string& signature) const; - // No value semantics CMsvcConfigure(const CMsvcConfigure&); CMsvcConfigure& operator= (CMsvcConfigure&); diff --git a/c++/src/build-system/project_tree_builder/proj_builder_app.cpp b/c++/src/build-system/project_tree_builder/proj_builder_app.cpp index 6e64ebe6..6450e0d4 100644 --- a/c++/src/build-system/project_tree_builder/proj_builder_app.cpp +++ b/c++/src/build-system/project_tree_builder/proj_builder_app.cpp @@ -1,4 +1,4 @@ -/* $Id: proj_builder_app.cpp 509504 2016-08-05 19:09:50Z fukanchi $ +/* $Id: proj_builder_app.cpp 537309 2017-05-30 17:01:38Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -405,7 +405,7 @@ struct PIsExcludedByDisuse //----------------------------------------------------------------------------- CProjBulderApp::CProjBulderApp(void) { - SetVersion( CVersionInfo(4,1,5) ); + SetVersion( CVersionInfo(4,2,1) ); m_ScanningWholeTree = false; m_Dll = false; m_AddMissingLibs = false; @@ -422,7 +422,6 @@ CProjBulderApp::CProjBulderApp(void) m_Dtdep = false; m_AddMissingDep = false; m_LibDep = false; - m_CMakeMode = false; m_Ide = 0; m_ExitCode = 0; } @@ -720,21 +719,17 @@ int CProjBulderApp::Run(void) m_ExitCode = 0; } PTB_INFO("Creating projects..."); - if (IsCMakeMode()) { - CMakeGenerator::GenerateCMakeTree(prj_tree); - } else { - if (CMsvc7RegSettings::GetMsvcPlatform() < CMsvc7RegSettings::eUnix) { - GenerateMsvcProjects(prj_tree); - } - else if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) { - GenerateUnixProjects(prj_tree); - } - else { - GenerateMacProjects(prj_tree); - } - ReportGeneratedFiles(); - ReportProjectWatchers(); + if (CMsvc7RegSettings::GetMsvcPlatform() < CMsvc7RegSettings::eUnix) { + GenerateMsvcProjects(prj_tree); + } + else if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) { + GenerateUnixProjects(prj_tree); + } + else { + GenerateMacProjects(prj_tree); } + ReportGeneratedFiles(); + ReportProjectWatchers(); // PTB_INFO("Done. Elapsed time = " << sw.Elapsed() << " seconds"); return m_ExitCode; @@ -1865,7 +1860,6 @@ void CProjBulderApp::ParseArguments(void) CDirEntry::CreateRelativePath(m_Root, m_Subtree)); } m_Solution = CDirEntry::NormalizePath(args["solution"].AsString()); - m_CMakeMode = NStr::CompareNocase(CDirEntry(m_Solution).GetName(), "cmake?") == 0; if (m_Solution == "\"\"") { m_Solution = ""; } @@ -1880,7 +1874,7 @@ void CProjBulderApp::ParseArguments(void) if (!CDirEntry::IsAbsolutePath(v)) { v = CDirEntry::ConcatPath(m_Root,v); } - LoadConfig(GetConfig(),&v); + LoadConfig(GetRWConfig(),&v); } string subtree; m_CustomConfiguration.GetPathValue("__arg_subtree", subtree); @@ -2655,7 +2649,7 @@ void CProjBulderApp::LoadDepGraph(const string& filename) bool is_framework = false; if (NStr::StartsWith(*t, "-l")) { is_lib = true; - t_name = t->substr(2); + t_name = t_name.substr(2); } else if (NStr::CompareNocase(*t,"-framework") == 0) { if (t != third_list.end()) { is_framework = true; diff --git a/c++/src/build-system/project_tree_builder/proj_builder_app.hpp b/c++/src/build-system/project_tree_builder/proj_builder_app.hpp index 727d6fe4..47297d5e 100644 --- a/c++/src/build-system/project_tree_builder/proj_builder_app.hpp +++ b/c++/src/build-system/project_tree_builder/proj_builder_app.hpp @@ -1,7 +1,7 @@ #ifndef PROJECT_TREE_BULDER__PROJ_BUILDER_APP__HPP #define PROJECT_TREE_BULDER__PROJ_BUILDER_APP__HPP -/* $Id: proj_builder_app.hpp 469083 2015-06-01 15:28:15Z gouriano $ +/* $Id: proj_builder_app.hpp 524100 2017-01-09 19:49:55Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -136,7 +136,6 @@ public: bool m_Dtdep; bool m_AddMissingDep; bool m_LibDep; - bool m_CMakeMode; int m_Ide; string m_Arch; @@ -155,8 +154,6 @@ public: map > m_3PartyLibraryOrder; public: - bool IsCMakeMode(void) const {return m_CMakeMode;} - bool UseAbsolutePath(const string& path) const; void AddCustomMetaData(const string& file); void GetMetaDataFiles(list* files) const; diff --git a/c++/src/build-system/project_tree_builder/proj_projects.cpp b/c++/src/build-system/project_tree_builder/proj_projects.cpp index c624e80e..e0dd54ba 100644 --- a/c++/src/build-system/project_tree_builder/proj_projects.cpp +++ b/c++/src/build-system/project_tree_builder/proj_projects.cpp @@ -1,4 +1,4 @@ -/* $Id: proj_projects.cpp 485908 2015-11-30 14:28:08Z gouriano $ +/* $Id: proj_projects.cpp 524100 2017-01-09 19:49:55Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -90,9 +90,6 @@ void CProjectsLstFileFilter::InitFromString(const string& subtree) } m_listEnabled.push_back( s ); } - if (GetApp().IsCMakeMode()) { - return; - } // m_ExcludePotential = true; m_ExcludePotential = GetApp().GetBuildRoot().empty(); } diff --git a/c++/src/build-system/project_tree_builder/proj_tree.cpp b/c++/src/build-system/project_tree_builder/proj_tree.cpp index 7d59f3cb..a8aa207c 100644 --- a/c++/src/build-system/project_tree_builder/proj_tree.cpp +++ b/c++/src/build-system/project_tree_builder/proj_tree.cpp @@ -1,4 +1,4 @@ -/* $Id: proj_tree.cpp 485908 2015-11-30 14:28:08Z gouriano $ +/* $Id: proj_tree.cpp 524100 2017-01-09 19:49:55Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -101,12 +101,10 @@ void CProjectItemsTree::CreateFrom(const string& root_src, tree->m_Projects.clear(); tree->m_RootSrc = root_src; - if (!GetApp().IsCMakeMode()) { - string dataspec = GetApp().GetDataspecProjId(); - string utility_projects_dir = GetApp().GetUtilityProjectsSrcDir(); - SLibProjectT::DoCreateDataSpec( - utility_projects_dir, dataspec, dataspec, tree, eMakeType_Undefined); - } + string dataspec = GetApp().GetDataspecProjId(); + string utility_projects_dir = GetApp().GetUtilityProjectsSrcDir(); + SLibProjectT::DoCreateDataSpec( + utility_projects_dir, dataspec, dataspec, tree, eMakeType_Undefined); ITERATE(TFiles, p, makein) { @@ -965,428 +963,6 @@ void CMakeProject::Write(const string& dirname) const out << endl; } -///////////////////////////////////////////////////////////////////////////// - -void CMakeGenerator::GenerateCMakeTree(CProjectItemsTree& projects_tree) -{ - CProjBulderApp& theApp = GetApp(); - string build_dir(CDirEntry(theApp.m_Solution).GetDir()); - string sln_dir(CDirEntry::ConcatPath(build_dir, "_cmake")); - string src_root( CDirEntry::ConvertToOSPath(projects_tree.m_RootSrc)); - string separator; - separator += CDirEntry::GetPathSeparator(); - map mkIn; - map mkPrj; - -// root node definitions - { - string unix_cfg = theApp.GetConfig().Get( CMsvc7RegSettings::GetMsvcSection(),"MetaData"); - if (!unix_cfg.empty()) { - unix_cfg = CDirEntry::ConcatPath(build_dir,unix_cfg); - if (CFile(unix_cfg).Exists()) { - CSimpleMakeFileContents unixDef; - CSimpleMakeFileContents::LoadFrom(unix_cfg,&unixDef); - string bldType; - if (unixDef.GetValue("DEBUG_SFX", bldType)) { - mkIn[""].AddDefinition("CMAKE_BUILD_TYPE", bldType); - } - } - } - mkIn[""].AddHeader("cmake_minimum_required(VERSION 2.8)"); - mkIn[""].AddDefinition("NCBI_TREE_ROOT", - CDirEntry::DeleteTrailingPathSeparator( - CDirEntry::ConcatPath("${CMAKE_CURRENT_SOURCE_DIR}", - CDirEntry::CreateRelativePath(sln_dir, theApp.m_Root)))); - mkIn[""].AddDefinition("NCBI_BUILD_ROOT", - CDirEntry::DeleteTrailingPathSeparator( - CDirEntry::ConcatPath("${CMAKE_CURRENT_SOURCE_DIR}", - CDirEntry::CreateRelativePath(sln_dir, build_dir)))); - mkIn[""].AddDefinition( "NCBI_CMAKE_ROOT", "${CMAKE_CURRENT_SOURCE_DIR}"); - mkIn[""].AddDefinition("CMAKE_MODULE_PATH", - "${CMAKE_MODULE_PATH} ${NCBI_TREE_ROOT}/src/build-system/cmake"); - - mkIn[""].AddInclude("CMakeLists.defaults"); - } - - - ITERATE(CProjectItemsTree::TProjects, p, projects_tree.m_Projects) { - const CProjItem& prj = p->second; - if (prj.m_MakeType >= eMakeType_Expendable) { -// expendables can and do fail to compile - continue; - } - string relpath = - CDirEntry::DeleteTrailingPathSeparator( - CDirEntry::CreateRelativePath(src_root, - CDirEntry::ConvertToOSPath(prj.m_SourcesBaseDir))); - list pathnodes; - NStr::Split(relpath, separator, pathnodes, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); - -// subdirectories/ build tree - string curpath; - ITERATE( list, n, pathnodes) { - mkIn[curpath].AddSubdir(*n); - if (!curpath.empty()) { - curpath += separator; - } - curpath += *n; - } - - string prj_name(CreateProjectName( p->first)); - string prj_path(CDirEntry::ConcatPath(relpath,prj_name)); - - mkIn[ relpath].AddProject( prj_name); - mkPrj[prj_path].SetProjKey( p->first); - -// sources - mkPrj[prj_path].AddDefinition("NCBI_PROJECT_SRC_DIR", "${NCBI_TREE_ROOT}/src/" + relpath); - mkPrj[prj_path].AddDefinition("NCBI_PROJECT_BUILD_DIR", "${NCBI_BUILD_ROOT}/" + relpath); - mkPrj[prj_path].AddDefinition("srcdir", "${NCBI_PROJECT_SRC_DIR}"); - - list prj_sources; - if (CMsvc7RegSettings::GetMsvcPlatform() == CMsvc7RegSettings::eUnix) { - prj.m_DataSource.GetValue("UNIX_SRC", prj_sources); - } - prj_sources.insert( prj_sources.end(), prj.m_Sources.begin(), prj.m_Sources.end()); - bool smth_by_datatool = false; - string location_default("${NCBI_PROJECT_SRC_DIR}"); - ITERATE( list, s, prj_sources) { - string relname = CMsvcSite::ToOSPath(*s); - string name = CDirEntry::ConcatPath(prj.m_SourcesBaseDir, relname); - if (s->at(0) != '@' && s->at(0) != '$') { - bool isfound = false; - string location(location_default); - string ext = SourceFileExt(name); - if (NStr::EndsWith(ext, ".in")) { - name = CDirEntry::ConcatPath(CDirEntry::ConcatPath(build_dir, relpath), *s); - relname = CDirEntry(name).GetName(); - location = "${NCBI_PROJECT_BUILD_DIR}"; - isfound = true; - } else if (!prj.m_DatatoolSources.empty()) { - const CDataToolGeneratedSrc *pFound = IsProducedByDatatool(name, prj); - if (pFound) { - smth_by_datatool = true; - location = CDirEntry::ConcatPath(location, - CDirEntry::CreateRelativePath(prj.m_SourcesBaseDir, - pFound->m_SourceBaseDir)); - isfound = true; - mkPrj[prj_path].AddProperty( - CMakeProperty("set_source_files_properties") - .AddValue(CDirEntry::ConcatPath(location, relname + ".cpp") + - " PROPERTIES GENERATED 1")); - } - } - isfound = isfound || CFile(name + ext).Exists(); - if (!isfound) { - mkPrj[prj_path].AddProperty( - CMakeProperty("set_source_files_properties") - .AddValue(CDirEntry::ConcatPath(location, relname + ".cpp") + - " PROPERTIES GENERATED 1")); - } - mkPrj[prj_path].AddSourceFile(location, relname); -#if 0 - } else if (CSymResolver::IsDefine(*s)) { -// mkPrj[prj_path].AddSourceFile( location_default, "${" + CSymResolver::StripDefine(FilterDefine(*s)) + "}"); -cerr << "Unhandled source: " << *s << " in " << prj.m_Name << endl; - } else if (SMakeProjectT::IsConfigurableDefine(*s)) { -// mkPrj[prj_path].AddSourceFile( location_default, "${" + SMakeProjectT::StripConfigurableDefine(*s) + "}"); -cerr << "Unhandled source: " << *s << " in " << prj.m_Name << endl; - } else { -cerr << "Unhandled source: " << *s << " in " << prj.m_Name << endl; -#endif - } - } -// datatool custom build - if (smth_by_datatool) { - ITERATE(list, d, prj.m_DatatoolSources) { - CMakeProperty cust_build("add_custom_command"); - string dataspec_module(CDirEntry(d->m_SourceFile).GetBase()); - string location = - CDirEntry::ConcatPath( CDirEntry::ConcatPath( - "${NCBI_PROJECT_SRC_DIR}", - CDirEntry::CreateRelativePath(prj.m_SourcesBaseDir, - d->m_SourceBaseDir)), - dataspec_module); - string output; - output = "OUTPUT"; - output += " " + location + ".files"; - output += " " + location + "__.cpp"; - output += " " + location + "___.cpp"; - cust_build.AddValue(output); - string command; - command = "COMMAND"; - command += " ${NCBI_DATATOOL}"; - command += " -oR ${NCBI_TREE_ROOT}"; - command += " -opm ${NCBI_TREE_ROOT}/src"; - command += " -m " + location + CDirEntry(d->m_SourceFile).GetExt(); - command += " -M \\\"" + NStr::Join(d->m_ImportModules, " ") + "\\\""; - command += " -oA "; - command += " -oc " + dataspec_module; - command += " -or " + relpath; - command += " -odi -od " + location + ".def"; - command += " -oex \\\"\\\" -ocvs -pch ncbi_pch.hpp"; - cust_build.AddValue(command); - string comment("COMMENT"); - comment += " \"Using datatool to generate C++ classes from " + d->m_SourceFile + "\""; - cust_build.AddValue(comment); - string depends("DEPENDS"); - depends += " " + location + CDirEntry(d->m_SourceFile).GetExt(); - if (CDirEntry(CDirEntry::ConcatPath(d->m_SourceBaseDir, dataspec_module + ".def")).Exists()) { - depends += " " + location + ".def"; - } - cust_build.AddValue(depends); - mkPrj[prj_path].AddProperty(cust_build); - } - } -// dependencies - vector to_process; - list tmp_list; - string value; - for (int deptype=0; deptype<2; ++deptype) { -// deptype = 0 -- libraries -// deptype = 1 -- other dependencies - list prj_libs; - to_process.clear(); - if (deptype == 0) { -#if 0 - if (p->first.Type() == CProjKey::eLib || - p->first.Type() == CProjKey::eDll) { -#if 0 -// this works - to_process.push_back("DLL_LIB"); - to_process.push_back("LIBS"); -#else -// this could be better.. or not.. - if (GetApp().GetBuildType().GetType() == CBuildType::eDll) { - to_process.push_back("USES_LIBRARIES"); - } -#endif -#else - if (p->first.Type() == CProjKey::eDll) { - to_process.push_back("DLL_LIB"); -#endif - } else if (p->first.Type() == CProjKey::eApp) { - to_process.clear(); - to_process.push_back("LIB"); - to_process.push_back("LIBS"); - } - } else if (deptype == 1) { - to_process.push_back("ASN_DEP"); -// to_process.push_back("USR_DEP"); - } - ITERATE(vector, top, to_process) { - if (prj.m_DataSource.GetValue(*top, tmp_list)) { - ITERATE( list, s, tmp_list) { - if (CSymResolver::HasDefine(*s)) { - string key = FilterDefine(*s); - if (CSymResolver::IsDefine(key)) { - key = CSymResolver::StripDefine(key); - if (prj.m_DataSource.GetValue(key, value)) { - if (CSymResolver::HasDefine(value)) { - NStr::ReplaceInPlace(value, "$(", "${"); - NStr::ReplaceInPlace(value, ")", "}"); - } - if (NStr::FindCase( value,"general") != NPOS) { - list vv_lst; - NStr::Split(value, LIST_SEPARATOR_LIBS, vv_lst, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); - NON_CONST_ITERATE( list, vv, vv_lst) { - if (*vv == "general") { - *vv = "general-lib"; - } - } - value = NStr::Join(vv_lst, " "); - } - mkPrj[prj_path].AddDefinition(key, value); - } - prj_libs.push_back( "${" + key + "}"); - } else { -// prj_libs.push_back( CSymResolver::TrimDefine(*s)); - value = *s; - NStr::ReplaceInPlace(value, "$(", "${"); - NStr::ReplaceInPlace(value, ")", "}"); - prj_libs.push_back(value); - } - } else if (SMakeProjectT::IsConfigurableDefine(*s)) { - value = SMakeProjectT::StripConfigurableDefine(*s); - prj_libs.push_back( "${" + value + "}"); - } else if (SMakeProjectT::HasConfigurableDefine(*s)) { -cerr << "Found ConfigurableDefine: " << *s << " in " << prj.m_Name << endl; - } else if (NStr::StartsWith(*s, "-l")) { - prj_libs.push_back( s->substr(2)); - } else { - prj_libs.push_back( *s); - } - } - } - if (deptype == 0 && *top == "LIBS") { - prj_libs.push_back("${ORIG_LIBS}"); - } - } - ITERATE( list, d, prj_libs) { - if (deptype == 0) { - mkPrj[prj_path].AddLibrary( *d); - } else if (deptype == 1) { - mkPrj[prj_path].AddDependency( *d); - } - } - } - -//include dirs - to_process.clear(); - to_process.push_back("CPPFLAGS"); - ITERATE(vector, top, to_process) { - prj.m_DataSource.GetValue(*top, tmp_list); - vector defines; - vector compflags; -#if 0 - if (tmp_list.empty()) { - compflags.push_back("${ORIG_CPPFLAGS}"); - } -#endif - ITERATE( list, s, tmp_list) { - if (CSymResolver::IsDefine(*s)) { - value = CSymResolver::StripDefine(FilterDefine(*s)); - if (NStr::EndsWith(value, "_INCLUDE")) { - mkPrj[prj_path].AddIncludeDirectory("${" + value + "}"); -// also look for additional definitions - const CMsvcSite& site = GetApp().GetSite(); - string resolved; - site.ResolveDefine(value, resolved); - list resolved_list; - NStr::Split(resolved, " ", resolved_list, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); - ITERATE( list, r, resolved_list) { - if (NStr::StartsWith(*r, "-D")) { - defines.push_back(*r); - } - } - - } - else { - compflags.push_back("${" + value + "}"); - } - } else if (CSymResolver::HasDefine(*s)) { -//cerr << "Found smth has define: " << *s << " in " << prj.m_Name << endl; - if (NStr::StartsWith(*s, "-I")) { - string val = SMakeProjectT::GetOneIncludeDir(*s, "-I"); - if (CSymResolver::HasDefine(val)) { - string key = FilterDefine(val); - if (CSymResolver::IsDefine(key)) { - key = CSymResolver::StripDefine(key); - if (prj.m_DataSource.GetValue(key, value)) { - mkPrj[prj_path].AddDefinition(key, value); - } - } - } -#if 0 - if (NStr::StartsWith(val,"$(srcdir)")) { - mkPrj[prj_path].AddIncludeDirectory(NStr::Replace(val, "$(srcdir)", "${NCBI_PROJECT_SRC_DIR}")); - } else if (NStr::StartsWith(val,"$(top_srcdir)")) { - mkPrj[prj_path].AddIncludeDirectory(NStr::Replace(val, "$(top_srcdir)", "${NCBI_TREE_ROOT}")); - } -#else - NStr::ReplaceInPlace(val,"$(", "${"); - NStr::ReplaceInPlace(val,")", "}"); - mkPrj[prj_path].AddIncludeDirectory(val); -#endif - } - } else if (NStr::StartsWith(*s, "-D")) { - defines.push_back(*s); - } - } - compflags.push_back("${ORIG_CPPFLAGS}"); - if (!defines.empty()) { -#if 0 - CMakeProperty def( "add_definitions"); - ITERATE( vector, d, defines) { - def.AddValue( *d); - } - mkPrj[prj_path].AddProperty( def); -#else - ITERATE( vector, d, defines) { - mkPrj[prj_path].AddCompilationDefine( NStr::Replace(*d, "-D", "")); - } -#endif - } - if (!compflags.empty()) { - ITERATE( vector, d, compflags) { - mkPrj[prj_path].AddCompilationFlag( *d); - } - } - } - -// tests - string prj_id0(p->first.Id()); - string prj_id(p->first.Id()); -#if 0 - if (p->first.Type() == CProjKey::eApp) { - prj_id += ".exe"; - } -#endif - if (prj.m_DataSource.GetValue("CHECK_COPY", tmp_list)) { - list ttmp; - ITERATE( list, s, tmp_list) { - if (CDirEntry(CDirEntry::ConcatPath(prj.m_SourcesBaseDir, *s)).Exists()) { - ttmp.push_back(*s); - } - } - tmp_list = ttmp; - if (!tmp_list.empty()) { - CMakeProperty cust_build("add_custom_command"); - cust_build.AddValue("TARGET " + prj_id + " POST_BUILD"); - ITERATE( list, s, tmp_list) { - cust_build.AddValue( "COMMAND test -e ${NCBI_PROJECT_SRC_DIR}/"+ *s + " && cp -rf ${NCBI_PROJECT_SRC_DIR}/" + *s + " ${NCBI_PROJECT_BUILD_DIR}/"); - } - mkPrj[prj_path].AddProperty(cust_build); - } - } - if (prj.m_DataSource.GetValue("CHECK_CMD", tmp_list)) { - { - CMakeProperty cust_build("add_custom_command"); - cust_build.AddValue("TARGET " + prj_id + " POST_BUILD"); - cust_build.AddValue( "COMMAND cp -rf ${NCBI_BUILD_BIN}/" + prj_id + " ${NCBI_PROJECT_BUILD_DIR}/" + prj_id0); - mkPrj[prj_path].AddProperty(cust_build); - } - set checks; - if (tmp_list.empty()) { - tmp_list.push_back(prj_id); - } - ITERATE( list, s, tmp_list) { - value = *s; - string check_name("/CHECK_NAME="); - string::size_type chkn = s->find(check_name); - if (chkn != string::npos) { - value = s->substr(0, chkn); - check_name = s->substr( chkn + check_name.length()); - NStr::ReplaceInPlace(check_name, " ", "_"); - } else { - if (value.empty()) { - value = prj_id0; - } - check_name = prj_id; - } - while (checks.find(check_name) != checks.end()) { - check_name += NStr::NumericToString( checks.size()); - } - checks.insert(check_name); - mkPrj[prj_path].AddProperty( - CMakeProperty("add_test") - .AddValue("NAME " + check_name) - .AddValue("WORKING_DIRECTORY ${NCBI_PROJECT_BUILD_DIR}") - .AddValue("COMMAND " + value)); - } - } - } - -// done - for (map::const_iterator n = mkIn.begin(); n != mkIn.end(); ++n) { - n->second.Write( CDirEntry::ConcatPath(sln_dir, n->first)); - } - - for (map::const_iterator n = mkPrj.begin(); n != mkPrj.end(); ++n) { - n->second.Write( CDirEntry(CDirEntry::ConcatPath(sln_dir, n->first)).GetDir()); - } -} - ///////////////////////////////////////////////////////////////////////////// void CMakefilePatch::PatchTreeMakefiles(const CProjectItemsTree& projects_tree) { diff --git a/c++/src/build-system/project_tree_builder/proj_tree.hpp b/c++/src/build-system/project_tree_builder/proj_tree.hpp index 7e6831bb..10b8c067 100644 --- a/c++/src/build-system/project_tree_builder/proj_tree.hpp +++ b/c++/src/build-system/project_tree_builder/proj_tree.hpp @@ -1,7 +1,7 @@ #ifndef PROJECT_TREE_BUILDER__PROJ_TREE__HPP #define PROJECT_TREE_BUILDER__PROJ_TREE__HPP -/* $Id: proj_tree.hpp 429667 2014-03-18 13:25:30Z gouriano $ +/* $Id: proj_tree.hpp 524100 2017-01-09 19:49:55Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -294,13 +294,6 @@ private: vector m_Properties; }; -///////////////////////////////////////////////////////////////////////////// -class CMakeGenerator -{ -public: - static void GenerateCMakeTree(CProjectItemsTree& projects_tree); -}; - ///////////////////////////////////////////////////////////////////////////// class CMakefilePatch { diff --git a/c++/src/build-system/project_tree_builder/proj_tree_builder.cpp b/c++/src/build-system/project_tree_builder/proj_tree_builder.cpp index 8088418f..44be2320 100644 --- a/c++/src/build-system/project_tree_builder/proj_tree_builder.cpp +++ b/c++/src/build-system/project_tree_builder/proj_tree_builder.cpp @@ -1,4 +1,4 @@ -/* $Id: proj_tree_builder.cpp 500658 2016-05-06 12:34:22Z gouriano $ +/* $Id: proj_tree_builder.cpp 524100 2017-01-09 19:49:55Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -3138,12 +3138,10 @@ void CProjectTreeBuilder::ProcessDir(const string& dir_name, subprojects_dirs[dir_entry->GetPath()] = is_root ? eMakeType_Undefined : eMakeType_Excluded; } - if (GetApp().IsScanningWholeTree() || is_root || !GetApp().IsCMakeMode()) { if (find(ordered_subprojects_dirs.begin(), ordered_subprojects_dirs.end(), name) == ordered_subprojects_dirs.end()) { ordered_subprojects_dirs.push_back(name); } - } } { map::const_iterator s; diff --git a/c++/src/build-system/ptb_version.txt b/c++/src/build-system/ptb_version.txt index b1cbc1fc..fae6e3d0 100644 --- a/c++/src/build-system/ptb_version.txt +++ b/c++/src/build-system/ptb_version.txt @@ -1 +1 @@ -4.1.5 +4.2.1 diff --git a/c++/src/build-system/relocate.sh.in b/c++/src/build-system/relocate.sh.in index 18fe9366..9e49a0f5 100644 --- a/c++/src/build-system/relocate.sh.in +++ b/c++/src/build-system/relocate.sh.in @@ -1,6 +1,6 @@ @script_shell@ -# $Id: relocate.sh.in 521320 2016-12-07 19:38:29Z blastadm $ +# $Id: relocate.sh.in 548945 2017-10-18 23:46:00Z blastadm $ # Author: Denis Vakatov, NCBI # # Adjust paths to this build tree and the relevant source tree @@ -48,6 +48,7 @@ fi files="\ Makefile.mk Makefile.meta Makefile.lib.tmpl Makefile.app.tmpl install.sh new_module.sh" +rwcdr=run_with_cd_reporter.py for f in $files ; do fff="$script_dir/$f" @@ -74,9 +75,19 @@ for f in $files ; do fi done -chmod +x "$script_dir"/*.sh.tmp +sed ' + s%^\(scriptdir *= *\).*%\1"'$src_tree/scripts'"%; + s%^\([# ]*outdir *= *\).*%\1"'$bld_tree/cd-reports'"%; + s%^\(status_dir *= *\).*%\1"'$status_dir'"%; +' $script_dir/$rwcdr > $script_dir/$rwcdr.tmp +if test $? -ne 0 ; then + echo "[$script_name] Error in processing file \"$rwcdr\"!" + exit 2 +fi -for f in $files ; do +chmod +x "$script_dir"/*.sh.tmp "$script_dir"/*.py.tmp + +for f in $files run_with_cd_reporter.py ; do fff="$script_dir/$f" echo " $f" test "$copy_times" = true && touch -r "$fff.tmp" "$fff" diff --git a/c++/src/build-system/run_with_cd_reporter.py.in b/c++/src/build-system/run_with_cd_reporter.py.in new file mode 100644 index 00000000..7d7c995e --- /dev/null +++ b/c++/src/build-system/run_with_cd_reporter.py.in @@ -0,0 +1,43 @@ +#!@PYTHON3@ +# $Id: run_with_cd_reporter.py.in 542182 2017-07-27 16:40:28Z ivanov $ +import os +import sys + +cd_reporter = '@CD_REPORTER@' +if not os.path.exists(cd_reporter): + os.execv(sys.argv[1], sys.argv[1:]) + +scriptdir = os.path.join('@abs_top_srcdir@', 'scripts') +# outdir = os.path.join('@build_root@', 'cd-reports') +status_dir = '@status_dir@' +wanted = frozenset(('name', 'type', 'contact', 'start_time', 'end_time', + 'succeeded', 'build_type', 'source_directory', + 'vcs_type', 'vcs_path', 'vcs_branch', + 'artifact_name', 'artifact_version', 'command_line')) + +## XXX - favor the real PyYAML installation accompanying cd_reporter? +sys.path.append(scriptdir + '/common/impl') +from ncbicxx_build_info import Collector +# from yaml import dump +# try: +# from yaml import CDumper as Dumper +# except ImportError: +# from yaml import Dumper + +pid = os.getpid() +collector = Collector() +collector.collect(sys.argv[1:], status_dir, wanted, @NCBI_SC_VERSION@) +args = [cd_reporter] # , '--dry-run', '-vvv' +for x in wanted: + try: + args.append('--%s=%s' % (x.replace('_', '-'), + collector.get_as_string(x))) + except KeyError: + pass +os.execv(cd_reporter, args) # prints status code -- arrange to discard it? + +# print('run_with_cd_reporter.py [%d]: Reporting on command %s' +# % (pid, ' '.join(sys.argv)), +# file = sys.stderr) +# out = open(('%s/%d.yaml') % (outdir, pid), 'w') +# dump(collector.info, out) diff --git a/c++/src/cgi/CMakeLists.cgi.lib.txt b/c++/src/cgi/CMakeLists.cgi.lib.txt new file mode 100644 index 00000000..d1a451a2 --- /dev/null +++ b/c++/src/cgi/CMakeLists.cgi.lib.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/cgi/Makefile.cgi.lib +# +add_library(xcgi + ncbicgi cgiapp cgictx ncbicgir ncbires ref_args cgi_run cgi_util + cgi_serial cgi_session cgi_exception cgiapp_cached cgi_entry_reader + user_agent +) +include_directories(SYSTEM ${FASTCGI_INCLUDE}) + +target_link_libraries(xcgi + xutil +) diff --git a/c++/src/cgi/CMakeLists.fcgi.lib.txt b/c++/src/cgi/CMakeLists.fcgi.lib.txt new file mode 100644 index 00000000..60efa894 --- /dev/null +++ b/c++/src/cgi/CMakeLists.fcgi.lib.txt @@ -0,0 +1,14 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/cgi/Makefile.fcgi.lib +# +add_library(xfcgi + ncbicgi cgiapp cgictx ncbicgir ncbires ref_args cgi_util cgi_serial + ${FASTCGI_OBJS} fcgi_run cgi_session cgi_exception cgiapp_cached + cgi_entry_reader user_agent +) +include_directories(SYSTEM ${FASTCGI_INCLUDE}) + +target_link_libraries(xfcgi + xutil ${FASTCGI_LIBS} +) + diff --git a/c++/src/cgi/CMakeLists.txt b/c++/src/cgi/CMakeLists.txt new file mode 100644 index 00000000..59d8128d --- /dev/null +++ b/c++/src/cgi/CMakeLists.txt @@ -0,0 +1,12 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.cgi.lib.txt) +if (FastCGI_FOUND) + include(CMakeLists.fcgi.lib.txt) +endif() + +# Recurse subdirectories +add_subdirectory(test ) diff --git a/c++/src/cgi/cgi_exception.cpp b/c++/src/cgi/cgi_exception.cpp index 6169fbf4..6d98ffb5 100644 --- a/c++/src/cgi/cgi_exception.cpp +++ b/c++/src/cgi/cgi_exception.cpp @@ -1,4 +1,4 @@ -/* $Id: cgi_exception.cpp 441525 2014-07-24 16:55:45Z grichenk $ +/* $Id: cgi_exception.cpp 522984 2016-12-27 17:38:25Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -56,50 +56,8 @@ void CCgiException::x_Assign(const CException& src) string CCgiException::GetStdStatusMessage(EStatusCode code) { - switch ( code ) { - case eStatusNotSet: return "Status not set"; - case e100_Continue: return "Continue"; - case e101_SwitchingProtocols: return "Switching Protocols"; - case e200_Ok: return "OK"; - case e201_Created: return "Created"; - case e202_Accepted: return "Accepted"; - case e203_NonAuthInformation: return "Non-Authoritative Information"; - case e204_NoContent: return "No Content"; - case e205_ResetContent: return "Reset Content"; - case e206_PartialContent: return "Partial Content"; - case e300_MultipleChoices: return "Multiple Choices"; - case e301_MovedPermanently: return "Moved Permanently"; - case e302_Found: return "Found"; - case e303_SeeOther: return "See Other"; - case e304_NotModified: return "Not Modified"; - case e305_UseProxy: return "Use Proxy"; - case e307_TemporaryRedirect: return "Temporary Redirect"; - case e400_BadRequest: return "Bad Request"; - case e401_Unauthorized: return "Unauthorized"; - case e402_PaymentRequired: return "Payment Required"; - case e403_Forbidden: return "Forbidden"; - case e404_NotFound: return "Not Found"; - case e405_MethodNotAllowed: return "Method Not Allowed"; - case e406_NotAcceptable: return "Not Acceptable"; - case e407_ProxyAuthRequired: return "Proxy Authentication Required"; - case e408_RequestTimeout: return "Request Timeout"; - case e409_Conflict: return "Conflict"; - case e410_Gone: return "Gone"; - case e411_LengthRequired: return "Length Required"; - case e412_PreconditionFailed: return "Precondition Failed"; - case e413_RequestEntityTooLarge: return "Request Entity Too Large"; - case e414_RequestURITooLong: return "Request-URI Too Long"; - case e415_UnsupportedMediaType: return "Unsupported Media Type"; - case e416_RangeNotSatisfiable: return "Requested Range Not Satisfiable"; - case e417_ExpectationFailed: return "Expectation Failed"; - case e500_InternalServerError: return "Internal Server Error"; - case e501_NotImplemented: return "Not Implemented"; - case e502_BadGateway: return "Bad Gateway"; - case e503_ServiceUnavailable: return "Service Unavailable"; - case e504_GatewayTimeout: return "Gateway Timeout"; - case e505_HTTPVerNotSupported: return "HTTP Version Not Supported"; - } - return "Unknown HTTP status code"; + return code == eStatusNotSet ? "Status not set" : + CRequestStatus::GetStdStatusMessage(CRequestStatus::ECode(code)); } diff --git a/c++/src/cgi/cgiapp.cpp b/c++/src/cgi/cgiapp.cpp index 2f5e1aee..e2cd47c5 100644 --- a/c++/src/cgi/cgiapp.cpp +++ b/c++/src/cgi/cgiapp.cpp @@ -1,4 +1,4 @@ -/* $Id: cgiapp.cpp 510827 2016-08-16 15:21:28Z ivanov $ +/* $Id: cgiapp.cpp 534862 2017-05-03 12:54:15Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -497,12 +497,12 @@ int CCgiApplication::Run(void) bool is_stat_log = GetConfig().GetBool("CGI", "StatLog", false, 0, CNcbiRegistry::eReturn); bool skip_stat_log = false; - auto_ptr stat(is_stat_log ? CreateStat() : 0); + unique_ptr stat(is_stat_log ? CreateStat() : 0); CNcbiOstream* orig_stream = NULL; //int orig_fd = -1; CNcbiStrstream result_copy; - auto_ptr new_stream; + unique_ptr new_stream; try { _TRACE("(CGI) CCgiApplication::Run: calling ProcessRequest"); @@ -552,9 +552,14 @@ int CCgiApplication::Run(void) } } GetDiagContext().SetAppState(eDiagAppState_Request); - result = CCgiContext::ProcessCORSRequest( - m_Context->GetRequest(), m_Context->GetResponse()) ? - 0 : ProcessRequest(*m_Context); + if (x_ProcessHelpRequest() || + x_ProcessVersionRequest() || + CCgiContext::ProcessCORSRequest(m_Context->GetRequest(), m_Context->GetResponse())) { + result = 0; + } + else { + result = ProcessRequest(*m_Context); + } GetDiagContext().SetAppState(eDiagAppState_RequestEnd); m_Context->GetResponse().Finalize(); if (result != 0) { @@ -569,7 +574,7 @@ int CCgiApplication::Run(void) if(caching_needed) SaveResultToCache(m_Context->GetRequest(), result_copy); else { - auto_ptr request(GetSavedRequest(m_RID)); + unique_ptr request(GetSavedRequest(m_RID)); if (request.get()) SaveResultToCache(*request, result_copy); } @@ -689,7 +694,7 @@ void CCgiApplication::ProcessHttpReferer(void) if ( !args.empty() ) { ref += "?" + args; } - GetConfig().Set("CONN", "HTTP_REFERER", ref); + GetRWConfig().Set("CONN", "HTTP_REFERER", ref); } } @@ -1424,7 +1429,7 @@ bool CCgiApplication::GetResultFromCache(const CCgiRequest& request, CNcbiOstrea try { CCacheHashedContent helper(*m_Cache); - auto_ptr reader( helper.GetHashedContent(checksum, content)); + unique_ptr reader( helper.GetHashedContent(checksum, content)); if (reader.get()) { //cout << "(Read) " << checksum << " --- " << content << endl; CRStream cache_reader(reader.get()); @@ -1444,7 +1449,7 @@ void CCgiApplication::SaveResultToCache(const CCgiRequest& request, CNcbiIstream return; try { CCacheHashedContent helper(*m_Cache); - auto_ptr writer( helper.StoreHashedContent(checksum, content) ); + unique_ptr writer( helper.StoreHashedContent(checksum, content) ); if (writer.get()) { // cout << "(Write) : " << checksum << " --- " << content << endl; CWStream cache_writer(writer.get()); @@ -1461,7 +1466,7 @@ void CCgiApplication::SaveRequest(const string& rid, const CCgiRequest& request) if (rid.empty()) return; try { - auto_ptr writer( m_Cache->GetWriteStream(rid, 0, "NS_JID") ); + unique_ptr writer( m_Cache->GetWriteStream(rid, 0, "NS_JID") ); if (writer.get()) { CWStream cache_stream(writer.get()); request.Serialize(cache_stream); @@ -1477,10 +1482,10 @@ CCgiRequest* CCgiApplication::GetSavedRequest(const string& rid) if (rid.empty()) return NULL; try { - auto_ptr reader(m_Cache->GetReadStream(rid, 0, "NS_JID")); + unique_ptr reader(m_Cache->GetReadStream(rid, 0, "NS_JID")); if (reader.get()) { CRStream cache_stream(reader.get()); - auto_ptr request(new CCgiRequest); + unique_ptr request(new CCgiRequest); request->Deserialize(cache_stream, 0); return request.release(); } @@ -1652,6 +1657,323 @@ bool CCgiApplication::x_DoneHeadRequest(void) const } +inline +bool CCgiApplication::SAcceptEntry::operator<(const SAcceptEntry& entry) const +{ + // Prefer specific type over wildcard. + bool this_wc = m_Type == "*"; + bool other_wc = entry.m_Type == "*"; + if (this_wc != other_wc) return !this_wc; + // Prefer specific subtype over wildcard. + this_wc = m_Subtype == "*"; + other_wc = entry.m_Subtype == "*"; + if (this_wc != other_wc) return !this_wc; + // Prefer more specific media range params. + if (m_MediaRangeParams.empty() != entry.m_MediaRangeParams.empty()) { + return !m_MediaRangeParams.empty(); + } + // Prefer higher quality factor. + if (m_Quality != entry.m_Quality) return m_Quality > entry.m_Quality; + // Otherwise sort by type/subtype values. + if (m_Type != entry.m_Type) return m_Type < entry.m_Type; + if (m_Subtype != entry.m_Subtype) return m_Subtype < entry.m_Subtype; + // Otherwise (same type/subtype, quality factor and number of params) + // consider entries equal. + return false; +} + + +void CCgiApplication::ParseAcceptHeader(TAcceptEntries& entries) const { + string accept = m_Context->GetRequest().GetProperty(eCgi_HttpAccept); + if (accept.empty()) return; + list types; + NStr::Split(accept, ",", types, NStr::fSplit_MergeDelimiters); + ITERATE(list, type_it, types) { + list parts; + NStr::Split(NStr::TruncateSpaces(*type_it), ";", parts, NStr::fSplit_MergeDelimiters); + if ( parts.empty() ) continue; + entries.push_back(SAcceptEntry()); + SAcceptEntry& entry = entries.back(); + NStr::SplitInTwo(NStr::TruncateSpaces(parts.front()), "/", entry.m_Type, entry.m_Subtype); + NStr::TruncateSpacesInPlace(entry.m_Type); + NStr::TruncateSpacesInPlace(entry.m_Subtype); + list::const_iterator ext_it = parts.begin(); + ++ext_it; // skip type/subtype + bool aparams = false; + while (ext_it != parts.end()) { + string name, value; + NStr::SplitInTwo(NStr::TruncateSpaces(*ext_it), "=", name, value); + NStr::TruncateSpacesInPlace(name); + NStr::TruncateSpacesInPlace(value); + if (name == "q") { + entry.m_Quality = NStr::StringToNumeric(value, NStr::fConvErr_NoThrow); + if (entry.m_Quality == 0 && errno != 0) { + entry.m_Quality = 1; + } + aparams = true; + ++ext_it; + continue; + } + if (aparams) { + entry.m_AcceptParams[name] = value; + } + else { + entry.m_MediaRangeParams += ";" + name + "=" + value; + } + ++ext_it; + } + } + entries.sort(); +} + + +NCBI_PARAM_DECL(bool, CGI, EnableHelpRequest); +NCBI_PARAM_DEF_EX(bool, CGI, EnableHelpRequest, true, + eParam_NoThread, CGI_ENABLE_HELP_REQUEST); +typedef NCBI_PARAM_TYPE(CGI, EnableHelpRequest) TEnableHelpRequest; + + +bool CCgiApplication::x_ProcessHelpRequest() +{ + if (!TEnableHelpRequest::GetDefault()) return false; + CCgiRequest& request = m_Context->GetRequest(); + if (request.GetRequestMethod() != CCgiRequest::eMethod_GET) return false; + bool found = false; + string format = request.GetEntry("ncbi_help", &found); + if ( !found ) return false; + ProcessHelpRequest(format); + return true; +} + + +static const char* kStdFormats[] = { "html", "xml", "json" }; +static const char* kStdContentTypes[] = { "text/html", "text/xml", "application/json" }; + +inline string FindContentType(CTempString format) { + for (size_t i = 0; i < sizeof(kStdFormats) / sizeof(kStdFormats[0]); ++i) { + if (format == kStdFormats[i]) return kStdContentTypes[i]; + } + return kEmptyStr; +} + + +void CCgiApplication::ProcessHelpRequest(const string& format) +{ + string base_name = GetProgramExecutablePath(); + string fname; + string content_type; + // If 'format' is set, try to find .help. or help. file. + if ( !format.empty() ) { + string fname_fmt = base_name + ".help." + format; + if ( CFile(fname_fmt).Exists() ) { + fname = fname_fmt; + content_type = FindContentType(format); + } + else { + fname_fmt = "help." + format; + if ( CFile(fname_fmt).Exists() ) { + fname = fname_fmt; + content_type = FindContentType(format); + } + } + } + + // If 'format' is not set or there's no file of the specified format, check + // 'Accept:' header. + if ( fname.empty() ) { + TAcceptEntries entries; + ParseAcceptHeader(entries); + ITERATE(TAcceptEntries, it, entries) { + string fname_accept = base_name + ".help." + it->m_Subtype + it->m_MediaRangeParams; + if ( CFile(fname_accept).Exists() ) { + fname = fname_accept; + content_type = it->m_Type + "/" + it->m_Subtype; + break; + } + } + if ( fname.empty() ) { + ITERATE(TAcceptEntries, it, entries) { + string fname_accept = "help." + it->m_Subtype + it->m_MediaRangeParams; + if ( CFile(fname_accept).Exists() ) { + fname = fname_accept; + content_type = it->m_Type + "/" + it->m_Subtype; + break; + } + } + } + } + + // Finally, check standard formats: html/xml/json + if ( fname.empty() ) { + for (size_t i = 0; i < sizeof(kStdFormats) / sizeof(kStdFormats[0]); ++i) { + string fname_std = base_name + ".help." + kStdFormats[i]; + if ( CFile(fname_std).Exists() ) { + fname = fname_std; + content_type = kStdContentTypes[i]; + break; + } + } + } + if ( fname.empty() ) { + for (size_t i = 0; i < sizeof(kStdFormats) / sizeof(kStdFormats[0]); ++i) { + string fname_std = string("help.") + kStdFormats[i]; + if ( CFile(fname_std).Exists() ) { + fname = fname_std; + content_type = kStdContentTypes[i]; + break; + } + } + } + + CCgiResponse& response = m_Context->GetResponse(); + if ( !fname.empty() ) { + CNcbiIfstream in(fname.c_str()); + + // Check if the file starts with "Content-type:" header followed by double-eol. + bool ct_found = false; + string ct; + getline(in, ct); + if ( NStr::StartsWith(ct, "content-type:", NStr::eNocase) ) { + string eol; + getline(in, eol); + if ( eol.empty() ) { + ct_found = true; + content_type = NStr::TruncateSpaces(ct.substr(13)); + } + } + if ( !ct_found ) { + in.seekg(0); + } + + if ( !content_type.empty()) { + response.SetContentType(content_type); + } + response.WriteHeader(); + NcbiStreamCopy(*response.GetOutput(), in); + } + else { + // Could not find help file, use arg descriptions instead. + const CArgDescriptions* args = GetArgDescriptions(); + if ( args ) { + response.SetContentType("text/xml"); + response.WriteHeader(); + args->PrintUsageXml(*response.GetOutput()); + } + else { + NCBI_THROW(CCgiRequestException, eData, + "Can not find help for CGI application"); + } + } +} + + +NCBI_PARAM_DECL(string, CGI, EnableVersionRequest); +NCBI_PARAM_DEF_EX(string, CGI, EnableVersionRequest, "t", + eParam_NoThread, CGI_ENABLE_VERSION_REQUEST); +typedef NCBI_PARAM_TYPE(CGI, EnableVersionRequest) TEnableVersionRequest; + + +bool CCgiApplication::x_ProcessVersionRequest() +{ + CCgiRequest& request = m_Context->GetRequest(); + if (request.GetRequestMethod() != CCgiRequest::eMethod_GET) return false; + + // If param value is a bool, enable the default ncbi_version CGI arg. + // Otherwise try to use the value as the arg's name, then fallback to + // ncbi_version. + bool use_alt_name = false; + string vparam = TEnableVersionRequest::GetDefault(); + if ( vparam.empty() ) return false; + try { + bool is_enabled = NStr::StringToBool(vparam); + if (!is_enabled) return false; + } + catch (CStringException) { + use_alt_name = true; + } + + string ver_type; + bool found = false; + if ( use_alt_name ) { + ver_type = request.GetEntry(vparam, &found); + } + if ( !found ) { + ver_type = request.GetEntry("ncbi_version", &found); + } + if ( !found ) return false; + + EVersionType vt; + if (ver_type.empty() || ver_type == "short") { + vt = eVersion_Short; + } + else if (ver_type == "full") { + vt = eVersion_Full; + } + else { + NCBI_THROW(CCgiRequestException, eEntry, + "Unsupported ncbi_version argument value"); + } + ProcessVersionRequest(vt); + return true; +} + + +void CCgiApplication::ProcessVersionRequest(EVersionType ver_type) +{ + string format = "plain"; + string content_type = "text/plain"; + TAcceptEntries entries; + ParseAcceptHeader(entries); + ITERATE(TAcceptEntries, it, entries) { + if (it->m_Subtype == "xml" || it->m_Subtype == "json" || + (it->m_Type == "text" && it->m_Subtype == "plain")) { + format = it->m_Subtype; + content_type = it->m_Type + "/" + it->m_Subtype; + break; + } + } + + CCgiResponse& response = m_Context->GetResponse(); + response.SetContentType(content_type); + response.WriteHeader(); + CNcbiOstream& out = *response.GetOutput(); + if (format == "plain") { + switch (ver_type) { + case eVersion_Short: + out << GetVersion().Print(); + break; + case eVersion_Full: + out << GetFullVersion().Print(GetAppName()); + break; + } + } + else if (format == "xml") { + switch (ver_type) { + case eVersion_Short: + out << GetFullVersion().PrintXml(kEmptyStr, CVersion::fVersionInfo); + break; + case eVersion_Full: + out << GetFullVersion().PrintXml(GetAppName()); + break; + } + } + else if (format == "json") { + switch (ver_type) { + case eVersion_Short: + out << GetFullVersion().PrintJson(kEmptyStr, CVersion::fVersionInfo); + break; + case eVersion_Full: + out << GetFullVersion().PrintJson(GetAppName()); + break; + } + } + else { + NCBI_THROW(CCgiRequestException, eData, + "Unsupported version format"); + } +} + + /////////////////////////////////////////////////////// // CCgiStatistics // diff --git a/c++/src/cgi/cgictx.cpp b/c++/src/cgi/cgictx.cpp index 577ec2f3..4bc3be95 100644 --- a/c++/src/cgi/cgictx.cpp +++ b/c++/src/cgi/cgictx.cpp @@ -1,4 +1,4 @@ -/* $Id: cgictx.cpp 509509 2016-08-05 19:12:20Z fukanchi $ +/* $Id: cgictx.cpp 544444 2017-08-23 13:08:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -113,7 +113,7 @@ CCgiContext::CCgiContext(CCgiApplication& app, int ofd, size_t errbuf_size, CCgiRequest::TFlags flags) - : m_App(app), + : m_App(&app), m_Request(new CCgiRequest(args ? args : &app.GetArguments(), env ? env : &app.GetEnvironment(), inp, flags, ifd, errbuf_size)), @@ -136,7 +136,7 @@ CCgiContext::CCgiContext(CCgiApplication& app, CNcbiIstream* is, CNcbiOstream* os, CCgiRequest::TFlags flags) - : m_App(app), + : m_App(&app), m_Request(new CCgiRequest()), m_Response(os, -1), m_SecureMode(eSecure_NotSet), @@ -148,10 +148,49 @@ CCgiContext::CCgiContext(CCgiApplication& app, } -void CCgiContext::x_InitSession(CCgiRequest::TFlags flags) +CCgiContext::CCgiContext(ICgiSessionStorage* session_storage, + const CNcbiArguments* args, + const CNcbiEnvironment* env, + CNcbiIstream* inp, + CNcbiOstream* out, + int ifd, + int ofd, + size_t errbuf_size, + CCgiRequest::TFlags flags) + : m_App(nullptr), + m_Request(new CCgiRequest(args, env, inp, flags, ifd, errbuf_size)), + m_Response(out, ofd), + m_SecureMode(eSecure_NotSet), + m_StatusCode(CCgiException::eStatusNotSet) +{ + m_Response.SetRequestMethod(m_Request->GetRequestMethod()); + m_Response.SetCgiRequest(*m_Request); + + if (flags & CCgiRequest::fDisableTrackingCookie) { + m_Response.DisableTrackingCookie(); + } + x_InitSession(flags, session_storage); + return; +} + + +CCgiApplication& CCgiContext::x_GetApp(void) const +{ + if ( !m_App ) { + NCBI_THROW(CCgiAppException, eApp, "NULL CCgiApplication in CCgiContext"); + } + return *m_App; +} + + +void CCgiContext::x_InitSession(CCgiRequest::TFlags flags, + ICgiSessionStorage* session_storage) { CCgiSessionParameters params; - ICgiSessionStorage* impl = m_App.GetSessionStorage(params); + ICgiSessionStorage* impl = session_storage; + if (!session_storage && m_App) { + impl = m_App->GetSessionStorage(params); + } m_Session.reset(new CCgiSession(*m_Request, impl, params.m_ImplOwner, @@ -202,25 +241,25 @@ CCgiContext::~CCgiContext(void) const CNcbiRegistry& CCgiContext::GetConfig(void) const { - return m_App.GetConfig(); + return x_GetApp().GetConfig(); } CNcbiRegistry& CCgiContext::GetConfig(void) { - return m_App.GetConfig(); + return x_GetApp().GetConfig(); } const CNcbiResource& CCgiContext::GetResource(void) const { - return m_App.GetResource(); + return x_GetApp().GetResource(); } CNcbiResource& CCgiContext::GetResource(void) { - return m_App.GetResource(); + return x_GetApp().GetResource(); } @@ -228,7 +267,7 @@ CCgiServerContext& CCgiContext::x_GetServerContext(void) const { CCgiServerContext* context = m_ServerContext.get(); if ( !context ) { - context = m_App.LoadServerContext(const_cast(*this)); + context = x_GetApp().LoadServerContext(const_cast(*this)); if ( !context ) { ERR_POST_X(12, "CCgiContext::GetServerContext: no server context set"); throw runtime_error("no server context set"); @@ -316,21 +355,19 @@ const string& CCgiContext::GetSelfURL(void) const (GetRequest().GetRandomProperty("X_FORWARDED_PROTO"), "https", PNocase()); m_SecureMode = secure ? eSecure_On : eSecure_Off; - m_SelfURL = secure ? "https://" : "http://"; + m_SelfURL = secure ? "https://" : "http://"; m_SelfURL += server; string port = GetRequest().GetProperty(eCgi_ServerPort); // Skip port if it's default for the selected scheme if ((secure && port == "443") || (!secure && port == "80") - || (server.size() >= port.size() + 2 && NStr::EndsWith(server, port) - && server[server.size() - port.size() - 1] == ':')) { - port = kEmptyStr; + || (server.size() >= port.size() + 2 && NStr::EndsWith(server, port) + && server[server.size() - port.size() - 1] == ':')) { + port.erase(); } if ( !port.empty() ) { m_SelfURL += ':'; m_SelfURL += port; } - // (replace adjacent '//' to work around a bug in the "www.ncbi" proxy; - // it should not hurt, and may help with similar proxies outside NCBI) string script_uri; script_uri = GetRequest().GetRandomProperty("SCRIPT_URL", false); if ( script_uri.empty() ) { @@ -339,9 +376,11 @@ const string& CCgiContext::GetSelfURL(void) const // Remove args if any size_t arg_pos = script_uri.find('?'); if (arg_pos != NPOS) { - script_uri = script_uri.substr(0, arg_pos); + script_uri.resize(arg_pos); } - m_SelfURL += NStr::Replace(script_uri, "//", "/"); + // (replace adjacent '//' to work around a bug in the "www.ncbi" proxy; + // it should not hurt, and may help with similar proxies outside NCBI) + m_SelfURL += NStr::ReplaceInPlace(script_uri, "//", "/"); return m_SelfURL; } @@ -602,7 +641,7 @@ static const char* kAC_MaxAge = "Access-Control-Max-Age"; static const char* kSimpleHeaders = " Accept Accept-Language Content-Language Content-Type"; static const char* kDefaultHeaders = - " Cache-Control Expires Last-Modified Pragma X-Accept-Charset X-Accept" + " Origin Cache-Control Expires Last-Modified Pragma X-Accept-Charset X-Accept" " X-Requested-With NCBI-SID NCBI-PHID"; @@ -786,6 +825,11 @@ bool CCgiContext::ProcessCORSRequest(const CCgiRequest& request, string allow_headers = TCORS_AllowHeaders::GetDefault(); allow_headers += kDefaultHeaders; if ( !allow_headers.empty() ) { + // Make comma-separated list. + TStringList allowed_list; + NStr::Split(allow_headers, ", ", allowed_list, + NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); + allow_headers = NStr::Join(allowed_list, ", "); response.SetHeaderValue(kAC_AllowHeaders, allow_headers); } const string& max_age = TCORS_MaxAge::GetDefault(); diff --git a/c++/src/cgi/fcgi_run.cpp b/c++/src/cgi/fcgi_run.cpp index 9597d7f8..63f4dad7 100644 --- a/c++/src/cgi/fcgi_run.cpp +++ b/c++/src/cgi/fcgi_run.cpp @@ -1,4 +1,4 @@ -/* $Id: fcgi_run.cpp 500790 2016-05-09 11:30:33Z ivanov $ +/* $Id: fcgi_run.cpp 523180 2016-12-29 14:05:52Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -640,9 +640,14 @@ bool CCgiApplication::x_RunFastCGI(int* result, unsigned int def_iter) } } GetDiagContext().SetAppState(eDiagAppState_Request); - x_result = CCgiContext::ProcessCORSRequest( - m_Context->GetRequest(), m_Context->GetResponse()) ? - 0 : ProcessRequest(*m_Context); + if (x_ProcessHelpRequest() || + x_ProcessVersionRequest() || + CCgiContext::ProcessCORSRequest(m_Context->GetRequest(), m_Context->GetResponse())) { + x_result = 0; + } + else { + x_result = ProcessRequest(*m_Context); + } GetDiagContext().SetAppState(eDiagAppState_RequestEnd); m_Context->GetResponse().Finalize(); if (x_result == 0) { diff --git a/c++/src/cgi/ncbicgi.cpp b/c++/src/cgi/ncbicgi.cpp index 8682c3a8..a053a095 100644 --- a/c++/src/cgi/ncbicgi.cpp +++ b/c++/src/cgi/ncbicgi.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbicgi.cpp 497034 2016-04-04 12:46:26Z dicuccio $ +/* $Id: ncbicgi.cpp 534862 2017-05-03 12:54:15Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1316,7 +1316,7 @@ void CCgiRequest::x_ProcessInputStream(TFlags flags, CNcbiIstream* istr, int ifd NStr::StartsWith(content_type, "multipart/form-data"))) { // Automagically retrieve and parse content into entries - auto_ptr temp_str; + unique_ptr temp_str; string* pstr = 0; // Check if the content must be saved if (flags & fSaveRequestContent) { diff --git a/c++/src/cgi/ncbires.cpp b/c++/src/cgi/ncbires.cpp index 69cd5162..87d7b171 100644 --- a/c++/src/cgi/ncbires.cpp +++ b/c++/src/cgi/ncbires.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbires.cpp 112285 2007-10-15 18:28:19Z ivanovp $ +/* $Id: ncbires.cpp 534862 2017-05-03 12:54:15Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -92,7 +92,7 @@ void CNcbiResource::HandleRequest( CCgiContext& ctx ) TCmdList::iterator it = find_if( m_cmd.begin(), m_cmd.end(), PRequested( ctx ) ); - auto_ptr cmd( ( it == m_cmd.end() ) + unique_ptr cmd( ( it == m_cmd.end() ) ? ( defCom = true, GetDefaultCommand() ) : (*it)->Clone() ); cmd->Execute( ctx ); @@ -104,7 +104,7 @@ void CNcbiResource::HandleRequest( CCgiContext& ctx ) _TRACE( e.what() ); ctx.PutMsg( string("Error handling request: ") + e.what() ); if( !defCom ) { - auto_ptr cmd( GetDefaultCommand() ); + unique_ptr cmd( GetDefaultCommand() ); cmd->Execute( ctx ); } } diff --git a/c++/src/cgi/user_agent.cpp b/c++/src/cgi/user_agent.cpp index e98b637d..72c984e1 100644 --- a/c++/src/cgi/user_agent.cpp +++ b/c++/src/cgi/user_agent.cpp @@ -1,4 +1,4 @@ -/* $Id: user_agent.cpp 514811 2016-09-26 15:28:21Z ivanov $ +/* $Id: user_agent.cpp 514600 2016-09-22 17:56:14Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/connect/CMakeLists.connect.lib.txt b/c++/src/connect/CMakeLists.connect.lib.txt new file mode 100644 index 00000000..b8944837 --- /dev/null +++ b/c++/src/connect/CMakeLists.connect.lib.txt @@ -0,0 +1,11 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/connect/Makefile.connect.lib +# + +add_library(connect + ${SRC_C} +) + +target_link_libraries(connect + ${NETWORK_LIBS} ${LIBS} +) diff --git a/c++/src/connect/CMakeLists.connssl.lib.txt b/c++/src/connect/CMakeLists.connssl.lib.txt new file mode 100644 index 00000000..0795ba4b --- /dev/null +++ b/c++/src/connect/CMakeLists.connssl.lib.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/connect/Makefile.connssl.lib +# +add_library(connssl + ${SRC_TLS} +) +include_directories(SYSTEM ${GNUTLS_INCLUDE} ${NCBI_C_INCLUDE}) + +link_directories(${NCBI_TOOLS_ROOT}/lib64) + +target_link_libraries(connssl + connect ${GNUTLS_LIBS} +) diff --git a/c++/src/connect/CMakeLists.txt b/c++/src/connect/CMakeLists.txt new file mode 100644 index 00000000..3021316b --- /dev/null +++ b/c++/src/connect/CMakeLists.txt @@ -0,0 +1,94 @@ +############################################################################## +# +# + +# +# The connect library uses a split between a shared C toolkit library and an +# independent C++ toolkit library +# These variables capture the split + +if (UNIX) + set(os_src ${LOCAL_LBSM}) +elseif (WIN32) + set(os_src ncbi_lbsmd_stub ncbi_strerror) +endif() + + +set(SRC_TLS ncbi_gnutls ncbi_mbedtls ncbi_tls + mbedtls/aes mbedtls/aesni mbedtls/arc4 mbedtls/asn1parse + mbedtls/asn1write mbedtls/base64 mbedtls/bignum mbedtls/blowfish + mbedtls/camellia mbedtls/ccm mbedtls/cipher mbedtls/cipher_wrap + mbedtls/cmac mbedtls/ctr_drbg mbedtls/des mbedtls/dhm mbedtls/ecdh + mbedtls/ecdsa mbedtls/ecjpake mbedtls/ecp mbedtls/ecp_curves + mbedtls/entropy mbedtls/entropy_poll mbedtls/error mbedtls/gcm + mbedtls/havege mbedtls/hmac_drbg mbedtls/md mbedtls/md2 + mbedtls/md4 mbedtls/mbedtls_md5 mbedtls/md_wrap + mbedtls/memory_buffer_alloc mbedtls/oid mbedtls/padlock + mbedtls/pem mbedtls/pk mbedtls/pk_wrap mbedtls/pkcs12 + mbedtls/pkcs5 mbedtls/pkparse mbedtls/pkwrite mbedtls/platform + mbedtls/ripemd160 mbedtls/rsa mbedtls/sha1 mbedtls/sha256 + mbedtls/sha512 mbedtls/threading mbedtls/timing + mbedtls/mbedtls_version mbedtls/version_features mbedtls/xtea + mbedtls/certs mbedtls/pkcs11 mbedtls/x509 mbedtls/x509_create + mbedtls/x509_crl mbedtls/x509_crt mbedtls/x509_csr + mbedtls/x509write_crt mbedtls/x509write_csr + mbedtls/debug mbedtls/net_sockets mbedtls/ssl_cache + mbedtls/ssl_ciphersuites mbedtls/ssl_cli mbedtls/ssl_cookie + mbedtls/ssl_srv mbedtls/ssl_ticket mbedtls/ssl_tls + + ncbi_gnutls ncbi_mbedtls ncbi_tls + mbedtls/aes mbedtls/aesni mbedtls/arc4 mbedtls/asn1parse + mbedtls/asn1write mbedtls/base64 mbedtls/bignum mbedtls/blowfish + mbedtls/camellia mbedtls/ccm mbedtls/cipher mbedtls/cipher_wrap + mbedtls/cmac mbedtls/ctr_drbg mbedtls/des mbedtls/dhm mbedtls/ecdh + mbedtls/ecdsa mbedtls/ecjpake mbedtls/ecp mbedtls/ecp_curves + mbedtls/entropy mbedtls/entropy_poll mbedtls/error mbedtls/gcm + mbedtls/havege mbedtls/hmac_drbg mbedtls/md mbedtls/md2 + mbedtls/md4 mbedtls/mbedtls_md5 mbedtls/md_wrap + mbedtls/memory_buffer_alloc mbedtls/oid mbedtls/padlock + mbedtls/pem mbedtls/pk mbedtls/pk_wrap mbedtls/pkcs12 + mbedtls/pkcs5 mbedtls/pkparse mbedtls/pkwrite mbedtls/platform + mbedtls/ripemd160 mbedtls/rsa mbedtls/sha1 mbedtls/sha256 + mbedtls/sha512 mbedtls/threading mbedtls/timing + mbedtls/mbedtls_version mbedtls/version_features mbedtls/xtea + mbedtls/certs mbedtls/pkcs11 mbedtls/x509 mbedtls/x509_create + mbedtls/x509_crl mbedtls/x509_crt mbedtls/x509_csr + mbedtls/x509write_crt mbedtls/x509write_csr + mbedtls/debug mbedtls/net_sockets mbedtls/ssl_cache + mbedtls/ssl_ciphersuites mbedtls/ssl_cli mbedtls/ssl_cookie + mbedtls/ssl_srv mbedtls/ssl_ticket mbedtls/ssl_tls + ) + +set(SRC_C + ncbi_ansi_ext ncbi_buffer ncbi_types ncbi_priv ncbi_core ncbi_util + ncbi_socket ncbi_connutil ncbi_connection ncbi_connector + ncbi_socket_connector ncbi_file_connector ncbi_http_connector + ncbi_memory_connector ncbi_heapmgr ncbi_server_info ncbi_service + ncbi_host_info ncbi_dispd ncbi_service_connector ncbi_sendmail + ncbi_ftp_connector ncbi_lb ncbi_local ncbi_base64 ncbi_version + ncbi_lbos ncbi_namerd parson ncbi_ipv6 ncbi_iprange ncbi_localip + ${os_src} + ) + +set(SRC_CXX + ncbi_socket_cxx ncbi_core_cxx email_diag_handler + ncbi_conn_streambuf ncbi_conn_stream ncbi_conn_test + ncbi_misc ncbi_namedpipe ncbi_namedpipe_connector + ncbi_pipe ncbi_pipe_connector ncbi_conn_reader_writer + ncbi_userhost ncbi_http_session ncbi_lbos_cxx ncbi_monkey + ${SRC_TLS} + ) + + +# Include projects from this directory +include(CMakeLists.connect.lib.txt) +include(CMakeLists.connssl.lib.txt) +include(CMakeLists.xxconnect.lib.txt) +include(CMakeLists.xconnect.lib.txt) +include(CMakeLists.xthrserv.lib.txt) + +# Recurse subdirectories +add_subdirectory(services) +add_subdirectory(ext) +add_subdirectory(test ) +add_subdirectory(daemons) diff --git a/c++/src/connect/CMakeLists.xconnect.lib.txt b/c++/src/connect/CMakeLists.xconnect.lib.txt new file mode 100644 index 00000000..d87a1302 --- /dev/null +++ b/c++/src/connect/CMakeLists.xconnect.lib.txt @@ -0,0 +1,12 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/connect/Makefile.xconnect.lib +# + +add_library(xconnect + ${SRC_C} ${SRC_CXX} +) + +target_link_libraries(xconnect + xncbi ${GNUTLS_LIBS} ${NETWORK_LIBS} +) + diff --git a/c++/src/connect/CMakeLists.xthrserv.lib.txt b/c++/src/connect/CMakeLists.xthrserv.lib.txt new file mode 100644 index 00000000..02f201b2 --- /dev/null +++ b/c++/src/connect/CMakeLists.xthrserv.lib.txt @@ -0,0 +1,9 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/connect/Makefile.xthrserv.lib +# +add_library(xthrserv + threaded_server server server_monitor connection_pool +) +target_link_libraries(xthrserv + xconnect xutil +) diff --git a/c++/src/connect/CMakeLists.xxconnect.lib.txt b/c++/src/connect/CMakeLists.xxconnect.lib.txt new file mode 100644 index 00000000..13c2870a --- /dev/null +++ b/c++/src/connect/CMakeLists.xxconnect.lib.txt @@ -0,0 +1,36 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/connect/Makefile.xxconnect.lib +# +add_library(xxconnect + ${SRC_CXX} +) + +if (BUILD_SHARED_LIBS) + +target_link_libraries(xxconnect + connect xncbi +) + +else() + +if (HAVE_NCBI_C) + +target_link_libraries(xxconnect + connect xncbi +) + +else() + +target_link_libraries(xxconnect + connect xncbi +) + +endif() + +endif() + + +target_link_libraries(xxconnect + connect xncbi ${GNUTLS_LIBS} ${NETWORK_LIBS} +) + diff --git a/c++/src/connect/Makefile.connect.lib b/c++/src/connect/Makefile.connect.lib index c703d3d3..718d3b0f 100644 --- a/c++/src/connect/Makefile.connect.lib +++ b/c++/src/connect/Makefile.connect.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.connect.lib 503166 2016-06-01 19:40:51Z lavr $ +# $Id: Makefile.connect.lib 537401 2017-05-31 15:53:43Z lavr $ SRC_C = ncbi_ansi_ext ncbi_buffer ncbi_types ncbi_priv ncbi_core ncbi_util \ ncbi_socket ncbi_connutil ncbi_connection ncbi_connector \ @@ -6,7 +6,7 @@ SRC_C = ncbi_ansi_ext ncbi_buffer ncbi_types ncbi_priv ncbi_core ncbi_util \ ncbi_memory_connector ncbi_heapmgr ncbi_server_info ncbi_service \ ncbi_host_info ncbi_dispd ncbi_service_connector ncbi_sendmail \ ncbi_ftp_connector ncbi_lb ncbi_local ncbi_base64 ncbi_version \ - ncbi_lbos parson + ncbi_lbos ncbi_namerd parson ncbi_ipv6 ncbi_iprange ncbi_localip SRC = $(SRC_C) UNIX_SRC = $(LOCAL_LBSM) @@ -16,4 +16,4 @@ PROJ_TAG = core mod_loadinfo LIBS = $(NETWORK_LIBS) $(ORIG_C_LIBS) -WATCHERS = lavr elisovdn +WATCHERS = lavr mcelhany diff --git a/c++/src/connect/Makefile.connect.lib.unix b/c++/src/connect/Makefile.connect.lib.unix index add7ef6f..f76895d7 100644 --- a/c++/src/connect/Makefile.connect.lib.unix +++ b/c++/src/connect/Makefile.connect.lib.unix @@ -1,4 +1,4 @@ -# $Id: Makefile.connect.lib.unix 503212 2016-06-01 21:36:53Z ucko $ +# $Id: Makefile.connect.lib.unix 537471 2017-05-31 19:59:02Z ucko $ # Adjust ICC flags to avoid problematic references to # __intel_sse2_str* functions (as of ICC [20]13) @@ -11,10 +11,13 @@ ifeq "$(COMPILER)-$(DEBUG_SFX)$(DLL)" "icc-Release" -fno-builtin-strncmp -fno-builtin-strspn ncbi_http_connector.o: CFLAGS += -fno-builtin-strcpy -fno-builtin-strcspn \ -fno-builtin-strspn + ncbi_iprange.o: CFLAGS += -fno-builtin-strncmp ncbi_lbos.o: CFLAGS += -fno-builtin-strcat ncbi_lbsm.o: CFLAGS += -fno-builtin-strcpy ncbi_lbsmd.o: CFLAGS += -fno-builtin-strcspn -fno-builtin-strspn ncbi_local.o: CFLAGS += -fno-builtin-strcspn -fno-builtin-strspn + ncbi_localip.o: CFLAGS += -fno-builtin-strcspn -fno-builtin-strspn + ncbi_namerd.o: CFLAGS += -fno-builtin-strcat ncbi_sendmail.o: CFLAGS += -fno-builtin-strcpy ncbi_server_info.o: CFLAGS += -fno-builtin-strcpy -fno-builtin-strcspn \ -fno-builtin-strspn diff --git a/c++/src/connect/Makefile.connssl.lib b/c++/src/connect/Makefile.connssl.lib index 1491b412..c340ca69 100644 --- a/c++/src/connect/Makefile.connssl.lib +++ b/c++/src/connect/Makefile.connssl.lib @@ -1,8 +1,30 @@ -# $Id: Makefile.connssl.lib 503166 2016-06-01 19:40:51Z lavr $ +# $Id: Makefile.connssl.lib 531303 2017-03-23 14:58:43Z ucko $ -CPPFLAGS = $(GNUTLS_INCLUDE) $(ORIG_CPPFLAGS) +CPPFLAGS = $(TLS_INCLUDE) $(ORIG_CPPFLAGS) -SRC = ncbi_gnutls +SRC_TLS = ncbi_gnutls ncbi_mbedtls ncbi_tls \ + mbedtls/aes mbedtls/aesni mbedtls/arc4 mbedtls/asn1parse \ + mbedtls/asn1write mbedtls/base64 mbedtls/bignum mbedtls/blowfish \ + mbedtls/camellia mbedtls/ccm mbedtls/cipher mbedtls/cipher_wrap \ + mbedtls/cmac mbedtls/ctr_drbg mbedtls/des mbedtls/dhm mbedtls/ecdh \ + mbedtls/ecdsa mbedtls/ecjpake mbedtls/ecp mbedtls/ecp_curves \ + mbedtls/entropy mbedtls/entropy_poll mbedtls/error mbedtls/gcm \ + mbedtls/havege mbedtls/hmac_drbg mbedtls/md mbedtls/md2 \ + mbedtls/md4 mbedtls/mbedtls_md5 mbedtls/md_wrap \ + mbedtls/memory_buffer_alloc mbedtls/oid mbedtls/padlock \ + mbedtls/pem mbedtls/pk mbedtls/pk_wrap mbedtls/pkcs12 \ + mbedtls/pkcs5 mbedtls/pkparse mbedtls/pkwrite mbedtls/platform \ + mbedtls/ripemd160 mbedtls/rsa mbedtls/sha1 mbedtls/sha256 \ + mbedtls/sha512 mbedtls/threading mbedtls/timing \ + mbedtls/mbedtls_version mbedtls/version_features mbedtls/xtea \ + mbedtls/certs mbedtls/pkcs11 mbedtls/x509 mbedtls/x509_create \ + mbedtls/x509_crl mbedtls/x509_crt mbedtls/x509_csr \ + mbedtls/x509write_crt mbedtls/x509write_csr \ + mbedtls/debug mbedtls/net_sockets mbedtls/ssl_cache \ + mbedtls/ssl_ciphersuites mbedtls/ssl_cli mbedtls/ssl_cookie \ + mbedtls/ssl_srv mbedtls/ssl_ticket mbedtls/ssl_tls + +SRC = $(SRC_TLS) LIB = connssl WATCHERS = lavr diff --git a/c++/src/connect/Makefile.connssl.lib.unix b/c++/src/connect/Makefile.connssl.lib.unix new file mode 100644 index 00000000..badc6b30 --- /dev/null +++ b/c++/src/connect/Makefile.connssl.lib.unix @@ -0,0 +1,8 @@ +# $Id: Makefile.connssl.lib.unix 531052 2017-03-20 20:57:34Z ucko $ + +# Adjust ICC flags to avoid problematic references to +# __intel_sse2_str* functions (as of ICC [20]15) + +ifeq "$(COMPILER)-$(DEBUG_SFX)$(DLL)" "icc-Release" + mbedtls/x509_create.o: CFLAGS += -fno-builtin-strncmp +endif diff --git a/c++/src/connect/Makefile.in b/c++/src/connect/Makefile.in index f5395e05..69383373 100644 --- a/c++/src/connect/Makefile.in +++ b/c++/src/connect/Makefile.in @@ -1,5 +1,5 @@ ################################# -# $Id: Makefile.in 255485 2011-02-24 14:58:27Z ivanov $ +# $Id: Makefile.in 530900 2017-03-19 01:06:13Z lavr $ # Author: Denis Vakatov (vakatov@ncbi.nlm.nih.gov) ################################# @@ -9,7 +9,7 @@ # - tests: "test/*.*" ################################# -LIB_PROJ = connect connssl xxconnect xconnect xthrserv +LIB_PROJ = connssl connect xxconnect xconnect xthrserv SUB_PROJ = services ext test daemons WATCHERS = lavr diff --git a/c++/src/connect/Makefile.xconnect.lib b/c++/src/connect/Makefile.xconnect.lib index 1d6a4404..35d7cb43 100644 --- a/c++/src/connect/Makefile.xconnect.lib +++ b/c++/src/connect/Makefile.xconnect.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.xconnect.lib 503166 2016-06-01 19:40:51Z lavr $ +# $Id: Makefile.xconnect.lib 530900 2017-03-19 01:06:13Z lavr $ # # XCONNECT -- includes: # CONNECT API (C-only, sources shared with the C Toolkit), plus @@ -8,12 +8,12 @@ include $(srcdir)/Makefile.connect.lib include $(srcdir)/Makefile.xxconnect.lib -SRC = $(SRC_C) $(SRC_CXX) +SRC = $(SRC_C) $(SRC_CXX) UNIX_SRC = $(LOCAL_LBSM) -LIB = xconnect +LIB = xconnect PROJ_TAG = core -LIBS = $(NETWORK_LIBS) $(ORIG_LIBS) +LIBS = $(NETWORK_LIBS) $(ORIG_LIBS) -WATCHERS = lavr elisovdn +WATCHERS = lavr mcelhany diff --git a/c++/src/connect/Makefile.xxconnect.lib b/c++/src/connect/Makefile.xxconnect.lib index 220ccc3d..642d5a9a 100644 --- a/c++/src/connect/Makefile.xxconnect.lib +++ b/c++/src/connect/Makefile.xxconnect.lib @@ -1,15 +1,15 @@ -# $Id: Makefile.xxconnect.lib 503166 2016-06-01 19:40:51Z lavr $ +# $Id: Makefile.xxconnect.lib 533505 2017-04-17 15:01:36Z mcelhany $ # # XXCONNECT -- includes C++-only part of connection library -CPPFLAGS = $(GNUTLS_INCLUDE) $(ORIG_CPPFLAGS) +include $(srcdir)/Makefile.connssl.lib SRC_CXX = ncbi_socket_cxx ncbi_core_cxx email_diag_handler \ ncbi_conn_streambuf ncbi_conn_stream ncbi_conn_test \ ncbi_misc ncbi_namedpipe ncbi_namedpipe_connector \ ncbi_pipe ncbi_pipe_connector ncbi_conn_reader_writer \ ncbi_userhost ncbi_http_session ncbi_lbos_cxx ncbi_monkey \ - ncbi_gnutls + $(SRC_TLS) SRC = $(SRC_CXX) @@ -18,4 +18,4 @@ PROJ_TAG = core LIBS = $(NETWORK_LIBS) $(ORIG_LIBS) -WATCHERS = lavr elisovdn +WATCHERS = lavr mcelhany diff --git a/c++/src/connect/Makefile.xxconnect.lib.unix b/c++/src/connect/Makefile.xxconnect.lib.unix index e247d174..6478f131 100644 --- a/c++/src/connect/Makefile.xxconnect.lib.unix +++ b/c++/src/connect/Makefile.xxconnect.lib.unix @@ -1,5 +1,6 @@ -# $Id: Makefile.xxconnect.lib.unix 486618 2015-12-08 03:51:15Z ucko $ +# $Id: Makefile.xxconnect.lib.unix 531052 2017-03-20 20:57:34Z ucko $ ifeq "$(COMPILER)-$(DEBUG_SFX)$(DLL)" "icc-Release" ncbi_conn_stream.o: CXXFLAGS += -fno-builtin-strspn ncbi_conn_test.o: CXXFLAGS += -fno-builtin-strcpy endif +include $(srcdir)/Makefile.connssl.lib.unix diff --git a/c++/src/connect/mbedtls/aes.c b/c++/src/connect/mbedtls/aes.c new file mode 100644 index 00000000..a186dee9 --- /dev/null +++ b/c++/src/connect/mbedtls/aes.c @@ -0,0 +1,1492 @@ +/* + * FIPS-197 compliant AES implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The AES block cipher was designed by Vincent Rijmen and Joan Daemen. + * + * http://csrc.nist.gov/encryption/aes/rijndael/Rijndael.pdf + * http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AES_C) + +#include + +#include "mbedtls/aes.h" +#if defined(MBEDTLS_PADLOCK_C) +#include "mbedtls/padlock.h" +#endif +#if defined(MBEDTLS_AESNI_C) +#include "mbedtls/aesni.h" +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_AES_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +#if defined(MBEDTLS_PADLOCK_C) && \ + ( defined(MBEDTLS_HAVE_X86) || defined(MBEDTLS_PADLOCK_ALIGN16) ) +static int aes_padlock_ace = -1; +#endif + +#if defined(MBEDTLS_AES_ROM_TABLES) +/* + * Forward S-box + */ +static const unsigned char FSb[256] = +{ + 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, + 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, + 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, + 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, + 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, + 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, + 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, + 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, + 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, + 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, + 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, + 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, + 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, + 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, + 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, + 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, + 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, + 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, + 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, + 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, + 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, + 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, + 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, + 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, + 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, + 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, + 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, + 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, + 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, + 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, + 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, + 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16 +}; + +/* + * Forward tables + */ +#define FT \ +\ + V(A5,63,63,C6), V(84,7C,7C,F8), V(99,77,77,EE), V(8D,7B,7B,F6), \ + V(0D,F2,F2,FF), V(BD,6B,6B,D6), V(B1,6F,6F,DE), V(54,C5,C5,91), \ + V(50,30,30,60), V(03,01,01,02), V(A9,67,67,CE), V(7D,2B,2B,56), \ + V(19,FE,FE,E7), V(62,D7,D7,B5), V(E6,AB,AB,4D), V(9A,76,76,EC), \ + V(45,CA,CA,8F), V(9D,82,82,1F), V(40,C9,C9,89), V(87,7D,7D,FA), \ + V(15,FA,FA,EF), V(EB,59,59,B2), V(C9,47,47,8E), V(0B,F0,F0,FB), \ + V(EC,AD,AD,41), V(67,D4,D4,B3), V(FD,A2,A2,5F), V(EA,AF,AF,45), \ + V(BF,9C,9C,23), V(F7,A4,A4,53), V(96,72,72,E4), V(5B,C0,C0,9B), \ + V(C2,B7,B7,75), V(1C,FD,FD,E1), V(AE,93,93,3D), V(6A,26,26,4C), \ + V(5A,36,36,6C), V(41,3F,3F,7E), V(02,F7,F7,F5), V(4F,CC,CC,83), \ + V(5C,34,34,68), V(F4,A5,A5,51), V(34,E5,E5,D1), V(08,F1,F1,F9), \ + V(93,71,71,E2), V(73,D8,D8,AB), V(53,31,31,62), V(3F,15,15,2A), \ + V(0C,04,04,08), V(52,C7,C7,95), V(65,23,23,46), V(5E,C3,C3,9D), \ + V(28,18,18,30), V(A1,96,96,37), V(0F,05,05,0A), V(B5,9A,9A,2F), \ + V(09,07,07,0E), V(36,12,12,24), V(9B,80,80,1B), V(3D,E2,E2,DF), \ + V(26,EB,EB,CD), V(69,27,27,4E), V(CD,B2,B2,7F), V(9F,75,75,EA), \ + V(1B,09,09,12), V(9E,83,83,1D), V(74,2C,2C,58), V(2E,1A,1A,34), \ + V(2D,1B,1B,36), V(B2,6E,6E,DC), V(EE,5A,5A,B4), V(FB,A0,A0,5B), \ + V(F6,52,52,A4), V(4D,3B,3B,76), V(61,D6,D6,B7), V(CE,B3,B3,7D), \ + V(7B,29,29,52), V(3E,E3,E3,DD), V(71,2F,2F,5E), V(97,84,84,13), \ + V(F5,53,53,A6), V(68,D1,D1,B9), V(00,00,00,00), V(2C,ED,ED,C1), \ + V(60,20,20,40), V(1F,FC,FC,E3), V(C8,B1,B1,79), V(ED,5B,5B,B6), \ + V(BE,6A,6A,D4), V(46,CB,CB,8D), V(D9,BE,BE,67), V(4B,39,39,72), \ + V(DE,4A,4A,94), V(D4,4C,4C,98), V(E8,58,58,B0), V(4A,CF,CF,85), \ + V(6B,D0,D0,BB), V(2A,EF,EF,C5), V(E5,AA,AA,4F), V(16,FB,FB,ED), \ + V(C5,43,43,86), V(D7,4D,4D,9A), V(55,33,33,66), V(94,85,85,11), \ + V(CF,45,45,8A), V(10,F9,F9,E9), V(06,02,02,04), V(81,7F,7F,FE), \ + V(F0,50,50,A0), V(44,3C,3C,78), V(BA,9F,9F,25), V(E3,A8,A8,4B), \ + V(F3,51,51,A2), V(FE,A3,A3,5D), V(C0,40,40,80), V(8A,8F,8F,05), \ + V(AD,92,92,3F), V(BC,9D,9D,21), V(48,38,38,70), V(04,F5,F5,F1), \ + V(DF,BC,BC,63), V(C1,B6,B6,77), V(75,DA,DA,AF), V(63,21,21,42), \ + V(30,10,10,20), V(1A,FF,FF,E5), V(0E,F3,F3,FD), V(6D,D2,D2,BF), \ + V(4C,CD,CD,81), V(14,0C,0C,18), V(35,13,13,26), V(2F,EC,EC,C3), \ + V(E1,5F,5F,BE), V(A2,97,97,35), V(CC,44,44,88), V(39,17,17,2E), \ + V(57,C4,C4,93), V(F2,A7,A7,55), V(82,7E,7E,FC), V(47,3D,3D,7A), \ + V(AC,64,64,C8), V(E7,5D,5D,BA), V(2B,19,19,32), V(95,73,73,E6), \ + V(A0,60,60,C0), V(98,81,81,19), V(D1,4F,4F,9E), V(7F,DC,DC,A3), \ + V(66,22,22,44), V(7E,2A,2A,54), V(AB,90,90,3B), V(83,88,88,0B), \ + V(CA,46,46,8C), V(29,EE,EE,C7), V(D3,B8,B8,6B), V(3C,14,14,28), \ + V(79,DE,DE,A7), V(E2,5E,5E,BC), V(1D,0B,0B,16), V(76,DB,DB,AD), \ + V(3B,E0,E0,DB), V(56,32,32,64), V(4E,3A,3A,74), V(1E,0A,0A,14), \ + V(DB,49,49,92), V(0A,06,06,0C), V(6C,24,24,48), V(E4,5C,5C,B8), \ + V(5D,C2,C2,9F), V(6E,D3,D3,BD), V(EF,AC,AC,43), V(A6,62,62,C4), \ + V(A8,91,91,39), V(A4,95,95,31), V(37,E4,E4,D3), V(8B,79,79,F2), \ + V(32,E7,E7,D5), V(43,C8,C8,8B), V(59,37,37,6E), V(B7,6D,6D,DA), \ + V(8C,8D,8D,01), V(64,D5,D5,B1), V(D2,4E,4E,9C), V(E0,A9,A9,49), \ + V(B4,6C,6C,D8), V(FA,56,56,AC), V(07,F4,F4,F3), V(25,EA,EA,CF), \ + V(AF,65,65,CA), V(8E,7A,7A,F4), V(E9,AE,AE,47), V(18,08,08,10), \ + V(D5,BA,BA,6F), V(88,78,78,F0), V(6F,25,25,4A), V(72,2E,2E,5C), \ + V(24,1C,1C,38), V(F1,A6,A6,57), V(C7,B4,B4,73), V(51,C6,C6,97), \ + V(23,E8,E8,CB), V(7C,DD,DD,A1), V(9C,74,74,E8), V(21,1F,1F,3E), \ + V(DD,4B,4B,96), V(DC,BD,BD,61), V(86,8B,8B,0D), V(85,8A,8A,0F), \ + V(90,70,70,E0), V(42,3E,3E,7C), V(C4,B5,B5,71), V(AA,66,66,CC), \ + V(D8,48,48,90), V(05,03,03,06), V(01,F6,F6,F7), V(12,0E,0E,1C), \ + V(A3,61,61,C2), V(5F,35,35,6A), V(F9,57,57,AE), V(D0,B9,B9,69), \ + V(91,86,86,17), V(58,C1,C1,99), V(27,1D,1D,3A), V(B9,9E,9E,27), \ + V(38,E1,E1,D9), V(13,F8,F8,EB), V(B3,98,98,2B), V(33,11,11,22), \ + V(BB,69,69,D2), V(70,D9,D9,A9), V(89,8E,8E,07), V(A7,94,94,33), \ + V(B6,9B,9B,2D), V(22,1E,1E,3C), V(92,87,87,15), V(20,E9,E9,C9), \ + V(49,CE,CE,87), V(FF,55,55,AA), V(78,28,28,50), V(7A,DF,DF,A5), \ + V(8F,8C,8C,03), V(F8,A1,A1,59), V(80,89,89,09), V(17,0D,0D,1A), \ + V(DA,BF,BF,65), V(31,E6,E6,D7), V(C6,42,42,84), V(B8,68,68,D0), \ + V(C3,41,41,82), V(B0,99,99,29), V(77,2D,2D,5A), V(11,0F,0F,1E), \ + V(CB,B0,B0,7B), V(FC,54,54,A8), V(D6,BB,BB,6D), V(3A,16,16,2C) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32_t FT0[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32_t FT1[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32_t FT2[256] = { FT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32_t FT3[256] = { FT }; +#undef V + +#undef FT + +/* + * Reverse S-box + */ +static const unsigned char RSb[256] = +{ + 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, + 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB, + 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, + 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, + 0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, + 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E, + 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, + 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25, + 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, + 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, + 0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, + 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84, + 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, + 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06, + 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, + 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, + 0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, + 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73, + 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, + 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E, + 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, + 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, + 0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, + 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4, + 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, + 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F, + 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, + 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, + 0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, + 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, + 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D +}; + +/* + * Reverse tables + */ +#define RT \ +\ + V(50,A7,F4,51), V(53,65,41,7E), V(C3,A4,17,1A), V(96,5E,27,3A), \ + V(CB,6B,AB,3B), V(F1,45,9D,1F), V(AB,58,FA,AC), V(93,03,E3,4B), \ + V(55,FA,30,20), V(F6,6D,76,AD), V(91,76,CC,88), V(25,4C,02,F5), \ + V(FC,D7,E5,4F), V(D7,CB,2A,C5), V(80,44,35,26), V(8F,A3,62,B5), \ + V(49,5A,B1,DE), V(67,1B,BA,25), V(98,0E,EA,45), V(E1,C0,FE,5D), \ + V(02,75,2F,C3), V(12,F0,4C,81), V(A3,97,46,8D), V(C6,F9,D3,6B), \ + V(E7,5F,8F,03), V(95,9C,92,15), V(EB,7A,6D,BF), V(DA,59,52,95), \ + V(2D,83,BE,D4), V(D3,21,74,58), V(29,69,E0,49), V(44,C8,C9,8E), \ + V(6A,89,C2,75), V(78,79,8E,F4), V(6B,3E,58,99), V(DD,71,B9,27), \ + V(B6,4F,E1,BE), V(17,AD,88,F0), V(66,AC,20,C9), V(B4,3A,CE,7D), \ + V(18,4A,DF,63), V(82,31,1A,E5), V(60,33,51,97), V(45,7F,53,62), \ + V(E0,77,64,B1), V(84,AE,6B,BB), V(1C,A0,81,FE), V(94,2B,08,F9), \ + V(58,68,48,70), V(19,FD,45,8F), V(87,6C,DE,94), V(B7,F8,7B,52), \ + V(23,D3,73,AB), V(E2,02,4B,72), V(57,8F,1F,E3), V(2A,AB,55,66), \ + V(07,28,EB,B2), V(03,C2,B5,2F), V(9A,7B,C5,86), V(A5,08,37,D3), \ + V(F2,87,28,30), V(B2,A5,BF,23), V(BA,6A,03,02), V(5C,82,16,ED), \ + V(2B,1C,CF,8A), V(92,B4,79,A7), V(F0,F2,07,F3), V(A1,E2,69,4E), \ + V(CD,F4,DA,65), V(D5,BE,05,06), V(1F,62,34,D1), V(8A,FE,A6,C4), \ + V(9D,53,2E,34), V(A0,55,F3,A2), V(32,E1,8A,05), V(75,EB,F6,A4), \ + V(39,EC,83,0B), V(AA,EF,60,40), V(06,9F,71,5E), V(51,10,6E,BD), \ + V(F9,8A,21,3E), V(3D,06,DD,96), V(AE,05,3E,DD), V(46,BD,E6,4D), \ + V(B5,8D,54,91), V(05,5D,C4,71), V(6F,D4,06,04), V(FF,15,50,60), \ + V(24,FB,98,19), V(97,E9,BD,D6), V(CC,43,40,89), V(77,9E,D9,67), \ + V(BD,42,E8,B0), V(88,8B,89,07), V(38,5B,19,E7), V(DB,EE,C8,79), \ + V(47,0A,7C,A1), V(E9,0F,42,7C), V(C9,1E,84,F8), V(00,00,00,00), \ + V(83,86,80,09), V(48,ED,2B,32), V(AC,70,11,1E), V(4E,72,5A,6C), \ + V(FB,FF,0E,FD), V(56,38,85,0F), V(1E,D5,AE,3D), V(27,39,2D,36), \ + V(64,D9,0F,0A), V(21,A6,5C,68), V(D1,54,5B,9B), V(3A,2E,36,24), \ + V(B1,67,0A,0C), V(0F,E7,57,93), V(D2,96,EE,B4), V(9E,91,9B,1B), \ + V(4F,C5,C0,80), V(A2,20,DC,61), V(69,4B,77,5A), V(16,1A,12,1C), \ + V(0A,BA,93,E2), V(E5,2A,A0,C0), V(43,E0,22,3C), V(1D,17,1B,12), \ + V(0B,0D,09,0E), V(AD,C7,8B,F2), V(B9,A8,B6,2D), V(C8,A9,1E,14), \ + V(85,19,F1,57), V(4C,07,75,AF), V(BB,DD,99,EE), V(FD,60,7F,A3), \ + V(9F,26,01,F7), V(BC,F5,72,5C), V(C5,3B,66,44), V(34,7E,FB,5B), \ + V(76,29,43,8B), V(DC,C6,23,CB), V(68,FC,ED,B6), V(63,F1,E4,B8), \ + V(CA,DC,31,D7), V(10,85,63,42), V(40,22,97,13), V(20,11,C6,84), \ + V(7D,24,4A,85), V(F8,3D,BB,D2), V(11,32,F9,AE), V(6D,A1,29,C7), \ + V(4B,2F,9E,1D), V(F3,30,B2,DC), V(EC,52,86,0D), V(D0,E3,C1,77), \ + V(6C,16,B3,2B), V(99,B9,70,A9), V(FA,48,94,11), V(22,64,E9,47), \ + V(C4,8C,FC,A8), V(1A,3F,F0,A0), V(D8,2C,7D,56), V(EF,90,33,22), \ + V(C7,4E,49,87), V(C1,D1,38,D9), V(FE,A2,CA,8C), V(36,0B,D4,98), \ + V(CF,81,F5,A6), V(28,DE,7A,A5), V(26,8E,B7,DA), V(A4,BF,AD,3F), \ + V(E4,9D,3A,2C), V(0D,92,78,50), V(9B,CC,5F,6A), V(62,46,7E,54), \ + V(C2,13,8D,F6), V(E8,B8,D8,90), V(5E,F7,39,2E), V(F5,AF,C3,82), \ + V(BE,80,5D,9F), V(7C,93,D0,69), V(A9,2D,D5,6F), V(B3,12,25,CF), \ + V(3B,99,AC,C8), V(A7,7D,18,10), V(6E,63,9C,E8), V(7B,BB,3B,DB), \ + V(09,78,26,CD), V(F4,18,59,6E), V(01,B7,9A,EC), V(A8,9A,4F,83), \ + V(65,6E,95,E6), V(7E,E6,FF,AA), V(08,CF,BC,21), V(E6,E8,15,EF), \ + V(D9,9B,E7,BA), V(CE,36,6F,4A), V(D4,09,9F,EA), V(D6,7C,B0,29), \ + V(AF,B2,A4,31), V(31,23,3F,2A), V(30,94,A5,C6), V(C0,66,A2,35), \ + V(37,BC,4E,74), V(A6,CA,82,FC), V(B0,D0,90,E0), V(15,D8,A7,33), \ + V(4A,98,04,F1), V(F7,DA,EC,41), V(0E,50,CD,7F), V(2F,F6,91,17), \ + V(8D,D6,4D,76), V(4D,B0,EF,43), V(54,4D,AA,CC), V(DF,04,96,E4), \ + V(E3,B5,D1,9E), V(1B,88,6A,4C), V(B8,1F,2C,C1), V(7F,51,65,46), \ + V(04,EA,5E,9D), V(5D,35,8C,01), V(73,74,87,FA), V(2E,41,0B,FB), \ + V(5A,1D,67,B3), V(52,D2,DB,92), V(33,56,10,E9), V(13,47,D6,6D), \ + V(8C,61,D7,9A), V(7A,0C,A1,37), V(8E,14,F8,59), V(89,3C,13,EB), \ + V(EE,27,A9,CE), V(35,C9,61,B7), V(ED,E5,1C,E1), V(3C,B1,47,7A), \ + V(59,DF,D2,9C), V(3F,73,F2,55), V(79,CE,14,18), V(BF,37,C7,73), \ + V(EA,CD,F7,53), V(5B,AA,FD,5F), V(14,6F,3D,DF), V(86,DB,44,78), \ + V(81,F3,AF,CA), V(3E,C4,68,B9), V(2C,34,24,38), V(5F,40,A3,C2), \ + V(72,C3,1D,16), V(0C,25,E2,BC), V(8B,49,3C,28), V(41,95,0D,FF), \ + V(71,01,A8,39), V(DE,B3,0C,08), V(9C,E4,B4,D8), V(90,C1,56,64), \ + V(61,84,CB,7B), V(70,B6,32,D5), V(74,5C,6C,48), V(42,57,B8,D0) + +#define V(a,b,c,d) 0x##a##b##c##d +static const uint32_t RT0[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##b##c##d##a +static const uint32_t RT1[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##c##d##a##b +static const uint32_t RT2[256] = { RT }; +#undef V + +#define V(a,b,c,d) 0x##d##a##b##c +static const uint32_t RT3[256] = { RT }; +#undef V + +#undef RT + +/* + * Round constants + */ +static const uint32_t RCON[10] = +{ + 0x00000001, 0x00000002, 0x00000004, 0x00000008, + 0x00000010, 0x00000020, 0x00000040, 0x00000080, + 0x0000001B, 0x00000036 +}; + +#else /* MBEDTLS_AES_ROM_TABLES */ + +/* + * Forward S-box & tables + */ +static unsigned char FSb[256]; +static uint32_t FT0[256]; +static uint32_t FT1[256]; +static uint32_t FT2[256]; +static uint32_t FT3[256]; + +/* + * Reverse S-box & tables + */ +static unsigned char RSb[256]; +static uint32_t RT0[256]; +static uint32_t RT1[256]; +static uint32_t RT2[256]; +static uint32_t RT3[256]; + +/* + * Round constants + */ +static uint32_t RCON[10]; + +/* + * Tables generation code + */ +#define ROTL8(x) ( ( x << 8 ) & 0xFFFFFFFF ) | ( x >> 24 ) +#define XTIME(x) ( ( x << 1 ) ^ ( ( x & 0x80 ) ? 0x1B : 0x00 ) ) +#define MUL(x,y) ( ( x && y ) ? pow[(log[x]+log[y]) % 255] : 0 ) + +static int aes_init_done = 0; + +static void aes_gen_tables( void ) +{ + int i, x, y, z; + int pow[256]; + int log[256]; + + /* + * compute pow and log tables over GF(2^8) + */ + for( i = 0, x = 1; i < 256; i++ ) + { + pow[i] = x; + log[x] = i; + x = ( x ^ XTIME( x ) ) & 0xFF; + } + + /* + * calculate the round constants + */ + for( i = 0, x = 1; i < 10; i++ ) + { + RCON[i] = (uint32_t) x; + x = XTIME( x ) & 0xFF; + } + + /* + * generate the forward and reverse S-boxes + */ + FSb[0x00] = 0x63; + RSb[0x63] = 0x00; + + for( i = 1; i < 256; i++ ) + { + x = pow[255 - log[i]]; + + y = x; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y; y = ( ( y << 1 ) | ( y >> 7 ) ) & 0xFF; + x ^= y ^ 0x63; + + FSb[i] = (unsigned char) x; + RSb[x] = (unsigned char) i; + } + + /* + * generate the forward and reverse tables + */ + for( i = 0; i < 256; i++ ) + { + x = FSb[i]; + y = XTIME( x ) & 0xFF; + z = ( y ^ x ) & 0xFF; + + FT0[i] = ( (uint32_t) y ) ^ + ( (uint32_t) x << 8 ) ^ + ( (uint32_t) x << 16 ) ^ + ( (uint32_t) z << 24 ); + + FT1[i] = ROTL8( FT0[i] ); + FT2[i] = ROTL8( FT1[i] ); + FT3[i] = ROTL8( FT2[i] ); + + x = RSb[i]; + + RT0[i] = ( (uint32_t) MUL( 0x0E, x ) ) ^ + ( (uint32_t) MUL( 0x09, x ) << 8 ) ^ + ( (uint32_t) MUL( 0x0D, x ) << 16 ) ^ + ( (uint32_t) MUL( 0x0B, x ) << 24 ); + + RT1[i] = ROTL8( RT0[i] ); + RT2[i] = ROTL8( RT1[i] ); + RT3[i] = ROTL8( RT2[i] ); + } +} + +#endif /* MBEDTLS_AES_ROM_TABLES */ + +void mbedtls_aes_init( mbedtls_aes_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_aes_context ) ); +} + +void mbedtls_aes_free( mbedtls_aes_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_aes_context ) ); +} + +/* + * AES key schedule (encryption) + */ +#if !defined(MBEDTLS_AES_SETKEY_ENC_ALT) +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + unsigned int i; + uint32_t *RK; + +#if !defined(MBEDTLS_AES_ROM_TABLES) + if( aes_init_done == 0 ) + { + aes_gen_tables(); + aes_init_done = 1; + + } +#endif + + switch( keybits ) + { + case 128: ctx->nr = 10; break; + case 192: ctx->nr = 12; break; + case 256: ctx->nr = 14; break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16) + if( aes_padlock_ace == -1 ) + aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE ); + + if( aes_padlock_ace ) + ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf ); + else +#endif + ctx->rk = RK = ctx->buf; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + return( mbedtls_aesni_setkey_enc( (unsigned char *) ctx->rk, key, keybits ) ); +#endif + + for( i = 0; i < ( keybits >> 5 ); i++ ) + { + GET_UINT32_LE( RK[i], key, i << 2 ); + } + + switch( ctx->nr ) + { + case 10: + + for( i = 0; i < 10; i++, RK += 4 ) + { + RK[4] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[3] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[3] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[3] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[3] ) & 0xFF ] << 24 ); + + RK[5] = RK[1] ^ RK[4]; + RK[6] = RK[2] ^ RK[5]; + RK[7] = RK[3] ^ RK[6]; + } + break; + + case 12: + + for( i = 0; i < 8; i++, RK += 6 ) + { + RK[6] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[5] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[5] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[5] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[5] ) & 0xFF ] << 24 ); + + RK[7] = RK[1] ^ RK[6]; + RK[8] = RK[2] ^ RK[7]; + RK[9] = RK[3] ^ RK[8]; + RK[10] = RK[4] ^ RK[9]; + RK[11] = RK[5] ^ RK[10]; + } + break; + + case 14: + + for( i = 0; i < 7; i++, RK += 8 ) + { + RK[8] = RK[0] ^ RCON[i] ^ + ( (uint32_t) FSb[ ( RK[7] >> 8 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[7] >> 16 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[7] >> 24 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[7] ) & 0xFF ] << 24 ); + + RK[9] = RK[1] ^ RK[8]; + RK[10] = RK[2] ^ RK[9]; + RK[11] = RK[3] ^ RK[10]; + + RK[12] = RK[4] ^ + ( (uint32_t) FSb[ ( RK[11] ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( RK[11] >> 24 ) & 0xFF ] << 24 ); + + RK[13] = RK[5] ^ RK[12]; + RK[14] = RK[6] ^ RK[13]; + RK[15] = RK[7] ^ RK[14]; + } + break; + } + + return( 0 ); +} +#endif /* !MBEDTLS_AES_SETKEY_ENC_ALT */ + +/* + * AES key schedule (decryption) + */ +#if !defined(MBEDTLS_AES_SETKEY_DEC_ALT) +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int i, j, ret; + mbedtls_aes_context cty; + uint32_t *RK; + uint32_t *SK; + + mbedtls_aes_init( &cty ); + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_PADLOCK_ALIGN16) + if( aes_padlock_ace == -1 ) + aes_padlock_ace = mbedtls_padlock_has_support( MBEDTLS_PADLOCK_ACE ); + + if( aes_padlock_ace ) + ctx->rk = RK = MBEDTLS_PADLOCK_ALIGN16( ctx->buf ); + else +#endif + ctx->rk = RK = ctx->buf; + + /* Also checks keybits */ + if( ( ret = mbedtls_aes_setkey_enc( &cty, key, keybits ) ) != 0 ) + goto exit; + + ctx->nr = cty.nr; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + { + mbedtls_aesni_inverse_key( (unsigned char *) ctx->rk, + (const unsigned char *) cty.rk, ctx->nr ); + goto exit; + } +#endif + + SK = cty.rk + cty.nr * 4; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for( i = ctx->nr - 1, SK -= 8; i > 0; i--, SK -= 8 ) + { + for( j = 0; j < 4; j++, SK++ ) + { + *RK++ = RT0[ FSb[ ( *SK ) & 0xFF ] ] ^ + RT1[ FSb[ ( *SK >> 8 ) & 0xFF ] ] ^ + RT2[ FSb[ ( *SK >> 16 ) & 0xFF ] ] ^ + RT3[ FSb[ ( *SK >> 24 ) & 0xFF ] ]; + } + } + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + +exit: + mbedtls_aes_free( &cty ); + + return( ret ); +} +#endif /* !MBEDTLS_AES_SETKEY_DEC_ALT */ + +#define AES_FROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ FT0[ ( Y0 ) & 0xFF ] ^ \ + FT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ FT0[ ( Y1 ) & 0xFF ] ^ \ + FT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y0 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ FT0[ ( Y2 ) & 0xFF ] ^ \ + FT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ FT0[ ( Y3 ) & 0xFF ] ^ \ + FT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + FT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + FT3[ ( Y2 >> 24 ) & 0xFF ]; \ +} + +#define AES_RROUND(X0,X1,X2,X3,Y0,Y1,Y2,Y3) \ +{ \ + X0 = *RK++ ^ RT0[ ( Y0 ) & 0xFF ] ^ \ + RT1[ ( Y3 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y2 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y1 >> 24 ) & 0xFF ]; \ + \ + X1 = *RK++ ^ RT0[ ( Y1 ) & 0xFF ] ^ \ + RT1[ ( Y0 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y3 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y2 >> 24 ) & 0xFF ]; \ + \ + X2 = *RK++ ^ RT0[ ( Y2 ) & 0xFF ] ^ \ + RT1[ ( Y1 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y0 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y3 >> 24 ) & 0xFF ]; \ + \ + X3 = *RK++ ^ RT0[ ( Y3 ) & 0xFF ] ^ \ + RT1[ ( Y2 >> 8 ) & 0xFF ] ^ \ + RT2[ ( Y1 >> 16 ) & 0xFF ] ^ \ + RT3[ ( Y0 >> 24 ) & 0xFF ]; \ +} + +/* + * AES-ECB block encryption + */ +#if !defined(MBEDTLS_AES_ENCRYPT_ALT) +void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; + GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; + GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; + GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; + + for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) + { + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_FROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_FROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y0 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y1 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y2 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) FSb[ ( Y3 ) & 0xFF ] ) ^ + ( (uint32_t) FSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) FSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) FSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + + PUT_UINT32_LE( X0, output, 0 ); + PUT_UINT32_LE( X1, output, 4 ); + PUT_UINT32_LE( X2, output, 8 ); + PUT_UINT32_LE( X3, output, 12 ); +} +#endif /* !MBEDTLS_AES_ENCRYPT_ALT */ + +/* + * AES-ECB block decryption + */ +#if !defined(MBEDTLS_AES_DECRYPT_ALT) +void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ) +{ + int i; + uint32_t *RK, X0, X1, X2, X3, Y0, Y1, Y2, Y3; + + RK = ctx->rk; + + GET_UINT32_LE( X0, input, 0 ); X0 ^= *RK++; + GET_UINT32_LE( X1, input, 4 ); X1 ^= *RK++; + GET_UINT32_LE( X2, input, 8 ); X2 ^= *RK++; + GET_UINT32_LE( X3, input, 12 ); X3 ^= *RK++; + + for( i = ( ctx->nr >> 1 ) - 1; i > 0; i-- ) + { + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + AES_RROUND( X0, X1, X2, X3, Y0, Y1, Y2, Y3 ); + } + + AES_RROUND( Y0, Y1, Y2, Y3, X0, X1, X2, X3 ); + + X0 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y0 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y3 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y2 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y1 >> 24 ) & 0xFF ] << 24 ); + + X1 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y1 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y0 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y3 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y2 >> 24 ) & 0xFF ] << 24 ); + + X2 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y2 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y1 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y0 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y3 >> 24 ) & 0xFF ] << 24 ); + + X3 = *RK++ ^ \ + ( (uint32_t) RSb[ ( Y3 ) & 0xFF ] ) ^ + ( (uint32_t) RSb[ ( Y2 >> 8 ) & 0xFF ] << 8 ) ^ + ( (uint32_t) RSb[ ( Y1 >> 16 ) & 0xFF ] << 16 ) ^ + ( (uint32_t) RSb[ ( Y0 >> 24 ) & 0xFF ] << 24 ); + + PUT_UINT32_LE( X0, output, 0 ); + PUT_UINT32_LE( X1, output, 4 ); + PUT_UINT32_LE( X2, output, 8 ); + PUT_UINT32_LE( X3, output, 12 ); +} +#endif /* !MBEDTLS_AES_DECRYPT_ALT */ + +/* + * AES-ECB block encryption/decryption + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_AES ) ) + return( mbedtls_aesni_crypt_ecb( ctx, mode, input, output ) ); +#endif + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86) + if( aes_padlock_ace ) + { + if( mbedtls_padlock_xcryptecb( ctx, mode, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + if( mode == MBEDTLS_AES_ENCRYPT ) + mbedtls_aes_encrypt( ctx, input, output ); + else + mbedtls_aes_decrypt( ctx, input, output ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * AES-CBC buffer encryption/decryption + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + if( length % 16 ) + return( MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH ); + +#if defined(MBEDTLS_PADLOCK_C) && defined(MBEDTLS_HAVE_X86) + if( aes_padlock_ace ) + { + if( mbedtls_padlock_xcryptcbc( ctx, mode, length, iv, input, output ) == 0 ) + return( 0 ); + + // If padlock data misaligned, we just fall back to + // unaccelerated mode + // + } +#endif + + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + mbedtls_aes_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_aes_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == MBEDTLS_AES_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} + +/* + * AES-CFB8 buffer encryption/decryption + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + unsigned char c; + unsigned char ov[17]; + + while( length-- ) + { + memcpy( ov, iv, 16 ); + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + + if( mode == MBEDTLS_AES_DECRYPT ) + ov[16] = *input; + + c = *output++ = (unsigned char)( iv[0] ^ *input++ ); + + if( mode == MBEDTLS_AES_ENCRYPT ) + ov[16] = c; + + memcpy( iv, ov + 1, 16 ); + } + + return( 0 ); +} +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR buffer encryption/decryption + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + mbedtls_aes_crypt_ecb( ctx, MBEDTLS_AES_ENCRYPT, nonce_counter, stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#endif /* !MBEDTLS_AES_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * AES test vectors from: + * + * http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip + */ +static const unsigned char aes_test_ecb_dec[3][16] = +{ + { 0x44, 0x41, 0x6A, 0xC2, 0xD1, 0xF5, 0x3C, 0x58, + 0x33, 0x03, 0x91, 0x7E, 0x6B, 0xE9, 0xEB, 0xE0 }, + { 0x48, 0xE3, 0x1E, 0x9E, 0x25, 0x67, 0x18, 0xF2, + 0x92, 0x29, 0x31, 0x9C, 0x19, 0xF1, 0x5B, 0xA4 }, + { 0x05, 0x8C, 0xCF, 0xFD, 0xBB, 0xCB, 0x38, 0x2D, + 0x1F, 0x6F, 0x56, 0x58, 0x5D, 0x8A, 0x4A, 0xDE } +}; + +static const unsigned char aes_test_ecb_enc[3][16] = +{ + { 0xC3, 0x4C, 0x05, 0x2C, 0xC0, 0xDA, 0x8D, 0x73, + 0x45, 0x1A, 0xFE, 0x5F, 0x03, 0xBE, 0x29, 0x7F }, + { 0xF3, 0xF6, 0x75, 0x2A, 0xE8, 0xD7, 0x83, 0x11, + 0x38, 0xF0, 0x41, 0x56, 0x06, 0x31, 0xB1, 0x14 }, + { 0x8B, 0x79, 0xEE, 0xCC, 0x93, 0xA0, 0xEE, 0x5D, + 0xFF, 0x30, 0xB4, 0xEA, 0x21, 0x63, 0x6D, 0xA4 } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const unsigned char aes_test_cbc_dec[3][16] = +{ + { 0xFA, 0xCA, 0x37, 0xE0, 0xB0, 0xC8, 0x53, 0x73, + 0xDF, 0x70, 0x6E, 0x73, 0xF7, 0xC9, 0xAF, 0x86 }, + { 0x5D, 0xF6, 0x78, 0xDD, 0x17, 0xBA, 0x4E, 0x75, + 0xB6, 0x17, 0x68, 0xC6, 0xAD, 0xEF, 0x7C, 0x7B }, + { 0x48, 0x04, 0xE1, 0x81, 0x8F, 0xE6, 0x29, 0x75, + 0x19, 0xA3, 0xE8, 0x8C, 0x57, 0x31, 0x04, 0x13 } +}; + +static const unsigned char aes_test_cbc_enc[3][16] = +{ + { 0x8A, 0x05, 0xFC, 0x5E, 0x09, 0x5A, 0xF4, 0x84, + 0x8A, 0x08, 0xD3, 0x28, 0xD3, 0x68, 0x8E, 0x3D }, + { 0x7B, 0xD9, 0x66, 0xD5, 0x3A, 0xD8, 0xC1, 0xBB, + 0x85, 0xD2, 0xAD, 0xFA, 0xE8, 0x7B, 0xB1, 0x04 }, + { 0xFE, 0x3C, 0x53, 0x65, 0x3E, 0x2F, 0x45, 0xB5, + 0x6F, 0xCD, 0x88, 0xB2, 0xCC, 0x89, 0x8F, 0xF0 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * AES-CFB128 test vectors from: + * + * http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf + */ +static const unsigned char aes_test_cfb128_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C }, + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B }, + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char aes_test_cfb128_iv[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F +}; + +static const unsigned char aes_test_cfb128_pt[64] = +{ + 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A, + 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51, + 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF, + 0xF6, 0x9F, 0x24, 0x45, 0xDF, 0x4F, 0x9B, 0x17, + 0xAD, 0x2B, 0x41, 0x7B, 0xE6, 0x6C, 0x37, 0x10 +}; + +static const unsigned char aes_test_cfb128_ct[3][64] = +{ + { 0x3B, 0x3F, 0xD9, 0x2E, 0xB7, 0x2D, 0xAD, 0x20, + 0x33, 0x34, 0x49, 0xF8, 0xE8, 0x3C, 0xFB, 0x4A, + 0xC8, 0xA6, 0x45, 0x37, 0xA0, 0xB3, 0xA9, 0x3F, + 0xCD, 0xE3, 0xCD, 0xAD, 0x9F, 0x1C, 0xE5, 0x8B, + 0x26, 0x75, 0x1F, 0x67, 0xA3, 0xCB, 0xB1, 0x40, + 0xB1, 0x80, 0x8C, 0xF1, 0x87, 0xA4, 0xF4, 0xDF, + 0xC0, 0x4B, 0x05, 0x35, 0x7C, 0x5D, 0x1C, 0x0E, + 0xEA, 0xC4, 0xC6, 0x6F, 0x9F, 0xF7, 0xF2, 0xE6 }, + { 0xCD, 0xC8, 0x0D, 0x6F, 0xDD, 0xF1, 0x8C, 0xAB, + 0x34, 0xC2, 0x59, 0x09, 0xC9, 0x9A, 0x41, 0x74, + 0x67, 0xCE, 0x7F, 0x7F, 0x81, 0x17, 0x36, 0x21, + 0x96, 0x1A, 0x2B, 0x70, 0x17, 0x1D, 0x3D, 0x7A, + 0x2E, 0x1E, 0x8A, 0x1D, 0xD5, 0x9B, 0x88, 0xB1, + 0xC8, 0xE6, 0x0F, 0xED, 0x1E, 0xFA, 0xC4, 0xC9, + 0xC0, 0x5F, 0x9F, 0x9C, 0xA9, 0x83, 0x4F, 0xA0, + 0x42, 0xAE, 0x8F, 0xBA, 0x58, 0x4B, 0x09, 0xFF }, + { 0xDC, 0x7E, 0x84, 0xBF, 0xDA, 0x79, 0x16, 0x4B, + 0x7E, 0xCD, 0x84, 0x86, 0x98, 0x5D, 0x38, 0x60, + 0x39, 0xFF, 0xED, 0x14, 0x3B, 0x28, 0xB1, 0xC8, + 0x32, 0x11, 0x3C, 0x63, 0x31, 0xE5, 0x40, 0x7B, + 0xDF, 0x10, 0x13, 0x24, 0x15, 0xE5, 0x4B, 0x92, + 0xA1, 0x3E, 0xD0, 0xA8, 0x26, 0x7A, 0xE2, 0xF9, + 0x75, 0xA3, 0x85, 0x74, 0x1A, 0xB9, 0xCE, 0xF8, + 0x20, 0x31, 0x62, 0x3D, 0x55, 0xB1, 0xE4, 0x71 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * AES-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc3686.html + */ + +static const unsigned char aes_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char aes_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char aes_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char aes_test_ctr_ct[3][48] = +{ + { 0xE4, 0x09, 0x5D, 0x4F, 0xB7, 0xA7, 0xB3, 0x79, + 0x2D, 0x61, 0x75, 0xA3, 0x26, 0x13, 0x11, 0xB8 }, + { 0x51, 0x04, 0xA1, 0x06, 0x16, 0x8A, 0x72, 0xD9, + 0x79, 0x0D, 0x41, 0xEE, 0x8E, 0xDA, 0xD3, 0x88, + 0xEB, 0x2E, 0x1E, 0xFC, 0x46, 0xDA, 0x57, 0xC8, + 0xFC, 0xE6, 0x30, 0xDF, 0x91, 0x41, 0xBE, 0x28 }, + { 0xC1, 0xCF, 0x48, 0xA8, 0x9F, 0x2F, 0xFD, 0xD9, + 0xCF, 0x46, 0x52, 0xE9, 0xEF, 0xDB, 0x72, 0xD7, + 0x45, 0x40, 0xA4, 0x2B, 0xDE, 0x6D, 0x78, 0x36, + 0xD5, 0x9A, 0x5C, 0xEA, 0xAE, 0xF3, 0x10, 0x53, + 0x25, 0xB2, 0x07, 0x2F } +}; + +static const int aes_test_ctr_len[3] = + { 16, 32, 36 }; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/* + * Checkup routine + */ +int mbedtls_aes_self_test( int verbose ) +{ + int ret = 0, i, j, u, v; + unsigned char key[32]; + unsigned char buf[64]; +#if defined(MBEDTLS_CIPHER_MODE_CBC) || defined(MBEDTLS_CIPHER_MODE_CFB) + unsigned char iv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char prv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) || defined(MBEDTLS_CIPHER_MODE_CFB) + size_t offset; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + int len; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + mbedtls_aes_context ctx; + + memset( key, 0, 32 ); + mbedtls_aes_init( &ctx ); + + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-ECB-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( buf, 0, 16 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + mbedtls_aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + mbedtls_aes_crypt_ecb( &ctx, v, buf, buf ); + + if( memcmp( buf, aes_test_ecb_enc[u], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CBC-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memset( iv , 0, 16 ); + memset( prv, 0, 16 ); + memset( buf, 0, 16 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + mbedtls_aes_setkey_dec( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + if( memcmp( buf, aes_test_cbc_dec[u], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[16]; + + mbedtls_aes_crypt_cbc( &ctx, v, 16, iv, buf, buf ); + + memcpy( tmp, prv, 16 ); + memcpy( prv, buf, 16 ); + memcpy( buf, tmp, 16 ); + } + + if( memcmp( prv, aes_test_cbc_enc[u], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + /* + * CFB128 mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CFB128-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, aes_test_cfb128_iv, 16 ); + memcpy( key, aes_test_cfb128_key[u], 16 + u * 8 ); + + offset = 0; + mbedtls_aes_setkey_enc( &ctx, key, 128 + u * 64 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + memcpy( buf, aes_test_cfb128_ct[u], 64 ); + mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_pt, 64 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + memcpy( buf, aes_test_cfb128_pt, 64 ); + mbedtls_aes_crypt_cfb128( &ctx, v, 64, &offset, iv, buf, buf ); + + if( memcmp( buf, aes_test_cfb128_ct[u], 64 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " AES-CTR-128 (%s): ", + ( v == MBEDTLS_AES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( nonce_counter, aes_test_ctr_nonce_counter[u], 16 ); + memcpy( key, aes_test_ctr_key[u], 16 ); + + offset = 0; + mbedtls_aes_setkey_enc( &ctx, key, 128 ); + + if( v == MBEDTLS_AES_DECRYPT ) + { + len = aes_test_ctr_len[u]; + memcpy( buf, aes_test_ctr_ct[u], len ); + + mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, aes_test_ctr_pt[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + else + { + len = aes_test_ctr_len[u]; + memcpy( buf, aes_test_ctr_pt[u], len ); + + mbedtls_aes_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, aes_test_ctr_ct[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + + ret = 0; + +exit: + mbedtls_aes_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_AES_C */ diff --git a/c++/src/connect/mbedtls/aesni.c b/c++/src/connect/mbedtls/aesni.c new file mode 100644 index 00000000..1ca3c3ef --- /dev/null +++ b/c++/src/connect/mbedtls/aesni.c @@ -0,0 +1,464 @@ +/* + * AES-NI support functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * [AES-WP] http://software.intel.com/en-us/articles/intel-advanced-encryption-standard-aes-instructions-set + * [CLMUL-WP] http://software.intel.com/en-us/articles/intel-carry-less-multiplication-instruction-and-its-usage-for-computing-the-gcm-mode/ + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_AESNI_C) + +#include "mbedtls/aesni.h" + +#include + +#ifndef asm +#define asm __asm +#endif + +#if defined(MBEDTLS_HAVE_X86_64) + +/* + * AES-NI support detection routine + */ +int mbedtls_aesni_has_support( unsigned int what ) +{ + static int done = 0; + static unsigned int c = 0; + + if( ! done ) + { + asm( "movl $1, %%eax \n\t" + "cpuid \n\t" + : "=c" (c) + : + : "eax", "ebx", "edx" ); + done = 1; + } + + return( ( c & what ) != 0 ); +} + +/* + * Binutils needs to be at least 2.19 to support AES-NI instructions. + * Unfortunately, a lot of users have a lower version now (2014-04). + * Emit bytecode directly in order to support "old" version of gas. + * + * Opcodes from the Intel architecture reference manual, vol. 3. + * We always use registers, so we don't need prefixes for memory operands. + * Operand macros are in gas order (src, dst) as opposed to Intel order + * (dst, src) in order to blend better into the surrounding assembly code. + */ +#define AESDEC ".byte 0x66,0x0F,0x38,0xDE," +#define AESDECLAST ".byte 0x66,0x0F,0x38,0xDF," +#define AESENC ".byte 0x66,0x0F,0x38,0xDC," +#define AESENCLAST ".byte 0x66,0x0F,0x38,0xDD," +#define AESIMC ".byte 0x66,0x0F,0x38,0xDB," +#define AESKEYGENA ".byte 0x66,0x0F,0x3A,0xDF," +#define PCLMULQDQ ".byte 0x66,0x0F,0x3A,0x44," + +#define xmm0_xmm0 "0xC0" +#define xmm0_xmm1 "0xC8" +#define xmm0_xmm2 "0xD0" +#define xmm0_xmm3 "0xD8" +#define xmm0_xmm4 "0xE0" +#define xmm1_xmm0 "0xC1" +#define xmm1_xmm2 "0xD1" + +/* + * AES-NI AES-ECB block en(de)cryption + */ +int mbedtls_aesni_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + asm( "movdqu (%3), %%xmm0 \n\t" // load input + "movdqu (%1), %%xmm1 \n\t" // load round key 0 + "pxor %%xmm1, %%xmm0 \n\t" // round 0 + "add $16, %1 \n\t" // point to next round key + "subl $1, %0 \n\t" // normal rounds = nr - 1 + "test %2, %2 \n\t" // mode? + "jz 2f \n\t" // 0 = decrypt + + "1: \n\t" // encryption loop + "movdqu (%1), %%xmm1 \n\t" // load round key + AESENC xmm1_xmm0 "\n\t" // do round + "add $16, %1 \n\t" // point to next round key + "subl $1, %0 \n\t" // loop + "jnz 1b \n\t" + "movdqu (%1), %%xmm1 \n\t" // load round key + AESENCLAST xmm1_xmm0 "\n\t" // last round + "jmp 3f \n\t" + + "2: \n\t" // decryption loop + "movdqu (%1), %%xmm1 \n\t" + AESDEC xmm1_xmm0 "\n\t" // do round + "add $16, %1 \n\t" + "subl $1, %0 \n\t" + "jnz 2b \n\t" + "movdqu (%1), %%xmm1 \n\t" // load round key + AESDECLAST xmm1_xmm0 "\n\t" // last round + + "3: \n\t" + "movdqu %%xmm0, (%4) \n\t" // export output + : + : "r" (ctx->nr), "r" (ctx->rk), "r" (mode), "r" (input), "r" (output) + : "memory", "cc", "xmm0", "xmm1" ); + + + return( 0 ); +} + +/* + * GCM multiplication: c = a times b in GF(2^128) + * Based on [CLMUL-WP] algorithms 1 (with equation 27) and 5. + */ +void mbedtls_aesni_gcm_mult( unsigned char c[16], + const unsigned char a[16], + const unsigned char b[16] ) +{ + unsigned char aa[16], bb[16], cc[16]; + size_t i; + + /* The inputs are in big-endian order, so byte-reverse them */ + for( i = 0; i < 16; i++ ) + { + aa[i] = a[15 - i]; + bb[i] = b[15 - i]; + } + + asm( "movdqu (%0), %%xmm0 \n\t" // a1:a0 + "movdqu (%1), %%xmm1 \n\t" // b1:b0 + + /* + * Caryless multiplication xmm2:xmm1 = xmm0 * xmm1 + * using [CLMUL-WP] algorithm 1 (p. 13). + */ + "movdqa %%xmm1, %%xmm2 \n\t" // copy of b1:b0 + "movdqa %%xmm1, %%xmm3 \n\t" // same + "movdqa %%xmm1, %%xmm4 \n\t" // same + PCLMULQDQ xmm0_xmm1 ",0x00 \n\t" // a0*b0 = c1:c0 + PCLMULQDQ xmm0_xmm2 ",0x11 \n\t" // a1*b1 = d1:d0 + PCLMULQDQ xmm0_xmm3 ",0x10 \n\t" // a0*b1 = e1:e0 + PCLMULQDQ xmm0_xmm4 ",0x01 \n\t" // a1*b0 = f1:f0 + "pxor %%xmm3, %%xmm4 \n\t" // e1+f1:e0+f0 + "movdqa %%xmm4, %%xmm3 \n\t" // same + "psrldq $8, %%xmm4 \n\t" // 0:e1+f1 + "pslldq $8, %%xmm3 \n\t" // e0+f0:0 + "pxor %%xmm4, %%xmm2 \n\t" // d1:d0+e1+f1 + "pxor %%xmm3, %%xmm1 \n\t" // c1+e0+f1:c0 + + /* + * Now shift the result one bit to the left, + * taking advantage of [CLMUL-WP] eq 27 (p. 20) + */ + "movdqa %%xmm1, %%xmm3 \n\t" // r1:r0 + "movdqa %%xmm2, %%xmm4 \n\t" // r3:r2 + "psllq $1, %%xmm1 \n\t" // r1<<1:r0<<1 + "psllq $1, %%xmm2 \n\t" // r3<<1:r2<<1 + "psrlq $63, %%xmm3 \n\t" // r1>>63:r0>>63 + "psrlq $63, %%xmm4 \n\t" // r3>>63:r2>>63 + "movdqa %%xmm3, %%xmm5 \n\t" // r1>>63:r0>>63 + "pslldq $8, %%xmm3 \n\t" // r0>>63:0 + "pslldq $8, %%xmm4 \n\t" // r2>>63:0 + "psrldq $8, %%xmm5 \n\t" // 0:r1>>63 + "por %%xmm3, %%xmm1 \n\t" // r1<<1|r0>>63:r0<<1 + "por %%xmm4, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1 + "por %%xmm5, %%xmm2 \n\t" // r3<<1|r2>>62:r2<<1|r1>>63 + + /* + * Now reduce modulo the GCM polynomial x^128 + x^7 + x^2 + x + 1 + * using [CLMUL-WP] algorithm 5 (p. 20). + * Currently xmm2:xmm1 holds x3:x2:x1:x0 (already shifted). + */ + /* Step 2 (1) */ + "movdqa %%xmm1, %%xmm3 \n\t" // x1:x0 + "movdqa %%xmm1, %%xmm4 \n\t" // same + "movdqa %%xmm1, %%xmm5 \n\t" // same + "psllq $63, %%xmm3 \n\t" // x1<<63:x0<<63 = stuff:a + "psllq $62, %%xmm4 \n\t" // x1<<62:x0<<62 = stuff:b + "psllq $57, %%xmm5 \n\t" // x1<<57:x0<<57 = stuff:c + + /* Step 2 (2) */ + "pxor %%xmm4, %%xmm3 \n\t" // stuff:a+b + "pxor %%xmm5, %%xmm3 \n\t" // stuff:a+b+c + "pslldq $8, %%xmm3 \n\t" // a+b+c:0 + "pxor %%xmm3, %%xmm1 \n\t" // x1+a+b+c:x0 = d:x0 + + /* Steps 3 and 4 */ + "movdqa %%xmm1,%%xmm0 \n\t" // d:x0 + "movdqa %%xmm1,%%xmm4 \n\t" // same + "movdqa %%xmm1,%%xmm5 \n\t" // same + "psrlq $1, %%xmm0 \n\t" // e1:x0>>1 = e1:e0' + "psrlq $2, %%xmm4 \n\t" // f1:x0>>2 = f1:f0' + "psrlq $7, %%xmm5 \n\t" // g1:x0>>7 = g1:g0' + "pxor %%xmm4, %%xmm0 \n\t" // e1+f1:e0'+f0' + "pxor %%xmm5, %%xmm0 \n\t" // e1+f1+g1:e0'+f0'+g0' + // e0'+f0'+g0' is almost e0+f0+g0, ex\tcept for some missing + // bits carried from d. Now get those\t bits back in. + "movdqa %%xmm1,%%xmm3 \n\t" // d:x0 + "movdqa %%xmm1,%%xmm4 \n\t" // same + "movdqa %%xmm1,%%xmm5 \n\t" // same + "psllq $63, %%xmm3 \n\t" // d<<63:stuff + "psllq $62, %%xmm4 \n\t" // d<<62:stuff + "psllq $57, %%xmm5 \n\t" // d<<57:stuff + "pxor %%xmm4, %%xmm3 \n\t" // d<<63+d<<62:stuff + "pxor %%xmm5, %%xmm3 \n\t" // missing bits of d:stuff + "psrldq $8, %%xmm3 \n\t" // 0:missing bits of d + "pxor %%xmm3, %%xmm0 \n\t" // e1+f1+g1:e0+f0+g0 + "pxor %%xmm1, %%xmm0 \n\t" // h1:h0 + "pxor %%xmm2, %%xmm0 \n\t" // x3+h1:x2+h0 + + "movdqu %%xmm0, (%2) \n\t" // done + : + : "r" (aa), "r" (bb), "r" (cc) + : "memory", "cc", "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5" ); + + /* Now byte-reverse the outputs */ + for( i = 0; i < 16; i++ ) + c[i] = cc[15 - i]; + + return; +} + +/* + * Compute decryption round keys from encryption round keys + */ +void mbedtls_aesni_inverse_key( unsigned char *invkey, + const unsigned char *fwdkey, int nr ) +{ + unsigned char *ik = invkey; + const unsigned char *fk = fwdkey + 16 * nr; + + memcpy( ik, fk, 16 ); + + for( fk -= 16, ik += 16; fk > fwdkey; fk -= 16, ik += 16 ) + asm( "movdqu (%0), %%xmm0 \n\t" + AESIMC xmm0_xmm0 "\n\t" + "movdqu %%xmm0, (%1) \n\t" + : + : "r" (fk), "r" (ik) + : "memory", "xmm0" ); + + memcpy( ik, fk, 16 ); +} + +/* + * Key expansion, 128-bit case + */ +static void aesni_setkey_enc_128( unsigned char *rk, + const unsigned char *key ) +{ + asm( "movdqu (%1), %%xmm0 \n\t" // copy the original key + "movdqu %%xmm0, (%0) \n\t" // as round key 0 + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next round key. + * + * On entry xmm0 is r3:r2:r1:r0 and xmm1 is X:stuff:stuff:stuff + * with X = rot( sub( r3 ) ) ^ RCON. + * + * On exit, xmm0 is r7:r6:r5:r4 + * with r4 = X + r0, r5 = r4 + r1, r6 = r5 + r2, r7 = r6 + r3 + * and those are written to the round key buffer. + */ + "1: \n\t" + "pshufd $0xff, %%xmm1, %%xmm1 \n\t" // X:X:X:X + "pxor %%xmm0, %%xmm1 \n\t" // X+r3:X+r2:X+r1:r4 + "pslldq $4, %%xmm0 \n\t" // r2:r1:r0:0 + "pxor %%xmm0, %%xmm1 \n\t" // X+r3+r2:X+r2+r1:r5:r4 + "pslldq $4, %%xmm0 \n\t" // etc + "pxor %%xmm0, %%xmm1 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm1, %%xmm0 \n\t" // update xmm0 for next time! + "add $16, %0 \n\t" // point to next round key + "movdqu %%xmm0, (%0) \n\t" // write it + "ret \n\t" + + /* Main "loop" */ + "2: \n\t" + AESKEYGENA xmm0_xmm1 ",0x01 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x02 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x04 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x08 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x10 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x20 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x40 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x80 \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x1B \n\tcall 1b \n\t" + AESKEYGENA xmm0_xmm1 ",0x36 \n\tcall 1b \n\t" + : + : "r" (rk), "r" (key) + : "memory", "cc", "0" ); +} + +/* + * Key expansion, 192-bit case + */ +static void aesni_setkey_enc_192( unsigned char *rk, + const unsigned char *key ) +{ + asm( "movdqu (%1), %%xmm0 \n\t" // copy original round key + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "movq 16(%1), %%xmm1 \n\t" + "movq %%xmm1, (%0) \n\t" + "add $8, %0 \n\t" + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next 6 quarter-keys. + * + * On entry xmm0 is r3:r2:r1:r0, xmm1 is stuff:stuff:r5:r4 + * and xmm2 is stuff:stuff:X:stuff with X = rot( sub( r3 ) ) ^ RCON. + * + * On exit, xmm0 is r9:r8:r7:r6 and xmm1 is stuff:stuff:r11:r10 + * and those are written to the round key buffer. + */ + "1: \n\t" + "pshufd $0x55, %%xmm2, %%xmm2 \n\t" // X:X:X:X + "pxor %%xmm0, %%xmm2 \n\t" // X+r3:X+r2:X+r1:r4 + "pslldq $4, %%xmm0 \n\t" // etc + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm2, %%xmm0 \n\t" // update xmm0 = r9:r8:r7:r6 + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "pshufd $0xff, %%xmm0, %%xmm2 \n\t" // r9:r9:r9:r9 + "pxor %%xmm1, %%xmm2 \n\t" // stuff:stuff:r9+r5:r10 + "pslldq $4, %%xmm1 \n\t" // r2:r1:r0:0 + "pxor %%xmm2, %%xmm1 \n\t" // xmm1 = stuff:stuff:r11:r10 + "movq %%xmm1, (%0) \n\t" + "add $8, %0 \n\t" + "ret \n\t" + + "2: \n\t" + AESKEYGENA xmm1_xmm2 ",0x01 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x02 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x04 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x08 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x10 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x20 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x40 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x80 \n\tcall 1b \n\t" + + : + : "r" (rk), "r" (key) + : "memory", "cc", "0" ); +} + +/* + * Key expansion, 256-bit case + */ +static void aesni_setkey_enc_256( unsigned char *rk, + const unsigned char *key ) +{ + asm( "movdqu (%1), %%xmm0 \n\t" + "movdqu %%xmm0, (%0) \n\t" + "add $16, %0 \n\t" + "movdqu 16(%1), %%xmm1 \n\t" + "movdqu %%xmm1, (%0) \n\t" + "jmp 2f \n\t" // skip auxiliary routine + + /* + * Finish generating the next two round keys. + * + * On entry xmm0 is r3:r2:r1:r0, xmm1 is r7:r6:r5:r4 and + * xmm2 is X:stuff:stuff:stuff with X = rot( sub( r7 )) ^ RCON + * + * On exit, xmm0 is r11:r10:r9:r8 and xmm1 is r15:r14:r13:r12 + * and those have been written to the output buffer. + */ + "1: \n\t" + "pshufd $0xff, %%xmm2, %%xmm2 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm0, %%xmm2 \n\t" + "pslldq $4, %%xmm0 \n\t" + "pxor %%xmm2, %%xmm0 \n\t" + "add $16, %0 \n\t" + "movdqu %%xmm0, (%0) \n\t" + + /* Set xmm2 to stuff:Y:stuff:stuff with Y = subword( r11 ) + * and proceed to generate next round key from there */ + AESKEYGENA xmm0_xmm2 ",0x00 \n\t" + "pshufd $0xaa, %%xmm2, %%xmm2 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm1, %%xmm2 \n\t" + "pslldq $4, %%xmm1 \n\t" + "pxor %%xmm2, %%xmm1 \n\t" + "add $16, %0 \n\t" + "movdqu %%xmm1, (%0) \n\t" + "ret \n\t" + + /* + * Main "loop" - Generating one more key than necessary, + * see definition of mbedtls_aes_context.buf + */ + "2: \n\t" + AESKEYGENA xmm1_xmm2 ",0x01 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x02 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x04 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x08 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x10 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x20 \n\tcall 1b \n\t" + AESKEYGENA xmm1_xmm2 ",0x40 \n\tcall 1b \n\t" + : + : "r" (rk), "r" (key) + : "memory", "cc", "0" ); +} + +/* + * Key expansion, wrapper + */ +int mbedtls_aesni_setkey_enc( unsigned char *rk, + const unsigned char *key, + size_t bits ) +{ + switch( bits ) + { + case 128: aesni_setkey_enc_128( rk, key ); break; + case 192: aesni_setkey_enc_192( rk, key ); break; + case 256: aesni_setkey_enc_256( rk, key ); break; + default : return( MBEDTLS_ERR_AES_INVALID_KEY_LENGTH ); + } + + return( 0 ); +} + +#endif /* MBEDTLS_HAVE_X86_64 */ + +#endif /* MBEDTLS_AESNI_C */ diff --git a/c++/src/connect/mbedtls/apache-2.0.txt b/c++/src/connect/mbedtls/apache-2.0.txt new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/c++/src/connect/mbedtls/apache-2.0.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/c++/src/connect/mbedtls/arc4.c b/c++/src/connect/mbedtls/arc4.c new file mode 100644 index 00000000..05b33d3f --- /dev/null +++ b/c++/src/connect/mbedtls/arc4.c @@ -0,0 +1,205 @@ +/* + * An implementation of the ARCFOUR algorithm + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ARCFOUR algorithm was publicly disclosed on 94/09. + * + * http://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ARC4_C) + +#include "mbedtls/arc4.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_ARC4_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +void mbedtls_arc4_init( mbedtls_arc4_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_arc4_context ) ); +} + +void mbedtls_arc4_free( mbedtls_arc4_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_arc4_context ) ); +} + +/* + * ARC4 key schedule + */ +void mbedtls_arc4_setup( mbedtls_arc4_context *ctx, const unsigned char *key, + unsigned int keylen ) +{ + int i, j, a; + unsigned int k; + unsigned char *m; + + ctx->x = 0; + ctx->y = 0; + m = ctx->m; + + for( i = 0; i < 256; i++ ) + m[i] = (unsigned char) i; + + j = k = 0; + + for( i = 0; i < 256; i++, k++ ) + { + if( k >= keylen ) k = 0; + + a = m[i]; + j = ( j + a + key[k] ) & 0xFF; + m[i] = m[j]; + m[j] = (unsigned char) a; + } +} + +/* + * ARC4 cipher function + */ +int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ) +{ + int x, y, a, b; + size_t i; + unsigned char *m; + + x = ctx->x; + y = ctx->y; + m = ctx->m; + + for( i = 0; i < length; i++ ) + { + x = ( x + 1 ) & 0xFF; a = m[x]; + y = ( y + a ) & 0xFF; b = m[y]; + + m[x] = (unsigned char) b; + m[y] = (unsigned char) a; + + output[i] = (unsigned char) + ( input[i] ^ m[(unsigned char)( a + b )] ); + } + + ctx->x = x; + ctx->y = y; + + return( 0 ); +} + +#endif /* !MBEDTLS_ARC4_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * ARC4 tests vectors as posted by Eric Rescorla in sep. 1994: + * + * http://groups.google.com/group/comp.security.misc/msg/10a300c9d21afca0 + */ +static const unsigned char arc4_test_key[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_pt[3][8] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char arc4_test_ct[3][8] = +{ + { 0x75, 0xB7, 0x87, 0x80, 0x99, 0xE0, 0xC5, 0x96 }, + { 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 }, + { 0xDE, 0x18, 0x89, 0x41, 0xA3, 0x37, 0x5D, 0x3A } +}; + +/* + * Checkup routine + */ +int mbedtls_arc4_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char ibuf[8]; + unsigned char obuf[8]; + mbedtls_arc4_context ctx; + + mbedtls_arc4_init( &ctx ); + + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " ARC4 test #%d: ", i + 1 ); + + memcpy( ibuf, arc4_test_pt[i], 8 ); + + mbedtls_arc4_setup( &ctx, arc4_test_key[i], 8 ); + mbedtls_arc4_crypt( &ctx, 8, ibuf, obuf ); + + if( memcmp( obuf, arc4_test_ct[i], 8 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_arc4_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ARC4_C */ diff --git a/c++/src/connect/mbedtls/asn1parse.c b/c++/src/connect/mbedtls/asn1parse.c new file mode 100644 index 00000000..4dd65c03 --- /dev/null +++ b/c++/src/connect/mbedtls/asn1parse.c @@ -0,0 +1,393 @@ +/* + * Generic ASN.1 parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) + +#include "mbedtls/asn1.h" + +#include + +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/bignum.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * ASN.1 DER decoding routines + */ +int mbedtls_asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ) +{ + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( ( **p & 0x80 ) == 0 ) + *len = *(*p)++; + else + { + switch( **p & 0x7F ) + { + case 1: + if( ( end - *p ) < 2 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = (*p)[1]; + (*p) += 2; + break; + + case 2: + if( ( end - *p ) < 3 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 8 ) | (*p)[2]; + (*p) += 3; + break; + + case 3: + if( ( end - *p ) < 4 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 16 ) | + ( (size_t)(*p)[2] << 8 ) | (*p)[3]; + (*p) += 4; + break; + + case 4: + if( ( end - *p ) < 5 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + *len = ( (size_t)(*p)[1] << 24 ) | ( (size_t)(*p)[2] << 16 ) | + ( (size_t)(*p)[3] << 8 ) | (*p)[4]; + (*p) += 5; + break; + + default: + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + } + } + + if( *len > (size_t) ( end - *p ) ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + return( 0 ); +} + +int mbedtls_asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ) +{ + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != tag ) + return( MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + (*p)++; + + return( mbedtls_asn1_get_len( p, end, len ) ); +} + +int mbedtls_asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_BOOLEAN ) ) != 0 ) + return( ret ); + + if( len != 1 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + *val = ( **p != 0 ) ? 1 : 0; + (*p)++; + + return( 0 ); +} + +int mbedtls_asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( ret ); + + if( len == 0 || len > sizeof( int ) || ( **p & 0x80 ) != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + *val = 0; + + while( len-- > 0 ) + { + *val = ( *val << 8 ) | **p; + (*p)++; + } + + return( 0 ); +} + +#if defined(MBEDTLS_BIGNUM_C) +int mbedtls_asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mbedtls_mpi *X ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, MBEDTLS_ASN1_INTEGER ) ) != 0 ) + return( ret ); + + ret = mbedtls_mpi_read_binary( X, *p, len ); + + *p += len; + + return( ret ); +} +#endif /* MBEDTLS_BIGNUM_C */ + +int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end, + mbedtls_asn1_bitstring *bs) +{ + int ret; + + /* Certificate type is a single byte bitstring */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &bs->len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 ) + return( ret ); + + /* Check length, subtract one for actual bit string length */ + if( bs->len < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + bs->len -= 1; + + /* Get number of unused bits, ensure unused bits <= 7 */ + bs->unused_bits = **p; + if( bs->unused_bits > 7 ) + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + (*p)++; + + /* Get actual bitstring */ + bs->p = *p; + *p += bs->len; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Get a bit string without unused bits + */ +int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end, + size_t *len ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_tag( p, end, len, MBEDTLS_ASN1_BIT_STRING ) ) != 0 ) + return( ret ); + + if( (*len)-- < 2 || *(*p)++ != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_DATA ); + + return( 0 ); +} + + + +/* + * Parses and splits an ASN.1 "SEQUENCE OF " + */ +int mbedtls_asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_sequence *cur, + int tag) +{ + int ret; + size_t len; + mbedtls_asn1_buf *buf; + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + buf = &(cur->buf); + buf->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &buf->len, tag ) ) != 0 ) + return( ret ); + + buf->p = *p; + *p += buf->len; + + /* Allocate and assign next pointer */ + if( *p < end ) + { + cur->next = (mbedtls_asn1_sequence*)mbedtls_calloc( 1, + sizeof( mbedtls_asn1_sequence ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_asn1_get_alg( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + alg->tag = **p; + end = *p + len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &alg->len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( ret ); + + alg->p = *p; + *p += alg->len; + + if( *p == end ) + { + mbedtls_zeroize( params, sizeof(mbedtls_asn1_buf) ); + return( 0 ); + } + + params->tag = **p; + (*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, ¶ms->len ) ) != 0 ) + return( ret ); + + params->p = *p; + *p += params->len; + + if( *p != end ) + return( MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_asn1_get_alg_null( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg ) +{ + int ret; + mbedtls_asn1_buf params; + + memset( ¶ms, 0, sizeof(mbedtls_asn1_buf) ); + + if( ( ret = mbedtls_asn1_get_alg( p, end, alg, ¶ms ) ) != 0 ) + return( ret ); + + if( ( params.tag != MBEDTLS_ASN1_NULL && params.tag != 0 ) || params.len != 0 ) + return( MBEDTLS_ERR_ASN1_INVALID_DATA ); + + return( 0 ); +} + +void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *cur ) +{ + if( cur == NULL ) + return; + + mbedtls_free( cur->oid.p ); + mbedtls_free( cur->val.p ); + + mbedtls_zeroize( cur, sizeof( mbedtls_asn1_named_data ) ); +} + +void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head ) +{ + mbedtls_asn1_named_data *cur; + + while( ( cur = *head ) != NULL ) + { + *head = cur->next; + mbedtls_asn1_free_named_data( cur ); + mbedtls_free( cur ); + } +} + +mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list, + const char *oid, size_t len ) +{ + while( list != NULL ) + { + if( list->oid.len == len && + memcmp( list->oid.p, oid, len ) == 0 ) + { + break; + } + + list = list->next; + } + + return( list ); +} + +#endif /* MBEDTLS_ASN1_PARSE_C */ diff --git a/c++/src/connect/mbedtls/asn1write.c b/c++/src/connect/mbedtls/asn1write.c new file mode 100644 index 00000000..69b61b20 --- /dev/null +++ b/c++/src/connect/mbedtls/asn1write.c @@ -0,0 +1,390 @@ +/* + * ASN.1 buffer writing functionality + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ASN1_WRITE_C) + +#include "mbedtls/asn1write.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len ) +{ + if( len < 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (unsigned char) len; + return( 1 ); + } + + if( len <= 0xFF ) + { + if( *p - start < 2 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (unsigned char) len; + *--(*p) = 0x81; + return( 2 ); + } + + if( len <= 0xFFFF ) + { + if( *p - start < 3 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = ( len ) & 0xFF; + *--(*p) = ( len >> 8 ) & 0xFF; + *--(*p) = 0x82; + return( 3 ); + } + + if( len <= 0xFFFFFF ) + { + if( *p - start < 4 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = ( len ) & 0xFF; + *--(*p) = ( len >> 8 ) & 0xFF; + *--(*p) = ( len >> 16 ) & 0xFF; + *--(*p) = 0x83; + return( 4 ); + } + + if( len <= 0xFFFFFFFF ) + { + if( *p - start < 5 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = ( len ) & 0xFF; + *--(*p) = ( len >> 8 ) & 0xFF; + *--(*p) = ( len >> 16 ) & 0xFF; + *--(*p) = ( len >> 24 ) & 0xFF; + *--(*p) = 0x84; + return( 5 ); + } + + return( MBEDTLS_ERR_ASN1_INVALID_LENGTH ); +} + +int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, unsigned char tag ) +{ + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = tag; + + return( 1 ); +} + +int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ) +{ + size_t len = 0; + + if( *p < start || (size_t)( *p - start ) < size ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = size; + (*p) -= len; + memcpy( *p, buf, len ); + + return( (int) len ); +} + +#if defined(MBEDTLS_BIGNUM_C) +int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X ) +{ + int ret; + size_t len = 0; + + // Write the MPI + // + len = mbedtls_mpi_size( X ); + + if( *p < start || (size_t)( *p - start ) < len ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + (*p) -= len; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, *p, len ) ); + + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + if( X->s ==1 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) ); + + ret = (int) len; + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_BIGNUM_C */ + +int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start ) +{ + int ret; + size_t len = 0; + + // Write NULL + // + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, 0) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_NULL ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) oid, oid_len ) ); + MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len , mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + size_t par_len ) +{ + int ret; + size_t len = 0; + + if( par_len == 0 ) + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_null( p, start ) ); + else + len += par_len; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean ) +{ + int ret; + size_t len = 0; + + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = (boolean) ? 255 : 0; + len++; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BOOLEAN ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ) +{ + int ret; + size_t len = 0; + + // TODO negative values and values larger than 128 + // DER format assumes 2s complement for numbers, so the leftmost bit + // should be 0 for positive numbers and 1 for negative numbers. + // + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len += 1; + *--(*p) = val; + + if( val > 0 && **p & 0x80 ) + { + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0x00; + len += 1; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_INTEGER ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) text, text_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_PRINTABLE_STRING ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) text, text_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_IA5_STRING ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t bits ) +{ + int ret; + size_t len = 0, size; + + size = ( bits / 8 ) + ( ( bits % 8 ) ? 1 : 0 ); + + // Calculate byte length + // + if( *p < start || (size_t)( *p - start ) < size + 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = size + 1; + (*p) -= size; + memcpy( *p, buf, size ); + + // Write unused bits + // + *--(*p) = (unsigned char) (size * 8 - bits); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) ); + + return( (int) len ); +} + +int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, buf, size ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) ); + + return( (int) len ); +} + +mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **head, + const char *oid, size_t oid_len, + const unsigned char *val, + size_t val_len ) +{ + mbedtls_asn1_named_data *cur; + + if( ( cur = mbedtls_asn1_find_named_data( *head, oid, oid_len ) ) == NULL ) + { + // Add new entry if not present yet based on OID + // + cur = (mbedtls_asn1_named_data*)mbedtls_calloc( 1, + sizeof(mbedtls_asn1_named_data) ); + if( cur == NULL ) + return( NULL ); + + cur->oid.len = oid_len; + cur->oid.p = mbedtls_calloc( 1, oid_len ); + if( cur->oid.p == NULL ) + { + mbedtls_free( cur ); + return( NULL ); + } + + memcpy( cur->oid.p, oid, oid_len ); + + cur->val.len = val_len; + cur->val.p = mbedtls_calloc( 1, val_len ); + if( cur->val.p == NULL ) + { + mbedtls_free( cur->oid.p ); + mbedtls_free( cur ); + return( NULL ); + } + + cur->next = *head; + *head = cur; + } + else if( cur->val.len < val_len ) + { + /* + * Enlarge existing value buffer if needed + * Preserve old data until the allocation succeeded, to leave list in + * a consistent state in case allocation fails. + */ + void *p = mbedtls_calloc( 1, val_len ); + if( p == NULL ) + return( NULL ); + + mbedtls_free( cur->val.p ); + cur->val.p = p; + cur->val.len = val_len; + } + + if( val != NULL ) + memcpy( cur->val.p, val, val_len ); + + return( cur ); +} +#endif /* MBEDTLS_ASN1_WRITE_C */ diff --git a/c++/src/connect/mbedtls/base64.c b/c++/src/connect/mbedtls/base64.c new file mode 100644 index 00000000..f06b57b3 --- /dev/null +++ b/c++/src/connect/mbedtls/base64.c @@ -0,0 +1,293 @@ +/* + * RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BASE64_C) + +#include "mbedtls/base64.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#include +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +static const unsigned char base64_enc_map[64] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', + 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', + 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '+', '/' +}; + +static const unsigned char base64_dec_map[128] = +{ + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, + 127, 127, 127, 62, 127, 127, 127, 63, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 127, 127, + 127, 64, 127, 127, 127, 0, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 127, 127, 127, 127, 127, 127, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 127, 127, 127, 127, 127 +}; + +#define BASE64_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ + +/* + * Encode a buffer into base64 format + */ +int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ) +{ + size_t i, n; + int C1, C2, C3; + unsigned char *p; + + if( slen == 0 ) + { + *olen = 0; + return( 0 ); + } + + n = slen / 3 + ( slen % 3 != 0 ); + + if( n > ( BASE64_SIZE_T_MAX - 1 ) / 4 ) + { + *olen = BASE64_SIZE_T_MAX; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + n *= 4; + + if( ( dlen < n + 1 ) || ( NULL == dst ) ) + { + *olen = n + 1; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + n = ( slen / 3 ) * 3; + + for( i = 0, p = dst; i < n; i += 3 ) + { + C1 = *src++; + C2 = *src++; + C3 = *src++; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F]; + *p++ = base64_enc_map[C3 & 0x3F]; + } + + if( i < slen ) + { + C1 = *src++; + C2 = ( ( i + 1 ) < slen ) ? *src++ : 0; + + *p++ = base64_enc_map[(C1 >> 2) & 0x3F]; + *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F]; + + if( ( i + 1 ) < slen ) + *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F]; + else *p++ = '='; + + *p++ = '='; + } + + *olen = p - dst; + *p = 0; + + return( 0 ); +} + +/* + * Decode a base64-formatted buffer + */ +int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ) +{ + size_t i, n; + uint32_t j, x; + unsigned char *p; + + /* First pass: check for validity and get output length */ + for( i = n = j = 0; i < slen; i++ ) + { + /* Skip spaces before checking for EOL */ + x = 0; + while( i < slen && src[i] == ' ' ) + { + ++i; + ++x; + } + + /* Spaces at end of buffer are OK */ + if( i == slen ) + break; + + if( ( slen - i ) >= 2 && + src[i] == '\r' && src[i + 1] == '\n' ) + continue; + + if( src[i] == '\n' ) + continue; + + /* Space inside a line is an error */ + if( x != 0 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] == '=' && ++j > 2 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( src[i] > 127 || base64_dec_map[src[i]] == 127 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + if( base64_dec_map[src[i]] < 64 && j != 0 ) + return( MBEDTLS_ERR_BASE64_INVALID_CHARACTER ); + + n++; + } + + if( n == 0 ) + { + *olen = 0; + return( 0 ); + } + + /* The following expression is to calculate the following formula without + * risk of integer overflow in n: + * n = ( ( n * 6 ) + 7 ) >> 3; + */ + n = ( 6 * ( n >> 3 ) ) + ( ( 6 * ( n & 0x7 ) + 7 ) >> 3 ); + n -= j; + + if( dst == NULL || dlen < n ) + { + *olen = n; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ ) + { + if( *src == '\r' || *src == '\n' || *src == ' ' ) + continue; + + j -= ( base64_dec_map[*src] == 64 ); + x = ( x << 6 ) | ( base64_dec_map[*src] & 0x3F ); + + if( ++n == 4 ) + { + n = 0; + if( j > 0 ) *p++ = (unsigned char)( x >> 16 ); + if( j > 1 ) *p++ = (unsigned char)( x >> 8 ); + if( j > 2 ) *p++ = (unsigned char)( x ); + } + } + + *olen = p - dst; + + return( 0 ); +} + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char base64_test_dec[64] = +{ + 0x24, 0x48, 0x6E, 0x56, 0x87, 0x62, 0x5A, 0xBD, + 0xBF, 0x17, 0xD9, 0xA2, 0xC4, 0x17, 0x1A, 0x01, + 0x94, 0xED, 0x8F, 0x1E, 0x11, 0xB3, 0xD7, 0x09, + 0x0C, 0xB6, 0xE9, 0x10, 0x6F, 0x22, 0xEE, 0x13, + 0xCA, 0xB3, 0x07, 0x05, 0x76, 0xC9, 0xFA, 0x31, + 0x6C, 0x08, 0x34, 0xFF, 0x8D, 0xC2, 0x6C, 0x38, + 0x00, 0x43, 0xE9, 0x54, 0x97, 0xAF, 0x50, 0x4B, + 0xD1, 0x41, 0xBA, 0x95, 0x31, 0x5A, 0x0B, 0x97 +}; + +static const unsigned char base64_test_enc[] = + "JEhuVodiWr2/F9mixBcaAZTtjx4Rs9cJDLbpEG8i7hPK" + "swcFdsn6MWwINP+Nwmw4AEPpVJevUEvRQbqVMVoLlw=="; + +/* + * Checkup routine + */ +int mbedtls_base64_self_test( int verbose ) +{ + size_t len; + const unsigned char *src; + unsigned char buffer[128]; + + if( verbose != 0 ) + mbedtls_printf( " Base64 encoding test: " ); + + src = base64_test_dec; + + if( mbedtls_base64_encode( buffer, sizeof( buffer ), &len, src, 64 ) != 0 || + memcmp( base64_test_enc, buffer, 88 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n Base64 decoding test: " ); + + src = base64_test_enc; + + if( mbedtls_base64_decode( buffer, sizeof( buffer ), &len, src, 88 ) != 0 || + memcmp( base64_test_dec, buffer, 64 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_BASE64_C */ diff --git a/c++/src/connect/mbedtls/bignum.c b/c++/src/connect/mbedtls/bignum.c new file mode 100644 index 00000000..8b9082cd --- /dev/null +++ b/c++/src/connect/mbedtls/bignum.c @@ -0,0 +1,2447 @@ +/* + * Multi-precision integer library + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The following sources were referenced in the design of this Multi-precision + * Integer library: + * + * [1] Handbook of Applied Cryptography - 1997 + * Menezes, van Oorschot and Vanstone + * + * [2] Multi-Precision Math + * Tom St Denis + * https://github.com/libtom/libtommath/blob/develop/tommath.pdf + * + * [3] GNU Multi-Precision Arithmetic Library + * https://gmplib.org/manual/index.html + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BIGNUM_C) + +#include "mbedtls/bignum.h" +#include "mbedtls/bn_mul.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_mpi_zeroize( mbedtls_mpi_uint *v, size_t n ) { + volatile mbedtls_mpi_uint *p = v; while( n-- ) *p++ = 0; +} + +#define ciL (sizeof(mbedtls_mpi_uint)) /* chars in limb */ +#define biL (ciL << 3) /* bits in limb */ +#define biH (ciL << 2) /* half limb size */ + +#define MPI_SIZE_T_MAX ( (size_t) -1 ) /* SIZE_T_MAX is not standard */ + +/* + * Convert between bits/chars and number of limbs + * Divide first in order to avoid potential overflows + */ +#define BITS_TO_LIMBS(i) ( (i) / biL + ( (i) % biL != 0 ) ) +#define CHARS_TO_LIMBS(i) ( (i) / ciL + ( (i) % ciL != 0 ) ) + +/* + * Initialize one MPI + */ +void mbedtls_mpi_init( mbedtls_mpi *X ) +{ + if( X == NULL ) + return; + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Unallocate one MPI + */ +void mbedtls_mpi_free( mbedtls_mpi *X ) +{ + if( X == NULL ) + return; + + if( X->p != NULL ) + { + mbedtls_mpi_zeroize( X->p, X->n ); + mbedtls_free( X->p ); + } + + X->s = 1; + X->n = 0; + X->p = NULL; +} + +/* + * Enlarge to the specified number of limbs + */ +int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ) +{ + mbedtls_mpi_uint *p; + + if( nblimbs > MBEDTLS_MPI_MAX_LIMBS ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->n < nblimbs ) + { + if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( nblimbs, ciL ) ) == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->p != NULL ) + { + memcpy( p, X->p, X->n * ciL ); + mbedtls_mpi_zeroize( X->p, X->n ); + mbedtls_free( X->p ); + } + + X->n = nblimbs; + X->p = p; + } + + return( 0 ); +} + +/* + * Resize down as much as possible, + * while keeping at least the specified number of limbs + */ +int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ) +{ + mbedtls_mpi_uint *p; + size_t i; + + /* Actually resize up in this case */ + if( X->n <= nblimbs ) + return( mbedtls_mpi_grow( X, nblimbs ) ); + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + i++; + + if( i < nblimbs ) + i = nblimbs; + + if( ( p = (mbedtls_mpi_uint*)mbedtls_calloc( i, ciL ) ) == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + if( X->p != NULL ) + { + memcpy( p, X->p, i * ciL ); + mbedtls_mpi_zeroize( X->p, X->n ); + mbedtls_free( X->p ); + } + + X->n = i; + X->p = p; + + return( 0 ); +} + +/* + * Copy the contents of Y into X + */ +int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + int ret; + size_t i; + + if( X == Y ) + return( 0 ); + + if( Y->p == NULL ) + { + mbedtls_mpi_free( X ); + return( 0 ); + } + + for( i = Y->n - 1; i > 0; i-- ) + if( Y->p[i] != 0 ) + break; + i++; + + X->s = Y->s; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i ) ); + + memset( X->p, 0, X->n * ciL ); + memcpy( X->p, Y->p, i * ciL ); + +cleanup: + + return( ret ); +} + +/* + * Swap the contents of X and Y + */ +void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ) +{ + mbedtls_mpi T; + + memcpy( &T, X, sizeof( mbedtls_mpi ) ); + memcpy( X, Y, sizeof( mbedtls_mpi ) ); + memcpy( Y, &T, sizeof( mbedtls_mpi ) ); +} + +/* + * Conditionally assign X = Y, without leaking information + * about whether the assignment was made or not. + * (Leaking information about the respective sizes of X and Y is ok however.) + */ +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ) +{ + int ret = 0; + size_t i; + + /* make sure assign is 0 or 1 in a time-constant manner */ + assign = (assign | (unsigned char)-assign) >> 7; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); + + X->s = X->s * ( 1 - assign ) + Y->s * assign; + + for( i = 0; i < Y->n; i++ ) + X->p[i] = X->p[i] * ( 1 - assign ) + Y->p[i] * assign; + + for( ; i < X->n; i++ ) + X->p[i] *= ( 1 - assign ); + +cleanup: + return( ret ); +} + +/* + * Conditionally swap X and Y, without leaking information + * about whether the swap was made or not. + * Here it is not ok to simply swap the pointers, which whould lead to + * different memory access patterns when X and Y are used afterwards. + */ +int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char swap ) +{ + int ret, s; + size_t i; + mbedtls_mpi_uint tmp; + + if( X == Y ) + return( 0 ); + + /* make sure swap is 0 or 1 in a time-constant manner */ + swap = (swap | (unsigned char)-swap) >> 7; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, Y->n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( Y, X->n ) ); + + s = X->s; + X->s = X->s * ( 1 - swap ) + Y->s * swap; + Y->s = Y->s * ( 1 - swap ) + s * swap; + + + for( i = 0; i < X->n; i++ ) + { + tmp = X->p[i]; + X->p[i] = X->p[i] * ( 1 - swap ) + Y->p[i] * swap; + Y->p[i] = Y->p[i] * ( 1 - swap ) + tmp * swap; + } + +cleanup: + return( ret ); +} + +/* + * Set value from integer + */ +int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, 1 ) ); + memset( X->p, 0, X->n * ciL ); + + X->p[0] = ( z < 0 ) ? -z : z; + X->s = ( z < 0 ) ? -1 : 1; + +cleanup: + + return( ret ); +} + +/* + * Get a specific bit + */ +int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ) +{ + if( X->n * biL <= pos ) + return( 0 ); + + return( ( X->p[pos / biL] >> ( pos % biL ) ) & 0x01 ); +} + +/* + * Set a bit to a specific value of 0 or 1 + */ +int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ) +{ + int ret = 0; + size_t off = pos / biL; + size_t idx = pos % biL; + + if( val != 0 && val != 1 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( X->n * biL <= pos ) + { + if( val == 0 ) + return( 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, off + 1 ) ); + } + + X->p[off] &= ~( (mbedtls_mpi_uint) 0x01 << idx ); + X->p[off] |= (mbedtls_mpi_uint) val << idx; + +cleanup: + + return( ret ); +} + +/* + * Return the number of less significant zero-bits + */ +size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ) +{ + size_t i, j, count = 0; + + for( i = 0; i < X->n; i++ ) + for( j = 0; j < biL; j++, count++ ) + if( ( ( X->p[i] >> j ) & 1 ) != 0 ) + return( count ); + + return( 0 ); +} + +/* + * Count leading zero bits in a given integer + */ +static size_t mbedtls_clz( const mbedtls_mpi_uint x ) +{ + size_t j; + mbedtls_mpi_uint mask = (mbedtls_mpi_uint) 1 << (biL - 1); + + for( j = 0; j < biL; j++ ) + { + if( x & mask ) break; + + mask >>= 1; + } + + return j; +} + +/* + * Return the number of bits + */ +size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ) +{ + size_t i, j; + + if( X->n == 0 ) + return( 0 ); + + for( i = X->n - 1; i > 0; i-- ) + if( X->p[i] != 0 ) + break; + + j = biL - mbedtls_clz( X->p[i] ); + + return( ( i * biL ) + j ); +} + +/* + * Return the total size in bytes + */ +size_t mbedtls_mpi_size( const mbedtls_mpi *X ) +{ + return( ( mbedtls_mpi_bitlen( X ) + 7 ) >> 3 ); +} + +/* + * Convert an ASCII character to digit value + */ +static int mpi_get_digit( mbedtls_mpi_uint *d, int radix, char c ) +{ + *d = 255; + + if( c >= 0x30 && c <= 0x39 ) *d = c - 0x30; + if( c >= 0x41 && c <= 0x46 ) *d = c - 0x37; + if( c >= 0x61 && c <= 0x66 ) *d = c - 0x57; + + if( *d >= (mbedtls_mpi_uint) radix ) + return( MBEDTLS_ERR_MPI_INVALID_CHARACTER ); + + return( 0 ); +} + +/* + * Import from an ASCII string + */ +int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ) +{ + int ret; + size_t i, j, slen, n; + mbedtls_mpi_uint d; + mbedtls_mpi T; + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T ); + + slen = strlen( s ); + + if( radix == 16 ) + { + if( slen > MPI_SIZE_T_MAX >> 2 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + n = BITS_TO_LIMBS( slen << 2 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = slen, j = 0; i > 0; i--, j++ ) + { + if( i == 1 && s[i - 1] == '-' ) + { + X->s = -1; + break; + } + + MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i - 1] ) ); + X->p[j / ( 2 * ciL )] |= d << ( ( j % ( 2 * ciL ) ) << 2 ); + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = 0; i < slen; i++ ) + { + if( i == 0 && s[i] == '-' ) + { + X->s = -1; + continue; + } + + MBEDTLS_MPI_CHK( mpi_get_digit( &d, radix, s[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T, X, radix ) ); + + if( X->s == 1 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, &T, d ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( X, &T, d ) ); + } + } + } + +cleanup: + + mbedtls_mpi_free( &T ); + + return( ret ); +} + +/* + * Helper to write the digits high-order first + */ +static int mpi_write_hlp( mbedtls_mpi *X, int radix, char **p ) +{ + int ret; + mbedtls_mpi_uint r; + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, radix ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_int( X, NULL, X, radix ) ); + + if( mbedtls_mpi_cmp_int( X, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mpi_write_hlp( X, radix, p ) ); + + if( r < 10 ) + *(*p)++ = (char)( r + 0x30 ); + else + *(*p)++ = (char)( r + 0x37 ); + +cleanup: + + return( ret ); +} + +/* + * Export into an ASCII string + */ +int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, + char *buf, size_t buflen, size_t *olen ) +{ + int ret = 0; + size_t n; + char *p; + mbedtls_mpi T; + + if( radix < 2 || radix > 16 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + n = mbedtls_mpi_bitlen( X ); + if( radix >= 4 ) n >>= 1; + if( radix >= 16 ) n >>= 1; + /* + * Round up the buffer length to an even value to ensure that there is + * enough room for hexadecimal values that can be represented in an odd + * number of digits. + */ + n += 3 + ( ( n + 1 ) & 1 ); + + if( buflen < n ) + { + *olen = n; + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + } + + p = buf; + mbedtls_mpi_init( &T ); + + if( X->s == -1 ) + *p++ = '-'; + + if( radix == 16 ) + { + int c; + size_t i, j, k; + + for( i = X->n, k = 0; i > 0; i-- ) + { + for( j = ciL; j > 0; j-- ) + { + c = ( X->p[i - 1] >> ( ( j - 1 ) << 3) ) & 0xFF; + + if( c == 0 && k == 0 && ( i + j ) != 2 ) + continue; + + *(p++) = "0123456789ABCDEF" [c / 16]; + *(p++) = "0123456789ABCDEF" [c % 16]; + k = 1; + } + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T, X ) ); + + if( T.s == -1 ) + T.s = 1; + + MBEDTLS_MPI_CHK( mpi_write_hlp( &T, radix, &p ) ); + } + + *p++ = '\0'; + *olen = p - buf; + +cleanup: + + mbedtls_mpi_free( &T ); + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Read X from an opened file + */ +int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ) +{ + mbedtls_mpi_uint d; + size_t slen; + char *p; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; + + memset( s, 0, sizeof( s ) ); + if( fgets( s, sizeof( s ) - 1, fin ) == NULL ) + return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); + + slen = strlen( s ); + if( slen == sizeof( s ) - 2 ) + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + + if( s[slen - 1] == '\n' ) { slen--; s[slen] = '\0'; } + if( s[slen - 1] == '\r' ) { slen--; s[slen] = '\0'; } + + p = s + slen; + while( --p >= s ) + if( mpi_get_digit( &d, radix, *p ) != 0 ) + break; + + return( mbedtls_mpi_read_string( X, radix, p + 1 ) ); +} + +/* + * Write X into an opened file (or stdout if fout == NULL) + */ +int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout ) +{ + int ret; + size_t n, slen, plen; + /* + * Buffer should have space for (short) label and decimal formatted MPI, + * newline characters and '\0' + */ + char s[ MBEDTLS_MPI_RW_BUFFER_SIZE ]; + + memset( s, 0, sizeof( s ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_string( X, radix, s, sizeof( s ) - 2, &n ) ); + + if( p == NULL ) p = ""; + + plen = strlen( p ); + slen = strlen( s ); + s[slen++] = '\r'; + s[slen++] = '\n'; + + if( fout != NULL ) + { + if( fwrite( p, 1, plen, fout ) != plen || + fwrite( s, 1, slen, fout ) != slen ) + return( MBEDTLS_ERR_MPI_FILE_IO_ERROR ); + } + else + mbedtls_printf( "%s%s", p, s ); + +cleanup: + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +/* + * Import X from unsigned binary data, big endian + */ +int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t i, j, n; + + for( n = 0; n < buflen; n++ ) + if( buf[n] != 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, CHARS_TO_LIMBS( buflen - n ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i = buflen, j = 0; i > n; i--, j++ ) + X->p[j / ciL] |= ((mbedtls_mpi_uint) buf[i - 1]) << ((j % ciL) << 3); + +cleanup: + + return( ret ); +} + +/* + * Export X into unsigned binary data, big endian + */ +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen ) +{ + size_t i, j, n; + + n = mbedtls_mpi_size( X ); + + if( buflen < n ) + return( MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL ); + + memset( buf, 0, buflen ); + + for( i = buflen - 1, j = 0; n > 0; i--, j++, n-- ) + buf[i] = (unsigned char)( X->p[j / ciL] >> ((j % ciL) << 3) ); + + return( 0 ); +} + +/* + * Left-shift: X <<= count + */ +int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ) +{ + int ret; + size_t i, v0, t1; + mbedtls_mpi_uint r0 = 0, r1; + + v0 = count / (biL ); + t1 = count & (biL - 1); + + i = mbedtls_mpi_bitlen( X ) + count; + + if( X->n * biL < i ) + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, BITS_TO_LIMBS( i ) ) ); + + ret = 0; + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = X->n; i > v0; i-- ) + X->p[i - 1] = X->p[i - v0 - 1]; + + for( ; i > 0; i-- ) + X->p[i - 1] = 0; + } + + /* + * shift by count % limb_size + */ + if( t1 > 0 ) + { + for( i = v0; i < X->n; i++ ) + { + r1 = X->p[i] >> (biL - t1); + X->p[i] <<= t1; + X->p[i] |= r0; + r0 = r1; + } + } + +cleanup: + + return( ret ); +} + +/* + * Right-shift: X >>= count + */ +int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ) +{ + size_t i, v0, v1; + mbedtls_mpi_uint r0 = 0, r1; + + v0 = count / biL; + v1 = count & (biL - 1); + + if( v0 > X->n || ( v0 == X->n && v1 > 0 ) ) + return mbedtls_mpi_lset( X, 0 ); + + /* + * shift by count / limb_size + */ + if( v0 > 0 ) + { + for( i = 0; i < X->n - v0; i++ ) + X->p[i] = X->p[i + v0]; + + for( ; i < X->n; i++ ) + X->p[i] = 0; + } + + /* + * shift by count % limb_size + */ + if( v1 > 0 ) + { + for( i = X->n; i > 0; i-- ) + { + r1 = X->p[i - 1] << (biL - v1); + X->p[i - 1] >>= v1; + X->p[i - 1] |= r0; + r0 = r1; + } + } + + return( 0 ); +} + +/* + * Compare unsigned values + */ +int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( 1 ); + if( j > i ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( 1 ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -1 ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ) +{ + size_t i, j; + + for( i = X->n; i > 0; i-- ) + if( X->p[i - 1] != 0 ) + break; + + for( j = Y->n; j > 0; j-- ) + if( Y->p[j - 1] != 0 ) + break; + + if( i == 0 && j == 0 ) + return( 0 ); + + if( i > j ) return( X->s ); + if( j > i ) return( -Y->s ); + + if( X->s > 0 && Y->s < 0 ) return( 1 ); + if( Y->s > 0 && X->s < 0 ) return( -1 ); + + for( ; i > 0; i-- ) + { + if( X->p[i - 1] > Y->p[i - 1] ) return( X->s ); + if( X->p[i - 1] < Y->p[i - 1] ) return( -X->s ); + } + + return( 0 ); +} + +/* + * Compare signed values + */ +int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ) +{ + mbedtls_mpi Y; + mbedtls_mpi_uint p[1]; + + *p = ( z < 0 ) ? -z : z; + Y.s = ( z < 0 ) ? -1 : 1; + Y.n = 1; + Y.p = p; + + return( mbedtls_mpi_cmp_mpi( X, &Y ) ); +} + +/* + * Unsigned addition: X = |A| + |B| (HAC 14.7) + */ +int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t i, j; + mbedtls_mpi_uint *o, *p, c, tmp; + + if( X == B ) + { + const mbedtls_mpi *T = A; A = X; B = T; + } + + if( X != A ) + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned additions. + */ + X->s = 1; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); + + o = B->p; p = X->p; c = 0; + + /* + * tmp is used because it might happen that p == o + */ + for( i = 0; i < j; i++, o++, p++ ) + { + tmp= *o; + *p += c; c = ( *p < c ); + *p += tmp; c += ( *p < tmp ); + } + + while( c != 0 ) + { + if( i >= X->n ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + 1 ) ); + p = X->p + i; + } + + *p += c; c = ( *p < c ); i++; p++; + } + +cleanup: + + return( ret ); +} + +/* + * Helper for mbedtls_mpi subtraction + */ +static void mpi_sub_hlp( size_t n, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d ) +{ + size_t i; + mbedtls_mpi_uint c, z; + + for( i = c = 0; i < n; i++, s++, d++ ) + { + z = ( *d < c ); *d -= c; + c = ( *d < *s ) + z; *d -= *s; + } + + while( c != 0 ) + { + z = ( *d < c ); *d -= c; + c = z; i++; d++; + } +} + +/* + * Unsigned subtraction: X = |A| - |B| (HAC 14.9) + */ +int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + mbedtls_mpi TB; + int ret; + size_t n; + + if( mbedtls_mpi_cmp_abs( A, B ) < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + mbedtls_mpi_init( &TB ); + + if( X == B ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); + B = &TB; + } + + if( X != A ) + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, A ) ); + + /* + * X should always be positive as a result of unsigned subtractions. + */ + X->s = 1; + + ret = 0; + + for( n = B->n; n > 0; n-- ) + if( B->p[n - 1] != 0 ) + break; + + mpi_sub_hlp( n, B->p, X->p ); + +cleanup: + + mbedtls_mpi_free( &TB ); + + return( ret ); +} + +/* + * Signed addition: X = A + B + */ +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s < 0 ) + { + if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed subtraction: X = A - B + */ +int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret, s = A->s; + + if( A->s * B->s > 0 ) + { + if( mbedtls_mpi_cmp_abs( A, B ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, A, B ) ); + X->s = s; + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( X, B, A ) ); + X->s = -s; + } + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( X, A, B ) ); + X->s = s; + } + +cleanup: + + return( ret ); +} + +/* + * Signed addition: X = A + b + */ +int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_add_mpi( X, A, &_B ) ); +} + +/* + * Signed subtraction: X = A - b + */ +int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_sub_mpi( X, A, &_B ) ); +} + +/* + * Helper for mbedtls_mpi multiplication + */ +static +#if defined(__APPLE__) && defined(__arm__) +/* + * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn) + * appears to need this to prevent bad ARM code generation at -O3. + */ +__attribute__ ((noinline)) +#endif +void mpi_mul_hlp( size_t i, mbedtls_mpi_uint *s, mbedtls_mpi_uint *d, mbedtls_mpi_uint b ) +{ + mbedtls_mpi_uint c = 0, t = 0; + +#if defined(MULADDC_HUIT) + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_HUIT + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#else /* MULADDC_HUIT */ + for( ; i >= 16; i -= 16 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i >= 8; i -= 8 ) + { + MULADDC_INIT + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + + MULADDC_CORE MULADDC_CORE + MULADDC_CORE MULADDC_CORE + MULADDC_STOP + } + + for( ; i > 0; i-- ) + { + MULADDC_INIT + MULADDC_CORE + MULADDC_STOP + } +#endif /* MULADDC_HUIT */ + + t++; + + do { + *d += c; c = ( *d < c ); d++; + } + while( c != 0 ); +} + +/* + * Baseline multiplication: X = A * B (HAC 14.12) + */ +int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t i, j; + mbedtls_mpi TA, TB; + + mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB ); + + if( X == A ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); A = &TA; } + if( X == B ) { MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); B = &TB; } + + for( i = A->n; i > 0; i-- ) + if( A->p[i - 1] != 0 ) + break; + + for( j = B->n; j > 0; j-- ) + if( B->p[j - 1] != 0 ) + break; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, i + j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( X, 0 ) ); + + for( i++; j > 0; j-- ) + mpi_mul_hlp( i - 1, A->p, X->p + j - 1, B->p[j - 1] ); + + X->s = A->s * B->s; + +cleanup: + + mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TA ); + + return( ret ); +} + +/* + * Baseline multiplication: X = A * b + */ +int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + _B.s = 1; + _B.n = 1; + _B.p = p; + p[0] = b; + + return( mbedtls_mpi_mul_mpi( X, A, &_B ) ); +} + +/* + * Unsigned integer divide - double mbedtls_mpi_uint dividend, u1/u0, and + * mbedtls_mpi_uint divisor, d + */ +static mbedtls_mpi_uint mbedtls_int_div_int( mbedtls_mpi_uint u1, + mbedtls_mpi_uint u0, mbedtls_mpi_uint d, mbedtls_mpi_uint *r ) +{ +#if defined(MBEDTLS_HAVE_UDBL) + mbedtls_t_udbl dividend, quotient; +#else + const mbedtls_mpi_uint radix = (mbedtls_mpi_uint) 1 << biH; + const mbedtls_mpi_uint uint_halfword_mask = ( (mbedtls_mpi_uint) 1 << biH ) - 1; + mbedtls_mpi_uint d0, d1, q0, q1, rAX, r0, quotient; + mbedtls_mpi_uint u0_msw, u0_lsw; + size_t s; +#endif + + /* + * Check for overflow + */ + if( 0 == d || u1 >= d ) + { + if (r != NULL) *r = ~0; + + return ( ~0 ); + } + +#if defined(MBEDTLS_HAVE_UDBL) + dividend = (mbedtls_t_udbl) u1 << biL; + dividend |= (mbedtls_t_udbl) u0; + quotient = dividend / d; + if( quotient > ( (mbedtls_t_udbl) 1 << biL ) - 1 ) + quotient = ( (mbedtls_t_udbl) 1 << biL ) - 1; + + if( r != NULL ) + *r = (mbedtls_mpi_uint)( dividend - (quotient * d ) ); + + return (mbedtls_mpi_uint) quotient; +#else + + /* + * Algorithm D, Section 4.3.1 - The Art of Computer Programming + * Vol. 2 - Seminumerical Algorithms, Knuth + */ + + /* + * Normalize the divisor, d, and dividend, u0, u1 + */ + s = mbedtls_clz( d ); + d = d << s; + + u1 = u1 << s; + u1 |= ( u0 >> ( biL - s ) ) & ( -(mbedtls_mpi_sint)s >> ( biL - 1 ) ); + u0 = u0 << s; + + d1 = d >> biH; + d0 = d & uint_halfword_mask; + + u0_msw = u0 >> biH; + u0_lsw = u0 & uint_halfword_mask; + + /* + * Find the first quotient and remainder + */ + q1 = u1 / d1; + r0 = u1 - d1 * q1; + + while( q1 >= radix || ( q1 * d0 > radix * r0 + u0_msw ) ) + { + q1 -= 1; + r0 += d1; + + if ( r0 >= radix ) break; + } + + rAX = ( u1 * radix ) + ( u0_msw - q1 * d ); + q0 = rAX / d1; + r0 = rAX - q0 * d1; + + while( q0 >= radix || ( q0 * d0 > radix * r0 + u0_lsw ) ) + { + q0 -= 1; + r0 += d1; + + if ( r0 >= radix ) break; + } + + if (r != NULL) + *r = ( rAX * radix + u0_lsw - q0 * d ) >> s; + + quotient = q1 * radix + q0; + + return quotient; +#endif +} + +/* + * Division by mbedtls_mpi: A = Q * B + R (HAC 14.20) + */ +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t i, n, t, k; + mbedtls_mpi X, Y, Z, T1, T2; + + if( mbedtls_mpi_cmp_int( B, 0 ) == 0 ) + return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); + + mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z ); + mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); + + if( mbedtls_mpi_cmp_abs( A, B ) < 0 ) + { + if( Q != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_lset( Q, 0 ) ); + if( R != NULL ) MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, A ) ); + return( 0 ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &X, A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, B ) ); + X.s = Y.s = 1; + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &Z, A->n + 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Z, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T1, 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T2, 3 ) ); + + k = mbedtls_mpi_bitlen( &Y ) % biL; + if( k < biL - 1 ) + { + k = biL - 1 - k; + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &X, k ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, k ) ); + } + else k = 0; + + n = X.n - 1; + t = Y.n - 1; + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &Y, biL * ( n - t ) ) ); + + while( mbedtls_mpi_cmp_mpi( &X, &Y ) >= 0 ) + { + Z.p[n - t]++; + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &Y ) ); + } + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, biL * ( n - t ) ) ); + + for( i = n; i > t ; i-- ) + { + if( X.p[i] >= Y.p[t] ) + Z.p[i - t - 1] = ~0; + else + { + Z.p[i - t - 1] = mbedtls_int_div_int( X.p[i], X.p[i - 1], + Y.p[t], NULL); + } + + Z.p[i - t - 1]++; + do + { + Z.p[i - t - 1]--; + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T1, 0 ) ); + T1.p[0] = ( t < 1 ) ? 0 : Y.p[t - 1]; + T1.p[1] = Y.p[t]; + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T1, Z.p[i - t - 1] ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &T2, 0 ) ); + T2.p[0] = ( i < 2 ) ? 0 : X.p[i - 2]; + T2.p[1] = ( i < 1 ) ? 0 : X.p[i - 1]; + T2.p[2] = X.p[i]; + } + while( mbedtls_mpi_cmp_mpi( &T1, &T2 ) > 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &Y, Z.p[i - t - 1] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) ); + + if( mbedtls_mpi_cmp_int( &X, 0 ) < 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &T1, &Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T1, biL * ( i - t - 1 ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &X, &X, &T1 ) ); + Z.p[i - t - 1]--; + } + } + + if( Q != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( Q, &Z ) ); + Q->s = A->s * B->s; + } + + if( R != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &X, k ) ); + X.s = A->s; + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( R, &X ) ); + + if( mbedtls_mpi_cmp_int( R, 0 ) == 0 ) + R->s = 1; + } + +cleanup: + + mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); + mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); + + return( ret ); +} + +/* + * Division by int: A = Q * b + R + */ +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + mbedtls_mpi _B; + mbedtls_mpi_uint p[1]; + + p[0] = ( b < 0 ) ? -b : b; + _B.s = ( b < 0 ) ? -1 : 1; + _B.n = 1; + _B.p = p; + + return( mbedtls_mpi_div_mpi( Q, R, A, &_B ) ); +} + +/* + * Modulo: R = A mod B + */ +int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + + if( mbedtls_mpi_cmp_int( B, 0 ) < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( NULL, R, A, B ) ); + + while( mbedtls_mpi_cmp_int( R, 0 ) < 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) ); + + while( mbedtls_mpi_cmp_mpi( R, B ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) ); + +cleanup: + + return( ret ); +} + +/* + * Modulo: r = A mod b + */ +int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b ) +{ + size_t i; + mbedtls_mpi_uint x, y, z; + + if( b == 0 ) + return( MBEDTLS_ERR_MPI_DIVISION_BY_ZERO ); + + if( b < 0 ) + return( MBEDTLS_ERR_MPI_NEGATIVE_VALUE ); + + /* + * handle trivial cases + */ + if( b == 1 ) + { + *r = 0; + return( 0 ); + } + + if( b == 2 ) + { + *r = A->p[0] & 1; + return( 0 ); + } + + /* + * general case + */ + for( i = A->n, y = 0; i > 0; i-- ) + { + x = A->p[i - 1]; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + + x <<= biH; + y = ( y << biH ) | ( x >> biH ); + z = y / b; + y -= z * b; + } + + /* + * If A is negative, then the current y represents a negative value. + * Flipping it to the positive side. + */ + if( A->s < 0 && y != 0 ) + y = b - y; + + *r = y; + + return( 0 ); +} + +/* + * Fast Montgomery initialization (thanks to Tom St Denis) + */ +static void mpi_montg_init( mbedtls_mpi_uint *mm, const mbedtls_mpi *N ) +{ + mbedtls_mpi_uint x, m0 = N->p[0]; + unsigned int i; + + x = m0; + x += ( ( m0 + 2 ) & 4 ) << 1; + + for( i = biL; i >= 8; i /= 2 ) + x *= ( 2 - ( m0 * x ) ); + + *mm = ~x + 1; +} + +/* + * Montgomery multiplication: A = A * B * R^-1 mod N (HAC 14.36) + */ +static int mpi_montmul( mbedtls_mpi *A, const mbedtls_mpi *B, const mbedtls_mpi *N, mbedtls_mpi_uint mm, + const mbedtls_mpi *T ) +{ + size_t i, n, m; + mbedtls_mpi_uint u0, u1, *d; + + if( T->n < N->n + 1 || T->p == NULL ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + memset( T->p, 0, T->n * ciL ); + + d = T->p; + n = N->n; + m = ( B->n < n ) ? B->n : n; + + for( i = 0; i < n; i++ ) + { + /* + * T = (T + u0*B + u1*N) / 2^biL + */ + u0 = A->p[i]; + u1 = ( d[0] + u0 * B->p[0] ) * mm; + + mpi_mul_hlp( m, B->p, d, u0 ); + mpi_mul_hlp( n, N->p, d, u1 ); + + *d++ = u0; d[n + 1] = 0; + } + + memcpy( A->p, d, ( n + 1 ) * ciL ); + + if( mbedtls_mpi_cmp_abs( A, N ) >= 0 ) + mpi_sub_hlp( n, N->p, A->p ); + else + /* prevent timing attacks */ + mpi_sub_hlp( n, A->p, T->p ); + + return( 0 ); +} + +/* + * Montgomery reduction: A = A * R^-1 mod N + */ +static int mpi_montred( mbedtls_mpi *A, const mbedtls_mpi *N, mbedtls_mpi_uint mm, const mbedtls_mpi *T ) +{ + mbedtls_mpi_uint z = 1; + mbedtls_mpi U; + + U.n = U.s = (int) z; + U.p = &z; + + return( mpi_montmul( A, &U, N, mm, T ) ); +} + +/* + * Sliding-window exponentiation: X = A^E mod N (HAC 14.85) + */ +int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR ) +{ + int ret; + size_t wbits, wsize, one = 1; + size_t i, j, nblimbs; + size_t bufsize, nbits; + mbedtls_mpi_uint ei, mm, state; + mbedtls_mpi RR, T, W[ 2 << MBEDTLS_MPI_WINDOW_SIZE ], Apos; + int neg; + + if( mbedtls_mpi_cmp_int( N, 0 ) < 0 || ( N->p[0] & 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + if( mbedtls_mpi_cmp_int( E, 0 ) < 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + /* + * Init temps and window size + */ + mpi_montg_init( &mm, N ); + mbedtls_mpi_init( &RR ); mbedtls_mpi_init( &T ); + mbedtls_mpi_init( &Apos ); + memset( W, 0, sizeof( W ) ); + + i = mbedtls_mpi_bitlen( E ); + + wsize = ( i > 671 ) ? 6 : ( i > 239 ) ? 5 : + ( i > 79 ) ? 4 : ( i > 23 ) ? 3 : 1; + + if( wsize > MBEDTLS_MPI_WINDOW_SIZE ) + wsize = MBEDTLS_MPI_WINDOW_SIZE; + + j = N->n + 1; + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( X, j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[1], j ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &T, j * 2 ) ); + + /* + * Compensate for negative A (and correct at the end) + */ + neg = ( A->s == -1 ); + if( neg ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Apos, A ) ); + Apos.s = 1; + A = &Apos; + } + + /* + * If 1st call, pre-compute R^2 mod N + */ + if( _RR == NULL || _RR->p == NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &RR, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &RR, N->n * 2 * biL ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &RR, &RR, N ) ); + + if( _RR != NULL ) + memcpy( _RR, &RR, sizeof( mbedtls_mpi ) ); + } + else + memcpy( &RR, _RR, sizeof( mbedtls_mpi ) ); + + /* + * W[1] = A * R^2 * R^-1 mod N = A * R mod N + */ + if( mbedtls_mpi_cmp_mpi( A, N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &W[1], A, N ) ); + else + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[1], A ) ); + + MBEDTLS_MPI_CHK( mpi_montmul( &W[1], &RR, N, mm, &T ) ); + + /* + * X = R^2 * R^-1 mod N = R mod N + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &RR ) ); + MBEDTLS_MPI_CHK( mpi_montred( X, N, mm, &T ) ); + + if( wsize > 1 ) + { + /* + * W[1 << (wsize - 1)] = W[1] ^ (wsize - 1) + */ + j = one << ( wsize - 1 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[j], N->n + 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[j], &W[1] ) ); + + for( i = 0; i < wsize - 1; i++ ) + MBEDTLS_MPI_CHK( mpi_montmul( &W[j], &W[j], N, mm, &T ) ); + + /* + * W[i] = W[i - 1] * W[1] + */ + for( i = j + 1; i < ( one << wsize ); i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( &W[i], N->n + 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &W[i], &W[i - 1] ) ); + + MBEDTLS_MPI_CHK( mpi_montmul( &W[i], &W[1], N, mm, &T ) ); + } + } + + nblimbs = E->n; + bufsize = 0; + nbits = 0; + wbits = 0; + state = 0; + + while( 1 ) + { + if( bufsize == 0 ) + { + if( nblimbs == 0 ) + break; + + nblimbs--; + + bufsize = sizeof( mbedtls_mpi_uint ) << 3; + } + + bufsize--; + + ei = (E->p[nblimbs] >> bufsize) & 1; + + /* + * skip leading 0s + */ + if( ei == 0 && state == 0 ) + continue; + + if( ei == 0 && state == 1 ) + { + /* + * out of window, square X + */ + MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) ); + continue; + } + + /* + * add ei to current window + */ + state = 2; + + nbits++; + wbits |= ( ei << ( wsize - nbits ) ); + + if( nbits == wsize ) + { + /* + * X = X^wsize R^-1 mod N + */ + for( i = 0; i < wsize; i++ ) + MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) ); + + /* + * X = X * W[wbits] R^-1 mod N + */ + MBEDTLS_MPI_CHK( mpi_montmul( X, &W[wbits], N, mm, &T ) ); + + state--; + nbits = 0; + wbits = 0; + } + } + + /* + * process the remaining bits + */ + for( i = 0; i < nbits; i++ ) + { + MBEDTLS_MPI_CHK( mpi_montmul( X, X, N, mm, &T ) ); + + wbits <<= 1; + + if( ( wbits & ( one << wsize ) ) != 0 ) + MBEDTLS_MPI_CHK( mpi_montmul( X, &W[1], N, mm, &T ) ); + } + + /* + * X = A^E * R * R^-1 mod N = A^E mod N + */ + MBEDTLS_MPI_CHK( mpi_montred( X, N, mm, &T ) ); + + if( neg ) + { + X->s = -1; + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( X, N, X ) ); + } + +cleanup: + + for( i = ( one << ( wsize - 1 ) ); i < ( one << wsize ); i++ ) + mbedtls_mpi_free( &W[i] ); + + mbedtls_mpi_free( &W[1] ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &Apos ); + + if( _RR == NULL || _RR->p == NULL ) + mbedtls_mpi_free( &RR ); + + return( ret ); +} + +/* + * Greatest common divisor: G = gcd(A, B) (HAC 14.54) + */ +int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B ) +{ + int ret; + size_t lz, lzt; + mbedtls_mpi TG, TA, TB; + + mbedtls_mpi_init( &TG ); mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TB ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TA, A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, B ) ); + + lz = mbedtls_mpi_lsb( &TA ); + lzt = mbedtls_mpi_lsb( &TB ); + + if( lzt < lz ) + lz = lzt; + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, lz ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, lz ) ); + + TA.s = TB.s = 1; + + while( mbedtls_mpi_cmp_int( &TA, 0 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, mbedtls_mpi_lsb( &TA ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, mbedtls_mpi_lsb( &TB ) ) ); + + if( mbedtls_mpi_cmp_mpi( &TA, &TB ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TA, &TA, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TA, 1 ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &TB, &TB, &TA ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TB, 1 ) ); + } + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &TB, lz ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( G, &TB ) ); + +cleanup: + + mbedtls_mpi_free( &TG ); mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TB ); + + return( ret ); +} + +/* + * Fill X with size bytes of random. + * + * Use a temporary bytes representation to make sure the result is the same + * regardless of the platform endianness (useful when f_rng is actually + * deterministic, eg for tests). + */ +int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( size > MBEDTLS_MPI_MAX_SIZE ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( f_rng( p_rng, buf, size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( X, buf, size ) ); + +cleanup: + return( ret ); +} + +/* + * Modular inverse: X = A^-1 mod N (HAC 14.61 / 14.64) + */ +int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N ) +{ + int ret; + mbedtls_mpi G, TA, TU, U1, U2, TB, TV, V1, V2; + + if( mbedtls_mpi_cmp_int( N, 0 ) <= 0 ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &TA ); mbedtls_mpi_init( &TU ); mbedtls_mpi_init( &U1 ); mbedtls_mpi_init( &U2 ); + mbedtls_mpi_init( &G ); mbedtls_mpi_init( &TB ); mbedtls_mpi_init( &TV ); + mbedtls_mpi_init( &V1 ); mbedtls_mpi_init( &V2 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, A, N ) ); + + if( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &TA, A, N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TU, &TA ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TB, N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &TV, N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &U2, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V1, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &V2, 1 ) ); + + do + { + while( ( TU.p[0] & 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TU, 1 ) ); + + if( ( U1.p[0] & 1 ) != 0 || ( U2.p[0] & 1 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &U1, &U1, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &TA ) ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &U2, 1 ) ); + } + + while( ( TV.p[0] & 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &TV, 1 ) ); + + if( ( V1.p[0] & 1 ) != 0 || ( V2.p[0] & 1 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, &TB ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &TA ) ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V1, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &V2, 1 ) ); + } + + if( mbedtls_mpi_cmp_mpi( &TU, &TV ) >= 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TU, &TU, &TV ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U1, &U1, &V1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U2, &U2, &V2 ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &TV, &TV, &TU ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, &U1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V2, &V2, &U2 ) ); + } + } + while( mbedtls_mpi_cmp_int( &TU, 0 ) != 0 ); + + while( mbedtls_mpi_cmp_int( &V1, 0 ) < 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &V1, &V1, N ) ); + + while( mbedtls_mpi_cmp_mpi( &V1, N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &V1, &V1, N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( X, &V1 ) ); + +cleanup: + + mbedtls_mpi_free( &TA ); mbedtls_mpi_free( &TU ); mbedtls_mpi_free( &U1 ); mbedtls_mpi_free( &U2 ); + mbedtls_mpi_free( &G ); mbedtls_mpi_free( &TB ); mbedtls_mpi_free( &TV ); + mbedtls_mpi_free( &V1 ); mbedtls_mpi_free( &V2 ); + + return( ret ); +} + +#if defined(MBEDTLS_GENPRIME) + +static const int small_prime[] = +{ + 3, 5, 7, 11, 13, 17, 19, 23, + 29, 31, 37, 41, 43, 47, 53, 59, + 61, 67, 71, 73, 79, 83, 89, 97, + 101, 103, 107, 109, 113, 127, 131, 137, + 139, 149, 151, 157, 163, 167, 173, 179, + 181, 191, 193, 197, 199, 211, 223, 227, + 229, 233, 239, 241, 251, 257, 263, 269, + 271, 277, 281, 283, 293, 307, 311, 313, + 317, 331, 337, 347, 349, 353, 359, 367, + 373, 379, 383, 389, 397, 401, 409, 419, + 421, 431, 433, 439, 443, 449, 457, 461, + 463, 467, 479, 487, 491, 499, 503, 509, + 521, 523, 541, 547, 557, 563, 569, 571, + 577, 587, 593, 599, 601, 607, 613, 617, + 619, 631, 641, 643, 647, 653, 659, 661, + 673, 677, 683, 691, 701, 709, 719, 727, + 733, 739, 743, 751, 757, 761, 769, 773, + 787, 797, 809, 811, 821, 823, 827, 829, + 839, 853, 857, 859, 863, 877, 881, 883, + 887, 907, 911, 919, 929, 937, 941, 947, + 953, 967, 971, 977, 983, 991, 997, -103 +}; + +/* + * Small divisors test (X must be positive) + * + * Return values: + * 0: no small factor (possible prime, more tests needed) + * 1: certain prime + * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: certain non-prime + * other negative: error + */ +static int mpi_check_small_factors( const mbedtls_mpi *X ) +{ + int ret = 0; + size_t i; + mbedtls_mpi_uint r; + + if( ( X->p[0] & 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + + for( i = 0; small_prime[i] > 0; i++ ) + { + if( mbedtls_mpi_cmp_int( X, small_prime[i] ) <= 0 ) + return( 1 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, small_prime[i] ) ); + + if( r == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + } + +cleanup: + return( ret ); +} + +/* + * Miller-Rabin pseudo-primality test (HAC 4.24) + */ +static int mpi_miller_rabin( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count; + size_t i, j, k, n, s; + mbedtls_mpi W, R, T, A, RR; + + mbedtls_mpi_init( &W ); mbedtls_mpi_init( &R ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &A ); + mbedtls_mpi_init( &RR ); + + /* + * W = |X| - 1 + * R = W >> lsb( W ) + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &W, X, 1 ) ); + s = mbedtls_mpi_lsb( &W ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R, &W ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &R, s ) ); + + i = mbedtls_mpi_bitlen( X ); + /* + * HAC, table 4.4 + */ + n = ( ( i >= 1300 ) ? 2 : ( i >= 850 ) ? 3 : + ( i >= 650 ) ? 4 : ( i >= 350 ) ? 8 : + ( i >= 250 ) ? 12 : ( i >= 150 ) ? 18 : 27 ); + + for( i = 0; i < n; i++ ) + { + /* + * pick a random A, 1 < A < |X| - 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + if( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 ) + { + j = mbedtls_mpi_bitlen( &A ) - mbedtls_mpi_bitlen( &W ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j + 1 ) ); + } + A.p[0] |= 3; + + count = 0; + do { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &A, X->n * ciL, f_rng, p_rng ) ); + + j = mbedtls_mpi_bitlen( &A ); + k = mbedtls_mpi_bitlen( &W ); + if (j > k) { + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &A, j - k ) ); + } + + if (count++ > 30) { + return MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + } + + } while ( mbedtls_mpi_cmp_mpi( &A, &W ) >= 0 || + mbedtls_mpi_cmp_int( &A, 1 ) <= 0 ); + + /* + * A = A^R mod |X| + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &A, &A, &R, X, &RR ) ); + + if( mbedtls_mpi_cmp_mpi( &A, &W ) == 0 || + mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + continue; + + j = 1; + while( j < s && mbedtls_mpi_cmp_mpi( &A, &W ) != 0 ) + { + /* + * A = A * A mod |X| + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &A, &A ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &A, &T, X ) ); + + if( mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + break; + + j++; + } + + /* + * not prime if A != |X| - 1 or A == 1 + */ + if( mbedtls_mpi_cmp_mpi( &A, &W ) != 0 || + mbedtls_mpi_cmp_int( &A, 1 ) == 0 ) + { + ret = MBEDTLS_ERR_MPI_NOT_ACCEPTABLE; + break; + } + } + +cleanup: + mbedtls_mpi_free( &W ); mbedtls_mpi_free( &R ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &A ); + mbedtls_mpi_free( &RR ); + + return( ret ); +} + +/* + * Pseudo-primality test: small factors, then Miller-Rabin + */ +int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi XX; + + XX.s = 1; + XX.n = X->n; + XX.p = X->p; + + if( mbedtls_mpi_cmp_int( &XX, 0 ) == 0 || + mbedtls_mpi_cmp_int( &XX, 1 ) == 0 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + + if( mbedtls_mpi_cmp_int( &XX, 2 ) == 0 ) + return( 0 ); + + if( ( ret = mpi_check_small_factors( &XX ) ) != 0 ) + { + if( ret == 1 ) + return( 0 ); + + return( ret ); + } + + return( mpi_miller_rabin( &XX, f_rng, p_rng ) ); +} + +/* + * Prime number generation + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t k, n; + mbedtls_mpi_uint r; + mbedtls_mpi Y; + + if( nbits < 3 || nbits > MBEDTLS_MPI_MAX_BITS ) + return( MBEDTLS_ERR_MPI_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &Y ); + + n = BITS_TO_LIMBS( nbits ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( X, n * ciL, f_rng, p_rng ) ); + + k = mbedtls_mpi_bitlen( X ); + if( k > nbits ) MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( X, k - nbits + 1 ) ); + + mbedtls_mpi_set_bit( X, nbits-1, 1 ); + + X->p[0] |= 1; + + if( dh_flag == 0 ) + { + while( ( ret = mbedtls_mpi_is_prime( X, f_rng, p_rng ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 2 ) ); + } + } + else + { + /* + * An necessary condition for Y and X = 2Y + 1 to be prime + * is X = 2 mod 3 (which is equivalent to Y = 2 mod 3). + * Make sure it is satisfied, while keeping X = 3 mod 4 + */ + + X->p[0] |= 2; + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_int( &r, X, 3 ) ); + if( r == 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 8 ) ); + else if( r == 1 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 4 ) ); + + /* Set Y = (X-1) / 2, which is X / 2 because X is odd */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Y, X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &Y, 1 ) ); + + while( 1 ) + { + /* + * First, check small factors for X and Y + * before doing Miller-Rabin on any of them + */ + if( ( ret = mpi_check_small_factors( X ) ) == 0 && + ( ret = mpi_check_small_factors( &Y ) ) == 0 && + ( ret = mpi_miller_rabin( X, f_rng, p_rng ) ) == 0 && + ( ret = mpi_miller_rabin( &Y, f_rng, p_rng ) ) == 0 ) + { + break; + } + + if( ret != MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ) + goto cleanup; + + /* + * Next candidates. We want to preserve Y = (X-1) / 2 and + * Y = 1 mod 2 and Y = 2 mod 3 (eq X = 3 mod 4 and X = 2 mod 3) + * so up Y by 6 and X by 12. + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( X, X, 12 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_int( &Y, &Y, 6 ) ); + } + } + +cleanup: + + mbedtls_mpi_free( &Y ); + + return( ret ); +} + +#endif /* MBEDTLS_GENPRIME */ + +#if defined(MBEDTLS_SELF_TEST) + +#define GCD_PAIR_COUNT 3 + +static const int gcd_pairs[GCD_PAIR_COUNT][3] = +{ + { 693, 609, 21 }, + { 1764, 868, 28 }, + { 768454923, 542167814, 1 } +}; + +/* + * Checkup routine + */ +int mbedtls_mpi_self_test( int verbose ) +{ + int ret, i; + mbedtls_mpi A, E, N, X, Y, U, V; + + mbedtls_mpi_init( &A ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &N ); mbedtls_mpi_init( &X ); + mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &U ); mbedtls_mpi_init( &V ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &A, 16, + "EFE021C2645FD1DC586E69184AF4A31E" \ + "D5F53E93B5F123FA41680867BA110131" \ + "944FE7952E2517337780CB0DB80E61AA" \ + "E7C8DDC6C5C6AADEB34EB38A2F40D5E6" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &E, 16, + "B2E7EFD37075B9F03FF989C7C5051C20" \ + "34D2A323810251127E7BF8625A4F49A5" \ + "F3E27F4DA8BD59C47D6DAABA4C8127BD" \ + "5B5C25763222FEFCCFC38B832366C29E" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &N, 16, + "0066A198186C18C10B2F5ED9B522752A" \ + "9830B69916E535C8F047518A889A43A5" \ + "94B6BED27A168D31D4A52F88925AA8F5" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "602AB7ECA597A3D6B56FF9829A5E8B85" \ + "9E857EA95A03512E2BAE7391688D264A" \ + "A5663B0341DB9CCFD2C4C5F421FEC814" \ + "8001B72E848A38CAE1C65F78E56ABDEF" \ + "E12D3C039B8A02D6BE593F0BBBDA56F1" \ + "ECF677152EF804370C1A305CAF3B5BF1" \ + "30879B56C61DE584A0F53A2447A51E" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #1 (mul_mpi): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &X, &Y, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "256567336059E52CAE22925474705F39A94" ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &V, 16, + "6613F26162223DF488E9CD48CC132C7A" \ + "0AC93C701B001B092E4E5B9F73BCD27B" \ + "9EE50D0657C77F374E903CDFA4C642" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #2 (div_mpi): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 || + mbedtls_mpi_cmp_mpi( &Y, &V ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &X, &A, &E, &N, NULL ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "36E139AEA55215609D2816998ED020BB" \ + "BD96C37890F65171D948E9BC7CBAA4D9" \ + "325D24D6A3C12710F10A09FA08AB87" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #3 (exp_mod): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &X, &A, &N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &U, 16, + "003A0AAEDD7E784FC07D8F9EC6E3BFD5" \ + "C3DBA76456363A10869622EAC2DD84EC" \ + "C5B8A74DAC4D09E03B5E0BE779F2DF61" ) ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #4 (inv_mod): " ); + + if( mbedtls_mpi_cmp_mpi( &X, &U ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " MPI test #5 (simple gcd): " ); + + for( i = 0; i < GCD_PAIR_COUNT; i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &X, gcd_pairs[i][0] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &Y, gcd_pairs[i][1] ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &A, &X, &Y ) ); + + if( mbedtls_mpi_cmp_int( &A, gcd_pairs[i][2] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed at %d\n", i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + + if( ret != 0 && verbose != 0 ) + mbedtls_printf( "Unexpected error, return code = %08X\n", ret ); + + mbedtls_mpi_free( &A ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &N ); mbedtls_mpi_free( &X ); + mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &U ); mbedtls_mpi_free( &V ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_BIGNUM_C */ diff --git a/c++/src/connect/mbedtls/blowfish.c b/c++/src/connect/mbedtls/blowfish.c new file mode 100644 index 00000000..9003f0df --- /dev/null +++ b/c++/src/connect/mbedtls/blowfish.c @@ -0,0 +1,656 @@ +/* + * Blowfish implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The Blowfish block cipher was designed by Bruce Schneier in 1993. + * http://www.schneier.com/blowfish.html + * http://en.wikipedia.org/wiki/Blowfish_%28cipher%29 + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_BLOWFISH_C) + +#include "mbedtls/blowfish.h" + +#include + +#if !defined(MBEDTLS_BLOWFISH_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +static const uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2] = { + 0x243F6A88L, 0x85A308D3L, 0x13198A2EL, 0x03707344L, + 0xA4093822L, 0x299F31D0L, 0x082EFA98L, 0xEC4E6C89L, + 0x452821E6L, 0x38D01377L, 0xBE5466CFL, 0x34E90C6CL, + 0xC0AC29B7L, 0xC97C50DDL, 0x3F84D5B5L, 0xB5470917L, + 0x9216D5D9L, 0x8979FB1BL +}; + +/* declarations of data at the end of this file */ +static const uint32_t S[4][256]; + +static uint32_t F( mbedtls_blowfish_context *ctx, uint32_t x ) +{ + unsigned short a, b, c, d; + uint32_t y; + + d = (unsigned short)(x & 0xFF); + x >>= 8; + c = (unsigned short)(x & 0xFF); + x >>= 8; + b = (unsigned short)(x & 0xFF); + x >>= 8; + a = (unsigned short)(x & 0xFF); + y = ctx->S[0][a] + ctx->S[1][b]; + y = y ^ ctx->S[2][c]; + y = y + ctx->S[3][d]; + + return( y ); +} + +static void blowfish_enc( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr ) +{ + uint32_t Xl, Xr, temp; + short i; + + Xl = *xl; + Xr = *xr; + + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS; ++i ) + { + Xl = Xl ^ ctx->P[i]; + Xr = F( ctx, Xl ) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS]; + Xl = Xl ^ ctx->P[MBEDTLS_BLOWFISH_ROUNDS + 1]; + + *xl = Xl; + *xr = Xr; +} + +static void blowfish_dec( mbedtls_blowfish_context *ctx, uint32_t *xl, uint32_t *xr ) +{ + uint32_t Xl, Xr, temp; + short i; + + Xl = *xl; + Xr = *xr; + + for( i = MBEDTLS_BLOWFISH_ROUNDS + 1; i > 1; --i ) + { + Xl = Xl ^ ctx->P[i]; + Xr = F( ctx, Xl ) ^ Xr; + + temp = Xl; + Xl = Xr; + Xr = temp; + } + + temp = Xl; + Xl = Xr; + Xr = temp; + + Xr = Xr ^ ctx->P[1]; + Xl = Xl ^ ctx->P[0]; + + *xl = Xl; + *xr = Xr; +} + +void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_blowfish_context ) ); +} + +void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_blowfish_context ) ); +} + +/* + * Blowfish key schedule + */ +int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + unsigned int i, j, k; + uint32_t data, datal, datar; + + if( keybits < MBEDTLS_BLOWFISH_MIN_KEY_BITS || keybits > MBEDTLS_BLOWFISH_MAX_KEY_BITS || + ( keybits % 8 ) ) + { + return( MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH ); + } + + keybits >>= 3; + + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < 256; j++ ) + ctx->S[i][j] = S[i][j]; + } + + j = 0; + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; ++i ) + { + data = 0x00000000; + for( k = 0; k < 4; ++k ) + { + data = ( data << 8 ) | key[j++]; + if( j >= keybits ) + j = 0; + } + ctx->P[i] = P[i] ^ data; + } + + datal = 0x00000000; + datar = 0x00000000; + + for( i = 0; i < MBEDTLS_BLOWFISH_ROUNDS + 2; i += 2 ) + { + blowfish_enc( ctx, &datal, &datar ); + ctx->P[i] = datal; + ctx->P[i + 1] = datar; + } + + for( i = 0; i < 4; i++ ) + { + for( j = 0; j < 256; j += 2 ) + { + blowfish_enc( ctx, &datal, &datar ); + ctx->S[i][j] = datal; + ctx->S[i][j + 1] = datar; + } + } + return( 0 ); +} + +/* + * Blowfish-ECB block encryption/decryption + */ +int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, + int mode, + const unsigned char input[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char output[MBEDTLS_BLOWFISH_BLOCKSIZE] ) +{ + uint32_t X0, X1; + + GET_UINT32_BE( X0, input, 0 ); + GET_UINT32_BE( X1, input, 4 ); + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + blowfish_dec( ctx, &X0, &X1 ); + } + else /* MBEDTLS_BLOWFISH_ENCRYPT */ + { + blowfish_enc( ctx, &X0, &X1 ); + } + + PUT_UINT32_BE( X0, output, 0 ); + PUT_UINT32_BE( X1, output, 4 ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * Blowfish-CBC buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[MBEDTLS_BLOWFISH_BLOCKSIZE]; + + if( length % MBEDTLS_BLOWFISH_BLOCKSIZE ) + return( MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, MBEDTLS_BLOWFISH_BLOCKSIZE ); + mbedtls_blowfish_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE;i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, MBEDTLS_BLOWFISH_BLOCKSIZE ); + + input += MBEDTLS_BLOWFISH_BLOCKSIZE; + output += MBEDTLS_BLOWFISH_BLOCKSIZE; + length -= MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < MBEDTLS_BLOWFISH_BLOCKSIZE; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_blowfish_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, MBEDTLS_BLOWFISH_BLOCKSIZE ); + + input += MBEDTLS_BLOWFISH_BLOCKSIZE; + output += MBEDTLS_BLOWFISH_BLOCKSIZE; + length -= MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * Blowfish CFB buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == MBEDTLS_BLOWFISH_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Blowfish CTR buffer encryption/decryption + */ +int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + mbedtls_blowfish_crypt_ecb( ctx, MBEDTLS_BLOWFISH_ENCRYPT, nonce_counter, + stream_block ); + + for( i = MBEDTLS_BLOWFISH_BLOCKSIZE; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) % MBEDTLS_BLOWFISH_BLOCKSIZE; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static const uint32_t S[4][256] = { + { 0xD1310BA6L, 0x98DFB5ACL, 0x2FFD72DBL, 0xD01ADFB7L, + 0xB8E1AFEDL, 0x6A267E96L, 0xBA7C9045L, 0xF12C7F99L, + 0x24A19947L, 0xB3916CF7L, 0x0801F2E2L, 0x858EFC16L, + 0x636920D8L, 0x71574E69L, 0xA458FEA3L, 0xF4933D7EL, + 0x0D95748FL, 0x728EB658L, 0x718BCD58L, 0x82154AEEL, + 0x7B54A41DL, 0xC25A59B5L, 0x9C30D539L, 0x2AF26013L, + 0xC5D1B023L, 0x286085F0L, 0xCA417918L, 0xB8DB38EFL, + 0x8E79DCB0L, 0x603A180EL, 0x6C9E0E8BL, 0xB01E8A3EL, + 0xD71577C1L, 0xBD314B27L, 0x78AF2FDAL, 0x55605C60L, + 0xE65525F3L, 0xAA55AB94L, 0x57489862L, 0x63E81440L, + 0x55CA396AL, 0x2AAB10B6L, 0xB4CC5C34L, 0x1141E8CEL, + 0xA15486AFL, 0x7C72E993L, 0xB3EE1411L, 0x636FBC2AL, + 0x2BA9C55DL, 0x741831F6L, 0xCE5C3E16L, 0x9B87931EL, + 0xAFD6BA33L, 0x6C24CF5CL, 0x7A325381L, 0x28958677L, + 0x3B8F4898L, 0x6B4BB9AFL, 0xC4BFE81BL, 0x66282193L, + 0x61D809CCL, 0xFB21A991L, 0x487CAC60L, 0x5DEC8032L, + 0xEF845D5DL, 0xE98575B1L, 0xDC262302L, 0xEB651B88L, + 0x23893E81L, 0xD396ACC5L, 0x0F6D6FF3L, 0x83F44239L, + 0x2E0B4482L, 0xA4842004L, 0x69C8F04AL, 0x9E1F9B5EL, + 0x21C66842L, 0xF6E96C9AL, 0x670C9C61L, 0xABD388F0L, + 0x6A51A0D2L, 0xD8542F68L, 0x960FA728L, 0xAB5133A3L, + 0x6EEF0B6CL, 0x137A3BE4L, 0xBA3BF050L, 0x7EFB2A98L, + 0xA1F1651DL, 0x39AF0176L, 0x66CA593EL, 0x82430E88L, + 0x8CEE8619L, 0x456F9FB4L, 0x7D84A5C3L, 0x3B8B5EBEL, + 0xE06F75D8L, 0x85C12073L, 0x401A449FL, 0x56C16AA6L, + 0x4ED3AA62L, 0x363F7706L, 0x1BFEDF72L, 0x429B023DL, + 0x37D0D724L, 0xD00A1248L, 0xDB0FEAD3L, 0x49F1C09BL, + 0x075372C9L, 0x80991B7BL, 0x25D479D8L, 0xF6E8DEF7L, + 0xE3FE501AL, 0xB6794C3BL, 0x976CE0BDL, 0x04C006BAL, + 0xC1A94FB6L, 0x409F60C4L, 0x5E5C9EC2L, 0x196A2463L, + 0x68FB6FAFL, 0x3E6C53B5L, 0x1339B2EBL, 0x3B52EC6FL, + 0x6DFC511FL, 0x9B30952CL, 0xCC814544L, 0xAF5EBD09L, + 0xBEE3D004L, 0xDE334AFDL, 0x660F2807L, 0x192E4BB3L, + 0xC0CBA857L, 0x45C8740FL, 0xD20B5F39L, 0xB9D3FBDBL, + 0x5579C0BDL, 0x1A60320AL, 0xD6A100C6L, 0x402C7279L, + 0x679F25FEL, 0xFB1FA3CCL, 0x8EA5E9F8L, 0xDB3222F8L, + 0x3C7516DFL, 0xFD616B15L, 0x2F501EC8L, 0xAD0552ABL, + 0x323DB5FAL, 0xFD238760L, 0x53317B48L, 0x3E00DF82L, + 0x9E5C57BBL, 0xCA6F8CA0L, 0x1A87562EL, 0xDF1769DBL, + 0xD542A8F6L, 0x287EFFC3L, 0xAC6732C6L, 0x8C4F5573L, + 0x695B27B0L, 0xBBCA58C8L, 0xE1FFA35DL, 0xB8F011A0L, + 0x10FA3D98L, 0xFD2183B8L, 0x4AFCB56CL, 0x2DD1D35BL, + 0x9A53E479L, 0xB6F84565L, 0xD28E49BCL, 0x4BFB9790L, + 0xE1DDF2DAL, 0xA4CB7E33L, 0x62FB1341L, 0xCEE4C6E8L, + 0xEF20CADAL, 0x36774C01L, 0xD07E9EFEL, 0x2BF11FB4L, + 0x95DBDA4DL, 0xAE909198L, 0xEAAD8E71L, 0x6B93D5A0L, + 0xD08ED1D0L, 0xAFC725E0L, 0x8E3C5B2FL, 0x8E7594B7L, + 0x8FF6E2FBL, 0xF2122B64L, 0x8888B812L, 0x900DF01CL, + 0x4FAD5EA0L, 0x688FC31CL, 0xD1CFF191L, 0xB3A8C1ADL, + 0x2F2F2218L, 0xBE0E1777L, 0xEA752DFEL, 0x8B021FA1L, + 0xE5A0CC0FL, 0xB56F74E8L, 0x18ACF3D6L, 0xCE89E299L, + 0xB4A84FE0L, 0xFD13E0B7L, 0x7CC43B81L, 0xD2ADA8D9L, + 0x165FA266L, 0x80957705L, 0x93CC7314L, 0x211A1477L, + 0xE6AD2065L, 0x77B5FA86L, 0xC75442F5L, 0xFB9D35CFL, + 0xEBCDAF0CL, 0x7B3E89A0L, 0xD6411BD3L, 0xAE1E7E49L, + 0x00250E2DL, 0x2071B35EL, 0x226800BBL, 0x57B8E0AFL, + 0x2464369BL, 0xF009B91EL, 0x5563911DL, 0x59DFA6AAL, + 0x78C14389L, 0xD95A537FL, 0x207D5BA2L, 0x02E5B9C5L, + 0x83260376L, 0x6295CFA9L, 0x11C81968L, 0x4E734A41L, + 0xB3472DCAL, 0x7B14A94AL, 0x1B510052L, 0x9A532915L, + 0xD60F573FL, 0xBC9BC6E4L, 0x2B60A476L, 0x81E67400L, + 0x08BA6FB5L, 0x571BE91FL, 0xF296EC6BL, 0x2A0DD915L, + 0xB6636521L, 0xE7B9F9B6L, 0xFF34052EL, 0xC5855664L, + 0x53B02D5DL, 0xA99F8FA1L, 0x08BA4799L, 0x6E85076AL }, + { 0x4B7A70E9L, 0xB5B32944L, 0xDB75092EL, 0xC4192623L, + 0xAD6EA6B0L, 0x49A7DF7DL, 0x9CEE60B8L, 0x8FEDB266L, + 0xECAA8C71L, 0x699A17FFL, 0x5664526CL, 0xC2B19EE1L, + 0x193602A5L, 0x75094C29L, 0xA0591340L, 0xE4183A3EL, + 0x3F54989AL, 0x5B429D65L, 0x6B8FE4D6L, 0x99F73FD6L, + 0xA1D29C07L, 0xEFE830F5L, 0x4D2D38E6L, 0xF0255DC1L, + 0x4CDD2086L, 0x8470EB26L, 0x6382E9C6L, 0x021ECC5EL, + 0x09686B3FL, 0x3EBAEFC9L, 0x3C971814L, 0x6B6A70A1L, + 0x687F3584L, 0x52A0E286L, 0xB79C5305L, 0xAA500737L, + 0x3E07841CL, 0x7FDEAE5CL, 0x8E7D44ECL, 0x5716F2B8L, + 0xB03ADA37L, 0xF0500C0DL, 0xF01C1F04L, 0x0200B3FFL, + 0xAE0CF51AL, 0x3CB574B2L, 0x25837A58L, 0xDC0921BDL, + 0xD19113F9L, 0x7CA92FF6L, 0x94324773L, 0x22F54701L, + 0x3AE5E581L, 0x37C2DADCL, 0xC8B57634L, 0x9AF3DDA7L, + 0xA9446146L, 0x0FD0030EL, 0xECC8C73EL, 0xA4751E41L, + 0xE238CD99L, 0x3BEA0E2FL, 0x3280BBA1L, 0x183EB331L, + 0x4E548B38L, 0x4F6DB908L, 0x6F420D03L, 0xF60A04BFL, + 0x2CB81290L, 0x24977C79L, 0x5679B072L, 0xBCAF89AFL, + 0xDE9A771FL, 0xD9930810L, 0xB38BAE12L, 0xDCCF3F2EL, + 0x5512721FL, 0x2E6B7124L, 0x501ADDE6L, 0x9F84CD87L, + 0x7A584718L, 0x7408DA17L, 0xBC9F9ABCL, 0xE94B7D8CL, + 0xEC7AEC3AL, 0xDB851DFAL, 0x63094366L, 0xC464C3D2L, + 0xEF1C1847L, 0x3215D908L, 0xDD433B37L, 0x24C2BA16L, + 0x12A14D43L, 0x2A65C451L, 0x50940002L, 0x133AE4DDL, + 0x71DFF89EL, 0x10314E55L, 0x81AC77D6L, 0x5F11199BL, + 0x043556F1L, 0xD7A3C76BL, 0x3C11183BL, 0x5924A509L, + 0xF28FE6EDL, 0x97F1FBFAL, 0x9EBABF2CL, 0x1E153C6EL, + 0x86E34570L, 0xEAE96FB1L, 0x860E5E0AL, 0x5A3E2AB3L, + 0x771FE71CL, 0x4E3D06FAL, 0x2965DCB9L, 0x99E71D0FL, + 0x803E89D6L, 0x5266C825L, 0x2E4CC978L, 0x9C10B36AL, + 0xC6150EBAL, 0x94E2EA78L, 0xA5FC3C53L, 0x1E0A2DF4L, + 0xF2F74EA7L, 0x361D2B3DL, 0x1939260FL, 0x19C27960L, + 0x5223A708L, 0xF71312B6L, 0xEBADFE6EL, 0xEAC31F66L, + 0xE3BC4595L, 0xA67BC883L, 0xB17F37D1L, 0x018CFF28L, + 0xC332DDEFL, 0xBE6C5AA5L, 0x65582185L, 0x68AB9802L, + 0xEECEA50FL, 0xDB2F953BL, 0x2AEF7DADL, 0x5B6E2F84L, + 0x1521B628L, 0x29076170L, 0xECDD4775L, 0x619F1510L, + 0x13CCA830L, 0xEB61BD96L, 0x0334FE1EL, 0xAA0363CFL, + 0xB5735C90L, 0x4C70A239L, 0xD59E9E0BL, 0xCBAADE14L, + 0xEECC86BCL, 0x60622CA7L, 0x9CAB5CABL, 0xB2F3846EL, + 0x648B1EAFL, 0x19BDF0CAL, 0xA02369B9L, 0x655ABB50L, + 0x40685A32L, 0x3C2AB4B3L, 0x319EE9D5L, 0xC021B8F7L, + 0x9B540B19L, 0x875FA099L, 0x95F7997EL, 0x623D7DA8L, + 0xF837889AL, 0x97E32D77L, 0x11ED935FL, 0x16681281L, + 0x0E358829L, 0xC7E61FD6L, 0x96DEDFA1L, 0x7858BA99L, + 0x57F584A5L, 0x1B227263L, 0x9B83C3FFL, 0x1AC24696L, + 0xCDB30AEBL, 0x532E3054L, 0x8FD948E4L, 0x6DBC3128L, + 0x58EBF2EFL, 0x34C6FFEAL, 0xFE28ED61L, 0xEE7C3C73L, + 0x5D4A14D9L, 0xE864B7E3L, 0x42105D14L, 0x203E13E0L, + 0x45EEE2B6L, 0xA3AAABEAL, 0xDB6C4F15L, 0xFACB4FD0L, + 0xC742F442L, 0xEF6ABBB5L, 0x654F3B1DL, 0x41CD2105L, + 0xD81E799EL, 0x86854DC7L, 0xE44B476AL, 0x3D816250L, + 0xCF62A1F2L, 0x5B8D2646L, 0xFC8883A0L, 0xC1C7B6A3L, + 0x7F1524C3L, 0x69CB7492L, 0x47848A0BL, 0x5692B285L, + 0x095BBF00L, 0xAD19489DL, 0x1462B174L, 0x23820E00L, + 0x58428D2AL, 0x0C55F5EAL, 0x1DADF43EL, 0x233F7061L, + 0x3372F092L, 0x8D937E41L, 0xD65FECF1L, 0x6C223BDBL, + 0x7CDE3759L, 0xCBEE7460L, 0x4085F2A7L, 0xCE77326EL, + 0xA6078084L, 0x19F8509EL, 0xE8EFD855L, 0x61D99735L, + 0xA969A7AAL, 0xC50C06C2L, 0x5A04ABFCL, 0x800BCADCL, + 0x9E447A2EL, 0xC3453484L, 0xFDD56705L, 0x0E1E9EC9L, + 0xDB73DBD3L, 0x105588CDL, 0x675FDA79L, 0xE3674340L, + 0xC5C43465L, 0x713E38D8L, 0x3D28F89EL, 0xF16DFF20L, + 0x153E21E7L, 0x8FB03D4AL, 0xE6E39F2BL, 0xDB83ADF7L }, + { 0xE93D5A68L, 0x948140F7L, 0xF64C261CL, 0x94692934L, + 0x411520F7L, 0x7602D4F7L, 0xBCF46B2EL, 0xD4A20068L, + 0xD4082471L, 0x3320F46AL, 0x43B7D4B7L, 0x500061AFL, + 0x1E39F62EL, 0x97244546L, 0x14214F74L, 0xBF8B8840L, + 0x4D95FC1DL, 0x96B591AFL, 0x70F4DDD3L, 0x66A02F45L, + 0xBFBC09ECL, 0x03BD9785L, 0x7FAC6DD0L, 0x31CB8504L, + 0x96EB27B3L, 0x55FD3941L, 0xDA2547E6L, 0xABCA0A9AL, + 0x28507825L, 0x530429F4L, 0x0A2C86DAL, 0xE9B66DFBL, + 0x68DC1462L, 0xD7486900L, 0x680EC0A4L, 0x27A18DEEL, + 0x4F3FFEA2L, 0xE887AD8CL, 0xB58CE006L, 0x7AF4D6B6L, + 0xAACE1E7CL, 0xD3375FECL, 0xCE78A399L, 0x406B2A42L, + 0x20FE9E35L, 0xD9F385B9L, 0xEE39D7ABL, 0x3B124E8BL, + 0x1DC9FAF7L, 0x4B6D1856L, 0x26A36631L, 0xEAE397B2L, + 0x3A6EFA74L, 0xDD5B4332L, 0x6841E7F7L, 0xCA7820FBL, + 0xFB0AF54EL, 0xD8FEB397L, 0x454056ACL, 0xBA489527L, + 0x55533A3AL, 0x20838D87L, 0xFE6BA9B7L, 0xD096954BL, + 0x55A867BCL, 0xA1159A58L, 0xCCA92963L, 0x99E1DB33L, + 0xA62A4A56L, 0x3F3125F9L, 0x5EF47E1CL, 0x9029317CL, + 0xFDF8E802L, 0x04272F70L, 0x80BB155CL, 0x05282CE3L, + 0x95C11548L, 0xE4C66D22L, 0x48C1133FL, 0xC70F86DCL, + 0x07F9C9EEL, 0x41041F0FL, 0x404779A4L, 0x5D886E17L, + 0x325F51EBL, 0xD59BC0D1L, 0xF2BCC18FL, 0x41113564L, + 0x257B7834L, 0x602A9C60L, 0xDFF8E8A3L, 0x1F636C1BL, + 0x0E12B4C2L, 0x02E1329EL, 0xAF664FD1L, 0xCAD18115L, + 0x6B2395E0L, 0x333E92E1L, 0x3B240B62L, 0xEEBEB922L, + 0x85B2A20EL, 0xE6BA0D99L, 0xDE720C8CL, 0x2DA2F728L, + 0xD0127845L, 0x95B794FDL, 0x647D0862L, 0xE7CCF5F0L, + 0x5449A36FL, 0x877D48FAL, 0xC39DFD27L, 0xF33E8D1EL, + 0x0A476341L, 0x992EFF74L, 0x3A6F6EABL, 0xF4F8FD37L, + 0xA812DC60L, 0xA1EBDDF8L, 0x991BE14CL, 0xDB6E6B0DL, + 0xC67B5510L, 0x6D672C37L, 0x2765D43BL, 0xDCD0E804L, + 0xF1290DC7L, 0xCC00FFA3L, 0xB5390F92L, 0x690FED0BL, + 0x667B9FFBL, 0xCEDB7D9CL, 0xA091CF0BL, 0xD9155EA3L, + 0xBB132F88L, 0x515BAD24L, 0x7B9479BFL, 0x763BD6EBL, + 0x37392EB3L, 0xCC115979L, 0x8026E297L, 0xF42E312DL, + 0x6842ADA7L, 0xC66A2B3BL, 0x12754CCCL, 0x782EF11CL, + 0x6A124237L, 0xB79251E7L, 0x06A1BBE6L, 0x4BFB6350L, + 0x1A6B1018L, 0x11CAEDFAL, 0x3D25BDD8L, 0xE2E1C3C9L, + 0x44421659L, 0x0A121386L, 0xD90CEC6EL, 0xD5ABEA2AL, + 0x64AF674EL, 0xDA86A85FL, 0xBEBFE988L, 0x64E4C3FEL, + 0x9DBC8057L, 0xF0F7C086L, 0x60787BF8L, 0x6003604DL, + 0xD1FD8346L, 0xF6381FB0L, 0x7745AE04L, 0xD736FCCCL, + 0x83426B33L, 0xF01EAB71L, 0xB0804187L, 0x3C005E5FL, + 0x77A057BEL, 0xBDE8AE24L, 0x55464299L, 0xBF582E61L, + 0x4E58F48FL, 0xF2DDFDA2L, 0xF474EF38L, 0x8789BDC2L, + 0x5366F9C3L, 0xC8B38E74L, 0xB475F255L, 0x46FCD9B9L, + 0x7AEB2661L, 0x8B1DDF84L, 0x846A0E79L, 0x915F95E2L, + 0x466E598EL, 0x20B45770L, 0x8CD55591L, 0xC902DE4CL, + 0xB90BACE1L, 0xBB8205D0L, 0x11A86248L, 0x7574A99EL, + 0xB77F19B6L, 0xE0A9DC09L, 0x662D09A1L, 0xC4324633L, + 0xE85A1F02L, 0x09F0BE8CL, 0x4A99A025L, 0x1D6EFE10L, + 0x1AB93D1DL, 0x0BA5A4DFL, 0xA186F20FL, 0x2868F169L, + 0xDCB7DA83L, 0x573906FEL, 0xA1E2CE9BL, 0x4FCD7F52L, + 0x50115E01L, 0xA70683FAL, 0xA002B5C4L, 0x0DE6D027L, + 0x9AF88C27L, 0x773F8641L, 0xC3604C06L, 0x61A806B5L, + 0xF0177A28L, 0xC0F586E0L, 0x006058AAL, 0x30DC7D62L, + 0x11E69ED7L, 0x2338EA63L, 0x53C2DD94L, 0xC2C21634L, + 0xBBCBEE56L, 0x90BCB6DEL, 0xEBFC7DA1L, 0xCE591D76L, + 0x6F05E409L, 0x4B7C0188L, 0x39720A3DL, 0x7C927C24L, + 0x86E3725FL, 0x724D9DB9L, 0x1AC15BB4L, 0xD39EB8FCL, + 0xED545578L, 0x08FCA5B5L, 0xD83D7CD3L, 0x4DAD0FC4L, + 0x1E50EF5EL, 0xB161E6F8L, 0xA28514D9L, 0x6C51133CL, + 0x6FD5C7E7L, 0x56E14EC4L, 0x362ABFCEL, 0xDDC6C837L, + 0xD79A3234L, 0x92638212L, 0x670EFA8EL, 0x406000E0L }, + { 0x3A39CE37L, 0xD3FAF5CFL, 0xABC27737L, 0x5AC52D1BL, + 0x5CB0679EL, 0x4FA33742L, 0xD3822740L, 0x99BC9BBEL, + 0xD5118E9DL, 0xBF0F7315L, 0xD62D1C7EL, 0xC700C47BL, + 0xB78C1B6BL, 0x21A19045L, 0xB26EB1BEL, 0x6A366EB4L, + 0x5748AB2FL, 0xBC946E79L, 0xC6A376D2L, 0x6549C2C8L, + 0x530FF8EEL, 0x468DDE7DL, 0xD5730A1DL, 0x4CD04DC6L, + 0x2939BBDBL, 0xA9BA4650L, 0xAC9526E8L, 0xBE5EE304L, + 0xA1FAD5F0L, 0x6A2D519AL, 0x63EF8CE2L, 0x9A86EE22L, + 0xC089C2B8L, 0x43242EF6L, 0xA51E03AAL, 0x9CF2D0A4L, + 0x83C061BAL, 0x9BE96A4DL, 0x8FE51550L, 0xBA645BD6L, + 0x2826A2F9L, 0xA73A3AE1L, 0x4BA99586L, 0xEF5562E9L, + 0xC72FEFD3L, 0xF752F7DAL, 0x3F046F69L, 0x77FA0A59L, + 0x80E4A915L, 0x87B08601L, 0x9B09E6ADL, 0x3B3EE593L, + 0xE990FD5AL, 0x9E34D797L, 0x2CF0B7D9L, 0x022B8B51L, + 0x96D5AC3AL, 0x017DA67DL, 0xD1CF3ED6L, 0x7C7D2D28L, + 0x1F9F25CFL, 0xADF2B89BL, 0x5AD6B472L, 0x5A88F54CL, + 0xE029AC71L, 0xE019A5E6L, 0x47B0ACFDL, 0xED93FA9BL, + 0xE8D3C48DL, 0x283B57CCL, 0xF8D56629L, 0x79132E28L, + 0x785F0191L, 0xED756055L, 0xF7960E44L, 0xE3D35E8CL, + 0x15056DD4L, 0x88F46DBAL, 0x03A16125L, 0x0564F0BDL, + 0xC3EB9E15L, 0x3C9057A2L, 0x97271AECL, 0xA93A072AL, + 0x1B3F6D9BL, 0x1E6321F5L, 0xF59C66FBL, 0x26DCF319L, + 0x7533D928L, 0xB155FDF5L, 0x03563482L, 0x8ABA3CBBL, + 0x28517711L, 0xC20AD9F8L, 0xABCC5167L, 0xCCAD925FL, + 0x4DE81751L, 0x3830DC8EL, 0x379D5862L, 0x9320F991L, + 0xEA7A90C2L, 0xFB3E7BCEL, 0x5121CE64L, 0x774FBE32L, + 0xA8B6E37EL, 0xC3293D46L, 0x48DE5369L, 0x6413E680L, + 0xA2AE0810L, 0xDD6DB224L, 0x69852DFDL, 0x09072166L, + 0xB39A460AL, 0x6445C0DDL, 0x586CDECFL, 0x1C20C8AEL, + 0x5BBEF7DDL, 0x1B588D40L, 0xCCD2017FL, 0x6BB4E3BBL, + 0xDDA26A7EL, 0x3A59FF45L, 0x3E350A44L, 0xBCB4CDD5L, + 0x72EACEA8L, 0xFA6484BBL, 0x8D6612AEL, 0xBF3C6F47L, + 0xD29BE463L, 0x542F5D9EL, 0xAEC2771BL, 0xF64E6370L, + 0x740E0D8DL, 0xE75B1357L, 0xF8721671L, 0xAF537D5DL, + 0x4040CB08L, 0x4EB4E2CCL, 0x34D2466AL, 0x0115AF84L, + 0xE1B00428L, 0x95983A1DL, 0x06B89FB4L, 0xCE6EA048L, + 0x6F3F3B82L, 0x3520AB82L, 0x011A1D4BL, 0x277227F8L, + 0x611560B1L, 0xE7933FDCL, 0xBB3A792BL, 0x344525BDL, + 0xA08839E1L, 0x51CE794BL, 0x2F32C9B7L, 0xA01FBAC9L, + 0xE01CC87EL, 0xBCC7D1F6L, 0xCF0111C3L, 0xA1E8AAC7L, + 0x1A908749L, 0xD44FBD9AL, 0xD0DADECBL, 0xD50ADA38L, + 0x0339C32AL, 0xC6913667L, 0x8DF9317CL, 0xE0B12B4FL, + 0xF79E59B7L, 0x43F5BB3AL, 0xF2D519FFL, 0x27D9459CL, + 0xBF97222CL, 0x15E6FC2AL, 0x0F91FC71L, 0x9B941525L, + 0xFAE59361L, 0xCEB69CEBL, 0xC2A86459L, 0x12BAA8D1L, + 0xB6C1075EL, 0xE3056A0CL, 0x10D25065L, 0xCB03A442L, + 0xE0EC6E0EL, 0x1698DB3BL, 0x4C98A0BEL, 0x3278E964L, + 0x9F1F9532L, 0xE0D392DFL, 0xD3A0342BL, 0x8971F21EL, + 0x1B0A7441L, 0x4BA3348CL, 0xC5BE7120L, 0xC37632D8L, + 0xDF359F8DL, 0x9B992F2EL, 0xE60B6F47L, 0x0FE3F11DL, + 0xE54CDA54L, 0x1EDAD891L, 0xCE6279CFL, 0xCD3E7E6FL, + 0x1618B166L, 0xFD2C1D05L, 0x848FD2C5L, 0xF6FB2299L, + 0xF523F357L, 0xA6327623L, 0x93A83531L, 0x56CCCD02L, + 0xACF08162L, 0x5A75EBB5L, 0x6E163697L, 0x88D273CCL, + 0xDE966292L, 0x81B949D0L, 0x4C50901BL, 0x71C65614L, + 0xE6C6C7BDL, 0x327A140AL, 0x45E1D006L, 0xC3F27B9AL, + 0xC9AA53FDL, 0x62A80F00L, 0xBB25BFE2L, 0x35BDD2F6L, + 0x71126905L, 0xB2040222L, 0xB6CBCF7CL, 0xCD769C2BL, + 0x53113EC0L, 0x1640E3D3L, 0x38ABBD60L, 0x2547ADF0L, + 0xBA38209CL, 0xF746CE76L, 0x77AFA1C5L, 0x20756060L, + 0x85CBFE4EL, 0x8AE88DD8L, 0x7AAAF9B0L, 0x4CF9AA7EL, + 0x1948C25CL, 0x02FB8A8CL, 0x01C36AE4L, 0xD6EBE1F9L, + 0x90D4F869L, 0xA65CDEA0L, 0x3F09252DL, 0xC208E69FL, + 0xB74E6132L, 0xCE77E25BL, 0x578FDFE3L, 0x3AC372E6L } +}; + +#endif /* !MBEDTLS_BLOWFISH_ALT */ +#endif /* MBEDTLS_BLOWFISH_C */ diff --git a/c++/src/connect/mbedtls/camellia.c b/c++/src/connect/mbedtls/camellia.c new file mode 100644 index 00000000..ac6f96a8 --- /dev/null +++ b/c++/src/connect/mbedtls/camellia.c @@ -0,0 +1,1072 @@ +/* + * Camellia implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The Camellia block cipher was designed by NTT and Mitsubishi Electric + * Corporation. + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/01espec.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CAMELLIA_C) + +#include "mbedtls/camellia.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_CAMELLIA_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +static const unsigned char SIGMA_CHARS[6][8] = +{ + { 0xa0, 0x9e, 0x66, 0x7f, 0x3b, 0xcc, 0x90, 0x8b }, + { 0xb6, 0x7a, 0xe8, 0x58, 0x4c, 0xaa, 0x73, 0xb2 }, + { 0xc6, 0xef, 0x37, 0x2f, 0xe9, 0x4f, 0x82, 0xbe }, + { 0x54, 0xff, 0x53, 0xa5, 0xf1, 0xd3, 0x6f, 0x1c }, + { 0x10, 0xe5, 0x27, 0xfa, 0xde, 0x68, 0x2d, 0x1d }, + { 0xb0, 0x56, 0x88, 0xc2, 0xb3, 0xe6, 0xc1, 0xfd } +}; + +#if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY) + +static const unsigned char FSb[256] = +{ + 112,130, 44,236,179, 39,192,229,228,133, 87, 53,234, 12,174, 65, + 35,239,107,147, 69, 25,165, 33,237, 14, 79, 78, 29,101,146,189, + 134,184,175,143,124,235, 31,206, 62, 48,220, 95, 94,197, 11, 26, + 166,225, 57,202,213, 71, 93, 61,217, 1, 90,214, 81, 86,108, 77, + 139, 13,154,102,251,204,176, 45,116, 18, 43, 32,240,177,132,153, + 223, 76,203,194, 52,126,118, 5,109,183,169, 49,209, 23, 4,215, + 20, 88, 58, 97,222, 27, 17, 28, 50, 15,156, 22, 83, 24,242, 34, + 254, 68,207,178,195,181,122,145, 36, 8,232,168, 96,252,105, 80, + 170,208,160,125,161,137, 98,151, 84, 91, 30,149,224,255,100,210, + 16,196, 0, 72,163,247,117,219,138, 3,230,218, 9, 63,221,148, + 135, 92,131, 2,205, 74,144, 51,115,103,246,243,157,127,191,226, + 82,155,216, 38,200, 55,198, 59,129,150,111, 75, 19,190, 99, 46, + 233,121,167,140,159,110,188,142, 41,245,249,182, 47,253,180, 89, + 120,152, 6,106,231, 70,113,186,212, 37,171, 66,136,162,141,250, + 114, 7,185, 85,248,238,172, 10, 54, 73, 42,104, 60, 56,241,164, + 64, 40,211,123,187,201, 67,193, 21,227,173,244,119,199,128,158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) (unsigned char)((FSb[(n)] >> 7 ^ FSb[(n)] << 1) & 0xff) +#define SBOX3(n) (unsigned char)((FSb[(n)] >> 1 ^ FSb[(n)] << 7) & 0xff) +#define SBOX4(n) FSb[((n) << 1 ^ (n) >> 7) &0xff] + +#else /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ + +static const unsigned char FSb[256] = +{ + 112, 130, 44, 236, 179, 39, 192, 229, 228, 133, 87, 53, 234, 12, 174, 65, + 35, 239, 107, 147, 69, 25, 165, 33, 237, 14, 79, 78, 29, 101, 146, 189, + 134, 184, 175, 143, 124, 235, 31, 206, 62, 48, 220, 95, 94, 197, 11, 26, + 166, 225, 57, 202, 213, 71, 93, 61, 217, 1, 90, 214, 81, 86, 108, 77, + 139, 13, 154, 102, 251, 204, 176, 45, 116, 18, 43, 32, 240, 177, 132, 153, + 223, 76, 203, 194, 52, 126, 118, 5, 109, 183, 169, 49, 209, 23, 4, 215, + 20, 88, 58, 97, 222, 27, 17, 28, 50, 15, 156, 22, 83, 24, 242, 34, + 254, 68, 207, 178, 195, 181, 122, 145, 36, 8, 232, 168, 96, 252, 105, 80, + 170, 208, 160, 125, 161, 137, 98, 151, 84, 91, 30, 149, 224, 255, 100, 210, + 16, 196, 0, 72, 163, 247, 117, 219, 138, 3, 230, 218, 9, 63, 221, 148, + 135, 92, 131, 2, 205, 74, 144, 51, 115, 103, 246, 243, 157, 127, 191, 226, + 82, 155, 216, 38, 200, 55, 198, 59, 129, 150, 111, 75, 19, 190, 99, 46, + 233, 121, 167, 140, 159, 110, 188, 142, 41, 245, 249, 182, 47, 253, 180, 89, + 120, 152, 6, 106, 231, 70, 113, 186, 212, 37, 171, 66, 136, 162, 141, 250, + 114, 7, 185, 85, 248, 238, 172, 10, 54, 73, 42, 104, 60, 56, 241, 164, + 64, 40, 211, 123, 187, 201, 67, 193, 21, 227, 173, 244, 119, 199, 128, 158 +}; + +static const unsigned char FSb2[256] = +{ + 224, 5, 88, 217, 103, 78, 129, 203, 201, 11, 174, 106, 213, 24, 93, 130, + 70, 223, 214, 39, 138, 50, 75, 66, 219, 28, 158, 156, 58, 202, 37, 123, + 13, 113, 95, 31, 248, 215, 62, 157, 124, 96, 185, 190, 188, 139, 22, 52, + 77, 195, 114, 149, 171, 142, 186, 122, 179, 2, 180, 173, 162, 172, 216, 154, + 23, 26, 53, 204, 247, 153, 97, 90, 232, 36, 86, 64, 225, 99, 9, 51, + 191, 152, 151, 133, 104, 252, 236, 10, 218, 111, 83, 98, 163, 46, 8, 175, + 40, 176, 116, 194, 189, 54, 34, 56, 100, 30, 57, 44, 166, 48, 229, 68, + 253, 136, 159, 101, 135, 107, 244, 35, 72, 16, 209, 81, 192, 249, 210, 160, + 85, 161, 65, 250, 67, 19, 196, 47, 168, 182, 60, 43, 193, 255, 200, 165, + 32, 137, 0, 144, 71, 239, 234, 183, 21, 6, 205, 181, 18, 126, 187, 41, + 15, 184, 7, 4, 155, 148, 33, 102, 230, 206, 237, 231, 59, 254, 127, 197, + 164, 55, 177, 76, 145, 110, 141, 118, 3, 45, 222, 150, 38, 125, 198, 92, + 211, 242, 79, 25, 63, 220, 121, 29, 82, 235, 243, 109, 94, 251, 105, 178, + 240, 49, 12, 212, 207, 140, 226, 117, 169, 74, 87, 132, 17, 69, 27, 245, + 228, 14, 115, 170, 241, 221, 89, 20, 108, 146, 84, 208, 120, 112, 227, 73, + 128, 80, 167, 246, 119, 147, 134, 131, 42, 199, 91, 233, 238, 143, 1, 61 +}; + +static const unsigned char FSb3[256] = +{ + 56, 65, 22, 118, 217, 147, 96, 242, 114, 194, 171, 154, 117, 6, 87, 160, + 145, 247, 181, 201, 162, 140, 210, 144, 246, 7, 167, 39, 142, 178, 73, 222, + 67, 92, 215, 199, 62, 245, 143, 103, 31, 24, 110, 175, 47, 226, 133, 13, + 83, 240, 156, 101, 234, 163, 174, 158, 236, 128, 45, 107, 168, 43, 54, 166, + 197, 134, 77, 51, 253, 102, 88, 150, 58, 9, 149, 16, 120, 216, 66, 204, + 239, 38, 229, 97, 26, 63, 59, 130, 182, 219, 212, 152, 232, 139, 2, 235, + 10, 44, 29, 176, 111, 141, 136, 14, 25, 135, 78, 11, 169, 12, 121, 17, + 127, 34, 231, 89, 225, 218, 61, 200, 18, 4, 116, 84, 48, 126, 180, 40, + 85, 104, 80, 190, 208, 196, 49, 203, 42, 173, 15, 202, 112, 255, 50, 105, + 8, 98, 0, 36, 209, 251, 186, 237, 69, 129, 115, 109, 132, 159, 238, 74, + 195, 46, 193, 1, 230, 37, 72, 153, 185, 179, 123, 249, 206, 191, 223, 113, + 41, 205, 108, 19, 100, 155, 99, 157, 192, 75, 183, 165, 137, 95, 177, 23, + 244, 188, 211, 70, 207, 55, 94, 71, 148, 250, 252, 91, 151, 254, 90, 172, + 60, 76, 3, 53, 243, 35, 184, 93, 106, 146, 213, 33, 68, 81, 198, 125, + 57, 131, 220, 170, 124, 119, 86, 5, 27, 164, 21, 52, 30, 28, 248, 82, + 32, 20, 233, 189, 221, 228, 161, 224, 138, 241, 214, 122, 187, 227, 64, 79 +}; + +static const unsigned char FSb4[256] = +{ + 112, 44, 179, 192, 228, 87, 234, 174, 35, 107, 69, 165, 237, 79, 29, 146, + 134, 175, 124, 31, 62, 220, 94, 11, 166, 57, 213, 93, 217, 90, 81, 108, + 139, 154, 251, 176, 116, 43, 240, 132, 223, 203, 52, 118, 109, 169, 209, 4, + 20, 58, 222, 17, 50, 156, 83, 242, 254, 207, 195, 122, 36, 232, 96, 105, + 170, 160, 161, 98, 84, 30, 224, 100, 16, 0, 163, 117, 138, 230, 9, 221, + 135, 131, 205, 144, 115, 246, 157, 191, 82, 216, 200, 198, 129, 111, 19, 99, + 233, 167, 159, 188, 41, 249, 47, 180, 120, 6, 231, 113, 212, 171, 136, 141, + 114, 185, 248, 172, 54, 42, 60, 241, 64, 211, 187, 67, 21, 173, 119, 128, + 130, 236, 39, 229, 133, 53, 12, 65, 239, 147, 25, 33, 14, 78, 101, 189, + 184, 143, 235, 206, 48, 95, 197, 26, 225, 202, 71, 61, 1, 214, 86, 77, + 13, 102, 204, 45, 18, 32, 177, 153, 76, 194, 126, 5, 183, 49, 23, 215, + 88, 97, 27, 28, 15, 22, 24, 34, 68, 178, 181, 145, 8, 168, 252, 80, + 208, 125, 137, 151, 91, 149, 255, 210, 196, 72, 247, 219, 3, 218, 63, 148, + 92, 2, 74, 51, 103, 243, 127, 226, 155, 38, 55, 59, 150, 75, 190, 46, + 121, 140, 110, 142, 245, 182, 253, 89, 152, 106, 70, 186, 37, 66, 162, 250, + 7, 85, 238, 10, 73, 104, 56, 164, 40, 123, 201, 193, 227, 244, 199, 158 +}; + +#define SBOX1(n) FSb[(n)] +#define SBOX2(n) FSb2[(n)] +#define SBOX3(n) FSb3[(n)] +#define SBOX4(n) FSb4[(n)] + +#endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ + +static const unsigned char shifts[2][4][4] = +{ + { + { 1, 1, 1, 1 }, /* KL */ + { 0, 0, 0, 0 }, /* KR */ + { 1, 1, 1, 1 }, /* KA */ + { 0, 0, 0, 0 } /* KB */ + }, + { + { 1, 0, 1, 1 }, /* KL */ + { 1, 1, 0, 1 }, /* KR */ + { 1, 1, 1, 0 }, /* KA */ + { 1, 1, 0, 1 } /* KB */ + } +}; + +static const signed char indexes[2][4][20] = +{ + { + { 0, 1, 2, 3, 8, 9, 10, 11, 38, 39, + 36, 37, 23, 20, 21, 22, 27, -1, -1, 26 }, /* KL -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, /* KR -> RK */ + { 4, 5, 6, 7, 12, 13, 14, 15, 16, 17, + 18, 19, -1, 24, 25, -1, 31, 28, 29, 30 }, /* KA -> RK */ + { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } /* KB -> RK */ + }, + { + { 0, 1, 2, 3, 61, 62, 63, 60, -1, -1, + -1, -1, 27, 24, 25, 26, 35, 32, 33, 34 }, /* KL -> RK */ + { -1, -1, -1, -1, 8, 9, 10, 11, 16, 17, + 18, 19, -1, -1, -1, -1, 39, 36, 37, 38 }, /* KR -> RK */ + { -1, -1, -1, -1, 12, 13, 14, 15, 58, 59, + 56, 57, 31, 28, 29, 30, -1, -1, -1, -1 }, /* KA -> RK */ + { 4, 5, 6, 7, 65, 66, 67, 64, 20, 21, + 22, 23, -1, -1, -1, -1, 43, 40, 41, 42 } /* KB -> RK */ + } +}; + +static const signed char transposes[2][20] = +{ + { + 21, 22, 23, 20, + -1, -1, -1, -1, + 18, 19, 16, 17, + 11, 8, 9, 10, + 15, 12, 13, 14 + }, + { + 25, 26, 27, 24, + 29, 30, 31, 28, + 18, 19, 16, 17, + -1, -1, -1, -1, + -1, -1, -1, -1 + } +}; + +/* Shift macro for 128 bit strings with rotation smaller than 32 bits (!) */ +#define ROTL(DEST, SRC, SHIFT) \ +{ \ + (DEST)[0] = (SRC)[0] << (SHIFT) ^ (SRC)[1] >> (32 - (SHIFT)); \ + (DEST)[1] = (SRC)[1] << (SHIFT) ^ (SRC)[2] >> (32 - (SHIFT)); \ + (DEST)[2] = (SRC)[2] << (SHIFT) ^ (SRC)[3] >> (32 - (SHIFT)); \ + (DEST)[3] = (SRC)[3] << (SHIFT) ^ (SRC)[0] >> (32 - (SHIFT)); \ +} + +#define FL(XL, XR, KL, KR) \ +{ \ + (XR) = ((((XL) & (KL)) << 1) | (((XL) & (KL)) >> 31)) ^ (XR); \ + (XL) = ((XR) | (KR)) ^ (XL); \ +} + +#define FLInv(YL, YR, KL, KR) \ +{ \ + (YL) = ((YR) | (KR)) ^ (YL); \ + (YR) = ((((YL) & (KL)) << 1) | (((YL) & (KL)) >> 31)) ^ (YR); \ +} + +#define SHIFT_AND_PLACE(INDEX, OFFSET) \ +{ \ + TK[0] = KC[(OFFSET) * 4 + 0]; \ + TK[1] = KC[(OFFSET) * 4 + 1]; \ + TK[2] = KC[(OFFSET) * 4 + 2]; \ + TK[3] = KC[(OFFSET) * 4 + 3]; \ + \ + for( i = 1; i <= 4; i++ ) \ + if( shifts[(INDEX)][(OFFSET)][i -1] ) \ + ROTL(TK + i * 4, TK, ( 15 * i ) % 32); \ + \ + for( i = 0; i < 20; i++ ) \ + if( indexes[(INDEX)][(OFFSET)][i] != -1 ) { \ + RK[indexes[(INDEX)][(OFFSET)][i]] = TK[ i ]; \ + } \ +} + +static void camellia_feistel( const uint32_t x[2], const uint32_t k[2], + uint32_t z[2]) +{ + uint32_t I0, I1; + I0 = x[0] ^ k[0]; + I1 = x[1] ^ k[1]; + + I0 = ((uint32_t) SBOX1((I0 >> 24) & 0xFF) << 24) | + ((uint32_t) SBOX2((I0 >> 16) & 0xFF) << 16) | + ((uint32_t) SBOX3((I0 >> 8) & 0xFF) << 8) | + ((uint32_t) SBOX4((I0 ) & 0xFF) ); + I1 = ((uint32_t) SBOX2((I1 >> 24) & 0xFF) << 24) | + ((uint32_t) SBOX3((I1 >> 16) & 0xFF) << 16) | + ((uint32_t) SBOX4((I1 >> 8) & 0xFF) << 8) | + ((uint32_t) SBOX1((I1 ) & 0xFF) ); + + I0 ^= (I1 << 8) | (I1 >> 24); + I1 ^= (I0 << 16) | (I0 >> 16); + I0 ^= (I1 >> 8) | (I1 << 24); + I1 ^= (I0 >> 8) | (I0 << 24); + + z[0] ^= I1; + z[1] ^= I0; +} + +void mbedtls_camellia_init( mbedtls_camellia_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_camellia_context ) ); +} + +void mbedtls_camellia_free( mbedtls_camellia_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_camellia_context ) ); +} + +/* + * Camellia key schedule (encryption) + */ +int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int idx; + size_t i; + uint32_t *RK; + unsigned char t[64]; + uint32_t SIGMA[6][2]; + uint32_t KC[16]; + uint32_t TK[20]; + + RK = ctx->rk; + + memset( t, 0, 64 ); + memset( RK, 0, sizeof(ctx->rk) ); + + switch( keybits ) + { + case 128: ctx->nr = 3; idx = 0; break; + case 192: + case 256: ctx->nr = 4; idx = 1; break; + default : return( MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH ); + } + + for( i = 0; i < keybits / 8; ++i ) + t[i] = key[i]; + + if( keybits == 192 ) { + for( i = 0; i < 8; i++ ) + t[24 + i] = ~t[16 + i]; + } + + /* + * Prepare SIGMA values + */ + for( i = 0; i < 6; i++ ) { + GET_UINT32_BE( SIGMA[i][0], SIGMA_CHARS[i], 0 ); + GET_UINT32_BE( SIGMA[i][1], SIGMA_CHARS[i], 4 ); + } + + /* + * Key storage in KC + * Order: KL, KR, KA, KB + */ + memset( KC, 0, sizeof(KC) ); + + /* Store KL, KR */ + for( i = 0; i < 8; i++ ) + GET_UINT32_BE( KC[i], t, i * 4 ); + + /* Generate KA */ + for( i = 0; i < 4; ++i ) + KC[8 + i] = KC[i] ^ KC[4 + i]; + + camellia_feistel( KC + 8, SIGMA[0], KC + 10 ); + camellia_feistel( KC + 10, SIGMA[1], KC + 8 ); + + for( i = 0; i < 4; ++i ) + KC[8 + i] ^= KC[i]; + + camellia_feistel( KC + 8, SIGMA[2], KC + 10 ); + camellia_feistel( KC + 10, SIGMA[3], KC + 8 ); + + if( keybits > 128 ) { + /* Generate KB */ + for( i = 0; i < 4; ++i ) + KC[12 + i] = KC[4 + i] ^ KC[8 + i]; + + camellia_feistel( KC + 12, SIGMA[4], KC + 14 ); + camellia_feistel( KC + 14, SIGMA[5], KC + 12 ); + } + + /* + * Generating subkeys + */ + + /* Manipulating KL */ + SHIFT_AND_PLACE( idx, 0 ); + + /* Manipulating KR */ + if( keybits > 128 ) { + SHIFT_AND_PLACE( idx, 1 ); + } + + /* Manipulating KA */ + SHIFT_AND_PLACE( idx, 2 ); + + /* Manipulating KB */ + if( keybits > 128 ) { + SHIFT_AND_PLACE( idx, 3 ); + } + + /* Do transpositions */ + for( i = 0; i < 20; i++ ) { + if( transposes[idx][i] != -1 ) { + RK[32 + 12 * idx + i] = RK[transposes[idx][i]]; + } + } + + return( 0 ); +} + +/* + * Camellia key schedule (decryption) + */ +int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ) +{ + int idx, ret; + size_t i; + mbedtls_camellia_context cty; + uint32_t *RK; + uint32_t *SK; + + mbedtls_camellia_init( &cty ); + + /* Also checks keybits */ + if( ( ret = mbedtls_camellia_setkey_enc( &cty, key, keybits ) ) != 0 ) + goto exit; + + ctx->nr = cty.nr; + idx = ( ctx->nr == 4 ); + + RK = ctx->rk; + SK = cty.rk + 24 * 2 + 8 * idx * 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + + for( i = 22 + 8 * idx, SK -= 6; i > 0; i--, SK -= 4 ) + { + *RK++ = *SK++; + *RK++ = *SK++; + } + + SK -= 2; + + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + *RK++ = *SK++; + +exit: + mbedtls_camellia_free( &cty ); + + return( ret ); +} + +/* + * Camellia-ECB block encryption/decryption + */ +int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int NR; + uint32_t *RK, X[4]; + + ( (void) mode ); + + NR = ctx->nr; + RK = ctx->rk; + + GET_UINT32_BE( X[0], input, 0 ); + GET_UINT32_BE( X[1], input, 4 ); + GET_UINT32_BE( X[2], input, 8 ); + GET_UINT32_BE( X[3], input, 12 ); + + X[0] ^= *RK++; + X[1] ^= *RK++; + X[2] ^= *RK++; + X[3] ^= *RK++; + + while( NR ) { + --NR; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + camellia_feistel( X, RK, X + 2 ); + RK += 2; + camellia_feistel( X + 2, RK, X ); + RK += 2; + + if( NR ) { + FL(X[0], X[1], RK[0], RK[1]); + RK += 2; + FLInv(X[2], X[3], RK[0], RK[1]); + RK += 2; + } + } + + X[2] ^= *RK++; + X[3] ^= *RK++; + X[0] ^= *RK++; + X[1] ^= *RK++; + + PUT_UINT32_BE( X[2], output, 0 ); + PUT_UINT32_BE( X[3], output, 4 ); + PUT_UINT32_BE( X[0], output, 8 ); + PUT_UINT32_BE( X[1], output, 12 ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * Camellia-CBC buffer encryption/decryption + */ +int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[16]; + + if( length % 16 ) + return( MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_CAMELLIA_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 16 ); + mbedtls_camellia_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 16; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_camellia_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 16 ); + + input += 16; + output += 16; + length -= 16; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/* + * Camellia-CFB128 buffer encryption/decryption + */ +int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int c; + size_t n = *iv_off; + + if( mode == MBEDTLS_CAMELLIA_DECRYPT ) + { + while( length-- ) + { + if( n == 0 ) + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv ); + + c = *input++; + *output++ = (unsigned char)( c ^ iv[n] ); + iv[n] = (unsigned char) c; + + n = ( n + 1 ) & 0x0F; + } + } + else + { + while( length-- ) + { + if( n == 0 ) + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, iv, iv ); + + iv[n] = *output++ = (unsigned char)( iv[n] ^ *input++ ); + + n = ( n + 1 ) & 0x0F; + } + } + + *iv_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Camellia-CTR buffer encryption/decryption + */ +int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ) +{ + int c, i; + size_t n = *nc_off; + + while( length-- ) + { + if( n == 0 ) { + mbedtls_camellia_crypt_ecb( ctx, MBEDTLS_CAMELLIA_ENCRYPT, nonce_counter, + stream_block ); + + for( i = 16; i > 0; i-- ) + if( ++nonce_counter[i - 1] != 0 ) + break; + } + c = *input++; + *output++ = (unsigned char)( c ^ stream_block[n] ); + + n = ( n + 1 ) & 0x0F; + } + + *nc_off = n; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#endif /* !MBEDTLS_CAMELLIA_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Camellia test vectors from: + * + * http://info.isl.ntt.co.jp/crypt/eng/camellia/technology.html: + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/intermediate.txt + * http://info.isl.ntt.co.jp/crypt/eng/camellia/dl/cryptrec/t_camellia.txt + * (For each bitlength: Key 0, Nr 39) + */ +#define CAMELLIA_TESTS_ECB 2 + +static const unsigned char camellia_test_ecb_key[3][CAMELLIA_TESTS_ECB][32] = +{ + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, + { + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }, +}; + +static const unsigned char camellia_test_ecb_plain[CAMELLIA_TESTS_ECB][16] = +{ + { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }, + { 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char camellia_test_ecb_cipher[3][CAMELLIA_TESTS_ECB][16] = +{ + { + { 0x67, 0x67, 0x31, 0x38, 0x54, 0x96, 0x69, 0x73, + 0x08, 0x57, 0x06, 0x56, 0x48, 0xea, 0xbe, 0x43 }, + { 0x38, 0x3C, 0x6C, 0x2A, 0xAB, 0xEF, 0x7F, 0xDE, + 0x25, 0xCD, 0x47, 0x0B, 0xF7, 0x74, 0xA3, 0x31 } + }, + { + { 0xb4, 0x99, 0x34, 0x01, 0xb3, 0xe9, 0x96, 0xf8, + 0x4e, 0xe5, 0xce, 0xe7, 0xd7, 0x9b, 0x09, 0xb9 }, + { 0xD1, 0x76, 0x3F, 0xC0, 0x19, 0xD7, 0x7C, 0xC9, + 0x30, 0xBF, 0xF2, 0xA5, 0x6F, 0x7C, 0x93, 0x64 } + }, + { + { 0x9a, 0xcc, 0x23, 0x7d, 0xff, 0x16, 0xd7, 0x6c, + 0x20, 0xef, 0x7c, 0x91, 0x9e, 0x3a, 0x75, 0x09 }, + { 0x05, 0x03, 0xFB, 0x10, 0xAB, 0x24, 0x1E, 0x7C, + 0xF4, 0x5D, 0x8C, 0xDE, 0xEE, 0x47, 0x43, 0x35 } + } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define CAMELLIA_TESTS_CBC 3 + +static const unsigned char camellia_test_cbc_key[3][32] = +{ + { 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6, + 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C } + , + { 0x8E, 0x73, 0xB0, 0xF7, 0xDA, 0x0E, 0x64, 0x52, + 0xC8, 0x10, 0xF3, 0x2B, 0x80, 0x90, 0x79, 0xE5, + 0x62, 0xF8, 0xEA, 0xD2, 0x52, 0x2C, 0x6B, 0x7B } + , + { 0x60, 0x3D, 0xEB, 0x10, 0x15, 0xCA, 0x71, 0xBE, + 0x2B, 0x73, 0xAE, 0xF0, 0x85, 0x7D, 0x77, 0x81, + 0x1F, 0x35, 0x2C, 0x07, 0x3B, 0x61, 0x08, 0xD7, + 0x2D, 0x98, 0x10, 0xA3, 0x09, 0x14, 0xDF, 0xF4 } +}; + +static const unsigned char camellia_test_cbc_iv[16] = + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F } +; + +static const unsigned char camellia_test_cbc_plain[CAMELLIA_TESTS_CBC][16] = +{ + { 0x6B, 0xC1, 0xBE, 0xE2, 0x2E, 0x40, 0x9F, 0x96, + 0xE9, 0x3D, 0x7E, 0x11, 0x73, 0x93, 0x17, 0x2A }, + { 0xAE, 0x2D, 0x8A, 0x57, 0x1E, 0x03, 0xAC, 0x9C, + 0x9E, 0xB7, 0x6F, 0xAC, 0x45, 0xAF, 0x8E, 0x51 }, + { 0x30, 0xC8, 0x1C, 0x46, 0xA3, 0x5C, 0xE4, 0x11, + 0xE5, 0xFB, 0xC1, 0x19, 0x1A, 0x0A, 0x52, 0xEF } + +}; + +static const unsigned char camellia_test_cbc_cipher[3][CAMELLIA_TESTS_CBC][16] = +{ + { + { 0x16, 0x07, 0xCF, 0x49, 0x4B, 0x36, 0xBB, 0xF0, + 0x0D, 0xAE, 0xB0, 0xB5, 0x03, 0xC8, 0x31, 0xAB }, + { 0xA2, 0xF2, 0xCF, 0x67, 0x16, 0x29, 0xEF, 0x78, + 0x40, 0xC5, 0xA5, 0xDF, 0xB5, 0x07, 0x48, 0x87 }, + { 0x0F, 0x06, 0x16, 0x50, 0x08, 0xCF, 0x8B, 0x8B, + 0x5A, 0x63, 0x58, 0x63, 0x62, 0x54, 0x3E, 0x54 } + }, + { + { 0x2A, 0x48, 0x30, 0xAB, 0x5A, 0xC4, 0xA1, 0xA2, + 0x40, 0x59, 0x55, 0xFD, 0x21, 0x95, 0xCF, 0x93 }, + { 0x5D, 0x5A, 0x86, 0x9B, 0xD1, 0x4C, 0xE5, 0x42, + 0x64, 0xF8, 0x92, 0xA6, 0xDD, 0x2E, 0xC3, 0xD5 }, + { 0x37, 0xD3, 0x59, 0xC3, 0x34, 0x98, 0x36, 0xD8, + 0x84, 0xE3, 0x10, 0xAD, 0xDF, 0x68, 0xC4, 0x49 } + }, + { + { 0xE6, 0xCF, 0xA3, 0x5F, 0xC0, 0x2B, 0x13, 0x4A, + 0x4D, 0x2C, 0x0B, 0x67, 0x37, 0xAC, 0x3E, 0xDA }, + { 0x36, 0xCB, 0xEB, 0x73, 0xBD, 0x50, 0x4B, 0x40, + 0x70, 0xB1, 0xB7, 0xDE, 0x2B, 0x21, 0xEB, 0x50 }, + { 0xE3, 0x1A, 0x60, 0x55, 0x29, 0x7D, 0x96, 0xCA, + 0x33, 0x30, 0xCD, 0xF1, 0xB1, 0x86, 0x0A, 0x83 } + } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/* + * Camellia-CTR test vectors from: + * + * http://www.faqs.org/rfcs/rfc5528.html + */ + +static const unsigned char camellia_test_ctr_key[3][16] = +{ + { 0xAE, 0x68, 0x52, 0xF8, 0x12, 0x10, 0x67, 0xCC, + 0x4B, 0xF7, 0xA5, 0x76, 0x55, 0x77, 0xF3, 0x9E }, + { 0x7E, 0x24, 0x06, 0x78, 0x17, 0xFA, 0xE0, 0xD7, + 0x43, 0xD6, 0xCE, 0x1F, 0x32, 0x53, 0x91, 0x63 }, + { 0x76, 0x91, 0xBE, 0x03, 0x5E, 0x50, 0x20, 0xA8, + 0xAC, 0x6E, 0x61, 0x85, 0x29, 0xF9, 0xA0, 0xDC } +}; + +static const unsigned char camellia_test_ctr_nonce_counter[3][16] = +{ + { 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0x6C, 0xB6, 0xDB, 0xC0, 0x54, 0x3B, 0x59, + 0xDA, 0x48, 0xD9, 0x0B, 0x00, 0x00, 0x00, 0x01 }, + { 0x00, 0xE0, 0x01, 0x7B, 0x27, 0x77, 0x7F, 0x3F, + 0x4A, 0x17, 0x86, 0xF0, 0x00, 0x00, 0x00, 0x01 } +}; + +static const unsigned char camellia_test_ctr_pt[3][48] = +{ + { 0x53, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x62, + 0x6C, 0x6F, 0x63, 0x6B, 0x20, 0x6D, 0x73, 0x67 }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F }, + + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, + 0x20, 0x21, 0x22, 0x23 } +}; + +static const unsigned char camellia_test_ctr_ct[3][48] = +{ + { 0xD0, 0x9D, 0xC2, 0x9A, 0x82, 0x14, 0x61, 0x9A, + 0x20, 0x87, 0x7C, 0x76, 0xDB, 0x1F, 0x0B, 0x3F }, + { 0xDB, 0xF3, 0xC7, 0x8D, 0xC0, 0x83, 0x96, 0xD4, + 0xDA, 0x7C, 0x90, 0x77, 0x65, 0xBB, 0xCB, 0x44, + 0x2B, 0x8E, 0x8E, 0x0F, 0x31, 0xF0, 0xDC, 0xA7, + 0x2C, 0x74, 0x17, 0xE3, 0x53, 0x60, 0xE0, 0x48 }, + { 0xB1, 0x9D, 0x1F, 0xCD, 0xCB, 0x75, 0xEB, 0x88, + 0x2F, 0x84, 0x9C, 0xE2, 0x4D, 0x85, 0xCF, 0x73, + 0x9C, 0xE6, 0x4B, 0x2B, 0x5C, 0x9D, 0x73, 0xF1, + 0x4F, 0x2D, 0x5D, 0x9D, 0xCE, 0x98, 0x89, 0xCD, + 0xDF, 0x50, 0x86, 0x96 } +}; + +static const int camellia_test_ctr_len[3] = + { 16, 32, 36 }; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/* + * Checkup routine + */ +int mbedtls_camellia_self_test( int verbose ) +{ + int i, j, u, v; + unsigned char key[32]; + unsigned char buf[64]; + unsigned char src[16]; + unsigned char dst[16]; +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char iv[16]; +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + size_t offset, len; + unsigned char nonce_counter[16]; + unsigned char stream_block[16]; +#endif + + mbedtls_camellia_context ctx; + + memset( key, 0, 32 ); + + for( j = 0; j < 6; j++ ) { + u = j >> 1; + v = j & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-ECB-%3d (%s): ", 128 + u * 64, + (v == MBEDTLS_CAMELLIA_DECRYPT) ? "dec" : "enc"); + + for( i = 0; i < CAMELLIA_TESTS_ECB; i++ ) { + memcpy( key, camellia_test_ecb_key[u][i], 16 + 8 * u ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + mbedtls_camellia_setkey_dec( &ctx, key, 128 + u * 64 ); + memcpy( src, camellia_test_ecb_cipher[u][i], 16 ); + memcpy( dst, camellia_test_ecb_plain[i], 16 ); + } else { /* MBEDTLS_CAMELLIA_ENCRYPT */ + mbedtls_camellia_setkey_enc( &ctx, key, 128 + u * 64 ); + memcpy( src, camellia_test_ecb_plain[i], 16 ); + memcpy( dst, camellia_test_ecb_cipher[u][i], 16 ); + } + + mbedtls_camellia_crypt_ecb( &ctx, v, src, buf ); + + if( memcmp( buf, dst, 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( j = 0; j < 6; j++ ) + { + u = j >> 1; + v = j & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-CBC-%3d (%s): ", 128 + u * 64, + ( v == MBEDTLS_CAMELLIA_DECRYPT ) ? "dec" : "enc" ); + + memcpy( src, camellia_test_cbc_iv, 16 ); + memcpy( dst, camellia_test_cbc_iv, 16 ); + memcpy( key, camellia_test_cbc_key[u], 16 + 8 * u ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + mbedtls_camellia_setkey_dec( &ctx, key, 128 + u * 64 ); + } else { + mbedtls_camellia_setkey_enc( &ctx, key, 128 + u * 64 ); + } + + for( i = 0; i < CAMELLIA_TESTS_CBC; i++ ) { + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) { + memcpy( iv , src, 16 ); + memcpy( src, camellia_test_cbc_cipher[u][i], 16 ); + memcpy( dst, camellia_test_cbc_plain[i], 16 ); + } else { /* MBEDTLS_CAMELLIA_ENCRYPT */ + memcpy( iv , dst, 16 ); + memcpy( src, camellia_test_cbc_plain[i], 16 ); + memcpy( dst, camellia_test_cbc_cipher[u][i], 16 ); + } + + mbedtls_camellia_crypt_cbc( &ctx, v, 16, iv, src, buf ); + + if( memcmp( buf, dst, 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /* + * CTR mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " CAMELLIA-CTR-128 (%s): ", + ( v == MBEDTLS_CAMELLIA_DECRYPT ) ? "dec" : "enc" ); + + memcpy( nonce_counter, camellia_test_ctr_nonce_counter[u], 16 ); + memcpy( key, camellia_test_ctr_key[u], 16 ); + + offset = 0; + mbedtls_camellia_setkey_enc( &ctx, key, 128 ); + + if( v == MBEDTLS_CAMELLIA_DECRYPT ) + { + len = camellia_test_ctr_len[u]; + memcpy( buf, camellia_test_ctr_ct[u], len ); + + mbedtls_camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, camellia_test_ctr_pt[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + else + { + len = camellia_test_ctr_len[u]; + memcpy( buf, camellia_test_ctr_pt[u], len ); + + mbedtls_camellia_crypt_ctr( &ctx, len, &offset, nonce_counter, stream_block, + buf, buf ); + + if( memcmp( buf, camellia_test_ctr_ct[u], len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CAMELLIA_C */ diff --git a/c++/src/connect/mbedtls/ccm.c b/c++/src/connect/mbedtls/ccm.c new file mode 100644 index 00000000..13a8fd1a --- /dev/null +++ b/c++/src/connect/mbedtls/ccm.c @@ -0,0 +1,464 @@ +/* + * NIST SP800-38C compliant CCM implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * Definition of CCM: + * http://csrc.nist.gov/publications/nistpubs/800-38C/SP800-38C_updated-July20_2007.pdf + * RFC 3610 "Counter with CBC-MAC (CCM)" + * + * Related: + * RFC 5116 "An Interface and Algorithms for Authenticated Encryption" + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CCM_C) + +#include "mbedtls/ccm.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +#define CCM_ENCRYPT 0 +#define CCM_DECRYPT 1 + +/* + * Initialize context + */ +void mbedtls_ccm_init( mbedtls_ccm_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ccm_context ) ); +} + +int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + + cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + if( cipher_info->block_size != 16 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + mbedtls_cipher_free( &ctx->cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +/* + * Free context + */ +void mbedtls_ccm_free( mbedtls_ccm_context *ctx ) +{ + mbedtls_cipher_free( &ctx->cipher_ctx ); + mbedtls_zeroize( ctx, sizeof( mbedtls_ccm_context ) ); +} + +/* + * Macros for common operations. + * Results in smaller compiled code than static inline functions. + */ + +/* + * Update the CBC-MAC state in y using a block in b + * (Always using b as the source helps the compiler optimise a bit better.) + */ +#define UPDATE_CBC_MAC \ + for( i = 0; i < 16; i++ ) \ + y[i] ^= b[i]; \ + \ + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, y, 16, y, &olen ) ) != 0 ) \ + return( ret ); + +/* + * Encrypt or decrypt a partial block with CTR + * Warning: using b for temporary storage! src and dst must not be b! + * This avoids allocating one more 16 bytes buffer while allowing src == dst. + */ +#define CTR_CRYPT( dst, src, len ) \ + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctr, 16, b, &olen ) ) != 0 ) \ + return( ret ); \ + \ + for( i = 0; i < len; i++ ) \ + dst[i] = src[i] ^ b[i]; + +/* + * Authenticated encryption or decryption + */ +static int ccm_auth_crypt( mbedtls_ccm_context *ctx, int mode, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ) +{ + int ret; + unsigned char i; + unsigned char q; + size_t len_left, olen; + unsigned char b[16]; + unsigned char y[16]; + unsigned char ctr[16]; + const unsigned char *src; + unsigned char *dst; + + /* + * Check length requirements: SP800-38C A.1 + * Additional requirement: a < 2^16 - 2^8 to simplify the code. + * 'length' checked later (when writing it to the first block) + */ + if( tag_len < 4 || tag_len > 16 || tag_len % 2 != 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + /* Also implies q is within bounds */ + if( iv_len < 7 || iv_len > 13 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + if( add_len > 0xFF00 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + q = 16 - 1 - (unsigned char) iv_len; + + /* + * First block B_0: + * 0 .. 0 flags + * 1 .. iv_len nonce (aka iv) + * iv_len+1 .. 15 length + * + * With flags as (bits): + * 7 0 + * 6 add present? + * 5 .. 3 (t - 2) / 2 + * 2 .. 0 q - 1 + */ + b[0] = 0; + b[0] |= ( add_len > 0 ) << 6; + b[0] |= ( ( tag_len - 2 ) / 2 ) << 3; + b[0] |= q - 1; + + memcpy( b + 1, iv, iv_len ); + + for( i = 0, len_left = length; i < q; i++, len_left >>= 8 ) + b[15-i] = (unsigned char)( len_left & 0xFF ); + + if( len_left > 0 ) + return( MBEDTLS_ERR_CCM_BAD_INPUT ); + + + /* Start CBC-MAC with first block */ + memset( y, 0, 16 ); + UPDATE_CBC_MAC; + + /* + * If there is additional data, update CBC-MAC with + * add_len, add, 0 (padding to a block boundary) + */ + if( add_len > 0 ) + { + size_t use_len; + len_left = add_len; + src = add; + + memset( b, 0, 16 ); + b[0] = (unsigned char)( ( add_len >> 8 ) & 0xFF ); + b[1] = (unsigned char)( ( add_len ) & 0xFF ); + + use_len = len_left < 16 - 2 ? len_left : 16 - 2; + memcpy( b + 2, src, use_len ); + len_left -= use_len; + src += use_len; + + UPDATE_CBC_MAC; + + while( len_left > 0 ) + { + use_len = len_left > 16 ? 16 : len_left; + + memset( b, 0, 16 ); + memcpy( b, src, use_len ); + UPDATE_CBC_MAC; + + len_left -= use_len; + src += use_len; + } + } + + /* + * Prepare counter block for encryption: + * 0 .. 0 flags + * 1 .. iv_len nonce (aka iv) + * iv_len+1 .. 15 counter (initially 1) + * + * With flags as (bits): + * 7 .. 3 0 + * 2 .. 0 q - 1 + */ + ctr[0] = q - 1; + memcpy( ctr + 1, iv, iv_len ); + memset( ctr + 1 + iv_len, 0, q ); + ctr[15] = 1; + + /* + * Authenticate and {en,de}crypt the message. + * + * The only difference between encryption and decryption is + * the respective order of authentication and {en,de}cryption. + */ + len_left = length; + src = input; + dst = output; + + while( len_left > 0 ) + { + size_t use_len = len_left > 16 ? 16 : len_left; + + if( mode == CCM_ENCRYPT ) + { + memset( b, 0, 16 ); + memcpy( b, src, use_len ); + UPDATE_CBC_MAC; + } + + CTR_CRYPT( dst, src, use_len ); + + if( mode == CCM_DECRYPT ) + { + memset( b, 0, 16 ); + memcpy( b, dst, use_len ); + UPDATE_CBC_MAC; + } + + dst += use_len; + src += use_len; + len_left -= use_len; + + /* + * Increment counter. + * No need to check for overflow thanks to the length check above. + */ + for( i = 0; i < q; i++ ) + if( ++ctr[15-i] != 0 ) + break; + } + + /* + * Authentication: reset counter and crypt/mask internal tag + */ + for( i = 0; i < q; i++ ) + ctr[15-i] = 0; + + CTR_CRYPT( y, y, 16 ); + memcpy( tag, y, tag_len ); + + return( 0 ); +} + +/* + * Authenticated encryption + */ +int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ) +{ + return( ccm_auth_crypt( ctx, CCM_ENCRYPT, length, iv, iv_len, + add, add_len, input, output, tag, tag_len ) ); +} + +/* + * Authenticated decryption + */ +int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ) +{ + int ret; + unsigned char check_tag[16]; + unsigned char i; + int diff; + + if( ( ret = ccm_auth_crypt( ctx, CCM_DECRYPT, length, + iv, iv_len, add, add_len, + input, output, check_tag, tag_len ) ) != 0 ) + { + return( ret ); + } + + /* Check tag in "constant-time" */ + for( diff = 0, i = 0; i < tag_len; i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + { + mbedtls_zeroize( output, length ); + return( MBEDTLS_ERR_CCM_AUTH_FAILED ); + } + + return( 0 ); +} + + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/* + * Examples 1 to 3 from SP800-38C Appendix C + */ + +#define NB_TESTS 3 + +/* + * The data is the same for all tests, only the used length changes + */ +static const unsigned char key[] = { + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f +}; + +static const unsigned char iv[] = { + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b +}; + +static const unsigned char ad[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 +}; + +static const unsigned char msg[] = { + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, +}; + +static const size_t iv_len [NB_TESTS] = { 7, 8, 12 }; +static const size_t add_len[NB_TESTS] = { 8, 16, 20 }; +static const size_t msg_len[NB_TESTS] = { 4, 16, 24 }; +static const size_t tag_len[NB_TESTS] = { 4, 6, 8 }; + +static const unsigned char res[NB_TESTS][32] = { + { 0x71, 0x62, 0x01, 0x5b, 0x4d, 0xac, 0x25, 0x5d }, + { 0xd2, 0xa1, 0xf0, 0xe0, 0x51, 0xea, 0x5f, 0x62, + 0x08, 0x1a, 0x77, 0x92, 0x07, 0x3d, 0x59, 0x3d, + 0x1f, 0xc6, 0x4f, 0xbf, 0xac, 0xcd }, + { 0xe3, 0xb2, 0x01, 0xa9, 0xf5, 0xb7, 0x1a, 0x7a, + 0x9b, 0x1c, 0xea, 0xec, 0xcd, 0x97, 0xe7, 0x0b, + 0x61, 0x76, 0xaa, 0xd9, 0xa4, 0x42, 0x8a, 0xa5, + 0x48, 0x43, 0x92, 0xfb, 0xc1, 0xb0, 0x99, 0x51 } +}; + +int mbedtls_ccm_self_test( int verbose ) +{ + mbedtls_ccm_context ctx; + unsigned char out[32]; + size_t i; + int ret; + + mbedtls_ccm_init( &ctx ); + + if( mbedtls_ccm_setkey( &ctx, MBEDTLS_CIPHER_ID_AES, key, 8 * sizeof key ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( " CCM: setup failed" ); + + return( 1 ); + } + + for( i = 0; i < NB_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " CCM-AES #%u: ", (unsigned int) i + 1 ); + + ret = mbedtls_ccm_encrypt_and_tag( &ctx, msg_len[i], + iv, iv_len[i], ad, add_len[i], + msg, out, + out + msg_len[i], tag_len[i] ); + + if( ret != 0 || + memcmp( out, res[i], msg_len[i] + tag_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + ret = mbedtls_ccm_auth_decrypt( &ctx, msg_len[i], + iv, iv_len[i], ad, add_len[i], + res[i], out, + res[i] + msg_len[i], tag_len[i] ); + + if( ret != 0 || + memcmp( out, msg, msg_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + mbedtls_ccm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_CCM_C */ diff --git a/c++/src/connect/mbedtls/certs.c b/c++/src/connect/mbedtls/certs.c new file mode 100644 index 00000000..ffe6bc98 --- /dev/null +++ b/c++/src/connect/mbedtls/certs.c @@ -0,0 +1,351 @@ +/* + * X.509 test certificates + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "mbedtls/certs.h" + +#if defined(MBEDTLS_CERTS_C) + +#if defined(MBEDTLS_ECDSA_C) +#define TEST_CA_CRT_EC \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIICUjCCAdegAwIBAgIJAMFD4n5iQ8zoMAoGCCqGSM49BAMCMD4xCzAJBgNVBAYT\r\n" \ +"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \ +"QyBDQTAeFw0xMzA5MjQxNTQ5NDhaFw0yMzA5MjIxNTQ5NDhaMD4xCzAJBgNVBAYT\r\n" \ +"Ak5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBF\r\n" \ +"QyBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABMPaKzRBN1gvh1b+/Im6KUNLTuBu\r\n" \ +"ww5XUzM5WNRStJGVOQsj318XJGJI/BqVKc4sLYfCiFKAr9ZqqyHduNMcbli4yuiy\r\n" \ +"aY7zQa0pw7RfdadHb9UZKVVpmlM7ILRmFmAzHqOBoDCBnTAdBgNVHQ4EFgQUnW0g\r\n" \ +"JEkBPyvLeLUZvH4kydv7NnwwbgYDVR0jBGcwZYAUnW0gJEkBPyvLeLUZvH4kydv7\r\n" \ +"NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEcMBoGA1UE\r\n" \ +"AxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAwGA1UdEwQFMAMBAf8w\r\n" \ +"CgYIKoZIzj0EAwIDaQAwZgIxAMO0YnNWKJUAfXgSJtJxexn4ipg+kv4znuR50v56\r\n" \ +"t4d0PCu412mUC6Nnd7izvtE2MgIxAP1nnJQjZ8BWukszFQDG48wxCCyci9qpdSMv\r\n" \ +"uCjn8pwUOkABXK8Mss90fzCfCEOtIA==\r\n" \ +"-----END CERTIFICATE-----\r\n" +const char mbedtls_test_ca_crt_ec[] = TEST_CA_CRT_EC; + +const char mbedtls_test_ca_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"Proc-Type: 4,ENCRYPTED\r\n" +"DEK-Info: DES-EDE3-CBC,307EAB469933D64E\r\n" +"\r\n" +"IxbrRmKcAzctJqPdTQLA4SWyBYYGYJVkYEna+F7Pa5t5Yg/gKADrFKcm6B72e7DG\r\n" +"ihExtZI648s0zdYw6qSJ74vrPSuWDe5qm93BqsfVH9svtCzWHW0pm1p0KTBCFfUq\r\n" +"UsuWTITwJImcnlAs1gaRZ3sAWm7cOUidL0fo2G0fYUFNcYoCSLffCFTEHBuPnagb\r\n" +"a77x/sY1Bvii8S9/XhDTb6pTMx06wzrm\r\n" +"-----END EC PRIVATE KEY-----\r\n"; + +const char mbedtls_test_ca_pwd_ec[] = "PolarSSLTest"; + +const char mbedtls_test_srv_crt_ec[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIICHzCCAaWgAwIBAgIBCTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n" +"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDBZMBMGByqGSM49AgEG\r\n" +"CCqGSM49AwEHA0IABDfMVtl2CR5acj7HWS3/IG7ufPkGkXTQrRS192giWWKSTuUA\r\n" +"2CMR/+ov0jRdXRa9iojCa3cNVc2KKg76Aci07f+jgZ0wgZowCQYDVR0TBAIwADAd\r\n" +"BgNVHQ4EFgQUUGGlj9QH2deCAQzlZX+MY0anE74wbgYDVR0jBGcwZYAUnW0gJEkB\r\n" +"PyvLeLUZvH4kydv7NnyhQqRAMD4xCzAJBgNVBAYTAk5MMREwDwYDVQQKEwhQb2xh\r\n" +"clNTTDEcMBoGA1UEAxMTUG9sYXJzc2wgVGVzdCBFQyBDQYIJAMFD4n5iQ8zoMAoG\r\n" +"CCqGSM49BAMCA2gAMGUCMQCaLFzXptui5WQN8LlO3ddh1hMxx6tzgLvT03MTVK2S\r\n" +"C12r0Lz3ri/moSEpNZWqPjkCMCE2f53GXcYLqyfyJR078c/xNSUU5+Xxl7VZ414V\r\n" +"fGa5kHvHARBPc8YAIVIqDvHH1Q==\r\n" +"-----END CERTIFICATE-----\r\n"; + +const char mbedtls_test_srv_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"MHcCAQEEIPEqEyB2AnCoPL/9U/YDHvdqXYbIogTywwyp6/UfDw6noAoGCCqGSM49\r\n" +"AwEHoUQDQgAEN8xW2XYJHlpyPsdZLf8gbu58+QaRdNCtFLX3aCJZYpJO5QDYIxH/\r\n" +"6i/SNF1dFr2KiMJrdw1VzYoqDvoByLTt/w==\r\n" +"-----END EC PRIVATE KEY-----\r\n"; + +const char mbedtls_test_cli_crt_ec[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIICLDCCAbKgAwIBAgIBDTAKBggqhkjOPQQDAjA+MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0EwHhcN\r\n" +"MTMwOTI0MTU1MjA0WhcNMjMwOTIyMTU1MjA0WjBBMQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxHzAdBgNVBAMTFlBvbGFyU1NMIFRlc3QgQ2xpZW50IDIw\r\n" +"WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARX5a6xc9/TrLuTuIH/Eq7u5lOszlVT\r\n" +"9jQOzC7jYyUL35ji81xgNpbA1RgUcOV/n9VLRRjlsGzVXPiWj4dwo+THo4GdMIGa\r\n" +"MAkGA1UdEwQCMAAwHQYDVR0OBBYEFHoAX4Zk/OBd5REQO7LmO8QmP8/iMG4GA1Ud\r\n" +"IwRnMGWAFJ1tICRJAT8ry3i1Gbx+JMnb+zZ8oUKkQDA+MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxHDAaBgNVBAMTE1BvbGFyc3NsIFRlc3QgRUMgQ0GC\r\n" +"CQDBQ+J+YkPM6DAKBggqhkjOPQQDAgNoADBlAjBKZQ17IIOimbmoD/yN7o89u3BM\r\n" +"lgOsjnhw3fIOoLIWy2WOGsk/LGF++DzvrRzuNiACMQCd8iem1XS4JK7haj8xocpU\r\n" +"LwjQje5PDGHfd3h9tP38Qknu5bJqws0md2KOKHyeV0U=\r\n" +"-----END CERTIFICATE-----\r\n"; + +const char mbedtls_test_cli_key_ec[] = +"-----BEGIN EC PRIVATE KEY-----\r\n" +"MHcCAQEEIPb3hmTxZ3/mZI3vyk7p3U3wBf+WIop6hDhkFzJhmLcqoAoGCCqGSM49\r\n" +"AwEHoUQDQgAEV+WusXPf06y7k7iB/xKu7uZTrM5VU/Y0Dswu42MlC9+Y4vNcYDaW\r\n" +"wNUYFHDlf5/VS0UY5bBs1Vz4lo+HcKPkxw==\r\n" +"-----END EC PRIVATE KEY-----\r\n"; + +const size_t mbedtls_test_ca_crt_ec_len = sizeof( mbedtls_test_ca_crt_ec ); +const size_t mbedtls_test_ca_key_ec_len = sizeof( mbedtls_test_ca_key_ec ); +const size_t mbedtls_test_ca_pwd_ec_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1; +const size_t mbedtls_test_srv_crt_ec_len = sizeof( mbedtls_test_srv_crt_ec ); +const size_t mbedtls_test_srv_key_ec_len = sizeof( mbedtls_test_srv_key_ec ); +const size_t mbedtls_test_cli_crt_ec_len = sizeof( mbedtls_test_cli_crt_ec ); +const size_t mbedtls_test_cli_key_ec_len = sizeof( mbedtls_test_cli_key_ec ); +#else +#define TEST_CA_CRT_EC +#endif /* MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_RSA_C) +#define TEST_CA_CRT_RSA \ +"-----BEGIN CERTIFICATE-----\r\n" \ +"MIIDhzCCAm+gAwIBAgIBADANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" \ +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" \ +"MTEwMjEyMTQ0NDAwWhcNMjEwMjEyMTQ0NDAwWjA7MQswCQYDVQQGEwJOTDERMA8G\r\n" \ +"A1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwggEiMA0G\r\n" \ +"CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDA3zf8F7vglp0/ht6WMn1EpRagzSHx\r\n" \ +"mdTs6st8GFgIlKXsm8WL3xoemTiZhx57wI053zhdcHgH057Zk+i5clHFzqMwUqny\r\n" \ +"50BwFMtEonILwuVA+T7lpg6z+exKY8C4KQB0nFc7qKUEkHHxvYPZP9al4jwqj+8n\r\n" \ +"YMPGn8u67GB9t+aEMr5P+1gmIgNb1LTV+/Xjli5wwOQuvfwu7uJBVcA0Ln0kcmnL\r\n" \ +"R7EUQIN9Z/SG9jGr8XmksrUuEvmEF/Bibyc+E1ixVA0hmnM3oTDPb5Lc9un8rNsu\r\n" \ +"KNF+AksjoBXyOGVkCeoMbo4bF6BxyLObyavpw/LPh5aPgAIynplYb6LVAgMBAAGj\r\n" \ +"gZUwgZIwDAYDVR0TBAUwAwEB/zAdBgNVHQ4EFgQUtFrkpbPe0lL2udWmlQ/rPrzH\r\n" \ +"/f8wYwYDVR0jBFwwWoAUtFrkpbPe0lL2udWmlQ/rPrzH/f+hP6Q9MDsxCzAJBgNV\r\n" \ +"BAYTAk5MMREwDwYDVQQKEwhQb2xhclNTTDEZMBcGA1UEAxMQUG9sYXJTU0wgVGVz\r\n" \ +"dCBDQYIBADANBgkqhkiG9w0BAQUFAAOCAQEAuP1U2ABUkIslsCfdlc2i94QHHYeJ\r\n" \ +"SsR4EdgHtdciUI5I62J6Mom+Y0dT/7a+8S6MVMCZP6C5NyNyXw1GWY/YR82XTJ8H\r\n" \ +"DBJiCTok5DbZ6SzaONBzdWHXwWwmi5vg1dxn7YxrM9d0IjxM27WNKs4sDQhZBQkF\r\n" \ +"pjmfs2cb4oPl4Y9T9meTx/lvdkRYEug61Jfn6cA+qHpyPYdTH+UshITnmp5/Ztkf\r\n" \ +"m/UTSLBNFNHesiTZeH31NcxYGdHSme9Nc/gfidRa0FLOCfWxRlFqAI47zG9jAQCZ\r\n" \ +"7Z2mCGDNMhjQc+BYcdnl0lPXjdDK6V0qCg1dVewhUBcW5gZKzV7e9+DpVA==\r\n" \ +"-----END CERTIFICATE-----\r\n" +const char mbedtls_test_ca_crt_rsa[] = TEST_CA_CRT_RSA; + +const char mbedtls_test_ca_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"Proc-Type: 4,ENCRYPTED\r\n" +"DEK-Info: DES-EDE3-CBC,A8A95B05D5B7206B\r\n" +"\r\n" +"9Qd9GeArejl1GDVh2lLV1bHt0cPtfbh5h/5zVpAVaFpqtSPMrElp50Rntn9et+JA\r\n" +"7VOyboR+Iy2t/HU4WvA687k3Bppe9GwKHjHhtl//8xFKwZr3Xb5yO5JUP8AUctQq\r\n" +"Nb8CLlZyuUC+52REAAthdWgsX+7dJO4yabzUcQ22Tp9JSD0hiL43BlkWYUNK3dAo\r\n" +"PZlmiptjnzVTjg1MxsBSydZinWOLBV8/JQgxSPo2yD4uEfig28qbvQ2wNIn0pnAb\r\n" +"GxnSAOazkongEGfvcjIIs+LZN9gXFhxcOh6kc4Q/c99B7QWETwLLkYgZ+z1a9VY9\r\n" +"gEU7CwCxYCD+h9hY6FPmsK0/lC4O7aeRKpYq00rPPxs6i7phiexg6ax6yTMmArQq\r\n" +"QmK3TAsJm8V/J5AWpLEV6jAFgRGymGGHnof0DXzVWZidrcZJWTNuGEX90nB3ee2w\r\n" +"PXJEFWKoD3K3aFcSLdHYr3mLGxP7H9ThQai9VsycxZKS5kwvBKQ//YMrmFfwPk8x\r\n" +"vTeY4KZMaUrveEel5tWZC94RSMKgxR6cyE1nBXyTQnDOGbfpNNgBKxyKbINWoOJU\r\n" +"WJZAwlsQn+QzCDwpri7+sV1mS3gBE6UY7aQmnmiiaC2V3Hbphxct/en5QsfDOt1X\r\n" +"JczSfpRWLlbPznZg8OQh/VgCMA58N5DjOzTIK7sJJ5r+94ZBTCpgAMbF588f0NTR\r\n" +"KCe4yrxGJR7X02M4nvD4IwOlpsQ8xQxZtOSgXv4LkxvdU9XJJKWZ/XNKJeWztxSe\r\n" +"Z1vdTc2YfsDBA2SEv33vxHx2g1vqtw8SjDRT2RaQSS0QuSaMJimdOX6mTOCBKk1J\r\n" +"9Q5mXTrER+/LnK0jEmXsBXWA5bqqVZIyahXSx4VYZ7l7w/PHiUDtDgyRhMMKi4n2\r\n" +"iQvQcWSQTjrpnlJbca1/DkpRt3YwrvJwdqb8asZU2VrNETh5x0QVefDRLFiVpif/\r\n" +"tUaeAe/P1F8OkS7OIZDs1SUbv/sD2vMbhNkUoCms3/PvNtdnvgL4F0zhaDpKCmlT\r\n" +"P8vx49E7v5CyRNmED9zZg4o3wmMqrQO93PtTug3Eu9oVx1zPQM1NVMyBa2+f29DL\r\n" +"1nuTCeXdo9+ni45xx+jAI4DCwrRdhJ9uzZyC6962H37H6D+5naNvClFR1s6li1Gb\r\n" +"nqPoiy/OBsEx9CaDGcqQBp5Wme/3XW+6z1ISOx+igwNTVCT14mHdBMbya0eIKft5\r\n" +"X+GnwtgEMyCYyyWuUct8g4RzErcY9+yW9Om5Hzpx4zOuW4NPZgPDTgK+t2RSL/Yq\r\n" +"rE1njrgeGYcVeG3f+OftH4s6fPbq7t1A5ZgUscbLMBqr9tK+OqygR4EgKBPsH6Cz\r\n" +"L6zlv/2RV0qAHvVuDJcIDIgwY5rJtINEm32rhOeFNJwZS5MNIC1czXZx5//ugX7l\r\n" +"I4sy5nbVhwSjtAk8Xg5dZbdTZ6mIrb7xqH+fdakZor1khG7bC2uIwibD3cSl2XkR\r\n" +"wN48lslbHnqqagr6Xm1nNOSVl8C/6kbJEsMpLhAezfRtGwvOucoaE+WbeUNolGde\r\n" +"P/eQiddSf0brnpiLJRh7qZrl9XuqYdpUqnoEdMAfotDOID8OtV7gt8a48ad8VPW2\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +const char mbedtls_test_ca_pwd_rsa[] = "PolarSSLTest"; + +const char mbedtls_test_srv_crt_rsa[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDNzCCAh+gAwIBAgIBAjANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTEwMjEyMTQ0NDA2WhcNMjEwMjEyMTQ0NDA2WjA0MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxEjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcN\r\n" +"AQEBBQADggEPADCCAQoCggEBAMFNo93nzR3RBNdJcriZrA545Do8Ss86ExbQWuTN\r\n" +"owCIp+4ea5anUrSQ7y1yej4kmvy2NKwk9XfgJmSMnLAofaHa6ozmyRyWvP7BBFKz\r\n" +"NtSj+uGxdtiQwWG0ZlI2oiZTqqt0Xgd9GYLbKtgfoNkNHC1JZvdbJXNG6AuKT2kM\r\n" +"tQCQ4dqCEGZ9rlQri2V5kaHiYcPNQEkI7mgM8YuG0ka/0LiqEQMef1aoGh5EGA8P\r\n" +"hYvai0Re4hjGYi/HZo36Xdh98yeJKQHFkA4/J/EwyEoO79bex8cna8cFPXrEAjya\r\n" +"HT4P6DSYW8tzS1KW2BGiLICIaTla0w+w3lkvEcf36hIBMJcCAwEAAaNNMEswCQYD\r\n" +"VR0TBAIwADAdBgNVHQ4EFgQUpQXoZLjc32APUBJNYKhkr02LQ5MwHwYDVR0jBBgw\r\n" +"FoAUtFrkpbPe0lL2udWmlQ/rPrzH/f8wDQYJKoZIhvcNAQEFBQADggEBAJxnXClY\r\n" +"oHkbp70cqBrsGXLybA74czbO5RdLEgFs7rHVS9r+c293luS/KdliLScZqAzYVylw\r\n" +"UfRWvKMoWhHYKp3dEIS4xTXk6/5zXxhv9Rw8SGc8qn6vITHk1S1mPevtekgasY5Y\r\n" +"iWQuM3h4YVlRH3HHEMAD1TnAexfXHHDFQGe+Bd1iAbz1/sH9H8l4StwX6egvTK3M\r\n" +"wXRwkKkvjKaEDA9ATbZx0mI8LGsxSuCqe9r9dyjmttd47J1p1Rulz3CLzaRcVIuS\r\n" +"RRQfaD8neM9c1S/iJ/amTVqJxA1KOdOS5780WhPfSArA+g4qAmSjelc3p4wWpha8\r\n" +"zhuYwjVuX6JHG0c=\r\n" +"-----END CERTIFICATE-----\r\n"; + +const char mbedtls_test_srv_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEpAIBAAKCAQEAwU2j3efNHdEE10lyuJmsDnjkOjxKzzoTFtBa5M2jAIin7h5r\r\n" +"lqdStJDvLXJ6PiSa/LY0rCT1d+AmZIycsCh9odrqjObJHJa8/sEEUrM21KP64bF2\r\n" +"2JDBYbRmUjaiJlOqq3ReB30Zgtsq2B+g2Q0cLUlm91slc0boC4pPaQy1AJDh2oIQ\r\n" +"Zn2uVCuLZXmRoeJhw81ASQjuaAzxi4bSRr/QuKoRAx5/VqgaHkQYDw+Fi9qLRF7i\r\n" +"GMZiL8dmjfpd2H3zJ4kpAcWQDj8n8TDISg7v1t7HxydrxwU9esQCPJodPg/oNJhb\r\n" +"y3NLUpbYEaIsgIhpOVrTD7DeWS8Rx/fqEgEwlwIDAQABAoIBAQCXR0S8EIHFGORZ\r\n" +"++AtOg6eENxD+xVs0f1IeGz57Tjo3QnXX7VBZNdj+p1ECvhCE/G7XnkgU5hLZX+G\r\n" +"Z0jkz/tqJOI0vRSdLBbipHnWouyBQ4e/A1yIJdlBtqXxJ1KE/ituHRbNc4j4kL8Z\r\n" +"/r6pvwnTI0PSx2Eqs048YdS92LT6qAv4flbNDxMn2uY7s4ycS4Q8w1JXnCeaAnYm\r\n" +"WYI5wxO+bvRELR2Mcz5DmVnL8jRyml6l6582bSv5oufReFIbyPZbQWlXgYnpu6He\r\n" +"GTc7E1zKYQGG/9+DQUl/1vQuCPqQwny0tQoX2w5tdYpdMdVm+zkLtbajzdTviJJa\r\n" +"TWzL6lt5AoGBAN86+SVeJDcmQJcv4Eq6UhtRr4QGMiQMz0Sod6ettYxYzMgxtw28\r\n" +"CIrgpozCc+UaZJLo7UxvC6an85r1b2nKPCLQFaggJ0H4Q0J/sZOhBIXaoBzWxveK\r\n" +"nupceKdVxGsFi8CDy86DBfiyFivfBj+47BbaQzPBj7C4rK7UlLjab2rDAoGBAN2u\r\n" +"AM2gchoFiu4v1HFL8D7lweEpi6ZnMJjnEu/dEgGQJFjwdpLnPbsj4c75odQ4Gz8g\r\n" +"sw9lao9VVzbusoRE/JGI4aTdO0pATXyG7eG1Qu+5Yc1YGXcCrliA2xM9xx+d7f+s\r\n" +"mPzN+WIEg5GJDYZDjAzHG5BNvi/FfM1C9dOtjv2dAoGAF0t5KmwbjWHBhcVqO4Ic\r\n" +"BVvN3BIlc1ue2YRXEDlxY5b0r8N4XceMgKmW18OHApZxfl8uPDauWZLXOgl4uepv\r\n" +"whZC3EuWrSyyICNhLY21Ah7hbIEBPF3L3ZsOwC+UErL+dXWLdB56Jgy3gZaBeW7b\r\n" +"vDrEnocJbqCm7IukhXHOBK8CgYEAwqdHB0hqyNSzIOGY7v9abzB6pUdA3BZiQvEs\r\n" +"3LjHVd4HPJ2x0N8CgrBIWOE0q8+0hSMmeE96WW/7jD3fPWwCR5zlXknxBQsfv0gP\r\n" +"3BC5PR0Qdypz+d+9zfMf625kyit4T/hzwhDveZUzHnk1Cf+IG7Q+TOEnLnWAWBED\r\n" +"ISOWmrUCgYAFEmRxgwAc/u+D6t0syCwAYh6POtscq9Y0i9GyWk89NzgC4NdwwbBH\r\n" +"4AgahOxIxXx2gxJnq3yfkJfIjwf0s2DyP0kY2y6Ua1OeomPeY9mrIS4tCuDQ6LrE\r\n" +"TB6l9VGoxJL4fyHnZb8L5gGvnB1bbD8cL6YPaDiOhcRseC9vBiEuVg==\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +const char mbedtls_test_cli_crt_rsa[] = +"-----BEGIN CERTIFICATE-----\r\n" +"MIIDPzCCAiegAwIBAgIBBDANBgkqhkiG9w0BAQUFADA7MQswCQYDVQQGEwJOTDER\r\n" +"MA8GA1UEChMIUG9sYXJTU0wxGTAXBgNVBAMTEFBvbGFyU1NMIFRlc3QgQ0EwHhcN\r\n" +"MTEwMjEyMTQ0NDA3WhcNMjEwMjEyMTQ0NDA3WjA8MQswCQYDVQQGEwJOTDERMA8G\r\n" +"A1UEChMIUG9sYXJTU0wxGjAYBgNVBAMTEVBvbGFyU1NMIENsaWVudCAyMIIBIjAN\r\n" +"BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6f\r\n" +"M60Nj4o8VmXl3ETZzGaFB9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu\r\n" +"1C93KYRhTYJQj6eVSHD1bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEw\r\n" +"MjDV0/YI0FZPRo7yX/k9Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v\r\n" +"4Jv4EFbMs44TFeY0BGbH7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx/\r\n" +"/DZrtenNLQNiTrM9AM+vdqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQAB\r\n" +"o00wSzAJBgNVHRMEAjAAMB0GA1UdDgQWBBRxoQBzckAvVHZeM/xSj7zx3WtGITAf\r\n" +"BgNVHSMEGDAWgBS0WuSls97SUva51aaVD+s+vMf9/zANBgkqhkiG9w0BAQUFAAOC\r\n" +"AQEAAn86isAM8X+mVwJqeItt6E9slhEQbAofyk+diH1Lh8Y9iLlWQSKbw/UXYjx5\r\n" +"LLPZcniovxIcARC/BjyZR9g3UwTHNGNm+rwrqa15viuNOFBchykX/Orsk02EH7NR\r\n" +"Alw5WLPorYjED6cdVQgBl9ot93HdJogRiXCxErM7NC8/eP511mjq+uLDjLKH8ZPQ\r\n" +"8I4ekHJnroLsDkIwXKGIsvIBHQy2ac/NwHLCQOK6mfum1pRx52V4Utu5dLLjD5bM\r\n" +"xOBC7KU4xZKuMXXZM6/93Yb51K/J4ahf1TxJlTWXtnzDr9saEYdNy2SKY/6ZiDNH\r\n" +"D+stpAKiQLAWaAusIWKYEyw9MQ==\r\n" +"-----END CERTIFICATE-----\r\n"; + +const char mbedtls_test_cli_key_rsa[] = +"-----BEGIN RSA PRIVATE KEY-----\r\n" +"MIIEpAIBAAKCAQEAyHTEzLn5tXnpRdkUYLB9u5Pyax6fM60Nj4o8VmXl3ETZzGaF\r\n" +"B9X4J7BKNdBjngpuG7fa8H6r7gwQk4ZJGDTzqCrSV/Uu1C93KYRhTYJQj6eVSHD1\r\n" +"bk2y1RPD0hrt5kPqQhTrdOrA7R/UV06p86jt0uDBMHEwMjDV0/YI0FZPRo7yX/k9\r\n" +"Z5GIMC5Cst99++UMd//sMcB4j7/Cf8qtbCHWjdmLao5v4Jv4EFbMs44TFeY0BGbH\r\n" +"7vk2DmqV9gmaBmf0ZXH4yqSxJeD+PIs1BGe64E92hfx//DZrtenNLQNiTrM9AM+v\r\n" +"dqBpVoNq0qjU51Bx5rU2BXcFbXvI5MT9TNUhXwIDAQABAoIBAGdNtfYDiap6bzst\r\n" +"yhCiI8m9TtrhZw4MisaEaN/ll3XSjaOG2dvV6xMZCMV+5TeXDHOAZnY18Yi18vzz\r\n" +"4Ut2TnNFzizCECYNaA2fST3WgInnxUkV3YXAyP6CNxJaCmv2aA0yFr2kFVSeaKGt\r\n" +"ymvljNp2NVkvm7Th8fBQBO7I7AXhz43k0mR7XmPgewe8ApZOG3hstkOaMvbWAvWA\r\n" +"zCZupdDjZYjOJqlA4eEA4H8/w7F83r5CugeBE8LgEREjLPiyejrU5H1fubEY+h0d\r\n" +"l5HZBJ68ybTXfQ5U9o/QKA3dd0toBEhhdRUDGzWtjvwkEQfqF1reGWj/tod/gCpf\r\n" +"DFi6X0ECgYEA4wOv/pjSC3ty6TuOvKX2rOUiBrLXXv2JSxZnMoMiWI5ipLQt+RYT\r\n" +"VPafL/m7Dn6MbwjayOkcZhBwk5CNz5A6Q4lJ64Mq/lqHznRCQQ2Mc1G8eyDF/fYL\r\n" +"Ze2pLvwP9VD5jTc2miDfw+MnvJhywRRLcemDFP8k4hQVtm8PMp3ZmNECgYEA4gz7\r\n" +"wzObR4gn8ibe617uQPZjWzUj9dUHYd+in1gwBCIrtNnaRn9I9U/Q6tegRYpii4ys\r\n" +"c176NmU+umy6XmuSKV5qD9bSpZWG2nLFnslrN15Lm3fhZxoeMNhBaEDTnLT26yoi\r\n" +"33gp0mSSWy94ZEqipms+ULF6sY1ZtFW6tpGFoy8CgYAQHhnnvJflIs2ky4q10B60\r\n" +"ZcxFp3rtDpkp0JxhFLhiizFrujMtZSjYNm5U7KkgPVHhLELEUvCmOnKTt4ap/vZ0\r\n" +"BxJNe1GZH3pW6SAvGDQpl9sG7uu/vTFP+lCxukmzxB0DrrDcvorEkKMom7ZCCRvW\r\n" +"KZsZ6YeH2Z81BauRj218kQKBgQCUV/DgKP2985xDTT79N08jUo3hTP5MVYCCuj/+\r\n" +"UeEw1TvZcx3LJby7P6Xad6a1/BqveaGyFKIfEFIaBUBItk801sDDpDaYc4gL00Xc\r\n" +"7lFuBHOZkxJYlss5QrGpuOEl9ZwUt5IrFLBdYaKqNHzNVC1pCPfb/JyH6Dr2HUxq\r\n" +"gxUwAQKBgQCcU6G2L8AG9d9c0UpOyL1tMvFe5Ttw0KjlQVdsh1MP6yigYo9DYuwu\r\n" +"bHFVW2r0dBTqegP2/KTOxKzaHfC1qf0RGDsUoJCNJrd1cwoCLG8P2EF4w3OBrKqv\r\n" +"8u4ytY0F+Vlanj5lm3TaoHSVF1+NWPyOTiwevIECGKwSxvlki4fDAA==\r\n" +"-----END RSA PRIVATE KEY-----\r\n"; + +const size_t mbedtls_test_ca_crt_rsa_len = sizeof( mbedtls_test_ca_crt_rsa ); +const size_t mbedtls_test_ca_key_rsa_len = sizeof( mbedtls_test_ca_key_rsa ); +const size_t mbedtls_test_ca_pwd_rsa_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1; +const size_t mbedtls_test_srv_crt_rsa_len = sizeof( mbedtls_test_srv_crt_rsa ); +const size_t mbedtls_test_srv_key_rsa_len = sizeof( mbedtls_test_srv_key_rsa ); +const size_t mbedtls_test_cli_crt_rsa_len = sizeof( mbedtls_test_cli_crt_rsa ); +const size_t mbedtls_test_cli_key_rsa_len = sizeof( mbedtls_test_cli_key_rsa ); +#else +#define TEST_CA_CRT_RSA +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_PEM_PARSE_C) +/* Concatenation of all available CA certificates */ +const char mbedtls_test_cas_pem[] = TEST_CA_CRT_RSA TEST_CA_CRT_EC; +const size_t mbedtls_test_cas_pem_len = sizeof( mbedtls_test_cas_pem ); +#endif + +/* List of all available CA certificates */ +const char * mbedtls_test_cas[] = { +#if defined(MBEDTLS_RSA_C) + mbedtls_test_ca_crt_rsa, +#endif +#if defined(MBEDTLS_ECDSA_C) + mbedtls_test_ca_crt_ec, +#endif + NULL +}; +const size_t mbedtls_test_cas_len[] = { +#if defined(MBEDTLS_RSA_C) + sizeof( mbedtls_test_ca_crt_rsa ), +#endif +#if defined(MBEDTLS_ECDSA_C) + sizeof( mbedtls_test_ca_crt_ec ), +#endif + 0 +}; + +#if defined(MBEDTLS_RSA_C) +const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_rsa; +const char *mbedtls_test_ca_key = mbedtls_test_ca_key_rsa; +const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_rsa; +const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_rsa; +const char *mbedtls_test_srv_key = mbedtls_test_srv_key_rsa; +const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_rsa; +const char *mbedtls_test_cli_key = mbedtls_test_cli_key_rsa; +const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_rsa ); +const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_rsa ); +const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_rsa ) - 1; +const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_rsa ); +const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_rsa ); +const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_rsa ); +const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_rsa ); +#else /* ! MBEDTLS_RSA_C, so MBEDTLS_ECDSA_C */ +const char *mbedtls_test_ca_crt = mbedtls_test_ca_crt_ec; +const char *mbedtls_test_ca_key = mbedtls_test_ca_key_ec; +const char *mbedtls_test_ca_pwd = mbedtls_test_ca_pwd_ec; +const char *mbedtls_test_srv_crt = mbedtls_test_srv_crt_ec; +const char *mbedtls_test_srv_key = mbedtls_test_srv_key_ec; +const char *mbedtls_test_cli_crt = mbedtls_test_cli_crt_ec; +const char *mbedtls_test_cli_key = mbedtls_test_cli_key_ec; +const size_t mbedtls_test_ca_crt_len = sizeof( mbedtls_test_ca_crt_ec ); +const size_t mbedtls_test_ca_key_len = sizeof( mbedtls_test_ca_key_ec ); +const size_t mbedtls_test_ca_pwd_len = sizeof( mbedtls_test_ca_pwd_ec ) - 1; +const size_t mbedtls_test_srv_crt_len = sizeof( mbedtls_test_srv_crt_ec ); +const size_t mbedtls_test_srv_key_len = sizeof( mbedtls_test_srv_key_ec ); +const size_t mbedtls_test_cli_crt_len = sizeof( mbedtls_test_cli_crt_ec ); +const size_t mbedtls_test_cli_key_len = sizeof( mbedtls_test_cli_key_ec ); +#endif /* MBEDTLS_RSA_C */ + +#endif /* MBEDTLS_CERTS_C */ diff --git a/c++/src/connect/mbedtls/cipher.c b/c++/src/connect/mbedtls/cipher.c new file mode 100644 index 00000000..e9e0b223 --- /dev/null +++ b/c++/src/connect/mbedtls/cipher.c @@ -0,0 +1,917 @@ +/** + * \file cipher.c + * + * \brief Generic cipher wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CIPHER_C) + +#include "mbedtls/cipher.h" +#include "mbedtls/cipher_internal.h" + +#include +#include + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_CMAC_C) +#include "mbedtls/cmac.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) +#define MBEDTLS_CIPHER_MODE_STREAM +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +static int supported_init = 0; + +const int *mbedtls_cipher_list( void ) +{ + const mbedtls_cipher_definition_t *def; + int *type; + + if( ! supported_init ) + { + def = mbedtls_cipher_definitions; + type = mbedtls_cipher_supported; + + while( def->type != 0 ) + *type++ = (*def++).type; + + *type = 0; + + supported_init = 1; + } + + return( mbedtls_cipher_supported ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ) +{ + const mbedtls_cipher_definition_t *def; + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( def->type == cipher_type ) + return( def->info ); + + return( NULL ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ) +{ + const mbedtls_cipher_definition_t *def; + + if( NULL == cipher_name ) + return( NULL ); + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( ! strcmp( def->info->name, cipher_name ) ) + return( def->info ); + + return( NULL ); +} + +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id, + int key_bitlen, + const mbedtls_cipher_mode_t mode ) +{ + const mbedtls_cipher_definition_t *def; + + for( def = mbedtls_cipher_definitions; def->info != NULL; def++ ) + if( def->info->base->cipher == cipher_id && + def->info->key_bitlen == (unsigned) key_bitlen && + def->info->mode == mode ) + return( def->info ); + + return( NULL ); +} + +void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); +} + +void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_CMAC_C) + if( ctx->cmac_ctx ) + { + mbedtls_zeroize( ctx->cmac_ctx, sizeof( mbedtls_cmac_context_t ) ); + mbedtls_free( ctx->cmac_ctx ); + } +#endif + + if( ctx->cipher_ctx ) + ctx->cipher_info->base->ctx_free_func( ctx->cipher_ctx ); + + mbedtls_zeroize( ctx, sizeof(mbedtls_cipher_context_t) ); +} + +int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ) +{ + if( NULL == cipher_info || NULL == ctx ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + memset( ctx, 0, sizeof( mbedtls_cipher_context_t ) ); + + if( NULL == ( ctx->cipher_ctx = cipher_info->base->ctx_alloc_func() ) ) + return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED ); + + ctx->cipher_info = cipher_info; + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + /* + * Ignore possible errors caused by a cipher mode that doesn't use padding + */ +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_PKCS7 ); +#else + (void) mbedtls_cipher_set_padding_mode( ctx, MBEDTLS_PADDING_NONE ); +#endif +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + + return( 0 ); +} + +int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key, + int key_bitlen, const mbedtls_operation_t operation ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_KEY_LEN ) == 0 && + (int) ctx->cipher_info->key_bitlen != key_bitlen ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + ctx->key_bitlen = key_bitlen; + ctx->operation = operation; + + /* + * For CFB and CTR mode always use the encryption key schedule + */ + if( MBEDTLS_ENCRYPT == operation || + MBEDTLS_MODE_CFB == ctx->cipher_info->mode || + MBEDTLS_MODE_CTR == ctx->cipher_info->mode ) + { + return ctx->cipher_info->base->setkey_enc_func( ctx->cipher_ctx, key, + ctx->key_bitlen ); + } + + if( MBEDTLS_DECRYPT == operation ) + return ctx->cipher_info->base->setkey_dec_func( ctx->cipher_ctx, key, + ctx->key_bitlen ); + + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); +} + +int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len ) +{ + size_t actual_iv_size; + + if( NULL == ctx || NULL == ctx->cipher_info || NULL == iv ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + /* avoid buffer overflow in ctx->iv */ + if( iv_len > MBEDTLS_MAX_IV_LENGTH ) + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + + if( ( ctx->cipher_info->flags & MBEDTLS_CIPHER_VARIABLE_IV_LEN ) != 0 ) + actual_iv_size = iv_len; + else + { + actual_iv_size = ctx->cipher_info->iv_size; + + /* avoid reading past the end of input buffer */ + if( actual_iv_size > iv_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + memcpy( ctx->iv, iv, actual_iv_size ); + ctx->iv_size = actual_iv_size; + + return( 0 ); +} + +int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + ctx->unprocessed_len = 0; + + return( 0 ); +} + +#if defined(MBEDTLS_GCM_C) +int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + return mbedtls_gcm_starts( (mbedtls_gcm_context *) ctx->cipher_ctx, ctx->operation, + ctx->iv, ctx->iv_size, ad, ad_len ); + } + + return( 0 ); +} +#endif /* MBEDTLS_GCM_C */ + +int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, + size_t ilen, unsigned char *output, size_t *olen ) +{ + int ret; + size_t block_size = 0; + + if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + *olen = 0; + block_size = mbedtls_cipher_get_block_size( ctx ); + + if( ctx->cipher_info->mode == MBEDTLS_MODE_ECB ) + { + if( ilen != block_size ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + *olen = ilen; + + if( 0 != ( ret = ctx->cipher_info->base->ecb_func( ctx->cipher_ctx, + ctx->operation, input, output ) ) ) + { + return( ret ); + } + + return( 0 ); + } + +#if defined(MBEDTLS_GCM_C) + if( ctx->cipher_info->mode == MBEDTLS_MODE_GCM ) + { + *olen = ilen; + return mbedtls_gcm_update( (mbedtls_gcm_context *) ctx->cipher_ctx, ilen, input, + output ); + } +#endif + + if ( 0 == block_size ) + { + return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT; + } + + if( input == output && + ( ctx->unprocessed_len != 0 || ilen % block_size ) ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CBC ) + { + size_t copy_len = 0; + + /* + * If there is not enough data for a full block, cache it. + */ + if( ( ctx->operation == MBEDTLS_DECRYPT && + ilen <= block_size - ctx->unprocessed_len ) || + ( ctx->operation == MBEDTLS_ENCRYPT && + ilen < block_size - ctx->unprocessed_len ) ) + { + memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, + ilen ); + + ctx->unprocessed_len += ilen; + return( 0 ); + } + + /* + * Process cached data first + */ + if( 0 != ctx->unprocessed_len ) + { + copy_len = block_size - ctx->unprocessed_len; + + memcpy( &( ctx->unprocessed_data[ctx->unprocessed_len] ), input, + copy_len ); + + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, block_size, ctx->iv, + ctx->unprocessed_data, output ) ) ) + { + return( ret ); + } + + *olen += block_size; + output += block_size; + ctx->unprocessed_len = 0; + + input += copy_len; + ilen -= copy_len; + } + + /* + * Cache final, incomplete block + */ + if( 0 != ilen ) + { + if( 0 == block_size ) + { + return MBEDTLS_ERR_CIPHER_INVALID_CONTEXT; + } + + copy_len = ilen % block_size; + if( copy_len == 0 && ctx->operation == MBEDTLS_DECRYPT ) + copy_len = block_size; + + memcpy( ctx->unprocessed_data, &( input[ilen - copy_len] ), + copy_len ); + + ctx->unprocessed_len += copy_len; + ilen -= copy_len; + } + + /* + * Process remaining full blocks + */ + if( ilen ) + { + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, ilen, ctx->iv, input, output ) ) ) + { + return( ret ); + } + + *olen += ilen; + } + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CFB ) + { + if( 0 != ( ret = ctx->cipher_info->base->cfb_func( ctx->cipher_ctx, + ctx->operation, ilen, &ctx->unprocessed_len, ctx->iv, + input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + if( ctx->cipher_info->mode == MBEDTLS_MODE_CTR ) + { + if( 0 != ( ret = ctx->cipher_info->base->ctr_func( ctx->cipher_ctx, + ilen, &ctx->unprocessed_len, ctx->iv, + ctx->unprocessed_data, input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + if( ctx->cipher_info->mode == MBEDTLS_MODE_STREAM ) + { + if( 0 != ( ret = ctx->cipher_info->base->stream_func( ctx->cipher_ctx, + ilen, input, output ) ) ) + { + return( ret ); + } + + *olen = ilen; + + return( 0 ); + } +#endif /* MBEDTLS_CIPHER_MODE_STREAM */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) +/* + * PKCS7 (and PKCS5) padding: fill with ll bytes, with ll = padding_len + */ +static void add_pkcs_padding( unsigned char *output, size_t output_len, + size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i; + + for( i = 0; i < padding_len; i++ ) + output[data_len + i] = (unsigned char) padding_len; +} + +static int get_pkcs_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i, pad_idx; + unsigned char padding_len, bad = 0; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + padding_len = input[input_len - 1]; + *data_len = input_len - padding_len; + + /* Avoid logical || since it results in a branch */ + bad |= padding_len > input_len; + bad |= padding_len == 0; + + /* The number of bytes checked must be independent of padding_len, + * so pick input_len, which is usually 8 or 16 (one block) */ + pad_idx = input_len - padding_len; + for( i = 0; i < input_len; i++ ) + bad |= ( input[i] ^ padding_len ) * ( i >= pad_idx ); + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); +} +#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ + +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) +/* + * One and zeros padding: fill with 80 00 ... 00 + */ +static void add_one_and_zeros_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i = 0; + + output[data_len] = 0x80; + for( i = 1; i < padding_len; i++ ) + output[data_len + i] = 0x00; +} + +static int get_one_and_zeros_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i; + unsigned char done = 0, prev_done, bad; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + bad = 0xFF; + *data_len = 0; + for( i = input_len; i > 0; i-- ) + { + prev_done = done; + done |= ( input[i-1] != 0 ); + *data_len |= ( i - 1 ) * ( done != prev_done ); + bad &= ( input[i-1] ^ 0x80 ) | ( done == prev_done ); + } + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); + +} +#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ + +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) +/* + * Zeros and len padding: fill with 00 ... 00 ll, where ll is padding length + */ +static void add_zeros_and_len_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t padding_len = output_len - data_len; + unsigned char i = 0; + + for( i = 1; i < padding_len; i++ ) + output[data_len + i - 1] = 0x00; + output[output_len - 1] = (unsigned char) padding_len; +} + +static int get_zeros_and_len_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i, pad_idx; + unsigned char padding_len, bad = 0; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + padding_len = input[input_len - 1]; + *data_len = input_len - padding_len; + + /* Avoid logical || since it results in a branch */ + bad |= padding_len > input_len; + bad |= padding_len == 0; + + /* The number of bytes checked must be independent of padding_len */ + pad_idx = input_len - padding_len; + for( i = 0; i < input_len - 1; i++ ) + bad |= input[i] * ( i >= pad_idx ); + + return( MBEDTLS_ERR_CIPHER_INVALID_PADDING * ( bad != 0 ) ); +} +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ + +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) +/* + * Zero padding: fill with 00 ... 00 + */ +static void add_zeros_padding( unsigned char *output, + size_t output_len, size_t data_len ) +{ + size_t i; + + for( i = data_len; i < output_len; i++ ) + output[i] = 0x00; +} + +static int get_zeros_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + size_t i; + unsigned char done = 0, prev_done; + + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *data_len = 0; + for( i = input_len; i > 0; i-- ) + { + prev_done = done; + done |= ( input[i-1] != 0 ); + *data_len |= i * ( done != prev_done ); + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ + +/* + * No padding: don't pad :) + * + * There is no add_padding function (check for NULL in mbedtls_cipher_finish) + * but a trivial get_padding function + */ +static int get_no_padding( unsigned char *input, size_t input_len, + size_t *data_len ) +{ + if( NULL == input || NULL == data_len ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *data_len = input_len; + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen ) +{ + if( NULL == ctx || NULL == ctx->cipher_info || NULL == olen ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + *olen = 0; + + if( MBEDTLS_MODE_CFB == ctx->cipher_info->mode || + MBEDTLS_MODE_CTR == ctx->cipher_info->mode || + MBEDTLS_MODE_GCM == ctx->cipher_info->mode || + MBEDTLS_MODE_STREAM == ctx->cipher_info->mode ) + { + return( 0 ); + } + + if( MBEDTLS_MODE_ECB == ctx->cipher_info->mode ) + { + if( ctx->unprocessed_len != 0 ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + return( 0 ); + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if( MBEDTLS_MODE_CBC == ctx->cipher_info->mode ) + { + int ret = 0; + + if( MBEDTLS_ENCRYPT == ctx->operation ) + { + /* check for 'no padding' mode */ + if( NULL == ctx->add_padding ) + { + if( 0 != ctx->unprocessed_len ) + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + + return( 0 ); + } + + ctx->add_padding( ctx->unprocessed_data, mbedtls_cipher_get_iv_size( ctx ), + ctx->unprocessed_len ); + } + else if( mbedtls_cipher_get_block_size( ctx ) != ctx->unprocessed_len ) + { + /* + * For decrypt operations, expect a full block, + * or an empty block if no padding + */ + if( NULL == ctx->add_padding && 0 == ctx->unprocessed_len ) + return( 0 ); + + return( MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED ); + } + + /* cipher block */ + if( 0 != ( ret = ctx->cipher_info->base->cbc_func( ctx->cipher_ctx, + ctx->operation, mbedtls_cipher_get_block_size( ctx ), ctx->iv, + ctx->unprocessed_data, output ) ) ) + { + return( ret ); + } + + /* Set output size for decryption */ + if( MBEDTLS_DECRYPT == ctx->operation ) + return ctx->get_padding( output, mbedtls_cipher_get_block_size( ctx ), + olen ); + + /* Set output size for encryption */ + *olen = mbedtls_cipher_get_block_size( ctx ); + return( 0 ); + } +#else + ((void) output); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode ) +{ + if( NULL == ctx || + MBEDTLS_MODE_CBC != ctx->cipher_info->mode ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + switch( mode ) + { +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + case MBEDTLS_PADDING_PKCS7: + ctx->add_padding = add_pkcs_padding; + ctx->get_padding = get_pkcs_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) + case MBEDTLS_PADDING_ONE_AND_ZEROS: + ctx->add_padding = add_one_and_zeros_padding; + ctx->get_padding = get_one_and_zeros_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) + case MBEDTLS_PADDING_ZEROS_AND_LEN: + ctx->add_padding = add_zeros_and_len_padding; + ctx->get_padding = get_zeros_and_len_padding; + break; +#endif +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) + case MBEDTLS_PADDING_ZEROS: + ctx->add_padding = add_zeros_padding; + ctx->get_padding = get_zeros_padding; + break; +#endif + case MBEDTLS_PADDING_NONE: + ctx->add_padding = NULL; + ctx->get_padding = get_no_padding; + break; + + default: + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +#if defined(MBEDTLS_GCM_C) +int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len ) +{ + if( NULL == ctx || NULL == ctx->cipher_info || NULL == tag ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_ENCRYPT != ctx->operation ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + return mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, tag, tag_len ); + + return( 0 ); +} + +int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len ) +{ + int ret; + + if( NULL == ctx || NULL == ctx->cipher_info || + MBEDTLS_DECRYPT != ctx->operation ) + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + unsigned char check_tag[16]; + size_t i; + int diff; + + if( tag_len > sizeof( check_tag ) ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( 0 != ( ret = mbedtls_gcm_finish( (mbedtls_gcm_context *) ctx->cipher_ctx, + check_tag, tag_len ) ) ) + { + return( ret ); + } + + /* Check the tag in "constant-time" */ + for( diff = 0, i = 0; i < tag_len; i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + return( MBEDTLS_ERR_CIPHER_AUTH_FAILED ); + + return( 0 ); + } + + return( 0 ); +} +#endif /* MBEDTLS_GCM_C */ + +/* + * Packet-oriented wrapper for non-AEAD modes + */ +int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ) +{ + int ret; + size_t finish_olen; + + if( ( ret = mbedtls_cipher_set_iv( ctx, iv, iv_len ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_reset( ctx ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_update( ctx, input, ilen, output, olen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_finish( ctx, output + *olen, &finish_olen ) ) != 0 ) + return( ret ); + + *olen += finish_olen; + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_AEAD) +/* + * Packet-oriented encryption for AEAD modes + */ +int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + unsigned char *tag, size_t tag_len ) +{ +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + *olen = ilen; + return( mbedtls_gcm_crypt_and_tag( ctx->cipher_ctx, MBEDTLS_GCM_ENCRYPT, ilen, + iv, iv_len, ad, ad_len, input, output, + tag_len, tag ) ); + } +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_CCM_C) + if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) + { + *olen = ilen; + return( mbedtls_ccm_encrypt_and_tag( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, input, output, + tag, tag_len ) ); + } +#endif /* MBEDTLS_CCM_C */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} + +/* + * Packet-oriented decryption for AEAD modes + */ +int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + const unsigned char *tag, size_t tag_len ) +{ +#if defined(MBEDTLS_GCM_C) + if( MBEDTLS_MODE_GCM == ctx->cipher_info->mode ) + { + int ret; + + *olen = ilen; + ret = mbedtls_gcm_auth_decrypt( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, + tag, tag_len, input, output ); + + if( ret == MBEDTLS_ERR_GCM_AUTH_FAILED ) + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + + return( ret ); + } +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_CCM_C) + if( MBEDTLS_MODE_CCM == ctx->cipher_info->mode ) + { + int ret; + + *olen = ilen; + ret = mbedtls_ccm_auth_decrypt( ctx->cipher_ctx, ilen, + iv, iv_len, ad, ad_len, + input, output, tag, tag_len ); + + if( ret == MBEDTLS_ERR_CCM_AUTH_FAILED ) + ret = MBEDTLS_ERR_CIPHER_AUTH_FAILED; + + return( ret ); + } +#endif /* MBEDTLS_CCM_C */ + + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); +} +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#endif /* MBEDTLS_CIPHER_C */ diff --git a/c++/src/connect/mbedtls/cipher_wrap.c b/c++/src/connect/mbedtls/cipher_wrap.c new file mode 100644 index 00000000..dc76af8f --- /dev/null +++ b/c++/src/connect/mbedtls/cipher_wrap.c @@ -0,0 +1,1451 @@ +/** + * \file cipher_wrap.c + * + * \brief Generic cipher wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CIPHER_C) + +#include "mbedtls/cipher_internal.h" + +#if defined(MBEDTLS_AES_C) +#include "mbedtls/aes.h" +#endif + +#if defined(MBEDTLS_ARC4_C) +#include "mbedtls/arc4.h" +#endif + +#if defined(MBEDTLS_CAMELLIA_C) +#include "mbedtls/camellia.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +#if defined(MBEDTLS_BLOWFISH_C) +#include "mbedtls/blowfish.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_GCM_C) +/* shared by all GCM ciphers */ +static void *gcm_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_gcm_context ) ); + + if( ctx != NULL ) + mbedtls_gcm_init( (mbedtls_gcm_context *) ctx ); + + return( ctx ); +} + +static void gcm_ctx_free( void *ctx ) +{ + mbedtls_gcm_free( ctx ); + mbedtls_free( ctx ); +} +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +/* shared by all CCM ciphers */ +static void *ccm_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ccm_context ) ); + + if( ctx != NULL ) + mbedtls_ccm_init( (mbedtls_ccm_context *) ctx ); + + return( ctx ); +} + +static void ccm_ctx_free( void *ctx ) +{ + mbedtls_ccm_free( ctx ); + mbedtls_free( ctx ); +} +#endif /* MBEDTLS_CCM_C */ + +#if defined(MBEDTLS_AES_C) + +static int aes_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_ecb( (mbedtls_aes_context *) ctx, operation, input, output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int aes_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_cbc( (mbedtls_aes_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int aes_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_cfb128( (mbedtls_aes_context *) ctx, operation, length, iv_off, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int aes_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_aes_crypt_ctr( (mbedtls_aes_context *) ctx, length, nc_off, nonce_counter, + stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int aes_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aes_setkey_dec( (mbedtls_aes_context *) ctx, key, key_bitlen ); +} + +static int aes_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_aes_setkey_enc( (mbedtls_aes_context *) ctx, key, key_bitlen ); +} + +static void * aes_ctx_alloc( void ) +{ + mbedtls_aes_context *aes = mbedtls_calloc( 1, sizeof( mbedtls_aes_context ) ); + + if( aes == NULL ) + return( NULL ); + + mbedtls_aes_init( aes ); + + return( aes ); +} + +static void aes_ctx_free( void *ctx ) +{ + mbedtls_aes_free( (mbedtls_aes_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t aes_info = { + MBEDTLS_CIPHER_ID_AES, + aes_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + aes_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + aes_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + aes_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + aes_setkey_enc_wrap, + aes_setkey_dec_wrap, + aes_ctx_alloc, + aes_ctx_free +}; + +static const mbedtls_cipher_info_t aes_128_ecb_info = { + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_MODE_ECB, + 128, + "AES-128-ECB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ecb_info = { + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_MODE_ECB, + 192, + "AES-192-ECB", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ecb_info = { + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_MODE_ECB, + 256, + "AES-256-ECB", + 16, + 0, + 16, + &aes_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t aes_128_cbc_info = { + MBEDTLS_CIPHER_AES_128_CBC, + MBEDTLS_MODE_CBC, + 128, + "AES-128-CBC", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_cbc_info = { + MBEDTLS_CIPHER_AES_192_CBC, + MBEDTLS_MODE_CBC, + 192, + "AES-192-CBC", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_cbc_info = { + MBEDTLS_CIPHER_AES_256_CBC, + MBEDTLS_MODE_CBC, + 256, + "AES-256-CBC", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t aes_128_cfb128_info = { + MBEDTLS_CIPHER_AES_128_CFB128, + MBEDTLS_MODE_CFB, + 128, + "AES-128-CFB128", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_cfb128_info = { + MBEDTLS_CIPHER_AES_192_CFB128, + MBEDTLS_MODE_CFB, + 192, + "AES-192-CFB128", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_cfb128_info = { + MBEDTLS_CIPHER_AES_256_CFB128, + MBEDTLS_MODE_CFB, + 256, + "AES-256-CFB128", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t aes_128_ctr_info = { + MBEDTLS_CIPHER_AES_128_CTR, + MBEDTLS_MODE_CTR, + 128, + "AES-128-CTR", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ctr_info = { + MBEDTLS_CIPHER_AES_192_CTR, + MBEDTLS_MODE_CTR, + 192, + "AES-192-CTR", + 16, + 0, + 16, + &aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ctr_info = { + MBEDTLS_CIPHER_AES_256_CTR, + MBEDTLS_MODE_CTR, + 256, + "AES-256-CTR", + 16, + 0, + 16, + &aes_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_aes_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_AES, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t gcm_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_aes_setkey_wrap, + gcm_aes_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t aes_128_gcm_info = { + MBEDTLS_CIPHER_AES_128_GCM, + MBEDTLS_MODE_GCM, + 128, + "AES-128-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; + +static const mbedtls_cipher_info_t aes_192_gcm_info = { + MBEDTLS_CIPHER_AES_192_GCM, + MBEDTLS_MODE_GCM, + 192, + "AES-192-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_gcm_info = { + MBEDTLS_CIPHER_AES_256_GCM, + MBEDTLS_MODE_GCM, + 256, + "AES-256-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_aes_info +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_aes_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_AES, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t ccm_aes_info = { + MBEDTLS_CIPHER_ID_AES, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_aes_setkey_wrap, + ccm_aes_setkey_wrap, + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t aes_128_ccm_info = { + MBEDTLS_CIPHER_AES_128_CCM, + MBEDTLS_MODE_CCM, + 128, + "AES-128-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; + +static const mbedtls_cipher_info_t aes_192_ccm_info = { + MBEDTLS_CIPHER_AES_192_CCM, + MBEDTLS_MODE_CCM, + 192, + "AES-192-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; + +static const mbedtls_cipher_info_t aes_256_ccm_info = { + MBEDTLS_CIPHER_AES_256_CCM, + MBEDTLS_MODE_CCM, + 256, + "AES-256-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_aes_info +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + +static int camellia_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_ecb( (mbedtls_camellia_context *) ctx, operation, input, + output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int camellia_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_cbc( (mbedtls_camellia_context *) ctx, operation, length, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int camellia_crypt_cfb128_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_cfb128( (mbedtls_camellia_context *) ctx, operation, length, + iv_off, iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int camellia_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_camellia_crypt_ctr( (mbedtls_camellia_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int camellia_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_camellia_setkey_dec( (mbedtls_camellia_context *) ctx, key, key_bitlen ); +} + +static int camellia_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_camellia_setkey_enc( (mbedtls_camellia_context *) ctx, key, key_bitlen ); +} + +static void * camellia_ctx_alloc( void ) +{ + mbedtls_camellia_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_camellia_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_camellia_init( ctx ); + + return( ctx ); +} + +static void camellia_ctx_free( void *ctx ) +{ + mbedtls_camellia_free( (mbedtls_camellia_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + camellia_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + camellia_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + camellia_crypt_cfb128_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + camellia_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + camellia_setkey_enc_wrap, + camellia_setkey_dec_wrap, + camellia_ctx_alloc, + camellia_ctx_free +}; + +static const mbedtls_cipher_info_t camellia_128_ecb_info = { + MBEDTLS_CIPHER_CAMELLIA_128_ECB, + MBEDTLS_MODE_ECB, + 128, + "CAMELLIA-128-ECB", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ecb_info = { + MBEDTLS_CIPHER_CAMELLIA_192_ECB, + MBEDTLS_MODE_ECB, + 192, + "CAMELLIA-192-ECB", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ecb_info = { + MBEDTLS_CIPHER_CAMELLIA_256_ECB, + MBEDTLS_MODE_ECB, + 256, + "CAMELLIA-256-ECB", + 16, + 0, + 16, + &camellia_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t camellia_128_cbc_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CBC, + MBEDTLS_MODE_CBC, + 128, + "CAMELLIA-128-CBC", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_cbc_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CBC, + MBEDTLS_MODE_CBC, + 192, + "CAMELLIA-192-CBC", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_cbc_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CBC, + MBEDTLS_MODE_CBC, + 256, + "CAMELLIA-256-CBC", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t camellia_128_cfb128_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, + MBEDTLS_MODE_CFB, + 128, + "CAMELLIA-128-CFB128", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_cfb128_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, + MBEDTLS_MODE_CFB, + 192, + "CAMELLIA-192-CFB128", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_cfb128_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, + MBEDTLS_MODE_CFB, + 256, + "CAMELLIA-256-CFB128", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t camellia_128_ctr_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CTR, + MBEDTLS_MODE_CTR, + 128, + "CAMELLIA-128-CTR", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ctr_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CTR, + MBEDTLS_MODE_CTR, + 192, + "CAMELLIA-192-CTR", + 16, + 0, + 16, + &camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ctr_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CTR, + MBEDTLS_MODE_CTR, + 256, + "CAMELLIA-256-CTR", + 16, + 0, + 16, + &camellia_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#if defined(MBEDTLS_GCM_C) +static int gcm_camellia_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_gcm_setkey( (mbedtls_gcm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t gcm_camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + gcm_camellia_setkey_wrap, + gcm_camellia_setkey_wrap, + gcm_ctx_alloc, + gcm_ctx_free, +}; + +static const mbedtls_cipher_info_t camellia_128_gcm_info = { + MBEDTLS_CIPHER_CAMELLIA_128_GCM, + MBEDTLS_MODE_GCM, + 128, + "CAMELLIA-128-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_gcm_info = { + MBEDTLS_CIPHER_CAMELLIA_192_GCM, + MBEDTLS_MODE_GCM, + 192, + "CAMELLIA-192-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_gcm_info = { + MBEDTLS_CIPHER_CAMELLIA_256_GCM, + MBEDTLS_MODE_GCM, + 256, + "CAMELLIA-256-GCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &gcm_camellia_info +}; +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CCM_C) +static int ccm_camellia_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_ccm_setkey( (mbedtls_ccm_context *) ctx, MBEDTLS_CIPHER_ID_CAMELLIA, + key, key_bitlen ); +} + +static const mbedtls_cipher_base_t ccm_camellia_info = { + MBEDTLS_CIPHER_ID_CAMELLIA, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + ccm_camellia_setkey_wrap, + ccm_camellia_setkey_wrap, + ccm_ctx_alloc, + ccm_ctx_free, +}; + +static const mbedtls_cipher_info_t camellia_128_ccm_info = { + MBEDTLS_CIPHER_CAMELLIA_128_CCM, + MBEDTLS_MODE_CCM, + 128, + "CAMELLIA-128-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_192_ccm_info = { + MBEDTLS_CIPHER_CAMELLIA_192_CCM, + MBEDTLS_MODE_CCM, + 192, + "CAMELLIA-192-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; + +static const mbedtls_cipher_info_t camellia_256_ccm_info = { + MBEDTLS_CIPHER_CAMELLIA_256_CCM, + MBEDTLS_MODE_CCM, + 256, + "CAMELLIA-256-CCM", + 12, + MBEDTLS_CIPHER_VARIABLE_IV_LEN, + 16, + &ccm_camellia_info +}; +#endif /* MBEDTLS_CCM_C */ + +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) + +static int des_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + ((void) operation); + return mbedtls_des_crypt_ecb( (mbedtls_des_context *) ctx, input, output ); +} + +static int des3_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + ((void) operation); + return mbedtls_des3_crypt_ecb( (mbedtls_des3_context *) ctx, input, output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int des_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_des_crypt_cbc( (mbedtls_des_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int des3_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, size_t length, + unsigned char *iv, const unsigned char *input, unsigned char *output ) +{ + return mbedtls_des3_crypt_cbc( (mbedtls_des3_context *) ctx, operation, length, iv, input, + output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static int des_setkey_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des_setkey_dec( (mbedtls_des_context *) ctx, key ); +} + +static int des_setkey_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des_setkey_enc( (mbedtls_des_context *) ctx, key ); +} + +static int des3_set2key_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set2key_dec( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set2key_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set2key_enc( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set3key_dec_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set3key_dec( (mbedtls_des3_context *) ctx, key ); +} + +static int des3_set3key_enc_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) key_bitlen); + + return mbedtls_des3_set3key_enc( (mbedtls_des3_context *) ctx, key ); +} + +static void * des_ctx_alloc( void ) +{ + mbedtls_des_context *des = mbedtls_calloc( 1, sizeof( mbedtls_des_context ) ); + + if( des == NULL ) + return( NULL ); + + mbedtls_des_init( des ); + + return( des ); +} + +static void des_ctx_free( void *ctx ) +{ + mbedtls_des_free( (mbedtls_des_context *) ctx ); + mbedtls_free( ctx ); +} + +static void * des3_ctx_alloc( void ) +{ + mbedtls_des3_context *des3; + des3 = mbedtls_calloc( 1, sizeof( mbedtls_des3_context ) ); + + if( des3 == NULL ) + return( NULL ); + + mbedtls_des3_init( des3 ); + + return( des3 ); +} + +static void des3_ctx_free( void *ctx ) +{ + mbedtls_des3_free( (mbedtls_des3_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t des_info = { + MBEDTLS_CIPHER_ID_DES, + des_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des_setkey_enc_wrap, + des_setkey_dec_wrap, + des_ctx_alloc, + des_ctx_free +}; + +static const mbedtls_cipher_info_t des_ecb_info = { + MBEDTLS_CIPHER_DES_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES, + "DES-ECB", + 8, + 0, + 8, + &des_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_cbc_info = { + MBEDTLS_CIPHER_DES_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES, + "DES-CBC", + 8, + 0, + 8, + &des_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static const mbedtls_cipher_base_t des_ede_info = { + MBEDTLS_CIPHER_ID_DES, + des3_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des3_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des3_set2key_enc_wrap, + des3_set2key_dec_wrap, + des3_ctx_alloc, + des3_ctx_free +}; + +static const mbedtls_cipher_info_t des_ede_ecb_info = { + MBEDTLS_CIPHER_DES_EDE_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES_EDE, + "DES-EDE-ECB", + 8, + 0, + 8, + &des_ede_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_ede_cbc_info = { + MBEDTLS_CIPHER_DES_EDE_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES_EDE, + "DES-EDE-CBC", + 8, + 0, + 8, + &des_ede_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +static const mbedtls_cipher_base_t des_ede3_info = { + MBEDTLS_CIPHER_ID_3DES, + des3_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + des3_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + des3_set3key_enc_wrap, + des3_set3key_dec_wrap, + des3_ctx_alloc, + des3_ctx_free +}; + +static const mbedtls_cipher_info_t des_ede3_ecb_info = { + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_MODE_ECB, + MBEDTLS_KEY_LENGTH_DES_EDE3, + "DES-EDE3-ECB", + 8, + 0, + 8, + &des_ede3_info +}; +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t des_ede3_cbc_info = { + MBEDTLS_CIPHER_DES_EDE3_CBC, + MBEDTLS_MODE_CBC, + MBEDTLS_KEY_LENGTH_DES_EDE3, + "DES-EDE3-CBC", + 8, + 0, + 8, + &des_ede3_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_BLOWFISH_C) + +static int blowfish_crypt_ecb_wrap( void *ctx, mbedtls_operation_t operation, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_ecb( (mbedtls_blowfish_context *) ctx, operation, input, + output ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static int blowfish_crypt_cbc_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, unsigned char *iv, const unsigned char *input, + unsigned char *output ) +{ + return mbedtls_blowfish_crypt_cbc( (mbedtls_blowfish_context *) ctx, operation, length, iv, + input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static int blowfish_crypt_cfb64_wrap( void *ctx, mbedtls_operation_t operation, + size_t length, size_t *iv_off, unsigned char *iv, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_cfb64( (mbedtls_blowfish_context *) ctx, operation, length, + iv_off, iv, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static int blowfish_crypt_ctr_wrap( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ) +{ + return mbedtls_blowfish_crypt_ctr( (mbedtls_blowfish_context *) ctx, length, nc_off, + nonce_counter, stream_block, input, output ); +} +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +static int blowfish_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + return mbedtls_blowfish_setkey( (mbedtls_blowfish_context *) ctx, key, key_bitlen ); +} + +static void * blowfish_ctx_alloc( void ) +{ + mbedtls_blowfish_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_blowfish_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_blowfish_init( ctx ); + + return( ctx ); +} + +static void blowfish_ctx_free( void *ctx ) +{ + mbedtls_blowfish_free( (mbedtls_blowfish_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t blowfish_info = { + MBEDTLS_CIPHER_ID_BLOWFISH, + blowfish_crypt_ecb_wrap, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + blowfish_crypt_cbc_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + blowfish_crypt_cfb64_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + blowfish_crypt_ctr_wrap, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + NULL, +#endif + blowfish_setkey_wrap, + blowfish_setkey_wrap, + blowfish_ctx_alloc, + blowfish_ctx_free +}; + +static const mbedtls_cipher_info_t blowfish_ecb_info = { + MBEDTLS_CIPHER_BLOWFISH_ECB, + MBEDTLS_MODE_ECB, + 128, + "BLOWFISH-ECB", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const mbedtls_cipher_info_t blowfish_cbc_info = { + MBEDTLS_CIPHER_BLOWFISH_CBC, + MBEDTLS_MODE_CBC, + 128, + "BLOWFISH-CBC", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +static const mbedtls_cipher_info_t blowfish_cfb64_info = { + MBEDTLS_CIPHER_BLOWFISH_CFB64, + MBEDTLS_MODE_CFB, + 128, + "BLOWFISH-CFB64", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +static const mbedtls_cipher_info_t blowfish_ctr_info = { + MBEDTLS_CIPHER_BLOWFISH_CTR, + MBEDTLS_MODE_CTR, + 128, + "BLOWFISH-CTR", + 8, + MBEDTLS_CIPHER_VARIABLE_KEY_LEN, + 8, + &blowfish_info +}; +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_ARC4_C) +static int arc4_crypt_stream_wrap( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + return( mbedtls_arc4_crypt( (mbedtls_arc4_context *) ctx, length, input, output ) ); +} + +static int arc4_setkey_wrap( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + /* we get key_bitlen in bits, arc4 expects it in bytes */ + if( key_bitlen % 8 != 0 ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + mbedtls_arc4_setup( (mbedtls_arc4_context *) ctx, key, key_bitlen / 8 ); + return( 0 ); +} + +static void * arc4_ctx_alloc( void ) +{ + mbedtls_arc4_context *ctx; + ctx = mbedtls_calloc( 1, sizeof( mbedtls_arc4_context ) ); + + if( ctx == NULL ) + return( NULL ); + + mbedtls_arc4_init( ctx ); + + return( ctx ); +} + +static void arc4_ctx_free( void *ctx ) +{ + mbedtls_arc4_free( (mbedtls_arc4_context *) ctx ); + mbedtls_free( ctx ); +} + +static const mbedtls_cipher_base_t arc4_base_info = { + MBEDTLS_CIPHER_ID_ARC4, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + arc4_crypt_stream_wrap, +#endif + arc4_setkey_wrap, + arc4_setkey_wrap, + arc4_ctx_alloc, + arc4_ctx_free +}; + +static const mbedtls_cipher_info_t arc4_128_info = { + MBEDTLS_CIPHER_ARC4_128, + MBEDTLS_MODE_STREAM, + 128, + "ARC4-128", + 0, + 0, + 1, + &arc4_base_info +}; +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +static int null_crypt_stream( void *ctx, size_t length, + const unsigned char *input, + unsigned char *output ) +{ + ((void) ctx); + memmove( output, input, length ); + return( 0 ); +} + +static int null_setkey( void *ctx, const unsigned char *key, + unsigned int key_bitlen ) +{ + ((void) ctx); + ((void) key); + ((void) key_bitlen); + + return( 0 ); +} + +static void * null_ctx_alloc( void ) +{ + return( (void *) 1 ); +} + +static void null_ctx_free( void *ctx ) +{ + ((void) ctx); +} + +static const mbedtls_cipher_base_t null_base_info = { + MBEDTLS_CIPHER_ID_NULL, + NULL, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + NULL, +#endif +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + null_crypt_stream, +#endif + null_setkey, + null_setkey, + null_ctx_alloc, + null_ctx_free +}; + +static const mbedtls_cipher_info_t null_cipher_info = { + MBEDTLS_CIPHER_NULL, + MBEDTLS_MODE_STREAM, + 0, + "NULL", + 0, + 0, + 1, + &null_base_info +}; +#endif /* defined(MBEDTLS_CIPHER_NULL_CIPHER) */ + +const mbedtls_cipher_definition_t mbedtls_cipher_definitions[] = +{ +#if defined(MBEDTLS_AES_C) + { MBEDTLS_CIPHER_AES_128_ECB, &aes_128_ecb_info }, + { MBEDTLS_CIPHER_AES_192_ECB, &aes_192_ecb_info }, + { MBEDTLS_CIPHER_AES_256_ECB, &aes_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_AES_128_CBC, &aes_128_cbc_info }, + { MBEDTLS_CIPHER_AES_192_CBC, &aes_192_cbc_info }, + { MBEDTLS_CIPHER_AES_256_CBC, &aes_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_AES_128_CFB128, &aes_128_cfb128_info }, + { MBEDTLS_CIPHER_AES_192_CFB128, &aes_192_cfb128_info }, + { MBEDTLS_CIPHER_AES_256_CFB128, &aes_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_AES_128_CTR, &aes_128_ctr_info }, + { MBEDTLS_CIPHER_AES_192_CTR, &aes_192_ctr_info }, + { MBEDTLS_CIPHER_AES_256_CTR, &aes_256_ctr_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_AES_128_GCM, &aes_128_gcm_info }, + { MBEDTLS_CIPHER_AES_192_GCM, &aes_192_gcm_info }, + { MBEDTLS_CIPHER_AES_256_GCM, &aes_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_AES_128_CCM, &aes_128_ccm_info }, + { MBEDTLS_CIPHER_AES_192_CCM, &aes_192_ccm_info }, + { MBEDTLS_CIPHER_AES_256_CCM, &aes_256_ccm_info }, +#endif +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_ARC4_C) + { MBEDTLS_CIPHER_ARC4_128, &arc4_128_info }, +#endif + +#if defined(MBEDTLS_BLOWFISH_C) + { MBEDTLS_CIPHER_BLOWFISH_ECB, &blowfish_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_BLOWFISH_CBC, &blowfish_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_BLOWFISH_CFB64, &blowfish_cfb64_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_BLOWFISH_CTR, &blowfish_ctr_info }, +#endif +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + { MBEDTLS_CIPHER_CAMELLIA_128_ECB, &camellia_128_ecb_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_ECB, &camellia_192_ecb_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_ECB, &camellia_256_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_CAMELLIA_128_CBC, &camellia_128_cbc_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CBC, &camellia_192_cbc_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CBC, &camellia_256_cbc_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CFB) + { MBEDTLS_CIPHER_CAMELLIA_128_CFB128, &camellia_128_cfb128_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CFB128, &camellia_192_cfb128_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CFB128, &camellia_256_cfb128_info }, +#endif +#if defined(MBEDTLS_CIPHER_MODE_CTR) + { MBEDTLS_CIPHER_CAMELLIA_128_CTR, &camellia_128_ctr_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CTR, &camellia_192_ctr_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CTR, &camellia_256_ctr_info }, +#endif +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_CIPHER_CAMELLIA_128_GCM, &camellia_128_gcm_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_GCM, &camellia_192_gcm_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_GCM, &camellia_256_gcm_info }, +#endif +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_CIPHER_CAMELLIA_128_CCM, &camellia_128_ccm_info }, + { MBEDTLS_CIPHER_CAMELLIA_192_CCM, &camellia_192_ccm_info }, + { MBEDTLS_CIPHER_CAMELLIA_256_CCM, &camellia_256_ccm_info }, +#endif +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) + { MBEDTLS_CIPHER_DES_ECB, &des_ecb_info }, + { MBEDTLS_CIPHER_DES_EDE_ECB, &des_ede_ecb_info }, + { MBEDTLS_CIPHER_DES_EDE3_ECB, &des_ede3_ecb_info }, +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_CIPHER_DES_CBC, &des_cbc_info }, + { MBEDTLS_CIPHER_DES_EDE_CBC, &des_ede_cbc_info }, + { MBEDTLS_CIPHER_DES_EDE3_CBC, &des_ede3_cbc_info }, +#endif +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) + { MBEDTLS_CIPHER_NULL, &null_cipher_info }, +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ + + { MBEDTLS_CIPHER_NONE, NULL } +}; + +#define NUM_CIPHERS sizeof mbedtls_cipher_definitions / sizeof mbedtls_cipher_definitions[0] +int mbedtls_cipher_supported[NUM_CIPHERS]; + +#endif /* MBEDTLS_CIPHER_C */ diff --git a/c++/src/connect/mbedtls/cmac.c b/c++/src/connect/mbedtls/cmac.c new file mode 100644 index 00000000..b2fe713a --- /dev/null +++ b/c++/src/connect/mbedtls/cmac.c @@ -0,0 +1,1074 @@ +/* + * \file cmac.c + * + * \brief NIST SP800-38B compliant CMAC implementation for AES and 3DES + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * - NIST SP 800-38B Recommendation for Block Cipher Modes of Operation: The + * CMAC Mode for Authentication + * http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38b.pdf + * + * - RFC 4493 - The AES-CMAC Algorithm + * https://tools.ietf.org/html/rfc4493 + * + * - RFC 4615 - The Advanced Encryption Standard-Cipher-based Message + * Authentication Code-Pseudo-Random Function-128 (AES-CMAC-PRF-128) + * Algorithm for the Internet Key Exchange Protocol (IKE) + * https://tools.ietf.org/html/rfc4615 + * + * Additional test vectors: ISO/IEC 9797-1 + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CMAC_C) + +#include "mbedtls/cmac.h" + +#include + + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#if defined(MBEDTLS_SELF_TEST) +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_SELF_TEST */ +#endif /* MBEDTLS_PLATFORM_C */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * Multiplication by u in the Galois field of GF(2^n) + * + * As explained in NIST SP 800-38B, this can be computed: + * + * If MSB(p) = 0, then p = (p << 1) + * If MSB(p) = 1, then p = (p << 1) ^ R_n + * with R_64 = 0x1B and R_128 = 0x87 + * + * Input and output MUST NOT point to the same buffer + * Block size must be 8 bytes or 16 bytes - the block sizes for DES and AES. + */ +static int cmac_multiply_by_u( unsigned char *output, + const unsigned char *input, + size_t blocksize ) +{ + const unsigned char R_128 = 0x87; + const unsigned char R_64 = 0x1B; + unsigned char R_n, mask; + unsigned char overflow = 0x00; + int i; + + if( blocksize == MBEDTLS_AES_BLOCK_SIZE ) + { + R_n = R_128; + } + else if( blocksize == MBEDTLS_DES3_BLOCK_SIZE ) + { + R_n = R_64; + } + else + { + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + for( i = (int)blocksize - 1; i >= 0; i-- ) + { + output[i] = input[i] << 1 | overflow; + overflow = input[i] >> 7; + } + + /* mask = ( input[0] >> 7 ) ? 0xff : 0x00 + * using bit operations to avoid branches */ + + /* MSVC has a warning about unary minus on unsigned, but this is + * well-defined and precisely what we want to do here */ +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4146 ) +#endif + mask = - ( input[0] >> 7 ); +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif + + output[ blocksize - 1 ] ^= R_n & mask; + + return( 0 ); +} + +/* + * Generate subkeys + * + * - as specified by RFC 4493, section 2.3 Subkey Generation Algorithm + */ +static int cmac_generate_subkeys( mbedtls_cipher_context_t *ctx, + unsigned char* K1, unsigned char* K2 ) +{ + int ret; + unsigned char L[MBEDTLS_CIPHER_BLKSIZE_MAX]; + size_t olen, block_size; + + mbedtls_zeroize( L, sizeof( L ) ); + + block_size = ctx->cipher_info->block_size; + + /* Calculate Ek(0) */ + if( ( ret = mbedtls_cipher_update( ctx, L, block_size, L, &olen ) ) != 0 ) + goto exit; + + /* + * Generate K1 and K2 + */ + if( ( ret = cmac_multiply_by_u( K1, L , block_size ) ) != 0 ) + goto exit; + + if( ( ret = cmac_multiply_by_u( K2, K1 , block_size ) ) != 0 ) + goto exit; + +exit: + mbedtls_zeroize( L, sizeof( L ) ); + + return( ret ); +} + +static void cmac_xor_block( unsigned char *output, const unsigned char *input1, + const unsigned char *input2, + const size_t block_size ) +{ + size_t index; + + for( index = 0; index < block_size; index++ ) + output[ index ] = input1[ index ] ^ input2[ index ]; +} + +/* + * Create padded last block from (partial) last block. + * + * We can't use the padding option from the cipher layer, as it only works for + * CBC and we use ECB mode, and anyway we need to XOR K1 or K2 in addition. + */ +static void cmac_pad( unsigned char padded_block[MBEDTLS_CIPHER_BLKSIZE_MAX], + size_t padded_block_len, + const unsigned char *last_block, + size_t last_block_len ) +{ + size_t j; + + for( j = 0; j < padded_block_len; j++ ) + { + if( j < last_block_len ) + padded_block[j] = last_block[j]; + else if( j == last_block_len ) + padded_block[j] = 0x80; + else + padded_block[j] = 0x00; + } +} + +int mbedtls_cipher_cmac_starts( mbedtls_cipher_context_t *ctx, + const unsigned char *key, size_t keybits ) +{ + mbedtls_cipher_type_t type; + mbedtls_cmac_context_t *cmac_ctx; + int retval; + + if( ctx == NULL || ctx->cipher_info == NULL || key == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + if( ( retval = mbedtls_cipher_setkey( ctx, key, (int)keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + return( retval ); + + type = ctx->cipher_info->type; + + switch( type ) + { + case MBEDTLS_CIPHER_AES_128_ECB: + case MBEDTLS_CIPHER_AES_192_ECB: + case MBEDTLS_CIPHER_AES_256_ECB: + case MBEDTLS_CIPHER_DES_EDE3_ECB: + break; + default: + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + } + + /* Allocated and initialise in the cipher context memory for the CMAC + * context */ + cmac_ctx = mbedtls_calloc( 1, sizeof( mbedtls_cmac_context_t ) ); + if( cmac_ctx == NULL ) + return( MBEDTLS_ERR_CIPHER_ALLOC_FAILED ); + + ctx->cmac_ctx = cmac_ctx; + + mbedtls_zeroize( cmac_ctx->state, sizeof( cmac_ctx->state ) ); + + return 0; +} + +int mbedtls_cipher_cmac_update( mbedtls_cipher_context_t *ctx, + const unsigned char *input, size_t ilen ) +{ + mbedtls_cmac_context_t* cmac_ctx; + unsigned char *state; + int ret = 0; + size_t n, j, olen, block_size; + + if( ctx == NULL || ctx->cipher_info == NULL || input == NULL || + ctx->cmac_ctx == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cmac_ctx = ctx->cmac_ctx; + block_size = ctx->cipher_info->block_size; + state = ctx->cmac_ctx->state; + + /* Is there data still to process from the last call, that's greater in + * size than a block? */ + if( cmac_ctx->unprocessed_len > 0 && + ilen > block_size - cmac_ctx->unprocessed_len ) + { + memcpy( &cmac_ctx->unprocessed_block[cmac_ctx->unprocessed_len], + input, + block_size - cmac_ctx->unprocessed_len ); + + cmac_xor_block( state, cmac_ctx->unprocessed_block, state, block_size ); + + if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state, + &olen ) ) != 0 ) + { + goto exit; + } + + input += block_size - cmac_ctx->unprocessed_len; + ilen -= block_size - cmac_ctx->unprocessed_len; + cmac_ctx->unprocessed_len = 0; + } + + /* n is the number of blocks including any final partial block */ + n = ( ilen + block_size - 1 ) / block_size; + + /* Iterate across the input data in block sized chunks, excluding any + * final partial or complete block */ + for( j = 1; j < n; j++ ) + { + cmac_xor_block( state, input, state, block_size ); + + if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state, + &olen ) ) != 0 ) + goto exit; + + ilen -= block_size; + input += block_size; + } + + /* If there is data left over that wasn't aligned to a block */ + if( ilen > 0 ) + { + memcpy( &cmac_ctx->unprocessed_block[cmac_ctx->unprocessed_len], + input, + ilen ); + cmac_ctx->unprocessed_len += ilen; + } + +exit: + return( ret ); +} + +int mbedtls_cipher_cmac_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output ) +{ + mbedtls_cmac_context_t* cmac_ctx; + unsigned char *state, *last_block; + unsigned char K1[MBEDTLS_CIPHER_BLKSIZE_MAX]; + unsigned char K2[MBEDTLS_CIPHER_BLKSIZE_MAX]; + unsigned char M_last[MBEDTLS_CIPHER_BLKSIZE_MAX]; + int ret; + size_t olen, block_size; + + if( ctx == NULL || ctx->cipher_info == NULL || ctx->cmac_ctx == NULL || + output == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cmac_ctx = ctx->cmac_ctx; + block_size = ctx->cipher_info->block_size; + state = cmac_ctx->state; + + mbedtls_zeroize( K1, sizeof( K1 ) ); + mbedtls_zeroize( K2, sizeof( K2 ) ); + cmac_generate_subkeys( ctx, K1, K2 ); + + last_block = cmac_ctx->unprocessed_block; + + /* Calculate last block */ + if( cmac_ctx->unprocessed_len < block_size ) + { + cmac_pad( M_last, block_size, last_block, cmac_ctx->unprocessed_len ); + cmac_xor_block( M_last, M_last, K2, block_size ); + } + else + { + /* Last block is complete block */ + cmac_xor_block( M_last, last_block, K1, block_size ); + } + + + cmac_xor_block( state, M_last, state, block_size ); + if( ( ret = mbedtls_cipher_update( ctx, state, block_size, state, + &olen ) ) != 0 ) + { + goto exit; + } + + memcpy( output, state, block_size ); + +exit: + /* Wipe the generated keys on the stack, and any other transients to avoid + * side channel leakage */ + mbedtls_zeroize( K1, sizeof( K1 ) ); + mbedtls_zeroize( K2, sizeof( K2 ) ); + + cmac_ctx->unprocessed_len = 0; + mbedtls_zeroize( cmac_ctx->unprocessed_block, + sizeof( cmac_ctx->unprocessed_block ) ); + + mbedtls_zeroize( state, MBEDTLS_CIPHER_BLKSIZE_MAX ); + return( ret ); +} + +int mbedtls_cipher_cmac_reset( mbedtls_cipher_context_t *ctx ) +{ + mbedtls_cmac_context_t* cmac_ctx; + + if( ctx == NULL || ctx->cipher_info == NULL || ctx->cmac_ctx == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cmac_ctx = ctx->cmac_ctx; + + /* Reset the internal state */ + cmac_ctx->unprocessed_len = 0; + mbedtls_zeroize( cmac_ctx->unprocessed_block, + sizeof( cmac_ctx->unprocessed_block ) ); + mbedtls_zeroize( cmac_ctx->state, + sizeof( cmac_ctx->state ) ); + + return( 0 ); +} + +int mbedtls_cipher_cmac( const mbedtls_cipher_info_t *cipher_info, + const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_cipher_context_t ctx; + int ret; + + if( cipher_info == NULL || key == NULL || input == NULL || output == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + mbedtls_cipher_init( &ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx, cipher_info ) ) != 0 ) + goto exit; + + ret = mbedtls_cipher_cmac_starts( &ctx, key, keylen ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_cipher_cmac_update( &ctx, input, ilen ); + if( ret != 0 ) + goto exit; + + ret = mbedtls_cipher_cmac_finish( &ctx, output ); + +exit: + mbedtls_cipher_free( &ctx ); + + return( ret ); +} + +#if defined(MBEDTLS_AES_C) +/* + * Implementation of AES-CMAC-PRF-128 defined in RFC 4615 + */ +int mbedtls_aes_cmac_prf_128( const unsigned char *key, size_t key_length, + const unsigned char *input, size_t in_len, + unsigned char *output ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + unsigned char zero_key[MBEDTLS_AES_BLOCK_SIZE]; + unsigned char int_key[MBEDTLS_AES_BLOCK_SIZE]; + + if( key == NULL || input == NULL || output == NULL ) + return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA ); + + cipher_info = mbedtls_cipher_info_from_type( MBEDTLS_CIPHER_AES_128_ECB ); + if( cipher_info == NULL ) + { + /* Failing at this point must be due to a build issue */ + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + goto exit; + } + + if( key_length == MBEDTLS_AES_BLOCK_SIZE ) + { + /* Use key as is */ + memcpy( int_key, key, MBEDTLS_AES_BLOCK_SIZE ); + } + else + { + memset( zero_key, 0, MBEDTLS_AES_BLOCK_SIZE ); + + ret = mbedtls_cipher_cmac( cipher_info, zero_key, 128, key, + key_length, int_key ); + if( ret != 0 ) + goto exit; + } + + ret = mbedtls_cipher_cmac( cipher_info, int_key, 128, input, in_len, + output ); + +exit: + mbedtls_zeroize( int_key, sizeof( int_key ) ); + + return( ret ); +} +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * CMAC test data for SP800-38B + * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/AES_CMAC.pdf + * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/TDES_CMAC.pdf + * + * AES-CMAC-PRF-128 test data from RFC 4615 + * https://tools.ietf.org/html/rfc4615#page-4 + */ + +#define NB_CMAC_TESTS_PER_KEY 4 +#define NB_PRF_TESTS 3 + +#if defined(MBEDTLS_AES_C) || defined(MBEDTLS_DES_C) +/* All CMAC test inputs are truncated from the same 64 byte buffer. */ +static const unsigned char test_message[] = { + /* PT */ + 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, + 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a, + 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, + 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51, + 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, + 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef, + 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, + 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 +}; +#endif /* MBEDTLS_AES_C || MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) +/* Truncation point of message for AES CMAC tests */ +static const unsigned int aes_message_lengths[NB_CMAC_TESTS_PER_KEY] = { + /* Mlen */ + 0, + 16, + 20, + 64 +}; + +/* CMAC-AES128 Test Data */ +static const unsigned char aes_128_key[16] = { + 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, + 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c +}; +static const unsigned char aes_128_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0xfb, 0xee, 0xd6, 0x18, 0x35, 0x71, 0x33, 0x66, + 0x7c, 0x85, 0xe0, 0x8f, 0x72, 0x36, 0xa8, 0xde + }, + { + /* K2 */ + 0xf7, 0xdd, 0xac, 0x30, 0x6a, 0xe2, 0x66, 0xcc, + 0xf9, 0x0b, 0xc1, 0x1e, 0xe4, 0x6d, 0x51, 0x3b + } +}; +static const unsigned char aes_128_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* Example #1 */ + 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, + 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 + }, + { + /* Example #2 */ + 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, + 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c + }, + { + /* Example #3 */ + 0x7d, 0x85, 0x44, 0x9e, 0xa6, 0xea, 0x19, 0xc8, + 0x23, 0xa7, 0xbf, 0x78, 0x83, 0x7d, 0xfa, 0xde + }, + { + /* Example #4 */ + 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, + 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe + } +}; + +/* CMAC-AES192 Test Data */ +static const unsigned char aes_192_key[24] = { + 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, + 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5, + 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b +}; +static const unsigned char aes_192_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0x44, 0x8a, 0x5b, 0x1c, 0x93, 0x51, 0x4b, 0x27, + 0x3e, 0xe6, 0x43, 0x9d, 0xd4, 0xda, 0xa2, 0x96 + }, + { + /* K2 */ + 0x89, 0x14, 0xb6, 0x39, 0x26, 0xa2, 0x96, 0x4e, + 0x7d, 0xcc, 0x87, 0x3b, 0xa9, 0xb5, 0x45, 0x2c + } +}; +static const unsigned char aes_192_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* Example #1 */ + 0xd1, 0x7d, 0xdf, 0x46, 0xad, 0xaa, 0xcd, 0xe5, + 0x31, 0xca, 0xc4, 0x83, 0xde, 0x7a, 0x93, 0x67 + }, + { + /* Example #2 */ + 0x9e, 0x99, 0xa7, 0xbf, 0x31, 0xe7, 0x10, 0x90, + 0x06, 0x62, 0xf6, 0x5e, 0x61, 0x7c, 0x51, 0x84 + }, + { + /* Example #3 */ + 0x3d, 0x75, 0xc1, 0x94, 0xed, 0x96, 0x07, 0x04, + 0x44, 0xa9, 0xfa, 0x7e, 0xc7, 0x40, 0xec, 0xf8 + }, + { + /* Example #4 */ + 0xa1, 0xd5, 0xdf, 0x0e, 0xed, 0x79, 0x0f, 0x79, + 0x4d, 0x77, 0x58, 0x96, 0x59, 0xf3, 0x9a, 0x11 + } +}; + +/* CMAC-AES256 Test Data */ +static const unsigned char aes_256_key[32] = { + 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, + 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81, + 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, + 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4 +}; +static const unsigned char aes_256_subkeys[2][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* K1 */ + 0xca, 0xd1, 0xed, 0x03, 0x29, 0x9e, 0xed, 0xac, + 0x2e, 0x9a, 0x99, 0x80, 0x86, 0x21, 0x50, 0x2f + }, + { + /* K2 */ + 0x95, 0xa3, 0xda, 0x06, 0x53, 0x3d, 0xdb, 0x58, + 0x5d, 0x35, 0x33, 0x01, 0x0c, 0x42, 0xa0, 0xd9 + } +}; +static const unsigned char aes_256_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_AES_BLOCK_SIZE] = { + { + /* Example #1 */ + 0x02, 0x89, 0x62, 0xf6, 0x1b, 0x7b, 0xf8, 0x9e, + 0xfc, 0x6b, 0x55, 0x1f, 0x46, 0x67, 0xd9, 0x83 + }, + { + /* Example #2 */ + 0x28, 0xa7, 0x02, 0x3f, 0x45, 0x2e, 0x8f, 0x82, + 0xbd, 0x4b, 0xf2, 0x8d, 0x8c, 0x37, 0xc3, 0x5c + }, + { + /* Example #3 */ + 0x15, 0x67, 0x27, 0xdc, 0x08, 0x78, 0x94, 0x4a, + 0x02, 0x3c, 0x1f, 0xe0, 0x3b, 0xad, 0x6d, 0x93 + }, + { + /* Example #4 */ + 0xe1, 0x99, 0x21, 0x90, 0x54, 0x9f, 0x6e, 0xd5, + 0x69, 0x6a, 0x2c, 0x05, 0x6c, 0x31, 0x54, 0x10 + } +}; +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_DES_C) +/* Truncation point of message for 3DES CMAC tests */ +static const unsigned int des3_message_lengths[NB_CMAC_TESTS_PER_KEY] = { + 0, + 16, + 20, + 32 +}; + +/* CMAC-TDES (Generation) - 2 Key Test Data */ +static const unsigned char des3_2key_key[24] = { + /* Key1 */ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, + /* Key2 */ + 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xEF, 0x01, + /* Key3 */ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef +}; +static const unsigned char des3_2key_subkeys[2][8] = { + { + /* K1 */ + 0x0d, 0xd2, 0xcb, 0x7a, 0x3d, 0x88, 0x88, 0xd9 + }, + { + /* K2 */ + 0x1b, 0xa5, 0x96, 0xf4, 0x7b, 0x11, 0x11, 0xb2 + } +}; +static const unsigned char des3_2key_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_DES3_BLOCK_SIZE] = { + { + /* Sample #1 */ + 0x79, 0xce, 0x52, 0xa7, 0xf7, 0x86, 0xa9, 0x60 + }, + { + /* Sample #2 */ + 0xcc, 0x18, 0xa0, 0xb7, 0x9a, 0xf2, 0x41, 0x3b + }, + { + /* Sample #3 */ + 0xc0, 0x6d, 0x37, 0x7e, 0xcd, 0x10, 0x19, 0x69 + }, + { + /* Sample #4 */ + 0x9c, 0xd3, 0x35, 0x80, 0xf9, 0xb6, 0x4d, 0xfb + } +}; + +/* CMAC-TDES (Generation) - 3 Key Test Data */ +static const unsigned char des3_3key_key[24] = { + /* Key1 */ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xaa, 0xcd, 0xef, + /* Key2 */ + 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, + /* Key3 */ + 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0x01, 0x23 +}; +static const unsigned char des3_3key_subkeys[2][8] = { + { + /* K1 */ + 0x9d, 0x74, 0xe7, 0x39, 0x33, 0x17, 0x96, 0xc0 + }, + { + /* K2 */ + 0x3a, 0xe9, 0xce, 0x72, 0x66, 0x2f, 0x2d, 0x9b + } +}; +static const unsigned char des3_3key_expected_result[NB_CMAC_TESTS_PER_KEY][MBEDTLS_DES3_BLOCK_SIZE] = { + { + /* Sample #1 */ + 0x7d, 0xb0, 0xd3, 0x7d, 0xf9, 0x36, 0xc5, 0x50 + }, + { + /* Sample #2 */ + 0x30, 0x23, 0x9c, 0xf1, 0xf5, 0x2e, 0x66, 0x09 + }, + { + /* Sample #3 */ + 0x6c, 0x9f, 0x3e, 0xe4, 0x92, 0x3f, 0x6b, 0xe2 + }, + { + /* Sample #4 */ + 0x99, 0x42, 0x9b, 0xd0, 0xbF, 0x79, 0x04, 0xe5 + } +}; + +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) +/* AES AES-CMAC-PRF-128 Test Data */ +static const unsigned char PRFK[] = { + /* Key */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0xed, 0xcb +}; + +/* Sizes in bytes */ +static const size_t PRFKlen[NB_PRF_TESTS] = { + 18, + 16, + 10 +}; + +/* Message */ +static const unsigned char PRFM[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13 +}; + +static const unsigned char PRFT[NB_PRF_TESTS][16] = { + { + 0x84, 0xa3, 0x48, 0xa4, 0xa4, 0x5d, 0x23, 0x5b, + 0xab, 0xff, 0xfc, 0x0d, 0x2b, 0x4d, 0xa0, 0x9a + }, + { + 0x98, 0x0a, 0xe8, 0x7b, 0x5f, 0x4c, 0x9c, 0x52, + 0x14, 0xf5, 0xb6, 0xa8, 0x45, 0x5e, 0x4c, 0x2d + }, + { + 0x29, 0x0d, 0x9e, 0x11, 0x2e, 0xdb, 0x09, 0xee, + 0x14, 0x1f, 0xcf, 0x64, 0xc0, 0xb7, 0x2f, 0x3d + } +}; +#endif /* MBEDTLS_AES_C */ + +static int cmac_test_subkeys( int verbose, + const char* testname, + const unsigned char* key, + int keybits, + const unsigned char* subkeys, + mbedtls_cipher_type_t cipher_type, + int block_size, + int num_tests ) +{ + int i, ret; + mbedtls_cipher_context_t ctx; + const mbedtls_cipher_info_t *cipher_info; + unsigned char K1[MBEDTLS_CIPHER_BLKSIZE_MAX]; + unsigned char K2[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + cipher_info = mbedtls_cipher_info_from_type( cipher_type ); + if( cipher_info == NULL ) + { + /* Failing at this point must be due to a build issue */ + return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE ); + } + + for( i = 0; i < num_tests; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " %s CMAC subkey #%u: ", testname, i + 1 ); + + mbedtls_cipher_init( &ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx, cipher_info ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "test execution failed\n" ); + + goto cleanup; + } + + if( ( ret = mbedtls_cipher_setkey( &ctx, key, keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "test execution failed\n" ); + + goto cleanup; + } + + ret = cmac_generate_subkeys( &ctx, K1, K2 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + goto cleanup; + } + + if( ( ret = memcmp( K1, subkeys, block_size ) ) != 0 || + ( ret = memcmp( K2, &subkeys[block_size], block_size ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + goto cleanup; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + mbedtls_cipher_free( &ctx ); + } + + goto exit; + +cleanup: + mbedtls_cipher_free( &ctx ); + +exit: + return( ret ); +} + +static int cmac_test_wth_cipher( int verbose, + const char* testname, + const unsigned char* key, + int keybits, + const unsigned char* messages, + const unsigned int message_lengths[4], + const unsigned char* expected_result, + mbedtls_cipher_type_t cipher_type, + int block_size, + int num_tests ) +{ + const mbedtls_cipher_info_t *cipher_info; + int i, ret; + unsigned char output[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + cipher_info = mbedtls_cipher_info_from_type( cipher_type ); + if( cipher_info == NULL ) + { + /* Failing at this point must be due to a build issue */ + ret = MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE; + goto exit; + } + + for( i = 0; i < num_tests; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " %s CMAC #%u: ", testname, i + 1 ); + + if( ( ret = mbedtls_cipher_cmac( cipher_info, key, keybits, messages, + message_lengths[i], output ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + goto exit; + } + + if( ( ret = memcmp( output, &expected_result[i * block_size], block_size ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + +exit: + return( ret ); +} + +#if defined(MBEDTLS_AES_C) +static int test_aes128_cmac_prf( int verbose ) +{ + int i; + int ret; + unsigned char output[MBEDTLS_AES_BLOCK_SIZE]; + + for( i = 0; i < NB_PRF_TESTS; i++ ) + { + mbedtls_printf( " AES CMAC 128 PRF #%u: ", i ); + ret = mbedtls_aes_cmac_prf_128( PRFK, PRFKlen[i], PRFM, 20, output ); + if( ret != 0 || + memcmp( output, PRFT[i], MBEDTLS_AES_BLOCK_SIZE ) != 0 ) + { + + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + else if( verbose != 0 ) + { + mbedtls_printf( "passed\n" ); + } + } + return( ret ); +} +#endif /* MBEDTLS_AES_C */ + +int mbedtls_cmac_self_test( int verbose ) +{ + int ret; + +#if defined(MBEDTLS_AES_C) + /* AES-128 */ + if( ( ret = cmac_test_subkeys( verbose, + "AES 128", + aes_128_key, + 128, + (const unsigned char*)aes_128_subkeys, + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "AES 128", + aes_128_key, + 128, + test_message, + aes_message_lengths, + (const unsigned char*)aes_128_expected_result, + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + /* AES-192 */ + if( ( ret = cmac_test_subkeys( verbose, + "AES 192", + aes_192_key, + 192, + (const unsigned char*)aes_192_subkeys, + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "AES 192", + aes_192_key, + 192, + test_message, + aes_message_lengths, + (const unsigned char*)aes_192_expected_result, + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + /* AES-256 */ + if( ( ret = cmac_test_subkeys( verbose, + "AES 256", + aes_256_key, + 256, + (const unsigned char*)aes_256_subkeys, + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher ( verbose, + "AES 256", + aes_256_key, + 256, + test_message, + aes_message_lengths, + (const unsigned char*)aes_256_expected_result, + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_AES_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_DES_C) + /* 3DES 2 key */ + if( ( ret = cmac_test_subkeys( verbose, + "3DES 2 key", + des3_2key_key, + 192, + (const unsigned char*)des3_2key_subkeys, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "3DES 2 key", + des3_2key_key, + 192, + test_message, + des3_message_lengths, + (const unsigned char*)des3_2key_expected_result, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + /* 3DES 3 key */ + if( ( ret = cmac_test_subkeys( verbose, + "3DES 3 key", + des3_3key_key, + 192, + (const unsigned char*)des3_3key_subkeys, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = cmac_test_wth_cipher( verbose, + "3DES 3 key", + des3_3key_key, + 192, + test_message, + des3_message_lengths, + (const unsigned char*)des3_3key_expected_result, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_DES3_BLOCK_SIZE, + NB_CMAC_TESTS_PER_KEY ) ) != 0 ) + { + return( ret ); + } +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) + if( ( ret = test_aes128_cmac_prf( verbose ) ) != 0 ) + return( ret ); +#endif /* MBEDTLS_AES_C */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CMAC_C */ diff --git a/c++/src/connect/mbedtls/ctr_drbg.c b/c++/src/connect/mbedtls/ctr_drbg.c new file mode 100644 index 00000000..55612c7f --- /dev/null +++ b/c++/src/connect/mbedtls/ctr_drbg.c @@ -0,0 +1,594 @@ +/* + * CTR_DRBG implementation based on AES-256 (NIST SP 800-90) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The NIST SP 800-90 DRBGs are described in the following publucation. + * + * http://csrc.nist.gov/publications/nistpubs/800-90/SP800-90revised_March2007.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) + +#include "mbedtls/ctr_drbg.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * CTR_DRBG context initialization + */ +void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ctr_drbg_context ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +/* + * Non-public function wrapped by mbedtls_ctr_drbg_seed(). Necessary to allow + * NIST tests to succeed (which require known length fixed entropy) + */ +int mbedtls_ctr_drbg_seed_entropy_len( + mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len, + size_t entropy_len ) +{ + int ret; + unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; + + memset( key, 0, MBEDTLS_CTR_DRBG_KEYSIZE ); + + mbedtls_aes_init( &ctx->aes_ctx ); + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + ctx->entropy_len = entropy_len; + ctx->reseed_interval = MBEDTLS_CTR_DRBG_RESEED_INTERVAL; + + /* + * Initialize with an empty key + */ + mbedtls_aes_setkey_enc( &ctx->aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ); + + if( ( ret = mbedtls_ctr_drbg_reseed( ctx, custom, len ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ) +{ + return( mbedtls_ctr_drbg_seed_entropy_len( ctx, f_entropy, p_entropy, custom, len, + MBEDTLS_CTR_DRBG_ENTROPY_LEN ) ); +} + +void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + mbedtls_aes_free( &ctx->aes_ctx ); + mbedtls_zeroize( ctx, sizeof( mbedtls_ctr_drbg_context ) ); +} + +void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, int resistance ) +{ + ctx->prediction_resistance = resistance; +} + +void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, size_t len ) +{ + ctx->entropy_len = len; +} + +void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, int interval ) +{ + ctx->reseed_interval = interval; +} + +static int block_cipher_df( unsigned char *output, + const unsigned char *data, size_t data_len ) +{ + unsigned char buf[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16]; + unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char key[MBEDTLS_CTR_DRBG_KEYSIZE]; + unsigned char chain[MBEDTLS_CTR_DRBG_BLOCKSIZE]; + unsigned char *p, *iv; + mbedtls_aes_context aes_ctx; + + int i, j; + size_t buf_len, use_len; + + if( data_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( buf, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT + MBEDTLS_CTR_DRBG_BLOCKSIZE + 16 ); + mbedtls_aes_init( &aes_ctx ); + + /* + * Construct IV (16 bytes) and S in buffer + * IV = Counter (in 32-bits) padded to 16 with zeroes + * S = Length input string (in 32-bits) || Length of output (in 32-bits) || + * data || 0x80 + * (Total is padded to a multiple of 16-bytes with zeroes) + */ + p = buf + MBEDTLS_CTR_DRBG_BLOCKSIZE; + *p++ = ( data_len >> 24 ) & 0xff; + *p++ = ( data_len >> 16 ) & 0xff; + *p++ = ( data_len >> 8 ) & 0xff; + *p++ = ( data_len ) & 0xff; + p += 3; + *p++ = MBEDTLS_CTR_DRBG_SEEDLEN; + memcpy( p, data, data_len ); + p[data_len] = 0x80; + + buf_len = MBEDTLS_CTR_DRBG_BLOCKSIZE + 8 + data_len + 1; + + for( i = 0; i < MBEDTLS_CTR_DRBG_KEYSIZE; i++ ) + key[i] = i; + + mbedtls_aes_setkey_enc( &aes_ctx, key, MBEDTLS_CTR_DRBG_KEYBITS ); + + /* + * Reduce data to MBEDTLS_CTR_DRBG_SEEDLEN bytes of data + */ + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + p = buf; + memset( chain, 0, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + use_len = buf_len; + + while( use_len > 0 ) + { + for( i = 0; i < MBEDTLS_CTR_DRBG_BLOCKSIZE; i++ ) + chain[i] ^= p[i]; + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + use_len -= ( use_len >= MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? + MBEDTLS_CTR_DRBG_BLOCKSIZE : use_len; + + mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, chain, chain ); + } + + memcpy( tmp + j, chain, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + + /* + * Update IV + */ + buf[3]++; + } + + /* + * Do final encryption with reduced data + */ + mbedtls_aes_setkey_enc( &aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ); + iv = tmp + MBEDTLS_CTR_DRBG_KEYSIZE; + p = output; + + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + mbedtls_aes_crypt_ecb( &aes_ctx, MBEDTLS_AES_ENCRYPT, iv, iv ); + memcpy( p, iv, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } + + mbedtls_aes_free( &aes_ctx ); + + return( 0 ); +} + +static int ctr_drbg_update_internal( mbedtls_ctr_drbg_context *ctx, + const unsigned char data[MBEDTLS_CTR_DRBG_SEEDLEN] ) +{ + unsigned char tmp[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char *p = tmp; + int i, j; + + memset( tmp, 0, MBEDTLS_CTR_DRBG_SEEDLEN ); + + for( j = 0; j < MBEDTLS_CTR_DRBG_SEEDLEN; j += MBEDTLS_CTR_DRBG_BLOCKSIZE ) + { + /* + * Increase counter + */ + for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, p ); + + p += MBEDTLS_CTR_DRBG_BLOCKSIZE; + } + + for( i = 0; i < MBEDTLS_CTR_DRBG_SEEDLEN; i++ ) + tmp[i] ^= data[i]; + + /* + * Update key and counter + */ + mbedtls_aes_setkey_enc( &ctx->aes_ctx, tmp, MBEDTLS_CTR_DRBG_KEYBITS ); + memcpy( ctx->counter, tmp + MBEDTLS_CTR_DRBG_KEYSIZE, MBEDTLS_CTR_DRBG_BLOCKSIZE ); + + return( 0 ); +} + +void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ) +{ + unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + + if( add_len > 0 ) + { + /* MAX_INPUT would be more logical here, but we have to match + * block_cipher_df()'s limits since we can't propagate errors */ + if( add_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ) + add_len = MBEDTLS_CTR_DRBG_MAX_SEED_INPUT; + + block_cipher_df( add_input, additional, add_len ); + ctr_drbg_update_internal( ctx, add_input ); + } +} + +int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ) +{ + unsigned char seed[MBEDTLS_CTR_DRBG_MAX_SEED_INPUT]; + size_t seedlen = 0; + + if( ctx->entropy_len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT || + len > MBEDTLS_CTR_DRBG_MAX_SEED_INPUT - ctx->entropy_len ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( seed, 0, MBEDTLS_CTR_DRBG_MAX_SEED_INPUT ); + + /* + * Gather entropy_len bytes of entropy to seed state + */ + if( 0 != ctx->f_entropy( ctx->p_entropy, seed, + ctx->entropy_len ) ) + { + return( MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED ); + } + + seedlen += ctx->entropy_len; + + /* + * Add additional data + */ + if( additional && len ) + { + memcpy( seed + seedlen, additional, len ); + seedlen += len; + } + + /* + * Reduce to 384 bits + */ + block_cipher_df( seed, seed, seedlen ); + + /* + * Update state + */ + ctr_drbg_update_internal( ctx, seed ); + ctx->reseed_counter = 1; + + return( 0 ); +} + +int mbedtls_ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ) +{ + int ret = 0; + mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng; + unsigned char add_input[MBEDTLS_CTR_DRBG_SEEDLEN]; + unsigned char *p = output; + unsigned char tmp[MBEDTLS_CTR_DRBG_BLOCKSIZE]; + int i; + size_t use_len; + + if( output_len > MBEDTLS_CTR_DRBG_MAX_REQUEST ) + return( MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG ); + + if( add_len > MBEDTLS_CTR_DRBG_MAX_INPUT ) + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + + memset( add_input, 0, MBEDTLS_CTR_DRBG_SEEDLEN ); + + if( ctx->reseed_counter > ctx->reseed_interval || + ctx->prediction_resistance ) + { + if( ( ret = mbedtls_ctr_drbg_reseed( ctx, additional, add_len ) ) != 0 ) + return( ret ); + + add_len = 0; + } + + if( add_len > 0 ) + { + block_cipher_df( add_input, additional, add_len ); + ctr_drbg_update_internal( ctx, add_input ); + } + + while( output_len > 0 ) + { + /* + * Increase counter + */ + for( i = MBEDTLS_CTR_DRBG_BLOCKSIZE; i > 0; i-- ) + if( ++ctx->counter[i - 1] != 0 ) + break; + + /* + * Crypt counter block + */ + mbedtls_aes_crypt_ecb( &ctx->aes_ctx, MBEDTLS_AES_ENCRYPT, ctx->counter, tmp ); + + use_len = ( output_len > MBEDTLS_CTR_DRBG_BLOCKSIZE ) ? MBEDTLS_CTR_DRBG_BLOCKSIZE : + output_len; + /* + * Copy random block to destination + */ + memcpy( p, tmp, use_len ); + p += use_len; + output_len -= use_len; + } + + ctr_drbg_update_internal( ctx, add_input ); + + ctx->reseed_counter++; + + return( 0 ); +} + +int mbedtls_ctr_drbg_random( void *p_rng, unsigned char *output, size_t output_len ) +{ + int ret; + mbedtls_ctr_drbg_context *ctx = (mbedtls_ctr_drbg_context *) p_rng; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = mbedtls_ctr_drbg_random_with_add( ctx, output, output_len, NULL, 0 ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ) +{ + int ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + FILE *f; + unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + + if( ( ret = mbedtls_ctr_drbg_random( ctx, buf, MBEDTLS_CTR_DRBG_MAX_INPUT ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, MBEDTLS_CTR_DRBG_MAX_INPUT, f ) != MBEDTLS_CTR_DRBG_MAX_INPUT ) + { + ret = MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + fclose( f ); + return( ret ); +} + +int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ) +{ + FILE *f; + size_t n; + unsigned char buf[ MBEDTLS_CTR_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > MBEDTLS_CTR_DRBG_MAX_INPUT ) + { + fclose( f ); + return( MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG ); + } + + if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR ); + } + + fclose( f ); + + mbedtls_ctr_drbg_update( ctx, buf, n ); + + return( mbedtls_ctr_drbg_write_seed_file( ctx, path ) ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) + +static const unsigned char entropy_source_pr[96] = + { 0xc1, 0x80, 0x81, 0xa6, 0x5d, 0x44, 0x02, 0x16, + 0x19, 0xb3, 0xf1, 0x80, 0xb1, 0xc9, 0x20, 0x02, + 0x6a, 0x54, 0x6f, 0x0c, 0x70, 0x81, 0x49, 0x8b, + 0x6e, 0xa6, 0x62, 0x52, 0x6d, 0x51, 0xb1, 0xcb, + 0x58, 0x3b, 0xfa, 0xd5, 0x37, 0x5f, 0xfb, 0xc9, + 0xff, 0x46, 0xd2, 0x19, 0xc7, 0x22, 0x3e, 0x95, + 0x45, 0x9d, 0x82, 0xe1, 0xe7, 0x22, 0x9f, 0x63, + 0x31, 0x69, 0xd2, 0x6b, 0x57, 0x47, 0x4f, 0xa3, + 0x37, 0xc9, 0x98, 0x1c, 0x0b, 0xfb, 0x91, 0x31, + 0x4d, 0x55, 0xb9, 0xe9, 0x1c, 0x5a, 0x5e, 0xe4, + 0x93, 0x92, 0xcf, 0xc5, 0x23, 0x12, 0xd5, 0x56, + 0x2c, 0x4a, 0x6e, 0xff, 0xdc, 0x10, 0xd0, 0x68 }; + +static const unsigned char entropy_source_nopr[64] = + { 0x5a, 0x19, 0x4d, 0x5e, 0x2b, 0x31, 0x58, 0x14, + 0x54, 0xde, 0xf6, 0x75, 0xfb, 0x79, 0x58, 0xfe, + 0xc7, 0xdb, 0x87, 0x3e, 0x56, 0x89, 0xfc, 0x9d, + 0x03, 0x21, 0x7c, 0x68, 0xd8, 0x03, 0x38, 0x20, + 0xf9, 0xe6, 0x5e, 0x04, 0xd8, 0x56, 0xf3, 0xa9, + 0xc4, 0x4a, 0x4c, 0xbd, 0xc1, 0xd0, 0x08, 0x46, + 0xf5, 0x98, 0x3d, 0x77, 0x1c, 0x1b, 0x13, 0x7e, + 0x4e, 0x0f, 0x9d, 0x8e, 0xf4, 0x09, 0xf9, 0x2e }; + +static const unsigned char nonce_pers_pr[16] = + { 0xd2, 0x54, 0xfc, 0xff, 0x02, 0x1e, 0x69, 0xd2, + 0x29, 0xc9, 0xcf, 0xad, 0x85, 0xfa, 0x48, 0x6c }; + +static const unsigned char nonce_pers_nopr[16] = + { 0x1b, 0x54, 0xb8, 0xff, 0x06, 0x42, 0xbf, 0xf5, + 0x21, 0xf1, 0x5c, 0x1c, 0x0b, 0x66, 0x5f, 0x3f }; + +static const unsigned char result_pr[16] = + { 0x34, 0x01, 0x16, 0x56, 0xb4, 0x29, 0x00, 0x8f, + 0x35, 0x63, 0xec, 0xb5, 0xf2, 0x59, 0x07, 0x23 }; + +static const unsigned char result_nopr[16] = + { 0xa0, 0x54, 0x30, 0x3d, 0x8a, 0x7e, 0xa9, 0x88, + 0x9d, 0x90, 0x3e, 0x07, 0x7c, 0x6f, 0x21, 0x8f }; + +static size_t test_offset; +static int ctr_drbg_self_test_entropy( void *data, unsigned char *buf, + size_t len ) +{ + const unsigned char *p = data; + memcpy( buf, p + test_offset, len ); + test_offset += len; + return( 0 ); +} + +#define CHK( c ) if( (c) != 0 ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + return( 1 ); \ + } + +/* + * Checkup routine + */ +int mbedtls_ctr_drbg_self_test( int verbose ) +{ + mbedtls_ctr_drbg_context ctx; + unsigned char buf[16]; + + mbedtls_ctr_drbg_init( &ctx ); + + /* + * Based on a NIST CTR_DRBG test vector (PR = True) + */ + if( verbose != 0 ) + mbedtls_printf( " CTR_DRBG (PR = TRUE) : " ); + + test_offset = 0; + CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, + (void *) entropy_source_pr, nonce_pers_pr, 16, 32 ) ); + mbedtls_ctr_drbg_set_prediction_resistance( &ctx, MBEDTLS_CTR_DRBG_PR_ON ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + CHK( memcmp( buf, result_pr, MBEDTLS_CTR_DRBG_BLOCKSIZE ) ); + + mbedtls_ctr_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + /* + * Based on a NIST CTR_DRBG test vector (PR = FALSE) + */ + if( verbose != 0 ) + mbedtls_printf( " CTR_DRBG (PR = FALSE): " ); + + mbedtls_ctr_drbg_init( &ctx ); + + test_offset = 0; + CHK( mbedtls_ctr_drbg_seed_entropy_len( &ctx, ctr_drbg_self_test_entropy, + (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32 ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); + CHK( mbedtls_ctr_drbg_reseed( &ctx, NULL, 0 ) ); + CHK( mbedtls_ctr_drbg_random( &ctx, buf, 16 ) ); + CHK( memcmp( buf, result_nopr, 16 ) ); + + mbedtls_ctr_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_CTR_DRBG_C */ diff --git a/c++/src/connect/mbedtls/debug.c b/c++/src/connect/mbedtls/debug.c new file mode 100644 index 00000000..f9229b36 --- /dev/null +++ b/c++/src/connect/mbedtls/debug.c @@ -0,0 +1,368 @@ +/* + * Debugging routines + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_DEBUG_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#define mbedtls_time_t time_t +#define mbedtls_snprintf snprintf +#endif + +#include "mbedtls/debug.h" + +#include +#include +#include + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#define DEBUG_BUF_SIZE 512 + +static int debug_threshold = 0; + +void mbedtls_debug_set_threshold( int threshold ) +{ + debug_threshold = threshold; +} + +/* + * All calls to f_dbg must be made via this function + */ +static inline void debug_send_line( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *str ) +{ + /* + * If in a threaded environment, we need a thread identifier. + * Since there is no portable way to get one, use the address of the ssl + * context instead, as it shouldn't be shared between threads. + */ +#if defined(MBEDTLS_THREADING_C) + char idstr[20 + DEBUG_BUF_SIZE]; /* 0x + 16 nibbles + ': ' */ + mbedtls_snprintf( idstr, sizeof( idstr ), "%p: %s", (void*)ssl, str ); + ssl->conf->f_dbg( ssl->conf->p_dbg, level, file, line, idstr ); +#else + ssl->conf->f_dbg( ssl->conf->p_dbg, level, file, line, str ); +#endif +} + +void mbedtls_debug_print_msg( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *format, ... ) +{ + va_list argp; + char str[DEBUG_BUF_SIZE]; + int ret; + + if( NULL == ssl || NULL == ssl->conf || NULL == ssl->conf->f_dbg || level > debug_threshold ) + return; + + va_start( argp, format ); +#if defined(_WIN32) +#if defined(_TRUNCATE) + ret = _vsnprintf_s( str, DEBUG_BUF_SIZE, _TRUNCATE, format, argp ); +#else + ret = _vsnprintf( str, DEBUG_BUF_SIZE, format, argp ); + if( ret < 0 || (size_t) ret == DEBUG_BUF_SIZE ) + { + str[DEBUG_BUF_SIZE-1] = '\0'; + ret = -1; + } +#endif +#else + ret = vsnprintf( str, DEBUG_BUF_SIZE, format, argp ); +#endif + va_end( argp ); + + if( ret >= 0 && ret < DEBUG_BUF_SIZE - 1 ) + { + str[ret] = '\n'; + str[ret + 1] = '\0'; + } + + debug_send_line( ssl, level, file, line, str ); +} + +void mbedtls_debug_print_ret( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, int ret ) +{ + char str[DEBUG_BUF_SIZE]; + + if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold ) + return; + + /* + * With non-blocking I/O and examples that just retry immediately, + * the logs would be quickly flooded with WANT_READ, so ignore that. + * Don't ignore WANT_WRITE however, since is is usually rare. + */ + if( ret == MBEDTLS_ERR_SSL_WANT_READ ) + return; + + mbedtls_snprintf( str, sizeof( str ), "%s() returned %d (-0x%04x)\n", + text, ret, -ret ); + + debug_send_line( ssl, level, file, line, str ); +} + +void mbedtls_debug_print_buf( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, const char *text, + const unsigned char *buf, size_t len ) +{ + char str[DEBUG_BUF_SIZE]; + char txt[17]; + size_t i, idx = 0; + + if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold ) + return; + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "dumping '%s' (%u bytes)\n", + text, (unsigned int) len ); + + debug_send_line( ssl, level, file, line, str ); + + idx = 0; + memset( txt, 0, sizeof( txt ) ); + for( i = 0; i < len; i++ ) + { + if( i >= 4096 ) + break; + + if( i % 16 == 0 ) + { + if( i > 0 ) + { + mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %s\n", txt ); + debug_send_line( ssl, level, file, line, str ); + + idx = 0; + memset( txt, 0, sizeof( txt ) ); + } + + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, "%04x: ", + (unsigned int) i ); + + } + + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %02x", + (unsigned int) buf[i] ); + txt[i % 16] = ( buf[i] > 31 && buf[i] < 127 ) ? buf[i] : '.' ; + } + + if( len > 0 ) + { + for( /* i = i */; i % 16 != 0; i++ ) + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " " ); + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %s\n", txt ); + debug_send_line( ssl, level, file, line, str ); + } +} + +#if defined(MBEDTLS_ECP_C) +void mbedtls_debug_print_ecp( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_ecp_point *X ) +{ + char str[DEBUG_BUF_SIZE]; + + if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || level > debug_threshold ) + return; + + mbedtls_snprintf( str, sizeof( str ), "%s(X)", text ); + mbedtls_debug_print_mpi( ssl, level, file, line, str, &X->X ); + + mbedtls_snprintf( str, sizeof( str ), "%s(Y)", text ); + mbedtls_debug_print_mpi( ssl, level, file, line, str, &X->Y ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_BIGNUM_C) +void mbedtls_debug_print_mpi( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_mpi *X ) +{ + char str[DEBUG_BUF_SIZE]; + int j, k, zeros = 1; + size_t i, n, idx = 0; + + if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || X == NULL || level > debug_threshold ) + return; + + for( n = X->n - 1; n > 0; n-- ) + if( X->p[n] != 0 ) + break; + + for( j = ( sizeof(mbedtls_mpi_uint) << 3 ) - 1; j >= 0; j-- ) + if( ( ( X->p[n] >> j ) & 1 ) != 0 ) + break; + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "value of '%s' (%d bits) is:\n", + text, (int) ( ( n * ( sizeof(mbedtls_mpi_uint) << 3 ) ) + j + 1 ) ); + + debug_send_line( ssl, level, file, line, str ); + + idx = 0; + for( i = n + 1, j = 0; i > 0; i-- ) + { + if( zeros && X->p[i - 1] == 0 ) + continue; + + for( k = sizeof( mbedtls_mpi_uint ) - 1; k >= 0; k-- ) + { + if( zeros && ( ( X->p[i - 1] >> ( k << 3 ) ) & 0xFF ) == 0 ) + continue; + else + zeros = 0; + + if( j % 16 == 0 ) + { + if( j > 0 ) + { + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "\n" ); + debug_send_line( ssl, level, file, line, str ); + idx = 0; + } + } + + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " %02x", (unsigned int) + ( X->p[i - 1] >> ( k << 3 ) ) & 0xFF ); + + j++; + } + + } + + if( zeros == 1 ) + idx += mbedtls_snprintf( str + idx, sizeof( str ) - idx, " 00" ); + + mbedtls_snprintf( str + idx, sizeof( str ) - idx, "\n" ); + debug_send_line( ssl, level, file, line, str ); +} +#endif /* MBEDTLS_BIGNUM_C */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +static void debug_print_pk( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_pk_context *pk ) +{ + size_t i; + mbedtls_pk_debug_item items[MBEDTLS_PK_DEBUG_MAX_ITEMS]; + char name[16]; + + memset( items, 0, sizeof( items ) ); + + if( mbedtls_pk_debug( pk, items ) != 0 ) + { + debug_send_line( ssl, level, file, line, + "invalid PK context\n" ); + return; + } + + for( i = 0; i < MBEDTLS_PK_DEBUG_MAX_ITEMS; i++ ) + { + if( items[i].type == MBEDTLS_PK_DEBUG_NONE ) + return; + + mbedtls_snprintf( name, sizeof( name ), "%s%s", text, items[i].name ); + name[sizeof( name ) - 1] = '\0'; + + if( items[i].type == MBEDTLS_PK_DEBUG_MPI ) + mbedtls_debug_print_mpi( ssl, level, file, line, name, items[i].value ); + else +#if defined(MBEDTLS_ECP_C) + if( items[i].type == MBEDTLS_PK_DEBUG_ECP ) + mbedtls_debug_print_ecp( ssl, level, file, line, name, items[i].value ); + else +#endif + debug_send_line( ssl, level, file, line, + "should not happen\n" ); + } +} + +static void debug_print_line_by_line( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, const char *text ) +{ + char str[DEBUG_BUF_SIZE]; + const char *start, *cur; + + start = text; + for( cur = text; *cur != '\0'; cur++ ) + { + if( *cur == '\n' ) + { + size_t len = cur - start + 1; + if( len > DEBUG_BUF_SIZE - 1 ) + len = DEBUG_BUF_SIZE - 1; + + memcpy( str, start, len ); + str[len] = '\0'; + + debug_send_line( ssl, level, file, line, str ); + + start = cur + 1; + } + } +} + +void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_x509_crt *crt ) +{ + char str[DEBUG_BUF_SIZE]; + int i = 0; + + if( ssl->conf == NULL || ssl->conf->f_dbg == NULL || crt == NULL || level > debug_threshold ) + return; + + while( crt != NULL ) + { + char buf[1024]; + + mbedtls_snprintf( str, sizeof( str ), "%s #%d:\n", text, ++i ); + debug_send_line( ssl, level, file, line, str ); + + mbedtls_x509_crt_info( buf, sizeof( buf ) - 1, "", crt ); + debug_print_line_by_line( ssl, level, file, line, buf ); + + debug_print_pk( ssl, level, file, line, "crt->", &crt->pk ); + + crt = crt->next; + } +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#endif /* MBEDTLS_DEBUG_C */ diff --git a/c++/src/connect/mbedtls/des.c b/c++/src/connect/mbedtls/des.c new file mode 100644 index 00000000..09f95cfc --- /dev/null +++ b/c++/src/connect/mbedtls/des.c @@ -0,0 +1,1061 @@ +/* + * FIPS-46-3 compliant Triple-DES implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * DES, on which TDES is based, was originally designed by Horst Feistel + * at IBM in 1974, and was adopted as a standard by NIST (formerly NBS). + * + * http://csrc.nist.gov/publications/fips/fips46-3/fips46-3.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_DES_C) + +#include "mbedtls/des.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_DES_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* + * Expanded DES S-boxes + */ +static const uint32_t SB1[64] = +{ + 0x01010400, 0x00000000, 0x00010000, 0x01010404, + 0x01010004, 0x00010404, 0x00000004, 0x00010000, + 0x00000400, 0x01010400, 0x01010404, 0x00000400, + 0x01000404, 0x01010004, 0x01000000, 0x00000004, + 0x00000404, 0x01000400, 0x01000400, 0x00010400, + 0x00010400, 0x01010000, 0x01010000, 0x01000404, + 0x00010004, 0x01000004, 0x01000004, 0x00010004, + 0x00000000, 0x00000404, 0x00010404, 0x01000000, + 0x00010000, 0x01010404, 0x00000004, 0x01010000, + 0x01010400, 0x01000000, 0x01000000, 0x00000400, + 0x01010004, 0x00010000, 0x00010400, 0x01000004, + 0x00000400, 0x00000004, 0x01000404, 0x00010404, + 0x01010404, 0x00010004, 0x01010000, 0x01000404, + 0x01000004, 0x00000404, 0x00010404, 0x01010400, + 0x00000404, 0x01000400, 0x01000400, 0x00000000, + 0x00010004, 0x00010400, 0x00000000, 0x01010004 +}; + +static const uint32_t SB2[64] = +{ + 0x80108020, 0x80008000, 0x00008000, 0x00108020, + 0x00100000, 0x00000020, 0x80100020, 0x80008020, + 0x80000020, 0x80108020, 0x80108000, 0x80000000, + 0x80008000, 0x00100000, 0x00000020, 0x80100020, + 0x00108000, 0x00100020, 0x80008020, 0x00000000, + 0x80000000, 0x00008000, 0x00108020, 0x80100000, + 0x00100020, 0x80000020, 0x00000000, 0x00108000, + 0x00008020, 0x80108000, 0x80100000, 0x00008020, + 0x00000000, 0x00108020, 0x80100020, 0x00100000, + 0x80008020, 0x80100000, 0x80108000, 0x00008000, + 0x80100000, 0x80008000, 0x00000020, 0x80108020, + 0x00108020, 0x00000020, 0x00008000, 0x80000000, + 0x00008020, 0x80108000, 0x00100000, 0x80000020, + 0x00100020, 0x80008020, 0x80000020, 0x00100020, + 0x00108000, 0x00000000, 0x80008000, 0x00008020, + 0x80000000, 0x80100020, 0x80108020, 0x00108000 +}; + +static const uint32_t SB3[64] = +{ + 0x00000208, 0x08020200, 0x00000000, 0x08020008, + 0x08000200, 0x00000000, 0x00020208, 0x08000200, + 0x00020008, 0x08000008, 0x08000008, 0x00020000, + 0x08020208, 0x00020008, 0x08020000, 0x00000208, + 0x08000000, 0x00000008, 0x08020200, 0x00000200, + 0x00020200, 0x08020000, 0x08020008, 0x00020208, + 0x08000208, 0x00020200, 0x00020000, 0x08000208, + 0x00000008, 0x08020208, 0x00000200, 0x08000000, + 0x08020200, 0x08000000, 0x00020008, 0x00000208, + 0x00020000, 0x08020200, 0x08000200, 0x00000000, + 0x00000200, 0x00020008, 0x08020208, 0x08000200, + 0x08000008, 0x00000200, 0x00000000, 0x08020008, + 0x08000208, 0x00020000, 0x08000000, 0x08020208, + 0x00000008, 0x00020208, 0x00020200, 0x08000008, + 0x08020000, 0x08000208, 0x00000208, 0x08020000, + 0x00020208, 0x00000008, 0x08020008, 0x00020200 +}; + +static const uint32_t SB4[64] = +{ + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802080, 0x00800081, 0x00800001, 0x00002001, + 0x00000000, 0x00802000, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00800080, 0x00800001, + 0x00000001, 0x00002000, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002001, 0x00002080, + 0x00800081, 0x00000001, 0x00002080, 0x00800080, + 0x00002000, 0x00802080, 0x00802081, 0x00000081, + 0x00800080, 0x00800001, 0x00802000, 0x00802081, + 0x00000081, 0x00000000, 0x00000000, 0x00802000, + 0x00002080, 0x00800080, 0x00800081, 0x00000001, + 0x00802001, 0x00002081, 0x00002081, 0x00000080, + 0x00802081, 0x00000081, 0x00000001, 0x00002000, + 0x00800001, 0x00002001, 0x00802080, 0x00800081, + 0x00002001, 0x00002080, 0x00800000, 0x00802001, + 0x00000080, 0x00800000, 0x00002000, 0x00802080 +}; + +static const uint32_t SB5[64] = +{ + 0x00000100, 0x02080100, 0x02080000, 0x42000100, + 0x00080000, 0x00000100, 0x40000000, 0x02080000, + 0x40080100, 0x00080000, 0x02000100, 0x40080100, + 0x42000100, 0x42080000, 0x00080100, 0x40000000, + 0x02000000, 0x40080000, 0x40080000, 0x00000000, + 0x40000100, 0x42080100, 0x42080100, 0x02000100, + 0x42080000, 0x40000100, 0x00000000, 0x42000000, + 0x02080100, 0x02000000, 0x42000000, 0x00080100, + 0x00080000, 0x42000100, 0x00000100, 0x02000000, + 0x40000000, 0x02080000, 0x42000100, 0x40080100, + 0x02000100, 0x40000000, 0x42080000, 0x02080100, + 0x40080100, 0x00000100, 0x02000000, 0x42080000, + 0x42080100, 0x00080100, 0x42000000, 0x42080100, + 0x02080000, 0x00000000, 0x40080000, 0x42000000, + 0x00080100, 0x02000100, 0x40000100, 0x00080000, + 0x00000000, 0x40080000, 0x02080100, 0x40000100 +}; + +static const uint32_t SB6[64] = +{ + 0x20000010, 0x20400000, 0x00004000, 0x20404010, + 0x20400000, 0x00000010, 0x20404010, 0x00400000, + 0x20004000, 0x00404010, 0x00400000, 0x20000010, + 0x00400010, 0x20004000, 0x20000000, 0x00004010, + 0x00000000, 0x00400010, 0x20004010, 0x00004000, + 0x00404000, 0x20004010, 0x00000010, 0x20400010, + 0x20400010, 0x00000000, 0x00404010, 0x20404000, + 0x00004010, 0x00404000, 0x20404000, 0x20000000, + 0x20004000, 0x00000010, 0x20400010, 0x00404000, + 0x20404010, 0x00400000, 0x00004010, 0x20000010, + 0x00400000, 0x20004000, 0x20000000, 0x00004010, + 0x20000010, 0x20404010, 0x00404000, 0x20400000, + 0x00404010, 0x20404000, 0x00000000, 0x20400010, + 0x00000010, 0x00004000, 0x20400000, 0x00404010, + 0x00004000, 0x00400010, 0x20004010, 0x00000000, + 0x20404000, 0x20000000, 0x00400010, 0x20004010 +}; + +static const uint32_t SB7[64] = +{ + 0x00200000, 0x04200002, 0x04000802, 0x00000000, + 0x00000800, 0x04000802, 0x00200802, 0x04200800, + 0x04200802, 0x00200000, 0x00000000, 0x04000002, + 0x00000002, 0x04000000, 0x04200002, 0x00000802, + 0x04000800, 0x00200802, 0x00200002, 0x04000800, + 0x04000002, 0x04200000, 0x04200800, 0x00200002, + 0x04200000, 0x00000800, 0x00000802, 0x04200802, + 0x00200800, 0x00000002, 0x04000000, 0x00200800, + 0x04000000, 0x00200800, 0x00200000, 0x04000802, + 0x04000802, 0x04200002, 0x04200002, 0x00000002, + 0x00200002, 0x04000000, 0x04000800, 0x00200000, + 0x04200800, 0x00000802, 0x00200802, 0x04200800, + 0x00000802, 0x04000002, 0x04200802, 0x04200000, + 0x00200800, 0x00000000, 0x00000002, 0x04200802, + 0x00000000, 0x00200802, 0x04200000, 0x00000800, + 0x04000002, 0x04000800, 0x00000800, 0x00200002 +}; + +static const uint32_t SB8[64] = +{ + 0x10001040, 0x00001000, 0x00040000, 0x10041040, + 0x10000000, 0x10001040, 0x00000040, 0x10000000, + 0x00040040, 0x10040000, 0x10041040, 0x00041000, + 0x10041000, 0x00041040, 0x00001000, 0x00000040, + 0x10040000, 0x10000040, 0x10001000, 0x00001040, + 0x00041000, 0x00040040, 0x10040040, 0x10041000, + 0x00001040, 0x00000000, 0x00000000, 0x10040040, + 0x10000040, 0x10001000, 0x00041040, 0x00040000, + 0x00041040, 0x00040000, 0x10041000, 0x00001000, + 0x00000040, 0x10040040, 0x00001000, 0x00041040, + 0x10001000, 0x00000040, 0x10000040, 0x10040000, + 0x10040040, 0x10000000, 0x00040000, 0x10001040, + 0x00000000, 0x10041040, 0x00040040, 0x10000040, + 0x10040000, 0x10001000, 0x10001040, 0x00000000, + 0x10041040, 0x00041000, 0x00041000, 0x00001040, + 0x00001040, 0x00040040, 0x10000000, 0x10041000 +}; + +/* + * PC1: left and right halves bit-swap + */ +static const uint32_t LHs[16] = +{ + 0x00000000, 0x00000001, 0x00000100, 0x00000101, + 0x00010000, 0x00010001, 0x00010100, 0x00010101, + 0x01000000, 0x01000001, 0x01000100, 0x01000101, + 0x01010000, 0x01010001, 0x01010100, 0x01010101 +}; + +static const uint32_t RHs[16] = +{ + 0x00000000, 0x01000000, 0x00010000, 0x01010000, + 0x00000100, 0x01000100, 0x00010100, 0x01010100, + 0x00000001, 0x01000001, 0x00010001, 0x01010001, + 0x00000101, 0x01000101, 0x00010101, 0x01010101, +}; + +/* + * Initial Permutation macro + */ +#define DES_IP(X,Y) \ +{ \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + Y = ((Y << 1) | (Y >> 31)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; Y ^= T; X ^= T; \ + X = ((X << 1) | (X >> 31)) & 0xFFFFFFFF; \ +} + +/* + * Final Permutation macro + */ +#define DES_FP(X,Y) \ +{ \ + X = ((X << 31) | (X >> 1)) & 0xFFFFFFFF; \ + T = (X ^ Y) & 0xAAAAAAAA; X ^= T; Y ^= T; \ + Y = ((Y << 31) | (Y >> 1)) & 0xFFFFFFFF; \ + T = ((Y >> 8) ^ X) & 0x00FF00FF; X ^= T; Y ^= (T << 8); \ + T = ((Y >> 2) ^ X) & 0x33333333; X ^= T; Y ^= (T << 2); \ + T = ((X >> 16) ^ Y) & 0x0000FFFF; Y ^= T; X ^= (T << 16); \ + T = ((X >> 4) ^ Y) & 0x0F0F0F0F; Y ^= T; X ^= (T << 4); \ +} + +/* + * DES round macro + */ +#define DES_ROUND(X,Y) \ +{ \ + T = *SK++ ^ X; \ + Y ^= SB8[ (T ) & 0x3F ] ^ \ + SB6[ (T >> 8) & 0x3F ] ^ \ + SB4[ (T >> 16) & 0x3F ] ^ \ + SB2[ (T >> 24) & 0x3F ]; \ + \ + T = *SK++ ^ ((X << 28) | (X >> 4)); \ + Y ^= SB7[ (T ) & 0x3F ] ^ \ + SB5[ (T >> 8) & 0x3F ] ^ \ + SB3[ (T >> 16) & 0x3F ] ^ \ + SB1[ (T >> 24) & 0x3F ]; \ +} + +#define SWAP(a,b) { uint32_t t = a; a = b; b = t; t = 0; } + +void mbedtls_des_init( mbedtls_des_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_des_context ) ); +} + +void mbedtls_des_free( mbedtls_des_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_des_context ) ); +} + +void mbedtls_des3_init( mbedtls_des3_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_des3_context ) ); +} + +void mbedtls_des3_free( mbedtls_des3_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_des3_context ) ); +} + +static const unsigned char odd_parity_table[128] = { 1, 2, 4, 7, 8, + 11, 13, 14, 16, 19, 21, 22, 25, 26, 28, 31, 32, 35, 37, 38, 41, 42, 44, + 47, 49, 50, 52, 55, 56, 59, 61, 62, 64, 67, 69, 70, 73, 74, 76, 79, 81, + 82, 84, 87, 88, 91, 93, 94, 97, 98, 100, 103, 104, 107, 109, 110, 112, + 115, 117, 118, 121, 122, 124, 127, 128, 131, 133, 134, 137, 138, 140, + 143, 145, 146, 148, 151, 152, 155, 157, 158, 161, 162, 164, 167, 168, + 171, 173, 174, 176, 179, 181, 182, 185, 186, 188, 191, 193, 194, 196, + 199, 200, 203, 205, 206, 208, 211, 213, 214, 217, 218, 220, 223, 224, + 227, 229, 230, 233, 234, 236, 239, 241, 242, 244, 247, 248, 251, 253, + 254 }; + +void mbedtls_des_key_set_parity( unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < MBEDTLS_DES_KEY_SIZE; i++ ) + key[i] = odd_parity_table[key[i] / 2]; +} + +/* + * Check the given key's parity, returns 1 on failure, 0 on SUCCESS + */ +int mbedtls_des_key_check_key_parity( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < MBEDTLS_DES_KEY_SIZE; i++ ) + if( key[i] != odd_parity_table[key[i] / 2] ) + return( 1 ); + + return( 0 ); +} + +/* + * Table of weak and semi-weak keys + * + * Source: http://en.wikipedia.org/wiki/Weak_key + * + * Weak: + * Alternating ones + zeros (0x0101010101010101) + * Alternating 'F' + 'E' (0xFEFEFEFEFEFEFEFE) + * '0xE0E0E0E0F1F1F1F1' + * '0x1F1F1F1F0E0E0E0E' + * + * Semi-weak: + * 0x011F011F010E010E and 0x1F011F010E010E01 + * 0x01E001E001F101F1 and 0xE001E001F101F101 + * 0x01FE01FE01FE01FE and 0xFE01FE01FE01FE01 + * 0x1FE01FE00EF10EF1 and 0xE01FE01FF10EF10E + * 0x1FFE1FFE0EFE0EFE and 0xFE1FFE1FFE0EFE0E + * 0xE0FEE0FEF1FEF1FE and 0xFEE0FEE0FEF1FEF1 + * + */ + +#define WEAK_KEY_COUNT 16 + +static const unsigned char weak_key_table[WEAK_KEY_COUNT][MBEDTLS_DES_KEY_SIZE] = +{ + { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, + { 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE }, + { 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E }, + { 0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1 }, + + { 0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E }, + { 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01 }, + { 0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1 }, + { 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01 }, + { 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE }, + { 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01 }, + { 0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1 }, + { 0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E }, + { 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE }, + { 0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E }, + { 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE }, + { 0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1 } +}; + +int mbedtls_des_key_check_weak( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + for( i = 0; i < WEAK_KEY_COUNT; i++ ) + if( memcmp( weak_key_table[i], key, MBEDTLS_DES_KEY_SIZE) == 0 ) + return( 1 ); + + return( 0 ); +} + +#if !defined(MBEDTLS_DES_SETKEY_ALT) +void mbedtls_des_setkey( uint32_t SK[32], const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + uint32_t X, Y, T; + + GET_UINT32_BE( X, key, 0 ); + GET_UINT32_BE( Y, key, 4 ); + + /* + * Permuted Choice 1 + */ + T = ((Y >> 4) ^ X) & 0x0F0F0F0F; X ^= T; Y ^= (T << 4); + T = ((Y ) ^ X) & 0x10101010; X ^= T; Y ^= (T ); + + X = (LHs[ (X ) & 0xF] << 3) | (LHs[ (X >> 8) & 0xF ] << 2) + | (LHs[ (X >> 16) & 0xF] << 1) | (LHs[ (X >> 24) & 0xF ] ) + | (LHs[ (X >> 5) & 0xF] << 7) | (LHs[ (X >> 13) & 0xF ] << 6) + | (LHs[ (X >> 21) & 0xF] << 5) | (LHs[ (X >> 29) & 0xF ] << 4); + + Y = (RHs[ (Y >> 1) & 0xF] << 3) | (RHs[ (Y >> 9) & 0xF ] << 2) + | (RHs[ (Y >> 17) & 0xF] << 1) | (RHs[ (Y >> 25) & 0xF ] ) + | (RHs[ (Y >> 4) & 0xF] << 7) | (RHs[ (Y >> 12) & 0xF ] << 6) + | (RHs[ (Y >> 20) & 0xF] << 5) | (RHs[ (Y >> 28) & 0xF ] << 4); + + X &= 0x0FFFFFFF; + Y &= 0x0FFFFFFF; + + /* + * calculate subkeys + */ + for( i = 0; i < 16; i++ ) + { + if( i < 2 || i == 8 || i == 15 ) + { + X = ((X << 1) | (X >> 27)) & 0x0FFFFFFF; + Y = ((Y << 1) | (Y >> 27)) & 0x0FFFFFFF; + } + else + { + X = ((X << 2) | (X >> 26)) & 0x0FFFFFFF; + Y = ((Y << 2) | (Y >> 26)) & 0x0FFFFFFF; + } + + *SK++ = ((X << 4) & 0x24000000) | ((X << 28) & 0x10000000) + | ((X << 14) & 0x08000000) | ((X << 18) & 0x02080000) + | ((X << 6) & 0x01000000) | ((X << 9) & 0x00200000) + | ((X >> 1) & 0x00100000) | ((X << 10) & 0x00040000) + | ((X << 2) & 0x00020000) | ((X >> 10) & 0x00010000) + | ((Y >> 13) & 0x00002000) | ((Y >> 4) & 0x00001000) + | ((Y << 6) & 0x00000800) | ((Y >> 1) & 0x00000400) + | ((Y >> 14) & 0x00000200) | ((Y ) & 0x00000100) + | ((Y >> 5) & 0x00000020) | ((Y >> 10) & 0x00000010) + | ((Y >> 3) & 0x00000008) | ((Y >> 18) & 0x00000004) + | ((Y >> 26) & 0x00000002) | ((Y >> 24) & 0x00000001); + + *SK++ = ((X << 15) & 0x20000000) | ((X << 17) & 0x10000000) + | ((X << 10) & 0x08000000) | ((X << 22) & 0x04000000) + | ((X >> 2) & 0x02000000) | ((X << 1) & 0x01000000) + | ((X << 16) & 0x00200000) | ((X << 11) & 0x00100000) + | ((X << 3) & 0x00080000) | ((X >> 6) & 0x00040000) + | ((X << 15) & 0x00020000) | ((X >> 4) & 0x00010000) + | ((Y >> 2) & 0x00002000) | ((Y << 8) & 0x00001000) + | ((Y >> 14) & 0x00000808) | ((Y >> 9) & 0x00000400) + | ((Y ) & 0x00000200) | ((Y << 7) & 0x00000100) + | ((Y >> 7) & 0x00000020) | ((Y >> 3) & 0x00000011) + | ((Y << 2) & 0x00000004) | ((Y >> 21) & 0x00000002); + } +} +#endif /* !MBEDTLS_DES_SETKEY_ALT */ + +/* + * DES key schedule (56-bit, encryption) + */ +int mbedtls_des_setkey_enc( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + mbedtls_des_setkey( ctx->sk, key ); + + return( 0 ); +} + +/* + * DES key schedule (56-bit, decryption) + */ +int mbedtls_des_setkey_dec( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ) +{ + int i; + + mbedtls_des_setkey( ctx->sk, key ); + + for( i = 0; i < 16; i += 2 ) + { + SWAP( ctx->sk[i ], ctx->sk[30 - i] ); + SWAP( ctx->sk[i + 1], ctx->sk[31 - i] ); + } + + return( 0 ); +} + +static void des3_set2key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[MBEDTLS_DES_KEY_SIZE*2] ) +{ + int i; + + mbedtls_des_setkey( esk, key ); + mbedtls_des_setkey( dsk + 32, key + 8 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[30 - i]; + dsk[i + 1] = esk[31 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + esk[i + 64] = esk[i ]; + esk[i + 65] = esk[i + 1]; + + dsk[i + 64] = dsk[i ]; + dsk[i + 65] = dsk[i + 1]; + } +} + +/* + * Triple-DES key schedule (112-bit, encryption) + */ +int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( ctx->sk, sk, key ); + mbedtls_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (112-bit, decryption) + */ +int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ) +{ + uint32_t sk[96]; + + des3_set2key( sk, ctx->sk, key ); + mbedtls_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +static void des3_set3key( uint32_t esk[96], + uint32_t dsk[96], + const unsigned char key[24] ) +{ + int i; + + mbedtls_des_setkey( esk, key ); + mbedtls_des_setkey( dsk + 32, key + 8 ); + mbedtls_des_setkey( esk + 64, key + 16 ); + + for( i = 0; i < 32; i += 2 ) + { + dsk[i ] = esk[94 - i]; + dsk[i + 1] = esk[95 - i]; + + esk[i + 32] = dsk[62 - i]; + esk[i + 33] = dsk[63 - i]; + + dsk[i + 64] = esk[30 - i]; + dsk[i + 65] = esk[31 - i]; + } +} + +/* + * Triple-DES key schedule (168-bit, encryption) + */ +int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( ctx->sk, sk, key ); + mbedtls_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * Triple-DES key schedule (168-bit, decryption) + */ +int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ) +{ + uint32_t sk[96]; + + des3_set3key( sk, ctx->sk, key ); + mbedtls_zeroize( sk, sizeof( sk ) ); + + return( 0 ); +} + +/* + * DES-ECB block encryption/decryption + */ +#if !defined(MBEDTLS_DES_CRYPT_ECB_ALT) +int mbedtls_des_crypt_ecb( mbedtls_des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} +#endif /* !MBEDTLS_DES_CRYPT_ECB_ALT */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * DES-CBC buffer encryption/decryption + */ +int mbedtls_des_crypt_cbc( mbedtls_des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_des_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* MBEDTLS_DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + mbedtls_des_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/* + * 3DES-ECB block encryption/decryption + */ +#if !defined(MBEDTLS_DES3_CRYPT_ECB_ALT) +int mbedtls_des3_crypt_ecb( mbedtls_des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ) +{ + int i; + uint32_t X, Y, T, *SK; + + SK = ctx->sk; + + GET_UINT32_BE( X, input, 0 ); + GET_UINT32_BE( Y, input, 4 ); + + DES_IP( X, Y ); + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( X, Y ); + DES_ROUND( Y, X ); + } + + for( i = 0; i < 8; i++ ) + { + DES_ROUND( Y, X ); + DES_ROUND( X, Y ); + } + + DES_FP( Y, X ); + + PUT_UINT32_BE( Y, output, 0 ); + PUT_UINT32_BE( X, output, 4 ); + + return( 0 ); +} +#endif /* !MBEDTLS_DES3_CRYPT_ECB_ALT */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * 3DES-CBC buffer encryption/decryption + */ +int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_DES_ENCRYPT ) + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_des3_crypt_ecb( ctx, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else /* MBEDTLS_DES_DECRYPT */ + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + mbedtls_des3_crypt_ecb( ctx, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#endif /* !MBEDTLS_DES_ALT */ + +#if defined(MBEDTLS_SELF_TEST) +/* + * DES and 3DES test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip + */ +static const unsigned char des3_test_keys[24] = +{ + 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, + 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, + 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF, 0x01, 0x23 +}; + +static const unsigned char des3_test_buf[8] = +{ + 0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74 +}; + +static const unsigned char des3_test_ecb_dec[3][8] = +{ + { 0xCD, 0xD6, 0x4F, 0x2F, 0x94, 0x27, 0xC1, 0x5D }, + { 0x69, 0x96, 0xC8, 0xFA, 0x47, 0xA2, 0xAB, 0xEB }, + { 0x83, 0x25, 0x39, 0x76, 0x44, 0x09, 0x1A, 0x0A } +}; + +static const unsigned char des3_test_ecb_enc[3][8] = +{ + { 0x6A, 0x2A, 0x19, 0xF4, 0x1E, 0xCA, 0x85, 0x4B }, + { 0x03, 0xE6, 0x9F, 0x5B, 0xFA, 0x58, 0xEB, 0x42 }, + { 0xDD, 0x17, 0xE8, 0xB8, 0xB4, 0x37, 0xD2, 0x32 } +}; + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +static const unsigned char des3_test_iv[8] = +{ + 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF, +}; + +static const unsigned char des3_test_cbc_dec[3][8] = +{ + { 0x12, 0x9F, 0x40, 0xB9, 0xD2, 0x00, 0x56, 0xB3 }, + { 0x47, 0x0E, 0xFC, 0x9A, 0x6B, 0x8E, 0xE3, 0x93 }, + { 0xC5, 0xCE, 0xCF, 0x63, 0xEC, 0xEC, 0x51, 0x4C } +}; + +static const unsigned char des3_test_cbc_enc[3][8] = +{ + { 0x54, 0xF1, 0x5A, 0xF6, 0xEB, 0xE3, 0xA4, 0xB4 }, + { 0x35, 0x76, 0x11, 0x56, 0x5F, 0xA1, 0x8E, 0x4D }, + { 0xCB, 0x19, 0x1F, 0x85, 0xD1, 0xED, 0x84, 0x39 } +}; +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/* + * Checkup routine + */ +int mbedtls_des_self_test( int verbose ) +{ + int i, j, u, v, ret = 0; + mbedtls_des_context ctx; + mbedtls_des3_context ctx3; + unsigned char buf[8]; +#if defined(MBEDTLS_CIPHER_MODE_CBC) + unsigned char prv[8]; + unsigned char iv[8]; +#endif + + mbedtls_des_init( &ctx ); + mbedtls_des3_init( &ctx3 ); + /* + * ECB mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " DES%c-ECB-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == MBEDTLS_DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + mbedtls_des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + mbedtls_des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + mbedtls_des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + mbedtls_des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + mbedtls_des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + mbedtls_des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + mbedtls_des_crypt_ecb( &ctx, buf, buf ); + else + mbedtls_des3_crypt_ecb( &ctx3, buf, buf ); + } + + if( ( v == MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_ecb_dec[u], 8 ) != 0 ) || + ( v != MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_ecb_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /* + * CBC mode + */ + for( i = 0; i < 6; i++ ) + { + u = i >> 1; + v = i & 1; + + if( verbose != 0 ) + mbedtls_printf( " DES%c-CBC-%3d (%s): ", + ( u == 0 ) ? ' ' : '3', 56 + u * 56, + ( v == MBEDTLS_DES_DECRYPT ) ? "dec" : "enc" ); + + memcpy( iv, des3_test_iv, 8 ); + memcpy( prv, des3_test_iv, 8 ); + memcpy( buf, des3_test_buf, 8 ); + + switch( i ) + { + case 0: + mbedtls_des_setkey_dec( &ctx, des3_test_keys ); + break; + + case 1: + mbedtls_des_setkey_enc( &ctx, des3_test_keys ); + break; + + case 2: + mbedtls_des3_set2key_dec( &ctx3, des3_test_keys ); + break; + + case 3: + mbedtls_des3_set2key_enc( &ctx3, des3_test_keys ); + break; + + case 4: + mbedtls_des3_set3key_dec( &ctx3, des3_test_keys ); + break; + + case 5: + mbedtls_des3_set3key_enc( &ctx3, des3_test_keys ); + break; + + default: + return( 1 ); + } + + if( v == MBEDTLS_DES_DECRYPT ) + { + for( j = 0; j < 10000; j++ ) + { + if( u == 0 ) + mbedtls_des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + mbedtls_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + } + } + else + { + for( j = 0; j < 10000; j++ ) + { + unsigned char tmp[8]; + + if( u == 0 ) + mbedtls_des_crypt_cbc( &ctx, v, 8, iv, buf, buf ); + else + mbedtls_des3_crypt_cbc( &ctx3, v, 8, iv, buf, buf ); + + memcpy( tmp, prv, 8 ); + memcpy( prv, buf, 8 ); + memcpy( buf, tmp, 8 ); + } + + memcpy( buf, prv, 8 ); + } + + if( ( v == MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_cbc_dec[u], 8 ) != 0 ) || + ( v != MBEDTLS_DES_DECRYPT && + memcmp( buf, des3_test_cbc_enc[u], 8 ) != 0 ) ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_des_free( &ctx ); + mbedtls_des3_free( &ctx3 ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DES_C */ diff --git a/c++/src/connect/mbedtls/dhm.c b/c++/src/connect/mbedtls/dhm.c new file mode 100644 index 00000000..a4715d17 --- /dev/null +++ b/c++/src/connect/mbedtls/dhm.c @@ -0,0 +1,627 @@ +/* + * Diffie-Hellman-Merkle key exchange + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The following sources were referenced in the design of this implementation + * of the Diffie-Hellman-Merkle algorithm: + * + * [1] Handbook of Applied Cryptography - 1997, Chapter 12 + * Menezes, van Oorschot and Vanstone + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_DHM_C) + +#include "mbedtls/dhm.h" + +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_ASN1_PARSE_C) +#include "mbedtls/asn1.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * helper to validate the mbedtls_mpi size and import it + */ +static int dhm_read_bignum( mbedtls_mpi *X, + unsigned char **p, + const unsigned char *end ) +{ + int ret, n; + + if( end - *p < 2 ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + n = ( (*p)[0] << 8 ) | (*p)[1]; + (*p) += 2; + + if( (int)( end - *p ) < n ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_mpi_read_binary( X, *p, n ) ) != 0 ) + return( MBEDTLS_ERR_DHM_READ_PARAMS_FAILED + ret ); + + (*p) += n; + + return( 0 ); +} + +/* + * Verify sanity of parameter with regards to P + * + * Parameter should be: 2 <= public_param <= P - 2 + * + * For more information on the attack, see: + * http://www.cl.cam.ac.uk/~rja14/Papers/psandqs.pdf + * http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2005-2643 + */ +static int dhm_check_range( const mbedtls_mpi *param, const mbedtls_mpi *P ) +{ + mbedtls_mpi L, U; + int ret = MBEDTLS_ERR_DHM_BAD_INPUT_DATA; + + mbedtls_mpi_init( &L ); mbedtls_mpi_init( &U ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &L, 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &U, P, 2 ) ); + + if( mbedtls_mpi_cmp_mpi( param, &L ) >= 0 && + mbedtls_mpi_cmp_mpi( param, &U ) <= 0 ) + { + ret = 0; + } + +cleanup: + mbedtls_mpi_free( &L ); mbedtls_mpi_free( &U ); + return( ret ); +} + +void mbedtls_dhm_init( mbedtls_dhm_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_dhm_context ) ); +} + +/* + * Parse the ServerKeyExchange parameters + */ +int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, + unsigned char **p, + const unsigned char *end ) +{ + int ret; + + if( ( ret = dhm_read_bignum( &ctx->P, p, end ) ) != 0 || + ( ret = dhm_read_bignum( &ctx->G, p, end ) ) != 0 || + ( ret = dhm_read_bignum( &ctx->GY, p, end ) ) != 0 ) + return( ret ); + + if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) + return( ret ); + + ctx->len = mbedtls_mpi_size( &ctx->P ); + + return( 0 ); +} + +/* + * Setup and write the ServerKeyExchange parameters + */ +int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count = 0; + size_t n1, n2, n3; + unsigned char *p; + + if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + /* + * Generate X as large as possible ( < P ) + */ + do + { + mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ); + + while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED ); + } + while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); + + /* + * Calculate GX = G^X mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, + &ctx->P , &ctx->RP ) ); + + if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) + return( ret ); + + /* + * export P, G, GX + */ +#define DHM_MPI_EXPORT(X,n) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( X, p + 2, n ) ); \ + *p++ = (unsigned char)( n >> 8 ); \ + *p++ = (unsigned char)( n ); p += n; + + n1 = mbedtls_mpi_size( &ctx->P ); + n2 = mbedtls_mpi_size( &ctx->G ); + n3 = mbedtls_mpi_size( &ctx->GX ); + + p = output; + DHM_MPI_EXPORT( &ctx->P , n1 ); + DHM_MPI_EXPORT( &ctx->G , n2 ); + DHM_MPI_EXPORT( &ctx->GX, n3 ); + + *olen = p - output; + + ctx->len = n1; + +cleanup: + + if( ret != 0 ) + return( MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED + ret ); + + return( 0 ); +} + +/* + * Import the peer's public value G^Y + */ +int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, + const unsigned char *input, size_t ilen ) +{ + int ret; + + if( ctx == NULL || ilen < 1 || ilen > ctx->len ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_mpi_read_binary( &ctx->GY, input, ilen ) ) != 0 ) + return( MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Create own private value X and export G^X + */ +int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret, count = 0; + + if( ctx == NULL || olen < 1 || olen > ctx->len ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( mbedtls_mpi_cmp_int( &ctx->P, 0 ) == 0 ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + /* + * generate X and calculate GX = G^X mod P + */ + do + { + mbedtls_mpi_fill_random( &ctx->X, x_size, f_rng, p_rng ); + + while( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->X, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED ); + } + while( dhm_check_range( &ctx->X, &ctx->P ) != 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->GX, &ctx->G, &ctx->X, + &ctx->P , &ctx->RP ) ); + + if( ( ret = dhm_check_range( &ctx->GX, &ctx->P ) ) != 0 ) + return( ret ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->GX, output, olen ) ); + +cleanup: + + if( ret != 0 ) + return( MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Use the blinding method and optimisation suggested in section 10 of: + * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, + * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer + * Berlin Heidelberg, 1996. p. 104-113. + */ +static int dhm_update_blinding( mbedtls_dhm_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret, count; + + /* + * Don't use any blinding the first time a particular X is used, + * but remember it to use blinding next time. + */ + if( mbedtls_mpi_cmp_mpi( &ctx->X, &ctx->pX ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &ctx->pX, &ctx->X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vi, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->Vf, 1 ) ); + + return( 0 ); + } + + /* + * Ok, we need blinding. Can we re-use existing values? + * If yes, just update them by squaring them. + */ + if( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->P ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->P ) ); + + return( 0 ); + } + + /* + * We need to generate blinding values from scratch + */ + + /* Vi = random( 2, P-1 ) */ + count = 0; + do + { + mbedtls_mpi_fill_random( &ctx->Vi, mbedtls_mpi_size( &ctx->P ), f_rng, p_rng ); + + while( mbedtls_mpi_cmp_mpi( &ctx->Vi, &ctx->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &ctx->Vi, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_MPI_NOT_ACCEPTABLE ); + } + while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) <= 0 ); + + /* Vf = Vi^-X mod P */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vf, &ctx->Vi, &ctx->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vf, &ctx->Vf, &ctx->X, &ctx->P, &ctx->RP ) ); + +cleanup: + return( ret ); +} + +/* + * Derive and export the shared secret (G^Y)^X mod P + */ +int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, + unsigned char *output, size_t output_size, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi GYb; + + if( ctx == NULL || output_size < ctx->len ) + return( MBEDTLS_ERR_DHM_BAD_INPUT_DATA ); + + if( ( ret = dhm_check_range( &ctx->GY, &ctx->P ) ) != 0 ) + return( ret ); + + mbedtls_mpi_init( &GYb ); + + /* Blind peer's value */ + if( f_rng != NULL ) + { + MBEDTLS_MPI_CHK( dhm_update_blinding( ctx, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &GYb, &ctx->GY, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &GYb, &GYb, &ctx->P ) ); + } + else + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &GYb, &ctx->GY ) ); + + /* Do modular exponentiation */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->K, &GYb, &ctx->X, + &ctx->P, &ctx->RP ) ); + + /* Unblind secret value */ + if( f_rng != NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->K, &ctx->K, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->K, &ctx->K, &ctx->P ) ); + } + + *olen = mbedtls_mpi_size( &ctx->K ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &ctx->K, output, *olen ) ); + +cleanup: + mbedtls_mpi_free( &GYb ); + + if( ret != 0 ) + return( MBEDTLS_ERR_DHM_CALC_SECRET_FAILED + ret ); + + return( 0 ); +} + +/* + * Free the components of a DHM key + */ +void mbedtls_dhm_free( mbedtls_dhm_context *ctx ) +{ + mbedtls_mpi_free( &ctx->pX); mbedtls_mpi_free( &ctx->Vf ); mbedtls_mpi_free( &ctx->Vi ); + mbedtls_mpi_free( &ctx->RP ); mbedtls_mpi_free( &ctx->K ); mbedtls_mpi_free( &ctx->GY ); + mbedtls_mpi_free( &ctx->GX ); mbedtls_mpi_free( &ctx->X ); mbedtls_mpi_free( &ctx->G ); + mbedtls_mpi_free( &ctx->P ); + + mbedtls_zeroize( ctx, sizeof( mbedtls_dhm_context ) ); +} + +#if defined(MBEDTLS_ASN1_PARSE_C) +/* + * Parse DHM parameters + */ +int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, + size_t dhminlen ) +{ + int ret; + size_t len; + unsigned char *p, *end; +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_context pem; + + mbedtls_pem_init( &pem ); + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( dhminlen == 0 || dhmin[dhminlen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN DH PARAMETERS-----", + "-----END DH PARAMETERS-----", + dhmin, NULL, 0, &dhminlen ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + dhminlen = pem.buflen; + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + goto exit; + + p = ( ret == 0 ) ? pem.buf : (unsigned char *) dhmin; +#else + p = (unsigned char *) dhmin; +#endif /* MBEDTLS_PEM_PARSE_C */ + end = p + dhminlen; + + /* + * DHParams ::= SEQUENCE { + * prime INTEGER, -- P + * generator INTEGER, -- g + * privateValueLength INTEGER OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; + goto exit; + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->P ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &dhm->G ) ) != 0 ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; + goto exit; + } + + if( p != end ) + { + /* This might be the optional privateValueLength. + * If so, we can cleanly discard it */ + mbedtls_mpi rec; + mbedtls_mpi_init( &rec ); + ret = mbedtls_asn1_get_mpi( &p, end, &rec ); + mbedtls_mpi_free( &rec ); + if ( ret != 0 ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + ret; + goto exit; + } + if ( p != end ) + { + ret = MBEDTLS_ERR_DHM_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + goto exit; + } + } + + ret = 0; + + dhm->len = mbedtls_mpi_size( &dhm->P ); + +exit: +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_free( &pem ); +#endif + if( ret != 0 ) + mbedtls_dhm_free( dhm ); + + return( ret ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load all data from a file into a given buffer. + * + * The file is expected to contain either PEM or DER encoded data. + * A terminating null byte is always appended. It is included in the announced + * length only if the data looks like it is PEM encoded. + */ +static int load_file( const char *path, unsigned char **buf, size_t *n ) +{ + FILE *f; + long size; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + if( ( size = ftell( f ) ) == -1 ) + { + fclose( f ); + return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); + } + fseek( f, 0, SEEK_SET ); + + *n = (size_t) size; + + if( *n + 1 == 0 || + ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) + { + fclose( f ); + return( MBEDTLS_ERR_DHM_ALLOC_FAILED ); + } + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + mbedtls_free( *buf ); + return( MBEDTLS_ERR_DHM_FILE_IO_ERROR ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) + ++*n; + + return( 0 ); +} + +/* + * Load and parse DHM parameters + */ +int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_dhm_parse_dhm( dhm, buf, n ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_ASN1_PARSE_C */ + +#if defined(MBEDTLS_SELF_TEST) + +static const char mbedtls_test_dhm_params[] = +"-----BEGIN DH PARAMETERS-----\r\n" +"MIGHAoGBAJ419DBEOgmQTzo5qXl5fQcN9TN455wkOL7052HzxxRVMyhYmwQcgJvh\r\n" +"1sa18fyfR9OiVEMYglOpkqVoGLN7qd5aQNNi5W7/C+VBdHTBJcGZJyyP5B3qcz32\r\n" +"9mLJKudlVudV0Qxk5qUJaPZ/xupz0NyoVpviuiBOI1gNi8ovSXWzAgEC\r\n" +"-----END DH PARAMETERS-----\r\n"; + +static const size_t mbedtls_test_dhm_params_len = sizeof( mbedtls_test_dhm_params ); + +/* + * Checkup routine + */ +int mbedtls_dhm_self_test( int verbose ) +{ + int ret; + mbedtls_dhm_context dhm; + + mbedtls_dhm_init( &dhm ); + + if( verbose != 0 ) + mbedtls_printf( " DHM parameter load: " ); + + if( ( ret = mbedtls_dhm_parse_dhm( &dhm, + (const unsigned char *) mbedtls_test_dhm_params, + mbedtls_test_dhm_params_len ) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n" ); + +exit: + mbedtls_dhm_free( &dhm ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_DHM_C */ diff --git a/c++/src/connect/mbedtls/ecdh.c b/c++/src/connect/mbedtls/ecdh.c new file mode 100644 index 00000000..c0a81473 --- /dev/null +++ b/c++/src/connect/mbedtls/ecdh.c @@ -0,0 +1,264 @@ +/* + * Elliptic curve Diffie-Hellman + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + * RFC 4492 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECDH_C) + +#include "mbedtls/ecdh.h" + +#include + +/* + * Generate public key: simple wrapper around mbedtls_ecp_gen_keypair + */ +int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + return mbedtls_ecp_gen_keypair( grp, d, Q, f_rng, p_rng ); +} + +/* + * Compute shared secret (SEC1 3.3.1) + */ +int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point P; + + mbedtls_ecp_point_init( &P ); + + /* + * Make sure Q is a valid pubkey before using it + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, &P, d, Q, f_rng, p_rng ) ); + + if( mbedtls_ecp_is_zero( &P ) ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( z, &P.X ) ); + +cleanup: + mbedtls_ecp_point_free( &P ); + + return( ret ); +} + +/* + * Initialize context + */ +void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ecdh_context ) ); +} + +/* + * Free context + */ +void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_ecp_group_free( &ctx->grp ); + mbedtls_ecp_point_free( &ctx->Q ); + mbedtls_ecp_point_free( &ctx->Qp ); + mbedtls_ecp_point_free( &ctx->Vi ); + mbedtls_ecp_point_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->d ); + mbedtls_mpi_free( &ctx->z ); + mbedtls_mpi_free( &ctx->_d ); +} + +/* + * Setup and write the ServerKeyExhange parameters (RFC 4492) + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ +int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t grp_len, pt_len; + + if( ctx == NULL || ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) + != 0 ) + return( ret ); + + if( ( ret = mbedtls_ecp_tls_write_group( &ctx->grp, &grp_len, buf, blen ) ) + != 0 ) + return( ret ); + + buf += grp_len; + blen -= grp_len; + + if( ( ret = mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, + &pt_len, buf, blen ) ) != 0 ) + return( ret ); + + *olen = grp_len + pt_len; + return( 0 ); +} + +/* + * Read the ServerKeyExhange parameters (RFC 4492) + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ +int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, + const unsigned char **buf, const unsigned char *end ) +{ + int ret; + + if( ( ret = mbedtls_ecp_tls_read_group( &ctx->grp, buf, end - *buf ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, buf, end - *buf ) ) + != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Get parameters from a keypair + */ +int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ) +{ + int ret; + + if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 ) + return( ret ); + + /* If it's not our key, just import the public part as Qp */ + if( side == MBEDTLS_ECDH_THEIRS ) + return( mbedtls_ecp_copy( &ctx->Qp, &key->Q ) ); + + /* Our key: import public (as Q) and private parts */ + if( side != MBEDTLS_ECDH_OURS ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 || + ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Setup and export the client public value + */ +int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + + if( ctx == NULL || ctx->grp.pbits == 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecdh_gen_public( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ) + != 0 ) + return( ret ); + + return mbedtls_ecp_tls_write_point( &ctx->grp, &ctx->Q, ctx->point_format, + olen, buf, blen ); +} + +/* + * Parse and import the client's public value + */ +int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ) +{ + int ret; + const unsigned char *p = buf; + + if( ctx == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_tls_read_point( &ctx->grp, &ctx->Qp, &p, blen ) ) != 0 ) + return( ret ); + + if( (size_t)( p - buf ) != blen ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + return( 0 ); +} + +/* + * Derive and export the shared secret + */ +int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + + if( ctx == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecdh_compute_shared( &ctx->grp, &ctx->z, &ctx->Qp, &ctx->d, + f_rng, p_rng ) ) != 0 ) + { + return( ret ); + } + + if( mbedtls_mpi_size( &ctx->z ) > blen ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + *olen = ctx->grp.pbits / 8 + ( ( ctx->grp.pbits % 8 ) != 0 ); + return mbedtls_mpi_write_binary( &ctx->z, buf, *olen ); +} + +#endif /* MBEDTLS_ECDH_C */ diff --git a/c++/src/connect/mbedtls/ecdsa.c b/c++/src/connect/mbedtls/ecdsa.c new file mode 100644 index 00000000..4156f3c3 --- /dev/null +++ b/c++/src/connect/mbedtls/ecdsa.c @@ -0,0 +1,448 @@ +/* + * Elliptic curve DSA + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECDSA_C) + +#include "mbedtls/ecdsa.h" +#include "mbedtls/asn1write.h" + +#include + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +#include "mbedtls/hmac_drbg.h" +#endif + +/* + * Derive a suitable integer for group grp from a buffer of length len + * SEC1 4.1.3 step 5 aka SEC1 4.1.4 step 3 + */ +static int derive_mpi( const mbedtls_ecp_group *grp, mbedtls_mpi *x, + const unsigned char *buf, size_t blen ) +{ + int ret; + size_t n_size = ( grp->nbits + 7 ) / 8; + size_t use_size = blen > n_size ? n_size : blen; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( x, buf, use_size ) ); + if( use_size * 8 > grp->nbits ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( x, use_size * 8 - grp->nbits ) ); + + /* While at it, reduce modulo N */ + if( mbedtls_mpi_cmp_mpi( x, &grp->N ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( x, x, &grp->N ) ); + +cleanup: + return( ret ); +} + +/* + * Compute ECDSA signature of a hashed message (SEC1 4.1.3) + * Obviously, compared to SEC1 4.1.3, we skip step 4 (hash message) + */ +int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret, key_tries, sign_tries, blind_tries; + mbedtls_ecp_point R; + mbedtls_mpi k, e, t; + + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if( grp->N.p == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + mbedtls_ecp_point_init( &R ); + mbedtls_mpi_init( &k ); mbedtls_mpi_init( &e ); mbedtls_mpi_init( &t ); + + sign_tries = 0; + do + { + /* + * Steps 1-3: generate a suitable ephemeral keypair + * and set r = xR mod n + */ + key_tries = 0; + do + { + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair( grp, &k, &R, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( r, &R.X, &grp->N ) ); + + if( key_tries++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + } + while( mbedtls_mpi_cmp_int( r, 0 ) == 0 ); + + /* + * Step 5: derive MPI from hashed message + */ + MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); + + /* + * Generate a random value to blind inv_mod in next step, + * avoiding a potential timing leak. + */ + blind_tries = 0; + do + { + size_t n_size = ( grp->nbits + 7 ) / 8; + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &t, n_size, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &t, 8 * n_size - grp->nbits ) ); + + /* See mbedtls_ecp_gen_keypair() */ + if( ++blind_tries > 30 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &t, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( &t, &grp->N ) >= 0 ); + + /* + * Step 6: compute s = (e + r * d) / k = t (e + rd) / (kt) mod n + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, r, d ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &e, &e, s ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &e, &e, &t ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &k, &k, &t ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( s, &k, &grp->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( s, s, &e ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( s, s, &grp->N ) ); + + if( sign_tries++ > 10 ) + { + ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; + goto cleanup; + } + } + while( mbedtls_mpi_cmp_int( s, 0 ) == 0 ); + +cleanup: + mbedtls_ecp_point_free( &R ); + mbedtls_mpi_free( &k ); mbedtls_mpi_free( &e ); mbedtls_mpi_free( &t ); + + return( ret ); +} + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/* + * Deterministic signature wrapper + */ +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ) +{ + int ret; + mbedtls_hmac_drbg_context rng_ctx; + unsigned char data[2 * MBEDTLS_ECP_MAX_BYTES]; + size_t grp_len = ( grp->nbits + 7 ) / 8; + const mbedtls_md_info_t *md_info; + mbedtls_mpi h; + + if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &h ); + mbedtls_hmac_drbg_init( &rng_ctx ); + + /* Use private key and message hash (reduced) to initialize HMAC_DRBG */ + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( d, data, grp_len ) ); + MBEDTLS_MPI_CHK( derive_mpi( grp, &h, buf, blen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, data + grp_len, grp_len ) ); + mbedtls_hmac_drbg_seed_buf( &rng_ctx, md_info, data, 2 * grp_len ); + + ret = mbedtls_ecdsa_sign( grp, r, s, d, buf, blen, + mbedtls_hmac_drbg_random, &rng_ctx ); + +cleanup: + mbedtls_hmac_drbg_free( &rng_ctx ); + mbedtls_mpi_free( &h ); + + return( ret ); +} +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/* + * Verify ECDSA signature of hashed message (SEC1 4.1.4) + * Obviously, compared to SEC1 4.1.3, we skip step 2 (hash message) + */ +int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s) +{ + int ret; + mbedtls_mpi e, s_inv, u1, u2; + mbedtls_ecp_point R; + + mbedtls_ecp_point_init( &R ); + mbedtls_mpi_init( &e ); mbedtls_mpi_init( &s_inv ); mbedtls_mpi_init( &u1 ); mbedtls_mpi_init( &u2 ); + + /* Fail cleanly on curves such as Curve25519 that can't be used for ECDSA */ + if( grp->N.p == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Step 1: make sure r and s are in range 1..n-1 + */ + if( mbedtls_mpi_cmp_int( r, 1 ) < 0 || mbedtls_mpi_cmp_mpi( r, &grp->N ) >= 0 || + mbedtls_mpi_cmp_int( s, 1 ) < 0 || mbedtls_mpi_cmp_mpi( s, &grp->N ) >= 0 ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + /* + * Additional precaution: make sure Q is valid + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_check_pubkey( grp, Q ) ); + + /* + * Step 3: derive MPI from hashed message + */ + MBEDTLS_MPI_CHK( derive_mpi( grp, &e, buf, blen ) ); + + /* + * Step 4: u1 = e / s mod n, u2 = r / s mod n + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &s_inv, s, &grp->N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u1, &e, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u1, &u1, &grp->N ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u2, r, &s_inv ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &u2, &u2, &grp->N ) ); + + /* + * Step 5: R = u1 G + u2 Q + * + * Since we're not using any secret data, no need to pass a RNG to + * mbedtls_ecp_mul() for countermesures. + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, &R, &u1, &grp->G, &u2, Q ) ); + + if( mbedtls_ecp_is_zero( &R ) ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + + /* + * Step 6: convert xR to an integer (no-op) + * Step 7: reduce xR mod n (gives v) + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &R.X, &R.X, &grp->N ) ); + + /* + * Step 8: check if v (that is, R.X) is equal to r + */ + if( mbedtls_mpi_cmp_mpi( &R.X, r ) != 0 ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free( &R ); + mbedtls_mpi_free( &e ); mbedtls_mpi_free( &s_inv ); mbedtls_mpi_free( &u1 ); mbedtls_mpi_free( &u2 ); + + return( ret ); +} + +/* + * Convert a signature (given by context) to ASN.1 + */ +static int ecdsa_signature_to_asn1( const mbedtls_mpi *r, const mbedtls_mpi *s, + unsigned char *sig, size_t *slen ) +{ + int ret; + unsigned char buf[MBEDTLS_ECDSA_MAX_LEN]; + unsigned char *p = buf + sizeof( buf ); + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, s ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &p, buf, r ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &p, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &p, buf, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ); + + memcpy( sig, p, len ); + *slen = len; + + return( 0 ); +} + +/* + * Compute and write signature + */ +int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi r, s; + + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &s ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + (void) f_rng; + (void) p_rng; + + MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign_det( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, md_alg ) ); +#else + (void) md_alg; + + MBEDTLS_MPI_CHK( mbedtls_ecdsa_sign( &ctx->grp, &r, &s, &ctx->d, + hash, hlen, f_rng, p_rng ) ); +#endif + + MBEDTLS_MPI_CHK( ecdsa_signature_to_asn1( &r, &s, sig, slen ) ); + +cleanup: + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &s ); + + return( ret ); +} + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) && \ + defined(MBEDTLS_ECDSA_DETERMINISTIC) +int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + mbedtls_md_type_t md_alg ) +{ + return( mbedtls_ecdsa_write_signature( ctx, md_alg, hash, hlen, sig, slen, + NULL, NULL ) ); +} +#endif + +/* + * Read and check signature + */ +int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen ) +{ + int ret; + unsigned char *p = (unsigned char *) sig; + const unsigned char *end = sig + slen; + size_t len; + mbedtls_mpi r, s; + + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &s ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if( p + len != end ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + goto cleanup; + } + + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &r ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &s ) ) != 0 ) + { + ret += MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + if( ( ret = mbedtls_ecdsa_verify( &ctx->grp, hash, hlen, + &ctx->Q, &r, &s ) ) != 0 ) + goto cleanup; + + if( p != end ) + ret = MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH; + +cleanup: + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &s ); + + return( ret ); +} + +/* + * Generate key pair + */ +int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + return( mbedtls_ecp_group_load( &ctx->grp, gid ) || + mbedtls_ecp_gen_keypair( &ctx->grp, &ctx->d, &ctx->Q, f_rng, p_rng ) ); +} + +/* + * Set context from an mbedtls_ecp_keypair + */ +int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ) +{ + int ret; + + if( ( ret = mbedtls_ecp_group_copy( &ctx->grp, &key->grp ) ) != 0 || + ( ret = mbedtls_mpi_copy( &ctx->d, &key->d ) ) != 0 || + ( ret = mbedtls_ecp_copy( &ctx->Q, &key->Q ) ) != 0 ) + { + mbedtls_ecdsa_free( ctx ); + } + + return( ret ); +} + +/* + * Initialize context + */ +void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ) +{ + mbedtls_ecp_keypair_init( ctx ); +} + +/* + * Free context + */ +void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ) +{ + mbedtls_ecp_keypair_free( ctx ); +} + +#endif /* MBEDTLS_ECDSA_C */ diff --git a/c++/src/connect/mbedtls/ecjpake.c b/c++/src/connect/mbedtls/ecjpake.c new file mode 100644 index 00000000..1fa1c2d8 --- /dev/null +++ b/c++/src/connect/mbedtls/ecjpake.c @@ -0,0 +1,1103 @@ +/* + * Elliptic curve J-PAKE + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References in the code are to the Thread v1.0 Specification, + * available to members of the Thread Group http://threadgroup.org/ + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECJPAKE_C) + +#include "mbedtls/ecjpake.h" + +#include + +/* + * Convert a mbedtls_ecjpake_role to identifier string + */ +static const char * const ecjpake_id[] = { + "client", + "server" +}; + +#define ID_MINE ( ecjpake_id[ ctx->role ] ) +#define ID_PEER ( ecjpake_id[ 1 - ctx->role ] ) + +/* + * Initialize context + */ +void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx ) +{ + if( ctx == NULL ) + return; + + ctx->md_info = NULL; + mbedtls_ecp_group_init( &ctx->grp ); + ctx->point_format = MBEDTLS_ECP_PF_UNCOMPRESSED; + + mbedtls_ecp_point_init( &ctx->Xm1 ); + mbedtls_ecp_point_init( &ctx->Xm2 ); + mbedtls_ecp_point_init( &ctx->Xp1 ); + mbedtls_ecp_point_init( &ctx->Xp2 ); + mbedtls_ecp_point_init( &ctx->Xp ); + + mbedtls_mpi_init( &ctx->xm1 ); + mbedtls_mpi_init( &ctx->xm2 ); + mbedtls_mpi_init( &ctx->s ); +} + +/* + * Free context + */ +void mbedtls_ecjpake_free( mbedtls_ecjpake_context *ctx ) +{ + if( ctx == NULL ) + return; + + ctx->md_info = NULL; + mbedtls_ecp_group_free( &ctx->grp ); + + mbedtls_ecp_point_free( &ctx->Xm1 ); + mbedtls_ecp_point_free( &ctx->Xm2 ); + mbedtls_ecp_point_free( &ctx->Xp1 ); + mbedtls_ecp_point_free( &ctx->Xp2 ); + mbedtls_ecp_point_free( &ctx->Xp ); + + mbedtls_mpi_free( &ctx->xm1 ); + mbedtls_mpi_free( &ctx->xm2 ); + mbedtls_mpi_free( &ctx->s ); +} + +/* + * Setup context + */ +int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx, + mbedtls_ecjpake_role role, + mbedtls_md_type_t hash, + mbedtls_ecp_group_id curve, + const unsigned char *secret, + size_t len ) +{ + int ret; + + ctx->role = role; + + if( ( ctx->md_info = mbedtls_md_info_from_type( hash ) ) == NULL ) + return( MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ctx->grp, curve ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->s, secret, len ) ); + +cleanup: + if( ret != 0 ) + mbedtls_ecjpake_free( ctx ); + + return( ret ); +} + +/* + * Check if context is ready for use + */ +int mbedtls_ecjpake_check( const mbedtls_ecjpake_context *ctx ) +{ + if( ctx->md_info == NULL || + ctx->grp.id == MBEDTLS_ECP_DP_NONE || + ctx->s.p == NULL ) + { + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + return( 0 ); +} + +/* + * Write a point plus its length to a buffer + */ +static int ecjpake_write_len_point( unsigned char **p, + const unsigned char *end, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *P ) +{ + int ret; + size_t len; + + /* Need at least 4 for length plus 1 for point */ + if( end < *p || end - *p < 5 ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + ret = mbedtls_ecp_point_write_binary( grp, P, pf, + &len, *p + 4, end - ( *p + 4 ) ); + if( ret != 0 ) + return( ret ); + + (*p)[0] = (unsigned char)( ( len >> 24 ) & 0xFF ); + (*p)[1] = (unsigned char)( ( len >> 16 ) & 0xFF ); + (*p)[2] = (unsigned char)( ( len >> 8 ) & 0xFF ); + (*p)[3] = (unsigned char)( ( len ) & 0xFF ); + + *p += 4 + len; + + return( 0 ); +} + +/* + * Size of the temporary buffer for ecjpake_hash: + * 3 EC points plus their length, plus ID and its length (4 + 6 bytes) + */ +#define ECJPAKE_HASH_BUF_LEN ( 3 * ( 4 + MBEDTLS_ECP_MAX_PT_LEN ) + 4 + 6 ) + +/* + * Compute hash for ZKP (7.4.2.2.2.1) + */ +static int ecjpake_hash( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_ecp_point *V, + const mbedtls_ecp_point *X, + const char *id, + mbedtls_mpi *h ) +{ + int ret; + unsigned char buf[ECJPAKE_HASH_BUF_LEN]; + unsigned char *p = buf; + const unsigned char *end = buf + sizeof( buf ); + const size_t id_len = strlen( id ); + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + + /* Write things to temporary buffer */ + MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, G ) ); + MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, V ) ); + MBEDTLS_MPI_CHK( ecjpake_write_len_point( &p, end, grp, pf, X ) ); + + if( end - p < 4 ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + *p++ = (unsigned char)( ( id_len >> 24 ) & 0xFF ); + *p++ = (unsigned char)( ( id_len >> 16 ) & 0xFF ); + *p++ = (unsigned char)( ( id_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( id_len ) & 0xFF ); + + if( end < p || (size_t)( end - p ) < id_len ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + memcpy( p, id, id_len ); + p += id_len; + + /* Compute hash */ + mbedtls_md( md_info, buf, p - buf, hash ); + + /* Turn it into an integer mod n */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( h, hash, + mbedtls_md_get_size( md_info ) ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( h, h, &grp->N ) ); + +cleanup: + return( ret ); +} + +/* + * Parse a ECShnorrZKP (7.4.2.2.2) and verify it (7.4.2.3.3) + */ +static int ecjpake_zkp_read( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_ecp_point *X, + const char *id, + const unsigned char **p, + const unsigned char *end ) +{ + int ret; + mbedtls_ecp_point V, VV; + mbedtls_mpi r, h; + size_t r_len; + + mbedtls_ecp_point_init( &V ); + mbedtls_ecp_point_init( &VV ); + mbedtls_mpi_init( &r ); + mbedtls_mpi_init( &h ); + + /* + * struct { + * ECPoint V; + * opaque r<1..2^8-1>; + * } ECSchnorrZKP; + */ + if( end < *p ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, &V, p, end - *p ) ); + + if( end < *p || (size_t)( end - *p ) < 1 ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + r_len = *(*p)++; + + if( end < *p || (size_t)( end - *p ) < r_len ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &r, *p, r_len ) ); + *p += r_len; + + /* + * Verification + */ + MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, pf, G, &V, X, id, &h ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( (mbedtls_ecp_group *) grp, + &VV, &h, X, &r, G ) ); + + if( mbedtls_ecp_point_cmp( &VV, &V ) != 0 ) + { + ret = MBEDTLS_ERR_ECP_VERIFY_FAILED; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free( &V ); + mbedtls_ecp_point_free( &VV ); + mbedtls_mpi_free( &r ); + mbedtls_mpi_free( &h ); + + return( ret ); +} + +/* + * Generate ZKP (7.4.2.3.2) and write it as ECSchnorrZKP (7.4.2.2.2) + */ +static int ecjpake_zkp_write( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + const mbedtls_mpi *x, + const mbedtls_ecp_point *X, + const char *id, + unsigned char **p, + const unsigned char *end, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point V; + mbedtls_mpi v; + mbedtls_mpi h; /* later recycled to hold r */ + size_t len; + + if( end < *p ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + mbedtls_ecp_point_init( &V ); + mbedtls_mpi_init( &v ); + mbedtls_mpi_init( &h ); + + /* Compute signature */ + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp, + G, &v, &V, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( ecjpake_hash( md_info, grp, pf, G, &V, X, id, &h ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &h, &h, x ) ); /* x*h */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &h, &v, &h ) ); /* v - x*h */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &h, &h, &grp->N ) ); /* r */ + + /* Write it out */ + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, &V, + pf, &len, *p, end - *p ) ); + *p += len; + + len = mbedtls_mpi_size( &h ); /* actually r */ + if( end < *p || (size_t)( end - *p ) < 1 + len || len > 255 ) + { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + + *(*p)++ = (unsigned char)( len & 0xFF ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &h, *p, len ) ); /* r */ + *p += len; + +cleanup: + mbedtls_ecp_point_free( &V ); + mbedtls_mpi_free( &v ); + mbedtls_mpi_free( &h ); + + return( ret ); +} + +/* + * Parse a ECJPAKEKeyKP (7.4.2.2.1) and check proof + * Output: verified public key X + */ +static int ecjpake_kkp_read( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_ecp_point *X, + const char *id, + const unsigned char **p, + const unsigned char *end ) +{ + int ret; + + if( end < *p ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * struct { + * ECPoint X; + * ECSchnorrZKP zkp; + * } ECJPAKEKeyKP; + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_point( grp, X, p, end - *p ) ); + if( mbedtls_ecp_is_zero( X ) ) + { + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + goto cleanup; + } + + MBEDTLS_MPI_CHK( ecjpake_zkp_read( md_info, grp, pf, G, X, id, p, end ) ); + +cleanup: + return( ret ); +} + +/* + * Generate an ECJPAKEKeyKP + * Output: the serialized structure, plus private/public key pair + */ +static int ecjpake_kkp_write( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_mpi *x, + mbedtls_ecp_point *X, + const char *id, + unsigned char **p, + const unsigned char *end, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t len; + + if( end < *p ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + /* Generate key (7.4.2.3.1) and write it out */ + MBEDTLS_MPI_CHK( mbedtls_ecp_gen_keypair_base( (mbedtls_ecp_group *) grp, G, x, X, + f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( grp, X, + pf, &len, *p, end - *p ) ); + *p += len; + + /* Generate and write proof */ + MBEDTLS_MPI_CHK( ecjpake_zkp_write( md_info, grp, pf, G, x, X, id, + p, end, f_rng, p_rng ) ); + +cleanup: + return( ret ); +} + +/* + * Read a ECJPAKEKeyKPPairList (7.4.2.3) and check proofs + * Ouputs: verified peer public keys Xa, Xb + */ +static int ecjpake_kkpp_read( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_ecp_point *Xa, + mbedtls_ecp_point *Xb, + const char *id, + const unsigned char *buf, + size_t len ) +{ + int ret; + const unsigned char *p = buf; + const unsigned char *end = buf + len; + + /* + * struct { + * ECJPAKEKeyKP ecjpake_key_kp_pair_list[2]; + * } ECJPAKEKeyKPPairList; + */ + MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, pf, G, Xa, id, &p, end ) ); + MBEDTLS_MPI_CHK( ecjpake_kkp_read( md_info, grp, pf, G, Xb, id, &p, end ) ); + + if( p != end ) + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + +cleanup: + return( ret ); +} + +/* + * Generate a ECJPAKEKeyKPPairList + * Outputs: the serialized structure, plus two private/public key pairs + */ +static int ecjpake_kkpp_write( const mbedtls_md_info_t *md_info, + const mbedtls_ecp_group *grp, + const int pf, + const mbedtls_ecp_point *G, + mbedtls_mpi *xm1, + mbedtls_ecp_point *Xa, + mbedtls_mpi *xm2, + mbedtls_ecp_point *Xb, + const char *id, + unsigned char *buf, + size_t len, + size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char *p = buf; + const unsigned char *end = buf + len; + + MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, pf, G, xm1, Xa, id, + &p, end, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( ecjpake_kkp_write( md_info, grp, pf, G, xm2, Xb, id, + &p, end, f_rng, p_rng ) ); + + *olen = p - buf; + +cleanup: + return( ret ); +} + +/* + * Read and process the first round message + */ +int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ) +{ + return( ecjpake_kkpp_read( ctx->md_info, &ctx->grp, ctx->point_format, + &ctx->grp.G, + &ctx->Xp1, &ctx->Xp2, ID_PEER, + buf, len ) ); +} + +/* + * Generate and write the first round message + */ +int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + return( ecjpake_kkpp_write( ctx->md_info, &ctx->grp, ctx->point_format, + &ctx->grp.G, + &ctx->xm1, &ctx->Xm1, &ctx->xm2, &ctx->Xm2, + ID_MINE, buf, len, olen, f_rng, p_rng ) ); +} + +/* + * Compute the sum of three points R = A + B + C + */ +static int ecjpake_ecp_add3( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *A, + const mbedtls_ecp_point *B, + const mbedtls_ecp_point *C ) +{ + int ret; + mbedtls_mpi one; + + mbedtls_mpi_init( &one ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, A, &one, B ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( grp, R, &one, R, &one, C ) ); + +cleanup: + mbedtls_mpi_free( &one ); + + return( ret ); +} + +/* + * Read and process second round message (C: 7.4.2.5, S: 7.4.2.6) + */ +int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ) +{ + int ret; + const unsigned char *p = buf; + const unsigned char *end = buf + len; + mbedtls_ecp_group grp; + mbedtls_ecp_point G; /* C: GB, S: GA */ + + mbedtls_ecp_group_init( &grp ); + mbedtls_ecp_point_init( &G ); + + /* + * Server: GA = X3 + X4 + X1 (7.4.2.6.1) + * Client: GB = X1 + X2 + X3 (7.4.2.5.1) + * Unified: G = Xm1 + Xm2 + Xp1 + * We need that before parsing in order to check Xp as we read it + */ + MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G, + &ctx->Xm1, &ctx->Xm2, &ctx->Xp1 ) ); + + /* + * struct { + * ECParameters curve_params; // only client reading server msg + * ECJPAKEKeyKP ecjpake_key_kp; + * } Client/ServerECJPAKEParams; + */ + if( ctx->role == MBEDTLS_ECJPAKE_CLIENT ) + { + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_read_group( &grp, &p, len ) ); + if( grp.id != ctx->grp.id ) + { + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + goto cleanup; + } + } + + MBEDTLS_MPI_CHK( ecjpake_kkp_read( ctx->md_info, &ctx->grp, + ctx->point_format, + &G, &ctx->Xp, ID_PEER, &p, end ) ); + + if( p != end ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + +cleanup: + mbedtls_ecp_group_free( &grp ); + mbedtls_ecp_point_free( &G ); + + return( ret ); +} + +/* + * Compute R = +/- X * S mod N, taking care not to leak S + */ +static int ecjpake_mul_secret( mbedtls_mpi *R, int sign, + const mbedtls_mpi *X, + const mbedtls_mpi *S, + const mbedtls_mpi *N, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_mpi b; /* Blinding value, then s + N * blinding */ + + mbedtls_mpi_init( &b ); + + /* b = s + rnd-128-bit * N */ + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &b, 16, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &b, &b, N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &b, &b, S ) ); + + /* R = sign * X * b mod N */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( R, X, &b ) ); + R->s *= sign; + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( R, R, N ) ); + +cleanup: + mbedtls_mpi_free( &b ); + + return( ret ); +} + +/* + * Generate and write the second round message (S: 7.4.2.5, C: 7.4.2.6) + */ +int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point G; /* C: GA, S: GB */ + mbedtls_ecp_point Xm; /* C: Xc, S: Xs */ + mbedtls_mpi xm; /* C: xc, S: xs */ + unsigned char *p = buf; + const unsigned char *end = buf + len; + size_t ec_len; + + mbedtls_ecp_point_init( &G ); + mbedtls_ecp_point_init( &Xm ); + mbedtls_mpi_init( &xm ); + + /* + * First generate private/public key pair (S: 7.4.2.5.1, C: 7.4.2.6.1) + * + * Client: GA = X1 + X3 + X4 | xs = x2 * s | Xc = xc * GA + * Server: GB = X3 + X1 + X2 | xs = x4 * s | Xs = xs * GB + * Unified: G = Xm1 + Xp1 + Xp2 | xm = xm2 * s | Xm = xm * G + */ + MBEDTLS_MPI_CHK( ecjpake_ecp_add3( &ctx->grp, &G, + &ctx->Xp1, &ctx->Xp2, &ctx->Xm1 ) ); + MBEDTLS_MPI_CHK( ecjpake_mul_secret( &xm, 1, &ctx->xm2, &ctx->s, + &ctx->grp.N, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &Xm, &xm, &G, f_rng, p_rng ) ); + + /* + * Now write things out + * + * struct { + * ECParameters curve_params; // only server writing its message + * ECJPAKEKeyKP ecjpake_key_kp; + * } Client/ServerECJPAKEParams; + */ + if( ctx->role == MBEDTLS_ECJPAKE_SERVER ) + { + if( end < p ) + { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_group( &ctx->grp, &ec_len, + p, end - p ) ); + p += ec_len; + } + + if( end < p ) + { + ret = MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; + goto cleanup; + } + MBEDTLS_MPI_CHK( mbedtls_ecp_tls_write_point( &ctx->grp, &Xm, + ctx->point_format, &ec_len, p, end - p ) ); + p += ec_len; + + MBEDTLS_MPI_CHK( ecjpake_zkp_write( ctx->md_info, &ctx->grp, + ctx->point_format, + &G, &xm, &Xm, ID_MINE, + &p, end, f_rng, p_rng ) ); + + *olen = p - buf; + +cleanup: + mbedtls_ecp_point_free( &G ); + mbedtls_ecp_point_free( &Xm ); + mbedtls_mpi_free( &xm ); + + return( ret ); +} + +/* + * Derive PMS (7.4.2.7 / 7.4.2.8) + */ +int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point K; + mbedtls_mpi m_xm2_s, one; + unsigned char kx[MBEDTLS_ECP_MAX_BYTES]; + size_t x_bytes; + + *olen = mbedtls_md_get_size( ctx->md_info ); + if( len < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + mbedtls_ecp_point_init( &K ); + mbedtls_mpi_init( &m_xm2_s ); + mbedtls_mpi_init( &one ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &one, 1 ) ); + + /* + * Client: K = ( Xs - X4 * x2 * s ) * x2 + * Server: K = ( Xc - X2 * x4 * s ) * x4 + * Unified: K = ( Xp - Xp2 * xm2 * s ) * xm2 + */ + MBEDTLS_MPI_CHK( ecjpake_mul_secret( &m_xm2_s, -1, &ctx->xm2, &ctx->s, + &ctx->grp.N, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_muladd( &ctx->grp, &K, + &one, &ctx->Xp, + &m_xm2_s, &ctx->Xp2 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &K, &ctx->xm2, &K, + f_rng, p_rng ) ); + + /* PMS = SHA-256( K.X ) */ + x_bytes = ( ctx->grp.pbits + 7 ) / 8; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &K.X, kx, x_bytes ) ); + MBEDTLS_MPI_CHK( mbedtls_md( ctx->md_info, kx, x_bytes, buf ) ); + +cleanup: + mbedtls_ecp_point_free( &K ); + mbedtls_mpi_free( &m_xm2_s ); + mbedtls_mpi_free( &one ); + + return( ret ); +} + +#undef ID_MINE +#undef ID_PEER + + +#if defined(MBEDTLS_SELF_TEST) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +#if !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + !defined(MBEDTLS_SHA256_C) +int mbedtls_ecjpake_self_test( int verbose ) +{ + (void) verbose; + return( 0 ); +} +#else + +static const unsigned char ecjpake_test_password[] = { + 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x6a, 0x70, 0x61, 0x6b, 0x65, 0x74, + 0x65, 0x73, 0x74 +}; + +static const unsigned char ecjpake_test_x1[] = { + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x21 +}; + +static const unsigned char ecjpake_test_x2[] = { + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81 +}; + +static const unsigned char ecjpake_test_x3[] = { + 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, + 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, + 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x81 +}; + +static const unsigned char ecjpake_test_x4[] = { + 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, + 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, + 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe1 +}; + +static const unsigned char ecjpake_test_cli_one[] = { + 0x41, 0x04, 0xac, 0xcf, 0x01, 0x06, 0xef, 0x85, 0x8f, 0xa2, 0xd9, 0x19, + 0x33, 0x13, 0x46, 0x80, 0x5a, 0x78, 0xb5, 0x8b, 0xba, 0xd0, 0xb8, 0x44, + 0xe5, 0xc7, 0x89, 0x28, 0x79, 0x14, 0x61, 0x87, 0xdd, 0x26, 0x66, 0xad, + 0xa7, 0x81, 0xbb, 0x7f, 0x11, 0x13, 0x72, 0x25, 0x1a, 0x89, 0x10, 0x62, + 0x1f, 0x63, 0x4d, 0xf1, 0x28, 0xac, 0x48, 0xe3, 0x81, 0xfd, 0x6e, 0xf9, + 0x06, 0x07, 0x31, 0xf6, 0x94, 0xa4, 0x41, 0x04, 0x1d, 0xd0, 0xbd, 0x5d, + 0x45, 0x66, 0xc9, 0xbe, 0xd9, 0xce, 0x7d, 0xe7, 0x01, 0xb5, 0xe8, 0x2e, + 0x08, 0xe8, 0x4b, 0x73, 0x04, 0x66, 0x01, 0x8a, 0xb9, 0x03, 0xc7, 0x9e, + 0xb9, 0x82, 0x17, 0x22, 0x36, 0xc0, 0xc1, 0x72, 0x8a, 0xe4, 0xbf, 0x73, + 0x61, 0x0d, 0x34, 0xde, 0x44, 0x24, 0x6e, 0xf3, 0xd9, 0xc0, 0x5a, 0x22, + 0x36, 0xfb, 0x66, 0xa6, 0x58, 0x3d, 0x74, 0x49, 0x30, 0x8b, 0xab, 0xce, + 0x20, 0x72, 0xfe, 0x16, 0x66, 0x29, 0x92, 0xe9, 0x23, 0x5c, 0x25, 0x00, + 0x2f, 0x11, 0xb1, 0x50, 0x87, 0xb8, 0x27, 0x38, 0xe0, 0x3c, 0x94, 0x5b, + 0xf7, 0xa2, 0x99, 0x5d, 0xda, 0x1e, 0x98, 0x34, 0x58, 0x41, 0x04, 0x7e, + 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, 0xd7, 0x92, 0x62, + 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, 0x40, 0x9a, 0xc5, + 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, 0x79, 0x0a, 0xeb, + 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, 0xd1, 0xc3, 0x35, + 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, 0xe3, 0x2b, 0xb0, + 0x13, 0xbb, 0x2b, 0x41, 0x04, 0xa4, 0x95, 0x58, 0xd3, 0x2e, 0xd1, 0xeb, + 0xfc, 0x18, 0x16, 0xaf, 0x4f, 0xf0, 0x9b, 0x55, 0xfc, 0xb4, 0xca, 0x47, + 0xb2, 0xa0, 0x2d, 0x1e, 0x7c, 0xaf, 0x11, 0x79, 0xea, 0x3f, 0xe1, 0x39, + 0x5b, 0x22, 0xb8, 0x61, 0x96, 0x40, 0x16, 0xfa, 0xba, 0xf7, 0x2c, 0x97, + 0x56, 0x95, 0xd9, 0x3d, 0x4d, 0xf0, 0xe5, 0x19, 0x7f, 0xe9, 0xf0, 0x40, + 0x63, 0x4e, 0xd5, 0x97, 0x64, 0x93, 0x77, 0x87, 0xbe, 0x20, 0xbc, 0x4d, + 0xee, 0xbb, 0xf9, 0xb8, 0xd6, 0x0a, 0x33, 0x5f, 0x04, 0x6c, 0xa3, 0xaa, + 0x94, 0x1e, 0x45, 0x86, 0x4c, 0x7c, 0xad, 0xef, 0x9c, 0xf7, 0x5b, 0x3d, + 0x8b, 0x01, 0x0e, 0x44, 0x3e, 0xf0 +}; + +static const unsigned char ecjpake_test_srv_one[] = { + 0x41, 0x04, 0x7e, 0xa6, 0xe3, 0xa4, 0x48, 0x70, 0x37, 0xa9, 0xe0, 0xdb, + 0xd7, 0x92, 0x62, 0xb2, 0xcc, 0x27, 0x3e, 0x77, 0x99, 0x30, 0xfc, 0x18, + 0x40, 0x9a, 0xc5, 0x36, 0x1c, 0x5f, 0xe6, 0x69, 0xd7, 0x02, 0xe1, 0x47, + 0x79, 0x0a, 0xeb, 0x4c, 0xe7, 0xfd, 0x65, 0x75, 0xab, 0x0f, 0x6c, 0x7f, + 0xd1, 0xc3, 0x35, 0x93, 0x9a, 0xa8, 0x63, 0xba, 0x37, 0xec, 0x91, 0xb7, + 0xe3, 0x2b, 0xb0, 0x13, 0xbb, 0x2b, 0x41, 0x04, 0x09, 0xf8, 0x5b, 0x3d, + 0x20, 0xeb, 0xd7, 0x88, 0x5c, 0xe4, 0x64, 0xc0, 0x8d, 0x05, 0x6d, 0x64, + 0x28, 0xfe, 0x4d, 0xd9, 0x28, 0x7a, 0xa3, 0x65, 0xf1, 0x31, 0xf4, 0x36, + 0x0f, 0xf3, 0x86, 0xd8, 0x46, 0x89, 0x8b, 0xc4, 0xb4, 0x15, 0x83, 0xc2, + 0xa5, 0x19, 0x7f, 0x65, 0xd7, 0x87, 0x42, 0x74, 0x6c, 0x12, 0xa5, 0xec, + 0x0a, 0x4f, 0xfe, 0x2f, 0x27, 0x0a, 0x75, 0x0a, 0x1d, 0x8f, 0xb5, 0x16, + 0x20, 0x93, 0x4d, 0x74, 0xeb, 0x43, 0xe5, 0x4d, 0xf4, 0x24, 0xfd, 0x96, + 0x30, 0x6c, 0x01, 0x17, 0xbf, 0x13, 0x1a, 0xfa, 0xbf, 0x90, 0xa9, 0xd3, + 0x3d, 0x11, 0x98, 0xd9, 0x05, 0x19, 0x37, 0x35, 0x14, 0x41, 0x04, 0x19, + 0x0a, 0x07, 0x70, 0x0f, 0xfa, 0x4b, 0xe6, 0xae, 0x1d, 0x79, 0xee, 0x0f, + 0x06, 0xae, 0xb5, 0x44, 0xcd, 0x5a, 0xdd, 0xaa, 0xbe, 0xdf, 0x70, 0xf8, + 0x62, 0x33, 0x21, 0x33, 0x2c, 0x54, 0xf3, 0x55, 0xf0, 0xfb, 0xfe, 0xc7, + 0x83, 0xed, 0x35, 0x9e, 0x5d, 0x0b, 0xf7, 0x37, 0x7a, 0x0f, 0xc4, 0xea, + 0x7a, 0xce, 0x47, 0x3c, 0x9c, 0x11, 0x2b, 0x41, 0xcc, 0xd4, 0x1a, 0xc5, + 0x6a, 0x56, 0x12, 0x41, 0x04, 0x36, 0x0a, 0x1c, 0xea, 0x33, 0xfc, 0xe6, + 0x41, 0x15, 0x64, 0x58, 0xe0, 0xa4, 0xea, 0xc2, 0x19, 0xe9, 0x68, 0x31, + 0xe6, 0xae, 0xbc, 0x88, 0xb3, 0xf3, 0x75, 0x2f, 0x93, 0xa0, 0x28, 0x1d, + 0x1b, 0xf1, 0xfb, 0x10, 0x60, 0x51, 0xdb, 0x96, 0x94, 0xa8, 0xd6, 0xe8, + 0x62, 0xa5, 0xef, 0x13, 0x24, 0xa3, 0xd9, 0xe2, 0x78, 0x94, 0xf1, 0xee, + 0x4f, 0x7c, 0x59, 0x19, 0x99, 0x65, 0xa8, 0xdd, 0x4a, 0x20, 0x91, 0x84, + 0x7d, 0x2d, 0x22, 0xdf, 0x3e, 0xe5, 0x5f, 0xaa, 0x2a, 0x3f, 0xb3, 0x3f, + 0xd2, 0xd1, 0xe0, 0x55, 0xa0, 0x7a, 0x7c, 0x61, 0xec, 0xfb, 0x8d, 0x80, + 0xec, 0x00, 0xc2, 0xc9, 0xeb, 0x12 +}; + +static const unsigned char ecjpake_test_srv_two[] = { + 0x03, 0x00, 0x17, 0x41, 0x04, 0x0f, 0xb2, 0x2b, 0x1d, 0x5d, 0x11, 0x23, + 0xe0, 0xef, 0x9f, 0xeb, 0x9d, 0x8a, 0x2e, 0x59, 0x0a, 0x1f, 0x4d, 0x7c, + 0xed, 0x2c, 0x2b, 0x06, 0x58, 0x6e, 0x8f, 0x2a, 0x16, 0xd4, 0xeb, 0x2f, + 0xda, 0x43, 0x28, 0xa2, 0x0b, 0x07, 0xd8, 0xfd, 0x66, 0x76, 0x54, 0xca, + 0x18, 0xc5, 0x4e, 0x32, 0xa3, 0x33, 0xa0, 0x84, 0x54, 0x51, 0xe9, 0x26, + 0xee, 0x88, 0x04, 0xfd, 0x7a, 0xf0, 0xaa, 0xa7, 0xa6, 0x41, 0x04, 0x55, + 0x16, 0xea, 0x3e, 0x54, 0xa0, 0xd5, 0xd8, 0xb2, 0xce, 0x78, 0x6b, 0x38, + 0xd3, 0x83, 0x37, 0x00, 0x29, 0xa5, 0xdb, 0xe4, 0x45, 0x9c, 0x9d, 0xd6, + 0x01, 0xb4, 0x08, 0xa2, 0x4a, 0xe6, 0x46, 0x5c, 0x8a, 0xc9, 0x05, 0xb9, + 0xeb, 0x03, 0xb5, 0xd3, 0x69, 0x1c, 0x13, 0x9e, 0xf8, 0x3f, 0x1c, 0xd4, + 0x20, 0x0f, 0x6c, 0x9c, 0xd4, 0xec, 0x39, 0x22, 0x18, 0xa5, 0x9e, 0xd2, + 0x43, 0xd3, 0xc8, 0x20, 0xff, 0x72, 0x4a, 0x9a, 0x70, 0xb8, 0x8c, 0xb8, + 0x6f, 0x20, 0xb4, 0x34, 0xc6, 0x86, 0x5a, 0xa1, 0xcd, 0x79, 0x06, 0xdd, + 0x7c, 0x9b, 0xce, 0x35, 0x25, 0xf5, 0x08, 0x27, 0x6f, 0x26, 0x83, 0x6c +}; + +static const unsigned char ecjpake_test_cli_two[] = { + 0x41, 0x04, 0x69, 0xd5, 0x4e, 0xe8, 0x5e, 0x90, 0xce, 0x3f, 0x12, 0x46, + 0x74, 0x2d, 0xe5, 0x07, 0xe9, 0x39, 0xe8, 0x1d, 0x1d, 0xc1, 0xc5, 0xcb, + 0x98, 0x8b, 0x58, 0xc3, 0x10, 0xc9, 0xfd, 0xd9, 0x52, 0x4d, 0x93, 0x72, + 0x0b, 0x45, 0x54, 0x1c, 0x83, 0xee, 0x88, 0x41, 0x19, 0x1d, 0xa7, 0xce, + 0xd8, 0x6e, 0x33, 0x12, 0xd4, 0x36, 0x23, 0xc1, 0xd6, 0x3e, 0x74, 0x98, + 0x9a, 0xba, 0x4a, 0xff, 0xd1, 0xee, 0x41, 0x04, 0x07, 0x7e, 0x8c, 0x31, + 0xe2, 0x0e, 0x6b, 0xed, 0xb7, 0x60, 0xc1, 0x35, 0x93, 0xe6, 0x9f, 0x15, + 0xbe, 0x85, 0xc2, 0x7d, 0x68, 0xcd, 0x09, 0xcc, 0xb8, 0xc4, 0x18, 0x36, + 0x08, 0x91, 0x7c, 0x5c, 0x3d, 0x40, 0x9f, 0xac, 0x39, 0xfe, 0xfe, 0xe8, + 0x2f, 0x72, 0x92, 0xd3, 0x6f, 0x0d, 0x23, 0xe0, 0x55, 0x91, 0x3f, 0x45, + 0xa5, 0x2b, 0x85, 0xdd, 0x8a, 0x20, 0x52, 0xe9, 0xe1, 0x29, 0xbb, 0x4d, + 0x20, 0x0f, 0x01, 0x1f, 0x19, 0x48, 0x35, 0x35, 0xa6, 0xe8, 0x9a, 0x58, + 0x0c, 0x9b, 0x00, 0x03, 0xba, 0xf2, 0x14, 0x62, 0xec, 0xe9, 0x1a, 0x82, + 0xcc, 0x38, 0xdb, 0xdc, 0xae, 0x60, 0xd9, 0xc5, 0x4c +}; + +static const unsigned char ecjpake_test_pms[] = { + 0xf3, 0xd4, 0x7f, 0x59, 0x98, 0x44, 0xdb, 0x92, 0xa5, 0x69, 0xbb, 0xe7, + 0x98, 0x1e, 0x39, 0xd9, 0x31, 0xfd, 0x74, 0x3b, 0xf2, 0x2e, 0x98, 0xf9, + 0xb4, 0x38, 0xf7, 0x19, 0xd3, 0xc4, 0xf3, 0x51 +}; + +/* Load my private keys and generate the correponding public keys */ +static int ecjpake_test_load( mbedtls_ecjpake_context *ctx, + const unsigned char *xm1, size_t len1, + const unsigned char *xm2, size_t len2 ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm1, xm1, len1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &ctx->xm2, xm2, len2 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm1, &ctx->xm1, + &ctx->grp.G, NULL, NULL ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &ctx->grp, &ctx->Xm2, &ctx->xm2, + &ctx->grp.G, NULL, NULL ) ); + +cleanup: + return( ret ); +} + +/* For tests we don't need a secure RNG; + * use the LGC from Numerical Recipes for simplicity */ +static int ecjpake_lgc( void *p, unsigned char *out, size_t len ) +{ + static uint32_t x = 42; + (void) p; + + while( len > 0 ) + { + size_t use_len = len > 4 ? 4 : len; + x = 1664525 * x + 1013904223; + memcpy( out, &x, use_len ); + out += use_len; + len -= use_len; + } + + return( 0 ); +} + +#define TEST_ASSERT( x ) \ + do { \ + if( x ) \ + ret = 0; \ + else \ + { \ + ret = 1; \ + goto cleanup; \ + } \ + } while( 0 ) + +/* + * Checkup routine + */ +int mbedtls_ecjpake_self_test( int verbose ) +{ + int ret; + mbedtls_ecjpake_context cli; + mbedtls_ecjpake_context srv; + unsigned char buf[512], pms[32]; + size_t len, pmslen; + + mbedtls_ecjpake_init( &cli ); + mbedtls_ecjpake_init( &srv ); + + if( verbose != 0 ) + mbedtls_printf( " ECJPAKE test #0 (setup): " ); + + TEST_ASSERT( mbedtls_ecjpake_setup( &cli, MBEDTLS_ECJPAKE_CLIENT, + MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1, + ecjpake_test_password, + sizeof( ecjpake_test_password ) ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_setup( &srv, MBEDTLS_ECJPAKE_SERVER, + MBEDTLS_MD_SHA256, MBEDTLS_ECP_DP_SECP256R1, + ecjpake_test_password, + sizeof( ecjpake_test_password ) ) == 0 ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " ECJPAKE test #1 (random handshake): " ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_one( &cli, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_one( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_two( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli, + pms, sizeof( pms ), &pmslen, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_write_round_two( &cli, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv, buf, len ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( len == pmslen ); + TEST_ASSERT( memcmp( buf, pms, len ) == 0 ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " ECJPAKE test #2 (reference handshake): " ); + + /* Simulate generation of round one */ + MBEDTLS_MPI_CHK( ecjpake_test_load( &cli, + ecjpake_test_x1, sizeof( ecjpake_test_x1 ), + ecjpake_test_x2, sizeof( ecjpake_test_x2 ) ) ); + + MBEDTLS_MPI_CHK( ecjpake_test_load( &srv, + ecjpake_test_x3, sizeof( ecjpake_test_x3 ), + ecjpake_test_x4, sizeof( ecjpake_test_x4 ) ) ); + + /* Read round one */ + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &srv, + ecjpake_test_cli_one, + sizeof( ecjpake_test_cli_one ) ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_one( &cli, + ecjpake_test_srv_one, + sizeof( ecjpake_test_srv_one ) ) == 0 ); + + /* Skip generation of round two, read round two */ + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &cli, + ecjpake_test_srv_two, + sizeof( ecjpake_test_srv_two ) ) == 0 ); + + TEST_ASSERT( mbedtls_ecjpake_read_round_two( &srv, + ecjpake_test_cli_two, + sizeof( ecjpake_test_cli_two ) ) == 0 ); + + /* Server derives PMS */ + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &srv, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( len == sizeof( ecjpake_test_pms ) ); + TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 ); + + memset( buf, 0, len ); /* Avoid interferences with next step */ + + /* Client derives PMS */ + TEST_ASSERT( mbedtls_ecjpake_derive_secret( &cli, + buf, sizeof( buf ), &len, ecjpake_lgc, NULL ) == 0 ); + + TEST_ASSERT( len == sizeof( ecjpake_test_pms ) ); + TEST_ASSERT( memcmp( buf, ecjpake_test_pms, len ) == 0 ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + mbedtls_ecjpake_free( &cli ); + mbedtls_ecjpake_free( &srv ); + + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#undef TEST_ASSERT + +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED && MBEDTLS_SHA256_C */ + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ECJPAKE_C */ diff --git a/c++/src/connect/mbedtls/ecp.c b/c++/src/connect/mbedtls/ecp.c new file mode 100644 index 00000000..f51f2251 --- /dev/null +++ b/c++/src/connect/mbedtls/ecp.c @@ -0,0 +1,2092 @@ +/* + * Elliptic curves over GF(p): generic functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * References: + * + * SEC1 http://www.secg.org/index.php?action=secg,docs_secg + * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone + * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf + * RFC 4492 for the related TLS structures and constants + * + * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf + * + * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis + * for elliptic curve cryptosystems. In : Cryptographic Hardware and + * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. + * + * + * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to + * render ECC resistant against Side Channel Attacks. IACR Cryptology + * ePrint Archive, 2004, vol. 2004, p. 342. + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECP_C) + +#include "mbedtls/ecp.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * Counts of point addition and doubling, and field multiplications. + * Used to test resistance of point multiplication to simple timing attacks. + */ +static unsigned long add_count, dbl_count, mul_count; +#endif + +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +#define ECP_SHORTWEIERSTRASS +#endif + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +#define ECP_MONTGOMERY +#endif + +/* + * Curve types: internal for now, might be exposed later + */ +typedef enum +{ + ECP_TYPE_NONE = 0, + ECP_TYPE_SHORT_WEIERSTRASS, /* y^2 = x^3 + a x + b */ + ECP_TYPE_MONTGOMERY, /* y^2 = x^3 + a x^2 + x */ +} ecp_curve_type; + +/* + * List of supported curves: + * - internal ID + * - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2) + * - size in bits + * - readable name + * + * Curves are listed in order: largest curves first, and for a given size, + * fastest curves first. This provides the default order for the SSL module. + * + * Reminder: update profiles in x509_crt.c when adding a new curves! + */ +static const mbedtls_ecp_curve_info ecp_supported_curves[] = +{ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + { MBEDTLS_ECP_DP_SECP521R1, 25, 521, "secp521r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + { MBEDTLS_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + { MBEDTLS_ECP_DP_SECP384R1, 24, 384, "secp384r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + { MBEDTLS_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + { MBEDTLS_ECP_DP_SECP256R1, 23, 256, "secp256r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + { MBEDTLS_ECP_DP_SECP256K1, 22, 256, "secp256k1" }, +#endif +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + { MBEDTLS_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + { MBEDTLS_ECP_DP_SECP224R1, 21, 224, "secp224r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + { MBEDTLS_ECP_DP_SECP224K1, 20, 224, "secp224k1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + { MBEDTLS_ECP_DP_SECP192R1, 19, 192, "secp192r1" }, +#endif +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + { MBEDTLS_ECP_DP_SECP192K1, 18, 192, "secp192k1" }, +#endif + { MBEDTLS_ECP_DP_NONE, 0, 0, NULL }, +}; + +#define ECP_NB_CURVES sizeof( ecp_supported_curves ) / \ + sizeof( ecp_supported_curves[0] ) + +static mbedtls_ecp_group_id ecp_supported_grp_id[ECP_NB_CURVES]; + +/* + * List of supported curves and associated info + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ) +{ + return( ecp_supported_curves ); +} + +/* + * List of supported curves, group ID only + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void ) +{ + static int init_done = 0; + + if( ! init_done ) + { + size_t i = 0; + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + ecp_supported_grp_id[i++] = curve_info->grp_id; + } + ecp_supported_grp_id[i] = MBEDTLS_ECP_DP_NONE; + + init_done = 1; + } + + return( ecp_supported_grp_id ); +} + +/* + * Get the curve info for the internal identifier + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id ) +{ + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( curve_info->grp_id == grp_id ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the curve info from the TLS identifier + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id ) +{ + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( curve_info->tls_id == tls_id ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the curve info from the name + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ) +{ + const mbedtls_ecp_curve_info *curve_info; + + for( curve_info = mbedtls_ecp_curve_list(); + curve_info->grp_id != MBEDTLS_ECP_DP_NONE; + curve_info++ ) + { + if( strcmp( curve_info->name, name ) == 0 ) + return( curve_info ); + } + + return( NULL ); +} + +/* + * Get the type of a curve + */ +static inline ecp_curve_type ecp_get_type( const mbedtls_ecp_group *grp ) +{ + if( grp->G.X.p == NULL ) + return( ECP_TYPE_NONE ); + + if( grp->G.Y.p == NULL ) + return( ECP_TYPE_MONTGOMERY ); + else + return( ECP_TYPE_SHORT_WEIERSTRASS ); +} + +/* + * Initialize (the components of) a point + */ +void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ) +{ + if( pt == NULL ) + return; + + mbedtls_mpi_init( &pt->X ); + mbedtls_mpi_init( &pt->Y ); + mbedtls_mpi_init( &pt->Z ); +} + +/* + * Initialize (the components of) a group + */ +void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ) +{ + if( grp == NULL ) + return; + + memset( grp, 0, sizeof( mbedtls_ecp_group ) ); +} + +/* + * Initialize (the components of) a key pair + */ +void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ) +{ + if( key == NULL ) + return; + + mbedtls_ecp_group_init( &key->grp ); + mbedtls_mpi_init( &key->d ); + mbedtls_ecp_point_init( &key->Q ); +} + +/* + * Unallocate (the components of) a point + */ +void mbedtls_ecp_point_free( mbedtls_ecp_point *pt ) +{ + if( pt == NULL ) + return; + + mbedtls_mpi_free( &( pt->X ) ); + mbedtls_mpi_free( &( pt->Y ) ); + mbedtls_mpi_free( &( pt->Z ) ); +} + +/* + * Unallocate (the components of) a group + */ +void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ) +{ + size_t i; + + if( grp == NULL ) + return; + + if( grp->h != 1 ) + { + mbedtls_mpi_free( &grp->P ); + mbedtls_mpi_free( &grp->A ); + mbedtls_mpi_free( &grp->B ); + mbedtls_ecp_point_free( &grp->G ); + mbedtls_mpi_free( &grp->N ); + } + + if( grp->T != NULL ) + { + for( i = 0; i < grp->T_size; i++ ) + mbedtls_ecp_point_free( &grp->T[i] ); + mbedtls_free( grp->T ); + } + + mbedtls_zeroize( grp, sizeof( mbedtls_ecp_group ) ); +} + +/* + * Unallocate (the components of) a key pair + */ +void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ) +{ + if( key == NULL ) + return; + + mbedtls_ecp_group_free( &key->grp ); + mbedtls_mpi_free( &key->d ); + mbedtls_ecp_point_free( &key->Q ); +} + +/* + * Copy the contents of a point + */ +int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->X, &Q->X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Y, &Q->Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Z, &Q->Z ) ); + +cleanup: + return( ret ); +} + +/* + * Copy the contents of a group object + */ +int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ) +{ + return mbedtls_ecp_group_load( dst, src->id ); +} + +/* + * Set point to zero + */ +int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->X , 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Y , 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z , 0 ) ); + +cleanup: + return( ret ); +} + +/* + * Tell if a point is zero + */ +int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ) +{ + return( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 ); +} + +/* + * Compare two points lazyly + */ +int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ) +{ + if( mbedtls_mpi_cmp_mpi( &P->X, &Q->X ) == 0 && + mbedtls_mpi_cmp_mpi( &P->Y, &Q->Y ) == 0 && + mbedtls_mpi_cmp_mpi( &P->Z, &Q->Z ) == 0 ) + { + return( 0 ); + } + + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Import a non-zero point from ASCII strings + */ +int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, + const char *x, const char *y ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->X, radix, x ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->Y, radix, y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Export a point into unsigned binary data (SEC1 2.3.3) + */ +int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen ) +{ + int ret = 0; + size_t plen; + + if( format != MBEDTLS_ECP_PF_UNCOMPRESSED && + format != MBEDTLS_ECP_PF_COMPRESSED ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Common case: P == 0 + */ + if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 ) + { + if( buflen < 1 ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x00; + *olen = 1; + + return( 0 ); + } + + plen = mbedtls_mpi_size( &grp->P ); + + if( format == MBEDTLS_ECP_PF_UNCOMPRESSED ) + { + *olen = 2 * plen + 1; + + if( buflen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x04; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->Y, buf + 1 + plen, plen ) ); + } + else if( format == MBEDTLS_ECP_PF_COMPRESSED ) + { + *olen = plen + 1; + + if( buflen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + buf[0] = 0x02 + mbedtls_mpi_get_bit( &P->Y, 0 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) ); + } + +cleanup: + return( ret ); +} + +/* + * Import a point from unsigned binary data (SEC1 2.3.4) + */ +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + const unsigned char *buf, size_t ilen ) +{ + int ret; + size_t plen; + + if( ilen < 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( buf[0] == 0x00 ) + { + if( ilen == 1 ) + return( mbedtls_ecp_set_zero( pt ) ); + else + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + plen = mbedtls_mpi_size( &grp->P ); + + if( buf[0] != 0x04 ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + if( ilen != 2 * plen + 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->X, buf + 1, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->Y, buf + 1 + plen, plen ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Import a point from a TLS ECPoint record (RFC 4492) + * struct { + * opaque point <1..2^8-1>; + * } ECPoint; + */ +int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + const unsigned char **buf, size_t buf_len ) +{ + unsigned char data_len; + const unsigned char *buf_start; + + /* + * We must have at least two bytes (1 for length, at least one for data) + */ + if( buf_len < 2 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + data_len = *(*buf)++; + if( data_len < 1 || data_len > buf_len - 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Save buffer start for read_binary and update buf + */ + buf_start = *buf; + *buf += data_len; + + return mbedtls_ecp_point_read_binary( grp, pt, buf_start, data_len ); +} + +/* + * Export a point as a TLS ECPoint record (RFC 4492) + * struct { + * opaque point <1..2^8-1>; + * } ECPoint; + */ +int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ) +{ + int ret; + + /* + * buffer length must be at least one, for our length byte + */ + if( blen < 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_point_write_binary( grp, pt, format, + olen, buf + 1, blen - 1) ) != 0 ) + return( ret ); + + /* + * write length to the first byte and update total length + */ + buf[0] = (unsigned char) *olen; + ++*olen; + + return( 0 ); +} + +/* + * Set a group from an ECParameters record (RFC 4492) + */ +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ) +{ + uint16_t tls_id; + const mbedtls_ecp_curve_info *curve_info; + + /* + * We expect at least three bytes (see below) + */ + if( len < 3 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * First byte is curve_type; only named_curve is handled + */ + if( *(*buf)++ != MBEDTLS_ECP_TLS_NAMED_CURVE ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Next two bytes are the namedcurve value + */ + tls_id = *(*buf)++; + tls_id <<= 8; + tls_id |= *(*buf)++; + + if( ( curve_info = mbedtls_ecp_curve_info_from_tls_id( tls_id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + return mbedtls_ecp_group_load( grp, curve_info->grp_id ); +} + +/* + * Write the ECParameters record corresponding to a group (RFC 4492) + */ +int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen ) +{ + const mbedtls_ecp_curve_info *curve_info; + + if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id( grp->id ) ) == NULL ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * We are going to write 3 bytes (see below) + */ + *olen = 3; + if( blen < *olen ) + return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL ); + + /* + * First byte is curve_type, always named_curve + */ + *buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE; + + /* + * Next two bytes are the namedcurve value + */ + buf[0] = curve_info->tls_id >> 8; + buf[1] = curve_info->tls_id & 0xFF; + + return( 0 ); +} + +/* + * Wrapper around fast quasi-modp functions, with fall-back to mbedtls_mpi_mod_mpi. + * See the documentation of struct mbedtls_ecp_group. + * + * This function is in the critial loop for mbedtls_ecp_mul, so pay attention to perf. + */ +static int ecp_modp( mbedtls_mpi *N, const mbedtls_ecp_group *grp ) +{ + int ret; + + if( grp->modp == NULL ) + return( mbedtls_mpi_mod_mpi( N, N, &grp->P ) ); + + /* N->s < 0 is a much faster test, which fails only if N is 0 */ + if( ( N->s < 0 && mbedtls_mpi_cmp_int( N, 0 ) != 0 ) || + mbedtls_mpi_bitlen( N ) > 2 * grp->pbits ) + { + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + MBEDTLS_MPI_CHK( grp->modp( N ) ); + + /* N->s < 0 is a much faster test, which fails only if N is 0 */ + while( N->s < 0 && mbedtls_mpi_cmp_int( N, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &grp->P ) ); + + while( mbedtls_mpi_cmp_mpi( N, &grp->P ) >= 0 ) + /* we known P, N and the result are positive */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( N, N, &grp->P ) ); + +cleanup: + return( ret ); +} + +/* + * Fast mod-p functions expect their argument to be in the 0..p^2 range. + * + * In order to guarantee that, we need to ensure that operands of + * mbedtls_mpi_mul_mpi are in the 0..p range. So, after each operation we will + * bring the result back to this range. + * + * The following macros are shortcuts for doing that. + */ + +/* + * Reduce a mbedtls_mpi mod p in-place, general case, to use after mbedtls_mpi_mul_mpi + */ +#if defined(MBEDTLS_SELF_TEST) +#define INC_MUL_COUNT mul_count++; +#else +#define INC_MUL_COUNT +#endif + +#define MOD_MUL( N ) do { MBEDTLS_MPI_CHK( ecp_modp( &N, grp ) ); INC_MUL_COUNT } \ + while( 0 ) + +/* + * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi + * N->s < 0 is a very fast test, which fails only if N is 0 + */ +#define MOD_SUB( N ) \ + while( N.s < 0 && mbedtls_mpi_cmp_int( &N, 0 ) != 0 ) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &N, &N, &grp->P ) ) + +/* + * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int. + * We known P, N and the result are positive, so sub_abs is correct, and + * a bit faster. + */ +#define MOD_ADD( N ) \ + while( mbedtls_mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &N, &N, &grp->P ) ) + +#if defined(ECP_SHORTWEIERSTRASS) +/* + * For curves in short Weierstrass form, we do all the internal operations in + * Jacobian coordinates. + * + * For multiplication, we'll use a comb method with coutermeasueres against + * SPA, hence timing attacks. + */ + +/* + * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) + * Cost: 1N := 1I + 3M + 1S + */ +static int ecp_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt ) +{ + int ret; + mbedtls_mpi Zi, ZZi; + + if( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 ) + return( 0 ); + + mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); + + /* + * X = X / Z^2 mod p + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &Zi, &pt->Z, &grp->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->X, &pt->X, &ZZi ) ); MOD_MUL( pt->X ); + + /* + * Y = Y / Z^3 mod p + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &ZZi ) ); MOD_MUL( pt->Y ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &Zi ) ); MOD_MUL( pt->Y ); + + /* + * Z = 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) ); + +cleanup: + + mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi ); + + return( ret ); +} + +/* + * Normalize jacobian coordinates of an array of (pointers to) points, + * using Montgomery's trick to perform only one inversion mod P. + * (See for example Cohen's "A Course in Computational Algebraic Number + * Theory", Algorithm 10.3.4.) + * + * Warning: fails (returning an error) if one of the points is zero! + * This should never happen, see choice of w in ecp_mul_comb(). + * + * Cost: 1N(t) := 1I + (6t - 3)M + 1S + */ +static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *T[], size_t t_len ) +{ + int ret; + size_t i; + mbedtls_mpi *c, u, Zi, ZZi; + + if( t_len < 2 ) + return( ecp_normalize_jac( grp, *T ) ); + + if( ( c = mbedtls_calloc( t_len, sizeof( mbedtls_mpi ) ) ) == NULL ) + return( MBEDTLS_ERR_ECP_ALLOC_FAILED ); + + mbedtls_mpi_init( &u ); mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi ); + + /* + * c[i] = Z_0 * ... * Z_i + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &c[0], &T[0]->Z ) ); + for( i = 1; i < t_len; i++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &c[i], &c[i-1], &T[i]->Z ) ); + MOD_MUL( c[i] ); + } + + /* + * u = 1 / (Z_0 * ... * Z_n) mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &u, &c[t_len-1], &grp->P ) ); + + for( i = t_len - 1; ; i-- ) + { + /* + * Zi = 1 / Z_i mod p + * u = 1 / (Z_0 * ... * Z_i) mod P + */ + if( i == 0 ) { + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Zi, &u ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &Zi, &u, &c[i-1] ) ); MOD_MUL( Zi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u, &u, &T[i]->Z ) ); MOD_MUL( u ); + } + + /* + * proceed as in normalize() + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->X, &T[i]->X, &ZZi ) ); MOD_MUL( T[i]->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &ZZi ) ); MOD_MUL( T[i]->Y ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &Zi ) ); MOD_MUL( T[i]->Y ); + + /* + * Post-precessing: reclaim some memory by shrinking coordinates + * - not storing Z (always 1) + * - shrinking other coordinates, but still keeping the same number of + * limbs as P, as otherwise it will too likely be regrown too fast. + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->X, grp->P.n ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->Y, grp->P.n ) ); + mbedtls_mpi_free( &T[i]->Z ); + + if( i == 0 ) + break; + } + +cleanup: + + mbedtls_mpi_free( &u ); mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi ); + for( i = 0; i < t_len; i++ ) + mbedtls_mpi_free( &c[i] ); + mbedtls_free( c ); + + return( ret ); +} + +/* + * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak. + * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid + */ +static int ecp_safe_invert_jac( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *Q, + unsigned char inv ) +{ + int ret; + unsigned char nonzero; + mbedtls_mpi mQY; + + mbedtls_mpi_init( &mQY ); + + /* Use the fact that -Q.Y mod P = P - Q.Y unless Q.Y == 0 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mQY, &grp->P, &Q->Y ) ); + nonzero = mbedtls_mpi_cmp_int( &Q->Y, 0 ) != 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &Q->Y, &mQY, inv & nonzero ) ); + +cleanup: + mbedtls_mpi_free( &mQY ); + + return( ret ); +} + +/* + * Point doubling R = 2 P, Jacobian coordinates + * + * Based on http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 . + * + * We follow the variable naming fairly closely. The formula variations that trade a MUL for a SQR + * (plus a few ADDs) aren't useful as our bignum implementation doesn't distinguish squaring. + * + * Standard optimizations are applied when curve parameter A is one of { 0, -3 }. + * + * Cost: 1D := 3M + 4S (A == 0) + * 4M + 4S (A == -3) + * 3M + 6S + 1a otherwise + */ +static int ecp_double_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P ) +{ + int ret; + mbedtls_mpi M, S, T, U; + +#if defined(MBEDTLS_SELF_TEST) + dbl_count++; +#endif + + mbedtls_mpi_init( &M ); mbedtls_mpi_init( &S ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &U ); + + /* Special case for A = -3 */ + if( grp->A.p == NULL ) + { + /* M = 3(X + Z^2)(X - Z^2) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->Z, &P->Z ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &P->X, &S ) ); MOD_ADD( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U, &P->X, &S ) ); MOD_SUB( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &T, &U ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &S, 3 ) ); MOD_ADD( M ); + } + else + { + /* M = 3.X^2 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->X, &P->X ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &S, 3 ) ); MOD_ADD( M ); + + /* Optimize away for "koblitz" curves with A = 0 */ + if( mbedtls_mpi_cmp_int( &grp->A, 0 ) != 0 ) + { + /* M += A.Z^4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->Z, &P->Z ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &S, &S ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &T, &grp->A ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &M, &M, &S ) ); MOD_ADD( M ); + } + } + + /* S = 4.X.Y^2 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &P->Y, &P->Y ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T, 1 ) ); MOD_ADD( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &P->X, &T ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &S, 1 ) ); MOD_ADD( S ); + + /* U = 8.Y^4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &U, &T, &T ) ); MOD_MUL( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &U, 1 ) ); MOD_ADD( U ); + + /* T = M^2 - 2.S */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &M, &M ) ); MOD_MUL( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T, &S ) ); MOD_SUB( T ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T, &S ) ); MOD_SUB( T ); + + /* S = M(S - T) - U */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S, &S, &T ) ); MOD_SUB( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S, &S, &M ) ); MOD_MUL( S ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S, &S, &U ) ); MOD_SUB( S ); + + /* U = 2.Y.Z */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &U, &P->Y, &P->Z ) ); MOD_MUL( U ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &U, 1 ) ); MOD_ADD( U ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->X, &T ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Y, &S ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Z, &U ) ); + +cleanup: + mbedtls_mpi_free( &M ); mbedtls_mpi_free( &S ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &U ); + + return( ret ); +} + +/* + * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22) + * + * The coordinates of Q must be normalized (= affine), + * but those of P don't need to. R is not normalized. + * + * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q. + * None of these cases can happen as intermediate step in ecp_mul_comb(): + * - at each step, P, Q and R are multiples of the base point, the factor + * being less than its order, so none of them is zero; + * - Q is an odd multiple of the base point, P an even multiple, + * due to the choice of precomputed points in the modified comb method. + * So branches for these cases do not leak secret information. + * + * We accept Q->Z being unset (saving memory in tables) as meaning 1. + * + * Cost: 1A := 8M + 3S + */ +static int ecp_add_mixed( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ) +{ + int ret; + mbedtls_mpi T1, T2, T3, T4, X, Y, Z; + +#if defined(MBEDTLS_SELF_TEST) + add_count++; +#endif + + /* + * Trivial cases: P == 0 or Q == 0 (case 1) + */ + if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 ) + return( mbedtls_ecp_copy( R, Q ) ); + + if( Q->Z.p != NULL && mbedtls_mpi_cmp_int( &Q->Z, 0 ) == 0 ) + return( mbedtls_ecp_copy( R, P ) ); + + /* + * Make sure Q coordinates are normalized + */ + if( Q->Z.p != NULL && mbedtls_mpi_cmp_int( &Q->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); mbedtls_mpi_init( &T3 ); mbedtls_mpi_init( &T4 ); + mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 ); + + /* Special cases (2) and (3) */ + if( mbedtls_mpi_cmp_int( &T1, 0 ) == 0 ) + { + if( mbedtls_mpi_cmp_int( &T2, 0 ) == 0 ) + { + ret = ecp_double_jac( grp, R, P ); + goto cleanup; + } + else + { + ret = mbedtls_ecp_set_zero( R ); + goto cleanup; + } + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->X, &X ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Y, &Y ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Z, &Z ) ); + +cleanup: + + mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); mbedtls_mpi_free( &T3 ); mbedtls_mpi_free( &T4 ); + mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z ); + + return( ret ); +} + +/* + * Randomize jacobian coordinates: + * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_jac(). + * + * This countermeasure was first suggested in [2]. + */ +static int ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_mpi l, ll; + size_t p_size = ( grp->pbits + 7 ) / 8; + int count = 0; + + mbedtls_mpi_init( &l ); mbedtls_mpi_init( &ll ); + + /* Generate l such that 1 < l < p */ + do + { + mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ); + + while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 ); + + /* Z = l * Z */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Z, &pt->Z, &l ) ); MOD_MUL( pt->Z ); + + /* X = l^2 * X */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ll, &l, &l ) ); MOD_MUL( ll ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->X, &pt->X, &ll ) ); MOD_MUL( pt->X ); + + /* Y = l^3 * Y */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ll, &ll, &l ) ); MOD_MUL( ll ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y, &pt->Y, &ll ) ); MOD_MUL( pt->Y ); + +cleanup: + mbedtls_mpi_free( &l ); mbedtls_mpi_free( &ll ); + + return( ret ); +} + +/* + * Check and define parameters used by the comb method (see below for details) + */ +#if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7 +#error "MBEDTLS_ECP_WINDOW_SIZE out of bounds" +#endif + +/* d = ceil( n / w ) */ +#define COMB_MAX_D ( MBEDTLS_ECP_MAX_BITS + 1 ) / 2 + +/* number of precomputed points */ +#define COMB_MAX_PRE ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) ) + +/* + * Compute the representation of m that will be used with our comb method. + * + * The basic comb method is described in GECC 3.44 for example. We use a + * modified version that provides resistance to SPA by avoiding zero + * digits in the representation as in [3]. We modify the method further by + * requiring that all K_i be odd, which has the small cost that our + * representation uses one more K_i, due to carries. + * + * Also, for the sake of compactness, only the seven low-order bits of x[i] + * are used to represent K_i, and the msb of x[i] encodes the the sign (s_i in + * the paper): it is set if and only if if s_i == -1; + * + * Calling conventions: + * - x is an array of size d + 1 + * - w is the size, ie number of teeth, of the comb, and must be between + * 2 and 7 (in practice, between 2 and MBEDTLS_ECP_WINDOW_SIZE) + * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d + * (the result will be incorrect if these assumptions are not satisfied) + */ +static void ecp_comb_fixed( unsigned char x[], size_t d, + unsigned char w, const mbedtls_mpi *m ) +{ + size_t i, j; + unsigned char c, cc, adjust; + + memset( x, 0, d+1 ); + + /* First get the classical comb values (except for x_d = 0) */ + for( i = 0; i < d; i++ ) + for( j = 0; j < w; j++ ) + x[i] |= mbedtls_mpi_get_bit( m, i + d * j ) << j; + + /* Now make sure x_1 .. x_d are odd */ + c = 0; + for( i = 1; i <= d; i++ ) + { + /* Add carry and update it */ + cc = x[i] & c; + x[i] = x[i] ^ c; + c = cc; + + /* Adjust if needed, avoiding branches */ + adjust = 1 - ( x[i] & 0x01 ); + c |= x[i] & ( x[i-1] * adjust ); + x[i] = x[i] ^ ( x[i-1] * adjust ); + x[i-1] |= adjust << 7; + } +} + +/* + * Precompute points for the comb method + * + * If i = i_{w-1} ... i_1 is the binary representation of i, then + * T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P + * + * T must be able to hold 2^{w - 1} elements + * + * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1) + */ +static int ecp_precompute_comb( const mbedtls_ecp_group *grp, + mbedtls_ecp_point T[], const mbedtls_ecp_point *P, + unsigned char w, size_t d ) +{ + int ret; + unsigned char i, k; + size_t j; + mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1]; + + /* + * Set T[0] = P and + * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value) + */ + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &T[0], P ) ); + + k = 0; + for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 ) + { + cur = T + i; + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) ); + for( j = 0; j < d; j++ ) + MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) ); + + TT[k++] = cur; + } + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); + + /* + * Compute the remaining ones using the minimal number of additions + * Be careful to update T[2^l] only after using it! + */ + k = 0; + for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 ) + { + j = i; + while( j-- ) + { + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, &T[i + j], &T[j], &T[i] ) ); + TT[k++] = &T[i + j]; + } + } + + MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) ); + +cleanup: + return( ret ); +} + +/* + * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] + */ +static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point T[], unsigned char t_len, + unsigned char i ) +{ + int ret; + unsigned char ii, j; + + /* Ignore the "sign" bit and scale down */ + ii = ( i & 0x7Fu ) >> 1; + + /* Read the whole table to thwart cache-based timing attacks */ + for( j = 0; j < t_len; j++ ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->X, &T[j].X, j == ii ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->Y, &T[j].Y, j == ii ) ); + } + + /* Safely invert result if i is "negative" */ + MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, i >> 7 ) ); + +cleanup: + return( ret ); +} + +/* + * Core multiplication algorithm for the (modified) comb method. + * This part is actually common with the basic comb method (GECC 3.44) + * + * Cost: d A + d D + 1 R + */ +static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_ecp_point T[], unsigned char t_len, + const unsigned char x[], size_t d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + mbedtls_ecp_point Txi; + size_t i; + + mbedtls_ecp_point_init( &Txi ); + + /* Start with a non-zero point and randomize its coordinates */ + i = d; + MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, t_len, x[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) ); + if( f_rng != 0 ) + MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) ); + + while( i-- != 0 ) + { + MBEDTLS_MPI_CHK( ecp_double_jac( grp, R, R ) ); + MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, t_len, x[i] ) ); + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) ); + } + +cleanup: + mbedtls_ecp_point_free( &Txi ); + + return( ret ); +} + +/* + * Multiplication using the comb method, + * for curves in short Weierstrass form + */ +static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char w, m_is_odd, p_eq_g, pre_len, i; + size_t d; + unsigned char k[COMB_MAX_D + 1]; + mbedtls_ecp_point *T; + mbedtls_mpi M, mm; + + mbedtls_mpi_init( &M ); + mbedtls_mpi_init( &mm ); + + /* we need N to be odd to trnaform m in an odd number, check now */ + if( mbedtls_mpi_get_bit( &grp->N, 0 ) != 1 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + /* + * Minimize the number of multiplications, that is minimize + * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w ) + * (see costs of the various parts, with 1S = 1M) + */ + w = grp->nbits >= 384 ? 5 : 4; + + /* + * If P == G, pre-compute a bit more, since this may be re-used later. + * Just adding one avoids upping the cost of the first mul too much, + * and the memory cost too. + */ +#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 + p_eq_g = ( mbedtls_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 && + mbedtls_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 ); + if( p_eq_g ) + w++; +#else + p_eq_g = 0; +#endif + + /* + * Make sure w is within bounds. + * (The last test is useful only for very small curves in the test suite.) + */ + if( w > MBEDTLS_ECP_WINDOW_SIZE ) + w = MBEDTLS_ECP_WINDOW_SIZE; + if( w >= grp->nbits ) + w = 2; + + /* Other sizes that depend on w */ + pre_len = 1U << ( w - 1 ); + d = ( grp->nbits + w - 1 ) / w; + + /* + * Prepare precomputed points: if P == G we want to + * use grp->T if already initialized, or initialize it. + */ + T = p_eq_g ? grp->T : NULL; + + if( T == NULL ) + { + T = mbedtls_calloc( pre_len, sizeof( mbedtls_ecp_point ) ); + if( T == NULL ) + { + ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; + goto cleanup; + } + + MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d ) ); + + if( p_eq_g ) + { + grp->T = T; + grp->T_size = pre_len; + } + } + + /* + * Make sure M is odd (M = m or M = N - m, since N is odd) + * using the fact that m * P = - (N - m) * P + */ + m_is_odd = ( mbedtls_mpi_get_bit( m, 0 ) == 1 ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &M, m ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mm, &grp->N, m ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &M, &mm, ! m_is_odd ) ); + + /* + * Go for comb multiplication, R = M * P + */ + ecp_comb_fixed( k, d, w, &M ); + MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, R, T, pre_len, k, d, f_rng, p_rng ) ); + + /* + * Now get m * P from M * P and normalize it + */ + MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, ! m_is_odd ) ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) ); + +cleanup: + + if( T != NULL && ! p_eq_g ) + { + for( i = 0; i < pre_len; i++ ) + mbedtls_ecp_point_free( &T[i] ); + mbedtls_free( T ); + } + + mbedtls_mpi_free( &M ); + mbedtls_mpi_free( &mm ); + + if( ret != 0 ) + mbedtls_ecp_point_free( R ); + + return( ret ); +} + +#endif /* ECP_SHORTWEIERSTRASS */ + +#if defined(ECP_MONTGOMERY) +/* + * For Montgomery curves, we do all the internal arithmetic in projective + * coordinates. Import/export of points uses only the x coordinates, which is + * internaly represented as X / Z. + * + * For scalar multiplication, we'll use a Montgomery ladder. + */ + +/* + * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1 + * Cost: 1M + 1I + */ +static int ecp_normalize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P ) +{ + int ret; + + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &P->Z, &P->Z, &grp->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->X, &P->X, &P->Z ) ); MOD_MUL( P->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) ); + +cleanup: + return( ret ); +} + +/* + * Randomize projective x/z coordinates: + * (X, Z) -> (l X, l Z) for random l + * This is sort of the reverse operation of ecp_normalize_mxz(). + * + * This countermeasure was first suggested in [2]. + * Cost: 2M + */ +static int ecp_randomize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_mpi l; + size_t p_size = ( grp->pbits + 7 ) / 8; + int count = 0; + + mbedtls_mpi_init( &l ); + + /* Generate l such that 1 < l < p */ + do + { + mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ); + + while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) ); + + if( count++ > 10 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->X, &P->X, &l ) ); MOD_MUL( P->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->Z, &P->Z, &l ) ); MOD_MUL( P->Z ); + +cleanup: + mbedtls_mpi_free( &l ); + + return( ret ); +} + +/* + * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q), + * for Montgomery curves in x/z coordinates. + * + * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3 + * with + * d = X1 + * P = (X2, Z2) + * Q = (X3, Z3) + * R = (X4, Z4) + * S = (X5, Z5) + * and eliminating temporary variables tO, ..., t4. + * + * Cost: 5M + 4S + */ +static int ecp_double_add_mxz( const mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, mbedtls_ecp_point *S, + const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, + const mbedtls_mpi *d ) +{ + int ret; + mbedtls_mpi A, AA, B, BB, E, C, D, DA, CB; + + mbedtls_mpi_init( &A ); mbedtls_mpi_init( &AA ); mbedtls_mpi_init( &B ); + mbedtls_mpi_init( &BB ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &C ); + mbedtls_mpi_init( &D ); mbedtls_mpi_init( &DA ); mbedtls_mpi_init( &CB ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &A, &P->X, &P->Z ) ); MOD_ADD( A ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &AA, &A, &A ) ); MOD_MUL( AA ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &B, &P->X, &P->Z ) ); MOD_SUB( B ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &BB, &B, &B ) ); MOD_MUL( BB ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &E, &AA, &BB ) ); MOD_SUB( E ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &C, &Q->X, &Q->Z ) ); MOD_ADD( C ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &D, &Q->X, &Q->Z ) ); MOD_SUB( D ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DA, &D, &A ) ); MOD_MUL( DA ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &CB, &C, &B ) ); MOD_MUL( CB ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &S->X, &DA, &CB ) ); MOD_MUL( S->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->X, &S->X, &S->X ) ); MOD_MUL( S->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S->Z, &DA, &CB ) ); MOD_SUB( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->Z, &S->Z, &S->Z ) ); MOD_MUL( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->Z, d, &S->Z ) ); MOD_MUL( S->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->X, &AA, &BB ) ); MOD_MUL( R->X ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->Z, &grp->A, &E ) ); MOD_MUL( R->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &R->Z, &BB, &R->Z ) ); MOD_ADD( R->Z ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->Z, &E, &R->Z ) ); MOD_MUL( R->Z ); + +cleanup: + mbedtls_mpi_free( &A ); mbedtls_mpi_free( &AA ); mbedtls_mpi_free( &B ); + mbedtls_mpi_free( &BB ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &C ); + mbedtls_mpi_free( &D ); mbedtls_mpi_free( &DA ); mbedtls_mpi_free( &CB ); + + return( ret ); +} + +/* + * Multiplication with Montgomery ladder in x/z coordinates, + * for curves in Montgomery form + */ +static int ecp_mul_mxz( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t i; + unsigned char b; + mbedtls_ecp_point RP; + mbedtls_mpi PX; + + mbedtls_ecp_point_init( &RP ); mbedtls_mpi_init( &PX ); + + /* Save PX and read from P before writing to R, in case P == R */ + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &PX, &P->X ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &RP, P ) ); + + /* Set R to zero in modified x/z coordinates */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->X, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 0 ) ); + mbedtls_mpi_free( &R->Y ); + + /* RP.X might be sligtly larger than P, so reduce it */ + MOD_ADD( RP.X ); + + /* Randomize coordinates of the starting point */ + if( f_rng != NULL ) + MBEDTLS_MPI_CHK( ecp_randomize_mxz( grp, &RP, f_rng, p_rng ) ); + + /* Loop invariant: R = result so far, RP = R + P */ + i = mbedtls_mpi_bitlen( m ); /* one past the (zero-based) most significant bit */ + while( i-- > 0 ) + { + b = mbedtls_mpi_get_bit( m, i ); + /* + * if (b) R = 2R + P else R = 2R, + * which is: + * if (b) double_add( RP, R, RP, R ) + * else double_add( R, RP, R, RP ) + * but using safe conditional swaps to avoid leaks + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->X, &RP.X, b ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) ); + MBEDTLS_MPI_CHK( ecp_double_add_mxz( grp, R, &RP, R, &RP, &PX ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->X, &RP.X, b ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) ); + } + + MBEDTLS_MPI_CHK( ecp_normalize_mxz( grp, R ) ); + +cleanup: + mbedtls_ecp_point_free( &RP ); mbedtls_mpi_free( &PX ); + + return( ret ); +} + +#endif /* ECP_MONTGOMERY */ + +/* + * Multiplication R = m * P + */ +int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + + /* Common sanity checks */ + if( mbedtls_mpi_cmp_int( &P->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_ecp_check_privkey( grp, m ) ) != 0 || + ( ret = mbedtls_ecp_check_pubkey( grp, P ) ) != 0 ) + return( ret ); + +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + return( ecp_mul_mxz( grp, R, m, P, f_rng, p_rng ) ); +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + return( ecp_mul_comb( grp, R, m, P, f_rng, p_rng ) ); +#endif + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +#if defined(ECP_SHORTWEIERSTRASS) +/* + * Check that an affine point is valid as a public key, + * short weierstrass curves (SEC1 3.2.3.1) + */ +static int ecp_check_pubkey_sw( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +{ + int ret; + mbedtls_mpi YY, RHS; + + /* pt coordinates must be normalized for our checks */ + if( mbedtls_mpi_cmp_int( &pt->X, 0 ) < 0 || + mbedtls_mpi_cmp_int( &pt->Y, 0 ) < 0 || + mbedtls_mpi_cmp_mpi( &pt->X, &grp->P ) >= 0 || + mbedtls_mpi_cmp_mpi( &pt->Y, &grp->P ) >= 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + mbedtls_mpi_init( &YY ); mbedtls_mpi_init( &RHS ); + + /* + * YY = Y^2 + * RHS = X (X^2 + A) + B = X^3 + A X + B + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &YY, &pt->Y, &pt->Y ) ); MOD_MUL( YY ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &RHS, &pt->X, &pt->X ) ); MOD_MUL( RHS ); + + /* Special case for A = -3 */ + if( grp->A.p == NULL ) + { + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &RHS, &RHS, 3 ) ); MOD_SUB( RHS ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &RHS, &RHS, &grp->A ) ); MOD_ADD( RHS ); + } + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &RHS, &RHS, &pt->X ) ); MOD_MUL( RHS ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &RHS, &RHS, &grp->B ) ); MOD_ADD( RHS ); + + if( mbedtls_mpi_cmp_mpi( &YY, &RHS ) != 0 ) + ret = MBEDTLS_ERR_ECP_INVALID_KEY; + +cleanup: + + mbedtls_mpi_free( &YY ); mbedtls_mpi_free( &RHS ); + + return( ret ); +} +#endif /* ECP_SHORTWEIERSTRASS */ + +/* + * R = m * P with shortcuts for m == 1 and m == -1 + * NOT constant-time - ONLY for short Weierstrass! + */ +static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp, + mbedtls_ecp_point *R, + const mbedtls_mpi *m, + const mbedtls_ecp_point *P ) +{ + int ret; + + if( mbedtls_mpi_cmp_int( m, 1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); + } + else if( mbedtls_mpi_cmp_int( m, -1 ) == 0 ) + { + MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) ); + if( mbedtls_mpi_cmp_int( &R->Y, 0 ) != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &R->Y, &grp->P, &R->Y ) ); + } + else + { + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, R, m, P, NULL, NULL ) ); + } + +cleanup: + return( ret ); +} + +/* + * Linear combination + * NOT constant-time + */ +int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q ) +{ + int ret; + mbedtls_ecp_point mP; + + if( ecp_get_type( grp ) != ECP_TYPE_SHORT_WEIERSTRASS ) + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + + mbedtls_ecp_point_init( &mP ); + + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, &mP, m, P ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, R, n, Q ) ); + + MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, &mP, R ) ); + MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) ); + +cleanup: + mbedtls_ecp_point_free( &mP ); + + return( ret ); +} + + +#if defined(ECP_MONTGOMERY) +/* + * Check validity of a public key for Montgomery curves with x-only schemes + */ +static int ecp_check_pubkey_mx( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +{ + /* [Curve25519 p. 5] Just check X is the correct number of bytes */ + if( mbedtls_mpi_size( &pt->X ) > ( grp->nbits + 7 ) / 8 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + + return( 0 ); +} +#endif /* ECP_MONTGOMERY */ + +/* + * Check that a point is valid as a public key + */ +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ) +{ + /* Must use affine coordinates */ + if( mbedtls_mpi_cmp_int( &pt->Z, 1 ) != 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + return( ecp_check_pubkey_mx( grp, pt ) ); +#endif +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + return( ecp_check_pubkey_sw( grp, pt ) ); +#endif + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Check that an mbedtls_mpi is valid as a private key + */ +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d ) +{ +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + { + /* see [Curve25519] page 5 */ + if( mbedtls_mpi_get_bit( d, 0 ) != 0 || + mbedtls_mpi_get_bit( d, 1 ) != 0 || + mbedtls_mpi_get_bit( d, 2 ) != 0 || + mbedtls_mpi_bitlen( d ) - 1 != grp->nbits ) /* mbedtls_mpi_bitlen is one-based! */ + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + else + return( 0 ); + } +#endif /* ECP_MONTGOMERY */ +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* see SEC1 3.2 */ + if( mbedtls_mpi_cmp_int( d, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ) + return( MBEDTLS_ERR_ECP_INVALID_KEY ); + else + return( 0 ); + } +#endif /* ECP_SHORTWEIERSTRASS */ + + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); +} + +/* + * Generate a keypair with configurable base point + */ +int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + size_t n_size = ( grp->nbits + 7 ) / 8; + +#if defined(ECP_MONTGOMERY) + if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY ) + { + /* [M225] page 5 */ + size_t b; + + do { + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( d, n_size, f_rng, p_rng ) ); + } while( mbedtls_mpi_bitlen( d ) == 0); + + /* Make sure the most significant bit is nbits */ + b = mbedtls_mpi_bitlen( d ) - 1; /* mbedtls_mpi_bitlen is one-based */ + if( b > grp->nbits ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, b - grp->nbits ) ); + else + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, grp->nbits, 1 ) ); + + /* Make sure the last three bits are unset */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 0, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 1, 0 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) ); + } + else +#endif /* ECP_MONTGOMERY */ +#if defined(ECP_SHORTWEIERSTRASS) + if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS ) + { + /* SEC1 3.2.1: Generate d such that 1 <= n < N */ + int count = 0; + unsigned char rnd[MBEDTLS_ECP_MAX_BYTES]; + + /* + * Match the procedure given in RFC 6979 (deterministic ECDSA): + * - use the same byte ordering; + * - keep the leftmost nbits bits of the generated octet string; + * - try until result is in the desired range. + * This also avoids any biais, which is especially important for ECDSA. + */ + do + { + MBEDTLS_MPI_CHK( f_rng( p_rng, rnd, n_size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( d, rnd, n_size ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, 8 * n_size - grp->nbits ) ); + + /* + * Each try has at worst a probability 1/2 of failing (the msb has + * a probability 1/2 of being 0, and then the result will be < N), + * so after 30 tries failure probability is a most 2**(-30). + * + * For most curves, 1 try is enough with overwhelming probability, + * since N starts with a lot of 1s in binary, but some curves + * such as secp224k1 are actually very close to the worst case. + */ + if( ++count > 30 ) + return( MBEDTLS_ERR_ECP_RANDOM_FAILED ); + } + while( mbedtls_mpi_cmp_int( d, 1 ) < 0 || + mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 ); + } + else +#endif /* ECP_SHORTWEIERSTRASS */ + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + +cleanup: + if( ret != 0 ) + return( ret ); + + return( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) ); +} + +/* + * Generate key pair, wrapper for conventional base point + */ +int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + return( mbedtls_ecp_gen_keypair_base( grp, &grp->G, d, Q, f_rng, p_rng ) ); +} + +/* + * Generate a keypair, prettier wrapper + */ +int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + + if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 ) + return( ret ); + + return( mbedtls_ecp_gen_keypair( &key->grp, &key->d, &key->Q, f_rng, p_rng ) ); +} + +/* + * Check a public-private key pair + */ +int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv ) +{ + int ret; + mbedtls_ecp_point Q; + mbedtls_ecp_group grp; + + if( pub->grp.id == MBEDTLS_ECP_DP_NONE || + pub->grp.id != prv->grp.id || + mbedtls_mpi_cmp_mpi( &pub->Q.X, &prv->Q.X ) || + mbedtls_mpi_cmp_mpi( &pub->Q.Y, &prv->Q.Y ) || + mbedtls_mpi_cmp_mpi( &pub->Q.Z, &prv->Q.Z ) ) + { + return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA ); + } + + mbedtls_ecp_point_init( &Q ); + mbedtls_ecp_group_init( &grp ); + + /* mbedtls_ecp_mul() needs a non-const group... */ + mbedtls_ecp_group_copy( &grp, &prv->grp ); + + /* Also checks d is valid */ + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &Q, &prv->d, &prv->grp.G, NULL, NULL ) ); + + if( mbedtls_mpi_cmp_mpi( &Q.X, &prv->Q.X ) || + mbedtls_mpi_cmp_mpi( &Q.Y, &prv->Q.Y ) || + mbedtls_mpi_cmp_mpi( &Q.Z, &prv->Q.Z ) ) + { + ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; + goto cleanup; + } + +cleanup: + mbedtls_ecp_point_free( &Q ); + mbedtls_ecp_group_free( &grp ); + + return( ret ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Checkup routine + */ +int mbedtls_ecp_self_test( int verbose ) +{ + int ret; + size_t i; + mbedtls_ecp_group grp; + mbedtls_ecp_point R, P; + mbedtls_mpi m; + unsigned long add_c_prev, dbl_c_prev, mul_c_prev; + /* exponents especially adapted for secp192r1 */ + const char *exponents[] = + { + "000000000000000000000000000000000000000000000001", /* one */ + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830", /* N - 1 */ + "5EA6F389A38B8BC81E767753B15AA5569E1782E30ABE7D25", /* random */ + "400000000000000000000000000000000000000000000000", /* one and zeros */ + "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", /* all ones */ + "555555555555555555555555555555555555555555555555", /* 101010... */ + }; + + mbedtls_ecp_group_init( &grp ); + mbedtls_ecp_point_init( &R ); + mbedtls_ecp_point_init( &P ); + mbedtls_mpi_init( &m ); + + /* Use secp192r1 if available, or any available curve */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, MBEDTLS_ECP_DP_SECP192R1 ) ); +#else + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, mbedtls_ecp_curve_list()->grp_id ) ); +#endif + + if( verbose != 0 ) + mbedtls_printf( " ECP test #1 (constant op_count, base point G): " ); + + /* Do a dummy multiplication first to trigger precomputation */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &m, 2 ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &P, &m, &grp.G, NULL, NULL ) ); + + add_count = 0; + dbl_count = 0; + mul_count = 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[0] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) ); + + for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ ) + { + add_c_prev = add_count; + dbl_c_prev = dbl_count; + mul_c_prev = mul_count; + add_count = 0; + dbl_count = 0; + mul_count = 0; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) ); + + if( add_count != add_c_prev || + dbl_count != dbl_c_prev || + mul_count != mul_c_prev ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (%u)\n", (unsigned int) i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " ECP test #2 (constant op_count, other point): " ); + /* We computed P = 2G last time, use it */ + + add_count = 0; + dbl_count = 0; + mul_count = 0; + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[0] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) ); + + for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ ) + { + add_c_prev = add_count; + dbl_c_prev = dbl_count; + mul_c_prev = mul_count; + add_count = 0; + dbl_count = 0; + mul_count = 0; + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[i] ) ); + MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) ); + + if( add_count != add_c_prev || + dbl_count != dbl_c_prev || + mul_count != mul_c_prev ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (%u)\n", (unsigned int) i ); + + ret = 1; + goto cleanup; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + + if( ret < 0 && verbose != 0 ) + mbedtls_printf( "Unexpected error, return code = %08X\n", ret ); + + mbedtls_ecp_group_free( &grp ); + mbedtls_ecp_point_free( &R ); + mbedtls_ecp_point_free( &P ); + mbedtls_mpi_free( &m ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ECP_C */ diff --git a/c++/src/connect/mbedtls/ecp_curves.c b/c++/src/connect/mbedtls/ecp_curves.c new file mode 100644 index 00000000..a2a5495a --- /dev/null +++ b/c++/src/connect/mbedtls/ecp_curves.c @@ -0,0 +1,1325 @@ +/* + * Elliptic curves over GF(p): curve-specific data and functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ECP_C) + +#include "mbedtls/ecp.h" + +#include + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* + * Conversion macros for embedded constants: + * build lists of mbedtls_mpi_uint's from lists of unsigned char's grouped by 8, 4 or 2 + */ +#if defined(MBEDTLS_HAVE_INT32) + +#define BYTES_TO_T_UINT_4( a, b, c, d ) \ + ( (mbedtls_mpi_uint) a << 0 ) | \ + ( (mbedtls_mpi_uint) b << 8 ) | \ + ( (mbedtls_mpi_uint) c << 16 ) | \ + ( (mbedtls_mpi_uint) d << 24 ) + +#define BYTES_TO_T_UINT_2( a, b ) \ + BYTES_TO_T_UINT_4( a, b, 0, 0 ) + +#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ + BYTES_TO_T_UINT_4( a, b, c, d ), \ + BYTES_TO_T_UINT_4( e, f, g, h ) + +#else /* 64-bits */ + +#define BYTES_TO_T_UINT_8( a, b, c, d, e, f, g, h ) \ + ( (mbedtls_mpi_uint) a << 0 ) | \ + ( (mbedtls_mpi_uint) b << 8 ) | \ + ( (mbedtls_mpi_uint) c << 16 ) | \ + ( (mbedtls_mpi_uint) d << 24 ) | \ + ( (mbedtls_mpi_uint) e << 32 ) | \ + ( (mbedtls_mpi_uint) f << 40 ) | \ + ( (mbedtls_mpi_uint) g << 48 ) | \ + ( (mbedtls_mpi_uint) h << 56 ) + +#define BYTES_TO_T_UINT_4( a, b, c, d ) \ + BYTES_TO_T_UINT_8( a, b, c, d, 0, 0, 0, 0 ) + +#define BYTES_TO_T_UINT_2( a, b ) \ + BYTES_TO_T_UINT_8( a, b, 0, 0, 0, 0, 0, 0 ) + +#endif /* bits in mbedtls_mpi_uint */ + +/* + * Note: the constants are in little-endian order + * to be directly usable in MPIs + */ + +/* + * Domain parameters for secp192r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +static const mbedtls_mpi_uint secp192r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp192r1_b[] = { + BYTES_TO_T_UINT_8( 0xB1, 0xB9, 0x46, 0xC1, 0xEC, 0xDE, 0xB8, 0xFE ), + BYTES_TO_T_UINT_8( 0x49, 0x30, 0x24, 0x72, 0xAB, 0xE9, 0xA7, 0x0F ), + BYTES_TO_T_UINT_8( 0xE7, 0x80, 0x9C, 0xE5, 0x19, 0x05, 0x21, 0x64 ), +}; +static const mbedtls_mpi_uint secp192r1_gx[] = { + BYTES_TO_T_UINT_8( 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4 ), + BYTES_TO_T_UINT_8( 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C ), + BYTES_TO_T_UINT_8( 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18 ), +}; +static const mbedtls_mpi_uint secp192r1_gy[] = { + BYTES_TO_T_UINT_8( 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73 ), + BYTES_TO_T_UINT_8( 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63 ), + BYTES_TO_T_UINT_8( 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07 ), +}; +static const mbedtls_mpi_uint secp192r1_n[] = { + BYTES_TO_T_UINT_8( 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14 ), + BYTES_TO_T_UINT_8( 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +/* + * Domain parameters for secp224r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +static const mbedtls_mpi_uint secp224r1_p[] = { + BYTES_TO_T_UINT_8( 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp224r1_b[] = { + BYTES_TO_T_UINT_8( 0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27 ), + BYTES_TO_T_UINT_8( 0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50 ), + BYTES_TO_T_UINT_8( 0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C ), + BYTES_TO_T_UINT_4( 0x85, 0x0A, 0x05, 0xB4 ), +}; +static const mbedtls_mpi_uint secp224r1_gx[] = { + BYTES_TO_T_UINT_8( 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34 ), + BYTES_TO_T_UINT_8( 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A ), + BYTES_TO_T_UINT_8( 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B ), + BYTES_TO_T_UINT_4( 0xBD, 0x0C, 0x0E, 0xB7 ), +}; +static const mbedtls_mpi_uint secp224r1_gy[] = { + BYTES_TO_T_UINT_8( 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44 ), + BYTES_TO_T_UINT_8( 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD ), + BYTES_TO_T_UINT_8( 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5 ), + BYTES_TO_T_UINT_4( 0x88, 0x63, 0x37, 0xBD ), +}; +static const mbedtls_mpi_uint secp224r1_n[] = { + BYTES_TO_T_UINT_8( 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13 ), + BYTES_TO_T_UINT_8( 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_4( 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +/* + * Domain parameters for secp256r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static const mbedtls_mpi_uint secp256r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp256r1_b[] = { + BYTES_TO_T_UINT_8( 0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B ), + BYTES_TO_T_UINT_8( 0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65 ), + BYTES_TO_T_UINT_8( 0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3 ), + BYTES_TO_T_UINT_8( 0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A ), +}; +static const mbedtls_mpi_uint secp256r1_gx[] = { + BYTES_TO_T_UINT_8( 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4 ), + BYTES_TO_T_UINT_8( 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77 ), + BYTES_TO_T_UINT_8( 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8 ), + BYTES_TO_T_UINT_8( 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B ), +}; +static const mbedtls_mpi_uint secp256r1_gy[] = { + BYTES_TO_T_UINT_8( 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB ), + BYTES_TO_T_UINT_8( 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B ), + BYTES_TO_T_UINT_8( 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E ), + BYTES_TO_T_UINT_8( 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F ), +}; +static const mbedtls_mpi_uint secp256r1_n[] = { + BYTES_TO_T_UINT_8( 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3 ), + BYTES_TO_T_UINT_8( 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +/* + * Domain parameters for secp384r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static const mbedtls_mpi_uint secp384r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp384r1_b[] = { + BYTES_TO_T_UINT_8( 0xEF, 0x2A, 0xEC, 0xD3, 0xED, 0xC8, 0x85, 0x2A ), + BYTES_TO_T_UINT_8( 0x9D, 0xD1, 0x2E, 0x8A, 0x8D, 0x39, 0x56, 0xC6 ), + BYTES_TO_T_UINT_8( 0x5A, 0x87, 0x13, 0x50, 0x8F, 0x08, 0x14, 0x03 ), + BYTES_TO_T_UINT_8( 0x12, 0x41, 0x81, 0xFE, 0x6E, 0x9C, 0x1D, 0x18 ), + BYTES_TO_T_UINT_8( 0x19, 0x2D, 0xF8, 0xE3, 0x6B, 0x05, 0x8E, 0x98 ), + BYTES_TO_T_UINT_8( 0xE4, 0xE7, 0x3E, 0xE2, 0xA7, 0x2F, 0x31, 0xB3 ), +}; +static const mbedtls_mpi_uint secp384r1_gx[] = { + BYTES_TO_T_UINT_8( 0xB7, 0x0A, 0x76, 0x72, 0x38, 0x5E, 0x54, 0x3A ), + BYTES_TO_T_UINT_8( 0x6C, 0x29, 0x55, 0xBF, 0x5D, 0xF2, 0x02, 0x55 ), + BYTES_TO_T_UINT_8( 0x38, 0x2A, 0x54, 0x82, 0xE0, 0x41, 0xF7, 0x59 ), + BYTES_TO_T_UINT_8( 0x98, 0x9B, 0xA7, 0x8B, 0x62, 0x3B, 0x1D, 0x6E ), + BYTES_TO_T_UINT_8( 0x74, 0xAD, 0x20, 0xF3, 0x1E, 0xC7, 0xB1, 0x8E ), + BYTES_TO_T_UINT_8( 0x37, 0x05, 0x8B, 0xBE, 0x22, 0xCA, 0x87, 0xAA ), +}; +static const mbedtls_mpi_uint secp384r1_gy[] = { + BYTES_TO_T_UINT_8( 0x5F, 0x0E, 0xEA, 0x90, 0x7C, 0x1D, 0x43, 0x7A ), + BYTES_TO_T_UINT_8( 0x9D, 0x81, 0x7E, 0x1D, 0xCE, 0xB1, 0x60, 0x0A ), + BYTES_TO_T_UINT_8( 0xC0, 0xB8, 0xF0, 0xB5, 0x13, 0x31, 0xDA, 0xE9 ), + BYTES_TO_T_UINT_8( 0x7C, 0x14, 0x9A, 0x28, 0xBD, 0x1D, 0xF4, 0xF8 ), + BYTES_TO_T_UINT_8( 0x29, 0xDC, 0x92, 0x92, 0xBF, 0x98, 0x9E, 0x5D ), + BYTES_TO_T_UINT_8( 0x6F, 0x2C, 0x26, 0x96, 0x4A, 0xDE, 0x17, 0x36 ), +}; +static const mbedtls_mpi_uint secp384r1_n[] = { + BYTES_TO_T_UINT_8( 0x73, 0x29, 0xC5, 0xCC, 0x6A, 0x19, 0xEC, 0xEC ), + BYTES_TO_T_UINT_8( 0x7A, 0xA7, 0xB0, 0x48, 0xB2, 0x0D, 0x1A, 0x58 ), + BYTES_TO_T_UINT_8( 0xDF, 0x2D, 0x37, 0xF4, 0x81, 0x4D, 0x63, 0xC7 ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +/* + * Domain parameters for secp521r1 + */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static const mbedtls_mpi_uint secp521r1_p[] = { + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_2( 0xFF, 0x01 ), +}; +static const mbedtls_mpi_uint secp521r1_b[] = { + BYTES_TO_T_UINT_8( 0x00, 0x3F, 0x50, 0x6B, 0xD4, 0x1F, 0x45, 0xEF ), + BYTES_TO_T_UINT_8( 0xF1, 0x34, 0x2C, 0x3D, 0x88, 0xDF, 0x73, 0x35 ), + BYTES_TO_T_UINT_8( 0x07, 0xBF, 0xB1, 0x3B, 0xBD, 0xC0, 0x52, 0x16 ), + BYTES_TO_T_UINT_8( 0x7B, 0x93, 0x7E, 0xEC, 0x51, 0x39, 0x19, 0x56 ), + BYTES_TO_T_UINT_8( 0xE1, 0x09, 0xF1, 0x8E, 0x91, 0x89, 0xB4, 0xB8 ), + BYTES_TO_T_UINT_8( 0xF3, 0x15, 0xB3, 0x99, 0x5B, 0x72, 0xDA, 0xA2 ), + BYTES_TO_T_UINT_8( 0xEE, 0x40, 0x85, 0xB6, 0xA0, 0x21, 0x9A, 0x92 ), + BYTES_TO_T_UINT_8( 0x1F, 0x9A, 0x1C, 0x8E, 0x61, 0xB9, 0x3E, 0x95 ), + BYTES_TO_T_UINT_2( 0x51, 0x00 ), +}; +static const mbedtls_mpi_uint secp521r1_gx[] = { + BYTES_TO_T_UINT_8( 0x66, 0xBD, 0xE5, 0xC2, 0x31, 0x7E, 0x7E, 0xF9 ), + BYTES_TO_T_UINT_8( 0x9B, 0x42, 0x6A, 0x85, 0xC1, 0xB3, 0x48, 0x33 ), + BYTES_TO_T_UINT_8( 0xDE, 0xA8, 0xFF, 0xA2, 0x27, 0xC1, 0x1D, 0xFE ), + BYTES_TO_T_UINT_8( 0x28, 0x59, 0xE7, 0xEF, 0x77, 0x5E, 0x4B, 0xA1 ), + BYTES_TO_T_UINT_8( 0xBA, 0x3D, 0x4D, 0x6B, 0x60, 0xAF, 0x28, 0xF8 ), + BYTES_TO_T_UINT_8( 0x21, 0xB5, 0x3F, 0x05, 0x39, 0x81, 0x64, 0x9C ), + BYTES_TO_T_UINT_8( 0x42, 0xB4, 0x95, 0x23, 0x66, 0xCB, 0x3E, 0x9E ), + BYTES_TO_T_UINT_8( 0xCD, 0xE9, 0x04, 0x04, 0xB7, 0x06, 0x8E, 0x85 ), + BYTES_TO_T_UINT_2( 0xC6, 0x00 ), +}; +static const mbedtls_mpi_uint secp521r1_gy[] = { + BYTES_TO_T_UINT_8( 0x50, 0x66, 0xD1, 0x9F, 0x76, 0x94, 0xBE, 0x88 ), + BYTES_TO_T_UINT_8( 0x40, 0xC2, 0x72, 0xA2, 0x86, 0x70, 0x3C, 0x35 ), + BYTES_TO_T_UINT_8( 0x61, 0x07, 0xAD, 0x3F, 0x01, 0xB9, 0x50, 0xC5 ), + BYTES_TO_T_UINT_8( 0x40, 0x26, 0xF4, 0x5E, 0x99, 0x72, 0xEE, 0x97 ), + BYTES_TO_T_UINT_8( 0x2C, 0x66, 0x3E, 0x27, 0x17, 0xBD, 0xAF, 0x17 ), + BYTES_TO_T_UINT_8( 0x68, 0x44, 0x9B, 0x57, 0x49, 0x44, 0xF5, 0x98 ), + BYTES_TO_T_UINT_8( 0xD9, 0x1B, 0x7D, 0x2C, 0xB4, 0x5F, 0x8A, 0x5C ), + BYTES_TO_T_UINT_8( 0x04, 0xC0, 0x3B, 0x9A, 0x78, 0x6A, 0x29, 0x39 ), + BYTES_TO_T_UINT_2( 0x18, 0x01 ), +}; +static const mbedtls_mpi_uint secp521r1_n[] = { + BYTES_TO_T_UINT_8( 0x09, 0x64, 0x38, 0x91, 0x1E, 0xB7, 0x6F, 0xBB ), + BYTES_TO_T_UINT_8( 0xAE, 0x47, 0x9C, 0x89, 0xB8, 0xC9, 0xB5, 0x3B ), + BYTES_TO_T_UINT_8( 0xD0, 0xA5, 0x09, 0xF7, 0x48, 0x01, 0xCC, 0x7F ), + BYTES_TO_T_UINT_8( 0x6B, 0x96, 0x2F, 0xBF, 0x83, 0x87, 0x86, 0x51 ), + BYTES_TO_T_UINT_8( 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_2( 0xFF, 0x01 ), +}; +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +static const mbedtls_mpi_uint secp192k1_p[] = { + BYTES_TO_T_UINT_8( 0x37, 0xEE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp192k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp192k1_b[] = { + BYTES_TO_T_UINT_2( 0x03, 0x00 ), +}; +static const mbedtls_mpi_uint secp192k1_gx[] = { + BYTES_TO_T_UINT_8( 0x7D, 0x6C, 0xE0, 0xEA, 0xB1, 0xD1, 0xA5, 0x1D ), + BYTES_TO_T_UINT_8( 0x34, 0xF4, 0xB7, 0x80, 0x02, 0x7D, 0xB0, 0x26 ), + BYTES_TO_T_UINT_8( 0xAE, 0xE9, 0x57, 0xC0, 0x0E, 0xF1, 0x4F, 0xDB ), +}; +static const mbedtls_mpi_uint secp192k1_gy[] = { + BYTES_TO_T_UINT_8( 0x9D, 0x2F, 0x5E, 0xD9, 0x88, 0xAA, 0x82, 0x40 ), + BYTES_TO_T_UINT_8( 0x34, 0x86, 0xBE, 0x15, 0xD0, 0x63, 0x41, 0x84 ), + BYTES_TO_T_UINT_8( 0xA7, 0x28, 0x56, 0x9C, 0x6D, 0x2F, 0x2F, 0x9B ), +}; +static const mbedtls_mpi_uint secp192k1_n[] = { + BYTES_TO_T_UINT_8( 0x8D, 0xFD, 0xDE, 0x74, 0x6A, 0x46, 0x69, 0x0F ), + BYTES_TO_T_UINT_8( 0x17, 0xFC, 0xF2, 0x26, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +static const mbedtls_mpi_uint secp224k1_p[] = { + BYTES_TO_T_UINT_8( 0x6D, 0xE5, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_4( 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp224k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp224k1_b[] = { + BYTES_TO_T_UINT_2( 0x05, 0x00 ), +}; +static const mbedtls_mpi_uint secp224k1_gx[] = { + BYTES_TO_T_UINT_8( 0x5C, 0xA4, 0xB7, 0xB6, 0x0E, 0x65, 0x7E, 0x0F ), + BYTES_TO_T_UINT_8( 0xA9, 0x75, 0x70, 0xE4, 0xE9, 0x67, 0xA4, 0x69 ), + BYTES_TO_T_UINT_8( 0xA1, 0x28, 0xFC, 0x30, 0xDF, 0x99, 0xF0, 0x4D ), + BYTES_TO_T_UINT_4( 0x33, 0x5B, 0x45, 0xA1 ), +}; +static const mbedtls_mpi_uint secp224k1_gy[] = { + BYTES_TO_T_UINT_8( 0xA5, 0x61, 0x6D, 0x55, 0xDB, 0x4B, 0xCA, 0xE2 ), + BYTES_TO_T_UINT_8( 0x59, 0xBD, 0xB0, 0xC0, 0xF7, 0x19, 0xE3, 0xF7 ), + BYTES_TO_T_UINT_8( 0xD6, 0xFB, 0xCA, 0x82, 0x42, 0x34, 0xBA, 0x7F ), + BYTES_TO_T_UINT_4( 0xED, 0x9F, 0x08, 0x7E ), +}; +static const mbedtls_mpi_uint secp224k1_n[] = { + BYTES_TO_T_UINT_8( 0xF7, 0xB1, 0x9F, 0x76, 0x71, 0xA9, 0xF0, 0xCA ), + BYTES_TO_T_UINT_8( 0x84, 0x61, 0xEC, 0xD2, 0xE8, 0xDC, 0x01, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ), + BYTES_TO_T_UINT_8( 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ), +}; +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static const mbedtls_mpi_uint secp256k1_p[] = { + BYTES_TO_T_UINT_8( 0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +static const mbedtls_mpi_uint secp256k1_a[] = { + BYTES_TO_T_UINT_2( 0x00, 0x00 ), +}; +static const mbedtls_mpi_uint secp256k1_b[] = { + BYTES_TO_T_UINT_2( 0x07, 0x00 ), +}; +static const mbedtls_mpi_uint secp256k1_gx[] = { + BYTES_TO_T_UINT_8( 0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59 ), + BYTES_TO_T_UINT_8( 0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02 ), + BYTES_TO_T_UINT_8( 0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55 ), + BYTES_TO_T_UINT_8( 0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79 ), +}; +static const mbedtls_mpi_uint secp256k1_gy[] = { + BYTES_TO_T_UINT_8( 0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C ), + BYTES_TO_T_UINT_8( 0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD ), + BYTES_TO_T_UINT_8( 0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D ), + BYTES_TO_T_UINT_8( 0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48 ), +}; +static const mbedtls_mpi_uint secp256k1_n[] = { + BYTES_TO_T_UINT_8( 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF ), + BYTES_TO_T_UINT_8( 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA ), + BYTES_TO_T_UINT_8( 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), + BYTES_TO_T_UINT_8( 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF ), +}; +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +/* + * Domain parameters for brainpoolP256r1 (RFC 5639 3.4) + */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP256r1_p[] = { + BYTES_TO_T_UINT_8( 0x77, 0x53, 0x6E, 0x1F, 0x1D, 0x48, 0x13, 0x20 ), + BYTES_TO_T_UINT_8( 0x28, 0x20, 0x26, 0xD5, 0x23, 0xF6, 0x3B, 0x6E ), + BYTES_TO_T_UINT_8( 0x72, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E ), + BYTES_TO_T_UINT_8( 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_a[] = { + BYTES_TO_T_UINT_8( 0xD9, 0xB5, 0x30, 0xF3, 0x44, 0x4B, 0x4A, 0xE9 ), + BYTES_TO_T_UINT_8( 0x6C, 0x5C, 0xDC, 0x26, 0xC1, 0x55, 0x80, 0xFB ), + BYTES_TO_T_UINT_8( 0xE7, 0xFF, 0x7A, 0x41, 0x30, 0x75, 0xF6, 0xEE ), + BYTES_TO_T_UINT_8( 0x57, 0x30, 0x2C, 0xFC, 0x75, 0x09, 0x5A, 0x7D ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_b[] = { + BYTES_TO_T_UINT_8( 0xB6, 0x07, 0x8C, 0xFF, 0x18, 0xDC, 0xCC, 0x6B ), + BYTES_TO_T_UINT_8( 0xCE, 0xE1, 0xF7, 0x5C, 0x29, 0x16, 0x84, 0x95 ), + BYTES_TO_T_UINT_8( 0xBF, 0x7C, 0xD7, 0xBB, 0xD9, 0xB5, 0x30, 0xF3 ), + BYTES_TO_T_UINT_8( 0x44, 0x4B, 0x4A, 0xE9, 0x6C, 0x5C, 0xDC, 0x26 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gx[] = { + BYTES_TO_T_UINT_8( 0x62, 0x32, 0xCE, 0x9A, 0xBD, 0x53, 0x44, 0x3A ), + BYTES_TO_T_UINT_8( 0xC2, 0x23, 0xBD, 0xE3, 0xE1, 0x27, 0xDE, 0xB9 ), + BYTES_TO_T_UINT_8( 0xAF, 0xB7, 0x81, 0xFC, 0x2F, 0x48, 0x4B, 0x2C ), + BYTES_TO_T_UINT_8( 0xCB, 0x57, 0x7E, 0xCB, 0xB9, 0xAE, 0xD2, 0x8B ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_gy[] = { + BYTES_TO_T_UINT_8( 0x97, 0x69, 0x04, 0x2F, 0xC7, 0x54, 0x1D, 0x5C ), + BYTES_TO_T_UINT_8( 0x54, 0x8E, 0xED, 0x2D, 0x13, 0x45, 0x77, 0xC2 ), + BYTES_TO_T_UINT_8( 0xC9, 0x1D, 0x61, 0x14, 0x1A, 0x46, 0xF8, 0x97 ), + BYTES_TO_T_UINT_8( 0xFD, 0xC4, 0xDA, 0xC3, 0x35, 0xF8, 0x7E, 0x54 ), +}; +static const mbedtls_mpi_uint brainpoolP256r1_n[] = { + BYTES_TO_T_UINT_8( 0xA7, 0x56, 0x48, 0x97, 0x82, 0x0E, 0x1E, 0x90 ), + BYTES_TO_T_UINT_8( 0xF7, 0xA6, 0x61, 0xB5, 0xA3, 0x7A, 0x39, 0x8C ), + BYTES_TO_T_UINT_8( 0x71, 0x8D, 0x83, 0x9D, 0x90, 0x0A, 0x66, 0x3E ), + BYTES_TO_T_UINT_8( 0xBC, 0xA9, 0xEE, 0xA1, 0xDB, 0x57, 0xFB, 0xA9 ), +}; +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +/* + * Domain parameters for brainpoolP384r1 (RFC 5639 3.6) + */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP384r1_p[] = { + BYTES_TO_T_UINT_8( 0x53, 0xEC, 0x07, 0x31, 0x13, 0x00, 0x47, 0x87 ), + BYTES_TO_T_UINT_8( 0x71, 0x1A, 0x1D, 0x90, 0x29, 0xA7, 0xD3, 0xAC ), + BYTES_TO_T_UINT_8( 0x23, 0x11, 0xB7, 0x7F, 0x19, 0xDA, 0xB1, 0x12 ), + BYTES_TO_T_UINT_8( 0xB4, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15 ), + BYTES_TO_T_UINT_8( 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F ), + BYTES_TO_T_UINT_8( 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_a[] = { + BYTES_TO_T_UINT_8( 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04 ), + BYTES_TO_T_UINT_8( 0xEB, 0xD4, 0x3A, 0x50, 0x4A, 0x81, 0xA5, 0x8A ), + BYTES_TO_T_UINT_8( 0x0F, 0xF9, 0x91, 0xBA, 0xEF, 0x65, 0x91, 0x13 ), + BYTES_TO_T_UINT_8( 0x87, 0x27, 0xB2, 0x4F, 0x8E, 0xA2, 0xBE, 0xC2 ), + BYTES_TO_T_UINT_8( 0xA0, 0xAF, 0x05, 0xCE, 0x0A, 0x08, 0x72, 0x3C ), + BYTES_TO_T_UINT_8( 0x0C, 0x15, 0x8C, 0x3D, 0xC6, 0x82, 0xC3, 0x7B ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_b[] = { + BYTES_TO_T_UINT_8( 0x11, 0x4C, 0x50, 0xFA, 0x96, 0x86, 0xB7, 0x3A ), + BYTES_TO_T_UINT_8( 0x94, 0xC9, 0xDB, 0x95, 0x02, 0x39, 0xB4, 0x7C ), + BYTES_TO_T_UINT_8( 0xD5, 0x62, 0xEB, 0x3E, 0xA5, 0x0E, 0x88, 0x2E ), + BYTES_TO_T_UINT_8( 0xA6, 0xD2, 0xDC, 0x07, 0xE1, 0x7D, 0xB7, 0x2F ), + BYTES_TO_T_UINT_8( 0x7C, 0x44, 0xF0, 0x16, 0x54, 0xB5, 0x39, 0x8B ), + BYTES_TO_T_UINT_8( 0x26, 0x28, 0xCE, 0x22, 0xDD, 0xC7, 0xA8, 0x04 ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gx[] = { + BYTES_TO_T_UINT_8( 0x1E, 0xAF, 0xD4, 0x47, 0xE2, 0xB2, 0x87, 0xEF ), + BYTES_TO_T_UINT_8( 0xAA, 0x46, 0xD6, 0x36, 0x34, 0xE0, 0x26, 0xE8 ), + BYTES_TO_T_UINT_8( 0xE8, 0x10, 0xBD, 0x0C, 0xFE, 0xCA, 0x7F, 0xDB ), + BYTES_TO_T_UINT_8( 0xE3, 0x4F, 0xF1, 0x7E, 0xE7, 0xA3, 0x47, 0x88 ), + BYTES_TO_T_UINT_8( 0x6B, 0x3F, 0xC1, 0xB7, 0x81, 0x3A, 0xA6, 0xA2 ), + BYTES_TO_T_UINT_8( 0xFF, 0x45, 0xCF, 0x68, 0xF0, 0x64, 0x1C, 0x1D ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_gy[] = { + BYTES_TO_T_UINT_8( 0x15, 0x53, 0x3C, 0x26, 0x41, 0x03, 0x82, 0x42 ), + BYTES_TO_T_UINT_8( 0x11, 0x81, 0x91, 0x77, 0x21, 0x46, 0x46, 0x0E ), + BYTES_TO_T_UINT_8( 0x28, 0x29, 0x91, 0xF9, 0x4F, 0x05, 0x9C, 0xE1 ), + BYTES_TO_T_UINT_8( 0x64, 0x58, 0xEC, 0xFE, 0x29, 0x0B, 0xB7, 0x62 ), + BYTES_TO_T_UINT_8( 0x52, 0xD5, 0xCF, 0x95, 0x8E, 0xEB, 0xB1, 0x5C ), + BYTES_TO_T_UINT_8( 0xA4, 0xC2, 0xF9, 0x20, 0x75, 0x1D, 0xBE, 0x8A ), +}; +static const mbedtls_mpi_uint brainpoolP384r1_n[] = { + BYTES_TO_T_UINT_8( 0x65, 0x65, 0x04, 0xE9, 0x02, 0x32, 0x88, 0x3B ), + BYTES_TO_T_UINT_8( 0x10, 0xC3, 0x7F, 0x6B, 0xAF, 0xB6, 0x3A, 0xCF ), + BYTES_TO_T_UINT_8( 0xA7, 0x25, 0x04, 0xAC, 0x6C, 0x6E, 0x16, 0x1F ), + BYTES_TO_T_UINT_8( 0xB3, 0x56, 0x54, 0xED, 0x09, 0x71, 0x2F, 0x15 ), + BYTES_TO_T_UINT_8( 0xDF, 0x41, 0xE6, 0x50, 0x7E, 0x6F, 0x5D, 0x0F ), + BYTES_TO_T_UINT_8( 0x28, 0x6D, 0x38, 0xA3, 0x82, 0x1E, 0xB9, 0x8C ), +}; +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +/* + * Domain parameters for brainpoolP512r1 (RFC 5639 3.7) + */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) +static const mbedtls_mpi_uint brainpoolP512r1_p[] = { + BYTES_TO_T_UINT_8( 0xF3, 0x48, 0x3A, 0x58, 0x56, 0x60, 0xAA, 0x28 ), + BYTES_TO_T_UINT_8( 0x85, 0xC6, 0x82, 0x2D, 0x2F, 0xFF, 0x81, 0x28 ), + BYTES_TO_T_UINT_8( 0xE6, 0x80, 0xA3, 0xE6, 0x2A, 0xA1, 0xCD, 0xAE ), + BYTES_TO_T_UINT_8( 0x42, 0x68, 0xC6, 0x9B, 0x00, 0x9B, 0x4D, 0x7D ), + BYTES_TO_T_UINT_8( 0x71, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6 ), + BYTES_TO_T_UINT_8( 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB ), + BYTES_TO_T_UINT_8( 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F ), + BYTES_TO_T_UINT_8( 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_a[] = { + BYTES_TO_T_UINT_8( 0xCA, 0x94, 0xFC, 0x77, 0x4D, 0xAC, 0xC1, 0xE7 ), + BYTES_TO_T_UINT_8( 0xB9, 0xC7, 0xF2, 0x2B, 0xA7, 0x17, 0x11, 0x7F ), + BYTES_TO_T_UINT_8( 0xB5, 0xC8, 0x9A, 0x8B, 0xC9, 0xF1, 0x2E, 0x0A ), + BYTES_TO_T_UINT_8( 0xA1, 0x3A, 0x25, 0xA8, 0x5A, 0x5D, 0xED, 0x2D ), + BYTES_TO_T_UINT_8( 0xBC, 0x63, 0x98, 0xEA, 0xCA, 0x41, 0x34, 0xA8 ), + BYTES_TO_T_UINT_8( 0x10, 0x16, 0xF9, 0x3D, 0x8D, 0xDD, 0xCB, 0x94 ), + BYTES_TO_T_UINT_8( 0xC5, 0x4C, 0x23, 0xAC, 0x45, 0x71, 0x32, 0xE2 ), + BYTES_TO_T_UINT_8( 0x89, 0x3B, 0x60, 0x8B, 0x31, 0xA3, 0x30, 0x78 ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_b[] = { + BYTES_TO_T_UINT_8( 0x23, 0xF7, 0x16, 0x80, 0x63, 0xBD, 0x09, 0x28 ), + BYTES_TO_T_UINT_8( 0xDD, 0xE5, 0xBA, 0x5E, 0xB7, 0x50, 0x40, 0x98 ), + BYTES_TO_T_UINT_8( 0x67, 0x3E, 0x08, 0xDC, 0xCA, 0x94, 0xFC, 0x77 ), + BYTES_TO_T_UINT_8( 0x4D, 0xAC, 0xC1, 0xE7, 0xB9, 0xC7, 0xF2, 0x2B ), + BYTES_TO_T_UINT_8( 0xA7, 0x17, 0x11, 0x7F, 0xB5, 0xC8, 0x9A, 0x8B ), + BYTES_TO_T_UINT_8( 0xC9, 0xF1, 0x2E, 0x0A, 0xA1, 0x3A, 0x25, 0xA8 ), + BYTES_TO_T_UINT_8( 0x5A, 0x5D, 0xED, 0x2D, 0xBC, 0x63, 0x98, 0xEA ), + BYTES_TO_T_UINT_8( 0xCA, 0x41, 0x34, 0xA8, 0x10, 0x16, 0xF9, 0x3D ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gx[] = { + BYTES_TO_T_UINT_8( 0x22, 0xF8, 0xB9, 0xBC, 0x09, 0x22, 0x35, 0x8B ), + BYTES_TO_T_UINT_8( 0x68, 0x5E, 0x6A, 0x40, 0x47, 0x50, 0x6D, 0x7C ), + BYTES_TO_T_UINT_8( 0x5F, 0x7D, 0xB9, 0x93, 0x7B, 0x68, 0xD1, 0x50 ), + BYTES_TO_T_UINT_8( 0x8D, 0xD4, 0xD0, 0xE2, 0x78, 0x1F, 0x3B, 0xFF ), + BYTES_TO_T_UINT_8( 0x8E, 0x09, 0xD0, 0xF4, 0xEE, 0x62, 0x3B, 0xB4 ), + BYTES_TO_T_UINT_8( 0xC1, 0x16, 0xD9, 0xB5, 0x70, 0x9F, 0xED, 0x85 ), + BYTES_TO_T_UINT_8( 0x93, 0x6A, 0x4C, 0x9C, 0x2E, 0x32, 0x21, 0x5A ), + BYTES_TO_T_UINT_8( 0x64, 0xD9, 0x2E, 0xD8, 0xBD, 0xE4, 0xAE, 0x81 ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_gy[] = { + BYTES_TO_T_UINT_8( 0x92, 0x08, 0xD8, 0x3A, 0x0F, 0x1E, 0xCD, 0x78 ), + BYTES_TO_T_UINT_8( 0x06, 0x54, 0xF0, 0xA8, 0x2F, 0x2B, 0xCA, 0xD1 ), + BYTES_TO_T_UINT_8( 0xAE, 0x63, 0x27, 0x8A, 0xD8, 0x4B, 0xCA, 0x5B ), + BYTES_TO_T_UINT_8( 0x5E, 0x48, 0x5F, 0x4A, 0x49, 0xDE, 0xDC, 0xB2 ), + BYTES_TO_T_UINT_8( 0x11, 0x81, 0x1F, 0x88, 0x5B, 0xC5, 0x00, 0xA0 ), + BYTES_TO_T_UINT_8( 0x1A, 0x7B, 0xA5, 0x24, 0x00, 0xF7, 0x09, 0xF2 ), + BYTES_TO_T_UINT_8( 0xFD, 0x22, 0x78, 0xCF, 0xA9, 0xBF, 0xEA, 0xC0 ), + BYTES_TO_T_UINT_8( 0xEC, 0x32, 0x63, 0x56, 0x5D, 0x38, 0xDE, 0x7D ), +}; +static const mbedtls_mpi_uint brainpoolP512r1_n[] = { + BYTES_TO_T_UINT_8( 0x69, 0x00, 0xA9, 0x9C, 0x82, 0x96, 0x87, 0xB5 ), + BYTES_TO_T_UINT_8( 0xDD, 0xDA, 0x5D, 0x08, 0x81, 0xD3, 0xB1, 0x1D ), + BYTES_TO_T_UINT_8( 0x47, 0x10, 0xAC, 0x7F, 0x19, 0x61, 0x86, 0x41 ), + BYTES_TO_T_UINT_8( 0x19, 0x26, 0xA9, 0x4C, 0x41, 0x5C, 0x3E, 0x55 ), + BYTES_TO_T_UINT_8( 0x70, 0x08, 0x33, 0x70, 0xCA, 0x9C, 0x63, 0xD6 ), + BYTES_TO_T_UINT_8( 0x0E, 0xD2, 0xC9, 0xB3, 0xB3, 0x8D, 0x30, 0xCB ), + BYTES_TO_T_UINT_8( 0x07, 0xFC, 0xC9, 0x33, 0xAE, 0xE6, 0xD4, 0x3F ), + BYTES_TO_T_UINT_8( 0x8B, 0xC4, 0xE9, 0xDB, 0xB8, 0x9D, 0xDD, 0xAA ), +}; +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + +/* + * Create an MPI from embedded constants + * (assumes len is an exact multiple of sizeof mbedtls_mpi_uint) + */ +static inline void ecp_mpi_load( mbedtls_mpi *X, const mbedtls_mpi_uint *p, size_t len ) +{ + X->s = 1; + X->n = len / sizeof( mbedtls_mpi_uint ); + X->p = (mbedtls_mpi_uint *) p; +} + +/* + * Set an MPI to static value 1 + */ +static inline void ecp_mpi_set1( mbedtls_mpi *X ) +{ + static mbedtls_mpi_uint one[] = { 1 }; + X->s = 1; + X->n = 1; + X->p = one; +} + +/* + * Make group available from embedded constants + */ +static int ecp_group_load( mbedtls_ecp_group *grp, + const mbedtls_mpi_uint *p, size_t plen, + const mbedtls_mpi_uint *a, size_t alen, + const mbedtls_mpi_uint *b, size_t blen, + const mbedtls_mpi_uint *gx, size_t gxlen, + const mbedtls_mpi_uint *gy, size_t gylen, + const mbedtls_mpi_uint *n, size_t nlen) +{ + ecp_mpi_load( &grp->P, p, plen ); + if( a != NULL ) + ecp_mpi_load( &grp->A, a, alen ); + ecp_mpi_load( &grp->B, b, blen ); + ecp_mpi_load( &grp->N, n, nlen ); + + ecp_mpi_load( &grp->G.X, gx, gxlen ); + ecp_mpi_load( &grp->G.Y, gy, gylen ); + ecp_mpi_set1( &grp->G.Z ); + + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + grp->nbits = mbedtls_mpi_bitlen( &grp->N ); + + grp->h = 1; + + return( 0 ); +} + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* Forward declarations */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +static int ecp_mod_p192( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +static int ecp_mod_p224( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +static int ecp_mod_p256( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +static int ecp_mod_p384( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +static int ecp_mod_p521( mbedtls_mpi * ); +#endif + +#define NIST_MODP( P ) grp->modp = ecp_mod_ ## P; +#else +#define NIST_MODP( P ) +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +/* Additional forward declarations */ +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +static int ecp_mod_p255( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +static int ecp_mod_p192k1( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +static int ecp_mod_p224k1( mbedtls_mpi * ); +#endif +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +static int ecp_mod_p256k1( mbedtls_mpi * ); +#endif + +#define LOAD_GROUP_A( G ) ecp_group_load( grp, \ + G ## _p, sizeof( G ## _p ), \ + G ## _a, sizeof( G ## _a ), \ + G ## _b, sizeof( G ## _b ), \ + G ## _gx, sizeof( G ## _gx ), \ + G ## _gy, sizeof( G ## _gy ), \ + G ## _n, sizeof( G ## _n ) ) + +#define LOAD_GROUP( G ) ecp_group_load( grp, \ + G ## _p, sizeof( G ## _p ), \ + NULL, 0, \ + G ## _b, sizeof( G ## _b ), \ + G ## _gx, sizeof( G ## _gx ), \ + G ## _gy, sizeof( G ## _gy ), \ + G ## _n, sizeof( G ## _n ) ) + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) +/* + * Specialized function for creating the Curve25519 group + */ +static int ecp_use_curve25519( mbedtls_ecp_group *grp ) +{ + int ret; + + /* Actually ( A + 2 ) / 4 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &grp->A, 16, "01DB42" ) ); + + /* P = 2^255 - 19 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &grp->P, 255 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &grp->P, &grp->P, 19 ) ); + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + + /* Y intentionaly not set, since we use x/z coordinates. + * This is used as a marker to identify Montgomery curves! */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.X, 9 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &grp->G.Z, 1 ) ); + mbedtls_mpi_free( &grp->G.Y ); + + /* Actually, the required msb for private keys */ + grp->nbits = 254; + +cleanup: + if( ret != 0 ) + mbedtls_ecp_group_free( grp ); + + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +/* + * Set a group using well-known domain parameters + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id id ) +{ + mbedtls_ecp_group_free( grp ); + + grp->id = id; + + switch( id ) + { +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + case MBEDTLS_ECP_DP_SECP192R1: + NIST_MODP( p192 ); + return( LOAD_GROUP( secp192r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + case MBEDTLS_ECP_DP_SECP224R1: + NIST_MODP( p224 ); + return( LOAD_GROUP( secp224r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + case MBEDTLS_ECP_DP_SECP256R1: + NIST_MODP( p256 ); + return( LOAD_GROUP( secp256r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + case MBEDTLS_ECP_DP_SECP384R1: + NIST_MODP( p384 ); + return( LOAD_GROUP( secp384r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + case MBEDTLS_ECP_DP_SECP521R1: + NIST_MODP( p521 ); + return( LOAD_GROUP( secp521r1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + case MBEDTLS_ECP_DP_SECP192K1: + grp->modp = ecp_mod_p192k1; + return( LOAD_GROUP_A( secp192k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + case MBEDTLS_ECP_DP_SECP224K1: + grp->modp = ecp_mod_p224k1; + return( LOAD_GROUP_A( secp224k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + case MBEDTLS_ECP_DP_SECP256K1: + grp->modp = ecp_mod_p256k1; + return( LOAD_GROUP_A( secp256k1 ) ); +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + case MBEDTLS_ECP_DP_BP256R1: + return( LOAD_GROUP_A( brainpoolP256r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + case MBEDTLS_ECP_DP_BP384R1: + return( LOAD_GROUP_A( brainpoolP384r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + case MBEDTLS_ECP_DP_BP512R1: + return( LOAD_GROUP_A( brainpoolP512r1 ) ); +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + case MBEDTLS_ECP_DP_CURVE25519: + grp->modp = ecp_mod_p255; + return( ecp_use_curve25519( grp ) ); +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + + default: + mbedtls_ecp_group_free( grp ); + return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ); + } +} + +#if defined(MBEDTLS_ECP_NIST_OPTIM) +/* + * Fast reduction modulo the primes used by the NIST curves. + * + * These functions are critical for speed, but not needed for correct + * operations. So, we make the choice to heavily rely on the internals of our + * bignum library, which creates a tight coupling between these functions and + * our MPI implementation. However, the coupling between the ECP module and + * MPI remains loose, since these functions can be deactivated at will. + */ + +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) +/* + * Compared to the way things are presented in FIPS 186-3 D.2, + * we proceed in columns, from right (least significant chunk) to left, + * adding chunks to N in place, and keeping a carry for the next chunk. + * This avoids moving things around in memory, and uselessly adding zeros, + * compared to the more straightforward, line-oriented approach. + * + * For this prime we need to handle data in chunks of 64 bits. + * Since this is always a multiple of our basic mbedtls_mpi_uint, we can + * use a mbedtls_mpi_uint * to designate such a chunk, and small loops to handle it. + */ + +/* Add 64-bit chunks (dst += src) and update carry */ +static inline void add64( mbedtls_mpi_uint *dst, mbedtls_mpi_uint *src, mbedtls_mpi_uint *carry ) +{ + unsigned char i; + mbedtls_mpi_uint c = 0; + for( i = 0; i < 8 / sizeof( mbedtls_mpi_uint ); i++, dst++, src++ ) + { + *dst += c; c = ( *dst < c ); + *dst += *src; c += ( *dst < *src ); + } + *carry += c; +} + +/* Add carry to a 64-bit chunk and update carry */ +static inline void carry64( mbedtls_mpi_uint *dst, mbedtls_mpi_uint *carry ) +{ + unsigned char i; + for( i = 0; i < 8 / sizeof( mbedtls_mpi_uint ); i++, dst++ ) + { + *dst += *carry; + *carry = ( *dst < *carry ); + } +} + +#define WIDTH 8 / sizeof( mbedtls_mpi_uint ) +#define A( i ) N->p + i * WIDTH +#define ADD( i ) add64( p, A( i ), &c ) +#define NEXT p += WIDTH; carry64( p, &c ) +#define LAST p += WIDTH; *p = c; while( ++p < end ) *p = 0 + +/* + * Fast quasi-reduction modulo p192 (FIPS 186-3 D.2.1) + */ +static int ecp_mod_p192( mbedtls_mpi *N ) +{ + int ret; + mbedtls_mpi_uint c = 0; + mbedtls_mpi_uint *p, *end; + + /* Make sure we have enough blocks so that A(5) is legal */ + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, 6 * WIDTH ) ); + + p = N->p; + end = p + N->n; + + ADD( 3 ); ADD( 5 ); NEXT; // A0 += A3 + A5 + ADD( 3 ); ADD( 4 ); ADD( 5 ); NEXT; // A1 += A3 + A4 + A5 + ADD( 4 ); ADD( 5 ); LAST; // A2 += A4 + A5 + +cleanup: + return( ret ); +} + +#undef WIDTH +#undef A +#undef ADD +#undef NEXT +#undef LAST +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +/* + * The reader is advised to first understand ecp_mod_p192() since the same + * general structure is used here, but with additional complications: + * (1) chunks of 32 bits, and (2) subtractions. + */ + +/* + * For these primes, we need to handle data in chunks of 32 bits. + * This makes it more complicated if we use 64 bits limbs in MPI, + * which prevents us from using a uniform access method as for p192. + * + * So, we define a mini abstraction layer to access 32 bit chunks, + * load them in 'cur' for work, and store them back from 'cur' when done. + * + * While at it, also define the size of N in terms of 32-bit chunks. + */ +#define LOAD32 cur = A( i ); + +#if defined(MBEDTLS_HAVE_INT32) /* 32 bit */ + +#define MAX32 N->n +#define A( j ) N->p[j] +#define STORE32 N->p[i] = cur; + +#else /* 64-bit */ + +#define MAX32 N->n * 2 +#define A( j ) j % 2 ? (uint32_t)( N->p[j/2] >> 32 ) : (uint32_t)( N->p[j/2] ) +#define STORE32 \ + if( i % 2 ) { \ + N->p[i/2] &= 0x00000000FFFFFFFF; \ + N->p[i/2] |= ((mbedtls_mpi_uint) cur) << 32; \ + } else { \ + N->p[i/2] &= 0xFFFFFFFF00000000; \ + N->p[i/2] |= (mbedtls_mpi_uint) cur; \ + } + +#endif /* sizeof( mbedtls_mpi_uint ) */ + +/* + * Helpers for addition and subtraction of chunks, with signed carry. + */ +static inline void add32( uint32_t *dst, uint32_t src, signed char *carry ) +{ + *dst += src; + *carry += ( *dst < src ); +} + +static inline void sub32( uint32_t *dst, uint32_t src, signed char *carry ) +{ + *carry -= ( *dst < src ); + *dst -= src; +} + +#define ADD( j ) add32( &cur, A( j ), &c ); +#define SUB( j ) sub32( &cur, A( j ), &c ); + +/* + * Helpers for the main 'loop' + * (see fix_negative for the motivation of C) + */ +#define INIT( b ) \ + int ret; \ + signed char c = 0, cc; \ + uint32_t cur; \ + size_t i = 0, bits = b; \ + mbedtls_mpi C; \ + mbedtls_mpi_uint Cp[ b / 8 / sizeof( mbedtls_mpi_uint) + 1 ]; \ + \ + C.s = 1; \ + C.n = b / 8 / sizeof( mbedtls_mpi_uint) + 1; \ + C.p = Cp; \ + memset( Cp, 0, C.n * sizeof( mbedtls_mpi_uint ) ); \ + \ + MBEDTLS_MPI_CHK( mbedtls_mpi_grow( N, b * 2 / 8 / sizeof( mbedtls_mpi_uint ) ) ); \ + LOAD32; + +#define NEXT \ + STORE32; i++; LOAD32; \ + cc = c; c = 0; \ + if( cc < 0 ) \ + sub32( &cur, -cc, &c ); \ + else \ + add32( &cur, cc, &c ); \ + +#define LAST \ + STORE32; i++; \ + cur = c > 0 ? c : 0; STORE32; \ + cur = 0; while( ++i < MAX32 ) { STORE32; } \ + if( c < 0 ) fix_negative( N, c, &C, bits ); + +/* + * If the result is negative, we get it in the form + * c * 2^(bits + 32) + N, with c negative and N positive shorter than 'bits' + */ +static inline int fix_negative( mbedtls_mpi *N, signed char c, mbedtls_mpi *C, size_t bits ) +{ + int ret; + + /* C = - c * 2^(bits + 32) */ +#if !defined(MBEDTLS_HAVE_INT64) + ((void) bits); +#else + if( bits == 224 ) + C->p[ C->n - 1 ] = ((mbedtls_mpi_uint) -c) << 32; + else +#endif + C->p[ C->n - 1 ] = (mbedtls_mpi_uint) -c; + + /* N = - ( C - N ) */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( N, C, N ) ); + N->s = -1; + +cleanup: + + return( ret ); +} + +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) +/* + * Fast quasi-reduction modulo p224 (FIPS 186-3 D.2.2) + */ +static int ecp_mod_p224( mbedtls_mpi *N ) +{ + INIT( 224 ); + + SUB( 7 ); SUB( 11 ); NEXT; // A0 += -A7 - A11 + SUB( 8 ); SUB( 12 ); NEXT; // A1 += -A8 - A12 + SUB( 9 ); SUB( 13 ); NEXT; // A2 += -A9 - A13 + SUB( 10 ); ADD( 7 ); ADD( 11 ); NEXT; // A3 += -A10 + A7 + A11 + SUB( 11 ); ADD( 8 ); ADD( 12 ); NEXT; // A4 += -A11 + A8 + A12 + SUB( 12 ); ADD( 9 ); ADD( 13 ); NEXT; // A5 += -A12 + A9 + A13 + SUB( 13 ); ADD( 10 ); LAST; // A6 += -A13 + A10 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) +/* + * Fast quasi-reduction modulo p256 (FIPS 186-3 D.2.3) + */ +static int ecp_mod_p256( mbedtls_mpi *N ) +{ + INIT( 256 ); + + ADD( 8 ); ADD( 9 ); + SUB( 11 ); SUB( 12 ); SUB( 13 ); SUB( 14 ); NEXT; // A0 + + ADD( 9 ); ADD( 10 ); + SUB( 12 ); SUB( 13 ); SUB( 14 ); SUB( 15 ); NEXT; // A1 + + ADD( 10 ); ADD( 11 ); + SUB( 13 ); SUB( 14 ); SUB( 15 ); NEXT; // A2 + + ADD( 11 ); ADD( 11 ); ADD( 12 ); ADD( 12 ); ADD( 13 ); + SUB( 15 ); SUB( 8 ); SUB( 9 ); NEXT; // A3 + + ADD( 12 ); ADD( 12 ); ADD( 13 ); ADD( 13 ); ADD( 14 ); + SUB( 9 ); SUB( 10 ); NEXT; // A4 + + ADD( 13 ); ADD( 13 ); ADD( 14 ); ADD( 14 ); ADD( 15 ); + SUB( 10 ); SUB( 11 ); NEXT; // A5 + + ADD( 14 ); ADD( 14 ); ADD( 15 ); ADD( 15 ); ADD( 14 ); ADD( 13 ); + SUB( 8 ); SUB( 9 ); NEXT; // A6 + + ADD( 15 ); ADD( 15 ); ADD( 15 ); ADD( 8 ); + SUB( 10 ); SUB( 11 ); SUB( 12 ); SUB( 13 ); LAST; // A7 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) +/* + * Fast quasi-reduction modulo p384 (FIPS 186-3 D.2.4) + */ +static int ecp_mod_p384( mbedtls_mpi *N ) +{ + INIT( 384 ); + + ADD( 12 ); ADD( 21 ); ADD( 20 ); + SUB( 23 ); NEXT; // A0 + + ADD( 13 ); ADD( 22 ); ADD( 23 ); + SUB( 12 ); SUB( 20 ); NEXT; // A2 + + ADD( 14 ); ADD( 23 ); + SUB( 13 ); SUB( 21 ); NEXT; // A2 + + ADD( 15 ); ADD( 12 ); ADD( 20 ); ADD( 21 ); + SUB( 14 ); SUB( 22 ); SUB( 23 ); NEXT; // A3 + + ADD( 21 ); ADD( 21 ); ADD( 16 ); ADD( 13 ); ADD( 12 ); ADD( 20 ); ADD( 22 ); + SUB( 15 ); SUB( 23 ); SUB( 23 ); NEXT; // A4 + + ADD( 22 ); ADD( 22 ); ADD( 17 ); ADD( 14 ); ADD( 13 ); ADD( 21 ); ADD( 23 ); + SUB( 16 ); NEXT; // A5 + + ADD( 23 ); ADD( 23 ); ADD( 18 ); ADD( 15 ); ADD( 14 ); ADD( 22 ); + SUB( 17 ); NEXT; // A6 + + ADD( 19 ); ADD( 16 ); ADD( 15 ); ADD( 23 ); + SUB( 18 ); NEXT; // A7 + + ADD( 20 ); ADD( 17 ); ADD( 16 ); + SUB( 19 ); NEXT; // A8 + + ADD( 21 ); ADD( 18 ); ADD( 17 ); + SUB( 20 ); NEXT; // A9 + + ADD( 22 ); ADD( 19 ); ADD( 18 ); + SUB( 21 ); NEXT; // A10 + + ADD( 23 ); ADD( 20 ); ADD( 19 ); + SUB( 22 ); LAST; // A11 + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#undef A +#undef LOAD32 +#undef STORE32 +#undef MAX32 +#undef INIT +#undef NEXT +#undef LAST + +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED || + MBEDTLS_ECP_DP_SECP256R1_ENABLED || + MBEDTLS_ECP_DP_SECP384R1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) +/* + * Here we have an actual Mersenne prime, so things are more straightforward. + * However, chunks are aligned on a 'weird' boundary (521 bits). + */ + +/* Size of p521 in terms of mbedtls_mpi_uint */ +#define P521_WIDTH ( 521 / 8 / sizeof( mbedtls_mpi_uint ) + 1 ) + +/* Bits to keep in the most significant mbedtls_mpi_uint */ +#define P521_MASK 0x01FF + +/* + * Fast quasi-reduction modulo p521 (FIPS 186-3 D.2.5) + * Write N as A1 + 2^521 A0, return A0 + A1 + */ +static int ecp_mod_p521( mbedtls_mpi *N ) +{ + int ret; + size_t i; + mbedtls_mpi M; + mbedtls_mpi_uint Mp[P521_WIDTH + 1]; + /* Worst case for the size of M is when mbedtls_mpi_uint is 16 bits: + * we need to hold bits 513 to 1056, which is 34 limbs, that is + * P521_WIDTH + 1. Otherwise P521_WIDTH is enough. */ + + if( N->n < P521_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P521_WIDTH - 1 ); + if( M.n > P521_WIDTH + 1 ) + M.n = P521_WIDTH + 1; + M.p = Mp; + memcpy( Mp, N->p + P521_WIDTH - 1, M.n * sizeof( mbedtls_mpi_uint ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, 521 % ( 8 * sizeof( mbedtls_mpi_uint ) ) ) ); + + /* N = A0 */ + N->p[P521_WIDTH - 1] &= P521_MASK; + for( i = P521_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} + +#undef P521_WIDTH +#undef P521_MASK +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ + +#endif /* MBEDTLS_ECP_NIST_OPTIM */ + +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + +/* Size of p255 in terms of mbedtls_mpi_uint */ +#define P255_WIDTH ( 255 / 8 / sizeof( mbedtls_mpi_uint ) + 1 ) + +/* + * Fast quasi-reduction modulo p255 = 2^255 - 19 + * Write N as A0 + 2^255 A1, return A0 + 19 * A1 + */ +static int ecp_mod_p255( mbedtls_mpi *N ) +{ + int ret; + size_t i; + mbedtls_mpi M; + mbedtls_mpi_uint Mp[P255_WIDTH + 2]; + + if( N->n < P255_WIDTH ) + return( 0 ); + + /* M = A1 */ + M.s = 1; + M.n = N->n - ( P255_WIDTH - 1 ); + if( M.n > P255_WIDTH + 1 ) + M.n = P255_WIDTH + 1; + M.p = Mp; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + P255_WIDTH - 1, M.n * sizeof( mbedtls_mpi_uint ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, 255 % ( 8 * sizeof( mbedtls_mpi_uint ) ) ) ); + M.n++; /* Make room for multiplication by 19 */ + + /* N = A0 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( N, 255, 0 ) ); + for( i = P255_WIDTH; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + 19 * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M, &M, 19 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) || \ + defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* + * Fast quasi-reduction modulo P = 2^s - R, + * with R about 33 bits, used by the Koblitz curves. + * + * Write N as A0 + 2^224 A1, return A0 + R * A1. + * Actually do two passes, since R is big. + */ +#define P_KOBLITZ_MAX ( 256 / 8 / sizeof( mbedtls_mpi_uint ) ) // Max limbs in P +#define P_KOBLITZ_R ( 8 / sizeof( mbedtls_mpi_uint ) ) // Limbs in R +static inline int ecp_mod_koblitz( mbedtls_mpi *N, mbedtls_mpi_uint *Rp, size_t p_limbs, + size_t adjust, size_t shift, mbedtls_mpi_uint mask ) +{ + int ret; + size_t i; + mbedtls_mpi M, R; + mbedtls_mpi_uint Mp[P_KOBLITZ_MAX + P_KOBLITZ_R + 1]; + + if( N->n < p_limbs ) + return( 0 ); + + /* Init R */ + R.s = 1; + R.p = Rp; + R.n = P_KOBLITZ_R; + + /* Common setup for M */ + M.s = 1; + M.p = Mp; + + /* M = A1 */ + M.n = N->n - ( p_limbs - adjust ); + if( M.n > p_limbs + adjust ) + M.n = p_limbs + adjust; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + p_limbs - adjust, M.n * sizeof( mbedtls_mpi_uint ) ); + if( shift != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, shift ) ); + M.n += R.n; /* Make room for multiplication by R */ + + /* N = A0 */ + if( mask != 0 ) + N->p[p_limbs - 1] &= mask; + for( i = p_limbs; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + R * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &M, &M, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + + /* Second pass */ + + /* M = A1 */ + M.n = N->n - ( p_limbs - adjust ); + if( M.n > p_limbs + adjust ) + M.n = p_limbs + adjust; + memset( Mp, 0, sizeof Mp ); + memcpy( Mp, N->p + p_limbs - adjust, M.n * sizeof( mbedtls_mpi_uint ) ); + if( shift != 0 ) + MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &M, shift ) ); + M.n += R.n; /* Make room for multiplication by R */ + + /* N = A0 */ + if( mask != 0 ) + N->p[p_limbs - 1] &= mask; + for( i = p_limbs; i < N->n; i++ ) + N->p[i] = 0; + + /* N = A0 + R * A1 */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &M, &M, &R ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_abs( N, N, &M ) ); + +cleanup: + return( ret ); +} +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED) || + MBEDTLS_ECP_DP_SECP224K1_ENABLED) || + MBEDTLS_ECP_DP_SECP256K1_ENABLED) */ + +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) +/* + * Fast quasi-reduction modulo p192k1 = 2^192 - R, + * with R = 2^32 + 2^12 + 2^8 + 2^7 + 2^6 + 2^3 + 1 = 0x0100001119 + */ +static int ecp_mod_p192k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0xC9, 0x11, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + + return( ecp_mod_koblitz( N, Rp, 192 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +} +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) +/* + * Fast quasi-reduction modulo p224k1 = 2^224 - R, + * with R = 2^32 + 2^12 + 2^11 + 2^9 + 2^7 + 2^4 + 2 + 1 = 0x0100001A93 + */ +static int ecp_mod_p224k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0x93, 0x1A, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + +#if defined(MBEDTLS_HAVE_INT64) + return( ecp_mod_koblitz( N, Rp, 4, 1, 32, 0xFFFFFFFF ) ); +#else + return( ecp_mod_koblitz( N, Rp, 224 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +#endif +} + +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ + +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) +/* + * Fast quasi-reduction modulo p256k1 = 2^256 - R, + * with R = 2^32 + 2^9 + 2^8 + 2^7 + 2^6 + 2^4 + 1 = 0x01000003D1 + */ +static int ecp_mod_p256k1( mbedtls_mpi *N ) +{ + static mbedtls_mpi_uint Rp[] = { + BYTES_TO_T_UINT_8( 0xD1, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 ) }; + return( ecp_mod_koblitz( N, Rp, 256 / 8 / sizeof( mbedtls_mpi_uint ), 0, 0, 0 ) ); +} +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ + +#endif /* MBEDTLS_ECP_C */ diff --git a/c++/src/connect/mbedtls/entropy.c b/c++/src/connect/mbedtls/entropy.c new file mode 100644 index 00000000..d4d1b27b --- /dev/null +++ b/c++/src/connect/mbedtls/entropy.c @@ -0,0 +1,655 @@ +/* + * Entropy accumulator implementation + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ENTROPY_C) + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) +#warning "**** WARNING! MBEDTLS_TEST_NULL_ENTROPY defined! " +#warning "**** THIS BUILD HAS NO DEFINED ENTROPY SOURCES " +#warning "**** THIS BUILD IS *NOT* SUITABLE FOR PRODUCTION USE " +#endif + +#include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#include "mbedtls/platform.h" +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if defined(MBEDTLS_HAVEGE_C) +#include "mbedtls/havege.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#define ENTROPY_MAX_LOOP 256 /**< Maximum amount to loop before error */ + +void mbedtls_entropy_init( mbedtls_entropy_context *ctx ) +{ + memset( ctx, 0, sizeof(mbedtls_entropy_context) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_starts( &ctx->accumulator, 0 ); +#else + mbedtls_sha256_starts( &ctx->accumulator, 0 ); +#endif +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_init( &ctx->havege_data ); +#endif + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) + mbedtls_entropy_add_source( ctx, mbedtls_null_entropy_poll, NULL, + 1, MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif + +#if !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) + mbedtls_entropy_add_source( ctx, mbedtls_platform_entropy_poll, NULL, + MBEDTLS_ENTROPY_MIN_PLATFORM, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_TIMING_C) + mbedtls_entropy_add_source( ctx, mbedtls_hardclock_poll, NULL, + MBEDTLS_ENTROPY_MIN_HARDCLOCK, + MBEDTLS_ENTROPY_SOURCE_WEAK ); +#endif +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_entropy_add_source( ctx, mbedtls_havege_poll, &ctx->havege_data, + MBEDTLS_ENTROPY_MIN_HAVEGE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + mbedtls_entropy_add_source( ctx, mbedtls_hardware_poll, NULL, + MBEDTLS_ENTROPY_MIN_HARDWARE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) + mbedtls_entropy_add_source( ctx, mbedtls_nv_seed_poll, NULL, + MBEDTLS_ENTROPY_BLOCK_SIZE, + MBEDTLS_ENTROPY_SOURCE_STRONG ); +#endif +#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */ +} + +void mbedtls_entropy_free( mbedtls_entropy_context *ctx ) +{ +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_free( &ctx->havege_data ); +#endif +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + mbedtls_zeroize( ctx, sizeof( mbedtls_entropy_context ) ); +} + +int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx, + mbedtls_entropy_f_source_ptr f_source, void *p_source, + size_t threshold, int strong ) +{ + int index, ret = 0; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + index = ctx->source_count; + if( index >= MBEDTLS_ENTROPY_MAX_SOURCES ) + { + ret = MBEDTLS_ERR_ENTROPY_MAX_SOURCES; + goto exit; + } + + ctx->source[index].f_source = f_source; + ctx->source[index].p_source = p_source; + ctx->source[index].threshold = threshold; + ctx->source[index].strong = strong; + + ctx->source_count++; + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Entropy accumulator update + */ +static int entropy_update( mbedtls_entropy_context *ctx, unsigned char source_id, + const unsigned char *data, size_t len ) +{ + unsigned char header[2]; + unsigned char tmp[MBEDTLS_ENTROPY_BLOCK_SIZE]; + size_t use_len = len; + const unsigned char *p = data; + + if( use_len > MBEDTLS_ENTROPY_BLOCK_SIZE ) + { +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512( data, len, tmp, 0 ); +#else + mbedtls_sha256( data, len, tmp, 0 ); +#endif + p = tmp; + use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; + } + + header[0] = source_id; + header[1] = use_len & 0xFF; + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_update( &ctx->accumulator, header, 2 ); + mbedtls_sha512_update( &ctx->accumulator, p, use_len ); +#else + mbedtls_sha256_update( &ctx->accumulator, header, 2 ); + mbedtls_sha256_update( &ctx->accumulator, p, use_len ); +#endif + + return( 0 ); +} + +int mbedtls_entropy_update_manual( mbedtls_entropy_context *ctx, + const unsigned char *data, size_t len ) +{ + int ret; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = entropy_update( ctx, MBEDTLS_ENTROPY_SOURCE_MANUAL, data, len ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Run through the different sources to add entropy to our accumulator + */ +static int entropy_gather_internal( mbedtls_entropy_context *ctx ) +{ + int ret, i, have_one_strong = 0; + unsigned char buf[MBEDTLS_ENTROPY_MAX_GATHER]; + size_t olen; + + if( ctx->source_count == 0 ) + return( MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED ); + + /* + * Run through our entropy sources + */ + for( i = 0; i < ctx->source_count; i++ ) + { + if( ctx->source[i].strong == MBEDTLS_ENTROPY_SOURCE_STRONG ) + have_one_strong = 1; + + olen = 0; + if( ( ret = ctx->source[i].f_source( ctx->source[i].p_source, + buf, MBEDTLS_ENTROPY_MAX_GATHER, &olen ) ) != 0 ) + { + return( ret ); + } + + /* + * Add if we actually gathered something + */ + if( olen > 0 ) + { + entropy_update( ctx, (unsigned char) i, buf, olen ); + ctx->source[i].size += olen; + } + } + + if( have_one_strong == 0 ) + return( MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE ); + + return( 0 ); +} + +/* + * Thread-safe wrapper for entropy_gather_internal() + */ +int mbedtls_entropy_gather( mbedtls_entropy_context *ctx ) +{ + int ret; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = entropy_gather_internal( ctx ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ) +{ + int ret, count = 0, i, done; + mbedtls_entropy_context *ctx = (mbedtls_entropy_context *) data; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + if( len > MBEDTLS_ENTROPY_BLOCK_SIZE ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + +#if defined(MBEDTLS_ENTROPY_NV_SEED) + /* Update the NV entropy seed before generating any entropy for outside + * use. + */ + if( ctx->initial_entropy_run == 0 ) + { + ctx->initial_entropy_run = 1; + if( ( ret = mbedtls_entropy_update_nv_seed( ctx ) ) != 0 ) + return( ret ); + } +#endif + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + /* + * Always gather extra entropy before a call + */ + do + { + if( count++ > ENTROPY_MAX_LOOP ) + { + ret = MBEDTLS_ERR_ENTROPY_SOURCE_FAILED; + goto exit; + } + + if( ( ret = entropy_gather_internal( ctx ) ) != 0 ) + goto exit; + + done = 1; + for( i = 0; i < ctx->source_count; i++ ) + if( ctx->source[i].size < ctx->source[i].threshold ) + done = 0; + } + while( ! done ); + + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_finish( &ctx->accumulator, buf ); + + /* + * Reset accumulator and counters and recycle existing entropy + */ + memset( &ctx->accumulator, 0, sizeof( mbedtls_sha512_context ) ); + mbedtls_sha512_starts( &ctx->accumulator, 0 ); + mbedtls_sha512_update( &ctx->accumulator, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + /* + * Perform second SHA-512 on entropy + */ + mbedtls_sha512( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf, 0 ); +#else /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */ + mbedtls_sha256_finish( &ctx->accumulator, buf ); + + /* + * Reset accumulator and counters and recycle existing entropy + */ + memset( &ctx->accumulator, 0, sizeof( mbedtls_sha256_context ) ); + mbedtls_sha256_starts( &ctx->accumulator, 0 ); + mbedtls_sha256_update( &ctx->accumulator, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + /* + * Perform second SHA-256 on entropy + */ + mbedtls_sha256( buf, MBEDTLS_ENTROPY_BLOCK_SIZE, buf, 0 ); +#endif /* MBEDTLS_ENTROPY_SHA512_ACCUMULATOR */ + + for( i = 0; i < ctx->source_count; i++ ) + ctx->source[i].size = 0; + + memcpy( output, buf, len ); + + ret = 0; + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +int mbedtls_entropy_update_nv_seed( mbedtls_entropy_context *ctx ) +{ + int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + unsigned char buf[ MBEDTLS_ENTROPY_MAX_SEED_SIZE ]; + + /* Read new seed and write it to NV */ + if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) + return( ret ); + + if( mbedtls_nv_seed_write( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) < 0 ) + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + + /* Manually update the remaining stream with a separator value to diverge */ + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + mbedtls_entropy_update_manual( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + return( 0 ); +} +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if defined(MBEDTLS_FS_IO) +int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path ) +{ + int ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + FILE *f; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + + if( ( ret = mbedtls_entropy_func( ctx, buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, MBEDTLS_ENTROPY_BLOCK_SIZE, f ) != MBEDTLS_ENTROPY_BLOCK_SIZE ) + { + ret = MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + fclose( f ); + return( ret ); +} + +int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path ) +{ + FILE *f; + size_t n; + unsigned char buf[ MBEDTLS_ENTROPY_MAX_SEED_SIZE ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > MBEDTLS_ENTROPY_MAX_SEED_SIZE ) + n = MBEDTLS_ENTROPY_MAX_SEED_SIZE; + + if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR ); + } + + fclose( f ); + + mbedtls_entropy_update_manual( ctx, buf, n ); + + return( mbedtls_entropy_write_seed_file( ctx, path ) ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) +#if !defined(MBEDTLS_TEST_NULL_ENTROPY) +/* + * Dummy source function + */ +static int entropy_dummy_source( void *data, unsigned char *output, + size_t len, size_t *olen ) +{ + ((void) data); + + memset( output, 0x2a, len ); + *olen = len; + + return( 0 ); +} +#endif /* !MBEDTLS_TEST_NULL_ENTROPY */ + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + +static int mbedtls_entropy_source_self_test_gather( unsigned char *buf, size_t buf_len ) +{ + int ret = 0; + size_t entropy_len = 0; + size_t olen = 0; + size_t attempts = buf_len; + + while( attempts > 0 && entropy_len < buf_len ) + { + if( ( ret = mbedtls_hardware_poll( NULL, buf + entropy_len, + buf_len - entropy_len, &olen ) ) != 0 ) + return( ret ); + + entropy_len += olen; + attempts--; + } + + if( entropy_len < buf_len ) + { + ret = 1; + } + + return( ret ); +} + + +static int mbedtls_entropy_source_self_test_check_bits( const unsigned char *buf, + size_t buf_len ) +{ + unsigned char set= 0xFF; + unsigned char unset = 0x00; + size_t i; + + for( i = 0; i < buf_len; i++ ) + { + set &= buf[i]; + unset |= buf[i]; + } + + return( set == 0xFF || unset == 0x00 ); +} + +/* + * A test to ensure hat the entropy sources are functioning correctly + * and there is no obvious failure. The test performs the following checks: + * - The entropy source is not providing only 0s (all bits unset) or 1s (all + * bits set). + * - The entropy source is not providing values in a pattern. Because the + * hardware could be providing data in an arbitrary length, this check polls + * the hardware entropy source twice and compares the result to ensure they + * are not equal. + * - The error code returned by the entropy source is not an error. + */ +int mbedtls_entropy_source_self_test( int verbose ) +{ + int ret = 0; + unsigned char buf0[2 * sizeof( unsigned long long int )]; + unsigned char buf1[2 * sizeof( unsigned long long int )]; + + if( verbose != 0 ) + mbedtls_printf( " ENTROPY_BIAS test: " ); + + memset( buf0, 0x00, sizeof( buf0 ) ); + memset( buf1, 0x00, sizeof( buf1 ) ); + + if( ( ret = mbedtls_entropy_source_self_test_gather( buf0, sizeof( buf0 ) ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_entropy_source_self_test_gather( buf1, sizeof( buf1 ) ) ) != 0 ) + goto cleanup; + + /* Make sure that the returned values are not all 0 or 1 */ + if( ( ret = mbedtls_entropy_source_self_test_check_bits( buf0, sizeof( buf0 ) ) ) != 0 ) + goto cleanup; + if( ( ret = mbedtls_entropy_source_self_test_check_bits( buf1, sizeof( buf1 ) ) ) != 0 ) + goto cleanup; + + /* Make sure that the entropy source is not returning values in a + * pattern */ + ret = memcmp( buf0, buf1, sizeof( buf0 ) ) == 0; + +cleanup: + if( verbose != 0 ) + { + if( ret != 0 ) + mbedtls_printf( "failed\n" ); + else + mbedtls_printf( "passed\n" ); + + mbedtls_printf( "\n" ); + } + + return( ret != 0 ); +} + +#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ + +/* + * The actual entropy quality is hard to test, but we can at least + * test that the functions don't cause errors and write the correct + * amount of data to buffers. + */ +int mbedtls_entropy_self_test( int verbose ) +{ + int ret = 1; +#if !defined(MBEDTLS_TEST_NULL_ENTROPY) + mbedtls_entropy_context ctx; + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; + unsigned char acc[MBEDTLS_ENTROPY_BLOCK_SIZE] = { 0 }; + size_t i, j; +#endif /* !MBEDTLS_TEST_NULL_ENTROPY */ + + if( verbose != 0 ) + mbedtls_printf( " ENTROPY test: " ); + +#if !defined(MBEDTLS_TEST_NULL_ENTROPY) + mbedtls_entropy_init( &ctx ); + + /* First do a gather to make sure we have default sources */ + if( ( ret = mbedtls_entropy_gather( &ctx ) ) != 0 ) + goto cleanup; + + ret = mbedtls_entropy_add_source( &ctx, entropy_dummy_source, NULL, 16, + MBEDTLS_ENTROPY_SOURCE_WEAK ); + if( ret != 0 ) + goto cleanup; + + if( ( ret = mbedtls_entropy_update_manual( &ctx, buf, sizeof buf ) ) != 0 ) + goto cleanup; + + /* + * To test that mbedtls_entropy_func writes correct number of bytes: + * - use the whole buffer and rely on ASan to detect overruns + * - collect entropy 8 times and OR the result in an accumulator: + * any byte should then be 0 with probably 2^(-64), so requiring + * each of the 32 or 64 bytes to be non-zero has a false failure rate + * of at most 2^(-58) which is acceptable. + */ + for( i = 0; i < 8; i++ ) + { + if( ( ret = mbedtls_entropy_func( &ctx, buf, sizeof( buf ) ) ) != 0 ) + goto cleanup; + + for( j = 0; j < sizeof( buf ); j++ ) + acc[j] |= buf[j]; + } + + for( j = 0; j < sizeof( buf ); j++ ) + { + if( acc[j] == 0 ) + { + ret = 1; + goto cleanup; + } + } + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + if( ( ret = mbedtls_entropy_source_self_test( 0 ) ) != 0 ) + goto cleanup; +#endif + +cleanup: + mbedtls_entropy_free( &ctx ); +#endif /* !MBEDTLS_TEST_NULL_ENTROPY */ + + if( verbose != 0 ) + { + if( ret != 0 ) + mbedtls_printf( "failed\n" ); + else + mbedtls_printf( "passed\n" ); + + mbedtls_printf( "\n" ); + } + + return( ret != 0 ); +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_ENTROPY_C */ diff --git a/c++/src/connect/mbedtls/entropy_poll.c b/c++/src/connect/mbedtls/entropy_poll.c new file mode 100644 index 00000000..a116e605 --- /dev/null +++ b/c++/src/connect/mbedtls/entropy_poll.c @@ -0,0 +1,268 @@ +/* + * Platform-specific and custom entropy polling functions + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ENTROPY_C) + +#include "mbedtls/entropy.h" +#include "mbedtls/entropy_poll.h" + +#if defined(MBEDTLS_TIMING_C) +#include +#include "mbedtls/timing.h" +#endif +#if defined(MBEDTLS_HAVEGE_C) +#include "mbedtls/havege.h" +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#include "mbedtls/platform.h" +#endif + +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) + +#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ + !defined(__APPLE__) && !defined(_WIN32) +#error "Platform entropy sources only work on Unix and Windows, see MBEDTLS_NO_PLATFORM_ENTROPY in config.h" +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +#if !defined(_WIN32_WINNT) +#define _WIN32_WINNT 0x0400 +#endif +#include +#include + +int mbedtls_platform_entropy_poll( void *data, unsigned char *output, size_t len, + size_t *olen ) +{ + HCRYPTPROV provider; + ((void) data); + *olen = 0; + + if( CryptAcquireContext( &provider, NULL, NULL, + PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) == FALSE ) + { + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + } + + if( CryptGenRandom( provider, (DWORD) len, output ) == FALSE ) + { + CryptReleaseContext( provider, 0 ); + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + } + + CryptReleaseContext( provider, 0 ); + *olen = len; + + return( 0 ); +} +#else /* _WIN32 && !EFIX64 && !EFI32 */ + +/* + * Test for Linux getrandom() support. + * Since there is no wrapper in the libc yet, use the generic syscall wrapper + * available in GNU libc and compatible libc's (eg uClibc). + */ +#if defined(__linux__) && defined(__GLIBC__) +#include +#include +#if defined(SYS_getrandom) +#define HAVE_GETRANDOM + +static int getrandom_wrapper( void *buf, size_t buflen, unsigned int flags ) +{ + /* MemSan cannot understand that the syscall writes to the buffer */ +#if defined(__has_feature) +#if __has_feature(memory_sanitizer) + memset( buf, 0, buflen ); +#endif +#endif + + return( syscall( SYS_getrandom, buf, buflen, flags ) ); +} + +#include +/* Check if version is at least 3.17.0 */ +static int check_version_3_17_plus( void ) +{ + int minor; + struct utsname un; + const char *ver; + + /* Get version information */ + uname(&un); + ver = un.release; + + /* Check major version; assume a single digit */ + if( ver[0] < '3' || ver[0] > '9' || ver [1] != '.' ) + return( -1 ); + + if( ver[0] - '0' > 3 ) + return( 0 ); + + /* Ok, so now we know major == 3, check minor. + * Assume 1 or 2 digits. */ + if( ver[2] < '0' || ver[2] > '9' ) + return( -1 ); + + minor = ver[2] - '0'; + + if( ver[3] >= '0' && ver[3] <= '9' ) + minor = 10 * minor + ver[3] - '0'; + else if( ver [3] != '.' ) + return( -1 ); + + if( minor < 17 ) + return( -1 ); + + return( 0 ); +} +static int has_getrandom = -1; +#endif /* SYS_getrandom */ +#endif /* __linux__ */ + +#include + +int mbedtls_platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + FILE *file; + size_t read_len; + ((void) data); + +#if defined(HAVE_GETRANDOM) + if( has_getrandom == -1 ) + has_getrandom = ( check_version_3_17_plus() == 0 ); + + if( has_getrandom ) + { + int ret; + + if( ( ret = getrandom_wrapper( output, len, 0 ) ) < 0 ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + *olen = ret; + return( 0 ); + } +#endif /* HAVE_GETRANDOM */ + + *olen = 0; + + file = fopen( "/dev/urandom", "rb" ); + if( file == NULL ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + read_len = fread( output, 1, len, file ); + if( read_len != len ) + { + fclose( file ); + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + } + + fclose( file ); + *olen = len; + + return( 0 ); +} +#endif /* _WIN32 && !EFIX64 && !EFI32 */ +#endif /* !MBEDTLS_NO_PLATFORM_ENTROPY */ + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) +int mbedtls_null_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + ((void) data); + ((void) output); + *olen = 0; + + if( len < sizeof(unsigned char) ) + return( 0 ); + + *olen = sizeof(unsigned char); + + return( 0 ); +} +#endif + +#if defined(MBEDTLS_TIMING_C) +int mbedtls_hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + unsigned long timer = mbedtls_timing_hardclock(); + ((void) data); + *olen = 0; + + if( len < sizeof(unsigned long) ) + return( 0 ); + + memcpy( output, &timer, sizeof(unsigned long) ); + *olen = sizeof(unsigned long); + + return( 0 ); +} +#endif /* MBEDTLS_TIMING_C */ + +#if defined(MBEDTLS_HAVEGE_C) +int mbedtls_havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + mbedtls_havege_state *hs = (mbedtls_havege_state *) data; + *olen = 0; + + if( mbedtls_havege_random( hs, output, len ) != 0 ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + *olen = len; + + return( 0 ); +} +#endif /* MBEDTLS_HAVEGE_C */ + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +int mbedtls_nv_seed_poll( void *data, + unsigned char *output, size_t len, size_t *olen ) +{ + unsigned char buf[MBEDTLS_ENTROPY_BLOCK_SIZE]; + size_t use_len = MBEDTLS_ENTROPY_BLOCK_SIZE; + ((void) data); + + memset( buf, 0, MBEDTLS_ENTROPY_BLOCK_SIZE ); + + if( mbedtls_nv_seed_read( buf, MBEDTLS_ENTROPY_BLOCK_SIZE ) < 0 ) + return( MBEDTLS_ERR_ENTROPY_SOURCE_FAILED ); + + if( len < use_len ) + use_len = len; + + memcpy( output, buf, use_len ); + *olen = use_len; + + return( 0 ); +} +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#endif /* MBEDTLS_ENTROPY_C */ diff --git a/c++/src/connect/mbedtls/error.c b/c++/src/connect/mbedtls/error.c new file mode 100644 index 00000000..dd2db0c4 --- /dev/null +++ b/c++/src/connect/mbedtls/error.c @@ -0,0 +1,707 @@ +/* + * Error message information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_ERROR_C) || defined(MBEDTLS_ERROR_STRERROR_DUMMY) +#include "mbedtls/error.h" +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_snprintf snprintf +#define mbedtls_time_t time_t +#endif + +#if defined(MBEDTLS_ERROR_C) + +#include + +#if defined(MBEDTLS_AES_C) +#include "mbedtls/aes.h" +#endif + +#if defined(MBEDTLS_BASE64_C) +#include "mbedtls/base64.h" +#endif + +#if defined(MBEDTLS_BIGNUM_C) +#include "mbedtls/bignum.h" +#endif + +#if defined(MBEDTLS_BLOWFISH_C) +#include "mbedtls/blowfish.h" +#endif + +#if defined(MBEDTLS_CAMELLIA_C) +#include "mbedtls/camellia.h" +#endif + +#if defined(MBEDTLS_CCM_C) +#include "mbedtls/ccm.h" +#endif + +#if defined(MBEDTLS_CIPHER_C) +#include "mbedtls/cipher.h" +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) +#include "mbedtls/ctr_drbg.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +#if defined(MBEDTLS_DHM_C) +#include "mbedtls/dhm.h" +#endif + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif + +#if defined(MBEDTLS_ENTROPY_C) +#include "mbedtls/entropy.h" +#endif + +#if defined(MBEDTLS_GCM_C) +#include "mbedtls/gcm.h" +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) +#include "mbedtls/hmac_drbg.h" +#endif + +#if defined(MBEDTLS_MD_C) +#include "mbedtls/md.h" +#endif + +#if defined(MBEDTLS_NET_C) +#include "mbedtls/net_sockets.h" +#endif + +#if defined(MBEDTLS_OID_C) +#include "mbedtls/oid.h" +#endif + +#if defined(MBEDTLS_PADLOCK_C) +#include "mbedtls/padlock.h" +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk.h" +#endif + +#if defined(MBEDTLS_PKCS12_C) +#include "mbedtls/pkcs12.h" +#endif + +#if defined(MBEDTLS_PKCS5_C) +#include "mbedtls/pkcs5.h" +#endif + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) +#include "mbedtls/ssl.h" +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "mbedtls/x509.h" +#endif + +#if defined(MBEDTLS_XTEA_C) +#include "mbedtls/xtea.h" +#endif + + +void mbedtls_strerror( int ret, char *buf, size_t buflen ) +{ + size_t len; + int use_ret; + + if( buflen == 0 ) + return; + + memset( buf, 0x00, buflen ); + + if( ret < 0 ) + ret = -ret; + + if( ret & 0xFF80 ) + { + use_ret = ret & 0xFF80; + + // High level error codes + // + // BEGIN generated code +#if defined(MBEDTLS_CIPHER_C) + if( use_ret == -(MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "CIPHER - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_INVALID_PADDING) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Input data contains invalid padding and is rejected" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Decryption of block requires a full block" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CIPHER - Authentication failed (for AEAD modes)" ); + if( use_ret == -(MBEDTLS_ERR_CIPHER_INVALID_CONTEXT) ) + mbedtls_snprintf( buf, buflen, "CIPHER - The context is invalid, eg because it was free()ed" ); +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_DHM_C) + if( use_ret == -(MBEDTLS_ERR_DHM_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "DHM - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_DHM_READ_PARAMS_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Reading of the DHM parameters failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Making of the DHM parameters failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Reading of the public values failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Making of the public value failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_CALC_SECRET_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Calculation of the DHM secret failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "DHM - The ASN.1 data is not formatted correctly" ); + if( use_ret == -(MBEDTLS_ERR_DHM_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "DHM - Allocation of memory failed" ); + if( use_ret == -(MBEDTLS_ERR_DHM_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "DHM - Read/write of file failed" ); +#endif /* MBEDTLS_DHM_C */ + +#if defined(MBEDTLS_ECP_C) + if( use_ret == -(MBEDTLS_ERR_ECP_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "ECP - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "ECP - The buffer is too small to write to" ); + if( use_ret == -(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "ECP - Requested curve not available" ); + if( use_ret == -(MBEDTLS_ERR_ECP_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - The signature is not valid" ); + if( use_ret == -(MBEDTLS_ERR_ECP_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_ECP_RANDOM_FAILED) ) + mbedtls_snprintf( buf, buflen, "ECP - Generation of random value, such as (ephemeral) key, failed" ); + if( use_ret == -(MBEDTLS_ERR_ECP_INVALID_KEY) ) + mbedtls_snprintf( buf, buflen, "ECP - Invalid private or public key" ); + if( use_ret == -(MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "ECP - Signature is valid but shorter than the user-supplied length" ); +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_MD_C) + if( use_ret == -(MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "MD - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_MD_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "MD - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_MD_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "MD - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_MD_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "MD - Opening or reading of file failed" ); +#endif /* MBEDTLS_MD_C */ + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) + if( use_ret == -(MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT) ) + mbedtls_snprintf( buf, buflen, "PEM - No PEM header or footer found" ); + if( use_ret == -(MBEDTLS_ERR_PEM_INVALID_DATA) ) + mbedtls_snprintf( buf, buflen, "PEM - PEM string is not as expected" ); + if( use_ret == -(MBEDTLS_ERR_PEM_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "PEM - Failed to allocate memory" ); + if( use_ret == -(MBEDTLS_ERR_PEM_INVALID_ENC_IV) ) + mbedtls_snprintf( buf, buflen, "PEM - RSA IV is not in hex-format" ); + if( use_ret == -(MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG) ) + mbedtls_snprintf( buf, buflen, "PEM - Unsupported key encryption algorithm" ); + if( use_ret == -(MBEDTLS_ERR_PEM_PASSWORD_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "PEM - Private key password can't be empty" ); + if( use_ret == -(MBEDTLS_ERR_PEM_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PEM - Given private key password does not allow for correct decryption" ); + if( use_ret == -(MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PEM - Unavailable feature, e.g. hashing/encryption combination" ); + if( use_ret == -(MBEDTLS_ERR_PEM_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PEM - Bad input parameters to function" ); +#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ + +#if defined(MBEDTLS_PK_C) + if( use_ret == -(MBEDTLS_ERR_PK_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "PK - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_PK_TYPE_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - Type mismatch, eg attempt to encrypt with an ECDSA key" ); + if( use_ret == -(MBEDTLS_ERR_PK_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PK - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PK_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "PK - Read/write of file failed" ); + if( use_ret == -(MBEDTLS_ERR_PK_KEY_INVALID_VERSION) ) + mbedtls_snprintf( buf, buflen, "PK - Unsupported key version" ); + if( use_ret == -(MBEDTLS_ERR_PK_KEY_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PK - Invalid key tag or value" ); + if( use_ret == -(MBEDTLS_ERR_PK_UNKNOWN_PK_ALG) ) + mbedtls_snprintf( buf, buflen, "PK - Key algorithm is unsupported (only RSA and EC are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_PASSWORD_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "PK - Private key password can't be empty" ); + if( use_ret == -(MBEDTLS_ERR_PK_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - Given private key password does not allow for correct decryption" ); + if( use_ret == -(MBEDTLS_ERR_PK_INVALID_PUBKEY) ) + mbedtls_snprintf( buf, buflen, "PK - The pubkey tag or value is invalid (only RSA and EC are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_INVALID_ALG) ) + mbedtls_snprintf( buf, buflen, "PK - The algorithm tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE) ) + mbedtls_snprintf( buf, buflen, "PK - Elliptic curve is unsupported (only NIST curves are supported)" ); + if( use_ret == -(MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PK - Unavailable feature, e.g. RSA disabled for RSA key" ); + if( use_ret == -(MBEDTLS_ERR_PK_SIG_LEN_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PK - The signature is valid but its length is less than expected" ); +#endif /* MBEDTLS_PK_C */ + +#if defined(MBEDTLS_PKCS12_C) + if( use_ret == -(MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Feature not available, e.g. unsupported encryption scheme" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - PBE ASN.1 data not as expected" ); + if( use_ret == -(MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PKCS12 - Given private key password does not allow for correct decryption" ); +#endif /* MBEDTLS_PKCS12_C */ + +#if defined(MBEDTLS_PKCS5_C) + if( use_ret == -(MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Unexpected ASN.1 data" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Requested encryption or digest alg not available" ); + if( use_ret == -(MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "PKCS5 - Given private key password does not allow for correct decryption" ); +#endif /* MBEDTLS_PKCS5_C */ + +#if defined(MBEDTLS_RSA_C) + if( use_ret == -(MBEDTLS_ERR_RSA_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "RSA - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_RSA_INVALID_PADDING) ) + mbedtls_snprintf( buf, buflen, "RSA - Input data contains invalid padding and is rejected" ); + if( use_ret == -(MBEDTLS_ERR_RSA_KEY_GEN_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - Something failed during generation of a key" ); + if( use_ret == -(MBEDTLS_ERR_RSA_KEY_CHECK_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - Key failed to pass the library's validity check" ); + if( use_ret == -(MBEDTLS_ERR_RSA_PUBLIC_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The public key operation failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_PRIVATE_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The private key operation failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The PKCS#1 verification failed" ); + if( use_ret == -(MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE) ) + mbedtls_snprintf( buf, buflen, "RSA - The output buffer for decryption is not large enough" ); + if( use_ret == -(MBEDTLS_ERR_RSA_RNG_FAILED) ) + mbedtls_snprintf( buf, buflen, "RSA - The random generator failed to generate non-zeros" ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_SSL_TLS_C) + if( use_ret == -(MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "SSL - The requested feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "SSL - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_MAC) ) + mbedtls_snprintf( buf, buflen, "SSL - Verification of the message MAC failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_RECORD) ) + mbedtls_snprintf( buf, buflen, "SSL - An invalid SSL record was received" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CONN_EOF) ) + mbedtls_snprintf( buf, buflen, "SSL - The connection indicated an EOF" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNKNOWN_CIPHER) ) + mbedtls_snprintf( buf, buflen, "SSL - An unknown cipher was received" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN) ) + mbedtls_snprintf( buf, buflen, "SSL - The server has no ciphersuites in common with the client" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_RNG) ) + mbedtls_snprintf( buf, buflen, "SSL - No RNG was provided to the SSL module" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE) ) + mbedtls_snprintf( buf, buflen, "SSL - No client certification received from the client, but required by the authentication mode" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Our own certificate(s) is/are too large to send in an SSL message" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - The own certificate is not set, but needed by the server" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - The own private key or pre-shared key is not set, but needed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - No CA Chain is set, but required to operate" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE) ) + mbedtls_snprintf( buf, buflen, "SSL - An unexpected message was received from our peer" ); + if( use_ret == -(MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE) ) + { + mbedtls_snprintf( buf, buflen, "SSL - A fatal alert message was received from our peer" ); + return; + } + if( use_ret == -(MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Verification of our peer failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) ) + mbedtls_snprintf( buf, buflen, "SSL - The peer notified us that the connection is going to be closed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientHello handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerHello handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the Certificate handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the CertificateRequest handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerKeyExchange handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ServerHelloDone handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Calculate Secret" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the CertificateVerify handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the ChangeCipherSpec handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_FINISHED) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the Finished handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HW_ACCEL_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Hardware acceleration function returned with error" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH) ) + mbedtls_snprintf( buf, buflen, "SSL - Hardware acceleration function skipped / left alone data" ); + if( use_ret == -(MBEDTLS_ERR_SSL_COMPRESSION_FAILED) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the compression / decompression failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION) ) + mbedtls_snprintf( buf, buflen, "SSL - Handshake protocol not within min/max boundaries" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET) ) + mbedtls_snprintf( buf, buflen, "SSL - Processing of the NewSessionTicket handshake message failed" ); + if( use_ret == -(MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - Session ticket has expired" ); + if( use_ret == -(MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "SSL - Public key type mismatch (eg, asked for RSA key exchange and presented EC key)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY) ) + mbedtls_snprintf( buf, buflen, "SSL - Unknown identity received (eg, PSK identity)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INTERNAL_ERROR) ) + mbedtls_snprintf( buf, buflen, "SSL - Internal error (eg, unexpected failure in lower-level module)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_COUNTER_WRAPPING) ) + mbedtls_snprintf( buf, buflen, "SSL - A counter would wrap (eg, too many messages exchanged)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO) ) + mbedtls_snprintf( buf, buflen, "SSL - Unexpected message at ServerHello in renegotiation" ); + if( use_ret == -(MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) ) + mbedtls_snprintf( buf, buflen, "SSL - DTLS client must retry for hello verification" ); + if( use_ret == -(MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "SSL - A buffer is too small to receive or write a message" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE) ) + mbedtls_snprintf( buf, buflen, "SSL - None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages)" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WANT_READ) ) + mbedtls_snprintf( buf, buflen, "SSL - Connection requires a read call" ); + if( use_ret == -(MBEDTLS_ERR_SSL_WANT_WRITE) ) + mbedtls_snprintf( buf, buflen, "SSL - Connection requires a write call" ); + if( use_ret == -(MBEDTLS_ERR_SSL_TIMEOUT) ) + mbedtls_snprintf( buf, buflen, "SSL - The operation timed out" ); + if( use_ret == -(MBEDTLS_ERR_SSL_CLIENT_RECONNECT) ) + mbedtls_snprintf( buf, buflen, "SSL - The client initiated a reconnect from the same port" ); + if( use_ret == -(MBEDTLS_ERR_SSL_UNEXPECTED_RECORD) ) + mbedtls_snprintf( buf, buflen, "SSL - Record header looks valid but is not expected" ); + if( use_ret == -(MBEDTLS_ERR_SSL_NON_FATAL) ) + mbedtls_snprintf( buf, buflen, "SSL - The alert message received indicates a non-fatal error" ); + if( use_ret == -(MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH) ) + mbedtls_snprintf( buf, buflen, "SSL - Couldn't set the hash for verifying CertificateVerify" ); +#endif /* MBEDTLS_SSL_TLS_C */ + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) + if( use_ret == -(MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "X509 - Unavailable feature, e.g. RSA hashing/encryption combination" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_OID) ) + mbedtls_snprintf( buf, buflen, "X509 - Requested OID is unknown" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_FORMAT) ) + mbedtls_snprintf( buf, buflen, "X509 - The CRT/CRL/CSR format is invalid, e.g. different type expected" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_VERSION) ) + mbedtls_snprintf( buf, buflen, "X509 - The CRT/CRL/CSR version element is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_SERIAL) ) + mbedtls_snprintf( buf, buflen, "X509 - The serial tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_ALG) ) + mbedtls_snprintf( buf, buflen, "X509 - The algorithm tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_NAME) ) + mbedtls_snprintf( buf, buflen, "X509 - The name tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_DATE) ) + mbedtls_snprintf( buf, buflen, "X509 - The date tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_SIGNATURE) ) + mbedtls_snprintf( buf, buflen, "X509 - The signature tag or value invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_INVALID_EXTENSIONS) ) + mbedtls_snprintf( buf, buflen, "X509 - The extension tag or value is invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_VERSION) ) + mbedtls_snprintf( buf, buflen, "X509 - CRT/CRL/CSR has an unsupported version number" ); + if( use_ret == -(MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG) ) + mbedtls_snprintf( buf, buflen, "X509 - Signature algorithm (oid) is unsupported" ); + if( use_ret == -(MBEDTLS_ERR_X509_SIG_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "X509 - Signature algorithms do not match. (see \\c ::mbedtls_x509_crt sig_oid)" ); + if( use_ret == -(MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) ) + mbedtls_snprintf( buf, buflen, "X509 - Certificate verification failed, e.g. CRL, CA or signature check failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT) ) + mbedtls_snprintf( buf, buflen, "X509 - Format not recognized as DER or PEM" ); + if( use_ret == -(MBEDTLS_ERR_X509_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "X509 - Input invalid" ); + if( use_ret == -(MBEDTLS_ERR_X509_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "X509 - Allocation of memory failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "X509 - Read/write of file failed" ); + if( use_ret == -(MBEDTLS_ERR_X509_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "X509 - Destination buffer is too small" ); +#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ + // END generated code + + if( strlen( buf ) == 0 ) + mbedtls_snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret ); + } + + use_ret = ret & ~0xFF80; + + if( use_ret == 0 ) + return; + + // If high level code is present, make a concatenation between both + // error strings. + // + len = strlen( buf ); + + if( len > 0 ) + { + if( buflen - len < 5 ) + return; + + mbedtls_snprintf( buf + len, buflen - len, " : " ); + + buf += len + 3; + buflen -= len + 3; + } + + // Low level error codes + // + // BEGIN generated code +#if defined(MBEDTLS_AES_C) + if( use_ret == -(MBEDTLS_ERR_AES_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "AES - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "AES - Invalid data input length" ); +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_ASN1_PARSE_C) + if( use_ret == -(MBEDTLS_ERR_ASN1_OUT_OF_DATA) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Out of data when parsing an ASN1 data structure" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) ) + mbedtls_snprintf( buf, buflen, "ASN1 - ASN1 tag was of an unexpected value" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_INVALID_LENGTH) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Error when trying to determine the length or invalid length" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_LENGTH_MISMATCH) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Actual length differs from expected length" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_INVALID_DATA) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Data is invalid. (not used)" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Memory allocation failed" ); + if( use_ret == -(MBEDTLS_ERR_ASN1_BUF_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "ASN1 - Buffer too small when writing ASN.1 data structure" ); +#endif /* MBEDTLS_ASN1_PARSE_C */ + +#if defined(MBEDTLS_BASE64_C) + if( use_ret == -(MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "BASE64 - Output buffer too small" ); + if( use_ret == -(MBEDTLS_ERR_BASE64_INVALID_CHARACTER) ) + mbedtls_snprintf( buf, buflen, "BASE64 - Invalid character in input" ); +#endif /* MBEDTLS_BASE64_C */ + +#if defined(MBEDTLS_BIGNUM_C) + if( use_ret == -(MBEDTLS_ERR_MPI_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - An error occurred while reading from or writing to a file" ); + if( use_ret == -(MBEDTLS_ERR_MPI_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_MPI_INVALID_CHARACTER) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - There is an invalid character in the digit string" ); + if( use_ret == -(MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The buffer is too small to write to" ); + if( use_ret == -(MBEDTLS_ERR_MPI_NEGATIVE_VALUE) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input arguments are negative or result in illegal output" ); + if( use_ret == -(MBEDTLS_ERR_MPI_DIVISION_BY_ZERO) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input argument for division is zero, which is not allowed" ); + if( use_ret == -(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - The input arguments are not acceptable" ); + if( use_ret == -(MBEDTLS_ERR_MPI_ALLOC_FAILED) ) + mbedtls_snprintf( buf, buflen, "BIGNUM - Memory allocation failed" ); +#endif /* MBEDTLS_BIGNUM_C */ + +#if defined(MBEDTLS_BLOWFISH_C) + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "BLOWFISH - Invalid data input length" ); +#endif /* MBEDTLS_BLOWFISH_C */ + +#if defined(MBEDTLS_CAMELLIA_C) + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid key length" ); + if( use_ret == -(MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "CAMELLIA - Invalid data input length" ); +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_CCM_C) + if( use_ret == -(MBEDTLS_ERR_CCM_BAD_INPUT) ) + mbedtls_snprintf( buf, buflen, "CCM - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_CCM_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "CCM - Authenticated decryption failed" ); +#endif /* MBEDTLS_CCM_C */ + +#if defined(MBEDTLS_CTR_DRBG_C) + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - The entropy source failed" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - Too many random requested in single call" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - Input too large (Entropy + additional)" ); + if( use_ret == -(MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "CTR_DRBG - Read/write error in file" ); +#endif /* MBEDTLS_CTR_DRBG_C */ + +#if defined(MBEDTLS_DES_C) + if( use_ret == -(MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "DES - The data input has an invalid length" ); +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ENTROPY_C) + if( use_ret == -(MBEDTLS_ERR_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - Critical entropy source failure" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_MAX_SOURCES) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No more sources can be added" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No sources have been added to poll" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - No strong sources have been added to poll" ); + if( use_ret == -(MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "ENTROPY - Read/write error in file" ); +#endif /* MBEDTLS_ENTROPY_C */ + +#if defined(MBEDTLS_GCM_C) + if( use_ret == -(MBEDTLS_ERR_GCM_AUTH_FAILED) ) + mbedtls_snprintf( buf, buflen, "GCM - Authenticated decryption failed" ); + if( use_ret == -(MBEDTLS_ERR_GCM_BAD_INPUT) ) + mbedtls_snprintf( buf, buflen, "GCM - Bad input parameters to function" ); +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_HMAC_DRBG_C) + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Too many random requested in single call" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Input too large (Entropy + additional)" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - Read/write error in file" ); + if( use_ret == -(MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED) ) + mbedtls_snprintf( buf, buflen, "HMAC_DRBG - The entropy source failed" ); +#endif /* MBEDTLS_HMAC_DRBG_C */ + +#if defined(MBEDTLS_NET_C) + if( use_ret == -(MBEDTLS_ERR_NET_SOCKET_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Failed to open a socket" ); + if( use_ret == -(MBEDTLS_ERR_NET_CONNECT_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - The connection to the given server / port failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_BIND_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Binding of the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_LISTEN_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Could not listen on the socket" ); + if( use_ret == -(MBEDTLS_ERR_NET_ACCEPT_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Could not accept the incoming connection" ); + if( use_ret == -(MBEDTLS_ERR_NET_RECV_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Reading information from the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_SEND_FAILED) ) + mbedtls_snprintf( buf, buflen, "NET - Sending information through the socket failed" ); + if( use_ret == -(MBEDTLS_ERR_NET_CONN_RESET) ) + mbedtls_snprintf( buf, buflen, "NET - Connection was reset by peer" ); + if( use_ret == -(MBEDTLS_ERR_NET_UNKNOWN_HOST) ) + mbedtls_snprintf( buf, buflen, "NET - Failed to get an IP address for the given hostname" ); + if( use_ret == -(MBEDTLS_ERR_NET_BUFFER_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "NET - Buffer is too small to hold the data" ); + if( use_ret == -(MBEDTLS_ERR_NET_INVALID_CONTEXT) ) + mbedtls_snprintf( buf, buflen, "NET - The context is invalid, eg because it was free()ed" ); +#endif /* MBEDTLS_NET_C */ + +#if defined(MBEDTLS_OID_C) + if( use_ret == -(MBEDTLS_ERR_OID_NOT_FOUND) ) + mbedtls_snprintf( buf, buflen, "OID - OID is not found" ); + if( use_ret == -(MBEDTLS_ERR_OID_BUF_TOO_SMALL) ) + mbedtls_snprintf( buf, buflen, "OID - output buffer is too small" ); +#endif /* MBEDTLS_OID_C */ + +#if defined(MBEDTLS_PADLOCK_C) + if( use_ret == -(MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED) ) + mbedtls_snprintf( buf, buflen, "PADLOCK - Input data should be aligned" ); +#endif /* MBEDTLS_PADLOCK_C */ + +#if defined(MBEDTLS_THREADING_C) + if( use_ret == -(MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE) ) + mbedtls_snprintf( buf, buflen, "THREADING - The selected feature is not available" ); + if( use_ret == -(MBEDTLS_ERR_THREADING_BAD_INPUT_DATA) ) + mbedtls_snprintf( buf, buflen, "THREADING - Bad input parameters to function" ); + if( use_ret == -(MBEDTLS_ERR_THREADING_MUTEX_ERROR) ) + mbedtls_snprintf( buf, buflen, "THREADING - Locking / unlocking / free failed with error code" ); +#endif /* MBEDTLS_THREADING_C */ + +#if defined(MBEDTLS_XTEA_C) + if( use_ret == -(MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH) ) + mbedtls_snprintf( buf, buflen, "XTEA - The data input has an invalid length" ); +#endif /* MBEDTLS_XTEA_C */ + // END generated code + + if( strlen( buf ) != 0 ) + return; + + mbedtls_snprintf( buf, buflen, "UNKNOWN ERROR CODE (%04X)", use_ret ); +} + +#else /* MBEDTLS_ERROR_C */ + +#if defined(MBEDTLS_ERROR_STRERROR_DUMMY) + +/* + * Provide an non-function in case MBEDTLS_ERROR_C is not defined + */ +void mbedtls_strerror( int ret, char *buf, size_t buflen ) +{ + ((void) ret); + + if( buflen > 0 ) + buf[0] = '\0'; +} + +#endif /* MBEDTLS_ERROR_STRERROR_DUMMY */ + +#endif /* MBEDTLS_ERROR_C */ diff --git a/c++/src/connect/mbedtls/gcm.c b/c++/src/connect/mbedtls/gcm.c new file mode 100644 index 00000000..f1210c52 --- /dev/null +++ b/c++/src/connect/mbedtls/gcm.c @@ -0,0 +1,952 @@ +/* + * NIST SP800-38D compliant GCM implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf + * + * See also: + * [MGV] http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf + * + * We use the algorithm described as Shoup's method with 4-bit tables in + * [MGV] 4.1, pp. 12-13, to enhance speed without using too much memory. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_GCM_C) + +#include "mbedtls/gcm.h" + +#include + +#if defined(MBEDTLS_AESNI_C) +#include "mbedtls/aesni.h" +#endif + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Initialize a context + */ +void mbedtls_gcm_init( mbedtls_gcm_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_gcm_context ) ); +} + +/* + * Precompute small multiples of H, that is set + * HH[i] || HL[i] = H times i, + * where i is seen as a field element as in [MGV], ie high-order bits + * correspond to low powers of P. The result is stored in the same way, that + * is the high-order bit of HH corresponds to P^0 and the low-order bit of HL + * corresponds to P^127. + */ +static int gcm_gen_table( mbedtls_gcm_context *ctx ) +{ + int ret, i, j; + uint64_t hi, lo; + uint64_t vl, vh; + unsigned char h[16]; + size_t olen = 0; + + memset( h, 0, 16 ); + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, h, 16, h, &olen ) ) != 0 ) + return( ret ); + + /* pack h as two 64-bits ints, big-endian */ + GET_UINT32_BE( hi, h, 0 ); + GET_UINT32_BE( lo, h, 4 ); + vh = (uint64_t) hi << 32 | lo; + + GET_UINT32_BE( hi, h, 8 ); + GET_UINT32_BE( lo, h, 12 ); + vl = (uint64_t) hi << 32 | lo; + + /* 8 = 1000 corresponds to 1 in GF(2^128) */ + ctx->HL[8] = vl; + ctx->HH[8] = vh; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + /* With CLMUL support, we need only h, not the rest of the table */ + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_CLMUL ) ) + return( 0 ); +#endif + + /* 0 corresponds to 0 in GF(2^128) */ + ctx->HH[0] = 0; + ctx->HL[0] = 0; + + for( i = 4; i > 0; i >>= 1 ) + { + uint32_t T = ( vl & 1 ) * 0xe1000000U; + vl = ( vh << 63 ) | ( vl >> 1 ); + vh = ( vh >> 1 ) ^ ( (uint64_t) T << 32); + + ctx->HL[i] = vl; + ctx->HH[i] = vh; + } + + for( i = 2; i <= 8; i *= 2 ) + { + uint64_t *HiL = ctx->HL + i, *HiH = ctx->HH + i; + vh = *HiH; + vl = *HiL; + for( j = 1; j < i; j++ ) + { + HiH[j] = vh ^ ctx->HH[j]; + HiL[j] = vl ^ ctx->HL[j]; + } + } + + return( 0 ); +} + +int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + + cipher_info = mbedtls_cipher_info_from_values( cipher, keybits, MBEDTLS_MODE_ECB ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + if( cipher_info->block_size != 16 ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + mbedtls_cipher_free( &ctx->cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &ctx->cipher_ctx, cipher_info ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_cipher_setkey( &ctx->cipher_ctx, key, keybits, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = gcm_gen_table( ctx ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Shoup's method for multiplication use this table with + * last4[x] = x times P^128 + * where x and last4[x] are seen as elements of GF(2^128) as in [MGV] + */ +static const uint64_t last4[16] = +{ + 0x0000, 0x1c20, 0x3840, 0x2460, + 0x7080, 0x6ca0, 0x48c0, 0x54e0, + 0xe100, 0xfd20, 0xd940, 0xc560, + 0x9180, 0x8da0, 0xa9c0, 0xb5e0 +}; + +/* + * Sets output to x times H using the precomputed tables. + * x and output are seen as elements of GF(2^128) as in [MGV]. + */ +static void gcm_mult( mbedtls_gcm_context *ctx, const unsigned char x[16], + unsigned char output[16] ) +{ + int i = 0; + unsigned char lo, hi, rem; + uint64_t zh, zl; + +#if defined(MBEDTLS_AESNI_C) && defined(MBEDTLS_HAVE_X86_64) + if( mbedtls_aesni_has_support( MBEDTLS_AESNI_CLMUL ) ) { + unsigned char h[16]; + + PUT_UINT32_BE( ctx->HH[8] >> 32, h, 0 ); + PUT_UINT32_BE( ctx->HH[8], h, 4 ); + PUT_UINT32_BE( ctx->HL[8] >> 32, h, 8 ); + PUT_UINT32_BE( ctx->HL[8], h, 12 ); + + mbedtls_aesni_gcm_mult( output, x, h ); + return; + } +#endif /* MBEDTLS_AESNI_C && MBEDTLS_HAVE_X86_64 */ + + lo = x[15] & 0xf; + + zh = ctx->HH[lo]; + zl = ctx->HL[lo]; + + for( i = 15; i >= 0; i-- ) + { + lo = x[i] & 0xf; + hi = x[i] >> 4; + + if( i != 15 ) + { + rem = (unsigned char) zl & 0xf; + zl = ( zh << 60 ) | ( zl >> 4 ); + zh = ( zh >> 4 ); + zh ^= (uint64_t) last4[rem] << 48; + zh ^= ctx->HH[lo]; + zl ^= ctx->HL[lo]; + + } + + rem = (unsigned char) zl & 0xf; + zl = ( zh << 60 ) | ( zl >> 4 ); + zh = ( zh >> 4 ); + zh ^= (uint64_t) last4[rem] << 48; + zh ^= ctx->HH[hi]; + zl ^= ctx->HL[hi]; + } + + PUT_UINT32_BE( zh >> 32, output, 0 ); + PUT_UINT32_BE( zh, output, 4 ); + PUT_UINT32_BE( zl >> 32, output, 8 ); + PUT_UINT32_BE( zl, output, 12 ); +} + +int mbedtls_gcm_starts( mbedtls_gcm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len ) +{ + int ret; + unsigned char work_buf[16]; + size_t i; + const unsigned char *p; + size_t use_len, olen = 0; + + /* IV and AD are limited to 2^64 bits, so 2^61 bytes */ + if( ( (uint64_t) iv_len ) >> 61 != 0 || + ( (uint64_t) add_len ) >> 61 != 0 ) + { + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + } + + memset( ctx->y, 0x00, sizeof(ctx->y) ); + memset( ctx->buf, 0x00, sizeof(ctx->buf) ); + + ctx->mode = mode; + ctx->len = 0; + ctx->add_len = 0; + + if( iv_len == 12 ) + { + memcpy( ctx->y, iv, iv_len ); + ctx->y[15] = 1; + } + else + { + memset( work_buf, 0x00, 16 ); + PUT_UINT32_BE( iv_len * 8, work_buf, 12 ); + + p = iv; + while( iv_len > 0 ) + { + use_len = ( iv_len < 16 ) ? iv_len : 16; + + for( i = 0; i < use_len; i++ ) + ctx->y[i] ^= p[i]; + + gcm_mult( ctx, ctx->y, ctx->y ); + + iv_len -= use_len; + p += use_len; + } + + for( i = 0; i < 16; i++ ) + ctx->y[i] ^= work_buf[i]; + + gcm_mult( ctx, ctx->y, ctx->y ); + } + + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ctx->base_ectr, + &olen ) ) != 0 ) + { + return( ret ); + } + + ctx->add_len = add_len; + p = add; + while( add_len > 0 ) + { + use_len = ( add_len < 16 ) ? add_len : 16; + + for( i = 0; i < use_len; i++ ) + ctx->buf[i] ^= p[i]; + + gcm_mult( ctx, ctx->buf, ctx->buf ); + + add_len -= use_len; + p += use_len; + } + + return( 0 ); +} + +int mbedtls_gcm_update( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + unsigned char ectr[16]; + size_t i; + const unsigned char *p; + unsigned char *out_p = output; + size_t use_len, olen = 0; + + if( output > input && (size_t) ( output - input ) < length ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + /* Total length is restricted to 2^39 - 256 bits, ie 2^36 - 2^5 bytes + * Also check for possible overflow */ + if( ctx->len + length < ctx->len || + (uint64_t) ctx->len + length > 0xFFFFFFFE0ull ) + { + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + } + + ctx->len += length; + + p = input; + while( length > 0 ) + { + use_len = ( length < 16 ) ? length : 16; + + for( i = 16; i > 12; i-- ) + if( ++ctx->y[i - 1] != 0 ) + break; + + if( ( ret = mbedtls_cipher_update( &ctx->cipher_ctx, ctx->y, 16, ectr, + &olen ) ) != 0 ) + { + return( ret ); + } + + for( i = 0; i < use_len; i++ ) + { + if( ctx->mode == MBEDTLS_GCM_DECRYPT ) + ctx->buf[i] ^= p[i]; + out_p[i] = ectr[i] ^ p[i]; + if( ctx->mode == MBEDTLS_GCM_ENCRYPT ) + ctx->buf[i] ^= out_p[i]; + } + + gcm_mult( ctx, ctx->buf, ctx->buf ); + + length -= use_len; + p += use_len; + out_p += use_len; + } + + return( 0 ); +} + +int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, + unsigned char *tag, + size_t tag_len ) +{ + unsigned char work_buf[16]; + size_t i; + uint64_t orig_len = ctx->len * 8; + uint64_t orig_add_len = ctx->add_len * 8; + + if( tag_len > 16 || tag_len < 4 ) + return( MBEDTLS_ERR_GCM_BAD_INPUT ); + + memcpy( tag, ctx->base_ectr, tag_len ); + + if( orig_len || orig_add_len ) + { + memset( work_buf, 0x00, 16 ); + + PUT_UINT32_BE( ( orig_add_len >> 32 ), work_buf, 0 ); + PUT_UINT32_BE( ( orig_add_len ), work_buf, 4 ); + PUT_UINT32_BE( ( orig_len >> 32 ), work_buf, 8 ); + PUT_UINT32_BE( ( orig_len ), work_buf, 12 ); + + for( i = 0; i < 16; i++ ) + ctx->buf[i] ^= work_buf[i]; + + gcm_mult( ctx, ctx->buf, ctx->buf ); + + for( i = 0; i < tag_len; i++ ) + tag[i] ^= ctx->buf[i]; + } + + return( 0 ); +} + +int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag ) +{ + int ret; + + if( ( ret = mbedtls_gcm_starts( ctx, mode, iv, iv_len, add, add_len ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_gcm_update( ctx, length, input, output ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_gcm_finish( ctx, tag, tag_len ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *tag, + size_t tag_len, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + unsigned char check_tag[16]; + size_t i; + int diff; + + if( ( ret = mbedtls_gcm_crypt_and_tag( ctx, MBEDTLS_GCM_DECRYPT, length, + iv, iv_len, add, add_len, + input, output, tag_len, check_tag ) ) != 0 ) + { + return( ret ); + } + + /* Check tag in "constant-time" */ + for( diff = 0, i = 0; i < tag_len; i++ ) + diff |= tag[i] ^ check_tag[i]; + + if( diff != 0 ) + { + mbedtls_zeroize( output, length ); + return( MBEDTLS_ERR_GCM_AUTH_FAILED ); + } + + return( 0 ); +} + +void mbedtls_gcm_free( mbedtls_gcm_context *ctx ) +{ + mbedtls_cipher_free( &ctx->cipher_ctx ); + mbedtls_zeroize( ctx, sizeof( mbedtls_gcm_context ) ); +} + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/* + * AES-GCM test vectors from: + * + * http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip + */ +#define MAX_TESTS 6 + +static const int key_index[MAX_TESTS] = + { 0, 0, 1, 1, 1, 1 }; + +static const unsigned char key[MAX_TESTS][32] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08, + 0xfe, 0xff, 0xe9, 0x92, 0x86, 0x65, 0x73, 0x1c, + 0x6d, 0x6a, 0x8f, 0x94, 0x67, 0x30, 0x83, 0x08 }, +}; + +static const size_t iv_len[MAX_TESTS] = + { 12, 12, 12, 12, 8, 60 }; + +static const int iv_index[MAX_TESTS] = + { 0, 0, 1, 1, 1, 2 }; + +static const unsigned char iv[MAX_TESTS][64] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + { 0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad, + 0xde, 0xca, 0xf8, 0x88 }, + { 0x93, 0x13, 0x22, 0x5d, 0xf8, 0x84, 0x06, 0xe5, + 0x55, 0x90, 0x9c, 0x5a, 0xff, 0x52, 0x69, 0xaa, + 0x6a, 0x7a, 0x95, 0x38, 0x53, 0x4f, 0x7d, 0xa1, + 0xe4, 0xc3, 0x03, 0xd2, 0xa3, 0x18, 0xa7, 0x28, + 0xc3, 0xc0, 0xc9, 0x51, 0x56, 0x80, 0x95, 0x39, + 0xfc, 0xf0, 0xe2, 0x42, 0x9a, 0x6b, 0x52, 0x54, + 0x16, 0xae, 0xdb, 0xf5, 0xa0, 0xde, 0x6a, 0x57, + 0xa6, 0x37, 0xb3, 0x9b }, +}; + +static const size_t add_len[MAX_TESTS] = + { 0, 0, 0, 20, 20, 20 }; + +static const int add_index[MAX_TESTS] = + { 0, 0, 0, 1, 1, 1 }; + +static const unsigned char additional[MAX_TESTS][64] = +{ + { 0x00 }, + { 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xfe, 0xed, 0xfa, 0xce, 0xde, 0xad, 0xbe, 0xef, + 0xab, 0xad, 0xda, 0xd2 }, +}; + +static const size_t pt_len[MAX_TESTS] = + { 0, 16, 64, 60, 60, 60 }; + +static const int pt_index[MAX_TESTS] = + { 0, 0, 1, 1, 1, 1 }; + +static const unsigned char pt[MAX_TESTS][64] = +{ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0xd9, 0x31, 0x32, 0x25, 0xf8, 0x84, 0x06, 0xe5, + 0xa5, 0x59, 0x09, 0xc5, 0xaf, 0xf5, 0x26, 0x9a, + 0x86, 0xa7, 0xa9, 0x53, 0x15, 0x34, 0xf7, 0xda, + 0x2e, 0x4c, 0x30, 0x3d, 0x8a, 0x31, 0x8a, 0x72, + 0x1c, 0x3c, 0x0c, 0x95, 0x95, 0x68, 0x09, 0x53, + 0x2f, 0xcf, 0x0e, 0x24, 0x49, 0xa6, 0xb5, 0x25, + 0xb1, 0x6a, 0xed, 0xf5, 0xaa, 0x0d, 0xe6, 0x57, + 0xba, 0x63, 0x7b, 0x39, 0x1a, 0xaf, 0xd2, 0x55 }, +}; + +static const unsigned char ct[MAX_TESTS * 3][64] = +{ + { 0x00 }, + { 0x03, 0x88, 0xda, 0xce, 0x60, 0xb6, 0xa3, 0x92, + 0xf3, 0x28, 0xc2, 0xb9, 0x71, 0xb2, 0xfe, 0x78 }, + { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91, 0x47, 0x3f, 0x59, 0x85 }, + { 0x42, 0x83, 0x1e, 0xc2, 0x21, 0x77, 0x74, 0x24, + 0x4b, 0x72, 0x21, 0xb7, 0x84, 0xd0, 0xd4, 0x9c, + 0xe3, 0xaa, 0x21, 0x2f, 0x2c, 0x02, 0xa4, 0xe0, + 0x35, 0xc1, 0x7e, 0x23, 0x29, 0xac, 0xa1, 0x2e, + 0x21, 0xd5, 0x14, 0xb2, 0x54, 0x66, 0x93, 0x1c, + 0x7d, 0x8f, 0x6a, 0x5a, 0xac, 0x84, 0xaa, 0x05, + 0x1b, 0xa3, 0x0b, 0x39, 0x6a, 0x0a, 0xac, 0x97, + 0x3d, 0x58, 0xe0, 0x91 }, + { 0x61, 0x35, 0x3b, 0x4c, 0x28, 0x06, 0x93, 0x4a, + 0x77, 0x7f, 0xf5, 0x1f, 0xa2, 0x2a, 0x47, 0x55, + 0x69, 0x9b, 0x2a, 0x71, 0x4f, 0xcd, 0xc6, 0xf8, + 0x37, 0x66, 0xe5, 0xf9, 0x7b, 0x6c, 0x74, 0x23, + 0x73, 0x80, 0x69, 0x00, 0xe4, 0x9f, 0x24, 0xb2, + 0x2b, 0x09, 0x75, 0x44, 0xd4, 0x89, 0x6b, 0x42, + 0x49, 0x89, 0xb5, 0xe1, 0xeb, 0xac, 0x0f, 0x07, + 0xc2, 0x3f, 0x45, 0x98 }, + { 0x8c, 0xe2, 0x49, 0x98, 0x62, 0x56, 0x15, 0xb6, + 0x03, 0xa0, 0x33, 0xac, 0xa1, 0x3f, 0xb8, 0x94, + 0xbe, 0x91, 0x12, 0xa5, 0xc3, 0xa2, 0x11, 0xa8, + 0xba, 0x26, 0x2a, 0x3c, 0xca, 0x7e, 0x2c, 0xa7, + 0x01, 0xe4, 0xa9, 0xa4, 0xfb, 0xa4, 0x3c, 0x90, + 0xcc, 0xdc, 0xb2, 0x81, 0xd4, 0x8c, 0x7c, 0x6f, + 0xd6, 0x28, 0x75, 0xd2, 0xac, 0xa4, 0x17, 0x03, + 0x4c, 0x34, 0xae, 0xe5 }, + { 0x00 }, + { 0x98, 0xe7, 0x24, 0x7c, 0x07, 0xf0, 0xfe, 0x41, + 0x1c, 0x26, 0x7e, 0x43, 0x84, 0xb0, 0xf6, 0x00 }, + { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10, 0xac, 0xad, 0xe2, 0x56 }, + { 0x39, 0x80, 0xca, 0x0b, 0x3c, 0x00, 0xe8, 0x41, + 0xeb, 0x06, 0xfa, 0xc4, 0x87, 0x2a, 0x27, 0x57, + 0x85, 0x9e, 0x1c, 0xea, 0xa6, 0xef, 0xd9, 0x84, + 0x62, 0x85, 0x93, 0xb4, 0x0c, 0xa1, 0xe1, 0x9c, + 0x7d, 0x77, 0x3d, 0x00, 0xc1, 0x44, 0xc5, 0x25, + 0xac, 0x61, 0x9d, 0x18, 0xc8, 0x4a, 0x3f, 0x47, + 0x18, 0xe2, 0x44, 0x8b, 0x2f, 0xe3, 0x24, 0xd9, + 0xcc, 0xda, 0x27, 0x10 }, + { 0x0f, 0x10, 0xf5, 0x99, 0xae, 0x14, 0xa1, 0x54, + 0xed, 0x24, 0xb3, 0x6e, 0x25, 0x32, 0x4d, 0xb8, + 0xc5, 0x66, 0x63, 0x2e, 0xf2, 0xbb, 0xb3, 0x4f, + 0x83, 0x47, 0x28, 0x0f, 0xc4, 0x50, 0x70, 0x57, + 0xfd, 0xdc, 0x29, 0xdf, 0x9a, 0x47, 0x1f, 0x75, + 0xc6, 0x65, 0x41, 0xd4, 0xd4, 0xda, 0xd1, 0xc9, + 0xe9, 0x3a, 0x19, 0xa5, 0x8e, 0x8b, 0x47, 0x3f, + 0xa0, 0xf0, 0x62, 0xf7 }, + { 0xd2, 0x7e, 0x88, 0x68, 0x1c, 0xe3, 0x24, 0x3c, + 0x48, 0x30, 0x16, 0x5a, 0x8f, 0xdc, 0xf9, 0xff, + 0x1d, 0xe9, 0xa1, 0xd8, 0xe6, 0xb4, 0x47, 0xef, + 0x6e, 0xf7, 0xb7, 0x98, 0x28, 0x66, 0x6e, 0x45, + 0x81, 0xe7, 0x90, 0x12, 0xaf, 0x34, 0xdd, 0xd9, + 0xe2, 0xf0, 0x37, 0x58, 0x9b, 0x29, 0x2d, 0xb3, + 0xe6, 0x7c, 0x03, 0x67, 0x45, 0xfa, 0x22, 0xe7, + 0xe9, 0xb7, 0x37, 0x3b }, + { 0x00 }, + { 0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, + 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18 }, + { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62, 0x89, 0x80, 0x15, 0xad }, + { 0x52, 0x2d, 0xc1, 0xf0, 0x99, 0x56, 0x7d, 0x07, + 0xf4, 0x7f, 0x37, 0xa3, 0x2a, 0x84, 0x42, 0x7d, + 0x64, 0x3a, 0x8c, 0xdc, 0xbf, 0xe5, 0xc0, 0xc9, + 0x75, 0x98, 0xa2, 0xbd, 0x25, 0x55, 0xd1, 0xaa, + 0x8c, 0xb0, 0x8e, 0x48, 0x59, 0x0d, 0xbb, 0x3d, + 0xa7, 0xb0, 0x8b, 0x10, 0x56, 0x82, 0x88, 0x38, + 0xc5, 0xf6, 0x1e, 0x63, 0x93, 0xba, 0x7a, 0x0a, + 0xbc, 0xc9, 0xf6, 0x62 }, + { 0xc3, 0x76, 0x2d, 0xf1, 0xca, 0x78, 0x7d, 0x32, + 0xae, 0x47, 0xc1, 0x3b, 0xf1, 0x98, 0x44, 0xcb, + 0xaf, 0x1a, 0xe1, 0x4d, 0x0b, 0x97, 0x6a, 0xfa, + 0xc5, 0x2f, 0xf7, 0xd7, 0x9b, 0xba, 0x9d, 0xe0, + 0xfe, 0xb5, 0x82, 0xd3, 0x39, 0x34, 0xa4, 0xf0, + 0x95, 0x4c, 0xc2, 0x36, 0x3b, 0xc7, 0x3f, 0x78, + 0x62, 0xac, 0x43, 0x0e, 0x64, 0xab, 0xe4, 0x99, + 0xf4, 0x7c, 0x9b, 0x1f }, + { 0x5a, 0x8d, 0xef, 0x2f, 0x0c, 0x9e, 0x53, 0xf1, + 0xf7, 0x5d, 0x78, 0x53, 0x65, 0x9e, 0x2a, 0x20, + 0xee, 0xb2, 0xb2, 0x2a, 0xaf, 0xde, 0x64, 0x19, + 0xa0, 0x58, 0xab, 0x4f, 0x6f, 0x74, 0x6b, 0xf4, + 0x0f, 0xc0, 0xc3, 0xb7, 0x80, 0xf2, 0x44, 0x45, + 0x2d, 0xa3, 0xeb, 0xf1, 0xc5, 0xd8, 0x2c, 0xde, + 0xa2, 0x41, 0x89, 0x97, 0x20, 0x0e, 0xf8, 0x2e, + 0x44, 0xae, 0x7e, 0x3f }, +}; + +static const unsigned char tag[MAX_TESTS * 3][16] = +{ + { 0x58, 0xe2, 0xfc, 0xce, 0xfa, 0x7e, 0x30, 0x61, + 0x36, 0x7f, 0x1d, 0x57, 0xa4, 0xe7, 0x45, 0x5a }, + { 0xab, 0x6e, 0x47, 0xd4, 0x2c, 0xec, 0x13, 0xbd, + 0xf5, 0x3a, 0x67, 0xb2, 0x12, 0x57, 0xbd, 0xdf }, + { 0x4d, 0x5c, 0x2a, 0xf3, 0x27, 0xcd, 0x64, 0xa6, + 0x2c, 0xf3, 0x5a, 0xbd, 0x2b, 0xa6, 0xfa, 0xb4 }, + { 0x5b, 0xc9, 0x4f, 0xbc, 0x32, 0x21, 0xa5, 0xdb, + 0x94, 0xfa, 0xe9, 0x5a, 0xe7, 0x12, 0x1a, 0x47 }, + { 0x36, 0x12, 0xd2, 0xe7, 0x9e, 0x3b, 0x07, 0x85, + 0x56, 0x1b, 0xe1, 0x4a, 0xac, 0xa2, 0xfc, 0xcb }, + { 0x61, 0x9c, 0xc5, 0xae, 0xff, 0xfe, 0x0b, 0xfa, + 0x46, 0x2a, 0xf4, 0x3c, 0x16, 0x99, 0xd0, 0x50 }, + { 0xcd, 0x33, 0xb2, 0x8a, 0xc7, 0x73, 0xf7, 0x4b, + 0xa0, 0x0e, 0xd1, 0xf3, 0x12, 0x57, 0x24, 0x35 }, + { 0x2f, 0xf5, 0x8d, 0x80, 0x03, 0x39, 0x27, 0xab, + 0x8e, 0xf4, 0xd4, 0x58, 0x75, 0x14, 0xf0, 0xfb }, + { 0x99, 0x24, 0xa7, 0xc8, 0x58, 0x73, 0x36, 0xbf, + 0xb1, 0x18, 0x02, 0x4d, 0xb8, 0x67, 0x4a, 0x14 }, + { 0x25, 0x19, 0x49, 0x8e, 0x80, 0xf1, 0x47, 0x8f, + 0x37, 0xba, 0x55, 0xbd, 0x6d, 0x27, 0x61, 0x8c }, + { 0x65, 0xdc, 0xc5, 0x7f, 0xcf, 0x62, 0x3a, 0x24, + 0x09, 0x4f, 0xcc, 0xa4, 0x0d, 0x35, 0x33, 0xf8 }, + { 0xdc, 0xf5, 0x66, 0xff, 0x29, 0x1c, 0x25, 0xbb, + 0xb8, 0x56, 0x8f, 0xc3, 0xd3, 0x76, 0xa6, 0xd9 }, + { 0x53, 0x0f, 0x8a, 0xfb, 0xc7, 0x45, 0x36, 0xb9, + 0xa9, 0x63, 0xb4, 0xf1, 0xc4, 0xcb, 0x73, 0x8b }, + { 0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, + 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19 }, + { 0xb0, 0x94, 0xda, 0xc5, 0xd9, 0x34, 0x71, 0xbd, + 0xec, 0x1a, 0x50, 0x22, 0x70, 0xe3, 0xcc, 0x6c }, + { 0x76, 0xfc, 0x6e, 0xce, 0x0f, 0x4e, 0x17, 0x68, + 0xcd, 0xdf, 0x88, 0x53, 0xbb, 0x2d, 0x55, 0x1b }, + { 0x3a, 0x33, 0x7d, 0xbf, 0x46, 0xa7, 0x92, 0xc4, + 0x5e, 0x45, 0x49, 0x13, 0xfe, 0x2e, 0xa8, 0xf2 }, + { 0xa4, 0x4a, 0x82, 0x66, 0xee, 0x1c, 0x8e, 0xb0, + 0xc8, 0xb5, 0xd4, 0xcf, 0x5a, 0xe9, 0xf1, 0x9a }, +}; + +int mbedtls_gcm_self_test( int verbose ) +{ + mbedtls_gcm_context ctx; + unsigned char buf[64]; + unsigned char tag_buf[16]; + int i, j, ret; + mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; + + mbedtls_gcm_init( &ctx ); + + for( j = 0; j < 3; j++ ) + { + int key_len = 128 + 64 * j; + + for( i = 0; i < MAX_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d (%s): ", + key_len, i, "enc" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_ENCRYPT, + pt_len[i], + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i], + pt[pt_index[i]], buf, 16, tag_buf ); + + if( ret != 0 || + memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d (%s): ", + key_len, i, "dec" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_crypt_and_tag( &ctx, MBEDTLS_GCM_DECRYPT, + pt_len[i], + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i], + ct[j * 6 + i], buf, 16, tag_buf ); + + if( ret != 0 || + memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d split (%s): ", + key_len, i, "enc" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_ENCRYPT, + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i] ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( pt_len[i] > 32 ) + { + size_t rest_len = pt_len[i] - 32; + ret = mbedtls_gcm_update( &ctx, 32, pt[pt_index[i]], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + ret = mbedtls_gcm_update( &ctx, rest_len, pt[pt_index[i]] + 32, + buf + 32 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + else + { + ret = mbedtls_gcm_update( &ctx, pt_len[i], pt[pt_index[i]], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 ); + if( ret != 0 || + memcmp( buf, ct[j * 6 + i], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " AES-GCM-%3d #%d split (%s): ", + key_len, i, "dec" ); + + mbedtls_gcm_setkey( &ctx, cipher, key[key_index[i]], key_len ); + + ret = mbedtls_gcm_starts( &ctx, MBEDTLS_GCM_DECRYPT, + iv[iv_index[i]], iv_len[i], + additional[add_index[i]], add_len[i] ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( pt_len[i] > 32 ) + { + size_t rest_len = pt_len[i] - 32; + ret = mbedtls_gcm_update( &ctx, 32, ct[j * 6 + i], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + ret = mbedtls_gcm_update( &ctx, rest_len, ct[j * 6 + i] + 32, + buf + 32 ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + else + { + ret = mbedtls_gcm_update( &ctx, pt_len[i], ct[j * 6 + i], buf ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + ret = mbedtls_gcm_finish( &ctx, tag_buf, 16 ); + if( ret != 0 || + memcmp( buf, pt[pt_index[i]], pt_len[i] ) != 0 || + memcmp( tag_buf, tag[j * 6 + i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + mbedtls_gcm_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + } + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#endif /* MBEDTLS_GCM_C */ diff --git a/c++/src/connect/mbedtls/havege.c b/c++/src/connect/mbedtls/havege.c new file mode 100644 index 00000000..2b75ef7b --- /dev/null +++ b/c++/src/connect/mbedtls/havege.c @@ -0,0 +1,245 @@ +/** + * \brief HAVEGE: HArdware Volatile Entropy Gathering and Expansion + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The HAVEGE RNG was designed by Andre Seznec in 2002. + * + * http://www.irisa.fr/caps/projects/hipsor/publi.php + * + * Contact: seznec(at)irisa_dot_fr - orocheco(at)irisa_dot_fr + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_HAVEGE_C) + +#include "mbedtls/havege.h" +#include "mbedtls/timing.h" + +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* ------------------------------------------------------------------------ + * On average, one iteration accesses two 8-word blocks in the havege WALK + * table, and generates 16 words in the RES array. + * + * The data read in the WALK table is updated and permuted after each use. + * The result of the hardware clock counter read is used for this update. + * + * 25 conditional tests are present. The conditional tests are grouped in + * two nested groups of 12 conditional tests and 1 test that controls the + * permutation; on average, there should be 6 tests executed and 3 of them + * should be mispredicted. + * ------------------------------------------------------------------------ + */ + +#define SWAP(X,Y) { int *T = X; X = Y; Y = T; } + +#define TST1_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; +#define TST2_ENTER if( PTEST & 1 ) { PTEST ^= 3; PTEST >>= 1; + +#define TST1_LEAVE U1++; } +#define TST2_LEAVE U2++; } + +#define ONE_ITERATION \ + \ + PTEST = PT1 >> 20; \ + \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + TST1_ENTER TST1_ENTER TST1_ENTER TST1_ENTER \ + \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + TST1_LEAVE TST1_LEAVE TST1_LEAVE TST1_LEAVE \ + \ + PTX = (PT1 >> 18) & 7; \ + PT1 &= 0x1FFF; \ + PT2 &= 0x1FFF; \ + CLK = (int) mbedtls_timing_hardclock(); \ + \ + i = 0; \ + A = &WALK[PT1 ]; RES[i++] ^= *A; \ + B = &WALK[PT2 ]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 1]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 4]; RES[i++] ^= *D; \ + \ + IN = (*A >> (1)) ^ (*A << (31)) ^ CLK; \ + *A = (*B >> (2)) ^ (*B << (30)) ^ CLK; \ + *B = IN ^ U1; \ + *C = (*C >> (3)) ^ (*C << (29)) ^ CLK; \ + *D = (*D >> (4)) ^ (*D << (28)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 2]; RES[i++] ^= *A; \ + B = &WALK[PT2 ^ 2]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 3]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 6]; RES[i++] ^= *D; \ + \ + if( PTEST & 1 ) SWAP( A, C ); \ + \ + IN = (*A >> (5)) ^ (*A << (27)) ^ CLK; \ + *A = (*B >> (6)) ^ (*B << (26)) ^ CLK; \ + *B = IN; CLK = (int) mbedtls_timing_hardclock(); \ + *C = (*C >> (7)) ^ (*C << (25)) ^ CLK; \ + *D = (*D >> (8)) ^ (*D << (24)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 4]; \ + B = &WALK[PT2 ^ 1]; \ + \ + PTEST = PT2 >> 1; \ + \ + PT2 = (RES[(i - 8) ^ PTY] ^ WALK[PT2 ^ PTY ^ 7]); \ + PT2 = ((PT2 & 0x1FFF) & (~8)) ^ ((PT1 ^ 8) & 0x8); \ + PTY = (PT2 >> 10) & 7; \ + \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + TST2_ENTER TST2_ENTER TST2_ENTER TST2_ENTER \ + \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + TST2_LEAVE TST2_LEAVE TST2_LEAVE TST2_LEAVE \ + \ + C = &WALK[PT1 ^ 5]; \ + D = &WALK[PT2 ^ 5]; \ + \ + RES[i++] ^= *A; \ + RES[i++] ^= *B; \ + RES[i++] ^= *C; \ + RES[i++] ^= *D; \ + \ + IN = (*A >> ( 9)) ^ (*A << (23)) ^ CLK; \ + *A = (*B >> (10)) ^ (*B << (22)) ^ CLK; \ + *B = IN ^ U2; \ + *C = (*C >> (11)) ^ (*C << (21)) ^ CLK; \ + *D = (*D >> (12)) ^ (*D << (20)) ^ CLK; \ + \ + A = &WALK[PT1 ^ 6]; RES[i++] ^= *A; \ + B = &WALK[PT2 ^ 3]; RES[i++] ^= *B; \ + C = &WALK[PT1 ^ 7]; RES[i++] ^= *C; \ + D = &WALK[PT2 ^ 7]; RES[i++] ^= *D; \ + \ + IN = (*A >> (13)) ^ (*A << (19)) ^ CLK; \ + *A = (*B >> (14)) ^ (*B << (18)) ^ CLK; \ + *B = IN; \ + *C = (*C >> (15)) ^ (*C << (17)) ^ CLK; \ + *D = (*D >> (16)) ^ (*D << (16)) ^ CLK; \ + \ + PT1 = ( RES[( i - 8 ) ^ PTX] ^ \ + WALK[PT1 ^ PTX ^ 7] ) & (~1); \ + PT1 ^= (PT2 ^ 0x10) & 0x10; \ + \ + for( n++, i = 0; i < 16; i++ ) \ + hs->pool[n % MBEDTLS_HAVEGE_COLLECT_SIZE] ^= RES[i]; + +/* + * Entropy gathering function + */ +static void havege_fill( mbedtls_havege_state *hs ) +{ + int i, n = 0; + int U1, U2, *A, *B, *C, *D; + int PT1, PT2, *WALK, RES[16]; + int PTX, PTY, CLK, PTEST, IN; + + WALK = hs->WALK; + PT1 = hs->PT1; + PT2 = hs->PT2; + + PTX = U1 = 0; + PTY = U2 = 0; + + (void)PTX; + + memset( RES, 0, sizeof( RES ) ); + + while( n < MBEDTLS_HAVEGE_COLLECT_SIZE * 4 ) + { + ONE_ITERATION + ONE_ITERATION + ONE_ITERATION + ONE_ITERATION + } + + hs->PT1 = PT1; + hs->PT2 = PT2; + + hs->offset[0] = 0; + hs->offset[1] = MBEDTLS_HAVEGE_COLLECT_SIZE / 2; +} + +/* + * HAVEGE initialization + */ +void mbedtls_havege_init( mbedtls_havege_state *hs ) +{ + memset( hs, 0, sizeof( mbedtls_havege_state ) ); + + havege_fill( hs ); +} + +void mbedtls_havege_free( mbedtls_havege_state *hs ) +{ + if( hs == NULL ) + return; + + mbedtls_zeroize( hs, sizeof( mbedtls_havege_state ) ); +} + +/* + * HAVEGE rand function + */ +int mbedtls_havege_random( void *p_rng, unsigned char *buf, size_t len ) +{ + int val; + size_t use_len; + mbedtls_havege_state *hs = (mbedtls_havege_state *) p_rng; + unsigned char *p = buf; + + while( len > 0 ) + { + use_len = len; + if( use_len > sizeof(int) ) + use_len = sizeof(int); + + if( hs->offset[1] >= MBEDTLS_HAVEGE_COLLECT_SIZE ) + havege_fill( hs ); + + val = hs->pool[hs->offset[0]++]; + val ^= hs->pool[hs->offset[1]++]; + + memcpy( p, &val, use_len ); + + len -= use_len; + p += use_len; + } + + return( 0 ); +} + +#endif /* MBEDTLS_HAVEGE_C */ diff --git a/c++/src/connect/mbedtls/hmac_drbg.c b/c++/src/connect/mbedtls/hmac_drbg.c new file mode 100644 index 00000000..bf5f9b5b --- /dev/null +++ b/c++/src/connect/mbedtls/hmac_drbg.c @@ -0,0 +1,529 @@ +/* + * HMAC_DRBG implementation (NIST SP 800-90) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The NIST SP 800-90A DRBGs are described in the following publication. + * http://csrc.nist.gov/publications/nistpubs/800-90A/SP800-90A.pdf + * References below are based on rev. 1 (January 2012). + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) + +#include "mbedtls/hmac_drbg.h" + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_SELF_TEST */ +#endif /* MBEDTLS_PLATFORM_C */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * HMAC_DRBG context initialization + */ +void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_hmac_drbg_context ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +/* + * HMAC_DRBG update, using optional additional data (10.1.2.2) + */ +void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t add_len ) +{ + size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info ); + unsigned char rounds = ( additional != NULL && add_len != 0 ) ? 2 : 1; + unsigned char sep[1]; + unsigned char K[MBEDTLS_MD_MAX_SIZE]; + + for( sep[0] = 0; sep[0] < rounds; sep[0]++ ) + { + /* Step 1 or 4 */ + mbedtls_md_hmac_reset( &ctx->md_ctx ); + mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); + mbedtls_md_hmac_update( &ctx->md_ctx, sep, 1 ); + if( rounds == 2 ) + mbedtls_md_hmac_update( &ctx->md_ctx, additional, add_len ); + mbedtls_md_hmac_finish( &ctx->md_ctx, K ); + + /* Step 2 or 5 */ + mbedtls_md_hmac_starts( &ctx->md_ctx, K, md_len ); + mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); + mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ); + } +} + +/* + * Simplified HMAC_DRBG initialisation (for use with deterministic ECDSA) + */ +int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + const unsigned char *data, size_t data_len ) +{ + int ret; + + if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + /* + * Set initial working state. + * Use the V memory location, which is currently all 0, to initialize the + * MD context with an all-zero key. Then set V to its initial value. + */ + mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, mbedtls_md_get_size( md_info ) ); + memset( ctx->V, 0x01, mbedtls_md_get_size( md_info ) ); + + mbedtls_hmac_drbg_update( ctx, data, data_len ); + + return( 0 ); +} + +/* + * HMAC_DRBG reseeding: 10.1.2.4 (arabic) + 9.2 (Roman) + */ +int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t len ) +{ + unsigned char seed[MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT]; + size_t seedlen; + + /* III. Check input length */ + if( len > MBEDTLS_HMAC_DRBG_MAX_INPUT || + ctx->entropy_len + len > MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ) + { + return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + } + + memset( seed, 0, MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT ); + + /* IV. Gather entropy_len bytes of entropy for the seed */ + if( ctx->f_entropy( ctx->p_entropy, seed, ctx->entropy_len ) != 0 ) + return( MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED ); + + seedlen = ctx->entropy_len; + + /* 1. Concatenate entropy and additional data if any */ + if( additional != NULL && len != 0 ) + { + memcpy( seed + seedlen, additional, len ); + seedlen += len; + } + + /* 2. Update state */ + mbedtls_hmac_drbg_update( ctx, seed, seedlen ); + + /* 3. Reset reseed_counter */ + ctx->reseed_counter = 1; + + /* 4. Done */ + return( 0 ); +} + +/* + * HMAC_DRBG initialisation (10.1.2.3 + 9.1) + */ +int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ) +{ + int ret; + size_t entropy_len, md_size; + + if( ( ret = mbedtls_md_setup( &ctx->md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + md_size = mbedtls_md_get_size( md_info ); + + /* + * Set initial working state. + * Use the V memory location, which is currently all 0, to initialize the + * MD context with an all-zero key. Then set V to its initial value. + */ + mbedtls_md_hmac_starts( &ctx->md_ctx, ctx->V, md_size ); + memset( ctx->V, 0x01, md_size ); + + ctx->f_entropy = f_entropy; + ctx->p_entropy = p_entropy; + + ctx->reseed_interval = MBEDTLS_HMAC_DRBG_RESEED_INTERVAL; + + /* + * See SP800-57 5.6.1 (p. 65-66) for the security strength provided by + * each hash function, then according to SP800-90A rev1 10.1 table 2, + * min_entropy_len (in bits) is security_strength. + * + * (This also matches the sizes used in the NIST test vectors.) + */ + entropy_len = md_size <= 20 ? 16 : /* 160-bits hash -> 128 bits */ + md_size <= 28 ? 24 : /* 224-bits hash -> 192 bits */ + 32; /* better (256+) -> 256 bits */ + + /* + * For initialisation, use more entropy to emulate a nonce + * (Again, matches test vectors.) + */ + ctx->entropy_len = entropy_len * 3 / 2; + + if( ( ret = mbedtls_hmac_drbg_reseed( ctx, custom, len ) ) != 0 ) + return( ret ); + + ctx->entropy_len = entropy_len; + + return( 0 ); +} + +/* + * Set prediction resistance + */ +void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx, + int resistance ) +{ + ctx->prediction_resistance = resistance; +} + +/* + * Set entropy length grabbed for reseeds + */ +void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, size_t len ) +{ + ctx->entropy_len = len; +} + +/* + * Set reseed interval + */ +void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, int interval ) +{ + ctx->reseed_interval = interval; +} + +/* + * HMAC_DRBG random function with optional additional data: + * 10.1.2.5 (arabic) + 9.3 (Roman) + */ +int mbedtls_hmac_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t out_len, + const unsigned char *additional, size_t add_len ) +{ + int ret; + mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng; + size_t md_len = mbedtls_md_get_size( ctx->md_ctx.md_info ); + size_t left = out_len; + unsigned char *out = output; + + /* II. Check request length */ + if( out_len > MBEDTLS_HMAC_DRBG_MAX_REQUEST ) + return( MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG ); + + /* III. Check input length */ + if( add_len > MBEDTLS_HMAC_DRBG_MAX_INPUT ) + return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + + /* 1. (aka VII and IX) Check reseed counter and PR */ + if( ctx->f_entropy != NULL && /* For no-reseeding instances */ + ( ctx->prediction_resistance == MBEDTLS_HMAC_DRBG_PR_ON || + ctx->reseed_counter > ctx->reseed_interval ) ) + { + if( ( ret = mbedtls_hmac_drbg_reseed( ctx, additional, add_len ) ) != 0 ) + return( ret ); + + add_len = 0; /* VII.4 */ + } + + /* 2. Use additional data if any */ + if( additional != NULL && add_len != 0 ) + mbedtls_hmac_drbg_update( ctx, additional, add_len ); + + /* 3, 4, 5. Generate bytes */ + while( left != 0 ) + { + size_t use_len = left > md_len ? md_len : left; + + mbedtls_md_hmac_reset( &ctx->md_ctx ); + mbedtls_md_hmac_update( &ctx->md_ctx, ctx->V, md_len ); + mbedtls_md_hmac_finish( &ctx->md_ctx, ctx->V ); + + memcpy( out, ctx->V, use_len ); + out += use_len; + left -= use_len; + } + + /* 6. Update */ + mbedtls_hmac_drbg_update( ctx, additional, add_len ); + + /* 7. Update reseed counter */ + ctx->reseed_counter++; + + /* 8. Done */ + return( 0 ); +} + +/* + * HMAC_DRBG random function + */ +int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len ) +{ + int ret; + mbedtls_hmac_drbg_context *ctx = (mbedtls_hmac_drbg_context *) p_rng; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + ret = mbedtls_hmac_drbg_random_with_add( ctx, output, out_len, NULL, 0 ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Free an HMAC_DRBG context + */ +void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ) +{ + if( ctx == NULL ) + return; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + mbedtls_md_free( &ctx->md_ctx ); + mbedtls_zeroize( ctx, sizeof( mbedtls_hmac_drbg_context ) ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) +{ + int ret; + FILE *f; + unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "wb" ) ) == NULL ) + return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); + + if( ( ret = mbedtls_hmac_drbg_random( ctx, buf, sizeof( buf ) ) ) != 0 ) + goto exit; + + if( fwrite( buf, 1, sizeof( buf ), f ) != sizeof( buf ) ) + { + ret = MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR; + goto exit; + } + + ret = 0; + +exit: + fclose( f ); + return( ret ); +} + +int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ) +{ + FILE *f; + size_t n; + unsigned char buf[ MBEDTLS_HMAC_DRBG_MAX_INPUT ]; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + n = (size_t) ftell( f ); + fseek( f, 0, SEEK_SET ); + + if( n > MBEDTLS_HMAC_DRBG_MAX_INPUT ) + { + fclose( f ); + return( MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG ); + } + + if( fread( buf, 1, n, f ) != n ) + { + fclose( f ); + return( MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR ); + } + + fclose( f ); + + mbedtls_hmac_drbg_update( ctx, buf, n ); + + return( mbedtls_hmac_drbg_write_seed_file( ctx, path ) ); +} +#endif /* MBEDTLS_FS_IO */ + + +#if defined(MBEDTLS_SELF_TEST) + +#if !defined(MBEDTLS_SHA1_C) +/* Dummy checkup routine */ +int mbedtls_hmac_drbg_self_test( int verbose ) +{ + (void) verbose; + return( 0 ); +} +#else + +#define OUTPUT_LEN 80 + +/* From a NIST PR=true test vector */ +static const unsigned char entropy_pr[] = { + 0xa0, 0xc9, 0xab, 0x58, 0xf1, 0xe2, 0xe5, 0xa4, 0xde, 0x3e, 0xbd, 0x4f, + 0xf7, 0x3e, 0x9c, 0x5b, 0x64, 0xef, 0xd8, 0xca, 0x02, 0x8c, 0xf8, 0x11, + 0x48, 0xa5, 0x84, 0xfe, 0x69, 0xab, 0x5a, 0xee, 0x42, 0xaa, 0x4d, 0x42, + 0x17, 0x60, 0x99, 0xd4, 0x5e, 0x13, 0x97, 0xdc, 0x40, 0x4d, 0x86, 0xa3, + 0x7b, 0xf5, 0x59, 0x54, 0x75, 0x69, 0x51, 0xe4 }; +static const unsigned char result_pr[OUTPUT_LEN] = { + 0x9a, 0x00, 0xa2, 0xd0, 0x0e, 0xd5, 0x9b, 0xfe, 0x31, 0xec, 0xb1, 0x39, + 0x9b, 0x60, 0x81, 0x48, 0xd1, 0x96, 0x9d, 0x25, 0x0d, 0x3c, 0x1e, 0x94, + 0x10, 0x10, 0x98, 0x12, 0x93, 0x25, 0xca, 0xb8, 0xfc, 0xcc, 0x2d, 0x54, + 0x73, 0x19, 0x70, 0xc0, 0x10, 0x7a, 0xa4, 0x89, 0x25, 0x19, 0x95, 0x5e, + 0x4b, 0xc6, 0x00, 0x1d, 0x7f, 0x4e, 0x6a, 0x2b, 0xf8, 0xa3, 0x01, 0xab, + 0x46, 0x05, 0x5c, 0x09, 0xa6, 0x71, 0x88, 0xf1, 0xa7, 0x40, 0xee, 0xf3, + 0xe1, 0x5c, 0x02, 0x9b, 0x44, 0xaf, 0x03, 0x44 }; + +/* From a NIST PR=false test vector */ +static const unsigned char entropy_nopr[] = { + 0x79, 0x34, 0x9b, 0xbf, 0x7c, 0xdd, 0xa5, 0x79, 0x95, 0x57, 0x86, 0x66, + 0x21, 0xc9, 0x13, 0x83, 0x11, 0x46, 0x73, 0x3a, 0xbf, 0x8c, 0x35, 0xc8, + 0xc7, 0x21, 0x5b, 0x5b, 0x96, 0xc4, 0x8e, 0x9b, 0x33, 0x8c, 0x74, 0xe3, + 0xe9, 0x9d, 0xfe, 0xdf }; +static const unsigned char result_nopr[OUTPUT_LEN] = { + 0xc6, 0xa1, 0x6a, 0xb8, 0xd4, 0x20, 0x70, 0x6f, 0x0f, 0x34, 0xab, 0x7f, + 0xec, 0x5a, 0xdc, 0xa9, 0xd8, 0xca, 0x3a, 0x13, 0x3e, 0x15, 0x9c, 0xa6, + 0xac, 0x43, 0xc6, 0xf8, 0xa2, 0xbe, 0x22, 0x83, 0x4a, 0x4c, 0x0a, 0x0a, + 0xff, 0xb1, 0x0d, 0x71, 0x94, 0xf1, 0xc1, 0xa5, 0xcf, 0x73, 0x22, 0xec, + 0x1a, 0xe0, 0x96, 0x4e, 0xd4, 0xbf, 0x12, 0x27, 0x46, 0xe0, 0x87, 0xfd, + 0xb5, 0xb3, 0xe9, 0x1b, 0x34, 0x93, 0xd5, 0xbb, 0x98, 0xfa, 0xed, 0x49, + 0xe8, 0x5f, 0x13, 0x0f, 0xc8, 0xa4, 0x59, 0xb7 }; + +/* "Entropy" from buffer */ +static size_t test_offset; +static int hmac_drbg_self_test_entropy( void *data, + unsigned char *buf, size_t len ) +{ + const unsigned char *p = data; + memcpy( buf, p + test_offset, len ); + test_offset += len; + return( 0 ); +} + +#define CHK( c ) if( (c) != 0 ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + return( 1 ); \ + } + +/* + * Checkup routine for HMAC_DRBG with SHA-1 + */ +int mbedtls_hmac_drbg_self_test( int verbose ) +{ + mbedtls_hmac_drbg_context ctx; + unsigned char buf[OUTPUT_LEN]; + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); + + mbedtls_hmac_drbg_init( &ctx ); + + /* + * PR = True + */ + if( verbose != 0 ) + mbedtls_printf( " HMAC_DRBG (PR = True) : " ); + + test_offset = 0; + CHK( mbedtls_hmac_drbg_seed( &ctx, md_info, + hmac_drbg_self_test_entropy, (void *) entropy_pr, + NULL, 0 ) ); + mbedtls_hmac_drbg_set_prediction_resistance( &ctx, MBEDTLS_HMAC_DRBG_PR_ON ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( memcmp( buf, result_pr, OUTPUT_LEN ) ); + mbedtls_hmac_drbg_free( &ctx ); + + mbedtls_hmac_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + /* + * PR = False + */ + if( verbose != 0 ) + mbedtls_printf( " HMAC_DRBG (PR = False) : " ); + + mbedtls_hmac_drbg_init( &ctx ); + + test_offset = 0; + CHK( mbedtls_hmac_drbg_seed( &ctx, md_info, + hmac_drbg_self_test_entropy, (void *) entropy_nopr, + NULL, 0 ) ); + CHK( mbedtls_hmac_drbg_reseed( &ctx, NULL, 0 ) ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( mbedtls_hmac_drbg_random( &ctx, buf, OUTPUT_LEN ) ); + CHK( memcmp( buf, result_nopr, OUTPUT_LEN ) ); + mbedtls_hmac_drbg_free( &ctx ); + + mbedtls_hmac_drbg_free( &ctx ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_HMAC_DRBG_C */ diff --git a/c++/src/connect/mbedtls/mbedtls/aes.h b/c++/src/connect/mbedtls/mbedtls/aes.h new file mode 100644 index 00000000..a36e825a --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/aes.h @@ -0,0 +1,297 @@ +/** + * \file aes.h + * + * \brief AES block cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_AES_H +#define MBEDTLS_AES_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +/* padlock.c and aesni.c rely on these values! */ +#define MBEDTLS_AES_ENCRYPT 1 +#define MBEDTLS_AES_DECRYPT 0 + +#define MBEDTLS_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */ +#define MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */ + +#if !defined(MBEDTLS_AES_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief AES context structure + * + * \note buf is able to hold 32 extra bytes, which can be used: + * - for alignment purposes if VIA padlock is used, and/or + * - to simplify key expansion in the 256-bit case by + * generating an extra round key + */ +typedef struct +{ + int nr; /*!< number of rounds */ + uint32_t *rk; /*!< AES round keys */ + uint32_t buf[68]; /*!< unaligned data */ +} +mbedtls_aes_context; + +/** + * \brief Initialize AES context + * + * \param ctx AES context to be initialized + */ +void mbedtls_aes_init( mbedtls_aes_context *ctx ); + +/** + * \brief Clear AES context + * + * \param ctx AES context to be cleared + */ +void mbedtls_aes_free( mbedtls_aes_context *ctx ); + +/** + * \brief AES key schedule (encryption) + * + * \param ctx AES context to be initialized + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aes_setkey_enc( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief AES key schedule (decryption) + * + * \param ctx AES context to be initialized + * \param key decryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aes_setkey_dec( mbedtls_aes_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief AES-ECB block encryption/decryption + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief AES-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH + */ +int mbedtls_aes_crypt_cbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief AES-CFB128 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_cfb128( mbedtls_aes_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +/** + * \brief AES-CFB8 buffer encryption/decryption. + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_cfb8( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief AES-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_aes_setkey_enc() for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. + * + * \param ctx AES context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int mbedtls_aes_crypt_ctr( mbedtls_aes_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +/** + * \brief Internal AES block encryption function + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_ENCRYPT_ALT) + * + * \param ctx AES context + * \param input Plaintext block + * \param output Output (ciphertext) block + */ +void mbedtls_aes_encrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief Internal AES block decryption function + * (Only exposed to allow overriding it, + * see MBEDTLS_AES_DECRYPT_ALT) + * + * \param ctx AES context + * \param input Ciphertext block + * \param output Output (plaintext) block + */ +void mbedtls_aes_decrypt( mbedtls_aes_context *ctx, + const unsigned char input[16], + unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_AES_ALT */ +#include "aes_alt.h" +#endif /* MBEDTLS_AES_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_aes_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* aes.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/aesni.h b/c++/src/connect/mbedtls/mbedtls/aesni.h new file mode 100644 index 00000000..b1b7f1cd --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/aesni.h @@ -0,0 +1,111 @@ +/** + * \file aesni.h + * + * \brief AES-NI for hardware AES acceleration on some Intel processors + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_AESNI_H +#define MBEDTLS_AESNI_H + +#include "aes.h" + +#define MBEDTLS_AESNI_AES 0x02000000u +#define MBEDTLS_AESNI_CLMUL 0x00000002u + +#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && \ + ( defined(__amd64__) || defined(__x86_64__) ) && \ + ! defined(MBEDTLS_HAVE_X86_64) +#define MBEDTLS_HAVE_X86_64 +#endif + +#if defined(MBEDTLS_HAVE_X86_64) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief AES-NI features detection routine + * + * \param what The feature to detect + * (MBEDTLS_AESNI_AES or MBEDTLS_AESNI_CLMUL) + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +int mbedtls_aesni_has_support( unsigned int what ); + +/** + * \brief AES-NI AES-ECB block en(de)cryption + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 on success (cannot fail) + */ +int mbedtls_aesni_crypt_ecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief GCM multiplication: c = a * b in GF(2^128) + * + * \param c Result + * \param a First operand + * \param b Second operand + * + * \note Both operands and result are bit strings interpreted as + * elements of GF(2^128) as per the GCM spec. + */ +void mbedtls_aesni_gcm_mult( unsigned char c[16], + const unsigned char a[16], + const unsigned char b[16] ); + +/** + * \brief Compute decryption round keys from encryption round keys + * + * \param invkey Round keys for the equivalent inverse cipher + * \param fwdkey Original round keys (for encryption) + * \param nr Number of rounds (that is, number of round keys minus one) + */ +void mbedtls_aesni_inverse_key( unsigned char *invkey, + const unsigned char *fwdkey, int nr ); + +/** + * \brief Perform key expansion (for encryption) + * + * \param rk Destination buffer where the round keys are written + * \param key Encryption key + * \param bits Key size in bits (must be 128, 192 or 256) + * + * \return 0 if successful, or MBEDTLS_ERR_AES_INVALID_KEY_LENGTH + */ +int mbedtls_aesni_setkey_enc( unsigned char *rk, + const unsigned char *key, + size_t bits ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_HAVE_X86_64 */ + +#endif /* MBEDTLS_AESNI_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/arc4.h b/c++/src/connect/mbedtls/mbedtls/arc4.h new file mode 100644 index 00000000..5fc5395a --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/arc4.h @@ -0,0 +1,113 @@ +/** + * \file arc4.h + * + * \brief The ARCFOUR stream cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ARC4_H +#define MBEDTLS_ARC4_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if !defined(MBEDTLS_ARC4_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief ARC4 context structure + */ +typedef struct +{ + int x; /*!< permutation index */ + int y; /*!< permutation index */ + unsigned char m[256]; /*!< permutation table */ +} +mbedtls_arc4_context; + +/** + * \brief Initialize ARC4 context + * + * \param ctx ARC4 context to be initialized + */ +void mbedtls_arc4_init( mbedtls_arc4_context *ctx ); + +/** + * \brief Clear ARC4 context + * + * \param ctx ARC4 context to be cleared + */ +void mbedtls_arc4_free( mbedtls_arc4_context *ctx ); + +/** + * \brief ARC4 key schedule + * + * \param ctx ARC4 context to be setup + * \param key the secret key + * \param keylen length of the key, in bytes + */ +void mbedtls_arc4_setup( mbedtls_arc4_context *ctx, const unsigned char *key, + unsigned int keylen ); + +/** + * \brief ARC4 cipher function + * + * \param ctx ARC4 context + * \param length length of the input data + * \param input buffer holding the input data + * \param output buffer for the output data + * + * \return 0 if successful + */ +int mbedtls_arc4_crypt( mbedtls_arc4_context *ctx, size_t length, const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_ARC4_ALT */ +#include "arc4_alt.h" +#endif /* MBEDTLS_ARC4_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_arc4_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* arc4.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/asn1.h b/c++/src/connect/mbedtls/mbedtls/asn1.h new file mode 100644 index 00000000..082832c8 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/asn1.h @@ -0,0 +1,342 @@ +/** + * \file asn1.h + * + * \brief Generic ASN.1 parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ASN1_H +#define MBEDTLS_ASN1_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_BIGNUM_C) +#include "bignum.h" +#endif + +/** + * \addtogroup asn1_module + * \{ + */ + +/** + * \name ASN1 Error codes + * These error codes are OR'ed to X509 error codes for + * higher error granularity. + * ASN1 is a standard to specify data structures. + * \{ + */ +#define MBEDTLS_ERR_ASN1_OUT_OF_DATA -0x0060 /**< Out of data when parsing an ASN1 data structure. */ +#define MBEDTLS_ERR_ASN1_UNEXPECTED_TAG -0x0062 /**< ASN1 tag was of an unexpected value. */ +#define MBEDTLS_ERR_ASN1_INVALID_LENGTH -0x0064 /**< Error when trying to determine the length or invalid length. */ +#define MBEDTLS_ERR_ASN1_LENGTH_MISMATCH -0x0066 /**< Actual length differs from expected length. */ +#define MBEDTLS_ERR_ASN1_INVALID_DATA -0x0068 /**< Data is invalid. (not used) */ +#define MBEDTLS_ERR_ASN1_ALLOC_FAILED -0x006A /**< Memory allocation failed */ +#define MBEDTLS_ERR_ASN1_BUF_TOO_SMALL -0x006C /**< Buffer too small when writing ASN.1 data structure. */ + +/* \} name */ + +/** + * \name DER constants + * These constants comply with DER encoded the ANS1 type tags. + * DER encoding uses hexadecimal representation. + * An example DER sequence is:\n + * - 0x02 -- tag indicating INTEGER + * - 0x01 -- length in octets + * - 0x05 -- value + * Such sequences are typically read into \c ::mbedtls_x509_buf. + * \{ + */ +#define MBEDTLS_ASN1_BOOLEAN 0x01 +#define MBEDTLS_ASN1_INTEGER 0x02 +#define MBEDTLS_ASN1_BIT_STRING 0x03 +#define MBEDTLS_ASN1_OCTET_STRING 0x04 +#define MBEDTLS_ASN1_NULL 0x05 +#define MBEDTLS_ASN1_OID 0x06 +#define MBEDTLS_ASN1_UTF8_STRING 0x0C +#define MBEDTLS_ASN1_SEQUENCE 0x10 +#define MBEDTLS_ASN1_SET 0x11 +#define MBEDTLS_ASN1_PRINTABLE_STRING 0x13 +#define MBEDTLS_ASN1_T61_STRING 0x14 +#define MBEDTLS_ASN1_IA5_STRING 0x16 +#define MBEDTLS_ASN1_UTC_TIME 0x17 +#define MBEDTLS_ASN1_GENERALIZED_TIME 0x18 +#define MBEDTLS_ASN1_UNIVERSAL_STRING 0x1C +#define MBEDTLS_ASN1_BMP_STRING 0x1E +#define MBEDTLS_ASN1_PRIMITIVE 0x00 +#define MBEDTLS_ASN1_CONSTRUCTED 0x20 +#define MBEDTLS_ASN1_CONTEXT_SPECIFIC 0x80 +/* \} name */ +/* \} addtogroup asn1_module */ + +/** Returns the size of the binary string, without the trailing \\0 */ +#define MBEDTLS_OID_SIZE(x) (sizeof(x) - 1) + +/** + * Compares an mbedtls_asn1_buf structure to a reference OID. + * + * Only works for 'defined' oid_str values (MBEDTLS_OID_HMAC_SHA1), you cannot use a + * 'unsigned char *oid' here! + */ +#define MBEDTLS_OID_CMP(oid_str, oid_buf) \ + ( ( MBEDTLS_OID_SIZE(oid_str) != (oid_buf)->len ) || \ + memcmp( (oid_str), (oid_buf)->p, (oid_buf)->len) != 0 ) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Functions to parse ASN.1 data structures + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef struct mbedtls_asn1_buf +{ + int tag; /**< ASN1 type, e.g. MBEDTLS_ASN1_UTF8_STRING. */ + size_t len; /**< ASN1 length, in octets. */ + unsigned char *p; /**< ASN1 data, e.g. in ASCII. */ +} +mbedtls_asn1_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef struct mbedtls_asn1_bitstring +{ + size_t len; /**< ASN1 length, in octets. */ + unsigned char unused_bits; /**< Number of unused bits at the end of the string */ + unsigned char *p; /**< Raw ASN1 data for the bit string */ +} +mbedtls_asn1_bitstring; + +/** + * Container for a sequence of ASN.1 items + */ +typedef struct mbedtls_asn1_sequence +{ + mbedtls_asn1_buf buf; /**< Buffer containing the given ASN.1 item. */ + struct mbedtls_asn1_sequence *next; /**< The next entry in the sequence. */ +} +mbedtls_asn1_sequence; + +/** + * Container for a sequence or list of 'named' ASN.1 data items + */ +typedef struct mbedtls_asn1_named_data +{ + mbedtls_asn1_buf oid; /**< The object identifier. */ + mbedtls_asn1_buf val; /**< The named value. */ + struct mbedtls_asn1_named_data *next; /**< The next entry in the sequence. */ + unsigned char next_merged; /**< Merge next item into the current one? */ +} +mbedtls_asn1_named_data; + +/** + * \brief Get the length of an ASN.1 element. + * Updates the pointer to immediately behind the length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the value + * + * \return 0 if successful, MBEDTLS_ERR_ASN1_OUT_OF_DATA on reaching + * end of data, MBEDTLS_ERR_ASN1_INVALID_LENGTH if length is + * unparseable. + */ +int mbedtls_asn1_get_len( unsigned char **p, + const unsigned char *end, + size_t *len ); + +/** + * \brief Get the tag and length of the tag. Check for the requested tag. + * Updates the pointer to immediately behind the tag and length. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len The variable that will receive the length + * \param tag The expected tag + * + * \return 0 if successful, MBEDTLS_ERR_ASN1_UNEXPECTED_TAG if tag did + * not match requested tag, or another specific ASN.1 error code. + */ +int mbedtls_asn1_get_tag( unsigned char **p, + const unsigned char *end, + size_t *len, int tag ); + +/** + * \brief Retrieve a boolean ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bool( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * \brief Retrieve an integer ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param val The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_int( unsigned char **p, + const unsigned char *end, + int *val ); + +/** + * \brief Retrieve a bitstring ASN.1 tag and its value. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param bs The variable that will receive the value + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bitstring( unsigned char **p, const unsigned char *end, + mbedtls_asn1_bitstring *bs); + +/** + * \brief Retrieve a bitstring ASN.1 tag without unused bits and its + * value. + * Updates the pointer to the beginning of the bit/octet string. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param len Length of the actual bit/octect string in bytes + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_bitstring_null( unsigned char **p, const unsigned char *end, + size_t *len ); + +/** + * \brief Parses and splits an ASN.1 "SEQUENCE OF " + * Updated the pointer to immediately behind the full sequence tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param cur First variable in the chain to fill + * \param tag Type of sequence + * + * \return 0 if successful or a specific ASN.1 error code. + */ +int mbedtls_asn1_get_sequence_of( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_sequence *cur, + int tag); + +#if defined(MBEDTLS_BIGNUM_C) +/** + * \brief Retrieve a MPI value from an integer ASN.1 tag. + * Updates the pointer to immediately behind the full tag. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param X The MPI that will receive the value + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_mpi( unsigned char **p, + const unsigned char *end, + mbedtls_mpi *X ); +#endif /* MBEDTLS_BIGNUM_C */ + +/** + * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence. + * Updates the pointer to immediately behind the full + * AlgorithmIdentifier. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param alg The buffer to receive the OID + * \param params The buffer to receive the params (if any) + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_alg( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg, mbedtls_asn1_buf *params ); + +/** + * \brief Retrieve an AlgorithmIdentifier ASN.1 sequence with NULL or no + * params. + * Updates the pointer to immediately behind the full + * AlgorithmIdentifier. + * + * \param p The position in the ASN.1 data + * \param end End of data + * \param alg The buffer to receive the OID + * + * \return 0 if successful or a specific ASN.1 or MPI error code. + */ +int mbedtls_asn1_get_alg_null( unsigned char **p, + const unsigned char *end, + mbedtls_asn1_buf *alg ); + +/** + * \brief Find a specific named_data entry in a sequence or list based on + * the OID. + * + * \param list The list to seek through + * \param oid The OID to look for + * \param len Size of the OID + * + * \return NULL if not found, or a pointer to the existing entry. + */ +mbedtls_asn1_named_data *mbedtls_asn1_find_named_data( mbedtls_asn1_named_data *list, + const char *oid, size_t len ); + +/** + * \brief Free a mbedtls_asn1_named_data entry + * + * \param entry The named data entry to free + */ +void mbedtls_asn1_free_named_data( mbedtls_asn1_named_data *entry ); + +/** + * \brief Free all entries in a mbedtls_asn1_named_data list + * Head will be set to NULL + * + * \param head Pointer to the head of the list of named data entries to free + */ +void mbedtls_asn1_free_named_data_list( mbedtls_asn1_named_data **head ); + +#ifdef __cplusplus +} +#endif + +#endif /* asn1.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/asn1write.h b/c++/src/connect/mbedtls/mbedtls/asn1write.h new file mode 100644 index 00000000..73ff32b6 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/asn1write.h @@ -0,0 +1,239 @@ +/** + * \file asn1write.h + * + * \brief ASN.1 buffer writing functionality + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ASN1_WRITE_H +#define MBEDTLS_ASN1_WRITE_H + +#include "asn1.h" + +#define MBEDTLS_ASN1_CHK_ADD(g, f) do { if( ( ret = f ) < 0 ) return( ret ); else \ + g += ret; } while( 0 ) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Write a length field in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param len the length to write + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_len( unsigned char **p, unsigned char *start, size_t len ); + +/** + * \brief Write a ASN.1 tag in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param tag the tag to write + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_tag( unsigned char **p, unsigned char *start, + unsigned char tag ); + +/** + * \brief Write raw buffer data + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param buf data buffer to write + * \param size length of the data buffer + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_raw_buffer( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ); + +#if defined(MBEDTLS_BIGNUM_C) +/** + * \brief Write a big number (MBEDTLS_ASN1_INTEGER) in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param X the MPI to write + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_mpi( unsigned char **p, unsigned char *start, const mbedtls_mpi *X ); +#endif /* MBEDTLS_BIGNUM_C */ + +/** + * \brief Write a NULL tag (MBEDTLS_ASN1_NULL) with zero data in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_null( unsigned char **p, unsigned char *start ); + +/** + * \brief Write an OID tag (MBEDTLS_ASN1_OID) and data in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param oid the OID to write + * \param oid_len length of the OID + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_oid( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len ); + +/** + * \brief Write an AlgorithmIdentifier sequence in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param oid the OID of the algorithm + * \param oid_len length of the OID + * \param par_len length of parameters, which must be already written. + * If 0, NULL parameters are added + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_algorithm_identifier( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + size_t par_len ); + +/** + * \brief Write a boolean tag (MBEDTLS_ASN1_BOOLEAN) and value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param boolean 0 or 1 + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_bool( unsigned char **p, unsigned char *start, int boolean ); + +/** + * \brief Write an int tag (MBEDTLS_ASN1_INTEGER) and value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param val the integer value + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_int( unsigned char **p, unsigned char *start, int val ); + +/** + * \brief Write a printable string tag (MBEDTLS_ASN1_PRINTABLE_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param text the text to write + * \param text_len length of the text + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_printable_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ); + +/** + * \brief Write an IA5 string tag (MBEDTLS_ASN1_IA5_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param text the text to write + * \param text_len length of the text + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_ia5_string( unsigned char **p, unsigned char *start, + const char *text, size_t text_len ); + +/** + * \brief Write a bitstring tag (MBEDTLS_ASN1_BIT_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param buf the bitstring + * \param bits the total number of bits in the bitstring + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_bitstring( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t bits ); + +/** + * \brief Write an octet string tag (MBEDTLS_ASN1_OCTET_STRING) and + * value in ASN.1 format + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param buf data buffer to write + * \param size length of the data buffer + * + * \return the length written or a negative error code + */ +int mbedtls_asn1_write_octet_string( unsigned char **p, unsigned char *start, + const unsigned char *buf, size_t size ); + +/** + * \brief Create or find a specific named_data entry for writing in a + * sequence or list based on the OID. If not already in there, + * a new entry is added to the head of the list. + * Warning: Destructive behaviour for the val data! + * + * \param list Pointer to the location of the head of the list to seek + * through (will be updated in case of a new entry) + * \param oid The OID to look for + * \param oid_len Size of the OID + * \param val Data to store (can be NULL if you want to fill it by hand) + * \param val_len Minimum length of the data buffer needed + * + * \return NULL if if there was a memory allocation error, or a pointer + * to the new / existing entry. + */ +mbedtls_asn1_named_data *mbedtls_asn1_store_named_data( mbedtls_asn1_named_data **list, + const char *oid, size_t oid_len, + const unsigned char *val, + size_t val_len ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_ASN1_WRITE_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/base64.h b/c++/src/connect/mbedtls/mbedtls/base64.h new file mode 100644 index 00000000..352c652d --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/base64.h @@ -0,0 +1,88 @@ +/** + * \file base64.h + * + * \brief RFC 1521 base64 encoding/decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BASE64_H +#define MBEDTLS_BASE64_H + +#include + +#define MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL -0x002A /**< Output buffer too small. */ +#define MBEDTLS_ERR_BASE64_INVALID_CHARACTER -0x002C /**< Invalid character in input. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Encode a buffer into base64 format + * + * \param dst destination buffer + * \param dlen size of the destination buffer + * \param olen number of bytes written + * \param src source buffer + * \param slen amount of data to be encoded + * + * \return 0 if successful, or MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL. + * *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * If that length cannot be represented, then no data is + * written to the buffer and *olen is set to the maximum + * length representable as a size_t. + * + * \note Call this function with dlen = 0 to obtain the + * required buffer size in *olen + */ +int mbedtls_base64_encode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ); + +/** + * \brief Decode a base64-formatted buffer + * + * \param dst destination buffer (can be NULL for checking size) + * \param dlen size of the destination buffer + * \param olen number of bytes written + * \param src source buffer + * \param slen amount of data to be decoded + * + * \return 0 if successful, MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL, or + * MBEDTLS_ERR_BASE64_INVALID_CHARACTER if the input data is + * not correct. *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with *dst = NULL or dlen = 0 to obtain + * the required buffer size in *olen + */ +int mbedtls_base64_decode( unsigned char *dst, size_t dlen, size_t *olen, + const unsigned char *src, size_t slen ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_base64_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* base64.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/bignum.h b/c++/src/connect/mbedtls/mbedtls/bignum.h new file mode 100644 index 00000000..aa51556a --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/bignum.h @@ -0,0 +1,717 @@ +/** + * \file bignum.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BIGNUM_H +#define MBEDTLS_BIGNUM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +#define MBEDTLS_ERR_MPI_FILE_IO_ERROR -0x0002 /**< An error occurred while reading from or writing to a file. */ +#define MBEDTLS_ERR_MPI_BAD_INPUT_DATA -0x0004 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_MPI_INVALID_CHARACTER -0x0006 /**< There is an invalid character in the digit string. */ +#define MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL -0x0008 /**< The buffer is too small to write to. */ +#define MBEDTLS_ERR_MPI_NEGATIVE_VALUE -0x000A /**< The input arguments are negative or result in illegal output. */ +#define MBEDTLS_ERR_MPI_DIVISION_BY_ZERO -0x000C /**< The input argument for division is zero, which is not allowed. */ +#define MBEDTLS_ERR_MPI_NOT_ACCEPTABLE -0x000E /**< The input arguments are not acceptable. */ +#define MBEDTLS_ERR_MPI_ALLOC_FAILED -0x0010 /**< Memory allocation failed. */ + +#define MBEDTLS_MPI_CHK(f) do { if( ( ret = f ) != 0 ) goto cleanup; } while( 0 ) + +/* + * Maximum size MPIs are allowed to grow to in number of limbs. + */ +#define MBEDTLS_MPI_MAX_LIMBS 10000 + +#if !defined(MBEDTLS_MPI_WINDOW_SIZE) +/* + * Maximum window size used for modular exponentiation. Default: 6 + * Minimum value: 1. Maximum value: 6. + * + * Result is an array of ( 2 << MBEDTLS_MPI_WINDOW_SIZE ) MPIs used + * for the sliding window calculation. (So 64 by default) + * + * Reduction in size, reduces speed. + */ +#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +#endif /* !MBEDTLS_MPI_WINDOW_SIZE */ + +#if !defined(MBEDTLS_MPI_MAX_SIZE) +/* + * Maximum size of MPIs allowed in bits and bytes for user-MPIs. + * ( Default: 512 bytes => 4096 bits, Maximum tested: 2048 bytes => 16384 bits ) + * + * Note: Calculations can results temporarily in larger MPIs. So the number + * of limbs required (MBEDTLS_MPI_MAX_LIMBS) is higher. + */ +#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ +#endif /* !MBEDTLS_MPI_MAX_SIZE */ + +#define MBEDTLS_MPI_MAX_BITS ( 8 * MBEDTLS_MPI_MAX_SIZE ) /**< Maximum number of bits for usable MPIs. */ + +/* + * When reading from files with mbedtls_mpi_read_file() and writing to files with + * mbedtls_mpi_write_file() the buffer should have space + * for a (short) label, the MPI (in the provided radix), the newline + * characters and the '\0'. + * + * By default we assume at least a 10 char label, a minimum radix of 10 + * (decimal) and a maximum of 4096 bit numbers (1234 decimal chars). + * Autosized at compile time for at least a 10 char label, a minimum radix + * of 10 (decimal) for a number of MBEDTLS_MPI_MAX_BITS size. + * + * This used to be statically sized to 1250 for a maximum of 4096 bit + * numbers (1234 decimal chars). + * + * Calculate using the formula: + * MBEDTLS_MPI_RW_BUFFER_SIZE = ceil(MBEDTLS_MPI_MAX_BITS / ln(10) * ln(2)) + + * LabelSize + 6 + */ +#define MBEDTLS_MPI_MAX_BITS_SCALE100 ( 100 * MBEDTLS_MPI_MAX_BITS ) +#define MBEDTLS_LN_2_DIV_LN_10_SCALE100 332 +#define MBEDTLS_MPI_RW_BUFFER_SIZE ( ((MBEDTLS_MPI_MAX_BITS_SCALE100 + MBEDTLS_LN_2_DIV_LN_10_SCALE100 - 1) / MBEDTLS_LN_2_DIV_LN_10_SCALE100) + 10 + 6 ) + +/* + * Define the base integer type, architecture-wise. + * + * 32-bit integers can be forced on 64-bit arches (eg. for testing purposes) + * by defining MBEDTLS_HAVE_INT32 and undefining MBEDTLS_HAVE_ASM + */ +#if ( ! defined(MBEDTLS_HAVE_INT32) && \ + defined(_MSC_VER) && defined(_M_AMD64) ) + #define MBEDTLS_HAVE_INT64 + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; +#else + #if ( ! defined(MBEDTLS_HAVE_INT32) && \ + defined(__GNUC__) && ( \ + defined(__amd64__) || defined(__x86_64__) || \ + defined(__ppc64__) || defined(__powerpc64__) || \ + defined(__ia64__) || defined(__alpha__) || \ + (defined(__sparc__) && defined(__arch64__)) || \ + defined(__s390x__) || defined(__mips64) ) ) + #define MBEDTLS_HAVE_INT64 + typedef int64_t mbedtls_mpi_sint; + typedef uint64_t mbedtls_mpi_uint; + /* mbedtls_t_udbl defined as 128-bit unsigned int */ + typedef unsigned int mbedtls_t_udbl __attribute__((mode(TI))); + #define MBEDTLS_HAVE_UDBL + #else + #define MBEDTLS_HAVE_INT32 + typedef int32_t mbedtls_mpi_sint; + typedef uint32_t mbedtls_mpi_uint; + typedef uint64_t mbedtls_t_udbl; + #define MBEDTLS_HAVE_UDBL + #endif /* !MBEDTLS_HAVE_INT32 && __GNUC__ && 64-bit platform */ +#endif /* !MBEDTLS_HAVE_INT32 && _MSC_VER && _M_AMD64 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MPI structure + */ +typedef struct +{ + int s; /*!< integer sign */ + size_t n; /*!< total # of limbs */ + mbedtls_mpi_uint *p; /*!< pointer to limbs */ +} +mbedtls_mpi; + +/** + * \brief Initialize one MPI (make internal references valid) + * This just makes it ready to be set or freed, + * but does not define a value for the MPI. + * + * \param X One MPI to initialize. + */ +void mbedtls_mpi_init( mbedtls_mpi *X ); + +/** + * \brief Unallocate one MPI + * + * \param X One MPI to unallocate. + */ +void mbedtls_mpi_free( mbedtls_mpi *X ); + +/** + * \brief Enlarge to the specified number of limbs + * + * \param X MPI to grow + * \param nblimbs The target number of limbs + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_grow( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief Resize down, keeping at least the specified number of limbs + * + * \param X MPI to shrink + * \param nblimbs The minimum number of limbs to keep + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shrink( mbedtls_mpi *X, size_t nblimbs ); + +/** + * \brief Copy the contents of Y into X + * + * \param X Destination MPI + * \param Y Source MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_copy( mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Swap the contents of X and Y + * + * \param X First MPI value + * \param Y Second MPI value + */ +void mbedtls_mpi_swap( mbedtls_mpi *X, mbedtls_mpi *Y ); + +/** + * \brief Safe conditional assignement X = Y if assign is 1 + * + * \param X MPI to conditionally assign to + * \param Y Value to be assigned + * \param assign 1: perform the assignment, 0: keep X's original value + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \note This function is equivalent to + * if( assign ) mbedtls_mpi_copy( X, Y ); + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + */ +int mbedtls_mpi_safe_cond_assign( mbedtls_mpi *X, const mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Safe conditional swap X <-> Y if swap is 1 + * + * \param X First mbedtls_mpi value + * \param Y Second mbedtls_mpi value + * \param assign 1: perform the swap, 0: keep X and Y's original values + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * + * \note This function is equivalent to + * if( assign ) mbedtls_mpi_swap( X, Y ); + * except that it avoids leaking any information about whether + * the assignment was done or not (the above code may leak + * information through branch prediction and/or memory access + * patterns analysis). + */ +int mbedtls_mpi_safe_cond_swap( mbedtls_mpi *X, mbedtls_mpi *Y, unsigned char assign ); + +/** + * \brief Set value from integer + * + * \param X MPI to set + * \param z Value to use + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_lset( mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Get a specific bit from X + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * + * \return Either a 0 or a 1 + */ +int mbedtls_mpi_get_bit( const mbedtls_mpi *X, size_t pos ); + +/** + * \brief Set a bit of X to a specific value of 0 or 1 + * + * \note Will grow X if necessary to set a bit to 1 in a not yet + * existing limb. Will not grow if bit should be set to 0 + * + * \param X MPI to use + * \param pos Zero-based index of the bit in X + * \param val The value to set the bit to (0 or 1) + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if val is not 0 or 1 + */ +int mbedtls_mpi_set_bit( mbedtls_mpi *X, size_t pos, unsigned char val ); + +/** + * \brief Return the number of zero-bits before the least significant + * '1' bit + * + * Note: Thus also the zero-based index of the least significant '1' bit + * + * \param X MPI to use + */ +size_t mbedtls_mpi_lsb( const mbedtls_mpi *X ); + +/** + * \brief Return the number of bits up to and including the most + * significant '1' bit' + * + * Note: Thus also the one-based index of the most significant '1' bit + * + * \param X MPI to use + */ +size_t mbedtls_mpi_bitlen( const mbedtls_mpi *X ); + +/** + * \brief Return the total size in bytes + * + * \param X MPI to use + */ +size_t mbedtls_mpi_size( const mbedtls_mpi *X ); + +/** + * \brief Import from an ASCII string + * + * \param X Destination MPI + * \param radix Input numeric base + * \param s Null-terminated string buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_mpi_read_string( mbedtls_mpi *X, int radix, const char *s ); + +/** + * \brief Export into an ASCII string + * + * \param X Source MPI + * \param radix Output numeric base + * \param buf Buffer to write the string to + * \param buflen Length of buf + * \param olen Length of the string written, including final NUL byte + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code. + * *olen is always updated to reflect the amount + * of data that has (or would have) been written. + * + * \note Call this function with buflen = 0 to obtain the + * minimum required buffer size in *olen. + */ +int mbedtls_mpi_write_string( const mbedtls_mpi *X, int radix, + char *buf, size_t buflen, size_t *olen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Read X from an opened file + * + * \param X Destination MPI + * \param radix Input numeric base + * \param fin Input file handle + * + * \return 0 if successful, MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if + * the file read buffer is too small or a + * MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_mpi_read_file( mbedtls_mpi *X, int radix, FILE *fin ); + +/** + * \brief Write X into an opened file, or stdout if fout is NULL + * + * \param p Prefix, can be NULL + * \param X Source MPI + * \param radix Output numeric base + * \param fout Output file handle (can be NULL) + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + * + * \note Set fout == NULL to print X on the console. + */ +int mbedtls_mpi_write_file( const char *p, const mbedtls_mpi *X, int radix, FILE *fout ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Import X from unsigned binary data, big endian + * + * \param X Destination MPI + * \param buf Input buffer + * \param buflen Input buffer size + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_read_binary( mbedtls_mpi *X, const unsigned char *buf, size_t buflen ); + +/** + * \brief Export X into unsigned binary data, big endian. + * Always fills the whole buffer, which will start with zeros + * if the number is smaller. + * + * \param X Source MPI + * \param buf Output buffer + * \param buflen Output buffer size + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL if buf isn't large enough + */ +int mbedtls_mpi_write_binary( const mbedtls_mpi *X, unsigned char *buf, size_t buflen ); + +/** + * \brief Left-shift: X <<= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shift_l( mbedtls_mpi *X, size_t count ); + +/** + * \brief Right-shift: X >>= count + * + * \param X MPI to shift + * \param count Amount to shift + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_shift_r( mbedtls_mpi *X, size_t count ); + +/** + * \brief Compare unsigned values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if |X| is greater than |Y|, + * -1 if |X| is lesser than |Y| or + * 0 if |X| is equal to |Y| + */ +int mbedtls_mpi_cmp_abs( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param Y Right-hand MPI + * + * \return 1 if X is greater than Y, + * -1 if X is lesser than Y or + * 0 if X is equal to Y + */ +int mbedtls_mpi_cmp_mpi( const mbedtls_mpi *X, const mbedtls_mpi *Y ); + +/** + * \brief Compare signed values + * + * \param X Left-hand MPI + * \param z The integer value to compare to + * + * \return 1 if X is greater than z, + * -1 if X is lesser than z or + * 0 if X is equal to z + */ +int mbedtls_mpi_cmp_int( const mbedtls_mpi *X, mbedtls_mpi_sint z ); + +/** + * \brief Unsigned addition: X = |A| + |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Unsigned subtraction: X = |A| - |B| + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B is greater than A + */ +int mbedtls_mpi_sub_abs( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed addition: X = A + B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed subtraction: X = A - B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_sub_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Signed addition: X = A + b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to add + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_add_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Signed subtraction: X = A - b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The integer value to subtract + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_sub_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Baseline multiplication: X = A * B + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_mul_mpi( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Baseline multiplication: X = A * b + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param b The unsigned integer value to multiply with + * + * \note b is unsigned + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_mul_int( mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint b ); + +/** + * \brief Division by mbedtls_mpi: A = Q * B + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0 + * + * \note Either Q or R can be NULL. + */ +int mbedtls_mpi_div_mpi( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Division by int: A = Q * b + R + * + * \param Q Destination MPI for the quotient + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0 + * + * \note Either Q or R can be NULL. + */ +int mbedtls_mpi_div_int( mbedtls_mpi *Q, mbedtls_mpi *R, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Modulo: R = A mod B + * + * \param R Destination MPI for the rest value + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if B == 0, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if B < 0 + */ +int mbedtls_mpi_mod_mpi( mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Modulo: r = A mod b + * + * \param r Destination mbedtls_mpi_uint + * \param A Left-hand MPI + * \param b Integer to divide by + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_DIVISION_BY_ZERO if b == 0, + * MBEDTLS_ERR_MPI_NEGATIVE_VALUE if b < 0 + */ +int mbedtls_mpi_mod_int( mbedtls_mpi_uint *r, const mbedtls_mpi *A, mbedtls_mpi_sint b ); + +/** + * \brief Sliding-window exponentiation: X = A^E mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param E Exponent MPI + * \param N Modular MPI + * \param _RR Speed-up MPI used for recalculations + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is negative or even or + * if E is negative + * + * \note _RR is used to avoid re-computing R*R mod N across + * multiple calls, which speeds up things a bit. It can + * be set to NULL if the extra performance is unneeded. + */ +int mbedtls_mpi_exp_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR ); + +/** + * \brief Fill an MPI X with size bytes of random + * + * \param X Destination MPI + * \param size Size in bytes + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_fill_random( mbedtls_mpi *X, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Greatest common divisor: G = gcd(A, B) + * + * \param G Destination MPI + * \param A Left-hand MPI + * \param B Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_mpi_gcd( mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B ); + +/** + * \brief Modular inverse: X = A^-1 mod N + * + * \param X Destination MPI + * \param A Left-hand MPI + * \param N Right-hand MPI + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if N is negative or nil + MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if A has no inverse mod N + */ +int mbedtls_mpi_inv_mod( mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N ); + +/** + * \brief Miller-Rabin primality test + * + * \param X MPI to check + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_NOT_ACCEPTABLE if X is not prime + */ +int mbedtls_mpi_is_prime( const mbedtls_mpi *X, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Prime number generation + * + * \param X Destination MPI + * \param nbits Required size of X in bits + * ( 3 <= nbits <= MBEDTLS_MPI_MAX_BITS ) + * \param dh_flag If 1, then (X-1)/2 will be prime too + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful (probably prime), + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_MPI_BAD_INPUT_DATA if nbits is < 3 + */ +int mbedtls_mpi_gen_prime( mbedtls_mpi *X, size_t nbits, int dh_flag, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_mpi_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* bignum.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/blowfish.h b/c++/src/connect/mbedtls/mbedtls/blowfish.h new file mode 100644 index 00000000..34626eef --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/blowfish.h @@ -0,0 +1,203 @@ +/** + * \file blowfish.h + * + * \brief Blowfish block cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_BLOWFISH_H +#define MBEDTLS_BLOWFISH_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_BLOWFISH_ENCRYPT 1 +#define MBEDTLS_BLOWFISH_DECRYPT 0 +#define MBEDTLS_BLOWFISH_MAX_KEY_BITS 448 +#define MBEDTLS_BLOWFISH_MIN_KEY_BITS 32 +#define MBEDTLS_BLOWFISH_ROUNDS 16 /**< Rounds to use. When increasing this value, make sure to extend the initialisation vectors */ +#define MBEDTLS_BLOWFISH_BLOCKSIZE 8 /* Blowfish uses 64 bit blocks */ + +#define MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH -0x0016 /**< Invalid key length. */ +#define MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH -0x0018 /**< Invalid data input length. */ + +#if !defined(MBEDTLS_BLOWFISH_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Blowfish context structure + */ +typedef struct +{ + uint32_t P[MBEDTLS_BLOWFISH_ROUNDS + 2]; /*!< Blowfish round keys */ + uint32_t S[4][256]; /*!< key dependent S-boxes */ +} +mbedtls_blowfish_context; + +/** + * \brief Initialize Blowfish context + * + * \param ctx Blowfish context to be initialized + */ +void mbedtls_blowfish_init( mbedtls_blowfish_context *ctx ); + +/** + * \brief Clear Blowfish context + * + * \param ctx Blowfish context to be cleared + */ +void mbedtls_blowfish_free( mbedtls_blowfish_context *ctx ); + +/** + * \brief Blowfish key schedule + * + * \param ctx Blowfish context to be initialized + * \param key encryption key + * \param keybits must be between 32 and 448 bits + * + * \return 0 if successful, or MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH + */ +int mbedtls_blowfish_setkey( mbedtls_blowfish_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief Blowfish-ECB block encryption/decryption + * + * \param ctx Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT + * \param input 8-byte input block + * \param output 8-byte output block + * + * \return 0 if successful + */ +int mbedtls_blowfish_crypt_ecb( mbedtls_blowfish_context *ctx, + int mode, + const unsigned char input[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char output[MBEDTLS_BLOWFISH_BLOCKSIZE] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief Blowfish-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (8 bytes) + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or + * MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH + */ +int mbedtls_blowfish_crypt_cbc( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief Blowfish CFB buffer encryption/decryption. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx Blowfish context + * \param mode MBEDTLS_BLOWFISH_ENCRYPT or MBEDTLS_BLOWFISH_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful + */ +int mbedtls_blowfish_crypt_cfb64( mbedtls_blowfish_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /*MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief Blowfish-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * \param ctx Blowfish context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 64-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int mbedtls_blowfish_crypt_ctr( mbedtls_blowfish_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[MBEDTLS_BLOWFISH_BLOCKSIZE], + unsigned char stream_block[MBEDTLS_BLOWFISH_BLOCKSIZE], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_BLOWFISH_ALT */ +#include "blowfish_alt.h" +#endif /* MBEDTLS_BLOWFISH_ALT */ + +#endif /* blowfish.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/bn_mul.h b/c++/src/connect/mbedtls/mbedtls/bn_mul.h new file mode 100644 index 00000000..cac3f145 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/bn_mul.h @@ -0,0 +1,885 @@ +/** + * \file bn_mul.h + * + * \brief Multi-precision integer library + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * Multiply source vector [s] with b, add result + * to destination vector [d] and set carry c. + * + * Currently supports: + * + * . IA-32 (386+) . AMD64 / EM64T + * . IA-32 (SSE2) . Motorola 68000 + * . PowerPC, 32-bit . MicroBlaze + * . PowerPC, 64-bit . TriCore + * . SPARC v8 . ARM v3+ + * . Alpha . MIPS32 + * . C, longlong . C, generic + */ +#ifndef MBEDTLS_BN_MUL_H +#define MBEDTLS_BN_MUL_H + +#include "bignum.h" + +#if defined(MBEDTLS_HAVE_ASM) + +#ifndef asm +#define asm __asm +#endif + +/* armcc5 --gnu defines __GNUC__ but doesn't support GNU's extended asm */ +#if defined(__GNUC__) && \ + ( !defined(__ARMCC_VERSION) || __ARMCC_VERSION >= 6000000 ) +#if defined(__i386__) + +#define MULADDC_INIT \ + asm( \ + "movl %%ebx, %0 \n\t" \ + "movl %5, %%esi \n\t" \ + "movl %6, %%edi \n\t" \ + "movl %7, %%ecx \n\t" \ + "movl %8, %%ebx \n\t" + +#define MULADDC_CORE \ + "lodsl \n\t" \ + "mull %%ebx \n\t" \ + "addl %%ecx, %%eax \n\t" \ + "adcl $0, %%edx \n\t" \ + "addl (%%edi), %%eax \n\t" \ + "adcl $0, %%edx \n\t" \ + "movl %%edx, %%ecx \n\t" \ + "stosl \n\t" + +#if defined(MBEDTLS_HAVE_SSE2) + +#define MULADDC_HUIT \ + "movd %%ecx, %%mm1 \n\t" \ + "movd %%ebx, %%mm0 \n\t" \ + "movd (%%edi), %%mm3 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd (%%esi), %%mm2 \n\t" \ + "pmuludq %%mm0, %%mm2 \n\t" \ + "movd 4(%%esi), %%mm4 \n\t" \ + "pmuludq %%mm0, %%mm4 \n\t" \ + "movd 8(%%esi), %%mm6 \n\t" \ + "pmuludq %%mm0, %%mm6 \n\t" \ + "movd 12(%%esi), %%mm7 \n\t" \ + "pmuludq %%mm0, %%mm7 \n\t" \ + "paddq %%mm2, %%mm1 \n\t" \ + "movd 4(%%edi), %%mm3 \n\t" \ + "paddq %%mm4, %%mm3 \n\t" \ + "movd 8(%%edi), %%mm5 \n\t" \ + "paddq %%mm6, %%mm5 \n\t" \ + "movd 12(%%edi), %%mm4 \n\t" \ + "paddq %%mm4, %%mm7 \n\t" \ + "movd %%mm1, (%%edi) \n\t" \ + "movd 16(%%esi), %%mm2 \n\t" \ + "pmuludq %%mm0, %%mm2 \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd 20(%%esi), %%mm4 \n\t" \ + "pmuludq %%mm0, %%mm4 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd 24(%%esi), %%mm6 \n\t" \ + "pmuludq %%mm0, %%mm6 \n\t" \ + "movd %%mm1, 4(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd 28(%%esi), %%mm3 \n\t" \ + "pmuludq %%mm0, %%mm3 \n\t" \ + "paddq %%mm5, %%mm1 \n\t" \ + "movd 16(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm2 \n\t" \ + "movd %%mm1, 8(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm7, %%mm1 \n\t" \ + "movd 20(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm4 \n\t" \ + "movd %%mm1, 12(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm2, %%mm1 \n\t" \ + "movd 24(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm6 \n\t" \ + "movd %%mm1, 16(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm4, %%mm1 \n\t" \ + "movd 28(%%edi), %%mm5 \n\t" \ + "paddq %%mm5, %%mm3 \n\t" \ + "movd %%mm1, 20(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm6, %%mm1 \n\t" \ + "movd %%mm1, 24(%%edi) \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "paddq %%mm3, %%mm1 \n\t" \ + "movd %%mm1, 28(%%edi) \n\t" \ + "addl $32, %%edi \n\t" \ + "addl $32, %%esi \n\t" \ + "psrlq $32, %%mm1 \n\t" \ + "movd %%mm1, %%ecx \n\t" + +#define MULADDC_STOP \ + "emms \n\t" \ + "movl %4, %%ebx \n\t" \ + "movl %%ecx, %1 \n\t" \ + "movl %%edi, %2 \n\t" \ + "movl %%esi, %3 \n\t" \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ecx", "edx", "esi", "edi" \ + ); + +#else + +#define MULADDC_STOP \ + "movl %4, %%ebx \n\t" \ + "movl %%ecx, %1 \n\t" \ + "movl %%edi, %2 \n\t" \ + "movl %%esi, %3 \n\t" \ + : "=m" (t), "=m" (c), "=m" (d), "=m" (s) \ + : "m" (t), "m" (s), "m" (d), "m" (c), "m" (b) \ + : "eax", "ecx", "edx", "esi", "edi" \ + ); +#endif /* SSE2 */ +#endif /* i386 */ + +#if defined(__amd64__) || defined (__x86_64__) + +#define MULADDC_INIT \ + asm( \ + "xorq %%r8, %%r8 \n\t" + +#define MULADDC_CORE \ + "movq (%%rsi), %%rax \n\t" \ + "mulq %%rbx \n\t" \ + "addq $8, %%rsi \n\t" \ + "addq %%rcx, %%rax \n\t" \ + "movq %%r8, %%rcx \n\t" \ + "adcq $0, %%rdx \n\t" \ + "nop \n\t" \ + "addq %%rax, (%%rdi) \n\t" \ + "adcq %%rdx, %%rcx \n\t" \ + "addq $8, %%rdi \n\t" + +#define MULADDC_STOP \ + : "+c" (c), "+D" (d), "+S" (s) \ + : "b" (b) \ + : "rax", "rdx", "r8" \ + ); + +#endif /* AMD64 */ + +#if defined(__mc68020__) || defined(__mcpu32__) + +#define MULADDC_INIT \ + asm( \ + "movl %3, %%a2 \n\t" \ + "movl %4, %%a3 \n\t" \ + "movl %5, %%d3 \n\t" \ + "movl %6, %%d2 \n\t" \ + "moveq #0, %%d0 \n\t" + +#define MULADDC_CORE \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "moveq #0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "addxl %%d4, %%d3 \n\t" + +#define MULADDC_STOP \ + "movl %%d3, %0 \n\t" \ + "movl %%a3, %1 \n\t" \ + "movl %%a2, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "d0", "d1", "d2", "d3", "d4", "a2", "a3" \ + ); + +#define MULADDC_HUIT \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d4:%%d1 \n\t" \ + "addxl %%d3, %%d1 \n\t" \ + "addxl %%d0, %%d4 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "movel %%a2@+, %%d1 \n\t" \ + "mulul %%d2, %%d3:%%d1 \n\t" \ + "addxl %%d4, %%d1 \n\t" \ + "addxl %%d0, %%d3 \n\t" \ + "addl %%d1, %%a3@+ \n\t" \ + "addxl %%d0, %%d3 \n\t" + +#endif /* MC68000 */ + +#if defined(__powerpc64__) || defined(__ppc64__) + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( \ + "ld r3, %3 \n\t" \ + "ld r4, %4 \n\t" \ + "ld r5, %5 \n\t" \ + "ld r6, %6 \n\t" \ + "addi r3, r3, -8 \n\t" \ + "addi r4, r4, -8 \n\t" \ + "addic r5, r5, 0 \n\t" + +#define MULADDC_CORE \ + "ldu r7, 8(r3) \n\t" \ + "mulld r8, r7, r6 \n\t" \ + "mulhdu r9, r7, r6 \n\t" \ + "adde r8, r8, r5 \n\t" \ + "ld r7, 8(r4) \n\t" \ + "addze r5, r9 \n\t" \ + "addc r8, r8, r7 \n\t" \ + "stdu r8, 8(r4) \n\t" + +#define MULADDC_STOP \ + "addze r5, r5 \n\t" \ + "addi r4, r4, 8 \n\t" \ + "addi r3, r3, 8 \n\t" \ + "std r5, %0 \n\t" \ + "std r4, %1 \n\t" \ + "std r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + + +#else /* __MACH__ && __APPLE__ */ + +#define MULADDC_INIT \ + asm( \ + "ld %%r3, %3 \n\t" \ + "ld %%r4, %4 \n\t" \ + "ld %%r5, %5 \n\t" \ + "ld %%r6, %6 \n\t" \ + "addi %%r3, %%r3, -8 \n\t" \ + "addi %%r4, %%r4, -8 \n\t" \ + "addic %%r5, %%r5, 0 \n\t" + +#define MULADDC_CORE \ + "ldu %%r7, 8(%%r3) \n\t" \ + "mulld %%r8, %%r7, %%r6 \n\t" \ + "mulhdu %%r9, %%r7, %%r6 \n\t" \ + "adde %%r8, %%r8, %%r5 \n\t" \ + "ld %%r7, 8(%%r4) \n\t" \ + "addze %%r5, %%r9 \n\t" \ + "addc %%r8, %%r8, %%r7 \n\t" \ + "stdu %%r8, 8(%%r4) \n\t" + +#define MULADDC_STOP \ + "addze %%r5, %%r5 \n\t" \ + "addi %%r4, %%r4, 8 \n\t" \ + "addi %%r3, %%r3, 8 \n\t" \ + "std %%r5, %0 \n\t" \ + "std %%r4, %1 \n\t" \ + "std %%r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#endif /* __MACH__ && __APPLE__ */ + +#elif defined(__powerpc__) || defined(__ppc__) /* end PPC64/begin PPC32 */ + +#if defined(__MACH__) && defined(__APPLE__) + +#define MULADDC_INIT \ + asm( \ + "lwz r3, %3 \n\t" \ + "lwz r4, %4 \n\t" \ + "lwz r5, %5 \n\t" \ + "lwz r6, %6 \n\t" \ + "addi r3, r3, -4 \n\t" \ + "addi r4, r4, -4 \n\t" \ + "addic r5, r5, 0 \n\t" + +#define MULADDC_CORE \ + "lwzu r7, 4(r3) \n\t" \ + "mullw r8, r7, r6 \n\t" \ + "mulhwu r9, r7, r6 \n\t" \ + "adde r8, r8, r5 \n\t" \ + "lwz r7, 4(r4) \n\t" \ + "addze r5, r9 \n\t" \ + "addc r8, r8, r7 \n\t" \ + "stwu r8, 4(r4) \n\t" + +#define MULADDC_STOP \ + "addze r5, r5 \n\t" \ + "addi r4, r4, 4 \n\t" \ + "addi r3, r3, 4 \n\t" \ + "stw r5, %0 \n\t" \ + "stw r4, %1 \n\t" \ + "stw r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#else /* __MACH__ && __APPLE__ */ + +#define MULADDC_INIT \ + asm( \ + "lwz %%r3, %3 \n\t" \ + "lwz %%r4, %4 \n\t" \ + "lwz %%r5, %5 \n\t" \ + "lwz %%r6, %6 \n\t" \ + "addi %%r3, %%r3, -4 \n\t" \ + "addi %%r4, %%r4, -4 \n\t" \ + "addic %%r5, %%r5, 0 \n\t" + +#define MULADDC_CORE \ + "lwzu %%r7, 4(%%r3) \n\t" \ + "mullw %%r8, %%r7, %%r6 \n\t" \ + "mulhwu %%r9, %%r7, %%r6 \n\t" \ + "adde %%r8, %%r8, %%r5 \n\t" \ + "lwz %%r7, 4(%%r4) \n\t" \ + "addze %%r5, %%r9 \n\t" \ + "addc %%r8, %%r8, %%r7 \n\t" \ + "stwu %%r8, 4(%%r4) \n\t" + +#define MULADDC_STOP \ + "addze %%r5, %%r5 \n\t" \ + "addi %%r4, %%r4, 4 \n\t" \ + "addi %%r3, %%r3, 4 \n\t" \ + "stw %%r5, %0 \n\t" \ + "stw %%r4, %1 \n\t" \ + "stw %%r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4", "r5", "r6", "r7", "r8", "r9" \ + ); + +#endif /* __MACH__ && __APPLE__ */ + +#endif /* PPC32 */ + +/* + * The Sparc(64) assembly is reported to be broken. + * Disable it for now, until we're able to fix it. + */ +#if 0 && defined(__sparc__) +#if defined(__sparc64__) + +#define MULADDC_INIT \ + asm( \ + "ldx %3, %%o0 \n\t" \ + "ldx %4, %%o1 \n\t" \ + "ld %5, %%o2 \n\t" \ + "ld %6, %%o3 \n\t" + +#define MULADDC_CORE \ + "ld [%%o0], %%o4 \n\t" \ + "inc 4, %%o0 \n\t" \ + "ld [%%o1], %%o5 \n\t" \ + "umul %%o3, %%o4, %%o4 \n\t" \ + "addcc %%o4, %%o2, %%o4 \n\t" \ + "rd %%y, %%g1 \n\t" \ + "addx %%g1, 0, %%g1 \n\t" \ + "addcc %%o4, %%o5, %%o4 \n\t" \ + "st %%o4, [%%o1] \n\t" \ + "addx %%g1, 0, %%o2 \n\t" \ + "inc 4, %%o1 \n\t" + + #define MULADDC_STOP \ + "st %%o2, %0 \n\t" \ + "stx %%o1, %1 \n\t" \ + "stx %%o0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); + +#else /* __sparc64__ */ + +#define MULADDC_INIT \ + asm( \ + "ld %3, %%o0 \n\t" \ + "ld %4, %%o1 \n\t" \ + "ld %5, %%o2 \n\t" \ + "ld %6, %%o3 \n\t" + +#define MULADDC_CORE \ + "ld [%%o0], %%o4 \n\t" \ + "inc 4, %%o0 \n\t" \ + "ld [%%o1], %%o5 \n\t" \ + "umul %%o3, %%o4, %%o4 \n\t" \ + "addcc %%o4, %%o2, %%o4 \n\t" \ + "rd %%y, %%g1 \n\t" \ + "addx %%g1, 0, %%g1 \n\t" \ + "addcc %%o4, %%o5, %%o4 \n\t" \ + "st %%o4, [%%o1] \n\t" \ + "addx %%g1, 0, %%o2 \n\t" \ + "inc 4, %%o1 \n\t" + +#define MULADDC_STOP \ + "st %%o2, %0 \n\t" \ + "st %%o1, %1 \n\t" \ + "st %%o0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "g1", "o0", "o1", "o2", "o3", "o4", \ + "o5" \ + ); + +#endif /* __sparc64__ */ +#endif /* __sparc__ */ + +#if defined(__microblaze__) || defined(microblaze) + +#define MULADDC_INIT \ + asm( \ + "lwi r3, %3 \n\t" \ + "lwi r4, %4 \n\t" \ + "lwi r5, %5 \n\t" \ + "lwi r6, %6 \n\t" \ + "andi r7, r6, 0xffff \n\t" \ + "bsrli r6, r6, 16 \n\t" + +#define MULADDC_CORE \ + "lhui r8, r3, 0 \n\t" \ + "addi r3, r3, 2 \n\t" \ + "lhui r9, r3, 0 \n\t" \ + "addi r3, r3, 2 \n\t" \ + "mul r10, r9, r6 \n\t" \ + "mul r11, r8, r7 \n\t" \ + "mul r12, r9, r7 \n\t" \ + "mul r13, r8, r6 \n\t" \ + "bsrli r8, r10, 16 \n\t" \ + "bsrli r9, r11, 16 \n\t" \ + "add r13, r13, r8 \n\t" \ + "add r13, r13, r9 \n\t" \ + "bslli r10, r10, 16 \n\t" \ + "bslli r11, r11, 16 \n\t" \ + "add r12, r12, r10 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "add r12, r12, r11 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "lwi r10, r4, 0 \n\t" \ + "add r12, r12, r10 \n\t" \ + "addc r13, r13, r0 \n\t" \ + "add r12, r12, r5 \n\t" \ + "addc r5, r13, r0 \n\t" \ + "swi r12, r4, 0 \n\t" \ + "addi r4, r4, 4 \n\t" + +#define MULADDC_STOP \ + "swi r5, %0 \n\t" \ + "swi r4, %1 \n\t" \ + "swi r3, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r3", "r4" "r5", "r6", "r7", "r8", \ + "r9", "r10", "r11", "r12", "r13" \ + ); + +#endif /* MicroBlaze */ + +#if defined(__tricore__) + +#define MULADDC_INIT \ + asm( \ + "ld.a %%a2, %3 \n\t" \ + "ld.a %%a3, %4 \n\t" \ + "ld.w %%d4, %5 \n\t" \ + "ld.w %%d1, %6 \n\t" \ + "xor %%d5, %%d5 \n\t" + +#define MULADDC_CORE \ + "ld.w %%d0, [%%a2+] \n\t" \ + "madd.u %%e2, %%e4, %%d0, %%d1 \n\t" \ + "ld.w %%d0, [%%a3] \n\t" \ + "addx %%d2, %%d2, %%d0 \n\t" \ + "addc %%d3, %%d3, 0 \n\t" \ + "mov %%d4, %%d3 \n\t" \ + "st.w [%%a3+], %%d2 \n\t" + +#define MULADDC_STOP \ + "st.w %0, %%d4 \n\t" \ + "st.a %1, %%a3 \n\t" \ + "st.a %2, %%a2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "d0", "d1", "e2", "d4", "a2", "a3" \ + ); + +#endif /* TriCore */ + +/* + * gcc -O0 by default uses r7 for the frame pointer, so it complains about our + * use of r7 below, unless -fomit-frame-pointer is passed. Unfortunately, + * passing that option is not easy when building with yotta. + * + * On the other hand, -fomit-frame-pointer is implied by any -Ox options with + * x !=0, which we can detect using __OPTIMIZE__ (which is also defined by + * clang and armcc5 under the same conditions). + * + * So, only use the optimized assembly below for optimized build, which avoids + * the build error and is pretty reasonable anyway. + */ +#if defined(__GNUC__) && !defined(__OPTIMIZE__) +#define MULADDC_CANNOT_USE_R7 +#endif + +#if defined(__arm__) && !defined(MULADDC_CANNOT_USE_R7) + +#if defined(__thumb__) && !defined(__thumb2__) + +#define MULADDC_INIT \ + asm( \ + "ldr r0, %3 \n\t" \ + "ldr r1, %4 \n\t" \ + "ldr r2, %5 \n\t" \ + "ldr r3, %6 \n\t" \ + "lsr r7, r3, #16 \n\t" \ + "mov r9, r7 \n\t" \ + "lsl r7, r3, #16 \n\t" \ + "lsr r7, r7, #16 \n\t" \ + "mov r8, r7 \n\t" + +#define MULADDC_CORE \ + "ldmia r0!, {r6} \n\t" \ + "lsr r7, r6, #16 \n\t" \ + "lsl r6, r6, #16 \n\t" \ + "lsr r6, r6, #16 \n\t" \ + "mov r4, r8 \n\t" \ + "mul r4, r6 \n\t" \ + "mov r3, r9 \n\t" \ + "mul r6, r3 \n\t" \ + "mov r5, r9 \n\t" \ + "mul r5, r7 \n\t" \ + "mov r3, r8 \n\t" \ + "mul r7, r3 \n\t" \ + "lsr r3, r6, #16 \n\t" \ + "add r5, r5, r3 \n\t" \ + "lsr r3, r7, #16 \n\t" \ + "add r5, r5, r3 \n\t" \ + "add r4, r4, r2 \n\t" \ + "mov r2, #0 \n\t" \ + "adc r5, r2 \n\t" \ + "lsl r3, r6, #16 \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r5, r2 \n\t" \ + "lsl r3, r7, #16 \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r5, r2 \n\t" \ + "ldr r3, [r1] \n\t" \ + "add r4, r4, r3 \n\t" \ + "adc r2, r5 \n\t" \ + "stmia r1!, {r4} \n\t" + +#define MULADDC_STOP \ + "str r2, %0 \n\t" \ + "str r1, %1 \n\t" \ + "str r0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "r8", "r9", "cc" \ + ); + +#else + +#define MULADDC_INIT \ + asm( \ + "ldr r0, %3 \n\t" \ + "ldr r1, %4 \n\t" \ + "ldr r2, %5 \n\t" \ + "ldr r3, %6 \n\t" + +#define MULADDC_CORE \ + "ldr r4, [r0], #4 \n\t" \ + "mov r5, #0 \n\t" \ + "ldr r6, [r1] \n\t" \ + "umlal r2, r5, r3, r4 \n\t" \ + "adds r7, r6, r2 \n\t" \ + "adc r2, r5, #0 \n\t" \ + "str r7, [r1], #4 \n\t" + +#define MULADDC_STOP \ + "str r2, %0 \n\t" \ + "str r1, %1 \n\t" \ + "str r0, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "r0", "r1", "r2", "r3", "r4", "r5", \ + "r6", "r7", "cc" \ + ); + +#endif /* Thumb */ + +#endif /* ARMv3 */ + +#if defined(__alpha__) + +#define MULADDC_INIT \ + asm( \ + "ldq $1, %3 \n\t" \ + "ldq $2, %4 \n\t" \ + "ldq $3, %5 \n\t" \ + "ldq $4, %6 \n\t" + +#define MULADDC_CORE \ + "ldq $6, 0($1) \n\t" \ + "addq $1, 8, $1 \n\t" \ + "mulq $6, $4, $7 \n\t" \ + "umulh $6, $4, $6 \n\t" \ + "addq $7, $3, $7 \n\t" \ + "cmpult $7, $3, $3 \n\t" \ + "ldq $5, 0($2) \n\t" \ + "addq $7, $5, $7 \n\t" \ + "cmpult $7, $5, $5 \n\t" \ + "stq $7, 0($2) \n\t" \ + "addq $2, 8, $2 \n\t" \ + "addq $6, $3, $3 \n\t" \ + "addq $5, $3, $3 \n\t" + +#define MULADDC_STOP \ + "stq $3, %0 \n\t" \ + "stq $2, %1 \n\t" \ + "stq $1, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "$1", "$2", "$3", "$4", "$5", "$6", "$7" \ + ); +#endif /* Alpha */ + +#if defined(__mips__) && !defined(__mips64) + +#define MULADDC_INIT \ + asm( \ + "lw $10, %3 \n\t" \ + "lw $11, %4 \n\t" \ + "lw $12, %5 \n\t" \ + "lw $13, %6 \n\t" + +#define MULADDC_CORE \ + "lw $14, 0($10) \n\t" \ + "multu $13, $14 \n\t" \ + "addi $10, $10, 4 \n\t" \ + "mflo $14 \n\t" \ + "mfhi $9 \n\t" \ + "addu $14, $12, $14 \n\t" \ + "lw $15, 0($11) \n\t" \ + "sltu $12, $14, $12 \n\t" \ + "addu $15, $14, $15 \n\t" \ + "sltu $14, $15, $14 \n\t" \ + "addu $12, $12, $9 \n\t" \ + "sw $15, 0($11) \n\t" \ + "addu $12, $12, $14 \n\t" \ + "addi $11, $11, 4 \n\t" + +#define MULADDC_STOP \ + "sw $12, %0 \n\t" \ + "sw $11, %1 \n\t" \ + "sw $10, %2 \n\t" \ + : "=m" (c), "=m" (d), "=m" (s) \ + : "m" (s), "m" (d), "m" (c), "m" (b) \ + : "$9", "$10", "$11", "$12", "$13", "$14", "$15" \ + ); + +#endif /* MIPS */ +#endif /* GNUC */ + +#if (defined(_MSC_VER) && defined(_M_IX86)) || defined(__WATCOMC__) + +#define MULADDC_INIT \ + __asm mov esi, s \ + __asm mov edi, d \ + __asm mov ecx, c \ + __asm mov ebx, b + +#define MULADDC_CORE \ + __asm lodsd \ + __asm mul ebx \ + __asm add eax, ecx \ + __asm adc edx, 0 \ + __asm add eax, [edi] \ + __asm adc edx, 0 \ + __asm mov ecx, edx \ + __asm stosd + +#if defined(MBEDTLS_HAVE_SSE2) + +#define EMIT __asm _emit + +#define MULADDC_HUIT \ + EMIT 0x0F EMIT 0x6E EMIT 0xC9 \ + EMIT 0x0F EMIT 0x6E EMIT 0xC3 \ + EMIT 0x0F EMIT 0x6E EMIT 0x1F \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x16 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x04 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x08 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x6E EMIT 0x7E EMIT 0x0C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x5F EMIT 0x04 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x08 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xEE \ + EMIT 0x0F EMIT 0x6E EMIT 0x67 EMIT 0x0C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xFC \ + EMIT 0x0F EMIT 0x7E EMIT 0x0F \ + EMIT 0x0F EMIT 0x6E EMIT 0x56 EMIT 0x10 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD0 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x66 EMIT 0x14 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xE0 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x6E EMIT 0x76 EMIT 0x18 \ + EMIT 0x0F EMIT 0xF4 EMIT 0xF0 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x04 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x6E EMIT 0x5E EMIT 0x1C \ + EMIT 0x0F EMIT 0xF4 EMIT 0xD8 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCD \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x10 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xD5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x08 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCF \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x14 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xE5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x0C \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCA \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x18 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xF5 \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x10 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCC \ + EMIT 0x0F EMIT 0x6E EMIT 0x6F EMIT 0x1C \ + EMIT 0x0F EMIT 0xD4 EMIT 0xDD \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x14 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCE \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x18 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0xD4 EMIT 0xCB \ + EMIT 0x0F EMIT 0x7E EMIT 0x4F EMIT 0x1C \ + EMIT 0x83 EMIT 0xC7 EMIT 0x20 \ + EMIT 0x83 EMIT 0xC6 EMIT 0x20 \ + EMIT 0x0F EMIT 0x73 EMIT 0xD1 EMIT 0x20 \ + EMIT 0x0F EMIT 0x7E EMIT 0xC9 + +#define MULADDC_STOP \ + EMIT 0x0F EMIT 0x77 \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#else + +#define MULADDC_STOP \ + __asm mov c, ecx \ + __asm mov d, edi \ + __asm mov s, esi \ + +#endif /* SSE2 */ +#endif /* MSVC */ + +#endif /* MBEDTLS_HAVE_ASM */ + +#if !defined(MULADDC_CORE) +#if defined(MBEDTLS_HAVE_UDBL) + +#define MULADDC_INIT \ +{ \ + mbedtls_t_udbl r; \ + mbedtls_mpi_uint r0, r1; + +#define MULADDC_CORE \ + r = *(s++) * (mbedtls_t_udbl) b; \ + r0 = (mbedtls_mpi_uint) r; \ + r1 = (mbedtls_mpi_uint)( r >> biL ); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#else +#define MULADDC_INIT \ +{ \ + mbedtls_mpi_uint s0, s1, b0, b1; \ + mbedtls_mpi_uint r0, r1, rx, ry; \ + b0 = ( b << biH ) >> biH; \ + b1 = ( b >> biH ); + +#define MULADDC_CORE \ + s0 = ( *s << biH ) >> biH; \ + s1 = ( *s >> biH ); s++; \ + rx = s0 * b1; r0 = s0 * b0; \ + ry = s1 * b0; r1 = s1 * b1; \ + r1 += ( rx >> biH ); \ + r1 += ( ry >> biH ); \ + rx <<= biH; ry <<= biH; \ + r0 += rx; r1 += (r0 < rx); \ + r0 += ry; r1 += (r0 < ry); \ + r0 += c; r1 += (r0 < c); \ + r0 += *d; r1 += (r0 < *d); \ + c = r1; *(d++) = r0; + +#define MULADDC_STOP \ +} + +#endif /* C (generic) */ +#endif /* C (longlong) */ + +#endif /* bn_mul.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/camellia.h b/c++/src/connect/mbedtls/mbedtls/camellia.h new file mode 100644 index 00000000..0424d623 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/camellia.h @@ -0,0 +1,235 @@ +/** + * \file camellia.h + * + * \brief Camellia block cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CAMELLIA_H +#define MBEDTLS_CAMELLIA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_CAMELLIA_ENCRYPT 1 +#define MBEDTLS_CAMELLIA_DECRYPT 0 + +#define MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH -0x0024 /**< Invalid key length. */ +#define MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH -0x0026 /**< Invalid data input length. */ + +#if !defined(MBEDTLS_CAMELLIA_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CAMELLIA context structure + */ +typedef struct +{ + int nr; /*!< number of rounds */ + uint32_t rk[68]; /*!< CAMELLIA round keys */ +} +mbedtls_camellia_context; + +/** + * \brief Initialize CAMELLIA context + * + * \param ctx CAMELLIA context to be initialized + */ +void mbedtls_camellia_init( mbedtls_camellia_context *ctx ); + +/** + * \brief Clear CAMELLIA context + * + * \param ctx CAMELLIA context to be cleared + */ +void mbedtls_camellia_free( mbedtls_camellia_context *ctx ); + +/** + * \brief CAMELLIA key schedule (encryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int mbedtls_camellia_setkey_enc( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief CAMELLIA key schedule (decryption) + * + * \param ctx CAMELLIA context to be initialized + * \param key decryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH + */ +int mbedtls_camellia_setkey_dec( mbedtls_camellia_context *ctx, const unsigned char *key, + unsigned int keybits ); + +/** + * \brief CAMELLIA-ECB block encryption/decryption + * + * \param ctx CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if successful + */ +int mbedtls_camellia_crypt_ecb( mbedtls_camellia_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief CAMELLIA-CBC buffer encryption/decryption + * Length should be a multiple of the block + * size (16 bytes) + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH + */ +int mbedtls_camellia_crypt_cbc( mbedtls_camellia_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_CIPHER_MODE_CFB) +/** + * \brief CAMELLIA-CFB128 buffer encryption/decryption + * + * Note: Due to the nature of CFB you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_camellia_setkey_enc() for both MBEDTLS_CAMELLIA_ENCRYPT and CAMELLIE_DECRYPT. + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx CAMELLIA context + * \param mode MBEDTLS_CAMELLIA_ENCRYPT or MBEDTLS_CAMELLIA_DECRYPT + * \param length length of the input data + * \param iv_off offset in IV (updated after use) + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH + */ +int mbedtls_camellia_crypt_cfb128( mbedtls_camellia_context *ctx, + int mode, + size_t length, + size_t *iv_off, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CFB */ + +#if defined(MBEDTLS_CIPHER_MODE_CTR) +/** + * \brief CAMELLIA-CTR buffer encryption/decryption + * + * Warning: You have to keep the maximum use of your counter in mind! + * + * Note: Due to the nature of CTR you should use the same key schedule for + * both encryption and decryption. So a context initialized with + * mbedtls_camellia_setkey_enc() for both MBEDTLS_CAMELLIA_ENCRYPT and MBEDTLS_CAMELLIA_DECRYPT. + * + * \param ctx CAMELLIA context + * \param length The length of the data + * \param nc_off The offset in the current stream_block (for resuming + * within current cipher stream). The offset pointer to + * should be 0 at the start of a stream. + * \param nonce_counter The 128-bit nonce and counter. + * \param stream_block The saved stream-block for resuming. Is overwritten + * by the function. + * \param input The input data stream + * \param output The output data stream + * + * \return 0 if successful + */ +int mbedtls_camellia_crypt_ctr( mbedtls_camellia_context *ctx, + size_t length, + size_t *nc_off, + unsigned char nonce_counter[16], + unsigned char stream_block[16], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CTR */ + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_CAMELLIA_ALT */ +#include "camellia_alt.h" +#endif /* MBEDTLS_CAMELLIA_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_camellia_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* camellia.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ccm.h b/c++/src/connect/mbedtls/mbedtls/ccm.h new file mode 100644 index 00000000..ef75839b --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ccm.h @@ -0,0 +1,141 @@ +/** + * \file ccm.h + * + * \brief Counter with CBC-MAC (CCM) for 128-bit block ciphers + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CCM_H +#define MBEDTLS_CCM_H + +#include "cipher.h" + +#define MBEDTLS_ERR_CCM_BAD_INPUT -0x000D /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_CCM_AUTH_FAILED -0x000F /**< Authenticated decryption failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CCM context structure + */ +typedef struct { + mbedtls_cipher_context_t cipher_ctx; /*!< cipher context used */ +} +mbedtls_ccm_context; + +/** + * \brief Initialize CCM context (just makes references valid) + * Makes the context ready for mbedtls_ccm_setkey() or + * mbedtls_ccm_free(). + * + * \param ctx CCM context to initialize + */ +void mbedtls_ccm_init( mbedtls_ccm_context *ctx ); + +/** + * \brief CCM initialization (encryption and decryption) + * + * \param ctx CCM context to be initialized + * \param cipher cipher to use (a 128-bit block cipher) + * \param key encryption key + * \param keybits key size in bits (must be acceptable by the cipher) + * + * \return 0 if successful, or a cipher specific error code + */ +int mbedtls_ccm_setkey( mbedtls_ccm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief Free a CCM context and underlying cipher sub-context + * + * \param ctx CCM context to free + */ +void mbedtls_ccm_free( mbedtls_ccm_context *ctx ); + +/** + * \brief CCM buffer encryption + * + * \param ctx CCM context + * \param length length of the input data in bytes + * \param iv nonce (initialization vector) + * \param iv_len length of IV in bytes + * must be 2, 3, 4, 5, 6, 7 or 8 + * \param add additional data + * \param add_len length of additional data in bytes + * must be less than 2^16 - 2^8 + * \param input buffer holding the input data + * \param output buffer for holding the output data + * must be at least 'length' bytes wide + * \param tag buffer for holding the tag + * \param tag_len length of the tag to generate in bytes + * must be 4, 6, 8, 10, 14 or 16 + * + * \note The tag is written to a separate buffer. To get the tag + * concatenated with the output as in the CCM spec, use + * tag = output + length and make sure the output buffer is + * at least length + tag_len wide. + * + * \return 0 if successful + */ +int mbedtls_ccm_encrypt_and_tag( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + unsigned char *tag, size_t tag_len ); + +/** + * \brief CCM buffer authenticated decryption + * + * \param ctx CCM context + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * \param tag buffer holding the tag + * \param tag_len length of the tag + * + * \return 0 if successful and authenticated, + * MBEDTLS_ERR_CCM_AUTH_FAILED if tag does not match + */ +int mbedtls_ccm_auth_decrypt( mbedtls_ccm_context *ctx, size_t length, + const unsigned char *iv, size_t iv_len, + const unsigned char *add, size_t add_len, + const unsigned char *input, unsigned char *output, + const unsigned char *tag, size_t tag_len ); + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_AES_C) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ccm_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST && MBEDTLS_AES_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CCM_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/certs.h b/c++/src/connect/mbedtls/mbedtls/certs.h new file mode 100644 index 00000000..ca49086e --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/certs.h @@ -0,0 +1,99 @@ +/** + * \file certs.h + * + * \brief Sample certificates and DHM parameters for testing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CERTS_H +#define MBEDTLS_CERTS_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) +/* Concatenation of all CA certificates in PEM format if available */ +extern const char mbedtls_test_cas_pem[]; +extern const size_t mbedtls_test_cas_pem_len; +#endif + +/* List of all CA certificates, terminated by NULL */ +extern const char * mbedtls_test_cas[]; +extern const size_t mbedtls_test_cas_len[]; + +/* + * Convenience for users who just want a certificate: + * RSA by default, or ECDSA if RSA is not available + */ +extern const char * mbedtls_test_ca_crt; +extern const size_t mbedtls_test_ca_crt_len; +extern const char * mbedtls_test_ca_key; +extern const size_t mbedtls_test_ca_key_len; +extern const char * mbedtls_test_ca_pwd; +extern const size_t mbedtls_test_ca_pwd_len; +extern const char * mbedtls_test_srv_crt; +extern const size_t mbedtls_test_srv_crt_len; +extern const char * mbedtls_test_srv_key; +extern const size_t mbedtls_test_srv_key_len; +extern const char * mbedtls_test_cli_crt; +extern const size_t mbedtls_test_cli_crt_len; +extern const char * mbedtls_test_cli_key; +extern const size_t mbedtls_test_cli_key_len; + +#if defined(MBEDTLS_ECDSA_C) +extern const char mbedtls_test_ca_crt_ec[]; +extern const size_t mbedtls_test_ca_crt_ec_len; +extern const char mbedtls_test_ca_key_ec[]; +extern const size_t mbedtls_test_ca_key_ec_len; +extern const char mbedtls_test_ca_pwd_ec[]; +extern const size_t mbedtls_test_ca_pwd_ec_len; +extern const char mbedtls_test_srv_crt_ec[]; +extern const size_t mbedtls_test_srv_crt_ec_len; +extern const char mbedtls_test_srv_key_ec[]; +extern const size_t mbedtls_test_srv_key_ec_len; +extern const char mbedtls_test_cli_crt_ec[]; +extern const size_t mbedtls_test_cli_crt_ec_len; +extern const char mbedtls_test_cli_key_ec[]; +extern const size_t mbedtls_test_cli_key_ec_len; +#endif + +#if defined(MBEDTLS_RSA_C) +extern const char mbedtls_test_ca_crt_rsa[]; +extern const size_t mbedtls_test_ca_crt_rsa_len; +extern const char mbedtls_test_ca_key_rsa[]; +extern const size_t mbedtls_test_ca_key_rsa_len; +extern const char mbedtls_test_ca_pwd_rsa[]; +extern const size_t mbedtls_test_ca_pwd_rsa_len; +extern const char mbedtls_test_srv_crt_rsa[]; +extern const size_t mbedtls_test_srv_crt_rsa_len; +extern const char mbedtls_test_srv_key_rsa[]; +extern const size_t mbedtls_test_srv_key_rsa_len; +extern const char mbedtls_test_cli_crt_rsa[]; +extern const size_t mbedtls_test_cli_crt_rsa_len; +extern const char mbedtls_test_cli_key_rsa[]; +extern const size_t mbedtls_test_cli_key_rsa_len; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* certs.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/check_config.h b/c++/src/connect/mbedtls/mbedtls/check_config.h new file mode 100644 index 00000000..fe86c1e8 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/check_config.h @@ -0,0 +1,628 @@ +/** + * \file check_config.h + * + * \brief Consistency checks for configuration options + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * It is recommended to include this file from your config.h + * in order to catch dependency issues early. + */ + +#ifndef MBEDTLS_CHECK_CONFIG_H +#define MBEDTLS_CHECK_CONFIG_H + +/* + * We assume CHAR_BIT is 8 in many places. In practice, this is true on our + * target platforms, so not an issue, but let's just be extra sure. + */ +#include +#if CHAR_BIT != 8 +#error "mbed TLS requires a platform with 8-bit chars" +#endif + +#if defined(_WIN32) +#if !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_C is required on Windows" +#endif + +/* Fix the config here. Not convenient to put an #ifdef _WIN32 in config.h as + * it would confuse config.pl. */ +#if !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && \ + !defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) +#define MBEDTLS_PLATFORM_SNPRINTF_ALT +#endif +#endif /* _WIN32 */ + +#if defined(TARGET_LIKE_MBED) && \ + ( defined(MBEDTLS_NET_C) || defined(MBEDTLS_TIMING_C) ) +#error "The NET and TIMING modules are not available for mbed OS - please use the network and timing functions provided by mbed OS" +#endif + +#if defined(MBEDTLS_DEPRECATED_WARNING) && \ + !defined(__GNUC__) && !defined(__clang__) +#error "MBEDTLS_DEPRECATED_WARNING only works with GCC and Clang" +#endif + +#if defined(MBEDTLS_HAVE_TIME_DATE) && !defined(MBEDTLS_HAVE_TIME) +#error "MBEDTLS_HAVE_TIME_DATE without MBEDTLS_HAVE_TIME does not make sense" +#endif + +#if defined(MBEDTLS_AESNI_C) && !defined(MBEDTLS_HAVE_ASM) +#error "MBEDTLS_AESNI_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_CTR_DRBG_C) && !defined(MBEDTLS_AES_C) +#error "MBEDTLS_CTR_DRBG_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_DHM_C) && !defined(MBEDTLS_BIGNUM_C) +#error "MBEDTLS_DHM_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_CMAC_C) && \ + !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_DES_C) +#error "MBEDTLS_CMAC_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECDH_C) && !defined(MBEDTLS_ECP_C) +#error "MBEDTLS_ECDH_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECDSA_C) && \ + ( !defined(MBEDTLS_ECP_C) || \ + !defined(MBEDTLS_ASN1_PARSE_C) || \ + !defined(MBEDTLS_ASN1_WRITE_C) ) +#error "MBEDTLS_ECDSA_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECJPAKE_C) && \ + ( !defined(MBEDTLS_ECP_C) || !defined(MBEDTLS_MD_C) ) +#error "MBEDTLS_ECJPAKE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) && !defined(MBEDTLS_HMAC_DRBG_C) +#error "MBEDTLS_ECDSA_DETERMINISTIC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ECP_C) && ( !defined(MBEDTLS_BIGNUM_C) || ( \ + !defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) && \ + !defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) ) ) +#error "MBEDTLS_ECP_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ENTROPY_C) && (!defined(MBEDTLS_SHA512_C) && \ + !defined(MBEDTLS_SHA256_C)) +#error "MBEDTLS_ENTROPY_C defined, but not all prerequisites" +#endif +#if defined(MBEDTLS_ENTROPY_C) && defined(MBEDTLS_SHA512_C) && \ + defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 64) +#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high" +#endif +#if defined(MBEDTLS_ENTROPY_C) && \ + ( !defined(MBEDTLS_SHA512_C) || defined(MBEDTLS_ENTROPY_FORCE_SHA256) ) \ + && defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) && (MBEDTLS_CTR_DRBG_ENTROPY_LEN > 32) +#error "MBEDTLS_CTR_DRBG_ENTROPY_LEN value too high" +#endif +#if defined(MBEDTLS_ENTROPY_C) && \ + defined(MBEDTLS_ENTROPY_FORCE_SHA256) && !defined(MBEDTLS_SHA256_C) +#error "MBEDTLS_ENTROPY_FORCE_SHA256 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \ + ( !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) ) +#error "MBEDTLS_TEST_NULL_ENTROPY defined, but not all prerequisites" +#endif +#if defined(MBEDTLS_TEST_NULL_ENTROPY) && \ + ( defined(MBEDTLS_ENTROPY_NV_SEED) || defined(MBEDTLS_ENTROPY_HARDWARE_ALT) || \ + defined(MBEDTLS_HAVEGE_C) ) +#error "MBEDTLS_TEST_NULL_ENTROPY defined, but entropy sources too" +#endif + +#if defined(MBEDTLS_GCM_C) && ( \ + !defined(MBEDTLS_AES_C) && !defined(MBEDTLS_CAMELLIA_C) ) +#error "MBEDTLS_GCM_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HAVEGE_C) && !defined(MBEDTLS_TIMING_C) +#error "MBEDTLS_HAVEGE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_HMAC_DRBG_C) && !defined(MBEDTLS_MD_C) +#error "MBEDTLS_HMAC_DRBG_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) && !defined(MBEDTLS_DHM_C) +#error "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) && \ + !defined(MBEDTLS_ECDH_C) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_DHM_C) || !defined(MBEDTLS_RSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_RSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \ + ( !defined(MBEDTLS_ECDH_C) || !defined(MBEDTLS_ECDSA_C) || \ + !defined(MBEDTLS_X509_CRT_PARSE_C) ) +#error "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \ + !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_X509_CRT_PARSE_C) || \ + !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) && \ + ( !defined(MBEDTLS_ECJPAKE_C) || !defined(MBEDTLS_SHA256_C) || \ + !defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ) +#error "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) && \ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_MEMORY_BUFFER_ALLOC_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PADLOCK_C) && !defined(MBEDTLS_HAVE_ASM) +#error "MBEDTLS_PADLOCK_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) && !defined(MBEDTLS_BASE64_C) +#error "MBEDTLS_PEM_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PEM_WRITE_C) && !defined(MBEDTLS_BASE64_C) +#error "MBEDTLS_PEM_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_C) && \ + ( !defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_ECP_C) ) +#error "MBEDTLS_PK_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_PARSE_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PK_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PK_WRITE_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PK_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PKCS11_C) && !defined(MBEDTLS_PK_C) +#error "MBEDTLS_PKCS11_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_EXIT_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_EXIT_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_EXIT) ||\ + defined(MBEDTLS_PLATFORM_EXIT_ALT) ) +#error "MBEDTLS_PLATFORM_EXIT_MACRO and MBEDTLS_PLATFORM_STD_EXIT/MBEDTLS_PLATFORM_EXIT_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_ALT) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\ + defined(MBEDTLS_PLATFORM_TIME_ALT) ) +#error "MBEDTLS_PLATFORM_TIME_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_TIME) ||\ + defined(MBEDTLS_PLATFORM_TIME_ALT) ) +#error "MBEDTLS_PLATFORM_TIME_TYPE_MACRO and MBEDTLS_PLATFORM_STD_TIME/MBEDTLS_PLATFORM_TIME_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_FPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_FPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_FPRINTF) ||\ + defined(MBEDTLS_PLATFORM_FPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_FPRINTF_MACRO and MBEDTLS_PLATFORM_STD_FPRINTF/MBEDTLS_PLATFORM_FPRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_PLATFORM_FREE_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) &&\ + defined(MBEDTLS_PLATFORM_STD_FREE) +#error "MBEDTLS_PLATFORM_FREE_MACRO and MBEDTLS_PLATFORM_STD_FREE cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && !defined(MBEDTLS_PLATFORM_CALLOC_MACRO) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO must be defined if MBEDTLS_PLATFORM_FREE_MACRO is" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_PLATFORM_MEMORY) ) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) &&\ + defined(MBEDTLS_PLATFORM_STD_CALLOC) +#error "MBEDTLS_PLATFORM_CALLOC_MACRO and MBEDTLS_PLATFORM_STD_CALLOC cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_CALLOC_MACRO) && !defined(MBEDTLS_PLATFORM_FREE_MACRO) +#error "MBEDTLS_PLATFORM_FREE_MACRO must be defined if MBEDTLS_PLATFORM_CALLOC_MACRO is" +#endif + +#if defined(MBEDTLS_PLATFORM_MEMORY) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_MEMORY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_PRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_PRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_PRINTF) ||\ + defined(MBEDTLS_PLATFORM_PRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_PRINTF_MACRO and MBEDTLS_PLATFORM_STD_PRINTF/MBEDTLS_PLATFORM_PRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SNPRINTF_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) && !defined(MBEDTLS_PLATFORM_C) +#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_SNPRINTF) ||\ + defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) ) +#error "MBEDTLS_PLATFORM_SNPRINTF_MACRO and MBEDTLS_PLATFORM_STD_SNPRINTF/MBEDTLS_PLATFORM_SNPRINTF_ALT cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) &&\ + !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) +#error "MBEDTLS_PLATFORM_STD_MEM_HDR defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_CALLOC) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_CALLOC defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_FREE) && !defined(MBEDTLS_PLATFORM_MEMORY) +#error "MBEDTLS_PLATFORM_STD_FREE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_EXIT) &&\ + !defined(MBEDTLS_PLATFORM_EXIT_ALT) +#error "MBEDTLS_PLATFORM_STD_EXIT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_TIME) &&\ + ( !defined(MBEDTLS_PLATFORM_TIME_ALT) ||\ + !defined(MBEDTLS_HAVE_TIME) ) +#error "MBEDTLS_PLATFORM_STD_TIME defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_FPRINTF) &&\ + !defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_FPRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_PRINTF) &&\ + !defined(MBEDTLS_PLATFORM_PRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_PRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_SNPRINTF) &&\ + !defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +#error "MBEDTLS_PLATFORM_STD_SNPRINTF defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_ENTROPY_NV_SEED) &&\ + ( !defined(MBEDTLS_PLATFORM_C) || !defined(MBEDTLS_ENTROPY_C) ) +#error "MBEDTLS_ENTROPY_NV_SEED defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) &&\ + !defined(MBEDTLS_ENTROPY_NV_SEED) +#error "MBEDTLS_PLATFORM_NV_SEED_ALT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) &&\ + !defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +#error "MBEDTLS_PLATFORM_STD_NV_SEED_READ defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) &&\ + !defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +#error "MBEDTLS_PLATFORM_STD_NV_SEED_WRITE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) ||\ + defined(MBEDTLS_PLATFORM_NV_SEED_ALT) ) +#error "MBEDTLS_PLATFORM_NV_SEED_READ_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_READ cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) &&\ + ( defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) ||\ + defined(MBEDTLS_PLATFORM_NV_SEED_ALT) ) +#error "MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO and MBEDTLS_PLATFORM_STD_NV_SEED_WRITE cannot be defined simultaneously" +#endif + +#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) ) +#error "MBEDTLS_RSA_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_RSA_C) && ( !defined(MBEDTLS_PKCS1_V21) && \ + !defined(MBEDTLS_PKCS1_V15) ) +#error "MBEDTLS_RSA_C defined, but none of the PKCS1 versions enabled" +#endif + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) && \ + ( !defined(MBEDTLS_RSA_C) || !defined(MBEDTLS_PKCS1_V21) ) +#error "MBEDTLS_X509_RSASSA_PSS_SUPPORT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_SSL3) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_SSL3 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) && ( !defined(MBEDTLS_MD5_C) || \ + !defined(MBEDTLS_SHA1_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1_1 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && ( !defined(MBEDTLS_SHA1_C) && \ + !defined(MBEDTLS_SHA256_C) && !defined(MBEDTLS_SHA512_C) ) +#error "MBEDTLS_SSL_PROTO_TLS1_2 defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_PROTO_DTLS defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_CLI_C) && !defined(MBEDTLS_SSL_TLS_C) +#error "MBEDTLS_SSL_CLI_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && ( !defined(MBEDTLS_CIPHER_C) || \ + !defined(MBEDTLS_MD_C) ) +#error "MBEDTLS_SSL_TLS_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_SRV_C) && !defined(MBEDTLS_SSL_TLS_C) +#error "MBEDTLS_SSL_SRV_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (!defined(MBEDTLS_SSL_PROTO_SSL3) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2)) +#error "MBEDTLS_SSL_TLS_C defined, but no protocols are active" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) && !defined(MBEDTLS_SSL_PROTO_TLS1)) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_TLS1) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && !defined(MBEDTLS_SSL_PROTO_TLS1_1)) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_TLS_C) && (defined(MBEDTLS_SSL_PROTO_SSL3) && \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) && (!defined(MBEDTLS_SSL_PROTO_TLS1) || \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1))) +#error "Illegal protocol selection" +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && !defined(MBEDTLS_SSL_PROTO_DTLS) +#error "MBEDTLS_SSL_DTLS_HELLO_VERIFY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && \ + !defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) +#error "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) && \ + ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ) +#error "MBEDTLS_SSL_DTLS_ANTI_REPLAY defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) && \ + ( !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) ) +#error "MBEDTLS_SSL_DTLS_BADMAC_LIMIT defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_ENCRYPT_THEN_MAC defined, but not all prerequsites" +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_1) && \ + !defined(MBEDTLS_SSL_PROTO_TLS1_2) +#error "MBEDTLS_SSL_EXTENDED_MASTER_SECRET defined, but not all prerequsites" +#endif + +#if defined(MBEDTLS_SSL_TICKET_C) && !defined(MBEDTLS_CIPHER_C) +#error "MBEDTLS_SSL_TICKET_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) && \ + !defined(MBEDTLS_SSL_PROTO_SSL3) && !defined(MBEDTLS_SSL_PROTO_TLS1) +#error "MBEDTLS_SSL_CBC_RECORD_SPLITTING defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) && \ + !defined(MBEDTLS_X509_CRT_PARSE_C) +#error "MBEDTLS_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_THREADING_PTHREAD) +#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_PTHREAD defined, but not all prerequisites" +#endif +#define MBEDTLS_THREADING_IMPL +#endif + +#if defined(MBEDTLS_THREADING_ALT) +#if !defined(MBEDTLS_THREADING_C) || defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_ALT defined, but not all prerequisites" +#endif +#define MBEDTLS_THREADING_IMPL +#endif + +#if defined(MBEDTLS_THREADING_C) && !defined(MBEDTLS_THREADING_IMPL) +#error "MBEDTLS_THREADING_C defined, single threading implementation required" +#endif +#undef MBEDTLS_THREADING_IMPL + +#if defined(MBEDTLS_VERSION_FEATURES) && !defined(MBEDTLS_VERSION_C) +#error "MBEDTLS_VERSION_FEATURES defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_USE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_PARSE_C) || \ + !defined(MBEDTLS_PK_PARSE_C) ) +#error "MBEDTLS_X509_USE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CREATE_C) && ( !defined(MBEDTLS_BIGNUM_C) || \ + !defined(MBEDTLS_OID_C) || !defined(MBEDTLS_ASN1_WRITE_C) || \ + !defined(MBEDTLS_PK_WRITE_C) ) +#error "MBEDTLS_X509_CREATE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CRT_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRL_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CRL_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CSR_PARSE_C) && ( !defined(MBEDTLS_X509_USE_C) ) +#error "MBEDTLS_X509_CSR_PARSE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CRT_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) ) +#error "MBEDTLS_X509_CRT_WRITE_C defined, but not all prerequisites" +#endif + +#if defined(MBEDTLS_X509_CSR_WRITE_C) && ( !defined(MBEDTLS_X509_CREATE_C) ) +#error "MBEDTLS_X509_CSR_WRITE_C defined, but not all prerequisites" +#endif + +/* + * Avoid warning from -pedantic. This is a convenient place for this + * workaround since this is included by every single file before the + * #if defined(MBEDTLS_xxx_C) that results in emtpy translation units. + */ +typedef int mbedtls_iso_c_forbids_empty_translation_units; + +#endif /* MBEDTLS_CHECK_CONFIG_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/cipher.h b/c++/src/connect/mbedtls/mbedtls/cipher.h new file mode 100644 index 00000000..b12e3884 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/cipher.h @@ -0,0 +1,709 @@ +/** + * \file cipher.h + * + * \brief Generic cipher wrapper. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CIPHER_H +#define MBEDTLS_CIPHER_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) +#define MBEDTLS_CIPHER_MODE_AEAD +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define MBEDTLS_CIPHER_MODE_WITH_PADDING +#endif + +#if defined(MBEDTLS_ARC4_C) +#define MBEDTLS_CIPHER_MODE_STREAM +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#define MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE -0x6080 /**< The selected feature is not available. */ +#define MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA -0x6100 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_CIPHER_ALLOC_FAILED -0x6180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_CIPHER_INVALID_PADDING -0x6200 /**< Input data contains invalid padding and is rejected. */ +#define MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED -0x6280 /**< Decryption of block requires a full block. */ +#define MBEDTLS_ERR_CIPHER_AUTH_FAILED -0x6300 /**< Authentication failed (for AEAD modes). */ +#define MBEDTLS_ERR_CIPHER_INVALID_CONTEXT -0x6380 /**< The context is invalid, eg because it was free()ed. */ + +#define MBEDTLS_CIPHER_VARIABLE_IV_LEN 0x01 /**< Cipher accepts IVs of variable length */ +#define MBEDTLS_CIPHER_VARIABLE_KEY_LEN 0x02 /**< Cipher accepts keys of variable length */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MBEDTLS_CIPHER_ID_NONE = 0, + MBEDTLS_CIPHER_ID_NULL, + MBEDTLS_CIPHER_ID_AES, + MBEDTLS_CIPHER_ID_DES, + MBEDTLS_CIPHER_ID_3DES, + MBEDTLS_CIPHER_ID_CAMELLIA, + MBEDTLS_CIPHER_ID_BLOWFISH, + MBEDTLS_CIPHER_ID_ARC4, +} mbedtls_cipher_id_t; + +typedef enum { + MBEDTLS_CIPHER_NONE = 0, + MBEDTLS_CIPHER_NULL, + MBEDTLS_CIPHER_AES_128_ECB, + MBEDTLS_CIPHER_AES_192_ECB, + MBEDTLS_CIPHER_AES_256_ECB, + MBEDTLS_CIPHER_AES_128_CBC, + MBEDTLS_CIPHER_AES_192_CBC, + MBEDTLS_CIPHER_AES_256_CBC, + MBEDTLS_CIPHER_AES_128_CFB128, + MBEDTLS_CIPHER_AES_192_CFB128, + MBEDTLS_CIPHER_AES_256_CFB128, + MBEDTLS_CIPHER_AES_128_CTR, + MBEDTLS_CIPHER_AES_192_CTR, + MBEDTLS_CIPHER_AES_256_CTR, + MBEDTLS_CIPHER_AES_128_GCM, + MBEDTLS_CIPHER_AES_192_GCM, + MBEDTLS_CIPHER_AES_256_GCM, + MBEDTLS_CIPHER_CAMELLIA_128_ECB, + MBEDTLS_CIPHER_CAMELLIA_192_ECB, + MBEDTLS_CIPHER_CAMELLIA_256_ECB, + MBEDTLS_CIPHER_CAMELLIA_128_CBC, + MBEDTLS_CIPHER_CAMELLIA_192_CBC, + MBEDTLS_CIPHER_CAMELLIA_256_CBC, + MBEDTLS_CIPHER_CAMELLIA_128_CFB128, + MBEDTLS_CIPHER_CAMELLIA_192_CFB128, + MBEDTLS_CIPHER_CAMELLIA_256_CFB128, + MBEDTLS_CIPHER_CAMELLIA_128_CTR, + MBEDTLS_CIPHER_CAMELLIA_192_CTR, + MBEDTLS_CIPHER_CAMELLIA_256_CTR, + MBEDTLS_CIPHER_CAMELLIA_128_GCM, + MBEDTLS_CIPHER_CAMELLIA_192_GCM, + MBEDTLS_CIPHER_CAMELLIA_256_GCM, + MBEDTLS_CIPHER_DES_ECB, + MBEDTLS_CIPHER_DES_CBC, + MBEDTLS_CIPHER_DES_EDE_ECB, + MBEDTLS_CIPHER_DES_EDE_CBC, + MBEDTLS_CIPHER_DES_EDE3_ECB, + MBEDTLS_CIPHER_DES_EDE3_CBC, + MBEDTLS_CIPHER_BLOWFISH_ECB, + MBEDTLS_CIPHER_BLOWFISH_CBC, + MBEDTLS_CIPHER_BLOWFISH_CFB64, + MBEDTLS_CIPHER_BLOWFISH_CTR, + MBEDTLS_CIPHER_ARC4_128, + MBEDTLS_CIPHER_AES_128_CCM, + MBEDTLS_CIPHER_AES_192_CCM, + MBEDTLS_CIPHER_AES_256_CCM, + MBEDTLS_CIPHER_CAMELLIA_128_CCM, + MBEDTLS_CIPHER_CAMELLIA_192_CCM, + MBEDTLS_CIPHER_CAMELLIA_256_CCM, +} mbedtls_cipher_type_t; + +typedef enum { + MBEDTLS_MODE_NONE = 0, + MBEDTLS_MODE_ECB, + MBEDTLS_MODE_CBC, + MBEDTLS_MODE_CFB, + MBEDTLS_MODE_OFB, /* Unused! */ + MBEDTLS_MODE_CTR, + MBEDTLS_MODE_GCM, + MBEDTLS_MODE_STREAM, + MBEDTLS_MODE_CCM, +} mbedtls_cipher_mode_t; + +typedef enum { + MBEDTLS_PADDING_PKCS7 = 0, /**< PKCS7 padding (default) */ + MBEDTLS_PADDING_ONE_AND_ZEROS, /**< ISO/IEC 7816-4 padding */ + MBEDTLS_PADDING_ZEROS_AND_LEN, /**< ANSI X.923 padding */ + MBEDTLS_PADDING_ZEROS, /**< zero padding (not reversible!) */ + MBEDTLS_PADDING_NONE, /**< never pad (full blocks only) */ +} mbedtls_cipher_padding_t; + +typedef enum { + MBEDTLS_OPERATION_NONE = -1, + MBEDTLS_DECRYPT = 0, + MBEDTLS_ENCRYPT, +} mbedtls_operation_t; + +enum { + /** Undefined key length */ + MBEDTLS_KEY_LENGTH_NONE = 0, + /** Key length, in bits (including parity), for DES keys */ + MBEDTLS_KEY_LENGTH_DES = 64, + /** Key length, in bits (including parity), for DES in two key EDE */ + MBEDTLS_KEY_LENGTH_DES_EDE = 128, + /** Key length, in bits (including parity), for DES in three-key EDE */ + MBEDTLS_KEY_LENGTH_DES_EDE3 = 192, +}; + +/** Maximum length of any IV, in bytes */ +#define MBEDTLS_MAX_IV_LENGTH 16 +/** Maximum block size of any cipher, in bytes */ +#define MBEDTLS_MAX_BLOCK_LENGTH 16 + +/** + * Base cipher information (opaque struct). + */ +typedef struct mbedtls_cipher_base_t mbedtls_cipher_base_t; + +/** + * CMAC context (opaque struct). + */ +typedef struct mbedtls_cmac_context_t mbedtls_cmac_context_t; + +/** + * Cipher information. Allows cipher functions to be called in a generic way. + */ +typedef struct { + /** Full cipher identifier (e.g. MBEDTLS_CIPHER_AES_256_CBC) */ + mbedtls_cipher_type_t type; + + /** Cipher mode (e.g. MBEDTLS_MODE_CBC) */ + mbedtls_cipher_mode_t mode; + + /** Cipher key length, in bits (default length for variable sized ciphers) + * (Includes parity bits for ciphers like DES) */ + unsigned int key_bitlen; + + /** Name of the cipher */ + const char * name; + + /** IV/NONCE size, in bytes. + * For cipher that accept many sizes: recommended size */ + unsigned int iv_size; + + /** Flags for variable IV size, variable key size, etc. */ + int flags; + + /** block size, in bytes */ + unsigned int block_size; + + /** Base cipher information and functions */ + const mbedtls_cipher_base_t *base; + +} mbedtls_cipher_info_t; + +/** + * Generic cipher context. + */ +typedef struct { + /** Information about the associated cipher */ + const mbedtls_cipher_info_t *cipher_info; + + /** Key length to use */ + int key_bitlen; + + /** Operation that the context's key has been initialised for */ + mbedtls_operation_t operation; + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) + /** Padding functions to use, if relevant for cipher mode */ + void (*add_padding)( unsigned char *output, size_t olen, size_t data_len ); + int (*get_padding)( unsigned char *input, size_t ilen, size_t *data_len ); +#endif + + /** Buffer for data that hasn't been encrypted yet */ + unsigned char unprocessed_data[MBEDTLS_MAX_BLOCK_LENGTH]; + + /** Number of bytes that still need processing */ + size_t unprocessed_len; + + /** Current IV or NONCE_COUNTER for CTR-mode */ + unsigned char iv[MBEDTLS_MAX_IV_LENGTH]; + + /** IV size in bytes (for ciphers with variable-length IVs) */ + size_t iv_size; + + /** Cipher-specific context */ + void *cipher_ctx; + +#if defined(MBEDTLS_CMAC_C) + /** CMAC Specific context */ + mbedtls_cmac_context_t *cmac_ctx; +#endif +} mbedtls_cipher_context_t; + +/** + * \brief Returns the list of ciphers supported by the generic cipher module. + * + * \return a statically allocated array of ciphers, the last entry + * is 0. + */ +const int *mbedtls_cipher_list( void ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher name. + * + * \param cipher_name Name of the cipher to search for. + * + * \return the cipher information structure associated with the + * given cipher_name, or NULL if not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_string( const char *cipher_name ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher type. + * + * \param cipher_type Type of the cipher to search for. + * + * \return the cipher information structure associated with the + * given cipher_type, or NULL if not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_type( const mbedtls_cipher_type_t cipher_type ); + +/** + * \brief Returns the cipher information structure associated + * with the given cipher id, key size and mode. + * + * \param cipher_id Id of the cipher to search for + * (e.g. MBEDTLS_CIPHER_ID_AES) + * \param key_bitlen Length of the key in bits + * \param mode Cipher mode (e.g. MBEDTLS_MODE_CBC) + * + * \return the cipher information structure associated with the + * given cipher_type, or NULL if not found. + */ +const mbedtls_cipher_info_t *mbedtls_cipher_info_from_values( const mbedtls_cipher_id_t cipher_id, + int key_bitlen, + const mbedtls_cipher_mode_t mode ); + +/** + * \brief Initialize a cipher_context (as NONE) + */ +void mbedtls_cipher_init( mbedtls_cipher_context_t *ctx ); + +/** + * \brief Free and clear the cipher-specific context of ctx. + * Freeing ctx itself remains the responsibility of the + * caller. + */ +void mbedtls_cipher_free( mbedtls_cipher_context_t *ctx ); + +/** + * \brief Initialises and fills the cipher context structure with + * the appropriate values. + * + * \note Currently also clears structure. In future versions you + * will be required to call mbedtls_cipher_init() on the structure + * first. + * + * \param ctx context to initialise. May not be NULL. + * \param cipher_info cipher to use. + * + * \return 0 on success, + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter failure, + * MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the + * cipher-specific context failed. + */ +int mbedtls_cipher_setup( mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info ); + +/** + * \brief Returns the block size of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return size of the cipher's blocks, or 0 if ctx has not been + * initialised. + */ +static inline unsigned int mbedtls_cipher_get_block_size( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->block_size; +} + +/** + * \brief Returns the mode of operation for the cipher. + * (e.g. MBEDTLS_MODE_CBC) + * + * \param ctx cipher's context. Must have been initialised. + * + * \return mode of operation, or MBEDTLS_MODE_NONE if ctx + * has not been initialised. + */ +static inline mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_MODE_NONE; + + return ctx->cipher_info->mode; +} + +/** + * \brief Returns the size of the cipher's IV/NONCE in bytes. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return If IV has not been set yet: (recommended) IV size + * (0 for ciphers not using IV/NONCE). + * If IV has already been set: actual size. + */ +static inline int mbedtls_cipher_get_iv_size( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + if( ctx->iv_size != 0 ) + return (int) ctx->iv_size; + + return (int) ctx->cipher_info->iv_size; +} + +/** + * \brief Returns the type of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return type of the cipher, or MBEDTLS_CIPHER_NONE if ctx has + * not been initialised. + */ +static inline mbedtls_cipher_type_t mbedtls_cipher_get_type( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_CIPHER_NONE; + + return ctx->cipher_info->type; +} + +/** + * \brief Returns the name of the given cipher, as a string. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return name of the cipher, or NULL if ctx was not initialised. + */ +static inline const char *mbedtls_cipher_get_name( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return 0; + + return ctx->cipher_info->name; +} + +/** + * \brief Returns the key length of the cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return cipher's key length, in bits, or + * MBEDTLS_KEY_LENGTH_NONE if ctx has not been + * initialised. + */ +static inline int mbedtls_cipher_get_key_bitlen( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_KEY_LENGTH_NONE; + + return (int) ctx->cipher_info->key_bitlen; +} + +/** + * \brief Returns the operation of the given cipher. + * + * \param ctx cipher's context. Must have been initialised. + * + * \return operation (MBEDTLS_ENCRYPT or MBEDTLS_DECRYPT), + * or MBEDTLS_OPERATION_NONE if ctx has not been + * initialised. + */ +static inline mbedtls_operation_t mbedtls_cipher_get_operation( const mbedtls_cipher_context_t *ctx ) +{ + if( NULL == ctx || NULL == ctx->cipher_info ) + return MBEDTLS_OPERATION_NONE; + + return ctx->operation; +} + +/** + * \brief Set the key to use with the given context. + * + * \param ctx generic cipher context. May not be NULL. Must have been + * initialised using cipher_context_from_type or + * cipher_context_from_string. + * \param key The key to use. + * \param key_bitlen key length to use, in bits. + * \param operation Operation that the key will be used for, either + * MBEDTLS_ENCRYPT or MBEDTLS_DECRYPT. + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails or a cipher specific + * error code. + */ +int mbedtls_cipher_setkey( mbedtls_cipher_context_t *ctx, const unsigned char *key, + int key_bitlen, const mbedtls_operation_t operation ); + +#if defined(MBEDTLS_CIPHER_MODE_WITH_PADDING) +/** + * \brief Set padding mode, for cipher modes that use padding. + * (Default: PKCS7 padding.) + * + * \param ctx generic cipher context + * \param mode padding mode + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE + * if selected padding mode is not supported, or + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if the cipher mode + * does not support padding. + */ +int mbedtls_cipher_set_padding_mode( mbedtls_cipher_context_t *ctx, mbedtls_cipher_padding_t mode ); +#endif /* MBEDTLS_CIPHER_MODE_WITH_PADDING */ + +/** + * \brief Set the initialization vector (IV) or nonce + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * + * \returns 0 on success, or MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA + * + * \note Some ciphers don't use IVs nor NONCE. For these + * ciphers, this function has no effect. + */ +int mbedtls_cipher_set_iv( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len ); + +/** + * \brief Finish preparation of the given context + * + * \param ctx generic cipher context + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA + * if parameter verification fails. + */ +int mbedtls_cipher_reset( mbedtls_cipher_context_t *ctx ); + +#if defined(MBEDTLS_GCM_C) +/** + * \brief Add additional data (for AEAD ciphers). + * Currently only supported with GCM. + * Must be called exactly once, after mbedtls_cipher_reset(). + * + * \param ctx generic cipher context + * \param ad Additional data to use. + * \param ad_len Length of ad. + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_cipher_update_ad( mbedtls_cipher_context_t *ctx, + const unsigned char *ad, size_t ad_len ); +#endif /* MBEDTLS_GCM_C */ + +/** + * \brief Generic cipher update function. Encrypts/decrypts + * using the given cipher context. Writes as many block + * size'd blocks of data as possible to output. Any data + * that cannot be written immediately will either be added + * to the next block, or flushed when cipher_final is + * called. + * Exception: for MBEDTLS_MODE_ECB, expects single block + * in size (e.g. 16 bytes for AES) + * + * \param ctx generic cipher context + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. Should be able to hold at + * least ilen + block_size. Cannot be the same buffer as + * input! + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails, + * MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE on an + * unsupported mode for a cipher or a cipher specific + * error code. + * + * \note If the underlying cipher is GCM, all calls to this + * function, except the last one before mbedtls_cipher_finish(), + * must have ilen a multiple of the block size. + */ +int mbedtls_cipher_update( mbedtls_cipher_context_t *ctx, const unsigned char *input, + size_t ilen, unsigned char *output, size_t *olen ); + +/** + * \brief Generic cipher finalisation function. If data still + * needs to be flushed from an incomplete block, data + * contained within it will be padded with the size of + * the last block, and written to the output buffer. + * + * \param ctx Generic cipher context + * \param output buffer to write data to. Needs block_size available. + * \param olen length of the data written to the output buffer. + * + * \returns 0 on success, MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA if + * parameter verification fails, + * MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption + * expected a full block but was not provided one, + * MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting or a cipher specific error code. + */ +int mbedtls_cipher_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output, size_t *olen ); + +#if defined(MBEDTLS_GCM_C) +/** + * \brief Write tag for AEAD ciphers. + * Currently only supported with GCM. + * Must be called after mbedtls_cipher_finish(). + * + * \param ctx Generic cipher context + * \param tag buffer to write the tag + * \param tag_len Length of the tag to write + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_cipher_write_tag( mbedtls_cipher_context_t *ctx, + unsigned char *tag, size_t tag_len ); + +/** + * \brief Check tag for AEAD ciphers. + * Currently only supported with GCM. + * Must be called after mbedtls_cipher_finish(). + * + * \param ctx Generic cipher context + * \param tag Buffer holding the tag + * \param tag_len Length of the tag to check + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_cipher_check_tag( mbedtls_cipher_context_t *ctx, + const unsigned char *tag, size_t tag_len ); +#endif /* MBEDTLS_GCM_C */ + +/** + * \brief Generic all-in-one encryption/decryption + * (for all ciphers except AEAD constructs). + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. Should be able to hold at + * least ilen + block_size. Cannot be the same buffer as + * input! + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * + * \note Some ciphers don't use IVs nor NONCE. For these + * ciphers, use iv = NULL and iv_len = 0. + * + * \returns 0 on success, or + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or + * MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED if decryption + * expected a full block but was not provided one, or + * MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding + * while decrypting, or + * a cipher specific error code. + */ +int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen ); + +#if defined(MBEDTLS_CIPHER_MODE_AEAD) +/** + * \brief Generic autenticated encryption (AEAD ciphers). + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * \param ad Additional data to authenticate. + * \param ad_len Length of ad. + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. + * Should be able to hold at least ilen. + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * \param tag buffer for the authentication tag + * \param tag_len desired tag length + * + * \returns 0 on success, or + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or + * a cipher specific error code. + */ +int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + unsigned char *tag, size_t tag_len ); + +/** + * \brief Generic autenticated decryption (AEAD ciphers). + * + * \param ctx generic cipher context + * \param iv IV to use (or NONCE_COUNTER for CTR-mode ciphers) + * \param iv_len IV length for ciphers with variable-size IV; + * discarded by ciphers with fixed-size IV. + * \param ad Additional data to be authenticated. + * \param ad_len Length of ad. + * \param input buffer holding the input data + * \param ilen length of the input data + * \param output buffer for the output data. + * Should be able to hold at least ilen. + * \param olen length of the output data, will be filled with the + * actual number of bytes written. + * \param tag buffer holding the authentication tag + * \param tag_len length of the authentication tag + * + * \returns 0 on success, or + * MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA, or + * MBEDTLS_ERR_CIPHER_AUTH_FAILED if data isn't authentic, + * or a cipher specific error code. + * + * \note If the data is not authentic, then the output buffer + * is zeroed out to prevent the unauthentic plaintext to + * be used by mistake, making this interface safer. + */ +int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx, + const unsigned char *iv, size_t iv_len, + const unsigned char *ad, size_t ad_len, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, + const unsigned char *tag, size_t tag_len ); +#endif /* MBEDTLS_CIPHER_MODE_AEAD */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CIPHER_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/cipher_internal.h b/c++/src/connect/mbedtls/mbedtls/cipher_internal.h new file mode 100644 index 00000000..6c58bcc5 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/cipher_internal.h @@ -0,0 +1,109 @@ +/** + * \file cipher_internal.h + * + * \brief Cipher wrappers. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CIPHER_WRAP_H +#define MBEDTLS_CIPHER_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Base cipher information. The non-mode specific functions and values. + */ +struct mbedtls_cipher_base_t +{ + /** Base Cipher type (e.g. MBEDTLS_CIPHER_ID_AES) */ + mbedtls_cipher_id_t cipher; + + /** Encrypt using ECB */ + int (*ecb_func)( void *ctx, mbedtls_operation_t mode, + const unsigned char *input, unsigned char *output ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + /** Encrypt using CBC */ + int (*cbc_func)( void *ctx, mbedtls_operation_t mode, size_t length, + unsigned char *iv, const unsigned char *input, + unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CFB) + /** Encrypt using CFB (Full length) */ + int (*cfb_func)( void *ctx, mbedtls_operation_t mode, size_t length, size_t *iv_off, + unsigned char *iv, const unsigned char *input, + unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CTR) + /** Encrypt using CTR */ + int (*ctr_func)( void *ctx, size_t length, size_t *nc_off, + unsigned char *nonce_counter, unsigned char *stream_block, + const unsigned char *input, unsigned char *output ); +#endif + +#if defined(MBEDTLS_CIPHER_MODE_STREAM) + /** Encrypt using STREAM */ + int (*stream_func)( void *ctx, size_t length, + const unsigned char *input, unsigned char *output ); +#endif + + /** Set key for encryption purposes */ + int (*setkey_enc_func)( void *ctx, const unsigned char *key, + unsigned int key_bitlen ); + + /** Set key for decryption purposes */ + int (*setkey_dec_func)( void *ctx, const unsigned char *key, + unsigned int key_bitlen); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + +}; + +typedef struct +{ + mbedtls_cipher_type_t type; + const mbedtls_cipher_info_t *info; +} mbedtls_cipher_definition_t; + +extern const mbedtls_cipher_definition_t mbedtls_cipher_definitions[]; + +extern int mbedtls_cipher_supported[]; + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CIPHER_WRAP_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/cmac.h b/c++/src/connect/mbedtls/mbedtls/cmac.h new file mode 100644 index 00000000..b5b7fd06 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/cmac.h @@ -0,0 +1,170 @@ +/** + * \file cmac.h + * + * \brief Cipher-based Message Authentication Code (CMAC) Mode for + * Authentication + * + * Copyright (C) 2015-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CMAC_H +#define MBEDTLS_CMAC_H + +#include "cipher.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MBEDTLS_AES_BLOCK_SIZE 16 +#define MBEDTLS_DES3_BLOCK_SIZE 8 + +#if defined(MBEDTLS_AES_C) +#define MBEDTLS_CIPHER_BLKSIZE_MAX 16 /* longest used by CMAC is AES */ +#else +#define MBEDTLS_CIPHER_BLKSIZE_MAX 8 /* longest used by CMAC is 3DES */ +#endif + +/** + * CMAC context structure - Contains internal state information only + */ +struct mbedtls_cmac_context_t +{ + /** Internal state of the CMAC algorithm */ + unsigned char state[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + /** Unprocessed data - either data that was not block aligned and is still + * pending to be processed, or the final block */ + unsigned char unprocessed_block[MBEDTLS_CIPHER_BLKSIZE_MAX]; + + /** Length of data pending to be processed */ + size_t unprocessed_len; +}; + +/** + * \brief Set the CMAC key and prepare to authenticate the input + * data. + * Should be called with an initialized cipher context. + * + * \param ctx Cipher context. This should be a cipher context, + * initialized to be one of the following types: + * MBEDTLS_CIPHER_AES_128_ECB, MBEDTLS_CIPHER_AES_192_ECB, + * MBEDTLS_CIPHER_AES_256_ECB or + * MBEDTLS_CIPHER_DES_EDE3_ECB. + * \param key CMAC key + * \param keybits length of the CMAC key in bits + * (must be acceptable by the cipher) + * + * \return 0 if successful, or a cipher specific error code + */ +int mbedtls_cipher_cmac_starts( mbedtls_cipher_context_t *ctx, + const unsigned char *key, size_t keybits ); + +/** + * \brief Generic CMAC process buffer. + * Called between mbedtls_cipher_cmac_starts() or + * mbedtls_cipher_cmac_reset() and + * mbedtls_cipher_cmac_finish(). + * May be called repeatedly. + * + * \param ctx CMAC context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_cipher_cmac_update( mbedtls_cipher_context_t *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief Output CMAC. + * Called after mbedtls_cipher_cmac_update(). + * Usually followed by mbedtls_cipher_cmac_reset(), then + * mbedtls_cipher_cmac_starts(), or mbedtls_cipher_free(). + * + * \param ctx CMAC context + * \param output Generic CMAC checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_cipher_cmac_finish( mbedtls_cipher_context_t *ctx, + unsigned char *output ); + +/** + * \brief Prepare to authenticate a new message with the same key. + * Called after mbedtls_cipher_cmac_finish() and before + * mbedtls_cipher_cmac_update(). + * + * \param ctx CMAC context to be reset + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_cipher_cmac_reset( mbedtls_cipher_context_t *ctx ); + +/** + * \brief Output = Generic_CMAC( cmac key, input buffer ) + * + * \param cipher_info message digest info + * \param key CMAC key + * \param keylen length of the CMAC key in bits + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic CMAC-result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_cipher_cmac( const mbedtls_cipher_info_t *cipher_info, + const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + +#if defined(MBEDTLS_AES_C) +/** + * \brief AES-CMAC-128-PRF + * Implementation of (AES-CMAC-PRF-128), as defined in RFC 4615 + * + * \param key PRF key + * \param key_len PRF key length in bytes + * \param input buffer holding the input data + * \param in_len length of the input data in bytes + * \param output buffer holding the generated pseudorandom output (16 bytes) + * + * \return 0 if successful + */ +int mbedtls_aes_cmac_prf_128( const unsigned char *key, size_t key_len, + const unsigned char *input, size_t in_len, + unsigned char output[16] ); +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_SELF_TEST) && ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_DES_C) ) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_cmac_self_test( int verbose ); +#endif /* MBEDTLS_SELF_TEST && ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_CMAC_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/compat-1.3.h b/c++/src/connect/mbedtls/mbedtls/compat-1.3.h new file mode 100644 index 00000000..af51b5f8 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/compat-1.3.h @@ -0,0 +1,2633 @@ +/** + * \file compat-1.3.h + * + * \brief Compatibility definitions for using mbed TLS with client code written + * for the PolarSSL naming conventions. + * + * \deprecated Use the new names directly instead + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) + +#if defined(MBEDTLS_DEPRECATED_WARNING) +#warning "Including compat-1.3.h is deprecated" +#endif + +#ifndef MBEDTLS_COMPAT13_H +#define MBEDTLS_COMPAT13_H + +/* + * config.h options + */ +#if defined MBEDTLS_AESNI_C +#define POLARSSL_AESNI_C MBEDTLS_AESNI_C +#endif +#if defined MBEDTLS_AES_ALT +#define POLARSSL_AES_ALT MBEDTLS_AES_ALT +#endif +#if defined MBEDTLS_AES_C +#define POLARSSL_AES_C MBEDTLS_AES_C +#endif +#if defined MBEDTLS_AES_ROM_TABLES +#define POLARSSL_AES_ROM_TABLES MBEDTLS_AES_ROM_TABLES +#endif +#if defined MBEDTLS_ARC4_ALT +#define POLARSSL_ARC4_ALT MBEDTLS_ARC4_ALT +#endif +#if defined MBEDTLS_ARC4_C +#define POLARSSL_ARC4_C MBEDTLS_ARC4_C +#endif +#if defined MBEDTLS_ASN1_PARSE_C +#define POLARSSL_ASN1_PARSE_C MBEDTLS_ASN1_PARSE_C +#endif +#if defined MBEDTLS_ASN1_WRITE_C +#define POLARSSL_ASN1_WRITE_C MBEDTLS_ASN1_WRITE_C +#endif +#if defined MBEDTLS_BASE64_C +#define POLARSSL_BASE64_C MBEDTLS_BASE64_C +#endif +#if defined MBEDTLS_BIGNUM_C +#define POLARSSL_BIGNUM_C MBEDTLS_BIGNUM_C +#endif +#if defined MBEDTLS_BLOWFISH_ALT +#define POLARSSL_BLOWFISH_ALT MBEDTLS_BLOWFISH_ALT +#endif +#if defined MBEDTLS_BLOWFISH_C +#define POLARSSL_BLOWFISH_C MBEDTLS_BLOWFISH_C +#endif +#if defined MBEDTLS_CAMELLIA_ALT +#define POLARSSL_CAMELLIA_ALT MBEDTLS_CAMELLIA_ALT +#endif +#if defined MBEDTLS_CAMELLIA_C +#define POLARSSL_CAMELLIA_C MBEDTLS_CAMELLIA_C +#endif +#if defined MBEDTLS_CAMELLIA_SMALL_MEMORY +#define POLARSSL_CAMELLIA_SMALL_MEMORY MBEDTLS_CAMELLIA_SMALL_MEMORY +#endif +#if defined MBEDTLS_CCM_C +#define POLARSSL_CCM_C MBEDTLS_CCM_C +#endif +#if defined MBEDTLS_CERTS_C +#define POLARSSL_CERTS_C MBEDTLS_CERTS_C +#endif +#if defined MBEDTLS_CIPHER_C +#define POLARSSL_CIPHER_C MBEDTLS_CIPHER_C +#endif +#if defined MBEDTLS_CIPHER_MODE_CBC +#define POLARSSL_CIPHER_MODE_CBC MBEDTLS_CIPHER_MODE_CBC +#endif +#if defined MBEDTLS_CIPHER_MODE_CFB +#define POLARSSL_CIPHER_MODE_CFB MBEDTLS_CIPHER_MODE_CFB +#endif +#if defined MBEDTLS_CIPHER_MODE_CTR +#define POLARSSL_CIPHER_MODE_CTR MBEDTLS_CIPHER_MODE_CTR +#endif +#if defined MBEDTLS_CIPHER_NULL_CIPHER +#define POLARSSL_CIPHER_NULL_CIPHER MBEDTLS_CIPHER_NULL_CIPHER +#endif +#if defined MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define POLARSSL_CIPHER_PADDING_ONE_AND_ZEROS MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#endif +#if defined MBEDTLS_CIPHER_PADDING_PKCS7 +#define POLARSSL_CIPHER_PADDING_PKCS7 MBEDTLS_CIPHER_PADDING_PKCS7 +#endif +#if defined MBEDTLS_CIPHER_PADDING_ZEROS +#define POLARSSL_CIPHER_PADDING_ZEROS MBEDTLS_CIPHER_PADDING_ZEROS +#endif +#if defined MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define POLARSSL_CIPHER_PADDING_ZEROS_AND_LEN MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#endif +#if defined MBEDTLS_CTR_DRBG_C +#define POLARSSL_CTR_DRBG_C MBEDTLS_CTR_DRBG_C +#endif +#if defined MBEDTLS_DEBUG_C +#define POLARSSL_DEBUG_C MBEDTLS_DEBUG_C +#endif +#if defined MBEDTLS_DEPRECATED_REMOVED +#define POLARSSL_DEPRECATED_REMOVED MBEDTLS_DEPRECATED_REMOVED +#endif +#if defined MBEDTLS_DEPRECATED_WARNING +#define POLARSSL_DEPRECATED_WARNING MBEDTLS_DEPRECATED_WARNING +#endif +#if defined MBEDTLS_DES_ALT +#define POLARSSL_DES_ALT MBEDTLS_DES_ALT +#endif +#if defined MBEDTLS_DES_C +#define POLARSSL_DES_C MBEDTLS_DES_C +#endif +#if defined MBEDTLS_DHM_C +#define POLARSSL_DHM_C MBEDTLS_DHM_C +#endif +#if defined MBEDTLS_ECDH_C +#define POLARSSL_ECDH_C MBEDTLS_ECDH_C +#endif +#if defined MBEDTLS_ECDSA_C +#define POLARSSL_ECDSA_C MBEDTLS_ECDSA_C +#endif +#if defined MBEDTLS_ECDSA_DETERMINISTIC +#define POLARSSL_ECDSA_DETERMINISTIC MBEDTLS_ECDSA_DETERMINISTIC +#endif +#if defined MBEDTLS_ECP_C +#define POLARSSL_ECP_C MBEDTLS_ECP_C +#endif +#if defined MBEDTLS_ECP_DP_BP256R1_ENABLED +#define POLARSSL_ECP_DP_BP256R1_ENABLED MBEDTLS_ECP_DP_BP256R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_BP384R1_ENABLED +#define POLARSSL_ECP_DP_BP384R1_ENABLED MBEDTLS_ECP_DP_BP384R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_BP512R1_ENABLED +#define POLARSSL_ECP_DP_BP512R1_ENABLED MBEDTLS_ECP_DP_BP512R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_CURVE25519_ENABLED +#define POLARSSL_ECP_DP_M255_ENABLED MBEDTLS_ECP_DP_CURVE25519_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define POLARSSL_ECP_DP_SECP192K1_ENABLED MBEDTLS_ECP_DP_SECP192K1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define POLARSSL_ECP_DP_SECP192R1_ENABLED MBEDTLS_ECP_DP_SECP192R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define POLARSSL_ECP_DP_SECP224K1_ENABLED MBEDTLS_ECP_DP_SECP224K1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define POLARSSL_ECP_DP_SECP224R1_ENABLED MBEDTLS_ECP_DP_SECP224R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define POLARSSL_ECP_DP_SECP256K1_ENABLED MBEDTLS_ECP_DP_SECP256K1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define POLARSSL_ECP_DP_SECP256R1_ENABLED MBEDTLS_ECP_DP_SECP256R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define POLARSSL_ECP_DP_SECP384R1_ENABLED MBEDTLS_ECP_DP_SECP384R1_ENABLED +#endif +#if defined MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define POLARSSL_ECP_DP_SECP521R1_ENABLED MBEDTLS_ECP_DP_SECP521R1_ENABLED +#endif +#if defined MBEDTLS_ECP_FIXED_POINT_OPTIM +#define POLARSSL_ECP_FIXED_POINT_OPTIM MBEDTLS_ECP_FIXED_POINT_OPTIM +#endif +#if defined MBEDTLS_ECP_MAX_BITS +#define POLARSSL_ECP_MAX_BITS MBEDTLS_ECP_MAX_BITS +#endif +#if defined MBEDTLS_ECP_NIST_OPTIM +#define POLARSSL_ECP_NIST_OPTIM MBEDTLS_ECP_NIST_OPTIM +#endif +#if defined MBEDTLS_ECP_WINDOW_SIZE +#define POLARSSL_ECP_WINDOW_SIZE MBEDTLS_ECP_WINDOW_SIZE +#endif +#if defined MBEDTLS_ENABLE_WEAK_CIPHERSUITES +#define POLARSSL_ENABLE_WEAK_CIPHERSUITES MBEDTLS_ENABLE_WEAK_CIPHERSUITES +#endif +#if defined MBEDTLS_ENTROPY_C +#define POLARSSL_ENTROPY_C MBEDTLS_ENTROPY_C +#endif +#if defined MBEDTLS_ENTROPY_FORCE_SHA256 +#define POLARSSL_ENTROPY_FORCE_SHA256 MBEDTLS_ENTROPY_FORCE_SHA256 +#endif +#if defined MBEDTLS_ERROR_C +#define POLARSSL_ERROR_C MBEDTLS_ERROR_C +#endif +#if defined MBEDTLS_ERROR_STRERROR_BC +#define POLARSSL_ERROR_STRERROR_BC MBEDTLS_ERROR_STRERROR_BC +#endif +#if defined MBEDTLS_ERROR_STRERROR_DUMMY +#define POLARSSL_ERROR_STRERROR_DUMMY MBEDTLS_ERROR_STRERROR_DUMMY +#endif +#if defined MBEDTLS_FS_IO +#define POLARSSL_FS_IO MBEDTLS_FS_IO +#endif +#if defined MBEDTLS_GCM_C +#define POLARSSL_GCM_C MBEDTLS_GCM_C +#endif +#if defined MBEDTLS_GENPRIME +#define POLARSSL_GENPRIME MBEDTLS_GENPRIME +#endif +#if defined MBEDTLS_HAVEGE_C +#define POLARSSL_HAVEGE_C MBEDTLS_HAVEGE_C +#endif +#if defined MBEDTLS_HAVE_ASM +#define POLARSSL_HAVE_ASM MBEDTLS_HAVE_ASM +#endif +#if defined MBEDTLS_HAVE_SSE2 +#define POLARSSL_HAVE_SSE2 MBEDTLS_HAVE_SSE2 +#endif +#if defined MBEDTLS_HAVE_TIME +#define POLARSSL_HAVE_TIME MBEDTLS_HAVE_TIME +#endif +#if defined MBEDTLS_HMAC_DRBG_C +#define POLARSSL_HMAC_DRBG_C MBEDTLS_HMAC_DRBG_C +#endif +#if defined MBEDTLS_HMAC_DRBG_MAX_INPUT +#define POLARSSL_HMAC_DRBG_MAX_INPUT MBEDTLS_HMAC_DRBG_MAX_INPUT +#endif +#if defined MBEDTLS_HMAC_DRBG_MAX_REQUEST +#define POLARSSL_HMAC_DRBG_MAX_REQUEST MBEDTLS_HMAC_DRBG_MAX_REQUEST +#endif +#if defined MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT +#define POLARSSL_HMAC_DRBG_MAX_SEED_INPUT MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT +#endif +#if defined MBEDTLS_HMAC_DRBG_RESEED_INTERVAL +#define POLARSSL_HMAC_DRBG_RESEED_INTERVAL MBEDTLS_HMAC_DRBG_RESEED_INTERVAL +#endif +#if defined MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_PSK_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#define POLARSSL_KEY_EXCHANGE_RSA_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_ENABLED +#endif +#if defined MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED +#endif +#if defined MBEDTLS_MD2_ALT +#define POLARSSL_MD2_ALT MBEDTLS_MD2_ALT +#endif +#if defined MBEDTLS_MD2_C +#define POLARSSL_MD2_C MBEDTLS_MD2_C +#endif +#if defined MBEDTLS_MD2_PROCESS_ALT +#define POLARSSL_MD2_PROCESS_ALT MBEDTLS_MD2_PROCESS_ALT +#endif +#if defined MBEDTLS_MD4_ALT +#define POLARSSL_MD4_ALT MBEDTLS_MD4_ALT +#endif +#if defined MBEDTLS_MD4_C +#define POLARSSL_MD4_C MBEDTLS_MD4_C +#endif +#if defined MBEDTLS_MD4_PROCESS_ALT +#define POLARSSL_MD4_PROCESS_ALT MBEDTLS_MD4_PROCESS_ALT +#endif +#if defined MBEDTLS_MD5_ALT +#define POLARSSL_MD5_ALT MBEDTLS_MD5_ALT +#endif +#if defined MBEDTLS_MD5_C +#define POLARSSL_MD5_C MBEDTLS_MD5_C +#endif +#if defined MBEDTLS_MD5_PROCESS_ALT +#define POLARSSL_MD5_PROCESS_ALT MBEDTLS_MD5_PROCESS_ALT +#endif +#if defined MBEDTLS_MD_C +#define POLARSSL_MD_C MBEDTLS_MD_C +#endif +#if defined MBEDTLS_MEMORY_ALIGN_MULTIPLE +#define POLARSSL_MEMORY_ALIGN_MULTIPLE MBEDTLS_MEMORY_ALIGN_MULTIPLE +#endif +#if defined MBEDTLS_MEMORY_BACKTRACE +#define POLARSSL_MEMORY_BACKTRACE MBEDTLS_MEMORY_BACKTRACE +#endif +#if defined MBEDTLS_MEMORY_BUFFER_ALLOC_C +#define POLARSSL_MEMORY_BUFFER_ALLOC_C MBEDTLS_MEMORY_BUFFER_ALLOC_C +#endif +#if defined MBEDTLS_MEMORY_C +#define POLARSSL_MEMORY_C MBEDTLS_MEMORY_C +#endif +#if defined MBEDTLS_MEMORY_DEBUG +#define POLARSSL_MEMORY_DEBUG MBEDTLS_MEMORY_DEBUG +#endif +#if defined MBEDTLS_MPI_MAX_SIZE +#define POLARSSL_MPI_MAX_SIZE MBEDTLS_MPI_MAX_SIZE +#endif +#if defined MBEDTLS_MPI_WINDOW_SIZE +#define POLARSSL_MPI_WINDOW_SIZE MBEDTLS_MPI_WINDOW_SIZE +#endif +#if defined MBEDTLS_NET_C +#define POLARSSL_NET_C MBEDTLS_NET_C +#endif +#if defined MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +#define POLARSSL_NO_DEFAULT_ENTROPY_SOURCES MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES +#endif +#if defined MBEDTLS_NO_PLATFORM_ENTROPY +#define POLARSSL_NO_PLATFORM_ENTROPY MBEDTLS_NO_PLATFORM_ENTROPY +#endif +#if defined MBEDTLS_OID_C +#define POLARSSL_OID_C MBEDTLS_OID_C +#endif +#if defined MBEDTLS_PADLOCK_C +#define POLARSSL_PADLOCK_C MBEDTLS_PADLOCK_C +#endif +#if defined MBEDTLS_PBKDF2_C +#define POLARSSL_PBKDF2_C MBEDTLS_PBKDF2_C +#endif +#if defined MBEDTLS_PEM_PARSE_C +#define POLARSSL_PEM_PARSE_C MBEDTLS_PEM_PARSE_C +#endif +#if defined MBEDTLS_PEM_WRITE_C +#define POLARSSL_PEM_WRITE_C MBEDTLS_PEM_WRITE_C +#endif +#if defined MBEDTLS_PKCS11_C +#define POLARSSL_PKCS11_C MBEDTLS_PKCS11_C +#endif +#if defined MBEDTLS_PKCS12_C +#define POLARSSL_PKCS12_C MBEDTLS_PKCS12_C +#endif +#if defined MBEDTLS_PKCS1_V15 +#define POLARSSL_PKCS1_V15 MBEDTLS_PKCS1_V15 +#endif +#if defined MBEDTLS_PKCS1_V21 +#define POLARSSL_PKCS1_V21 MBEDTLS_PKCS1_V21 +#endif +#if defined MBEDTLS_PKCS5_C +#define POLARSSL_PKCS5_C MBEDTLS_PKCS5_C +#endif +#if defined MBEDTLS_PK_C +#define POLARSSL_PK_C MBEDTLS_PK_C +#endif +#if defined MBEDTLS_PK_PARSE_C +#define POLARSSL_PK_PARSE_C MBEDTLS_PK_PARSE_C +#endif +#if defined MBEDTLS_PK_PARSE_EC_EXTENDED +#define POLARSSL_PK_PARSE_EC_EXTENDED MBEDTLS_PK_PARSE_EC_EXTENDED +#endif +#if defined MBEDTLS_PK_RSA_ALT_SUPPORT +#define POLARSSL_PK_RSA_ALT_SUPPORT MBEDTLS_PK_RSA_ALT_SUPPORT +#endif +#if defined MBEDTLS_PK_WRITE_C +#define POLARSSL_PK_WRITE_C MBEDTLS_PK_WRITE_C +#endif +#if defined MBEDTLS_PLATFORM_C +#define POLARSSL_PLATFORM_C MBEDTLS_PLATFORM_C +#endif +#if defined MBEDTLS_PLATFORM_EXIT_ALT +#define POLARSSL_PLATFORM_EXIT_ALT MBEDTLS_PLATFORM_EXIT_ALT +#endif +#if defined MBEDTLS_PLATFORM_EXIT_MACRO +#define POLARSSL_PLATFORM_EXIT_MACRO MBEDTLS_PLATFORM_EXIT_MACRO +#endif +#if defined MBEDTLS_PLATFORM_FPRINTF_ALT +#define POLARSSL_PLATFORM_FPRINTF_ALT MBEDTLS_PLATFORM_FPRINTF_ALT +#endif +#if defined MBEDTLS_PLATFORM_FPRINTF_MACRO +#define POLARSSL_PLATFORM_FPRINTF_MACRO MBEDTLS_PLATFORM_FPRINTF_MACRO +#endif +#if defined MBEDTLS_PLATFORM_FREE_MACRO +#define POLARSSL_PLATFORM_FREE_MACRO MBEDTLS_PLATFORM_FREE_MACRO +#endif +#if defined MBEDTLS_PLATFORM_MEMORY +#define POLARSSL_PLATFORM_MEMORY MBEDTLS_PLATFORM_MEMORY +#endif +#if defined MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#define POLARSSL_PLATFORM_NO_STD_FUNCTIONS MBEDTLS_PLATFORM_NO_STD_FUNCTIONS +#endif +#if defined MBEDTLS_PLATFORM_PRINTF_ALT +#define POLARSSL_PLATFORM_PRINTF_ALT MBEDTLS_PLATFORM_PRINTF_ALT +#endif +#if defined MBEDTLS_PLATFORM_PRINTF_MACRO +#define POLARSSL_PLATFORM_PRINTF_MACRO MBEDTLS_PLATFORM_PRINTF_MACRO +#endif +#if defined MBEDTLS_PLATFORM_SNPRINTF_ALT +#define POLARSSL_PLATFORM_SNPRINTF_ALT MBEDTLS_PLATFORM_SNPRINTF_ALT +#endif +#if defined MBEDTLS_PLATFORM_SNPRINTF_MACRO +#define POLARSSL_PLATFORM_SNPRINTF_MACRO MBEDTLS_PLATFORM_SNPRINTF_MACRO +#endif +#if defined MBEDTLS_PLATFORM_STD_EXIT +#define POLARSSL_PLATFORM_STD_EXIT MBEDTLS_PLATFORM_STD_EXIT +#endif +#if defined MBEDTLS_PLATFORM_STD_FPRINTF +#define POLARSSL_PLATFORM_STD_FPRINTF MBEDTLS_PLATFORM_STD_FPRINTF +#endif +#if defined MBEDTLS_PLATFORM_STD_FREE +#define POLARSSL_PLATFORM_STD_FREE MBEDTLS_PLATFORM_STD_FREE +#endif +#if defined MBEDTLS_PLATFORM_STD_MALLOC +#define POLARSSL_PLATFORM_STD_MALLOC MBEDTLS_PLATFORM_STD_MALLOC +#endif +#if defined MBEDTLS_PLATFORM_STD_MEM_HDR +#define POLARSSL_PLATFORM_STD_MEM_HDR MBEDTLS_PLATFORM_STD_MEM_HDR +#endif +#if defined MBEDTLS_PLATFORM_STD_PRINTF +#define POLARSSL_PLATFORM_STD_PRINTF MBEDTLS_PLATFORM_STD_PRINTF +#endif +#if defined MBEDTLS_PLATFORM_STD_SNPRINTF +#define POLARSSL_PLATFORM_STD_SNPRINTF MBEDTLS_PLATFORM_STD_SNPRINTF +#endif +#if defined MBEDTLS_PSK_MAX_LEN +#define POLARSSL_PSK_MAX_LEN MBEDTLS_PSK_MAX_LEN +#endif +#if defined MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#define POLARSSL_REMOVE_ARC4_CIPHERSUITES MBEDTLS_REMOVE_ARC4_CIPHERSUITES +#endif +#if defined MBEDTLS_RIPEMD160_ALT +#define POLARSSL_RIPEMD160_ALT MBEDTLS_RIPEMD160_ALT +#endif +#if defined MBEDTLS_RIPEMD160_C +#define POLARSSL_RIPEMD160_C MBEDTLS_RIPEMD160_C +#endif +#if defined MBEDTLS_RIPEMD160_PROCESS_ALT +#define POLARSSL_RIPEMD160_PROCESS_ALT MBEDTLS_RIPEMD160_PROCESS_ALT +#endif +#if defined MBEDTLS_RSA_C +#define POLARSSL_RSA_C MBEDTLS_RSA_C +#endif +#if defined MBEDTLS_RSA_NO_CRT +#define POLARSSL_RSA_NO_CRT MBEDTLS_RSA_NO_CRT +#endif +#if defined MBEDTLS_SELF_TEST +#define POLARSSL_SELF_TEST MBEDTLS_SELF_TEST +#endif +#if defined MBEDTLS_SHA1_ALT +#define POLARSSL_SHA1_ALT MBEDTLS_SHA1_ALT +#endif +#if defined MBEDTLS_SHA1_C +#define POLARSSL_SHA1_C MBEDTLS_SHA1_C +#endif +#if defined MBEDTLS_SHA1_PROCESS_ALT +#define POLARSSL_SHA1_PROCESS_ALT MBEDTLS_SHA1_PROCESS_ALT +#endif +#if defined MBEDTLS_SHA256_ALT +#define POLARSSL_SHA256_ALT MBEDTLS_SHA256_ALT +#endif +#if defined MBEDTLS_SHA256_C +#define POLARSSL_SHA256_C MBEDTLS_SHA256_C +#endif +#if defined MBEDTLS_SHA256_PROCESS_ALT +#define POLARSSL_SHA256_PROCESS_ALT MBEDTLS_SHA256_PROCESS_ALT +#endif +#if defined MBEDTLS_SHA512_ALT +#define POLARSSL_SHA512_ALT MBEDTLS_SHA512_ALT +#endif +#if defined MBEDTLS_SHA512_C +#define POLARSSL_SHA512_C MBEDTLS_SHA512_C +#endif +#if defined MBEDTLS_SHA512_PROCESS_ALT +#define POLARSSL_SHA512_PROCESS_ALT MBEDTLS_SHA512_PROCESS_ALT +#endif +#if defined MBEDTLS_SSL_AEAD_RANDOM_IV +#define POLARSSL_SSL_AEAD_RANDOM_IV MBEDTLS_SSL_AEAD_RANDOM_IV +#endif +#if defined MBEDTLS_SSL_ALERT_MESSAGES +#define POLARSSL_SSL_ALERT_MESSAGES MBEDTLS_SSL_ALERT_MESSAGES +#endif +#if defined MBEDTLS_SSL_ALL_ALERT_MESSAGES +#define POLARSSL_SSL_ALL_ALERT_MESSAGES MBEDTLS_SSL_ALL_ALERT_MESSAGES +#endif +#if defined MBEDTLS_SSL_ALPN +#define POLARSSL_SSL_ALPN MBEDTLS_SSL_ALPN +#endif +#if defined MBEDTLS_SSL_CACHE_C +#define POLARSSL_SSL_CACHE_C MBEDTLS_SSL_CACHE_C +#endif +#if defined MBEDTLS_SSL_CBC_RECORD_SPLITTING +#define POLARSSL_SSL_CBC_RECORD_SPLITTING MBEDTLS_SSL_CBC_RECORD_SPLITTING +#endif +#if defined MBEDTLS_SSL_CLI_C +#define POLARSSL_SSL_CLI_C MBEDTLS_SSL_CLI_C +#endif +#if defined MBEDTLS_SSL_COOKIE_C +#define POLARSSL_SSL_COOKIE_C MBEDTLS_SSL_COOKIE_C +#endif +#if defined MBEDTLS_SSL_COOKIE_TIMEOUT +#define POLARSSL_SSL_COOKIE_TIMEOUT MBEDTLS_SSL_COOKIE_TIMEOUT +#endif +#if defined MBEDTLS_SSL_DEBUG_ALL +#define POLARSSL_SSL_DEBUG_ALL MBEDTLS_SSL_DEBUG_ALL +#endif +#if defined MBEDTLS_SSL_DISABLE_RENEGOTIATION +#define POLARSSL_SSL_DISABLE_RENEGOTIATION MBEDTLS_SSL_DISABLE_RENEGOTIATION +#endif +#if defined MBEDTLS_SSL_DTLS_ANTI_REPLAY +#define POLARSSL_SSL_DTLS_ANTI_REPLAY MBEDTLS_SSL_DTLS_ANTI_REPLAY +#endif +#if defined MBEDTLS_SSL_DTLS_BADMAC_LIMIT +#define POLARSSL_SSL_DTLS_BADMAC_LIMIT MBEDTLS_SSL_DTLS_BADMAC_LIMIT +#endif +#if defined MBEDTLS_SSL_DTLS_HELLO_VERIFY +#define POLARSSL_SSL_DTLS_HELLO_VERIFY MBEDTLS_SSL_DTLS_HELLO_VERIFY +#endif +#if defined MBEDTLS_SSL_ENCRYPT_THEN_MAC +#define POLARSSL_SSL_ENCRYPT_THEN_MAC MBEDTLS_SSL_ENCRYPT_THEN_MAC +#endif +#if defined MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#define POLARSSL_SSL_EXTENDED_MASTER_SECRET MBEDTLS_SSL_EXTENDED_MASTER_SECRET +#endif +#if defined MBEDTLS_SSL_FALLBACK_SCSV +#define POLARSSL_SSL_FALLBACK_SCSV MBEDTLS_SSL_FALLBACK_SCSV +#endif +#if defined MBEDTLS_SSL_HW_RECORD_ACCEL +#define POLARSSL_SSL_HW_RECORD_ACCEL MBEDTLS_SSL_HW_RECORD_ACCEL +#endif +#if defined MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#define POLARSSL_SSL_MAX_FRAGMENT_LENGTH MBEDTLS_SSL_MAX_FRAGMENT_LENGTH +#endif +#if defined MBEDTLS_SSL_PROTO_DTLS +#define POLARSSL_SSL_PROTO_DTLS MBEDTLS_SSL_PROTO_DTLS +#endif +#if defined MBEDTLS_SSL_PROTO_SSL3 +#define POLARSSL_SSL_PROTO_SSL3 MBEDTLS_SSL_PROTO_SSL3 +#endif +#if defined MBEDTLS_SSL_PROTO_TLS1 +#define POLARSSL_SSL_PROTO_TLS1 MBEDTLS_SSL_PROTO_TLS1 +#endif +#if defined MBEDTLS_SSL_PROTO_TLS1_1 +#define POLARSSL_SSL_PROTO_TLS1_1 MBEDTLS_SSL_PROTO_TLS1_1 +#endif +#if defined MBEDTLS_SSL_PROTO_TLS1_2 +#define POLARSSL_SSL_PROTO_TLS1_2 MBEDTLS_SSL_PROTO_TLS1_2 +#endif +#if defined MBEDTLS_SSL_RENEGOTIATION +#define POLARSSL_SSL_RENEGOTIATION MBEDTLS_SSL_RENEGOTIATION +#endif +#if defined MBEDTLS_SSL_SERVER_NAME_INDICATION +#define POLARSSL_SSL_SERVER_NAME_INDICATION MBEDTLS_SSL_SERVER_NAME_INDICATION +#endif +#if defined MBEDTLS_SSL_SESSION_TICKETS +#define POLARSSL_SSL_SESSION_TICKETS MBEDTLS_SSL_SESSION_TICKETS +#endif +#if defined MBEDTLS_SSL_SRV_C +#define POLARSSL_SSL_SRV_C MBEDTLS_SSL_SRV_C +#endif +#if defined MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE +#define POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE +#endif +#if defined MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO +#define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO +#endif +#if defined MBEDTLS_SSL_TLS_C +#define POLARSSL_SSL_TLS_C MBEDTLS_SSL_TLS_C +#endif +#if defined MBEDTLS_SSL_TRUNCATED_HMAC +#define POLARSSL_SSL_TRUNCATED_HMAC MBEDTLS_SSL_TRUNCATED_HMAC +#endif +#if defined MBEDTLS_THREADING_ALT +#define POLARSSL_THREADING_ALT MBEDTLS_THREADING_ALT +#endif +#if defined MBEDTLS_THREADING_C +#define POLARSSL_THREADING_C MBEDTLS_THREADING_C +#endif +#if defined MBEDTLS_THREADING_PTHREAD +#define POLARSSL_THREADING_PTHREAD MBEDTLS_THREADING_PTHREAD +#endif +#if defined MBEDTLS_TIMING_ALT +#define POLARSSL_TIMING_ALT MBEDTLS_TIMING_ALT +#endif +#if defined MBEDTLS_TIMING_C +#define POLARSSL_TIMING_C MBEDTLS_TIMING_C +#endif +#if defined MBEDTLS_VERSION_C +#define POLARSSL_VERSION_C MBEDTLS_VERSION_C +#endif +#if defined MBEDTLS_VERSION_FEATURES +#define POLARSSL_VERSION_FEATURES MBEDTLS_VERSION_FEATURES +#endif +#if defined MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 +#define POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3 MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 +#endif +#if defined MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION +#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION +#endif +#if defined MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE +#define POLARSSL_X509_CHECK_EXTENDED_KEY_USAGE MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE +#endif +#if defined MBEDTLS_X509_CHECK_KEY_USAGE +#define POLARSSL_X509_CHECK_KEY_USAGE MBEDTLS_X509_CHECK_KEY_USAGE +#endif +#if defined MBEDTLS_X509_CREATE_C +#define POLARSSL_X509_CREATE_C MBEDTLS_X509_CREATE_C +#endif +#if defined MBEDTLS_X509_CRL_PARSE_C +#define POLARSSL_X509_CRL_PARSE_C MBEDTLS_X509_CRL_PARSE_C +#endif +#if defined MBEDTLS_X509_CRT_PARSE_C +#define POLARSSL_X509_CRT_PARSE_C MBEDTLS_X509_CRT_PARSE_C +#endif +#if defined MBEDTLS_X509_CRT_WRITE_C +#define POLARSSL_X509_CRT_WRITE_C MBEDTLS_X509_CRT_WRITE_C +#endif +#if defined MBEDTLS_X509_CSR_PARSE_C +#define POLARSSL_X509_CSR_PARSE_C MBEDTLS_X509_CSR_PARSE_C +#endif +#if defined MBEDTLS_X509_CSR_WRITE_C +#define POLARSSL_X509_CSR_WRITE_C MBEDTLS_X509_CSR_WRITE_C +#endif +#if defined MBEDTLS_X509_MAX_INTERMEDIATE_CA +#define POLARSSL_X509_MAX_INTERMEDIATE_CA MBEDTLS_X509_MAX_INTERMEDIATE_CA +#endif +#if defined MBEDTLS_X509_RSASSA_PSS_SUPPORT +#define POLARSSL_X509_RSASSA_PSS_SUPPORT MBEDTLS_X509_RSASSA_PSS_SUPPORT +#endif +#if defined MBEDTLS_X509_USE_C +#define POLARSSL_X509_USE_C MBEDTLS_X509_USE_C +#endif +#if defined MBEDTLS_XTEA_ALT +#define POLARSSL_XTEA_ALT MBEDTLS_XTEA_ALT +#endif +#if defined MBEDTLS_XTEA_C +#define POLARSSL_XTEA_C MBEDTLS_XTEA_C +#endif +#if defined MBEDTLS_ZLIB_SUPPORT +#define POLARSSL_ZLIB_SUPPORT MBEDTLS_ZLIB_SUPPORT +#endif + +/* + * Misc names (macros, types, functions, enum constants...) + */ +#define AES_DECRYPT MBEDTLS_AES_DECRYPT +#define AES_ENCRYPT MBEDTLS_AES_ENCRYPT +#define ASN1_BIT_STRING MBEDTLS_ASN1_BIT_STRING +#define ASN1_BMP_STRING MBEDTLS_ASN1_BMP_STRING +#define ASN1_BOOLEAN MBEDTLS_ASN1_BOOLEAN +#define ASN1_CHK_ADD MBEDTLS_ASN1_CHK_ADD +#define ASN1_CONSTRUCTED MBEDTLS_ASN1_CONSTRUCTED +#define ASN1_CONTEXT_SPECIFIC MBEDTLS_ASN1_CONTEXT_SPECIFIC +#define ASN1_GENERALIZED_TIME MBEDTLS_ASN1_GENERALIZED_TIME +#define ASN1_IA5_STRING MBEDTLS_ASN1_IA5_STRING +#define ASN1_INTEGER MBEDTLS_ASN1_INTEGER +#define ASN1_NULL MBEDTLS_ASN1_NULL +#define ASN1_OCTET_STRING MBEDTLS_ASN1_OCTET_STRING +#define ASN1_OID MBEDTLS_ASN1_OID +#define ASN1_PRIMITIVE MBEDTLS_ASN1_PRIMITIVE +#define ASN1_PRINTABLE_STRING MBEDTLS_ASN1_PRINTABLE_STRING +#define ASN1_SEQUENCE MBEDTLS_ASN1_SEQUENCE +#define ASN1_SET MBEDTLS_ASN1_SET +#define ASN1_T61_STRING MBEDTLS_ASN1_T61_STRING +#define ASN1_UNIVERSAL_STRING MBEDTLS_ASN1_UNIVERSAL_STRING +#define ASN1_UTC_TIME MBEDTLS_ASN1_UTC_TIME +#define ASN1_UTF8_STRING MBEDTLS_ASN1_UTF8_STRING +#define BADCERT_CN_MISMATCH MBEDTLS_X509_BADCERT_CN_MISMATCH +#define BADCERT_EXPIRED MBEDTLS_X509_BADCERT_EXPIRED +#define BADCERT_FUTURE MBEDTLS_X509_BADCERT_FUTURE +#define BADCERT_MISSING MBEDTLS_X509_BADCERT_MISSING +#define BADCERT_NOT_TRUSTED MBEDTLS_X509_BADCERT_NOT_TRUSTED +#define BADCERT_OTHER MBEDTLS_X509_BADCERT_OTHER +#define BADCERT_REVOKED MBEDTLS_X509_BADCERT_REVOKED +#define BADCERT_SKIP_VERIFY MBEDTLS_X509_BADCERT_SKIP_VERIFY +#define BADCRL_EXPIRED MBEDTLS_X509_BADCRL_EXPIRED +#define BADCRL_FUTURE MBEDTLS_X509_BADCRL_FUTURE +#define BADCRL_NOT_TRUSTED MBEDTLS_X509_BADCRL_NOT_TRUSTED +#define BLOWFISH_BLOCKSIZE MBEDTLS_BLOWFISH_BLOCKSIZE +#define BLOWFISH_DECRYPT MBEDTLS_BLOWFISH_DECRYPT +#define BLOWFISH_ENCRYPT MBEDTLS_BLOWFISH_ENCRYPT +#define BLOWFISH_MAX_KEY MBEDTLS_BLOWFISH_MAX_KEY_BITS +#define BLOWFISH_MIN_KEY MBEDTLS_BLOWFISH_MIN_KEY_BITS +#define BLOWFISH_ROUNDS MBEDTLS_BLOWFISH_ROUNDS +#define CAMELLIA_DECRYPT MBEDTLS_CAMELLIA_DECRYPT +#define CAMELLIA_ENCRYPT MBEDTLS_CAMELLIA_ENCRYPT +#define COLLECT_SIZE MBEDTLS_HAVEGE_COLLECT_SIZE +#define CTR_DRBG_BLOCKSIZE MBEDTLS_CTR_DRBG_BLOCKSIZE +#define CTR_DRBG_ENTROPY_LEN MBEDTLS_CTR_DRBG_ENTROPY_LEN +#define CTR_DRBG_KEYBITS MBEDTLS_CTR_DRBG_KEYBITS +#define CTR_DRBG_KEYSIZE MBEDTLS_CTR_DRBG_KEYSIZE +#define CTR_DRBG_MAX_INPUT MBEDTLS_CTR_DRBG_MAX_INPUT +#define CTR_DRBG_MAX_REQUEST MBEDTLS_CTR_DRBG_MAX_REQUEST +#define CTR_DRBG_MAX_SEED_INPUT MBEDTLS_CTR_DRBG_MAX_SEED_INPUT +#define CTR_DRBG_PR_OFF MBEDTLS_CTR_DRBG_PR_OFF +#define CTR_DRBG_PR_ON MBEDTLS_CTR_DRBG_PR_ON +#define CTR_DRBG_RESEED_INTERVAL MBEDTLS_CTR_DRBG_RESEED_INTERVAL +#define CTR_DRBG_SEEDLEN MBEDTLS_CTR_DRBG_SEEDLEN +#define DEPRECATED MBEDTLS_DEPRECATED +#define DES_DECRYPT MBEDTLS_DES_DECRYPT +#define DES_ENCRYPT MBEDTLS_DES_ENCRYPT +#define DES_KEY_SIZE MBEDTLS_DES_KEY_SIZE +#define ENTROPY_BLOCK_SIZE MBEDTLS_ENTROPY_BLOCK_SIZE +#define ENTROPY_MAX_GATHER MBEDTLS_ENTROPY_MAX_GATHER +#define ENTROPY_MAX_SEED_SIZE MBEDTLS_ENTROPY_MAX_SEED_SIZE +#define ENTROPY_MAX_SOURCES MBEDTLS_ENTROPY_MAX_SOURCES +#define ENTROPY_MIN_HARDCLOCK MBEDTLS_ENTROPY_MIN_HARDCLOCK +#define ENTROPY_MIN_HAVEGE MBEDTLS_ENTROPY_MIN_HAVEGE +#define ENTROPY_MIN_PLATFORM MBEDTLS_ENTROPY_MIN_PLATFORM +#define ENTROPY_SOURCE_MANUAL MBEDTLS_ENTROPY_SOURCE_MANUAL +#define EXT_AUTHORITY_KEY_IDENTIFIER MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER +#define EXT_BASIC_CONSTRAINTS MBEDTLS_X509_EXT_BASIC_CONSTRAINTS +#define EXT_CERTIFICATE_POLICIES MBEDTLS_X509_EXT_CERTIFICATE_POLICIES +#define EXT_CRL_DISTRIBUTION_POINTS MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS +#define EXT_EXTENDED_KEY_USAGE MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE +#define EXT_FRESHEST_CRL MBEDTLS_X509_EXT_FRESHEST_CRL +#define EXT_INIHIBIT_ANYPOLICY MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY +#define EXT_ISSUER_ALT_NAME MBEDTLS_X509_EXT_ISSUER_ALT_NAME +#define EXT_KEY_USAGE MBEDTLS_X509_EXT_KEY_USAGE +#define EXT_NAME_CONSTRAINTS MBEDTLS_X509_EXT_NAME_CONSTRAINTS +#define EXT_NS_CERT_TYPE MBEDTLS_X509_EXT_NS_CERT_TYPE +#define EXT_POLICY_CONSTRAINTS MBEDTLS_X509_EXT_POLICY_CONSTRAINTS +#define EXT_POLICY_MAPPINGS MBEDTLS_X509_EXT_POLICY_MAPPINGS +#define EXT_SUBJECT_ALT_NAME MBEDTLS_X509_EXT_SUBJECT_ALT_NAME +#define EXT_SUBJECT_DIRECTORY_ATTRS MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS +#define EXT_SUBJECT_KEY_IDENTIFIER MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER +#define GCM_DECRYPT MBEDTLS_GCM_DECRYPT +#define GCM_ENCRYPT MBEDTLS_GCM_ENCRYPT +#define KU_CRL_SIGN MBEDTLS_X509_KU_CRL_SIGN +#define KU_DATA_ENCIPHERMENT MBEDTLS_X509_KU_DATA_ENCIPHERMENT +#define KU_DIGITAL_SIGNATURE MBEDTLS_X509_KU_DIGITAL_SIGNATURE +#define KU_KEY_AGREEMENT MBEDTLS_X509_KU_KEY_AGREEMENT +#define KU_KEY_CERT_SIGN MBEDTLS_X509_KU_KEY_CERT_SIGN +#define KU_KEY_ENCIPHERMENT MBEDTLS_X509_KU_KEY_ENCIPHERMENT +#define KU_NON_REPUDIATION MBEDTLS_X509_KU_NON_REPUDIATION +#define LN_2_DIV_LN_10_SCALE100 MBEDTLS_LN_2_DIV_LN_10_SCALE100 +#define MD_CONTEXT_T_INIT MBEDTLS_MD_CONTEXT_T_INIT +#define MEMORY_VERIFY_ALLOC MBEDTLS_MEMORY_VERIFY_ALLOC +#define MEMORY_VERIFY_ALWAYS MBEDTLS_MEMORY_VERIFY_ALWAYS +#define MEMORY_VERIFY_FREE MBEDTLS_MEMORY_VERIFY_FREE +#define MEMORY_VERIFY_NONE MBEDTLS_MEMORY_VERIFY_NONE +#define MPI_CHK MBEDTLS_MPI_CHK +#define NET_PROTO_TCP MBEDTLS_NET_PROTO_TCP +#define NET_PROTO_UDP MBEDTLS_NET_PROTO_UDP +#define NS_CERT_TYPE_EMAIL MBEDTLS_X509_NS_CERT_TYPE_EMAIL +#define NS_CERT_TYPE_EMAIL_CA MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA +#define NS_CERT_TYPE_OBJECT_SIGNING MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING +#define NS_CERT_TYPE_OBJECT_SIGNING_CA MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA +#define NS_CERT_TYPE_RESERVED MBEDTLS_X509_NS_CERT_TYPE_RESERVED +#define NS_CERT_TYPE_SSL_CA MBEDTLS_X509_NS_CERT_TYPE_SSL_CA +#define NS_CERT_TYPE_SSL_CLIENT MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT +#define NS_CERT_TYPE_SSL_SERVER MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER +#define OID_ANSI_X9_62 MBEDTLS_OID_ANSI_X9_62 +#define OID_ANSI_X9_62_FIELD_TYPE MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE +#define OID_ANSI_X9_62_PRIME_FIELD MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD +#define OID_ANSI_X9_62_SIG MBEDTLS_OID_ANSI_X9_62_SIG +#define OID_ANSI_X9_62_SIG_SHA2 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 +#define OID_ANY_EXTENDED_KEY_USAGE MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE +#define OID_AT MBEDTLS_OID_AT +#define OID_AT_CN MBEDTLS_OID_AT_CN +#define OID_AT_COUNTRY MBEDTLS_OID_AT_COUNTRY +#define OID_AT_DN_QUALIFIER MBEDTLS_OID_AT_DN_QUALIFIER +#define OID_AT_GENERATION_QUALIFIER MBEDTLS_OID_AT_GENERATION_QUALIFIER +#define OID_AT_GIVEN_NAME MBEDTLS_OID_AT_GIVEN_NAME +#define OID_AT_INITIALS MBEDTLS_OID_AT_INITIALS +#define OID_AT_LOCALITY MBEDTLS_OID_AT_LOCALITY +#define OID_AT_ORGANIZATION MBEDTLS_OID_AT_ORGANIZATION +#define OID_AT_ORG_UNIT MBEDTLS_OID_AT_ORG_UNIT +#define OID_AT_POSTAL_ADDRESS MBEDTLS_OID_AT_POSTAL_ADDRESS +#define OID_AT_POSTAL_CODE MBEDTLS_OID_AT_POSTAL_CODE +#define OID_AT_PSEUDONYM MBEDTLS_OID_AT_PSEUDONYM +#define OID_AT_SERIAL_NUMBER MBEDTLS_OID_AT_SERIAL_NUMBER +#define OID_AT_STATE MBEDTLS_OID_AT_STATE +#define OID_AT_SUR_NAME MBEDTLS_OID_AT_SUR_NAME +#define OID_AT_TITLE MBEDTLS_OID_AT_TITLE +#define OID_AT_UNIQUE_IDENTIFIER MBEDTLS_OID_AT_UNIQUE_IDENTIFIER +#define OID_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER +#define OID_BASIC_CONSTRAINTS MBEDTLS_OID_BASIC_CONSTRAINTS +#define OID_CERTICOM MBEDTLS_OID_CERTICOM +#define OID_CERTIFICATE_POLICIES MBEDTLS_OID_CERTIFICATE_POLICIES +#define OID_CLIENT_AUTH MBEDTLS_OID_CLIENT_AUTH +#define OID_CMP MBEDTLS_OID_CMP +#define OID_CODE_SIGNING MBEDTLS_OID_CODE_SIGNING +#define OID_COUNTRY_US MBEDTLS_OID_COUNTRY_US +#define OID_CRL_DISTRIBUTION_POINTS MBEDTLS_OID_CRL_DISTRIBUTION_POINTS +#define OID_CRL_NUMBER MBEDTLS_OID_CRL_NUMBER +#define OID_DES_CBC MBEDTLS_OID_DES_CBC +#define OID_DES_EDE3_CBC MBEDTLS_OID_DES_EDE3_CBC +#define OID_DIGEST_ALG_MD2 MBEDTLS_OID_DIGEST_ALG_MD2 +#define OID_DIGEST_ALG_MD4 MBEDTLS_OID_DIGEST_ALG_MD4 +#define OID_DIGEST_ALG_MD5 MBEDTLS_OID_DIGEST_ALG_MD5 +#define OID_DIGEST_ALG_SHA1 MBEDTLS_OID_DIGEST_ALG_SHA1 +#define OID_DIGEST_ALG_SHA224 MBEDTLS_OID_DIGEST_ALG_SHA224 +#define OID_DIGEST_ALG_SHA256 MBEDTLS_OID_DIGEST_ALG_SHA256 +#define OID_DIGEST_ALG_SHA384 MBEDTLS_OID_DIGEST_ALG_SHA384 +#define OID_DIGEST_ALG_SHA512 MBEDTLS_OID_DIGEST_ALG_SHA512 +#define OID_DOMAIN_COMPONENT MBEDTLS_OID_DOMAIN_COMPONENT +#define OID_ECDSA_SHA1 MBEDTLS_OID_ECDSA_SHA1 +#define OID_ECDSA_SHA224 MBEDTLS_OID_ECDSA_SHA224 +#define OID_ECDSA_SHA256 MBEDTLS_OID_ECDSA_SHA256 +#define OID_ECDSA_SHA384 MBEDTLS_OID_ECDSA_SHA384 +#define OID_ECDSA_SHA512 MBEDTLS_OID_ECDSA_SHA512 +#define OID_EC_ALG_ECDH MBEDTLS_OID_EC_ALG_ECDH +#define OID_EC_ALG_UNRESTRICTED MBEDTLS_OID_EC_ALG_UNRESTRICTED +#define OID_EC_BRAINPOOL_V1 MBEDTLS_OID_EC_BRAINPOOL_V1 +#define OID_EC_GRP_BP256R1 MBEDTLS_OID_EC_GRP_BP256R1 +#define OID_EC_GRP_BP384R1 MBEDTLS_OID_EC_GRP_BP384R1 +#define OID_EC_GRP_BP512R1 MBEDTLS_OID_EC_GRP_BP512R1 +#define OID_EC_GRP_SECP192K1 MBEDTLS_OID_EC_GRP_SECP192K1 +#define OID_EC_GRP_SECP192R1 MBEDTLS_OID_EC_GRP_SECP192R1 +#define OID_EC_GRP_SECP224K1 MBEDTLS_OID_EC_GRP_SECP224K1 +#define OID_EC_GRP_SECP224R1 MBEDTLS_OID_EC_GRP_SECP224R1 +#define OID_EC_GRP_SECP256K1 MBEDTLS_OID_EC_GRP_SECP256K1 +#define OID_EC_GRP_SECP256R1 MBEDTLS_OID_EC_GRP_SECP256R1 +#define OID_EC_GRP_SECP384R1 MBEDTLS_OID_EC_GRP_SECP384R1 +#define OID_EC_GRP_SECP521R1 MBEDTLS_OID_EC_GRP_SECP521R1 +#define OID_EMAIL_PROTECTION MBEDTLS_OID_EMAIL_PROTECTION +#define OID_EXTENDED_KEY_USAGE MBEDTLS_OID_EXTENDED_KEY_USAGE +#define OID_FRESHEST_CRL MBEDTLS_OID_FRESHEST_CRL +#define OID_GOV MBEDTLS_OID_GOV +#define OID_HMAC_SHA1 MBEDTLS_OID_HMAC_SHA1 +#define OID_ID_CE MBEDTLS_OID_ID_CE +#define OID_INIHIBIT_ANYPOLICY MBEDTLS_OID_INIHIBIT_ANYPOLICY +#define OID_ISO_CCITT_DS MBEDTLS_OID_ISO_CCITT_DS +#define OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ISO_IDENTIFIED_ORG +#define OID_ISO_ITU_COUNTRY MBEDTLS_OID_ISO_ITU_COUNTRY +#define OID_ISO_ITU_US_ORG MBEDTLS_OID_ISO_ITU_US_ORG +#define OID_ISO_MEMBER_BODIES MBEDTLS_OID_ISO_MEMBER_BODIES +#define OID_ISSUER_ALT_NAME MBEDTLS_OID_ISSUER_ALT_NAME +#define OID_KEY_USAGE MBEDTLS_OID_KEY_USAGE +#define OID_KP MBEDTLS_OID_KP +#define OID_MGF1 MBEDTLS_OID_MGF1 +#define OID_NAME_CONSTRAINTS MBEDTLS_OID_NAME_CONSTRAINTS +#define OID_NETSCAPE MBEDTLS_OID_NETSCAPE +#define OID_NS_BASE_URL MBEDTLS_OID_NS_BASE_URL +#define OID_NS_CA_POLICY_URL MBEDTLS_OID_NS_CA_POLICY_URL +#define OID_NS_CA_REVOCATION_URL MBEDTLS_OID_NS_CA_REVOCATION_URL +#define OID_NS_CERT MBEDTLS_OID_NS_CERT +#define OID_NS_CERT_SEQUENCE MBEDTLS_OID_NS_CERT_SEQUENCE +#define OID_NS_CERT_TYPE MBEDTLS_OID_NS_CERT_TYPE +#define OID_NS_COMMENT MBEDTLS_OID_NS_COMMENT +#define OID_NS_DATA_TYPE MBEDTLS_OID_NS_DATA_TYPE +#define OID_NS_RENEWAL_URL MBEDTLS_OID_NS_RENEWAL_URL +#define OID_NS_REVOCATION_URL MBEDTLS_OID_NS_REVOCATION_URL +#define OID_NS_SSL_SERVER_NAME MBEDTLS_OID_NS_SSL_SERVER_NAME +#define OID_OCSP_SIGNING MBEDTLS_OID_OCSP_SIGNING +#define OID_OIW_SECSIG MBEDTLS_OID_OIW_SECSIG +#define OID_OIW_SECSIG_ALG MBEDTLS_OID_OIW_SECSIG_ALG +#define OID_OIW_SECSIG_SHA1 MBEDTLS_OID_OIW_SECSIG_SHA1 +#define OID_ORGANIZATION MBEDTLS_OID_ORGANIZATION +#define OID_ORG_ANSI_X9_62 MBEDTLS_OID_ORG_ANSI_X9_62 +#define OID_ORG_CERTICOM MBEDTLS_OID_ORG_CERTICOM +#define OID_ORG_DOD MBEDTLS_OID_ORG_DOD +#define OID_ORG_GOV MBEDTLS_OID_ORG_GOV +#define OID_ORG_NETSCAPE MBEDTLS_OID_ORG_NETSCAPE +#define OID_ORG_OIW MBEDTLS_OID_ORG_OIW +#define OID_ORG_RSA_DATA_SECURITY MBEDTLS_OID_ORG_RSA_DATA_SECURITY +#define OID_ORG_TELETRUST MBEDTLS_OID_ORG_TELETRUST +#define OID_PKCS MBEDTLS_OID_PKCS +#define OID_PKCS1 MBEDTLS_OID_PKCS1 +#define OID_PKCS12 MBEDTLS_OID_PKCS12 +#define OID_PKCS12_PBE MBEDTLS_OID_PKCS12_PBE +#define OID_PKCS12_PBE_SHA1_DES2_EDE_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC +#define OID_PKCS12_PBE_SHA1_DES3_EDE_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC +#define OID_PKCS12_PBE_SHA1_RC2_128_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_128_CBC +#define OID_PKCS12_PBE_SHA1_RC2_40_CBC MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_40_CBC +#define OID_PKCS12_PBE_SHA1_RC4_128 MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128 +#define OID_PKCS12_PBE_SHA1_RC4_40 MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_40 +#define OID_PKCS1_MD2 MBEDTLS_OID_PKCS1_MD2 +#define OID_PKCS1_MD4 MBEDTLS_OID_PKCS1_MD4 +#define OID_PKCS1_MD5 MBEDTLS_OID_PKCS1_MD5 +#define OID_PKCS1_RSA MBEDTLS_OID_PKCS1_RSA +#define OID_PKCS1_SHA1 MBEDTLS_OID_PKCS1_SHA1 +#define OID_PKCS1_SHA224 MBEDTLS_OID_PKCS1_SHA224 +#define OID_PKCS1_SHA256 MBEDTLS_OID_PKCS1_SHA256 +#define OID_PKCS1_SHA384 MBEDTLS_OID_PKCS1_SHA384 +#define OID_PKCS1_SHA512 MBEDTLS_OID_PKCS1_SHA512 +#define OID_PKCS5 MBEDTLS_OID_PKCS5 +#define OID_PKCS5_PBES2 MBEDTLS_OID_PKCS5_PBES2 +#define OID_PKCS5_PBE_MD2_DES_CBC MBEDTLS_OID_PKCS5_PBE_MD2_DES_CBC +#define OID_PKCS5_PBE_MD2_RC2_CBC MBEDTLS_OID_PKCS5_PBE_MD2_RC2_CBC +#define OID_PKCS5_PBE_MD5_DES_CBC MBEDTLS_OID_PKCS5_PBE_MD5_DES_CBC +#define OID_PKCS5_PBE_MD5_RC2_CBC MBEDTLS_OID_PKCS5_PBE_MD5_RC2_CBC +#define OID_PKCS5_PBE_SHA1_DES_CBC MBEDTLS_OID_PKCS5_PBE_SHA1_DES_CBC +#define OID_PKCS5_PBE_SHA1_RC2_CBC MBEDTLS_OID_PKCS5_PBE_SHA1_RC2_CBC +#define OID_PKCS5_PBKDF2 MBEDTLS_OID_PKCS5_PBKDF2 +#define OID_PKCS5_PBMAC1 MBEDTLS_OID_PKCS5_PBMAC1 +#define OID_PKCS9 MBEDTLS_OID_PKCS9 +#define OID_PKCS9_CSR_EXT_REQ MBEDTLS_OID_PKCS9_CSR_EXT_REQ +#define OID_PKCS9_EMAIL MBEDTLS_OID_PKCS9_EMAIL +#define OID_PKIX MBEDTLS_OID_PKIX +#define OID_POLICY_CONSTRAINTS MBEDTLS_OID_POLICY_CONSTRAINTS +#define OID_POLICY_MAPPINGS MBEDTLS_OID_POLICY_MAPPINGS +#define OID_PRIVATE_KEY_USAGE_PERIOD MBEDTLS_OID_PRIVATE_KEY_USAGE_PERIOD +#define OID_RSASSA_PSS MBEDTLS_OID_RSASSA_PSS +#define OID_RSA_COMPANY MBEDTLS_OID_RSA_COMPANY +#define OID_RSA_SHA_OBS MBEDTLS_OID_RSA_SHA_OBS +#define OID_SERVER_AUTH MBEDTLS_OID_SERVER_AUTH +#define OID_SIZE MBEDTLS_OID_SIZE +#define OID_SUBJECT_ALT_NAME MBEDTLS_OID_SUBJECT_ALT_NAME +#define OID_SUBJECT_DIRECTORY_ATTRS MBEDTLS_OID_SUBJECT_DIRECTORY_ATTRS +#define OID_SUBJECT_KEY_IDENTIFIER MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER +#define OID_TELETRUST MBEDTLS_OID_TELETRUST +#define OID_TIME_STAMPING MBEDTLS_OID_TIME_STAMPING +#define PADLOCK_ACE MBEDTLS_PADLOCK_ACE +#define PADLOCK_ALIGN16 MBEDTLS_PADLOCK_ALIGN16 +#define PADLOCK_PHE MBEDTLS_PADLOCK_PHE +#define PADLOCK_PMM MBEDTLS_PADLOCK_PMM +#define PADLOCK_RNG MBEDTLS_PADLOCK_RNG +#define PKCS12_DERIVE_IV MBEDTLS_PKCS12_DERIVE_IV +#define PKCS12_DERIVE_KEY MBEDTLS_PKCS12_DERIVE_KEY +#define PKCS12_DERIVE_MAC_KEY MBEDTLS_PKCS12_DERIVE_MAC_KEY +#define PKCS12_PBE_DECRYPT MBEDTLS_PKCS12_PBE_DECRYPT +#define PKCS12_PBE_ENCRYPT MBEDTLS_PKCS12_PBE_ENCRYPT +#define PKCS5_DECRYPT MBEDTLS_PKCS5_DECRYPT +#define PKCS5_ENCRYPT MBEDTLS_PKCS5_ENCRYPT +#define POLARSSL_AESNI_AES MBEDTLS_AESNI_AES +#define POLARSSL_AESNI_CLMUL MBEDTLS_AESNI_CLMUL +#define POLARSSL_AESNI_H MBEDTLS_AESNI_H +#define POLARSSL_AES_H MBEDTLS_AES_H +#define POLARSSL_ARC4_H MBEDTLS_ARC4_H +#define POLARSSL_ASN1_H MBEDTLS_ASN1_H +#define POLARSSL_ASN1_WRITE_H MBEDTLS_ASN1_WRITE_H +#define POLARSSL_BASE64_H MBEDTLS_BASE64_H +#define POLARSSL_BIGNUM_H MBEDTLS_BIGNUM_H +#define POLARSSL_BLOWFISH_H MBEDTLS_BLOWFISH_H +#define POLARSSL_BN_MUL_H MBEDTLS_BN_MUL_H +#define POLARSSL_CAMELLIA_H MBEDTLS_CAMELLIA_H +#define POLARSSL_CCM_H MBEDTLS_CCM_H +#define POLARSSL_CERTS_H MBEDTLS_CERTS_H +#define POLARSSL_CHECK_CONFIG_H MBEDTLS_CHECK_CONFIG_H +#define POLARSSL_CIPHERSUITE_NODTLS MBEDTLS_CIPHERSUITE_NODTLS +#define POLARSSL_CIPHERSUITE_SHORT_TAG MBEDTLS_CIPHERSUITE_SHORT_TAG +#define POLARSSL_CIPHERSUITE_WEAK MBEDTLS_CIPHERSUITE_WEAK +#define POLARSSL_CIPHER_AES_128_CBC MBEDTLS_CIPHER_AES_128_CBC +#define POLARSSL_CIPHER_AES_128_CCM MBEDTLS_CIPHER_AES_128_CCM +#define POLARSSL_CIPHER_AES_128_CFB128 MBEDTLS_CIPHER_AES_128_CFB128 +#define POLARSSL_CIPHER_AES_128_CTR MBEDTLS_CIPHER_AES_128_CTR +#define POLARSSL_CIPHER_AES_128_ECB MBEDTLS_CIPHER_AES_128_ECB +#define POLARSSL_CIPHER_AES_128_GCM MBEDTLS_CIPHER_AES_128_GCM +#define POLARSSL_CIPHER_AES_192_CBC MBEDTLS_CIPHER_AES_192_CBC +#define POLARSSL_CIPHER_AES_192_CCM MBEDTLS_CIPHER_AES_192_CCM +#define POLARSSL_CIPHER_AES_192_CFB128 MBEDTLS_CIPHER_AES_192_CFB128 +#define POLARSSL_CIPHER_AES_192_CTR MBEDTLS_CIPHER_AES_192_CTR +#define POLARSSL_CIPHER_AES_192_ECB MBEDTLS_CIPHER_AES_192_ECB +#define POLARSSL_CIPHER_AES_192_GCM MBEDTLS_CIPHER_AES_192_GCM +#define POLARSSL_CIPHER_AES_256_CBC MBEDTLS_CIPHER_AES_256_CBC +#define POLARSSL_CIPHER_AES_256_CCM MBEDTLS_CIPHER_AES_256_CCM +#define POLARSSL_CIPHER_AES_256_CFB128 MBEDTLS_CIPHER_AES_256_CFB128 +#define POLARSSL_CIPHER_AES_256_CTR MBEDTLS_CIPHER_AES_256_CTR +#define POLARSSL_CIPHER_AES_256_ECB MBEDTLS_CIPHER_AES_256_ECB +#define POLARSSL_CIPHER_AES_256_GCM MBEDTLS_CIPHER_AES_256_GCM +#define POLARSSL_CIPHER_ARC4_128 MBEDTLS_CIPHER_ARC4_128 +#define POLARSSL_CIPHER_BLOWFISH_CBC MBEDTLS_CIPHER_BLOWFISH_CBC +#define POLARSSL_CIPHER_BLOWFISH_CFB64 MBEDTLS_CIPHER_BLOWFISH_CFB64 +#define POLARSSL_CIPHER_BLOWFISH_CTR MBEDTLS_CIPHER_BLOWFISH_CTR +#define POLARSSL_CIPHER_BLOWFISH_ECB MBEDTLS_CIPHER_BLOWFISH_ECB +#define POLARSSL_CIPHER_CAMELLIA_128_CBC MBEDTLS_CIPHER_CAMELLIA_128_CBC +#define POLARSSL_CIPHER_CAMELLIA_128_CCM MBEDTLS_CIPHER_CAMELLIA_128_CCM +#define POLARSSL_CIPHER_CAMELLIA_128_CFB128 MBEDTLS_CIPHER_CAMELLIA_128_CFB128 +#define POLARSSL_CIPHER_CAMELLIA_128_CTR MBEDTLS_CIPHER_CAMELLIA_128_CTR +#define POLARSSL_CIPHER_CAMELLIA_128_ECB MBEDTLS_CIPHER_CAMELLIA_128_ECB +#define POLARSSL_CIPHER_CAMELLIA_128_GCM MBEDTLS_CIPHER_CAMELLIA_128_GCM +#define POLARSSL_CIPHER_CAMELLIA_192_CBC MBEDTLS_CIPHER_CAMELLIA_192_CBC +#define POLARSSL_CIPHER_CAMELLIA_192_CCM MBEDTLS_CIPHER_CAMELLIA_192_CCM +#define POLARSSL_CIPHER_CAMELLIA_192_CFB128 MBEDTLS_CIPHER_CAMELLIA_192_CFB128 +#define POLARSSL_CIPHER_CAMELLIA_192_CTR MBEDTLS_CIPHER_CAMELLIA_192_CTR +#define POLARSSL_CIPHER_CAMELLIA_192_ECB MBEDTLS_CIPHER_CAMELLIA_192_ECB +#define POLARSSL_CIPHER_CAMELLIA_192_GCM MBEDTLS_CIPHER_CAMELLIA_192_GCM +#define POLARSSL_CIPHER_CAMELLIA_256_CBC MBEDTLS_CIPHER_CAMELLIA_256_CBC +#define POLARSSL_CIPHER_CAMELLIA_256_CCM MBEDTLS_CIPHER_CAMELLIA_256_CCM +#define POLARSSL_CIPHER_CAMELLIA_256_CFB128 MBEDTLS_CIPHER_CAMELLIA_256_CFB128 +#define POLARSSL_CIPHER_CAMELLIA_256_CTR MBEDTLS_CIPHER_CAMELLIA_256_CTR +#define POLARSSL_CIPHER_CAMELLIA_256_ECB MBEDTLS_CIPHER_CAMELLIA_256_ECB +#define POLARSSL_CIPHER_CAMELLIA_256_GCM MBEDTLS_CIPHER_CAMELLIA_256_GCM +#define POLARSSL_CIPHER_DES_CBC MBEDTLS_CIPHER_DES_CBC +#define POLARSSL_CIPHER_DES_ECB MBEDTLS_CIPHER_DES_ECB +#define POLARSSL_CIPHER_DES_EDE3_CBC MBEDTLS_CIPHER_DES_EDE3_CBC +#define POLARSSL_CIPHER_DES_EDE3_ECB MBEDTLS_CIPHER_DES_EDE3_ECB +#define POLARSSL_CIPHER_DES_EDE_CBC MBEDTLS_CIPHER_DES_EDE_CBC +#define POLARSSL_CIPHER_DES_EDE_ECB MBEDTLS_CIPHER_DES_EDE_ECB +#define POLARSSL_CIPHER_H MBEDTLS_CIPHER_H +#define POLARSSL_CIPHER_ID_3DES MBEDTLS_CIPHER_ID_3DES +#define POLARSSL_CIPHER_ID_AES MBEDTLS_CIPHER_ID_AES +#define POLARSSL_CIPHER_ID_ARC4 MBEDTLS_CIPHER_ID_ARC4 +#define POLARSSL_CIPHER_ID_BLOWFISH MBEDTLS_CIPHER_ID_BLOWFISH +#define POLARSSL_CIPHER_ID_CAMELLIA MBEDTLS_CIPHER_ID_CAMELLIA +#define POLARSSL_CIPHER_ID_DES MBEDTLS_CIPHER_ID_DES +#define POLARSSL_CIPHER_ID_NONE MBEDTLS_CIPHER_ID_NONE +#define POLARSSL_CIPHER_ID_NULL MBEDTLS_CIPHER_ID_NULL +#define POLARSSL_CIPHER_MODE_AEAD MBEDTLS_CIPHER_MODE_AEAD +#define POLARSSL_CIPHER_MODE_STREAM MBEDTLS_CIPHER_MODE_STREAM +#define POLARSSL_CIPHER_MODE_WITH_PADDING MBEDTLS_CIPHER_MODE_WITH_PADDING +#define POLARSSL_CIPHER_NONE MBEDTLS_CIPHER_NONE +#define POLARSSL_CIPHER_NULL MBEDTLS_CIPHER_NULL +#define POLARSSL_CIPHER_VARIABLE_IV_LEN MBEDTLS_CIPHER_VARIABLE_IV_LEN +#define POLARSSL_CIPHER_VARIABLE_KEY_LEN MBEDTLS_CIPHER_VARIABLE_KEY_LEN +#define POLARSSL_CIPHER_WRAP_H MBEDTLS_CIPHER_WRAP_H +#define POLARSSL_CONFIG_H MBEDTLS_CONFIG_H +#define POLARSSL_CTR_DRBG_H MBEDTLS_CTR_DRBG_H +#define POLARSSL_DEBUG_H MBEDTLS_DEBUG_H +#define POLARSSL_DEBUG_LOG_FULL MBEDTLS_DEBUG_LOG_FULL +#define POLARSSL_DEBUG_LOG_RAW MBEDTLS_DEBUG_LOG_RAW +#define POLARSSL_DECRYPT MBEDTLS_DECRYPT +#define POLARSSL_DES_H MBEDTLS_DES_H +#define POLARSSL_DHM_H MBEDTLS_DHM_H +#define POLARSSL_DHM_RFC2409_MODP_1024_G MBEDTLS_DHM_RFC2409_MODP_1024_G +#define POLARSSL_DHM_RFC2409_MODP_1024_P MBEDTLS_DHM_RFC2409_MODP_1024_P +#define POLARSSL_DHM_RFC3526_MODP_2048_G MBEDTLS_DHM_RFC3526_MODP_2048_G +#define POLARSSL_DHM_RFC3526_MODP_2048_P MBEDTLS_DHM_RFC3526_MODP_2048_P +#define POLARSSL_DHM_RFC3526_MODP_3072_G MBEDTLS_DHM_RFC3526_MODP_3072_G +#define POLARSSL_DHM_RFC3526_MODP_3072_P MBEDTLS_DHM_RFC3526_MODP_3072_P +#define POLARSSL_DHM_RFC5114_MODP_1024_G MBEDTLS_DHM_RFC5114_MODP_1024_G +#define POLARSSL_DHM_RFC5114_MODP_1024_P MBEDTLS_DHM_RFC5114_MODP_1024_P +#define POLARSSL_DHM_RFC5114_MODP_2048_G MBEDTLS_DHM_RFC5114_MODP_2048_G +#define POLARSSL_DHM_RFC5114_MODP_2048_P MBEDTLS_DHM_RFC5114_MODP_2048_P +#define POLARSSL_ECDH_H MBEDTLS_ECDH_H +#define POLARSSL_ECDH_OURS MBEDTLS_ECDH_OURS +#define POLARSSL_ECDH_THEIRS MBEDTLS_ECDH_THEIRS +#define POLARSSL_ECDSA_H MBEDTLS_ECDSA_H +#define POLARSSL_ECP_DP_BP256R1 MBEDTLS_ECP_DP_BP256R1 +#define POLARSSL_ECP_DP_BP384R1 MBEDTLS_ECP_DP_BP384R1 +#define POLARSSL_ECP_DP_BP512R1 MBEDTLS_ECP_DP_BP512R1 +#define POLARSSL_ECP_DP_M255 MBEDTLS_ECP_DP_CURVE25519 +#define POLARSSL_ECP_DP_MAX MBEDTLS_ECP_DP_MAX +#define POLARSSL_ECP_DP_NONE MBEDTLS_ECP_DP_NONE +#define POLARSSL_ECP_DP_SECP192K1 MBEDTLS_ECP_DP_SECP192K1 +#define POLARSSL_ECP_DP_SECP192R1 MBEDTLS_ECP_DP_SECP192R1 +#define POLARSSL_ECP_DP_SECP224K1 MBEDTLS_ECP_DP_SECP224K1 +#define POLARSSL_ECP_DP_SECP224R1 MBEDTLS_ECP_DP_SECP224R1 +#define POLARSSL_ECP_DP_SECP256K1 MBEDTLS_ECP_DP_SECP256K1 +#define POLARSSL_ECP_DP_SECP256R1 MBEDTLS_ECP_DP_SECP256R1 +#define POLARSSL_ECP_DP_SECP384R1 MBEDTLS_ECP_DP_SECP384R1 +#define POLARSSL_ECP_DP_SECP521R1 MBEDTLS_ECP_DP_SECP521R1 +#define POLARSSL_ECP_H MBEDTLS_ECP_H +#define POLARSSL_ECP_MAX_BYTES MBEDTLS_ECP_MAX_BYTES +#define POLARSSL_ECP_MAX_PT_LEN MBEDTLS_ECP_MAX_PT_LEN +#define POLARSSL_ECP_PF_COMPRESSED MBEDTLS_ECP_PF_COMPRESSED +#define POLARSSL_ECP_PF_UNCOMPRESSED MBEDTLS_ECP_PF_UNCOMPRESSED +#define POLARSSL_ECP_TLS_NAMED_CURVE MBEDTLS_ECP_TLS_NAMED_CURVE +#define POLARSSL_ENCRYPT MBEDTLS_ENCRYPT +#define POLARSSL_ENTROPY_H MBEDTLS_ENTROPY_H +#define POLARSSL_ENTROPY_POLL_H MBEDTLS_ENTROPY_POLL_H +#define POLARSSL_ENTROPY_SHA256_ACCUMULATOR MBEDTLS_ENTROPY_SHA256_ACCUMULATOR +#define POLARSSL_ENTROPY_SHA512_ACCUMULATOR MBEDTLS_ENTROPY_SHA512_ACCUMULATOR +#define POLARSSL_ERROR_H MBEDTLS_ERROR_H +#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH MBEDTLS_ERR_AES_INVALID_KEY_LENGTH +#define POLARSSL_ERR_ASN1_BUF_TOO_SMALL MBEDTLS_ERR_ASN1_BUF_TOO_SMALL +#define POLARSSL_ERR_ASN1_INVALID_DATA MBEDTLS_ERR_ASN1_INVALID_DATA +#define POLARSSL_ERR_ASN1_INVALID_LENGTH MBEDTLS_ERR_ASN1_INVALID_LENGTH +#define POLARSSL_ERR_ASN1_LENGTH_MISMATCH MBEDTLS_ERR_ASN1_LENGTH_MISMATCH +#define POLARSSL_ERR_ASN1_MALLOC_FAILED MBEDTLS_ERR_ASN1_ALLOC_FAILED +#define POLARSSL_ERR_ASN1_OUT_OF_DATA MBEDTLS_ERR_ASN1_OUT_OF_DATA +#define POLARSSL_ERR_ASN1_UNEXPECTED_TAG MBEDTLS_ERR_ASN1_UNEXPECTED_TAG +#define POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL +#define POLARSSL_ERR_BASE64_INVALID_CHARACTER MBEDTLS_ERR_BASE64_INVALID_CHARACTER +#define POLARSSL_ERR_BLOWFISH_INVALID_INPUT_LENGTH MBEDTLS_ERR_BLOWFISH_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_BLOWFISH_INVALID_KEY_LENGTH MBEDTLS_ERR_BLOWFISH_INVALID_KEY_LENGTH +#define POLARSSL_ERR_CAMELLIA_INVALID_INPUT_LENGTH MBEDTLS_ERR_CAMELLIA_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_CAMELLIA_INVALID_KEY_LENGTH MBEDTLS_ERR_CAMELLIA_INVALID_KEY_LENGTH +#define POLARSSL_ERR_CCM_AUTH_FAILED MBEDTLS_ERR_CCM_AUTH_FAILED +#define POLARSSL_ERR_CCM_BAD_INPUT MBEDTLS_ERR_CCM_BAD_INPUT +#define POLARSSL_ERR_CIPHER_ALLOC_FAILED MBEDTLS_ERR_CIPHER_ALLOC_FAILED +#define POLARSSL_ERR_CIPHER_AUTH_FAILED MBEDTLS_ERR_CIPHER_AUTH_FAILED +#define POLARSSL_ERR_CIPHER_BAD_INPUT_DATA MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA +#define POLARSSL_ERR_CIPHER_FEATURE_UNAVAILABLE MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_CIPHER_FULL_BLOCK_EXPECTED MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED +#define POLARSSL_ERR_CIPHER_INVALID_PADDING MBEDTLS_ERR_CIPHER_INVALID_PADDING +#define POLARSSL_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED +#define POLARSSL_ERR_CTR_DRBG_FILE_IO_ERROR MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR +#define POLARSSL_ERR_CTR_DRBG_INPUT_TOO_BIG MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG +#define POLARSSL_ERR_CTR_DRBG_REQUEST_TOO_BIG MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG +#define POLARSSL_ERR_DES_INVALID_INPUT_LENGTH MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH +#define POLARSSL_ERR_DHM_BAD_INPUT_DATA MBEDTLS_ERR_DHM_BAD_INPUT_DATA +#define POLARSSL_ERR_DHM_CALC_SECRET_FAILED MBEDTLS_ERR_DHM_CALC_SECRET_FAILED +#define POLARSSL_ERR_DHM_FILE_IO_ERROR MBEDTLS_ERR_DHM_FILE_IO_ERROR +#define POLARSSL_ERR_DHM_INVALID_FORMAT MBEDTLS_ERR_DHM_INVALID_FORMAT +#define POLARSSL_ERR_DHM_MAKE_PARAMS_FAILED MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED +#define POLARSSL_ERR_DHM_MAKE_PUBLIC_FAILED MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED +#define POLARSSL_ERR_DHM_MALLOC_FAILED MBEDTLS_ERR_DHM_ALLOC_FAILED +#define POLARSSL_ERR_DHM_READ_PARAMS_FAILED MBEDTLS_ERR_DHM_READ_PARAMS_FAILED +#define POLARSSL_ERR_DHM_READ_PUBLIC_FAILED MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED +#define POLARSSL_ERR_ECP_BAD_INPUT_DATA MBEDTLS_ERR_ECP_BAD_INPUT_DATA +#define POLARSSL_ERR_ECP_BUFFER_TOO_SMALL MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL +#define POLARSSL_ERR_ECP_FEATURE_UNAVAILABLE MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_ECP_INVALID_KEY MBEDTLS_ERR_ECP_INVALID_KEY +#define POLARSSL_ERR_ECP_MALLOC_FAILED MBEDTLS_ERR_ECP_ALLOC_FAILED +#define POLARSSL_ERR_ECP_RANDOM_FAILED MBEDTLS_ERR_ECP_RANDOM_FAILED +#define POLARSSL_ERR_ECP_SIG_LEN_MISMATCH MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH +#define POLARSSL_ERR_ECP_VERIFY_FAILED MBEDTLS_ERR_ECP_VERIFY_FAILED +#define POLARSSL_ERR_ENTROPY_FILE_IO_ERROR MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR +#define POLARSSL_ERR_ENTROPY_MAX_SOURCES MBEDTLS_ERR_ENTROPY_MAX_SOURCES +#define POLARSSL_ERR_ENTROPY_NO_SOURCES_DEFINED MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED +#define POLARSSL_ERR_ENTROPY_SOURCE_FAILED MBEDTLS_ERR_ENTROPY_SOURCE_FAILED +#define POLARSSL_ERR_GCM_AUTH_FAILED MBEDTLS_ERR_GCM_AUTH_FAILED +#define POLARSSL_ERR_GCM_BAD_INPUT MBEDTLS_ERR_GCM_BAD_INPUT +#define POLARSSL_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED +#define POLARSSL_ERR_HMAC_DRBG_FILE_IO_ERROR MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR +#define POLARSSL_ERR_HMAC_DRBG_INPUT_TOO_BIG MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG +#define POLARSSL_ERR_HMAC_DRBG_REQUEST_TOO_BIG MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG +#define POLARSSL_ERR_MD2_FILE_IO_ERROR MBEDTLS_ERR_MD2_FILE_IO_ERROR +#define POLARSSL_ERR_MD4_FILE_IO_ERROR MBEDTLS_ERR_MD4_FILE_IO_ERROR +#define POLARSSL_ERR_MD5_FILE_IO_ERROR MBEDTLS_ERR_MD5_FILE_IO_ERROR +#define POLARSSL_ERR_MD_ALLOC_FAILED MBEDTLS_ERR_MD_ALLOC_FAILED +#define POLARSSL_ERR_MD_BAD_INPUT_DATA MBEDTLS_ERR_MD_BAD_INPUT_DATA +#define POLARSSL_ERR_MD_FEATURE_UNAVAILABLE MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_MD_FILE_IO_ERROR MBEDTLS_ERR_MD_FILE_IO_ERROR +#define POLARSSL_ERR_MPI_BAD_INPUT_DATA MBEDTLS_ERR_MPI_BAD_INPUT_DATA +#define POLARSSL_ERR_MPI_BUFFER_TOO_SMALL MBEDTLS_ERR_MPI_BUFFER_TOO_SMALL +#define POLARSSL_ERR_MPI_DIVISION_BY_ZERO MBEDTLS_ERR_MPI_DIVISION_BY_ZERO +#define POLARSSL_ERR_MPI_FILE_IO_ERROR MBEDTLS_ERR_MPI_FILE_IO_ERROR +#define POLARSSL_ERR_MPI_INVALID_CHARACTER MBEDTLS_ERR_MPI_INVALID_CHARACTER +#define POLARSSL_ERR_MPI_MALLOC_FAILED MBEDTLS_ERR_MPI_ALLOC_FAILED +#define POLARSSL_ERR_MPI_NEGATIVE_VALUE MBEDTLS_ERR_MPI_NEGATIVE_VALUE +#define POLARSSL_ERR_MPI_NOT_ACCEPTABLE MBEDTLS_ERR_MPI_NOT_ACCEPTABLE +#define POLARSSL_ERR_NET_ACCEPT_FAILED MBEDTLS_ERR_NET_ACCEPT_FAILED +#define POLARSSL_ERR_NET_BIND_FAILED MBEDTLS_ERR_NET_BIND_FAILED +#define POLARSSL_ERR_NET_CONNECT_FAILED MBEDTLS_ERR_NET_CONNECT_FAILED +#define POLARSSL_ERR_NET_CONN_RESET MBEDTLS_ERR_NET_CONN_RESET +#define POLARSSL_ERR_NET_LISTEN_FAILED MBEDTLS_ERR_NET_LISTEN_FAILED +#define POLARSSL_ERR_NET_RECV_FAILED MBEDTLS_ERR_NET_RECV_FAILED +#define POLARSSL_ERR_NET_SEND_FAILED MBEDTLS_ERR_NET_SEND_FAILED +#define POLARSSL_ERR_NET_SOCKET_FAILED MBEDTLS_ERR_NET_SOCKET_FAILED +#define POLARSSL_ERR_NET_TIMEOUT MBEDTLS_ERR_SSL_TIMEOUT +#define POLARSSL_ERR_NET_UNKNOWN_HOST MBEDTLS_ERR_NET_UNKNOWN_HOST +#define POLARSSL_ERR_NET_WANT_READ MBEDTLS_ERR_SSL_WANT_READ +#define POLARSSL_ERR_NET_WANT_WRITE MBEDTLS_ERR_SSL_WANT_WRITE +#define POLARSSL_ERR_OID_BUF_TOO_SMALL MBEDTLS_ERR_OID_BUF_TOO_SMALL +#define POLARSSL_ERR_OID_NOT_FOUND MBEDTLS_ERR_OID_NOT_FOUND +#define POLARSSL_ERR_PADLOCK_DATA_MISALIGNED MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED +#define POLARSSL_ERR_PBKDF2_BAD_INPUT_DATA MBEDTLS_ERR_PBKDF2_BAD_INPUT_DATA +#define POLARSSL_ERR_PEM_BAD_INPUT_DATA MBEDTLS_ERR_PEM_BAD_INPUT_DATA +#define POLARSSL_ERR_PEM_FEATURE_UNAVAILABLE MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PEM_INVALID_DATA MBEDTLS_ERR_PEM_INVALID_DATA +#define POLARSSL_ERR_PEM_INVALID_ENC_IV MBEDTLS_ERR_PEM_INVALID_ENC_IV +#define POLARSSL_ERR_PEM_MALLOC_FAILED MBEDTLS_ERR_PEM_ALLOC_FAILED +#define POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT +#define POLARSSL_ERR_PEM_PASSWORD_MISMATCH MBEDTLS_ERR_PEM_PASSWORD_MISMATCH +#define POLARSSL_ERR_PEM_PASSWORD_REQUIRED MBEDTLS_ERR_PEM_PASSWORD_REQUIRED +#define POLARSSL_ERR_PEM_UNKNOWN_ENC_ALG MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG +#define POLARSSL_ERR_PKCS12_BAD_INPUT_DATA MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA +#define POLARSSL_ERR_PKCS12_FEATURE_UNAVAILABLE MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PKCS12_PASSWORD_MISMATCH MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH +#define POLARSSL_ERR_PKCS12_PBE_INVALID_FORMAT MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT +#define POLARSSL_ERR_PKCS5_BAD_INPUT_DATA MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA +#define POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PKCS5_INVALID_FORMAT MBEDTLS_ERR_PKCS5_INVALID_FORMAT +#define POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH +#define POLARSSL_ERR_PK_BAD_INPUT_DATA MBEDTLS_ERR_PK_BAD_INPUT_DATA +#define POLARSSL_ERR_PK_FEATURE_UNAVAILABLE MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_PK_FILE_IO_ERROR MBEDTLS_ERR_PK_FILE_IO_ERROR +#define POLARSSL_ERR_PK_INVALID_ALG MBEDTLS_ERR_PK_INVALID_ALG +#define POLARSSL_ERR_PK_INVALID_PUBKEY MBEDTLS_ERR_PK_INVALID_PUBKEY +#define POLARSSL_ERR_PK_KEY_INVALID_FORMAT MBEDTLS_ERR_PK_KEY_INVALID_FORMAT +#define POLARSSL_ERR_PK_KEY_INVALID_VERSION MBEDTLS_ERR_PK_KEY_INVALID_VERSION +#define POLARSSL_ERR_PK_MALLOC_FAILED MBEDTLS_ERR_PK_ALLOC_FAILED +#define POLARSSL_ERR_PK_PASSWORD_MISMATCH MBEDTLS_ERR_PK_PASSWORD_MISMATCH +#define POLARSSL_ERR_PK_PASSWORD_REQUIRED MBEDTLS_ERR_PK_PASSWORD_REQUIRED +#define POLARSSL_ERR_PK_SIG_LEN_MISMATCH MBEDTLS_ERR_PK_SIG_LEN_MISMATCH +#define POLARSSL_ERR_PK_TYPE_MISMATCH MBEDTLS_ERR_PK_TYPE_MISMATCH +#define POLARSSL_ERR_PK_UNKNOWN_NAMED_CURVE MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE +#define POLARSSL_ERR_PK_UNKNOWN_PK_ALG MBEDTLS_ERR_PK_UNKNOWN_PK_ALG +#define POLARSSL_ERR_RIPEMD160_FILE_IO_ERROR MBEDTLS_ERR_RIPEMD160_FILE_IO_ERROR +#define POLARSSL_ERR_RSA_BAD_INPUT_DATA MBEDTLS_ERR_RSA_BAD_INPUT_DATA +#define POLARSSL_ERR_RSA_INVALID_PADDING MBEDTLS_ERR_RSA_INVALID_PADDING +#define POLARSSL_ERR_RSA_KEY_CHECK_FAILED MBEDTLS_ERR_RSA_KEY_CHECK_FAILED +#define POLARSSL_ERR_RSA_KEY_GEN_FAILED MBEDTLS_ERR_RSA_KEY_GEN_FAILED +#define POLARSSL_ERR_RSA_OUTPUT_TOO_LARGE MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE +#define POLARSSL_ERR_RSA_PRIVATE_FAILED MBEDTLS_ERR_RSA_PRIVATE_FAILED +#define POLARSSL_ERR_RSA_PUBLIC_FAILED MBEDTLS_ERR_RSA_PUBLIC_FAILED +#define POLARSSL_ERR_RSA_RNG_FAILED MBEDTLS_ERR_RSA_RNG_FAILED +#define POLARSSL_ERR_RSA_VERIFY_FAILED MBEDTLS_ERR_RSA_VERIFY_FAILED +#define POLARSSL_ERR_SHA1_FILE_IO_ERROR MBEDTLS_ERR_SHA1_FILE_IO_ERROR +#define POLARSSL_ERR_SHA256_FILE_IO_ERROR MBEDTLS_ERR_SHA256_FILE_IO_ERROR +#define POLARSSL_ERR_SHA512_FILE_IO_ERROR MBEDTLS_ERR_SHA512_FILE_IO_ERROR +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST +#define POLARSSL_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY +#define POLARSSL_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_HELLO MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS +#define POLARSSL_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP +#define POLARSSL_ERR_SSL_BAD_HS_FINISHED MBEDTLS_ERR_SSL_BAD_HS_FINISHED +#define POLARSSL_ERR_SSL_BAD_HS_NEW_SESSION_TICKET MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET +#define POLARSSL_ERR_SSL_BAD_HS_PROTOCOL_VERSION MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_HELLO_DONE MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE +#define POLARSSL_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE +#define POLARSSL_ERR_SSL_BAD_INPUT_DATA MBEDTLS_ERR_SSL_BAD_INPUT_DATA +#define POLARSSL_ERR_SSL_BUFFER_TOO_SMALL MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL +#define POLARSSL_ERR_SSL_CA_CHAIN_REQUIRED MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED +#define POLARSSL_ERR_SSL_CERTIFICATE_REQUIRED MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED +#define POLARSSL_ERR_SSL_CERTIFICATE_TOO_LARGE MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE +#define POLARSSL_ERR_SSL_COMPRESSION_FAILED MBEDTLS_ERR_SSL_COMPRESSION_FAILED +#define POLARSSL_ERR_SSL_CONN_EOF MBEDTLS_ERR_SSL_CONN_EOF +#define POLARSSL_ERR_SSL_COUNTER_WRAPPING MBEDTLS_ERR_SSL_COUNTER_WRAPPING +#define POLARSSL_ERR_SSL_FATAL_ALERT_MESSAGE MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE +#define POLARSSL_ERR_SSL_FEATURE_UNAVAILABLE MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_SSL_HELLO_VERIFY_REQUIRED MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED +#define POLARSSL_ERR_SSL_HW_ACCEL_FAILED MBEDTLS_ERR_SSL_HW_ACCEL_FAILED +#define POLARSSL_ERR_SSL_HW_ACCEL_FALLTHROUGH MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH +#define POLARSSL_ERR_SSL_INTERNAL_ERROR MBEDTLS_ERR_SSL_INTERNAL_ERROR +#define POLARSSL_ERR_SSL_INVALID_MAC MBEDTLS_ERR_SSL_INVALID_MAC +#define POLARSSL_ERR_SSL_INVALID_RECORD MBEDTLS_ERR_SSL_INVALID_RECORD +#define POLARSSL_ERR_SSL_MALLOC_FAILED MBEDTLS_ERR_SSL_ALLOC_FAILED +#define POLARSSL_ERR_SSL_NO_CIPHER_CHOSEN MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN +#define POLARSSL_ERR_SSL_NO_CLIENT_CERTIFICATE MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE +#define POLARSSL_ERR_SSL_NO_RNG MBEDTLS_ERR_SSL_NO_RNG +#define POLARSSL_ERR_SSL_NO_USABLE_CIPHERSUITE MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE +#define POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY +#define POLARSSL_ERR_SSL_PEER_VERIFY_FAILED MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED +#define POLARSSL_ERR_SSL_PK_TYPE_MISMATCH MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH +#define POLARSSL_ERR_SSL_PRIVATE_KEY_REQUIRED MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED +#define POLARSSL_ERR_SSL_SESSION_TICKET_EXPIRED MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED +#define POLARSSL_ERR_SSL_UNEXPECTED_MESSAGE MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE +#define POLARSSL_ERR_SSL_UNKNOWN_CIPHER MBEDTLS_ERR_SSL_UNKNOWN_CIPHER +#define POLARSSL_ERR_SSL_UNKNOWN_IDENTITY MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY +#define POLARSSL_ERR_SSL_WAITING_SERVER_HELLO_RENEGO MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO +#define POLARSSL_ERR_THREADING_BAD_INPUT_DATA MBEDTLS_ERR_THREADING_BAD_INPUT_DATA +#define POLARSSL_ERR_THREADING_FEATURE_UNAVAILABLE MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_THREADING_MUTEX_ERROR MBEDTLS_ERR_THREADING_MUTEX_ERROR +#define POLARSSL_ERR_X509_BAD_INPUT_DATA MBEDTLS_ERR_X509_BAD_INPUT_DATA +#define POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT +#define POLARSSL_ERR_X509_CERT_VERIFY_FAILED MBEDTLS_ERR_X509_CERT_VERIFY_FAILED +#define POLARSSL_ERR_X509_FEATURE_UNAVAILABLE MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE +#define POLARSSL_ERR_X509_FILE_IO_ERROR MBEDTLS_ERR_X509_FILE_IO_ERROR +#define POLARSSL_ERR_X509_INVALID_ALG MBEDTLS_ERR_X509_INVALID_ALG +#define POLARSSL_ERR_X509_INVALID_DATE MBEDTLS_ERR_X509_INVALID_DATE +#define POLARSSL_ERR_X509_INVALID_EXTENSIONS MBEDTLS_ERR_X509_INVALID_EXTENSIONS +#define POLARSSL_ERR_X509_INVALID_FORMAT MBEDTLS_ERR_X509_INVALID_FORMAT +#define POLARSSL_ERR_X509_INVALID_NAME MBEDTLS_ERR_X509_INVALID_NAME +#define POLARSSL_ERR_X509_INVALID_SERIAL MBEDTLS_ERR_X509_INVALID_SERIAL +#define POLARSSL_ERR_X509_INVALID_SIGNATURE MBEDTLS_ERR_X509_INVALID_SIGNATURE +#define POLARSSL_ERR_X509_INVALID_VERSION MBEDTLS_ERR_X509_INVALID_VERSION +#define POLARSSL_ERR_X509_MALLOC_FAILED MBEDTLS_ERR_X509_ALLOC_FAILED +#define POLARSSL_ERR_X509_SIG_MISMATCH MBEDTLS_ERR_X509_SIG_MISMATCH +#define POLARSSL_ERR_X509_UNKNOWN_OID MBEDTLS_ERR_X509_UNKNOWN_OID +#define POLARSSL_ERR_X509_UNKNOWN_SIG_ALG MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG +#define POLARSSL_ERR_X509_UNKNOWN_VERSION MBEDTLS_ERR_X509_UNKNOWN_VERSION +#define POLARSSL_ERR_XTEA_INVALID_INPUT_LENGTH MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH +#define POLARSSL_GCM_H MBEDTLS_GCM_H +#define POLARSSL_HAVEGE_H MBEDTLS_HAVEGE_H +#define POLARSSL_HAVE_INT32 MBEDTLS_HAVE_INT32 +#define POLARSSL_HAVE_INT64 MBEDTLS_HAVE_INT64 +#define POLARSSL_HAVE_UDBL MBEDTLS_HAVE_UDBL +#define POLARSSL_HAVE_X86 MBEDTLS_HAVE_X86 +#define POLARSSL_HAVE_X86_64 MBEDTLS_HAVE_X86_64 +#define POLARSSL_HMAC_DRBG_H MBEDTLS_HMAC_DRBG_H +#define POLARSSL_HMAC_DRBG_PR_OFF MBEDTLS_HMAC_DRBG_PR_OFF +#define POLARSSL_HMAC_DRBG_PR_ON MBEDTLS_HMAC_DRBG_PR_ON +#define POLARSSL_KEY_EXCHANGE_DHE_PSK MBEDTLS_KEY_EXCHANGE_DHE_PSK +#define POLARSSL_KEY_EXCHANGE_DHE_RSA MBEDTLS_KEY_EXCHANGE_DHE_RSA +#define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA +#define POLARSSL_KEY_EXCHANGE_ECDHE_PSK MBEDTLS_KEY_EXCHANGE_ECDHE_PSK +#define POLARSSL_KEY_EXCHANGE_ECDHE_RSA MBEDTLS_KEY_EXCHANGE_ECDHE_RSA +#define POLARSSL_KEY_EXCHANGE_ECDH_ECDSA MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA +#define POLARSSL_KEY_EXCHANGE_ECDH_RSA MBEDTLS_KEY_EXCHANGE_ECDH_RSA +#define POLARSSL_KEY_EXCHANGE_NONE MBEDTLS_KEY_EXCHANGE_NONE +#define POLARSSL_KEY_EXCHANGE_PSK MBEDTLS_KEY_EXCHANGE_PSK +#define POLARSSL_KEY_EXCHANGE_RSA MBEDTLS_KEY_EXCHANGE_RSA +#define POLARSSL_KEY_EXCHANGE_RSA_PSK MBEDTLS_KEY_EXCHANGE_RSA_PSK +#define POLARSSL_KEY_EXCHANGE__SOME__ECDHE_ENABLED MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED +#define POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED +#define POLARSSL_KEY_EXCHANGE__WITH_CERT__ENABLED MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED +#define POLARSSL_KEY_LENGTH_DES MBEDTLS_KEY_LENGTH_DES +#define POLARSSL_KEY_LENGTH_DES_EDE MBEDTLS_KEY_LENGTH_DES_EDE +#define POLARSSL_KEY_LENGTH_DES_EDE3 MBEDTLS_KEY_LENGTH_DES_EDE3 +#define POLARSSL_KEY_LENGTH_NONE MBEDTLS_KEY_LENGTH_NONE +#define POLARSSL_MAX_BLOCK_LENGTH MBEDTLS_MAX_BLOCK_LENGTH +#define POLARSSL_MAX_IV_LENGTH MBEDTLS_MAX_IV_LENGTH +#define POLARSSL_MD2_H MBEDTLS_MD2_H +#define POLARSSL_MD4_H MBEDTLS_MD4_H +#define POLARSSL_MD5_H MBEDTLS_MD5_H +#define POLARSSL_MD_H MBEDTLS_MD_H +#define POLARSSL_MD_MAX_SIZE MBEDTLS_MD_MAX_SIZE +#define POLARSSL_MD_MD2 MBEDTLS_MD_MD2 +#define POLARSSL_MD_MD4 MBEDTLS_MD_MD4 +#define POLARSSL_MD_MD5 MBEDTLS_MD_MD5 +#define POLARSSL_MD_NONE MBEDTLS_MD_NONE +#define POLARSSL_MD_RIPEMD160 MBEDTLS_MD_RIPEMD160 +#define POLARSSL_MD_SHA1 MBEDTLS_MD_SHA1 +#define POLARSSL_MD_SHA224 MBEDTLS_MD_SHA224 +#define POLARSSL_MD_SHA256 MBEDTLS_MD_SHA256 +#define POLARSSL_MD_SHA384 MBEDTLS_MD_SHA384 +#define POLARSSL_MD_SHA512 MBEDTLS_MD_SHA512 +#define POLARSSL_MD_WRAP_H MBEDTLS_MD_WRAP_H +#define POLARSSL_MEMORY_BUFFER_ALLOC_H MBEDTLS_MEMORY_BUFFER_ALLOC_H +#define POLARSSL_MEMORY_H MBEDTLS_MEMORY_H +#define POLARSSL_MODE_CBC MBEDTLS_MODE_CBC +#define POLARSSL_MODE_CCM MBEDTLS_MODE_CCM +#define POLARSSL_MODE_CFB MBEDTLS_MODE_CFB +#define POLARSSL_MODE_CTR MBEDTLS_MODE_CTR +#define POLARSSL_MODE_ECB MBEDTLS_MODE_ECB +#define POLARSSL_MODE_GCM MBEDTLS_MODE_GCM +#define POLARSSL_MODE_NONE MBEDTLS_MODE_NONE +#define POLARSSL_MODE_OFB MBEDTLS_MODE_OFB +#define POLARSSL_MODE_STREAM MBEDTLS_MODE_STREAM +#define POLARSSL_MPI_MAX_BITS MBEDTLS_MPI_MAX_BITS +#define POLARSSL_MPI_MAX_BITS_SCALE100 MBEDTLS_MPI_MAX_BITS_SCALE100 +#define POLARSSL_MPI_MAX_LIMBS MBEDTLS_MPI_MAX_LIMBS +#define POLARSSL_MPI_RW_BUFFER_SIZE MBEDTLS_MPI_RW_BUFFER_SIZE +#define POLARSSL_NET_H MBEDTLS_NET_H +#define POLARSSL_NET_LISTEN_BACKLOG MBEDTLS_NET_LISTEN_BACKLOG +#define POLARSSL_OID_H MBEDTLS_OID_H +#define POLARSSL_OPERATION_NONE MBEDTLS_OPERATION_NONE +#define POLARSSL_PADDING_NONE MBEDTLS_PADDING_NONE +#define POLARSSL_PADDING_ONE_AND_ZEROS MBEDTLS_PADDING_ONE_AND_ZEROS +#define POLARSSL_PADDING_PKCS7 MBEDTLS_PADDING_PKCS7 +#define POLARSSL_PADDING_ZEROS MBEDTLS_PADDING_ZEROS +#define POLARSSL_PADDING_ZEROS_AND_LEN MBEDTLS_PADDING_ZEROS_AND_LEN +#define POLARSSL_PADLOCK_H MBEDTLS_PADLOCK_H +#define POLARSSL_PBKDF2_H MBEDTLS_PBKDF2_H +#define POLARSSL_PEM_H MBEDTLS_PEM_H +#define POLARSSL_PKCS11_H MBEDTLS_PKCS11_H +#define POLARSSL_PKCS12_H MBEDTLS_PKCS12_H +#define POLARSSL_PKCS5_H MBEDTLS_PKCS5_H +#define POLARSSL_PK_DEBUG_ECP MBEDTLS_PK_DEBUG_ECP +#define POLARSSL_PK_DEBUG_MAX_ITEMS MBEDTLS_PK_DEBUG_MAX_ITEMS +#define POLARSSL_PK_DEBUG_MPI MBEDTLS_PK_DEBUG_MPI +#define POLARSSL_PK_DEBUG_NONE MBEDTLS_PK_DEBUG_NONE +#define POLARSSL_PK_ECDSA MBEDTLS_PK_ECDSA +#define POLARSSL_PK_ECKEY MBEDTLS_PK_ECKEY +#define POLARSSL_PK_ECKEY_DH MBEDTLS_PK_ECKEY_DH +#define POLARSSL_PK_H MBEDTLS_PK_H +#define POLARSSL_PK_NONE MBEDTLS_PK_NONE +#define POLARSSL_PK_RSA MBEDTLS_PK_RSA +#define POLARSSL_PK_RSASSA_PSS MBEDTLS_PK_RSASSA_PSS +#define POLARSSL_PK_RSA_ALT MBEDTLS_PK_RSA_ALT +#define POLARSSL_PK_WRAP_H MBEDTLS_PK_WRAP_H +#define POLARSSL_PLATFORM_H MBEDTLS_PLATFORM_H +#define POLARSSL_PREMASTER_SIZE MBEDTLS_PREMASTER_SIZE +#define POLARSSL_RIPEMD160_H MBEDTLS_RIPEMD160_H +#define POLARSSL_RSA_H MBEDTLS_RSA_H +#define POLARSSL_SHA1_H MBEDTLS_SHA1_H +#define POLARSSL_SHA256_H MBEDTLS_SHA256_H +#define POLARSSL_SHA512_H MBEDTLS_SHA512_H +#define POLARSSL_SSL_CACHE_H MBEDTLS_SSL_CACHE_H +#define POLARSSL_SSL_CIPHERSUITES_H MBEDTLS_SSL_CIPHERSUITES_H +#define POLARSSL_SSL_COOKIE_H MBEDTLS_SSL_COOKIE_H +#define POLARSSL_SSL_H MBEDTLS_SSL_H +#define POLARSSL_THREADING_H MBEDTLS_THREADING_H +#define POLARSSL_THREADING_IMPL MBEDTLS_THREADING_IMPL +#define POLARSSL_TIMING_H MBEDTLS_TIMING_H +#define POLARSSL_VERSION_H MBEDTLS_VERSION_H +#define POLARSSL_VERSION_MAJOR MBEDTLS_VERSION_MAJOR +#define POLARSSL_VERSION_MINOR MBEDTLS_VERSION_MINOR +#define POLARSSL_VERSION_NUMBER MBEDTLS_VERSION_NUMBER +#define POLARSSL_VERSION_PATCH MBEDTLS_VERSION_PATCH +#define POLARSSL_VERSION_STRING MBEDTLS_VERSION_STRING +#define POLARSSL_VERSION_STRING_FULL MBEDTLS_VERSION_STRING_FULL +#define POLARSSL_X509_CRL_H MBEDTLS_X509_CRL_H +#define POLARSSL_X509_CRT_H MBEDTLS_X509_CRT_H +#define POLARSSL_X509_CSR_H MBEDTLS_X509_CSR_H +#define POLARSSL_X509_H MBEDTLS_X509_H +#define POLARSSL_XTEA_H MBEDTLS_XTEA_H +#define RSA_CRYPT MBEDTLS_RSA_CRYPT +#define RSA_PKCS_V15 MBEDTLS_RSA_PKCS_V15 +#define RSA_PKCS_V21 MBEDTLS_RSA_PKCS_V21 +#define RSA_PRIVATE MBEDTLS_RSA_PRIVATE +#define RSA_PUBLIC MBEDTLS_RSA_PUBLIC +#define RSA_SALT_LEN_ANY MBEDTLS_RSA_SALT_LEN_ANY +#define RSA_SIGN MBEDTLS_RSA_SIGN +#define SSL_ALERT_LEVEL_FATAL MBEDTLS_SSL_ALERT_LEVEL_FATAL +#define SSL_ALERT_LEVEL_WARNING MBEDTLS_SSL_ALERT_LEVEL_WARNING +#define SSL_ALERT_MSG_ACCESS_DENIED MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED +#define SSL_ALERT_MSG_BAD_CERT MBEDTLS_SSL_ALERT_MSG_BAD_CERT +#define SSL_ALERT_MSG_BAD_RECORD_MAC MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC +#define SSL_ALERT_MSG_CERT_EXPIRED MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED +#define SSL_ALERT_MSG_CERT_REVOKED MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED +#define SSL_ALERT_MSG_CERT_UNKNOWN MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN +#define SSL_ALERT_MSG_CLOSE_NOTIFY MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY +#define SSL_ALERT_MSG_DECODE_ERROR MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR +#define SSL_ALERT_MSG_DECOMPRESSION_FAILURE MBEDTLS_SSL_ALERT_MSG_DECOMPRESSION_FAILURE +#define SSL_ALERT_MSG_DECRYPTION_FAILED MBEDTLS_SSL_ALERT_MSG_DECRYPTION_FAILED +#define SSL_ALERT_MSG_DECRYPT_ERROR MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR +#define SSL_ALERT_MSG_EXPORT_RESTRICTION MBEDTLS_SSL_ALERT_MSG_EXPORT_RESTRICTION +#define SSL_ALERT_MSG_HANDSHAKE_FAILURE MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE +#define SSL_ALERT_MSG_ILLEGAL_PARAMETER MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER +#define SSL_ALERT_MSG_INAPROPRIATE_FALLBACK MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK +#define SSL_ALERT_MSG_INSUFFICIENT_SECURITY MBEDTLS_SSL_ALERT_MSG_INSUFFICIENT_SECURITY +#define SSL_ALERT_MSG_INTERNAL_ERROR MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR +#define SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL +#define SSL_ALERT_MSG_NO_CERT MBEDTLS_SSL_ALERT_MSG_NO_CERT +#define SSL_ALERT_MSG_NO_RENEGOTIATION MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION +#define SSL_ALERT_MSG_PROTOCOL_VERSION MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION +#define SSL_ALERT_MSG_RECORD_OVERFLOW MBEDTLS_SSL_ALERT_MSG_RECORD_OVERFLOW +#define SSL_ALERT_MSG_UNEXPECTED_MESSAGE MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE +#define SSL_ALERT_MSG_UNKNOWN_CA MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA +#define SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY +#define SSL_ALERT_MSG_UNRECOGNIZED_NAME MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME +#define SSL_ALERT_MSG_UNSUPPORTED_CERT MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT +#define SSL_ALERT_MSG_UNSUPPORTED_EXT MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT +#define SSL_ALERT_MSG_USER_CANCELED MBEDTLS_SSL_ALERT_MSG_USER_CANCELED +#define SSL_ANTI_REPLAY_DISABLED MBEDTLS_SSL_ANTI_REPLAY_DISABLED +#define SSL_ANTI_REPLAY_ENABLED MBEDTLS_SSL_ANTI_REPLAY_ENABLED +#define SSL_ARC4_DISABLED MBEDTLS_SSL_ARC4_DISABLED +#define SSL_ARC4_ENABLED MBEDTLS_SSL_ARC4_ENABLED +#define SSL_BUFFER_LEN MBEDTLS_SSL_BUFFER_LEN +#define SSL_CACHE_DEFAULT_MAX_ENTRIES MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES +#define SSL_CACHE_DEFAULT_TIMEOUT MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT +#define SSL_CBC_RECORD_SPLITTING_DISABLED MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED +#define SSL_CBC_RECORD_SPLITTING_ENABLED MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED +#define SSL_CERTIFICATE_REQUEST MBEDTLS_SSL_CERTIFICATE_REQUEST +#define SSL_CERTIFICATE_VERIFY MBEDTLS_SSL_CERTIFICATE_VERIFY +#define SSL_CERT_TYPE_ECDSA_SIGN MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN +#define SSL_CERT_TYPE_RSA_SIGN MBEDTLS_SSL_CERT_TYPE_RSA_SIGN +#define SSL_CHANNEL_INBOUND MBEDTLS_SSL_CHANNEL_INBOUND +#define SSL_CHANNEL_OUTBOUND MBEDTLS_SSL_CHANNEL_OUTBOUND +#define SSL_CIPHERSUITES MBEDTLS_SSL_CIPHERSUITES +#define SSL_CLIENT_CERTIFICATE MBEDTLS_SSL_CLIENT_CERTIFICATE +#define SSL_CLIENT_CHANGE_CIPHER_SPEC MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC +#define SSL_CLIENT_FINISHED MBEDTLS_SSL_CLIENT_FINISHED +#define SSL_CLIENT_HELLO MBEDTLS_SSL_CLIENT_HELLO +#define SSL_CLIENT_KEY_EXCHANGE MBEDTLS_SSL_CLIENT_KEY_EXCHANGE +#define SSL_COMPRESSION_ADD MBEDTLS_SSL_COMPRESSION_ADD +#define SSL_COMPRESS_DEFLATE MBEDTLS_SSL_COMPRESS_DEFLATE +#define SSL_COMPRESS_NULL MBEDTLS_SSL_COMPRESS_NULL +#define SSL_DEBUG_BUF MBEDTLS_SSL_DEBUG_BUF +#define SSL_DEBUG_CRT MBEDTLS_SSL_DEBUG_CRT +#define SSL_DEBUG_ECP MBEDTLS_SSL_DEBUG_ECP +#define SSL_DEBUG_MPI MBEDTLS_SSL_DEBUG_MPI +#define SSL_DEBUG_MSG MBEDTLS_SSL_DEBUG_MSG +#define SSL_DEBUG_RET MBEDTLS_SSL_DEBUG_RET +#define SSL_DEFAULT_TICKET_LIFETIME MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME +#define SSL_DTLS_TIMEOUT_DFL_MAX MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX +#define SSL_DTLS_TIMEOUT_DFL_MIN MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN +#define SSL_EMPTY_RENEGOTIATION_INFO MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO +#define SSL_ETM_DISABLED MBEDTLS_SSL_ETM_DISABLED +#define SSL_ETM_ENABLED MBEDTLS_SSL_ETM_ENABLED +#define SSL_EXTENDED_MS_DISABLED MBEDTLS_SSL_EXTENDED_MS_DISABLED +#define SSL_EXTENDED_MS_ENABLED MBEDTLS_SSL_EXTENDED_MS_ENABLED +#define SSL_FALLBACK_SCSV MBEDTLS_SSL_FALLBACK_SCSV +#define SSL_FLUSH_BUFFERS MBEDTLS_SSL_FLUSH_BUFFERS +#define SSL_HANDSHAKE_OVER MBEDTLS_SSL_HANDSHAKE_OVER +#define SSL_HANDSHAKE_WRAPUP MBEDTLS_SSL_HANDSHAKE_WRAPUP +#define SSL_HASH_MD5 MBEDTLS_SSL_HASH_MD5 +#define SSL_HASH_NONE MBEDTLS_SSL_HASH_NONE +#define SSL_HASH_SHA1 MBEDTLS_SSL_HASH_SHA1 +#define SSL_HASH_SHA224 MBEDTLS_SSL_HASH_SHA224 +#define SSL_HASH_SHA256 MBEDTLS_SSL_HASH_SHA256 +#define SSL_HASH_SHA384 MBEDTLS_SSL_HASH_SHA384 +#define SSL_HASH_SHA512 MBEDTLS_SSL_HASH_SHA512 +#define SSL_HELLO_REQUEST MBEDTLS_SSL_HELLO_REQUEST +#define SSL_HS_CERTIFICATE MBEDTLS_SSL_HS_CERTIFICATE +#define SSL_HS_CERTIFICATE_REQUEST MBEDTLS_SSL_HS_CERTIFICATE_REQUEST +#define SSL_HS_CERTIFICATE_VERIFY MBEDTLS_SSL_HS_CERTIFICATE_VERIFY +#define SSL_HS_CLIENT_HELLO MBEDTLS_SSL_HS_CLIENT_HELLO +#define SSL_HS_CLIENT_KEY_EXCHANGE MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE +#define SSL_HS_FINISHED MBEDTLS_SSL_HS_FINISHED +#define SSL_HS_HELLO_REQUEST MBEDTLS_SSL_HS_HELLO_REQUEST +#define SSL_HS_HELLO_VERIFY_REQUEST MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST +#define SSL_HS_NEW_SESSION_TICKET MBEDTLS_SSL_HS_NEW_SESSION_TICKET +#define SSL_HS_SERVER_HELLO MBEDTLS_SSL_HS_SERVER_HELLO +#define SSL_HS_SERVER_HELLO_DONE MBEDTLS_SSL_HS_SERVER_HELLO_DONE +#define SSL_HS_SERVER_KEY_EXCHANGE MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE +#define SSL_INITIAL_HANDSHAKE MBEDTLS_SSL_INITIAL_HANDSHAKE +#define SSL_IS_CLIENT MBEDTLS_SSL_IS_CLIENT +#define SSL_IS_FALLBACK MBEDTLS_SSL_IS_FALLBACK +#define SSL_IS_NOT_FALLBACK MBEDTLS_SSL_IS_NOT_FALLBACK +#define SSL_IS_SERVER MBEDTLS_SSL_IS_SERVER +#define SSL_LEGACY_ALLOW_RENEGOTIATION MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION +#define SSL_LEGACY_BREAK_HANDSHAKE MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE +#define SSL_LEGACY_NO_RENEGOTIATION MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION +#define SSL_LEGACY_RENEGOTIATION MBEDTLS_SSL_LEGACY_RENEGOTIATION +#define SSL_MAC_ADD MBEDTLS_SSL_MAC_ADD +#define SSL_MAJOR_VERSION_3 MBEDTLS_SSL_MAJOR_VERSION_3 +#define SSL_MAX_CONTENT_LEN MBEDTLS_SSL_MAX_CONTENT_LEN +#define SSL_MAX_FRAG_LEN_1024 MBEDTLS_SSL_MAX_FRAG_LEN_1024 +#define SSL_MAX_FRAG_LEN_2048 MBEDTLS_SSL_MAX_FRAG_LEN_2048 +#define SSL_MAX_FRAG_LEN_4096 MBEDTLS_SSL_MAX_FRAG_LEN_4096 +#define SSL_MAX_FRAG_LEN_512 MBEDTLS_SSL_MAX_FRAG_LEN_512 +#define SSL_MAX_FRAG_LEN_INVALID MBEDTLS_SSL_MAX_FRAG_LEN_INVALID +#define SSL_MAX_FRAG_LEN_NONE MBEDTLS_SSL_MAX_FRAG_LEN_NONE +#define SSL_MAX_MAJOR_VERSION MBEDTLS_SSL_MAX_MAJOR_VERSION +#define SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MAX_MINOR_VERSION +#define SSL_MINOR_VERSION_0 MBEDTLS_SSL_MINOR_VERSION_0 +#define SSL_MINOR_VERSION_1 MBEDTLS_SSL_MINOR_VERSION_1 +#define SSL_MINOR_VERSION_2 MBEDTLS_SSL_MINOR_VERSION_2 +#define SSL_MINOR_VERSION_3 MBEDTLS_SSL_MINOR_VERSION_3 +#define SSL_MIN_MAJOR_VERSION MBEDTLS_SSL_MIN_MAJOR_VERSION +#define SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MIN_MINOR_VERSION +#define SSL_MSG_ALERT MBEDTLS_SSL_MSG_ALERT +#define SSL_MSG_APPLICATION_DATA MBEDTLS_SSL_MSG_APPLICATION_DATA +#define SSL_MSG_CHANGE_CIPHER_SPEC MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC +#define SSL_MSG_HANDSHAKE MBEDTLS_SSL_MSG_HANDSHAKE +#define SSL_PADDING_ADD MBEDTLS_SSL_PADDING_ADD +#define SSL_RENEGOTIATION MBEDTLS_SSL_RENEGOTIATION +#define SSL_RENEGOTIATION_DISABLED MBEDTLS_SSL_RENEGOTIATION_DISABLED +#define SSL_RENEGOTIATION_DONE MBEDTLS_SSL_RENEGOTIATION_DONE +#define SSL_RENEGOTIATION_ENABLED MBEDTLS_SSL_RENEGOTIATION_ENABLED +#define SSL_RENEGOTIATION_NOT_ENFORCED MBEDTLS_SSL_RENEGOTIATION_NOT_ENFORCED +#define SSL_RENEGOTIATION_PENDING MBEDTLS_SSL_RENEGOTIATION_PENDING +#define SSL_RENEGO_MAX_RECORDS_DEFAULT MBEDTLS_SSL_RENEGO_MAX_RECORDS_DEFAULT +#define SSL_RETRANS_FINISHED MBEDTLS_SSL_RETRANS_FINISHED +#define SSL_RETRANS_PREPARING MBEDTLS_SSL_RETRANS_PREPARING +#define SSL_RETRANS_SENDING MBEDTLS_SSL_RETRANS_SENDING +#define SSL_RETRANS_WAITING MBEDTLS_SSL_RETRANS_WAITING +#define SSL_SECURE_RENEGOTIATION MBEDTLS_SSL_SECURE_RENEGOTIATION +#define SSL_SERVER_CERTIFICATE MBEDTLS_SSL_SERVER_CERTIFICATE +#define SSL_SERVER_CHANGE_CIPHER_SPEC MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC +#define SSL_SERVER_FINISHED MBEDTLS_SSL_SERVER_FINISHED +#define SSL_SERVER_HELLO MBEDTLS_SSL_SERVER_HELLO +#define SSL_SERVER_HELLO_DONE MBEDTLS_SSL_SERVER_HELLO_DONE +#define SSL_SERVER_HELLO_VERIFY_REQUEST_SENT MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT +#define SSL_SERVER_KEY_EXCHANGE MBEDTLS_SSL_SERVER_KEY_EXCHANGE +#define SSL_SERVER_NEW_SESSION_TICKET MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET +#define SSL_SESSION_TICKETS_DISABLED MBEDTLS_SSL_SESSION_TICKETS_DISABLED +#define SSL_SESSION_TICKETS_ENABLED MBEDTLS_SSL_SESSION_TICKETS_ENABLED +#define SSL_SIG_ANON MBEDTLS_SSL_SIG_ANON +#define SSL_SIG_ECDSA MBEDTLS_SSL_SIG_ECDSA +#define SSL_SIG_RSA MBEDTLS_SSL_SIG_RSA +#define SSL_TRANSPORT_DATAGRAM MBEDTLS_SSL_TRANSPORT_DATAGRAM +#define SSL_TRANSPORT_STREAM MBEDTLS_SSL_TRANSPORT_STREAM +#define SSL_TRUNCATED_HMAC_LEN MBEDTLS_SSL_TRUNCATED_HMAC_LEN +#define SSL_TRUNC_HMAC_DISABLED MBEDTLS_SSL_TRUNC_HMAC_DISABLED +#define SSL_TRUNC_HMAC_ENABLED MBEDTLS_SSL_TRUNC_HMAC_ENABLED +#define SSL_VERIFY_DATA_MAX_LEN MBEDTLS_SSL_VERIFY_DATA_MAX_LEN +#define SSL_VERIFY_NONE MBEDTLS_SSL_VERIFY_NONE +#define SSL_VERIFY_OPTIONAL MBEDTLS_SSL_VERIFY_OPTIONAL +#define SSL_VERIFY_REQUIRED MBEDTLS_SSL_VERIFY_REQUIRED +#define TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_DHE_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA +#define TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_DHE_PSK_WITH_AES_128_CCM MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM +#define TLS_DHE_PSK_WITH_AES_128_CCM_8 MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8 +#define TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 +#define TLS_DHE_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA +#define TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_DHE_PSK_WITH_AES_256_CCM MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM +#define TLS_DHE_PSK_WITH_AES_256_CCM_8 MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8 +#define TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 +#define TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_DHE_PSK_WITH_NULL_SHA MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA +#define TLS_DHE_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 +#define TLS_DHE_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 +#define TLS_DHE_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA +#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA +#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_DHE_RSA_WITH_AES_128_CCM MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM +#define TLS_DHE_RSA_WITH_AES_128_CCM_8 MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8 +#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA +#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 +#define TLS_DHE_RSA_WITH_AES_256_CCM MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM +#define TLS_DHE_RSA_WITH_AES_256_CCM_8 MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8 +#define TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA +#define TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA +#define TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 +#define TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_DHE_RSA_WITH_DES_CBC_SHA MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDHE_ECDSA_WITH_AES_128_CCM MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM +#define TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 +#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA +#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDHE_ECDSA_WITH_AES_256_CCM MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM +#define TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 +#define TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDHE_ECDSA_WITH_NULL_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA +#define TLS_ECDHE_ECDSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA +#define TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA +#define TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA +#define TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDHE_PSK_WITH_NULL_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA +#define TLS_ECDHE_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 +#define TLS_ECDHE_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 +#define TLS_ECDHE_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA +#define TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA +#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA +#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDHE_RSA_WITH_NULL_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA +#define TLS_ECDHE_RSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA +#define TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA +#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA +#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDH_ECDSA_WITH_NULL_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA +#define TLS_ECDH_ECDSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA +#define TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA +#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA +#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 +#define TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_ECDH_RSA_WITH_NULL_SHA MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA +#define TLS_ECDH_RSA_WITH_RC4_128_SHA MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA +#define TLS_EXT_ALPN MBEDTLS_TLS_EXT_ALPN +#define TLS_EXT_ENCRYPT_THEN_MAC MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC +#define TLS_EXT_EXTENDED_MASTER_SECRET MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET +#define TLS_EXT_MAX_FRAGMENT_LENGTH MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH +#define TLS_EXT_RENEGOTIATION_INFO MBEDTLS_TLS_EXT_RENEGOTIATION_INFO +#define TLS_EXT_SERVERNAME MBEDTLS_TLS_EXT_SERVERNAME +#define TLS_EXT_SERVERNAME_HOSTNAME MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME +#define TLS_EXT_SESSION_TICKET MBEDTLS_TLS_EXT_SESSION_TICKET +#define TLS_EXT_SIG_ALG MBEDTLS_TLS_EXT_SIG_ALG +#define TLS_EXT_SUPPORTED_ELLIPTIC_CURVES MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES +#define TLS_EXT_SUPPORTED_POINT_FORMATS MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS +#define TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT +#define TLS_EXT_TRUNCATED_HMAC MBEDTLS_TLS_EXT_TRUNCATED_HMAC +#define TLS_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA +#define TLS_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_PSK_WITH_AES_128_CCM MBEDTLS_TLS_PSK_WITH_AES_128_CCM +#define TLS_PSK_WITH_AES_128_CCM_8 MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8 +#define TLS_PSK_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 +#define TLS_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA +#define TLS_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_PSK_WITH_AES_256_CCM MBEDTLS_TLS_PSK_WITH_AES_256_CCM +#define TLS_PSK_WITH_AES_256_CCM_8 MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8 +#define TLS_PSK_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 +#define TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_PSK_WITH_NULL_SHA MBEDTLS_TLS_PSK_WITH_NULL_SHA +#define TLS_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_PSK_WITH_NULL_SHA256 +#define TLS_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_PSK_WITH_NULL_SHA384 +#define TLS_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_PSK_WITH_RC4_128_SHA +#define TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA +#define TLS_RSA_PSK_WITH_AES_128_CBC_SHA MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA +#define TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 +#define TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 +#define TLS_RSA_PSK_WITH_AES_256_CBC_SHA MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA +#define TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 +#define TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 +#define TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 +#define TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_RSA_PSK_WITH_NULL_SHA MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA +#define TLS_RSA_PSK_WITH_NULL_SHA256 MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 +#define TLS_RSA_PSK_WITH_NULL_SHA384 MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 +#define TLS_RSA_PSK_WITH_RC4_128_SHA MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA +#define TLS_RSA_WITH_3DES_EDE_CBC_SHA MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA +#define TLS_RSA_WITH_AES_128_CBC_SHA MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA +#define TLS_RSA_WITH_AES_128_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 +#define TLS_RSA_WITH_AES_128_CCM MBEDTLS_TLS_RSA_WITH_AES_128_CCM +#define TLS_RSA_WITH_AES_128_CCM_8 MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8 +#define TLS_RSA_WITH_AES_128_GCM_SHA256 MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 +#define TLS_RSA_WITH_AES_256_CBC_SHA MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA +#define TLS_RSA_WITH_AES_256_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 +#define TLS_RSA_WITH_AES_256_CCM MBEDTLS_TLS_RSA_WITH_AES_256_CCM +#define TLS_RSA_WITH_AES_256_CCM_8 MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8 +#define TLS_RSA_WITH_AES_256_GCM_SHA384 MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 +#define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA +#define TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 +#define TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 +#define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA +#define TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 +#define TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 +#define TLS_RSA_WITH_DES_CBC_SHA MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA +#define TLS_RSA_WITH_NULL_MD5 MBEDTLS_TLS_RSA_WITH_NULL_MD5 +#define TLS_RSA_WITH_NULL_SHA MBEDTLS_TLS_RSA_WITH_NULL_SHA +#define TLS_RSA_WITH_NULL_SHA256 MBEDTLS_TLS_RSA_WITH_NULL_SHA256 +#define TLS_RSA_WITH_RC4_128_MD5 MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 +#define TLS_RSA_WITH_RC4_128_SHA MBEDTLS_TLS_RSA_WITH_RC4_128_SHA +#define UL64 MBEDTLS_UL64 +#define X509_CRT_VERSION_1 MBEDTLS_X509_CRT_VERSION_1 +#define X509_CRT_VERSION_2 MBEDTLS_X509_CRT_VERSION_2 +#define X509_CRT_VERSION_3 MBEDTLS_X509_CRT_VERSION_3 +#define X509_FORMAT_DER MBEDTLS_X509_FORMAT_DER +#define X509_FORMAT_PEM MBEDTLS_X509_FORMAT_PEM +#define X509_MAX_DN_NAME_SIZE MBEDTLS_X509_MAX_DN_NAME_SIZE +#define X509_RFC5280_MAX_SERIAL_LEN MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN +#define X509_RFC5280_UTC_TIME_LEN MBEDTLS_X509_RFC5280_UTC_TIME_LEN +#define XTEA_DECRYPT MBEDTLS_XTEA_DECRYPT +#define XTEA_ENCRYPT MBEDTLS_XTEA_ENCRYPT +#define _asn1_bitstring mbedtls_asn1_bitstring +#define _asn1_buf mbedtls_asn1_buf +#define _asn1_named_data mbedtls_asn1_named_data +#define _asn1_sequence mbedtls_asn1_sequence +#define _ssl_cache_context mbedtls_ssl_cache_context +#define _ssl_cache_entry mbedtls_ssl_cache_entry +#define _ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t +#define _ssl_context mbedtls_ssl_context +#define _ssl_flight_item mbedtls_ssl_flight_item +#define _ssl_handshake_params mbedtls_ssl_handshake_params +#define _ssl_key_cert mbedtls_ssl_key_cert +#define _ssl_premaster_secret mbedtls_ssl_premaster_secret +#define _ssl_session mbedtls_ssl_session +#define _ssl_ticket_keys mbedtls_ssl_ticket_keys +#define _ssl_transform mbedtls_ssl_transform +#define _x509_crl mbedtls_x509_crl +#define _x509_crl_entry mbedtls_x509_crl_entry +#define _x509_crt mbedtls_x509_crt +#define _x509_csr mbedtls_x509_csr +#define _x509_time mbedtls_x509_time +#define _x509write_cert mbedtls_x509write_cert +#define _x509write_csr mbedtls_x509write_csr +#define aes_context mbedtls_aes_context +#define aes_crypt_cbc mbedtls_aes_crypt_cbc +#define aes_crypt_cfb128 mbedtls_aes_crypt_cfb128 +#define aes_crypt_cfb8 mbedtls_aes_crypt_cfb8 +#define aes_crypt_ctr mbedtls_aes_crypt_ctr +#define aes_crypt_ecb mbedtls_aes_crypt_ecb +#define aes_free mbedtls_aes_free +#define aes_init mbedtls_aes_init +#define aes_self_test mbedtls_aes_self_test +#define aes_setkey_dec mbedtls_aes_setkey_dec +#define aes_setkey_enc mbedtls_aes_setkey_enc +#define aesni_crypt_ecb mbedtls_aesni_crypt_ecb +#define aesni_gcm_mult mbedtls_aesni_gcm_mult +#define aesni_inverse_key mbedtls_aesni_inverse_key +#define aesni_setkey_enc mbedtls_aesni_setkey_enc +#define aesni_supports mbedtls_aesni_has_support +#define alarmed mbedtls_timing_alarmed +#define arc4_context mbedtls_arc4_context +#define arc4_crypt mbedtls_arc4_crypt +#define arc4_free mbedtls_arc4_free +#define arc4_init mbedtls_arc4_init +#define arc4_self_test mbedtls_arc4_self_test +#define arc4_setup mbedtls_arc4_setup +#define asn1_bitstring mbedtls_asn1_bitstring +#define asn1_buf mbedtls_asn1_buf +#define asn1_find_named_data mbedtls_asn1_find_named_data +#define asn1_free_named_data mbedtls_asn1_free_named_data +#define asn1_free_named_data_list mbedtls_asn1_free_named_data_list +#define asn1_get_alg mbedtls_asn1_get_alg +#define asn1_get_alg_null mbedtls_asn1_get_alg_null +#define asn1_get_bitstring mbedtls_asn1_get_bitstring +#define asn1_get_bitstring_null mbedtls_asn1_get_bitstring_null +#define asn1_get_bool mbedtls_asn1_get_bool +#define asn1_get_int mbedtls_asn1_get_int +#define asn1_get_len mbedtls_asn1_get_len +#define asn1_get_mpi mbedtls_asn1_get_mpi +#define asn1_get_sequence_of mbedtls_asn1_get_sequence_of +#define asn1_get_tag mbedtls_asn1_get_tag +#define asn1_named_data mbedtls_asn1_named_data +#define asn1_sequence mbedtls_asn1_sequence +#define asn1_store_named_data mbedtls_asn1_store_named_data +#define asn1_write_algorithm_identifier mbedtls_asn1_write_algorithm_identifier +#define asn1_write_bitstring mbedtls_asn1_write_bitstring +#define asn1_write_bool mbedtls_asn1_write_bool +#define asn1_write_ia5_string mbedtls_asn1_write_ia5_string +#define asn1_write_int mbedtls_asn1_write_int +#define asn1_write_len mbedtls_asn1_write_len +#define asn1_write_mpi mbedtls_asn1_write_mpi +#define asn1_write_null mbedtls_asn1_write_null +#define asn1_write_octet_string mbedtls_asn1_write_octet_string +#define asn1_write_oid mbedtls_asn1_write_oid +#define asn1_write_printable_string mbedtls_asn1_write_printable_string +#define asn1_write_raw_buffer mbedtls_asn1_write_raw_buffer +#define asn1_write_tag mbedtls_asn1_write_tag +#define base64_decode mbedtls_base64_decode +#define base64_encode mbedtls_base64_encode +#define base64_self_test mbedtls_base64_self_test +#define blowfish_context mbedtls_blowfish_context +#define blowfish_crypt_cbc mbedtls_blowfish_crypt_cbc +#define blowfish_crypt_cfb64 mbedtls_blowfish_crypt_cfb64 +#define blowfish_crypt_ctr mbedtls_blowfish_crypt_ctr +#define blowfish_crypt_ecb mbedtls_blowfish_crypt_ecb +#define blowfish_free mbedtls_blowfish_free +#define blowfish_init mbedtls_blowfish_init +#define blowfish_setkey mbedtls_blowfish_setkey +#define camellia_context mbedtls_camellia_context +#define camellia_crypt_cbc mbedtls_camellia_crypt_cbc +#define camellia_crypt_cfb128 mbedtls_camellia_crypt_cfb128 +#define camellia_crypt_ctr mbedtls_camellia_crypt_ctr +#define camellia_crypt_ecb mbedtls_camellia_crypt_ecb +#define camellia_free mbedtls_camellia_free +#define camellia_init mbedtls_camellia_init +#define camellia_self_test mbedtls_camellia_self_test +#define camellia_setkey_dec mbedtls_camellia_setkey_dec +#define camellia_setkey_enc mbedtls_camellia_setkey_enc +#define ccm_auth_decrypt mbedtls_ccm_auth_decrypt +#define ccm_context mbedtls_ccm_context +#define ccm_encrypt_and_tag mbedtls_ccm_encrypt_and_tag +#define ccm_free mbedtls_ccm_free +#define ccm_init mbedtls_ccm_init +#define ccm_self_test mbedtls_ccm_self_test +#define cipher_auth_decrypt mbedtls_cipher_auth_decrypt +#define cipher_auth_encrypt mbedtls_cipher_auth_encrypt +#define cipher_base_t mbedtls_cipher_base_t +#define cipher_check_tag mbedtls_cipher_check_tag +#define cipher_context_t mbedtls_cipher_context_t +#define cipher_crypt mbedtls_cipher_crypt +#define cipher_definition_t mbedtls_cipher_definition_t +#define cipher_definitions mbedtls_cipher_definitions +#define cipher_finish mbedtls_cipher_finish +#define cipher_free mbedtls_cipher_free +#define cipher_free_ctx mbedtls_cipher_free_ctx +#define cipher_get_block_size mbedtls_cipher_get_block_size +#define cipher_get_cipher_mode mbedtls_cipher_get_cipher_mode +#define cipher_get_iv_size mbedtls_cipher_get_iv_size +#define cipher_get_key_size mbedtls_cipher_get_key_bitlen +#define cipher_get_name mbedtls_cipher_get_name +#define cipher_get_operation mbedtls_cipher_get_operation +#define cipher_get_type mbedtls_cipher_get_type +#define cipher_id_t mbedtls_cipher_id_t +#define cipher_info_from_string mbedtls_cipher_info_from_string +#define cipher_info_from_type mbedtls_cipher_info_from_type +#define cipher_info_from_values mbedtls_cipher_info_from_values +#define cipher_info_t mbedtls_cipher_info_t +#define cipher_init mbedtls_cipher_init +#define cipher_init_ctx mbedtls_cipher_setup +#define cipher_list mbedtls_cipher_list +#define cipher_mode_t mbedtls_cipher_mode_t +#define cipher_padding_t mbedtls_cipher_padding_t +#define cipher_reset mbedtls_cipher_reset +#define cipher_self_test mbedtls_cipher_self_test +#define cipher_set_iv mbedtls_cipher_set_iv +#define cipher_set_padding_mode mbedtls_cipher_set_padding_mode +#define cipher_setkey mbedtls_cipher_setkey +#define cipher_type_t mbedtls_cipher_type_t +#define cipher_update mbedtls_cipher_update +#define cipher_update_ad mbedtls_cipher_update_ad +#define cipher_write_tag mbedtls_cipher_write_tag +#define ctr_drbg_context mbedtls_ctr_drbg_context +#define ctr_drbg_free mbedtls_ctr_drbg_free +#define ctr_drbg_init mbedtls_ctr_drbg_init +#define ctr_drbg_init_entropy_len mbedtls_ctr_drbg_init_entropy_len +#define ctr_drbg_random mbedtls_ctr_drbg_random +#define ctr_drbg_random_with_add mbedtls_ctr_drbg_random_with_add +#define ctr_drbg_reseed mbedtls_ctr_drbg_reseed +#define ctr_drbg_self_test mbedtls_ctr_drbg_self_test +#define ctr_drbg_set_entropy_len mbedtls_ctr_drbg_set_entropy_len +#define ctr_drbg_set_prediction_resistance mbedtls_ctr_drbg_set_prediction_resistance +#define ctr_drbg_set_reseed_interval mbedtls_ctr_drbg_set_reseed_interval +#define ctr_drbg_update mbedtls_ctr_drbg_update +#define ctr_drbg_update_seed_file mbedtls_ctr_drbg_update_seed_file +#define ctr_drbg_write_seed_file mbedtls_ctr_drbg_write_seed_file +#define debug_fmt mbedtls_debug_fmt +#define debug_print_buf mbedtls_debug_print_buf +#define debug_print_crt mbedtls_debug_print_crt +#define debug_print_ecp mbedtls_debug_print_ecp +#define debug_print_mpi mbedtls_debug_print_mpi +#define debug_print_msg mbedtls_debug_print_msg +#define debug_print_ret mbedtls_debug_print_ret +#define debug_set_log_mode mbedtls_debug_set_log_mode +#define debug_set_threshold mbedtls_debug_set_threshold +#define des3_context mbedtls_des3_context +#define des3_crypt_cbc mbedtls_des3_crypt_cbc +#define des3_crypt_ecb mbedtls_des3_crypt_ecb +#define des3_free mbedtls_des3_free +#define des3_init mbedtls_des3_init +#define des3_set2key_dec mbedtls_des3_set2key_dec +#define des3_set2key_enc mbedtls_des3_set2key_enc +#define des3_set3key_dec mbedtls_des3_set3key_dec +#define des3_set3key_enc mbedtls_des3_set3key_enc +#define des_context mbedtls_des_context +#define des_crypt_cbc mbedtls_des_crypt_cbc +#define des_crypt_ecb mbedtls_des_crypt_ecb +#define des_free mbedtls_des_free +#define des_init mbedtls_des_init +#define des_key_check_key_parity mbedtls_des_key_check_key_parity +#define des_key_check_weak mbedtls_des_key_check_weak +#define des_key_set_parity mbedtls_des_key_set_parity +#define des_self_test mbedtls_des_self_test +#define des_setkey_dec mbedtls_des_setkey_dec +#define des_setkey_enc mbedtls_des_setkey_enc +#define dhm_calc_secret mbedtls_dhm_calc_secret +#define dhm_context mbedtls_dhm_context +#define dhm_free mbedtls_dhm_free +#define dhm_init mbedtls_dhm_init +#define dhm_make_params mbedtls_dhm_make_params +#define dhm_make_public mbedtls_dhm_make_public +#define dhm_parse_dhm mbedtls_dhm_parse_dhm +#define dhm_parse_dhmfile mbedtls_dhm_parse_dhmfile +#define dhm_read_params mbedtls_dhm_read_params +#define dhm_read_public mbedtls_dhm_read_public +#define dhm_self_test mbedtls_dhm_self_test +#define ecdh_calc_secret mbedtls_ecdh_calc_secret +#define ecdh_compute_shared mbedtls_ecdh_compute_shared +#define ecdh_context mbedtls_ecdh_context +#define ecdh_free mbedtls_ecdh_free +#define ecdh_gen_public mbedtls_ecdh_gen_public +#define ecdh_get_params mbedtls_ecdh_get_params +#define ecdh_init mbedtls_ecdh_init +#define ecdh_make_params mbedtls_ecdh_make_params +#define ecdh_make_public mbedtls_ecdh_make_public +#define ecdh_read_params mbedtls_ecdh_read_params +#define ecdh_read_public mbedtls_ecdh_read_public +#define ecdh_self_test mbedtls_ecdh_self_test +#define ecdh_side mbedtls_ecdh_side +#define ecdsa_context mbedtls_ecdsa_context +#define ecdsa_free mbedtls_ecdsa_free +#define ecdsa_from_keypair mbedtls_ecdsa_from_keypair +#define ecdsa_genkey mbedtls_ecdsa_genkey +#define ecdsa_info mbedtls_ecdsa_info +#define ecdsa_init mbedtls_ecdsa_init +#define ecdsa_read_signature mbedtls_ecdsa_read_signature +#define ecdsa_self_test mbedtls_ecdsa_self_test +#define ecdsa_sign mbedtls_ecdsa_sign +#define ecdsa_sign_det mbedtls_ecdsa_sign_det +#define ecdsa_verify mbedtls_ecdsa_verify +#define ecdsa_write_signature mbedtls_ecdsa_write_signature +#define ecdsa_write_signature_det mbedtls_ecdsa_write_signature_det +#define eckey_info mbedtls_eckey_info +#define eckeydh_info mbedtls_eckeydh_info +#define ecp_add mbedtls_ecp_add +#define ecp_check_privkey mbedtls_ecp_check_privkey +#define ecp_check_pub_priv mbedtls_ecp_check_pub_priv +#define ecp_check_pubkey mbedtls_ecp_check_pubkey +#define ecp_copy mbedtls_ecp_copy +#define ecp_curve_info mbedtls_ecp_curve_info +#define ecp_curve_info_from_grp_id mbedtls_ecp_curve_info_from_grp_id +#define ecp_curve_info_from_name mbedtls_ecp_curve_info_from_name +#define ecp_curve_info_from_tls_id mbedtls_ecp_curve_info_from_tls_id +#define ecp_curve_list mbedtls_ecp_curve_list +#define ecp_gen_key mbedtls_ecp_gen_key +#define ecp_gen_keypair mbedtls_ecp_gen_keypair +#define ecp_group mbedtls_ecp_group +#define ecp_group_copy mbedtls_ecp_group_copy +#define ecp_group_free mbedtls_ecp_group_free +#define ecp_group_id mbedtls_ecp_group_id +#define ecp_group_init mbedtls_ecp_group_init +#define ecp_group_read_string mbedtls_ecp_group_read_string +#define ecp_grp_id_list mbedtls_ecp_grp_id_list +#define ecp_is_zero mbedtls_ecp_is_zero +#define ecp_keypair mbedtls_ecp_keypair +#define ecp_keypair_free mbedtls_ecp_keypair_free +#define ecp_keypair_init mbedtls_ecp_keypair_init +#define ecp_mul mbedtls_ecp_mul +#define ecp_point mbedtls_ecp_point +#define ecp_point_free mbedtls_ecp_point_free +#define ecp_point_init mbedtls_ecp_point_init +#define ecp_point_read_binary mbedtls_ecp_point_read_binary +#define ecp_point_read_string mbedtls_ecp_point_read_string +#define ecp_point_write_binary mbedtls_ecp_point_write_binary +#define ecp_self_test mbedtls_ecp_self_test +#define ecp_set_zero mbedtls_ecp_set_zero +#define ecp_sub mbedtls_ecp_sub +#define ecp_tls_read_group mbedtls_ecp_tls_read_group +#define ecp_tls_read_point mbedtls_ecp_tls_read_point +#define ecp_tls_write_group mbedtls_ecp_tls_write_group +#define ecp_tls_write_point mbedtls_ecp_tls_write_point +#define ecp_use_known_dp mbedtls_ecp_group_load +#define entropy_add_source mbedtls_entropy_add_source +#define entropy_context mbedtls_entropy_context +#define entropy_free mbedtls_entropy_free +#define entropy_func mbedtls_entropy_func +#define entropy_gather mbedtls_entropy_gather +#define entropy_init mbedtls_entropy_init +#define entropy_self_test mbedtls_entropy_self_test +#define entropy_update_manual mbedtls_entropy_update_manual +#define entropy_update_seed_file mbedtls_entropy_update_seed_file +#define entropy_write_seed_file mbedtls_entropy_write_seed_file +#define error_strerror mbedtls_strerror +#define f_source_ptr mbedtls_entropy_f_source_ptr +#define gcm_auth_decrypt mbedtls_gcm_auth_decrypt +#define gcm_context mbedtls_gcm_context +#define gcm_crypt_and_tag mbedtls_gcm_crypt_and_tag +#define gcm_finish mbedtls_gcm_finish +#define gcm_free mbedtls_gcm_free +#define gcm_init mbedtls_gcm_init +#define gcm_self_test mbedtls_gcm_self_test +#define gcm_starts mbedtls_gcm_starts +#define gcm_update mbedtls_gcm_update +#define get_timer mbedtls_timing_get_timer +#define hardclock mbedtls_timing_hardclock +#define hardclock_poll mbedtls_hardclock_poll +#define havege_free mbedtls_havege_free +#define havege_init mbedtls_havege_init +#define havege_poll mbedtls_havege_poll +#define havege_random mbedtls_havege_random +#define havege_state mbedtls_havege_state +#define hmac_drbg_context mbedtls_hmac_drbg_context +#define hmac_drbg_free mbedtls_hmac_drbg_free +#define hmac_drbg_init mbedtls_hmac_drbg_init +#define hmac_drbg_init_buf mbedtls_hmac_drbg_init_buf +#define hmac_drbg_random mbedtls_hmac_drbg_random +#define hmac_drbg_random_with_add mbedtls_hmac_drbg_random_with_add +#define hmac_drbg_reseed mbedtls_hmac_drbg_reseed +#define hmac_drbg_self_test mbedtls_hmac_drbg_self_test +#define hmac_drbg_set_entropy_len mbedtls_hmac_drbg_set_entropy_len +#define hmac_drbg_set_prediction_resistance mbedtls_hmac_drbg_set_prediction_resistance +#define hmac_drbg_set_reseed_interval mbedtls_hmac_drbg_set_reseed_interval +#define hmac_drbg_update mbedtls_hmac_drbg_update +#define hmac_drbg_update_seed_file mbedtls_hmac_drbg_update_seed_file +#define hmac_drbg_write_seed_file mbedtls_hmac_drbg_write_seed_file +#define hr_time mbedtls_timing_hr_time +#define key_exchange_type_t mbedtls_key_exchange_type_t +#define md mbedtls_md +#define md2 mbedtls_md2 +#define md2_context mbedtls_md2_context +#define md2_file mbedtls_md2_file +#define md2_finish mbedtls_md2_finish +#define md2_free mbedtls_md2_free +#define md2_hmac mbedtls_md2_hmac +#define md2_hmac_finish mbedtls_md2_hmac_finish +#define md2_hmac_reset mbedtls_md2_hmac_reset +#define md2_hmac_starts mbedtls_md2_hmac_starts +#define md2_hmac_update mbedtls_md2_hmac_update +#define md2_info mbedtls_md2_info +#define md2_init mbedtls_md2_init +#define md2_process mbedtls_md2_process +#define md2_self_test mbedtls_md2_self_test +#define md2_starts mbedtls_md2_starts +#define md2_update mbedtls_md2_update +#define md4 mbedtls_md4 +#define md4_context mbedtls_md4_context +#define md4_file mbedtls_md4_file +#define md4_finish mbedtls_md4_finish +#define md4_free mbedtls_md4_free +#define md4_hmac mbedtls_md4_hmac +#define md4_hmac_finish mbedtls_md4_hmac_finish +#define md4_hmac_reset mbedtls_md4_hmac_reset +#define md4_hmac_starts mbedtls_md4_hmac_starts +#define md4_hmac_update mbedtls_md4_hmac_update +#define md4_info mbedtls_md4_info +#define md4_init mbedtls_md4_init +#define md4_process mbedtls_md4_process +#define md4_self_test mbedtls_md4_self_test +#define md4_starts mbedtls_md4_starts +#define md4_update mbedtls_md4_update +#define md5 mbedtls_md5 +#define md5_context mbedtls_md5_context +#define md5_file mbedtls_md5_file +#define md5_finish mbedtls_md5_finish +#define md5_free mbedtls_md5_free +#define md5_hmac mbedtls_md5_hmac +#define md5_hmac_finish mbedtls_md5_hmac_finish +#define md5_hmac_reset mbedtls_md5_hmac_reset +#define md5_hmac_starts mbedtls_md5_hmac_starts +#define md5_hmac_update mbedtls_md5_hmac_update +#define md5_info mbedtls_md5_info +#define md5_init mbedtls_md5_init +#define md5_process mbedtls_md5_process +#define md5_self_test mbedtls_md5_self_test +#define md5_starts mbedtls_md5_starts +#define md5_update mbedtls_md5_update +#define md_context_t mbedtls_md_context_t +#define md_file mbedtls_md_file +#define md_finish mbedtls_md_finish +#define md_free mbedtls_md_free +#define md_free_ctx mbedtls_md_free_ctx +#define md_get_name mbedtls_md_get_name +#define md_get_size mbedtls_md_get_size +#define md_get_type mbedtls_md_get_type +#define md_hmac mbedtls_md_hmac +#define md_hmac_finish mbedtls_md_hmac_finish +#define md_hmac_reset mbedtls_md_hmac_reset +#define md_hmac_starts mbedtls_md_hmac_starts +#define md_hmac_update mbedtls_md_hmac_update +#define md_info_from_string mbedtls_md_info_from_string +#define md_info_from_type mbedtls_md_info_from_type +#define md_info_t mbedtls_md_info_t +#define md_init mbedtls_md_init +#define md_init_ctx mbedtls_md_init_ctx +#define md_list mbedtls_md_list +#define md_process mbedtls_md_process +#define md_starts mbedtls_md_starts +#define md_type_t mbedtls_md_type_t +#define md_update mbedtls_md_update +#define memory_buffer_alloc_cur_get mbedtls_memory_buffer_alloc_cur_get +#define memory_buffer_alloc_free mbedtls_memory_buffer_alloc_free +#define memory_buffer_alloc_init mbedtls_memory_buffer_alloc_init +#define memory_buffer_alloc_max_get mbedtls_memory_buffer_alloc_max_get +#define memory_buffer_alloc_max_reset mbedtls_memory_buffer_alloc_max_reset +#define memory_buffer_alloc_self_test mbedtls_memory_buffer_alloc_self_test +#define memory_buffer_alloc_status mbedtls_memory_buffer_alloc_status +#define memory_buffer_alloc_verify mbedtls_memory_buffer_alloc_verify +#define memory_buffer_set_verify mbedtls_memory_buffer_set_verify +#define memory_set_own mbedtls_memory_set_own +#define mpi mbedtls_mpi +#define mpi_add_abs mbedtls_mpi_add_abs +#define mpi_add_int mbedtls_mpi_add_int +#define mpi_add_mpi mbedtls_mpi_add_mpi +#define mpi_cmp_abs mbedtls_mpi_cmp_abs +#define mpi_cmp_int mbedtls_mpi_cmp_int +#define mpi_cmp_mpi mbedtls_mpi_cmp_mpi +#define mpi_copy mbedtls_mpi_copy +#define mpi_div_int mbedtls_mpi_div_int +#define mpi_div_mpi mbedtls_mpi_div_mpi +#define mpi_exp_mod mbedtls_mpi_exp_mod +#define mpi_fill_random mbedtls_mpi_fill_random +#define mpi_free mbedtls_mpi_free +#define mpi_gcd mbedtls_mpi_gcd +#define mpi_gen_prime mbedtls_mpi_gen_prime +#define mpi_get_bit mbedtls_mpi_get_bit +#define mpi_grow mbedtls_mpi_grow +#define mpi_init mbedtls_mpi_init +#define mpi_inv_mod mbedtls_mpi_inv_mod +#define mpi_is_prime mbedtls_mpi_is_prime +#define mpi_lsb mbedtls_mpi_lsb +#define mpi_lset mbedtls_mpi_lset +#define mpi_mod_int mbedtls_mpi_mod_int +#define mpi_mod_mpi mbedtls_mpi_mod_mpi +#define mpi_msb mbedtls_mpi_bitlen +#define mpi_mul_int mbedtls_mpi_mul_int +#define mpi_mul_mpi mbedtls_mpi_mul_mpi +#define mpi_read_binary mbedtls_mpi_read_binary +#define mpi_read_file mbedtls_mpi_read_file +#define mpi_read_string mbedtls_mpi_read_string +#define mpi_safe_cond_assign mbedtls_mpi_safe_cond_assign +#define mpi_safe_cond_swap mbedtls_mpi_safe_cond_swap +#define mpi_self_test mbedtls_mpi_self_test +#define mpi_set_bit mbedtls_mpi_set_bit +#define mpi_shift_l mbedtls_mpi_shift_l +#define mpi_shift_r mbedtls_mpi_shift_r +#define mpi_shrink mbedtls_mpi_shrink +#define mpi_size mbedtls_mpi_size +#define mpi_sub_abs mbedtls_mpi_sub_abs +#define mpi_sub_int mbedtls_mpi_sub_int +#define mpi_sub_mpi mbedtls_mpi_sub_mpi +#define mpi_swap mbedtls_mpi_swap +#define mpi_write_binary mbedtls_mpi_write_binary +#define mpi_write_file mbedtls_mpi_write_file +#define mpi_write_string mbedtls_mpi_write_string +#define net_accept mbedtls_net_accept +#define net_bind mbedtls_net_bind +#define net_close mbedtls_net_free +#define net_connect mbedtls_net_connect +#define net_recv mbedtls_net_recv +#define net_recv_timeout mbedtls_net_recv_timeout +#define net_send mbedtls_net_send +#define net_set_block mbedtls_net_set_block +#define net_set_nonblock mbedtls_net_set_nonblock +#define net_usleep mbedtls_net_usleep +#define oid_descriptor_t mbedtls_oid_descriptor_t +#define oid_get_attr_short_name mbedtls_oid_get_attr_short_name +#define oid_get_cipher_alg mbedtls_oid_get_cipher_alg +#define oid_get_ec_grp mbedtls_oid_get_ec_grp +#define oid_get_extended_key_usage mbedtls_oid_get_extended_key_usage +#define oid_get_md_alg mbedtls_oid_get_md_alg +#define oid_get_numeric_string mbedtls_oid_get_numeric_string +#define oid_get_oid_by_ec_grp mbedtls_oid_get_oid_by_ec_grp +#define oid_get_oid_by_md mbedtls_oid_get_oid_by_md +#define oid_get_oid_by_pk_alg mbedtls_oid_get_oid_by_pk_alg +#define oid_get_oid_by_sig_alg mbedtls_oid_get_oid_by_sig_alg +#define oid_get_pk_alg mbedtls_oid_get_pk_alg +#define oid_get_pkcs12_pbe_alg mbedtls_oid_get_pkcs12_pbe_alg +#define oid_get_sig_alg mbedtls_oid_get_sig_alg +#define oid_get_sig_alg_desc mbedtls_oid_get_sig_alg_desc +#define oid_get_x509_ext_type mbedtls_oid_get_x509_ext_type +#define operation_t mbedtls_operation_t +#define padlock_supports mbedtls_padlock_has_support +#define padlock_xcryptcbc mbedtls_padlock_xcryptcbc +#define padlock_xcryptecb mbedtls_padlock_xcryptecb +#define pbkdf2_hmac mbedtls_pbkdf2_hmac +#define pbkdf2_self_test mbedtls_pbkdf2_self_test +#define pem_context mbedtls_pem_context +#define pem_free mbedtls_pem_free +#define pem_init mbedtls_pem_init +#define pem_read_buffer mbedtls_pem_read_buffer +#define pem_write_buffer mbedtls_pem_write_buffer +#define pk_can_do mbedtls_pk_can_do +#define pk_check_pair mbedtls_pk_check_pair +#define pk_context mbedtls_pk_context +#define pk_debug mbedtls_pk_debug +#define pk_debug_item mbedtls_pk_debug_item +#define pk_debug_type mbedtls_pk_debug_type +#define pk_decrypt mbedtls_pk_decrypt +#define pk_ec mbedtls_pk_ec +#define pk_encrypt mbedtls_pk_encrypt +#define pk_free mbedtls_pk_free +#define pk_get_len mbedtls_pk_get_len +#define pk_get_name mbedtls_pk_get_name +#define pk_get_size mbedtls_pk_get_bitlen +#define pk_get_type mbedtls_pk_get_type +#define pk_info_from_type mbedtls_pk_info_from_type +#define pk_info_t mbedtls_pk_info_t +#define pk_init mbedtls_pk_init +#define pk_init_ctx mbedtls_pk_setup +#define pk_init_ctx_rsa_alt mbedtls_pk_setup_rsa_alt +#define pk_load_file mbedtls_pk_load_file +#define pk_parse_key mbedtls_pk_parse_key +#define pk_parse_keyfile mbedtls_pk_parse_keyfile +#define pk_parse_public_key mbedtls_pk_parse_public_key +#define pk_parse_public_keyfile mbedtls_pk_parse_public_keyfile +#define pk_parse_subpubkey mbedtls_pk_parse_subpubkey +#define pk_rsa mbedtls_pk_rsa +#define pk_rsa_alt_decrypt_func mbedtls_pk_rsa_alt_decrypt_func +#define pk_rsa_alt_key_len_func mbedtls_pk_rsa_alt_key_len_func +#define pk_rsa_alt_sign_func mbedtls_pk_rsa_alt_sign_func +#define pk_rsassa_pss_options mbedtls_pk_rsassa_pss_options +#define pk_sign mbedtls_pk_sign +#define pk_type_t mbedtls_pk_type_t +#define pk_verify mbedtls_pk_verify +#define pk_verify_ext mbedtls_pk_verify_ext +#define pk_write_key_der mbedtls_pk_write_key_der +#define pk_write_key_pem mbedtls_pk_write_key_pem +#define pk_write_pubkey mbedtls_pk_write_pubkey +#define pk_write_pubkey_der mbedtls_pk_write_pubkey_der +#define pk_write_pubkey_pem mbedtls_pk_write_pubkey_pem +#define pkcs11_context mbedtls_pkcs11_context +#define pkcs11_decrypt mbedtls_pkcs11_decrypt +#define pkcs11_priv_key_free mbedtls_pkcs11_priv_key_free +#define pkcs11_priv_key_init mbedtls_pkcs11_priv_key_bind +#define pkcs11_sign mbedtls_pkcs11_sign +#define pkcs11_x509_cert_init mbedtls_pkcs11_x509_cert_bind +#define pkcs12_derivation mbedtls_pkcs12_derivation +#define pkcs12_pbe mbedtls_pkcs12_pbe +#define pkcs12_pbe_sha1_rc4_128 mbedtls_pkcs12_pbe_sha1_rc4_128 +#define pkcs5_pbes2 mbedtls_pkcs5_pbes2 +#define pkcs5_pbkdf2_hmac mbedtls_pkcs5_pbkdf2_hmac +#define pkcs5_self_test mbedtls_pkcs5_self_test +#define platform_entropy_poll mbedtls_platform_entropy_poll +#define platform_set_exit mbedtls_platform_set_exit +#define platform_set_fprintf mbedtls_platform_set_fprintf +#define platform_set_malloc_free mbedtls_platform_set_malloc_free +#define platform_set_printf mbedtls_platform_set_printf +#define platform_set_snprintf mbedtls_platform_set_snprintf +#define polarssl_exit mbedtls_exit +#define polarssl_fprintf mbedtls_fprintf +#define polarssl_free mbedtls_free +#define polarssl_malloc mbedtls_malloc +#define polarssl_mutex_free mbedtls_mutex_free +#define polarssl_mutex_init mbedtls_mutex_init +#define polarssl_mutex_lock mbedtls_mutex_lock +#define polarssl_mutex_unlock mbedtls_mutex_unlock +#define polarssl_printf mbedtls_printf +#define polarssl_snprintf mbedtls_snprintf +#define polarssl_strerror mbedtls_strerror +#define ripemd160 mbedtls_ripemd160 +#define ripemd160_context mbedtls_ripemd160_context +#define ripemd160_file mbedtls_ripemd160_file +#define ripemd160_finish mbedtls_ripemd160_finish +#define ripemd160_free mbedtls_ripemd160_free +#define ripemd160_hmac mbedtls_ripemd160_hmac +#define ripemd160_hmac_finish mbedtls_ripemd160_hmac_finish +#define ripemd160_hmac_reset mbedtls_ripemd160_hmac_reset +#define ripemd160_hmac_starts mbedtls_ripemd160_hmac_starts +#define ripemd160_hmac_update mbedtls_ripemd160_hmac_update +#define ripemd160_info mbedtls_ripemd160_info +#define ripemd160_init mbedtls_ripemd160_init +#define ripemd160_process mbedtls_ripemd160_process +#define ripemd160_self_test mbedtls_ripemd160_self_test +#define ripemd160_starts mbedtls_ripemd160_starts +#define ripemd160_update mbedtls_ripemd160_update +#define rsa_alt_context mbedtls_rsa_alt_context +#define rsa_alt_info mbedtls_rsa_alt_info +#define rsa_check_privkey mbedtls_rsa_check_privkey +#define rsa_check_pub_priv mbedtls_rsa_check_pub_priv +#define rsa_check_pubkey mbedtls_rsa_check_pubkey +#define rsa_context mbedtls_rsa_context +#define rsa_copy mbedtls_rsa_copy +#define rsa_decrypt_func mbedtls_rsa_decrypt_func +#define rsa_free mbedtls_rsa_free +#define rsa_gen_key mbedtls_rsa_gen_key +#define rsa_info mbedtls_rsa_info +#define rsa_init mbedtls_rsa_init +#define rsa_key_len_func mbedtls_rsa_key_len_func +#define rsa_pkcs1_decrypt mbedtls_rsa_pkcs1_decrypt +#define rsa_pkcs1_encrypt mbedtls_rsa_pkcs1_encrypt +#define rsa_pkcs1_sign mbedtls_rsa_pkcs1_sign +#define rsa_pkcs1_verify mbedtls_rsa_pkcs1_verify +#define rsa_private mbedtls_rsa_private +#define rsa_public mbedtls_rsa_public +#define rsa_rsaes_oaep_decrypt mbedtls_rsa_rsaes_oaep_decrypt +#define rsa_rsaes_oaep_encrypt mbedtls_rsa_rsaes_oaep_encrypt +#define rsa_rsaes_pkcs1_v15_decrypt mbedtls_rsa_rsaes_pkcs1_v15_decrypt +#define rsa_rsaes_pkcs1_v15_encrypt mbedtls_rsa_rsaes_pkcs1_v15_encrypt +#define rsa_rsassa_pkcs1_v15_sign mbedtls_rsa_rsassa_pkcs1_v15_sign +#define rsa_rsassa_pkcs1_v15_verify mbedtls_rsa_rsassa_pkcs1_v15_verify +#define rsa_rsassa_pss_sign mbedtls_rsa_rsassa_pss_sign +#define rsa_rsassa_pss_verify mbedtls_rsa_rsassa_pss_verify +#define rsa_rsassa_pss_verify_ext mbedtls_rsa_rsassa_pss_verify_ext +#define rsa_self_test mbedtls_rsa_self_test +#define rsa_set_padding mbedtls_rsa_set_padding +#define rsa_sign_func mbedtls_rsa_sign_func +#define safer_memcmp mbedtls_ssl_safer_memcmp +#define set_alarm mbedtls_set_alarm +#define sha1 mbedtls_sha1 +#define sha1_context mbedtls_sha1_context +#define sha1_file mbedtls_sha1_file +#define sha1_finish mbedtls_sha1_finish +#define sha1_free mbedtls_sha1_free +#define sha1_hmac mbedtls_sha1_hmac +#define sha1_hmac_finish mbedtls_sha1_hmac_finish +#define sha1_hmac_reset mbedtls_sha1_hmac_reset +#define sha1_hmac_starts mbedtls_sha1_hmac_starts +#define sha1_hmac_update mbedtls_sha1_hmac_update +#define sha1_info mbedtls_sha1_info +#define sha1_init mbedtls_sha1_init +#define sha1_process mbedtls_sha1_process +#define sha1_self_test mbedtls_sha1_self_test +#define sha1_starts mbedtls_sha1_starts +#define sha1_update mbedtls_sha1_update +#define sha224_info mbedtls_sha224_info +#define sha256 mbedtls_sha256 +#define sha256_context mbedtls_sha256_context +#define sha256_file mbedtls_sha256_file +#define sha256_finish mbedtls_sha256_finish +#define sha256_free mbedtls_sha256_free +#define sha256_hmac mbedtls_sha256_hmac +#define sha256_hmac_finish mbedtls_sha256_hmac_finish +#define sha256_hmac_reset mbedtls_sha256_hmac_reset +#define sha256_hmac_starts mbedtls_sha256_hmac_starts +#define sha256_hmac_update mbedtls_sha256_hmac_update +#define sha256_info mbedtls_sha256_info +#define sha256_init mbedtls_sha256_init +#define sha256_process mbedtls_sha256_process +#define sha256_self_test mbedtls_sha256_self_test +#define sha256_starts mbedtls_sha256_starts +#define sha256_update mbedtls_sha256_update +#define sha384_info mbedtls_sha384_info +#define sha512 mbedtls_sha512 +#define sha512_context mbedtls_sha512_context +#define sha512_file mbedtls_sha512_file +#define sha512_finish mbedtls_sha512_finish +#define sha512_free mbedtls_sha512_free +#define sha512_hmac mbedtls_sha512_hmac +#define sha512_hmac_finish mbedtls_sha512_hmac_finish +#define sha512_hmac_reset mbedtls_sha512_hmac_reset +#define sha512_hmac_starts mbedtls_sha512_hmac_starts +#define sha512_hmac_update mbedtls_sha512_hmac_update +#define sha512_info mbedtls_sha512_info +#define sha512_init mbedtls_sha512_init +#define sha512_process mbedtls_sha512_process +#define sha512_self_test mbedtls_sha512_self_test +#define sha512_starts mbedtls_sha512_starts +#define sha512_update mbedtls_sha512_update +#define source_state mbedtls_entropy_source_state +#define ssl_cache_context mbedtls_ssl_cache_context +#define ssl_cache_entry mbedtls_ssl_cache_entry +#define ssl_cache_free mbedtls_ssl_cache_free +#define ssl_cache_get mbedtls_ssl_cache_get +#define ssl_cache_init mbedtls_ssl_cache_init +#define ssl_cache_set mbedtls_ssl_cache_set +#define ssl_cache_set_max_entries mbedtls_ssl_cache_set_max_entries +#define ssl_cache_set_timeout mbedtls_ssl_cache_set_timeout +#define ssl_check_cert_usage mbedtls_ssl_check_cert_usage +#define ssl_ciphersuite_from_id mbedtls_ssl_ciphersuite_from_id +#define ssl_ciphersuite_from_string mbedtls_ssl_ciphersuite_from_string +#define ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t +#define ssl_ciphersuite_uses_ec mbedtls_ssl_ciphersuite_uses_ec +#define ssl_ciphersuite_uses_psk mbedtls_ssl_ciphersuite_uses_psk +#define ssl_close_notify mbedtls_ssl_close_notify +#define ssl_context mbedtls_ssl_context +#define ssl_cookie_check mbedtls_ssl_cookie_check +#define ssl_cookie_check_t mbedtls_ssl_cookie_check_t +#define ssl_cookie_ctx mbedtls_ssl_cookie_ctx +#define ssl_cookie_free mbedtls_ssl_cookie_free +#define ssl_cookie_init mbedtls_ssl_cookie_init +#define ssl_cookie_set_timeout mbedtls_ssl_cookie_set_timeout +#define ssl_cookie_setup mbedtls_ssl_cookie_setup +#define ssl_cookie_write mbedtls_ssl_cookie_write +#define ssl_cookie_write_t mbedtls_ssl_cookie_write_t +#define ssl_curve_is_acceptable mbedtls_ssl_curve_is_acceptable +#define ssl_derive_keys mbedtls_ssl_derive_keys +#define ssl_dtls_replay_check mbedtls_ssl_dtls_replay_check +#define ssl_dtls_replay_update mbedtls_ssl_dtls_replay_update +#define ssl_fetch_input mbedtls_ssl_fetch_input +#define ssl_flight_item mbedtls_ssl_flight_item +#define ssl_flush_output mbedtls_ssl_flush_output +#define ssl_free mbedtls_ssl_free +#define ssl_get_alpn_protocol mbedtls_ssl_get_alpn_protocol +#define ssl_get_bytes_avail mbedtls_ssl_get_bytes_avail +#define ssl_get_ciphersuite mbedtls_ssl_get_ciphersuite +#define ssl_get_ciphersuite_id mbedtls_ssl_get_ciphersuite_id +#define ssl_get_ciphersuite_name mbedtls_ssl_get_ciphersuite_name +#define ssl_get_ciphersuite_sig_pk_alg mbedtls_ssl_get_ciphersuite_sig_pk_alg +#define ssl_get_peer_cert mbedtls_ssl_get_peer_cert +#define ssl_get_record_expansion mbedtls_ssl_get_record_expansion +#define ssl_get_session mbedtls_ssl_get_session +#define ssl_get_verify_result mbedtls_ssl_get_verify_result +#define ssl_get_version mbedtls_ssl_get_version +#define ssl_handshake mbedtls_ssl_handshake +#define ssl_handshake_client_step mbedtls_ssl_handshake_client_step +#define ssl_handshake_free mbedtls_ssl_handshake_free +#define ssl_handshake_params mbedtls_ssl_handshake_params +#define ssl_handshake_server_step mbedtls_ssl_handshake_server_step +#define ssl_handshake_step mbedtls_ssl_handshake_step +#define ssl_handshake_wrapup mbedtls_ssl_handshake_wrapup +#define ssl_hdr_len mbedtls_ssl_hdr_len +#define ssl_hs_hdr_len mbedtls_ssl_hs_hdr_len +#define ssl_hw_record_activate mbedtls_ssl_hw_record_activate +#define ssl_hw_record_finish mbedtls_ssl_hw_record_finish +#define ssl_hw_record_init mbedtls_ssl_hw_record_init +#define ssl_hw_record_read mbedtls_ssl_hw_record_read +#define ssl_hw_record_reset mbedtls_ssl_hw_record_reset +#define ssl_hw_record_write mbedtls_ssl_hw_record_write +#define ssl_init mbedtls_ssl_init +#define ssl_key_cert mbedtls_ssl_key_cert +#define ssl_legacy_renegotiation mbedtls_ssl_conf_legacy_renegotiation +#define ssl_list_ciphersuites mbedtls_ssl_list_ciphersuites +#define ssl_md_alg_from_hash mbedtls_ssl_md_alg_from_hash +#define ssl_optimize_checksum mbedtls_ssl_optimize_checksum +#define ssl_own_cert mbedtls_ssl_own_cert +#define ssl_own_key mbedtls_ssl_own_key +#define ssl_parse_certificate mbedtls_ssl_parse_certificate +#define ssl_parse_change_cipher_spec mbedtls_ssl_parse_change_cipher_spec +#define ssl_parse_finished mbedtls_ssl_parse_finished +#define ssl_pk_alg_from_sig mbedtls_ssl_pk_alg_from_sig +#define ssl_pkcs11_decrypt mbedtls_ssl_pkcs11_decrypt +#define ssl_pkcs11_key_len mbedtls_ssl_pkcs11_key_len +#define ssl_pkcs11_sign mbedtls_ssl_pkcs11_sign +#define ssl_psk_derive_premaster mbedtls_ssl_psk_derive_premaster +#define ssl_read mbedtls_ssl_read +#define ssl_read_record mbedtls_ssl_read_record +#define ssl_read_version mbedtls_ssl_read_version +#define ssl_recv_flight_completed mbedtls_ssl_recv_flight_completed +#define ssl_renegotiate mbedtls_ssl_renegotiate +#define ssl_resend mbedtls_ssl_resend +#define ssl_reset_checksum mbedtls_ssl_reset_checksum +#define ssl_send_alert_message mbedtls_ssl_send_alert_message +#define ssl_send_fatal_handshake_failure mbedtls_ssl_send_fatal_handshake_failure +#define ssl_send_flight_completed mbedtls_ssl_send_flight_completed +#define ssl_session mbedtls_ssl_session +#define ssl_session_free mbedtls_ssl_session_free +#define ssl_session_init mbedtls_ssl_session_init +#define ssl_session_reset mbedtls_ssl_session_reset +#define ssl_set_alpn_protocols mbedtls_ssl_conf_alpn_protocols +#define ssl_set_arc4_support mbedtls_ssl_conf_arc4_support +#define ssl_set_authmode mbedtls_ssl_conf_authmode +#define ssl_set_bio mbedtls_ssl_set_bio +#define ssl_set_ca_chain mbedtls_ssl_conf_ca_chain +#define ssl_set_cbc_record_splitting mbedtls_ssl_conf_cbc_record_splitting +#define ssl_set_ciphersuites mbedtls_ssl_conf_ciphersuites +#define ssl_set_ciphersuites_for_version mbedtls_ssl_conf_ciphersuites_for_version +#define ssl_set_client_transport_id mbedtls_ssl_set_client_transport_id +#define ssl_set_curves mbedtls_ssl_conf_curves +#define ssl_set_dbg mbedtls_ssl_conf_dbg +#define ssl_set_dh_param mbedtls_ssl_conf_dh_param +#define ssl_set_dh_param_ctx mbedtls_ssl_conf_dh_param_ctx +#define ssl_set_dtls_anti_replay mbedtls_ssl_conf_dtls_anti_replay +#define ssl_set_dtls_badmac_limit mbedtls_ssl_conf_dtls_badmac_limit +#define ssl_set_dtls_cookies mbedtls_ssl_conf_dtls_cookies +#define ssl_set_encrypt_then_mac mbedtls_ssl_conf_encrypt_then_mac +#define ssl_set_endpoint mbedtls_ssl_conf_endpoint +#define ssl_set_extended_master_secret mbedtls_ssl_conf_extended_master_secret +#define ssl_set_fallback mbedtls_ssl_conf_fallback +#define ssl_set_handshake_timeout mbedtls_ssl_conf_handshake_timeout +#define ssl_set_hostname mbedtls_ssl_set_hostname +#define ssl_set_max_frag_len mbedtls_ssl_conf_max_frag_len +#define ssl_set_max_version mbedtls_ssl_conf_max_version +#define ssl_set_min_version mbedtls_ssl_conf_min_version +#define ssl_set_own_cert mbedtls_ssl_conf_own_cert +#define ssl_set_own_cert_alt mbedtls_ssl_set_own_cert_alt +#define ssl_set_own_cert_rsa mbedtls_ssl_set_own_cert_rsa +#define ssl_set_psk mbedtls_ssl_conf_psk +#define ssl_set_psk_cb mbedtls_ssl_conf_psk_cb +#define ssl_set_renegotiation mbedtls_ssl_conf_renegotiation +#define ssl_set_renegotiation_enforced mbedtls_ssl_conf_renegotiation_enforced +#define ssl_set_renegotiation_period mbedtls_ssl_conf_renegotiation_period +#define ssl_set_rng mbedtls_ssl_conf_rng +#define ssl_set_session mbedtls_ssl_set_session +#define ssl_set_session_cache mbedtls_ssl_conf_session_cache +#define ssl_set_session_ticket_lifetime mbedtls_ssl_conf_session_ticket_lifetime +#define ssl_set_session_tickets mbedtls_ssl_conf_session_tickets +#define ssl_set_sni mbedtls_ssl_conf_sni +#define ssl_set_transport mbedtls_ssl_conf_transport +#define ssl_set_truncated_hmac mbedtls_ssl_conf_truncated_hmac +#define ssl_set_verify mbedtls_ssl_conf_verify +#define ssl_sig_from_pk mbedtls_ssl_sig_from_pk +#define ssl_states mbedtls_ssl_states +#define ssl_ticket_keys mbedtls_ssl_ticket_keys +#define ssl_transform mbedtls_ssl_transform +#define ssl_transform_free mbedtls_ssl_transform_free +#define ssl_write mbedtls_ssl_write +#define ssl_write_certificate mbedtls_ssl_write_certificate +#define ssl_write_change_cipher_spec mbedtls_ssl_write_change_cipher_spec +#define ssl_write_finished mbedtls_ssl_write_finished +#define ssl_write_record mbedtls_ssl_write_record +#define ssl_write_version mbedtls_ssl_write_version +#define supported_ciphers mbedtls_cipher_supported +#define t_sint mbedtls_mpi_sint +#define t_udbl mbedtls_t_udbl +#define t_uint mbedtls_mpi_uint +#define test_ca_crt mbedtls_test_ca_crt +#define test_ca_crt_ec mbedtls_test_ca_crt_ec +#define test_ca_crt_rsa mbedtls_test_ca_crt_rsa +#define test_ca_key mbedtls_test_ca_key +#define test_ca_key_ec mbedtls_test_ca_key_ec +#define test_ca_key_rsa mbedtls_test_ca_key_rsa +#define test_ca_list mbedtls_test_cas_pem +#define test_ca_pwd mbedtls_test_ca_pwd +#define test_ca_pwd_ec mbedtls_test_ca_pwd_ec +#define test_ca_pwd_rsa mbedtls_test_ca_pwd_rsa +#define test_cli_crt mbedtls_test_cli_crt +#define test_cli_crt_ec mbedtls_test_cli_crt_ec +#define test_cli_crt_rsa mbedtls_test_cli_crt_rsa +#define test_cli_key mbedtls_test_cli_key +#define test_cli_key_ec mbedtls_test_cli_key_ec +#define test_cli_key_rsa mbedtls_test_cli_key_rsa +#define test_dhm_params mbedtls_test_dhm_params +#define test_srv_crt mbedtls_test_srv_crt +#define test_srv_crt_ec mbedtls_test_srv_crt_ec +#define test_srv_crt_rsa mbedtls_test_srv_crt_rsa +#define test_srv_key mbedtls_test_srv_key +#define test_srv_key_ec mbedtls_test_srv_key_ec +#define test_srv_key_rsa mbedtls_test_srv_key_rsa +#define threading_mutex_t mbedtls_threading_mutex_t +#define threading_set_alt mbedtls_threading_set_alt +#define timing_self_test mbedtls_timing_self_test +#define version_check_feature mbedtls_version_check_feature +#define version_get_number mbedtls_version_get_number +#define version_get_string mbedtls_version_get_string +#define version_get_string_full mbedtls_version_get_string_full +#define x509_bitstring mbedtls_x509_bitstring +#define x509_buf mbedtls_x509_buf +#define x509_crl mbedtls_x509_crl +#define x509_crl_entry mbedtls_x509_crl_entry +#define x509_crl_free mbedtls_x509_crl_free +#define x509_crl_info mbedtls_x509_crl_info +#define x509_crl_init mbedtls_x509_crl_init +#define x509_crl_parse mbedtls_x509_crl_parse +#define x509_crl_parse_der mbedtls_x509_crl_parse_der +#define x509_crl_parse_file mbedtls_x509_crl_parse_file +#define x509_crt mbedtls_x509_crt +#define x509_crt_check_extended_key_usage mbedtls_x509_crt_check_extended_key_usage +#define x509_crt_check_key_usage mbedtls_x509_crt_check_key_usage +#define x509_crt_free mbedtls_x509_crt_free +#define x509_crt_info mbedtls_x509_crt_info +#define x509_crt_init mbedtls_x509_crt_init +#define x509_crt_parse mbedtls_x509_crt_parse +#define x509_crt_parse_der mbedtls_x509_crt_parse_der +#define x509_crt_parse_file mbedtls_x509_crt_parse_file +#define x509_crt_parse_path mbedtls_x509_crt_parse_path +#define x509_crt_revoked mbedtls_x509_crt_is_revoked +#define x509_crt_verify mbedtls_x509_crt_verify +#define x509_csr mbedtls_x509_csr +#define x509_csr_free mbedtls_x509_csr_free +#define x509_csr_info mbedtls_x509_csr_info +#define x509_csr_init mbedtls_x509_csr_init +#define x509_csr_parse mbedtls_x509_csr_parse +#define x509_csr_parse_der mbedtls_x509_csr_parse_der +#define x509_csr_parse_file mbedtls_x509_csr_parse_file +#define x509_dn_gets mbedtls_x509_dn_gets +#define x509_get_alg mbedtls_x509_get_alg +#define x509_get_alg_null mbedtls_x509_get_alg_null +#define x509_get_ext mbedtls_x509_get_ext +#define x509_get_name mbedtls_x509_get_name +#define x509_get_rsassa_pss_params mbedtls_x509_get_rsassa_pss_params +#define x509_get_serial mbedtls_x509_get_serial +#define x509_get_sig mbedtls_x509_get_sig +#define x509_get_sig_alg mbedtls_x509_get_sig_alg +#define x509_get_time mbedtls_x509_get_time +#define x509_key_size_helper mbedtls_x509_key_size_helper +#define x509_name mbedtls_x509_name +#define x509_oid_get_description mbedtls_x509_oid_get_description +#define x509_oid_get_numeric_string mbedtls_x509_oid_get_numeric_string +#define x509_self_test mbedtls_x509_self_test +#define x509_sequence mbedtls_x509_sequence +#define x509_serial_gets mbedtls_x509_serial_gets +#define x509_set_extension mbedtls_x509_set_extension +#define x509_sig_alg_gets mbedtls_x509_sig_alg_gets +#define x509_string_to_names mbedtls_x509_string_to_names +#define x509_time mbedtls_x509_time +#define x509_time_expired mbedtls_x509_time_is_past +#define x509_time_future mbedtls_x509_time_is_future +#define x509_write_extensions mbedtls_x509_write_extensions +#define x509_write_names mbedtls_x509_write_names +#define x509_write_sig mbedtls_x509_write_sig +#define x509write_cert mbedtls_x509write_cert +#define x509write_crt_der mbedtls_x509write_crt_der +#define x509write_crt_free mbedtls_x509write_crt_free +#define x509write_crt_init mbedtls_x509write_crt_init +#define x509write_crt_pem mbedtls_x509write_crt_pem +#define x509write_crt_set_authority_key_identifier mbedtls_x509write_crt_set_authority_key_identifier +#define x509write_crt_set_basic_constraints mbedtls_x509write_crt_set_basic_constraints +#define x509write_crt_set_extension mbedtls_x509write_crt_set_extension +#define x509write_crt_set_issuer_key mbedtls_x509write_crt_set_issuer_key +#define x509write_crt_set_issuer_name mbedtls_x509write_crt_set_issuer_name +#define x509write_crt_set_key_usage mbedtls_x509write_crt_set_key_usage +#define x509write_crt_set_md_alg mbedtls_x509write_crt_set_md_alg +#define x509write_crt_set_ns_cert_type mbedtls_x509write_crt_set_ns_cert_type +#define x509write_crt_set_serial mbedtls_x509write_crt_set_serial +#define x509write_crt_set_subject_key mbedtls_x509write_crt_set_subject_key +#define x509write_crt_set_subject_key_identifier mbedtls_x509write_crt_set_subject_key_identifier +#define x509write_crt_set_subject_name mbedtls_x509write_crt_set_subject_name +#define x509write_crt_set_validity mbedtls_x509write_crt_set_validity +#define x509write_crt_set_version mbedtls_x509write_crt_set_version +#define x509write_csr mbedtls_x509write_csr +#define x509write_csr_der mbedtls_x509write_csr_der +#define x509write_csr_free mbedtls_x509write_csr_free +#define x509write_csr_init mbedtls_x509write_csr_init +#define x509write_csr_pem mbedtls_x509write_csr_pem +#define x509write_csr_set_extension mbedtls_x509write_csr_set_extension +#define x509write_csr_set_key mbedtls_x509write_csr_set_key +#define x509write_csr_set_key_usage mbedtls_x509write_csr_set_key_usage +#define x509write_csr_set_md_alg mbedtls_x509write_csr_set_md_alg +#define x509write_csr_set_ns_cert_type mbedtls_x509write_csr_set_ns_cert_type +#define x509write_csr_set_subject_name mbedtls_x509write_csr_set_subject_name +#define xtea_context mbedtls_xtea_context +#define xtea_crypt_cbc mbedtls_xtea_crypt_cbc +#define xtea_crypt_ecb mbedtls_xtea_crypt_ecb +#define xtea_free mbedtls_xtea_free +#define xtea_init mbedtls_xtea_init +#define xtea_self_test mbedtls_xtea_self_test +#define xtea_setup mbedtls_xtea_setup + +#endif /* compat-1.3.h */ +#endif /* MBEDTLS_DEPRECATED_REMOVED */ diff --git a/c++/src/connect/mbedtls/mbedtls/config.h b/c++/src/connect/mbedtls/mbedtls/config.h new file mode 100644 index 00000000..e5492fc1 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/config.h @@ -0,0 +1,2614 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * This set of compile-time options may be used to enable + * or disable features selectively, and reduce the global + * memory footprint. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_CONFIG_H +#define MBEDTLS_CONFIG_H + +#include + +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE) +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +/** + * \name SECTION: System support + * + * This section sets system specific settings. + * \{ + */ + +/** + * \def MBEDTLS_HAVE_ASM + * + * The compiler has support for asm(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/mbedtls/bn_mul.h + * + * Comment to disable the use of assembly code. + */ +#define MBEDTLS_HAVE_ASM + +/** + * \def MBEDTLS_HAVE_SSE2 + * + * CPU supports SSE2 instruction set. + * + * Uncomment if the CPU supports SSE2 (IA-32 specific). + */ +#if defined(__SSE2__) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2) +# define MBEDTLS_HAVE_SSE2 +#endif + +/** + * \def MBEDTLS_HAVE_TIME + * + * System has time.h and time(). + * The time does not need to be correct, only time differences are used, + * by contrast with MBEDTLS_HAVE_TIME_DATE + * + * Defining MBEDTLS_HAVE_TIME allows you to specify MBEDTLS_PLATFORM_TIME_ALT, + * MBEDTLS_PLATFORM_TIME_MACRO, MBEDTLS_PLATFORM_TIME_TYPE_MACRO and + * MBEDTLS_PLATFORM_STD_TIME. + * + * Comment if your system does not support time functions + */ +#define MBEDTLS_HAVE_TIME + +/** + * \def MBEDTLS_HAVE_TIME_DATE + * + * System has time.h and time(), gmtime() and the clock is correct. + * The time needs to be correct (not necesarily very accurate, but at least + * the date should be correct). This is used to verify the validity period of + * X.509 certificates. + * + * Comment if your system does not have a correct clock. + */ +#define MBEDTLS_HAVE_TIME_DATE + +/** + * \def MBEDTLS_PLATFORM_MEMORY + * + * Enable the memory allocation layer. + * + * By default mbed TLS uses the system-provided calloc() and free(). + * This allows different allocators (self-implemented or provided) to be + * provided to the platform abstraction layer. + * + * Enabling MBEDTLS_PLATFORM_MEMORY without the + * MBEDTLS_PLATFORM_{FREE,CALLOC}_MACROs will provide + * "mbedtls_platform_set_calloc_free()" allowing you to set an alternative calloc() and + * free() function pointer at runtime. + * + * Enabling MBEDTLS_PLATFORM_MEMORY and specifying + * MBEDTLS_PLATFORM_{CALLOC,FREE}_MACROs will allow you to specify the + * alternate function at compile time. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Enable this layer to allow use of alternative memory allocators. + */ +//#define MBEDTLS_PLATFORM_MEMORY + +/** + * \def MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + * + * Do not assign standard functions in the platform layer (e.g. calloc() to + * MBEDTLS_PLATFORM_STD_CALLOC and printf() to MBEDTLS_PLATFORM_STD_PRINTF) + * + * This makes sure there are no linking errors on platforms that do not support + * these functions. You will HAVE to provide alternatives, either at runtime + * via the platform_set_xxx() functions or at compile time by setting + * the MBEDTLS_PLATFORM_STD_XXX defines, or enabling a + * MBEDTLS_PLATFORM_XXX_MACRO. + * + * Requires: MBEDTLS_PLATFORM_C + * + * Uncomment to prevent default assignment of standard functions in the + * platform layer. + */ +//#define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS + +/** + * \def MBEDTLS_PLATFORM_EXIT_ALT + * + * MBEDTLS_PLATFORM_XXX_ALT: Uncomment a macro to let mbed TLS support the + * function in the platform abstraction layer. + * + * Example: In case you uncomment MBEDTLS_PLATFORM_PRINTF_ALT, mbed TLS will + * provide a function "mbedtls_platform_set_printf()" that allows you to set an + * alternative printf function pointer. + * + * All these define require MBEDTLS_PLATFORM_C to be defined! + * + * \note MBEDTLS_PLATFORM_SNPRINTF_ALT is required on Windows; + * it will be enabled automatically by check_config.h + * + * \warning MBEDTLS_PLATFORM_XXX_ALT cannot be defined at the same time as + * MBEDTLS_PLATFORM_XXX_MACRO! + * + * Requires: MBEDTLS_PLATFORM_TIME_ALT requires MBEDTLS_HAVE_TIME + * + * Uncomment a macro to enable alternate implementation of specific base + * platform function + */ +//#define MBEDTLS_PLATFORM_EXIT_ALT +//#define MBEDTLS_PLATFORM_TIME_ALT +//#define MBEDTLS_PLATFORM_FPRINTF_ALT +//#define MBEDTLS_PLATFORM_PRINTF_ALT +//#define MBEDTLS_PLATFORM_SNPRINTF_ALT +//#define MBEDTLS_PLATFORM_NV_SEED_ALT + +/** + * \def MBEDTLS_DEPRECATED_WARNING + * + * Mark deprecated functions so that they generate a warning if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * This only works with GCC and Clang. With other compilers, you may want to + * use MBEDTLS_DEPRECATED_REMOVED + * + * Uncomment to get warnings on using deprecated functions. + */ +#if defined(NCBI_COMPILER_GCC) || defined(NCBI_COMPILER_ICC) +# define MBEDTLS_DEPRECATED_WARNING +#endif + +/** + * \def MBEDTLS_DEPRECATED_REMOVED + * + * Remove deprecated functions so that they generate an error if used. + * Functions deprecated in one version will usually be removed in the next + * version. You can enable this to help you prepare the transition to a new + * major version by making sure your code is not using these functions. + * + * Uncomment to get errors on using deprecated functions. + */ +//#define MBEDTLS_DEPRECATED_REMOVED + +/* \} name SECTION: System support */ + +/** + * \name SECTION: mbed TLS feature support + * + * This section sets support for features that are or are not needed + * within the modules that are enabled. + * \{ + */ + +/** + * \def MBEDTLS_TIMING_ALT + * + * Uncomment to provide your own alternate implementation for mbedtls_timing_hardclock(), + * mbedtls_timing_get_timer(), mbedtls_set_alarm(), mbedtls_set/get_delay() + * + * Only works if you have MBEDTLS_TIMING_C enabled. + * + * You will need to provide a header "timing_alt.h" and an implementation at + * compile time. + */ +//#define MBEDTLS_TIMING_ALT + +/** + * \def MBEDTLS_AES_ALT + * + * MBEDTLS__MODULE_NAME__ALT: Uncomment a macro to let mbed TLS use your + * alternate core implementation of a symmetric crypto or hash module (e.g. + * platform specific assembly optimized implementations). Keep in mind that + * the function prototypes should remain the same. + * + * This replaces the whole module. If you only want to replace one of the + * functions, use one of the MBEDTLS__FUNCTION_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_AES_ALT, mbed TLS will no longer + * provide the "struct mbedtls_aes_context" definition and omit the base function + * declarations and implementations. "aes_alt.h" will be included from + * "aes.h" to include the new function definitions. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * module. + */ +//#define MBEDTLS_AES_ALT +//#define MBEDTLS_ARC4_ALT +//#define MBEDTLS_BLOWFISH_ALT +//#define MBEDTLS_CAMELLIA_ALT +//#define MBEDTLS_DES_ALT +//#define MBEDTLS_XTEA_ALT +//#define MBEDTLS_MD2_ALT +//#define MBEDTLS_MD4_ALT +//#define MBEDTLS_MD5_ALT +//#define MBEDTLS_RIPEMD160_ALT +//#define MBEDTLS_SHA1_ALT +//#define MBEDTLS_SHA256_ALT +//#define MBEDTLS_SHA512_ALT + +/** + * \def MBEDTLS_MD2_PROCESS_ALT + * + * MBEDTLS__FUNCTION_NAME__ALT: Uncomment a macro to let mbed TLS use you + * alternate core implementation of symmetric crypto or hash function. Keep in + * mind that function prototypes should remain the same. + * + * This replaces only one function. The header file from mbed TLS is still + * used, in contrast to the MBEDTLS__MODULE_NAME__ALT flags. + * + * Example: In case you uncomment MBEDTLS_SHA256_PROCESS_ALT, mbed TLS will + * no longer provide the mbedtls_sha1_process() function, but it will still provide + * the other function (using your mbedtls_sha1_process() function) and the definition + * of mbedtls_sha1_context, so your implementation of mbedtls_sha1_process must be compatible + * with this definition. + * + * Note: if you use the AES_xxx_ALT macros, then is is recommended to also set + * MBEDTLS_AES_ROM_TABLES in order to help the linker garbage-collect the AES + * tables. + * + * Uncomment a macro to enable alternate implementation of the corresponding + * function. + */ +//#define MBEDTLS_MD2_PROCESS_ALT +//#define MBEDTLS_MD4_PROCESS_ALT +//#define MBEDTLS_MD5_PROCESS_ALT +//#define MBEDTLS_RIPEMD160_PROCESS_ALT +//#define MBEDTLS_SHA1_PROCESS_ALT +//#define MBEDTLS_SHA256_PROCESS_ALT +//#define MBEDTLS_SHA512_PROCESS_ALT +//#define MBEDTLS_DES_SETKEY_ALT +//#define MBEDTLS_DES_CRYPT_ECB_ALT +//#define MBEDTLS_DES3_CRYPT_ECB_ALT +//#define MBEDTLS_AES_SETKEY_ENC_ALT +//#define MBEDTLS_AES_SETKEY_DEC_ALT +//#define MBEDTLS_AES_ENCRYPT_ALT +//#define MBEDTLS_AES_DECRYPT_ALT + +/** + * \def MBEDTLS_TEST_NULL_ENTROPY + * + * Enables testing and use of mbed TLS without any configured entropy sources. + * This permits use of the library on platforms before an entropy source has + * been integrated (see for example the MBEDTLS_ENTROPY_HARDWARE_ALT or the + * MBEDTLS_ENTROPY_NV_SEED switches). + * + * WARNING! This switch MUST be disabled in production builds, and is suitable + * only for development. + * Enabling the switch negates any security provided by the library. + * + * Requires MBEDTLS_ENTROPY_C, MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + */ +//#define MBEDTLS_TEST_NULL_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_HARDWARE_ALT + * + * Uncomment this macro to let mbed TLS use your own implementation of a + * hardware entropy collector. + * + * Your function must be called \c mbedtls_hardware_poll(), have the same + * prototype as declared in entropy_poll.h, and accept NULL as first argument. + * + * Uncomment to use your own hardware entropy collector. + */ +//#define MBEDTLS_ENTROPY_HARDWARE_ALT + +/** + * \def MBEDTLS_AES_ROM_TABLES + * + * Store the AES tables in ROM. + * + * Uncomment this macro to store the AES tables in ROM. + */ +//#define MBEDTLS_AES_ROM_TABLES + +/** + * \def MBEDTLS_CAMELLIA_SMALL_MEMORY + * + * Use less ROM for the Camellia implementation (saves about 768 bytes). + * + * Uncomment this macro to use less memory for Camellia. + */ +//#define MBEDTLS_CAMELLIA_SMALL_MEMORY + +/** + * \def MBEDTLS_CIPHER_MODE_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CBC + +/** + * \def MBEDTLS_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CFB + +/** + * \def MBEDTLS_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +#define MBEDTLS_CIPHER_MODE_CTR + +/** + * \def MBEDTLS_CIPHER_NULL_CIPHER + * + * Enable NULL cipher. + * Warning: Only do so when you know what you are doing. This allows for + * encryption or channels without any security! + * + * Requires MBEDTLS_ENABLE_WEAK_CIPHERSUITES as well to enable + * the following ciphersuites: + * MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_WITH_NULL_SHA + * MBEDTLS_TLS_RSA_WITH_NULL_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA + * MBEDTLS_TLS_PSK_WITH_NULL_SHA384 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA256 + * MBEDTLS_TLS_PSK_WITH_NULL_SHA + * + * Uncomment this macro to enable the NULL cipher and ciphersuites + */ +//#define MBEDTLS_CIPHER_NULL_CIPHER + +/** + * \def MBEDTLS_CIPHER_PADDING_PKCS7 + * + * MBEDTLS_CIPHER_PADDING_XXX: Uncomment or comment macros to add support for + * specific padding modes in the cipher layer with cipher modes that support + * padding (e.g. CBC) + * + * If you disable all padding modes, only full blocks can be used with CBC. + * + * Enable padding modes in the cipher layer. + */ +#define MBEDTLS_CIPHER_PADDING_PKCS7 +#define MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS +#define MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN +#define MBEDTLS_CIPHER_PADDING_ZEROS + +/** + * \def MBEDTLS_ENABLE_WEAK_CIPHERSUITES + * + * Enable weak ciphersuites in SSL / TLS. + * Warning: Only do so when you know what you are doing. This allows for + * channels with virtually no security at all! + * + * This enables the following ciphersuites: + * MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA + * + * Uncomment this macro to enable weak ciphersuites + */ +//#define MBEDTLS_ENABLE_WEAK_CIPHERSUITES + +/** + * \def MBEDTLS_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by mbedtls_ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with mbedtls_ssl_conf_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +#define MBEDTLS_REMOVE_ARC4_CIPHERSUITES + +/** + * \def MBEDTLS_ECP_DP_SECP192R1_ENABLED + * + * MBEDTLS_ECP_XXXX_ENABLED: Enables specific curves within the Elliptic Curve + * module. By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +#define MBEDTLS_ECP_DP_SECP192R1_ENABLED +#define MBEDTLS_ECP_DP_SECP224R1_ENABLED +#define MBEDTLS_ECP_DP_SECP256R1_ENABLED +#define MBEDTLS_ECP_DP_SECP384R1_ENABLED +#define MBEDTLS_ECP_DP_SECP521R1_ENABLED +#define MBEDTLS_ECP_DP_SECP192K1_ENABLED +#define MBEDTLS_ECP_DP_SECP224K1_ENABLED +#define MBEDTLS_ECP_DP_SECP256K1_ENABLED +#define MBEDTLS_ECP_DP_BP256R1_ENABLED +#define MBEDTLS_ECP_DP_BP384R1_ENABLED +#define MBEDTLS_ECP_DP_BP512R1_ENABLED +#define MBEDTLS_ECP_DP_CURVE25519_ENABLED + +/** + * \def MBEDTLS_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +#define MBEDTLS_ECP_NIST_OPTIM + +/** + * \def MBEDTLS_ECDSA_DETERMINISTIC + * + * Enable deterministic ECDSA (RFC 6979). + * Standard ECDSA is "fragile" in the sense that lack of entropy when signing + * may result in a compromise of the long-term signing key. This is avoided by + * the deterministic variant. + * + * Requires: MBEDTLS_HMAC_DRBG_C + * + * Comment this macro to disable deterministic ECDSA. + */ +#define MBEDTLS_ECDSA_DETERMINISTIC + +/** + * \def MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + * + * Enable the PSK based ciphersuite modes in SSL / TLS. + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + * + * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + * + * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + * + * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + */ +#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_DHM_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_RSA_C, MBEDTLS_PKCS1_V15, + * MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_ECDSA_C, MBEDTLS_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + */ +#define MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: MBEDTLS_ECDH_C, MBEDTLS_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + * + * Enable the ECJPAKE based ciphersuite modes in SSL / TLS. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Requires: MBEDTLS_ECJPAKE_C + * MBEDTLS_SHA256_C + * MBEDTLS_ECP_DP_SECP256R1_ENABLED + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 + */ +//#define MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED + +/** + * \def MBEDTLS_PK_PARSE_EC_EXTENDED + * + * Enhance support for reading EC keys using variants of SEC1 not allowed by + * RFC 5915 and RFC 5480. + * + * Currently this means parsing the SpecifiedECDomain choice of EC + * parameters (only known groups are supported, not arbitrary domains, to + * avoid validation issues). + * + * Disable if you only need to support RFC 5915 + 5480 key formats. + */ +#define MBEDTLS_PK_PARSE_EC_EXTENDED + +/** + * \def MBEDTLS_ERROR_STRERROR_DUMMY + * + * Enable a dummy error function to make use of mbedtls_strerror() in + * third party libraries easier when MBEDTLS_ERROR_C is disabled + * (no effect when MBEDTLS_ERROR_C is enabled). + * + * You can safely disable this if MBEDTLS_ERROR_C is enabled, or if you're + * not using mbedtls_strerror() or error_strerror() in your application. + * + * Disable if you run into name conflicts and want to really remove the + * mbedtls_strerror() + */ +#define MBEDTLS_ERROR_STRERROR_DUMMY + +/** + * \def MBEDTLS_GENPRIME + * + * Enable the prime-number generation code. + * + * Requires: MBEDTLS_BIGNUM_C + */ +#define MBEDTLS_GENPRIME + +/** + * \def MBEDTLS_FS_IO + * + * Enable functions that use the filesystem. + */ +#define MBEDTLS_FS_IO + +/** + * \def MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + * + * Do not add default entropy sources. These are the platform specific, + * mbedtls_timing_hardclock and HAVEGE based poll functions. + * + * This is useful to have more control over the added entropy sources in an + * application. + * + * Uncomment this macro to prevent loading of default entropy functions. + */ +//#define MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES + +/** + * \def MBEDTLS_NO_PLATFORM_ENTROPY + * + * Do not use built-in platform entropy functions. + * This is useful if your platform does not support + * standards like the /dev/urandom or Windows CryptoAPI. + * + * Uncomment this macro to disable the built-in platform entropy functions. + */ +//#define MBEDTLS_NO_PLATFORM_ENTROPY + +/** + * \def MBEDTLS_ENTROPY_FORCE_SHA256 + * + * Force the entropy accumulator to use a SHA-256 accumulator instead of the + * default SHA-512 based one (if both are available). + * + * Requires: MBEDTLS_SHA256_C + * + * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option + * if you have performance concerns. + * + * This option is only useful if both MBEDTLS_SHA256_C and + * MBEDTLS_SHA512_C are defined. Otherwise the available hash module is used. + */ +//#define MBEDTLS_ENTROPY_FORCE_SHA256 + +/** + * \def MBEDTLS_ENTROPY_NV_SEED + * + * Enable the non-volatile (NV) seed file-based entropy source. + * (Also enables the NV seed read/write functions in the platform layer) + * + * This is crucial (if not required) on systems that do not have a + * cryptographic entropy source (in hardware or kernel) available. + * + * Requires: MBEDTLS_ENTROPY_C, MBEDTLS_PLATFORM_C + * + * \note The read/write functions that are used by the entropy source are + * determined in the platform layer, and can be modified at runtime and/or + * compile-time depending on the flags (MBEDTLS_PLATFORM_NV_SEED_*) used. + * + * \note If you use the default implementation functions that read a seedfile + * with regular fopen(), please make sure you make a seedfile with the + * proper name (defined in MBEDTLS_PLATFORM_STD_NV_SEED_FILE) and at + * least MBEDTLS_ENTROPY_BLOCK_SIZE bytes in size that can be read from + * and written to or you will get an entropy source error! The default + * implementation will only use the first MBEDTLS_ENTROPY_BLOCK_SIZE + * bytes from the file. + * + * \note The entropy collector will write to the seed file before entropy is + * given to an external source, to update it. + */ +//#define MBEDTLS_ENTROPY_NV_SEED + +/** + * \def MBEDTLS_MEMORY_DEBUG + * + * Enable debugging of buffer allocator memory issues. Automatically prints + * (to stderr) all (fatal) messages on memory allocation issues. Enables + * function for 'debug output' of allocated memory. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Uncomment this macro to let the buffer allocator print out error messages. + */ +//#define MBEDTLS_MEMORY_DEBUG + +/** + * \def MBEDTLS_MEMORY_BACKTRACE + * + * Include backtrace information with each allocated block. + * + * Requires: MBEDTLS_MEMORY_BUFFER_ALLOC_C + * GLIBC-compatible backtrace() an backtrace_symbols() support + * + * Uncomment this macro to include backtrace information + */ +//#define MBEDTLS_MEMORY_BACKTRACE + +/** + * \def MBEDTLS_PK_RSA_ALT_SUPPORT + * + * Support external private RSA keys (eg from a HSM) in the PK layer. + * + * Comment this macro to disable support for external private RSA keys. + */ +#define MBEDTLS_PK_RSA_ALT_SUPPORT + +/** + * \def MBEDTLS_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: MBEDTLS_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define MBEDTLS_PKCS1_V15 + +/** + * \def MBEDTLS_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: MBEDTLS_MD_C, MBEDTLS_RSA_C + * + * This enables support for RSAES-OAEP and RSASSA-PSS operations. + */ +#define MBEDTLS_PKCS1_V21 + +/** + * \def MBEDTLS_RSA_NO_CRT + * + * Do not use the Chinese Remainder Theorem for the RSA private operation. + * + * Uncomment this macro to disable the use of CRT in RSA. + * + */ +//#define MBEDTLS_RSA_NO_CRT + +/** + * \def MBEDTLS_SELF_TEST + * + * Enable the checkup functions (*_self_test). + */ +#define MBEDTLS_SELF_TEST + +/** + * \def MBEDTLS_SHA256_SMALLER + * + * Enable an implementation of SHA-256 that has lower ROM footprint but also + * lower performance. + * + * The default implementation is meant to be a reasonnable compromise between + * performance and size. This version optimizes more aggressively for size at + * the expense of performance. Eg on Cortex-M4 it reduces the size of + * mbedtls_sha256_process() from ~2KB to ~0.5KB for a performance hit of about + * 30%. + * + * Uncomment to enable the smaller implementation of SHA256. + */ +//#define MBEDTLS_SHA256_SMALLER + +/** + * \def MBEDTLS_SSL_ALL_ALERT_MESSAGES + * + * Enable sending of alert messages in case of encountered errors as per RFC. + * If you choose not to send the alert messages, mbed TLS can still communicate + * with other servers, only debugging of failures is harder. + * + * The advantage of not sending alert messages, is that no information is given + * about reasons for failures thus preventing adversaries of gaining intel. + * + * Enable sending of all alert messages + */ +#define MBEDTLS_SSL_ALL_ALERT_MESSAGES + +/** + * \def MBEDTLS_SSL_DEBUG_ALL + * + * Enable the debug messages in SSL module for all issues. + * Debug messages have been disabled in some places to prevent timing + * attacks due to (unbalanced) debugging function calls. + * + * If you need all error reporting you should enable this during debugging, + * but remove this for production servers that should log as well. + * + * Uncomment this macro to report all debug messages on errors introducing + * a timing side-channel. + * + */ +//#define MBEDTLS_SSL_DEBUG_ALL + +/** \def MBEDTLS_SSL_ENCRYPT_THEN_MAC + * + * Enable support for Encrypt-then-MAC, RFC 7366. + * + * This allows peers that both support it to use a more robust protection for + * ciphersuites using CBC, providing deep resistance against timing attacks + * on the padding or underlying cipher. + * + * This only affects CBC ciphersuites, and is useless if none is defined. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Encrypt-then-MAC + */ +#define MBEDTLS_SSL_ENCRYPT_THEN_MAC + +/** \def MBEDTLS_SSL_EXTENDED_MASTER_SECRET + * + * Enable support for Extended Master Secret, aka Session Hash + * (draft-ietf-tls-session-hash-02). + * + * This was introduced as "the proper fix" to the Triple Handshake familiy of + * attacks, but it is recommended to always use it (even if you disable + * renegotiation), since it actually fixes a more fundamental issue in the + * original SSL/TLS design, and has implications beyond Triple Handshake. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1 or + * MBEDTLS_SSL_PROTO_TLS1_1 or + * MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for Extended Master Secret. + */ +#define MBEDTLS_SSL_EXTENDED_MASTER_SECRET + +/** + * \def MBEDTLS_SSL_FALLBACK_SCSV + * + * Enable support for FALLBACK_SCSV (draft-ietf-tls-downgrade-scsv-00). + * + * For servers, it is recommended to always enable this, unless you support + * only one version of TLS, or know for sure that none of your clients + * implements a fallback strategy. + * + * For clients, you only need this if you're using a fallback strategy, which + * is not recommended in the first place, unless you absolutely need it to + * interoperate with buggy (version-intolerant) servers. + * + * Comment this macro to disable support for FALLBACK_SCSV + */ +#define MBEDTLS_SSL_FALLBACK_SCSV + +/** + * \def MBEDTLS_SSL_HW_RECORD_ACCEL + * + * Enable hooking functions in SSL module for hardware acceleration of + * individual records. + * + * Uncomment this macro to enable hooking functions. + */ +//#define MBEDTLS_SSL_HW_RECORD_ACCEL + +/** + * \def MBEDTLS_SSL_CBC_RECORD_SPLITTING + * + * Enable 1/n-1 record splitting for CBC mode in SSLv3 and TLS 1.0. + * + * This is a countermeasure to the BEAST attack, which also minimizes the risk + * of interoperability issues compared to sending 0-length records. + * + * Comment this macro to disable 1/n-1 record splitting. + */ +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING + +/** + * \def MBEDTLS_SSL_RENEGOTIATION + * + * Disable support for TLS renegotiation. + * + * The two main uses of renegotiation are (1) refresh keys on long-lived + * connections and (2) client authentication after the initial handshake. + * If you don't need renegotiation, it's probably better to disable it, since + * it has been associated with security issues in the past and is easy to + * misuse/misunderstand. + * + * Comment this to disable support for renegotiation. + */ +#define MBEDTLS_SSL_RENEGOTIATION + +/** + * \def MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + * + * Enable support for receiving and parsing SSLv2 Client Hello messages for the + * SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to enable support for SSLv2 Client Hello messages. + */ +//#define MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + +/** + * \def MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + * + * Pick the ciphersuite according to the client's preferences rather than ours + * in the SSL Server module (MBEDTLS_SSL_SRV_C). + * + * Uncomment this macro to respect client's ciphersuite order + */ +//#define MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE + +/** + * \def MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + * + * Enable support for RFC 6066 max_fragment_length extension in SSL. + * + * Comment this macro to disable support for the max_fragment_length extension + */ +#define MBEDTLS_SSL_MAX_FRAGMENT_LENGTH + +/** + * \def MBEDTLS_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +//#define MBEDTLS_SSL_PROTO_SSL3 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1 (and DTLS 1.0 if DTLS is enabled). + * + * Requires: MBEDTLS_MD5_C + * MBEDTLS_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 / DTLS 1.0 + */ +#define MBEDTLS_SSL_PROTO_TLS1_1 + +/** + * \def MBEDTLS_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2 (and DTLS 1.2 if DTLS is enabled). + * + * Requires: MBEDTLS_SHA1_C or MBEDTLS_SHA256_C or MBEDTLS_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 / DTLS 1.2 + */ +#define MBEDTLS_SSL_PROTO_TLS1_2 + +/** + * \def MBEDTLS_SSL_PROTO_DTLS + * + * Enable support for DTLS (all available versions). + * + * Enable this and MBEDTLS_SSL_PROTO_TLS1_1 to enable DTLS 1.0, + * and/or this and MBEDTLS_SSL_PROTO_TLS1_2 to enable DTLS 1.2. + * + * Requires: MBEDTLS_SSL_PROTO_TLS1_1 + * or MBEDTLS_SSL_PROTO_TLS1_2 + * + * Comment this macro to disable support for DTLS + */ +#define MBEDTLS_SSL_PROTO_DTLS + +/** + * \def MBEDTLS_SSL_ALPN + * + * Enable support for RFC 7301 Application Layer Protocol Negotiation. + * + * Comment this macro to disable support for ALPN. + */ +#define MBEDTLS_SSL_ALPN + +/** + * \def MBEDTLS_SSL_DTLS_ANTI_REPLAY + * + * Enable support for the anti-replay mechanism in DTLS. + * + * Requires: MBEDTLS_SSL_TLS_C + * MBEDTLS_SSL_PROTO_DTLS + * + * \warning Disabling this is often a security risk! + * See mbedtls_ssl_conf_dtls_anti_replay() for details. + * + * Comment this to disable anti-replay in DTLS. + */ +#define MBEDTLS_SSL_DTLS_ANTI_REPLAY + +/** + * \def MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Enable support for HelloVerifyRequest on DTLS servers. + * + * This feature is highly recommended to prevent DTLS servers being used as + * amplifiers in DoS attacks against other hosts. It should always be enabled + * unless you know for sure amplification cannot be a problem in the + * environment in which your server operates. + * + * \warning Disabling this can ba a security risk! (see above) + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + * + * Comment this to disable support for HelloVerifyRequest. + */ +#define MBEDTLS_SSL_DTLS_HELLO_VERIFY + +/** + * \def MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + * + * Enable server-side support for clients that reconnect from the same port. + * + * Some clients unexpectedly close the connection and try to reconnect using the + * same source port. This needs special support from the server to handle the + * new connection securely, as described in section 4.2.8 of RFC 6347. This + * flag enables that support. + * + * Requires: MBEDTLS_SSL_DTLS_HELLO_VERIFY + * + * Comment this to disable support for clients reusing the source port. + */ +#define MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE + +/** + * \def MBEDTLS_SSL_DTLS_BADMAC_LIMIT + * + * Enable support for a limit of records with bad MAC. + * + * See mbedtls_ssl_conf_dtls_badmac_limit(). + * + * Requires: MBEDTLS_SSL_PROTO_DTLS + */ +#define MBEDTLS_SSL_DTLS_BADMAC_LIMIT + +/** + * \def MBEDTLS_SSL_SESSION_TICKETS + * + * Enable support for RFC 5077 session tickets in SSL. + * Client-side, provides full support for session tickets (maintainance of a + * session store remains the responsibility of the application, though). + * Server-side, you also need to provide callbacks for writing and parsing + * tickets, including authenticated encryption and key management. Example + * callbacks are provided by MBEDTLS_SSL_TICKET_C. + * + * Comment this macro to disable support for SSL session tickets + */ +#define MBEDTLS_SSL_SESSION_TICKETS + +/** + * \def MBEDTLS_SSL_EXPORT_KEYS + * + * Enable support for exporting key block and master secret. + * This is required for certain users of TLS, e.g. EAP-TLS. + * + * Comment this macro to disable support for key export + */ +#define MBEDTLS_SSL_EXPORT_KEYS + +/** + * \def MBEDTLS_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Requires: MBEDTLS_X509_CRT_PARSE_C + * + * Comment this macro to disable support for server name indication in SSL + */ +#define MBEDTLS_SSL_SERVER_NAME_INDICATION + +/** + * \def MBEDTLS_SSL_TRUNCATED_HMAC + * + * Enable support for RFC 6066 truncated HMAC in SSL. + * + * Comment this macro to disable support for truncated HMAC in SSL + */ +#define MBEDTLS_SSL_TRUNCATED_HMAC + +/** + * \def MBEDTLS_THREADING_ALT + * + * Provide your own alternate threading implementation. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to allow your own alternate threading implementation. + */ +#ifdef NCBI_THREADS +# define MBEDTLS_THREADING_ALT +#endif + +/** + * \def MBEDTLS_THREADING_PTHREAD + * + * Enable the pthread wrapper layer for the threading layer. + * + * Requires: MBEDTLS_THREADING_C + * + * Uncomment this to enable pthread mutexes. + */ +//#define MBEDTLS_THREADING_PTHREAD + +/** + * \def MBEDTLS_VERSION_FEATURES + * + * Allow run-time checking of compile-time enabled features. Thus allowing users + * to check at run-time if the library is for instance compiled with threading + * support via mbedtls_version_check_feature(). + * + * Requires: MBEDTLS_VERSION_C + * + * Comment this to disable run-time checking and save ROM space + */ +#define MBEDTLS_VERSION_FEATURES + +/** + * \def MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an extension in a v1 or v2 certificate. + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 + +/** + * \def MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an unknown critical extension. + * + * \warning Depending on your PKI use, enabling this can be a security risk! + * + * Uncomment to prevent an error. + */ +//#define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + +/** + * \def MBEDTLS_X509_CHECK_KEY_USAGE + * + * Enable verification of the keyUsage extension (CA and leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused + * (intermediate) CA and leaf certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip keyUsage checking for both CA and leaf certificates. + */ +#define MBEDTLS_X509_CHECK_KEY_USAGE + +/** + * \def MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + * + * Enable verification of the extendedKeyUsage extension (leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip extendedKeyUsage checking for certificates. + */ +#define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE + +/** + * \def MBEDTLS_X509_RSASSA_PSS_SUPPORT + * + * Enable parsing and verification of X.509 certificates, CRLs and CSRS + * signed with RSASSA-PSS (aka PKCS#1 v2.1). + * + * Comment this macro to disallow using RSASSA-PSS in certificates. + */ +#define MBEDTLS_X509_RSASSA_PSS_SUPPORT + +/** + * \def MBEDTLS_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * \warning TLS-level compression MAY REDUCE SECURITY! See for example the + * CRIME attack. Before enabling this option, you should examine with care if + * CRIME or similar exploits may be a applicable to your use case. + * + * \note Currently compression can't be used with DTLS. + * + * Used in: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This feature requires zlib library and headers to be present. + * + * Uncomment to enable use of ZLIB + */ +#if defined(HAVE_LIBZ) && 0 +# define MBEDTLS_ZLIB_SUPPORT +#endif +/* \} name SECTION: mbed TLS feature support */ + +/** + * \name SECTION: mbed TLS modules + * + * This section enables or disables entire modules in mbed TLS + * \{ + */ + +/** + * \def MBEDTLS_AESNI_C + * + * Enable AES-NI support on x86-64. + * + * Module: library/aesni.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the AES-NI instructions on x86-64 + */ +#define MBEDTLS_AESNI_C + +/** + * \def MBEDTLS_AES_C + * + * Enable the AES block cipher. + * + * Module: library/aes.c + * Caller: library/ssl_tls.c + * library/pem.c + * library/ctr_drbg.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA + * + * PEM_PARSE uses AES for decrypting encrypted keys. + */ +#define MBEDTLS_AES_C + +/** + * \def MBEDTLS_ARC4_C + * + * Enable the ARCFOUR stream cipher. + * + * Module: library/arc4.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_SHA + * MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 + * MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA + * MBEDTLS_TLS_PSK_WITH_RC4_128_SHA + */ +#define MBEDTLS_ARC4_C + +/** + * \def MBEDTLS_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define MBEDTLS_ASN1_PARSE_C + +/** + * \def MBEDTLS_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/x509write_csr.c + */ +#define MBEDTLS_ASN1_WRITE_C + +/** + * \def MBEDTLS_BASE64_C + * + * Enable the Base64 module. + * + * Module: library/base64.c + * Caller: library/pem.c + * + * This module is required for PEM support (required by X.509). + */ +#define MBEDTLS_BASE64_C + +/** + * \def MBEDTLS_BIGNUM_C + * + * Enable the multi-precision integer library. + * + * Module: library/bignum.c + * Caller: library/dhm.c + * library/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) support. + */ +#define MBEDTLS_BIGNUM_C + +/** + * \def MBEDTLS_BLOWFISH_C + * + * Enable the Blowfish block cipher. + * + * Module: library/blowfish.c + */ +#define MBEDTLS_BLOWFISH_C + +/** + * \def MBEDTLS_CAMELLIA_C + * + * Enable the Camellia block cipher. + * + * Module: library/camellia.c + * Caller: library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + */ +#define MBEDTLS_CAMELLIA_C + +/** + * \def MBEDTLS_CCM_C + * + * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher. + * + * Module: library/ccm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-CCM ciphersuites, if other requisites are + * enabled as well. + */ +#define MBEDTLS_CCM_C + +/** + * \def MBEDTLS_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * This module is used for testing (ssl_client/server). + */ +#define MBEDTLS_CERTS_C + +/** + * \def MBEDTLS_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * Uncomment to enable generic cipher wrappers. + */ +#define MBEDTLS_CIPHER_C + +/** + * \def MBEDTLS_CMAC_C + * + * Enable the CMAC (Cipher-based Message Authentication Code) mode for block + * ciphers. + * + * Module: library/cmac.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_DES_C + * + */ +//#define MBEDTLS_CMAC_C + +/** + * \def MBEDTLS_CTR_DRBG_C + * + * Enable the CTR_DRBG AES-256-based random generator. + * + * Module: library/ctr_drbg.c + * Caller: + * + * Requires: MBEDTLS_AES_C + * + * This module provides the CTR_DRBG AES-256 random number generator. + */ +#define MBEDTLS_CTR_DRBG_C + +/** + * \def MBEDTLS_DEBUG_C + * + * Enable the debug functions. + * + * Module: library/debug.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module provides debugging functions. + */ +#define MBEDTLS_DEBUG_C + +/** + * \def MBEDTLS_DES_C + * + * Enable the DES block cipher. + * + * Module: library/des.c + * Caller: library/pem.c + * library/ssl_tls.c + * + * This module enables the following ciphersuites (if other requisites are + * enabled as well): + * MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA + * + * PEM_PARSE uses DES/3DES for decrypting encrypted keys. + */ +#define MBEDTLS_DES_C + +/** + * \def MBEDTLS_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + */ +#define MBEDTLS_DHM_C + +/** + * \def MBEDTLS_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: MBEDTLS_ECP_C + */ +#define MBEDTLS_ECDH_C + +/** + * \def MBEDTLS_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_ASN1_WRITE_C, MBEDTLS_ASN1_PARSE_C + */ +#define MBEDTLS_ECDSA_C + +/** + * \def MBEDTLS_ECJPAKE_C + * + * Enable the elliptic curve J-PAKE library. + * + * \warning This is currently experimental. EC J-PAKE support is based on the + * Thread v1.0.0 specification; incompatible changes to the specification + * might still happen. For this reason, this is disabled by default. + * + * Module: library/ecjpake.c + * Caller: + * + * This module is used by the following key exchanges: + * ECJPAKE + * + * Requires: MBEDTLS_ECP_C, MBEDTLS_MD_C + */ +//#define MBEDTLS_ECJPAKE_C + +/** + * \def MBEDTLS_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * library/ecjpake.c + * + * Requires: MBEDTLS_BIGNUM_C and at least one MBEDTLS_ECP_DP_XXX_ENABLED + */ +#define MBEDTLS_ECP_C + +/** + * \def MBEDTLS_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: MBEDTLS_SHA512_C or MBEDTLS_SHA256_C + * + * This module provides a generic entropy pool + */ +#define MBEDTLS_ENTROPY_C + +/** + * \def MBEDTLS_ERROR_C + * + * Enable error code to error string conversion. + * + * Module: library/error.c + * Caller: + * + * This module enables mbedtls_strerror(). + */ +#define MBEDTLS_ERROR_C + +/** + * \def MBEDTLS_GCM_C + * + * Enable the Galois/Counter Mode (GCM) for AES. + * + * Module: library/gcm.c + * + * Requires: MBEDTLS_AES_C or MBEDTLS_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +#define MBEDTLS_GCM_C + +/** + * \def MBEDTLS_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Warning: the HAVEGE random generator is not suitable for virtualized + * environments + * + * Warning: the HAVEGE random generator is dependent on timing and specific + * processor traits. It is therefore not advised to use HAVEGE as + * your applications primary random generator or primary entropy pool + * input. As a secondary input to your entropy pool, it IS able add + * the (limited) extra entropy it provides. + * + * Module: library/havege.c + * Caller: + * + * Requires: MBEDTLS_TIMING_C + * + * Uncomment to enable the HAVEGE random generator. + */ +//#define MBEDTLS_HAVEGE_C + +/** + * \def MBEDTLS_HMAC_DRBG_C + * + * Enable the HMAC_DRBG random generator. + * + * Module: library/hmac_drbg.c + * Caller: + * + * Requires: MBEDTLS_MD_C + * + * Uncomment to enable the HMAC_DRBG random number geerator. + */ +#define MBEDTLS_HMAC_DRBG_C + +/** + * \def MBEDTLS_MD_C + * + * Enable the generic message digest layer. + * + * Module: library/md.c + * Caller: + * + * Uncomment to enable generic message digest wrappers. + */ +#define MBEDTLS_MD_C + +/** + * \def MBEDTLS_MD2_C + * + * Enable the MD2 hash algorithm. + * + * Module: library/md2.c + * Caller: + * + * Uncomment to enable support for (rare) MD2-signed X.509 certs. + */ +//#define MBEDTLS_MD2_C + +/** + * \def MBEDTLS_MD4_C + * + * Enable the MD4 hash algorithm. + * + * Module: library/md4.c + * Caller: + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + */ +//#define MBEDTLS_MD4_C + +/** + * \def MBEDTLS_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/md5.c + * Caller: library/md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS and X.509. + * PEM_PARSE uses MD5 for decrypting encrypted keys. + */ +#define MBEDTLS_MD5_C + +/** + * \def MBEDTLS_MEMORY_BUFFER_ALLOC_C + * + * Enable the buffer allocator implementation that makes use of a (stack) + * based buffer to 'allocate' dynamic memory. (replaces calloc() and free() + * calls) + * + * Module: library/memory_buffer_alloc.c + * + * Requires: MBEDTLS_PLATFORM_C + * MBEDTLS_PLATFORM_MEMORY (to use it within mbed TLS) + * + * Enable this module to enable the buffer memory allocator. + */ +//#define MBEDTLS_MEMORY_BUFFER_ALLOC_C + +/** + * \def MBEDTLS_NET_C + * + * Enable the TCP and UDP over IPv6/IPv4 networking routines. + * + * \note This module only works on POSIX/Unix (including Linux, BSD and OS X) + * and Windows. For other platforms, you'll want to disable it, and write your + * own networking callbacks to be passed to \c mbedtls_ssl_set_bio(). + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * + * Module: library/net_sockets.c + * + * This module provides networking routines. + */ +#define MBEDTLS_NET_C + +/** + * \def MBEDTLS_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define MBEDTLS_OID_C + +/** + * \def MBEDTLS_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * Requires: MBEDTLS_HAVE_ASM + * + * This modules adds support for the VIA PadLock on x86. + */ +#define MBEDTLS_PADLOCK_C + +/** + * \def MBEDTLS_PEM_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +#define MBEDTLS_PEM_PARSE_C + +/** + * \def MBEDTLS_PEM_WRITE_C + * + * Enable PEM encoding / writing. + * + * Module: library/pem.c + * Caller: library/pkwrite.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * Requires: MBEDTLS_BASE64_C + * + * This modules adds support for encoding / writing PEM files. + */ +#define MBEDTLS_PEM_WRITE_C + +/** + * \def MBEDTLS_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_RSA_C or MBEDTLS_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define MBEDTLS_PK_C + +/** + * \def MBEDTLS_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define MBEDTLS_PK_PARSE_C + +/** + * \def MBEDTLS_PK_WRITE_C + * + * Enable the generic public (asymetric) key writer. + * + * Module: library/pkwrite.c + * Caller: library/x509write.c + * + * Requires: MBEDTLS_PK_C + * + * Uncomment to enable generic public key write functions. + */ +#define MBEDTLS_PK_WRITE_C + +/** + * \def MBEDTLS_PKCS5_C + * + * Enable PKCS#5 functions. + * + * Module: library/pkcs5.c + * + * Requires: MBEDTLS_MD_C + * + * This module adds support for the PKCS#5 functions. + */ +#define MBEDTLS_PKCS5_C + +/** + * \def MBEDTLS_PKCS11_C + * + * Enable wrapper for PKCS#11 smartcard support. + * + * Module: library/pkcs11.c + * Caller: library/pk.c + * + * Requires: MBEDTLS_PK_C + * + * This module enables SSL/TLS PKCS #11 smartcard support. + * Requires the presence of the PKCS#11 helper library (libpkcs11-helper) + */ +//#define MBEDTLS_PKCS11_C + +/** + * \def MBEDTLS_PKCS12_C + * + * Enable PKCS#12 PBE functions. + * Adds algorithms for parsing PKCS#8 encrypted private keys + * + * Module: library/pkcs12.c + * Caller: library/pkparse.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * Can use: MBEDTLS_ARC4_C + * + * This module enables PKCS#12 functions. + */ +#define MBEDTLS_PKCS12_C + +/** + * \def MBEDTLS_PLATFORM_C + * + * Enable the platform abstraction layer that allows you to re-assign + * functions like calloc(), free(), snprintf(), printf(), fprintf(), exit(). + * + * Enabling MBEDTLS_PLATFORM_C enables to use of MBEDTLS_PLATFORM_XXX_ALT + * or MBEDTLS_PLATFORM_XXX_MACRO directives, allowing the functions mentioned + * above to be specified at runtime or compile time respectively. + * + * \note This abstraction layer must be enabled on Windows (including MSYS2) + * as other module rely on it for a fixed snprintf implementation. + * + * Module: library/platform.c + * Caller: Most other .c files + * + * This module enables abstraction of common (libc) functions. + */ +#define MBEDTLS_PLATFORM_C + +/** + * \def MBEDTLS_RIPEMD160_C + * + * Enable the RIPEMD-160 hash algorithm. + * + * Module: library/ripemd160.c + * Caller: library/md.c + * + */ +#define MBEDTLS_RIPEMD160_C + +/** + * \def MBEDTLS_RSA_C + * + * Enable the RSA public-key cryptosystem. + * + * Module: library/rsa.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509.c + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C + */ +#define MBEDTLS_RSA_C + +/** + * \def MBEDTLS_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/sha1.c + * Caller: library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define MBEDTLS_SHA1_C + +/** + * \def MBEDTLS_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * + * Module: library/sha256.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * This module adds support for SHA-224 and SHA-256. + * This module is required for the SSL/TLS 1.2 PRF function. + */ +#define MBEDTLS_SHA256_C + +/** + * \def MBEDTLS_SHA512_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * + * Module: library/sha512.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This module adds support for SHA-384 and SHA-512. + */ +#define MBEDTLS_SHA512_C + +/** + * \def MBEDTLS_SSL_CACHE_C + * + * Enable simple SSL cache implementation. + * + * Module: library/ssl_cache.c + * Caller: + * + * Requires: MBEDTLS_SSL_CACHE_C + */ +#define MBEDTLS_SSL_CACHE_C + +/** + * \def MBEDTLS_SSL_COOKIE_C + * + * Enable basic implementation of DTLS cookies for hello verification. + * + * Module: library/ssl_cookie.c + * Caller: + */ +#define MBEDTLS_SSL_COOKIE_C + +/** + * \def MBEDTLS_SSL_TICKET_C + * + * Enable an implementation of TLS server-side callbacks for session tickets. + * + * Module: library/ssl_ticket.c + * Caller: + * + * Requires: MBEDTLS_CIPHER_C + */ +#define MBEDTLS_SSL_TICKET_C + +/** + * \def MBEDTLS_SSL_CLI_C + * + * Enable the SSL/TLS client code. + * + * Module: library/ssl_cli.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS client support. + */ +#define MBEDTLS_SSL_CLI_C + +/** + * \def MBEDTLS_SSL_SRV_C + * + * Enable the SSL/TLS server code. + * + * Module: library/ssl_srv.c + * Caller: + * + * Requires: MBEDTLS_SSL_TLS_C + * + * This module is required for SSL/TLS server support. + */ +#define MBEDTLS_SSL_SRV_C + +/** + * \def MBEDTLS_SSL_TLS_C + * + * Enable the generic SSL/TLS code. + * + * Module: library/ssl_tls.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: MBEDTLS_CIPHER_C, MBEDTLS_MD_C + * and at least one of the MBEDTLS_SSL_PROTO_XXX defines + * + * This module is required for SSL/TLS. + */ +#define MBEDTLS_SSL_TLS_C + +/** + * \def MBEDTLS_THREADING_C + * + * Enable the threading abstraction layer. + * By default mbed TLS assumes it is used in a non-threaded environment or that + * contexts are not shared between threads. If you do intend to use contexts + * between threads, you will need to enable this layer to prevent race + * conditions. See also our Knowledge Base article about threading: + * https://tls.mbed.org/kb/development/thread-safety-and-multi-threading + * + * Module: library/threading.c + * + * This allows different threading implementations (self-implemented or + * provided). + * + * You will have to enable either MBEDTLS_THREADING_ALT or + * MBEDTLS_THREADING_PTHREAD. + * + * Enable this layer to allow use of mutexes within mbed TLS + */ +#if defined(MBEDTLS_THREADING_ALT) || defined(MBEDTLS_THREADING_PTHREAD) +# define MBEDTLS_THREADING_C +#endif + +/** + * \def MBEDTLS_TIMING_C + * + * Enable the semi-portable timing interface. + * + * \note The provided implementation only works on POSIX/Unix (including Linux, + * BSD and OS X) and Windows. On other platforms, you can either disable that + * module and provide your own implementations of the callbacks needed by + * \c mbedtls_ssl_set_timer_cb() for DTLS, or leave it enabled and provide + * your own implementation of the whole module by setting + * \c MBEDTLS_TIMING_ALT in the current file. + * + * \note See also our Knowledge Base article about porting to a new + * environment: + * https://tls.mbed.org/kb/how-to/how-do-i-port-mbed-tls-to-a-new-environment-OS + * + * Module: library/timing.c + * Caller: library/havege.c + * + * This module is used by the HAVEGE random number generator. + */ +#define MBEDTLS_TIMING_C + +/** + * \def MBEDTLS_VERSION_C + * + * Enable run-time version information. + * + * Module: library/version.c + * + * This module provides run-time version information. + */ +#define MBEDTLS_VERSION_C + +/** + * \def MBEDTLS_X509_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: MBEDTLS_ASN1_PARSE_C, MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, + * MBEDTLS_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define MBEDTLS_X509_USE_C + +/** + * \def MBEDTLS_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define MBEDTLS_X509_CRT_PARSE_C + +/** + * \def MBEDTLS_X509_CRL_PARSE_C + * + * Enable X.509 CRL parsing. + * + * Module: library/x509_crl.c + * Caller: library/x509_crt.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is required for X.509 CRL parsing. + */ +#define MBEDTLS_X509_CRL_PARSE_C + +/** + * \def MBEDTLS_X509_CSR_PARSE_C + * + * Enable X.509 Certificate Signing Request (CSR) parsing. + * + * Module: library/x509_csr.c + * Caller: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_USE_C + * + * This module is used for reading X.509 certificate request. + */ +#define MBEDTLS_X509_CSR_PARSE_C + +/** + * \def MBEDTLS_X509_CREATE_C + * + * Enable X.509 core for creating certificates. + * + * Module: library/x509_create.c + * + * Requires: MBEDTLS_BIGNUM_C, MBEDTLS_OID_C, MBEDTLS_PK_WRITE_C + * + * This module is the basis for creating X.509 certificates and CSRs. + */ +#define MBEDTLS_X509_CREATE_C + +/** + * \def MBEDTLS_X509_CRT_WRITE_C + * + * Enable creating X.509 certificates. + * + * Module: library/x509_crt_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate creation. + */ +#define MBEDTLS_X509_CRT_WRITE_C + +/** + * \def MBEDTLS_X509_CSR_WRITE_C + * + * Enable creating X.509 Certificate Signing Requests (CSR). + * + * Module: library/x509_csr_write.c + * + * Requires: MBEDTLS_X509_CREATE_C + * + * This module is required for X.509 certificate request writing. + */ +#define MBEDTLS_X509_CSR_WRITE_C + +/** + * \def MBEDTLS_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +#define MBEDTLS_XTEA_C + +/* \} name SECTION: mbed TLS modules */ + +/** + * \name SECTION: Module configuration options + * + * This section allows for the setting of module specific sizes and + * configuration options. The default values are already present in the + * relevant header files and should suffice for the regular use cases. + * + * Our advice is to enable options and change their values here + * only if you have a good reason and know the consequences. + * + * Please check the respective header file for documentation on these + * parameters (to prevent duplicate documentation). + * \{ + */ + +/* MPI / BIGNUM options */ +//#define MBEDTLS_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +//#define MBEDTLS_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ + +/* CTR_DRBG options */ +//#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +//#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* HMAC_DRBG options */ +//#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* ECP options */ +//#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +//#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +//#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ + +/* Entropy options */ +//#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +//#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +//#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Default minimum number of bytes required for the hardware entropy source mbedtls_hardware_poll() before entropy is released */ + +/* Memory buffer allocator options */ +//#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ + +/* Platform options */ +//#define MBEDTLS_PLATFORM_STD_MEM_HDR /**< Header to include if MBEDTLS_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ +//#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS 0 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE 1 /**< Default exit value to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" /**< Seed file to read/write with default implementation */ + +/* To Use Function Macros MBEDTLS_PLATFORM_C must be enabled */ +/* MBEDTLS_PLATFORM_XXX_MACRO and MBEDTLS_PLATFORM_XXX_ALT cannot both be defined */ +//#define MBEDTLS_PLATFORM_CALLOC_MACRO calloc /**< Default allocator macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_FREE_MACRO free /**< Default free macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_EXIT_MACRO exit /**< Default exit macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_TIME_MACRO time /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_TIME_TYPE_MACRO time_t /**< Default time macro to use, can be undefined. MBEDTLS_HAVE_TIME must be enabled */ +//#define MBEDTLS_PLATFORM_FPRINTF_MACRO fprintf /**< Default fprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_PRINTF_MACRO printf /**< Default printf macro to use, can be undefined */ +/* Note: your snprintf must correclty zero-terminate the buffer! */ +//#define MBEDTLS_PLATFORM_SNPRINTF_MACRO snprintf /**< Default snprintf macro to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_READ_MACRO mbedtls_platform_std_nv_seed_read /**< Default nv_seed_read function to use, can be undefined */ +//#define MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO mbedtls_platform_std_nv_seed_write /**< Default nv_seed_write function to use, can be undefined */ + +/* SSL Cache options */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +//#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +/* SSL options */ +//#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 /**< Maxium fragment length in bytes, determines the size of each of the two internal I/O buffers */ +//#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define MBEDTLS_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ +//#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ + +/** + * Complete list of ciphersuites to use, in order of preference. + * + * \warning No dependency checking is done on that field! This option can only + * be used to restrict the set of available ciphersuites. It is your + * responsibility to make sure the needed modules are active. + * + * Use this to save a few hundred bytes of ROM (default ordering of all + * available ciphersuites) and a few to a few hundred bytes of RAM. + * + * The value below is only an example, not the default. + */ +//#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + +/* X509 options */ +//#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 /**< Maximum number of intermediate CAs in a verification chain. */ +//#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 /**< Maximum length of a path/filename string in bytes including the null terminator character ('\0'). */ + +/* \} name SECTION: Customisation configuration options */ + +/* Target and application specific configurations */ +//#define YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE "mbedtls/target_config.h" + +#if defined(TARGET_LIKE_MBED) && defined(YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE) +#include YOTTA_CFG_MBEDTLS_TARGET_CONFIG_FILE +#endif + +/* + * Allow user to override any previous default. + * + * Use two macro names for that, as: + * - with yotta the prefix YOTTA_CFG_ is forced + * - without yotta is looks weird to have a YOTTA prefix. + */ +#if defined(YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE) +#include YOTTA_CFG_MBEDTLS_USER_CONFIG_FILE +#elif defined(MBEDTLS_USER_CONFIG_FILE) +#include MBEDTLS_USER_CONFIG_FILE +#endif + +#include "check_config.h" + +#include "ncbicxx_rename_mbedtls.h" + +#endif /* MBEDTLS_CONFIG_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/ctr_drbg.h b/c++/src/connect/mbedtls/mbedtls/ctr_drbg.h new file mode 100644 index 00000000..f3e9d096 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ctr_drbg.h @@ -0,0 +1,290 @@ +/** + * \file ctr_drbg.h + * + * \brief CTR_DRBG based on AES-256 (NIST SP 800-90) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_CTR_DRBG_H +#define MBEDTLS_CTR_DRBG_H + +#include "aes.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +#define MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED -0x0034 /**< The entropy source failed. */ +#define MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG -0x0036 /**< Too many random requested in single call. */ +#define MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG -0x0038 /**< Input too large (Entropy + additional). */ +#define MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR -0x003A /**< Read/write error in file. */ + +#define MBEDTLS_CTR_DRBG_BLOCKSIZE 16 /**< Block size used by the cipher */ +#define MBEDTLS_CTR_DRBG_KEYSIZE 32 /**< Key size used by the cipher */ +#define MBEDTLS_CTR_DRBG_KEYBITS ( MBEDTLS_CTR_DRBG_KEYSIZE * 8 ) +#define MBEDTLS_CTR_DRBG_SEEDLEN ( MBEDTLS_CTR_DRBG_KEYSIZE + MBEDTLS_CTR_DRBG_BLOCKSIZE ) + /**< The seed length (counter + AES key) */ + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_CTR_DRBG_ENTROPY_LEN) +#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) +#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +#else +#define MBEDTLS_CTR_DRBG_ENTROPY_LEN 32 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +#endif +#endif + +#if !defined(MBEDTLS_CTR_DRBG_RESEED_INTERVAL) +#define MBEDTLS_CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_INPUT) +#define MBEDTLS_CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_REQUEST) +#define MBEDTLS_CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#endif + +#if !defined(MBEDTLS_CTR_DRBG_MAX_SEED_INPUT) +#define MBEDTLS_CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ +#endif + +/* \} name SECTION: Module settings */ + +#define MBEDTLS_CTR_DRBG_PR_OFF 0 /**< No prediction resistance */ +#define MBEDTLS_CTR_DRBG_PR_ON 1 /**< Prediction resistance enabled */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief CTR_DRBG context structure + */ +typedef struct +{ + unsigned char counter[16]; /*!< counter (V) */ + int reseed_counter; /*!< reseed counter */ + int prediction_resistance; /*!< enable prediction resistance (Automatic + reseed before every random generation) */ + size_t entropy_len; /*!< amount of entropy grabbed on each + (re)seed */ + int reseed_interval; /*!< reseed interval */ + + mbedtls_aes_context aes_ctx; /*!< AES context */ + + /* + * Callbacks (Entropy) + */ + int (*f_entropy)(void *, unsigned char *, size_t); + + void *p_entropy; /*!< context for the entropy function */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} +mbedtls_ctr_drbg_context; + +/** + * \brief CTR_DRBG context initialization + * Makes the context ready for mbedtls_ctr_drbg_seed() or + * mbedtls_ctr_drbg_free(). + * + * \param ctx CTR_DRBG context to be initialized + */ +void mbedtls_ctr_drbg_init( mbedtls_ctr_drbg_context *ctx ); + +/** + * \brief CTR_DRBG initial seeding + * Seed and setup entropy source for future reseeds. + * + * Note: Personalization data can be provided in addition to the more generic + * entropy source to make this instantiation as unique as possible. + * + * \param ctx CTR_DRBG context to be seeded + * \param f_entropy Entropy callback (p_entropy, buffer to fill, buffer + * length) + * \param p_entropy Entropy context + * \param custom Personalization data (Device specific identifiers) + * (Can be NULL) + * \param len Length of personalization data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_ctr_drbg_seed( mbedtls_ctr_drbg_context *ctx, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ); + +/** + * \brief Clear CTR_CRBG context data + * + * \param ctx CTR_DRBG context to clear + */ +void mbedtls_ctr_drbg_free( mbedtls_ctr_drbg_context *ctx ); + +/** + * \brief Enable / disable prediction resistance (Default: Off) + * + * Note: If enabled, entropy is used for ctx->entropy_len before each call! + * Only use this if you have ample supply of good entropy! + * + * \param ctx CTR_DRBG context + * \param resistance MBEDTLS_CTR_DRBG_PR_ON or MBEDTLS_CTR_DRBG_PR_OFF + */ +void mbedtls_ctr_drbg_set_prediction_resistance( mbedtls_ctr_drbg_context *ctx, + int resistance ); + +/** + * \brief Set the amount of entropy grabbed on each (re)seed + * (Default: MBEDTLS_CTR_DRBG_ENTROPY_LEN) + * + * \param ctx CTR_DRBG context + * \param len Amount of entropy to grab + */ +void mbedtls_ctr_drbg_set_entropy_len( mbedtls_ctr_drbg_context *ctx, + size_t len ); + +/** + * \brief Set the reseed interval + * (Default: MBEDTLS_CTR_DRBG_RESEED_INTERVAL) + * + * \param ctx CTR_DRBG context + * \param interval Reseed interval + */ +void mbedtls_ctr_drbg_set_reseed_interval( mbedtls_ctr_drbg_context *ctx, + int interval ); + +/** + * \brief CTR_DRBG reseeding (extracts data from entropy source) + * + * \param ctx CTR_DRBG context + * \param additional Additional data to add to state (Can be NULL) + * \param len Length of additional data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_ctr_drbg_reseed( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t len ); + +/** + * \brief CTR_DRBG update state + * + * \param ctx CTR_DRBG context + * \param additional Additional data to update state with + * \param add_len Length of additional data + * + * \note If add_len is greater than MBEDTLS_CTR_DRBG_MAX_SEED_INPUT, + * only the first MBEDTLS_CTR_DRBG_MAX_SEED_INPUT bytes are used, + * the remaining ones are silently discarded. + */ +void mbedtls_ctr_drbg_update( mbedtls_ctr_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); + +/** + * \brief CTR_DRBG generate random with additional update input + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * \param additional Additional data to update with (Can be NULL) + * \param add_len Length of additional data + * + * \return 0 if successful, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int mbedtls_ctr_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, size_t add_len ); + +/** + * \brief CTR_DRBG generate random + * + * Note: Automatically reseeds if reseed_counter is reached. + * + * \param p_rng CTR_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * + * \return 0 if successful, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG + */ +int mbedtls_ctr_drbg_random( void *p_rng, + unsigned char *output, size_t output_len ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx CTR_DRBG context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error, or + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_ctr_drbg_write_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance + * + * \param ctx CTR_DRBG context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_CTR_DRBG_FILE_IO_ERROR on file error, + * MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or + * MBEDTLS_ERR_CTR_DRBG_INPUT_TOO_BIG + */ +int mbedtls_ctr_drbg_update_seed_file( mbedtls_ctr_drbg_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ctr_drbg_self_test( int verbose ); + +/* Internal functions (do not call directly) */ +int mbedtls_ctr_drbg_seed_entropy_len( mbedtls_ctr_drbg_context *, + int (*)(void *, unsigned char *, size_t), void *, + const unsigned char *, size_t, size_t ); + +#ifdef __cplusplus +} +#endif + +#endif /* ctr_drbg.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/debug.h b/c++/src/connect/mbedtls/mbedtls/debug.h new file mode 100644 index 00000000..29579964 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/debug.h @@ -0,0 +1,228 @@ +/** + * \file debug.h + * + * \brief Functions for controlling and providing debug output from the library. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_DEBUG_H +#define MBEDTLS_DEBUG_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ssl.h" + +#if defined(MBEDTLS_ECP_C) +#include "ecp.h" +#endif + +#if defined(MBEDTLS_DEBUG_C) + +#define MBEDTLS_DEBUG_STRIP_PARENS( ... ) __VA_ARGS__ + +#define MBEDTLS_SSL_DEBUG_MSG( level, args ) \ + mbedtls_debug_print_msg( ssl, level, __FILE__, __LINE__, \ + MBEDTLS_DEBUG_STRIP_PARENS args ) + +#define MBEDTLS_SSL_DEBUG_RET( level, text, ret ) \ + mbedtls_debug_print_ret( ssl, level, __FILE__, __LINE__, text, ret ) + +#define MBEDTLS_SSL_DEBUG_BUF( level, text, buf, len ) \ + mbedtls_debug_print_buf( ssl, level, __FILE__, __LINE__, text, buf, len ) + +#if defined(MBEDTLS_BIGNUM_C) +#define MBEDTLS_SSL_DEBUG_MPI( level, text, X ) \ + mbedtls_debug_print_mpi( ssl, level, __FILE__, __LINE__, text, X ) +#endif + +#if defined(MBEDTLS_ECP_C) +#define MBEDTLS_SSL_DEBUG_ECP( level, text, X ) \ + mbedtls_debug_print_ecp( ssl, level, __FILE__, __LINE__, text, X ) +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#define MBEDTLS_SSL_DEBUG_CRT( level, text, crt ) \ + mbedtls_debug_print_crt( ssl, level, __FILE__, __LINE__, text, crt ) +#endif + +#else /* MBEDTLS_DEBUG_C */ + +#define MBEDTLS_SSL_DEBUG_MSG( level, args ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_RET( level, text, ret ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_BUF( level, text, buf, len ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_MPI( level, text, X ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_ECP( level, text, X ) do { } while( 0 ) +#define MBEDTLS_SSL_DEBUG_CRT( level, text, crt ) do { } while( 0 ) + +#endif /* MBEDTLS_DEBUG_C */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Set the threshold error level to handle globally all debug output. + * Debug messages that have a level over the threshold value are + * discarded. + * (Default value: 0 = No debug ) + * + * \param threshold theshold level of messages to filter on. Messages at a + * higher level will be discarded. + * - Debug levels + * - 0 No debug + * - 1 Error + * - 2 State change + * - 3 Informational + * - 4 Verbose + */ +void mbedtls_debug_set_threshold( int threshold ); + +/** + * \brief Print a message to the debug output. This function is always used + * through the MBEDTLS_SSL_DEBUG_MSG() macro, which supplies the ssl + * context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the message has occurred in + * \param line line number the message has occurred at + * \param format format specifier, in printf format + * \param ... variables used by the format specifier + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_msg( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *format, ... ); + +/** + * \brief Print the return value of a function to the debug output. This + * function is always used through the MBEDTLS_SSL_DEBUG_RET() macro, + * which supplies the ssl context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param text the name of the function that returned the error + * \param ret the return code value + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_ret( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, int ret ); + +/** + * \brief Output a buffer of size len bytes to the debug output. This function + * is always used through the MBEDTLS_SSL_DEBUG_BUF() macro, + * which supplies the ssl context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param text a name or label for the buffer being dumped. Normally the + * variable or buffer name + * \param buf the buffer to be outputted + * \param len length of the buffer + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_buf( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, const char *text, + const unsigned char *buf, size_t len ); + +#if defined(MBEDTLS_BIGNUM_C) +/** + * \brief Print a MPI variable to the debug output. This function is always + * used through the MBEDTLS_SSL_DEBUG_MPI() macro, which supplies the + * ssl context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param text a name or label for the MPI being output. Normally the + * variable name + * \param X the MPI variable + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_mpi( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_mpi *X ); +#endif + +#if defined(MBEDTLS_ECP_C) +/** + * \brief Print an ECP point to the debug output. This function is always + * used through the MBEDTLS_SSL_DEBUG_ECP() macro, which supplies the + * ssl context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param text a name or label for the ECP point being output. Normally the + * variable name + * \param X the ECP point + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_ecp( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_ecp_point *X ); +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Print a X.509 certificate structure to the debug output. This + * function is always used through the MBEDTLS_SSL_DEBUG_CRT() macro, + * which supplies the ssl context, file and line number parameters. + * + * \param ssl SSL context + * \param level error level of the debug message + * \param file file the error has occurred in + * \param line line number the error has occurred in + * \param text a name or label for the certificate being output + * \param crt X.509 certificate structure + * + * \attention This function is intended for INTERNAL usage within the + * library only. + */ +void mbedtls_debug_print_crt( const mbedtls_ssl_context *ssl, int level, + const char *file, int line, + const char *text, const mbedtls_x509_crt *crt ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* debug.h */ + diff --git a/c++/src/connect/mbedtls/mbedtls/des.h b/c++/src/connect/mbedtls/mbedtls/des.h new file mode 100644 index 00000000..5ca2ecf2 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/des.h @@ -0,0 +1,306 @@ +/** + * \file des.h + * + * \brief DES block cipher + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_DES_H +#define MBEDTLS_DES_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_DES_ENCRYPT 1 +#define MBEDTLS_DES_DECRYPT 0 + +#define MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH -0x0032 /**< The data input has an invalid length. */ + +#define MBEDTLS_DES_KEY_SIZE 8 + +#if !defined(MBEDTLS_DES_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DES context structure + */ +typedef struct +{ + uint32_t sk[32]; /*!< DES subkeys */ +} +mbedtls_des_context; + +/** + * \brief Triple-DES context structure + */ +typedef struct +{ + uint32_t sk[96]; /*!< 3DES subkeys */ +} +mbedtls_des3_context; + +/** + * \brief Initialize DES context + * + * \param ctx DES context to be initialized + */ +void mbedtls_des_init( mbedtls_des_context *ctx ); + +/** + * \brief Clear DES context + * + * \param ctx DES context to be cleared + */ +void mbedtls_des_free( mbedtls_des_context *ctx ); + +/** + * \brief Initialize Triple-DES context + * + * \param ctx DES3 context to be initialized + */ +void mbedtls_des3_init( mbedtls_des3_context *ctx ); + +/** + * \brief Clear Triple-DES context + * + * \param ctx DES3 context to be cleared + */ +void mbedtls_des3_free( mbedtls_des3_context *ctx ); + +/** + * \brief Set key parity on the given key to odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + */ +void mbedtls_des_key_set_parity( unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Check that key parity on the given key is odd. + * + * DES keys are 56 bits long, but each byte is padded with + * a parity bit to allow verification. + * + * \param key 8-byte secret key + * + * \return 0 is parity was ok, 1 if parity was not correct. + */ +int mbedtls_des_key_check_key_parity( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Check that key is not a weak or semi-weak DES key + * + * \param key 8-byte secret key + * + * \return 0 if no weak key was found, 1 if a weak key was identified. + */ +int mbedtls_des_key_check_weak( const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, encryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int mbedtls_des_setkey_enc( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief DES key schedule (56-bit, decryption) + * + * \param ctx DES context to be initialized + * \param key 8-byte secret key + * + * \return 0 + */ +int mbedtls_des_setkey_dec( mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); + +/** + * \brief Triple-DES key schedule (112-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set2key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (112-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 16-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set2key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2] ); + +/** + * \brief Triple-DES key schedule (168-bit, encryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set3key_enc( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ); + +/** + * \brief Triple-DES key schedule (168-bit, decryption) + * + * \param ctx 3DES context to be initialized + * \param key 24-byte secret key + * + * \return 0 + */ +int mbedtls_des3_set3key_dec( mbedtls_des3_context *ctx, + const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3] ); + +/** + * \brief DES-ECB block encryption/decryption + * + * \param ctx DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int mbedtls_des_crypt_ecb( mbedtls_des_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief DES-CBC buffer encryption/decryption + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx DES context + * \param mode MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + */ +int mbedtls_des_crypt_cbc( mbedtls_des_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/** + * \brief 3DES-ECB block encryption/decryption + * + * \param ctx 3DES context + * \param input 64-bit input block + * \param output 64-bit output block + * + * \return 0 if successful + */ +int mbedtls_des3_crypt_ecb( mbedtls_des3_context *ctx, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief 3DES-CBC buffer encryption/decryption + * + * \note Upon exit, the content of the IV is updated so that you can + * call the function same function again on the following + * block(s) of data and get the same result as if it was + * encrypted in one call. This allows a "streaming" usage. + * If on the other hand you need to retain the contents of the + * IV, you should either save it manually or use the cipher + * module instead. + * + * \param ctx 3DES context + * \param mode MBEDTLS_DES_ENCRYPT or MBEDTLS_DES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if successful, or MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH + */ +int mbedtls_des3_crypt_cbc( mbedtls_des3_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output ); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +/** + * \brief Internal function for key expansion. + * (Only exposed to allow overriding it, + * see MBEDTLS_DES_SETKEY_ALT) + * + * \param SK Round keys + * \param key Base key + */ +void mbedtls_des_setkey( uint32_t SK[32], + const unsigned char key[MBEDTLS_DES_KEY_SIZE] ); +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_DES_ALT */ +#include "des_alt.h" +#endif /* MBEDTLS_DES_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_des_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* des.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/dhm.h b/c++/src/connect/mbedtls/mbedtls/dhm.h new file mode 100644 index 00000000..d7ab1522 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/dhm.h @@ -0,0 +1,305 @@ +/** + * \file dhm.h + * + * \brief Diffie-Hellman-Merkle key exchange + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_DHM_H +#define MBEDTLS_DHM_H + +#include "bignum.h" + +/* + * DHM Error codes + */ +#define MBEDTLS_ERR_DHM_BAD_INPUT_DATA -0x3080 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_DHM_READ_PARAMS_FAILED -0x3100 /**< Reading of the DHM parameters failed. */ +#define MBEDTLS_ERR_DHM_MAKE_PARAMS_FAILED -0x3180 /**< Making of the DHM parameters failed. */ +#define MBEDTLS_ERR_DHM_READ_PUBLIC_FAILED -0x3200 /**< Reading of the public values failed. */ +#define MBEDTLS_ERR_DHM_MAKE_PUBLIC_FAILED -0x3280 /**< Making of the public value failed. */ +#define MBEDTLS_ERR_DHM_CALC_SECRET_FAILED -0x3300 /**< Calculation of the DHM secret failed. */ +#define MBEDTLS_ERR_DHM_INVALID_FORMAT -0x3380 /**< The ASN.1 data is not formatted correctly. */ +#define MBEDTLS_ERR_DHM_ALLOC_FAILED -0x3400 /**< Allocation of memory failed. */ +#define MBEDTLS_ERR_DHM_FILE_IO_ERROR -0x3480 /**< Read/write of file failed. */ + +/** + * RFC 3526 defines a number of standardized Diffie-Hellman groups + * for IKE. + * RFC 5114 defines a number of standardized Diffie-Hellman groups + * that can be used. + * + * Some are included here for convenience. + * + * Included are: + * RFC 3526 3. 2048-bit MODP Group + * RFC 3526 4. 3072-bit MODP Group + * RFC 3526 5. 4096-bit MODP Group + * RFC 5114 2.2. 2048-bit MODP Group with 224-bit Prime Order Subgroup + */ +#define MBEDTLS_DHM_RFC3526_MODP_2048_P \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AACAA68FFFFFFFFFFFFFFFF" + +#define MBEDTLS_DHM_RFC3526_MODP_2048_G "02" + +#define MBEDTLS_DHM_RFC3526_MODP_3072_P \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ + "43DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF" + +#define MBEDTLS_DHM_RFC3526_MODP_3072_G "02" + +#define MBEDTLS_DHM_RFC3526_MODP_4096_P \ + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" \ + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" \ + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" \ + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \ + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D" \ + "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F" \ + "83655D23DCA3AD961C62F356208552BB9ED529077096966D" \ + "670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B" \ + "E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9" \ + "DE2BCBF6955817183995497CEA956AE515D2261898FA0510" \ + "15728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64" \ + "ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7" \ + "ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6B" \ + "F12FFA06D98A0864D87602733EC86A64521F2B18177B200C" \ + "BBE117577A615D6C770988C0BAD946E208E24FA074E5AB31" \ + "43DB5BFCE0FD108E4B82D120A92108011A723C12A787E6D7" \ + "88719A10BDBA5B2699C327186AF4E23C1A946834B6150BDA" \ + "2583E9CA2AD44CE8DBBBC2DB04DE8EF92E8EFC141FBECAA6" \ + "287C59474E6BC05D99B2964FA090C3A2233BA186515BE7ED" \ + "1F612970CEE2D7AFB81BDD762170481CD0069127D5B05AA9" \ + "93B4EA988D8FDDC186FFB7DC90A6C08F4DF435C934063199" \ + "FFFFFFFFFFFFFFFF" + +#define MBEDTLS_DHM_RFC3526_MODP_4096_G "02" + +#define MBEDTLS_DHM_RFC5114_MODP_2048_P \ + "AD107E1E9123A9D0D660FAA79559C51FA20D64E5683B9FD1" \ + "B54B1597B61D0A75E6FA141DF95A56DBAF9A3C407BA1DF15" \ + "EB3D688A309C180E1DE6B85A1274A0A66D3F8152AD6AC212" \ + "9037C9EDEFDA4DF8D91E8FEF55B7394B7AD5B7D0B6C12207" \ + "C9F98D11ED34DBF6C6BA0B2C8BBC27BE6A00E0A0B9C49708" \ + "B3BF8A317091883681286130BC8985DB1602E714415D9330" \ + "278273C7DE31EFDC7310F7121FD5A07415987D9ADC0A486D" \ + "CDF93ACC44328387315D75E198C641A480CD86A1B9E587E8" \ + "BE60E69CC928B2B9C52172E413042E9B23F10B0E16E79763" \ + "C9B53DCF4BA80A29E3FB73C16B8E75B97EF363E2FFA31F71" \ + "CF9DE5384E71B81C0AC4DFFE0C10E64F" + +#define MBEDTLS_DHM_RFC5114_MODP_2048_G \ + "AC4032EF4F2D9AE39DF30B5C8FFDAC506CDEBE7B89998CAF"\ + "74866A08CFE4FFE3A6824A4E10B9A6F0DD921F01A70C4AFA"\ + "AB739D7700C29F52C57DB17C620A8652BE5E9001A8D66AD7"\ + "C17669101999024AF4D027275AC1348BB8A762D0521BC98A"\ + "E247150422EA1ED409939D54DA7460CDB5F6C6B250717CBE"\ + "F180EB34118E98D119529A45D6F834566E3025E316A330EF"\ + "BB77A86F0C1AB15B051AE3D428C8F8ACB70A8137150B8EEB"\ + "10E183EDD19963DDD9E263E4770589EF6AA21E7F5F2FF381"\ + "B539CCE3409D13CD566AFBB48D6C019181E1BCFE94B30269"\ + "EDFE72FE9B6AA4BD7B5A0F1C71CFFF4C19C418E1F6EC0179"\ + "81BC087F2A7065B384B890D3191F2BFA" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief DHM context structure + */ +typedef struct +{ + size_t len; /*!< size(P) in chars */ + mbedtls_mpi P; /*!< prime modulus */ + mbedtls_mpi G; /*!< generator */ + mbedtls_mpi X; /*!< secret value */ + mbedtls_mpi GX; /*!< self = G^X mod P */ + mbedtls_mpi GY; /*!< peer = G^Y mod P */ + mbedtls_mpi K; /*!< key = GY^X mod P */ + mbedtls_mpi RP; /*!< cached R^2 mod P */ + mbedtls_mpi Vi; /*!< blinding value */ + mbedtls_mpi Vf; /*!< un-blinding value */ + mbedtls_mpi pX; /*!< previous X */ +} +mbedtls_dhm_context; + +/** + * \brief Initialize DHM context + * + * \param ctx DHM context to be initialized + */ +void mbedtls_dhm_init( mbedtls_dhm_context *ctx ); + +/** + * \brief Parse the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param p &(start of input buffer) + * \param end end of buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +int mbedtls_dhm_read_params( mbedtls_dhm_context *ctx, + unsigned char **p, + const unsigned char *end ); + +/** + * \brief Setup and write the ServerKeyExchange parameters + * + * \param ctx DHM context + * \param x_size private value size in bytes + * \param output destination buffer + * \param olen number of chars written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note This function assumes that ctx->P and ctx->G + * have already been properly set (for example + * using mbedtls_mpi_read_string or mbedtls_mpi_read_binary). + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +int mbedtls_dhm_make_params( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Import the peer's public value G^Y + * + * \param ctx DHM context + * \param input input buffer + * \param ilen size of buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +int mbedtls_dhm_read_public( mbedtls_dhm_context *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief Create own private value X and export G^X + * + * \param ctx DHM context + * \param x_size private value size in bytes + * \param output destination buffer + * \param olen must be at least equal to the size of P, ctx->len + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + */ +int mbedtls_dhm_make_public( mbedtls_dhm_context *ctx, int x_size, + unsigned char *output, size_t olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Derive and export the shared secret (G^Y)^X mod P + * + * \param ctx DHM context + * \param output destination buffer + * \param output_size size of the destination buffer + * \param olen on exit, holds the actual number of bytes written + * \param f_rng RNG function, for blinding purposes + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_DHM_XXX error code + * + * \note If non-NULL, f_rng is used to blind the input as + * countermeasure against timing attacks. Blinding is + * automatically used if and only if our secret value X is + * re-used and costs nothing otherwise, so it is recommended + * to always pass a non-NULL f_rng argument. + */ +int mbedtls_dhm_calc_secret( mbedtls_dhm_context *ctx, + unsigned char *output, size_t output_size, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Free and clear the components of a DHM key + * + * \param ctx DHM context to free and clear + */ +void mbedtls_dhm_free( mbedtls_dhm_context *ctx ); + +#if defined(MBEDTLS_ASN1_PARSE_C) +/** \ingroup x509_module */ +/** + * \brief Parse DHM parameters in PEM or DER format + * + * \param dhm DHM context to be initialized + * \param dhmin input buffer + * \param dhminlen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific DHM or PEM error code + */ +int mbedtls_dhm_parse_dhm( mbedtls_dhm_context *dhm, const unsigned char *dhmin, + size_t dhminlen ); + +#if defined(MBEDTLS_FS_IO) +/** \ingroup x509_module */ +/** + * \brief Load and parse DHM parameters + * + * \param dhm DHM context to be initialized + * \param path filename to read the DHM Parameters from + * + * \return 0 if successful, or a specific DHM or PEM error code + */ +int mbedtls_dhm_parse_dhmfile( mbedtls_dhm_context *dhm, const char *path ); +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_ASN1_PARSE_C */ + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_dhm_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* dhm.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ecdh.h b/c++/src/connect/mbedtls/mbedtls/ecdh.h new file mode 100644 index 00000000..625a2819 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ecdh.h @@ -0,0 +1,214 @@ +/** + * \file ecdh.h + * + * \brief Elliptic curve Diffie-Hellman + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ECDH_H +#define MBEDTLS_ECDH_H + +#include "ecp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * When importing from an EC key, select if it is our key or the peer's key + */ +typedef enum +{ + MBEDTLS_ECDH_OURS, + MBEDTLS_ECDH_THEIRS, +} mbedtls_ecdh_side; + +/** + * \brief ECDH context structure + */ +typedef struct +{ + mbedtls_ecp_group grp; /*!< elliptic curve used */ + mbedtls_mpi d; /*!< our secret value (private key) */ + mbedtls_ecp_point Q; /*!< our public value (public key) */ + mbedtls_ecp_point Qp; /*!< peer's public value (public key) */ + mbedtls_mpi z; /*!< shared secret */ + int point_format; /*!< format for point export in TLS messages */ + mbedtls_ecp_point Vi; /*!< blinding value (for later) */ + mbedtls_ecp_point Vf; /*!< un-blinding value (for later) */ + mbedtls_mpi _d; /*!< previous d (for later) */ +} +mbedtls_ecdh_context; + +/** + * \brief Generate a public key. + * Raw function that only does the core computation. + * + * \param grp ECP group + * \param d Destination MPI (secret exponent, aka private key) + * \param Q Destination point (public key) + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +int mbedtls_ecdh_gen_public( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Compute shared secret + * Raw function that only does the core computation. + * + * \param grp ECP group + * \param z Destination MPI (shared secret) + * \param Q Public key from other party + * \param d Our secret exponent (private key) + * \param f_rng RNG function (see notes) + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * + * \note If f_rng is not NULL, it is used to implement + * countermeasures against potential elaborate timing + * attacks, see \c mbedtls_ecp_mul() for details. + */ +int mbedtls_ecdh_compute_shared( mbedtls_ecp_group *grp, mbedtls_mpi *z, + const mbedtls_ecp_point *Q, const mbedtls_mpi *d, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Initialize context + * + * \param ctx Context to initialize + */ +void mbedtls_ecdh_init( mbedtls_ecdh_context *ctx ); + +/** + * \brief Free context + * + * \param ctx Context to free + */ +void mbedtls_ecdh_free( mbedtls_ecdh_context *ctx ); + +/** + * \brief Generate a public key and a TLS ServerKeyExchange payload. + * (First function used by a TLS server for ECDHE.) + * + * \param ctx ECDH context + * \param olen number of chars written + * \param buf destination buffer + * \param blen length of buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note This function assumes that ctx->grp has already been + * properly set (for example using mbedtls_ecp_group_load). + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_make_params( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Parse and procress a TLS ServerKeyExhange payload. + * (First function used by a TLS client for ECDHE.) + * + * \param ctx ECDH context + * \param buf pointer to start of input buffer + * \param end one past end of buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_read_params( mbedtls_ecdh_context *ctx, + const unsigned char **buf, const unsigned char *end ); + +/** + * \brief Setup an ECDH context from an EC key. + * (Used by clients and servers in place of the + * ServerKeyEchange for static ECDH: import ECDH parameters + * from a certificate's EC key information.) + * + * \param ctx ECDH constext to set + * \param key EC key to use + * \param side Is it our key (1) or the peer's key (0) ? + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_get_params( mbedtls_ecdh_context *ctx, const mbedtls_ecp_keypair *key, + mbedtls_ecdh_side side ); + +/** + * \brief Generate a public key and a TLS ClientKeyExchange payload. + * (Second function used by a TLS client for ECDH(E).) + * + * \param ctx ECDH context + * \param olen number of bytes actually written + * \param buf destination buffer + * \param blen size of destination buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_make_public( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Parse and process a TLS ClientKeyExchange payload. + * (Second function used by a TLS server for ECDH(E).) + * + * \param ctx ECDH context + * \param buf start of input buffer + * \param blen length of input buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_read_public( mbedtls_ecdh_context *ctx, + const unsigned char *buf, size_t blen ); + +/** + * \brief Derive and export the shared secret. + * (Last function used by both TLS client en servers.) + * + * \param ctx ECDH context + * \param olen number of bytes written + * \param buf destination buffer + * \param blen buffer length + * \param f_rng RNG function, see notes for \c mbedtls_ecdh_compute_shared() + * \param p_rng RNG parameter + * + * \return 0 if successful, or an MBEDTLS_ERR_ECP_XXX error code + */ +int mbedtls_ecdh_calc_secret( mbedtls_ecdh_context *ctx, size_t *olen, + unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#ifdef __cplusplus +} +#endif + +#endif /* ecdh.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ecdsa.h b/c++/src/connect/mbedtls/mbedtls/ecdsa.h new file mode 100644 index 00000000..52827d8d --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ecdsa.h @@ -0,0 +1,248 @@ +/** + * \file ecdsa.h + * + * \brief Elliptic curve DSA + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ECDSA_H +#define MBEDTLS_ECDSA_H + +#include "ecp.h" +#include "md.h" + +/* + * RFC 4492 page 20: + * + * Ecdsa-Sig-Value ::= SEQUENCE { + * r INTEGER, + * s INTEGER + * } + * + * Size is at most + * 1 (tag) + 1 (len) + 1 (initial 0) + ECP_MAX_BYTES for each of r and s, + * twice that + 1 (tag) + 2 (len) for the sequence + * (assuming ECP_MAX_BYTES is less than 126 for r and s, + * and less than 124 (total len <= 255) for the sequence) + */ +#if MBEDTLS_ECP_MAX_BYTES > 124 +#error "MBEDTLS_ECP_MAX_BYTES bigger than expected, please fix MBEDTLS_ECDSA_MAX_LEN" +#endif +/** Maximum size of an ECDSA signature in bytes */ +#define MBEDTLS_ECDSA_MAX_LEN ( 3 + 2 * ( 3 + MBEDTLS_ECP_MAX_BYTES ) ) + +/** + * \brief ECDSA context structure + */ +typedef mbedtls_ecp_keypair mbedtls_ecdsa_context; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Compute ECDSA signature of a previously hashed message + * + * \note The deterministic version is usually prefered. + * + * \param grp ECP group + * \param r First output integer + * \param s Second output integer + * \param d Private signing key + * \param buf Message hash + * \param blen Length of buf + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +int mbedtls_ecdsa_sign( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +/** + * \brief Compute ECDSA signature of a previously hashed message, + * deterministic version (RFC 6979). + * + * \param grp ECP group + * \param r First output integer + * \param s Second output integer + * \param d Private signing key + * \param buf Message hash + * \param blen Length of buf + * \param md_alg MD algorithm used to hash the message + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +int mbedtls_ecdsa_sign_det( mbedtls_ecp_group *grp, mbedtls_mpi *r, mbedtls_mpi *s, + const mbedtls_mpi *d, const unsigned char *buf, size_t blen, + mbedtls_md_type_t md_alg ); +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/** + * \brief Verify ECDSA signature of a previously hashed message + * + * \param grp ECP group + * \param buf Message hash + * \param blen Length of buf + * \param Q Public key to use for verification + * \param r First integer of the signature + * \param s Second integer of the signature + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +int mbedtls_ecdsa_verify( mbedtls_ecp_group *grp, + const unsigned char *buf, size_t blen, + const mbedtls_ecp_point *Q, const mbedtls_mpi *r, const mbedtls_mpi *s); + +/** + * \brief Compute ECDSA signature and write it to buffer, + * serialized as defined in RFC 4492 page 20. + * (Not thread-safe to use same context in multiple threads) + * + * \note The deterministice version (RFC 6979) is used if + * MBEDTLS_ECDSA_DETERMINISTIC is defined. + * + * \param ctx ECDSA context + * \param md_alg Algorithm that was used to hash the message + * \param hash Message hash + * \param hlen Length of hash + * \param sig Buffer that will hold the signature + * \param slen Length of the signature written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note The "sig" buffer must be at least as large as twice the + * size of the curve used, plus 9 (eg. 73 bytes if a 256-bit + * curve is used). MBEDTLS_ECDSA_MAX_LEN is always safe. + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX, MBEDTLS_ERR_MPI_XXX or + * MBEDTLS_ERR_ASN1_XXX error code + */ +int mbedtls_ecdsa_write_signature( mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Compute ECDSA signature and write it to buffer, + * serialized as defined in RFC 4492 page 20. + * Deterministic version, RFC 6979. + * (Not thread-safe to use same context in multiple threads) + * + * \deprecated Superseded by mbedtls_ecdsa_write_signature() in 2.0.0 + * + * \param ctx ECDSA context + * \param hash Message hash + * \param hlen Length of hash + * \param sig Buffer that will hold the signature + * \param slen Length of the signature written + * \param md_alg MD algorithm used to hash the message + * + * \note The "sig" buffer must be at least as large as twice the + * size of the curve used, plus 9 (eg. 73 bytes if a 256-bit + * curve is used). MBEDTLS_ECDSA_MAX_LEN is always safe. + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX, MBEDTLS_ERR_MPI_XXX or + * MBEDTLS_ERR_ASN1_XXX error code + */ +int mbedtls_ecdsa_write_signature_det( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + unsigned char *sig, size_t *slen, + mbedtls_md_type_t md_alg ) MBEDTLS_DEPRECATED; +#undef MBEDTLS_DEPRECATED +#endif /* MBEDTLS_DEPRECATED_REMOVED */ +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ + +/** + * \brief Read and verify an ECDSA signature + * + * \param ctx ECDSA context + * \param hash Message hash + * \param hlen Size of hash + * \param sig Signature to read and verify + * \param slen Size of sig + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid, + * MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if the signature is + * valid but its actual length is less than siglen, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_ecdsa_read_signature( mbedtls_ecdsa_context *ctx, + const unsigned char *hash, size_t hlen, + const unsigned char *sig, size_t slen ); + +/** + * \brief Generate an ECDSA keypair on the given curve + * + * \param ctx ECDSA context in which the keypair should be stored + * \param gid Group (elliptic curve) to use. One of the various + * MBEDTLS_ECP_DP_XXX macros depending on configuration. + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 on success, or a MBEDTLS_ERR_ECP_XXX code. + */ +int mbedtls_ecdsa_genkey( mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Set an ECDSA context from an EC key pair + * + * \param ctx ECDSA context to set + * \param key EC key to use + * + * \return 0 on success, or a MBEDTLS_ERR_ECP_XXX code. + */ +int mbedtls_ecdsa_from_keypair( mbedtls_ecdsa_context *ctx, const mbedtls_ecp_keypair *key ); + +/** + * \brief Initialize context + * + * \param ctx Context to initialize + */ +void mbedtls_ecdsa_init( mbedtls_ecdsa_context *ctx ); + +/** + * \brief Free context + * + * \param ctx Context to free + */ +void mbedtls_ecdsa_free( mbedtls_ecdsa_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* ecdsa.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ecjpake.h b/c++/src/connect/mbedtls/mbedtls/ecjpake.h new file mode 100644 index 00000000..b7b61604 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ecjpake.h @@ -0,0 +1,238 @@ +/** + * \file ecjpake.h + * + * \brief Elliptic curve J-PAKE + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ECJPAKE_H +#define MBEDTLS_ECJPAKE_H + +/* + * J-PAKE is a password-authenticated key exchange that allows deriving a + * strong shared secret from a (potentially low entropy) pre-shared + * passphrase, with forward secrecy and mutual authentication. + * https://en.wikipedia.org/wiki/Password_Authenticated_Key_Exchange_by_Juggling + * + * This file implements the Elliptic Curve variant of J-PAKE, + * as defined in Chapter 7.4 of the Thread v1.0 Specification, + * available to members of the Thread Group http://threadgroup.org/ + * + * As the J-PAKE algorithm is inherently symmetric, so is our API. + * Each party needs to send its first round message, in any order, to the + * other party, then each sends its second round message, in any order. + * The payloads are serialized in a way suitable for use in TLS, but could + * also be use outside TLS. + */ + +#include "ecp.h" +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Roles in the EC J-PAKE exchange + */ +typedef enum { + MBEDTLS_ECJPAKE_CLIENT = 0, /**< Client */ + MBEDTLS_ECJPAKE_SERVER, /**< Server */ +} mbedtls_ecjpake_role; + +/** + * EC J-PAKE context structure. + * + * J-PAKE is a symmetric protocol, except for the identifiers used in + * Zero-Knowledge Proofs, and the serialization of the second message + * (KeyExchange) as defined by the Thread spec. + * + * In order to benefit from this symmetry, we choose a different naming + * convetion from the Thread v1.0 spec. Correspondance is indicated in the + * description as a pair C: client name, S: server name + */ +typedef struct +{ + const mbedtls_md_info_t *md_info; /**< Hash to use */ + mbedtls_ecp_group grp; /**< Elliptic curve */ + mbedtls_ecjpake_role role; /**< Are we client or server? */ + int point_format; /**< Format for point export */ + + mbedtls_ecp_point Xm1; /**< My public key 1 C: X1, S: X3 */ + mbedtls_ecp_point Xm2; /**< My public key 2 C: X2, S: X4 */ + mbedtls_ecp_point Xp1; /**< Peer public key 1 C: X3, S: X1 */ + mbedtls_ecp_point Xp2; /**< Peer public key 2 C: X4, S: X2 */ + mbedtls_ecp_point Xp; /**< Peer public key C: Xs, S: Xc */ + + mbedtls_mpi xm1; /**< My private key 1 C: x1, S: x3 */ + mbedtls_mpi xm2; /**< My private key 2 C: x2, S: x4 */ + + mbedtls_mpi s; /**< Pre-shared secret (passphrase) */ +} mbedtls_ecjpake_context; + +/** + * \brief Initialize a context + * (just makes it ready for setup() or free()). + * + * \param ctx context to initialize + */ +void mbedtls_ecjpake_init( mbedtls_ecjpake_context *ctx ); + +/** + * \brief Set up a context for use + * + * \note Currently the only values for hash/curve allowed by the + * standard are MBEDTLS_MD_SHA256/MBEDTLS_ECP_DP_SECP256R1. + * + * \param ctx context to set up + * \param role Our role: client or server + * \param hash hash function to use (MBEDTLS_MD_XXX) + * \param curve elliptic curve identifier (MBEDTLS_ECP_DP_XXX) + * \param secret pre-shared secret (passphrase) + * \param len length of the shared secret + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_setup( mbedtls_ecjpake_context *ctx, + mbedtls_ecjpake_role role, + mbedtls_md_type_t hash, + mbedtls_ecp_group_id curve, + const unsigned char *secret, + size_t len ); + +/* + * \brief Check if a context is ready for use + * + * \param ctx Context to check + * + * \return 0 if the context is ready for use, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise + */ +int mbedtls_ecjpake_check( const mbedtls_ecjpake_context *ctx ); + +/** + * \brief Generate and write the first round message + * (TLS: contents of the Client/ServerHello extension, + * excluding extension type and length bytes) + * + * \param ctx Context to use + * \param buf Buffer to write the contents to + * \param len Buffer size + * \param olen Will be updated with the number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_write_round_one( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Read and process the first round message + * (TLS: contents of the Client/ServerHello extension, + * excluding extension type and length bytes) + * + * \param ctx Context to use + * \param buf Pointer to extension contents + * \param len Extension length + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_read_round_one( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ); + +/** + * \brief Generate and write the second round message + * (TLS: contents of the Client/ServerKeyExchange) + * + * \param ctx Context to use + * \param buf Buffer to write the contents to + * \param len Buffer size + * \param olen Will be updated with the number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_write_round_two( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Read and process the second round message + * (TLS: contents of the Client/ServerKeyExchange) + * + * \param ctx Context to use + * \param buf Pointer to the message + * \param len Message length + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_read_round_two( mbedtls_ecjpake_context *ctx, + const unsigned char *buf, + size_t len ); + +/** + * \brief Derive the shared secret + * (TLS: Pre-Master Secret) + * + * \param ctx Context to use + * \param buf Buffer to write the contents to + * \param len Buffer size + * \param olen Will be updated with the number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successfull, + * a negative error code otherwise + */ +int mbedtls_ecjpake_derive_secret( mbedtls_ecjpake_context *ctx, + unsigned char *buf, size_t len, size_t *olen, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Free a context's content + * + * \param ctx context to free + */ +void mbedtls_ecjpake_free( mbedtls_ecjpake_context *ctx ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_ecjpake_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ecjpake.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ecp.h b/c++/src/connect/mbedtls/mbedtls/ecp.h new file mode 100644 index 00000000..5246c789 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ecp.h @@ -0,0 +1,669 @@ +/** + * \file ecp.h + * + * \brief Elliptic curves over GF(p) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ECP_H +#define MBEDTLS_ECP_H + +#include "bignum.h" + +/* + * ECP error codes + */ +#define MBEDTLS_ERR_ECP_BAD_INPUT_DATA -0x4F80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL -0x4F00 /**< The buffer is too small to write to. */ +#define MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE -0x4E80 /**< Requested curve not available. */ +#define MBEDTLS_ERR_ECP_VERIFY_FAILED -0x4E00 /**< The signature is not valid. */ +#define MBEDTLS_ERR_ECP_ALLOC_FAILED -0x4D80 /**< Memory allocation failed. */ +#define MBEDTLS_ERR_ECP_RANDOM_FAILED -0x4D00 /**< Generation of random value, such as (ephemeral) key, failed. */ +#define MBEDTLS_ERR_ECP_INVALID_KEY -0x4C80 /**< Invalid private or public key. */ +#define MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH -0x4C00 /**< Signature is valid but shorter than the user-supplied length. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Domain parameters (curve, subgroup and generator) identifiers. + * + * Only curves over prime fields are supported. + * + * \warning This library does not support validation of arbitrary domain + * parameters. Therefore, only well-known domain parameters from trusted + * sources should be used. See mbedtls_ecp_group_load(). + */ +typedef enum +{ + MBEDTLS_ECP_DP_NONE = 0, + MBEDTLS_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */ + MBEDTLS_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */ + MBEDTLS_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */ + MBEDTLS_ECP_DP_SECP384R1, /*!< 384-bits NIST curve */ + MBEDTLS_ECP_DP_SECP521R1, /*!< 521-bits NIST curve */ + MBEDTLS_ECP_DP_BP256R1, /*!< 256-bits Brainpool curve */ + MBEDTLS_ECP_DP_BP384R1, /*!< 384-bits Brainpool curve */ + MBEDTLS_ECP_DP_BP512R1, /*!< 512-bits Brainpool curve */ + MBEDTLS_ECP_DP_CURVE25519, /*!< Curve25519 */ + MBEDTLS_ECP_DP_SECP192K1, /*!< 192-bits "Koblitz" curve */ + MBEDTLS_ECP_DP_SECP224K1, /*!< 224-bits "Koblitz" curve */ + MBEDTLS_ECP_DP_SECP256K1, /*!< 256-bits "Koblitz" curve */ +} mbedtls_ecp_group_id; + +/** + * Number of supported curves (plus one for NONE). + * + * (Montgomery curves excluded for now.) + */ +#define MBEDTLS_ECP_DP_MAX 12 + +/** + * Curve information for use by other modules + */ +typedef struct +{ + mbedtls_ecp_group_id grp_id; /*!< Internal identifier */ + uint16_t tls_id; /*!< TLS NamedCurve identifier */ + uint16_t bit_size; /*!< Curve size in bits */ + const char *name; /*!< Human-friendly name */ +} mbedtls_ecp_curve_info; + +/** + * \brief ECP point structure (jacobian coordinates) + * + * \note All functions expect and return points satisfying + * the following condition: Z == 0 or Z == 1. (Other + * values of Z are used by internal functions only.) + * The point is zero, or "at infinity", if Z == 0. + * Otherwise, X and Y are its standard (affine) coordinates. + */ +typedef struct +{ + mbedtls_mpi X; /*!< the point's X coordinate */ + mbedtls_mpi Y; /*!< the point's Y coordinate */ + mbedtls_mpi Z; /*!< the point's Z coordinate */ +} +mbedtls_ecp_point; + +/** + * \brief ECP group structure + * + * We consider two types of curves equations: + * 1. Short Weierstrass y^2 = x^3 + A x + B mod P (SEC1 + RFC 4492) + * 2. Montgomery, y^2 = x^3 + A x^2 + x mod P (Curve25519 + draft) + * In both cases, a generator G for a prime-order subgroup is fixed. In the + * short weierstrass, this subgroup is actually the whole curve, and its + * cardinal is denoted by N. + * + * In the case of Short Weierstrass curves, our code requires that N is an odd + * prime. (Use odd in mbedtls_ecp_mul() and prime in mbedtls_ecdsa_sign() for blinding.) + * + * In the case of Montgomery curves, we don't store A but (A + 2) / 4 which is + * the quantity actually used in the formulas. Also, nbits is not the size of N + * but the required size for private keys. + * + * If modp is NULL, reduction modulo P is done using a generic algorithm. + * Otherwise, it must point to a function that takes an mbedtls_mpi in the range + * 0..2^(2*pbits)-1 and transforms it in-place in an integer of little more + * than pbits, so that the integer may be efficiently brought in the 0..P-1 + * range by a few additions or substractions. It must return 0 on success and + * non-zero on failure. + */ +typedef struct +{ + mbedtls_ecp_group_id id; /*!< internal group identifier */ + mbedtls_mpi P; /*!< prime modulus of the base field */ + mbedtls_mpi A; /*!< 1. A in the equation, or 2. (A + 2) / 4 */ + mbedtls_mpi B; /*!< 1. B in the equation, or 2. unused */ + mbedtls_ecp_point G; /*!< generator of the (sub)group used */ + mbedtls_mpi N; /*!< 1. the order of G, or 2. unused */ + size_t pbits; /*!< number of bits in P */ + size_t nbits; /*!< number of bits in 1. P, or 2. private keys */ + unsigned int h; /*!< internal: 1 if the constants are static */ + int (*modp)(mbedtls_mpi *); /*!< function for fast reduction mod P */ + int (*t_pre)(mbedtls_ecp_point *, void *); /*!< unused */ + int (*t_post)(mbedtls_ecp_point *, void *); /*!< unused */ + void *t_data; /*!< unused */ + mbedtls_ecp_point *T; /*!< pre-computed points for ecp_mul_comb() */ + size_t T_size; /*!< number for pre-computed points */ +} +mbedtls_ecp_group; + +/** + * \brief ECP key pair structure + * + * A generic key pair that could be used for ECDSA, fixed ECDH, etc. + * + * \note Members purposefully in the same order as struc mbedtls_ecdsa_context. + */ +typedef struct +{ + mbedtls_ecp_group grp; /*!< Elliptic curve and base point */ + mbedtls_mpi d; /*!< our secret value */ + mbedtls_ecp_point Q; /*!< our public value */ +} +mbedtls_ecp_keypair; + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_ECP_MAX_BITS) +/** + * Maximum size of the groups (that is, of N and P) + */ +#define MBEDTLS_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +#endif + +#define MBEDTLS_ECP_MAX_BYTES ( ( MBEDTLS_ECP_MAX_BITS + 7 ) / 8 ) +#define MBEDTLS_ECP_MAX_PT_LEN ( 2 * MBEDTLS_ECP_MAX_BYTES + 1 ) + +#if !defined(MBEDTLS_ECP_WINDOW_SIZE) +/* + * Maximum "window" size used for point multiplication. + * Default: 6. + * Minimum value: 2. Maximum value: 7. + * + * Result is an array of at most ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) ) + * points used for point multiplication. This value is directly tied to EC + * peak memory usage, so decreasing it by one should roughly cut memory usage + * by two (if large curves are in use). + * + * Reduction in size may reduce speed, but larger curves are impacted first. + * Sample performances (in ECDHE handshakes/s, with FIXED_POINT_OPTIM = 1): + * w-size: 6 5 4 3 2 + * 521 145 141 135 120 97 + * 384 214 209 198 177 146 + * 256 320 320 303 262 226 + + * 224 475 475 453 398 342 + * 192 640 640 633 587 476 + */ +#define MBEDTLS_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +#endif /* MBEDTLS_ECP_WINDOW_SIZE */ + +#if !defined(MBEDTLS_ECP_FIXED_POINT_OPTIM) +/* + * Trade memory for speed on fixed-point multiplication. + * + * This speeds up repeated multiplication of the generator (that is, the + * multiplication in ECDSA signatures, and half of the multiplications in + * ECDSA verification and ECDHE) by a factor roughly 3 to 4. + * + * The cost is increasing EC peak memory usage by a factor roughly 2. + * + * Change this value to 0 to reduce peak memory usage. + */ +#define MBEDTLS_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ +#endif /* MBEDTLS_ECP_FIXED_POINT_OPTIM */ + +/* \} name SECTION: Module settings */ + +/* + * Point formats, from RFC 4492's enum ECPointFormat + */ +#define MBEDTLS_ECP_PF_UNCOMPRESSED 0 /**< Uncompressed point format */ +#define MBEDTLS_ECP_PF_COMPRESSED 1 /**< Compressed point format */ + +/* + * Some other constants from RFC 4492 + */ +#define MBEDTLS_ECP_TLS_NAMED_CURVE 3 /**< ECCurveType's named_curve */ + +/** + * \brief Get the list of supported curves in order of preferrence + * (full information) + * + * \return A statically allocated array, the last entry is 0. + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void ); + +/** + * \brief Get the list of supported curves in order of preferrence + * (grp_id only) + * + * \return A statically allocated array, + * terminated with MBEDTLS_ECP_DP_NONE. + */ +const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void ); + +/** + * \brief Get curve information from an internal group identifier + * + * \param grp_id A MBEDTLS_ECP_DP_XXX value + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id ); + +/** + * \brief Get curve information from a TLS NamedCurve value + * + * \param tls_id A MBEDTLS_ECP_DP_XXX value + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id ); + +/** + * \brief Get curve information from a human-readable name + * + * \param name The name + * + * \return The associated curve information or NULL + */ +const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name ); + +/** + * \brief Initialize a point (as zero) + */ +void mbedtls_ecp_point_init( mbedtls_ecp_point *pt ); + +/** + * \brief Initialize a group (to something meaningless) + */ +void mbedtls_ecp_group_init( mbedtls_ecp_group *grp ); + +/** + * \brief Initialize a key pair (as an invalid one) + */ +void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key ); + +/** + * \brief Free the components of a point + */ +void mbedtls_ecp_point_free( mbedtls_ecp_point *pt ); + +/** + * \brief Free the components of an ECP group + */ +void mbedtls_ecp_group_free( mbedtls_ecp_group *grp ); + +/** + * \brief Free the components of a key pair + */ +void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key ); + +/** + * \brief Copy the contents of point Q into P + * + * \param P Destination point + * \param Q Source point + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q ); + +/** + * \brief Copy the contents of a group object + * + * \param dst Destination group + * \param src Source group + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src ); + +/** + * \brief Set a point to zero + * + * \param pt Destination point + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt ); + +/** + * \brief Tell if a point is zero + * + * \param pt Point to test + * + * \return 1 if point is zero, 0 otherwise + */ +int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt ); + +/** + * \brief Compare two points + * + * \note This assumes the points are normalized. Otherwise, + * they may compare as "not equal" even if they are. + * + * \param P First point to compare + * \param Q Second point to compare + * + * \return 0 if the points are equal, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA otherwise + */ +int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P, + const mbedtls_ecp_point *Q ); + +/** + * \brief Import a non-zero point from two ASCII strings + * + * \param P Destination point + * \param radix Input numeric base + * \param x First affine coordinate as a null-terminated string + * \param y Second affine coordinate as a null-terminated string + * + * \return 0 if successful, or a MBEDTLS_ERR_MPI_XXX error code + */ +int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix, + const char *x, const char *y ); + +/** + * \brief Export a point into unsigned binary data + * + * \param grp Group to which the point should belong + * \param P Point to export + * \param format Point format, should be a MBEDTLS_ECP_PF_XXX macro + * \param olen Length of the actual output + * \param buf Output buffer + * \param buflen Length of the output buffer + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P, + int format, size_t *olen, + unsigned char *buf, size_t buflen ); + +/** + * \brief Import a point from unsigned binary data + * + * \param grp Group to which the point should belong + * \param P Point to import + * \param buf Input buffer + * \param ilen Actual length of input + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the point format + * is not implemented. + * + * \note This function does NOT check that the point actually + * belongs to the given group, see mbedtls_ecp_check_pubkey() for + * that. + */ +int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, + const unsigned char *buf, size_t ilen ); + +/** + * \brief Import a point from a TLS ECPoint record + * + * \param grp ECP group used + * \param pt Destination point + * \param buf $(Start of input buffer) + * \param len Buffer length + * + * \note buf is updated to point right after the ECPoint on exit + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid + */ +int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, + const unsigned char **buf, size_t len ); + +/** + * \brief Export a point as a TLS ECPoint record + * + * \param grp ECP group used + * \param pt Point to export + * \param format Export format + * \param olen length of data written + * \param buf Buffer to write to + * \param blen Buffer length + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BAD_INPUT_DATA + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, + int format, size_t *olen, + unsigned char *buf, size_t blen ); + +/** + * \brief Set a group using well-known domain parameters + * + * \param grp Destination group + * \param index Index in the list of well-known domain parameters + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE for unkownn groups + * + * \note Index should be a value of RFC 4492's enum NamedCurve, + * usually in the form of a MBEDTLS_ECP_DP_XXX macro. + */ +int mbedtls_ecp_group_load( mbedtls_ecp_group *grp, mbedtls_ecp_group_id index ); + +/** + * \brief Set a group from a TLS ECParameters record + * + * \param grp Destination group + * \param buf &(Start of input buffer) + * \param len Buffer length + * + * \note buf is updated to point right after ECParameters on exit + * + * \return 0 if successful, + * MBEDTLS_ERR_MPI_XXX if initialization failed + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA if input is invalid + */ +int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len ); + +/** + * \brief Write the TLS ECParameters record for a group + * + * \param grp ECP group used + * \param olen Number of bytes actually written + * \param buf Buffer to write to + * \param blen Buffer length + * + * \return 0 if successful, + * or MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL + */ +int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen, + unsigned char *buf, size_t blen ); + +/** + * \brief Multiplication by an integer: R = m * P + * (Not thread-safe to use same group in multiple threads) + * + * \note In order to prevent timing attacks, this function + * executes the exact same sequence of (base field) + * operations for any valid m. It avoids any if-branch or + * array index depending on the value of m. + * + * \note If f_rng is not NULL, it is used to randomize intermediate + * results in order to prevent potential timing attacks + * targeting these results. It is recommended to always + * provide a non-NULL f_rng (the overhead is negligible). + * + * \param grp ECP group + * \param R Destination point + * \param m Integer by which to multiply + * \param P Point to multiply + * \param f_rng RNG function (see notes) + * \param p_rng RNG parameter + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_INVALID_KEY if m is not a valid privkey + * or P is not a valid pubkey, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Multiplication and addition of two points by integers: + * R = m * P + n * Q + * (Not thread-safe to use same group in multiple threads) + * + * \note In contrast to mbedtls_ecp_mul(), this function does not guarantee + * a constant execution flow and timing. + * + * \param grp ECP group + * \param R Destination point + * \param m Integer by which to multiply P + * \param P Point to multiply by m + * \param n Integer by which to multiply Q + * \param Q Point to be multiplied by n + * + * \return 0 if successful, + * MBEDTLS_ERR_ECP_INVALID_KEY if m or n is not a valid privkey + * or P or Q is not a valid pubkey, + * MBEDTLS_ERR_MPI_ALLOC_FAILED if memory allocation failed + */ +int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, + const mbedtls_mpi *m, const mbedtls_ecp_point *P, + const mbedtls_mpi *n, const mbedtls_ecp_point *Q ); + +/** + * \brief Check that a point is a valid public key on this curve + * + * \param grp Curve/group the point should belong to + * \param pt Point to check + * + * \return 0 if point is a valid public key, + * MBEDTLS_ERR_ECP_INVALID_KEY otherwise. + * + * \note This function only checks the point is non-zero, has valid + * coordinates and lies on the curve, but not that it is + * indeed a multiple of G. This is additional check is more + * expensive, isn't required by standards, and shouldn't be + * necessary if the group used has a small cofactor. In + * particular, it is useless for the NIST groups which all + * have a cofactor of 1. + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt ); + +/** + * \brief Check that an mbedtls_mpi is a valid private key for this curve + * + * \param grp Group used + * \param d Integer to check + * + * \return 0 if point is a valid private key, + * MBEDTLS_ERR_ECP_INVALID_KEY otherwise. + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d ); + +/** + * \brief Generate a keypair with configurable base point + * + * \param grp ECP group + * \param G Chosen base point + * \param d Destination MPI (secret part) + * \param Q Destination point (public part) + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp, + const mbedtls_ecp_point *G, + mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Generate a keypair + * + * \param grp ECP group + * \param d Destination MPI (secret part) + * \param Q Destination point (public part) + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + * + * \note Uses bare components rather than an mbedtls_ecp_keypair structure + * in order to ease use with other structures such as + * mbedtls_ecdh_context of mbedtls_ecdsa_context. + */ +int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Generate a keypair + * + * \param grp_id ECP group identifier + * \param key Destination keypair + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 if successful, + * or a MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code + */ +int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Check a public-private key pair + * + * \param pub Keypair structure holding a public key + * \param prv Keypair structure holding a private (plus public) key + * + * \return 0 if successful (keys are valid and match), or + * MBEDTLS_ERR_ECP_BAD_INPUT_DATA, or + * a MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX code. + */ +int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_ecp_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* ecp.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/entropy.h b/c++/src/connect/mbedtls/mbedtls/entropy.h new file mode 100644 index 00000000..747aca4d --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/entropy.h @@ -0,0 +1,287 @@ +/** + * \file entropy.h + * + * \brief Entropy accumulator implementation + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ENTROPY_H +#define MBEDTLS_ENTROPY_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if defined(MBEDTLS_SHA512_C) && !defined(MBEDTLS_ENTROPY_FORCE_SHA256) +#include "sha512.h" +#define MBEDTLS_ENTROPY_SHA512_ACCUMULATOR +#else +#if defined(MBEDTLS_SHA256_C) +#define MBEDTLS_ENTROPY_SHA256_ACCUMULATOR +#include "sha256.h" +#endif +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +#if defined(MBEDTLS_HAVEGE_C) +#include "havege.h" +#endif + +#define MBEDTLS_ERR_ENTROPY_SOURCE_FAILED -0x003C /**< Critical entropy source failure. */ +#define MBEDTLS_ERR_ENTROPY_MAX_SOURCES -0x003E /**< No more sources can be added. */ +#define MBEDTLS_ERR_ENTROPY_NO_SOURCES_DEFINED -0x0040 /**< No sources have been added to poll. */ +#define MBEDTLS_ERR_ENTROPY_NO_STRONG_SOURCE -0x003D /**< No strong sources have been added to poll. */ +#define MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR -0x003F /**< Read/write error in file. */ + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_ENTROPY_MAX_SOURCES) +#define MBEDTLS_ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +#endif + +#if !defined(MBEDTLS_ENTROPY_MAX_GATHER) +#define MBEDTLS_ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ +#endif + +/* \} name SECTION: Module settings */ + +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) +#define MBEDTLS_ENTROPY_BLOCK_SIZE 64 /**< Block size of entropy accumulator (SHA-512) */ +#else +#define MBEDTLS_ENTROPY_BLOCK_SIZE 32 /**< Block size of entropy accumulator (SHA-256) */ +#endif + +#define MBEDTLS_ENTROPY_MAX_SEED_SIZE 1024 /**< Maximum size of seed we read from seed file */ +#define MBEDTLS_ENTROPY_SOURCE_MANUAL MBEDTLS_ENTROPY_MAX_SOURCES + +#define MBEDTLS_ENTROPY_SOURCE_STRONG 1 /**< Entropy source is strong */ +#define MBEDTLS_ENTROPY_SOURCE_WEAK 0 /**< Entropy source is weak */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Entropy poll callback pointer + * + * \param data Callback-specific data pointer + * \param output Data to fill + * \param len Maximum size to provide + * \param olen The actual amount of bytes put into the buffer (Can be 0) + * + * \return 0 if no critical failures occurred, + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED otherwise + */ +typedef int (*mbedtls_entropy_f_source_ptr)(void *data, unsigned char *output, size_t len, + size_t *olen); + +/** + * \brief Entropy source state + */ +typedef struct +{ + mbedtls_entropy_f_source_ptr f_source; /**< The entropy source callback */ + void * p_source; /**< The callback data pointer */ + size_t size; /**< Amount received in bytes */ + size_t threshold; /**< Minimum bytes required before release */ + int strong; /**< Is the source strong? */ +} +mbedtls_entropy_source_state; + +/** + * \brief Entropy context structure + */ +typedef struct +{ +#if defined(MBEDTLS_ENTROPY_SHA512_ACCUMULATOR) + mbedtls_sha512_context accumulator; +#else + mbedtls_sha256_context accumulator; +#endif + int source_count; + mbedtls_entropy_source_state source[MBEDTLS_ENTROPY_MAX_SOURCES]; +#if defined(MBEDTLS_HAVEGE_C) + mbedtls_havege_state havege_data; +#endif +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< mutex */ +#endif +#if defined(MBEDTLS_ENTROPY_NV_SEED) + int initial_entropy_run; +#endif +} +mbedtls_entropy_context; + +/** + * \brief Initialize the context + * + * \param ctx Entropy context to initialize + */ +void mbedtls_entropy_init( mbedtls_entropy_context *ctx ); + +/** + * \brief Free the data in the context + * + * \param ctx Entropy context to free + */ +void mbedtls_entropy_free( mbedtls_entropy_context *ctx ); + +/** + * \brief Adds an entropy source to poll + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * \param f_source Entropy function + * \param p_source Function data + * \param threshold Minimum required from source before entropy is released + * ( with mbedtls_entropy_func() ) (in bytes) + * \param strong MBEDTLS_ENTROPY_SOURCE_STRONG or + * MBEDTSL_ENTROPY_SOURCE_WEAK. + * At least one strong source needs to be added. + * Weaker sources (such as the cycle counter) can be used as + * a complement. + * + * \return 0 if successful or MBEDTLS_ERR_ENTROPY_MAX_SOURCES + */ +int mbedtls_entropy_add_source( mbedtls_entropy_context *ctx, + mbedtls_entropy_f_source_ptr f_source, void *p_source, + size_t threshold, int strong ); + +/** + * \brief Trigger an extra gather poll for the accumulator + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * + * \return 0 if successful, or MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_gather( mbedtls_entropy_context *ctx ); + +/** + * \brief Retrieve entropy from the accumulator + * (Maximum length: MBEDTLS_ENTROPY_BLOCK_SIZE) + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param data Entropy context + * \param output Buffer to fill + * \param len Number of bytes desired, must be at most MBEDTLS_ENTROPY_BLOCK_SIZE + * + * \return 0 if successful, or MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_func( void *data, unsigned char *output, size_t len ); + +/** + * \brief Add data to the accumulator manually + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param ctx Entropy context + * \param data Data to add + * \param len Length of data + * + * \return 0 if successful + */ +int mbedtls_entropy_update_manual( mbedtls_entropy_context *ctx, + const unsigned char *data, size_t len ); + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +/** + * \brief Trigger an update of the seed file in NV by using the + * current entropy pool. + * + * \param ctx Entropy context + * + * \return 0 if successful + */ +int mbedtls_entropy_update_nv_seed( mbedtls_entropy_context *ctx ); +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR on file error, or + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_write_seed_file( mbedtls_entropy_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance. No more than MBEDTLS_ENTROPY_MAX_SEED_SIZE bytes are + * read from the seed file. The rest is ignored. + * + * \param ctx Entropy context + * \param path Name of the file + * + * \return 0 if successful, + * MBEDTLS_ERR_ENTROPY_FILE_IO_ERROR on file error, + * MBEDTLS_ERR_ENTROPY_SOURCE_FAILED + */ +int mbedtls_entropy_update_seed_file( mbedtls_entropy_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * This module self-test also calls the entropy self-test, + * mbedtls_entropy_source_self_test(); + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_entropy_self_test( int verbose ); + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) +/** + * \brief Checkup routine + * + * Verifies the integrity of the hardware entropy source + * provided by the function 'mbedtls_hardware_poll()'. + * + * Note this is the only hardware entropy source that is known + * at link time, and other entropy sources configured + * dynamically at runtime by the function + * mbedtls_entropy_add_source() will not be tested. + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_entropy_source_self_test( int verbose ); +#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ +#endif /* MBEDTLS_SELF_TEST */ + +#ifdef __cplusplus +} +#endif + +#endif /* entropy.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/entropy_poll.h b/c++/src/connect/mbedtls/mbedtls/entropy_poll.h new file mode 100644 index 00000000..81258d5f --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/entropy_poll.h @@ -0,0 +1,109 @@ +/** + * \file entropy_poll.h + * + * \brief Platform-specific and custom entropy polling functions + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ENTROPY_POLL_H +#define MBEDTLS_ENTROPY_POLL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Default thresholds for built-in sources, in bytes + */ +#define MBEDTLS_ENTROPY_MIN_PLATFORM 32 /**< Minimum for platform source */ +#define MBEDTLS_ENTROPY_MIN_HAVEGE 32 /**< Minimum for HAVEGE */ +#define MBEDTLS_ENTROPY_MIN_HARDCLOCK 4 /**< Minimum for mbedtls_timing_hardclock() */ +#if !defined(MBEDTLS_ENTROPY_MIN_HARDWARE) +#define MBEDTLS_ENTROPY_MIN_HARDWARE 32 /**< Minimum for the hardware source */ +#endif + +/** + * \brief Entropy poll callback that provides 0 entropy. + */ +#if defined(MBEDTLS_TEST_NULL_ENTROPY) + int mbedtls_null_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if !defined(MBEDTLS_NO_PLATFORM_ENTROPY) +/** + * \brief Platform-specific entropy poll callback + */ +int mbedtls_platform_entropy_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_HAVEGE_C) +/** + * \brief HAVEGE based entropy poll callback + * + * Requires an HAVEGE state as its data pointer. + */ +int mbedtls_havege_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_TIMING_C) +/** + * \brief mbedtls_timing_hardclock-based entropy poll callback + */ +int mbedtls_hardclock_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) +/** + * \brief Entropy poll callback for a hardware source + * + * \warning This is not provided by mbed TLS! + * See \c MBEDTLS_ENTROPY_HARDWARE_ALT in config.h. + * + * \note This must accept NULL as its first argument. + */ +int mbedtls_hardware_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +/** + * \brief Entropy poll callback for a non-volatile seed file + * + * \note This must accept NULL as its first argument. + */ +int mbedtls_nv_seed_poll( void *data, + unsigned char *output, size_t len, size_t *olen ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* entropy_poll.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/error.h b/c++/src/connect/mbedtls/mbedtls/error.h new file mode 100644 index 00000000..5e549f6b --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/error.h @@ -0,0 +1,107 @@ +/** + * \file error.h + * + * \brief Error to string translation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_ERROR_H +#define MBEDTLS_ERROR_H + +#include + +/** + * Error code layout. + * + * Currently we try to keep all error codes within the negative space of 16 + * bits signed integers to support all platforms (-0x0001 - -0x7FFF). In + * addition we'd like to give two layers of information on the error if + * possible. + * + * For that purpose the error codes are segmented in the following manner: + * + * 16 bit error code bit-segmentation + * + * 1 bit - Unused (sign bit) + * 3 bits - High level module ID + * 5 bits - Module-dependent error code + * 7 bits - Low level module errors + * + * For historical reasons, low-level error codes are divided in even and odd, + * even codes were assigned first, and -1 is reserved for other errors. + * + * Low-level module errors (0x0002-0x007E, 0x0003-0x007F) + * + * Module Nr Codes assigned + * MPI 7 0x0002-0x0010 + * GCM 2 0x0012-0x0014 + * BLOWFISH 2 0x0016-0x0018 + * THREADING 3 0x001A-0x001E + * AES 2 0x0020-0x0022 + * CAMELLIA 2 0x0024-0x0026 + * XTEA 1 0x0028-0x0028 + * BASE64 2 0x002A-0x002C + * OID 1 0x002E-0x002E 0x000B-0x000B + * PADLOCK 1 0x0030-0x0030 + * DES 1 0x0032-0x0032 + * CTR_DBRG 4 0x0034-0x003A + * ENTROPY 3 0x003C-0x0040 0x003D-0x003F + * NET 11 0x0042-0x0052 0x0043-0x0045 + * ASN1 7 0x0060-0x006C + * PBKDF2 1 0x007C-0x007C + * HMAC_DRBG 4 0x0003-0x0009 + * CCM 2 0x000D-0x000F + * + * High-level module nr (3 bits - 0x0...-0x7...) + * Name ID Nr of Errors + * PEM 1 9 + * PKCS#12 1 4 (Started from top) + * X509 2 19 + * PKCS5 2 4 (Started from top) + * DHM 3 9 + * PK 3 14 (Started from top) + * RSA 4 9 + * ECP 4 8 (Started from top) + * MD 5 4 + * CIPHER 6 6 + * SSL 6 17 (Started from top) + * SSL 7 31 + * + * Module dependent error code (5 bits 0x.00.-0x.F8.) + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Translate a mbed TLS error code into a string representation, + * Result is truncated if necessary and always includes a terminating + * null byte. + * + * \param errnum error code + * \param buffer buffer to place representation in + * \param buflen length of the buffer + */ +void mbedtls_strerror( int errnum, char *buffer, size_t buflen ); + +#ifdef __cplusplus +} +#endif + +#endif /* error.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/gcm.h b/c++/src/connect/mbedtls/mbedtls/gcm.h new file mode 100644 index 00000000..1b77aaed --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/gcm.h @@ -0,0 +1,220 @@ +/** + * \file gcm.h + * + * \brief Galois/Counter mode for 128-bit block ciphers + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_GCM_H +#define MBEDTLS_GCM_H + +#include "cipher.h" + +#include + +#define MBEDTLS_GCM_ENCRYPT 1 +#define MBEDTLS_GCM_DECRYPT 0 + +#define MBEDTLS_ERR_GCM_AUTH_FAILED -0x0012 /**< Authenticated decryption failed. */ +#define MBEDTLS_ERR_GCM_BAD_INPUT -0x0014 /**< Bad input parameters to function. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief GCM context structure + */ +typedef struct { + mbedtls_cipher_context_t cipher_ctx;/*!< cipher context used */ + uint64_t HL[16]; /*!< Precalculated HTable */ + uint64_t HH[16]; /*!< Precalculated HTable */ + uint64_t len; /*!< Total data length */ + uint64_t add_len; /*!< Total add length */ + unsigned char base_ectr[16];/*!< First ECTR for tag */ + unsigned char y[16]; /*!< Y working value */ + unsigned char buf[16]; /*!< buf working value */ + int mode; /*!< Encrypt or Decrypt */ +} +mbedtls_gcm_context; + +/** + * \brief Initialize GCM context (just makes references valid) + * Makes the context ready for mbedtls_gcm_setkey() or + * mbedtls_gcm_free(). + * + * \param ctx GCM context to initialize + */ +void mbedtls_gcm_init( mbedtls_gcm_context *ctx ); + +/** + * \brief GCM initialization (encryption) + * + * \param ctx GCM context to be initialized + * \param cipher cipher to use (a 128-bit block cipher) + * \param key encryption key + * \param keybits must be 128, 192 or 256 + * + * \return 0 if successful, or a cipher specific error code + */ +int mbedtls_gcm_setkey( mbedtls_gcm_context *ctx, + mbedtls_cipher_id_t cipher, + const unsigned char *key, + unsigned int keybits ); + +/** + * \brief GCM buffer encryption/decryption using a block cipher + * + * \note On encryption, the output buffer can be the same as the input buffer. + * On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param mode MBEDTLS_GCM_ENCRYPT or MBEDTLS_GCM_DECRYPT + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * \param tag_len length of the tag to generate + * \param tag buffer for holding the tag + * + * \return 0 if successful + */ +int mbedtls_gcm_crypt_and_tag( mbedtls_gcm_context *ctx, + int mode, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *input, + unsigned char *output, + size_t tag_len, + unsigned char *tag ); + +/** + * \brief GCM buffer authenticated decryption using a block cipher + * + * \note On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param length length of the input data + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data + * \param add_len length of additional data + * \param tag buffer holding the tag + * \param tag_len length of the tag + * \param input buffer holding the input data + * \param output buffer for holding the output data + * + * \return 0 if successful and authenticated, + * MBEDTLS_ERR_GCM_AUTH_FAILED if tag does not match + */ +int mbedtls_gcm_auth_decrypt( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len, + const unsigned char *tag, + size_t tag_len, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic GCM stream start function + * + * \param ctx GCM context + * \param mode MBEDTLS_GCM_ENCRYPT or MBEDTLS_GCM_DECRYPT + * \param iv initialization vector + * \param iv_len length of IV + * \param add additional data (or NULL if length is 0) + * \param add_len length of additional data + * + * \return 0 if successful + */ +int mbedtls_gcm_starts( mbedtls_gcm_context *ctx, + int mode, + const unsigned char *iv, + size_t iv_len, + const unsigned char *add, + size_t add_len ); + +/** + * \brief Generic GCM update function. Encrypts/decrypts using the + * given GCM context. Expects input to be a multiple of 16 + * bytes! Only the last call before mbedtls_gcm_finish() can be less + * than 16 bytes! + * + * \note On decryption, the output buffer cannot be the same as input buffer. + * If buffers overlap, the output buffer must trail at least 8 bytes + * behind the input buffer. + * + * \param ctx GCM context + * \param length length of the input data + * \param input buffer holding the input data + * \param output buffer for holding the output data + * + * \return 0 if successful or MBEDTLS_ERR_GCM_BAD_INPUT + */ +int mbedtls_gcm_update( mbedtls_gcm_context *ctx, + size_t length, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic GCM finalisation function. Wraps up the GCM stream + * and generates the tag. The tag can have a maximum length of + * 16 bytes. + * + * \param ctx GCM context + * \param tag buffer for holding the tag + * \param tag_len length of the tag to generate (must be at least 4) + * + * \return 0 if successful or MBEDTLS_ERR_GCM_BAD_INPUT + */ +int mbedtls_gcm_finish( mbedtls_gcm_context *ctx, + unsigned char *tag, + size_t tag_len ); + +/** + * \brief Free a GCM context and underlying cipher sub-context + * + * \param ctx GCM context to free + */ +void mbedtls_gcm_free( mbedtls_gcm_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_gcm_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* gcm.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/havege.h b/c++/src/connect/mbedtls/mbedtls/havege.h new file mode 100644 index 00000000..dac5d311 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/havege.h @@ -0,0 +1,74 @@ +/** + * \file havege.h + * + * \brief HAVEGE: HArdware Volatile Entropy Gathering and Expansion + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_HAVEGE_H +#define MBEDTLS_HAVEGE_H + +#include + +#define MBEDTLS_HAVEGE_COLLECT_SIZE 1024 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief HAVEGE state structure + */ +typedef struct +{ + int PT1, PT2, offset[2]; + int pool[MBEDTLS_HAVEGE_COLLECT_SIZE]; + int WALK[8192]; +} +mbedtls_havege_state; + +/** + * \brief HAVEGE initialization + * + * \param hs HAVEGE state to be initialized + */ +void mbedtls_havege_init( mbedtls_havege_state *hs ); + +/** + * \brief Clear HAVEGE state + * + * \param hs HAVEGE state to be cleared + */ +void mbedtls_havege_free( mbedtls_havege_state *hs ); + +/** + * \brief HAVEGE rand function + * + * \param p_rng A HAVEGE state + * \param output Buffer to fill + * \param len Length of buffer + * + * \return 0 + */ +int mbedtls_havege_random( void *p_rng, unsigned char *output, size_t len ); + +#ifdef __cplusplus +} +#endif + +#endif /* havege.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/hmac_drbg.h b/c++/src/connect/mbedtls/mbedtls/hmac_drbg.h new file mode 100644 index 00000000..e3e19422 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/hmac_drbg.h @@ -0,0 +1,299 @@ +/** + * \file hmac_drbg.h + * + * \brief HMAC_DRBG (NIST SP 800-90A) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_HMAC_DRBG_H +#define MBEDTLS_HMAC_DRBG_H + +#include "md.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/* + * Error codes + */ +#define MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG -0x0003 /**< Too many random requested in single call. */ +#define MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG -0x0005 /**< Input too large (Entropy + additional). */ +#define MBEDTLS_ERR_HMAC_DRBG_FILE_IO_ERROR -0x0007 /**< Read/write error in file. */ +#define MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED -0x0009 /**< The entropy source failed. */ + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_HMAC_DRBG_RESEED_INTERVAL) +#define MBEDTLS_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +#endif + +#if !defined(MBEDTLS_HMAC_DRBG_MAX_INPUT) +#define MBEDTLS_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +#endif + +#if !defined(MBEDTLS_HMAC_DRBG_MAX_REQUEST) +#define MBEDTLS_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +#endif + +#if !defined(MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT) +#define MBEDTLS_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ +#endif + +/* \} name SECTION: Module settings */ + +#define MBEDTLS_HMAC_DRBG_PR_OFF 0 /**< No prediction resistance */ +#define MBEDTLS_HMAC_DRBG_PR_ON 1 /**< Prediction resistance enabled */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * HMAC_DRBG context. + */ +typedef struct +{ + /* Working state: the key K is not stored explicitely, + * but is implied by the HMAC context */ + mbedtls_md_context_t md_ctx; /*!< HMAC context (inc. K) */ + unsigned char V[MBEDTLS_MD_MAX_SIZE]; /*!< V in the spec */ + int reseed_counter; /*!< reseed counter */ + + /* Administrative state */ + size_t entropy_len; /*!< entropy bytes grabbed on each (re)seed */ + int prediction_resistance; /*!< enable prediction resistance (Automatic + reseed before every random generation) */ + int reseed_interval; /*!< reseed interval */ + + /* Callbacks */ + int (*f_entropy)(void *, unsigned char *, size_t); /*!< entropy function */ + void *p_entropy; /*!< context for the entropy function */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} mbedtls_hmac_drbg_context; + +/** + * \brief HMAC_DRBG context initialization + * Makes the context ready for mbedtls_hmac_drbg_seed(), + * mbedtls_hmac_drbg_seed_buf() or + * mbedtls_hmac_drbg_free(). + * + * \param ctx HMAC_DRBG context to be initialized + */ +void mbedtls_hmac_drbg_init( mbedtls_hmac_drbg_context *ctx ); + +/** + * \brief HMAC_DRBG initial seeding + * Seed and setup entropy source for future reseeds. + * + * \param ctx HMAC_DRBG context to be seeded + * \param md_info MD algorithm to use for HMAC_DRBG + * \param f_entropy Entropy callback (p_entropy, buffer to fill, buffer + * length) + * \param p_entropy Entropy context + * \param custom Personalization data (Device specific identifiers) + * (Can be NULL) + * \param len Length of personalization data + * + * \note The "security strength" as defined by NIST is set to: + * 128 bits if md_alg is SHA-1, + * 192 bits if md_alg is SHA-224, + * 256 bits if md_alg is SHA-256 or higher. + * Note that SHA-256 is just as efficient as SHA-224. + * + * \return 0 if successful, or + * MBEDTLS_ERR_MD_BAD_INPUT_DATA, or + * MBEDTLS_ERR_MD_ALLOC_FAILED, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED. + */ +int mbedtls_hmac_drbg_seed( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + int (*f_entropy)(void *, unsigned char *, size_t), + void *p_entropy, + const unsigned char *custom, + size_t len ); + +/** + * \brief Initilisation of simpified HMAC_DRBG (never reseeds). + * (For use with deterministic ECDSA.) + * + * \param ctx HMAC_DRBG context to be initialised + * \param md_info MD algorithm to use for HMAC_DRBG + * \param data Concatenation of entropy string and additional data + * \param data_len Length of data in bytes + * + * \return 0 if successful, or + * MBEDTLS_ERR_MD_BAD_INPUT_DATA, or + * MBEDTLS_ERR_MD_ALLOC_FAILED. + */ +int mbedtls_hmac_drbg_seed_buf( mbedtls_hmac_drbg_context *ctx, + const mbedtls_md_info_t * md_info, + const unsigned char *data, size_t data_len ); + +/** + * \brief Enable / disable prediction resistance (Default: Off) + * + * Note: If enabled, entropy is used for ctx->entropy_len before each call! + * Only use this if you have ample supply of good entropy! + * + * \param ctx HMAC_DRBG context + * \param resistance MBEDTLS_HMAC_DRBG_PR_ON or MBEDTLS_HMAC_DRBG_PR_OFF + */ +void mbedtls_hmac_drbg_set_prediction_resistance( mbedtls_hmac_drbg_context *ctx, + int resistance ); + +/** + * \brief Set the amount of entropy grabbed on each reseed + * (Default: given by the security strength, which + * depends on the hash used, see \c mbedtls_hmac_drbg_init() ) + * + * \param ctx HMAC_DRBG context + * \param len Amount of entropy to grab, in bytes + */ +void mbedtls_hmac_drbg_set_entropy_len( mbedtls_hmac_drbg_context *ctx, + size_t len ); + +/** + * \brief Set the reseed interval + * (Default: MBEDTLS_HMAC_DRBG_RESEED_INTERVAL) + * + * \param ctx HMAC_DRBG context + * \param interval Reseed interval + */ +void mbedtls_hmac_drbg_set_reseed_interval( mbedtls_hmac_drbg_context *ctx, + int interval ); + +/** + * \brief HMAC_DRBG update state + * + * \param ctx HMAC_DRBG context + * \param additional Additional data to update state with, or NULL + * \param add_len Length of additional data, or 0 + * + * \note Additional data is optional, pass NULL and 0 as second + * third argument if no additional data is being used. + */ +void mbedtls_hmac_drbg_update( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t add_len ); + +/** + * \brief HMAC_DRBG reseeding (extracts data from entropy source) + * + * \param ctx HMAC_DRBG context + * \param additional Additional data to add to state (Can be NULL) + * \param len Length of additional data + * + * \return 0 if successful, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_hmac_drbg_reseed( mbedtls_hmac_drbg_context *ctx, + const unsigned char *additional, size_t len ); + +/** + * \brief HMAC_DRBG generate random with additional update input + * + * Note: Automatically reseeds if reseed_counter is reached or PR is enabled. + * + * \param p_rng HMAC_DRBG context + * \param output Buffer to fill + * \param output_len Length of the buffer + * \param additional Additional data to update with (can be NULL) + * \param add_len Length of additional data (can be 0) + * + * \return 0 if successful, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG, or + * MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG. + */ +int mbedtls_hmac_drbg_random_with_add( void *p_rng, + unsigned char *output, size_t output_len, + const unsigned char *additional, + size_t add_len ); + +/** + * \brief HMAC_DRBG generate random + * + * Note: Automatically reseeds if reseed_counter is reached or PR is enabled. + * + * \param p_rng HMAC_DRBG context + * \param output Buffer to fill + * \param out_len Length of the buffer + * + * \return 0 if successful, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED, or + * MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG + */ +int mbedtls_hmac_drbg_random( void *p_rng, unsigned char *output, size_t out_len ); + +/** + * \brief Free an HMAC_DRBG context + * + * \param ctx HMAC_DRBG context to free. + */ +void mbedtls_hmac_drbg_free( mbedtls_hmac_drbg_context *ctx ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Write a seed file + * + * \param ctx HMAC_DRBG context + * \param path Name of the file + * + * \return 0 if successful, 1 on file error, or + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED + */ +int mbedtls_hmac_drbg_write_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ); + +/** + * \brief Read and update a seed file. Seed is added to this + * instance + * + * \param ctx HMAC_DRBG context + * \param path Name of the file + * + * \return 0 if successful, 1 on file error, + * MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED or + * MBEDTLS_ERR_HMAC_DRBG_INPUT_TOO_BIG + */ +int mbedtls_hmac_drbg_update_seed_file( mbedtls_hmac_drbg_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ + + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_hmac_drbg_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* hmac_drbg.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/md.h b/c++/src/connect/mbedtls/mbedtls/md.h new file mode 100644 index 00000000..9b996a95 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/md.h @@ -0,0 +1,354 @@ +/** + * \file md.h + * + * \brief Generic message digest wrapper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD_H +#define MBEDTLS_MD_H + +#include + +#define MBEDTLS_ERR_MD_FEATURE_UNAVAILABLE -0x5080 /**< The selected feature is not available. */ +#define MBEDTLS_ERR_MD_BAD_INPUT_DATA -0x5100 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_MD_ALLOC_FAILED -0x5180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_MD_FILE_IO_ERROR -0x5200 /**< Opening or reading of file failed. */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + MBEDTLS_MD_NONE=0, + MBEDTLS_MD_MD2, + MBEDTLS_MD_MD4, + MBEDTLS_MD_MD5, + MBEDTLS_MD_SHA1, + MBEDTLS_MD_SHA224, + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA384, + MBEDTLS_MD_SHA512, + MBEDTLS_MD_RIPEMD160, +} mbedtls_md_type_t; + +#if defined(MBEDTLS_SHA512_C) +#define MBEDTLS_MD_MAX_SIZE 64 /* longest known is SHA512 */ +#else +#define MBEDTLS_MD_MAX_SIZE 32 /* longest known is SHA256 or less */ +#endif + +/** + * Opaque struct defined in md_internal.h + */ +typedef struct mbedtls_md_info_t mbedtls_md_info_t; + +/** + * Generic message digest context. + */ +typedef struct { + /** Information about the associated message digest */ + const mbedtls_md_info_t *md_info; + + /** Digest-specific context */ + void *md_ctx; + + /** HMAC part of the context */ + void *hmac_ctx; +} mbedtls_md_context_t; + +/** + * \brief Returns the list of digests supported by the generic digest module. + * + * \return a statically allocated array of digests, the last entry + * is 0. + */ +const int *mbedtls_md_list( void ); + +/** + * \brief Returns the message digest information associated with the + * given digest name. + * + * \param md_name Name of the digest to search for. + * + * \return The message digest information associated with md_name or + * NULL if not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ); + +/** + * \brief Returns the message digest information associated with the + * given digest type. + * + * \param md_type type of digest to search for. + * + * \return The message digest information associated with md_type or + * NULL if not found. + */ +const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ); + +/** + * \brief Initialize a md_context (as NONE) + * This should always be called first. + * Prepares the context for mbedtls_md_setup() or mbedtls_md_free(). + */ +void mbedtls_md_init( mbedtls_md_context_t *ctx ); + +/** + * \brief Free and clear the internal structures of ctx. + * Can be called at any time after mbedtls_md_init(). + * Mandatory once mbedtls_md_setup() has been called. + */ +void mbedtls_md_free( mbedtls_md_context_t *ctx ); + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +#if defined(MBEDTLS_DEPRECATED_WARNING) +#define MBEDTLS_DEPRECATED __attribute__((deprecated)) +#else +#define MBEDTLS_DEPRECATED +#endif +/** + * \brief Select MD to use and allocate internal structures. + * Should be called after mbedtls_md_init() or mbedtls_md_free(). + * Makes it necessary to call mbedtls_md_free() later. + * + * \deprecated Superseded by mbedtls_md_setup() in 2.0.0 + * + * \param ctx Context to set up. + * \param md_info Message digest to use. + * + * \returns \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure, + * \c MBEDTLS_ERR_MD_ALLOC_FAILED memory allocation failure. + */ +int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) MBEDTLS_DEPRECATED; +#undef MBEDTLS_DEPRECATED +#endif /* MBEDTLS_DEPRECATED_REMOVED */ + +/** + * \brief Select MD to use and allocate internal structures. + * Should be called after mbedtls_md_init() or mbedtls_md_free(). + * Makes it necessary to call mbedtls_md_free() later. + * + * \param ctx Context to set up. + * \param md_info Message digest to use. + * \param hmac 0 to save some memory if HMAC will not be used, + * non-zero is HMAC is going to be used with this context. + * + * \returns \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure, + * \c MBEDTLS_ERR_MD_ALLOC_FAILED memory allocation failure. + */ +int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ); + +/** + * \brief Clone the state of an MD context + * + * \note The two contexts must have been setup to the same type + * (cloning from SHA-256 to SHA-512 make no sense). + * + * \warning Only clones the MD state, not the HMAC state! (for now) + * + * \param dst The destination context + * \param src The context to be cloned + * + * \return \c 0 on success, + * \c MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter failure. + */ +int mbedtls_md_clone( mbedtls_md_context_t *dst, + const mbedtls_md_context_t *src ); + +/** + * \brief Returns the size of the message digest output. + * + * \param md_info message digest info + * + * \return size of the message digest output in bytes. + */ +unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info ); + +/** + * \brief Returns the type of the message digest output. + * + * \param md_info message digest info + * + * \return type of the message digest output. + */ +mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info ); + +/** + * \brief Returns the name of the message digest output. + * + * \param md_info message digest info + * + * \return name of the message digest output. + */ +const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ); + +/** + * \brief Prepare the context to digest a new message. + * Generally called after mbedtls_md_setup() or mbedtls_md_finish(). + * Followed by mbedtls_md_update(). + * + * \param ctx generic message digest context. + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_starts( mbedtls_md_context_t *ctx ); + +/** + * \brief Generic message digest process buffer + * Called between mbedtls_md_starts() and mbedtls_md_finish(). + * May be called repeatedly. + * + * \param ctx Generic message digest context + * \param input buffer holding the datal + * \param ilen length of the input data + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief Generic message digest final digest + * Called after mbedtls_md_update(). + * Usually followed by mbedtls_md_free() or mbedtls_md_starts(). + * + * \param ctx Generic message digest context + * \param output Generic message digest checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ); + +/** + * \brief Output = message_digest( input buffer ) + * + * \param md_info message digest info + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic message digest checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Output = message_digest( file contents ) + * + * \param md_info message digest info + * \param path input file name + * \param output generic message digest checksum result + * + * \return 0 if successful, + * MBEDTLS_ERR_MD_FILE_IO_ERROR if file input failed, + * MBEDTLS_ERR_MD_BAD_INPUT_DATA if md_info was NULL. + */ +int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, + unsigned char *output ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Set HMAC key and prepare to authenticate a new message. + * Usually called after mbedtls_md_setup() or mbedtls_md_hmac_finish(). + * + * \param ctx HMAC context + * \param key HMAC secret key + * \param keylen length of the HMAC key in bytes + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, + size_t keylen ); + +/** + * \brief Generic HMAC process buffer. + * Called between mbedtls_md_hmac_starts() or mbedtls_md_hmac_reset() + * and mbedtls_md_hmac_finish(). + * May be called repeatedly. + * + * \param ctx HMAC context + * \param input buffer holding the data + * \param ilen length of the input data + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief Output HMAC. + * Called after mbedtls_md_hmac_update(). + * Usually followed by mbedtls_md_hmac_reset(), + * mbedtls_md_hmac_starts(), or mbedtls_md_free(). + * + * \param ctx HMAC context + * \param output Generic HMAC checksum result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output); + +/** + * \brief Prepare to authenticate a new message with the same key. + * Called after mbedtls_md_hmac_finish() and before + * mbedtls_md_hmac_update(). + * + * \param ctx HMAC context to be reset + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ); + +/** + * \brief Output = Generic_HMAC( hmac key, input buffer ) + * + * \param md_info message digest info + * \param key HMAC secret key + * \param keylen length of the HMAC key in bytes + * \param input buffer holding the data + * \param ilen length of the input data + * \param output Generic HMAC-result + * + * \returns 0 on success, MBEDTLS_ERR_MD_BAD_INPUT_DATA if parameter + * verification fails. + */ +int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ); + +/* Internal use */ +int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_MD_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/md2.h b/c++/src/connect/mbedtls/mbedtls/md2.h new file mode 100644 index 00000000..0f93fbf4 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/md2.h @@ -0,0 +1,136 @@ +/** + * \file md2.h + * + * \brief MD2 message digest algorithm (hash function) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD2_H +#define MBEDTLS_MD2_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#if !defined(MBEDTLS_MD2_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD2 context structure + */ +typedef struct +{ + unsigned char cksum[16]; /*!< checksum of the data block */ + unsigned char state[48]; /*!< intermediate digest state */ + unsigned char buffer[16]; /*!< data block being processed */ + size_t left; /*!< amount of data in buffer */ +} +mbedtls_md2_context; + +/** + * \brief Initialize MD2 context + * + * \param ctx MD2 context to be initialized + */ +void mbedtls_md2_init( mbedtls_md2_context *ctx ); + +/** + * \brief Clear MD2 context + * + * \param ctx MD2 context to be cleared + */ +void mbedtls_md2_free( mbedtls_md2_context *ctx ); + +/** + * \brief Clone (the state of) an MD2 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_md2_clone( mbedtls_md2_context *dst, + const mbedtls_md2_context *src ); + +/** + * \brief MD2 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_md2_starts( mbedtls_md2_context *ctx ); + +/** + * \brief MD2 process buffer + * + * \param ctx MD2 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_md2_update( mbedtls_md2_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD2 final digest + * + * \param ctx MD2 context + * \param output MD2 checksum result + */ +void mbedtls_md2_finish( mbedtls_md2_context *ctx, unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_MD2_ALT */ +#include "md2_alt.h" +#endif /* MBEDTLS_MD2_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD2( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD2 checksum result + */ +void mbedtls_md2( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_md2_self_test( int verbose ); + +/* Internal use */ +void mbedtls_md2_process( mbedtls_md2_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md2.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/md4.h b/c++/src/connect/mbedtls/mbedtls/md4.h new file mode 100644 index 00000000..45214d41 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/md4.h @@ -0,0 +1,136 @@ +/** + * \file md4.h + * + * \brief MD4 message digest algorithm (hash function) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD4_H +#define MBEDTLS_MD4_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_MD4_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD4 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_md4_context; + +/** + * \brief Initialize MD4 context + * + * \param ctx MD4 context to be initialized + */ +void mbedtls_md4_init( mbedtls_md4_context *ctx ); + +/** + * \brief Clear MD4 context + * + * \param ctx MD4 context to be cleared + */ +void mbedtls_md4_free( mbedtls_md4_context *ctx ); + +/** + * \brief Clone (the state of) an MD4 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_md4_clone( mbedtls_md4_context *dst, + const mbedtls_md4_context *src ); + +/** + * \brief MD4 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_md4_starts( mbedtls_md4_context *ctx ); + +/** + * \brief MD4 process buffer + * + * \param ctx MD4 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_md4_update( mbedtls_md4_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD4 final digest + * + * \param ctx MD4 context + * \param output MD4 checksum result + */ +void mbedtls_md4_finish( mbedtls_md4_context *ctx, unsigned char output[16] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_MD4_ALT */ +#include "md4_alt.h" +#endif /* MBEDTLS_MD4_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD4( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD4 checksum result + */ +void mbedtls_md4( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_md4_self_test( int verbose ); + +/* Internal use */ +void mbedtls_md4_process( mbedtls_md4_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md4.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/md5.h b/c++/src/connect/mbedtls/mbedtls/md5.h new file mode 100644 index 00000000..5a64061a --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/md5.h @@ -0,0 +1,136 @@ +/** + * \file md5.h + * + * \brief MD5 message digest algorithm (hash function) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD5_H +#define MBEDTLS_MD5_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_MD5_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief MD5 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[4]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_md5_context; + +/** + * \brief Initialize MD5 context + * + * \param ctx MD5 context to be initialized + */ +void mbedtls_md5_init( mbedtls_md5_context *ctx ); + +/** + * \brief Clear MD5 context + * + * \param ctx MD5 context to be cleared + */ +void mbedtls_md5_free( mbedtls_md5_context *ctx ); + +/** + * \brief Clone (the state of) an MD5 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_md5_clone( mbedtls_md5_context *dst, + const mbedtls_md5_context *src ); + +/** + * \brief MD5 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_md5_starts( mbedtls_md5_context *ctx ); + +/** + * \brief MD5 process buffer + * + * \param ctx MD5 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief MD5 final digest + * + * \param ctx MD5 context + * \param output MD5 checksum result + */ +void mbedtls_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] ); + +/* Internal use */ +void mbedtls_md5_process( mbedtls_md5_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_MD5_ALT */ +#include "md5_alt.h" +#endif /* MBEDTLS_MD5_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = MD5( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output MD5 checksum result + */ +void mbedtls_md5( const unsigned char *input, size_t ilen, unsigned char output[16] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_md5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_md5.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/md_internal.h b/c++/src/connect/mbedtls/mbedtls/md_internal.h new file mode 100644 index 00000000..e2441bbc --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/md_internal.h @@ -0,0 +1,114 @@ +/** + * \file md_internal.h + * + * \brief Message digest wrappers. + * + * \warning This in an internal header. Do not include directly. + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MD_WRAP_H +#define MBEDTLS_MD_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Message digest information. + * Allows message digest functions to be called in a generic way. + */ +struct mbedtls_md_info_t +{ + /** Digest identifier */ + mbedtls_md_type_t type; + + /** Name of the message digest */ + const char * name; + + /** Output length of the digest function in bytes */ + int size; + + /** Block length of the digest function in bytes */ + int block_size; + + /** Digest initialisation function */ + void (*starts_func)( void *ctx ); + + /** Digest update function */ + void (*update_func)( void *ctx, const unsigned char *input, size_t ilen ); + + /** Digest finalisation function */ + void (*finish_func)( void *ctx, unsigned char *output ); + + /** Generic digest function */ + void (*digest_func)( const unsigned char *input, size_t ilen, + unsigned char *output ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + + /** Clone state from a context */ + void (*clone_func)( void *dst, const void *src ); + + /** Internal use only */ + void (*process_func)( void *ctx, const unsigned char *input ); +}; + +#if defined(MBEDTLS_MD2_C) +extern const mbedtls_md_info_t mbedtls_md2_info; +#endif +#if defined(MBEDTLS_MD4_C) +extern const mbedtls_md_info_t mbedtls_md4_info; +#endif +#if defined(MBEDTLS_MD5_C) +extern const mbedtls_md_info_t mbedtls_md5_info; +#endif +#if defined(MBEDTLS_RIPEMD160_C) +extern const mbedtls_md_info_t mbedtls_ripemd160_info; +#endif +#if defined(MBEDTLS_SHA1_C) +extern const mbedtls_md_info_t mbedtls_sha1_info; +#endif +#if defined(MBEDTLS_SHA256_C) +extern const mbedtls_md_info_t mbedtls_sha224_info; +extern const mbedtls_md_info_t mbedtls_sha256_info; +#endif +#if defined(MBEDTLS_SHA512_C) +extern const mbedtls_md_info_t mbedtls_sha384_info; +extern const mbedtls_md_info_t mbedtls_sha512_info; +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_MD_WRAP_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/memory_buffer_alloc.h b/c++/src/connect/mbedtls/mbedtls/memory_buffer_alloc.h new file mode 100644 index 00000000..d5df316f --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/memory_buffer_alloc.h @@ -0,0 +1,150 @@ +/** + * \file memory_buffer_alloc.h + * + * \brief Buffer-based memory allocator + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_MEMORY_BUFFER_ALLOC_H +#define MBEDTLS_MEMORY_BUFFER_ALLOC_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_MEMORY_ALIGN_MULTIPLE) +#define MBEDTLS_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ +#endif + +/* \} name SECTION: Module settings */ + +#define MBEDTLS_MEMORY_VERIFY_NONE 0 +#define MBEDTLS_MEMORY_VERIFY_ALLOC (1 << 0) +#define MBEDTLS_MEMORY_VERIFY_FREE (1 << 1) +#define MBEDTLS_MEMORY_VERIFY_ALWAYS (MBEDTLS_MEMORY_VERIFY_ALLOC | MBEDTLS_MEMORY_VERIFY_FREE) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Initialize use of stack-based memory allocator. + * The stack-based allocator does memory management inside the + * presented buffer and does not call calloc() and free(). + * It sets the global mbedtls_calloc() and mbedtls_free() pointers + * to its own functions. + * (Provided mbedtls_calloc() and mbedtls_free() are thread-safe if + * MBEDTLS_THREADING_C is defined) + * + * \note This code is not optimized and provides a straight-forward + * implementation of a stack-based memory allocator. + * + * \param buf buffer to use as heap + * \param len size of the buffer + */ +void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len ); + +/** + * \brief Free the mutex for thread-safety and clear remaining memory + */ +void mbedtls_memory_buffer_alloc_free( void ); + +/** + * \brief Determine when the allocator should automatically verify the state + * of the entire chain of headers / meta-data. + * (Default: MBEDTLS_MEMORY_VERIFY_NONE) + * + * \param verify One of MBEDTLS_MEMORY_VERIFY_NONE, MBEDTLS_MEMORY_VERIFY_ALLOC, + * MBEDTLS_MEMORY_VERIFY_FREE or MBEDTLS_MEMORY_VERIFY_ALWAYS + */ +void mbedtls_memory_buffer_set_verify( int verify ); + +#if defined(MBEDTLS_MEMORY_DEBUG) +/** + * \brief Print out the status of the allocated memory (primarily for use + * after a program should have de-allocated all memory) + * Prints out a list of 'still allocated' blocks and their stack + * trace if MBEDTLS_MEMORY_BACKTRACE is defined. + */ +void mbedtls_memory_buffer_alloc_status( void ); + +/** + * \brief Get the peak heap usage so far + * + * \param max_used Peak number of bytes in use or committed. This + * includes bytes in allocated blocks too small to split + * into smaller blocks but larger than the requested size. + * \param max_blocks Peak number of blocks in use, including free and used + */ +void mbedtls_memory_buffer_alloc_max_get( size_t *max_used, size_t *max_blocks ); + +/** + * \brief Reset peak statistics + */ +void mbedtls_memory_buffer_alloc_max_reset( void ); + +/** + * \brief Get the current heap usage + * + * \param cur_used Current number of bytes in use or committed. This + * includes bytes in allocated blocks too small to split + * into smaller blocks but larger than the requested size. + * \param cur_blocks Current number of blocks in use, including free and used + */ +void mbedtls_memory_buffer_alloc_cur_get( size_t *cur_used, size_t *cur_blocks ); +#endif /* MBEDTLS_MEMORY_DEBUG */ + +/** + * \brief Verifies that all headers in the memory buffer are correct + * and contain sane values. Helps debug buffer-overflow errors. + * + * Prints out first failure if MBEDTLS_MEMORY_DEBUG is defined. + * Prints out full header information if MBEDTLS_MEMORY_DEBUG + * is defined. (Includes stack trace information for each block if + * MBEDTLS_MEMORY_BACKTRACE is defined as well). + * + * \return 0 if verified, 1 otherwise + */ +int mbedtls_memory_buffer_alloc_verify( void ); + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_memory_buffer_alloc_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* memory_buffer_alloc.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ncbicxx_rename_mbedtls.h b/c++/src/connect/mbedtls/mbedtls/ncbicxx_rename_mbedtls.h new file mode 100644 index 00000000..e47031ed --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ncbicxx_rename_mbedtls.h @@ -0,0 +1,1450 @@ +/* + nm -g -defined-only connect/mbedtls/?*.o | \ + awk '/ / { s=substr($3, 2); print "#define", s " \\\n " s "_ncbicxx_2_4_2" }' + */ +#define mbedtls_aes_crypt_cbc \ + mbedtls_aes_crypt_cbc_ncbicxx_2_4_2 +#define mbedtls_aes_crypt_cfb128 \ + mbedtls_aes_crypt_cfb128_ncbicxx_2_4_2 +#define mbedtls_aes_crypt_cfb8 \ + mbedtls_aes_crypt_cfb8_ncbicxx_2_4_2 +#define mbedtls_aes_crypt_ctr \ + mbedtls_aes_crypt_ctr_ncbicxx_2_4_2 +#define mbedtls_aes_crypt_ecb \ + mbedtls_aes_crypt_ecb_ncbicxx_2_4_2 +#define mbedtls_aes_decrypt \ + mbedtls_aes_decrypt_ncbicxx_2_4_2 +#define mbedtls_aes_encrypt \ + mbedtls_aes_encrypt_ncbicxx_2_4_2 +#define mbedtls_aes_free \ + mbedtls_aes_free_ncbicxx_2_4_2 +#define mbedtls_aes_init \ + mbedtls_aes_init_ncbicxx_2_4_2 +#define mbedtls_aes_self_test \ + mbedtls_aes_self_test_ncbicxx_2_4_2 +#define mbedtls_aes_setkey_dec \ + mbedtls_aes_setkey_dec_ncbicxx_2_4_2 +#define mbedtls_aes_setkey_enc \ + mbedtls_aes_setkey_enc_ncbicxx_2_4_2 +#define mbedtls_aesni_crypt_ecb \ + mbedtls_aesni_crypt_ecb_ncbicxx_2_4_2 +#define mbedtls_aesni_gcm_mult \ + mbedtls_aesni_gcm_mult_ncbicxx_2_4_2 +#define mbedtls_aesni_has_support \ + mbedtls_aesni_has_support_ncbicxx_2_4_2 +#define mbedtls_aesni_inverse_key \ + mbedtls_aesni_inverse_key_ncbicxx_2_4_2 +#define mbedtls_aesni_setkey_enc \ + mbedtls_aesni_setkey_enc_ncbicxx_2_4_2 +#define mbedtls_arc4_crypt \ + mbedtls_arc4_crypt_ncbicxx_2_4_2 +#define mbedtls_arc4_free \ + mbedtls_arc4_free_ncbicxx_2_4_2 +#define mbedtls_arc4_init \ + mbedtls_arc4_init_ncbicxx_2_4_2 +#define mbedtls_arc4_self_test \ + mbedtls_arc4_self_test_ncbicxx_2_4_2 +#define mbedtls_arc4_setup \ + mbedtls_arc4_setup_ncbicxx_2_4_2 +#define mbedtls_asn1_find_named_data \ + mbedtls_asn1_find_named_data_ncbicxx_2_4_2 +#define mbedtls_asn1_free_named_data \ + mbedtls_asn1_free_named_data_ncbicxx_2_4_2 +#define mbedtls_asn1_free_named_data_list \ + mbedtls_asn1_free_named_data_list_ncbicxx_2_4_2 +#define mbedtls_asn1_get_alg \ + mbedtls_asn1_get_alg_ncbicxx_2_4_2 +#define mbedtls_asn1_get_alg_null \ + mbedtls_asn1_get_alg_null_ncbicxx_2_4_2 +#define mbedtls_asn1_get_bitstring \ + mbedtls_asn1_get_bitstring_ncbicxx_2_4_2 +#define mbedtls_asn1_get_bitstring_null \ + mbedtls_asn1_get_bitstring_null_ncbicxx_2_4_2 +#define mbedtls_asn1_get_bool \ + mbedtls_asn1_get_bool_ncbicxx_2_4_2 +#define mbedtls_asn1_get_int \ + mbedtls_asn1_get_int_ncbicxx_2_4_2 +#define mbedtls_asn1_get_len \ + mbedtls_asn1_get_len_ncbicxx_2_4_2 +#define mbedtls_asn1_get_mpi \ + mbedtls_asn1_get_mpi_ncbicxx_2_4_2 +#define mbedtls_asn1_get_sequence_of \ + mbedtls_asn1_get_sequence_of_ncbicxx_2_4_2 +#define mbedtls_asn1_get_tag \ + mbedtls_asn1_get_tag_ncbicxx_2_4_2 +#define mbedtls_asn1_store_named_data \ + mbedtls_asn1_store_named_data_ncbicxx_2_4_2 +#define mbedtls_asn1_write_algorithm_identifier \ + mbedtls_asn1_write_algorithm_identifier_ncbicxx_2_4_2 +#define mbedtls_asn1_write_bitstring \ + mbedtls_asn1_write_bitstring_ncbicxx_2_4_2 +#define mbedtls_asn1_write_bool \ + mbedtls_asn1_write_bool_ncbicxx_2_4_2 +#define mbedtls_asn1_write_ia5_string \ + mbedtls_asn1_write_ia5_string_ncbicxx_2_4_2 +#define mbedtls_asn1_write_int \ + mbedtls_asn1_write_int_ncbicxx_2_4_2 +#define mbedtls_asn1_write_len \ + mbedtls_asn1_write_len_ncbicxx_2_4_2 +#define mbedtls_asn1_write_mpi \ + mbedtls_asn1_write_mpi_ncbicxx_2_4_2 +#define mbedtls_asn1_write_null \ + mbedtls_asn1_write_null_ncbicxx_2_4_2 +#define mbedtls_asn1_write_octet_string \ + mbedtls_asn1_write_octet_string_ncbicxx_2_4_2 +#define mbedtls_asn1_write_oid \ + mbedtls_asn1_write_oid_ncbicxx_2_4_2 +#define mbedtls_asn1_write_printable_string \ + mbedtls_asn1_write_printable_string_ncbicxx_2_4_2 +#define mbedtls_asn1_write_raw_buffer \ + mbedtls_asn1_write_raw_buffer_ncbicxx_2_4_2 +#define mbedtls_asn1_write_tag \ + mbedtls_asn1_write_tag_ncbicxx_2_4_2 +#define mbedtls_base64_decode \ + mbedtls_base64_decode_ncbicxx_2_4_2 +#define mbedtls_base64_encode \ + mbedtls_base64_encode_ncbicxx_2_4_2 +#define mbedtls_base64_self_test \ + mbedtls_base64_self_test_ncbicxx_2_4_2 +#define mbedtls_mpi_add_abs \ + mbedtls_mpi_add_abs_ncbicxx_2_4_2 +#define mbedtls_mpi_add_int \ + mbedtls_mpi_add_int_ncbicxx_2_4_2 +#define mbedtls_mpi_add_mpi \ + mbedtls_mpi_add_mpi_ncbicxx_2_4_2 +#define mbedtls_mpi_bitlen \ + mbedtls_mpi_bitlen_ncbicxx_2_4_2 +#define mbedtls_mpi_cmp_abs \ + mbedtls_mpi_cmp_abs_ncbicxx_2_4_2 +#define mbedtls_mpi_cmp_int \ + mbedtls_mpi_cmp_int_ncbicxx_2_4_2 +#define mbedtls_mpi_cmp_mpi \ + mbedtls_mpi_cmp_mpi_ncbicxx_2_4_2 +#define mbedtls_mpi_copy \ + mbedtls_mpi_copy_ncbicxx_2_4_2 +#define mbedtls_mpi_div_int \ + mbedtls_mpi_div_int_ncbicxx_2_4_2 +#define mbedtls_mpi_div_mpi \ + mbedtls_mpi_div_mpi_ncbicxx_2_4_2 +#define mbedtls_mpi_exp_mod \ + mbedtls_mpi_exp_mod_ncbicxx_2_4_2 +#define mbedtls_mpi_fill_random \ + mbedtls_mpi_fill_random_ncbicxx_2_4_2 +#define mbedtls_mpi_free \ + mbedtls_mpi_free_ncbicxx_2_4_2 +#define mbedtls_mpi_gcd \ + mbedtls_mpi_gcd_ncbicxx_2_4_2 +#define mbedtls_mpi_gen_prime \ + mbedtls_mpi_gen_prime_ncbicxx_2_4_2 +#define mbedtls_mpi_get_bit \ + mbedtls_mpi_get_bit_ncbicxx_2_4_2 +#define mbedtls_mpi_grow \ + mbedtls_mpi_grow_ncbicxx_2_4_2 +#define mbedtls_mpi_init \ + mbedtls_mpi_init_ncbicxx_2_4_2 +#define mbedtls_mpi_inv_mod \ + mbedtls_mpi_inv_mod_ncbicxx_2_4_2 +#define mbedtls_mpi_is_prime \ + mbedtls_mpi_is_prime_ncbicxx_2_4_2 +#define mbedtls_mpi_lsb \ + mbedtls_mpi_lsb_ncbicxx_2_4_2 +#define mbedtls_mpi_lset \ + mbedtls_mpi_lset_ncbicxx_2_4_2 +#define mbedtls_mpi_mod_int \ + mbedtls_mpi_mod_int_ncbicxx_2_4_2 +#define mbedtls_mpi_mod_mpi \ + mbedtls_mpi_mod_mpi_ncbicxx_2_4_2 +#define mbedtls_mpi_mul_int \ + mbedtls_mpi_mul_int_ncbicxx_2_4_2 +#define mbedtls_mpi_mul_mpi \ + mbedtls_mpi_mul_mpi_ncbicxx_2_4_2 +#define mbedtls_mpi_read_binary \ + mbedtls_mpi_read_binary_ncbicxx_2_4_2 +#define mbedtls_mpi_read_file \ + mbedtls_mpi_read_file_ncbicxx_2_4_2 +#define mbedtls_mpi_read_string \ + mbedtls_mpi_read_string_ncbicxx_2_4_2 +#define mbedtls_mpi_safe_cond_assign \ + mbedtls_mpi_safe_cond_assign_ncbicxx_2_4_2 +#define mbedtls_mpi_safe_cond_swap \ + mbedtls_mpi_safe_cond_swap_ncbicxx_2_4_2 +#define mbedtls_mpi_self_test \ + mbedtls_mpi_self_test_ncbicxx_2_4_2 +#define mbedtls_mpi_set_bit \ + mbedtls_mpi_set_bit_ncbicxx_2_4_2 +#define mbedtls_mpi_shift_l \ + mbedtls_mpi_shift_l_ncbicxx_2_4_2 +#define mbedtls_mpi_shift_r \ + mbedtls_mpi_shift_r_ncbicxx_2_4_2 +#define mbedtls_mpi_shrink \ + mbedtls_mpi_shrink_ncbicxx_2_4_2 +#define mbedtls_mpi_size \ + mbedtls_mpi_size_ncbicxx_2_4_2 +#define mbedtls_mpi_sub_abs \ + mbedtls_mpi_sub_abs_ncbicxx_2_4_2 +#define mbedtls_mpi_sub_int \ + mbedtls_mpi_sub_int_ncbicxx_2_4_2 +#define mbedtls_mpi_sub_mpi \ + mbedtls_mpi_sub_mpi_ncbicxx_2_4_2 +#define mbedtls_mpi_swap \ + mbedtls_mpi_swap_ncbicxx_2_4_2 +#define mbedtls_mpi_write_binary \ + mbedtls_mpi_write_binary_ncbicxx_2_4_2 +#define mbedtls_mpi_write_file \ + mbedtls_mpi_write_file_ncbicxx_2_4_2 +#define mbedtls_mpi_write_string \ + mbedtls_mpi_write_string_ncbicxx_2_4_2 +#define mbedtls_blowfish_crypt_cbc \ + mbedtls_blowfish_crypt_cbc_ncbicxx_2_4_2 +#define mbedtls_blowfish_crypt_cfb64 \ + mbedtls_blowfish_crypt_cfb64_ncbicxx_2_4_2 +#define mbedtls_blowfish_crypt_ctr \ + mbedtls_blowfish_crypt_ctr_ncbicxx_2_4_2 +#define mbedtls_blowfish_crypt_ecb \ + mbedtls_blowfish_crypt_ecb_ncbicxx_2_4_2 +#define mbedtls_blowfish_free \ + mbedtls_blowfish_free_ncbicxx_2_4_2 +#define mbedtls_blowfish_init \ + mbedtls_blowfish_init_ncbicxx_2_4_2 +#define mbedtls_blowfish_setkey \ + mbedtls_blowfish_setkey_ncbicxx_2_4_2 +#define mbedtls_camellia_crypt_cbc \ + mbedtls_camellia_crypt_cbc_ncbicxx_2_4_2 +#define mbedtls_camellia_crypt_cfb128 \ + mbedtls_camellia_crypt_cfb128_ncbicxx_2_4_2 +#define mbedtls_camellia_crypt_ctr \ + mbedtls_camellia_crypt_ctr_ncbicxx_2_4_2 +#define mbedtls_camellia_crypt_ecb \ + mbedtls_camellia_crypt_ecb_ncbicxx_2_4_2 +#define mbedtls_camellia_free \ + mbedtls_camellia_free_ncbicxx_2_4_2 +#define mbedtls_camellia_init \ + mbedtls_camellia_init_ncbicxx_2_4_2 +#define mbedtls_camellia_self_test \ + mbedtls_camellia_self_test_ncbicxx_2_4_2 +#define mbedtls_camellia_setkey_dec \ + mbedtls_camellia_setkey_dec_ncbicxx_2_4_2 +#define mbedtls_camellia_setkey_enc \ + mbedtls_camellia_setkey_enc_ncbicxx_2_4_2 +#define mbedtls_ccm_auth_decrypt \ + mbedtls_ccm_auth_decrypt_ncbicxx_2_4_2 +#define mbedtls_ccm_encrypt_and_tag \ + mbedtls_ccm_encrypt_and_tag_ncbicxx_2_4_2 +#define mbedtls_ccm_free \ + mbedtls_ccm_free_ncbicxx_2_4_2 +#define mbedtls_ccm_init \ + mbedtls_ccm_init_ncbicxx_2_4_2 +#define mbedtls_ccm_self_test \ + mbedtls_ccm_self_test_ncbicxx_2_4_2 +#define mbedtls_ccm_setkey \ + mbedtls_ccm_setkey_ncbicxx_2_4_2 +#define mbedtls_test_ca_crt \ + mbedtls_test_ca_crt_ncbicxx_2_4_2 +#define mbedtls_test_ca_crt_ec \ + mbedtls_test_ca_crt_ec_ncbicxx_2_4_2 +#define mbedtls_test_ca_crt_ec_len \ + mbedtls_test_ca_crt_ec_len_ncbicxx_2_4_2 +#define mbedtls_test_ca_crt_len \ + mbedtls_test_ca_crt_len_ncbicxx_2_4_2 +#define mbedtls_test_ca_crt_rsa \ + mbedtls_test_ca_crt_rsa_ncbicxx_2_4_2 +#define mbedtls_test_ca_crt_rsa_len \ + mbedtls_test_ca_crt_rsa_len_ncbicxx_2_4_2 +#define mbedtls_test_ca_key \ + mbedtls_test_ca_key_ncbicxx_2_4_2 +#define mbedtls_test_ca_key_ec \ + mbedtls_test_ca_key_ec_ncbicxx_2_4_2 +#define mbedtls_test_ca_key_ec_len \ + mbedtls_test_ca_key_ec_len_ncbicxx_2_4_2 +#define mbedtls_test_ca_key_len \ + mbedtls_test_ca_key_len_ncbicxx_2_4_2 +#define mbedtls_test_ca_key_rsa \ + mbedtls_test_ca_key_rsa_ncbicxx_2_4_2 +#define mbedtls_test_ca_key_rsa_len \ + mbedtls_test_ca_key_rsa_len_ncbicxx_2_4_2 +#define mbedtls_test_ca_pwd \ + mbedtls_test_ca_pwd_ncbicxx_2_4_2 +#define mbedtls_test_ca_pwd_ec \ + mbedtls_test_ca_pwd_ec_ncbicxx_2_4_2 +#define mbedtls_test_ca_pwd_ec_len \ + mbedtls_test_ca_pwd_ec_len_ncbicxx_2_4_2 +#define mbedtls_test_ca_pwd_len \ + mbedtls_test_ca_pwd_len_ncbicxx_2_4_2 +#define mbedtls_test_ca_pwd_rsa \ + mbedtls_test_ca_pwd_rsa_ncbicxx_2_4_2 +#define mbedtls_test_ca_pwd_rsa_len \ + mbedtls_test_ca_pwd_rsa_len_ncbicxx_2_4_2 +#define mbedtls_test_cas \ + mbedtls_test_cas_ncbicxx_2_4_2 +#define mbedtls_test_cas_len \ + mbedtls_test_cas_len_ncbicxx_2_4_2 +#define mbedtls_test_cas_pem \ + mbedtls_test_cas_pem_ncbicxx_2_4_2 +#define mbedtls_test_cas_pem_len \ + mbedtls_test_cas_pem_len_ncbicxx_2_4_2 +#define mbedtls_test_cli_crt \ + mbedtls_test_cli_crt_ncbicxx_2_4_2 +#define mbedtls_test_cli_crt_ec \ + mbedtls_test_cli_crt_ec_ncbicxx_2_4_2 +#define mbedtls_test_cli_crt_ec_len \ + mbedtls_test_cli_crt_ec_len_ncbicxx_2_4_2 +#define mbedtls_test_cli_crt_len \ + mbedtls_test_cli_crt_len_ncbicxx_2_4_2 +#define mbedtls_test_cli_crt_rsa \ + mbedtls_test_cli_crt_rsa_ncbicxx_2_4_2 +#define mbedtls_test_cli_crt_rsa_len \ + mbedtls_test_cli_crt_rsa_len_ncbicxx_2_4_2 +#define mbedtls_test_cli_key \ + mbedtls_test_cli_key_ncbicxx_2_4_2 +#define mbedtls_test_cli_key_ec \ + mbedtls_test_cli_key_ec_ncbicxx_2_4_2 +#define mbedtls_test_cli_key_ec_len \ + mbedtls_test_cli_key_ec_len_ncbicxx_2_4_2 +#define mbedtls_test_cli_key_len \ + mbedtls_test_cli_key_len_ncbicxx_2_4_2 +#define mbedtls_test_cli_key_rsa \ + mbedtls_test_cli_key_rsa_ncbicxx_2_4_2 +#define mbedtls_test_cli_key_rsa_len \ + mbedtls_test_cli_key_rsa_len_ncbicxx_2_4_2 +#define mbedtls_test_srv_crt \ + mbedtls_test_srv_crt_ncbicxx_2_4_2 +#define mbedtls_test_srv_crt_ec \ + mbedtls_test_srv_crt_ec_ncbicxx_2_4_2 +#define mbedtls_test_srv_crt_ec_len \ + mbedtls_test_srv_crt_ec_len_ncbicxx_2_4_2 +#define mbedtls_test_srv_crt_len \ + mbedtls_test_srv_crt_len_ncbicxx_2_4_2 +#define mbedtls_test_srv_crt_rsa \ + mbedtls_test_srv_crt_rsa_ncbicxx_2_4_2 +#define mbedtls_test_srv_crt_rsa_len \ + mbedtls_test_srv_crt_rsa_len_ncbicxx_2_4_2 +#define mbedtls_test_srv_key \ + mbedtls_test_srv_key_ncbicxx_2_4_2 +#define mbedtls_test_srv_key_ec \ + mbedtls_test_srv_key_ec_ncbicxx_2_4_2 +#define mbedtls_test_srv_key_ec_len \ + mbedtls_test_srv_key_ec_len_ncbicxx_2_4_2 +#define mbedtls_test_srv_key_len \ + mbedtls_test_srv_key_len_ncbicxx_2_4_2 +#define mbedtls_test_srv_key_rsa \ + mbedtls_test_srv_key_rsa_ncbicxx_2_4_2 +#define mbedtls_test_srv_key_rsa_len \ + mbedtls_test_srv_key_rsa_len_ncbicxx_2_4_2 +#define mbedtls_cipher_auth_decrypt \ + mbedtls_cipher_auth_decrypt_ncbicxx_2_4_2 +#define mbedtls_cipher_auth_encrypt \ + mbedtls_cipher_auth_encrypt_ncbicxx_2_4_2 +#define mbedtls_cipher_check_tag \ + mbedtls_cipher_check_tag_ncbicxx_2_4_2 +#define mbedtls_cipher_crypt \ + mbedtls_cipher_crypt_ncbicxx_2_4_2 +#define mbedtls_cipher_finish \ + mbedtls_cipher_finish_ncbicxx_2_4_2 +#define mbedtls_cipher_free \ + mbedtls_cipher_free_ncbicxx_2_4_2 +#define mbedtls_cipher_info_from_string \ + mbedtls_cipher_info_from_string_ncbicxx_2_4_2 +#define mbedtls_cipher_info_from_type \ + mbedtls_cipher_info_from_type_ncbicxx_2_4_2 +#define mbedtls_cipher_info_from_values \ + mbedtls_cipher_info_from_values_ncbicxx_2_4_2 +#define mbedtls_cipher_init \ + mbedtls_cipher_init_ncbicxx_2_4_2 +#define mbedtls_cipher_list \ + mbedtls_cipher_list_ncbicxx_2_4_2 +#define mbedtls_cipher_reset \ + mbedtls_cipher_reset_ncbicxx_2_4_2 +#define mbedtls_cipher_set_iv \ + mbedtls_cipher_set_iv_ncbicxx_2_4_2 +#define mbedtls_cipher_set_padding_mode \ + mbedtls_cipher_set_padding_mode_ncbicxx_2_4_2 +#define mbedtls_cipher_setkey \ + mbedtls_cipher_setkey_ncbicxx_2_4_2 +#define mbedtls_cipher_setup \ + mbedtls_cipher_setup_ncbicxx_2_4_2 +#define mbedtls_cipher_update \ + mbedtls_cipher_update_ncbicxx_2_4_2 +#define mbedtls_cipher_update_ad \ + mbedtls_cipher_update_ad_ncbicxx_2_4_2 +#define mbedtls_cipher_write_tag \ + mbedtls_cipher_write_tag_ncbicxx_2_4_2 +#define mbedtls_cipher_definitions \ + mbedtls_cipher_definitions_ncbicxx_2_4_2 +#define mbedtls_cipher_supported \ + mbedtls_cipher_supported_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_free \ + mbedtls_ctr_drbg_free_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_init \ + mbedtls_ctr_drbg_init_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_random \ + mbedtls_ctr_drbg_random_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_random_with_add \ + mbedtls_ctr_drbg_random_with_add_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_reseed \ + mbedtls_ctr_drbg_reseed_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_seed \ + mbedtls_ctr_drbg_seed_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_seed_entropy_len \ + mbedtls_ctr_drbg_seed_entropy_len_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_self_test \ + mbedtls_ctr_drbg_self_test_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_set_entropy_len \ + mbedtls_ctr_drbg_set_entropy_len_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_set_prediction_resistance \ + mbedtls_ctr_drbg_set_prediction_resistance_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_set_reseed_interval \ + mbedtls_ctr_drbg_set_reseed_interval_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_update \ + mbedtls_ctr_drbg_update_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_update_seed_file \ + mbedtls_ctr_drbg_update_seed_file_ncbicxx_2_4_2 +#define mbedtls_ctr_drbg_write_seed_file \ + mbedtls_ctr_drbg_write_seed_file_ncbicxx_2_4_2 +#define mbedtls_debug_print_buf \ + mbedtls_debug_print_buf_ncbicxx_2_4_2 +#define mbedtls_debug_print_crt \ + mbedtls_debug_print_crt_ncbicxx_2_4_2 +#define mbedtls_debug_print_ecp \ + mbedtls_debug_print_ecp_ncbicxx_2_4_2 +#define mbedtls_debug_print_mpi \ + mbedtls_debug_print_mpi_ncbicxx_2_4_2 +#define mbedtls_debug_print_msg \ + mbedtls_debug_print_msg_ncbicxx_2_4_2 +#define mbedtls_debug_print_ret \ + mbedtls_debug_print_ret_ncbicxx_2_4_2 +#define mbedtls_debug_set_threshold \ + mbedtls_debug_set_threshold_ncbicxx_2_4_2 +#define mbedtls_des3_crypt_cbc \ + mbedtls_des3_crypt_cbc_ncbicxx_2_4_2 +#define mbedtls_des3_crypt_ecb \ + mbedtls_des3_crypt_ecb_ncbicxx_2_4_2 +#define mbedtls_des3_free \ + mbedtls_des3_free_ncbicxx_2_4_2 +#define mbedtls_des3_init \ + mbedtls_des3_init_ncbicxx_2_4_2 +#define mbedtls_des3_set2key_dec \ + mbedtls_des3_set2key_dec_ncbicxx_2_4_2 +#define mbedtls_des3_set2key_enc \ + mbedtls_des3_set2key_enc_ncbicxx_2_4_2 +#define mbedtls_des3_set3key_dec \ + mbedtls_des3_set3key_dec_ncbicxx_2_4_2 +#define mbedtls_des3_set3key_enc \ + mbedtls_des3_set3key_enc_ncbicxx_2_4_2 +#define mbedtls_des_crypt_cbc \ + mbedtls_des_crypt_cbc_ncbicxx_2_4_2 +#define mbedtls_des_crypt_ecb \ + mbedtls_des_crypt_ecb_ncbicxx_2_4_2 +#define mbedtls_des_free \ + mbedtls_des_free_ncbicxx_2_4_2 +#define mbedtls_des_init \ + mbedtls_des_init_ncbicxx_2_4_2 +#define mbedtls_des_key_check_key_parity \ + mbedtls_des_key_check_key_parity_ncbicxx_2_4_2 +#define mbedtls_des_key_check_weak \ + mbedtls_des_key_check_weak_ncbicxx_2_4_2 +#define mbedtls_des_key_set_parity \ + mbedtls_des_key_set_parity_ncbicxx_2_4_2 +#define mbedtls_des_self_test \ + mbedtls_des_self_test_ncbicxx_2_4_2 +#define mbedtls_des_setkey \ + mbedtls_des_setkey_ncbicxx_2_4_2 +#define mbedtls_des_setkey_dec \ + mbedtls_des_setkey_dec_ncbicxx_2_4_2 +#define mbedtls_des_setkey_enc \ + mbedtls_des_setkey_enc_ncbicxx_2_4_2 +#define mbedtls_dhm_calc_secret \ + mbedtls_dhm_calc_secret_ncbicxx_2_4_2 +#define mbedtls_dhm_free \ + mbedtls_dhm_free_ncbicxx_2_4_2 +#define mbedtls_dhm_init \ + mbedtls_dhm_init_ncbicxx_2_4_2 +#define mbedtls_dhm_make_params \ + mbedtls_dhm_make_params_ncbicxx_2_4_2 +#define mbedtls_dhm_make_public \ + mbedtls_dhm_make_public_ncbicxx_2_4_2 +#define mbedtls_dhm_parse_dhm \ + mbedtls_dhm_parse_dhm_ncbicxx_2_4_2 +#define mbedtls_dhm_parse_dhmfile \ + mbedtls_dhm_parse_dhmfile_ncbicxx_2_4_2 +#define mbedtls_dhm_read_params \ + mbedtls_dhm_read_params_ncbicxx_2_4_2 +#define mbedtls_dhm_read_public \ + mbedtls_dhm_read_public_ncbicxx_2_4_2 +#define mbedtls_dhm_self_test \ + mbedtls_dhm_self_test_ncbicxx_2_4_2 +#define mbedtls_ecdh_calc_secret \ + mbedtls_ecdh_calc_secret_ncbicxx_2_4_2 +#define mbedtls_ecdh_compute_shared \ + mbedtls_ecdh_compute_shared_ncbicxx_2_4_2 +#define mbedtls_ecdh_free \ + mbedtls_ecdh_free_ncbicxx_2_4_2 +#define mbedtls_ecdh_gen_public \ + mbedtls_ecdh_gen_public_ncbicxx_2_4_2 +#define mbedtls_ecdh_get_params \ + mbedtls_ecdh_get_params_ncbicxx_2_4_2 +#define mbedtls_ecdh_init \ + mbedtls_ecdh_init_ncbicxx_2_4_2 +#define mbedtls_ecdh_make_params \ + mbedtls_ecdh_make_params_ncbicxx_2_4_2 +#define mbedtls_ecdh_make_public \ + mbedtls_ecdh_make_public_ncbicxx_2_4_2 +#define mbedtls_ecdh_read_params \ + mbedtls_ecdh_read_params_ncbicxx_2_4_2 +#define mbedtls_ecdh_read_public \ + mbedtls_ecdh_read_public_ncbicxx_2_4_2 +#define mbedtls_ecdsa_free \ + mbedtls_ecdsa_free_ncbicxx_2_4_2 +#define mbedtls_ecdsa_from_keypair \ + mbedtls_ecdsa_from_keypair_ncbicxx_2_4_2 +#define mbedtls_ecdsa_genkey \ + mbedtls_ecdsa_genkey_ncbicxx_2_4_2 +#define mbedtls_ecdsa_init \ + mbedtls_ecdsa_init_ncbicxx_2_4_2 +#define mbedtls_ecdsa_read_signature \ + mbedtls_ecdsa_read_signature_ncbicxx_2_4_2 +#define mbedtls_ecdsa_sign \ + mbedtls_ecdsa_sign_ncbicxx_2_4_2 +#define mbedtls_ecdsa_sign_det \ + mbedtls_ecdsa_sign_det_ncbicxx_2_4_2 +#define mbedtls_ecdsa_verify \ + mbedtls_ecdsa_verify_ncbicxx_2_4_2 +#define mbedtls_ecdsa_write_signature \ + mbedtls_ecdsa_write_signature_ncbicxx_2_4_2 +#define mbedtls_ecdsa_write_signature_det \ + mbedtls_ecdsa_write_signature_det_ncbicxx_2_4_2 +#define mbedtls_ecp_check_privkey \ + mbedtls_ecp_check_privkey_ncbicxx_2_4_2 +#define mbedtls_ecp_check_pub_priv \ + mbedtls_ecp_check_pub_priv_ncbicxx_2_4_2 +#define mbedtls_ecp_check_pubkey \ + mbedtls_ecp_check_pubkey_ncbicxx_2_4_2 +#define mbedtls_ecp_copy \ + mbedtls_ecp_copy_ncbicxx_2_4_2 +#define mbedtls_ecp_curve_info_from_grp_id \ + mbedtls_ecp_curve_info_from_grp_id_ncbicxx_2_4_2 +#define mbedtls_ecp_curve_info_from_name \ + mbedtls_ecp_curve_info_from_name_ncbicxx_2_4_2 +#define mbedtls_ecp_curve_info_from_tls_id \ + mbedtls_ecp_curve_info_from_tls_id_ncbicxx_2_4_2 +#define mbedtls_ecp_curve_list \ + mbedtls_ecp_curve_list_ncbicxx_2_4_2 +#define mbedtls_ecp_gen_key \ + mbedtls_ecp_gen_key_ncbicxx_2_4_2 +#define mbedtls_ecp_gen_keypair \ + mbedtls_ecp_gen_keypair_ncbicxx_2_4_2 +#define mbedtls_ecp_gen_keypair_base \ + mbedtls_ecp_gen_keypair_base_ncbicxx_2_4_2 +#define mbedtls_ecp_group_copy \ + mbedtls_ecp_group_copy_ncbicxx_2_4_2 +#define mbedtls_ecp_group_free \ + mbedtls_ecp_group_free_ncbicxx_2_4_2 +#define mbedtls_ecp_group_init \ + mbedtls_ecp_group_init_ncbicxx_2_4_2 +#define mbedtls_ecp_grp_id_list \ + mbedtls_ecp_grp_id_list_ncbicxx_2_4_2 +#define mbedtls_ecp_is_zero \ + mbedtls_ecp_is_zero_ncbicxx_2_4_2 +#define mbedtls_ecp_keypair_free \ + mbedtls_ecp_keypair_free_ncbicxx_2_4_2 +#define mbedtls_ecp_keypair_init \ + mbedtls_ecp_keypair_init_ncbicxx_2_4_2 +#define mbedtls_ecp_mul \ + mbedtls_ecp_mul_ncbicxx_2_4_2 +#define mbedtls_ecp_muladd \ + mbedtls_ecp_muladd_ncbicxx_2_4_2 +#define mbedtls_ecp_point_cmp \ + mbedtls_ecp_point_cmp_ncbicxx_2_4_2 +#define mbedtls_ecp_point_free \ + mbedtls_ecp_point_free_ncbicxx_2_4_2 +#define mbedtls_ecp_point_init \ + mbedtls_ecp_point_init_ncbicxx_2_4_2 +#define mbedtls_ecp_point_read_binary \ + mbedtls_ecp_point_read_binary_ncbicxx_2_4_2 +#define mbedtls_ecp_point_read_string \ + mbedtls_ecp_point_read_string_ncbicxx_2_4_2 +#define mbedtls_ecp_point_write_binary \ + mbedtls_ecp_point_write_binary_ncbicxx_2_4_2 +#define mbedtls_ecp_self_test \ + mbedtls_ecp_self_test_ncbicxx_2_4_2 +#define mbedtls_ecp_set_zero \ + mbedtls_ecp_set_zero_ncbicxx_2_4_2 +#define mbedtls_ecp_tls_read_group \ + mbedtls_ecp_tls_read_group_ncbicxx_2_4_2 +#define mbedtls_ecp_tls_read_point \ + mbedtls_ecp_tls_read_point_ncbicxx_2_4_2 +#define mbedtls_ecp_tls_write_group \ + mbedtls_ecp_tls_write_group_ncbicxx_2_4_2 +#define mbedtls_ecp_tls_write_point \ + mbedtls_ecp_tls_write_point_ncbicxx_2_4_2 +#define mbedtls_ecp_group_load \ + mbedtls_ecp_group_load_ncbicxx_2_4_2 +#define mbedtls_entropy_add_source \ + mbedtls_entropy_add_source_ncbicxx_2_4_2 +#define mbedtls_entropy_free \ + mbedtls_entropy_free_ncbicxx_2_4_2 +#define mbedtls_entropy_func \ + mbedtls_entropy_func_ncbicxx_2_4_2 +#define mbedtls_entropy_gather \ + mbedtls_entropy_gather_ncbicxx_2_4_2 +#define mbedtls_entropy_init \ + mbedtls_entropy_init_ncbicxx_2_4_2 +#define mbedtls_entropy_self_test \ + mbedtls_entropy_self_test_ncbicxx_2_4_2 +#define mbedtls_entropy_update_manual \ + mbedtls_entropy_update_manual_ncbicxx_2_4_2 +#define mbedtls_entropy_update_seed_file \ + mbedtls_entropy_update_seed_file_ncbicxx_2_4_2 +#define mbedtls_entropy_write_seed_file \ + mbedtls_entropy_write_seed_file_ncbicxx_2_4_2 +#define mbedtls_hardclock_poll \ + mbedtls_hardclock_poll_ncbicxx_2_4_2 +#define mbedtls_platform_entropy_poll \ + mbedtls_platform_entropy_poll_ncbicxx_2_4_2 +#define mbedtls_strerror \ + mbedtls_strerror_ncbicxx_2_4_2 +#define mbedtls_gcm_auth_decrypt \ + mbedtls_gcm_auth_decrypt_ncbicxx_2_4_2 +#define mbedtls_gcm_crypt_and_tag \ + mbedtls_gcm_crypt_and_tag_ncbicxx_2_4_2 +#define mbedtls_gcm_finish \ + mbedtls_gcm_finish_ncbicxx_2_4_2 +#define mbedtls_gcm_free \ + mbedtls_gcm_free_ncbicxx_2_4_2 +#define mbedtls_gcm_init \ + mbedtls_gcm_init_ncbicxx_2_4_2 +#define mbedtls_gcm_self_test \ + mbedtls_gcm_self_test_ncbicxx_2_4_2 +#define mbedtls_gcm_setkey \ + mbedtls_gcm_setkey_ncbicxx_2_4_2 +#define mbedtls_gcm_starts \ + mbedtls_gcm_starts_ncbicxx_2_4_2 +#define mbedtls_gcm_update \ + mbedtls_gcm_update_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_free \ + mbedtls_hmac_drbg_free_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_init \ + mbedtls_hmac_drbg_init_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_random \ + mbedtls_hmac_drbg_random_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_random_with_add \ + mbedtls_hmac_drbg_random_with_add_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_reseed \ + mbedtls_hmac_drbg_reseed_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_seed \ + mbedtls_hmac_drbg_seed_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_seed_buf \ + mbedtls_hmac_drbg_seed_buf_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_self_test \ + mbedtls_hmac_drbg_self_test_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_set_entropy_len \ + mbedtls_hmac_drbg_set_entropy_len_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_set_prediction_resistance \ + mbedtls_hmac_drbg_set_prediction_resistance_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_set_reseed_interval \ + mbedtls_hmac_drbg_set_reseed_interval_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_update \ + mbedtls_hmac_drbg_update_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_update_seed_file \ + mbedtls_hmac_drbg_update_seed_file_ncbicxx_2_4_2 +#define mbedtls_hmac_drbg_write_seed_file \ + mbedtls_hmac_drbg_write_seed_file_ncbicxx_2_4_2 +#define mbedtls_md \ + mbedtls_md_ncbicxx_2_4_2 +#define mbedtls_md_clone \ + mbedtls_md_clone_ncbicxx_2_4_2 +#define mbedtls_md_file \ + mbedtls_md_file_ncbicxx_2_4_2 +#define mbedtls_md_finish \ + mbedtls_md_finish_ncbicxx_2_4_2 +#define mbedtls_md_free \ + mbedtls_md_free_ncbicxx_2_4_2 +#define mbedtls_md_get_name \ + mbedtls_md_get_name_ncbicxx_2_4_2 +#define mbedtls_md_get_size \ + mbedtls_md_get_size_ncbicxx_2_4_2 +#define mbedtls_md_get_type \ + mbedtls_md_get_type_ncbicxx_2_4_2 +#define mbedtls_md_hmac \ + mbedtls_md_hmac_ncbicxx_2_4_2 +#define mbedtls_md_hmac_finish \ + mbedtls_md_hmac_finish_ncbicxx_2_4_2 +#define mbedtls_md_hmac_reset \ + mbedtls_md_hmac_reset_ncbicxx_2_4_2 +#define mbedtls_md_hmac_starts \ + mbedtls_md_hmac_starts_ncbicxx_2_4_2 +#define mbedtls_md_hmac_update \ + mbedtls_md_hmac_update_ncbicxx_2_4_2 +#define mbedtls_md_info_from_string \ + mbedtls_md_info_from_string_ncbicxx_2_4_2 +#define mbedtls_md_info_from_type \ + mbedtls_md_info_from_type_ncbicxx_2_4_2 +#define mbedtls_md_init \ + mbedtls_md_init_ncbicxx_2_4_2 +#define mbedtls_md_init_ctx \ + mbedtls_md_init_ctx_ncbicxx_2_4_2 +#define mbedtls_md_list \ + mbedtls_md_list_ncbicxx_2_4_2 +#define mbedtls_md_process \ + mbedtls_md_process_ncbicxx_2_4_2 +#define mbedtls_md_setup \ + mbedtls_md_setup_ncbicxx_2_4_2 +#define mbedtls_md_starts \ + mbedtls_md_starts_ncbicxx_2_4_2 +#define mbedtls_md_update \ + mbedtls_md_update_ncbicxx_2_4_2 +#define mbedtls_md5 \ + mbedtls_md5_ncbicxx_2_4_2 +#define mbedtls_md5_clone \ + mbedtls_md5_clone_ncbicxx_2_4_2 +#define mbedtls_md5_finish \ + mbedtls_md5_finish_ncbicxx_2_4_2 +#define mbedtls_md5_free \ + mbedtls_md5_free_ncbicxx_2_4_2 +#define mbedtls_md5_init \ + mbedtls_md5_init_ncbicxx_2_4_2 +#define mbedtls_md5_process \ + mbedtls_md5_process_ncbicxx_2_4_2 +#define mbedtls_md5_self_test \ + mbedtls_md5_self_test_ncbicxx_2_4_2 +#define mbedtls_md5_starts \ + mbedtls_md5_starts_ncbicxx_2_4_2 +#define mbedtls_md5_update \ + mbedtls_md5_update_ncbicxx_2_4_2 +#define mbedtls_md5_info \ + mbedtls_md5_info_ncbicxx_2_4_2 +#define mbedtls_ripemd160_info \ + mbedtls_ripemd160_info_ncbicxx_2_4_2 +#define mbedtls_sha1_info \ + mbedtls_sha1_info_ncbicxx_2_4_2 +#define mbedtls_sha224_info \ + mbedtls_sha224_info_ncbicxx_2_4_2 +#define mbedtls_sha256_info \ + mbedtls_sha256_info_ncbicxx_2_4_2 +#define mbedtls_sha384_info \ + mbedtls_sha384_info_ncbicxx_2_4_2 +#define mbedtls_sha512_info \ + mbedtls_sha512_info_ncbicxx_2_4_2 +#define mbedtls_net_accept \ + mbedtls_net_accept_ncbicxx_2_4_2 +#define mbedtls_net_bind \ + mbedtls_net_bind_ncbicxx_2_4_2 +#define mbedtls_net_connect \ + mbedtls_net_connect_ncbicxx_2_4_2 +#define mbedtls_net_free \ + mbedtls_net_free_ncbicxx_2_4_2 +#define mbedtls_net_init \ + mbedtls_net_init_ncbicxx_2_4_2 +#define mbedtls_net_recv \ + mbedtls_net_recv_ncbicxx_2_4_2 +#define mbedtls_net_recv_timeout \ + mbedtls_net_recv_timeout_ncbicxx_2_4_2 +#define mbedtls_net_send \ + mbedtls_net_send_ncbicxx_2_4_2 +#define mbedtls_net_set_block \ + mbedtls_net_set_block_ncbicxx_2_4_2 +#define mbedtls_net_set_nonblock \ + mbedtls_net_set_nonblock_ncbicxx_2_4_2 +#define mbedtls_net_usleep \ + mbedtls_net_usleep_ncbicxx_2_4_2 +#define mbedtls_oid_get_attr_short_name \ + mbedtls_oid_get_attr_short_name_ncbicxx_2_4_2 +#define mbedtls_oid_get_cipher_alg \ + mbedtls_oid_get_cipher_alg_ncbicxx_2_4_2 +#define mbedtls_oid_get_ec_grp \ + mbedtls_oid_get_ec_grp_ncbicxx_2_4_2 +#define mbedtls_oid_get_extended_key_usage \ + mbedtls_oid_get_extended_key_usage_ncbicxx_2_4_2 +#define mbedtls_oid_get_md_alg \ + mbedtls_oid_get_md_alg_ncbicxx_2_4_2 +#define mbedtls_oid_get_numeric_string \ + mbedtls_oid_get_numeric_string_ncbicxx_2_4_2 +#define mbedtls_oid_get_oid_by_ec_grp \ + mbedtls_oid_get_oid_by_ec_grp_ncbicxx_2_4_2 +#define mbedtls_oid_get_oid_by_md \ + mbedtls_oid_get_oid_by_md_ncbicxx_2_4_2 +#define mbedtls_oid_get_oid_by_pk_alg \ + mbedtls_oid_get_oid_by_pk_alg_ncbicxx_2_4_2 +#define mbedtls_oid_get_oid_by_sig_alg \ + mbedtls_oid_get_oid_by_sig_alg_ncbicxx_2_4_2 +#define mbedtls_oid_get_pk_alg \ + mbedtls_oid_get_pk_alg_ncbicxx_2_4_2 +#define mbedtls_oid_get_pkcs12_pbe_alg \ + mbedtls_oid_get_pkcs12_pbe_alg_ncbicxx_2_4_2 +#define mbedtls_oid_get_sig_alg \ + mbedtls_oid_get_sig_alg_ncbicxx_2_4_2 +#define mbedtls_oid_get_sig_alg_desc \ + mbedtls_oid_get_sig_alg_desc_ncbicxx_2_4_2 +#define mbedtls_oid_get_x509_ext_type \ + mbedtls_oid_get_x509_ext_type_ncbicxx_2_4_2 +#define mbedtls_pem_free \ + mbedtls_pem_free_ncbicxx_2_4_2 +#define mbedtls_pem_init \ + mbedtls_pem_init_ncbicxx_2_4_2 +#define mbedtls_pem_read_buffer \ + mbedtls_pem_read_buffer_ncbicxx_2_4_2 +#define mbedtls_pem_write_buffer \ + mbedtls_pem_write_buffer_ncbicxx_2_4_2 +#define mbedtls_pk_can_do \ + mbedtls_pk_can_do_ncbicxx_2_4_2 +#define mbedtls_pk_check_pair \ + mbedtls_pk_check_pair_ncbicxx_2_4_2 +#define mbedtls_pk_debug \ + mbedtls_pk_debug_ncbicxx_2_4_2 +#define mbedtls_pk_decrypt \ + mbedtls_pk_decrypt_ncbicxx_2_4_2 +#define mbedtls_pk_encrypt \ + mbedtls_pk_encrypt_ncbicxx_2_4_2 +#define mbedtls_pk_free \ + mbedtls_pk_free_ncbicxx_2_4_2 +#define mbedtls_pk_get_bitlen \ + mbedtls_pk_get_bitlen_ncbicxx_2_4_2 +#define mbedtls_pk_get_name \ + mbedtls_pk_get_name_ncbicxx_2_4_2 +#define mbedtls_pk_get_type \ + mbedtls_pk_get_type_ncbicxx_2_4_2 +#define mbedtls_pk_info_from_type \ + mbedtls_pk_info_from_type_ncbicxx_2_4_2 +#define mbedtls_pk_init \ + mbedtls_pk_init_ncbicxx_2_4_2 +#define mbedtls_pk_setup \ + mbedtls_pk_setup_ncbicxx_2_4_2 +#define mbedtls_pk_setup_rsa_alt \ + mbedtls_pk_setup_rsa_alt_ncbicxx_2_4_2 +#define mbedtls_pk_sign \ + mbedtls_pk_sign_ncbicxx_2_4_2 +#define mbedtls_pk_verify \ + mbedtls_pk_verify_ncbicxx_2_4_2 +#define mbedtls_pk_verify_ext \ + mbedtls_pk_verify_ext_ncbicxx_2_4_2 +#define mbedtls_ecdsa_info \ + mbedtls_ecdsa_info_ncbicxx_2_4_2 +#define mbedtls_eckey_info \ + mbedtls_eckey_info_ncbicxx_2_4_2 +#define mbedtls_eckeydh_info \ + mbedtls_eckeydh_info_ncbicxx_2_4_2 +#define mbedtls_rsa_alt_info \ + mbedtls_rsa_alt_info_ncbicxx_2_4_2 +#define mbedtls_rsa_info \ + mbedtls_rsa_info_ncbicxx_2_4_2 +#define mbedtls_pkcs12_derivation \ + mbedtls_pkcs12_derivation_ncbicxx_2_4_2 +#define mbedtls_pkcs12_pbe \ + mbedtls_pkcs12_pbe_ncbicxx_2_4_2 +#define mbedtls_pkcs12_pbe_sha1_rc4_128 \ + mbedtls_pkcs12_pbe_sha1_rc4_128_ncbicxx_2_4_2 +#define mbedtls_pkcs5_pbes2 \ + mbedtls_pkcs5_pbes2_ncbicxx_2_4_2 +#define mbedtls_pkcs5_pbkdf2_hmac \ + mbedtls_pkcs5_pbkdf2_hmac_ncbicxx_2_4_2 +#define mbedtls_pkcs5_self_test \ + mbedtls_pkcs5_self_test_ncbicxx_2_4_2 +#define mbedtls_pk_load_file \ + mbedtls_pk_load_file_ncbicxx_2_4_2 +#define mbedtls_pk_parse_key \ + mbedtls_pk_parse_key_ncbicxx_2_4_2 +#define mbedtls_pk_parse_keyfile \ + mbedtls_pk_parse_keyfile_ncbicxx_2_4_2 +#define mbedtls_pk_parse_public_key \ + mbedtls_pk_parse_public_key_ncbicxx_2_4_2 +#define mbedtls_pk_parse_public_keyfile \ + mbedtls_pk_parse_public_keyfile_ncbicxx_2_4_2 +#define mbedtls_pk_parse_subpubkey \ + mbedtls_pk_parse_subpubkey_ncbicxx_2_4_2 +#define mbedtls_pk_write_key_der \ + mbedtls_pk_write_key_der_ncbicxx_2_4_2 +#define mbedtls_pk_write_key_pem \ + mbedtls_pk_write_key_pem_ncbicxx_2_4_2 +#define mbedtls_pk_write_pubkey \ + mbedtls_pk_write_pubkey_ncbicxx_2_4_2 +#define mbedtls_pk_write_pubkey_der \ + mbedtls_pk_write_pubkey_der_ncbicxx_2_4_2 +#define mbedtls_pk_write_pubkey_pem \ + mbedtls_pk_write_pubkey_pem_ncbicxx_2_4_2 +#define mbedtls_ripemd160 \ + mbedtls_ripemd160_ncbicxx_2_4_2 +#define mbedtls_ripemd160_clone \ + mbedtls_ripemd160_clone_ncbicxx_2_4_2 +#define mbedtls_ripemd160_finish \ + mbedtls_ripemd160_finish_ncbicxx_2_4_2 +#define mbedtls_ripemd160_free \ + mbedtls_ripemd160_free_ncbicxx_2_4_2 +#define mbedtls_ripemd160_init \ + mbedtls_ripemd160_init_ncbicxx_2_4_2 +#define mbedtls_ripemd160_process \ + mbedtls_ripemd160_process_ncbicxx_2_4_2 +#define mbedtls_ripemd160_self_test \ + mbedtls_ripemd160_self_test_ncbicxx_2_4_2 +#define mbedtls_ripemd160_starts \ + mbedtls_ripemd160_starts_ncbicxx_2_4_2 +#define mbedtls_ripemd160_update \ + mbedtls_ripemd160_update_ncbicxx_2_4_2 +#define mbedtls_rsa_check_privkey \ + mbedtls_rsa_check_privkey_ncbicxx_2_4_2 +#define mbedtls_rsa_check_pub_priv \ + mbedtls_rsa_check_pub_priv_ncbicxx_2_4_2 +#define mbedtls_rsa_check_pubkey \ + mbedtls_rsa_check_pubkey_ncbicxx_2_4_2 +#define mbedtls_rsa_copy \ + mbedtls_rsa_copy_ncbicxx_2_4_2 +#define mbedtls_rsa_free \ + mbedtls_rsa_free_ncbicxx_2_4_2 +#define mbedtls_rsa_gen_key \ + mbedtls_rsa_gen_key_ncbicxx_2_4_2 +#define mbedtls_rsa_init \ + mbedtls_rsa_init_ncbicxx_2_4_2 +#define mbedtls_rsa_pkcs1_decrypt \ + mbedtls_rsa_pkcs1_decrypt_ncbicxx_2_4_2 +#define mbedtls_rsa_pkcs1_encrypt \ + mbedtls_rsa_pkcs1_encrypt_ncbicxx_2_4_2 +#define mbedtls_rsa_pkcs1_sign \ + mbedtls_rsa_pkcs1_sign_ncbicxx_2_4_2 +#define mbedtls_rsa_pkcs1_verify \ + mbedtls_rsa_pkcs1_verify_ncbicxx_2_4_2 +#define mbedtls_rsa_private \ + mbedtls_rsa_private_ncbicxx_2_4_2 +#define mbedtls_rsa_public \ + mbedtls_rsa_public_ncbicxx_2_4_2 +#define mbedtls_rsa_rsaes_oaep_decrypt \ + mbedtls_rsa_rsaes_oaep_decrypt_ncbicxx_2_4_2 +#define mbedtls_rsa_rsaes_oaep_encrypt \ + mbedtls_rsa_rsaes_oaep_encrypt_ncbicxx_2_4_2 +#define mbedtls_rsa_rsaes_pkcs1_v15_decrypt \ + mbedtls_rsa_rsaes_pkcs1_v15_decrypt_ncbicxx_2_4_2 +#define mbedtls_rsa_rsaes_pkcs1_v15_encrypt \ + mbedtls_rsa_rsaes_pkcs1_v15_encrypt_ncbicxx_2_4_2 +#define mbedtls_rsa_rsassa_pkcs1_v15_sign \ + mbedtls_rsa_rsassa_pkcs1_v15_sign_ncbicxx_2_4_2 +#define mbedtls_rsa_rsassa_pkcs1_v15_verify \ + mbedtls_rsa_rsassa_pkcs1_v15_verify_ncbicxx_2_4_2 +#define mbedtls_rsa_rsassa_pss_sign \ + mbedtls_rsa_rsassa_pss_sign_ncbicxx_2_4_2 +#define mbedtls_rsa_rsassa_pss_verify \ + mbedtls_rsa_rsassa_pss_verify_ncbicxx_2_4_2 +#define mbedtls_rsa_rsassa_pss_verify_ext \ + mbedtls_rsa_rsassa_pss_verify_ext_ncbicxx_2_4_2 +#define mbedtls_rsa_self_test \ + mbedtls_rsa_self_test_ncbicxx_2_4_2 +#define mbedtls_rsa_set_padding \ + mbedtls_rsa_set_padding_ncbicxx_2_4_2 +#define mbedtls_sha1 \ + mbedtls_sha1_ncbicxx_2_4_2 +#define mbedtls_sha1_clone \ + mbedtls_sha1_clone_ncbicxx_2_4_2 +#define mbedtls_sha1_finish \ + mbedtls_sha1_finish_ncbicxx_2_4_2 +#define mbedtls_sha1_free \ + mbedtls_sha1_free_ncbicxx_2_4_2 +#define mbedtls_sha1_init \ + mbedtls_sha1_init_ncbicxx_2_4_2 +#define mbedtls_sha1_process \ + mbedtls_sha1_process_ncbicxx_2_4_2 +#define mbedtls_sha1_self_test \ + mbedtls_sha1_self_test_ncbicxx_2_4_2 +#define mbedtls_sha1_starts \ + mbedtls_sha1_starts_ncbicxx_2_4_2 +#define mbedtls_sha1_update \ + mbedtls_sha1_update_ncbicxx_2_4_2 +#define mbedtls_sha256 \ + mbedtls_sha256_ncbicxx_2_4_2 +#define mbedtls_sha256_clone \ + mbedtls_sha256_clone_ncbicxx_2_4_2 +#define mbedtls_sha256_finish \ + mbedtls_sha256_finish_ncbicxx_2_4_2 +#define mbedtls_sha256_free \ + mbedtls_sha256_free_ncbicxx_2_4_2 +#define mbedtls_sha256_init \ + mbedtls_sha256_init_ncbicxx_2_4_2 +#define mbedtls_sha256_process \ + mbedtls_sha256_process_ncbicxx_2_4_2 +#define mbedtls_sha256_self_test \ + mbedtls_sha256_self_test_ncbicxx_2_4_2 +#define mbedtls_sha256_starts \ + mbedtls_sha256_starts_ncbicxx_2_4_2 +#define mbedtls_sha256_update \ + mbedtls_sha256_update_ncbicxx_2_4_2 +#define mbedtls_sha512 \ + mbedtls_sha512_ncbicxx_2_4_2 +#define mbedtls_sha512_clone \ + mbedtls_sha512_clone_ncbicxx_2_4_2 +#define mbedtls_sha512_finish \ + mbedtls_sha512_finish_ncbicxx_2_4_2 +#define mbedtls_sha512_free \ + mbedtls_sha512_free_ncbicxx_2_4_2 +#define mbedtls_sha512_init \ + mbedtls_sha512_init_ncbicxx_2_4_2 +#define mbedtls_sha512_process \ + mbedtls_sha512_process_ncbicxx_2_4_2 +#define mbedtls_sha512_self_test \ + mbedtls_sha512_self_test_ncbicxx_2_4_2 +#define mbedtls_sha512_starts \ + mbedtls_sha512_starts_ncbicxx_2_4_2 +#define mbedtls_sha512_update \ + mbedtls_sha512_update_ncbicxx_2_4_2 +#define mbedtls_ssl_cache_free \ + mbedtls_ssl_cache_free_ncbicxx_2_4_2 +#define mbedtls_ssl_cache_get \ + mbedtls_ssl_cache_get_ncbicxx_2_4_2 +#define mbedtls_ssl_cache_init \ + mbedtls_ssl_cache_init_ncbicxx_2_4_2 +#define mbedtls_ssl_cache_set \ + mbedtls_ssl_cache_set_ncbicxx_2_4_2 +#define mbedtls_ssl_cache_set_max_entries \ + mbedtls_ssl_cache_set_max_entries_ncbicxx_2_4_2 +#define mbedtls_ssl_cache_set_timeout \ + mbedtls_ssl_cache_set_timeout_ncbicxx_2_4_2 +#define mbedtls_ssl_ciphersuite_from_id \ + mbedtls_ssl_ciphersuite_from_id_ncbicxx_2_4_2 +#define mbedtls_ssl_ciphersuite_from_string \ + mbedtls_ssl_ciphersuite_from_string_ncbicxx_2_4_2 +#define mbedtls_ssl_ciphersuite_uses_ec \ + mbedtls_ssl_ciphersuite_uses_ec_ncbicxx_2_4_2 +#define mbedtls_ssl_ciphersuite_uses_psk \ + mbedtls_ssl_ciphersuite_uses_psk_ncbicxx_2_4_2 +#define mbedtls_ssl_get_ciphersuite_id \ + mbedtls_ssl_get_ciphersuite_id_ncbicxx_2_4_2 +#define mbedtls_ssl_get_ciphersuite_name \ + mbedtls_ssl_get_ciphersuite_name_ncbicxx_2_4_2 +#define mbedtls_ssl_get_ciphersuite_sig_pk_alg \ + mbedtls_ssl_get_ciphersuite_sig_pk_alg_ncbicxx_2_4_2 +#define mbedtls_ssl_list_ciphersuites \ + mbedtls_ssl_list_ciphersuites_ncbicxx_2_4_2 +#define mbedtls_ssl_handshake_client_step \ + mbedtls_ssl_handshake_client_step_ncbicxx_2_4_2 +#define mbedtls_ssl_cookie_check \ + mbedtls_ssl_cookie_check_ncbicxx_2_4_2 +#define mbedtls_ssl_cookie_free \ + mbedtls_ssl_cookie_free_ncbicxx_2_4_2 +#define mbedtls_ssl_cookie_init \ + mbedtls_ssl_cookie_init_ncbicxx_2_4_2 +#define mbedtls_ssl_cookie_set_timeout \ + mbedtls_ssl_cookie_set_timeout_ncbicxx_2_4_2 +#define mbedtls_ssl_cookie_setup \ + mbedtls_ssl_cookie_setup_ncbicxx_2_4_2 +#define mbedtls_ssl_cookie_write \ + mbedtls_ssl_cookie_write_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_dtls_cookies \ + mbedtls_ssl_conf_dtls_cookies_ncbicxx_2_4_2 +#define mbedtls_ssl_handshake_server_step \ + mbedtls_ssl_handshake_server_step_ncbicxx_2_4_2 +#define mbedtls_ssl_set_client_transport_id \ + mbedtls_ssl_set_client_transport_id_ncbicxx_2_4_2 +#define mbedtls_ssl_ticket_free \ + mbedtls_ssl_ticket_free_ncbicxx_2_4_2 +#define mbedtls_ssl_ticket_init \ + mbedtls_ssl_ticket_init_ncbicxx_2_4_2 +#define mbedtls_ssl_ticket_parse \ + mbedtls_ssl_ticket_parse_ncbicxx_2_4_2 +#define mbedtls_ssl_ticket_setup \ + mbedtls_ssl_ticket_setup_ncbicxx_2_4_2 +#define mbedtls_ssl_ticket_write \ + mbedtls_ssl_ticket_write_ncbicxx_2_4_2 +#define mbedtls_ssl_check_cert_usage \ + mbedtls_ssl_check_cert_usage_ncbicxx_2_4_2 +#define mbedtls_ssl_check_curve \ + mbedtls_ssl_check_curve_ncbicxx_2_4_2 +#define mbedtls_ssl_check_sig_hash \ + mbedtls_ssl_check_sig_hash_ncbicxx_2_4_2 +#define mbedtls_ssl_close_notify \ + mbedtls_ssl_close_notify_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_alpn_protocols \ + mbedtls_ssl_conf_alpn_protocols_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_arc4_support \ + mbedtls_ssl_conf_arc4_support_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_authmode \ + mbedtls_ssl_conf_authmode_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_ca_chain \ + mbedtls_ssl_conf_ca_chain_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_cbc_record_splitting \ + mbedtls_ssl_conf_cbc_record_splitting_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_cert_profile \ + mbedtls_ssl_conf_cert_profile_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_ciphersuites \ + mbedtls_ssl_conf_ciphersuites_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_ciphersuites_for_version \ + mbedtls_ssl_conf_ciphersuites_for_version_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_curves \ + mbedtls_ssl_conf_curves_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_dbg \ + mbedtls_ssl_conf_dbg_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_dh_param \ + mbedtls_ssl_conf_dh_param_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_dh_param_ctx \ + mbedtls_ssl_conf_dh_param_ctx_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_dhm_min_bitlen \ + mbedtls_ssl_conf_dhm_min_bitlen_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_dtls_anti_replay \ + mbedtls_ssl_conf_dtls_anti_replay_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_dtls_badmac_limit \ + mbedtls_ssl_conf_dtls_badmac_limit_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_encrypt_then_mac \ + mbedtls_ssl_conf_encrypt_then_mac_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_endpoint \ + mbedtls_ssl_conf_endpoint_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_export_keys_cb \ + mbedtls_ssl_conf_export_keys_cb_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_extended_master_secret \ + mbedtls_ssl_conf_extended_master_secret_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_fallback \ + mbedtls_ssl_conf_fallback_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_handshake_timeout \ + mbedtls_ssl_conf_handshake_timeout_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_legacy_renegotiation \ + mbedtls_ssl_conf_legacy_renegotiation_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_max_frag_len \ + mbedtls_ssl_conf_max_frag_len_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_max_version \ + mbedtls_ssl_conf_max_version_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_min_version \ + mbedtls_ssl_conf_min_version_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_own_cert \ + mbedtls_ssl_conf_own_cert_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_psk \ + mbedtls_ssl_conf_psk_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_psk_cb \ + mbedtls_ssl_conf_psk_cb_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_read_timeout \ + mbedtls_ssl_conf_read_timeout_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_renegotiation \ + mbedtls_ssl_conf_renegotiation_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_renegotiation_enforced \ + mbedtls_ssl_conf_renegotiation_enforced_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_renegotiation_period \ + mbedtls_ssl_conf_renegotiation_period_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_rng \ + mbedtls_ssl_conf_rng_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_session_cache \ + mbedtls_ssl_conf_session_cache_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_session_tickets \ + mbedtls_ssl_conf_session_tickets_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_session_tickets_cb \ + mbedtls_ssl_conf_session_tickets_cb_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_sig_hashes \ + mbedtls_ssl_conf_sig_hashes_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_sni \ + mbedtls_ssl_conf_sni_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_transport \ + mbedtls_ssl_conf_transport_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_truncated_hmac \ + mbedtls_ssl_conf_truncated_hmac_ncbicxx_2_4_2 +#define mbedtls_ssl_conf_verify \ + mbedtls_ssl_conf_verify_ncbicxx_2_4_2 +#define mbedtls_ssl_config_defaults \ + mbedtls_ssl_config_defaults_ncbicxx_2_4_2 +#define mbedtls_ssl_config_free \ + mbedtls_ssl_config_free_ncbicxx_2_4_2 +#define mbedtls_ssl_config_init \ + mbedtls_ssl_config_init_ncbicxx_2_4_2 +#define mbedtls_ssl_derive_keys \ + mbedtls_ssl_derive_keys_ncbicxx_2_4_2 +#define mbedtls_ssl_dtls_replay_check \ + mbedtls_ssl_dtls_replay_check_ncbicxx_2_4_2 +#define mbedtls_ssl_dtls_replay_update \ + mbedtls_ssl_dtls_replay_update_ncbicxx_2_4_2 +#define mbedtls_ssl_fetch_input \ + mbedtls_ssl_fetch_input_ncbicxx_2_4_2 +#define mbedtls_ssl_flush_output \ + mbedtls_ssl_flush_output_ncbicxx_2_4_2 +#define mbedtls_ssl_free \ + mbedtls_ssl_free_ncbicxx_2_4_2 +#define mbedtls_ssl_get_alpn_protocol \ + mbedtls_ssl_get_alpn_protocol_ncbicxx_2_4_2 +#define mbedtls_ssl_get_bytes_avail \ + mbedtls_ssl_get_bytes_avail_ncbicxx_2_4_2 +#define mbedtls_ssl_get_ciphersuite \ + mbedtls_ssl_get_ciphersuite_ncbicxx_2_4_2 +#define mbedtls_ssl_get_max_frag_len \ + mbedtls_ssl_get_max_frag_len_ncbicxx_2_4_2 +#define mbedtls_ssl_get_peer_cert \ + mbedtls_ssl_get_peer_cert_ncbicxx_2_4_2 +#define mbedtls_ssl_get_record_expansion \ + mbedtls_ssl_get_record_expansion_ncbicxx_2_4_2 +#define mbedtls_ssl_get_session \ + mbedtls_ssl_get_session_ncbicxx_2_4_2 +#define mbedtls_ssl_get_verify_result \ + mbedtls_ssl_get_verify_result_ncbicxx_2_4_2 +#define mbedtls_ssl_get_version \ + mbedtls_ssl_get_version_ncbicxx_2_4_2 +#define mbedtls_ssl_handle_message_type \ + mbedtls_ssl_handle_message_type_ncbicxx_2_4_2 +#define mbedtls_ssl_handshake \ + mbedtls_ssl_handshake_ncbicxx_2_4_2 +#define mbedtls_ssl_handshake_free \ + mbedtls_ssl_handshake_free_ncbicxx_2_4_2 +#define mbedtls_ssl_handshake_step \ + mbedtls_ssl_handshake_step_ncbicxx_2_4_2 +#define mbedtls_ssl_handshake_wrapup \ + mbedtls_ssl_handshake_wrapup_ncbicxx_2_4_2 +#define mbedtls_ssl_hash_from_md_alg \ + mbedtls_ssl_hash_from_md_alg_ncbicxx_2_4_2 +#define mbedtls_ssl_init \ + mbedtls_ssl_init_ncbicxx_2_4_2 +#define mbedtls_ssl_md_alg_from_hash \ + mbedtls_ssl_md_alg_from_hash_ncbicxx_2_4_2 +#define mbedtls_ssl_optimize_checksum \ + mbedtls_ssl_optimize_checksum_ncbicxx_2_4_2 +#define mbedtls_ssl_parse_certificate \ + mbedtls_ssl_parse_certificate_ncbicxx_2_4_2 +#define mbedtls_ssl_parse_change_cipher_spec \ + mbedtls_ssl_parse_change_cipher_spec_ncbicxx_2_4_2 +#define mbedtls_ssl_parse_finished \ + mbedtls_ssl_parse_finished_ncbicxx_2_4_2 +#define mbedtls_ssl_pk_alg_from_sig \ + mbedtls_ssl_pk_alg_from_sig_ncbicxx_2_4_2 +#define mbedtls_ssl_prepare_handshake_record \ + mbedtls_ssl_prepare_handshake_record_ncbicxx_2_4_2 +#define mbedtls_ssl_psk_derive_premaster \ + mbedtls_ssl_psk_derive_premaster_ncbicxx_2_4_2 +#define mbedtls_ssl_read \ + mbedtls_ssl_read_ncbicxx_2_4_2 +#define mbedtls_ssl_read_record \ + mbedtls_ssl_read_record_ncbicxx_2_4_2 +#define mbedtls_ssl_read_record_layer \ + mbedtls_ssl_read_record_layer_ncbicxx_2_4_2 +#define mbedtls_ssl_read_version \ + mbedtls_ssl_read_version_ncbicxx_2_4_2 +#define mbedtls_ssl_recv_flight_completed \ + mbedtls_ssl_recv_flight_completed_ncbicxx_2_4_2 +#define mbedtls_ssl_renegotiate \ + mbedtls_ssl_renegotiate_ncbicxx_2_4_2 +#define mbedtls_ssl_resend \ + mbedtls_ssl_resend_ncbicxx_2_4_2 +#define mbedtls_ssl_reset_checksum \ + mbedtls_ssl_reset_checksum_ncbicxx_2_4_2 +#define mbedtls_ssl_send_alert_message \ + mbedtls_ssl_send_alert_message_ncbicxx_2_4_2 +#define mbedtls_ssl_send_fatal_handshake_failure \ + mbedtls_ssl_send_fatal_handshake_failure_ncbicxx_2_4_2 +#define mbedtls_ssl_send_flight_completed \ + mbedtls_ssl_send_flight_completed_ncbicxx_2_4_2 +#define mbedtls_ssl_session_free \ + mbedtls_ssl_session_free_ncbicxx_2_4_2 +#define mbedtls_ssl_session_init \ + mbedtls_ssl_session_init_ncbicxx_2_4_2 +#define mbedtls_ssl_session_reset \ + mbedtls_ssl_session_reset_ncbicxx_2_4_2 +#define mbedtls_ssl_set_bio \ + mbedtls_ssl_set_bio_ncbicxx_2_4_2 +#define mbedtls_ssl_set_calc_verify_md \ + mbedtls_ssl_set_calc_verify_md_ncbicxx_2_4_2 +#define mbedtls_ssl_set_hostname \ + mbedtls_ssl_set_hostname_ncbicxx_2_4_2 +#define mbedtls_ssl_set_hs_authmode \ + mbedtls_ssl_set_hs_authmode_ncbicxx_2_4_2 +#define mbedtls_ssl_set_hs_ca_chain \ + mbedtls_ssl_set_hs_ca_chain_ncbicxx_2_4_2 +#define mbedtls_ssl_set_hs_own_cert \ + mbedtls_ssl_set_hs_own_cert_ncbicxx_2_4_2 +#define mbedtls_ssl_set_hs_psk \ + mbedtls_ssl_set_hs_psk_ncbicxx_2_4_2 +#define mbedtls_ssl_set_session \ + mbedtls_ssl_set_session_ncbicxx_2_4_2 +#define mbedtls_ssl_set_timer_cb \ + mbedtls_ssl_set_timer_cb_ncbicxx_2_4_2 +#define mbedtls_ssl_setup \ + mbedtls_ssl_setup_ncbicxx_2_4_2 +#define mbedtls_ssl_sig_from_pk \ + mbedtls_ssl_sig_from_pk_ncbicxx_2_4_2 +#define mbedtls_ssl_transform_free \ + mbedtls_ssl_transform_free_ncbicxx_2_4_2 +#define mbedtls_ssl_update_handshake_status \ + mbedtls_ssl_update_handshake_status_ncbicxx_2_4_2 +#define mbedtls_ssl_write \ + mbedtls_ssl_write_ncbicxx_2_4_2 +#define mbedtls_ssl_write_certificate \ + mbedtls_ssl_write_certificate_ncbicxx_2_4_2 +#define mbedtls_ssl_write_change_cipher_spec \ + mbedtls_ssl_write_change_cipher_spec_ncbicxx_2_4_2 +#define mbedtls_ssl_write_finished \ + mbedtls_ssl_write_finished_ncbicxx_2_4_2 +#define mbedtls_ssl_write_record \ + mbedtls_ssl_write_record_ncbicxx_2_4_2 +#define mbedtls_ssl_write_version \ + mbedtls_ssl_write_version_ncbicxx_2_4_2 +#define mbedtls_set_alarm \ + mbedtls_set_alarm_ncbicxx_2_4_2 +#define mbedtls_timing_alarmed \ + mbedtls_timing_alarmed_ncbicxx_2_4_2 +#define mbedtls_timing_get_delay \ + mbedtls_timing_get_delay_ncbicxx_2_4_2 +#define mbedtls_timing_get_timer \ + mbedtls_timing_get_timer_ncbicxx_2_4_2 +#define mbedtls_timing_hardclock \ + mbedtls_timing_hardclock_ncbicxx_2_4_2 +#define mbedtls_timing_self_test \ + mbedtls_timing_self_test_ncbicxx_2_4_2 +#define mbedtls_timing_set_delay \ + mbedtls_timing_set_delay_ncbicxx_2_4_2 +#define mbedtls_version_get_number \ + mbedtls_version_get_number_ncbicxx_2_4_2 +#define mbedtls_version_get_string \ + mbedtls_version_get_string_ncbicxx_2_4_2 +#define mbedtls_version_get_string_full \ + mbedtls_version_get_string_full_ncbicxx_2_4_2 +#define mbedtls_version_check_feature \ + mbedtls_version_check_feature_ncbicxx_2_4_2 +#define mbedtls_x509_dn_gets \ + mbedtls_x509_dn_gets_ncbicxx_2_4_2 +#define mbedtls_x509_get_alg \ + mbedtls_x509_get_alg_ncbicxx_2_4_2 +#define mbedtls_x509_get_alg_null \ + mbedtls_x509_get_alg_null_ncbicxx_2_4_2 +#define mbedtls_x509_get_ext \ + mbedtls_x509_get_ext_ncbicxx_2_4_2 +#define mbedtls_x509_get_name \ + mbedtls_x509_get_name_ncbicxx_2_4_2 +#define mbedtls_x509_get_rsassa_pss_params \ + mbedtls_x509_get_rsassa_pss_params_ncbicxx_2_4_2 +#define mbedtls_x509_get_serial \ + mbedtls_x509_get_serial_ncbicxx_2_4_2 +#define mbedtls_x509_get_sig \ + mbedtls_x509_get_sig_ncbicxx_2_4_2 +#define mbedtls_x509_get_sig_alg \ + mbedtls_x509_get_sig_alg_ncbicxx_2_4_2 +#define mbedtls_x509_get_time \ + mbedtls_x509_get_time_ncbicxx_2_4_2 +#define mbedtls_x509_key_size_helper \ + mbedtls_x509_key_size_helper_ncbicxx_2_4_2 +#define mbedtls_x509_self_test \ + mbedtls_x509_self_test_ncbicxx_2_4_2 +#define mbedtls_x509_serial_gets \ + mbedtls_x509_serial_gets_ncbicxx_2_4_2 +#define mbedtls_x509_sig_alg_gets \ + mbedtls_x509_sig_alg_gets_ncbicxx_2_4_2 +#define mbedtls_x509_time_is_future \ + mbedtls_x509_time_is_future_ncbicxx_2_4_2 +#define mbedtls_x509_time_is_past \ + mbedtls_x509_time_is_past_ncbicxx_2_4_2 +#define mbedtls_x509_set_extension \ + mbedtls_x509_set_extension_ncbicxx_2_4_2 +#define mbedtls_x509_string_to_names \ + mbedtls_x509_string_to_names_ncbicxx_2_4_2 +#define mbedtls_x509_write_extensions \ + mbedtls_x509_write_extensions_ncbicxx_2_4_2 +#define mbedtls_x509_write_names \ + mbedtls_x509_write_names_ncbicxx_2_4_2 +#define mbedtls_x509_write_sig \ + mbedtls_x509_write_sig_ncbicxx_2_4_2 +#define mbedtls_x509_crl_free \ + mbedtls_x509_crl_free_ncbicxx_2_4_2 +#define mbedtls_x509_crl_info \ + mbedtls_x509_crl_info_ncbicxx_2_4_2 +#define mbedtls_x509_crl_init \ + mbedtls_x509_crl_init_ncbicxx_2_4_2 +#define mbedtls_x509_crl_parse \ + mbedtls_x509_crl_parse_ncbicxx_2_4_2 +#define mbedtls_x509_crl_parse_der \ + mbedtls_x509_crl_parse_der_ncbicxx_2_4_2 +#define mbedtls_x509_crl_parse_file \ + mbedtls_x509_crl_parse_file_ncbicxx_2_4_2 +#define mbedtls_x509_crt_check_extended_key_usage \ + mbedtls_x509_crt_check_extended_key_usage_ncbicxx_2_4_2 +#define mbedtls_x509_crt_check_key_usage \ + mbedtls_x509_crt_check_key_usage_ncbicxx_2_4_2 +#define mbedtls_x509_crt_free \ + mbedtls_x509_crt_free_ncbicxx_2_4_2 +#define mbedtls_x509_crt_info \ + mbedtls_x509_crt_info_ncbicxx_2_4_2 +#define mbedtls_x509_crt_init \ + mbedtls_x509_crt_init_ncbicxx_2_4_2 +#define mbedtls_x509_crt_is_revoked \ + mbedtls_x509_crt_is_revoked_ncbicxx_2_4_2 +#define mbedtls_x509_crt_parse \ + mbedtls_x509_crt_parse_ncbicxx_2_4_2 +#define mbedtls_x509_crt_parse_der \ + mbedtls_x509_crt_parse_der_ncbicxx_2_4_2 +#define mbedtls_x509_crt_parse_file \ + mbedtls_x509_crt_parse_file_ncbicxx_2_4_2 +#define mbedtls_x509_crt_parse_path \ + mbedtls_x509_crt_parse_path_ncbicxx_2_4_2 +#define mbedtls_x509_crt_profile_default \ + mbedtls_x509_crt_profile_default_ncbicxx_2_4_2 +#define mbedtls_x509_crt_profile_next \ + mbedtls_x509_crt_profile_next_ncbicxx_2_4_2 +#define mbedtls_x509_crt_profile_suiteb \ + mbedtls_x509_crt_profile_suiteb_ncbicxx_2_4_2 +#define mbedtls_x509_crt_verify \ + mbedtls_x509_crt_verify_ncbicxx_2_4_2 +#define mbedtls_x509_crt_verify_info \ + mbedtls_x509_crt_verify_info_ncbicxx_2_4_2 +#define mbedtls_x509_crt_verify_with_profile \ + mbedtls_x509_crt_verify_with_profile_ncbicxx_2_4_2 +#define mbedtls_x509_csr_free \ + mbedtls_x509_csr_free_ncbicxx_2_4_2 +#define mbedtls_x509_csr_info \ + mbedtls_x509_csr_info_ncbicxx_2_4_2 +#define mbedtls_x509_csr_init \ + mbedtls_x509_csr_init_ncbicxx_2_4_2 +#define mbedtls_x509_csr_parse \ + mbedtls_x509_csr_parse_ncbicxx_2_4_2 +#define mbedtls_x509_csr_parse_der \ + mbedtls_x509_csr_parse_der_ncbicxx_2_4_2 +#define mbedtls_x509_csr_parse_file \ + mbedtls_x509_csr_parse_file_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_der \ + mbedtls_x509write_crt_der_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_free \ + mbedtls_x509write_crt_free_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_init \ + mbedtls_x509write_crt_init_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_pem \ + mbedtls_x509write_crt_pem_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_authority_key_identifier \ + mbedtls_x509write_crt_set_authority_key_identifier_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_basic_constraints \ + mbedtls_x509write_crt_set_basic_constraints_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_extension \ + mbedtls_x509write_crt_set_extension_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_issuer_key \ + mbedtls_x509write_crt_set_issuer_key_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_issuer_name \ + mbedtls_x509write_crt_set_issuer_name_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_key_usage \ + mbedtls_x509write_crt_set_key_usage_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_md_alg \ + mbedtls_x509write_crt_set_md_alg_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_ns_cert_type \ + mbedtls_x509write_crt_set_ns_cert_type_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_serial \ + mbedtls_x509write_crt_set_serial_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_subject_key \ + mbedtls_x509write_crt_set_subject_key_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_subject_key_identifier \ + mbedtls_x509write_crt_set_subject_key_identifier_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_subject_name \ + mbedtls_x509write_crt_set_subject_name_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_validity \ + mbedtls_x509write_crt_set_validity_ncbicxx_2_4_2 +#define mbedtls_x509write_crt_set_version \ + mbedtls_x509write_crt_set_version_ncbicxx_2_4_2 +#define mbedtls_x509write_csr_der \ + mbedtls_x509write_csr_der_ncbicxx_2_4_2 +#define mbedtls_x509write_csr_free \ + mbedtls_x509write_csr_free_ncbicxx_2_4_2 +#define mbedtls_x509write_csr_init \ + mbedtls_x509write_csr_init_ncbicxx_2_4_2 +#define mbedtls_x509write_csr_pem \ + mbedtls_x509write_csr_pem_ncbicxx_2_4_2 +#define mbedtls_x509write_csr_set_extension \ + mbedtls_x509write_csr_set_extension_ncbicxx_2_4_2 +#define mbedtls_x509write_csr_set_key \ + mbedtls_x509write_csr_set_key_ncbicxx_2_4_2 +#define mbedtls_x509write_csr_set_key_usage \ + mbedtls_x509write_csr_set_key_usage_ncbicxx_2_4_2 +#define mbedtls_x509write_csr_set_md_alg \ + mbedtls_x509write_csr_set_md_alg_ncbicxx_2_4_2 +#define mbedtls_x509write_csr_set_ns_cert_type \ + mbedtls_x509write_csr_set_ns_cert_type_ncbicxx_2_4_2 +#define mbedtls_x509write_csr_set_subject_name \ + mbedtls_x509write_csr_set_subject_name_ncbicxx_2_4_2 +#define mbedtls_xtea_crypt_cbc \ + mbedtls_xtea_crypt_cbc_ncbicxx_2_4_2 +#define mbedtls_xtea_crypt_ecb \ + mbedtls_xtea_crypt_ecb_ncbicxx_2_4_2 +#define mbedtls_xtea_free \ + mbedtls_xtea_free_ncbicxx_2_4_2 +#define mbedtls_xtea_init \ + mbedtls_xtea_init_ncbicxx_2_4_2 +#define mbedtls_xtea_self_test \ + mbedtls_xtea_self_test_ncbicxx_2_4_2 +#define mbedtls_xtea_setup \ + mbedtls_xtea_setup_ncbicxx_2_4_2 diff --git a/c++/src/connect/mbedtls/mbedtls/net.h b/c++/src/connect/mbedtls/mbedtls/net.h new file mode 100644 index 00000000..c19e06eb --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/net.h @@ -0,0 +1,31 @@ +/** + * \file net.h + * + * \brief Deprecated header file that includes mbedtls/net_sockets.h + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + * + * \deprecated Superseded by mbedtls/net_sockets.h + */ + +#if !defined(MBEDTLS_DEPRECATED_REMOVED) +#include "net_sockets.h" +#if defined(MBEDTLS_DEPRECATED_WARNING) +#warning "Deprecated header file: Superseded by mbedtls/net_sockets.h" +#endif /* MBEDTLS_DEPRECATED_WARNING */ +#endif /* !MBEDTLS_DEPRECATED_REMOVED */ diff --git a/c++/src/connect/mbedtls/mbedtls/net_sockets.h b/c++/src/connect/mbedtls/mbedtls/net_sockets.h new file mode 100644 index 00000000..de335526 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/net_sockets.h @@ -0,0 +1,225 @@ +/** + * \file net_sockets.h + * + * \brief Network communication functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_NET_SOCKETS_H +#define MBEDTLS_NET_SOCKETS_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "ssl.h" + +#include +#include + +#define MBEDTLS_ERR_NET_SOCKET_FAILED -0x0042 /**< Failed to open a socket. */ +#define MBEDTLS_ERR_NET_CONNECT_FAILED -0x0044 /**< The connection to the given server / port failed. */ +#define MBEDTLS_ERR_NET_BIND_FAILED -0x0046 /**< Binding of the socket failed. */ +#define MBEDTLS_ERR_NET_LISTEN_FAILED -0x0048 /**< Could not listen on the socket. */ +#define MBEDTLS_ERR_NET_ACCEPT_FAILED -0x004A /**< Could not accept the incoming connection. */ +#define MBEDTLS_ERR_NET_RECV_FAILED -0x004C /**< Reading information from the socket failed. */ +#define MBEDTLS_ERR_NET_SEND_FAILED -0x004E /**< Sending information through the socket failed. */ +#define MBEDTLS_ERR_NET_CONN_RESET -0x0050 /**< Connection was reset by peer. */ +#define MBEDTLS_ERR_NET_UNKNOWN_HOST -0x0052 /**< Failed to get an IP address for the given hostname. */ +#define MBEDTLS_ERR_NET_BUFFER_TOO_SMALL -0x0043 /**< Buffer is too small to hold the data. */ +#define MBEDTLS_ERR_NET_INVALID_CONTEXT -0x0045 /**< The context is invalid, eg because it was free()ed. */ + +#define MBEDTLS_NET_LISTEN_BACKLOG 10 /**< The backlog that listen() should use. */ + +#define MBEDTLS_NET_PROTO_TCP 0 /**< The TCP transport protocol */ +#define MBEDTLS_NET_PROTO_UDP 1 /**< The UDP transport protocol */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Wrapper type for sockets. + * + * Currently backed by just a file descriptor, but might be more in the future + * (eg two file descriptors for combined IPv4 + IPv6 support, or additional + * structures for hand-made UDP demultiplexing). + */ +typedef struct +{ + int fd; /**< The underlying file descriptor */ +} +mbedtls_net_context; + +/** + * \brief Initialize a context + * Just makes the context ready to be used or freed safely. + * + * \param ctx Context to initialize + */ +void mbedtls_net_init( mbedtls_net_context *ctx ); + +/** + * \brief Initiate a connection with host:port in the given protocol + * + * \param ctx Socket to use + * \param host Host to connect to + * \param port Port to connect to + * \param proto Protocol: MBEDTLS_NET_PROTO_TCP or MBEDTLS_NET_PROTO_UDP + * + * \return 0 if successful, or one of: + * MBEDTLS_ERR_NET_SOCKET_FAILED, + * MBEDTLS_ERR_NET_UNKNOWN_HOST, + * MBEDTLS_ERR_NET_CONNECT_FAILED + * + * \note Sets the socket in connected mode even with UDP. + */ +int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, const char *port, int proto ); + +/** + * \brief Create a receiving socket on bind_ip:port in the chosen + * protocol. If bind_ip == NULL, all interfaces are bound. + * + * \param ctx Socket to use + * \param bind_ip IP to bind to, can be NULL + * \param port Port number to use + * \param proto Protocol: MBEDTLS_NET_PROTO_TCP or MBEDTLS_NET_PROTO_UDP + * + * \return 0 if successful, or one of: + * MBEDTLS_ERR_NET_SOCKET_FAILED, + * MBEDTLS_ERR_NET_BIND_FAILED, + * MBEDTLS_ERR_NET_LISTEN_FAILED + * + * \note Regardless of the protocol, opens the sockets and binds it. + * In addition, make the socket listening if protocol is TCP. + */ +int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto ); + +/** + * \brief Accept a connection from a remote client + * + * \param bind_ctx Relevant socket + * \param client_ctx Will contain the connected client socket + * \param client_ip Will contain the client IP address + * \param buf_size Size of the client_ip buffer + * \param ip_len Will receive the size of the client IP written + * + * \return 0 if successful, or + * MBEDTLS_ERR_NET_ACCEPT_FAILED, or + * MBEDTLS_ERR_NET_BUFFER_TOO_SMALL if buf_size is too small, + * MBEDTLS_ERR_SSL_WANT_READ if bind_fd was set to + * non-blocking and accept() would block. + */ +int mbedtls_net_accept( mbedtls_net_context *bind_ctx, + mbedtls_net_context *client_ctx, + void *client_ip, size_t buf_size, size_t *ip_len ); + +/** + * \brief Set the socket blocking + * + * \param ctx Socket to set + * + * \return 0 if successful, or a non-zero error code + */ +int mbedtls_net_set_block( mbedtls_net_context *ctx ); + +/** + * \brief Set the socket non-blocking + * + * \param ctx Socket to set + * + * \return 0 if successful, or a non-zero error code + */ +int mbedtls_net_set_nonblock( mbedtls_net_context *ctx ); + +/** + * \brief Portable usleep helper + * + * \param usec Amount of microseconds to sleep + * + * \note Real amount of time slept will not be less than + * select()'s timeout granularity (typically, 10ms). + */ +void mbedtls_net_usleep( unsigned long usec ); + +/** + * \brief Read at most 'len' characters. If no error occurs, + * the actual amount read is returned. + * + * \param ctx Socket + * \param buf The buffer to write to + * \param len Maximum length of the buffer + * + * \return the number of bytes received, + * or a non-zero error code; with a non-blocking socket, + * MBEDTLS_ERR_SSL_WANT_READ indicates read() would block. + */ +int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ); + +/** + * \brief Write at most 'len' characters. If no error occurs, + * the actual amount read is returned. + * + * \param ctx Socket + * \param buf The buffer to read from + * \param len The length of the buffer + * + * \return the number of bytes sent, + * or a non-zero error code; with a non-blocking socket, + * MBEDTLS_ERR_SSL_WANT_WRITE indicates write() would block. + */ +int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ); + +/** + * \brief Read at most 'len' characters, blocking for at most + * 'timeout' seconds. If no error occurs, the actual amount + * read is returned. + * + * \param ctx Socket + * \param buf The buffer to write to + * \param len Maximum length of the buffer + * \param timeout Maximum number of milliseconds to wait for data + * 0 means no timeout (wait forever) + * + * \return the number of bytes received, + * or a non-zero error code: + * MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out, + * MBEDTLS_ERR_SSL_WANT_READ if interrupted by a signal. + * + * \note This function will block (until data becomes available or + * timeout is reached) even if the socket is set to + * non-blocking. Handling timeouts with non-blocking reads + * requires a different strategy. + */ +int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, + uint32_t timeout ); + +/** + * \brief Gracefully shutdown the connection and free associated data + * + * \param ctx The context to free + */ +void mbedtls_net_free( mbedtls_net_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* net_sockets.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/oid.h b/c++/src/connect/mbedtls/mbedtls/oid.h new file mode 100644 index 00000000..fcecdafd --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/oid.h @@ -0,0 +1,570 @@ +/** + * \file oid.h + * + * \brief Object Identifier (OID) database + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_OID_H +#define MBEDTLS_OID_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "asn1.h" +#include "pk.h" + +#include + +#if defined(MBEDTLS_CIPHER_C) +#include "cipher.h" +#endif + +#if defined(MBEDTLS_MD_C) +#include "md.h" +#endif + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "x509.h" +#endif + +#define MBEDTLS_ERR_OID_NOT_FOUND -0x002E /**< OID is not found. */ +#define MBEDTLS_ERR_OID_BUF_TOO_SMALL -0x000B /**< output buffer is too small */ + +/* + * Top level OID tuples + */ +#define MBEDTLS_OID_ISO_MEMBER_BODIES "\x2a" /* {iso(1) member-body(2)} */ +#define MBEDTLS_OID_ISO_IDENTIFIED_ORG "\x2b" /* {iso(1) identified-organization(3)} */ +#define MBEDTLS_OID_ISO_CCITT_DS "\x55" /* {joint-iso-ccitt(2) ds(5)} */ +#define MBEDTLS_OID_ISO_ITU_COUNTRY "\x60" /* {joint-iso-itu-t(2) country(16)} */ + +/* + * ISO Member bodies OID parts + */ +#define MBEDTLS_OID_COUNTRY_US "\x86\x48" /* {us(840)} */ +#define MBEDTLS_OID_ORG_RSA_DATA_SECURITY "\x86\xf7\x0d" /* {rsadsi(113549)} */ +#define MBEDTLS_OID_RSA_COMPANY MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \ + MBEDTLS_OID_ORG_RSA_DATA_SECURITY /* {iso(1) member-body(2) us(840) rsadsi(113549)} */ +#define MBEDTLS_OID_ORG_ANSI_X9_62 "\xce\x3d" /* ansi-X9-62(10045) */ +#define MBEDTLS_OID_ANSI_X9_62 MBEDTLS_OID_ISO_MEMBER_BODIES MBEDTLS_OID_COUNTRY_US \ + MBEDTLS_OID_ORG_ANSI_X9_62 + +/* + * ISO Identified organization OID parts + */ +#define MBEDTLS_OID_ORG_DOD "\x06" /* {dod(6)} */ +#define MBEDTLS_OID_ORG_OIW "\x0e" +#define MBEDTLS_OID_OIW_SECSIG MBEDTLS_OID_ORG_OIW "\x03" +#define MBEDTLS_OID_OIW_SECSIG_ALG MBEDTLS_OID_OIW_SECSIG "\x02" +#define MBEDTLS_OID_OIW_SECSIG_SHA1 MBEDTLS_OID_OIW_SECSIG_ALG "\x1a" +#define MBEDTLS_OID_ORG_CERTICOM "\x81\x04" /* certicom(132) */ +#define MBEDTLS_OID_CERTICOM MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_CERTICOM +#define MBEDTLS_OID_ORG_TELETRUST "\x24" /* teletrust(36) */ +#define MBEDTLS_OID_TELETRUST MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_TELETRUST + +/* + * ISO ITU OID parts + */ +#define MBEDTLS_OID_ORGANIZATION "\x01" /* {organization(1)} */ +#define MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ISO_ITU_COUNTRY MBEDTLS_OID_COUNTRY_US MBEDTLS_OID_ORGANIZATION /* {joint-iso-itu-t(2) country(16) us(840) organization(1)} */ + +#define MBEDTLS_OID_ORG_GOV "\x65" /* {gov(101)} */ +#define MBEDTLS_OID_GOV MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_GOV /* {joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101)} */ + +#define MBEDTLS_OID_ORG_NETSCAPE "\x86\xF8\x42" /* {netscape(113730)} */ +#define MBEDTLS_OID_NETSCAPE MBEDTLS_OID_ISO_ITU_US_ORG MBEDTLS_OID_ORG_NETSCAPE /* Netscape OID {joint-iso-itu-t(2) country(16) us(840) organization(1) netscape(113730)} */ + +/* ISO arc for standard certificate and CRL extensions */ +#define MBEDTLS_OID_ID_CE MBEDTLS_OID_ISO_CCITT_DS "\x1D" /**< id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29} */ + +/** + * Private Internet Extensions + * { iso(1) identified-organization(3) dod(6) internet(1) + * security(5) mechanisms(5) pkix(7) } + */ +#define MBEDTLS_OID_PKIX MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_ORG_DOD "\x01\x05\x05\x07" + +/* + * Arc for standard naming attributes + */ +#define MBEDTLS_OID_AT MBEDTLS_OID_ISO_CCITT_DS "\x04" /**< id-at OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 4} */ +#define MBEDTLS_OID_AT_CN MBEDTLS_OID_AT "\x03" /**< id-at-commonName AttributeType:= {id-at 3} */ +#define MBEDTLS_OID_AT_SUR_NAME MBEDTLS_OID_AT "\x04" /**< id-at-surName AttributeType:= {id-at 4} */ +#define MBEDTLS_OID_AT_SERIAL_NUMBER MBEDTLS_OID_AT "\x05" /**< id-at-serialNumber AttributeType:= {id-at 5} */ +#define MBEDTLS_OID_AT_COUNTRY MBEDTLS_OID_AT "\x06" /**< id-at-countryName AttributeType:= {id-at 6} */ +#define MBEDTLS_OID_AT_LOCALITY MBEDTLS_OID_AT "\x07" /**< id-at-locality AttributeType:= {id-at 7} */ +#define MBEDTLS_OID_AT_STATE MBEDTLS_OID_AT "\x08" /**< id-at-state AttributeType:= {id-at 8} */ +#define MBEDTLS_OID_AT_ORGANIZATION MBEDTLS_OID_AT "\x0A" /**< id-at-organizationName AttributeType:= {id-at 10} */ +#define MBEDTLS_OID_AT_ORG_UNIT MBEDTLS_OID_AT "\x0B" /**< id-at-organizationalUnitName AttributeType:= {id-at 11} */ +#define MBEDTLS_OID_AT_TITLE MBEDTLS_OID_AT "\x0C" /**< id-at-title AttributeType:= {id-at 12} */ +#define MBEDTLS_OID_AT_POSTAL_ADDRESS MBEDTLS_OID_AT "\x10" /**< id-at-postalAddress AttributeType:= {id-at 16} */ +#define MBEDTLS_OID_AT_POSTAL_CODE MBEDTLS_OID_AT "\x11" /**< id-at-postalCode AttributeType:= {id-at 17} */ +#define MBEDTLS_OID_AT_GIVEN_NAME MBEDTLS_OID_AT "\x2A" /**< id-at-givenName AttributeType:= {id-at 42} */ +#define MBEDTLS_OID_AT_INITIALS MBEDTLS_OID_AT "\x2B" /**< id-at-initials AttributeType:= {id-at 43} */ +#define MBEDTLS_OID_AT_GENERATION_QUALIFIER MBEDTLS_OID_AT "\x2C" /**< id-at-generationQualifier AttributeType:= {id-at 44} */ +#define MBEDTLS_OID_AT_UNIQUE_IDENTIFIER MBEDTLS_OID_AT "\x2D" /**< id-at-uniqueIdentifier AttributType:= {id-at 45} */ +#define MBEDTLS_OID_AT_DN_QUALIFIER MBEDTLS_OID_AT "\x2E" /**< id-at-dnQualifier AttributeType:= {id-at 46} */ +#define MBEDTLS_OID_AT_PSEUDONYM MBEDTLS_OID_AT "\x41" /**< id-at-pseudonym AttributeType:= {id-at 65} */ + +#define MBEDTLS_OID_DOMAIN_COMPONENT "\x09\x92\x26\x89\x93\xF2\x2C\x64\x01\x19" /** id-domainComponent AttributeType:= {itu-t(0) data(9) pss(2342) ucl(19200300) pilot(100) pilotAttributeType(1) domainComponent(25)} */ + +/* + * OIDs for standard certificate extensions + */ +#define MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x23" /**< id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 } */ +#define MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER MBEDTLS_OID_ID_CE "\x0E" /**< id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 } */ +#define MBEDTLS_OID_KEY_USAGE MBEDTLS_OID_ID_CE "\x0F" /**< id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 } */ +#define MBEDTLS_OID_CERTIFICATE_POLICIES MBEDTLS_OID_ID_CE "\x20" /**< id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 } */ +#define MBEDTLS_OID_POLICY_MAPPINGS MBEDTLS_OID_ID_CE "\x21" /**< id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 } */ +#define MBEDTLS_OID_SUBJECT_ALT_NAME MBEDTLS_OID_ID_CE "\x11" /**< id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 } */ +#define MBEDTLS_OID_ISSUER_ALT_NAME MBEDTLS_OID_ID_CE "\x12" /**< id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 } */ +#define MBEDTLS_OID_SUBJECT_DIRECTORY_ATTRS MBEDTLS_OID_ID_CE "\x09" /**< id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 } */ +#define MBEDTLS_OID_BASIC_CONSTRAINTS MBEDTLS_OID_ID_CE "\x13" /**< id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 } */ +#define MBEDTLS_OID_NAME_CONSTRAINTS MBEDTLS_OID_ID_CE "\x1E" /**< id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 } */ +#define MBEDTLS_OID_POLICY_CONSTRAINTS MBEDTLS_OID_ID_CE "\x24" /**< id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 } */ +#define MBEDTLS_OID_EXTENDED_KEY_USAGE MBEDTLS_OID_ID_CE "\x25" /**< id-ce-extKeyUsage OBJECT IDENTIFIER ::= { id-ce 37 } */ +#define MBEDTLS_OID_CRL_DISTRIBUTION_POINTS MBEDTLS_OID_ID_CE "\x1F" /**< id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= { id-ce 31 } */ +#define MBEDTLS_OID_INIHIBIT_ANYPOLICY MBEDTLS_OID_ID_CE "\x36" /**< id-ce-inhibitAnyPolicy OBJECT IDENTIFIER ::= { id-ce 54 } */ +#define MBEDTLS_OID_FRESHEST_CRL MBEDTLS_OID_ID_CE "\x2E" /**< id-ce-freshestCRL OBJECT IDENTIFIER ::= { id-ce 46 } */ + +/* + * Netscape certificate extensions + */ +#define MBEDTLS_OID_NS_CERT MBEDTLS_OID_NETSCAPE "\x01" +#define MBEDTLS_OID_NS_CERT_TYPE MBEDTLS_OID_NS_CERT "\x01" +#define MBEDTLS_OID_NS_BASE_URL MBEDTLS_OID_NS_CERT "\x02" +#define MBEDTLS_OID_NS_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x03" +#define MBEDTLS_OID_NS_CA_REVOCATION_URL MBEDTLS_OID_NS_CERT "\x04" +#define MBEDTLS_OID_NS_RENEWAL_URL MBEDTLS_OID_NS_CERT "\x07" +#define MBEDTLS_OID_NS_CA_POLICY_URL MBEDTLS_OID_NS_CERT "\x08" +#define MBEDTLS_OID_NS_SSL_SERVER_NAME MBEDTLS_OID_NS_CERT "\x0C" +#define MBEDTLS_OID_NS_COMMENT MBEDTLS_OID_NS_CERT "\x0D" +#define MBEDTLS_OID_NS_DATA_TYPE MBEDTLS_OID_NETSCAPE "\x02" +#define MBEDTLS_OID_NS_CERT_SEQUENCE MBEDTLS_OID_NS_DATA_TYPE "\x05" + +/* + * OIDs for CRL extensions + */ +#define MBEDTLS_OID_PRIVATE_KEY_USAGE_PERIOD MBEDTLS_OID_ID_CE "\x10" +#define MBEDTLS_OID_CRL_NUMBER MBEDTLS_OID_ID_CE "\x14" /**< id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 } */ + +/* + * X.509 v3 Extended key usage OIDs + */ +#define MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE MBEDTLS_OID_EXTENDED_KEY_USAGE "\x00" /**< anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } */ + +#define MBEDTLS_OID_KP MBEDTLS_OID_PKIX "\x03" /**< id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } */ +#define MBEDTLS_OID_SERVER_AUTH MBEDTLS_OID_KP "\x01" /**< id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } */ +#define MBEDTLS_OID_CLIENT_AUTH MBEDTLS_OID_KP "\x02" /**< id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } */ +#define MBEDTLS_OID_CODE_SIGNING MBEDTLS_OID_KP "\x03" /**< id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } */ +#define MBEDTLS_OID_EMAIL_PROTECTION MBEDTLS_OID_KP "\x04" /**< id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } */ +#define MBEDTLS_OID_TIME_STAMPING MBEDTLS_OID_KP "\x08" /**< id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } */ +#define MBEDTLS_OID_OCSP_SIGNING MBEDTLS_OID_KP "\x09" /**< id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } */ + +/* + * PKCS definition OIDs + */ + +#define MBEDTLS_OID_PKCS MBEDTLS_OID_RSA_COMPANY "\x01" /**< pkcs OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) 1 } */ +#define MBEDTLS_OID_PKCS1 MBEDTLS_OID_PKCS "\x01" /**< pkcs-1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } */ +#define MBEDTLS_OID_PKCS5 MBEDTLS_OID_PKCS "\x05" /**< pkcs-5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } */ +#define MBEDTLS_OID_PKCS9 MBEDTLS_OID_PKCS "\x09" /**< pkcs-9 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } */ +#define MBEDTLS_OID_PKCS12 MBEDTLS_OID_PKCS "\x0c" /**< pkcs-12 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } */ + +/* + * PKCS#1 OIDs + */ +#define MBEDTLS_OID_PKCS1_RSA MBEDTLS_OID_PKCS1 "\x01" /**< rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 } */ +#define MBEDTLS_OID_PKCS1_MD2 MBEDTLS_OID_PKCS1 "\x02" /**< md2WithRSAEncryption ::= { pkcs-1 2 } */ +#define MBEDTLS_OID_PKCS1_MD4 MBEDTLS_OID_PKCS1 "\x03" /**< md4WithRSAEncryption ::= { pkcs-1 3 } */ +#define MBEDTLS_OID_PKCS1_MD5 MBEDTLS_OID_PKCS1 "\x04" /**< md5WithRSAEncryption ::= { pkcs-1 4 } */ +#define MBEDTLS_OID_PKCS1_SHA1 MBEDTLS_OID_PKCS1 "\x05" /**< sha1WithRSAEncryption ::= { pkcs-1 5 } */ +#define MBEDTLS_OID_PKCS1_SHA224 MBEDTLS_OID_PKCS1 "\x0e" /**< sha224WithRSAEncryption ::= { pkcs-1 14 } */ +#define MBEDTLS_OID_PKCS1_SHA256 MBEDTLS_OID_PKCS1 "\x0b" /**< sha256WithRSAEncryption ::= { pkcs-1 11 } */ +#define MBEDTLS_OID_PKCS1_SHA384 MBEDTLS_OID_PKCS1 "\x0c" /**< sha384WithRSAEncryption ::= { pkcs-1 12 } */ +#define MBEDTLS_OID_PKCS1_SHA512 MBEDTLS_OID_PKCS1 "\x0d" /**< sha512WithRSAEncryption ::= { pkcs-1 13 } */ + +#define MBEDTLS_OID_RSA_SHA_OBS "\x2B\x0E\x03\x02\x1D" + +#define MBEDTLS_OID_PKCS9_EMAIL MBEDTLS_OID_PKCS9 "\x01" /**< emailAddress AttributeType ::= { pkcs-9 1 } */ + +/* RFC 4055 */ +#define MBEDTLS_OID_RSASSA_PSS MBEDTLS_OID_PKCS1 "\x0a" /**< id-RSASSA-PSS ::= { pkcs-1 10 } */ +#define MBEDTLS_OID_MGF1 MBEDTLS_OID_PKCS1 "\x08" /**< id-mgf1 ::= { pkcs-1 8 } */ + +/* + * Digest algorithms + */ +#define MBEDTLS_OID_DIGEST_ALG_MD2 MBEDTLS_OID_RSA_COMPANY "\x02\x02" /**< id-mbedtls_md2 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 2 } */ +#define MBEDTLS_OID_DIGEST_ALG_MD4 MBEDTLS_OID_RSA_COMPANY "\x02\x04" /**< id-mbedtls_md4 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 4 } */ +#define MBEDTLS_OID_DIGEST_ALG_MD5 MBEDTLS_OID_RSA_COMPANY "\x02\x05" /**< id-mbedtls_md5 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 5 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA1 MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_SHA1 /**< id-mbedtls_sha1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 26 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA224 MBEDTLS_OID_GOV "\x03\x04\x02\x04" /**< id-sha224 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 4 } */ +#define MBEDTLS_OID_DIGEST_ALG_SHA256 MBEDTLS_OID_GOV "\x03\x04\x02\x01" /**< id-mbedtls_sha256 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 } */ + +#define MBEDTLS_OID_DIGEST_ALG_SHA384 MBEDTLS_OID_GOV "\x03\x04\x02\x02" /**< id-sha384 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 2 } */ + +#define MBEDTLS_OID_DIGEST_ALG_SHA512 MBEDTLS_OID_GOV "\x03\x04\x02\x03" /**< id-mbedtls_sha512 OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 } */ + +#define MBEDTLS_OID_HMAC_SHA1 MBEDTLS_OID_RSA_COMPANY "\x02\x07" /**< id-hmacWithSHA1 OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) digestAlgorithm(2) 7 } */ + +/* + * Encryption algorithms + */ +#define MBEDTLS_OID_DES_CBC MBEDTLS_OID_ISO_IDENTIFIED_ORG MBEDTLS_OID_OIW_SECSIG_ALG "\x07" /**< desCBC OBJECT IDENTIFIER ::= { iso(1) identified-organization(3) oiw(14) secsig(3) algorithms(2) 7 } */ +#define MBEDTLS_OID_DES_EDE3_CBC MBEDTLS_OID_RSA_COMPANY "\x03\x07" /**< des-ede3-cbc OBJECT IDENTIFIER ::= { iso(1) member-body(2) -- us(840) rsadsi(113549) encryptionAlgorithm(3) 7 } */ + +/* + * PKCS#5 OIDs + */ +#define MBEDTLS_OID_PKCS5_PBKDF2 MBEDTLS_OID_PKCS5 "\x0c" /**< id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12} */ +#define MBEDTLS_OID_PKCS5_PBES2 MBEDTLS_OID_PKCS5 "\x0d" /**< id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13} */ +#define MBEDTLS_OID_PKCS5_PBMAC1 MBEDTLS_OID_PKCS5 "\x0e" /**< id-PBMAC1 OBJECT IDENTIFIER ::= {pkcs-5 14} */ + +/* + * PKCS#5 PBES1 algorithms + */ +#define MBEDTLS_OID_PKCS5_PBE_MD2_DES_CBC MBEDTLS_OID_PKCS5 "\x01" /**< pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1} */ +#define MBEDTLS_OID_PKCS5_PBE_MD2_RC2_CBC MBEDTLS_OID_PKCS5 "\x04" /**< pbeWithMD2AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 4} */ +#define MBEDTLS_OID_PKCS5_PBE_MD5_DES_CBC MBEDTLS_OID_PKCS5 "\x03" /**< pbeWithMD5AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 3} */ +#define MBEDTLS_OID_PKCS5_PBE_MD5_RC2_CBC MBEDTLS_OID_PKCS5 "\x06" /**< pbeWithMD5AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 6} */ +#define MBEDTLS_OID_PKCS5_PBE_SHA1_DES_CBC MBEDTLS_OID_PKCS5 "\x0a" /**< pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10} */ +#define MBEDTLS_OID_PKCS5_PBE_SHA1_RC2_CBC MBEDTLS_OID_PKCS5 "\x0b" /**< pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11} */ + +/* + * PKCS#8 OIDs + */ +#define MBEDTLS_OID_PKCS9_CSR_EXT_REQ MBEDTLS_OID_PKCS9 "\x0e" /**< extensionRequest OBJECT IDENTIFIER ::= {pkcs-9 14} */ + +/* + * PKCS#12 PBE OIDs + */ +#define MBEDTLS_OID_PKCS12_PBE MBEDTLS_OID_PKCS12 "\x01" /**< pkcs-12PbeIds OBJECT IDENTIFIER ::= {pkcs-12 1} */ + +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128 MBEDTLS_OID_PKCS12_PBE "\x01" /**< pbeWithSHAAnd128BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 1} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_40 MBEDTLS_OID_PKCS12_PBE "\x02" /**< pbeWithSHAAnd40BitRC4 OBJECT IDENTIFIER ::= {pkcs-12PbeIds 2} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x03" /**< pbeWithSHAAnd3-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 3} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC MBEDTLS_OID_PKCS12_PBE "\x04" /**< pbeWithSHAAnd2-KeyTripleDES-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 4} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_128_CBC MBEDTLS_OID_PKCS12_PBE "\x05" /**< pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 5} */ +#define MBEDTLS_OID_PKCS12_PBE_SHA1_RC2_40_CBC MBEDTLS_OID_PKCS12_PBE "\x06" /**< pbeWithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 6} */ + +/* + * EC key algorithms from RFC 5480 + */ + +/* id-ecPublicKey OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } */ +#define MBEDTLS_OID_EC_ALG_UNRESTRICTED MBEDTLS_OID_ANSI_X9_62 "\x02\01" + +/* id-ecDH OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) + * schemes(1) ecdh(12) } */ +#define MBEDTLS_OID_EC_ALG_ECDH MBEDTLS_OID_CERTICOM "\x01\x0c" + +/* + * ECParameters namedCurve identifiers, from RFC 5480, RFC 5639, and SEC2 + */ + +/* secp192r1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 1 } */ +#define MBEDTLS_OID_EC_GRP_SECP192R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x01" + +/* secp224r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 33 } */ +#define MBEDTLS_OID_EC_GRP_SECP224R1 MBEDTLS_OID_CERTICOM "\x00\x21" + +/* secp256r1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 7 } */ +#define MBEDTLS_OID_EC_GRP_SECP256R1 MBEDTLS_OID_ANSI_X9_62 "\x03\x01\x07" + +/* secp384r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 34 } */ +#define MBEDTLS_OID_EC_GRP_SECP384R1 MBEDTLS_OID_CERTICOM "\x00\x22" + +/* secp521r1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 35 } */ +#define MBEDTLS_OID_EC_GRP_SECP521R1 MBEDTLS_OID_CERTICOM "\x00\x23" + +/* secp192k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 31 } */ +#define MBEDTLS_OID_EC_GRP_SECP192K1 MBEDTLS_OID_CERTICOM "\x00\x1f" + +/* secp224k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 32 } */ +#define MBEDTLS_OID_EC_GRP_SECP224K1 MBEDTLS_OID_CERTICOM "\x00\x20" + +/* secp256k1 OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) curve(0) 10 } */ +#define MBEDTLS_OID_EC_GRP_SECP256K1 MBEDTLS_OID_CERTICOM "\x00\x0a" + +/* RFC 5639 4.1 + * ecStdCurvesAndGeneration OBJECT IDENTIFIER::= {iso(1) + * identified-organization(3) teletrust(36) algorithm(3) signature- + * algorithm(3) ecSign(2) 8} + * ellipticCurve OBJECT IDENTIFIER ::= {ecStdCurvesAndGeneration 1} + * versionOne OBJECT IDENTIFIER ::= {ellipticCurve 1} */ +#define MBEDTLS_OID_EC_BRAINPOOL_V1 MBEDTLS_OID_TELETRUST "\x03\x03\x02\x08\x01\x01" + +/* brainpoolP256r1 OBJECT IDENTIFIER ::= {versionOne 7} */ +#define MBEDTLS_OID_EC_GRP_BP256R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x07" + +/* brainpoolP384r1 OBJECT IDENTIFIER ::= {versionOne 11} */ +#define MBEDTLS_OID_EC_GRP_BP384R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0B" + +/* brainpoolP512r1 OBJECT IDENTIFIER ::= {versionOne 13} */ +#define MBEDTLS_OID_EC_GRP_BP512R1 MBEDTLS_OID_EC_BRAINPOOL_V1 "\x0D" + +/* + * SEC1 C.1 + * + * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } + * id-fieldType OBJECT IDENTIFIER ::= { ansi-X9-62 fieldType(1)} + */ +#define MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE MBEDTLS_OID_ANSI_X9_62 "\x01" +#define MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD MBEDTLS_OID_ANSI_X9_62_FIELD_TYPE "\x01" + +/* + * ECDSA signature identifiers, from RFC 5480 + */ +#define MBEDTLS_OID_ANSI_X9_62_SIG MBEDTLS_OID_ANSI_X9_62 "\x04" /* signatures(4) */ +#define MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 MBEDTLS_OID_ANSI_X9_62_SIG "\x03" /* ecdsa-with-SHA2(3) */ + +/* ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) 1 } */ +#define MBEDTLS_OID_ECDSA_SHA1 MBEDTLS_OID_ANSI_X9_62_SIG "\x01" + +/* ecdsa-with-SHA224 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 1 } */ +#define MBEDTLS_OID_ECDSA_SHA224 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x01" + +/* ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 2 } */ +#define MBEDTLS_OID_ECDSA_SHA256 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x02" + +/* ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 3 } */ +#define MBEDTLS_OID_ECDSA_SHA384 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x03" + +/* ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { + * iso(1) member-body(2) us(840) ansi-X9-62(10045) signatures(4) + * ecdsa-with-SHA2(3) 4 } */ +#define MBEDTLS_OID_ECDSA_SHA512 MBEDTLS_OID_ANSI_X9_62_SIG_SHA2 "\x04" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Base OID descriptor structure + */ +typedef struct { + const char *asn1; /*!< OID ASN.1 representation */ + size_t asn1_len; /*!< length of asn1 */ + const char *name; /*!< official name (e.g. from RFC) */ + const char *description; /*!< human friendly description */ +} mbedtls_oid_descriptor_t; + +/** + * \brief Translate an ASN.1 OID into its numeric representation + * (e.g. "\x2A\x86\x48\x86\xF7\x0D" into "1.2.840.113549") + * + * \param buf buffer to put representation in + * \param size size of the buffer + * \param oid OID to translate + * + * \return Length of the string written (excluding final NULL) or + * MBEDTLS_ERR_OID_BUF_TOO_SMALL in case of error + */ +int mbedtls_oid_get_numeric_string( char *buf, size_t size, const mbedtls_asn1_buf *oid ); + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +/** + * \brief Translate an X.509 extension OID into local values + * + * \param oid OID to use + * \param ext_type place to store the extension type + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_x509_ext_type( const mbedtls_asn1_buf *oid, int *ext_type ); +#endif + +/** + * \brief Translate an X.509 attribute type OID into the short name + * (e.g. the OID for an X520 Common Name into "CN") + * + * \param oid OID to use + * \param short_name place to store the string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_attr_short_name( const mbedtls_asn1_buf *oid, const char **short_name ); + +/** + * \brief Translate PublicKeyAlgorithm OID into pk_type + * + * \param oid OID to use + * \param pk_alg place to store public key algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_pk_alg( const mbedtls_asn1_buf *oid, mbedtls_pk_type_t *pk_alg ); + +/** + * \brief Translate pk_type into PublicKeyAlgorithm OID + * + * \param pk_alg Public key type to look for + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_type_t pk_alg, + const char **oid, size_t *olen ); + +#if defined(MBEDTLS_ECP_C) +/** + * \brief Translate NamedCurve OID into an EC group identifier + * + * \param oid OID to use + * \param grp_id place to store group id + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_ec_grp( const mbedtls_asn1_buf *oid, mbedtls_ecp_group_id *grp_id ); + +/** + * \brief Translate EC group identifier into NamedCurve OID + * + * \param grp_id EC group identifier + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_ec_grp( mbedtls_ecp_group_id grp_id, + const char **oid, size_t *olen ); +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_MD_C) +/** + * \brief Translate SignatureAlgorithm OID into md_type and pk_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * \param pk_alg place to store public key algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_sig_alg( const mbedtls_asn1_buf *oid, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg ); + +/** + * \brief Translate SignatureAlgorithm OID into description + * + * \param oid OID to use + * \param desc place to store string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_sig_alg_desc( const mbedtls_asn1_buf *oid, const char **desc ); + +/** + * \brief Translate md_type and pk_type into SignatureAlgorithm OID + * + * \param md_alg message digest algorithm + * \param pk_alg public key algorithm + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_sig_alg( mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const char **oid, size_t *olen ); + +/** + * \brief Translate hash algorithm OID into md_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_md_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg ); +#endif /* MBEDTLS_MD_C */ + +/** + * \brief Translate Extended Key Usage OID into description + * + * \param oid OID to use + * \param desc place to store string pointer + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_extended_key_usage( const mbedtls_asn1_buf *oid, const char **desc ); + +/** + * \brief Translate md_type into hash algorithm OID + * + * \param md_alg message digest algorithm + * \param oid place to store ASN.1 OID string pointer + * \param olen length of the OID + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_oid_by_md( mbedtls_md_type_t md_alg, const char **oid, size_t *olen ); + +#if defined(MBEDTLS_CIPHER_C) +/** + * \brief Translate encryption algorithm OID into cipher_type + * + * \param oid OID to use + * \param cipher_alg place to store cipher algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_cipher_alg( const mbedtls_asn1_buf *oid, mbedtls_cipher_type_t *cipher_alg ); +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_PKCS12_C) +/** + * \brief Translate PKCS#12 PBE algorithm OID into md_type and + * cipher_type + * + * \param oid OID to use + * \param md_alg place to store message digest algorithm + * \param cipher_alg place to store cipher algorithm + * + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ +int mbedtls_oid_get_pkcs12_pbe_alg( const mbedtls_asn1_buf *oid, mbedtls_md_type_t *md_alg, + mbedtls_cipher_type_t *cipher_alg ); +#endif /* MBEDTLS_PKCS12_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* oid.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/padlock.h b/c++/src/connect/mbedtls/mbedtls/padlock.h new file mode 100644 index 00000000..2045a5ab --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/padlock.h @@ -0,0 +1,107 @@ +/** + * \file padlock.h + * + * \brief VIA PadLock ACE for HW encryption/decryption supported by some + * processors + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PADLOCK_H +#define MBEDTLS_PADLOCK_H + +#include "aes.h" + +#define MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED -0x0030 /**< Input data should be aligned. */ + +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define MBEDTLS_HAVE_ASAN +#endif +#endif + +/* Some versions of ASan result in errors about not enough registers */ +#if defined(MBEDTLS_HAVE_ASM) && defined(__GNUC__) && defined(__i386__) && \ + !defined(MBEDTLS_HAVE_ASAN) + +#ifndef MBEDTLS_HAVE_X86 +#define MBEDTLS_HAVE_X86 +#endif + +#include + +#define MBEDTLS_PADLOCK_RNG 0x000C +#define MBEDTLS_PADLOCK_ACE 0x00C0 +#define MBEDTLS_PADLOCK_PHE 0x0C00 +#define MBEDTLS_PADLOCK_PMM 0x3000 + +#define MBEDTLS_PADLOCK_ALIGN16(x) (uint32_t *) (16 + ((int32_t) x & ~15)) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PadLock detection routine + * + * \param feature The feature to detect + * + * \return 1 if CPU has support for the feature, 0 otherwise + */ +int mbedtls_padlock_has_support( int feature ); + +/** + * \brief PadLock AES-ECB block en(de)cryption + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param input 16-byte input block + * \param output 16-byte output block + * + * \return 0 if success, 1 if operation failed + */ +int mbedtls_padlock_xcryptecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ); + +/** + * \brief PadLock AES-CBC buffer en(de)cryption + * + * \param ctx AES context + * \param mode MBEDTLS_AES_ENCRYPT or MBEDTLS_AES_DECRYPT + * \param length length of the input data + * \param iv initialization vector (updated after use) + * \param input buffer holding the input data + * \param output buffer holding the output data + * + * \return 0 if success, 1 if operation failed + */ +int mbedtls_padlock_xcryptcbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ); + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_X86 */ + +#endif /* padlock.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/pem.h b/c++/src/connect/mbedtls/mbedtls/pem.h new file mode 100644 index 00000000..54dc02d7 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/pem.h @@ -0,0 +1,129 @@ +/** + * \file pem.h + * + * \brief Privacy Enhanced Mail (PEM) decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PEM_H +#define MBEDTLS_PEM_H + +#include + +/** + * \name PEM Error codes + * These error codes are returned in case of errors reading the + * PEM data. + * \{ + */ +#define MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT -0x1080 /**< No PEM header or footer found. */ +#define MBEDTLS_ERR_PEM_INVALID_DATA -0x1100 /**< PEM string is not as expected. */ +#define MBEDTLS_ERR_PEM_ALLOC_FAILED -0x1180 /**< Failed to allocate memory. */ +#define MBEDTLS_ERR_PEM_INVALID_ENC_IV -0x1200 /**< RSA IV is not in hex-format. */ +#define MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG -0x1280 /**< Unsupported key encryption algorithm. */ +#define MBEDTLS_ERR_PEM_PASSWORD_REQUIRED -0x1300 /**< Private key password can't be empty. */ +#define MBEDTLS_ERR_PEM_PASSWORD_MISMATCH -0x1380 /**< Given private key password does not allow for correct decryption. */ +#define MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE -0x1400 /**< Unavailable feature, e.g. hashing/encryption combination. */ +#define MBEDTLS_ERR_PEM_BAD_INPUT_DATA -0x1480 /**< Bad input parameters to function. */ +/* \} name */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) +/** + * \brief PEM context structure + */ +typedef struct +{ + unsigned char *buf; /*!< buffer for decoded data */ + size_t buflen; /*!< length of the buffer */ + unsigned char *info; /*!< buffer for extra header information */ +} +mbedtls_pem_context; + +/** + * \brief PEM context setup + * + * \param ctx context to be initialized + */ +void mbedtls_pem_init( mbedtls_pem_context *ctx ); + +/** + * \brief Read a buffer for PEM information and store the resulting + * data into the specified context buffers. + * + * \param ctx context to use + * \param header header string to seek and expect + * \param footer footer string to seek and expect + * \param data source data to look in (must be nul-terminated) + * \param pwd password for decryption (can be NULL) + * \param pwdlen length of password + * \param use_len destination for total length used (set after header is + * correctly read, so unless you get + * MBEDTLS_ERR_PEM_BAD_INPUT_DATA or + * MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT, use_len is + * the length to skip) + * + * \note Attempts to check password correctness by verifying if + * the decrypted text starts with an ASN.1 sequence of + * appropriate length + * + * \return 0 on success, or a specific PEM error code + */ +int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer, + const unsigned char *data, + const unsigned char *pwd, + size_t pwdlen, size_t *use_len ); + +/** + * \brief PEM context memory freeing + * + * \param ctx context to be freed + */ +void mbedtls_pem_free( mbedtls_pem_context *ctx ); +#endif /* MBEDTLS_PEM_PARSE_C */ + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a buffer of PEM information from a DER encoded + * buffer. + * + * \param header header string to write + * \param footer footer string to write + * \param der_data DER data to write + * \param der_len length of the DER data + * \param buf buffer to write to + * \param buf_len length of output buffer + * \param olen total length written / required (if buf_len is not enough) + * + * \return 0 on success, or a specific PEM or BASE64 error code. On + * MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL olen is the required + * size. + */ +int mbedtls_pem_write_buffer( const char *header, const char *footer, + const unsigned char *der_data, size_t der_len, + unsigned char *buf, size_t buf_len, size_t *olen ); +#endif /* MBEDTLS_PEM_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* pem.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/pk.h b/c++/src/connect/mbedtls/mbedtls/pk.h new file mode 100644 index 00000000..f9f9b9bb --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/pk.h @@ -0,0 +1,616 @@ +/** + * \file pk.h + * + * \brief Public Key abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_PK_H +#define MBEDTLS_PK_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "md.h" + +#if defined(MBEDTLS_RSA_C) +#include "rsa.h" +#endif + +#if defined(MBEDTLS_ECP_C) +#include "ecp.h" +#endif + +#if defined(MBEDTLS_ECDSA_C) +#include "ecdsa.h" +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#define MBEDTLS_ERR_PK_ALLOC_FAILED -0x3F80 /**< Memory allocation failed. */ +#define MBEDTLS_ERR_PK_TYPE_MISMATCH -0x3F00 /**< Type mismatch, eg attempt to encrypt with an ECDSA key */ +#define MBEDTLS_ERR_PK_BAD_INPUT_DATA -0x3E80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PK_FILE_IO_ERROR -0x3E00 /**< Read/write of file failed. */ +#define MBEDTLS_ERR_PK_KEY_INVALID_VERSION -0x3D80 /**< Unsupported key version */ +#define MBEDTLS_ERR_PK_KEY_INVALID_FORMAT -0x3D00 /**< Invalid key tag or value. */ +#define MBEDTLS_ERR_PK_UNKNOWN_PK_ALG -0x3C80 /**< Key algorithm is unsupported (only RSA and EC are supported). */ +#define MBEDTLS_ERR_PK_PASSWORD_REQUIRED -0x3C00 /**< Private key password can't be empty. */ +#define MBEDTLS_ERR_PK_PASSWORD_MISMATCH -0x3B80 /**< Given private key password does not allow for correct decryption. */ +#define MBEDTLS_ERR_PK_INVALID_PUBKEY -0x3B00 /**< The pubkey tag or value is invalid (only RSA and EC are supported). */ +#define MBEDTLS_ERR_PK_INVALID_ALG -0x3A80 /**< The algorithm tag or value is invalid. */ +#define MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE -0x3A00 /**< Elliptic curve is unsupported (only NIST curves are supported). */ +#define MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE -0x3980 /**< Unavailable feature, e.g. RSA disabled for RSA key. */ +#define MBEDTLS_ERR_PK_SIG_LEN_MISMATCH -0x3900 /**< The signature is valid but its length is less than expected. */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Public key types + */ +typedef enum { + MBEDTLS_PK_NONE=0, + MBEDTLS_PK_RSA, + MBEDTLS_PK_ECKEY, + MBEDTLS_PK_ECKEY_DH, + MBEDTLS_PK_ECDSA, + MBEDTLS_PK_RSA_ALT, + MBEDTLS_PK_RSASSA_PSS, +} mbedtls_pk_type_t; + +/** + * \brief Options for RSASSA-PSS signature verification. + * See \c mbedtls_rsa_rsassa_pss_verify_ext() + */ +typedef struct +{ + mbedtls_md_type_t mgf1_hash_id; + int expected_salt_len; + +} mbedtls_pk_rsassa_pss_options; + +/** + * \brief Types for interfacing with the debug module + */ +typedef enum +{ + MBEDTLS_PK_DEBUG_NONE = 0, + MBEDTLS_PK_DEBUG_MPI, + MBEDTLS_PK_DEBUG_ECP, +} mbedtls_pk_debug_type; + +/** + * \brief Item to send to the debug module + */ +typedef struct +{ + mbedtls_pk_debug_type type; + const char *name; + void *value; +} mbedtls_pk_debug_item; + +/** Maximum number of item send for debugging, plus 1 */ +#define MBEDTLS_PK_DEBUG_MAX_ITEMS 3 + +/** + * \brief Public key information and operations + */ +typedef struct mbedtls_pk_info_t mbedtls_pk_info_t; + +/** + * \brief Public key container + */ +typedef struct +{ + const mbedtls_pk_info_t * pk_info; /**< Public key informations */ + void * pk_ctx; /**< Underlying public key context */ +} mbedtls_pk_context; + +#if defined(MBEDTLS_RSA_C) +/** + * Quick access to an RSA context inside a PK context. + * + * \warning You must make sure the PK context actually holds an RSA context + * before using this function! + */ +static inline mbedtls_rsa_context *mbedtls_pk_rsa( const mbedtls_pk_context pk ) +{ + return( (mbedtls_rsa_context *) (pk).pk_ctx ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/** + * Quick access to an EC context inside a PK context. + * + * \warning You must make sure the PK context actually holds an EC context + * before using this function! + */ +static inline mbedtls_ecp_keypair *mbedtls_pk_ec( const mbedtls_pk_context pk ) +{ + return( (mbedtls_ecp_keypair *) (pk).pk_ctx ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/** + * \brief Types for RSA-alt abstraction + */ +typedef int (*mbedtls_pk_rsa_alt_decrypt_func)( void *ctx, int mode, size_t *olen, + const unsigned char *input, unsigned char *output, + size_t output_max_len ); +typedef int (*mbedtls_pk_rsa_alt_sign_func)( void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, + const unsigned char *hash, unsigned char *sig ); +typedef size_t (*mbedtls_pk_rsa_alt_key_len_func)( void *ctx ); +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/** + * \brief Return information associated with the given PK type + * + * \param pk_type PK type to search for. + * + * \return The PK info associated with the type or NULL if not found. + */ +const mbedtls_pk_info_t *mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ); + +/** + * \brief Initialize a mbedtls_pk_context (as NONE) + */ +void mbedtls_pk_init( mbedtls_pk_context *ctx ); + +/** + * \brief Free a mbedtls_pk_context + */ +void mbedtls_pk_free( mbedtls_pk_context *ctx ); + +/** + * \brief Initialize a PK context with the information given + * and allocates the type-specific PK subcontext. + * + * \param ctx Context to initialize. Must be empty (type NONE). + * \param info Information to use + * + * \return 0 on success, + * MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input, + * MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure. + * + * \note For contexts holding an RSA-alt key, use + * \c mbedtls_pk_setup_rsa_alt() instead. + */ +int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ); + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/** + * \brief Initialize an RSA-alt context + * + * \param ctx Context to initialize. Must be empty (type NONE). + * \param key RSA key pointer + * \param decrypt_func Decryption function + * \param sign_func Signing function + * \param key_len_func Function returning key length in bytes + * + * \return 0 on success, or MBEDTLS_ERR_PK_BAD_INPUT_DATA if the + * context wasn't already initialized as RSA_ALT. + * + * \note This function replaces \c mbedtls_pk_setup() for RSA-alt. + */ +int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key, + mbedtls_pk_rsa_alt_decrypt_func decrypt_func, + mbedtls_pk_rsa_alt_sign_func sign_func, + mbedtls_pk_rsa_alt_key_len_func key_len_func ); +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/** + * \brief Get the size in bits of the underlying key + * + * \param ctx Context to use + * + * \return Key size in bits, or 0 on error + */ +size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ); + +/** + * \brief Get the length in bytes of the underlying key + * \param ctx Context to use + * + * \return Key length in bytes, or 0 on error + */ +static inline size_t mbedtls_pk_get_len( const mbedtls_pk_context *ctx ) +{ + return( ( mbedtls_pk_get_bitlen( ctx ) + 7 ) / 8 ); +} + +/** + * \brief Tell if a context can do the operation given by type + * + * \param ctx Context to test + * \param type Target type + * + * \return 0 if context can't do the operations, + * 1 otherwise. + */ +int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ); + +/** + * \brief Verify signature (including padding if relevant). + * + * \param ctx PK context to use + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Signature to verify + * \param sig_len Signature length + * + * \return 0 on success (signature is valid), + * MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if the signature is + * valid but its actual length is less than sig_len, + * or a specific error code. + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * Use \c mbedtls_pk_verify_ext( MBEDTLS_PK_RSASSA_PSS, ... ) + * to verify RSASSA_PSS signatures. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0 + */ +int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +/** + * \brief Verify signature, with options. + * (Includes verification of the padding depending on type.) + * + * \param type Signature type (inc. possible padding type) to verify + * \param options Pointer to type-specific options, or NULL + * \param ctx PK context to use + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Signature to verify + * \param sig_len Signature length + * + * \return 0 on success (signature is valid), + * MBEDTLS_ERR_PK_TYPE_MISMATCH if the PK context can't be + * used for this type of signatures, + * MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if the signature is + * valid but its actual length is less than sig_len, + * or a specific error code. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note md_alg may be MBEDTLS_MD_NONE, only if hash_len != 0 + * + * \note If type is MBEDTLS_PK_RSASSA_PSS, then options must point + * to a mbedtls_pk_rsassa_pss_options structure, + * otherwise it must be NULL. + */ +int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, + mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +/** + * \brief Make signature, including padding if relevant. + * + * \param ctx PK context to use - must hold a private key + * \param md_alg Hash algorithm used (see notes) + * \param hash Hash of the message to sign + * \param hash_len Hash length or 0 (see notes) + * \param sig Place to write the signature + * \param sig_len Number of bytes written + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \return 0 on success, or a specific error code. + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * There is no interface in the PK module to make RSASSA-PSS + * signatures yet. + * + * \note If hash_len is 0, then the length associated with md_alg + * is used instead, or an error returned if it is invalid. + * + * \note For RSA, md_alg may be MBEDTLS_MD_NONE if hash_len != 0. + * For ECDSA, md_alg may never be MBEDTLS_MD_NONE. + */ +int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Decrypt message (including padding if relevant). + * + * \param ctx PK context to use - must hold a private key + * \param input Input to decrypt + * \param ilen Input size + * \param output Decrypted output + * \param olen Decrypted message length + * \param osize Size of the output buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Encrypt message (including padding if relevant). + * + * \param ctx PK context to use + * \param input Message to encrypt + * \param ilen Message size + * \param output Encrypted output + * \param olen Encrypted output length + * \param osize Size of the output buffer + * \param f_rng RNG function + * \param p_rng RNG parameter + * + * \note For RSA keys, the default padding type is PKCS#1 v1.5. + * + * \return 0 on success, or a specific error code. + */ +int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +/** + * \brief Check if a public-private pair of keys matches. + * + * \param pub Context holding a public key. + * \param prv Context holding a private (and public) key. + * + * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + */ +int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ); + +/** + * \brief Export debug information + * + * \param ctx Context to use + * \param items Place to write debug items + * + * \return 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA + */ +int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ); + +/** + * \brief Access the type name + * + * \param ctx Context to use + * + * \return Type name on success, or "invalid PK" + */ +const char * mbedtls_pk_get_name( const mbedtls_pk_context *ctx ); + +/** + * \brief Get the key type + * + * \param ctx Context to use + * + * \return Type on success, or MBEDTLS_PK_NONE + */ +mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ); + +#if defined(MBEDTLS_PK_PARSE_C) +/** \ingroup pk_module */ +/** + * \brief Parse a private key in PEM or DER format + * + * \param ctx key to be initialized + * \param key input buffer + * \param keylen size of the buffer + * (including the terminating null byte for PEM data) + * \param pwd password for decryption (optional) + * \param pwdlen size of the password + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ); + +/** \ingroup pk_module */ +/** + * \brief Parse a public key in PEM or DER format + * + * \param ctx key to be initialized + * \param key input buffer + * \param keylen size of the buffer + * (including the terminating null byte for PEM data) + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen ); + +#if defined(MBEDTLS_FS_IO) +/** \ingroup pk_module */ +/** + * \brief Load and parse a private key + * + * \param ctx key to be initialized + * \param path filename to read the private key from + * \param password password to decrypt the file (can be NULL) + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If you need a + * specific key type, check the result with mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, + const char *path, const char *password ); + +/** \ingroup pk_module */ +/** + * \brief Load and parse a public key + * + * \param ctx key to be initialized + * \param path filename to read the public key from + * + * \note On entry, ctx must be empty, either freshly initialised + * with mbedtls_pk_init() or reset with mbedtls_pk_free(). If + * you need a specific key type, check the result with + * mbedtls_pk_can_do(). + * + * \note The key is also checked for correctness. + * + * \return 0 if successful, or a specific PK or PEM error code + */ +int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ); +#endif /* MBEDTLS_FS_IO */ +#endif /* MBEDTLS_PK_PARSE_C */ + +#if defined(MBEDTLS_PK_WRITE_C) +/** + * \brief Write a private key to a PKCS#1 or SEC1 DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx private to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return length of data written if successful, or a specific + * error code + */ +int mbedtls_pk_write_key_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +/** + * \brief Write a public key to a SubjectPublicKeyInfo DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx public key to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return length of data written if successful, or a specific + * error code + */ +int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a public key to a PEM string + * + * \param ctx public key to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return 0 if successful, or a specific error code + */ +int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); + +/** + * \brief Write a private key to a PKCS#1 or SEC1 PEM string + * + * \param ctx private to write away + * \param buf buffer to write to + * \param size size of the buffer + * + * \return 0 if successful, or a specific error code + */ +int mbedtls_pk_write_key_pem( mbedtls_pk_context *ctx, unsigned char *buf, size_t size ); +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_PK_WRITE_C */ + +/* + * WARNING: Low-level functions. You probably do not want to use these unless + * you are certain you do ;) + */ + +#if defined(MBEDTLS_PK_PARSE_C) +/** + * \brief Parse a SubjectPublicKeyInfo DER structure + * + * \param p the position in the ASN.1 data + * \param end end of the buffer + * \param pk the key to fill + * + * \return 0 if successful, or a specific PK error code + */ +int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, + mbedtls_pk_context *pk ); +#endif /* MBEDTLS_PK_PARSE_C */ + +#if defined(MBEDTLS_PK_WRITE_C) +/** + * \brief Write a subjectPublicKey to ASN.1 data + * Note: function works backwards in data buffer + * + * \param p reference to current position pointer + * \param start start of the buffer (for bounds-checking) + * \param key public key to write away + * + * \return the length written or a negative error code + */ +int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, + const mbedtls_pk_context *key ); +#endif /* MBEDTLS_PK_WRITE_C */ + +/* + * Internal module functions. You probably do not want to use these unless you + * know you do. + */ +#if defined(MBEDTLS_FS_IO) +int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PK_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/pk_internal.h b/c++/src/connect/mbedtls/mbedtls/pk_internal.h new file mode 100644 index 00000000..01d0f214 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/pk_internal.h @@ -0,0 +1,114 @@ +/** + * \file pk.h + * + * \brief Public Key abstraction layer: wrapper functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#ifndef MBEDTLS_PK_WRAP_H +#define MBEDTLS_PK_WRAP_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "pk.h" + +struct mbedtls_pk_info_t +{ + /** Public key type */ + mbedtls_pk_type_t type; + + /** Type name */ + const char *name; + + /** Get key size in bits */ + size_t (*get_bitlen)( const void * ); + + /** Tell if the context implements this type (e.g. ECKEY can do ECDSA) */ + int (*can_do)( mbedtls_pk_type_t type ); + + /** Verify signature */ + int (*verify_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + + /** Make signature */ + int (*sign_func)( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Decrypt message */ + int (*decrypt_func)( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Encrypt message */ + int (*encrypt_func)( void *ctx, const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + + /** Check public-private key pair */ + int (*check_pair_func)( const void *pub, const void *prv ); + + /** Allocate a new context */ + void * (*ctx_alloc_func)( void ); + + /** Free the given context */ + void (*ctx_free_func)( void *ctx ); + + /** Interface with the debug module */ + void (*debug_func)( const void *ctx, mbedtls_pk_debug_item *items ); + +}; +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* Container for RSA-alt */ +typedef struct +{ + void *key; + mbedtls_pk_rsa_alt_decrypt_func decrypt_func; + mbedtls_pk_rsa_alt_sign_func sign_func; + mbedtls_pk_rsa_alt_key_len_func key_len_func; +} mbedtls_rsa_alt_context; +#endif + +#if defined(MBEDTLS_RSA_C) +extern const mbedtls_pk_info_t mbedtls_rsa_info; +#endif + +#if defined(MBEDTLS_ECP_C) +extern const mbedtls_pk_info_t mbedtls_eckey_info; +extern const mbedtls_pk_info_t mbedtls_eckeydh_info; +#endif + +#if defined(MBEDTLS_ECDSA_C) +extern const mbedtls_pk_info_t mbedtls_ecdsa_info; +#endif + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +extern const mbedtls_pk_info_t mbedtls_rsa_alt_info; +#endif + +#endif /* MBEDTLS_PK_WRAP_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/pkcs11.h b/c++/src/connect/mbedtls/mbedtls/pkcs11.h new file mode 100644 index 00000000..2e889281 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/pkcs11.h @@ -0,0 +1,173 @@ +/** + * \file pkcs11.h + * + * \brief Wrapper for PKCS#11 library libpkcs11-helper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS11_H +#define MBEDTLS_PKCS11_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PKCS11_C) + +#include "x509_crt.h" + +#include + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Context for PKCS #11 private keys. + */ +typedef struct { + pkcs11h_certificate_t pkcs11h_cert; + int len; +} mbedtls_pkcs11_context; + +/** + * Initialize a mbedtls_pkcs11_context. + * (Just making memory references valid.) + */ +void mbedtls_pkcs11_init( mbedtls_pkcs11_context *ctx ); + +/** + * Fill in a mbed TLS certificate, based on the given PKCS11 helper certificate. + * + * \param cert X.509 certificate to fill + * \param pkcs11h_cert PKCS #11 helper certificate + * + * \return 0 on success. + */ +int mbedtls_pkcs11_x509_cert_bind( mbedtls_x509_crt *cert, pkcs11h_certificate_t pkcs11h_cert ); + +/** + * Set up a mbedtls_pkcs11_context storing the given certificate. Note that the + * mbedtls_pkcs11_context will take over control of the certificate, freeing it when + * done. + * + * \param priv_key Private key structure to fill. + * \param pkcs11_cert PKCS #11 helper certificate + * + * \return 0 on success + */ +int mbedtls_pkcs11_priv_key_bind( mbedtls_pkcs11_context *priv_key, + pkcs11h_certificate_t pkcs11_cert ); + +/** + * Free the contents of the given private key context. Note that the structure + * itself is not freed. + * + * \param priv_key Private key structure to cleanup + */ +void mbedtls_pkcs11_priv_key_free( mbedtls_pkcs11_context *priv_key ); + +/** + * \brief Do an RSA private key decrypt, then remove the message + * padding + * + * \param ctx PKCS #11 context + * \param mode must be MBEDTLS_RSA_PRIVATE, for compatibility with rsa.c's signature + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param olen will contain the plaintext length + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int mbedtls_pkcs11_decrypt( mbedtls_pkcs11_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Do a private RSA to sign a message digest + * + * \param ctx PKCS #11 context + * \param mode must be MBEDTLS_RSA_PRIVATE, for compatibility with rsa.c's signature + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_pkcs11_sign( mbedtls_pkcs11_context *ctx, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * SSL/TLS wrappers for PKCS#11 functions + */ +static inline int mbedtls_ssl_pkcs11_decrypt( void *ctx, int mode, size_t *olen, + const unsigned char *input, unsigned char *output, + size_t output_max_len ) +{ + return mbedtls_pkcs11_decrypt( (mbedtls_pkcs11_context *) ctx, mode, olen, input, output, + output_max_len ); +} + +static inline int mbedtls_ssl_pkcs11_sign( void *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, + const unsigned char *hash, unsigned char *sig ) +{ + ((void) f_rng); + ((void) p_rng); + return mbedtls_pkcs11_sign( (mbedtls_pkcs11_context *) ctx, mode, md_alg, + hashlen, hash, sig ); +} + +static inline size_t mbedtls_ssl_pkcs11_key_len( void *ctx ) +{ + return ( (mbedtls_pkcs11_context *) ctx )->len; +} + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_PKCS11_C */ + +#endif /* MBEDTLS_PKCS11_H */ diff --git a/c++/src/connect/mbedtls/mbedtls/pkcs12.h b/c++/src/connect/mbedtls/mbedtls/pkcs12.h new file mode 100644 index 00000000..9b2d9045 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/pkcs12.h @@ -0,0 +1,119 @@ +/** + * \file pkcs12.h + * + * \brief PKCS#12 Personal Information Exchange Syntax + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS12_H +#define MBEDTLS_PKCS12_H + +#include "md.h" +#include "cipher.h" +#include "asn1.h" + +#include + +#define MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA -0x1F80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE -0x1F00 /**< Feature not available, e.g. unsupported encryption scheme. */ +#define MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT -0x1E80 /**< PBE ASN.1 data not as expected. */ +#define MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH -0x1E00 /**< Given private key password does not allow for correct decryption. */ + +#define MBEDTLS_PKCS12_DERIVE_KEY 1 /**< encryption/decryption key */ +#define MBEDTLS_PKCS12_DERIVE_IV 2 /**< initialization vector */ +#define MBEDTLS_PKCS12_DERIVE_MAC_KEY 3 /**< integrity / MAC key */ + +#define MBEDTLS_PKCS12_PBE_DECRYPT 0 +#define MBEDTLS_PKCS12_PBE_ENCRYPT 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PKCS12 Password Based function (encryption / decryption) + * for pbeWithSHAAnd128BitRC4 + * + * \param pbe_params an ASN1 buffer containing the pkcs-12PbeParams structure + * \param mode either MBEDTLS_PKCS12_PBE_ENCRYPT or MBEDTLS_PKCS12_PBE_DECRYPT + * \param pwd the password used (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param input the input data + * \param len data length + * \param output the output buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_XXX code + */ +int mbedtls_pkcs12_pbe_sha1_rc4_128( mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *input, size_t len, + unsigned char *output ); + +/** + * \brief PKCS12 Password Based function (encryption / decryption) + * for cipher-based and mbedtls_md-based PBE's + * + * \param pbe_params an ASN1 buffer containing the pkcs-12PbeParams structure + * \param mode either MBEDTLS_PKCS12_PBE_ENCRYPT or MBEDTLS_PKCS12_PBE_DECRYPT + * \param cipher_type the cipher used + * \param md_type the mbedtls_md used + * \param pwd the password used (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param input the input data + * \param len data length + * \param output the output buffer + * + * \return 0 if successful, or a MBEDTLS_ERR_XXX code + */ +int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode, + mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *input, size_t len, + unsigned char *output ); + +/** + * \brief The PKCS#12 derivation function uses a password and a salt + * to produce pseudo-random bits for a particular "purpose". + * + * Depending on the given id, this function can produce an + * encryption/decryption key, an nitialization vector or an + * integrity key. + * + * \param data buffer to store the derived data in + * \param datalen length to fill + * \param pwd password to use (may be NULL if no password is used) + * \param pwdlen length of the password (may be 0) + * \param salt salt buffer to use + * \param saltlen length of the salt + * \param mbedtls_md mbedtls_md type to use during the derivation + * \param id id that describes the purpose (can be MBEDTLS_PKCS12_DERIVE_KEY, + * MBEDTLS_PKCS12_DERIVE_IV or MBEDTLS_PKCS12_DERIVE_MAC_KEY) + * \param iterations number of iterations + * + * \return 0 if successful, or a MD, BIGNUM type error. + */ +int mbedtls_pkcs12_derivation( unsigned char *data, size_t datalen, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *salt, size_t saltlen, + mbedtls_md_type_t mbedtls_md, int id, int iterations ); + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs12.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/pkcs5.h b/c++/src/connect/mbedtls/mbedtls/pkcs5.h new file mode 100644 index 00000000..ec5cb9e7 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/pkcs5.h @@ -0,0 +1,94 @@ +/** + * \file pkcs5.h + * + * \brief PKCS#5 functions + * + * \author Mathias Olsson + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PKCS5_H +#define MBEDTLS_PKCS5_H + +#include "asn1.h" +#include "md.h" + +#include +#include + +#define MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA -0x2f80 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_PKCS5_INVALID_FORMAT -0x2f00 /**< Unexpected ASN.1 data. */ +#define MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE -0x2e80 /**< Requested encryption or digest alg not available. */ +#define MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH -0x2e00 /**< Given private key password does not allow for correct decryption. */ + +#define MBEDTLS_PKCS5_DECRYPT 0 +#define MBEDTLS_PKCS5_ENCRYPT 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief PKCS#5 PBES2 function + * + * \param pbe_params the ASN.1 algorithm parameters + * \param mode either MBEDTLS_PKCS5_DECRYPT or MBEDTLS_PKCS5_ENCRYPT + * \param pwd password to use when generating key + * \param pwdlen length of password + * \param data data to process + * \param datalen length of data + * \param output output buffer + * + * \returns 0 on success, or a MBEDTLS_ERR_XXX code if verification fails. + */ +int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output ); + +/** + * \brief PKCS#5 PBKDF2 using HMAC + * + * \param ctx Generic HMAC context + * \param password Password to use when generating key + * \param plen Length of password + * \param salt Salt to use when generating key + * \param slen Length of salt + * \param iteration_count Iteration count + * \param key_length Length of generated key in bytes + * \param output Generated key. Must be at least as big as key_length + * + * \returns 0 on success, or a MBEDTLS_ERR_XXX code if verification fails. + */ +int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_pkcs5_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* pkcs5.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/platform.h b/c++/src/connect/mbedtls/mbedtls/platform.h new file mode 100644 index 00000000..5c159cd0 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/platform.h @@ -0,0 +1,295 @@ +/** + * \file platform.h + * + * \brief mbed TLS Platform abstraction layer + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PLATFORM_H +#define MBEDTLS_PLATFORM_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include "platform_time.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) +#include +#include +#include +#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF) +#if defined(_WIN32) +#define MBEDTLS_PLATFORM_STD_SNPRINTF mbedtls_platform_win32_snprintf /**< Default snprintf to use */ +#else +#define MBEDTLS_PLATFORM_STD_SNPRINTF snprintf /**< Default snprintf to use */ +#endif +#endif +#if !defined(MBEDTLS_PLATFORM_STD_PRINTF) +#define MBEDTLS_PLATFORM_STD_PRINTF printf /**< Default printf to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF) +#define MBEDTLS_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_CALLOC) +#define MBEDTLS_PLATFORM_STD_CALLOC calloc /**< Default allocator to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_FREE) +#define MBEDTLS_PLATFORM_STD_FREE free /**< Default free to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT) +#define MBEDTLS_PLATFORM_STD_EXIT exit /**< Default exit to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_TIME) +#define MBEDTLS_PLATFORM_STD_TIME time /**< Default time to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS) +#define MBEDTLS_PLATFORM_STD_EXIT_SUCCESS EXIT_SUCCESS /**< Default exit value to use */ +#endif +#if !defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE) +#define MBEDTLS_PLATFORM_STD_EXIT_FAILURE EXIT_FAILURE /**< Default exit value to use */ +#endif +#if defined(MBEDTLS_FS_IO) +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) +#define MBEDTLS_PLATFORM_STD_NV_SEED_READ mbedtls_platform_std_nv_seed_read +#endif +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) +#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE mbedtls_platform_std_nv_seed_write +#endif +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_FILE) +#define MBEDTLS_PLATFORM_STD_NV_SEED_FILE "seedfile" +#endif +#endif /* MBEDTLS_FS_IO */ +#else /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ +#if defined(MBEDTLS_PLATFORM_STD_MEM_HDR) +#include MBEDTLS_PLATFORM_STD_MEM_HDR +#endif +#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ + + +/* \} name SECTION: Module settings */ + +/* + * The function pointers for calloc and free + */ +#if defined(MBEDTLS_PLATFORM_MEMORY) +#if defined(MBEDTLS_PLATFORM_FREE_MACRO) && \ + defined(MBEDTLS_PLATFORM_CALLOC_MACRO) +#define mbedtls_free MBEDTLS_PLATFORM_FREE_MACRO +#define mbedtls_calloc MBEDTLS_PLATFORM_CALLOC_MACRO +#else +/* For size_t */ +#include +extern void * (*mbedtls_calloc)( size_t n, size_t size ); +extern void (*mbedtls_free)( void *ptr ); + +/** + * \brief Set your own memory implementation function pointers + * + * \param calloc_func the calloc function implementation + * \param free_func the free function implementation + * + * \return 0 if successful + */ +int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ), + void (*free_func)( void * ) ); +#endif /* MBEDTLS_PLATFORM_FREE_MACRO && MBEDTLS_PLATFORM_CALLOC_MACRO */ +#else /* !MBEDTLS_PLATFORM_MEMORY */ +#define mbedtls_free free +#define mbedtls_calloc calloc +#endif /* MBEDTLS_PLATFORM_MEMORY && !MBEDTLS_PLATFORM_{FREE,CALLOC}_MACRO */ + +/* + * The function pointers for fprintf + */ +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +/* We need FILE * */ +#include +extern int (*mbedtls_fprintf)( FILE *stream, const char *format, ... ); + +/** + * \brief Set your own fprintf function pointer + * + * \param fprintf_func the fprintf function implementation + * + * \return 0 + */ +int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *stream, const char *, + ... ) ); +#else +#if defined(MBEDTLS_PLATFORM_FPRINTF_MACRO) +#define mbedtls_fprintf MBEDTLS_PLATFORM_FPRINTF_MACRO +#else +#define mbedtls_fprintf fprintf +#endif /* MBEDTLS_PLATFORM_FPRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ + +/* + * The function pointers for printf + */ +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) +extern int (*mbedtls_printf)( const char *format, ... ); + +/** + * \brief Set your own printf function pointer + * + * \param printf_func the printf function implementation + * + * \return 0 + */ +int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) ); +#else /* !MBEDTLS_PLATFORM_PRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_PRINTF_MACRO) +#define mbedtls_printf MBEDTLS_PLATFORM_PRINTF_MACRO +#else +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_PRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */ + +/* + * The function pointers for snprintf + * + * The snprintf implementation should conform to C99: + * - it *must* always correctly zero-terminate the buffer + * (except when n == 0, then it must leave the buffer untouched) + * - however it is acceptable to return -1 instead of the required length when + * the destination buffer is too short. + */ +#if defined(_WIN32) +/* For Windows (inc. MSYS2), we provide our own fixed implementation */ +int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... ); +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +extern int (*mbedtls_snprintf)( char * s, size_t n, const char * format, ... ); + +/** + * \brief Set your own snprintf function pointer + * + * \param snprintf_func the snprintf function implementation + * + * \return 0 + */ +int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n, + const char * format, ... ) ); +#else /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_SNPRINTF_MACRO) +#define mbedtls_snprintf MBEDTLS_PLATFORM_SNPRINTF_MACRO +#else +#define mbedtls_snprintf snprintf +#endif /* MBEDTLS_PLATFORM_SNPRINTF_MACRO */ +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ + +/* + * The function pointers for exit + */ +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) +extern void (*mbedtls_exit)( int status ); + +/** + * \brief Set your own exit function pointer + * + * \param exit_func the exit function implementation + * + * \return 0 + */ +int mbedtls_platform_set_exit( void (*exit_func)( int status ) ); +#else +#if defined(MBEDTLS_PLATFORM_EXIT_MACRO) +#define mbedtls_exit MBEDTLS_PLATFORM_EXIT_MACRO +#else +#define mbedtls_exit exit +#endif /* MBEDTLS_PLATFORM_EXIT_MACRO */ +#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ + +/* + * The default exit values + */ +#if defined(MBEDTLS_PLATFORM_STD_EXIT_SUCCESS) +#define MBEDTLS_EXIT_SUCCESS MBEDTLS_PLATFORM_STD_EXIT_SUCCESS +#else +#define MBEDTLS_EXIT_SUCCESS 0 +#endif +#if defined(MBEDTLS_PLATFORM_STD_EXIT_FAILURE) +#define MBEDTLS_EXIT_FAILURE MBEDTLS_PLATFORM_STD_EXIT_FAILURE +#else +#define MBEDTLS_EXIT_FAILURE 1 +#endif + +/* + * The function pointers for reading from and writing a seed file to + * Non-Volatile storage (NV) in a platform-independent way + * + * Only enabled when the NV seed entropy source is enabled + */ +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO) +/* Internal standard platform definitions */ +int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len ); +int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len ); +#endif + +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +extern int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ); +extern int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ); + +/** + * \brief Set your own seed file writing/reading functions + * + * \param nv_seed_read_func the seed reading function implementation + * \param nv_seed_write_func the seed writing function implementation + * + * \return 0 + */ +int mbedtls_platform_set_nv_seed( + int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ), + int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len ) + ); +#else +#if defined(MBEDTLS_PLATFORM_NV_SEED_READ_MACRO) && \ + defined(MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO) +#define mbedtls_nv_seed_read MBEDTLS_PLATFORM_NV_SEED_READ_MACRO +#define mbedtls_nv_seed_write MBEDTLS_PLATFORM_NV_SEED_WRITE_MACRO +#else +#define mbedtls_nv_seed_read mbedtls_platform_std_nv_seed_read +#define mbedtls_nv_seed_write mbedtls_platform_std_nv_seed_write +#endif +#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */ +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#ifdef __cplusplus +} +#endif + +#endif /* platform.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/platform_time.h b/c++/src/connect/mbedtls/mbedtls/platform_time.h new file mode 100644 index 00000000..abb34314 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/platform_time.h @@ -0,0 +1,81 @@ +/** + * \file platform_time.h + * + * \brief mbed TLS Platform time abstraction + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_PLATFORM_TIME_H +#define MBEDTLS_PLATFORM_TIME_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +/* + * The time_t datatype + */ +#if defined(MBEDTLS_PLATFORM_TIME_TYPE_MACRO) +typedef MBEDTLS_PLATFORM_TIME_TYPE_MACRO mbedtls_time_t; +#else +/* For time_t */ +#include +typedef time_t mbedtls_time_t; +#endif /* MBEDTLS_PLATFORM_TIME_TYPE_MACRO */ + +/* + * The function pointers for time + */ +#if defined(MBEDTLS_PLATFORM_TIME_ALT) +extern mbedtls_time_t (*mbedtls_time)( mbedtls_time_t* time ); + +/** + * \brief Set your own time function pointer + * + * \param time_func the time function implementation + * + * \return 0 + */ +int mbedtls_platform_set_time( mbedtls_time_t (*time_func)( mbedtls_time_t* time ) ); +#else +#if defined(MBEDTLS_PLATFORM_TIME_MACRO) +#define mbedtls_time MBEDTLS_PLATFORM_TIME_MACRO +#else +#define mbedtls_time time +#endif /* MBEDTLS_PLATFORM_TIME_MACRO */ +#endif /* MBEDTLS_PLATFORM_TIME_ALT */ + +#ifdef __cplusplus +} +#endif + +#endif /* platform_time.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ripemd160.h b/c++/src/connect/mbedtls/mbedtls/ripemd160.h new file mode 100644 index 00000000..7083fc85 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ripemd160.h @@ -0,0 +1,138 @@ +/** + * \file ripemd160.h + * + * \brief RIPE MD-160 message digest + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_RIPEMD160_H +#define MBEDTLS_RIPEMD160_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_RIPEMD160_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief RIPEMD-160 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_ripemd160_context; + +/** + * \brief Initialize RIPEMD-160 context + * + * \param ctx RIPEMD-160 context to be initialized + */ +void mbedtls_ripemd160_init( mbedtls_ripemd160_context *ctx ); + +/** + * \brief Clear RIPEMD-160 context + * + * \param ctx RIPEMD-160 context to be cleared + */ +void mbedtls_ripemd160_free( mbedtls_ripemd160_context *ctx ); + +/** + * \brief Clone (the state of) an RIPEMD-160 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_ripemd160_clone( mbedtls_ripemd160_context *dst, + const mbedtls_ripemd160_context *src ); + +/** + * \brief RIPEMD-160 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_ripemd160_starts( mbedtls_ripemd160_context *ctx ); + +/** + * \brief RIPEMD-160 process buffer + * + * \param ctx RIPEMD-160 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_ripemd160_update( mbedtls_ripemd160_context *ctx, + const unsigned char *input, size_t ilen ); + +/** + * \brief RIPEMD-160 final digest + * + * \param ctx RIPEMD-160 context + * \param output RIPEMD-160 checksum result + */ +void mbedtls_ripemd160_finish( mbedtls_ripemd160_context *ctx, unsigned char output[20] ); + +/* Internal use */ +void mbedtls_ripemd160_process( mbedtls_ripemd160_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_RIPEMD160_ALT */ +#include "ripemd160.h" +#endif /* MBEDTLS_RIPEMD160_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = RIPEMD-160( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output RIPEMD-160 checksum result + */ +void mbedtls_ripemd160( const unsigned char *input, size_t ilen, + unsigned char output[20] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_ripemd160_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_ripemd160.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/rsa.h b/c++/src/connect/mbedtls/mbedtls/rsa.h new file mode 100644 index 00000000..54653dfd --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/rsa.h @@ -0,0 +1,652 @@ +/** + * \file rsa.h + * + * \brief The RSA public-key cryptosystem + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_RSA_H +#define MBEDTLS_RSA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "bignum.h" +#include "md.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/* + * RSA Error codes + */ +#define MBEDTLS_ERR_RSA_BAD_INPUT_DATA -0x4080 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_RSA_INVALID_PADDING -0x4100 /**< Input data contains invalid padding and is rejected. */ +#define MBEDTLS_ERR_RSA_KEY_GEN_FAILED -0x4180 /**< Something failed during generation of a key. */ +#define MBEDTLS_ERR_RSA_KEY_CHECK_FAILED -0x4200 /**< Key failed to pass the library's validity check. */ +#define MBEDTLS_ERR_RSA_PUBLIC_FAILED -0x4280 /**< The public key operation failed. */ +#define MBEDTLS_ERR_RSA_PRIVATE_FAILED -0x4300 /**< The private key operation failed. */ +#define MBEDTLS_ERR_RSA_VERIFY_FAILED -0x4380 /**< The PKCS#1 verification failed. */ +#define MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE -0x4400 /**< The output buffer for decryption is not large enough. */ +#define MBEDTLS_ERR_RSA_RNG_FAILED -0x4480 /**< The random generator failed to generate non-zeros. */ + +/* + * RSA constants + */ +#define MBEDTLS_RSA_PUBLIC 0 +#define MBEDTLS_RSA_PRIVATE 1 + +#define MBEDTLS_RSA_PKCS_V15 0 +#define MBEDTLS_RSA_PKCS_V21 1 + +#define MBEDTLS_RSA_SIGN 1 +#define MBEDTLS_RSA_CRYPT 2 + +#define MBEDTLS_RSA_SALT_LEN_ANY -1 + +/* + * The above constants may be used even if the RSA module is compile out, + * eg for alternative (PKCS#11) RSA implemenations in the PK layers. + */ +#if defined(MBEDTLS_RSA_C) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief RSA context structure + */ +typedef struct +{ + int ver; /*!< always 0 */ + size_t len; /*!< size(N) in chars */ + + mbedtls_mpi N; /*!< public modulus */ + mbedtls_mpi E; /*!< public exponent */ + + mbedtls_mpi D; /*!< private exponent */ + mbedtls_mpi P; /*!< 1st prime factor */ + mbedtls_mpi Q; /*!< 2nd prime factor */ + mbedtls_mpi DP; /*!< D % (P - 1) */ + mbedtls_mpi DQ; /*!< D % (Q - 1) */ + mbedtls_mpi QP; /*!< 1 / (Q % P) */ + + mbedtls_mpi RN; /*!< cached R^2 mod N */ + mbedtls_mpi RP; /*!< cached R^2 mod P */ + mbedtls_mpi RQ; /*!< cached R^2 mod Q */ + + mbedtls_mpi Vi; /*!< cached blinding value */ + mbedtls_mpi Vf; /*!< cached un-blinding value */ + + int padding; /*!< MBEDTLS_RSA_PKCS_V15 for 1.5 padding and + MBEDTLS_RSA_PKCS_v21 for OAEP/PSS */ + int hash_id; /*!< Hash identifier of mbedtls_md_type_t as + specified in the mbedtls_md.h header file + for the EME-OAEP and EMSA-PSS + encoding */ +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< Thread-safety mutex */ +#endif +} +mbedtls_rsa_context; + +/** + * \brief Initialize an RSA context + * + * Note: Set padding to MBEDTLS_RSA_PKCS_V21 for the RSAES-OAEP + * encryption scheme and the RSASSA-PSS signature scheme. + * + * \param ctx RSA context to be initialized + * \param padding MBEDTLS_RSA_PKCS_V15 or MBEDTLS_RSA_PKCS_V21 + * \param hash_id MBEDTLS_RSA_PKCS_V21 hash identifier + * + * \note The hash_id parameter is actually ignored + * when using MBEDTLS_RSA_PKCS_V15 padding. + * + * \note Choice of padding mode is strictly enforced for private key + * operations, since there might be security concerns in + * mixing padding modes. For public key operations it's merely + * a default value, which can be overriden by calling specific + * rsa_rsaes_xxx or rsa_rsassa_xxx functions. + * + * \note The chosen hash is always used for OEAP encryption. + * For PSS signatures, it's always used for making signatures, + * but can be overriden (and always is, if set to + * MBEDTLS_MD_NONE) for verifying them. + */ +void mbedtls_rsa_init( mbedtls_rsa_context *ctx, + int padding, + int hash_id); + +/** + * \brief Set padding for an already initialized RSA context + * See \c mbedtls_rsa_init() for details. + * + * \param ctx RSA context to be set + * \param padding MBEDTLS_RSA_PKCS_V15 or MBEDTLS_RSA_PKCS_V21 + * \param hash_id MBEDTLS_RSA_PKCS_V21 hash identifier + */ +void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, int hash_id); + +/** + * \brief Generate an RSA keypair + * + * \param ctx RSA context that will hold the key + * \param f_rng RNG function + * \param p_rng RNG parameter + * \param nbits size of the public key in bits + * \param exponent public exponent (e.g., 65537) + * + * \note mbedtls_rsa_init() must be called beforehand to setup + * the RSA context. + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ); + +/** + * \brief Check a public RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ); + +/** + * \brief Check a private RSA key + * + * \param ctx RSA context to be checked + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ); + +/** + * \brief Check a public-private RSA key pair. + * Check each of the contexts, and make sure they match. + * + * \param pub RSA context holding the public key + * \param prv RSA context holding the private key + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + */ +int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, const mbedtls_rsa_context *prv ); + +/** + * \brief Do an RSA public key operation + * + * \param ctx RSA context + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note This function does NOT take care of message + * padding. Also, be sure to set input[0] = 0 or ensure that + * input is smaller than N. + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_public( mbedtls_rsa_context *ctx, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Do an RSA private key operation + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for blinding) + * \param p_rng RNG parameter + * \param input input buffer + * \param output output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The input and output buffers must be large + * enough (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_private( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic wrapper to perform a PKCS#1 encryption using the + * mode from the context. Add the message padding, then do an + * RSA operation. + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding + * and MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Perform a PKCS#1 v1.5 encryption (RSAES-PKCS1-v1_5-ENCRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Perform a PKCS#1 v2.1 OAEP encryption (RSAES-OAEP-ENCRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for padding and PKCS#1 v2.1 encoding + * and MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param label buffer holding the custom label to use + * \param label_len contains the label length + * \param ilen contains the plaintext length + * \param input buffer holding the data to be encrypted + * \param output buffer that will hold the ciphertext + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output ); + +/** + * \brief Generic wrapper to perform a PKCS#1 decryption using the + * mode from the context. Do an RSA operation, then remove + * the message padding + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Perform a PKCS#1 v1.5 decryption (RSAES-PKCS1-v1_5-DECRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Perform a PKCS#1 v2.1 OAEP decryption (RSAES-OAEP-DECRYPT) + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param label buffer holding the custom label to use + * \param label_len contains the label length + * \param olen will contain the plaintext length + * \param input buffer holding the encrypted data + * \param output buffer that will hold the plaintext + * \param output_max_len maximum length of the output buffer + * + * \return 0 if successful, or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The output buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise + * an error is thrown. + */ +int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ); + +/** + * \brief Generic wrapper to perform a PKCS#1 signature using the + * mode from the context. Do a private RSA operation to sign + * a message digest + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding and for + * MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding, see comments on + * \note \c mbedtls_rsa_rsassa_pss_sign() for details on md_alg and hash_id. + */ +int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v1.5 signature (RSASSA-PKCS1-v1_5-SIGN) + * + * \param ctx RSA context + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v2.1 PSS signature (RSASSA-PSS-SIGN) + * + * \param ctx RSA context + * \param f_rng RNG function (Needed for PKCS#1 v2.1 encoding and for + * MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer that will hold the ciphertext + * + * \return 0 if the signing operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note The hash_id in the RSA context is the one used for the + * encoding. md_alg in the function call is the type of hash + * that is encoded. According to RFC 3447 it is advised to + * keep both hashes the same. + */ +int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ); + +/** + * \brief Generic wrapper to perform a PKCS#1 verification using the + * mode from the context. Do a public RSA operation and check + * the message digest + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note In case of PKCS#1 v2.1 encoding, see comments on + * \c mbedtls_rsa_rsassa_pss_verify() about md_alg and hash_id. + */ +int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v1.5 verification (RSASSA-PKCS1-v1_5-VERIFY) + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + */ +int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY) + * (This is the "simple" version.) + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note The hash_id in the RSA context is the one used for the + * verification. md_alg in the function call is the type of + * hash that is verified. According to RFC 3447 it is advised to + * keep both hashes the same. If hash_id in the RSA context is + * unset, the md_alg from the function call is used. + */ +int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ); + +/** + * \brief Perform a PKCS#1 v2.1 PSS verification (RSASSA-PSS-VERIFY) + * (This is the version with "full" options.) + * + * \param ctx points to an RSA public key + * \param f_rng RNG function (Only needed for MBEDTLS_RSA_PRIVATE) + * \param p_rng RNG parameter + * \param mode MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE + * \param md_alg a MBEDTLS_MD_XXX (use MBEDTLS_MD_NONE for signing raw data) + * \param hashlen message digest length (for MBEDTLS_MD_NONE only) + * \param hash buffer holding the message digest + * \param mgf1_hash_id message digest used for mask generation + * \param expected_salt_len Length of the salt used in padding, use + * MBEDTLS_RSA_SALT_LEN_ANY to accept any salt length + * \param sig buffer holding the ciphertext + * + * \return 0 if the verify operation was successful, + * or an MBEDTLS_ERR_RSA_XXX error code + * + * \note The "sig" buffer must be as large as the size + * of ctx->N (eg. 128 bytes if RSA-1024 is used). + * + * \note The hash_id in the RSA context is ignored. + */ +int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + mbedtls_md_type_t mgf1_hash_id, + int expected_salt_len, + const unsigned char *sig ); + +/** + * \brief Copy the components of an RSA context + * + * \param dst Destination context + * \param src Source context + * + * \return 0 on success, + * MBEDTLS_ERR_MPI_ALLOC_FAILED on memory allocation failure + */ +int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ); + +/** + * \brief Free the components of an RSA key + * + * \param ctx RSA Context to free + */ +void mbedtls_rsa_free( mbedtls_rsa_context *ctx ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_rsa_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_RSA_C */ + +#endif /* rsa.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/sha1.h b/c++/src/connect/mbedtls/mbedtls/sha1.h new file mode 100644 index 00000000..7a67c6c1 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/sha1.h @@ -0,0 +1,136 @@ +/** + * \file sha1.h + * + * \brief SHA-1 cryptographic hash function + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA1_H +#define MBEDTLS_SHA1_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_SHA1_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-1 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[5]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ +} +mbedtls_sha1_context; + +/** + * \brief Initialize SHA-1 context + * + * \param ctx SHA-1 context to be initialized + */ +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ); + +/** + * \brief Clear SHA-1 context + * + * \param ctx SHA-1 context to be cleared + */ +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-1 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ); + +/** + * \brief SHA-1 context setup + * + * \param ctx context to be initialized + */ +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ); + +/** + * \brief SHA-1 process buffer + * + * \param ctx SHA-1 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ); + +/** + * \brief SHA-1 final digest + * + * \param ctx SHA-1 context + * \param output SHA-1 checksum result + */ +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ); + +/* Internal use */ +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_SHA1_ALT */ +#include "sha1_alt.h" +#endif /* MBEDTLS_SHA1_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-1( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-1 checksum result + */ +void mbedtls_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_sha1_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha1.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/sha256.h b/c++/src/connect/mbedtls/mbedtls/sha256.h new file mode 100644 index 00000000..f8041adf --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/sha256.h @@ -0,0 +1,141 @@ +/** + * \file sha256.h + * + * \brief SHA-224 and SHA-256 cryptographic hash function + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA256_H +#define MBEDTLS_SHA256_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_SHA256_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-256 context structure + */ +typedef struct +{ + uint32_t total[2]; /*!< number of bytes processed */ + uint32_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[64]; /*!< data block being processed */ + int is224; /*!< 0 => SHA-256, else SHA-224 */ +} +mbedtls_sha256_context; + +/** + * \brief Initialize SHA-256 context + * + * \param ctx SHA-256 context to be initialized + */ +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ); + +/** + * \brief Clear SHA-256 context + * + * \param ctx SHA-256 context to be cleared + */ +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-256 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ); + +/** + * \brief SHA-256 context setup + * + * \param ctx context to be initialized + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ); + +/** + * \brief SHA-256 process buffer + * + * \param ctx SHA-256 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-256 final digest + * + * \param ctx SHA-256 context + * \param output SHA-224/256 checksum result + */ +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ); + +/* Internal use */ +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_SHA256_ALT */ +#include "sha256_alt.h" +#endif /* MBEDTLS_SHA256_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-256( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-224/256 checksum result + * \param is224 0 = use SHA256, 1 = use SHA224 + */ +void mbedtls_sha256( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_sha256_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha256.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/sha512.h b/c++/src/connect/mbedtls/mbedtls/sha512.h new file mode 100644 index 00000000..627694f4 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/sha512.h @@ -0,0 +1,141 @@ +/** + * \file sha512.h + * + * \brief SHA-384 and SHA-512 cryptographic hash function + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SHA512_H +#define MBEDTLS_SHA512_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#if !defined(MBEDTLS_SHA512_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief SHA-512 context structure + */ +typedef struct +{ + uint64_t total[2]; /*!< number of bytes processed */ + uint64_t state[8]; /*!< intermediate digest state */ + unsigned char buffer[128]; /*!< data block being processed */ + int is384; /*!< 0 => SHA-512, else SHA-384 */ +} +mbedtls_sha512_context; + +/** + * \brief Initialize SHA-512 context + * + * \param ctx SHA-512 context to be initialized + */ +void mbedtls_sha512_init( mbedtls_sha512_context *ctx ); + +/** + * \brief Clear SHA-512 context + * + * \param ctx SHA-512 context to be cleared + */ +void mbedtls_sha512_free( mbedtls_sha512_context *ctx ); + +/** + * \brief Clone (the state of) a SHA-512 context + * + * \param dst The destination context + * \param src The context to be cloned + */ +void mbedtls_sha512_clone( mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src ); + +/** + * \brief SHA-512 context setup + * + * \param ctx context to be initialized + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, int is384 ); + +/** + * \brief SHA-512 process buffer + * + * \param ctx SHA-512 context + * \param input buffer holding the data + * \param ilen length of the input data + */ +void mbedtls_sha512_update( mbedtls_sha512_context *ctx, const unsigned char *input, + size_t ilen ); + +/** + * \brief SHA-512 final digest + * + * \param ctx SHA-512 context + * \param output SHA-384/512 checksum result + */ +void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, unsigned char output[64] ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_SHA512_ALT */ +#include "sha512_alt.h" +#endif /* MBEDTLS_SHA512_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Output = SHA-512( input buffer ) + * + * \param input buffer holding the data + * \param ilen length of the input data + * \param output SHA-384/512 checksum result + * \param is384 0 = use SHA512, 1 = use SHA384 + */ +void mbedtls_sha512( const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_sha512_self_test( int verbose ); + +/* Internal use */ +void mbedtls_sha512_process( mbedtls_sha512_context *ctx, const unsigned char data[128] ); + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_sha512.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ssl.h b/c++/src/connect/mbedtls/mbedtls/ssl.h new file mode 100644 index 00000000..66f16ff6 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ssl.h @@ -0,0 +1,2559 @@ +/** + * \file ssl.h + * + * \brief SSL/TLS functions. + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_H +#define MBEDTLS_SSL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "bignum.h" +#include "ecp.h" + +#include "ssl_ciphersuites.h" + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#include "x509_crt.h" +#include "x509_crl.h" +#endif + +#if defined(MBEDTLS_DHM_C) +#include "dhm.h" +#endif + +#if defined(MBEDTLS_ECDH_C) +#include "ecdh.h" +#endif + +#if defined(MBEDTLS_ZLIB_SUPPORT) +#include "zlib.h" +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include "platform_time.h" +#endif + +/* + * SSL Error codes + */ +#define MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE -0x7080 /**< The requested feature is not available. */ +#define MBEDTLS_ERR_SSL_BAD_INPUT_DATA -0x7100 /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_SSL_INVALID_MAC -0x7180 /**< Verification of the message MAC failed. */ +#define MBEDTLS_ERR_SSL_INVALID_RECORD -0x7200 /**< An invalid SSL record was received. */ +#define MBEDTLS_ERR_SSL_CONN_EOF -0x7280 /**< The connection indicated an EOF. */ +#define MBEDTLS_ERR_SSL_UNKNOWN_CIPHER -0x7300 /**< An unknown cipher was received. */ +#define MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN -0x7380 /**< The server has no ciphersuites in common with the client. */ +#define MBEDTLS_ERR_SSL_NO_RNG -0x7400 /**< No RNG was provided to the SSL module. */ +#define MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE -0x7480 /**< No client certification received from the client, but required by the authentication mode. */ +#define MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE -0x7500 /**< Our own certificate(s) is/are too large to send in an SSL message. */ +#define MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED -0x7580 /**< The own certificate is not set, but needed by the server. */ +#define MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED -0x7600 /**< The own private key or pre-shared key is not set, but needed. */ +#define MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED -0x7680 /**< No CA Chain is set, but required to operate. */ +#define MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE -0x7700 /**< An unexpected message was received from our peer. */ +#define MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE -0x7780 /**< A fatal alert message was received from our peer. */ +#define MBEDTLS_ERR_SSL_PEER_VERIFY_FAILED -0x7800 /**< Verification of our peer failed. */ +#define MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY -0x7880 /**< The peer notified us that the connection is going to be closed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO -0x7900 /**< Processing of the ClientHello handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO -0x7980 /**< Processing of the ServerHello handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE -0x7A00 /**< Processing of the Certificate handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST -0x7A80 /**< Processing of the CertificateRequest handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE -0x7B00 /**< Processing of the ServerKeyExchange handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE -0x7B80 /**< Processing of the ServerHelloDone handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE -0x7C00 /**< Processing of the ClientKeyExchange handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP -0x7C80 /**< Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Read Public. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS -0x7D00 /**< Processing of the ClientKeyExchange handshake message failed in DHM / ECDH Calculate Secret. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY -0x7D80 /**< Processing of the CertificateVerify handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC -0x7E00 /**< Processing of the ChangeCipherSpec handshake message failed. */ +#define MBEDTLS_ERR_SSL_BAD_HS_FINISHED -0x7E80 /**< Processing of the Finished handshake message failed. */ +#define MBEDTLS_ERR_SSL_ALLOC_FAILED -0x7F00 /**< Memory allocation failed */ +#define MBEDTLS_ERR_SSL_HW_ACCEL_FAILED -0x7F80 /**< Hardware acceleration function returned with error */ +#define MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH -0x6F80 /**< Hardware acceleration function skipped / left alone data */ +#define MBEDTLS_ERR_SSL_COMPRESSION_FAILED -0x6F00 /**< Processing of the compression / decompression failed */ +#define MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION -0x6E80 /**< Handshake protocol not within min/max boundaries */ +#define MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET -0x6E00 /**< Processing of the NewSessionTicket handshake message failed. */ +#define MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED -0x6D80 /**< Session ticket has expired. */ +#define MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH -0x6D00 /**< Public key type mismatch (eg, asked for RSA key exchange and presented EC key) */ +#define MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY -0x6C80 /**< Unknown identity received (eg, PSK identity) */ +#define MBEDTLS_ERR_SSL_INTERNAL_ERROR -0x6C00 /**< Internal error (eg, unexpected failure in lower-level module) */ +#define MBEDTLS_ERR_SSL_COUNTER_WRAPPING -0x6B80 /**< A counter would wrap (eg, too many messages exchanged). */ +#define MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO -0x6B00 /**< Unexpected message at ServerHello in renegotiation. */ +#define MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED -0x6A80 /**< DTLS client must retry for hello verification */ +#define MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL -0x6A00 /**< A buffer is too small to receive or write a message */ +#define MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE -0x6980 /**< None of the common ciphersuites is usable (eg, no suitable certificate, see debug messages). */ +#define MBEDTLS_ERR_SSL_WANT_READ -0x6900 /**< Connection requires a read call. */ +#define MBEDTLS_ERR_SSL_WANT_WRITE -0x6880 /**< Connection requires a write call. */ +#define MBEDTLS_ERR_SSL_TIMEOUT -0x6800 /**< The operation timed out. */ +#define MBEDTLS_ERR_SSL_CLIENT_RECONNECT -0x6780 /**< The client initiated a reconnect from the same port. */ +#define MBEDTLS_ERR_SSL_UNEXPECTED_RECORD -0x6700 /**< Record header looks valid but is not expected. */ +#define MBEDTLS_ERR_SSL_NON_FATAL -0x6680 /**< The alert message received indicates a non-fatal error. */ +#define MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH -0x6600 /**< Couldn't set the hash for verifying CertificateVerify */ + +/* + * Various constants + */ +#define MBEDTLS_SSL_MAJOR_VERSION_3 3 +#define MBEDTLS_SSL_MINOR_VERSION_0 0 /*!< SSL v3.0 */ +#define MBEDTLS_SSL_MINOR_VERSION_1 1 /*!< TLS v1.0 */ +#define MBEDTLS_SSL_MINOR_VERSION_2 2 /*!< TLS v1.1 */ +#define MBEDTLS_SSL_MINOR_VERSION_3 3 /*!< TLS v1.2 */ + +#define MBEDTLS_SSL_TRANSPORT_STREAM 0 /*!< TLS */ +#define MBEDTLS_SSL_TRANSPORT_DATAGRAM 1 /*!< DTLS */ + +#define MBEDTLS_SSL_MAX_HOST_NAME_LEN 255 /*!< Maximum host name defined in RFC 1035 */ + +/* RFC 6066 section 4, see also mfl_code_to_length in ssl_tls.c + * NONE must be zero so that memset()ing structure to zero works */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_NONE 0 /*!< don't use this extension */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_512 1 /*!< MaxFragmentLength 2^9 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_1024 2 /*!< MaxFragmentLength 2^10 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_2048 3 /*!< MaxFragmentLength 2^11 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_4096 4 /*!< MaxFragmentLength 2^12 */ +#define MBEDTLS_SSL_MAX_FRAG_LEN_INVALID 5 /*!< first invalid value */ + +#define MBEDTLS_SSL_IS_CLIENT 0 +#define MBEDTLS_SSL_IS_SERVER 1 + +#define MBEDTLS_SSL_IS_NOT_FALLBACK 0 +#define MBEDTLS_SSL_IS_FALLBACK 1 + +#define MBEDTLS_SSL_EXTENDED_MS_DISABLED 0 +#define MBEDTLS_SSL_EXTENDED_MS_ENABLED 1 + +#define MBEDTLS_SSL_ETM_DISABLED 0 +#define MBEDTLS_SSL_ETM_ENABLED 1 + +#define MBEDTLS_SSL_COMPRESS_NULL 0 +#define MBEDTLS_SSL_COMPRESS_DEFLATE 1 + +#define MBEDTLS_SSL_VERIFY_NONE 0 +#define MBEDTLS_SSL_VERIFY_OPTIONAL 1 +#define MBEDTLS_SSL_VERIFY_REQUIRED 2 +#define MBEDTLS_SSL_VERIFY_UNSET 3 /* Used only for sni_authmode */ + +#define MBEDTLS_SSL_LEGACY_RENEGOTIATION 0 +#define MBEDTLS_SSL_SECURE_RENEGOTIATION 1 + +#define MBEDTLS_SSL_RENEGOTIATION_DISABLED 0 +#define MBEDTLS_SSL_RENEGOTIATION_ENABLED 1 + +#define MBEDTLS_SSL_ANTI_REPLAY_DISABLED 0 +#define MBEDTLS_SSL_ANTI_REPLAY_ENABLED 1 + +#define MBEDTLS_SSL_RENEGOTIATION_NOT_ENFORCED -1 +#define MBEDTLS_SSL_RENEGO_MAX_RECORDS_DEFAULT 16 + +#define MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION 0 +#define MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION 1 +#define MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE 2 + +#define MBEDTLS_SSL_TRUNC_HMAC_DISABLED 0 +#define MBEDTLS_SSL_TRUNC_HMAC_ENABLED 1 +#define MBEDTLS_SSL_TRUNCATED_HMAC_LEN 10 /* 80 bits, rfc 6066 section 7 */ + +#define MBEDTLS_SSL_SESSION_TICKETS_DISABLED 0 +#define MBEDTLS_SSL_SESSION_TICKETS_ENABLED 1 + +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED 0 +#define MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED 1 + +#define MBEDTLS_SSL_ARC4_ENABLED 0 +#define MBEDTLS_SSL_ARC4_DISABLED 1 + +#define MBEDTLS_SSL_PRESET_DEFAULT 0 +#define MBEDTLS_SSL_PRESET_SUITEB 2 + +/* + * Default range for DTLS retransmission timer value, in milliseconds. + * RFC 6347 4.2.4.1 says from 1 second to 60 seconds. + */ +#define MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN 1000 +#define MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX 60000 + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME) +#define MBEDTLS_SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +#endif + +/* + * Maxium fragment length in bytes, + * determines the size of each of the two internal I/O buffers. + * + * Note: the RFC defines the default size of SSL / TLS messages. If you + * change the value here, other clients / servers may not be able to + * communicate with you anymore. Only change this value if you control + * both sides of the connection and have it reduced at both sides, or + * if you're using the Max Fragment Length extension and you know all your + * peers are using it too! + */ +#if !defined(MBEDTLS_SSL_MAX_CONTENT_LEN) +#define MBEDTLS_SSL_MAX_CONTENT_LEN 16384 /**< Size of the input / output buffer */ +#endif + +/* \} name SECTION: Module settings */ + +/* + * Length of the verify data for secure renegotiation + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define MBEDTLS_SSL_VERIFY_DATA_MAX_LEN 36 +#else +#define MBEDTLS_SSL_VERIFY_DATA_MAX_LEN 12 +#endif + +/* + * Signaling ciphersuite values (SCSV) + */ +#define MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO 0xFF /**< renegotiation info ext */ +#define MBEDTLS_SSL_FALLBACK_SCSV_VALUE 0x5600 /**< RFC 7507 section 2 */ + +/* + * Supported Signature and Hash algorithms (For TLS 1.2) + * RFC 5246 section 7.4.1.4.1 + */ +#define MBEDTLS_SSL_HASH_NONE 0 +#define MBEDTLS_SSL_HASH_MD5 1 +#define MBEDTLS_SSL_HASH_SHA1 2 +#define MBEDTLS_SSL_HASH_SHA224 3 +#define MBEDTLS_SSL_HASH_SHA256 4 +#define MBEDTLS_SSL_HASH_SHA384 5 +#define MBEDTLS_SSL_HASH_SHA512 6 + +#define MBEDTLS_SSL_SIG_ANON 0 +#define MBEDTLS_SSL_SIG_RSA 1 +#define MBEDTLS_SSL_SIG_ECDSA 3 + +/* + * Client Certificate Types + * RFC 5246 section 7.4.4 plus RFC 4492 section 5.5 + */ +#define MBEDTLS_SSL_CERT_TYPE_RSA_SIGN 1 +#define MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN 64 + +/* + * Message, alert and handshake types + */ +#define MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC 20 +#define MBEDTLS_SSL_MSG_ALERT 21 +#define MBEDTLS_SSL_MSG_HANDSHAKE 22 +#define MBEDTLS_SSL_MSG_APPLICATION_DATA 23 + +#define MBEDTLS_SSL_ALERT_LEVEL_WARNING 1 +#define MBEDTLS_SSL_ALERT_LEVEL_FATAL 2 + +#define MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY 0 /* 0x00 */ +#define MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE 10 /* 0x0A */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC 20 /* 0x14 */ +#define MBEDTLS_SSL_ALERT_MSG_DECRYPTION_FAILED 21 /* 0x15 */ +#define MBEDTLS_SSL_ALERT_MSG_RECORD_OVERFLOW 22 /* 0x16 */ +#define MBEDTLS_SSL_ALERT_MSG_DECOMPRESSION_FAILURE 30 /* 0x1E */ +#define MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE 40 /* 0x28 */ +#define MBEDTLS_SSL_ALERT_MSG_NO_CERT 41 /* 0x29 */ +#define MBEDTLS_SSL_ALERT_MSG_BAD_CERT 42 /* 0x2A */ +#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_CERT 43 /* 0x2B */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_REVOKED 44 /* 0x2C */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_EXPIRED 45 /* 0x2D */ +#define MBEDTLS_SSL_ALERT_MSG_CERT_UNKNOWN 46 /* 0x2E */ +#define MBEDTLS_SSL_ALERT_MSG_ILLEGAL_PARAMETER 47 /* 0x2F */ +#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_CA 48 /* 0x30 */ +#define MBEDTLS_SSL_ALERT_MSG_ACCESS_DENIED 49 /* 0x31 */ +#define MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR 50 /* 0x32 */ +#define MBEDTLS_SSL_ALERT_MSG_DECRYPT_ERROR 51 /* 0x33 */ +#define MBEDTLS_SSL_ALERT_MSG_EXPORT_RESTRICTION 60 /* 0x3C */ +#define MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION 70 /* 0x46 */ +#define MBEDTLS_SSL_ALERT_MSG_INSUFFICIENT_SECURITY 71 /* 0x47 */ +#define MBEDTLS_SSL_ALERT_MSG_INTERNAL_ERROR 80 /* 0x50 */ +#define MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK 86 /* 0x56 */ +#define MBEDTLS_SSL_ALERT_MSG_USER_CANCELED 90 /* 0x5A */ +#define MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION 100 /* 0x64 */ +#define MBEDTLS_SSL_ALERT_MSG_UNSUPPORTED_EXT 110 /* 0x6E */ +#define MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME 112 /* 0x70 */ +#define MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY 115 /* 0x73 */ +#define MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL 120 /* 0x78 */ + +#define MBEDTLS_SSL_HS_HELLO_REQUEST 0 +#define MBEDTLS_SSL_HS_CLIENT_HELLO 1 +#define MBEDTLS_SSL_HS_SERVER_HELLO 2 +#define MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST 3 +#define MBEDTLS_SSL_HS_NEW_SESSION_TICKET 4 +#define MBEDTLS_SSL_HS_CERTIFICATE 11 +#define MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE 12 +#define MBEDTLS_SSL_HS_CERTIFICATE_REQUEST 13 +#define MBEDTLS_SSL_HS_SERVER_HELLO_DONE 14 +#define MBEDTLS_SSL_HS_CERTIFICATE_VERIFY 15 +#define MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE 16 +#define MBEDTLS_SSL_HS_FINISHED 20 + +/* + * TLS extensions + */ +#define MBEDTLS_TLS_EXT_SERVERNAME 0 +#define MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME 0 + +#define MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH 1 + +#define MBEDTLS_TLS_EXT_TRUNCATED_HMAC 4 + +#define MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES 10 +#define MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS 11 + +#define MBEDTLS_TLS_EXT_SIG_ALG 13 + +#define MBEDTLS_TLS_EXT_ALPN 16 + +#define MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC 22 /* 0x16 */ +#define MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET 0x0017 /* 23 */ + +#define MBEDTLS_TLS_EXT_SESSION_TICKET 35 + +#define MBEDTLS_TLS_EXT_ECJPAKE_KKPP 256 /* experimental */ + +#define MBEDTLS_TLS_EXT_RENEGOTIATION_INFO 0xFF01 + +/* + * Size defines + */ +#if !defined(MBEDTLS_PSK_MAX_LEN) +#define MBEDTLS_PSK_MAX_LEN 32 /* 256 bits */ +#endif + +/* Dummy type used only for its size */ +union mbedtls_ssl_premaster_secret +{ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + unsigned char _pms_rsa[48]; /* RFC 5246 8.1.1 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + unsigned char _pms_dhm[MBEDTLS_MPI_MAX_SIZE]; /* RFC 5246 8.1.2 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + unsigned char _pms_ecdh[MBEDTLS_ECP_MAX_BYTES]; /* RFC 4492 5.10 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + unsigned char _pms_psk[4 + 2 * MBEDTLS_PSK_MAX_LEN]; /* RFC 4279 2 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + unsigned char _pms_dhe_psk[4 + MBEDTLS_MPI_MAX_SIZE + + MBEDTLS_PSK_MAX_LEN]; /* RFC 4279 3 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + unsigned char _pms_rsa_psk[52 + MBEDTLS_PSK_MAX_LEN]; /* RFC 4279 4 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + unsigned char _pms_ecdhe_psk[4 + MBEDTLS_ECP_MAX_BYTES + + MBEDTLS_PSK_MAX_LEN]; /* RFC 5489 2 */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + unsigned char _pms_ecjpake[32]; /* Thread spec: SHA-256 output */ +#endif +}; + +#define MBEDTLS_PREMASTER_SIZE sizeof( union mbedtls_ssl_premaster_secret ) + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * SSL state machine + */ +typedef enum +{ + MBEDTLS_SSL_HELLO_REQUEST, + MBEDTLS_SSL_CLIENT_HELLO, + MBEDTLS_SSL_SERVER_HELLO, + MBEDTLS_SSL_SERVER_CERTIFICATE, + MBEDTLS_SSL_SERVER_KEY_EXCHANGE, + MBEDTLS_SSL_CERTIFICATE_REQUEST, + MBEDTLS_SSL_SERVER_HELLO_DONE, + MBEDTLS_SSL_CLIENT_CERTIFICATE, + MBEDTLS_SSL_CLIENT_KEY_EXCHANGE, + MBEDTLS_SSL_CERTIFICATE_VERIFY, + MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC, + MBEDTLS_SSL_CLIENT_FINISHED, + MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC, + MBEDTLS_SSL_SERVER_FINISHED, + MBEDTLS_SSL_FLUSH_BUFFERS, + MBEDTLS_SSL_HANDSHAKE_WRAPUP, + MBEDTLS_SSL_HANDSHAKE_OVER, + MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET, + MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT, +} +mbedtls_ssl_states; + +/** + * \brief Callback type: send data on the network. + * + * \note That callback may be either blocking or non-blocking. + * + * \param ctx Context for the send callback (typically a file descriptor) + * \param buf Buffer holding the data to send + * \param len Length of the data to send + * + * \return The callback must return the number of bytes sent if any, + * or a non-zero error code. + * If performing non-blocking I/O, \c MBEDTLS_ERR_SSL_WANT_WRITE + * must be returned when the operation would block. + * + * \note The callback is allowed to send fewer bytes than requested. + * It must always return the number of bytes actually sent. + */ +typedef int mbedtls_ssl_send_t( void *ctx, + const unsigned char *buf, + size_t len ); + +/** + * \brief Callback type: receive data from the network. + * + * \note That callback may be either blocking or non-blocking. + * + * \param ctx Context for the receive callback (typically a file + * descriptor) + * \param buf Buffer to write the received data to + * \param len Length of the receive buffer + * + * \return The callback must return the number of bytes received, + * or a non-zero error code. + * If performing non-blocking I/O, \c MBEDTLS_ERR_SSL_WANT_READ + * must be returned when the operation would block. + * + * \note The callback may receive fewer bytes than the length of the + * buffer. It must always return the number of bytes actually + * received and written to the buffer. + */ +typedef int mbedtls_ssl_recv_t( void *ctx, + unsigned char *buf, + size_t len ); + +/** + * \brief Callback type: receive data from the network, with timeout + * + * \note That callback must block until data is received, or the + * timeout delay expires, or the operation is interrupted by a + * signal. + * + * \param ctx Context for the receive callback (typically a file descriptor) + * \param buf Buffer to write the received data to + * \param len Length of the receive buffer + * \param timeout Maximum nomber of millisecondes to wait for data + * 0 means no timeout (potentially waiting forever) + * + * \return The callback must return the number of bytes received, + * or a non-zero error code: + * \c MBEDTLS_ERR_SSL_TIMEOUT if the operation timed out, + * \c MBEDTLS_ERR_SSL_WANT_READ if interrupted by a signal. + * + * \note The callback may receive fewer bytes than the length of the + * buffer. It must always return the number of bytes actually + * received and written to the buffer. + */ +typedef int mbedtls_ssl_recv_timeout_t( void *ctx, + unsigned char *buf, + size_t len, + uint32_t timeout ); +/** + * \brief Callback type: set a pair of timers/delays to watch + * + * \param ctx Context pointer + * \param int_ms Intermediate delay in milliseconds + * \param fin_ms Final delay in milliseconds + * 0 cancels the current timer. + * + * \note This callback must at least store the necessary information + * for the associated \c mbedtls_ssl_get_timer_t callback to + * return correct information. + * + * \note If using a event-driven style of programming, an event must + * be generated when the final delay is passed. The event must + * cause a call to \c mbedtls_ssl_handshake() with the proper + * SSL context to be scheduled. Care must be taken to ensure + * that at most one such call happens at a time. + * + * \note Only one timer at a time must be running. Calling this + * function while a timer is running must cancel it. Cancelled + * timers must not generate any event. + */ +typedef void mbedtls_ssl_set_timer_t( void * ctx, + uint32_t int_ms, + uint32_t fin_ms ); + +/** + * \brief Callback type: get status of timers/delays + * + * \param ctx Context pointer + * + * \return This callback must return: + * -1 if cancelled (fin_ms == 0), + * 0 if none of the delays have passed, + * 1 if only the intermediate delay has passed, + * 2 if the final delay has passed. + */ +typedef int mbedtls_ssl_get_timer_t( void * ctx ); + + +/* Defined below */ +typedef struct mbedtls_ssl_session mbedtls_ssl_session; +typedef struct mbedtls_ssl_context mbedtls_ssl_context; +typedef struct mbedtls_ssl_config mbedtls_ssl_config; + +/* Defined in ssl_internal.h */ +typedef struct mbedtls_ssl_transform mbedtls_ssl_transform; +typedef struct mbedtls_ssl_handshake_params mbedtls_ssl_handshake_params; +#if defined(MBEDTLS_X509_CRT_PARSE_C) +typedef struct mbedtls_ssl_key_cert mbedtls_ssl_key_cert; +#endif +#if defined(MBEDTLS_SSL_PROTO_DTLS) +typedef struct mbedtls_ssl_flight_item mbedtls_ssl_flight_item; +#endif + +/* + * This structure is used for storing current session data. + */ +struct mbedtls_ssl_session +{ +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t start; /*!< starting time */ +#endif + int ciphersuite; /*!< chosen ciphersuite */ + int compression; /*!< chosen compression */ + size_t id_len; /*!< session id length */ + unsigned char id[32]; /*!< session identifier */ + unsigned char master[48]; /*!< the master secret */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_x509_crt *peer_cert; /*!< peer X.509 cert chain */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + uint32_t verify_result; /*!< verification result */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + unsigned char *ticket; /*!< RFC 5077 session ticket */ + size_t ticket_len; /*!< session ticket length */ + uint32_t ticket_lifetime; /*!< ticket lifetime hint */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + unsigned char mfl_code; /*!< MaxFragmentLength negotiated by peer */ +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + int trunc_hmac; /*!< flag for truncated hmac activation */ +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + int encrypt_then_mac; /*!< flag for EtM activation */ +#endif +}; + +/** + * SSL/TLS configuration to be shared between mbedtls_ssl_context structures. + */ +struct mbedtls_ssl_config +{ + /* Group items by size (largest first) to minimize padding overhead */ + + /* + * Pointers + */ + + const int *ciphersuite_list[4]; /*!< allowed ciphersuites per version */ + + /** Callback for printing debug output */ + void (*f_dbg)(void *, int, const char *, int, const char *); + void *p_dbg; /*!< context for the debug function */ + + /** Callback for getting (pseudo-)random numbers */ + int (*f_rng)(void *, unsigned char *, size_t); + void *p_rng; /*!< context for the RNG function */ + + /** Callback to retrieve a session from the cache */ + int (*f_get_cache)(void *, mbedtls_ssl_session *); + /** Callback to store a session into the cache */ + int (*f_set_cache)(void *, const mbedtls_ssl_session *); + void *p_cache; /*!< context for cache callbacks */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + /** Callback for setting cert according to SNI extension */ + int (*f_sni)(void *, mbedtls_ssl_context *, const unsigned char *, size_t); + void *p_sni; /*!< context for SNI callback */ +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /** Callback to customize X.509 certificate chain verification */ + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *); + void *p_vrfy; /*!< context for X.509 verify calllback */ +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + /** Callback to retrieve PSK key from identity */ + int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, size_t); + void *p_psk; /*!< context for PSK callback */ +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + /** Callback to create & write a cookie for ClientHello veirifcation */ + int (*f_cookie_write)( void *, unsigned char **, unsigned char *, + const unsigned char *, size_t ); + /** Callback to verify validity of a ClientHello cookie */ + int (*f_cookie_check)( void *, const unsigned char *, size_t, + const unsigned char *, size_t ); + void *p_cookie; /*!< context for the cookie callbacks */ +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) + /** Callback to create & write a session ticket */ + int (*f_ticket_write)( void *, const mbedtls_ssl_session *, + unsigned char *, const unsigned char *, size_t *, uint32_t * ); + /** Callback to parse a session ticket into a session structure */ + int (*f_ticket_parse)( void *, mbedtls_ssl_session *, unsigned char *, size_t); + void *p_ticket; /*!< context for the ticket callbacks */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + /** Callback to export key block and master secret */ + int (*f_export_keys)( void *, const unsigned char *, + const unsigned char *, size_t, size_t, size_t ); + void *p_export_keys; /*!< context for key export callback */ +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + const mbedtls_x509_crt_profile *cert_profile; /*!< verification profile */ + mbedtls_ssl_key_cert *key_cert; /*!< own certificate/key pair(s) */ + mbedtls_x509_crt *ca_chain; /*!< trusted CAs */ + mbedtls_x509_crl *ca_crl; /*!< trusted CAs CRLs */ +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + const int *sig_hashes; /*!< allowed signature hashes */ +#endif + +#if defined(MBEDTLS_ECP_C) + const mbedtls_ecp_group_id *curve_list; /*!< allowed curves */ +#endif + +#if defined(MBEDTLS_DHM_C) + mbedtls_mpi dhm_P; /*!< prime modulus for DHM */ + mbedtls_mpi dhm_G; /*!< generator for DHM */ +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + unsigned char *psk; /*!< pre-shared key */ + size_t psk_len; /*!< length of the pre-shared key */ + unsigned char *psk_identity; /*!< identity for PSK negotiation */ + size_t psk_identity_len;/*!< length of identity */ +#endif + +#if defined(MBEDTLS_SSL_ALPN) + const char **alpn_list; /*!< ordered list of protocols */ +#endif + + /* + * Numerical settings (int then char) + */ + + uint32_t read_timeout; /*!< timeout for mbedtls_ssl_read (ms) */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint32_t hs_timeout_min; /*!< initial value of the handshake + retransmission timeout (ms) */ + uint32_t hs_timeout_max; /*!< maximum value of the handshake + retransmission timeout (ms) */ +#endif + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renego_max_records; /*!< grace period for renegotiation */ + unsigned char renego_period[8]; /*!< value of the record counters + that triggers renegotiation */ +#endif + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + unsigned int badmac_limit; /*!< limit of records with a bad MAC */ +#endif + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) + unsigned int dhm_min_bitlen; /*!< min. bit length of the DHM prime */ +#endif + + unsigned char max_major_ver; /*!< max. major version used */ + unsigned char max_minor_ver; /*!< max. minor version used */ + unsigned char min_major_ver; /*!< min. major version used */ + unsigned char min_minor_ver; /*!< min. minor version used */ + + /* + * Flags (bitfields) + */ + + unsigned int endpoint : 1; /*!< 0: client, 1: server */ + unsigned int transport : 1; /*!< stream (TLS) or datagram (DTLS) */ + unsigned int authmode : 2; /*!< MBEDTLS_SSL_VERIFY_XXX */ + /* needed even with renego disabled for LEGACY_BREAK_HANDSHAKE */ + unsigned int allow_legacy_renegotiation : 2 ; /*!< MBEDTLS_LEGACY_XXX */ +#if defined(MBEDTLS_ARC4_C) + unsigned int arc4_disabled : 1; /*!< blacklist RC4 ciphersuites? */ +#endif +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + unsigned int mfl_code : 3; /*!< desired fragment length */ +#endif +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + unsigned int encrypt_then_mac : 1 ; /*!< negotiate encrypt-then-mac? */ +#endif +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + unsigned int extended_ms : 1; /*!< negotiate extended master secret? */ +#endif +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + unsigned int anti_replay : 1; /*!< detect and prevent replay? */ +#endif +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + unsigned int cbc_record_splitting : 1; /*!< do cbc record splitting */ +#endif +#if defined(MBEDTLS_SSL_RENEGOTIATION) + unsigned int disable_renegotiation : 1; /*!< disable renegotiation? */ +#endif +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + unsigned int trunc_hmac : 1; /*!< negotiate truncated hmac? */ +#endif +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + unsigned int session_tickets : 1; /*!< use session tickets? */ +#endif +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C) + unsigned int fallback : 1; /*!< is this a fallback? */ +#endif +}; + + +struct mbedtls_ssl_context +{ + const mbedtls_ssl_config *conf; /*!< configuration information */ + + /* + * Miscellaneous + */ + int state; /*!< SSL handshake: current state */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renego_status; /*!< Initial, in progress, pending? */ + int renego_records_seen; /*!< Records since renego request, or with DTLS, + number of retransmissions of request if + renego_max_records is < 0 */ +#endif + + int major_ver; /*!< equal to MBEDTLS_SSL_MAJOR_VERSION_3 */ + int minor_ver; /*!< either 0 (SSL3) or 1 (TLS1.0) */ + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + unsigned badmac_seen; /*!< records with a bad MAC received */ +#endif + + mbedtls_ssl_send_t *f_send; /*!< Callback for network send */ + mbedtls_ssl_recv_t *f_recv; /*!< Callback for network receive */ + mbedtls_ssl_recv_timeout_t *f_recv_timeout; + /*!< Callback for network receive with timeout */ + + void *p_bio; /*!< context for I/O operations */ + + /* + * Session layer + */ + mbedtls_ssl_session *session_in; /*!< current session data (in) */ + mbedtls_ssl_session *session_out; /*!< current session data (out) */ + mbedtls_ssl_session *session; /*!< negotiated session data */ + mbedtls_ssl_session *session_negotiate; /*!< session data in negotiation */ + + mbedtls_ssl_handshake_params *handshake; /*!< params required only during + the handshake process */ + + /* + * Record layer transformations + */ + mbedtls_ssl_transform *transform_in; /*!< current transform params (in) */ + mbedtls_ssl_transform *transform_out; /*!< current transform params (in) */ + mbedtls_ssl_transform *transform; /*!< negotiated transform params */ + mbedtls_ssl_transform *transform_negotiate; /*!< transform params in negotiation */ + + /* + * Timers + */ + void *p_timer; /*!< context for the timer callbacks */ + + mbedtls_ssl_set_timer_t *f_set_timer; /*!< set timer callback */ + mbedtls_ssl_get_timer_t *f_get_timer; /*!< get timer callback */ + + /* + * Record layer (incoming data) + */ + unsigned char *in_buf; /*!< input buffer */ + unsigned char *in_ctr; /*!< 64-bit incoming message counter + TLS: maintained by us + DTLS: read from peer */ + unsigned char *in_hdr; /*!< start of record header */ + unsigned char *in_len; /*!< two-bytes message length field */ + unsigned char *in_iv; /*!< ivlen-byte IV */ + unsigned char *in_msg; /*!< message contents (in_iv+ivlen) */ + unsigned char *in_offt; /*!< read offset in application data */ + + int in_msgtype; /*!< record header: message type */ + size_t in_msglen; /*!< record header: message length */ + size_t in_left; /*!< amount of data read so far */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + uint16_t in_epoch; /*!< DTLS epoch for incoming records */ + size_t next_record_offset; /*!< offset of the next record in datagram + (equal to in_left if none) */ +#endif +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + uint64_t in_window_top; /*!< last validated record seq_num */ + uint64_t in_window; /*!< bitmask for replay detection */ +#endif + + size_t in_hslen; /*!< current handshake message length, + including the handshake header */ + int nb_zero; /*!< # of 0-length encrypted messages */ + int record_read; /*!< record is already present */ + + /* + * Record layer (outgoing data) + */ + unsigned char *out_buf; /*!< output buffer */ + unsigned char *out_ctr; /*!< 64-bit outgoing message counter */ + unsigned char *out_hdr; /*!< start of record header */ + unsigned char *out_len; /*!< two-bytes message length field */ + unsigned char *out_iv; /*!< ivlen-byte IV */ + unsigned char *out_msg; /*!< message contents (out_iv+ivlen) */ + + int out_msgtype; /*!< record header: message type */ + size_t out_msglen; /*!< record header: message length */ + size_t out_left; /*!< amount of data not yet written */ + +#if defined(MBEDTLS_ZLIB_SUPPORT) + unsigned char *compress_buf; /*!< zlib data buffer */ +#endif +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + signed char split_done; /*!< current record already splitted? */ +#endif + + /* + * PKI layer + */ + int client_auth; /*!< flag for client auth. */ + + /* + * User settings + */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + char *hostname; /*!< expected peer CN for verification + (and SNI if available) */ +#endif + +#if defined(MBEDTLS_SSL_ALPN) + const char *alpn_chosen; /*!< negotiated protocol */ +#endif + + /* + * Information for DTLS hello verify + */ +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + unsigned char *cli_id; /*!< transport-level ID of the client */ + size_t cli_id_len; /*!< length of cli_id */ +#endif + + /* + * Secure renegotiation + */ + /* needed to know when to send extension on server */ + int secure_renegotiation; /*!< does peer support legacy or + secure renegotiation */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + size_t verify_data_len; /*!< length of verify data stored */ + char own_verify_data[MBEDTLS_SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */ + char peer_verify_data[MBEDTLS_SSL_VERIFY_DATA_MAX_LEN]; /*!< previous handshake verify data */ +#endif +}; + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + +#define MBEDTLS_SSL_CHANNEL_OUTBOUND 0 +#define MBEDTLS_SSL_CHANNEL_INBOUND 1 + +extern int (*mbedtls_ssl_hw_record_init)(mbedtls_ssl_context *ssl, + const unsigned char *key_enc, const unsigned char *key_dec, + size_t keylen, + const unsigned char *iv_enc, const unsigned char *iv_dec, + size_t ivlen, + const unsigned char *mac_enc, const unsigned char *mac_dec, + size_t maclen); +extern int (*mbedtls_ssl_hw_record_activate)(mbedtls_ssl_context *ssl, int direction); +extern int (*mbedtls_ssl_hw_record_reset)(mbedtls_ssl_context *ssl); +extern int (*mbedtls_ssl_hw_record_write)(mbedtls_ssl_context *ssl); +extern int (*mbedtls_ssl_hw_record_read)(mbedtls_ssl_context *ssl); +extern int (*mbedtls_ssl_hw_record_finish)(mbedtls_ssl_context *ssl); +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + +/** + * \brief Returns the list of ciphersuites supported by the SSL/TLS module. + * + * \return a statically allocated array of ciphersuites, the last + * entry is 0. + */ +const int *mbedtls_ssl_list_ciphersuites( void ); + +/** + * \brief Return the name of the ciphersuite associated with the + * given ID + * + * \param ciphersuite_id SSL ciphersuite ID + * + * \return a string containing the ciphersuite name + */ +const char *mbedtls_ssl_get_ciphersuite_name( const int ciphersuite_id ); + +/** + * \brief Return the ID of the ciphersuite associated with the + * given name + * + * \param ciphersuite_name SSL ciphersuite name + * + * \return the ID with the ciphersuite or 0 if not found + */ +int mbedtls_ssl_get_ciphersuite_id( const char *ciphersuite_name ); + +/** + * \brief Initialize an SSL context + * Just makes the context ready for mbedtls_ssl_setup() or + * mbedtls_ssl_free() + * + * \param ssl SSL context + */ +void mbedtls_ssl_init( mbedtls_ssl_context *ssl ); + +/** + * \brief Set up an SSL context for use + * + * \note No copy of the configuration context is made, it can be + * shared by many mbedtls_ssl_context structures. + * + * \warning Modifying the conf structure after it has been used in this + * function is unsupported! + * + * \param ssl SSL context + * \param conf SSL configuration to use + * + * \return 0 if successful, or MBEDTLS_ERR_SSL_ALLOC_FAILED if + * memory allocation failed + */ +int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, + const mbedtls_ssl_config *conf ); + +/** + * \brief Reset an already initialized SSL context for re-use + * while retaining application-set variables, function + * pointers and data. + * + * \param ssl SSL context + * \return 0 if successful, or MBEDTLS_ERR_SSL_ALLOC_FAILED, + MBEDTLS_ERR_SSL_HW_ACCEL_FAILED or + * MBEDTLS_ERR_SSL_COMPRESSION_FAILED + */ +int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl ); + +/** + * \brief Set the current endpoint type + * + * \param conf SSL configuration + * \param endpoint must be MBEDTLS_SSL_IS_CLIENT or MBEDTLS_SSL_IS_SERVER + */ +void mbedtls_ssl_conf_endpoint( mbedtls_ssl_config *conf, int endpoint ); + +/** + * \brief Set the transport type (TLS or DTLS). + * Default: TLS + * + * \note For DTLS, you must either provide a recv callback that + * doesn't block, or one that handles timeouts, see + * \c mbedtls_ssl_set_bio(). You also need to provide timer + * callbacks with \c mbedtls_ssl_set_timer_cb(). + * + * \param conf SSL configuration + * \param transport transport type: + * MBEDTLS_SSL_TRANSPORT_STREAM for TLS, + * MBEDTLS_SSL_TRANSPORT_DATAGRAM for DTLS. + */ +void mbedtls_ssl_conf_transport( mbedtls_ssl_config *conf, int transport ); + +/** + * \brief Set the certificate verification mode + * Default: NONE on server, REQUIRED on client + * + * \param conf SSL configuration + * \param authmode can be: + * + * MBEDTLS_SSL_VERIFY_NONE: peer certificate is not checked + * (default on server) + * (insecure on client) + * + * MBEDTLS_SSL_VERIFY_OPTIONAL: peer certificate is checked, however the + * handshake continues even if verification failed; + * mbedtls_ssl_get_verify_result() can be called after the + * handshake is complete. + * + * MBEDTLS_SSL_VERIFY_REQUIRED: peer *must* present a valid certificate, + * handshake is aborted if verification failed. + * (default on client) + * + * \note On client, MBEDTLS_SSL_VERIFY_REQUIRED is the recommended mode. + * With MBEDTLS_SSL_VERIFY_OPTIONAL, the user needs to call mbedtls_ssl_get_verify_result() at + * the right time(s), which may not be obvious, while REQUIRED always perform + * the verification as soon as possible. For example, REQUIRED was protecting + * against the "triple handshake" attack even before it was found. + */ +void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Set the verification callback (Optional). + * + * If set, the verify callback is called for each + * certificate in the chain. For implementation + * information, please see \c x509parse_verify() + * + * \param conf SSL configuration + * \param f_vrfy verification function + * \param p_vrfy verification parameter + */ +void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/** + * \brief Set the random number generator callback + * + * \param conf SSL configuration + * \param f_rng RNG function + * \param p_rng RNG parameter + */ +void mbedtls_ssl_conf_rng( mbedtls_ssl_config *conf, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Set the debug callback + * + * The callback has the following argument: + * void * opaque context for the callback + * int debug level + * const char * file name + * int line number + * const char * message + * + * \param conf SSL configuration + * \param f_dbg debug function + * \param p_dbg debug parameter + */ +void mbedtls_ssl_conf_dbg( mbedtls_ssl_config *conf, + void (*f_dbg)(void *, int, const char *, int, const char *), + void *p_dbg ); + +/** + * \brief Set the underlying BIO callbacks for write, read and + * read-with-timeout. + * + * \param ssl SSL context + * \param p_bio parameter (context) shared by BIO callbacks + * \param f_send write callback + * \param f_recv read callback + * \param f_recv_timeout blocking read callback with timeout. + * + * \note One of f_recv or f_recv_timeout can be NULL, in which case + * the other is used. If both are non-NULL, f_recv_timeout is + * used and f_recv is ignored (as if it were NULL). + * + * \note The two most common use cases are: + * - non-blocking I/O, f_recv != NULL, f_recv_timeout == NULL + * - blocking I/O, f_recv == NULL, f_recv_timout != NULL + * + * \note For DTLS, you need to provide either a non-NULL + * f_recv_timeout callback, or a f_recv that doesn't block. + * + * \note See the documentations of \c mbedtls_ssl_sent_t, + * \c mbedtls_ssl_recv_t and \c mbedtls_ssl_recv_timeout_t for + * the conventions those callbacks must follow. + * + * \note On some platforms, net_sockets.c provides + * \c mbedtls_net_send(), \c mbedtls_net_recv() and + * \c mbedtls_net_recv_timeout() that are suitable to be used + * here. + */ +void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, + void *p_bio, + mbedtls_ssl_send_t *f_send, + mbedtls_ssl_recv_t *f_recv, + mbedtls_ssl_recv_timeout_t *f_recv_timeout ); + +/** + * \brief Set the timeout period for mbedtls_ssl_read() + * (Default: no timeout.) + * + * \param conf SSL configuration context + * \param timeout Timeout value in milliseconds. + * Use 0 for no timeout (default). + * + * \note With blocking I/O, this will only work if a non-NULL + * \c f_recv_timeout was set with \c mbedtls_ssl_set_bio(). + * With non-blocking I/O, this will only work if timer + * callbacks were set with \c mbedtls_ssl_set_timer_cb(). + * + * \note With non-blocking I/O, you may also skip this function + * altogether and handle timeouts at the application layer. + */ +void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout ); + +/** + * \brief Set the timer callbacks (Mandatory for DTLS.) + * + * \param ssl SSL context + * \param p_timer parameter (context) shared by timer callbacks + * \param f_set_timer set timer callback + * \param f_get_timer get timer callback. Must return: + * + * \note See the documentation of \c mbedtls_ssl_set_timer_t and + * \c mbedtls_ssl_get_timer_t for the conventions this pair of + * callbacks must follow. + * + * \note On some platforms, timing.c provides + * \c mbedtls_timing_set_delay() and + * \c mbedtls_timing_get_delay() that are suitable for using + * here, except if using an event-driven style. + * + * \note See also the "DTLS tutorial" article in our knowledge base. + * https://tls.mbed.org/kb/how-to/dtls-tutorial + */ +void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, + void *p_timer, + mbedtls_ssl_set_timer_t *f_set_timer, + mbedtls_ssl_get_timer_t *f_get_timer ); + +/** + * \brief Callback type: generate and write session ticket + * + * \note This describes what a callback implementation should do. + * This callback should generate an encrypted and + * authenticated ticket for the session and write it to the + * output buffer. Here, ticket means the opaque ticket part + * of the NewSessionTicket structure of RFC 5077. + * + * \param p_ticket Context for the callback + * \param session SSL session to be written in the ticket + * \param start Start of the output buffer + * \param end End of the output buffer + * \param tlen On exit, holds the length written + * \param lifetime On exit, holds the lifetime of the ticket in seconds + * + * \return 0 if successful, or + * a specific MBEDTLS_ERR_XXX code. + */ +typedef int mbedtls_ssl_ticket_write_t( void *p_ticket, + const mbedtls_ssl_session *session, + unsigned char *start, + const unsigned char *end, + size_t *tlen, + uint32_t *lifetime ); + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +/** + * \brief Callback type: Export key block and master secret + * + * \note This is required for certain uses of TLS, e.g. EAP-TLS + * (RFC 5216) and Thread. The key pointers are ephemeral and + * therefore must not be stored. The master secret and keys + * should not be used directly except as an input to a key + * derivation function. + * + * \param p_expkey Context for the callback + * \param ms Pointer to master secret (fixed length: 48 bytes) + * \param kb Pointer to key block, see RFC 5246 section 6.3 + * (variable length: 2 * maclen + 2 * keylen + 2 * ivlen). + * \param maclen MAC length + * \param keylen Key length + * \param ivlen IV length + * + * \return 0 if successful, or + * a specific MBEDTLS_ERR_XXX code. + */ +typedef int mbedtls_ssl_export_keys_t( void *p_expkey, + const unsigned char *ms, + const unsigned char *kb, + size_t maclen, + size_t keylen, + size_t ivlen ); +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + +/** + * \brief Callback type: parse and load session ticket + * + * \note This describes what a callback implementation should do. + * This callback should parse a session ticket as generated + * by the corresponding mbedtls_ssl_ticket_write_t function, + * and, if the ticket is authentic and valid, load the + * session. + * + * \note The implementation is allowed to modify the first len + * bytes of the input buffer, eg to use it as a temporary + * area for the decrypted ticket contents. + * + * \param p_ticket Context for the callback + * \param session SSL session to be loaded + * \param buf Start of the buffer containing the ticket + * \param len Length of the ticket. + * + * \return 0 if successful, or + * MBEDTLS_ERR_SSL_INVALID_MAC if not authentic, or + * MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED if expired, or + * any other non-zero code for other failures. + */ +typedef int mbedtls_ssl_ticket_parse_t( void *p_ticket, + mbedtls_ssl_session *session, + unsigned char *buf, + size_t len ); + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Configure SSL session ticket callbacks (server only). + * (Default: none.) + * + * \note On server, session tickets are enabled by providing + * non-NULL callbacks. + * + * \note On client, use \c mbedtls_ssl_conf_session_tickets(). + * + * \param conf SSL configuration context + * \param f_ticket_write Callback for writing a ticket + * \param f_ticket_parse Callback for parsing a ticket + * \param p_ticket Context shared by the two callbacks + */ +void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_ticket_write_t *f_ticket_write, + mbedtls_ssl_ticket_parse_t *f_ticket_parse, + void *p_ticket ); +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +/** + * \brief Configure key export callback. + * (Default: none.) + * + * \note See \c mbedtls_ssl_export_keys_t. + * + * \param conf SSL configuration context + * \param f_export_keys Callback for exporting keys + * \param p_export_keys Context for the callback + */ +void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_keys_t *f_export_keys, + void *p_export_keys ); +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ + +/** + * \brief Callback type: generate a cookie + * + * \param ctx Context for the callback + * \param p Buffer to write to, + * must be updated to point right after the cookie + * \param end Pointer to one past the end of the output buffer + * \param info Client ID info that was passed to + * \c mbedtls_ssl_set_client_transport_id() + * \param ilen Length of info in bytes + * + * \return The callback must return 0 on success, + * or a negative error code. + */ +typedef int mbedtls_ssl_cookie_write_t( void *ctx, + unsigned char **p, unsigned char *end, + const unsigned char *info, size_t ilen ); + +/** + * \brief Callback type: verify a cookie + * + * \param ctx Context for the callback + * \param cookie Cookie to verify + * \param clen Length of cookie + * \param info Client ID info that was passed to + * \c mbedtls_ssl_set_client_transport_id() + * \param ilen Length of info in bytes + * + * \return The callback must return 0 if cookie is valid, + * or a negative error code. + */ +typedef int mbedtls_ssl_cookie_check_t( void *ctx, + const unsigned char *cookie, size_t clen, + const unsigned char *info, size_t ilen ); + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Register callbacks for DTLS cookies + * (Server only. DTLS only.) + * + * Default: dummy callbacks that fail, in order to force you to + * register working callbacks (and initialize their context). + * + * To disable HelloVerifyRequest, register NULL callbacks. + * + * \warning Disabling hello verification allows your server to be used + * for amplification in DoS attacks against other hosts. + * Only disable if you known this can't happen in your + * particular environment. + * + * \note See comments on \c mbedtls_ssl_handshake() about handling + * the MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED that is expected + * on the first handshake attempt when this is enabled. + * + * \note This is also necessary to handle client reconnection from + * the same port as described in RFC 6347 section 4.2.8 (only + * the variant with cookies is supported currently). See + * comments on \c mbedtls_ssl_read() for details. + * + * \param conf SSL configuration + * \param f_cookie_write Cookie write callback + * \param f_cookie_check Cookie check callback + * \param p_cookie Context for both callbacks + */ +void mbedtls_ssl_conf_dtls_cookies( mbedtls_ssl_config *conf, + mbedtls_ssl_cookie_write_t *f_cookie_write, + mbedtls_ssl_cookie_check_t *f_cookie_check, + void *p_cookie ); + +/** + * \brief Set client's transport-level identification info. + * (Server only. DTLS only.) + * + * This is usually the IP address (and port), but could be + * anything identify the client depending on the underlying + * network stack. Used for HelloVerifyRequest with DTLS. + * This is *not* used to route the actual packets. + * + * \param ssl SSL context + * \param info Transport-level info identifying the client (eg IP + port) + * \param ilen Length of info in bytes + * + * \note An internal copy is made, so the info buffer can be reused. + * + * \return 0 on success, + * MBEDTLS_ERR_SSL_BAD_INPUT_DATA if used on client, + * MBEDTLS_ERR_SSL_ALLOC_FAILED if out of memory. + */ +int mbedtls_ssl_set_client_transport_id( mbedtls_ssl_context *ssl, + const unsigned char *info, + size_t ilen ); + +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +/** + * \brief Enable or disable anti-replay protection for DTLS. + * (DTLS only, no effect on TLS.) + * Default: enabled. + * + * \param conf SSL configuration + * \param mode MBEDTLS_SSL_ANTI_REPLAY_ENABLED or MBEDTLS_SSL_ANTI_REPLAY_DISABLED. + * + * \warning Disabling this is a security risk unless the application + * protocol handles duplicated packets in a safe way. You + * should not disable this without careful consideration. + * However, if your application already detects duplicated + * packets and needs information about them to adjust its + * transmission strategy, then you'll want to disable this. + */ +void mbedtls_ssl_conf_dtls_anti_replay( mbedtls_ssl_config *conf, char mode ); +#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) +/** + * \brief Set a limit on the number of records with a bad MAC + * before terminating the connection. + * (DTLS only, no effect on TLS.) + * Default: 0 (disabled). + * + * \param conf SSL configuration + * \param limit Limit, or 0 to disable. + * + * \note If the limit is N, then the connection is terminated when + * the Nth non-authentic record is seen. + * + * \note Records with an invalid header are not counted, only the + * ones going through the authentication-decryption phase. + * + * \note This is a security trade-off related to the fact that it's + * often relatively easy for an active attacker ot inject UDP + * datagrams. On one hand, setting a low limit here makes it + * easier for such an attacker to forcibly terminated a + * connection. On the other hand, a high limit or no limit + * might make us waste resources checking authentication on + * many bogus packets. + */ +void mbedtls_ssl_conf_dtls_badmac_limit( mbedtls_ssl_config *conf, unsigned limit ); +#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/** + * \brief Set retransmit timeout values for the DTLS handshake. + * (DTLS only, no effect on TLS.) + * + * \param conf SSL configuration + * \param min Initial timeout value in milliseconds. + * Default: 1000 (1 second). + * \param max Maximum timeout value in milliseconds. + * Default: 60000 (60 seconds). + * + * \note Default values are from RFC 6347 section 4.2.4.1. + * + * \note The 'min' value should typically be slightly above the + * expected round-trip time to your peer, plus whatever time + * it takes for the peer to process the message. For example, + * if your RTT is about 600ms and you peer needs up to 1s to + * do the cryptographic operations in the handshake, then you + * should set 'min' slightly above 1600. Lower values of 'min' + * might cause spurious resends which waste network resources, + * while larger value of 'min' will increase overall latency + * on unreliable network links. + * + * \note The more unreliable your network connection is, the larger + * your max / min ratio needs to be in order to achieve + * reliable handshakes. + * + * \note Messages are retransmitted up to log2(ceil(max/min)) times. + * For example, if min = 1s and max = 5s, the retransmit plan + * goes: send ... 1s -> resend ... 2s -> resend ... 4s -> + * resend ... 5s -> give up and return a timeout error. + */ +void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf, uint32_t min, uint32_t max ); +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Set the session cache callbacks (server-side only) + * If not set, no session resuming is done (except if session + * tickets are enabled too). + * + * The session cache has the responsibility to check for stale + * entries based on timeout. See RFC 5246 for recommendations. + * + * Warning: session.peer_cert is cleared by the SSL/TLS layer on + * connection shutdown, so do not cache the pointer! Either set + * it to NULL or make a full copy of the certificate. + * + * The get callback is called once during the initial handshake + * to enable session resuming. The get function has the + * following parameters: (void *parameter, mbedtls_ssl_session *session) + * If a valid entry is found, it should fill the master of + * the session object with the cached values and return 0, + * return 1 otherwise. Optionally peer_cert can be set as well + * if it is properly present in cache entry. + * + * The set callback is called once during the initial handshake + * to enable session resuming after the entire handshake has + * been finished. The set function has the following parameters: + * (void *parameter, const mbedtls_ssl_session *session). The function + * should create a cache entry for future retrieval based on + * the data in the session structure and should keep in mind + * that the mbedtls_ssl_session object presented (and all its referenced + * data) is cleared by the SSL/TLS layer when the connection is + * terminated. It is recommended to add metadata to determine if + * an entry is still valid in the future. Return 0 if + * successfully cached, return 1 otherwise. + * + * \param conf SSL configuration + * \param p_cache parmater (context) for both callbacks + * \param f_get_cache session get callback + * \param f_set_cache session set callback + */ +void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, + void *p_cache, + int (*f_get_cache)(void *, mbedtls_ssl_session *), + int (*f_set_cache)(void *, const mbedtls_ssl_session *) ); +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Request resumption of session (client-side only) + * Session data is copied from presented session structure. + * + * \param ssl SSL context + * \param session session context + * + * \return 0 if successful, + * MBEDTLS_ERR_SSL_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_SSL_BAD_INPUT_DATA if used server-side or + * arguments are otherwise invalid + * + * \sa mbedtls_ssl_get_session() + */ +int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session *session ); +#endif /* MBEDTLS_SSL_CLI_C */ + +/** + * \brief Set the list of allowed ciphersuites and the preference + * order. First in the list has the highest preference. + * (Overrides all version-specific lists) + * + * The ciphersuites array is not copied, and must remain + * valid for the lifetime of the ssl_config. + * + * Note: The server uses its own preferences + * over the preference of the client unless + * MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE is defined! + * + * \param conf SSL configuration + * \param ciphersuites 0-terminated list of allowed ciphersuites + */ +void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, + const int *ciphersuites ); + +/** + * \brief Set the list of allowed ciphersuites and the + * preference order for a specific version of the protocol. + * (Only useful on the server side) + * + * The ciphersuites array is not copied, and must remain + * valid for the lifetime of the ssl_config. + * + * \param conf SSL configuration + * \param ciphersuites 0-terminated list of allowed ciphersuites + * \param major Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 + * supported) + * \param minor Minor version number (MBEDTLS_SSL_MINOR_VERSION_0, + * MBEDTLS_SSL_MINOR_VERSION_1 and MBEDTLS_SSL_MINOR_VERSION_2, + * MBEDTLS_SSL_MINOR_VERSION_3 supported) + * + * \note With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0 + * and MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2 + */ +void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf, + const int *ciphersuites, + int major, int minor ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Set the X.509 security profile used for verification + * + * \note The restrictions are enforced for all certificates in the + * chain. However, signatures in the handshake are not covered + * by this setting but by \b mbedtls_ssl_conf_sig_hashes(). + * + * \param conf SSL configuration + * \param profile Profile to use + */ +void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf, + const mbedtls_x509_crt_profile *profile ); + +/** + * \brief Set the data required to verify peer certificate + * + * \param conf SSL configuration + * \param ca_chain trusted CA chain (meaning all fully trusted top-level CAs) + * \param ca_crl trusted CA CRLs + */ +void mbedtls_ssl_conf_ca_chain( mbedtls_ssl_config *conf, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ); + +/** + * \brief Set own certificate chain and private key + * + * \note own_cert should contain in order from the bottom up your + * certificate chain. The top certificate (self-signed) + * can be omitted. + * + * \note On server, this function can be called multiple times to + * provision more than one cert/key pair (eg one ECDSA, one + * RSA with SHA-256, one RSA with SHA-1). An adequate + * certificate will be selected according to the client's + * advertised capabilities. In case mutliple certificates are + * adequate, preference is given to the one set by the first + * call to this function, then second, etc. + * + * \note On client, only the first call has any effect. That is, + * only one client certificate can be provisioned. The + * server's preferences in its CertficateRequest message will + * be ignored and our only cert will be sent regardless of + * whether it matches those preferences - the server can then + * decide what it wants to do with it. + * + * \param conf SSL configuration + * \param own_cert own public certificate chain + * \param pk_key own private key + * + * \return 0 on success or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *conf, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +/** + * \brief Set the Pre Shared Key (PSK) and the expected identity name + * + * \note This is mainly useful for clients. Servers will usually + * want to use \c mbedtls_ssl_conf_psk_cb() instead. + * + * \note Currently clients can only register one pre-shared key. + * In other words, the servers' identity hint is ignored. + * Support for setting multiple PSKs on clients and selecting + * one based on the identity hint is not a planned feature but + * feedback is welcomed. + * + * \param conf SSL configuration + * \param psk pointer to the pre-shared key + * \param psk_len pre-shared key length + * \param psk_identity pointer to the pre-shared key identity + * \param psk_identity_len identity key length + * + * \return 0 if successful or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, + const unsigned char *psk, size_t psk_len, + const unsigned char *psk_identity, size_t psk_identity_len ); + + +/** + * \brief Set the Pre Shared Key (PSK) for the current handshake + * + * \note This should only be called inside the PSK callback, + * ie the function passed to \c mbedtls_ssl_conf_psk_cb(). + * + * \param ssl SSL context + * \param psk pointer to the pre-shared key + * \param psk_len pre-shared key length + * + * \return 0 if successful or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, + const unsigned char *psk, size_t psk_len ); + +/** + * \brief Set the PSK callback (server-side only). + * + * If set, the PSK callback is called for each + * handshake where a PSK ciphersuite was negotiated. + * The caller provides the identity received and wants to + * receive the actual PSK data and length. + * + * The callback has the following parameters: (void *parameter, + * mbedtls_ssl_context *ssl, const unsigned char *psk_identity, + * size_t identity_len) + * If a valid PSK identity is found, the callback should use + * \c mbedtls_ssl_set_hs_psk() on the ssl context to set the + * correct PSK and return 0. + * Any other return value will result in a denied PSK identity. + * + * \note If you set a PSK callback using this function, then you + * don't need to set a PSK key and identity using + * \c mbedtls_ssl_conf_psk(). + * + * \param conf SSL configuration + * \param f_psk PSK identity function + * \param p_psk PSK identity parameter + */ +void mbedtls_ssl_conf_psk_cb( mbedtls_ssl_config *conf, + int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, + size_t), + void *p_psk ); +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) +/** + * \brief Set the Diffie-Hellman public P and G values, + * read as hexadecimal strings (server-side only) + * (Default: MBEDTLS_DHM_RFC5114_MODP_2048_[PG]) + * + * \param conf SSL configuration + * \param dhm_P Diffie-Hellman-Merkle modulus + * \param dhm_G Diffie-Hellman-Merkle generator + * + * \return 0 if successful + */ +int mbedtls_ssl_conf_dh_param( mbedtls_ssl_config *conf, const char *dhm_P, const char *dhm_G ); + +/** + * \brief Set the Diffie-Hellman public P and G values, + * read from existing context (server-side only) + * + * \param conf SSL configuration + * \param dhm_ctx Diffie-Hellman-Merkle context + * + * \return 0 if successful + */ +int mbedtls_ssl_conf_dh_param_ctx( mbedtls_ssl_config *conf, mbedtls_dhm_context *dhm_ctx ); +#endif /* MBEDTLS_DHM_C && defined(MBEDTLS_SSL_SRV_C) */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Set the minimum length for Diffie-Hellman parameters. + * (Client-side only.) + * (Default: 1024 bits.) + * + * \param conf SSL configuration + * \param bitlen Minimum bit length of the DHM prime + */ +void mbedtls_ssl_conf_dhm_min_bitlen( mbedtls_ssl_config *conf, + unsigned int bitlen ); +#endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_ECP_C) +/** + * \brief Set the allowed curves in order of preference. + * (Default: all defined curves.) + * + * On server: this only affects selection of the ECDHE curve; + * the curves used for ECDH and ECDSA are determined by the + * list of available certificates instead. + * + * On client: this affects the list of curves offered for any + * use. The server can override our preference order. + * + * Both sides: limits the set of curves accepted for use in + * ECDHE and in the peer's end-entity certificate. + * + * \note This has no influence on which curves are allowed inside the + * certificate chains, see \c mbedtls_ssl_conf_cert_profile() + * for that. For the end-entity certificate however, the key + * will be accepted only if it is allowed both by this list + * and by the cert profile. + * + * \note This list should be ordered by decreasing preference + * (preferred curve first). + * + * \param conf SSL configuration + * \param curves Ordered list of allowed curves, + * terminated by MBEDTLS_ECP_DP_NONE. + */ +void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf, + const mbedtls_ecp_group_id *curves ); +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +/** + * \brief Set the allowed hashes for signatures during the handshake. + * (Default: all available hashes except MD5.) + * + * \note This only affects which hashes are offered and can be used + * for signatures during the handshake. Hashes for message + * authentication and the TLS PRF are controlled by the + * ciphersuite, see \c mbedtls_ssl_conf_ciphersuites(). Hashes + * used for certificate signature are controlled by the + * verification profile, see \c mbedtls_ssl_conf_cert_profile(). + * + * \note This list should be ordered by decreasing preference + * (preferred hash first). + * + * \param conf SSL configuration + * \param hashes Ordered list of allowed signature hashes, + * terminated by \c MBEDTLS_MD_NONE. + */ +void mbedtls_ssl_conf_sig_hashes( mbedtls_ssl_config *conf, + const int *hashes ); +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Set the hostname to check against the received server + * certificate. It sets the ServerName TLS extension too, + * if the extension is enabled. + * (client-side only) + * + * \param ssl SSL context + * \param hostname the server hostname + * + * \return 0 if successful or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +/** + * \brief Set own certificate and key for the current handshake + * + * \note Same as \c mbedtls_ssl_conf_own_cert() but for use within + * the SNI callback. + * + * \param ssl SSL context + * \param own_cert own public certificate chain + * \param pk_key own private key + * + * \return 0 on success or MBEDTLS_ERR_SSL_ALLOC_FAILED + */ +int mbedtls_ssl_set_hs_own_cert( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ); + +/** + * \brief Set the data required to verify peer certificate for the + * current handshake + * + * \note Same as \c mbedtls_ssl_conf_ca_chain() but for use within + * the SNI callback. + * + * \param ssl SSL context + * \param ca_chain trusted CA chain (meaning all fully trusted top-level CAs) + * \param ca_crl trusted CA CRLs + */ +void mbedtls_ssl_set_hs_ca_chain( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ); + +/** + * \brief Set authmode for the current handshake. + * + * \note Same as \c mbedtls_ssl_conf_authmode() but for use within + * the SNI callback. + * + * \param ssl SSL context + * \param authmode MBEDTLS_SSL_VERIFY_NONE, MBEDTLS_SSL_VERIFY_OPTIONAL or + * MBEDTLS_SSL_VERIFY_REQUIRED + */ +void mbedtls_ssl_set_hs_authmode( mbedtls_ssl_context *ssl, + int authmode ); + +/** + * \brief Set server side ServerName TLS extension callback + * (optional, server-side only). + * + * If set, the ServerName callback is called whenever the + * server receives a ServerName TLS extension from the client + * during a handshake. The ServerName callback has the + * following parameters: (void *parameter, mbedtls_ssl_context *ssl, + * const unsigned char *hostname, size_t len). If a suitable + * certificate is found, the callback must set the + * certificate(s) and key(s) to use with \c + * mbedtls_ssl_set_hs_own_cert() (can be called repeatedly), + * and may optionally adjust the CA and associated CRL with \c + * mbedtls_ssl_set_hs_ca_chain() as well as the client + * authentication mode with \c mbedtls_ssl_set_hs_authmode(), + * then must return 0. If no matching name is found, the + * callback must either set a default cert, or + * return non-zero to abort the handshake at this point. + * + * \param conf SSL configuration + * \param f_sni verification function + * \param p_sni verification parameter + */ +void mbedtls_ssl_conf_sni( mbedtls_ssl_config *conf, + int (*f_sni)(void *, mbedtls_ssl_context *, const unsigned char *, + size_t), + void *p_sni ); +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +/** + * \brief Set the EC J-PAKE password for current handshake. + * + * \note An internal copy is made, and destroyed as soon as the + * handshake is completed, or when the SSL context is reset or + * freed. + * + * \note The SSL context needs to be already set up. The right place + * to call this function is between \c mbedtls_ssl_setup() or + * \c mbedtls_ssl_reset() and \c mbedtls_ssl_handshake(). + * + * \param ssl SSL context + * \param pw EC J-PAKE password (pre-shared secret) + * \param pw_len length of pw in bytes + * + * \return 0 on success, or a negative error code. + */ +int mbedtls_ssl_set_hs_ecjpake_password( mbedtls_ssl_context *ssl, + const unsigned char *pw, + size_t pw_len ); +#endif /*MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN) +/** + * \brief Set the supported Application Layer Protocols. + * + * \param conf SSL configuration + * \param protos Pointer to a NULL-terminated list of supported protocols, + * in decreasing preference order. The pointer to the list is + * recorded by the library for later reference as required, so + * the lifetime of the table must be atleast as long as the + * lifetime of the SSL configuration structure. + * + * \return 0 on success, or MBEDTLS_ERR_SSL_BAD_INPUT_DATA. + */ +int mbedtls_ssl_conf_alpn_protocols( mbedtls_ssl_config *conf, const char **protos ); + +/** + * \brief Get the name of the negotiated Application Layer Protocol. + * This function should be called after the handshake is + * completed. + * + * \param ssl SSL context + * + * \return Protcol name, or NULL if no protocol was negotiated. + */ +const char *mbedtls_ssl_get_alpn_protocol( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_ALPN */ + +/** + * \brief Set the maximum supported version sent from the client side + * and/or accepted at the server side + * (Default: MBEDTLS_SSL_MAX_MAJOR_VERSION, MBEDTLS_SSL_MAX_MINOR_VERSION) + * + * \note This ignores ciphersuites from higher versions. + * + * \note With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0 and + * MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2 + * + * \param conf SSL configuration + * \param major Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 supported) + * \param minor Minor version number (MBEDTLS_SSL_MINOR_VERSION_0, + * MBEDTLS_SSL_MINOR_VERSION_1 and MBEDTLS_SSL_MINOR_VERSION_2, + * MBEDTLS_SSL_MINOR_VERSION_3 supported) + */ +void mbedtls_ssl_conf_max_version( mbedtls_ssl_config *conf, int major, int minor ); + +/** + * \brief Set the minimum accepted SSL/TLS protocol version + * (Default: TLS 1.0) + * + * \note Input outside of the SSL_MAX_XXXXX_VERSION and + * SSL_MIN_XXXXX_VERSION range is ignored. + * + * \note MBEDTLS_SSL_MINOR_VERSION_0 (SSL v3) should be avoided. + * + * \note With DTLS, use MBEDTLS_SSL_MINOR_VERSION_2 for DTLS 1.0 and + * MBEDTLS_SSL_MINOR_VERSION_3 for DTLS 1.2 + * + * \param conf SSL configuration + * \param major Major version number (only MBEDTLS_SSL_MAJOR_VERSION_3 supported) + * \param minor Minor version number (MBEDTLS_SSL_MINOR_VERSION_0, + * MBEDTLS_SSL_MINOR_VERSION_1 and MBEDTLS_SSL_MINOR_VERSION_2, + * MBEDTLS_SSL_MINOR_VERSION_3 supported) + */ +void mbedtls_ssl_conf_min_version( mbedtls_ssl_config *conf, int major, int minor ); + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Set the fallback flag (client-side only). + * (Default: MBEDTLS_SSL_IS_NOT_FALLBACK). + * + * \note Set to MBEDTLS_SSL_IS_FALLBACK when preparing a fallback + * connection, that is a connection with max_version set to a + * lower value than the value you're willing to use. Such + * fallback connections are not recommended but are sometimes + * necessary to interoperate with buggy (version-intolerant) + * servers. + * + * \warning You should NOT set this to MBEDTLS_SSL_IS_FALLBACK for + * non-fallback connections! This would appear to work for a + * while, then cause failures when the server is upgraded to + * support a newer TLS version. + * + * \param conf SSL configuration + * \param fallback MBEDTLS_SSL_IS_NOT_FALLBACK or MBEDTLS_SSL_IS_FALLBACK + */ +void mbedtls_ssl_conf_fallback( mbedtls_ssl_config *conf, char fallback ); +#endif /* MBEDTLS_SSL_FALLBACK_SCSV && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +/** + * \brief Enable or disable Encrypt-then-MAC + * (Default: MBEDTLS_SSL_ETM_ENABLED) + * + * \note This should always be enabled, it is a security + * improvement, and should not cause any interoperability + * issue (used only if the peer supports it too). + * + * \param conf SSL configuration + * \param etm MBEDTLS_SSL_ETM_ENABLED or MBEDTLS_SSL_ETM_DISABLED + */ +void mbedtls_ssl_conf_encrypt_then_mac( mbedtls_ssl_config *conf, char etm ); +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +/** + * \brief Enable or disable Extended Master Secret negotiation. + * (Default: MBEDTLS_SSL_EXTENDED_MS_ENABLED) + * + * \note This should always be enabled, it is a security fix to the + * protocol, and should not cause any interoperability issue + * (used only if the peer supports it too). + * + * \param conf SSL configuration + * \param ems MBEDTLS_SSL_EXTENDED_MS_ENABLED or MBEDTLS_SSL_EXTENDED_MS_DISABLED + */ +void mbedtls_ssl_conf_extended_master_secret( mbedtls_ssl_config *conf, char ems ); +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_ARC4_C) +/** + * \brief Disable or enable support for RC4 + * (Default: MBEDTLS_SSL_ARC4_DISABLED) + * + * \warning Use of RC4 in DTLS/TLS has been prohibited by RFC 7465 + * for security reasons. Use at your own risk. + * + * \note This function is deprecated and will likely be removed in + * a future version of the library. + * RC4 is disabled by default at compile time and needs to be + * actively enabled for use with legacy systems. + * + * \param conf SSL configuration + * \param arc4 MBEDTLS_SSL_ARC4_ENABLED or MBEDTLS_SSL_ARC4_DISABLED + */ +void mbedtls_ssl_conf_arc4_support( mbedtls_ssl_config *conf, char arc4 ); +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +/** + * \brief Set the maximum fragment length to emit and/or negotiate + * (Default: MBEDTLS_SSL_MAX_CONTENT_LEN, usually 2^14 bytes) + * (Server: set maximum fragment length to emit, + * usually negotiated by the client during handshake + * (Client: set maximum fragment length to emit *and* + * negotiate with the server during handshake) + * + * \param conf SSL configuration + * \param mfl_code Code for maximum fragment length (allowed values: + * MBEDTLS_SSL_MAX_FRAG_LEN_512, MBEDTLS_SSL_MAX_FRAG_LEN_1024, + * MBEDTLS_SSL_MAX_FRAG_LEN_2048, MBEDTLS_SSL_MAX_FRAG_LEN_4096) + * + * \return 0 if successful or MBEDTLS_ERR_SSL_BAD_INPUT_DATA + */ +int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *conf, unsigned char mfl_code ); +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +/** + * \brief Activate negotiation of truncated HMAC + * (Default: MBEDTLS_SSL_TRUNC_HMAC_DISABLED) + * + * \param conf SSL configuration + * \param truncate Enable or disable (MBEDTLS_SSL_TRUNC_HMAC_ENABLED or + * MBEDTLS_SSL_TRUNC_HMAC_DISABLED) + */ +void mbedtls_ssl_conf_truncated_hmac( mbedtls_ssl_config *conf, int truncate ); +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) +/** + * \brief Enable / Disable 1/n-1 record splitting + * (Default: MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED) + * + * \note Only affects SSLv3 and TLS 1.0, not higher versions. + * Does not affect non-CBC ciphersuites in any version. + * + * \param conf SSL configuration + * \param split MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED or + * MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED + */ +void mbedtls_ssl_conf_cbc_record_splitting( mbedtls_ssl_config *conf, char split ); +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Enable / Disable session tickets (client only). + * (Default: MBEDTLS_SSL_SESSION_TICKETS_ENABLED.) + * + * \note On server, use \c mbedtls_ssl_conf_session_tickets_cb(). + * + * \param conf SSL configuration + * \param use_tickets Enable or disable (MBEDTLS_SSL_SESSION_TICKETS_ENABLED or + * MBEDTLS_SSL_SESSION_TICKETS_DISABLED) + */ +void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ); +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +/** + * \brief Enable / Disable renegotiation support for connection when + * initiated by peer + * (Default: MBEDTLS_SSL_RENEGOTIATION_DISABLED) + * + * \warning It is recommended to always disable renegotation unless you + * know you need it and you know what you're doing. In the + * past, there have been several issues associated with + * renegotiation or a poor understanding of its properties. + * + * \note Server-side, enabling renegotiation also makes the server + * susceptible to a resource DoS by a malicious client. + * + * \param conf SSL configuration + * \param renegotiation Enable or disable (MBEDTLS_SSL_RENEGOTIATION_ENABLED or + * MBEDTLS_SSL_RENEGOTIATION_DISABLED) + */ +void mbedtls_ssl_conf_renegotiation( mbedtls_ssl_config *conf, int renegotiation ); +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/** + * \brief Prevent or allow legacy renegotiation. + * (Default: MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION) + * + * MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION allows connections to + * be established even if the peer does not support + * secure renegotiation, but does not allow renegotiation + * to take place if not secure. + * (Interoperable and secure option) + * + * MBEDTLS_SSL_LEGACY_ALLOW_RENEGOTIATION allows renegotiations + * with non-upgraded peers. Allowing legacy renegotiation + * makes the connection vulnerable to specific man in the + * middle attacks. (See RFC 5746) + * (Most interoperable and least secure option) + * + * MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE breaks off connections + * if peer does not support secure renegotiation. Results + * in interoperability issues with non-upgraded peers + * that do not support renegotiation altogether. + * (Most secure option, interoperability issues) + * + * \param conf SSL configuration + * \param allow_legacy Prevent or allow (SSL_NO_LEGACY_RENEGOTIATION, + * SSL_ALLOW_LEGACY_RENEGOTIATION or + * MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE) + */ +void mbedtls_ssl_conf_legacy_renegotiation( mbedtls_ssl_config *conf, int allow_legacy ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +/** + * \brief Enforce renegotiation requests. + * (Default: enforced, max_records = 16) + * + * When we request a renegotiation, the peer can comply or + * ignore the request. This function allows us to decide + * whether to enforce our renegotiation requests by closing + * the connection if the peer doesn't comply. + * + * However, records could already be in transit from the peer + * when the request is emitted. In order to increase + * reliability, we can accept a number of records before the + * expected handshake records. + * + * The optimal value is highly dependent on the specific usage + * scenario. + * + * \note With DTLS and server-initiated renegotiation, the + * HelloRequest is retransmited every time mbedtls_ssl_read() times + * out or receives Application Data, until: + * - max_records records have beens seen, if it is >= 0, or + * - the number of retransmits that would happen during an + * actual handshake has been reached. + * Please remember the request might be lost a few times + * if you consider setting max_records to a really low value. + * + * \warning On client, the grace period can only happen during + * mbedtls_ssl_read(), as opposed to mbedtls_ssl_write() and mbedtls_ssl_renegotiate() + * which always behave as if max_record was 0. The reason is, + * if we receive application data from the server, we need a + * place to write it, which only happens during mbedtls_ssl_read(). + * + * \param conf SSL configuration + * \param max_records Use MBEDTLS_SSL_RENEGOTIATION_NOT_ENFORCED if you don't want to + * enforce renegotiation, or a non-negative value to enforce + * it but allow for a grace period of max_records records. + */ +void mbedtls_ssl_conf_renegotiation_enforced( mbedtls_ssl_config *conf, int max_records ); + +/** + * \brief Set record counter threshold for periodic renegotiation. + * (Default: 2^48 - 1) + * + * Renegotiation is automatically triggered when a record + * counter (outgoing or ingoing) crosses the defined + * threshold. The default value is meant to prevent the + * connection from being closed when the counter is about to + * reached its maximal value (it is not allowed to wrap). + * + * Lower values can be used to enforce policies such as "keys + * must be refreshed every N packets with cipher X". + * + * The renegotiation period can be disabled by setting + * conf->disable_renegotiation to + * MBEDTLS_SSL_RENEGOTIATION_DISABLED. + * + * \note When the configured transport is + * MBEDTLS_SSL_TRANSPORT_DATAGRAM the maximum renegotiation + * period is 2^48 - 1, and for MBEDTLS_SSL_TRANSPORT_STREAM, + * the maximum renegotiation period is 2^64 - 1. + * + * \param conf SSL configuration + * \param period The threshold value: a big-endian 64-bit number. + */ +void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, + const unsigned char period[8] ); +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/** + * \brief Return the number of data bytes available to read + * + * \param ssl SSL context + * + * \return how many bytes are available in the read buffer + */ +size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the result of the certificate verification + * + * \param ssl SSL context + * + * \return 0 if successful, + * -1 if result is not available (eg because the handshake was + * aborted too early), or + * a combination of BADCERT_xxx and BADCRL_xxx flags, see + * x509.h + */ +uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the name of the current ciphersuite + * + * \param ssl SSL context + * + * \return a string containing the ciphersuite name + */ +const char *mbedtls_ssl_get_ciphersuite( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the current SSL version (SSLv3/TLSv1/etc) + * + * \param ssl SSL context + * + * \return a string containing the SSL version + */ +const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ); + +/** + * \brief Return the (maximum) number of bytes added by the record + * layer: header + encryption/MAC overhead (inc. padding) + * + * \param ssl SSL context + * + * \return Current maximum record expansion in bytes, or + * MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE if compression is + * enabled, which makes expansion much less predictable + */ +int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +/** + * \brief Return the maximum fragment length (payload, in bytes). + * This is the value negotiated with peer if any, + * or the locally configured value. + * + * \note With DTLS, \c mbedtls_ssl_write() will return an error if + * called with a larger length value. + * With TLS, \c mbedtls_ssl_write() will fragment the input if + * necessary and return the number of bytes written; it is up + * to the caller to call \c mbedtls_ssl_write() again in + * order to send the remaining bytes if any. + * + * \param ssl SSL context + * + * \return Current maximum fragment length. + */ +size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * \brief Return the peer certificate from the current connection + * + * Note: Can be NULL in case no certificate was sent during + * the handshake. Different calls for the same connection can + * return the same or different pointers for the same + * certificate and even a different certificate altogether. + * The peer cert CAN change in a single connection if + * renegotiation is performed. + * + * \param ssl SSL context + * + * \return the current peer certificate + */ +const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +/** + * \brief Save session in order to resume it later (client-side only) + * Session data is copied to presented session structure. + * + * \warning Currently, peer certificate is lost in the operation. + * + * \param ssl SSL context + * \param session session context + * + * \return 0 if successful, + * MBEDTLS_ERR_SSL_ALLOC_FAILED if memory allocation failed, + * MBEDTLS_ERR_SSL_BAD_INPUT_DATA if used server-side or + * arguments are otherwise invalid + * + * \sa mbedtls_ssl_set_session() + */ +int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session *session ); +#endif /* MBEDTLS_SSL_CLI_C */ + +/** + * \brief Perform the SSL handshake + * + * \param ssl SSL context + * + * \return 0 if successful, or + * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or + * MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED (see below), or + * a specific SSL error code. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + * + * \note If DTLS is in use, then you may choose to handle + * MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED specially for logging + * purposes, as it is an expected return value rather than an + * actual error, but you still need to reset/free the context. + */ +int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl ); + +/** + * \brief Perform a single step of the SSL handshake + * + * \note The state of the context (ssl->state) will be at + * the next state after execution of this function. Do not + * call this function if state is MBEDTLS_SSL_HANDSHAKE_OVER. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + * + * \param ssl SSL context + * + * \return 0 if successful, or + * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or + * a specific SSL error code. + */ +int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +/** + * \brief Initiate an SSL renegotiation on the running connection. + * Client: perform the renegotiation right now. + * Server: request renegotiation, which will be performed + * during the next call to mbedtls_ssl_read() if honored by + * client. + * + * \param ssl SSL context + * + * \return 0 if successful, or any mbedtls_ssl_handshake() return + * value. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + */ +int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl ); +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/** + * \brief Read at most 'len' application data bytes + * + * \param ssl SSL context + * \param buf buffer that will hold the data + * \param len maximum number of bytes to read + * + * \return the number of bytes read, or + * 0 for EOF, or + * MBEDTLS_ERR_SSL_WANT_READ or MBEDTLS_ERR_SSL_WANT_WRITE, or + * MBEDTLS_ERR_SSL_CLIENT_RECONNECT (see below), or + * another negative error code. + * + * \note If this function returns something other than a positive + * value or MBEDTLS_ERR_SSL_WANT_READ/WRITE or + * MBEDTLS_ERR_SSL_CLIENT_RECONNECT, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + * + * \note When this function return MBEDTLS_ERR_SSL_CLIENT_RECONNECT + * (which can only happen server-side), it means that a client + * is initiating a new connection using the same source port. + * You can either treat that as a connection close and wait + * for the client to resend a ClientHello, or directly + * continue with \c mbedtls_ssl_handshake() with the same + * context (as it has beeen reset internally). Either way, you + * should make sure this is seen by the application as a new + * connection: application state, if any, should be reset, and + * most importantly the identity of the client must be checked + * again. WARNING: not validating the identity of the client + * again, or not transmitting the new identity to the + * application layer, would allow authentication bypass! + */ +int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ); + +/** + * \brief Try to write exactly 'len' application data bytes + * + * \warning This function will do partial writes in some cases. If the + * return value is non-negative but less than length, the + * function must be called again with updated arguments: + * buf + ret, len - ret (if ret is the return value) until + * it returns a value equal to the last 'len' argument. + * + * \param ssl SSL context + * \param buf buffer holding the data + * \param len how many bytes must be written + * + * \return the number of bytes actually written (may be less than len), + * or MBEDTLS_ERR_SSL_WANT_WRITE or MBEDTLS_ERR_SSL_WANT_READ, + * or another negative error code. + * + * \note If this function returns something other than a positive + * value or MBEDTLS_ERR_SSL_WANT_READ/WRITE, the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + * + * \note When this function returns MBEDTLS_ERR_SSL_WANT_WRITE/READ, + * it must be called later with the *same* arguments, + * until it returns a positive value. + * + * \note If the requested length is greater than the maximum + * fragment length (either the built-in limit or the one set + * or negotiated with the peer), then: + * - with TLS, less bytes than requested are written. + * - with DTLS, MBEDTLS_ERR_SSL_BAD_INPUT_DATA is returned. + * \c mbedtls_ssl_get_max_frag_len() may be used to query the + * active maximum fragment length. + */ +int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ); + +/** + * \brief Send an alert message + * + * \param ssl SSL context + * \param level The alert level of the message + * (MBEDTLS_SSL_ALERT_LEVEL_WARNING or MBEDTLS_SSL_ALERT_LEVEL_FATAL) + * \param message The alert message (SSL_ALERT_MSG_*) + * + * \return 0 if successful, or a specific SSL error code. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + */ +int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, + unsigned char level, + unsigned char message ); +/** + * \brief Notify the peer that the connection is being closed + * + * \param ssl SSL context + * + * \return 0 if successful, or a specific SSL error code. + * + * \note If this function returns something other than 0 or + * MBEDTLS_ERR_SSL_WANT_READ/WRITE, then the ssl context + * becomes unusable, and you should either free it or call + * \c mbedtls_ssl_session_reset() on it before re-using it for + * a new connection; the current connection must be closed. + */ +int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl ); + +/** + * \brief Free referenced items in an SSL context and clear memory + * + * \param ssl SSL context + */ +void mbedtls_ssl_free( mbedtls_ssl_context *ssl ); + +/** + * \brief Initialize an SSL configuration context + * Just makes the context ready for + * mbedtls_ssl_config_defaults() or mbedtls_ssl_config_free(). + * + * \note You need to call mbedtls_ssl_config_defaults() unless you + * manually set all of the relevent fields yourself. + * + * \param conf SSL configuration context + */ +void mbedtls_ssl_config_init( mbedtls_ssl_config *conf ); + +/** + * \brief Load reasonnable default SSL configuration values. + * (You need to call mbedtls_ssl_config_init() first.) + * + * \param conf SSL configuration context + * \param endpoint MBEDTLS_SSL_IS_CLIENT or MBEDTLS_SSL_IS_SERVER + * \param transport MBEDTLS_SSL_TRANSPORT_STREAM for TLS, or + * MBEDTLS_SSL_TRANSPORT_DATAGRAM for DTLS + * \param preset a MBEDTLS_SSL_PRESET_XXX value + * + * \note See \c mbedtls_ssl_conf_transport() for notes on DTLS. + * + * \return 0 if successful, or + * MBEDTLS_ERR_XXX_ALLOC_FAILED on memory allocation error. + */ +int mbedtls_ssl_config_defaults( mbedtls_ssl_config *conf, + int endpoint, int transport, int preset ); + +/** + * \brief Free an SSL configuration context + * + * \param conf SSL configuration context + */ +void mbedtls_ssl_config_free( mbedtls_ssl_config *conf ); + +/** + * \brief Initialize SSL session structure + * + * \param session SSL session + */ +void mbedtls_ssl_session_init( mbedtls_ssl_session *session ); + +/** + * \brief Free referenced items in an SSL session including the + * peer certificate and clear memory + * + * \param session SSL session + */ +void mbedtls_ssl_session_free( mbedtls_ssl_session *session ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ssl_cache.h b/c++/src/connect/mbedtls/mbedtls/ssl_cache.h new file mode 100644 index 00000000..3734bb72 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ssl_cache.h @@ -0,0 +1,143 @@ +/** + * \file ssl_cache.h + * + * \brief SSL session cache implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_CACHE_H +#define MBEDTLS_SSL_CACHE_H + +#include "ssl.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ + +#if !defined(MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT) +#define MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT 86400 /*!< 1 day */ +#endif + +#if !defined(MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES) +#define MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /*!< Maximum entries in cache */ +#endif + +/* \} name SECTION: Module settings */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct mbedtls_ssl_cache_context mbedtls_ssl_cache_context; +typedef struct mbedtls_ssl_cache_entry mbedtls_ssl_cache_entry; + +/** + * \brief This structure is used for storing cache entries + */ +struct mbedtls_ssl_cache_entry +{ +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t timestamp; /*!< entry timestamp */ +#endif + mbedtls_ssl_session session; /*!< entry session */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_x509_buf peer_cert; /*!< entry peer_cert */ +#endif + mbedtls_ssl_cache_entry *next; /*!< chain pointer */ +}; + +/** + * \brief Cache context + */ +struct mbedtls_ssl_cache_context +{ + mbedtls_ssl_cache_entry *chain; /*!< start of the chain */ + int timeout; /*!< cache entry timeout */ + int max_entries; /*!< maximum entries */ +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; /*!< mutex */ +#endif +}; + +/** + * \brief Initialize an SSL cache context + * + * \param cache SSL cache context + */ +void mbedtls_ssl_cache_init( mbedtls_ssl_cache_context *cache ); + +/** + * \brief Cache get callback implementation + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param data SSL cache context + * \param session session to retrieve entry for + */ +int mbedtls_ssl_cache_get( void *data, mbedtls_ssl_session *session ); + +/** + * \brief Cache set callback implementation + * (Thread-safe if MBEDTLS_THREADING_C is enabled) + * + * \param data SSL cache context + * \param session session to store entry for + */ +int mbedtls_ssl_cache_set( void *data, const mbedtls_ssl_session *session ); + +#if defined(MBEDTLS_HAVE_TIME) +/** + * \brief Set the cache timeout + * (Default: MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT (1 day)) + * + * A timeout of 0 indicates no timeout. + * + * \param cache SSL cache context + * \param timeout cache entry timeout in seconds + */ +void mbedtls_ssl_cache_set_timeout( mbedtls_ssl_cache_context *cache, int timeout ); +#endif /* MBEDTLS_HAVE_TIME */ + +/** + * \brief Set the maximum number of cache entries + * (Default: MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES (50)) + * + * \param cache SSL cache context + * \param max cache entry maximum + */ +void mbedtls_ssl_cache_set_max_entries( mbedtls_ssl_cache_context *cache, int max ); + +/** + * \brief Free referenced items in a cache context and clear memory + * + * \param cache SSL cache context + */ +void mbedtls_ssl_cache_free( mbedtls_ssl_cache_context *cache ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_cache.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ssl_ciphersuites.h b/c++/src/connect/mbedtls/mbedtls/ssl_ciphersuites.h new file mode 100644 index 00000000..deaaa375 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ssl_ciphersuites.h @@ -0,0 +1,321 @@ +/** + * \file ssl_ciphersuites.h + * + * \brief SSL Ciphersuites for mbed TLS + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_CIPHERSUITES_H +#define MBEDTLS_SSL_CIPHERSUITES_H + +#include "pk.h" +#include "cipher.h" +#include "md.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Supported ciphersuites (Official IANA names) + */ +#define MBEDTLS_TLS_RSA_WITH_NULL_MD5 0x01 /**< Weak! */ +#define MBEDTLS_TLS_RSA_WITH_NULL_SHA 0x02 /**< Weak! */ + +#define MBEDTLS_TLS_RSA_WITH_RC4_128_MD5 0x04 +#define MBEDTLS_TLS_RSA_WITH_RC4_128_SHA 0x05 +#define MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA 0x09 /**< Weak! Not in TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x0A + +#define MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA 0x15 /**< Weak! Not in TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x16 + +#define MBEDTLS_TLS_PSK_WITH_NULL_SHA 0x2C /**< Weak! */ +#define MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA 0x2D /**< Weak! */ +#define MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA 0x2E /**< Weak! */ +#define MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA 0x2F + +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x33 +#define MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA 0x35 +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x39 + +#define MBEDTLS_TLS_RSA_WITH_NULL_SHA256 0x3B /**< Weak! */ +#define MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256 0x3C /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256 0x3D /**< TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA 0x41 +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA 0x45 + +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x67 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x6B /**< TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA 0x84 +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA 0x88 + +#define MBEDTLS_TLS_PSK_WITH_RC4_128_SHA 0x8A +#define MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA 0x8B +#define MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA 0x8C +#define MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA 0x8D + +#define MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA 0x8E +#define MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA 0x8F +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA 0x90 +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA 0x91 + +#define MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA 0x92 +#define MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA 0x93 +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA 0x94 +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA 0x95 + +#define MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256 0x9C /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384 0x9D /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x9E /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x9F /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256 0xA8 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384 0xA9 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 0xAA /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 0xAB /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 0xAC /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 0xAD /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256 0xAE +#define MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384 0xAF +#define MBEDTLS_TLS_PSK_WITH_NULL_SHA256 0xB0 /**< Weak! */ +#define MBEDTLS_TLS_PSK_WITH_NULL_SHA384 0xB1 /**< Weak! */ + +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 0xB2 +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 0xB3 +#define MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256 0xB4 /**< Weak! */ +#define MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384 0xB5 /**< Weak! */ + +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 0xB6 +#define MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 0xB7 +#define MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256 0xB8 /**< Weak! */ +#define MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384 0xB9 /**< Weak! */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xBA /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xBE /**< TLS 1.2 */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 0xC0 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 0xC4 /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001 /**< Weak! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005 /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006 /**< Weak! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 0xC007 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC008 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B /**< Weak! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA 0xC00C /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0xC00D /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010 /**< Weak! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA 0xC011 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014 /**< Not in SSL3! */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 0xC025 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 0xC026 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 0xC028 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 0xC029 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 0xC02A /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0xC02E /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 0xC032 /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA 0xC033 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA 0xC034 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA 0xC035 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA 0xC036 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 0xC037 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 0xC038 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA 0xC039 /**< Weak! No SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256 0xC03A /**< Weak! No SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384 0xC03B /**< Weak! No SSL3! */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0xC072 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0xC073 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 0xC074 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 0xC075 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xC076 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 0xC077 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 0xC078 /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 0xC079 /**< Not in SSL3! */ + +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC07A /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC07B /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC07C /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC07D /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 0xC086 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 0xC087 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 0xC088 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 0xC089 /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC08A /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC08B /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 0xC08C /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 0xC08D /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC08E /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC08F /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC090 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC091 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 0xC092 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 0xC093 /**< TLS 1.2 */ + +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC094 +#define MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC095 +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC096 +#define MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC097 +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC098 +#define MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC099 +#define MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 0xC09A /**< Not in SSL3! */ +#define MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 0xC09B /**< Not in SSL3! */ + +#define MBEDTLS_TLS_RSA_WITH_AES_128_CCM 0xC09C /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_CCM 0xC09D /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM 0xC09E /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM 0xC09F /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8 0xC0A0 /**< TLS 1.2 */ +#define MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8 0xC0A1 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8 0xC0A2 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8 0xC0A3 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_128_CCM 0xC0A4 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_256_CCM 0xC0A5 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM 0xC0A6 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM 0xC0A7 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8 0xC0A8 /**< TLS 1.2 */ +#define MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8 0xC0A9 /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8 0xC0AA /**< TLS 1.2 */ +#define MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8 0xC0AB /**< TLS 1.2 */ +/* The last two are named with PSK_DHE in the RFC, which looks like a typo */ + +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM 0xC0AC /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM 0xC0AD /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE /**< TLS 1.2 */ +#define MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 0xC0AF /**< TLS 1.2 */ + +#define MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 0xC0FF /**< experimental */ + +/* Reminder: update mbedtls_ssl_premaster_secret when adding a new key exchange. + * Reminder: update MBEDTLS_KEY_EXCHANGE__xxx below + */ +typedef enum { + MBEDTLS_KEY_EXCHANGE_NONE = 0, + MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_KEY_EXCHANGE_ECJPAKE, +} mbedtls_key_exchange_type_t; + +/* Key exchanges using a certificate */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED +#endif + +/* Key exchanges using a PSK */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED +#endif + +/* Key exchanges using a ECDHE */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#define MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED +#endif + +typedef struct mbedtls_ssl_ciphersuite_t mbedtls_ssl_ciphersuite_t; + +#define MBEDTLS_CIPHERSUITE_WEAK 0x01 /**< Weak ciphersuite flag */ +#define MBEDTLS_CIPHERSUITE_SHORT_TAG 0x02 /**< Short authentication tag, + eg for CCM_8 */ +#define MBEDTLS_CIPHERSUITE_NODTLS 0x04 /**< Can't be used with DTLS */ + +/** + * \brief This structure is used for storing ciphersuite information + */ +struct mbedtls_ssl_ciphersuite_t +{ + int id; + const char * name; + + mbedtls_cipher_type_t cipher; + mbedtls_md_type_t mac; + mbedtls_key_exchange_type_t key_exchange; + + int min_major_ver; + int min_minor_ver; + int max_major_ver; + int max_minor_ver; + + unsigned char flags; +}; + +const int *mbedtls_ssl_list_ciphersuites( void ); + +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_string( const char *ciphersuite_name ); +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_id( int ciphersuite_id ); + +#if defined(MBEDTLS_PK_C) +mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info ); +#endif + +int mbedtls_ssl_ciphersuite_uses_ec( const mbedtls_ssl_ciphersuite_t *info ); +int mbedtls_ssl_ciphersuite_uses_psk( const mbedtls_ssl_ciphersuite_t *info ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_ciphersuites.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ssl_cookie.h b/c++/src/connect/mbedtls/mbedtls/ssl_cookie.h new file mode 100644 index 00000000..037e1c31 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ssl_cookie.h @@ -0,0 +1,108 @@ +/** + * \file ssl_cookie.h + * + * \brief DTLS cookie callbacks implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_COOKIE_H +#define MBEDTLS_SSL_COOKIE_H + +#include "ssl.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +/** + * \name SECTION: Module settings + * + * The configuration options you can set for this module are in this section. + * Either change them in config.h or define them on the compiler command line. + * \{ + */ +#ifndef MBEDTLS_SSL_COOKIE_TIMEOUT +#define MBEDTLS_SSL_COOKIE_TIMEOUT 60 /**< Default expiration delay of DTLS cookies, in seconds if HAVE_TIME, or in number of cookies issued */ +#endif + +/* \} name SECTION: Module settings */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Context for the default cookie functions. + */ +typedef struct +{ + mbedtls_md_context_t hmac_ctx; /*!< context for the HMAC portion */ +#if !defined(MBEDTLS_HAVE_TIME) + unsigned long serial; /*!< serial number for expiration */ +#endif + unsigned long timeout; /*!< timeout delay, in seconds if HAVE_TIME, + or in number of tickets issued */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} mbedtls_ssl_cookie_ctx; + +/** + * \brief Initialize cookie context + */ +void mbedtls_ssl_cookie_init( mbedtls_ssl_cookie_ctx *ctx ); + +/** + * \brief Setup cookie context (generate keys) + */ +int mbedtls_ssl_cookie_setup( mbedtls_ssl_cookie_ctx *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +/** + * \brief Set expiration delay for cookies + * (Default MBEDTLS_SSL_COOKIE_TIMEOUT) + * + * \param ctx Cookie contex + * \param delay Delay, in seconds if HAVE_TIME, or in number of cookies + * issued in the meantime. + * 0 to disable expiration (NOT recommended) + */ +void mbedtls_ssl_cookie_set_timeout( mbedtls_ssl_cookie_ctx *ctx, unsigned long delay ); + +/** + * \brief Free cookie context + */ +void mbedtls_ssl_cookie_free( mbedtls_ssl_cookie_ctx *ctx ); + +/** + * \brief Generate cookie, see \c mbedtls_ssl_cookie_write_t + */ +mbedtls_ssl_cookie_write_t mbedtls_ssl_cookie_write; + +/** + * \brief Verify cookie, see \c mbedtls_ssl_cookie_write_t + */ +mbedtls_ssl_cookie_check_t mbedtls_ssl_cookie_check; + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_cookie.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ssl_internal.h b/c++/src/connect/mbedtls/mbedtls/ssl_internal.h new file mode 100644 index 00000000..668c0f56 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ssl_internal.h @@ -0,0 +1,500 @@ +/** + * \file ssl_ticket.h + * + * \brief Internal functions shared by the SSL modules + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_INTERNAL_H +#define MBEDTLS_SSL_INTERNAL_H + +#include "ssl.h" + +#if defined(MBEDTLS_MD5_C) +#include "md5.h" +#endif + +#if defined(MBEDTLS_SHA1_C) +#include "sha1.h" +#endif + +#if defined(MBEDTLS_SHA256_C) +#include "sha256.h" +#endif + +#if defined(MBEDTLS_SHA512_C) +#include "sha512.h" +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +#include "ecjpake.h" +#endif + +#if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \ + !defined(inline) && !defined(__cplusplus) +#define inline __inline +#endif + +/* Determine minimum supported version */ +#define MBEDTLS_SSL_MIN_MAJOR_VERSION MBEDTLS_SSL_MAJOR_VERSION_3 + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_0 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_1 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_2 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#define MBEDTLS_SSL_MIN_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_3 +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1 */ +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +/* Determine maximum supported version */ +#define MBEDTLS_SSL_MAX_MAJOR_VERSION MBEDTLS_SSL_MAJOR_VERSION_3 + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_3 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_2 +#else +#if defined(MBEDTLS_SSL_PROTO_TLS1) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_1 +#else +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define MBEDTLS_SSL_MAX_MINOR_VERSION MBEDTLS_SSL_MINOR_VERSION_0 +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#define MBEDTLS_SSL_INITIAL_HANDSHAKE 0 +#define MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS 1 /* In progress */ +#define MBEDTLS_SSL_RENEGOTIATION_DONE 2 /* Done or aborted */ +#define MBEDTLS_SSL_RENEGOTIATION_PENDING 3 /* Requested (server only) */ + +/* + * DTLS retransmission states, see RFC 6347 4.2.4 + * + * The SENDING state is merged in PREPARING for initial sends, + * but is distinct for resends. + * + * Note: initial state is wrong for server, but is not used anyway. + */ +#define MBEDTLS_SSL_RETRANS_PREPARING 0 +#define MBEDTLS_SSL_RETRANS_SENDING 1 +#define MBEDTLS_SSL_RETRANS_WAITING 2 +#define MBEDTLS_SSL_RETRANS_FINISHED 3 + +/* + * Allow extra bytes for record, authentication and encryption overhead: + * counter (8) + header (5) + IV(16) + MAC (16-48) + padding (0-256) + * and allow for a maximum of 1024 of compression expansion if + * enabled. + */ +#if defined(MBEDTLS_ZLIB_SUPPORT) +#define MBEDTLS_SSL_COMPRESSION_ADD 1024 +#else +#define MBEDTLS_SSL_COMPRESSION_ADD 0 +#endif + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_MODE_CBC) +/* Ciphersuites using HMAC */ +#if defined(MBEDTLS_SHA512_C) +#define MBEDTLS_SSL_MAC_ADD 48 /* SHA-384 used for HMAC */ +#elif defined(MBEDTLS_SHA256_C) +#define MBEDTLS_SSL_MAC_ADD 32 /* SHA-256 used for HMAC */ +#else +#define MBEDTLS_SSL_MAC_ADD 20 /* SHA-1 used for HMAC */ +#endif +#else +/* AEAD ciphersuites: GCM and CCM use a 128 bits tag */ +#define MBEDTLS_SSL_MAC_ADD 16 +#endif + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#define MBEDTLS_SSL_PADDING_ADD 256 +#else +#define MBEDTLS_SSL_PADDING_ADD 0 +#endif + +#define MBEDTLS_SSL_BUFFER_LEN ( MBEDTLS_SSL_MAX_CONTENT_LEN \ + + MBEDTLS_SSL_COMPRESSION_ADD \ + + 29 /* counter + header + IV */ \ + + MBEDTLS_SSL_MAC_ADD \ + + MBEDTLS_SSL_PADDING_ADD \ + ) + +/* + * TLS extension flags (for extensions with outgoing ServerHello content + * that need it (e.g. for RENEGOTIATION_INFO the server already knows because + * of state of the renegotiation flag, so no indicator is required) + */ +#define MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT (1 << 0) +#define MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK (1 << 1) + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This structure contains the parameters only needed during handshake. + */ +struct mbedtls_ssl_handshake_params +{ + /* + * Handshake specific crypto variables + */ + int sig_alg; /*!< Hash algorithm for signature */ + int verify_sig_alg; /*!< Signature algorithm for verify */ +#if defined(MBEDTLS_DHM_C) + mbedtls_dhm_context dhm_ctx; /*!< DHM key exchange */ +#endif +#if defined(MBEDTLS_ECDH_C) + mbedtls_ecdh_context ecdh_ctx; /*!< ECDH key exchange */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + mbedtls_ecjpake_context ecjpake_ctx; /*!< EC J-PAKE key exchange */ +#if defined(MBEDTLS_SSL_CLI_C) + unsigned char *ecjpake_cache; /*!< Cache for ClientHello ext */ + size_t ecjpake_cache_len; /*!< Length of cached data */ +#endif +#endif +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + const mbedtls_ecp_curve_info **curves; /*!< Supported elliptic curves */ +#endif +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + unsigned char *psk; /*!< PSK from the callback */ + size_t psk_len; /*!< Length of PSK from callback */ +#endif +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_ssl_key_cert *key_cert; /*!< chosen key/cert pair (server) */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + int sni_authmode; /*!< authmode from SNI callback */ + mbedtls_ssl_key_cert *sni_key_cert; /*!< key/cert list from SNI */ + mbedtls_x509_crt *sni_ca_chain; /*!< trusted CAs from SNI callback */ + mbedtls_x509_crl *sni_ca_crl; /*!< trusted CAs CRLs from SNI */ +#endif +#endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + unsigned int out_msg_seq; /*!< Outgoing handshake sequence number */ + unsigned int in_msg_seq; /*!< Incoming handshake sequence number */ + + unsigned char *verify_cookie; /*!< Cli: HelloVerifyRequest cookie + Srv: unused */ + unsigned char verify_cookie_len; /*!< Cli: cookie length + Srv: flag for sending a cookie */ + + unsigned char *hs_msg; /*!< Reassembled handshake message */ + + uint32_t retransmit_timeout; /*!< Current value of timeout */ + unsigned char retransmit_state; /*!< Retransmission state */ + mbedtls_ssl_flight_item *flight; /*!< Current outgoing flight */ + mbedtls_ssl_flight_item *cur_msg; /*!< Current message in flight */ + unsigned int in_flight_start_seq; /*!< Minimum message sequence in the + flight being received */ + mbedtls_ssl_transform *alt_transform_out; /*!< Alternative transform for + resending messages */ + unsigned char alt_out_ctr[8]; /*!< Alternative record epoch/counter + for resending messages */ +#endif + + /* + * Checksum contexts + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_context fin_md5; + mbedtls_sha1_context fin_sha1; +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_context fin_sha256; +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_context fin_sha512; +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + void (*update_checksum)(mbedtls_ssl_context *, const unsigned char *, size_t); + void (*calc_verify)(mbedtls_ssl_context *, unsigned char *); + void (*calc_finished)(mbedtls_ssl_context *, unsigned char *, int); + int (*tls_prf)(const unsigned char *, size_t, const char *, + const unsigned char *, size_t, + unsigned char *, size_t); + + size_t pmslen; /*!< premaster length */ + + unsigned char randbytes[64]; /*!< random bytes */ + unsigned char premaster[MBEDTLS_PREMASTER_SIZE]; + /*!< premaster secret */ + + int resume; /*!< session resume indicator*/ + int max_major_ver; /*!< max. major version client*/ + int max_minor_ver; /*!< max. minor version client*/ + int cli_exts; /*!< client extension presence*/ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + int new_session_ticket; /*!< use NewSessionTicket? */ +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + int extended_ms; /*!< use Extended Master Secret? */ +#endif +}; + +/* + * This structure contains a full set of runtime transform parameters + * either in negotiation or active. + */ +struct mbedtls_ssl_transform +{ + /* + * Session specific crypto layer + */ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + /*!< Chosen cipersuite_info */ + unsigned int keylen; /*!< symmetric key length (bytes) */ + size_t minlen; /*!< min. ciphertext length */ + size_t ivlen; /*!< IV length */ + size_t fixed_ivlen; /*!< Fixed part of IV (AEAD) */ + size_t maclen; /*!< MAC length */ + + unsigned char iv_enc[16]; /*!< IV (encryption) */ + unsigned char iv_dec[16]; /*!< IV (decryption) */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + /* Needed only for SSL v3.0 secret */ + unsigned char mac_enc[20]; /*!< SSL v3.0 secret (enc) */ + unsigned char mac_dec[20]; /*!< SSL v3.0 secret (dec) */ +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + + mbedtls_md_context_t md_ctx_enc; /*!< MAC (encryption) */ + mbedtls_md_context_t md_ctx_dec; /*!< MAC (decryption) */ + + mbedtls_cipher_context_t cipher_ctx_enc; /*!< encryption context */ + mbedtls_cipher_context_t cipher_ctx_dec; /*!< decryption context */ + + /* + * Session specific compression layer + */ +#if defined(MBEDTLS_ZLIB_SUPPORT) + z_stream ctx_deflate; /*!< compression context */ + z_stream ctx_inflate; /*!< decompression context */ +#endif +}; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/* + * List of certificate + private key pairs + */ +struct mbedtls_ssl_key_cert +{ + mbedtls_x509_crt *cert; /*!< cert */ + mbedtls_pk_context *key; /*!< private key */ + mbedtls_ssl_key_cert *next; /*!< next key/cert pair */ +}; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/* + * List of handshake messages kept around for resending + */ +struct mbedtls_ssl_flight_item +{ + unsigned char *p; /*!< message, including handshake headers */ + size_t len; /*!< length of p */ + unsigned char type; /*!< type of the message: handshake or CCS */ + mbedtls_ssl_flight_item *next; /*!< next handshake message(s) */ +}; +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + +/** + * \brief Free referenced items in an SSL transform context and clear + * memory + * + * \param transform SSL transform context + */ +void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ); + +/** + * \brief Free referenced items in an SSL handshake context and clear + * memory + * + * \param handshake SSL handshake context + */ +void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake ); + +int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_handshake_wrapup( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl ); + +void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ); + +int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl ); + +int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ); + +void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, + const mbedtls_ssl_ciphersuite_t *ciphersuite_info ); + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex ); +#endif + +#if defined(MBEDTLS_PK_C) +unsigned char mbedtls_ssl_sig_from_pk( mbedtls_pk_context *pk ); +mbedtls_pk_type_t mbedtls_ssl_pk_alg_from_sig( unsigned char sig ); +#endif + +mbedtls_md_type_t mbedtls_ssl_md_alg_from_hash( unsigned char hash ); +unsigned char mbedtls_ssl_hash_from_md_alg( int md ); +int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context *ssl, int md ); + +#if defined(MBEDTLS_ECP_C) +int mbedtls_ssl_check_curve( const mbedtls_ssl_context *ssl, mbedtls_ecp_group_id grp_id ); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, + mbedtls_md_type_t md ); +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +static inline mbedtls_pk_context *mbedtls_ssl_own_key( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_key_cert *key_cert; + + if( ssl->handshake != NULL && ssl->handshake->key_cert != NULL ) + key_cert = ssl->handshake->key_cert; + else + key_cert = ssl->conf->key_cert; + + return( key_cert == NULL ? NULL : key_cert->key ); +} + +static inline mbedtls_x509_crt *mbedtls_ssl_own_cert( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_key_cert *key_cert; + + if( ssl->handshake != NULL && ssl->handshake->key_cert != NULL ) + key_cert = ssl->handshake->key_cert; + else + key_cert = ssl->conf->key_cert; + + return( key_cert == NULL ? NULL : key_cert->cert ); +} + +/* + * Check usage of a certificate wrt extensions: + * keyUsage, extendedKeyUsage (later), and nSCertType (later). + * + * Warning: cert_endpoint is the endpoint of the cert (ie, of our peer when we + * check a cert we received from them)! + * + * Return 0 if everything is OK, -1 if not. + */ +int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, + const mbedtls_ssl_ciphersuite_t *ciphersuite, + int cert_endpoint, + uint32_t *flags ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +void mbedtls_ssl_write_version( int major, int minor, int transport, + unsigned char ver[2] ); +void mbedtls_ssl_read_version( int *major, int *minor, int transport, + const unsigned char ver[2] ); + +static inline size_t mbedtls_ssl_hdr_len( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( 13 ); +#else + ((void) ssl); +#endif + return( 5 ); +} + +static inline size_t mbedtls_ssl_hs_hdr_len( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( 12 ); +#else + ((void) ssl); +#endif + return( 4 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ); +int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ); +#endif + +/* Visible for testing purposes only */ +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +int mbedtls_ssl_dtls_replay_check( mbedtls_ssl_context *ssl ); +void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl ); +#endif + +/* constant-time buffer comparison */ +static inline int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n ) +{ + size_t i; + const unsigned char *A = (const unsigned char *) a; + const unsigned char *B = (const unsigned char *) b; + unsigned char diff = 0; + + for( i = 0; i < n; i++ ) + diff |= A[i] ^ B[i]; + + return( diff ); +} + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_internal.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/ssl_ticket.h b/c++/src/connect/mbedtls/mbedtls/ssl_ticket.h new file mode 100644 index 00000000..7c6bc61b --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/ssl_ticket.h @@ -0,0 +1,135 @@ +/** + * \file ssl_ticket.h + * + * \brief TLS server ticket callbacks implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_SSL_TICKET_H +#define MBEDTLS_SSL_TICKET_H + +/* + * This implementation of the session ticket callbacks includes key + * management, rotating the keys periodically in order to preserve forward + * secrecy, when MBEDTLS_HAVE_TIME is defined. + */ + +#include "ssl.h" +#include "cipher.h" + +#if defined(MBEDTLS_THREADING_C) +#include "threading.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Information for session ticket protection + */ +typedef struct +{ + unsigned char name[4]; /*!< random key identifier */ + uint32_t generation_time; /*!< key generation timestamp (seconds) */ + mbedtls_cipher_context_t ctx; /*!< context for auth enc/decryption */ +} +mbedtls_ssl_ticket_key; + +/** + * \brief Context for session ticket handling functions + */ +typedef struct +{ + mbedtls_ssl_ticket_key keys[2]; /*!< ticket protection keys */ + unsigned char active; /*!< index of the currently active key */ + + uint32_t ticket_lifetime; /*!< lifetime of tickets in seconds */ + + /** Callback for getting (pseudo-)random numbers */ + int (*f_rng)(void *, unsigned char *, size_t); + void *p_rng; /*!< context for the RNG function */ + +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} +mbedtls_ssl_ticket_context; + +/** + * \brief Initialize a ticket context. + * (Just make it ready for mbedtls_ssl_ticket_setup() + * or mbedtls_ssl_ticket_free().) + * + * \param ctx Context to be initialized + */ +void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx ); + +/** + * \brief Prepare context to be actually used + * + * \param ctx Context to be set up + * \param f_rng RNG callback function + * \param p_rng RNG callback context + * \param cipher AEAD cipher to use for ticket protection. + * Recommended value: MBEDTLS_CIPHER_AES_256_GCM. + * \param lifetime Tickets lifetime in seconds + * Recommended value: 86400 (one day). + * + * \note It is highly recommended to select a cipher that is at + * least as strong as the the strongest ciphersuite + * supported. Usually that means a 256-bit key. + * + * \note The lifetime of the keys is twice the lifetime of tickets. + * It is recommended to pick a reasonnable lifetime so as not + * to negate the benefits of forward secrecy. + * + * \return 0 if successful, + * or a specific MBEDTLS_ERR_XXX error code + */ +int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_cipher_type_t cipher, + uint32_t lifetime ); + +/** + * \brief Implementation of the ticket write callback + * + * \note See \c mbedlts_ssl_ticket_write_t for description + */ +mbedtls_ssl_ticket_write_t mbedtls_ssl_ticket_write; + +/** + * \brief Implementation of the ticket parse callback + * + * \note See \c mbedlts_ssl_ticket_parse_t for description + */ +mbedtls_ssl_ticket_parse_t mbedtls_ssl_ticket_parse; + +/** + * \brief Free a context's content and zeroize it. + * + * \param ctx Context to be cleaned up + */ +void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx ); + +#ifdef __cplusplus +} +#endif + +#endif /* ssl_ticket.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/threading.h b/c++/src/connect/mbedtls/mbedtls/threading.h new file mode 100644 index 00000000..b0c34ecc --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/threading.h @@ -0,0 +1,106 @@ +/** + * \file threading.h + * + * \brief Threading abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_THREADING_H +#define MBEDTLS_THREADING_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE -0x001A /**< The selected feature is not available. */ +#define MBEDTLS_ERR_THREADING_BAD_INPUT_DATA -0x001C /**< Bad input parameters to function. */ +#define MBEDTLS_ERR_THREADING_MUTEX_ERROR -0x001E /**< Locking / unlocking / free failed with error code. */ + +#if defined(MBEDTLS_THREADING_PTHREAD) +#include +typedef struct +{ + pthread_mutex_t mutex; + char is_valid; +} mbedtls_threading_mutex_t; +#endif + +#if defined(MBEDTLS_THREADING_ALT) +/* You should define the mbedtls_threading_mutex_t type in your header */ +#include "threading_alt.h" + +/** + * \brief Set your alternate threading implementation function + * pointers and initialize global mutexes. If used, this + * function must be called once in the main thread before any + * other mbed TLS function is called, and + * mbedtls_threading_free_alt() must be called once in the main + * thread after all other mbed TLS functions. + * + * \note mutex_init() and mutex_free() don't return a status code. + * If mutex_init() fails, it should leave its argument (the + * mutex) in a state such that mutex_lock() will fail when + * called with this argument. + * + * \param mutex_init the init function implementation + * \param mutex_free the free function implementation + * \param mutex_lock the lock function implementation + * \param mutex_unlock the unlock function implementation + */ +void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t * ), + void (*mutex_free)( mbedtls_threading_mutex_t * ), + int (*mutex_lock)( mbedtls_threading_mutex_t * ), + int (*mutex_unlock)( mbedtls_threading_mutex_t * ) ); + +/** + * \brief Free global mutexes. + */ +void mbedtls_threading_free_alt( void ); +#endif /* MBEDTLS_THREADING_ALT */ + +#if defined(MBEDTLS_THREADING_C) +/* + * The function pointers for mutex_init, mutex_free, mutex_ and mutex_unlock + * + * All these functions are expected to work or the result will be undefined. + */ +extern void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t *mutex ); +extern void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t *mutex ); +extern int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t *mutex ); +extern int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t *mutex ); + +/* + * Global mutexes + */ +extern mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex; +extern mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex; +#endif /* MBEDTLS_THREADING_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* threading.h */ diff --git a/c++/src/connect/services/util.hpp b/c++/src/connect/mbedtls/mbedtls/threading_alt.h similarity index 76% rename from c++/src/connect/services/util.hpp rename to c++/src/connect/mbedtls/mbedtls/threading_alt.h index 6c815cb1..e9de7e10 100644 --- a/c++/src/connect/services/util.hpp +++ b/c++/src/connect/mbedtls/mbedtls/threading_alt.h @@ -1,7 +1,7 @@ -#ifndef SRC_CONN_SERVICES___UTIL__HPP -#define SRC_CONN_SERVICES___UTIL__HPP +#ifndef CONNECT___MBEDTLS__THREADING_ALT__H +#define CONNECT___MBEDTLS__THREADING_ALT__H -/* $Id: util.hpp 385113 2013-01-04 20:28:34Z kazimird $ +/* $Id: threading_alt.h 531176 2017-03-22 13:25:44Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -26,21 +26,17 @@ * * =========================================================================== * - * Authors: Dmitry Kazimirov + * Author: Anton Lavrentiev * * File Description: - * Utility functions local to the connect/services implementation part. + * MBEDTLS support for SSL in connection library * */ -#include +struct MT_LOCK_tag; +typedef struct MT_LOCK_tag* MT_LOCK; +typedef MT_LOCK mbedtls_threading_mutex_t; -BEGIN_NCBI_SCOPE -unsigned g_NumberOfUnderscoresPlusOne(const string& str); - -END_NCBI_SCOPE - - -#endif /* SRC_CONN_SERVICES___UTIL__HPP */ +#endif /*CONNECT___MBEDTLS__THREADING_ALT__H*/ diff --git a/c++/src/connect/mbedtls/mbedtls/timing.h b/c++/src/connect/mbedtls/mbedtls/timing.h new file mode 100644 index 00000000..ae7a713e --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/timing.h @@ -0,0 +1,141 @@ +/** + * \file timing.h + * + * \brief Portable interface to the CPU cycle counter + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_TIMING_H +#define MBEDTLS_TIMING_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if !defined(MBEDTLS_TIMING_ALT) +// Regular implementation +// + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief timer structure + */ +struct mbedtls_timing_hr_time +{ + unsigned char opaque[32]; +}; + +/** + * \brief Context for mbedtls_timing_set/get_delay() + */ +typedef struct +{ + struct mbedtls_timing_hr_time timer; + uint32_t int_ms; + uint32_t fin_ms; +} mbedtls_timing_delay_context; + +extern volatile int mbedtls_timing_alarmed; + +/** + * \brief Return the CPU cycle counter value + * + * \warning This is only a best effort! Do not rely on this! + * In particular, it is known to be unreliable on virtual + * machines. + */ +unsigned long mbedtls_timing_hardclock( void ); + +/** + * \brief Return the elapsed time in milliseconds + * + * \param val points to a timer structure + * \param reset if set to 1, the timer is restarted + */ +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ); + +/** + * \brief Setup an alarm clock + * + * \param seconds delay before the "mbedtls_timing_alarmed" flag is set + * + * \warning Only one alarm at a time is supported. In a threaded + * context, this means one for the whole process, not one per + * thread. + */ +void mbedtls_set_alarm( int seconds ); + +/** + * \brief Set a pair of delays to watch + * (See \c mbedtls_timing_get_delay().) + * + * \param data Pointer to timing data + * Must point to a valid \c mbedtls_timing_delay_context struct. + * \param int_ms First (intermediate) delay in milliseconds. + * \param fin_ms Second (final) delay in milliseconds. + * Pass 0 to cancel the current delay. + */ +void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ); + +/** + * \brief Get the status of delays + * (Memory helper: number of delays passed.) + * + * \param data Pointer to timing data + * Must point to a valid \c mbedtls_timing_delay_context struct. + * + * \return -1 if cancelled (fin_ms = 0) + * 0 if none of the delays are passed, + * 1 if only the intermediate delay is passed, + * 2 if the final delay is passed. + */ +int mbedtls_timing_get_delay( void *data ); + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_TIMING_ALT */ +#include "timing_alt.h" +#endif /* MBEDTLS_TIMING_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(MBEDTLS_SELF_TEST) +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if a test failed + */ +int mbedtls_timing_self_test( int verbose ); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* timing.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/version.h b/c++/src/connect/mbedtls/mbedtls/version.h new file mode 100644 index 00000000..f00e158c --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/version.h @@ -0,0 +1,111 @@ +/** + * \file version.h + * + * \brief Run-time version information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * This set of compile-time defines and run-time variables can be used to + * determine the version number of the mbed TLS library used. + */ +#ifndef MBEDTLS_VERSION_H +#define MBEDTLS_VERSION_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +/** + * The version number x.y.z is split into three parts. + * Major, Minor, Patchlevel + */ +#define MBEDTLS_VERSION_MAJOR 2 +#define MBEDTLS_VERSION_MINOR 4 +#define MBEDTLS_VERSION_PATCH 2 + +/** + * The single version number has the following structure: + * MMNNPP00 + * Major version | Minor version | Patch version + */ +#define MBEDTLS_VERSION_NUMBER 0x02040200 +#define MBEDTLS_VERSION_STRING "2.4.2" +#define MBEDTLS_VERSION_STRING_FULL "mbed TLS 2.4.2" + +#if defined(MBEDTLS_VERSION_C) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Get the version number. + * + * \return The constructed version number in the format + * MMNNPP00 (Major, Minor, Patch). + */ +unsigned int mbedtls_version_get_number( void ); + +/** + * Get the version string ("x.y.z"). + * + * \param string The string that will receive the value. + * (Should be at least 9 bytes in size) + */ +void mbedtls_version_get_string( char *string ); + +/** + * Get the full version string ("mbed TLS x.y.z"). + * + * \param string The string that will receive the value. The mbed TLS version + * string will use 18 bytes AT MOST including a terminating + * null byte. + * (So the buffer should be at least 18 bytes to receive this + * version string). + */ +void mbedtls_version_get_string_full( char *string ); + +/** + * \brief Check if support for a feature was compiled into this + * mbed TLS binary. This allows you to see at runtime if the + * library was for instance compiled with or without + * Multi-threading support. + * + * \note only checks against defines in the sections "System + * support", "mbed TLS modules" and "mbed TLS feature + * support" in config.h + * + * \param feature The string for the define to check (e.g. "MBEDTLS_AES_C") + * + * \return 0 if the feature is present, + * -1 if the feature is not present and + * -2 if support for feature checking as a whole was not + * compiled in. + */ +int mbedtls_version_check_feature( const char *feature ); + +#ifdef __cplusplus +} +#endif + +#endif /* MBEDTLS_VERSION_C */ + +#endif /* version.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/x509.h b/c++/src/connect/mbedtls/mbedtls/x509.h new file mode 100644 index 00000000..f219bf12 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/x509.h @@ -0,0 +1,331 @@ +/** + * \file x509.h + * + * \brief X.509 generic defines and structures + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_H +#define MBEDTLS_X509_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "asn1.h" +#include "pk.h" + +#if defined(MBEDTLS_RSA_C) +#include "rsa.h" +#endif + +/** + * \addtogroup x509_module + * \{ + */ + +#if !defined(MBEDTLS_X509_MAX_INTERMEDIATE_CA) +/** + * Maximum number of intermediate CAs in a verification chain. + * That is, maximum length of the chain, excluding the end-entity certificate + * and the trusted root certificate. + * + * Set this to a low value to prevent an adversary from making you waste + * resources verifying an overlong certificate chain. + */ +#define MBEDTLS_X509_MAX_INTERMEDIATE_CA 8 +#endif + +/** + * \name X509 Error codes + * \{ + */ +#define MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE -0x2080 /**< Unavailable feature, e.g. RSA hashing/encryption combination. */ +#define MBEDTLS_ERR_X509_UNKNOWN_OID -0x2100 /**< Requested OID is unknown. */ +#define MBEDTLS_ERR_X509_INVALID_FORMAT -0x2180 /**< The CRT/CRL/CSR format is invalid, e.g. different type expected. */ +#define MBEDTLS_ERR_X509_INVALID_VERSION -0x2200 /**< The CRT/CRL/CSR version element is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_SERIAL -0x2280 /**< The serial tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_ALG -0x2300 /**< The algorithm tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_NAME -0x2380 /**< The name tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_DATE -0x2400 /**< The date tag or value is invalid. */ +#define MBEDTLS_ERR_X509_INVALID_SIGNATURE -0x2480 /**< The signature tag or value invalid. */ +#define MBEDTLS_ERR_X509_INVALID_EXTENSIONS -0x2500 /**< The extension tag or value is invalid. */ +#define MBEDTLS_ERR_X509_UNKNOWN_VERSION -0x2580 /**< CRT/CRL/CSR has an unsupported version number. */ +#define MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG -0x2600 /**< Signature algorithm (oid) is unsupported. */ +#define MBEDTLS_ERR_X509_SIG_MISMATCH -0x2680 /**< Signature algorithms do not match. (see \c ::mbedtls_x509_crt sig_oid) */ +#define MBEDTLS_ERR_X509_CERT_VERIFY_FAILED -0x2700 /**< Certificate verification failed, e.g. CRL, CA or signature check failed. */ +#define MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT -0x2780 /**< Format not recognized as DER or PEM. */ +#define MBEDTLS_ERR_X509_BAD_INPUT_DATA -0x2800 /**< Input invalid. */ +#define MBEDTLS_ERR_X509_ALLOC_FAILED -0x2880 /**< Allocation of memory failed. */ +#define MBEDTLS_ERR_X509_FILE_IO_ERROR -0x2900 /**< Read/write of file failed. */ +#define MBEDTLS_ERR_X509_BUFFER_TOO_SMALL -0x2980 /**< Destination buffer is too small. */ +/* \} name */ + +/** + * \name X509 Verify codes + * \{ + */ +/* Reminder: update x509_crt_verify_strings[] in library/x509_crt.c */ +#define MBEDTLS_X509_BADCERT_EXPIRED 0x01 /**< The certificate validity has expired. */ +#define MBEDTLS_X509_BADCERT_REVOKED 0x02 /**< The certificate has been revoked (is on a CRL). */ +#define MBEDTLS_X509_BADCERT_CN_MISMATCH 0x04 /**< The certificate Common Name (CN) does not match with the expected CN. */ +#define MBEDTLS_X509_BADCERT_NOT_TRUSTED 0x08 /**< The certificate is not correctly signed by the trusted CA. */ +#define MBEDTLS_X509_BADCRL_NOT_TRUSTED 0x10 /**< The CRL is not correctly signed by the trusted CA. */ +#define MBEDTLS_X509_BADCRL_EXPIRED 0x20 /**< The CRL is expired. */ +#define MBEDTLS_X509_BADCERT_MISSING 0x40 /**< Certificate was missing. */ +#define MBEDTLS_X509_BADCERT_SKIP_VERIFY 0x80 /**< Certificate verification was skipped. */ +#define MBEDTLS_X509_BADCERT_OTHER 0x0100 /**< Other reason (can be used by verify callback) */ +#define MBEDTLS_X509_BADCERT_FUTURE 0x0200 /**< The certificate validity starts in the future. */ +#define MBEDTLS_X509_BADCRL_FUTURE 0x0400 /**< The CRL is from the future */ +#define MBEDTLS_X509_BADCERT_KEY_USAGE 0x0800 /**< Usage does not match the keyUsage extension. */ +#define MBEDTLS_X509_BADCERT_EXT_KEY_USAGE 0x1000 /**< Usage does not match the extendedKeyUsage extension. */ +#define MBEDTLS_X509_BADCERT_NS_CERT_TYPE 0x2000 /**< Usage does not match the nsCertType extension. */ +#define MBEDTLS_X509_BADCERT_BAD_MD 0x4000 /**< The certificate is signed with an unacceptable hash. */ +#define MBEDTLS_X509_BADCERT_BAD_PK 0x8000 /**< The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA). */ +#define MBEDTLS_X509_BADCERT_BAD_KEY 0x010000 /**< The certificate is signed with an unacceptable key (eg bad curve, RSA too short). */ +#define MBEDTLS_X509_BADCRL_BAD_MD 0x020000 /**< The CRL is signed with an unacceptable hash. */ +#define MBEDTLS_X509_BADCRL_BAD_PK 0x040000 /**< The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA). */ +#define MBEDTLS_X509_BADCRL_BAD_KEY 0x080000 /**< The CRL is signed with an unacceptable key (eg bad curve, RSA too short). */ + +/* \} name */ +/* \} addtogroup x509_module */ + +/* + * X.509 v3 Key Usage Extension flags + * Reminder: update x509_info_key_usage() when adding new flags. + */ +#define MBEDTLS_X509_KU_DIGITAL_SIGNATURE (0x80) /* bit 0 */ +#define MBEDTLS_X509_KU_NON_REPUDIATION (0x40) /* bit 1 */ +#define MBEDTLS_X509_KU_KEY_ENCIPHERMENT (0x20) /* bit 2 */ +#define MBEDTLS_X509_KU_DATA_ENCIPHERMENT (0x10) /* bit 3 */ +#define MBEDTLS_X509_KU_KEY_AGREEMENT (0x08) /* bit 4 */ +#define MBEDTLS_X509_KU_KEY_CERT_SIGN (0x04) /* bit 5 */ +#define MBEDTLS_X509_KU_CRL_SIGN (0x02) /* bit 6 */ +#define MBEDTLS_X509_KU_ENCIPHER_ONLY (0x01) /* bit 7 */ +#define MBEDTLS_X509_KU_DECIPHER_ONLY (0x8000) /* bit 8 */ + +/* + * Netscape certificate types + * (http://www.mozilla.org/projects/security/pki/nss/tech-notes/tn3.html) + */ + +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT (0x80) /* bit 0 */ +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER (0x40) /* bit 1 */ +#define MBEDTLS_X509_NS_CERT_TYPE_EMAIL (0x20) /* bit 2 */ +#define MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING (0x10) /* bit 3 */ +#define MBEDTLS_X509_NS_CERT_TYPE_RESERVED (0x08) /* bit 4 */ +#define MBEDTLS_X509_NS_CERT_TYPE_SSL_CA (0x04) /* bit 5 */ +#define MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA (0x02) /* bit 6 */ +#define MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA (0x01) /* bit 7 */ + +/* + * X.509 extension types + * + * Comments refer to the status for using certificates. Status can be + * different for writing certificates or reading CRLs or CSRs. + */ +#define MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER (1 << 0) +#define MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER (1 << 1) +#define MBEDTLS_X509_EXT_KEY_USAGE (1 << 2) +#define MBEDTLS_X509_EXT_CERTIFICATE_POLICIES (1 << 3) +#define MBEDTLS_X509_EXT_POLICY_MAPPINGS (1 << 4) +#define MBEDTLS_X509_EXT_SUBJECT_ALT_NAME (1 << 5) /* Supported (DNS) */ +#define MBEDTLS_X509_EXT_ISSUER_ALT_NAME (1 << 6) +#define MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS (1 << 7) +#define MBEDTLS_X509_EXT_BASIC_CONSTRAINTS (1 << 8) /* Supported */ +#define MBEDTLS_X509_EXT_NAME_CONSTRAINTS (1 << 9) +#define MBEDTLS_X509_EXT_POLICY_CONSTRAINTS (1 << 10) +#define MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE (1 << 11) +#define MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS (1 << 12) +#define MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY (1 << 13) +#define MBEDTLS_X509_EXT_FRESHEST_CRL (1 << 14) + +#define MBEDTLS_X509_EXT_NS_CERT_TYPE (1 << 16) + +/* + * Storage format identifiers + * Recognized formats: PEM and DER + */ +#define MBEDTLS_X509_FORMAT_DER 1 +#define MBEDTLS_X509_FORMAT_PEM 2 + +#define MBEDTLS_X509_MAX_DN_NAME_SIZE 256 /**< Maximum value size of a DN entry */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures for parsing X.509 certificates, CRLs and CSRs + * \{ + */ + +/** + * Type-length-value structure that allows for ASN1 using DER. + */ +typedef mbedtls_asn1_buf mbedtls_x509_buf; + +/** + * Container for ASN1 bit strings. + */ +typedef mbedtls_asn1_bitstring mbedtls_x509_bitstring; + +/** + * Container for ASN1 named information objects. + * It allows for Relative Distinguished Names (e.g. cn=localhost,ou=code,etc.). + */ +typedef mbedtls_asn1_named_data mbedtls_x509_name; + +/** + * Container for a sequence of ASN.1 items + */ +typedef mbedtls_asn1_sequence mbedtls_x509_sequence; + +/** Container for date and time (precision in seconds). */ +typedef struct mbedtls_x509_time +{ + int year, mon, day; /**< Date. */ + int hour, min, sec; /**< Time. */ +} +mbedtls_x509_time; + +/** \} name Structures for parsing X.509 certificates, CRLs and CSRs */ +/** \} addtogroup x509_module */ + +/** + * \brief Store the certificate DN in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param dn The X509 name to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_dn_gets( char *buf, size_t size, const mbedtls_x509_name *dn ); + +/** + * \brief Store the certificate serial in printable form into buf; + * no more than size characters will be written. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param serial The X509 serial to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *serial ); + +/** + * \brief Check a given mbedtls_x509_time against the system time + * and tell if it's in the past. + * + * \note Intended usage is "if( is_past( valid_to ) ) ERROR". + * Hence the return value of 1 if on internal errors. + * + * \param time mbedtls_x509_time to check + * + * \return 1 if the given time is in the past or an error occured, + * 0 otherwise. + */ +int mbedtls_x509_time_is_past( const mbedtls_x509_time *time ); + +/** + * \brief Check a given mbedtls_x509_time against the system time + * and tell if it's in the future. + * + * \note Intended usage is "if( is_future( valid_from ) ) ERROR". + * Hence the return value of 1 if on internal errors. + * + * \param time mbedtls_x509_time to check + * + * \return 1 if the given time is in the future or an error occured, + * 0 otherwise. + */ +int mbedtls_x509_time_is_future( const mbedtls_x509_time *time ); + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_x509_self_test( int verbose ); + +/* + * Internal module functions. You probably do not want to use these unless you + * know you do. + */ +int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, + mbedtls_x509_name *cur ); +int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg ); +int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg, mbedtls_x509_buf *params ); +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) +int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, + mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, + int *salt_len ); +#endif +int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ); +int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, + void **sig_opts ); +int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, + mbedtls_x509_time *time ); +int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *serial ); +int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *ext, int tag ); +int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid, + mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const void *sig_opts ); +int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ); +int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name ); +int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, size_t oid_len, + int critical, const unsigned char *val, + size_t val_len ); +int mbedtls_x509_write_extensions( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ); +int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ); +int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ); + +#define MBEDTLS_X509_SAFE_SNPRINTF \ + do { \ + if( ret < 0 || (size_t) ret >= n ) \ + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); \ + \ + n -= (size_t) ret; \ + p += (size_t) ret; \ + } while( 0 ) + +#ifdef __cplusplus +} +#endif + +#endif /* x509.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/x509_crl.h b/c++/src/connect/mbedtls/mbedtls/x509_crl.h new file mode 100644 index 00000000..79884399 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/x509_crl.h @@ -0,0 +1,173 @@ +/** + * \file x509_crl.h + * + * \brief X.509 certificate revocation list parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_CRL_H +#define MBEDTLS_X509_CRL_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "x509.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures and functions for parsing CRLs + * \{ + */ + +/** + * Certificate revocation list entry. + * Contains the CA-specific serial numbers and revocation dates. + */ +typedef struct mbedtls_x509_crl_entry +{ + mbedtls_x509_buf raw; + + mbedtls_x509_buf serial; + + mbedtls_x509_time revocation_date; + + mbedtls_x509_buf entry_ext; + + struct mbedtls_x509_crl_entry *next; +} +mbedtls_x509_crl_entry; + +/** + * Certificate revocation list structure. + * Every CRL may have multiple entries. + */ +typedef struct mbedtls_x509_crl +{ + mbedtls_x509_buf raw; /**< The raw certificate data (DER). */ + mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< CRL version (1=v1, 2=v2) */ + mbedtls_x509_buf sig_oid; /**< CRL signature type identifier */ + + mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). */ + + mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ + + mbedtls_x509_time this_update; + mbedtls_x509_time next_update; + + mbedtls_x509_crl_entry entry; /**< The CRL entries containing the certificate revocation times for this CA. */ + + mbedtls_x509_buf crl_ext; + + mbedtls_x509_buf sig_oid2; + mbedtls_x509_buf sig; + mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ + + struct mbedtls_x509_crl *next; +} +mbedtls_x509_crl; + +/** + * \brief Parse a DER-encoded CRL and append it to the chained list + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data in DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, + const unsigned char *buf, size_t buflen ); +/** + * \brief Parse one or more CRLs and append them to the chained list + * + * \note Mutliple CRLs are accepted only if using PEM format + * + * \param chain points to the start of the chain + * \param buf buffer holding the CRL data in PEM or DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, size_t buflen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Load one or more CRLs and append them to the chained list + * + * \note Mutliple CRLs are accepted only if using PEM format + * + * \param chain points to the start of the chain + * \param path filename to read the CRLs from (in PEM or DER encoding) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crl_parse_file( mbedtls_x509_crl *chain, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Returns an informational string about the CRL. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crl The X509 CRL to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crl_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crl *crl ); + +/** + * \brief Initialize a CRL (chain) + * + * \param crl CRL chain to initialize + */ +void mbedtls_x509_crl_init( mbedtls_x509_crl *crl ); + +/** + * \brief Unallocate all CRL data + * + * \param crl CRL chain to free + */ +void mbedtls_x509_crl_free( mbedtls_x509_crl *crl ); + +/* \} name */ +/* \} addtogroup x509_module */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_x509_crl.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/x509_crt.h b/c++/src/connect/mbedtls/mbedtls/x509_crt.h new file mode 100644 index 00000000..383e484f --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/x509_crt.h @@ -0,0 +1,654 @@ +/** + * \file x509_crt.h + * + * \brief X.509 certificate parsing and writing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_CRT_H +#define MBEDTLS_X509_CRT_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "x509.h" +#include "x509_crl.h" + +/** + * \addtogroup x509_module + * \{ + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \name Structures and functions for parsing and writing X.509 certificates + * \{ + */ + +/** + * Container for an X.509 certificate. The certificate may be chained. + */ +typedef struct mbedtls_x509_crt +{ + mbedtls_x509_buf raw; /**< The raw certificate data (DER). */ + mbedtls_x509_buf tbs; /**< The raw certificate body (DER). The part that is To Be Signed. */ + + int version; /**< The X.509 version. (1=v1, 2=v2, 3=v3) */ + mbedtls_x509_buf serial; /**< Unique id for certificate issued by a specific CA. */ + mbedtls_x509_buf sig_oid; /**< Signature algorithm, e.g. sha1RSA */ + + mbedtls_x509_buf issuer_raw; /**< The raw issuer data (DER). Used for quick comparison. */ + mbedtls_x509_buf subject_raw; /**< The raw subject data (DER). Used for quick comparison. */ + + mbedtls_x509_name issuer; /**< The parsed issuer data (named information object). */ + mbedtls_x509_name subject; /**< The parsed subject data (named information object). */ + + mbedtls_x509_time valid_from; /**< Start time of certificate validity. */ + mbedtls_x509_time valid_to; /**< End time of certificate validity. */ + + mbedtls_pk_context pk; /**< Container for the public key context. */ + + mbedtls_x509_buf issuer_id; /**< Optional X.509 v2/v3 issuer unique identifier. */ + mbedtls_x509_buf subject_id; /**< Optional X.509 v2/v3 subject unique identifier. */ + mbedtls_x509_buf v3_ext; /**< Optional X.509 v3 extensions. */ + mbedtls_x509_sequence subject_alt_names; /**< Optional list of Subject Alternative Names (Only dNSName supported). */ + + int ext_types; /**< Bit string containing detected and parsed extensions */ + int ca_istrue; /**< Optional Basic Constraint extension value: 1 if this certificate belongs to a CA, 0 otherwise. */ + int max_pathlen; /**< Optional Basic Constraint extension value: The maximum path length to the root certificate. Path length is 1 higher than RFC 5280 'meaning', so 1+ */ + + unsigned int key_usage; /**< Optional key usage extension value: See the values in x509.h */ + + mbedtls_x509_sequence ext_key_usage; /**< Optional list of extended key usage OIDs. */ + + unsigned char ns_cert_type; /**< Optional Netscape certificate type extension value: See the values in x509.h */ + + mbedtls_x509_buf sig; /**< Signature: hash of the tbs part signed with the private key. */ + mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ + + struct mbedtls_x509_crt *next; /**< Next certificate in the CA-chain. */ +} +mbedtls_x509_crt; + +/** + * Build flag from an algorithm/curve identifier (pk, md, ecp) + * Since 0 is always XXX_NONE, ignore it. + */ +#define MBEDTLS_X509_ID_FLAG( id ) ( 1 << ( id - 1 ) ) + +/** + * Security profile for certificate verification. + * + * All lists are bitfields, built by ORing flags from MBEDTLS_X509_ID_FLAG(). + */ +typedef struct +{ + uint32_t allowed_mds; /**< MDs for signatures */ + uint32_t allowed_pks; /**< PK algs for signatures */ + uint32_t allowed_curves; /**< Elliptic curves for ECDSA */ + uint32_t rsa_min_bitlen; /**< Minimum size for RSA keys */ +} +mbedtls_x509_crt_profile; + +#define MBEDTLS_X509_CRT_VERSION_1 0 +#define MBEDTLS_X509_CRT_VERSION_2 1 +#define MBEDTLS_X509_CRT_VERSION_3 2 + +#define MBEDTLS_X509_RFC5280_MAX_SERIAL_LEN 32 +#define MBEDTLS_X509_RFC5280_UTC_TIME_LEN 15 + +#if !defined( MBEDTLS_X509_MAX_FILE_PATH_LEN ) +#define MBEDTLS_X509_MAX_FILE_PATH_LEN 512 +#endif + +/** + * Container for writing a certificate (CRT) + */ +typedef struct mbedtls_x509write_cert +{ + int version; + mbedtls_mpi serial; + mbedtls_pk_context *subject_key; + mbedtls_pk_context *issuer_key; + mbedtls_asn1_named_data *subject; + mbedtls_asn1_named_data *issuer; + mbedtls_md_type_t md_alg; + char not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN + 1]; + char not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN + 1]; + mbedtls_asn1_named_data *extensions; +} +mbedtls_x509write_cert; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/** + * Default security profile. Should provide a good balance between security + * and compatibility with current deployments. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default; + +/** + * Expected next default profile. Recommended for new deployments. + * Currently targets a 128-bit security level, except for RSA-2048. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next; + +/** + * NSA Suite B profile. + */ +extern const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb; + +/** + * \brief Parse a single DER formatted certificate and add it + * to the chained list. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate DER data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf, + size_t buflen ); + +/** + * \brief Parse one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param buf buffer holding the certificate data in PEM or DER format + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Load one or more certificates and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path filename to read the certificates from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ); + +/** + * \brief Load one or more certificate files from a path and add them + * to the chained list. Parses permissively. If some + * certificates can be parsed, the result is the number + * of failed certificates it encountered. If none complete + * correctly, the first error is returned. + * + * \param chain points to the start of the chain + * \param path directory / folder to read the certificate files from + * + * \return 0 if all certificates parsed successfully, a positive number + * if partly successful or a specific X509 or PEM error code + */ +int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Returns an informational string about the + * certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param crt The X509 certificate to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crt *crt ); + +/** + * \brief Returns an informational string about the + * verification status of a certificate. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param flags Verification flags created by mbedtls_x509_crt_verify() + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, + uint32_t flags ); + +/** + * \brief Verify the certificate signature + * + * The verify callback is a user-supplied callback that + * can clear / modify / add flags for a certificate. If set, + * the verification callback is called for each + * certificate in the chain (from the trust-ca down to the + * presented crt). The parameters for the callback are: + * (void *parameter, mbedtls_x509_crt *crt, int certificate_depth, + * int *flags). With the flags representing current flags for + * that specific certificate and the certificate depth from + * the bottom (Peer cert depth = 0). + * + * All flags left after returning from the callback + * are also returned to the application. The function should + * return 0 for anything but a fatal error. + * + * \note In case verification failed, the results can be displayed + * using \c mbedtls_x509_crt_verify_info() + * + * \note Same as \c mbedtls_x509_crt_verify_with_profile() with the + * default security profile. + * + * \note It is your responsibility to provide up-to-date CRLs for + * all trusted CAs. If no CRL is provided for the CA that was + * used to sign the certificate, CRL verification is skipped + * silently, that is *without* setting any flag. + * + * \param crt a certificate (chain) to be verified + * \param trust_ca the list of trusted CAs + * \param ca_crl the list of CRLs for trusted CAs (see note above) + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 if successful or MBEDTLS_ERR_X509_CERT_VERIFY_FAILED + * in which case *flags will have one or more + * MBEDTLS_X509_BADCERT_XXX or MBEDTLS_X509_BADCRL_XXX flags + * set, + * or another error in case of a fatal error encountered + * during the verification process. + */ +int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); + +/** + * \brief Verify the certificate signature according to profile + * + * \note Same as \c mbedtls_x509_crt_verify(), but with explicit + * security profile. + * + * \note The restrictions on keys (RSA minimum size, allowed curves + * for ECDSA) apply to all certificates: trusted root, + * intermediate CAs if any, and end entity certificate. + * + * \param crt a certificate (chain) to be verified + * \param trust_ca the list of trusted CAs + * \param ca_crl the list of CRLs for trusted CAs + * \param profile security profile for verification + * \param cn expected Common Name (can be set to + * NULL if the CN must not be verified) + * \param flags result of the verification + * \param f_vrfy verification function + * \param p_vrfy verification parameter + * + * \return 0 if successful or MBEDTLS_ERR_X509_CERT_VERIFY_FAILED + * in which case *flags will have one or more + * MBEDTLS_X509_BADCERT_XXX or MBEDTLS_X509_BADCRL_XXX flags + * set, + * or another error in case of a fatal error encountered + * during the verification process. + */ +int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ); + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) +/** + * \brief Check usage of certificate against keyUsage extension. + * + * \param crt Leaf certificate used. + * \param usage Intended usage(s) (eg MBEDTLS_X509_KU_KEY_ENCIPHERMENT + * before using the certificate to perform an RSA key + * exchange). + * + * \note Except for decipherOnly and encipherOnly, a bit set in the + * usage argument means this bit MUST be set in the + * certificate. For decipherOnly and encipherOnly, it means + * that bit MAY be set. + * + * \return 0 is these uses of the certificate are allowed, + * MBEDTLS_ERR_X509_BAD_INPUT_DATA if the keyUsage extension + * is present but does not match the usage argument. + * + * \note You should only call this function on leaf certificates, on + * (intermediate) CAs the keyUsage extension is automatically + * checked by \c mbedtls_x509_crt_verify(). + */ +int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, + unsigned int usage ); +#endif /* MBEDTLS_X509_CHECK_KEY_USAGE) */ + +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +/** + * \brief Check usage of certificate against extentedJeyUsage. + * + * \param crt Leaf certificate used. + * \param usage_oid Intended usage (eg MBEDTLS_OID_SERVER_AUTH or MBEDTLS_OID_CLIENT_AUTH). + * \param usage_len Length of usage_oid (eg given by MBEDTLS_OID_SIZE()). + * + * \return 0 if this use of the certificate is allowed, + * MBEDTLS_ERR_X509_BAD_INPUT_DATA if not. + * + * \note Usually only makes sense on leaf certificates. + */ +int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, + const char *usage_oid, + size_t usage_len ); +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) */ + +#if defined(MBEDTLS_X509_CRL_PARSE_C) +/** + * \brief Verify the certificate revocation status + * + * \param crt a certificate to be verified + * \param crl the CRL to verify against + * + * \return 1 if the certificate is revoked, 0 otherwise + * + */ +int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ); +#endif /* MBEDTLS_X509_CRL_PARSE_C */ + +/** + * \brief Initialize a certificate (chain) + * + * \param crt Certificate chain to initialize + */ +void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ); + +/** + * \brief Unallocate all certificate data + * + * \param crt Certificate chain to free + */ +void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* \} name */ +/* \} addtogroup x509_module */ + +#if defined(MBEDTLS_X509_CRT_WRITE_C) +/** + * \brief Initialize a CRT writing context + * + * \param ctx CRT context to initialize + */ +void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx ); + +/** + * \brief Set the verion for a Certificate + * Default: MBEDTLS_X509_CRT_VERSION_3 + * + * \param ctx CRT context to use + * \param version version to set (MBEDTLS_X509_CRT_VERSION_1, MBEDTLS_X509_CRT_VERSION_2 or + * MBEDTLS_X509_CRT_VERSION_3) + */ +void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version ); + +/** + * \brief Set the serial number for a Certificate. + * + * \param ctx CRT context to use + * \param serial serial number to set + * + * \return 0 if successful + */ +int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls_mpi *serial ); + +/** + * \brief Set the validity period for a Certificate + * Timestamps should be in string format for UTC timezone + * i.e. "YYYYMMDDhhmmss" + * e.g. "20131231235959" for December 31st 2013 + * at 23:59:59 + * + * \param ctx CRT context to use + * \param not_before not_before timestamp + * \param not_after not_after timestamp + * + * \return 0 if timestamp was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, const char *not_before, + const char *not_after ); + +/** + * \brief Set the issuer name for a Certificate + * Issuer names should contain a comma-separated list + * of OID types and values: + * e.g. "C=UK,O=ARM,CN=mbed TLS CA" + * + * \param ctx CRT context to use + * \param issuer_name issuer name to set + * + * \return 0 if issuer name was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx, + const char *issuer_name ); + +/** + * \brief Set the subject name for a Certificate + * Subject names should contain a comma-separated list + * of OID types and values: + * e.g. "C=UK,O=ARM,CN=mbed TLS Server 1" + * + * \param ctx CRT context to use + * \param subject_name subject name to set + * + * \return 0 if subject name was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx, + const char *subject_name ); + +/** + * \brief Set the subject public key for the certificate + * + * \param ctx CRT context to use + * \param key public key to include + */ +void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ); + +/** + * \brief Set the issuer key used for signing the certificate + * + * \param ctx CRT context to use + * \param key private key to sign with + */ +void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ); + +/** + * \brief Set the MD algorithm to use for the signature + * (e.g. MBEDTLS_MD_SHA1) + * + * \param ctx CRT context to use + * \param md_alg MD algorithm to use + */ +void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, mbedtls_md_type_t md_alg ); + +/** + * \brief Generic function to add to or replace an extension in the + * CRT + * + * \param ctx CRT context to use + * \param oid OID of the extension + * \param oid_len length of the OID + * \param critical if the extension is critical (per the RFC's definition) + * \param val value of the extension OCTET STRING + * \param val_len length of the value data + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx, + const char *oid, size_t oid_len, + int critical, + const unsigned char *val, size_t val_len ); + +/** + * \brief Set the basicConstraints extension for a CRT + * + * \param ctx CRT context to use + * \param is_ca is this a CA certificate + * \param max_pathlen maximum length of certificate chains below this + * certificate (only for CA certificates, -1 is + * inlimited) + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx, + int is_ca, int max_pathlen ); + +#if defined(MBEDTLS_SHA1_C) +/** + * \brief Set the subjectKeyIdentifier extension for a CRT + * Requires that mbedtls_x509write_crt_set_subject_key() has been + * called before + * + * \param ctx CRT context to use + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx ); + +/** + * \brief Set the authorityKeyIdentifier extension for a CRT + * Requires that mbedtls_x509write_crt_set_issuer_key() has been + * called before + * + * \param ctx CRT context to use + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx ); +#endif /* MBEDTLS_SHA1_C */ + +/** + * \brief Set the Key Usage Extension flags + * (e.g. MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN) + * + * \param ctx CRT context to use + * \param key_usage key usage flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx, + unsigned int key_usage ); + +/** + * \brief Set the Netscape Cert Type flags + * (e.g. MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT | MBEDTLS_X509_NS_CERT_TYPE_EMAIL) + * + * \param ctx CRT context to use + * \param ns_cert_type Netscape Cert Type flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, + unsigned char ns_cert_type ); + +/** + * \brief Free the contents of a CRT write context + * + * \param ctx CRT context to free + */ +void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx ); + +/** + * \brief Write a built up certificate to a X509 DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx certificate to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return length of data written if successful, or a specific + * error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a built up certificate to a X509 PEM string + * + * \param ctx certificate to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return 0 if successful, or a specific error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_X509_CRT_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_x509_crt.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/x509_csr.h b/c++/src/connect/mbedtls/mbedtls/x509_csr.h new file mode 100644 index 00000000..fe9843cb --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/x509_csr.h @@ -0,0 +1,298 @@ +/** + * \file x509_csr.h + * + * \brief X.509 certificate signing request parsing and writing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_X509_CSR_H +#define MBEDTLS_X509_CSR_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include "x509.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \addtogroup x509_module + * \{ */ + +/** + * \name Structures and functions for X.509 Certificate Signing Requests (CSR) + * \{ + */ + +/** + * Certificate Signing Request (CSR) structure. + */ +typedef struct mbedtls_x509_csr +{ + mbedtls_x509_buf raw; /**< The raw CSR data (DER). */ + mbedtls_x509_buf cri; /**< The raw CertificateRequestInfo body (DER). */ + + int version; /**< CSR version (1=v1). */ + + mbedtls_x509_buf subject_raw; /**< The raw subject data (DER). */ + mbedtls_x509_name subject; /**< The parsed subject data (named information object). */ + + mbedtls_pk_context pk; /**< Container for the public key context. */ + + mbedtls_x509_buf sig_oid; + mbedtls_x509_buf sig; + mbedtls_md_type_t sig_md; /**< Internal representation of the MD algorithm of the signature algorithm, e.g. MBEDTLS_MD_SHA256 */ + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ +} +mbedtls_x509_csr; + +/** + * Container for writing a CSR + */ +typedef struct mbedtls_x509write_csr +{ + mbedtls_pk_context *key; + mbedtls_asn1_named_data *subject; + mbedtls_md_type_t md_alg; + mbedtls_asn1_named_data *extensions; +} +mbedtls_x509write_csr; + +#if defined(MBEDTLS_X509_CSR_PARSE_C) +/** + * \brief Load a Certificate Signing Request (CSR) in DER format + * + * \note CSR attributes (if any) are currently silently ignored. + * + * \param csr CSR context to fill + * \param buf buffer holding the CRL data + * \param buflen size of the buffer + * + * \return 0 if successful, or a specific X509 error code + */ +int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, + const unsigned char *buf, size_t buflen ); + +/** + * \brief Load a Certificate Signing Request (CSR), DER or PEM format + * + * \note See notes for \c mbedtls_x509_csr_parse_der() + * + * \param csr CSR context to fill + * \param buf buffer holding the CRL data + * \param buflen size of the buffer + * (including the terminating null byte for PEM data) + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen ); + +#if defined(MBEDTLS_FS_IO) +/** + * \brief Load a Certificate Signing Request (CSR) + * + * \note See notes for \c mbedtls_x509_csr_parse() + * + * \param csr CSR context to fill + * \param path filename to read the CSR from + * + * \return 0 if successful, or a specific X509 or PEM error code + */ +int mbedtls_x509_csr_parse_file( mbedtls_x509_csr *csr, const char *path ); +#endif /* MBEDTLS_FS_IO */ + +/** + * \brief Returns an informational string about the + * CSR. + * + * \param buf Buffer to write to + * \param size Maximum size of buffer + * \param prefix A line prefix + * \param csr The X509 CSR to represent + * + * \return The length of the string written (not including the + * terminated nul byte), or a negative error code. + */ +int mbedtls_x509_csr_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_csr *csr ); + +/** + * \brief Initialize a CSR + * + * \param csr CSR to initialize + */ +void mbedtls_x509_csr_init( mbedtls_x509_csr *csr ); + +/** + * \brief Unallocate all CSR data + * + * \param csr CSR to free + */ +void mbedtls_x509_csr_free( mbedtls_x509_csr *csr ); +#endif /* MBEDTLS_X509_CSR_PARSE_C */ + +/* \} name */ +/* \} addtogroup x509_module */ + +#if defined(MBEDTLS_X509_CSR_WRITE_C) +/** + * \brief Initialize a CSR context + * + * \param ctx CSR context to initialize + */ +void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx ); + +/** + * \brief Set the subject name for a CSR + * Subject names should contain a comma-separated list + * of OID types and values: + * e.g. "C=UK,O=ARM,CN=mbed TLS Server 1" + * + * \param ctx CSR context to use + * \param subject_name subject name to set + * + * \return 0 if subject name was parsed successfully, or + * a specific error code + */ +int mbedtls_x509write_csr_set_subject_name( mbedtls_x509write_csr *ctx, + const char *subject_name ); + +/** + * \brief Set the key for a CSR (public key will be included, + * private key used to sign the CSR when writing it) + * + * \param ctx CSR context to use + * \param key Asymetric key to include + */ +void mbedtls_x509write_csr_set_key( mbedtls_x509write_csr *ctx, mbedtls_pk_context *key ); + +/** + * \brief Set the MD algorithm to use for the signature + * (e.g. MBEDTLS_MD_SHA1) + * + * \param ctx CSR context to use + * \param md_alg MD algorithm to use + */ +void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg ); + +/** + * \brief Set the Key Usage Extension flags + * (e.g. MBEDTLS_X509_KU_DIGITAL_SIGNATURE | MBEDTLS_X509_KU_KEY_CERT_SIGN) + * + * \param ctx CSR context to use + * \param key_usage key usage flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage ); + +/** + * \brief Set the Netscape Cert Type flags + * (e.g. MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT | MBEDTLS_X509_NS_CERT_TYPE_EMAIL) + * + * \param ctx CSR context to use + * \param ns_cert_type Netscape Cert Type flags to set + * + * \return 0 if successful, or MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_csr_set_ns_cert_type( mbedtls_x509write_csr *ctx, + unsigned char ns_cert_type ); + +/** + * \brief Generic function to add to or replace an extension in the + * CSR + * + * \param ctx CSR context to use + * \param oid OID of the extension + * \param oid_len length of the OID + * \param val value of the extension OCTET STRING + * \param val_len length of the value data + * + * \return 0 if successful, or a MBEDTLS_ERR_X509_ALLOC_FAILED + */ +int mbedtls_x509write_csr_set_extension( mbedtls_x509write_csr *ctx, + const char *oid, size_t oid_len, + const unsigned char *val, size_t val_len ); + +/** + * \brief Free the contents of a CSR context + * + * \param ctx CSR context to free + */ +void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx ); + +/** + * \brief Write a CSR (Certificate Signing Request) to a + * DER structure + * Note: data is written at the end of the buffer! Use the + * return value to determine where you should start + * using the buffer + * + * \param ctx CSR to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return length of data written if successful, or a specific + * error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); + +#if defined(MBEDTLS_PEM_WRITE_C) +/** + * \brief Write a CSR (Certificate Signing Request) to a + * PEM string + * + * \param ctx CSR to write away + * \param buf buffer to write to + * \param size size of the buffer + * \param f_rng RNG function (for signature, see note) + * \param p_rng RNG parameter + * + * \return 0 if successful, or a specific error code + * + * \note f_rng may be NULL if RSA is used for signature and the + * signature is made offline (otherwise f_rng is desirable + * for countermeasures against timing attacks). + * ECDSA signatures always require a non-NULL f_rng. + */ +int mbedtls_x509write_csr_pem( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ); +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_X509_CSR_WRITE_C */ + +#ifdef __cplusplus +} +#endif + +#endif /* mbedtls_x509_csr.h */ diff --git a/c++/src/connect/mbedtls/mbedtls/xtea.h b/c++/src/connect/mbedtls/mbedtls/xtea.h new file mode 100644 index 00000000..b073f84e --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls/xtea.h @@ -0,0 +1,139 @@ +/** + * \file xtea.h + * + * \brief XTEA block cipher (32-bit) + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +#ifndef MBEDTLS_XTEA_H +#define MBEDTLS_XTEA_H + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#include +#include + +#define MBEDTLS_XTEA_ENCRYPT 1 +#define MBEDTLS_XTEA_DECRYPT 0 + +#define MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH -0x0028 /**< The data input has an invalid length. */ + +#if !defined(MBEDTLS_XTEA_ALT) +// Regular implementation +// + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief XTEA context structure + */ +typedef struct +{ + uint32_t k[4]; /*!< key */ +} +mbedtls_xtea_context; + +/** + * \brief Initialize XTEA context + * + * \param ctx XTEA context to be initialized + */ +void mbedtls_xtea_init( mbedtls_xtea_context *ctx ); + +/** + * \brief Clear XTEA context + * + * \param ctx XTEA context to be cleared + */ +void mbedtls_xtea_free( mbedtls_xtea_context *ctx ); + +/** + * \brief XTEA key schedule + * + * \param ctx XTEA context to be initialized + * \param key the secret key + */ +void mbedtls_xtea_setup( mbedtls_xtea_context *ctx, const unsigned char key[16] ); + +/** + * \brief XTEA cipher function + * + * \param ctx XTEA context + * \param mode MBEDTLS_XTEA_ENCRYPT or MBEDTLS_XTEA_DECRYPT + * \param input 8-byte input block + * \param output 8-byte output block + * + * \return 0 if successful + */ +int mbedtls_xtea_crypt_ecb( mbedtls_xtea_context *ctx, + int mode, + const unsigned char input[8], + unsigned char output[8] ); + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/** + * \brief XTEA CBC cipher function + * + * \param ctx XTEA context + * \param mode MBEDTLS_XTEA_ENCRYPT or MBEDTLS_XTEA_DECRYPT + * \param length the length of input, multiple of 8 + * \param iv initialization vector for CBC mode + * \param input input block + * \param output output block + * + * \return 0 if successful, + * MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH if the length % 8 != 0 + */ +int mbedtls_xtea_crypt_cbc( mbedtls_xtea_context *ctx, + int mode, + size_t length, + unsigned char iv[8], + const unsigned char *input, + unsigned char *output); +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#ifdef __cplusplus +} +#endif + +#else /* MBEDTLS_XTEA_ALT */ +#include "xtea_alt.h" +#endif /* MBEDTLS_XTEA_ALT */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Checkup routine + * + * \return 0 if successful, or 1 if the test failed + */ +int mbedtls_xtea_self_test( int verbose ); + +#ifdef __cplusplus +} +#endif + +#endif /* xtea.h */ diff --git a/c++/src/connect/mbedtls/mbedtls_md5.c b/c++/src/connect/mbedtls/mbedtls_md5.c new file mode 100644 index 00000000..5d972dc9 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls_md5.c @@ -0,0 +1,404 @@ +/* + * RFC 1321 compliant MD5 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The MD5 algorithm was designed by Ron Rivest in 1991. + * + * http://www.ietf.org/rfc/rfc1321.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD5_C) + +#include "mbedtls/md5.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_MD5_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +void mbedtls_md5_init( mbedtls_md5_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md5_context ) ); +} + +void mbedtls_md5_free( mbedtls_md5_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_md5_context ) ); +} + +void mbedtls_md5_clone( mbedtls_md5_context *dst, + const mbedtls_md5_context *src ) +{ + *dst = *src; +} + +/* + * MD5 context setup + */ +void mbedtls_md5_starts( mbedtls_md5_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +#if !defined(MBEDTLS_MD5_PROCESS_ALT) +void mbedtls_md5_process( mbedtls_md5_context *ctx, const unsigned char data[64] ) +{ + uint32_t X[16], A, B, C, D; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define P(a,b,c,d,k,s,t) \ +{ \ + a += F(b,c,d) + X[k] + t; a = S(a,s) + b; \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) + + P( A, B, C, D, 0, 7, 0xD76AA478 ); + P( D, A, B, C, 1, 12, 0xE8C7B756 ); + P( C, D, A, B, 2, 17, 0x242070DB ); + P( B, C, D, A, 3, 22, 0xC1BDCEEE ); + P( A, B, C, D, 4, 7, 0xF57C0FAF ); + P( D, A, B, C, 5, 12, 0x4787C62A ); + P( C, D, A, B, 6, 17, 0xA8304613 ); + P( B, C, D, A, 7, 22, 0xFD469501 ); + P( A, B, C, D, 8, 7, 0x698098D8 ); + P( D, A, B, C, 9, 12, 0x8B44F7AF ); + P( C, D, A, B, 10, 17, 0xFFFF5BB1 ); + P( B, C, D, A, 11, 22, 0x895CD7BE ); + P( A, B, C, D, 12, 7, 0x6B901122 ); + P( D, A, B, C, 13, 12, 0xFD987193 ); + P( C, D, A, B, 14, 17, 0xA679438E ); + P( B, C, D, A, 15, 22, 0x49B40821 ); + +#undef F + +#define F(x,y,z) (y ^ (z & (x ^ y))) + + P( A, B, C, D, 1, 5, 0xF61E2562 ); + P( D, A, B, C, 6, 9, 0xC040B340 ); + P( C, D, A, B, 11, 14, 0x265E5A51 ); + P( B, C, D, A, 0, 20, 0xE9B6C7AA ); + P( A, B, C, D, 5, 5, 0xD62F105D ); + P( D, A, B, C, 10, 9, 0x02441453 ); + P( C, D, A, B, 15, 14, 0xD8A1E681 ); + P( B, C, D, A, 4, 20, 0xE7D3FBC8 ); + P( A, B, C, D, 9, 5, 0x21E1CDE6 ); + P( D, A, B, C, 14, 9, 0xC33707D6 ); + P( C, D, A, B, 3, 14, 0xF4D50D87 ); + P( B, C, D, A, 8, 20, 0x455A14ED ); + P( A, B, C, D, 13, 5, 0xA9E3E905 ); + P( D, A, B, C, 2, 9, 0xFCEFA3F8 ); + P( C, D, A, B, 7, 14, 0x676F02D9 ); + P( B, C, D, A, 12, 20, 0x8D2A4C8A ); + +#undef F + +#define F(x,y,z) (x ^ y ^ z) + + P( A, B, C, D, 5, 4, 0xFFFA3942 ); + P( D, A, B, C, 8, 11, 0x8771F681 ); + P( C, D, A, B, 11, 16, 0x6D9D6122 ); + P( B, C, D, A, 14, 23, 0xFDE5380C ); + P( A, B, C, D, 1, 4, 0xA4BEEA44 ); + P( D, A, B, C, 4, 11, 0x4BDECFA9 ); + P( C, D, A, B, 7, 16, 0xF6BB4B60 ); + P( B, C, D, A, 10, 23, 0xBEBFBC70 ); + P( A, B, C, D, 13, 4, 0x289B7EC6 ); + P( D, A, B, C, 0, 11, 0xEAA127FA ); + P( C, D, A, B, 3, 16, 0xD4EF3085 ); + P( B, C, D, A, 6, 23, 0x04881D05 ); + P( A, B, C, D, 9, 4, 0xD9D4D039 ); + P( D, A, B, C, 12, 11, 0xE6DB99E5 ); + P( C, D, A, B, 15, 16, 0x1FA27CF8 ); + P( B, C, D, A, 2, 23, 0xC4AC5665 ); + +#undef F + +#define F(x,y,z) (y ^ (x | ~z)) + + P( A, B, C, D, 0, 6, 0xF4292244 ); + P( D, A, B, C, 7, 10, 0x432AFF97 ); + P( C, D, A, B, 14, 15, 0xAB9423A7 ); + P( B, C, D, A, 5, 21, 0xFC93A039 ); + P( A, B, C, D, 12, 6, 0x655B59C3 ); + P( D, A, B, C, 3, 10, 0x8F0CCC92 ); + P( C, D, A, B, 10, 15, 0xFFEFF47D ); + P( B, C, D, A, 1, 21, 0x85845DD1 ); + P( A, B, C, D, 8, 6, 0x6FA87E4F ); + P( D, A, B, C, 15, 10, 0xFE2CE6E0 ); + P( C, D, A, B, 6, 15, 0xA3014314 ); + P( B, C, D, A, 13, 21, 0x4E0811A1 ); + P( A, B, C, D, 4, 6, 0xF7537E82 ); + P( D, A, B, C, 11, 10, 0xBD3AF235 ); + P( C, D, A, B, 2, 15, 0x2AD7D2BB ); + P( B, C, D, A, 9, 21, 0xEB86D391 ); + +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} +#endif /* !MBEDTLS_MD5_PROCESS_ALT */ + +/* + * MD5 process buffer + */ +void mbedtls_md5_update( mbedtls_md5_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_md5_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_md5_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } +} + +static const unsigned char md5_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD5 final digest + */ +void mbedtls_md5_finish( mbedtls_md5_context *ctx, unsigned char output[16] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_md5_update( ctx, md5_padding, padn ); + mbedtls_md5_update( ctx, msglen, 8 ); + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); +} + +#endif /* !MBEDTLS_MD5_ALT */ + +/* + * output = MD5( input buffer ) + */ +void mbedtls_md5( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + mbedtls_md5_context ctx; + + mbedtls_md5_init( &ctx ); + mbedtls_md5_starts( &ctx ); + mbedtls_md5_update( &ctx, input, ilen ); + mbedtls_md5_finish( &ctx, output ); + mbedtls_md5_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * RFC 1321 test vectors + */ +static const unsigned char md5_test_buf[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" \ + "345678901234567890" } +}; + +static const int md5_test_buflen[7] = +{ + 0, 1, 3, 14, 26, 62, 80 +}; + +static const unsigned char md5_test_sum[7][16] = +{ + { 0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04, + 0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E }, + { 0x0C, 0xC1, 0x75, 0xB9, 0xC0, 0xF1, 0xB6, 0xA8, + 0x31, 0xC3, 0x99, 0xE2, 0x69, 0x77, 0x26, 0x61 }, + { 0x90, 0x01, 0x50, 0x98, 0x3C, 0xD2, 0x4F, 0xB0, + 0xD6, 0x96, 0x3F, 0x7D, 0x28, 0xE1, 0x7F, 0x72 }, + { 0xF9, 0x6B, 0x69, 0x7D, 0x7C, 0xB7, 0x93, 0x8D, + 0x52, 0x5A, 0x2F, 0x31, 0xAA, 0xF1, 0x61, 0xD0 }, + { 0xC3, 0xFC, 0xD3, 0xD7, 0x61, 0x92, 0xE4, 0x00, + 0x7D, 0xFB, 0x49, 0x6C, 0xCA, 0x67, 0xE1, 0x3B }, + { 0xD1, 0x74, 0xAB, 0x98, 0xD2, 0x77, 0xD9, 0xF5, + 0xA5, 0x61, 0x1C, 0x2C, 0x9F, 0x41, 0x9D, 0x9F }, + { 0x57, 0xED, 0xF4, 0xA2, 0x2B, 0xE3, 0xC9, 0x55, + 0xAC, 0x49, 0xDA, 0x2E, 0x21, 0x07, 0xB6, 0x7A } +}; + +/* + * Checkup routine + */ +int mbedtls_md5_self_test( int verbose ) +{ + int i; + unsigned char md5sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD5 test #%d: ", i + 1 ); + + mbedtls_md5( md5_test_buf[i], md5_test_buflen[i], md5sum ); + + if( memcmp( md5sum, md5_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD5_C */ diff --git a/c++/src/connect/mbedtls/mbedtls_version.c b/c++/src/connect/mbedtls/mbedtls_version.c new file mode 100644 index 00000000..6ca80d46 --- /dev/null +++ b/c++/src/connect/mbedtls/mbedtls_version.c @@ -0,0 +1,50 @@ +/* + * Version information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_VERSION_C) + +#include "mbedtls/version.h" +#include + +unsigned int mbedtls_version_get_number() +{ + return( MBEDTLS_VERSION_NUMBER ); +} + +void mbedtls_version_get_string( char *string ) +{ + memcpy( string, MBEDTLS_VERSION_STRING, + sizeof( MBEDTLS_VERSION_STRING ) ); +} + +void mbedtls_version_get_string_full( char *string ) +{ + memcpy( string, MBEDTLS_VERSION_STRING_FULL, + sizeof( MBEDTLS_VERSION_STRING_FULL ) ); +} + +#endif /* MBEDTLS_VERSION_C */ diff --git a/c++/src/connect/mbedtls/md.c b/c++/src/connect/mbedtls/md.c new file mode 100644 index 00000000..eda98f63 --- /dev/null +++ b/c++/src/connect/mbedtls/md.c @@ -0,0 +1,471 @@ +/** + * \file mbedtls_md.c + * + * \brief Generic message digest wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD_C) + +#include "mbedtls/md.h" +#include "mbedtls/md_internal.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +#if defined(MBEDTLS_FS_IO) +#include +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Reminder: update profiles in x509_crt.c when adding a new hash! + */ +static const int supported_digests[] = { + +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_MD_SHA512, + MBEDTLS_MD_SHA384, +#endif + +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA224, +#endif + +#if defined(MBEDTLS_SHA1_C) + MBEDTLS_MD_SHA1, +#endif + +#if defined(MBEDTLS_RIPEMD160_C) + MBEDTLS_MD_RIPEMD160, +#endif + +#if defined(MBEDTLS_MD5_C) + MBEDTLS_MD_MD5, +#endif + +#if defined(MBEDTLS_MD4_C) + MBEDTLS_MD_MD4, +#endif + +#if defined(MBEDTLS_MD2_C) + MBEDTLS_MD_MD2, +#endif + + MBEDTLS_MD_NONE +}; + +const int *mbedtls_md_list( void ) +{ + return( supported_digests ); +} + +const mbedtls_md_info_t *mbedtls_md_info_from_string( const char *md_name ) +{ + if( NULL == md_name ) + return( NULL ); + + /* Get the appropriate digest information */ +#if defined(MBEDTLS_MD2_C) + if( !strcmp( "MD2", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD2 ); +#endif +#if defined(MBEDTLS_MD4_C) + if( !strcmp( "MD4", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD4 ); +#endif +#if defined(MBEDTLS_MD5_C) + if( !strcmp( "MD5", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_MD5 ); +#endif +#if defined(MBEDTLS_RIPEMD160_C) + if( !strcmp( "RIPEMD160", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_RIPEMD160 ); +#endif +#if defined(MBEDTLS_SHA1_C) + if( !strcmp( "SHA1", md_name ) || !strcmp( "SHA", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); +#endif +#if defined(MBEDTLS_SHA256_C) + if( !strcmp( "SHA224", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA224 ); + if( !strcmp( "SHA256", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + if( !strcmp( "SHA384", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA384 ); + if( !strcmp( "SHA512", md_name ) ) + return mbedtls_md_info_from_type( MBEDTLS_MD_SHA512 ); +#endif + return( NULL ); +} + +const mbedtls_md_info_t *mbedtls_md_info_from_type( mbedtls_md_type_t md_type ) +{ + switch( md_type ) + { +#if defined(MBEDTLS_MD2_C) + case MBEDTLS_MD_MD2: + return( &mbedtls_md2_info ); +#endif +#if defined(MBEDTLS_MD4_C) + case MBEDTLS_MD_MD4: + return( &mbedtls_md4_info ); +#endif +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_MD_MD5: + return( &mbedtls_md5_info ); +#endif +#if defined(MBEDTLS_RIPEMD160_C) + case MBEDTLS_MD_RIPEMD160: + return( &mbedtls_ripemd160_info ); +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_MD_SHA1: + return( &mbedtls_sha1_info ); +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_MD_SHA224: + return( &mbedtls_sha224_info ); + case MBEDTLS_MD_SHA256: + return( &mbedtls_sha256_info ); +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_MD_SHA384: + return( &mbedtls_sha384_info ); + case MBEDTLS_MD_SHA512: + return( &mbedtls_sha512_info ); +#endif + default: + return( NULL ); + } +} + +void mbedtls_md_init( mbedtls_md_context_t *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md_context_t ) ); +} + +void mbedtls_md_free( mbedtls_md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return; + + if( ctx->md_ctx != NULL ) + ctx->md_info->ctx_free_func( ctx->md_ctx ); + + if( ctx->hmac_ctx != NULL ) + { + mbedtls_zeroize( ctx->hmac_ctx, 2 * ctx->md_info->block_size ); + mbedtls_free( ctx->hmac_ctx ); + } + + mbedtls_zeroize( ctx, sizeof( mbedtls_md_context_t ) ); +} + +int mbedtls_md_clone( mbedtls_md_context_t *dst, + const mbedtls_md_context_t *src ) +{ + if( dst == NULL || dst->md_info == NULL || + src == NULL || src->md_info == NULL || + dst->md_info != src->md_info ) + { + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + } + + dst->md_info->clone_func( dst->md_ctx, src->md_ctx ); + + return( 0 ); +} + +#if ! defined(MBEDTLS_DEPRECATED_REMOVED) +int mbedtls_md_init_ctx( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info ) +{ + return mbedtls_md_setup( ctx, md_info, 1 ); +} +#endif + +int mbedtls_md_setup( mbedtls_md_context_t *ctx, const mbedtls_md_info_t *md_info, int hmac ) +{ + if( md_info == NULL || ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( ( ctx->md_ctx = md_info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_MD_ALLOC_FAILED ); + + if( hmac != 0 ) + { + ctx->hmac_ctx = mbedtls_calloc( 2, md_info->block_size ); + if( ctx->hmac_ctx == NULL ) + { + md_info->ctx_free_func( ctx->md_ctx ); + return( MBEDTLS_ERR_MD_ALLOC_FAILED ); + } + } + + ctx->md_info = md_info; + + return( 0 ); +} + +int mbedtls_md_starts( mbedtls_md_context_t *ctx ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->starts_func( ctx->md_ctx ); + + return( 0 ); +} + +int mbedtls_md_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->update_func( ctx->md_ctx, input, ilen ); + + return( 0 ); +} + +int mbedtls_md_finish( mbedtls_md_context_t *ctx, unsigned char *output ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->finish_func( ctx->md_ctx, output ); + + return( 0 ); +} + +int mbedtls_md( const mbedtls_md_info_t *md_info, const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + md_info->digest_func( input, ilen, output ); + + return( 0 ); +} + +#if defined(MBEDTLS_FS_IO) +int mbedtls_md_file( const mbedtls_md_info_t *md_info, const char *path, unsigned char *output ) +{ + int ret; + FILE *f; + size_t n; + mbedtls_md_context_t ctx; + unsigned char buf[1024]; + + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_MD_FILE_IO_ERROR ); + + mbedtls_md_init( &ctx ); + + if( ( ret = mbedtls_md_setup( &ctx, md_info, 0 ) ) != 0 ) + goto cleanup; + + md_info->starts_func( ctx.md_ctx ); + + while( ( n = fread( buf, 1, sizeof( buf ), f ) ) > 0 ) + md_info->update_func( ctx.md_ctx, buf, n ); + + if( ferror( f ) != 0 ) + { + ret = MBEDTLS_ERR_MD_FILE_IO_ERROR; + goto cleanup; + } + + md_info->finish_func( ctx.md_ctx, output ); + +cleanup: + fclose( f ); + mbedtls_md_free( &ctx ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +int mbedtls_md_hmac_starts( mbedtls_md_context_t *ctx, const unsigned char *key, size_t keylen ) +{ + unsigned char sum[MBEDTLS_MD_MAX_SIZE]; + unsigned char *ipad, *opad; + size_t i; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + if( keylen > (size_t) ctx->md_info->block_size ) + { + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, key, keylen ); + ctx->md_info->finish_func( ctx->md_ctx, sum ); + + keylen = ctx->md_info->size; + key = sum; + } + + ipad = (unsigned char *) ctx->hmac_ctx; + opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size; + + memset( ipad, 0x36, ctx->md_info->block_size ); + memset( opad, 0x5C, ctx->md_info->block_size ); + + for( i = 0; i < keylen; i++ ) + { + ipad[i] = (unsigned char)( ipad[i] ^ key[i] ); + opad[i] = (unsigned char)( opad[i] ^ key[i] ); + } + + mbedtls_zeroize( sum, sizeof( sum ) ); + + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, ipad, ctx->md_info->block_size ); + + return( 0 ); +} + +int mbedtls_md_hmac_update( mbedtls_md_context_t *ctx, const unsigned char *input, size_t ilen ) +{ + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->update_func( ctx->md_ctx, input, ilen ); + + return( 0 ); +} + +int mbedtls_md_hmac_finish( mbedtls_md_context_t *ctx, unsigned char *output ) +{ + unsigned char tmp[MBEDTLS_MD_MAX_SIZE]; + unsigned char *opad; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + opad = (unsigned char *) ctx->hmac_ctx + ctx->md_info->block_size; + + ctx->md_info->finish_func( ctx->md_ctx, tmp ); + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, opad, ctx->md_info->block_size ); + ctx->md_info->update_func( ctx->md_ctx, tmp, ctx->md_info->size ); + ctx->md_info->finish_func( ctx->md_ctx, output ); + + return( 0 ); +} + +int mbedtls_md_hmac_reset( mbedtls_md_context_t *ctx ) +{ + unsigned char *ipad; + + if( ctx == NULL || ctx->md_info == NULL || ctx->hmac_ctx == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ipad = (unsigned char *) ctx->hmac_ctx; + + ctx->md_info->starts_func( ctx->md_ctx ); + ctx->md_info->update_func( ctx->md_ctx, ipad, ctx->md_info->block_size ); + + return( 0 ); +} + +int mbedtls_md_hmac( const mbedtls_md_info_t *md_info, const unsigned char *key, size_t keylen, + const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_md_context_t ctx; + int ret; + + if( md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + mbedtls_md_init( &ctx ); + + if( ( ret = mbedtls_md_setup( &ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + mbedtls_md_hmac_starts( &ctx, key, keylen ); + mbedtls_md_hmac_update( &ctx, input, ilen ); + mbedtls_md_hmac_finish( &ctx, output ); + + mbedtls_md_free( &ctx ); + + return( 0 ); +} + +int mbedtls_md_process( mbedtls_md_context_t *ctx, const unsigned char *data ) +{ + if( ctx == NULL || ctx->md_info == NULL ) + return( MBEDTLS_ERR_MD_BAD_INPUT_DATA ); + + ctx->md_info->process_func( ctx->md_ctx, data ); + + return( 0 ); +} + +unsigned char mbedtls_md_get_size( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( 0 ); + + return md_info->size; +} + +mbedtls_md_type_t mbedtls_md_get_type( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( MBEDTLS_MD_NONE ); + + return md_info->type; +} + +const char *mbedtls_md_get_name( const mbedtls_md_info_t *md_info ) +{ + if( md_info == NULL ) + return( NULL ); + + return md_info->name; +} + +#endif /* MBEDTLS_MD_C */ diff --git a/c++/src/connect/mbedtls/md2.c b/c++/src/connect/mbedtls/md2.c new file mode 100644 index 00000000..95cbcce6 --- /dev/null +++ b/c++/src/connect/mbedtls/md2.c @@ -0,0 +1,288 @@ +/* + * RFC 1115/1319 compliant MD2 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The MD2 algorithm was designed by Ron Rivest in 1989. + * + * http://www.ietf.org/rfc/rfc1115.txt + * http://www.ietf.org/rfc/rfc1319.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD2_C) + +#include "mbedtls/md2.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_MD2_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +static const unsigned char PI_SUBST[256] = +{ + 0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, + 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13, 0x62, 0xA7, 0x05, 0xF3, + 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, + 0x82, 0xCA, 0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, + 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12, 0xBE, 0x4E, + 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, + 0xBB, 0x2F, 0xEE, 0x7A, 0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, + 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21, + 0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, + 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03, 0xFF, 0x19, 0x30, 0xB3, + 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, + 0xAA, 0xC6, 0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, + 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1, 0x45, 0x9D, + 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, + 0xE6, 0x2D, 0xA8, 0x02, 0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, + 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F, + 0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, + 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26, 0x2C, 0x53, 0x0D, 0x6E, + 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, + 0x4D, 0x52, 0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, + 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A, 0x78, 0x88, + 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, + 0x3B, 0x00, 0x1D, 0x39, 0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, + 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A, + 0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, + 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14 +}; + +void mbedtls_md2_init( mbedtls_md2_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md2_context ) ); +} + +void mbedtls_md2_free( mbedtls_md2_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_md2_context ) ); +} + +void mbedtls_md2_clone( mbedtls_md2_context *dst, + const mbedtls_md2_context *src ) +{ + *dst = *src; +} + +/* + * MD2 context setup + */ +void mbedtls_md2_starts( mbedtls_md2_context *ctx ) +{ + memset( ctx->cksum, 0, 16 ); + memset( ctx->state, 0, 46 ); + memset( ctx->buffer, 0, 16 ); + ctx->left = 0; +} + +#if !defined(MBEDTLS_MD2_PROCESS_ALT) +void mbedtls_md2_process( mbedtls_md2_context *ctx ) +{ + int i, j; + unsigned char t = 0; + + for( i = 0; i < 16; i++ ) + { + ctx->state[i + 16] = ctx->buffer[i]; + ctx->state[i + 32] = + (unsigned char)( ctx->buffer[i] ^ ctx->state[i]); + } + + for( i = 0; i < 18; i++ ) + { + for( j = 0; j < 48; j++ ) + { + ctx->state[j] = (unsigned char) + ( ctx->state[j] ^ PI_SUBST[t] ); + t = ctx->state[j]; + } + + t = (unsigned char)( t + i ); + } + + t = ctx->cksum[15]; + + for( i = 0; i < 16; i++ ) + { + ctx->cksum[i] = (unsigned char) + ( ctx->cksum[i] ^ PI_SUBST[ctx->buffer[i] ^ t] ); + t = ctx->cksum[i]; + } +} +#endif /* !MBEDTLS_MD2_PROCESS_ALT */ + +/* + * MD2 process buffer + */ +void mbedtls_md2_update( mbedtls_md2_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + + while( ilen > 0 ) + { + if( ilen > 16 - ctx->left ) + fill = 16 - ctx->left; + else + fill = ilen; + + memcpy( ctx->buffer + ctx->left, input, fill ); + + ctx->left += fill; + input += fill; + ilen -= fill; + + if( ctx->left == 16 ) + { + ctx->left = 0; + mbedtls_md2_process( ctx ); + } + } +} + +/* + * MD2 final digest + */ +void mbedtls_md2_finish( mbedtls_md2_context *ctx, unsigned char output[16] ) +{ + size_t i; + unsigned char x; + + x = (unsigned char)( 16 - ctx->left ); + + for( i = ctx->left; i < 16; i++ ) + ctx->buffer[i] = x; + + mbedtls_md2_process( ctx ); + + memcpy( ctx->buffer, ctx->cksum, 16 ); + mbedtls_md2_process( ctx ); + + memcpy( output, ctx->state, 16 ); +} + +#endif /* !MBEDTLS_MD2_ALT */ + +/* + * output = MD2( input buffer ) + */ +void mbedtls_md2( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + mbedtls_md2_context ctx; + + mbedtls_md2_init( &ctx ); + mbedtls_md2_starts( &ctx ); + mbedtls_md2_update( &ctx, input, ilen ); + mbedtls_md2_finish( &ctx, output ); + mbedtls_md2_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * RFC 1319 test vectors + */ +static const char md2_test_str[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" \ + "345678901234567890" } +}; + +static const unsigned char md2_test_sum[7][16] = +{ + { 0x83, 0x50, 0xE5, 0xA3, 0xE2, 0x4C, 0x15, 0x3D, + 0xF2, 0x27, 0x5C, 0x9F, 0x80, 0x69, 0x27, 0x73 }, + { 0x32, 0xEC, 0x01, 0xEC, 0x4A, 0x6D, 0xAC, 0x72, + 0xC0, 0xAB, 0x96, 0xFB, 0x34, 0xC0, 0xB5, 0xD1 }, + { 0xDA, 0x85, 0x3B, 0x0D, 0x3F, 0x88, 0xD9, 0x9B, + 0x30, 0x28, 0x3A, 0x69, 0xE6, 0xDE, 0xD6, 0xBB }, + { 0xAB, 0x4F, 0x49, 0x6B, 0xFB, 0x2A, 0x53, 0x0B, + 0x21, 0x9F, 0xF3, 0x30, 0x31, 0xFE, 0x06, 0xB0 }, + { 0x4E, 0x8D, 0xDF, 0xF3, 0x65, 0x02, 0x92, 0xAB, + 0x5A, 0x41, 0x08, 0xC3, 0xAA, 0x47, 0x94, 0x0B }, + { 0xDA, 0x33, 0xDE, 0xF2, 0xA4, 0x2D, 0xF1, 0x39, + 0x75, 0x35, 0x28, 0x46, 0xC3, 0x03, 0x38, 0xCD }, + { 0xD5, 0x97, 0x6F, 0x79, 0xD8, 0x3D, 0x3A, 0x0D, + 0xC9, 0x80, 0x6C, 0x3C, 0x66, 0xF3, 0xEF, 0xD8 } +}; + +/* + * Checkup routine + */ +int mbedtls_md2_self_test( int verbose ) +{ + int i; + unsigned char md2sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD2 test #%d: ", i + 1 ); + + mbedtls_md2( (unsigned char *) md2_test_str[i], + strlen( md2_test_str[i] ), md2sum ); + + if( memcmp( md2sum, md2_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD2_C */ diff --git a/c++/src/connect/mbedtls/md4.c b/c++/src/connect/mbedtls/md4.c new file mode 100644 index 00000000..11a77e3a --- /dev/null +++ b/c++/src/connect/mbedtls/md4.c @@ -0,0 +1,384 @@ +/* + * RFC 1186/1320 compliant MD4 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The MD4 algorithm was designed by Ron Rivest in 1990. + * + * http://www.ietf.org/rfc/rfc1186.txt + * http://www.ietf.org/rfc/rfc1320.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD4_C) + +#include "mbedtls/md4.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_MD4_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +void mbedtls_md4_init( mbedtls_md4_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_md4_context ) ); +} + +void mbedtls_md4_free( mbedtls_md4_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_md4_context ) ); +} + +void mbedtls_md4_clone( mbedtls_md4_context *dst, + const mbedtls_md4_context *src ) +{ + *dst = *src; +} + +/* + * MD4 context setup + */ +void mbedtls_md4_starts( mbedtls_md4_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; +} + +#if !defined(MBEDTLS_MD4_PROCESS_ALT) +void mbedtls_md4_process( mbedtls_md4_context *ctx, const unsigned char data[64] ) +{ + uint32_t X[16], A, B, C, D; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + +#define F(x, y, z) ((x & y) | ((~x) & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 1], 7 ); + P( C, D, A, B, X[ 2], 11 ); + P( B, C, D, A, X[ 3], 19 ); + P( A, B, C, D, X[ 4], 3 ); + P( D, A, B, C, X[ 5], 7 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[ 7], 19 ); + P( A, B, C, D, X[ 8], 3 ); + P( D, A, B, C, X[ 9], 7 ); + P( C, D, A, B, X[10], 11 ); + P( B, C, D, A, X[11], 19 ); + P( A, B, C, D, X[12], 3 ); + P( D, A, B, C, X[13], 7 ); + P( C, D, A, B, X[14], 11 ); + P( B, C, D, A, X[15], 19 ); + +#undef P +#undef F + +#define F(x,y,z) ((x & y) | (x & z) | (y & z)) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x5A827999; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 4], 5 ); + P( C, D, A, B, X[ 8], 9 ); + P( B, C, D, A, X[12], 13 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 5], 5 ); + P( C, D, A, B, X[ 9], 9 ); + P( B, C, D, A, X[13], 13 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[ 6], 5 ); + P( C, D, A, B, X[10], 9 ); + P( B, C, D, A, X[14], 13 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[ 7], 5 ); + P( C, D, A, B, X[11], 9 ); + P( B, C, D, A, X[15], 13 ); + +#undef P +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define P(a,b,c,d,x,s) { a += F(b,c,d) + x + 0x6ED9EBA1; a = S(a,s); } + + P( A, B, C, D, X[ 0], 3 ); + P( D, A, B, C, X[ 8], 9 ); + P( C, D, A, B, X[ 4], 11 ); + P( B, C, D, A, X[12], 15 ); + P( A, B, C, D, X[ 2], 3 ); + P( D, A, B, C, X[10], 9 ); + P( C, D, A, B, X[ 6], 11 ); + P( B, C, D, A, X[14], 15 ); + P( A, B, C, D, X[ 1], 3 ); + P( D, A, B, C, X[ 9], 9 ); + P( C, D, A, B, X[ 5], 11 ); + P( B, C, D, A, X[13], 15 ); + P( A, B, C, D, X[ 3], 3 ); + P( D, A, B, C, X[11], 9 ); + P( C, D, A, B, X[ 7], 11 ); + P( B, C, D, A, X[15], 15 ); + +#undef F +#undef P + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; +} +#endif /* !MBEDTLS_MD4_PROCESS_ALT */ + +/* + * MD4 process buffer + */ +void mbedtls_md4_update( mbedtls_md4_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, fill ); + mbedtls_md4_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_md4_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), + (void *) input, ilen ); + } +} + +static const unsigned char md4_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * MD4 final digest + */ +void mbedtls_md4_finish( mbedtls_md4_context *ctx, unsigned char output[16] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_md4_update( ctx, (unsigned char *) md4_padding, padn ); + mbedtls_md4_update( ctx, msglen, 8 ); + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); +} + +#endif /* !MBEDTLS_MD4_ALT */ + +/* + * output = MD4( input buffer ) + */ +void mbedtls_md4( const unsigned char *input, size_t ilen, unsigned char output[16] ) +{ + mbedtls_md4_context ctx; + + mbedtls_md4_init( &ctx ); + mbedtls_md4_starts( &ctx ); + mbedtls_md4_update( &ctx, input, ilen ); + mbedtls_md4_finish( &ctx, output ); + mbedtls_md4_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * RFC 1320 test vectors + */ +static const char md4_test_str[7][81] = +{ + { "" }, + { "a" }, + { "abc" }, + { "message digest" }, + { "abcdefghijklmnopqrstuvwxyz" }, + { "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" }, + { "12345678901234567890123456789012345678901234567890123456789012" \ + "345678901234567890" } +}; + +static const unsigned char md4_test_sum[7][16] = +{ + { 0x31, 0xD6, 0xCF, 0xE0, 0xD1, 0x6A, 0xE9, 0x31, + 0xB7, 0x3C, 0x59, 0xD7, 0xE0, 0xC0, 0x89, 0xC0 }, + { 0xBD, 0xE5, 0x2C, 0xB3, 0x1D, 0xE3, 0x3E, 0x46, + 0x24, 0x5E, 0x05, 0xFB, 0xDB, 0xD6, 0xFB, 0x24 }, + { 0xA4, 0x48, 0x01, 0x7A, 0xAF, 0x21, 0xD8, 0x52, + 0x5F, 0xC1, 0x0A, 0xE8, 0x7A, 0xA6, 0x72, 0x9D }, + { 0xD9, 0x13, 0x0A, 0x81, 0x64, 0x54, 0x9F, 0xE8, + 0x18, 0x87, 0x48, 0x06, 0xE1, 0xC7, 0x01, 0x4B }, + { 0xD7, 0x9E, 0x1C, 0x30, 0x8A, 0xA5, 0xBB, 0xCD, + 0xEE, 0xA8, 0xED, 0x63, 0xDF, 0x41, 0x2D, 0xA9 }, + { 0x04, 0x3F, 0x85, 0x82, 0xF2, 0x41, 0xDB, 0x35, + 0x1C, 0xE6, 0x27, 0xE1, 0x53, 0xE7, 0xF0, 0xE4 }, + { 0xE3, 0x3B, 0x4D, 0xDC, 0x9C, 0x38, 0xF2, 0x19, + 0x9C, 0x3E, 0x7B, 0x16, 0x4F, 0xCC, 0x05, 0x36 } +}; + +/* + * Checkup routine + */ +int mbedtls_md4_self_test( int verbose ) +{ + int i; + unsigned char md4sum[16]; + + for( i = 0; i < 7; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " MD4 test #%d: ", i + 1 ); + + mbedtls_md4( (unsigned char *) md4_test_str[i], + strlen( md4_test_str[i] ), md4sum ); + + if( memcmp( md4sum, md4_test_sum[i], 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MD4_C */ diff --git a/c++/src/connect/mbedtls/md_wrap.c b/c++/src/connect/mbedtls/md_wrap.c new file mode 100644 index 00000000..2cfcae20 --- /dev/null +++ b/c++/src/connect/mbedtls/md_wrap.c @@ -0,0 +1,575 @@ +/** + * \file md_wrap.c + * + * \brief Generic message digest wrapper for mbed TLS + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MD_C) + +#include "mbedtls/md_internal.h" + +#if defined(MBEDTLS_MD2_C) +#include "mbedtls/md2.h" +#endif + +#if defined(MBEDTLS_MD4_C) +#include "mbedtls/md4.h" +#endif + +#if defined(MBEDTLS_MD5_C) +#include "mbedtls/md5.h" +#endif + +#if defined(MBEDTLS_RIPEMD160_C) +#include "mbedtls/ripemd160.h" +#endif + +#if defined(MBEDTLS_SHA1_C) +#include "mbedtls/sha1.h" +#endif + +#if defined(MBEDTLS_SHA256_C) +#include "mbedtls/sha256.h" +#endif + +#if defined(MBEDTLS_SHA512_C) +#include "mbedtls/sha512.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_MD2_C) + +static void md2_starts_wrap( void *ctx ) +{ + mbedtls_md2_starts( (mbedtls_md2_context *) ctx ); +} + +static void md2_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_md2_update( (mbedtls_md2_context *) ctx, input, ilen ); +} + +static void md2_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_md2_finish( (mbedtls_md2_context *) ctx, output ); +} + +static void *md2_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md2_context ) ); + + if( ctx != NULL ) + mbedtls_md2_init( (mbedtls_md2_context *) ctx ); + + return( ctx ); +} + +static void md2_ctx_free( void *ctx ) +{ + mbedtls_md2_free( (mbedtls_md2_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md2_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md2_clone( (mbedtls_md2_context *) dst, + (const mbedtls_md2_context *) src ); +} + +static void md2_process_wrap( void *ctx, const unsigned char *data ) +{ + ((void) data); + + mbedtls_md2_process( (mbedtls_md2_context *) ctx ); +} + +const mbedtls_md_info_t mbedtls_md2_info = { + MBEDTLS_MD_MD2, + "MD2", + 16, + 16, + md2_starts_wrap, + md2_update_wrap, + md2_finish_wrap, + mbedtls_md2, + md2_ctx_alloc, + md2_ctx_free, + md2_clone_wrap, + md2_process_wrap, +}; + +#endif /* MBEDTLS_MD2_C */ + +#if defined(MBEDTLS_MD4_C) + +static void md4_starts_wrap( void *ctx ) +{ + mbedtls_md4_starts( (mbedtls_md4_context *) ctx ); +} + +static void md4_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_md4_update( (mbedtls_md4_context *) ctx, input, ilen ); +} + +static void md4_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_md4_finish( (mbedtls_md4_context *) ctx, output ); +} + +static void *md4_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md4_context ) ); + + if( ctx != NULL ) + mbedtls_md4_init( (mbedtls_md4_context *) ctx ); + + return( ctx ); +} + +static void md4_ctx_free( void *ctx ) +{ + mbedtls_md4_free( (mbedtls_md4_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md4_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md4_clone( (mbedtls_md4_context *) dst, + (const mbedtls_md4_context *) src ); +} + +static void md4_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_md4_process( (mbedtls_md4_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_md4_info = { + MBEDTLS_MD_MD4, + "MD4", + 16, + 64, + md4_starts_wrap, + md4_update_wrap, + md4_finish_wrap, + mbedtls_md4, + md4_ctx_alloc, + md4_ctx_free, + md4_clone_wrap, + md4_process_wrap, +}; + +#endif /* MBEDTLS_MD4_C */ + +#if defined(MBEDTLS_MD5_C) + +static void md5_starts_wrap( void *ctx ) +{ + mbedtls_md5_starts( (mbedtls_md5_context *) ctx ); +} + +static void md5_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_md5_update( (mbedtls_md5_context *) ctx, input, ilen ); +} + +static void md5_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_md5_finish( (mbedtls_md5_context *) ctx, output ); +} + +static void *md5_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_md5_context ) ); + + if( ctx != NULL ) + mbedtls_md5_init( (mbedtls_md5_context *) ctx ); + + return( ctx ); +} + +static void md5_ctx_free( void *ctx ) +{ + mbedtls_md5_free( (mbedtls_md5_context *) ctx ); + mbedtls_free( ctx ); +} + +static void md5_clone_wrap( void *dst, const void *src ) +{ + mbedtls_md5_clone( (mbedtls_md5_context *) dst, + (const mbedtls_md5_context *) src ); +} + +static void md5_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_md5_process( (mbedtls_md5_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_md5_info = { + MBEDTLS_MD_MD5, + "MD5", + 16, + 64, + md5_starts_wrap, + md5_update_wrap, + md5_finish_wrap, + mbedtls_md5, + md5_ctx_alloc, + md5_ctx_free, + md5_clone_wrap, + md5_process_wrap, +}; + +#endif /* MBEDTLS_MD5_C */ + +#if defined(MBEDTLS_RIPEMD160_C) + +static void ripemd160_starts_wrap( void *ctx ) +{ + mbedtls_ripemd160_starts( (mbedtls_ripemd160_context *) ctx ); +} + +static void ripemd160_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_ripemd160_update( (mbedtls_ripemd160_context *) ctx, input, ilen ); +} + +static void ripemd160_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_ripemd160_finish( (mbedtls_ripemd160_context *) ctx, output ); +} + +static void *ripemd160_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ripemd160_context ) ); + + if( ctx != NULL ) + mbedtls_ripemd160_init( (mbedtls_ripemd160_context *) ctx ); + + return( ctx ); +} + +static void ripemd160_ctx_free( void *ctx ) +{ + mbedtls_ripemd160_free( (mbedtls_ripemd160_context *) ctx ); + mbedtls_free( ctx ); +} + +static void ripemd160_clone_wrap( void *dst, const void *src ) +{ + mbedtls_ripemd160_clone( (mbedtls_ripemd160_context *) dst, + (const mbedtls_ripemd160_context *) src ); +} + +static void ripemd160_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_ripemd160_process( (mbedtls_ripemd160_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_ripemd160_info = { + MBEDTLS_MD_RIPEMD160, + "RIPEMD160", + 20, + 64, + ripemd160_starts_wrap, + ripemd160_update_wrap, + ripemd160_finish_wrap, + mbedtls_ripemd160, + ripemd160_ctx_alloc, + ripemd160_ctx_free, + ripemd160_clone_wrap, + ripemd160_process_wrap, +}; + +#endif /* MBEDTLS_RIPEMD160_C */ + +#if defined(MBEDTLS_SHA1_C) + +static void sha1_starts_wrap( void *ctx ) +{ + mbedtls_sha1_starts( (mbedtls_sha1_context *) ctx ); +} + +static void sha1_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha1_update( (mbedtls_sha1_context *) ctx, input, ilen ); +} + +static void sha1_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_sha1_finish( (mbedtls_sha1_context *) ctx, output ); +} + +static void *sha1_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha1_context ) ); + + if( ctx != NULL ) + mbedtls_sha1_init( (mbedtls_sha1_context *) ctx ); + + return( ctx ); +} + +static void sha1_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha1_clone( (mbedtls_sha1_context *) dst, + (const mbedtls_sha1_context *) src ); +} + +static void sha1_ctx_free( void *ctx ) +{ + mbedtls_sha1_free( (mbedtls_sha1_context *) ctx ); + mbedtls_free( ctx ); +} + +static void sha1_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_sha1_process( (mbedtls_sha1_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_sha1_info = { + MBEDTLS_MD_SHA1, + "SHA1", + 20, + 64, + sha1_starts_wrap, + sha1_update_wrap, + sha1_finish_wrap, + mbedtls_sha1, + sha1_ctx_alloc, + sha1_ctx_free, + sha1_clone_wrap, + sha1_process_wrap, +}; + +#endif /* MBEDTLS_SHA1_C */ + +/* + * Wrappers for generic message digests + */ +#if defined(MBEDTLS_SHA256_C) + +static void sha224_starts_wrap( void *ctx ) +{ + mbedtls_sha256_starts( (mbedtls_sha256_context *) ctx, 1 ); +} + +static void sha224_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha256_update( (mbedtls_sha256_context *) ctx, input, ilen ); +} + +static void sha224_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_sha256_finish( (mbedtls_sha256_context *) ctx, output ); +} + +static void sha224_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha256( input, ilen, output, 1 ); +} + +static void *sha224_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha256_context ) ); + + if( ctx != NULL ) + mbedtls_sha256_init( (mbedtls_sha256_context *) ctx ); + + return( ctx ); +} + +static void sha224_ctx_free( void *ctx ) +{ + mbedtls_sha256_free( (mbedtls_sha256_context *) ctx ); + mbedtls_free( ctx ); +} + +static void sha224_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha256_clone( (mbedtls_sha256_context *) dst, + (const mbedtls_sha256_context *) src ); +} + +static void sha224_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_sha256_process( (mbedtls_sha256_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_sha224_info = { + MBEDTLS_MD_SHA224, + "SHA224", + 28, + 64, + sha224_starts_wrap, + sha224_update_wrap, + sha224_finish_wrap, + sha224_wrap, + sha224_ctx_alloc, + sha224_ctx_free, + sha224_clone_wrap, + sha224_process_wrap, +}; + +static void sha256_starts_wrap( void *ctx ) +{ + mbedtls_sha256_starts( (mbedtls_sha256_context *) ctx, 0 ); +} + +static void sha256_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha256( input, ilen, output, 0 ); +} + +const mbedtls_md_info_t mbedtls_sha256_info = { + MBEDTLS_MD_SHA256, + "SHA256", + 32, + 64, + sha256_starts_wrap, + sha224_update_wrap, + sha224_finish_wrap, + sha256_wrap, + sha224_ctx_alloc, + sha224_ctx_free, + sha224_clone_wrap, + sha224_process_wrap, +}; + +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + +static void sha384_starts_wrap( void *ctx ) +{ + mbedtls_sha512_starts( (mbedtls_sha512_context *) ctx, 1 ); +} + +static void sha384_update_wrap( void *ctx, const unsigned char *input, + size_t ilen ) +{ + mbedtls_sha512_update( (mbedtls_sha512_context *) ctx, input, ilen ); +} + +static void sha384_finish_wrap( void *ctx, unsigned char *output ) +{ + mbedtls_sha512_finish( (mbedtls_sha512_context *) ctx, output ); +} + +static void sha384_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha512( input, ilen, output, 1 ); +} + +static void *sha384_ctx_alloc( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_sha512_context ) ); + + if( ctx != NULL ) + mbedtls_sha512_init( (mbedtls_sha512_context *) ctx ); + + return( ctx ); +} + +static void sha384_ctx_free( void *ctx ) +{ + mbedtls_sha512_free( (mbedtls_sha512_context *) ctx ); + mbedtls_free( ctx ); +} + +static void sha384_clone_wrap( void *dst, const void *src ) +{ + mbedtls_sha512_clone( (mbedtls_sha512_context *) dst, + (const mbedtls_sha512_context *) src ); +} + +static void sha384_process_wrap( void *ctx, const unsigned char *data ) +{ + mbedtls_sha512_process( (mbedtls_sha512_context *) ctx, data ); +} + +const mbedtls_md_info_t mbedtls_sha384_info = { + MBEDTLS_MD_SHA384, + "SHA384", + 48, + 128, + sha384_starts_wrap, + sha384_update_wrap, + sha384_finish_wrap, + sha384_wrap, + sha384_ctx_alloc, + sha384_ctx_free, + sha384_clone_wrap, + sha384_process_wrap, +}; + +static void sha512_starts_wrap( void *ctx ) +{ + mbedtls_sha512_starts( (mbedtls_sha512_context *) ctx, 0 ); +} + +static void sha512_wrap( const unsigned char *input, size_t ilen, + unsigned char *output ) +{ + mbedtls_sha512( input, ilen, output, 0 ); +} + +const mbedtls_md_info_t mbedtls_sha512_info = { + MBEDTLS_MD_SHA512, + "SHA512", + 64, + 128, + sha512_starts_wrap, + sha384_update_wrap, + sha384_finish_wrap, + sha512_wrap, + sha384_ctx_alloc, + sha384_ctx_free, + sha384_clone_wrap, + sha384_process_wrap, +}; + +#endif /* MBEDTLS_SHA512_C */ + +#endif /* MBEDTLS_MD_C */ diff --git a/c++/src/connect/mbedtls/memory_buffer_alloc.c b/c++/src/connect/mbedtls/memory_buffer_alloc.c new file mode 100644 index 00000000..545d5a2c --- /dev/null +++ b/c++/src/connect/mbedtls/memory_buffer_alloc.c @@ -0,0 +1,745 @@ +/* + * Buffer-based memory allocator + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) +#include "mbedtls/memory_buffer_alloc.h" + +/* No need for the header guard as MBEDTLS_MEMORY_BUFFER_ALLOC_C + is dependent upon MBEDTLS_PLATFORM_C */ +#include "mbedtls/platform.h" + +#include + +#if defined(MBEDTLS_MEMORY_BACKTRACE) +#include +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +#define MAGIC1 0xFF00AA55 +#define MAGIC2 0xEE119966 +#define MAX_BT 20 + +typedef struct _memory_header memory_header; +struct _memory_header +{ + size_t magic1; + size_t size; + size_t alloc; + memory_header *prev; + memory_header *next; + memory_header *prev_free; + memory_header *next_free; +#if defined(MBEDTLS_MEMORY_BACKTRACE) + char **trace; + size_t trace_count; +#endif + size_t magic2; +}; + +typedef struct +{ + unsigned char *buf; + size_t len; + memory_header *first; + memory_header *first_free; + int verify; +#if defined(MBEDTLS_MEMORY_DEBUG) + size_t alloc_count; + size_t free_count; + size_t total_used; + size_t maximum_used; + size_t header_count; + size_t maximum_header_count; +#endif +#if defined(MBEDTLS_THREADING_C) + mbedtls_threading_mutex_t mutex; +#endif +} +buffer_alloc_ctx; + +static buffer_alloc_ctx heap; + +#if defined(MBEDTLS_MEMORY_DEBUG) +static void debug_header( memory_header *hdr ) +{ +#if defined(MBEDTLS_MEMORY_BACKTRACE) + size_t i; +#endif + + mbedtls_fprintf( stderr, "HDR: PTR(%10zu), PREV(%10zu), NEXT(%10zu), " + "ALLOC(%zu), SIZE(%10zu)\n", + (size_t) hdr, (size_t) hdr->prev, (size_t) hdr->next, + hdr->alloc, hdr->size ); + mbedtls_fprintf( stderr, " FPREV(%10zu), FNEXT(%10zu)\n", + (size_t) hdr->prev_free, (size_t) hdr->next_free ); + +#if defined(MBEDTLS_MEMORY_BACKTRACE) + mbedtls_fprintf( stderr, "TRACE: \n" ); + for( i = 0; i < hdr->trace_count; i++ ) + mbedtls_fprintf( stderr, "%s\n", hdr->trace[i] ); + mbedtls_fprintf( stderr, "\n" ); +#endif +} + +static void debug_chain() +{ + memory_header *cur = heap.first; + + mbedtls_fprintf( stderr, "\nBlock list\n" ); + while( cur != NULL ) + { + debug_header( cur ); + cur = cur->next; + } + + mbedtls_fprintf( stderr, "Free list\n" ); + cur = heap.first_free; + + while( cur != NULL ) + { + debug_header( cur ); + cur = cur->next_free; + } +} +#endif /* MBEDTLS_MEMORY_DEBUG */ + +static int verify_header( memory_header *hdr ) +{ + if( hdr->magic1 != MAGIC1 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: MAGIC1 mismatch\n" ); +#endif + return( 1 ); + } + + if( hdr->magic2 != MAGIC2 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: MAGIC2 mismatch\n" ); +#endif + return( 1 ); + } + + if( hdr->alloc > 1 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: alloc has illegal value\n" ); +#endif + return( 1 ); + } + + if( hdr->prev != NULL && hdr->prev == hdr->next ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: prev == next\n" ); +#endif + return( 1 ); + } + + if( hdr->prev_free != NULL && hdr->prev_free == hdr->next_free ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: prev_free == next_free\n" ); +#endif + return( 1 ); + } + + return( 0 ); +} + +static int verify_chain() +{ + memory_header *prv = heap.first, *cur = heap.first->next; + + if( verify_header( heap.first ) != 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification of first header " + "failed\n" ); +#endif + return( 1 ); + } + + if( heap.first->prev != NULL ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification failed: " + "first->prev != NULL\n" ); +#endif + return( 1 ); + } + + while( cur != NULL ) + { + if( verify_header( cur ) != 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification of header " + "failed\n" ); +#endif + return( 1 ); + } + + if( cur->prev != prv ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: verification failed: " + "cur->prev != prv\n" ); +#endif + return( 1 ); + } + + prv = cur; + cur = cur->next; + } + + return( 0 ); +} + +static void *buffer_alloc_calloc( size_t n, size_t size ) +{ + memory_header *new, *cur = heap.first_free; + unsigned char *p; + void *ret; + size_t original_len, len; +#if defined(MBEDTLS_MEMORY_BACKTRACE) + void *trace_buffer[MAX_BT]; + size_t trace_cnt; +#endif + + if( heap.buf == NULL || heap.first == NULL ) + return( NULL ); + + original_len = len = n * size; + + if( n != 0 && len / n != size ) + return( NULL ); + + if( len % MBEDTLS_MEMORY_ALIGN_MULTIPLE ) + { + len -= len % MBEDTLS_MEMORY_ALIGN_MULTIPLE; + len += MBEDTLS_MEMORY_ALIGN_MULTIPLE; + } + + // Find block that fits + // + while( cur != NULL ) + { + if( cur->size >= len ) + break; + + cur = cur->next_free; + } + + if( cur == NULL ) + return( NULL ); + + if( cur->alloc != 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: block in free_list but allocated " + "data\n" ); +#endif + mbedtls_exit( 1 ); + } + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.alloc_count++; +#endif + + // Found location, split block if > memory_header + 4 room left + // + if( cur->size - len < sizeof(memory_header) + + MBEDTLS_MEMORY_ALIGN_MULTIPLE ) + { + cur->alloc = 1; + + // Remove from free_list + // + if( cur->prev_free != NULL ) + cur->prev_free->next_free = cur->next_free; + else + heap.first_free = cur->next_free; + + if( cur->next_free != NULL ) + cur->next_free->prev_free = cur->prev_free; + + cur->prev_free = NULL; + cur->next_free = NULL; + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.total_used += cur->size; + if( heap.total_used > heap.maximum_used ) + heap.maximum_used = heap.total_used; +#endif +#if defined(MBEDTLS_MEMORY_BACKTRACE) + trace_cnt = backtrace( trace_buffer, MAX_BT ); + cur->trace = backtrace_symbols( trace_buffer, trace_cnt ); + cur->trace_count = trace_cnt; +#endif + + if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 ) + mbedtls_exit( 1 ); + + ret = (unsigned char *) cur + sizeof( memory_header ); + memset( ret, 0, original_len ); + + return( ret ); + } + + p = ( (unsigned char *) cur ) + sizeof(memory_header) + len; + new = (memory_header *) p; + + new->size = cur->size - len - sizeof(memory_header); + new->alloc = 0; + new->prev = cur; + new->next = cur->next; +#if defined(MBEDTLS_MEMORY_BACKTRACE) + new->trace = NULL; + new->trace_count = 0; +#endif + new->magic1 = MAGIC1; + new->magic2 = MAGIC2; + + if( new->next != NULL ) + new->next->prev = new; + + // Replace cur with new in free_list + // + new->prev_free = cur->prev_free; + new->next_free = cur->next_free; + if( new->prev_free != NULL ) + new->prev_free->next_free = new; + else + heap.first_free = new; + + if( new->next_free != NULL ) + new->next_free->prev_free = new; + + cur->alloc = 1; + cur->size = len; + cur->next = new; + cur->prev_free = NULL; + cur->next_free = NULL; + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.header_count++; + if( heap.header_count > heap.maximum_header_count ) + heap.maximum_header_count = heap.header_count; + heap.total_used += cur->size; + if( heap.total_used > heap.maximum_used ) + heap.maximum_used = heap.total_used; +#endif +#if defined(MBEDTLS_MEMORY_BACKTRACE) + trace_cnt = backtrace( trace_buffer, MAX_BT ); + cur->trace = backtrace_symbols( trace_buffer, trace_cnt ); + cur->trace_count = trace_cnt; +#endif + + if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 ) + mbedtls_exit( 1 ); + + ret = (unsigned char *) cur + sizeof( memory_header ); + memset( ret, 0, original_len ); + + return( ret ); +} + +static void buffer_alloc_free( void *ptr ) +{ + memory_header *hdr, *old = NULL; + unsigned char *p = (unsigned char *) ptr; + + if( ptr == NULL || heap.buf == NULL || heap.first == NULL ) + return; + + if( p < heap.buf || p > heap.buf + heap.len ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: mbedtls_free() outside of managed " + "space\n" ); +#endif + mbedtls_exit( 1 ); + } + + p -= sizeof(memory_header); + hdr = (memory_header *) p; + + if( verify_header( hdr ) != 0 ) + mbedtls_exit( 1 ); + + if( hdr->alloc != 1 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + mbedtls_fprintf( stderr, "FATAL: mbedtls_free() on unallocated " + "data\n" ); +#endif + mbedtls_exit( 1 ); + } + + hdr->alloc = 0; + +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.free_count++; + heap.total_used -= hdr->size; +#endif + +#if defined(MBEDTLS_MEMORY_BACKTRACE) + free( hdr->trace ); + hdr->trace = NULL; + hdr->trace_count = 0; +#endif + + // Regroup with block before + // + if( hdr->prev != NULL && hdr->prev->alloc == 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.header_count--; +#endif + hdr->prev->size += sizeof(memory_header) + hdr->size; + hdr->prev->next = hdr->next; + old = hdr; + hdr = hdr->prev; + + if( hdr->next != NULL ) + hdr->next->prev = hdr; + + memset( old, 0, sizeof(memory_header) ); + } + + // Regroup with block after + // + if( hdr->next != NULL && hdr->next->alloc == 0 ) + { +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.header_count--; +#endif + hdr->size += sizeof(memory_header) + hdr->next->size; + old = hdr->next; + hdr->next = hdr->next->next; + + if( hdr->prev_free != NULL || hdr->next_free != NULL ) + { + if( hdr->prev_free != NULL ) + hdr->prev_free->next_free = hdr->next_free; + else + heap.first_free = hdr->next_free; + + if( hdr->next_free != NULL ) + hdr->next_free->prev_free = hdr->prev_free; + } + + hdr->prev_free = old->prev_free; + hdr->next_free = old->next_free; + + if( hdr->prev_free != NULL ) + hdr->prev_free->next_free = hdr; + else + heap.first_free = hdr; + + if( hdr->next_free != NULL ) + hdr->next_free->prev_free = hdr; + + if( hdr->next != NULL ) + hdr->next->prev = hdr; + + memset( old, 0, sizeof(memory_header) ); + } + + // Prepend to free_list if we have not merged + // (Does not have to stay in same order as prev / next list) + // + if( old == NULL ) + { + hdr->next_free = heap.first_free; + if( heap.first_free != NULL ) + heap.first_free->prev_free = hdr; + heap.first_free = hdr; + } + + if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_FREE ) && verify_chain() != 0 ) + mbedtls_exit( 1 ); +} + +void mbedtls_memory_buffer_set_verify( int verify ) +{ + heap.verify = verify; +} + +int mbedtls_memory_buffer_alloc_verify() +{ + return verify_chain(); +} + +#if defined(MBEDTLS_MEMORY_DEBUG) +void mbedtls_memory_buffer_alloc_status() +{ + mbedtls_fprintf( stderr, + "Current use: %zu blocks / %zu bytes, max: %zu blocks / " + "%zu bytes (total %zu bytes), alloc / free: %zu / %zu\n", + heap.header_count, heap.total_used, + heap.maximum_header_count, heap.maximum_used, + heap.maximum_header_count * sizeof( memory_header ) + + heap.maximum_used, + heap.alloc_count, heap.free_count ); + + if( heap.first->next == NULL ) + mbedtls_fprintf( stderr, "All memory de-allocated in stack buffer\n" ); + else + { + mbedtls_fprintf( stderr, "Memory currently allocated:\n" ); + debug_chain(); + } +} + +void mbedtls_memory_buffer_alloc_max_get( size_t *max_used, size_t *max_blocks ) +{ + *max_used = heap.maximum_used; + *max_blocks = heap.maximum_header_count; +} + +void mbedtls_memory_buffer_alloc_max_reset( void ) +{ + heap.maximum_used = 0; + heap.maximum_header_count = 0; +} + +void mbedtls_memory_buffer_alloc_cur_get( size_t *cur_used, size_t *cur_blocks ) +{ + *cur_used = heap.total_used; + *cur_blocks = heap.header_count; +} +#endif /* MBEDTLS_MEMORY_DEBUG */ + +#if defined(MBEDTLS_THREADING_C) +static void *buffer_alloc_calloc_mutexed( size_t n, size_t size ) +{ + void *buf; + if( mbedtls_mutex_lock( &heap.mutex ) != 0 ) + return( NULL ); + buf = buffer_alloc_calloc( n, size ); + if( mbedtls_mutex_unlock( &heap.mutex ) ) + return( NULL ); + return( buf ); +} + +static void buffer_alloc_free_mutexed( void *ptr ) +{ + /* We have to good option here, but corrupting the heap seems + * worse than loosing memory. */ + if( mbedtls_mutex_lock( &heap.mutex ) ) + return; + buffer_alloc_free( ptr ); + (void) mbedtls_mutex_unlock( &heap.mutex ); +} +#endif /* MBEDTLS_THREADING_C */ + +void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len ) +{ + memset( &heap, 0, sizeof(buffer_alloc_ctx) ); + memset( buf, 0, len ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &heap.mutex ); + mbedtls_platform_set_calloc_free( buffer_alloc_calloc_mutexed, + buffer_alloc_free_mutexed ); +#else + mbedtls_platform_set_calloc_free( buffer_alloc_calloc, buffer_alloc_free ); +#endif + + if( (size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE ) + { + /* Adjust len first since buf is used in the computation */ + len -= MBEDTLS_MEMORY_ALIGN_MULTIPLE + - (size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE; + buf += MBEDTLS_MEMORY_ALIGN_MULTIPLE + - (size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE; + } + + heap.buf = buf; + heap.len = len; + + heap.first = (memory_header *) buf; + heap.first->size = len - sizeof(memory_header); + heap.first->magic1 = MAGIC1; + heap.first->magic2 = MAGIC2; + heap.first_free = heap.first; +} + +void mbedtls_memory_buffer_alloc_free() +{ +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &heap.mutex ); +#endif + mbedtls_zeroize( &heap, sizeof(buffer_alloc_ctx) ); +} + +#if defined(MBEDTLS_SELF_TEST) +static int check_pointer( void *p ) +{ + if( p == NULL ) + return( -1 ); + + if( (size_t) p % MBEDTLS_MEMORY_ALIGN_MULTIPLE != 0 ) + return( -1 ); + + return( 0 ); +} + +static int check_all_free( ) +{ + if( +#if defined(MBEDTLS_MEMORY_DEBUG) + heap.total_used != 0 || +#endif + heap.first != heap.first_free || + (void *) heap.first != (void *) heap.buf ) + { + return( -1 ); + } + + return( 0 ); +} + +#define TEST_ASSERT( condition ) \ + if( ! (condition) ) \ + { \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + \ + ret = 1; \ + goto cleanup; \ + } + +int mbedtls_memory_buffer_alloc_self_test( int verbose ) +{ + unsigned char buf[1024]; + unsigned char *p, *q, *r, *end; + int ret = 0; + + if( verbose != 0 ) + mbedtls_printf( " MBA test #1 (basic alloc-free cycle): " ); + + mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) ); + + p = mbedtls_calloc( 1, 1 ); + q = mbedtls_calloc( 1, 128 ); + r = mbedtls_calloc( 1, 16 ); + + TEST_ASSERT( check_pointer( p ) == 0 && + check_pointer( q ) == 0 && + check_pointer( r ) == 0 ); + + mbedtls_free( r ); + mbedtls_free( q ); + mbedtls_free( p ); + + TEST_ASSERT( check_all_free( ) == 0 ); + + /* Memorize end to compare with the next test */ + end = heap.buf + heap.len; + + mbedtls_memory_buffer_alloc_free( ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " MBA test #2 (buf not aligned): " ); + + mbedtls_memory_buffer_alloc_init( buf + 1, sizeof( buf ) - 1 ); + + TEST_ASSERT( heap.buf + heap.len == end ); + + p = mbedtls_calloc( 1, 1 ); + q = mbedtls_calloc( 1, 128 ); + r = mbedtls_calloc( 1, 16 ); + + TEST_ASSERT( check_pointer( p ) == 0 && + check_pointer( q ) == 0 && + check_pointer( r ) == 0 ); + + mbedtls_free( r ); + mbedtls_free( q ); + mbedtls_free( p ); + + TEST_ASSERT( check_all_free( ) == 0 ); + + mbedtls_memory_buffer_alloc_free( ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " MBA test #3 (full): " ); + + mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) ); + + p = mbedtls_calloc( 1, sizeof( buf ) - sizeof( memory_header ) ); + + TEST_ASSERT( check_pointer( p ) == 0 ); + TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL ); + + mbedtls_free( p ); + + p = mbedtls_calloc( 1, sizeof( buf ) - 2 * sizeof( memory_header ) - 16 ); + q = mbedtls_calloc( 1, 16 ); + + TEST_ASSERT( check_pointer( p ) == 0 && check_pointer( q ) == 0 ); + TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL ); + + mbedtls_free( q ); + + TEST_ASSERT( mbedtls_calloc( 1, 17 ) == NULL ); + + mbedtls_free( p ); + + TEST_ASSERT( check_all_free( ) == 0 ); + + mbedtls_memory_buffer_alloc_free( ); + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +cleanup: + mbedtls_memory_buffer_alloc_free( ); + + return( ret ); +} +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */ diff --git a/c++/src/connect/mbedtls/net_sockets.c b/c++/src/connect/mbedtls/net_sockets.c new file mode 100644 index 00000000..80be6ec6 --- /dev/null +++ b/c++/src/connect/mbedtls/net_sockets.c @@ -0,0 +1,586 @@ +/* + * TCP/IP or UDP/IP networking functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_NET_C) + +#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ + !defined(__APPLE__) && !defined(_WIN32) +#error "This module only works on Unix and Windows, see MBEDTLS_NET_C in config.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#endif + +#include "mbedtls/net_sockets.h" + +#include + +#if (defined(_WIN32) || defined(_WIN32_WCE)) && !defined(EFIX64) && \ + !defined(EFI32) + +#ifdef _WIN32_WINNT +#undef _WIN32_WINNT +#endif +/* Enables getaddrinfo() & Co */ +#define _WIN32_WINNT 0x0501 +#include + +#include +#include + +#if defined(_MSC_VER) +#if defined(_WIN32_WCE) +#pragma comment( lib, "ws2.lib" ) +#else +#pragma comment( lib, "ws2_32.lib" ) +#endif +#endif /* _MSC_VER */ + +#define read(fd,buf,len) recv(fd,(char*)buf,(int) len,0) +#define write(fd,buf,len) send(fd,(char*)buf,(int) len,0) +#define close(fd) closesocket(fd) + +static int wsa_init_done = 0; + +#else /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +/* Some MS functions want int and MSVC warns if we pass size_t, + * but the standard fucntions use socklen_t, so cast only for MSVC */ +#if defined(_MSC_VER) +#define MSVC_INT_CAST (int) +#else +#define MSVC_INT_CAST +#endif + +#include + +#include + +#include + +/* + * Prepare for using the sockets interface + */ +static int net_prepare( void ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + WSADATA wsaData; + + if( wsa_init_done == 0 ) + { + if( WSAStartup( MAKEWORD(2,0), &wsaData ) != 0 ) + return( MBEDTLS_ERR_NET_SOCKET_FAILED ); + + wsa_init_done = 1; + } +#else +#if !defined(EFIX64) && !defined(EFI32) + signal( SIGPIPE, SIG_IGN ); +#endif +#endif + return( 0 ); +} + +/* + * Initialize a context + */ +void mbedtls_net_init( mbedtls_net_context *ctx ) +{ + ctx->fd = -1; +} + +/* + * Initiate a TCP connection with host:port and the given protocol + */ +int mbedtls_net_connect( mbedtls_net_context *ctx, const char *host, + const char *port, int proto ) +{ + int ret; + struct addrinfo hints, *addr_list, *cur; + + if( ( ret = net_prepare() ) != 0 ) + return( ret ); + + /* Do name resolution with both IPv6 and IPv4 */ + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; + + if( getaddrinfo( host, port, &hints, &addr_list ) != 0 ) + return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + + /* Try the sockaddrs until a connection succeeds */ + ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; + for( cur = addr_list; cur != NULL; cur = cur->ai_next ) + { + ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, + cur->ai_protocol ); + if( ctx->fd < 0 ) + { + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + if( connect( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) == 0 ) + { + ret = 0; + break; + } + + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_CONNECT_FAILED; + } + + freeaddrinfo( addr_list ); + + return( ret ); +} + +/* + * Create a listening socket on bind_ip:port + */ +int mbedtls_net_bind( mbedtls_net_context *ctx, const char *bind_ip, const char *port, int proto ) +{ + int n, ret; + struct addrinfo hints, *addr_list, *cur; + + if( ( ret = net_prepare() ) != 0 ) + return( ret ); + + /* Bind to IPv6 and/or IPv4, but only in the desired protocol */ + memset( &hints, 0, sizeof( hints ) ); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = proto == MBEDTLS_NET_PROTO_UDP ? SOCK_DGRAM : SOCK_STREAM; + hints.ai_protocol = proto == MBEDTLS_NET_PROTO_UDP ? IPPROTO_UDP : IPPROTO_TCP; + if( bind_ip == NULL ) + hints.ai_flags = AI_PASSIVE; + + if( getaddrinfo( bind_ip, port, &hints, &addr_list ) != 0 ) + return( MBEDTLS_ERR_NET_UNKNOWN_HOST ); + + /* Try the sockaddrs until a binding succeeds */ + ret = MBEDTLS_ERR_NET_UNKNOWN_HOST; + for( cur = addr_list; cur != NULL; cur = cur->ai_next ) + { + ctx->fd = (int) socket( cur->ai_family, cur->ai_socktype, + cur->ai_protocol ); + if( ctx->fd < 0 ) + { + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + n = 1; + if( setsockopt( ctx->fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &n, sizeof( n ) ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_SOCKET_FAILED; + continue; + } + + if( bind( ctx->fd, cur->ai_addr, MSVC_INT_CAST cur->ai_addrlen ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_BIND_FAILED; + continue; + } + + /* Listen only makes sense for TCP */ + if( proto == MBEDTLS_NET_PROTO_TCP ) + { + if( listen( ctx->fd, MBEDTLS_NET_LISTEN_BACKLOG ) != 0 ) + { + close( ctx->fd ); + ret = MBEDTLS_ERR_NET_LISTEN_FAILED; + continue; + } + } + + /* Bind was successful */ + ret = 0; + break; + } + + freeaddrinfo( addr_list ); + + return( ret ); + +} + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) +/* + * Check if the requested operation would be blocking on a non-blocking socket + * and thus 'failed' with a negative return value. + */ +static int net_would_block( const mbedtls_net_context *ctx ) +{ + ((void) ctx); + return( WSAGetLastError() == WSAEWOULDBLOCK ); +} +#else +/* + * Check if the requested operation would be blocking on a non-blocking socket + * and thus 'failed' with a negative return value. + * + * Note: on a blocking socket this function always returns 0! + */ +static int net_would_block( const mbedtls_net_context *ctx ) +{ + /* + * Never return 'WOULD BLOCK' on a non-blocking socket + */ + if( ( fcntl( ctx->fd, F_GETFL ) & O_NONBLOCK ) != O_NONBLOCK ) + return( 0 ); + + switch( errno ) + { +#if defined EAGAIN + case EAGAIN: +#endif +#if defined EWOULDBLOCK && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif + return( 1 ); + } + return( 0 ); +} +#endif /* ( _WIN32 || _WIN32_WCE ) && !EFIX64 && !EFI32 */ + +/* + * Accept a connection from a remote client + */ +int mbedtls_net_accept( mbedtls_net_context *bind_ctx, + mbedtls_net_context *client_ctx, + void *client_ip, size_t buf_size, size_t *ip_len ) +{ + int ret; + int type; + + struct sockaddr_storage client_addr; + +#if defined(__socklen_t_defined) || defined(_SOCKLEN_T) || \ + defined(_SOCKLEN_T_DECLARED) || defined(__DEFINED_socklen_t) + socklen_t n = (socklen_t) sizeof( client_addr ); + socklen_t type_len = (socklen_t) sizeof( type ); +#else + int n = (int) sizeof( client_addr ); + int type_len = (int) sizeof( type ); +#endif + + /* Is this a TCP or UDP socket? */ + if( getsockopt( bind_ctx->fd, SOL_SOCKET, SO_TYPE, + (void *) &type, &type_len ) != 0 || + ( type != SOCK_STREAM && type != SOCK_DGRAM ) ) + { + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + } + + if( type == SOCK_STREAM ) + { + /* TCP: actual accept() */ + ret = client_ctx->fd = (int) accept( bind_ctx->fd, + (struct sockaddr *) &client_addr, &n ); + } + else + { + /* UDP: wait for a message, but keep it in the queue */ + char buf[1] = { 0 }; + + ret = (int) recvfrom( bind_ctx->fd, buf, sizeof( buf ), MSG_PEEK, + (struct sockaddr *) &client_addr, &n ); + +#if defined(_WIN32) + if( ret == SOCKET_ERROR && + WSAGetLastError() == WSAEMSGSIZE ) + { + /* We know buf is too small, thanks, just peeking here */ + ret = 0; + } +#endif + } + + if( ret < 0 ) + { + if( net_would_block( bind_ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + } + + /* UDP: hijack the listening socket to communicate with the client, + * then bind a new socket to accept new connections */ + if( type != SOCK_STREAM ) + { + struct sockaddr_storage local_addr; + int one = 1; + + if( connect( bind_ctx->fd, (struct sockaddr *) &client_addr, n ) != 0 ) + return( MBEDTLS_ERR_NET_ACCEPT_FAILED ); + + client_ctx->fd = bind_ctx->fd; + bind_ctx->fd = -1; /* In case we exit early */ + + n = sizeof( struct sockaddr_storage ); + if( getsockname( client_ctx->fd, + (struct sockaddr *) &local_addr, &n ) != 0 || + ( bind_ctx->fd = (int) socket( local_addr.ss_family, + SOCK_DGRAM, IPPROTO_UDP ) ) < 0 || + setsockopt( bind_ctx->fd, SOL_SOCKET, SO_REUSEADDR, + (const char *) &one, sizeof( one ) ) != 0 ) + { + return( MBEDTLS_ERR_NET_SOCKET_FAILED ); + } + + if( bind( bind_ctx->fd, (struct sockaddr *) &local_addr, n ) != 0 ) + { + return( MBEDTLS_ERR_NET_BIND_FAILED ); + } + } + + if( client_ip != NULL ) + { + if( client_addr.ss_family == AF_INET ) + { + struct sockaddr_in *addr4 = (struct sockaddr_in *) &client_addr; + *ip_len = sizeof( addr4->sin_addr.s_addr ); + + if( buf_size < *ip_len ) + return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); + + memcpy( client_ip, &addr4->sin_addr.s_addr, *ip_len ); + } + else + { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &client_addr; + *ip_len = sizeof( addr6->sin6_addr.s6_addr ); + + if( buf_size < *ip_len ) + return( MBEDTLS_ERR_NET_BUFFER_TOO_SMALL ); + + memcpy( client_ip, &addr6->sin6_addr.s6_addr, *ip_len); + } + } + + return( 0 ); +} + +/* + * Set the socket blocking or non-blocking + */ +int mbedtls_net_set_block( mbedtls_net_context *ctx ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + u_long n = 0; + return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); +#else + return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) & ~O_NONBLOCK ) ); +#endif +} + +int mbedtls_net_set_nonblock( mbedtls_net_context *ctx ) +{ +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + u_long n = 1; + return( ioctlsocket( ctx->fd, FIONBIO, &n ) ); +#else + return( fcntl( ctx->fd, F_SETFL, fcntl( ctx->fd, F_GETFL ) | O_NONBLOCK ) ); +#endif +} + +/* + * Portable usleep helper + */ +void mbedtls_net_usleep( unsigned long usec ) +{ +#if defined(_WIN32) + Sleep( ( usec + 999 ) / 1000 ); +#else + struct timeval tv; + tv.tv_sec = usec / 1000000; +#if defined(__unix__) || defined(__unix) || \ + ( defined(__APPLE__) && defined(__MACH__) ) + tv.tv_usec = (suseconds_t) usec % 1000000; +#else + tv.tv_usec = usec % 1000000; +#endif + select( 0, NULL, NULL, NULL, &tv ); +#endif +} + +/* + * Read at most 'len' characters + */ +int mbedtls_net_recv( void *ctx, unsigned char *buf, size_t len ) +{ + int ret; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + ret = (int) read( fd, buf, len ); + + if( ret < 0 ) + { + if( net_would_block( ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); +#else + if( errno == EPIPE || errno == ECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); + + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + + return( MBEDTLS_ERR_NET_RECV_FAILED ); + } + + return( ret ); +} + +/* + * Read at most 'len' characters, blocking for at most 'timeout' ms + */ +int mbedtls_net_recv_timeout( void *ctx, unsigned char *buf, size_t len, + uint32_t timeout ) +{ + int ret; + struct timeval tv; + fd_set read_fds; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + FD_ZERO( &read_fds ); + FD_SET( fd, &read_fds ); + + tv.tv_sec = timeout / 1000; + tv.tv_usec = ( timeout % 1000 ) * 1000; + + ret = select( fd + 1, &read_fds, NULL, NULL, timeout == 0 ? NULL : &tv ); + + /* Zero fds ready means we timed out */ + if( ret == 0 ) + return( MBEDTLS_ERR_SSL_TIMEOUT ); + + if( ret < 0 ) + { +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAEINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#else + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + + return( MBEDTLS_ERR_NET_RECV_FAILED ); + } + + /* This call will not block */ + return( mbedtls_net_recv( ctx, buf, len ) ); +} + +/* + * Write at most 'len' characters + */ +int mbedtls_net_send( void *ctx, const unsigned char *buf, size_t len ) +{ + int ret; + int fd = ((mbedtls_net_context *) ctx)->fd; + + if( fd < 0 ) + return( MBEDTLS_ERR_NET_INVALID_CONTEXT ); + + ret = (int) write( fd, buf, len ); + + if( ret < 0 ) + { + if( net_would_block( ctx ) != 0 ) + return( MBEDTLS_ERR_SSL_WANT_WRITE ); + +#if ( defined(_WIN32) || defined(_WIN32_WCE) ) && !defined(EFIX64) && \ + !defined(EFI32) + if( WSAGetLastError() == WSAECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); +#else + if( errno == EPIPE || errno == ECONNRESET ) + return( MBEDTLS_ERR_NET_CONN_RESET ); + + if( errno == EINTR ) + return( MBEDTLS_ERR_SSL_WANT_WRITE ); +#endif + + return( MBEDTLS_ERR_NET_SEND_FAILED ); + } + + return( ret ); +} + +/* + * Gracefully close the connection + */ +void mbedtls_net_free( mbedtls_net_context *ctx ) +{ + if( ctx->fd == -1 ) + return; + + shutdown( ctx->fd, 2 ); + close( ctx->fd ); + + ctx->fd = -1; +} + +#endif /* MBEDTLS_NET_C */ diff --git a/c++/src/connect/mbedtls/oid.c b/c++/src/connect/mbedtls/oid.c new file mode 100644 index 00000000..f13826ed --- /dev/null +++ b/c++/src/connect/mbedtls/oid.c @@ -0,0 +1,710 @@ +/** + * \file oid.c + * + * \brief Object Identifier (OID) database + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_OID_C) + +#include "mbedtls/oid.h" +#include "mbedtls/rsa.h" + +#include +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +#include "mbedtls/x509.h" +#endif + +/* + * Macro to automatically add the size of #define'd OIDs + */ +#define ADD_LEN(s) s, MBEDTLS_OID_SIZE(s) + +/* + * Macro to generate an internal function for oid_XXX_from_asn1() (used by + * the other functions) + */ +#define FN_OID_TYPED_FROM_ASN1( TYPE_T, NAME, LIST ) \ +static const TYPE_T * oid_ ## NAME ## _from_asn1( const mbedtls_asn1_buf *oid ) \ +{ \ + const TYPE_T *p = LIST; \ + const mbedtls_oid_descriptor_t *cur = (const mbedtls_oid_descriptor_t *) p; \ + if( p == NULL || oid == NULL ) return( NULL ); \ + while( cur->asn1 != NULL ) { \ + if( cur->asn1_len == oid->len && \ + memcmp( cur->asn1, oid->p, oid->len ) == 0 ) { \ + return( p ); \ + } \ + p++; \ + cur = (const mbedtls_oid_descriptor_t *) p; \ + } \ + return( NULL ); \ +} + +/* + * Macro to generate a function for retrieving a single attribute from the + * descriptor of an mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_DESCRIPTOR_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *ATTR1 = data->descriptor.ATTR1; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving a single attribute from an + * mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_ATTR1(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *ATTR1 = data->ATTR1; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving two attributes from an + * mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_ATTR2(FN_NAME, TYPE_T, TYPE_NAME, ATTR1_TYPE, ATTR1, \ + ATTR2_TYPE, ATTR2) \ +int FN_NAME( const mbedtls_asn1_buf *oid, ATTR1_TYPE * ATTR1, ATTR2_TYPE * ATTR2 ) \ +{ \ + const TYPE_T *data = oid_ ## TYPE_NAME ## _from_asn1( oid ); \ + if( data == NULL ) return( MBEDTLS_ERR_OID_NOT_FOUND ); \ + *ATTR1 = data->ATTR1; \ + *ATTR2 = data->ATTR2; \ + return( 0 ); \ +} + +/* + * Macro to generate a function for retrieving the OID based on a single + * attribute from a mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_OID_BY_ATTR1(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1) \ +int FN_NAME( ATTR1_TYPE ATTR1, const char **oid, size_t *olen ) \ +{ \ + const TYPE_T *cur = LIST; \ + while( cur->descriptor.asn1 != NULL ) { \ + if( cur->ATTR1 == ATTR1 ) { \ + *oid = cur->descriptor.asn1; \ + *olen = cur->descriptor.asn1_len; \ + return( 0 ); \ + } \ + cur++; \ + } \ + return( MBEDTLS_ERR_OID_NOT_FOUND ); \ +} + +/* + * Macro to generate a function for retrieving the OID based on two + * attributes from a mbedtls_oid_descriptor_t wrapper. + */ +#define FN_OID_GET_OID_BY_ATTR2(FN_NAME, TYPE_T, LIST, ATTR1_TYPE, ATTR1, \ + ATTR2_TYPE, ATTR2) \ +int FN_NAME( ATTR1_TYPE ATTR1, ATTR2_TYPE ATTR2, const char **oid , \ + size_t *olen ) \ +{ \ + const TYPE_T *cur = LIST; \ + while( cur->descriptor.asn1 != NULL ) { \ + if( cur->ATTR1 == ATTR1 && cur->ATTR2 == ATTR2 ) { \ + *oid = cur->descriptor.asn1; \ + *olen = cur->descriptor.asn1_len; \ + return( 0 ); \ + } \ + cur++; \ + } \ + return( MBEDTLS_ERR_OID_NOT_FOUND ); \ +} + +#if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) +/* + * For X520 attribute types + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + const char *short_name; +} oid_x520_attr_t; + +static const oid_x520_attr_t oid_x520_attr_type[] = +{ + { + { ADD_LEN( MBEDTLS_OID_AT_CN ), "id-at-commonName", "Common Name" }, + "CN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_COUNTRY ), "id-at-countryName", "Country" }, + "C", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_LOCALITY ), "id-at-locality", "Locality" }, + "L", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_STATE ), "id-at-state", "State" }, + "ST", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_ORGANIZATION ),"id-at-organizationName", "Organization" }, + "O", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_ORG_UNIT ), "id-at-organizationalUnitName", "Org Unit" }, + "OU", + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS9_EMAIL ), "emailAddress", "E-mail address" }, + "emailAddress", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_SERIAL_NUMBER ),"id-at-serialNumber", "Serial number" }, + "serialNumber", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_POSTAL_ADDRESS ),"id-at-postalAddress", "Postal address" }, + "postalAddress", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_POSTAL_CODE ), "id-at-postalCode", "Postal code" }, + "postalCode", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_SUR_NAME ), "id-at-surName", "Surname" }, + "SN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_GIVEN_NAME ), "id-at-givenName", "Given name" }, + "GN", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_INITIALS ), "id-at-initials", "Initials" }, + "initials", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_GENERATION_QUALIFIER ), "id-at-generationQualifier", "Generation qualifier" }, + "generationQualifier", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_TITLE ), "id-at-title", "Title" }, + "title", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_DN_QUALIFIER ),"id-at-dnQualifier", "Distinguished Name qualifier" }, + "dnQualifier", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_PSEUDONYM ), "id-at-pseudonym", "Pseudonym" }, + "pseudonym", + }, + { + { ADD_LEN( MBEDTLS_OID_DOMAIN_COMPONENT ), "id-domainComponent", "Domain component" }, + "DC", + }, + { + { ADD_LEN( MBEDTLS_OID_AT_UNIQUE_IDENTIFIER ), "id-at-uniqueIdentifier", "Unique Identifier" }, + "uniqueIdentifier", + }, + { + { NULL, 0, NULL, NULL }, + NULL, + } +}; + +FN_OID_TYPED_FROM_ASN1(oid_x520_attr_t, x520_attr, oid_x520_attr_type) +FN_OID_GET_ATTR1(mbedtls_oid_get_attr_short_name, oid_x520_attr_t, x520_attr, const char *, short_name) + +/* + * For X509 extensions + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + int ext_type; +} oid_x509_ext_t; + +static const oid_x509_ext_t oid_x509_ext[] = +{ + { + { ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ), "id-ce-basicConstraints", "Basic Constraints" }, + MBEDTLS_X509_EXT_BASIC_CONSTRAINTS, + }, + { + { ADD_LEN( MBEDTLS_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" }, + MBEDTLS_X509_EXT_KEY_USAGE, + }, + { + { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" }, + MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE, + }, + { + { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" }, + MBEDTLS_X509_EXT_SUBJECT_ALT_NAME, + }, + { + { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" }, + MBEDTLS_X509_EXT_NS_CERT_TYPE, + }, + { + { NULL, 0, NULL, NULL }, + 0, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_x509_ext_t, x509_ext, oid_x509_ext) +FN_OID_GET_ATTR1(mbedtls_oid_get_x509_ext_type, oid_x509_ext_t, x509_ext, int, ext_type) + +static const mbedtls_oid_descriptor_t oid_ext_key_usage[] = +{ + { ADD_LEN( MBEDTLS_OID_SERVER_AUTH ), "id-kp-serverAuth", "TLS Web Server Authentication" }, + { ADD_LEN( MBEDTLS_OID_CLIENT_AUTH ), "id-kp-clientAuth", "TLS Web Client Authentication" }, + { ADD_LEN( MBEDTLS_OID_CODE_SIGNING ), "id-kp-codeSigning", "Code Signing" }, + { ADD_LEN( MBEDTLS_OID_EMAIL_PROTECTION ), "id-kp-emailProtection", "E-mail Protection" }, + { ADD_LEN( MBEDTLS_OID_TIME_STAMPING ), "id-kp-timeStamping", "Time Stamping" }, + { ADD_LEN( MBEDTLS_OID_OCSP_SIGNING ), "id-kp-OCSPSigning", "OCSP Signing" }, + { NULL, 0, NULL, NULL }, +}; + +FN_OID_TYPED_FROM_ASN1(mbedtls_oid_descriptor_t, ext_key_usage, oid_ext_key_usage) +FN_OID_GET_ATTR1(mbedtls_oid_get_extended_key_usage, mbedtls_oid_descriptor_t, ext_key_usage, const char *, description) +#endif /* MBEDTLS_X509_USE_C || MBEDTLS_X509_CREATE_C */ + +#if defined(MBEDTLS_MD_C) +/* + * For SignatureAlgorithmIdentifier + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; + mbedtls_pk_type_t pk_alg; +} oid_sig_alg_t; + +static const oid_sig_alg_t oid_sig_alg[] = +{ +#if defined(MBEDTLS_RSA_C) +#if defined(MBEDTLS_MD2_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD2 ), "md2WithRSAEncryption", "RSA with MD2" }, + MBEDTLS_MD_MD2, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_MD2_C */ +#if defined(MBEDTLS_MD4_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD4 ), "md4WithRSAEncryption", "RSA with MD4" }, + MBEDTLS_MD_MD4, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_MD4_C */ +#if defined(MBEDTLS_MD5_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_MD5 ), "md5WithRSAEncryption", "RSA with MD5" }, + MBEDTLS_MD_MD5, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_MD5_C */ +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA1 ), "sha-1WithRSAEncryption", "RSA with SHA1" }, + MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA224 ), "sha224WithRSAEncryption", "RSA with SHA-224" }, + MBEDTLS_MD_SHA224, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA256 ), "sha256WithRSAEncryption", "RSA with SHA-256" }, + MBEDTLS_MD_SHA256, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA384 ), "sha384WithRSAEncryption", "RSA with SHA-384" }, + MBEDTLS_MD_SHA384, MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS1_SHA512 ), "sha512WithRSAEncryption", "RSA with SHA-512" }, + MBEDTLS_MD_SHA512, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_RSA_SHA_OBS ), "sha-1WithRSAEncryption", "RSA with SHA1" }, + MBEDTLS_MD_SHA1, MBEDTLS_PK_RSA, + }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECDSA_C) +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA1 ), "ecdsa-with-SHA1", "ECDSA with SHA1" }, + MBEDTLS_MD_SHA1, MBEDTLS_PK_ECDSA, + }, +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA224 ), "ecdsa-with-SHA224", "ECDSA with SHA224" }, + MBEDTLS_MD_SHA224, MBEDTLS_PK_ECDSA, + }, + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA256 ), "ecdsa-with-SHA256", "ECDSA with SHA256" }, + MBEDTLS_MD_SHA256, MBEDTLS_PK_ECDSA, + }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA384 ), "ecdsa-with-SHA384", "ECDSA with SHA384" }, + MBEDTLS_MD_SHA384, MBEDTLS_PK_ECDSA, + }, + { + { ADD_LEN( MBEDTLS_OID_ECDSA_SHA512 ), "ecdsa-with-SHA512", "ECDSA with SHA512" }, + MBEDTLS_MD_SHA512, MBEDTLS_PK_ECDSA, + }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_ECDSA_C */ +#if defined(MBEDTLS_RSA_C) + { + { ADD_LEN( MBEDTLS_OID_RSASSA_PSS ), "RSASSA-PSS", "RSASSA-PSS" }, + MBEDTLS_MD_NONE, MBEDTLS_PK_RSASSA_PSS, + }, +#endif /* MBEDTLS_RSA_C */ + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, MBEDTLS_PK_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_sig_alg_t, sig_alg, oid_sig_alg) +FN_OID_GET_DESCRIPTOR_ATTR1(mbedtls_oid_get_sig_alg_desc, oid_sig_alg_t, sig_alg, const char *, description) +FN_OID_GET_ATTR2(mbedtls_oid_get_sig_alg, oid_sig_alg_t, sig_alg, mbedtls_md_type_t, md_alg, mbedtls_pk_type_t, pk_alg) +FN_OID_GET_OID_BY_ATTR2(mbedtls_oid_get_oid_by_sig_alg, oid_sig_alg_t, oid_sig_alg, mbedtls_pk_type_t, pk_alg, mbedtls_md_type_t, md_alg) +#endif /* MBEDTLS_MD_C */ + +/* + * For PublicKeyInfo (PKCS1, RFC 5480) + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_pk_type_t pk_alg; +} oid_pk_alg_t; + +static const oid_pk_alg_t oid_pk_alg[] = +{ + { + { ADD_LEN( MBEDTLS_OID_PKCS1_RSA ), "rsaEncryption", "RSA" }, + MBEDTLS_PK_RSA, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_ALG_UNRESTRICTED ), "id-ecPublicKey", "Generic EC key" }, + MBEDTLS_PK_ECKEY, + }, + { + { ADD_LEN( MBEDTLS_OID_EC_ALG_ECDH ), "id-ecDH", "EC key for ECDH" }, + MBEDTLS_PK_ECKEY_DH, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_PK_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_pk_alg_t, pk_alg, oid_pk_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_pk_alg, oid_pk_alg_t, pk_alg, mbedtls_pk_type_t, pk_alg) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_pk_alg, oid_pk_alg_t, oid_pk_alg, mbedtls_pk_type_t, pk_alg) + +#if defined(MBEDTLS_ECP_C) +/* + * For namedCurve (RFC 5480) + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_ecp_group_id grp_id; +} oid_ecp_grp_t; + +static const oid_ecp_grp_t oid_ecp_grp[] = +{ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192R1 ), "secp192r1", "secp192r1" }, + MBEDTLS_ECP_DP_SECP192R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224R1 ), "secp224r1", "secp224r1" }, + MBEDTLS_ECP_DP_SECP224R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256R1 ), "secp256r1", "secp256r1" }, + MBEDTLS_ECP_DP_SECP256R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP384R1 ), "secp384r1", "secp384r1" }, + MBEDTLS_ECP_DP_SECP384R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP521R1 ), "secp521r1", "secp521r1" }, + MBEDTLS_ECP_DP_SECP521R1, + }, +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP192K1 ), "secp192k1", "secp192k1" }, + MBEDTLS_ECP_DP_SECP192K1, + }, +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP224K1 ), "secp224k1", "secp224k1" }, + MBEDTLS_ECP_DP_SECP224K1, + }, +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_SECP256K1 ), "secp256k1", "secp256k1" }, + MBEDTLS_ECP_DP_SECP256K1, + }, +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP256R1 ), "brainpoolP256r1","brainpool256r1" }, + MBEDTLS_ECP_DP_BP256R1, + }, +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP384R1 ), "brainpoolP384r1","brainpool384r1" }, + MBEDTLS_ECP_DP_BP384R1, + }, +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + { + { ADD_LEN( MBEDTLS_OID_EC_GRP_BP512R1 ), "brainpoolP512r1","brainpool512r1" }, + MBEDTLS_ECP_DP_BP512R1, + }, +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ + { + { NULL, 0, NULL, NULL }, + MBEDTLS_ECP_DP_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp) +FN_OID_GET_ATTR1(mbedtls_oid_get_ec_grp, oid_ecp_grp_t, grp_id, mbedtls_ecp_group_id, grp_id) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_ec_grp, oid_ecp_grp_t, oid_ecp_grp, mbedtls_ecp_group_id, grp_id) +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_CIPHER_C) +/* + * For PKCS#5 PBES2 encryption algorithm + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_cipher_type_t cipher_alg; +} oid_cipher_alg_t; + +static const oid_cipher_alg_t oid_cipher_alg[] = +{ + { + { ADD_LEN( MBEDTLS_OID_DES_CBC ), "desCBC", "DES-CBC" }, + MBEDTLS_CIPHER_DES_CBC, + }, + { + { ADD_LEN( MBEDTLS_OID_DES_EDE3_CBC ), "des-ede3-cbc", "DES-EDE3-CBC" }, + MBEDTLS_CIPHER_DES_EDE3_CBC, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_CIPHER_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_cipher_alg_t, cipher_alg, oid_cipher_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_cipher_alg, oid_cipher_alg_t, cipher_alg, mbedtls_cipher_type_t, cipher_alg) +#endif /* MBEDTLS_CIPHER_C */ + +#if defined(MBEDTLS_MD_C) +/* + * For digestAlgorithm + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; +} oid_md_alg_t; + +static const oid_md_alg_t oid_md_alg[] = +{ +#if defined(MBEDTLS_MD2_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD2 ), "id-md2", "MD2" }, + MBEDTLS_MD_MD2, + }, +#endif /* MBEDTLS_MD2_C */ +#if defined(MBEDTLS_MD4_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD4 ), "id-md4", "MD4" }, + MBEDTLS_MD_MD4, + }, +#endif /* MBEDTLS_MD4_C */ +#if defined(MBEDTLS_MD5_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_MD5 ), "id-md5", "MD5" }, + MBEDTLS_MD_MD5, + }, +#endif /* MBEDTLS_MD5_C */ +#if defined(MBEDTLS_SHA1_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA1 ), "id-sha1", "SHA-1" }, + MBEDTLS_MD_SHA1, + }, +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA224 ), "id-sha224", "SHA-224" }, + MBEDTLS_MD_SHA224, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA256 ), "id-sha256", "SHA-256" }, + MBEDTLS_MD_SHA256, + }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA384 ), "id-sha384", "SHA-384" }, + MBEDTLS_MD_SHA384, + }, + { + { ADD_LEN( MBEDTLS_OID_DIGEST_ALG_SHA512 ), "id-sha512", "SHA-512" }, + MBEDTLS_MD_SHA512, + }, +#endif /* MBEDTLS_SHA512_C */ + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_md_alg_t, md_alg, oid_md_alg) +FN_OID_GET_ATTR1(mbedtls_oid_get_md_alg, oid_md_alg_t, md_alg, mbedtls_md_type_t, md_alg) +FN_OID_GET_OID_BY_ATTR1(mbedtls_oid_get_oid_by_md, oid_md_alg_t, oid_md_alg, mbedtls_md_type_t, md_alg) +#endif /* MBEDTLS_MD_C */ + +#if defined(MBEDTLS_PKCS12_C) +/* + * For PKCS#12 PBEs + */ +typedef struct { + mbedtls_oid_descriptor_t descriptor; + mbedtls_md_type_t md_alg; + mbedtls_cipher_type_t cipher_alg; +} oid_pkcs12_pbe_alg_t; + +static const oid_pkcs12_pbe_alg_t oid_pkcs12_pbe_alg[] = +{ + { + { ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES3_EDE_CBC ), "pbeWithSHAAnd3-KeyTripleDES-CBC", "PBE with SHA1 and 3-Key 3DES" }, + MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE3_CBC, + }, + { + { ADD_LEN( MBEDTLS_OID_PKCS12_PBE_SHA1_DES2_EDE_CBC ), "pbeWithSHAAnd2-KeyTripleDES-CBC", "PBE with SHA1 and 2-Key 3DES" }, + MBEDTLS_MD_SHA1, MBEDTLS_CIPHER_DES_EDE_CBC, + }, + { + { NULL, 0, NULL, NULL }, + MBEDTLS_MD_NONE, MBEDTLS_CIPHER_NONE, + }, +}; + +FN_OID_TYPED_FROM_ASN1(oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, oid_pkcs12_pbe_alg) +FN_OID_GET_ATTR2(mbedtls_oid_get_pkcs12_pbe_alg, oid_pkcs12_pbe_alg_t, pkcs12_pbe_alg, mbedtls_md_type_t, md_alg, mbedtls_cipher_type_t, cipher_alg) +#endif /* MBEDTLS_PKCS12_C */ + +#define OID_SAFE_SNPRINTF \ + do { \ + if( ret < 0 || (size_t) ret >= n ) \ + return( MBEDTLS_ERR_OID_BUF_TOO_SMALL ); \ + \ + n -= (size_t) ret; \ + p += (size_t) ret; \ + } while( 0 ) + +/* Return the x.y.z.... style numeric string for the given OID */ +int mbedtls_oid_get_numeric_string( char *buf, size_t size, + const mbedtls_asn1_buf *oid ) +{ + int ret; + size_t i, n; + unsigned int value; + char *p; + + p = buf; + n = size; + + /* First byte contains first two dots */ + if( oid->len > 0 ) + { + ret = mbedtls_snprintf( p, n, "%d.%d", oid->p[0] / 40, oid->p[0] % 40 ); + OID_SAFE_SNPRINTF; + } + + value = 0; + for( i = 1; i < oid->len; i++ ) + { + /* Prevent overflow in value. */ + if( ( ( value << 7 ) >> 7 ) != value ) + return( MBEDTLS_ERR_OID_BUF_TOO_SMALL ); + + value <<= 7; + value += oid->p[i] & 0x7F; + + if( !( oid->p[i] & 0x80 ) ) + { + /* Last byte */ + ret = mbedtls_snprintf( p, n, ".%d", value ); + OID_SAFE_SNPRINTF; + value = 0; + } + } + + return( (int) ( size - n ) ); +} + +#endif /* MBEDTLS_OID_C */ diff --git a/c++/src/connect/mbedtls/padlock.c b/c++/src/connect/mbedtls/padlock.c new file mode 100644 index 00000000..b85ff9cd --- /dev/null +++ b/c++/src/connect/mbedtls/padlock.c @@ -0,0 +1,170 @@ +/* + * VIA PadLock support functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * This implementation is based on the VIA PadLock Programming Guide: + * + * http://www.via.com.tw/en/downloads/whitepapers/initiatives/padlock/ + * programming_guide.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PADLOCK_C) + +#include "mbedtls/padlock.h" + +#include + +#ifndef asm +#define asm __asm +#endif + +#if defined(MBEDTLS_HAVE_X86) + +/* + * PadLock detection routine + */ +int mbedtls_padlock_has_support( int feature ) +{ + static int flags = -1; + int ebx = 0, edx = 0; + + if( flags == -1 ) + { + asm( "movl %%ebx, %0 \n\t" + "movl $0xC0000000, %%eax \n\t" + "cpuid \n\t" + "cmpl $0xC0000001, %%eax \n\t" + "movl $0, %%edx \n\t" + "jb unsupported \n\t" + "movl $0xC0000001, %%eax \n\t" + "cpuid \n\t" + "unsupported: \n\t" + "movl %%edx, %1 \n\t" + "movl %2, %%ebx \n\t" + : "=m" (ebx), "=m" (edx) + : "m" (ebx) + : "eax", "ecx", "edx" ); + + flags = edx; + } + + return( flags & feature ); +} + +/* + * PadLock AES-ECB block en(de)cryption + */ +int mbedtls_padlock_xcryptecb( mbedtls_aes_context *ctx, + int mode, + const unsigned char input[16], + unsigned char output[16] ) +{ + int ebx = 0; + uint32_t *rk; + uint32_t *blk; + uint32_t *ctrl; + unsigned char buf[256]; + + rk = ctx->rk; + blk = MBEDTLS_PADLOCK_ALIGN16( buf ); + memcpy( blk, input, 16 ); + + ctrl = blk + 4; + *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + ( mode^1 ) - 10 ) << 9 ); + + asm( "pushfl \n\t" + "popfl \n\t" + "movl %%ebx, %0 \n\t" + "movl $1, %%ecx \n\t" + "movl %2, %%edx \n\t" + "movl %3, %%ebx \n\t" + "movl %4, %%esi \n\t" + "movl %4, %%edi \n\t" + ".byte 0xf3,0x0f,0xa7,0xc8 \n\t" + "movl %1, %%ebx \n\t" + : "=m" (ebx) + : "m" (ebx), "m" (ctrl), "m" (rk), "m" (blk) + : "memory", "ecx", "edx", "esi", "edi" ); + + memcpy( output, blk, 16 ); + + return( 0 ); +} + +/* + * PadLock AES-CBC buffer en(de)cryption + */ +int mbedtls_padlock_xcryptcbc( mbedtls_aes_context *ctx, + int mode, + size_t length, + unsigned char iv[16], + const unsigned char *input, + unsigned char *output ) +{ + int ebx = 0; + size_t count; + uint32_t *rk; + uint32_t *iw; + uint32_t *ctrl; + unsigned char buf[256]; + + if( ( (long) input & 15 ) != 0 || + ( (long) output & 15 ) != 0 ) + return( MBEDTLS_ERR_PADLOCK_DATA_MISALIGNED ); + + rk = ctx->rk; + iw = MBEDTLS_PADLOCK_ALIGN16( buf ); + memcpy( iw, iv, 16 ); + + ctrl = iw + 4; + *ctrl = 0x80 | ctx->nr | ( ( ctx->nr + ( mode ^ 1 ) - 10 ) << 9 ); + + count = ( length + 15 ) >> 4; + + asm( "pushfl \n\t" + "popfl \n\t" + "movl %%ebx, %0 \n\t" + "movl %2, %%ecx \n\t" + "movl %3, %%edx \n\t" + "movl %4, %%ebx \n\t" + "movl %5, %%esi \n\t" + "movl %6, %%edi \n\t" + "movl %7, %%eax \n\t" + ".byte 0xf3,0x0f,0xa7,0xd0 \n\t" + "movl %1, %%ebx \n\t" + : "=m" (ebx) + : "m" (ebx), "m" (count), "m" (ctrl), + "m" (rk), "m" (input), "m" (output), "m" (iw) + : "memory", "eax", "ecx", "edx", "esi", "edi" ); + + memcpy( iv, iw, 16 ); + + return( 0 ); +} + +#endif /* MBEDTLS_HAVE_X86 */ + +#endif /* MBEDTLS_PADLOCK_C */ diff --git a/c++/src/connect/mbedtls/pem.c b/c++/src/connect/mbedtls/pem.c new file mode 100644 index 00000000..8dd86a4a --- /dev/null +++ b/c++/src/connect/mbedtls/pem.c @@ -0,0 +1,449 @@ +/* + * Privacy Enhanced Mail (PEM) decoding + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) || defined(MBEDTLS_PEM_WRITE_C) + +#include "mbedtls/pem.h" +#include "mbedtls/base64.h" +#include "mbedtls/des.h" +#include "mbedtls/aes.h" +#include "mbedtls/md5.h" +#include "mbedtls/cipher.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void mbedtls_pem_init( mbedtls_pem_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_pem_context ) ); +} + +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) +/* + * Read a 16-byte hex string and convert it to binary + */ +static int pem_get_iv( const unsigned char *s, unsigned char *iv, + size_t iv_len ) +{ + size_t i, j, k; + + memset( iv, 0, iv_len ); + + for( i = 0; i < iv_len * 2; i++, s++ ) + { + if( *s >= '0' && *s <= '9' ) j = *s - '0'; else + if( *s >= 'A' && *s <= 'F' ) j = *s - '7'; else + if( *s >= 'a' && *s <= 'f' ) j = *s - 'W'; else + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + k = ( ( i & 1 ) != 0 ) ? j : j << 4; + + iv[i >> 1] = (unsigned char)( iv[i >> 1] | k ); + } + + return( 0 ); +} + +static void pem_pbkdf1( unsigned char *key, size_t keylen, + unsigned char *iv, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_md5_context md5_ctx; + unsigned char md5sum[16]; + size_t use_len; + + mbedtls_md5_init( &md5_ctx ); + + /* + * key[ 0..15] = MD5(pwd || IV) + */ + mbedtls_md5_starts( &md5_ctx ); + mbedtls_md5_update( &md5_ctx, pwd, pwdlen ); + mbedtls_md5_update( &md5_ctx, iv, 8 ); + mbedtls_md5_finish( &md5_ctx, md5sum ); + + if( keylen <= 16 ) + { + memcpy( key, md5sum, keylen ); + + mbedtls_md5_free( &md5_ctx ); + mbedtls_zeroize( md5sum, 16 ); + return; + } + + memcpy( key, md5sum, 16 ); + + /* + * key[16..23] = MD5(key[ 0..15] || pwd || IV]) + */ + mbedtls_md5_starts( &md5_ctx ); + mbedtls_md5_update( &md5_ctx, md5sum, 16 ); + mbedtls_md5_update( &md5_ctx, pwd, pwdlen ); + mbedtls_md5_update( &md5_ctx, iv, 8 ); + mbedtls_md5_finish( &md5_ctx, md5sum ); + + use_len = 16; + if( keylen < 32 ) + use_len = keylen - 16; + + memcpy( key + 16, md5sum, use_len ); + + mbedtls_md5_free( &md5_ctx ); + mbedtls_zeroize( md5sum, 16 ); +} + +#if defined(MBEDTLS_DES_C) +/* + * Decrypt with DES-CBC, using PBKDF1 for key derivation + */ +static void pem_des_decrypt( unsigned char des_iv[8], + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_des_context des_ctx; + unsigned char des_key[8]; + + mbedtls_des_init( &des_ctx ); + + pem_pbkdf1( des_key, 8, des_iv, pwd, pwdlen ); + + mbedtls_des_setkey_dec( &des_ctx, des_key ); + mbedtls_des_crypt_cbc( &des_ctx, MBEDTLS_DES_DECRYPT, buflen, + des_iv, buf, buf ); + + mbedtls_des_free( &des_ctx ); + mbedtls_zeroize( des_key, 8 ); +} + +/* + * Decrypt with 3DES-CBC, using PBKDF1 for key derivation + */ +static void pem_des3_decrypt( unsigned char des3_iv[8], + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_des3_context des3_ctx; + unsigned char des3_key[24]; + + mbedtls_des3_init( &des3_ctx ); + + pem_pbkdf1( des3_key, 24, des3_iv, pwd, pwdlen ); + + mbedtls_des3_set3key_dec( &des3_ctx, des3_key ); + mbedtls_des3_crypt_cbc( &des3_ctx, MBEDTLS_DES_DECRYPT, buflen, + des3_iv, buf, buf ); + + mbedtls_des3_free( &des3_ctx ); + mbedtls_zeroize( des3_key, 24 ); +} +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) +/* + * Decrypt with AES-XXX-CBC, using PBKDF1 for key derivation + */ +static void pem_aes_decrypt( unsigned char aes_iv[16], unsigned int keylen, + unsigned char *buf, size_t buflen, + const unsigned char *pwd, size_t pwdlen ) +{ + mbedtls_aes_context aes_ctx; + unsigned char aes_key[32]; + + mbedtls_aes_init( &aes_ctx ); + + pem_pbkdf1( aes_key, keylen, aes_iv, pwd, pwdlen ); + + mbedtls_aes_setkey_dec( &aes_ctx, aes_key, keylen * 8 ); + mbedtls_aes_crypt_cbc( &aes_ctx, MBEDTLS_AES_DECRYPT, buflen, + aes_iv, buf, buf ); + + mbedtls_aes_free( &aes_ctx ); + mbedtls_zeroize( aes_key, keylen ); +} +#endif /* MBEDTLS_AES_C */ + +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + +int mbedtls_pem_read_buffer( mbedtls_pem_context *ctx, const char *header, const char *footer, + const unsigned char *data, const unsigned char *pwd, + size_t pwdlen, size_t *use_len ) +{ + int ret, enc; + size_t len; + unsigned char *buf; + const unsigned char *s1, *s2, *end; +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + unsigned char pem_iv[16]; + mbedtls_cipher_type_t enc_alg = MBEDTLS_CIPHER_NONE; +#else + ((void) pwd); + ((void) pwdlen); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + + if( ctx == NULL ) + return( MBEDTLS_ERR_PEM_BAD_INPUT_DATA ); + + s1 = (unsigned char *) strstr( (const char *) data, header ); + + if( s1 == NULL ) + return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + s2 = (unsigned char *) strstr( (const char *) data, footer ); + + if( s2 == NULL || s2 <= s1 ) + return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + s1 += strlen( header ); + if( *s1 == ' ' ) s1++; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ); + + end = s2; + end += strlen( footer ); + if( *end == ' ' ) end++; + if( *end == '\r' ) end++; + if( *end == '\n' ) end++; + *use_len = end - data; + + enc = 0; + + if( s2 - s1 >= 22 && memcmp( s1, "Proc-Type: 4,ENCRYPTED", 22 ) == 0 ) + { +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + enc++; + + s1 += 22; + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_INVALID_DATA ); + + +#if defined(MBEDTLS_DES_C) + if( s2 - s1 >= 23 && memcmp( s1, "DEK-Info: DES-EDE3-CBC,", 23 ) == 0 ) + { + enc_alg = MBEDTLS_CIPHER_DES_EDE3_CBC; + + s1 += 23; + if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8 ) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 16; + } + else if( s2 - s1 >= 18 && memcmp( s1, "DEK-Info: DES-CBC,", 18 ) == 0 ) + { + enc_alg = MBEDTLS_CIPHER_DES_CBC; + + s1 += 18; + if( s2 - s1 < 16 || pem_get_iv( s1, pem_iv, 8) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 16; + } +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) + if( s2 - s1 >= 14 && memcmp( s1, "DEK-Info: AES-", 14 ) == 0 ) + { + if( s2 - s1 < 22 ) + return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); + else if( memcmp( s1, "DEK-Info: AES-128-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_128_CBC; + else if( memcmp( s1, "DEK-Info: AES-192-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_192_CBC; + else if( memcmp( s1, "DEK-Info: AES-256-CBC,", 22 ) == 0 ) + enc_alg = MBEDTLS_CIPHER_AES_256_CBC; + else + return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); + + s1 += 22; + if( s2 - s1 < 32 || pem_get_iv( s1, pem_iv, 16 ) != 0 ) + return( MBEDTLS_ERR_PEM_INVALID_ENC_IV ); + + s1 += 32; + } +#endif /* MBEDTLS_AES_C */ + + if( enc_alg == MBEDTLS_CIPHER_NONE ) + return( MBEDTLS_ERR_PEM_UNKNOWN_ENC_ALG ); + + if( *s1 == '\r' ) s1++; + if( *s1 == '\n' ) s1++; + else return( MBEDTLS_ERR_PEM_INVALID_DATA ); +#else + return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + } + + if( s1 >= s2 ) + return( MBEDTLS_ERR_PEM_INVALID_DATA ); + + ret = mbedtls_base64_decode( NULL, 0, &len, s1, s2 - s1 ); + + if( ret == MBEDTLS_ERR_BASE64_INVALID_CHARACTER ) + return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); + + if( ( buf = mbedtls_calloc( 1, len ) ) == NULL ) + return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); + + if( ( ret = mbedtls_base64_decode( buf, len, &len, s1, s2 - s1 ) ) != 0 ) + { + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_INVALID_DATA + ret ); + } + + if( enc != 0 ) + { +#if defined(MBEDTLS_MD5_C) && defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_DES_C) || defined(MBEDTLS_AES_C) ) + if( pwd == NULL ) + { + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ); + } + +#if defined(MBEDTLS_DES_C) + if( enc_alg == MBEDTLS_CIPHER_DES_EDE3_CBC ) + pem_des3_decrypt( pem_iv, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_DES_CBC ) + pem_des_decrypt( pem_iv, buf, len, pwd, pwdlen ); +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_AES_C) + if( enc_alg == MBEDTLS_CIPHER_AES_128_CBC ) + pem_aes_decrypt( pem_iv, 16, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_AES_192_CBC ) + pem_aes_decrypt( pem_iv, 24, buf, len, pwd, pwdlen ); + else if( enc_alg == MBEDTLS_CIPHER_AES_256_CBC ) + pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen ); +#endif /* MBEDTLS_AES_C */ + + /* + * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3 + * length bytes (allow 4 to be sure) in all known use cases. + * + * Use that as heurisitic to try detecting password mismatchs. + */ + if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 ) + { + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ); + } +#else + mbedtls_free( buf ); + return( MBEDTLS_ERR_PEM_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_MD5_C && MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_DES_C ) */ + } + + ctx->buf = buf; + ctx->buflen = len; + + return( 0 ); +} + +void mbedtls_pem_free( mbedtls_pem_context *ctx ) +{ + mbedtls_free( ctx->buf ); + mbedtls_free( ctx->info ); + + mbedtls_zeroize( ctx, sizeof( mbedtls_pem_context ) ); +} +#endif /* MBEDTLS_PEM_PARSE_C */ + +#if defined(MBEDTLS_PEM_WRITE_C) +int mbedtls_pem_write_buffer( const char *header, const char *footer, + const unsigned char *der_data, size_t der_len, + unsigned char *buf, size_t buf_len, size_t *olen ) +{ + int ret; + unsigned char *encode_buf, *c, *p = buf; + size_t len = 0, use_len, add_len = 0; + + mbedtls_base64_encode( NULL, 0, &use_len, der_data, der_len ); + add_len = strlen( header ) + strlen( footer ) + ( use_len / 64 ) + 1; + + if( use_len + add_len > buf_len ) + { + *olen = use_len + add_len; + return( MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL ); + } + + if( ( encode_buf = mbedtls_calloc( 1, use_len ) ) == NULL ) + return( MBEDTLS_ERR_PEM_ALLOC_FAILED ); + + if( ( ret = mbedtls_base64_encode( encode_buf, use_len, &use_len, der_data, + der_len ) ) != 0 ) + { + mbedtls_free( encode_buf ); + return( ret ); + } + + memcpy( p, header, strlen( header ) ); + p += strlen( header ); + c = encode_buf; + + while( use_len ) + { + len = ( use_len > 64 ) ? 64 : use_len; + memcpy( p, c, len ); + use_len -= len; + p += len; + c += len; + *p++ = '\n'; + } + + memcpy( p, footer, strlen( footer ) ); + p += strlen( footer ); + + *p++ = '\0'; + *olen = p - buf; + + mbedtls_free( encode_buf ); + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ +#endif /* MBEDTLS_PEM_PARSE_C || MBEDTLS_PEM_WRITE_C */ diff --git a/c++/src/connect/mbedtls/pk.c b/c++/src/connect/mbedtls/pk.c new file mode 100644 index 00000000..8d13bc5c --- /dev/null +++ b/c++/src/connect/mbedtls/pk.c @@ -0,0 +1,383 @@ +/* + * Public Key abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk.h" +#include "mbedtls/pk_internal.h" + +#include "mbedtls/bignum.h" + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif + +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Initialise a mbedtls_pk_context + */ +void mbedtls_pk_init( mbedtls_pk_context *ctx ) +{ + if( ctx == NULL ) + return; + + ctx->pk_info = NULL; + ctx->pk_ctx = NULL; +} + +/* + * Free (the components of) a mbedtls_pk_context + */ +void mbedtls_pk_free( mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return; + + ctx->pk_info->ctx_free_func( ctx->pk_ctx ); + + mbedtls_zeroize( ctx, sizeof( mbedtls_pk_context ) ); +} + +/* + * Get pk_info structure from type + */ +const mbedtls_pk_info_t * mbedtls_pk_info_from_type( mbedtls_pk_type_t pk_type ) +{ + switch( pk_type ) { +#if defined(MBEDTLS_RSA_C) + case MBEDTLS_PK_RSA: + return( &mbedtls_rsa_info ); +#endif +#if defined(MBEDTLS_ECP_C) + case MBEDTLS_PK_ECKEY: + return( &mbedtls_eckey_info ); + case MBEDTLS_PK_ECKEY_DH: + return( &mbedtls_eckeydh_info ); +#endif +#if defined(MBEDTLS_ECDSA_C) + case MBEDTLS_PK_ECDSA: + return( &mbedtls_ecdsa_info ); +#endif + /* MBEDTLS_PK_RSA_ALT omitted on purpose */ + default: + return( NULL ); + } +} + +/* + * Initialise context + */ +int mbedtls_pk_setup( mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info ) +{ + if( ctx == NULL || info == NULL || ctx->pk_info != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + ctx->pk_info = info; + + return( 0 ); +} + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* + * Initialize an RSA-alt context + */ +int mbedtls_pk_setup_rsa_alt( mbedtls_pk_context *ctx, void * key, + mbedtls_pk_rsa_alt_decrypt_func decrypt_func, + mbedtls_pk_rsa_alt_sign_func sign_func, + mbedtls_pk_rsa_alt_key_len_func key_len_func ) +{ + mbedtls_rsa_alt_context *rsa_alt; + const mbedtls_pk_info_t *info = &mbedtls_rsa_alt_info; + + if( ctx == NULL || ctx->pk_info != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ( ctx->pk_ctx = info->ctx_alloc_func() ) == NULL ) + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + + ctx->pk_info = info; + + rsa_alt = (mbedtls_rsa_alt_context *) ctx->pk_ctx; + + rsa_alt->key = key; + rsa_alt->decrypt_func = decrypt_func; + rsa_alt->sign_func = sign_func; + rsa_alt->key_len_func = key_len_func; + + return( 0 ); +} +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +/* + * Tell if a PK can do the operations of the given type + */ +int mbedtls_pk_can_do( const mbedtls_pk_context *ctx, mbedtls_pk_type_t type ) +{ + /* null or NONE context can't do anything */ + if( ctx == NULL || ctx->pk_info == NULL ) + return( 0 ); + + return( ctx->pk_info->can_do( type ) ); +} + +/* + * Helper for mbedtls_pk_sign and mbedtls_pk_verify + */ +static inline int pk_hashlen_helper( mbedtls_md_type_t md_alg, size_t *hash_len ) +{ + const mbedtls_md_info_t *md_info; + + if( *hash_len != 0 ) + return( 0 ); + + if( ( md_info = mbedtls_md_info_from_type( md_alg ) ) == NULL ) + return( -1 ); + + *hash_len = mbedtls_md_get_size( md_info ); + return( 0 ); +} + +/* + * Verify a signature + */ +int mbedtls_pk_verify( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + if( ctx == NULL || ctx->pk_info == NULL || + pk_hashlen_helper( md_alg, &hash_len ) != 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->verify_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->verify_func( ctx->pk_ctx, md_alg, hash, hash_len, + sig, sig_len ) ); +} + +/* + * Verify a signature with options + */ +int mbedtls_pk_verify_ext( mbedtls_pk_type_t type, const void *options, + mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ! mbedtls_pk_can_do( ctx, type ) ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + if( type == MBEDTLS_PK_RSASSA_PSS ) + { +#if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_PKCS1_V21) + int ret; + const mbedtls_pk_rsassa_pss_options *pss_opts; + +#if defined(MBEDTLS_HAVE_INT64) + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* MBEDTLS_HAVE_INT64 */ + + if( options == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + pss_opts = (const mbedtls_pk_rsassa_pss_options *) options; + + if( sig_len < mbedtls_pk_get_len( ctx ) ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + ret = mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_pk_rsa( *ctx ), + NULL, NULL, MBEDTLS_RSA_PUBLIC, + md_alg, (unsigned int) hash_len, hash, + pss_opts->mgf1_hash_id, + pss_opts->expected_salt_len, + sig ); + if( ret != 0 ) + return( ret ); + + if( sig_len > mbedtls_pk_get_len( ctx ) ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( 0 ); +#else + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); +#endif /* MBEDTLS_RSA_C && MBEDTLS_PKCS1_V21 */ + } + + /* General case: no options */ + if( options != NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + return( mbedtls_pk_verify( ctx, md_alg, hash, hash_len, sig, sig_len ) ); +} + +/* + * Make a signature + */ +int mbedtls_pk_sign( mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + if( ctx == NULL || ctx->pk_info == NULL || + pk_hashlen_helper( md_alg, &hash_len ) != 0 ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->sign_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->sign_func( ctx->pk_ctx, md_alg, hash, hash_len, + sig, sig_len, f_rng, p_rng ) ); +} + +/* + * Decrypt message + */ +int mbedtls_pk_decrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->decrypt_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->decrypt_func( ctx->pk_ctx, input, ilen, + output, olen, osize, f_rng, p_rng ) ); +} + +/* + * Encrypt message + */ +int mbedtls_pk_encrypt( mbedtls_pk_context *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->encrypt_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + return( ctx->pk_info->encrypt_func( ctx->pk_ctx, input, ilen, + output, olen, osize, f_rng, p_rng ) ); +} + +/* + * Check public-private key pair + */ +int mbedtls_pk_check_pair( const mbedtls_pk_context *pub, const mbedtls_pk_context *prv ) +{ + if( pub == NULL || pub->pk_info == NULL || + prv == NULL || prv->pk_info == NULL || + prv->pk_info->check_pair_func == NULL ) + { + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + } + + if( prv->pk_info->type == MBEDTLS_PK_RSA_ALT ) + { + if( pub->pk_info->type != MBEDTLS_PK_RSA ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + } + else + { + if( pub->pk_info != prv->pk_info ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + } + + return( prv->pk_info->check_pair_func( pub->pk_ctx, prv->pk_ctx ) ); +} + +/* + * Get key size in bits + */ +size_t mbedtls_pk_get_bitlen( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( 0 ); + + return( ctx->pk_info->get_bitlen( ctx->pk_ctx ) ); +} + +/* + * Export debug information + */ +int mbedtls_pk_debug( const mbedtls_pk_context *ctx, mbedtls_pk_debug_item *items ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + if( ctx->pk_info->debug_func == NULL ) + return( MBEDTLS_ERR_PK_TYPE_MISMATCH ); + + ctx->pk_info->debug_func( ctx->pk_ctx, items ); + return( 0 ); +} + +/* + * Access the PK type name + */ +const char *mbedtls_pk_get_name( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( "invalid PK" ); + + return( ctx->pk_info->name ); +} + +/* + * Access the PK type + */ +mbedtls_pk_type_t mbedtls_pk_get_type( const mbedtls_pk_context *ctx ) +{ + if( ctx == NULL || ctx->pk_info == NULL ) + return( MBEDTLS_PK_NONE ); + + return( ctx->pk_info->type ); +} + +#endif /* MBEDTLS_PK_C */ diff --git a/c++/src/connect/mbedtls/pk_wrap.c b/c++/src/connect/mbedtls/pk_wrap.c new file mode 100644 index 00000000..db6274cb --- /dev/null +++ b/c++/src/connect/mbedtls/pk_wrap.c @@ -0,0 +1,513 @@ +/* + * Public Key abstraction layer: wrapper functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_C) +#include "mbedtls/pk_internal.h" + +/* Even if RSA not activated, for the sake of RSA-alt */ +#include "mbedtls/rsa.h" +#include "mbedtls/bignum.h" + +#include + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif + +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} +#endif + +#if defined(MBEDTLS_RSA_C) +static int rsa_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_RSA || + type == MBEDTLS_PK_RSASSA_PSS ); +} + +static size_t rsa_get_bitlen( const void *ctx ) +{ + return( 8 * ((const mbedtls_rsa_context *) ctx)->len ); +} + +static int rsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + +#if defined(MBEDTLS_HAVE_INT64) + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* MBEDTLS_HAVE_INT64 */ + + if( sig_len < ((mbedtls_rsa_context *) ctx)->len ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( ( ret = mbedtls_rsa_pkcs1_verify( (mbedtls_rsa_context *) ctx, NULL, NULL, + MBEDTLS_RSA_PUBLIC, md_alg, + (unsigned int) hash_len, hash, sig ) ) != 0 ) + return( ret ); + + if( sig_len > ((mbedtls_rsa_context *) ctx)->len ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( 0 ); +} + +static int rsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ +#if defined(MBEDTLS_HAVE_INT64) + if( md_alg == MBEDTLS_MD_NONE && UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* MBEDTLS_HAVE_INT64 */ + + *sig_len = ((mbedtls_rsa_context *) ctx)->len; + + return( mbedtls_rsa_pkcs1_sign( (mbedtls_rsa_context *) ctx, f_rng, p_rng, MBEDTLS_RSA_PRIVATE, + md_alg, (unsigned int) hash_len, hash, sig ) ); +} + +static int rsa_decrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + if( ilen != ((mbedtls_rsa_context *) ctx)->len ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + return( mbedtls_rsa_pkcs1_decrypt( (mbedtls_rsa_context *) ctx, f_rng, p_rng, + MBEDTLS_RSA_PRIVATE, olen, input, output, osize ) ); +} + +static int rsa_encrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + *olen = ((mbedtls_rsa_context *) ctx)->len; + + if( *olen > osize ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + return( mbedtls_rsa_pkcs1_encrypt( (mbedtls_rsa_context *) ctx, + f_rng, p_rng, MBEDTLS_RSA_PUBLIC, ilen, input, output ) ); +} + +static int rsa_check_pair_wrap( const void *pub, const void *prv ) +{ + return( mbedtls_rsa_check_pub_priv( (const mbedtls_rsa_context *) pub, + (const mbedtls_rsa_context *) prv ) ); +} + +static void *rsa_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_rsa_context ) ); + + if( ctx != NULL ) + mbedtls_rsa_init( (mbedtls_rsa_context *) ctx, 0, 0 ); + + return( ctx ); +} + +static void rsa_free_wrap( void *ctx ) +{ + mbedtls_rsa_free( (mbedtls_rsa_context *) ctx ); + mbedtls_free( ctx ); +} + +static void rsa_debug( const void *ctx, mbedtls_pk_debug_item *items ) +{ + items->type = MBEDTLS_PK_DEBUG_MPI; + items->name = "rsa.N"; + items->value = &( ((mbedtls_rsa_context *) ctx)->N ); + + items++; + + items->type = MBEDTLS_PK_DEBUG_MPI; + items->name = "rsa.E"; + items->value = &( ((mbedtls_rsa_context *) ctx)->E ); +} + +const mbedtls_pk_info_t mbedtls_rsa_info = { + MBEDTLS_PK_RSA, + "RSA", + rsa_get_bitlen, + rsa_can_do, + rsa_verify_wrap, + rsa_sign_wrap, + rsa_decrypt_wrap, + rsa_encrypt_wrap, + rsa_check_pair_wrap, + rsa_alloc_wrap, + rsa_free_wrap, + rsa_debug, +}; +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * Generic EC key + */ +static int eckey_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECKEY || + type == MBEDTLS_PK_ECKEY_DH || + type == MBEDTLS_PK_ECDSA ); +} + +static size_t eckey_get_bitlen( const void *ctx ) +{ + return( ((mbedtls_ecp_keypair *) ctx)->grp.pbits ); +} + +#if defined(MBEDTLS_ECDSA_C) +/* Forward declarations */ +static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ); + +static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ); + +static int eckey_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + mbedtls_ecdsa_context ecdsa; + + mbedtls_ecdsa_init( &ecdsa ); + + if( ( ret = mbedtls_ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 ) + ret = ecdsa_verify_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len ); + + mbedtls_ecdsa_free( &ecdsa ); + + return( ret ); +} + +static int eckey_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret; + mbedtls_ecdsa_context ecdsa; + + mbedtls_ecdsa_init( &ecdsa ); + + if( ( ret = mbedtls_ecdsa_from_keypair( &ecdsa, ctx ) ) == 0 ) + ret = ecdsa_sign_wrap( &ecdsa, md_alg, hash, hash_len, sig, sig_len, + f_rng, p_rng ); + + mbedtls_ecdsa_free( &ecdsa ); + + return( ret ); +} + +#endif /* MBEDTLS_ECDSA_C */ + +static int eckey_check_pair( const void *pub, const void *prv ) +{ + return( mbedtls_ecp_check_pub_priv( (const mbedtls_ecp_keypair *) pub, + (const mbedtls_ecp_keypair *) prv ) ); +} + +static void *eckey_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecp_keypair ) ); + + if( ctx != NULL ) + mbedtls_ecp_keypair_init( ctx ); + + return( ctx ); +} + +static void eckey_free_wrap( void *ctx ) +{ + mbedtls_ecp_keypair_free( (mbedtls_ecp_keypair *) ctx ); + mbedtls_free( ctx ); +} + +static void eckey_debug( const void *ctx, mbedtls_pk_debug_item *items ) +{ + items->type = MBEDTLS_PK_DEBUG_ECP; + items->name = "eckey.Q"; + items->value = &( ((mbedtls_ecp_keypair *) ctx)->Q ); +} + +const mbedtls_pk_info_t mbedtls_eckey_info = { + MBEDTLS_PK_ECKEY, + "EC", + eckey_get_bitlen, + eckey_can_do, +#if defined(MBEDTLS_ECDSA_C) + eckey_verify_wrap, + eckey_sign_wrap, +#else + NULL, + NULL, +#endif + NULL, + NULL, + eckey_check_pair, + eckey_alloc_wrap, + eckey_free_wrap, + eckey_debug, +}; + +/* + * EC key restricted to ECDH + */ +static int eckeydh_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECKEY || + type == MBEDTLS_PK_ECKEY_DH ); +} + +const mbedtls_pk_info_t mbedtls_eckeydh_info = { + MBEDTLS_PK_ECKEY_DH, + "EC_DH", + eckey_get_bitlen, /* Same underlying key structure */ + eckeydh_can_do, + NULL, + NULL, + NULL, + NULL, + eckey_check_pair, + eckey_alloc_wrap, /* Same underlying key structure */ + eckey_free_wrap, /* Same underlying key structure */ + eckey_debug, /* Same underlying key structure */ +}; +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_ECDSA_C) +static int ecdsa_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_ECDSA ); +} + +static int ecdsa_verify_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + const unsigned char *sig, size_t sig_len ) +{ + int ret; + ((void) md_alg); + + ret = mbedtls_ecdsa_read_signature( (mbedtls_ecdsa_context *) ctx, + hash, hash_len, sig, sig_len ); + + if( ret == MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH ) + return( MBEDTLS_ERR_PK_SIG_LEN_MISMATCH ); + + return( ret ); +} + +static int ecdsa_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + return( mbedtls_ecdsa_write_signature( (mbedtls_ecdsa_context *) ctx, + md_alg, hash, hash_len, sig, sig_len, f_rng, p_rng ) ); +} + +static void *ecdsa_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_ecdsa_context ) ); + + if( ctx != NULL ) + mbedtls_ecdsa_init( (mbedtls_ecdsa_context *) ctx ); + + return( ctx ); +} + +static void ecdsa_free_wrap( void *ctx ) +{ + mbedtls_ecdsa_free( (mbedtls_ecdsa_context *) ctx ); + mbedtls_free( ctx ); +} + +const mbedtls_pk_info_t mbedtls_ecdsa_info = { + MBEDTLS_PK_ECDSA, + "ECDSA", + eckey_get_bitlen, /* Compatible key structures */ + ecdsa_can_do, + ecdsa_verify_wrap, + ecdsa_sign_wrap, + NULL, + NULL, + eckey_check_pair, /* Compatible key structures */ + ecdsa_alloc_wrap, + ecdsa_free_wrap, + eckey_debug, /* Compatible key structures */ +}; +#endif /* MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) +/* + * Support for alternative RSA-private implementations + */ + +static int rsa_alt_can_do( mbedtls_pk_type_t type ) +{ + return( type == MBEDTLS_PK_RSA ); +} + +static size_t rsa_alt_get_bitlen( const void *ctx ) +{ + const mbedtls_rsa_alt_context *rsa_alt = (const mbedtls_rsa_alt_context *) ctx; + + return( 8 * rsa_alt->key_len_func( rsa_alt->key ) ); +} + +static int rsa_alt_sign_wrap( void *ctx, mbedtls_md_type_t md_alg, + const unsigned char *hash, size_t hash_len, + unsigned char *sig, size_t *sig_len, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_alt_context *rsa_alt = (mbedtls_rsa_alt_context *) ctx; + +#if defined(MBEDTLS_HAVE_INT64) + if( UINT_MAX < hash_len ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); +#endif /* MBEDTLS_HAVE_INT64 */ + + *sig_len = rsa_alt->key_len_func( rsa_alt->key ); + + return( rsa_alt->sign_func( rsa_alt->key, f_rng, p_rng, MBEDTLS_RSA_PRIVATE, + md_alg, (unsigned int) hash_len, hash, sig ) ); +} + +static int rsa_alt_decrypt_wrap( void *ctx, + const unsigned char *input, size_t ilen, + unsigned char *output, size_t *olen, size_t osize, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + mbedtls_rsa_alt_context *rsa_alt = (mbedtls_rsa_alt_context *) ctx; + + ((void) f_rng); + ((void) p_rng); + + if( ilen != rsa_alt->key_len_func( rsa_alt->key ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + return( rsa_alt->decrypt_func( rsa_alt->key, + MBEDTLS_RSA_PRIVATE, olen, input, output, osize ) ); +} + +#if defined(MBEDTLS_RSA_C) +static int rsa_alt_check_pair( const void *pub, const void *prv ) +{ + unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char hash[32]; + size_t sig_len = 0; + int ret; + + if( rsa_alt_get_bitlen( prv ) != rsa_get_bitlen( pub ) ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + memset( hash, 0x2a, sizeof( hash ) ); + + if( ( ret = rsa_alt_sign_wrap( (void *) prv, MBEDTLS_MD_NONE, + hash, sizeof( hash ), + sig, &sig_len, NULL, NULL ) ) != 0 ) + { + return( ret ); + } + + if( rsa_verify_wrap( (void *) pub, MBEDTLS_MD_NONE, + hash, sizeof( hash ), sig, sig_len ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + return( 0 ); +} +#endif /* MBEDTLS_RSA_C */ + +static void *rsa_alt_alloc_wrap( void ) +{ + void *ctx = mbedtls_calloc( 1, sizeof( mbedtls_rsa_alt_context ) ); + + if( ctx != NULL ) + memset( ctx, 0, sizeof( mbedtls_rsa_alt_context ) ); + + return( ctx ); +} + +static void rsa_alt_free_wrap( void *ctx ) +{ + mbedtls_zeroize( ctx, sizeof( mbedtls_rsa_alt_context ) ); + mbedtls_free( ctx ); +} + +const mbedtls_pk_info_t mbedtls_rsa_alt_info = { + MBEDTLS_PK_RSA_ALT, + "RSA-alt", + rsa_alt_get_bitlen, + rsa_alt_can_do, + NULL, + rsa_alt_sign_wrap, + rsa_alt_decrypt_wrap, + NULL, +#if defined(MBEDTLS_RSA_C) + rsa_alt_check_pair, +#else + NULL, +#endif + rsa_alt_alloc_wrap, + rsa_alt_free_wrap, + NULL, +}; + +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ + +#endif /* MBEDTLS_PK_C */ diff --git a/c++/src/connect/mbedtls/pkcs11.c b/c++/src/connect/mbedtls/pkcs11.c new file mode 100644 index 00000000..0ea64252 --- /dev/null +++ b/c++/src/connect/mbedtls/pkcs11.c @@ -0,0 +1,240 @@ +/** + * \file pkcs11.c + * + * \brief Wrapper for PKCS#11 library libpkcs11-helper + * + * \author Adriaan de Jong + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#include "mbedtls/pkcs11.h" + +#if defined(MBEDTLS_PKCS11_C) + +#include "mbedtls/md.h" +#include "mbedtls/oid.h" +#include "mbedtls/x509_crt.h" + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include + +void mbedtls_pkcs11_init( mbedtls_pkcs11_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_pkcs11_context ) ); +} + +int mbedtls_pkcs11_x509_cert_bind( mbedtls_x509_crt *cert, pkcs11h_certificate_t pkcs11_cert ) +{ + int ret = 1; + unsigned char *cert_blob = NULL; + size_t cert_blob_size = 0; + + if( cert == NULL ) + { + ret = 2; + goto cleanup; + } + + if( pkcs11h_certificate_getCertificateBlob( pkcs11_cert, NULL, + &cert_blob_size ) != CKR_OK ) + { + ret = 3; + goto cleanup; + } + + cert_blob = mbedtls_calloc( 1, cert_blob_size ); + if( NULL == cert_blob ) + { + ret = 4; + goto cleanup; + } + + if( pkcs11h_certificate_getCertificateBlob( pkcs11_cert, cert_blob, + &cert_blob_size ) != CKR_OK ) + { + ret = 5; + goto cleanup; + } + + if( 0 != mbedtls_x509_crt_parse( cert, cert_blob, cert_blob_size ) ) + { + ret = 6; + goto cleanup; + } + + ret = 0; + +cleanup: + if( NULL != cert_blob ) + mbedtls_free( cert_blob ); + + return( ret ); +} + + +int mbedtls_pkcs11_priv_key_bind( mbedtls_pkcs11_context *priv_key, + pkcs11h_certificate_t pkcs11_cert ) +{ + int ret = 1; + mbedtls_x509_crt cert; + + mbedtls_x509_crt_init( &cert ); + + if( priv_key == NULL ) + goto cleanup; + + if( 0 != mbedtls_pkcs11_x509_cert_bind( &cert, pkcs11_cert ) ) + goto cleanup; + + priv_key->len = mbedtls_pk_get_len( &cert.pk ); + priv_key->pkcs11h_cert = pkcs11_cert; + + ret = 0; + +cleanup: + mbedtls_x509_crt_free( &cert ); + + return( ret ); +} + +void mbedtls_pkcs11_priv_key_free( mbedtls_pkcs11_context *priv_key ) +{ + if( NULL != priv_key ) + pkcs11h_certificate_freeCertificate( priv_key->pkcs11h_cert ); +} + +int mbedtls_pkcs11_decrypt( mbedtls_pkcs11_context *ctx, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ) +{ + size_t input_len, output_len; + + if( NULL == ctx ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( MBEDTLS_RSA_PRIVATE != mode ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + output_len = input_len = ctx->len; + + if( input_len < 16 || input_len > output_max_len ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* Determine size of output buffer */ + if( pkcs11h_certificate_decryptAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, input, + input_len, NULL, &output_len ) != CKR_OK ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + if( output_len > output_max_len ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + if( pkcs11h_certificate_decryptAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, input, + input_len, output, &output_len ) != CKR_OK ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + *olen = output_len; + return( 0 ); +} + +int mbedtls_pkcs11_sign( mbedtls_pkcs11_context *ctx, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t sig_len = 0, asn_len = 0, oid_size = 0; + unsigned char *p = sig; + const char *oid; + + if( NULL == ctx ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( MBEDTLS_RSA_PRIVATE != mode ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( md_alg != MBEDTLS_MD_NONE ) + { + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + asn_len = 10 + oid_size; + } + + sig_len = ctx->len; + if( hashlen > sig_len || asn_len > sig_len || + hashlen + asn_len > sig_len ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + if( md_alg != MBEDTLS_MD_NONE ) + { + /* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x08 + oid_size + hashlen ); + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x04 + oid_size ); + *p++ = MBEDTLS_ASN1_OID; + *p++ = oid_size & 0xFF; + memcpy( p, oid, oid_size ); + p += oid_size; + *p++ = MBEDTLS_ASN1_NULL; + *p++ = 0x00; + *p++ = MBEDTLS_ASN1_OCTET_STRING; + *p++ = hashlen; + } + + memcpy( p, hash, hashlen ); + + if( pkcs11h_certificate_signAny( ctx->pkcs11h_cert, CKM_RSA_PKCS, sig, + asn_len + hashlen, sig, &sig_len ) != CKR_OK ) + { + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + } + + return( 0 ); +} + +#endif /* defined(MBEDTLS_PKCS11_C) */ diff --git a/c++/src/connect/mbedtls/pkcs12.c b/c++/src/connect/mbedtls/pkcs12.c new file mode 100644 index 00000000..c603a135 --- /dev/null +++ b/c++/src/connect/mbedtls/pkcs12.c @@ -0,0 +1,365 @@ +/* + * PKCS#12 Personal Information Exchange Syntax + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The PKCS #12 Personal Information Exchange Syntax Standard v1.1 + * + * http://www.rsa.com/rsalabs/pkcs/files/h11301-wp-pkcs-12v1-1-personal-information-exchange-syntax.pdf + * ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-12/pkcs-12v1-1.asn + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PKCS12_C) + +#include "mbedtls/pkcs12.h" +#include "mbedtls/asn1.h" +#include "mbedtls/cipher.h" + +#include + +#if defined(MBEDTLS_ARC4_C) +#include "mbedtls/arc4.h" +#endif + +#if defined(MBEDTLS_DES_C) +#include "mbedtls/des.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +static int pkcs12_parse_pbe_params( mbedtls_asn1_buf *params, + mbedtls_asn1_buf *salt, int *iterations ) +{ + int ret; + unsigned char **p = ¶ms->p; + const unsigned char *end = params->p + params->len; + + /* + * pkcs-12PbeParams ::= SEQUENCE { + * salt OCTET STRING, + * iterations INTEGER + * } + * + */ + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + if( ( ret = mbedtls_asn1_get_tag( p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); + + salt->p = *p; + *p += salt->len; + + if( ( ret = mbedtls_asn1_get_int( p, end, iterations ) ) != 0 ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_PKCS12_PBE_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +#define PKCS12_MAX_PWDLEN 128 + +static int pkcs12_pbe_derive_key_iv( mbedtls_asn1_buf *pbe_params, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + unsigned char *key, size_t keylen, + unsigned char *iv, size_t ivlen ) +{ + int ret, iterations = 0; + mbedtls_asn1_buf salt; + size_t i; + unsigned char unipwd[PKCS12_MAX_PWDLEN * 2 + 2]; + + if( pwdlen > PKCS12_MAX_PWDLEN ) + return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA ); + + memset( &salt, 0, sizeof(mbedtls_asn1_buf) ); + memset( &unipwd, 0, sizeof(unipwd) ); + + if( ( ret = pkcs12_parse_pbe_params( pbe_params, &salt, + &iterations ) ) != 0 ) + return( ret ); + + for( i = 0; i < pwdlen; i++ ) + unipwd[i * 2 + 1] = pwd[i]; + + if( ( ret = mbedtls_pkcs12_derivation( key, keylen, unipwd, pwdlen * 2 + 2, + salt.p, salt.len, md_type, + MBEDTLS_PKCS12_DERIVE_KEY, iterations ) ) != 0 ) + { + return( ret ); + } + + if( iv == NULL || ivlen == 0 ) + return( 0 ); + + if( ( ret = mbedtls_pkcs12_derivation( iv, ivlen, unipwd, pwdlen * 2 + 2, + salt.p, salt.len, md_type, + MBEDTLS_PKCS12_DERIVE_IV, iterations ) ) != 0 ) + { + return( ret ); + } + return( 0 ); +} + +#undef PKCS12_MAX_PWDLEN + +int mbedtls_pkcs12_pbe_sha1_rc4_128( mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t len, + unsigned char *output ) +{ +#if !defined(MBEDTLS_ARC4_C) + ((void) pbe_params); + ((void) mode); + ((void) pwd); + ((void) pwdlen); + ((void) data); + ((void) len); + ((void) output); + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); +#else + int ret; + unsigned char key[16]; + mbedtls_arc4_context ctx; + ((void) mode); + + mbedtls_arc4_init( &ctx ); + + if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, MBEDTLS_MD_SHA1, + pwd, pwdlen, + key, 16, NULL, 0 ) ) != 0 ) + { + return( ret ); + } + + mbedtls_arc4_setup( &ctx, key, 16 ); + if( ( ret = mbedtls_arc4_crypt( &ctx, len, data, output ) ) != 0 ) + goto exit; + +exit: + mbedtls_zeroize( key, sizeof( key ) ); + mbedtls_arc4_free( &ctx ); + + return( ret ); +#endif /* MBEDTLS_ARC4_C */ +} + +int mbedtls_pkcs12_pbe( mbedtls_asn1_buf *pbe_params, int mode, + mbedtls_cipher_type_t cipher_type, mbedtls_md_type_t md_type, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t len, + unsigned char *output ) +{ + int ret, keylen = 0; + unsigned char key[32]; + unsigned char iv[16]; + const mbedtls_cipher_info_t *cipher_info; + mbedtls_cipher_context_t cipher_ctx; + size_t olen = 0; + + cipher_info = mbedtls_cipher_info_from_type( cipher_type ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); + + keylen = cipher_info->key_bitlen / 8; + + if( ( ret = pkcs12_pbe_derive_key_iv( pbe_params, md_type, pwd, pwdlen, + key, keylen, + iv, cipher_info->iv_size ) ) != 0 ) + { + return( ret ); + } + + mbedtls_cipher_init( &cipher_ctx ); + + if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_set_iv( &cipher_ctx, iv, cipher_info->iv_size ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_reset( &cipher_ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_update( &cipher_ctx, data, len, + output, &olen ) ) != 0 ) + { + goto exit; + } + + if( ( ret = mbedtls_cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 ) + ret = MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH; + +exit: + mbedtls_zeroize( key, sizeof( key ) ); + mbedtls_zeroize( iv, sizeof( iv ) ); + mbedtls_cipher_free( &cipher_ctx ); + + return( ret ); +} + +static void pkcs12_fill_buffer( unsigned char *data, size_t data_len, + const unsigned char *filler, size_t fill_len ) +{ + unsigned char *p = data; + size_t use_len; + + while( data_len > 0 ) + { + use_len = ( data_len > fill_len ) ? fill_len : data_len; + memcpy( p, filler, use_len ); + p += use_len; + data_len -= use_len; + } +} + +int mbedtls_pkcs12_derivation( unsigned char *data, size_t datalen, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *salt, size_t saltlen, + mbedtls_md_type_t md_type, int id, int iterations ) +{ + int ret; + unsigned int j; + + unsigned char diversifier[128]; + unsigned char salt_block[128], pwd_block[128], hash_block[128]; + unsigned char hash_output[MBEDTLS_MD_MAX_SIZE]; + unsigned char *p; + unsigned char c; + + size_t hlen, use_len, v, i; + + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + // This version only allows max of 64 bytes of password or salt + if( datalen > 128 || pwdlen > 64 || saltlen > 64 ) + return( MBEDTLS_ERR_PKCS12_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( md_type ); + if( md_info == NULL ) + return( MBEDTLS_ERR_PKCS12_FEATURE_UNAVAILABLE ); + + mbedtls_md_init( &md_ctx ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + return( ret ); + hlen = mbedtls_md_get_size( md_info ); + + if( hlen <= 32 ) + v = 64; + else + v = 128; + + memset( diversifier, (unsigned char) id, v ); + + pkcs12_fill_buffer( salt_block, v, salt, saltlen ); + pkcs12_fill_buffer( pwd_block, v, pwd, pwdlen ); + + p = data; + while( datalen > 0 ) + { + // Calculate hash( diversifier || salt_block || pwd_block ) + if( ( ret = mbedtls_md_starts( &md_ctx ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, diversifier, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, salt_block, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_update( &md_ctx, pwd_block, v ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_md_finish( &md_ctx, hash_output ) ) != 0 ) + goto exit; + + // Perform remaining ( iterations - 1 ) recursive hash calculations + for( i = 1; i < (size_t) iterations; i++ ) + { + if( ( ret = mbedtls_md( md_info, hash_output, hlen, hash_output ) ) != 0 ) + goto exit; + } + + use_len = ( datalen > hlen ) ? hlen : datalen; + memcpy( p, hash_output, use_len ); + datalen -= use_len; + p += use_len; + + if( datalen == 0 ) + break; + + // Concatenating copies of hash_output into hash_block (B) + pkcs12_fill_buffer( hash_block, v, hash_output, hlen ); + + // B += 1 + for( i = v; i > 0; i-- ) + if( ++hash_block[i - 1] != 0 ) + break; + + // salt_block += B + c = 0; + for( i = v; i > 0; i-- ) + { + j = salt_block[i - 1] + hash_block[i - 1] + c; + c = (unsigned char) (j >> 8); + salt_block[i - 1] = j & 0xFF; + } + + // pwd_block += B + c = 0; + for( i = v; i > 0; i-- ) + { + j = pwd_block[i - 1] + hash_block[i - 1] + c; + c = (unsigned char) (j >> 8); + pwd_block[i - 1] = j & 0xFF; + } + } + + ret = 0; + +exit: + mbedtls_zeroize( salt_block, sizeof( salt_block ) ); + mbedtls_zeroize( pwd_block, sizeof( pwd_block ) ); + mbedtls_zeroize( hash_block, sizeof( hash_block ) ); + mbedtls_zeroize( hash_output, sizeof( hash_output ) ); + + mbedtls_md_free( &md_ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_PKCS12_C */ diff --git a/c++/src/connect/mbedtls/pkcs5.c b/c++/src/connect/mbedtls/pkcs5.c new file mode 100644 index 00000000..e28d5a84 --- /dev/null +++ b/c++/src/connect/mbedtls/pkcs5.c @@ -0,0 +1,406 @@ +/** + * \file pkcs5.c + * + * \brief PKCS#5 functions + * + * \author Mathias Olsson + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * PKCS#5 includes PBKDF2 and more + * + * http://tools.ietf.org/html/rfc2898 (Specification) + * http://tools.ietf.org/html/rfc6070 (Test vectors) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PKCS5_C) + +#include "mbedtls/pkcs5.h" +#include "mbedtls/asn1.h" +#include "mbedtls/cipher.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +static int pkcs5_parse_pbkdf2_params( const mbedtls_asn1_buf *params, + mbedtls_asn1_buf *salt, int *iterations, + int *keylen, mbedtls_md_type_t *md_type ) +{ + int ret; + mbedtls_asn1_buf prf_alg_oid; + unsigned char *p = params->p; + const unsigned char *end = params->p + params->len; + + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + /* + * PBKDF2-params ::= SEQUENCE { + * salt OCTET STRING, + * iterationCount INTEGER, + * keyLength INTEGER OPTIONAL + * prf AlgorithmIdentifier DEFAULT algid-hmacWithSHA1 + * } + * + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &salt->len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + salt->p = p; + p += salt->len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, iterations ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_int( &p, end, keylen ) ) != 0 ) + { + if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_alg_null( &p, end, &prf_alg_oid ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + if( MBEDTLS_OID_CMP( MBEDTLS_OID_HMAC_SHA1, &prf_alg_oid ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + *md_type = MBEDTLS_MD_SHA1; + + if( p != end ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +int mbedtls_pkcs5_pbes2( const mbedtls_asn1_buf *pbe_params, int mode, + const unsigned char *pwd, size_t pwdlen, + const unsigned char *data, size_t datalen, + unsigned char *output ) +{ + int ret, iterations = 0, keylen = 0; + unsigned char *p, *end; + mbedtls_asn1_buf kdf_alg_oid, enc_scheme_oid, kdf_alg_params, enc_scheme_params; + mbedtls_asn1_buf salt; + mbedtls_md_type_t md_type = MBEDTLS_MD_SHA1; + unsigned char key[32], iv[32]; + size_t olen = 0; + const mbedtls_md_info_t *md_info; + const mbedtls_cipher_info_t *cipher_info; + mbedtls_md_context_t md_ctx; + mbedtls_cipher_type_t cipher_alg; + mbedtls_cipher_context_t cipher_ctx; + + p = pbe_params->p; + end = p + pbe_params->len; + + /* + * PBES2-params ::= SEQUENCE { + * keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, + * encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} + * } + */ + if( pbe_params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &kdf_alg_oid, &kdf_alg_params ) ) != 0 ) + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + + // Only PBKDF2 supported at the moment + // + if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBKDF2, &kdf_alg_oid ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( ( ret = pkcs5_parse_pbkdf2_params( &kdf_alg_params, + &salt, &iterations, &keylen, + &md_type ) ) != 0 ) + { + return( ret ); + } + + md_info = mbedtls_md_info_from_type( md_type ); + if( md_info == NULL ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &enc_scheme_oid, + &enc_scheme_params ) ) != 0 ) + { + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT + ret ); + } + + if( mbedtls_oid_get_cipher_alg( &enc_scheme_oid, &cipher_alg ) != 0 ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + cipher_info = mbedtls_cipher_info_from_type( cipher_alg ); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_PKCS5_FEATURE_UNAVAILABLE ); + + /* + * The value of keylen from pkcs5_parse_pbkdf2_params() is ignored + * since it is optional and we don't know if it was set or not + */ + keylen = cipher_info->key_bitlen / 8; + + if( enc_scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING || + enc_scheme_params.len != cipher_info->iv_size ) + { + return( MBEDTLS_ERR_PKCS5_INVALID_FORMAT ); + } + + mbedtls_md_init( &md_ctx ); + mbedtls_cipher_init( &cipher_ctx ); + + memcpy( iv, enc_scheme_params.p, enc_scheme_params.len ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_pkcs5_pbkdf2_hmac( &md_ctx, pwd, pwdlen, salt.p, salt.len, + iterations, keylen, key ) ) != 0 ) + { + goto exit; + } + + if( ( ret = mbedtls_cipher_setup( &cipher_ctx, cipher_info ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_setkey( &cipher_ctx, key, 8 * keylen, (mbedtls_operation_t) mode ) ) != 0 ) + goto exit; + + if( ( ret = mbedtls_cipher_crypt( &cipher_ctx, iv, enc_scheme_params.len, + data, datalen, output, &olen ) ) != 0 ) + ret = MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH; + +exit: + mbedtls_md_free( &md_ctx ); + mbedtls_cipher_free( &cipher_ctx ); + + return( ret ); +} + +int mbedtls_pkcs5_pbkdf2_hmac( mbedtls_md_context_t *ctx, const unsigned char *password, + size_t plen, const unsigned char *salt, size_t slen, + unsigned int iteration_count, + uint32_t key_length, unsigned char *output ) +{ + int ret, j; + unsigned int i; + unsigned char md1[MBEDTLS_MD_MAX_SIZE]; + unsigned char work[MBEDTLS_MD_MAX_SIZE]; + unsigned char md_size = mbedtls_md_get_size( ctx->md_info ); + size_t use_len; + unsigned char *out_p = output; + unsigned char counter[4]; + + memset( counter, 0, 4 ); + counter[3] = 1; + + if( iteration_count > 0xFFFFFFFF ) + return( MBEDTLS_ERR_PKCS5_BAD_INPUT_DATA ); + + while( key_length ) + { + // U1 ends up in work + // + if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, salt, slen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, counter, 4 ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_finish( ctx, work ) ) != 0 ) + return( ret ); + + memcpy( md1, work, md_size ); + + for( i = 1; i < iteration_count; i++ ) + { + // U2 ends up in md1 + // + if( ( ret = mbedtls_md_hmac_starts( ctx, password, plen ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_update( ctx, md1, md_size ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_md_hmac_finish( ctx, md1 ) ) != 0 ) + return( ret ); + + // U1 xor U2 + // + for( j = 0; j < md_size; j++ ) + work[j] ^= md1[j]; + } + + use_len = ( key_length < md_size ) ? key_length : md_size; + memcpy( out_p, work, use_len ); + + key_length -= (uint32_t) use_len; + out_p += use_len; + + for( i = 4; i > 0; i-- ) + if( ++counter[i - 1] != 0 ) + break; + } + + return( 0 ); +} + +#if defined(MBEDTLS_SELF_TEST) + +#if !defined(MBEDTLS_SHA1_C) +int mbedtls_pkcs5_self_test( int verbose ) +{ + if( verbose != 0 ) + mbedtls_printf( " PBKDF2 (SHA1): skipped\n\n" ); + + return( 0 ); +} +#else + +#define MAX_TESTS 6 + +static const size_t plen[MAX_TESTS] = + { 8, 8, 8, 24, 9 }; + +static const unsigned char password[MAX_TESTS][32] = +{ + "password", + "password", + "password", + "passwordPASSWORDpassword", + "pass\0word", +}; + +static const size_t slen[MAX_TESTS] = + { 4, 4, 4, 36, 5 }; + +static const unsigned char salt[MAX_TESTS][40] = +{ + "salt", + "salt", + "salt", + "saltSALTsaltSALTsaltSALTsaltSALTsalt", + "sa\0lt", +}; + +static const uint32_t it_cnt[MAX_TESTS] = + { 1, 2, 4096, 4096, 4096 }; + +static const uint32_t key_len[MAX_TESTS] = + { 20, 20, 20, 25, 16 }; + +static const unsigned char result_key[MAX_TESTS][32] = +{ + { 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71, + 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06, + 0x2f, 0xe0, 0x37, 0xa6 }, + { 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c, + 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0, + 0xd8, 0xde, 0x89, 0x57 }, + { 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a, + 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0, + 0x65, 0xa4, 0x29, 0xc1 }, + { 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b, + 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a, + 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70, + 0x38 }, + { 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d, + 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3 }, +}; + +int mbedtls_pkcs5_self_test( int verbose ) +{ + mbedtls_md_context_t sha1_ctx; + const mbedtls_md_info_t *info_sha1; + int ret, i; + unsigned char key[64]; + + mbedtls_md_init( &sha1_ctx ); + + info_sha1 = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ); + if( info_sha1 == NULL ) + { + ret = 1; + goto exit; + } + + if( ( ret = mbedtls_md_setup( &sha1_ctx, info_sha1, 1 ) ) != 0 ) + { + ret = 1; + goto exit; + } + + for( i = 0; i < MAX_TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " PBKDF2 (SHA1) #%d: ", i ); + + ret = mbedtls_pkcs5_pbkdf2_hmac( &sha1_ctx, password[i], plen[i], salt[i], + slen[i], it_cnt[i], key_len[i], key ); + if( ret != 0 || + memcmp( result_key[i], key, key_len[i] ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_md_free( &sha1_ctx ); + + return( ret ); +} +#endif /* MBEDTLS_SHA1_C */ + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_PKCS5_C */ diff --git a/c++/src/connect/mbedtls/pkparse.c b/c++/src/connect/mbedtls/pkparse.c new file mode 100644 index 00000000..efdf4374 --- /dev/null +++ b/c++/src/connect/mbedtls/pkparse.c @@ -0,0 +1,1293 @@ +/* + * Public Key layer for parsing key files and structures + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_PARSE_C) + +#include "mbedtls/pk.h" +#include "mbedtls/asn1.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif +#if defined(MBEDTLS_PKCS5_C) +#include "mbedtls/pkcs5.h" +#endif +#if defined(MBEDTLS_PKCS12_C) +#include "mbedtls/pkcs12.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_FS_IO) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Load all data from a file into a given buffer. + * + * The file is expected to contain either PEM or DER encoded data. + * A terminating null byte is always appended. It is included in the announced + * length only if the data looks like it is PEM encoded. + */ +int mbedtls_pk_load_file( const char *path, unsigned char **buf, size_t *n ) +{ + FILE *f; + long size; + + if( ( f = fopen( path, "rb" ) ) == NULL ) + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + + fseek( f, 0, SEEK_END ); + if( ( size = ftell( f ) ) == -1 ) + { + fclose( f ); + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + } + fseek( f, 0, SEEK_SET ); + + *n = (size_t) size; + + if( *n + 1 == 0 || + ( *buf = mbedtls_calloc( 1, *n + 1 ) ) == NULL ) + { + fclose( f ); + return( MBEDTLS_ERR_PK_ALLOC_FAILED ); + } + + if( fread( *buf, 1, *n, f ) != *n ) + { + fclose( f ); + mbedtls_free( *buf ); + return( MBEDTLS_ERR_PK_FILE_IO_ERROR ); + } + + fclose( f ); + + (*buf)[*n] = '\0'; + + if( strstr( (const char *) *buf, "-----BEGIN " ) != NULL ) + ++*n; + + return( 0 ); +} + +/* + * Load and parse a private key + */ +int mbedtls_pk_parse_keyfile( mbedtls_pk_context *ctx, + const char *path, const char *pwd ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + if( pwd == NULL ) + ret = mbedtls_pk_parse_key( ctx, buf, n, NULL, 0 ); + else + ret = mbedtls_pk_parse_key( ctx, buf, n, + (const unsigned char *) pwd, strlen( pwd ) ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} + +/* + * Load and parse a public key + */ +int mbedtls_pk_parse_public_keyfile( mbedtls_pk_context *ctx, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_pk_parse_public_key( ctx, buf, n ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +#if defined(MBEDTLS_ECP_C) +/* Minimally parse an ECParameters buffer to and mbedtls_asn1_buf + * + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } + * -- implicitCurve NULL + * } + */ +static int pk_get_ecparams( unsigned char **p, const unsigned char *end, + mbedtls_asn1_buf *params ) +{ + int ret; + + /* Tag may be either OID or SEQUENCE */ + params->tag = **p; + if( params->tag != MBEDTLS_ASN1_OID +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) + && params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) +#endif + ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } + + if( ( ret = mbedtls_asn1_get_tag( p, end, ¶ms->len, params->tag ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + params->p = *p; + *p += params->len; + + if( *p != end ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) +/* + * Parse a SpecifiedECDomain (SEC 1 C.2) and (mostly) fill the group with it. + * WARNING: the resulting group should only be used with + * pk_group_id_from_specified(), since its base point may not be set correctly + * if it was encoded compressed. + * + * SpecifiedECDomain ::= SEQUENCE { + * version SpecifiedECDomainVersion(ecdpVer1 | ecdpVer2 | ecdpVer3, ...), + * fieldID FieldID {{FieldTypes}}, + * curve Curve, + * base ECPoint, + * order INTEGER, + * cofactor INTEGER OPTIONAL, + * hash HashAlgorithm OPTIONAL, + * ... + * } + * + * We only support prime-field as field type, and ignore hash and cofactor. + */ +static int pk_group_from_specified( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) +{ + int ret; + unsigned char *p = params->p; + const unsigned char * const end = params->p + params->len; + const unsigned char *end_field, *end_curve; + size_t len; + int ver; + + /* SpecifiedECDomainVersion ::= INTEGER { 1, 2, 3 } */ + if( ( ret = mbedtls_asn1_get_int( &p, end, &ver ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ver < 1 || ver > 3 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + + /* + * FieldID { FIELD-ID:IOSet } ::= SEQUENCE { -- Finite field + * fieldType FIELD-ID.&id({IOSet}), + * parameters FIELD-ID.&Type({IOSet}{@fieldType}) + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + end_field = p + len; + + /* + * FIELD-ID ::= TYPE-IDENTIFIER + * FieldTypes FIELD-ID ::= { + * { Prime-p IDENTIFIED BY prime-field } | + * { Characteristic-two IDENTIFIED BY characteristic-two-field } + * } + * prime-field OBJECT IDENTIFIER ::= { id-fieldType 1 } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_field, &len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( ret ); + + if( len != MBEDTLS_OID_SIZE( MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD ) || + memcmp( p, MBEDTLS_OID_ANSI_X9_62_PRIME_FIELD, len ) != 0 ) + { + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + } + + p += len; + + /* Prime-p ::= INTEGER -- Field of size p. */ + if( ( ret = mbedtls_asn1_get_mpi( &p, end_field, &grp->P ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + grp->pbits = mbedtls_mpi_bitlen( &grp->P ); + + if( p != end_field ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * Curve ::= SEQUENCE { + * a FieldElement, + * b FieldElement, + * seed BIT STRING OPTIONAL + * -- Shall be present if used in SpecifiedECDomain + * -- with version equal to ecdpVer2 or ecdpVer3 + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( ret ); + + end_curve = p + len; + + /* + * FieldElement ::= OCTET STRING + * containing an integer in the case of a prime field + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || + ( ret = mbedtls_mpi_read_binary( &grp->A, p, len ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 || + ( ret = mbedtls_mpi_read_binary( &grp->B, p, len ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + /* Ignore seed BIT STRING OPTIONAL */ + if( ( ret = mbedtls_asn1_get_tag( &p, end_curve, &len, MBEDTLS_ASN1_BIT_STRING ) ) == 0 ) + p += len; + + if( p != end_curve ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * ECPoint ::= OCTET STRING + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_ecp_point_read_binary( grp, &grp->G, + ( const unsigned char *) p, len ) ) != 0 ) + { + /* + * If we can't read the point because it's compressed, cheat by + * reading only the X coordinate and the parity bit of Y. + */ + if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE || + ( p[0] != 0x02 && p[0] != 0x03 ) || + len != mbedtls_mpi_size( &grp->P ) + 1 || + mbedtls_mpi_read_binary( &grp->G.X, p + 1, len - 1 ) != 0 || + mbedtls_mpi_lset( &grp->G.Y, p[0] - 2 ) != 0 || + mbedtls_mpi_lset( &grp->G.Z, 1 ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + } + } + + p += len; + + /* + * order INTEGER + */ + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &grp->N ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + grp->nbits = mbedtls_mpi_bitlen( &grp->N ); + + /* + * Allow optional elements by purposefully not enforcing p == end here. + */ + + return( 0 ); +} + +/* + * Find the group id associated with an (almost filled) group as generated by + * pk_group_from_specified(), or return an error if unknown. + */ +static int pk_group_id_from_group( const mbedtls_ecp_group *grp, mbedtls_ecp_group_id *grp_id ) +{ + int ret = 0; + mbedtls_ecp_group ref; + const mbedtls_ecp_group_id *id; + + mbedtls_ecp_group_init( &ref ); + + for( id = mbedtls_ecp_grp_id_list(); *id != MBEDTLS_ECP_DP_NONE; id++ ) + { + /* Load the group associated to that id */ + mbedtls_ecp_group_free( &ref ); + MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &ref, *id ) ); + + /* Compare to the group we were given, starting with easy tests */ + if( grp->pbits == ref.pbits && grp->nbits == ref.nbits && + mbedtls_mpi_cmp_mpi( &grp->P, &ref.P ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->A, &ref.A ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->B, &ref.B ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->N, &ref.N ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->G.X, &ref.G.X ) == 0 && + mbedtls_mpi_cmp_mpi( &grp->G.Z, &ref.G.Z ) == 0 && + /* For Y we may only know the parity bit, so compare only that */ + mbedtls_mpi_get_bit( &grp->G.Y, 0 ) == mbedtls_mpi_get_bit( &ref.G.Y, 0 ) ) + { + break; + } + + } + +cleanup: + mbedtls_ecp_group_free( &ref ); + + *grp_id = *id; + + if( ret == 0 && *id == MBEDTLS_ECP_DP_NONE ) + ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; + + return( ret ); +} + +/* + * Parse a SpecifiedECDomain (SEC 1 C.2) and find the associated group ID + */ +static int pk_group_id_from_specified( const mbedtls_asn1_buf *params, + mbedtls_ecp_group_id *grp_id ) +{ + int ret; + mbedtls_ecp_group grp; + + mbedtls_ecp_group_init( &grp ); + + if( ( ret = pk_group_from_specified( params, &grp ) ) != 0 ) + goto cleanup; + + ret = pk_group_id_from_group( &grp, grp_id ); + +cleanup: + mbedtls_ecp_group_free( &grp ); + + return( ret ); +} +#endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */ + +/* + * Use EC parameters to initialise an EC group + * + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * specifiedCurve SpecifiedECDomain -- = SEQUENCE { ... } + * -- implicitCurve NULL + */ +static int pk_use_ecparams( const mbedtls_asn1_buf *params, mbedtls_ecp_group *grp ) +{ + int ret; + mbedtls_ecp_group_id grp_id; + + if( params->tag == MBEDTLS_ASN1_OID ) + { + if( mbedtls_oid_get_ec_grp( params, &grp_id ) != 0 ) + return( MBEDTLS_ERR_PK_UNKNOWN_NAMED_CURVE ); + } + else + { +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) + if( ( ret = pk_group_id_from_specified( params, &grp_id ) ) != 0 ) + return( ret ); +#else + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); +#endif + } + + /* + * grp may already be initilialized; if so, make sure IDs match + */ + if( grp->id != MBEDTLS_ECP_DP_NONE && grp->id != grp_id ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + + if( ( ret = mbedtls_ecp_group_load( grp, grp_id ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * EC public key is an EC point + * + * The caller is responsible for clearing the structure upon failure if + * desired. Take care to pass along the possible ECP_FEATURE_UNAVAILABLE + * return code of mbedtls_ecp_point_read_binary() and leave p in a usable state. + */ +static int pk_get_ecpubkey( unsigned char **p, const unsigned char *end, + mbedtls_ecp_keypair *key ) +{ + int ret; + + if( ( ret = mbedtls_ecp_point_read_binary( &key->grp, &key->Q, + (const unsigned char *) *p, end - *p ) ) == 0 ) + { + ret = mbedtls_ecp_check_pubkey( &key->grp, &key->Q ); + } + + /* + * We know mbedtls_ecp_point_read_binary consumed all bytes or failed + */ + *p = (unsigned char *) end; + + return( ret ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_RSA_C) +/* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ +static int pk_get_rsapubkey( unsigned char **p, + const unsigned char *end, + mbedtls_rsa_context *rsa ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = mbedtls_asn1_get_mpi( p, end, &rsa->N ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( p, end, &rsa->E ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = mbedtls_rsa_check_pubkey( rsa ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY ); + + rsa->len = mbedtls_mpi_size( &rsa->N ); + + return( 0 ); +} +#endif /* MBEDTLS_RSA_C */ + +/* Get a PK algorithm identifier + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ +static int pk_get_pk_alg( unsigned char **p, + const unsigned char *end, + mbedtls_pk_type_t *pk_alg, mbedtls_asn1_buf *params ) +{ + int ret; + mbedtls_asn1_buf alg_oid; + + memset( params, 0, sizeof(mbedtls_asn1_buf) ); + + if( ( ret = mbedtls_asn1_get_alg( p, end, &alg_oid, params ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_ALG + ret ); + + if( mbedtls_oid_get_pk_alg( &alg_oid, pk_alg ) != 0 ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + /* + * No parameters with RSA (only for EC) + */ + if( *pk_alg == MBEDTLS_PK_RSA && + ( ( params->tag != MBEDTLS_ASN1_NULL && params->tag != 0 ) || + params->len != 0 ) ) + { + return( MBEDTLS_ERR_PK_INVALID_ALG ); + } + + return( 0 ); +} + +/* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ +int mbedtls_pk_parse_subpubkey( unsigned char **p, const unsigned char *end, + mbedtls_pk_context *pk ) +{ + int ret; + size_t len; + mbedtls_asn1_buf alg_params; + mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + const mbedtls_pk_info_t *pk_info; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = *p + len; + + if( ( ret = pk_get_pk_alg( p, end, &pk_alg, &alg_params ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_PK_INVALID_PUBKEY + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA ) + { + ret = pk_get_rsapubkey( p, end, mbedtls_pk_rsa( *pk ) ); + } else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECKEY_DH || pk_alg == MBEDTLS_PK_ECKEY ) + { + ret = pk_use_ecparams( &alg_params, &mbedtls_pk_ec( *pk )->grp ); + if( ret == 0 ) + ret = pk_get_ecpubkey( p, end, mbedtls_pk_ec( *pk ) ); + } else +#endif /* MBEDTLS_ECP_C */ + ret = MBEDTLS_ERR_PK_UNKNOWN_PK_ALG; + + if( ret == 0 && *p != end ) + ret = MBEDTLS_ERR_PK_INVALID_PUBKEY + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH; + + if( ret != 0 ) + mbedtls_pk_free( pk ); + + return( ret ); +} + +#if defined(MBEDTLS_RSA_C) +/* + * Parse a PKCS#1 encoded private RSA key + */ +static int pk_parse_key_pkcs1_der( mbedtls_rsa_context *rsa, + const unsigned char *key, + size_t keylen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + + p = (unsigned char *) key; + end = p + keylen; + + /* + * This function parses the RSAPrivateKey (PKCS#1) + * + * RSAPrivateKey ::= SEQUENCE { + * version Version, + * modulus INTEGER, -- n + * publicExponent INTEGER, -- e + * privateExponent INTEGER, -- d + * prime1 INTEGER, -- p + * prime2 INTEGER, -- q + * exponent1 INTEGER, -- d mod (p-1) + * exponent2 INTEGER, -- d mod (q-1) + * coefficient INTEGER, -- (inverse of q) mod p + * otherPrimeInfos OtherPrimeInfos OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &rsa->ver ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + if( rsa->ver != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); + } + + if( ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->N ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->E ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->D ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->P ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->Q ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DP ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->DQ ) ) != 0 || + ( ret = mbedtls_asn1_get_mpi( &p, end, &rsa->QP ) ) != 0 ) + { + mbedtls_rsa_free( rsa ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + rsa->len = mbedtls_mpi_size( &rsa->N ); + + if( p != end ) + { + mbedtls_rsa_free( rsa ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + if( ( ret = mbedtls_rsa_check_privkey( rsa ) ) != 0 ) + { + mbedtls_rsa_free( rsa ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * Parse a SEC1 encoded private EC key + */ +static int pk_parse_key_sec1_der( mbedtls_ecp_keypair *eck, + const unsigned char *key, + size_t keylen ) +{ + int ret; + int version, pubkey_done; + size_t len; + mbedtls_asn1_buf params; + unsigned char *p = (unsigned char *) key; + unsigned char *end = p + keylen; + unsigned char *end2; + + /* + * RFC 5915, or SEC1 Appendix C.4 + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( version != 1 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_mpi_read_binary( &eck->d, p, len ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + p += len; + + pubkey_done = 0; + if( p != end ) + { + /* + * Is 'parameters' present? + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) + { + if( ( ret = pk_get_ecparams( &p, p + len, ¶ms) ) != 0 || + ( ret = pk_use_ecparams( ¶ms, &eck->grp ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( ret ); + } + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + /* + * Is 'publickey' present? If not, or if we can't read it (eg because it + * is compressed), create it from the private key. + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) + { + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_bitstring_null( &p, end2, &len ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( p + len != end2 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( ( ret = pk_get_ecpubkey( &p, end2, eck ) ) == 0 ) + pubkey_done = 1; + else + { + /* + * The only acceptable failure mode of pk_get_ecpubkey() above + * is if the point format is not recognized. + */ + if( ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); + } + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + } + + if( ! pubkey_done && + ( ret = mbedtls_ecp_mul( &eck->grp, &eck->Q, &eck->d, &eck->grp.G, + NULL, NULL ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 ) + { + mbedtls_ecp_keypair_free( eck ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_ECP_C */ + +/* + * Parse an unencrypted PKCS#8 encoded private key + */ +static int pk_parse_key_pkcs8_unencrypted_der( + mbedtls_pk_context *pk, + const unsigned char* key, + size_t keylen ) +{ + int ret, version; + size_t len; + mbedtls_asn1_buf params; + unsigned char *p = (unsigned char *) key; + unsigned char *end = p + keylen; + mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + const mbedtls_pk_info_t *pk_info; + + /* + * This function parses the PrivatKeyInfo object (PKCS#8 v1.2 = RFC 5208) + * + * PrivateKeyInfo ::= SEQUENCE { + * version Version, + * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, + * privateKey PrivateKey, + * attributes [0] IMPLICIT Attributes OPTIONAL } + * + * Version ::= INTEGER + * PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier + * PrivateKey ::= OCTET STRING + * + * The PrivateKey OCTET STRING is a SEC1 ECPrivateKey + */ + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end, &version ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( version != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_VERSION + ret ); + + if( ( ret = pk_get_pk_alg( &p, end, &pk_alg, ¶ms ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( len < 1 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( ( pk_info = mbedtls_pk_info_from_type( pk_alg ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA ) + { + if( ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), p, len ) ) != 0 ) + { + mbedtls_pk_free( pk ); + return( ret ); + } + } else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECKEY || pk_alg == MBEDTLS_PK_ECKEY_DH ) + { + if( ( ret = pk_use_ecparams( ¶ms, &mbedtls_pk_ec( *pk )->grp ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), p, len ) ) != 0 ) + { + mbedtls_pk_free( pk ); + return( ret ); + } + } else +#endif /* MBEDTLS_ECP_C */ + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + return( 0 ); +} + +/* + * Parse an encrypted PKCS#8 encoded private key + */ +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) +static int pk_parse_key_pkcs8_encrypted_der( + mbedtls_pk_context *pk, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret, decrypted = 0; + size_t len; + unsigned char buf[2048]; + unsigned char *p, *end; + mbedtls_asn1_buf pbe_alg_oid, pbe_params; +#if defined(MBEDTLS_PKCS12_C) + mbedtls_cipher_type_t cipher_alg; + mbedtls_md_type_t md_alg; +#endif + + memset( buf, 0, sizeof( buf ) ); + + p = (unsigned char *) key; + end = p + keylen; + + if( pwdlen == 0 ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + + /* + * This function parses the EncryptedPrivatKeyInfo object (PKCS#8) + * + * EncryptedPrivateKeyInfo ::= SEQUENCE { + * encryptionAlgorithm EncryptionAlgorithmIdentifier, + * encryptedData EncryptedData + * } + * + * EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier + * + * EncryptedData ::= OCTET STRING + * + * The EncryptedData OCTET STRING is a PKCS#8 PrivateKeyInfo + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + } + + end = p + len; + + if( ( ret = mbedtls_asn1_get_alg( &p, end, &pbe_alg_oid, &pbe_params ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT + ret ); + + if( len > sizeof( buf ) ) + return( MBEDTLS_ERR_PK_BAD_INPUT_DATA ); + + /* + * Decrypt EncryptedData with appropriate PDE + */ +#if defined(MBEDTLS_PKCS12_C) + if( mbedtls_oid_get_pkcs12_pbe_alg( &pbe_alg_oid, &md_alg, &cipher_alg ) == 0 ) + { + if( ( ret = mbedtls_pkcs12_pbe( &pbe_params, MBEDTLS_PKCS12_PBE_DECRYPT, + cipher_alg, md_alg, + pwd, pwdlen, p, len, buf ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_PKCS12_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + return( ret ); + } + + decrypted = 1; + } + else if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS12_PBE_SHA1_RC4_128, &pbe_alg_oid ) == 0 ) + { + if( ( ret = mbedtls_pkcs12_pbe_sha1_rc4_128( &pbe_params, + MBEDTLS_PKCS12_PBE_DECRYPT, + pwd, pwdlen, + p, len, buf ) ) != 0 ) + { + return( ret ); + } + + // Best guess for password mismatch when using RC4. If first tag is + // not MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE + // + if( *buf != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + decrypted = 1; + } + else +#endif /* MBEDTLS_PKCS12_C */ +#if defined(MBEDTLS_PKCS5_C) + if( MBEDTLS_OID_CMP( MBEDTLS_OID_PKCS5_PBES2, &pbe_alg_oid ) == 0 ) + { + if( ( ret = mbedtls_pkcs5_pbes2( &pbe_params, MBEDTLS_PKCS5_DECRYPT, pwd, pwdlen, + p, len, buf ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_PKCS5_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + + return( ret ); + } + + decrypted = 1; + } + else +#endif /* MBEDTLS_PKCS5_C */ + { + ((void) pwd); + } + + if( decrypted == 0 ) + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( pk_parse_key_pkcs8_unencrypted_der( pk, buf, len ) ); +} +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ + +/* + * Parse a private key + */ +int mbedtls_pk_parse_key( mbedtls_pk_context *pk, + const unsigned char *key, size_t keylen, + const unsigned char *pwd, size_t pwdlen ) +{ + int ret; + const mbedtls_pk_info_t *pk_info; + +#if defined(MBEDTLS_PEM_PARSE_C) + size_t len; + mbedtls_pem_context pem; + + mbedtls_pem_init( &pem ); + +#if defined(MBEDTLS_RSA_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN RSA PRIVATE KEY-----", + "-----END RSA PRIVATE KEY-----", + key, pwd, pwdlen, &len ); + + if( ret == 0 ) + { + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN EC PRIVATE KEY-----", + "-----END EC PRIVATE KEY-----", + key, pwd, pwdlen, &len ); + if( ret == 0 ) + { + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_MISMATCH ) + return( MBEDTLS_ERR_PK_PASSWORD_MISMATCH ); + else if( ret == MBEDTLS_ERR_PEM_PASSWORD_REQUIRED ) + return( MBEDTLS_ERR_PK_PASSWORD_REQUIRED ); + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_ECP_C */ + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN PRIVATE KEY-----", + "-----END PRIVATE KEY-----", + key, NULL, 0, &len ); + if( ret == 0 ) + { + if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); + +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN ENCRYPTED PRIVATE KEY-----", + "-----END ENCRYPTED PRIVATE KEY-----", + key, NULL, 0, &len ); + if( ret == 0 ) + { + if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, + pem.buf, pem.buflen, + pwd, pwdlen ) ) != 0 ) + { + mbedtls_pk_free( pk ); + } + + mbedtls_pem_free( &pem ); + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + return( ret ); +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ +#else + ((void) ret); + ((void) pwd); + ((void) pwdlen); +#endif /* MBEDTLS_PEM_PARSE_C */ + + /* + * At this point we only know it's not a PEM formatted key. Could be any + * of the known DER encoded private key formats + * + * We try the different DER format parsers to see if one passes without + * error + */ +#if defined(MBEDTLS_PKCS12_C) || defined(MBEDTLS_PKCS5_C) + if( ( ret = pk_parse_key_pkcs8_encrypted_der( pk, key, keylen, + pwd, pwdlen ) ) == 0 ) + { + return( 0 ); + } + + mbedtls_pk_free( pk ); + + if( ret == MBEDTLS_ERR_PK_PASSWORD_MISMATCH ) + { + return( ret ); + } +#endif /* MBEDTLS_PKCS12_C || MBEDTLS_PKCS5_C */ + + if( ( ret = pk_parse_key_pkcs8_unencrypted_der( pk, key, keylen ) ) == 0 ) + return( 0 ); + + mbedtls_pk_free( pk ); + +#if defined(MBEDTLS_RSA_C) + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_RSA ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_pkcs1_der( mbedtls_pk_rsa( *pk ), key, keylen ) ) == 0 ) + { + return( 0 ); + } + + mbedtls_pk_free( pk ); +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) + if( ( pk_info = mbedtls_pk_info_from_type( MBEDTLS_PK_ECKEY ) ) == NULL ) + return( MBEDTLS_ERR_PK_UNKNOWN_PK_ALG ); + + if( ( ret = mbedtls_pk_setup( pk, pk_info ) ) != 0 || + ( ret = pk_parse_key_sec1_der( mbedtls_pk_ec( *pk ), key, keylen ) ) == 0 ) + { + return( 0 ); + } + + mbedtls_pk_free( pk ); +#endif /* MBEDTLS_ECP_C */ + + return( MBEDTLS_ERR_PK_KEY_INVALID_FORMAT ); +} + +/* + * Parse a public key + */ +int mbedtls_pk_parse_public_key( mbedtls_pk_context *ctx, + const unsigned char *key, size_t keylen ) +{ + int ret; + unsigned char *p; +#if defined(MBEDTLS_PEM_PARSE_C) + size_t len; + mbedtls_pem_context pem; + + mbedtls_pem_init( &pem ); + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( keylen == 0 || key[keylen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN PUBLIC KEY-----", + "-----END PUBLIC KEY-----", + key, NULL, 0, &len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + key = pem.buf; + keylen = pem.buflen; + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } +#endif /* MBEDTLS_PEM_PARSE_C */ + p = (unsigned char *) key; + + ret = mbedtls_pk_parse_subpubkey( &p, p + keylen, ctx ); + +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_free( &pem ); +#endif + + return( ret ); +} + +#endif /* MBEDTLS_PK_PARSE_C */ diff --git a/c++/src/connect/mbedtls/pkwrite.c b/c++/src/connect/mbedtls/pkwrite.c new file mode 100644 index 00000000..83b798c1 --- /dev/null +++ b/c++/src/connect/mbedtls/pkwrite.c @@ -0,0 +1,439 @@ +/* + * Public Key layer for writing key files and structures + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PK_WRITE_C) + +#include "mbedtls/pk.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_RSA_C) +#include "mbedtls/rsa.h" +#endif +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif +#if defined(MBEDTLS_ECDSA_C) +#include "mbedtls/ecdsa.h" +#endif +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#if defined(MBEDTLS_RSA_C) +/* + * RSAPublicKey ::= SEQUENCE { + * modulus INTEGER, -- n + * publicExponent INTEGER -- e + * } + */ +static int pk_write_rsa_pubkey( unsigned char **p, unsigned char *start, + mbedtls_rsa_context *rsa ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( p, start, &rsa->E ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( p, start, &rsa->N ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * EC public key is an EC point + */ +static int pk_write_ec_pubkey( unsigned char **p, unsigned char *start, + mbedtls_ecp_keypair *ec ) +{ + int ret; + size_t len = 0; + unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN]; + + if( ( ret = mbedtls_ecp_point_write_binary( &ec->grp, &ec->Q, + MBEDTLS_ECP_PF_UNCOMPRESSED, + &len, buf, sizeof( buf ) ) ) != 0 ) + { + return( ret ); + } + + if( *p < start || (size_t)( *p - start ) < len ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *p -= len; + memcpy( *p, buf, len ); + + return( (int) len ); +} + +/* + * ECParameters ::= CHOICE { + * namedCurve OBJECT IDENTIFIER + * } + */ +static int pk_write_ec_param( unsigned char **p, unsigned char *start, + mbedtls_ecp_keypair *ec ) +{ + int ret; + size_t len = 0; + const char *oid; + size_t oid_len; + + if( ( ret = mbedtls_oid_get_oid_by_ec_grp( ec->grp.id, &oid, &oid_len ) ) != 0 ) + return( ret ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); + + return( (int) len ); +} +#endif /* MBEDTLS_ECP_C */ + +int mbedtls_pk_write_pubkey( unsigned char **p, unsigned char *start, + const mbedtls_pk_context *key ) +{ + int ret; + size_t len = 0; + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + MBEDTLS_ASN1_CHK_ADD( len, pk_write_rsa_pubkey( p, start, mbedtls_pk_rsa( *key ) ) ); + else +#endif +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + MBEDTLS_ASN1_CHK_ADD( len, pk_write_ec_pubkey( p, start, mbedtls_pk_ec( *key ) ) ); + else +#endif + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( (int) len ); +} + +int mbedtls_pk_write_pubkey_der( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char *c; + size_t len = 0, par_len = 0, oid_len; + const char *oid; + + c = buf + size; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, key ) ); + + if( c - buf < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + /* + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + */ + *--c = 0; + len += 1; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) ); + + if( ( ret = mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_get_type( key ), + &oid, &oid_len ) ) != 0 ) + { + return( ret ); + } + +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, mbedtls_pk_ec( *key ) ) ); + } +#endif + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, buf, oid, oid_len, + par_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +int mbedtls_pk_write_key_der( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char *c = buf + size; + size_t len = 0; + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + { + mbedtls_rsa_context *rsa = mbedtls_pk_rsa( *key ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->QP ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->DQ ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->DP ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->Q ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->P ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->D ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->E ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &rsa->N ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 0 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + } + else +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + mbedtls_ecp_keypair *ec = mbedtls_pk_ec( *key ); + size_t pub_len = 0, par_len = 0; + + /* + * RFC 5915, or SEC1 Appendix C.4 + * + * ECPrivateKey ::= SEQUENCE { + * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1), + * privateKey OCTET STRING, + * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL, + * publicKey [1] BIT STRING OPTIONAL + * } + */ + + /* publicKey */ + MBEDTLS_ASN1_CHK_ADD( pub_len, pk_write_ec_pubkey( &c, buf, ec ) ); + + if( c - buf < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + *--c = 0; + pub_len += 1; + + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) ); + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) ); + + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_len( &c, buf, pub_len ) ); + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_asn1_write_tag( &c, buf, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ); + len += pub_len; + + /* parameters */ + MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, ec ) ); + + MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_len( &c, buf, par_len ) ); + MBEDTLS_ASN1_CHK_ADD( par_len, mbedtls_asn1_write_tag( &c, buf, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ); + len += par_len; + + /* privateKey: write as MPI then fix tag */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, buf, &ec->d ) ); + *c = MBEDTLS_ASN1_OCTET_STRING; + + /* version */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, 1 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + } + else +#endif /* MBEDTLS_ECP_C */ + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + return( (int) len ); +} + +#if defined(MBEDTLS_PEM_WRITE_C) + +#define PEM_BEGIN_PUBLIC_KEY "-----BEGIN PUBLIC KEY-----\n" +#define PEM_END_PUBLIC_KEY "-----END PUBLIC KEY-----\n" + +#define PEM_BEGIN_PRIVATE_KEY_RSA "-----BEGIN RSA PRIVATE KEY-----\n" +#define PEM_END_PRIVATE_KEY_RSA "-----END RSA PRIVATE KEY-----\n" +#define PEM_BEGIN_PRIVATE_KEY_EC "-----BEGIN EC PRIVATE KEY-----\n" +#define PEM_END_PRIVATE_KEY_EC "-----END EC PRIVATE KEY-----\n" + +/* + * Max sizes of key per types. Shown as tag + len (+ content). + */ + +#if defined(MBEDTLS_RSA_C) +/* + * RSA public keys: + * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 3 + * algorithm AlgorithmIdentifier, 1 + 1 (sequence) + * + 1 + 1 + 9 (rsa oid) + * + 1 + 1 (params null) + * subjectPublicKey BIT STRING } 1 + 3 + (1 + below) + * RSAPublicKey ::= SEQUENCE { 1 + 3 + * modulus INTEGER, -- n 1 + 3 + MPI_MAX + 1 + * publicExponent INTEGER -- e 1 + 3 + MPI_MAX + 1 + * } + */ +#define RSA_PUB_DER_MAX_BYTES 38 + 2 * MBEDTLS_MPI_MAX_SIZE + +/* + * RSA private keys: + * RSAPrivateKey ::= SEQUENCE { 1 + 3 + * version Version, 1 + 1 + 1 + * modulus INTEGER, 1 + 3 + MPI_MAX + 1 + * publicExponent INTEGER, 1 + 3 + MPI_MAX + 1 + * privateExponent INTEGER, 1 + 3 + MPI_MAX + 1 + * prime1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * prime2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * exponent1 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * exponent2 INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * coefficient INTEGER, 1 + 3 + MPI_MAX / 2 + 1 + * otherPrimeInfos OtherPrimeInfos OPTIONAL 0 (not supported) + * } + */ +#define MPI_MAX_SIZE_2 MBEDTLS_MPI_MAX_SIZE / 2 + \ + MBEDTLS_MPI_MAX_SIZE % 2 +#define RSA_PRV_DER_MAX_BYTES 47 + 3 * MBEDTLS_MPI_MAX_SIZE \ + + 5 * MPI_MAX_SIZE_2 + +#else /* MBEDTLS_RSA_C */ + +#define RSA_PUB_DER_MAX_BYTES 0 +#define RSA_PRV_DER_MAX_BYTES 0 + +#endif /* MBEDTLS_RSA_C */ + +#if defined(MBEDTLS_ECP_C) +/* + * EC public keys: + * SubjectPublicKeyInfo ::= SEQUENCE { 1 + 2 + * algorithm AlgorithmIdentifier, 1 + 1 (sequence) + * + 1 + 1 + 7 (ec oid) + * + 1 + 1 + 9 (namedCurve oid) + * subjectPublicKey BIT STRING 1 + 2 + 1 [1] + * + 1 (point format) [1] + * + 2 * ECP_MAX (coords) [1] + * } + */ +#define ECP_PUB_DER_MAX_BYTES 30 + 2 * MBEDTLS_ECP_MAX_BYTES + +/* + * EC private keys: + * ECPrivateKey ::= SEQUENCE { 1 + 2 + * version INTEGER , 1 + 1 + 1 + * privateKey OCTET STRING, 1 + 1 + ECP_MAX + * parameters [0] ECParameters OPTIONAL, 1 + 1 + (1 + 1 + 9) + * publicKey [1] BIT STRING OPTIONAL 1 + 2 + [1] above + * } + */ +#define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDTLS_ECP_MAX_BYTES + +#else /* MBEDTLS_ECP_C */ + +#define ECP_PUB_DER_MAX_BYTES 0 +#define ECP_PRV_DER_MAX_BYTES 0 + +#endif /* MBEDTLS_ECP_C */ + +#define PUB_DER_MAX_BYTES RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \ + RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES +#define PRV_DER_MAX_BYTES RSA_PRV_DER_MAX_BYTES > ECP_PRV_DER_MAX_BYTES ? \ + RSA_PRV_DER_MAX_BYTES : ECP_PRV_DER_MAX_BYTES + +int mbedtls_pk_write_pubkey_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char output_buf[PUB_DER_MAX_BYTES]; + size_t olen = 0; + + if( ( ret = mbedtls_pk_write_pubkey_der( key, output_buf, + sizeof(output_buf) ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_PUBLIC_KEY, PEM_END_PUBLIC_KEY, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +int mbedtls_pk_write_key_pem( mbedtls_pk_context *key, unsigned char *buf, size_t size ) +{ + int ret; + unsigned char output_buf[PRV_DER_MAX_BYTES]; + const char *begin, *end; + size_t olen = 0; + + if( ( ret = mbedtls_pk_write_key_der( key, output_buf, sizeof(output_buf) ) ) < 0 ) + return( ret ); + +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_RSA ) + { + begin = PEM_BEGIN_PRIVATE_KEY_RSA; + end = PEM_END_PRIVATE_KEY_RSA; + } + else +#endif +#if defined(MBEDTLS_ECP_C) + if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY ) + { + begin = PEM_BEGIN_PRIVATE_KEY_EC; + end = PEM_END_PRIVATE_KEY_EC; + } + else +#endif + return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE ); + + if( ( ret = mbedtls_pem_write_buffer( begin, end, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ + +#endif /* MBEDTLS_PK_WRITE_C */ diff --git a/c++/src/connect/mbedtls/platform.c b/c++/src/connect/mbedtls/platform.c new file mode 100644 index 00000000..8b336c38 --- /dev/null +++ b/c++/src/connect/mbedtls/platform.c @@ -0,0 +1,307 @@ +/* + * Platform abstraction layer + * + * Copyright (C) 2006-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_PLATFORM_C) + +#include "mbedtls/platform.h" + +#if defined(MBEDTLS_PLATFORM_MEMORY) +#if !defined(MBEDTLS_PLATFORM_STD_CALLOC) +static void *platform_calloc_uninit( size_t n, size_t size ) +{ + ((void) n); + ((void) size); + return( NULL ); +} + +#define MBEDTLS_PLATFORM_STD_CALLOC platform_calloc_uninit +#endif /* !MBEDTLS_PLATFORM_STD_CALLOC */ + +#if !defined(MBEDTLS_PLATFORM_STD_FREE) +static void platform_free_uninit( void *ptr ) +{ + ((void) ptr); +} + +#define MBEDTLS_PLATFORM_STD_FREE platform_free_uninit +#endif /* !MBEDTLS_PLATFORM_STD_FREE */ + +void * (*mbedtls_calloc)( size_t, size_t ) = MBEDTLS_PLATFORM_STD_CALLOC; +void (*mbedtls_free)( void * ) = MBEDTLS_PLATFORM_STD_FREE; + +int mbedtls_platform_set_calloc_free( void * (*calloc_func)( size_t, size_t ), + void (*free_func)( void * ) ) +{ + mbedtls_calloc = calloc_func; + mbedtls_free = free_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_MEMORY */ + +#if defined(_WIN32) +#include +int mbedtls_platform_win32_snprintf( char *s, size_t n, const char *fmt, ... ) +{ + int ret; + va_list argp; + + /* Avoid calling the invalid parameter handler by checking ourselves */ + if( s == NULL || n == 0 || fmt == NULL ) + return( -1 ); + + va_start( argp, fmt ); +#if defined(_TRUNCATE) + ret = _vsnprintf_s( s, n, _TRUNCATE, fmt, argp ); +#else + ret = _vsnprintf( s, n, fmt, argp ); + if( ret < 0 || (size_t) ret == n ) + { + s[n-1] = '\0'; + ret = -1; + } +#endif + va_end( argp ); + + return( ret ); +} +#endif + +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_SNPRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_snprintf_uninit( char * s, size_t n, + const char * format, ... ) +{ + ((void) s); + ((void) n); + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_SNPRINTF platform_snprintf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_SNPRINTF */ + +int (*mbedtls_snprintf)( char * s, size_t n, + const char * format, + ... ) = MBEDTLS_PLATFORM_STD_SNPRINTF; + +int mbedtls_platform_set_snprintf( int (*snprintf_func)( char * s, size_t n, + const char * format, + ... ) ) +{ + mbedtls_snprintf = snprintf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_PRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_printf_uninit( const char *format, ... ) +{ + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_PRINTF platform_printf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_PRINTF */ + +int (*mbedtls_printf)( const char *, ... ) = MBEDTLS_PLATFORM_STD_PRINTF; + +int mbedtls_platform_set_printf( int (*printf_func)( const char *, ... ) ) +{ + mbedtls_printf = printf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_FPRINTF) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_fprintf_uninit( FILE *stream, const char *format, ... ) +{ + ((void) stream); + ((void) format); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_FPRINTF platform_fprintf_uninit +#endif /* !MBEDTLS_PLATFORM_STD_FPRINTF */ + +int (*mbedtls_fprintf)( FILE *, const char *, ... ) = + MBEDTLS_PLATFORM_STD_FPRINTF; + +int mbedtls_platform_set_fprintf( int (*fprintf_func)( FILE *, const char *, ... ) ) +{ + mbedtls_fprintf = fprintf_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ + +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_EXIT) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static void platform_exit_uninit( int status ) +{ + ((void) status); +} + +#define MBEDTLS_PLATFORM_STD_EXIT platform_exit_uninit +#endif /* !MBEDTLS_PLATFORM_STD_EXIT */ + +void (*mbedtls_exit)( int status ) = MBEDTLS_PLATFORM_STD_EXIT; + +int mbedtls_platform_set_exit( void (*exit_func)( int status ) ) +{ + mbedtls_exit = exit_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ + +#if defined(MBEDTLS_HAVE_TIME) + +#if defined(MBEDTLS_PLATFORM_TIME_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_TIME) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static mbedtls_time_t platform_time_uninit( mbedtls_time_t* timer ) +{ + ((void) timer); + return( 0 ); +} + +#define MBEDTLS_PLATFORM_STD_TIME platform_time_uninit +#endif /* !MBEDTLS_PLATFORM_STD_TIME */ + +mbedtls_time_t (*mbedtls_time)( mbedtls_time_t* timer ) = MBEDTLS_PLATFORM_STD_TIME; + +int mbedtls_platform_set_time( mbedtls_time_t (*time_func)( mbedtls_time_t* timer ) ) +{ + mbedtls_time = time_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_TIME_ALT */ + +#endif /* MBEDTLS_HAVE_TIME */ + +#if defined(MBEDTLS_ENTROPY_NV_SEED) +#if !defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) && defined(MBEDTLS_FS_IO) +/* Default implementations for the platform independent seed functions use + * standard libc file functions to read from and write to a pre-defined filename + */ +int mbedtls_platform_std_nv_seed_read( unsigned char *buf, size_t buf_len ) +{ + FILE *file; + size_t n; + + if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "rb" ) ) == NULL ) + return -1; + + if( ( n = fread( buf, 1, buf_len, file ) ) != buf_len ) + { + fclose( file ); + return -1; + } + + fclose( file ); + return( (int)n ); +} + +int mbedtls_platform_std_nv_seed_write( unsigned char *buf, size_t buf_len ) +{ + FILE *file; + size_t n; + + if( ( file = fopen( MBEDTLS_PLATFORM_STD_NV_SEED_FILE, "w" ) ) == NULL ) + return -1; + + if( ( n = fwrite( buf, 1, buf_len, file ) ) != buf_len ) + { + fclose( file ); + return -1; + } + + fclose( file ); + return( (int)n ); +} +#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ + +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_READ) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_nv_seed_read_uninit( unsigned char *buf, size_t buf_len ) +{ + ((void) buf); + ((void) buf_len); + return( -1 ); +} + +#define MBEDTLS_PLATFORM_STD_NV_SEED_READ platform_nv_seed_read_uninit +#endif /* !MBEDTLS_PLATFORM_STD_NV_SEED_READ */ + +#if !defined(MBEDTLS_PLATFORM_STD_NV_SEED_WRITE) +/* + * Make dummy function to prevent NULL pointer dereferences + */ +static int platform_nv_seed_write_uninit( unsigned char *buf, size_t buf_len ) +{ + ((void) buf); + ((void) buf_len); + return( -1 ); +} + +#define MBEDTLS_PLATFORM_STD_NV_SEED_WRITE platform_nv_seed_write_uninit +#endif /* !MBEDTLS_PLATFORM_STD_NV_SEED_WRITE */ + +int (*mbedtls_nv_seed_read)( unsigned char *buf, size_t buf_len ) = + MBEDTLS_PLATFORM_STD_NV_SEED_READ; +int (*mbedtls_nv_seed_write)( unsigned char *buf, size_t buf_len ) = + MBEDTLS_PLATFORM_STD_NV_SEED_WRITE; + +int mbedtls_platform_set_nv_seed( + int (*nv_seed_read_func)( unsigned char *buf, size_t buf_len ), + int (*nv_seed_write_func)( unsigned char *buf, size_t buf_len ) ) +{ + mbedtls_nv_seed_read = nv_seed_read_func; + mbedtls_nv_seed_write = nv_seed_write_func; + return( 0 ); +} +#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */ +#endif /* MBEDTLS_ENTROPY_NV_SEED */ + +#endif /* MBEDTLS_PLATFORM_C */ diff --git a/c++/src/connect/mbedtls/ripemd160.c b/c++/src/connect/mbedtls/ripemd160.c new file mode 100644 index 00000000..cdb0a63c --- /dev/null +++ b/c++/src/connect/mbedtls/ripemd160.c @@ -0,0 +1,467 @@ +/* + * RIPE MD-160 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +/* + * The RIPEMD-160 algorithm was designed by RIPE in 1996 + * http://homes.esat.kuleuven.be/~bosselae/mbedtls_ripemd160.html + * http://ehash.iaik.tugraz.at/wiki/RIPEMD-160 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_RIPEMD160_C) + +#include "mbedtls/ripemd160.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +/* + * 32-bit integer manipulation macros (little endian) + */ +#ifndef GET_UINT32_LE +#define GET_UINT32_LE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] ) \ + | ( (uint32_t) (b)[(i) + 1] << 8 ) \ + | ( (uint32_t) (b)[(i) + 2] << 16 ) \ + | ( (uint32_t) (b)[(i) + 3] << 24 ); \ +} +#endif + +#ifndef PUT_UINT32_LE +#define PUT_UINT32_LE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( ( (n) ) & 0xFF ); \ + (b)[(i) + 1] = (unsigned char) ( ( (n) >> 8 ) & 0xFF ); \ + (b)[(i) + 2] = (unsigned char) ( ( (n) >> 16 ) & 0xFF ); \ + (b)[(i) + 3] = (unsigned char) ( ( (n) >> 24 ) & 0xFF ); \ +} +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void mbedtls_ripemd160_init( mbedtls_ripemd160_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ripemd160_context ) ); +} + +void mbedtls_ripemd160_free( mbedtls_ripemd160_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_ripemd160_context ) ); +} + +void mbedtls_ripemd160_clone( mbedtls_ripemd160_context *dst, + const mbedtls_ripemd160_context *src ) +{ + *dst = *src; +} + +/* + * RIPEMD-160 context setup + */ +void mbedtls_ripemd160_starts( mbedtls_ripemd160_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +#if !defined(MBEDTLS_RIPEMD160_PROCESS_ALT) +/* + * Process one block + */ +void mbedtls_ripemd160_process( mbedtls_ripemd160_context *ctx, const unsigned char data[64] ) +{ + uint32_t A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, X[16]; + + GET_UINT32_LE( X[ 0], data, 0 ); + GET_UINT32_LE( X[ 1], data, 4 ); + GET_UINT32_LE( X[ 2], data, 8 ); + GET_UINT32_LE( X[ 3], data, 12 ); + GET_UINT32_LE( X[ 4], data, 16 ); + GET_UINT32_LE( X[ 5], data, 20 ); + GET_UINT32_LE( X[ 6], data, 24 ); + GET_UINT32_LE( X[ 7], data, 28 ); + GET_UINT32_LE( X[ 8], data, 32 ); + GET_UINT32_LE( X[ 9], data, 36 ); + GET_UINT32_LE( X[10], data, 40 ); + GET_UINT32_LE( X[11], data, 44 ); + GET_UINT32_LE( X[12], data, 48 ); + GET_UINT32_LE( X[13], data, 52 ); + GET_UINT32_LE( X[14], data, 56 ); + GET_UINT32_LE( X[15], data, 60 ); + + A = Ap = ctx->state[0]; + B = Bp = ctx->state[1]; + C = Cp = ctx->state[2]; + D = Dp = ctx->state[3]; + E = Ep = ctx->state[4]; + +#define F1( x, y, z ) ( x ^ y ^ z ) +#define F2( x, y, z ) ( ( x & y ) | ( ~x & z ) ) +#define F3( x, y, z ) ( ( x | ~y ) ^ z ) +#define F4( x, y, z ) ( ( x & z ) | ( y & ~z ) ) +#define F5( x, y, z ) ( x ^ ( y | ~z ) ) + +#define S( x, n ) ( ( x << n ) | ( x >> (32 - n) ) ) + +#define P( a, b, c, d, e, r, s, f, k ) \ + a += f( b, c, d ) + X[r] + k; \ + a = S( a, s ) + e; \ + c = S( c, 10 ); + +#define P2( a, b, c, d, e, r, s, rp, sp ) \ + P( a, b, c, d, e, r, s, F, K ); \ + P( a ## p, b ## p, c ## p, d ## p, e ## p, rp, sp, Fp, Kp ); + +#define F F1 +#define K 0x00000000 +#define Fp F5 +#define Kp 0x50A28BE6 + P2( A, B, C, D, E, 0, 11, 5, 8 ); + P2( E, A, B, C, D, 1, 14, 14, 9 ); + P2( D, E, A, B, C, 2, 15, 7, 9 ); + P2( C, D, E, A, B, 3, 12, 0, 11 ); + P2( B, C, D, E, A, 4, 5, 9, 13 ); + P2( A, B, C, D, E, 5, 8, 2, 15 ); + P2( E, A, B, C, D, 6, 7, 11, 15 ); + P2( D, E, A, B, C, 7, 9, 4, 5 ); + P2( C, D, E, A, B, 8, 11, 13, 7 ); + P2( B, C, D, E, A, 9, 13, 6, 7 ); + P2( A, B, C, D, E, 10, 14, 15, 8 ); + P2( E, A, B, C, D, 11, 15, 8, 11 ); + P2( D, E, A, B, C, 12, 6, 1, 14 ); + P2( C, D, E, A, B, 13, 7, 10, 14 ); + P2( B, C, D, E, A, 14, 9, 3, 12 ); + P2( A, B, C, D, E, 15, 8, 12, 6 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F2 +#define K 0x5A827999 +#define Fp F4 +#define Kp 0x5C4DD124 + P2( E, A, B, C, D, 7, 7, 6, 9 ); + P2( D, E, A, B, C, 4, 6, 11, 13 ); + P2( C, D, E, A, B, 13, 8, 3, 15 ); + P2( B, C, D, E, A, 1, 13, 7, 7 ); + P2( A, B, C, D, E, 10, 11, 0, 12 ); + P2( E, A, B, C, D, 6, 9, 13, 8 ); + P2( D, E, A, B, C, 15, 7, 5, 9 ); + P2( C, D, E, A, B, 3, 15, 10, 11 ); + P2( B, C, D, E, A, 12, 7, 14, 7 ); + P2( A, B, C, D, E, 0, 12, 15, 7 ); + P2( E, A, B, C, D, 9, 15, 8, 12 ); + P2( D, E, A, B, C, 5, 9, 12, 7 ); + P2( C, D, E, A, B, 2, 11, 4, 6 ); + P2( B, C, D, E, A, 14, 7, 9, 15 ); + P2( A, B, C, D, E, 11, 13, 1, 13 ); + P2( E, A, B, C, D, 8, 12, 2, 11 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F3 +#define K 0x6ED9EBA1 +#define Fp F3 +#define Kp 0x6D703EF3 + P2( D, E, A, B, C, 3, 11, 15, 9 ); + P2( C, D, E, A, B, 10, 13, 5, 7 ); + P2( B, C, D, E, A, 14, 6, 1, 15 ); + P2( A, B, C, D, E, 4, 7, 3, 11 ); + P2( E, A, B, C, D, 9, 14, 7, 8 ); + P2( D, E, A, B, C, 15, 9, 14, 6 ); + P2( C, D, E, A, B, 8, 13, 6, 6 ); + P2( B, C, D, E, A, 1, 15, 9, 14 ); + P2( A, B, C, D, E, 2, 14, 11, 12 ); + P2( E, A, B, C, D, 7, 8, 8, 13 ); + P2( D, E, A, B, C, 0, 13, 12, 5 ); + P2( C, D, E, A, B, 6, 6, 2, 14 ); + P2( B, C, D, E, A, 13, 5, 10, 13 ); + P2( A, B, C, D, E, 11, 12, 0, 13 ); + P2( E, A, B, C, D, 5, 7, 4, 7 ); + P2( D, E, A, B, C, 12, 5, 13, 5 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F4 +#define K 0x8F1BBCDC +#define Fp F2 +#define Kp 0x7A6D76E9 + P2( C, D, E, A, B, 1, 11, 8, 15 ); + P2( B, C, D, E, A, 9, 12, 6, 5 ); + P2( A, B, C, D, E, 11, 14, 4, 8 ); + P2( E, A, B, C, D, 10, 15, 1, 11 ); + P2( D, E, A, B, C, 0, 14, 3, 14 ); + P2( C, D, E, A, B, 8, 15, 11, 14 ); + P2( B, C, D, E, A, 12, 9, 15, 6 ); + P2( A, B, C, D, E, 4, 8, 0, 14 ); + P2( E, A, B, C, D, 13, 9, 5, 6 ); + P2( D, E, A, B, C, 3, 14, 12, 9 ); + P2( C, D, E, A, B, 7, 5, 2, 12 ); + P2( B, C, D, E, A, 15, 6, 13, 9 ); + P2( A, B, C, D, E, 14, 8, 9, 12 ); + P2( E, A, B, C, D, 5, 6, 7, 5 ); + P2( D, E, A, B, C, 6, 5, 10, 15 ); + P2( C, D, E, A, B, 2, 12, 14, 8 ); +#undef F +#undef K +#undef Fp +#undef Kp + +#define F F5 +#define K 0xA953FD4E +#define Fp F1 +#define Kp 0x00000000 + P2( B, C, D, E, A, 4, 9, 12, 8 ); + P2( A, B, C, D, E, 0, 15, 15, 5 ); + P2( E, A, B, C, D, 5, 5, 10, 12 ); + P2( D, E, A, B, C, 9, 11, 4, 9 ); + P2( C, D, E, A, B, 7, 6, 1, 12 ); + P2( B, C, D, E, A, 12, 8, 5, 5 ); + P2( A, B, C, D, E, 2, 13, 8, 14 ); + P2( E, A, B, C, D, 10, 12, 7, 6 ); + P2( D, E, A, B, C, 14, 5, 6, 8 ); + P2( C, D, E, A, B, 1, 12, 2, 13 ); + P2( B, C, D, E, A, 3, 13, 13, 6 ); + P2( A, B, C, D, E, 8, 14, 14, 5 ); + P2( E, A, B, C, D, 11, 11, 0, 15 ); + P2( D, E, A, B, C, 6, 8, 3, 13 ); + P2( C, D, E, A, B, 15, 5, 9, 11 ); + P2( B, C, D, E, A, 13, 6, 11, 11 ); +#undef F +#undef K +#undef Fp +#undef Kp + + C = ctx->state[1] + C + Dp; + ctx->state[1] = ctx->state[2] + D + Ep; + ctx->state[2] = ctx->state[3] + E + Ap; + ctx->state[3] = ctx->state[4] + A + Bp; + ctx->state[4] = ctx->state[0] + B + Cp; + ctx->state[0] = C; +} +#endif /* !MBEDTLS_RIPEMD160_PROCESS_ALT */ + +/* + * RIPEMD-160 process buffer + */ +void mbedtls_ripemd160_update( mbedtls_ripemd160_context *ctx, + const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_ripemd160_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_ripemd160_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + { + memcpy( (void *) (ctx->buffer + left), input, ilen ); + } +} + +static const unsigned char ripemd160_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * RIPEMD-160 final digest + */ +void mbedtls_ripemd160_finish( mbedtls_ripemd160_context *ctx, unsigned char output[20] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_LE( low, msglen, 0 ); + PUT_UINT32_LE( high, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_ripemd160_update( ctx, ripemd160_padding, padn ); + mbedtls_ripemd160_update( ctx, msglen, 8 ); + + PUT_UINT32_LE( ctx->state[0], output, 0 ); + PUT_UINT32_LE( ctx->state[1], output, 4 ); + PUT_UINT32_LE( ctx->state[2], output, 8 ); + PUT_UINT32_LE( ctx->state[3], output, 12 ); + PUT_UINT32_LE( ctx->state[4], output, 16 ); +} + +/* + * output = RIPEMD-160( input buffer ) + */ +void mbedtls_ripemd160( const unsigned char *input, size_t ilen, + unsigned char output[20] ) +{ + mbedtls_ripemd160_context ctx; + + mbedtls_ripemd160_init( &ctx ); + mbedtls_ripemd160_starts( &ctx ); + mbedtls_ripemd160_update( &ctx, input, ilen ); + mbedtls_ripemd160_finish( &ctx, output ); + mbedtls_ripemd160_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * Test vectors from the RIPEMD-160 paper and + * http://homes.esat.kuleuven.be/~bosselae/mbedtls_ripemd160.html#HMAC + */ +#define TESTS 8 +#define KEYS 2 +static const char *ripemd160_test_input[TESTS] = +{ + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "1234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890", +}; + +static const unsigned char ripemd160_test_md[TESTS][20] = +{ + { 0x9c, 0x11, 0x85, 0xa5, 0xc5, 0xe9, 0xfc, 0x54, 0x61, 0x28, + 0x08, 0x97, 0x7e, 0xe8, 0xf5, 0x48, 0xb2, 0x25, 0x8d, 0x31 }, + { 0x0b, 0xdc, 0x9d, 0x2d, 0x25, 0x6b, 0x3e, 0xe9, 0xda, 0xae, + 0x34, 0x7b, 0xe6, 0xf4, 0xdc, 0x83, 0x5a, 0x46, 0x7f, 0xfe }, + { 0x8e, 0xb2, 0x08, 0xf7, 0xe0, 0x5d, 0x98, 0x7a, 0x9b, 0x04, + 0x4a, 0x8e, 0x98, 0xc6, 0xb0, 0x87, 0xf1, 0x5a, 0x0b, 0xfc }, + { 0x5d, 0x06, 0x89, 0xef, 0x49, 0xd2, 0xfa, 0xe5, 0x72, 0xb8, + 0x81, 0xb1, 0x23, 0xa8, 0x5f, 0xfa, 0x21, 0x59, 0x5f, 0x36 }, + { 0xf7, 0x1c, 0x27, 0x10, 0x9c, 0x69, 0x2c, 0x1b, 0x56, 0xbb, + 0xdc, 0xeb, 0x5b, 0x9d, 0x28, 0x65, 0xb3, 0x70, 0x8d, 0xbc }, + { 0x12, 0xa0, 0x53, 0x38, 0x4a, 0x9c, 0x0c, 0x88, 0xe4, 0x05, + 0xa0, 0x6c, 0x27, 0xdc, 0xf4, 0x9a, 0xda, 0x62, 0xeb, 0x2b }, + { 0xb0, 0xe2, 0x0b, 0x6e, 0x31, 0x16, 0x64, 0x02, 0x86, 0xed, + 0x3a, 0x87, 0xa5, 0x71, 0x30, 0x79, 0xb2, 0x1f, 0x51, 0x89 }, + { 0x9b, 0x75, 0x2e, 0x45, 0x57, 0x3d, 0x4b, 0x39, 0xf4, 0xdb, + 0xd3, 0x32, 0x3c, 0xab, 0x82, 0xbf, 0x63, 0x32, 0x6b, 0xfb }, +}; + +/* + * Checkup routine + */ +int mbedtls_ripemd160_self_test( int verbose ) +{ + int i; + unsigned char output[20]; + + memset( output, 0, sizeof output ); + + for( i = 0; i < TESTS; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " RIPEMD-160 test #%d: ", i + 1 ); + + mbedtls_ripemd160( (const unsigned char *) ripemd160_test_input[i], + strlen( ripemd160_test_input[i] ), + output ); + + if( memcmp( output, ripemd160_test_md[i], 20 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_RIPEMD160_C */ diff --git a/c++/src/connect/mbedtls/rsa.c b/c++/src/connect/mbedtls/rsa.c new file mode 100644 index 00000000..40ef2a94 --- /dev/null +++ b/c++/src/connect/mbedtls/rsa.c @@ -0,0 +1,1730 @@ +/* + * The RSA public-key cryptosystem + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The following sources were referenced in the design of this implementation + * of the RSA algorithm: + * + * [1] A method for obtaining digital signatures and public-key cryptosystems + * R Rivest, A Shamir, and L Adleman + * http://people.csail.mit.edu/rivest/pubs.html#RSA78 + * + * [2] Handbook of Applied Cryptography - 1997, Chapter 8 + * Menezes, van Oorschot and Vanstone + * + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_RSA_C) + +#include "mbedtls/rsa.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_PKCS1_V21) +#include "mbedtls/md.h" +#endif + +#if defined(MBEDTLS_PKCS1_V15) && !defined(__OpenBSD__) +#include +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +/* + * Initialize an RSA context + */ +void mbedtls_rsa_init( mbedtls_rsa_context *ctx, + int padding, + int hash_id ) +{ + memset( ctx, 0, sizeof( mbedtls_rsa_context ) ); + + mbedtls_rsa_set_padding( ctx, padding, hash_id ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +/* + * Set padding for an existing RSA context + */ +void mbedtls_rsa_set_padding( mbedtls_rsa_context *ctx, int padding, int hash_id ) +{ + ctx->padding = padding; + ctx->hash_id = hash_id; +} + +#if defined(MBEDTLS_GENPRIME) + +/* + * Generate an RSA keypair + */ +int mbedtls_rsa_gen_key( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + unsigned int nbits, int exponent ) +{ + int ret; + mbedtls_mpi P1, Q1, H, G; + + if( f_rng == NULL || nbits < 128 || exponent < 3 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( nbits % 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); + mbedtls_mpi_init( &H ); mbedtls_mpi_init( &G ); + + /* + * find primes P and Q with Q < P so that: + * GCD( E, (P-1)*(Q-1) ) == 1 + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &ctx->E, exponent ) ); + + do + { + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->P, nbits >> 1, 0, + f_rng, p_rng ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gen_prime( &ctx->Q, nbits >> 1, 0, + f_rng, p_rng ) ); + + if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) == 0 ) + continue; + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->N, &ctx->P, &ctx->Q ) ); + if( mbedtls_mpi_bitlen( &ctx->N ) != nbits ) + continue; + + if( mbedtls_mpi_cmp_mpi( &ctx->P, &ctx->Q ) < 0 ) + mbedtls_mpi_swap( &ctx->P, &ctx->Q ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) ); + } + while( mbedtls_mpi_cmp_int( &G, 1 ) != 0 ); + + /* + * D = E^-1 mod ((P-1)*(Q-1)) + * DP = D mod (P - 1) + * DQ = D mod (Q - 1) + * QP = Q^-1 mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->D , &ctx->E, &H ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DP, &ctx->D, &P1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->DQ, &ctx->D, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->QP, &ctx->Q, &ctx->P ) ); + + ctx->len = ( mbedtls_mpi_bitlen( &ctx->N ) + 7 ) >> 3; + +cleanup: + + mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); mbedtls_mpi_free( &H ); mbedtls_mpi_free( &G ); + + if( ret != 0 ) + { + mbedtls_rsa_free( ctx ); + return( MBEDTLS_ERR_RSA_KEY_GEN_FAILED + ret ); + } + + return( 0 ); +} + +#endif /* MBEDTLS_GENPRIME */ + +/* + * Check a public RSA key + */ +int mbedtls_rsa_check_pubkey( const mbedtls_rsa_context *ctx ) +{ + if( !ctx->N.p || !ctx->E.p ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + if( ( ctx->N.p[0] & 1 ) == 0 || + ( ctx->E.p[0] & 1 ) == 0 ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + if( mbedtls_mpi_bitlen( &ctx->N ) < 128 || + mbedtls_mpi_bitlen( &ctx->N ) > MBEDTLS_MPI_MAX_BITS ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + if( mbedtls_mpi_bitlen( &ctx->E ) < 2 || + mbedtls_mpi_cmp_mpi( &ctx->E, &ctx->N ) >= 0 ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + return( 0 ); +} + +/* + * Check a private RSA key + */ +int mbedtls_rsa_check_privkey( const mbedtls_rsa_context *ctx ) +{ + int ret; + mbedtls_mpi PQ, DE, P1, Q1, H, I, G, G2, L1, L2, DP, DQ, QP; + + if( ( ret = mbedtls_rsa_check_pubkey( ctx ) ) != 0 ) + return( ret ); + + if( !ctx->P.p || !ctx->Q.p || !ctx->D.p ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + + mbedtls_mpi_init( &PQ ); mbedtls_mpi_init( &DE ); mbedtls_mpi_init( &P1 ); mbedtls_mpi_init( &Q1 ); + mbedtls_mpi_init( &H ); mbedtls_mpi_init( &I ); mbedtls_mpi_init( &G ); mbedtls_mpi_init( &G2 ); + mbedtls_mpi_init( &L1 ); mbedtls_mpi_init( &L2 ); mbedtls_mpi_init( &DP ); mbedtls_mpi_init( &DQ ); + mbedtls_mpi_init( &QP ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &PQ, &ctx->P, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DE, &ctx->D, &ctx->E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &P1, &ctx->P, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &Q1, &ctx->Q, 1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &H, &P1, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G, &ctx->E, &H ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &G2, &P1, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_div_mpi( &L1, &L2, &H, &G2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &I, &DE, &L1 ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DP, &ctx->D, &P1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &DQ, &ctx->D, &Q1 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &QP, &ctx->Q, &ctx->P ) ); + /* + * Check for a valid PKCS1v2 private key + */ + if( mbedtls_mpi_cmp_mpi( &PQ, &ctx->N ) != 0 || + mbedtls_mpi_cmp_mpi( &DP, &ctx->DP ) != 0 || + mbedtls_mpi_cmp_mpi( &DQ, &ctx->DQ ) != 0 || + mbedtls_mpi_cmp_mpi( &QP, &ctx->QP ) != 0 || + mbedtls_mpi_cmp_int( &L2, 0 ) != 0 || + mbedtls_mpi_cmp_int( &I, 1 ) != 0 || + mbedtls_mpi_cmp_int( &G, 1 ) != 0 ) + { + ret = MBEDTLS_ERR_RSA_KEY_CHECK_FAILED; + } + +cleanup: + mbedtls_mpi_free( &PQ ); mbedtls_mpi_free( &DE ); mbedtls_mpi_free( &P1 ); mbedtls_mpi_free( &Q1 ); + mbedtls_mpi_free( &H ); mbedtls_mpi_free( &I ); mbedtls_mpi_free( &G ); mbedtls_mpi_free( &G2 ); + mbedtls_mpi_free( &L1 ); mbedtls_mpi_free( &L2 ); mbedtls_mpi_free( &DP ); mbedtls_mpi_free( &DQ ); + mbedtls_mpi_free( &QP ); + + if( ret == MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ) + return( ret ); + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED + ret ); + + return( 0 ); +} + +/* + * Check if contexts holding a public and private key match + */ +int mbedtls_rsa_check_pub_priv( const mbedtls_rsa_context *pub, const mbedtls_rsa_context *prv ) +{ + if( mbedtls_rsa_check_pubkey( pub ) != 0 || + mbedtls_rsa_check_privkey( prv ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + if( mbedtls_mpi_cmp_mpi( &pub->N, &prv->N ) != 0 || + mbedtls_mpi_cmp_mpi( &pub->E, &prv->E ) != 0 ) + { + return( MBEDTLS_ERR_RSA_KEY_CHECK_FAILED ); + } + + return( 0 ); +} + +/* + * Do an RSA public key operation + */ +int mbedtls_rsa_public( mbedtls_rsa_context *ctx, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + mbedtls_mpi T; + + mbedtls_mpi_init( &T ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) ); + + if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + olen = ctx->len; + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, &ctx->E, &ctx->N, &ctx->RN ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) ); + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + mbedtls_mpi_free( &T ); + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_PUBLIC_FAILED + ret ); + + return( 0 ); +} + +/* + * Generate or update blinding values, see section 10 of: + * KOCHER, Paul C. Timing attacks on implementations of Diffie-Hellman, RSA, + * DSS, and other systems. In : Advances in Cryptology-CRYPTO'96. Springer + * Berlin Heidelberg, 1996. p. 104-113. + */ +static int rsa_prepare_blinding( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng ) +{ + int ret, count = 0; + + if( ctx->Vf.p != NULL ) + { + /* We already have blinding values, just update them by squaring */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vi, &ctx->Vi, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vi, &ctx->Vi, &ctx->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ctx->Vf, &ctx->Vf, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &ctx->Vf, &ctx->Vf, &ctx->N ) ); + + goto cleanup; + } + + /* Unblinding value: Vf = random number, invertible mod N */ + do { + if( count++ > 10 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &ctx->Vf, ctx->len - 1, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_gcd( &ctx->Vi, &ctx->Vf, &ctx->N ) ); + } while( mbedtls_mpi_cmp_int( &ctx->Vi, 1 ) != 0 ); + + /* Blinding value: Vi = Vf^(-e) mod N */ + MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &ctx->Vi, &ctx->Vf, &ctx->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &ctx->Vi, &ctx->Vi, &ctx->E, &ctx->N, &ctx->RN ) ); + + +cleanup: + return( ret ); +} + +/* + * Do an RSA private key operation + */ +int mbedtls_rsa_private( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + const unsigned char *input, + unsigned char *output ) +{ + int ret; + size_t olen; + mbedtls_mpi T, T1, T2; + + /* Make sure we have private key info, prevent possible misuse */ + if( ctx->P.p == NULL || ctx->Q.p == NULL || ctx->D.p == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_mpi_init( &T ); mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &T, input, ctx->len ) ); + if( mbedtls_mpi_cmp_mpi( &T, &ctx->N ) >= 0 ) + { + ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA; + goto cleanup; + } + + if( f_rng != NULL ) + { + /* + * Blinding + * T = T * Vi mod N + */ + MBEDTLS_MPI_CHK( rsa_prepare_blinding( ctx, f_rng, p_rng ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) ); + } + +#if defined(MBEDTLS_RSA_NO_CRT) + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T, &T, &ctx->D, &ctx->N, &ctx->RN ) ); +#else + /* + * faster decryption using the CRT + * + * T1 = input ^ dP mod P + * T2 = input ^ dQ mod Q + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T1, &T, &ctx->DP, &ctx->P, &ctx->RP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_exp_mod( &T2, &T, &ctx->DQ, &ctx->Q, &ctx->RQ ) ); + + /* + * T = (T1 - T2) * (Q^-1 mod P) mod P + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T, &T1, &T2 ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->QP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T1, &ctx->P ) ); + + /* + * T = T2 + T * Q + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1, &T, &ctx->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T, &T2, &T1 ) ); +#endif /* MBEDTLS_RSA_NO_CRT */ + + if( f_rng != NULL ) + { + /* + * Unblind + * T = T * Vf mod N + */ + MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T, &T, &ctx->Vf ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_mod_mpi( &T, &T, &ctx->N ) ); + } + + olen = ctx->len; + MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &T, output, olen ) ); + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + mbedtls_mpi_free( &T ); mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); + + if( ret != 0 ) + return( MBEDTLS_ERR_RSA_PRIVATE_FAILED + ret ); + + return( 0 ); +} + +#if defined(MBEDTLS_PKCS1_V21) +/** + * Generate and apply the MGF1 operation (from PKCS#1 v2.1) to a buffer. + * + * \param dst buffer to mask + * \param dlen length of destination buffer + * \param src source of the mask generation + * \param slen length of the source buffer + * \param md_ctx message digest context to use + */ +static void mgf_mask( unsigned char *dst, size_t dlen, unsigned char *src, + size_t slen, mbedtls_md_context_t *md_ctx ) +{ + unsigned char mask[MBEDTLS_MD_MAX_SIZE]; + unsigned char counter[4]; + unsigned char *p; + unsigned int hlen; + size_t i, use_len; + + memset( mask, 0, MBEDTLS_MD_MAX_SIZE ); + memset( counter, 0, 4 ); + + hlen = mbedtls_md_get_size( md_ctx->md_info ); + + /* Generate and apply dbMask */ + p = dst; + + while( dlen > 0 ) + { + use_len = hlen; + if( dlen < hlen ) + use_len = dlen; + + mbedtls_md_starts( md_ctx ); + mbedtls_md_update( md_ctx, src, slen ); + mbedtls_md_update( md_ctx, counter, 4 ); + mbedtls_md_finish( md_ctx, mask ); + + for( i = 0; i < use_len; ++i ) + *p++ ^= mask[i]; + + counter[3]++; + + dlen -= use_len; + } +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-ENCRYPT function + */ +int mbedtls_rsa_rsaes_oaep_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + size_t olen; + int ret; + unsigned char *p = output; + unsigned int hlen; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( f_rng == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + hlen = mbedtls_md_get_size( md_info ); + + /* first comparison checks for overflow */ + if( ilen + 2 * hlen + 2 < ilen || olen < ilen + 2 * hlen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + memset( output, 0, olen ); + + *p++ = 0; + + /* Generate a random octet string seed */ + if( ( ret = f_rng( p_rng, p, hlen ) ) != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + p += hlen; + + /* Construct DB */ + mbedtls_md( md_info, label, label_len, p ); + p += hlen; + p += olen - 2 * hlen - 2 - ilen; + *p++ = 1; + memcpy( p, input, ilen ); + + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + { + mbedtls_md_free( &md_ctx ); + return( ret ); + } + + /* maskedDB: Apply dbMask to DB */ + mgf_mask( output + hlen + 1, olen - hlen - 1, output + 1, hlen, + &md_ctx ); + + /* maskedSeed: Apply seedMask to seed */ + mgf_mask( output + 1, hlen, output + hlen + 1, olen - hlen - 1, + &md_ctx ); + + mbedtls_md_free( &md_ctx ); + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, output, output ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-ENCRYPT function + */ +int mbedtls_rsa_rsaes_pkcs1_v15_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + size_t nb_pad, olen; + int ret; + unsigned char *p = output; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + // We don't check p_rng because it won't be dereferenced here + if( f_rng == NULL || input == NULL || output == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + /* first comparison checks for overflow */ + if( ilen + 11 < ilen || olen < ilen + 11 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + nb_pad = olen - 3 - ilen; + + *p++ = 0; + if( mode == MBEDTLS_RSA_PUBLIC ) + { + *p++ = MBEDTLS_RSA_CRYPT; + + while( nb_pad-- > 0 ) + { + int rng_dl = 100; + + do { + ret = f_rng( p_rng, p, 1 ); + } while( *p == 0 && --rng_dl && ret == 0 ); + + /* Check if RNG failed to generate data */ + if( rng_dl == 0 || ret != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + p++; + } + } + else + { + *p++ = MBEDTLS_RSA_SIGN; + + while( nb_pad-- > 0 ) + *p++ = 0xFF; + } + + *p++ = 0; + memcpy( p, input, ilen ); + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, output, output ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, output, output ) ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Add the message padding, then do an RSA operation + */ +int mbedtls_rsa_pkcs1_encrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t ilen, + const unsigned char *input, + unsigned char *output ) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsaes_pkcs1_v15_encrypt( ctx, f_rng, p_rng, mode, ilen, + input, output ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsaes_oaep_encrypt( ctx, f_rng, p_rng, mode, NULL, 0, + ilen, input, output ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSAES-OAEP-DECRYPT function + */ +int mbedtls_rsa_rsaes_oaep_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + const unsigned char *label, size_t label_len, + size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len ) +{ + int ret; + size_t ilen, i, pad_len; + unsigned char *p, bad, pad_done; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + unsigned char lhash[MBEDTLS_MD_MAX_SIZE]; + unsigned int hlen; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + /* + * Parameters sanity checks + */ + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hlen = mbedtls_md_get_size( md_info ); + + // checking for integer underflow + if( 2 * hlen + 2 > ilen ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + /* + * RSA operation + */ + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, input, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf ); + + if( ret != 0 ) + return( ret ); + + /* + * Unmask data and generate lHash + */ + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + { + mbedtls_md_free( &md_ctx ); + return( ret ); + } + + + /* Generate lHash */ + mbedtls_md( md_info, label, label_len, lhash ); + + /* seed: Apply seedMask to maskedSeed */ + mgf_mask( buf + 1, hlen, buf + hlen + 1, ilen - hlen - 1, + &md_ctx ); + + /* DB: Apply dbMask to maskedDB */ + mgf_mask( buf + hlen + 1, ilen - hlen - 1, buf + 1, hlen, + &md_ctx ); + + mbedtls_md_free( &md_ctx ); + + /* + * Check contents, in "constant-time" + */ + p = buf; + bad = 0; + + bad |= *p++; /* First byte must be 0 */ + + p += hlen; /* Skip seed */ + + /* Check lHash */ + for( i = 0; i < hlen; i++ ) + bad |= lhash[i] ^ *p++; + + /* Get zero-padding len, but always read till end of buffer + * (minus one, for the 01 byte) */ + pad_len = 0; + pad_done = 0; + for( i = 0; i < ilen - 2 * hlen - 2; i++ ) + { + pad_done |= p[i]; + pad_len += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; + } + + p += pad_len; + bad |= *p++ ^ 0x01; + + /* + * The only information "leaked" is whether the padding was correct or not + * (eg, no data is copied if it was not correct). This meets the + * recommendations in PKCS#1 v2.2: an opponent cannot distinguish between + * the different error conditions. + */ + if( bad != 0 ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + if( ilen - ( p - buf ) > output_max_len ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + *olen = ilen - (p - buf); + memcpy( output, p, *olen ); + + return( 0 ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function + */ +int mbedtls_rsa_rsaes_pkcs1_v15_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + int ret; + size_t ilen, pad_count = 0, i; + unsigned char *p, bad, pad_done = 0; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ilen = ctx->len; + + if( ilen < 16 || ilen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, input, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, input, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + bad = 0; + + /* + * Check and get padding len in "constant-time" + */ + bad |= *p++; /* First byte must be 0 */ + + /* This test does not depend on secret data */ + if( mode == MBEDTLS_RSA_PRIVATE ) + { + bad |= *p++ ^ MBEDTLS_RSA_CRYPT; + + /* Get padding len, but always read till end of buffer + * (minus one, for the 00 byte) */ + for( i = 0; i < ilen - 3; i++ ) + { + pad_done |= ((p[i] | (unsigned char)-p[i]) >> 7) ^ 1; + pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1; + } + + p += pad_count; + bad |= *p++; /* Must be zero */ + } + else + { + bad |= *p++ ^ MBEDTLS_RSA_SIGN; + + /* Get padding len, but always read till end of buffer + * (minus one, for the 00 byte) */ + for( i = 0; i < ilen - 3; i++ ) + { + pad_done |= ( p[i] != 0xFF ); + pad_count += ( pad_done == 0 ); + } + + p += pad_count; + bad |= *p++; /* Must be zero */ + } + + bad |= ( pad_count < 8 ); + + if( bad ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + if( ilen - ( p - buf ) > output_max_len ) + return( MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE ); + + *olen = ilen - (p - buf); + memcpy( output, p, *olen ); + + return( 0 ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation, then remove the message padding + */ +int mbedtls_rsa_pkcs1_decrypt( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, size_t *olen, + const unsigned char *input, + unsigned char *output, + size_t output_max_len) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsaes_pkcs1_v15_decrypt( ctx, f_rng, p_rng, mode, olen, + input, output, output_max_len ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsaes_oaep_decrypt( ctx, f_rng, p_rng, mode, NULL, 0, + olen, input, output, + output_max_len ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-SIGN function + */ +int mbedtls_rsa_rsassa_pss_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t olen; + unsigned char *p = sig; + unsigned char salt[MBEDTLS_MD_MAX_SIZE]; + unsigned int slen, hlen, offset = 0; + int ret; + size_t msb; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( f_rng == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + + if( md_alg != MBEDTLS_MD_NONE ) + { + /* Gather length of hash to sign */ + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + } + + md_info = mbedtls_md_info_from_type( (mbedtls_md_type_t) ctx->hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hlen = mbedtls_md_get_size( md_info ); + slen = hlen; + + if( olen < hlen + slen + 2 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + memset( sig, 0, olen ); + + /* Generate salt of length slen */ + if( ( ret = f_rng( p_rng, salt, slen ) ) != 0 ) + return( MBEDTLS_ERR_RSA_RNG_FAILED + ret ); + + /* Note: EMSA-PSS encoding is over the length of N - 1 bits */ + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + p += olen - hlen * 2 - 2; + *p++ = 0x01; + memcpy( p, salt, slen ); + p += slen; + + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + { + mbedtls_md_free( &md_ctx ); + return( ret ); + } + + /* Generate H = Hash( M' ) */ + mbedtls_md_starts( &md_ctx ); + mbedtls_md_update( &md_ctx, p, 8 ); + mbedtls_md_update( &md_ctx, hash, hashlen ); + mbedtls_md_update( &md_ctx, salt, slen ); + mbedtls_md_finish( &md_ctx, p ); + + /* Compensate for boundary condition when applying mask */ + if( msb % 8 == 0 ) + offset = 1; + + /* maskedDB: Apply dbMask to DB */ + mgf_mask( sig + offset, olen - hlen - 1 - offset, p, hlen, &md_ctx ); + + mbedtls_md_free( &md_ctx ); + + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + sig[0] &= 0xFF >> ( olen * 8 - msb ); + + p += hlen; + *p++ = 0xBC; + + return( ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, sig ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig ) ); +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-V1_5-SIGN function + */ +/* + * Do an RSA operation to sign the message digest + */ +int mbedtls_rsa_rsassa_pkcs1_v15_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + size_t nb_pad, olen, oid_size = 0; + unsigned char *p = sig; + const char *oid = NULL; + unsigned char *sig_try = NULL, *verif = NULL; + size_t i; + unsigned char diff; + volatile unsigned char diff_no_optimize; + int ret; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + olen = ctx->len; + nb_pad = olen - 3; + + if( md_alg != MBEDTLS_MD_NONE ) + { + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + if( mbedtls_oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + nb_pad -= 10 + oid_size; + + hashlen = mbedtls_md_get_size( md_info ); + } + + nb_pad -= hashlen; + + if( ( nb_pad < 8 ) || ( nb_pad > olen ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + *p++ = 0; + *p++ = MBEDTLS_RSA_SIGN; + memset( p, 0xFF, nb_pad ); + p += nb_pad; + *p++ = 0; + + if( md_alg == MBEDTLS_MD_NONE ) + { + memcpy( p, hash, hashlen ); + } + else + { + /* + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + */ + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x08 + oid_size + hashlen ); + *p++ = MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED; + *p++ = (unsigned char) ( 0x04 + oid_size ); + *p++ = MBEDTLS_ASN1_OID; + *p++ = oid_size & 0xFF; + memcpy( p, oid, oid_size ); + p += oid_size; + *p++ = MBEDTLS_ASN1_NULL; + *p++ = 0x00; + *p++ = MBEDTLS_ASN1_OCTET_STRING; + *p++ = hashlen; + memcpy( p, hash, hashlen ); + } + + if( mode == MBEDTLS_RSA_PUBLIC ) + return( mbedtls_rsa_public( ctx, sig, sig ) ); + + /* + * In order to prevent Lenstra's attack, make the signature in a + * temporary buffer and check it before returning it. + */ + sig_try = mbedtls_calloc( 1, ctx->len ); + if( sig_try == NULL ) + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + + verif = mbedtls_calloc( 1, ctx->len ); + if( verif == NULL ) + { + mbedtls_free( sig_try ); + return( MBEDTLS_ERR_MPI_ALLOC_FAILED ); + } + + MBEDTLS_MPI_CHK( mbedtls_rsa_private( ctx, f_rng, p_rng, sig, sig_try ) ); + MBEDTLS_MPI_CHK( mbedtls_rsa_public( ctx, sig_try, verif ) ); + + /* Compare in constant time just in case */ + for( diff = 0, i = 0; i < ctx->len; i++ ) + diff |= verif[i] ^ sig[i]; + diff_no_optimize = diff; + + if( diff_no_optimize != 0 ) + { + ret = MBEDTLS_ERR_RSA_PRIVATE_FAILED; + goto cleanup; + } + + memcpy( sig, sig_try, ctx->len ); + +cleanup: + mbedtls_free( sig_try ); + mbedtls_free( verif ); + + return( ret ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation to sign the message digest + */ +int mbedtls_rsa_pkcs1_sign( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + unsigned char *sig ) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsassa_pkcs1_v15_sign( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsassa_pss_sign( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +#if defined(MBEDTLS_PKCS1_V21) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PSS-VERIFY function + */ +int mbedtls_rsa_rsassa_pss_verify_ext( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + mbedtls_md_type_t mgf1_hash_id, + int expected_salt_len, + const unsigned char *sig ) +{ + int ret; + size_t siglen; + unsigned char *p; + unsigned char result[MBEDTLS_MD_MAX_SIZE]; + unsigned char zeros[8]; + unsigned int hlen; + size_t slen, msb; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V21 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + siglen = ctx->len; + + if( siglen < 16 || siglen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( buf[siglen - 1] != 0xBC ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + if( md_alg != MBEDTLS_MD_NONE ) + { + /* Gather length of hash to sign */ + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hashlen = mbedtls_md_get_size( md_info ); + } + + md_info = mbedtls_md_info_from_type( mgf1_hash_id ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + hlen = mbedtls_md_get_size( md_info ); + slen = siglen - hlen - 1; /* Currently length of salt + padding */ + + memset( zeros, 0, 8 ); + + /* + * Note: EMSA-PSS verification is over the length of N - 1 bits + */ + msb = mbedtls_mpi_bitlen( &ctx->N ) - 1; + + /* Compensate for boundary condition when applying mask */ + if( msb % 8 == 0 ) + { + p++; + siglen -= 1; + } + if( buf[0] >> ( 8 - siglen * 8 + msb ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + mbedtls_md_init( &md_ctx ); + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 0 ) ) != 0 ) + { + mbedtls_md_free( &md_ctx ); + return( ret ); + } + + mgf_mask( p, siglen - hlen - 1, p + siglen - hlen - 1, hlen, &md_ctx ); + + buf[0] &= 0xFF >> ( siglen * 8 - msb ); + + while( p < buf + siglen && *p == 0 ) + p++; + + if( p == buf + siglen || + *p++ != 0x01 ) + { + mbedtls_md_free( &md_ctx ); + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } + + /* Actual salt len */ + slen -= p - buf; + + if( expected_salt_len != MBEDTLS_RSA_SALT_LEN_ANY && + slen != (size_t) expected_salt_len ) + { + mbedtls_md_free( &md_ctx ); + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } + + /* + * Generate H = Hash( M' ) + */ + mbedtls_md_starts( &md_ctx ); + mbedtls_md_update( &md_ctx, zeros, 8 ); + mbedtls_md_update( &md_ctx, hash, hashlen ); + mbedtls_md_update( &md_ctx, p, slen ); + mbedtls_md_finish( &md_ctx, result ); + + mbedtls_md_free( &md_ctx ); + + if( memcmp( p + slen, result, hlen ) == 0 ) + return( 0 ); + else + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); +} + +/* + * Simplified PKCS#1 v2.1 RSASSA-PSS-VERIFY function + */ +int mbedtls_rsa_rsassa_pss_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + mbedtls_md_type_t mgf1_hash_id = ( ctx->hash_id != MBEDTLS_MD_NONE ) + ? (mbedtls_md_type_t) ctx->hash_id + : md_alg; + + return( mbedtls_rsa_rsassa_pss_verify_ext( ctx, f_rng, p_rng, mode, + md_alg, hashlen, hash, + mgf1_hash_id, MBEDTLS_RSA_SALT_LEN_ANY, + sig ) ); + +} +#endif /* MBEDTLS_PKCS1_V21 */ + +#if defined(MBEDTLS_PKCS1_V15) +/* + * Implementation of the PKCS#1 v2.1 RSASSA-PKCS1-v1_5-VERIFY function + */ +int mbedtls_rsa_rsassa_pkcs1_v15_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + int ret; + size_t len, siglen, asn1_len; + unsigned char *p, *end; + mbedtls_md_type_t msg_md_alg; + const mbedtls_md_info_t *md_info; + mbedtls_asn1_buf oid; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; + + if( mode == MBEDTLS_RSA_PRIVATE && ctx->padding != MBEDTLS_RSA_PKCS_V15 ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + siglen = ctx->len; + + if( siglen < 16 || siglen > sizeof( buf ) ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + + ret = ( mode == MBEDTLS_RSA_PUBLIC ) + ? mbedtls_rsa_public( ctx, sig, buf ) + : mbedtls_rsa_private( ctx, f_rng, p_rng, sig, buf ); + + if( ret != 0 ) + return( ret ); + + p = buf; + + if( *p++ != 0 || *p++ != MBEDTLS_RSA_SIGN ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + + while( *p != 0 ) + { + if( p >= buf + siglen - 1 || *p != 0xFF ) + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + p++; + } + p++; + + len = siglen - ( p - buf ); + + if( len == hashlen && md_alg == MBEDTLS_MD_NONE ) + { + if( memcmp( p, hash, hashlen ) == 0 ) + return( 0 ); + else + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + } + + md_info = mbedtls_md_info_from_type( md_alg ); + if( md_info == NULL ) + return( MBEDTLS_ERR_RSA_BAD_INPUT_DATA ); + hashlen = mbedtls_md_get_size( md_info ); + + end = p + len; + + /* + * Parse the ASN.1 structure inside the PKCS#1 v1.5 structure + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( asn1_len + 2 != len ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( asn1_len + 6 + hashlen != len ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + oid.p = p; + p += oid.len; + + if( mbedtls_oid_get_md_alg( &oid, &msg_md_alg ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( md_alg != msg_md_alg ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + /* + * assume the algorithm parameters must be NULL + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_NULL ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &asn1_len, MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( asn1_len != hashlen ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + if( memcmp( p, hash, hashlen ) != 0 ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + p += hashlen; + + if( p != end ) + return( MBEDTLS_ERR_RSA_VERIFY_FAILED ); + + return( 0 ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Do an RSA operation and check the message digest + */ +int mbedtls_rsa_pkcs1_verify( mbedtls_rsa_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng, + int mode, + mbedtls_md_type_t md_alg, + unsigned int hashlen, + const unsigned char *hash, + const unsigned char *sig ) +{ + switch( ctx->padding ) + { +#if defined(MBEDTLS_PKCS1_V15) + case MBEDTLS_RSA_PKCS_V15: + return mbedtls_rsa_rsassa_pkcs1_v15_verify( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + +#if defined(MBEDTLS_PKCS1_V21) + case MBEDTLS_RSA_PKCS_V21: + return mbedtls_rsa_rsassa_pss_verify( ctx, f_rng, p_rng, mode, md_alg, + hashlen, hash, sig ); +#endif + + default: + return( MBEDTLS_ERR_RSA_INVALID_PADDING ); + } +} + +/* + * Copy the components of an RSA key + */ +int mbedtls_rsa_copy( mbedtls_rsa_context *dst, const mbedtls_rsa_context *src ) +{ + int ret; + + dst->ver = src->ver; + dst->len = src->len; + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->N, &src->N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->E, &src->E ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->D, &src->D ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->P, &src->P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Q, &src->Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DP, &src->DP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->DQ, &src->DQ ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->QP, &src->QP ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RN, &src->RN ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RP, &src->RP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->RQ, &src->RQ ) ); + + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vi, &src->Vi ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &dst->Vf, &src->Vf ) ); + + dst->padding = src->padding; + dst->hash_id = src->hash_id; + +cleanup: + if( ret != 0 ) + mbedtls_rsa_free( dst ); + + return( ret ); +} + +/* + * Free the components of an RSA key + */ +void mbedtls_rsa_free( mbedtls_rsa_context *ctx ) +{ + mbedtls_mpi_free( &ctx->Vi ); mbedtls_mpi_free( &ctx->Vf ); + mbedtls_mpi_free( &ctx->RQ ); mbedtls_mpi_free( &ctx->RP ); mbedtls_mpi_free( &ctx->RN ); + mbedtls_mpi_free( &ctx->QP ); mbedtls_mpi_free( &ctx->DQ ); mbedtls_mpi_free( &ctx->DP ); + mbedtls_mpi_free( &ctx->Q ); mbedtls_mpi_free( &ctx->P ); mbedtls_mpi_free( &ctx->D ); + mbedtls_mpi_free( &ctx->E ); mbedtls_mpi_free( &ctx->N ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif +} + +#if defined(MBEDTLS_SELF_TEST) + +#include "mbedtls/sha1.h" + +/* + * Example RSA-1024 keypair, for test purposes + */ +#define KEY_LEN 128 + +#define RSA_N "9292758453063D803DD603D5E777D788" \ + "8ED1D5BF35786190FA2F23EBC0848AEA" \ + "DDA92CA6C3D80B32C4D109BE0F36D6AE" \ + "7130B9CED7ACDF54CFC7555AC14EEBAB" \ + "93A89813FBF3C4F8066D2D800F7C38A8" \ + "1AE31942917403FF4946B0A83D3D3E05" \ + "EE57C6F5F5606FB5D4BC6CD34EE0801A" \ + "5E94BB77B07507233A0BC7BAC8F90F79" + +#define RSA_E "10001" + +#define RSA_D "24BF6185468786FDD303083D25E64EFC" \ + "66CA472BC44D253102F8B4A9D3BFA750" \ + "91386C0077937FE33FA3252D28855837" \ + "AE1B484A8A9A45F7EE8C0C634F99E8CD" \ + "DF79C5CE07EE72C7F123142198164234" \ + "CABB724CF78B8173B9F880FC86322407" \ + "AF1FEDFDDE2BEB674CA15F3E81A1521E" \ + "071513A1E85B5DFA031F21ECAE91A34D" + +#define RSA_P "C36D0EB7FCD285223CFB5AABA5BDA3D8" \ + "2C01CAD19EA484A87EA4377637E75500" \ + "FCB2005C5C7DD6EC4AC023CDA285D796" \ + "C3D9E75E1EFC42488BB4F1D13AC30A57" + +#define RSA_Q "C000DF51A7C77AE8D7C7370C1FF55B69" \ + "E211C2B9E5DB1ED0BF61D0D9899620F4" \ + "910E4168387E3C30AA1E00C339A79508" \ + "8452DD96A9A5EA5D9DCA68DA636032AF" + +#define RSA_DP "C1ACF567564274FB07A0BBAD5D26E298" \ + "3C94D22288ACD763FD8E5600ED4A702D" \ + "F84198A5F06C2E72236AE490C93F07F8" \ + "3CC559CD27BC2D1CA488811730BB5725" + +#define RSA_DQ "4959CBF6F8FEF750AEE6977C155579C7" \ + "D8AAEA56749EA28623272E4F7D0592AF" \ + "7C1F1313CAC9471B5C523BFE592F517B" \ + "407A1BD76C164B93DA2D32A383E58357" + +#define RSA_QP "9AE7FBC99546432DF71896FC239EADAE" \ + "F38D18D2B2F0E2DD275AA977E2BF4411" \ + "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ + "A74206CEC169D74BF5A8C50D6F48EA08" + +#define PT_LEN 24 +#define RSA_PT "\xAA\xBB\xCC\x03\x02\x01\x00\xFF\xFF\xFF\xFF\xFF" \ + "\x11\x22\x33\x0A\x0B\x0C\xCC\xDD\xDD\xDD\xDD\xDD" + +#if defined(MBEDTLS_PKCS1_V15) +static int myrand( void *rng_state, unsigned char *output, size_t len ) +{ +#if !defined(__OpenBSD__) + size_t i; + + if( rng_state != NULL ) + rng_state = NULL; + + for( i = 0; i < len; ++i ) + output[i] = rand(); +#else + if( rng_state != NULL ) + rng_state = NULL; + + arc4random_buf( output, len ); +#endif /* !OpenBSD */ + + return( 0 ); +} +#endif /* MBEDTLS_PKCS1_V15 */ + +/* + * Checkup routine + */ +int mbedtls_rsa_self_test( int verbose ) +{ + int ret = 0; +#if defined(MBEDTLS_PKCS1_V15) + size_t len; + mbedtls_rsa_context rsa; + unsigned char rsa_plaintext[PT_LEN]; + unsigned char rsa_decrypted[PT_LEN]; + unsigned char rsa_ciphertext[KEY_LEN]; +#if defined(MBEDTLS_SHA1_C) + unsigned char sha1sum[20]; +#endif + + mbedtls_rsa_init( &rsa, MBEDTLS_RSA_PKCS_V15, 0 ); + + rsa.len = KEY_LEN; + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.N , 16, RSA_N ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.E , 16, RSA_E ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.D , 16, RSA_D ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.P , 16, RSA_P ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.Q , 16, RSA_Q ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.DP, 16, RSA_DP ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.DQ, 16, RSA_DQ ) ); + MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &rsa.QP, 16, RSA_QP ) ); + + if( verbose != 0 ) + mbedtls_printf( " RSA key validation: " ); + + if( mbedtls_rsa_check_pubkey( &rsa ) != 0 || + mbedtls_rsa_check_privkey( &rsa ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 encryption : " ); + + memcpy( rsa_plaintext, RSA_PT, PT_LEN ); + + if( mbedtls_rsa_pkcs1_encrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PUBLIC, PT_LEN, + rsa_plaintext, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 decryption : " ); + + if( mbedtls_rsa_pkcs1_decrypt( &rsa, myrand, NULL, MBEDTLS_RSA_PRIVATE, &len, + rsa_ciphertext, rsa_decrypted, + sizeof(rsa_decrypted) ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( memcmp( rsa_decrypted, rsa_plaintext, len ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +#if defined(MBEDTLS_SHA1_C) + if( verbose != 0 ) + mbedtls_printf( " PKCS#1 data sign : " ); + + mbedtls_sha1( rsa_plaintext, PT_LEN, sha1sum ); + + if( mbedtls_rsa_pkcs1_sign( &rsa, myrand, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 0, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n PKCS#1 sig. verify: " ); + + if( mbedtls_rsa_pkcs1_verify( &rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 0, + sha1sum, rsa_ciphertext ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); +#endif /* MBEDTLS_SHA1_C */ + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +cleanup: + mbedtls_rsa_free( &rsa ); +#else /* MBEDTLS_PKCS1_V15 */ + ((void) verbose); +#endif /* MBEDTLS_PKCS1_V15 */ + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_RSA_C */ diff --git a/c++/src/connect/mbedtls/sha1.c b/c++/src/connect/mbedtls/sha1.c new file mode 100644 index 00000000..2ccf2a2f --- /dev/null +++ b/c++/src/connect/mbedtls/sha1.c @@ -0,0 +1,448 @@ +/* + * FIPS-180-1 compliant SHA-1 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-1 standard was published by NIST in 1993. + * + * http://www.itl.nist.gov/fipspubs/fip180-1.htm + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA1_C) + +#include "mbedtls/sha1.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_SHA1_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = (unsigned char*)v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +void mbedtls_sha1_init( mbedtls_sha1_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_free( mbedtls_sha1_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha1_context ) ); +} + +void mbedtls_sha1_clone( mbedtls_sha1_context *dst, + const mbedtls_sha1_context *src ) +{ + *dst = *src; +} + +/* + * SHA-1 context setup + */ +void mbedtls_sha1_starts( mbedtls_sha1_context *ctx ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + ctx->state[0] = 0x67452301; + ctx->state[1] = 0xEFCDAB89; + ctx->state[2] = 0x98BADCFE; + ctx->state[3] = 0x10325476; + ctx->state[4] = 0xC3D2E1F0; +} + +#if !defined(MBEDTLS_SHA1_PROCESS_ALT) +void mbedtls_sha1_process( mbedtls_sha1_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp, W[16], A, B, C, D, E; + + GET_UINT32_BE( W[ 0], data, 0 ); + GET_UINT32_BE( W[ 1], data, 4 ); + GET_UINT32_BE( W[ 2], data, 8 ); + GET_UINT32_BE( W[ 3], data, 12 ); + GET_UINT32_BE( W[ 4], data, 16 ); + GET_UINT32_BE( W[ 5], data, 20 ); + GET_UINT32_BE( W[ 6], data, 24 ); + GET_UINT32_BE( W[ 7], data, 28 ); + GET_UINT32_BE( W[ 8], data, 32 ); + GET_UINT32_BE( W[ 9], data, 36 ); + GET_UINT32_BE( W[10], data, 40 ); + GET_UINT32_BE( W[11], data, 44 ); + GET_UINT32_BE( W[12], data, 48 ); + GET_UINT32_BE( W[13], data, 52 ); + GET_UINT32_BE( W[14], data, 56 ); + GET_UINT32_BE( W[15], data, 60 ); + +#define S(x,n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n))) + +#define R(t) \ +( \ + temp = W[( t - 3 ) & 0x0F] ^ W[( t - 8 ) & 0x0F] ^ \ + W[( t - 14 ) & 0x0F] ^ W[ t & 0x0F], \ + ( W[t & 0x0F] = S(temp,1) ) \ +) + +#define P(a,b,c,d,e,x) \ +{ \ + e += S(a,5) + F(b,c,d) + K + x; b = S(b,30); \ +} + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + +#define F(x,y,z) (z ^ (x & (y ^ z))) +#define K 0x5A827999 + + P( A, B, C, D, E, W[0] ); + P( E, A, B, C, D, W[1] ); + P( D, E, A, B, C, W[2] ); + P( C, D, E, A, B, W[3] ); + P( B, C, D, E, A, W[4] ); + P( A, B, C, D, E, W[5] ); + P( E, A, B, C, D, W[6] ); + P( D, E, A, B, C, W[7] ); + P( C, D, E, A, B, W[8] ); + P( B, C, D, E, A, W[9] ); + P( A, B, C, D, E, W[10] ); + P( E, A, B, C, D, W[11] ); + P( D, E, A, B, C, W[12] ); + P( C, D, E, A, B, W[13] ); + P( B, C, D, E, A, W[14] ); + P( A, B, C, D, E, W[15] ); + P( E, A, B, C, D, R(16) ); + P( D, E, A, B, C, R(17) ); + P( C, D, E, A, B, R(18) ); + P( B, C, D, E, A, R(19) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0x6ED9EBA1 + + P( A, B, C, D, E, R(20) ); + P( E, A, B, C, D, R(21) ); + P( D, E, A, B, C, R(22) ); + P( C, D, E, A, B, R(23) ); + P( B, C, D, E, A, R(24) ); + P( A, B, C, D, E, R(25) ); + P( E, A, B, C, D, R(26) ); + P( D, E, A, B, C, R(27) ); + P( C, D, E, A, B, R(28) ); + P( B, C, D, E, A, R(29) ); + P( A, B, C, D, E, R(30) ); + P( E, A, B, C, D, R(31) ); + P( D, E, A, B, C, R(32) ); + P( C, D, E, A, B, R(33) ); + P( B, C, D, E, A, R(34) ); + P( A, B, C, D, E, R(35) ); + P( E, A, B, C, D, R(36) ); + P( D, E, A, B, C, R(37) ); + P( C, D, E, A, B, R(38) ); + P( B, C, D, E, A, R(39) ); + +#undef K +#undef F + +#define F(x,y,z) ((x & y) | (z & (x | y))) +#define K 0x8F1BBCDC + + P( A, B, C, D, E, R(40) ); + P( E, A, B, C, D, R(41) ); + P( D, E, A, B, C, R(42) ); + P( C, D, E, A, B, R(43) ); + P( B, C, D, E, A, R(44) ); + P( A, B, C, D, E, R(45) ); + P( E, A, B, C, D, R(46) ); + P( D, E, A, B, C, R(47) ); + P( C, D, E, A, B, R(48) ); + P( B, C, D, E, A, R(49) ); + P( A, B, C, D, E, R(50) ); + P( E, A, B, C, D, R(51) ); + P( D, E, A, B, C, R(52) ); + P( C, D, E, A, B, R(53) ); + P( B, C, D, E, A, R(54) ); + P( A, B, C, D, E, R(55) ); + P( E, A, B, C, D, R(56) ); + P( D, E, A, B, C, R(57) ); + P( C, D, E, A, B, R(58) ); + P( B, C, D, E, A, R(59) ); + +#undef K +#undef F + +#define F(x,y,z) (x ^ y ^ z) +#define K 0xCA62C1D6 + + P( A, B, C, D, E, R(60) ); + P( E, A, B, C, D, R(61) ); + P( D, E, A, B, C, R(62) ); + P( C, D, E, A, B, R(63) ); + P( B, C, D, E, A, R(64) ); + P( A, B, C, D, E, R(65) ); + P( E, A, B, C, D, R(66) ); + P( D, E, A, B, C, R(67) ); + P( C, D, E, A, B, R(68) ); + P( B, C, D, E, A, R(69) ); + P( A, B, C, D, E, R(70) ); + P( E, A, B, C, D, R(71) ); + P( D, E, A, B, C, R(72) ); + P( C, D, E, A, B, R(73) ); + P( B, C, D, E, A, R(74) ); + P( A, B, C, D, E, R(75) ); + P( E, A, B, C, D, R(76) ); + P( D, E, A, B, C, R(77) ); + P( C, D, E, A, B, R(78) ); + P( B, C, D, E, A, R(79) ); + +#undef K +#undef F + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; +} +#endif /* !MBEDTLS_SHA1_PROCESS_ALT */ + +/* + * SHA-1 process buffer + */ +void mbedtls_sha1_update( mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha1_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha1_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha1_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-1 final digest + */ +void mbedtls_sha1_finish( mbedtls_sha1_context *ctx, unsigned char output[20] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha1_update( ctx, sha1_padding, padn ); + mbedtls_sha1_update( ctx, msglen, 8 ); + + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); +} + +#endif /* !MBEDTLS_SHA1_ALT */ + +/* + * output = SHA-1( input buffer ) + */ +void mbedtls_sha1( const unsigned char *input, size_t ilen, unsigned char output[20] ) +{ + mbedtls_sha1_context ctx; + + mbedtls_sha1_init( &ctx ); + mbedtls_sha1_starts( &ctx ); + mbedtls_sha1_update( &ctx, input, ilen ); + mbedtls_sha1_finish( &ctx, output ); + mbedtls_sha1_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-1 test vectors + */ +static const unsigned char sha1_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const int sha1_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha1_test_sum[3][20] = +{ + { 0xA9, 0x99, 0x3E, 0x36, 0x47, 0x06, 0x81, 0x6A, 0xBA, 0x3E, + 0x25, 0x71, 0x78, 0x50, 0xC2, 0x6C, 0x9C, 0xD0, 0xD8, 0x9D }, + { 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E, 0xBA, 0xAE, + 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5, 0xE5, 0x46, 0x70, 0xF1 }, + { 0x34, 0xAA, 0x97, 0x3C, 0xD4, 0xC4, 0xDA, 0xA4, 0xF6, 0x1E, + 0xEB, 0x2B, 0xDB, 0xAD, 0x27, 0x31, 0x65, 0x34, 0x01, 0x6F } +}; + +/* + * Checkup routine + */ +int mbedtls_sha1_self_test( int verbose ) +{ + int i, j, buflen, ret = 0; + unsigned char buf[1024]; + unsigned char sha1sum[20]; + mbedtls_sha1_context ctx; + + mbedtls_sha1_init( &ctx ); + + /* + * SHA-1 + */ + for( i = 0; i < 3; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " SHA-1 test #%d: ", i + 1 ); + + mbedtls_sha1_starts( &ctx ); + + if( i == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + mbedtls_sha1_update( &ctx, buf, buflen ); + } + else + mbedtls_sha1_update( &ctx, sha1_test_buf[i], + sha1_test_buflen[i] ); + + mbedtls_sha1_finish( &ctx, sha1sum ); + + if( memcmp( sha1sum, sha1_test_sum[i], 20 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_sha1_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA1_C */ diff --git a/c++/src/connect/mbedtls/sha256.c b/c++/src/connect/mbedtls/sha256.c new file mode 100644 index 00000000..ad25d383 --- /dev/null +++ b/c++/src/connect/mbedtls/sha256.c @@ -0,0 +1,458 @@ +/* + * FIPS-180-2 compliant SHA-256 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-256 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA256_C) + +#include "mbedtls/sha256.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_SHA256_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +do { \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} while( 0 ) +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +do { \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} while( 0 ) +#endif + +void mbedtls_sha256_init( mbedtls_sha256_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_free( mbedtls_sha256_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha256_context ) ); +} + +void mbedtls_sha256_clone( mbedtls_sha256_context *dst, + const mbedtls_sha256_context *src ) +{ + *dst = *src; +} + +/* + * SHA-256 context setup + */ +void mbedtls_sha256_starts( mbedtls_sha256_context *ctx, int is224 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is224 == 0 ) + { + /* SHA-256 */ + ctx->state[0] = 0x6A09E667; + ctx->state[1] = 0xBB67AE85; + ctx->state[2] = 0x3C6EF372; + ctx->state[3] = 0xA54FF53A; + ctx->state[4] = 0x510E527F; + ctx->state[5] = 0x9B05688C; + ctx->state[6] = 0x1F83D9AB; + ctx->state[7] = 0x5BE0CD19; + } + else + { + /* SHA-224 */ + ctx->state[0] = 0xC1059ED8; + ctx->state[1] = 0x367CD507; + ctx->state[2] = 0x3070DD17; + ctx->state[3] = 0xF70E5939; + ctx->state[4] = 0xFFC00B31; + ctx->state[5] = 0x68581511; + ctx->state[6] = 0x64F98FA7; + ctx->state[7] = 0xBEFA4FA4; + } + + ctx->is224 = is224; +} + +#if !defined(MBEDTLS_SHA256_PROCESS_ALT) +static const uint32_t K[] = +{ + 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5, + 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5, + 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3, + 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174, + 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC, + 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA, + 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7, + 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967, + 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13, + 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85, + 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3, + 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070, + 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5, + 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3, + 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208, + 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2, +}; + +#define SHR(x,n) ((x & 0xFFFFFFFF) >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (32 - n))) + +#define S0(x) (ROTR(x, 7) ^ ROTR(x,18) ^ SHR(x, 3)) +#define S1(x) (ROTR(x,17) ^ ROTR(x,19) ^ SHR(x,10)) + +#define S2(x) (ROTR(x, 2) ^ ROTR(x,13) ^ ROTR(x,22)) +#define S3(x) (ROTR(x, 6) ^ ROTR(x,11) ^ ROTR(x,25)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define R(t) \ +( \ + W[t] = S1(W[t - 2]) + W[t - 7] + \ + S0(W[t - 15]) + W[t - 16] \ +) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + +void mbedtls_sha256_process( mbedtls_sha256_context *ctx, const unsigned char data[64] ) +{ + uint32_t temp1, temp2, W[64]; + uint32_t A[8]; + unsigned int i; + + for( i = 0; i < 8; i++ ) + A[i] = ctx->state[i]; + +#if defined(MBEDTLS_SHA256_SMALLER) + for( i = 0; i < 64; i++ ) + { + if( i < 16 ) + GET_UINT32_BE( W[i], data, 4 * i ); + else + R( i ); + + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i], K[i] ); + + temp1 = A[7]; A[7] = A[6]; A[6] = A[5]; A[5] = A[4]; A[4] = A[3]; + A[3] = A[2]; A[2] = A[1]; A[1] = A[0]; A[0] = temp1; + } +#else /* MBEDTLS_SHA256_SMALLER */ + for( i = 0; i < 16; i++ ) + GET_UINT32_BE( W[i], data, 4 * i ); + + for( i = 0; i < 16; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], W[i+0], K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], W[i+1], K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], W[i+2], K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], W[i+3], K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], W[i+4], K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], W[i+5], K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], W[i+6], K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], W[i+7], K[i+7] ); + } + + for( i = 16; i < 64; i += 8 ) + { + P( A[0], A[1], A[2], A[3], A[4], A[5], A[6], A[7], R(i+0), K[i+0] ); + P( A[7], A[0], A[1], A[2], A[3], A[4], A[5], A[6], R(i+1), K[i+1] ); + P( A[6], A[7], A[0], A[1], A[2], A[3], A[4], A[5], R(i+2), K[i+2] ); + P( A[5], A[6], A[7], A[0], A[1], A[2], A[3], A[4], R(i+3), K[i+3] ); + P( A[4], A[5], A[6], A[7], A[0], A[1], A[2], A[3], R(i+4), K[i+4] ); + P( A[3], A[4], A[5], A[6], A[7], A[0], A[1], A[2], R(i+5), K[i+5] ); + P( A[2], A[3], A[4], A[5], A[6], A[7], A[0], A[1], R(i+6), K[i+6] ); + P( A[1], A[2], A[3], A[4], A[5], A[6], A[7], A[0], R(i+7), K[i+7] ); + } +#endif /* MBEDTLS_SHA256_SMALLER */ + + for( i = 0; i < 8; i++ ) + ctx->state[i] += A[i]; +} +#endif /* !MBEDTLS_SHA256_PROCESS_ALT */ + +/* + * SHA-256 process buffer + */ +void mbedtls_sha256_update( mbedtls_sha256_context *ctx, const unsigned char *input, + size_t ilen ) +{ + size_t fill; + uint32_t left; + + if( ilen == 0 ) + return; + + left = ctx->total[0] & 0x3F; + fill = 64 - left; + + ctx->total[0] += (uint32_t) ilen; + ctx->total[0] &= 0xFFFFFFFF; + + if( ctx->total[0] < (uint32_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha256_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 64 ) + { + mbedtls_sha256_process( ctx, input ); + input += 64; + ilen -= 64; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha256_padding[64] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-256 final digest + */ +void mbedtls_sha256_finish( mbedtls_sha256_context *ctx, unsigned char output[32] ) +{ + uint32_t last, padn; + uint32_t high, low; + unsigned char msglen[8]; + + high = ( ctx->total[0] >> 29 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT32_BE( high, msglen, 0 ); + PUT_UINT32_BE( low, msglen, 4 ); + + last = ctx->total[0] & 0x3F; + padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last ); + + mbedtls_sha256_update( ctx, sha256_padding, padn ); + mbedtls_sha256_update( ctx, msglen, 8 ); + + PUT_UINT32_BE( ctx->state[0], output, 0 ); + PUT_UINT32_BE( ctx->state[1], output, 4 ); + PUT_UINT32_BE( ctx->state[2], output, 8 ); + PUT_UINT32_BE( ctx->state[3], output, 12 ); + PUT_UINT32_BE( ctx->state[4], output, 16 ); + PUT_UINT32_BE( ctx->state[5], output, 20 ); + PUT_UINT32_BE( ctx->state[6], output, 24 ); + + if( ctx->is224 == 0 ) + PUT_UINT32_BE( ctx->state[7], output, 28 ); +} + +#endif /* !MBEDTLS_SHA256_ALT */ + +/* + * output = SHA-256( input buffer ) + */ +void mbedtls_sha256( const unsigned char *input, size_t ilen, + unsigned char output[32], int is224 ) +{ + mbedtls_sha256_context ctx; + + mbedtls_sha256_init( &ctx ); + mbedtls_sha256_starts( &ctx, is224 ); + mbedtls_sha256_update( &ctx, input, ilen ); + mbedtls_sha256_finish( &ctx, output ); + mbedtls_sha256_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha256_test_buf[3][57] = +{ + { "abc" }, + { "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" }, + { "" } +}; + +static const int sha256_test_buflen[3] = +{ + 3, 56, 1000 +}; + +static const unsigned char sha256_test_sum[6][32] = +{ + /* + * SHA-224 test vectors + */ + { 0x23, 0x09, 0x7D, 0x22, 0x34, 0x05, 0xD8, 0x22, + 0x86, 0x42, 0xA4, 0x77, 0xBD, 0xA2, 0x55, 0xB3, + 0x2A, 0xAD, 0xBC, 0xE4, 0xBD, 0xA0, 0xB3, 0xF7, + 0xE3, 0x6C, 0x9D, 0xA7 }, + { 0x75, 0x38, 0x8B, 0x16, 0x51, 0x27, 0x76, 0xCC, + 0x5D, 0xBA, 0x5D, 0xA1, 0xFD, 0x89, 0x01, 0x50, + 0xB0, 0xC6, 0x45, 0x5C, 0xB4, 0xF5, 0x8B, 0x19, + 0x52, 0x52, 0x25, 0x25 }, + { 0x20, 0x79, 0x46, 0x55, 0x98, 0x0C, 0x91, 0xD8, + 0xBB, 0xB4, 0xC1, 0xEA, 0x97, 0x61, 0x8A, 0x4B, + 0xF0, 0x3F, 0x42, 0x58, 0x19, 0x48, 0xB2, 0xEE, + 0x4E, 0xE7, 0xAD, 0x67 }, + + /* + * SHA-256 test vectors + */ + { 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA, + 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23, + 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C, + 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD }, + { 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8, + 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39, + 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67, + 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 }, + { 0xCD, 0xC7, 0x6E, 0x5C, 0x99, 0x14, 0xFB, 0x92, + 0x81, 0xA1, 0xC7, 0xE2, 0x84, 0xD7, 0x3E, 0x67, + 0xF1, 0x80, 0x9A, 0x48, 0xA4, 0x97, 0x20, 0x0E, + 0x04, 0x6D, 0x39, 0xCC, 0xC7, 0x11, 0x2C, 0xD0 } +}; + +/* + * Checkup routine + */ +int mbedtls_sha256_self_test( int verbose ) +{ + int i, j, k, buflen, ret = 0; + unsigned char *buf; + unsigned char sha256sum[32]; + mbedtls_sha256_context ctx; + + buf = mbedtls_calloc( 1024, sizeof(unsigned char) ); + if( NULL == buf ) + { + if( verbose != 0 ) + mbedtls_printf( "Buffer allocation failed\n" ); + + return( 1 ); + } + + mbedtls_sha256_init( &ctx ); + + for( i = 0; i < 6; i++ ) + { + j = i % 3; + k = i < 3; + + if( verbose != 0 ) + mbedtls_printf( " SHA-%d test #%d: ", 256 - k * 32, j + 1 ); + + mbedtls_sha256_starts( &ctx, k ); + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + mbedtls_sha256_update( &ctx, buf, buflen ); + } + else + mbedtls_sha256_update( &ctx, sha256_test_buf[j], + sha256_test_buflen[j] ); + + mbedtls_sha256_finish( &ctx, sha256sum ); + + if( memcmp( sha256sum, sha256_test_sum[i], 32 - k * 4 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_sha256_free( &ctx ); + mbedtls_free( buf ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA256_C */ diff --git a/c++/src/connect/mbedtls/sha512.c b/c++/src/connect/mbedtls/sha512.c new file mode 100644 index 00000000..724522ac --- /dev/null +++ b/c++/src/connect/mbedtls/sha512.c @@ -0,0 +1,514 @@ +/* + * FIPS-180-2 compliant SHA-384/512 implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SHA-512 Secure Hash Standard was published by NIST in 2002. + * + * http://csrc.nist.gov/publications/fips/fips180-2/fips180-2.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SHA512_C) + +#include "mbedtls/sha512.h" + +#if defined(_MSC_VER) || defined(__WATCOMC__) + #define UL64(x) x##ui64 +#else + #define UL64(x) x##ULL +#endif + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_printf printf +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_SHA512_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 64-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT64_BE +#define GET_UINT64_BE(n,b,i) \ +{ \ + (n) = ( (uint64_t) (b)[(i) ] << 56 ) \ + | ( (uint64_t) (b)[(i) + 1] << 48 ) \ + | ( (uint64_t) (b)[(i) + 2] << 40 ) \ + | ( (uint64_t) (b)[(i) + 3] << 32 ) \ + | ( (uint64_t) (b)[(i) + 4] << 24 ) \ + | ( (uint64_t) (b)[(i) + 5] << 16 ) \ + | ( (uint64_t) (b)[(i) + 6] << 8 ) \ + | ( (uint64_t) (b)[(i) + 7] ); \ +} +#endif /* GET_UINT64_BE */ + +#ifndef PUT_UINT64_BE +#define PUT_UINT64_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 56 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 48 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 40 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) >> 32 ); \ + (b)[(i) + 4] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 5] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 6] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 7] = (unsigned char) ( (n) ); \ +} +#endif /* PUT_UINT64_BE */ + +void mbedtls_sha512_init( mbedtls_sha512_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_sha512_context ) ); +} + +void mbedtls_sha512_free( mbedtls_sha512_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_sha512_context ) ); +} + +void mbedtls_sha512_clone( mbedtls_sha512_context *dst, + const mbedtls_sha512_context *src ) +{ + *dst = *src; +} + +/* + * SHA-512 context setup + */ +void mbedtls_sha512_starts( mbedtls_sha512_context *ctx, int is384 ) +{ + ctx->total[0] = 0; + ctx->total[1] = 0; + + if( is384 == 0 ) + { + /* SHA-512 */ + ctx->state[0] = UL64(0x6A09E667F3BCC908); + ctx->state[1] = UL64(0xBB67AE8584CAA73B); + ctx->state[2] = UL64(0x3C6EF372FE94F82B); + ctx->state[3] = UL64(0xA54FF53A5F1D36F1); + ctx->state[4] = UL64(0x510E527FADE682D1); + ctx->state[5] = UL64(0x9B05688C2B3E6C1F); + ctx->state[6] = UL64(0x1F83D9ABFB41BD6B); + ctx->state[7] = UL64(0x5BE0CD19137E2179); + } + else + { + /* SHA-384 */ + ctx->state[0] = UL64(0xCBBB9D5DC1059ED8); + ctx->state[1] = UL64(0x629A292A367CD507); + ctx->state[2] = UL64(0x9159015A3070DD17); + ctx->state[3] = UL64(0x152FECD8F70E5939); + ctx->state[4] = UL64(0x67332667FFC00B31); + ctx->state[5] = UL64(0x8EB44A8768581511); + ctx->state[6] = UL64(0xDB0C2E0D64F98FA7); + ctx->state[7] = UL64(0x47B5481DBEFA4FA4); + } + + ctx->is384 = is384; +} + +#if !defined(MBEDTLS_SHA512_PROCESS_ALT) + +/* + * Round constants + */ +static const uint64_t K[80] = +{ + UL64(0x428A2F98D728AE22), UL64(0x7137449123EF65CD), + UL64(0xB5C0FBCFEC4D3B2F), UL64(0xE9B5DBA58189DBBC), + UL64(0x3956C25BF348B538), UL64(0x59F111F1B605D019), + UL64(0x923F82A4AF194F9B), UL64(0xAB1C5ED5DA6D8118), + UL64(0xD807AA98A3030242), UL64(0x12835B0145706FBE), + UL64(0x243185BE4EE4B28C), UL64(0x550C7DC3D5FFB4E2), + UL64(0x72BE5D74F27B896F), UL64(0x80DEB1FE3B1696B1), + UL64(0x9BDC06A725C71235), UL64(0xC19BF174CF692694), + UL64(0xE49B69C19EF14AD2), UL64(0xEFBE4786384F25E3), + UL64(0x0FC19DC68B8CD5B5), UL64(0x240CA1CC77AC9C65), + UL64(0x2DE92C6F592B0275), UL64(0x4A7484AA6EA6E483), + UL64(0x5CB0A9DCBD41FBD4), UL64(0x76F988DA831153B5), + UL64(0x983E5152EE66DFAB), UL64(0xA831C66D2DB43210), + UL64(0xB00327C898FB213F), UL64(0xBF597FC7BEEF0EE4), + UL64(0xC6E00BF33DA88FC2), UL64(0xD5A79147930AA725), + UL64(0x06CA6351E003826F), UL64(0x142929670A0E6E70), + UL64(0x27B70A8546D22FFC), UL64(0x2E1B21385C26C926), + UL64(0x4D2C6DFC5AC42AED), UL64(0x53380D139D95B3DF), + UL64(0x650A73548BAF63DE), UL64(0x766A0ABB3C77B2A8), + UL64(0x81C2C92E47EDAEE6), UL64(0x92722C851482353B), + UL64(0xA2BFE8A14CF10364), UL64(0xA81A664BBC423001), + UL64(0xC24B8B70D0F89791), UL64(0xC76C51A30654BE30), + UL64(0xD192E819D6EF5218), UL64(0xD69906245565A910), + UL64(0xF40E35855771202A), UL64(0x106AA07032BBD1B8), + UL64(0x19A4C116B8D2D0C8), UL64(0x1E376C085141AB53), + UL64(0x2748774CDF8EEB99), UL64(0x34B0BCB5E19B48A8), + UL64(0x391C0CB3C5C95A63), UL64(0x4ED8AA4AE3418ACB), + UL64(0x5B9CCA4F7763E373), UL64(0x682E6FF3D6B2B8A3), + UL64(0x748F82EE5DEFB2FC), UL64(0x78A5636F43172F60), + UL64(0x84C87814A1F0AB72), UL64(0x8CC702081A6439EC), + UL64(0x90BEFFFA23631E28), UL64(0xA4506CEBDE82BDE9), + UL64(0xBEF9A3F7B2C67915), UL64(0xC67178F2E372532B), + UL64(0xCA273ECEEA26619C), UL64(0xD186B8C721C0C207), + UL64(0xEADA7DD6CDE0EB1E), UL64(0xF57D4F7FEE6ED178), + UL64(0x06F067AA72176FBA), UL64(0x0A637DC5A2C898A6), + UL64(0x113F9804BEF90DAE), UL64(0x1B710B35131C471B), + UL64(0x28DB77F523047D84), UL64(0x32CAAB7B40C72493), + UL64(0x3C9EBE0A15C9BEBC), UL64(0x431D67C49C100D4C), + UL64(0x4CC5D4BECB3E42B6), UL64(0x597F299CFC657E2A), + UL64(0x5FCB6FAB3AD6FAEC), UL64(0x6C44198C4A475817) +}; + +void mbedtls_sha512_process( mbedtls_sha512_context *ctx, const unsigned char data[128] ) +{ + int i; + uint64_t temp1, temp2, W[80]; + uint64_t A, B, C, D, E, F, G, H; + +#define SHR(x,n) (x >> n) +#define ROTR(x,n) (SHR(x,n) | (x << (64 - n))) + +#define S0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ SHR(x, 7)) +#define S1(x) (ROTR(x,19) ^ ROTR(x,61) ^ SHR(x, 6)) + +#define S2(x) (ROTR(x,28) ^ ROTR(x,34) ^ ROTR(x,39)) +#define S3(x) (ROTR(x,14) ^ ROTR(x,18) ^ ROTR(x,41)) + +#define F0(x,y,z) ((x & y) | (z & (x | y))) +#define F1(x,y,z) (z ^ (x & (y ^ z))) + +#define P(a,b,c,d,e,f,g,h,x,K) \ +{ \ + temp1 = h + S3(e) + F1(e,f,g) + K + x; \ + temp2 = S2(a) + F0(a,b,c); \ + d += temp1; h = temp1 + temp2; \ +} + + for( i = 0; i < 16; i++ ) + { + GET_UINT64_BE( W[i], data, i << 3 ); + } + + for( ; i < 80; i++ ) + { + W[i] = S1(W[i - 2]) + W[i - 7] + + S0(W[i - 15]) + W[i - 16]; + } + + A = ctx->state[0]; + B = ctx->state[1]; + C = ctx->state[2]; + D = ctx->state[3]; + E = ctx->state[4]; + F = ctx->state[5]; + G = ctx->state[6]; + H = ctx->state[7]; + i = 0; + + do + { + P( A, B, C, D, E, F, G, H, W[i], K[i] ); i++; + P( H, A, B, C, D, E, F, G, W[i], K[i] ); i++; + P( G, H, A, B, C, D, E, F, W[i], K[i] ); i++; + P( F, G, H, A, B, C, D, E, W[i], K[i] ); i++; + P( E, F, G, H, A, B, C, D, W[i], K[i] ); i++; + P( D, E, F, G, H, A, B, C, W[i], K[i] ); i++; + P( C, D, E, F, G, H, A, B, W[i], K[i] ); i++; + P( B, C, D, E, F, G, H, A, W[i], K[i] ); i++; + } + while( i < 80 ); + + ctx->state[0] += A; + ctx->state[1] += B; + ctx->state[2] += C; + ctx->state[3] += D; + ctx->state[4] += E; + ctx->state[5] += F; + ctx->state[6] += G; + ctx->state[7] += H; +} +#endif /* !MBEDTLS_SHA512_PROCESS_ALT */ + +/* + * SHA-512 process buffer + */ +void mbedtls_sha512_update( mbedtls_sha512_context *ctx, const unsigned char *input, + size_t ilen ) +{ + size_t fill; + unsigned int left; + + if( ilen == 0 ) + return; + + left = (unsigned int) (ctx->total[0] & 0x7F); + fill = 128 - left; + + ctx->total[0] += (uint64_t) ilen; + + if( ctx->total[0] < (uint64_t) ilen ) + ctx->total[1]++; + + if( left && ilen >= fill ) + { + memcpy( (void *) (ctx->buffer + left), input, fill ); + mbedtls_sha512_process( ctx, ctx->buffer ); + input += fill; + ilen -= fill; + left = 0; + } + + while( ilen >= 128 ) + { + mbedtls_sha512_process( ctx, input ); + input += 128; + ilen -= 128; + } + + if( ilen > 0 ) + memcpy( (void *) (ctx->buffer + left), input, ilen ); +} + +static const unsigned char sha512_padding[128] = +{ + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* + * SHA-512 final digest + */ +void mbedtls_sha512_finish( mbedtls_sha512_context *ctx, unsigned char output[64] ) +{ + size_t last, padn; + uint64_t high, low; + unsigned char msglen[16]; + + high = ( ctx->total[0] >> 61 ) + | ( ctx->total[1] << 3 ); + low = ( ctx->total[0] << 3 ); + + PUT_UINT64_BE( high, msglen, 0 ); + PUT_UINT64_BE( low, msglen, 8 ); + + last = (size_t)( ctx->total[0] & 0x7F ); + padn = ( last < 112 ) ? ( 112 - last ) : ( 240 - last ); + + mbedtls_sha512_update( ctx, sha512_padding, padn ); + mbedtls_sha512_update( ctx, msglen, 16 ); + + PUT_UINT64_BE( ctx->state[0], output, 0 ); + PUT_UINT64_BE( ctx->state[1], output, 8 ); + PUT_UINT64_BE( ctx->state[2], output, 16 ); + PUT_UINT64_BE( ctx->state[3], output, 24 ); + PUT_UINT64_BE( ctx->state[4], output, 32 ); + PUT_UINT64_BE( ctx->state[5], output, 40 ); + + if( ctx->is384 == 0 ) + { + PUT_UINT64_BE( ctx->state[6], output, 48 ); + PUT_UINT64_BE( ctx->state[7], output, 56 ); + } +} + +#endif /* !MBEDTLS_SHA512_ALT */ + +/* + * output = SHA-512( input buffer ) + */ +void mbedtls_sha512( const unsigned char *input, size_t ilen, + unsigned char output[64], int is384 ) +{ + mbedtls_sha512_context ctx; + + mbedtls_sha512_init( &ctx ); + mbedtls_sha512_starts( &ctx, is384 ); + mbedtls_sha512_update( &ctx, input, ilen ); + mbedtls_sha512_finish( &ctx, output ); + mbedtls_sha512_free( &ctx ); +} + +#if defined(MBEDTLS_SELF_TEST) + +/* + * FIPS-180-2 test vectors + */ +static const unsigned char sha512_test_buf[3][113] = +{ + { "abc" }, + { "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" }, + { "" } +}; + +static const int sha512_test_buflen[3] = +{ + 3, 112, 1000 +}; + +static const unsigned char sha512_test_sum[6][64] = +{ + /* + * SHA-384 test vectors + */ + { 0xCB, 0x00, 0x75, 0x3F, 0x45, 0xA3, 0x5E, 0x8B, + 0xB5, 0xA0, 0x3D, 0x69, 0x9A, 0xC6, 0x50, 0x07, + 0x27, 0x2C, 0x32, 0xAB, 0x0E, 0xDE, 0xD1, 0x63, + 0x1A, 0x8B, 0x60, 0x5A, 0x43, 0xFF, 0x5B, 0xED, + 0x80, 0x86, 0x07, 0x2B, 0xA1, 0xE7, 0xCC, 0x23, + 0x58, 0xBA, 0xEC, 0xA1, 0x34, 0xC8, 0x25, 0xA7 }, + { 0x09, 0x33, 0x0C, 0x33, 0xF7, 0x11, 0x47, 0xE8, + 0x3D, 0x19, 0x2F, 0xC7, 0x82, 0xCD, 0x1B, 0x47, + 0x53, 0x11, 0x1B, 0x17, 0x3B, 0x3B, 0x05, 0xD2, + 0x2F, 0xA0, 0x80, 0x86, 0xE3, 0xB0, 0xF7, 0x12, + 0xFC, 0xC7, 0xC7, 0x1A, 0x55, 0x7E, 0x2D, 0xB9, + 0x66, 0xC3, 0xE9, 0xFA, 0x91, 0x74, 0x60, 0x39 }, + { 0x9D, 0x0E, 0x18, 0x09, 0x71, 0x64, 0x74, 0xCB, + 0x08, 0x6E, 0x83, 0x4E, 0x31, 0x0A, 0x4A, 0x1C, + 0xED, 0x14, 0x9E, 0x9C, 0x00, 0xF2, 0x48, 0x52, + 0x79, 0x72, 0xCE, 0xC5, 0x70, 0x4C, 0x2A, 0x5B, + 0x07, 0xB8, 0xB3, 0xDC, 0x38, 0xEC, 0xC4, 0xEB, + 0xAE, 0x97, 0xDD, 0xD8, 0x7F, 0x3D, 0x89, 0x85 }, + + /* + * SHA-512 test vectors + */ + { 0xDD, 0xAF, 0x35, 0xA1, 0x93, 0x61, 0x7A, 0xBA, + 0xCC, 0x41, 0x73, 0x49, 0xAE, 0x20, 0x41, 0x31, + 0x12, 0xE6, 0xFA, 0x4E, 0x89, 0xA9, 0x7E, 0xA2, + 0x0A, 0x9E, 0xEE, 0xE6, 0x4B, 0x55, 0xD3, 0x9A, + 0x21, 0x92, 0x99, 0x2A, 0x27, 0x4F, 0xC1, 0xA8, + 0x36, 0xBA, 0x3C, 0x23, 0xA3, 0xFE, 0xEB, 0xBD, + 0x45, 0x4D, 0x44, 0x23, 0x64, 0x3C, 0xE8, 0x0E, + 0x2A, 0x9A, 0xC9, 0x4F, 0xA5, 0x4C, 0xA4, 0x9F }, + { 0x8E, 0x95, 0x9B, 0x75, 0xDA, 0xE3, 0x13, 0xDA, + 0x8C, 0xF4, 0xF7, 0x28, 0x14, 0xFC, 0x14, 0x3F, + 0x8F, 0x77, 0x79, 0xC6, 0xEB, 0x9F, 0x7F, 0xA1, + 0x72, 0x99, 0xAE, 0xAD, 0xB6, 0x88, 0x90, 0x18, + 0x50, 0x1D, 0x28, 0x9E, 0x49, 0x00, 0xF7, 0xE4, + 0x33, 0x1B, 0x99, 0xDE, 0xC4, 0xB5, 0x43, 0x3A, + 0xC7, 0xD3, 0x29, 0xEE, 0xB6, 0xDD, 0x26, 0x54, + 0x5E, 0x96, 0xE5, 0x5B, 0x87, 0x4B, 0xE9, 0x09 }, + { 0xE7, 0x18, 0x48, 0x3D, 0x0C, 0xE7, 0x69, 0x64, + 0x4E, 0x2E, 0x42, 0xC7, 0xBC, 0x15, 0xB4, 0x63, + 0x8E, 0x1F, 0x98, 0xB1, 0x3B, 0x20, 0x44, 0x28, + 0x56, 0x32, 0xA8, 0x03, 0xAF, 0xA9, 0x73, 0xEB, + 0xDE, 0x0F, 0xF2, 0x44, 0x87, 0x7E, 0xA6, 0x0A, + 0x4C, 0xB0, 0x43, 0x2C, 0xE5, 0x77, 0xC3, 0x1B, + 0xEB, 0x00, 0x9C, 0x5C, 0x2C, 0x49, 0xAA, 0x2E, + 0x4E, 0xAD, 0xB2, 0x17, 0xAD, 0x8C, 0xC0, 0x9B } +}; + +/* + * Checkup routine + */ +int mbedtls_sha512_self_test( int verbose ) +{ + int i, j, k, buflen, ret = 0; + unsigned char *buf; + unsigned char sha512sum[64]; + mbedtls_sha512_context ctx; + + buf = mbedtls_calloc( 1024, sizeof(unsigned char) ); + if( NULL == buf ) + { + if( verbose != 0 ) + mbedtls_printf( "Buffer allocation failed\n" ); + + return( 1 ); + } + + mbedtls_sha512_init( &ctx ); + + for( i = 0; i < 6; i++ ) + { + j = i % 3; + k = i < 3; + + if( verbose != 0 ) + mbedtls_printf( " SHA-%d test #%d: ", 512 - k * 128, j + 1 ); + + mbedtls_sha512_starts( &ctx, k ); + + if( j == 2 ) + { + memset( buf, 'a', buflen = 1000 ); + + for( j = 0; j < 1000; j++ ) + mbedtls_sha512_update( &ctx, buf, buflen ); + } + else + mbedtls_sha512_update( &ctx, sha512_test_buf[j], + sha512_test_buflen[j] ); + + mbedtls_sha512_finish( &ctx, sha512sum ); + + if( memcmp( sha512sum, sha512_test_sum[i], 64 - k * 16 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_sha512_free( &ctx ); + mbedtls_free( buf ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_SHA512_C */ diff --git a/c++/src/connect/mbedtls/ssl_cache.c b/c++/src/connect/mbedtls/ssl_cache.c new file mode 100644 index 00000000..9b62de2d --- /dev/null +++ b/c++/src/connect/mbedtls/ssl_cache.c @@ -0,0 +1,326 @@ +/* + * SSL session cache implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * These session callbacks use a simple chained list + * to store and retrieve the session information. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_CACHE_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/ssl_cache.h" + +#include + +void mbedtls_ssl_cache_init( mbedtls_ssl_cache_context *cache ) +{ + memset( cache, 0, sizeof( mbedtls_ssl_cache_context ) ); + + cache->timeout = MBEDTLS_SSL_CACHE_DEFAULT_TIMEOUT; + cache->max_entries = MBEDTLS_SSL_CACHE_DEFAULT_MAX_ENTRIES; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &cache->mutex ); +#endif +} + +int mbedtls_ssl_cache_get( void *data, mbedtls_ssl_session *session ) +{ + int ret = 1; +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t t = mbedtls_time( NULL ); +#endif + mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data; + mbedtls_ssl_cache_entry *cur, *entry; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &cache->mutex ) != 0 ) + return( 1 ); +#endif + + cur = cache->chain; + entry = NULL; + + while( cur != NULL ) + { + entry = cur; + cur = cur->next; + +#if defined(MBEDTLS_HAVE_TIME) + if( cache->timeout != 0 && + (int) ( t - entry->timestamp ) > cache->timeout ) + continue; +#endif + + if( session->ciphersuite != entry->session.ciphersuite || + session->compression != entry->session.compression || + session->id_len != entry->session.id_len ) + continue; + + if( memcmp( session->id, entry->session.id, + entry->session.id_len ) != 0 ) + continue; + + memcpy( session->master, entry->session.master, 48 ); + + session->verify_result = entry->session.verify_result; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /* + * Restore peer certificate (without rest of the original chain) + */ + if( entry->peer_cert.p != NULL ) + { + if( ( session->peer_cert = mbedtls_calloc( 1, + sizeof(mbedtls_x509_crt) ) ) == NULL ) + { + ret = 1; + goto exit; + } + + mbedtls_x509_crt_init( session->peer_cert ); + if( mbedtls_x509_crt_parse( session->peer_cert, entry->peer_cert.p, + entry->peer_cert.len ) != 0 ) + { + mbedtls_free( session->peer_cert ); + session->peer_cert = NULL; + ret = 1; + goto exit; + } + } +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + ret = 0; + goto exit; + } + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &cache->mutex ) != 0 ) + ret = 1; +#endif + + return( ret ); +} + +int mbedtls_ssl_cache_set( void *data, const mbedtls_ssl_session *session ) +{ + int ret = 1; +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t t = time( NULL ), oldest = 0; + mbedtls_ssl_cache_entry *old = NULL; +#endif + mbedtls_ssl_cache_context *cache = (mbedtls_ssl_cache_context *) data; + mbedtls_ssl_cache_entry *cur, *prv; + int count = 0; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &cache->mutex ) ) != 0 ) + return( ret ); +#endif + + cur = cache->chain; + prv = NULL; + + while( cur != NULL ) + { + count++; + +#if defined(MBEDTLS_HAVE_TIME) + if( cache->timeout != 0 && + (int) ( t - cur->timestamp ) > cache->timeout ) + { + cur->timestamp = t; + break; /* expired, reuse this slot, update timestamp */ + } +#endif + + if( memcmp( session->id, cur->session.id, cur->session.id_len ) == 0 ) + break; /* client reconnected, keep timestamp for session id */ + +#if defined(MBEDTLS_HAVE_TIME) + if( oldest == 0 || cur->timestamp < oldest ) + { + oldest = cur->timestamp; + old = cur; + } +#endif + + prv = cur; + cur = cur->next; + } + + if( cur == NULL ) + { +#if defined(MBEDTLS_HAVE_TIME) + /* + * Reuse oldest entry if max_entries reached + */ + if( count >= cache->max_entries ) + { + if( old == NULL ) + { + ret = 1; + goto exit; + } + + cur = old; + } +#else /* MBEDTLS_HAVE_TIME */ + /* + * Reuse first entry in chain if max_entries reached, + * but move to last place + */ + if( count >= cache->max_entries ) + { + if( cache->chain == NULL ) + { + ret = 1; + goto exit; + } + + cur = cache->chain; + cache->chain = cur->next; + cur->next = NULL; + prv->next = cur; + } +#endif /* MBEDTLS_HAVE_TIME */ + else + { + /* + * max_entries not reached, create new entry + */ + cur = mbedtls_calloc( 1, sizeof(mbedtls_ssl_cache_entry) ); + if( cur == NULL ) + { + ret = 1; + goto exit; + } + + if( prv == NULL ) + cache->chain = cur; + else + prv->next = cur; + } + +#if defined(MBEDTLS_HAVE_TIME) + cur->timestamp = t; +#endif + } + + memcpy( &cur->session, session, sizeof( mbedtls_ssl_session ) ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /* + * If we're reusing an entry, free its certificate first + */ + if( cur->peer_cert.p != NULL ) + { + mbedtls_free( cur->peer_cert.p ); + memset( &cur->peer_cert, 0, sizeof(mbedtls_x509_buf) ); + } + + /* + * Store peer certificate + */ + if( session->peer_cert != NULL ) + { + cur->peer_cert.p = mbedtls_calloc( 1, session->peer_cert->raw.len ); + if( cur->peer_cert.p == NULL ) + { + ret = 1; + goto exit; + } + + memcpy( cur->peer_cert.p, session->peer_cert->raw.p, + session->peer_cert->raw.len ); + cur->peer_cert.len = session->peer_cert->raw.len; + + cur->session.peer_cert = NULL; + } +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + ret = 0; + +exit: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &cache->mutex ) != 0 ) + ret = 1; +#endif + + return( ret ); +} + +#if defined(MBEDTLS_HAVE_TIME) +void mbedtls_ssl_cache_set_timeout( mbedtls_ssl_cache_context *cache, int timeout ) +{ + if( timeout < 0 ) timeout = 0; + + cache->timeout = timeout; +} +#endif /* MBEDTLS_HAVE_TIME */ + +void mbedtls_ssl_cache_set_max_entries( mbedtls_ssl_cache_context *cache, int max ) +{ + if( max < 0 ) max = 0; + + cache->max_entries = max; +} + +void mbedtls_ssl_cache_free( mbedtls_ssl_cache_context *cache ) +{ + mbedtls_ssl_cache_entry *cur, *prv; + + cur = cache->chain; + + while( cur != NULL ) + { + prv = cur; + cur = cur->next; + + mbedtls_ssl_session_free( &prv->session ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + mbedtls_free( prv->peer_cert.p ); +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + mbedtls_free( prv ); + } + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &cache->mutex ); +#endif +} + +#endif /* MBEDTLS_SSL_CACHE_C */ diff --git a/c++/src/connect/mbedtls/ssl_ciphersuites.c b/c++/src/connect/mbedtls/ssl_ciphersuites.c new file mode 100644 index 00000000..a762bf7c --- /dev/null +++ b/c++/src/connect/mbedtls/ssl_ciphersuites.c @@ -0,0 +1,1857 @@ +/** + * \file ssl_ciphersuites.c + * + * \brief SSL ciphersuites for mbed TLS + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_TLS_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#endif + +#include "mbedtls/ssl_ciphersuites.h" +#include "mbedtls/ssl.h" + +#include + +/* + * Ordered from most preferred to least preferred in terms of security. + * + * Current rule (except rc4, weak and null which come last): + * 1. By key exchange: + * Forward-secure non-PSK > forward-secure PSK > ECJPAKE > other non-PSK > other PSK + * 2. By key length and cipher: + * AES-256 > Camellia-256 > AES-128 > Camellia-128 > 3DES + * 3. By cipher mode when relevant GCM > CCM > CBC > CCM_8 + * 4. By hash function used when relevant + * 5. By key exchange/auth again: EC > non-EC + */ +static const int ciphersuite_preference[] = +{ +#if defined(MBEDTLS_SSL_CIPHERSUITES) + MBEDTLS_SSL_CIPHERSUITES, +#else + /* All AES-256 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, + MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8, + + /* All CAMELLIA-256 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, + + /* All AES-128 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, + MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8, + + /* All CAMELLIA-128 ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, + + /* All remaining >= 128-bit ephemeral suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, + + /* The PSK ephemeral suites */ + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8, + + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8, + + MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, + + /* The ECJPAKE suite */ + MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8, + + /* All AES-256 suites */ + MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_RSA_WITH_AES_256_CCM, + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8, + + /* All CAMELLIA-256 suites */ + MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, + + /* All AES-128 suites */ + MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_128_CCM, + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8, + + /* All CAMELLIA-128 suites */ + MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, + + /* All remaining >= 128-bit suites */ + MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + + /* The RSA PSK suites */ + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384, + + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256, + + MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, + + /* The PSK suites */ + MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_256_CCM, + MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384, + MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, + + MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_128_CCM, + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256, + MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256, + MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, + + MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA, + + /* RC4 suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA, + MBEDTLS_TLS_RSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_RSA_WITH_RC4_128_MD5, + MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA, + MBEDTLS_TLS_PSK_WITH_RC4_128_SHA, + + /* Weak suites */ + MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA, + MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA, + + /* NULL suites */ + MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA, + + MBEDTLS_TLS_RSA_WITH_NULL_SHA256, + MBEDTLS_TLS_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_RSA_WITH_NULL_MD5, + MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA, + MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA, + MBEDTLS_TLS_PSK_WITH_NULL_SHA384, + MBEDTLS_TLS_PSK_WITH_NULL_SHA256, + MBEDTLS_TLS_PSK_WITH_NULL_SHA, + +#endif /* MBEDTLS_SSL_CIPHERSUITES */ + 0 +}; + +static const mbedtls_ssl_ciphersuite_t ciphersuite_definitions[] = +{ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM, "TLS-ECDHE-ECDSA-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8, "TLS-ECDHE-ECDSA-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM, "TLS-ECDHE-ECDSA-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, "TLS-ECDHE-ECDSA-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDHE-ECDSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS-ECDHE-ECDSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_ECDSA_WITH_NULL_SHA, "TLS-ECDHE-ECDSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDHE-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDHE-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_RC4_128_SHA, "TLS-ECDHE-RSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_RSA_WITH_NULL_SHA, "TLS-ECDHE-RSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C && MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CBC_SHA, "TLS-DHE-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CBC_SHA, "TLS-DHE-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM, "TLS-DHE-RSA-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_RSA_WITH_AES_256_CCM_8, "TLS-DHE-RSA-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM, "TLS-DHE-RSA-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_RSA_WITH_AES_128_CCM_8, "TLS-DHE-RSA-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA, "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA, "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-DHE-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-DHE-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA512_C) && defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C && MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256, "TLS-RSA-WITH-AES-256-CBC-SHA256", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_RSA_WITH_AES_128_CBC_SHA, "TLS-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA, "TLS-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_RSA_WITH_AES_256_CCM, "TLS-RSA-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_RSA_WITH_AES_256_CCM_8, "TLS-RSA-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_RSA_WITH_AES_128_CCM, "TLS-RSA-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_RSA_WITH_AES_128_CCM_8, "TLS-RSA-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_CBC_SHA, "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_CBC_SHA, "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_MD5_C) + { MBEDTLS_TLS_RSA_WITH_RC4_128_MD5, "TLS-RSA-WITH-RC4-128-MD5", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_MD5, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_RC4_128_SHA, "TLS-RSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256, "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256, "TLS-ECDH-RSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384, "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384, "TLS-ECDH-RSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDH-RSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDH-RSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDH-RSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDH-RSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDH-RSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_RC4_128_SHA, "TLS-ECDH-RSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_RSA_WITH_NULL_SHA, "TLS-ECDH-RSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_SHA1_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256, "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256, "TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384, "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_GCM_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384, "TLS-ECDH-ECDSA-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256, "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384, "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, "TLS-ECDH-ECDSA-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_RC4_128_SHA, "TLS-ECDH-ECDSA-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ + +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDH_ECDSA_WITH_NULL_SHA, "TLS-ECDH-ECDSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_AES_128_GCM_SHA256, "TLS-PSK-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_AES_256_GCM_SHA384, "TLS-PSK-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA256, "TLS-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA384, "TLS-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_AES_128_CBC_SHA, "TLS-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_PSK_WITH_AES_256_CBC_SHA, "TLS-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_PSK_WITH_AES_256_CCM, "TLS-PSK-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_PSK_WITH_AES_256_CCM_8, "TLS-PSK-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_PSK_WITH_AES_128_CCM, "TLS-PSK-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8, "TLS-PSK-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256, "TLS-PSK-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384, "TLS-PSK-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_RC4_128_SHA, "TLS-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_GCM_SHA256, "TLS-DHE-PSK-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_GCM_SHA384, "TLS-DHE-PSK-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, "TLS-DHE-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, "TLS-DHE-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CBC_SHA, "TLS-DHE-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CBC_SHA, "TLS-DHE-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM, "TLS-DHE-PSK-WITH-AES-256-CCM", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_PSK_WITH_AES_256_CCM_8, "TLS-DHE-PSK-WITH-AES-256-CCM-8", + MBEDTLS_CIPHER_AES_256_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM, "TLS-DHE-PSK-WITH-AES-128-CCM", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + { MBEDTLS_TLS_DHE_PSK_WITH_AES_128_CCM_8, "TLS-DHE-PSK-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-DHE-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-DHE-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256, "TLS-DHE-PSK-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384, "TLS-DHE-PSK-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-DHE-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_RC4_128_SHA, "TLS-DHE-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, "TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, "TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, "TLS-ECDHE-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA, "TLS-ECDHE-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-ECDHE-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-ECDHE-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-ECDHE-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_RC4_128_SHA, "TLS-ECDHE-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_128_GCM_SHA256, "TLS-RSA-PSK-WITH-AES-128-GCM-SHA256", + MBEDTLS_CIPHER_AES_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_256_GCM_SHA384, "TLS-RSA-PSK-WITH-AES-256-GCM-SHA384", + MBEDTLS_CIPHER_AES_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA256, "TLS-RSA-PSK-WITH-AES-128-CBC-SHA256", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, "TLS-RSA-PSK-WITH-AES-256-CBC-SHA384", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_AES_128_CBC_SHA, "TLS-RSA-PSK-WITH-AES-128-CBC-SHA", + MBEDTLS_CIPHER_AES_128_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, + + { MBEDTLS_TLS_RSA_PSK_WITH_AES_256_CBC_SHA, "TLS-RSA-PSK-WITH-AES-256-CBC-SHA", + MBEDTLS_CIPHER_AES_256_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_AES_C */ + +#if defined(MBEDTLS_CAMELLIA_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256, "TLS-RSA-PSK-WITH-CAMELLIA-128-CBC-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_CBC, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384, "TLS-RSA-PSK-WITH-CAMELLIA-256-CBC-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_CBC, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + +#if defined(MBEDTLS_GCM_C) +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256, "TLS-RSA-PSK-WITH-CAMELLIA-128-GCM-SHA256", + MBEDTLS_CIPHER_CAMELLIA_128_GCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384, "TLS-RSA-PSK-WITH-CAMELLIA-256-GCM-SHA384", + MBEDTLS_CIPHER_CAMELLIA_256_GCM, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_GCM_C */ +#endif /* MBEDTLS_CAMELLIA_C */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA, "TLS-RSA-PSK-WITH-3DES-EDE-CBC-SHA", + MBEDTLS_CIPHER_DES_EDE3_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + 0 }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ + +#if defined(MBEDTLS_ARC4_C) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_RC4_128_SHA, "TLS-RSA-PSK-WITH-RC4-128-SHA", + MBEDTLS_CIPHER_ARC4_128, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_NODTLS }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_ARC4_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +#if defined(MBEDTLS_AES_C) +#if defined(MBEDTLS_CCM_C) + { MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8, "TLS-ECJPAKE-WITH-AES-128-CCM-8", + MBEDTLS_CIPHER_AES_128_CCM, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECJPAKE, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_SHORT_TAG }, +#endif /* MBEDTLS_CCM_C */ +#endif /* MBEDTLS_AES_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_ENABLE_WEAK_CIPHERSUITES) +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) +#if defined(MBEDTLS_MD5_C) + { MBEDTLS_TLS_RSA_WITH_NULL_MD5, "TLS-RSA-WITH-NULL-MD5", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_MD5, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_NULL_SHA, "TLS-RSA-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_WITH_NULL_SHA256, "TLS-RSA-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_PSK_WITH_NULL_SHA, "TLS-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_PSK_WITH_NULL_SHA256, "TLS-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_PSK_WITH_NULL_SHA384, "TLS-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA, "TLS-DHE-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA256, "TLS-DHE-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_DHE_PSK_WITH_NULL_SHA384, "TLS-DHE-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_DHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA, "TLS-ECDHE-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA256, "TLS-ECDHE-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_ECDHE_PSK_WITH_NULL_SHA384, "TLS-ECDHE-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_ECDHE_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA, "TLS-RSA-PSK-WITH-NULL-SHA", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ + +#if defined(MBEDTLS_SHA256_C) + { MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA256, "TLS-RSA-PSK-WITH-NULL-SHA256", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA256, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif + +#if defined(MBEDTLS_SHA512_C) + { MBEDTLS_TLS_RSA_PSK_WITH_NULL_SHA384, "TLS-RSA-PSK-WITH-NULL-SHA384", + MBEDTLS_CIPHER_NULL, MBEDTLS_MD_SHA384, MBEDTLS_KEY_EXCHANGE_RSA_PSK, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_1, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ + +#if defined(MBEDTLS_DES_C) +#if defined(MBEDTLS_CIPHER_MODE_CBC) +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_DHE_RSA_WITH_DES_CBC_SHA, "TLS-DHE-RSA-WITH-DES-CBC-SHA", + MBEDTLS_CIPHER_DES_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_DHE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) +#if defined(MBEDTLS_SHA1_C) + { MBEDTLS_TLS_RSA_WITH_DES_CBC_SHA, "TLS-RSA-WITH-DES-CBC-SHA", + MBEDTLS_CIPHER_DES_CBC, MBEDTLS_MD_SHA1, MBEDTLS_KEY_EXCHANGE_RSA, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0, + MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3, + MBEDTLS_CIPHERSUITE_WEAK }, +#endif /* MBEDTLS_SHA1_C */ +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* MBEDTLS_DES_C */ +#endif /* MBEDTLS_ENABLE_WEAK_CIPHERSUITES */ + + { 0, "", + MBEDTLS_CIPHER_NONE, MBEDTLS_MD_NONE, MBEDTLS_KEY_EXCHANGE_NONE, + 0, 0, 0, 0, 0 } +}; + +#if defined(MBEDTLS_SSL_CIPHERSUITES) +const int *mbedtls_ssl_list_ciphersuites( void ) +{ + return( ciphersuite_preference ); +} +#else +#define MAX_CIPHERSUITES sizeof( ciphersuite_definitions ) / \ + sizeof( ciphersuite_definitions[0] ) +static int supported_ciphersuites[MAX_CIPHERSUITES]; +static int supported_init = 0; + +const int *mbedtls_ssl_list_ciphersuites( void ) +{ + /* + * On initial call filter out all ciphersuites not supported by current + * build based on presence in the ciphersuite_definitions. + */ + if( supported_init == 0 ) + { + const int *p; + int *q; + + for( p = ciphersuite_preference, q = supported_ciphersuites; + *p != 0 && q < supported_ciphersuites + MAX_CIPHERSUITES - 1; + p++ ) + { +#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES) + const mbedtls_ssl_ciphersuite_t *cs_info; + if( ( cs_info = mbedtls_ssl_ciphersuite_from_id( *p ) ) != NULL && + cs_info->cipher != MBEDTLS_CIPHER_ARC4_128 ) +#else + if( mbedtls_ssl_ciphersuite_from_id( *p ) != NULL ) +#endif + *(q++) = *p; + } + *q = 0; + + supported_init = 1; + } + + return( supported_ciphersuites ); +} +#endif /* MBEDTLS_SSL_CIPHERSUITES */ + +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_string( + const char *ciphersuite_name ) +{ + const mbedtls_ssl_ciphersuite_t *cur = ciphersuite_definitions; + + if( NULL == ciphersuite_name ) + return( NULL ); + + while( cur->id != 0 ) + { + if( 0 == strcmp( cur->name, ciphersuite_name ) ) + return( cur ); + + cur++; + } + + return( NULL ); +} + +const mbedtls_ssl_ciphersuite_t *mbedtls_ssl_ciphersuite_from_id( int ciphersuite ) +{ + const mbedtls_ssl_ciphersuite_t *cur = ciphersuite_definitions; + + while( cur->id != 0 ) + { + if( cur->id == ciphersuite ) + return( cur ); + + cur++; + } + + return( NULL ); +} + +const char *mbedtls_ssl_get_ciphersuite_name( const int ciphersuite_id ) +{ + const mbedtls_ssl_ciphersuite_t *cur; + + cur = mbedtls_ssl_ciphersuite_from_id( ciphersuite_id ); + + if( cur == NULL ) + return( "unknown" ); + + return( cur->name ); +} + +int mbedtls_ssl_get_ciphersuite_id( const char *ciphersuite_name ) +{ + const mbedtls_ssl_ciphersuite_t *cur; + + cur = mbedtls_ssl_ciphersuite_from_string( ciphersuite_name ); + + if( cur == NULL ) + return( 0 ); + + return( cur->id ); +} + +#if defined(MBEDTLS_PK_C) +mbedtls_pk_type_t mbedtls_ssl_get_ciphersuite_sig_pk_alg( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_RSA: + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_RSA_PSK: + return( MBEDTLS_PK_RSA ); + + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + return( MBEDTLS_PK_ECDSA ); + + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + return( MBEDTLS_PK_ECKEY ); + + default: + return( MBEDTLS_PK_NONE ); + } +} +#endif /* MBEDTLS_PK_C */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) +int mbedtls_ssl_ciphersuite_uses_ec( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +int mbedtls_ssl_ciphersuite_uses_psk( const mbedtls_ssl_ciphersuite_t *info ) +{ + switch( info->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_PSK: + case MBEDTLS_KEY_EXCHANGE_RSA_PSK: + case MBEDTLS_KEY_EXCHANGE_DHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: + return( 1 ); + + default: + return( 0 ); + } +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#endif /* MBEDTLS_SSL_TLS_C */ diff --git a/c++/src/connect/mbedtls/ssl_cli.c b/c++/src/connect/mbedtls/ssl_cli.c new file mode 100644 index 00000000..223823b3 --- /dev/null +++ b/c++/src/connect/mbedtls/ssl_cli.c @@ -0,0 +1,3405 @@ +/* + * SSLv3/TLSv1 client-side functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_CLI_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" + +#include + +#include + +#if defined(MBEDTLS_HAVE_TIME) +#include "mbedtls/platform_time.h" +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} +#endif + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static void ssl_write_hostname_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t hostname_len; + + *olen = 0; + + if( ssl->hostname == NULL ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding server name extension: %s", + ssl->hostname ) ); + + hostname_len = strlen( ssl->hostname ); + + if( end < p || (size_t)( end - p ) < hostname_len + 9 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* + * struct { + * NameType name_type; + * select (name_type) { + * case host_name: HostName; + * } name; + * } ServerName; + * + * enum { + * host_name(0), (255) + * } NameType; + * + * opaque HostName<1..2^16-1>; + * + * struct { + * ServerName server_name_list<1..2^16-1> + * } ServerNameList; + */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME ) & 0xFF ); + + *p++ = (unsigned char)( ( (hostname_len + 5) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( (hostname_len + 5) ) & 0xFF ); + + *p++ = (unsigned char)( ( (hostname_len + 3) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( (hostname_len + 3) ) & 0xFF ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME ) & 0xFF ); + *p++ = (unsigned char)( ( hostname_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( hostname_len ) & 0xFF ); + + memcpy( p, ssl->hostname, hostname_len ); + + *olen = hostname_len + 9; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +static void ssl_write_renegotiation_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + if( ssl->renego_status != MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding renegotiation extension" ) ); + + if( end < p || (size_t)( end - p ) < 5 + ssl->verify_data_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* + * Secure renegotiation + */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO ) & 0xFF ); + + *p++ = 0x00; + *p++ = ( ssl->verify_data_len + 1 ) & 0xFF; + *p++ = ssl->verify_data_len & 0xFF; + + memcpy( p, ssl->own_verify_data, ssl->verify_data_len ); + + *olen = 5 + ssl->verify_data_len; +} +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/* + * Only if we handle at least one key exchange that needs signatures. + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +static void ssl_write_signature_algorithms_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t sig_alg_len = 0; + const int *md; +#if defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECDSA_C) + unsigned char *sig_alg_list = buf + 6; +#endif + + *olen = 0; + + if( ssl->conf->max_minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding signature_algorithms extension" ) ); + + for( md = ssl->conf->sig_hashes; *md != MBEDTLS_MD_NONE; md++ ) + { +#if defined(MBEDTLS_ECDSA_C) + sig_alg_len += 2; +#endif +#if defined(MBEDTLS_RSA_C) + sig_alg_len += 2; +#endif + } + + if( end < p || (size_t)( end - p ) < sig_alg_len + 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + /* + * Prepare signature_algorithms extension (TLS 1.2) + */ + sig_alg_len = 0; + + for( md = ssl->conf->sig_hashes; *md != MBEDTLS_MD_NONE; md++ ) + { +#if defined(MBEDTLS_ECDSA_C) + sig_alg_list[sig_alg_len++] = mbedtls_ssl_hash_from_md_alg( *md ); + sig_alg_list[sig_alg_len++] = MBEDTLS_SSL_SIG_ECDSA; +#endif +#if defined(MBEDTLS_RSA_C) + sig_alg_list[sig_alg_len++] = mbedtls_ssl_hash_from_md_alg( *md ); + sig_alg_list[sig_alg_len++] = MBEDTLS_SSL_SIG_RSA; +#endif + } + + /* + * enum { + * none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), + * sha512(6), (255) + * } HashAlgorithm; + * + * enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } + * SignatureAlgorithm; + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + * + * SignatureAndHashAlgorithm + * supported_signature_algorithms<2..2^16-2>; + */ + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SIG_ALG >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SIG_ALG ) & 0xFF ); + + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( sig_alg_len + 2 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( sig_alg_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( sig_alg_len ) & 0xFF ); + + *olen = 6 + sig_alg_len; +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_supported_elliptic_curves_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + unsigned char *elliptic_curve_list = p + 6; + size_t elliptic_curve_len = 0; + const mbedtls_ecp_curve_info *info; +#if defined(MBEDTLS_ECP_C) + const mbedtls_ecp_group_id *grp_id; +#else + ((void) ssl); +#endif + + *olen = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding supported_elliptic_curves extension" ) ); + +#if defined(MBEDTLS_ECP_C) + for( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) + { + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); +#else + for( info = mbedtls_ecp_curve_list(); info->grp_id != MBEDTLS_ECP_DP_NONE; info++ ) + { +#endif + if( info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid curve in ssl configuration" ) ); + return; + } + + elliptic_curve_len += 2; + } + + if( end < p || (size_t)( end - p ) < 6 + elliptic_curve_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + elliptic_curve_len = 0; + +#if defined(MBEDTLS_ECP_C) + for( grp_id = ssl->conf->curve_list; *grp_id != MBEDTLS_ECP_DP_NONE; grp_id++ ) + { + info = mbedtls_ecp_curve_info_from_grp_id( *grp_id ); +#else + for( info = mbedtls_ecp_curve_list(); info->grp_id != MBEDTLS_ECP_DP_NONE; info++ ) + { +#endif + elliptic_curve_list[elliptic_curve_len++] = info->tls_id >> 8; + elliptic_curve_list[elliptic_curve_len++] = info->tls_id & 0xFF; + } + + if( elliptic_curve_len == 0 ) + return; + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES ) & 0xFF ); + + *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( elliptic_curve_len + 2 ) ) & 0xFF ); + + *p++ = (unsigned char)( ( ( elliptic_curve_len ) >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ( elliptic_curve_len ) ) & 0xFF ); + + *olen = 6 + elliptic_curve_len; +} + +static void ssl_write_supported_point_formats_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding supported_point_formats extension" ) ); + + if( end < p || (size_t)( end - p ) < 6 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS ) & 0xFF ); + + *p++ = 0x00; + *p++ = 2; + + *p++ = 1; + *p++ = MBEDTLS_ECP_PF_UNCOMPRESSED; + + *olen = 6; +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_ecjpake_kkpp_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + int ret; + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t kkpp_len; + + *olen = 0; + + /* Skip costly extension if we can't use EC J-PAKE anyway */ + if( mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding ecjpake_kkpp extension" ) ); + + if( end - p < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP ) & 0xFF ); + + /* + * We may need to send ClientHello multiple times for Hello verification. + * We don't want to compute fresh values every time (both for performance + * and consistency reasons), so cache the extension content. + */ + if( ssl->handshake->ecjpake_cache == NULL || + ssl->handshake->ecjpake_cache_len == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "generating new ecjpake parameters" ) ); + + ret = mbedtls_ecjpake_write_round_one( &ssl->handshake->ecjpake_ctx, + p + 2, end - p - 2, &kkpp_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1 , "mbedtls_ecjpake_write_round_one", ret ); + return; + } + + ssl->handshake->ecjpake_cache = mbedtls_calloc( 1, kkpp_len ); + if( ssl->handshake->ecjpake_cache == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "allocation failed" ) ); + return; + } + + memcpy( ssl->handshake->ecjpake_cache, p + 2, kkpp_len ); + ssl->handshake->ecjpake_cache_len = kkpp_len; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "re-using cached ecjpake parameters" ) ); + + kkpp_len = ssl->handshake->ecjpake_cache_len; + + if( (size_t)( end - p - 2 ) < kkpp_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + memcpy( p + 2, ssl->handshake->ecjpake_cache, kkpp_len ); + } + + *p++ = (unsigned char)( ( kkpp_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( kkpp_len ) & 0xFF ); + + *olen = kkpp_len + 4; +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static void ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE ) { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding max_fragment_length extension" ) ); + + if( end < p || (size_t)( end - p ) < 5 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->conf->mfl_code; + + *olen = 5; +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static void ssl_write_truncated_hmac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_DISABLED ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding truncated_hmac extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static void ssl_write_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED || + ssl->conf->max_minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding encrypt_then_mac " + "extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static void ssl_write_extended_ms_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + *olen = 0; + + if( ssl->conf->extended_ms == MBEDTLS_SSL_EXTENDED_MS_DISABLED || + ssl->conf->max_minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding extended_master_secret " + "extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static void ssl_write_session_ticket_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t tlen = ssl->session_negotiate->ticket_len; + + *olen = 0; + + if( ssl->conf->session_tickets == MBEDTLS_SSL_SESSION_TICKETS_DISABLED ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding session ticket extension" ) ); + + if( end < p || (size_t)( end - p ) < 4 + tlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET ) & 0xFF ); + + *p++ = (unsigned char)( ( tlen >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( tlen ) & 0xFF ); + + *olen = 4; + + if( ssl->session_negotiate->ticket == NULL || tlen == 0 ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "sending session ticket of length %d", tlen ) ); + + memcpy( p, ssl->session_negotiate->ticket, tlen ); + + *olen += tlen; +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_ALPN) +static void ssl_write_alpn_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t alpnlen = 0; + const char **cur; + + *olen = 0; + + if( ssl->conf->alpn_list == NULL ) + { + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, adding alpn extension" ) ); + + for( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + alpnlen += (unsigned char)( strlen( *cur ) & 0xFF ) + 1; + + if( end < p || (size_t)( end - p ) < 6 + alpnlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN ) & 0xFF ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + */ + + /* Skip writing extension and list length for now */ + p += 4; + + for( cur = ssl->conf->alpn_list; *cur != NULL; cur++ ) + { + *p = (unsigned char)( strlen( *cur ) & 0xFF ); + memcpy( p + 1, *cur, *p ); + p += 1 + *p; + } + + *olen = p - buf; + + /* List length = olen - 2 (ext_type) - 2 (ext_len) - 2 (list_len) */ + buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF ); + buf[5] = (unsigned char)( ( ( *olen - 6 ) ) & 0xFF ); + + /* Extension length = olen - 2 (ext_type) - 2 (ext_len) */ + buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF ); + buf[3] = (unsigned char)( ( ( *olen - 4 ) ) & 0xFF ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * Generate random bytes for ClientHello + */ +static int ssl_generate_random( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *p = ssl->handshake->randbytes; +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t t; +#endif + + /* + * When responding to a verify request, MUST reuse random (RFC 6347 4.2.1) + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->verify_cookie != NULL ) + { + return( 0 ); + } +#endif + +#if defined(MBEDTLS_HAVE_TIME) + t = mbedtls_time( NULL ); + *p++ = (unsigned char)( t >> 24 ); + *p++ = (unsigned char)( t >> 16 ); + *p++ = (unsigned char)( t >> 8 ); + *p++ = (unsigned char)( t ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, current time: %lu", t ) ); +#else + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 4 ) ) != 0 ) + return( ret ); + + p += 4; +#endif /* MBEDTLS_HAVE_TIME */ + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 28 ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +static int ssl_write_client_hello( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t i, n, olen, ext_len = 0; + unsigned char *buf; + unsigned char *p, *q; + unsigned char offer_compress; + const int *ciphersuites; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write client hello" ) ); + + if( ssl->conf->f_rng == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no RNG provided") ); + return( MBEDTLS_ERR_SSL_NO_RNG ); + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + ssl->major_ver = ssl->conf->min_major_ver; + ssl->minor_ver = ssl->conf->min_minor_ver; + } + + if( ssl->conf->max_major_ver == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "configured max major version is invalid, " + "consider using mbedtls_ssl_config_defaults()" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 highest version supported + * 6 . 9 current UNIX time + * 10 . 37 random bytes + */ + buf = ssl->out_msg; + p = buf + 4; + + mbedtls_ssl_write_version( ssl->conf->max_major_ver, ssl->conf->max_minor_ver, + ssl->conf->transport, p ); + p += 2; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, max version: [%d:%d]", + buf[4], buf[5] ) ); + + if( ( ret = ssl_generate_random( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_generate_random", ret ); + return( ret ); + } + + memcpy( p, ssl->handshake->randbytes, 32 ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, random bytes", p, 32 ); + p += 32; + + /* + * 38 . 38 session id length + * 39 . 39+n session id + * 39+n . 39+n DTLS only: cookie length (1 byte) + * 40+n . .. DTSL only: cookie + * .. . .. ciphersuitelist length (2 bytes) + * .. . .. ciphersuitelist + * .. . .. compression methods length (1 byte) + * .. . .. compression methods + * .. . .. extensions length (2 bytes) + * .. . .. extensions + */ + n = ssl->session_negotiate->id_len; + + if( n < 16 || n > 32 || +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE || +#endif + ssl->handshake->resume == 0 ) + { + n = 0; + } + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + /* + * RFC 5077 section 3.4: "When presenting a ticket, the client MAY + * generate and include a Session ID in the TLS ClientHello." + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + if( ssl->session_negotiate->ticket != NULL && + ssl->session_negotiate->ticket_len != 0 ) + { + ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->session_negotiate->id, 32 ); + + if( ret != 0 ) + return( ret ); + + ssl->session_negotiate->id_len = n = 32; + } + } +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + + *p++ = (unsigned char) n; + + for( i = 0; i < n; i++ ) + *p++ = ssl->session_negotiate->id[i]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, session id len.: %d", n ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, session id", buf + 39, n ); + + /* + * DTLS cookie + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( ssl->handshake->verify_cookie == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no verify cookie to send" ) ); + *p++ = 0; + } + else + { + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, cookie", + ssl->handshake->verify_cookie, + ssl->handshake->verify_cookie_len ); + + *p++ = ssl->handshake->verify_cookie_len; + memcpy( p, ssl->handshake->verify_cookie, + ssl->handshake->verify_cookie_len ); + p += ssl->handshake->verify_cookie_len; + } + } +#endif + + /* + * Ciphersuite list + */ + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + + /* Skip writing ciphersuite length for now */ + n = 0; + q = p; + p += 2; + + for( i = 0; ciphersuites[i] != 0; i++ ) + { + ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( ciphersuites[i] ); + + if( ciphersuite_info == NULL ) + continue; + + if( ciphersuite_info->min_minor_ver > ssl->conf->max_minor_ver || + ciphersuite_info->max_minor_ver < ssl->conf->min_minor_ver ) + continue; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( ciphersuite_info->flags & MBEDTLS_CIPHERSUITE_NODTLS ) ) + continue; +#endif + +#if defined(MBEDTLS_ARC4_C) + if( ssl->conf->arc4_disabled == MBEDTLS_SSL_ARC4_DISABLED && + ciphersuite_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) + continue; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE && + mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 ) + continue; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, add ciphersuite: %04x", + ciphersuites[i] ) ); + + n++; + *p++ = (unsigned char)( ciphersuites[i] >> 8 ); + *p++ = (unsigned char)( ciphersuites[i] ); + } + + /* + * Add TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + *p++ = (unsigned char)( MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO >> 8 ); + *p++ = (unsigned char)( MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO ); + n++; + } + + /* Some versions of OpenSSL don't handle it correctly if not at end */ +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + if( ssl->conf->fallback == MBEDTLS_SSL_IS_FALLBACK ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "adding FALLBACK_SCSV" ) ); + *p++ = (unsigned char)( MBEDTLS_SSL_FALLBACK_SCSV_VALUE >> 8 ); + *p++ = (unsigned char)( MBEDTLS_SSL_FALLBACK_SCSV_VALUE ); + n++; + } +#endif + + *q++ = (unsigned char)( n >> 7 ); + *q++ = (unsigned char)( n << 1 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, got %d ciphersuites", n ) ); + +#if defined(MBEDTLS_ZLIB_SUPPORT) + offer_compress = 1; +#else + offer_compress = 0; +#endif + + /* + * We don't support compression with DTLS right now: is many records come + * in the same datagram, uncompressing one could overwrite the next one. + * We don't want to add complexity for handling that case unless there is + * an actual need for it. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + offer_compress = 0; +#endif + + if( offer_compress ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 2 ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d %d", + MBEDTLS_SSL_COMPRESS_DEFLATE, MBEDTLS_SSL_COMPRESS_NULL ) ); + + *p++ = 2; + *p++ = MBEDTLS_SSL_COMPRESS_DEFLATE; + *p++ = MBEDTLS_SSL_COMPRESS_NULL; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress len.: %d", 1 ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, compress alg.: %d", + MBEDTLS_SSL_COMPRESS_NULL ) ); + + *p++ = 1; + *p++ = MBEDTLS_SSL_COMPRESS_NULL; + } + + // First write extensions, then the total length + // +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + ssl_write_hostname_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl_write_renegotiation_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + ssl_write_signature_algorithms_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl_write_supported_elliptic_curves_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; + + ssl_write_supported_point_formats_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl_write_ecjpake_kkpp_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + ssl_write_max_fragment_length_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + ssl_write_truncated_hmac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + ssl_write_encrypt_then_mac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + ssl_write_extended_ms_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ALPN) + ssl_write_alpn_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + ssl_write_session_ticket_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + + /* olen unused if all extensions are disabled */ + ((void) olen); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello, total extension length: %d", + ext_len ) ); + + if( ext_len > 0 ) + { + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + p += ext_len; + } + + ssl->out_msglen = p - buf; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CLIENT_HELLO; + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_send_flight_completed( ssl ); +#endif + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write client hello" ) ); + + return( 0 ); +} + +static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + /* Check verify-data in constant-time. The length OTOH is no secret */ + if( len != 1 + ssl->verify_data_len * 2 || + buf[0] != ssl->verify_data_len * 2 || + mbedtls_ssl_safer_memcmp( buf + 1, + ssl->own_verify_data, ssl->verify_data_len ) != 0 || + mbedtls_ssl_safer_memcmp( buf + 1 + ssl->verify_data_len, + ssl->peer_verify_data, ssl->verify_data_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + if( len != 1 || buf[0] != 0x00 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + } + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + /* + * server should use the extension only if we did, + * and if so the server's value should match ours (and len is always 1) + */ + if( ssl->conf->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE || + len != 1 || + buf[0] != ssl->conf->mfl_code ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static int ssl_parse_truncated_hmac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_DISABLED || + len != 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->session_negotiate->trunc_hmac = MBEDTLS_SSL_TRUNC_HMAC_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static int ssl_parse_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 || + len != 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->session_negotiate->encrypt_then_mac = MBEDTLS_SSL_ETM_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static int ssl_parse_extended_ms_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->extended_ms == MBEDTLS_SSL_EXTENDED_MS_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 || + len != 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->handshake->extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_parse_session_ticket_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( ssl->conf->session_tickets == MBEDTLS_SSL_SESSION_TICKETS_DISABLED || + len != 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + ((void) buf); + + ssl->handshake->new_session_ticket = 1; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_supported_point_formats_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t list_size; + const unsigned char *p; + + list_size = buf[0]; + if( list_size + 1 != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + p = buf + 1; + while( list_size > 0 ) + { + if( p[0] == MBEDTLS_ECP_PF_UNCOMPRESSED || + p[0] == MBEDTLS_ECP_PF_COMPRESSED ) + { +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + ssl->handshake->ecdh_ctx.point_format = p[0]; +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl->handshake->ecjpake_ctx.point_format = p[0]; +#endif + MBEDTLS_SSL_DEBUG_MSG( 4, ( "point format selected: %d", p[0] ) ); + return( 0 ); + } + + list_size--; + p++; + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no point format in common" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_ecjpake_kkpp( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + + if( ssl->transform_negotiate->ciphersuite_info->key_exchange != + MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip ecjpake kkpp extension" ) ); + return( 0 ); + } + + /* If we got here, we no longer need our cached extension */ + mbedtls_free( ssl->handshake->ecjpake_cache ); + ssl->handshake->ecjpake_cache = NULL; + ssl->handshake->ecjpake_cache_len = 0; + + if( ( ret = mbedtls_ecjpake_read_round_one( &ssl->handshake->ecjpake_ctx, + buf, len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_one", ret ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len, name_len; + const char **p; + + /* If we didn't send it, the server shouldn't send it */ + if( ssl->conf->alpn_list == NULL ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + * + * the "ProtocolNameList" MUST contain exactly one "ProtocolName" + */ + + /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */ + if( len < 4 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + list_len = ( buf[0] << 8 ) | buf[1]; + if( list_len != len - 2 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + name_len = buf[2]; + if( name_len != list_len - 1 ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + + /* Check that the server chosen protocol was in our list and save it */ + for( p = ssl->conf->alpn_list; *p != NULL; p++ ) + { + if( name_len == strlen( *p ) && + memcmp( buf + 3, *p, name_len ) == 0 ) + { + ssl->alpn_chosen = *p; + return( 0 ); + } + } + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * Parse HelloVerifyRequest. Only called after verifying the HS type. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) +static int ssl_parse_hello_verify_request( mbedtls_ssl_context *ssl ) +{ + const unsigned char *p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + int major_ver, minor_ver; + unsigned char cookie_len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse hello verify request" ) ); + + /* + * struct { + * ProtocolVersion server_version; + * opaque cookie<0..2^8-1>; + * } HelloVerifyRequest; + */ + MBEDTLS_SSL_DEBUG_BUF( 3, "server version", p, 2 ); + mbedtls_ssl_read_version( &major_ver, &minor_ver, ssl->conf->transport, p ); + p += 2; + + /* + * Since the RFC is not clear on this point, accept DTLS 1.0 (TLS 1.1) + * even is lower than our min version. + */ + if( major_ver < MBEDTLS_SSL_MAJOR_VERSION_3 || + minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 || + major_ver > ssl->conf->max_major_ver || + minor_ver > ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server version" ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + cookie_len = *p++; + MBEDTLS_SSL_DEBUG_BUF( 3, "cookie", p, cookie_len ); + + if( ( ssl->in_msg + ssl->in_msglen ) - p < cookie_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, + ( "cookie length does not match incoming message size" ) ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_DECODE_ERROR ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + mbedtls_free( ssl->handshake->verify_cookie ); + + ssl->handshake->verify_cookie = mbedtls_calloc( 1, cookie_len ); + if( ssl->handshake->verify_cookie == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed (%d bytes)", cookie_len ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ssl->handshake->verify_cookie, p, cookie_len ); + ssl->handshake->verify_cookie_len = cookie_len; + + /* Start over at ClientHello */ + ssl->state = MBEDTLS_SSL_CLIENT_HELLO; + mbedtls_ssl_reset_checksum( ssl ); + + mbedtls_ssl_recv_flight_completed( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse hello verify request" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +static int ssl_parse_server_hello( mbedtls_ssl_context *ssl ) +{ + int ret, i; + size_t n; + size_t ext_len; + unsigned char *buf, *ext; + unsigned char comp; +#if defined(MBEDTLS_ZLIB_SUPPORT) + int accept_comp; +#endif +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renegotiation_info_seen = 0; +#endif + int handshake_failure = 0; + const mbedtls_ssl_ciphersuite_t *suite_info; +#if defined(MBEDTLS_DEBUG_C) + uint32_t t; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello" ) ); + + buf = ssl->in_msg; + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + ssl->renego_records_seen++; + + if( ssl->conf->renego_max_records >= 0 && + ssl->renego_records_seen > ssl->conf->renego_max_records ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation requested, " + "but not honored by server" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-handshake message during renego" ) ); + return( MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( buf[0] == MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received hello verify request" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server hello" ) ); + return( ssl_parse_hello_verify_request( ssl ) ); + } + else + { + /* We made it through the verification process */ + mbedtls_free( ssl->handshake->verify_cookie ); + ssl->handshake->verify_cookie = NULL; + ssl->handshake->verify_cookie_len = 0; + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + if( ssl->in_hslen < 38 + mbedtls_ssl_hs_hdr_len( ssl ) || + buf[0] != MBEDTLS_SSL_HS_SERVER_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* + * 0 . 1 server_version + * 2 . 33 random (maybe including 4 bytes of Unix time) + * 34 . 34 session_id length = n + * 35 . 34+n session_id + * 35+n . 36+n cipher_suite + * 37+n . 37+n compression_method + * + * 38+n . 39+n extensions length (optional) + * 40+n . .. extensions + */ + buf += mbedtls_ssl_hs_hdr_len( ssl ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, version", buf + 0, 2 ); + mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver, + ssl->conf->transport, buf + 0 ); + + if( ssl->major_ver < ssl->conf->min_major_ver || + ssl->minor_ver < ssl->conf->min_minor_ver || + ssl->major_ver > ssl->conf->max_major_ver || + ssl->minor_ver > ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server version out of bounds - " + " min: [%d:%d], server: [%d:%d], max: [%d:%d]", + ssl->conf->min_major_ver, ssl->conf->min_minor_ver, + ssl->major_ver, ssl->minor_ver, + ssl->conf->max_major_ver, ssl->conf->max_minor_ver ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + +#if defined(MBEDTLS_DEBUG_C) + t = ( (uint32_t) buf[2] << 24 ) + | ( (uint32_t) buf[3] << 16 ) + | ( (uint32_t) buf[4] << 8 ) + | ( (uint32_t) buf[5] ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) ); +#endif + + memcpy( ssl->handshake->randbytes + 32, buf + 2, 32 ); + + n = buf[34]; + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 2, 32 ); + + if( n > 32 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( ssl->in_hslen > mbedtls_ssl_hs_hdr_len( ssl ) + 39 + n ) + { + ext_len = ( ( buf[38 + n] << 8 ) + | ( buf[39 + n] ) ); + + if( ( ext_len > 0 && ext_len < 4 ) || + ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + 40 + n + ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + else if( ssl->in_hslen == mbedtls_ssl_hs_hdr_len( ssl ) + 38 + n ) + { + ext_len = 0; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + /* ciphersuite (used later) */ + i = ( buf[35 + n] << 8 ) | buf[36 + n]; + + /* + * Read and check compression + */ + comp = buf[37 + n]; + +#if defined(MBEDTLS_ZLIB_SUPPORT) + /* See comments in ssl_write_client_hello() */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + accept_comp = 0; + else +#endif + accept_comp = 1; + + if( comp != MBEDTLS_SSL_COMPRESS_NULL && + ( comp != MBEDTLS_SSL_COMPRESS_DEFLATE || accept_comp == 0 ) ) +#else /* MBEDTLS_ZLIB_SUPPORT */ + if( comp != MBEDTLS_SSL_COMPRESS_NULL ) +#endif/* MBEDTLS_ZLIB_SUPPORT */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server hello, bad compression: %d", comp ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + /* + * Initialize update checksum functions + */ + ssl->transform_negotiate->ciphersuite_info = mbedtls_ssl_ciphersuite_from_id( i ); + + if( ssl->transform_negotiate->ciphersuite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ciphersuite info for %04x not found", i ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + mbedtls_ssl_optimize_checksum( ssl, ssl->transform_negotiate->ciphersuite_info ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, session id", buf + 35, n ); + + /* + * Check if the session can be resumed + */ + if( ssl->handshake->resume == 0 || n == 0 || +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE || +#endif + ssl->session_negotiate->ciphersuite != i || + ssl->session_negotiate->compression != comp || + ssl->session_negotiate->id_len != n || + memcmp( ssl->session_negotiate->id, buf + 35, n ) != 0 ) + { + ssl->state++; + ssl->handshake->resume = 0; +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = mbedtls_time( NULL ); +#endif + ssl->session_negotiate->ciphersuite = i; + ssl->session_negotiate->compression = comp; + ssl->session_negotiate->id_len = n; + memcpy( ssl->session_negotiate->id, buf + 35, n ); + } + else + { + ssl->state = MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC; + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "%s session has been resumed", + ssl->handshake->resume ? "a" : "no" ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %04x", i ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: %d", buf[37 + n] ) ); + + suite_info = mbedtls_ssl_ciphersuite_from_id( ssl->session_negotiate->ciphersuite ); + if( suite_info == NULL +#if defined(MBEDTLS_ARC4_C) + || ( ssl->conf->arc4_disabled && + suite_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) +#endif + ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s", suite_info->name ) ); + + i = 0; + while( 1 ) + { + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i] == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + if( ssl->conf->ciphersuite_list[ssl->minor_ver][i++] == + ssl->session_negotiate->ciphersuite ) + { + break; + } + } + + if( comp != MBEDTLS_SSL_COMPRESS_NULL +#if defined(MBEDTLS_ZLIB_SUPPORT) + && comp != MBEDTLS_SSL_COMPRESS_DEFLATE +#endif + ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + ssl->session_negotiate->compression = comp; + + ext = buf + 40 + n; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "server hello, total extension length: %d", ext_len ) ); + + while( ext_len ) + { + unsigned int ext_id = ( ( ext[0] << 8 ) + | ( ext[1] ) ); + unsigned int ext_size = ( ( ext[2] << 8 ) + | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + switch( ext_id ) + { + case MBEDTLS_TLS_EXT_RENEGOTIATION_INFO: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + renegotiation_info_seen = 1; +#endif + + if( ( ret = ssl_parse_renegotiation_info( ssl, ext + 4, + ext_size ) ) != 0 ) + return( ret ); + + break; + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + case MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found max_fragment_length extension" ) ); + + if( ( ret = ssl_parse_max_fragment_length_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + case MBEDTLS_TLS_EXT_TRUNCATED_HMAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found truncated_hmac extension" ) ); + + if( ( ret = ssl_parse_truncated_hmac_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + case MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found encrypt_then_mac extension" ) ); + + if( ( ret = ssl_parse_encrypt_then_mac_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + case MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found extended_master_secret extension" ) ); + + if( ( ret = ssl_parse_extended_ms_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + case MBEDTLS_TLS_EXT_SESSION_TICKET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found session_ticket extension" ) ); + + if( ( ret = ssl_parse_session_ticket_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported_point_formats extension" ) ); + + if( ( ret = ssl_parse_supported_point_formats_ext( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_ECJPAKE_KKPP: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ecjpake_kkpp extension" ) ); + + if( ( ret = ssl_parse_ecjpake_kkpp( ssl, + ext + 4, ext_size ) ) != 0 ) + { + return( ret ); + } + + break; +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN) + case MBEDTLS_TLS_EXT_ALPN: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) ); + + if( ( ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size ) ) != 0 ) + return( ret ); + + break; +#endif /* MBEDTLS_SSL_ALPN */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", + ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + } + + /* + * Renegotiation security checks + */ + if( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + handshake_failure = 1; + } +#if defined(MBEDTLS_SSL_RENEGOTIATION) + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_SECURE_RENEGOTIATION && + renegotiation_info_seen == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension missing (secure)" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation not allowed" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + renegotiation_info_seen == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension present (legacy)" ) ); + handshake_failure = 1; + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + if( handshake_failure == 1 ) + { + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server hello" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +static int ssl_parse_server_dh_params( mbedtls_ssl_context *ssl, unsigned char **p, + unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + /* + * Ephemeral DH parameters: + * + * struct { + * opaque dh_p<1..2^16-1>; + * opaque dh_g<1..2^16-1>; + * opaque dh_Ys<1..2^16-1>; + * } ServerDHParams; + */ + if( ( ret = mbedtls_dhm_read_params( &ssl->handshake->dhm_ctx, p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 2, ( "mbedtls_dhm_read_params" ), ret ); + return( ret ); + } + + if( ssl->handshake->dhm_ctx.len * 8 < ssl->conf->dhm_min_bitlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "DHM prime too short: %d < %d", + ssl->handshake->dhm_ctx.len * 8, + ssl->conf->dhm_min_bitlen ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->handshake->dhm_ctx.G ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->handshake->dhm_ctx.GY ); + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +static int ssl_check_server_ecdh_params( const mbedtls_ssl_context *ssl ) +{ + const mbedtls_ecp_curve_info *curve_info; + + curve_info = mbedtls_ecp_curve_info_from_grp_id( ssl->handshake->ecdh_ctx.grp.id ); + if( curve_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDH curve: %s", curve_info->name ) ); + +#if defined(MBEDTLS_ECP_C) + if( mbedtls_ssl_check_curve( ssl, ssl->handshake->ecdh_ctx.grp.id ) != 0 ) +#else + if( ssl->handshake->ecdh_ctx.grp.nbits < 163 || + ssl->handshake->ecdh_ctx.grp.nbits > 521 ) +#endif + return( -1 ); + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp", &ssl->handshake->ecdh_ctx.Qp ); + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) +static int ssl_parse_server_ecdh_params( mbedtls_ssl_context *ssl, + unsigned char **p, + unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + /* + * Ephemeral ECDH parameters: + * + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ + if( ( ret = mbedtls_ecdh_read_params( &ssl->handshake->ecdh_ctx, + (const unsigned char **) p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_read_params" ), ret ); + return( ret ); + } + + if( ssl_check_server_ecdh_params( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message (ECDHE curve)" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +static int ssl_parse_server_psk_hint( mbedtls_ssl_context *ssl, + unsigned char **p, + unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t len; + ((void) ssl); + + /* + * PSK parameters: + * + * opaque psk_identity_hint<0..2^16-1>; + */ + len = (*p)[0] << 8 | (*p)[1]; + *p += 2; + + if( (*p) + len > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message (psk_identity_hint length)" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + /* + * Note: we currently ignore the PKS identity hint, as we only allow one + * PSK to be provisionned on the client. This could be changed later if + * someone needs that feature. + */ + *p += len; + ret = 0; + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) +/* + * Generate a pre-master secret and encrypt it with the server's RSA key + */ +static int ssl_write_encrypted_pms( mbedtls_ssl_context *ssl, + size_t offset, size_t *olen, + size_t pms_offset ) +{ + int ret; + size_t len_bytes = ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ? 0 : 2; + unsigned char *p = ssl->handshake->premaster + pms_offset; + + if( offset + len_bytes > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small for encrypted pms" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + /* + * Generate (part of) the pre-master as + * struct { + * ProtocolVersion client_version; + * opaque random[46]; + * } PreMasterSecret; + */ + mbedtls_ssl_write_version( ssl->conf->max_major_ver, ssl->conf->max_minor_ver, + ssl->conf->transport, p ); + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p + 2, 46 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_rng", ret ); + return( ret ); + } + + ssl->handshake->pmslen = 48; + + if( ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * Now write it out, encrypted + */ + if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, + MBEDTLS_PK_RSA ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate key type mismatch" ) ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + + if( ( ret = mbedtls_pk_encrypt( &ssl->session_negotiate->peer_cert->pk, + p, ssl->handshake->pmslen, + ssl->out_msg + offset + len_bytes, olen, + MBEDTLS_SSL_MAX_CONTENT_LEN - offset - len_bytes, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_rsa_pkcs1_encrypt", ret ); + return( ret ); + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( len_bytes == 2 ) + { + ssl->out_msg[offset+0] = (unsigned char)( *olen >> 8 ); + ssl->out_msg[offset+1] = (unsigned char)( *olen ); + *olen += 2; + } +#endif + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_parse_signature_algorithm( mbedtls_ssl_context *ssl, + unsigned char **p, + unsigned char *end, + mbedtls_md_type_t *md_alg, + mbedtls_pk_type_t *pk_alg ) +{ + ((void) ssl); + *md_alg = MBEDTLS_MD_NONE; + *pk_alg = MBEDTLS_PK_NONE; + + /* Only in TLS 1.2 */ + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + { + return( 0 ); + } + + if( (*p) + 2 > end ) + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + + /* + * Get hash algorithm + */ + if( ( *md_alg = mbedtls_ssl_md_alg_from_hash( (*p)[0] ) ) == MBEDTLS_MD_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Server used unsupported " + "HashAlgorithm %d", *(p)[0] ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + /* + * Get signature algorithm + */ + if( ( *pk_alg = mbedtls_ssl_pk_alg_from_sig( (*p)[1] ) ) == MBEDTLS_PK_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server used unsupported " + "SignatureAlgorithm %d", (*p)[1] ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + /* + * Check if the hash is acceptable + */ + if( mbedtls_ssl_check_sig_hash( ssl, *md_alg ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server used HashAlgorithm " + "that was not offered" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Server used SignatureAlgorithm %d", (*p)[1] ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "Server used HashAlgorithm %d", (*p)[0] ) ); + *p += 2; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) +{ + int ret; + const mbedtls_ecp_keypair *peer_key; + + if( ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, + MBEDTLS_PK_ECKEY ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + + peer_key = mbedtls_pk_ec( ssl->session_negotiate->peer_cert->pk ); + + if( ( ret = mbedtls_ecdh_get_params( &ssl->handshake->ecdh_ctx, peer_key, + MBEDTLS_ECDH_THEIRS ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_get_params" ), ret ); + return( ret ); + } + + if( ssl_check_server_ecdh_params( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server certificate (ECDH curve)" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +static int ssl_parse_server_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + unsigned char *p, *end; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server key exchange" ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) ); + ssl->state++; + return( 0 ); + } + ((void) p); + ((void) end); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) + { + if( ( ret = ssl_get_ecdh_params_from_cert( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_get_ecdh_params_from_cert", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse server key exchange" ) ); + ssl->state++; + return( 0 ); + } + ((void) p); + ((void) end); +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * ServerKeyExchange may be skipped with PSK and RSA-PSK when the server + * doesn't use a psk_identity_hint + */ + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE ) + { + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + ssl->record_read = 1; + goto exit; + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + end = ssl->in_msg + ssl->in_hslen; + MBEDTLS_SSL_DEBUG_BUF( 3, "server key exchange", p, end - p ); + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + if( ssl_parse_server_psk_hint( ssl, &p, end ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } /* FALLTROUGH */ +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + ; /* nothing more to do */ + else +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + if( ssl_parse_server_dh_params( ssl, &p, end ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + if( ssl_parse_server_ecdh_params( ssl, &p, end ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + ret = mbedtls_ecjpake_read_round_two( &ssl->handshake->ecjpake_ctx, + p, end - p ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_two", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + size_t sig_len, hashlen; + unsigned char hash[64]; + mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE; + mbedtls_pk_type_t pk_alg = MBEDTLS_PK_NONE; + unsigned char *params = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + size_t params_len = p - params; + + /* + * Handle the digitally-signed structure + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + if( ssl_parse_signature_algorithm( ssl, &p, end, + &md_alg, &pk_alg ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + if( pk_alg != mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ) + { + pk_alg = mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ); + + /* Default hash for ECDSA is SHA-1 */ + if( pk_alg == MBEDTLS_PK_ECDSA && md_alg == MBEDTLS_MD_NONE ) + md_alg = MBEDTLS_MD_SHA1; + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * Read signature + */ + sig_len = ( p[0] << 8 ) | p[1]; + p += 2; + + if( end != p + sig_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "signature", p, sig_len ); + + /* + * Compute the hash that has been signed + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( md_alg == MBEDTLS_MD_NONE ) + { + mbedtls_md5_context mbedtls_md5; + mbedtls_sha1_context mbedtls_sha1; + + mbedtls_md5_init( &mbedtls_md5 ); + mbedtls_sha1_init( &mbedtls_sha1 ); + + hashlen = 36; + + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(ClientHello.random + ServerHello.random + * + ServerParams); + * sha_hash + * SHA(ClientHello.random + ServerHello.random + * + ServerParams); + */ + mbedtls_md5_starts( &mbedtls_md5 ); + mbedtls_md5_update( &mbedtls_md5, ssl->handshake->randbytes, 64 ); + mbedtls_md5_update( &mbedtls_md5, params, params_len ); + mbedtls_md5_finish( &mbedtls_md5, hash ); + + mbedtls_sha1_starts( &mbedtls_sha1 ); + mbedtls_sha1_update( &mbedtls_sha1, ssl->handshake->randbytes, 64 ); + mbedtls_sha1_update( &mbedtls_sha1, params, params_len ); + mbedtls_sha1_finish( &mbedtls_sha1, hash + 16 ); + + mbedtls_md5_free( &mbedtls_md5 ); + mbedtls_sha1_free( &mbedtls_sha1 ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( md_alg != MBEDTLS_MD_NONE ) + { + mbedtls_md_context_t ctx; + + mbedtls_md_init( &ctx ); + + /* Info from md_alg will be used instead */ + hashlen = 0; + + /* + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * }; + */ + if( ( ret = mbedtls_md_setup( &ctx, + mbedtls_md_info_from_type( md_alg ), 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret ); + return( ret ); + } + + mbedtls_md_starts( &ctx ); + mbedtls_md_update( &ctx, ssl->handshake->randbytes, 64 ); + mbedtls_md_update( &ctx, params, params_len ); + mbedtls_md_finish( &ctx, hash ); + mbedtls_md_free( &ctx ); + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen != 0 ? hashlen : + (unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) ); + + if( ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "certificate required" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * Verify signature + */ + if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, pk_alg ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server key exchange message" ) ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + + if( ( ret = mbedtls_pk_verify( &ssl->session_negotiate->peer_cert->pk, + md_alg, hash, hashlen, p, sig_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +exit: + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server key exchange" ) ); + + return( 0 ); +} + +#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_parse_certificate_request( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate request" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else +static int ssl_parse_certificate_request( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *buf; + size_t n = 0; + size_t cert_type_len = 0, dn_len = 0; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate request" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate request" ) ); + ssl->state++; + return( 0 ); + } + + if( ssl->record_read == 0 ) + { + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + ssl->record_read = 1; + } + + ssl->client_auth = 0; + ssl->state++; + + if( ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE_REQUEST ) + ssl->client_auth++; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "got %s certificate request", + ssl->client_auth ? "a" : "no" ) ); + + if( ssl->client_auth == 0 ) + goto exit; + + ssl->record_read = 0; + + /* + * struct { + * ClientCertificateType certificate_types<1..2^8-1>; + * SignatureAndHashAlgorithm + * supported_signature_algorithms<2^16-1>; -- TLS 1.2 only + * DistinguishedName certificate_authorities<0..2^16-1>; + * } CertificateRequest; + * + * Since we only support a single certificate on clients, let's just + * ignore all the information that's supposed to help us pick a + * certificate. + * + * We could check that our certificate matches the request, and bail out + * if it doesn't, but it's simpler to just send the certificate anyway, + * and give the server the opportunity to decide if it should terminate + * the connection when it doesn't like our certificate. + * + * Same goes for the hash in TLS 1.2's signature_algorithms: at this + * point we only have one hash available (see comments in + * write_certificate_verify), so let's just use what we have. + * + * However, we still minimally parse the message to check it is at least + * superficially sane. + */ + buf = ssl->in_msg; + + /* certificate_types */ + cert_type_len = buf[mbedtls_ssl_hs_hdr_len( ssl )]; + n = cert_type_len; + + if( ssl->in_hslen < mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + + /* supported_signature_algorithms */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + size_t sig_alg_len = ( ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 1 + n] << 8 ) + | ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n] ) ); +#if defined(MBEDTLS_DEBUG_C) + unsigned char* sig_alg = buf + mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n; + size_t i; + + for( i = 0; i < sig_alg_len; i += 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Supported Signature Algorithm found: %d,%d", sig_alg[i], sig_alg[i + 1] ) ); + } +#endif + + n += 2 + sig_alg_len; + + if( ssl->in_hslen < mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + /* certificate_authorities */ + dn_len = ( ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 1 + n] << 8 ) + | ( buf[mbedtls_ssl_hs_hdr_len( ssl ) + 2 + n] ) ); + + n += dn_len; + if( ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + 3 + n ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate request message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_REQUEST ); + } + +exit: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate request" ) ); + + return( 0 ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +static int ssl_parse_server_hello_done( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse server hello done" ) ); + + if( ssl->record_read == 0 ) + { + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + } + ssl->record_read = 0; + + if( ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) || + ssl->in_msg[0] != MBEDTLS_SSL_HS_SERVER_HELLO_DONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad server hello done message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_HELLO_DONE ); + } + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_recv_flight_completed( ssl ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse server hello done" ) ); + + return( 0 ); +} + +static int ssl_write_client_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t i, n; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write client key exchange" ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA ) + { + /* + * DHM key exchange -- send G^X mod P + */ + n = ssl->handshake->dhm_ctx.len; + + ssl->out_msg[4] = (unsigned char)( n >> 8 ); + ssl->out_msg[5] = (unsigned char)( n ); + i = 6; + + ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + &ssl->out_msg[i], n, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_public", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->handshake->dhm_ctx.GX ); + + if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx, + ssl->handshake->premaster, + MBEDTLS_PREMASTER_SIZE, + &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) + { + /* + * ECDH key exchange -- send client public value + */ + i = 4; + + ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, + &n, + &ssl->out_msg[i], 1000, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_public", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q ); + + if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, + &ssl->handshake->pmslen, + ssl->handshake->premaster, + MBEDTLS_MPI_MAX_SIZE, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.z ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + /* + * opaque psk_identity<0..2^16-1>; + */ + if( ssl->conf->psk == NULL || ssl->conf->psk_identity == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key for PSK" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + i = 4; + n = ssl->conf->psk_identity_len; + + if( i + 2 + n > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk identity too long or " + "SSL buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + ssl->out_msg[i++] = (unsigned char)( n >> 8 ); + ssl->out_msg[i++] = (unsigned char)( n ); + + memcpy( ssl->out_msg + i, ssl->conf->psk_identity, ssl->conf->psk_identity_len ); + i += ssl->conf->psk_identity_len; + +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ) + { + n = 0; + } + else +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + if( ( ret = ssl_write_encrypted_pms( ssl, i, &n, 2 ) ) != 0 ) + return( ret ); + } + else +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + /* + * ClientDiffieHellmanPublic public (DHM send G^X mod P) + */ + n = ssl->handshake->dhm_ctx.len; + + if( i + 2 + n > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "psk identity or DHM size too long" + " or SSL buffer too short" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + ssl->out_msg[i++] = (unsigned char)( n >> 8 ); + ssl->out_msg[i++] = (unsigned char)( n ); + + ret = mbedtls_dhm_make_public( &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + &ssl->out_msg[i], n, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_public", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + /* + * ClientECDiffieHellmanPublic public; + */ + ret = mbedtls_ecdh_make_public( &ssl->handshake->ecdh_ctx, &n, + &ssl->out_msg[i], MBEDTLS_SSL_MAX_CONTENT_LEN - i, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_public", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q", &ssl->handshake->ecdh_ctx.Q ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) + { + i = 4; + if( ( ret = ssl_write_encrypted_pms( ssl, i, &n, 0 ) ) != 0 ) + return( ret ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + i = 4; + + ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx, + ssl->out_msg + i, MBEDTLS_SSL_MAX_CONTENT_LEN - i, &n, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_write_round_two", ret ); + return( ret ); + } + + ret = mbedtls_ecjpake_derive_secret( &ssl->handshake->ecjpake_ctx, + ssl->handshake->premaster, 32, &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_derive_secret", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ + { + ((void) ciphersuite_info); + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->out_msglen = i + n; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write client key exchange" ) ); + + return( 0 ); +} + +#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) ); + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else +static int ssl_write_certificate_verify( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + size_t n = 0, offset = 0; + unsigned char hash[48]; + unsigned char *hash_start = hash; + mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE; + unsigned int hashlen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate verify" ) ); + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + if( ssl->client_auth == 0 || mbedtls_ssl_own_cert( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + if( mbedtls_ssl_own_key( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key for certificate" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Make an RSA signature of the handshake digests + */ + ssl->handshake->calc_verify( ssl, hash ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + { + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(handshake_messages); + * + * sha_hash + * SHA(handshake_messages); + */ + hashlen = 36; + md_alg = MBEDTLS_MD_NONE; + + /* + * For ECDSA, default hash is SHA-1 only + */ + if( mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_ECDSA ) ) + { + hash_start += 16; + hashlen -= 16; + md_alg = MBEDTLS_MD_SHA1; + } + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + /* + * digitally-signed struct { + * opaque handshake_messages[handshake_messages_length]; + * }; + * + * Taking shortcut here. We assume that the server always allows the + * PRF Hash function and has sent it in the allowed signature + * algorithms list received in the Certificate Request message. + * + * Until we encounter a server that does not, we will take this + * shortcut. + * + * Reason: Otherwise we should have running hashes for SHA512 and SHA224 + * in order to satisfy 'weird' needs from the server side. + */ + if( ssl->transform_negotiate->ciphersuite_info->mac == + MBEDTLS_MD_SHA384 ) + { + md_alg = MBEDTLS_MD_SHA384; + ssl->out_msg[4] = MBEDTLS_SSL_HASH_SHA384; + } + else + { + md_alg = MBEDTLS_MD_SHA256; + ssl->out_msg[4] = MBEDTLS_SSL_HASH_SHA256; + } + ssl->out_msg[5] = mbedtls_ssl_sig_from_pk( mbedtls_ssl_own_key( ssl ) ); + + /* Info from md_alg will be used instead */ + hashlen = 0; + offset = 2; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash_start, hashlen, + ssl->out_msg + 6 + offset, &n, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); + return( ret ); + } + + ssl->out_msg[4 + offset] = (unsigned char)( n >> 8 ); + ssl->out_msg[5 + offset] = (unsigned char)( n ); + + ssl->out_msglen = 6 + n + offset; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE_VERIFY; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate verify" ) ); + + return( ret ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_parse_new_session_ticket( mbedtls_ssl_context *ssl ) +{ + int ret; + uint32_t lifetime; + size_t ticket_len; + unsigned char *ticket; + const unsigned char *msg; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse new session ticket" ) ); + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* + * struct { + * uint32 ticket_lifetime_hint; + * opaque ticket<0..2^16-1>; + * } NewSessionTicket; + * + * 0 . 3 ticket_lifetime_hint + * 4 . 5 ticket_len (n) + * 6 . 5+n ticket content + */ + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_NEW_SESSION_TICKET || + ssl->in_hslen < 6 + mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + msg = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + + lifetime = ( msg[0] << 24 ) | ( msg[1] << 16 ) | + ( msg[2] << 8 ) | ( msg[3] ); + + ticket_len = ( msg[4] << 8 ) | ( msg[5] ); + + if( ticket_len + 6 + mbedtls_ssl_hs_hdr_len( ssl ) != ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad new session ticket message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_NEW_SESSION_TICKET ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket length: %d", ticket_len ) ); + + /* We're not waiting for a NewSessionTicket message any more */ + ssl->handshake->new_session_ticket = 0; + ssl->state = MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC; + + /* + * Zero-length ticket means the server changed his mind and doesn't want + * to send a ticket after all, so just forget it + */ + if( ticket_len == 0 ) + return( 0 ); + + mbedtls_zeroize( ssl->session_negotiate->ticket, + ssl->session_negotiate->ticket_len ); + mbedtls_free( ssl->session_negotiate->ticket ); + ssl->session_negotiate->ticket = NULL; + ssl->session_negotiate->ticket_len = 0; + + if( ( ticket = mbedtls_calloc( 1, ticket_len ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ticket alloc failed" ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + memcpy( ticket, msg + 6, ticket_len ); + + ssl->session_negotiate->ticket = ticket; + ssl->session_negotiate->ticket_len = ticket_len; + ssl->session_negotiate->ticket_lifetime = lifetime; + + /* + * RFC 5077 section 3.4: + * "If the client receives a session ticket from the server, then it + * discards any Session ID that was sent in the ServerHello." + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket in use, discarding session id" ) ); + ssl->session_negotiate->id_len = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse new session ticket" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +/* + * SSL handshake -- client side -- single step + */ +int mbedtls_ssl_handshake_client_step( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "client state: %d", ssl->state ) ); + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + return( ret ); + } +#endif + + /* Change state now, so that it is right in mbedtls_ssl_read_record(), used + * by DTLS for dropping out-of-sequence ChangeCipherSpec records */ +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + if( ssl->state == MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC && + ssl->handshake->new_session_ticket != 0 ) + { + ssl->state = MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET; + } +#endif + + switch( ssl->state ) + { + case MBEDTLS_SSL_HELLO_REQUEST: + ssl->state = MBEDTLS_SSL_CLIENT_HELLO; + break; + + /* + * ==> ClientHello + */ + case MBEDTLS_SSL_CLIENT_HELLO: + ret = ssl_write_client_hello( ssl ); + break; + + /* + * <== ServerHello + * Certificate + * ( ServerKeyExchange ) + * ( CertificateRequest ) + * ServerHelloDone + */ + case MBEDTLS_SSL_SERVER_HELLO: + ret = ssl_parse_server_hello( ssl ); + break; + + case MBEDTLS_SSL_SERVER_CERTIFICATE: + ret = mbedtls_ssl_parse_certificate( ssl ); + break; + + case MBEDTLS_SSL_SERVER_KEY_EXCHANGE: + ret = ssl_parse_server_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_REQUEST: + ret = ssl_parse_certificate_request( ssl ); + break; + + case MBEDTLS_SSL_SERVER_HELLO_DONE: + ret = ssl_parse_server_hello_done( ssl ); + break; + + /* + * ==> ( Certificate/Alert ) + * ClientKeyExchange + * ( CertificateVerify ) + * ChangeCipherSpec + * Finished + */ + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + ret = mbedtls_ssl_write_certificate( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: + ret = ssl_write_client_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_VERIFY: + ret = ssl_write_certificate_verify( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC: + ret = mbedtls_ssl_write_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_FINISHED: + ret = mbedtls_ssl_write_finished( ssl ); + break; + + /* + * <== ( NewSessionTicket ) + * ChangeCipherSpec + * Finished + */ +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET: + ret = ssl_parse_new_session_ticket( ssl ); + break; +#endif + + case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC: + ret = mbedtls_ssl_parse_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_SERVER_FINISHED: + ret = mbedtls_ssl_parse_finished( ssl ); + break; + + case MBEDTLS_SSL_FLUSH_BUFFERS: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; + break; + + case MBEDTLS_SSL_HANDSHAKE_WRAPUP: + mbedtls_ssl_handshake_wrapup( ssl ); + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_CLI_C */ diff --git a/c++/src/connect/mbedtls/ssl_cookie.c b/c++/src/connect/mbedtls/ssl_cookie.c new file mode 100644 index 00000000..caf11999 --- /dev/null +++ b/c++/src/connect/mbedtls/ssl_cookie.c @@ -0,0 +1,260 @@ +/* + * DTLS cookie callbacks implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * These session callbacks use a simple chained list + * to store and retrieve the session information. + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_COOKIE_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/ssl_cookie.h" +#include "mbedtls/ssl_internal.h" + +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * If DTLS is in use, then at least one of SHA-1, SHA-256, SHA-512 is + * available. Try SHA-256 first, 512 wastes resources since we need to stay + * with max 32 bytes of cookie for DTLS 1.0 + */ +#if defined(MBEDTLS_SHA256_C) +#define COOKIE_MD MBEDTLS_MD_SHA224 +#define COOKIE_MD_OUTLEN 32 +#define COOKIE_HMAC_LEN 28 +#elif defined(MBEDTLS_SHA512_C) +#define COOKIE_MD MBEDTLS_MD_SHA384 +#define COOKIE_MD_OUTLEN 48 +#define COOKIE_HMAC_LEN 28 +#elif defined(MBEDTLS_SHA1_C) +#define COOKIE_MD MBEDTLS_MD_SHA1 +#define COOKIE_MD_OUTLEN 20 +#define COOKIE_HMAC_LEN 20 +#else +#error "DTLS hello verify needs SHA-1 or SHA-2" +#endif + +/* + * Cookies are formed of a 4-bytes timestamp (or serial number) and + * an HMAC of timestemp and client ID. + */ +#define COOKIE_LEN ( 4 + COOKIE_HMAC_LEN ) + +void mbedtls_ssl_cookie_init( mbedtls_ssl_cookie_ctx *ctx ) +{ + mbedtls_md_init( &ctx->hmac_ctx ); +#if !defined(MBEDTLS_HAVE_TIME) + ctx->serial = 0; +#endif + ctx->timeout = MBEDTLS_SSL_COOKIE_TIMEOUT; + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +void mbedtls_ssl_cookie_set_timeout( mbedtls_ssl_cookie_ctx *ctx, unsigned long delay ) +{ + ctx->timeout = delay; +} + +void mbedtls_ssl_cookie_free( mbedtls_ssl_cookie_ctx *ctx ) +{ + mbedtls_md_free( &ctx->hmac_ctx ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + + mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_cookie_ctx ) ); +} + +int mbedtls_ssl_cookie_setup( mbedtls_ssl_cookie_ctx *ctx, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char key[COOKIE_MD_OUTLEN]; + + if( ( ret = f_rng( p_rng, key, sizeof( key ) ) ) != 0 ) + return( ret ); + + ret = mbedtls_md_setup( &ctx->hmac_ctx, mbedtls_md_info_from_type( COOKIE_MD ), 1 ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_md_hmac_starts( &ctx->hmac_ctx, key, sizeof( key ) ); + if( ret != 0 ) + return( ret ); + + mbedtls_zeroize( key, sizeof( key ) ); + + return( 0 ); +} + +/* + * Generate the HMAC part of a cookie + */ +static int ssl_cookie_hmac( mbedtls_md_context_t *hmac_ctx, + const unsigned char time[4], + unsigned char **p, unsigned char *end, + const unsigned char *cli_id, size_t cli_id_len ) +{ + unsigned char hmac_out[COOKIE_MD_OUTLEN]; + + if( (size_t)( end - *p ) < COOKIE_HMAC_LEN ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + if( mbedtls_md_hmac_reset( hmac_ctx ) != 0 || + mbedtls_md_hmac_update( hmac_ctx, time, 4 ) != 0 || + mbedtls_md_hmac_update( hmac_ctx, cli_id, cli_id_len ) != 0 || + mbedtls_md_hmac_finish( hmac_ctx, hmac_out ) != 0 ) + { + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + memcpy( *p, hmac_out, COOKIE_HMAC_LEN ); + *p += COOKIE_HMAC_LEN; + + return( 0 ); +} + +/* + * Generate cookie for DTLS ClientHello verification + */ +int mbedtls_ssl_cookie_write( void *p_ctx, + unsigned char **p, unsigned char *end, + const unsigned char *cli_id, size_t cli_id_len ) +{ + int ret; + mbedtls_ssl_cookie_ctx *ctx = (mbedtls_ssl_cookie_ctx *) p_ctx; + unsigned long t; + + if( ctx == NULL || cli_id == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( (size_t)( end - *p ) < COOKIE_LEN ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + +#if defined(MBEDTLS_HAVE_TIME) + t = (unsigned long) mbedtls_time( NULL ); +#else + t = ctx->serial++; +#endif + + (*p)[0] = (unsigned char)( t >> 24 ); + (*p)[1] = (unsigned char)( t >> 16 ); + (*p)[2] = (unsigned char)( t >> 8 ); + (*p)[3] = (unsigned char)( t ); + *p += 4; + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + ret ); +#endif + + ret = ssl_cookie_hmac( &ctx->hmac_ctx, *p - 4, + p, end, cli_id, cli_id_len ); + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + + MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Check a cookie + */ +int mbedtls_ssl_cookie_check( void *p_ctx, + const unsigned char *cookie, size_t cookie_len, + const unsigned char *cli_id, size_t cli_id_len ) +{ + unsigned char ref_hmac[COOKIE_HMAC_LEN]; + int ret = 0; + unsigned char *p = ref_hmac; + mbedtls_ssl_cookie_ctx *ctx = (mbedtls_ssl_cookie_ctx *) p_ctx; + unsigned long cur_time, cookie_time; + + if( ctx == NULL || cli_id == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( cookie_len != COOKIE_LEN ) + return( -1 ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + ret ); +#endif + + if( ssl_cookie_hmac( &ctx->hmac_ctx, cookie, + &p, p + sizeof( ref_hmac ), + cli_id, cli_id_len ) != 0 ) + ret = -1; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR + + MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + if( ret != 0 ) + return( ret ); + + if( mbedtls_ssl_safer_memcmp( cookie + 4, ref_hmac, sizeof( ref_hmac ) ) != 0 ) + return( -1 ); + +#if defined(MBEDTLS_HAVE_TIME) + cur_time = (unsigned long) mbedtls_time( NULL ); +#else + cur_time = ctx->serial; +#endif + + cookie_time = ( (unsigned long) cookie[0] << 24 ) | + ( (unsigned long) cookie[1] << 16 ) | + ( (unsigned long) cookie[2] << 8 ) | + ( (unsigned long) cookie[3] ); + + if( ctx->timeout != 0 && cur_time - cookie_time > ctx->timeout ) + return( -1 ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_COOKIE_C */ diff --git a/c++/src/connect/mbedtls/ssl_srv.c b/c++/src/connect/mbedtls/ssl_srv.c new file mode 100644 index 00000000..fc0d2d7b --- /dev/null +++ b/c++/src/connect/mbedtls/ssl_srv.c @@ -0,0 +1,3926 @@ +/* + * SSLv3/TLSv1 server-side functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_SRV_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" + +#include + +#if defined(MBEDTLS_ECP_C) +#include "mbedtls/ecp.h" +#endif + +#if defined(MBEDTLS_HAVE_TIME) +#include "mbedtls/platform_time.h" +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) +int mbedtls_ssl_set_client_transport_id( mbedtls_ssl_context *ssl, + const unsigned char *info, + size_t ilen ) +{ + if( ssl->conf->endpoint != MBEDTLS_SSL_IS_SERVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + mbedtls_free( ssl->cli_id ); + + if( ( ssl->cli_id = mbedtls_calloc( 1, ilen ) ) == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( ssl->cli_id, info, ilen ); + ssl->cli_id_len = ilen; + + return( 0 ); +} + +void mbedtls_ssl_conf_dtls_cookies( mbedtls_ssl_config *conf, + mbedtls_ssl_cookie_write_t *f_cookie_write, + mbedtls_ssl_cookie_check_t *f_cookie_check, + void *p_cookie ) +{ + conf->f_cookie_write = f_cookie_write; + conf->f_cookie_check = f_cookie_check; + conf->p_cookie = p_cookie; +} +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +static int ssl_parse_servername_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + size_t servername_list_size, hostname_len; + const unsigned char *p; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "parse ServerName extension" ) ); + + servername_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( servername_list_size + 2 != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + p = buf + 2; + while( servername_list_size > 0 ) + { + hostname_len = ( ( p[1] << 8 ) | p[2] ); + if( hostname_len + 3 > servername_list_size ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( p[0] == MBEDTLS_TLS_EXT_SERVERNAME_HOSTNAME ) + { + ret = ssl->conf->f_sni( ssl->conf->p_sni, + ssl, p + 3, hostname_len ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_sni_wrapper", ret ); + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNRECOGNIZED_NAME ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + return( 0 ); + } + + servername_list_size -= hostname_len + 3; + p += hostname_len + 3; + } + + if( servername_list_size != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +static int ssl_parse_renegotiation_info( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + /* Check verify-data in constant-time. The length OTOH is no secret */ + if( len != 1 + ssl->verify_data_len || + buf[0] != ssl->verify_data_len || + mbedtls_ssl_safer_memcmp( buf + 1, ssl->peer_verify_data, + ssl->verify_data_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-matching renegotiation info" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + if( len != 1 || buf[0] != 0x0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "non-zero length renegotiation info" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + } + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +static int ssl_parse_signature_algorithms_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t sig_alg_list_size; + const unsigned char *p; + const unsigned char *end = buf + len; + const int *md_cur; + + + sig_alg_list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( sig_alg_list_size + 2 != len || + sig_alg_list_size % 2 != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * For now, ignore the SignatureAlgorithm part and rely on offered + * ciphersuites only for that part. To be fixed later. + * + * So, just look at the HashAlgorithm part. + */ + for( md_cur = ssl->conf->sig_hashes; *md_cur != MBEDTLS_MD_NONE; md_cur++ ) { + for( p = buf + 2; p < end; p += 2 ) { + if( *md_cur == (int) mbedtls_ssl_md_alg_from_hash( p[0] ) ) { + ssl->handshake->sig_alg = p[0]; + goto have_sig_alg; + } + } + } + + /* Some key echanges do not need signatures at all */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no signature_algorithm in common" ) ); + return( 0 ); + +have_sig_alg: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, signature_algorithm ext: %d", + ssl->handshake->sig_alg ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_supported_elliptic_curves( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t list_size, our_size; + const unsigned char *p; + const mbedtls_ecp_curve_info *curve_info, **curves; + + list_size = ( ( buf[0] << 8 ) | ( buf[1] ) ); + if( list_size + 2 != len || + list_size % 2 != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* Should never happen unless client duplicates the extension */ + if( ssl->handshake->curves != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* Don't allow our peer to make us allocate too much memory, + * and leave room for a final 0 */ + our_size = list_size / 2 + 1; + if( our_size > MBEDTLS_ECP_DP_MAX ) + our_size = MBEDTLS_ECP_DP_MAX; + + if( ( curves = mbedtls_calloc( our_size, sizeof( *curves ) ) ) == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ssl->handshake->curves = curves; + + p = buf + 2; + while( list_size > 0 && our_size > 1 ) + { + curve_info = mbedtls_ecp_curve_info_from_tls_id( ( p[0] << 8 ) | p[1] ); + + if( curve_info != NULL ) + { + *curves++ = curve_info; + our_size--; + } + + list_size -= 2; + p += 2; + } + + return( 0 ); +} + +static int ssl_parse_supported_point_formats( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + size_t list_size; + const unsigned char *p; + + list_size = buf[0]; + if( list_size + 1 != len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + p = buf + 1; + while( list_size > 0 ) + { + if( p[0] == MBEDTLS_ECP_PF_UNCOMPRESSED || + p[0] == MBEDTLS_ECP_PF_COMPRESSED ) + { +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + ssl->handshake->ecdh_ctx.point_format = p[0]; +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl->handshake->ecjpake_ctx.point_format = p[0]; +#endif + MBEDTLS_SSL_DEBUG_MSG( 4, ( "point format selected: %d", p[0] ) ); + return( 0 ); + } + + list_size--; + p++; + } + + return( 0 ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static int ssl_parse_ecjpake_kkpp( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + int ret; + + if( mbedtls_ecjpake_check( &ssl->handshake->ecjpake_ctx ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip ecjpake kkpp extension" ) ); + return( 0 ); + } + + if( ( ret = mbedtls_ecjpake_read_round_one( &ssl->handshake->ecjpake_ctx, + buf, len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_one", ret ); + return( ret ); + } + + /* Only mark the extension as OK when we're sure it is */ + ssl->handshake->cli_exts |= MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static int ssl_parse_max_fragment_length_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 1 || buf[0] >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->session_negotiate->mfl_code = buf[0]; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static int ssl_parse_truncated_hmac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ((void) buf); + + if( ssl->conf->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_ENABLED ) + ssl->session_negotiate->trunc_hmac = MBEDTLS_SSL_TRUNC_HMAC_ENABLED; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static int ssl_parse_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ((void) buf); + + if( ssl->conf->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED && + ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl->session_negotiate->encrypt_then_mac = MBEDTLS_SSL_ETM_ENABLED; + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static int ssl_parse_extended_ms_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, + size_t len ) +{ + if( len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ((void) buf); + + if( ssl->conf->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED && + ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl->handshake->extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED; + } + + return( 0 ); +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_parse_session_ticket_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t len ) +{ + int ret; + mbedtls_ssl_session session; + + mbedtls_ssl_session_init( &session ); + + if( ssl->conf->f_ticket_parse == NULL || + ssl->conf->f_ticket_write == NULL ) + { + return( 0 ); + } + + /* Remember the client asked us to send a new ticket */ + ssl->handshake->new_session_ticket = 1; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket length: %d", len ) ); + + if( len == 0 ) + return( 0 ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket rejected: renegotiating" ) ); + return( 0 ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + /* + * Failures are ok: just ignore the ticket and proceed. + */ + if( ( ret = ssl->conf->f_ticket_parse( ssl->conf->p_ticket, &session, + buf, len ) ) != 0 ) + { + mbedtls_ssl_session_free( &session ); + + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is not authentic" ) ); + else if( ret == MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED ) + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ticket is expired" ) ); + else + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_ticket_parse", ret ); + + return( 0 ); + } + + /* + * Keep the session ID sent by the client, since we MUST send it back to + * inform them we're accepting the ticket (RFC 5077 section 3.4) + */ + session.id_len = ssl->session_negotiate->id_len; + memcpy( &session.id, ssl->session_negotiate->id, session.id_len ); + + mbedtls_ssl_session_free( ssl->session_negotiate ); + memcpy( ssl->session_negotiate, &session, sizeof( mbedtls_ssl_session ) ); + + /* Zeroize instead of free as we copied the content */ + mbedtls_zeroize( &session, sizeof( mbedtls_ssl_session ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "session successfully restored from ticket" ) ); + + ssl->handshake->resume = 1; + + /* Don't send a new ticket after all, this one is OK */ + ssl->handshake->new_session_ticket = 0; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_ALPN) +static int ssl_parse_alpn_ext( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + size_t list_len, cur_len, ours_len; + const unsigned char *theirs, *start, *end; + const char **ours; + + /* If ALPN not configured, just ignore the extension */ + if( ssl->conf->alpn_list == NULL ) + return( 0 ); + + /* + * opaque ProtocolName<1..2^8-1>; + * + * struct { + * ProtocolName protocol_name_list<2..2^16-1> + * } ProtocolNameList; + */ + + /* Min length is 2 (list_len) + 1 (name_len) + 1 (name) */ + if( len < 4 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + list_len = ( buf[0] << 8 ) | buf[1]; + if( list_len != len - 2 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + /* + * Use our order of preference + */ + start = buf + 2; + end = buf + len; + for( ours = ssl->conf->alpn_list; *ours != NULL; ours++ ) + { + ours_len = strlen( *ours ); + for( theirs = start; theirs != end; theirs += cur_len ) + { + /* If the list is well formed, we should get equality first */ + if( theirs > end ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + cur_len = *theirs++; + + /* Empty strings MUST NOT be included */ + if( cur_len == 0 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + if( cur_len == ours_len && + memcmp( theirs, *ours, cur_len ) == 0 ) + { + ssl->alpn_chosen = *ours; + return( 0 ); + } + } + } + + /* If we get there, no match was found */ + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +/* + * Auxiliary functions for ServerHello parsing and related actions + */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +/* + * Return 0 if the given key uses one of the acceptable curves, -1 otherwise + */ +#if defined(MBEDTLS_ECDSA_C) +static int ssl_check_key_curve( mbedtls_pk_context *pk, + const mbedtls_ecp_curve_info **curves ) +{ + const mbedtls_ecp_curve_info **crv = curves; + mbedtls_ecp_group_id grp_id = mbedtls_pk_ec( *pk )->grp.id; + + while( *crv != NULL ) + { + if( (*crv)->grp_id == grp_id ) + return( 0 ); + crv++; + } + + return( -1 ); +} +#endif /* MBEDTLS_ECDSA_C */ + +/* + * Try picking a certificate for this ciphersuite, + * return 0 on success and -1 on failure. + */ +static int ssl_pick_cert( mbedtls_ssl_context *ssl, + const mbedtls_ssl_ciphersuite_t * ciphersuite_info ) +{ + mbedtls_ssl_key_cert *cur, *list, *fallback = NULL; + mbedtls_pk_type_t pk_alg = mbedtls_ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ); + uint32_t flags; + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_key_cert != NULL ) + list = ssl->handshake->sni_key_cert; + else +#endif + list = ssl->conf->key_cert; + + if( pk_alg == MBEDTLS_PK_NONE ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite requires certificate" ) ); + + if( list == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server has no certificate" ) ); + return( -1 ); + } + + for( cur = list; cur != NULL; cur = cur->next ) + { + MBEDTLS_SSL_DEBUG_CRT( 3, "candidate certificate chain, certificate", + cur->cert ); + + if( ! mbedtls_pk_can_do( cur->key, pk_alg ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: key type" ) ); + continue; + } + + /* + * This avoids sending the client a cert it'll reject based on + * keyUsage or other extensions. + * + * It also allows the user to provision different certificates for + * different uses based on keyUsage, eg if they want to avoid signing + * and decrypting with the same RSA key. + */ + if( mbedtls_ssl_check_cert_usage( cur->cert, ciphersuite_info, + MBEDTLS_SSL_IS_SERVER, &flags ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: " + "(extended) key usage extension" ) ); + continue; + } + +#if defined(MBEDTLS_ECDSA_C) + if( pk_alg == MBEDTLS_PK_ECDSA && + ssl_check_key_curve( cur->key, ssl->handshake->curves ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate mismatch: elliptic curve" ) ); + continue; + } +#endif + + /* + * Try to select a SHA-1 certificate for pre-1.2 clients, but still + * present them a SHA-higher cert rather than failing if it's the only + * one we got that satisfies the other conditions. + */ + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 && + cur->cert->sig_md != MBEDTLS_MD_SHA1 ) + { + if( fallback == NULL ) + fallback = cur; + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "certificate not preferred: " + "sha-2 with pre-TLS 1.2 client" ) ); + continue; + } + } + + /* If we get there, we got a winner */ + break; + } + + if( cur == NULL ) + cur = fallback; + + /* Do not update ssl->handshake->key_cert unless there is a match */ + if( cur != NULL ) + { + ssl->handshake->key_cert = cur; + MBEDTLS_SSL_DEBUG_CRT( 3, "selected certificate chain, certificate", + ssl->handshake->key_cert->cert ); + return( 0 ); + } + + return( -1 ); +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* + * Check if a given ciphersuite is suitable for use with our config/keys/etc + * Sets ciphersuite_info only if the suite matches. + */ +static int ssl_ciphersuite_match( mbedtls_ssl_context *ssl, int suite_id, + const mbedtls_ssl_ciphersuite_t **ciphersuite_info ) +{ + const mbedtls_ssl_ciphersuite_t *suite_info; + + suite_info = mbedtls_ssl_ciphersuite_from_id( suite_id ); + if( suite_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "trying ciphersuite: %s", suite_info->name ) ); + + if( suite_info->min_minor_ver > ssl->minor_ver || + suite_info->max_minor_ver < ssl->minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: version" ) ); + return( 0 ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ( suite_info->flags & MBEDTLS_CIPHERSUITE_NODTLS ) ) + return( 0 ); +#endif + +#if defined(MBEDTLS_ARC4_C) + if( ssl->conf->arc4_disabled == MBEDTLS_SSL_ARC4_DISABLED && + suite_info->cipher == MBEDTLS_CIPHER_ARC4_128 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: rc4" ) ); + return( 0 ); + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( suite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE && + ( ssl->handshake->cli_exts & MBEDTLS_TLS_EXT_ECJPAKE_KKPP_OK ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: ecjpake " + "not configured or ext missing" ) ); + return( 0 ); + } +#endif + + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) + if( mbedtls_ssl_ciphersuite_uses_ec( suite_info ) && + ( ssl->handshake->curves == NULL || + ssl->handshake->curves[0] == NULL ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: " + "no common elliptic curve" ) ); + return( 0 ); + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + /* If the ciphersuite requires a pre-shared key and we don't + * have one, skip it now rather than failing later */ + if( mbedtls_ssl_ciphersuite_uses_psk( suite_info ) && + ssl->conf->f_psk == NULL && + ( ssl->conf->psk == NULL || ssl->conf->psk_identity == NULL || + ssl->conf->psk_identity_len == 0 || ssl->conf->psk_len == 0 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: no pre-shared key" ) ); + return( 0 ); + } +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + /* + * Final check: if ciphersuite requires us to have a + * certificate/key of a particular type: + * - select the appropriate certificate if we have one, or + * - try the next ciphersuite if we don't + * This must be done last since we modify the key_cert list. + */ + if( ssl_pick_cert( ssl, suite_info ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite mismatch: " + "no suitable certificate" ) ); + return( 0 ); + } +#endif + + *ciphersuite_info = suite_info; + return( 0 ); +} + +#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) +static int ssl_parse_client_hello_v2( mbedtls_ssl_context *ssl ) +{ + int ret, got_common_suite; + unsigned int i, j; + size_t n; + unsigned int ciph_len, sess_len, chal_len; + unsigned char *buf, *p; + const int *ciphersuites; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client hello v2" ) ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client hello v2 illegal for renegotiation" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + buf = ssl->in_hdr; + + MBEDTLS_SSL_DEBUG_BUF( 4, "record header", buf, 5 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v2, message type: %d", + buf[2] ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v2, message len.: %d", + ( ( buf[0] & 0x7F ) << 8 ) | buf[1] ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v2, max. version: [%d:%d]", + buf[3], buf[4] ) ); + + /* + * SSLv2 Client Hello + * + * Record layer: + * 0 . 1 message length + * + * SSL layer: + * 2 . 2 message type + * 3 . 4 protocol version + */ + if( buf[2] != MBEDTLS_SSL_HS_CLIENT_HELLO || + buf[3] != MBEDTLS_SSL_MAJOR_VERSION_3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + n = ( ( buf[0] << 8 ) | buf[1] ) & 0x7FFF; + + if( n < 17 || n > 512 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->major_ver = MBEDTLS_SSL_MAJOR_VERSION_3; + ssl->minor_ver = ( buf[4] <= ssl->conf->max_minor_ver ) + ? buf[4] : ssl->conf->max_minor_ver; + + if( ssl->minor_ver < ssl->conf->min_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum" + " [%d:%d] < [%d:%d]", + ssl->major_ver, ssl->minor_ver, + ssl->conf->min_major_ver, ssl->conf->min_minor_ver ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + ssl->handshake->max_major_ver = buf[3]; + ssl->handshake->max_minor_ver = buf[4]; + + if( ( ret = mbedtls_ssl_fetch_input( ssl, 2 + n ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + ssl->handshake->update_checksum( ssl, buf + 2, n ); + + buf = ssl->in_msg; + n = ssl->in_left - 5; + + /* + * 0 . 1 ciphersuitelist length + * 2 . 3 session id length + * 4 . 5 challenge length + * 6 . .. ciphersuitelist + * .. . .. session id + * .. . .. challenge + */ + MBEDTLS_SSL_DEBUG_BUF( 4, "record contents", buf, n ); + + ciph_len = ( buf[0] << 8 ) | buf[1]; + sess_len = ( buf[2] << 8 ) | buf[3]; + chal_len = ( buf[4] << 8 ) | buf[5]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciph_len: %d, sess_len: %d, chal_len: %d", + ciph_len, sess_len, chal_len ) ); + + /* + * Make sure each parameter length is valid + */ + if( ciph_len < 3 || ( ciph_len % 3 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( sess_len > 32 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( chal_len < 8 || chal_len > 32 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( n != 6 + ciph_len + sess_len + chal_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", + buf + 6, ciph_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, session id", + buf + 6 + ciph_len, sess_len ); + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, challenge", + buf + 6 + ciph_len + sess_len, chal_len ); + + p = buf + 6 + ciph_len; + ssl->session_negotiate->id_len = sess_len; + memset( ssl->session_negotiate->id, 0, + sizeof( ssl->session_negotiate->id ) ); + memcpy( ssl->session_negotiate->id, p, ssl->session_negotiate->id_len ); + + p += sess_len; + memset( ssl->handshake->randbytes, 0, 64 ); + memcpy( ssl->handshake->randbytes + 32 - chal_len, p, chal_len ); + + /* + * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ + for( i = 0, p = buf + 6; i < ciph_len; i += 3, p += 3 ) + { + if( p[0] == 0 && p[1] == 0 && p[2] == MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV " + "during renegotiation" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + break; + } + } + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + for( i = 0, p = buf + 6; i < ciph_len; i += 3, p += 3 ) + { + if( p[0] == 0 && + p[1] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE >> 8 ) & 0xff ) && + p[2] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE ) & 0xff ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "received FALLBACK_SCSV" ) ); + + if( ssl->minor_ver < ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "inapropriate fallback" ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + break; + } + } +#endif /* MBEDTLS_SSL_FALLBACK_SCSV */ + + got_common_suite = 0; + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + ciphersuite_info = NULL; +#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 ) + { + for( i = 0; ciphersuites[i] != 0; i++ ) +#else + for( i = 0; ciphersuites[i] != 0; i++ ) + { + for( j = 0, p = buf + 6; j < ciph_len; j += 3, p += 3 ) +#endif + { + if( p[0] != 0 || + p[1] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) || + p[2] != ( ( ciphersuites[i] ) & 0xFF ) ) + continue; + + got_common_suite = 1; + + if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i], + &ciphersuite_info ) ) != 0 ) + return( ret ); + + if( ciphersuite_info != NULL ) + goto have_ciphersuite_v2; + } + } + + if( got_common_suite ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, " + "but none of them usable" ) ); + return( MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); + return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + } + +have_ciphersuite_v2: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s", ciphersuite_info->name ) ); + + ssl->session_negotiate->ciphersuite = ciphersuites[i]; + ssl->transform_negotiate->ciphersuite_info = ciphersuite_info; + + /* + * SSLv2 Client Hello relevant renegotiation security checks + */ + if( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->in_left = 0; + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse client hello v2" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO */ + +static int ssl_parse_client_hello( mbedtls_ssl_context *ssl ) +{ + int ret, got_common_suite; + size_t i, j; + size_t ciph_offset, comp_offset, ext_offset; + size_t msg_len, ciph_len, sess_len, comp_len, ext_len; +#if defined(MBEDTLS_SSL_PROTO_DTLS) + size_t cookie_offset, cookie_len; +#endif + unsigned char *buf, *p, *ext; +#if defined(MBEDTLS_SSL_RENEGOTIATION) + int renegotiation_info_seen = 0; +#endif + int handshake_failure = 0; + const int *ciphersuites; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + int major, minor; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client hello" ) ); + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +read_record_header: +#endif + /* + * If renegotiating, then the input was read with mbedtls_ssl_read_record(), + * otherwise read it ourselves manually in order to support SSLv2 + * ClientHello, which doesn't use the same record layer format. + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE ) +#endif + { + if( ( ret = mbedtls_ssl_fetch_input( ssl, 5 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + } + + buf = ssl->in_hdr; + +#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_STREAM ) +#endif + if( ( buf[0] & 0x80 ) != 0 ) + return ssl_parse_client_hello_v2( ssl ); +#endif + + MBEDTLS_SSL_DEBUG_BUF( 4, "record header", buf, mbedtls_ssl_hdr_len( ssl ) ); + + /* + * SSLv3/TLS Client Hello + * + * Record layer: + * 0 . 0 message type + * 1 . 2 protocol version + * 3 . 11 DTLS: epoch + record sequence number + * 3 . 4 message length + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, message type: %d", + buf[0] ) ); + + if( buf[0] != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, message len.: %d", + ( ssl->in_len[0] << 8 ) | ssl->in_len[1] ) ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, protocol version: [%d:%d]", + buf[1], buf[2] ) ); + + mbedtls_ssl_read_version( &major, &minor, ssl->conf->transport, buf + 1 ); + + /* According to RFC 5246 Appendix E.1, the version here is typically + * "{03,00}, the lowest version number supported by the client, [or] the + * value of ClientHello.client_version", so the only meaningful check here + * is the major version shouldn't be less than 3 */ + if( major < MBEDTLS_SSL_MAJOR_VERSION_3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* For DTLS if this is the initial handshake, remember the client sequence + * number to use it in our next message (RFC 6347 4.2.1) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM +#if defined(MBEDTLS_SSL_RENEGOTIATION) + && ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE +#endif + ) + { + /* Epoch should be 0 for initial handshakes */ + if( ssl->in_ctr[0] != 0 || ssl->in_ctr[1] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + memcpy( ssl->out_ctr + 2, ssl->in_ctr + 2, 6 ); + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + if( mbedtls_ssl_dtls_replay_check( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "replayed record, discarding" ) ); + ssl->next_record_offset = 0; + ssl->in_left = 0; + goto read_record_header; + } + + /* No MAC to check yet, so we can update right now */ + mbedtls_ssl_dtls_replay_update( ssl ); +#endif + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + msg_len = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + /* Set by mbedtls_ssl_read_record() */ + msg_len = ssl->in_hslen; + } + else +#endif + { + if( msg_len > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + if( ( ret = mbedtls_ssl_fetch_input( ssl, mbedtls_ssl_hdr_len( ssl ) + msg_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + /* Done reading this record, get ready for the next one */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + ssl->next_record_offset = msg_len + mbedtls_ssl_hdr_len( ssl ); + else +#endif + ssl->in_left = 0; + } + + buf = ssl->in_msg; + + MBEDTLS_SSL_DEBUG_BUF( 4, "record contents", buf, msg_len ); + + ssl->handshake->update_checksum( ssl, buf, msg_len ); + + /* + * Handshake layer: + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 DTLS only: message seqence number + * 6 . 8 DTLS only: fragment offset + * 9 . 11 DTLS only: fragment length + */ + if( msg_len < mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, handshake type: %d", buf[0] ) ); + + if( buf[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "client hello v3, handshake len.: %d", + ( buf[1] << 16 ) | ( buf[2] << 8 ) | buf[3] ) ); + + /* We don't support fragmentation of ClientHello (yet?) */ + if( buf[1] != 0 || + msg_len != mbedtls_ssl_hs_hdr_len( ssl ) + ( ( buf[2] << 8 ) | buf[3] ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + /* + * Copy the client's handshake message_seq on initial handshakes, + * check sequence number on renego. + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + /* This couldn't be done in ssl_prepare_handshake_record() */ + unsigned int cli_msg_seq = ( ssl->in_msg[4] << 8 ) | + ssl->in_msg[5]; + + if( cli_msg_seq != ssl->handshake->in_msg_seq ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message_seq: " + "%d (expected %d)", cli_msg_seq, + ssl->handshake->in_msg_seq ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ssl->handshake->in_msg_seq++; + } + else +#endif + { + unsigned int cli_msg_seq = ( ssl->in_msg[4] << 8 ) | + ssl->in_msg[5]; + ssl->handshake->out_msg_seq = cli_msg_seq; + ssl->handshake->in_msg_seq = cli_msg_seq + 1; + } + + /* + * For now we don't support fragmentation, so make sure + * fragment_offset == 0 and fragment_length == length + */ + if( ssl->in_msg[6] != 0 || ssl->in_msg[7] != 0 || ssl->in_msg[8] != 0 || + memcmp( ssl->in_msg + 1, ssl->in_msg + 9, 3 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "ClientHello fragmentation not supported" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + buf += mbedtls_ssl_hs_hdr_len( ssl ); + msg_len -= mbedtls_ssl_hs_hdr_len( ssl ); + + /* + * ClientHello layer: + * 0 . 1 protocol version + * 2 . 33 random bytes (starting with 4 bytes of Unix time) + * 34 . 35 session id length (1 byte) + * 35 . 34+x session id + * 35+x . 35+x DTLS only: cookie length (1 byte) + * 36+x . .. DTLS only: cookie + * .. . .. ciphersuite list length (2 bytes) + * .. . .. ciphersuite list + * .. . .. compression alg. list length (1 byte) + * .. . .. compression alg. list + * .. . .. extensions length (2 bytes, optional) + * .. . .. extensions (optional) + */ + + /* + * Minimal length (with everything empty and extensions ommitted) is + * 2 + 32 + 1 + 2 + 1 = 38 bytes. Check that first, so that we can + * read at least up to session id length without worrying. + */ + if( msg_len < 38 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Check and save the protocol version + */ + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, version", buf, 2 ); + + mbedtls_ssl_read_version( &ssl->major_ver, &ssl->minor_ver, + ssl->conf->transport, buf ); + + ssl->handshake->max_major_ver = ssl->major_ver; + ssl->handshake->max_minor_ver = ssl->minor_ver; + + if( ssl->major_ver < ssl->conf->min_major_ver || + ssl->minor_ver < ssl->conf->min_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "client only supports ssl smaller than minimum" + " [%d:%d] < [%d:%d]", + ssl->major_ver, ssl->minor_ver, + ssl->conf->min_major_ver, ssl->conf->min_minor_ver ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION ); + + return( MBEDTLS_ERR_SSL_BAD_HS_PROTOCOL_VERSION ); + } + + if( ssl->major_ver > ssl->conf->max_major_ver ) + { + ssl->major_ver = ssl->conf->max_major_ver; + ssl->minor_ver = ssl->conf->max_minor_ver; + } + else if( ssl->minor_ver > ssl->conf->max_minor_ver ) + ssl->minor_ver = ssl->conf->max_minor_ver; + + /* + * Save client random (inc. Unix time) + */ + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, random bytes", buf + 2, 32 ); + + memcpy( ssl->handshake->randbytes, buf + 2, 32 ); + + /* + * Check the session ID length and save session ID + */ + sess_len = buf[34]; + + if( sess_len > sizeof( ssl->session_negotiate->id ) || + sess_len + 34 + 2 > msg_len ) /* 2 for cipherlist length field */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, session id", buf + 35, sess_len ); + + ssl->session_negotiate->id_len = sess_len; + memset( ssl->session_negotiate->id, 0, + sizeof( ssl->session_negotiate->id ) ); + memcpy( ssl->session_negotiate->id, buf + 35, + ssl->session_negotiate->id_len ); + + /* + * Check the cookie length and content + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + cookie_offset = 35 + sess_len; + cookie_len = buf[cookie_offset]; + + if( cookie_offset + 1 + cookie_len + 2 > msg_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, cookie", + buf + cookie_offset + 1, cookie_len ); + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) + if( ssl->conf->f_cookie_check != NULL +#if defined(MBEDTLS_SSL_RENEGOTIATION) + && ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE +#endif + ) + { + if( ssl->conf->f_cookie_check( ssl->conf->p_cookie, + buf + cookie_offset + 1, cookie_len, + ssl->cli_id, ssl->cli_id_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification failed" ) ); + ssl->handshake->verify_cookie_len = 1; + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification passed" ) ); + ssl->handshake->verify_cookie_len = 0; + } + } + else +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + { + /* We know we didn't send a cookie, so it should be empty */ + if( cookie_len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "cookie verification skipped" ) ); + } + + /* + * Check the ciphersuitelist length (will be parsed later) + */ + ciph_offset = cookie_offset + 1 + cookie_len; + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + ciph_offset = 35 + sess_len; + + ciph_len = ( buf[ciph_offset + 0] << 8 ) + | ( buf[ciph_offset + 1] ); + + if( ciph_len < 2 || + ciph_len + 2 + ciph_offset + 1 > msg_len || /* 1 for comp. alg. len */ + ( ciph_len % 2 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, ciphersuitelist", + buf + ciph_offset + 2, ciph_len ); + + /* + * Check the compression algorithms length and pick one + */ + comp_offset = ciph_offset + 2 + ciph_len; + + comp_len = buf[comp_offset]; + + if( comp_len < 1 || + comp_len > 16 || + comp_len + comp_offset + 1 > msg_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello, compression", + buf + comp_offset + 1, comp_len ); + + ssl->session_negotiate->compression = MBEDTLS_SSL_COMPRESS_NULL; +#if defined(MBEDTLS_ZLIB_SUPPORT) + for( i = 0; i < comp_len; ++i ) + { + if( buf[comp_offset + 1 + i] == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + ssl->session_negotiate->compression = MBEDTLS_SSL_COMPRESS_DEFLATE; + break; + } + } +#endif + + /* See comments in ssl_write_client_hello() */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + ssl->session_negotiate->compression = MBEDTLS_SSL_COMPRESS_NULL; +#endif + + /* Do not parse the extensions if the protocol is SSLv3 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ( ssl->major_ver != 3 ) || ( ssl->minor_ver != 0 ) ) + { +#endif + /* + * Check the extension length + */ + ext_offset = comp_offset + 1 + comp_len; + if( msg_len > ext_offset ) + { + if( msg_len < ext_offset + 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + ext_len = ( buf[ext_offset + 0] << 8 ) + | ( buf[ext_offset + 1] ); + + if( ( ext_len > 0 && ext_len < 4 ) || + msg_len != ext_offset + 2 + ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } + else + ext_len = 0; + + ext = buf + ext_offset + 2; + MBEDTLS_SSL_DEBUG_BUF( 3, "client hello extensions", ext, ext_len ); + + while( ext_len != 0 ) + { + unsigned int ext_id = ( ( ext[0] << 8 ) + | ( ext[1] ) ); + unsigned int ext_size = ( ( ext[2] << 8 ) + | ( ext[3] ) ); + + if( ext_size + 4 > ext_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + switch( ext_id ) + { +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + case MBEDTLS_TLS_EXT_SERVERNAME: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ServerName extension" ) ); + if( ssl->conf->f_sni == NULL ) + break; + + ret = ssl_parse_servername_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + + case MBEDTLS_TLS_EXT_RENEGOTIATION_INFO: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found renegotiation extension" ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + renegotiation_info_seen = 1; +#endif + + ret = ssl_parse_renegotiation_info( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) && \ + defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + case MBEDTLS_TLS_EXT_SIG_ALG: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found signature_algorithms extension" ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + break; +#endif + + ret = ssl_parse_signature_algorithms_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 && + MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_SUPPORTED_ELLIPTIC_CURVES: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported elliptic curves extension" ) ); + + ret = ssl_parse_supported_elliptic_curves( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; + + case MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found supported point formats extension" ) ); + ssl->handshake->cli_exts |= MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT; + + ret = ssl_parse_supported_point_formats( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || + MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + case MBEDTLS_TLS_EXT_ECJPAKE_KKPP: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found ecjpake kkpp extension" ) ); + + ret = ssl_parse_ecjpake_kkpp( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + case MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found max fragment length extension" ) ); + + ret = ssl_parse_max_fragment_length_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + case MBEDTLS_TLS_EXT_TRUNCATED_HMAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found truncated hmac extension" ) ); + + ret = ssl_parse_truncated_hmac_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + case MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found encrypt then mac extension" ) ); + + ret = ssl_parse_encrypt_then_mac_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + case MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found extended master secret extension" ) ); + + ret = ssl_parse_extended_ms_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + case MBEDTLS_TLS_EXT_SESSION_TICKET: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found session ticket extension" ) ); + + ret = ssl_parse_session_ticket_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_ALPN) + case MBEDTLS_TLS_EXT_ALPN: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "found alpn extension" ) ); + + ret = ssl_parse_alpn_ext( ssl, ext + 4, ext_size ); + if( ret != 0 ) + return( ret ); + break; +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + + default: + MBEDTLS_SSL_DEBUG_MSG( 3, ( "unknown extension found: %d (ignoring)", + ext_id ) ); + } + + ext_len -= 4 + ext_size; + ext += 4 + ext_size; + + if( ext_len > 0 && ext_len < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client hello message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + } +#if defined(MBEDTLS_SSL_PROTO_SSL3) + } +#endif + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + for( i = 0, p = buf + 41 + sess_len; i < ciph_len; i += 2, p += 2 ) + { + if( p[0] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE >> 8 ) & 0xff ) && + p[1] == (unsigned char)( ( MBEDTLS_SSL_FALLBACK_SCSV_VALUE ) & 0xff ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received FALLBACK_SCSV" ) ); + + if( ssl->minor_ver < ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "inapropriate fallback" ) ); + + mbedtls_ssl_send_alert_message( ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_INAPROPRIATE_FALLBACK ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + break; + } + } +#endif /* MBEDTLS_SSL_FALLBACK_SCSV */ + + /* + * Check for TLS_EMPTY_RENEGOTIATION_INFO_SCSV + */ + for( i = 0, p = buf + ciph_offset + 2; i < ciph_len; i += 2, p += 2 ) + { + if( p[0] == 0 && p[1] == MBEDTLS_SSL_EMPTY_RENEGOTIATION_INFO ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "received TLS_EMPTY_RENEGOTIATION_INFO " ) ); +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received RENEGOTIATION SCSV during renegotiation" ) ); + + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } +#endif + ssl->secure_renegotiation = MBEDTLS_SSL_SECURE_RENEGOTIATION; + break; + } + } + + /* + * Renegotiation security checks + */ + if( ssl->secure_renegotiation != MBEDTLS_SSL_SECURE_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_BREAK_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation, breaking off handshake" ) ); + handshake_failure = 1; + } +#if defined(MBEDTLS_SSL_RENEGOTIATION) + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_SECURE_RENEGOTIATION && + renegotiation_info_seen == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension missing (secure)" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "legacy renegotiation not allowed" ) ); + handshake_failure = 1; + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + renegotiation_info_seen == 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation_info extension present (legacy)" ) ); + handshake_failure = 1; + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + if( handshake_failure == 1 ) + { + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + /* + * Search for a matching ciphersuite + * (At the end because we need information from the EC-based extensions + * and certificate from the SNI callback triggered by the SNI extension.) + */ + got_common_suite = 0; + ciphersuites = ssl->conf->ciphersuite_list[ssl->minor_ver]; + ciphersuite_info = NULL; +#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 ) + { + for( i = 0; ciphersuites[i] != 0; i++ ) +#else + for( i = 0; ciphersuites[i] != 0; i++ ) + { + for( j = 0, p = buf + ciph_offset + 2; j < ciph_len; j += 2, p += 2 ) +#endif + { + if( p[0] != ( ( ciphersuites[i] >> 8 ) & 0xFF ) || + p[1] != ( ( ciphersuites[i] ) & 0xFF ) ) + continue; + + got_common_suite = 1; + + if( ( ret = ssl_ciphersuite_match( ssl, ciphersuites[i], + &ciphersuite_info ) ) != 0 ) + return( ret ); + + if( ciphersuite_info != NULL ) + goto have_ciphersuite; + } + } + + if( got_common_suite ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got ciphersuites in common, " + "but none of them usable" ) ); + mbedtls_ssl_send_fatal_handshake_failure( ssl ); + return( MBEDTLS_ERR_SSL_NO_USABLE_CIPHERSUITE ); + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no ciphersuites in common" ) ); + mbedtls_ssl_send_fatal_handshake_failure( ssl ); + return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + } + +have_ciphersuite: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "selected ciphersuite: %s", ciphersuite_info->name ) ); + + ssl->session_negotiate->ciphersuite = ciphersuites[i]; + ssl->transform_negotiate->ciphersuite_info = ciphersuite_info; + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_recv_flight_completed( ssl ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse client hello" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +static void ssl_write_truncated_hmac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->session_negotiate->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_DISABLED ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding truncated hmac extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_TRUNCATED_HMAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +static void ssl_write_encrypt_then_mac_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + const mbedtls_ssl_ciphersuite_t *suite = NULL; + const mbedtls_cipher_info_t *cipher = NULL; + + if( ssl->session_negotiate->encrypt_then_mac == MBEDTLS_SSL_EXTENDED_MS_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + *olen = 0; + return; + } + + /* + * RFC 7366: "If a server receives an encrypt-then-MAC request extension + * from a client and then selects a stream or Authenticated Encryption + * with Associated Data (AEAD) ciphersuite, it MUST NOT send an + * encrypt-then-MAC response extension back to the client." + */ + if( ( suite = mbedtls_ssl_ciphersuite_from_id( + ssl->session_negotiate->ciphersuite ) ) == NULL || + ( cipher = mbedtls_cipher_info_from_type( suite->cipher ) ) == NULL || + cipher->mode != MBEDTLS_MODE_CBC ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding encrypt then mac extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ENCRYPT_THEN_MAC ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +static void ssl_write_extended_ms_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_DISABLED || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding extended master secret " + "extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_EXTENDED_MASTER_SECRET ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static void ssl_write_session_ticket_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->handshake->new_session_ticket == 0 ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding session ticket extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SESSION_TICKET ) & 0xFF ); + + *p++ = 0x00; + *p++ = 0x00; + + *olen = 4; +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +static void ssl_write_renegotiation_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->secure_renegotiation != MBEDTLS_SSL_SECURE_RENEGOTIATION ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, secure renegotiation extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_RENEGOTIATION_INFO ) & 0xFF ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status != MBEDTLS_SSL_INITIAL_HANDSHAKE ) + { + *p++ = 0x00; + *p++ = ( ssl->verify_data_len * 2 + 1 ) & 0xFF; + *p++ = ssl->verify_data_len * 2 & 0xFF; + + memcpy( p, ssl->peer_verify_data, ssl->verify_data_len ); + p += ssl->verify_data_len; + memcpy( p, ssl->own_verify_data, ssl->verify_data_len ); + p += ssl->verify_data_len; + } + else +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + { + *p++ = 0x00; + *p++ = 0x01; + *p++ = 0x00; + } + + *olen = p - buf; +} + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +static void ssl_write_max_fragment_length_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + + if( ssl->session_negotiate->mfl_code == MBEDTLS_SSL_MAX_FRAG_LEN_NONE ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, max_fragment_length extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_MAX_FRAGMENT_LENGTH ) & 0xFF ); + + *p++ = 0x00; + *p++ = 1; + + *p++ = ssl->session_negotiate->mfl_code; + + *olen = 5; +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_supported_point_formats_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + unsigned char *p = buf; + ((void) ssl); + + if( ( ssl->handshake->cli_exts & + MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS_PRESENT ) == 0 ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, supported_point_formats extension" ) ); + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_SUPPORTED_POINT_FORMATS ) & 0xFF ); + + *p++ = 0x00; + *p++ = 2; + + *p++ = 1; + *p++ = MBEDTLS_ECP_PF_UNCOMPRESSED; + + *olen = 6; +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C || MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +static void ssl_write_ecjpake_kkpp_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, + size_t *olen ) +{ + int ret; + unsigned char *p = buf; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + size_t kkpp_len; + + *olen = 0; + + /* Skip costly computation if not needed */ + if( ssl->transform_negotiate->ciphersuite_info->key_exchange != + MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, ecjpake kkpp extension" ) ); + + if( end - p < 4 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "buffer too small" ) ); + return; + } + + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( MBEDTLS_TLS_EXT_ECJPAKE_KKPP ) & 0xFF ); + + ret = mbedtls_ecjpake_write_round_one( &ssl->handshake->ecjpake_ctx, + p + 2, end - p - 2, &kkpp_len, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1 , "mbedtls_ecjpake_write_round_one", ret ); + return; + } + + *p++ = (unsigned char)( ( kkpp_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( kkpp_len ) & 0xFF ); + + *olen = kkpp_len + 4; +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_SSL_ALPN ) +static void ssl_write_alpn_ext( mbedtls_ssl_context *ssl, + unsigned char *buf, size_t *olen ) +{ + if( ssl->alpn_chosen == NULL ) + { + *olen = 0; + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, adding alpn extension" ) ); + + /* + * 0 . 1 ext identifier + * 2 . 3 ext length + * 4 . 5 protocol list length + * 6 . 6 protocol name length + * 7 . 7+n protocol name + */ + buf[0] = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN >> 8 ) & 0xFF ); + buf[1] = (unsigned char)( ( MBEDTLS_TLS_EXT_ALPN ) & 0xFF ); + + *olen = 7 + strlen( ssl->alpn_chosen ); + + buf[2] = (unsigned char)( ( ( *olen - 4 ) >> 8 ) & 0xFF ); + buf[3] = (unsigned char)( ( ( *olen - 4 ) ) & 0xFF ); + + buf[4] = (unsigned char)( ( ( *olen - 6 ) >> 8 ) & 0xFF ); + buf[5] = (unsigned char)( ( ( *olen - 6 ) ) & 0xFF ); + + buf[6] = (unsigned char)( ( ( *olen - 7 ) ) & 0xFF ); + + memcpy( buf + 7, ssl->alpn_chosen, *olen - 7 ); +} +#endif /* MBEDTLS_ECDH_C || MBEDTLS_ECDSA_C */ + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) +static int ssl_write_hello_verify_request( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *p = ssl->out_msg + 4; + unsigned char *cookie_len_byte; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write hello verify request" ) ); + + /* + * struct { + * ProtocolVersion server_version; + * opaque cookie<0..2^8-1>; + * } HelloVerifyRequest; + */ + + /* The RFC is not clear on this point, but sending the actual negotiated + * version looks like the most interoperable thing to do. */ + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, p ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server version", p, 2 ); + p += 2; + + /* If we get here, f_cookie_check is not null */ + if( ssl->conf->f_cookie_write == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "inconsistent cookie callbacks" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Skip length byte until we know the length */ + cookie_len_byte = p++; + + if( ( ret = ssl->conf->f_cookie_write( ssl->conf->p_cookie, + &p, ssl->out_buf + MBEDTLS_SSL_BUFFER_LEN, + ssl->cli_id, ssl->cli_id_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "f_cookie_write", ret ); + return( ret ); + } + + *cookie_len_byte = (unsigned char)( p - ( cookie_len_byte + 1 ) ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "cookie sent", cookie_len_byte + 1, *cookie_len_byte ); + + ssl->out_msglen = p - ssl->out_msg; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST; + + ssl->state = MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write hello verify request" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + +static int ssl_write_server_hello( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_HAVE_TIME) + mbedtls_time_t t; +#endif + int ret; + size_t olen, ext_len = 0, n; + unsigned char *buf, *p; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server hello" ) ); + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->verify_cookie_len != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "client hello was not authenticated" ) ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + + return( ssl_write_hello_verify_request( ssl ) ); + } +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ + + if( ssl->conf->f_rng == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no RNG provided") ); + return( MBEDTLS_ERR_SSL_NO_RNG ); + } + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 5 protocol version + * 6 . 9 UNIX time() + * 10 . 37 random bytes + */ + buf = ssl->out_msg; + p = buf + 4; + + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, p ); + p += 2; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen version: [%d:%d]", + buf[4], buf[5] ) ); + +#if defined(MBEDTLS_HAVE_TIME) + t = mbedtls_time( NULL ); + *p++ = (unsigned char)( t >> 24 ); + *p++ = (unsigned char)( t >> 16 ); + *p++ = (unsigned char)( t >> 8 ); + *p++ = (unsigned char)( t ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, current time: %lu", t ) ); +#else + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 4 ) ) != 0 ) + return( ret ); + + p += 4; +#endif /* MBEDTLS_HAVE_TIME */ + + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, p, 28 ) ) != 0 ) + return( ret ); + + p += 28; + + memcpy( ssl->handshake->randbytes + 32, buf + 6, 32 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, random bytes", buf + 6, 32 ); + + /* + * Resume is 0 by default, see ssl_handshake_init(). + * It may be already set to 1 by ssl_parse_session_ticket_ext(). + * If not, try looking up session ID in our cache. + */ + if( ssl->handshake->resume == 0 && +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status == MBEDTLS_SSL_INITIAL_HANDSHAKE && +#endif + ssl->session_negotiate->id_len != 0 && + ssl->conf->f_get_cache != NULL && + ssl->conf->f_get_cache( ssl->conf->p_cache, ssl->session_negotiate ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "session successfully restored from cache" ) ); + ssl->handshake->resume = 1; + } + + if( ssl->handshake->resume == 0 ) + { + /* + * New session, create a new session id, + * unless we're about to issue a session ticket + */ + ssl->state++; + +#if defined(MBEDTLS_HAVE_TIME) + ssl->session_negotiate->start = mbedtls_time( NULL ); +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + if( ssl->handshake->new_session_ticket != 0 ) + { + ssl->session_negotiate->id_len = n = 0; + memset( ssl->session_negotiate->id, 0, 32 ); + } + else +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + { + ssl->session_negotiate->id_len = n = 32; + if( ( ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->session_negotiate->id, + n ) ) != 0 ) + return( ret ); + } + } + else + { + /* + * Resuming a session + */ + n = ssl->session_negotiate->id_len; + ssl->state = MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC; + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + } + + /* + * 38 . 38 session id length + * 39 . 38+n session id + * 39+n . 40+n chosen ciphersuite + * 41+n . 41+n chosen compression alg. + * 42+n . 43+n extensions length + * 44+n . 43+n+m extensions + */ + *p++ = (unsigned char) ssl->session_negotiate->id_len; + memcpy( p, ssl->session_negotiate->id, ssl->session_negotiate->id_len ); + p += ssl->session_negotiate->id_len; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, session id len.: %d", n ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "server hello, session id", buf + 39, n ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "%s session has been resumed", + ssl->handshake->resume ? "a" : "no" ) ); + + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite >> 8 ); + *p++ = (unsigned char)( ssl->session_negotiate->ciphersuite ); + *p++ = (unsigned char)( ssl->session_negotiate->compression ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, chosen ciphersuite: %s", + mbedtls_ssl_get_ciphersuite_name( ssl->session_negotiate->ciphersuite ) ) ); + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, compress alg.: 0x%02X", + ssl->session_negotiate->compression ) ); + + /* Do not write the extensions if the protocol is SSLv3 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ( ssl->major_ver != 3 ) || ( ssl->minor_ver != 0 ) ) + { +#endif + + /* + * First write extensions, then the total length + */ + ssl_write_renegotiation_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + ssl_write_max_fragment_length_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + ssl_write_truncated_hmac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + ssl_write_encrypt_then_mac_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + ssl_write_extended_ms_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + ssl_write_session_ticket_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl_write_supported_point_formats_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + ssl_write_ecjpake_kkpp_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + +#if defined(MBEDTLS_SSL_ALPN) + ssl_write_alpn_ext( ssl, p + 2 + ext_len, &olen ); + ext_len += olen; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "server hello, total extension length: %d", ext_len ) ); + + if( ext_len > 0 ) + { + *p++ = (unsigned char)( ( ext_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( ext_len ) & 0xFF ); + p += ext_len; + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + } +#endif + + ssl->out_msglen = p - buf; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO; + + ret = mbedtls_ssl_write_record( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello" ) ); + + return( ret ); +} + +#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else +static int ssl_write_certificate_request( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + size_t dn_size, total_dn_size; /* excluding length bytes */ + size_t ct_len, sa_len; /* including length bytes */ + unsigned char *buf, *p; + const unsigned char * const end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + const mbedtls_x509_crt *crt; + int authmode; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate request" ) ); + + ssl->state++; + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; + else +#endif + authmode = ssl->conf->authmode; + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE || + authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate request" ) ); + return( 0 ); + } + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 4 cert type count + * 5 .. m-1 cert types + * m .. m+1 sig alg length (TLS 1.2 only) + * m+1 .. n-1 SignatureAndHashAlgorithms (TLS 1.2 only) + * n .. n+1 length of all DNs + * n+2 .. n+3 length of DN 1 + * n+4 .. ... Distinguished Name #1 + * ... .. ... length of DN 2, etc. + */ + buf = ssl->out_msg; + p = buf + 4; + + /* + * Supported certificate types + * + * ClientCertificateType certificate_types<1..2^8-1>; + * enum { (255) } ClientCertificateType; + */ + ct_len = 0; + +#if defined(MBEDTLS_RSA_C) + p[1 + ct_len++] = MBEDTLS_SSL_CERT_TYPE_RSA_SIGN; +#endif +#if defined(MBEDTLS_ECDSA_C) + p[1 + ct_len++] = MBEDTLS_SSL_CERT_TYPE_ECDSA_SIGN; +#endif + + p[0] = (unsigned char) ct_len++; + p += ct_len; + + sa_len = 0; +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * Add signature_algorithms for verify (TLS 1.2) + * + * SignatureAndHashAlgorithm supported_signature_algorithms<2..2^16-2>; + * + * struct { + * HashAlgorithm hash; + * SignatureAlgorithm signature; + * } SignatureAndHashAlgorithm; + * + * enum { (255) } HashAlgorithm; + * enum { (255) } SignatureAlgorithm; + */ + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + const int *cur; + + /* + * Supported signature algorithms + */ + for( cur = ssl->conf->sig_hashes; *cur != MBEDTLS_MD_NONE; cur++ ) + { + unsigned char hash = mbedtls_ssl_hash_from_md_alg( *cur ); + + if( MBEDTLS_SSL_HASH_NONE == hash || mbedtls_ssl_set_calc_verify_md( ssl, hash ) ) + continue; + +#if defined(MBEDTLS_RSA_C) + p[2 + sa_len++] = hash; + p[2 + sa_len++] = MBEDTLS_SSL_SIG_RSA; +#endif +#if defined(MBEDTLS_ECDSA_C) + p[2 + sa_len++] = hash; + p[2 + sa_len++] = MBEDTLS_SSL_SIG_ECDSA; +#endif + } + + p[0] = (unsigned char)( sa_len >> 8 ); + p[1] = (unsigned char)( sa_len ); + sa_len += 2; + p += sa_len; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + /* + * DistinguishedName certificate_authorities<0..2^16-1>; + * opaque DistinguishedName<1..2^16-1>; + */ + p += 2; +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_ca_chain != NULL ) + crt = ssl->handshake->sni_ca_chain; + else +#endif + crt = ssl->conf->ca_chain; + + total_dn_size = 0; + while( crt != NULL && crt->version != 0 ) + { + dn_size = crt->subject_raw.len; + + if( end < p || + (size_t)( end - p ) < dn_size || + (size_t)( end - p ) < 2 + dn_size ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "skipping CAs: buffer too short" ) ); + break; + } + + *p++ = (unsigned char)( dn_size >> 8 ); + *p++ = (unsigned char)( dn_size ); + memcpy( p, crt->subject_raw.p, dn_size ); + p += dn_size; + + MBEDTLS_SSL_DEBUG_BUF( 3, "requested DN", p - dn_size, dn_size ); + + total_dn_size += 2 + dn_size; + crt = crt->next; + } + + ssl->out_msglen = p - buf; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE_REQUEST; + ssl->out_msg[4 + ct_len + sa_len] = (unsigned char)( total_dn_size >> 8 ); + ssl->out_msg[5 + ct_len + sa_len] = (unsigned char)( total_dn_size ); + + ret = mbedtls_ssl_write_record( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate request" ) ); + + return( ret ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +static int ssl_get_ecdh_params_from_cert( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ! mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_ECKEY ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server key not ECDH capable" ) ); + return( MBEDTLS_ERR_SSL_PK_TYPE_MISMATCH ); + } + + if( ( ret = mbedtls_ecdh_get_params( &ssl->handshake->ecdh_ctx, + mbedtls_pk_ec( *mbedtls_ssl_own_key( ssl ) ), + MBEDTLS_ECDH_OURS ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ecdh_get_params" ), ret ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +static int ssl_write_server_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t n = 0; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = + ssl->transform_negotiate->ciphersuite_info; + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + unsigned char *p = ssl->out_msg + 4; + unsigned char *dig_signed = p; + size_t dig_signed_len = 0, len; + ((void) dig_signed); + ((void) dig_signed_len); + ((void) len); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server key exchange" ) ); + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) ); + ssl->state++; + return( 0 ); + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) + { + ssl_get_ecdh_params_from_cert( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write server key exchange" ) ); + ssl->state++; + return( 0 ); + } +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + size_t jlen; + const unsigned char *end = ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN; + + ret = mbedtls_ecjpake_write_round_two( &ssl->handshake->ecjpake_ctx, + p, end - p, &jlen, ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_write_round_two", ret ); + return( ret ); + } + + p += jlen; + n += jlen; + } +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + /* Note: we don't support identity hints, until someone asks + * for them. */ + *(p++) = 0x00; + *(p++) = 0x00; + + n += 2; + } +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + if( ssl->conf->dhm_P.p == NULL || ssl->conf->dhm_G.p == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no DH parameters set" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * Ephemeral DH parameters: + * + * struct { + * opaque dh_p<1..2^16-1>; + * opaque dh_g<1..2^16-1>; + * opaque dh_Ys<1..2^16-1>; + * } ServerDHParams; + */ + if( ( ret = mbedtls_mpi_copy( &ssl->handshake->dhm_ctx.P, &ssl->conf->dhm_P ) ) != 0 || + ( ret = mbedtls_mpi_copy( &ssl->handshake->dhm_ctx.G, &ssl->conf->dhm_G ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_mpi_copy", ret ); + return( ret ); + } + + if( ( ret = mbedtls_dhm_make_params( &ssl->handshake->dhm_ctx, + (int) mbedtls_mpi_size( &ssl->handshake->dhm_ctx.P ), + p, &len, ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_make_params", ret ); + return( ret ); + } + + dig_signed = p; + dig_signed_len = len; + + p += len; + n += len; + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: X ", &ssl->handshake->dhm_ctx.X ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: P ", &ssl->handshake->dhm_ctx.P ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: G ", &ssl->handshake->dhm_ctx.G ); + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GX", &ssl->handshake->dhm_ctx.GX ); + } +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + /* + * Ephemeral ECDH parameters: + * + * struct { + * ECParameters curve_params; + * ECPoint public; + * } ServerECDHParams; + */ + const mbedtls_ecp_curve_info **curve = NULL; + const mbedtls_ecp_group_id *gid; + + /* Match our preference list against the offered curves */ + for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) + for( curve = ssl->handshake->curves; *curve != NULL; curve++ ) + if( (*curve)->grp_id == *gid ) + goto curve_matching_done; + +curve_matching_done: + if( curve == NULL || *curve == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "no matching curve for ECDHE" ) ); + return( MBEDTLS_ERR_SSL_NO_CIPHER_CHOSEN ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ECDHE curve: %s", (*curve)->name ) ); + + if( ( ret = mbedtls_ecp_group_load( &ssl->handshake->ecdh_ctx.grp, + (*curve)->grp_id ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecp_group_load", ret ); + return( ret ); + } + + if( ( ret = mbedtls_ecdh_make_params( &ssl->handshake->ecdh_ctx, &len, + p, MBEDTLS_SSL_MAX_CONTENT_LEN - n, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_make_params", ret ); + return( ret ); + } + + dig_signed = p; + dig_signed_len = len; + + p += len; + n += len; + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Q ", &ssl->handshake->ecdh_ctx.Q ); + } +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__ECDHE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + size_t signature_len = 0; + unsigned int hashlen = 0; + unsigned char hash[64]; + mbedtls_md_type_t md_alg = MBEDTLS_MD_NONE; + + /* + * Choose hash algorithm. NONE means MD5 + SHA1 here. + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + md_alg = mbedtls_ssl_md_alg_from_hash( ssl->handshake->sig_alg ); + + if( md_alg == MBEDTLS_MD_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ciphersuite_info->key_exchange == + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA ) + { + md_alg = MBEDTLS_MD_SHA1; + } + else +#endif + { + md_alg = MBEDTLS_MD_NONE; + } + + /* + * Compute the hash to be signed + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( md_alg == MBEDTLS_MD_NONE ) + { + mbedtls_md5_context mbedtls_md5; + mbedtls_sha1_context mbedtls_sha1; + + mbedtls_md5_init( &mbedtls_md5 ); + mbedtls_sha1_init( &mbedtls_sha1 ); + + /* + * digitally-signed struct { + * opaque md5_hash[16]; + * opaque sha_hash[20]; + * }; + * + * md5_hash + * MD5(ClientHello.random + ServerHello.random + * + ServerParams); + * sha_hash + * SHA(ClientHello.random + ServerHello.random + * + ServerParams); + */ + mbedtls_md5_starts( &mbedtls_md5 ); + mbedtls_md5_update( &mbedtls_md5, ssl->handshake->randbytes, 64 ); + mbedtls_md5_update( &mbedtls_md5, dig_signed, dig_signed_len ); + mbedtls_md5_finish( &mbedtls_md5, hash ); + + mbedtls_sha1_starts( &mbedtls_sha1 ); + mbedtls_sha1_update( &mbedtls_sha1, ssl->handshake->randbytes, 64 ); + mbedtls_sha1_update( &mbedtls_sha1, dig_signed, dig_signed_len ); + mbedtls_sha1_finish( &mbedtls_sha1, hash + 16 ); + + hashlen = 36; + + mbedtls_md5_free( &mbedtls_md5 ); + mbedtls_sha1_free( &mbedtls_sha1 ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || \ + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( md_alg != MBEDTLS_MD_NONE ) + { + mbedtls_md_context_t ctx; + const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type( md_alg ); + + mbedtls_md_init( &ctx ); + + /* Info from md_alg will be used instead */ + hashlen = 0; + + /* + * digitally-signed struct { + * opaque client_random[32]; + * opaque server_random[32]; + * ServerDHParams params; + * }; + */ + if( ( ret = mbedtls_md_setup( &ctx, md_info, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret ); + return( ret ); + } + + mbedtls_md_starts( &ctx ); + mbedtls_md_update( &ctx, ssl->handshake->randbytes, 64 ); + mbedtls_md_update( &ctx, dig_signed, dig_signed_len ); + mbedtls_md_finish( &ctx, hash ); + mbedtls_md_free( &ctx ); + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 3, "parameters hash", hash, hashlen != 0 ? hashlen : + (unsigned int) ( mbedtls_md_get_size( mbedtls_md_info_from_type( md_alg ) ) ) ); + + /* + * Make the signature + */ + if( mbedtls_ssl_own_key( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no private key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + *(p++) = ssl->handshake->sig_alg; + *(p++) = mbedtls_ssl_sig_from_pk( mbedtls_ssl_own_key( ssl ) ); + + n += 2; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + if( ( ret = mbedtls_pk_sign( mbedtls_ssl_own_key( ssl ), md_alg, hash, hashlen, + p + 2 , &signature_len, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_sign", ret ); + return( ret ); + } + + *(p++) = (unsigned char)( signature_len >> 8 ); + *(p++) = (unsigned char)( signature_len ); + n += 2; + + MBEDTLS_SSL_DEBUG_BUF( 3, "my signature", p, signature_len ); + + n += signature_len; + } +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || + MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + + ssl->out_msglen = 4 + n; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_KEY_EXCHANGE; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server key exchange" ) ); + + return( 0 ); +} + +static int ssl_write_server_hello_done( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write server hello done" ) ); + + ssl->out_msglen = 4; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_SERVER_HELLO_DONE; + + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_send_flight_completed( ssl ); +#endif + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write server hello done" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) +static int ssl_parse_client_dh_public( mbedtls_ssl_context *ssl, unsigned char **p, + const unsigned char *end ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t n; + + /* + * Receive G^Y mod P, premaster = (G^Y)^X mod P + */ + if( *p + 2 > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + n = ( (*p)[0] << 8 ) | (*p)[1]; + *p += 2; + + if( *p + n > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = mbedtls_dhm_read_public( &ssl->handshake->dhm_ctx, *p, n ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_read_public", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); + } + + *p += n; + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: GY", &ssl->handshake->dhm_ctx.GY ); + + return( ret ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) +static int ssl_parse_encrypted_pms( mbedtls_ssl_context *ssl, + const unsigned char *p, + const unsigned char *end, + size_t pms_offset ) +{ + int ret; + size_t len = mbedtls_pk_get_len( mbedtls_ssl_own_key( ssl ) ); + unsigned char *pms = ssl->handshake->premaster + pms_offset; + unsigned char ver[2]; + unsigned char fake_pms[48], peer_pms[48]; + unsigned char mask; + size_t i, peer_pmslen; + unsigned int diff; + + if( ! mbedtls_pk_can_do( mbedtls_ssl_own_key( ssl ), MBEDTLS_PK_RSA ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no RSA private key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Decrypt the premaster using own private RSA key + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( *p++ != ( ( len >> 8 ) & 0xFF ) || + *p++ != ( ( len ) & 0xFF ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + } +#endif + + if( p + len != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + mbedtls_ssl_write_version( ssl->handshake->max_major_ver, + ssl->handshake->max_minor_ver, + ssl->conf->transport, ver ); + + /* + * Protection against Bleichenbacher's attack: invalid PKCS#1 v1.5 padding + * must not cause the connection to end immediately; instead, send a + * bad_record_mac later in the handshake. + * Also, avoid data-dependant branches here to protect against + * timing-based variants. + */ + ret = ssl->conf->f_rng( ssl->conf->p_rng, fake_pms, sizeof( fake_pms ) ); + if( ret != 0 ) + return( ret ); + + ret = mbedtls_pk_decrypt( mbedtls_ssl_own_key( ssl ), p, len, + peer_pms, &peer_pmslen, + sizeof( peer_pms ), + ssl->conf->f_rng, ssl->conf->p_rng ); + + diff = (unsigned int) ret; + diff |= peer_pmslen ^ 48; + diff |= peer_pms[0] ^ ver[0]; + diff |= peer_pms[1] ^ ver[1]; + +#if defined(MBEDTLS_SSL_DEBUG_ALL) + if( diff != 0 ) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); +#endif + + if( sizeof( ssl->handshake->premaster ) < pms_offset || + sizeof( ssl->handshake->premaster ) - pms_offset < 48 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + ssl->handshake->pmslen = 48; + + /* mask = diff ? 0xff : 0x00 using bit operations to avoid branches */ + /* MSVC has a warning about unary minus on unsigned, but this is + * well-defined and precisely what we want to do here */ +#if defined(_MSC_VER) +#pragma warning( push ) +#pragma warning( disable : 4146 ) +#endif + mask = - ( ( diff | - diff ) >> ( sizeof( unsigned int ) * 8 - 1 ) ); +#if defined(_MSC_VER) +#pragma warning( pop ) +#endif + + for( i = 0; i < ssl->handshake->pmslen; i++ ) + pms[i] = ( mask & fake_pms[i] ) | ( (~mask) & peer_pms[i] ); + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +static int ssl_parse_client_psk_identity( mbedtls_ssl_context *ssl, unsigned char **p, + const unsigned char *end ) +{ + int ret = 0; + size_t n; + + if( ssl->conf->f_psk == NULL && + ( ssl->conf->psk == NULL || ssl->conf->psk_identity == NULL || + ssl->conf->psk_identity_len == 0 || ssl->conf->psk_len == 0 ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no pre-shared key" ) ); + return( MBEDTLS_ERR_SSL_PRIVATE_KEY_REQUIRED ); + } + + /* + * Receive client pre-shared key identity name + */ + if( *p + 2 > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + n = ( (*p)[0] << 8 ) | (*p)[1]; + *p += 2; + + if( n < 1 || n > 65535 || *p + n > end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ssl->conf->f_psk != NULL ) + { + if( ssl->conf->f_psk( ssl->conf->p_psk, ssl, *p, n ) != 0 ) + ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; + } + else + { + /* Identity is not a big secret since clients send it in the clear, + * but treat it carefully anyway, just in case */ + if( n != ssl->conf->psk_identity_len || + mbedtls_ssl_safer_memcmp( ssl->conf->psk_identity, *p, n ) != 0 ) + { + ret = MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY; + } + } + + if( ret == MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ) + { + MBEDTLS_SSL_DEBUG_BUF( 3, "Unknown PSK identity", *p, n ); + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNKNOWN_PSK_IDENTITY ) ) != 0 ) + { + return( ret ); + } + + return( MBEDTLS_ERR_SSL_UNKNOWN_IDENTITY ); + } + + *p += n; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +static int ssl_parse_client_key_exchange( mbedtls_ssl_context *ssl ) +{ + int ret; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info; + unsigned char *p, *end; + + ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse client key exchange" ) ); + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + p = ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ); + end = ssl->in_msg + ssl->in_hslen; + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_KEY_EXCHANGE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_RSA ) + { + if( ( ret = ssl_parse_client_dh_public( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_dh_public" ), ret ); + return( ret ); + } + + if( p != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx, + ssl->handshake->premaster, + MBEDTLS_PREMASTER_SIZE, + &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_RSA || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA ) + { + if( ( ret = mbedtls_ecdh_read_public( &ssl->handshake->ecdh_ctx, + p, end - p) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_read_public", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); + } + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.Qp ); + + if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, + &ssl->handshake->pmslen, + ssl->handshake->premaster, + MBEDTLS_MPI_MAX_SIZE, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_CS ); + } + + MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z ", &ssl->handshake->ecdh_ctx.z ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED || + MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK ) + { + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + + if( p != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + + if( ( ret = ssl_parse_encrypted_pms( ssl, p, end, 2 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_encrypted_pms" ), ret ); + return( ret ); + } + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + if( ( ret = ssl_parse_client_dh_public( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_dh_public" ), ret ); + return( ret ); + } + + if( p != end ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad client key exchange" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE ); + } + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + if( ( ret = ssl_parse_client_psk_identity( ssl, &p, end ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_client_psk_identity" ), ret ); + return( ret ); + } + + if( ( ret = mbedtls_ecdh_read_public( &ssl->handshake->ecdh_ctx, + p, end - p ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_read_public", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_KEY_EXCHANGE_RP ); + } + + MBEDTLS_SSL_DEBUG_ECP( 3, "ECDH: Qp ", &ssl->handshake->ecdh_ctx.Qp ); + + if( ( ret = mbedtls_ssl_psk_derive_premaster( ssl, + ciphersuite_info->key_exchange ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_psk_derive_premaster", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA ) + { + if( ( ret = ssl_parse_encrypted_pms( ssl, p, end, 0 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "ssl_parse_parse_encrypted_pms_secret" ), ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + ret = mbedtls_ecjpake_read_round_two( &ssl->handshake->ecjpake_ctx, + p, end - p ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_read_round_two", ret ); + return( MBEDTLS_ERR_SSL_BAD_HS_SERVER_KEY_EXCHANGE ); + } + + ret = mbedtls_ecjpake_derive_secret( &ssl->handshake->ecjpake_ctx, + ssl->handshake->premaster, 32, &ssl->handshake->pmslen, + ssl->conf->f_rng, ssl->conf->p_rng ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecjpake_derive_secret", ret ); + return( ret ); + } + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ( ret = mbedtls_ssl_derive_keys( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_derive_keys", ret ); + return( ret ); + } + + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse client key exchange" ) ); + + return( 0 ); +} + +#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED)&& \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) +static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else +static int ssl_parse_certificate_verify( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t i, sig_len; + unsigned char hash[48]; + unsigned char *hash_start = hash; + size_t hashlen; +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + mbedtls_pk_type_t pk_alg; +#endif + mbedtls_md_type_t md_alg; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate verify" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE || + ssl->session_negotiate->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate verify" ) ); + ssl->state++; + return( 0 ); + } + + /* Read the message without adding it to the checksum */ + do { + + if( ( ret = mbedtls_ssl_read_record_layer( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret ); + return( ret ); + } + + ret = mbedtls_ssl_handle_message_type( ssl ); + + } while( MBEDTLS_ERR_SSL_NON_FATAL == ret ); + + if( 0 != ret ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_handle_message_type" ), ret ); + return( ret ); + } + + ssl->state++; + + /* Process the message contents */ + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE || + ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE_VERIFY ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + i = mbedtls_ssl_hs_hdr_len( ssl ); + + /* + * struct { + * SignatureAndHashAlgorithm algorithm; -- TLS 1.2 only + * opaque signature<0..2^16-1>; + * } DigitallySigned; + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + { + md_alg = MBEDTLS_MD_NONE; + hashlen = 36; + + /* For ECDSA, use SHA-1, not MD-5 + SHA-1 */ + if( mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, + MBEDTLS_PK_ECDSA ) ) + { + hash_start += 16; + hashlen -= 16; + md_alg = MBEDTLS_MD_SHA1; + } + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 || MBEDTLS_SSL_PROTO_TLS1 || + MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + if( i + 2 > ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* + * Hash + */ + md_alg = mbedtls_ssl_md_alg_from_hash( ssl->in_msg[i] ); + + if( md_alg == MBEDTLS_MD_NONE || mbedtls_ssl_set_calc_verify_md( ssl, ssl->in_msg[i] ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg" + " for verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + +#if !defined(MBEDTLS_MD_SHA1) + if( MBEDTLS_MD_SHA1 == md_alg ) + hash_start += 16; +#endif + + /* Info from md_alg will be used instead */ + hashlen = 0; + + i++; + + /* + * Signature + */ + if( ( pk_alg = mbedtls_ssl_pk_alg_from_sig( ssl->in_msg[i] ) ) + == MBEDTLS_PK_NONE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "peer not adhering to requested sig_alg" + " for verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* + * Check the certificate's key type matches the signature alg + */ + if( ! mbedtls_pk_can_do( &ssl->session_negotiate->peer_cert->pk, pk_alg ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "sig_alg doesn't match cert key" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + i++; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( i + 2 > ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + sig_len = ( ssl->in_msg[i] << 8 ) | ssl->in_msg[i+1]; + i += 2; + + if( i + sig_len != ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate verify message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE_VERIFY ); + } + + /* Calculate hash and verify signature */ + ssl->handshake->calc_verify( ssl, hash ); + + if( ( ret = mbedtls_pk_verify( &ssl->session_negotiate->peer_cert->pk, + md_alg, hash_start, hashlen, + ssl->in_msg + i, sig_len ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_pk_verify", ret ); + return( ret ); + } + + mbedtls_ssl_update_handshake_status( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate verify" ) ); + + return( ret ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED && + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +static int ssl_write_new_session_ticket( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t tlen; + uint32_t lifetime; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write new session ticket" ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_NEW_SESSION_TICKET; + + /* + * struct { + * uint32 ticket_lifetime_hint; + * opaque ticket<0..2^16-1>; + * } NewSessionTicket; + * + * 4 . 7 ticket_lifetime_hint (0 = unspecified) + * 8 . 9 ticket_len (n) + * 10 . 9+n ticket content + */ + + if( ( ret = ssl->conf->f_ticket_write( ssl->conf->p_ticket, + ssl->session_negotiate, + ssl->out_msg + 10, + ssl->out_msg + MBEDTLS_SSL_MAX_CONTENT_LEN, + &tlen, &lifetime ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_ticket_write", ret ); + tlen = 0; + } + + ssl->out_msg[4] = ( lifetime >> 24 ) & 0xFF; + ssl->out_msg[5] = ( lifetime >> 16 ) & 0xFF; + ssl->out_msg[6] = ( lifetime >> 8 ) & 0xFF; + ssl->out_msg[7] = ( lifetime ) & 0xFF; + + ssl->out_msg[8] = (unsigned char)( ( tlen >> 8 ) & 0xFF ); + ssl->out_msg[9] = (unsigned char)( ( tlen ) & 0xFF ); + + ssl->out_msglen = 10 + tlen; + + /* + * Morally equivalent to updating ssl->state, but NewSessionTicket and + * ChangeCipherSpec share the same state. + */ + ssl->handshake->new_session_ticket = 0; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write new session ticket" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +/* + * SSL handshake -- server side -- single step + */ +int mbedtls_ssl_handshake_server_step( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "server state: %d", ssl->state ) ); + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + return( ret ); + } +#endif + + switch( ssl->state ) + { + case MBEDTLS_SSL_HELLO_REQUEST: + ssl->state = MBEDTLS_SSL_CLIENT_HELLO; + break; + + /* + * <== ClientHello + */ + case MBEDTLS_SSL_CLIENT_HELLO: + ret = ssl_parse_client_hello( ssl ); + break; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + case MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT: + return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ); +#endif + + /* + * ==> ServerHello + * Certificate + * ( ServerKeyExchange ) + * ( CertificateRequest ) + * ServerHelloDone + */ + case MBEDTLS_SSL_SERVER_HELLO: + ret = ssl_write_server_hello( ssl ); + break; + + case MBEDTLS_SSL_SERVER_CERTIFICATE: + ret = mbedtls_ssl_write_certificate( ssl ); + break; + + case MBEDTLS_SSL_SERVER_KEY_EXCHANGE: + ret = ssl_write_server_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_REQUEST: + ret = ssl_write_certificate_request( ssl ); + break; + + case MBEDTLS_SSL_SERVER_HELLO_DONE: + ret = ssl_write_server_hello_done( ssl ); + break; + + /* + * <== ( Certificate/Alert ) + * ClientKeyExchange + * ( CertificateVerify ) + * ChangeCipherSpec + * Finished + */ + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + ret = mbedtls_ssl_parse_certificate( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: + ret = ssl_parse_client_key_exchange( ssl ); + break; + + case MBEDTLS_SSL_CERTIFICATE_VERIFY: + ret = ssl_parse_certificate_verify( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC: + ret = mbedtls_ssl_parse_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_CLIENT_FINISHED: + ret = mbedtls_ssl_parse_finished( ssl ); + break; + + /* + * ==> ( NewSessionTicket ) + * ChangeCipherSpec + * Finished + */ + case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC: +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + if( ssl->handshake->new_session_ticket != 0 ) + ret = ssl_write_new_session_ticket( ssl ); + else +#endif + ret = mbedtls_ssl_write_change_cipher_spec( ssl ); + break; + + case MBEDTLS_SSL_SERVER_FINISHED: + ret = mbedtls_ssl_write_finished( ssl ); + break; + + case MBEDTLS_SSL_FLUSH_BUFFERS: + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake: done" ) ); + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; + break; + + case MBEDTLS_SSL_HANDSHAKE_WRAPUP: + mbedtls_ssl_handshake_wrapup( ssl ); + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid state %d", ssl->state ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_SRV_C */ diff --git a/c++/src/connect/mbedtls/ssl_ticket.c b/c++/src/connect/mbedtls/ssl_ticket.c new file mode 100644 index 00000000..4d9116d2 --- /dev/null +++ b/c++/src/connect/mbedtls/ssl_ticket.c @@ -0,0 +1,489 @@ +/* + * TLS server tickets callbacks implementation + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_TICKET_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/ssl_ticket.h" + +#include + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Initialze context + */ +void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_init( &ctx->mutex ); +#endif +} + +#define MAX_KEY_BYTES 32 /* 256 bits */ + +/* + * Generate/update a key + */ +static int ssl_ticket_gen_key( mbedtls_ssl_ticket_context *ctx, + unsigned char index ) +{ + int ret; + unsigned char buf[MAX_KEY_BYTES]; + mbedtls_ssl_ticket_key *key = ctx->keys + index; + +#if defined(MBEDTLS_HAVE_TIME) + key->generation_time = (uint32_t) mbedtls_time( NULL ); +#endif + + if( ( ret = ctx->f_rng( ctx->p_rng, key->name, sizeof( key->name ) ) ) != 0 ) + return( ret ); + + if( ( ret = ctx->f_rng( ctx->p_rng, buf, sizeof( buf ) ) ) != 0 ) + return( ret ); + + /* With GCM and CCM, same context can encrypt & decrypt */ + ret = mbedtls_cipher_setkey( &key->ctx, buf, + mbedtls_cipher_get_key_bitlen( &key->ctx ), + MBEDTLS_ENCRYPT ); + + mbedtls_zeroize( buf, sizeof( buf ) ); + + return( ret ); +} + +/* + * Rotate/generate keys if necessary + */ +static int ssl_ticket_update_keys( mbedtls_ssl_ticket_context *ctx ) +{ +#if !defined(MBEDTLS_HAVE_TIME) + ((void) ctx); +#else + if( ctx->ticket_lifetime != 0 ) + { + uint32_t current_time = (uint32_t) mbedtls_time( NULL ); + uint32_t key_time = ctx->keys[ctx->active].generation_time; + + if( current_time > key_time && + current_time - key_time < ctx->ticket_lifetime ) + { + return( 0 ); + } + + ctx->active = 1 - ctx->active; + + return( ssl_ticket_gen_key( ctx, ctx->active ) ); + } + else +#endif /* MBEDTLS_HAVE_TIME */ + return( 0 ); +} + +/* + * Setup context for actual use + */ +int mbedtls_ssl_ticket_setup( mbedtls_ssl_ticket_context *ctx, + int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, + mbedtls_cipher_type_t cipher, + uint32_t lifetime ) +{ + int ret; + const mbedtls_cipher_info_t *cipher_info; + + ctx->f_rng = f_rng; + ctx->p_rng = p_rng; + + ctx->ticket_lifetime = lifetime; + + cipher_info = mbedtls_cipher_info_from_type( cipher); + if( cipher_info == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( cipher_info->mode != MBEDTLS_MODE_GCM && + cipher_info->mode != MBEDTLS_MODE_CCM ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( cipher_info->key_bitlen > 8 * MAX_KEY_BYTES ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_cipher_setup( &ctx->keys[0].ctx, cipher_info ) ) != 0 || + ( ret = mbedtls_cipher_setup( &ctx->keys[1].ctx, cipher_info ) ) != 0 ) + { + return( ret ); + } + + if( ( ret = ssl_ticket_gen_key( ctx, 0 ) ) != 0 || + ( ret = ssl_ticket_gen_key( ctx, 1 ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +/* + * Serialize a session in the following format: + * 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session) + * n . n+2 peer_cert length = m (0 if no certificate) + * n+3 . n+2+m peer cert ASN.1 + */ +static int ssl_save_session( const mbedtls_ssl_session *session, + unsigned char *buf, size_t buf_len, + size_t *olen ) +{ + unsigned char *p = buf; + size_t left = buf_len; +#if defined(MBEDTLS_X509_CRT_PARSE_C) + size_t cert_len; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + if( left < sizeof( mbedtls_ssl_session ) ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + memcpy( p, session, sizeof( mbedtls_ssl_session ) ); + p += sizeof( mbedtls_ssl_session ); + left -= sizeof( mbedtls_ssl_session ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( session->peer_cert == NULL ) + cert_len = 0; + else + cert_len = session->peer_cert->raw.len; + + if( left < 3 + cert_len ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + *p++ = (unsigned char)( cert_len >> 16 & 0xFF ); + *p++ = (unsigned char)( cert_len >> 8 & 0xFF ); + *p++ = (unsigned char)( cert_len & 0xFF ); + + if( session->peer_cert != NULL ) + memcpy( p, session->peer_cert->raw.p, cert_len ); + + p += cert_len; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + *olen = p - buf; + + return( 0 ); +} + +/* + * Unserialise session, see ssl_save_session() + */ +static int ssl_load_session( mbedtls_ssl_session *session, + const unsigned char *buf, size_t len ) +{ + const unsigned char *p = buf; + const unsigned char * const end = buf + len; +#if defined(MBEDTLS_X509_CRT_PARSE_C) + size_t cert_len; +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + if( p + sizeof( mbedtls_ssl_session ) > end ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memcpy( session, p, sizeof( mbedtls_ssl_session ) ); + p += sizeof( mbedtls_ssl_session ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( p + 3 > end ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + cert_len = ( p[0] << 16 ) | ( p[1] << 8 ) | p[2]; + p += 3; + + if( cert_len == 0 ) + { + session->peer_cert = NULL; + } + else + { + int ret; + + if( p + cert_len > end ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + session->peer_cert = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); + + if( session->peer_cert == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + mbedtls_x509_crt_init( session->peer_cert ); + + if( ( ret = mbedtls_x509_crt_parse_der( session->peer_cert, + p, cert_len ) ) != 0 ) + { + mbedtls_x509_crt_free( session->peer_cert ); + mbedtls_free( session->peer_cert ); + session->peer_cert = NULL; + return( ret ); + } + + p += cert_len; + } +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + + if( p != end ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + return( 0 ); +} + +/* + * Create session ticket, with the following structure: + * + * struct { + * opaque key_name[4]; + * opaque iv[12]; + * opaque encrypted_state<0..2^16-1>; + * opaque tag[16]; + * } ticket; + * + * The key_name, iv, and length of encrypted_state are the additional + * authenticated data. + */ +int mbedtls_ssl_ticket_write( void *p_ticket, + const mbedtls_ssl_session *session, + unsigned char *start, + const unsigned char *end, + size_t *tlen, + uint32_t *ticket_lifetime ) +{ + int ret; + mbedtls_ssl_ticket_context *ctx = p_ticket; + mbedtls_ssl_ticket_key *key; + unsigned char *key_name = start; + unsigned char *iv = start + 4; + unsigned char *state_len_bytes = iv + 12; + unsigned char *state = state_len_bytes + 2; + unsigned char *tag; + size_t clear_len, ciph_len; + + *tlen = 0; + + if( ctx == NULL || ctx->f_rng == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* We need at least 4 bytes for key_name, 12 for IV, 2 for len 16 for tag, + * in addition to session itself, that will be checked when writing it. */ + if( end - start < 4 + 12 + 2 + 16 ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 ) + goto cleanup; + + key = &ctx->keys[ctx->active]; + + *ticket_lifetime = ctx->ticket_lifetime; + + memcpy( key_name, key->name, 4 ); + + if( ( ret = ctx->f_rng( ctx->p_rng, iv, 12 ) ) != 0 ) + goto cleanup; + + /* Dump session state */ + if( ( ret = ssl_save_session( session, + state, end - state, &clear_len ) ) != 0 || + (unsigned long) clear_len > 65535 ) + { + goto cleanup; + } + state_len_bytes[0] = ( clear_len >> 8 ) & 0xff; + state_len_bytes[1] = ( clear_len ) & 0xff; + + /* Encrypt and authenticate */ + tag = state + clear_len; + if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx, + iv, 12, key_name, 4 + 12 + 2, + state, clear_len, state, &ciph_len, tag, 16 ) ) != 0 ) + { + goto cleanup; + } + if( ciph_len != clear_len ) + { + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto cleanup; + } + + *tlen = 4 + 12 + 2 + 16 + ciph_len; + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Select key based on name + */ +static mbedtls_ssl_ticket_key *ssl_ticket_select_key( + mbedtls_ssl_ticket_context *ctx, + const unsigned char name[4] ) +{ + unsigned char i; + + for( i = 0; i < sizeof( ctx->keys ) / sizeof( *ctx->keys ); i++ ) + if( memcmp( name, ctx->keys[i].name, 4 ) == 0 ) + return( &ctx->keys[i] ); + + return( NULL ); +} + +/* + * Load session ticket (see mbedtls_ssl_ticket_write for structure) + */ +int mbedtls_ssl_ticket_parse( void *p_ticket, + mbedtls_ssl_session *session, + unsigned char *buf, + size_t len ) +{ + int ret; + mbedtls_ssl_ticket_context *ctx = p_ticket; + mbedtls_ssl_ticket_key *key; + unsigned char *key_name = buf; + unsigned char *iv = buf + 4; + unsigned char *enc_len_p = iv + 12; + unsigned char *ticket = enc_len_p + 2; + unsigned char *tag; + size_t enc_len, clear_len; + + if( ctx == NULL || ctx->f_rng == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* See mbedtls_ssl_ticket_write() */ + if( len < 4 + 12 + 2 + 16 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_THREADING_C) + if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 ) + return( ret ); +#endif + + if( ( ret = ssl_ticket_update_keys( ctx ) ) != 0 ) + goto cleanup; + + enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1]; + tag = ticket + enc_len; + + if( len != 4 + 12 + 2 + enc_len + 16 ) + { + ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA; + goto cleanup; + } + + /* Select key */ + if( ( key = ssl_ticket_select_key( ctx, key_name ) ) == NULL ) + { + /* We can't know for sure but this is a likely option unless we're + * under attack - this is only informative anyway */ + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + goto cleanup; + } + + /* Decrypt and authenticate */ + if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx, iv, 12, + key_name, 4 + 12 + 2, ticket, enc_len, + ticket, &clear_len, tag, 16 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED ) + ret = MBEDTLS_ERR_SSL_INVALID_MAC; + + goto cleanup; + } + if( clear_len != enc_len ) + { + ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR; + goto cleanup; + } + + /* Actually load session */ + if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 ) + goto cleanup; + +#if defined(MBEDTLS_HAVE_TIME) + { + /* Check for expiration */ + mbedtls_time_t current_time = mbedtls_time( NULL ); + + if( current_time < session->start || + (uint32_t)( current_time - session->start ) > ctx->ticket_lifetime ) + { + ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED; + goto cleanup; + } + } +#endif + +cleanup: +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} + +/* + * Free context + */ +void mbedtls_ssl_ticket_free( mbedtls_ssl_ticket_context *ctx ) +{ + mbedtls_cipher_free( &ctx->keys[0].ctx ); + mbedtls_cipher_free( &ctx->keys[1].ctx ); + +#if defined(MBEDTLS_THREADING_C) + mbedtls_mutex_free( &ctx->mutex ); +#endif + + mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) ); +} + +#endif /* MBEDTLS_SSL_TICKET_C */ diff --git a/c++/src/connect/mbedtls/ssl_tls.c b/c++/src/connect/mbedtls/ssl_tls.c new file mode 100644 index 00000000..d9ab8329 --- /dev/null +++ b/c++/src/connect/mbedtls/ssl_tls.c @@ -0,0 +1,7687 @@ +/* + * SSLv3/TLSv1 shared functions + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The SSL 3.0 specification was drafted by Netscape in 1996, + * and became an IETF standard in 1999. + * + * http://wp.netscape.com/eng/ssl3/ + * http://www.ietf.org/rfc/rfc2246.txt + * http://www.ietf.org/rfc/rfc4346.txt + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SSL_TLS_C) + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_calloc calloc +#define mbedtls_free free +#endif + +#include "mbedtls/debug.h" +#include "mbedtls/ssl.h" +#include "mbedtls/ssl_internal.h" + +#include + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +#include "mbedtls/oid.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* Length of the "epoch" field in the record header */ +static inline size_t ssl_ep_len( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( 2 ); +#else + ((void) ssl); +#endif + return( 0 ); +} + +/* + * Start a timer. + * Passing millisecs = 0 cancels a running timer. + */ +static void ssl_set_timer( mbedtls_ssl_context *ssl, uint32_t millisecs ) +{ + if( ssl->f_set_timer == NULL ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "set_timer to %d ms", (int) millisecs ) ); + ssl->f_set_timer( ssl->p_timer, millisecs / 4, millisecs ); +} + +/* + * Return -1 is timer is expired, 0 if it isn't. + */ +static int ssl_check_timer( mbedtls_ssl_context *ssl ) +{ + if( ssl->f_get_timer == NULL ) + return( 0 ); + + if( ssl->f_get_timer( ssl->p_timer ) == 2 ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "timer expired" ) ); + return( -1 ); + } + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/* + * Double the retransmit timeout value, within the allowed range, + * returning -1 if the maximum value has already been reached. + */ +static int ssl_double_retransmit_timeout( mbedtls_ssl_context *ssl ) +{ + uint32_t new_timeout; + + if( ssl->handshake->retransmit_timeout >= ssl->conf->hs_timeout_max ) + return( -1 ); + + new_timeout = 2 * ssl->handshake->retransmit_timeout; + + /* Avoid arithmetic overflow and range overflow */ + if( new_timeout < ssl->handshake->retransmit_timeout || + new_timeout > ssl->conf->hs_timeout_max ) + { + new_timeout = ssl->conf->hs_timeout_max; + } + + ssl->handshake->retransmit_timeout = new_timeout; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs", + ssl->handshake->retransmit_timeout ) ); + + return( 0 ); +} + +static void ssl_reset_retransmit_timeout( mbedtls_ssl_context *ssl ) +{ + ssl->handshake->retransmit_timeout = ssl->conf->hs_timeout_min; + MBEDTLS_SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs", + ssl->handshake->retransmit_timeout ) ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +/* + * Convert max_fragment_length codes to length. + * RFC 6066 says: + * enum{ + * 2^9(1), 2^10(2), 2^11(3), 2^12(4), (255) + * } MaxFragmentLength; + * and we add 0 -> extension unused + */ +static unsigned int mfl_code_to_length[MBEDTLS_SSL_MAX_FRAG_LEN_INVALID] = +{ + MBEDTLS_SSL_MAX_CONTENT_LEN, /* MBEDTLS_SSL_MAX_FRAG_LEN_NONE */ + 512, /* MBEDTLS_SSL_MAX_FRAG_LEN_512 */ + 1024, /* MBEDTLS_SSL_MAX_FRAG_LEN_1024 */ + 2048, /* MBEDTLS_SSL_MAX_FRAG_LEN_2048 */ + 4096, /* MBEDTLS_SSL_MAX_FRAG_LEN_4096 */ +}; +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_CLI_C) +static int ssl_session_copy( mbedtls_ssl_session *dst, const mbedtls_ssl_session *src ) +{ + mbedtls_ssl_session_free( dst ); + memcpy( dst, src, sizeof( mbedtls_ssl_session ) ); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( src->peer_cert != NULL ) + { + int ret; + + dst->peer_cert = mbedtls_calloc( 1, sizeof(mbedtls_x509_crt) ); + if( dst->peer_cert == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + mbedtls_x509_crt_init( dst->peer_cert ); + + if( ( ret = mbedtls_x509_crt_parse_der( dst->peer_cert, src->peer_cert->raw.p, + src->peer_cert->raw.len ) ) != 0 ) + { + mbedtls_free( dst->peer_cert ); + dst->peer_cert = NULL; + return( ret ); + } + } +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + if( src->ticket != NULL ) + { + dst->ticket = mbedtls_calloc( 1, src->ticket_len ); + if( dst->ticket == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( dst->ticket, src->ticket, src->ticket_len ); + } +#endif /* MBEDTLS_SSL_SESSION_TICKETS && MBEDTLS_SSL_CLI_C */ + + return( 0 ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) +int (*mbedtls_ssl_hw_record_init)( mbedtls_ssl_context *ssl, + const unsigned char *key_enc, const unsigned char *key_dec, + size_t keylen, + const unsigned char *iv_enc, const unsigned char *iv_dec, + size_t ivlen, + const unsigned char *mac_enc, const unsigned char *mac_dec, + size_t maclen ) = NULL; +int (*mbedtls_ssl_hw_record_activate)( mbedtls_ssl_context *ssl, int direction) = NULL; +int (*mbedtls_ssl_hw_record_reset)( mbedtls_ssl_context *ssl ) = NULL; +int (*mbedtls_ssl_hw_record_write)( mbedtls_ssl_context *ssl ) = NULL; +int (*mbedtls_ssl_hw_record_read)( mbedtls_ssl_context *ssl ) = NULL; +int (*mbedtls_ssl_hw_record_finish)( mbedtls_ssl_context *ssl ) = NULL; +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + +/* + * Key material generation + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) +static int ssl3_prf( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t i; + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + unsigned char padding[16]; + unsigned char sha1sum[20]; + ((void)label); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + /* + * SSLv3: + * block = + * MD5( secret + SHA1( 'A' + secret + random ) ) + + * MD5( secret + SHA1( 'BB' + secret + random ) ) + + * MD5( secret + SHA1( 'CCC' + secret + random ) ) + + * ... + */ + for( i = 0; i < dlen / 16; i++ ) + { + memset( padding, (unsigned char) ('A' + i), 1 + i ); + + mbedtls_sha1_starts( &sha1 ); + mbedtls_sha1_update( &sha1, padding, 1 + i ); + mbedtls_sha1_update( &sha1, secret, slen ); + mbedtls_sha1_update( &sha1, random, rlen ); + mbedtls_sha1_finish( &sha1, sha1sum ); + + mbedtls_md5_starts( &md5 ); + mbedtls_md5_update( &md5, secret, slen ); + mbedtls_md5_update( &md5, sha1sum, 20 ); + mbedtls_md5_finish( &md5, dstbuf + i * 16 ); + } + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + mbedtls_zeroize( padding, sizeof( padding ) ); + mbedtls_zeroize( sha1sum, sizeof( sha1sum ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +static int tls1_prf( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t nb, hs; + size_t i, j, k; + const unsigned char *S1, *S2; + unsigned char tmp[128]; + unsigned char h_i[20]; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + int ret; + + mbedtls_md_init( &md_ctx ); + + if( sizeof( tmp ) < 20 + strlen( label ) + rlen ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + hs = ( slen + 1 ) / 2; + S1 = secret; + S2 = secret + slen - hs; + + nb = strlen( label ); + memcpy( tmp + 20, label, nb ); + memcpy( tmp + 20 + nb, random, rlen ); + nb += rlen; + + /* + * First compute P_md5(secret,label+random)[0..dlen] + */ + if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_MD5 ) ) == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + mbedtls_md_hmac_starts( &md_ctx, S1, hs ); + mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb ); + mbedtls_md_hmac_finish( &md_ctx, 4 + tmp ); + + for( i = 0; i < dlen; i += 16 ) + { + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, 4 + tmp, 16 + nb ); + mbedtls_md_hmac_finish( &md_ctx, h_i ); + + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, 4 + tmp, 16 ); + mbedtls_md_hmac_finish( &md_ctx, 4 + tmp ); + + k = ( i + 16 > dlen ) ? dlen % 16 : 16; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = h_i[j]; + } + + mbedtls_md_free( &md_ctx ); + + /* + * XOR out with P_sha1(secret,label+random)[0..dlen] + */ + if( ( md_info = mbedtls_md_info_from_type( MBEDTLS_MD_SHA1 ) ) == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + if( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + mbedtls_md_hmac_starts( &md_ctx, S2, hs ); + mbedtls_md_hmac_update( &md_ctx, tmp + 20, nb ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + for( i = 0; i < dlen; i += 20 ) + { + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, 20 + nb ); + mbedtls_md_hmac_finish( &md_ctx, h_i ); + + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, 20 ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + k = ( i + 20 > dlen ) ? dlen % 20 : 20; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = (unsigned char)( dstbuf[i + j] ^ h_i[j] ); + } + + mbedtls_md_free( &md_ctx ); + + mbedtls_zeroize( tmp, sizeof( tmp ) ); + mbedtls_zeroize( h_i, sizeof( h_i ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1) || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +static int tls_prf_generic( mbedtls_md_type_t md_type, + const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + size_t nb; + size_t i, j, k, md_len; + unsigned char tmp[128]; + unsigned char h_i[MBEDTLS_MD_MAX_SIZE]; + const mbedtls_md_info_t *md_info; + mbedtls_md_context_t md_ctx; + int ret; + + mbedtls_md_init( &md_ctx ); + + if( ( md_info = mbedtls_md_info_from_type( md_type ) ) == NULL ) + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + + md_len = mbedtls_md_get_size( md_info ); + + if( sizeof( tmp ) < md_len + strlen( label ) + rlen ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + nb = strlen( label ); + memcpy( tmp + md_len, label, nb ); + memcpy( tmp + md_len + nb, random, rlen ); + nb += rlen; + + /* + * Compute P_(secret, label + random)[0..dlen] + */ + if ( ( ret = mbedtls_md_setup( &md_ctx, md_info, 1 ) ) != 0 ) + return( ret ); + + mbedtls_md_hmac_starts( &md_ctx, secret, slen ); + mbedtls_md_hmac_update( &md_ctx, tmp + md_len, nb ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + for( i = 0; i < dlen; i += md_len ) + { + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, md_len + nb ); + mbedtls_md_hmac_finish( &md_ctx, h_i ); + + mbedtls_md_hmac_reset ( &md_ctx ); + mbedtls_md_hmac_update( &md_ctx, tmp, md_len ); + mbedtls_md_hmac_finish( &md_ctx, tmp ); + + k = ( i + md_len > dlen ) ? dlen % md_len : md_len; + + for( j = 0; j < k; j++ ) + dstbuf[i + j] = h_i[j]; + } + + mbedtls_md_free( &md_ctx ); + + mbedtls_zeroize( tmp, sizeof( tmp ) ); + mbedtls_zeroize( h_i, sizeof( h_i ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SHA256_C) +static int tls_prf_sha256( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + return( tls_prf_generic( MBEDTLS_MD_SHA256, secret, slen, + label, random, rlen, dstbuf, dlen ) ); +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static int tls_prf_sha384( const unsigned char *secret, size_t slen, + const char *label, + const unsigned char *random, size_t rlen, + unsigned char *dstbuf, size_t dlen ) +{ + return( tls_prf_generic( MBEDTLS_MD_SHA384, secret, slen, + label, random, rlen, dstbuf, dlen ) ); +} +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +static void ssl_update_checksum_start( mbedtls_ssl_context *, const unsigned char *, size_t ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_update_checksum_md5sha1( mbedtls_ssl_context *, const unsigned char *, size_t ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +static void ssl_calc_verify_ssl( mbedtls_ssl_context *, unsigned char * ); +static void ssl_calc_finished_ssl( mbedtls_ssl_context *, unsigned char *, int ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_calc_verify_tls( mbedtls_ssl_context *, unsigned char * ); +static void ssl_calc_finished_tls( mbedtls_ssl_context *, unsigned char *, int ); +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +static void ssl_update_checksum_sha256( mbedtls_ssl_context *, const unsigned char *, size_t ); +static void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *,unsigned char * ); +static void ssl_calc_finished_tls_sha256( mbedtls_ssl_context *,unsigned char *, int ); +#endif + +#if defined(MBEDTLS_SHA512_C) +static void ssl_update_checksum_sha384( mbedtls_ssl_context *, const unsigned char *, size_t ); +static void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *, unsigned char * ); +static void ssl_calc_finished_tls_sha384( mbedtls_ssl_context *, unsigned char *, int ); +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +int mbedtls_ssl_derive_keys( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + unsigned char tmp[64]; + unsigned char keyblk[256]; + unsigned char *key1; + unsigned char *key2; + unsigned char *mac_enc; + unsigned char *mac_dec; + size_t iv_copy_len; + const mbedtls_cipher_info_t *cipher_info; + const mbedtls_md_info_t *md_info; + + mbedtls_ssl_session *session = ssl->session_negotiate; + mbedtls_ssl_transform *transform = ssl->transform_negotiate; + mbedtls_ssl_handshake_params *handshake = ssl->handshake; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> derive keys" ) ); + + cipher_info = mbedtls_cipher_info_from_type( transform->ciphersuite_info->cipher ); + if( cipher_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "cipher info for %d not found", + transform->ciphersuite_info->cipher ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + md_info = mbedtls_md_info_from_type( transform->ciphersuite_info->mac ); + if( md_info == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "mbedtls_md info for %d not found", + transform->ciphersuite_info->mac ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * Set appropriate PRF function and other SSL / TLS / TLS1.2 functions + */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + handshake->tls_prf = ssl3_prf; + handshake->calc_verify = ssl_calc_verify_ssl; + handshake->calc_finished = ssl_calc_finished_ssl; + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ) + { + handshake->tls_prf = tls1_prf; + handshake->calc_verify = ssl_calc_verify_tls; + handshake->calc_finished = ssl_calc_finished_tls; + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA512_C) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 && + transform->ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) + { + handshake->tls_prf = tls_prf_sha384; + handshake->calc_verify = ssl_calc_verify_tls_sha384; + handshake->calc_finished = ssl_calc_finished_tls_sha384; + } + else +#endif +#if defined(MBEDTLS_SHA256_C) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + handshake->tls_prf = tls_prf_sha256; + handshake->calc_verify = ssl_calc_verify_tls_sha256; + handshake->calc_finished = ssl_calc_finished_tls_sha256; + } + else +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * SSLv3: + * master = + * MD5( premaster + SHA1( 'A' + premaster + randbytes ) ) + + * MD5( premaster + SHA1( 'BB' + premaster + randbytes ) ) + + * MD5( premaster + SHA1( 'CCC' + premaster + randbytes ) ) + * + * TLSv1+: + * master = PRF( premaster, "master secret", randbytes )[0..47] + */ + if( handshake->resume == 0 ) + { + MBEDTLS_SSL_DEBUG_BUF( 3, "premaster secret", handshake->premaster, + handshake->pmslen ); + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + if( ssl->handshake->extended_ms == MBEDTLS_SSL_EXTENDED_MS_ENABLED ) + { + unsigned char session_hash[48]; + size_t hash_len; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using extended master secret" ) ); + + ssl->handshake->calc_verify( ssl, session_hash ); + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { +#if defined(MBEDTLS_SHA512_C) + if( ssl->transform_negotiate->ciphersuite_info->mac == + MBEDTLS_MD_SHA384 ) + { + hash_len = 48; + } + else +#endif + hash_len = 32; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + hash_len = 36; + + MBEDTLS_SSL_DEBUG_BUF( 3, "session hash", session_hash, hash_len ); + + ret = handshake->tls_prf( handshake->premaster, handshake->pmslen, + "extended master secret", + session_hash, hash_len, + session->master, 48 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); + return( ret ); + } + + } + else +#endif + ret = handshake->tls_prf( handshake->premaster, handshake->pmslen, + "master secret", + handshake->randbytes, 64, + session->master, 48 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); + return( ret ); + } + + mbedtls_zeroize( handshake->premaster, sizeof(handshake->premaster) ); + } + else + MBEDTLS_SSL_DEBUG_MSG( 3, ( "no premaster (session resumed)" ) ); + + /* + * Swap the client and server random values. + */ + memcpy( tmp, handshake->randbytes, 64 ); + memcpy( handshake->randbytes, tmp + 32, 32 ); + memcpy( handshake->randbytes + 32, tmp, 32 ); + mbedtls_zeroize( tmp, sizeof( tmp ) ); + + /* + * SSLv3: + * key block = + * MD5( master + SHA1( 'A' + master + randbytes ) ) + + * MD5( master + SHA1( 'BB' + master + randbytes ) ) + + * MD5( master + SHA1( 'CCC' + master + randbytes ) ) + + * MD5( master + SHA1( 'DDDD' + master + randbytes ) ) + + * ... + * + * TLSv1: + * key block = PRF( master, "key expansion", randbytes ) + */ + ret = handshake->tls_prf( session->master, 48, "key expansion", + handshake->randbytes, 64, keyblk, 256 ); + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "prf", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "ciphersuite = %s", + mbedtls_ssl_get_ciphersuite_name( session->ciphersuite ) ) ); + MBEDTLS_SSL_DEBUG_BUF( 3, "master secret", session->master, 48 ); + MBEDTLS_SSL_DEBUG_BUF( 4, "random bytes", handshake->randbytes, 64 ); + MBEDTLS_SSL_DEBUG_BUF( 4, "key block", keyblk, 256 ); + + mbedtls_zeroize( handshake->randbytes, sizeof( handshake->randbytes ) ); + + /* + * Determine the appropriate key, IV and MAC length. + */ + + transform->keylen = cipher_info->key_bitlen / 8; + + if( cipher_info->mode == MBEDTLS_MODE_GCM || + cipher_info->mode == MBEDTLS_MODE_CCM ) + { + transform->maclen = 0; + + transform->ivlen = 12; + transform->fixed_ivlen = 4; + + /* Minimum length is expicit IV + tag */ + transform->minlen = transform->ivlen - transform->fixed_ivlen + + ( transform->ciphersuite_info->flags & + MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16 ); + } + else + { + /* Initialize HMAC contexts */ + if( ( ret = mbedtls_md_setup( &transform->md_ctx_enc, md_info, 1 ) ) != 0 || + ( ret = mbedtls_md_setup( &transform->md_ctx_dec, md_info, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_md_setup", ret ); + return( ret ); + } + + /* Get MAC length */ + transform->maclen = mbedtls_md_get_size( md_info ); + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + /* + * If HMAC is to be truncated, we shall keep the leftmost bytes, + * (rfc 6066 page 13 or rfc 2104 section 4), + * so we only need to adjust the length here. + */ + if( session->trunc_hmac == MBEDTLS_SSL_TRUNC_HMAC_ENABLED ) + transform->maclen = MBEDTLS_SSL_TRUNCATED_HMAC_LEN; +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + + /* IV length */ + transform->ivlen = cipher_info->iv_size; + + /* Minimum length */ + if( cipher_info->mode == MBEDTLS_MODE_STREAM ) + transform->minlen = transform->maclen; + else + { + /* + * GenericBlockCipher: + * 1. if EtM is in use: one block plus MAC + * otherwise: * first multiple of blocklen greater than maclen + * 2. IV except for SSL3 and TLS 1.0 + */ +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + if( session->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED ) + { + transform->minlen = transform->maclen + + cipher_info->block_size; + } + else +#endif + { + transform->minlen = transform->maclen + + cipher_info->block_size + - transform->maclen % cipher_info->block_size; + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_1 ) + ; /* No need to adjust minlen */ + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_2 || + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_3 ) + { + transform->minlen += transform->ivlen; + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "keylen: %d, minlen: %d, ivlen: %d, maclen: %d", + transform->keylen, transform->minlen, transform->ivlen, + transform->maclen ) ); + + /* + * Finally setup the cipher contexts, IVs and MAC secrets. + */ +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + key1 = keyblk + transform->maclen * 2; + key2 = keyblk + transform->maclen * 2 + transform->keylen; + + mac_enc = keyblk; + mac_dec = keyblk + transform->maclen; + + /* + * This is not used in TLS v1.1. + */ + iv_copy_len = ( transform->fixed_ivlen ) ? + transform->fixed_ivlen : transform->ivlen; + memcpy( transform->iv_enc, key2 + transform->keylen, iv_copy_len ); + memcpy( transform->iv_dec, key2 + transform->keylen + iv_copy_len, + iv_copy_len ); + } + else +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + key1 = keyblk + transform->maclen * 2 + transform->keylen; + key2 = keyblk + transform->maclen * 2; + + mac_enc = keyblk + transform->maclen; + mac_dec = keyblk; + + /* + * This is not used in TLS v1.1. + */ + iv_copy_len = ( transform->fixed_ivlen ) ? + transform->fixed_ivlen : transform->ivlen; + memcpy( transform->iv_dec, key1 + transform->keylen, iv_copy_len ); + memcpy( transform->iv_enc, key1 + transform->keylen + iv_copy_len, + iv_copy_len ); + } + else +#endif /* MBEDTLS_SSL_SRV_C */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( transform->maclen > sizeof transform->mac_enc ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + memcpy( transform->mac_enc, mac_enc, transform->maclen ); + memcpy( transform->mac_dec, mac_dec, transform->maclen ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + { + mbedtls_md_hmac_starts( &transform->md_ctx_enc, mac_enc, transform->maclen ); + mbedtls_md_hmac_starts( &transform->md_ctx_dec, mac_dec, transform->maclen ); + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_init != NULL ) + { + int ret = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_init()" ) ); + + if( ( ret = mbedtls_ssl_hw_record_init( ssl, key1, key2, transform->keylen, + transform->iv_enc, transform->iv_dec, + iv_copy_len, + mac_enc, mac_dec, + transform->maclen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_init", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + if( ssl->conf->f_export_keys != NULL ) + { + ssl->conf->f_export_keys( ssl->conf->p_export_keys, + session->master, keyblk, + transform->maclen, transform->keylen, + iv_copy_len ); + } +#endif + + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_enc, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_setup( &transform->cipher_ctx_dec, + cipher_info ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setup", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_enc, key1, + cipher_info->key_bitlen, + MBEDTLS_ENCRYPT ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_setkey( &transform->cipher_ctx_dec, key2, + cipher_info->key_bitlen, + MBEDTLS_DECRYPT ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_setkey", ret ); + return( ret ); + } + +#if defined(MBEDTLS_CIPHER_MODE_CBC) + if( cipher_info->mode == MBEDTLS_MODE_CBC ) + { + if( ( ret = mbedtls_cipher_set_padding_mode( &transform->cipher_ctx_enc, + MBEDTLS_PADDING_NONE ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret ); + return( ret ); + } + + if( ( ret = mbedtls_cipher_set_padding_mode( &transform->cipher_ctx_dec, + MBEDTLS_PADDING_NONE ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_set_padding_mode", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_CIPHER_MODE_CBC */ + + mbedtls_zeroize( keyblk, sizeof( keyblk ) ); + +#if defined(MBEDTLS_ZLIB_SUPPORT) + // Initialize compression + // + if( session->compression == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + if( ssl->compress_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Allocating compression buffer" ) ); + ssl->compress_buf = mbedtls_calloc( 1, MBEDTLS_SSL_BUFFER_LEN ); + if( ssl->compress_buf == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", + MBEDTLS_SSL_BUFFER_LEN ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "Initializing zlib states" ) ); + + memset( &transform->ctx_deflate, 0, sizeof( transform->ctx_deflate ) ); + memset( &transform->ctx_inflate, 0, sizeof( transform->ctx_inflate ) ); + + if( deflateInit( &transform->ctx_deflate, + Z_DEFAULT_COMPRESSION ) != Z_OK || + inflateInit( &transform->ctx_inflate ) != Z_OK ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Failed to initialize compression" ) ); + return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); + } + } +#endif /* MBEDTLS_ZLIB_SUPPORT */ + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= derive keys" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +void ssl_calc_verify_ssl( mbedtls_ssl_context *ssl, unsigned char hash[36] ) +{ + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + unsigned char pad_1[48]; + unsigned char pad_2[48]; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify ssl" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + memset( pad_1, 0x36, 48 ); + memset( pad_2, 0x5C, 48 ); + + mbedtls_md5_update( &md5, ssl->session_negotiate->master, 48 ); + mbedtls_md5_update( &md5, pad_1, 48 ); + mbedtls_md5_finish( &md5, hash ); + + mbedtls_md5_starts( &md5 ); + mbedtls_md5_update( &md5, ssl->session_negotiate->master, 48 ); + mbedtls_md5_update( &md5, pad_2, 48 ); + mbedtls_md5_update( &md5, hash, 16 ); + mbedtls_md5_finish( &md5, hash ); + + mbedtls_sha1_update( &sha1, ssl->session_negotiate->master, 48 ); + mbedtls_sha1_update( &sha1, pad_1, 40 ); + mbedtls_sha1_finish( &sha1, hash + 16 ); + + mbedtls_sha1_starts( &sha1 ); + mbedtls_sha1_update( &sha1, ssl->session_negotiate->master, 48 ); + mbedtls_sha1_update( &sha1, pad_2, 40 ); + mbedtls_sha1_update( &sha1, hash + 16, 20 ); + mbedtls_sha1_finish( &sha1, hash + 16 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + return; +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +void ssl_calc_verify_tls( mbedtls_ssl_context *ssl, unsigned char hash[36] ) +{ + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify tls" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + mbedtls_md5_finish( &md5, hash ); + mbedtls_sha1_finish( &sha1, hash + 16 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 36 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + return; +} +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +void ssl_calc_verify_tls_sha256( mbedtls_ssl_context *ssl, unsigned char hash[32] ) +{ + mbedtls_sha256_context sha256; + + mbedtls_sha256_init( &sha256 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify sha256" ) ); + + mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 ); + mbedtls_sha256_finish( &sha256, hash ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 32 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_sha256_free( &sha256 ); + + return; +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +void ssl_calc_verify_tls_sha384( mbedtls_ssl_context *ssl, unsigned char hash[48] ) +{ + mbedtls_sha512_context sha512; + + mbedtls_sha512_init( &sha512 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc verify sha384" ) ); + + mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 ); + mbedtls_sha512_finish( &sha512, hash ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calculated verify result", hash, 48 ); + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc verify" ) ); + + mbedtls_sha512_free( &sha512 ); + + return; +} +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +int mbedtls_ssl_psk_derive_premaster( mbedtls_ssl_context *ssl, mbedtls_key_exchange_type_t key_ex ) +{ + unsigned char *p = ssl->handshake->premaster; + unsigned char *end = p + sizeof( ssl->handshake->premaster ); + const unsigned char *psk = ssl->conf->psk; + size_t psk_len = ssl->conf->psk_len; + + /* If the psk callback was called, use its result */ + if( ssl->handshake->psk != NULL ) + { + psk = ssl->handshake->psk; + psk_len = ssl->handshake->psk_len; + } + + /* + * PMS = struct { + * opaque other_secret<0..2^16-1>; + * opaque psk<0..2^16-1>; + * }; + * with "other_secret" depending on the particular key exchange + */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_PSK ) + { + if( end - p < 2 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + *(p++) = (unsigned char)( psk_len >> 8 ); + *(p++) = (unsigned char)( psk_len ); + + if( end < p || (size_t)( end - p ) < psk_len ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memset( p, 0, psk_len ); + p += psk_len; + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + /* + * other_secret already set by the ClientKeyExchange message, + * and is 48 bytes long + */ + *p++ = 0; + *p++ = 48; + p += 48; + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_DHE_PSK ) + { + int ret; + size_t len; + + /* Write length only when we know the actual value */ + if( ( ret = mbedtls_dhm_calc_secret( &ssl->handshake->dhm_ctx, + p + 2, end - ( p + 2 ), &len, + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_dhm_calc_secret", ret ); + return( ret ); + } + *(p++) = (unsigned char)( len >> 8 ); + *(p++) = (unsigned char)( len ); + p += len; + + MBEDTLS_SSL_DEBUG_MPI( 3, "DHM: K ", &ssl->handshake->dhm_ctx.K ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + if( key_ex == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK ) + { + int ret; + size_t zlen; + + if( ( ret = mbedtls_ecdh_calc_secret( &ssl->handshake->ecdh_ctx, &zlen, + p + 2, end - ( p + 2 ), + ssl->conf->f_rng, ssl->conf->p_rng ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ecdh_calc_secret", ret ); + return( ret ); + } + + *(p++) = (unsigned char)( zlen >> 8 ); + *(p++) = (unsigned char)( zlen ); + p += zlen; + + MBEDTLS_SSL_DEBUG_MPI( 3, "ECDH: z", &ssl->handshake->ecdh_ctx.z ); + } + else +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* opaque psk<0..2^16-1>; */ + if( end - p < 2 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + *(p++) = (unsigned char)( psk_len >> 8 ); + *(p++) = (unsigned char)( psk_len ); + + if( end < p || (size_t)( end - p ) < psk_len ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + memcpy( p, psk, psk_len ); + p += psk_len; + + ssl->handshake->pmslen = p - ssl->handshake->premaster; + + return( 0 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +/* + * SSLv3.0 MAC functions + */ +static void ssl_mac( mbedtls_md_context_t *md_ctx, unsigned char *secret, + unsigned char *buf, size_t len, + unsigned char *ctr, int type ) +{ + unsigned char header[11]; + unsigned char padding[48]; + int padlen; + int md_size = mbedtls_md_get_size( md_ctx->md_info ); + int md_type = mbedtls_md_get_type( md_ctx->md_info ); + + /* Only MD5 and SHA-1 supported */ + if( md_type == MBEDTLS_MD_MD5 ) + padlen = 48; + else + padlen = 40; + + memcpy( header, ctr, 8 ); + header[ 8] = (unsigned char) type; + header[ 9] = (unsigned char)( len >> 8 ); + header[10] = (unsigned char)( len ); + + memset( padding, 0x36, padlen ); + mbedtls_md_starts( md_ctx ); + mbedtls_md_update( md_ctx, secret, md_size ); + mbedtls_md_update( md_ctx, padding, padlen ); + mbedtls_md_update( md_ctx, header, 11 ); + mbedtls_md_update( md_ctx, buf, len ); + mbedtls_md_finish( md_ctx, buf + len ); + + memset( padding, 0x5C, padlen ); + mbedtls_md_starts( md_ctx ); + mbedtls_md_update( md_ctx, secret, md_size ); + mbedtls_md_update( md_ctx, padding, padlen ); + mbedtls_md_update( md_ctx, buf + len, md_size ); + mbedtls_md_finish( md_ctx, buf + len ); +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) || \ + ( defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) ) +#define SSL_SOME_MODES_USE_MAC +#endif + +/* + * Encryption/decryption functions + */ +static int ssl_encrypt_buf( mbedtls_ssl_context *ssl ) +{ + mbedtls_cipher_mode_t mode; + int auth_done = 0; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> encrypt buf" ) ); + + if( ssl->session_out == NULL || ssl->transform_out == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + mode = mbedtls_cipher_get_cipher_mode( &ssl->transform_out->cipher_ctx_enc ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "before encrypt: output payload", + ssl->out_msg, ssl->out_msglen ); + + /* + * Add MAC before if needed + */ +#if defined(SSL_SOME_MODES_USE_MAC) + if( mode == MBEDTLS_MODE_STREAM || + ( mode == MBEDTLS_MODE_CBC +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + && ssl->session_out->encrypt_then_mac == MBEDTLS_SSL_ETM_DISABLED +#endif + ) ) + { +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl_mac( &ssl->transform_out->md_ctx_enc, + ssl->transform_out->mac_enc, + ssl->out_msg, ssl->out_msglen, + ssl->out_ctr, ssl->out_msgtype ); + } + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + { + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_ctr, 8 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_hdr, 3 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, ssl->out_len, 2 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, + ssl->out_msg, ssl->out_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, + ssl->out_msg + ssl->out_msglen ); + mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc ); + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", + ssl->out_msg + ssl->out_msglen, + ssl->transform_out->maclen ); + + ssl->out_msglen += ssl->transform_out->maclen; + auth_done++; + } +#endif /* AEAD not the only option */ + + /* + * Encrypt + */ +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) + if( mode == MBEDTLS_MODE_STREAM ) + { + int ret; + size_t olen = 0; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of padding", + ssl->out_msglen, 0 ) ); + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_out->cipher_ctx_enc, + ssl->transform_out->iv_enc, + ssl->transform_out->ivlen, + ssl->out_msg, ssl->out_msglen, + ssl->out_msg, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( ssl->out_msglen != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) + if( mode == MBEDTLS_MODE_GCM || + mode == MBEDTLS_MODE_CCM ) + { + int ret; + size_t enc_msglen, olen; + unsigned char *enc_msg; + unsigned char add_data[13]; + unsigned char taglen = ssl->transform_out->ciphersuite_info->flags & + MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; + + memcpy( add_data, ssl->out_ctr, 8 ); + add_data[8] = ssl->out_msgtype; + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, add_data + 9 ); + add_data[11] = ( ssl->out_msglen >> 8 ) & 0xFF; + add_data[12] = ssl->out_msglen & 0xFF; + + MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", + add_data, 13 ); + + /* + * Generate IV + */ + if( ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen != 8 ) + { + /* Reminder if we ever add an AEAD mode with a different size */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + memcpy( ssl->transform_out->iv_enc + ssl->transform_out->fixed_ivlen, + ssl->out_ctr, 8 ); + memcpy( ssl->out_iv, ssl->out_ctr, 8 ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->out_iv, + ssl->transform_out->ivlen - ssl->transform_out->fixed_ivlen ); + + /* + * Fix pointer positions and message length with added IV + */ + enc_msg = ssl->out_msg; + enc_msglen = ssl->out_msglen; + ssl->out_msglen += ssl->transform_out->ivlen - + ssl->transform_out->fixed_ivlen; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of padding", + ssl->out_msglen, 0 ) ); + + /* + * Encrypt and authenticate + */ + if( ( ret = mbedtls_cipher_auth_encrypt( &ssl->transform_out->cipher_ctx_enc, + ssl->transform_out->iv_enc, + ssl->transform_out->ivlen, + add_data, 13, + enc_msg, enc_msglen, + enc_msg, &olen, + enc_msg + enc_msglen, taglen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_encrypt", ret ); + return( ret ); + } + + if( olen != enc_msglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->out_msglen += taglen; + auth_done++; + + MBEDTLS_SSL_DEBUG_BUF( 4, "after encrypt: tag", enc_msg + enc_msglen, taglen ); + } + else +#endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) + if( mode == MBEDTLS_MODE_CBC ) + { + int ret; + unsigned char *enc_msg; + size_t enc_msglen, padlen, olen = 0, i; + + padlen = ssl->transform_out->ivlen - ( ssl->out_msglen + 1 ) % + ssl->transform_out->ivlen; + if( padlen == ssl->transform_out->ivlen ) + padlen = 0; + + for( i = 0; i <= padlen; i++ ) + ssl->out_msg[ssl->out_msglen + i] = (unsigned char) padlen; + + ssl->out_msglen += padlen + 1; + + enc_msglen = ssl->out_msglen; + enc_msg = ssl->out_msg; + +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * Prepend per-record IV for block cipher in TLS v1.1 and up as per + * Method 1 (6.2.3.2. in RFC4346 and RFC5246) + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* + * Generate IV + */ + ret = ssl->conf->f_rng( ssl->conf->p_rng, ssl->transform_out->iv_enc, + ssl->transform_out->ivlen ); + if( ret != 0 ) + return( ret ); + + memcpy( ssl->out_iv, ssl->transform_out->iv_enc, + ssl->transform_out->ivlen ); + + /* + * Fix pointer positions and message length with added IV + */ + enc_msg = ssl->out_msg; + enc_msglen = ssl->out_msglen; + ssl->out_msglen += ssl->transform_out->ivlen; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before encrypt: msglen = %d, " + "including %d bytes of IV and %d bytes of padding", + ssl->out_msglen, ssl->transform_out->ivlen, + padlen + 1 ) ); + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_out->cipher_ctx_enc, + ssl->transform_out->iv_enc, + ssl->transform_out->ivlen, + enc_msg, enc_msglen, + enc_msg, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( enc_msglen != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* + * Save IV in SSL3 and TLS1 + */ + memcpy( ssl->transform_out->iv_enc, + ssl->transform_out->cipher_ctx_enc.iv, + ssl->transform_out->ivlen ); + } +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + if( auth_done == 0 ) + { + /* + * MAC(MAC_write_key, seq_num + + * TLSCipherText.type + + * TLSCipherText.version + + * length_of( (IV +) ENC(...) ) + + * IV + // except for TLS 1.0 + * ENC(content + padding + padding_length)); + */ + unsigned char pseudo_hdr[13]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); + + memcpy( pseudo_hdr + 0, ssl->out_ctr, 8 ); + memcpy( pseudo_hdr + 8, ssl->out_hdr, 3 ); + pseudo_hdr[11] = (unsigned char)( ( ssl->out_msglen >> 8 ) & 0xFF ); + pseudo_hdr[12] = (unsigned char)( ( ssl->out_msglen ) & 0xFF ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", pseudo_hdr, 13 ); + + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, pseudo_hdr, 13 ); + mbedtls_md_hmac_update( &ssl->transform_out->md_ctx_enc, + ssl->out_iv, ssl->out_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_out->md_ctx_enc, + ssl->out_iv + ssl->out_msglen ); + mbedtls_md_hmac_reset( &ssl->transform_out->md_ctx_enc ); + + ssl->out_msglen += ssl->transform_out->maclen; + auth_done++; + } +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + } + else +#endif /* MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C ) */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* Make extra sure authentication was performed, exactly once */ + if( auth_done != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= encrypt buf" ) ); + + return( 0 ); +} + +#define SSL_MAX_MAC_SIZE 48 + +static int ssl_decrypt_buf( mbedtls_ssl_context *ssl ) +{ + size_t i; + mbedtls_cipher_mode_t mode; + int auth_done = 0; +#if defined(SSL_SOME_MODES_USE_MAC) + size_t padlen = 0, correct = 1; +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> decrypt buf" ) ); + + if( ssl->session_in == NULL || ssl->transform_in == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + mode = mbedtls_cipher_get_cipher_mode( &ssl->transform_in->cipher_ctx_dec ); + + if( ssl->in_msglen < ssl->transform_in->minlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "in_msglen (%d) < minlen (%d)", + ssl->in_msglen, ssl->transform_in->minlen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + +#if defined(MBEDTLS_ARC4_C) || defined(MBEDTLS_CIPHER_NULL_CIPHER) + if( mode == MBEDTLS_MODE_STREAM ) + { + int ret; + size_t olen = 0; + + padlen = 0; + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_in->cipher_ctx_dec, + ssl->transform_in->iv_dec, + ssl->transform_in->ivlen, + ssl->in_msg, ssl->in_msglen, + ssl->in_msg, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( ssl->in_msglen != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_ARC4_C || MBEDTLS_CIPHER_NULL_CIPHER */ +#if defined(MBEDTLS_GCM_C) || defined(MBEDTLS_CCM_C) + if( mode == MBEDTLS_MODE_GCM || + mode == MBEDTLS_MODE_CCM ) + { + int ret; + size_t dec_msglen, olen; + unsigned char *dec_msg; + unsigned char *dec_msg_result; + unsigned char add_data[13]; + unsigned char taglen = ssl->transform_in->ciphersuite_info->flags & + MBEDTLS_CIPHERSUITE_SHORT_TAG ? 8 : 16; + size_t explicit_iv_len = ssl->transform_in->ivlen - + ssl->transform_in->fixed_ivlen; + + if( ssl->in_msglen < explicit_iv_len + taglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < explicit_iv_len (%d) " + "+ taglen (%d)", ssl->in_msglen, + explicit_iv_len, taglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + dec_msglen = ssl->in_msglen - explicit_iv_len - taglen; + + dec_msg = ssl->in_msg; + dec_msg_result = ssl->in_msg; + ssl->in_msglen = dec_msglen; + + memcpy( add_data, ssl->in_ctr, 8 ); + add_data[8] = ssl->in_msgtype; + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, add_data + 9 ); + add_data[11] = ( ssl->in_msglen >> 8 ) & 0xFF; + add_data[12] = ssl->in_msglen & 0xFF; + + MBEDTLS_SSL_DEBUG_BUF( 4, "additional data used for AEAD", + add_data, 13 ); + + memcpy( ssl->transform_in->iv_dec + ssl->transform_in->fixed_ivlen, + ssl->in_iv, + ssl->transform_in->ivlen - ssl->transform_in->fixed_ivlen ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "IV used", ssl->transform_in->iv_dec, + ssl->transform_in->ivlen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "TAG used", dec_msg + dec_msglen, taglen ); + + /* + * Decrypt and authenticate + */ + if( ( ret = mbedtls_cipher_auth_decrypt( &ssl->transform_in->cipher_ctx_dec, + ssl->transform_in->iv_dec, + ssl->transform_in->ivlen, + add_data, 13, + dec_msg, dec_msglen, + dec_msg_result, &olen, + dec_msg + dec_msglen, taglen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_decrypt", ret ); + + if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED ) + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + + return( ret ); + } + auth_done++; + + if( olen != dec_msglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else +#endif /* MBEDTLS_GCM_C || MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) && \ + ( defined(MBEDTLS_AES_C) || defined(MBEDTLS_CAMELLIA_C) ) + if( mode == MBEDTLS_MODE_CBC ) + { + /* + * Decrypt and check the padding + */ + int ret; + unsigned char *dec_msg; + unsigned char *dec_msg_result; + size_t dec_msglen; + size_t minlen = 0; + size_t olen = 0; + + /* + * Check immediate ciphertext sanity + */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + minlen += ssl->transform_in->ivlen; +#endif + + if( ssl->in_msglen < minlen + ssl->transform_in->ivlen || + ssl->in_msglen < minlen + ssl->transform_in->maclen + 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < max( ivlen(%d), maclen (%d) " + "+ 1 ) ( + expl IV )", ssl->in_msglen, + ssl->transform_in->ivlen, + ssl->transform_in->maclen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + + dec_msglen = ssl->in_msglen; + dec_msg = ssl->in_msg; + dec_msg_result = ssl->in_msg; + + /* + * Authenticate before decrypt if enabled + */ +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + if( ssl->session_in->encrypt_then_mac == MBEDTLS_SSL_ETM_ENABLED ) + { + unsigned char computed_mac[SSL_MAX_MAC_SIZE]; + unsigned char pseudo_hdr[13]; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "using encrypt then mac" ) ); + + dec_msglen -= ssl->transform_in->maclen; + ssl->in_msglen -= ssl->transform_in->maclen; + + memcpy( pseudo_hdr + 0, ssl->in_ctr, 8 ); + memcpy( pseudo_hdr + 8, ssl->in_hdr, 3 ); + pseudo_hdr[11] = (unsigned char)( ( ssl->in_msglen >> 8 ) & 0xFF ); + pseudo_hdr[12] = (unsigned char)( ( ssl->in_msglen ) & 0xFF ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "MAC'd meta-data", pseudo_hdr, 13 ); + + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, pseudo_hdr, 13 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, + ssl->in_iv, ssl->in_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, computed_mac ); + mbedtls_md_hmac_reset( &ssl->transform_in->md_ctx_dec ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", ssl->in_iv + ssl->in_msglen, + ssl->transform_in->maclen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", computed_mac, + ssl->transform_in->maclen ); + + if( mbedtls_ssl_safer_memcmp( ssl->in_iv + ssl->in_msglen, computed_mac, + ssl->transform_in->maclen ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); + + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + auth_done++; + } +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ + + /* + * Check length sanity + */ + if( ssl->in_msglen % ssl->transform_in->ivlen != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) %% ivlen (%d) != 0", + ssl->in_msglen, ssl->transform_in->ivlen ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) || defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * Initialize for prepended IV for block cipher in TLS v1.1 and up + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + dec_msglen -= ssl->transform_in->ivlen; + ssl->in_msglen -= ssl->transform_in->ivlen; + + for( i = 0; i < ssl->transform_in->ivlen; i++ ) + ssl->transform_in->iv_dec[i] = ssl->in_iv[i]; + } +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 || MBEDTLS_SSL_PROTO_TLS1_2 */ + + if( ( ret = mbedtls_cipher_crypt( &ssl->transform_in->cipher_ctx_dec, + ssl->transform_in->iv_dec, + ssl->transform_in->ivlen, + dec_msg, dec_msglen, + dec_msg_result, &olen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_crypt", ret ); + return( ret ); + } + + if( dec_msglen != olen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_2 ) + { + /* + * Save IV in SSL3 and TLS1 + */ + memcpy( ssl->transform_in->iv_dec, + ssl->transform_in->cipher_ctx_dec.iv, + ssl->transform_in->ivlen ); + } +#endif + + padlen = 1 + ssl->in_msg[ssl->in_msglen - 1]; + + if( ssl->in_msglen < ssl->transform_in->maclen + padlen && + auth_done == 0 ) + { +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "msglen (%d) < maclen (%d) + padlen (%d)", + ssl->in_msglen, ssl->transform_in->maclen, padlen ) ); +#endif + padlen = 0; + correct = 0; + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( padlen > ssl->transform_in->ivlen ) + { +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad padding length: is %d, " + "should be no more than %d", + padlen, ssl->transform_in->ivlen ) ); +#endif + correct = 0; + } + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver > MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* + * TLSv1+: always check the padding up to the first failure + * and fake check up to 256 bytes of padding + */ + size_t pad_count = 0, real_count = 1; + size_t padding_idx = ssl->in_msglen - padlen - 1; + + /* + * Padding is guaranteed to be incorrect if: + * 1. padlen >= ssl->in_msglen + * + * 2. padding_idx >= MBEDTLS_SSL_MAX_CONTENT_LEN + + * ssl->transform_in->maclen + * + * In both cases we reset padding_idx to a safe value (0) to + * prevent out-of-buffer reads. + */ + correct &= ( ssl->in_msglen >= padlen + 1 ); + correct &= ( padding_idx < MBEDTLS_SSL_MAX_CONTENT_LEN + + ssl->transform_in->maclen ); + + padding_idx *= correct; + + for( i = 1; i <= 256; i++ ) + { + real_count &= ( i <= padlen ); + pad_count += real_count * + ( ssl->in_msg[padding_idx + i] == padlen - 1 ); + } + + correct &= ( pad_count == padlen ); /* Only 1 on correct padding */ + +#if defined(MBEDTLS_SSL_DEBUG_ALL) + if( padlen > 0 && correct == 0 ) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad padding byte detected" ) ); +#endif + padlen &= correct * 0x1FF; + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->in_msglen -= padlen; + } + else +#endif /* MBEDTLS_CIPHER_MODE_CBC && + ( MBEDTLS_AES_C || MBEDTLS_CAMELLIA_C ) */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "raw buffer after decryption", + ssl->in_msg, ssl->in_msglen ); + + /* + * Authenticate if not done yet. + * Compute the MAC regardless of the padding result (RFC4346, CBCTIME). + */ +#if defined(SSL_SOME_MODES_USE_MAC) + if( auth_done == 0 ) + { + unsigned char tmp[SSL_MAX_MAC_SIZE]; + + ssl->in_msglen -= ssl->transform_in->maclen; + + ssl->in_len[0] = (unsigned char)( ssl->in_msglen >> 8 ); + ssl->in_len[1] = (unsigned char)( ssl->in_msglen ); + + memcpy( tmp, ssl->in_msg + ssl->in_msglen, ssl->transform_in->maclen ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl_mac( &ssl->transform_in->md_ctx_dec, + ssl->transform_in->mac_dec, + ssl->in_msg, ssl->in_msglen, + ssl->in_ctr, ssl->in_msgtype ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver > MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* + * Process MAC and always update for padlen afterwards to make + * total time independent of padlen + * + * extra_run compensates MAC check for padlen + * + * Known timing attacks: + * - Lucky Thirteen (http://www.isg.rhul.ac.uk/tls/TLStiming.pdf) + * + * We use ( ( Lx + 8 ) / 64 ) to handle 'negative Lx' values + * correctly. (We round down instead of up, so -56 is the correct + * value for our calculations instead of -55) + */ + size_t j, extra_run = 0; + extra_run = ( 13 + ssl->in_msglen + padlen + 8 ) / 64 - + ( 13 + ssl->in_msglen + 8 ) / 64; + + extra_run &= correct * 0xFF; + + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_ctr, 8 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_hdr, 3 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_len, 2 ); + mbedtls_md_hmac_update( &ssl->transform_in->md_ctx_dec, ssl->in_msg, + ssl->in_msglen ); + mbedtls_md_hmac_finish( &ssl->transform_in->md_ctx_dec, + ssl->in_msg + ssl->in_msglen ); + /* Call mbedtls_md_process at least once due to cache attacks */ + for( j = 0; j < extra_run + 1; j++ ) + mbedtls_md_process( &ssl->transform_in->md_ctx_dec, ssl->in_msg ); + + mbedtls_md_hmac_reset( &ssl->transform_in->md_ctx_dec ); + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "message mac", tmp, ssl->transform_in->maclen ); + MBEDTLS_SSL_DEBUG_BUF( 4, "computed mac", ssl->in_msg + ssl->in_msglen, + ssl->transform_in->maclen ); + + if( mbedtls_ssl_safer_memcmp( tmp, ssl->in_msg + ssl->in_msglen, + ssl->transform_in->maclen ) != 0 ) + { +#if defined(MBEDTLS_SSL_DEBUG_ALL) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "message mac does not match" ) ); +#endif + correct = 0; + } + auth_done++; + + /* + * Finally check the correct flag + */ + if( correct == 0 ) + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } +#endif /* SSL_SOME_MODES_USE_MAC */ + + /* Make extra sure authentication was performed, exactly once */ + if( auth_done != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + if( ssl->in_msglen == 0 ) + { + ssl->nb_zero++; + + /* + * Three or more empty messages may be a DoS attack + * (excessive CPU consumption). + */ + if( ssl->nb_zero > 3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received four consecutive empty " + "messages, possible DoS attack" ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } + } + else + ssl->nb_zero = 0; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ; /* in_ctr read from peer, not maintained internally */ + } + else +#endif + { + for( i = 8; i > ssl_ep_len( ssl ); i-- ) + if( ++ssl->in_ctr[i - 1] != 0 ) + break; + + /* The loop goes to its end iff the counter is wrapping */ + if( i == ssl_ep_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "incoming message counter would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= decrypt buf" ) ); + + return( 0 ); +} + +#undef MAC_NONE +#undef MAC_PLAINTEXT +#undef MAC_CIPHERTEXT + +#if defined(MBEDTLS_ZLIB_SUPPORT) +/* + * Compression/decompression functions + */ +static int ssl_compress_buf( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *msg_post = ssl->out_msg; + size_t len_pre = ssl->out_msglen; + unsigned char *msg_pre = ssl->compress_buf; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> compress buf" ) ); + + if( len_pre == 0 ) + return( 0 ); + + memcpy( msg_pre, ssl->out_msg, len_pre ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before compression: msglen = %d, ", + ssl->out_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "before compression: output payload", + ssl->out_msg, ssl->out_msglen ); + + ssl->transform_out->ctx_deflate.next_in = msg_pre; + ssl->transform_out->ctx_deflate.avail_in = len_pre; + ssl->transform_out->ctx_deflate.next_out = msg_post; + ssl->transform_out->ctx_deflate.avail_out = MBEDTLS_SSL_BUFFER_LEN; + + ret = deflate( &ssl->transform_out->ctx_deflate, Z_SYNC_FLUSH ); + if( ret != Z_OK ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "failed to perform compression (%d)", ret ) ); + return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); + } + + ssl->out_msglen = MBEDTLS_SSL_BUFFER_LEN - + ssl->transform_out->ctx_deflate.avail_out; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "after compression: msglen = %d, ", + ssl->out_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "after compression: output payload", + ssl->out_msg, ssl->out_msglen ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= compress buf" ) ); + + return( 0 ); +} + +static int ssl_decompress_buf( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *msg_post = ssl->in_msg; + size_t len_pre = ssl->in_msglen; + unsigned char *msg_pre = ssl->compress_buf; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> decompress buf" ) ); + + if( len_pre == 0 ) + return( 0 ); + + memcpy( msg_pre, ssl->in_msg, len_pre ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "before decompression: msglen = %d, ", + ssl->in_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "before decompression: input payload", + ssl->in_msg, ssl->in_msglen ); + + ssl->transform_in->ctx_inflate.next_in = msg_pre; + ssl->transform_in->ctx_inflate.avail_in = len_pre; + ssl->transform_in->ctx_inflate.next_out = msg_post; + ssl->transform_in->ctx_inflate.avail_out = MBEDTLS_SSL_MAX_CONTENT_LEN; + + ret = inflate( &ssl->transform_in->ctx_inflate, Z_SYNC_FLUSH ); + if( ret != Z_OK ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "failed to perform decompression (%d)", ret ) ); + return( MBEDTLS_ERR_SSL_COMPRESSION_FAILED ); + } + + ssl->in_msglen = MBEDTLS_SSL_MAX_CONTENT_LEN - + ssl->transform_in->ctx_inflate.avail_out; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "after decompression: msglen = %d, ", + ssl->in_msglen ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "after decompression: input payload", + ssl->in_msg, ssl->in_msglen ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= decompress buf" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_ZLIB_SUPPORT */ + +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) +static int ssl_write_hello_request( mbedtls_ssl_context *ssl ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +static int ssl_resend_hello_request( mbedtls_ssl_context *ssl ) +{ + /* If renegotiation is not enforced, retransmit until we would reach max + * timeout if we were using the usual handshake doubling scheme */ + if( ssl->conf->renego_max_records < 0 ) + { + uint32_t ratio = ssl->conf->hs_timeout_max / ssl->conf->hs_timeout_min + 1; + unsigned char doublings = 1; + + while( ratio != 0 ) + { + ++doublings; + ratio >>= 1; + } + + if( ++ssl->renego_records_seen > doublings ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "no longer retransmitting hello request" ) ); + return( 0 ); + } + } + + return( ssl_write_hello_request( ssl ) ); +} +#endif +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */ + +/* + * Fill the input message buffer by appending data to it. + * The amount of data already fetched is in ssl->in_left. + * + * If we return 0, is it guaranteed that (at least) nb_want bytes are + * available (from this read and/or a previous one). Otherwise, an error code + * is returned (possibly EOF or WANT_READ). + * + * With stream transport (TLS) on success ssl->in_left == nb_want, but + * with datagram transport (DTLS) on success ssl->in_left >= nb_want, + * since we always read a whole datagram at once. + * + * For DTLS, it is up to the caller to set ssl->next_record_offset when + * they're done reading a record. + */ +int mbedtls_ssl_fetch_input( mbedtls_ssl_context *ssl, size_t nb_want ) +{ + int ret; + size_t len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> fetch input" ) ); + + if( ssl->f_recv == NULL && ssl->f_recv_timeout == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " + "or mbedtls_ssl_set_bio()" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( nb_want > MBEDTLS_SSL_BUFFER_LEN - (size_t)( ssl->in_hdr - ssl->in_buf ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "requesting more data than fits" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + uint32_t timeout; + + /* Just to be sure */ + if( ssl->f_set_timer == NULL || ssl->f_get_timer == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "You must use " + "mbedtls_ssl_set_timer_cb() for DTLS" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* + * The point is, we need to always read a full datagram at once, so we + * sometimes read more then requested, and handle the additional data. + * It could be the rest of the current record (while fetching the + * header) and/or some other records in the same datagram. + */ + + /* + * Move to the next record in the already read datagram if applicable + */ + if( ssl->next_record_offset != 0 ) + { + if( ssl->in_left < ssl->next_record_offset ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->in_left -= ssl->next_record_offset; + + if( ssl->in_left != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "next record in same datagram, offset: %d", + ssl->next_record_offset ) ); + memmove( ssl->in_hdr, + ssl->in_hdr + ssl->next_record_offset, + ssl->in_left ); + } + + ssl->next_record_offset = 0; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", + ssl->in_left, nb_want ) ); + + /* + * Done if we already have enough data. + */ + if( nb_want <= ssl->in_left) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= fetch input" ) ); + return( 0 ); + } + + /* + * A record can't be split accross datagrams. If we need to read but + * are not at the beginning of a new record, the caller did something + * wrong. + */ + if( ssl->in_left != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + /* + * Don't even try to read if time's out already. + * This avoids by-passing the timer when repeatedly receiving messages + * that will end up being dropped. + */ + if( ssl_check_timer( ssl ) != 0 ) + ret = MBEDTLS_ERR_SSL_TIMEOUT; + else + { + len = MBEDTLS_SSL_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf ); + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + timeout = ssl->handshake->retransmit_timeout; + else + timeout = ssl->conf->read_timeout; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "f_recv_timeout: %u ms", timeout ) ); + + if( ssl->f_recv_timeout != NULL ) + ret = ssl->f_recv_timeout( ssl->p_bio, ssl->in_hdr, len, + timeout ); + else + ret = ssl->f_recv( ssl->p_bio, ssl->in_hdr, len ); + + MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_recv(_timeout)", ret ); + + if( ret == 0 ) + return( MBEDTLS_ERR_SSL_CONN_EOF ); + } + + if( ret == MBEDTLS_ERR_SSL_TIMEOUT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "timeout" ) ); + ssl_set_timer( ssl, 0 ); + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ssl_double_retransmit_timeout( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake timeout" ) ); + return( MBEDTLS_ERR_SSL_TIMEOUT ); + } + + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) + else if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + if( ( ret = ssl_resend_hello_request( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_resend_hello_request", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */ + } + + if( ret < 0 ) + return( ret ); + + ssl->in_left = ret; + } + else +#endif + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", + ssl->in_left, nb_want ) ); + + while( ssl->in_left < nb_want ) + { + len = nb_want - ssl->in_left; + + if( ssl_check_timer( ssl ) != 0 ) + ret = MBEDTLS_ERR_SSL_TIMEOUT; + else + { + if( ssl->f_recv_timeout != NULL ) + { + ret = ssl->f_recv_timeout( ssl->p_bio, + ssl->in_hdr + ssl->in_left, len, + ssl->conf->read_timeout ); + } + else + { + ret = ssl->f_recv( ssl->p_bio, + ssl->in_hdr + ssl->in_left, len ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "in_left: %d, nb_want: %d", + ssl->in_left, nb_want ) ); + MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_recv(_timeout)", ret ); + + if( ret == 0 ) + return( MBEDTLS_ERR_SSL_CONN_EOF ); + + if( ret < 0 ) + return( ret ); + + ssl->in_left += ret; + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= fetch input" ) ); + + return( 0 ); +} + +/* + * Flush any data not yet written + */ +int mbedtls_ssl_flush_output( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned char *buf, i; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> flush output" ) ); + + if( ssl->f_send == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "Bad usage of mbedtls_ssl_set_bio() " + "or mbedtls_ssl_set_bio()" ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + /* Avoid incrementing counter if data is flushed */ + if( ssl->out_left == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) ); + return( 0 ); + } + + while( ssl->out_left > 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "message length: %d, out_left: %d", + mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen, ssl->out_left ) ); + + buf = ssl->out_hdr + mbedtls_ssl_hdr_len( ssl ) + + ssl->out_msglen - ssl->out_left; + ret = ssl->f_send( ssl->p_bio, buf, ssl->out_left ); + + MBEDTLS_SSL_DEBUG_RET( 2, "ssl->f_send", ret ); + + if( ret <= 0 ) + return( ret ); + + ssl->out_left -= ret; + } + + for( i = 8; i > ssl_ep_len( ssl ); i-- ) + if( ++ssl->out_ctr[i - 1] != 0 ) + break; + + /* The loop goes to its end iff the counter is wrapping */ + if( i == ssl_ep_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "outgoing message counter would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= flush output" ) ); + + return( 0 ); +} + +/* + * Functions to handle the DTLS retransmission state machine + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/* + * Append current handshake message to current outgoing flight + */ +static int ssl_flight_append( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_flight_item *msg; + + /* Allocate space for current message */ + if( ( msg = mbedtls_calloc( 1, sizeof( mbedtls_ssl_flight_item ) ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc %d bytes failed", + sizeof( mbedtls_ssl_flight_item ) ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + if( ( msg->p = mbedtls_calloc( 1, ssl->out_msglen ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc %d bytes failed", ssl->out_msglen ) ); + mbedtls_free( msg ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + /* Copy current handshake message with headers */ + memcpy( msg->p, ssl->out_msg, ssl->out_msglen ); + msg->len = ssl->out_msglen; + msg->type = ssl->out_msgtype; + msg->next = NULL; + + /* Append to the current flight */ + if( ssl->handshake->flight == NULL ) + ssl->handshake->flight = msg; + else + { + mbedtls_ssl_flight_item *cur = ssl->handshake->flight; + while( cur->next != NULL ) + cur = cur->next; + cur->next = msg; + } + + return( 0 ); +} + +/* + * Free the current flight of handshake messages + */ +static void ssl_flight_free( mbedtls_ssl_flight_item *flight ) +{ + mbedtls_ssl_flight_item *cur = flight; + mbedtls_ssl_flight_item *next; + + while( cur != NULL ) + { + next = cur->next; + + mbedtls_free( cur->p ); + mbedtls_free( cur ); + + cur = next; + } +} + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +static void ssl_dtls_replay_reset( mbedtls_ssl_context *ssl ); +#endif + +/* + * Swap transform_out and out_ctr with the alternative ones + */ +static void ssl_swap_epochs( mbedtls_ssl_context *ssl ) +{ + mbedtls_ssl_transform *tmp_transform; + unsigned char tmp_out_ctr[8]; + + if( ssl->transform_out == ssl->handshake->alt_transform_out ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip swap epochs" ) ); + return; + } + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "swap epochs" ) ); + + /* Swap transforms */ + tmp_transform = ssl->transform_out; + ssl->transform_out = ssl->handshake->alt_transform_out; + ssl->handshake->alt_transform_out = tmp_transform; + + /* Swap epoch + sequence_number */ + memcpy( tmp_out_ctr, ssl->out_ctr, 8 ); + memcpy( ssl->out_ctr, ssl->handshake->alt_out_ctr, 8 ); + memcpy( ssl->handshake->alt_out_ctr, tmp_out_ctr, 8 ); + + /* Adjust to the newly activated transform */ + if( ssl->transform_out != NULL && + ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->out_msg = ssl->out_iv + ssl->transform_out->ivlen - + ssl->transform_out->fixed_ivlen; + } + else + ssl->out_msg = ssl->out_iv; + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_activate != NULL ) + { + if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_OUTBOUND ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif +} + +/* + * Retransmit the current flight of messages. + * + * Need to remember the current message in case flush_output returns + * WANT_WRITE, causing us to exit this function and come back later. + * This function must be called until state is no longer SENDING. + */ +int mbedtls_ssl_resend( mbedtls_ssl_context *ssl ) +{ + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> mbedtls_ssl_resend" ) ); + + if( ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialise resending" ) ); + + ssl->handshake->cur_msg = ssl->handshake->flight; + ssl_swap_epochs( ssl ); + + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_SENDING; + } + + while( ssl->handshake->cur_msg != NULL ) + { + int ret; + mbedtls_ssl_flight_item *cur = ssl->handshake->cur_msg; + + /* Swap epochs before sending Finished: we can't do it after + * sending ChangeCipherSpec, in case write returns WANT_READ. + * Must be done before copying, may change out_msg pointer */ + if( cur->type == MBEDTLS_SSL_MSG_HANDSHAKE && + cur->p[0] == MBEDTLS_SSL_HS_FINISHED ) + { + ssl_swap_epochs( ssl ); + } + + memcpy( ssl->out_msg, cur->p, cur->len ); + ssl->out_msglen = cur->len; + ssl->out_msgtype = cur->type; + + ssl->handshake->cur_msg = cur->next; + + MBEDTLS_SSL_DEBUG_BUF( 3, "resent handshake message header", ssl->out_msg, 12 ); + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + } + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; + else + { + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; + ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= mbedtls_ssl_resend" ) ); + + return( 0 ); +} + +/* + * To be called when the last message of an incoming flight is received. + */ +void mbedtls_ssl_recv_flight_completed( mbedtls_ssl_context *ssl ) +{ + /* We won't need to resend that one any more */ + ssl_flight_free( ssl->handshake->flight ); + ssl->handshake->flight = NULL; + ssl->handshake->cur_msg = NULL; + + /* The next incoming flight will start with this msg_seq */ + ssl->handshake->in_flight_start_seq = ssl->handshake->in_msg_seq; + + /* Cancel timer */ + ssl_set_timer( ssl, 0 ); + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) + { + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; + } + else + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_PREPARING; +} + +/* + * To be called when the last message of an outgoing flight is send. + */ +void mbedtls_ssl_send_flight_completed( mbedtls_ssl_context *ssl ) +{ + ssl_reset_retransmit_timeout( ssl ); + ssl_set_timer( ssl, ssl->handshake->retransmit_timeout ); + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) + { + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_FINISHED; + } + else + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +/* + * Record layer functions + */ + +/* + * Write current record. + * Uses ssl->out_msgtype, ssl->out_msglen and bytes at ssl->out_msg. + */ +int mbedtls_ssl_write_record( mbedtls_ssl_context *ssl ) +{ + int ret, done = 0, out_msg_type; + size_t len = ssl->out_msglen; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write record" ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + ; /* Skip special handshake treatment when resending */ + } + else +#endif + if( ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + out_msg_type = ssl->out_msg[0]; + + if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST && + ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + ssl->out_msg[1] = (unsigned char)( ( len - 4 ) >> 16 ); + ssl->out_msg[2] = (unsigned char)( ( len - 4 ) >> 8 ); + ssl->out_msg[3] = (unsigned char)( ( len - 4 ) ); + + /* + * DTLS has additional fields in the Handshake layer, + * between the length field and the actual payload: + * uint16 message_seq; + * uint24 fragment_offset; + * uint24 fragment_length; + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + /* Make room for the additional DTLS fields */ + memmove( ssl->out_msg + 12, ssl->out_msg + 4, len - 4 ); + ssl->out_msglen += 8; + len += 8; + + /* Write message_seq and update it, except for HelloRequest */ + if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) + { + ssl->out_msg[4] = ( ssl->handshake->out_msg_seq >> 8 ) & 0xFF; + ssl->out_msg[5] = ( ssl->handshake->out_msg_seq ) & 0xFF; + ++( ssl->handshake->out_msg_seq ); + } + else + { + ssl->out_msg[4] = 0; + ssl->out_msg[5] = 0; + } + + /* We don't fragment, so frag_offset = 0 and frag_len = len */ + memset( ssl->out_msg + 6, 0x00, 3 ); + memcpy( ssl->out_msg + 9, ssl->out_msg + 1, 3 ); + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + if( out_msg_type != MBEDTLS_SSL_HS_HELLO_REQUEST ) + ssl->handshake->update_checksum( ssl, ssl->out_msg, len ); + } + + /* Save handshake and CCS messages for resending */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL && + ssl->handshake->retransmit_state != MBEDTLS_SSL_RETRANS_SENDING && + ( ssl->out_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC || + ssl->out_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) ) + { + if( ( ret = ssl_flight_append( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_flight_append", ret ); + return( ret ); + } + } +#endif + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->transform_out != NULL && + ssl->session_out->compression == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + if( ( ret = ssl_compress_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_compress_buf", ret ); + return( ret ); + } + + len = ssl->out_msglen; + } +#endif /*MBEDTLS_ZLIB_SUPPORT */ + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_write != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_write()" ) ); + + ret = mbedtls_ssl_hw_record_write( ssl ); + if( ret != 0 && ret != MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_write", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + if( ret == 0 ) + done = 1; + } +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + if( !done ) + { + ssl->out_hdr[0] = (unsigned char) ssl->out_msgtype; + mbedtls_ssl_write_version( ssl->major_ver, ssl->minor_ver, + ssl->conf->transport, ssl->out_hdr + 1 ); + + ssl->out_len[0] = (unsigned char)( len >> 8 ); + ssl->out_len[1] = (unsigned char)( len ); + + if( ssl->transform_out != NULL ) + { + if( ( ret = ssl_encrypt_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_encrypt_buf", ret ); + return( ret ); + } + + len = ssl->out_msglen; + ssl->out_len[0] = (unsigned char)( len >> 8 ); + ssl->out_len[1] = (unsigned char)( len ); + } + + ssl->out_left = mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "output record: msgtype = %d, " + "version = [%d:%d], msglen = %d", + ssl->out_hdr[0], ssl->out_hdr[1], ssl->out_hdr[2], + ( ssl->out_len[0] << 8 ) | ssl->out_len[1] ) ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "output record sent to network", + ssl->out_hdr, mbedtls_ssl_hdr_len( ssl ) + ssl->out_msglen ); + } + + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write record" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +/* + * Mark bits in bitmask (used for DTLS HS reassembly) + */ +static void ssl_bitmask_set( unsigned char *mask, size_t offset, size_t len ) +{ + unsigned int start_bits, end_bits; + + start_bits = 8 - ( offset % 8 ); + if( start_bits != 8 ) + { + size_t first_byte_idx = offset / 8; + + /* Special case */ + if( len <= start_bits ) + { + for( ; len != 0; len-- ) + mask[first_byte_idx] |= 1 << ( start_bits - len ); + + /* Avoid potential issues with offset or len becoming invalid */ + return; + } + + offset += start_bits; /* Now offset % 8 == 0 */ + len -= start_bits; + + for( ; start_bits != 0; start_bits-- ) + mask[first_byte_idx] |= 1 << ( start_bits - 1 ); + } + + end_bits = len % 8; + if( end_bits != 0 ) + { + size_t last_byte_idx = ( offset + len ) / 8; + + len -= end_bits; /* Now len % 8 == 0 */ + + for( ; end_bits != 0; end_bits-- ) + mask[last_byte_idx] |= 1 << ( 8 - end_bits ); + } + + memset( mask + offset / 8, 0xFF, len / 8 ); +} + +/* + * Check that bitmask is full + */ +static int ssl_bitmask_check( unsigned char *mask, size_t len ) +{ + size_t i; + + for( i = 0; i < len / 8; i++ ) + if( mask[i] != 0xFF ) + return( -1 ); + + for( i = 0; i < len % 8; i++ ) + if( ( mask[len / 8] & ( 1 << ( 7 - i ) ) ) == 0 ) + return( -1 ); + + return( 0 ); +} + +/* + * Reassemble fragmented DTLS handshake messages. + * + * Use a temporary buffer for reassembly, divided in two parts: + * - the first holds the reassembled message (including handshake header), + * - the second holds a bitmask indicating which parts of the message + * (excluding headers) have been received so far. + */ +static int ssl_reassemble_dtls_handshake( mbedtls_ssl_context *ssl ) +{ + unsigned char *msg, *bitmask; + size_t frag_len, frag_off; + size_t msg_len = ssl->in_hslen - 12; /* Without headers */ + + if( ssl->handshake == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "not supported outside handshake (for now)" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + /* + * For first fragment, check size and allocate buffer + */ + if( ssl->handshake->hs_msg == NULL ) + { + size_t alloc_len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "initialize reassembly, total length = %d", + msg_len ) ); + + if( ssl->in_hslen > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake message too large" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + /* The bitmask needs one bit per byte of message excluding header */ + alloc_len = 12 + msg_len + msg_len / 8 + ( msg_len % 8 != 0 ); + + ssl->handshake->hs_msg = mbedtls_calloc( 1, alloc_len ); + if( ssl->handshake->hs_msg == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc failed (%d bytes)", alloc_len ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + /* Prepare final header: copy msg_type, length and message_seq, + * then add standardised fragment_offset and fragment_length */ + memcpy( ssl->handshake->hs_msg, ssl->in_msg, 6 ); + memset( ssl->handshake->hs_msg + 6, 0, 3 ); + memcpy( ssl->handshake->hs_msg + 9, + ssl->handshake->hs_msg + 1, 3 ); + } + else + { + /* Make sure msg_type and length are consistent */ + if( memcmp( ssl->handshake->hs_msg, ssl->in_msg, 4 ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "fragment header mismatch" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + } + + msg = ssl->handshake->hs_msg + 12; + bitmask = msg + msg_len; + + /* + * Check and copy current fragment + */ + frag_off = ( ssl->in_msg[6] << 16 ) | + ( ssl->in_msg[7] << 8 ) | + ssl->in_msg[8]; + frag_len = ( ssl->in_msg[9] << 16 ) | + ( ssl->in_msg[10] << 8 ) | + ssl->in_msg[11]; + + if( frag_off + frag_len > msg_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment offset/len: %d + %d > %d", + frag_off, frag_len, msg_len ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + if( frag_len + 12 > ssl->in_msglen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "invalid fragment length: %d + 12 > %d", + frag_len, ssl->in_msglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "adding fragment, offset = %d, length = %d", + frag_off, frag_len ) ); + + memcpy( msg + frag_off, ssl->in_msg + 12, frag_len ); + ssl_bitmask_set( bitmask, frag_off, frag_len ); + + /* + * Do we have the complete message by now? + * If yes, finalize it, else ask to read the next record. + */ + if( ssl_bitmask_check( bitmask, msg_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "message is not complete yet" ) ); + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "handshake message completed" ) ); + + if( frag_len + 12 < ssl->in_msglen ) + { + /* + * We'got more handshake messages in the same record. + * This case is not handled now because no know implementation does + * that and it's hard to test, so we prefer to fail cleanly for now. + */ + MBEDTLS_SSL_DEBUG_MSG( 1, ( "last fragment not alone in its record" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + if( ssl->in_left > ssl->next_record_offset ) + { + /* + * We've got more data in the buffer after the current record, + * that we don't want to overwrite. Move it before writing the + * reassembled message, and adjust in_left and next_record_offset. + */ + unsigned char *cur_remain = ssl->in_hdr + ssl->next_record_offset; + unsigned char *new_remain = ssl->in_msg + ssl->in_hslen; + size_t remain_len = ssl->in_left - ssl->next_record_offset; + + /* First compute and check new lengths */ + ssl->next_record_offset = new_remain - ssl->in_hdr; + ssl->in_left = ssl->next_record_offset + remain_len; + + if( ssl->in_left > MBEDTLS_SSL_BUFFER_LEN - + (size_t)( ssl->in_hdr - ssl->in_buf ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "reassembled message too large for buffer" ) ); + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + } + + memmove( new_remain, cur_remain, remain_len ); + } + + memcpy( ssl->in_msg, ssl->handshake->hs_msg, ssl->in_hslen ); + + mbedtls_free( ssl->handshake->hs_msg ); + ssl->handshake->hs_msg = NULL; + + MBEDTLS_SSL_DEBUG_BUF( 3, "reassembled handshake message", + ssl->in_msg, ssl->in_hslen ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + +int mbedtls_ssl_prepare_handshake_record( mbedtls_ssl_context *ssl ) +{ + if( ssl->in_msglen < mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake message too short: %d", + ssl->in_msglen ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + ssl->in_hslen = mbedtls_ssl_hs_hdr_len( ssl ) + ( + ( ssl->in_msg[1] << 16 ) | + ( ssl->in_msg[2] << 8 ) | + ssl->in_msg[3] ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "handshake message: msglen =" + " %d, type = %d, hslen = %d", + ssl->in_msglen, ssl->in_msg[0], ssl->in_hslen ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + int ret; + unsigned int recv_msg_seq = ( ssl->in_msg[4] << 8 ) | ssl->in_msg[5]; + + /* ssl->handshake is NULL when receiving ClientHello for renego */ + if( ssl->handshake != NULL && + recv_msg_seq != ssl->handshake->in_msg_seq ) + { + /* Retransmit only on last message from previous flight, to avoid + * too many retransmissions. + * Besides, No sane server ever retransmits HelloVerifyRequest */ + if( recv_msg_seq == ssl->handshake->in_flight_start_seq - 1 && + ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received message from last flight, " + "message_seq = %d, start_of_flight = %d", + recv_msg_seq, + ssl->handshake->in_flight_start_seq ) ); + + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret ); + return( ret ); + } + } + else + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "dropping out-of-sequence message: " + "message_seq = %d, expected = %d", + recv_msg_seq, + ssl->handshake->in_msg_seq ) ); + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + /* Wait until message completion to increment in_msg_seq */ + + /* Reassemble if current message is fragmented or reassembly is + * already in progress */ + if( ssl->in_msglen < ssl->in_hslen || + memcmp( ssl->in_msg + 6, "\0\0\0", 3 ) != 0 || + memcmp( ssl->in_msg + 9, ssl->in_msg + 1, 3 ) != 0 || + ( ssl->handshake != NULL && ssl->handshake->hs_msg != NULL ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "found fragmented DTLS handshake message" ) ); + + if( ( ret = ssl_reassemble_dtls_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_reassemble_dtls_handshake", ret ); + return( ret ); + } + } + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + /* With TLS we don't handle fragmentation (for now) */ + if( ssl->in_msglen < ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLS handshake fragmentation not supported" ) ); + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); + } + + return( 0 ); +} + +void mbedtls_ssl_update_handshake_status( mbedtls_ssl_context *ssl ) +{ + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER && + ssl->handshake != NULL ) + { + ssl->handshake->update_checksum( ssl, ssl->in_msg, ssl->in_hslen ); + } + + /* Handshake message is complete, increment counter */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL ) + { + ssl->handshake->in_msg_seq++; + } +#endif +} + +/* + * DTLS anti-replay: RFC 6347 4.1.2.6 + * + * in_window is a field of bits numbered from 0 (lsb) to 63 (msb). + * Bit n is set iff record number in_window_top - n has been seen. + * + * Usually, in_window_top is the last record number seen and the lsb of + * in_window is set. The only exception is the initial state (record number 0 + * not seen yet). + */ +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +static void ssl_dtls_replay_reset( mbedtls_ssl_context *ssl ) +{ + ssl->in_window_top = 0; + ssl->in_window = 0; +} + +static inline uint64_t ssl_load_six_bytes( unsigned char *buf ) +{ + return( ( (uint64_t) buf[0] << 40 ) | + ( (uint64_t) buf[1] << 32 ) | + ( (uint64_t) buf[2] << 24 ) | + ( (uint64_t) buf[3] << 16 ) | + ( (uint64_t) buf[4] << 8 ) | + ( (uint64_t) buf[5] ) ); +} + +/* + * Return 0 if sequence number is acceptable, -1 otherwise + */ +int mbedtls_ssl_dtls_replay_check( mbedtls_ssl_context *ssl ) +{ + uint64_t rec_seqnum = ssl_load_six_bytes( ssl->in_ctr + 2 ); + uint64_t bit; + + if( ssl->conf->anti_replay == MBEDTLS_SSL_ANTI_REPLAY_DISABLED ) + return( 0 ); + + if( rec_seqnum > ssl->in_window_top ) + return( 0 ); + + bit = ssl->in_window_top - rec_seqnum; + + if( bit >= 64 ) + return( -1 ); + + if( ( ssl->in_window & ( (uint64_t) 1 << bit ) ) != 0 ) + return( -1 ); + + return( 0 ); +} + +/* + * Update replay window on new validated record + */ +void mbedtls_ssl_dtls_replay_update( mbedtls_ssl_context *ssl ) +{ + uint64_t rec_seqnum = ssl_load_six_bytes( ssl->in_ctr + 2 ); + + if( ssl->conf->anti_replay == MBEDTLS_SSL_ANTI_REPLAY_DISABLED ) + return; + + if( rec_seqnum > ssl->in_window_top ) + { + /* Update window_top and the contents of the window */ + uint64_t shift = rec_seqnum - ssl->in_window_top; + + if( shift >= 64 ) + ssl->in_window = 1; + else + { + ssl->in_window <<= shift; + ssl->in_window |= 1; + } + + ssl->in_window_top = rec_seqnum; + } + else + { + /* Mark that number as seen in the current window */ + uint64_t bit = ssl->in_window_top - rec_seqnum; + + if( bit < 64 ) /* Always true, but be extra sure */ + ssl->in_window |= (uint64_t) 1 << bit; + } +} +#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ + +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) +/* Forward declaration */ +static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ); + +/* + * Without any SSL context, check if a datagram looks like a ClientHello with + * a valid cookie, and if it doesn't, generate a HelloVerifyRequest message. + * Both input and output include full DTLS headers. + * + * - if cookie is valid, return 0 + * - if ClientHello looks superficially valid but cookie is not, + * fill obuf and set olen, then + * return MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED + * - otherwise return a specific error code + */ +static int ssl_check_dtls_clihlo_cookie( + mbedtls_ssl_cookie_write_t *f_cookie_write, + mbedtls_ssl_cookie_check_t *f_cookie_check, + void *p_cookie, + const unsigned char *cli_id, size_t cli_id_len, + const unsigned char *in, size_t in_len, + unsigned char *obuf, size_t buf_len, size_t *olen ) +{ + size_t sid_len, cookie_len; + unsigned char *p; + + if( f_cookie_write == NULL || f_cookie_check == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* + * Structure of ClientHello with record and handshake headers, + * and expected values. We don't need to check a lot, more checks will be + * done when actually parsing the ClientHello - skipping those checks + * avoids code duplication and does not make cookie forging any easier. + * + * 0-0 ContentType type; copied, must be handshake + * 1-2 ProtocolVersion version; copied + * 3-4 uint16 epoch; copied, must be 0 + * 5-10 uint48 sequence_number; copied + * 11-12 uint16 length; (ignored) + * + * 13-13 HandshakeType msg_type; (ignored) + * 14-16 uint24 length; (ignored) + * 17-18 uint16 message_seq; copied + * 19-21 uint24 fragment_offset; copied, must be 0 + * 22-24 uint24 fragment_length; (ignored) + * + * 25-26 ProtocolVersion client_version; (ignored) + * 27-58 Random random; (ignored) + * 59-xx SessionID session_id; 1 byte len + sid_len content + * 60+ opaque cookie<0..2^8-1>; 1 byte len + content + * ... + * + * Minimum length is 61 bytes. + */ + if( in_len < 61 || + in[0] != MBEDTLS_SSL_MSG_HANDSHAKE || + in[3] != 0 || in[4] != 0 || + in[19] != 0 || in[20] != 0 || in[21] != 0 ) + { + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + } + + sid_len = in[59]; + if( sid_len > in_len - 61 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + cookie_len = in[60 + sid_len]; + if( cookie_len > in_len - 60 ) + return( MBEDTLS_ERR_SSL_BAD_HS_CLIENT_HELLO ); + + if( f_cookie_check( p_cookie, in + sid_len + 61, cookie_len, + cli_id, cli_id_len ) == 0 ) + { + /* Valid cookie */ + return( 0 ); + } + + /* + * If we get here, we've got an invalid cookie, let's prepare HVR. + * + * 0-0 ContentType type; copied + * 1-2 ProtocolVersion version; copied + * 3-4 uint16 epoch; copied + * 5-10 uint48 sequence_number; copied + * 11-12 uint16 length; olen - 13 + * + * 13-13 HandshakeType msg_type; hello_verify_request + * 14-16 uint24 length; olen - 25 + * 17-18 uint16 message_seq; copied + * 19-21 uint24 fragment_offset; copied + * 22-24 uint24 fragment_length; olen - 25 + * + * 25-26 ProtocolVersion server_version; 0xfe 0xff + * 27-27 opaque cookie<0..2^8-1>; cookie_len = olen - 27, cookie + * + * Minimum length is 28. + */ + if( buf_len < 28 ) + return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL ); + + /* Copy most fields and adapt others */ + memcpy( obuf, in, 25 ); + obuf[13] = MBEDTLS_SSL_HS_HELLO_VERIFY_REQUEST; + obuf[25] = 0xfe; + obuf[26] = 0xff; + + /* Generate and write actual cookie */ + p = obuf + 28; + if( f_cookie_write( p_cookie, + &p, obuf + buf_len, cli_id, cli_id_len ) != 0 ) + { + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + *olen = p - obuf; + + /* Go back and fill length fields */ + obuf[27] = (unsigned char)( *olen - 28 ); + + obuf[14] = obuf[22] = (unsigned char)( ( *olen - 25 ) >> 16 ); + obuf[15] = obuf[23] = (unsigned char)( ( *olen - 25 ) >> 8 ); + obuf[16] = obuf[24] = (unsigned char)( ( *olen - 25 ) ); + + obuf[11] = (unsigned char)( ( *olen - 13 ) >> 8 ); + obuf[12] = (unsigned char)( ( *olen - 13 ) ); + + return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ); +} + +/* + * Handle possible client reconnect with the same UDP quadruplet + * (RFC 6347 Section 4.2.8). + * + * Called by ssl_parse_record_header() in case we receive an epoch 0 record + * that looks like a ClientHello. + * + * - if the input looks like a ClientHello without cookies, + * send back HelloVerifyRequest, then + * return MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED + * - if the input looks like a ClientHello with a valid cookie, + * reset the session of the current context, and + * return MBEDTLS_ERR_SSL_CLIENT_RECONNECT + * - if anything goes wrong, return a specific error code + * + * mbedtls_ssl_read_record() will ignore the record if anything else than + * MBEDTLS_ERR_SSL_CLIENT_RECONNECT or 0 is returned, although this function + * cannot not return 0. + */ +static int ssl_handle_possible_reconnect( mbedtls_ssl_context *ssl ) +{ + int ret; + size_t len; + + ret = ssl_check_dtls_clihlo_cookie( + ssl->conf->f_cookie_write, + ssl->conf->f_cookie_check, + ssl->conf->p_cookie, + ssl->cli_id, ssl->cli_id_len, + ssl->in_buf, ssl->in_left, + ssl->out_buf, MBEDTLS_SSL_MAX_CONTENT_LEN, &len ); + + MBEDTLS_SSL_DEBUG_RET( 2, "ssl_check_dtls_clihlo_cookie", ret ); + + if( ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ) + { + /* Don't check write errors as we can't do anything here. + * If the error is permanent we'll catch it later, + * if it's not, then hopefully it'll work next time. */ + (void) ssl->f_send( ssl->p_bio, ssl->out_buf, len ); + + return( MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED ); + } + + if( ret == 0 ) + { + /* Got a valid cookie, partially reset context */ + if( ( ret = ssl_session_reset_int( ssl, 1 ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "reset", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_CLIENT_RECONNECT ); + } + + return( ret ); +} +#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ + +/* + * ContentType type; + * ProtocolVersion version; + * uint16 epoch; // DTLS only + * uint48 sequence_number; // DTLS only + * uint16 length; + * + * Return 0 if header looks sane (and, for DTLS, the record is expected) + * MBEDTLS_ERR_SSL_INVALID_RECORD if the header looks bad, + * MBEDTLS_ERR_SSL_UNEXPECTED_RECORD (DTLS only) if sane but unexpected. + * + * With DTLS, mbedtls_ssl_read_record() will: + * 1. proceed with the record if this function returns 0 + * 2. drop only the current record if this function returns UNEXPECTED_RECORD + * 3. return CLIENT_RECONNECT if this function return that value + * 4. drop the whole datagram if this function returns anything else. + * Point 2 is needed when the peer is resending, and we have already received + * the first record from a datagram but are still waiting for the others. + */ +static int ssl_parse_record_header( mbedtls_ssl_context *ssl ) +{ + int ret; + int major_ver, minor_ver; + + MBEDTLS_SSL_DEBUG_BUF( 4, "input record header", ssl->in_hdr, mbedtls_ssl_hdr_len( ssl ) ); + + ssl->in_msgtype = ssl->in_hdr[0]; + ssl->in_msglen = ( ssl->in_len[0] << 8 ) | ssl->in_len[1]; + mbedtls_ssl_read_version( &major_ver, &minor_ver, ssl->conf->transport, ssl->in_hdr + 1 ); + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "input record: msgtype = %d, " + "version = [%d:%d], msglen = %d", + ssl->in_msgtype, + major_ver, minor_ver, ssl->in_msglen ) ); + + /* Check record type */ + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msgtype != MBEDTLS_SSL_MSG_ALERT && + ssl->in_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC && + ssl->in_msgtype != MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "unknown record type" ) ); + + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_UNEXPECTED_MESSAGE ) ) != 0 ) + { + return( ret ); + } + + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + /* Check version */ + if( major_ver != ssl->major_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "major version mismatch" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + if( minor_ver > ssl->conf->max_minor_ver ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "minor version mismatch" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + /* Check length against the size of our buffer */ + if( ssl->in_msglen > MBEDTLS_SSL_BUFFER_LEN + - (size_t)( ssl->in_msg - ssl->in_buf ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + + /* Check length against bounds of the current transform and version */ + if( ssl->transform_in == NULL ) + { + if( ssl->in_msglen < 1 || + ssl->in_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + } + else + { + if( ssl->in_msglen < ssl->transform_in->minlen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 && + ssl->in_msglen > ssl->transform_in->minlen + MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + /* + * TLS encrypted messages can have up to 256 bytes of padding + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 && + ssl->in_msglen > ssl->transform_in->minlen + + MBEDTLS_SSL_MAX_CONTENT_LEN + 256 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } +#endif + } + + /* + * DTLS-related tests done last, because most of them may result in + * silently dropping the record (but not the whole datagram), and we only + * want to consider that after ensuring that the "basic" fields (type, + * version, length) are sane. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + unsigned int rec_epoch = ( ssl->in_ctr[0] << 8 ) | ssl->in_ctr[1]; + + /* Drop unexpected ChangeCipherSpec messages */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC && + ssl->state != MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC && + ssl->state != MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ChangeCipherSpec" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } + + /* Drop unexpected ApplicationData records, + * except at the beginning of renegotiations */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA && + ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER +#if defined(MBEDTLS_SSL_RENEGOTIATION) + && ! ( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS && + ssl->state == MBEDTLS_SSL_SERVER_HELLO ) +#endif + ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "dropping unexpected ApplicationData" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } + + /* Check epoch (and sequence number) with DTLS */ + if( rec_epoch != ssl->in_epoch ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "record from another epoch: " + "expected %d, received %d", + ssl->in_epoch, rec_epoch ) ); + +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) && defined(MBEDTLS_SSL_SRV_C) + /* + * Check for an epoch 0 ClientHello. We can't use in_msg here to + * access the first byte of record content (handshake type), as we + * have an active transform (possibly iv_len != 0), so use the + * fact that the record header len is 13 instead. + */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER && + rec_epoch == 0 && + ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_left > 13 && + ssl->in_buf[13] == MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "possible client reconnect " + "from the same port" ) ); + return( ssl_handle_possible_reconnect( ssl ) ); + } + else +#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE && MBEDTLS_SSL_SRV_C */ + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + /* Replay detection only works for the current epoch */ + if( rec_epoch == ssl->in_epoch && + mbedtls_ssl_dtls_replay_check( ssl ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "replayed record" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ); + } +#endif + } +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + + return( 0 ); +} + +/* + * If applicable, decrypt (and decompress) record content + */ +static int ssl_prepare_record_content( mbedtls_ssl_context *ssl ) +{ + int ret, done = 0; + + MBEDTLS_SSL_DEBUG_BUF( 4, "input record from network", + ssl->in_hdr, mbedtls_ssl_hdr_len( ssl ) + ssl->in_msglen ); + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_read != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_read()" ) ); + + ret = mbedtls_ssl_hw_record_read( ssl ); + if( ret != 0 && ret != MBEDTLS_ERR_SSL_HW_ACCEL_FALLTHROUGH ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_read", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + + if( ret == 0 ) + done = 1; + } +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ + if( !done && ssl->transform_in != NULL ) + { + if( ( ret = ssl_decrypt_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_decrypt_buf", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_BUF( 4, "input payload after decrypt", + ssl->in_msg, ssl->in_msglen ); + + if( ssl->in_msglen > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad message length" ) ); + return( MBEDTLS_ERR_SSL_INVALID_RECORD ); + } + } + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->transform_in != NULL && + ssl->session_in->compression == MBEDTLS_SSL_COMPRESS_DEFLATE ) + { + if( ( ret = ssl_decompress_buf( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_decompress_buf", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_ZLIB_SUPPORT */ + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + mbedtls_ssl_dtls_replay_update( ssl ); + } +#endif + + return( 0 ); +} + +static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ); + +/* + * Read a record. + * + * Silently ignore non-fatal alert (and for DTLS, invalid records as well, + * RFC 6347 4.1.2.7) and continue reading until a valid record is found. + * + */ +int mbedtls_ssl_read_record( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read record" ) ); + + do { + + if( ( ret = mbedtls_ssl_read_record_layer( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_read_record_layer" ), ret ); + return( ret ); + } + + ret = mbedtls_ssl_handle_message_type( ssl ); + + } while( MBEDTLS_ERR_SSL_NON_FATAL == ret ); + + if( 0 != ret ) + { + MBEDTLS_SSL_DEBUG_RET( 1, ( "mbedtls_ssl_handle_message_type" ), ret ); + return( ret ); + } + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + mbedtls_ssl_update_handshake_status( ssl ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= read record" ) ); + + return( 0 ); +} + +int mbedtls_ssl_read_record_layer( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ssl->in_hslen != 0 && ssl->in_hslen < ssl->in_msglen ) + { + /* + * Get next Handshake message in the current record + */ + ssl->in_msglen -= ssl->in_hslen; + + memmove( ssl->in_msg, ssl->in_msg + ssl->in_hslen, + ssl->in_msglen ); + + MBEDTLS_SSL_DEBUG_BUF( 4, "remaining content in record", + ssl->in_msg, ssl->in_msglen ); + + return( 0 ); + } + + ssl->in_hslen = 0; + + /* + * Read the record header and parse it + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) +read_record_header: +#endif + + if( ( ret = mbedtls_ssl_fetch_input( ssl, mbedtls_ssl_hdr_len( ssl ) ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + if( ( ret = ssl_parse_record_header( ssl ) ) != 0 ) + { +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ret != MBEDTLS_ERR_SSL_CLIENT_RECONNECT ) + { + if( ret == MBEDTLS_ERR_SSL_UNEXPECTED_RECORD ) + { + /* Skip unexpected record (but not whole datagram) */ + ssl->next_record_offset = ssl->in_msglen + + mbedtls_ssl_hdr_len( ssl ); + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding unexpected record " + "(header)" ) ); + } + else + { + /* Skip invalid record and the rest of the datagram */ + ssl->next_record_offset = 0; + ssl->in_left = 0; + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding invalid record " + "(header)" ) ); + } + + /* Get next record */ + goto read_record_header; + } +#endif + return( ret ); + } + + /* + * Read and optionally decrypt the message contents + */ + if( ( ret = mbedtls_ssl_fetch_input( ssl, + mbedtls_ssl_hdr_len( ssl ) + ssl->in_msglen ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_fetch_input", ret ); + return( ret ); + } + + /* Done reading this record, get ready for the next one */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + ssl->next_record_offset = ssl->in_msglen + mbedtls_ssl_hdr_len( ssl ); + else +#endif + ssl->in_left = 0; + + if( ( ret = ssl_prepare_record_content( ssl ) ) != 0 ) + { +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + /* Silently discard invalid records */ + if( ret == MBEDTLS_ERR_SSL_INVALID_RECORD || + ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + { + /* Except when waiting for Finished as a bad mac here + * probably means something went wrong in the handshake + * (eg wrong psk used, mitm downgrade attempt, etc.) */ + if( ssl->state == MBEDTLS_SSL_CLIENT_FINISHED || + ssl->state == MBEDTLS_SSL_SERVER_FINISHED ) + { +#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + { + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC ); + } +#endif + return( ret ); + } + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + if( ssl->conf->badmac_limit != 0 && + ++ssl->badmac_seen >= ssl->conf->badmac_limit ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "too many records with bad MAC" ) ); + return( MBEDTLS_ERR_SSL_INVALID_MAC ); + } +#endif + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "discarding invalid record (mac)" ) ); + goto read_record_header; + } + + return( ret ); + } + else +#endif + { + /* Error out (and send alert) on invalid records */ +#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) + if( ret == MBEDTLS_ERR_SSL_INVALID_MAC ) + { + mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_BAD_RECORD_MAC ); + } +#endif + return( ret ); + } + } + + /* + * When we sent the last flight of the handshake, we MUST respond to a + * retransmit of the peer's previous flight with a retransmit. (In + * practice, only the Finished message will make it, other messages + * including CCS use the old transform so they're dropped as invalid.) + * + * If the record we received is not a handshake message, however, it + * means the peer received our last flight so we can clean up + * handshake info. + * + * This check needs to be done before prepare_handshake() due to an edge + * case: if the client immediately requests renegotiation, this + * finishes the current handshake first, avoiding the new ClientHello + * being mistaken for an ancient message in the current handshake. + */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake != NULL && + ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_FINISHED ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "received retransmit of last flight" ) ); + + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_resend", ret ); + return( ret ); + } + + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + else + { + ssl_handshake_wrapup_free_hs_transform( ssl ); + } + } +#endif + + return( 0 ); +} + +int mbedtls_ssl_handle_message_type( mbedtls_ssl_context *ssl ) +{ + int ret; + + /* + * Handle particular types of records + */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + if( ( ret = mbedtls_ssl_prepare_handshake_record( ssl ) ) != 0 ) + { + return( ret ); + } + } + + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "got an alert message, type: [%d:%d]", + ssl->in_msg[0], ssl->in_msg[1] ) ); + + /* + * Ignore non-fatal alerts, except close_notify and no_renegotiation + */ + if( ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_FATAL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "is a fatal alert message (msg %d)", + ssl->in_msg[1] ) ); + return( MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE ); + } + + if( ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a close notify message" ) ); + return( MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ); + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION_ENABLED) + if( ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a SSLv3 no_cert" ) ); + /* Will be handled when trying to parse ServerHello */ + return( 0 ); + } +#endif + +#if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_SRV_C) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 && + ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_CERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "is a SSLv3 no_cert" ) ); + /* Will be handled in mbedtls_ssl_parse_certificate() */ + return( 0 ); + } +#endif /* MBEDTLS_SSL_PROTO_SSL3 && MBEDTLS_SSL_SRV_C */ + + /* Silently ignore: fetch new message */ + return MBEDTLS_ERR_SSL_NON_FATAL; + } + + return( 0 ); +} + +int mbedtls_ssl_send_fatal_handshake_failure( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} + +int mbedtls_ssl_send_alert_message( mbedtls_ssl_context *ssl, + unsigned char level, + unsigned char message ) +{ + int ret; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> send alert message" ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_ALERT; + ssl->out_msglen = 2; + ssl->out_msg[0] = level; + ssl->out_msg[1] = message; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= send alert message" ) ); + + return( 0 ); +} + +/* + * Handshake functions + */ +#if !defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) && \ + !defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) +int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +{ + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); +} +#else +int mbedtls_ssl_write_certificate( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t i, n; + const mbedtls_x509_crt *crt; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + if( ssl->client_auth == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip write certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + /* + * If using SSLv3 and got no cert, send an Alert message + * (otherwise an empty Certificate message will be sent). + */ + if( mbedtls_ssl_own_cert( ssl ) == NULL && + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + ssl->out_msglen = 2; + ssl->out_msgtype = MBEDTLS_SSL_MSG_ALERT; + ssl->out_msg[0] = MBEDTLS_SSL_ALERT_LEVEL_WARNING; + ssl->out_msg[1] = MBEDTLS_SSL_ALERT_MSG_NO_CERT; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "got no certificate to send" ) ); + goto write_msg; + } +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + } +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( mbedtls_ssl_own_cert( ssl ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no certificate to send" ) ); + return( MBEDTLS_ERR_SSL_CERTIFICATE_REQUIRED ); + } + } +#endif + + MBEDTLS_SSL_DEBUG_CRT( 3, "own certificate", mbedtls_ssl_own_cert( ssl ) ); + + /* + * 0 . 0 handshake type + * 1 . 3 handshake length + * 4 . 6 length of all certs + * 7 . 9 length of cert. 1 + * 10 . n-1 peer certificate + * n . n+2 length of cert. 2 + * n+3 . ... upper level cert, etc. + */ + i = 7; + crt = mbedtls_ssl_own_cert( ssl ); + + while( crt != NULL ) + { + n = crt->raw.len; + if( n > MBEDTLS_SSL_MAX_CONTENT_LEN - 3 - i ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "certificate too large, %d > %d", + i + 3 + n, MBEDTLS_SSL_MAX_CONTENT_LEN ) ); + return( MBEDTLS_ERR_SSL_CERTIFICATE_TOO_LARGE ); + } + + ssl->out_msg[i ] = (unsigned char)( n >> 16 ); + ssl->out_msg[i + 1] = (unsigned char)( n >> 8 ); + ssl->out_msg[i + 2] = (unsigned char)( n ); + + i += 3; memcpy( ssl->out_msg + i, crt->raw.p, n ); + i += n; crt = crt->next; + } + + ssl->out_msg[4] = (unsigned char)( ( i - 7 ) >> 16 ); + ssl->out_msg[5] = (unsigned char)( ( i - 7 ) >> 8 ); + ssl->out_msg[6] = (unsigned char)( ( i - 7 ) ); + + ssl->out_msglen = i; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_CERTIFICATE; + +#if defined(MBEDTLS_SSL_PROTO_SSL3) && defined(MBEDTLS_SSL_CLI_C) +write_msg: +#endif + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write certificate" ) ); + + return( ret ); +} + +int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + size_t i, n; + const mbedtls_ssl_ciphersuite_t *ciphersuite_info = ssl->transform_negotiate->ciphersuite_info; + int authmode = ssl->conf->authmode; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse certificate" ) ); + + if( ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_DHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECDHE_PSK || + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_ECJPAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ciphersuite_info->key_exchange == MBEDTLS_KEY_EXCHANGE_RSA_PSK ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_authmode != MBEDTLS_SSL_VERIFY_UNSET ) + authmode = ssl->handshake->sni_authmode; +#endif + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + authmode == MBEDTLS_SSL_VERIFY_NONE ) + { + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_SKIP_VERIFY; + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= skip parse certificate" ) ); + ssl->state++; + return( 0 ); + } +#endif + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + ssl->state++; + +#if defined(MBEDTLS_SSL_SRV_C) +#if defined(MBEDTLS_SSL_PROTO_SSL3) + /* + * Check if the client sent an empty certificate + */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( ssl->in_msglen == 2 && + ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT && + ssl->in_msg[0] == MBEDTLS_SSL_ALERT_LEVEL_WARNING && + ssl->in_msg[1] == MBEDTLS_SSL_ALERT_MSG_NO_CERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "SSLv3 client has no certificate" ) ); + + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + return( 0 ); + else + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } + } +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_0 ) + { + if( ssl->in_hslen == 3 + mbedtls_ssl_hs_hdr_len( ssl ) && + ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE && + ssl->in_msg[0] == MBEDTLS_SSL_HS_CERTIFICATE && + memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), "\0\0\0", 3 ) == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "TLSv1 client has no certificate" ) ); + + ssl->session_negotiate->verify_result = MBEDTLS_X509_BADCERT_MISSING; + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + return( 0 ); + else + return( MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE ); + } + } +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || \ + MBEDTLS_SSL_PROTO_TLS1_2 */ +#endif /* MBEDTLS_SSL_SRV_C */ + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_CERTIFICATE || + ssl->in_hslen < mbedtls_ssl_hs_hdr_len( ssl ) + 3 + 3 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + i = mbedtls_ssl_hs_hdr_len( ssl ); + + /* + * Same message structure as in mbedtls_ssl_write_certificate() + */ + n = ( ssl->in_msg[i+1] << 8 ) | ssl->in_msg[i+2]; + + if( ssl->in_msg[i] != 0 || + ssl->in_hslen != n + 3 + mbedtls_ssl_hs_hdr_len( ssl ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + /* In case we tried to reuse a session but it failed */ + if( ssl->session_negotiate->peer_cert != NULL ) + { + mbedtls_x509_crt_free( ssl->session_negotiate->peer_cert ); + mbedtls_free( ssl->session_negotiate->peer_cert ); + } + + if( ( ssl->session_negotiate->peer_cert = mbedtls_calloc( 1, + sizeof( mbedtls_x509_crt ) ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", + sizeof( mbedtls_x509_crt ) ) ); + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert ); + + i += 3; + + while( i < ssl->in_hslen ) + { + if( ssl->in_msg[i] != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + n = ( (unsigned int) ssl->in_msg[i + 1] << 8 ) + | (unsigned int) ssl->in_msg[i + 2]; + i += 3; + + if( n < 128 || i + n > ssl->in_hslen ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + ret = mbedtls_x509_crt_parse_der( ssl->session_negotiate->peer_cert, + ssl->in_msg + i, n ); + if( 0 != ret && ( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + MBEDTLS_ERR_OID_NOT_FOUND ) != ret ) + { + MBEDTLS_SSL_DEBUG_RET( 1, " mbedtls_x509_crt_parse_der", ret ); + return( ret ); + } + + i += n; + } + + MBEDTLS_SSL_DEBUG_CRT( 3, "peer certificate", ssl->session_negotiate->peer_cert ); + + /* + * On client, make sure the server cert doesn't change during renego to + * avoid "triple handshake" attack: https://secure-resumption.com/ + */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) && defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + if( ssl->session->peer_cert == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "new server cert during renegotiation" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + + if( ssl->session->peer_cert->raw.len != + ssl->session_negotiate->peer_cert->raw.len || + memcmp( ssl->session->peer_cert->raw.p, + ssl->session_negotiate->peer_cert->raw.p, + ssl->session->peer_cert->raw.len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "server cert changed during renegotiation" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE ); + } + } +#endif /* MBEDTLS_SSL_RENEGOTIATION && MBEDTLS_SSL_CLI_C */ + + if( authmode != MBEDTLS_SSL_VERIFY_NONE ) + { + mbedtls_x509_crt *ca_chain; + mbedtls_x509_crl *ca_crl; + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + if( ssl->handshake->sni_ca_chain != NULL ) + { + ca_chain = ssl->handshake->sni_ca_chain; + ca_crl = ssl->handshake->sni_ca_crl; + } + else +#endif + { + ca_chain = ssl->conf->ca_chain; + ca_crl = ssl->conf->ca_crl; + } + + if( ca_chain == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "got no CA chain" ) ); + return( MBEDTLS_ERR_SSL_CA_CHAIN_REQUIRED ); + } + + /* + * Main check: verify certificate + */ + ret = mbedtls_x509_crt_verify_with_profile( + ssl->session_negotiate->peer_cert, + ca_chain, ca_crl, + ssl->conf->cert_profile, + ssl->hostname, + &ssl->session_negotiate->verify_result, + ssl->conf->f_vrfy, ssl->conf->p_vrfy ); + + if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "x509_verify_cert", ret ); + } + + /* + * Secondary checks: always done, but change 'ret' only if it was 0 + */ + +#if defined(MBEDTLS_ECP_C) + { + const mbedtls_pk_context *pk = &ssl->session_negotiate->peer_cert->pk; + + /* If certificate uses an EC key, make sure the curve is OK */ + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECKEY ) && + mbedtls_ssl_check_curve( ssl, mbedtls_pk_ec( *pk )->grp.id ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (EC key curve)" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } + } +#endif /* MBEDTLS_ECP_C */ + + if( mbedtls_ssl_check_cert_usage( ssl->session_negotiate->peer_cert, + ciphersuite_info, + ! ssl->conf->endpoint, + &ssl->session_negotiate->verify_result ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad certificate (usage extensions)" ) ); + if( ret == 0 ) + ret = MBEDTLS_ERR_SSL_BAD_HS_CERTIFICATE; + } + + if( authmode == MBEDTLS_SSL_VERIFY_OPTIONAL ) + ret = 0; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse certificate" ) ); + + return( ret ); +} +#endif /* !MBEDTLS_KEY_EXCHANGE_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED + !MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED + !MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ + +int mbedtls_ssl_write_change_cipher_spec( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write change cipher spec" ) ); + + ssl->out_msgtype = MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC; + ssl->out_msglen = 1; + ssl->out_msg[0] = 1; + + ssl->state++; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write change cipher spec" ) ); + + return( 0 ); +} + +int mbedtls_ssl_parse_change_cipher_spec( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse change cipher spec" ) ); + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_CHANGE_CIPHER_SPEC ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->in_msglen != 1 || ssl->in_msg[0] != 1 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad change cipher spec message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_CHANGE_CIPHER_SPEC ); + } + + /* + * Switch to our negotiated transform and session parameters for inbound + * data. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "switching to new transform spec for inbound data" ) ); + ssl->transform_in = ssl->transform_negotiate; + ssl->session_in = ssl->session_negotiate; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + ssl_dtls_replay_reset( ssl ); +#endif + + /* Increment epoch */ + if( ++ssl->in_epoch == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS epoch would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + memset( ssl->in_ctr, 0, 8 ); + + /* + * Set the in_msg pointer to the correct location based on IV length + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->in_msg = ssl->in_iv + ssl->transform_negotiate->ivlen - + ssl->transform_negotiate->fixed_ivlen; + } + else + ssl->in_msg = ssl->in_iv; + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_activate != NULL ) + { + if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_INBOUND ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif + + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse change cipher spec" ) ); + + return( 0 ); +} + +void mbedtls_ssl_optimize_checksum( mbedtls_ssl_context *ssl, + const mbedtls_ssl_ciphersuite_t *ciphersuite_info ) +{ + ((void) ciphersuite_info); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + if( ssl->minor_ver < MBEDTLS_SSL_MINOR_VERSION_3 ) + ssl->handshake->update_checksum = ssl_update_checksum_md5sha1; + else +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA512_C) + if( ciphersuite_info->mac == MBEDTLS_MD_SHA384 ) + ssl->handshake->update_checksum = ssl_update_checksum_sha384; + else +#endif +#if defined(MBEDTLS_SHA256_C) + if( ciphersuite_info->mac != MBEDTLS_MD_SHA384 ) + ssl->handshake->update_checksum = ssl_update_checksum_sha256; + else +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return; + } +} + +void mbedtls_ssl_reset_checksum( mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_starts( &ssl->handshake->fin_md5 ); + mbedtls_sha1_starts( &ssl->handshake->fin_sha1 ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_starts( &ssl->handshake->fin_sha256, 0 ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_starts( &ssl->handshake->fin_sha512, 1 ); +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +} + +static void ssl_update_checksum_start( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_update( &ssl->handshake->fin_md5 , buf, len ); + mbedtls_sha1_update( &ssl->handshake->fin_sha1, buf, len ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_update( &ssl->handshake->fin_sha256, buf, len ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_update( &ssl->handshake->fin_sha512, buf, len ); +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +} + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_update_checksum_md5sha1( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + mbedtls_md5_update( &ssl->handshake->fin_md5 , buf, len ); + mbedtls_sha1_update( &ssl->handshake->fin_sha1, buf, len ); +} +#endif + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +static void ssl_update_checksum_sha256( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + mbedtls_sha256_update( &ssl->handshake->fin_sha256, buf, len ); +} +#endif + +#if defined(MBEDTLS_SHA512_C) +static void ssl_update_checksum_sha384( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + mbedtls_sha512_update( &ssl->handshake->fin_sha512, buf, len ); +} +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +static void ssl_calc_finished_ssl( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + const char *sender; + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + + unsigned char padbuf[48]; + unsigned char md5sum[16]; + unsigned char sha1sum[20]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished ssl" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + /* + * SSLv3: + * hash = + * MD5( master + pad2 + + * MD5( handshake + sender + master + pad1 ) ) + * + SHA1( master + pad2 + + * SHA1( handshake + sender + master + pad1 ) ) + */ + +#if !defined(MBEDTLS_MD5_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *) + md5.state, sizeof( md5.state ) ); +#endif + +#if !defined(MBEDTLS_SHA1_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *) + sha1.state, sizeof( sha1.state ) ); +#endif + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) ? "CLNT" + : "SRVR"; + + memset( padbuf, 0x36, 48 ); + + mbedtls_md5_update( &md5, (const unsigned char *) sender, 4 ); + mbedtls_md5_update( &md5, session->master, 48 ); + mbedtls_md5_update( &md5, padbuf, 48 ); + mbedtls_md5_finish( &md5, md5sum ); + + mbedtls_sha1_update( &sha1, (const unsigned char *) sender, 4 ); + mbedtls_sha1_update( &sha1, session->master, 48 ); + mbedtls_sha1_update( &sha1, padbuf, 40 ); + mbedtls_sha1_finish( &sha1, sha1sum ); + + memset( padbuf, 0x5C, 48 ); + + mbedtls_md5_starts( &md5 ); + mbedtls_md5_update( &md5, session->master, 48 ); + mbedtls_md5_update( &md5, padbuf, 48 ); + mbedtls_md5_update( &md5, md5sum, 16 ); + mbedtls_md5_finish( &md5, buf ); + + mbedtls_sha1_starts( &sha1 ); + mbedtls_sha1_update( &sha1, session->master, 48 ); + mbedtls_sha1_update( &sha1, padbuf , 40 ); + mbedtls_sha1_update( &sha1, sha1sum, 20 ); + mbedtls_sha1_finish( &sha1, buf + 16 ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, 36 ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + mbedtls_zeroize( md5sum, sizeof( md5sum ) ); + mbedtls_zeroize( sha1sum, sizeof( sha1sum ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +static void ssl_calc_finished_tls( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + mbedtls_md5_context md5; + mbedtls_sha1_context sha1; + unsigned char padbuf[36]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls" ) ); + + mbedtls_md5_init( &md5 ); + mbedtls_sha1_init( &sha1 ); + + mbedtls_md5_clone( &md5, &ssl->handshake->fin_md5 ); + mbedtls_sha1_clone( &sha1, &ssl->handshake->fin_sha1 ); + + /* + * TLSv1: + * hash = PRF( master, finished_label, + * MD5( handshake ) + SHA1( handshake ) )[0..11] + */ + +#if !defined(MBEDTLS_MD5_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *) + md5.state, sizeof( md5.state ) ); +#endif + +#if !defined(MBEDTLS_SHA1_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *) + sha1.state, sizeof( sha1.state ) ); +#endif + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + mbedtls_md5_finish( &md5, padbuf ); + mbedtls_sha1_finish( &sha1, padbuf + 16 ); + + ssl->handshake->tls_prf( session->master, 48, sender, + padbuf, 36, buf, len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + mbedtls_md5_free( &md5 ); + mbedtls_sha1_free( &sha1 ); + + mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ + +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) +static void ssl_calc_finished_tls_sha256( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + mbedtls_sha256_context sha256; + unsigned char padbuf[32]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + mbedtls_sha256_init( &sha256 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls sha256" ) ); + + mbedtls_sha256_clone( &sha256, &ssl->handshake->fin_sha256 ); + + /* + * TLSv1.2: + * hash = PRF( master, finished_label, + * Hash( handshake ) )[0.11] + */ + +#if !defined(MBEDTLS_SHA256_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha2 state", (unsigned char *) + sha256.state, sizeof( sha256.state ) ); +#endif + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + mbedtls_sha256_finish( &sha256, padbuf ); + + ssl->handshake->tls_prf( session->master, 48, sender, + padbuf, 32, buf, len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + mbedtls_sha256_free( &sha256 ); + + mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SHA256_C */ + +#if defined(MBEDTLS_SHA512_C) +static void ssl_calc_finished_tls_sha384( + mbedtls_ssl_context *ssl, unsigned char *buf, int from ) +{ + int len = 12; + const char *sender; + mbedtls_sha512_context sha512; + unsigned char padbuf[48]; + + mbedtls_ssl_session *session = ssl->session_negotiate; + if( !session ) + session = ssl->session; + + mbedtls_sha512_init( &sha512 ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> calc finished tls sha384" ) ); + + mbedtls_sha512_clone( &sha512, &ssl->handshake->fin_sha512 ); + + /* + * TLSv1.2: + * hash = PRF( master, finished_label, + * Hash( handshake ) )[0.11] + */ + +#if !defined(MBEDTLS_SHA512_ALT) + MBEDTLS_SSL_DEBUG_BUF( 4, "finished sha512 state", (unsigned char *) + sha512.state, sizeof( sha512.state ) ); +#endif + + sender = ( from == MBEDTLS_SSL_IS_CLIENT ) + ? "client finished" + : "server finished"; + + mbedtls_sha512_finish( &sha512, padbuf ); + + ssl->handshake->tls_prf( session->master, 48, sender, + padbuf, 48, buf, len ); + + MBEDTLS_SSL_DEBUG_BUF( 3, "calc finished result", buf, len ); + + mbedtls_sha512_free( &sha512 ); + + mbedtls_zeroize( padbuf, sizeof( padbuf ) ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= calc finished" ) ); +} +#endif /* MBEDTLS_SHA512_C */ +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +static void ssl_handshake_wrapup_free_hs_transform( mbedtls_ssl_context *ssl ) +{ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "=> handshake wrapup: final free" ) ); + + /* + * Free our handshake params + */ + mbedtls_ssl_handshake_free( ssl->handshake ); + mbedtls_free( ssl->handshake ); + ssl->handshake = NULL; + + /* + * Free the previous transform and swith in the current one + */ + if( ssl->transform ) + { + mbedtls_ssl_transform_free( ssl->transform ); + mbedtls_free( ssl->transform ); + } + ssl->transform = ssl->transform_negotiate; + ssl->transform_negotiate = NULL; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup: final free" ) ); +} + +void mbedtls_ssl_handshake_wrapup( mbedtls_ssl_context *ssl ) +{ + int resume = ssl->handshake->resume; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "=> handshake wrapup" ) ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_DONE; + ssl->renego_records_seen = 0; + } +#endif + + /* + * Free the previous session and switch in the current one + */ + if( ssl->session ) + { +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + /* RFC 7366 3.1: keep the EtM state */ + ssl->session_negotiate->encrypt_then_mac = + ssl->session->encrypt_then_mac; +#endif + + mbedtls_ssl_session_free( ssl->session ); + mbedtls_free( ssl->session ); + } + ssl->session = ssl->session_negotiate; + ssl->session_negotiate = NULL; + + /* + * Add cache entry + */ + if( ssl->conf->f_set_cache != NULL && + ssl->session->id_len != 0 && + resume == 0 ) + { + if( ssl->conf->f_set_cache( ssl->conf->p_cache, ssl->session ) != 0 ) + MBEDTLS_SSL_DEBUG_MSG( 1, ( "cache did not store session" ) ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->handshake->flight != NULL ) + { + /* Cancel handshake timer */ + ssl_set_timer( ssl, 0 ); + + /* Keep last flight around in case we need to resend it: + * we need the handshake and transform structures for that */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "skip freeing handshake and transform" ) ); + } + else +#endif + ssl_handshake_wrapup_free_hs_transform( ssl ); + + ssl->state++; + + MBEDTLS_SSL_DEBUG_MSG( 3, ( "<= handshake wrapup" ) ); +} + +int mbedtls_ssl_write_finished( mbedtls_ssl_context *ssl ) +{ + int ret, hash_len; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write finished" ) ); + + /* + * Set the out_msg pointer to the correct location based on IV length + */ + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_2 ) + { + ssl->out_msg = ssl->out_iv + ssl->transform_negotiate->ivlen - + ssl->transform_negotiate->fixed_ivlen; + } + else + ssl->out_msg = ssl->out_iv; + + ssl->handshake->calc_finished( ssl, ssl->out_msg + 4, ssl->conf->endpoint ); + + /* + * RFC 5246 7.4.9 (Page 63) says 12 is the default length and ciphersuites + * may define some other value. Currently (early 2016), no defined + * ciphersuite does this (and this is unlikely to change as activity has + * moved to TLS 1.3 now) so we can keep the hardcoded 12 here. + */ + hash_len = ( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) ? 36 : 12; + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->verify_data_len = hash_len; + memcpy( ssl->own_verify_data, ssl->out_msg + 4, hash_len ); +#endif + + ssl->out_msglen = 4 + hash_len; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_FINISHED; + + /* + * In case of session resuming, invert the client and server + * ChangeCipherSpec messages order. + */ + if( ssl->handshake->resume != 0 ) + { +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; +#endif +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ssl->state = MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC; +#endif + } + else + ssl->state++; + + /* + * Switch to our negotiated transform and session parameters for outbound + * data. + */ + MBEDTLS_SSL_DEBUG_MSG( 3, ( "switching to new transform spec for outbound data" ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + unsigned char i; + + /* Remember current epoch settings for resending */ + ssl->handshake->alt_transform_out = ssl->transform_out; + memcpy( ssl->handshake->alt_out_ctr, ssl->out_ctr, 8 ); + + /* Set sequence_number to zero */ + memset( ssl->out_ctr + 2, 0, 6 ); + + /* Increment epoch */ + for( i = 2; i > 0; i-- ) + if( ++ssl->out_ctr[i - 1] != 0 ) + break; + + /* The loop goes to its end iff the counter is wrapping */ + if( i == 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "DTLS epoch would wrap" ) ); + return( MBEDTLS_ERR_SSL_COUNTER_WRAPPING ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_DTLS */ + memset( ssl->out_ctr, 0, 8 ); + + ssl->transform_out = ssl->transform_negotiate; + ssl->session_out = ssl->session_negotiate; + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_activate != NULL ) + { + if( ( ret = mbedtls_ssl_hw_record_activate( ssl, MBEDTLS_SSL_CHANNEL_OUTBOUND ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_activate", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_send_flight_completed( ssl ); +#endif + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write finished" ) ); + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_PROTO_SSL3) +#define SSL_MAX_HASH_LEN 36 +#else +#define SSL_MAX_HASH_LEN 12 +#endif + +int mbedtls_ssl_parse_finished( mbedtls_ssl_context *ssl ) +{ + int ret; + unsigned int hash_len; + unsigned char buf[SSL_MAX_HASH_LEN]; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> parse finished" ) ); + + ssl->handshake->calc_finished( ssl, buf, ssl->conf->endpoint ^ 1 ); + + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + /* There is currently no ciphersuite using another length with TLS 1.2 */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + hash_len = 36; + else +#endif + hash_len = 12; + + if( ssl->in_msg[0] != MBEDTLS_SSL_HS_FINISHED || + ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) + hash_len ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + } + + if( mbedtls_ssl_safer_memcmp( ssl->in_msg + mbedtls_ssl_hs_hdr_len( ssl ), + buf, hash_len ) != 0 ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad finished message" ) ); + return( MBEDTLS_ERR_SSL_BAD_HS_FINISHED ); + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->verify_data_len = hash_len; + memcpy( ssl->peer_verify_data, buf, hash_len ); +#endif + + if( ssl->handshake->resume != 0 ) + { +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ssl->state = MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC; +#endif +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ssl->state = MBEDTLS_SSL_HANDSHAKE_WRAPUP; +#endif + } + else + ssl->state++; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + mbedtls_ssl_recv_flight_completed( ssl ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= parse finished" ) ); + + return( 0 ); +} + +static void ssl_handshake_params_init( mbedtls_ssl_handshake_params *handshake ) +{ + memset( handshake, 0, sizeof( mbedtls_ssl_handshake_params ) ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_init( &handshake->fin_md5 ); + mbedtls_sha1_init( &handshake->fin_sha1 ); + mbedtls_md5_starts( &handshake->fin_md5 ); + mbedtls_sha1_starts( &handshake->fin_sha1 ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_init( &handshake->fin_sha256 ); + mbedtls_sha256_starts( &handshake->fin_sha256, 0 ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_init( &handshake->fin_sha512 ); + mbedtls_sha512_starts( &handshake->fin_sha512, 1 ); +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + + handshake->update_checksum = ssl_update_checksum_start; + handshake->sig_alg = MBEDTLS_SSL_HASH_SHA1; + +#if defined(MBEDTLS_DHM_C) + mbedtls_dhm_init( &handshake->dhm_ctx ); +#endif +#if defined(MBEDTLS_ECDH_C) + mbedtls_ecdh_init( &handshake->ecdh_ctx ); +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + mbedtls_ecjpake_init( &handshake->ecjpake_ctx ); +#if defined(MBEDTLS_SSL_CLI_C) + handshake->ecjpake_cache = NULL; + handshake->ecjpake_cache_len = 0; +#endif +#endif + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + handshake->sni_authmode = MBEDTLS_SSL_VERIFY_UNSET; +#endif +} + +static void ssl_transform_init( mbedtls_ssl_transform *transform ) +{ + memset( transform, 0, sizeof(mbedtls_ssl_transform) ); + + mbedtls_cipher_init( &transform->cipher_ctx_enc ); + mbedtls_cipher_init( &transform->cipher_ctx_dec ); + + mbedtls_md_init( &transform->md_ctx_enc ); + mbedtls_md_init( &transform->md_ctx_dec ); +} + +void mbedtls_ssl_session_init( mbedtls_ssl_session *session ) +{ + memset( session, 0, sizeof(mbedtls_ssl_session) ); +} + +static int ssl_handshake_init( mbedtls_ssl_context *ssl ) +{ + /* Clear old handshake information if present */ + if( ssl->transform_negotiate ) + mbedtls_ssl_transform_free( ssl->transform_negotiate ); + if( ssl->session_negotiate ) + mbedtls_ssl_session_free( ssl->session_negotiate ); + if( ssl->handshake ) + mbedtls_ssl_handshake_free( ssl->handshake ); + + /* + * Either the pointers are now NULL or cleared properly and can be freed. + * Now allocate missing structures. + */ + if( ssl->transform_negotiate == NULL ) + { + ssl->transform_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_transform) ); + } + + if( ssl->session_negotiate == NULL ) + { + ssl->session_negotiate = mbedtls_calloc( 1, sizeof(mbedtls_ssl_session) ); + } + + if( ssl->handshake == NULL ) + { + ssl->handshake = mbedtls_calloc( 1, sizeof(mbedtls_ssl_handshake_params) ); + } + + /* All pointers should exist and can be directly freed without issue */ + if( ssl->handshake == NULL || + ssl->transform_negotiate == NULL || + ssl->session_negotiate == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc() of ssl sub-contexts failed" ) ); + + mbedtls_free( ssl->handshake ); + mbedtls_free( ssl->transform_negotiate ); + mbedtls_free( ssl->session_negotiate ); + + ssl->handshake = NULL; + ssl->transform_negotiate = NULL; + ssl->session_negotiate = NULL; + + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + /* Initialize structures */ + mbedtls_ssl_session_init( ssl->session_negotiate ); + ssl_transform_init( ssl->transform_negotiate ); + ssl_handshake_params_init( ssl->handshake ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->handshake->alt_transform_out = ssl->transform_out; + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_PREPARING; + else + ssl->handshake->retransmit_state = MBEDTLS_SSL_RETRANS_WAITING; + + ssl_set_timer( ssl, 0 ); + } +#endif + + return( 0 ); +} + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) +/* Dummy cookie callbacks for defaults */ +static int ssl_cookie_write_dummy( void *ctx, + unsigned char **p, unsigned char *end, + const unsigned char *cli_id, size_t cli_id_len ) +{ + ((void) ctx); + ((void) p); + ((void) end); + ((void) cli_id); + ((void) cli_id_len); + + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +} + +static int ssl_cookie_check_dummy( void *ctx, + const unsigned char *cookie, size_t cookie_len, + const unsigned char *cli_id, size_t cli_id_len ) +{ + ((void) ctx); + ((void) cookie); + ((void) cookie_len); + ((void) cli_id); + ((void) cli_id_len); + + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +} +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY && MBEDTLS_SSL_SRV_C */ + +/* + * Initialize an SSL context + */ +void mbedtls_ssl_init( mbedtls_ssl_context *ssl ) +{ + memset( ssl, 0, sizeof( mbedtls_ssl_context ) ); +} + +/* + * Setup an SSL context + */ +int mbedtls_ssl_setup( mbedtls_ssl_context *ssl, + const mbedtls_ssl_config *conf ) +{ + int ret; + const size_t len = MBEDTLS_SSL_BUFFER_LEN; + + ssl->conf = conf; + + /* + * Prepare base structures + */ + if( ( ssl-> in_buf = mbedtls_calloc( 1, len ) ) == NULL || + ( ssl->out_buf = mbedtls_calloc( 1, len ) ) == NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "alloc(%d bytes) failed", len ) ); + mbedtls_free( ssl->in_buf ); + ssl->in_buf = NULL; + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + ssl->out_hdr = ssl->out_buf; + ssl->out_ctr = ssl->out_buf + 3; + ssl->out_len = ssl->out_buf + 11; + ssl->out_iv = ssl->out_buf + 13; + ssl->out_msg = ssl->out_buf + 13; + + ssl->in_hdr = ssl->in_buf; + ssl->in_ctr = ssl->in_buf + 3; + ssl->in_len = ssl->in_buf + 11; + ssl->in_iv = ssl->in_buf + 13; + ssl->in_msg = ssl->in_buf + 13; + } + else +#endif + { + ssl->out_ctr = ssl->out_buf; + ssl->out_hdr = ssl->out_buf + 8; + ssl->out_len = ssl->out_buf + 11; + ssl->out_iv = ssl->out_buf + 13; + ssl->out_msg = ssl->out_buf + 13; + + ssl->in_ctr = ssl->in_buf; + ssl->in_hdr = ssl->in_buf + 8; + ssl->in_len = ssl->in_buf + 11; + ssl->in_iv = ssl->in_buf + 13; + ssl->in_msg = ssl->in_buf + 13; + } + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Reset an initialized and used SSL context for re-use while retaining + * all application-set variables, function pointers and data. + * + * If partial is non-zero, keep data in the input buffer and client ID. + * (Use when a DTLS client reconnects from the same port.) + */ +static int ssl_session_reset_int( mbedtls_ssl_context *ssl, int partial ) +{ + int ret; + + ssl->state = MBEDTLS_SSL_HELLO_REQUEST; + + /* Cancel any possibly running timer */ + ssl_set_timer( ssl, 0 ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + ssl->renego_status = MBEDTLS_SSL_INITIAL_HANDSHAKE; + ssl->renego_records_seen = 0; + + ssl->verify_data_len = 0; + memset( ssl->own_verify_data, 0, MBEDTLS_SSL_VERIFY_DATA_MAX_LEN ); + memset( ssl->peer_verify_data, 0, MBEDTLS_SSL_VERIFY_DATA_MAX_LEN ); +#endif + ssl->secure_renegotiation = MBEDTLS_SSL_LEGACY_RENEGOTIATION; + + ssl->in_offt = NULL; + + ssl->in_msg = ssl->in_buf + 13; + ssl->in_msgtype = 0; + ssl->in_msglen = 0; + if( partial == 0 ) + ssl->in_left = 0; +#if defined(MBEDTLS_SSL_PROTO_DTLS) + ssl->next_record_offset = 0; + ssl->in_epoch = 0; +#endif +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + ssl_dtls_replay_reset( ssl ); +#endif + + ssl->in_hslen = 0; + ssl->nb_zero = 0; + ssl->record_read = 0; + + ssl->out_msg = ssl->out_buf + 13; + ssl->out_msgtype = 0; + ssl->out_msglen = 0; + ssl->out_left = 0; +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + if( ssl->split_done != MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED ) + ssl->split_done = 0; +#endif + + ssl->transform_in = NULL; + ssl->transform_out = NULL; + + memset( ssl->out_buf, 0, MBEDTLS_SSL_BUFFER_LEN ); + if( partial == 0 ) + memset( ssl->in_buf, 0, MBEDTLS_SSL_BUFFER_LEN ); + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_reset != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_reset()" ) ); + if( ( ret = mbedtls_ssl_hw_record_reset( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_hw_record_reset", ret ); + return( MBEDTLS_ERR_SSL_HW_ACCEL_FAILED ); + } + } +#endif + + if( ssl->transform ) + { + mbedtls_ssl_transform_free( ssl->transform ); + mbedtls_free( ssl->transform ); + ssl->transform = NULL; + } + + if( ssl->session ) + { + mbedtls_ssl_session_free( ssl->session ); + mbedtls_free( ssl->session ); + ssl->session = NULL; + } + +#if defined(MBEDTLS_SSL_ALPN) + ssl->alpn_chosen = NULL; +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + if( partial == 0 ) + { + mbedtls_free( ssl->cli_id ); + ssl->cli_id = NULL; + ssl->cli_id_len = 0; + } +#endif + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +/* + * Reset an initialized and used SSL context for re-use while retaining + * all application-set variables, function pointers and data. + */ +int mbedtls_ssl_session_reset( mbedtls_ssl_context *ssl ) +{ + return( ssl_session_reset_int( ssl, 0 ) ); +} + +/* + * SSL set accessors + */ +void mbedtls_ssl_conf_endpoint( mbedtls_ssl_config *conf, int endpoint ) +{ + conf->endpoint = endpoint; +} + +void mbedtls_ssl_conf_transport( mbedtls_ssl_config *conf, int transport ) +{ + conf->transport = transport; +} + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) +void mbedtls_ssl_conf_dtls_anti_replay( mbedtls_ssl_config *conf, char mode ) +{ + conf->anti_replay = mode; +} +#endif + +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) +void mbedtls_ssl_conf_dtls_badmac_limit( mbedtls_ssl_config *conf, unsigned limit ) +{ + conf->badmac_limit = limit; +} +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) +void mbedtls_ssl_conf_handshake_timeout( mbedtls_ssl_config *conf, uint32_t min, uint32_t max ) +{ + conf->hs_timeout_min = min; + conf->hs_timeout_max = max; +} +#endif + +void mbedtls_ssl_conf_authmode( mbedtls_ssl_config *conf, int authmode ) +{ + conf->authmode = authmode; +} + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +void mbedtls_ssl_conf_verify( mbedtls_ssl_config *conf, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + conf->f_vrfy = f_vrfy; + conf->p_vrfy = p_vrfy; +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +void mbedtls_ssl_conf_rng( mbedtls_ssl_config *conf, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + conf->f_rng = f_rng; + conf->p_rng = p_rng; +} + +void mbedtls_ssl_conf_dbg( mbedtls_ssl_config *conf, + void (*f_dbg)(void *, int, const char *, int, const char *), + void *p_dbg ) +{ + conf->f_dbg = f_dbg; + conf->p_dbg = p_dbg; +} + +void mbedtls_ssl_set_bio( mbedtls_ssl_context *ssl, + void *p_bio, + mbedtls_ssl_send_t *f_send, + mbedtls_ssl_recv_t *f_recv, + mbedtls_ssl_recv_timeout_t *f_recv_timeout ) +{ + ssl->p_bio = p_bio; + ssl->f_send = f_send; + ssl->f_recv = f_recv; + ssl->f_recv_timeout = f_recv_timeout; +} + +void mbedtls_ssl_conf_read_timeout( mbedtls_ssl_config *conf, uint32_t timeout ) +{ + conf->read_timeout = timeout; +} + +void mbedtls_ssl_set_timer_cb( mbedtls_ssl_context *ssl, + void *p_timer, + mbedtls_ssl_set_timer_t *f_set_timer, + mbedtls_ssl_get_timer_t *f_get_timer ) +{ + ssl->p_timer = p_timer; + ssl->f_set_timer = f_set_timer; + ssl->f_get_timer = f_get_timer; + + /* Make sure we start with no timer running */ + ssl_set_timer( ssl, 0 ); +} + +#if defined(MBEDTLS_SSL_SRV_C) +void mbedtls_ssl_conf_session_cache( mbedtls_ssl_config *conf, + void *p_cache, + int (*f_get_cache)(void *, mbedtls_ssl_session *), + int (*f_set_cache)(void *, const mbedtls_ssl_session *) ) +{ + conf->p_cache = p_cache; + conf->f_get_cache = f_get_cache; + conf->f_set_cache = f_set_cache; +} +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +int mbedtls_ssl_set_session( mbedtls_ssl_context *ssl, const mbedtls_ssl_session *session ) +{ + int ret; + + if( ssl == NULL || + session == NULL || + ssl->session_negotiate == NULL || + ssl->conf->endpoint != MBEDTLS_SSL_IS_CLIENT ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( ( ret = ssl_session_copy( ssl->session_negotiate, session ) ) != 0 ) + return( ret ); + + ssl->handshake->resume = 1; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +void mbedtls_ssl_conf_ciphersuites( mbedtls_ssl_config *conf, + const int *ciphersuites ) +{ + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] = ciphersuites; + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = ciphersuites; + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = ciphersuites; + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = ciphersuites; +} + +void mbedtls_ssl_conf_ciphersuites_for_version( mbedtls_ssl_config *conf, + const int *ciphersuites, + int major, int minor ) +{ + if( major != MBEDTLS_SSL_MAJOR_VERSION_3 ) + return; + + if( minor < MBEDTLS_SSL_MINOR_VERSION_0 || minor > MBEDTLS_SSL_MINOR_VERSION_3 ) + return; + + conf->ciphersuite_list[minor] = ciphersuites; +} + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +void mbedtls_ssl_conf_cert_profile( mbedtls_ssl_config *conf, + const mbedtls_x509_crt_profile *profile ) +{ + conf->cert_profile = profile; +} + +/* Append a new keycert entry to a (possibly empty) list */ +static int ssl_append_key_cert( mbedtls_ssl_key_cert **head, + mbedtls_x509_crt *cert, + mbedtls_pk_context *key ) +{ + mbedtls_ssl_key_cert *new; + + new = mbedtls_calloc( 1, sizeof( mbedtls_ssl_key_cert ) ); + if( new == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + new->cert = cert; + new->key = key; + new->next = NULL; + + /* Update head is the list was null, else add to the end */ + if( *head == NULL ) + { + *head = new; + } + else + { + mbedtls_ssl_key_cert *cur = *head; + while( cur->next != NULL ) + cur = cur->next; + cur->next = new; + } + + return( 0 ); +} + +int mbedtls_ssl_conf_own_cert( mbedtls_ssl_config *conf, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ) +{ + return( ssl_append_key_cert( &conf->key_cert, own_cert, pk_key ) ); +} + +void mbedtls_ssl_conf_ca_chain( mbedtls_ssl_config *conf, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ) +{ + conf->ca_chain = ca_chain; + conf->ca_crl = ca_crl; +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +int mbedtls_ssl_set_hs_own_cert( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *own_cert, + mbedtls_pk_context *pk_key ) +{ + return( ssl_append_key_cert( &ssl->handshake->sni_key_cert, + own_cert, pk_key ) ); +} + +void mbedtls_ssl_set_hs_ca_chain( mbedtls_ssl_context *ssl, + mbedtls_x509_crt *ca_chain, + mbedtls_x509_crl *ca_crl ) +{ + ssl->handshake->sni_ca_chain = ca_chain; + ssl->handshake->sni_ca_crl = ca_crl; +} + +void mbedtls_ssl_set_hs_authmode( mbedtls_ssl_context *ssl, + int authmode ) +{ + ssl->handshake->sni_authmode = authmode; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) +/* + * Set EC J-PAKE password for current handshake + */ +int mbedtls_ssl_set_hs_ecjpake_password( mbedtls_ssl_context *ssl, + const unsigned char *pw, + size_t pw_len ) +{ + mbedtls_ecjpake_role role; + + if( ssl->handshake == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + role = MBEDTLS_ECJPAKE_SERVER; + else + role = MBEDTLS_ECJPAKE_CLIENT; + + return( mbedtls_ecjpake_setup( &ssl->handshake->ecjpake_ctx, + role, + MBEDTLS_MD_SHA256, + MBEDTLS_ECP_DP_SECP256R1, + pw, pw_len ) ); +} +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) +int mbedtls_ssl_conf_psk( mbedtls_ssl_config *conf, + const unsigned char *psk, size_t psk_len, + const unsigned char *psk_identity, size_t psk_identity_len ) +{ + if( psk == NULL || psk_identity == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( psk_len > MBEDTLS_PSK_MAX_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + /* Identity len will be encoded on two bytes */ + if( ( psk_identity_len >> 16 ) != 0 || + psk_identity_len > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + if( conf->psk != NULL || conf->psk_identity != NULL ) + { + mbedtls_free( conf->psk ); + mbedtls_free( conf->psk_identity ); + conf->psk = NULL; + conf->psk_identity = NULL; + } + + if( ( conf->psk = mbedtls_calloc( 1, psk_len ) ) == NULL || + ( conf->psk_identity = mbedtls_calloc( 1, psk_identity_len ) ) == NULL ) + { + mbedtls_free( conf->psk ); + mbedtls_free( conf->psk_identity ); + conf->psk = NULL; + conf->psk_identity = NULL; + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + } + + conf->psk_len = psk_len; + conf->psk_identity_len = psk_identity_len; + + memcpy( conf->psk, psk, conf->psk_len ); + memcpy( conf->psk_identity, psk_identity, conf->psk_identity_len ); + + return( 0 ); +} + +int mbedtls_ssl_set_hs_psk( mbedtls_ssl_context *ssl, + const unsigned char *psk, size_t psk_len ) +{ + if( psk == NULL || ssl->handshake == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( psk_len > MBEDTLS_PSK_MAX_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ssl->handshake->psk != NULL ) + mbedtls_free( ssl->handshake->psk ); + + if( ( ssl->handshake->psk = mbedtls_calloc( 1, psk_len ) ) == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + ssl->handshake->psk_len = psk_len; + memcpy( ssl->handshake->psk, psk, ssl->handshake->psk_len ); + + return( 0 ); +} + +void mbedtls_ssl_conf_psk_cb( mbedtls_ssl_config *conf, + int (*f_psk)(void *, mbedtls_ssl_context *, const unsigned char *, + size_t), + void *p_psk ) +{ + conf->f_psk = f_psk; + conf->p_psk = p_psk; +} +#endif /* MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) +int mbedtls_ssl_conf_dh_param( mbedtls_ssl_config *conf, const char *dhm_P, const char *dhm_G ) +{ + int ret; + + if( ( ret = mbedtls_mpi_read_string( &conf->dhm_P, 16, dhm_P ) ) != 0 || + ( ret = mbedtls_mpi_read_string( &conf->dhm_G, 16, dhm_G ) ) != 0 ) + { + mbedtls_mpi_free( &conf->dhm_P ); + mbedtls_mpi_free( &conf->dhm_G ); + return( ret ); + } + + return( 0 ); +} + +int mbedtls_ssl_conf_dh_param_ctx( mbedtls_ssl_config *conf, mbedtls_dhm_context *dhm_ctx ) +{ + int ret; + + if( ( ret = mbedtls_mpi_copy( &conf->dhm_P, &dhm_ctx->P ) ) != 0 || + ( ret = mbedtls_mpi_copy( &conf->dhm_G, &dhm_ctx->G ) ) != 0 ) + { + mbedtls_mpi_free( &conf->dhm_P ); + mbedtls_mpi_free( &conf->dhm_G ); + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) +/* + * Set the minimum length for Diffie-Hellman parameters + */ +void mbedtls_ssl_conf_dhm_min_bitlen( mbedtls_ssl_config *conf, + unsigned int bitlen ) +{ + conf->dhm_min_bitlen = bitlen; +} +#endif /* MBEDTLS_DHM_C && MBEDTLS_SSL_CLI_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +/* + * Set allowed/preferred hashes for handshake signatures + */ +void mbedtls_ssl_conf_sig_hashes( mbedtls_ssl_config *conf, + const int *hashes ) +{ + conf->sig_hashes = hashes; +} +#endif + +#if defined(MBEDTLS_ECP_C) +/* + * Set the allowed elliptic curves + */ +void mbedtls_ssl_conf_curves( mbedtls_ssl_config *conf, + const mbedtls_ecp_group_id *curve_list ) +{ + conf->curve_list = curve_list; +} +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname ) +{ + size_t hostname_len; + + if( hostname == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + hostname_len = strlen( hostname ); + + if( hostname_len + 1 == 0 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( hostname_len > MBEDTLS_SSL_MAX_HOST_NAME_LEN ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ssl->hostname = mbedtls_calloc( 1, hostname_len + 1 ); + + if( ssl->hostname == NULL ) + return( MBEDTLS_ERR_SSL_ALLOC_FAILED ); + + memcpy( ssl->hostname, hostname, hostname_len ); + + ssl->hostname[hostname_len] = '\0'; + + return( 0 ); +} +#endif + +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) +void mbedtls_ssl_conf_sni( mbedtls_ssl_config *conf, + int (*f_sni)(void *, mbedtls_ssl_context *, + const unsigned char *, size_t), + void *p_sni ) +{ + conf->f_sni = f_sni; + conf->p_sni = p_sni; +} +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_ALPN) +int mbedtls_ssl_conf_alpn_protocols( mbedtls_ssl_config *conf, const char **protos ) +{ + size_t cur_len, tot_len; + const char **p; + + /* + * RFC 7301 3.1: "Empty strings MUST NOT be included and byte strings + * MUST NOT be truncated." + * We check lengths now rather than later. + */ + tot_len = 0; + for( p = protos; *p != NULL; p++ ) + { + cur_len = strlen( *p ); + tot_len += cur_len; + + if( cur_len == 0 || cur_len > 255 || tot_len > 65535 ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + conf->alpn_list = protos; + + return( 0 ); +} + +const char *mbedtls_ssl_get_alpn_protocol( const mbedtls_ssl_context *ssl ) +{ + return( ssl->alpn_chosen ); +} +#endif /* MBEDTLS_SSL_ALPN */ + +void mbedtls_ssl_conf_max_version( mbedtls_ssl_config *conf, int major, int minor ) +{ + conf->max_major_ver = major; + conf->max_minor_ver = minor; +} + +void mbedtls_ssl_conf_min_version( mbedtls_ssl_config *conf, int major, int minor ) +{ + conf->min_major_ver = major; + conf->min_minor_ver = minor; +} + +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) && defined(MBEDTLS_SSL_CLI_C) +void mbedtls_ssl_conf_fallback( mbedtls_ssl_config *conf, char fallback ) +{ + conf->fallback = fallback; +} +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) +void mbedtls_ssl_conf_encrypt_then_mac( mbedtls_ssl_config *conf, char etm ) +{ + conf->encrypt_then_mac = etm; +} +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) +void mbedtls_ssl_conf_extended_master_secret( mbedtls_ssl_config *conf, char ems ) +{ + conf->extended_ms = ems; +} +#endif + +#if defined(MBEDTLS_ARC4_C) +void mbedtls_ssl_conf_arc4_support( mbedtls_ssl_config *conf, char arc4 ) +{ + conf->arc4_disabled = arc4; +} +#endif + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +int mbedtls_ssl_conf_max_frag_len( mbedtls_ssl_config *conf, unsigned char mfl_code ) +{ + if( mfl_code >= MBEDTLS_SSL_MAX_FRAG_LEN_INVALID || + mfl_code_to_length[mfl_code] > MBEDTLS_SSL_MAX_CONTENT_LEN ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + conf->mfl_code = mfl_code; + + return( 0 ); +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) +void mbedtls_ssl_conf_truncated_hmac( mbedtls_ssl_config *conf, int truncate ) +{ + conf->trunc_hmac = truncate; +} +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) +void mbedtls_ssl_conf_cbc_record_splitting( mbedtls_ssl_config *conf, char split ) +{ + conf->cbc_record_splitting = split; +} +#endif + +void mbedtls_ssl_conf_legacy_renegotiation( mbedtls_ssl_config *conf, int allow_legacy ) +{ + conf->allow_legacy_renegotiation = allow_legacy; +} + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +void mbedtls_ssl_conf_renegotiation( mbedtls_ssl_config *conf, int renegotiation ) +{ + conf->disable_renegotiation = renegotiation; +} + +void mbedtls_ssl_conf_renegotiation_enforced( mbedtls_ssl_config *conf, int max_records ) +{ + conf->renego_max_records = max_records; +} + +void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, + const unsigned char period[8] ) +{ + memcpy( conf->renego_period, period, 8 ); +} +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#if defined(MBEDTLS_SSL_CLI_C) +void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ) +{ + conf->session_tickets = use_tickets; +} +#endif + +#if defined(MBEDTLS_SSL_SRV_C) +void mbedtls_ssl_conf_session_tickets_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_ticket_write_t *f_ticket_write, + mbedtls_ssl_ticket_parse_t *f_ticket_parse, + void *p_ticket ) +{ + conf->f_ticket_write = f_ticket_write; + conf->f_ticket_parse = f_ticket_parse; + conf->p_ticket = p_ticket; +} +#endif +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ + +#if defined(MBEDTLS_SSL_EXPORT_KEYS) +void mbedtls_ssl_conf_export_keys_cb( mbedtls_ssl_config *conf, + mbedtls_ssl_export_keys_t *f_export_keys, + void *p_export_keys ) +{ + conf->f_export_keys = f_export_keys; + conf->p_export_keys = p_export_keys; +} +#endif + +/* + * SSL get accessors + */ +size_t mbedtls_ssl_get_bytes_avail( const mbedtls_ssl_context *ssl ) +{ + return( ssl->in_offt == NULL ? 0 : ssl->in_msglen ); +} + +uint32_t mbedtls_ssl_get_verify_result( const mbedtls_ssl_context *ssl ) +{ + if( ssl->session != NULL ) + return( ssl->session->verify_result ); + + if( ssl->session_negotiate != NULL ) + return( ssl->session_negotiate->verify_result ); + + return( 0xFFFFFFFF ); +} + +const char *mbedtls_ssl_get_ciphersuite( const mbedtls_ssl_context *ssl ) +{ + if( ssl == NULL || ssl->session == NULL ) + return( NULL ); + + return mbedtls_ssl_get_ciphersuite_name( ssl->session->ciphersuite ); +} + +const char *mbedtls_ssl_get_version( const mbedtls_ssl_context *ssl ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + switch( ssl->minor_ver ) + { + case MBEDTLS_SSL_MINOR_VERSION_2: + return( "DTLSv1.0" ); + + case MBEDTLS_SSL_MINOR_VERSION_3: + return( "DTLSv1.2" ); + + default: + return( "unknown (DTLS)" ); + } + } +#endif + + switch( ssl->minor_ver ) + { + case MBEDTLS_SSL_MINOR_VERSION_0: + return( "SSLv3.0" ); + + case MBEDTLS_SSL_MINOR_VERSION_1: + return( "TLSv1.0" ); + + case MBEDTLS_SSL_MINOR_VERSION_2: + return( "TLSv1.1" ); + + case MBEDTLS_SSL_MINOR_VERSION_3: + return( "TLSv1.2" ); + + default: + return( "unknown" ); + } +} + +int mbedtls_ssl_get_record_expansion( const mbedtls_ssl_context *ssl ) +{ + size_t transform_expansion; + const mbedtls_ssl_transform *transform = ssl->transform_out; + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->session_out->compression != MBEDTLS_SSL_COMPRESS_NULL ) + return( MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE ); +#endif + + if( transform == NULL ) + return( (int) mbedtls_ssl_hdr_len( ssl ) ); + + switch( mbedtls_cipher_get_cipher_mode( &transform->cipher_ctx_enc ) ) + { + case MBEDTLS_MODE_GCM: + case MBEDTLS_MODE_CCM: + case MBEDTLS_MODE_STREAM: + transform_expansion = transform->minlen; + break; + + case MBEDTLS_MODE_CBC: + transform_expansion = transform->maclen + + mbedtls_cipher_get_block_size( &transform->cipher_ctx_enc ); + break; + + default: + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + + return( (int)( mbedtls_ssl_hdr_len( ssl ) + transform_expansion ) ); +} + +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) +size_t mbedtls_ssl_get_max_frag_len( const mbedtls_ssl_context *ssl ) +{ + size_t max_len; + + /* + * Assume mfl_code is correct since it was checked when set + */ + max_len = mfl_code_to_length[ssl->conf->mfl_code]; + + /* + * Check if a smaller max length was negotiated + */ + if( ssl->session_out != NULL && + mfl_code_to_length[ssl->session_out->mfl_code] < max_len ) + { + max_len = mfl_code_to_length[ssl->session_out->mfl_code]; + } + + return max_len; +} +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +const mbedtls_x509_crt *mbedtls_ssl_get_peer_cert( const mbedtls_ssl_context *ssl ) +{ + if( ssl == NULL || ssl->session == NULL ) + return( NULL ); + + return( ssl->session->peer_cert ); +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +#if defined(MBEDTLS_SSL_CLI_C) +int mbedtls_ssl_get_session( const mbedtls_ssl_context *ssl, mbedtls_ssl_session *dst ) +{ + if( ssl == NULL || + dst == NULL || + ssl->session == NULL || + ssl->conf->endpoint != MBEDTLS_SSL_IS_CLIENT ) + { + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + + return( ssl_session_copy( dst, ssl->session ) ); +} +#endif /* MBEDTLS_SSL_CLI_C */ + +/* + * Perform a single step of the SSL handshake + */ +int mbedtls_ssl_handshake_step( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + ret = mbedtls_ssl_handshake_client_step( ssl ); +#endif +#if defined(MBEDTLS_SSL_SRV_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ret = mbedtls_ssl_handshake_server_step( ssl ); +#endif + + return( ret ); +} + +/* + * Perform the SSL handshake + */ +int mbedtls_ssl_handshake( mbedtls_ssl_context *ssl ) +{ + int ret = 0; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> handshake" ) ); + + while( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + ret = mbedtls_ssl_handshake_step( ssl ); + + if( ret != 0 ) + break; + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= handshake" ) ); + + return( ret ); +} + +#if defined(MBEDTLS_SSL_RENEGOTIATION) +#if defined(MBEDTLS_SSL_SRV_C) +/* + * Write HelloRequest to request renegotiation on server + */ +static int ssl_write_hello_request( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write hello request" ) ); + + ssl->out_msglen = 4; + ssl->out_msgtype = MBEDTLS_SSL_MSG_HANDSHAKE; + ssl->out_msg[0] = MBEDTLS_SSL_HS_HELLO_REQUEST; + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write hello request" ) ); + + return( 0 ); +} +#endif /* MBEDTLS_SSL_SRV_C */ + +/* + * Actually renegotiate current connection, triggered by either: + * - any side: calling mbedtls_ssl_renegotiate(), + * - client: receiving a HelloRequest during mbedtls_ssl_read(), + * - server: receiving any handshake message on server during mbedtls_ssl_read() after + * the initial handshake is completed. + * If the handshake doesn't complete due to waiting for I/O, it will continue + * during the next calls to mbedtls_ssl_renegotiate() or mbedtls_ssl_read() respectively. + */ +static int ssl_start_renegotiation( mbedtls_ssl_context *ssl ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> renegotiate" ) ); + + if( ( ret = ssl_handshake_init( ssl ) ) != 0 ) + return( ret ); + + /* RFC 6347 4.2.2: "[...] the HelloRequest will have message_seq = 0 and + * the ServerHello will have message_seq = 1" */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + ssl->handshake->out_msg_seq = 1; + else + ssl->handshake->in_msg_seq = 1; + } +#endif + + ssl->state = MBEDTLS_SSL_HELLO_REQUEST; + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS; + + if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= renegotiate" ) ); + + return( 0 ); +} + +/* + * Renegotiate current connection on client, + * or request renegotiation on server + */ +int mbedtls_ssl_renegotiate( mbedtls_ssl_context *ssl ) +{ + int ret = MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_SSL_SRV_C) + /* On server, just send the request */ + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING; + + /* Did we already try/start sending HelloRequest? */ + if( ssl->out_left != 0 ) + return( mbedtls_ssl_flush_output( ssl ) ); + + return( ssl_write_hello_request( ssl ) ); + } +#endif /* MBEDTLS_SSL_SRV_C */ + +#if defined(MBEDTLS_SSL_CLI_C) + /* + * On client, either start the renegotiation process or, + * if already in progress, continue the handshake + */ + if( ssl->renego_status != MBEDTLS_SSL_RENEGOTIATION_IN_PROGRESS ) + { + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + if( ( ret = ssl_start_renegotiation( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_start_renegotiation", ret ); + return( ret ); + } + } + else + { + if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_CLI_C */ + + return( ret ); +} + +/* + * Check record counters and renegotiate if they're above the limit. + */ +static int ssl_check_ctr_renegotiate( mbedtls_ssl_context *ssl ) +{ + size_t ep_len = ssl_ep_len( ssl ); + int in_ctr_cmp; + int out_ctr_cmp; + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER || + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING || + ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED ) + { + return( 0 ); + } + + in_ctr_cmp = memcmp( ssl->in_ctr + ep_len, + ssl->conf->renego_period + ep_len, 8 - ep_len ); + out_ctr_cmp = memcmp( ssl->out_ctr + ep_len, + ssl->conf->renego_period + ep_len, 8 - ep_len ); + + if( in_ctr_cmp <= 0 && out_ctr_cmp <= 0 ) + { + return( 0 ); + } + + MBEDTLS_SSL_DEBUG_MSG( 1, ( "record counter limit reached: renegotiate" ) ); + return( mbedtls_ssl_renegotiate( ssl ) ); +} +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + +/* + * Receive application data decrypted from the SSL layer + */ +int mbedtls_ssl_read( mbedtls_ssl_context *ssl, unsigned char *buf, size_t len ) +{ + int ret, record_read = 0; + size_t n; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> read" ) ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + return( ret ); + + if( ssl->handshake != NULL && + ssl->handshake->retransmit_state == MBEDTLS_SSL_RETRANS_SENDING ) + { + if( ( ret = mbedtls_ssl_resend( ssl ) ) != 0 ) + return( ret ); + } + } +#endif + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ( ret = ssl_check_ctr_renegotiate( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); + return( ret ); + } +#endif + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + ret = mbedtls_ssl_handshake( ssl ); + if( ret == MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO ) + { + record_read = 1; + } + else if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + } + + if( ssl->in_offt == NULL ) + { + /* Start timer if not already running */ + if( ssl->f_get_timer != NULL && + ssl->f_get_timer( ssl->p_timer ) == -1 ) + { + ssl_set_timer( ssl, ssl->conf->read_timeout ); + } + + if( ! record_read ) + { + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_SSL_CONN_EOF ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + } + + if( ssl->in_msglen == 0 && + ssl->in_msgtype == MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + /* + * OpenSSL sends empty messages to randomize the IV + */ + if( ( ret = mbedtls_ssl_read_record( ssl ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_SSL_CONN_EOF ) + return( 0 ); + + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_read_record", ret ); + return( ret ); + } + } + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_HANDSHAKE ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "received handshake message" ) ); + +#if defined(MBEDTLS_SSL_CLI_C) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT && + ( ssl->in_msg[0] != MBEDTLS_SSL_HS_HELLO_REQUEST || + ssl->in_hslen != mbedtls_ssl_hs_hdr_len( ssl ) ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not HelloRequest)" ) ); + + /* With DTLS, drop the packet (probably from last handshake) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->in_msg[0] != MBEDTLS_SSL_HS_CLIENT_HELLO ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "handshake received (not ClientHello)" ) ); + + /* With DTLS, drop the packet (probably from last handshake) */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + return( MBEDTLS_ERR_SSL_WANT_READ ); +#endif + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } +#endif + + if( ssl->conf->disable_renegotiation == MBEDTLS_SSL_RENEGOTIATION_DISABLED || + ( ssl->secure_renegotiation == MBEDTLS_SSL_LEGACY_RENEGOTIATION && + ssl->conf->allow_legacy_renegotiation == + MBEDTLS_SSL_LEGACY_NO_RENEGOTIATION ) ) + { + MBEDTLS_SSL_DEBUG_MSG( 3, ( "refusing renegotiation, sending alert" ) ); + +#if defined(MBEDTLS_SSL_PROTO_SSL3) + if( ssl->minor_ver == MBEDTLS_SSL_MINOR_VERSION_0 ) + { + /* + * SSLv3 does not have a "no_renegotiation" alert + */ + if( ( ret = mbedtls_ssl_send_fatal_handshake_failure( ssl ) ) != 0 ) + return( ret ); + } + else +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver >= MBEDTLS_SSL_MINOR_VERSION_1 ) + { + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_WARNING, + MBEDTLS_SSL_ALERT_MSG_NO_RENEGOTIATION ) ) != 0 ) + { + return( ret ); + } + } + else +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 || + MBEDTLS_SSL_PROTO_TLS1_2 */ + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "should never happen" ) ); + return( MBEDTLS_ERR_SSL_INTERNAL_ERROR ); + } + } + else + { + /* DTLS clients need to know renego is server-initiated */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM && + ssl->conf->endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + ssl->renego_status = MBEDTLS_SSL_RENEGOTIATION_PENDING; + } +#endif + ret = ssl_start_renegotiation( ssl ); + if( ret == MBEDTLS_ERR_SSL_WAITING_SERVER_HELLO_RENEGO ) + { + record_read = 1; + } + else if( ret != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_start_renegotiation", ret ); + return( ret ); + } + } + + /* If a non-handshake record was read during renego, fallthrough, + * else tell the user they should call mbedtls_ssl_read() again */ + if( ! record_read ) + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + else if( ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + + if( ssl->conf->renego_max_records >= 0 ) + { + if( ++ssl->renego_records_seen > ssl->conf->renego_max_records ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "renegotiation requested, " + "but not honored by client" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + } + } +#endif /* MBEDTLS_SSL_RENEGOTIATION */ + + /* Fatal and closure alerts handled by mbedtls_ssl_read_record() */ + if( ssl->in_msgtype == MBEDTLS_SSL_MSG_ALERT ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "ignoring non-fatal non-closure alert" ) ); + return( MBEDTLS_ERR_SSL_WANT_READ ); + } + + if( ssl->in_msgtype != MBEDTLS_SSL_MSG_APPLICATION_DATA ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "bad application data message" ) ); + return( MBEDTLS_ERR_SSL_UNEXPECTED_MESSAGE ); + } + + ssl->in_offt = ssl->in_msg; + + /* We're going to return something now, cancel timer, + * except if handshake (renegotiation) is in progress */ + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + ssl_set_timer( ssl, 0 ); + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + /* If we requested renego but received AppData, resend HelloRequest. + * Do it now, after setting in_offt, to avoid taking this branch + * again if ssl_write_hello_request() returns WANT_WRITE */ +#if defined(MBEDTLS_SSL_SRV_C) && defined(MBEDTLS_SSL_RENEGOTIATION) + if( ssl->conf->endpoint == MBEDTLS_SSL_IS_SERVER && + ssl->renego_status == MBEDTLS_SSL_RENEGOTIATION_PENDING ) + { + if( ( ret = ssl_resend_hello_request( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_resend_hello_request", ret ); + return( ret ); + } + } +#endif /* MBEDTLS_SSL_SRV_C && MBEDTLS_SSL_RENEGOTIATION */ +#endif + } + + n = ( len < ssl->in_msglen ) + ? len : ssl->in_msglen; + + memcpy( buf, ssl->in_offt, n ); + ssl->in_msglen -= n; + + if( ssl->in_msglen == 0 ) + /* all bytes consumed */ + ssl->in_offt = NULL; + else + /* more data available */ + ssl->in_offt += n; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= read" ) ); + + return( (int) n ); +} + +/* + * Send application data to be encrypted by the SSL layer, + * taking care of max fragment length and buffer size + */ +static int ssl_write_real( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + int ret; +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + size_t max_len = mbedtls_ssl_get_max_frag_len( ssl ); + + if( len > max_len ) + { +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( ssl->conf->transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + MBEDTLS_SSL_DEBUG_MSG( 1, ( "fragment larger than the (negotiated) " + "maximum fragment length: %d > %d", + len, max_len ) ); + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + } + else +#endif + len = max_len; + } +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ + + if( ssl->out_left != 0 ) + { + if( ( ret = mbedtls_ssl_flush_output( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_flush_output", ret ); + return( ret ); + } + } + else + { + ssl->out_msglen = len; + ssl->out_msgtype = MBEDTLS_SSL_MSG_APPLICATION_DATA; + memcpy( ssl->out_msg, buf, len ); + + if( ( ret = mbedtls_ssl_write_record( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_write_record", ret ); + return( ret ); + } + } + + return( (int) len ); +} + +/* + * Write application data, doing 1/n-1 splitting if necessary. + * + * With non-blocking I/O, ssl_write_real() may return WANT_WRITE, + * then the caller will call us again with the same arguments, so + * remember wether we already did the split or not. + */ +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) +static int ssl_write_split( mbedtls_ssl_context *ssl, + const unsigned char *buf, size_t len ) +{ + int ret; + + if( ssl->conf->cbc_record_splitting == + MBEDTLS_SSL_CBC_RECORD_SPLITTING_DISABLED || + len <= 1 || + ssl->minor_ver > MBEDTLS_SSL_MINOR_VERSION_1 || + mbedtls_cipher_get_cipher_mode( &ssl->transform_out->cipher_ctx_enc ) + != MBEDTLS_MODE_CBC ) + { + return( ssl_write_real( ssl, buf, len ) ); + } + + if( ssl->split_done == 0 ) + { + if( ( ret = ssl_write_real( ssl, buf, 1 ) ) <= 0 ) + return( ret ); + ssl->split_done = 1; + } + + if( ( ret = ssl_write_real( ssl, buf + 1, len - 1 ) ) <= 0 ) + return( ret ); + ssl->split_done = 0; + + return( ret + 1 ); +} +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ + +/* + * Write application data (public-facing wrapper) + */ +int mbedtls_ssl_write( mbedtls_ssl_context *ssl, const unsigned char *buf, size_t len ) +{ + int ret; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write" ) ); + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + if( ( ret = ssl_check_ctr_renegotiate( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "ssl_check_ctr_renegotiate", ret ); + return( ret ); + } +#endif + + if( ssl->state != MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ( ret = mbedtls_ssl_handshake( ssl ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_handshake", ret ); + return( ret ); + } + } + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + ret = ssl_write_split( ssl, buf, len ); +#else + ret = ssl_write_real( ssl, buf, len ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write" ) ); + + return( ret ); +} + +/* + * Notify the peer that the connection is being closed + */ +int mbedtls_ssl_close_notify( mbedtls_ssl_context *ssl ) +{ + int ret; + + if( ssl == NULL || ssl->conf == NULL ) + return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA ); + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> write close notify" ) ); + + if( ssl->out_left != 0 ) + return( mbedtls_ssl_flush_output( ssl ) ); + + if( ssl->state == MBEDTLS_SSL_HANDSHAKE_OVER ) + { + if( ( ret = mbedtls_ssl_send_alert_message( ssl, + MBEDTLS_SSL_ALERT_LEVEL_WARNING, + MBEDTLS_SSL_ALERT_MSG_CLOSE_NOTIFY ) ) != 0 ) + { + MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_ssl_send_alert_message", ret ); + return( ret ); + } + } + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= write close notify" ) ); + + return( 0 ); +} + +void mbedtls_ssl_transform_free( mbedtls_ssl_transform *transform ) +{ + if( transform == NULL ) + return; + +#if defined(MBEDTLS_ZLIB_SUPPORT) + deflateEnd( &transform->ctx_deflate ); + inflateEnd( &transform->ctx_inflate ); +#endif + + mbedtls_cipher_free( &transform->cipher_ctx_enc ); + mbedtls_cipher_free( &transform->cipher_ctx_dec ); + + mbedtls_md_free( &transform->md_ctx_enc ); + mbedtls_md_free( &transform->md_ctx_dec ); + + mbedtls_zeroize( transform, sizeof( mbedtls_ssl_transform ) ); +} + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +static void ssl_key_cert_free( mbedtls_ssl_key_cert *key_cert ) +{ + mbedtls_ssl_key_cert *cur = key_cert, *next; + + while( cur != NULL ) + { + next = cur->next; + mbedtls_free( cur ); + cur = next; + } +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +void mbedtls_ssl_handshake_free( mbedtls_ssl_handshake_params *handshake ) +{ + if( handshake == NULL ) + return; + +#if defined(MBEDTLS_SSL_PROTO_SSL3) || defined(MBEDTLS_SSL_PROTO_TLS1) || \ + defined(MBEDTLS_SSL_PROTO_TLS1_1) + mbedtls_md5_free( &handshake->fin_md5 ); + mbedtls_sha1_free( &handshake->fin_sha1 ); +#endif +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) +#if defined(MBEDTLS_SHA256_C) + mbedtls_sha256_free( &handshake->fin_sha256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + mbedtls_sha512_free( &handshake->fin_sha512 ); +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ + +#if defined(MBEDTLS_DHM_C) + mbedtls_dhm_free( &handshake->dhm_ctx ); +#endif +#if defined(MBEDTLS_ECDH_C) + mbedtls_ecdh_free( &handshake->ecdh_ctx ); +#endif +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + mbedtls_ecjpake_free( &handshake->ecjpake_ctx ); +#if defined(MBEDTLS_SSL_CLI_C) + mbedtls_free( handshake->ecjpake_cache ); + handshake->ecjpake_cache = NULL; + handshake->ecjpake_cache_len = 0; +#endif +#endif + +#if defined(MBEDTLS_ECDH_C) || defined(MBEDTLS_ECDSA_C) || \ + defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + /* explicit void pointer cast for buggy MS compiler */ + mbedtls_free( (void *) handshake->curves ); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( handshake->psk != NULL ) + { + mbedtls_zeroize( handshake->psk, handshake->psk_len ); + mbedtls_free( handshake->psk ); + } +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) && \ + defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + /* + * Free only the linked list wrapper, not the keys themselves + * since the belong to the SNI callback + */ + if( handshake->sni_key_cert != NULL ) + { + mbedtls_ssl_key_cert *cur = handshake->sni_key_cert, *next; + + while( cur != NULL ) + { + next = cur->next; + mbedtls_free( cur ); + cur = next; + } + } +#endif /* MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_SSL_SERVER_NAME_INDICATION */ + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + mbedtls_free( handshake->verify_cookie ); + mbedtls_free( handshake->hs_msg ); + ssl_flight_free( handshake->flight ); +#endif + + mbedtls_zeroize( handshake, sizeof( mbedtls_ssl_handshake_params ) ); +} + +void mbedtls_ssl_session_free( mbedtls_ssl_session *session ) +{ + if( session == NULL ) + return; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( session->peer_cert != NULL ) + { + mbedtls_x509_crt_free( session->peer_cert ); + mbedtls_free( session->peer_cert ); + } +#endif + +#if defined(MBEDTLS_SSL_SESSION_TICKETS) && defined(MBEDTLS_SSL_CLI_C) + mbedtls_free( session->ticket ); +#endif + + mbedtls_zeroize( session, sizeof( mbedtls_ssl_session ) ); +} + +/* + * Free an SSL context + */ +void mbedtls_ssl_free( mbedtls_ssl_context *ssl ) +{ + if( ssl == NULL ) + return; + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "=> free" ) ); + + if( ssl->out_buf != NULL ) + { + mbedtls_zeroize( ssl->out_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_free( ssl->out_buf ); + } + + if( ssl->in_buf != NULL ) + { + mbedtls_zeroize( ssl->in_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_free( ssl->in_buf ); + } + +#if defined(MBEDTLS_ZLIB_SUPPORT) + if( ssl->compress_buf != NULL ) + { + mbedtls_zeroize( ssl->compress_buf, MBEDTLS_SSL_BUFFER_LEN ); + mbedtls_free( ssl->compress_buf ); + } +#endif + + if( ssl->transform ) + { + mbedtls_ssl_transform_free( ssl->transform ); + mbedtls_free( ssl->transform ); + } + + if( ssl->handshake ) + { + mbedtls_ssl_handshake_free( ssl->handshake ); + mbedtls_ssl_transform_free( ssl->transform_negotiate ); + mbedtls_ssl_session_free( ssl->session_negotiate ); + + mbedtls_free( ssl->handshake ); + mbedtls_free( ssl->transform_negotiate ); + mbedtls_free( ssl->session_negotiate ); + } + + if( ssl->session ) + { + mbedtls_ssl_session_free( ssl->session ); + mbedtls_free( ssl->session ); + } + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + if( ssl->hostname != NULL ) + { + mbedtls_zeroize( ssl->hostname, strlen( ssl->hostname ) ); + mbedtls_free( ssl->hostname ); + } +#endif + +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + if( mbedtls_ssl_hw_record_finish != NULL ) + { + MBEDTLS_SSL_DEBUG_MSG( 2, ( "going for mbedtls_ssl_hw_record_finish()" ) ); + mbedtls_ssl_hw_record_finish( ssl ); + } +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + mbedtls_free( ssl->cli_id ); +#endif + + MBEDTLS_SSL_DEBUG_MSG( 2, ( "<= free" ) ); + + /* Actually clear after last debug message */ + mbedtls_zeroize( ssl, sizeof( mbedtls_ssl_context ) ); +} + +/* + * Initialze mbedtls_ssl_config + */ +void mbedtls_ssl_config_init( mbedtls_ssl_config *conf ) +{ + memset( conf, 0, sizeof( mbedtls_ssl_config ) ); +} + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +static int ssl_preset_default_hashes[] = { +#if defined(MBEDTLS_SHA512_C) + MBEDTLS_MD_SHA512, + MBEDTLS_MD_SHA384, +#endif +#if defined(MBEDTLS_SHA256_C) + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA224, +#endif +#if defined(MBEDTLS_SHA1_C) + MBEDTLS_MD_SHA1, +#endif + MBEDTLS_MD_NONE +}; +#endif + +static int ssl_preset_suiteb_ciphersuites[] = { + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + MBEDTLS_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + 0 +}; + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +static int ssl_preset_suiteb_hashes[] = { + MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA384, + MBEDTLS_MD_NONE +}; +#endif + +#if defined(MBEDTLS_ECP_C) +static mbedtls_ecp_group_id ssl_preset_suiteb_curves[] = { + MBEDTLS_ECP_DP_SECP256R1, + MBEDTLS_ECP_DP_SECP384R1, + MBEDTLS_ECP_DP_NONE +}; +#endif + +/* + * Load default in mbedtls_ssl_config + */ +int mbedtls_ssl_config_defaults( mbedtls_ssl_config *conf, + int endpoint, int transport, int preset ) +{ +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) + int ret; +#endif + + /* Use the functions here so that they are covered in tests, + * but otherwise access member directly for efficiency */ + mbedtls_ssl_conf_endpoint( conf, endpoint ); + mbedtls_ssl_conf_transport( conf, transport ); + + /* + * Things that are common to all presets + */ +#if defined(MBEDTLS_SSL_CLI_C) + if( endpoint == MBEDTLS_SSL_IS_CLIENT ) + { + conf->authmode = MBEDTLS_SSL_VERIFY_REQUIRED; +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + conf->session_tickets = MBEDTLS_SSL_SESSION_TICKETS_ENABLED; +#endif + } +#endif + +#if defined(MBEDTLS_ARC4_C) + conf->arc4_disabled = MBEDTLS_SSL_ARC4_DISABLED; +#endif + +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + conf->encrypt_then_mac = MBEDTLS_SSL_ETM_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + conf->extended_ms = MBEDTLS_SSL_EXTENDED_MS_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + conf->cbc_record_splitting = MBEDTLS_SSL_CBC_RECORD_SPLITTING_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) && defined(MBEDTLS_SSL_SRV_C) + conf->f_cookie_write = ssl_cookie_write_dummy; + conf->f_cookie_check = ssl_cookie_check_dummy; +#endif + +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + conf->anti_replay = MBEDTLS_SSL_ANTI_REPLAY_ENABLED; +#endif + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + conf->hs_timeout_min = MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MIN; + conf->hs_timeout_max = MBEDTLS_SSL_DTLS_TIMEOUT_DFL_MAX; +#endif + +#if defined(MBEDTLS_SSL_RENEGOTIATION) + conf->renego_max_records = MBEDTLS_SSL_RENEGO_MAX_RECORDS_DEFAULT; + memset( conf->renego_period, 0x00, 2 ); + memset( conf->renego_period + 2, 0xFF, 6 ); +#endif + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_SRV_C) + if( endpoint == MBEDTLS_SSL_IS_SERVER ) + { + if( ( ret = mbedtls_ssl_conf_dh_param( conf, + MBEDTLS_DHM_RFC5114_MODP_2048_P, + MBEDTLS_DHM_RFC5114_MODP_2048_G ) ) != 0 ) + { + return( ret ); + } + } +#endif + + /* + * Preset-specific defaults + */ + switch( preset ) + { + /* + * NSA Suite B + */ + case MBEDTLS_SSL_PRESET_SUITEB: + conf->min_major_ver = MBEDTLS_SSL_MAJOR_VERSION_3; + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */ + conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION; + conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION; + + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = + ssl_preset_suiteb_ciphersuites; + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + conf->cert_profile = &mbedtls_x509_crt_profile_suiteb; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + conf->sig_hashes = ssl_preset_suiteb_hashes; +#endif + +#if defined(MBEDTLS_ECP_C) + conf->curve_list = ssl_preset_suiteb_curves; +#endif + break; + + /* + * Default + */ + default: + conf->min_major_ver = MBEDTLS_SSL_MAJOR_VERSION_3; + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_1; /* TLS 1.0 */ + conf->max_major_ver = MBEDTLS_SSL_MAX_MAJOR_VERSION; + conf->max_minor_ver = MBEDTLS_SSL_MAX_MINOR_VERSION; + +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + conf->min_minor_ver = MBEDTLS_SSL_MINOR_VERSION_2; +#endif + + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_0] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_1] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_2] = + conf->ciphersuite_list[MBEDTLS_SSL_MINOR_VERSION_3] = + mbedtls_ssl_list_ciphersuites(); + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + conf->cert_profile = &mbedtls_x509_crt_profile_default; +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) + conf->sig_hashes = ssl_preset_default_hashes; +#endif + +#if defined(MBEDTLS_ECP_C) + conf->curve_list = mbedtls_ecp_grp_id_list(); +#endif + +#if defined(MBEDTLS_DHM_C) && defined(MBEDTLS_SSL_CLI_C) + conf->dhm_min_bitlen = 1024; +#endif + } + + return( 0 ); +} + +/* + * Free mbedtls_ssl_config + */ +void mbedtls_ssl_config_free( mbedtls_ssl_config *conf ) +{ +#if defined(MBEDTLS_DHM_C) + mbedtls_mpi_free( &conf->dhm_P ); + mbedtls_mpi_free( &conf->dhm_G ); +#endif + +#if defined(MBEDTLS_KEY_EXCHANGE__SOME__PSK_ENABLED) + if( conf->psk != NULL ) + { + mbedtls_zeroize( conf->psk, conf->psk_len ); + mbedtls_zeroize( conf->psk_identity, conf->psk_identity_len ); + mbedtls_free( conf->psk ); + mbedtls_free( conf->psk_identity ); + conf->psk_len = 0; + conf->psk_identity_len = 0; + } +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + ssl_key_cert_free( conf->key_cert ); +#endif + + mbedtls_zeroize( conf, sizeof( mbedtls_ssl_config ) ); +} + +#if defined(MBEDTLS_PK_C) && \ + ( defined(MBEDTLS_RSA_C) || defined(MBEDTLS_ECDSA_C) ) +/* + * Convert between MBEDTLS_PK_XXX and SSL_SIG_XXX + */ +unsigned char mbedtls_ssl_sig_from_pk( mbedtls_pk_context *pk ) +{ +#if defined(MBEDTLS_RSA_C) + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_RSA ) ) + return( MBEDTLS_SSL_SIG_RSA ); +#endif +#if defined(MBEDTLS_ECDSA_C) + if( mbedtls_pk_can_do( pk, MBEDTLS_PK_ECDSA ) ) + return( MBEDTLS_SSL_SIG_ECDSA ); +#endif + return( MBEDTLS_SSL_SIG_ANON ); +} + +mbedtls_pk_type_t mbedtls_ssl_pk_alg_from_sig( unsigned char sig ) +{ + switch( sig ) + { +#if defined(MBEDTLS_RSA_C) + case MBEDTLS_SSL_SIG_RSA: + return( MBEDTLS_PK_RSA ); +#endif +#if defined(MBEDTLS_ECDSA_C) + case MBEDTLS_SSL_SIG_ECDSA: + return( MBEDTLS_PK_ECDSA ); +#endif + default: + return( MBEDTLS_PK_NONE ); + } +} +#endif /* MBEDTLS_PK_C && ( MBEDTLS_RSA_C || MBEDTLS_ECDSA_C ) */ + +/* + * Convert from MBEDTLS_SSL_HASH_XXX to MBEDTLS_MD_XXX + */ +mbedtls_md_type_t mbedtls_ssl_md_alg_from_hash( unsigned char hash ) +{ + switch( hash ) + { +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_SSL_HASH_MD5: + return( MBEDTLS_MD_MD5 ); +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_SSL_HASH_SHA1: + return( MBEDTLS_MD_SHA1 ); +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_SSL_HASH_SHA224: + return( MBEDTLS_MD_SHA224 ); + case MBEDTLS_SSL_HASH_SHA256: + return( MBEDTLS_MD_SHA256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_SSL_HASH_SHA384: + return( MBEDTLS_MD_SHA384 ); + case MBEDTLS_SSL_HASH_SHA512: + return( MBEDTLS_MD_SHA512 ); +#endif + default: + return( MBEDTLS_MD_NONE ); + } +} + +/* + * Convert from MBEDTLS_MD_XXX to MBEDTLS_SSL_HASH_XXX + */ +unsigned char mbedtls_ssl_hash_from_md_alg( int md ) +{ + switch( md ) + { +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_MD_MD5: + return( MBEDTLS_SSL_HASH_MD5 ); +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_MD_SHA1: + return( MBEDTLS_SSL_HASH_SHA1 ); +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_MD_SHA224: + return( MBEDTLS_SSL_HASH_SHA224 ); + case MBEDTLS_MD_SHA256: + return( MBEDTLS_SSL_HASH_SHA256 ); +#endif +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_MD_SHA384: + return( MBEDTLS_SSL_HASH_SHA384 ); + case MBEDTLS_MD_SHA512: + return( MBEDTLS_SSL_HASH_SHA512 ); +#endif + default: + return( MBEDTLS_SSL_HASH_NONE ); + } +} + +#if defined(MBEDTLS_ECP_C) +/* + * Check if a curve proposed by the peer is in our list. + * Return 0 if we're willing to use it, -1 otherwise. + */ +int mbedtls_ssl_check_curve( const mbedtls_ssl_context *ssl, mbedtls_ecp_group_id grp_id ) +{ + const mbedtls_ecp_group_id *gid; + + if( ssl->conf->curve_list == NULL ) + return( -1 ); + + for( gid = ssl->conf->curve_list; *gid != MBEDTLS_ECP_DP_NONE; gid++ ) + if( *gid == grp_id ) + return( 0 ); + + return( -1 ); +} +#endif /* MBEDTLS_ECP_C */ + +#if defined(MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED) +/* + * Check if a hash proposed by the peer is in our list. + * Return 0 if we're willing to use it, -1 otherwise. + */ +int mbedtls_ssl_check_sig_hash( const mbedtls_ssl_context *ssl, + mbedtls_md_type_t md ) +{ + const int *cur; + + if( ssl->conf->sig_hashes == NULL ) + return( -1 ); + + for( cur = ssl->conf->sig_hashes; *cur != MBEDTLS_MD_NONE; cur++ ) + if( *cur == (int) md ) + return( 0 ); + + return( -1 ); +} +#endif /* MBEDTLS_KEY_EXCHANGE__WITH_CERT__ENABLED */ + +#if defined(MBEDTLS_X509_CRT_PARSE_C) +int mbedtls_ssl_check_cert_usage( const mbedtls_x509_crt *cert, + const mbedtls_ssl_ciphersuite_t *ciphersuite, + int cert_endpoint, + uint32_t *flags ) +{ + int ret = 0; +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + int usage = 0; +#endif +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + const char *ext_oid; + size_t ext_len; +#endif + +#if !defined(MBEDTLS_X509_CHECK_KEY_USAGE) && \ + !defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + ((void) cert); + ((void) cert_endpoint); + ((void) flags); +#endif + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + if( cert_endpoint == MBEDTLS_SSL_IS_SERVER ) + { + /* Server part of the key exchange */ + switch( ciphersuite->key_exchange ) + { + case MBEDTLS_KEY_EXCHANGE_RSA: + case MBEDTLS_KEY_EXCHANGE_RSA_PSK: + usage = MBEDTLS_X509_KU_KEY_ENCIPHERMENT; + break; + + case MBEDTLS_KEY_EXCHANGE_DHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA: + usage = MBEDTLS_X509_KU_DIGITAL_SIGNATURE; + break; + + case MBEDTLS_KEY_EXCHANGE_ECDH_RSA: + case MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA: + usage = MBEDTLS_X509_KU_KEY_AGREEMENT; + break; + + /* Don't use default: we want warnings when adding new values */ + case MBEDTLS_KEY_EXCHANGE_NONE: + case MBEDTLS_KEY_EXCHANGE_PSK: + case MBEDTLS_KEY_EXCHANGE_DHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECDHE_PSK: + case MBEDTLS_KEY_EXCHANGE_ECJPAKE: + usage = 0; + } + } + else + { + /* Client auth: we only implement rsa_sign and mbedtls_ecdsa_sign for now */ + usage = MBEDTLS_X509_KU_DIGITAL_SIGNATURE; + } + + if( mbedtls_x509_crt_check_key_usage( cert, usage ) != 0 ) + { + *flags |= MBEDTLS_X509_BADCERT_KEY_USAGE; + ret = -1; + } +#else + ((void) ciphersuite); +#endif /* MBEDTLS_X509_CHECK_KEY_USAGE */ + +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + if( cert_endpoint == MBEDTLS_SSL_IS_SERVER ) + { + ext_oid = MBEDTLS_OID_SERVER_AUTH; + ext_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_SERVER_AUTH ); + } + else + { + ext_oid = MBEDTLS_OID_CLIENT_AUTH; + ext_len = MBEDTLS_OID_SIZE( MBEDTLS_OID_CLIENT_AUTH ); + } + + if( mbedtls_x509_crt_check_extended_key_usage( cert, ext_oid, ext_len ) != 0 ) + { + *flags |= MBEDTLS_X509_BADCERT_EXT_KEY_USAGE; + ret = -1; + } +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ + + return( ret ); +} +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + +/* + * Convert version numbers to/from wire format + * and, for DTLS, to/from TLS equivalent. + * + * For TLS this is the identity. + * For DTLS, use 1's complement (v -> 255 - v, and then map as follows: + * 1.0 <-> 3.2 (DTLS 1.0 is based on TLS 1.1) + * 1.x <-> 3.x+1 for x != 0 (DTLS 1.2 based on TLS 1.2) + */ +void mbedtls_ssl_write_version( int major, int minor, int transport, + unsigned char ver[2] ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + if( minor == MBEDTLS_SSL_MINOR_VERSION_2 ) + --minor; /* DTLS 1.0 stored as TLS 1.1 internally */ + + ver[0] = (unsigned char)( 255 - ( major - 2 ) ); + ver[1] = (unsigned char)( 255 - ( minor - 1 ) ); + } + else +#else + ((void) transport); +#endif + { + ver[0] = (unsigned char) major; + ver[1] = (unsigned char) minor; + } +} + +void mbedtls_ssl_read_version( int *major, int *minor, int transport, + const unsigned char ver[2] ) +{ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + if( transport == MBEDTLS_SSL_TRANSPORT_DATAGRAM ) + { + *major = 255 - ver[0] + 2; + *minor = 255 - ver[1] + 1; + + if( *minor == MBEDTLS_SSL_MINOR_VERSION_1 ) + ++*minor; /* DTLS 1.0 stored as TLS 1.1 internally */ + } + else +#else + ((void) transport); +#endif + { + *major = ver[0]; + *minor = ver[1]; + } +} + +int mbedtls_ssl_set_calc_verify_md( mbedtls_ssl_context *ssl, int md ) +{ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + if( ssl->minor_ver != MBEDTLS_SSL_MINOR_VERSION_3 ) + return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH; + + switch( md ) + { +#if defined(MBEDTLS_SSL_PROTO_TLS1) || defined(MBEDTLS_SSL_PROTO_TLS1_1) +#if defined(MBEDTLS_MD5_C) + case MBEDTLS_SSL_HASH_MD5: + return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH; +#endif +#if defined(MBEDTLS_SHA1_C) + case MBEDTLS_SSL_HASH_SHA1: + ssl->handshake->calc_verify = ssl_calc_verify_tls; + break; +#endif +#endif /* MBEDTLS_SSL_PROTO_TLS1 || MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SHA512_C) + case MBEDTLS_SSL_HASH_SHA384: + ssl->handshake->calc_verify = ssl_calc_verify_tls_sha384; + break; +#endif +#if defined(MBEDTLS_SHA256_C) + case MBEDTLS_SSL_HASH_SHA256: + ssl->handshake->calc_verify = ssl_calc_verify_tls_sha256; + break; +#endif + default: + return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH; + } + + return 0; +#else /* !MBEDTLS_SSL_PROTO_TLS1_2 */ + (void) ssl; + (void) md; + + return MBEDTLS_ERR_SSL_INVALID_VERIFY_HASH; +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +} + +#endif /* MBEDTLS_SSL_TLS_C */ diff --git a/c++/src/connect/mbedtls/threading.c b/c++/src/connect/mbedtls/threading.c new file mode 100644 index 00000000..cb680ab2 --- /dev/null +++ b/c++/src/connect/mbedtls/threading.c @@ -0,0 +1,138 @@ +/* + * Threading abstraction layer + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_THREADING_C) + +#include "mbedtls/threading.h" + +#if defined(MBEDTLS_THREADING_PTHREAD) +static void threading_mutex_init_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || mutex->is_valid ) + return; + + mutex->is_valid = pthread_mutex_init( &mutex->mutex, NULL ) == 0; +} + +static void threading_mutex_free_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || !mutex->is_valid ) + return; + + (void) pthread_mutex_destroy( &mutex->mutex ); + mutex->is_valid = 0; +} + +static int threading_mutex_lock_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || ! mutex->is_valid ) + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); + + if( pthread_mutex_lock( &mutex->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + return( 0 ); +} + +static int threading_mutex_unlock_pthread( mbedtls_threading_mutex_t *mutex ) +{ + if( mutex == NULL || ! mutex->is_valid ) + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); + + if( pthread_mutex_unlock( &mutex->mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); + + return( 0 ); +} + +void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t * ) = threading_mutex_init_pthread; +void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t * ) = threading_mutex_free_pthread; +int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t * ) = threading_mutex_lock_pthread; +int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t * ) = threading_mutex_unlock_pthread; + +/* + * With phtreads we can statically initialize mutexes + */ +#define MUTEX_INIT = { PTHREAD_MUTEX_INITIALIZER, 1 } + +#endif /* MBEDTLS_THREADING_PTHREAD */ + +#if defined(MBEDTLS_THREADING_ALT) +static int threading_mutex_fail( mbedtls_threading_mutex_t *mutex ) +{ + ((void) mutex ); + return( MBEDTLS_ERR_THREADING_BAD_INPUT_DATA ); +} +static void threading_mutex_dummy( mbedtls_threading_mutex_t *mutex ) +{ + ((void) mutex ); + return; +} + +void (*mbedtls_mutex_init)( mbedtls_threading_mutex_t * ) = threading_mutex_dummy; +void (*mbedtls_mutex_free)( mbedtls_threading_mutex_t * ) = threading_mutex_dummy; +int (*mbedtls_mutex_lock)( mbedtls_threading_mutex_t * ) = threading_mutex_fail; +int (*mbedtls_mutex_unlock)( mbedtls_threading_mutex_t * ) = threading_mutex_fail; + +/* + * Set functions pointers and initialize global mutexes + */ +void mbedtls_threading_set_alt( void (*mutex_init)( mbedtls_threading_mutex_t * ), + void (*mutex_free)( mbedtls_threading_mutex_t * ), + int (*mutex_lock)( mbedtls_threading_mutex_t * ), + int (*mutex_unlock)( mbedtls_threading_mutex_t * ) ) +{ + mbedtls_mutex_init = mutex_init; + mbedtls_mutex_free = mutex_free; + mbedtls_mutex_lock = mutex_lock; + mbedtls_mutex_unlock = mutex_unlock; + + mbedtls_mutex_init( &mbedtls_threading_readdir_mutex ); + mbedtls_mutex_init( &mbedtls_threading_gmtime_mutex ); +} + +/* + * Free global mutexes + */ +void mbedtls_threading_free_alt( void ) +{ + mbedtls_mutex_free( &mbedtls_threading_readdir_mutex ); + mbedtls_mutex_free( &mbedtls_threading_gmtime_mutex ); +} +#endif /* MBEDTLS_THREADING_ALT */ + +/* + * Define global mutexes + */ +#ifndef MUTEX_INIT +#define MUTEX_INIT +#endif +mbedtls_threading_mutex_t mbedtls_threading_readdir_mutex MUTEX_INIT; +mbedtls_threading_mutex_t mbedtls_threading_gmtime_mutex MUTEX_INIT; + +#endif /* MBEDTLS_THREADING_C */ + diff --git a/c++/src/connect/mbedtls/timing.c b/c++/src/connect/mbedtls/timing.c new file mode 100644 index 00000000..a7c7ff02 --- /dev/null +++ b/c++/src/connect/mbedtls/timing.c @@ -0,0 +1,525 @@ +/* + * Portable interface to the CPU cycle counter + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_SELF_TEST) && defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif + +#if defined(MBEDTLS_TIMING_C) + +#include "mbedtls/timing.h" + +#if !defined(MBEDTLS_TIMING_ALT) + +#if !defined(unix) && !defined(__unix__) && !defined(__unix) && \ + !defined(__APPLE__) && !defined(_WIN32) +#error "This module only works on Unix and Windows, see MBEDTLS_TIMING_C in config.h" +#endif + +#ifndef asm +#define asm __asm +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +#include +#include + +struct _hr_time +{ + LARGE_INTEGER start; +}; + +#else + +#include +#include +#include +#include +#include + +struct _hr_time +{ + struct timeval start; +}; + +#endif /* _WIN32 && !EFIX64 && !EFI32 */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + ( defined(_MSC_VER) && defined(_M_IX86) ) || defined(__WATCOMC__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tsc; + __asm rdtsc + __asm mov [tsc], eax + return( tsc ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + ( _MSC_VER && _M_IX86 ) || __WATCOMC__ */ + +/* some versions of mingw-64 have 32-bit longs even on x84_64 */ +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__i386__) || ( \ + ( defined(__amd64__) || defined( __x86_64__) ) && __SIZEOF_LONG__ == 4 ) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long lo, hi; + asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); + return( lo ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __i386__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__amd64__) || defined(__x86_64__) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long lo, hi; + asm volatile( "rdtsc" : "=a" (lo), "=d" (hi) ); + return( lo | ( hi << 32 ) ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && ( __amd64__ || __x86_64__ ) */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && ( defined(__powerpc__) || defined(__ppc__) ) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tbl, tbu0, tbu1; + + do + { + asm volatile( "mftbu %0" : "=r" (tbu0) ); + asm volatile( "mftb %0" : "=r" (tbl ) ); + asm volatile( "mftbu %0" : "=r" (tbu1) ); + } + while( tbu0 != tbu1 ); + + return( tbl ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && ( __powerpc__ || __ppc__ ) */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__sparc64__) + +#if defined(__OpenBSD__) +#warning OpenBSD does not allow access to tick register using software version instead +#else +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tick; + asm volatile( "rdpr %%tick, %0;" : "=&r" (tick) ); + return( tick ); +} +#endif /* __OpenBSD__ */ +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __sparc64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__sparc__) && !defined(__sparc64__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long tick; + asm volatile( ".byte 0x83, 0x41, 0x00, 0x00" ); + asm volatile( "mov %%g1, %0" : "=r" (tick) ); + return( tick ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __sparc__ && !__sparc64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__alpha__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long cc; + asm volatile( "rpcc %0" : "=r" (cc) ); + return( cc & 0xFFFFFFFF ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __alpha__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(MBEDTLS_HAVE_ASM) && \ + defined(__GNUC__) && defined(__ia64__) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + unsigned long itc; + asm volatile( "mov %0 = ar.itc" : "=r" (itc) ); + return( itc ); +} +#endif /* !HAVE_HARDCLOCK && MBEDTLS_HAVE_ASM && + __GNUC__ && __ia64__ */ + +#if !defined(HAVE_HARDCLOCK) && defined(_MSC_VER) && \ + !defined(EFIX64) && !defined(EFI32) + +#define HAVE_HARDCLOCK + +unsigned long mbedtls_timing_hardclock( void ) +{ + LARGE_INTEGER offset; + + QueryPerformanceCounter( &offset ); + + return( (unsigned long)( offset.QuadPart ) ); +} +#endif /* !HAVE_HARDCLOCK && _MSC_VER && !EFIX64 && !EFI32 */ + +#if !defined(HAVE_HARDCLOCK) + +#define HAVE_HARDCLOCK + +static int hardclock_init = 0; +static struct timeval tv_init; + +unsigned long mbedtls_timing_hardclock( void ) +{ + struct timeval tv_cur; + + if( hardclock_init == 0 ) + { + gettimeofday( &tv_init, NULL ); + hardclock_init = 1; + } + + gettimeofday( &tv_cur, NULL ); + return( ( tv_cur.tv_sec - tv_init.tv_sec ) * 1000000 + + ( tv_cur.tv_usec - tv_init.tv_usec ) ); +} +#endif /* !HAVE_HARDCLOCK */ + +volatile int mbedtls_timing_alarmed = 0; + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) +{ + unsigned long delta; + LARGE_INTEGER offset, hfreq; + struct _hr_time *t = (struct _hr_time *) val; + + QueryPerformanceCounter( &offset ); + QueryPerformanceFrequency( &hfreq ); + + delta = (unsigned long)( ( 1000 * + ( offset.QuadPart - t->start.QuadPart ) ) / + hfreq.QuadPart ); + + if( reset ) + QueryPerformanceCounter( &t->start ); + + return( delta ); +} + +/* It's OK to use a global because alarm() is supposed to be global anyway */ +static DWORD alarmMs; + +static DWORD WINAPI TimerProc( LPVOID TimerContext ) +{ + ((void) TimerContext); + Sleep( alarmMs ); + mbedtls_timing_alarmed = 1; + return( TRUE ); +} + +void mbedtls_set_alarm( int seconds ) +{ + DWORD ThreadId; + + mbedtls_timing_alarmed = 0; + alarmMs = seconds * 1000; + CloseHandle( CreateThread( NULL, 0, TimerProc, NULL, 0, &ThreadId ) ); +} + +#else /* _WIN32 && !EFIX64 && !EFI32 */ + +unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset ) +{ + unsigned long delta; + struct timeval offset; + struct _hr_time *t = (struct _hr_time *) val; + + gettimeofday( &offset, NULL ); + + if( reset ) + { + t->start.tv_sec = offset.tv_sec; + t->start.tv_usec = offset.tv_usec; + return( 0 ); + } + + delta = ( offset.tv_sec - t->start.tv_sec ) * 1000 + + ( offset.tv_usec - t->start.tv_usec ) / 1000; + + return( delta ); +} + +static void sighandler( int signum ) +{ + mbedtls_timing_alarmed = 1; + signal( signum, sighandler ); +} + +void mbedtls_set_alarm( int seconds ) +{ + mbedtls_timing_alarmed = 0; + signal( SIGALRM, sighandler ); + alarm( seconds ); +} + +#endif /* _WIN32 && !EFIX64 && !EFI32 */ + +/* + * Set delays to watch + */ +void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms ) +{ + mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; + + ctx->int_ms = int_ms; + ctx->fin_ms = fin_ms; + + if( fin_ms != 0 ) + (void) mbedtls_timing_get_timer( &ctx->timer, 1 ); +} + +/* + * Get number of delays expired + */ +int mbedtls_timing_get_delay( void *data ) +{ + mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data; + unsigned long elapsed_ms; + + if( ctx->fin_ms == 0 ) + return( -1 ); + + elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 ); + + if( elapsed_ms >= ctx->fin_ms ) + return( 2 ); + + if( elapsed_ms >= ctx->int_ms ) + return( 1 ); + + return( 0 ); +} + +#endif /* !MBEDTLS_TIMING_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * Busy-waits for the given number of milliseconds. + * Used for testing mbedtls_timing_hardclock. + */ +static void busy_msleep( unsigned long msec ) +{ + struct mbedtls_timing_hr_time hires; + unsigned long i = 0; /* for busy-waiting */ + volatile unsigned long j; /* to prevent optimisation */ + + (void) mbedtls_timing_get_timer( &hires, 1 ); + + while( mbedtls_timing_get_timer( &hires, 0 ) < msec ) + i++; + + j = i; + (void) j; +} + +#define FAIL do \ +{ \ + if( verbose != 0 ) \ + mbedtls_printf( "failed\n" ); \ + \ + return( 1 ); \ +} while( 0 ) + +/* + * Checkup routine + * + * Warning: this is work in progress, some tests may not be reliable enough + * yet! False positives may happen. + */ +int mbedtls_timing_self_test( int verbose ) +{ + unsigned long cycles, ratio; + unsigned long millisecs, secs; + int hardfail; + struct mbedtls_timing_hr_time hires; + uint32_t a, b; + mbedtls_timing_delay_context ctx; + + if( verbose != 0 ) + mbedtls_printf( " TIMING tests note: will take some time!\n" ); + + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #1 (set_alarm / get_timer): " ); + + for( secs = 1; secs <= 3; secs++ ) + { + (void) mbedtls_timing_get_timer( &hires, 1 ); + + mbedtls_set_alarm( (int) secs ); + while( !mbedtls_timing_alarmed ) + ; + + millisecs = mbedtls_timing_get_timer( &hires, 0 ); + + /* For some reason on Windows it looks like alarm has an extra delay + * (maybe related to creating a new thread). Allow some room here. */ + if( millisecs < 800 * secs || millisecs > 1200 * secs + 300 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( 1 ); + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #2 (set/get_delay ): " ); + + for( a = 200; a <= 400; a += 200 ) + { + for( b = 200; b <= 400; b += 200 ) + { + mbedtls_timing_set_delay( &ctx, a, a + b ); + + busy_msleep( a - a / 8 ); + if( mbedtls_timing_get_delay( &ctx ) != 0 ) + FAIL; + + busy_msleep( a / 4 ); + if( mbedtls_timing_get_delay( &ctx ) != 1 ) + FAIL; + + busy_msleep( b - a / 8 - b / 8 ); + if( mbedtls_timing_get_delay( &ctx ) != 1 ) + FAIL; + + busy_msleep( b / 4 ); + if( mbedtls_timing_get_delay( &ctx ) != 2 ) + FAIL; + } + } + + mbedtls_timing_set_delay( &ctx, 0, 0 ); + busy_msleep( 200 ); + if( mbedtls_timing_get_delay( &ctx ) != -1 ) + FAIL; + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + + if( verbose != 0 ) + mbedtls_printf( " TIMING test #3 (hardclock / get_timer): " ); + + /* + * Allow one failure for possible counter wrapping. + * On a 4Ghz 32-bit machine the cycle counter wraps about once per second; + * since the whole test is about 10ms, it shouldn't happen twice in a row. + */ + hardfail = 0; + +hard_test: + if( hardfail > 1 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed (ignored)\n" ); + + goto hard_test_done; + } + + /* Get a reference ratio cycles/ms */ + millisecs = 1; + cycles = mbedtls_timing_hardclock(); + busy_msleep( millisecs ); + cycles = mbedtls_timing_hardclock() - cycles; + ratio = cycles / millisecs; + + /* Check that the ratio is mostly constant */ + for( millisecs = 2; millisecs <= 4; millisecs++ ) + { + cycles = mbedtls_timing_hardclock(); + busy_msleep( millisecs ); + cycles = mbedtls_timing_hardclock() - cycles; + + /* Allow variation up to 20% */ + if( cycles / millisecs < ratio - ratio / 5 || + cycles / millisecs > ratio + ratio / 5 ) + { + hardfail++; + goto hard_test; + } + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + +hard_test_done: + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + + return( 0 ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_TIMING_C */ diff --git a/c++/src/connect/mbedtls/version_features.c b/c++/src/connect/mbedtls/version_features.c new file mode 100644 index 00000000..9d107eeb --- /dev/null +++ b/c++/src/connect/mbedtls/version_features.c @@ -0,0 +1,648 @@ +/* + * Version feature information + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_VERSION_C) + +#include "mbedtls/version.h" + +#include + +static const char *features[] = { +#if defined(MBEDTLS_VERSION_FEATURES) +#if defined(MBEDTLS_HAVE_ASM) + "MBEDTLS_HAVE_ASM", +#endif /* MBEDTLS_HAVE_ASM */ +#if defined(MBEDTLS_HAVE_SSE2) + "MBEDTLS_HAVE_SSE2", +#endif /* MBEDTLS_HAVE_SSE2 */ +#if defined(MBEDTLS_HAVE_TIME) + "MBEDTLS_HAVE_TIME", +#endif /* MBEDTLS_HAVE_TIME */ +#if defined(MBEDTLS_HAVE_TIME_DATE) + "MBEDTLS_HAVE_TIME_DATE", +#endif /* MBEDTLS_HAVE_TIME_DATE */ +#if defined(MBEDTLS_PLATFORM_MEMORY) + "MBEDTLS_PLATFORM_MEMORY", +#endif /* MBEDTLS_PLATFORM_MEMORY */ +#if defined(MBEDTLS_PLATFORM_NO_STD_FUNCTIONS) + "MBEDTLS_PLATFORM_NO_STD_FUNCTIONS", +#endif /* MBEDTLS_PLATFORM_NO_STD_FUNCTIONS */ +#if defined(MBEDTLS_PLATFORM_EXIT_ALT) + "MBEDTLS_PLATFORM_EXIT_ALT", +#endif /* MBEDTLS_PLATFORM_EXIT_ALT */ +#if defined(MBEDTLS_PLATFORM_TIME_ALT) + "MBEDTLS_PLATFORM_TIME_ALT", +#endif /* MBEDTLS_PLATFORM_TIME_ALT */ +#if defined(MBEDTLS_PLATFORM_FPRINTF_ALT) + "MBEDTLS_PLATFORM_FPRINTF_ALT", +#endif /* MBEDTLS_PLATFORM_FPRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_PRINTF_ALT) + "MBEDTLS_PLATFORM_PRINTF_ALT", +#endif /* MBEDTLS_PLATFORM_PRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_SNPRINTF_ALT) + "MBEDTLS_PLATFORM_SNPRINTF_ALT", +#endif /* MBEDTLS_PLATFORM_SNPRINTF_ALT */ +#if defined(MBEDTLS_PLATFORM_NV_SEED_ALT) + "MBEDTLS_PLATFORM_NV_SEED_ALT", +#endif /* MBEDTLS_PLATFORM_NV_SEED_ALT */ +#if defined(MBEDTLS_DEPRECATED_WARNING) + "MBEDTLS_DEPRECATED_WARNING", +#endif /* MBEDTLS_DEPRECATED_WARNING */ +#if defined(MBEDTLS_DEPRECATED_REMOVED) + "MBEDTLS_DEPRECATED_REMOVED", +#endif /* MBEDTLS_DEPRECATED_REMOVED */ +#if defined(MBEDTLS_TIMING_ALT) + "MBEDTLS_TIMING_ALT", +#endif /* MBEDTLS_TIMING_ALT */ +#if defined(MBEDTLS_AES_ALT) + "MBEDTLS_AES_ALT", +#endif /* MBEDTLS_AES_ALT */ +#if defined(MBEDTLS_ARC4_ALT) + "MBEDTLS_ARC4_ALT", +#endif /* MBEDTLS_ARC4_ALT */ +#if defined(MBEDTLS_BLOWFISH_ALT) + "MBEDTLS_BLOWFISH_ALT", +#endif /* MBEDTLS_BLOWFISH_ALT */ +#if defined(MBEDTLS_CAMELLIA_ALT) + "MBEDTLS_CAMELLIA_ALT", +#endif /* MBEDTLS_CAMELLIA_ALT */ +#if defined(MBEDTLS_DES_ALT) + "MBEDTLS_DES_ALT", +#endif /* MBEDTLS_DES_ALT */ +#if defined(MBEDTLS_XTEA_ALT) + "MBEDTLS_XTEA_ALT", +#endif /* MBEDTLS_XTEA_ALT */ +#if defined(MBEDTLS_MD2_ALT) + "MBEDTLS_MD2_ALT", +#endif /* MBEDTLS_MD2_ALT */ +#if defined(MBEDTLS_MD4_ALT) + "MBEDTLS_MD4_ALT", +#endif /* MBEDTLS_MD4_ALT */ +#if defined(MBEDTLS_MD5_ALT) + "MBEDTLS_MD5_ALT", +#endif /* MBEDTLS_MD5_ALT */ +#if defined(MBEDTLS_RIPEMD160_ALT) + "MBEDTLS_RIPEMD160_ALT", +#endif /* MBEDTLS_RIPEMD160_ALT */ +#if defined(MBEDTLS_SHA1_ALT) + "MBEDTLS_SHA1_ALT", +#endif /* MBEDTLS_SHA1_ALT */ +#if defined(MBEDTLS_SHA256_ALT) + "MBEDTLS_SHA256_ALT", +#endif /* MBEDTLS_SHA256_ALT */ +#if defined(MBEDTLS_SHA512_ALT) + "MBEDTLS_SHA512_ALT", +#endif /* MBEDTLS_SHA512_ALT */ +#if defined(MBEDTLS_MD2_PROCESS_ALT) + "MBEDTLS_MD2_PROCESS_ALT", +#endif /* MBEDTLS_MD2_PROCESS_ALT */ +#if defined(MBEDTLS_MD4_PROCESS_ALT) + "MBEDTLS_MD4_PROCESS_ALT", +#endif /* MBEDTLS_MD4_PROCESS_ALT */ +#if defined(MBEDTLS_MD5_PROCESS_ALT) + "MBEDTLS_MD5_PROCESS_ALT", +#endif /* MBEDTLS_MD5_PROCESS_ALT */ +#if defined(MBEDTLS_RIPEMD160_PROCESS_ALT) + "MBEDTLS_RIPEMD160_PROCESS_ALT", +#endif /* MBEDTLS_RIPEMD160_PROCESS_ALT */ +#if defined(MBEDTLS_SHA1_PROCESS_ALT) + "MBEDTLS_SHA1_PROCESS_ALT", +#endif /* MBEDTLS_SHA1_PROCESS_ALT */ +#if defined(MBEDTLS_SHA256_PROCESS_ALT) + "MBEDTLS_SHA256_PROCESS_ALT", +#endif /* MBEDTLS_SHA256_PROCESS_ALT */ +#if defined(MBEDTLS_SHA512_PROCESS_ALT) + "MBEDTLS_SHA512_PROCESS_ALT", +#endif /* MBEDTLS_SHA512_PROCESS_ALT */ +#if defined(MBEDTLS_DES_SETKEY_ALT) + "MBEDTLS_DES_SETKEY_ALT", +#endif /* MBEDTLS_DES_SETKEY_ALT */ +#if defined(MBEDTLS_DES_CRYPT_ECB_ALT) + "MBEDTLS_DES_CRYPT_ECB_ALT", +#endif /* MBEDTLS_DES_CRYPT_ECB_ALT */ +#if defined(MBEDTLS_DES3_CRYPT_ECB_ALT) + "MBEDTLS_DES3_CRYPT_ECB_ALT", +#endif /* MBEDTLS_DES3_CRYPT_ECB_ALT */ +#if defined(MBEDTLS_AES_SETKEY_ENC_ALT) + "MBEDTLS_AES_SETKEY_ENC_ALT", +#endif /* MBEDTLS_AES_SETKEY_ENC_ALT */ +#if defined(MBEDTLS_AES_SETKEY_DEC_ALT) + "MBEDTLS_AES_SETKEY_DEC_ALT", +#endif /* MBEDTLS_AES_SETKEY_DEC_ALT */ +#if defined(MBEDTLS_AES_ENCRYPT_ALT) + "MBEDTLS_AES_ENCRYPT_ALT", +#endif /* MBEDTLS_AES_ENCRYPT_ALT */ +#if defined(MBEDTLS_AES_DECRYPT_ALT) + "MBEDTLS_AES_DECRYPT_ALT", +#endif /* MBEDTLS_AES_DECRYPT_ALT */ +#if defined(MBEDTLS_TEST_NULL_ENTROPY) + "MBEDTLS_TEST_NULL_ENTROPY", +#endif /* MBEDTLS_TEST_NULL_ENTROPY */ +#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT) + "MBEDTLS_ENTROPY_HARDWARE_ALT", +#endif /* MBEDTLS_ENTROPY_HARDWARE_ALT */ +#if defined(MBEDTLS_AES_ROM_TABLES) + "MBEDTLS_AES_ROM_TABLES", +#endif /* MBEDTLS_AES_ROM_TABLES */ +#if defined(MBEDTLS_CAMELLIA_SMALL_MEMORY) + "MBEDTLS_CAMELLIA_SMALL_MEMORY", +#endif /* MBEDTLS_CAMELLIA_SMALL_MEMORY */ +#if defined(MBEDTLS_CIPHER_MODE_CBC) + "MBEDTLS_CIPHER_MODE_CBC", +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#if defined(MBEDTLS_CIPHER_MODE_CFB) + "MBEDTLS_CIPHER_MODE_CFB", +#endif /* MBEDTLS_CIPHER_MODE_CFB */ +#if defined(MBEDTLS_CIPHER_MODE_CTR) + "MBEDTLS_CIPHER_MODE_CTR", +#endif /* MBEDTLS_CIPHER_MODE_CTR */ +#if defined(MBEDTLS_CIPHER_NULL_CIPHER) + "MBEDTLS_CIPHER_NULL_CIPHER", +#endif /* MBEDTLS_CIPHER_NULL_CIPHER */ +#if defined(MBEDTLS_CIPHER_PADDING_PKCS7) + "MBEDTLS_CIPHER_PADDING_PKCS7", +#endif /* MBEDTLS_CIPHER_PADDING_PKCS7 */ +#if defined(MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS) + "MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS", +#endif /* MBEDTLS_CIPHER_PADDING_ONE_AND_ZEROS */ +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN) + "MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN", +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS_AND_LEN */ +#if defined(MBEDTLS_CIPHER_PADDING_ZEROS) + "MBEDTLS_CIPHER_PADDING_ZEROS", +#endif /* MBEDTLS_CIPHER_PADDING_ZEROS */ +#if defined(MBEDTLS_ENABLE_WEAK_CIPHERSUITES) + "MBEDTLS_ENABLE_WEAK_CIPHERSUITES", +#endif /* MBEDTLS_ENABLE_WEAK_CIPHERSUITES */ +#if defined(MBEDTLS_REMOVE_ARC4_CIPHERSUITES) + "MBEDTLS_REMOVE_ARC4_CIPHERSUITES", +#endif /* MBEDTLS_REMOVE_ARC4_CIPHERSUITES */ +#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) + "MBEDTLS_ECP_DP_SECP192R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) + "MBEDTLS_ECP_DP_SECP224R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) + "MBEDTLS_ECP_DP_SECP256R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) + "MBEDTLS_ECP_DP_SECP384R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) + "MBEDTLS_ECP_DP_SECP521R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP521R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) + "MBEDTLS_ECP_DP_SECP192K1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP192K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) + "MBEDTLS_ECP_DP_SECP224K1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP224K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) + "MBEDTLS_ECP_DP_SECP256K1_ENABLED", +#endif /* MBEDTLS_ECP_DP_SECP256K1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) + "MBEDTLS_ECP_DP_BP256R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_BP256R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) + "MBEDTLS_ECP_DP_BP384R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_BP384R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) + "MBEDTLS_ECP_DP_BP512R1_ENABLED", +#endif /* MBEDTLS_ECP_DP_BP512R1_ENABLED */ +#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) + "MBEDTLS_ECP_DP_CURVE25519_ENABLED", +#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ +#if defined(MBEDTLS_ECP_NIST_OPTIM) + "MBEDTLS_ECP_NIST_OPTIM", +#endif /* MBEDTLS_ECP_NIST_OPTIM */ +#if defined(MBEDTLS_ECDSA_DETERMINISTIC) + "MBEDTLS_ECDSA_DETERMINISTIC", +#endif /* MBEDTLS_ECDSA_DETERMINISTIC */ +#if defined(MBEDTLS_KEY_EXCHANGE_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED) + "MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_PSK_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_DHE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECDH_RSA_ENABLED */ +#if defined(MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED) + "MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED", +#endif /* MBEDTLS_KEY_EXCHANGE_ECJPAKE_ENABLED */ +#if defined(MBEDTLS_PK_PARSE_EC_EXTENDED) + "MBEDTLS_PK_PARSE_EC_EXTENDED", +#endif /* MBEDTLS_PK_PARSE_EC_EXTENDED */ +#if defined(MBEDTLS_ERROR_STRERROR_DUMMY) + "MBEDTLS_ERROR_STRERROR_DUMMY", +#endif /* MBEDTLS_ERROR_STRERROR_DUMMY */ +#if defined(MBEDTLS_GENPRIME) + "MBEDTLS_GENPRIME", +#endif /* MBEDTLS_GENPRIME */ +#if defined(MBEDTLS_FS_IO) + "MBEDTLS_FS_IO", +#endif /* MBEDTLS_FS_IO */ +#if defined(MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES) + "MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES", +#endif /* MBEDTLS_NO_DEFAULT_ENTROPY_SOURCES */ +#if defined(MBEDTLS_NO_PLATFORM_ENTROPY) + "MBEDTLS_NO_PLATFORM_ENTROPY", +#endif /* MBEDTLS_NO_PLATFORM_ENTROPY */ +#if defined(MBEDTLS_ENTROPY_FORCE_SHA256) + "MBEDTLS_ENTROPY_FORCE_SHA256", +#endif /* MBEDTLS_ENTROPY_FORCE_SHA256 */ +#if defined(MBEDTLS_ENTROPY_NV_SEED) + "MBEDTLS_ENTROPY_NV_SEED", +#endif /* MBEDTLS_ENTROPY_NV_SEED */ +#if defined(MBEDTLS_MEMORY_DEBUG) + "MBEDTLS_MEMORY_DEBUG", +#endif /* MBEDTLS_MEMORY_DEBUG */ +#if defined(MBEDTLS_MEMORY_BACKTRACE) + "MBEDTLS_MEMORY_BACKTRACE", +#endif /* MBEDTLS_MEMORY_BACKTRACE */ +#if defined(MBEDTLS_PK_RSA_ALT_SUPPORT) + "MBEDTLS_PK_RSA_ALT_SUPPORT", +#endif /* MBEDTLS_PK_RSA_ALT_SUPPORT */ +#if defined(MBEDTLS_PKCS1_V15) + "MBEDTLS_PKCS1_V15", +#endif /* MBEDTLS_PKCS1_V15 */ +#if defined(MBEDTLS_PKCS1_V21) + "MBEDTLS_PKCS1_V21", +#endif /* MBEDTLS_PKCS1_V21 */ +#if defined(MBEDTLS_RSA_NO_CRT) + "MBEDTLS_RSA_NO_CRT", +#endif /* MBEDTLS_RSA_NO_CRT */ +#if defined(MBEDTLS_SELF_TEST) + "MBEDTLS_SELF_TEST", +#endif /* MBEDTLS_SELF_TEST */ +#if defined(MBEDTLS_SHA256_SMALLER) + "MBEDTLS_SHA256_SMALLER", +#endif /* MBEDTLS_SHA256_SMALLER */ +#if defined(MBEDTLS_SSL_ALL_ALERT_MESSAGES) + "MBEDTLS_SSL_ALL_ALERT_MESSAGES", +#endif /* MBEDTLS_SSL_ALL_ALERT_MESSAGES */ +#if defined(MBEDTLS_SSL_DEBUG_ALL) + "MBEDTLS_SSL_DEBUG_ALL", +#endif /* MBEDTLS_SSL_DEBUG_ALL */ +#if defined(MBEDTLS_SSL_ENCRYPT_THEN_MAC) + "MBEDTLS_SSL_ENCRYPT_THEN_MAC", +#endif /* MBEDTLS_SSL_ENCRYPT_THEN_MAC */ +#if defined(MBEDTLS_SSL_EXTENDED_MASTER_SECRET) + "MBEDTLS_SSL_EXTENDED_MASTER_SECRET", +#endif /* MBEDTLS_SSL_EXTENDED_MASTER_SECRET */ +#if defined(MBEDTLS_SSL_FALLBACK_SCSV) + "MBEDTLS_SSL_FALLBACK_SCSV", +#endif /* MBEDTLS_SSL_FALLBACK_SCSV */ +#if defined(MBEDTLS_SSL_HW_RECORD_ACCEL) + "MBEDTLS_SSL_HW_RECORD_ACCEL", +#endif /* MBEDTLS_SSL_HW_RECORD_ACCEL */ +#if defined(MBEDTLS_SSL_CBC_RECORD_SPLITTING) + "MBEDTLS_SSL_CBC_RECORD_SPLITTING", +#endif /* MBEDTLS_SSL_CBC_RECORD_SPLITTING */ +#if defined(MBEDTLS_SSL_RENEGOTIATION) + "MBEDTLS_SSL_RENEGOTIATION", +#endif /* MBEDTLS_SSL_RENEGOTIATION */ +#if defined(MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO) + "MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO", +#endif /* MBEDTLS_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO */ +#if defined(MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE) + "MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE", +#endif /* MBEDTLS_SSL_SRV_RESPECT_CLIENT_PREFERENCE */ +#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH) + "MBEDTLS_SSL_MAX_FRAGMENT_LENGTH", +#endif /* MBEDTLS_SSL_MAX_FRAGMENT_LENGTH */ +#if defined(MBEDTLS_SSL_PROTO_SSL3) + "MBEDTLS_SSL_PROTO_SSL3", +#endif /* MBEDTLS_SSL_PROTO_SSL3 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1) + "MBEDTLS_SSL_PROTO_TLS1", +#endif /* MBEDTLS_SSL_PROTO_TLS1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_1) + "MBEDTLS_SSL_PROTO_TLS1_1", +#endif /* MBEDTLS_SSL_PROTO_TLS1_1 */ +#if defined(MBEDTLS_SSL_PROTO_TLS1_2) + "MBEDTLS_SSL_PROTO_TLS1_2", +#endif /* MBEDTLS_SSL_PROTO_TLS1_2 */ +#if defined(MBEDTLS_SSL_PROTO_DTLS) + "MBEDTLS_SSL_PROTO_DTLS", +#endif /* MBEDTLS_SSL_PROTO_DTLS */ +#if defined(MBEDTLS_SSL_ALPN) + "MBEDTLS_SSL_ALPN", +#endif /* MBEDTLS_SSL_ALPN */ +#if defined(MBEDTLS_SSL_DTLS_ANTI_REPLAY) + "MBEDTLS_SSL_DTLS_ANTI_REPLAY", +#endif /* MBEDTLS_SSL_DTLS_ANTI_REPLAY */ +#if defined(MBEDTLS_SSL_DTLS_HELLO_VERIFY) + "MBEDTLS_SSL_DTLS_HELLO_VERIFY", +#endif /* MBEDTLS_SSL_DTLS_HELLO_VERIFY */ +#if defined(MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE) + "MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE", +#endif /* MBEDTLS_SSL_DTLS_CLIENT_PORT_REUSE */ +#if defined(MBEDTLS_SSL_DTLS_BADMAC_LIMIT) + "MBEDTLS_SSL_DTLS_BADMAC_LIMIT", +#endif /* MBEDTLS_SSL_DTLS_BADMAC_LIMIT */ +#if defined(MBEDTLS_SSL_SESSION_TICKETS) + "MBEDTLS_SSL_SESSION_TICKETS", +#endif /* MBEDTLS_SSL_SESSION_TICKETS */ +#if defined(MBEDTLS_SSL_EXPORT_KEYS) + "MBEDTLS_SSL_EXPORT_KEYS", +#endif /* MBEDTLS_SSL_EXPORT_KEYS */ +#if defined(MBEDTLS_SSL_SERVER_NAME_INDICATION) + "MBEDTLS_SSL_SERVER_NAME_INDICATION", +#endif /* MBEDTLS_SSL_SERVER_NAME_INDICATION */ +#if defined(MBEDTLS_SSL_TRUNCATED_HMAC) + "MBEDTLS_SSL_TRUNCATED_HMAC", +#endif /* MBEDTLS_SSL_TRUNCATED_HMAC */ +#if defined(MBEDTLS_THREADING_ALT) + "MBEDTLS_THREADING_ALT", +#endif /* MBEDTLS_THREADING_ALT */ +#if defined(MBEDTLS_THREADING_PTHREAD) + "MBEDTLS_THREADING_PTHREAD", +#endif /* MBEDTLS_THREADING_PTHREAD */ +#if defined(MBEDTLS_VERSION_FEATURES) + "MBEDTLS_VERSION_FEATURES", +#endif /* MBEDTLS_VERSION_FEATURES */ +#if defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) + "MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3", +#endif /* MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3 */ +#if defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + "MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION", +#endif /* MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION */ +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + "MBEDTLS_X509_CHECK_KEY_USAGE", +#endif /* MBEDTLS_X509_CHECK_KEY_USAGE */ +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) + "MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE", +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + "MBEDTLS_X509_RSASSA_PSS_SUPPORT", +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ +#if defined(MBEDTLS_ZLIB_SUPPORT) + "MBEDTLS_ZLIB_SUPPORT", +#endif /* MBEDTLS_ZLIB_SUPPORT */ +#if defined(MBEDTLS_AESNI_C) + "MBEDTLS_AESNI_C", +#endif /* MBEDTLS_AESNI_C */ +#if defined(MBEDTLS_AES_C) + "MBEDTLS_AES_C", +#endif /* MBEDTLS_AES_C */ +#if defined(MBEDTLS_ARC4_C) + "MBEDTLS_ARC4_C", +#endif /* MBEDTLS_ARC4_C */ +#if defined(MBEDTLS_ASN1_PARSE_C) + "MBEDTLS_ASN1_PARSE_C", +#endif /* MBEDTLS_ASN1_PARSE_C */ +#if defined(MBEDTLS_ASN1_WRITE_C) + "MBEDTLS_ASN1_WRITE_C", +#endif /* MBEDTLS_ASN1_WRITE_C */ +#if defined(MBEDTLS_BASE64_C) + "MBEDTLS_BASE64_C", +#endif /* MBEDTLS_BASE64_C */ +#if defined(MBEDTLS_BIGNUM_C) + "MBEDTLS_BIGNUM_C", +#endif /* MBEDTLS_BIGNUM_C */ +#if defined(MBEDTLS_BLOWFISH_C) + "MBEDTLS_BLOWFISH_C", +#endif /* MBEDTLS_BLOWFISH_C */ +#if defined(MBEDTLS_CAMELLIA_C) + "MBEDTLS_CAMELLIA_C", +#endif /* MBEDTLS_CAMELLIA_C */ +#if defined(MBEDTLS_CCM_C) + "MBEDTLS_CCM_C", +#endif /* MBEDTLS_CCM_C */ +#if defined(MBEDTLS_CERTS_C) + "MBEDTLS_CERTS_C", +#endif /* MBEDTLS_CERTS_C */ +#if defined(MBEDTLS_CIPHER_C) + "MBEDTLS_CIPHER_C", +#endif /* MBEDTLS_CIPHER_C */ +#if defined(MBEDTLS_CMAC_C) + "MBEDTLS_CMAC_C", +#endif /* MBEDTLS_CMAC_C */ +#if defined(MBEDTLS_CTR_DRBG_C) + "MBEDTLS_CTR_DRBG_C", +#endif /* MBEDTLS_CTR_DRBG_C */ +#if defined(MBEDTLS_DEBUG_C) + "MBEDTLS_DEBUG_C", +#endif /* MBEDTLS_DEBUG_C */ +#if defined(MBEDTLS_DES_C) + "MBEDTLS_DES_C", +#endif /* MBEDTLS_DES_C */ +#if defined(MBEDTLS_DHM_C) + "MBEDTLS_DHM_C", +#endif /* MBEDTLS_DHM_C */ +#if defined(MBEDTLS_ECDH_C) + "MBEDTLS_ECDH_C", +#endif /* MBEDTLS_ECDH_C */ +#if defined(MBEDTLS_ECDSA_C) + "MBEDTLS_ECDSA_C", +#endif /* MBEDTLS_ECDSA_C */ +#if defined(MBEDTLS_ECJPAKE_C) + "MBEDTLS_ECJPAKE_C", +#endif /* MBEDTLS_ECJPAKE_C */ +#if defined(MBEDTLS_ECP_C) + "MBEDTLS_ECP_C", +#endif /* MBEDTLS_ECP_C */ +#if defined(MBEDTLS_ENTROPY_C) + "MBEDTLS_ENTROPY_C", +#endif /* MBEDTLS_ENTROPY_C */ +#if defined(MBEDTLS_ERROR_C) + "MBEDTLS_ERROR_C", +#endif /* MBEDTLS_ERROR_C */ +#if defined(MBEDTLS_GCM_C) + "MBEDTLS_GCM_C", +#endif /* MBEDTLS_GCM_C */ +#if defined(MBEDTLS_HAVEGE_C) + "MBEDTLS_HAVEGE_C", +#endif /* MBEDTLS_HAVEGE_C */ +#if defined(MBEDTLS_HMAC_DRBG_C) + "MBEDTLS_HMAC_DRBG_C", +#endif /* MBEDTLS_HMAC_DRBG_C */ +#if defined(MBEDTLS_MD_C) + "MBEDTLS_MD_C", +#endif /* MBEDTLS_MD_C */ +#if defined(MBEDTLS_MD2_C) + "MBEDTLS_MD2_C", +#endif /* MBEDTLS_MD2_C */ +#if defined(MBEDTLS_MD4_C) + "MBEDTLS_MD4_C", +#endif /* MBEDTLS_MD4_C */ +#if defined(MBEDTLS_MD5_C) + "MBEDTLS_MD5_C", +#endif /* MBEDTLS_MD5_C */ +#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C) + "MBEDTLS_MEMORY_BUFFER_ALLOC_C", +#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */ +#if defined(MBEDTLS_NET_C) + "MBEDTLS_NET_C", +#endif /* MBEDTLS_NET_C */ +#if defined(MBEDTLS_OID_C) + "MBEDTLS_OID_C", +#endif /* MBEDTLS_OID_C */ +#if defined(MBEDTLS_PADLOCK_C) + "MBEDTLS_PADLOCK_C", +#endif /* MBEDTLS_PADLOCK_C */ +#if defined(MBEDTLS_PEM_PARSE_C) + "MBEDTLS_PEM_PARSE_C", +#endif /* MBEDTLS_PEM_PARSE_C */ +#if defined(MBEDTLS_PEM_WRITE_C) + "MBEDTLS_PEM_WRITE_C", +#endif /* MBEDTLS_PEM_WRITE_C */ +#if defined(MBEDTLS_PK_C) + "MBEDTLS_PK_C", +#endif /* MBEDTLS_PK_C */ +#if defined(MBEDTLS_PK_PARSE_C) + "MBEDTLS_PK_PARSE_C", +#endif /* MBEDTLS_PK_PARSE_C */ +#if defined(MBEDTLS_PK_WRITE_C) + "MBEDTLS_PK_WRITE_C", +#endif /* MBEDTLS_PK_WRITE_C */ +#if defined(MBEDTLS_PKCS5_C) + "MBEDTLS_PKCS5_C", +#endif /* MBEDTLS_PKCS5_C */ +#if defined(MBEDTLS_PKCS11_C) + "MBEDTLS_PKCS11_C", +#endif /* MBEDTLS_PKCS11_C */ +#if defined(MBEDTLS_PKCS12_C) + "MBEDTLS_PKCS12_C", +#endif /* MBEDTLS_PKCS12_C */ +#if defined(MBEDTLS_PLATFORM_C) + "MBEDTLS_PLATFORM_C", +#endif /* MBEDTLS_PLATFORM_C */ +#if defined(MBEDTLS_RIPEMD160_C) + "MBEDTLS_RIPEMD160_C", +#endif /* MBEDTLS_RIPEMD160_C */ +#if defined(MBEDTLS_RSA_C) + "MBEDTLS_RSA_C", +#endif /* MBEDTLS_RSA_C */ +#if defined(MBEDTLS_SHA1_C) + "MBEDTLS_SHA1_C", +#endif /* MBEDTLS_SHA1_C */ +#if defined(MBEDTLS_SHA256_C) + "MBEDTLS_SHA256_C", +#endif /* MBEDTLS_SHA256_C */ +#if defined(MBEDTLS_SHA512_C) + "MBEDTLS_SHA512_C", +#endif /* MBEDTLS_SHA512_C */ +#if defined(MBEDTLS_SSL_CACHE_C) + "MBEDTLS_SSL_CACHE_C", +#endif /* MBEDTLS_SSL_CACHE_C */ +#if defined(MBEDTLS_SSL_COOKIE_C) + "MBEDTLS_SSL_COOKIE_C", +#endif /* MBEDTLS_SSL_COOKIE_C */ +#if defined(MBEDTLS_SSL_TICKET_C) + "MBEDTLS_SSL_TICKET_C", +#endif /* MBEDTLS_SSL_TICKET_C */ +#if defined(MBEDTLS_SSL_CLI_C) + "MBEDTLS_SSL_CLI_C", +#endif /* MBEDTLS_SSL_CLI_C */ +#if defined(MBEDTLS_SSL_SRV_C) + "MBEDTLS_SSL_SRV_C", +#endif /* MBEDTLS_SSL_SRV_C */ +#if defined(MBEDTLS_SSL_TLS_C) + "MBEDTLS_SSL_TLS_C", +#endif /* MBEDTLS_SSL_TLS_C */ +#if defined(MBEDTLS_THREADING_C) + "MBEDTLS_THREADING_C", +#endif /* MBEDTLS_THREADING_C */ +#if defined(MBEDTLS_TIMING_C) + "MBEDTLS_TIMING_C", +#endif /* MBEDTLS_TIMING_C */ +#if defined(MBEDTLS_VERSION_C) + "MBEDTLS_VERSION_C", +#endif /* MBEDTLS_VERSION_C */ +#if defined(MBEDTLS_X509_USE_C) + "MBEDTLS_X509_USE_C", +#endif /* MBEDTLS_X509_USE_C */ +#if defined(MBEDTLS_X509_CRT_PARSE_C) + "MBEDTLS_X509_CRT_PARSE_C", +#endif /* MBEDTLS_X509_CRT_PARSE_C */ +#if defined(MBEDTLS_X509_CRL_PARSE_C) + "MBEDTLS_X509_CRL_PARSE_C", +#endif /* MBEDTLS_X509_CRL_PARSE_C */ +#if defined(MBEDTLS_X509_CSR_PARSE_C) + "MBEDTLS_X509_CSR_PARSE_C", +#endif /* MBEDTLS_X509_CSR_PARSE_C */ +#if defined(MBEDTLS_X509_CREATE_C) + "MBEDTLS_X509_CREATE_C", +#endif /* MBEDTLS_X509_CREATE_C */ +#if defined(MBEDTLS_X509_CRT_WRITE_C) + "MBEDTLS_X509_CRT_WRITE_C", +#endif /* MBEDTLS_X509_CRT_WRITE_C */ +#if defined(MBEDTLS_X509_CSR_WRITE_C) + "MBEDTLS_X509_CSR_WRITE_C", +#endif /* MBEDTLS_X509_CSR_WRITE_C */ +#if defined(MBEDTLS_XTEA_C) + "MBEDTLS_XTEA_C", +#endif /* MBEDTLS_XTEA_C */ +#endif /* MBEDTLS_VERSION_FEATURES */ + NULL +}; + +int mbedtls_version_check_feature( const char *feature ) +{ + const char **idx = features; + + if( *idx == NULL ) + return( -2 ); + + if( feature == NULL ) + return( -1 ); + + while( *idx != NULL ) + { + if( !strcmp( *idx, feature ) ) + return( 0 ); + idx++; + } + return( -1 ); +} + +#endif /* MBEDTLS_VERSION_C */ + diff --git a/c++/src/connect/mbedtls/x509.c b/c++/src/connect/mbedtls/x509.c new file mode 100644 index 00000000..e4387707 --- /dev/null +++ b/c++/src/connect/mbedtls/x509.c @@ -0,0 +1,1098 @@ +/* + * X.509 common functions for parsing and verification + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_USE_C) + +#include "mbedtls/x509.h" +#include "mbedtls/asn1.h" +#include "mbedtls/oid.h" + +#include +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_printf printf +#define mbedtls_snprintf snprintf +#endif + + +#if defined(MBEDTLS_HAVE_TIME) +#include "mbedtls/platform_time.h" +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +#include +#else +#include +#endif + +#if defined(MBEDTLS_FS_IO) +#include +#if !defined(_WIN32) +#include +#include +#include +#endif +#endif + +#define CHECK(code) if( ( ret = code ) != 0 ){ return( ret ); } +#define CHECK_RANGE(min, max, val) if( val < min || val > max ){ return( ret ); } + +/* + * CertificateSerialNumber ::= INTEGER + */ +int mbedtls_x509_get_serial( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *serial ) +{ + int ret; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_PRIMITIVE | 2 ) && + **p != MBEDTLS_ASN1_INTEGER ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + serial->tag = *(*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, &serial->len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_SERIAL + ret ); + + serial->p = *p; + *p += serial->len; + + return( 0 ); +} + +/* Get an algorithm identifier without parameters (eg for signatures) + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + */ +int mbedtls_x509_get_alg_null( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_alg_null( p, end, alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + return( 0 ); +} + +/* + * Parse an algorithm identifier with (optional) paramaters + */ +int mbedtls_x509_get_alg( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *alg, mbedtls_x509_buf *params ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_alg( p, end, alg, params ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + return( 0 ); +} + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) +/* + * HashAlgorithm ::= AlgorithmIdentifier + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL } + * + * For HashAlgorithm, parameters MUST be NULL or absent. + */ +static int x509_get_hash_alg( const mbedtls_x509_buf *alg, mbedtls_md_type_t *md_alg ) +{ + int ret; + unsigned char *p; + const unsigned char *end; + mbedtls_x509_buf md_oid; + size_t len; + + /* Make sure we got a SEQUENCE and setup bounds */ + if( alg->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + p = (unsigned char *) alg->p; + end = p + alg->len; + + if( p >= end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + /* Parse md_oid */ + md_oid.tag = *p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &md_oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + md_oid.p = p; + p += md_oid.len; + + /* Get md_alg from md_oid */ + if( ( ret = mbedtls_oid_get_md_alg( &md_oid, md_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + /* Make sure params is absent of NULL */ + if( p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, MBEDTLS_ASN1_NULL ) ) != 0 || len != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * RSASSA-PSS-params ::= SEQUENCE { + * hashAlgorithm [0] HashAlgorithm DEFAULT sha1Identifier, + * maskGenAlgorithm [1] MaskGenAlgorithm DEFAULT mgf1SHA1Identifier, + * saltLength [2] INTEGER DEFAULT 20, + * trailerField [3] INTEGER DEFAULT 1 } + * -- Note that the tags in this Sequence are explicit. + * + * RFC 4055 (which defines use of RSASSA-PSS in PKIX) states that the value + * of trailerField MUST be 1, and PKCS#1 v2.2 doesn't even define any other + * option. Enfore this at parsing time. + */ +int mbedtls_x509_get_rsassa_pss_params( const mbedtls_x509_buf *params, + mbedtls_md_type_t *md_alg, mbedtls_md_type_t *mgf_md, + int *salt_len ) +{ + int ret; + unsigned char *p; + const unsigned char *end, *end2; + size_t len; + mbedtls_x509_buf alg_id, alg_params; + + /* First set everything to defaults */ + *md_alg = MBEDTLS_MD_SHA1; + *mgf_md = MBEDTLS_MD_SHA1; + *salt_len = 20; + + /* Make sure params is a SEQUENCE and setup bounds */ + if( params->tag != ( MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + p = (unsigned char *) params->p; + end = p + params->len; + + if( p == end ) + return( 0 ); + + /* + * HashAlgorithm + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) == 0 ) + { + end2 = p + len; + + /* HashAlgorithm ::= AlgorithmIdentifier (without parameters) */ + if( ( ret = mbedtls_x509_get_alg_null( &p, end2, &alg_id ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_oid_get_md_alg( &alg_id, md_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * MaskGenAlgorithm + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1 ) ) == 0 ) + { + end2 = p + len; + + /* MaskGenAlgorithm ::= AlgorithmIdentifier (params = HashAlgorithm) */ + if( ( ret = mbedtls_x509_get_alg( &p, end2, &alg_id, &alg_params ) ) != 0 ) + return( ret ); + + /* Only MFG1 is recognised for now */ + if( MBEDTLS_OID_CMP( MBEDTLS_OID_MGF1, &alg_id ) != 0 ) + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE + + MBEDTLS_ERR_OID_NOT_FOUND ); + + /* Parse HashAlgorithm */ + if( ( ret = x509_get_hash_alg( &alg_params, mgf_md ) ) != 0 ) + return( ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * salt_len + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2 ) ) == 0 ) + { + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end2, salt_len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p == end ) + return( 0 ); + + /* + * trailer_field (if present, must be 1) + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 3 ) ) == 0 ) + { + int trailer_field; + + end2 = p + len; + + if( ( ret = mbedtls_asn1_get_int( &p, end2, &trailer_field ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end2 ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + if( trailer_field != 1 ) + return( MBEDTLS_ERR_X509_INVALID_ALG ); + } + else if( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( MBEDTLS_ERR_X509_INVALID_ALG + ret ); + + if( p != end ) + return( MBEDTLS_ERR_X509_INVALID_ALG + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + +/* + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +static int x509_get_attr_type_value( unsigned char **p, + const unsigned char *end, + mbedtls_x509_name *cur ) +{ + int ret; + size_t len; + mbedtls_x509_buf *oid; + mbedtls_x509_buf *val; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + oid = &cur->oid; + oid->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &oid->len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + oid->p = *p; + *p += oid->len; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + if( **p != MBEDTLS_ASN1_BMP_STRING && **p != MBEDTLS_ASN1_UTF8_STRING && + **p != MBEDTLS_ASN1_T61_STRING && **p != MBEDTLS_ASN1_PRINTABLE_STRING && + **p != MBEDTLS_ASN1_IA5_STRING && **p != MBEDTLS_ASN1_UNIVERSAL_STRING && + **p != MBEDTLS_ASN1_BIT_STRING ) + return( MBEDTLS_ERR_X509_INVALID_NAME + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + val = &cur->val; + val->tag = *(*p)++; + + if( ( ret = mbedtls_asn1_get_len( p, end, &val->len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + val->p = *p; + *p += val->len; + + cur->next = NULL; + + return( 0 ); +} + +/* + * Name ::= CHOICE { -- only one possibility for now -- + * rdnSequence RDNSequence } + * + * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName + * + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + * + * The data structure is optimized for the common case where each RDN has only + * one element, which is represented as a list of AttributeTypeAndValue. + * For the general case we still use a flat list, but we mark elements of the + * same set so that they are "merged" together in the functions that consume + * this list, eg mbedtls_x509_dn_gets(). + */ +int mbedtls_x509_get_name( unsigned char **p, const unsigned char *end, + mbedtls_x509_name *cur ) +{ + int ret; + size_t set_len; + const unsigned char *end_set; + + /* don't use recursion, we'd risk stack overflow if not optimized */ + while( 1 ) + { + /* + * parse SET + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &set_len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SET ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_NAME + ret ); + + end_set = *p + set_len; + + while( 1 ) + { + if( ( ret = x509_get_attr_type_value( p, end_set, cur ) ) != 0 ) + return( ret ); + + if( *p == end_set ) + break; + + /* Mark this item as being no the only one in a set */ + cur->next_merged = 1; + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur = cur->next; + } + + /* + * continue until end of SEQUENCE is reached + */ + if( *p == end ) + return( 0 ); + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_name ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur = cur->next; + } +} + +static int x509_parse_int( unsigned char **p, size_t n, int *res ) +{ + *res = 0; + + for( ; n > 0; --n ) + { + if( ( **p < '0') || ( **p > '9' ) ) + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + + *res *= 10; + *res += ( *(*p)++ - '0' ); + } + + return( 0 ); +} + +static int x509_date_is_valid(const mbedtls_x509_time *time) +{ + int ret = MBEDTLS_ERR_X509_INVALID_DATE; + + CHECK_RANGE( 0, 9999, time->year ); + CHECK_RANGE( 0, 23, time->hour ); + CHECK_RANGE( 0, 59, time->min ); + CHECK_RANGE( 0, 59, time->sec ); + + switch( time->mon ) + { + case 1: case 3: case 5: case 7: case 8: case 10: case 12: + CHECK_RANGE( 1, 31, time->day ); + break; + case 4: case 6: case 9: case 11: + CHECK_RANGE( 1, 30, time->day ); + break; + case 2: + CHECK_RANGE( 1, 28 + (time->year % 4 == 0), time->day ); + break; + default: + return( ret ); + } + + return( 0 ); +} + +/* + * Parse an ASN1_UTC_TIME (yearlen=2) or ASN1_GENERALIZED_TIME (yearlen=4) + * field. + */ +static int x509_parse_time( unsigned char **p, size_t len, size_t yearlen, + mbedtls_x509_time *time ) +{ + int ret; + + /* + * Minimum length is 10 or 12 depending on yearlen + */ + if ( len < yearlen + 8 ) + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + len -= yearlen + 8; + + /* + * Parse year, month, day, hour, minute + */ + CHECK( x509_parse_int( p, yearlen, &time->year ) ); + if ( 2 == yearlen ) + { + if ( time->year < 50 ) + time->year += 100; + + time->year += 1900; + } + + CHECK( x509_parse_int( p, 2, &time->mon ) ); + CHECK( x509_parse_int( p, 2, &time->day ) ); + CHECK( x509_parse_int( p, 2, &time->hour ) ); + CHECK( x509_parse_int( p, 2, &time->min ) ); + + /* + * Parse seconds if present + */ + if ( len >= 2 ) + { + CHECK( x509_parse_int( p, 2, &time->sec ) ); + len -= 2; + } + else + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + + /* + * Parse trailing 'Z' if present + */ + if ( 1 == len && 'Z' == **p ) + { + (*p)++; + len--; + } + + /* + * We should have parsed all characters at this point + */ + if ( 0 != len ) + return ( MBEDTLS_ERR_X509_INVALID_DATE ); + + CHECK( x509_date_is_valid( time ) ); + + return ( 0 ); +} + +/* + * Time ::= CHOICE { + * utcTime UTCTime, + * generalTime GeneralizedTime } + */ +int mbedtls_x509_get_time( unsigned char **p, const unsigned char *end, + mbedtls_x509_time *time ) +{ + int ret; + size_t len, year_len; + unsigned char tag; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + tag = **p; + + if( tag == MBEDTLS_ASN1_UTC_TIME ) + year_len = 2; + else if( tag == MBEDTLS_ASN1_GENERALIZED_TIME ) + year_len = 4; + else + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + (*p)++; + ret = mbedtls_asn1_get_len( p, end, &len ); + + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); + + return x509_parse_time( p, len, year_len, time ); +} + +int mbedtls_x509_get_sig( unsigned char **p, const unsigned char *end, mbedtls_x509_buf *sig ) +{ + int ret; + size_t len; + int tag_type; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + tag_type = **p; + + if( ( ret = mbedtls_asn1_get_bitstring_null( p, end, &len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_SIGNATURE + ret ); + + sig->tag = tag_type; + sig->len = len; + sig->p = *p; + + *p += len; + + return( 0 ); +} + +/* + * Get signature algorithm from alg OID and optional parameters + */ +int mbedtls_x509_get_sig_alg( const mbedtls_x509_buf *sig_oid, const mbedtls_x509_buf *sig_params, + mbedtls_md_type_t *md_alg, mbedtls_pk_type_t *pk_alg, + void **sig_opts ) +{ + int ret; + + if( *sig_opts != NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + if( ( ret = mbedtls_oid_get_sig_alg( sig_oid, md_alg, pk_alg ) ) != 0 ) + return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG + ret ); + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + if( *pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + mbedtls_pk_rsassa_pss_options *pss_opts; + + pss_opts = mbedtls_calloc( 1, sizeof( mbedtls_pk_rsassa_pss_options ) ); + if( pss_opts == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + ret = mbedtls_x509_get_rsassa_pss_params( sig_params, + md_alg, + &pss_opts->mgf1_hash_id, + &pss_opts->expected_salt_len ); + if( ret != 0 ) + { + mbedtls_free( pss_opts ); + return( ret ); + } + + *sig_opts = (void *) pss_opts; + } + else +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + { + /* Make sure parameters are absent or NULL */ + if( ( sig_params->tag != MBEDTLS_ASN1_NULL && sig_params->tag != 0 ) || + sig_params->len != 0 ) + return( MBEDTLS_ERR_X509_INVALID_ALG ); + } + + return( 0 ); +} + +/* + * X.509 Extensions (No parsing of extensions, pointer should + * be either manually updated or extensions should be parsed!) + */ +int mbedtls_x509_get_ext( unsigned char **p, const unsigned char *end, + mbedtls_x509_buf *ext, int tag ) +{ + int ret; + size_t len; + + if( *p == end ) + return( 0 ); + + ext->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &ext->len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | tag ) ) != 0 ) + return( ret ); + + ext->p = *p; + end = *p + ext->len; + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + * + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( end != *p + len ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Store the name in printable form into buf; no more + * than size characters will be written + */ +int mbedtls_x509_dn_gets( char *buf, size_t size, const mbedtls_x509_name *dn ) +{ + int ret; + size_t i, n; + unsigned char c, merge = 0; + const mbedtls_x509_name *name; + const char *short_name = NULL; + char s[MBEDTLS_X509_MAX_DN_NAME_SIZE], *p; + + memset( s, 0, sizeof( s ) ); + + name = dn; + p = buf; + n = size; + + while( name != NULL ) + { + if( !name->oid.p ) + { + name = name->next; + continue; + } + + if( name != dn ) + { + ret = mbedtls_snprintf( p, n, merge ? " + " : ", " ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + ret = mbedtls_oid_get_attr_short_name( &name->oid, &short_name ); + + if( ret == 0 ) + ret = mbedtls_snprintf( p, n, "%s=", short_name ); + else + ret = mbedtls_snprintf( p, n, "\?\?=" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + for( i = 0; i < name->val.len; i++ ) + { + if( i >= sizeof( s ) - 1 ) + break; + + c = name->val.p[i]; + if( c < 32 || c == 127 || ( c > 128 && c < 160 ) ) + s[i] = '?'; + else s[i] = c; + } + s[i] = '\0'; + ret = mbedtls_snprintf( p, n, "%s", s ); + MBEDTLS_X509_SAFE_SNPRINTF; + + merge = name->next_merged; + name = name->next; + } + + return( (int) ( size - n ) ); +} + +/* + * Store the serial in printable form into buf; no more + * than size characters will be written + */ +int mbedtls_x509_serial_gets( char *buf, size_t size, const mbedtls_x509_buf *serial ) +{ + int ret; + size_t i, n, nr; + char *p; + + p = buf; + n = size; + + nr = ( serial->len <= 32 ) + ? serial->len : 28; + + for( i = 0; i < nr; i++ ) + { + if( i == 0 && nr > 1 && serial->p[i] == 0x0 ) + continue; + + ret = mbedtls_snprintf( p, n, "%02X%s", + serial->p[i], ( i < nr - 1 ) ? ":" : "" ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + if( nr != serial->len ) + { + ret = mbedtls_snprintf( p, n, "...." ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + return( (int) ( size - n ) ); +} + +/* + * Helper for writing signature algorithms + */ +int mbedtls_x509_sig_alg_gets( char *buf, size_t size, const mbedtls_x509_buf *sig_oid, + mbedtls_pk_type_t pk_alg, mbedtls_md_type_t md_alg, + const void *sig_opts ) +{ + int ret; + char *p = buf; + size_t n = size; + const char *desc = NULL; + + ret = mbedtls_oid_get_sig_alg_desc( sig_oid, &desc ); + if( ret != 0 ) + ret = mbedtls_snprintf( p, n, "???" ); + else + ret = mbedtls_snprintf( p, n, "%s", desc ); + MBEDTLS_X509_SAFE_SNPRINTF; + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + if( pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + const mbedtls_pk_rsassa_pss_options *pss_opts; + const mbedtls_md_info_t *md_info, *mgf_md_info; + + pss_opts = (const mbedtls_pk_rsassa_pss_options *) sig_opts; + + md_info = mbedtls_md_info_from_type( md_alg ); + mgf_md_info = mbedtls_md_info_from_type( pss_opts->mgf1_hash_id ); + + ret = mbedtls_snprintf( p, n, " (%s, MGF1-%s, 0x%02X)", + md_info ? mbedtls_md_get_name( md_info ) : "???", + mgf_md_info ? mbedtls_md_get_name( mgf_md_info ) : "???", + pss_opts->expected_salt_len ); + MBEDTLS_X509_SAFE_SNPRINTF; + } +#else + ((void) pk_alg); + ((void) md_alg); + ((void) sig_opts); +#endif /* MBEDTLS_X509_RSASSA_PSS_SUPPORT */ + + return( (int)( size - n ) ); +} + +/* + * Helper for writing "RSA key size", "EC key size", etc + */ +int mbedtls_x509_key_size_helper( char *buf, size_t buf_size, const char *name ) +{ + char *p = buf; + size_t n = buf_size; + int ret; + + ret = mbedtls_snprintf( p, n, "%s key size", name ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( 0 ); +} + +#if defined(MBEDTLS_HAVE_TIME_DATE) +/* + * Set the time structure to the current time. + * Return 0 on success, non-zero on failure. + */ +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +static int x509_get_current_time( mbedtls_x509_time *now ) +{ + SYSTEMTIME st; + + GetSystemTime( &st ); + + now->year = st.wYear; + now->mon = st.wMonth; + now->day = st.wDay; + now->hour = st.wHour; + now->min = st.wMinute; + now->sec = st.wSecond; + + return( 0 ); +} +#else +static int x509_get_current_time( mbedtls_x509_time *now ) +{ + struct tm *lt; + mbedtls_time_t tt; + int ret = 0; + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_lock( &mbedtls_threading_gmtime_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + tt = mbedtls_time( NULL ); + lt = gmtime( &tt ); + + if( lt == NULL ) + ret = -1; + else + { + now->year = lt->tm_year + 1900; + now->mon = lt->tm_mon + 1; + now->day = lt->tm_mday; + now->hour = lt->tm_hour; + now->min = lt->tm_min; + now->sec = lt->tm_sec; + } + +#if defined(MBEDTLS_THREADING_C) + if( mbedtls_mutex_unlock( &mbedtls_threading_gmtime_mutex ) != 0 ) + return( MBEDTLS_ERR_THREADING_MUTEX_ERROR ); +#endif + + return( ret ); +} +#endif /* _WIN32 && !EFIX64 && !EFI32 */ + +/* + * Return 0 if before <= after, 1 otherwise + */ +static int x509_check_time( const mbedtls_x509_time *before, const mbedtls_x509_time *after ) +{ + if( before->year > after->year ) + return( 1 ); + + if( before->year == after->year && + before->mon > after->mon ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day > after->day ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour > after->hour ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour == after->hour && + before->min > after->min ) + return( 1 ); + + if( before->year == after->year && + before->mon == after->mon && + before->day == after->day && + before->hour == after->hour && + before->min == after->min && + before->sec > after->sec ) + return( 1 ); + + return( 0 ); +} + +int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ) +{ + mbedtls_x509_time now; + + if( x509_get_current_time( &now ) != 0 ) + return( 1 ); + + return( x509_check_time( &now, to ) ); +} + +int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) +{ + mbedtls_x509_time now; + + if( x509_get_current_time( &now ) != 0 ) + return( 1 ); + + return( x509_check_time( from, &now ) ); +} + +#else /* MBEDTLS_HAVE_TIME_DATE */ + +int mbedtls_x509_time_is_past( const mbedtls_x509_time *to ) +{ + ((void) to); + return( 0 ); +} + +int mbedtls_x509_time_is_future( const mbedtls_x509_time *from ) +{ + ((void) from); + return( 0 ); +} +#endif /* MBEDTLS_HAVE_TIME_DATE */ + +#if defined(MBEDTLS_SELF_TEST) + +#include "mbedtls/x509_crt.h" +#include "mbedtls/certs.h" + +/* + * Checkup routine + */ +int mbedtls_x509_self_test( int verbose ) +{ +#if defined(MBEDTLS_CERTS_C) && defined(MBEDTLS_SHA1_C) + int ret; + uint32_t flags; + mbedtls_x509_crt cacert; + mbedtls_x509_crt clicert; + + if( verbose != 0 ) + mbedtls_printf( " X.509 certificate load: " ); + + mbedtls_x509_crt_init( &clicert ); + + ret = mbedtls_x509_crt_parse( &clicert, (const unsigned char *) mbedtls_test_cli_crt, + mbedtls_test_cli_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + + mbedtls_x509_crt_init( &cacert ); + + ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_ca_crt, + mbedtls_test_ca_crt_len ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n X.509 signature verify: "); + + ret = mbedtls_x509_crt_verify( &clicert, &cacert, NULL, NULL, &flags, NULL, NULL ); + if( ret != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + return( ret ); + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n\n"); + + mbedtls_x509_crt_free( &cacert ); + mbedtls_x509_crt_free( &clicert ); + + return( 0 ); +#else + ((void) verbose); + return( 0 ); +#endif /* MBEDTLS_CERTS_C && MBEDTLS_SHA1_C */ +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_X509_USE_C */ diff --git a/c++/src/connect/mbedtls/x509_create.c b/c++/src/connect/mbedtls/x509_create.c new file mode 100644 index 00000000..df20ec8e --- /dev/null +++ b/c++/src/connect/mbedtls/x509_create.c @@ -0,0 +1,340 @@ +/* + * X.509 base functions for creating certificates / CSRs + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CREATE_C) + +#include "mbedtls/x509.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/oid.h" + +#include + +typedef struct { + const char *name; + size_t name_len; + const char*oid; +} x509_attr_descriptor_t; + +#define ADD_STRLEN( s ) s, sizeof( s ) - 1 + +static const x509_attr_descriptor_t x509_attrs[] = +{ + { ADD_STRLEN( "CN" ), MBEDTLS_OID_AT_CN }, + { ADD_STRLEN( "commonName" ), MBEDTLS_OID_AT_CN }, + { ADD_STRLEN( "C" ), MBEDTLS_OID_AT_COUNTRY }, + { ADD_STRLEN( "countryName" ), MBEDTLS_OID_AT_COUNTRY }, + { ADD_STRLEN( "O" ), MBEDTLS_OID_AT_ORGANIZATION }, + { ADD_STRLEN( "organizationName" ), MBEDTLS_OID_AT_ORGANIZATION }, + { ADD_STRLEN( "L" ), MBEDTLS_OID_AT_LOCALITY }, + { ADD_STRLEN( "locality" ), MBEDTLS_OID_AT_LOCALITY }, + { ADD_STRLEN( "R" ), MBEDTLS_OID_PKCS9_EMAIL }, + { ADD_STRLEN( "OU" ), MBEDTLS_OID_AT_ORG_UNIT }, + { ADD_STRLEN( "organizationalUnitName" ), MBEDTLS_OID_AT_ORG_UNIT }, + { ADD_STRLEN( "ST" ), MBEDTLS_OID_AT_STATE }, + { ADD_STRLEN( "stateOrProvinceName" ), MBEDTLS_OID_AT_STATE }, + { ADD_STRLEN( "emailAddress" ), MBEDTLS_OID_PKCS9_EMAIL }, + { ADD_STRLEN( "serialNumber" ), MBEDTLS_OID_AT_SERIAL_NUMBER }, + { ADD_STRLEN( "postalAddress" ), MBEDTLS_OID_AT_POSTAL_ADDRESS }, + { ADD_STRLEN( "postalCode" ), MBEDTLS_OID_AT_POSTAL_CODE }, + { ADD_STRLEN( "dnQualifier" ), MBEDTLS_OID_AT_DN_QUALIFIER }, + { ADD_STRLEN( "title" ), MBEDTLS_OID_AT_TITLE }, + { ADD_STRLEN( "surName" ), MBEDTLS_OID_AT_SUR_NAME }, + { ADD_STRLEN( "SN" ), MBEDTLS_OID_AT_SUR_NAME }, + { ADD_STRLEN( "givenName" ), MBEDTLS_OID_AT_GIVEN_NAME }, + { ADD_STRLEN( "GN" ), MBEDTLS_OID_AT_GIVEN_NAME }, + { ADD_STRLEN( "initials" ), MBEDTLS_OID_AT_INITIALS }, + { ADD_STRLEN( "pseudonym" ), MBEDTLS_OID_AT_PSEUDONYM }, + { ADD_STRLEN( "generationQualifier" ), MBEDTLS_OID_AT_GENERATION_QUALIFIER }, + { ADD_STRLEN( "domainComponent" ), MBEDTLS_OID_DOMAIN_COMPONENT }, + { ADD_STRLEN( "DC" ), MBEDTLS_OID_DOMAIN_COMPONENT }, + { NULL, 0, NULL } +}; + +static const char *x509_at_oid_from_name( const char *name, size_t name_len ) +{ + const x509_attr_descriptor_t *cur; + + for( cur = x509_attrs; cur->name != NULL; cur++ ) + if( cur->name_len == name_len && + strncmp( cur->name, name, name_len ) == 0 ) + break; + + return( cur->oid ); +} + +int mbedtls_x509_string_to_names( mbedtls_asn1_named_data **head, const char *name ) +{ + int ret = 0; + const char *s = name, *c = s; + const char *end = s + strlen( s ); + const char *oid = NULL; + int in_tag = 1; + char data[MBEDTLS_X509_MAX_DN_NAME_SIZE]; + char *d = data; + + /* Clear existing chain if present */ + mbedtls_asn1_free_named_data_list( head ); + + while( c <= end ) + { + if( in_tag && *c == '=' ) + { + if( ( oid = x509_at_oid_from_name( s, c - s ) ) == NULL ) + { + ret = MBEDTLS_ERR_X509_UNKNOWN_OID; + goto exit; + } + + s = c + 1; + in_tag = 0; + d = data; + } + + if( !in_tag && *c == '\\' && c != end ) + { + c++; + + /* Check for valid escaped characters */ + if( c == end || *c != ',' ) + { + ret = MBEDTLS_ERR_X509_INVALID_NAME; + goto exit; + } + } + else if( !in_tag && ( *c == ',' || c == end ) ) + { + if( mbedtls_asn1_store_named_data( head, oid, strlen( oid ), + (unsigned char *) data, + d - data ) == NULL ) + { + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + } + + while( c < end && *(c + 1) == ' ' ) + c++; + + s = c + 1; + in_tag = 1; + } + + if( !in_tag && s != c + 1 ) + { + *(d++) = *c; + + if( d - data == MBEDTLS_X509_MAX_DN_NAME_SIZE ) + { + ret = MBEDTLS_ERR_X509_INVALID_NAME; + goto exit; + } + } + + c++; + } + +exit: + + return( ret ); +} + +/* The first byte of the value in the mbedtls_asn1_named_data structure is reserved + * to store the critical boolean for us + */ +int mbedtls_x509_set_extension( mbedtls_asn1_named_data **head, const char *oid, size_t oid_len, + int critical, const unsigned char *val, size_t val_len ) +{ + mbedtls_asn1_named_data *cur; + + if( ( cur = mbedtls_asn1_store_named_data( head, oid, oid_len, + NULL, val_len + 1 ) ) == NULL ) + { + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + } + + cur->val.p[0] = critical; + memcpy( cur->val.p + 1, val, val_len ); + + return( 0 ); +} + +/* + * RelativeDistinguishedName ::= + * SET OF AttributeTypeAndValue + * + * AttributeTypeAndValue ::= SEQUENCE { + * type AttributeType, + * value AttributeValue } + * + * AttributeType ::= OBJECT IDENTIFIER + * + * AttributeValue ::= ANY DEFINED BY AttributeType + */ +static int x509_write_name( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + const unsigned char *name, size_t name_len ) +{ + int ret; + size_t len = 0; + + // Write PrintableString for all except MBEDTLS_OID_PKCS9_EMAIL + // + if( MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS9_EMAIL ) == oid_len && + memcmp( oid, MBEDTLS_OID_PKCS9_EMAIL, oid_len ) == 0 ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_ia5_string( p, start, + (const char *) name, + name_len ) ); + } + else + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_printable_string( p, start, + (const char *) name, + name_len ) ); + } + + // Write OID + // + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SET ) ); + + return( (int) len ); +} + +int mbedtls_x509_write_names( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ) +{ + int ret; + size_t len = 0; + mbedtls_asn1_named_data *cur = first; + + while( cur != NULL ) + { + MBEDTLS_ASN1_CHK_ADD( len, x509_write_name( p, start, (char *) cur->oid.p, + cur->oid.len, + cur->val.p, cur->val.len ) ); + cur = cur->next; + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +int mbedtls_x509_write_sig( unsigned char **p, unsigned char *start, + const char *oid, size_t oid_len, + unsigned char *sig, size_t size ) +{ + int ret; + size_t len = 0; + + if( *p < start || (size_t)( *p - start ) < size ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + len = size; + (*p) -= len; + memcpy( *p, sig, len ); + + if( *p - start < 1 ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + *--(*p) = 0; + len += 1; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_BIT_STRING ) ); + + // Write OID + // + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( p, start, oid, + oid_len, 0 ) ); + + return( (int) len ); +} + +static int x509_write_extension( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *ext ) +{ + int ret; + size_t len = 0; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, ext->val.p + 1, + ext->val.len - 1 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, ext->val.len - 1 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OCTET_STRING ) ); + + if( ext->val.p[0] != 0 ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( p, start, 1 ) ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, ext->oid.p, + ext->oid.len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, ext->oid.len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_OID ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +/* + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING + * -- contains the DER encoding of an ASN.1 value + * -- corresponding to the extension type identified + * -- by extnID + * } + */ +int mbedtls_x509_write_extensions( unsigned char **p, unsigned char *start, + mbedtls_asn1_named_data *first ) +{ + int ret; + size_t len = 0; + mbedtls_asn1_named_data *cur_ext = first; + + while( cur_ext != NULL ) + { + MBEDTLS_ASN1_CHK_ADD( len, x509_write_extension( p, start, cur_ext ) ); + cur_ext = cur_ext->next; + } + + return( (int) len ); +} + +#endif /* MBEDTLS_X509_CREATE_C */ diff --git a/c++/src/connect/mbedtls/x509_crl.c b/c++/src/connect/mbedtls/x509_crl.c new file mode 100644 index 00000000..76c49f13 --- /dev/null +++ b/c++/src/connect/mbedtls/x509_crl.c @@ -0,0 +1,723 @@ +/* + * X.509 Certidicate Revocation List (CRL) parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CRL_PARSE_C) + +#include "mbedtls/x509_crl.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_snprintf snprintf +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +#include +#else +#include +#endif + +#if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32) +#include +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Version ::= INTEGER { v1(0), v2(1) } + */ +static int x509_crl_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); + } + + return( 0 ); +} + +/* + * X.509 CRL v2 extensions (no extensions parsed yet.) + */ +static int x509_get_crl_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *ext ) +{ + int ret; + size_t len = 0; + + /* Get explicit tag */ + if( ( ret = mbedtls_x509_get_ext( p, end, ext, 0) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + *p += len; + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL v2 entry extensions (no extensions parsed yet.) + */ +static int x509_get_crl_entry_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *ext ) +{ + int ret; + size_t len = 0; + + /* OPTIONAL */ + if( end <= *p ) + return( 0 ); + + ext->tag = **p; + ext->p = *p; + + /* + * Get CRL-entry extension sequence header + * crlEntryExtensions Extensions OPTIONAL -- if present, MUST be v2 + */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &ext->len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + ext->p = NULL; + return( 0 ); + } + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + } + + end = *p + ext->len; + + if( end != *p + ext->len ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + *p += len; + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 CRL Entries + */ +static int x509_get_entries( unsigned char **p, + const unsigned char *end, + mbedtls_x509_crl_entry *entry ) +{ + int ret; + size_t entry_len; + mbedtls_x509_crl_entry *cur_entry = entry; + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_tag( p, end, &entry_len, + MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + end = *p + entry_len; + + while( *p < end ) + { + size_t len2; + const unsigned char *end2; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len2, + MBEDTLS_ASN1_SEQUENCE | MBEDTLS_ASN1_CONSTRUCTED ) ) != 0 ) + { + return( ret ); + } + + cur_entry->raw.tag = **p; + cur_entry->raw.p = *p; + cur_entry->raw.len = len2; + end2 = *p + len2; + + if( ( ret = mbedtls_x509_get_serial( p, end2, &cur_entry->serial ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_x509_get_time( p, end2, + &cur_entry->revocation_date ) ) != 0 ) + return( ret ); + + if( ( ret = x509_get_crl_entry_ext( p, end2, + &cur_entry->entry_ext ) ) != 0 ) + return( ret ); + + if( *p < end ) + { + cur_entry->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crl_entry ) ); + + if( cur_entry->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + cur_entry = cur_entry->next; + } + } + + return( 0 ); +} + +/* + * Parse one CRLs in DER format and append it to the chained list + */ +int mbedtls_x509_crl_parse_der( mbedtls_x509_crl *chain, + const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; + mbedtls_x509_crl *crl = chain; + + /* + * Check for valid input + */ + if( crl == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); + + /* + * Add new CRL on the end of the chain if needed. + */ + while( crl->version != 0 && crl->next != NULL ) + crl = crl->next; + + if( crl->version != 0 && crl->next == NULL ) + { + crl->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crl ) ); + + if( crl->next == NULL ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + } + + mbedtls_x509_crl_init( crl->next ); + crl = crl->next; + } + + /* + * Copy raw DER-encoded CRL + */ + if( ( p = mbedtls_calloc( 1, buflen ) ) == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + crl->raw.p = p; + crl->raw.len = buflen; + + end = p + buflen; + + /* + * CertificateList ::= SEQUENCE { + * tbsCertList TBSCertList, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + if( len != (size_t) ( end - p ) ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* + * TBSCertList ::= SEQUENCE { + */ + crl->tbs.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + end = p + len; + crl->tbs.len = end - crl->tbs.p; + + /* + * Version ::= INTEGER OPTIONAL { v1(0), v2(1) } + * -- if present, MUST be v2 + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_crl_get_version( &p, end, &crl->version ) ) != 0 || + ( ret = mbedtls_x509_get_alg( &p, end, &crl->sig_oid, &sig_params1 ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + crl->version++; + + if( crl->version > 2 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + } + + if( ( ret = mbedtls_x509_get_sig_alg( &crl->sig_oid, &sig_params1, + &crl->sig_md, &crl->sig_pk, + &crl->sig_opts ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG ); + } + + /* + * issuer Name + */ + crl->issuer_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_x509_get_name( &p, p + len, &crl->issuer ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + crl->issuer_raw.len = p - crl->issuer_raw.p; + + /* + * thisUpdate Time + * nextUpdate Time OPTIONAL + */ + if( ( ret = mbedtls_x509_get_time( &p, end, &crl->this_update ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( ( ret = mbedtls_x509_get_time( &p, end, &crl->next_update ) ) != 0 ) + { + if( ret != ( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) && + ret != ( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ) ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + } + + /* + * revokedCertificates SEQUENCE OF SEQUENCE { + * userCertificate CertificateSerialNumber, + * revocationDate Time, + * crlEntryExtensions Extensions OPTIONAL + * -- if present, MUST be v2 + * } OPTIONAL + */ + if( ( ret = x509_get_entries( &p, end, &crl->entry ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + /* + * crlExtensions EXPLICIT Extensions OPTIONAL + * -- if present, MUST be v2 + */ + if( crl->version == 2 ) + { + ret = x509_get_crl_ext( &p, end, &crl->crl_ext ); + + if( ret != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + } + + if( p != end ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crl->raw.p + crl->raw.len; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( crl->sig_oid.len != sig_oid2.len || + memcmp( crl->sig_oid.p, sig_oid2.p, crl->sig_oid.len ) != 0 || + sig_params1.len != sig_params2.len || + ( sig_params1.len != 0 && + memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_SIG_MISMATCH ); + } + + if( ( ret = mbedtls_x509_get_sig( &p, end, &crl->sig ) ) != 0 ) + { + mbedtls_x509_crl_free( crl ); + return( ret ); + } + + if( p != end ) + { + mbedtls_x509_crl_free( crl ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse one or more CRLs and add them to the chained list + */ +int mbedtls_x509_crl_parse( mbedtls_x509_crl *chain, const unsigned char *buf, size_t buflen ) +{ +#if defined(MBEDTLS_PEM_PARSE_C) + int ret; + size_t use_len; + mbedtls_pem_context pem; + int is_pem = 0; + + if( chain == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + do + { + mbedtls_pem_init( &pem ); + + // Avoid calling mbedtls_pem_read_buffer() on non-null-terminated + // string + if( buflen == 0 || buf[buflen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN X509 CRL-----", + "-----END X509 CRL-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + is_pem = 1; + + buflen -= use_len; + buf += use_len; + + if( ( ret = mbedtls_x509_crl_parse_der( chain, + pem.buf, pem.buflen ) ) != 0 ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + } + else if( is_pem ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + + mbedtls_pem_free( &pem ); + } + /* In the PEM case, buflen is 1 at the end, for the terminated NULL byte. + * And a valid CRL cannot be less than 1 byte anyway. */ + while( is_pem && buflen > 1 ); + + if( is_pem ) + return( 0 ); + else +#endif /* MBEDTLS_PEM_PARSE_C */ + return( mbedtls_x509_crl_parse_der( chain, buf, buflen ) ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load one or more CRLs and add them to the chained list + */ +int mbedtls_x509_crl_parse_file( mbedtls_x509_crl *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_x509_crl_parse( chain, buf, n ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +/* + * Return an informational string about the certificate. + */ +#define BEFORE_COLON 14 +#define BC "14" +/* + * Return an informational string about the CRL. + */ +int mbedtls_x509_crl_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crl *crl ) +{ + int ret; + size_t n; + char *p; + const mbedtls_x509_crl_entry *entry; + + p = buf; + n = size; + + ret = mbedtls_snprintf( p, n, "%sCRL version : %d", + prefix, crl->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crl->issuer ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sthis update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->this_update.year, crl->this_update.mon, + crl->this_update.day, crl->this_update.hour, + crl->this_update.min, crl->this_update.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%snext update : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crl->next_update.year, crl->next_update.mon, + crl->next_update.day, crl->next_update.hour, + crl->next_update.min, crl->next_update.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + entry = &crl->entry; + + ret = mbedtls_snprintf( p, n, "\n%sRevoked certificates:", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + while( entry != NULL && entry->raw.len != 0 ) + { + ret = mbedtls_snprintf( p, n, "\n%sserial number: ", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_serial_gets( p, n, &entry->serial ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, " revocation date: " \ + "%04d-%02d-%02d %02d:%02d:%02d", + entry->revocation_date.year, entry->revocation_date.mon, + entry->revocation_date.day, entry->revocation_date.hour, + entry->revocation_date.min, entry->revocation_date.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + entry = entry->next; + } + + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_sig_alg_gets( p, n, &crl->sig_oid, crl->sig_pk, crl->sig_md, + crl->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); +} + +/* + * Initialize a CRL chain + */ +void mbedtls_x509_crl_init( mbedtls_x509_crl *crl ) +{ + memset( crl, 0, sizeof(mbedtls_x509_crl) ); +} + +/* + * Unallocate all CRL data + */ +void mbedtls_x509_crl_free( mbedtls_x509_crl *crl ) +{ + mbedtls_x509_crl *crl_cur = crl; + mbedtls_x509_crl *crl_prv; + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; + mbedtls_x509_crl_entry *entry_cur; + mbedtls_x509_crl_entry *entry_prv; + + if( crl == NULL ) + return; + + do + { +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( crl_cur->sig_opts ); +#endif + + name_cur = crl_cur->issuer.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + entry_cur = crl_cur->entry.next; + while( entry_cur != NULL ) + { + entry_prv = entry_cur; + entry_cur = entry_cur->next; + mbedtls_zeroize( entry_prv, sizeof( mbedtls_x509_crl_entry ) ); + mbedtls_free( entry_prv ); + } + + if( crl_cur->raw.p != NULL ) + { + mbedtls_zeroize( crl_cur->raw.p, crl_cur->raw.len ); + mbedtls_free( crl_cur->raw.p ); + } + + crl_cur = crl_cur->next; + } + while( crl_cur != NULL ); + + crl_cur = crl; + do + { + crl_prv = crl_cur; + crl_cur = crl_cur->next; + + mbedtls_zeroize( crl_prv, sizeof( mbedtls_x509_crl ) ); + if( crl_prv != crl ) + mbedtls_free( crl_prv ); + } + while( crl_cur != NULL ); +} + +#endif /* MBEDTLS_X509_CRL_PARSE_C */ diff --git a/c++/src/connect/mbedtls/x509_crt.c b/c++/src/connect/mbedtls/x509_crt.c new file mode 100644 index 00000000..d984bf34 --- /dev/null +++ b/c++/src/connect/mbedtls/x509_crt.c @@ -0,0 +1,2404 @@ +/* + * X.509 certificate parsing and verification + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CRT_PARSE_C) + +#include "mbedtls/x509_crt.h" +#include "mbedtls/oid.h" + +#include +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_THREADING_C) +#include "mbedtls/threading.h" +#endif + +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) +#include +#else +#include +#endif + +#if defined(MBEDTLS_FS_IO) +#include +#if !defined(_WIN32) || defined(EFIX64) || defined(EFI32) +#include +#include +#include +#endif /* !_WIN32 || EFIX64 || EFI32 */ +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Default profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_default = +{ + /* Hashes from SHA-1 and above */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_RIPEMD160 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ + 0xFFFFFFF, /* Any curve */ + 2048, +}; + +/* + * Next-default profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_next = +{ + /* Hashes from SHA-256 and above */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ), + 0xFFFFFFF, /* Any PK alg */ +#if defined(MBEDTLS_ECP_C) + /* Curves at or above 128-bit security level */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP521R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP384R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_BP512R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256K1 ), +#else + 0, +#endif + 2048, +}; + +/* + * NSA Suite B Profile + */ +const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_suiteb = +{ + /* Only SHA-256 and 384 */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ), + /* Only ECDSA */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_PK_ECDSA ), +#if defined(MBEDTLS_ECP_C) + /* Only NIST P-256 and P-384 */ + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP256R1 ) | + MBEDTLS_X509_ID_FLAG( MBEDTLS_ECP_DP_SECP384R1 ), +#else + 0, +#endif + 0, +}; + +/* + * Check md_alg against profile + * Return 0 if md_alg acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_md_alg( const mbedtls_x509_crt_profile *profile, + mbedtls_md_type_t md_alg ) +{ + if( ( profile->allowed_mds & MBEDTLS_X509_ID_FLAG( md_alg ) ) != 0 ) + return( 0 ); + + return( -1 ); +} + +/* + * Check pk_alg against profile + * Return 0 if pk_alg acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_pk_alg( const mbedtls_x509_crt_profile *profile, + mbedtls_pk_type_t pk_alg ) +{ + if( ( profile->allowed_pks & MBEDTLS_X509_ID_FLAG( pk_alg ) ) != 0 ) + return( 0 ); + + return( -1 ); +} + +/* + * Check key against profile + * Return 0 if pk_alg acceptable for this profile, -1 otherwise + */ +static int x509_profile_check_key( const mbedtls_x509_crt_profile *profile, + mbedtls_pk_type_t pk_alg, + const mbedtls_pk_context *pk ) +{ +#if defined(MBEDTLS_RSA_C) + if( pk_alg == MBEDTLS_PK_RSA || pk_alg == MBEDTLS_PK_RSASSA_PSS ) + { + if( mbedtls_pk_get_bitlen( pk ) >= profile->rsa_min_bitlen ) + return( 0 ); + + return( -1 ); + } +#endif + +#if defined(MBEDTLS_ECP_C) + if( pk_alg == MBEDTLS_PK_ECDSA || + pk_alg == MBEDTLS_PK_ECKEY || + pk_alg == MBEDTLS_PK_ECKEY_DH ) + { + mbedtls_ecp_group_id gid = mbedtls_pk_ec( *pk )->grp.id; + + if( ( profile->allowed_curves & MBEDTLS_X509_ID_FLAG( gid ) ) != 0 ) + return( 0 ); + + return( -1 ); + } +#endif + + return( -1 ); +} + +/* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ +static int x509_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( ret ); + } + + end = *p + len; + + if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_VERSION + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ +static int x509_get_dates( unsigned char **p, + const unsigned char *end, + mbedtls_x509_time *from, + mbedtls_x509_time *to ) +{ + int ret; + size_t len; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_DATE + ret ); + + end = *p + len; + + if( ( ret = mbedtls_x509_get_time( p, end, from ) ) != 0 ) + return( ret ); + + if( ( ret = mbedtls_x509_get_time( p, end, to ) ) != 0 ) + return( ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_DATE + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 v2/v3 unique identifier (not parsed) + */ +static int x509_get_uid( unsigned char **p, + const unsigned char *end, + mbedtls_x509_buf *uid, int n ) +{ + int ret; + + if( *p == end ) + return( 0 ); + + uid->tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &uid->len, + MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | n ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + uid->p = *p; + *p += uid->len; + + return( 0 ); +} + +static int x509_get_basic_constraints( unsigned char **p, + const unsigned char *end, + int *ca_istrue, + int *max_pathlen ) +{ + int ret; + size_t len; + + /* + * BasicConstraints ::= SEQUENCE { + * cA BOOLEAN DEFAULT FALSE, + * pathLenConstraint INTEGER (0..MAX) OPTIONAL } + */ + *ca_istrue = 0; /* DEFAULT FALSE */ + *max_pathlen = 0; /* endless */ + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_bool( p, end, ca_istrue ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + ret = mbedtls_asn1_get_int( p, end, ca_istrue ); + + if( ret != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *ca_istrue != 0 ) + *ca_istrue = 1; + } + + if( *p == end ) + return( 0 ); + + if( ( ret = mbedtls_asn1_get_int( p, end, max_pathlen ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + (*max_pathlen)++; + + return( 0 ); +} + +static int x509_get_ns_cert_type( unsigned char **p, + const unsigned char *end, + unsigned char *ns_cert_type) +{ + int ret; + mbedtls_x509_bitstring bs = { 0, 0, NULL }; + + if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( bs.len != 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + /* Get actual bitstring */ + *ns_cert_type = *bs.p; + return( 0 ); +} + +static int x509_get_key_usage( unsigned char **p, + const unsigned char *end, + unsigned int *key_usage) +{ + int ret; + size_t i; + mbedtls_x509_bitstring bs = { 0, 0, NULL }; + + if( ( ret = mbedtls_asn1_get_bitstring( p, end, &bs ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( bs.len < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + /* Get actual bitstring */ + *key_usage = 0; + for( i = 0; i < bs.len && i < sizeof( unsigned int ); i++ ) + { + *key_usage |= (unsigned int) bs.p[i] << (8*i); + } + + return( 0 ); +} + +/* + * ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId + * + * KeyPurposeId ::= OBJECT IDENTIFIER + */ +static int x509_get_ext_key_usage( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *ext_key_usage) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_sequence_of( p, end, ext_key_usage, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* Sequence length must be >= 1 */ + if( ext_key_usage->buf.p == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_INVALID_LENGTH ); + + return( 0 ); +} + +/* + * SubjectAltName ::= GeneralNames + * + * GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName + * + * GeneralName ::= CHOICE { + * otherName [0] OtherName, + * rfc822Name [1] IA5String, + * dNSName [2] IA5String, + * x400Address [3] ORAddress, + * directoryName [4] Name, + * ediPartyName [5] EDIPartyName, + * uniformResourceIdentifier [6] IA5String, + * iPAddress [7] OCTET STRING, + * registeredID [8] OBJECT IDENTIFIER } + * + * OtherName ::= SEQUENCE { + * type-id OBJECT IDENTIFIER, + * value [0] EXPLICIT ANY DEFINED BY type-id } + * + * EDIPartyName ::= SEQUENCE { + * nameAssigner [0] DirectoryString OPTIONAL, + * partyName [1] DirectoryString } + * + * NOTE: we only parse and use dNSName at this point. + */ +static int x509_get_subject_alt_name( unsigned char **p, + const unsigned char *end, + mbedtls_x509_sequence *subject_alt_name ) +{ + int ret; + size_t len, tag_len; + mbedtls_asn1_buf *buf; + unsigned char tag; + mbedtls_asn1_sequence *cur = subject_alt_name; + + /* Get main sequence tag */ + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( *p + len != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + while( *p < end ) + { + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + tag = **p; + (*p)++; + if( ( ret = mbedtls_asn1_get_len( p, end, &tag_len ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + if( ( tag & MBEDTLS_ASN1_CONTEXT_SPECIFIC ) != MBEDTLS_ASN1_CONTEXT_SPECIFIC ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + + /* Skip everything but DNS name */ + if( tag != ( MBEDTLS_ASN1_CONTEXT_SPECIFIC | 2 ) ) + { + *p += tag_len; + continue; + } + + /* Allocate and assign next pointer */ + if( cur->buf.p != NULL ) + { + if( cur->next != NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); + + cur->next = mbedtls_calloc( 1, sizeof( mbedtls_asn1_sequence ) ); + + if( cur->next == NULL ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_ALLOC_FAILED ); + + cur = cur->next; + } + + buf = &(cur->buf); + buf->tag = tag; + buf->p = *p; + buf->len = tag_len; + *p += buf->len; + } + + /* Set final sequence entry's next pointer to NULL */ + cur->next = NULL; + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * X.509 v3 extensions + * + */ +static int x509_get_crt_ext( unsigned char **p, + const unsigned char *end, + mbedtls_x509_crt *crt ) +{ + int ret; + size_t len; + unsigned char *end_ext_data, *end_ext_octet; + + if( ( ret = mbedtls_x509_get_ext( p, end, &crt->v3_ext, 3 ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + return( 0 ); + + return( ret ); + } + + while( *p < end ) + { + /* + * Extension ::= SEQUENCE { + * extnID OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * extnValue OCTET STRING } + */ + mbedtls_x509_buf extn_oid = {0, 0, NULL}; + int is_critical = 0; /* DEFAULT FALSE */ + int ext_type = 0; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + end_ext_data = *p + len; + + /* Get extension ID */ + extn_oid.tag = **p; + + if( ( ret = mbedtls_asn1_get_tag( p, end, &extn_oid.len, MBEDTLS_ASN1_OID ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + extn_oid.p = *p; + *p += extn_oid.len; + + if( ( end - *p ) < 1 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_OUT_OF_DATA ); + + /* Get optional critical */ + if( ( ret = mbedtls_asn1_get_bool( p, end_ext_data, &is_critical ) ) != 0 && + ( ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + /* Data should be octet string type */ + if( ( ret = mbedtls_asn1_get_tag( p, end_ext_data, &len, + MBEDTLS_ASN1_OCTET_STRING ) ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + ret ); + + end_ext_octet = *p + len; + + if( end_ext_octet != end_ext_data ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + /* + * Detect supported extensions + */ + ret = mbedtls_oid_get_x509_ext_type( &extn_oid, &ext_type ); + + if( ret != 0 ) + { + /* No parser found, skip extension */ + *p = end_ext_octet; + +#if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + if( is_critical ) + { + /* Data is marked as critical: fail */ + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); + } +#endif + continue; + } + + /* Forbid repeated extensions */ + if( ( crt->ext_types & ext_type ) != 0 ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS ); + + crt->ext_types |= ext_type; + + switch( ext_type ) + { + case MBEDTLS_X509_EXT_BASIC_CONSTRAINTS: + /* Parse basic constraints */ + if( ( ret = x509_get_basic_constraints( p, end_ext_octet, + &crt->ca_istrue, &crt->max_pathlen ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_KEY_USAGE: + /* Parse key usage */ + if( ( ret = x509_get_key_usage( p, end_ext_octet, + &crt->key_usage ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE: + /* Parse extended key usage */ + if( ( ret = x509_get_ext_key_usage( p, end_ext_octet, + &crt->ext_key_usage ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_SUBJECT_ALT_NAME: + /* Parse subject alt name */ + if( ( ret = x509_get_subject_alt_name( p, end_ext_octet, + &crt->subject_alt_names ) ) != 0 ) + return( ret ); + break; + + case MBEDTLS_X509_EXT_NS_CERT_TYPE: + /* Parse netscape certificate type */ + if( ( ret = x509_get_ns_cert_type( p, end_ext_octet, + &crt->ns_cert_type ) ) != 0 ) + return( ret ); + break; + + default: + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + } + } + + if( *p != end ) + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + + return( 0 ); +} + +/* + * Parse and fill a single X.509 certificate in DER format + */ +static int x509_crt_parse_der_core( mbedtls_x509_crt *crt, const unsigned char *buf, + size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end, *crt_end; + mbedtls_x509_buf sig_params1, sig_params2, sig_oid2; + + memset( &sig_params1, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_params2, 0, sizeof( mbedtls_x509_buf ) ); + memset( &sig_oid2, 0, sizeof( mbedtls_x509_buf ) ); + + /* + * Check for valid input + */ + if( crt == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + // Use the original buffer until we figure out actual length + p = (unsigned char*) buf; + len = buflen; + end = p + len; + + /* + * Certificate ::= SEQUENCE { + * tbsCertificate TBSCertificate, + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + if( len > (size_t) ( end - p ) ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + crt_end = p + len; + + // Create and populate a new buffer for the raw field + crt->raw.len = crt_end - buf; + crt->raw.p = p = mbedtls_calloc( 1, crt->raw.len ); + if( p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( p, buf, crt->raw.len ); + + // Direct pointers to the new buffer + p += crt->raw.len - len; + end = crt_end = p + len; + + /* + * TBSCertificate ::= SEQUENCE { + */ + crt->tbs.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + end = p + len; + crt->tbs.len = end - crt->tbs.p; + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + * + * CertificateSerialNumber ::= INTEGER + * + * signature AlgorithmIdentifier + */ + if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 || + ( ret = mbedtls_x509_get_serial( &p, end, &crt->serial ) ) != 0 || + ( ret = mbedtls_x509_get_alg( &p, end, &crt->sig_oid, + &sig_params1 ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + crt->version++; + + if( crt->version > 3 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + } + + if( ( ret = mbedtls_x509_get_sig_alg( &crt->sig_oid, &sig_params1, + &crt->sig_md, &crt->sig_pk, + &crt->sig_opts ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * issuer Name + */ + crt->issuer_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_x509_get_name( &p, p + len, &crt->issuer ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + crt->issuer_raw.len = p - crt->issuer_raw.p; + + /* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + * + */ + if( ( ret = x509_get_dates( &p, end, &crt->valid_from, + &crt->valid_to ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * subject Name + */ + crt->subject_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( len && ( ret = mbedtls_x509_get_name( &p, p + len, &crt->subject ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + crt->subject_raw.len = p - crt->subject_raw.p; + + /* + * SubjectPublicKeyInfo + */ + if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &crt->pk ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + /* + * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, + * -- If present, version shall be v2 or v3 + * extensions [3] EXPLICIT Extensions OPTIONAL + * -- If present, version shall be v3 + */ + if( crt->version == 2 || crt->version == 3 ) + { + ret = x509_get_uid( &p, end, &crt->issuer_id, 1 ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + + if( crt->version == 2 || crt->version == 3 ) + { + ret = x509_get_uid( &p, end, &crt->subject_id, 2 ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + +#if !defined(MBEDTLS_X509_ALLOW_EXTENSIONS_NON_V3) + if( crt->version == 3 ) +#endif + { + ret = x509_get_crt_ext( &p, end, crt ); + if( ret != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + } + + if( p != end ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + end = crt_end; + + /* + * } + * -- end of TBSCertificate + * + * signatureAlgorithm AlgorithmIdentifier, + * signatureValue BIT STRING + */ + if( ( ret = mbedtls_x509_get_alg( &p, end, &sig_oid2, &sig_params2 ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + if( crt->sig_oid.len != sig_oid2.len || + memcmp( crt->sig_oid.p, sig_oid2.p, crt->sig_oid.len ) != 0 || + sig_params1.len != sig_params2.len || + ( sig_params1.len != 0 && + memcmp( sig_params1.p, sig_params2.p, sig_params1.len ) != 0 ) ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_SIG_MISMATCH ); + } + + if( ( ret = mbedtls_x509_get_sig( &p, end, &crt->sig ) ) != 0 ) + { + mbedtls_x509_crt_free( crt ); + return( ret ); + } + + if( p != end ) + { + mbedtls_x509_crt_free( crt ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse one X.509 certificate in DER format from a buffer and add them to a + * chained list + */ +int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *buf, + size_t buflen ) +{ + int ret; + mbedtls_x509_crt *crt = chain, *prev = NULL; + + /* + * Check for valid input + */ + if( crt == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + while( crt->version != 0 && crt->next != NULL ) + { + prev = crt; + crt = crt->next; + } + + /* + * Add new certificate on the end of the chain if needed. + */ + if( crt->version != 0 && crt->next == NULL ) + { + crt->next = mbedtls_calloc( 1, sizeof( mbedtls_x509_crt ) ); + + if( crt->next == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + prev = crt; + mbedtls_x509_crt_init( crt->next ); + crt = crt->next; + } + + if( ( ret = x509_crt_parse_der_core( crt, buf, buflen ) ) != 0 ) + { + if( prev ) + prev->next = NULL; + + if( crt != chain ) + mbedtls_free( crt ); + + return( ret ); + } + + return( 0 ); +} + +/* + * Parse one or more PEM certificates from a buffer and add them to the chained + * list + */ +int mbedtls_x509_crt_parse( mbedtls_x509_crt *chain, const unsigned char *buf, size_t buflen ) +{ +#if defined(MBEDTLS_PEM_PARSE_C) + int success = 0, first_error = 0, total_failed = 0; + int buf_format = MBEDTLS_X509_FORMAT_DER; +#endif + + /* + * Check for valid input + */ + if( chain == NULL || buf == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + /* + * Determine buffer content. Buffer contains either one DER certificate or + * one or more PEM certificates. + */ +#if defined(MBEDTLS_PEM_PARSE_C) + if( buflen != 0 && buf[buflen - 1] == '\0' && + strstr( (const char *) buf, "-----BEGIN CERTIFICATE-----" ) != NULL ) + { + buf_format = MBEDTLS_X509_FORMAT_PEM; + } + + if( buf_format == MBEDTLS_X509_FORMAT_DER ) + return mbedtls_x509_crt_parse_der( chain, buf, buflen ); +#else + return mbedtls_x509_crt_parse_der( chain, buf, buflen ); +#endif + +#if defined(MBEDTLS_PEM_PARSE_C) + if( buf_format == MBEDTLS_X509_FORMAT_PEM ) + { + int ret; + mbedtls_pem_context pem; + + /* 1 rather than 0 since the terminating NULL byte is counted in */ + while( buflen > 1 ) + { + size_t use_len; + mbedtls_pem_init( &pem ); + + /* If we get there, we know the string is null-terminated */ + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN CERTIFICATE-----", + "-----END CERTIFICATE-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded + */ + buflen -= use_len; + buf += use_len; + } + else if( ret == MBEDTLS_ERR_PEM_BAD_INPUT_DATA ) + { + return( ret ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + + /* + * PEM header and footer were found + */ + buflen -= use_len; + buf += use_len; + + if( first_error == 0 ) + first_error = ret; + + total_failed++; + continue; + } + else + break; + + ret = mbedtls_x509_crt_parse_der( chain, pem.buf, pem.buflen ); + + mbedtls_pem_free( &pem ); + + if( ret != 0 ) + { + /* + * Quit parsing on a memory error + */ + if( ret == MBEDTLS_ERR_X509_ALLOC_FAILED ) + return( ret ); + + if( first_error == 0 ) + first_error = ret; + + total_failed++; + continue; + } + + success = 1; + } + } + + if( success ) + return( total_failed ); + else if( first_error ) + return( first_error ); + else + return( MBEDTLS_ERR_X509_CERT_UNKNOWN_FORMAT ); +#endif /* MBEDTLS_PEM_PARSE_C */ +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load one or more certificates and add them to the chained list + */ +int mbedtls_x509_crt_parse_file( mbedtls_x509_crt *chain, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_x509_crt_parse( chain, buf, n ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} + +int mbedtls_x509_crt_parse_path( mbedtls_x509_crt *chain, const char *path ) +{ + int ret = 0; +#if defined(_WIN32) && !defined(EFIX64) && !defined(EFI32) + int w_ret; + WCHAR szDir[MAX_PATH]; + char filename[MAX_PATH]; + char *p; + size_t len = strlen( path ); + + WIN32_FIND_DATAW file_data; + HANDLE hFind; + + if( len > MAX_PATH - 3 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + memset( szDir, 0, sizeof(szDir) ); + memset( filename, 0, MAX_PATH ); + memcpy( filename, path, len ); + filename[len++] = '\\'; + p = filename + len; + filename[len++] = '*'; + + w_ret = MultiByteToWideChar( CP_ACP, 0, filename, (int)len, szDir, + MAX_PATH - 3 ); + if( w_ret == 0 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + hFind = FindFirstFileW( szDir, &file_data ); + if( hFind == INVALID_HANDLE_VALUE ) + return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); + + len = MAX_PATH - len; + do + { + memset( p, 0, len ); + + if( file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) + continue; + + w_ret = WideCharToMultiByte( CP_ACP, 0, file_data.cFileName, + lstrlenW( file_data.cFileName ), + p, (int) len - 1, + NULL, NULL ); + if( w_ret == 0 ) + return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); + + w_ret = mbedtls_x509_crt_parse_file( chain, filename ); + if( w_ret < 0 ) + ret++; + else + ret += w_ret; + } + while( FindNextFileW( hFind, &file_data ) != 0 ); + + if( GetLastError() != ERROR_NO_MORE_FILES ) + ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; + + FindClose( hFind ); +#else /* _WIN32 */ + int t_ret; + int snp_ret; + struct stat sb; + struct dirent *entry; + char entry_name[MBEDTLS_X509_MAX_FILE_PATH_LEN]; + DIR *dir = opendir( path ); + + if( dir == NULL ) + return( MBEDTLS_ERR_X509_FILE_IO_ERROR ); + +#if defined(MBEDTLS_THREADING_PTHREAD) + if( ( ret = mbedtls_mutex_lock( &mbedtls_threading_readdir_mutex ) ) != 0 ) + { + closedir( dir ); + return( ret ); + } +#endif + + while( ( entry = readdir( dir ) ) != NULL ) + { + snp_ret = mbedtls_snprintf( entry_name, sizeof entry_name, + "%s/%s", path, entry->d_name ); + + if( snp_ret < 0 || (size_t)snp_ret >= sizeof entry_name ) + { + ret = MBEDTLS_ERR_X509_BUFFER_TOO_SMALL; + goto cleanup; + } + else if( stat( entry_name, &sb ) == -1 ) + { + ret = MBEDTLS_ERR_X509_FILE_IO_ERROR; + goto cleanup; + } + + if( !S_ISREG( sb.st_mode ) ) + continue; + + // Ignore parse errors + // + t_ret = mbedtls_x509_crt_parse_file( chain, entry_name ); + if( t_ret < 0 ) + ret++; + else + ret += t_ret; + } + +cleanup: + closedir( dir ); + +#if defined(MBEDTLS_THREADING_PTHREAD) + if( mbedtls_mutex_unlock( &mbedtls_threading_readdir_mutex ) != 0 ) + ret = MBEDTLS_ERR_THREADING_MUTEX_ERROR; +#endif + +#endif /* _WIN32 */ + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +static int x509_info_subject_alt_name( char **buf, size_t *size, + const mbedtls_x509_sequence *subject_alt_name ) +{ + size_t i; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = subject_alt_name; + const char *sep = ""; + size_t sep_len = 0; + + while( cur != NULL ) + { + if( cur->buf.len + sep_len >= n ) + { + *p = '\0'; + return( MBEDTLS_ERR_X509_BUFFER_TOO_SMALL ); + } + + n -= cur->buf.len + sep_len; + for( i = 0; i < sep_len; i++ ) + *p++ = sep[i]; + for( i = 0; i < cur->buf.len; i++ ) + *p++ = cur->buf.p[i]; + + sep = ", "; + sep_len = 2; + + cur = cur->next; + } + + *p = '\0'; + + *size = n; + *buf = p; + + return( 0 ); +} + +#define PRINT_ITEM(i) \ + { \ + ret = mbedtls_snprintf( p, n, "%s" i, sep ); \ + MBEDTLS_X509_SAFE_SNPRINTF; \ + sep = ", "; \ + } + +#define CERT_TYPE(type,name) \ + if( ns_cert_type & type ) \ + PRINT_ITEM( name ); + +static int x509_info_cert_type( char **buf, size_t *size, + unsigned char ns_cert_type ) +{ + int ret; + size_t n = *size; + char *p = *buf; + const char *sep = ""; + + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CLIENT, "SSL Client" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_SERVER, "SSL Server" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL, "Email" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING, "Object Signing" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_RESERVED, "Reserved" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_SSL_CA, "SSL CA" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_EMAIL_CA, "Email CA" ); + CERT_TYPE( MBEDTLS_X509_NS_CERT_TYPE_OBJECT_SIGNING_CA, "Object Signing CA" ); + + *size = n; + *buf = p; + + return( 0 ); +} + +#define KEY_USAGE(code,name) \ + if( key_usage & code ) \ + PRINT_ITEM( name ); + +static int x509_info_key_usage( char **buf, size_t *size, + unsigned int key_usage ) +{ + int ret; + size_t n = *size; + char *p = *buf; + const char *sep = ""; + + KEY_USAGE( MBEDTLS_X509_KU_DIGITAL_SIGNATURE, "Digital Signature" ); + KEY_USAGE( MBEDTLS_X509_KU_NON_REPUDIATION, "Non Repudiation" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_ENCIPHERMENT, "Key Encipherment" ); + KEY_USAGE( MBEDTLS_X509_KU_DATA_ENCIPHERMENT, "Data Encipherment" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_AGREEMENT, "Key Agreement" ); + KEY_USAGE( MBEDTLS_X509_KU_KEY_CERT_SIGN, "Key Cert Sign" ); + KEY_USAGE( MBEDTLS_X509_KU_CRL_SIGN, "CRL Sign" ); + KEY_USAGE( MBEDTLS_X509_KU_ENCIPHER_ONLY, "Encipher Only" ); + KEY_USAGE( MBEDTLS_X509_KU_DECIPHER_ONLY, "Decipher Only" ); + + *size = n; + *buf = p; + + return( 0 ); +} + +static int x509_info_ext_key_usage( char **buf, size_t *size, + const mbedtls_x509_sequence *extended_key_usage ) +{ + int ret; + const char *desc; + size_t n = *size; + char *p = *buf; + const mbedtls_x509_sequence *cur = extended_key_usage; + const char *sep = ""; + + while( cur != NULL ) + { + if( mbedtls_oid_get_extended_key_usage( &cur->buf, &desc ) != 0 ) + desc = "???"; + + ret = mbedtls_snprintf( p, n, "%s%s", sep, desc ); + MBEDTLS_X509_SAFE_SNPRINTF; + + sep = ", "; + + cur = cur->next; + } + + *size = n; + *buf = p; + + return( 0 ); +} + +/* + * Return an informational string about the certificate. + */ +#define BEFORE_COLON 18 +#define BC "18" +int mbedtls_x509_crt_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_crt *crt ) +{ + int ret; + size_t n; + char *p; + char key_size_str[BEFORE_COLON]; + + p = buf; + n = size; + + if( NULL == crt ) + { + ret = mbedtls_snprintf( p, n, "\nCertificate is uninitialised!\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); + } + + ret = mbedtls_snprintf( p, n, "%scert. version : %d\n", + prefix, crt->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_snprintf( p, n, "%sserial number : ", + prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_serial_gets( p, n, &crt->serial ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissuer name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crt->issuer ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &crt->subject ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sissued on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_from.year, crt->valid_from.mon, + crt->valid_from.day, crt->valid_from.hour, + crt->valid_from.min, crt->valid_from.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%sexpires on : " \ + "%04d-%02d-%02d %02d:%02d:%02d", prefix, + crt->valid_to.year, crt->valid_to.mon, + crt->valid_to.day, crt->valid_to.hour, + crt->valid_to.min, crt->valid_to.sec ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_sig_alg_gets( p, n, &crt->sig_oid, crt->sig_pk, + crt->sig_md, crt->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + /* Key size */ + if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, + mbedtls_pk_get_name( &crt->pk ) ) ) != 0 ) + { + return( ret ); + } + + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits", prefix, key_size_str, + (int) mbedtls_pk_get_bitlen( &crt->pk ) ); + MBEDTLS_X509_SAFE_SNPRINTF; + + /* + * Optional extensions + */ + + if( crt->ext_types & MBEDTLS_X509_EXT_BASIC_CONSTRAINTS ) + { + ret = mbedtls_snprintf( p, n, "\n%sbasic constraints : CA=%s", prefix, + crt->ca_istrue ? "true" : "false" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( crt->max_pathlen > 0 ) + { + ret = mbedtls_snprintf( p, n, ", max_pathlen=%d", crt->max_pathlen - 1 ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + } + + if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + { + ret = mbedtls_snprintf( p, n, "\n%ssubject alt name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_subject_alt_name( &p, &n, + &crt->subject_alt_names ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_NS_CERT_TYPE ) + { + ret = mbedtls_snprintf( p, n, "\n%scert. type : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_cert_type( &p, &n, crt->ns_cert_type ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) + { + ret = mbedtls_snprintf( p, n, "\n%skey usage : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_key_usage( &p, &n, crt->key_usage ) ) != 0 ) + return( ret ); + } + + if( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) + { + ret = mbedtls_snprintf( p, n, "\n%sext key usage : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = x509_info_ext_key_usage( &p, &n, + &crt->ext_key_usage ) ) != 0 ) + return( ret ); + } + + ret = mbedtls_snprintf( p, n, "\n" ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); +} + +struct x509_crt_verify_string { + int code; + const char *string; +}; + +static const struct x509_crt_verify_string x509_crt_verify_strings[] = { + { MBEDTLS_X509_BADCERT_EXPIRED, "The certificate validity has expired" }, + { MBEDTLS_X509_BADCERT_REVOKED, "The certificate has been revoked (is on a CRL)" }, + { MBEDTLS_X509_BADCERT_CN_MISMATCH, "The certificate Common Name (CN) does not match with the expected CN" }, + { MBEDTLS_X509_BADCERT_NOT_TRUSTED, "The certificate is not correctly signed by the trusted CA" }, + { MBEDTLS_X509_BADCRL_NOT_TRUSTED, "The CRL is not correctly signed by the trusted CA" }, + { MBEDTLS_X509_BADCRL_EXPIRED, "The CRL is expired" }, + { MBEDTLS_X509_BADCERT_MISSING, "Certificate was missing" }, + { MBEDTLS_X509_BADCERT_SKIP_VERIFY, "Certificate verification was skipped" }, + { MBEDTLS_X509_BADCERT_OTHER, "Other reason (can be used by verify callback)" }, + { MBEDTLS_X509_BADCERT_FUTURE, "The certificate validity starts in the future" }, + { MBEDTLS_X509_BADCRL_FUTURE, "The CRL is from the future" }, + { MBEDTLS_X509_BADCERT_KEY_USAGE, "Usage does not match the keyUsage extension" }, + { MBEDTLS_X509_BADCERT_EXT_KEY_USAGE, "Usage does not match the extendedKeyUsage extension" }, + { MBEDTLS_X509_BADCERT_NS_CERT_TYPE, "Usage does not match the nsCertType extension" }, + { MBEDTLS_X509_BADCERT_BAD_MD, "The certificate is signed with an unacceptable hash." }, + { MBEDTLS_X509_BADCERT_BAD_PK, "The certificate is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, + { MBEDTLS_X509_BADCERT_BAD_KEY, "The certificate is signed with an unacceptable key (eg bad curve, RSA too short)." }, + { MBEDTLS_X509_BADCRL_BAD_MD, "The CRL is signed with an unacceptable hash." }, + { MBEDTLS_X509_BADCRL_BAD_PK, "The CRL is signed with an unacceptable PK alg (eg RSA vs ECDSA)." }, + { MBEDTLS_X509_BADCRL_BAD_KEY, "The CRL is signed with an unacceptable key (eg bad curve, RSA too short)." }, + { 0, NULL } +}; + +int mbedtls_x509_crt_verify_info( char *buf, size_t size, const char *prefix, + uint32_t flags ) +{ + int ret; + const struct x509_crt_verify_string *cur; + char *p = buf; + size_t n = size; + + for( cur = x509_crt_verify_strings; cur->string != NULL ; cur++ ) + { + if( ( flags & cur->code ) == 0 ) + continue; + + ret = mbedtls_snprintf( p, n, "%s%s\n", prefix, cur->string ); + MBEDTLS_X509_SAFE_SNPRINTF; + flags ^= cur->code; + } + + if( flags != 0 ) + { + ret = mbedtls_snprintf( p, n, "%sUnknown reason " + "(this should not happen)\n", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + } + + return( (int) ( size - n ) ); +} + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) +int mbedtls_x509_crt_check_key_usage( const mbedtls_x509_crt *crt, + unsigned int usage ) +{ + unsigned int usage_must, usage_may; + unsigned int may_mask = MBEDTLS_X509_KU_ENCIPHER_ONLY + | MBEDTLS_X509_KU_DECIPHER_ONLY; + + if( ( crt->ext_types & MBEDTLS_X509_EXT_KEY_USAGE ) == 0 ) + return( 0 ); + + usage_must = usage & ~may_mask; + + if( ( ( crt->key_usage & ~may_mask ) & usage_must ) != usage_must ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + usage_may = usage & may_mask; + + if( ( ( crt->key_usage & may_mask ) | usage_may ) != usage_may ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + return( 0 ); +} +#endif + +#if defined(MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE) +int mbedtls_x509_crt_check_extended_key_usage( const mbedtls_x509_crt *crt, + const char *usage_oid, + size_t usage_len ) +{ + const mbedtls_x509_sequence *cur; + + /* Extension is not mandatory, absent means no restriction */ + if( ( crt->ext_types & MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE ) == 0 ) + return( 0 ); + + /* + * Look for the requested usage (or wildcard ANY) in our list + */ + for( cur = &crt->ext_key_usage; cur != NULL; cur = cur->next ) + { + const mbedtls_x509_buf *cur_oid = &cur->buf; + + if( cur_oid->len == usage_len && + memcmp( cur_oid->p, usage_oid, usage_len ) == 0 ) + { + return( 0 ); + } + + if( MBEDTLS_OID_CMP( MBEDTLS_OID_ANY_EXTENDED_KEY_USAGE, cur_oid ) == 0 ) + return( 0 ); + } + + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); +} +#endif /* MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE */ + +#if defined(MBEDTLS_X509_CRL_PARSE_C) +/* + * Return 1 if the certificate is revoked, or 0 otherwise. + */ +int mbedtls_x509_crt_is_revoked( const mbedtls_x509_crt *crt, const mbedtls_x509_crl *crl ) +{ + const mbedtls_x509_crl_entry *cur = &crl->entry; + + while( cur != NULL && cur->serial.len != 0 ) + { + if( crt->serial.len == cur->serial.len && + memcmp( crt->serial.p, cur->serial.p, crt->serial.len ) == 0 ) + { + if( mbedtls_x509_time_is_past( &cur->revocation_date ) ) + return( 1 ); + } + + cur = cur->next; + } + + return( 0 ); +} + +/* + * Check that the given certificate is not revoked according to the CRL. + * Skip validation is no CRL for the given CA is present. + */ +static int x509_crt_verifycrl( mbedtls_x509_crt *crt, mbedtls_x509_crt *ca, + mbedtls_x509_crl *crl_list, + const mbedtls_x509_crt_profile *profile ) +{ + int flags = 0; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + const mbedtls_md_info_t *md_info; + + if( ca == NULL ) + return( flags ); + + while( crl_list != NULL ) + { + if( crl_list->version == 0 || + crl_list->issuer_raw.len != ca->subject_raw.len || + memcmp( crl_list->issuer_raw.p, ca->subject_raw.p, + crl_list->issuer_raw.len ) != 0 ) + { + crl_list = crl_list->next; + continue; + } + + /* + * Check if the CA is configured to sign CRLs + */ +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + if( mbedtls_x509_crt_check_key_usage( ca, MBEDTLS_X509_KU_CRL_SIGN ) != 0 ) + { + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } +#endif + + /* + * Check if CRL is correctly signed by the trusted CA + */ + if( x509_profile_check_md_alg( profile, crl_list->sig_md ) != 0 ) + flags |= MBEDTLS_X509_BADCRL_BAD_MD; + + if( x509_profile_check_pk_alg( profile, crl_list->sig_pk ) != 0 ) + flags |= MBEDTLS_X509_BADCRL_BAD_PK; + + md_info = mbedtls_md_info_from_type( crl_list->sig_md ); + if( md_info == NULL ) + { + /* + * Cannot check 'unknown' hash + */ + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } + + mbedtls_md( md_info, crl_list->tbs.p, crl_list->tbs.len, hash ); + + if( x509_profile_check_key( profile, crl_list->sig_pk, &ca->pk ) != 0 ) + flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + if( mbedtls_pk_verify_ext( crl_list->sig_pk, crl_list->sig_opts, &ca->pk, + crl_list->sig_md, hash, mbedtls_md_get_size( md_info ), + crl_list->sig.p, crl_list->sig.len ) != 0 ) + { + flags |= MBEDTLS_X509_BADCRL_NOT_TRUSTED; + break; + } + + /* + * Check for validity of CRL (Do not drop out) + */ + if( mbedtls_x509_time_is_past( &crl_list->next_update ) ) + flags |= MBEDTLS_X509_BADCRL_EXPIRED; + + if( mbedtls_x509_time_is_future( &crl_list->this_update ) ) + flags |= MBEDTLS_X509_BADCRL_FUTURE; + + /* + * Check if certificate is revoked + */ + if( mbedtls_x509_crt_is_revoked( crt, crl_list ) ) + { + flags |= MBEDTLS_X509_BADCERT_REVOKED; + break; + } + + crl_list = crl_list->next; + } + + return( flags ); +} +#endif /* MBEDTLS_X509_CRL_PARSE_C */ + +/* + * Like memcmp, but case-insensitive and always returns -1 if different + */ +static int x509_memcasecmp( const void *s1, const void *s2, size_t len ) +{ + size_t i; + unsigned char diff; + const unsigned char *n1 = s1, *n2 = s2; + + for( i = 0; i < len; i++ ) + { + diff = n1[i] ^ n2[i]; + + if( diff == 0 ) + continue; + + if( diff == 32 && + ( ( n1[i] >= 'a' && n1[i] <= 'z' ) || + ( n1[i] >= 'A' && n1[i] <= 'Z' ) ) ) + { + continue; + } + + return( -1 ); + } + + return( 0 ); +} + +/* + * Return 0 if name matches wildcard, -1 otherwise + */ +static int x509_check_wildcard( const char *cn, mbedtls_x509_buf *name ) +{ + size_t i; + size_t cn_idx = 0, cn_len = strlen( cn ); + + if( name->len < 3 || name->p[0] != '*' || name->p[1] != '.' ) + return( 0 ); + + for( i = 0; i < cn_len; ++i ) + { + if( cn[i] == '.' ) + { + cn_idx = i; + break; + } + } + + if( cn_idx == 0 ) + return( -1 ); + + if( cn_len - cn_idx == name->len - 1 && + x509_memcasecmp( name->p + 1, cn + cn_idx, name->len - 1 ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Compare two X.509 strings, case-insensitive, and allowing for some encoding + * variations (but not all). + * + * Return 0 if equal, -1 otherwise. + */ +static int x509_string_cmp( const mbedtls_x509_buf *a, const mbedtls_x509_buf *b ) +{ + if( a->tag == b->tag && + a->len == b->len && + memcmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + if( ( a->tag == MBEDTLS_ASN1_UTF8_STRING || a->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + ( b->tag == MBEDTLS_ASN1_UTF8_STRING || b->tag == MBEDTLS_ASN1_PRINTABLE_STRING ) && + a->len == b->len && + x509_memcasecmp( a->p, b->p, b->len ) == 0 ) + { + return( 0 ); + } + + return( -1 ); +} + +/* + * Compare two X.509 Names (aka rdnSequence). + * + * See RFC 5280 section 7.1, though we don't implement the whole algorithm: + * we sometimes return unequal when the full algorithm would return equal, + * but never the other way. (In particular, we don't do Unicode normalisation + * or space folding.) + * + * Return 0 if equal, -1 otherwise. + */ +static int x509_name_cmp( const mbedtls_x509_name *a, const mbedtls_x509_name *b ) +{ + /* Avoid recursion, it might not be optimised by the compiler */ + while( a != NULL || b != NULL ) + { + if( a == NULL || b == NULL ) + return( -1 ); + + /* type */ + if( a->oid.tag != b->oid.tag || + a->oid.len != b->oid.len || + memcmp( a->oid.p, b->oid.p, b->oid.len ) != 0 ) + { + return( -1 ); + } + + /* value */ + if( x509_string_cmp( &a->val, &b->val ) != 0 ) + return( -1 ); + + /* structure of the list of sets */ + if( a->next_merged != b->next_merged ) + return( -1 ); + + a = a->next; + b = b->next; + } + + /* a == NULL == b */ + return( 0 ); +} + +/* + * Check if 'parent' is a suitable parent (signing CA) for 'child'. + * Return 0 if yes, -1 if not. + * + * top means parent is a locally-trusted certificate + * bottom means child is the end entity cert + */ +static int x509_crt_check_parent( const mbedtls_x509_crt *child, + const mbedtls_x509_crt *parent, + int top, int bottom ) +{ + int need_ca_bit; + + /* Parent must be the issuer */ + if( x509_name_cmp( &child->issuer, &parent->subject ) != 0 ) + return( -1 ); + + /* Parent must have the basicConstraints CA bit set as a general rule */ + need_ca_bit = 1; + + /* Exception: v1/v2 certificates that are locally trusted. */ + if( top && parent->version < 3 ) + need_ca_bit = 0; + + /* Exception: self-signed end-entity certs that are locally trusted. */ + if( top && bottom && + child->raw.len == parent->raw.len && + memcmp( child->raw.p, parent->raw.p, child->raw.len ) == 0 ) + { + need_ca_bit = 0; + } + + if( need_ca_bit && ! parent->ca_istrue ) + return( -1 ); + +#if defined(MBEDTLS_X509_CHECK_KEY_USAGE) + if( need_ca_bit && + mbedtls_x509_crt_check_key_usage( parent, MBEDTLS_X509_KU_KEY_CERT_SIGN ) != 0 ) + { + return( -1 ); + } +#endif + + return( 0 ); +} + +static int x509_crt_verify_top( + mbedtls_x509_crt *child, mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + int path_cnt, int self_cnt, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + int ret; + uint32_t ca_flags = 0; + int check_path_cnt; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + const mbedtls_md_info_t *md_info; + mbedtls_x509_crt *future_past_ca = NULL; + + if( mbedtls_x509_time_is_past( &child->valid_to ) ) + *flags |= MBEDTLS_X509_BADCERT_EXPIRED; + + if( mbedtls_x509_time_is_future( &child->valid_from ) ) + *flags |= MBEDTLS_X509_BADCERT_FUTURE; + + if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_MD; + + if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + /* + * Child is the top of the chain. Check against the trust_ca list. + */ + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + + md_info = mbedtls_md_info_from_type( child->sig_md ); + if( md_info == NULL ) + { + /* + * Cannot check 'unknown', no need to try any CA + */ + trust_ca = NULL; + } + else + mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ); + + for( /* trust_ca */ ; trust_ca != NULL; trust_ca = trust_ca->next ) + { + if( x509_crt_check_parent( child, trust_ca, 1, path_cnt == 0 ) != 0 ) + continue; + + check_path_cnt = path_cnt + 1; + + /* + * Reduce check_path_cnt to check against if top of the chain is + * the same as the trusted CA + */ + if( child->subject_raw.len == trust_ca->subject_raw.len && + memcmp( child->subject_raw.p, trust_ca->subject_raw.p, + child->issuer_raw.len ) == 0 ) + { + check_path_cnt--; + } + + /* Self signed certificates do not count towards the limit */ + if( trust_ca->max_pathlen > 0 && + trust_ca->max_pathlen < check_path_cnt - self_cnt ) + { + continue; + } + + if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &trust_ca->pk, + child->sig_md, hash, mbedtls_md_get_size( md_info ), + child->sig.p, child->sig.len ) != 0 ) + { + continue; + } + + if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) || + mbedtls_x509_time_is_future( &trust_ca->valid_from ) ) + { + if ( future_past_ca == NULL ) + future_past_ca = trust_ca; + + continue; + } + + break; + } + + if( trust_ca != NULL || ( trust_ca = future_past_ca ) != NULL ) + { + /* + * Top of chain is signed by a trusted CA + */ + *flags &= ~MBEDTLS_X509_BADCERT_NOT_TRUSTED; + + if( x509_profile_check_key( profile, child->sig_pk, &trust_ca->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + } + + /* + * If top of chain is not the same as the trusted CA send a verify request + * to the callback for any issues with validity and CRL presence for the + * trusted CA certificate. + */ + if( trust_ca != NULL && + ( child->subject_raw.len != trust_ca->subject_raw.len || + memcmp( child->subject_raw.p, trust_ca->subject_raw.p, + child->issuer_raw.len ) != 0 ) ) + { +#if defined(MBEDTLS_X509_CRL_PARSE_C) + /* Check trusted CA's CRL for the chain's top crt */ + *flags |= x509_crt_verifycrl( child, trust_ca, ca_crl, profile ); +#else + ((void) ca_crl); +#endif + + if( mbedtls_x509_time_is_past( &trust_ca->valid_to ) ) + ca_flags |= MBEDTLS_X509_BADCERT_EXPIRED; + + if( mbedtls_x509_time_is_future( &trust_ca->valid_from ) ) + ca_flags |= MBEDTLS_X509_BADCERT_FUTURE; + + if( NULL != f_vrfy ) + { + if( ( ret = f_vrfy( p_vrfy, trust_ca, path_cnt + 1, + &ca_flags ) ) != 0 ) + { + return( ret ); + } + } + } + + /* Call callback on top cert */ + if( NULL != f_vrfy ) + { + if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) + return( ret ); + } + + *flags |= ca_flags; + + return( 0 ); +} + +static int x509_crt_verify_child( + mbedtls_x509_crt *child, mbedtls_x509_crt *parent, + mbedtls_x509_crt *trust_ca, mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + int path_cnt, int self_cnt, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + int ret; + uint32_t parent_flags = 0; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + mbedtls_x509_crt *grandparent; + const mbedtls_md_info_t *md_info; + + /* Counting intermediate self signed certificates */ + if( ( path_cnt != 0 ) && x509_name_cmp( &child->issuer, &child->subject ) == 0 ) + self_cnt++; + + /* path_cnt is 0 for the first intermediate CA */ + if( 1 + path_cnt > MBEDTLS_X509_MAX_INTERMEDIATE_CA ) + { + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); + } + + if( mbedtls_x509_time_is_past( &child->valid_to ) ) + *flags |= MBEDTLS_X509_BADCERT_EXPIRED; + + if( mbedtls_x509_time_is_future( &child->valid_from ) ) + *flags |= MBEDTLS_X509_BADCERT_FUTURE; + + if( x509_profile_check_md_alg( profile, child->sig_md ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_MD; + + if( x509_profile_check_pk_alg( profile, child->sig_pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + md_info = mbedtls_md_info_from_type( child->sig_md ); + if( md_info == NULL ) + { + /* + * Cannot check 'unknown' hash + */ + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + } + else + { + mbedtls_md( md_info, child->tbs.p, child->tbs.len, hash ); + + if( x509_profile_check_key( profile, child->sig_pk, &parent->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + if( mbedtls_pk_verify_ext( child->sig_pk, child->sig_opts, &parent->pk, + child->sig_md, hash, mbedtls_md_get_size( md_info ), + child->sig.p, child->sig.len ) != 0 ) + { + *flags |= MBEDTLS_X509_BADCERT_NOT_TRUSTED; + } + } + +#if defined(MBEDTLS_X509_CRL_PARSE_C) + /* Check trusted CA's CRL for the given crt */ + *flags |= x509_crt_verifycrl(child, parent, ca_crl, profile ); +#endif + + /* Look for a grandparent in trusted CAs */ + for( grandparent = trust_ca; + grandparent != NULL; + grandparent = grandparent->next ) + { + if( x509_crt_check_parent( parent, grandparent, + 0, path_cnt == 0 ) == 0 ) + break; + } + + if( grandparent != NULL ) + { + ret = x509_crt_verify_top( parent, grandparent, ca_crl, profile, + path_cnt + 1, self_cnt, &parent_flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + /* Look for a grandparent upwards the chain */ + for( grandparent = parent->next; + grandparent != NULL; + grandparent = grandparent->next ) + { + /* +2 because the current step is not yet accounted for + * and because max_pathlen is one higher than it should be. + * Also self signed certificates do not count to the limit. */ + if( grandparent->max_pathlen > 0 && + grandparent->max_pathlen < 2 + path_cnt - self_cnt ) + { + continue; + } + + if( x509_crt_check_parent( parent, grandparent, + 0, path_cnt == 0 ) == 0 ) + break; + } + + /* Is our parent part of the chain or at the top? */ + if( grandparent != NULL ) + { + ret = x509_crt_verify_child( parent, grandparent, trust_ca, ca_crl, + profile, path_cnt + 1, self_cnt, &parent_flags, + f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + ret = x509_crt_verify_top( parent, trust_ca, ca_crl, profile, + path_cnt + 1, self_cnt, &parent_flags, + f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + } + + /* child is verified to be a child of the parent, call verify callback */ + if( NULL != f_vrfy ) + if( ( ret = f_vrfy( p_vrfy, child, path_cnt, flags ) ) != 0 ) + return( ret ); + + *flags |= parent_flags; + + return( 0 ); +} + +/* + * Verify the certificate validity + */ +int mbedtls_x509_crt_verify( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + return( mbedtls_x509_crt_verify_with_profile( crt, trust_ca, ca_crl, + &mbedtls_x509_crt_profile_default, cn, flags, f_vrfy, p_vrfy ) ); +} + + +/* + * Verify the certificate validity, with profile + */ +int mbedtls_x509_crt_verify_with_profile( mbedtls_x509_crt *crt, + mbedtls_x509_crt *trust_ca, + mbedtls_x509_crl *ca_crl, + const mbedtls_x509_crt_profile *profile, + const char *cn, uint32_t *flags, + int (*f_vrfy)(void *, mbedtls_x509_crt *, int, uint32_t *), + void *p_vrfy ) +{ + size_t cn_len; + int ret; + int pathlen = 0, selfsigned = 0; + mbedtls_x509_crt *parent; + mbedtls_x509_name *name; + mbedtls_x509_sequence *cur = NULL; + mbedtls_pk_type_t pk_type; + + if( profile == NULL ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + *flags = 0; + + if( cn != NULL ) + { + name = &crt->subject; + cn_len = strlen( cn ); + + if( crt->ext_types & MBEDTLS_X509_EXT_SUBJECT_ALT_NAME ) + { + cur = &crt->subject_alt_names; + + while( cur != NULL ) + { + if( cur->buf.len == cn_len && + x509_memcasecmp( cn, cur->buf.p, cn_len ) == 0 ) + break; + + if( cur->buf.len > 2 && + memcmp( cur->buf.p, "*.", 2 ) == 0 && + x509_check_wildcard( cn, &cur->buf ) == 0 ) + { + break; + } + + cur = cur->next; + } + + if( cur == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } + else + { + while( name != NULL ) + { + if( MBEDTLS_OID_CMP( MBEDTLS_OID_AT_CN, &name->oid ) == 0 ) + { + if( name->val.len == cn_len && + x509_memcasecmp( name->val.p, cn, cn_len ) == 0 ) + break; + + if( name->val.len > 2 && + memcmp( name->val.p, "*.", 2 ) == 0 && + x509_check_wildcard( cn, &name->val ) == 0 ) + break; + } + + name = name->next; + } + + if( name == NULL ) + *flags |= MBEDTLS_X509_BADCERT_CN_MISMATCH; + } + } + + /* Check the type and size of the key */ + pk_type = mbedtls_pk_get_type( &crt->pk ); + + if( x509_profile_check_pk_alg( profile, pk_type ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_PK; + + if( x509_profile_check_key( profile, pk_type, &crt->pk ) != 0 ) + *flags |= MBEDTLS_X509_BADCERT_BAD_KEY; + + /* Look for a parent in trusted CAs */ + for( parent = trust_ca; parent != NULL; parent = parent->next ) + { + if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 ) + break; + } + + if( parent != NULL ) + { + ret = x509_crt_verify_top( crt, parent, ca_crl, profile, + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + /* Look for a parent upwards the chain */ + for( parent = crt->next; parent != NULL; parent = parent->next ) + if( x509_crt_check_parent( crt, parent, 0, pathlen == 0 ) == 0 ) + break; + + /* Are we part of the chain or at the top? */ + if( parent != NULL ) + { + ret = x509_crt_verify_child( crt, parent, trust_ca, ca_crl, profile, + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + else + { + ret = x509_crt_verify_top( crt, trust_ca, ca_crl, profile, + pathlen, selfsigned, flags, f_vrfy, p_vrfy ); + if( ret != 0 ) + return( ret ); + } + } + + if( *flags != 0 ) + return( MBEDTLS_ERR_X509_CERT_VERIFY_FAILED ); + + return( 0 ); +} + +/* + * Initialize a certificate chain + */ +void mbedtls_x509_crt_init( mbedtls_x509_crt *crt ) +{ + memset( crt, 0, sizeof(mbedtls_x509_crt) ); +} + +/* + * Unallocate all certificate data + */ +void mbedtls_x509_crt_free( mbedtls_x509_crt *crt ) +{ + mbedtls_x509_crt *cert_cur = crt; + mbedtls_x509_crt *cert_prv; + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; + mbedtls_x509_sequence *seq_cur; + mbedtls_x509_sequence *seq_prv; + + if( crt == NULL ) + return; + + do + { + mbedtls_pk_free( &cert_cur->pk ); + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( cert_cur->sig_opts ); +#endif + + name_cur = cert_cur->issuer.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + name_cur = cert_cur->subject.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + seq_cur = cert_cur->ext_key_usage.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + + seq_cur = cert_cur->subject_alt_names.next; + while( seq_cur != NULL ) + { + seq_prv = seq_cur; + seq_cur = seq_cur->next; + mbedtls_zeroize( seq_prv, sizeof( mbedtls_x509_sequence ) ); + mbedtls_free( seq_prv ); + } + + if( cert_cur->raw.p != NULL ) + { + mbedtls_zeroize( cert_cur->raw.p, cert_cur->raw.len ); + mbedtls_free( cert_cur->raw.p ); + } + + cert_cur = cert_cur->next; + } + while( cert_cur != NULL ); + + cert_cur = crt; + do + { + cert_prv = cert_cur; + cert_cur = cert_cur->next; + + mbedtls_zeroize( cert_prv, sizeof( mbedtls_x509_crt ) ); + if( cert_prv != crt ) + mbedtls_free( cert_prv ); + } + while( cert_cur != NULL ); +} + +#endif /* MBEDTLS_X509_CRT_PARSE_C */ + diff --git a/c++/src/connect/mbedtls/x509_csr.c b/c++/src/connect/mbedtls/x509_csr.c new file mode 100644 index 00000000..f92b66c5 --- /dev/null +++ b/c++/src/connect/mbedtls/x509_csr.c @@ -0,0 +1,423 @@ +/* + * X.509 Certificate Signing Request (CSR) parsing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * The ITU-T X.509 standard defines a certificate format for PKI. + * + * http://www.ietf.org/rfc/rfc5280.txt (Certificates and CRLs) + * http://www.ietf.org/rfc/rfc3279.txt (Alg IDs for CRLs) + * http://www.ietf.org/rfc/rfc2986.txt (CSRs, aka PKCS#10) + * + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf + * http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CSR_PARSE_C) + +#include "mbedtls/x509_csr.h" +#include "mbedtls/oid.h" + +#include + +#if defined(MBEDTLS_PEM_PARSE_C) +#include "mbedtls/pem.h" +#endif + +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#include +#define mbedtls_free free +#define mbedtls_calloc calloc +#define mbedtls_snprintf snprintf +#endif + +#if defined(MBEDTLS_FS_IO) || defined(EFIX64) || defined(EFI32) +#include +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * Version ::= INTEGER { v1(0) } + */ +static int x509_csr_get_version( unsigned char **p, + const unsigned char *end, + int *ver ) +{ + int ret; + + if( ( ret = mbedtls_asn1_get_int( p, end, ver ) ) != 0 ) + { + if( ret == MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ) + { + *ver = 0; + return( 0 ); + } + + return( MBEDTLS_ERR_X509_INVALID_VERSION + ret ); + } + + return( 0 ); +} + +/* + * Parse a CSR in DER format + */ +int mbedtls_x509_csr_parse_der( mbedtls_x509_csr *csr, + const unsigned char *buf, size_t buflen ) +{ + int ret; + size_t len; + unsigned char *p, *end; + mbedtls_x509_buf sig_params; + + memset( &sig_params, 0, sizeof( mbedtls_x509_buf ) ); + + /* + * Check for valid input + */ + if( csr == NULL || buf == NULL || buflen == 0 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + mbedtls_x509_csr_init( csr ); + + /* + * first copy the raw DER data + */ + p = mbedtls_calloc( 1, len = buflen ); + + if( p == NULL ) + return( MBEDTLS_ERR_X509_ALLOC_FAILED ); + + memcpy( p, buf, buflen ); + + csr->raw.p = p; + csr->raw.len = len; + end = p + len; + + /* + * CertificationRequest ::= SEQUENCE { + * certificationRequestInfo CertificationRequestInfo, + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + * } + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT ); + } + + if( len != (size_t) ( end - p ) ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + /* + * CertificationRequestInfo ::= SEQUENCE { + */ + csr->cri.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + end = p + len; + csr->cri.len = end - csr->cri.p; + + /* + * Version ::= INTEGER { v1(0) } + */ + if( ( ret = x509_csr_get_version( &p, end, &csr->version ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + csr->version++; + + if( csr->version != 1 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_UNKNOWN_VERSION ); + } + + /* + * subject Name + */ + csr->subject_raw.p = p; + + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + if( ( ret = mbedtls_x509_get_name( &p, p + len, &csr->subject ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + csr->subject_raw.len = p - csr->subject_raw.p; + + /* + * subjectPKInfo SubjectPublicKeyInfo + */ + if( ( ret = mbedtls_pk_parse_subpubkey( &p, end, &csr->pk ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + /* + * attributes [0] Attributes + * + * The list of possible attributes is open-ended, though RFC 2985 + * (PKCS#9) defines a few in section 5.4. We currently don't support any, + * so we just ignore them. This is a safe thing to do as the worst thing + * that could happen is that we issue a certificate that does not match + * the requester's expectations - this cannot cause a violation of our + * signature policies. + */ + if( ( ret = mbedtls_asn1_get_tag( &p, end, &len, + MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + ret ); + } + + p += len; + + end = csr->raw.p + csr->raw.len; + + /* + * signatureAlgorithm AlgorithmIdentifier, + * signature BIT STRING + */ + if( ( ret = mbedtls_x509_get_alg( &p, end, &csr->sig_oid, &sig_params ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + if( ( ret = mbedtls_x509_get_sig_alg( &csr->sig_oid, &sig_params, + &csr->sig_md, &csr->sig_pk, + &csr->sig_opts ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_UNKNOWN_SIG_ALG ); + } + + if( ( ret = mbedtls_x509_get_sig( &p, end, &csr->sig ) ) != 0 ) + { + mbedtls_x509_csr_free( csr ); + return( ret ); + } + + if( p != end ) + { + mbedtls_x509_csr_free( csr ); + return( MBEDTLS_ERR_X509_INVALID_FORMAT + + MBEDTLS_ERR_ASN1_LENGTH_MISMATCH ); + } + + return( 0 ); +} + +/* + * Parse a CSR, allowing for PEM or raw DER encoding + */ +int mbedtls_x509_csr_parse( mbedtls_x509_csr *csr, const unsigned char *buf, size_t buflen ) +{ +#if defined(MBEDTLS_PEM_PARSE_C) + int ret; + size_t use_len; + mbedtls_pem_context pem; +#endif + + /* + * Check for valid input + */ + if( csr == NULL || buf == NULL || buflen == 0 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + +#if defined(MBEDTLS_PEM_PARSE_C) + mbedtls_pem_init( &pem ); + + /* Avoid calling mbedtls_pem_read_buffer() on non-null-terminated string */ + if( buf[buflen - 1] != '\0' ) + ret = MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT; + else + ret = mbedtls_pem_read_buffer( &pem, + "-----BEGIN CERTIFICATE REQUEST-----", + "-----END CERTIFICATE REQUEST-----", + buf, NULL, 0, &use_len ); + + if( ret == 0 ) + { + /* + * Was PEM encoded, parse the result + */ + if( ( ret = mbedtls_x509_csr_parse_der( csr, pem.buf, pem.buflen ) ) != 0 ) + return( ret ); + + mbedtls_pem_free( &pem ); + return( 0 ); + } + else if( ret != MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT ) + { + mbedtls_pem_free( &pem ); + return( ret ); + } + else +#endif /* MBEDTLS_PEM_PARSE_C */ + return( mbedtls_x509_csr_parse_der( csr, buf, buflen ) ); +} + +#if defined(MBEDTLS_FS_IO) +/* + * Load a CSR into the structure + */ +int mbedtls_x509_csr_parse_file( mbedtls_x509_csr *csr, const char *path ) +{ + int ret; + size_t n; + unsigned char *buf; + + if( ( ret = mbedtls_pk_load_file( path, &buf, &n ) ) != 0 ) + return( ret ); + + ret = mbedtls_x509_csr_parse( csr, buf, n ); + + mbedtls_zeroize( buf, n ); + mbedtls_free( buf ); + + return( ret ); +} +#endif /* MBEDTLS_FS_IO */ + +#define BEFORE_COLON 14 +#define BC "14" +/* + * Return an informational string about the CSR. + */ +int mbedtls_x509_csr_info( char *buf, size_t size, const char *prefix, + const mbedtls_x509_csr *csr ) +{ + int ret; + size_t n; + char *p; + char key_size_str[BEFORE_COLON]; + + p = buf; + n = size; + + ret = mbedtls_snprintf( p, n, "%sCSR version : %d", + prefix, csr->version ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssubject name : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + ret = mbedtls_x509_dn_gets( p, n, &csr->subject ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_snprintf( p, n, "\n%ssigned using : ", prefix ); + MBEDTLS_X509_SAFE_SNPRINTF; + + ret = mbedtls_x509_sig_alg_gets( p, n, &csr->sig_oid, csr->sig_pk, csr->sig_md, + csr->sig_opts ); + MBEDTLS_X509_SAFE_SNPRINTF; + + if( ( ret = mbedtls_x509_key_size_helper( key_size_str, BEFORE_COLON, + mbedtls_pk_get_name( &csr->pk ) ) ) != 0 ) + { + return( ret ); + } + + ret = mbedtls_snprintf( p, n, "\n%s%-" BC "s: %d bits\n", prefix, key_size_str, + (int) mbedtls_pk_get_bitlen( &csr->pk ) ); + MBEDTLS_X509_SAFE_SNPRINTF; + + return( (int) ( size - n ) ); +} + +/* + * Initialize a CSR + */ +void mbedtls_x509_csr_init( mbedtls_x509_csr *csr ) +{ + memset( csr, 0, sizeof(mbedtls_x509_csr) ); +} + +/* + * Unallocate all CSR data + */ +void mbedtls_x509_csr_free( mbedtls_x509_csr *csr ) +{ + mbedtls_x509_name *name_cur; + mbedtls_x509_name *name_prv; + + if( csr == NULL ) + return; + + mbedtls_pk_free( &csr->pk ); + +#if defined(MBEDTLS_X509_RSASSA_PSS_SUPPORT) + mbedtls_free( csr->sig_opts ); +#endif + + name_cur = csr->subject.next; + while( name_cur != NULL ) + { + name_prv = name_cur; + name_cur = name_cur->next; + mbedtls_zeroize( name_prv, sizeof( mbedtls_x509_name ) ); + mbedtls_free( name_prv ); + } + + if( csr->raw.p != NULL ) + { + mbedtls_zeroize( csr->raw.p, csr->raw.len ); + mbedtls_free( csr->raw.p ); + } + + mbedtls_zeroize( csr, sizeof( mbedtls_x509_csr ) ); +} + +#endif /* MBEDTLS_X509_CSR_PARSE_C */ diff --git a/c++/src/connect/mbedtls/x509write_crt.c b/c++/src/connect/mbedtls/x509write_crt.c new file mode 100644 index 00000000..d1d9a22a --- /dev/null +++ b/c++/src/connect/mbedtls/x509write_crt.c @@ -0,0 +1,459 @@ +/* + * X.509 certificate writing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * References: + * - certificates: RFC 5280, updated by RFC 6818 + * - CSRs: PKCS#10 v1.7 aka RFC 2986 + * - attributes: PKCS#9 v2.0 aka RFC 2985 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CRT_WRITE_C) + +#include "mbedtls/x509_crt.h" +#include "mbedtls/oid.h" +#include "mbedtls/asn1write.h" +#include "mbedtls/sha1.h" + +#include + +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif /* MBEDTLS_PEM_WRITE_C */ + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void mbedtls_x509write_crt_init( mbedtls_x509write_cert *ctx ) +{ + memset( ctx, 0, sizeof(mbedtls_x509write_cert) ); + + mbedtls_mpi_init( &ctx->serial ); + ctx->version = MBEDTLS_X509_CRT_VERSION_3; +} + +void mbedtls_x509write_crt_free( mbedtls_x509write_cert *ctx ) +{ + mbedtls_mpi_free( &ctx->serial ); + + mbedtls_asn1_free_named_data_list( &ctx->subject ); + mbedtls_asn1_free_named_data_list( &ctx->issuer ); + mbedtls_asn1_free_named_data_list( &ctx->extensions ); + + mbedtls_zeroize( ctx, sizeof(mbedtls_x509write_cert) ); +} + +void mbedtls_x509write_crt_set_version( mbedtls_x509write_cert *ctx, int version ) +{ + ctx->version = version; +} + +void mbedtls_x509write_crt_set_md_alg( mbedtls_x509write_cert *ctx, mbedtls_md_type_t md_alg ) +{ + ctx->md_alg = md_alg; +} + +void mbedtls_x509write_crt_set_subject_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ) +{ + ctx->subject_key = key; +} + +void mbedtls_x509write_crt_set_issuer_key( mbedtls_x509write_cert *ctx, mbedtls_pk_context *key ) +{ + ctx->issuer_key = key; +} + +int mbedtls_x509write_crt_set_subject_name( mbedtls_x509write_cert *ctx, + const char *subject_name ) +{ + return mbedtls_x509_string_to_names( &ctx->subject, subject_name ); +} + +int mbedtls_x509write_crt_set_issuer_name( mbedtls_x509write_cert *ctx, + const char *issuer_name ) +{ + return mbedtls_x509_string_to_names( &ctx->issuer, issuer_name ); +} + +int mbedtls_x509write_crt_set_serial( mbedtls_x509write_cert *ctx, const mbedtls_mpi *serial ) +{ + int ret; + + if( ( ret = mbedtls_mpi_copy( &ctx->serial, serial ) ) != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_crt_set_validity( mbedtls_x509write_cert *ctx, const char *not_before, + const char *not_after ) +{ + if( strlen( not_before ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 || + strlen( not_after ) != MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1 ) + { + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + } + strncpy( ctx->not_before, not_before, MBEDTLS_X509_RFC5280_UTC_TIME_LEN ); + strncpy( ctx->not_after , not_after , MBEDTLS_X509_RFC5280_UTC_TIME_LEN ); + ctx->not_before[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z'; + ctx->not_after[MBEDTLS_X509_RFC5280_UTC_TIME_LEN - 1] = 'Z'; + + return( 0 ); +} + +int mbedtls_x509write_crt_set_extension( mbedtls_x509write_cert *ctx, + const char *oid, size_t oid_len, + int critical, + const unsigned char *val, size_t val_len ) +{ + return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len, + critical, val, val_len ); +} + +int mbedtls_x509write_crt_set_basic_constraints( mbedtls_x509write_cert *ctx, + int is_ca, int max_pathlen ) +{ + int ret; + unsigned char buf[9]; + unsigned char *c = buf + sizeof(buf); + size_t len = 0; + + memset( buf, 0, sizeof(buf) ); + + if( is_ca && max_pathlen > 127 ) + return( MBEDTLS_ERR_X509_BAD_INPUT_DATA ); + + if( is_ca ) + { + if( max_pathlen >= 0 ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, buf, max_pathlen ) ); + } + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_bool( &c, buf, 1 ) ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_BASIC_CONSTRAINTS, + MBEDTLS_OID_SIZE( MBEDTLS_OID_BASIC_CONSTRAINTS ), + 0, buf + sizeof(buf) - len, len ); +} + +#if defined(MBEDTLS_SHA1_C) +int mbedtls_x509write_crt_set_subject_key_identifier( mbedtls_x509write_cert *ctx ) +{ + int ret; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */ + unsigned char *c = buf + sizeof(buf); + size_t len = 0; + + memset( buf, 0, sizeof(buf) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->subject_key ) ); + + mbedtls_sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); + c = buf + sizeof(buf) - 20; + len = 20; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_OCTET_STRING ) ); + + return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER, + MBEDTLS_OID_SIZE( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ), + 0, buf + sizeof(buf) - len, len ); +} + +int mbedtls_x509write_crt_set_authority_key_identifier( mbedtls_x509write_cert *ctx ) +{ + int ret; + unsigned char buf[MBEDTLS_MPI_MAX_SIZE * 2 + 20]; /* tag, length + 2xMPI */ + unsigned char *c = buf + sizeof(buf); + size_t len = 0; + + memset( buf, 0, sizeof(buf) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey( &c, buf, ctx->issuer_key ) ); + + mbedtls_sha1( buf + sizeof(buf) - len, len, buf + sizeof(buf) - 20 ); + c = buf + sizeof(buf) - 20; + len = 20; + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | 0 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER, + MBEDTLS_OID_SIZE( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ), + 0, buf + sizeof(buf) - len, len ); +} +#endif /* MBEDTLS_SHA1_C */ + +int mbedtls_x509write_crt_set_key_usage( mbedtls_x509write_cert *ctx, + unsigned int key_usage ) +{ + unsigned char buf[4], ku; + unsigned char *c; + int ret; + + /* We currently only support 7 bits, from 0x80 to 0x02 */ + if( ( key_usage & ~0xfe ) != 0 ) + return( MBEDTLS_ERR_X509_FEATURE_UNAVAILABLE ); + + c = buf + 4; + ku = (unsigned char) key_usage; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ku, 7 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), + 1, buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_crt_set_ns_cert_type( mbedtls_x509write_cert *ctx, + unsigned char ns_cert_type ) +{ + unsigned char buf[4]; + unsigned char *c; + int ret; + + c = buf + 4; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_crt_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), + 0, buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +static int x509_write_time( unsigned char **p, unsigned char *start, + const char *time, size_t size ) +{ + int ret; + size_t len = 0; + + /* + * write MBEDTLS_ASN1_UTC_TIME if year < 2050 (2 bytes shorter) + */ + if( time[0] == '2' && time[1] == '0' && time [2] < '5' ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) time + 2, + size - 2 ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_UTC_TIME ) ); + } + else + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_raw_buffer( p, start, + (const unsigned char *) time, + size ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( p, start, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( p, start, MBEDTLS_ASN1_GENERALIZED_TIME ) ); + } + + return( (int) len ); +} + +int mbedtls_x509write_crt_der( mbedtls_x509write_cert *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + const char *sig_oid; + size_t sig_oid_len = 0; + unsigned char *c, *c2; + unsigned char hash[64]; + unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char tmp_buf[2048]; + size_t sub_len = 0, pub_len = 0, sig_and_oid_len = 0, sig_len; + size_t len = 0; + mbedtls_pk_type_t pk_alg; + + /* + * Prepare data to be signed in tmp_buf + */ + c = tmp_buf + sizeof( tmp_buf ); + + /* Signature algorithm needed in TBS, and later for actual signature */ + pk_alg = mbedtls_pk_get_type( ctx->issuer_key ); + if( pk_alg == MBEDTLS_PK_ECKEY ) + pk_alg = MBEDTLS_PK_ECDSA; + + if( ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, + &sig_oid, &sig_oid_len ) ) != 0 ) + { + return( ret ); + } + + /* + * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | + MBEDTLS_ASN1_CONSTRUCTED | 3 ) ); + + /* + * SubjectPublicKeyInfo + */ + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->subject_key, + tmp_buf, c - tmp_buf ) ); + c -= pub_len; + len += pub_len; + + /* + * Subject ::= Name + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->subject ) ); + + /* + * Validity ::= SEQUENCE { + * notBefore Time, + * notAfter Time } + */ + sub_len = 0; + + MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_after, + MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) ); + + MBEDTLS_ASN1_CHK_ADD( sub_len, x509_write_time( &c, tmp_buf, ctx->not_before, + MBEDTLS_X509_RFC5280_UTC_TIME_LEN ) ); + + len += sub_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + /* + * Issuer ::= Name + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->issuer ) ); + + /* + * Signature ::= AlgorithmIdentifier + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, tmp_buf, + sig_oid, strlen( sig_oid ), 0 ) ); + + /* + * Serial ::= INTEGER + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_mpi( &c, tmp_buf, &ctx->serial ) ); + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + sub_len = 0; + MBEDTLS_ASN1_CHK_ADD( sub_len, mbedtls_asn1_write_int( &c, tmp_buf, ctx->version ) ); + len += sub_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, sub_len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONTEXT_SPECIFIC | + MBEDTLS_ASN1_CONSTRUCTED | 0 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + /* + * Make signature + */ + mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash ); + + if( ( ret = mbedtls_pk_sign( ctx->issuer_key, ctx->md_alg, hash, 0, sig, &sig_len, + f_rng, p_rng ) ) != 0 ) + { + return( ret ); + } + + /* + * Write data to output buffer + */ + c2 = buf + size; + MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf, + sig_oid, sig_oid_len, sig, sig_len ) ); + + if( len > (size_t)( c2 - buf ) ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + c2 -= len; + memcpy( c2, c, len ); + + len += sig_and_oid_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c2, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c2, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +#define PEM_BEGIN_CRT "-----BEGIN CERTIFICATE-----\n" +#define PEM_END_CRT "-----END CERTIFICATE-----\n" + +#if defined(MBEDTLS_PEM_WRITE_C) +int mbedtls_x509write_crt_pem( mbedtls_x509write_cert *crt, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char output_buf[4096]; + size_t olen = 0; + + if( ( ret = mbedtls_x509write_crt_der( crt, output_buf, sizeof(output_buf), + f_rng, p_rng ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CRT, PEM_END_CRT, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ + +#endif /* MBEDTLS_X509_CRT_WRITE_C */ diff --git a/c++/src/connect/mbedtls/x509write_csr.c b/c++/src/connect/mbedtls/x509write_csr.c new file mode 100644 index 00000000..8fd856b2 --- /dev/null +++ b/c++/src/connect/mbedtls/x509write_csr.c @@ -0,0 +1,259 @@ +/* + * X.509 Certificate Signing Request writing + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ +/* + * References: + * - CSRs: PKCS#10 v1.7 aka RFC 2986 + * - attributes: PKCS#9 v2.0 aka RFC 2985 + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_X509_CSR_WRITE_C) + +#include "mbedtls/x509_csr.h" +#include "mbedtls/oid.h" +#include "mbedtls/asn1write.h" + +#include +#include + +#if defined(MBEDTLS_PEM_WRITE_C) +#include "mbedtls/pem.h" +#endif + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +void mbedtls_x509write_csr_init( mbedtls_x509write_csr *ctx ) +{ + memset( ctx, 0, sizeof(mbedtls_x509write_csr) ); +} + +void mbedtls_x509write_csr_free( mbedtls_x509write_csr *ctx ) +{ + mbedtls_asn1_free_named_data_list( &ctx->subject ); + mbedtls_asn1_free_named_data_list( &ctx->extensions ); + + mbedtls_zeroize( ctx, sizeof(mbedtls_x509write_csr) ); +} + +void mbedtls_x509write_csr_set_md_alg( mbedtls_x509write_csr *ctx, mbedtls_md_type_t md_alg ) +{ + ctx->md_alg = md_alg; +} + +void mbedtls_x509write_csr_set_key( mbedtls_x509write_csr *ctx, mbedtls_pk_context *key ) +{ + ctx->key = key; +} + +int mbedtls_x509write_csr_set_subject_name( mbedtls_x509write_csr *ctx, + const char *subject_name ) +{ + return mbedtls_x509_string_to_names( &ctx->subject, subject_name ); +} + +int mbedtls_x509write_csr_set_extension( mbedtls_x509write_csr *ctx, + const char *oid, size_t oid_len, + const unsigned char *val, size_t val_len ) +{ + return mbedtls_x509_set_extension( &ctx->extensions, oid, oid_len, + 0, val, val_len ); +} + +int mbedtls_x509write_csr_set_key_usage( mbedtls_x509write_csr *ctx, unsigned char key_usage ) +{ + unsigned char buf[4]; + unsigned char *c; + int ret; + + c = buf + 4; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &key_usage, 7 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_KEY_USAGE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_KEY_USAGE ), + buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_csr_set_ns_cert_type( mbedtls_x509write_csr *ctx, + unsigned char ns_cert_type ) +{ + unsigned char buf[4]; + unsigned char *c; + int ret; + + c = buf + 4; + + if( ( ret = mbedtls_asn1_write_bitstring( &c, buf, &ns_cert_type, 8 ) ) != 4 ) + return( ret ); + + ret = mbedtls_x509write_csr_set_extension( ctx, MBEDTLS_OID_NS_CERT_TYPE, + MBEDTLS_OID_SIZE( MBEDTLS_OID_NS_CERT_TYPE ), + buf, 4 ); + if( ret != 0 ) + return( ret ); + + return( 0 ); +} + +int mbedtls_x509write_csr_der( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + const char *sig_oid; + size_t sig_oid_len = 0; + unsigned char *c, *c2; + unsigned char hash[64]; + unsigned char sig[MBEDTLS_MPI_MAX_SIZE]; + unsigned char tmp_buf[2048]; + size_t pub_len = 0, sig_and_oid_len = 0, sig_len; + size_t len = 0; + mbedtls_pk_type_t pk_alg; + + /* + * Prepare data to be signed in tmp_buf + */ + c = tmp_buf + sizeof( tmp_buf ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_extensions( &c, tmp_buf, ctx->extensions ) ); + + if( len ) + { + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SET ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( &c, tmp_buf, MBEDTLS_OID_PKCS9_CSR_EXT_REQ, + MBEDTLS_OID_SIZE( MBEDTLS_OID_PKCS9_CSR_EXT_REQ ) ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + } + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_CONTEXT_SPECIFIC ) ); + + MBEDTLS_ASN1_CHK_ADD( pub_len, mbedtls_pk_write_pubkey_der( ctx->key, + tmp_buf, c - tmp_buf ) ); + c -= pub_len; + len += pub_len; + + /* + * Subject ::= Name + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_x509_write_names( &c, tmp_buf, ctx->subject ) ); + + /* + * Version ::= INTEGER { v1(0), v2(1), v3(2) } + */ + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_int( &c, tmp_buf, 0 ) ); + + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, tmp_buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, tmp_buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + /* + * Prepare signature + */ + mbedtls_md( mbedtls_md_info_from_type( ctx->md_alg ), c, len, hash ); + + pk_alg = mbedtls_pk_get_type( ctx->key ); + if( pk_alg == MBEDTLS_PK_ECKEY ) + pk_alg = MBEDTLS_PK_ECDSA; + + if( ( ret = mbedtls_pk_sign( ctx->key, ctx->md_alg, hash, 0, sig, &sig_len, + f_rng, p_rng ) ) != 0 || + ( ret = mbedtls_oid_get_oid_by_sig_alg( pk_alg, ctx->md_alg, + &sig_oid, &sig_oid_len ) ) != 0 ) + { + return( ret ); + } + + /* + * Write data to output buffer + */ + c2 = buf + size; + MBEDTLS_ASN1_CHK_ADD( sig_and_oid_len, mbedtls_x509_write_sig( &c2, buf, + sig_oid, sig_oid_len, sig, sig_len ) ); + + if( len > (size_t)( c2 - buf ) ) + return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL ); + + c2 -= len; + memcpy( c2, c, len ); + + len += sig_and_oid_len; + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c2, buf, len ) ); + MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c2, buf, MBEDTLS_ASN1_CONSTRUCTED | + MBEDTLS_ASN1_SEQUENCE ) ); + + return( (int) len ); +} + +#define PEM_BEGIN_CSR "-----BEGIN CERTIFICATE REQUEST-----\n" +#define PEM_END_CSR "-----END CERTIFICATE REQUEST-----\n" + +#if defined(MBEDTLS_PEM_WRITE_C) +int mbedtls_x509write_csr_pem( mbedtls_x509write_csr *ctx, unsigned char *buf, size_t size, + int (*f_rng)(void *, unsigned char *, size_t), + void *p_rng ) +{ + int ret; + unsigned char output_buf[4096]; + size_t olen = 0; + + if( ( ret = mbedtls_x509write_csr_der( ctx, output_buf, sizeof(output_buf), + f_rng, p_rng ) ) < 0 ) + { + return( ret ); + } + + if( ( ret = mbedtls_pem_write_buffer( PEM_BEGIN_CSR, PEM_END_CSR, + output_buf + sizeof(output_buf) - ret, + ret, buf, size, &olen ) ) != 0 ) + { + return( ret ); + } + + return( 0 ); +} +#endif /* MBEDTLS_PEM_WRITE_C */ + +#endif /* MBEDTLS_X509_CSR_WRITE_C */ diff --git a/c++/src/connect/mbedtls/xtea.c b/c++/src/connect/mbedtls/xtea.c new file mode 100644 index 00000000..fe0a3509 --- /dev/null +++ b/c++/src/connect/mbedtls/xtea.c @@ -0,0 +1,281 @@ +/* + * An 32-bit implementation of the XTEA algorithm + * + * Copyright (C) 2006-2015, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This file is part of mbed TLS (https://tls.mbed.org) + */ + +#if !defined(MBEDTLS_CONFIG_FILE) +#include "mbedtls/config.h" +#else +#include MBEDTLS_CONFIG_FILE +#endif + +#if defined(MBEDTLS_XTEA_C) + +#include "mbedtls/xtea.h" + +#include + +#if defined(MBEDTLS_SELF_TEST) +#if defined(MBEDTLS_PLATFORM_C) +#include "mbedtls/platform.h" +#else +#include +#define mbedtls_printf printf +#endif /* MBEDTLS_PLATFORM_C */ +#endif /* MBEDTLS_SELF_TEST */ + +#if !defined(MBEDTLS_XTEA_ALT) + +/* Implementation that should never be optimized out by the compiler */ +static void mbedtls_zeroize( void *v, size_t n ) { + volatile unsigned char *p = v; while( n-- ) *p++ = 0; +} + +/* + * 32-bit integer manipulation macros (big endian) + */ +#ifndef GET_UINT32_BE +#define GET_UINT32_BE(n,b,i) \ +{ \ + (n) = ( (uint32_t) (b)[(i) ] << 24 ) \ + | ( (uint32_t) (b)[(i) + 1] << 16 ) \ + | ( (uint32_t) (b)[(i) + 2] << 8 ) \ + | ( (uint32_t) (b)[(i) + 3] ); \ +} +#endif + +#ifndef PUT_UINT32_BE +#define PUT_UINT32_BE(n,b,i) \ +{ \ + (b)[(i) ] = (unsigned char) ( (n) >> 24 ); \ + (b)[(i) + 1] = (unsigned char) ( (n) >> 16 ); \ + (b)[(i) + 2] = (unsigned char) ( (n) >> 8 ); \ + (b)[(i) + 3] = (unsigned char) ( (n) ); \ +} +#endif + +void mbedtls_xtea_init( mbedtls_xtea_context *ctx ) +{ + memset( ctx, 0, sizeof( mbedtls_xtea_context ) ); +} + +void mbedtls_xtea_free( mbedtls_xtea_context *ctx ) +{ + if( ctx == NULL ) + return; + + mbedtls_zeroize( ctx, sizeof( mbedtls_xtea_context ) ); +} + +/* + * XTEA key schedule + */ +void mbedtls_xtea_setup( mbedtls_xtea_context *ctx, const unsigned char key[16] ) +{ + int i; + + memset( ctx, 0, sizeof(mbedtls_xtea_context) ); + + for( i = 0; i < 4; i++ ) + { + GET_UINT32_BE( ctx->k[i], key, i << 2 ); + } +} + +/* + * XTEA encrypt function + */ +int mbedtls_xtea_crypt_ecb( mbedtls_xtea_context *ctx, int mode, + const unsigned char input[8], unsigned char output[8]) +{ + uint32_t *k, v0, v1, i; + + k = ctx->k; + + GET_UINT32_BE( v0, input, 0 ); + GET_UINT32_BE( v1, input, 4 ); + + if( mode == MBEDTLS_XTEA_ENCRYPT ) + { + uint32_t sum = 0, delta = 0x9E3779B9; + + for( i = 0; i < 32; i++ ) + { + v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); + sum += delta; + v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]); + } + } + else /* MBEDTLS_XTEA_DECRYPT */ + { + uint32_t delta = 0x9E3779B9, sum = delta * 32; + + for( i = 0; i < 32; i++ ) + { + v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + k[(sum>>11) & 3]); + sum -= delta; + v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + k[sum & 3]); + } + } + + PUT_UINT32_BE( v0, output, 0 ); + PUT_UINT32_BE( v1, output, 4 ); + + return( 0 ); +} + +#if defined(MBEDTLS_CIPHER_MODE_CBC) +/* + * XTEA-CBC buffer encryption/decryption + */ +int mbedtls_xtea_crypt_cbc( mbedtls_xtea_context *ctx, int mode, size_t length, + unsigned char iv[8], const unsigned char *input, + unsigned char *output) +{ + int i; + unsigned char temp[8]; + + if( length % 8 ) + return( MBEDTLS_ERR_XTEA_INVALID_INPUT_LENGTH ); + + if( mode == MBEDTLS_XTEA_DECRYPT ) + { + while( length > 0 ) + { + memcpy( temp, input, 8 ); + mbedtls_xtea_crypt_ecb( ctx, mode, input, output ); + + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( output[i] ^ iv[i] ); + + memcpy( iv, temp, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + else + { + while( length > 0 ) + { + for( i = 0; i < 8; i++ ) + output[i] = (unsigned char)( input[i] ^ iv[i] ); + + mbedtls_xtea_crypt_ecb( ctx, mode, output, output ); + memcpy( iv, output, 8 ); + + input += 8; + output += 8; + length -= 8; + } + } + + return( 0 ); +} +#endif /* MBEDTLS_CIPHER_MODE_CBC */ +#endif /* !MBEDTLS_XTEA_ALT */ + +#if defined(MBEDTLS_SELF_TEST) + +/* + * XTEA tests vectors (non-official) + */ + +static const unsigned char xtea_test_key[6][16] = +{ + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x0c, 0x0d, 0x0e, 0x0f }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 } +}; + +static const unsigned char xtea_test_pt[6][8] = +{ + { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0x5a, 0x5b, 0x6e, 0x27, 0x89, 0x48, 0xd7, 0x7f }, + { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0x70, 0xe1, 0x22, 0x5d, 0x6e, 0x4e, 0x76, 0x55 } +}; + +static const unsigned char xtea_test_ct[6][8] = +{ + { 0x49, 0x7d, 0xf3, 0xd0, 0x72, 0x61, 0x2c, 0xb5 }, + { 0xe7, 0x8f, 0x2d, 0x13, 0x74, 0x43, 0x41, 0xd8 }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 }, + { 0xa0, 0x39, 0x05, 0x89, 0xf8, 0xb8, 0xef, 0xa5 }, + { 0xed, 0x23, 0x37, 0x5a, 0x82, 0x1a, 0x8c, 0x2d }, + { 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41 } +}; + +/* + * Checkup routine + */ +int mbedtls_xtea_self_test( int verbose ) +{ + int i, ret = 0; + unsigned char buf[8]; + mbedtls_xtea_context ctx; + + mbedtls_xtea_init( &ctx ); + for( i = 0; i < 6; i++ ) + { + if( verbose != 0 ) + mbedtls_printf( " XTEA test #%d: ", i + 1 ); + + memcpy( buf, xtea_test_pt[i], 8 ); + + mbedtls_xtea_setup( &ctx, xtea_test_key[i] ); + mbedtls_xtea_crypt_ecb( &ctx, MBEDTLS_XTEA_ENCRYPT, buf, buf ); + + if( memcmp( buf, xtea_test_ct[i], 8 ) != 0 ) + { + if( verbose != 0 ) + mbedtls_printf( "failed\n" ); + + ret = 1; + goto exit; + } + + if( verbose != 0 ) + mbedtls_printf( "passed\n" ); + } + + if( verbose != 0 ) + mbedtls_printf( "\n" ); + +exit: + mbedtls_xtea_free( &ctx ); + + return( ret ); +} + +#endif /* MBEDTLS_SELF_TEST */ + +#endif /* MBEDTLS_XTEA_C */ diff --git a/c++/src/connect/ncbi_ansi_ext.c b/c++/src/connect/ncbi_ansi_ext.c index 0a5af931..8714e8fd 100644 --- a/c++/src/connect/ncbi_ansi_ext.c +++ b/c++/src/connect/ncbi_ansi_ext.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_ansi_ext.c 451610 2014-11-07 21:00:36Z lavr $ +/* $Id: ncbi_ansi_ext.c 534368 2017-04-26 19:27:52Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -38,8 +38,16 @@ #include -#ifndef HAVE_STRDUP +#ifndef HAVE_STRNLEN +size_t strnlen(const char* str, size_t maxlen) +{ + const char* end = (const char*) memchr(str, '\0', maxlen); + return end ? (size_t)(end - str) : maxlen; +} +#endif /*HAVE_STRNLEN*/ + +#ifndef HAVE_STRDUP char* strdup(const char* str) { size_t size = strlen(str) + 1; @@ -48,15 +56,13 @@ char* strdup(const char* str) memcpy(res, str, size); return res; } - #endif /*HAVE_STRDUP*/ #ifndef HAVE_STRNDUP - char* strndup(const char* str, size_t n) { - const char* end = n ? memchr(str, '\0', n) : 0; + const char* end = n ? (const char*) memchr(str, '\0', n) : 0; size_t size = end ? (size_t)(end - str) : n; char* res = (char*) malloc(size + 1); if (res) { @@ -65,7 +71,6 @@ char* strndup(const char* str, size_t n) } return res; } - #endif /*HAVE_STRNDUP*/ @@ -145,19 +150,34 @@ char* strncpy0(char* s1, const char* s2, size_t n) } +#ifndef HAVE_MEMCCHR +void* memcchr(const void* s, int c, size_t n) +{ + unsigned char* p = (unsigned char*) s; + size_t i; + for (i = 0; i < n; ++i) { + if (*p != (unsigned char) c) + return p; + ++p; + } + return 0; +} +#endif /*!HAVE_MEMCCHR*/ + + #ifndef HAVE_MEMRCHR /* suboptimal but working implementation */ void* memrchr(const void* s, int c, size_t n) { unsigned char* e = (unsigned char*) s + n; size_t i; - for (i = 0; i < n; i++) { + for (i = 0; i < n; ++i) { if (*--e == (unsigned char) c) return e; } return 0; } -#endif/*!HAVE_MEMRCHR*/ +#endif /*!HAVE_MEMRCHR*/ static const double x_pow10[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 }; @@ -177,7 +197,7 @@ char* NCBI_simple_ftoa(char* s, double f, int p) v = f < 0.0 ? -f : f; x = (long)(v + 0.5 / w); y = (long)(w * (v - x) + 0.5); - assert(p || !y); /* with precision 0, output of "0" is empty */ + assert(p || !y); /* with precision 0, output of ".0" is empty */ return s + sprintf(s, &"-%ld%s%.*lu"[!(f < 0.0)], x, &"."[!p], p, y); } diff --git a/c++/src/connect/ncbi_ansi_ext.h b/c++/src/connect/ncbi_ansi_ext.h index 561785f0..b676f8f2 100644 --- a/c++/src/connect/ncbi_ansi_ext.h +++ b/c++/src/connect/ncbi_ansi_ext.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_ANSI_EXT__H #define CONNECT___NCBI_ANSI_EXT__H -/* $Id: ncbi_ansi_ext.h 373800 2012-09-04 12:23:35Z lavr $ +/* $Id: ncbi_ansi_ext.h 534368 2017-04-26 19:27:52Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -29,7 +29,8 @@ * Author: Anton Lavrentiev * * File Description: - * Non-ANSI, yet widely used functions +///@file ncbi_ansi_ext.h + * Non-ANSI, yet widely used string/memory functions * */ @@ -44,20 +45,39 @@ extern "C" { #endif +#ifndef HAVE_STRNLEN + +# ifdef strnlen +# undef strnlen +# endif +# define strnlen NCBI_strnlen + +/** Return the number of characters in the string pointed to by "str" (not + * including the '\0' character but no more than "maxlen" (if the '\0' + * character hasn't been found within the first "maxlen" characters). + */ +NCBI_XCONNECT_EXPORT +size_t strnlen(const char* str, size_t maxlen); + +#endif /*HAVE_STRNLEN*/ + + #ifndef HAVE_STRDUP # ifdef strdup # undef strdup # endif -# define strdup NCBI_strdup +# define strdup NCBI_strdup -/* Create a copy of string "str". - * Return an identical malloc'ed string, which must be explicitly freed - * by free() when no longer needed. +/** Create a copy of string "str". + * Return an identical malloc'ed string, which must be explicitly freed by + * free() when no longer needed. */ NCBI_XCONNECT_EXPORT -char* strdup(const char* str); +char* strdup(const char* str); +#elif defined(NCBI_COMPILER_MSVC) +# define strdup _strdup #endif /*HAVE_STRDUP*/ @@ -66,14 +86,14 @@ char* strdup(const char* str); # ifdef strndup # undef strndup # endif -# define strndup NCBI_strndup +# define strndup NCBI_strndup -/* Create a copy of up to "n" first characters of string "str". - * Return a malloc'ed and '\0'-terminated string, which must be - * explicitly freed by free() when no longer needed. +/** Create a copy of up to "n" first characters of string "str". + * Return a malloc'ed and '\0'-terminated string, which must be explicitly + * freed by free() when no longer needed. */ NCBI_XCONNECT_EXPORT -char* strndup(const char* str, size_t n); +char* strndup(const char* str, size_t n); #endif /*HAVE_STRNDUP*/ @@ -84,90 +104,107 @@ char* strndup(const char* str, size_t n); # undef strcasecmp # undef strncasecmp # endif -# define strcasecmp NCBI_strcasecmp -# define strncasecmp NCBI_strncasecmp +# define strcasecmp NCBI_strcasecmp +# define strncasecmp NCBI_strncasecmp -/* Compare "s1" and "s2", ignoring case. - * Return less than, equal to or greater than zero if - * "s1" is lexicographically less than, equal to or greater than "s2". +/** Compare "s1" and "s2", ignoring case. + * Return less than, equal to or greater than zero if + * "s1" is lexicographically less than, equal to or greater than "s2". */ NCBI_XCONNECT_EXPORT -int strcasecmp(const char* s1, const char* s2); +int strcasecmp(const char* s1, const char* s2); -/* Compare not more than "n" characters of "s1" and "s2", ignoring case. - * Return less than, equal to or greater than zero if - * "s1" is lexicographically less than, equal to or greater than "s2". +/** Compare not more than "n" characters of "s1" and "s2", ignoring case. + * Return less than, equal to or greater than zero if + * "s1" is lexicographically less than, equal to or greater than "s2". */ NCBI_XCONNECT_EXPORT -int strncasecmp(const char* s1, const char* s2, size_t n); +int strncasecmp(const char* s1, const char* s2, size_t n); -#endif/*HAVE_STRCASECMP*/ +#endif /*HAVE_STRCASECMP*/ #ifdef strupr # undef strupr # undef strlwr #endif -#define strupr NCBI_strupr -#define strlwr NCBI_strlwr +#define strupr NCBI_strupr +#define strlwr NCBI_strlwr -/* Convert a string to uppercase, then return pointer to - * the altered string. Because the conversion is made in place, the - * returned pointer is the same as the passed one. +/** Convert a string to uppercase, then return pointer to + * the altered string. Because the conversion is made in place, the + * returned pointer is the same as the passed one. */ -char* strupr(char* s); +char* strupr(char* s); -/* Convert a string to lowercase, then return pointer to - * the altered string. Because the conversion is made in place, the - * returned pointer is the same as the passed one. +/** Convert a string to lowercase, then return pointer to + * the altered string. Because the conversion is made in place, the + * returned pointer is the same as the passed one. */ -char* strlwr(char* s); +char* strlwr(char* s); -/* Copy not more than "n" characters from string "s2" into "s1" - * and return the result, which is always null-terminated. - * NOTE: The difference of this function from standard strncpy() is in - * that the result is always null-terminated and that the function does not - * pad "s1" with null bytes should "s2" be shorter than "n" characters. +/** Copy not more than "n" characters from string "s2" into "s1" + * and return the result, which is always null-terminated. + * NOTE: The difference of this function from standard strncpy() is in + * that the result is always null-terminated and that the function does not + * pad "s1" with null bytes should "s2" be shorter than "n" characters. */ NCBI_XCONNECT_EXPORT char* strncpy0(char* s1, const char* s2, size_t n); +#ifndef HAVE_MEMCCHR + +#ifdef memcchr +# undef memcchr +#endif +#define memcchr NCBI_memcchr + +/** Find the address of the first occurrence of a byte that is NOT char "c" + * within the "n" bytes of memory at the address "s". Return NULL if all + * bytes are "c". + */ +void* memcchr(const void* s, int c, size_t n); + +#endif /*!HAVE_MEMCCHR*/ + + #ifndef HAVE_MEMRCHR #ifdef memrchr # undef memrchr #endif -#define memrchr NCBI_memrchr +#define memrchr NCBI_memrchr -/* Find address of the last occurrence of char "c" within "n" bytes of a memory - * block beginning at the address "s". Return NULL if no such byte is found. +/** Find the address of the last occurrence of char "c" within "n" bytes of a + * memory block of size "n" beginning at the address "s". Return NULL if no + * such byte is found. */ -void* memrchr(const void* s, int c, size_t n); +void* memrchr(const void* s, int c, size_t n); -#endif/*!HAVE_MEMRCHR*/ +#endif /*!HAVE_MEMRCHR*/ -/* Locale-independent double-to-ASCII conversion of value "f" into a character - * buffer pointed to by "s", with a specified precision (mantissa digits) "p". - * There is an internal limit on precision (so larger values of "p" will be - * silently truncated). The maximal representable whole part corresponds to - * the maximal signed long integer. Otherwise, the behavior is undefined. - * Return the pointer past the output string (points to the terminating '\0'). +/** Locale-independent double-to-ASCII conversion of value "f" into a character + * buffer pointed to by "s", with a specified precision (mantissa digits) "p". + * There is an internal limit on precision (so larger values of "p" will be + * silently truncated). The maximal representable whole part corresponds to + * the maximal signed long integer. Otherwise, the behavior is undefined. + * Return the pointer past the output string (points to the terminating '\0'). */ NCBI_XCONNECT_EXPORT char* NCBI_simple_ftoa(char* s, double f, int p); -/* Locale-independent ASCII-to-double conversion of string "s". Does not work - * for scientific notation (values including exponent). Sets "e" to point to - * the character that stopped conversion. Clears "errno" but sets it non-zero - * in case of conversion errors. Maximal value for the whole part may not - * exceed the maximal signed long integer, and for mantissa -- unsigned long - * integer. - * Returns the result of conversion (on error sets errno, returns 0.0). - * @note e == s upon return if no valid input was found and consumed. +/** Locale-independent ASCII-to-double conversion of string "s". Does not work + * for scientific notation (values including exponent). Sets "e" to point to + * the character that stopped conversion. Clears "errno" but sets it non-zero + * in case of conversion errors. Maximal value for the whole part may not + * exceed the maximal signed long integer, and for mantissa -- unsigned long + * integer. + * Returns result of the conversion (on error sets errno, returns 0.0). + * @note e == s upon return if no valid input was found and consumed. */ NCBI_XCONNECT_EXPORT double NCBI_simple_atof(const char* s, char** e); diff --git a/c++/src/connect/ncbi_assert.h b/c++/src/connect/ncbi_assert.h index e0bacae1..9e8aaa12 100644 --- a/c++/src/connect/ncbi_assert.h +++ b/c++/src/connect/ncbi_assert.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_ASSERT__H #define CONNECT___NCBI_ASSERT__H -/* $Id: ncbi_assert.h 450208 2014-10-23 15:47:44Z vakatov $ +/* $Id: ncbi_assert.h 534369 2017-04-26 19:28:37Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -30,6 +30,7 @@ * * File Description: * Run-time debugging + * */ #include "ncbi_config.h" @@ -47,7 +48,7 @@ #if defined(NDEBUG) # define verify(expr) while ( expr ) break #else -# define verify(expr) assert(expr) +# define verify(expr) assert( expr ) #endif #endif /* CONNECT___NCBI_ASSERT__H */ diff --git a/c++/src/connect/ncbi_comm.h b/c++/src/connect/ncbi_comm.h index ba4db432..476aeaef 100644 --- a/c++/src/connect/ncbi_comm.h +++ b/c++/src/connect/ncbi_comm.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_COMM__H #define CONNECT___NCBI_COMM__H -/* $Id: ncbi_comm.h 516330 2016-10-12 17:20:46Z ivanov $ +/* $Id: ncbi_comm.h 515657 2016-10-04 18:51:51Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/connect/ncbi_conn_stream.cpp b/c++/src/connect/ncbi_conn_stream.cpp index 93319bb2..9fdedb68 100644 --- a/c++/src/connect/ncbi_conn_stream.cpp +++ b/c++/src/connect/ncbi_conn_stream.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_conn_stream.cpp 507385 2016-07-18 22:38:48Z lavr $ +/* $Id: ncbi_conn_stream.cpp 547023 2017-09-25 17:18:32Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -52,13 +52,13 @@ BEGIN_NCBI_SCOPE CConn_IOStream::CConn_IOStream(const TConn_Pair& connpair, const STimeout* timeout, - size_t buf_size, TConn_Flags flags, + size_t buf_size, TConn_Flags flgs, CT_CHAR_TYPE* ptr, size_t size) : CNcbiIostream(0), m_CSb(0) { auto_ptr csb(new CConn_Streambuf(connpair.first, connpair.second, - timeout, buf_size, flags, ptr, size)); + timeout, buf_size, flgs, ptr, size)); CONN conn = csb->GetCONN(); if (conn) { SOCK s/*dummy*/; @@ -76,13 +76,12 @@ CConn_IOStream::CConn_IOStream(const TConn_Pair& connpair, CConn_IOStream::CConn_IOStream(CONN conn, bool close, const STimeout* timeout, - size_t buf_size, TConn_Flags flags, + size_t buf_size, TConn_Flags flgs, CT_CHAR_TYPE* ptr, size_t size) : CNcbiIostream(0), m_CSb(0) { auto_ptr - csb(new CConn_Streambuf(conn, close, - timeout, buf_size, flags, ptr, size)); + csb(new CConn_Streambuf(conn, close, timeout, buf_size, flgs, ptr, size)); if (conn) { SOCK s/*dummy*/; // NB: CONN_Write(0 bytes) could have caused the same effect as GetSOCK @@ -237,7 +236,7 @@ CConn_SocketStream::CConn_SocketStream(const string& host, unsigned short port, const void* data, size_t size, - TSOCK_Flags flags, + TSOCK_Flags flgs, unsigned short max_try, const STimeout* timeout, size_t buf_size) @@ -246,7 +245,7 @@ CConn_SocketStream::CConn_SocketStream(const string& host, max_try, data, size, - flags), + flgs), eIO_Unknown), timeout, buf_size) { @@ -273,30 +272,30 @@ s_SocketConnectorBuilder(const SConnNetInfo* net_info, const STimeout* timeout, const void* data, size_t size, - TSOCK_Flags flags) + TSOCK_Flags flgs) { EIO_Status status = eIO_Success; bool proxy = false; SOCK sock = 0; _ASSERT(net_info); - if ((flags & (fSOCK_LogOn | fSOCK_LogDefault)) == fSOCK_LogDefault + if ((flgs & (fSOCK_LogOn | fSOCK_LogDefault)) == fSOCK_LogDefault && net_info->debug_printout == eDebugPrintout_Data) { - flags &= ~fSOCK_LogDefault; - flags |= fSOCK_LogOn; + flgs &= ~fSOCK_LogDefault; + flgs |= fSOCK_LogOn; } if (net_info->http_proxy_host[0] && net_info->http_proxy_port) { status = HTTP_CreateTunnel(net_info, fHTTP_NoAutoRetry, &sock); _ASSERT(!sock ^ !(status != eIO_Success)); if (status == eIO_Success - && (size || (flags & ~(fSOCK_LogOn | fSOCK_LogDefault)))) { + && (size || (flgs & ~(fSOCK_LogOn | fSOCK_LogDefault)))) { SSOCK_Init init; memset(&init, 0, sizeof(init)); init.data = data; init.size = size; init.cred = net_info->credentials; SOCK s; - status = SOCK_CreateOnTopInternal(sock, 0, &s, &init, flags); + status = SOCK_CreateOnTopInternal(sock, 0, &s, &init, flgs); _ASSERT(!s ^ !(status != eIO_Success)); SOCK_Destroy(sock); sock = s; @@ -338,7 +337,7 @@ s_SocketConnectorBuilder(const SConnNetInfo* net_info, init.size = size; init.cred = net_info->credentials; status = SOCK_CreateInternal(net_info->host, net_info->port, timeout, - &sock, &init, flags); + &sock, &init, flgs); _ASSERT(!sock ^ !(status != eIO_Success)); } string hostport(net_info->host); @@ -359,11 +358,11 @@ s_SocketConnectorBuilder(const SConnNetInfo* net_info, CConn_SocketStream::CConn_SocketStream(const SConnNetInfo& net_info, const void* data, size_t size, - TSOCK_Flags flags, + TSOCK_Flags flgs, const STimeout* timeout, size_t buf_size) : CConn_IOStream(s_SocketConnectorBuilder(&net_info, timeout, - data, size, flags), + data, size, flgs), timeout, buf_size) { return; @@ -412,7 +411,7 @@ struct Deleter static CConn_IOStream::TConn_Pair s_HttpConnectorBuilder(const SConnNetInfo* net_info, - EReqMethod method, + TReqMethod method, const char* url, const char* host, unsigned short port, @@ -423,7 +422,7 @@ s_HttpConnectorBuilder(const SConnNetInfo* net_info, FHTTP_Adjust adjust, FHTTP_Cleanup cleanup, FHTTP_ParseHeader parse_header, - THTTP_Flags flags, + THTTP_Flags flgs, const STimeout* timeout) { size_t len; @@ -474,7 +473,7 @@ s_HttpConnectorBuilder(const SConnNetInfo* net_info, if (timeout != kDefaultTimeout) x_net_info->timeout = timeout; CONNECTOR c = HTTP_CreateConnectorEx(x_net_info.get(), - flags, + flgs, parse_header, user_data, adjust, @@ -488,7 +487,7 @@ CConn_HttpStream::CConn_HttpStream(const string& host, const string& args, const string& user_header, unsigned short port, - THTTP_Flags flags, + THTTP_Flags flgs, const STimeout* timeout, size_t buf_size) : CConn_IOStream(s_HttpConnectorBuilder(0, @@ -503,7 +502,7 @@ CConn_HttpStream::CConn_HttpStream(const string& host, 0, 0, x_ParseHeader, - flags, + flgs, timeout), timeout, buf_size), m_UserData(0), m_UserAdjust(0), m_UserCleanup(0), m_UserParseHeader(0) @@ -513,7 +512,7 @@ CConn_HttpStream::CConn_HttpStream(const string& host, CConn_HttpStream::CConn_HttpStream(const string& url, - THTTP_Flags flags, + THTTP_Flags flgs, const STimeout* timeout, size_t buf_size) : CConn_IOStream(s_HttpConnectorBuilder(0, @@ -528,7 +527,7 @@ CConn_HttpStream::CConn_HttpStream(const string& url, 0, 0, x_ParseHeader, - flags, + flgs, timeout), timeout, buf_size), m_UserData(0), m_UserAdjust(0), m_UserCleanup(0), m_UserParseHeader(0) @@ -540,7 +539,7 @@ CConn_HttpStream::CConn_HttpStream(const string& url, CConn_HttpStream::CConn_HttpStream(const string& url, EReqMethod method, const string& user_header, - THTTP_Flags flags, + THTTP_Flags flgs, const STimeout* timeout, size_t buf_size) : CConn_IOStream(s_HttpConnectorBuilder(0, @@ -555,7 +554,7 @@ CConn_HttpStream::CConn_HttpStream(const string& url, 0, 0, x_ParseHeader, - flags, + flgs, timeout), timeout, buf_size), m_UserData(0), m_UserAdjust(0), m_UserCleanup(0), m_UserParseHeader(0) @@ -571,7 +570,7 @@ CConn_HttpStream::CConn_HttpStream(const string& url, void* user_data, FHTTP_Adjust adjust, FHTTP_Cleanup cleanup, - THTTP_Flags flags, + THTTP_Flags flgs, const STimeout* timeout, size_t buf_size) : CConn_IOStream(s_HttpConnectorBuilder(net_info, @@ -586,7 +585,7 @@ CConn_HttpStream::CConn_HttpStream(const string& url, adjust ? x_Adjust : 0, cleanup ? x_Cleanup : 0, x_ParseHeader, - flags, + flgs, timeout), timeout, buf_size), m_UserData(user_data), m_UserAdjust(adjust), @@ -602,7 +601,7 @@ CConn_HttpStream::CConn_HttpStream(const SConnNetInfo* net_info, void* user_data, FHTTP_Adjust adjust, FHTTP_Cleanup cleanup, - THTTP_Flags flags, + THTTP_Flags flgs, const STimeout* timeout, size_t buf_size) : CConn_IOStream(s_HttpConnectorBuilder(net_info, @@ -617,7 +616,7 @@ CConn_HttpStream::CConn_HttpStream(const SConnNetInfo* net_info, adjust ? x_Adjust : 0, cleanup ? x_Cleanup : 0, x_ParseHeader, - flags, + flgs, timeout), timeout, buf_size), m_UserData(user_data), m_UserAdjust(adjust), @@ -642,14 +641,15 @@ EIO_Status CConn_HttpStream::Fetch(const STimeout* timeout) } // NB: must never be upcalled (directly or indirectly) from any stream ctor -// for SHTTP_StatusData may yet be unbuilt (and the text field invalid)! +// for SHTTP_StatusData may yet be unbuilt (and the header field invalid)! static EHTTP_HeaderParse s_ParseHttpHeader(const char* header, SHTTP_StatusData& data) { int c, n; + data.header = header; if (sscanf(header, "%*s %u%n", &c, &n) < 1) return eHTTP_HeaderError; - const char* str = header + n; + const char* str = data.header.c_str() + n; str += strspn(str, " \t"); const char* eol = strchr(str, '\n'); if (!eol) @@ -758,7 +758,7 @@ CConn_ServiceStream::CConn_ServiceStream(const string& service, net_info, 0, // user_header extra, - &m_CBData, + &m_CBD, extra && extra->reset ? x_Reset : 0, extra && extra->adjust @@ -786,7 +786,7 @@ CConn_ServiceStream::CConn_ServiceStream(const string& service, 0, //net_info user_header.c_str(), extra, - &m_CBData, + &m_CBD, extra && extra->reset ? x_Reset : 0, extra && extra->adjust @@ -969,23 +969,23 @@ void CConn_MemoryStream::ToVector(vector* vec) static CConn_IOStream::TConn_Pair s_PipeConnectorBuilder(const string& cmd, const vector& args, - CPipe::TCreateFlags flags, + CPipe::TCreateFlags flgs, size_t pipe_size, CPipe*& pipe) { pipe = new CPipe(pipe_size); - CONNECTOR c = PIPE_CreateConnector(cmd, args, flags, pipe, eNoOwnership); + CONNECTOR c = PIPE_CreateConnector(cmd, args, flgs, pipe, eNoOwnership); return CConn_IOStream::TConn_Pair(c, eIO_Unknown); } CConn_PipeStream::CConn_PipeStream(const string& cmd, const vector& args, - CPipe::TCreateFlags flags, + CPipe::TCreateFlags flgs, size_t pipe_size, const STimeout* timeout, size_t buf_size) - : CConn_IOStream(s_PipeConnectorBuilder(cmd, args, flags, pipe_size, + : CConn_IOStream(s_PipeConnectorBuilder(cmd, args, flgs, pipe_size, m_Pipe), timeout, buf_size), m_ExitCode(-1) { @@ -1028,7 +1028,7 @@ CConn_NamedPipeStream::CConn_NamedPipeStream(const string& pipename, static CConn_IOStream::TConn_Pair s_FtpConnectorBuilder(const SConnNetInfo* net_info, - TFTP_Flags flag, + TFTP_Flags flgs, const SFTP_Callback* cmcb, const STimeout* timeout) { @@ -1043,7 +1043,7 @@ s_FtpConnectorBuilder(const SConnNetInfo* net_info, x_net_info = xx_net_info; } else x_net_info = net_info; - CONNECTOR c = FTP_CreateConnector(x_net_info, flag, cmcb); + CONNECTOR c = FTP_CreateConnector(x_net_info, flgs, cmcb); if (x_net_info != net_info) ConnNetInfo_Destroy((SConnNetInfo*) x_net_info); return CConn_IOStream::TConn_Pair(c, eIO_Unknown); @@ -1062,7 +1062,7 @@ CConn_FtpStream::CConn_FtpStream(const string& host, const string& pass, const string& path, unsigned short port, - TFTP_Flags flag, + TFTP_Flags flgs, const SFTP_Callback* cmcb, const STimeout* timeout, size_t buf_size) @@ -1071,7 +1071,7 @@ CConn_FtpStream::CConn_FtpStream(const string& host, user.c_str(), pass.c_str(), path.c_str(), - flag, + flgs, cmcb), eIO_Unknown), timeout, buf_size, @@ -1082,12 +1082,12 @@ CConn_FtpStream::CConn_FtpStream(const string& host, CConn_FtpStream::CConn_FtpStream(const SConnNetInfo& net_info, - TFTP_Flags flag, + TFTP_Flags flgs, const SFTP_Callback* cmcb, const STimeout* timeout, size_t buf_size) : CConn_IOStream(s_FtpConnectorBuilder(&net_info, - flag, + flgs, cmcb, timeout), timeout, buf_size, @@ -1137,12 +1137,12 @@ CConn_FTPDownloadStream::CConn_FTPDownloadStream(const string& host, const string& pass, const string& path, unsigned short port, - TFTP_Flags flag, + TFTP_Flags flgs, const SFTP_Callback* cmcb, Uint8 offset, const STimeout* timeout, size_t buf_size) - : CConn_FtpStream(host, user, pass, path, port, flag, cmcb, + : CConn_FtpStream(host, user, pass, path, port, flgs, cmcb, timeout, buf_size) { if (!file.empty()) @@ -1151,12 +1151,12 @@ CConn_FTPDownloadStream::CConn_FTPDownloadStream(const string& host, CConn_FTPDownloadStream::CConn_FTPDownloadStream(const SConnNetInfo& net_info, - TFTP_Flags flag, + TFTP_Flags flgs, const SFTP_Callback* cmcb, Uint8 offset, const STimeout* timeout, size_t buf_size) - : CConn_FtpStream(net_info, flag | fFTP_IgnorePath, cmcb, + : CConn_FtpStream(net_info, flgs | fFTP_IgnorePath, cmcb, timeout, buf_size) { if (net_info.path[0]) @@ -1190,10 +1190,10 @@ CConn_FTPUploadStream::CConn_FTPUploadStream(const string& host, const string& file, const string& path, unsigned short port, - TFTP_Flags flag, + TFTP_Flags flgs, Uint8 offset, const STimeout* timeout) - : CConn_FtpStream(host, user, pass, path, port, flag, 0/*cmcb*/, + : CConn_FtpStream(host, user, pass, path, port, flgs, 0/*cmcb*/, timeout) { if (!file.empty()) @@ -1202,10 +1202,10 @@ CConn_FTPUploadStream::CConn_FTPUploadStream(const string& host, CConn_FTPUploadStream::CConn_FTPUploadStream(const SConnNetInfo& net_info, - TFTP_Flags flag, + TFTP_Flags flgs, Uint8 offset, const STimeout* timeout) - : CConn_FtpStream(net_info, flag | fFTP_IgnorePath, 0/*cmcb*/, + : CConn_FtpStream(net_info, flgs | fFTP_IgnorePath, 0/*cmcb*/, timeout) { if (net_info.path[0]) diff --git a/c++/src/connect/ncbi_conn_streambuf.cpp b/c++/src/connect/ncbi_conn_streambuf.cpp index 40013597..08b02fb6 100644 --- a/c++/src/connect/ncbi_conn_streambuf.cpp +++ b/c++/src/connect/ncbi_conn_streambuf.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_conn_streambuf.cpp 463881 2015-04-01 21:51:06Z lavr $ +/* $Id: ncbi_conn_streambuf.cpp 530261 2017-03-13 17:05:56Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -71,7 +71,7 @@ CConn_Streambuf::CConn_Streambuf(CONNECTOR connector, EIO_Status status, const STimeout* timeout, size_t buf_size, - CConn_IOStream::TConn_Flags flags, + CConn_IOStream::TConn_Flags flgs, CT_CHAR_TYPE* ptr, size_t size) : m_Conn(0), m_WriteBuf(0), m_ReadBuf(&x_Buf), m_BufSize(1), @@ -84,8 +84,8 @@ CConn_Streambuf::CConn_Streambuf(CONNECTOR connector, ERR_POST_X(2, x_Message("CConn_Streambuf(): NULL connector")); return; } - if ((flags & (CConn_IOStream::fConn_Untie | - CConn_IOStream::fConn_WriteBuffered)) + if ((flgs & (CConn_IOStream::fConn_Untie | + CConn_IOStream::fConn_WriteBuffered)) == CConn_IOStream::fConn_WriteBuffered && buf_size) { m_Tie = true; } @@ -93,13 +93,13 @@ CConn_Streambuf::CConn_Streambuf(CONNECTOR connector, | (m_Tie ? 0 : fCONN_Untie), &m_Conn)) != eIO_Success) { ERR_POST_X(3, x_Message("CConn_Streambuf(): CONN_Create() failed")); - _ASSERT(!connector->meta && !connector->next); + _ASSERT(!m_Conn && !connector->meta && !connector->next); if (connector->destroy) connector->destroy(connector); return; } _ASSERT(m_Conn); - x_Init(timeout, buf_size, flags, ptr, size); + x_Init(timeout, buf_size, flgs, ptr, size); } @@ -107,7 +107,7 @@ CConn_Streambuf::CConn_Streambuf(CONN conn, bool close, const STimeout* timeout, size_t buf_size, - CConn_IOStream::TConn_Flags flags, + CConn_IOStream::TConn_Flags flgs, CT_CHAR_TYPE* ptr, size_t size) : m_Conn(conn), m_WriteBuf(0), m_ReadBuf(&x_Buf), m_BufSize(1), @@ -119,12 +119,12 @@ CConn_Streambuf::CConn_Streambuf(CONN conn, ERR_POST_X(1, x_Message("CConn_Streambuf(): NULL connection")); return; } - if ((flags & (CConn_IOStream::fConn_Untie | - CConn_IOStream::fConn_WriteBuffered)) + if ((flgs & (CConn_IOStream::fConn_Untie | + CConn_IOStream::fConn_WriteBuffered)) == CConn_IOStream::fConn_WriteBuffered && buf_size) { m_Tie = true; } - x_Init(timeout, buf_size, flags, ptr, size); + x_Init(timeout, buf_size, flgs, ptr, size); } @@ -136,7 +136,7 @@ EIO_Status CConn_Streambuf::Status(EIO_Event direction) const void CConn_Streambuf::x_Init(const STimeout* timeout, size_t buf_size, - CConn_IOStream::TConn_Flags flags, + CConn_IOStream::TConn_Flags flgs, CT_CHAR_TYPE* ptr, size_t size) { _ASSERT(m_Status == eIO_Success); @@ -147,23 +147,23 @@ void CConn_Streambuf::x_Init(const STimeout* timeout, size_t buf_size, _VERIFY(CONN_SetTimeout(m_Conn, eIO_Close, timeout) ==eIO_Success); } - if (!(flags & (CConn_IOStream::fConn_ReadBuffered | - CConn_IOStream::fConn_WriteBuffered))) { + if (!(flgs & (CConn_IOStream::fConn_ReadBuffered | + CConn_IOStream::fConn_WriteBuffered))) { buf_size = 0; } if (buf_size) { m_WriteBuf = new CT_CHAR_TYPE[buf_size - << ((flags & (CConn_IOStream::fConn_ReadBuffered | - CConn_IOStream::fConn_WriteBuffered)) - == (CConn_IOStream::fConn_ReadBuffered | - CConn_IOStream::fConn_WriteBuffered) + << ((flgs & (CConn_IOStream::fConn_ReadBuffered | + CConn_IOStream::fConn_WriteBuffered)) + == (CConn_IOStream::fConn_ReadBuffered | + CConn_IOStream::fConn_WriteBuffered) ? 1 : 0)]; - if (flags & CConn_IOStream::fConn_ReadBuffered) + if (flgs & CConn_IOStream::fConn_ReadBuffered) m_BufSize = buf_size; - if (!(flags & CConn_IOStream::fConn_WriteBuffered)) + if (!(flgs & CConn_IOStream::fConn_WriteBuffered)) buf_size = 0; - if (flags & CConn_IOStream::fConn_ReadBuffered) + if (flgs & CConn_IOStream::fConn_ReadBuffered) m_ReadBuf = m_WriteBuf + buf_size; } /* else see ctor */ @@ -385,7 +385,7 @@ CT_INT_TYPE CConn_Streambuf::underflow(void) return CT_EOF; // flush output buffer, if tied up to it - if (m_Tie && x_sync() != 0) + if (m_Tie && x_Sync() != 0) return CT_EOF; #ifdef NCBI_COMPILER_MIPSPRO @@ -414,13 +414,12 @@ CT_INT_TYPE CConn_Streambuf::underflow(void) } -streamsize CConn_Streambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m) +streamsize CConn_Streambuf::x_Read(CT_CHAR_TYPE* buf, streamsize m) { - if (!m_Conn) - return 0; + _ASSERT(m_Conn); // flush output buffer, if tied up to it - if (m_Tie && x_sync() != 0) + if (m_Tie && x_Sync() != 0) return 0; if (m < 0) @@ -435,19 +434,21 @@ streamsize CConn_Streambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m) n_read = (size_t)(egptr() - gptr()); if (n_read > n) n_read = n; - memcpy(buf, gptr(), n_read); + if (buf) + memcpy(buf, gptr(), n_read); gbump(int(n_read)); - n -= n_read; + n -= n_read; if (!n) return (streamsize) n_read; - buf += n_read; + if (buf) + buf += n_read; } else n_read = 0; do { // next, read from the connection - size_t x_toread = n && n < m_BufSize ? m_BufSize : n; - CT_CHAR_TYPE* x_buf = n < m_BufSize ? m_ReadBuf : buf; + size_t x_toread = !buf || (n && n < m_BufSize) ? m_BufSize : n; + CT_CHAR_TYPE* x_buf = !buf || ( n < m_BufSize) ? m_ReadBuf : buf; size_t x_read; m_Status = CONN_Read(m_Conn, x_buf, x_toread, @@ -465,7 +466,8 @@ streamsize CConn_Streambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m) size_t xx_read = x_read; if (x_read > n) x_read = n; - memcpy(buf, m_ReadBuf, x_read); + if (buf) + memcpy(buf, m_ReadBuf, x_read); setg(m_ReadBuf, m_ReadBuf + x_read, m_ReadBuf + xx_read); } else { _ASSERT(x_read <= n); @@ -473,17 +475,24 @@ streamsize CConn_Streambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m) memcpy(m_ReadBuf, buf + x_read - xx_read, xx_read); setg(m_ReadBuf, m_ReadBuf + xx_read, m_ReadBuf + xx_read); } - n_read += x_read; + n_read += x_read; if (m_Status != eIO_Success) break; - buf += x_read; - n -= x_read; + if (buf) + buf += x_read; + n -= x_read; } while (n); return (streamsize) n_read; } +streamsize CConn_Streambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m) +{ + return m_Conn ? x_Read(buf, m) : 0; +} + + streamsize CConn_Streambuf::showmanyc(void) { static const STimeout kZeroTmo = {0, 0}; @@ -495,7 +504,7 @@ streamsize CConn_Streambuf::showmanyc(void) // flush output buffer, if tied up to it if (m_Tie) - x_sync(); + x_Sync(); const STimeout* tmo; const STimeout* timeout = CONN_GetTimeout(m_Conn, eIO_Read); @@ -571,16 +580,21 @@ CT_POS_TYPE CConn_Streambuf::seekoff(CT_OFF_TYPE off, IOS_BASE::seekdir whence, IOS_BASE::openmode which) { - if (m_Conn && off == 0 && whence == IOS_BASE::cur) { - // tellp()/tellg() support only + if (whence == IOS_BASE::cur && off == 0) { + // tellg()/tellp() support switch (which) { - case IOS_BASE::out: - return x_PPos + (CT_OFF_TYPE)(pptr() - pbase()); case IOS_BASE::in: - return x_GPos - (CT_OFF_TYPE)(egptr() - gptr()); + return x_GetGPos(); + case IOS_BASE::out: + return x_GetPPos(); default: break; } + } else if (which == IOS_BASE::in + && ((whence == IOS_BASE::cur && (off > 0)) || + (whence == IOS_BASE::beg && (off -= x_GetGPos()) >= 0))){ + if (m_Conn && x_Read(0, (streamsize) off) == (streamsize) off) + return x_GetGPos(); } return (CT_POS_TYPE)((CT_OFF_TYPE)(-1L)); } diff --git a/c++/src/connect/ncbi_conn_streambuf.hpp b/c++/src/connect/ncbi_conn_streambuf.hpp index 77df368e..cac0bdec 100644 --- a/c++/src/connect/ncbi_conn_streambuf.hpp +++ b/c++/src/connect/ncbi_conn_streambuf.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CONN_STREAMBUF__HPP #define CONNECT___NCBI_CONN_STREAMBUF__HPP -/* $Id: ncbi_conn_streambuf.hpp 463569 2015-03-30 16:23:11Z lavr $ +/* $Id: ncbi_conn_streambuf.hpp 530261 2017-03-13 17:05:56Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -77,7 +77,11 @@ protected: // this method is declared here to be disabled (exception) at run-time virtual CNcbiStreambuf* setbuf(CT_CHAR_TYPE* buf, streamsize buf_size); - // only seekoff(0, IOS_BASE::cur) is permitted (to obtain current position) + /// Only seekoff(0, IOS_BASE::cur, *) to obtain current position, and input + /// skip-forward are permitted: + /// seekoff(off, IOS_BASE::cur or IOS_BASE::beg, IOS_BASE::in) when the + /// requested stream position is past the current input position (so the + /// stream can read forward internally to reach that position). virtual CT_POS_TYPE seekoff(CT_OFF_TYPE off, IOS_BASE::seekdir whence, IOS_BASE::openmode which = IOS_BASE::in | IOS_BASE::out); @@ -95,9 +99,17 @@ protected: #endif /*NCBI_OS_MSWIN*/ protected: - int x_sync(void) + CT_POS_TYPE x_GetGPos(void) + { return x_GPos - (CT_OFF_TYPE)(egptr() - gptr()); } + + CT_POS_TYPE x_GetPPos(void) + { return x_PPos + (CT_OFF_TYPE)(pptr() - pbase()); } + + int x_Sync(void) { return pbase() < pptr() ? sync() : 0; } + streamsize x_Read(CT_CHAR_TYPE* buf, streamsize n); + private: CONN m_Conn; // underlying connection handle diff --git a/c++/src/connect/ncbi_conn_test.cpp b/c++/src/connect/ncbi_conn_test.cpp index df065c73..55c7af5e 100644 --- a/c++/src/connect/ncbi_conn_test.cpp +++ b/c++/src/connect/ncbi_conn_test.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_conn_test.cpp 516329 2016-10-12 17:20:25Z ivanov $ +/* $Id: ncbi_conn_test.cpp 533072 2017-04-12 19:09:37Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -141,7 +141,7 @@ string CConnTest::x_TimeoutMsg(void) int n = ::sprintf(tmo, "%u", m_Timeout->sec); if (m_Timeout->usec) ::sprintf(tmo + n, ".%06u", m_Timeout->usec); - string result("Make sure the specified timeout value "); + string result("Make sure the specified timeout value of "); result += tmo; result += "s is adequate for your network throughput\n"; return result; @@ -310,8 +310,9 @@ EIO_Status CConnTest::ExtraCheckOnFailure(void) ::sprintf(net_info->path, "/NcbiTest%08lX%08lX", (unsigned long) sec, (unsigned long) nanosec); + size_t n; vector< AutoPtr > http; - for (size_t n = 0; n < sizeof(kTests) / sizeof(kTests[0]); ++n) { + for (n = 0; n < sizeof(kTests) / sizeof(kTests[0]); ++n) { char user_header[80]; net_info->scheme = kTests[n].scheme; const char* host = kTests[n].host; @@ -360,7 +361,7 @@ EIO_Status CConnTest::ExtraCheckOnFailure(void) } } while (status != eIO_Interrupt && !deadline.IsExpired()); - if (status == eIO_Success && http.size()) + if (status == eIO_Success && http.size() == n) status = eIO_Timeout; PostCheck(eNone, 0/*main*/, status, kEmptyStr); @@ -1146,7 +1147,7 @@ static inline unsigned int ud(time_t one, time_t two) } -static size_t rnd(size_t minimal, size_t maximal) +static inline size_t rnd(size_t minimal, size_t maximal) { return minimal <= maximal ? minimal + rand() % (maximal - minimal + 1) : 0; } @@ -1399,9 +1400,9 @@ EIO_Status CConnTest::x_CheckTrap(string* reason) bool CConnTest::IsNcbiInhouseClient(void) { static const STimeout kFast = { 2, 0 }; - CConn_HttpStream http("/Service/getenv.cgi", + CConn_HttpStream http("https:///Service/getenv.cgi", fHTTP_KeepHeader | fHTTP_NoAutoRetry, &kFast); - char line[1024]; + char line[256]; if (!http || !http.getline(line, sizeof(line))) return false; int code; diff --git a/c++/src/connect/ncbi_connection.c b/c++/src/connect/ncbi_connection.c index a81caf22..93a12d03 100644 --- a/c++/src/connect/ncbi_connection.c +++ b/c++/src/connect/ncbi_connection.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_connection.c 513293 2016-09-09 11:36:15Z ivanov $ +/* $Id: ncbi_connection.c 532676 2017-04-07 14:32:22Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -253,7 +253,7 @@ static EIO_Status x_Flush(CONN conn, const STimeout* timeout) static EIO_Status x_ReInit(CONN conn, CONNECTOR connector, int/*bool*/ close) { - static const STimeout* timeout = 0/*dummy*/; + const STimeout* timeout = 0; EIO_Status status; CONNECTOR x_conn; @@ -289,9 +289,9 @@ static EIO_Status x_ReInit(CONN conn, CONNECTOR connector, int/*bool*/ close) /* call current connector's "CLOSE" method */ if (conn->meta.close) { EIO_Status closed; - const STimeout* timeout = (conn->c_timeout == kDefaultTimeout - ? conn->meta.default_timeout - : conn->c_timeout); + timeout = (conn->c_timeout == kDefaultTimeout + ? conn->meta.default_timeout + : conn->c_timeout); assert(timeout != kDefaultTimeout); closed = conn->meta.close(conn->meta.c_close, timeout); if (closed != eIO_Success) @@ -1041,16 +1041,16 @@ extern EIO_Status CONN_ReadLine status = s_CONN_Read(conn, x_buf, size ? x_size : 0, &x_read, 0); conn->r_status = status; - for (i = 0; i < x_read && len < size; i++) { + for (i = 0; i < x_read && len < size; ++i) { char c = x_buf[i]; if (c == '\n') { done = 1/*true*/; - i++; + ++i; break; } if (x_buf == w) line[len] = c; - len++; + ++len; } if (i < x_read) { assert(done || len >= size); diff --git a/c++/src/connect/ncbi_connector.c b/c++/src/connect/ncbi_connector.c index 166fbabc..8c716680 100644 --- a/c++/src/connect/ncbi_connector.c +++ b/c++/src/connect/ncbi_connector.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_connector.c 513293 2016-09-09 11:36:15Z ivanov $ +/* $Id: ncbi_connector.c 513232 2016-09-08 15:47:40Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/connect/ncbi_connssl.h b/c++/src/connect/ncbi_connssl.h index 7ae0ec2a..7682d872 100644 --- a/c++/src/connect/ncbi_connssl.h +++ b/c++/src/connect/ncbi_connssl.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CONNSSL__H #define CONNECT___NCBI_CONNSSL__H -/* $Id: ncbi_connssl.h 466061 2015-04-28 18:05:33Z lavr $ +/* $Id: ncbi_connssl.h 537331 2017-05-30 19:56:20Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -43,7 +43,8 @@ extern "C" { typedef enum { - eNcbiCred_GnuTls = 0x484FFB94 + eNcbiCred_GnuTls = 0x484FFB94, + eNcbiCred_MbedTls = 0xC12CC16C } ENcbiCred; @@ -67,8 +68,8 @@ struct SNcbiCred { typedef EIO_Status (*FSSLPull) (SOCK sock, void* buf, size_t size, size_t* done, int/*bool*/ logdata); -/* Write up to "size" bytes of "data", and return the number of bytes - * actually written via the "done" pointer (m.b. non-null, on call "*done"==0). +/* Write up to "size" bytes of "data", and return the number of bytes actually + * written via the "done" pointer (must be non-null, on call "*done"==0). * The call is allowed to log the transaction data if "logdata" is non-zero. * The call is always allowed to log errors (regardless of the last parameter). * Return: @@ -81,7 +82,7 @@ typedef EIO_Status (*FSSLPush) (SOCK sock, const void* data, size_t size, typedef EIO_Status (*FSSLInit) (FSSLPull pull, FSSLPush push); -typedef void* (*FSSLCreate)(ESOCK_Side side, SOCK sock, +typedef void* (*FSSLCreate)(ESOCK_Side side, SOCK sock, const char* host, NCBI_CRED cred, int* error); typedef EIO_Status (*FSSLOpen) (void* session, int* error, char** desc); @@ -100,21 +101,23 @@ typedef EIO_Status (*FSSLWrite) (void* session, const void* data, size_t size, typedef EIO_Status (*FSSLClose) (void* session, int how, int* error); typedef void (*FSSLDelete)(void* session); typedef void (*FSSLExit) (void); -typedef const char* (*FSSLError) (void* session, int error); +typedef const char* (*FSSLError) (void* session, int error, + char* buf, size_t size); /* Table of "virtual functions" */ struct SOCKSSL_struct { - FSSLInit Init; - FSSLCreate Create; - FSSLOpen Open; - FSSLRead Read; - FSSLWrite Write; - FSSLClose Close; - FSSLDelete Delete; - FSSLExit Exit; - FSSLError Error; + const char* Name; + FSSLInit Init; + FSSLCreate Create; + FSSLOpen Open; + FSSLRead Read; + FSSLWrite Write; + FSSLClose Close; + FSSLDelete Delete; + FSSLExit Exit; + FSSLError Error; }; diff --git a/c++/src/connect/ncbi_connutil.c b/c++/src/connect/ncbi_connutil.c index e0f3516c..59607bf7 100644 --- a/c++/src/connect/ncbi_connutil.c +++ b/c++/src/connect/ncbi_connutil.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_connutil.c 513930 2016-09-16 15:08:47Z ivanov $ +/* $Id: ncbi_connutil.c 533696 2017-04-18 21:33:46Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -85,7 +85,8 @@ static char* x_StrcatCRLF(char* dst, const char* src) } -static const char* x_GetValue(const char* service, const char* param, +static const char* x_GetValue(const char* svc, size_t svclen, + const char* param, char* value, size_t value_size, const char* def_value, int* /*bool*/ generic) { @@ -93,21 +94,19 @@ static const char* x_GetValue(const char* service, const char* param, const char* val; char* s; - if (!value || value_size <= 0) - return 0; - *value = '\0'; + assert(!svc || (*svc && svclen == strlen(svc))); + assert(param && *param); + assert(value && value_size > 0); - if (!param || !*param) - return 0; + *value = '\0'; *generic = 0/*false*/; - if (service && *service) { + if (svc) { /* Service-specific inquiry */ int/*bool*/ end; char temp[sizeof(buf)]; - size_t slen = strlen(service); size_t plen = strlen(param) + 1; - size_t len = slen + 1 + plen; + size_t len = svclen + 1 + plen; if (strncasecmp(param, DEF_CONN_REG_SECTION "_", sizeof(DEF_CONN_REG_SECTION)) != 0) { @@ -119,7 +118,7 @@ static const char* x_GetValue(const char* service, const char* param, return 0; /* First, environment search for 'service_CONN_param' */ - s = (char*) memcpy(buf, service, slen) + slen; + s = (char*) memcpy(buf, svc, svclen) + svclen; *s++ = '_'; if (!end) { memcpy(s, DEF_CONN_REG_SECTION, sizeof(DEF_CONN_REG_SECTION) - 1); @@ -137,8 +136,8 @@ static const char* x_GetValue(const char* service, const char* param, CORE_UNLOCK; /* Next, search for 'CONN_param' in '[service]' registry section */ - buf[slen++] = '\0'; - s = buf + slen; + buf[svclen++] = '\0'; + s = buf + svclen; CORE_REG_GET(buf, s, value, value_size, end ? def_value : 0); if (*value || end) return value; @@ -179,16 +178,22 @@ static const char* x_GetValue(const char* service, const char* param, } -static const char* s_GetValue(const char* service, const char* param, +static const char* s_GetValue(const char* svc, size_t len, const char* param, char* value, size_t value_size, const char* def_value, int* /*bool*/ generic) { - const char* retval = x_GetValue(service, param, - value, value_size, def_value, generic); + const char* retval; + + assert(!svc || (*svc && len == strlen(svc))); + assert(param && *param); + assert(value && value_size > 0); + + retval = x_GetValue(svc, len, param, + value, value_size, def_value, generic); if (retval) { /*strip enveloping quotes*/ - size_t len = strlen(value); - if (len > 1 && (value[0] == '"' || value[0] == '\'') + if ((len = strlen(value)) > 1 + && (value[0] == '"' || value[0] == '\'') && strchr(value + 1, value[0]) == value + len - 1) { if (len -= 2) memcpy(value, value + 1, len); @@ -196,6 +201,7 @@ static const char* s_GetValue(const char* service, const char* param, } assert(retval == value); } + return retval; } @@ -204,8 +210,30 @@ extern const char* ConnNetInfo_GetValue(const char* service, const char* param, char* value, size_t value_size, const char* def_value) { + const char* retval; int/*bool*/ dummy; - return s_GetValue(service, param, value, value_size, def_value, &dummy); + size_t len = 0; + + if (!value || value_size < 1) + return 0; + if (!param || !*param) + return 0; + + if (service) { + if (!*service) + service = 0; + else if (!(service = SERV_ServiceName(service))) + return 0; + else + verify((len = strlen(service))); + } + + retval = s_GetValue(service, len, param, + value, value_size, def_value, &dummy); + if (len) + free((void*) service); + + return retval; } @@ -300,7 +328,7 @@ static int/*bool*/ s_InfoIsValid(const SConnNetInfo* info) extern SConnNetInfo* ConnNetInfo_Create(const char* service) { #define REG_VALUE(name, value, def_value) \ - s_GetValue(service, name, value, sizeof(value), def_value, &generic) + s_GetValue(service, len, name, value, sizeof(value), def_value, &generic) int/*bool*/ generic; SConnNetInfo* info; @@ -311,7 +339,15 @@ extern SConnNetInfo* ConnNetInfo_Create(const char* service) double dbl; char* e; - len = service ? strlen(service) : 0; + if (service && *service) { + if (!(service = SERV_ServiceName(service))) + return 0; + assert(*service); + len = strlen(service); + } else { + len = 0; + service = 0; + } /* NB: created *NOT* cleared up with all 0s */ if (!(info = (SConnNetInfo*) malloc(sizeof(*info) + len))) @@ -319,7 +355,7 @@ extern SConnNetInfo* ConnNetInfo_Create(const char* service) info->reserved = 0/*MBZ*/; /* store the service name, which this structure has been created for */ - memcpy((char*) info->svc, service ? service : "", ++len); + memcpy((char*) info->svc, service ? service : "", len + 1); /* client host: default */ info->client_host[0] = '\0'; @@ -429,8 +465,8 @@ extern SConnNetInfo* ConnNetInfo_Create(const char* service) /* connection timeout */ REG_VALUE(REG_CONN_TIMEOUT, str, 0); - len = strlen(str); - if (len < 3 || 8 < len || strncasecmp(str, "infinite", len) != 0) { + val = (long) strlen(str); + if (val < 3 || 8 < val || strncasecmp(str, "infinite", val) != 0) { if (!*str || (dbl = NCBI_simple_atof(str, &e)) < 0.0 || errno || *e) dbl = DEF_CONN_TIMEOUT; info->tmo.sec = (unsigned int) dbl; @@ -456,6 +492,9 @@ extern SConnNetInfo* ConnNetInfo_Create(const char* service) /* magic */ info->magic = CONN_NET_INFO_MAGIC; + if (len) + free((void*) service); + /* done */ return info; #undef REG_VALUE @@ -493,7 +532,7 @@ extern int/*bool*/ ConnNetInfo_ParseURL(SConnNetInfo* info, const char* url) return 0/*failure*/; if (!port || port ^ (port & 0xFFFF)) return 0/*failure*/; - info->port = port; + info->port = (unsigned short) port; } if (len) { memcpy(info->host, url, len); @@ -520,7 +559,7 @@ extern int/*bool*/ ConnNetInfo_ParseURL(SConnNetInfo* info, const char* url) /* username:password */ if (!hostlen) { - user = pass = host = scheme == eURL_File ? "" : 0; + user = pass = host = (scheme == eURL_File ? "" : 0); userlen = passlen = 0; } else { if (!(s = (const char*) memrchr(host, '@', hostlen))) { @@ -644,7 +683,7 @@ extern int/*bool*/ ConnNetInfo_ParseURL(SConnNetInfo* info, const char* url) info->pass[passlen] = '\0'; } if (port >= 0 || scheme == eURL_File) - info->port = port < 0 ? 0 : port; + info->port = (unsigned short)(port < 0 ? 0 : port); if (host) { memcpy(info->host, host, hostlen); info->host[hostlen] = '\0'; @@ -1479,10 +1518,8 @@ extern char* ConnNetInfo_URL(const SConnNetInfo* info) req_method = info->req_method & ~eReqMethod_v1; scheme = x_Scheme((EURLScheme) info->scheme, buf); assert(!scheme || *scheme); - if ((!scheme && req_method != eReqMethod_Connect) || - ( scheme && !isalpha((unsigned char)(*scheme)))) { + if (scheme && !isalpha((unsigned char)(*scheme))) return 0/*failure*/; - } if (req_method == eReqMethod_Connect) { scheme = ""; @@ -1491,7 +1528,8 @@ extern char* ConnNetInfo_URL(const SConnNetInfo* info) args = ""; len = 0; } else { - assert(scheme); + if (!scheme) + scheme = ""; schlen = strlen(scheme); path = info->path; args = info->args; @@ -1504,7 +1542,11 @@ extern char* ConnNetInfo_URL(const SConnNetInfo* info) assert(scheme && args); strlwr((char*) memcpy(url, scheme, schlen + 1)); len = schlen; - len += sprintf(url + len, &"://%s"[schlen ? 0 : 3], info->host); + len += sprintf(url + len, &"://%s"[schlen + ? 0 + : req_method == eReqMethod_Connect + ? 3 + : 1], info->host); if (info->port || !path/*req_method == eReqMethod_Connect*/) len += sprintf(url + len, ":%hu", info->port); sprintf(url + len, "%s%s%s%s", @@ -1585,6 +1627,7 @@ extern EIO_Status URL_ConnectEx size_t hdr_len; size_t args_len; char temp[80]; + unsigned short x_port; EReqMethod x_req_meth; size_t user_hdr_len = user_hdr && *user_hdr ? strlen(user_hdr) : 0; @@ -1604,11 +1647,15 @@ extern EIO_Status URL_ConnectEx /*FIXME: the check to be removed*/ if (cred && cred < (NCBI_CRED) 4096) { + if (port) + sprintf(temp, ":%hu", port); + else + *temp = '\0'; CORE_LOGF(eLOG_Critical, - ("[URL_ConnectEx; http%s://%s:%hu%s%s] " + ("[URL_ConnectEx; http%s://%s%s%s%s] " " Obsolete feature 'encode_args' is no longer supported", &"s"[!(flags & fSOCK_Secure)], - host, port, &"/"[*path == '/'], path)); + host, temp, &"/"[*path == '/'], path)); return x_URLConnectErrorReturn(s, eIO_InvalidArg); } @@ -1632,30 +1679,40 @@ extern EIO_Status URL_ConnectEx x_req_meth = content_length ? eReqMethod_Post : eReqMethod_Get; else if (content_length && (x_req_meth == eReqMethod_Head || x_req_meth == eReqMethod_Get)) { + if (port) + sprintf(temp, ":%hu", port); + else + *temp = '\0'; CORE_LOGF_X(3, eLOG_Warning, - ("[URL_Connect; http%s://%s:%hu%s%s] " + ("[URL_Connect; http%s://%s%s%s%s] " " Content-Length (%lu) is ignored with request method %s", &"s"[!(flags & fSOCK_Secure)], - host, port, &"/"[*path == '/'], path, + host, temp, &"/"[*path == '/'], path, (unsigned long) content_length, x_req_meth == eReqMethod_Get ? "GET" : "HEAD")); content_length = 0; } if (!(str = x_ReqMethod(x_req_meth, 0))) { + char tmp[40]; + if (port) + sprintf(temp, ":%hu", port); + else + *temp = '\0'; CORE_LOGF_X(4, eLOG_Error, - ("[URL_Connect; http%s://%s:%hu%s%s] " + ("[URL_Connect; http%s://%s%s%s%s] " " Unsupported request method %s", &"s"[!(flags & fSOCK_Secure)], - host, port, &"/"[*path == '/'], path, - x_ReqMethod(req_method, temp))); + host, temp, &"/"[*path == '/'], path, + x_ReqMethod(req_method, tmp))); assert(0); return x_URLConnectErrorReturn(s, eIO_NotSupported); } + x_port = port; if (x_req_meth != eReqMethod_Connect) { - if (!port) - port = flags & fSOCK_Secure ? CONN_PORT_HTTPS : CONN_PORT_HTTP; + if (!x_port) + x_port = flags & fSOCK_Secure ? CONN_PORT_HTTPS : CONN_PORT_HTTP; args_len = args ? strcspn(args, "#") : 0; } else args_len = 0; @@ -1689,11 +1746,15 @@ extern EIO_Status URL_ConnectEx (x_req_meth == eReqMethod_Connect && content_length && !BUF_Write(&buf, args, content_length))) { int x_errno = errno; + if (port) + sprintf(temp, ":%hu", port); + else + *temp = '\0'; CORE_LOGF_ERRNO_X(5, eLOG_Error, x_errno, - ("[URL_Connect; http%s://%s:%hu%s%s%s%.*s] " + ("[URL_Connect; http%s://%s%s%s%s%s%.*s] " " Cannot build HTTP header", &"s"[!(flags & fSOCK_Secure)], - host, port, &"/"[*path == '/'], path, + host, temp, &"/"[*path == '/'], path, &"?"[!args_len], (int) args_len, args)); BUF_Destroy(buf); return x_URLConnectErrorReturn(s, eIO_Unknown); @@ -1702,11 +1763,15 @@ extern EIO_Status URL_ConnectEx if (!(hdr = (char*) malloc(hdr_len = BUF_Size(buf))) || BUF_Read(buf, hdr, hdr_len) != hdr_len) { int x_errno = errno; + if (port) + sprintf(temp, ":%hu", port); + else + *temp = '\0'; CORE_LOGF_ERRNO_X(6, eLOG_Error, x_errno, - ("[URL_Connect; http%s://%s:%hu%s%s%s%.*s] " + ("[URL_Connect; http%s://%s%s%s%s%s%.*s] " " Cannot maintain HTTP header (%lu byte%s)", &"s"[!(flags & fSOCK_Secure)], - host, port, &"/"[*path == '/'], path, + host, temp, &"/"[*path == '/'], path, &"?"[!args_len], (int) args_len, args, (unsigned long) hdr_len, &"s"[hdr_len == 1])); if (hdr) @@ -1728,27 +1793,32 @@ extern EIO_Status URL_ConnectEx SOCK_Destroy(s); } else { /* connect to HTTPD */ - status = SOCK_CreateInternal(host, port, o_timeout, sock/*new*/, + status = SOCK_CreateInternal(host, x_port, o_timeout, sock/*new*/, &init, flags); } free(hdr); if (status != eIO_Success) { + char timeout[40]; assert(!*sock); if (status == eIO_Timeout && o_timeout) { - sprintf(temp, "[%u.%06u]", + sprintf(timeout, "[%u.%06u]", (unsigned int)(o_timeout->sec + o_timeout->usec/1000000), (unsigned int) (o_timeout->usec%1000000)); } else + *timeout = '\0'; + if (port) + sprintf(temp, ":%hu", port); + else *temp = '\0'; CORE_LOGF_X(7, eLOG_Error, - ("[URL_Connect; http%s://%s:%hu%s%s%s%.*s] " + ("[URL_Connect; http%s://%s%s%s%s%s%.*s] " " Failed to %s: %s%s", &"s"[!(flags & fSOCK_Secure)], - host, port, &"/"[*path == '/'], path, + host, temp, &"/"[*path == '/'], path, &"?"[!args_len], (int) args_len, args, s ? "use connection" : "connect", - IO_StatusStr(status), temp)); + IO_StatusStr(status), timeout)); } else verify(SOCK_SetTimeout(*sock, eIO_ReadWrite, rw_timeout)==eIO_Success); return status; @@ -2466,7 +2536,7 @@ void SERV_PrintFirewallPorts(char* buf, size_t bufsize, EFWMode mode) for (n = m = 0; n < SizeOf(s_FWPorts); ++n, m += sizeof(s_FWPorts[0])<<3) { unsigned short p; TNCBI_BigCount mask = s_FWPorts[n]; - for (p = m + 1; mask; ++p, mask >>= 1) { + for (p = (unsigned short) m + 1; mask; ++p, mask >>= 1) { if (mask & 1) { char port[10]; int k = sprintf(port, &" %hu"[!len], p); diff --git a/c++/src/connect/ncbi_core.c b/c++/src/connect/ncbi_core.c index a5301014..95d5cb5a 100644 --- a/c++/src/connect/ncbi_core.c +++ b/c++/src/connect/ncbi_core.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_core.c 507875 2016-07-21 21:24:44Z lavr $ +/* $Id: ncbi_core.c 545593 2017-09-07 18:06:33Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,6 +31,7 @@ */ #include "ncbi_ansi_ext.h" +#include "ncbi_once.h" #include "ncbi_priv.h" #include @@ -38,21 +39,14 @@ # include #endif /*NCBI_OS_UNIX*/ -#if defined(NCBI_CXX_TOOLKIT) && defined(_MT) && !defined(NCBI_WITHOUT_MT) -# if defined(NCBI_OS_MSWIN) +#ifdef NCBI_CXX_TOOLKIT +# if defined(NCBI_POSIX_THREADS) +# include +# elif defined(NCBI_WIN32_THREADS) # define WIN32_LEAN_AND_MEAN # include -# define NCBI_WIN32_THREADS -# elif defined(NCBI_OS_UNIX) -# include -# define NCBI_POSIX_THREADS -# else -# define NCBI_NO_THREADS -# endif /*NCBI_OS*/ -#else -# define NCBI_NO_THREADS -#endif /*NCBI_CXX_TOOLKT && _MT && !NCBI_WITHOUT_MT*/ - +# endif +#endif /*NCBI_CXX_TOOLKIT*/ /****************************************************************************** @@ -78,43 +72,67 @@ extern const char* IO_StatusStr(EIO_Status status) } - /****************************************************************************** * MT locking */ -/* Check the validity of the MT locker */ -#define MT_LOCK_VALID \ - assert(lk->ref_count && lk->magic_number == kMT_LOCK_magic_number) +/* Check the validity of the MT lock */ +#define MT_LOCK_VALID assert(lk->count && lk->magic == kMT_LOCK_magic) -/* MT locker data and callbacks */ +/* MT lock data and callbacks */ struct MT_LOCK_tag { - unsigned int ref_count; /* reference counter */ - void* user_data; /* for "handler()" and "cleanup()" */ - FMT_LOCK_Handler handler; /* locking function */ - FMT_LOCK_Cleanup cleanup; /* cleanup function */ - unsigned int magic_number; /* used internally to make sure it's init'd */ + volatile unsigned int count; /* reference count */ + void* data; /* for "handler()" and "cleanup()" */ + FMT_LOCK_Handler handler; /* handler callback for [un]locking */ + FMT_LOCK_Cleanup cleanup; /* cleanup callback for "data" */ + unsigned int magic; /* internal consistency assurance */ }; -#define kMT_LOCK_magic_number 0x7A96283F +#define kMT_LOCK_magic 0x7A96283F + + +#if defined(NCBI_CXX_TOOLKIT) && defined(NCBI_THREADS) + +# if defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER) +# define NCBI_RECURSIVE_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER +# elif defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) +# define NCBI_RECURSIVE_MUTEX_INIT PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP +# endif /*PTHREAD_RECURSIVE_MUTEX_INITIALIZER...*/ -#ifndef NCBI_NO_THREADS /*ARGSUSED*/ static int/*bool*/ s_CORE_MT_Lock_default_handler(void* unused, EMT_Lock action) { -# if defined(NCBI_POSIX_THREADS) && \ - defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) - static pthread_mutex_t sx_Mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +# if defined(NCBI_POSIX_THREADS) + + static pthread_mutex_t sx_Mutex +# ifdef NCBI_RECURSIVE_MUTEX_INIT + = NCBI_RECURSIVE_MUTEX_INIT +# endif/*NCBI_RECURSIVE_MUTEX_INIT*/ + ; + +# ifndef NCBI_RECURSIVE_MUTEX_INIT + static void* /*bool*/ sx_Init = 0/*false*/; + static int /*bool*/ sx_Inited = 0/*false*/; + if (CORE_Once(&sx_Init)) { + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&sx_Mutex, &attr); + pthread_mutexattr_destroy(&attr); + sx_Inited = 1; /*go*/ + } else while (!sx_Inited) + CORE_Msdelay(1/*ms*/); /*spin*/ +# endif /*!NCBI_RECURSIVE_MUTEX_INIT*/ switch (action) { case eMT_Lock: case eMT_LockRead: - return pthread_mutex_lock(&sx_Mutex) == 0 ? 1/*ok*/ : 0/*fail*/; + return pthread_mutex_lock (&sx_Mutex) == 0 ? 1/*ok*/ : 0/*fail*/; case eMT_Unlock: - return pthread_mutex_unlock(&sx_Mutex) == 0 ? 1/*ok*/ : 0/*fail*/; + return pthread_mutex_unlock (&sx_Mutex) == 0 ? 1/*ok*/ : 0/*fail*/; case eMT_TryLock: case eMT_TryLockRead: return pthread_mutex_trylock(&sx_Mutex) == 0 ? 1/*ok*/ : 0/*fail*/; @@ -124,15 +142,14 @@ static int/*bool*/ s_CORE_MT_Lock_default_handler(void* unused, # elif defined(NCBI_WIN32_THREADS) static CRITICAL_SECTION sx_Crit; - static LONG sx_Init = 0; - static int/*bool*/ sx_Inited = 0/*false*/; + static LONG /*bool*/ sx_Init = 0/*false*/; + static int /*bool*/ sx_Inited = 0/*false*/; - LONG init = InterlockedCompareExchange(&sx_Init, 1, 0); - if (!init) { + if (!InterlockedCompareExchange(&sx_Init, 1, 0)) { InitializeCriticalSection(&sx_Crit); sx_Inited = 1; /*go*/ } else while (!sx_Inited) - Sleep(1/*ms*/); /*spin*/ + CORE_Msdelay(1/*ms*/); /*spin*/ switch (action) { case eMT_Lock: @@ -150,39 +167,45 @@ static int/*bool*/ s_CORE_MT_Lock_default_handler(void* unused, # else + if (g_CORE_Log) { + static void* /*bool*/ sx_Once = 0/*false*/; + if (CORE_Once(&sx_Once)) + CORE_LOG(eLOG_Critical, "Using uninitialized CORE MT-LOCK"); + } return -1/*not implemented*/; # endif /*NCBI_..._THREADS*/ } -#endif /*!NCBI_NO_THREADS*/ + +#endif /*NCBI_CXX_TOOLKIT && NCBI_THREADS*/ struct MT_LOCK_tag g_CORE_MT_Lock_default = { 1/* ref count */, 0/* user data */, -#ifndef NCBI_NO_THREADS +#if defined(NCBI_CXX_TOOLKIT) && defined(NCBI_THREADS) s_CORE_MT_Lock_default_handler, #else 0/* noop handler */, -#endif /*NCBI_NO_THREADS*/ +#endif /*NCBI_CXX_TOOLKIT && NCBI_THREADS*/ 0/* cleanup */, - kMT_LOCK_magic_number + kMT_LOCK_magic }; extern MT_LOCK MT_LOCK_Create -(void* user_data, +(void* data, FMT_LOCK_Handler handler, FMT_LOCK_Cleanup cleanup) { MT_LOCK lk = (struct MT_LOCK_tag*) malloc(sizeof(struct MT_LOCK_tag)); if (lk) { - lk->ref_count = 1; - lk->user_data = user_data; - lk->handler = handler; - lk->cleanup = cleanup; - lk->magic_number = kMT_LOCK_magic_number; + lk->count = 1; + lk->data = data; + lk->handler = handler; + lk->cleanup = cleanup; + lk->magic = kMT_LOCK_magic; } return lk; } @@ -190,30 +213,37 @@ extern MT_LOCK MT_LOCK_Create extern MT_LOCK MT_LOCK_AddRef(MT_LOCK lk) { - MT_LOCK_VALID; - if (lk != &g_CORE_MT_Lock_default) - lk->ref_count++; + if (lk) { + MT_LOCK_VALID; + if (lk != &g_CORE_MT_Lock_default) { + MT_LOCK_Do(lk, eMT_Lock); + lk->count++; + MT_LOCK_Do(lk, eMT_Unlock); + } + } return lk; } extern MT_LOCK MT_LOCK_Delete(MT_LOCK lk) { - if (lk && lk != &g_CORE_MT_Lock_default) { + if (lk) { MT_LOCK_VALID; - - if (!--lk->ref_count) { - if (lk->handler) { /* weak extra protection */ - verify(lk->handler(lk->user_data, eMT_Lock)); - verify(lk->handler(lk->user_data, eMT_Unlock)); + if (lk != &g_CORE_MT_Lock_default) { + unsigned int count; + if (lk->handler) + verify(lk->handler(lk->data, eMT_Lock)); + count = --lk->count; + if (lk->handler) + verify(lk->handler(lk->data, eMT_Unlock)); + if (!count) { + if (lk->cleanup) + lk->cleanup(lk->data); + + lk->magic++; + free(lk); + lk = 0; } - - if (lk->cleanup) - lk->cleanup(lk->user_data); - - lk->magic_number++; - free(lk); - lk = 0; } } return lk; @@ -223,10 +253,7 @@ extern MT_LOCK MT_LOCK_Delete(MT_LOCK lk) extern int/*bool*/ MT_LOCK_DoInternal(MT_LOCK lk, EMT_Lock how) { MT_LOCK_VALID; - - return lk->handler - ? lk->handler(lk->user_data, how) - : -1/* rightful non-doing */; + return lk->handler ? lk->handler(lk->data, how) : -1/*rightful non-doing*/; } @@ -236,26 +263,25 @@ extern int/*bool*/ MT_LOCK_DoInternal(MT_LOCK lk, EMT_Lock how) */ /* Lock/unlock the logger */ -#define LOG_LOCK_WRITE verify(MT_LOCK_Do(lg->mt_lock, eMT_Lock)) -#define LOG_LOCK_READ verify(MT_LOCK_Do(lg->mt_lock, eMT_LockRead)) -#define LOG_UNLOCK verify(MT_LOCK_Do(lg->mt_lock, eMT_Unlock)) +#define LOG_LOCK_WRITE verify(MT_LOCK_Do(lg->lock, eMT_Lock)) +#define LOG_LOCK_READ verify(MT_LOCK_Do(lg->lock, eMT_LockRead)) +#define LOG_UNLOCK verify(MT_LOCK_Do(lg->lock, eMT_Unlock)) /* Check the validity of the logger */ -#define LOG_VALID \ - assert(lg->ref_count && lg->magic_number == kLOG_magic_number) +#define LOG_VALID assert(lg->count && lg->magic == kLOG_magic) /* Logger data and callbacks */ struct LOG_tag { - unsigned int ref_count; - void* user_data; + unsigned int count; + void* data; FLOG_Handler handler; FLOG_Cleanup cleanup; - MT_LOCK mt_lock; - unsigned int magic_number; /* used internally, to make sure it's init'd */ + MT_LOCK lock; + unsigned int magic; }; -#define kLOG_magic_number 0x3FB97156 +#define kLOG_magic 0x3FB97156 extern const char* LOG_LevelStr(ELOG_Level level) @@ -277,20 +303,20 @@ extern const char* LOG_LevelStr(ELOG_Level level) extern LOG LOG_Create -(void* user_data, +(void* data, FLOG_Handler handler, FLOG_Cleanup cleanup, - MT_LOCK mt_lock) + MT_LOCK lock) { LOG lg = (struct LOG_tag*) malloc(sizeof(struct LOG_tag)); if (lg) { - lg->ref_count = 1; - lg->user_data = user_data; - lg->handler = handler; - lg->cleanup = cleanup; - lg->mt_lock = mt_lock; - lg->magic_number = kLOG_magic_number; + lg->count = 1; + lg->data = data; + lg->handler = handler; + lg->cleanup = cleanup; + lg->lock = MT_LOCK_AddRef(lock); + lg->magic = kLOG_magic; } return lg; } @@ -298,7 +324,7 @@ extern LOG LOG_Create extern LOG LOG_Reset (LOG lg, - void* user_data, + void* data, FLOG_Handler handler, FLOG_Cleanup cleanup) { @@ -306,11 +332,11 @@ extern LOG LOG_Reset LOG_VALID; if (lg->cleanup) - lg->cleanup(lg->user_data); + lg->cleanup(lg->data); - lg->user_data = user_data; - lg->handler = handler; - lg->cleanup = cleanup; + lg->data = data; + lg->handler = handler; + lg->cleanup = cleanup; LOG_UNLOCK; return lg; @@ -322,7 +348,7 @@ extern LOG LOG_AddRef(LOG lg) LOG_LOCK_WRITE; LOG_VALID; - lg->ref_count++; + lg->count++; LOG_UNLOCK; return lg; @@ -335,8 +361,8 @@ extern LOG LOG_Delete(LOG lg) LOG_LOCK_WRITE; LOG_VALID; - if (lg->ref_count > 1) { - lg->ref_count--; + if (lg->count > 1) { + lg->count--; LOG_UNLOCK; return lg; } @@ -344,11 +370,10 @@ extern LOG LOG_Delete(LOG lg) LOG_UNLOCK; LOG_Reset(lg, 0, 0, 0); - lg->ref_count--; - lg->magic_number++; + lg->count--; + lg->magic++; - if (lg->mt_lock) - MT_LOCK_Delete(lg->mt_lock); + lg->lock = MT_LOCK_Delete(lg->lock); free(lg); } return 0; @@ -357,26 +382,26 @@ extern LOG LOG_Delete(LOG lg) extern void LOG_WriteInternal (LOG lg, - SLOG_Handler* call_data + SLOG_Message* mess ) { - assert(!call_data->raw_size || call_data->raw_data); + assert(!mess->raw_size || mess->raw_data); if (lg) { LOG_LOCK_READ; LOG_VALID; if (lg->handler) - lg->handler(lg->user_data, call_data); + lg->handler(lg->data, mess); LOG_UNLOCK; - if (call_data->dynamic && call_data->message) - free((void*) call_data->message); + if (mess->dynamic && mess->message) + free((void*) mess->message); } /* unconditional exit/abort on fatal error */ - if (call_data->level == eLOG_Fatal) { + if (mess->level == eLOG_Fatal) { #ifdef NDEBUG fflush(0); _exit(255); @@ -401,21 +426,21 @@ extern void LOG_Write size_t raw_size ) { - SLOG_Handler call_data; - - call_data.dynamic = 0; - call_data.message = message; - call_data.level = level; - call_data.module = module; - call_data.func = func; - call_data.file = file; - call_data.line = line; - call_data.raw_data = raw_data; - call_data.raw_size = raw_size; - call_data.err_code = code; - call_data.err_subcode = subcode; - - LOG_WriteInternal(lg, &call_data); + SLOG_Message mess; + + mess.dynamic = 0; + mess.message = message; + mess.level = level; + mess.module = module; + mess.func = func; + mess.file = file; + mess.line = line; + mess.raw_data = raw_data; + mess.raw_size = raw_size; + mess.err_code = code; + mess.err_subcode = subcode; + + LOG_WriteInternal(lg, &mess); } @@ -425,46 +450,45 @@ extern void LOG_Write */ /* Lock/unlock the registry */ -#define REG_LOCK_WRITE verify(MT_LOCK_Do(rg->mt_lock, eMT_Lock)) -#define REG_LOCK_READ verify(MT_LOCK_Do(rg->mt_lock, eMT_LockRead)) -#define REG_UNLOCK verify(MT_LOCK_Do(rg->mt_lock, eMT_Unlock)) +#define REG_LOCK_WRITE verify(MT_LOCK_Do(rg->lock, eMT_Lock)) +#define REG_LOCK_READ verify(MT_LOCK_Do(rg->lock, eMT_LockRead)) +#define REG_UNLOCK verify(MT_LOCK_Do(rg->lock, eMT_Unlock)) /* Check the validity of the registry */ -#define REG_VALID \ - assert(rg->ref_count && rg->magic_number == kREG_magic_number) +#define REG_VALID assert(rg->count && rg->magic == kREG_magic) /* Logger data and callbacks */ struct REG_tag { - unsigned int ref_count; - void* user_data; + unsigned int count; + void* data; FREG_Get get; FREG_Set set; FREG_Cleanup cleanup; - MT_LOCK mt_lock; - unsigned int magic_number; /* used internally, to make sure it's init'd */ + MT_LOCK lock; + unsigned int magic; }; -#define kREG_magic_number 0xA921BC08 +#define kREG_magic 0xA921BC08 extern REG REG_Create -(void* user_data, +(void* data, FREG_Get get, FREG_Set set, FREG_Cleanup cleanup, - MT_LOCK mt_lock) + MT_LOCK lock) { REG rg = (struct REG_tag*) malloc(sizeof(struct REG_tag)); if (rg) { - rg->ref_count = 1; - rg->user_data = user_data; - rg->get = get; - rg->set = set; - rg->cleanup = cleanup; - rg->mt_lock = mt_lock; - rg->magic_number = kREG_magic_number; + rg->count = 1; + rg->data = data; + rg->get = get; + rg->set = set; + rg->cleanup = cleanup; + rg->lock = MT_LOCK_AddRef(lock); + rg->magic = kREG_magic; } return rg; } @@ -472,7 +496,7 @@ extern REG REG_Create extern void REG_Reset (REG rg, - void* user_data, + void* data, FREG_Get get, FREG_Set set, FREG_Cleanup cleanup, @@ -482,12 +506,12 @@ extern void REG_Reset REG_VALID; if (rg->cleanup && do_cleanup) - rg->cleanup(rg->user_data); + rg->cleanup(rg->data); - rg->user_data = user_data; - rg->get = get; - rg->set = set; - rg->cleanup = cleanup; + rg->data = data; + rg->get = get; + rg->set = set; + rg->cleanup = cleanup; REG_UNLOCK; } @@ -498,7 +522,7 @@ extern REG REG_AddRef(REG rg) REG_LOCK_WRITE; REG_VALID; - rg->ref_count++; + rg->count++; REG_UNLOCK; return rg; @@ -511,8 +535,8 @@ extern REG REG_Delete(REG rg) REG_LOCK_WRITE; REG_VALID; - if (rg->ref_count > 1) { - rg->ref_count--; + if (rg->count > 1) { + rg->count--; REG_UNLOCK; return rg; } @@ -520,11 +544,10 @@ extern REG REG_Delete(REG rg) REG_UNLOCK; REG_Reset(rg, 0, 0, 0, 0, 1/*true*/); - rg->ref_count--; - rg->magic_number++; + rg->count--; + rg->magic++; - if (rg->mt_lock) - MT_LOCK_Delete(rg->mt_lock); + rg->lock = MT_LOCK_Delete(rg->lock); free(rg); } return 0; @@ -552,7 +575,7 @@ extern const char* REG_Get REG_VALID; if (rg->get) - rg->get(rg->user_data, section, name, value, value_size); + rg->get(rg->data, section, name, value, value_size); REG_UNLOCK; } @@ -575,7 +598,7 @@ extern int/*bool*/ REG_Set REG_VALID; result = (rg->set - ? rg->set(rg->user_data, section, name, value, storage) + ? rg->set(rg->data, section, name, value, storage) : 0/*failed*/); REG_UNLOCK; diff --git a/c++/src/connect/ncbi_core_cxx.cpp b/c++/src/connect/ncbi_core_cxx.cpp index bb1cb323..eec75cb3 100644 --- a/c++/src/connect/ncbi_core_cxx.cpp +++ b/c++/src/connect/ncbi_core_cxx.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_core_cxx.cpp 507875 2016-07-21 21:24:44Z lavr $ +/* $Id: ncbi_core_cxx.cpp 532418 2017-04-05 03:37:11Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,14 +34,13 @@ */ #include +#include "ncbi_ansi_ext.h" +#include "ncbi_priv.h" #include #include #include #include -#include #include -#include "ncbi_ansi_ext.h" -#include "ncbi_priv.h" #include #define NCBI_USE_ERRCODE_X Connect_Core @@ -63,7 +62,8 @@ static void s_REG_Get(void* user_data, char* value, size_t value_size) THROWS_NONE { try { - string result(static_cast (user_data)->Get(section, name)); + string result + = static_cast (user_data)->Get(section, name); if (!result.empty()) { /*FIXME: This is *bad* because of possible truncation*/ @@ -104,7 +104,7 @@ extern "C" { static void s_REG_Cleanup(void* user_data) THROWS_NONE { try { - static_cast (user_data)->RemoveReference(); + static_cast (user_data)->RemoveReference(); } NCBI_CATCH_ALL_X(3, "s_REG_Cleanup() failed"); } @@ -113,13 +113,25 @@ static void s_REG_Cleanup(void* user_data) THROWS_NONE extern REG REG_cxx2c(IRWRegistry* reg, bool pass_ownership) { - if (pass_ownership && reg) { + if (!reg) + return 0; + if (pass_ownership) reg->AddReference(); - } - return reg - ? REG_Create(static_cast (reg), s_REG_Get, s_REG_Set, - pass_ownership ? s_REG_Cleanup : 0, 0) - : 0; + return REG_Create(reg, + s_REG_Get, s_REG_Set, + pass_ownership ? s_REG_Cleanup : 0, 0); +} + + +extern REG REG_cxx2c(const IRWRegistry* reg, bool pass_ownership) +{ + if (!reg) + return 0; + if (pass_ownership) + reg->AddReference(); + return REG_Create(const_cast (reg), + s_REG_Get, 0/*no setter*/, + pass_ownership ? s_REG_Cleanup : 0, 0); } @@ -128,12 +140,12 @@ extern REG REG_cxx2c(IRWRegistry* reg, bool pass_ownership) ***********************************************************************/ extern "C" { -static void s_LOG_Handler(void* /*user_data*/, - SLOG_Handler* call_data) THROWS_NONE +static void s_LOG_Handler(void* /*data*/, + SLOG_Message* mess) THROWS_NONE { try { EDiagSev level; - switch (call_data->level) { + switch (mess->level) { case eLOG_Trace: level = eDiag_Trace; break; @@ -155,25 +167,24 @@ static void s_LOG_Handler(void* /*user_data*/, level = eDiag_Fatal; break; } - if (!IsVisibleDiagPostLevel(level)) { + if (!IsVisibleDiagPostLevel(level)) return; - } - CDiagCompileInfo info(call_data->file, - call_data->line, - call_data->func, - call_data->module); + CDiagCompileInfo info(mess->file, + mess->line, + mess->func, + mess->module); CNcbiDiag diag(info, level); - diag.SetErrorCode(call_data->err_code, call_data->err_subcode); - diag << call_data->message; - if (call_data->raw_size) { + diag.SetErrorCode(mess->err_code, mess->err_subcode); + diag << mess->message; + if (mess->raw_size) { diag << "\n#################### [BEGIN] Raw Data (" << - call_data->raw_size << - " byte" << (call_data->raw_size != 1 ? "s" : "") << ")\n" << + mess->raw_size << + " byte" << (mess->raw_size != 1 ? "s" : "") << ")\n" << NStr::PrintableString - (CTempString(static_cast(call_data->raw_data), - call_data->raw_size), + (CTempString(static_cast(mess->raw_data), + mess->raw_size), NStr::fNewLine_Passthru | NStr::fNonAscii_Quote) << "\n#################### [END] Raw Data"; } @@ -210,14 +221,12 @@ static int/*bool*/ s_LOCK_Handler(void* user_data, EMT_Lock how) lock->Unlock(); break; case eMT_TryLock: - if (!lock->TryWriteLock()) { + if (!lock->TryWriteLock()) return 0/*false*/; - } break; case eMT_TryLockRead: - if (!lock->TryReadLock()) { + if (!lock->TryReadLock()) return 0/*false*/; - } break; default: NCBI_THROW(CCoreException, eCore, "Lock used with unknown op #" + @@ -294,9 +303,8 @@ static char* s_GetRequestID(ENcbiRequestID reqid) extern "C" { static const char* s_GetRequestDTab(void) { - if (!CDiagContext::GetRequestContext().IsSetDtab()) { + if (!CDiagContext::GetRequestContext().IsSetDtab()) CDiagContext::GetRequestContext().SetDtab(""); - } return CDiagContext::GetRequestContext().GetDtab().c_str(); } } @@ -352,6 +360,13 @@ extern "C" { { CMonkey::Instance()->Close(sock); } + + + static void s_MonkeySockHasSocket(void* /* SOCK* */ sock, + MONKEY_SOCKTYPE socket) + { + CMonkey::Instance()->SockHasSocket((SOCK)sock, socket); + } } @@ -375,18 +390,20 @@ static void s_SetMonkeyHooks(EMonkeyHookSwitch hook_switch) switch (hook_switch) { case eMonkeyHookSwitch_Disabled: - g_MONKEY_Send = 0; - g_MONKEY_Recv = 0; - g_MONKEY_Connect = 0; - g_MONKEY_Poll = 0; - g_MONKEY_Close = 0; + g_MONKEY_Send = 0; + g_MONKEY_Recv = 0; + g_MONKEY_Connect = 0; + g_MONKEY_Poll = 0; + g_MONKEY_Close = 0; + g_MONKEY_SockHasSocket = 0; break; case eMonkeyHookSwitch_Enabled: - g_MONKEY_Send = s_MonkeySend; - g_MONKEY_Recv = s_MonkeyRecv; - g_MONKEY_Connect = s_MonkeyConnect; - g_MONKEY_Poll = s_MonkeyPoll; - g_MONKEY_Close = s_MonkeyClose; + g_MONKEY_Send = s_MonkeySend; + g_MONKEY_Recv = s_MonkeyRecv; + g_MONKEY_Connect = s_MonkeyConnect; + g_MONKEY_Poll = s_MonkeyPoll; + g_MONKEY_Close = s_MonkeyClose; + g_MONKEY_SockHasSocket = s_MonkeySockHasSocket; break; default: break; @@ -419,7 +436,7 @@ static void s_Fini(void) THROWS_NONE if (s_CORE_Set & eCORE_SetLOG) CORE_SetLOG(0); if (s_CORE_Set & eCORE_SetLOCK) - CORE_SetLOCK(0); + CORE_SetLOCK(&g_CORE_MT_Lock_default); g_CORE_Set &= ~s_CORE_Set; s_CORE_Set = 0; } @@ -433,11 +450,11 @@ static void s_Fini(void) THROWS_NONE DEFINE_STATIC_FAST_MUTEX(s_ConnectInitMutex); /* NB: gets called under a lock */ -static void s_Init(IRWRegistry* reg = 0, - FSSLSetup ssl = 0, - CRWLock* lock = 0, - TConnectInitFlags flag = 0, - EConnectInit how = eConnectInit_Weak) +static void s_Init(const IRWRegistry* reg = 0, + FSSLSetup ssl = 0, + CRWLock* lock = 0, + TConnectInitFlags flag = 0, + EConnectInit how = eConnectInit_Weak) { _ASSERT(how != eConnectInit_Intact); @@ -483,14 +500,16 @@ static void s_Init(IRWRegistry* reg = 0, /* PUBLIC */ -extern void CONNECT_Init(IRWRegistry* reg, - CRWLock* lock, - TConnectInitFlags flag) +extern void CONNECT_Init(const IRWRegistry* reg, + CRWLock* lock, + TConnectInitFlags flag, + FSSLSetup ssl) { CFastMutexGuard guard(s_ConnectInitMutex); try { g_CORE_Set = 0; - s_Init(reg, flag & eConnectInit_NoSSL ? 0 : NcbiSetupGnuTls, + s_Init(reg, flag & eConnectInit_NoSSL ? 0 : + ssl ? ssl : NcbiSetupTls, lock, flag, eConnectInit_Explicit); } NCBI_CATCH_ALL_X(8, "CONNECT_Init() failed"); @@ -506,7 +525,7 @@ CConnIniter::CConnIniter(void) if (s_ConnectInit == eConnectInit_Intact) { CMutexGuard appguard(CNcbiApplication::GetInstanceMutex()); CNcbiApplication* app = CNcbiApplication::Instance(); - s_Init(app ? &app->GetConfig() : 0, NcbiSetupGnuTls); + s_Init(app ? &app->GetConfig() : 0, NcbiSetupTls); } } NCBI_CATCH_ALL_X(7, "CConn_Initer::CConn_Initer() failed"); diff --git a/c++/src/connect/ncbi_dispd.c b/c++/src/connect/ncbi_dispd.c index fa059b1e..3142834e 100644 --- a/c++/src/connect/ncbi_dispd.c +++ b/c++/src/connect/ncbi_dispd.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_dispd.c 516325 2016-10-12 17:18:28Z ivanov $ +/* $Id: ncbi_dispd.c 527593 2017-02-14 18:39:16Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -267,7 +267,7 @@ static int/*bool*/ s_Update(SERV_ITER iter, const char* text, int code) while (*text && isspace((unsigned char)(*text))) text++; CORE_LOGF_X(6, failure ? eLOG_Warning : eLOG_Note, - ("[%s] %s", data->net_info->svc, text)); + ("[%s] %s", data->net_info->svc/*not exact*/, text)); } #endif /*_DEBUG && !NDEBUG*/ if (failure) { diff --git a/c++/src/connect/ncbi_ftp_connector.c b/c++/src/connect/ncbi_ftp_connector.c index 6eb688a9..b60e1425 100644 --- a/c++/src/connect/ncbi_ftp_connector.c +++ b/c++/src/connect/ncbi_ftp_connector.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_ftp_connector.c 503173 2016-06-01 19:44:56Z lavr $ +/* $Id: ncbi_ftp_connector.c 532866 2017-04-10 17:55:22Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -38,7 +38,7 @@ * * Note: We do not implement transfers of files whose names include * CR or LF characters: for those to work, all FTP commands will - * have be required to terminate with CRLF at the user level + * have to be required to terminate with CRLF at the user level * (currently, LF alone acts as the command terminator), and all * solitary CRs to be recoded as 'CR\0' (per the RFC), yet all * solitary LFs to be passed through. Nonetheless, we escape all @@ -89,7 +89,9 @@ typedef struct { unsigned send:1; /* true when in send mode (STOR/APPE) */ unsigned open:1; /* true when data open ok in send mode */ unsigned rclr:1; /* true when "rest" to clear by next cmd */ - unsigned soft:12; /* learned server features (future ext) */ + unsigned abor:1; /* last cmd was ABOR (proftpd bug w/450) */ + unsigned free:1; /* unused */ + unsigned soft:10; /* learned server features (future ext) */ TFTP_Features feat; /* FTP server features as discovered */ TFTP_Flags flag; /* connector flags per constructor */ SFTP_Callback cmcb; /* user-provided command callback */ @@ -171,8 +173,11 @@ static EIO_Status x_FTPCloseData(SFTPConnector* xxx, size, &"s"[size == 1])); status = eIO_Unknown; } - } else if (size && how != eIO_ReadWrite) - CORE_TRACEF(("[FTP; %s] Transfer size verified", xxx->what)); + } else if (size && how != eIO_ReadWrite) { + CORE_TRACEF(("[FTP; %s] Transfer size verified (" + "%" NCBI_BIGCOUNT_FORMAT_SPEC " byte%s)", + xxx->what, size, &"s"[size == 1])); + } } else { if (!xxx->cntl) { how = eIO_Open; @@ -206,7 +211,7 @@ static EIO_Status x_FTPParseReply(SFTPConnector* xxx, int* code, assert(xxx->cntl); - for (lineno = 0 ; ; lineno++) { + for (lineno = 0; ; ++lineno) { EIO_Status rdstat; const char* msg; char buf[1024]; @@ -238,7 +243,7 @@ static EIO_Status x_FTPParseReply(SFTPConnector* xxx, int* code, m = 0; } msg += strspn(msg, " \t"); - if (status == eIO_Success && replycb) + if (status == eIO_Success && replycb && !(c == 450 && xxx->abor)) status = replycb(xxx, lineno && m ? 0 : c, lineno, msg); if (!lineno) { *code = c; @@ -248,6 +253,11 @@ static EIO_Status x_FTPParseReply(SFTPConnector* xxx, int* code, if (m) break; } + if (*code == 450 && xxx->abor) { + xxx->abor = 0/*false*/; + /* http://bugs.proftpd.org/show_bug.cgi?id=4252 */ + status = x_FTPParseReply(xxx, code, line, maxlinelen, replycb); + } return status; } @@ -310,6 +320,10 @@ static EIO_Status s_FTPDrainReply(SFTPConnector* xxx, int* code, int cXX) int quit = *code; *code = 0; while ((status = s_FTPReply(xxx, &c, 0, 0, 0)) == eIO_Success) { + if (c == 450 && xxx->abor) { + xxx->abor = 0/*false*/; + continue; + } *code = c; if ((quit && quit == c) || (cXX && c / 100 == cXX)) break; @@ -797,6 +811,7 @@ static EIO_Status x_FTPAbort(SFTPConnector* xxx, ? eIO_Open/*warning*/ : eIO_Close/*silent*/, 0); } assert(!xxx->data); + xxx->abor = 1/*true*/; if (status == eIO_Success) { int code = 426; int/*bool*/ sync = xxx->sync; @@ -1000,7 +1015,7 @@ static EIO_Status x_FTPPort(SFTPConnector* xxx, memcpy(octet, &host, sizeof(host)); memcpy(octet + sizeof(host), &port, sizeof(port)); for (n = 0; n < sizeof(octet); n++) - s += sprintf(s, "%s%u", &","[!n], octet[n]); + s += sprintf(s, &",%u"[!n], octet[n]); assert(s < buf + sizeof(buf)); status = s_FTPCommand(xxx, "PORT", buf); if (status != eIO_Success) @@ -1621,6 +1636,8 @@ static EIO_Status s_FTPNegotiate(SFTPConnector* xxx, static EIO_Status s_FTPPollCntl(SFTPConnector* xxx, const STimeout* timeout) { EIO_Status status = eIO_Success; + int/*bool*/ abor = xxx->abor; + xxx->abor = 0/*false*/; while (SOCK_Wait(xxx->cntl, eIO_Read, &kZeroTimeout) == eIO_Success) { char buf[80]; int code; @@ -1631,6 +1648,10 @@ static EIO_Status s_FTPPollCntl(SFTPConnector* xxx, const STimeout* timeout) } status = s_FTPReply(xxx, &code, buf, sizeof(buf) - 1, 0); if (status == eIO_Success) { + if (code == 450 && abor) { + abor = 0/*false*/; + continue; + } assert(!xxx->data || xxx->send); CORE_LOGF_X(12, xxx->data ? eLOG_Error : eLOG_Warning, ("[FTP%s%s] %spurious response %d from server%s%s", @@ -1646,6 +1667,7 @@ static EIO_Status s_FTPPollCntl(SFTPConnector* xxx, const STimeout* timeout) if (status == eIO_Closed) break; } + xxx->abor = abor; return status; } @@ -1715,10 +1737,10 @@ static EIO_Status s_FTPExecute(SFTPConnector* xxx, const STimeout* timeout) strncasecmp(c - 3, "PWD", 3) == 0 || strncasecmp(c - 3, "MKD", 3) == 0 || strncasecmp(c - 3, "RMD", 3) == 0)) { - status = s_FTPDir(xxx, s, *c ? c + 1 : c); + status = s_FTPDir (xxx, s, *c ? c + 1 : c); } else if (size == 4 && (strncasecmp(s, "CDUP", 4) == 0 || strncasecmp(s, "XCUP", 4) == 0)) { - status = s_FTPDir(xxx, s, *c ? c + 1 : c); + status = s_FTPDir (xxx, s, *c ? c + 1 : c); } else if (size == 4 && strncasecmp(s, "SYST", 4) == 0) { status = s_FTPSyst(xxx, s); } else if (size == 4 && strncasecmp(s, "STAT", 4) == 0) { @@ -1761,6 +1783,8 @@ static EIO_Status s_FTPExecute(SFTPConnector* xxx, const STimeout* timeout) free(s); out: xxx->w_status = status; + if (status != eIO_Timeout) + xxx->abor = 0/*false*/; BUF_Erase(xxx->wbuf); return status; } @@ -1873,6 +1897,7 @@ static EIO_Status s_VT_Open &xxx->cntl, 0, 0, fSOCK_KeepAlive | (xxx->flag & fFTP_LogControl ? fSOCK_LogOn : fSOCK_LogDefault)); + xxx->sync = 0/*false*/; if (status == eIO_Success) { SOCK_DisableOSSendDelay(xxx->cntl, 1/*yes,disable*/); SOCK_SetTimeout(xxx->cntl, eIO_ReadWrite, timeout); @@ -1886,7 +1911,7 @@ static EIO_Status s_VT_Open status = x_FTPDir(xxx, 0, xxx->info->path); } if (status == eIO_Success) { - xxx->send = xxx->open = xxx->rclr = 0/*false*/; + xxx->send = xxx->open = xxx->rclr = xxx->abor = 0/*false*/; assert(xxx->sync); xxx->rest = 0; break; diff --git a/c++/src/connect/ncbi_gnutls.c b/c++/src/connect/ncbi_gnutls.c index f1e5a017..fa3fb598 100644 --- a/c++/src/connect/ncbi_gnutls.c +++ b/c++/src/connect/ncbi_gnutls.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_gnutls.c 517037 2016-10-20 11:20:25Z ivanov $ +/* $Id: ncbi_gnutls.c 545593 2017-09-07 18:06:33Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -47,34 +47,36 @@ # define NCBI_NOTSUPPORTED ENOSYS # else # define NCBI_NOTSUPPORTED EINVAL -# endif /*not implemented*/ +# endif -# ifdef HAVE_LIBGCRYPT +# if GNUTLS_VERSION_NUMBER < 0x020C00 +# ifdef HAVE_LIBGCRYPT -# include +# include -# if defined(NCBI_POSIX_THREADS) +# if defined(NCBI_POSIX_THREADS) -# include -# ifdef __cplusplus +# include +# ifdef __cplusplus extern "C" { -# endif /*__cplusplus*/ +# endif /*__cplusplus*/ GCRY_THREAD_OPTION_PTHREAD_IMPL; -# ifdef __cplusplus +# ifdef __cplusplus } /* extern "C" */ -# endif /*__cplusplus*/ +# endif /*__cplusplus*/ -# elif defined(NCBI_THREADS) +# elif defined(NCBI_THREADS) -# ifdef __cplusplus +# ifdef __cplusplus extern "C" { -# endif /*__cplusplus*/ +# endif /*__cplusplus*/ static int gcry_user_mutex_init(void** lock) { - return !(*lock = CORE_GetLOCK()) ? NCBI_NOTSUPPORTED : 0; + return !(*lock = MT_LOCK_AddRef(g_CORE_MT_Lock)) ? NCBI_NOTSUPPORTED : 0; } static int gcry_user_mutex_destroy(void** lock) { + g_CORE_MT_Lock = MT_LOCK_Delete(*((MT_LOCK*) lock)); *lock = 0; return 0; } @@ -92,20 +94,47 @@ static struct gcry_thread_cbs gcry_threads_user = { gcry_user_mutex_lock, gcry_user_mutex_unlock, NULL/*all other fields NULL-inited*/ }; -# ifdef __cplusplus +# ifdef __cplusplus } /* extern "C" */ -# endif /*__cplusplus*/ +# endif /*__cplusplus*/ -# endif /*NCBI_POSIX_THREADS*/ +# endif /*NCBI_..._THREADS*/ + +# endif /*HAVE_LIBGCRYPT*/ +# elif defined(NCBI_THREADS) +# ifdef __cplusplus +extern "C" { +# endif /*__cplusplus*/ +static int gtls_user_mutex_init(void** lock) +{ + return !(*lock = MT_LOCK_AddRef(g_CORE_MT_Lock)) ? NCBI_NOTSUPPORTED : 0; +} +static int gtls_user_mutex_deinit(void** lock) +{ + g_CORE_MT_Lock = MT_LOCK_Delete((MT_LOCK)(*lock)); + *lock = 0; + return 0; +} +static int gtls_user_mutex_lock(void** lock) +{ + return MT_LOCK_Do((MT_LOCK)(*lock), eMT_Lock) > 0 ? 0 : NCBI_NOTSUPPORTED; +} +static int gtls_user_mutex_unlock(void** lock) +{ + return MT_LOCK_Do((MT_LOCK)(*lock), eMT_Unlock) ? 0 : NCBI_NOTSUPPORTED; +} +# ifdef __cplusplus +} +# endif /*__cplusplus*/ +# endif -# endif /*HAVE_LIBGCRYPT*/ # ifdef __cplusplus extern "C" { # endif /*__cplusplus*/ static EIO_Status s_GnuTlsInit (FSSLPull pull, FSSLPush push); -static void* s_GnuTlsCreate(ESOCK_Side side, SOCK sock, +static void* s_GnuTlsCreate(ESOCK_Side side, SOCK sock, const char* host, NCBI_CRED cred, int* error); static EIO_Status s_GnuTlsOpen (void* session, int* error, char** desc); static EIO_Status s_GnuTlsRead (void* session, void* buf, size_t size, @@ -115,7 +144,8 @@ static EIO_Status s_GnuTlsWrite (void* session, const void* data, size_t size, static EIO_Status s_GnuTlsClose (void* session, int how, int* error); static void s_GnuTlsDelete(void* session); static void s_GnuTlsExit (void); -static const char* s_GnuTlsError (void* session, int error); +static const char* s_GnuTlsError (void* session, int error, + char* buf, size_t size); static void x_GnuTlsLogger(int level, const char* message); static ssize_t x_GnuTlsPull (gnutls_transport_ptr_t, void*, size_t); @@ -150,23 +180,22 @@ static FSSLPush s_Push; static void x_GnuTlsLogger(int level, const char* message) { /* do some basic filtering and EOL cut-offs */ - int len = message ? strlen(message) : 0; + size_t len = message ? strlen(message) : 0; if (!len || *message == '\n') return; if (strncasecmp(message, "ASSERT: ", 8) == 0) return; if (message[len - 1] == '\n') - len--; - CORE_LOGF(eLOG_Note, ("GNUTLS%d: %.*s", level, len, message)); + --len; + CORE_LOGF(eLOG_Note, ("GNUTLS%d: %.*s", level, (int) len, message)); } # ifdef __GNUC__ inline # endif /*__GNUC__*/ -static EIO_Status x_RetryStatus(gnutls_session_t session, EIO_Event direction) +static EIO_Status x_RetryStatus(SOCK sock, EIO_Event direction) { - SOCK sock = (SOCK) gnutls_session_get_ptr(session); EIO_Status status; if (direction == eIO_Open) { EIO_Status r_status = SOCK_Status(sock, eIO_Read); @@ -181,18 +210,19 @@ static EIO_Status x_RetryStatus(gnutls_session_t session, EIO_Event direction) # ifdef __GNUC__ inline # endif /*__GNUC__*/ -static EIO_Status x_ErrorToStatus(int* error, - gnutls_session_t session,EIO_Event direction) +static EIO_Status x_ErrorToStatus(int* error, gnutls_session_t session, + EIO_Event direction) { + SOCK sock; EIO_Status status; - SOCK sock = (SOCK) gnutls_transport_get_ptr(session); - assert(error && *error <= 0); + assert(error && *error <= 0/*GNUTLS_E_SUCCESS*/); if (!*error) return eIO_Success; - else if (*error == GNUTLS_E_AGAIN) - status = x_RetryStatus(session, direction); + sock = (SOCK) gnutls_transport_get_ptr(session); + if (*error == GNUTLS_E_AGAIN) + status = x_RetryStatus(sock, direction); else if (*error == GNUTLS_E_INTERRUPTED) status = eIO_Interrupt; else if (*error == GNUTLS_E_WARNING_ALERT_RECEIVED) { @@ -217,33 +247,11 @@ static EIO_Status x_ErrorToStatus(int* error, status = eIO_Closed; else status = eIO_Unknown; -#if 0 - CORE_TRACEF(("GNUTLS error %d -> CONNECT status %s", - *error, IO_StatusStr(status))); -#endif - return status; -} + CORE_LOGF(eLOG_Trace, ("GNUTLS error %d -> CONNECT GNUTLS status %s", + *error, IO_StatusStr(status))); -# ifdef __GNUC__ -inline -# endif /*__GNUC__*/ -static int/*bool*/ x_IsTimeout(SOCK sock, EIO_Event direction) -{ - int retval; - switch (direction) { - case eIO_Read: - retval = !sock->r_tv_set || (sock->r_tv.tv_sec | sock->r_tv.tv_usec); - break; - case eIO_Write: - retval = !sock->w_tv_set || (sock->w_tv.tv_sec | sock->w_tv.tv_usec); - break; - default: - retval = 0; - assert(0); - break; - } - return retval; + return status; } @@ -255,10 +263,11 @@ static int x_StatusToError(EIO_Status status, SOCK sock, EIO_Event direction) int error; assert(status != eIO_Success); + assert(direction == eIO_Read || direction == eIO_Write); switch (status) { case eIO_Timeout: - error = x_IsTimeout(sock, direction) ? SOCK_ETIMEDOUT : EAGAIN; + error = EAGAIN; break; case eIO_Closed: error = SOCK_ENOTCONN; @@ -277,16 +286,21 @@ static int x_StatusToError(EIO_Status status, SOCK sock, EIO_Event direction) error = EINVAL; break; } -#if 0 - CORE_TRACEF(("CONNECT status %s -> %s %d", IO_StatusStr(status), - error ? "error" : "errno", - error ? error : errno)); -#endif + + {{ + const char* x_what = error ? "error" : "errno"; + int x_error = error ? error : errno; + CORE_LOGF(eLOG_Trace, ("CONNECT GNUTLS status %s -> %s %d", + IO_StatusStr(status), x_what, x_error)); + if (!error) + errno = x_error; /* restore errno that may be clobbered by log */ + }} + return error; } -static void* s_GnuTlsCreate(ESOCK_Side side, SOCK sock, +static void* s_GnuTlsCreate(ESOCK_Side side, SOCK sock, const char* host, NCBI_CRED cred, int* error) { gnutls_transport_ptr_t ptr = (gnutls_transport_ptr_t) sock; @@ -297,10 +311,11 @@ static void* s_GnuTlsCreate(ESOCK_Side side, SOCK sock, gnutls_anon_client_credentials_t acred; gnutls_session_t session; char val[128]; + size_t len; int err; if (end == GNUTLS_SERVER) { - /*FIXME: not yet supported*/ + CORE_LOG(eLOG_Error, "Server-side SSL not yet supported with GNUTLS"); *error = 0; return 0; } @@ -312,6 +327,9 @@ static void* s_GnuTlsCreate(ESOCK_Side side, SOCK sock, if (!acred || (cred && (cred->type != eNcbiCred_GnuTls || !cred->data))) { + CORE_LOGF(eLOG_Error, ("Cannot %s GNUTLS credentials: %s", + acred ? "use" : "set", + acred ? "Invalid format" : "Not initialized")); /*FIXME: there's a NULL(data)-terminated array of credentials */ *error = 0; return 0; @@ -322,6 +340,8 @@ static void* s_GnuTlsCreate(ESOCK_Side side, SOCK sock, ConnNetInfo_GetValue(0, "GNUTLS_PRIORITY", val, sizeof(val), 0); + len = host ? strlen(host) : 0; + if ((err = gnutls_set_default_priority(session)) != 0 || # if LIBGNUTLS_VERSION_NUMBER >= 0x020200 ( *val && @@ -337,7 +357,9 @@ static void* s_GnuTlsCreate(ESOCK_Side side, SOCK sock, # endif /*LIBGNUTLS_VERSION_NUMBER<3.3.6*/ (err = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred ? cred->data : xcred)) != 0 || - (err = gnutls_credentials_set(session, GNUTLS_CRD_ANON, acred))!= 0) { + (err = gnutls_credentials_set(session, GNUTLS_CRD_ANON, acred))!= 0 || + (len && (err = gnutls_server_name_set(session, GNUTLS_NAME_DNS, + host, len)) != 0)) { gnutls_deinit(session); *error = err; return 0; @@ -368,8 +390,9 @@ static EIO_Status s_GnuTlsOpen(void* session, int* error, char** desc) } while (x_error && x_error == GNUTLS_E_REHANDSHAKE); if (x_error < 0) { - status = x_ErrorToStatus(&x_error, - (gnutls_session_t) session, eIO_Open); + status = x_ErrorToStatus(&x_error, (gnutls_session_t) session, + eIO_Open); + assert(status != eIO_Success); *error = x_error; } else { # if LIBGNUTLS_VERSION_NUMBER >= 0x030110 @@ -378,9 +401,10 @@ static EIO_Status s_GnuTlsOpen(void* session, int* error, char** desc) *desc = strdup(temp); gnutls_free(temp); } -# endif /*LIBGNUTLS_VERSION_NUMBER<3.1.10*/ +# endif /*LIBGNUTLS_VERSION_NUMBER>=3.1.10*/ status = eIO_Success; } + return status; } @@ -388,15 +412,19 @@ static EIO_Status s_GnuTlsOpen(void* session, int* error, char** desc) #ifdef __GNUC__ inline #endif /*__GNUC__*/ -static int x_IfToLog(void) +static int/*bool*/ x_IfToLog(void) { return 7 < s_GnuTlsLogLevel && s_GnuTlsLogLevel <= 10 ? 1/*T*/ : 0/*F*/; } /*ARGSUSED*/ +#ifdef __GNUC__ +inline +#endif /*__GNUC__*/ static void x_set_errno(gnutls_session_t session, int error) { + assert(session); # if LIBGNUTLS_VERSION_NUMBER >= 0x010504 gnutls_transport_set_errno(session, error); # else @@ -471,21 +499,67 @@ static ssize_t x_GnuTlsPush(gnutls_transport_ptr_t ptr, } +static EIO_Status x_InitLocking(void) +{ + EIO_Status status; + +# if GNUTLS_VERSION_NUMBER < 0x020C00 +# ifdef HAVE_LIBGCRYPT +# if defined(NCBI_POSIX_THREADS) + status = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread) == 0 + ? eIO_Success + : eIO_NotSupported; +# elif defined(NCBI_THREADS) + MT_LOCK lk = CORE_GetLOCK(); + if (MT_LOCK_Do(lk, eMT_Lock) != -1) { + status = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_user) == 0 + ? eIO_Success + : eIO_NotSupported; + MT_LOCK_Do(lk, eMT_Unlock); + } else + status = lk ? eIO_Success : eIO_NotSupported; +# elif !defined(NCBI_NO_THREADS) && defined(_MT) + CORE_LOG(eLOG_Critical,"LIBGCRYPT uninitialized: Unknown threading model"); + status = eIO_NotSupported; +# endif /*NCBI_POSIX_THREADS*/ +# endif /*HAVE_LIBGCRYPT*/ +# elif defined(NCBI_THREADS) + MT_LOCK lk = CORE_GetLOCK(); + if (MT_LOCK_Do(lk, eMT_Lock) != -1) { + /* NB: calls global_deinit/global_init internally */ + gnutls_global_set_mutex(gtls_user_mutex_init, gtls_user_mutex_deinit, + gtls_user_mutex_lock, gtls_user_mutex_unlock); + MT_LOCK_Do(lk, eMT_Unlock); + status = eIO_Success; + } else + status = lk ? eIO_Success : eIO_NotSupported; +# elif !defined(NCBI_NO_THREADS) && defined(_MT) + CORE_LOG(eLOG_Critical,"GNUTLS locking uninited: Unknown threading model"); + status = eIO_NotSupported; +# else + status = eIO_Success; +# endif + + return status; +} + + static EIO_Status s_GnuTlsRead(void* session, void* buf, size_t n_todo, size_t* n_done, int* error) { EIO_Status status; - int x_read; + ssize_t x_read; assert(session); x_read = gnutls_record_recv((gnutls_session_t) session, buf, n_todo); - assert(x_read < 0 || x_read <= n_todo); + assert(x_read < 0 || (size_t) x_read <= n_todo); if (x_read <= 0) { - status = x_ErrorToStatus(&x_read, - (gnutls_session_t) session, eIO_Read); - *error = x_read; + int x_error = (int) x_read; + status = x_ErrorToStatus(&x_error, (gnutls_session_t) session, + eIO_Read); + *error = x_error; x_read = 0; } else status = eIO_Success; @@ -499,17 +573,18 @@ static EIO_Status x_GnuTlsWrite(void* session, const void* data, size_t n_todo, size_t* n_done, int* error) { EIO_Status status; - int x_written; + ssize_t x_written; assert(session); x_written = gnutls_record_send((gnutls_session_t) session, data, n_todo); - assert(x_written < 0 || x_written <= n_todo); + assert(x_written < 0 || (size_t) x_written <= n_todo); if (x_written <= 0) { - status = x_ErrorToStatus(&x_written, - (gnutls_session_t) session, eIO_Write); - *error = x_written; + int x_error = (int) x_written; + status = x_ErrorToStatus(&x_error, (gnutls_session_t) session, + eIO_Write); + *error = x_error; x_written = 0; } else status = eIO_Success; @@ -580,6 +655,7 @@ static EIO_Status s_GnuTlsInit(FSSLPull pull, FSSLPush push) gnutls_anon_client_credentials_t acred; gnutls_certificate_credentials_t xcred; const char* version; + EIO_Status status; const char* val; char buf[32]; @@ -593,46 +669,46 @@ static EIO_Status s_GnuTlsInit(FSSLPull pull, FSSLPush push) assert(0); } - val = ConnNetInfo_GetValue(0, "GNUTLS_LOGLEVEL", buf, sizeof(buf), 0); + if (!pull || !push) + return eIO_InvalidArg; + + val = ConnNetInfo_GetValue(0, "TLS_LOGLEVEL", buf, sizeof(buf), 0); CORE_LOCK_READ; if (!val || !*val) - val = getenv("GNUTLS_DEBUG_LEVEL"); + val = getenv("GNUTLS_DEBUG_LEVEL"); /* GNUTLS proprietary setting */ if (val && *val) { + ELOG_Level level; s_GnuTlsLogLevel = atoi(val); CORE_UNLOCK; if (s_GnuTlsLogLevel) { gnutls_global_set_log_function(x_GnuTlsLogger); if (val == buf) gnutls_global_set_log_level(s_GnuTlsLogLevel); - CORE_LOGF(eLOG_Note, ("GNUTLS V%s (Loglevel=%d)", - version, s_GnuTlsLogLevel)); - } + level = eLOG_Note; + } else + level = eLOG_Trace; + CORE_LOGF(level, ("GNUTLS V%s (LogLevel=%d)", + version, s_GnuTlsLogLevel)); } else CORE_UNLOCK; -# ifdef HAVE_LIBGCRYPT -# if defined(NCBI_POSIX_THREADS) - if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread) != 0) + if ((status = x_InitLocking()) != eIO_Success) goto out; -# elif defined(NCBI_THREADS) - if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_user) != 0) - goto out; -# elif defined(_MT) - CORE_LOG(eLOG_Critical,"LIBGCRYPT uninitialized: Unknown threading model"); -# endif /*NCBI_POSIX_THREADS*/ -# endif /*HAVE_LIBGCRYPT*/ - if (!pull || !push || !gnutls_check_version(LIBGNUTLS_VERSION) - || gnutls_global_init() != GNUTLS_E_SUCCESS/*0*/) { + if (!gnutls_check_version(LIBGNUTLS_VERSION) || + gnutls_global_init() != GNUTLS_E_SUCCESS/*0*/) { + status = eIO_NotSupported; goto out; } if (gnutls_anon_allocate_client_credentials(&acred) != 0) { gnutls_global_deinit(); + status = eIO_Unknown; goto out; } if (gnutls_certificate_allocate_credentials(&xcred) != 0) { gnutls_anon_free_client_credentials(acred); gnutls_global_deinit(); + status = eIO_Unknown; goto out; } @@ -646,7 +722,7 @@ static EIO_Status s_GnuTlsInit(FSSLPull pull, FSSLPush push) out: gnutls_global_set_log_level(s_GnuTlsLogLevel = 0); gnutls_global_set_log_function(0); - return eIO_NotSupported; + return status; } @@ -669,10 +745,15 @@ static void s_GnuTlsExit(void) gnutls_global_set_log_level(s_GnuTlsLogLevel = 0); gnutls_global_set_log_function(0); + + /* If GNUTLS is loaded as a DLL, it still has init count 1, so make sure + * cleanup worked completely (MSVC2015 ReleaseDLL build breaks if not) */ + gnutls_global_deinit(); } -static const char* s_GnuTlsError(void* session/*unused*/, int error) +static const char* s_GnuTlsError(void* session/*unused*/, int error, + char* buf/*unused*/, size_t size/*unused*/) { /* GNUTLS defines only negative error codes */ return error >= 0 ? 0 : error < GNUTLS_E_APPLICATION_ERROR_MAX @@ -698,7 +779,8 @@ static EIO_Status s_GnuTlsInit(FSSLPull unused_pull, FSSLPush unused_push) extern SOCKSSL NcbiSetupGnuTls(void) { static const struct SOCKSSL_struct kGnuTlsOps = { - s_GnuTlsInit + "GNUTLS" + , s_GnuTlsInit #ifdef HAVE_LIBGNUTLS , s_GnuTlsCreate , s_GnuTlsOpen diff --git a/c++/src/connect/ncbi_heapmgr.c b/c++/src/connect/ncbi_heapmgr.c index 73ac75bf..ad01faae 100644 --- a/c++/src/connect/ncbi_heapmgr.c +++ b/c++/src/connect/ncbi_heapmgr.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_heapmgr.c 456320 2015-01-09 17:51:13Z lavr $ +/* $Id: ncbi_heapmgr.c 527595 2017-02-14 18:42:16Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -84,7 +84,7 @@ * For automatic traverse purposes there is a 'HEAP_Walk' call, which returns * the next block (either free, or used) from the heap. Given a NULL-pointer, * this function returns the very first block, whereas all subsequent calls - * with the argument being the last observed block results in the next block + * with the argument being the last observed block, result in the next block * returned. NULL comes back when no more blocks exist in the heap. * * Note that for proper heap operations, no allocation(s) should happen between @@ -132,7 +132,7 @@ #ifdef NCBI_OS_LINUX # if NCBI_PLATFORM_BITS == 64 # ifdef __GNUC__ -# define HEAP_PACKED __attribute__ ((packed)) +# define HEAP_PACKED __attribute__((packed)) # elif defined(_CRAYC) # define HEAP_PACKED /* */ # else @@ -177,7 +177,10 @@ static int/*bool*/ s_HEAP_fast = 1/*true*/; #define HEAP_EXTENT(b) ((b) << _HEAP_SIZESHIFT) #define HEAP_ALIGN(a) _HEAP_ALIGN(a, HEAP_EXTENT(1)) #define HEAP_MASK (~(HEAP_EXTENT(1) - 1)) -#define HEAP_LAST 0x80000000UL +#define _HEAP_OLDLAST 0x80000000UL +#define HEAP_PREV_BIT 8 +#define HEAP_NEXT_BIT 4 +#define HEAP_LAST (2 | _HEAP_OLDLAST) #define HEAP_USED 1 #define HEAP_FREE 0 #define HEAP_SIZE(s) ((s) & HEAP_MASK) @@ -187,12 +190,17 @@ static int/*bool*/ s_HEAP_fast = 1/*true*/; #define HEAP_PREV(b) ((SHEAP_HeapBlock*) \ ((char*)(b) - HEAP_SIZE((b)->head.flag))) #define HEAP_INDEX(b, base) ((TNCBI_Size)((b) - (base))) -#define HEAP_ISLAST(b) ( (b)->head.flag & HEAP_LAST) -#define HEAP_ISFREE(b) (((b)->head.flag & HEAP_USED) == HEAP_FREE) -#define HEAP_ISUSED(b) (((b)->head.flag & HEAP_USED) != HEAP_FREE) +#define HEAP_ISLAST(b) ((b)->head.flag & HEAP_LAST) +#define HEAP_ISUSED(b) ((b)->head.flag & HEAP_USED) + + +#if HEAP_MASK != ~((HEAP_PREV_BIT | HEAP_NEXT_BIT | \ + HEAP_FREE | HEAP_USED | HEAP_LAST) & ~_HEAP_OLDLAST) \ + || HEAP_BLOCKS(~HEAP_MASK) != 0 +# error "HEAP_MASK invalid" +#endif -#if 0 /*FIXME*/ /* Performance / integrity improvements: * 1. flag is to keep byte-size of the previous block (instead of the magic); * 2. since sizes always have last nibble zero, use that in the flag field as @@ -205,17 +213,18 @@ static int/*bool*/ s_HEAP_fast = 1/*true*/; * Yet keeping current size clean will still allow fast forward moves. * Remove: * HEAP_FREE - * HEAP_ISFREE + * _HEAP_OLDLAST * Change: * HEAP_LAST -> 2 + * Use HEAP_ISLAST() return value instead of the ternary op in assgn: faster */ static int/*bool*/ x_Parity(unsigned int v) { #if 0 - v ^= v >> 1; - v ^= v >> 2; - v = (v & 0x11111111U) * 0x11111111U; + v ^= v >> 1; + v ^= v >> 2; + v = (v & 0x11111111U) * 0x11111111U; return (v >> 28) & 1; #else v ^= v >> 16; @@ -225,7 +234,24 @@ static int/*bool*/ x_Parity(unsigned int v) return (0x6996 >> v) & 1; #endif } -#endif /*0*/ + + +#ifdef __GNUC__ +inline +#endif /*__GNUC__*/ +static unsigned int x_NextBit(TNCBI_Size size) +{ + return x_Parity(size) ? HEAP_NEXT_BIT : 0; +} + + +#ifdef __GNUC__ +inline +#endif /*__GNUC__*/ +static unsigned int x_PrevBit(TNCBI_Size size) +{ + return x_Parity(size) ? HEAP_PREV_BIT : 0; +} HEAP HEAP_Create(void* base, TNCBI_Size size, @@ -308,10 +334,12 @@ HEAP HEAP_Attach(const void* base, TNCBI_Size maxsize, int serial) TNCBI_Size size = 0; if (base && (!maxsize || maxsize > sizeof(SHEAP_Block))) { - const SHEAP_HeapBlock* b = (const SHEAP_HeapBlock*) base; + const SHEAP_HeapBlock* b = (const SHEAP_HeapBlock*) base, *p = 0; for (;;) { #if 0 /*FIXME*/ - if (!HEAP_ISUSED(b) && !HEAP_ISFREE(b)) { /*FIXME*/ + if ((b->head.flag & HEAP_NEXT_BIT) != x_NextBit(b->size) || + (b->head.flag & HEAP_PREV_BIT) != x_PrevBit(HEAP_SIZE(b->flag)) + || (p && p != b - HEAP_BLOCKS(b->flag))) { CORE_LOGF_X(5, eLOG_Error, ("Heap Attach: Heap corrupt @%u (0x%08X, %u)", HEAP_INDEX(b, (SHEAP_HeapBlock*) base), @@ -333,6 +361,7 @@ HEAP HEAP_Attach(const void* base, TNCBI_Size maxsize, int serial) } if (HEAP_ISLAST(b)) break; + p = b; b = HEAP_NEXT(b); } } @@ -368,8 +397,8 @@ static SHEAP_HeapBlock* s_HEAP_Find(HEAP heap, SHEAP_HeapBlock *f, *b, *e = heap->base + heap->free; TNCBI_Size find = size ? *size : 0; - assert(!hint || HEAP_ISFREE(hint)); - assert(heap->free < heap->size && HEAP_ISFREE(e)); + assert(!hint || !HEAP_ISUSED(hint)); + assert(heap->free < heap->size && !HEAP_ISUSED(e)); if (!hint && find < (e->head.size >> 1)) { /* begin from the smallest block */ for (b = heap->base + e->nextfree; ; b = heap->base + b->nextfree) { @@ -379,7 +408,7 @@ static SHEAP_HeapBlock* s_HEAP_Find(HEAP heap, b = 0; goto err; } - if (!HEAP_ISFREE(b)) + if (HEAP_ISUSED(b)) goto err; } if (find <= b->head.size || b == e) @@ -395,7 +424,7 @@ static SHEAP_HeapBlock* s_HEAP_Find(HEAP heap, b = 0; goto err; } - if (!HEAP_ISFREE(b)) + if (HEAP_ISUSED(b)) goto err; } if (!f) { @@ -435,7 +464,7 @@ static void s_HEAP_Link(HEAP heap, SHEAP_HeapBlock* f, SHEAP_HeapBlock* hint) unsigned int free = HEAP_INDEX(f, heap->base); SHEAP_HeapBlock* b; - assert(HEAP_ISFREE(f) && (!hint || HEAP_ISFREE(hint))); + assert(!HEAP_ISUSED(f) && (!hint || !HEAP_ISUSED(hint))); if (heap->free == heap->size) { assert(!hint); f->prevfree = free; @@ -445,7 +474,7 @@ static void s_HEAP_Link(HEAP heap, SHEAP_HeapBlock* f, SHEAP_HeapBlock* hint) } assert(heap->free < heap->size); b = heap->base + heap->free; - assert(HEAP_ISFREE(b)); + assert(!HEAP_ISUSED(b)); if (b->head.size < f->head.size) { assert(!hint); /* Link in AFTER b, and also set the new free head */ @@ -459,7 +488,7 @@ static void s_HEAP_Link(HEAP heap, SHEAP_HeapBlock* f, SHEAP_HeapBlock* hint) /* find a block "b" that is just bigger than "f" */ assert(!hint || size <= hint->head.size); b = s_HEAP_Find(heap, &size, hint); - assert(b && HEAP_ISFREE(b)); + assert(b && !HEAP_ISUSED(b)); /* Link in BEFORE b (so that f <= b) */ f->nextfree = HEAP_INDEX(b, heap->base); f->prevfree = b->prevfree; @@ -503,11 +532,11 @@ static SHEAP_HeapBlock* s_HEAP_Collect(HEAP heap, TNCBI_Size need) SHEAP_HeapBlock* n = b == e ? 0 : HEAP_NEXT(b); assert(!n || HEAP_SIZE(b->head.size) == b->head.size); if (n) - last = HEAP_ISLAST(b); - if (!n || HEAP_ISFREE(b)) { + last = HEAP_ISLAST(b) ? HEAP_LAST : 0; + if (!n || !HEAP_ISUSED(b)) { if (n) { assert(!need || b->head.size < need); - assert(n == e || !HEAP_ISFREE(n)); + assert(n == e || HEAP_ISUSED(n)); free += b->head.size; } if (f) { @@ -564,9 +593,8 @@ static SHEAP_HeapBlock* s_HEAP_Collect(HEAP heap, TNCBI_Size need) } while (b); if (f) { - /*FIXME*/ assert(last); - f->head.flag = (p ? p->head.size : 0) | 2/*HEAP_LAST*/; + f->head.flag = (p ? p->head.size : 0) | last; } return f; } @@ -584,10 +612,10 @@ static SHEAP_Block* s_HEAP_Take(HEAP heap, int/*bool*/ tail) { assert(HEAP_SIZE(size) == size); - assert(HEAP_ISFREE(b) && size <= b->head.size); + assert(!HEAP_ISUSED(b) && size <= b->head.size); if (size + HEAP_EXTENT(1) <= b->head.size) { /* the block is to used partially */ - unsigned int last = HEAP_ISLAST(b); + unsigned int last = HEAP_ISLAST(b) ? HEAP_LAST : 0; SHEAP_HeapBlock* f; if (tail) { f = b; @@ -665,8 +693,8 @@ SHEAP_Block* HEAP_Alloc(HEAP heap, } else if (unlikely(need <= free)) { /*NB: here f returns unlinked*/ f = s_HEAP_Collect(heap, need); - assert(f && HEAP_ISFREE(f) && need <= f->head.size); - if (unlikely(f->head.flag & 2/*HEAP_LAST*/)) + assert(f && !HEAP_ISUSED(f) && need <= f->head.size); + if (unlikely(f->head.flag & HEAP_LAST)) f->head.flag = HEAP_FREE | HEAP_LAST; n = 0; } else @@ -698,7 +726,7 @@ SHEAP_Block* HEAP_Alloc(HEAP heap, } else { assert(base <= f && f < base + heap->size && HEAP_ISLAST(f)); hsize = HEAP_BLOCKS(hsize); - if (unlikely(!HEAP_ISFREE(f))) { + if (unlikely(HEAP_ISUSED(f))) { f->head.flag &= ~HEAP_LAST; /* New block is at the very top of the heap */ heap->last = heap->size; @@ -727,7 +755,7 @@ SHEAP_Block* HEAP_Alloc(HEAP heap, heap->size = hsize; assert(!n); } - assert(f && HEAP_ISFREE(f) && need <= f->head.size); + assert(f && !HEAP_ISUSED(f) && need <= f->head.size); return s_HEAP_Take(heap, f, n, need, size, tail); } @@ -740,7 +768,7 @@ static void s_HEAP_Free(HEAP heap, /* NB: in order to maintain HEAP_Walk() "b" must have "size" updated * so that the next heap block could be located correctly, and also * "flag" must keep its HEAP_LAST bit so that it can be verified. */ - unsigned int last = HEAP_ISLAST(b); + unsigned int last = HEAP_ISLAST(b) ? HEAP_LAST : 0; assert(p < b && b < n); assert((!p || HEAP_NEXT(p) == b) && b && HEAP_NEXT(b) == n); @@ -748,7 +776,7 @@ static void s_HEAP_Free(HEAP heap, s_HEAP_Unlink(b); b->head.flag = HEAP_FREE | last; - if (!last && HEAP_ISFREE(n)) { + if (!last && !HEAP_ISUSED(n)) { assert((n->nextfree | n->prevfree) != (TNCBI_Size)(~0)); b->head.size += n->head.size; if (HEAP_ISLAST(n)) { @@ -758,7 +786,7 @@ static void s_HEAP_Free(HEAP heap, } if (n == heap->base + heap->free) { if (heap->free == n->prevfree) { - assert(!p || !HEAP_ISFREE(p)); + assert(!p || HEAP_ISUSED(p)); assert(n->prevfree == n->nextfree); heap->free = HEAP_INDEX(b, heap->base); b->prevfree = heap->free; @@ -771,7 +799,7 @@ static void s_HEAP_Free(HEAP heap, heap->base[n->prevfree].nextfree = n->nextfree; s_HEAP_Unlink(n); } - if (p && HEAP_ISFREE(p)) { + if (p && !HEAP_ISUSED(p)) { assert((p->nextfree | p->prevfree) != (TNCBI_Size)(~0)); p->head.size += b->head.size; if (last) { @@ -828,7 +856,7 @@ void HEAP_Free(HEAP heap, SHEAP_Block* ptr) return; } if (unlikely(&b->head == ptr)) { - if (unlikely(HEAP_ISFREE(b))) { + if (unlikely(!HEAP_ISUSED(b))) { CORE_LOGF_X(12, eLOG_Warning, ("Heap Free%s: Freeing free block @%u", s_HEAP_Id(_id, heap), @@ -890,7 +918,7 @@ void HEAP_FreeFast(HEAP heap, SHEAP_Block* ptr, const SHEAP_Block* prev) HEAP_Free(heap, ptr); return; } - if (unlikely(HEAP_ISFREE(b))) { + if (unlikely(!HEAP_ISUSED(b))) { CORE_LOGF_X(19, eLOG_Warning, ("Heap Free%s: Freeing free block @%u", s_HEAP_Id(_id, heap), HEAP_INDEX(b, heap->base))); @@ -923,8 +951,8 @@ HEAP HEAP_Trim(HEAP heap) b = s_HEAP_Collect(heap, 0); if (b) { - assert(HEAP_ISFREE(b) && (b->head.flag & 2/*HEAP_LAST*/)); - prev = HEAP_BLOCKS(b->head.flag); + assert(!HEAP_ISUSED(b) && HEAP_ISLAST(b)); + prev = HEAP_BLOCKS(b->head.flag & ~_HEAP_OLDLAST); b->head.flag = HEAP_FREE | HEAP_LAST; } else prev = 0; @@ -934,7 +962,7 @@ HEAP HEAP_Trim(HEAP heap) } else if (!(size = b->head.size % heap->chunk)) { hsize = HEAP_EXTENT(heap->size) - b->head.size; b -= prev; - assert(!prev || !HEAP_ISFREE(b)); + assert(!prev || HEAP_ISUSED(b)); } else { assert(HEAP_EXTENT(1) <= size); hsize = HEAP_EXTENT(heap->size) - b->head.size + size; @@ -960,7 +988,7 @@ HEAP HEAP_Trim(HEAP heap) heap->size = hsize; if (base && b) { b = base + prev; - if (!HEAP_ISFREE(b)) { + if (HEAP_ISUSED(b)) { assert(heap->free == hsize); b->head.flag |= HEAP_LAST; heap->last = prev; @@ -1031,7 +1059,7 @@ static SHEAP_Block* s_HEAP_Walk(const HEAP heap, const SHEAP_Block* ptr) HEAP_INDEX(b, heap->base), msg)); } - if (HEAP_ISFREE(b)) { + if (!HEAP_ISUSED(b)) { const SHEAP_HeapBlock* c; if (heap->chunk/*RW heap*/) { /* Free blocks are tricky! They can be left-overs from @@ -1044,8 +1072,8 @@ static SHEAP_Block* s_HEAP_Walk(const HEAP heap, const SHEAP_Block* ptr) if (e <= c || heap->size <= c->prevfree || heap->size <= c->nextfree - || !HEAP_ISFREE(heap->base + c->prevfree) - || !HEAP_ISFREE(heap->base + c->nextfree) + || HEAP_ISUSED(heap->base + c->prevfree) + || HEAP_ISUSED(heap->base + c->nextfree) || e < (s = HEAP_NEXT(c))) { c = 0; break; @@ -1086,15 +1114,15 @@ static SHEAP_Block* s_HEAP_Walk(const HEAP heap, const SHEAP_Block* ptr) c = b; if (heap->size <= b->prevfree || heap->size <= b->nextfree - || !HEAP_ISFREE(heap->base + b->prevfree) - || !HEAP_ISFREE(heap->base + b->nextfree)) { + || HEAP_ISUSED(heap->base + b->prevfree) + || HEAP_ISUSED(heap->base + b->nextfree)) { b = 0; } else if (b->prevfree != b->nextfree || b != heap->base + b->nextfree) { for (i = 0; i < heap->size; ++i) { const SHEAP_HeapBlock* s = b; b = heap->base + b->nextfree; - if (!HEAP_ISFREE(b) || b == s || + if (HEAP_ISUSED(b) || b == s || heap->size <= b->nextfree || s != heap->base + b->prevfree) { b = 0; @@ -1125,7 +1153,7 @@ static SHEAP_Block* s_HEAP_Walk(const HEAP heap, const SHEAP_Block* ptr) /* check that a used block is not within the chain of free blocks but ignore any inconsistencies in the chain */ for (i = 0; c < e && i < heap->size; ++i) { - if (!HEAP_ISFREE(c)) + if (HEAP_ISUSED(c)) break; if (c <= b && b < HEAP_NEXT(c)) { CORE_LOGF_X(20, eLOG_Error, @@ -1149,10 +1177,10 @@ static SHEAP_Block* s_HEAP_Walk(const HEAP heap, const SHEAP_Block* ptr) CORE_LOGF_X(22, eLOG_Error, ("Heap Walk%s: Last block @%u", s_HEAP_Id(_id,heap), HEAP_INDEX(p, heap->base))); - } else if (HEAP_ISFREE(p) && HEAP_ISFREE(b)) { + } else if (!HEAP_ISUSED(p) && !HEAP_ISUSED(b)) { const SHEAP_HeapBlock* c = heap->base; while (c < p) { - if (HEAP_ISFREE(c) && n <= HEAP_NEXT(c)) + if (!HEAP_ISUSED(c) && n <= HEAP_NEXT(c)) break; c = HEAP_NEXT(c); } diff --git a/c++/src/connect/ncbi_http_connector.c b/c++/src/connect/ncbi_http_connector.c index b93f2d28..f0ae4609 100644 --- a/c++/src/connect/ncbi_http_connector.c +++ b/c++/src/connect/ncbi_http_connector.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_http_connector.c 505576 2016-06-27 16:34:25Z lavr $ +/* $Id: ncbi_http_connector.c 547023 2017-09-25 17:18:32Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -255,8 +255,8 @@ inline #endif /*__GNUC__*/ static int/*bool*/ x_IsWriteThru(const SHttpConnector* uuu) { - return uuu->net_info->version && (uuu->flags & fHTTP_WriteThru) - ? 1/*true*/ : 0/*false*/; + return !uuu->net_info->version || !(uuu->flags & fHTTP_WriteThru) + ? 0/*false*/ : 1/*true*/; } @@ -315,7 +315,7 @@ static EIO_Status s_Adjust(SHttpConnector* uuu, int fail = 0; switch (retry->mode) { case eRetry_Redirect: - if (uuu->entity) + if (uuu->entity/*FIXME*/) fail = -2; /*FALLTHRU*/ case eRetry_Redirect303: @@ -348,6 +348,7 @@ static EIO_Status s_Adjust(SHttpConnector* uuu, eReqMethod_Post) { uuu->net_info->req_method = eReqMethod_Get; + /*FIXME: body buffer must be emptied*/ } else fail = -2; } @@ -876,7 +877,7 @@ static EIO_Status s_ConnectAndSend(SHttpConnector* uuu, status = SOCK_Write(uuu->sock, 0, 0, 0, eIO_WritePlain); if (status == eIO_Success) { uuu->conn_state = eCS_ReadHeader; - uuu->keepalive = 0/*uuu->net_info->version*/; + uuu->keepalive = uuu->net_info->version; uuu->expected = (TNCBI_BigCount)(-1L); uuu->received = 0; uuu->chunked = 0; @@ -1267,7 +1268,9 @@ static EIO_Status s_ReadHeader(SHttpConnector* uuu, http_code = -1; uuu->http_code = http_code; if (http_code < 200 || 299 < http_code) { - if (http_code == 301 || http_code == 302 || http_code == 307) + if (http_code == 304) + /*void*/; + else if (http_code == 301 || http_code == 302 || http_code == 307) retry->mode = eRetry_Redirect; else if (http_code == 303) retry->mode = eRetry_Redirect303; @@ -1284,12 +1287,12 @@ static EIO_Status s_ReadHeader(SHttpConnector* uuu, } else http_code = 0/*no server error*/; - if ((http_code || !x_IsErrorHeader(uuu)) - && uuu->net_info->debug_printout == eDebugPrintout_Some) { + if (uuu->net_info->debug_printout == eDebugPrintout_Some + && (http_code || !x_IsErrorHeader(uuu))) { /* HTTP header gets printed as part of data logging when uuu->net_info->debug_printout == eDebugPrintout_Data. */ const char* header_header; - if (!http_code) + if (!http_code || http_code == 304) header_header = "HTTP header"; else if (fatal) header_header = "HTTP header (fatal)"; @@ -1339,8 +1342,8 @@ static EIO_Status s_ReadHeader(SHttpConnector* uuu, if (header_parse == eHTTP_HeaderError) { retry->mode = eRetry_None; - if (!http_code/*i.e. was okay*/ && x_IsErrorHeader(uuu) - && uuu->net_info->debug_printout == eDebugPrintout_Some) { + if (uuu->net_info->debug_printout == eDebugPrintout_Some + && !http_code/*i.e. was okay*/ && x_IsErrorHeader(uuu)) { if (!url) url = ConnNetInfo_URL(uuu->net_info); CORE_DATAF_X(9, eLOG_Note, hdr, size, @@ -1362,8 +1365,10 @@ static EIO_Status s_ReadHeader(SHttpConnector* uuu, | (retry->mode & eRetry_Redirect ? eHTTP_Location : retry->mode & eRetry_Authenticate ? eHTTP_Authenticate : 0) | (uuu->flags & fHTTP_NoAutomagicSID ? 0 : eHTTP_NcbiSid); - if (uuu->http_code / 100 != 1 && uuu->http_code != 204) + if (uuu->http_code / 100 != 1 + && uuu->http_code != 204 && uuu->http_code != 304) { tags |= eHTTP_ContentLength | eHTTP_TransferEncoding; + } /* NB: the loop may clobber "hdr" unless fHTTP_KeepHeader is set */ for (s = strchr(hdr, '\n'); s && *s; s = strchr(s + 1, '\n')) { @@ -1541,12 +1546,11 @@ static EIO_Status s_ReadHeader(SHttpConnector* uuu, break; } while(--e > te); n = (size_t)(e - te); - if (n < 7 || strncasecmp(&e[-7], "chunked", 7) != 0 - || (!isspace((unsigned char) e[-8]) - && e[-8] != ':' && e[-8] != ',')) { - uuu->keepalive = 0; - } else + if (n == 7 && strncasecmp(&e[-7], "chunked", 7) == 0 + && (isspace((unsigned char) e[-8]) + || e[-8] == ':' || e[-8] == ',')) { uuu->chunked = 1; + } uuu->expected = 0; tags &= ~(eHTTP_ContentLength | eHTTP_TransferEncoding); if (!uuu->net_info->version) { @@ -1559,6 +1563,8 @@ static EIO_Status s_ReadHeader(SHttpConnector* uuu, if (!tags) break; } + if (uuu->keepalive && uuu->expected == (TNCBI_BigCount)(-1L)) + uuu->keepalive = 0; if (uuu->flags & fHTTP_KeepHeader) { assert(retry->mode == eRetry_None); @@ -1580,7 +1586,7 @@ static EIO_Status s_ReadHeader(SHttpConnector* uuu, if (!retry->data) free(hdr); - if (http_code == 0) { + if (!http_code || http_code == 304) { if (url) free(url); return header_parse == eHTTP_HeaderError ? eIO_Unknown : eIO_Success; @@ -1607,7 +1613,7 @@ static EIO_Status s_ReadHeader(SHttpConnector* uuu, if (header_parse == eHTTP_HeaderContinue && status == eIO_Closed) { if (url) free(url); - return retry->mode ? status : eIO_Success; + return retry->mode ? status/*eIO_Closed*/ : eIO_Success; } } else status = eIO_Success/*NB: irrelevant*/; @@ -1852,21 +1858,20 @@ static EIO_Status s_Read(SHttpConnector* uuu, void* buf, status = eIO_Unknown; how = "premature EOM in"; } - } else { - if (uuu->expected < uuu->received) { - if (uuu->flags & fHCC_UrlDecodeInput) { - assert(*n_read); - --(*n_read); - } else { - TNCBI_BigCount excess = uuu->received - uuu->expected; - assert(*n_read >= excess); - *n_read -= (size_t) excess; - } - uuu->conn_state = eCS_Discard; - status = eIO_Unknown; - how = "too much"; + } else if (uuu->expected < uuu->received) { + if (uuu->flags & fHCC_UrlDecodeInput) { + assert(*n_read); + --(*n_read); + } else { + TNCBI_BigCount excess = uuu->received - uuu->expected; + assert(*n_read >= excess); + *n_read -= (size_t) excess; } - } + uuu->conn_state = eCS_Discard; + status = eIO_Unknown; + how = "too much"; + } else if (!uuu->chunked && uuu->keepalive) + uuu->conn_state = eCS_DoneBody; if (how) { char* url = ConnNetInfo_URL(uuu->net_info); CORE_LOGF_X(21, eLOG_Warning, @@ -2040,6 +2045,9 @@ static EIO_Status s_VT_Wait if (status != eIO_Success) return status; assert(uuu->sock); + status = SOCK_Status(uuu->sock, eIO_Read); + if (status != eIO_Success) + return status; return SOCK_Wait(uuu->sock, eIO_Read, timeout); case eIO_Write: if (uuu->can_connect == fCC_None) @@ -2104,6 +2112,16 @@ static EIO_Status s_VT_Write /* check if writing is at all legitimate */ if (size && (uuu->net_info->req_method == eReqMethod_Head || uuu->net_info->req_method == eReqMethod_Get)) { + char* url = ConnNetInfo_URL(uuu->net_info); + CORE_LOGF_X(24, eLOG_Error, + ("[HTTP%s%s] Illegal write (%lu byte%s) with %s", + url ? "; " : "", + url ? url : "", + (unsigned long) size, &"s"[size == 1], + uuu->net_info->req_method == eReqMethod_Get + ? "GET" : "HEAD")); + if (url) + free(url); return eIO_Closed; } @@ -2277,17 +2295,18 @@ static void s_Destroy /* NB: per the standard, the HTTP tag name is misspelled as "Referer" */ static int/*bool*/ x_FixupUserHeader(SConnNetInfo* net_info, + int /*bool*/ has_ref, int* /*bool*/ has_sid) { - int/*bool*/ has_referer = 0/*false*/; int/*bool*/ has_host = 0/*false*/; const char* s; if ((s = net_info->http_user_header) != 0) { int/*bool*/ first = 1/*true*/; while (*s) { - if (strncasecmp(s, &"\nReferer:"[first], 9 - first) == 0) { - has_referer = 1/*true*/; + if (has_ref < 0/*unset*/ + && strncasecmp(s, &"\nReferer:"[first], 9 - first) == 0) { + has_ref = 1/*true*/; } else if (strncasecmp(s, &"\nHost:"[first], 6 - first) == 0) { has_host = 1/*true*/; #ifdef HAVE_LIBCONNEXT @@ -2319,12 +2338,14 @@ static int/*bool*/ x_FixupUserHeader(SConnNetInfo* net_info, sprintf(buf, "User-Agent: %.80s", s); ConnNetInfo_ExtendUserHeader(net_info, buf); } - if (!has_referer && net_info->http_referer && *net_info->http_referer + if (has_ref <= 0 && net_info->http_referer && *net_info->http_referer && (s = (char*) malloc(strlen(net_info->http_referer) + 10)) != 0) { sprintf((char*) s, "Referer: %s", net_info->http_referer); ConnNetInfo_AppendUserHeader(net_info, s); free((void*) s); } + if (net_info->external) + ConnNetInfo_OverrideUserHeader(net_info, NCBI_EXTERNAL ": Y"); return has_host; } @@ -2339,6 +2360,7 @@ static EIO_Status s_CreateHttpConnector SConnNetInfo* xxx; SHttpConnector* uuu; char* fff; + int/*bool*/ ref; int/*bool*/ sid; *http = 0; @@ -2385,16 +2407,18 @@ static EIO_Status s_CreateHttpConnector xxx->http_referer = 0; } ConnNetInfo_DeleteUserHeader(xxx, "Referer:"); - } - - if (xxx->max_try == 0 || (flags & fHTTP_NoAutoRetry)) - xxx->max_try = 1; + ref = 0/*false*/; + } else + ref = -1/*unset*/; if (!(uuu = (SHttpConnector*) malloc(sizeof(SHttpConnector)))) { ConnNetInfo_Destroy(xxx); return eIO_Unknown; } + if (xxx->max_try < 1 || (flags & fHTTP_NoAutoRetry)) + xxx->max_try = 1; + /* initialize internal data structure */ uuu->net_info = xxx; @@ -2404,7 +2428,7 @@ static EIO_Status s_CreateHttpConnector uuu->cleanup = 0; sid = flags & fHTTP_NoAutomagicSID ? 1 : tunnel; - uuu->skip_host = x_FixupUserHeader(xxx, &sid); + uuu->skip_host = x_FixupUserHeader(xxx, ref, &sid); if (sid) flags |= fHTTP_NoAutomagicSID; uuu->flags = flags; @@ -2516,6 +2540,8 @@ extern EIO_Status HTTP_CreateTunnelEx if (!sock) return eIO_InvalidArg; *sock = 0; + if (!net_info) + return eIO_InvalidArg; status = s_CreateHttpConnector(net_info, 0/*user_header*/, 1/*tunnel*/, flags | fHTTP_DropUnread, &uuu); diff --git a/c++/src/connect/ncbi_http_session.cpp b/c++/src/connect/ncbi_http_session.cpp index 2e14f097..401ab154 100644 --- a/c++/src/connect/ncbi_http_session.cpp +++ b/c++/src/connect/ncbi_http_session.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_http_session.cpp 519414 2016-11-15 18:23:40Z ivanov $ +/* $Id: ncbi_http_session.cpp 532795 2017-04-09 16:38:29Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -549,11 +549,13 @@ CHttpRequest::CHttpRequest(CHttpSession& session, EReqMethod method) : m_Session(&session), m_Url(url), + m_IsService(false), m_Method(method), m_Headers(new CHttpHeaders), m_Timeout(CTimeout::eDefault), m_Deadline(CTimeout::eDefault), - m_RetryProcessing(ESwitch::eDefault) + m_RetryProcessing(ESwitch::eDefault), + m_AdjustUrl(0) { } @@ -746,16 +748,16 @@ void CHttpRequest::x_InitConnection(bool use_form_data) NCBI_THROW(CHttpSessionException, eBadRequest, "An attempt to execute HTTP request already being executed"); } - SConnNetInfo* connnetinfo = ConnNetInfo_Create(0); + SConnNetInfo* net_info = ConnNetInfo_Create(0); if (m_Session->GetProtocol() == CHttpSession::eHTTP_11) { - connnetinfo->version = 1; + net_info->version = 1; } - connnetinfo->req_method = m_Method; + net_info->req_method = m_Method; // Save headers set automatically (e.g. from CONN_HTTP_USER_HEADER). - if (connnetinfo->http_user_header) { + if (net_info->http_user_header) { CHttpHeaders usr_hdr; - usr_hdr.ParseHttpHeader(connnetinfo->http_user_header); + usr_hdr.ParseHttpHeader(net_info->http_user_header); m_Headers->Merge(usr_hdr); } @@ -768,30 +770,32 @@ void CHttpRequest::x_InitConnection(bool use_form_data) if ( !m_Timeout.IsDefault() ) { STimeout sto; - ConnNetInfo_SetTimeout(connnetinfo, g_CTimeoutToSTimeout(m_Timeout, sto)); + ConnNetInfo_SetTimeout(net_info, g_CTimeoutToSTimeout(m_Timeout, sto)); } if ( !m_Retries.IsNull() ) { - connnetinfo->max_try = x_RetriesToMaxtry(m_Retries); + net_info->max_try = x_RetriesToMaxtry(m_Retries); } m_Stream.Reset(new TStreamRef); m_Response.Reset(new CHttpResponse(*m_Session, m_Url, *m_Stream)); - if ( m_Url.GetIsGeneric() ) { + if ( !m_Url.IsService() ) { // Connect using HTTP. + m_IsService = false; m_Stream->SetConnStream(new CConn_HttpStream( m_Url.ComposeUrl(CUrlArgs::eAmp_Char), - connnetinfo, + net_info, headers.c_str(), sx_ParseHeader, this, sx_Adjust, 0, // cleanup - // Always set AdjustOnRedirect flag - we need this to send correct cookies. + // Always set AdjustOnRedirect flag - to send correct cookies. m_Session->GetHttpFlags() | fHTTP_AdjustOnRedirect)); } else { // Try to resolve service name. - ConnNetInfo_SetUserHeader(connnetinfo, headers.c_str()); + m_IsService = true; + ConnNetInfo_SetUserHeader(net_info, headers.c_str()); SSERVICE_Extra x_extra; memset(&x_extra, 0, sizeof(x_extra)); x_extra.data = this; @@ -799,12 +803,12 @@ void CHttpRequest::x_InitConnection(bool use_form_data) x_extra.parse_header = sx_ParseHeader; x_extra.flags = m_Session->GetHttpFlags() | fHTTP_AdjustOnRedirect; m_Stream->SetConnStream(new CConn_ServiceStream( - m_Url.ComposeUrl(CUrlArgs::eAmp_Char), + m_Url.GetService(), // Ignore other fields now, set them in sx_Adjust fSERV_Http, - connnetinfo, + net_info, &x_extra)); } - ConnNetInfo_Destroy(connnetinfo); + ConnNetInfo_Destroy(net_info); } @@ -848,7 +852,7 @@ EHTTP_HeaderParse CHttpRequest::sx_ParseHeader(const char* http_header, // user_data must contain CHttpRequest*. int CHttpRequest::sx_Adjust(SConnNetInfo* net_info, void* user_data, - unsigned int /*failure_count*/) + unsigned int failure_count) { if ( !user_data ) return 1; // Reset and re-fill headers on redirects (failure_count == 0). @@ -873,6 +877,22 @@ int CHttpRequest::sx_Adjust(SConnNetInfo* net_info, // Update location if it's different from the original url. char* loc = ConnNetInfo_URL(net_info); if (loc) { + CUrl url(loc); + if (failure_count == (unsigned int)(-1) && req->m_IsService) { + bool adjust = true; + if (req->m_AdjustUrl) { + adjust = req->m_AdjustUrl->AdjustUrl(url); + } + else { + url.Adjust(req->m_Url, CUrl::fPath_Append | CUrl::fArgs_Merge); + } + if ( adjust ) { + ConnNetInfo_ParseURL(net_info, url.ComposeUrl(CUrlArgs::eAmp_Char).c_str()); + // Re-read the url and save it in the response. + free(loc); + loc = ConnNetInfo_URL(net_info); + } + } resp->m_Location.SetUrl(loc); free(loc); } diff --git a/c++/src/connect/ncbi_iprange.c b/c++/src/connect/ncbi_iprange.c new file mode 100644 index 00000000..94de202f --- /dev/null +++ b/c++/src/connect/ncbi_iprange.c @@ -0,0 +1,399 @@ +/* $Id: ncbi_iprange.c 545913 2017-09-12 14:25:49Z ivanov $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * IP range manipulating API + * + */ + +#include "ncbi_ansi_ext.h" +#include "ncbi_assert.h" +#include +#include +#include +#include +#include +#include + + +extern int/*bool*/ NcbiIsInIPRange(const SIPRange* range, + const TNCBI_IPv6Addr* addr) +{ + if (range && addr) { + unsigned int a, b, ip; + + if (range->type == eIPRange_Host) { + assert(!range->b); + assert(sizeof(range->a) == sizeof(*addr)); + return !memcmp(&range->a, addr, sizeof(range->a)); + } + switch (range->type) { + case eIPRange_Range: + assert(NcbiIsIPv4(&range->a)); + if (!NcbiIsIPv4(addr)) + return 0/*false*/; + /* all host byte order */ + a = SOCK_NetToHostLong(NcbiIPv6ToIPv4(&range->a, 0)); + b = SOCK_NetToHostLong( range->b ); + ip = SOCK_NetToHostLong(NcbiIPv6ToIPv4( addr, 0)); + assert(a <= b && ip); + return a <= ip && ip <= b; + case eIPRange_Network: + a = NcbiIsIPv4(&range->a); + b = NcbiIsIPv4(addr); + if (!(a & b)) { + return a ^ b + ? 0/*false*/ + : NcbiIsInIPv6Network(&range->a, range->b, addr); + } + /* all network byte order */ + a = NcbiIPv6ToIPv4(&range->a, 0); + b = range->b; + ip = NcbiIPv6ToIPv4( addr, 0); + assert(a && b && ip); + return !((ip & b) ^ a); + default: + assert(0); + /*FALLTHRU*/ + case eIPRange_None: + case eIPRange_Application: + break; + } + } + return 0/*false*/; +} + + +extern SIPRange NcbiTrueIPRange(const SIPRange* range) +{ + SIPRange retval; + if (range) { + switch (range->type) { + default: + assert(0); + /*FALLTHRU*/ + case eIPRange_None: + case eIPRange_Application: + memset(&retval, 0, sizeof(retval)); + /*retval.type = eIPRange_None;*/ + return retval; + case eIPRange_Host: + assert(!range->b); + if (!NcbiIsIPv4(&range->a)) { + retval = *range; + return retval; + } + retval.a = range->a; + retval.b = NcbiIPv6ToIPv4(&range->a, 0); + break; + case eIPRange_Range: + assert(NcbiIsIPv4(&range->a) && range->b); + retval.a = range->a; + retval.b = range->b; + break; + case eIPRange_Network: + assert(range->b); + if (!NcbiIsIPv4(&range->a)) { + retval = *range; + return retval; + } + retval.a = range->a; + retval.b = (NcbiIPv6ToIPv4(&range->a, 0) & range->b) | ~range->b; + break; + } + retval.type = eIPRange_Range; + } else + memset(&retval, 0, sizeof(retval)); + return retval; +} + + +#ifdef __GNUC__ +inline +#endif /*__GNUC__*/ +static size_t x_size(const char* dst, size_t len, const char* ptr) +{ + return len > (size_t)(ptr - dst) ? len - (size_t)(ptr - dst) : 0; +} + + +extern const char* NcbiDumpIPRange(const SIPRange* range, + char* buf, size_t bufsize) +{ + char result[150]; + + if (!range || !buf || !bufsize) + return 0; + + if (range->type == eIPRange_Application) { + *buf = '\0'; + return buf; + } + + if (range->type != eIPRange_None) { + char* s = result; + SIPRange temp = NcbiTrueIPRange(range); + switch (range->type) { + case eIPRange_Host: + assert(!range->b); + strcpy(s, "Host"); + s += 4; + break; + case eIPRange_Range: + assert(range->b); + assert(NcbiIsIPv4(&range->a)); + strcpy(s, "Range"); + s += 5; + break; + case eIPRange_Network: + assert(range->b); + strcpy(s, "Network"); + s += 7; + break; + default: + assert(0); + return 0; + } + *s++ = ' '; + if (!NcbiIsIPv4(&range->a)) { + assert(range->type != eIPRange_Range); + s = NcbiIPv6ToString(s, x_size(result, sizeof(result), s), + &range->a); + assert(s + 40 < result + sizeof(result)); + if (s && range->type == eIPRange_Network) + sprintf(s, "/%u", range->b); + } else { + if (SOCK_ntoa(NcbiIPv6ToIPv4(&range->a, 0), + s, x_size(result, sizeof(result), s)) != 0) { + strcpy(s++, "?"); + } else + s += strlen(s); + if (range->type != eIPRange_Host) { + *s++ = '-'; + if (SOCK_ntoa(temp.b, + s, x_size(result, sizeof(result), s)) != 0) { + strcpy(s, "?"); + } + } + } + } else + strcpy(result, "None"); + + return strncpy0(buf, result, bufsize - 1); +} + + +extern int/*bool*/ NcbiParseIPRange(SIPRange* range, const char* str) +{ + unsigned int addr, temp; + const char* t; + size_t n; + char* e; + long d; + + if (!range || !str) + return 0/*failure*/; + + if (!*str) { + memset(range, 0, sizeof(*range)); + /*range->type = eIPRange_None;*/ + return 1/*success*/; + } + + t = NcbiStringToAddr(&range->a, str, strlen(str)); + if (t && t != str) { + if (!*t /*t == str + strlen(str)*/) { + range->b = 0; + range->type = eIPRange_Host; + return 1/*success*/; + } + if (*t++ == '/' && !isspace((unsigned char)(*t))) { + errno = 0; + d = strtol(t, &e, 10); + if (!errno && t != e && !*e && d > 0) { + int/*bool*/ ipv4 = NcbiIsIPv4(&range->a); + if (ipv4 && d <= 32) { + if (!d || d == 32) { + range->b = 0; + range->type = eIPRange_Host; + return 1/*success*/; + } + addr = SOCK_NetToHostLong(NcbiIPv6ToIPv4(&range->a, 0)); + temp = ~0UL << (32 - d); + range->b = SOCK_HostToNetLong(temp); + range->type = eIPRange_Network; + return addr && !(addr & ~temp); + } else if (!ipv4 && d <= (sizeof(range->a.octet) << 3)) { + if (!d || d == (sizeof(range->a.octet) << 3)) { + range->b = 0; + range->type = eIPRange_Host; + return 1/*success*/; + } + range->b = d; + range->type = eIPRange_Network; + d = (sizeof(range->a.octet) << 3) - d; + for (n = sizeof(range->a.octet); n > 0; --n) { + if (d >= 8) { + if (range->a.octet[n - 1] & ~0) + return 0/*failure*/; + d -= 8; + } else if (d) { + if (range->a.octet[n - 1] & ~(~0 << d)) + return 0/*failure*/; + break; + } else + break; + } + return !NcbiIsEmptyIPv6(&range->a); + } else + return 0/*failure*/; + } + } + } + + if (!SOCK_isip(str)) { + int dots = 0; + const char* p = str; + range->type = eIPRange_Host; + addr = 0/*not actually necessary*/; + for (;;) { + char s[4]; + if (*p != '*') { + errno = 0; + d = strtol(p, &e, 10); + if (errno || p == e || e - p > 3 || d < 0 || 255 < d + || sprintf(s, "%u", (unsigned int) d) != (int)(e - p)) { + break/*goto out*/; + } + p = e; + } else if (!*++p && dots) { + temp = (4 - dots) << 3; + addr <<= temp; + NcbiIPv4ToIPv6(&range->a, SOCK_HostToNetLong(addr), 0); + range->b = SOCK_HostToNetLong(~0UL << temp); + range->type = eIPRange_Network; + return 1/*success*/; + } else + return 0/*failure (asterisks not valid in hostnames)*/; + switch (range->type) { + case eIPRange_Host: + addr <<= 8; + addr |= d; + if (*p != '.') { + addr <<= (3 - dots) << 3; + switch (*p) { + case '/': + range->type = eIPRange_Network; + break; + case '-': + range->type = eIPRange_Range; + p++; + continue; + default: + goto out; + } + } else if (++dots <= 3) { + p++; + continue; + } else + goto out; + assert(*p == '/' && range->type == eIPRange_Network); + t = NcbiStringToIPv4(&range->b, ++p, 0); + if (!t || *t) + continue; + NcbiIPv4ToIPv6(&range->a, SOCK_HostToNetLong(addr), 0); + if (!range->b || !(temp = ~SOCK_NetToHostLong(range->b))) { + range->b = 0; + range->type = eIPRange_Host; + return 1/*success*/; + } + return !(temp & (temp + 1)) && addr && !(addr & temp); + case eIPRange_Range: + if (*p) + goto out; + temp = dots > 0 ? addr : 0; + temp &= ~((1 << ((4 - dots) << 3)) - 1); + temp |= d << ((3 - dots) << 3); + temp |= (1 << ((3 - dots) << 3)) - 1; + NcbiIPv4ToIPv6(&range->a, SOCK_HostToNetLong(addr), 0); + if (addr == temp) { + range->b = 0; + range->type = eIPRange_Host; + return 1/*success*/; + } + range->b = SOCK_HostToNetLong(temp); + return addr < temp; + case eIPRange_Network: + if (*p || d > 32) + return 0/*failure (slashes not valid in hostnames)*/; + NcbiIPv4ToIPv6(&range->a, SOCK_HostToNetLong(addr), 0); + if (!d || d == 32) { + range->b = 0; + range->type = eIPRange_Host; + return 1/*success*/; + } + temp = ~0UL << (32 - d); + range->b = SOCK_HostToNetLong(temp); + return addr && !(addr & ~temp); + default: + assert(0); + return 0/*failure*/; + } + } + out: + /* last resort (and maybe expensive one): try as a regular host name */ + ; + } else { /* NB: SOCK_gethostbyname() returns 0 on an unknown host */ + size_t n; + if (strcasecmp(str, "255.255.255.255") == 0) { + addr = (unsigned int)(~0UL); + NcbiIPv4ToIPv6(&range->a, addr, 0); + range->b = 0; + range->type = eIPRange_Host; + return 1/*success*/; + } + for (n = 0; n < 4; ++n) { + size_t len = 1 + (n << 1); + if (strncmp(str, "0.0.0.0", len) == 0 && !str[len]) { + NcbiIPv4ToIPv6(&range->a, 0, 0); + range->b = 0; + range->type = eIPRange_Host; + return 1/*success*/; + } + } + /* forbid other misleading IP representations */ + if (!SOCK_isipEx(str, 1/*fullquad*/)) + return 0/*failure*/; + } + + if (!(addr = SOCK_gethostbyname(str))) + return 0/*failure*/; + NcbiIPv4ToIPv6(&range->a, addr, 0); + range->b = 0; + range->type = eIPRange_Host; + return 1/*success*/; +} diff --git a/c++/src/connect/ncbi_ipv6.c b/c++/src/connect/ncbi_ipv6.c new file mode 100644 index 00000000..0d168f09 --- /dev/null +++ b/c++/src/connect/ncbi_ipv6.c @@ -0,0 +1,693 @@ +/* $Id: ncbi_ipv6.c 545913 2017-09-12 14:25:49Z ivanov $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * IPv6 addressing support + * + */ + +#include "ncbi_ansi_ext.h" +#include "ncbi_priv.h" +#include +#include +#include +#include +#include +#include +#include + + +struct SIPDNSsfx { + const char* sfx; + const size_t len; +}; +static const struct SIPDNSsfx kIPv6DNS = { ".ip6.arpa", 9 }; +static const struct SIPDNSsfx kIPv4DNS = { ".in-addr.arpa", 13 }; + + +static int/*bool*/ x_NcbiIsIPv4(const TNCBI_IPv6Addr* addr, int/*bool*/ mapped) +{ + /* RFC 4291 2.1, 3 + NB: 2.5.5.1 and 2.5.5.2 - both obsoleted by RFC 6052 2.1 */ + unsigned short word; + size_t i; + for (i = 0; i < 5; ++i) { + memcpy(&word, addr->octet + (i << 1), sizeof(word)); + if (word) + return 0/*false*/; + } + memcpy(&word, addr->octet + (5 << 1), sizeof(word)); + if (word == 0x0000 && mapped >= 0) { + /* IPv4-compatible IPv6 */ + unsigned int temp; + memcpy(&temp, addr->octet + sizeof(addr->octet) - sizeof(temp), + sizeof(temp)); + return SOCK_NetToHostLong(temp) & 0xFF000000 ? 1/*T*/ : 0/*F*/; + } + /* IPv6 mapped IPv4 */ + return word == 0xFFFF && mapped ? 1/*true*/ : 0/*false*/; +} + + +extern int/*bool*/ NcbiIsEmptyIPv6(const TNCBI_IPv6Addr* addr) +{ + return !memcchr(addr->octet, '\0', sizeof(addr->octet)) + || (x_NcbiIsIPv4(addr, 1/*mapped*/) && !NcbiIPv6ToIPv4(addr, 0)) + ? 1/*true*/ : 0/*false*/; +} + + +extern int/*bool*/ NcbiIsIPv4(const TNCBI_IPv6Addr* addr) +{ + return x_NcbiIsIPv4(addr, 1/*mapped*/); +} + + +extern unsigned int NcbiIPv6ToIPv4(const TNCBI_IPv6Addr* addr, size_t pfxlen) +{ + unsigned int ipv4; + static const size_t size = sizeof(ipv4); + if (pfxlen == 0) { + if (!x_NcbiIsIPv4(addr, 1/*mapped*/)) + return 0; + pfxlen = 96; + } + switch (pfxlen) { /*RFC 6052 2.2*/ + case 32: + memcpy( &ipv4, &addr->octet[4], size); + break; + case 40: + memcpy( &ipv4, &addr->octet[5], size - 1); + memcpy((char*) &ipv4 + size - 1, &addr->octet[9], 1); + break; + case 48: + memcpy( &ipv4, &addr->octet[6], size - 2); + memcpy((char*) &ipv4 + size - 2, &addr->octet[9], 2); + break; + case 56: + memcpy( &ipv4, &addr->octet[7], size - 3); + memcpy((char*) &ipv4 + size - 3, &addr->octet[9], 3); + break; + case 64: + memcpy( &ipv4, &addr->octet[9], size); + break; + case 96: + memcpy( &ipv4, &addr->octet[12], size); + break; + default: + assert(0); + return (unsigned int)(-1L)/*failure*/; + } + return ipv4; +} + + +extern int/*bool*/ NcbiIPv4ToIPv6(TNCBI_IPv6Addr* addr, + unsigned int ipv4, size_t pfxlen) +{ + static const size_t size = sizeof(ipv4); + if (pfxlen == 0) { + /* creates IPv6 mapped */ + memset(addr, 0, sizeof(*addr)); + memset(addr->octet + (5 << 1), '\xFF', sizeof(unsigned short)); + pfxlen = 96; + } + switch (pfxlen) { /*RFC 6052 2.2*/ + case 32: + memcpy(&addr->octet[4], &ipv4, size); + break; + case 40: + memcpy(&addr->octet[5], &ipv4, size - 1); + memcpy(&addr->octet[9], (char*) &ipv4 + size - 1, 1); + break; + case 48: + memcpy(&addr->octet[6], &ipv4, size - 2); + memcpy(&addr->octet[9], (char*) &ipv4 + size - 2, 2); + break; + case 56: + memcpy(&addr->octet[7], &ipv4, size - 3); + memcpy(&addr->octet[9], (char*) &ipv4 + size - 3, 3); + break; + case 64: + memcpy(&addr->octet[9], &ipv4, size); + break; + case 96: + memcpy(&addr->octet[12], &ipv4, size); + break; + default: + assert(0); + return 0/*failure*/; + } + return 1/*success*/; +} + + +/* Parse "str" as an IP address, and return 0 if failed, otherwise a pointer to + * the first non-parsed char (which is neither a digit nor a dot) and "dst" + * updated with the just read IPv4 address in network byte order. + */ +static const char* x_StringToIPv4(unsigned int* dst, + const char* str, size_t len) +{ + size_t n; + int octets = 0; + unsigned int tmp; + int/*bool*/ was_digit = 0/*false*/; + unsigned char *ptr = (unsigned char*) &tmp; + + *ptr = 0; + for (n = 0; n < len; ++n) { + unsigned char c = str[n]; + if ('0' <= c && c <= '9') { + unsigned int val; + if (was_digit && !*ptr) + return 0/*leading "0" in octet*/; + val = *ptr * 10 + (c - '0'); + if (val > 255) + return 0; + *ptr = val; + if (!was_digit) { + ++octets; + assert(octets <= 4); + was_digit = 1/*true*/; + } + } else if (c == '.') { + if (!was_digit || octets >= 4) + return 0; + was_digit = 0/*false*/; + *++ptr = 0; + } else + break; + } + if (octets != 4) + return 0/*failure*/; + + *dst = tmp; + return str + n; +} + + +static char* x_IPv4ToString(char* buf, size_t bufsize, const void* src) +{ + char tmp[sizeof("255.255.255.255")]; + unsigned char* ptr = (unsigned char*) src; + size_t len + = (size_t) sprintf(tmp, "%u.%u.%u.%u", ptr[0], ptr[1], ptr[2], ptr[3]); + return len < bufsize ? (char*) memcpy(buf, tmp, len + 1/*EOS*/) + len : 0; +} + + +/* Returns ptr past read (0 on error) */ +static const char* x_StringToIPv6(TNCBI_IPv6Addr* addr, + const char* str, size_t len) +{ + unsigned short word; + struct { + const char* ptr; + size_t len; + } token[sizeof(addr->octet) / sizeof(word) + 1]; + size_t maxt = sizeof(token) / sizeof(token[0]) - 1, t, n; + TNCBI_IPv6Addr temp; + unsigned char* dst; + int/*bool*/ ipv4; + unsigned int ip; + size_t gap; + + if (len < 2 || (str[n = 0] == ':' && str[++n] != ':')) + return 0/*failure*/; + gap = ipv4 = 0/*false*/; + token[t = 0].ptr = str + n; + while (n <= len) { + assert(t <= maxt); + if (n == len || str[n] == ':') { + token[t].len = (size_t)(&str[n] - token[t].ptr); + if (token[t].len) { + if (n++ == len) { + if (++t > maxt) + return 0/*failure*/; + break; + } + } else { + if (n++ == len) + break; + if (gap++) /*RFC 4291 2.2, 2*/ + return 0/*failure*/; + } + /*str[n - 1] == ':'*/ + token[t].len++; + if (++t > maxt) + return 0/*failure*/; + token[t].ptr = str + n; + continue; + } + if (!isxdigit((unsigned char) str[n])) { + token[t].len = (size_t)(&str[n] - token[t].ptr); + if (token[t].len) { + if (str[n] == '.') { + if (t <= maxt - sizeof(ip) / sizeof(word)) { + const char* end + = x_StringToIPv4(&ip, + token[t].ptr, + token[t].len + (len - n)); + if (end && *end != ':' + && t <= (maxt -= sizeof(ip) / sizeof(word))) { + token[t].len = (size_t)(end - token[t].ptr); + ipv4 = 1/*true*/; + break; + } + } + return 0/*failure*/; + } + if (++t > maxt) + return 0/*failure*/; + } + break; + } + n++; + } + + assert(t <= maxt); + if (t < maxt && !gap) + return 0/*failure*/; + + dst = temp.octet; + for (n = 0; n < t; ++n) { + assert(token[n].len); + if (*token[n].ptr != ':') { + char* end; + long val; + assert(isxdigit((unsigned char) token[n].ptr[0])); + errno = 0; + val = strtol(token[n].ptr, &end, 16); + if (errno || val ^ (val & 0xFFFF)) + return 0/*failure*/; + assert(end == token[n].ptr + token[n].len - (*end == ':')); + if (*end == ':' && n == t - !ipv4) + return 0/*failure*/; + word = SOCK_HostToNetShort((unsigned short) val); + memcpy(dst, &word, sizeof(word)); + dst += sizeof(word); + } else { + gap = (maxt - t) * sizeof(word) + sizeof(word); + memset(dst, 0, gap); + dst += gap; + } + } + if (ipv4) { + memcpy(dst, &ip, sizeof(ip)); + ++t; + } + + *addr = temp; + return token[t - 1].ptr + token[t - 1].len; +} + + +extern const char* NcbiStringToIPv4(unsigned int* addr, + const char* str, size_t len) +{ + size_t n; + if (!addr) + return 0/*failure*/; + *addr = 0; + if (!str) + return 0/*failure*/; + if (!len) + len = strlen(str); + for (n = 0; n < len; ++n) { + if (!isspace((unsigned char) str[n])) + break; + } + return x_StringToIPv4(addr, str + n, len - n); +} + + +extern const char* NcbiStringToIPv6(TNCBI_IPv6Addr* addr, + const char* str, size_t len) +{ + size_t n; + if (!addr) + return 0/*failure*/; + memset(addr, 0, sizeof(*addr)); + if (!str || !*str) + return 0/*failure*/; + if (!len) + len = strlen(str); + for (n = 0; n < len; ++n) { + if (!isspace((unsigned char) str[n])) + break; + } + return x_StringToIPv6(addr, str + n, len - n); +} + + +static char* x_IPv6ToString(char* buf, size_t bufsize, + const TNCBI_IPv6Addr* addr) +{ + char ipv6[64/*enough for sizeof(8 * "xxxx:")*/]; + char ipv4[sizeof("255.255.255.255")]; + unsigned short word; + struct { + size_t pos; + size_t len; + } gap[sizeof(addr->octet) / sizeof(word)]; + size_t i, n, z, zlen; + char* ptr = ipv6; + + if (x_NcbiIsIPv4(addr, 1/*mapped*/)) { + unsigned int ip; + n = sizeof(addr->octet) - sizeof(ip); + memcpy(&ip, addr->octet + n, sizeof(ip)); + SOCK_ntoa(ip, ipv4, sizeof(ipv4)); + n /= sizeof(word); + } else { + n = sizeof(addr->octet) / sizeof(word); + *ipv4 = '\0'; + } + + gap[0].pos = 0; + i = z = zlen = 0; + while (i <= n) { + memcpy(&word, &addr->octet[i * sizeof(word)], sizeof(word)); + if (i == n || word) { + size_t len = i - gap[z].pos; + if (len > 1) { /*RFC 5952 4.2.2*/ + gap[z++].len = len; + if (zlen < len) + zlen = len; /*RFC 5952 4.2.1*/ + } + if (i == n) + break; + assert(z < sizeof(gap) / sizeof(gap[0])); + gap[z].pos = ++i; + } else + ++i; + } + + i = z = 0; + while (i < n) { + if (zlen && gap[z].pos == i) { + assert(zlen > 1); + if (zlen == gap[z].len) { + *ptr++ = ':'; + if (zlen == n - i) + *ptr++ = ':'; + i += zlen; + zlen = 0; /*RFC 5952 4.2.3*/ + continue; + } + z++; + } + memcpy(&word, &addr->octet[i * sizeof(word)], sizeof(word)); + ptr += sprintf(ptr, &":%x"[!i], /*RFC 5952 4.1, 4.3*/ + SOCK_NetToHostShort(word)); + ++i; + } + assert(ptr > ipv6); + + i = strlen(ipv4); + if (i) { + if (ptr[-1] != ':') + *ptr++ = ':'; + } + n = (size_t)(ptr - ipv6); + z = n + i; + if (z < bufsize) { + memcpy(buf, ipv6, n); + buf += n; + memcpy(buf, ipv4, i); + buf += i; + *buf = '\0'; + } else + buf = 0; + return buf; +} + + +/* Returns ptr past written (points to '\0'); 0 on error */ +extern char* NcbiIPv4ToString(char* buf, size_t bufsize, + unsigned int addr) +{ + /* sanity */ + if (!buf || !bufsize) + return 0; + *buf = '\0'; + + return x_IPv4ToString(buf, bufsize, &addr); +} + + +/* Returns ptr past written (points to '\0'); 0 on error */ +extern char* NcbiIPv6ToString(char* buf, size_t bufsize, + const TNCBI_IPv6Addr* addr) +{ + /* sanity */ + if (!buf || !bufsize) + return 0; + *buf = '\0'; + + return x_IPv6ToString(buf, bufsize, addr); +} + + +extern char* NcbiAddrToString(char* buf, size_t bufsize, + const TNCBI_IPv6Addr* addr) +{ + if (!buf || !bufsize) + return 0; + *buf = '\0'; + + if (x_NcbiIsIPv4(addr, -1/*mapped only*/)) { + unsigned int ipv4 = NcbiIPv6ToIPv4(addr, 0); + return x_IPv4ToString(buf, bufsize, &ipv4); + } + return x_IPv6ToString(buf, bufsize, addr); +} + + +extern const char* NcbiAddrToDNS(char* buf, size_t bufsize, + const TNCBI_IPv6Addr* addr) +{ + char tmp[sizeof(addr->octet)*4 + 16/*slack*/], *dst = tmp; + const struct SIPDNSsfx* sfx; + const unsigned char* src; + size_t n, len; + + if (!buf || !bufsize) + return 0; + *buf = '\0'; + + len = 0; + src = addr->octet + sizeof(addr->octet) - 1; + if (x_NcbiIsIPv4(addr, -1/*mapped only*/)) { + sfx = &kIPv4DNS; + for (n = 0; n < sizeof(unsigned int); ++n) { + size_t off = (size_t)sprintf(dst, "%d.", *src--); + dst += off; + len += off; + } + } else { + sfx = &kIPv6DNS; + for (n = 0; n < sizeof(addr->octet); ++n) { + size_t off = (size_t)sprintf(dst, "%x.%x.", *src & 0xF, *src >> 4); + dst += off; + len += off; + --src; + } + } + if (len + sfx->len <= bufsize) { + memcpy(buf, tmp, len); + buf += len; + memcpy(buf, sfx->sfx + 1, sfx->len); + buf += sfx->len; + return buf; + } + + return 0; +} + + +/* NB: "str" is actually bounded by the ".in-addr.apra" suffix */ +static const char* x_DNSToIPv4(unsigned int* addr, + const char* str, size_t len) +{ + size_t n; + unsigned int temp; + CORE_DEBUG_ARG(const char* end = str + len;) + unsigned char* ptr = (unsigned char*) &temp + sizeof(temp); + assert(*end == '.'); + if (len < 7/*"x.x.x.x"*/ || 15/*xxx.xxx.xxx.xxx*/ < len) + return 0/*failure*/; + for (n = 0; n < sizeof(temp); ++n) { + char s[4]; + char* e; + long d; + errno = 0; + d = strtol(str, &e, 10); /*NB: "str" may be at "in-addr" safely here*/ + if (errno || str == e || e - str > 3 || *e != '.' + || d < 0 || 255 < d + || sprintf(s, "%u", (unsigned int) d) != (int)(e - str)) { + return 0/*failure*/; + } + assert(e <= end); + *--ptr = (unsigned char) d; + str = ++e; + } + *addr = temp; + return --str; +} + + +/* NB: "str" is actually bounded by the ".ip6.arpa" suffix */ +static const char* x_DNSToIPv6(TNCBI_IPv6Addr* addr, + const char* str, size_t len) +{ + static const char xdigits[] = "0123456789abcdef"; + CORE_DEBUG_ARG(const char* end = str + len;) + TNCBI_IPv6Addr temp; + unsigned char* dst; + size_t n; + assert(*end == '.'); + if (len != 4 * sizeof(addr->octet) - 1) + return 0/*failure*/; + dst = temp.octet + sizeof(temp.octet) - 1; + for (n = 0; n < 2 * sizeof(addr->octet); ++n) { + const char* ptr = strchr(xdigits, tolower((unsigned char)(*str++))); + unsigned char val; + assert(str <= end); + if (!ptr || *str++ != '.') + return 0/*failure*/; + val = (unsigned char)(ptr - xdigits); + if (n & 1) { + val <<= 4; + *dst-- |= val; + } else + *dst = val; + } + *addr = temp; + return --str; +} + + +static const char* s_StringToAddr(TNCBI_IPv6Addr* addr, + const char* str, size_t len, + int/*bool*/ dns) +{ + unsigned int ipv4; + const char* tmp; + size_t n; + + if (!addr) + return 0/*failure*/; + memset(addr, 0, sizeof(*addr)); + if (!str || !*str) + return 0/*failure*/; + + if (!len) + len = strlen(str); + for (n = 0; n < len; ++n) { + if (!isspace((unsigned char) str[n])) + break; + } + str += n; + len -= n; + for (n = 0; n < len; ++n) { + if (!str[n] || isspace((unsigned char) str[n])) + break; + } + if (!(len = n)) + return 0/*failure*/; + + if (dns) { + dns = str[--n] == '.' ? 1/*true*/ : 0/*false*/; + if (len > kIPv4DNS.len + && strncasecmp(tmp = str + len - (kIPv4DNS.len + dns), + kIPv4DNS.sfx, kIPv4DNS.len) == 0) { + if (x_DNSToIPv4(&ipv4, str, len - (kIPv4DNS.len + dns)) == tmp) { + NcbiIPv4ToIPv6(addr, ipv4, 0); + return tmp + (kIPv4DNS.len + dns); + } else if (dns) + return 0/*failure*/; + } + if (len > kIPv6DNS.len + && strncasecmp(tmp = str + len - (kIPv6DNS.len + dns), + kIPv6DNS.sfx, kIPv6DNS.len) == 0) { + if (x_DNSToIPv6(addr, str, len - (kIPv6DNS.len + dns)) == tmp) + return tmp + (kIPv6DNS.len + dns); + else if (dns) + return 0/*failure*/; + } + } + + if ((tmp = x_StringToIPv4(&ipv4, str, len)) != 0) { + NcbiIPv4ToIPv6(addr, ipv4, 0); + return tmp; + } + return x_StringToIPv6(addr, str, len); +} + + +extern const char* NcbiIPToAddr(TNCBI_IPv6Addr* addr, + const char* str, size_t len) +{ + return s_StringToAddr(addr, str, len, 0); +} + + +extern const char* NcbiStringToAddr(TNCBI_IPv6Addr* addr, + const char* str, size_t len) +{ + return s_StringToAddr(addr, str, len, 1); +} + + +int/*bool*/ NcbiIsInIPv6Network(const TNCBI_IPv6Addr* base, + unsigned int bits, + const TNCBI_IPv6Addr* addr) +{ + size_t n; + + if (bits > (sizeof(base->octet) << 3)) + return 0/*false*/; + + for (n = 0; n < sizeof(addr->octet); ++n) { + unsigned char mask; + if (!bits) + mask = 0; + else if (8 > bits) { + mask = ~0 << (8 - bits); + bits = 0; + } else { + mask = ~0; + bits -= 8; + } + if ((addr->octet[n] & mask) ^ base->octet[n]) + return 0/*false*/; + } + + return 1/*true*/; +} diff --git a/c++/src/connect/ncbi_lbos.c b/c++/src/connect/ncbi_lbos.c index 5de92597..ceadd761 100644 --- a/c++/src/connect/ncbi_lbos.c +++ b/c++/src/connect/ncbi_lbos.c @@ -34,40 +34,45 @@ #include "ncbi_ansi_ext.h" -#include #include "ncbi_lbosp.h" #include "ncbi_priv.h" -#include /* free, realloc, calloc, malloc */ -#include /* isdigit */ #include "parson.h" -#define kHostportStringLength (16+1+5)/**< - strlen("255.255.255.255")+ - strlen(":") + - strlen("65535") */ -#define kMaxLineSize 1024 /**< used to build strings*/ - +#include +#include +#include +#include +#include -#define NCBI_USE_ERRCODE_X Connect_LBSM /**< Used in - CORE_LOG*_X */ +#define NCBI_USE_ERRCODE_X Connect_LBOS +#define kHostportStringLength (16+1+5) /* strlen("255.255.255.255") + + strlen(":") + + strlen("65535") */ +#define kMaxLineSize 1024 /* used to build strings */ + #ifdef NCBI_COMPILER_MSVC -# define LBOS_STRTOK strtok_s +# define LBOS_STRTOK strtok_s +#else +# define LBOS_STRTOK strtok_r +#endif /*NCBI_COMPILER_MSVC*/ + +#ifdef NCBI_OS_MSWIN +# define LBOS_RESOLVER_FILE \ + "C:\\Apps\\Admin_Installs\\etc\\ncbi\\lbosresolver" #else -# define LBOS_STRTOK strtok_r -#endif +# define LBOS_RESOLVER_FILE "/etc/ncbi/lbosresolver" +#endif /*NCBI_OS_MSWIN*/ + + /*///////////////////////////////////////////////////////////////////////////// // STATIC VARIABLES // /////////////////////////////////////////////////////////////////////////////*/ -#ifdef NCBI_OS_MSWIN - static const char* kLbosresolverFile = "C:\\Apps\\Admin_Installs\\etc" - "\\ncbi\\lbosresolver"; -#else - static const char* kLbosresolverFile = "/etc/ncbi/lbosresolver"; -#endif -static const char* kLBOSQuery = "/lbos/v3/services/" - "?format=json&show=all&q="; +static const char* kLbosresolverFile = LBOS_RESOLVER_FILE; + +static const char* kLBOSQuery = "/lbos/v3/services/" + "?format=json&show=all&q="; /* * LBOS registry section for announcement @@ -289,8 +294,7 @@ int/*bool*/ s_LBOS_AddAnnouncedServer(const char* service, return_code = 1; /* extract host from healthcheck url */ healthcheck_info = ConnNetInfo_Clone(s_EmptyNetInfo); - healthcheck_info->host[0] = '\0'; /* to be sure that it will be - * overridden */ + healthcheck_info->host[0] = '\0'; /* to make sure it will be overridden */ ConnNetInfo_ParseURL(healthcheck_info, healthcheck_url); /* Create new element of list*/ @@ -299,7 +303,7 @@ int/*bool*/ s_LBOS_AddAnnouncedServer(const char* service, handle.version = strdup(version); handle.service = strdup(service); - /* We search for the same server being already announced */ + /* We search for the same server being already announced */ s_LBOS_RemoveAnnouncedServer(service, version, port, healthcheck_info->host); ConnNetInfo_Destroy(healthcheck_info); @@ -457,7 +461,6 @@ char* g_LBOS_StringNConcat(char* dest, if (buf == NULL) { CORE_LOG_X(eLBOS_MemAlloc, eLOG_Critical, "g_LBOS_StringConcat: No RAM. Returning NULL."); - free(buf); free(dest); return NULL; } @@ -576,23 +579,24 @@ char* g_LBOS_GetLBOSAddressEx (ELBOSFindMethod priority_find_method, break; case eLBOS_FindMethod_CustomHost : if (g_LBOS_StringIsNullOrEmpty(lbos_addr)) { - CORE_LOG_X(1, eLOG_Warning, "Use of custom LBOS address was " - "asked for, but no custom address was supplied. " - "Using default LBOS."); + CORE_LOG_X(1, eLOG_Error, "Use of custom LBOS address " + "requested, but no custom address supplied. " + "Using default LBOS"); break; } address = strdup(lbos_addr); if (address == NULL) { - CORE_LOG_X(1, eLOG_Warning, "Did not manage to copy custom " - "LBOS address. Probably insufficient RAM."); + CORE_LOG_ERRNO_X(1, eLOG_Warning, errno, + "Cannot copy custom LBOS address"); } break; case eLBOS_FindMethod_Lbosresolve : #if defined NCBI_OS_LINUX || defined NCBI_OS_MSWIN lbosaddress = s_LBOS_ReadLbosresolver(); if (g_LBOS_StringIsNullOrEmpty(lbosaddress)) { - CORE_LOG_X(1, eLOG_Warning, "Trying to find LBOS using " - "/etc/ncbi/lbosresolve failed"); + CORE_LOGF_X(1, eLOG_Warning, + ("Attempt to locate LBOS using %s has failed", + kLbosresolverFile)); } else { address = strdup(lbosaddress); } @@ -601,10 +605,10 @@ char* g_LBOS_GetLBOSAddressEx (ELBOSFindMethod priority_find_method, case eLBOS_FindMethod_Registry: lbosaddress_temp = g_LBOS_RegGet("CONN", "lbos", NULL); if (g_LBOS_StringIsNullOrEmpty(lbosaddress_temp)) { - CORE_LOG_X(1, eLOG_Warning, "Trying to find LBOS in " - "registry [CONN]lbos failed. " - "Using address in " - "/etc/ncbi/lbosresolver"); + CORE_LOGF_X(1, eLOG_Note, + ("Attempt to locate LBOS in registry" + " [CONN]LBOS has failed. Using address from %s", + kLbosresolverFile)); free(lbosaddress_temp); /* just in case */ lbosaddress_temp = NULL; break; @@ -710,55 +714,58 @@ static const char* s_LBOS_ReadRole() */ static const char* s_LBOS_ReadLbosresolver(void) { - if (s_LBOS_Lbosresolver != NULL) { + if (s_LBOS_Lbosresolver) { return s_LBOS_Lbosresolver; } - FILE* lbosresolver_file; + FILE* fp; + char str[kMaxLineSize]; size_t len; - char str[kMaxLineSize]; - char* read_result; /* during function will become equal either NULL - or str, do not free() */ - if ((lbosresolver_file = fopen(kLbosresolverFile, "r")) == NULL) { - CORE_LOGF(eLOG_Warning, ("LBOS mapper: " - "could not open file %s", - kLbosresolverFile)); - return NULL; + char* rv; + + if (!(fp = fopen(kLbosresolverFile, "r"))) { + CORE_LOGF_ERRNO(eLOG_Warning, errno, + ("[LBOS] Cannot open %s", + kLbosresolverFile)); + return 0; } - read_result = fgets(str, sizeof(str), lbosresolver_file); - fclose(lbosresolver_file); - if (read_result == NULL) { - CORE_LOG(eLOG_Warning, "s_LBOS_ReadLBOSResolve: " - "memory allocation failed"); - return NULL; + rv = fgets(str, sizeof(str), fp); + fclose(fp); + + if (!rv) { + CORE_LOGF_ERRNO(eLOG_Warning, errno, + ("[LBOS] Cannot read %s", + kLbosresolverFile)); + return 0; } - len = strlen(str); - assert(len); + + verify((len = strlen(str))); if (g_LBOS_StringIsNullOrEmpty(str)) { /* No domain recognized */ CORE_LOGF(eLOG_Warning, - ("LBOS mapper: file %s is empty, no LBOS address available", + ("[LBOS] No LBOS address found in %s", kLbosresolverFile)); - free(read_result); - return NULL; + return 0; } - /*We remove unnecessary '/n' and probably '/r' */ + + /* Remove unnecessary '/n' and probably '/r' */ if (str[len - 1] == '\n') { - if (--len && str[len - 1] == '\r') { + if (--len && str[len - 1] == '\r') { --len; } str[len] = '\0'; } + CORE_LOCK_WRITE; - /* Check one more time that no other thread managed to fill - * static variable ahead of this thread. If this happened, - * release memory */ - if (s_LBOS_Lbosresolver == NULL) - /* We skip "http://" and "/lbos" */ - str[strlen(str) - strlen("/lbos")] = '\0'; - s_LBOS_Lbosresolver = strdup(str + 7); + /* Check one more time that no other thread managed to fill static + * variable ahead of this thread. If that happened, do nothing */ + if (s_LBOS_Lbosresolver == 0) { + /* Strip both trailing "/lbos" and leading "http://" */ + str[len - 5] = '\0'; + s_LBOS_Lbosresolver = strdup(str + 7); + } CORE_UNLOCK; - + return s_LBOS_Lbosresolver; } #endif /* defined NCBI_OS_LINUX || defined NCBI_OS_MSWIN */ @@ -819,12 +826,12 @@ static CONN s_LBOS_ConnectURL(SConnNetInfo* net_info, const char* url, CONN conn; CONNECTOR connector; - CORE_LOGF(eLOG_Note, ("Parsing URL \"%s\"", url)); + CORE_LOGF(eLOG_Trace, ("Parsing URL \"%s\"", url)); if (!ConnNetInfo_ParseURL(net_info, url)) { CORE_LOG(eLOG_Warning, "Cannot parse URL"); return NULL; } - CORE_LOGF(eLOG_Note, ("Creating HTTP%s connector", + CORE_LOGF(eLOG_Trace, ("Creating HTTP%s connector", &"S"[net_info->scheme != eURL_Https])); if (!(connector = HTTP_CreateConnectorEx(net_info, flags, g_LBOS_UnitTesting_GetLBOSFuncs()->ParseHeader, @@ -834,7 +841,7 @@ static CONN s_LBOS_ConnectURL(SConnNetInfo* net_info, const char* url, CORE_LOG(eLOG_Warning, "Cannot create HTTP connector"); return NULL; } - CORE_LOG(eLOG_Note, "Creating connection"); + CORE_LOG(eLOG_Trace, "Creating connection"); if (CONN_Create(connector, &conn) != eIO_Success) { CORE_LOG(eLOG_Warning, "Cannot create connection"); return NULL; @@ -1078,10 +1085,11 @@ static SSERV_Info** s_LBOS_ResolveIPPort(const char* lbos_address, serviceEndpoints = x_json_object_get_array(services, x_json_object_get_name(services, 0)); /* Iterate through endpoints */ + time_t now = 0; for (j = 0; j < x_json_array_get_count(serviceEndpoints); j++) { const char *host, *rate, *extra, *type; char* server_description; - const char* descr_format = "%s %s:%u %s Regular R=%s L=no T=25"; + const char* descr_format = "%s %s:%u %s R=%s T=%lu"; int port; serviceEndpoint = x_json_array_get_object(serviceEndpoints, j); host = x_json_object_dotget_string(serviceEndpoint, @@ -1098,7 +1106,7 @@ static SSERV_Info** s_LBOS_ResolveIPPort(const char* lbos_address, /* -------------type------------- */ type = x_json_object_dotget_string(serviceEndpoint, "meta.type"); - type = !g_LBOS_StringIsNullOrEmpty(type) ? type : "STANDALONE"; + type = !g_LBOS_StringIsNullOrEmpty(type) ? type : "HTTP"; /* -------------extra------------- */ extra = x_json_object_dotget_string(serviceEndpoint, "meta.extra"); @@ -1113,11 +1121,20 @@ static SSERV_Info** s_LBOS_ResolveIPPort(const char* lbos_address, size_t length; /* used to count size to allocate for server_description, and then for g_LBOS_StringConcat*/ /* Occasionally, we are not able to allocate memory */ + if (!*extra) { + if (strncasecmp(type, "HTTP", 4) == 0) + extra = "/"; + else if (strcasecmp(type, "NCBID") == 0) + extra = "''"; + } length = strlen(descr_format) + strlen(type) + strlen(host) + - 5 /*length of port*/ + strlen(extra) + strlen(rate); + 5 /*length of port*/ + strlen(extra) + strlen(rate) + + 40/*time*/; server_description = malloc(sizeof(char) * length); + if (!now) + now = time(0); sprintf(server_description, descr_format, type, host, - port, extra, rate); + port, extra, rate, (unsigned long) now + 25); SSERV_Info * info = SERV_ReadInfoEx(server_description,service_name, 0); free(server_description); if (info == NULL) { @@ -1186,7 +1203,7 @@ static void s_LBOS_FillCandidates(SLBOS_Data* data, const char* service) g_LBOS_UnitTesting_GetLBOSFuncs()->ResolveIPPort(lbos_address, service, data->net_info); if (hostports_array == NULL) { - CORE_LOGF_X(1, eLOG_Trace, ("Ho servers of \"%s\" found by LBOS", + CORE_LOGF_X(1, eLOG_Trace, ("No servers of \"%s\" found by LBOS", service)); return; } @@ -1260,8 +1277,8 @@ static int s_LBOS_CheckAnnounceArgs(const char* service, } } } - if (port < 1 || port > 65535) { - CORE_LOG(eLOG_Critical, "Error with announcement, incorrect port."); + if (!port) { + CORE_LOG(eLOG_Critical, "Error with announcement, invalid port."); return 0; } if (g_LBOS_StringIsNullOrEmpty(version)) { @@ -1294,9 +1311,9 @@ static int s_LBOS_CheckDeannounceArgs(const char* service, "not contain protocol or port"); return 0; } - if (port < 1 || port > 65535) { + if (!port) { CORE_LOG(eLOG_Critical, "Invalid argument passed for de-announcement, " - "incorrect port."); + "invalid port."); return 0; } if (g_LBOS_StringIsNullOrEmpty(version)) { @@ -1608,6 +1625,10 @@ static void s_LBOS_Initialize(void) } if (s_EmptyNetInfo == NULL) { s_EmptyNetInfo = ConnNetInfo_Create(NULL); + if (s_EmptyNetInfo) { + s_EmptyNetInfo->scheme = eURL_Http; + s_EmptyNetInfo->req_method = eReqMethod_Any; + } } CORE_UNLOCK; s_LBOS_TurnedOn = 1; /* To ensure that initialization does @@ -1626,19 +1647,6 @@ static void s_LBOS_Initialize(void) ("DTAB from registry: %s ", s_LBOS_DTABLocal)); } - /* Check On/Off status */ - char* lbos_toggle = g_LBOS_RegGet("CONN", "LBOS_ENABLE", NULL); - int lbos_toggled = ConnNetInfo_Boolean(lbos_toggle); - free(lbos_toggle); - if (lbos_toggled) { - CORE_LOG_X(1, eLOG_Note, "LBOS is turned ON in config."); - } else { - CORE_LOG_X(1, eLOG_Warning, - "LBOS is NOT turned ON in config! Please provide " - "[CONN]LBOS_ENABLE=1"); - s_LBOS_TurnedOn = 0; - return; - } /* * Try to find LBOS */ @@ -1930,24 +1938,19 @@ const SSERV_VTable* SERV_LBOS_Open( SERV_ITER iter, data->net_info = ConnNetInfo_Clone(s_EmptyNetInfo); } else { data->net_info = ConnNetInfo_Clone(net_info); - } - // Check if CONNECT_Init() has been run before - if (g_CORE_GetRequestDtab == NULL) { - CORE_LOG(eLOG_Critical, - "LBOS FAIL! Please run CONNECT_Init() prior to using LBOS!\n" - "Example:\n" - "CNcbiRegistry& config = CNcbiApplication::Instance()" - "->GetConfig();\n" - "CONNECT_Init(&config);\n" - "LBOS::Announce(...);"); - s_LBOS_DestroyData(data); - if (iter->name != orig_serv_name) { - free(new_name); - iter->name = orig_serv_name; + if (data->net_info) { + data->net_info->scheme = eURL_Http; + data->net_info->req_method = eReqMethod_Any; } - return NULL; } - const char* request_dtab = g_CORE_GetRequestDtab(); + // Check if CONNECT_Init() has been called before + const char* request_dtab = 0; + if (!g_CORE_GetRequestDtab) { + CORE_LOG(eLOG_Critical, + "LBOS MAY FAIL! " + " Make sure to call CONNECT_Init() prior to using LBOS!"); + } else + request_dtab = g_CORE_GetRequestDtab(); if (!g_LBOS_StringIsNullOrEmpty(request_dtab)) { /* Add a semicolon to separate DTabs */ ConnNetInfo_ExtendUserHeader(data->net_info, "DTab-Local: ;"); diff --git a/c++/src/connect/ncbi_lbos_cxx.cpp b/c++/src/connect/ncbi_lbos_cxx.cpp index 836e5932..3ce05e49 100644 --- a/c++/src/connect/ncbi_lbos_cxx.cpp +++ b/c++/src/connect/ncbi_lbos_cxx.cpp @@ -293,7 +293,7 @@ void LBOS::AnnounceFromRegistry(const string& reg_sec) const string& reg_section = reg_sec.empty() ? kLBOSAnnounceRegistrySection : reg_sec; LOG_POST(Error << "Registry section is " << reg_section); - CNcbiRegistry& config = CNcbiApplication::Instance()->GetConfig(); + const CNcbiRegistry& config = CNcbiApplication::Instance()->GetConfig(); string host = config.Get(reg_section, kLBOSServerHostVariable); string service = config.Get(reg_section, kLBOSServiceVariable); string version = config.Get(reg_section, kLBOSVersionVariable); @@ -530,8 +530,9 @@ const char* CLBOSException::GetErrCodeString(void) const return "Failed to parse LBOS output."; /* 550 */ case eDisabled: - return "LBOS functionality is turned OFF. Check config file or " - "connection to LBOS."; + return "LBOS functionality is turned OFF. " + "Check that registry has [CONN]LBOS_ENABLE=1 and " + "that connection to LBOS is stable"; default: return "Unknown LBOS error code"; } diff --git a/c++/src/connect/ncbi_localip.c b/c++/src/connect/ncbi_localip.c new file mode 100644 index 00000000..71180b73 --- /dev/null +++ b/c++/src/connect/ncbi_localip.c @@ -0,0 +1,396 @@ +/* $Id: ncbi_localip.c 537410 2017-05-31 16:20:20Z lavr $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * Determine IP locality (within NCBI) of a given address + * + */ + +#include "ncbi_ansi_ext.h" +#include "ncbi_assert.h" +#include "ncbi_priv.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(NCBI_OS_UNIX) +# include +# include +# include +# include +#elif defined(NCBI_OS_MSWIN) +# include +# ifndef R_OK +# define R_OK 2 +# endif /*!R_OK*/ +#endif /*NCBI_OS_...*/ + +#define NCBI_USE_ERRCODE_X Connect_LocalIP + + +#ifndef INADDR_LOOPBACK +# define INADDR_LOOPBACK 0x7F000001 +#endif /*!INADDR_LOOPBACK*/ + +#if defined(NCBI_OS_MSWIN) && !defined(PATH_MAX) +# ifdef _MAX_PATH +# define PATH_MAX _MAX_PATH +#else +# define PATH_MAX 1024 +# endif /*_MAX_PATH*/ +#endif /*NCBI_OS_MSWIN && !PATH_MAX*/ + +#if PATH_MAX < 256 +# define BUFSIZE 256 +#else +# define BUFSIZE PATH_MAX +#endif /*PATHMAX<256*/ + +#ifdef SizeOf +# undef SizeOf +#endif /*SizeOf*/ +#define SizeOf(a) (sizeof(a) / sizeof((a)[0])) + +#if defined(_DEBUG) && !defined(NDEBUG) +/*# define NCBI_LOCALIP_DEBUG 1*/ +#endif /*_DEBUG && !NDEBUG*/ + + +static int/*bool*/ s_Inited = 0/*false*/; + + +static SIPRange s_LocalIP[256 + 1] = { { eIPRange_None } }; + + +#ifdef HAVE_LIBCONNEXT + + +# include "ext/ncbi_localip.c" + + +static const SIPRange* x_IsOverlappingRange(const SIPRange* range, size_t n) +{ + size_t i; + assert(n < SizeOf(s_LocalIP)); + for (i = 0; i < n; ++i) { + if (NcbiIsInIPRange(&s_LocalIP[i], &range->a) || + NcbiIsInIPRange(range, &s_LocalIP[i].a)) { + return &s_LocalIP[i]; + } + } + return 0/*no overlap*/; +} + + +static int/*bool*/ xx_LoadLocalIPs(CONN conn) +{ + unsigned int domain; + EIO_Status status; + char buf[128+1]; + size_t n, len; + int lineno; + + /* localnet */ + NcbiIPv4ToIPv6(&s_LocalIP[0].a, SOCK_HostToNetLong(kLocalIP[0].a), 0); + s_LocalIP[0].b = SOCK_HostToNetLong(kLocalIP[0].b); + s_LocalIP[0].type = kLocalIP[0].t; + /* IPv6 localhost, ::1 */ + memset(&s_LocalIP[1], 0, sizeof(s_LocalIP[1])); + s_LocalIP[1].a.octet[sizeof(s_LocalIP[1].a.octet) - 1] = 1; + s_LocalIP[1].type = eIPRange_Host; + + domain = 0; + lineno = 0; + n = 2/*localnet(s) always added*/; + while ((status = CONN_ReadLine(conn, buf, sizeof(buf) - 1, &len)) + == eIO_Success) { + SIPRange local; + char* c, *err; + + ++lineno; + if (!len) + continue; + if (buf[len - 1] == '\r') + --len; + buf[len] = '\0'; + if (!(len = strcspn(buf, "!#"))) + continue; + if (!*(c = buf + strspn(buf, " \t"))) + continue; + len = strcspn(c, " \t"); + err = c + len; + if (*err && !*(err += strspn(err, " \t"))) + c[len] = '\0'; + if (!*err && len && *c == '[' && c[--len] == ']') { + c[len] = '\0'; + if (len > sizeof(local.a.octet) - 1) + len = sizeof(local.a.octet) - 1; + strncpy0((char*) local.a.octet, ++c, len); + for (len = 2; len < n; ++len) { + if (s_LocalIP[len].type == eIPRange_Application + && strcasecmp((const char*) s_LocalIP[len].a.octet, + (const char*) local.a.octet) == 0) { + CORE_LOGF_X(2, eLOG_Error, + ("Ignoring duplicate domain at line %u: '%s'", + lineno, c)); + break; + } + } + if (len < n) + continue; + local.b = ++domain; + local.type = eIPRange_Application; + } else { + const SIPRange* over; + if (*err || !NcbiParseIPRange(&local, c) + || (local.type == eIPRange_Host && NcbiIsEmptyIPv6(&local.a))){ + if (!*err) + err = c; + CORE_LOGF_X(3, eLOG_Error, + ("Ignoring invalid local IP spec at line %u: '%s'", + lineno, err)); + continue; + } + if ((over = x_IsOverlappingRange(&local, n)) != 0) { + char temp[150]; + const char* tmp + = strchr(NcbiDumpIPRange(over, temp, sizeof(temp)), ' '); + if (!tmp++) + tmp = temp; + CORE_LOGF_X(4, eLOG_Warning, + ("Local IP spec at line %u, '%s' overlaps with" + " already defined one: %s", lineno, c, tmp)); + } + } + assert(local.type != eIPRange_None); + if (n >= SizeOf(s_LocalIP)) { + CORE_LOGF_X(5, eLOG_Error, + ("Too many local IP specs, max %u allowed", + (unsigned int)(n - 2/*localnet*/))); + break; + } + s_LocalIP[n++] = local; + } + if (status != eIO_Closed || n < 3) + return 0/*false*/; + + if (n < SizeOf(s_LocalIP)) + s_LocalIP[n].type = eIPRange_None; + + n -= 2; /* compensate for auto-added localnet(s) */ + CORE_LOGF(eLOG_Trace, ("Done loading local IP specs, %u line%s, %u entr%s" + " (%u domain%s)", lineno, &"s"[lineno == 1], + (unsigned int) n, n == 1 ? "y" : "ies", + domain, &"s"[domain == 1])); + return 1/*true*/; +} + + +static int/*bool*/ x_LoadLocalIPs(CONNECTOR c, const char* source) +{ + CONN conn; + int/*bool*/ loaded = 0/*false*/; + if (c && CONN_Create(c, &conn) == eIO_Success) { + CORE_LOGF(eLOG_Trace, + ("Loading local IP specs from \"%s\"", source)); + loaded = xx_LoadLocalIPs(conn); + CONN_Close(conn); + } else if (c && c->destroy) + c->destroy(c); + return loaded; +} + + +static void s_LoadLocalIPs(void) +{ + static const char* kFile[] = { + "/etc/ncbi/local_ips_v2", + "/etc/ncbi/local_ips" + }; + static const char kLocalIPs[] = "LOCAL_IPS"; + char buf[PATH_MAX + 1]; + const char* file = ConnNetInfo_GetValue(0, kLocalIPs, + buf, sizeof(buf) - 1, ""); + size_t n; + + if (file && strcasecmp(file, "--HARDCODED--") != 0) { + SConnNetInfo* net_info; + ELOG_Level level; + for (n = 0; n < SizeOf(kFile); ++n) { + if (n || !*file) + file = kFile[n]; + if (access(file, R_OK) == 0 && + x_LoadLocalIPs(FILE_CreateConnector(file, 0), file)) { + return; + } + if (errno == ENOENT && file != buf) { +# ifdef NCBI_OS_LINUX + level = n ? eLOG_Warning : eLOG_Trace; +# else + level = eLOG_Trace; +# endif /*NCBI_OS_LINUX*/ + } else + level = eLOG_Error; + CORE_LOGF_ERRNO_X(1, level, errno, + ("Cannot load local IP specs from \"%s\"",file)); + if (file == buf) + break; + } + net_info = ConnNetInfo_Create(kLocalIPs); + /* Build HTTP connector here to save on a dispatcher hit */ + if (ConnNetInfo_SetupStandardArgs(net_info, kLocalIPs) && + x_LoadLocalIPs(HTTP_CreateConnector(net_info, + "User-Agent: ncbi_localnet", + fHTTP_NoAutoRetry | + fHTTP_SuppressMessages), + kLocalIPs)) { + ConnNetInfo_Destroy(net_info); + return; + } + ConnNetInfo_Destroy(net_info); + if (net_info) { +# ifdef NCBI_OS_LINUX + level = eLOG_Trace; +# else + level = eLOG_Warning; +# endif /*NCBI_OS_LINUX*/ + } else + level = eLOG_Error; + CORE_LOGF_X(1, level, + ("Cannot load local IP specs from \"%s\"", kLocalIPs)); + } + + CORE_LOG(eLOG_Trace, "Using default local IPv4 specs"); + assert(SizeOf(s_LocalIP) > SizeOf(kLocalIP)); + for (n = 0; n < SizeOf(kLocalIP); ++n) { + s_LocalIP[n].type = kLocalIP[n].t; + NcbiIPv4ToIPv6(&s_LocalIP[n].a, + SOCK_HostToNetLong(kLocalIP[n].a), 0); + s_LocalIP[n].b = SOCK_HostToNetLong(kLocalIP[n].b); + } + s_LocalIP[n].type = eIPRange_None; +} + + +#else + + +#define s_LoadLocalIPs() /*void*/ + + +#endif /*HAVE_LIBCONNEXT*/ + + +extern void NcbiInitLocalIP(void) +{ + /*CORE_LOCK_WRITE;*/ + s_Inited = 0/*F*/; + /*CORE_UNLOCK;*/ +} + + +extern int/*bool*/ NcbiIsLocalIPEx(const TNCBI_IPv6Addr* addr, + SNcbiDomainInfo* info) +{ + size_t n; + + if (!s_Inited) { + CORE_LOCK_WRITE; + if (!s_Inited) { + s_LoadLocalIPs(); + s_Inited = 1; + CORE_UNLOCK; +#ifdef NCBI_LOCALIP_DEBUG + for (n = 0; n < SizeOf(s_LocalIP); ++n) { + char buf[150]; + const char* result; + if (s_LocalIP[n].type == eIPRange_Application) { + assert(s_LocalIP[n].b); + sprintf(buf, "Domain %u: %s", + s_LocalIP[n].b, s_LocalIP[n].a.octet); + assert(strlen(buf) < sizeof(buf)); + result = buf; + } else + result = NcbiDumpIPRange(s_LocalIP + n, buf, sizeof(buf)); + if (result) + CORE_LOG_X(1, eLOG_Trace, result); + if (s_LocalIP[n].type == eIPRange_None) + break; + } +#endif /*NCBI_LOCALIP_DEBUG*/ + } else + CORE_UNLOCK; + } + + if (addr) { + SNcbiDomainInfo x_info; + memset(&x_info, 0, sizeof(x_info)); + for (n = 0; n < SizeOf(s_LocalIP); ++n) { + if (s_LocalIP[n].type == eIPRange_None) + break; + if (s_LocalIP[n].type == eIPRange_Application) { + x_info.sfx = (const char*) s_LocalIP[n].a.octet; + x_info.num = s_LocalIP[n].b; + continue; + } + if (NcbiIsInIPRange(s_LocalIP + n, addr)) { + if ( info ) + *info = x_info; + return 1/*true*/; + } + } + } + + if (info) + memset(info, 0, sizeof(*info)); + return 0/*false*/; +} + + +extern int/*bool*/ NcbiIsLocalIP(unsigned int ip) +{ + if (ip) { + unsigned int addr = SOCK_NetToHostLong(ip); + if ( +#ifdef IN_BADCLASS + !IN_BADCLASS(addr) +#else + (addr & 0xF0000000) ^ 0xF0000000 +#endif /*IN_BADCLASS*/ + ) { + TNCBI_IPv6Addr temp; + NcbiIPv4ToIPv6(&temp, ip, 0); + return NcbiIsLocalIPEx(&temp, 0); + } + } + return 0/*false*/; +} diff --git a/c++/src/connect/ncbi_mbedtls.c b/c++/src/connect/ncbi_mbedtls.c new file mode 100644 index 00000000..1aeb08fc --- /dev/null +++ b/c++/src/connect/ncbi_mbedtls.c @@ -0,0 +1,739 @@ +/* $Id: ncbi_mbedtls.c 545593 2017-09-07 18:06:33Z ivanov $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * MBEDTLS support for SSL in connection library + * + */ + +#include "ncbi_ansi_ext.h" +#include "ncbi_connssl.h" +#include "ncbi_priv.h" +#include +#include +#include + +#if defined(HAVE_LIBMBEDTLS) || defined(NCBI_CXX_TOOLKIT) + +# ifdef HAVE_LIBMBEDTLS /* external */ +# include +# include +# include +# include +# include +# include +# include +# include +# else +# include "mbedtls/mbedtls/ctr_drbg.h" +# include "mbedtls/mbedtls/debug.h" +# include "mbedtls/mbedtls/entropy.h" +# include "mbedtls/mbedtls/error.h" +# include "mbedtls/mbedtls/net_sockets.h" +# include "mbedtls/mbedtls/ssl.h" +# include "mbedtls/mbedtls/threading.h" +# include "mbedtls/mbedtls/version.h" +# endif /*HAVE_LIBMBEDTLS*/ + +# if defined(ENOTSUP) +# define NCBI_NOTSUPPORTED ENOTSUP +# elif defined(ENOSYS) +# define NCBI_NOTSUPPORTED ENOSYS +# else +# define NCBI_NOTSUPPORTED EINVAL +# endif + + +# if defined(MBEDTLS_THREADING_ALT) && defined(NCBI_THREADS) +# ifdef MBEDTLS_THREADING_PTHREAD +# error "MBEDTLS_THREADING_ALT and MBEDTLS_THREADING_PTHREAD conflict" +# endif /*MBEDTLS_THREADING_PTHREAD*/ +static void mbtls_user_mutex_init(MT_LOCK* lock) +{ + if (lock) + *lock = MT_LOCK_AddRef(g_CORE_MT_Lock); +} +static void mbtls_user_mutex_deinit(MT_LOCK* lock) +{ + if (lock) { + g_CORE_MT_Lock = MT_LOCK_Delete(*lock); + *lock = 0; + } +} +static int mbtls_user_mutex_lock(MT_LOCK* lock) +{ + if (lock) { + switch (MT_LOCK_Do((MT_LOCK)(*lock), eMT_Lock)) { + case -1: + return MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE; + case 0: + return MBEDTLS_ERR_THREADING_MUTEX_ERROR; + case 1: + return 0; + default: + break; + } + } + return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA; +} +static int mbtls_user_mutex_unlock(MT_LOCK* lock) +{ + if (lock) { + switch (MT_LOCK_Do((MT_LOCK)(*lock), eMT_Unlock)) { + case -1: + return MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE; + case 0: + return MBEDTLS_ERR_THREADING_MUTEX_ERROR; + case 1: + return 0; + default: + break; + } + } + return MBEDTLS_ERR_THREADING_BAD_INPUT_DATA; +} +# endif /*MBEDTLS_THREADING_ALT && NCBI_THREADS*/ + +# ifdef __cplusplus +extern "C" { +# endif /*__cplusplus*/ + +static EIO_Status s_MbedTlsInit (FSSLPull pull, FSSLPush push); +static void* s_MbedTlsCreate(ESOCK_Side side, SOCK sock, + const char* host, NCBI_CRED cred, + int* error); +static EIO_Status s_MbedTlsOpen (void* session, int* error, char** desc); +static EIO_Status s_MbedTlsRead (void* session, void* buf, + size_t size, size_t* done, int* error); +static EIO_Status s_MbedTlsWrite (void* session, const void* data, + size_t size, size_t* done, int* error); +static EIO_Status s_MbedTlsClose (void* session, int how, int* error); +static void s_MbedTlsDelete(void* session); +static void s_MbedTlsExit (void); +static const char* s_MbedTlsError (void* session, int error, + char* buf, size_t size); + +static void x_MbedTlsLogger(void* data, int level, + const char* file, int line, + const char* message); +static int x_MbedTlsPull (void*, unsigned char*, size_t); +static int x_MbedTlsPush (void*, const unsigned char*, size_t); + +# ifdef __cplusplus +} +# endif /*__cplusplus*/ + + +static int s_MbedTlsLogLevel; +static mbedtls_entropy_context s_MbedTlsEntropy; +static mbedtls_ctr_drbg_context s_MbedTlsCtrDrbg; +static mbedtls_ssl_config s_MbedTlsConf; +static FSSLPull s_Pull; +static FSSLPush s_Push; + + +/*ARGSUSED*/ +static void x_MbedTlsLogger(void* unused, int level, + const char* file, int line, + const char* message) +{ + /* do some basic filtering and EOL cut-offs */ + size_t len = message ? strlen(message) : 0; + if (!len || *message == '\n') + return; + if (message[len - 1] == '\n') + --len; + CORE_LOGF(eLOG_Note, ("MBEDTLS%d: %.*s", level, (int) len, message)); +} + + +# ifdef __GNUC__ +inline +# endif /*__GNUC__*/ +static EIO_Status x_RetryStatus(SOCK sock, EIO_Event direction) +{ + EIO_Status status; + if (direction == eIO_Open) { + EIO_Status r_status = SOCK_Status(sock, eIO_Read); + EIO_Status w_status = SOCK_Status(sock, eIO_Write); + status = r_status > w_status ? r_status : w_status; + } else + status = SOCK_Status(sock, direction); + return status == eIO_Success ? eIO_Timeout : status; +} + + +# ifdef __GNUC__ +inline +# endif /*__GNUC__*/ +static EIO_Status x_ErrorToStatus(int error, mbedtls_ssl_context* session, + EIO_Event direction) +{ + SOCK sock; + EIO_Status status; + + assert(error <= 0); + + if (!error) + return eIO_Success; + sock = (SOCK) session->p_bio; + switch (error) { + case MBEDTLS_ERR_SSL_WANT_READ: + status = x_RetryStatus(sock, direction); + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + status = x_RetryStatus(sock, direction); + break; + case MBEDTLS_ERR_SSL_TIMEOUT: + status = eIO_Timeout; + break; + case MBEDTLS_ERR_THREADING_FEATURE_UNAVAILABLE: + case MBEDTLS_ERR_SSL_FEATURE_UNAVAILABLE: + case MBEDTLS_ERR_SSL_INTERNAL_ERROR: + status = eIO_NotSupported; + break; + case MBEDTLS_ERR_THREADING_BAD_INPUT_DATA: + case MBEDTLS_ERR_SSL_BAD_INPUT_DATA: + status = eIO_InvalidArg; + break; + case MBEDTLS_ERR_NET_CONN_RESET: + case MBEDTLS_ERR_SSL_CONN_EOF: + case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: + case MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE: + status = eIO_Closed; + break; + case MBEDTLS_ERR_NET_RECV_FAILED: + if (sock->r_status != eIO_Success && + sock->r_status != eIO_Unknown) { + status = sock->r_status; + } else + status = eIO_Unknown; + break; + case MBEDTLS_ERR_NET_SEND_FAILED: + if (sock->w_status != eIO_Success && + sock->w_status != eIO_Unknown) { + status = sock->w_status; + } else + status = eIO_Unknown; + break; + case MBEDTLS_ERR_SSL_NON_FATAL: + /*return eIO_Interrupt;*/ + default: + status = eIO_Unknown; + break; + } + + CORE_LOGF(eLOG_Trace, ("MBEDTLS error %d -> CONNECT MBEDTLS status %s", + error, IO_StatusStr(status))); + + return status; +} + + +# ifdef __GNUC__ +inline +# endif /*__GNUC__*/ +static int x_StatusToError(EIO_Status status, SOCK sock, EIO_Event direction) +{ + int error; + + assert(status != eIO_Success); + assert(direction == eIO_Read || direction == eIO_Write); + + switch (status) { + case eIO_Timeout: + error = EAGAIN; + break; + case eIO_Closed: + error = SOCK_ENOTCONN; + break; + case eIO_Interrupt: + error = SOCK_EINTR; + break; + case eIO_NotSupported: + error = NCBI_NOTSUPPORTED; + break; + case eIO_Unknown: + error = 0/*keep*/; + break; + default: + /*NB:eIO_InvalidArg*/ + error = EINVAL; + break; + } + + {{ + const char* x_what = error ? "error" : "errno"; + int x_error = error ? error : errno; + CORE_LOGF(eLOG_Trace, ("CONNECT MBEDTLS status %s -> %s %d", + IO_StatusStr(status), x_what, x_error)); + if (!error) + errno = x_error; /* restore errno that may be clobbered by log */ + }} + + if (error) + errno = error; + else if (!(error = errno)) + error = EINVAL; + + switch (error) { + case EAGAIN: + case SOCK_EINTR: + return direction == eIO_Read + ? MBEDTLS_ERR_SSL_WANT_READ + : MBEDTLS_ERR_SSL_WANT_WRITE; + case SOCK_ENOTCONN: + return MBEDTLS_ERR_NET_CONN_RESET; + default: + break; + } + return MBEDTLS_ERR_SSL_INTERNAL_ERROR; +} + + +static void* s_MbedTlsCreate(ESOCK_Side side, SOCK sock, + const char* host, NCBI_CRED cred, int* error) +{ + int end = (side == eSOCK_Client + ? MBEDTLS_SSL_IS_CLIENT + : MBEDTLS_SSL_IS_SERVER); + mbedtls_ssl_context* session; + + if (end == MBEDTLS_SSL_IS_SERVER) { + /*FIXME: not yet supported*/ + *error = 0; + return 0; + } + + *error = 0; + + if (cred && (cred->type != eNcbiCred_MbedTls || !cred->data)) { + /*FIXME: there's a NULL(data)-terminated array of credentials */ + CORE_LOGF(eLOG_Error, + ("%s credentials in MBEDTLS session", + cred->type != eNcbiCred_MbedTls + ? "Foreign" + : "Empty")); + return 0; + } + + if (!(session = (mbedtls_ssl_context*) malloc(sizeof(*session)))) { + *error = errno; + return 0; + } + mbedtls_ssl_init(session); + if ((*error = mbedtls_ssl_setup(session, &s_MbedTlsConf)) != 0) { + mbedtls_ssl_free(session); + free(session); + return 0; + } + + if (host && *host + && (*error = mbedtls_ssl_set_hostname(session, host)) != 0) { + mbedtls_ssl_free(session); + free(session); + return 0; + } + + mbedtls_ssl_set_bio(session, sock, x_MbedTlsPush, x_MbedTlsPull, 0); + + return session; +} + + +static EIO_Status s_MbedTlsOpen(void* session, int* error, char** desc) +{ + EIO_Status status; + int x_error; + + *desc = 0; + + x_error = mbedtls_ssl_handshake((mbedtls_ssl_context*) session); + + if (x_error < 0) { + status = x_ErrorToStatus(x_error, (mbedtls_ssl_context*) session, + eIO_Open); + *error = x_error; + } else + status = eIO_Success; + + return status; +} + + +#ifdef __GNUC__ +inline +#endif /*__GNUC__*/ +static int/*bool*/ x_IfToLog(void) +{ + return 4 < s_MbedTlsLogLevel ? 1/*T*/ : 0/*F*/; +} + + +static int x_MbedTlsPull(void* ctx, unsigned char* buf, size_t size) +{ + EIO_Status status; + SOCK sock = (SOCK) ctx; + FSSLPull pull = s_Pull; + + if (pull) { + size_t x_read = 0; + status = pull(sock, buf, size, &x_read, x_IfToLog()); + if (x_read > 0 || status == eIO_Success/*&& x_read==0*/) { + assert(status == eIO_Success); + assert(x_read <= size); + return (int) x_read; + } + } else + status = eIO_NotSupported; + + return x_StatusToError(status, sock, eIO_Read); +} + + +static int x_MbedTlsPush(void* ctx, const unsigned char* data, size_t size) +{ + EIO_Status status; + SOCK sock = (SOCK) ctx; + FSSLPush push = s_Push; + + if (push) { + ssize_t n_written = 0; + do { + size_t x_written = 0; + status = push(sock, data, size, &x_written, x_IfToLog()); + if (!x_written) { + assert(!size || status != eIO_Success); + if (size || status != eIO_Success) + goto out; + } else { + assert(status == eIO_Success); + assert(x_written <= size); + n_written += x_written; + size -= x_written; + data = data + x_written; + } + } while (size); + return (int) n_written; + } else + status = eIO_NotSupported; + + out: + return x_StatusToError(status, sock, eIO_Write); +} + + +static EIO_Status x_InitLocking(void) +{ + EIO_Status status; + +# ifdef NCBI_THREADS + switch (mbedtls_version_check_feature("MBEDTLS_THREADING_C")) { + case 0: + break; + case -1: + return eIO_NotSupported; + case -2: + return eIO_InvalidArg; + default: + return eIO_Unknown; + } +# endif /*NCBI_THREADS*/ +# ifdef MBEDTLS_THREADING_PTHREAD + status = eIO_Success; +# elif defined(MBEDTLS_THREADING_ALT) && defined(NCBI_THREADS) + MT_LOCK lk = CORE_GetLOCK(); + if (MT_LOCK_Do(lk, eMT_Lock) != -1) { + mbedtls_threading_set_alt(mbtls_user_mutex_init, + mbtls_user_mutex_deinit, + mbtls_user_mutex_lock, + mbtls_user_mutex_unlock); + MT_LOCK_Do(lk, eMT_Unlock); + status = eIO_Success; + } else + status = lk ? eIO_Success : eIO_NotSupported; +# elif !defined(NCBI_NO_THREADS) && defined(_MT) + CORE_LOG(eLOG_Critical, + "MBEDTLS locking uninited: Unknown threading model"); + status = eIO_NotSupported; +# else + status = eIO_Success; +# endif + + return status; +} + + +static void x_FreeLocking(void) +{ +# if defined(MBEDTLS_THREADING_ALT) && defined(NCBI_THREADS) + mbedtls_threading_free_alt(); +# endif /*MBEDTLS_THREADING_ALT && NCBI_THREADS*/ +} + + +static EIO_Status s_MbedTlsRead(void* session, void* buf, size_t n_todo, + size_t* n_done, int* error) +{ + EIO_Status status; + int x_read; + + assert(session); + + x_read = mbedtls_ssl_read((mbedtls_ssl_context*) session, buf, n_todo); + assert(x_read < 0 || x_read <= n_todo); + + if (x_read <= 0) { + status = x_ErrorToStatus(x_read, (mbedtls_ssl_context*) session, + eIO_Read); + *error = x_read; + x_read = 0; + } else + status = eIO_Success; + + *n_done = x_read; + return status; +} + + +static EIO_Status x_MbedTlsWrite(void* session, const void* data, + size_t n_todo, size_t* n_done, int* error) +{ + EIO_Status status; + int x_written; + + assert(session); + + x_written = mbedtls_ssl_write((mbedtls_ssl_context*)session, data, n_todo); + assert(x_written < 0 || x_written <= n_todo); + + if (x_written <= 0) { + status = x_ErrorToStatus(x_written, (mbedtls_ssl_context*) session, + eIO_Write); + *error = x_written; + x_written = 0; + } else + status = eIO_Success; + + *n_done = x_written; + return status; +} + + +static EIO_Status s_MbedTlsWrite(void* session, const void* data, + size_t n_todo, size_t* n_done, int* error) +{ + size_t max_size + = mbedtls_ssl_get_max_frag_len((mbedtls_ssl_context*) session); + EIO_Status status; + + *n_done = 0; + + do { + size_t x_todo = n_todo > max_size ? max_size : n_todo; + size_t x_done; + status = x_MbedTlsWrite(session, data, x_todo, &x_done, error); + assert((status == eIO_Success) == (x_done > 0)); + assert(status == eIO_Success || *error); + assert(x_done <= x_todo); + if (status != eIO_Success) + break; + *n_done += x_done; + if (x_todo != x_done) + break; + n_todo -= x_done; + data = (const char*) data + x_done; + } while (n_todo); + + return *n_done ? eIO_Success : status; +} + + +static EIO_Status s_MbedTlsClose(void* session, int how/*unused*/, int* error) +{ + assert(session); + + return (*error = mbedtls_ssl_close_notify((mbedtls_ssl_context*) session)) + == 0 ? eIO_Success : eIO_Unknown; +} + + +static void s_MbedTlsDelete(void* session) +{ + assert(session); + + mbedtls_ssl_free((mbedtls_ssl_context*) session); + free(session); +} + + +/* NB: Called under a lock */ +static EIO_Status s_MbedTlsInit(FSSLPull pull, FSSLPush push) +{ + static const char kMbedTls[] = +# ifdef HAVE_LIBMBEDTLS + "External " +# else + "Embedded " +# endif /*HAVE_LIBMBEDTLS*/ + "MBEDTLS"; + EIO_Status status; + char version[80]; + const char* val; + char buf[32]; + + mbedtls_version_get_string(version); + if (strcasecmp(MBEDTLS_VERSION_STRING, version) != 0) { + CORE_LOGF(eLOG_Critical, + ("%s version mismatch: %s headers vs. %s runtime", + kMbedTls, MBEDTLS_VERSION_STRING, version)); + assert(0); + } + + if (!pull || !push) + return eIO_InvalidArg; + + mbedtls_ssl_config_init(&s_MbedTlsConf); + mbedtls_ssl_config_defaults(&s_MbedTlsConf, + MBEDTLS_SSL_IS_CLIENT, + MBEDTLS_SSL_TRANSPORT_STREAM, + MBEDTLS_SSL_PRESET_DEFAULT); + mbedtls_ssl_conf_authmode(&s_MbedTlsConf, MBEDTLS_SSL_VERIFY_NONE); + + val = ConnNetInfo_GetValue(0, "TLS_LOGLEVEL", buf, sizeof(buf), 0); + CORE_LOCK_READ; + if (val && *val) { + ELOG_Level level; + s_MbedTlsLogLevel = atoi(val); + CORE_UNLOCK; + if (s_MbedTlsLogLevel) { + mbedtls_debug_set_threshold(s_MbedTlsLogLevel); + mbedtls_ssl_conf_dbg(&s_MbedTlsConf, x_MbedTlsLogger, 0); + level = eLOG_Note; + } else + level = eLOG_Trace; + CORE_LOGF(level, ("%s V%s (LogLevel=%d)", + kMbedTls, version, s_MbedTlsLogLevel)); + } + else + CORE_UNLOCK; + + if ((status = x_InitLocking()) != eIO_Success) { + mbedtls_ssl_config_free(&s_MbedTlsConf); + mbedtls_debug_set_threshold(s_MbedTlsLogLevel = 0); + memset(&s_MbedTlsConf, 0, sizeof(s_MbedTlsConf)); + return status; + } + + mbedtls_entropy_init(&s_MbedTlsEntropy); + mbedtls_ctr_drbg_init(&s_MbedTlsCtrDrbg); + + if (mbedtls_ctr_drbg_seed(&s_MbedTlsCtrDrbg, mbedtls_entropy_func, + &s_MbedTlsEntropy, 0, 0) != 0) { + s_MbedTlsExit(); + return eIO_Unknown; + } + mbedtls_ssl_conf_rng(&s_MbedTlsConf, + mbedtls_ctr_drbg_random, &s_MbedTlsCtrDrbg); + + s_Pull = pull; + s_Push = push; + return eIO_Success; +} + + +/* NB: Called under a lock */ +static void s_MbedTlsExit(void) +{ + s_Push = 0; + s_Pull = 0; + + mbedtls_ctr_drbg_free(&s_MbedTlsCtrDrbg); + mbedtls_entropy_free(&s_MbedTlsEntropy); + mbedtls_ssl_config_free(&s_MbedTlsConf); + mbedtls_debug_set_threshold(s_MbedTlsLogLevel = 0); + memset(&s_MbedTlsCtrDrbg, 0, sizeof(s_MbedTlsCtrDrbg)); + memset(&s_MbedTlsEntropy, 0, sizeof(s_MbedTlsEntropy)); + memset(&s_MbedTlsConf, 0, sizeof(s_MbedTlsConf)); + x_FreeLocking(); +} + + +static const char* s_MbedTlsError(void* session/*unused*/, int error, + char* buf, size_t size) +{ + mbedtls_strerror(error, buf, size); + return buf; +} + + +#else + + +/*ARGSUSED*/ +static EIO_Status s_MbedTlsInit(FSSLPull unused_pull, FSSLPush unused_push) +{ + CORE_LOG(eLOG_Critical, "Unavailable feature MBEDTLS"); + return eIO_NotSupported; +} + + +#endif /*HAVE_LIBMBEDTLS || NCBI_CXX_TOOLKIT*/ + + +extern SOCKSSL NcbiSetupMbedTls(void) +{ + static const struct SOCKSSL_struct kMbedTlsOps = { + "MBEDTLS" + , s_MbedTlsInit +#if defined(HAVE_LIBMBEDTLS) || defined(NCBI_CXX_TOOLKIT) + , s_MbedTlsCreate + , s_MbedTlsOpen + , s_MbedTlsRead + , s_MbedTlsWrite + , s_MbedTlsClose + , s_MbedTlsDelete + , s_MbedTlsExit + , s_MbedTlsError +#endif /*HAVE_LIBMBEDTLS || NCBI_CXX_TOOLKIT*/ + }; +#if !defined(HAVE_LIBMBEDTLS) && !defined(NCBI_CXX_TOOLKIT) + CORE_LOG(eLOG_Warning, "Unavailable feature MBEDTLS"); +#endif /*!HAVE_LIBMBEDTLS && !NCBI_CXX_TOOLKIT*/ + return &kMbedTlsOps; +} + + +extern NCBI_CRED NcbiCredMbedTls(void* xcred) +{ + struct SNcbiCred* cred = (NCBI_CRED) calloc(xcred ? 2 : 1, sizeof(*cred)); + if (cred && xcred) { + cred->type = eNcbiCred_MbedTls; + cred->data = xcred; + } + return cred; +} diff --git a/c++/src/connect/ncbi_monkey.cpp b/c++/src/connect/ncbi_monkey.cpp index 683015e0..0693e0aa 100644 --- a/c++/src/connect/ncbi_monkey.cpp +++ b/c++/src/connect/ncbi_monkey.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_monkey.cpp 505633 2016-06-27 19:28:13Z elisovdn $ +/* $Id: ncbi_monkey.cpp 519826 2016-11-18 16:17:44Z elisovdn $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -46,6 +46,7 @@ # include # include "ncbi_monkeyp.hpp" # include +#include /* OS-dependent way to set socket errors */ # ifdef NCBI_OS_MSWIN @@ -70,6 +71,7 @@ BEGIN_NCBI_SCOPE DEFINE_STATIC_FAST_MUTEX(s_ConfigMutex); +DEFINE_STATIC_FAST_MUTEX(s_NetworkDataCacheMutex); DEFINE_STATIC_FAST_MUTEX(s_SeedLogConfigMutex); DEFINE_STATIC_FAST_MUTEX(s_SingletonMutex); DEFINE_STATIC_FAST_MUTEX(s_KnownConnMutex); @@ -79,7 +81,15 @@ const int kRandCount = 100; /* Registry names */ const string kMonkeyMainSect = "CHAOS_MONKEY"; const string kEnablField = "enabled"; -const string kSeedField = "seed"; +const string kSeedField = "seed"; + +#define PARAM_TWICE_EXCEPTION(param) \ + throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), \ + NULL, CMonkeyException::e_MonkeyInvalidArgs, \ + string("Parameter \"" param "\" is set " \ + "twice in [") + GetSection() + "]" + \ + s_RuleTypeString(GetActionType())); + /*///////////////////////////////////////////////////////////////////////////// // MOCK DEFINITIONS // @@ -101,6 +111,34 @@ const string kSeedField = "seed"; */ MONKEY_MOCK_MACRO() +string CMonkeyMocks::MainMonkeySection = "CHAOS_MONKEY"; + + +void CMonkeyMocks::Reset() +{ + MainMonkeySection = "CHAOS_MONKEY"; +} + +string CMonkeyMocks::GetMainMonkeySection() +{ + return MainMonkeySection; +} +void CMonkeyMocks::SetMainMonkeySection(string section) +{ + MainMonkeySection = section; +} + + +/*////////////////////////////////////////////////////////////////////////////// +// CMonkeyException // +//////////////////////////////////////////////////////////////////////////////*/ +const char* CMonkeyException::what() const throw() +{ + + return CException::GetMsg().c_str(); +} + + # endif /* NCBI_MONKEY_TESTS */ /*///////////////////////////////////////////////////////////////////////////// // STATIC CONVENIENCE FUNCTIONS // @@ -109,7 +147,6 @@ static vector& s_Monkey_Split(const string &s, char delim, vector &elems) { - g_MonkeyMock_SetInterceptedPoll(false); stringstream ss(s); string item; while (getline(ss, item, delim)) { @@ -199,7 +236,7 @@ static void s_TimeoutingSocketDestroy(void) static string s_GetMonkeySection() { CNcbiRegistry& config = CNcbiApplication::Instance()->GetConfig(); - return config.Get(kMonkeyMainSect, "config"); + return config.Get(CMonkeyMocks::GetMainMonkeySection(), "config"); } @@ -226,11 +263,11 @@ static void s_MONKEY_GenRandomString(char *s, const size_t len) { } -static void s_GetSocketDestinations(MONKEY_SOCKTYPE sock, - string* fqdn, - string* IP, - unsigned short* my_port, - unsigned short* peer_port) +void CMonkey::x_GetSocketDestinations(MONKEY_SOCKTYPE sock, + string* fqdn, + string* IP, + unsigned short* my_port, + unsigned short* peer_port) { struct sockaddr_in sock_addr; #ifdef NCBI_OS_MSWIN @@ -252,10 +289,11 @@ static void s_GetSocketDestinations(MONKEY_SOCKTYPE sock, #else u_long addr = sock_addr.sin_addr.S_un.S_addr; #endif + SFqdnIp&& net_data = x_GetFqdnIp(addr); if (fqdn != NULL) - *fqdn = CSocketAPI::gethostbyaddr (addr); + *fqdn = net_data.fqdn; if (IP != NULL) - *IP = CSocketAPI::HostPortToString(addr, 0); + *IP = net_data.ip; } @@ -319,21 +357,68 @@ const CMonkeySeedKey& CMonkeySeedAccessor::Key() /*////////////////////////////////////////////////////////////////////////////// -// CMonkeyException // +// CMonkeyRuleBase // //////////////////////////////////////////////////////////////////////////////*/ -const char* CMonkeyException::what() const throw() +static string s_RuleTypeString(EMonkeyActionType type) { - return m_Message.c_str(); + switch (type) { + case eMonkey_Connect: + return "connect"; + case eMonkey_Poll: + return "poll"; + case eMonkey_Recv: + return "read"; + case eMonkey_Send: + return "write"; + default: + throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), + NULL, CMonkeyException::e_MonkeyInvalidArgs, + string("Unknown EMonkeyActionType value")); + } +} + + +static string s_SocketCallString(EMonkeyActionType action) +{ + switch (action) { + case eMonkey_Recv: + return "recv()"; + case eMonkey_Send: + return "send()"; + case eMonkey_Poll: + return "poll()"; + case eMonkey_Connect: + return "connect()"; + default: + throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), + NULL, CMonkeyException::e_MonkeyInvalidArgs, + string("Unknown EMonkeyActionType value")); + } +} + + +static string s_EIOStatusString(EIO_Status status) +{ + switch (status) { + case eIO_Timeout: + return "eIO_Timeout"; + case eIO_Closed: + return "eIO_Closed"; + case eIO_Unknown: + return "eIO_Unknown"; + case eIO_Interrupt: + return "eIO_Interrupt"; + default: + break; + } } -/*////////////////////////////////////////////////////////////////////////////// -// CMonkeyRuleBase // -//////////////////////////////////////////////////////////////////////////////*/ CMonkeyRuleBase::CMonkeyRuleBase(EMonkeyActionType action_type, + string section, const vector& params) : m_ReturnStatus(-1), m_RepeatType(eMonkey_RepeatNone), m_Delay (0), - m_RunsSize(0), m_ActionType(action_type) + m_RunsSize(0), m_ActionType(action_type), m_Section(section) { /** If there are no-interception runs before repeating the cycle, * we know that from m_RunsSize */ @@ -352,26 +437,6 @@ CMonkeyRuleBase::CMonkeyRuleBase(EMonkeyActionType action_type, } -static string s_PrintActionType(EMonkeyActionType action) { - switch (action) - { - case eMonkey_Recv: - return "recv()"; - case eMonkey_Send: - return "send()"; - case eMonkey_Poll: - return "poll()"; - case eMonkey_Connect: - return "connect()"; - default: - throw CMonkeyException( - CDiagCompileInfo(__FILE__, __LINE__), - NULL, CMonkeyException::e_MonkeyInvalidArgs, - string("Unknown EMonkeyActionType value")); - } -} - - void CMonkeyRuleBase::AddSocket(MONKEY_SOCKTYPE sock) { /* Element has to exist */ @@ -379,18 +444,19 @@ void CMonkeyRuleBase::AddSocket(MONKEY_SOCKTYPE sock) } /** Check that the rule should trigger on this run */ -bool CMonkeyRuleBase::CheckRun(MONKEY_SOCKTYPE sock, - unsigned short probability_left) const +bool CMonkeyRuleBase::CheckRun(MONKEY_SOCKTYPE sock, + unsigned short rule_probability, + unsigned short probability_left) const { bool isRun = false; - int rand_val = CMonkey::Instance()->GetRand(Key()); - isRun = (rand_val % 100) < GetProbability(sock) * 100 / probability_left; + int rand_val = CMonkey::Instance()->GetRand(Key()) % 100; + isRun = (rand_val) < rule_probability * 100 / probability_left; LOG_POST(Note << "[CMonkeyRuleBase::CheckRun] Checking if the rule " - << "for " << s_PrintActionType(m_ActionType) + << "for " << s_SocketCallString(m_ActionType) << " will be run this time. Random value is " - << rand_val << ", probability threshold is " - << m_Runs.at(m_RunPos.at(sock)) * 100); + << rand_val << ", probability threshold is " + << rule_probability * 100 / probability_left); LOG_POST(Note << "[CMonkeyRuleBase::CheckRun] The rule will be " << (isRun ? "" : "NOT ") << "run"); return isRun; @@ -405,10 +471,16 @@ unsigned short CMonkeyRuleBase::GetProbability(MONKEY_SOCKTYPE sock) const NULL, CMonkeyException::e_MonkeyInvalidArgs, "The socket provided has not been registered with current rule"); } + /* If 'runs' not set, the rule always engages */ + if (m_RunsSize == 0) { + return 100; + } if (m_RunMode == eMonkey_RunProbability) { return static_cast(m_Runs.at(m_RunPos.at(sock)) * 100); } else { - if ((m_RunPos.at(sock) + 1) > *m_Runs.rbegin()) { + /* If current run is more than the maximum run in the rule, we have to + * start over, or stop*/ + if ((double)(m_RunPos.at(sock) + 1) > m_Runs.back()) { switch (m_RepeatType) { case eMonkey_RepeatNone: return 0; @@ -426,14 +498,22 @@ unsigned short CMonkeyRuleBase::GetProbability(MONKEY_SOCKTYPE sock) const } + void CMonkeyRuleBase::x_ReadEIOStatus(const string& eIOStatus_in) { + /* Check that 'runs' has not been set before */ + if (m_ReturnStatus != -1) { + PARAM_TWICE_EXCEPTION("return_status"); + } string eIOStatus = eIOStatus_in; NStr::ToLower(eIOStatus); if (eIOStatus == "eio_closed") { m_ReturnStatus = eIO_Closed; } else if (eIOStatus == "eio_invalidarg") { - m_ReturnStatus = eIO_InvalidArg; + throw CMonkeyException( + CDiagCompileInfo(__FILE__, __LINE__), + NULL, CMonkeyException::e_MonkeyInvalidArgs, + string("Unsupported 'return_status': ") + eIOStatus_in); } else if (eIOStatus == "eio_interrupt") { m_ReturnStatus = eIO_Interrupt; } else if (eIOStatus == "eio_success") { @@ -455,19 +535,24 @@ void CMonkeyRuleBase::x_ReadEIOStatus(const string& eIOStatus_in) void CMonkeyRuleBase::x_ReadRuns(const string& runs) { + /* Check that 'runs' has not been set before */ + if (m_RunsSize != 0) { + PARAM_TWICE_EXCEPTION("runs"); + } /* We get the string already without whitespaces and only have to split it on commas*/ vector runs_list = s_Monkey_Split(runs, ','); if (runs_list.size() == 0) - throw CMonkeyException( - CDiagCompileInfo(__FILE__, __LINE__), - NULL, CMonkeyException::e_MonkeyInvalidArgs, - string("\"Runs\" parameter is empty")); - if (runs_list.size() == 1) - runs_list.push_back("..."); + throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), + NULL, CMonkeyException::e_MonkeyInvalidArgs, + string("Parameter \"runs\" is empty in [") + + m_Section + "]" + + s_RuleTypeString(m_ActionType)); m_RunMode = runs_list[0][runs_list[0].length() - 1] == '%' ? eMonkey_RunProbability : eMonkey_RunNumber; + if (runs_list.size() == 1 && m_RunMode == eMonkey_RunProbability) + runs_list.push_back("..."); m_RepeatType = eMonkey_RepeatNone; if ( *runs_list.rbegin() == "repeat" ) { m_RepeatType = eMonkey_RepeatAgain; @@ -477,10 +562,10 @@ void CMonkeyRuleBase::x_ReadRuns(const string& runs) ERunFormat run_format = runs_list[0].find_first_of(':') != string::npos ? eMonkey_RunRanges : - eMonkey_RunSequence; + eMonkey_RunSequence; unsigned int end_pos = (m_RepeatType == eMonkey_RepeatNone) - ? runs_list.size() : runs_list.size() - 1; + ? runs_list.size() : runs_list.size() - 1; for ( unsigned int i = 0; i < end_pos; i++ ) { string& run = runs_list[i]; @@ -513,7 +598,8 @@ void CMonkeyRuleBase::x_ReadRuns(const string& runs) "In the string of runs: " + runs + " the first " "element MUST set value for the first run"); } - prob = NStr::StringToDouble(run.substr(prob_start+1, run.length() - prob_start - 2)); + prob = NStr::StringToDouble(run.substr(prob_start + 1, + run.length() - prob_start - 2)); for (size_t j = last_step+1; j > 0 && j < step; j++) { m_Runs.push_back(*m_Runs.rbegin()); } @@ -541,6 +627,7 @@ void CMonkeyRuleBase::x_ReadRuns(const string& runs) m_Runs.push_back(val); } } + m_RunsSize = m_Runs.size(); } @@ -556,6 +643,18 @@ unsigned long CMonkeyRuleBase::GetDelay() const } +std::string CMonkeyRuleBase::GetSection(void) const +{ + return m_Section; +} + + +EMonkeyActionType CMonkeyRuleBase::GetActionType(void) const +{ + return m_ActionType; +} + + void CMonkeyRuleBase::IterateRun(MONKEY_SOCKTYPE sock) { if (m_Runs.empty()) @@ -591,109 +690,19 @@ void CMonkeyRuleBase::IterateRun(MONKEY_SOCKTYPE sock) /*////////////////////////////////////////////////////////////////////////////// // CMonkeyRWRuleBase // //////////////////////////////////////////////////////////////////////////////*/ -CMonkeyRWRuleBase::CMonkeyRWRuleBase(EMonkeyActionType action_type, - const vector& params) - : CMonkeyRuleBase(action_type, params), m_Text(""), m_TextLength(0), - m_Garbage(false), m_FillType(eMonkey_FillRepeat) -{ - for ( unsigned int i = 0; i < params.size(); i++ ) { - vector name_value = s_Monkey_Split(params[i], '='); - string name = name_value[0]; - string value = name_value[1]; - if (name == "text") { - if (GetReturnStatus() != eIO_Success && GetReturnStatus() != -1) { - throw CMonkeyException( - CDiagCompileInfo(__FILE__, __LINE__), - NULL, CMonkeyException::e_MonkeyInvalidArgs, - string("Return error status is set in Rule, cannot " - "set 'text' parameter")); - } - if (value == "garbage") { - m_Garbage = true; - } - /* The text should start and finish with ' or " */ - else if ( value[0] == value[value.length() - 1] - && (value[0] == '\'' || value[0] == '\"') ) - { - m_Garbage = false; - m_Text = value.substr(1, value.length() - 2); - } else { - throw CMonkeyException( - CDiagCompileInfo(__FILE__, __LINE__), - NULL, CMonkeyException::e_MonkeyInvalidArgs, - string("Could not parse 'text' for Rule: ") + value); - } - } else if (name == "text_length") { - m_TextLength = NStr::StringToInt(value); - } else if (name == "fill") { - if (value == "last_letter") { - m_FillType = eMonkey_FillLastLetter; - } else if (name == "repeat") { - m_FillType = eMonkey_FillRepeat; - } - } - } - /* Checking that everything was set */ - if (GetReturnStatus() == eIO_Success && m_Text == "") { - throw CMonkeyException( - CDiagCompileInfo(__FILE__, __LINE__), - NULL, CMonkeyException::e_MonkeyInvalidArgs, - string("Parameter 'text' not set to a non-empty value for rule, " - "but 'return_status' set to eIO_Success requires 'text' to " - "be set")); - } - if (GetReturnStatus() == -1 && m_Text == "") { - throw CMonkeyException( - CDiagCompileInfo(__FILE__, __LINE__), - NULL, CMonkeyException::e_MonkeyInvalidArgs, - string("Parameter 'text' not set to a non-empty value for rule, " - "but 'return_status' not set requires 'text' to " - "be set")); - } -} - - -void CMonkeyRWRuleBase::x_ReadFill(const string& fill_str) +CMonkeyRWRuleBase::CMonkeyRWRuleBase(EMonkeyActionType action_type, + string section, + const vector& params) + : CMonkeyRuleBase(action_type, section, params) { - string fill = fill_str; - if (NStr::ToLower(fill) == "repeat") { - m_FillType = eMonkey_FillRepeat; - } - if (NStr::ToLower(fill) == "last_letter") { - m_FillType = eMonkey_FillLastLetter; - } -} - - -string CMonkeyRWRuleBase::GetText() const -{ - return m_Text; -} - - -size_t CMonkeyRWRuleBase::GetTextLength() const -{ - return m_TextLength; -} - - -bool CMonkeyRWRuleBase::GetGarbage() const -{ - return m_Garbage; -} - - -CMonkeyRWRuleBase::EFillType CMonkeyRWRuleBase::GetFillType() const -{ - return m_FillType; } ////////////////////////////////////////////////////////////////////////// // CMonkeyWriteRule ////////////////////////////////////////////////////////////////////////// -CMonkeyWriteRule::CMonkeyWriteRule(const vector& params) - : CMonkeyRWRuleBase(eMonkey_Send, params) +CMonkeyWriteRule::CMonkeyWriteRule(string section, const vector& params) + : CMonkeyRWRuleBase(eMonkey_Send, section, params) { } @@ -707,9 +716,12 @@ MONKEY_RETTYPE CMonkeyWriteRule::Run(MONKEY_SOCKTYPE sock, #ifdef NCBI_MONKEY_TESTS g_MonkeyMock_SetInterceptedSend(true); #endif /* NCBI_MONKEY_TESTS */ - LOG_POST(Error << "[CMonkeyWriteRule::Run] CHAOS MONKEY ENGAGE!!! " - "INTERCEPTED send()"); int return_status = GetReturnStatus(); + LOG_POST(Error << "[CMonkeyReadRule::Run] CHAOS MONKEY ENGAGE!!! " + "INTERCEPTED send(). " << + (return_status != -1 + ? s_EIOStatusString((EIO_Status)return_status) + : string())); if (return_status != eIO_Success && return_status != -1) { switch (return_status) { case eIO_Timeout: @@ -721,44 +733,24 @@ MONKEY_RETTYPE CMonkeyWriteRule::Run(MONKEY_SOCKTYPE sock, return -1; case eIO_Unknown: MONKEY_SET_SOCKET_ERROR(MONKEY_ENOPROTOOPT); - return -1; + return -1; + case eIO_Interrupt: + MONKEY_SET_SOCKET_ERROR(SOCK_EINTR); + return -1; default: break; } } - /* We cannot write more than the user asked */ - size_t max_size; - if (GetTextLength() == 0) { - max_size = min(GetTextLength(), (size_t)size); - } - else { - max_size = size; - } - /* Fill data */ - void* new_data = (char*)malloc(max_size * sizeof(char)); - if (GetGarbage()) { - s_MONKEY_GenRandomString((char*)new_data, max_size); - } else { - string text = GetText(); - if (GetFillType() == CMonkeyRWRuleBase::eMonkey_FillRepeat) { - text += text; - text = text.substr(0, max_size); - } - if (GetFillType() == CMonkeyRWRuleBase::eMonkey_FillLastLetter) - text.insert(text.length() - 1, max_size - text.length(), - text[text.length()-1]); - memcpy(new_data, text.c_str(), max_size); - } - return send(sock, (const char*)new_data, size, flags); + return send(sock, (const char*)data, size, flags); } ////////////////////////////////////////////////////////////////////////// // CMonkeyReadRule ////////////////////////////////////////////////////////////////////////// -CMonkeyReadRule::CMonkeyReadRule(const vector& params) - : CMonkeyRWRuleBase(eMonkey_Recv, params) +CMonkeyReadRule::CMonkeyReadRule(string section, const vector& params) + : CMonkeyRWRuleBase(eMonkey_Recv, section, params) { STimeout r_timeout = { 1, 0 }; } @@ -773,9 +765,12 @@ MONKEY_RETTYPE CMonkeyReadRule::Run(MONKEY_SOCKTYPE sock, #ifdef NCBI_MONKEY_TESTS g_MonkeyMock_SetInterceptedRecv(true); #endif /* NCBI_MONKEY_TESTS */ - LOG_POST(Error << "[CMonkeyReadRule::Run] CHAOS MONKEY ENGAGE!!! " - "INTERCEPTED recv()"); int return_status = GetReturnStatus(); + LOG_POST(Error << "[CMonkeyReadRule::Run] CHAOS MONKEY ENGAGE!!! " + "INTERCEPTED recv(). " << + (return_status != -1 + ? s_EIOStatusString((EIO_Status)return_status) + : string())); if (return_status != eIO_Success && return_status != -1) { switch (return_status) { case eIO_Timeout: @@ -788,6 +783,8 @@ MONKEY_RETTYPE CMonkeyReadRule::Run(MONKEY_SOCKTYPE sock, case eIO_Unknown: MONKEY_SET_SOCKET_ERROR(MONKEY_ENOPROTOOPT); return -1; + case eIO_Interrupt: + MONKEY_SET_SOCKET_ERROR(SOCK_EINTR); default: break; } @@ -798,25 +795,7 @@ MONKEY_RETTYPE CMonkeyReadRule::Run(MONKEY_SOCKTYPE sock, /* So we decided to override */ MONKEY_RETTYPE bytes_read = recv(sock, buf, size, flags); - - /* We cannot resize the buffer since it can be a local array, so we have to - * decrease monkey text length instead */ - size_t max_size = min(GetTextLength() - 1, static_cast(size) - 1); - /* Replace data */ - if (GetGarbage()) { - s_MONKEY_GenRandomString((char*)buf, max_size); - } else { - string text = GetText(); - if (GetFillType() == CMonkeyRWRuleBase::eMonkey_FillRepeat) { - text += text; - text = text.substr(0, GetTextLength()); - } - if (GetFillType() == CMonkeyRWRuleBase::eMonkey_FillLastLetter) - text.insert(text.length()-1, GetTextLength() - text.length(), - text[text.length()-1]); - memcpy(buf, text.c_str(), GetTextLength()); - } - + return bytes_read; } @@ -825,17 +804,34 @@ MONKEY_RETTYPE CMonkeyReadRule::Run(MONKEY_SOCKTYPE sock, // CMonkeyConnectRule ////////////////////////////////////////////////////////////////////////// -CMonkeyConnectRule::CMonkeyConnectRule(const vector& params) - : CMonkeyRuleBase(eMonkey_Connect, params) +CMonkeyConnectRule::CMonkeyConnectRule(string section, + const vector& params) + : CMonkeyRuleBase(eMonkey_Connect, section, params) { + bool allow_set = false; for (unsigned int i = 0; i < params.size(); i++) { vector name_value = s_Monkey_Split(params[i], '='); string name = name_value[0]; string value = name_value[1]; if (name == "allow") { + if (allow_set) { + throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), + NULL, + CMonkeyException::e_MonkeyInvalidArgs, + string("Parameter \"allow\" is set " + "twice in [") + GetSection() + "]" + + s_RuleTypeString(GetActionType())); + } m_Allow = ConnNetInfo_Boolean(value.c_str()) == 1; + allow_set = true; } } + if (!allow_set) + throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), + NULL, CMonkeyException::e_MonkeyInvalidArgs, + string("Parameter \"allow\" not set in [") + + GetSection() + "]" + + s_RuleTypeString(GetActionType())); } @@ -846,9 +842,12 @@ int CMonkeyConnectRule::Run(MONKEY_SOCKTYPE sock, #ifdef NCBI_MONKEY_TESTS g_MonkeyMock_SetInterceptedConnect(true); #endif /* NCBI_MONKEY_TESTS */ - LOG_POST(Error << "[CMonkeyConnectRule::Run] CHAOS MONKEY ENGAGE!!! " - "INTERCEPTED connect()"); int return_status = GetReturnStatus(); + LOG_POST(Error << "[CMonkeyReadRule::Run] CHAOS MONKEY ENGAGE!!! " + "INTERCEPTED connect(). " << + (return_status != -1 + ? s_EIOStatusString((EIO_Status)return_status) + : string())); if (return_status != eIO_Success && return_status != -1) { switch (return_status) { case eIO_Timeout: @@ -893,20 +892,34 @@ int CMonkeyConnectRule::Run(MONKEY_SOCKTYPE sock, ////////////////////////////////////////////////////////////////////////// // CMonkeyPollRule ////////////////////////////////////////////////////////////////////////// -CMonkeyPollRule::CMonkeyPollRule(const vector& params) - : CMonkeyRuleBase(eMonkey_Poll, params) +CMonkeyPollRule::CMonkeyPollRule(string section, const vector& params) + : CMonkeyRuleBase(eMonkey_Poll, section, params) { -#ifdef NCBI_MONKEY_TESTS - g_MonkeyMock_SetInterceptedPoll(true); -#endif /* NCBI_MONKEY_TESTS */ + bool ignore_set = false; for ( unsigned int i = 0; i < params.size(); i++ ) { vector name_value = s_Monkey_Split(params[i], '='); string name = name_value[0]; string value = name_value[1]; if (name == "ignore") { + if (ignore_set) { + throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), + NULL, + CMonkeyException::e_MonkeyInvalidArgs, + string("Parameter \"ignore\" is set " + "twice in [") + GetSection() + "]" + + s_RuleTypeString(GetActionType())); + } m_Ignore = ConnNetInfo_Boolean(value.c_str()) == 1; + ignore_set = true; } } + if (!ignore_set) { + throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), + NULL, CMonkeyException::e_MonkeyInvalidArgs, + string("Parameter \"ignore\" not set in [") + + GetSection() + "]" + + s_RuleTypeString(GetActionType())); + } } @@ -914,8 +927,12 @@ bool CMonkeyPollRule::Run(size_t* n, SOCK* sock, EIO_Status* return_status) { - LOG_POST(Error << "[CMonkeyPollRule::Run] CHAOS MONKEY ENGAGE!!! " - "INTERCEPTED poll()"); +#ifdef NCBI_MONKEY_TESTS + g_MonkeyMock_SetInterceptedPoll(true); +#endif /* NCBI_MONKEY_TESTS */ + LOG_POST(Error << "[CMonkeyReadRule::Run] CHAOS MONKEY ENGAGE!!! " + "INTERCEPTED poll(). " << + (m_Ignore ? "Ignoring poll" : "NOT ignoring poll")); if (m_Ignore) { return true; } @@ -977,19 +994,20 @@ void CMonkeyPlan::x_LoadRules(const string& section, /* If a rule was read - parse it */ string temp_conf = NStr::Replace(rule_str, string(" "), string("")); vector params = s_Monkey_Split(temp_conf, ';'); - container.push_back(Rule_Ty(params)); + container.push_back(Rule_Ty(section, params)); if ( multi_rule ) { int rule_num = 2; string val_name = rule_type_str + NStr::IntToString(rule_num++); while ( (rule_str = config.Get(section, val_name)) != "" ) { temp_conf = NStr::Replace(rule_str, string(" "), string("")); params = s_Monkey_Split(temp_conf, ';'); - container.push_back(Rule_Ty(params)); + container.push_back(Rule_Ty(section, params)); val_name = rule_type_str+ NStr::IntToString(rule_num++); } } } + #ifndef NCBI_OS_MSWIN /** Regex-like check (might use some refactoring) */ static bool s_MatchRegex(const string& to_match, const string& regex) @@ -1069,29 +1087,19 @@ bool CMonkeyPlan::Match(const string& sock_host, const string& sock_url, unsigned short probability_left) { - /* Regex test just in case */ - static int regex_works = 1; /* 0 for not working, 1 for working */ -#if 0 - if (regex_works == -1) { - regex test_regexp("test_regex"); /* should not match "test" */ - string test_string = "test.*"; - smatch test_find; - if (!regex_match(test_string, test_find, test_regexp)) { - regex_works = 0; /* we learn that regex implementation is fake */ - } - regex_works = 1; - } -#endif /* 0 */ - /* Check that regex works and that at least one of hostname and IP * is not empty*/ - if ( regex_works && !m_HostRegex.empty() && - (sock_host.length() + sock_url.length() > 0) ) { + if ( !m_HostRegex.empty() && + (sock_host.length() + sock_url.length() > 0) ) { #ifdef NCBI_OS_MSWIN regex reg(m_HostRegex); smatch find; if (!regex_match(sock_host, find, reg) && !regex_match(sock_url, find, reg)) { + LOG_POST(Note << "[CMonkeyPlan::Match] Plan " << m_Name << " was " + << "NOT matched. Reason: " + << "[host regex mismatch, host=" << sock_host + << ", regex = \"" << m_HostRegex << "\"]"); return false; } #else @@ -1109,6 +1117,10 @@ bool CMonkeyPlan::Match(const string& sock_host, } } if (!match_found) { + LOG_POST(Note << "[CMonkeyPlan::Match] Plan " << m_Name << " was " + << "NOT matched. Reason: " + << "[host regex mismatch, host=" << sock_host + << ", regex = \"" << m_HostRegex << "\"]"); return false; } #endif /* NCBI_OS_MSWIN */ @@ -1122,18 +1134,22 @@ bool CMonkeyPlan::Match(const string& sock_host, break; } } - int rand_val = CMonkey::Instance()->GetRand(Key()); - LOG_POST(Note << "[CMonkeyPlan::Match] Checking if plan " << m_Name - << " will be matched. Random value is " - << rand_val << ", plan probability is " - << m_Probability << "%, probability left is " - << probability_left << "%, so probability threshold is" + int rand_val = CMonkey::Instance()->GetRand(Key()) % 100; + bool prob_match = rand_val < m_Probability * 100 / probability_left; + LOG_POST(Note << "[CMonkeyPlan::Match] Checking if plan " << m_Name + << " will be matched. Random value is " + << rand_val << ", plan probability is " + << m_Probability << "%, probability left is " + << probability_left << "%, so probability threshold is " << m_Probability * 100 / probability_left << "%"); - LOG_POST(Note << "[CMonkeyPlan::Match] Plan " << m_Name << " was " - << ((port_match && ((rand_val % 100) < m_Probability)) ? - "" : "NOT ") << "matched"); - return port_match ? ((rand_val % 100) < m_Probability*100/probability_left) - : false; + bool match = port_match && prob_match; + LOG_POST(Note << "[CMonkeyPlan::Match] Plan " << m_Name << " was " + << (match ? "" : "NOT ") << "matched" + << (!match ? ". Reason: " : "") + << (port_match ? "" : "[invalid port range] ") + << (prob_match ? "" : "[probability threshold]")); + return port_match ? (rand_val < m_Probability * 100 / probability_left) + : false; } @@ -1145,13 +1161,15 @@ bool CMonkeyPlan::WriteRule(MONKEY_SOCKTYPE sock, SOCK* sock_ptr) { short probability_left = 100; + int res = -1; for (unsigned int i = 0; i < m_WriteRules.size(); i++) { m_WriteRules[i].AddSocket(sock); unsigned short rule_prob = m_WriteRules[i].GetProbability(sock); - if (m_WriteRules[i].CheckRun(sock)) { + if (m_WriteRules[i].CheckRun(sock, rule_prob, probability_left)) { *bytes_written = m_WriteRules[i].Run(sock, data, size, flags, sock_ptr); - return true; + res = 1; + break; } /* If this rule did not engage, we go to the next rule, and remember to normalize probability of next rule */ @@ -1167,7 +1185,15 @@ bool CMonkeyPlan::WriteRule(MONKEY_SOCKTYPE sock, } } // If no rules engaged, return 0 - return false; + if (res == -1) + res = 0; + + // Iterate run in all rules + for (unsigned int i = 0; i < m_WriteRules.size(); i++) { + m_WriteRules[i].IterateRun(sock); + } + + return res == 0 ? false : true; } @@ -1179,12 +1205,14 @@ bool CMonkeyPlan::ReadRule(MONKEY_SOCKTYPE sock, SOCK* sock_ptr) { short probability_left = 100; + int res = -1; for (unsigned int i = 0; i < m_ReadRules.size(); i++) { m_ReadRules[i].AddSocket(sock); unsigned short rule_prob = m_ReadRules[i].GetProbability(sock); - if (m_ReadRules[i].CheckRun(sock)) { + if (m_ReadRules[i].CheckRun(sock, rule_prob, probability_left)) { *bytes_read = m_ReadRules[i].Run(sock, buf, size, flags, sock_ptr); - return true; + res = 1; + break; } /* If this rule did not engage, we go to the next rule, and and remember to normalize probability of next rule */ @@ -1192,14 +1220,23 @@ bool CMonkeyPlan::ReadRule(MONKEY_SOCKTYPE sock, if (probability_left <= 0) { stringstream ss; ss << "Probability below zero for write rule in plan " << m_Name - << ". Check config!"; - throw CMonkeyException( - CDiagCompileInfo(__FILE__, __LINE__), - NULL, CMonkeyException::e_MonkeyInvalidArgs, - ss.str()); + << ". Check config!"; + throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), + NULL, CMonkeyException::e_MonkeyInvalidArgs, + ss.str()); } } - return false; + + // If no rules engaged, return 0 + if (res == -1) + res = 0; + + // Iterate run in all rules + for (unsigned int i = 0; i < m_ReadRules.size(); i++) { + m_ReadRules[i].IterateRun(sock); + } + + return res == 0 ? false : true; } @@ -1209,17 +1246,22 @@ bool CMonkeyPlan::ConnectRule(MONKEY_SOCKTYPE sock, int* result) { short probability_left = 100; + /* We are fine with losing precision. Just need a unique ID*/ + MONKEY_SOCKTYPE x_sock = CMonkey::Instance()->GetSockBySocketid(sock); + int res = -1; for (unsigned int i = 0; i < m_ConnectRules.size(); i++) { - m_ConnectRules[i].AddSocket(sock); - unsigned short rule_prob = m_ConnectRules[i].GetProbability(sock); + m_ConnectRules[i].AddSocket(x_sock); + unsigned short rule_prob = + m_ConnectRules[i].GetProbability(x_sock); /* Check if the rule will trigger on this run. If not - we go to the next rule in plan */ - if (m_ConnectRules[i].CheckRun(sock)) { + if (m_ConnectRules[i].CheckRun(x_sock, rule_prob, probability_left)) { /* 'result' is the result of connect() launched in the rule. It can even be result of original connect() with real parameters. Or, it can be an error code of a failed fake connect() */ *result = m_ConnectRules[i].Run(sock, name, namelen); - return true; + res = 1; + break; } /* If this rule did not engage, we go to the next rule, and and remember to normalize probability of next rule */ @@ -1228,14 +1270,22 @@ bool CMonkeyPlan::ConnectRule(MONKEY_SOCKTYPE sock, stringstream ss; ss << "Probability below zero for write rule in plan " << m_Name << ". Check config!"; - throw CMonkeyException( - CDiagCompileInfo(__FILE__, __LINE__), - NULL, CMonkeyException::e_MonkeyInvalidArgs, - ss.str()); + throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), + NULL, CMonkeyException::e_MonkeyInvalidArgs, + ss.str()); } } - // If no rules triggered - return false; + + // If no rules engaged, return 0 + if (res == -1) + res = 0; + + // Iterate run in all rules + for (unsigned int i = 0; i < m_ConnectRules.size(); i++) { + m_ConnectRules[i].IterateRun(x_sock); + } + + return res == 0 ? false : true; } @@ -1244,11 +1294,14 @@ bool CMonkeyPlan::PollRule(size_t* n, EIO_Status* return_status) { short probability_left = 100; + int res = -1; for (unsigned int i = 0; i < m_PollRules.size(); i++) { m_PollRules[i].AddSocket((*sock)->sock); unsigned short rule_prob = m_PollRules[i].GetProbability((*sock)->sock); - if (m_PollRules[i].CheckRun((*sock)->sock)) { - return m_PollRules[i].Run(n, sock, return_status); + if (m_PollRules[i].CheckRun((*sock)->sock, rule_prob, probability_left)) + { + res = m_PollRules[i].Run(n, sock, return_status) ? 1 : 0; + break; } LOG_POST(Error << "[CMonkeyPlan::PollRule] CHAOS MONKEY NOT " "ENGAGED!!! poll() passed"); @@ -1265,9 +1318,19 @@ bool CMonkeyPlan::PollRule(size_t* n, ss.str()); } } + // If no rules triggered, return 0 - *return_status = EIO_Status::eIO_Success; - return false; + if (res == -1) { + res = 0; + *return_status = EIO_Status::eIO_Success; + } + + // Iterate run in all rules + for (unsigned int i = 0; i < m_PollRules.size(); i++) { + m_PollRules[i].IterateRun((*sock)->sock); + } + + return res == 0 ? false : true; } @@ -1305,7 +1368,7 @@ CMonkey* CMonkey::sm_Instance = NULL; FMonkeyHookSwitch CMonkey::sm_HookSwitch = NULL; -CMonkey::CMonkey() : m_Probability(1.0), m_Enabled(false) +CMonkey::CMonkey() : m_Probability(100), m_Enabled(false) { if (sm_HookSwitch == NULL) { throw CMonkeyException( @@ -1345,20 +1408,21 @@ void CMonkey::ReloadConfig(const string& config) assert(sm_HookSwitch != NULL); CFastMutexGuard spawn_guard(s_ConfigMutex); string rules; - string monkey_section = config.empty() ? s_GetMonkeySection() : + string monkey_section = config.empty() ? s_GetMonkeySection() : config; list sections; + m_Plans.clear(); CNcbiRegistry& reg = CNcbiApplication::Instance()->GetConfig(); - if (ConnNetInfo_Boolean(reg.Get(kMonkeyMainSect, kEnablField).c_str()) != 1) + if (ConnNetInfo_Boolean(reg.Get(kMonkeyMainSect, kEnablField).c_str()) != 1) { - LOG_POST(Note << "[CMonkey::ReloadConfig] Chaos Monkey is disabled " + LOG_POST(Note << "[CMonkey::ReloadConfig] Chaos Monkey is disabled " << "in [" << kMonkeyMainSect << "]"); m_Enabled = false; return; } string seed = reg.Get(kMonkeyMainSect, kSeedField).c_str(); if (seed != "") { - LOG_POST(Note << "[CMonkey::ReloadConfig] Chaos Monkey seed is set " + LOG_POST(Note << "[CMonkey::ReloadConfig] Chaos Monkey seed is set " << "to " << seed << " in config"); SetSeed(NStr::StringToInt(seed)); } @@ -1366,37 +1430,50 @@ void CMonkey::ReloadConfig(const string& config) /* If the section does not exist */ if (find(sections.begin(), sections.end(), monkey_section) == sections.end()) { + LOG_POST(Error << "[CMonkey::ReloadConfig] Config section [" << + monkey_section << "] does not exist, Chaos Monkey " + "is NOT active!"); m_Enabled = false; return; } if (ConnNetInfo_Boolean(reg.Get(monkey_section, kEnablField).c_str()) != 1) { - LOG_POST(Note << "[CMonkey::ReloadConfig] Chaos Monkey is disabled " + LOG_POST(Note << "[CMonkey::ReloadConfig] Chaos Monkey is disabled " << "in [" << monkey_section << "]"); m_Enabled = false; return; } m_Enabled = true; LOG_POST(Error << "[CMonkey::ReloadConfig] Chaos Monkey is active!"); - string probability = reg.Get(monkey_section, "probability"); - if (probability != "") { - probability = NStr::Replace(probability, " ", ""); - auto arr = s_Monkey_Split(probability, '='); + string prob_str = reg.Get(monkey_section, "probability"); + if (prob_str != "") { + prob_str = NStr::Replace(prob_str, " ", ""); + int prob; try { - if (*probability.rbegin() != '%') { - m_Probability = NStr::StringToDouble(probability) * 100; + if (*prob_str.rbegin() == '%') { + string prob_tmp = prob_str.substr(0, prob_str.length() - 1); + prob = NStr::StringToInt(prob_tmp); } else { - probability = probability.substr(0, probability.length() - 1); - m_Probability = NStr::StringToDouble(probability); + prob = (int)(NStr::StringToDouble(prob_str) * 100); } + if (prob < 0 || prob > 100) { + throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), + NULL, + CMonkeyException::e_MonkeyInvalidArgs, + "Parameter \"probability\"=" + prob_str + + " for section [" + monkey_section + + "] is not a valid value " + "(valid range is 0%-100% or 0.0-1.0)"); + } + m_Probability = (unsigned short)prob; } catch (const CStringException&) { throw CMonkeyException(CDiagCompileInfo(__FILE__, __LINE__), NULL, CMonkeyException::e_MonkeyInvalidArgs, - "Probability \"" + probability - + "\" for section " + monkey_section - + " could not be parsed"); + "Parameter \"probability\"=" + prob_str + + " for section [" + monkey_section + + "] could not be parsed"); } } // Disable hooks while Monkey initializes @@ -1420,7 +1497,7 @@ void CMonkey::ReloadConfig(const string& config) "probability for plans stays under 100% (where the remaining " "percents go to connections that are not intercepted by any plan)." "\nTurning Chaos Monkey off"; - CORE_LOG(eLOG_Critical, ss.str().c_str()); + LOG_POST(Critical << ss.str()); m_Enabled = false; } if (m_Enabled) { @@ -1442,17 +1519,22 @@ MONKEY_RETTYPE CMonkey::Send(MONKEY_SOCKTYPE sock, { string host_fqdn, host_IP; unsigned short peer_port; - s_GetSocketDestinations(sock, &host_fqdn, &host_IP, NULL, &peer_port); - CMonkeyPlan* sock_plan = x_FindPlan(sock, host_fqdn, host_IP, peer_port); - - if (sock_plan != NULL) { - MONKEY_RETTYPE bytes_written; - /* Plan may decide to leave connection untouched */ - if ( sock_plan->WriteRule(sock, data, size, flags, &bytes_written, - sock_ptr) ) - return bytes_written; + if (m_Enabled) { + x_GetSocketDestinations(sock, &host_fqdn, &host_IP, NULL, &peer_port); + LOG_POST(Note << "[CMonkey::Send] For connection with port " + << peer_port << ", host " << host_IP + << " and hostname " << host_fqdn << "."); + CMonkeyPlan* sock_plan = x_FindPlan(sock, host_fqdn,host_IP,peer_port); + + if (sock_plan != NULL) { + MONKEY_RETTYPE bytes_written; + /* Plan may decide to leave connection untouched */ + if (sock_plan->WriteRule(sock, data, size, flags, &bytes_written, + sock_ptr) ) + return bytes_written; + } } - return send(sock, (const char*)data, size, flags); + return send(sock, (const char*)data, size, flags); } @@ -1464,14 +1546,20 @@ MONKEY_RETTYPE CMonkey::Recv(MONKEY_SOCKTYPE sock, { string host_fqdn, host_IP; unsigned short peer_port; - s_GetSocketDestinations(sock, &host_fqdn, &host_IP, NULL, &peer_port); - - CMonkeyPlan* sock_plan = x_FindPlan(sock, host_fqdn, host_IP, peer_port); - - if (sock_plan != NULL) { - MONKEY_RETTYPE bytes_read; - if (sock_plan->ReadRule(sock, buf, size, flags, &bytes_read, sock_ptr)) - return bytes_read; + if (m_Enabled) { + x_GetSocketDestinations(sock, &host_fqdn, &host_IP, NULL, &peer_port); + LOG_POST(Note << "[CMonkey::Recv] For connection with port " + << peer_port << ", host " << host_IP + << " and hostname " << host_fqdn << "."); + + CMonkeyPlan* sock_plan = x_FindPlan(sock, host_fqdn, host_IP,peer_port); + + if (sock_plan != NULL) { + MONKEY_RETTYPE bytes_read; + if (sock_plan->ReadRule(sock, buf, size, flags, &bytes_read, + sock_ptr)) + return bytes_read; + } } return recv(sock, buf, size, flags); } @@ -1488,18 +1576,23 @@ int CMonkey::Connect(MONKEY_SOCKTYPE sock, struct sockaddr_un un; #endif /*NCBI_OS_UNIX*/ } addr; - addr.sa = *name; - unsigned int host = addr.in.sin_addr.s_addr; - string host_fqdn, host_IP; - unsigned short peer_port = ntohs(addr.in.sin_port); - host_fqdn = CSocketAPI::gethostbyaddr(host); - host_IP = CSocketAPI::HostPortToString(host, 0); - - CMonkeyPlan* sock_plan = x_FindPlan(sock, host_fqdn, host_IP, peer_port); - if (sock_plan != NULL) { - int result; - if ( sock_plan->ConnectRule(sock, name, namelen, &result) ) - return result; + if (m_Enabled) { + addr.sa = *name; + unsigned int host = addr.in.sin_addr.s_addr; + string host_fqdn, host_IP; + unsigned short peer_port = ntohs(addr.in.sin_port); + SFqdnIp&& net_data = x_GetFqdnIp(host); + LOG_POST(Note << "[CMonkey::Connect] For connection with port " + << peer_port << ", host " << host_IP + << " and hostname " << host_fqdn << "."); + CMonkeyPlan* sock_plan = x_FindPlan(CMonkey::GetSockBySocketid(sock), + net_data.fqdn, net_data.ip, + peer_port); + if (sock_plan != NULL) { + int result; + if ( sock_plan->ConnectRule(sock, name, namelen, &result) ) + return result; + } } return connect(sock, name, namelen); } @@ -1509,24 +1602,35 @@ bool CMonkey::Poll(size_t* n, SSOCK_Poll** polls, EIO_Status* return_status) { - size_t polls_iter = 0; - SSOCK_Poll* new_polls = - static_cast(calloc(*n, sizeof(SSOCK_Poll))); - int polls_count = 0; - while (polls_iter < *n) { - SOCK& sock = (*polls)[polls_iter].sock; - string host_fqdn = CSocketAPI::gethostbyaddr(sock->host); - string host_IP = CSocketAPI::HostPortToString(sock->host, 0); - CMonkeyPlan* sock_plan = x_FindPlan(sock->id, "", "", sock->myport); - if (sock_plan == NULL || - (sock_plan != NULL && !sock_plan->PollRule(n, &sock, return_status)) - ) { - new_polls[polls_count++] = (*polls)[polls_iter]; + if (m_Enabled) { + size_t polls_iter = 0; + SSOCK_Poll* new_polls = + static_cast(calloc(*n, sizeof(SSOCK_Poll))); + int polls_count = 0; + while (polls_iter < *n) { + SOCK& sock = (*polls)[polls_iter].sock; + if (sock == NULL) continue; + LOG_POST(Note << "[CMonkey::Poll] For connection with port " + << sock->myport << ", host and " + "hostname ."); + if (sock != nullptr) + { + CMonkeyPlan* sock_plan = x_FindPlan(sock->id, "", "", + sock->myport); + if (sock_plan == NULL || + (sock_plan != NULL && !sock_plan->PollRule(n, &sock, + return_status)) ) + { + new_polls[polls_count++] = (*polls)[polls_iter]; + } + } else { /* something unreadable by Monkey, but still valid */ + new_polls[polls_count++] = (*polls)[polls_iter]; + } + polls_iter++; } - polls_iter++; + *polls = new_polls; + *n = polls_count; } - *polls = new_polls; - *n = polls_count; return false; } @@ -1537,6 +1641,33 @@ void CMonkey::Close(MONKEY_SOCKTYPE sock) if (sock_plan != m_KnownSockets.end()) { m_KnownSockets.erase(sock_plan); } + auto sock_iter = m_SocketMemory.begin(); + for ( ; sock_iter != m_SocketMemory.end() ; ) + { + if (sock_iter->first == sock) + m_SocketMemory.erase(sock_iter++); + else + ++sock_iter; + } +} + + +void CMonkey::SockHasSocket(SOCK sock, MONKEY_SOCKTYPE socket) +{ + m_SocketMemory[socket] = sock; +} + + +MONKEY_SOCKTYPE CMonkey::GetSockBySocketid(MONKEY_SOCKTYPE socket) +{ + union SSockSocket + { + SOCK sock; + MONKEY_SOCKTYPE socket; + }; + SSockSocket sock_socket; + sock_socket.sock = m_SocketMemory[socket]; + return sock_socket.socket; } @@ -1558,15 +1689,17 @@ CMonkeyPlan* CMonkey::x_FindPlan(MONKEY_SOCKTYPE sock, const string& hostname, } /* Plan was not found. First roll the dice to know if Monkey will process * current socket */ - int rand_val = CMonkey::Instance()->GetRand(Key()); - LOG_POST(Note << "[CMonkey::x_FindPlan] Checking if connection will be " + int rand_val = CMonkey::Instance()->GetRand(Key()) % 100; + LOG_POST(Note << "[CMonkey::x_FindPlan] Checking if connection " + "with port " << port << ", host " << host_IP + << " and hostname " << hostname << " will be " << "intercepted by Chaos Monkey. Random value is " << rand_val << ", probability threshold is " << m_Probability); - LOG_POST(Note << "[CMonkey::x_FindPlan] The connection will be " - << ((rand_val % 100 >= m_Probability) ? "NOT " : "") - << "processed."); - if (rand_val % 100 >= m_Probability) { + LOG_POST(Note << "[CMonkey::x_FindPlan] The connection will " + << ((rand_val >= m_Probability) ? "NOT " : "") + << "be processed."); + if (rand_val >= m_Probability) { return NULL; } /* Now we can find a plan */ @@ -1595,6 +1728,18 @@ CMonkeyPlan* CMonkey::x_FindPlan(MONKEY_SOCKTYPE sock, const string& hostname, } +CMonkey::SFqdnIp CMonkey::x_GetFqdnIp(unsigned int host) +{ + CFastMutexGuard guard(s_NetworkDataCacheMutex); + auto iter = m_NetworkDataCache.find(host); + if (iter != m_NetworkDataCache.end()) + return iter->second; + string host_fqdn = CSocketAPI::gethostbyaddr(host); + string host_IP = CSocketAPI::HostPortToString(host, 0); + return m_NetworkDataCache[host] = SFqdnIp(host_fqdn, host_IP); +} + + bool CMonkey::RegisterThread(int token) { if (!m_Enabled) { diff --git a/c++/src/connect/ncbi_monkeyp.hpp b/c++/src/connect/ncbi_monkeyp.hpp index 05250edf..c9315385 100644 --- a/c++/src/connect/ncbi_monkeyp.hpp +++ b/c++/src/connect/ncbi_monkeyp.hpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_monkeyp.hpp 503153 2016-06-01 19:11:37Z elisovdn $ +/* $Id: ncbi_monkeyp.hpp 508616 2016-07-29 15:22:55Z elisovdn $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -48,16 +48,22 @@ BEGIN_NCBI_SCOPE using namespace std; -#define MONKEY_MOCK_MACRO() \ -DECLARE_MONKEY_MOCK(bool, InterceptedRecv, false); \ -DECLARE_MONKEY_MOCK(bool, InterceptedSend, false); \ -DECLARE_MONKEY_MOCK(bool, InterceptedConnect, false); \ -DECLARE_MONKEY_MOCK(bool, InterceptedPoll, false); \ -DECLARE_MONKEY_MOCK(string, LastRecvContent, ""); \ -DECLARE_MONKEY_MOCK(string, LastSendContent, ""); \ -DECLARE_MONKEY_MOCK(EIO_Status, LastRecvStatus, eIO_Success); \ -DECLARE_MONKEY_MOCK(EIO_Status, LastSendStatus, eIO_Success); \ -DECLARE_MONKEY_MOCK(EIO_Status, LastConnectStatus, eIO_Success); +/* Generate mock function declarations like: + * + * bool g_MonkeyMock_GetInterceptedRecv(); + * void g_MonkeyMock_SetInterceptedRecv(const bool& val); + */ +#define MONKEY_MOCK_MACRO() \ +DECLARE_MONKEY_MOCK(bool, InterceptedRecv, false); \ +DECLARE_MONKEY_MOCK(bool, InterceptedSend, false); \ +DECLARE_MONKEY_MOCK(bool, InterceptedConnect, false); \ +DECLARE_MONKEY_MOCK(bool, InterceptedPoll, false); \ +DECLARE_MONKEY_MOCK(string, LastRecvContent, ""); \ +DECLARE_MONKEY_MOCK(string, LastSendContent, ""); \ +DECLARE_MONKEY_MOCK(EIO_Status, LastRecvStatus, eIO_Success); \ +DECLARE_MONKEY_MOCK(EIO_Status, LastSendStatus, eIO_Success); \ +DECLARE_MONKEY_MOCK(EIO_Status, LastConnectStatus, eIO_Success); \ +DECLARE_MONKEY_MOCK(EIO_Status, LastPollStatus, eIO_Success); #undef DECLARE_MONKEY_MOCK @@ -67,13 +73,39 @@ DECLARE_MONKEY_MOCK(EIO_Status, LastConnectStatus, eIO_Success); MONKEY_MOCK_MACRO() void g_Monkey_Foo(); - + + class CMonkeySpy { }; +class CMonkeyMocks +{ +public: + static void Reset(); + static string GetMainMonkeySection(); + static void SetMainMonkeySection(string section); +private: + static string MainMonkeySection; +}; + + +class CMonkeyMockCleanup +{ +public: + CMonkeyMockCleanup() + { + CMonkeyMocks::Reset(); + } + ~CMonkeyMockCleanup() + { + CMonkeyMocks::Reset(); + } +}; + + #endif /* #ifdef NCBI_MONKEY_TESTS */ END_NCBI_SCOPE diff --git a/c++/src/connect/ncbi_namerd.c b/c++/src/connect/ncbi_namerd.c new file mode 100644 index 00000000..eee3ce3d --- /dev/null +++ b/c++/src/connect/ncbi_namerd.c @@ -0,0 +1,1542 @@ +/* $Id: ncbi_namerd.c 539642 2017-06-26 13:22:31Z ivanov $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Anton Lavrentiev, David McElhany + * + * File Description: + * Low-level API to resolve an NCBI service name to server meta-addresses + * with the use of NAMERD. + * + */ + +#include "ncbi_ansi_ext.h" +#include "ncbi_comm.h" +#include "ncbi_lb.h" +#include "ncbi_namerd.h" +#include "ncbi_once.h" +#include "ncbi_priv.h" +#include "parson.h" + +#include +#include +#include +#include + +#include +#include +#include + + +#ifdef _MSC_VER +#define FMT_SIZE_T "%llu" +#define FMT_TIME_T "%llu" +#else +#define FMT_SIZE_T "%zu" +#define FMT_TIME_T "%lu" +#endif + + +#define NCBI_USE_ERRCODE_X Connect_Namerd + + +/* NAMERD subcodes for CORE_LOG*X() macros */ +enum ENAMERD_Subcodes { + eNSub_Message = 0, /**< not an error */ + eNSub_Alloc = 1, /**< memory allocation failed */ + eNSub_BadData = 2, /**< bad data was provided */ + eNSub_Connect = 3, /**< problem in connect library */ + eNSub_HttpRead = 4, /**< failed reading from HTTP conn */ + eNSub_Json = 5, /**< a JSON parsing failure */ + eNSub_Libc = 6, /**< a standard library failure */ + eNSub_NoService = 7, /**< couldn't reach namerd service provider */ + eNSub_TooLong = 8 /**< data was too long to fit in a buffer */ +}; + + +/* Apache is limited to around 4000 byte query strings. -- todo: find reference + * Note that this is approximate and doesn't need to be precise because + * it's more than should be required for namerd anyway. + */ +#define MAX_QRY_STR_LEN 4000 + +/* This is hard-coded in the definition of SConnNetInfo in ncbi_connutil.h */ +#define MAX_ARGS_LEN 2048 + +/* Misc. */ +#define DTAB_HDR_FIELD_NAME "DTab-Local" +#define NIL '\0' + + +/* Registry entry names and default values for NAMERD "SConnNetInfo" fields. + Note that these are purely for the NAMERD API; they don't relate to any + other part of the connect library, returned endpoints, or client code. + Therefore, they are independent of other connect library macros. + Also, the namerd API doesn't support using a port so there's no macro for + that. + */ +#define REG_NAMERD_SECTION "_NAMERD" + +#define REG_NAMERD_PROXY_HOST_KEY "PROXY_HOST" + +/* NAMERD_TODO - "temporarily" support plain "linkerd" on Unix only */ +#if defined(NCBI_OS_UNIX) && ! defined(NCBI_OS_CYGWIN) +#define REG_NAMERD_PROXY_HOST_DEF "linkerd" +#else +#define REG_NAMERD_PROXY_HOST_DEF \ + "linkerd-proxy.service.bethesda-dev.consul.ncbi.nlm.nih.gov" +#endif + +#define REG_NAMERD_PROXY_PORT_KEY "PROXY_PORT" +#define REG_NAMERD_PROXY_PORT_DEF 4140 + +#define REG_NAMERD_API_HOST_KEY "API_HOST" +#define REG_NAMERD_API_HOST_DEF "namerd-api.linkerd.ncbi.nlm.nih.gov" + +#define REG_NAMERD_API_PATH_KEY "API_PATH" +#define REG_NAMERD_API_PATH_DEF "/api/1/resolve" + +#define REG_NAMERD_API_ARGS_KEY "API_ARGS" +#define REG_NAMERD_API_ARGS_DEF "path=/service/" + +#define REG_NAMERD_API_REQ_KEY "API_REQ_METHOD" +#define REG_NAMERD_API_REQ_DEF "GET" + +#define REG_NAMERD_API_SCHEME_KEY "API_SCHEME" +#define REG_NAMERD_API_SCHEME_DEF "http" + +#define REG_NAMERD_API_ENV_KEY "API_ENVIRONMENT" +#define REG_NAMERD_API_ENV_DEF "default" + +#define REG_NAMERD_DTAB_KEY "DTAB" +#define REG_NAMERD_DTAB_DEF "" + + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +static int/*bool*/ s_Adjust(SConnNetInfo* net_info, + void* iter, + unsigned int unused); + +static SSERV_Info* s_GetNextInfo(SERV_ITER, HOST_INFO*); +static int/*bool*/ s_Update (SERV_ITER, const char*, int); +static void s_Reset (SERV_ITER); +static void s_Close (SERV_ITER); + +static const SSERV_VTable s_op = { + s_GetNextInfo, NULL/*Feedback*/, s_Update, s_Reset, s_Close, "NAMERD" +}; + +static EHTTP_HeaderParse s_ParseHeader(const char* header, + void* iter, + int server_error); + +#ifdef __cplusplus +} /* extern "C" */ +#endif /*__cplusplus*/ + + +struct SNAMERD_Data { + short/*bool*/ eof; /* no more resolves */ + short/*bool*/ fail; /* no more connects */ + short/*bool*/ done; /* all endpoints have been processed */ + SConnNetInfo* net_info; + SLB_Candidate* cand; + size_t n_cand; + size_t a_cand; +}; + + +/* Extra-verbose tracing to make following nested functions easier. */ +#define EXTRA_VERBOSE_DBG 1 +#if defined(EXTRA_VERBOSE_DBG) && defined(_DEBUG) && ! defined(NDEBUG) + +static int s_nest = 0; /* trace nest level */ + +#define NEST_PFX ".........................................................." +#define NEST_PFXX "**********************************************************" +#define MAX_NEST ((int)(sizeof(NEST_PFX)-1)) + +#define PFXI (s_nest++ > MAX_NEST ? NEST_PFXX : NEST_PFX + MAX_NEST - s_nest+1) +#define PFXO (--s_nest > MAX_NEST ? NEST_PFXX : NEST_PFX + MAX_NEST - s_nest ) + +#define TIN( fmt ) CORE_TRACEF(("%s[ " fmt, PFXI )); +#define TIN1(fmt, arg ) CORE_TRACEF(("%s[ " fmt, PFXI, arg )); +#define TIN2(fmt, arg1, arg2) CORE_TRACEF(("%s[ " fmt, PFXI, arg1, arg2)); + +#define TOUT( fmt ) CORE_TRACEF(("%s] " fmt, PFXO )); +#define TOUT1(fmt, arg ) CORE_TRACEF(("%s] " fmt, PFXO, arg )); + +#else + +#define TIN( fmt ) +#define TIN1(fmt, arg ) +#define TIN2(fmt, arg1, arg2) + +#define TOUT( fmt ) +#define TOUT1(fmt, arg ) + +#endif /* EXTRA_VERBOSE_DBG */ + + +/* Some static variables needed only to support testing with mock data. + Testing with mock data is currently limited to single-threaded tests. */ +static int s_initialized = 0; +static BUF s_mock_buf = NULL; +static const char* s_mock_body = NULL; + + +/* Set up the ability to flexibly use either a file or http connector for + reading from. This will enable higher performance normal operation while + also allowing file input for testing with minimal code impact. + */ +static CONNECTOR s_CreateConnectorHttp(SERV_ITER iter); +static CONNECTOR s_CreateConnectorMemory(SERV_ITER iter); + +typedef CONNECTOR (*fCreateConnector)(SERV_ITER iter); +static fCreateConnector s_CreateConnector = s_CreateConnectorHttp; + + +static CONNECTOR s_CreateConnectorHttp(SERV_ITER iter) +{ + CORE_TRACE("s_CreateConnectorHttp()"); + struct SNAMERD_Data* data = (struct SNAMERD_Data*) iter->data; + + return HTTP_CreateConnectorEx(data->net_info, fHTTP_Flushable, + s_ParseHeader, iter/*data*/, s_Adjust, 0/*cleanup*/); +} + + +static void s_DestroyMockBuf(void) +{ + if (s_mock_buf) + BUF_Destroy(s_mock_buf); + s_mock_buf = NULL; +} + + +static CONNECTOR s_CreateConnectorMemory(SERV_ITER iter) +{ + CORE_TRACE("s_CreateConnectorMemory()"); + assert(s_mock_body); + + /* Reset buffer for each connector */ + s_DestroyMockBuf(); + + BUF_Append(&s_mock_buf, (void*)s_mock_body, strlen(s_mock_body)); + + return MEMORY_CreateConnectorEx(s_mock_buf, 0); +} + + +static void s_Quit(void) +{ + s_DestroyMockBuf(); + CORE_LOCK_WRITE; + s_initialized = 0; + CORE_UNLOCK; +} + + +static void s_Init(void) +{ + CORE_LOCK_READ; + if (s_initialized) { + CORE_UNLOCK; + return; + } + CORE_UNLOCK; + + if (atexit(s_Quit) == 0) { + CORE_LOCK_WRITE; + s_initialized = 1; + CORE_UNLOCK; + } else { + static void* s_Once = 0; + if (CORE_Once(&s_Once)) { + CORE_LOG_X(eNSub_Libc, eLOG_Error, + "Error registering atexit function."); + } + } +} + + +static EIO_Status s_CONN_Create(SERV_ITER iter, CONNECTOR* c_p, CONN* conn_p) +{ + EIO_Status status = eIO_Unknown; + + TIN("s_CONN_Create()"); + + /* require valid, NULL pointers */ + assert(c_p && ! *c_p ); + assert(conn_p && ! *conn_p); + + *c_p = s_CreateConnector(iter); + if (*c_p) { + status = CONN_Create(*c_p, conn_p); + if (status != eIO_Success) { + CORE_LOGF_X(eNSub_Connect, eLOG_Error, + ("Unable to create connection, status = %s.", + IO_StatusStr(status))); + if ((*c_p)->destroy && (*c_p)->handle) + (*c_p)->destroy(*c_p); + *c_p = NULL; + *conn_p = NULL; + } + } else { + CORE_LOG_X(eNSub_Connect, eLOG_Error, "Unable to create connector."); + } + + TOUT("s_CONN_Create()"); + return status; +} + + +static void s_CONN_Destroy(CONNECTOR* c_p, CONN* conn_p) +{ + assert(conn_p); + if (*conn_p) CONN_Close(*conn_p); + *c_p = NULL; + *conn_p = NULL; + s_DestroyMockBuf(); +} + + +/* Update a dtab value by appending another entry. */ +static void s_UpdateDtab(char** dest_dtab_p, char* src_dtab, int* success_p) +{ + char* new_dtab = NULL; + char enc_dtab[MAX_QRY_STR_LEN + 1]; + size_t new_size, src_size, enc_size; + + TIN2("s_UpdateDtab(\"%s\") -- old dtab = \"%s\"", src_dtab, + *dest_dtab_p ? *dest_dtab_p : ""); + + if ( ! *success_p) { + TOUT("s_UpdateDtab() -- prior no success"); + return; + } + if ( ! *src_dtab) { + TOUT("s_UpdateDtab() -- prior no dtab"); + return; + } + + /* Ignore header label if it was included. */ + if (strncasecmp(src_dtab, DTAB_HDR_FIELD_NAME ":", + sizeof(DTAB_HDR_FIELD_NAME) + 1/*':'*/ - 1/*'\0'*/) == 0) + { + /* advance start past name, colon, and any whitespace */ + src_dtab += sizeof(DTAB_HDR_FIELD_NAME) + 1/*':'*/ - 1/*'\0'*/; + while (*src_dtab == ' ' || *src_dtab == '\t') ++src_dtab; + } + + /* Dtabs passed as query string parameter must be url-encoded, for example: + * from: "/lbsm/bounce=>/service/xyz" + * to: "%2Flbsm%2Fbounce%3D%3E%2Fservice%2Fxyz" + */ + URL_Encode(src_dtab, strlen(src_dtab), &src_size, + enc_dtab, MAX_QRY_STR_LEN, &enc_size); + enc_dtab[enc_size] = NIL; /* not done by URL_Encode() */ + + /* If dtab already has an entry then append a semicolon and the new dtab. */ + if (*dest_dtab_p && **dest_dtab_p) { + new_size = strlen(*dest_dtab_p) + 3/* "%3B" */ + strlen(enc_dtab) + 1; + new_dtab = (char*)realloc(*dest_dtab_p, new_size); + if (new_dtab) { + strcat(new_dtab, "%3B"); /* url-encoded ';' separator */ + strcat(new_dtab, enc_dtab); + } + } else { + /* Dtab didn't exist yet, so just clone it. */ + new_dtab = strdup(enc_dtab); + } + if ( ! new_dtab) { + *success_p = 0; + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, "Couldn't alloc for dtab."); + TOUT("s_UpdateDtab() -- bad alloc"); + return; + } + + /* Update the caller's pointer. */ + *dest_dtab_p = new_dtab; + + TOUT1("s_UpdateDtab() -- new dtab = \"%s\"", new_dtab); +} + + +static TReqMethod s_GetReqMethod() +{ + char val[20]; + + if ( ! ConnNetInfo_GetValue(REG_NAMERD_SECTION, + REG_NAMERD_API_REQ_KEY, val, sizeof(val)-1, + REG_NAMERD_API_REQ_DEF)) + { + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, + "Couldn't alloc for request method."); + return eReqMethod_Any; + } + if ( ! *val) return eReqMethod_Any; + if (strcasecmp(val, "GET") == 0) return eReqMethod_Get; + if (strcasecmp(val, "POST") == 0) return eReqMethod_Post; + if (strcasecmp(val, "GET11") == 0) return eReqMethod_Get11; + if (strcasecmp(val, "POST11") == 0) return eReqMethod_Post11; + + return eReqMethod_Any; +} + + +static EBURLScheme s_GetScheme() +{ + char val[12]; + + if ( ! ConnNetInfo_GetValue(REG_NAMERD_SECTION, + REG_NAMERD_API_SCHEME_KEY, val, sizeof(val)-1, + REG_NAMERD_API_SCHEME_DEF)) + { + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, + "Couldn't alloc for scheme."); + return eURL_Unspec; + } + if ( ! *val) return eURL_Unspec; + if (strcasecmp(val, "http") == 0) return eURL_Http; + if (strcasecmp(val, "https") == 0) return eURL_Https; + + return eURL_Unspec; +} + + +static unsigned short s_GetProxyPort() +{ + char val[24]; + char reg_def_port[24]; + unsigned short port; + + sprintf(reg_def_port, "%hu", REG_NAMERD_PROXY_PORT_DEF); + if ( ! ConnNetInfo_GetValue(REG_NAMERD_SECTION, + REG_NAMERD_PROXY_PORT_KEY, val, sizeof(val)-1, + reg_def_port)) + { + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, + "Couldn't alloc for proxy port."); + return 0; + } + if ( ! *val) + return 0; + if (sscanf(val, "%hu", &port) == 1) + return port; + + return 0; +} + + +static void s_RemoveCand(struct SNAMERD_Data* data, size_t n, int free_info) +{ + CORE_TRACE("s_RemoveCand() Removing endpoint."); + assert(n >= 0 && n < data->n_cand); + if (free_info) + free((void*) data->cand[n].info); + if (n < --data->n_cand) { + memmove(data->cand + n, data->cand + n + 1, + (data->n_cand - n) * sizeof(*data->cand)); + } + if (data->n_cand == 0) + data->done = 1; +} + + +static void s_RemoveStandby(struct SNAMERD_Data* data) +{ + double max_rate = 0.0; + int all_standby = 1, i; + + /* basic logic: + if any endpoints have rate >= LBSM_STANDBY_THRESHOLD + discard all endpoints with rate < LBSM_STANDBY_THRESHOLD + else + discard all endpoints with rate < highest rate + */ + + for (i = 0; i < (int)data->n_cand; ++i) { + + if (max_rate < data->cand[i].info->rate) + max_rate = data->cand[i].info->rate; + + if (data->cand[i].info->rate >= LBSM_STANDBY_THRESHOLD) + all_standby = 0; + } + + for (i = (int)data->n_cand - 1; i >= 0; --i) { + if (data->cand[i].info->rate < + (all_standby ? max_rate : LBSM_STANDBY_THRESHOLD)) + s_RemoveCand(data, (size_t)i, 1); + } +} + + +static int/*bool*/ s_AddServerInfo(struct SNAMERD_Data* data, SSERV_Info* info) +{ + const char* name = SERV_NameOfInfo(info); + size_t i; + + /* First check that the new server info updates an existing one */ + for (i = 0; i < data->n_cand; ++i) { + if (strcasecmp(name, SERV_NameOfInfo(data->cand[i].info)) == 0 + && SERV_EqualInfo(info, data->cand[i].info)) + { + /* Replace older version */ + CORE_TRACE("Replaced older version."); + free((void*) data->cand[i].info); + data->cand[i].info = info; + data->cand[i].status = info->rate; + + return 1; + } + } + + /* Grow candidates container at capacity - trigger growth when there's no + longer room for a new entry. */ + if (data->a_cand == 0 || data->n_cand >= data->a_cand) { + size_t n = data->a_cand + 10; + SLB_Candidate* temp = + (SLB_Candidate*)realloc(data->cand, n * sizeof(*temp)); + if ( ! temp) { + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, + "Failed to reallocate memory for new candidates."); + return 0; + } + data->cand = temp; + data->a_cand = n; + } + + /* Add the new service to the list */ +#if defined(_DEBUG) && ! defined(NDEBUG) + {{ + char hostbuf[40]; + SOCK_ntoa(info->host, hostbuf, sizeof(hostbuf)); + CORE_TRACEF(("Added candidate %s:%hu with svc_type '%s'.", + hostbuf, info->port, SERV_TypeStr(info->type))); + }} +#endif + data->cand[data->n_cand].info = info; + data->cand[data->n_cand].status = info->rate; + data->n_cand++; + data->done = 0; + + return 1; +} + + +/* Parse the "addrs[i].meta.expires" JSON from the namerd API, and adjust + it according to the local timezone/DST to get the UTC epoch time. + This function is not meant to be a generic ISO-8601 parser. It expects + the namerd API to return times in the format: "2017-03-29T23:02:55Z" + Unfortunately, strptime is not supported at all on Windows, and doesn't + support the "%z" format on Unix, so some custom parsing is required. + */ +static TNCBI_Time s_ParseExpires(time_t tt_now, const char* expires) +{ + int tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec; + char tm_zulu; + + assert(expires); + + if (sscanf(expires, "%d-%d-%dT%d:%d:%d%c", &tm_year, &tm_mon, &tm_mday, + &tm_hour, &tm_min, &tm_sec, &tm_zulu) != 7 || + tm_year < 2017 || + (tm_mon < 0 || tm_mon > 11) || + (tm_mday < 1 || tm_mday > 31) || + (tm_hour < 0 || tm_hour > 23) || + (tm_min < 0 || tm_min > 59) || + (tm_sec < 0 || tm_sec > 60) || + tm_zulu != 'Z') + { + CORE_LOGF_X(eNSub_Json, eLOG_Error, + ("Unexpected JSON {\"addrs[i].meta.expires\"} " + "value '%s'.", expires)); + return 0; + } + tm_year -= 1900; /* years since 1900 */ + tm_mon -= 1; /* months since January: 0-11 */ + + /* Get the UTC epoch time for the expires value. */ + struct tm tm_expires; + tm_expires.tm_year = tm_year; + tm_expires.tm_mon = tm_mon; + tm_expires.tm_mday = tm_mday; + tm_expires.tm_hour = tm_hour; + tm_expires.tm_min = tm_min; + tm_expires.tm_sec = tm_sec; + tm_expires.tm_isdst = 0; + tm_expires.tm_wday = 0; + tm_expires.tm_yday = 0; + + /* Adjust for time diff between local and UTC, which should + correspond to 3600 x (number of time zones from UTC), + i.e. diff between current TZ (UTC-12 to UTC+14) and UTC. */ + double tdiff; + struct tm tm_now; + CORE_LOCK_WRITE; + tm_now = *gmtime(&tt_now); + CORE_UNLOCK; + tdiff = difftime(mktime(&tm_expires), mktime(&tm_now)); + if (tdiff < -14.0 * 3600.0 || tdiff > 12.0 * 3600.0) { + CORE_LOGF_X(eNSub_Json, eLOG_Error, + ("Unexpected JSON {\"addrs[i].meta.expires\"} " + "value '%s' - tdiff = %lf", expires, tdiff)); + return 0; + } + TNCBI_Time timeval = (TNCBI_Time)((double)tt_now + tdiff); + /*CORE_TRACEF( + ("expires: %s tdiff %lf now " FMT_TIME_T " info->time %u", + expires, tdiff, tt_now, timeval));*/ + + return timeval; +} + + +/* Parsing the response requires having the entire response in + one buffer. Therefore, realloc as necessary. + + If the realloc'd size significantly exceeds the needed size, be nice and + realloc it back down to match the needed size. + */ +static EIO_Status s_ReadFullResponse(CONN conn, char** bufp, + SConnNetInfo* net_info) +{ + /* just try a limited number of buffer sizes, in a + roughly geometric sequence */ + static size_t buf_len_steps[] = {3100, 100100, 3100100}; + int max_steps = sizeof(buf_len_steps)/sizeof(buf_len_steps[0]); + size_t waste_threshold = 50100; + size_t total_got = 0; + size_t buf_len, step_max, step_got; + char* new_buf; + int num_steps; + EIO_Status status = eIO_Unknown; + + TIN("s_ReadFullResponse()"); + + assert(bufp); + assert(net_info); + + for (num_steps = 0; num_steps < max_steps; ++num_steps) { + + /* Expand the buffer to the next step size. */ + buf_len = buf_len_steps[num_steps]; + new_buf = (char*)realloc(*bufp, buf_len); + if ( ! new_buf) { + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, + "Failed to allocate memory for response buffer."); + if (*bufp) { + free(*bufp); + *bufp = NULL; + } + TOUT("s_ReadFullResponse() -- bad alloc"); + return eIO_Unknown; + } + *bufp = new_buf; + + /* Read the next block of data. */ + step_max = buf_len - total_got - 1/* zero-terminate */; + step_got = 0; + do { + size_t read_max, read_got; + read_max = step_max - step_got; + status = CONN_Read(conn, *bufp + total_got + step_got, + read_max, &read_got, eIO_ReadPlain); + step_got += read_got; + CORE_TRACEF(( + "CONN_Read(step_max,step_got,read_max,read_got,status)=(" + FMT_SIZE_T "," FMT_SIZE_T "," FMT_SIZE_T "," FMT_SIZE_T ",%s)", + step_max, step_got, read_max, read_got, IO_StatusStr(status))); + } while (step_got < step_max && status == eIO_Success); + total_got += step_got; + + /* Need to increase buffer size? */ + if (step_got == step_max && status == eIO_Success) { + continue; + } + + /* Handle problems. */ + if (status != eIO_Closed) { + CORE_LOGF_X(eNSub_HttpRead, eLOG_Error, + ("Read error: %s", IO_StatusStr(status))); + free(*bufp); + *bufp = NULL; + TOUT("s_ReadFullResponse() -- read problem"); + return status; + } + + /* All data has been fetched. */ + CORE_TRACEF(( + "All data fetched, (num_steps,buf_len,total_got,step_max," + "step_got)=(%d," FMT_SIZE_T "," FMT_SIZE_T "," FMT_SIZE_T + "," FMT_SIZE_T ")", num_steps, buf_len, total_got, step_max, + step_got)); + break; + } + + /* See if the max buffer size was insufficient (this is extremely unlikely + and would suggest reviewing the design of this function). */ + if (step_got == step_max && status == eIO_Success) { + CORE_LOG_X(eNSub_TooLong, eLOG_Error, "Insufficient buffer size."); + free(*bufp); + *bufp = NULL; + TOUT("s_ReadFullResponse() -- read problem"); + return status; + } + + (*bufp)[total_got] = NIL; /* zero-terminate */ + + /* Reduce the buffer size if there's a lot of wasted space. */ + if (buf_len - total_got > waste_threshold) { + new_buf = (char*)realloc(*bufp, total_got + 1/* zero-terminate */); + if (new_buf) { + *bufp = new_buf; + } + } + + CORE_TRACEF(("Got response: %s", *bufp)); + + TOUT("s_ReadFullResponse()"); + return eIO_Success; +} + + +static int/*bool*/ s_ParseResponse(SERV_ITER iter, CONN conn) +{ + struct SNAMERD_Data* data = (struct SNAMERD_Data*) iter->data; + SConnNetInfo* net_info = data->net_info; + x_JSON_Value* root_value = NULL; + char* response = NULL; + int/*bool*/ retval = 0; + + TIN("s_ParseResponse()"); + + if (eIO_Success == s_ReadFullResponse(conn, &response, net_info)) { + x_JSON_Object *root_obj; + x_JSON_Array *address_arr; + const char *success_type; + size_t it; + + /* root object */ + root_value = x_json_parse_string(response); + if ( ! root_value) { + CORE_LOG_X(eNSub_Json, eLOG_Error, + "Response couldn't be parsed as JSON."); + goto out; + } + if (x_json_value_get_type(root_value) != JSONObject) { + CORE_LOG_X(eNSub_Json, eLOG_Error, + "Response root name is not a JSON object."); + goto out; + } + root_obj = x_json_value_get_object(root_value); + if ( ! root_obj) { + CORE_LOG_X(eNSub_Json, eLOG_Error, + "Couldn't get JSON root object."); + goto out; + } +#if defined(_DEBUG) && ! defined(NDEBUG) + char json[9999]; + if (x_json_serialize_to_buffer_pretty( + root_value, json, sizeof(json)-1) == JSONSuccess) + CORE_TRACEF(("Got JSON:\n%s", json)); + else + CORE_LOG_X(eNSub_Json, eLOG_Error, "Couldn't serialize JSON"); +#endif + + /* top-level {"type" : "bound"} expected for successful connection */ + success_type = x_json_object_get_string(root_obj, "type"); + if ( ! success_type) { + CORE_LOG_X(eNSub_Json, eLOG_Error, + "Couldn't get JSON {\"type\"} value."); + goto out; + } + if (strcmp(success_type, "bound") != 0) { + CORE_LOGF_X(eNSub_NoService, eLOG_Error, + ("Service \"%s\" appears to be unknown.", iter->name)); + goto out; + } + + /* top-level {"addrs" : []} contains endpoint data */ + address_arr = x_json_object_get_array(root_obj, "addrs"); + if ( ! address_arr) { + CORE_LOG_X(eNSub_Json, eLOG_Error, + "Couldn't get JSON {\"addrs\"} array."); + goto out; + } + + /* Note: top-level {"meta" : {}} not currently used */ + + /* Iterate through addresses, adding to "candidates". */ + for (it = 0; it < x_json_array_get_count(address_arr); ++it) { + x_JSON_Object *address; + const char *host, *extra, *svc_type, *mode; + const char *cpfx, *ctype; + const char *local; + const char *priv; + const char *stateful; + char *server_description; + double rate; + int port; + + /* JSON|SSERV_Info|variable mapping to format string: + meta.expires|time|time -------------------------------+ + meta.stateful|mode|stateful ---------------------+ | + meta.rate|rate|rate ---------------------------+ | | + meta.mode|site|priv ----------------------+ | | | + meta.mode|site|local -------------------+ | | | | + meta.contentType|mime_*|cpfx,ctype | | | | | + meta.extra|extra|extra -------+ | | | | | | + port|port|port ------------+ | | | | | | | + ip|host|host -----------+ | | | | | | | | + meta.serviceType| | | | | | | | | | + type|svc_type ---+ | | | | | | | | | + [] [] [] [] [__] [][] [][] [] */ + const char* descr_fmt = "%s %s:%u %s %s%s L=%s%s R=%s%s T=%u"; + /* NOTE: Some fields must not be included in certain situations + because SERV_ReadInfoEx() does not expect them in those + situations, and if they are present then SERV_ReadInfoEx() + will prematurely terminate processing the description. + Specifically: + do not include when + -------------- --------------------- + P= type=DNS + S= type=DNS or type=HTTP + */ + + /* get a handle on the object for this iteration */ + address = x_json_array_get_object(address_arr, it); + if ( ! address) { + CORE_LOG_X(eNSub_Json, eLOG_Error, + "Couldn't get JSON {\"addrs[i]\"} object."); + goto out; + } + + /* SSERV_Info.host <=== addrs[i].ip */ + host = x_json_object_get_string(address, "ip"); + if ( ! host || ! *host) { + CORE_LOG_X(eNSub_Json, eLOG_Error, + "Couldn't get JSON {\"addrs[i].ip\"} value."); + goto out; + } + + /* SSERV_Info.port <=== addrs[i].port */ + /* Unfortunately the x_json_object_get_number() function does + not distinguish failure from a legitimate zero value. :-/ + Therefore, first explicitly check for the value. */ + if ( ! x_json_object_has_value_of_type( + (const x_JSON_Object *)address, + (const char *)"port", JSONNumber)) + { + CORE_LOG_X(eNSub_Json, eLOG_Error, + "Couldn't get JSON {\"addrs.port\"} name."); + goto out; + } + port = (int)x_json_object_get_number(address, "port"); + if (port <= 0 || port > 65535) { + CORE_LOGF_X(eNSub_Json, eLOG_Error, + ("Invalid JSON {\"addrs[i].port\"} value (%d).", port)); + goto out; + } + + /* SSERV_Info.type <=== addrs[i].meta.serviceType */ + svc_type = x_json_object_dotget_string(address, "meta.serviceType"); + if ( ! svc_type || ! *svc_type) + svc_type = "HTTP"; + + /* Make sure the service type matches an allowed type. */ + ESERV_Type type; + if ( ! SERV_ReadType(svc_type, &type) || + ! (iter->types & type)) + { + CORE_TRACEF(( + "Ignoring endpoint %s:%d with unallowed svc_type '%s'.", + host, port, svc_type)); + continue; + } + CORE_TRACEF(( + "Parsed endpoint %s:%d with allowed svc_type '%s'.", + host, port, svc_type)); + + /* SSERV_Info.mode <=== addrs[i].meta.stateful */ + if (x_json_object_dothas_value_of_type(address, "meta.stateful", + JSONBoolean)) + { + int st = x_json_object_dotget_boolean(address, "meta.stateful"); + if (st == 0) { + stateful = ""; + } else if (st == 1) { + stateful = " S=YES"; + } else { + CORE_LOGF_X(eNSub_Json, eLOG_Error, + ("Invalid JSON {\"addrs[i].meta.stateful\"} value (%d).", + st)); + goto out; + } + } else { + stateful = ""; + } + + /* SSERV_Info.site <=== addrs[i].meta.mode */ + local = "NO"; + priv = ""; + if (x_json_object_dothas_value_of_type(address, "meta.mode", + JSONString)) + { + mode = x_json_object_dotget_string(address, "meta.mode"); + if ( ! mode || ! *mode) { + CORE_LOG_X(eNSub_Json, eLOG_Error, + "Couldn't get JSON {\"addrs[i].meta.mode\"} value."); + goto out; + } + if (strcmp(mode, "L") == 0) { + local = "YES"; + } else if (strcmp(mode, "H") == 0) { + local = "YES"; + priv = " P=YES"; + } else { + CORE_LOGF_X(eNSub_Json, eLOG_Error, + ("Unexpected JSON {\"addrs[i].meta.mode\"} value '%s'.", + mode)); + goto out; + } + } + + /* SSERV_Info.rate <=== addrs[i].meta.rate */ + if (x_json_object_dothas_value_of_type(address, "meta.rate", + JSONNumber)) + { + rate = x_json_object_dotget_number(address, "meta.rate"); + } else { + rate = 0.0; + } + /* verify magnitude */ + if (rate < 0.0 || rate > 10000.0) { + CORE_LOGF_X(eNSub_Json, eLOG_Error, + ("Unexpected JSON {\"addrs[i].meta.rate\"} value '%lf'.", + rate)); + goto out; + } + /* format with 3-digit precsion for standby; else 2-digits */ + char rate_str[12]; + sprintf(rate_str, "%.*lf", + (rate < LBSM_STANDBY_THRESHOLD ? 3 : 2), rate); + + /* SSERV_Info.time <=== addrs[i].meta.expires */ + time_t tt_now = time(0); + TNCBI_Time timeval = (TNCBI_Time)(tt_now + LBSM_DEFAULT_TIME); + if (x_json_object_dothas_value_of_type(address, "meta.expires", + JSONString)) + { + timeval = s_ParseExpires(tt_now, + x_json_object_dotget_string(address, "meta.expires")); + if ( ! timeval) + goto out; + } else { + static void* s_Once = 0; + if (CORE_Once(&s_Once)) { + CORE_LOGF_X(eNSub_Json, eLOG_Warning, + ("Missing JSON {\"addrs[i].meta.expires\"} - " + "using current time (" FMT_TIME_T + ") + default expiration " + "(%u) = %u", tt_now, LBSM_DEFAULT_TIME, timeval)); + } + } + + /* SSERV_Info.mime_t + SSERV_Info.mime_s + SSERV_Info.mime_e <=== addrs[i].meta.contentType */ + ctype = x_json_object_dotget_string(address, "meta.contentType"); + cpfx = (ctype ? " C=" : ""); + ctype = (ctype ? ctype : ""); + + /* SSERV_Info.extra <=== addrs[i].meta.extra */ + extra = x_json_object_dotget_string(address, "meta.extra"); + if ( ! extra || ! *extra) { + if (strcmp(svc_type, "HTTP") == 0) { + CORE_LOG_X(eNSub_Json, eLOG_Error, + "Namerd API did not return a path in meta.extra " + "JSON for an HTTP type service"); + extra = "/ERROR/namerd/API/did/not/return/a/path/in" + "/meta.extra/JSON/for/an/HTTP/type/service"; + } else if (strcmp(svc_type, "NCBID") == 0) { + CORE_LOG_X(eNSub_Json, eLOG_Warning, + "Namerd API did not return args in meta.extra " + "JSON for an NCBID type service"); + extra = "''"; + } else { + extra = ""; + } + } + + /* Prepare description */ + size_t length; + length = strlen(descr_fmt) + strlen(svc_type) + strlen(host) + + 5 /*length of port*/ + strlen(extra) + strlen(cpfx) + + strlen(ctype) + strlen(local) + strlen(priv) + + strlen(rate_str) + strlen(stateful) + + 20/*length of timeval*/; + server_description = (char*)malloc(sizeof(char) * length); + if ( ! server_description) { + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, + "Couldn't alloc for server description."); + goto out; + } + sprintf(server_description, descr_fmt, svc_type, host, + port, extra, cpfx, ctype, local, priv, rate_str, stateful, + timeval); + + /* Parse description into SSERV_Info */ + CORE_TRACEF( + ("Parsing server description: '%s'", server_description)); + SSERV_Info* info = SERV_ReadInfoEx(server_description, + iter->name, 0); + /*CORE_TRACEF( + ("Parsed server description; expires=%u", info->time));*/ + + if ( ! info) { + CORE_LOGF_X(eNSub_BadData, eLOG_Warning, + ("Unable to add server info with description '%s'.", + server_description)); + free(server_description); + continue; + } + free(server_description); + + /* Add new info to collection */ + if (s_AddServerInfo(data, info)) { + retval = 1; /* at least one info added */ + /* Note: successful s_AddServerInfo() frees 'info' */ + } else { + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, + "Unable to add server info."); + free(info); /* not freed by failed s_AddServerInfo() */ + goto out; + } + } + + /* Filter out standby endpoints */ + s_RemoveStandby(data); + } + +out: + if (response) free(response); + if (root_value) x_json_value_free(root_value); + TOUT("s_ParseResponse()"); + return retval; +} + + +/* Parse buffer and extract DTab-Local header, if present. */ +static char* s_GetDtabHeaderFromBuf(const char* buf) +{ + char* start = (char*)buf; + char* end; + char* dup_hdr; + + TIN1("s_GetDtabHeaderFromBuf(\"%s\")", buf ? buf : ""); + + if (start && strncasecmp(start, DTAB_HDR_FIELD_NAME ":", + sizeof(DTAB_HDR_FIELD_NAME) + 1/*':'*/ - 1/*'\0'*/) == 0) + { + /* advance start past name, colon, and any whitespace */ + start += sizeof(DTAB_HDR_FIELD_NAME) + 1; + while (*start == ' ' || *start == '\t') ++start; + + /* advance end to \0 or eol (excluding eol) */ + end = start; + while (*end && *end != '\r' && *end != '\n') ++end; + + /* clone the header value */ + dup_hdr = (char*)malloc(end - start + 1); + if ( ! dup_hdr) { + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, + "Couldn't alloc for dtab header value."); + TOUT("s_GetDtabHeaderFromBuf() -- bad alloc"); + return NULL; + } + memcpy(dup_hdr, start, end - start); + dup_hdr[end - start] = NIL; + TOUT1("s_GetDtabHeaderFromBuf() -- got dtab header \"%s\"", dup_hdr); + return dup_hdr; + } + + TOUT("s_GetDtabHeaderFromBuf()"); + return NULL; +} + + +/* If there's a dtab in the user header, add it to the caller's dtab. */ +static void s_UpdateDtabFromUserHeader(char** dtab_p, int* success_p, + SConnNetInfo* net_info) +{ + char* dtab = NULL; + + TIN2("s_UpdateDtabFromUserHeader(\"%s\") -- success=%d", + net_info->http_user_header ? net_info->http_user_header : "", + *success_p); + + if ( ! *success_p) { + TOUT("s_UpdateDtabFromUserHeader() -- prior no success"); + return; + } + + dtab = s_GetDtabHeaderFromBuf(net_info->http_user_header); + if (dtab) { + /*ConnNetInfo_DeleteUserHeader(net_info, DTAB_HDR_FIELD_NAME);*/ + s_UpdateDtab(dtab_p, dtab, success_p); + free(dtab); + } + + TOUT("s_UpdateDtabFromUserHeader()"); +} + + +/* If there's a dtab in the registry, add it to the caller's dtab. */ +static void s_UpdateDtabFromRegistry(char** dtab_p, int* success_p, + const char* service) +{ + char val[MAX_QRY_STR_LEN + 1]; + + TIN2("s_UpdateDtabFromRegistry(\"%s\") -- success=%d", + service ? service : "", *success_p); + + if ( ! *success_p) { + TOUT("s_UpdateDtabFromRegistry() -- prior no success"); + return; + } + + if ( ! ConnNetInfo_GetValue(REG_NAMERD_SECTION, + REG_NAMERD_DTAB_KEY, val, MAX_QRY_STR_LEN, + REG_NAMERD_DTAB_DEF)) + { + *success_p = 0; + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, + "Couldn't alloc for dtab from registry."); + TOUT("s_UpdateDtabFromRegistry() -- bad alloc"); + return; + } + + s_UpdateDtab(dtab_p, val, success_p); + + TOUT("s_UpdateDtabFromRegistry()"); +} + + +/* If net_info->http_user_header contains a DTab-Local header, that value + * must be moved to net_info->args, which in turn populates the "dtab" + * parameter in the HTTP query string. It must not be in a header because + * if it was, it would apply to the namerd service itself, not the requested + * service. Instead, the namerd service uses the dtab param for resolution. + * + * Thus, this function builds the dtab param from (highest priority first): + * * CONN_DTAB environment variable + * * DTab-Local header in net_info->http_user_header + */ +static int/*bool*/ s_ProcessDtab(SConnNetInfo* net_info) +{ +#define DTAB_ARGS_SEP "&dtab=" + int/*bool*/ success = 1; + char* dtab = NULL; + + TIN("s_ProcessDtab()"); + + /* Dtab precedence (highest first): registry > user_header */ + s_UpdateDtabFromRegistry(&dtab, &success, net_info->svc); + s_UpdateDtabFromUserHeader(&dtab, &success, net_info); + + if (success && dtab) { + if (strlen(net_info->args) + strlen(DTAB_ARGS_SEP) + + strlen(dtab) < MAX_ARGS_LEN) + { + strcat(net_info->args, DTAB_ARGS_SEP); + strcat(net_info->args, dtab); + } else { + CORE_LOG_X(eNSub_TooLong, eLOG_Error, "Dtab too long."); + success = 0; + } + } + + if (dtab) free(dtab); + + TOUT("s_ProcessDtab()"); + return success; +#undef DTAB_ARGS_SEP +} + + +static EHTTP_HeaderParse s_ParseHeader(const char* header, + void* iter, + int server_error) +{ + struct SNAMERD_Data* data = (struct SNAMERD_Data*)((SERV_ITER) iter)->data; + int code = 0/*success code if any*/; + + TIN1("s_ParseHeader(\"%s\")", header); + + if (server_error == 400 || server_error == 403 || server_error == 404) { + data->fail = 1/*true*/; + } else if (sscanf(header, "%*s %d", &code) < 1) { + data->eof = 1/*true*/; + TOUT("s_ParseHeader() -- eof=true"); + return eHTTP_HeaderError; + } + + /* check for empty document */ + if (code == 204) + data->eof = 1/*true*/; + + TOUT("s_ParseHeader()"); + return eHTTP_HeaderSuccess; +} + + +static int/*bool*/ s_Adjust(SConnNetInfo* net_info, + void* iter, + unsigned int unused) +{ + struct SNAMERD_Data* data = (struct SNAMERD_Data*)((SERV_ITER) iter)->data; + return data->fail ? 0/*no more tries*/ : 1/*may try again*/; +} + + +static int/*bool*/ s_Resolve(SERV_ITER iter) +{ + struct SNAMERD_Data* data = (struct SNAMERD_Data*) iter->data; + SConnNetInfo* net_info = data->net_info; + CONNECTOR c = NULL; + CONN conn = NULL; + int/*bool*/ retval = 0; + + TIN("s_Resolve()"); + assert( ! (data->eof | data->fail)); + assert( !! net_info->stateless == !! iter->stateless); + + /* Handle DTAB, if present. */ + s_ProcessDtab(net_info); + + /* Create connector and connection, and fetch and parse the response. */ + if (s_CONN_Create(iter, &c, &conn) == eIO_Success) { + retval = s_ParseResponse(iter, conn); + } + s_CONN_Destroy(&c, &conn); + + TOUT("s_Resolve()"); + return retval; +} + + +static int/*bool*/ s_IsUpdateNeeded(TNCBI_Time now, struct SNAMERD_Data *data) +{ + /* Note: Because the namerd API does not supply rate data for many + of the services it resolves, a rate-based algorithm can't be used. + It could end up in an infinite loop because the total could be zero, + thus causing immediate repeated updates of the same server, forever. + Therefore, use a simpler algorithm that is just: + An update is needed if: + * there are no candidates; or + * any candidates are expired. + */ + int any_expired = 0, i; + + for (i = (int)data->n_cand - 1; i >= 0; --i) { + const SSERV_Info* info = data->cand[i].info; + if (info->time < now) { +#if defined(_DEBUG) && ! defined(NDEBUG) + TNCBI_Time tnow = (TNCBI_Time)time(0); + CORE_TRACE("Endpoint expired:"); + CORE_TRACEF(( + " info->time (%u) < iter->time (%u) now (%u)", + info->time, now, tnow)); + CORE_TRACEF(( + " iter->time - info->time (%d) now - iter->time (%d)", + now - info->time, tnow - now)); +#endif + any_expired = 1; + s_RemoveCand(data, (size_t)i, 1); + } + } + + return any_expired || data->n_cand == 0; +} + + +static int/*bool*/ s_Update(SERV_ITER iter, const char* text, int code) +{ + /*struct SNAMERD_Data* data = (struct SNAMERD_Data*) iter->data;*/ + int retval = 0; + + TIN2("s_Update(\"%s\", %d)", text ? text : "", code); + + TOUT1("s_Update() -- %supdated", retval ? "" : "not "); + return retval; +} + + +static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info) +{ + struct SNAMERD_Data* data = (struct SNAMERD_Data*) iter->data; + SSERV_Info* info; + size_t n; + + TIN("s_GetNextInfo()"); + assert(data); + + if (data->n_cand < 1 && data->done) { + data->done = 0; + TOUT("s_GetNextInfo() -- no cand"); + return NULL; + } + + if (s_IsUpdateNeeded(iter->time, data)) { + if ( ! (data->eof | data->fail)) + s_Resolve(iter); + } + + /* No need to load-balance - that's already been done by the namerd service. + * Just take the first one. + */ + n = 0; + info = (SSERV_Info*) data->cand[n].info; + info->rate = data->cand[n].status; + + /* Remove returned info */ + s_RemoveCand(data, n, 0); + + if (host_info) + *host_info = NULL; + + TOUT("s_GetNextInfo()"); + return info; +} + + +static void s_Reset(SERV_ITER iter) +{ + struct SNAMERD_Data* data = (struct SNAMERD_Data*) iter->data; + + TIN("s_Reset()"); + + if (data) { + data->eof = data->fail = data->done = 0/*false*/; + if (data->cand) { + size_t i; + assert(data->n_cand <= data->a_cand); + for (i = 0; i < data->n_cand; ++i) + free((void*) data->cand[i].info); + data->n_cand = 0; + } + } + + TOUT("s_Reset()"); +} + + +static void s_Close(SERV_ITER iter) +{ + struct SNAMERD_Data* data = (struct SNAMERD_Data*) iter->data; + + TIN("s_Close()"); + + /* Make sure s_Reset() has been called. */ + assert(data); + if (data->n_cand) + s_Reset(iter); + assert( ! data->n_cand); /* s_Reset() clears candidates count */ + + if (data->cand) + free(data->cand); + + ConnNetInfo_Destroy(data->net_info); + free(data); + iter->data = NULL; + + TOUT("s_Close()"); +} + + +/*********************************************************************** + * EXTERNAL + ***********************************************************************/ + +extern const SSERV_VTable* SERV_NAMERD_Open(SERV_ITER iter, + const SConnNetInfo* net_info, + SSERV_Info** info) +{ + struct SNAMERD_Data* data; + char namerd_env[32]; + + TIN1("SERV_NAMERD_Open(\"%s\")", iter->name); + + s_Init(); + + assert(iter); + assert(net_info); + + /* Check that service name is provided - otherwise there is nothing to + * search for. */ + if ( ! iter->name) { + CORE_LOG_X(eNSub_BadData, eLOG_Error, + "\"iter->name\" is NULL, not able to continue SERV_NAMERD_Open"); + TOUT("SERV_NAMERD_Open() -- fail"); + return NULL; + } + assert(iter->name); + assert(*iter->name); + + /* Prohibit catalog-prefixed services, e.g. "/lbsm/" */ + if (iter->name[0] == '/') { + CORE_LOGF_X(eNSub_BadData, eLOG_Error, + ("Invalid service name \"%s\" - must not begin with '/'.", + iter->name)); + TOUT("SERV_NAMERD_Open() -- fail"); + return NULL; + } + + /* Check that iter is not a mask. */ + if (iter->ismask) { + CORE_LOG_X(eNSub_BadData, eLOG_Error, + "NAMERD doesn't support masks."); + TOUT("SERV_NAMERD_Open() -- fail"); + return NULL; + } + + if ( ! (data = (struct SNAMERD_Data*) calloc(1, sizeof(*data)))) { + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, + "Could not allocate for SNAMERD_Data."); + TOUT("SERV_NAMERD_Open() -- fail"); + return NULL; + } + iter->data = data; + + if ( ! (data->net_info = ConnNetInfo_Clone(net_info))) { + CORE_LOG_X(eNSub_Alloc, eLOG_Critical, "Couldn't clone net_info."); + s_Close(iter); + TOUT("SERV_NAMERD_Open() -- fail"); + return NULL; + } + + if ( ! ConnNetInfo_SetupStandardArgs(data->net_info, iter->name)) { + CORE_LOG_X(eNSub_BadData, eLOG_Critical, + "Couldn't set up standard args."); + s_Close(iter); + TOUT("SERV_NAMERD_Open() -- fail"); + return NULL; + } + + if (g_NCBI_ConnectRandomSeed == 0) { + g_NCBI_ConnectRandomSeed = iter->time ^ NCBI_CONNECT_SRAND_ADDEND; + srand(g_NCBI_ConnectRandomSeed); + } + + data->net_info->http_proxy_port = s_GetProxyPort(); + data->net_info->req_method = s_GetReqMethod(); + data->net_info->scheme = s_GetScheme(); + data->net_info->port = 0; /* namerd doesn't support a port */ + data->net_info->host[0] = NIL; + data->net_info->path[0] = NIL; + data->net_info->args[0] = NIL; + + if ( ! ConnNetInfo_GetValue(REG_NAMERD_SECTION, + REG_NAMERD_PROXY_HOST_KEY, data->net_info->http_proxy_host, + sizeof(data->net_info->http_proxy_host) - 1, + REG_NAMERD_PROXY_HOST_DEF)) + { + data->net_info->http_proxy_host[0] = NIL; + } + if ( ! ConnNetInfo_GetValue(REG_NAMERD_SECTION, + REG_NAMERD_API_HOST_KEY, data->net_info->host, sizeof(net_info->host)-1, + REG_NAMERD_API_HOST_DEF)) + { + data->net_info->host[0] = NIL; + } + if ( ! ConnNetInfo_GetValue(REG_NAMERD_SECTION, + REG_NAMERD_API_PATH_KEY, data->net_info->path, sizeof(net_info->path)-1, + REG_NAMERD_API_PATH_DEF)) + { + data->net_info->path[0] = NIL; + } + if (ConnNetInfo_GetValue(REG_NAMERD_SECTION, + REG_NAMERD_API_ENV_KEY, namerd_env, sizeof(namerd_env)-1, + REG_NAMERD_API_ENV_DEF)) + { + if (strlen(data->net_info->path) + strlen(namerd_env) < + sizeof(net_info->path) - 2) /* -2 for '/' separator and NIL */ + { + strcat(data->net_info->path, "/"); + strcat(data->net_info->path, namerd_env); + } + } + if ( ! ConnNetInfo_GetValue(REG_NAMERD_SECTION, + REG_NAMERD_API_ARGS_KEY, data->net_info->args, sizeof(net_info->args)-1, + REG_NAMERD_API_ARGS_DEF)) + { + data->net_info->args[0] = NIL; + } else { + strcat(data->net_info->args, iter->name); + } + + if (iter->stateless) + data->net_info->stateless = 1/*true*/; + if ((iter->types & fSERV_Firewall) && ! data->net_info->firewall) + data->net_info->firewall = eFWMode_Adaptive; + + iter->op = &s_op; /*SERV_Update() [from HTTP callback] expects*/ + s_Resolve(iter); + iter->op = NULL; + + if ( ! data->n_cand && (data->fail || + ! (data->net_info->stateless && + data->net_info->firewall))) + { + s_Close(iter); + TOUT("SERV_NAMERD_Open() -- fail"); + return NULL; + } + + /* call GetNextInfo subsequently if info is actually needed */ + if (info) *info = NULL; + + TOUT("SERV_NAMERD_Open()"); + return &s_op; +} + + +extern int SERV_NAMERD_SetConnectorSource(const char* mock_body) +{ + s_Init(); + + if ( ! mock_body || ! *mock_body) { + s_CreateConnector = s_CreateConnectorHttp; + return 1; + } + s_mock_body = mock_body; + s_CreateConnector = s_CreateConnectorMemory; + return 1; +} diff --git a/c++/src/connect/ncbi_namerd.h b/c++/src/connect/ncbi_namerd.h new file mode 100644 index 00000000..c988e1cb --- /dev/null +++ b/c++/src/connect/ncbi_namerd.h @@ -0,0 +1,55 @@ +#ifndef CONNECT___NAMERD__H +#define CONNECT___NAMERD__H + +/* $Id: ncbi_namerd.h 533505 2017-04-17 15:01:36Z mcelhany $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: David McElhany + * + * File Description: + * Low-level API to resolve NCBI service name to the server meta-address + * with the use of NAMERD. + * + */ + +#include "ncbi_servicep.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +extern const SSERV_VTable* SERV_NAMERD_Open(SERV_ITER iter, + const SConnNetInfo* net_info, + SSERV_Info** info); + +extern int SERV_NAMERD_SetConnectorSource(const char* mock_body); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* CONNECT___NAMERD__H */ diff --git a/c++/src/connect/ncbi_once.h b/c++/src/connect/ncbi_once.h new file mode 100644 index 00000000..4a92e589 --- /dev/null +++ b/c++/src/connect/ncbi_once.h @@ -0,0 +1,63 @@ +#ifndef CONNECT___NCBI_ONCE__H +#define CONNECT___NCBI_ONCE__H + +/* $Id: ncbi_once.h 537475 2017-05-31 20:48:22Z lavr $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Anton Lavrentiev + * + * File Description: + * Once time setter CORE_Once + * + */ + +#include "ncbi_config.h" +#ifdef NCBI_CXX_TOOLKIT +# include +#endif /*NCBI_CXX_TOOLKIT*/ + + +/** Return non-zero (true) if "*once" had a value of NULL, and set the value to + * non-NULL regardless (best effort: atomically). Return 0 (false) otherwise. + */ +#ifdef NCBI_CXX_TOOLKIT +# define CORE_Once(once) (!NCBI_SwapPointers((once), (void*) 1)) +#else +# ifdef __GNUC__ +inline +# endif /*__GNUC__*/ +static int/*bool*/ CORE_Once(void** once) +{ + /* poor man's solution */ + if (!*once) { + *once = (void*) 1; + return 1/*true*/; + } else + return 0/*false*/; +} +#endif /*NCBI_CXX_TOOLKIT*/ + + +#endif /* CONNECT___NCBI_ONCE__H */ diff --git a/c++/src/connect/ncbi_priv.c b/c++/src/connect/ncbi_priv.c index 87cd30c3..9bc3368c 100644 --- a/c++/src/connect/ncbi_priv.c +++ b/c++/src/connect/ncbi_priv.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_priv.c 507875 2016-07-21 21:24:44Z lavr $ +/* $Id: ncbi_priv.c 534371 2017-04-26 19:30:49Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -42,6 +42,7 @@ #include #include + /* GLOBALS */ TCORE_Set g_CORE_Set = 0; MT_LOCK g_CORE_MT_Lock = &g_CORE_MT_Lock_default; @@ -58,6 +59,7 @@ FMonkeyRecv g_MONKEY_Recv = 0; FMonkeyConnect g_MONKEY_Connect = 0; FMonkeyPoll g_MONKEY_Poll = 0; FMonkeyClose g_MONKEY_Close = 0; +FSockHasSocket g_MONKEY_SockHasSocket = 0; #endif /*NCBI_MONKEY*/ diff --git a/c++/src/connect/ncbi_priv.h b/c++/src/connect/ncbi_priv.h index 72eeb088..f6ab2f73 100644 --- a/c++/src/connect/ncbi_priv.h +++ b/c++/src/connect/ncbi_priv.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_PRIV__H #define CONNECT___NCBI_PRIV__H -/* $Id: ncbi_priv.h 507875 2016-07-21 21:24:44Z lavr $ +/* $Id: ncbi_priv.h 537410 2017-05-31 16:20:20Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -55,6 +55,9 @@ * */ + +//#define NCBI_MONKEY + #include "ncbi_assert.h" #include #ifdef NCBI_MONKEY @@ -96,13 +99,14 @@ NCBI_C_DEFINE_ERRCODE_X(Connect_Util, 303, 9); NCBI_C_DEFINE_ERRCODE_X(Connect_LBSM, 304, 33); NCBI_C_DEFINE_ERRCODE_X(Connect_FTP, 305, 13); NCBI_C_DEFINE_ERRCODE_X(Connect_SMTP, 306, 33); -NCBI_C_DEFINE_ERRCODE_X(Connect_HTTP, 307, 23); -NCBI_C_DEFINE_ERRCODE_X(Connect_Service, 308, 9); +NCBI_C_DEFINE_ERRCODE_X(Connect_HTTP, 307, 24); +NCBI_C_DEFINE_ERRCODE_X(Connect_Service, 308, 11); NCBI_C_DEFINE_ERRCODE_X(Connect_HeapMgr, 309, 33); - /* 310 unused */ +NCBI_C_DEFINE_ERRCODE_X(Connect_LBOS, 310, 600); /*safe upper bound*/ NCBI_C_DEFINE_ERRCODE_X(Connect_Mghbn, 311, 16); NCBI_C_DEFINE_ERRCODE_X(Connect_Crypt, 312, 5); -NCBI_C_DEFINE_ERRCODE_X(Connect_LocalNet, 313, 4); +NCBI_C_DEFINE_ERRCODE_X(Connect_LocalIP, 313, 5); +NCBI_C_DEFINE_ERRCODE_X(Connect_Namerd, 314, 9); /** Make one identifier from 2 parts */ #define NCBI_C_CONCAT_IDENTIFIER(prefix, postfix) prefix##postfix @@ -209,7 +213,7 @@ extern NCBI_XCONNECT_EXPORT LOG g_CORE_Log; do { \ ELOG_Level _xx_level = (_level); \ if (g_CORE_Log || _xx_level == eLOG_Fatal) { \ - SLOG_Handler _mess; \ + SLOG_Message _mess; \ _mess.dynamic = _dynamic; \ _mess.message = NcbiMessagePlusError(&_mess.dynamic, \ (_message), \ @@ -244,7 +248,7 @@ extern NCBI_XCONNECT_EXPORT LOG g_CORE_Log; extern NCBI_XCONNECT_EXPORT const char* g_CORE_Sprintf(const char* fmt, ...) #ifdef __GNUC__ - __attribute__((format(printf, 1, 2))) + __attribute__((format(printf,1,2))) #endif ; @@ -365,6 +369,7 @@ typedef const char* (*FNcbiGetRequestDtab)(void); extern NCBI_XCONNECT_EXPORT FNcbiGetRequestDtab g_CORE_GetRequestDtab; + /****************************************************************************** * Miscellanea */ @@ -378,6 +383,7 @@ extern NCBI_XCONNECT_EXPORT FNcbiGetRequestDtab g_CORE_GetRequestDtab; #endif /*__GNUC__*/ + /****************************************************************************** * NCBI Crazy Monkey support */ @@ -387,21 +393,21 @@ extern NCBI_XCONNECT_EXPORT FNcbiGetRequestDtab g_CORE_GetRequestDtab; * some types have to be pre-selected based on current OS */ # ifdef NCBI_OS_MSWIN -# define MONKEY_RETTYPE int -# define MONKEY_SOCKTYPE SOCKET -# define MONKEY_DATATYPE char* -# define MONKEY_LENTYPE int +# define MONKEY_RETTYPE int +# define MONKEY_SOCKTYPE SOCKET +# define MONKEY_DATATYPE char* +# define MONKEY_LENTYPE int # define MONKEY_SOCKLENTYPE int -# define MONKEY_STDCALL __stdcall /* in Windows, socket functions have - prototypes with __stdcall */ +# define MONKEY_STDCALL __stdcall /*in Windows, socket functions + have prototypes with __stdcall*/ # else -# define MONKEY_RETTYPE ssize_t -# define MONKEY_SOCKTYPE int -# define MONKEY_DATATYPE void* -# define MONKEY_LENTYPE size_t +# define MONKEY_RETTYPE ssize_t +# define MONKEY_SOCKTYPE int +# define MONKEY_DATATYPE void* +# define MONKEY_LENTYPE size_t # define MONKEY_SOCKLENTYPE socklen_t -# define MONKEY_STDCALL /* empty*/ -# endif /* NCBI_OS_MSWIN */ +# define MONKEY_STDCALL /*empty*/ +# endif /*NCBI_OS_MSWIN*/ /****************************************************************************** * Socket functions via Crazy Monkey @@ -422,16 +428,20 @@ typedef int(MONKEY_STDCALL *FMonkeyConnect)(MONKEY_SOCKTYPE sock, const struct sockaddr* name, MONKEY_SOCKLENTYPE namelen); -typedef int /* bool */ (*FMonkeyPoll) (size_t* n, - void* /*SSOCK_Poll[]* */polls, +typedef int /*bool*/ (*FMonkeyPoll) (size_t* n, + void* /*SSOCK_Poll[]**/polls, EIO_Status* ret_status); typedef void (*FMonkeyClose) (SOCKET sock); +typedef void (*FSockHasSocket)(void* /* SOCK* */ sock, + MONKEY_SOCKTYPE socket); + extern NCBI_XCONNECT_EXPORT FMonkeySend g_MONKEY_Send; extern NCBI_XCONNECT_EXPORT FMonkeyRecv g_MONKEY_Recv; extern NCBI_XCONNECT_EXPORT FMonkeyPoll g_MONKEY_Poll; extern NCBI_XCONNECT_EXPORT FMonkeyConnect g_MONKEY_Connect; extern NCBI_XCONNECT_EXPORT FMonkeyClose g_MONKEY_Close; +extern NCBI_XCONNECT_EXPORT FSockHasSocket g_MONKEY_SockHasSocket; #endif /*NCBI_MONKEY*/ diff --git a/c++/src/connect/ncbi_sendmail.c b/c++/src/connect/ncbi_sendmail.c index 91ce7cf2..fe98c53c 100644 --- a/c++/src/connect/ncbi_sendmail.c +++ b/c++/src/connect/ncbi_sendmail.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_sendmail.c 488581 2016-01-01 00:39:45Z lavr $ +/* $Id: ncbi_sendmail.c 534370 2017-04-26 19:29:20Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -41,15 +41,15 @@ #define NCBI_USE_ERRCODE_X Connect_SMTP -#define MX_MAGIC_COOKIE 0xBA8ADEDA -#define MX_CRLF "\r\n" +#define MX_SENDMAIL_MAGIC 0xBA8ADEDA +#define MX_CRLF "\r\n" -#define SMTP_READERR -1 /* Read error from socket */ -#define SMTP_READTMO -2 /* Read timed out */ -#define SMTP_RESPERR -3 /* Cannot read response prefix */ -#define SMTP_NOCODE -4 /* No response code detected (letters?) */ -#define SMTP_BADCODE -5 /* Response code doesn't match in lines */ -#define SMTP_BADRESP -6 /* Malformed response */ +#define SMTP_READERR -1 /* Read error from socket */ +#define SMTP_READTMO -2 /* Read timed out */ +#define SMTP_RESPERR -3 /* Cannot read response prefix */ +#define SMTP_NOCODE -4 /* No response code detected (letters?) */ +#define SMTP_BADCODE -5 /* Response code doesn't match in lines */ +#define SMTP_BADRESP -6 /* Malformed response */ /* Read SMTP response from the socket. @@ -59,9 +59,10 @@ * read error or protocol violations). * Return 0 in case of a call error. */ -static int s_SockRead(SOCK sock, char* response, size_t max_response_len) +static int s_SockRead(SOCK sock, char* response, size_t max_response_len, + int/*bool*/ savecode) { - int/*bool*/ done = 0; + int/*bool*/ done = 0/*false*/; size_t n = 0; int code = 0; @@ -92,6 +93,14 @@ static int s_SockRead(SOCK sock, char* response, size_t max_response_len) code = (int) strtol(buf, &e, 10); if (errno || code <= 0 || e != buf + 3) return SMTP_NOCODE; + if (savecode) { + n = 3; + if (n > max_response_len) + n = max_response_len; + memcpy(response, buf, n); + if (n < max_response_len) + response[n++] = ' '; + } } else if (code != atoi(buf)) return SMTP_BADCODE; } else @@ -103,7 +112,7 @@ static int s_SockRead(SOCK sock, char* response, size_t max_response_len) if (status == eIO_Closed) { if (n < max_response_len) response[n++] = '\n'; - done = 1; + done = 1/*true*/; break; } if (!m) @@ -121,7 +130,6 @@ static int s_SockRead(SOCK sock, char* response, size_t max_response_len) response[n] = ' '; } else { *response = '\0'; - assert(done); break; } } while (!done); @@ -132,9 +140,10 @@ static int s_SockRead(SOCK sock, char* response, size_t max_response_len) static int/*bool*/ s_SockReadResponse(SOCK sock, int code, int alt_code, - char* buf, size_t buf_size) + char* buf, size_t buf_size, + int/*bool*/ savecode) { - int c = s_SockRead(sock, buf, buf_size); + int c = s_SockRead(sock, buf, buf_size, savecode); if (c <= 0) { const char* message = 0; switch (c) { @@ -163,7 +172,7 @@ static int/*bool*/ s_SockReadResponse(SOCK sock, int code, int alt_code, } assert(message); strncpy0(buf, message, buf_size - 1); - } else if (c == code || (alt_code && c == alt_code)) + } else if (!code || c == code || (alt_code && c == alt_code)) return 1/*success*/; return 0/*failure*/; } @@ -312,7 +321,7 @@ extern SSendMailInfo* SendMailInfo_InitEx(SSendMailInfo* info, info->mx_host = s_MxHost; info->mx_port = s_MxPort; info->mx_options = 0; - info->magic_cookie = MX_MAGIC_COOKIE; + info->magic = MX_SENDMAIL_MAGIC; } return info; } @@ -338,8 +347,13 @@ extern const char* CORE_SendMail(const char* to, sock = 0; \ } \ CORE_LOGF_X(subcode, eLOG_Error, ("[SendMail] %s", reason)); \ - if (!sock) \ + if (!sock) { \ + if (info->mx_options & fSendMail_ExtendedErrInfo) { \ + char* retval = strdup(reason); \ + return retval ? retval : ""; \ + } \ return reason; \ + } \ /*NOTREACHED*/ \ } while (0) @@ -351,8 +365,21 @@ extern const char* CORE_SendMail(const char* to, } \ CORE_LOGF_X(subcode, eLOG_Error, \ ("[SendMail] %s: %s", reason, explanation)); \ - if (!sock) \ + if (!sock) { \ + if (info->mx_options & fSendMail_ExtendedErrInfo) { \ + size_t len = strlen(reason); \ + char* retval = (char*) malloc(len + 3 \ + + strlen(explanation)); \ + if (!retval) \ + return ""; \ + memcpy(retval, reason, len); \ + retval[len++] = ':'; \ + retval[len++] = ' '; \ + strcpy(retval + len, explanation); \ + return retval; \ + } \ return reason; \ + } \ /*NOTREACHED*/ \ } while (0) @@ -361,7 +388,8 @@ static const char* s_SendRcpt(SOCK sock, const char* to, char buf[], size_t buf_size, const char what[], const char write_error[], - const char proto_error[]) + const char proto_error[], + const SSendMailInfo* info) { char c; while ((c = *to++) != '\0') { @@ -399,8 +427,10 @@ static const char* s_SendRcpt(SOCK sock, const char* to, !s_SockWrite(sock, ">" MX_CRLF, sizeof(MX_CRLF))) { SENDMAIL_RETURN(4, write_error); } - if (!s_SockReadResponse(sock, 250, 251, buf, buf_size)) + if (!s_SockReadResponse(sock, 250, 251, buf, buf_size, + info->mx_options & fSendMail_ExtendedErrInfo)){ SENDMAIL_RETURN2(5, proto_error, buf); + } if (!c) break; } @@ -428,13 +458,15 @@ static size_t s_FromSize(const SSendMailInfo* info) } -#define SENDMAIL_SENDRCPT(what, list, buffer) \ - s_SendRcpt(sock, list, buffer, sizeof(buffer), what, \ - "Write error in RCPT (" what ") command", \ - "Protocol error in RCPT (" what ") command") +#define SENDMAIL_SENDRCPT(what, list, buffer) \ + s_SendRcpt(sock, list, buffer, sizeof(buffer), what, \ + "Write error in RCPT (" what ") command", \ + "Protocol error in RCPT (" what ") command", \ + info) -#define SENDMAIL_READ_RESPONSE(code, altcode, buffer) \ - s_SockReadResponse(sock, code, altcode, buffer, sizeof(buffer)) +#define SENDMAIL_READ_RESPONSE(code, buffer) \ + s_SockReadResponse(sock, code, 0, buffer, sizeof(buffer), \ + info->mx_options & fSendMail_ExtendedErrInfo) extern const char* CORE_SendMailEx(const char* to, @@ -451,8 +483,8 @@ extern const char* CORE_SendMailEx(const char* to, SOCK sock = 0; info = uinfo ? uinfo : SendMailInfo_Init(&ainfo); - if (info->magic_cookie != MX_MAGIC_COOKIE) - SENDMAIL_RETURN(6, "Invalid magic cookie"); + if (info->magic != MX_SENDMAIL_MAGIC) + SENDMAIL_RETURN(6, "SSendMailInfo inited improperly: invalid magic"); if ((!to || !*to) && (!info->cc || !*info->cc) && @@ -473,7 +505,7 @@ extern const char* CORE_SendMailEx(const char* to, SOCK_SetTimeout(sock, eIO_Close, &info->mx_timeout); /* Follow the protocol conversation, RFC821 */ - if (!SENDMAIL_READ_RESPONSE(220, 0, buffer)) + if (!SENDMAIL_READ_RESPONSE(220, buffer)) SENDMAIL_RETURN2(9, "Protocol error in connection init", buffer); if ((!(info->mx_options & fSendMail_StripNonFQDNHost) @@ -486,7 +518,7 @@ extern const char* CORE_SendMailEx(const char* to, !s_SockWrite(sock, MX_CRLF, sizeof(MX_CRLF)-1)) { SENDMAIL_RETURN(11, "Write error in HELO command"); } - if (!SENDMAIL_READ_RESPONSE(250, 0, buffer)) + if (!SENDMAIL_READ_RESPONSE(250, buffer)) SENDMAIL_RETURN2(12, "Protocol error in HELO command", buffer); if (!s_SockWrite(sock, "MAIL FROM: <", 12) || @@ -494,7 +526,7 @@ extern const char* CORE_SendMailEx(const char* to, !s_SockWrite(sock, ">" MX_CRLF, sizeof(MX_CRLF))) { SENDMAIL_RETURN(13, "Write error in MAIL command"); } - if (!SENDMAIL_READ_RESPONSE(250, 0, buffer)) + if (!SENDMAIL_READ_RESPONSE(250, buffer)) SENDMAIL_RETURN2(14, "Protocol error in MAIL command", buffer); if (to && *to) { @@ -517,7 +549,7 @@ extern const char* CORE_SendMailEx(const char* to, if (!s_SockWrite(sock, "DATA" MX_CRLF, 4 + sizeof(MX_CRLF)-1)) SENDMAIL_RETURN(15, "Write error in DATA command"); - if (!SENDMAIL_READ_RESPONSE(354, 0, buffer)) + if (!SENDMAIL_READ_RESPONSE(354, buffer)) SENDMAIL_RETURN2(16, "Protocol error in DATA command", buffer); (void) SOCK_SetCork(sock, eOn); @@ -598,12 +630,13 @@ extern const char* CORE_SendMailEx(const char* to, assert(sizeof(buffer) > sizeof(MX_CRLF) && sizeof(MX_CRLF) >= 3); + status = eIO_Timeout; if (info->header && *info->header) { size_t n = 0, m = strlen(info->header); int/*bool*/ newline = 0/*false*/; while (n < m) { size_t k = 0; - if (SOCK_Wait(sock, eIO_Read, &zero) != eIO_Timeout) + if ((status = SOCK_Wait(sock, eIO_Read, &zero)) != eIO_Timeout) break; while (k < sizeof(buffer) - sizeof(MX_CRLF)) { if (info->header[n] == '\n') { @@ -622,12 +655,20 @@ extern const char* CORE_SendMailEx(const char* to, if (!s_SockWrite(sock, buffer, k)) SENDMAIL_RETURN(21, "Write error while sending custom header"); } - if (n < m) - SENDMAIL_RETURN(22, "Header write error"); + if (n < m) { + const char* error = "Custom header write error"; + assert(status != eIO_Timeout); + if (status != eIO_Success) + strncpy0(buffer, IO_StatusStr(status), sizeof(buffer) - 1); + else if (SENDMAIL_READ_RESPONSE(0, buffer)) + error = "Spurious response while writing custom header"; + SENDMAIL_RETURN2(22, error, buffer); + } if (!newline && !s_SockWrite(sock, MX_CRLF, sizeof(MX_CRLF)-1)) - SENDMAIL_RETURN(23, "Write error while finalizing custom header"); + SENDMAIL_RETURN(23, "Write error in finalizing custom header"); } + assert(status == eIO_Timeout); if (body) { size_t n = 0, m = info->body_size ? info->body_size : strlen(body); int/*bool*/ newline = 0/*false*/; @@ -637,7 +678,7 @@ extern const char* CORE_SendMailEx(const char* to, } while (n < m) { size_t k = 0; - if (SOCK_Wait(sock, eIO_Read, &zero) != eIO_Timeout) + if ((status = SOCK_Wait(sock, eIO_Read, &zero)) != eIO_Timeout) break; while (k < sizeof(buffer) - sizeof(MX_CRLF)) { if (body[n] == '\n') { @@ -661,8 +702,15 @@ extern const char* CORE_SendMailEx(const char* to, if (!s_SockWrite(sock, buffer, k)) SENDMAIL_RETURN(25, "Write error while sending message body"); } - if (n < m) - SENDMAIL_RETURN(26, "Body write error"); + if (n < m) { + const char* error = "Message body write error"; + assert(status == eIO_Timeout); + if (status != eIO_Success) + strncpy0(buffer, IO_StatusStr(status), sizeof(buffer) - 1); + else if (SENDMAIL_READ_RESPONSE(0, buffer)) + error = "Spurious response while writing message body"; + SENDMAIL_RETURN2(26, error, buffer); + } if ((!newline && m && !s_SockWrite(sock,MX_CRLF,sizeof(MX_CRLF)-1)) || !s_SockWrite(sock, "." MX_CRLF, sizeof(MX_CRLF))) { SENDMAIL_RETURN(27, "Write error while finalizing message body"); @@ -672,12 +720,12 @@ extern const char* CORE_SendMailEx(const char* to, (void) SOCK_SetCork(sock, eOff); - if (!SENDMAIL_READ_RESPONSE(250, 0, buffer)) + if (!SENDMAIL_READ_RESPONSE(250, buffer)) SENDMAIL_RETURN2(29, "Protocol error in sending message", buffer); if (!s_SockWrite(sock, "QUIT" MX_CRLF, 4 + sizeof(MX_CRLF)-1)) SENDMAIL_RETURN(30, "Write error in QUIT command"); - if (!SENDMAIL_READ_RESPONSE(221, 0, buffer)) + if (!SENDMAIL_READ_RESPONSE(221, buffer)) SENDMAIL_RETURN2(31, "Protocol error in QUIT command", buffer); SOCK_Close(sock); diff --git a/c++/src/connect/ncbi_server_info.c b/c++/src/connect/ncbi_server_info.c index 542fe63b..a6af489b 100644 --- a/c++/src/connect/ncbi_server_info.c +++ b/c++/src/connect/ncbi_server_info.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_server_info.c 507385 2016-07-18 22:38:48Z lavr $ +/* $Id: ncbi_server_info.c 548391 2017-10-13 14:22:34Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -43,34 +43,52 @@ #endif /*fabs*/ #define fabs(v) ((v) < 0.0 ? -(v) : (v)) -#define MAX_IP_ADDR_LEN 16 /*sizeof("255.255.255.255")*/ +#define MAX_IP_ADDR_LEN 80 /*IPv6 compatible*/ + +#define SERV_VHOSTABLE (/*fSERV_Ncbid |*/ fSERV_Http | fSERV_Standalone) + + +/* + * Server-info storage model: + * SSERV_Info's basic fields are stored per the structure; + * SSERV_Info::u is the last "fixed" field; + * SSERV_Info::u's string parameters are stored contiguously following the + * "fixed" area (SSERV_Ops::SizeOf() returns the size of the + * type-dependent "u" plus all the string parameters); + * SSERV_Info::vhost (if non-zero) is stored past the parameters; + * SSERV_Info::extra defines the size of "extra" opaque bytes (which may be + * used to keep private information) that follow vhost (or the + * SSERV_Info::u's block if vhost is empty), zero means none; + * SERV_SizeOfInfo() returns the size that includes all of the above. + * Service name may be stored right past the entire info, contiguously. + */ /***************************************************************************** * Attributes for the different server types:: Interface */ -/* Table of virtual functions +/* Table of operations: req = required; opt = optional */ typedef struct { - SSERV_Info* (*Read )(const char** str, size_t add); - char* (*Write )(size_t reserve, const USERV_Info* u); - int/*bool*/ (*Equal )(const USERV_Info *u1, const USERV_Info *u2); - size_t (*SizeOf)(const USERV_Info *u); -} SSERV_Info_VTable; + SSERV_Info* (*Read )(const char** str, size_t add); /*req*/ + char* (*Write )(size_t reserve, const USERV_Info* u); /*req*/ + int/*bool*/ (*Equal )(const USERV_Info *u1, const USERV_Info *u2); /*opt*/ + size_t (*SizeOf)(const USERV_Info *u); /*req*/ +} SSERV_Ops; /* Attributes */ typedef struct { - ESERV_Type type; - const char* tag; - size_t tag_len; - SSERV_Info_VTable vtable; + ESERV_Type type; + const char* tag; + size_t len; + SSERV_Ops ops; } SSERV_Attr; -/* Flags +/* Flags: to be removed, backward compatibility only */ static const char kRegularInter[] = "RegularInter"; static const char kBlastInter[] = "BlastInter"; @@ -80,13 +98,14 @@ static const char kBlast[] = "Blast"; static struct { const char* tag; size_t len; - ESERV_Flag val; + ESERV_Algo algo; + ESERV_Site site; } kFlags[] = { /* must be ordered longer-to-shorter */ - { kRegularInter, sizeof(kRegularInter)-1, eSERV_RegularInter }, - { kBlastInter, sizeof(kBlastInter)-1, eSERV_BlastInter }, - { kRegular, sizeof(kRegular)-1, eSERV_Regular }, - { kBlast, sizeof(kBlast)-1, eSERV_Blast } + { kRegularInter, sizeof(kRegularInter)-1, eSERV_Regular, fSERV_Interzone }, + { kBlastInter, sizeof(kBlastInter)-1, eSERV_Blast, fSERV_Interzone }, + { kRegular, sizeof(kRegular)-1, eSERV_Regular, 0 }, + { kBlast, sizeof(kBlast)-1, eSERV_Blast, 0 } }; @@ -99,9 +118,7 @@ static const SSERV_Attr* s_GetAttrByTag (const char* tag); extern const char* SERV_TypeStr(ESERV_Type type) { const SSERV_Attr* attr = s_GetAttrByType(type); - if (attr) - return attr->tag; - return ""; + return attr ? attr->tag : ""; } @@ -112,7 +129,7 @@ extern const char* SERV_ReadType(const char* str, if (!attr) return 0; *type = attr->type; - return str + attr->tag_len; + return str + attr->len; } @@ -143,33 +160,49 @@ extern char* SERV_WriteInfo(const SSERV_Info* info) memmove(c_t, p, strlen(p) + 1); } else *c_t = '\0'; - reserve = attr->tag_len+1 + MAX_IP_ADDR_LEN + 1+5/*port*/ + 1+12/*flag*/ + - 1+9/*coef*/ + 3+strlen(c_t)/*cont.type*/ + 3*(1+5)/*site*/ + - 1+14/*rate*/ + 2*(1+5)/*mode*/ + 1+12/*time*/ + 1/*EOL*/; + reserve = attr->len+1 + MAX_IP_ADDR_LEN + 1+5/*port*/ + 1+12/*algo*/ + + 1+9/*coef*/ + 3+strlen(c_t)/*cont.type*/ + 3*(1+5)/*site*/ + + 1+14/*rate*/ + 2*(1+5)/*mode*/ + 1+12/*time*/ + 2*(1+5)/*$,X*/ + + 3+info->vhost + + 1/*EOL*/; /* write server-specific info */ - if ((str = attr->vtable.Write(reserve, &info->u)) != 0) { + if ((str = attr->ops.Write(reserve, &info->u)) != 0) { char* s = str; size_t n; - memcpy(s, attr->tag, attr->tag_len); - s += attr->tag_len; + memcpy(s, attr->tag, attr->len); + s += attr->len; *s++ = ' '; - s += SOCK_HostPortToString(info->host, info->port, s, reserve); + if (info->host == SOCK_HostToNetLong(-1L)) { + int/*bool*/ ipv6 = !NcbiIsIPv4(&info->addr); + if (ipv6) + *s++ = '['; + s = NcbiAddrToString(s, reserve, &info->addr); + if (ipv6) + *s++ = ']'; + if (info->port) + s += sprintf(s, ":%hu", info->port); + } else + s += SOCK_HostPortToString(info->host, info->port, s, reserve); if ((n = strlen(str + reserve)) != 0) { *s++ = ' '; memmove(s, str + reserve, n + 1); s = str + strlen(str); } - for (n = 0; n < sizeof(kFlags) / sizeof(kFlags[0]); ++n) { - if (info->flag == kFlags[n].val) { - s += sprintf(s, " %s", kFlags[n].tag); - break; - } + if (info->algo != eSERV_Regular) { + assert(info->algo == eSERV_Blast); + strcpy(s, " A=B"); + s += 4; } if (info->coef) s = NCBI_simple_ftoa(strcpy(s, " B=") + 3, info->coef, 2); if (*c_t) s += sprintf(s, " C=%s", c_t); + if (info->vhost) { + size_t size = attr->ops.SizeOf(&info->u); + const char* vhost = (const char*) &info->u + size; + s += sprintf(s, " H=%.*s", (int) info->vhost, vhost); + } s += sprintf(s, " L=%s", k_NY[info->site & fSERV_Local]); if (info->type != fSERV_Dns && (info->site & fSERV_Private)) s += sprintf(s, " P=yes"); @@ -180,6 +213,8 @@ extern char* SERV_WriteInfo(const SSERV_Info* info) if (info->type != fSERV_Dns && (info->mode & fSERV_Secure)) s += sprintf(s, " $=yes"); sprintf(s, " T=%lu", (unsigned long) info->time); + if (info->site & fSERV_Interzone) + s += sprintf(s, " X=yes"); } return str; } @@ -189,26 +224,34 @@ SSERV_Info* SERV_ReadInfoEx(const char* str, const char* name, int/*bool*/ lazy) { - int/*bool*/ coef, mime, locl, priv, rate, sful, secu, time, flag; + int/*bool*/ algo, coef, mime, locl, priv, rate, sful, secu, time, cros, vh; + const char* vhost; + const SSERV_Attr* attr; + TNCBI_IPv6Addr addr; ESERV_Type type; unsigned int host; /* network byte order */ unsigned short port; /* host (native) byte order */ SSERV_Info* info; + size_t len; /* detect server type */ str = SERV_ReadType(str, &type); if (!str || (*str && !isspace((unsigned char)(*str)))) return 0; /* NB: "str" guarantees there is a non-NULL attr */ + verify((attr = s_GetAttrByType(type)) != 0); while (*str && isspace((unsigned char)(*str))) ++str; - if (*str && (*str == ':' || !ispunct((unsigned char)(*str)))) { + + /* read optional connection point */ + if (*str && + (*str == ':' || *str == '[' || !ispunct((unsigned char)(*str)))) { const char* end = str; - size_t len; while (*end && !isspace((unsigned char)(*end))) ++end; verify((len = (size_t)(end - str)) > 0); - if (*str != ':') { + + if (!(*str == ':' || *str == '[')) { if (strcspn(str, "=") >= len) { size_t i; for (i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); ++i) { @@ -222,28 +265,84 @@ SSERV_Info* SERV_ReadInfoEx(const char* str, end = 0; } if (end) { - if (!(str = SOCK_StringToHostPortEx(str, &host, &port, lazy))) + int/*bool*/ ipv6 = *str == '[' && len > 2 ? 1/*T*/ : 0/*F*/; + const char* tmp = NcbiIPToAddr(&addr, str + ipv6, len - ipv6); + if (tmp && (!ipv6 || *tmp == ']')) { + str = tmp + ipv6; + if (str != end && *str != ':') + return 0; + ipv6 = 1; + vhost = 0; + } else { + vhost = attr->type & SERV_VHOSTABLE ? str : 0; + ipv6 = 0; + } + if (str == end) + port = 0; + else if (!(str = SOCK_StringToHostPortEx(str, &host, &port, lazy))) return 0; - if (str != end) + else if (str != end) return 0; + if (!ipv6) + NcbiIPv4ToIPv6(&addr, host, 0); + else if (NcbiIsIPv4(&addr)) + host = NcbiIPv6ToIPv4(&addr, 0); + else + host = SOCK_HostToNetLong(-1L); while (*str && isspace((unsigned char)(*str))) ++str; + if (vhost) { + int/*bool*/ dot = 0/*false*/; + for (len = 0; len < (size_t)(end - vhost); ++len) { + if (vhost[len] == ':') + break; + if (vhost[len] == '.') + dot = 1/*true*/; + } + if (len > 1 && dot) { + tmp = strndup(vhost, len); + /*NB: NcbiIPToAddr() can parse full-quad IPv4, so !vhost*/ + assert(!tmp || !SOCK_isipEx(tmp, 1/*full-quad*/)); + if (tmp) { + if (SOCK_isip(tmp)/*NB: very unlikely*/) + vhost = 0; + free((void*) tmp); + } else + vhost = 0; + } else + vhost = 0; + } } else { host = 0; port = 0; + memset(&addr, 0, sizeof(addr)); + vhost = 0; + len = 0; } } else { host = 0; port = 0; + memset(&addr, 0, sizeof(addr)); + vhost = 0; + len = 0; } - /* read server-specific info according to the detected type */ - info = s_GetAttrByType(type)->vtable.Read(&str, name ? strlen(name)+1 : 0); + if (!port && attr->type == fSERV_Standalone) + return 0; + + /* read server-specific info according to the detected type... */ + info = attr->ops.Read(&str, + (name ? strlen(name) + 1 : 0) + + (attr->type & SERV_VHOSTABLE ? 256 : 0)); if (!info) return 0; + assert(info->type == attr->type); info->host = host; info->port = port; - coef = mime = locl = priv = rate = sful = secu = time = flag = 0/*false*/; - /* continue reading server info: optional parts... */ + info->addr = addr; + algo = coef = mime = locl = priv = rate = sful = secu = time = cros = vh + = 0/*false*/; + + /* ...continue reading server info: optional tags */ while (*str && isspace((unsigned char)(*str))) ++str; while (*str) { @@ -256,8 +355,25 @@ SSERV_Info* SERV_ReadInfoEx(const char* str, EMIME_Type mime_t; EMIME_SubType mime_s; EMIME_Encoding mime_e; - + switch (toupper((unsigned char)(*str++))) { + case 'A': + if (algo) + break; + algo = 1/*true*/; + switch (*str) { + case 'B': + info->algo = eSERV_Blast; + ++str; + break; + case 'R': + info->algo = eSERV_Regular; + ++str; + break; + default: + break; + } + break; case 'B': if (coef) break; @@ -287,6 +403,19 @@ SSERV_Info* SERV_ReadInfoEx(const char* str, str++; } break; + case 'H': + if (!(info->type & SERV_VHOSTABLE)) + break; + if (vh) + break; + vh = 1/*true*/; + for (len = 0; *++str; ++len) { + if (isspace((unsigned char)(*str))) + break; + } + assert(len); + vhost = str - len; + break; case 'L': if (locl) break; @@ -368,25 +497,55 @@ SSERV_Info* SERV_ReadInfoEx(const char* str, str += n; } break; + case 'X': + if (cros) + break; + cros = 1/*true*/; + if (sscanf(++str, "%3s%n", s, &n) >= 1) { + if (strcasecmp(s, "YES") == 0) { + info->site |= fSERV_Interzone; + str += n; + } else if (strcasecmp(s, "NO") == 0) { + info->mode &= ~fSERV_Interzone; + str += n; + } + } + break; } - } else if (!flag) { + } else if (!algo) { size_t i; - flag = 1/*true*/; + algo = 1/*true*/; for (i = 0; i < sizeof(kFlags) / sizeof(kFlags[0]); ++i) { if (strncasecmp(str, kFlags[i].tag, kFlags[i].len) == 0) { - info->flag = kFlags[i].val; + if (kFlags[i].site) { + if (cros) + break; + cros = 1/*true*/; + info->site |= kFlags[i].site; + } + info->algo = kFlags[i].algo; str += kFlags[i].len; break; } } } else - break; + break; if (*str && !isspace((unsigned char)(*str))) break; while (*str && isspace((unsigned char)(*str))) ++str; } - if (!*str) { + + if (!*str && (!vh || secu || (info->type & fSERV_Http))) { + if (!vh && !(secu || (info->type & fSERV_Http))) + vhost = 0; + if (vhost) { + if (len > 255) + len = 255; + strncpy0((char*) &info->u + attr->ops.SizeOf(&info->u), + vhost, len); + info->vhost = (unsigned char) len; + } if (name) { strcpy((char*) info + SERV_SizeOfInfo(info), name); if (info->type == fSERV_Dns) @@ -420,7 +579,6 @@ SSERV_Info* SERV_CopyInfoEx(const SSERV_Info* orig, return 0; if ((info = (SSERV_Info*)malloc(size + (name ? strlen(name)+1 : 0))) != 0){ memcpy(info, orig, size); - memset(&info->reserved, 0, sizeof(info->reserved)); if (name) { strcpy((char*) info + size, name); if (orig->type == fSERV_Dns) @@ -440,9 +598,8 @@ extern SSERV_Info* SERV_CopyInfo(const SSERV_Info* orig) const char* SERV_NameOfInfo(const SSERV_Info* info) { - if (!info) - return 0; - return info->type != fSERV_Dns || info->u.dns.name + return !info ? 0 + : info->type != fSERV_Dns || info->u.dns.name ? (const char*) info + SERV_SizeOfInfo(info) : ""; } @@ -451,7 +608,11 @@ extern size_t SERV_SizeOfInfo(const SSERV_Info *info) { const SSERV_Attr* attr = info ? s_GetAttrByType(info->type) : 0; return attr - ? sizeof(*info) - sizeof(info->u) + attr->vtable.SizeOf(&info->u) : 0; + ? (sizeof(*info) - sizeof(info->u) + + attr->ops.SizeOf(&info->u) + + info->vhost + + info->extra) + : 0; } @@ -459,13 +620,30 @@ extern int/*bool*/ SERV_EqualInfo(const SSERV_Info *i1, const SSERV_Info *i2) { const SSERV_Attr* attr; - if (i1->type != i2->type || i1->host != i2->host || i1->port != i2->port) - return 0; - attr = s_GetAttrByType(i1->type/*==i2->type*/); - return attr->vtable.Equal ? attr->vtable.Equal(&i1->u, &i2->u) : 1; + assert(i1 && i2); + if (i1->type != i2->type || + i1->host != i2->host || + i1->port != i2->port) { + return 0/*false*/; + } + if (!NcbiIsEmptyIPv6(&i1->addr) && !NcbiIsEmptyIPv6(&i2->addr) + && memcmp(&i1->addr, &i2->addr, sizeof(i1->addr)) != 0) { + return 0/*false*/; + } + if (!(attr = s_GetAttrByType(i1->type/*==i2->type*/))) + return 0/*false*/; + return attr->ops.Equal ? attr->ops.Equal(&i1->u, &i2->u) : 1; } +extern const char* SERV_HostOfInfo(const SSERV_Info* info) +{ + const SSERV_Attr* attr; + if (!info->vhost || !(attr = s_GetAttrByType(info->type))) + return 0; + return (const char*) &info->u + attr->ops.SizeOf(&info->u); +} + /***************************************************************************** * NCBID:: constructor and virtual functions @@ -539,8 +717,10 @@ SSERV_Info* SERV_CreateNcbidInfoEx(unsigned int host, info->mime_t = eMIME_T_Undefined; info->mime_s = eMIME_Undefined; info->mime_e = eENCOD_None; - info->flag = SERV_DEFAULT_FLAG; - memset(&info->reserved, 0, sizeof(info->reserved)); + info->algo = SERV_DEFAULT_ALGO; + info->vhost = 0; + info->extra = 0; + memset(&info->addr, 0, sizeof(info->addr)); info->u.ncbid.args = (TNCBI_Size) sizeof(info->u.ncbid); if (args && strcmp(args, "''"/*special case*/) == 0) args = 0; @@ -563,7 +743,7 @@ extern SSERV_Info* SERV_CreateNcbidInfo(unsigned int host, */ /*ARGSUSED*/ -static char* s_Standalone_Write(size_t reserve, const USERV_Info* u_info) +static char* s_Standalone_Write(size_t reserve, const USERV_Info* u) { char* str = (char*) malloc(reserve + 1); @@ -604,8 +784,10 @@ SSERV_Info* SERV_CreateStandaloneInfoEx(unsigned int host, info->mime_t = eMIME_T_Undefined; info->mime_s = eMIME_Undefined; info->mime_e = eENCOD_None; - info->flag = SERV_DEFAULT_FLAG; - memset(&info->reserved, 0, sizeof(info->reserved)); + info->algo = SERV_DEFAULT_ALGO; + info->vhost = 0; + info->extra = 0; + memset(&info->addr, 0, sizeof(info->addr)); memset(&info->u.standalone, 0, sizeof(info->u.standalone)); } return info; @@ -683,8 +865,9 @@ static SSERV_Info* s_Http_Read(const char** str, size_t add) static size_t s_Http_SizeOf(const USERV_Info* u) { - return sizeof(u->http) + strlen(SERV_HTTP_PATH(&u->http))+1 + - strlen(SERV_HTTP_ARGS(&u->http))+1; + return sizeof(u->http) + + strlen(SERV_HTTP_PATH(&u->http))+1 + + strlen(SERV_HTTP_ARGS(&u->http))+1; } @@ -720,11 +903,13 @@ SSERV_Info* SERV_CreateHttpInfoEx(ESERV_Type type, info->mime_t = eMIME_T_Undefined; info->mime_s = eMIME_Undefined; info->mime_e = eENCOD_None; - info->flag = SERV_DEFAULT_FLAG; - memset(&info->reserved, 0, sizeof(info->reserved)); + info->algo = SERV_DEFAULT_ALGO; + info->vhost = 0; + info->extra = 0; + memset(&info->addr, 0, sizeof(info->addr)); info->u.http.path = (TNCBI_Size) sizeof(info->u.http); - info->u.http.args = (TNCBI_Size) (info->u.http.path + - (path ? strlen(path) : 0) + 1); + info->u.http.args = (TNCBI_Size) (info->u.http.path + + (path ? strlen(path) : 0) + 1); strcpy(SERV_HTTP_PATH(&info->u.http), path ? path : ""); strcpy(SERV_HTTP_ARGS(&info->u.http), args ? args : ""); } @@ -746,9 +931,9 @@ extern SSERV_Info* SERV_CreateHttpInfo(ESERV_Type type, * FIREWALL:: constructor and virtual functions */ -static char* s_Firewall_Write(size_t reserve, const USERV_Info* u_info) +static char* s_Firewall_Write(size_t reserve, const USERV_Info* u) { - const char* name = SERV_TypeStr(u_info->firewall.type); + const char* name = SERV_TypeStr(u->firewall.type); size_t namelen = strlen(name); char* str = (char*) malloc(reserve + (namelen ? namelen + 1 : 0)); @@ -801,8 +986,10 @@ SSERV_Info* SERV_CreateFirewallInfoEx(unsigned int host, info->mime_t = eMIME_T_Undefined; info->mime_s = eMIME_Undefined; info->mime_e = eENCOD_None; - info->flag = SERV_DEFAULT_FLAG; - memset(&info->reserved, 0, sizeof(info->reserved)); + info->algo = SERV_DEFAULT_ALGO; + info->vhost = 0; + info->extra = 0; + memset(&info->addr, 0, sizeof(info->addr)); info->u.firewall.type = type; } return info; @@ -822,7 +1009,7 @@ SSERV_Info* SERV_CreateFirewallInfo(unsigned int host, */ /*ARGSUSED*/ -static char* s_Dns_Write(size_t reserve, const USERV_Info* u_info) +static char* s_Dns_Write(size_t reserve, const USERV_Info* u) { char* str = (char*) malloc(reserve + 1); @@ -845,7 +1032,8 @@ static size_t s_Dns_SizeOf(const USERV_Info* u) } -SSERV_Info* SERV_CreateDnsInfoEx(unsigned int host, size_t add) +SSERV_Info* SERV_CreateDnsInfoEx(unsigned int host, + size_t add) { SSERV_Info* info = (SSERV_Info*) malloc(sizeof(SSERV_Info) + add); @@ -861,8 +1049,10 @@ SSERV_Info* SERV_CreateDnsInfoEx(unsigned int host, size_t add) info->mime_t = eMIME_T_Undefined; info->mime_s = eMIME_Undefined; info->mime_e = eENCOD_None; - info->flag = SERV_DEFAULT_FLAG; - memset(&info->reserved, 0, sizeof(info->reserved)); + info->algo = SERV_DEFAULT_ALGO; + info->vhost = 0; + info->extra = 0; + memset(&info->addr, 0, sizeof(info->addr)); memset(&info->u.dns, 0, sizeof(info->u.dns)); } return info; @@ -942,7 +1132,7 @@ static const SSERV_Attr* s_GetAttrByTag(const char* tag) if (tag) { size_t i; for (i = 0; i < sizeof(kSERV_Attr)/sizeof(kSERV_Attr[0]); ++i) { - size_t len = kSERV_Attr[i].tag_len; + size_t len = kSERV_Attr[i].len; if (strncasecmp(tag, kSERV_Attr[i].tag, len) == 0 && (!tag[len] || isspace((unsigned char) tag[len]))) return &kSERV_Attr[i]; diff --git a/c++/src/connect/ncbi_server_infop.h b/c++/src/connect/ncbi_server_infop.h index 19577da5..0eac7026 100644 --- a/c++/src/connect/ncbi_server_infop.h +++ b/c++/src/connect/ncbi_server_infop.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_SERVER_INFOP__H #define CONNECT___NCBI_SERVER_INFOP__H -/* $Id: ncbi_server_infop.h 451383 2014-11-06 15:18:01Z lavr $ +/* $Id: ncbi_server_infop.h 527592 2017-02-14 18:35:37Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -99,6 +99,12 @@ const char* SERV_NameOfInfo ); +NCBI_XCONNECT_EXPORT +const char* SERV_HostOfInfo +(const SSERV_Info* info + ); + + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/c++/src/connect/ncbi_service.c b/c++/src/connect/ncbi_service.c index f4f9ecc1..f9476626 100644 --- a/c++/src/connect/ncbi_service.c +++ b/c++/src/connect/ncbi_service.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_service.c 513929 2016-09-16 15:08:30Z ivanov $ +/* $Id: ncbi_service.c 533605 2017-04-18 15:12:53Z mcelhany $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,6 +37,7 @@ #ifdef NCBI_CXX_TOOLKIT # include "ncbi_lbosp.h" #endif +#include "ncbi_namerd.h" #include "ncbi_priv.h" #include #include @@ -71,8 +72,8 @@ ESwitch SERV_DoFastOpens(ESwitch on) } -static char* x_ServiceName(const char* service, - int/*bool*/ ismask, unsigned int depth) +static char* x_ServiceName(const char* service, unsigned int depth, + int/*bool*/ ismask, int/*bool*/ isfast) { char buf[128]; char srv[128]; @@ -100,7 +101,7 @@ static char* x_ServiceName(const char* service, "Too long")); return 0/*failure*/; } - if (!s_Fast && !ismask) { + if (!ismask && !isfast) { s = (char*) memcpy(buf, service, len) + len; *s++ = '_'; memcpy(s, CONN_SERVICE_NAME, sizeof(CONN_SERVICE_NAME)); @@ -112,17 +113,18 @@ static char* x_ServiceName(const char* service, s = srv; } if (*s && strcasecmp(s, service) != 0) - return x_ServiceName(s, ismask, depth + 1); + return x_ServiceName(s, depth + 1, ismask, isfast); } return strdup(service); } -static char* s_ServiceName(const char* service, int/*bool*/ ismask) +static char* s_ServiceName(const char* service, + int/*bool*/ ismask, int/*bool*/ isfast) { char* retval; CORE_LOCK_READ; - retval = x_ServiceName(service, ismask, 0); + retval = x_ServiceName(service, 0/*depth*/, ismask, isfast); CORE_UNLOCK; return retval; } @@ -130,7 +132,7 @@ static char* s_ServiceName(const char* service, int/*bool*/ ismask) char* SERV_ServiceName(const char* service) { - return s_ServiceName(service, 0); + return s_ServiceName(service, 0/*ismask*/, 0/*isfast*/); } @@ -201,6 +203,7 @@ static SERV_ITER x_Open(const char* service, int/*bool*/ do_lbsmd = -1/*unassigned*/, #ifdef NCBI_CXX_TOOLKIT + do_namerd = -1/*unassigned*/, do_lbos = -1/*unassigned*/, #endif /*NCBI_CXX_TOOLKIT*/ do_dispd = -1/*unassigned*/; @@ -208,7 +211,7 @@ static SERV_ITER x_Open(const char* service, SERV_ITER iter; const char* s; - if (!(s = s_ServiceName(service, ismask))) + if (!(s = s_ServiceName(service, ismask, s_Fast))) return 0; if (!(iter = (SERV_ITER) calloc(1, sizeof(*iter)))) { free((void*) s); @@ -299,6 +302,9 @@ static SERV_ITER x_Open(const char* service, (service, REG_CONN_DISPD_DISABLE))) #ifdef NCBI_CXX_TOOLKIT && + !(do_namerd = s_IsMapperConfigured + (service, REG_CONN_NAMERD_ENABLE)) + && !(do_lbos = s_IsMapperConfigured (service, REG_CONN_LBOS_ENABLE)) #endif /*NCBI_CXX_TOOLKIT*/ @@ -306,6 +312,11 @@ static SERV_ITER x_Open(const char* service, #ifdef NCBI_CXX_TOOLKIT && + (!do_namerd || + (do_namerd < 0 && !(do_namerd = s_IsMapperConfigured + (service, REG_CONN_NAMERD_ENABLE))) || + !(op = SERV_NAMERD_Open(iter, net_info, info))) + && (!do_lbos || (do_lbos < 0 && !(do_lbos = s_IsMapperConfigured (service, REG_CONN_LBOS_ENABLE))) || @@ -317,7 +328,11 @@ static SERV_ITER x_Open(const char* service, (do_dispd < 0 && !(do_dispd = !s_IsMapperConfigured (service, REG_CONN_DISPD_DISABLE))) || !(op = SERV_DISPD_Open(iter, net_info, info, host_info)))) { +#ifdef NCBI_CXX_TOOLKIT + if (!do_namerd && !do_lbsmd && !do_dispd) { +#else if (!do_lbsmd && !do_dispd) { +#endif /*NCBI_CXX_TOOLKIT*/ CORE_LOGF_X(1, eLOG_Error, ("[%s] No service mappers available", service)); } @@ -339,7 +354,7 @@ static void s_SkipSkip(SERV_ITER iter) n = 0; while (n < iter->n_skip) { SSERV_InfoCPtr temp = iter->skip[n]; - if (temp->time != NCBI_TIME_INFINITE + if (temp != iter->last && temp->time != NCBI_TIME_INFINITE && (!iter->time/*iterator reset*/ || ((temp->type != fSERV_Dns || temp->host) && temp->time < iter->time))) { @@ -348,8 +363,6 @@ static void s_SkipSkip(SERV_ITER iter) memmove((void*) ptr, (void*)(ptr + 1), (iter->n_skip - n) * sizeof(*ptr)); } - if (iter->last == temp) - iter->last = 0; free((void*) temp); } else n++; @@ -769,7 +782,8 @@ char* SERV_Print(SERV_ITER iter, SConnNetInfo* net_info, int/*bool*/ but_last) buffer[buflen++] = ' '; memcpy(buffer + buflen, name, namelen); buflen += namelen; - } + } else if (iter->types < t) + break; } if (buffer[buflen - 1] != ':') { strcpy(&buffer[buflen], "\r\n"); @@ -828,7 +842,7 @@ char* SERV_Print(SERV_ITER iter, SConnNetInfo* net_info, int/*bool*/ but_last) iter->time = (TNCBI_Time) time(0); s_SkipSkip(iter); /* Put all the rest into rejection list */ - for (i = 0; i < iter->n_skip; i++) { + for (i = 0; i < iter->n_skip; ++i) { /* NB: all skip infos are now kept with names (perhaps, empty) */ const char* name = SERV_NameOfInfo(iter->skip[i]); size_t namelen = name && *name ? strlen(name) : 0; diff --git a/c++/src/connect/ncbi_service_connector.c b/c++/src/connect/ncbi_service_connector.c index f6394d33..2edf9208 100644 --- a/c++/src/connect/ncbi_service_connector.c +++ b/c++/src/connect/ncbi_service_connector.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_service_connector.c 516325 2016-10-12 17:18:28Z ivanov $ +/* $Id: ncbi_service_connector.c 533405 2017-04-14 20:36:09Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -44,24 +44,35 @@ typedef struct SServiceConnectorTag { - const char* type; /* Verbal connector type */ - const char* descr; /* Verbal connector description */ - SConnNetInfo* net_info; /* Connection information */ - const char* user_header; /* User header currently set */ - SERV_ITER iter; /* Dispatcher information */ - SMetaConnector meta; /* Low level comm.conn and its VT */ - unsigned int host; /* Parsed connection info... (n.b.o) */ - unsigned short port; /* ... (h.b.o) */ - unsigned short retry; /* Open retry count since last okay */ - TSERV_TypeOnly types; /* Server types w/o any specials */ - unsigned reset:1; /* Non-zero if iter was just reset */ - SSERVICE_Extra extra; /* Extra params as passed to ctor */ - ticket_t ticket; /* Network byte order (none if zero) */ - EIO_Status status; /* Status of last op */ - const char service[1]; /* Untranslated (orig.) service name */ + SMetaConnector meta; /* Low level comm.conn and its VT */ + const char* type; /* Verbal connector type */ + const char* descr; /* Verbal connector description */ + const SConnNetInfo* net_info; /* Connection information, read-only */ + const char* user_header; /* User header currently set */ + + SERV_ITER iter; /* Dispatcher information */ + + SSERVICE_Extra extra; /* Extra params as passed to ctor */ + EIO_Status status; /* Status of last I/O op */ + + unsigned short retry; /* Open retry count since last okay */ + TSERV_TypeOnly types; /* Server types w/o any specials */ + unsigned reset:1; /* Non-zero if iter was just reset */ + unsigned warned:1; /* Non-zero when needed adj via HTTP */ + unsigned unused:5; + unsigned secure:1; /* Set when must start ssl on SOCK */ + + ticket_t ticket; /* Network byte order (none if zero) */ + unsigned int host; /* Parsed connection info... (n.b.o) */ + unsigned short port; /* ... (h.b.o) */ + + const char service[1]; /* Untranslated (orig.) service name */ } SServiceConnector; +static const char kHttpHostTag[] = "Host: "; + + /*********************************************************************** * INTERNAL -- "s_VT_*" functions for the "virt. table" of connector methods ***********************************************************************/ @@ -127,7 +138,7 @@ static EHTTP_HeaderParse s_ParseHeader(const char* header, int/*bool*/ user_callback_enabled) { static const char kStateless[] = "TRY_STATELESS"; - static const size_t klen = sizeof(kStateless) - 1; + static const size_t kSLen = sizeof(kStateless) - 1; SServiceConnector* uuu = (SServiceConnector*) user_data; EHTTP_HeaderParse header_parse; @@ -151,8 +162,8 @@ static EHTTP_HeaderParse s_ParseHeader(const char* header, header += sizeof(HTTP_CONNECTION_INFO) - 1; while (*header && isspace((unsigned char)(*header))) header++; - if (strncasecmp(header, kStateless, klen) == 0 && - (!header[klen] || isspace((unsigned char) header[klen]))) { + if (strncasecmp(header, kStateless, kSLen) == 0 && + (!header[kSLen] || isspace((unsigned char) header[kSLen]))) { /* Special keyword for switching into stateless mode */ uuu->host = (unsigned int)(-1); #if defined(_DEBUG) && !defined(NDEBUG) @@ -168,7 +179,9 @@ static EHTTP_HeaderParse s_ParseHeader(const char* header, if (sscanf(header, "%u.%u.%u.%u%n", &i1, &i2, &i3, &i4, &n) < 4 || sscanf(header + n, "%hu%x%n", &uuu->port, &tkt, &m) < 2 - || (header[m += n] && !isspace((unsigned char)header[m]))){ + || (header[m += n] && !(header[m] == '$') && + !isspace((unsigned char)((header + m) + [header[m] == '$'])))) { break/*failed - unreadable connection info*/; } o1 = i1; o2 = i2; o3 = i3; o4 = i4; @@ -179,10 +192,12 @@ static EHTTP_HeaderParse s_ParseHeader(const char* header, break/*failed - bad host:port in connection info*/; } uuu->ticket = SOCK_HostToNetLong(tkt); + if (header[m] == '$') + uuu->secure = 1; } } if ((header = strchr(header, '\n')) != 0) - header++; + ++header; } if (header && *header) @@ -503,6 +518,44 @@ static CONNECTOR s_SocketConnectorBuilder(SConnNetInfo* net_info, } +static int/*bool*/ x_SetHostPort(SConnNetInfo* net_info, + const SSERV_Info* info) +{ + const char* vhost = SERV_HostOfInfo(info); + + if (vhost) { + char* tag; + if (!(tag = (char*) malloc(sizeof(kHttpHostTag) + info->vhost))) + return 0/*failure*/; + sprintf(tag, "%s%.*s", kHttpHostTag, (int) info->vhost, vhost); + if (!ConnNetInfo_OverrideUserHeader(net_info, tag)) { + free(tag); + return 0/*failure*/; + } + free(tag); + } + if (info->host == SOCK_HostToNetLong(-1L)) { + int/*bool*/ ipv6 = !NcbiIsIPv4(&info->addr); + char* end = NcbiAddrToString(net_info->host + ipv6, + sizeof(net_info->host) - 2*ipv6, + &info->addr); + if (!end) { + *net_info->host = '\0'; + return 0/*failure*/; + } + if (ipv6) { + *net_info->host = '['; + *end++ = ']'; + *end = '\0'; + } + } else + SOCK_ntoa(info->host, net_info->host, sizeof(net_info->host)); + + net_info->port = info->port; + return 1/*success*/; +} + + /* Although all additional HTTP tags that comprise the dispatching have their * default values, which in most cases are fine with us, we will use these tags * explicitly to distinguish the calls originated within the service connector @@ -529,8 +582,13 @@ static int/*bool*/ s_Adjust(SConnNetInfo* net_info, char* iter_header; SSERV_InfoCPtr info; - assert(n > 0 && (!net_info->firewall || net_info->stateless)); + assert(n || uuu->extra.adjust); + assert(!net_info->firewall || net_info->stateless); + + if (!n || n == (unsigned int)(-1)) + return uuu->extra.adjust(net_info, uuu->extra.data, n); + uuu->warned = 1; if (uuu->retry >= uuu->net_info->max_try) return 0/*failure - too many errors*/; uuu->retry++; @@ -601,13 +659,13 @@ static int/*bool*/ s_Adjust(SConnNetInfo* net_info, } else /*NB: special case ""*/ uuu->user_header = 0; - if (info->type == fSERV_Ncbid || (info->type & fSERV_Http)) { - SOCK_ntoa(info->host, net_info->host, sizeof(net_info->host)); - net_info->port = info->port; - } else { + if (info->type != fSERV_Ncbid && !(info->type & fSERV_Http)) { + ConnNetInfo_DeleteUserHeader(net_info, kHttpHostTag); strcpy(net_info->host, uuu->net_info->host); net_info->port = uuu->net_info->port; - } + } else if (!x_SetHostPort(net_info, info)) + return 0/*failure - not adjusted*/; + return uuu->extra.adjust && !uuu->extra.adjust(net_info, uuu->extra.data, uuu->retry) ? 0/*failure - not adjusted*/ @@ -637,12 +695,17 @@ static CONNECTOR s_Open(SServiceConnector* uuu, char* iter_header; EReqMethod req_method; - if (info && info->type != fSERV_Firewall) { - /* Not a firewall/relay connection here */ - /* We know the connection point, let's try to use it! */ - if (info->type != fSERV_Standalone || !net_info->stateless) { - SOCK_ntoa(info->host, net_info->host, sizeof(net_info->host)); - net_info->port = info->port; + assert(net_info->firewall || info); + ConnNetInfo_DeleteUserHeader(net_info, kHttpHostTag); + if ((!net_info->firewall && info->type != fSERV_Firewall) + || (info && ((info->type & fSERV_Http) || + (info->type == fSERV_Ncbid && net_info->stateless)))){ + /* Not a firewall/relay connection here: + We know the connection point, so let's try to use it! */ + if ((info->type != fSERV_Standalone || !net_info->stateless) + && !x_SetHostPort(net_info, info)) { + *status = eIO_Unknown; + return 0; } switch (info->type) { @@ -650,15 +713,12 @@ static CONNECTOR s_Open(SServiceConnector* uuu, /* Connection directly to NCBID, add NCBID-specific tags */ if (info->mode & fSERV_Secure) net_info->scheme = eURL_Https; - if (net_info->stateless) { + req_method = eReqMethod_Any; /* replaced with GET if aux HTTP */ + user_header = net_info->stateless /* Connection request with data */ - user_header = "Connection-Mode: STATELESS\r\n"; /*default*/ - req_method = eReqMethod_Post; - } else { + ? "Connection-Mode: STATELESS\r\n" /*default*/ /* We will be waiting for conn-info back */ - user_header = "Connection-Mode: STATEFUL\r\n"; - req_method = eReqMethod_Get; - } + : "Connection-Mode: STATEFUL\r\n"; user_header = s_AdjustNetParams(uuu->service, net_info, req_method, NCBID_WEBPATH, SERV_NCBID_ARGS(&info->u.ncbid), @@ -669,6 +729,7 @@ static CONNECTOR s_Open(SServiceConnector* uuu, case fSERV_HttpGet: case fSERV_HttpPost: /* Connection directly to CGI */ + net_info->stateless = 1/*true*/; req_method = info->type == fSERV_HttpGet ? eReqMethod_Get : (info->type == fSERV_HttpPost ? eReqMethod_Post : eReqMethod_Any); @@ -688,6 +749,8 @@ static CONNECTOR s_Open(SServiceConnector* uuu, ? fSOCK_Secure : 0); } /* Otherwise, it will be a pass-thru connection via dispatcher */ + if (!net_info->scheme) + net_info->scheme = eURL_Https; user_header = "Client-Mode: STATELESS_ONLY\r\n"; /*default*/ user_header = s_AdjustNetParams(uuu->service, net_info, eReqMethod_Any, 0, 0, @@ -701,42 +764,45 @@ static CONNECTOR s_Open(SServiceConnector* uuu, break; } } else { + /* Firewall/relay connection via dispatcher */ + TSERV_Type type; EMIME_Type mime_t; EMIME_SubType mime_s; EMIME_Encoding mime_e; + if (!net_info->scheme) net_info->scheme = eURL_Https; - if (net_info->stateless - || (info && (info->u.firewall.type & fSERV_Http))) { - if (info) { - req_method = (info->u.firewall.type == fSERV_HttpGet - ? eReqMethod_Get - : (info->u.firewall.type == fSERV_HttpPost - ? eReqMethod_Post - : eReqMethod_Any)); - net_info->stateless = 1/*true*/; - } else - req_method = eReqMethod_Any; + if (info && (fSERV_Http & (type = info->type == fSERV_Firewall + ? info->u.firewall.type + : info->type))) { + req_method = (type == fSERV_HttpGet + ? eReqMethod_Get + : (type == fSERV_HttpPost + ? eReqMethod_Post + : eReqMethod_Any)); + net_info->stateless = 1/*true*/; } else - req_method = eReqMethod_Get; + req_method = eReqMethod_Any; /* may downgrade to GET w/aux HTTP */ + if (info) { mime_t = info->mime_t; mime_s = info->mime_s; mime_e = info->mime_e; + but_last = 1/*true*/; } else { mime_t = eMIME_T_Undefined; mime_s = eMIME_Undefined; mime_e = eENCOD_None; } + /* Firewall/relay connection thru dispatcher, special tags */ user_header = (net_info->stateless ? "Client-Mode: STATELESS_ONLY\r\n" /*default*/ : "Client-Mode: STATEFUL_CAPABLE\r\n"); - user_header = s_AdjustNetParams(uuu->service, net_info, req_method, - 0, 0, 0, user_header, - mime_t, mime_s, mime_e, 0); - if (info) - but_last = 1/*true*/; + user_header = s_AdjustNetParams(uuu->service, net_info, + req_method, 0, 0, + 0, user_header, mime_t, + mime_s, mime_e, 0); } if (!user_header) { *status = eIO_Unknown; @@ -779,7 +845,7 @@ static CONNECTOR s_Open(SServiceConnector* uuu, ); *status = eIO_Success; - if (!net_info->stateless && (!info || + if (!net_info->stateless && (net_info->firewall || info->type == fSERV_Firewall || info->type == fSERV_Ncbid)) { /* Auxiliary HTTP connector first */ @@ -791,8 +857,11 @@ static CONNECTOR s_Open(SServiceConnector* uuu, uuu->host = 0; uuu->port = 0; uuu->ticket = 0; - net_info->max_try = 1; - c = HTTP_CreateConnectorEx(net_info, fHTTP_Flushable, + uuu->secure = 0; + assert(!net_info->req_method); + net_info->req_method = eReqMethod_Get; + c = HTTP_CreateConnectorEx(net_info, + fHTTP_Flushable | fHTTP_NoAutoRetry, s_ParseHeaderNoUCB, uuu/*user_data*/, 0/*adjust*/, 0/*cleanup*/); /* Wait for connection info back from dispatcher */ @@ -825,7 +894,7 @@ static CONNECTOR s_Open(SServiceConnector* uuu, assert(!uuu->host); } if (uuu->host == (unsigned int)(-1)) { - assert(!info || info->type == fSERV_Firewall); + assert(net_info->firewall || info->type == fSERV_Firewall); assert(!net_info->stateless); net_info->stateless = 1/*true*/; /* Fallback to try to use stateless mode instead */ @@ -858,10 +927,8 @@ static CONNECTOR s_Open(SServiceConnector* uuu, return s_SocketConnectorBuilder(net_info, uuu->descr, status, &uuu->ticket, uuu->ticket ? sizeof(uuu->ticket) : 0, - info && (info->mode & fSERV_Secure) - ? fSOCK_Secure : 0); + uuu->secure ? fSOCK_Secure : 0); } - ConnNetInfo_DeleteUserHeader(net_info, "Host:"); if (info && (info->mode & fSERV_Secure)) net_info->scheme = eURL_Https; else if (!net_info->scheme) @@ -869,10 +936,14 @@ static CONNECTOR s_Open(SServiceConnector* uuu, assert(!uuu->descr); uuu->descr = ConnNetInfo_URL(net_info); return !uuu->extra.adjust - || uuu->extra.adjust(net_info, uuu->extra.data, 0) + || uuu->extra.adjust(net_info, uuu->extra.data, (unsigned int)(-1)) ? HTTP_CreateConnectorEx(net_info, (uuu->extra.flags - & (fHTTP_Flushable | fHTTP_NoAutoRetry)) + & (fHTTP_Flushable | + fHTTP_NoAutoRetry | + (uuu->extra.adjust + ? fHTTP_AdjustOnRedirect + : 0))) | fHTTP_AutoReconnect, s_ParseHeaderUCB, uuu/*user_data*/, s_Adjust, 0/*cleanup*/) @@ -946,6 +1017,7 @@ static EIO_Status s_VT_Open(CONNECTOR connector, const STimeout* timeout) SMetaConnector* meta = connector->meta; EIO_Status status = eIO_Closed; + uuu->warned = 0; for (uuu->retry = 0; uuu->retry < uuu->net_info->max_try; uuu->retry++) { SConnNetInfo* net_info; SSERV_InfoCPtr info; @@ -962,6 +1034,23 @@ static EIO_Status s_VT_Open(CONNECTOR connector, const STimeout* timeout) || strcasecmp(SERV_MapperName(uuu->iter), "local") == 0)) { break; } + if ((uuu->types & ~fSERV_Firewall) + && info && ((info->type != fSERV_Firewall + && !(uuu->types & info->type)) || + (info->type == fSERV_Firewall + && !(uuu->types & info->u.firewall.type)))) { + const char* type = SERV_TypeStr(info->type == fSERV_Firewall + ? info->u.firewall.type + : info->type); + char buf[40]; + sprintf(buf, + *type ? " (0x%hX)" : "0x%hX", (unsigned short) info->type); + CORE_LOGF_X(10, eLOG_Critical, + ("[%s] Mismatched server type %s%s not within 0x%hX", + uuu->service, type, buf, (unsigned short)uuu->types)); + status = eIO_Unknown; + continue; + } if (uuu->type) { free((void*) uuu->type); uuu->type = 0; @@ -1031,19 +1120,25 @@ static EIO_Status s_VT_Open(CONNECTOR connector, const STimeout* timeout) if (status == eIO_Success) break; - if (!stateless && (!info || info->type == fSERV_Firewall)) { + if (!stateless + && (uuu->net_info->firewall || info->type == fSERV_Firewall)) { static const char kFWDLink[] = CONN_FWD_LINK; CORE_LOGF_X(6, eLOG_Error, ("[%s] %s connection failure (%s) usually" " indicates possible firewall configuration" " problems; please consult <%s>", uuu->service, - !info ? "Firewall" : "Stateful relay", + uuu->net_info->firewall ? "Firewall":"Stateful relay", IO_StatusStr(status), kFWDLink)); } s_Close(connector, timeout, 0/*retain*/); } - + if (status != eIO_Success && !uuu->warned + && uuu->retry > 1 && uuu->retry >= uuu->net_info->max_try) { + CORE_LOGF_X(11, eLOG_Error, + ("[%s] Too many failed attempts (%hu), giving up", + uuu->service, uuu->retry)); + } uuu->status = status; return status; } @@ -1086,7 +1181,7 @@ static void s_Destroy(CONNECTOR connector) uuu->extra.cleanup(uuu->extra.data); s_CloseDispatcher(uuu); s_Cleanup(uuu); - ConnNetInfo_Destroy(uuu->net_info); + ConnNetInfo_Destroy((SConnNetInfo*) uuu->net_info); free(uuu); free(connector); } @@ -1103,6 +1198,7 @@ extern CONNECTOR SERVICE_CreateConnectorEx const SSERVICE_Extra* extra) { char* x_service; + SConnNetInfo* x_net_info; CONNECTOR ccc; size_t len; SServiceConnector* xxx; @@ -1129,11 +1225,12 @@ extern CONNECTOR SERVICE_CreateConnectorEx ccc->destroy = s_Destroy; xxx->types = types; - xxx->net_info = (net_info + x_net_info = (net_info ? ConnNetInfo_Clone(net_info) - : ConnNetInfo_Create(service)); + : ConnNetInfo_Create(x_service)); + xxx->net_info = x_net_info; - if (!ConnNetInfo_SetupStandardArgs(xxx->net_info, x_service)) { + if (!ConnNetInfo_SetupStandardArgs(x_net_info, x_service)) { free(x_service); s_Destroy(ccc); return 0; @@ -1144,11 +1241,11 @@ extern CONNECTOR SERVICE_CreateConnectorEx /* now get ready for first probe dispatching */ if ( types & fSERV_Stateless ) - xxx->net_info->stateless = 1/*true*/; - if ((types & fSERV_Firewall) && !xxx->net_info->firewall) - xxx->net_info->firewall = eFWMode_Adaptive; - if (xxx->net_info->max_try < 1) - xxx->net_info->max_try = 1; + x_net_info->stateless = 1/*true*/; + if ((types & fSERV_Firewall) && !x_net_info->firewall) + x_net_info->firewall = eFWMode_Adaptive; + if (x_net_info->max_try < 1) + x_net_info->max_try = 1; if (!s_OpenDispatcher(xxx)) { s_Destroy(ccc); return 0; diff --git a/c++/src/connect/ncbi_socket.c b/c++/src/connect/ncbi_socket.c index 2c092db5..39baa4ac 100644 --- a/c++/src/connect/ncbi_socket.c +++ b/c++/src/connect/ncbi_socket.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_socket.c 517038 2016-10-20 11:20:53Z ivanov $ +/* $Id: ncbi_socket.c 545960 2017-09-12 17:07:06Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -75,9 +75,7 @@ #include "ncbi_ansi_ext.h" #include "ncbi_connssl.h" #include "ncbi_priv.h" -#ifdef NCBI_CXX_TOOLKIT -# include -#endif /*NCBI_CXX_TOOLKIT*/ +#include "ncbi_once.h" #include #include @@ -133,12 +131,17 @@ #ifdef NCBI_MONKEY /* A hack - we know that SOCK variable has name "sock" in code. - * If the desired behavior is timeout, "sock" will be replaced with a - * connection to non-working server */ -# define send(a,b,c,d) ((g_MONKEY_Send == NULL) ? send(a,b,c,d) : g_MONKEY_Send(a,b,c,d,&sock)) -# define recv(a,b,c,d) ((g_MONKEY_Recv == NULL) ? recv(a,b,c,d) : g_MONKEY_Recv(a,b,c,d,&sock)) -# define connect(a,b,c) ((g_MONKEY_Connect == NULL) ? connect(a,b,c) : g_MONKEY_Connect(a,b,c)) -#endif + If the desired behavior is timeout, "sock" will be replaced with a + connection to non-working server */ +# define send(a,b,c,d) \ + (g_MONKEY_Send ? g_MONKEY_Send(a,b,c,d,&sock) : send(a,b,c,d)) +# define recv(a,b,c,d) \ + (g_MONKEY_Recv ? g_MONKEY_Recv(a,b,c,d,&sock) : recv(a,b,c,d)) +# define connect(a,b,c) \ + (g_MONKEY_Connect ? g_MONKEY_Connect(a,b,c) : connect(a,b,c)) +#endif /*NCBI_MONKEY*/ + + /****************************************************************************** * TYPEDEFS & MACROS */ @@ -281,10 +284,12 @@ static const char* s_StrError(SOCK sock, int error) if (sock) { FSSLError sslerror = sock->session && s_SSL ? s_SSL->Error : 0; if (sslerror) { + char errbuf[256]; const char* strerr = sslerror(sock->session == SESSION_INVALID - ? 0 : sock->session, error); + ? 0 : sock->session, error, + errbuf, sizeof(errbuf)); if (strerr && *strerr) - return MSWIN_STRDUP(strerr); + return ERR_STRDUP(strerr); } } return s_StrErrorInternal(error); @@ -774,7 +779,7 @@ static EIO_Status s_Init(void) # endif /*NCBI_OS_MSWIN*/ #endif /*_DEBUG && !NDEBUG*/ -#if defined(NCBI_OS_MSWIN) +#if defined(NCBI_OS_MSWIN) {{ WSADATA wsadata; int error = WSAStartup(MAKEWORD(1,1), &wsadata); @@ -802,22 +807,16 @@ static EIO_Status s_Init(void) } #endif /*platform-specific init*/ - s_Initialized = 1/*inited*/; #ifndef NCBI_OS_MSWIN {{ - static void*/*bool*/ s_AtExitSet = 0; -#ifdef NCBI_CXX_TOOLKIT - if (!NCBI_SwapPointers(&s_AtExitSet, (void*) 1)) - atexit((void (*)(void)) SOCK_ShutdownAPI); -#else - if (!s_AtExitSet) { - s_AtExitSet = (void*) 1; + static void* /*bool*/ s_AtExitSet = 0/*false*/; + if (CORE_Once(&s_AtExitSet)) atexit((void (*)(void)) SOCK_ShutdownAPI); - } -#endif /*NCBI_CXX_TOOLKIT*/ }} #endif /*NCBI_OS_MSWIN*/ + s_Initialized = 1/*inited*/; + CORE_UNLOCK; CORE_TRACE("[SOCK::InitializeAPI] End"); return eIO_Success; @@ -836,8 +835,8 @@ static EIO_Status s_Send(SOCK, const void*, size_t, size_t*, int); static EIO_Status s_InitAPI_(int secure) { - static const struct SOCKSSL_struct kNoSSL = { 0 }; - EIO_Status status = eIO_Success; + static const struct SOCKSSL_struct kNoSSL = { "", 0 }; + EIO_Status status; if (!s_Initialized && (status = s_Init()) != eIO_Success) return status; @@ -847,29 +846,36 @@ static EIO_Status s_InitAPI_(int secure) if (s_Initialized < 0) return eIO_NotSupported; - if (secure && !s_SSL) { - if (s_SSLSetup) { - SOCKSSL ssl = s_SSLSetup(); - if (ssl && ssl->Init) { - CORE_LOCK_WRITE; - if (!s_SSL) { - s_SSL = ((status = ssl->Init(s_Recv,s_Send)) == eIO_Success - ? ssl : &kNoSSL); - } - CORE_UNLOCK; - } else + if (!secure) + return eIO_Success; + + if (s_SSL) + return s_SSL == &kNoSSL ? eIO_NotSupported : eIO_Success; + + if (s_SSLSetup) { + CORE_LOCK_WRITE; + if (!s_SSL) { + SOCKSSL ssl; + if (!s_SSLSetup || !(ssl = s_SSLSetup())) { + s_SSL = &kNoSSL; status = eIO_NotSupported; - } else { - static int once = 1/*true*/; - if (once) { - once = 0/*false*/; - CORE_LOG(eLOG_Critical, "Secure socket layer (SSL) has not" - " been properly initialized in the NCBI Toolkit. " - " Have you forgotten to call SOCK_SetupSSL()?"); + } else{ + s_SSL = ((status = ssl->Init(s_Recv, s_Send)) == eIO_Success + ? ssl : &kNoSSL); } - status = eIO_NotSupported; + } else + status = s_SSL == &kNoSSL ? eIO_NotSupported : eIO_Success; + CORE_UNLOCK; + } else { + static void* /*bool*/ s_Once = 0/*false*/; + if (CORE_Once(&s_Once)) { + CORE_LOG(eLOG_Critical, "Secure socket layer (SSL) has not" + " been properly initialized in the NCBI Toolkit. " + " Have you forgotten to call SOCK_SetupSSL()?"); } + status = eIO_NotSupported; } + return status; } @@ -905,6 +911,22 @@ extern EIO_Status SOCK_InitializeAPI(void) } +/* Must be called under a lock */ +#ifdef __GNUC__ +inline +#endif /*__GNUC__*/ +static void x_ShutdownSSL(void) +{ + if (s_Initialized > 0) { + FSSLExit sslexit = s_SSLSetup && s_SSL ? s_SSL->Exit : 0; + s_SSLSetup = 0; + s_SSL = 0; + if (sslexit) + sslexit(); + } +} + + extern EIO_Status SOCK_ShutdownAPI(void) { if (s_Initialized < 0) @@ -920,13 +942,7 @@ extern EIO_Status SOCK_ShutdownAPI(void) } s_Initialized = -1/*deinited*/; - if (s_SSL) { - FSSLExit sslexit = s_SSL->Exit; - s_SSLSetup = 0; - s_SSL = 0; - if (sslexit) - sslexit(); - } + x_ShutdownSSL(); #ifdef NCBI_OS_MSWIN {{ @@ -1181,15 +1197,14 @@ static unsigned int s_gethostbyname_(const char* hostname, ESwitch log) /* a non-standard helper */ static unsigned int s_getlocalhostaddress(ESwitch reget, ESwitch log) { - static int once = 1/*true*/; + static void* /*bool*/ s_Once = 0/*false*/; /* cached IP address of the local host */ static unsigned int s_LocalHostAddress = 0; if (reget == eOn || (!s_LocalHostAddress && reget != eOff)) s_LocalHostAddress = s_gethostbyname_(0, log); if (s_LocalHostAddress) return s_LocalHostAddress; - if (once && reget != eOff) { - once = 0/*false*/; + if (!s_Once && reget != eOff && CORE_Once(&s_Once)) { CORE_LOGF_X(9, reget == eDefault ? eLOG_Warning : eLOG_Error, ("[SOCK::GetLocalHostAddress] " " Cannot obtain local host address%s", @@ -1201,7 +1216,7 @@ static unsigned int s_getlocalhostaddress(ESwitch reget, ESwitch log) static unsigned int s_gethostbyname(const char* hostname, ESwitch log) { - static int once = 1/*true*/; + static void* /*bool*/ s_Once = 0/*false*/; unsigned int retval = s_gethostbyname_(hostname, log); if (!retval) { @@ -1212,9 +1227,9 @@ static unsigned int s_gethostbyname(const char* hostname, ESwitch log) info.host = hostname; s_ErrorCallback(&info); } - } else if (once && !hostname && SOCK_IsLoopbackAddress(retval)) { + } else if (!s_Once && !hostname + && SOCK_IsLoopbackAddress(retval) && CORE_Once(&s_Once)) { char addr[40 + 1]; - once = 0/*false*/; *addr = " "[SOCK_ntoa(retval, addr + 1, sizeof(addr) - 1) ? 1 : 0]; CORE_LOGF_X(155, eLOG_Warning, ("[SOCK::gethostbyname] " @@ -1373,14 +1388,14 @@ static char* s_gethostbyaddr_(unsigned int host, char* name, static const char* s_gethostbyaddr(unsigned int host, char* name, size_t namesize, ESwitch log) { - static int once = 1/*true*/; + static void* /*bool*/ s_Once = 0/*false*/; const char* retval = s_gethostbyaddr_(host, name, namesize, log); - if (once && retval + if (!s_Once && retval && ((SOCK_IsLoopbackAddress(host) && strncasecmp(retval, "localhost", 9) != 0) || (!host - && strncasecmp(retval, "localhost", 9) == 0))) { - once = 0/*false*/; + && strncasecmp(retval, "localhost", 9) == 0)) + && CORE_Once(&s_Once)) { CORE_LOGF_X(10, eLOG_Warning, ("[SOCK::gethostbyaddr] " " Got \"%.*s\" for %s address", MAXHOSTNAMELEN, @@ -1398,6 +1413,9 @@ static const char* s_gethostbyaddr(unsigned int host, char* name, /* Switch the specified socket I/O between blocking and non-blocking mode */ +#ifdef __GNUC__ +inline +#endif /*__GNUC__*/ static int/*bool*/ s_SetNonblock(TSOCK_Handle sock, int/*bool*/ nonblock) { #if defined(NCBI_OS_MSWIN) @@ -1415,6 +1433,9 @@ static int/*bool*/ s_SetNonblock(TSOCK_Handle sock, int/*bool*/ nonblock) /* Set close-on-exec flag */ +#ifdef __GNUC__ +inline +#endif /*__GNUC__*/ static int/*bool*/ s_SetCloexec(TSOCK_Handle x_sock, int/*bool*/ cloexec) { #if defined(NCBI_OS_UNIX) @@ -1430,6 +1451,9 @@ static int/*bool*/ s_SetCloexec(TSOCK_Handle x_sock, int/*bool*/ cloexec) /*ARGSUSED*/ +#ifdef __GNUC__ +inline +#endif /*__GNUC__*/ static int/*bool*/ s_SetReuseAddress(TSOCK_Handle x_sock, int/*bool*/ on_off) { #if defined(NCBI_OS_UNIX) || defined(NCBI_OS_MSWIN) @@ -1448,6 +1472,9 @@ static int/*bool*/ s_SetReuseAddress(TSOCK_Handle x_sock, int/*bool*/ on_off) #ifdef SO_KEEPALIVE +#ifdef __GNUC__ +inline +#endif /*__GNUC__*/ static int/*bool*/ s_SetKeepAlive(TSOCK_Handle x_sock, int/*bool*/ on_off) { # ifdef NCBI_OS_MSWIN @@ -1462,6 +1489,9 @@ static int/*bool*/ s_SetKeepAlive(TSOCK_Handle x_sock, int/*bool*/ on_off) #ifdef SO_OOBINLINE +#ifdef __GNUC__ +inline +#endif /*__GNUC__*/ static int/*bool*/ s_SetOobInline(TSOCK_Handle x_sock, int/*bool*/ on_off) { # ifdef NCBI_OS_MSWIN @@ -1692,7 +1722,7 @@ static EIO_Status s_Select_(size_t n, ready = bad = 1/*true*/; continue; } - count++; + ++count; # endif /*NCBI_OS_MSWIN*/ } assert(i >= n); @@ -3214,7 +3244,8 @@ static EIO_Status s_Send(SOCK sock, for (;;) { /* optionally auto-resume if interrupted */ int error = 0; - int x_written = send(sock->sock, (void*) data, WIN_INT_CAST size, flag < 0 ? MSG_OOB : 0); + int x_written = send(sock->sock, (void*) data, WIN_INT_CAST size, + flag < 0 ? MSG_OOB : 0); if (x_written >= 0 || (x_written < 0 && ((error = SOCK_ERRNO) == SOCK_EPIPE || @@ -3946,13 +3977,16 @@ static EIO_Status s_Close_(SOCK sock, int abort) static EIO_Status s_Close(SOCK sock) { -#if defined NCBI_MONKEY - /* Not interception of close(). + EIO_Status status; + +#ifdef NCBI_MONKEY + /* Not interception of close(). We only tell Monkey to "forget" this socket */ - if (g_MONKEY_Close != NULL) + if (g_MONKEY_Close) g_MONKEY_Close(sock->sock); -#endif /* NCBI_MONKEY */ - EIO_Status status = s_Close_(sock, 0/*orderly*/); +#endif /*NCBI_MONKEY*/ + + status = s_Close_(sock, 0/*orderly*/); if (s_ErrHook && status != eIO_Success) { SSOCK_ErrInfo info; char addr[40]; @@ -3972,8 +4006,8 @@ static EIO_Status s_Close(SOCK sock) info.status = status; s_ErrorCallback(&info); } - return status; + return status; } @@ -3999,6 +4033,7 @@ static EIO_Status s_Connect_(SOCK sock, TSOCK_Handle x_sock; EIO_Status status; int error; + int type; int n; assert(sock->type == eSocket && sock->side == eSOCK_Client); @@ -4009,21 +4044,30 @@ static EIO_Status s_Connect_(SOCK sock, if (sock->session) { FSSLCreate sslcreate = s_SSL ? s_SSL->Create : 0; + const char* hostname = 0; void* session; assert(sock->sock == SOCK_INVALID); assert(sock->session == SESSION_INVALID); +#ifdef NCBI_OS_UNIX + if (!sock->path[0]) +#endif /*NCBI_OS_UNIX*/ + hostname = host; + if (!hostname || SOCK_isip(hostname)) + hostname = ""; if (!sslcreate) { session = 0; error = 0; } else - session = sslcreate(eSOCK_Client, sock, sock->cred, &error); + session = sslcreate(eSOCK_Client,sock,hostname,sock->cred,&error); if (!session) { const char* strerr = s_StrError(sock, error); CORE_LOGF_ERRNO_EXX(131, eLOG_Error, error, strerr ? strerr : "", ("%s[SOCK::Connect] " - " Failed to initialize secure session", - s_ID(sock, _id))); + " %s to initialize secure session%s%s", + s_ID(sock, _id), + sslcreate ? "Unable" : "Failed", + *hostname ? " with " : "", hostname)); UTIL_ReleaseBuffer(strerr); return eIO_NotSupported; } @@ -4079,7 +4123,17 @@ static EIO_Status s_Connect_(SOCK sock, } /* create the new socket */ - if ((x_sock = socket(addr.sa.sa_family, SOCK_STREAM, 0)) == SOCK_INVALID) { + type = SOCK_STREAM; +#ifdef NCBI_OS_LINUX +# ifdef SOCK_NONBLOCK + type |= SOCK_NONBLOCK; +# endif /*SOCK_NONBLOCK*/ +# ifdef SOCK_CLOEXEC + if (!sock->crossexec || sock->session) + type |= SOCK_CLOEXEC; +# endif /*SOCK_CLOEXEC*/ +#endif /*NCBI_OS_LINUX*/ + if ((x_sock = socket(addr.sa.sa_family, type, 0)) == SOCK_INVALID) { const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO); CORE_LOGF_ERRNO_EXX(23, eLOG_Error, error, strerr ? strerr : "", @@ -4095,7 +4149,14 @@ static EIO_Status s_Connect_(SOCK sock, sock->w_status = eIO_Success; assert(sock->w_len == 0); -#ifdef NCBI_OS_MSWIN +#ifdef NCBI_MONKEY + /* Bind created x_sock to the sock in Chaos Monkey, this information is + important to keep rules working */ + if (g_MONKEY_SockHasSocket) + g_MONKEY_SockHasSocket(sock, x_sock); +#endif /*NCBI_MONKEY*/ + +#if defined(NCBI_OS_MSWIN) assert(!sock->event); if (!(sock->event = WSACreateEvent())) { DWORD err = GetLastError(); @@ -4121,7 +4182,7 @@ static EIO_Status s_Connect_(SOCK sock, s_Close_(sock, -2/*silent abort*/); return eIO_Unknown; } -#else +#elif !defined(NCBI_OS_LINUX) || !defined(SOCK_NONBLOCK) /* set non-blocking mode */ if (!s_SetNonblock(x_sock, 1/*true*/)) { const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO); @@ -4161,27 +4222,29 @@ static EIO_Status s_Connect_(SOCK sock, #endif /*SO_OOBINLINE*/ } +#if !defined(NCBI_OS_LINUX) || !defined(SOCK_CLOEXEC) if ((!sock->crossexec || sock->session) && !s_SetCloexec(x_sock, 1)) { const char* strerr; -#ifdef NCBI_OS_MSWIN +# ifdef NCBI_OS_MSWIN DWORD err = GetLastError(); strerr = s_WinStrerror(err); error = err; -#else +# else error = errno; strerr = SOCK_STRERROR(error); -#endif /*NCBI_OS_MSWIN*/ +# endif /*NCBI_OS_MSWIN*/ CORE_LOGF_ERRNO_EXX(129, eLOG_Warning, error, strerr ? strerr : "", ("%s[SOCK::Connect] " " Cannot set socket close-on-exec mode", s_ID(sock, _id))); -#ifdef NCBI_OS_MSWIN +# ifdef NCBI_OS_MSWIN UTIL_ReleaseBufferOnHeap(strerr); -#else +# else UTIL_ReleaseBuffer(strerr); -#endif /*NCBI_OS_MSWIN*/ +# endif /*NCBI_OS_MSWIN*/ } +#endif /*!NCBI_OS_LINUX || !SOCK_CLOEXEC*/ /* establish connection to the peer */ sock->connected = 0/*false*/; @@ -4571,14 +4634,15 @@ static EIO_Status s_CreateOnTop(const void* handle, session = 0; error = 0; } else - session = sslcreate(eSOCK_Client, x_sock, cred, &error); + session = sslcreate(eSOCK_Client, x_sock, 0, cred, &error); if (!session) { const char* strerr = s_StrError(x_sock, error); CORE_LOGF_ERRNO_EXX(132, eLOG_Error, error, strerr ? strerr : "", ("%s[SOCK::CreateOnTop] " - " Failed to initialize secure session", - s_ID(x_sock, _id))); + " %s to initialize secure session", + s_ID(x_sock, _id), + sslcreate ? "Unable" : "Failed")); UTIL_ReleaseBuffer(strerr); x_sock->sock = SOCK_INVALID; SOCK_Close(x_sock); @@ -4677,6 +4741,7 @@ static EIO_Status s_CreateListening(const char* path, mode_t u; #endif /*NCBI_OS_UNIX*/ const char* cp; + int type; #ifdef NCBI_OS_MSWIN WSAEVENT event; #endif /*NCBI_OS_MSWIN*/ @@ -4718,7 +4783,17 @@ static EIO_Status s_CreateListening(const char* path, } /* create new(listening) socket */ - if ((x_lsock = socket(addr.sa.sa_family, SOCK_STREAM, 0)) == SOCK_INVALID){ + type = SOCK_STREAM; +#ifdef NCBI_OS_LINUX +# ifdef SOCK_NONBLOCK + type |= SOCK_NONBLOCK; +# endif /*SOCK_NONBLOCK*/ +# ifdef SOCK_CLOEXEC + if (!(flags & fSOCK_KeepOnExec)) + type |= SOCK_CLOEXEC; +# endif /*SOCK_CLOEXEC*/ +#endif /*NCBI_OS_LINUX*/ + if ((x_lsock = socket(addr.sa.sa_family, type, 0)) == SOCK_INVALID){ const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO); if (!path) { if (port) @@ -4741,10 +4816,10 @@ static EIO_Status s_CreateListening(const char* path, const char* failed = 0; #if defined(NCBI_OS_MSWIN) && defined(SO_EXCLUSIVEADDRUSE) /* The use of this option comes with caveats, but it is better - * to use it rather than having (or leaving) a chance for another - * process (which uses SO_REUSEADDR, maliciously or not) be able - * to bind to the same port number and snatch incoming connections. - * Until a connection exists originated from the port with this + * to use it rather than to have (or leave) a chance for another + * process (which uses SO_REUSEADDR, maliciously or not) to be able + * to bind to the same port number, and snatch incoming connections. + * Until a connection exists, that originated from the port with this * option set, the port (even if the listening instance was closed) * cannot be re-bound (important for service restarts!). See MSDN. */ @@ -4756,7 +4831,7 @@ static EIO_Status s_CreateListening(const char* path, #elif !defined(NCBI_OS_MSWIN) /* * It was confirmed(?) that at least on Solaris 2.5 this precaution: - * 1) makes the address released immediately upon the process + * 1) makes the address(port) released immediately upon the process * termination; * 2) still issues EADDRINUSE error on the attempt to bind() to the * same address being in-use by a living process (if SOCK_STREAM). @@ -4864,7 +4939,7 @@ static EIO_Status s_CreateListening(const char* path, assert((path && !port) || (port && !path)); -#ifdef NCBI_OS_MSWIN +#if defined(NCBI_OS_MSWIN) if (!(event = WSACreateEvent())) { DWORD err = GetLastError(); const char* strerr = s_WinStrerror(err); @@ -4892,7 +4967,7 @@ static EIO_Status s_CreateListening(const char* path, WSACloseEvent(event); return eIO_Unknown; } -#else +#elif !defined(NCBI_OS_LINUX) || !defined(SOCK_NONBLOCK) /* set non-blocking mode */ if (!s_SetNonblock(x_lsock, 1/*true*/)) { const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO); @@ -4910,7 +4985,7 @@ static EIO_Status s_CreateListening(const char* path, SOCK_CLOSE(x_lsock); return eIO_Unknown; } -#endif /*NCBI_OS_MSWIN*/ +#endif /* listen */ if (listen(x_lsock, backlog) != 0) { @@ -4956,16 +5031,17 @@ static EIO_Status s_CreateListening(const char* path, (*lsock)->event = event; #endif /*NCBI_OS*/ +#if !defined(NCBI_OS_LINUX) || !defined(SOCK_CLOEXEC) if (!(flags & fSOCK_KeepOnExec) && !s_SetCloexec(x_lsock, 1/*true*/)) { const char* strerr; -#ifdef NCBI_OS_MSWIN +# ifdef NCBI_OS_MSWIN DWORD err = GetLastError(); strerr = s_WinStrerror(err); error = err; -#else +# else error = errno; strerr = SOCK_STRERROR(error); -#endif /*NCBI_OS_MSWIN*/ +# endif /*NCBI_OS_MSWIN*/ if (!path) { sprintf(_id, ":%hu", port); cp = _id; @@ -4976,12 +5052,13 @@ static EIO_Status s_CreateListening(const char* path, ("LSOCK#%u[%u]@%s: [LSOCK::Create] " " Cannot set socket close-on-exec mode", x_id, (unsigned int) x_lsock, cp)); -#ifdef NCBI_OS_MSWIN +# ifdef NCBI_OS_MSWIN UTIL_ReleaseBufferOnHeap(strerr); -#else +# else UTIL_ReleaseBuffer(strerr); -#endif /*NCBI_OS_MSWIN*/ +# endif /*NCBI_OS_MSWIN*/ } +#endif /*!NCBI_OS_LINUX || !SOCK_CLOEXEC*/ /* statistics & logging */ if ((*lsock)->log == eOn || ((*lsock)->log == eDefault && s_Log == eOn)){ @@ -5803,7 +5880,7 @@ extern EIO_Status TRIGGER_Set(TRIGGER trigger) # if defined(NCBI_OS_UNIX) - if (!NCBI_SwapPointers((void**) &trigger->isset.ptr, (void*) 1/*true*/)) { + if (CORE_Once((void**) &trigger->isset.ptr)) { if (write(trigger->out, "", 1) < 0 && errno != EAGAIN) return eIO_Unknown; } @@ -6489,22 +6566,23 @@ extern EIO_Status SOCK_Poll(size_t n, size_t* n_ready) { EIO_Status status; -#if defined NCBI_MONKEY + struct timeval tv; + size_t i; + +#ifdef NCBI_MONKEY int/*bool*/ call_intercepted = 0; - size_t orig_n = n; SSOCK_Poll* orig_polls = polls; /* to know if 'polls' was replaced */ EIO_Status mnk_status = -1; - if (g_MONKEY_Poll != NULL) { + size_t orig_n = n; + if (g_MONKEY_Poll) { /* Not a poll function itself, just removes some of "polls" items */ call_intercepted = g_MONKEY_Poll(&n, &polls, &mnk_status); } - /* Even if call was intercepted, s_Select continues as if nothing - happened, because what we did is just removed some SSOCK_Poll pointers. - The changes made in s_Select will appear in the original array, but only - for those SSOCK_Poll's that were left by Monkey */ -#endif /* defined NCBI_MONKEY */ - struct timeval tv; - size_t i; + /* Even if call was intercepted, s_Select() continues as if nothing + happened, because what we did was just removed some SSOCK_Poll pointers. + The changes made in s_Select() will appear in the original array, but + only for those SSOCK_Poll's that were left by Monkey */ +#endif /*NCBI_MONKEY*/ if (n && !polls) { if (n_ready) @@ -6535,25 +6613,23 @@ extern EIO_Status SOCK_Poll(size_t n, } status = s_SelectStallsafe(n, polls, s_to2tv(timeout, &tv), n_ready); -#if defined NCBI_MONKEY - /* Copy poll results to the original array. Probably Monkey excluded - * some sockets from array, so we need two iterators */ + +#ifdef NCBI_MONKEY + /* Copy poll results to the original array. Probably Monkey excluded some + sockets from array, so we need two iterators */ if (orig_polls != polls) { - size_t orig_iter = 0, new_iter = 0; - /* First - initialize events with eIO_Open (no event) */ + size_t orig_iter, new_iter; for (orig_iter = 0; orig_iter < orig_n; orig_iter++) { - orig_polls[orig_iter].event = eIO_Open /* no event */; - orig_polls[orig_iter].revent = eIO_Open /* no event */; - } - for (; new_iter < n; new_iter++) { - while (orig_iter < orig_n) { - if (orig_polls[orig_iter].sock->sock - == polls[new_iter].sock->sock) { - orig_polls[orig_iter].event = polls[new_iter].event; - orig_polls[orig_iter].revent = polls[new_iter].revent; - break; /* Item found! Now increase new_iter */ + orig_polls[orig_iter].event = eIO_Open/*no event*/; + orig_polls[orig_iter].revent = eIO_Open/*no event*/; + } + for (new_iter = 0; new_iter < n; new_iter++) { + for (orig_iter = 0; orig_iter < orig_n; orig_iter++) { + if (orig_polls[orig_iter].sock->sock + == polls[new_iter].sock->sock) { + orig_polls[orig_iter] = polls[new_iter]; + break; } - orig_iter++; } } free(polls); @@ -6562,7 +6638,8 @@ extern EIO_Status SOCK_Poll(size_t n, return mnk_status; } } -#endif /* defined NCBI_MONKEY */ +#endif /*NCBI_MONKEY*/ + return status; } @@ -7007,11 +7084,10 @@ extern char* SOCK_GetPeerAddressStringEx(SOCK sock, case eSAF_Full: #ifdef NCBI_OS_UNIX if (sock->path[0]) { - size_t len = strlen(sock->path); - if (len < bufsize) + if ((len = strlen(sock->path)) < bufsize) memcpy(buf, sock->path, len + 1); else - return 0; + return 0/*error*/; } else #endif /*NCBI_OS_UNIX*/ if (!SOCK_HostPortToString(sock->host, sock->port, buf, bufsize)) @@ -7023,10 +7099,10 @@ extern char* SOCK_GetPeerAddressStringEx(SOCK sock, *buf = '\0'; else #endif /*NCBI_OS_UNIX*/ - if ((len = (size_t) sprintf(port, "%hu", sock->port)) >= bufsize) - return 0/*error*/; - else + if ((len = (size_t) sprintf(port, "%hu", sock->port)) < bufsize) memcpy(buf, port, len + 1); + else + return 0/*error*/; break; case eSAF_IP: #ifdef NCBI_OS_UNIX @@ -7199,6 +7275,7 @@ extern EIO_Status DSOCK_Create(SOCK* sock) extern EIO_Status DSOCK_CreateEx(SOCK* sock, TSOCK_Flags flags) { + int type; #ifdef NCBI_OS_MSWIN HANDLE event; #endif /*NCBI_OS_MSWIN*/ @@ -7212,8 +7289,18 @@ extern EIO_Status DSOCK_CreateEx(SOCK* sock, TSOCK_Flags flags) if ((flags & fSOCK_Secure) || s_InitAPI(0) != eIO_Success) return eIO_NotSupported; + type = SOCK_DGRAM; +#ifdef NCBI_OS_LINUX +# ifdef SOCK_NONBLOCK + type |= SOCK_NONBLOCK; +# endif /*SOCK_NONBLOCK*/ +# ifdef SOCK_CLOEXEC + if (!(flags & fSOCK_KeepOnExec)) + type |= SOCK_CLOEXEC; +# endif /*SOCK_CLOEXEC*/ +#endif /*NCBI_OS_LINUX*/ /* create new datagram socket */ - if ((x_sock = socket(AF_INET, SOCK_DGRAM, 0)) == SOCK_INVALID) { + if ((x_sock = socket(AF_INET, type, 0)) == SOCK_INVALID) { const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO); CORE_LOGF_ERRNO_EXX(76, eLOG_Error, error, strerr ? strerr : "", @@ -7224,7 +7311,7 @@ extern EIO_Status DSOCK_CreateEx(SOCK* sock, TSOCK_Flags flags) return eIO_Unknown; } -#ifdef NCBI_OS_MSWIN +#if defined(NCBI_OS_MSWIN) if (!(event = WSACreateEvent())) { DWORD err = GetLastError(); const char* strerr = s_WinStrerror(err); @@ -7250,7 +7337,7 @@ extern EIO_Status DSOCK_CreateEx(SOCK* sock, TSOCK_Flags flags) WSACloseEvent(event); return eIO_Unknown; } -#else +#elif !defined(NCBI_OS_LINUX) || !defined(SOCK_NONBLOCK) /* set to non-blocking mode */ if (!s_SetNonblock(x_sock, 1/*true*/)) { const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO); @@ -7263,7 +7350,7 @@ extern EIO_Status DSOCK_CreateEx(SOCK* sock, TSOCK_Flags flags) SOCK_CLOSE(x_sock); return eIO_Unknown; } -#endif /*NCBI_OS_MSWIN*/ +#endif if (!(*sock = (SOCK) calloc(1, sizeof(**sock)))) { SOCK_CLOSE(x_sock); @@ -7293,28 +7380,30 @@ extern EIO_Status DSOCK_CreateEx(SOCK* sock, TSOCK_Flags flags) BUF_SetChunkSize(&(*sock)->r_buf, SOCK_BUF_CHUNK_SIZE); BUF_SetChunkSize(&(*sock)->w_buf, SOCK_BUF_CHUNK_SIZE); +#if !defined(NCBI_OS_LINUX) || !defined(SOCK_CLOEXEC) if (!(*sock)->crossexec && !s_SetCloexec(x_sock, 1/*true*/)) { const char* strerr; char _id[MAXIDLEN]; -#ifdef NCBI_OS_MSWIN +# ifdef NCBI_OS_MSWIN DWORD err = GetLastError(); strerr = s_WinStrerror(err); error = err; -#else +# else error = errno; strerr = SOCK_STRERROR(error); -#endif /*NCBI_OS_MSWIN*/ +# endif /*NCBI_OS_MSWIN*/ CORE_LOGF_ERRNO_EXX(130, eLOG_Warning, error, strerr ? strerr : "", ("%s[DSOCK::Create] Cannot set" " socket close-on-exec mode", s_ID(*sock, _id))); -#ifdef NCBI_OS_MSWIN +# ifdef NCBI_OS_MSWIN UTIL_ReleaseBufferOnHeap(strerr); -#else +# else UTIL_ReleaseBuffer(strerr); -#endif /*NCBI_OS_MSWIN*/ +# endif /*NCBI_OS_MSWIN*/ } +#endif /*!NCBI_OS_LINUX || !SOCK_CLOEXEC*/ /* statistics & logging */ if ((*sock)->log == eOn || ((*sock)->log == eDefault && s_Log == eOn)) @@ -8236,35 +8325,43 @@ extern size_t SOCK_HostPortToString(unsigned int host, */ -extern void SOCK_SetupSSL(FSSLSetup setup) +void SOCK_SetupSSLInternal(FSSLSetup setup, int/*bool*/ init) { CORE_LOCK_WRITE; - if (!setup) { - s_SSLSetup = 0; - if (s_SSL) { - FSSLExit sslexit = s_SSL->Exit; - s_SSL = 0; - if (sslexit) - sslexit(); - } - } else if (s_SSLSetup != setup) { - if (!s_SSLSetup) - s_SSLSetup = setup; - else if (s_Initialized < 0) - s_SSLSetup = 0; - else + if (!setup) + x_ShutdownSSL(); + else if (s_SSLSetup != setup || (s_SSL && init)) { + if (s_SSLSetup) { + if (init) + s_SSL = 0; /* NB: race / memory leak if was non-NULL ! */ + CORE_UNLOCK; CORE_LOG(eLOG_Critical, "Cannot reset SSL while it is in use"); + return; + } else + assert(!s_SSL); + s_SSLSetup = s_Initialized < 0 ? 0 : setup; } - g_CORE_Set |= eCORE_SetSSL; CORE_UNLOCK; } +extern void SOCK_SetupSSL(FSSLSetup setup) +{ + SOCK_SetupSSLInternal(setup, 0/*false*/); +} + + extern EIO_Status SOCK_SetupSSLEx(FSSLSetup setup) { - SOCK_SetupSSL(setup); + SOCK_SetupSSLInternal(setup, 0/*false*/); return setup ? s_InitAPI(1/*secure*/) : eIO_Success; } + + +extern const char* SOCK_SSLName(void) +{ + return !s_SSLSetup ? 0 : !s_SSL ? "" : s_SSL->Name; +} diff --git a/c++/src/connect/ncbi_socket_connector.c b/c++/src/connect/ncbi_socket_connector.c index 19f12d5a..cd53a56d 100644 --- a/c++/src/connect/ncbi_socket_connector.c +++ b/c++/src/connect/ncbi_socket_connector.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_socket_connector.c 462719 2015-03-20 16:47:04Z lavr $ +/* $Id: ncbi_socket_connector.c 530222 2017-03-13 15:02:18Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -69,7 +69,7 @@ typedef struct { #ifdef __GNUC__ inline #endif /*__GNUC__*/ -static const char* x_GetType(SSockConnector* xxx) +static const char* x_GetType(SSockConnector* unused) { return g_kNcbiSockNameAbbr; /*NB: Important!*/ } diff --git a/c++/src/connect/ncbi_strerror.c b/c++/src/connect/ncbi_strerror.c index ca71e70e..436661f1 100644 --- a/c++/src/connect/ncbi_strerror.c +++ b/c++/src/connect/ncbi_strerror.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_strerror.c 487456 2015-12-17 18:55:21Z ucko $ +/* $Id: ncbi_strerror.c 530912 2017-03-19 16:36:07Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -52,31 +52,7 @@ static const char* s_WinStrdup(const char* str) char* s = (char*) LocalAlloc(LMEM_FIXED, ++n * sizeof(*s)); return s ? (const char*) memcpy(s, str, n) : 0; } - -# define MSWIN_STRDUP(s) s_WinStrdup(s) - -# ifndef UTIL_ReleaseBuffer -# define UTIL_ReleaseBuffer(x) UTIL_ReleaseBufferOnHeap(x) -# endif - -# else /*NCBI_OS_MSWIN && _UNICODE*/ - -# define MSWIN_STRDUP(s) (s) - -# ifndef UTIL_TcharToUtf8 -# define UTIL_TcharToUtf8(x) (x) -# endif - -# ifndef UTIL_ReleaseBuffer -# define UTIL_ReleaseBuffer(x) /*void*/ -# endif - -# endif /*NCBI_OS_MSWIN && _UNICODE*/ - - -# ifdef NCBI_OS_MSWIN - -# ifdef _UNICODE +# define ERR_STRDUP(s) s_WinStrdup(s) extern const char* UTIL_TcharToUtf8(const TCHAR* str) { @@ -93,9 +69,30 @@ extern const char* UTIL_TcharToUtf8(const TCHAR* str) return s; } -# endif /*_UNICODE*/ +# ifndef UTIL_ReleaseBuffer(x) +# define UTIL_ReleaseBuffer(x) UTIL_ReleaseBufferOnHeap(x) +# endif + +# else /*NCBI_OS_MSWIN && _UNICODE*/ + +# define ERR_STRDUP(s) strdup(s) + +# ifdef UTIL_TcharToUtf8 +# undef UTIL_TcharToUtf8 +# endif +# define UTIL_TcharToUtf8(x) strdup(x) + +# ifdef UTIL_ReleaseBuffer +# undef UTIL_ReleaseBuffer +# endif +# define UTIL_ReleaseBuffer(x) free((void*)(x)) + +# endif /*NCBI_OS_MSWIN && _UNICODE*/ + + +# ifdef NCBI_OS_MSWIN -extern void UTIL_ReleaseBufferOnHeap(const void* ptr) +extern void UTIL_ReleaseBufferOnHeap(const void* ptr) { if (ptr) LocalFree((HLOCAL) ptr); @@ -332,20 +329,20 @@ static const char* s_StrErrorInternal(int error) if (errsup[i].erroff < error) { const char* errstr = errsup[i].errfun(error - errsup[i].erroff); if (errstr && *errstr) - return errstr; + return ERR_STRDUP(errstr); } } #endif /*NCBI_OS_LINUX || NCBI_OS_CYGWIN*/ for (i = 0; i < sizeof(errmap) / sizeof(errmap[0]) - 1/*dummy*/; ++i) { if (errmap[i].errnum == error) - return MSWIN_STRDUP(errmap[i].errstr); + return ERR_STRDUP(errmap[i].errstr); } # if defined(NCBI_OS_MSWIN) && defined(_UNICODE) return UTIL_TcharToUtf8(_wcserror(error)); # else - return strerror(error); + return ERR_STRDUP(strerror(error)); # endif /*NCBI_OS_MSWIN && _UNICODE*/ } diff --git a/c++/src/connect/ncbi_tls.c b/c++/src/connect/ncbi_tls.c new file mode 100644 index 00000000..0e0a7ba7 --- /dev/null +++ b/c++/src/connect/ncbi_tls.c @@ -0,0 +1,98 @@ +/* $Id: ncbi_tls.c 537331 2017-05-30 19:56:20Z lavr $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * SSL support in connection library + * + */ + +#include "ncbi_ansi_ext.h" +#include "ncbi_connssl.h" +#include "ncbi_priv.h" +#include +#include +#include +#include + + +/* Establish default here! */ +#if defined(HAVE_LIBMBEDTLS) || defined(NCBI_CXX_TOOLKIT) +# define NcbiSetupDefaultTls NcbiSetupMbedTls +#elif defined(HAVE_LIBGNUTLS) +# define NcbiSetupDefaultTls NcbiSetupGnuTls +#else +# define NcbiSetupDefaultTls 0 +#endif + + +/*ARGSUSED*/ +#ifdef __cplusplus +extern "C" +#endif /*__cplusplus*/ +static EIO_Status s_NoTlsInit(FSSLPull unused_pull, FSSLPush unused_push) +{ + CORE_LOG(eLOG_Critical, "SSL has been explicitly disabled"); + return eIO_NotSupported; +} + + +static SOCKSSL x_SetupNoTls(void) +{ + static const struct SOCKSSL_struct kNoTlsOps = { + "NONE", + s_NoTlsInit + }; + CORE_LOG(eLOG_Trace, "SSL has been explicitly disabled"); + return &kNoTlsOps; +} + + +extern SOCKSSL NcbiSetupTls(void) +{ + static FSSLSetup s_Setup = (FSSLSetup)(-1L); + if (s_Setup == (FSSLSetup)(-1L)) { + char str[32]; + ConnNetInfo_GetValue(0, "USESSL", str, sizeof(str), 0); + if (!ConnNetInfo_Boolean(str) && *str) { + if (strcmp (str, "0") == 0 || + strcasecmp(str, "no") == 0 || + strcasecmp(str, "off") == 0 || + strcasecmp(str, "false") == 0) { + s_Setup = x_SetupNoTls; + } else if (strcasecmp(str, "GNUTLS") == 0) { + s_Setup = NcbiSetupGnuTls; + } else if (strcasecmp(str, "MBEDTLS") == 0) { + s_Setup = NcbiSetupMbedTls; + } else { + CORE_LOGF(eLOG_Critical, ("Unknown TLS provider \"%s\"", str)); + s_Setup = 0/*unknown provider*/; + } + } else if (!(s_Setup = NcbiSetupDefaultTls)) + CORE_LOG(eLOG_Critical, "No TLS support included in this build"); + } + return s_Setup ? s_Setup() : 0; +} diff --git a/c++/src/connect/ncbi_util.c b/c++/src/connect/ncbi_util.c index 55205f56..5d316b29 100644 --- a/c++/src/connect/ncbi_util.c +++ b/c++/src/connect/ncbi_util.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_util.c 507875 2016-07-21 21:24:44Z lavr $ +/* $Id: ncbi_util.c 545592 2017-09-07 18:06:13Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -53,8 +53,10 @@ # include # endif /*NCBI_OS_LINUX*/ # include -# include +# include +# include # include +# include #endif /*NCBI_OS_UNIX*/ #if defined(NCBI_OS_MSWIN) || defined(NCBI_OS_CYGWIN) # define WIN32_LEAN_AND_MEAN @@ -348,8 +350,8 @@ extern const char* NcbiMessagePlusError extern char* LOG_ComposeMessage -(const SLOG_Handler* call_data, - TLOG_FormatFlags format_flags) +(const SLOG_Message* mess, + TLOG_FormatFlags flags) { static const char kRawData_Begin[] = "\n#################### [BEGIN] Raw Data (%lu byte%s):\n"; @@ -370,18 +372,18 @@ extern char* LOG_ComposeMessage size_t total_len; /* Adjust formatting flags */ - if (call_data->level == eLOG_Trace && !(format_flags & fLOG_None)) - format_flags |= fLOG_Full; - if (format_flags == fLOG_Default) { + if (mess->level == eLOG_Trace && !(flags & fLOG_None)) + flags |= fLOG_Full; + if (flags == fLOG_Default) { #if !defined(_DEBUG) || defined(NDEBUG) - format_flags = fLOG_Short; + flags = fLOG_Short; #else - format_flags = fLOG_Full; + flags = fLOG_Full; #endif /*!_DEBUG || NDEBUG*/ } /* Pre-calculate total message length */ - if ((format_flags & fLOG_DateTime) != 0) { + if ((flags & fLOG_DateTime) != 0) { #ifdef NCBI_OS_MSWIN /*Should be compiler-dependent but C-Tkit lacks it*/ _strdate(&datetime[datetime_len]); datetime_len += strlen(&datetime[datetime_len]); @@ -410,19 +412,18 @@ extern char* LOG_ComposeMessage datetime_len = strftime(datetime, sizeof(datetime), timefmt, tm); #endif /*NCBI_OS_MSWIN*/ } - if ((format_flags & fLOG_Level) != 0 - && (call_data->level != eLOG_Note - || !(format_flags & fLOG_OmitNoteLevel))) { - level = LOG_LevelStr(call_data->level); + if ((flags & fLOG_Level) != 0 + && (mess->level != eLOG_Note || !(flags & fLOG_OmitNoteLevel))) { + level = LOG_LevelStr(mess->level); level_len = strlen(level) + 2; } - if ((format_flags & fLOG_Module) != 0 && - call_data->module && *call_data->module) { - module_len = strlen(call_data->module) + 3; + if ((flags & fLOG_Module) != 0 + && mess->module && *mess->module) { + module_len = strlen(mess->module) + 3; } - if ((format_flags & fLOG_Function) != 0 && - call_data->func && *call_data->func) { - function = call_data->func; + if ((flags & fLOG_Function) != 0 + && mess->func && *mess->func) { + function = mess->func; if (!module_len) function_len = 3; function_len += strlen(function) + 2; @@ -430,19 +431,18 @@ extern char* LOG_ComposeMessage function_len = 0; } else function = 0; - if ((format_flags & fLOG_FileLine) != 0 && - call_data->file && *call_data->file) { - file_line_len = 12 + strlen(call_data->file) + 11; - } - if (call_data->message && *call_data->message) { - message_len = strlen(call_data->message); + if ((flags & fLOG_FileLine) != 0 + && mess->file && *mess->file) { + file_line_len = 12 + strlen(mess->file) + 11; } + if (mess->message && *mess->message) + message_len = strlen(mess->message); - if (call_data->raw_size) { + if (mess->raw_size) { data_len = (sizeof(kRawData_Begin) + 20 + UTIL_PrintableStringSize((const char*) - call_data->raw_data, - call_data->raw_size) + + mess->raw_data, + mess->raw_size) + sizeof(kRawData_End)); } @@ -462,18 +462,18 @@ extern char* LOG_ComposeMessage } if (file_line_len) { s += sprintf(s, "\"%s\", line %d: ", - call_data->file, (int) call_data->line); + mess->file, (int) mess->line); } if (module_len | function_len) *s++ = '['; if (module_len) { - memcpy(s, call_data->module, module_len -= 3); + memcpy(s, mess->module, module_len -= 3); s += module_len; } if (function_len) { memcpy(s, "::", 2); s += 2; - memcpy(s, function, function_len -= module_len ? 2 : 5); + memcpy(s, function, function_len -= (module_len ? 2 : 5)); s += function_len; } if (module_len | function_len) { @@ -487,18 +487,18 @@ extern char* LOG_ComposeMessage *s++ = ' '; } if (message_len) { - memcpy(s, call_data->message, message_len); + memcpy(s, mess->message, message_len); s += message_len; } if (data_len) { s += sprintf(s, kRawData_Begin, - (unsigned long) call_data->raw_size, - &"s"[call_data->raw_size == 1]); + (unsigned long) mess->raw_size, + &"s"[mess->raw_size == 1]); s = UTIL_PrintableString((const char*) - call_data->raw_data, - call_data->raw_size, - s, format_flags & fLOG_FullOctal); + mess->raw_data, + mess->raw_size, + s, flags & fLOG_FullOctal); memcpy(s, kRawData_End, sizeof(kRawData_End)); } else @@ -521,21 +521,23 @@ typedef struct { #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ -static void s_LOG_FileHandler(void* user_data, SLOG_Handler* call_data) +static void s_LOG_FileHandler(void* data, SLOG_Message* mess) { - SLogData* data = (SLogData*) user_data; - assert(data && data->fp); - assert(call_data); + SLogData* logdata = (SLogData*) data; + assert(logdata && logdata->fp); + assert(mess); - if (call_data->level >= data->cut_off || - call_data->level >= data->fatal_err) { - char* str = LOG_ComposeMessage(call_data, s_LogFormatFlags); + if (mess->level >= logdata->cut_off || + mess->level >= logdata->fatal_err) { + char* str = LOG_ComposeMessage(mess, s_LogFormatFlags); if (str) { - fprintf(data->fp, "%s\n", str); - fflush(data->fp); + size_t len = strlen(str); + str[len++] = '\n'; + fwrite(str, len, 1, logdata->fp); + fflush(logdata->fp); free(str); } - if (call_data->level >= data->fatal_err) { + if (mess->level >= logdata->fatal_err) { #ifdef NDEBUG exit(1); #else @@ -553,16 +555,16 @@ static void s_LOG_FileHandler(void* user_data, SLOG_Handler* call_data) #ifdef __cplusplus extern "C" { #endif /*__cplusplus*/ -static void s_LOG_FileCleanup(void* user_data) +static void s_LOG_FileCleanup(void* data) { - SLogData* data = (SLogData*) user_data; + SLogData* logdata = (SLogData*) data; - assert(data && data->fp); - if (data->auto_close) - fclose(data->fp); + assert(logdata && logdata->fp); + if (logdata->auto_close) + fclose(logdata->fp); else - fflush(data->fp); - free(user_data); + fflush(logdata->fp); + free(logdata); } #ifdef __cplusplus } @@ -577,15 +579,22 @@ extern void LOG_ToFILE_Ex int/*bool*/ auto_close ) { - SLogData* data = (SLogData*)(fp ? malloc(sizeof(*data)) : 0); - if (data) { - data->fp = fp; - data->cut_off = cut_off; - data->fatal_err = fatal_err; - data->auto_close = auto_close; - LOG_Reset(lg, data, s_LOG_FileHandler, s_LOG_FileCleanup); + SLogData* logdata; + if (fp) { + fflush(fp); + logdata = (SLogData*) malloc(sizeof(*logdata)); + } else + logdata = 0; + if (logdata) { + logdata->fp = fp; + logdata->cut_off = cut_off; + logdata->fatal_err = fatal_err; + logdata->auto_close = auto_close; + LOG_Reset(lg, logdata, s_LOG_FileHandler, s_LOG_FileCleanup); } else { LOG_Reset(lg, 0/*data*/, 0/*handler*/, 0/*cleanup*/); + if (fp && auto_close) + fclose(fp); } } @@ -927,6 +936,39 @@ extern size_t CORE_GetVMPageSize(void) +/**************************************************************************** + * CORE_Msdelay + */ + +extern void CORE_Msdelay(unsigned long ms) +{ +#if defined(NCBI_OS_MSWIN) + Sleep(ms); +#elif defined(NCBI_OS_UNIX) +# ifdef HAVE_USLEEP + if (usleep(ms * 1000) < 0 && errno == EINVAL) { +# endif /*HAVE_USLEEP*/ +# if defined(HAVE_NANOSLEEP) + struct timespec ts; + ts.tv_sec = ms / 1000; + ts.tv_nsec = (ms % 1000) * 1000000; + nanosleep(&ts, 0); +# else + struct timeval tv; + tv.tv_sec = ms / 1000; + tv.tv_usec = (ms % 1000) * 1000; + select(0, 0, 0, 0, &tv); +# endif /*HAVE_NANOSLEEP*/ +# ifdef HAVE_USLEEP + } +# endif /*HAVE_USLEEP*/ +#else +# error "Unsupported platform." +#endif /*NCBI_OS*/ +} + + + /**************************************************************************** * CRC32 */ diff --git a/c++/src/connect/parson.c b/c++/src/connect/parson.c index 9b6267be..bfccfd48 100644 --- a/c++/src/connect/parson.c +++ b/c++/src/connect/parson.c @@ -1,24 +1,23 @@ /* - Parson ( http://kgabis.github.com/parson/ ) - Copyright (c) 2012 - 2016 Krzysztof Gabis - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. +Parson ( http://kgabis.github.com/parson/ ) +Copyright (c) 2012 - 2016 Krzysztof Gabis +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ #ifdef _MSC_VER #ifndef _CRT_SECURE_NO_WARNINGS @@ -994,6 +993,24 @@ x_JSON_Value * x_json_object_get_value_at(const x_JSON_Object *object, size_t in return object->values[index]; } +int x_json_object_has_value (const x_JSON_Object *object, const char *name) { + return x_json_object_get_value(object, name) != NULL; +} + +int x_json_object_has_value_of_type(const x_JSON_Object *object, const char *name, x_JSON_Value_Type type) { + x_JSON_Value *val = x_json_object_get_value(object, name); + return val != NULL && x_json_value_get_type(val) == type; +} + +int x_json_object_dothas_value (const x_JSON_Object *object, const char *name) { + return x_json_object_dotget_value(object, name) != NULL; +} + +int x_json_object_dothas_value_of_type(const x_JSON_Object *object, const char *name, x_JSON_Value_Type type) { + x_JSON_Value *val = x_json_object_dotget_value(object, name); + return val != NULL && x_json_value_get_type(val) == type; +} + /* JSON Array API */ x_JSON_Value * x_json_array_get_value(const x_JSON_Array *array, size_t index) { if (array == NULL || index >= x_json_array_get_count(array)) @@ -1764,4 +1781,4 @@ int x_json_boolean(const x_JSON_Value *value) { void x_json_set_allocation_functions(x_JSON_Malloc_Function malloc_fun, x_JSON_Free_Function free_fun) { parson_malloc = malloc_fun; parson_free = free_fun; -} +} \ No newline at end of file diff --git a/c++/src/connect/parson.h b/c++/src/connect/parson.h index e905f415..760f1085 100644 --- a/c++/src/connect/parson.h +++ b/c++/src/connect/parson.h @@ -1,24 +1,24 @@ /* - Parson ( http://kgabis.github.com/parson/ ) - Copyright (c) 2012 - 2016 Krzysztof Gabis - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. +Parson ( http://kgabis.github.com/parson/ ) +Copyright (c) 2012 - 2016 Krzysztof Gabis + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. */ #ifndef parson_parson_h @@ -31,193 +31,201 @@ extern "C" #include /* size_t */ -/* Types and enums */ -typedef struct x_json_object_t x_JSON_Object; -typedef struct x_json_array_t x_JSON_Array; -typedef struct x_json_value_t x_JSON_Value; - -enum x_json_value_type { - JSONError = -1, - JSONNull = 1, - JSONString = 2, - JSONNumber = 3, - JSONObject = 4, - JSONArray = 5, - JSONBoolean = 6 -}; -typedef int x_JSON_Value_Type; - -enum x_json_result_t { - JSONSuccess = 0, - JSONFailure = -1 -}; -typedef int x_JSON_Status; - -typedef void * (*x_JSON_Malloc_Function)(size_t); -typedef void (*x_JSON_Free_Function)(void *); - -/* Call only once, before calling any other function from parson API. If not called, malloc and free - from stdlib will be used for all allocations */ -void x_json_set_allocation_functions(x_JSON_Malloc_Function malloc_fun, x_JSON_Free_Function free_fun); - -/* Parses first JSON value in a file, returns NULL in case of error */ -x_JSON_Value * x_json_parse_file(const char *filename); - -/* Parses first JSON value in a file and ignores comments (/ * * / and //), - returns NULL in case of error */ -x_JSON_Value * x_json_parse_file_with_comments(const char *filename); - -/* Parses first JSON value in a string, returns NULL in case of error */ -x_JSON_Value * x_json_parse_string(const char *string); - -/* Parses first JSON value in a string and ignores comments (/ * * / and //), + /* Types and enums */ + typedef struct x_json_object_t x_JSON_Object; + typedef struct x_json_array_t x_JSON_Array; + typedef struct x_json_value_t x_JSON_Value; + + enum x_json_value_type { + JSONError = -1, + JSONNull = 1, + JSONString = 2, + JSONNumber = 3, + JSONObject = 4, + JSONArray = 5, + JSONBoolean = 6 + }; + typedef int x_JSON_Value_Type; + + enum x_json_result_t { + JSONSuccess = 0, + JSONFailure = -1 + }; + typedef int x_JSON_Status; + + typedef void * (*x_JSON_Malloc_Function)(size_t); + typedef void(*x_JSON_Free_Function)(void *); + + /* Call only once, before calling any other function from parson API. If not called, malloc and free + from stdlib will be used for all allocations */ + void x_json_set_allocation_functions(x_JSON_Malloc_Function malloc_fun, x_JSON_Free_Function free_fun); + + /* Parses first JSON value in a file, returns NULL in case of error */ + x_JSON_Value * x_json_parse_file(const char *filename); + + /* Parses first JSON value in a file and ignores comments (/ * * / and //), returns NULL in case of error */ -x_JSON_Value * x_json_parse_string_with_comments(const char *string); - -/* Serialization */ -size_t x_json_serialization_size(const x_JSON_Value *value); /* returns 0 on fail */ -x_JSON_Status x_json_serialize_to_buffer(const x_JSON_Value *value, char *buf, size_t buf_size_in_bytes); -x_JSON_Status x_json_serialize_to_file(const x_JSON_Value *value, const char *filename); -char * x_json_serialize_to_string(const x_JSON_Value *value); - -/* Pretty serialization */ -size_t x_json_serialization_size_pretty(const x_JSON_Value *value); /* returns 0 on fail */ -x_JSON_Status x_json_serialize_to_buffer_pretty(const x_JSON_Value *value, char *buf, size_t buf_size_in_bytes); -x_JSON_Status x_json_serialize_to_file_pretty(const x_JSON_Value *value, const char *filename); -char * x_json_serialize_to_string_pretty(const x_JSON_Value *value); - -void x_json_free_serialized_string(char *string); /* frees string from json_serialize_to_string and json_serialize_to_string_pretty */ - -/* Comparing */ -int x_json_value_equals(const x_JSON_Value *a, const x_JSON_Value *b); - -/* Validation - This is *NOT* JSON Schema. It validates json by checking if object have identically - named fields with matching types. - For example schema {"name":"", "age":0} will validate - {"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"}, - but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}. - In case of arrays, only first value in schema is checked against all values in tested array. - Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays, - null validates values of every type. - */ -x_JSON_Status json_validate(const x_JSON_Value *schema, const x_JSON_Value *value); + x_JSON_Value * x_json_parse_file_with_comments(const char *filename); -/* - * JSON Object - */ -x_JSON_Value * x_json_object_get_value (const x_JSON_Object *object, const char *name); -const char * x_json_object_get_string (const x_JSON_Object *object, const char *name); -x_JSON_Object * x_json_object_get_object (const x_JSON_Object *object, const char *name); -x_JSON_Array * x_json_object_get_array (const x_JSON_Object *object, const char *name); -double x_json_object_get_number (const x_JSON_Object *object, const char *name); /* returns 0 on fail */ -int x_json_object_get_boolean(const x_JSON_Object *object, const char *name); /* returns -1 on fail */ - -/* dotget functions enable addressing values with dot notation in nested objects, - just like in structs or c++/java/c# objects (e.g. objectA.objectB.value). - Because valid names in JSON can contain dots, some values may be inaccessible - this way. */ -x_JSON_Value * x_json_object_dotget_value (const x_JSON_Object *object, const char *name); -const char * x_json_object_dotget_string (const x_JSON_Object *object, const char *name); -x_JSON_Object * x_json_object_dotget_object (const x_JSON_Object *object, const char *name); -x_JSON_Array * x_json_object_dotget_array (const x_JSON_Object *object, const char *name); -double x_json_object_dotget_number (const x_JSON_Object *object, const char *name); /* returns 0 on fail */ -int x_json_object_dotget_boolean(const x_JSON_Object *object, const char *name); /* returns -1 on fail */ - -/* Functions to get available names */ -size_t x_json_object_get_count (const x_JSON_Object *object); -const char * x_json_object_get_name (const x_JSON_Object *object, size_t index); -x_JSON_Value * x_json_object_get_value_at(const x_JSON_Object *object, size_t index); - -/* Creates new name-value pair or frees and replaces old value with a new one. - * json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */ -x_JSON_Status x_json_object_set_value(x_JSON_Object *object, const char *name, x_JSON_Value *value); -x_JSON_Status x_json_object_set_string(x_JSON_Object *object, const char *name, const char *string); -x_JSON_Status x_json_object_set_number(x_JSON_Object *object, const char *name, double number); -x_JSON_Status x_json_object_set_boolean(x_JSON_Object *object, const char *name, int boolean); -x_JSON_Status x_json_object_set_null(x_JSON_Object *object, const char *name); - -/* Works like dotget functions, but creates whole hierarchy if necessary. - * json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */ -x_JSON_Status x_json_object_dotset_value(x_JSON_Object *object, const char *name, x_JSON_Value *value); -x_JSON_Status x_json_object_dotset_string(x_JSON_Object *object, const char *name, const char *string); -x_JSON_Status x_json_object_dotset_number(x_JSON_Object *object, const char *name, double number); -x_JSON_Status x_json_object_dotset_boolean(x_JSON_Object *object, const char *name, int boolean); -x_JSON_Status x_json_object_dotset_null(x_JSON_Object *object, const char *name); - -/* Frees and removes name-value pair */ -x_JSON_Status x_json_object_remove(x_JSON_Object *object, const char *name); - -/* Works like dotget function, but removes name-value pair only on exact match. */ -x_JSON_Status x_json_object_dotremove(x_JSON_Object *object, const char *key); - -/* Removes all name-value pairs in object */ -x_JSON_Status x_json_object_clear(x_JSON_Object *object); - -/* - *JSON Array - */ -x_JSON_Value * x_json_array_get_value (const x_JSON_Array *array, size_t index); -const char * x_json_array_get_string (const x_JSON_Array *array, size_t index); -x_JSON_Object * x_json_array_get_object (const x_JSON_Array *array, size_t index); -x_JSON_Array * x_json_array_get_array (const x_JSON_Array *array, size_t index); -double x_json_array_get_number (const x_JSON_Array *array, size_t index); /* returns 0 on fail */ -int x_json_array_get_boolean(const x_JSON_Array *array, size_t index); /* returns -1 on fail */ -size_t x_json_array_get_count (const x_JSON_Array *array); - -/* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist. - * Order of values in array may change during execution. */ -x_JSON_Status json_array_remove(x_JSON_Array *array, size_t i); - -/* Frees and removes from array value at given index and replaces it with given one. - * Does nothing and returns JSONFailure if index doesn't exist. - * json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */ -x_JSON_Status x_json_array_replace_value(x_JSON_Array *array, size_t i, x_JSON_Value *value); -x_JSON_Status x_json_array_replace_string(x_JSON_Array *array, size_t i, const char* string); -x_JSON_Status x_json_array_replace_number(x_JSON_Array *array, size_t i, double number); -x_JSON_Status x_json_array_replace_boolean(x_JSON_Array *array, size_t i, int boolean); -x_JSON_Status x_json_array_replace_null(x_JSON_Array *array, size_t i); - -/* Frees and removes all values from array */ -x_JSON_Status x_json_array_clear(x_JSON_Array *array); - -/* Appends new value at the end of array. - * json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */ -x_JSON_Status x_json_array_append_value(x_JSON_Array *array, x_JSON_Value *value); -x_JSON_Status x_json_array_append_string(x_JSON_Array *array, const char *string); -x_JSON_Status x_json_array_append_number(x_JSON_Array *array, double number); -x_JSON_Status x_json_array_append_boolean(x_JSON_Array *array, int boolean); -x_JSON_Status x_json_array_append_null(x_JSON_Array *array); + /* Parses first JSON value in a string, returns NULL in case of error */ + x_JSON_Value * x_json_parse_string(const char *string); -/* - *JSON Value - */ -x_JSON_Value * x_json_value_init_object (void); -x_JSON_Value * x_json_value_init_array (void); -x_JSON_Value * x_json_value_init_string (const char *string); /* copies passed string */ -x_JSON_Value * x_json_value_init_number (double number); -x_JSON_Value * x_json_value_init_boolean(int boolean); -x_JSON_Value * x_json_value_init_null (void); -x_JSON_Value * x_json_value_deep_copy (const x_JSON_Value *value); -void x_json_value_free (x_JSON_Value *value); - -x_JSON_Value_Type x_json_value_get_type (const x_JSON_Value *value); -x_JSON_Object * x_json_value_get_object (const x_JSON_Value *value); -x_JSON_Array * x_json_value_get_array (const x_JSON_Value *value); -const char * x_json_value_get_string (const x_JSON_Value *value); -double x_json_value_get_number (const x_JSON_Value *value); -int x_json_value_get_boolean(const x_JSON_Value *value); - -/* Same as above, but shorter */ -x_JSON_Value_Type x_json_type (const x_JSON_Value *value); -x_JSON_Object * x_json_object (const x_JSON_Value *value); -x_JSON_Array * x_json_array (const x_JSON_Value *value); -const char * x_json_string (const x_JSON_Value *value); -double x_json_number (const x_JSON_Value *value); -int x_json_boolean(const x_JSON_Value *value); + /* Parses first JSON value in a string and ignores comments (/ * * / and //), + returns NULL in case of error */ + x_JSON_Value * x_json_parse_string_with_comments(const char *string); + + /* Serialization */ + size_t x_json_serialization_size(const x_JSON_Value *value); /* returns 0 on fail */ + x_JSON_Status x_json_serialize_to_buffer(const x_JSON_Value *value, char *buf, size_t buf_size_in_bytes); + x_JSON_Status x_json_serialize_to_file(const x_JSON_Value *value, const char *filename); + char * x_json_serialize_to_string(const x_JSON_Value *value); + + /* Pretty serialization */ + size_t x_json_serialization_size_pretty(const x_JSON_Value *value); /* returns 0 on fail */ + x_JSON_Status x_json_serialize_to_buffer_pretty(const x_JSON_Value *value, char *buf, size_t buf_size_in_bytes); + x_JSON_Status x_json_serialize_to_file_pretty(const x_JSON_Value *value, const char *filename); + char * x_json_serialize_to_string_pretty(const x_JSON_Value *value); + + void x_json_free_serialized_string(char *string); /* frees string from x_json_serialize_to_string and x_json_serialize_to_string_pretty */ + + /* Comparing */ + int x_json_value_equals(const x_JSON_Value *a, const x_JSON_Value *b); + + /* Validation + This is *NOT* JSON Schema. It validates json by checking if object have identically + named fields with matching types. + For example schema {"name":"", "age":0} will validate + {"name":"Joe", "age":25} and {"name":"Joe", "age":25, "gender":"m"}, + but not {"name":"Joe"} or {"name":"Joe", "age":"Cucumber"}. + In case of arrays, only first value in schema is checked against all values in tested array. + Empty objects ({}) validate all objects, empty arrays ([]) validate all arrays, + null validates values of every type. + */ + x_JSON_Status x_json_validate(const x_JSON_Value *schema, const x_JSON_Value *value); + + /* + * JSON Object + */ + x_JSON_Value * x_json_object_get_value(const x_JSON_Object *object, const char *name); + const char * x_json_object_get_string(const x_JSON_Object *object, const char *name); + x_JSON_Object * x_json_object_get_object(const x_JSON_Object *object, const char *name); + x_JSON_Array * x_json_object_get_array(const x_JSON_Object *object, const char *name); + double x_json_object_get_number(const x_JSON_Object *object, const char *name); /* returns 0 on fail */ + int x_json_object_get_boolean(const x_JSON_Object *object, const char *name); /* returns -1 on fail */ + + /* dotget functions enable addressing values with dot notation in nested objects, + just like in structs or c++/java/c# objects (e.g. objectA.objectB.value). + Because valid names in JSON can contain dots, some values may be inaccessible + this way. */ + x_JSON_Value * x_json_object_dotget_value(const x_JSON_Object *object, const char *name); + const char * x_json_object_dotget_string(const x_JSON_Object *object, const char *name); + x_JSON_Object * x_json_object_dotget_object(const x_JSON_Object *object, const char *name); + x_JSON_Array * x_json_object_dotget_array(const x_JSON_Object *object, const char *name); + double x_json_object_dotget_number(const x_JSON_Object *object, const char *name); /* returns 0 on fail */ + int x_json_object_dotget_boolean(const x_JSON_Object *object, const char *name); /* returns -1 on fail */ + + /* Functions to get available names */ + size_t x_json_object_get_count(const x_JSON_Object *object); + const char * x_json_object_get_name(const x_JSON_Object *object, size_t index); + x_JSON_Value * x_json_object_get_value_at(const x_JSON_Object *object, size_t index); + + /* Functions to check if object has a value with a specific name. Returned value is 1 if object has + * a value and 0 if it doesn't. dothas functions behave exactly like dotget functions. */ + int x_json_object_has_value(const x_JSON_Object *object, const char *name); + int x_json_object_has_value_of_type(const x_JSON_Object *object, const char *name, x_JSON_Value_Type type); + + int x_json_object_dothas_value(const x_JSON_Object *object, const char *name); + int x_json_object_dothas_value_of_type(const x_JSON_Object *object, const char *name, x_JSON_Value_Type type); + + /* Creates new name-value pair or frees and replaces old value with a new one. + * x_json_object_set_value does not copy passed value so it shouldn't be freed afterwards. */ + x_JSON_Status x_json_object_set_value(x_JSON_Object *object, const char *name, x_JSON_Value *value); + x_JSON_Status x_json_object_set_string(x_JSON_Object *object, const char *name, const char *string); + x_JSON_Status x_json_object_set_number(x_JSON_Object *object, const char *name, double number); + x_JSON_Status x_json_object_set_boolean(x_JSON_Object *object, const char *name, int boolean); + x_JSON_Status x_json_object_set_null(x_JSON_Object *object, const char *name); + + /* Works like dotget functions, but creates whole hierarchy if necessary. + * x_json_object_dotset_value does not copy passed value so it shouldn't be freed afterwards. */ + x_JSON_Status x_json_object_dotset_value(x_JSON_Object *object, const char *name, x_JSON_Value *value); + x_JSON_Status x_json_object_dotset_string(x_JSON_Object *object, const char *name, const char *string); + x_JSON_Status x_json_object_dotset_number(x_JSON_Object *object, const char *name, double number); + x_JSON_Status x_json_object_dotset_boolean(x_JSON_Object *object, const char *name, int boolean); + x_JSON_Status x_json_object_dotset_null(x_JSON_Object *object, const char *name); + + /* Frees and removes name-value pair */ + x_JSON_Status x_json_object_remove(x_JSON_Object *object, const char *name); + + /* Works like dotget function, but removes name-value pair only on exact match. */ + x_JSON_Status x_json_object_dotremove(x_JSON_Object *object, const char *key); + + /* Removes all name-value pairs in object */ + x_JSON_Status x_json_object_clear(x_JSON_Object *object); + + /* + *JSON Array + */ + x_JSON_Value * x_json_array_get_value(const x_JSON_Array *array, size_t index); + const char * x_json_array_get_string(const x_JSON_Array *array, size_t index); + x_JSON_Object * x_json_array_get_object(const x_JSON_Array *array, size_t index); + x_JSON_Array * x_json_array_get_array(const x_JSON_Array *array, size_t index); + double x_json_array_get_number(const x_JSON_Array *array, size_t index); /* returns 0 on fail */ + int x_json_array_get_boolean(const x_JSON_Array *array, size_t index); /* returns -1 on fail */ + size_t x_json_array_get_count(const x_JSON_Array *array); + + /* Frees and removes value at given index, does nothing and returns JSONFailure if index doesn't exist. + * Order of values in array may change during execution. */ + x_JSON_Status x_json_array_remove(x_JSON_Array *array, size_t i); + + /* Frees and removes from array value at given index and replaces it with given one. + * Does nothing and returns JSONFailure if index doesn't exist. + * x_json_array_replace_value does not copy passed value so it shouldn't be freed afterwards. */ + x_JSON_Status x_json_array_replace_value(x_JSON_Array *array, size_t i, x_JSON_Value *value); + x_JSON_Status x_json_array_replace_string(x_JSON_Array *array, size_t i, const char* string); + x_JSON_Status x_json_array_replace_number(x_JSON_Array *array, size_t i, double number); + x_JSON_Status x_json_array_replace_boolean(x_JSON_Array *array, size_t i, int boolean); + x_JSON_Status x_json_array_replace_null(x_JSON_Array *array, size_t i); + + /* Frees and removes all values from array */ + x_JSON_Status x_json_array_clear(x_JSON_Array *array); + + /* Appends new value at the end of array. + * x_json_array_append_value does not copy passed value so it shouldn't be freed afterwards. */ + x_JSON_Status x_json_array_append_value(x_JSON_Array *array, x_JSON_Value *value); + x_JSON_Status x_json_array_append_string(x_JSON_Array *array, const char *string); + x_JSON_Status x_json_array_append_number(x_JSON_Array *array, double number); + x_JSON_Status x_json_array_append_boolean(x_JSON_Array *array, int boolean); + x_JSON_Status x_json_array_append_null(x_JSON_Array *array); + + /* + *JSON Value + */ + x_JSON_Value * x_json_value_init_object(void); + x_JSON_Value * x_json_value_init_array(void); + x_JSON_Value * x_json_value_init_string(const char *string); /* copies passed string */ + x_JSON_Value * x_json_value_init_number(double number); + x_JSON_Value * x_json_value_init_boolean(int boolean); + x_JSON_Value * x_json_value_init_null(void); + x_JSON_Value * x_json_value_deep_copy(const x_JSON_Value *value); + void x_json_value_free(x_JSON_Value *value); + + x_JSON_Value_Type x_json_value_get_type(const x_JSON_Value *value); + x_JSON_Object * x_json_value_get_object(const x_JSON_Value *value); + x_JSON_Array * x_json_value_get_array(const x_JSON_Value *value); + const char * x_json_value_get_string(const x_JSON_Value *value); + double x_json_value_get_number(const x_JSON_Value *value); + int x_json_value_get_boolean(const x_JSON_Value *value); + + /* Same as above, but shorter */ + x_JSON_Value_Type x_json_type(const x_JSON_Value *value); + x_JSON_Object * x_json_object(const x_JSON_Value *value); + x_JSON_Array * x_json_array(const x_JSON_Value *value); + const char * x_json_string(const x_JSON_Value *value); + double x_json_number(const x_JSON_Value *value); + int x_json_boolean(const x_JSON_Value *value); #ifdef __cplusplus } #endif -#endif +#endif \ No newline at end of file diff --git a/c++/src/connect/server.cpp b/c++/src/connect/server.cpp index a28f0c12..00d940b2 100644 --- a/c++/src/connect/server.cpp +++ b/c++/src/connect/server.cpp @@ -1,4 +1,4 @@ -/* $Id: server.cpp 506707 2016-07-11 15:26:50Z satskyse $ +/* $Id: server.cpp 508624 2016-07-29 15:32:34Z satskyse $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -126,12 +126,7 @@ CBlockingQueue_ForServer::Put(const TRequest& data) { CMutexGuard guard(m_Mutex); if (m_Queue.empty()) { - #ifdef NCBI_HAVE_CONDITIONAL_VARIABLE m_GetCond.SignalAll(); - #else - m_GetSem.TryWait(); // is this still needed? - m_GetSem.Post(); - #endif } TItemHandle handle(new CQueueItem(data)); m_Queue.push_back(handle); @@ -144,24 +139,12 @@ CBlockingQueue_ForServer::GetHandle(void) CMutexGuard guard(m_Mutex); while (m_Queue.empty()) { - #ifdef NCBI_HAVE_CONDITIONAL_VARIABLE m_GetCond.WaitForSignal(m_Mutex); - #else - m_GetSem.TryWait(); - m_GetSem.Post(); - #endif } TItemHandle handle(m_Queue.front()); m_Queue.pop_front(); - #ifndef NCBI_HAVE_CONDITIONAL_VARIABLE - if (!m_Queue.empty()) { - m_GetSem.TryWait(); - m_GetSem.Post(); - } - #endif - guard.Release(); // avoid possible deadlocks from x_SetStatus handle->x_SetStatus(CQueueItemBase::eActive); return handle; diff --git a/c++/src/connect/services/CMakeLists.ncbi_xblobstorage_netcache.lib.txt b/c++/src/connect/services/CMakeLists.ncbi_xblobstorage_netcache.lib.txt new file mode 100644 index 00000000..711eef70 --- /dev/null +++ b/c++/src/connect/services/CMakeLists.ncbi_xblobstorage_netcache.lib.txt @@ -0,0 +1,9 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/connect/services/Makefile.ncbi_xblobstorage_netcache.lib +# +add_library(ncbi_xblobstorage_netcache + blob_storage_netcache +) +target_link_libraries(ncbi_xblobstorage_netcache + xconnserv +) diff --git a/c++/src/connect/services/CMakeLists.ncbi_xcache_netcache.lib.txt b/c++/src/connect/services/CMakeLists.ncbi_xcache_netcache.lib.txt new file mode 100644 index 00000000..8ce5adba --- /dev/null +++ b/c++/src/connect/services/CMakeLists.ncbi_xcache_netcache.lib.txt @@ -0,0 +1,9 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/connect/services/Makefile.ncbi_xcache_netcache.lib +# +add_library(ncbi_xcache_netcache + neticache_client +) +target_link_libraries(ncbi_xcache_netcache + xconnserv +) diff --git a/c++/src/connect/services/CMakeLists.txt b/c++/src/connect/services/CMakeLists.txt new file mode 100644 index 00000000..ef8f14fb --- /dev/null +++ b/c++/src/connect/services/CMakeLists.txt @@ -0,0 +1,11 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xconnserv.lib.txt) +include(CMakeLists.ncbi_xcache_netcache.lib.txt) +include(CMakeLists.ncbi_xblobstorage_netcache.lib.txt) + +# Recurse subdirectories +add_subdirectory(test ) diff --git a/c++/src/connect/services/CMakeLists.xconnserv.lib.txt b/c++/src/connect/services/CMakeLists.xconnserv.lib.txt new file mode 100644 index 00000000..f8c16dda --- /dev/null +++ b/c++/src/connect/services/CMakeLists.xconnserv.lib.txt @@ -0,0 +1,25 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/connect/services/Makefile.xconnserv.lib +# +add_library(xconnserv + grid_worker ns_client_factory grid_worker_app + grid_client grid_client_app + wn_commit_thread wn_main_loop wn_cleanup wn_offline_mode + grid_control_thread + grid_globals grid_rw_impl remote_app + srv_connections netservice_api + netservice_params + netschedule_api netschedule_api_submitter netschedule_api_executor + netschedule_api_reader netschedule_api_admin netschedule_api_getjob + netschedule_key netschedule_api_expt + netcache_key netcache_rw netcache_params netcache_api + netcache_api_admin netcache_search + netservice_protocol_parser util clparser + json_over_uttp netstorage netstorage_rpc + netstorageobjectloc netstorageobjectinfo netstorage_direct_nc + ns_output_parser + ns_job_serializer compound_id compound_id_v0 tmp_wn_info +) +target_link_libraries(xconnserv + xthrserv +) diff --git a/c++/src/connect/services/Makefile.xconnserv.lib b/c++/src/connect/services/Makefile.xconnserv.lib index 52ff3b47..20369c06 100644 --- a/c++/src/connect/services/Makefile.xconnserv.lib +++ b/c++/src/connect/services/Makefile.xconnserv.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.xconnserv.lib 520437 2016-11-28 18:35:09Z ivanov $ +# $Id: Makefile.xconnserv.lib 524753 2017-01-13 16:15:36Z sadyrovr $ SRC = grid_worker ns_client_factory grid_worker_app \ grid_client grid_client_app \ @@ -6,7 +6,7 @@ SRC = grid_worker ns_client_factory grid_worker_app \ grid_control_thread \ grid_globals grid_rw_impl remote_app \ srv_connections netservice_api \ - balancing netservice_params \ + netservice_params \ netschedule_api netschedule_api_submitter netschedule_api_executor \ netschedule_api_reader netschedule_api_admin netschedule_api_getjob \ netschedule_key netschedule_api_expt \ @@ -15,7 +15,7 @@ SRC = grid_worker ns_client_factory grid_worker_app \ netservice_protocol_parser util clparser \ json_over_uttp netstorage netstorage_rpc \ netstorageobjectloc netstorageobjectinfo netstorage_direct_nc \ - pack_int ns_output_parser \ + ns_output_parser \ ns_job_serializer compound_id compound_id_v0 tmp_wn_info LIB = xconnserv diff --git a/c++/src/connect/services/balancing.cpp b/c++/src/connect/services/balancing.cpp deleted file mode 100644 index 994d5297..00000000 --- a/c++/src/connect/services/balancing.cpp +++ /dev/null @@ -1,87 +0,0 @@ -/* $Id: balancing.cpp 209919 2010-10-29 17:55:16Z kazimird $ - * =========================================================================== - * - * PUBLIC DOMAIN NOTICE - * National Center for Biotechnology Information - * - * This software/database is a "United States Government Work" under the - * terms of the United States Copyright Act. It was written as part of - * the author's official duties as a United States Government employee and - * thus cannot be copyrighted. This software/database is freely available - * to the public for use. The National Library of Medicine and the U.S. - * Government have not placed any restriction on its use or reproduction. - * - * Although all reasonable efforts have been taken to ensure the accuracy - * and reliability of the software and data, the NLM and the U.S. - * Government do not and cannot warrant the performance or results that - * may be obtained by using this software or data. The NLM and the U.S. - * Government disclaim all warranties, express or implied, including - * warranties of performance, merchantability or fitness for any particular - * purpose. - * - * Please cite the author in any work or product based on this material. - * - * =========================================================================== - * - * File Description: - * Contains definitions related to server discovery by the load balancer. - * - * Authors: - * Dmitry Kazimirov - * - */ - -#include - -#include "netservice_params.hpp" -#include "balancing.hpp" - -#include -#include - -BEGIN_NCBI_SCOPE - -bool CSimpleRebalanceStrategy::NeedRebalance() -{ - CFastMutexGuard g(m_Mutex); - CTime current_time(GetFastLocalTime()); - if ((m_RebalanceTime > 0 && current_time >= m_NextRebalanceTime) || - (m_RebalanceRequests > 0 && - m_RequestCounter >= m_RebalanceRequests)) { - m_RequestCounter = 0; - m_LastRebalanceTime = current_time; - m_NextRebalanceTime = current_time; - m_NextRebalanceTime.AddNanoSecond(m_RebalanceTime * 1000000); - return true; - } - return false; -} - -CRef - CreateSimpleRebalanceStrategy(CConfig& config, const string& driver_name) -{ - return CRef(new CSimpleRebalanceStrategy( - config.GetInt(driver_name, "rebalance_requests", - CConfig::eErr_NoThrow, REBALANCE_REQUESTS_DEFAULT), - s_SecondsToMilliseconds(config.GetString(driver_name, - "rebalance_time", CConfig::eErr_NoThrow, - NCBI_AS_STRING(REBALANCE_TIME_DEFAULT)), - SECONDS_DOUBLE_TO_MS_UL(REBALANCE_TIME_DEFAULT)))); -} - -CRef - CreateSimpleRebalanceStrategy(int rebalance_requests, int rebalance_time) -{ - return CRef( - new CSimpleRebalanceStrategy(rebalance_requests, rebalance_time)); -} - -CRef CreateDefaultRebalanceStrategy() -{ - return CRef( - new CSimpleRebalanceStrategy(REBALANCE_REQUESTS_DEFAULT, - SECONDS_DOUBLE_TO_MS_UL(REBALANCE_TIME_DEFAULT))); -} - - -END_NCBI_SCOPE diff --git a/c++/src/connect/services/balancing.hpp b/c++/src/connect/services/balancing.hpp index 99b4489a..2c707f41 100644 --- a/c++/src/connect/services/balancing.hpp +++ b/c++/src/connect/services/balancing.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES___BALANCING__HPP #define CONNECT_SERVICES___BALANCING__HPP -/* $Id: balancing.hpp 209919 2010-10-29 17:55:16Z kazimird $ +/* $Id: balancing.hpp 517449 2016-10-25 13:48:28Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,23 +34,35 @@ * */ -#include +#include +#include BEGIN_NCBI_SCOPE class CSimpleRebalanceStrategy : public CObject { public: - CSimpleRebalanceStrategy(int rebalance_requests, int rebalance_time) : - m_RebalanceRequests(rebalance_requests), - m_RebalanceTime(rebalance_time), + CSimpleRebalanceStrategy(int max_requests, double max_seconds) : + m_MaxRequests(max_requests), + m_MaxNs(static_cast(max_seconds * kNanoSecondsPerSecond)), m_RequestCounter(0), - m_LastRebalanceTime(CTime::eEmpty), m_NextRebalanceTime(CTime::eEmpty) { } - bool NeedRebalance(); + bool NeedRebalance() + { + CFastMutexGuard g(m_Mutex); + CTime current_time(GetFastLocalTime()); + if ((m_MaxNs > 0 && current_time >= m_NextRebalanceTime) || + (m_MaxRequests > 0 && m_RequestCounter >= m_MaxRequests)) { + m_RequestCounter = 0; + m_NextRebalanceTime = current_time; + m_NextRebalanceTime.AddNanoSecond(m_MaxNs); + return true; + } + return false; + } void OnResourceRequested() { CFastMutexGuard g(m_Mutex); @@ -59,34 +71,22 @@ public: void Reset() { CFastMutexGuard g(m_Mutex); m_RequestCounter = 0; - m_LastRebalanceTime.Clear(); m_NextRebalanceTime.Clear(); } - const CTime& GetLastRebalanceTime() - { - return m_LastRebalanceTime; - } + + // The following two parameters define how often LBSMD is queried by default. + // TODO: Replace with constexpr after it is supported by MS VS + static int DefaultMaxRequests() { return 5000; } + static double DefaultMaxSeconds() { return 10.0; } private: - int m_RebalanceRequests; - int m_RebalanceTime; + const int m_MaxRequests; + const long m_MaxNs; int m_RequestCounter; - CTime m_LastRebalanceTime; CTime m_NextRebalanceTime; CFastMutex m_Mutex; }; -class CConfig; - -NCBI_XCONNECT_EXPORT CRef - CreateSimpleRebalanceStrategy(CConfig& config, const string& driver_name); - -NCBI_XCONNECT_EXPORT CRef - CreateSimpleRebalanceStrategy(int rebalance_requests, int rebalance_time); - -NCBI_XCONNECT_EXPORT CRef - CreateDefaultRebalanceStrategy(); - END_NCBI_SCOPE #endif /* CONNECT_SERVICES___BALANCING__HPP */ diff --git a/c++/src/connect/services/clparser.cpp b/c++/src/connect/services/clparser.cpp index 5dad2e37..e4ccfd41 100644 --- a/c++/src/connect/services/clparser.cpp +++ b/c++/src/connect/services/clparser.cpp @@ -1,4 +1,4 @@ -/* $Id: clparser.cpp 485043 2015-11-18 14:43:31Z sadyrovr $ +/* $Id: clparser.cpp 540006 2017-06-29 17:44:23Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -85,17 +85,16 @@ struct SOptionInfo : public SOptionOrCommandInfo { string result(AddDashes(m_NameVariants.front())); if (m_NameVariants.size() > 1) { - result.append(" ["); + result.append(", "); TNameVariantList::const_iterator name(m_NameVariants.begin()); result.append(AddDashes(*++name)); while (++name != m_NameVariants.end()) { result.append(", "); result.append(AddDashes(*name)); } - result.push_back(']'); } if (m_Type == CCommandLineParser::eOptionWithParameter) - result.append(" ARG"); + result.append("=ARG"); return result; } @@ -576,12 +575,12 @@ int SCommandLineParserImpl::ParseAndValidate(int argc, const char* const *argv) const SCommandInfo* command_info = command->second; - ITERATE(TOptionValues, option_value, m_OptionValues) + ITERATE(TOptionValues, it, m_OptionValues) if (find(command_info->m_AcceptedOptions.begin(), - command_info->m_AcceptedOptions.end(), option_value->first) == + command_info->m_AcceptedOptions.end(), it->first) == command_info->m_AcceptedOptions.end()) Throw("command '" + command_name + "' doesn't accept option '" + - option_value->first->GetNameVariants() + "'", + it->first->GetNameVariants() + "'", command_name); expected_positional_arguments = &command_info->m_PositionalArguments; diff --git a/c++/src/connect/services/compound_id.cpp b/c++/src/connect/services/compound_id.cpp index 1d241333..aa595d32 100644 --- a/c++/src/connect/services/compound_id.cpp +++ b/c++/src/connect/services/compound_id.cpp @@ -1,4 +1,4 @@ -/* $Id: compound_id.cpp 489731 2016-01-15 15:57:28Z sadyrovr $ +/* $Id: compound_id.cpp 525545 2017-01-25 16:05:36Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -922,20 +922,20 @@ CCompoundID CCompoundIDPool::FromDump(const string& cid_dump) pos = seq; \ counter = seq_len - 1; \ do { \ - pos[1] ^= *pos ^ length_factor--; \ + pos[1] = (unsigned char)(pos[1] ^ *pos ^ length_factor--); \ ++pos; \ } while (--counter > 0); static void s_Scramble(unsigned char* seq, size_t seq_len) { if (seq_len > 1) { - unsigned char length_factor = ((unsigned char) seq_len << 1) - 1; + unsigned char length_factor = (unsigned char)(((unsigned char) seq_len << 1) - 1); unsigned char* pos; size_t counter; SCRAMBLE_PASS(); - *seq ^= *pos ^ length_factor--; + *seq = (unsigned char)(*seq ^ *pos ^ length_factor--); SCRAMBLE_PASS(); } @@ -960,7 +960,7 @@ void g_PackID(void* binary_id, size_t binary_id_len, string& packed_id) #define UNSCRAMBLE_PASS() \ counter = seq_len - 1; \ do { \ - *pos ^= pos[-1] ^ ++length_factor; \ + *pos = (unsigned char)(*pos ^ pos[-1] ^ ++length_factor); \ --pos; \ } while (--counter > 0); @@ -975,7 +975,7 @@ static void s_Unscramble(unsigned char* seq, size_t seq_len) pos = seq + seq_len - 1; - *seq ^= *pos ^ ++length_factor; + *seq = (unsigned char)(*seq ^ *pos ^ ++length_factor); UNSCRAMBLE_PASS(); } diff --git a/c++/src/connect/services/compound_id_v0.cpp b/c++/src/connect/services/compound_id_v0.cpp index 286992cf..7d98b557 100644 --- a/c++/src/connect/services/compound_id_v0.cpp +++ b/c++/src/connect/services/compound_id_v0.cpp @@ -1,4 +1,4 @@ -/* $Id: compound_id_v0.cpp 461156 2015-03-06 16:43:46Z sadyrovr $ +/* $Id: compound_id_v0.cpp 524753 2017-01-13 16:15:36Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,7 +37,6 @@ #include #include "compound_id_impl.hpp" -#include "pack_int.hpp" #include @@ -85,6 +84,154 @@ static const char s_TypePrefix[eCIT_NumberOfTypes] = { /* eCIT_NestedCID */ 0 }; +/// Save a 8-byte unsigned integer to a variable-length array of +/// up to 9 bytes. +/// +/// @param dst +/// Pointer to the receiving buffer. +/// @param dst_size +/// Size of the receiving buffer in bytes. If the buffer is too +/// small to store a particular number, the buffer will not be +/// changed, but the function will return the value that would +/// have been returned if the buffer was big enough. The caller +/// must check whether the returned value is greater than +/// 'dst_size'. This, of course, is not necessary if 'dst_size' +/// is guaranteed to be at least 9 bytes long, which is the +/// maximum possible packed length of an 8-byte number. +/// @param number +/// The integer to pack. +/// +/// @return +/// The number of bytes stored in the 'dst' buffer. Or the +/// number of bytes that would have been stored if the buffer +/// was big enough (see the dscription of 'dst_size'). +/// +/// @see g_UnpackInteger +/// +unsigned g_PackInteger(void* dst, size_t dst_size, Uint8 number) +{ + if ((signed char) number >= 0 && (unsigned char) number == number) { + if (dst_size > 0) + *(unsigned char*) dst = (unsigned char) number; + return 1; + } + + unsigned char buffer[sizeof(number)]; + unsigned char *ptr = buffer + sizeof(buffer) - 1; + + *ptr = (unsigned char) number; + unsigned length = 1; + + Uint8 mask = 0x7F; + Uint8 mask_shift; + + while ((number >>= 8) > (mask_shift = (mask >> 1))) { + *--ptr = (unsigned char) number; + ++length; + mask = mask_shift; + } + + if (dst_size > length) { + *(unsigned char*) dst = (unsigned char) (~mask | number); + + memcpy(((unsigned char*) dst) + 1, ptr, length); + } + + return length + 1; +} + +#define REC_DATA \ +{ \ + REC(2, 0x00), REC(2, 0x01), REC(2, 0x02), REC(2, 0x03), REC(2, 0x04), \ + REC(2, 0x05), REC(2, 0x06), REC(2, 0x07), REC(2, 0x08), REC(2, 0x09), \ + REC(2, 0x0A), REC(2, 0x0B), REC(2, 0x0C), REC(2, 0x0D), REC(2, 0x0E), \ + REC(2, 0x0F), REC(2, 0x10), REC(2, 0x11), REC(2, 0x12), REC(2, 0x13), \ + REC(2, 0x14), REC(2, 0x15), REC(2, 0x16), REC(2, 0x17), REC(2, 0x18), \ + REC(2, 0x19), REC(2, 0x1A), REC(2, 0x1B), REC(2, 0x1C), REC(2, 0x1D), \ + REC(2, 0x1E), REC(2, 0x1F), REC(2, 0x20), REC(2, 0x21), REC(2, 0x22), \ + REC(2, 0x23), REC(2, 0x24), REC(2, 0x25), REC(2, 0x26), REC(2, 0x27), \ + REC(2, 0x28), REC(2, 0x29), REC(2, 0x2A), REC(2, 0x2B), REC(2, 0x2C), \ + REC(2, 0x2D), REC(2, 0x2E), REC(2, 0x2F), REC(2, 0x30), REC(2, 0x31), \ + REC(2, 0x32), REC(2, 0x33), REC(2, 0x34), REC(2, 0x35), REC(2, 0x36), \ + REC(2, 0x37), REC(2, 0x38), REC(2, 0x39), REC(2, 0x3A), REC(2, 0x3B), \ + REC(2, 0x3C), REC(2, 0x3D), REC(2, 0x3E), REC(2, 0x3F), REC(3, 0x00), \ + REC(3, 0x01), REC(3, 0x02), REC(3, 0x03), REC(3, 0x04), REC(3, 0x05), \ + REC(3, 0x06), REC(3, 0x07), REC(3, 0x08), REC(3, 0x09), REC(3, 0x0A), \ + REC(3, 0x0B), REC(3, 0x0C), REC(3, 0x0D), REC(3, 0x0E), REC(3, 0x0F), \ + REC(3, 0x10), REC(3, 0x11), REC(3, 0x12), REC(3, 0x13), REC(3, 0x14), \ + REC(3, 0x15), REC(3, 0x16), REC(3, 0x17), REC(3, 0x18), REC(3, 0x19), \ + REC(3, 0x1A), REC(3, 0x1B), REC(3, 0x1C), REC(3, 0x1D), REC(3, 0x1E), \ + REC(3, 0x1F), REC(4, 0x00), REC(4, 0x01), REC(4, 0x02), REC(4, 0x03), \ + REC(4, 0x04), REC(4, 0x05), REC(4, 0x06), REC(4, 0x07), REC(4, 0x08), \ + REC(4, 0x09), REC(4, 0x0A), REC(4, 0x0B), REC(4, 0x0C), REC(4, 0x0D), \ + REC(4, 0x0E), REC(4, 0x0F), REC(5, 0x00), REC(5, 0x01), REC(5, 0x02), \ + REC(5, 0x03), REC(5, 0x04), REC(5, 0x05), REC(5, 0x06), REC(5, 0x07), \ + REC(6, 0x00), REC(6, 0x01), REC(6, 0x02), REC(6, 0x03), REC(7, 0x00), \ + REC(7, 0x01), REC(8, 0x00), REC(9, 0x00) \ +} + +#define REC(length, bits) {length, (bits << 8)} + +struct SCodeRec +{ + unsigned length; + Uint8 bits; +} static const s_CodeRec[128] = REC_DATA; + +/// Unpack an unsigned integer from a byte array prepared by +/// g_PackInteger(). +/// +/// @param src +/// The source byte array. +/// @param src_size +/// Number of bytes available in 'src'. +/// @param number +/// Pointer to a variable where the integer originally passed +/// to g_PackInteger() will be stored. If 'src_size' bytes is +/// not enough to reconstitute the integer, the variable will +/// not be changed. +/// +/// @return +/// The length of the packed integer stored in 'src' regardless +/// of whether the integer was actually unpacked or not (in case +/// if 'src_size' was less that the value that g_PackInteger() +/// originally returned, see the description of the 'number' +/// argument). +/// +/// @see g_PackInteger +/// +unsigned g_UnpackInteger(const void* src, size_t src_size, Uint8* number) +{ + const unsigned char* ptr = (const unsigned char*) src; + + if (src_size == 0) + return 0; + + _ASSERT(number); + + if ((signed char) *ptr >= 0) { + *number = (Uint8) *ptr; + return 1; + } + + SCodeRec acc = s_CodeRec[*ptr - 0x80]; + + if (src_size >= acc.length) { + unsigned count = acc.length - 1; + + for (;;) { + acc.bits += *++ptr; + if (--count == 0) { + *number = acc.bits; + break; + } + acc.bits <<= 8; + } + } + + return acc.length; +} + struct SIDPackingBuffer { char m_Buffer[1024]; diff --git a/c++/src/connect/services/grid_client.cpp b/c++/src/connect/services/grid_client.cpp index 34bda8c7..12e45eb0 100644 --- a/c++/src/connect/services/grid_client.cpp +++ b/c++/src/connect/services/grid_client.cpp @@ -1,4 +1,4 @@ -/* $Id: grid_client.cpp 492431 2016-02-17 17:05:04Z sadyrovr $ +/* $Id: grid_client.cpp 537172 2017-05-26 15:53:31Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,8 +37,6 @@ #include #include -#include - BEGIN_NCBI_SCOPE ////////////////////////////////////////////////////////////////////////////// @@ -114,31 +112,12 @@ void CGridClient::SetJobInput(const string& input) CNcbiOstream& CGridClient::GetOStream() { UseNextSubHitID(); - - m_Writer.reset(new CStringOrBlobStorageWriter( - GetMaxServerInputSize(), - GetNetCacheAPI(), - m_Job.input)); - - m_WStream.reset(new CWStream(m_Writer.get(), - 0, 0, CRWStreambuf::fLeakExceptions)); - - m_WStream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); - - return *m_WStream; + return m_GridWrite(GetNetCacheAPI(), GetMaxServerInputSize(), m_Job.input); } void CGridClient::CloseStream() { - if (m_Writer.get() != NULL) { - if (m_WStream.get() != NULL) { - m_WStream->flush(); - m_WStream.reset(); - } - - m_Writer->Close(); - m_Writer.reset(); - } + m_GridWrite.Reset(true); } string CGridClient::Submit(const string& affinity) @@ -153,12 +132,12 @@ string CGridClient::Submit(const string& affinity) return job_key; } -CNetScheduleAPI::EJobStatus CGridClient::SubmitAndWait(unsigned wait_time) +CNetScheduleAPI::EJobStatus CGridClient::SubmitAndWait(unsigned wait_time, pair receiver) { CloseStream(); time_t job_exptime = 0; CNetScheduleAPI::EJobStatus status = - m_NetScheduleSubmitter->SubmitJobAndWait(m_Job, wait_time, &job_exptime); + m_NetScheduleSubmitter->SubmitJobAndWait(m_Job, wait_time, &job_exptime, receiver); return x_CheckAllJobBlobs(status, job_exptime); } @@ -199,18 +178,8 @@ void CGridJobBatchSubmitter::SetJobInput(const string& input) CNcbiOstream& CGridJobBatchSubmitter::GetOStream() { CheckIfBatchSubmittedAndPrepareNextJob(); - - m_Writer.reset(new CStringOrBlobStorageWriter( - m_GridClient.GetMaxServerInputSize(), - m_GridClient.GetNetCacheAPI(), - m_Jobs[m_JobIndex].input)); - - m_WStream.reset(new CWStream(m_Writer.get(), - 0, 0, CRWStreambuf::fLeakExceptions)); - - m_WStream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); - - return *m_WStream; + return m_GridWrite(m_GridClient.GetNetCacheAPI(), m_GridClient.GetMaxServerInputSize(), + m_Jobs[m_JobIndex].input); } void CGridJobBatchSubmitter::SetJobMask(CNetScheduleAPI::TJobMask mask) @@ -230,11 +199,7 @@ void CGridJobBatchSubmitter::SetJobAffinity(const string& affinity) void CGridJobBatchSubmitter::PrepareNextJob() { CheckIfBatchAlreadySubmitted(); - m_WStream.reset(); - if (m_Writer.get() != NULL) { - m_Writer->Close(); - m_Writer.reset(); - } + m_GridWrite.Reset(); if (!m_Jobs.empty()) ++m_JobIndex; m_Jobs.push_back(CNetScheduleJob()); @@ -244,11 +209,7 @@ void CGridJobBatchSubmitter::PrepareNextJob() void CGridJobBatchSubmitter::Submit(const string& job_group) { CheckIfBatchAlreadySubmitted(); - m_WStream.reset(); - if (m_Writer.get() != NULL) { - m_Writer->Close(); - m_Writer.reset(); - } + m_GridWrite.Reset(); if (!m_Jobs.empty()) { m_GridClient.GetNetScheduleSubmitter().SubmitJobBatch(m_Jobs, job_group); @@ -258,11 +219,7 @@ void CGridJobBatchSubmitter::Submit(const string& job_group) void CGridJobBatchSubmitter::Reset() { - m_WStream.reset(); - if (m_Writer.get() != NULL) { - m_Writer->Close(); - m_Writer.reset(); - } + m_GridWrite.Reset(); m_HasBeenSubmitted = false; m_JobIndex = 0; m_Jobs.clear(); @@ -318,12 +275,7 @@ CNetScheduleAPI::EJobStatus CGridClient::GetStatus() CNcbiIstream& CGridClient::GetIStream() { x_GetJobDetails(); - IReader* reader = new CStringOrBlobStorageReader( - m_Job.output, GetNetCacheAPI(), &m_BlobSize); - m_RStream.reset(new CRStream(reader,0,0,CRWStreambuf::fOwnReader - | CRWStreambuf::fLeakExceptions)); - m_RStream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); - return *m_RStream; + return m_GridRead(GetNetCacheAPI(), m_Job.output, &m_BlobSize); } string CGridClient::GetProgressMessage() @@ -360,7 +312,7 @@ void CGridClient::SetJobKey(const string& job_key) { m_Job.Reset(); m_Job.job_id = job_key; - m_RStream.reset(); + m_GridRead.Reset(); m_BlobSize = 0; m_JobDetailsRead = false; } diff --git a/c++/src/connect/services/grid_control_thread.cpp b/c++/src/connect/services/grid_control_thread.cpp index 3063da16..79aaac2b 100644 --- a/c++/src/connect/services/grid_control_thread.cpp +++ b/c++/src/connect/services/grid_control_thread.cpp @@ -1,4 +1,4 @@ -/* $Id: grid_control_thread.cpp 491506 2016-02-05 16:08:02Z sadyrovr $ +/* $Id: grid_control_thread.cpp 513338 2016-09-09 15:19:49Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -60,13 +60,12 @@ public: CNcbiOstream& os, CWorkerNodeControlServer* control_server) { - const CVersion& version(control_server->GetWorkerNode().GetAppVersion()); - const CVersionInfo& version_info(version.GetVersionInfo()); - const SBuildInfo& build_info(version.GetBuildInfo()); + CGridWorkerNode node(control_server->GetWorkerNode()); + const CGridWorkerNode::TVersion version(node.GetAppVersion()); - os << "OK:version=" << NStr::URLEncode(version_info.Print()) << - "&build_date=" << NStr::URLEncode(build_info.date) << - "&build_tag=" << NStr::URLEncode(build_info.tag) << "\n"; + os << "OK:version=" << NStr::URLEncode(version[0]) << + "&build_date=" << NStr::URLEncode(version[1]) << + "&build_tag=" << NStr::URLEncode(version[2]) << "\n"; } }; @@ -75,7 +74,7 @@ class CAdminCmdProcessor : public CWorkerNodeControlServer::IRequestProcessor public: virtual bool Authenticate(const string& host, const string& /*auth*/, - const string& queue, + const string& /*queue*/, CNcbiOstream& os, CWorkerNodeControlServer* control_server) { @@ -167,14 +166,12 @@ public: CWorkerNodeControlServer* control_server) { CGridWorkerNode node(control_server->GetWorkerNode()); - const CVersion& version(control_server->GetWorkerNode().GetAppVersion()); - const CVersionInfo& version_info(version.GetVersionInfo()); - const SBuildInfo& build_info(version.GetBuildInfo()); + const CGridWorkerNode::TVersion version(node.GetAppVersion()); os << "OK:Application: " << node.GetAppName() << - "\nVersion: " << version_info.Print() << - "\nBuild date: " << build_info.date << - "\nBuild tag: " << build_info.tag << "\n"; + "\nVersion: " << version[0] << + "\nBuild date: " << version[1] << + "\nBuild tag: " << version[2] << "\n"; {{ CMutexGuard guard(CNcbiApplication::GetInstanceMutex()); @@ -237,7 +234,7 @@ public: class CGetLoadProcessor : public CWorkerNodeControlServer::IRequestProcessor { public: - virtual bool Authenticate(const string& host, + virtual bool Authenticate(const string& /*host*/, const string& auth, const string& queue, CNcbiOstream& os, diff --git a/c++/src/connect/services/grid_control_thread.hpp b/c++/src/connect/services/grid_control_thread.hpp index ac5b53e6..2b7fe0f5 100644 --- a/c++/src/connect/services/grid_control_thread.hpp +++ b/c++/src/connect/services/grid_control_thread.hpp @@ -2,7 +2,7 @@ #define _GRID_CONTROL_THREADD_HPP_ -/* $Id: grid_control_thread.hpp 443514 2014-08-14 21:35:38Z kazimird $ +/* $Id: grid_control_thread.hpp 512595 2016-09-01 15:29:40Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -54,11 +54,11 @@ public: public: virtual ~IRequestProcessor() {} - virtual bool Authenticate(const string& host, - const string& auth, - const string& queue, - CNcbiOstream& reply, - CWorkerNodeControlServer* control_server) + virtual bool Authenticate(const string& /*host*/, + const string& /*auth*/, + const string& /*queue*/, + CNcbiOstream& /*reply*/, + CWorkerNodeControlServer* /*control_server*/) { return true; } diff --git a/c++/src/connect/services/grid_globals.cpp b/c++/src/connect/services/grid_globals.cpp index e3f50232..ac429b31 100644 --- a/c++/src/connect/services/grid_globals.cpp +++ b/c++/src/connect/services/grid_globals.cpp @@ -1,4 +1,4 @@ -/* $Id: grid_globals.cpp 455687 2015-01-02 17:47:12Z kazimird $ +/* $Id: grid_globals.cpp 532734 2017-04-07 21:19:41Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -158,7 +158,7 @@ void CWNJobWatcher::Print(CNcbiOstream& os) const NStr::PrintableString(it->first->GetJobInput()) << "\" -- running for " << (int) it->second.elasped_time.Elapsed() << " seconds."; - if (it->second.flag) + if (it->second.is_stuck) os << "!!! LONG RUNNING JOB !!!"; os << "\n"; } @@ -170,11 +170,13 @@ void CWNJobWatcher::CheckForInfiniteLoop() size_t count = 0; CMutexGuard guard(m_ActiveJobsMutex); NON_CONST_ITERATE(TActiveJobs, it, m_ActiveJobs) { - if (!it->second.flag) { + if (!it->second.is_stuck) { if ( it->second.elasped_time.Elapsed() > m_InfiniteLoopTime) { - ERR_POST_X(3, "An infinite loop is detected in job " - << it->first->GetJobKey()); - it->second.flag = true; + const auto job_key = it->first->GetJobKey(); + ERR_POST_X(3, "An infinite loop is detected in job " << job_key); + GetDiagContext().Extra().Print("job_key", job_key); + + it->second.is_stuck = true; CGridGlobals::GetInstance(). RequestShutdown(CNetScheduleAdmin::eShutdownImmediate); } @@ -194,7 +196,7 @@ void CWNJobWatcher::x_KillNode(CGridWorkerNode worker) CMutexGuard guard(m_ActiveJobsMutex); NON_CONST_ITERATE(TActiveJobs, it, m_ActiveJobs) { CNetScheduleJob& job = it->first->GetJob(); - if (!it->second.flag) + if (!it->second.is_stuck) worker.GetNSExecutor().ReturnJob(job); else { job.error_msg = "Job execution time exceeded " + diff --git a/c++/src/connect/services/grid_rw_impl.cpp b/c++/src/connect/services/grid_rw_impl.cpp index 9e36e9a2..073c0ba0 100644 --- a/c++/src/connect/services/grid_rw_impl.cpp +++ b/c++/src/connect/services/grid_rw_impl.cpp @@ -1,4 +1,4 @@ -/* $Id: grid_rw_impl.cpp 489744 2016-01-15 16:50:24Z sadyrovr $ +/* $Id: grid_rw_impl.cpp 537554 2017-06-01 16:19:22Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,9 +31,21 @@ #include +#include + +#include + #include #include +#include + +#include +#include +#include +#include +#include + #define NCBI_USE_ERRCODE_X ConnServ_ReadWrite @@ -44,64 +56,341 @@ static const char s_JobOutputPrefixNetCache[] = "K "; #define JOB_OUTPUT_PREFIX_LEN 2 -CStringOrBlobStorageWriter::CStringOrBlobStorageWriter(size_t max_string_size, - SNetCacheAPIImpl* storage, string& job_output_ref) : - m_Storage(storage), m_Data(job_output_ref), m_MaxBuffSize(max_string_size) +struct SDataDirectWriter : IEmbeddedStreamWriter +{ + SDataDirectWriter(const CNetScheduleJob& job); + + ERW_Result Write(const void* buf, size_t count, size_t* bytes_written = 0) override; + ERW_Result Flush() override; + + void Close() override; + void Abort() override; + +private: + bool Connect(); + + enum { Created, Connected, Off } m_State; + CListeningSocket m_ListeningSocket; + unique_ptr m_TransmissionWriter; +}; + +SDataDirectWriter::SDataDirectWriter(const CNetScheduleJob& job) : + m_State(Off) +{ + if (m_ListeningSocket.Listen(0) != eIO_Success) return; + + auto local_host = CSocketAPI::GetLocalHostAddress(); + auto local_port = m_ListeningSocket.GetPort(eNH_HostByteOrder); + + auto other_host = job.submitter.first; + auto other_port = job.submitter.second; + + if (other_host.empty() || !other_port) return; + + ostringstream oss; + oss << "job_key=" << job.job_id << "&job_status=ReadyToWrite&worker_node_host=" << local_host << + "&worker_node_port=" << local_port; + + CDatagramSocket udp_socket; + auto buf = oss.str(); + + if (udp_socket.Send(buf.data(), buf.size(), other_host, other_port) != eIO_Success) return; + + m_State = Created; +} + +bool SDataDirectWriter::Connect() +{ + CSocket* socket = nullptr; + STimeout timeout{ 0, 1 }; + + if (m_ListeningSocket.Accept(socket, &timeout) != eIO_Success) return false; + + auto socket_writer = new CSocketReaderWriter(socket, eTakeOwnership, eIO_WritePlain); + m_TransmissionWriter.reset(new CTransmissionWriter(socket_writer, eTakeOwnership)); + m_State = Connected; + return true; +} + +ERW_Result SDataDirectWriter::Write(const void* buf, size_t count, size_t* bytes_written) +{ + if (m_State == Off) return eRW_Timeout; + + if ((m_State != Connected) && !Connect()) return eRW_Timeout; + + if (m_TransmissionWriter->Write(buf, count, bytes_written) == eRW_Success) return eRW_Success; + + Abort(); + return eRW_Error; +} + +ERW_Result SDataDirectWriter::Flush() +{ + if (m_State != Connected) return eRW_Success; + + if (m_TransmissionWriter->Flush() == eRW_Success) return eRW_Success; + + Abort(); + return eRW_Error; +} + +void SDataDirectWriter::Close() +{ + if (m_State != Connected) return; + + m_TransmissionWriter->SetSendEof(CTransmissionWriter::eSendEofPacket); + Abort(); +} + +void SDataDirectWriter::Abort() +{ + if (m_State != Connected) return; + + m_TransmissionWriter->Close(); + m_TransmissionWriter.reset(); +} + +struct SMultiWriter : IEmbeddedStreamWriter +{ + SMultiWriter(initializer_list init); + ERW_Result Write(const void* buf, size_t count, size_t* bytes_written = 0) override; + ERW_Result Flush() override; + + void Close() override; + void Abort() override; + +private: + using TBuffer = deque; + using TWriter = unique_ptr; + using TWriterPos = size_t; + using TWriterInfo = pair; + using TWriters = list; + + template + ERW_Result Do(bool all_writers, TAction action); + + ERW_Result WriteImpl(TWriters::iterator i); + + TBuffer m_Buffer; + TWriters m_Writers; +}; + +SMultiWriter::SMultiWriter(initializer_list init) { - job_output_ref = s_JobOutputPrefixEmbedded; + for (auto p : init) { + m_Writers.emplace_back(TWriter(p), 0); + } } -ERW_Result CStringOrBlobStorageWriter::Write(const void* buf, - size_t count, - size_t* bytes_written) +template +ERW_Result SMultiWriter::Do(bool all_writers, TAction action) { - if (m_NetCacheWriter.get()) - return m_NetCacheWriter->Write(buf, count, bytes_written); + bool any_success = false; + auto i = m_Writers.begin(); + + while (i != m_Writers.end()) { + try { + switch (action(i)) { + case eRW_Success: + if (!all_writers) return eRW_Success; + + any_success = true; + /* FALL THROUGH */ + + case eRW_Timeout: + ++i; + continue; + + default: + break; + } + } + catch (...) { + } + + i = m_Writers.erase(i); + } + + return m_Writers.empty() ? eRW_Error : (any_success ? eRW_Success : eRW_Timeout); +} + +ERW_Result SMultiWriter::Write(const void* buf, size_t count, size_t* bytes_written) +{ + if (bytes_written) *bytes_written = count; + if (!count) return eRW_Success; + + m_Buffer.insert(m_Buffer.end(), static_cast(buf), static_cast(buf) + count); - if (m_Data.size() + count <= m_MaxBuffSize) { + return Do(false, [&](TWriters::iterator i) { + return WriteImpl(i); + }); +} + +ERW_Result SMultiWriter::WriteImpl(TWriters::iterator i) +{ + array buf; + + for (;;) { + auto start = m_Buffer.cbegin() + i->second; + const size_t max = distance(start, m_Buffer.cend()); + size_t to_write = min(buf.size(), max); + + if (!to_write) return eRW_Success; + + copy_n(start, to_write, buf.begin()); + + char* data = buf.data(); + size_t written = 0; + + while (to_write) { + auto result = i->first->Write(data, to_write, &written); + + switch (result) { + case eRW_Success: + data += written; + to_write -= written; + i->second += written; + continue; + + default: + return result; + } + } + } +} + +ERW_Result SMultiWriter::Flush() +{ + return Do(false, [](TWriters::iterator i) { + return i->first->Flush(); + }); +} + +void SMultiWriter::Close() +{ + Do(true, [&](TWriters::iterator i) { + WriteImpl(i); + i->first->Close(); + return eRW_Success; + }); +} + +void SMultiWriter::Abort() +{ + Do(true, [](TWriters::iterator i) { + i->first->Abort(); + return eRW_Success; + }); +} + +CStringOrWriter::CStringOrWriter(size_t max_data_size, string& data_ref, TWriterCreate writer_create) : + m_MaxDataSize(max_data_size), + m_Data(data_ref), + m_WriterCreate(writer_create) +{ + m_Data = s_JobOutputPrefixEmbedded; +} + +ERW_Result CStringOrWriter::Write(const void* buf, size_t count, size_t* bytes_written) +{ + if (m_Writer) return m_Writer->Write(buf, count, bytes_written); + + if (m_Data.size() + count <= m_MaxDataSize) { m_Data.append((const char*) buf, count); - if (bytes_written != NULL) - *bytes_written = count; + if (bytes_written) *bytes_written = count; return eRW_Success; } string key; - m_NetCacheWriter.reset(m_Storage.PutData(&key)); + unique_ptr writer(m_WriterCreate(key)); + + if (!writer) return eRW_Error; if (m_Data.size() > JOB_OUTPUT_PREFIX_LEN) { - ERW_Result ret = m_NetCacheWriter->Write( + ERW_Result ret = writer->Write( m_Data.data() + JOB_OUTPUT_PREFIX_LEN, m_Data.size() - JOB_OUTPUT_PREFIX_LEN); - if (ret != eRW_Success) { - m_NetCacheWriter.reset(NULL); - return ret; - } + if (ret != eRW_Success) return ret; } m_Data = s_JobOutputPrefixNetCache + key; - return m_NetCacheWriter->Write(buf, count, bytes_written); + m_Writer = move(writer); + return m_Writer->Write(buf, count, bytes_written); } -ERW_Result CStringOrBlobStorageWriter::Flush(void) +ERW_Result CStringOrWriter::Flush(void) { - return m_NetCacheWriter.get() ? m_NetCacheWriter->Flush() : eRW_Success; + return m_Writer ? m_Writer->Flush() : eRW_Success; } -void CStringOrBlobStorageWriter::Close() +void CStringOrWriter::Close() { - if (m_NetCacheWriter.get()) - m_NetCacheWriter->Close(); + if (m_Writer) m_Writer->Close(); } -void CStringOrBlobStorageWriter::Abort() +void CStringOrWriter::Abort() { - if (m_NetCacheWriter.get()) - m_NetCacheWriter->Abort(); + if (m_Writer) m_Writer->Abort(); } +CStringOrWriter::TWriterCreate s_NetCacheWriterCreate(CNetCacheAPI api) +{ + return [api](string& key) mutable { return api.PutData(&key); }; +} + +CStringOrBlobStorageWriter::CStringOrBlobStorageWriter(size_t max_string_size, + SNetCacheAPIImpl* storage, string& job_output_ref) : + CStringOrWriter(max_string_size, job_output_ref, s_NetCacheWriterCreate(storage)) +{ +} + +CNcbiOstream& SGridWrite::operator()(CNetCacheAPI nc_api, size_t embedded_max_size, string& data) +{ + writer.reset(new CStringOrBlobStorageWriter(embedded_max_size, nc_api, data)); + + stream.reset(new CWStream(writer.get(), 0, 0, CRWStreambuf::fLeakExceptions)); + stream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); + + return *stream; +} + +CNcbiOstream& SGridWrite::operator()(CNetCacheAPI nc_api, size_t embedded_max_size, bool direct_output, CNetScheduleJob& job) +{ + if (!direct_output) return operator()(nc_api, embedded_max_size, job.output); + + using TWriter = unique_ptr; + + auto l = [nc_api, &job](string& key) mutable { + TWriter direct_writer(new SDataDirectWriter(job)); + TWriter nc_writer(nc_api.PutData(&key)); + TWriter multi_writer(new SMultiWriter{direct_writer.get(), nc_writer.get()}); + + direct_writer.release(); + nc_writer.release(); + return multi_writer.release(); + }; + + writer.reset(new CStringOrWriter(embedded_max_size, job.output, l)); + + stream.reset(new CWStream(writer.get(), 0, 0, CRWStreambuf::fLeakExceptions)); + stream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); + + return *stream; +} + +void SGridWrite::Reset(bool flush) +{ + if (flush && stream) stream->flush(); + stream.reset(); + + if (writer) { + writer->Close(); + writer.reset(); + } +} //////////////////////////////////////////////////////////////////////////// // @@ -192,4 +481,19 @@ ERW_Result CStringOrBlobStorageReader::PendingCount(size_t* count) return eRW_Success; } +CNcbiIstream& SGridRead::operator()(CNetCacheAPI nc_api, const string& data, size_t* data_size) +{ + auto reader = new CStringOrBlobStorageReader(data, nc_api, data_size); + + stream.reset(new CRStream(reader, 0, 0, CRWStreambuf::fOwnReader | CRWStreambuf::fLeakExceptions)); + stream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); + + return *stream; +} + +void SGridRead::Reset() +{ + stream.reset(); +} + END_NCBI_SCOPE diff --git a/c++/src/connect/services/grid_worker.cpp b/c++/src/connect/services/grid_worker.cpp index d0553942..16f588a2 100644 --- a/c++/src/connect/services/grid_worker.cpp +++ b/c++/src/connect/services/grid_worker.cpp @@ -1,4 +1,4 @@ -/* $Id: grid_worker.cpp 509503 2016-08-05 19:09:23Z fukanchi $ +/* $Id: grid_worker.cpp 537169 2017-05-26 15:43:05Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -76,7 +76,7 @@ class CGridControlThread : public CThread { public: CGridControlThread(SGridWorkerNodeImpl* worker_node, - unsigned int start_port, unsigned int end_port) : m_Control( + unsigned short start_port, unsigned short end_port) : m_Control( new CWorkerNodeControlServer(worker_node, start_port, end_port)), m_ThreadName(worker_node->GetAppName() + "_ct") { @@ -298,7 +298,7 @@ public: virtual ~CIdleWatcher() {}; - virtual void Notify(const CWorkerNodeJobContext& job, EEvent event) + virtual void Notify(const CWorkerNodeJobContext&, EEvent event) { if (event == eJobStarted) { m_RunningJobs.Add(1); @@ -355,15 +355,13 @@ void CGridWorkerNode::Init() { m_Impl->m_Listener->OnInit(&m_Impl->m_App); - IRWRegistry& reg = m_Impl->m_App.GetConfig(); + const IRegistry& reg = m_Impl->m_App.GetConfig(); if (reg.GetBool("log", "merge_lines", false)) { SetDiagPostFlag(eDPF_PreMergeLines); SetDiagPostFlag(eDPF_MergeLines); } - reg.Set(kNetScheduleAPIDriverName, "discover_low_priority_servers", "true"); - m_Impl->m_NetScheduleAPI = CNetScheduleAPI(reg); m_Impl->m_NetCacheAPI = CNetCacheAPI(reg, kEmptyStr, m_Impl->m_NetScheduleAPI); @@ -445,6 +443,7 @@ void SGridWorkerNodeImpl::x_WNCoreInit() "log_progress", false, 0, IRegistry::eErrPost); m_ThreadPoolTimeout = reg.GetInt(kServerSec, "thread_pool_timeout", 30, 0, IRegistry::eErrPost); + m_DirectOutput = reg.GetBool(kServerSec, "direct_output", false, 0, IRegistry::eErrPost); } void SGridWorkerNodeImpl::x_StartWorkerThreads() @@ -524,7 +523,7 @@ int SGridWorkerNodeImpl::Run( const CArgs& args = m_App.GetArgs(); - unsigned int start_port, end_port; + unsigned short start_port, end_port; {{ string control_port_arg(args["control_port"] ? @@ -537,8 +536,8 @@ int SGridWorkerNodeImpl::Run( from_port, to_port, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); - start_port = NStr::StringToUInt(from_port); - end_port = to_port.empty() ? start_port : NStr::StringToUInt(to_port); + start_port = NStr::StringToNumeric(from_port); + end_port = to_port.empty() ? start_port : NStr::StringToNumeric(to_port); }} #ifdef NCBI_OS_UNIX @@ -1083,9 +1082,19 @@ string CGridWorkerNode::GetAppName() const return m_Impl->m_JobProcessorFactory->GetAppName(); } -const CVersion& CGridWorkerNode::GetAppVersion() const +CGridWorkerNode::TVersion CGridWorkerNode::GetAppVersion() const { - return m_Impl->m_App.GetFullVersion(); + const CVersion& version(m_Impl->m_App.GetFullVersion()); + const CVersionInfo& version_info(version.GetVersionInfo()); + const SBuildInfo& build_info(version.GetBuildInfo()); + + const auto& job_factory(m_Impl->m_JobProcessorFactory); + _ASSERT(job_factory.get()); + const string job_version(job_factory->GetAppVersion()); + + // Double braces to suppress erroneous Clang warning (Bug 21629) + return TVersion{{ job_version.empty() ? version_info.Print() : job_version, + build_info.date, build_info.tag }}; } CNetCacheAPI CGridWorkerNode::GetNetCacheAPI() const diff --git a/c++/src/connect/services/grid_worker_impl.hpp b/c++/src/connect/services/grid_worker_impl.hpp index 4ce913ef..ec6e03a6 100644 --- a/c++/src/connect/services/grid_worker_impl.hpp +++ b/c++/src/connect/services/grid_worker_impl.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES__GRID_WORKER_IMPL__HPP #define CONNECT_SERVICES__GRID_WORKER_IMPL__HPP -/* $Id: grid_worker_impl.hpp 518714 2016-11-07 18:04:33Z ivanov $ +/* $Id: grid_worker_impl.hpp 537169 2017-05-26 15:43:05Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,7 +37,9 @@ #include "wn_cleanup.hpp" #include "netschedule_api_impl.hpp" -#include +#include + +#include BEGIN_NCBI_SCOPE @@ -68,6 +70,9 @@ struct SWorkerNodeJobContextImpl : public CObject const CDeadline GetTimeout() const { return m_Deadline; } void ResetTimeout(unsigned seconds) { m_Deadline = CDeadline(seconds, 0); } + CNcbiIstream& GetIStream(); + CNcbiOstream& GetOStream(); + SGridWorkerNodeImpl* m_WorkerNode; CNetScheduleJob m_Job; CWorkerNodeJobContext::ECommitStatus m_JobCommitStatus; @@ -83,9 +88,8 @@ struct SWorkerNodeJobContextImpl : public CObject CRequestRateControl m_ProgressMsgThrottler; CNetScheduleExecutor m_NetScheduleExecutor; CNetCacheAPI m_NetCacheAPI; - auto_ptr m_RStream; - auto_ptr m_Writer; - auto_ptr m_WStream; + SGridRead m_GridRead; + SGridWrite m_GridWrite; // Used for the job "pullback" mechanism. unsigned m_JobGeneration; @@ -254,27 +258,45 @@ struct SGridWorkerNodeImpl : public CObject bool m_ProgressLogRequested; size_t m_QueueEmbeddedOutputSize; unsigned m_ThreadPoolTimeout; + bool m_DirectOutput; /// Bookkeeping of jobs being executed (to prevent simultaneous runs of the same job) struct SJobsInProgress { - bool Add(const string& id) + bool Add(const CNetScheduleJob& job) + { + TFastMutexGuard lock(m_Mutex); + auto it = m_Jobs.find(job.job_id); + + if (it == m_Jobs.end()) { + return m_Jobs.emplace(job.job_id, job.auth_token).second; + } + + it->second = job.auth_token; + return false; + } + + void Update(CNetScheduleJob& job) { TFastMutexGuard lock(m_Mutex); - return m_Ids.insert(id).second; + auto it = m_Jobs.find(job.job_id); + + _ASSERT(it != m_Jobs.end()); + job.auth_token = it->second; } - size_t Remove(const string& id) + void Remove(const CNetScheduleJob& job) { TFastMutexGuard lock(m_Mutex); - const size_t erased = m_Ids.erase(id); - _ASSERT(erased); - return erased; + auto it = m_Jobs.find(job.job_id); + + _ASSERT(it != m_Jobs.end()); + m_Jobs.erase(it); } private: CFastMutex m_Mutex; - unordered_set m_Ids; + unordered_map m_Jobs; }; SJobsInProgress m_JobsInProgress; diff --git a/c++/src/connect/services/json_over_uttp.cpp b/c++/src/connect/services/json_over_uttp.cpp index 8c37858e..058ae545 100644 --- a/c++/src/connect/services/json_over_uttp.cpp +++ b/c++/src/connect/services/json_over_uttp.cpp @@ -1,4 +1,4 @@ -/* $Id: json_over_uttp.cpp 502217 2016-05-23 15:32:11Z sadyrovr $ +/* $Id: json_over_uttp.cpp 527718 2017-02-15 17:27:37Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -97,8 +97,7 @@ const char* CJsonException::GetErrCodeString() const } } -typedef CRef > TJsonNodeRef; +typedef CNetRef TJsonNodeRef; struct SJsonObjectElement { SJsonObjectElement(const string& key, SJsonNodeImpl* node_impl) : @@ -300,24 +299,34 @@ CJsonNode CJsonNode::NewArrayNode() return new SJsonArrayNodeImpl; } -CJsonNode CJsonNode::NewStringNode(const string& value) +CJsonNode::CJsonNode(const string& value) + : m_Impl(new SJsonStringNodeImpl(value)) { - return new SJsonStringNodeImpl(value); } -CJsonNode CJsonNode::NewIntegerNode(Int8 value) +CJsonNode::CJsonNode(const char* value) + : m_Impl(new SJsonStringNodeImpl(value)) { - return new SJsonFixedSizeNodeImpl(value); } -CJsonNode CJsonNode::NewDoubleNode(double value) +CJsonNode::CJsonNode(int value) + : CJsonNode(new SJsonFixedSizeNodeImpl(Int8(value))) { - return new SJsonFixedSizeNodeImpl(value); } -CJsonNode CJsonNode::NewBooleanNode(bool value) +CJsonNode::CJsonNode(Int8 value) + : CJsonNode(new SJsonFixedSizeNodeImpl(value)) +{ +} + +CJsonNode::CJsonNode(double value) + : CJsonNode(new SJsonFixedSizeNodeImpl(value)) +{ +} + +CJsonNode::CJsonNode(bool value) + : CJsonNode(new SJsonFixedSizeNodeImpl(value)) { - return new SJsonFixedSizeNodeImpl(value); } CJsonNode CJsonNode::NewNullNode() @@ -384,11 +393,38 @@ CJsonNode CJsonNode::GuessType(const CTempString& value) NewStringNode(value); } +CJsonNode::TInstance s_CreateImpl(CJsonNode::ENodeType type) +{ + switch (type) + { + case CJsonNode::eObject: return new SJsonObjectNodeImpl; + case CJsonNode::eArray: return new SJsonArrayNodeImpl; + case CJsonNode::eString: return new SJsonStringNodeImpl(string()); + case CJsonNode::eInteger: return new SJsonFixedSizeNodeImpl(Int8()); + case CJsonNode::eDouble: return new SJsonFixedSizeNodeImpl(double()); + case CJsonNode::eBoolean: return new SJsonFixedSizeNodeImpl(bool()); + case CJsonNode::eNull: return new SJsonFixedSizeNodeImpl(); + } + + NCBI_THROW_FMT(CJsonException, eInvalidNodeType, "Unknown type: " << type); + return nullptr; // Not reached +} + +CJsonNode::CJsonNode(ENodeType type) : + m_Impl(s_CreateImpl(type)) +{ +} + CJsonNode::ENodeType CJsonNode::GetNodeType() const { return m_Impl->m_NodeType; } +string CJsonNode::GetTypeName() const +{ + return m_Impl->GetTypeName(); +} + struct SJsonObjectKeyIterator : public SJsonIteratorImpl { SJsonObjectKeyIterator(SJsonObjectNodeImpl* container) : @@ -402,8 +438,7 @@ struct SJsonObjectKeyIterator : public SJsonIteratorImpl virtual bool Next(); virtual bool IsValid() const; - CRef > m_Container; + CNetRef m_Container; TJsonObjectElements::iterator m_Iterator; }; @@ -443,8 +478,7 @@ struct SJsonObjectElementOrderIterator : public SJsonIteratorImpl virtual bool Next(); virtual bool IsValid() const; - CRef > m_Container; + CNetRef m_Container; TJsonObjectElementOrder::iterator m_Iterator; }; @@ -484,8 +518,7 @@ struct SJsonArrayIterator : public SJsonIteratorImpl virtual bool Next(); virtual bool IsValid() const; - CRef > m_Container; + CNetRef m_Container; TJsonNodeVector::iterator m_Iterator; }; diff --git a/c++/src/connect/services/netcache_api.cpp b/c++/src/connect/services/netcache_api.cpp index b5b41115..3f0a8b7e 100644 --- a/c++/src/connect/services/netcache_api.cpp +++ b/c++/src/connect/services/netcache_api.cpp @@ -1,4 +1,4 @@ -/* $Id: netcache_api.cpp 520436 2016-11-28 18:34:35Z ivanov $ +/* $Id: netcache_api.cpp 535008 2017-05-04 16:02:37Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -87,14 +87,11 @@ CRef CNetCacheServerListener::AllocServerProperties() return CRef(new SNetCacheServerProperties); } -CConfig* CNetCacheServerListener::OnPreInit(CObject* api_impl, - CConfig* config, string* config_section, string& client_name) +void CNetCacheServerListener::OnPreInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections, string& client_name) { SNetCacheAPIImpl* nc_impl = static_cast(api_impl); _ASSERT(nc_impl); - _ASSERT(nc_impl->m_Service); - _ASSERT(config_section); if (CNetScheduleAPI api = nc_impl->m_NetScheduleAPI) { // Use client name from NetSchedule if it's not provided for NetCache @@ -102,85 +99,57 @@ CConfig* CNetCacheServerListener::OnPreInit(CObject* api_impl, client_name = api.GetExecutor().GetClientName(); } - CNetScheduleConfigLoader loader( - "nc.", "netcache_conf_from_netschedule"); - return loader.Get(api, config, *config_section); - } + CNetScheduleConfigLoader loader(registry, sections, false); - return NULL; + loader(api); + } } -void CNetCacheServerListener::OnInit(CObject* api_impl, - CConfig* config, const string& config_section) +void CNetCacheServerListener::OnInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections) { SNetCacheAPIImpl* nc_impl = static_cast(api_impl); m_Auth = nc_impl->m_Service->MakeAuthString(); - if (nc_impl->m_Service->GetClientName().length() < 3) { + nc_impl->Init(registry, sections); +} + +void SNetCacheAPIImpl::Init(ISynRegistry& registry, const SRegSynonyms& sections) +{ + if (m_Service->GetClientName().length() < 3) { NCBI_THROW(CNetCacheException, eAuthenticationError, "Client name is too short or empty"); } - const string default_temp_dir("."); - - if (config != NULL) { - string temp_dir = config->GetString(config_section, - "tmp_dir", CConfig::eErr_NoThrow, kEmptyStr); - - if (temp_dir.empty()) - temp_dir = config->GetString(config_section, - "tmp_path", CConfig::eErr_NoThrow, default_temp_dir); - - nc_impl->m_TempDir = temp_dir.empty() ? default_temp_dir : temp_dir; - - nc_impl->m_CacheInput = config->GetBool(config_section, - "cache_input", CConfig::eErr_NoThrow, false); + m_TempDir = registry.Get(sections, { "tmp_dir", "tmp_path" }, "."); + m_CacheInput = registry.Get(sections, "cache_input", false); + m_CacheOutput = registry.Get(sections, "cache_output", false); + const bool prolong_on_write = registry.Get(sections, "prolong_blob_lifetime_on_write", true); + const bool create_on_write = registry.Get(sections, "create_blob_on_write", true); - nc_impl->m_CacheOutput = config->GetBool(config_section, - "cache_output", CConfig::eErr_NoThrow, false); + m_DefaultParameters.SetMirroringMode( registry.Get(sections, "enable_mirroring", kEmptyStr)); + m_DefaultParameters.SetServerCheck( registry.Get(sections, "server_check", kEmptyStr)); + m_DefaultParameters.SetServerCheckHint(registry.Get(sections, "server_check_hint", kEmptyStr)); + m_DefaultParameters.SetUseCompoundID( registry.Get(sections, "use_compound_id", false)); - nc_impl->m_DefaultParameters.SetMirroringMode( - config->GetString(config_section, "enable_mirroring", - CConfig::eErr_NoThrow, kEmptyStr)); + const auto allowed_services = registry.Get(sections, "allowed_services", kEmptyStr); - nc_impl->m_DefaultParameters.SetServerCheck( - config->GetString(config_section, - "server_check", CConfig::eErr_NoThrow, kEmptyStr)); + m_FlagsOnWrite = (prolong_on_write ? 0 : 1) | (create_on_write ? 0 : 2); - nc_impl->m_DefaultParameters.SetServerCheckHint( - config->GetString(config_section, - "server_check_hint", CConfig::eErr_NoThrow, kEmptyStr)); + if (allowed_services.empty()) return; - if (config->GetBool(config_section, - "use_compound_id", CConfig::eErr_NoThrow, false)) - nc_impl->m_DefaultParameters.SetUseCompoundID(true); + m_ServiceMap.Restrict(); - const auto allowed_services = config->GetString(config_section, - "allowed_services", CConfig::eErr_NoThrow, kEmptyStr); + vector services; + NStr::Split(allowed_services, ", ", services, + NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); - if (!allowed_services.empty()) { - nc_impl->m_ServiceMap.Restrict(); - - vector services; - NStr::Split(allowed_services, ", ", services, - NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); - - for (auto& service : services) { - // Do not add configured service, it is always allowed - if (NStr::CompareNocase(service, - nc_impl->m_Service.GetServiceName())) { - nc_impl->m_ServiceMap.AddToAllowed(service); - } - } + for (auto& service : services) { + // Do not add configured service, it is always allowed + if (NStr::CompareNocase(service, + m_Service.GetServiceName())) { + m_ServiceMap.AddToAllowed(service); } - - nc_impl->m_ProlongBlobLifetimeOnWrite = config->GetBool(config_section, - "prolong_blob_lifetime_on_write", CConfig::eErr_NoThrow, true); - } else { - nc_impl->m_TempDir = default_temp_dir; - nc_impl->m_CacheInput = false; - nc_impl->m_CacheOutput = false; } } @@ -262,27 +231,20 @@ CRef CNetCacheServerListener::x_GetServerProperties( const char* const kNetCacheAPIDriverName = "netcache_api"; -static const char* const s_NetCacheConfigSections[] = { - kNetCacheAPIDriverName, - "netcache_client", - "netcache", - NULL -}; - -SNetCacheAPIImpl::SNetCacheAPIImpl(CConfig* config, const string& section, +SNetCacheAPIImpl::SNetCacheAPIImpl(SConfigOrRegistry conf_or_reg, const string& section, const string& service, const string& client_name, CNetScheduleAPI::TInstance ns_api) : - m_Service(new SNetServiceImpl("NetCacheAPI", client_name, + m_Service(new SNetServiceImpl("NetCacheAPI", service, client_name, new CNetCacheServerListener)), m_NetScheduleAPI(ns_api), m_DefaultParameters(eVoid) { - m_Service->Init(this, service, config, section, s_NetCacheConfigSections); + m_Service->Init(this, conf_or_reg, { section, kNetCacheAPIDriverName, "netcache_client", "netcache" }); } -SNetCacheAPIImpl::SNetCacheAPIImpl(const string& api_name, +SNetCacheAPIImpl::SNetCacheAPIImpl(const string& api_name, const string& service, const string& client_name, INetServerConnectionListener* listener) : - m_Service(new SNetServiceImpl(api_name, client_name, listener)), + m_Service(new SNetServiceImpl(api_name, service, client_name, listener)), m_DefaultParameters(eVoid) { } @@ -511,11 +473,10 @@ CNetCacheAPI::CNetCacheAPI(CNetCacheAPI::EAppRegistry /* use_app_reg */, } CNetCacheAPI::CNetCacheAPI(const IRegistry& reg, const string& conf_section, - CNetScheduleAPI::TInstance ns_api) + CNetScheduleAPI::TInstance ns_api) : + m_Impl(new SNetCacheAPIImpl(reg, conf_section, + kEmptyStr, kEmptyStr, ns_api)) { - CConfig conf(reg); - m_Impl = new SNetCacheAPIImpl(&conf, conf_section, - kEmptyStr, kEmptyStr, ns_api); } CNetCacheAPI::CNetCacheAPI(CConfig* conf, const string& conf_section, @@ -571,7 +532,7 @@ CNetServerConnection SNetCacheAPIImpl::InitiateWriteCmd( m_UseNextSubHitID.ProperCommand(); AppendClientIPSessionIDPasswordAgeHitID(&cmd, parameters); - if (!m_ProlongBlobLifetimeOnWrite) cmd.append(" flags=1"); + if (m_FlagsOnWrite) cmd.append(" flags=").append(to_string(m_FlagsOnWrite)); CNetServer::SExecResult exec_result; @@ -986,7 +947,7 @@ CNetCacheAPI CNetCacheAPI::GetServer(CNetServer::TInstance server) void CNetCacheAPI::SetEventHandler(INetEventHandler* event_handler) { - m_Impl->GetListener()->m_EventHandler = event_handler; + m_Impl->m_Service->SetEventHandler(event_handler); } CCompoundIDPool CNetCacheAPI::GetCompoundIDPool() diff --git a/c++/src/connect/services/netcache_api_impl.hpp b/c++/src/connect/services/netcache_api_impl.hpp index 1d820fa0..21ebb6f2 100644 --- a/c++/src/connect/services/netcache_api_impl.hpp +++ b/c++/src/connect/services/netcache_api_impl.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES___NETCACHE_API_IMPL__HPP #define CONNECT_SERVICES___NETCACHE_API_IMPL__HPP -/* $Id: netcache_api_impl.hpp 520437 2016-11-28 18:35:09Z ivanov $ +/* $Id: netcache_api_impl.hpp 535008 2017-05-04 16:02:37Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -51,36 +51,30 @@ struct SNetCacheServerProperties : public INetServerProperties bool mirrored; }; -class NCBI_XCONNECT_EXPORT CNetCacheServerListener : - public INetServerConnectionListener +class NCBI_XCONNECT_EXPORT CNetCacheServerListener : public INetServerConnectionListener { public: - virtual CRef AllocServerProperties(); + CRef AllocServerProperties() override; -public: - virtual CConfig* OnPreInit(CObject* api_impl, - CConfig* config, string* config_section, string& client_name); - virtual void OnInit(CObject* api_impl, - CConfig* config, const string& config_section); - virtual void OnConnected(CNetServerConnection& connection); - virtual void OnError(const string& err_msg, CNetServer& server); - virtual void OnWarning(const string& warn_msg, CNetServer& server); + void OnPreInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections, string& client_name) override; + void OnInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections) override; + void OnConnected(CNetServerConnection& connection) override; + void OnError(const string& err_msg, CNetServer& server) override; + void OnWarning(const string& warn_msg, CNetServer& server) override; - static CRef x_GetServerProperties( - SNetServerImpl* server_impl); + static CRef x_GetServerProperties(SNetServerImpl* server_impl); string m_Auth; - CRef m_EventHandler; }; struct NCBI_XCONNECT_EXPORT SNetCacheAPIImpl : public CObject { - SNetCacheAPIImpl(CConfig* config, const string& section, + SNetCacheAPIImpl(SConfigOrRegistry conf_or_reg, const string& section, const string& service, const string& client_name, CNetScheduleAPI::TInstance ns_api); // For use by SNetICacheClientImpl - SNetCacheAPIImpl(const string& api_name, const string& client_name, + SNetCacheAPIImpl(const string& api_name, const string& service, const string& client_name, INetServerConnectionListener* listener); // Special constructor for CNetCacheAPI::GetServer(). @@ -120,11 +114,7 @@ struct NCBI_XCONNECT_EXPORT SNetCacheAPIImpl : public CObject SNetServiceImpl::eRethrowServerErrors, INetServerConnectionListener* conn_listener = NULL); - CNetCacheServerListener* GetListener() - { - return static_cast( - m_Service->m_Listener.GetPointer()); - } + void Init(ISynRegistry& registry, const SRegSynonyms& sections); CNetService m_Service; @@ -141,7 +131,7 @@ struct NCBI_XCONNECT_EXPORT SNetCacheAPIImpl : public CObject CCompoundIDPool m_CompoundIDPool; SUseNextSubHitID m_UseNextSubHitID; - bool m_ProlongBlobLifetimeOnWrite = true; + size_t m_FlagsOnWrite = 0; }; struct SNetCacheAdminImpl : public CObject diff --git a/c++/src/connect/services/netcache_key.cpp b/c++/src/connect/services/netcache_key.cpp index 5c75707c..fa5a02ce 100644 --- a/c++/src/connect/services/netcache_key.cpp +++ b/c++/src/connect/services/netcache_key.cpp @@ -1,4 +1,4 @@ -/* $Id: netcache_key.cpp 445349 2014-09-03 19:16:54Z kazimird $ +/* $Id: netcache_key.cpp 524755 2017-01-13 16:18:16Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,7 +32,7 @@ #include -#include "util.hpp" +#include #include #include @@ -274,7 +274,8 @@ bool CNetCacheKey::ParseBlobKey(const char* key_str, static void AppendServiceNameExtension(string& blob_id, const string& service_name) { - blob_id.append(g_NumberOfUnderscoresPlusOne(service_name), '_'); + auto c = 1 + count(service_name.begin(), service_name.end(), '_'); + blob_id.append(c, '_'); blob_id.append("S_", 2); blob_id.append(service_name); } diff --git a/c++/src/connect/services/netcache_rw.cpp b/c++/src/connect/services/netcache_rw.cpp index 0d3bafd4..2b8cd5bb 100644 --- a/c++/src/connect/services/netcache_rw.cpp +++ b/c++/src/connect/services/netcache_rw.cpp @@ -1,4 +1,4 @@ -/* $Id: netcache_rw.cpp 495903 2016-03-22 15:17:00Z sadyrovr $ +/* $Id: netcache_rw.cpp 524754 2017-01-13 16:16:42Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -164,37 +164,6 @@ ERW_Result CNetCacheReader::Read(void* buf, return eRW_Success; } -ERW_Result g_ReadFromNetCache(IReader* reader, - char* buf, size_t count, size_t* bytes_read) -{ - size_t iter_bytes_read; - size_t total_bytes_read = 0; - ERW_Result rw_res = eRW_Success; - - while (count > 0) { - rw_res = reader->Read(buf, count, &iter_bytes_read); - if (rw_res == eRW_Success) { - total_bytes_read += iter_bytes_read; - buf += iter_bytes_read; - count -= iter_bytes_read; - } else if (rw_res == eRW_Eof) - break; - else { - const CNetCacheReader* netcache_reader = - static_cast(reader); - NCBI_THROW_FMT(CNetCacheException, eBlobClipped, - "I/O error while reading NetCache BLOB " << - netcache_reader->GetBlobID() << ": " << - g_RW_ResultToString(rw_res)); - } - } - - if (bytes_read != NULL) - *bytes_read = total_bytes_read; - - return rw_res; -} - ERW_Result CNetCacheReader::PendingCount(size_t* count) { if (m_CachingEnabled || m_BlobBytesToRead == 0) { diff --git a/c++/src/connect/services/netcache_search.cpp b/c++/src/connect/services/netcache_search.cpp index b4b2bd7e..5e93b3b1 100644 --- a/c++/src/connect/services/netcache_search.cpp +++ b/c++/src/connect/services/netcache_search.cpp @@ -1,4 +1,4 @@ -/* $Id: netcache_search.cpp 520437 2016-11-28 18:35:09Z ivanov $ +/* $Id: netcache_search.cpp 540265 2017-07-05 14:45:55Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -475,23 +475,40 @@ size_t SBlobInfoImpl::operator[](SIZE) const string kSeparator = "\t"; -void SBlobInfoImpl::Parse() +pair s_GetField(const string& data, size_t& pos) { - vector fields; + size_t eq = data.find("=", pos); + + if (eq == string::npos) { + NCBI_THROW_FMT(CNetCacheException, eInvalidServerResponse, "Invalid response '" << data << "'"); + } + + CTempString name(data, pos, eq - pos); + + pos = data.find(kSeparator, ++eq); + + if (pos == string::npos) pos = data.size(); - NStr::Split(m_Data, kSeparator, fields); + CTempString value(data, eq, pos++ - eq); + + return make_pair(name, value); +} + +void SBlobInfoImpl::Parse() +{ + for (size_t pos = 0; pos < m_Data.size(); ) { + const auto field = s_GetField(m_Data, pos); + const auto& name = field.first; + const auto& value = field.second; - for (auto& field : fields) { - string name, value; - NStr::SplitInTwo(field, "=", name, value); if (name == "cr_time") { - m_Created = time_point(seconds(stoll(value))); + m_Created = time_point(seconds(NStr::StringToNumeric(value))); } else if (name == "exp") { - m_Expires = time_point(seconds(stoll(value))); + m_Expires = time_point(seconds(NStr::StringToNumeric(value))); } else if (name == "ver_dead") { - m_VersionExpires = time_point(seconds(stoll(value))); + m_VersionExpires = time_point(seconds(NStr::StringToNumeric(value))); } else if (name == "size") { - m_Size = stoull(value); + m_Size = NStr::StringToNumeric(value); } else { NCBI_THROW_FMT(CNetCacheException, eInvalidServerResponse, "Unknown field '" << name << "' in response '" << m_Data << "'"); diff --git a/c++/src/connect/services/neticache_client.cpp b/c++/src/connect/services/neticache_client.cpp index 3f14c070..375b52f0 100644 --- a/c++/src/connect/services/neticache_client.cpp +++ b/c++/src/connect/services/neticache_client.cpp @@ -1,4 +1,4 @@ -/* $Id: neticache_client.cpp 520437 2016-11-28 18:35:09Z ivanov $ +/* $Id: neticache_client.cpp 535008 2017-05-04 16:02:37Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -65,19 +65,11 @@ BEGIN_NCBI_SCOPE class CNetICacheServerListener : public CNetCacheServerListener { protected: - virtual void OnInit(CObject* api_impl, - CConfig* config, const string& config_section); + void OnInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections) override; }; const char* const kNetICacheDriverName = "netcache"; -static const char* const s_NetICacheConfigSections[] = { - "netcache_api", - "netcache_client", - kNetICacheDriverName, - NULL -}; - static string s_CheckKeySubkey( const string& key, const string& subkey, string* encoded_key) { @@ -116,7 +108,7 @@ static string s_KeyVersionSubkeyToBlobID( { string blob_id(kEmptyStr); blob_id.reserve(1 + key.length() + 2 + - int(sizeof(version) * 1.5) + 2 + subkey.length() + 1); + int((double)sizeof(version) * 1.5) + 2 + subkey.length() + 1); string encoded_subkey(s_CheckKeySubkey(key, subkey, &blob_id)); @@ -135,33 +127,18 @@ static const char s_NetICacheAPIName[] = "NetICacheClient"; struct SNetICacheClientImpl : public SNetCacheAPIImpl, protected CConnIniter { - SNetICacheClientImpl(CConfig* config, + SNetICacheClientImpl(SConfigOrRegistry conf_or_reg, const string& section, const string& service_name, const string& client_name, const string& cache_name) : - SNetCacheAPIImpl(s_NetICacheAPIName, client_name, + SNetCacheAPIImpl(s_NetICacheAPIName, service_name, client_name, new CNetICacheServerListener), m_CacheFlags(ICache::fBestPerformance) { m_DefaultParameters.SetCacheName(cache_name); - m_Service->Init(this, service_name, - config, section, s_NetICacheConfigSections); - } - - SNetICacheClientImpl(const IRegistry& reg, - const string& section, - const string& service_name, - const string& client_name, - const string& cache_name) : - SNetCacheAPIImpl(s_NetICacheAPIName, client_name, - new CNetICacheServerListener), - m_CacheFlags(ICache::fBestPerformance) - { - m_DefaultParameters.SetCacheName(cache_name); - CConfig config(reg); - m_Service->Init(this, service_name, - &config, section, s_NetICacheConfigSections); + m_Service->Init(this, conf_or_reg, + { section, "netcache_api", "netcache_client", kNetICacheDriverName }); } CNetServer::SExecResult ChooseServerAndExec(const string& cmd, @@ -194,46 +171,33 @@ struct SNetICacheClientImpl : public SNetCacheAPIImpl, protected CConnIniter size_t* blob_size_ptr, const CNamedParameterList* optional); + void Init(ISynRegistry& registry, const SRegSynonyms& sections); + ICache::TFlags m_CacheFlags; }; -void CNetICacheServerListener::OnInit(CObject* api_impl, - CConfig* config, const string& config_section) +void CNetICacheServerListener::OnInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections) { - CNetCacheServerListener::OnInit(api_impl, config, config_section); + CNetCacheServerListener::OnInit(api_impl, registry, sections); SNetICacheClientImpl* icache_impl = static_cast(api_impl); - if (icache_impl->m_DefaultParameters.GetCacheName().empty()) { - if (config == NULL) { - NCBI_THROW(CNetCacheException, - eAuthenticationError, "ICache database name is not defined"); - } else { - try { - icache_impl->m_DefaultParameters.SetCacheName( - config->GetString(config_section, - "name", CConfig::eErr_Throw, kEmptyStr)); - } - catch (exception&) { - icache_impl->m_DefaultParameters.SetCacheName( - config->GetString(config_section, - "cache_name", CConfig::eErr_Throw, - "default_cache")); - } - } - } + icache_impl->Init(registry, sections); +} + +void SNetICacheClientImpl::Init(ISynRegistry& registry, const SRegSynonyms& sections) +{ + auto cache_name = m_DefaultParameters.GetCacheName(); - if (icache_impl->m_DefaultParameters.GetCacheName().length() > - MAX_ICACHE_CACHE_NAME_LENGTH) { - NCBI_THROW(CNetCacheException, - eAuthenticationError, "NetICache: cache name is too long"); + if (cache_name.empty()) cache_name = registry.Get(sections, { "name", "cache_name" }, "default_cache"); + + if (cache_name.length() > MAX_ICACHE_CACHE_NAME_LENGTH) { + NCBI_THROW(CNetCacheException, eAuthenticationError, "NetICache: cache name is too long"); } - if (config != NULL) - icache_impl->m_DefaultParameters.SetTryAllServers( - config->GetBool(config_section, - "try_all_servers", CConfig::eErr_NoThrow, false)); + m_DefaultParameters.SetCacheName(cache_name); + m_DefaultParameters.SetTryAllServers(registry.Get(sections, "try_all_servers", false)); } CNetServerConnection SNetICacheClientImpl::InitiateWriteCmd( @@ -249,13 +213,13 @@ CNetServerConnection SNetICacheClientImpl::InitiateWriteCmd( cmd.append(" confirm=1"); m_UseNextSubHitID.ProperCommand(); AppendClientIPSessionIDPasswordAgeHitID(&cmd, parameters); - if (!m_ProlongBlobLifetimeOnWrite) cmd.append(" flags=1"); + if (m_FlagsOnWrite) cmd.append(" flags=").append(to_string(m_FlagsOnWrite)); return ChooseServerAndExec(cmd, nc_writer->GetKey(), false, parameters).conn; } -CNetICacheClient::CNetICacheClient(EAppRegistry use_app_reg, +CNetICacheClient::CNetICacheClient(EAppRegistry, const string& conf_section) : m_Impl(new SNetICacheClientImpl(NULL, conf_section, kEmptyStr, kEmptyStr, kEmptyStr)) @@ -406,13 +370,13 @@ CNetServer::SExecResult SNetICacheClientImpl::ChooseServerAndExec( return exec_result; } -void CNetICacheClient::RegisterSession(unsigned pid) +void CNetICacheClient::RegisterSession(unsigned) { NCBI_THROW(CNetCacheException, eNotImplemented, "SMR is not implemented"); } -void CNetICacheClient::UnRegisterSession(unsigned pid) +void CNetICacheClient::UnRegisterSession(unsigned) { NCBI_THROW(CNetCacheException, eNotImplemented, "SMU is not implemented"); } @@ -430,9 +394,7 @@ void CNetICacheClient::SetFlags(ICache::TFlags flags) } -void CNetICacheClient::SetTimeStampPolicy(TTimeStampFlags policy, - unsigned int timeout, - unsigned int max_timeout) +void CNetICacheClient::SetTimeStampPolicy(TTimeStampFlags, unsigned, unsigned) { NCBI_THROW(CNetCacheException, eNotImplemented, "STSP is not implemented"); } @@ -456,7 +418,7 @@ bool CNetICacheClient::IsOpen() const } -void CNetICacheClient::SetVersionRetention(EKeepVersions policy) +void CNetICacheClient::SetVersionRetention(EKeepVersions) { NCBI_THROW(CNetCacheException, eNotImplemented, "SVRP is not implemented"); } @@ -511,65 +473,13 @@ size_t CNetICacheClient::GetBlobSize(const string& key, } -void CNetICacheClient::GetBlobOwner(const string& key, - int version, - const string& subkey, - string* owner) +void CNetICacheClient::GetBlobOwner(const string&, int, const string&, + string* owner) { ERR_POST("NetCache command 'GBLW' has been phased out"); *owner = kEmptyStr; } -list CNetICacheClient::GetSubkeyList(const string& key) -{ - CNetServerMultilineCmdOutput output( - m_Impl->ChooseServerAndExec( - m_Impl->MakeStdCmd("BLIST", key, &m_Impl->m_DefaultParameters), - key, - true, - &m_Impl->m_DefaultParameters)); - - output->SetNetCacheCompatMode(); - string line; - - if (!output.ReadLine(line)) { - NCBI_THROW(CNetCacheException, eInvalidServerResponse, - "Failed to read SIZE field"); - } - - const string kSize = "SIZE="; - string::size_type pos = line.find(kSize); - - if (pos == string::npos) { - NCBI_THROW(CNetCacheException, eInvalidServerResponse, - "No SIZE field in reply to BLIST command"); - } - - Int8 to_read = NStr::StringToInt8(line.substr(pos + kSize.size()), - NStr::fAllowTrailingSymbols); - - list result; - - while (to_read > 0) { - output.ReadLine(line); - to_read -= line.size() + 1; // Plus newline character - - vector blob; - NStr::Split(line, ",", blob, NStr::fSplit_NoMergeDelims); - - // It should be "cachename,key,subkey" - if (blob.size() != 3) { - NCBI_THROW_FMT(CNetCacheException, eInvalidServerResponse, - "Unexpected response format: " << line); - } - - // Only subkey is used - result.push_back(blob[2]); - } - - return result; -} - IReader* SNetICacheClientImpl::GetReadStreamPart( const string& key, int version, const string& subkey, size_t offset, size_t part_size, @@ -739,9 +649,7 @@ void CNetICacheClient::RemoveBlob(const string& key, m_Impl->ExecStdCmd("REMO", key, version, subkey, ¶meters); } -time_t CNetICacheClient::GetAccessTime(const string& key, - int version, - const string& subkey) +time_t CNetICacheClient::GetAccessTime(const string&, int, const string&) { NCBI_THROW(CNetCacheException, eNotImplemented, "GACT is not implemented"); } @@ -773,31 +681,43 @@ bool CNetICacheClient::HasBlob(const string& key, const string& subkey, } } -void CNetICacheClient::Purge(time_t access_timeout, - EKeepVersions keep_last_version) +void CNetICacheClient::Purge(time_t access_timeout, EKeepVersions keep_last_version) { - NCBI_THROW(CNetCacheException, eNotImplemented, "PRG1 is not implemented"); + Purge(kEmptyStr, kEmptyStr, access_timeout, keep_last_version); } -void CNetICacheClient::Purge(const string& /*key*/, - const string& /*subkey*/, - time_t /*access_timeout*/, - EKeepVersions /*keep_last_version*/) +void CNetICacheClient::Purge(const string& key, + const string& subkey, + time_t access_timeout, + EKeepVersions) { - NCBI_THROW(CNetCacheException, eNotImplemented, "PRG1 is not implemented"); -} + if (access_timeout) { + NCBI_THROW(CNetCacheException, eNotImplemented, "Not implemented"); + } -IReader* CNetICacheClient::GetReadStream( - const string& key, - int version, - const string& subkey, - size_t* blob_size_ptr, - CNetCacheAPI::ECachingMode caching_mode, - CNetServer::TInstance server_to_use) -{ - return GetReadStreamPart(key, version, subkey, 0, 0, blob_size_ptr, - (nc_caching_mode = caching_mode, nc_server_to_use = server_to_use)); + if (!subkey.empty()) { + if (key.empty()) { + NCBI_THROW(CNetCacheException, eNotImplemented, "Not implemented"); + } + + return RemoveBlob(key, 0, subkey); + } + + // TODO: Replace with a command from CXX-8948 when it is deployed everywhere + using namespace ncbi::grid::netcache::search; + + // NB: 'size >= 0' condition is used to get all blobs + auto result = Search(key.empty() ? fields::size >= 0 : fields::key == key); + + for (auto& blob_info : result) { + try { + RemoveBlob(blob_info[fields::key], 0, blob_info[fields::subkey]); + } + catch (CNetCacheException& e) { + if (e.GetErrCode() != CNetCacheException::eBlobNotFound) throw; + } + } } IReader* CNetICacheClient::GetReadStream( @@ -929,14 +849,12 @@ public: { } - virtual CRef AllocServerProperties(); - virtual CConfig* OnPreInit(CObject* api_impl, - CConfig* config, string* config_section, string& client_name); - virtual void OnInit(CObject* api_impl, - CConfig* config, const string& config_section); - virtual void OnConnected(CNetServerConnection& connection); - virtual void OnError(const string& err_msg, CNetServer& server); - virtual void OnWarning(const string& warn_msg, CNetServer& server); + CRef AllocServerProperties() override; + void OnPreInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections, string& client_name) override; + void OnInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections) override; + void OnConnected(CNetServerConnection& connection) override; + void OnError(const string& err_msg, CNetServer& server) override; + void OnWarning(const string& warn_msg, CNetServer& server) override; CRef m_DelegateListener; string m_Key; @@ -949,17 +867,14 @@ CRef CSetValidWarningSuppressor::AllocServerProperties() return m_DelegateListener->AllocServerProperties(); } -CConfig* CSetValidWarningSuppressor::OnPreInit(CObject* api_impl, - CConfig* config, string* config_section, string& client_name) +void CSetValidWarningSuppressor::OnPreInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections, string& client_name) { - return m_DelegateListener->OnPreInit(api_impl, config, config_section, - client_name); + m_DelegateListener->OnPreInit(api_impl, registry, sections, client_name); } -void CSetValidWarningSuppressor::OnInit(CObject* api_impl, - CConfig* config, const string& config_section) +void CSetValidWarningSuppressor::OnInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections) { - m_DelegateListener->OnInit(api_impl, config, config_section); + m_DelegateListener->OnInit(api_impl, registry, sections); } void CSetValidWarningSuppressor::OnConnected(CNetServerConnection& connection) @@ -1097,14 +1012,14 @@ string CNetICacheClient::GetCacheName(void) const } -bool CNetICacheClient::SameCacheParams(const TCacheParams* params) const +bool CNetICacheClient::SameCacheParams(const TCacheParams*) const { return false; } void CNetICacheClient::SetEventHandler(INetEventHandler* event_handler) { - m_Impl->GetListener()->m_EventHandler = event_handler; + m_Impl->m_Service->SetEventHandler(event_handler); } vector CNetICacheClient::Search( diff --git a/c++/src/connect/services/netschedule_api.cpp b/c++/src/connect/services/netschedule_api.cpp index 67dbf74d..12f7ea31 100644 --- a/c++/src/connect/services/netschedule_api.cpp +++ b/c++/src/connect/services/netschedule_api.cpp @@ -1,4 +1,4 @@ -/* $Id: netschedule_api.cpp 514423 2016-09-21 17:22:32Z ivanov $ +/* $Id: netschedule_api.cpp 541657 2017-07-20 13:36:33Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -52,11 +53,28 @@ BEGIN_NCBI_SCOPE -void g_AppendClientIPSessionIDHitID(string& cmd) +namespace grid { +namespace netschedule { +namespace limits { + +void ThrowIllegalChar(const string& name, const string& value, char c) +{ + NCBI_THROW_FMT(CConfigException, eInvalidParameter, + "Invalid character '" << NStr::PrintableString(CTempString(&c, 1)) << + "' in the " << name << " \"" << NStr::PrintableString(value) << "\"."); +} + +} +} +} + +using namespace grid::netschedule; + +void g_AppendClientIPSessionIDHitID(string& cmd, bool use_next_sub_hit_id) { CRequestContext& req = CDiagContext::GetRequestContext(); g_AppendClientIPAndSessionID(cmd, req); - g_AppendHitID(cmd, req.GetCurrentSubHitID()); + g_AppendHitID(cmd, use_next_sub_hit_id ? req.GetNextSubHitID() : req.GetCurrentSubHitID()); } SNetScheduleNotificationThread::SNetScheduleNotificationThread( @@ -105,7 +123,7 @@ CNetScheduleNotificationHandler::CNetScheduleNotificationHandler() } int g_ParseNSOutput(const string& attr_string, const char* const* attr_names, - string* attr_values, int attr_count) + string* attr_values, size_t attr_count) { try { CUrlArgs attr_parser(attr_string); @@ -355,63 +373,37 @@ void SNetScheduleAPIImpl::x_ClearNode() } } -// The purpose of this class is to suppress possible errors -// when config loading is not enabled explicitly. -// -// Errors would happen when we try to load config from servers that either -// do not support "GETP2" command (introduced in 4.16.9) -// or, do not support "QINF2 service=name" command (introduced in 4.17.0) -// or, do not have "service to queue" mapping set -// or, are not actually NetSchedule servers but worker nodes -// or, are currently not reachable (behind some firewall) -// and need cross connectivity which is usually enabled later -// -// This class is turned off (becomes noop, by providing NULL as api_impl) -// when config loading is enabled explicitly -class CNetScheduleConfigLoader::CErrorSuppressor -{ -private: - typedef CRef THandlerRef; - - struct SHandler : public INetEventHandler - { - bool OnError(CException::TErrCode err_code) { return true; } - }; -public: - CErrorSuppressor(SNetScheduleAPIImpl* api_impl) : - m_ApiImpl(api_impl) - { - if (m_ApiImpl) { - THandlerRef& handler = m_ApiImpl->GetListener()->m_EventHandler; - m_OriginalHandler = handler; - handler = new SHandler; - m_MaxRetries = TServConn_ConnMaxRetries::GetDefault(); - TServConn_ConnMaxRetries::SetDefault(0); - } - } +CTempString s_GetSection(bool ns_conf) +{ + return ns_conf ? "netschedule_conf_from_netschedule" : "netcache_conf_from_netschedule"; +} - ~CErrorSuppressor() - { - if (m_ApiImpl) { - m_ApiImpl->GetListener()->m_EventHandler = m_OriginalHandler; - TServConn_ConnMaxRetries::SetDefault(m_MaxRetries); - } - } +CNetScheduleConfigLoader::CNetScheduleConfigLoader(ISynRegistry& registry, SRegSynonyms& sections, bool ns_conf) : + m_Registry(registry), m_Sections(sections), m_NsConf(ns_conf), m_Mode(eImplicit) +{ + sections.insert(sections.begin(), s_GetSection(m_NsConf)); -private: - SNetScheduleAPIImpl* m_ApiImpl; - THandlerRef m_OriginalHandler; - unsigned m_MaxRetries; -}; + const auto param = "load_config_from_ns"; -CNetScheduleConfigLoader::CNetScheduleConfigLoader( - const CTempString& prefix, const CTempString& section) : - m_Prefix(prefix), m_Section(section) -{ + if (m_Registry.Has(m_Sections, param)) { + m_Mode = m_Registry.Get(m_Sections, param, true) ? eExplicit : eOff; + } } -bool CNetScheduleConfigLoader::Transform(const CTempString& prefix, string& name) +bool CNetScheduleConfigLoader::Transform(const string& prefix, string& name) const { + if (m_NsConf) { + // If it's "service to queue" special case (we do not know queue name) + if (name == "queue_name") return true; + + // Queue parameter "timeout" determines the initial TTL of a submitted job. + // Since "timeout" is too generic, replaced it with "job_ttl" on client side. + if (name == "timeout") { + name = "job_ttl"; + return true; + } + } + // Only params starting with provided prefix are used if (NStr::StartsWith(name, prefix)) { name.erase(0, prefix.size()); @@ -421,98 +413,63 @@ bool CNetScheduleConfigLoader::Transform(const CTempString& prefix, string& name return false; } -CConfig* CNetScheduleConfigLoader::Parse(const TParams& params, - const CTempString& prefix) -{ - auto_ptr result; - - ITERATE(TParams, it, params) { - string param = it->first; - - if (Transform(prefix, param)) { - if (!result.get()) { - result.reset(new CConfig::TParamTree); - } - - result->AddNode(CConfig::TParamValue(param, it->second)); - } - } - - return result.get() ? new CConfig(result.release()) : NULL; -} - -CConfig* CNetScheduleConfigLoader::Get(SNetScheduleAPIImpl* impl, - CConfig* config, string& section) +bool CNetScheduleConfigLoader::operator()(SNetScheduleAPIImpl* impl) { _ASSERT(impl); - bool set_explicitly = false; + if (m_Mode == eOff) return false; - try { - if (config) { - // If it is disabled explicitly - if (!config->GetBool(section, "load_config_from_ns", - CConfig::eErr_Throw, true)) { - return NULL; - } + // Turn off any subsequent attempts + const auto mode = m_Mode; + m_Mode = eOff; - set_explicitly = true; - } - } - catch (CConfigException&) { - } + // Errors could happen when we try to load config from servers that either + // do not support "GETP2" command (introduced in 4.16.9) + // or, do not support "QINF2 service=name" command (introduced in 4.17.0) + // or, do not have "service to queue" mapping set + // or, are not actually NetSchedule servers but worker nodes + // or, are currently not reachable (behind some firewall) + // and need cross connectivity which is usually enabled later + // + // This guard is set to suppress errors and avoid retries if config loading is not enabled explicitly + shared_ptr try_guard; + if (mode == eImplicit) try_guard = impl->m_Service->GetTryGuard(); - // Disable error suppressor if config loading is set explicitly - CErrorSuppressor suppressor(set_explicitly ? NULL : impl); - TParams queue_params; + CNetScheduleAPI::TQueueParams queue_params; try { impl->GetQueueParams(kEmptyStr, queue_params); } catch (...) { - if (set_explicitly) throw; - return NULL; + if (mode == eExplicit) throw; + return false; } - if (CConfig* result = Parse(queue_params, m_Prefix)) { - section = m_Section; - return result; - } + CRef mem_registry(new CMemoryRegistry); + const string prefix = m_NsConf ? "ns." : "nc."; + const string section = s_GetSection(m_NsConf); - return NULL; -} + for (auto& param : queue_params) { + auto name = param.first; -CNetScheduleOwnConfigLoader::CNetScheduleOwnConfigLoader() : - CNetScheduleConfigLoader( - "ns.", "netschedule_conf_from_netschedule") -{ -} - -bool CNetScheduleOwnConfigLoader::Transform(const CTempString& prefix, - string& name) -{ - // If it's "service to queue" special case (we do not know queue name) - if (name == "queue_name") { - return true; + if (Transform(prefix, name)) { + mem_registry->Set(section, name, param.second); + } } - // Queue parameter "timeout" determines the initial TTL of a submitted job. - // Since "timeout" is too generic, replaced it with "job_ttl" on client side. - if (name == "timeout") { - name = "job_ttl"; - return true; - } + if (mem_registry->Empty()) return false; - return CNetScheduleConfigLoader::Transform(prefix, name); + m_Registry.Add(mem_registry.GetObject()); + return true; } -void CNetScheduleServerListener::SetAuthString(SNetScheduleAPIImpl* impl) +string SNetScheduleAPIImpl::MakeAuthString() { - string auth(impl->m_Service->MakeAuthString()); + string auth(m_Service->MakeAuthString()); - if (!impl->m_ProgramVersion.empty()) { + if (!m_ProgramVersion.empty()) { auth += " prog=\""; - auth += impl->m_ProgramVersion; + auth += m_ProgramVersion; auth += '\"'; } @@ -536,15 +493,15 @@ void CNetScheduleServerListener::SetAuthString(SNetScheduleAPIImpl* impl) break; } - if (!impl->m_ClientNode.empty()) { + if (!m_ClientNode.empty()) { auth += " client_node=\""; - auth += impl->m_ClientNode; + auth += m_ClientNode; auth += '\"'; } - if (!impl->m_ClientSession.empty()) { + if (!m_ClientSession.empty()) { auth += " client_session=\""; - auth += impl->m_ClientSession; + auth += m_ClientSession; auth += '\"'; } @@ -558,32 +515,24 @@ void CNetScheduleServerListener::SetAuthString(SNetScheduleAPIImpl* impl) } }} - ITERATE(SNetScheduleAPIImpl::TAuthParams, it, impl->m_AuthParams) { + ITERATE(SNetScheduleAPIImpl::TAuthParams, it, m_AuthParams) { auth += it->second; } auth += " ns_compat_ver=\"" COMPATIBLE_NETSCHEDULE_VERSION "\"" "\r\n"; - auth += impl->m_Queue; + auth += m_Queue; // Make the auth token look like a command to be able to // check for potential authentication/initialization errors // like the "queue not found" error. if (m_Mode & fNonWnCompatible) { auth += "\r\nVERSION"; - - if (!g_AppendClientIPAndSessionID(auth) && - !impl->m_ClientSession.empty()) { - auth += " sid=\""; - auth += NStr::PrintableString(impl->m_ClientSession); - auth += '"'; - } - - g_AppendHitID(auth); + g_AppendClientIPSessionIDHitID(auth); } - m_Auth = auth; + return auth; } bool CNetScheduleServerListener::NeedToSubmitAffinities( @@ -613,150 +562,68 @@ CRef CNetScheduleServerListener::AllocServerProperties() return CRef(new SNetScheduleServerProperties); } -// This class makes parameter reading to be performed only once -template -struct SCfgReader -{ - SCfgReader(TDestType& dest, - CConfig*& config, - const string& section, - const string& param, - const TSrcType& def_value = TSrcType(), - const list* synonyms = 0, - bool already_read = false) : - m_Dest(dest), - m_Config(config), - m_Section(section), - m_Param(param), - m_DefValue(def_value), - m_AlreadyRead(already_read), - m_Synonyms(synonyms) - { - if (!m_AlreadyRead) m_Dest = m_DefValue; - } - - bool ReadOnce() - { - _ASSERT(m_Config); - - if (m_AlreadyRead) return false; - - try { - m_Dest = m_Config->Get(m_Section, m_Param, - CConfig::eErr_Throw, m_DefValue, m_Synonyms); - } - catch (CConfigException&) { - return false; - } - - return m_AlreadyRead = true; - } - -private: - TDestType& m_Dest; - CConfig*& m_Config; - const string& m_Section; - const string m_Param; - const TSrcType m_DefValue; - bool m_AlreadyRead; - const list* m_Synonyms; -}; - -void CNetScheduleServerListener::OnInit( - CObject* api_impl, CConfig* config, const string& section) +void CNetScheduleServerListener::OnInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections) { SNetScheduleAPIImpl* ns_impl = static_cast(api_impl); _ASSERT(ns_impl); SetDiagUserAndHost(); + ns_impl->Init(registry, sections); +} + +void SNetScheduleAPIImpl::Init(ISynRegistry& registry, SRegSynonyms& sections) +{ + if (!m_Queue.empty()) limits::Check(m_Queue); const string& user(GetDiagContext().GetUsername()); - ns_impl->m_ClientNode = - ns_impl->m_Service->GetClientName() + "::" + + m_ClientNode = + m_Service->GetClientName() + "::" + (user.empty() ? kEmptyStr : user + '@') + GetDiagContext().GetHost(); - auto_ptr config_holder; - CNetScheduleOwnConfigLoader loader; - - string module = section; + m_Config.Init(registry, sections); - string& queue_ref = ns_impl->m_Queue; + CNetScheduleConfigLoader loader(registry, sections); - if (!queue_ref.empty()) { - SNetScheduleAPIImpl::VerifyQueueNameAlphabet(queue_ref); - } - - const list embedded_synonyms{"use_embedded_input"}; - bool use_affinities_value; - - SCfgReader queue(queue_ref, - config, module, "queue_name", kEmptyStr, 0, !queue_ref.empty()); - - SCfgReader embedded(ns_impl->m_UseEmbeddedStorage, - config, module, "use_embedded_storage", true, &embedded_synonyms); - - SCfgReader use_affinities(use_affinities_value, - config, module, "use_affinities"); - - SCfgReader job_group(ns_impl->m_JobGroup, - config, module, "job_group"); - - SCfgReader job_ttl(ns_impl->m_JobTtl, - config, module, "job_ttl"); - - SCfgReader client_node(ns_impl->m_ClientNode, - config, module, "client_node", ns_impl->m_ClientNode); - - SCfgReader scope(m_Scope, config, module, "scope"); + bool affinities_initialized = false; // There are two phases of OnInit in case we need to load config from server // 1) Setup as much as possible and try to get config from server // 2) Setup everything using received config from server - for (int phase = 0; phase < 2; ++phase) { - if (config) { - if (queue.ReadOnce()) { - SNetScheduleAPIImpl::VerifyQueueNameAlphabet(queue_ref); - } - - embedded.ReadOnce(); + do { + if (m_Queue.empty()) { + m_Queue = registry.Get(sections, "queue_name", ""); + if (!m_Queue.empty()) limits::Check(m_Queue); + } - if (use_affinities.ReadOnce() && use_affinities_value) { - ns_impl->InitAffinities(config, module); - } + m_UseEmbeddedStorage = registry.Get(sections, { "use_embedded_storage", "use_embedded_input" }, true); + m_JobGroup = registry.Get(sections, "job_group", ""); + m_JobTtl = registry.Get(sections, "job_ttl", 0); + m_ClientNode = registry.Get(sections, "client_node", m_ClientNode); + GetListener()->Scope() = registry.Get(sections, "scope", ""); - job_group.ReadOnce(); - job_ttl.ReadOnce(); - client_node.ReadOnce(); - scope.ReadOnce(); + if (!affinities_initialized && registry.Get(sections, "use_affinities", false)) { + affinities_initialized = true; + InitAffinities(registry, sections); } - if (!ns_impl->m_ClientNode.empty()) { - ns_impl->m_ClientSession = + if (!m_ClientNode.empty()) { + m_ClientSession = NStr::NumericToString(CDiagContext::GetPID()) + '@' + NStr::NumericToString(GetFastLocalTime().GetTimeT()) + ':' + GetDiagContext().GetStringUID(); } - SetAuthString(ns_impl); - - // If we should load config from NetSchedule server - // and have not done it already and not working in WN compatible mode - if (!phase && (m_Mode & fConfigLoading)) { - if (CConfig* alt = loader.Get(ns_impl, config, module)) { - config_holder.reset(alt); - config = alt; - continue; - } - } + GetListener()->SetAuthString(MakeAuthString()); - break; - } + // If not working in WN compatible mode + if (!(m_Mode & fConfigLoading)) break; + } while (loader(this)); } void CNetScheduleServerListener::OnConnected(CNetServerConnection& connection) { - if (m_Mode & fNonWnCompatible) { + if (m_NonWn) { string version_info(connection.Exec(m_Auth, false)); CNetServerInfo server_info(new SNetServerInfoImpl(version_info)); @@ -852,63 +719,57 @@ void CNetScheduleServerListener::OnWarning(const string& warn_msg, const char* const kNetScheduleAPIDriverName = "netschedule_api"; -static const char* const s_NetScheduleConfigSections[] = { - kNetScheduleAPIDriverName, - NULL -}; +SNetScheduleAPIImpl::SNetScheduleAPIImpl(SConfigOrRegistry conf_or_reg, const string& section) : + m_Mode(GetMode(false, true)), + m_Service(new SNetServiceImpl("NetScheduleAPI", kEmptyStr, kEmptyStr, + new CNetScheduleServerListener(m_Mode & fNonWnCompatible))) +{ + m_Service->Init(this, conf_or_reg, { section, kNetScheduleAPIDriverName }); +} -SNetScheduleAPIImpl::SNetScheduleAPIImpl( - CConfig* config, const string& section, - const string& service_name, const string& client_name, +SNetScheduleAPIImpl::SNetScheduleAPIImpl(const string& service_name, const string& client_name, const string& queue_name, bool wn, bool try_config) : - m_Service(new SNetServiceImpl("NetScheduleAPI", client_name, - new CNetScheduleServerListener(wn, try_config))), - m_Queue(queue_name), - m_AffinityPreference(CNetScheduleExecutor::eAnyJob), - m_JobTtl(0) + m_Mode(GetMode(wn, try_config)), + m_Service(new SNetServiceImpl("NetScheduleAPI", service_name, client_name, + new CNetScheduleServerListener(m_Mode & fNonWnCompatible))), + m_Queue(queue_name) { - m_Service->Init(this, service_name, - config, section, s_NetScheduleConfigSections); + m_Service->Init(this, nullptr, kNetScheduleAPIDriverName); } SNetScheduleAPIImpl::SNetScheduleAPIImpl( SNetServerInPool* server, SNetScheduleAPIImpl* parent) : + m_Mode(parent->m_Mode), m_Service(new SNetServiceImpl(server, parent->m_Service)), m_Queue(parent->m_Queue), m_ProgramVersion(parent->m_ProgramVersion), m_ClientNode(parent->m_ClientNode), m_ClientSession(parent->m_ClientSession), m_AffinityPreference(parent->m_AffinityPreference), - m_JobTtl(0), m_UseEmbeddedStorage(parent->m_UseEmbeddedStorage) { } CNetScheduleAPI::CNetScheduleAPI(CNetScheduleAPI::EAppRegistry /*use_app_reg*/, const string& conf_section /* = kEmptyStr */) : - m_Impl(new SNetScheduleAPIImpl(NULL, conf_section, - kEmptyStr, kEmptyStr, kEmptyStr)) + m_Impl(new SNetScheduleAPIImpl(nullptr, conf_section)) { } CNetScheduleAPI::CNetScheduleAPI(const IRegistry& reg, - const string& conf_section) + const string& conf_section) : + m_Impl(new SNetScheduleAPIImpl(reg, conf_section)) { - CConfig conf(reg); - m_Impl = new SNetScheduleAPIImpl(&conf, conf_section, - kEmptyStr, kEmptyStr, kEmptyStr); } CNetScheduleAPI::CNetScheduleAPI(CConfig* conf, const string& conf_section) : - m_Impl(new SNetScheduleAPIImpl(conf, conf_section, - kEmptyStr, kEmptyStr, kEmptyStr)) + m_Impl(new SNetScheduleAPIImpl(conf, conf_section)) { } CNetScheduleAPI::CNetScheduleAPI(const string& service_name, const string& client_name, const string& queue_name) : - m_Impl(new SNetScheduleAPIImpl(NULL, kEmptyStr, - service_name, client_name, queue_name)) + m_Impl(new SNetScheduleAPIImpl(service_name, client_name, queue_name)) { } @@ -999,6 +860,7 @@ CNetScheduleAPI::ENetScheduleWarningType EXTRACT_WARNING_TYPE(QueueAlreadyPaused); EXTRACT_WARNING_TYPE(QueueNotPaused); EXTRACT_WARNING_TYPE(CommandObsolete); + EXTRACT_WARNING_TYPE(JobNotRead); return eWarnUnknown; } @@ -1027,6 +889,7 @@ const char* CNetScheduleAPI::WarningTypeToString( WARNING_TYPE_TO_STRING(QueueAlreadyPaused); WARNING_TYPE_TO_STRING(QueueNotPaused); WARNING_TYPE_TO_STRING(CommandObsolete); + WARNING_TYPE_TO_STRING(JobNotRead); default: return "eWarnUnknown"; } @@ -1255,7 +1118,7 @@ void SNetScheduleAPIImpl::GetQueueParams( string cmd("QINF2 "); if (!queue_name.empty()) { - SNetScheduleAPIImpl::VerifyQueueNameAlphabet(queue_name); + limits::Check(queue_name); cmd += queue_name; } else if (!m_Queue.empty()) { @@ -1302,33 +1165,15 @@ void CNetScheduleAPI::GetProgressMsg(CNetScheduleJob& job) job.progress_msg = NStr::ParseEscapes(m_Impl->x_ExecOnce("MGET", job)); } -void SNetScheduleAPIImpl::VerifyQueueNameAlphabet(const string& queue_name) -{ - if (queue_name.empty()) { - NCBI_THROW_FMT(CConfigException, eParameterMissing, - "Queue name cannot be empty."); - } - if (queue_name[0] == '_') { - NCBI_THROW_FMT(CConfigException, eParameterMissing, - "Queue name cannot start with an underscore character."); - } - g_VerifyAlphabet(queue_name, "queue name", eCC_BASE64URL); -} - -static void s_VerifyClientCredentialString(const string& str, - const CTempString& param_name) +void CNetScheduleAPI::SetClientNode(const string& client_node) { - if (str.empty()) { + // Cannot add this to limits::SClientNode due to CNetScheduleAPIExt allowing reset to empty values + if (client_node.empty()) { NCBI_THROW_FMT(CConfigException, eParameterMissing, - "'" << param_name << "' cannot be empty"); + "'" << limits::SClientNode::Name() << "' cannot be empty"); } - g_VerifyAlphabet(str, param_name, eCC_RelaxedId); -} - -void CNetScheduleAPI::SetClientNode(const string& client_node) -{ - s_VerifyClientCredentialString(client_node, "client node ID"); + limits::Check(client_node); m_Impl->m_ClientNode = client_node; @@ -1337,7 +1182,13 @@ void CNetScheduleAPI::SetClientNode(const string& client_node) void CNetScheduleAPI::SetClientSession(const string& client_session) { - s_VerifyClientCredentialString(client_session, "client session ID"); + // Cannot add this to limits::SClientSession due to CNetScheduleAPIExt allowing reset to empty values + if (client_session.empty()) { + NCBI_THROW_FMT(CConfigException, eParameterMissing, + "'" << limits::SClientSession::Name() << "' cannot be empty"); + } + + limits::Check(client_session); m_Impl->m_ClientSession = client_session; @@ -1348,12 +1199,12 @@ void SNetScheduleAPIImpl::UpdateAuthString() { m_Service->m_ServerPool->ResetServerConnections(); - GetListener()->SetAuthString(this); + GetListener()->SetAuthString(MakeAuthString()); } void CNetScheduleAPI::SetClientType(CNetScheduleAPI::EClientType client_type) { - m_Impl->GetListener()->m_ClientType = client_type; + m_Impl->m_ClientType = client_type; m_Impl->UpdateAuthString(); } @@ -1380,19 +1231,12 @@ void SNetScheduleAPIImpl::SetAuthParam(const string& param_name, UpdateAuthString(); } -void SNetScheduleAPIImpl::InitAffinities(CConfig* config, const string& section) +void SNetScheduleAPIImpl::InitAffinities(ISynRegistry& registry, const SRegSynonyms& sections) { - const bool claim_new_affinities = config->GetBool(section, - "claim_new_affinities", CConfig::eErr_NoThrow, false); - - const bool process_any_job = config->GetBool(section, - "process_any_job", CConfig::eErr_NoThrow, false); - - const string affinity_list = config->GetString(section, - "affinity_list", CConfig::eErr_NoThrow, kEmptyStr); - - const string affinity_ladder = config->GetString(section, - "affinity_ladder", CConfig::eErr_NoThrow, kEmptyStr); + const bool claim_new_affinities = registry.Get(sections, "claim_new_affinities", false); + const bool process_any_job = registry.Get(sections, "process_any_job", false); + const string affinity_list = registry.Get(sections, "affinity_list", kEmptyStr); + const string affinity_ladder = registry.Get(sections, "affinity_ladder", kEmptyStr); if (affinity_ladder.empty()) { @@ -1412,7 +1256,7 @@ void SNetScheduleAPIImpl::InitAffinities(CConfig* config, const string& section) NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); for (auto& affinity : m_AffinityList) { - VerifyAffinityAlphabet(affinity); + limits::Check(affinity); } return; @@ -1441,7 +1285,7 @@ void SNetScheduleAPIImpl::InitAffinities(CConfig* config, const string& section) string affinity_step; for (auto& affinity : affinities) { - VerifyAffinityAlphabet(affinity); + limits::Check(affinity); if (!affinity_step.empty()) affinity_step += ','; affinity_step += affinity; @@ -1449,6 +1293,17 @@ void SNetScheduleAPIImpl::InitAffinities(CConfig* config, const string& section) } } +void SNetScheduleAPIImpl::SConfig::Init(ISynRegistry& registry, SRegSynonyms& sections) +{ + const auto kDOCTimeoutDefault = 0.03; + + double doc_timeout = registry.Get(sections, "direct_output_connect_timeout", kDOCTimeoutDefault); + + if (doc_timeout <= 0) doc_timeout = kDOCTimeoutDefault; + + g_CTimeoutToSTimeout(CTimeout(doc_timeout), direct_output_connect_timeout); +} + /////////////////////////////////////////////////////////////////////////////// /// @internal @@ -1492,8 +1347,7 @@ public: version.Match(NCBI_INTERFACE_VERSION(IFace)) != CVersionInfo::eNonCompatible) { CConfig config(params); - return new SNetScheduleAPIImpl(&config, m_DriverName, - kEmptyStr, kEmptyStr, kEmptyStr); + return new SNetScheduleAPIImpl(&config, m_DriverName); } return NULL; } @@ -1539,7 +1393,7 @@ void CNetScheduleAPIExt::UseOldStyleAuth() void CNetScheduleAPIExt::SetEventHandler(INetEventHandler* event_handler) { - m_Impl->GetListener()->m_EventHandler = event_handler; + m_Impl->m_Service->SetEventHandler(event_handler); } CCompoundIDPool CNetScheduleAPIExt::GetCompoundIDPool() @@ -1554,14 +1408,14 @@ CNetScheduleAPI CNetScheduleAPIExt::GetServer(CNetServer::TInstance server) void CNetScheduleAPIExt::ReSetClientNode(const string& client_node) { - g_VerifyAlphabet(client_node, "client node ID", eCC_RelaxedId); + limits::Check(client_node); m_Impl->m_ClientNode = client_node; m_Impl->UpdateAuthString(); } void CNetScheduleAPIExt::ReSetClientSession(const string& client_session) { - g_VerifyAlphabet(client_session, "client session ID", eCC_RelaxedId); + limits::Check(client_session); m_Impl->m_ClientSession = client_session; m_Impl->UpdateAuthString(); } @@ -1570,16 +1424,14 @@ CNetScheduleAPI::TInstance CNetScheduleAPIExt::CreateWnCompat(const string& service_name, const string& client_name) { - return new SNetScheduleAPIImpl(nullptr, kEmptyStr, - service_name, client_name, kEmptyStr, true, false); + return new SNetScheduleAPIImpl(service_name, client_name, kEmptyStr, true, false); } CNetScheduleAPI::TInstance CNetScheduleAPIExt::CreateNoCfgLoad(const string& service_name, const string& client_name, const string& queue_name) { - return new SNetScheduleAPIImpl(nullptr, kEmptyStr, - service_name, client_name, queue_name, false, false); + return new SNetScheduleAPIImpl(service_name, client_name, queue_name, false, false); } diff --git a/c++/src/connect/services/netschedule_api_admin.cpp b/c++/src/connect/services/netschedule_api_admin.cpp index 429b8a96..151fa882 100644 --- a/c++/src/connect/services/netschedule_api_admin.cpp +++ b/c++/src/connect/services/netschedule_api_admin.cpp @@ -1,4 +1,4 @@ -/* $Id: netschedule_api_admin.cpp 492051 2016-02-11 17:22:40Z sadyrovr $ +/* $Id: netschedule_api_admin.cpp 536834 2017-05-23 20:06:58Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -39,6 +39,8 @@ BEGIN_NCBI_SCOPE +using namespace grid::netschedule; + void CNetScheduleAdmin::SwitchToDrainMode(ESwitch on_off) { string cmd(on_off != eOff ? @@ -68,7 +70,7 @@ void CNetScheduleAdmin::ReloadServerConfig() void CNetScheduleAdmin::CreateQueue(const string& qname, const string& qclass, const string& description) { - SNetScheduleAPIImpl::VerifyQueueNameAlphabet(qname); + limits::Check(qname); string cmd = "QCRE " + qname; cmd += ' '; @@ -87,7 +89,7 @@ void CNetScheduleAdmin::CreateQueue(const string& qname, const string& qclass, void CNetScheduleAdmin::DeleteQueue(const string& qname) { - SNetScheduleAPIImpl::VerifyQueueNameAlphabet(qname); + limits::Check(qname); string cmd("QDEL " + qname); g_AppendClientIPSessionIDHitID(cmd); @@ -120,9 +122,7 @@ void CNetScheduleAdmin::CancelAllJobs(const string& job_statuses) cmd.assign("CANCEL status="); cmd.append(job_statuses); } - CRequestContext& req = CDiagContext::GetRequestContext(); - g_AppendClientIPAndSessionID(cmd, req); - g_AppendHitID(cmd, req.GetNextSubHitID()); + g_AppendClientIPSessionIDHitID(cmd, true); m_Impl->m_API->m_Service.ExecOnAllServers(cmd); } @@ -157,7 +157,7 @@ void CNetScheduleAdmin::DumpQueue( cmd.append(NStr::NumericToString(job_count)); } if (!job_group.empty()) { - SNetScheduleAPIImpl::VerifyJobGroupAlphabet(job_group); + limits::Check(job_group); cmd.append(" group="); cmd.append(job_group); } @@ -378,13 +378,13 @@ void CNetScheduleAdmin::StatusSnapshot( string cmd = "STAT JOBS"; if (!affinity_token.empty()) { - SNetScheduleAPIImpl::VerifyAffinityAlphabet(affinity_token); + limits::Check(affinity_token); cmd.append(" aff="); cmd.append(affinity_token); } if (!job_group.empty()) { - SNetScheduleAPIImpl::VerifyJobGroupAlphabet(job_group); + limits::Check(job_group); cmd.append(" group="); cmd.append(job_group); } diff --git a/c++/src/connect/services/netschedule_api_executor.cpp b/c++/src/connect/services/netschedule_api_executor.cpp index 442cca36..7e67c631 100644 --- a/c++/src/connect/services/netschedule_api_executor.cpp +++ b/c++/src/connect/services/netschedule_api_executor.cpp @@ -1,4 +1,4 @@ -/* $Id: netschedule_api_executor.cpp 518714 2016-11-07 18:04:33Z ivanov $ +/* $Id: netschedule_api_executor.cpp 537163 2017-05-26 15:32:47Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -40,12 +40,9 @@ BEGIN_NCBI_SCOPE -#define SKIP_SPACE(ptr) \ - while (isspace((unsigned char) *(ptr))) \ - ++ptr; +using namespace grid::netschedule; -static bool s_DoParseGet2JobResponse( - CNetScheduleJob& job, const string& response) +bool s_DoParseGet2JobResponse(CNetScheduleJob& job, const string& response) { enum { eJobKey, @@ -56,145 +53,73 @@ static bool s_DoParseGet2JobResponse( eClientSessionID, ePageHitID, eJobMask, + eSubmitterNotifHost, + eSubmitterNotifPort, eNumberOfJobBits }; int job_bits = 0; CUrlArgs url_parser(response); ITERATE(CUrlArgs::TArgs, field, url_parser.GetArgs()) { - switch (field->name[0]) { - case 'j': - if (field->name == "job_key") { - job_bits |= (1 << eJobKey); - job.job_id = field->value; - } - break; - case 'i': - if (field->name == "input") { - job_bits |= (1 << eJobInput); - job.input = field->value; - } - break; - - case 'a': - if (field->name == "auth_token") { - job_bits |= (1 << eJobAuthToken); - job.auth_token = field->value; - } else if (field->name == "affinity") { - job_bits |= (1 << eJobAffinity); - job.affinity = field->value; - } - break; - - case 'c': - if (field->name == "client_ip") { - job_bits |= (1 << eClientIP); - job.client_ip = field->value; - } else if (field->name == "client_sid") { - job_bits |= (1 << eClientSessionID); - job.session_id = field->value; - } - break; - - case 'm': - if (field->name == "mask") { - job_bits |= (1 << eJobMask); - job.mask = atoi(field->value.c_str()); - } - break; - case 'n': - if (field->name == "ncbi_phid") { - job_bits |= (1 << ePageHitID); - job.page_hit_id = field->value; - } + if (field->name == "job_key") { + job_bits |= (1 << eJobKey); + job.job_id = field->value; + + } else if (field->name == "input") { + job_bits |= (1 << eJobInput); + job.input = field->value; + + } else if (field->name == "auth_token") { + job_bits |= (1 << eJobAuthToken); + job.auth_token = field->value; + + } else if (field->name == "affinity") { + job_bits |= (1 << eJobAffinity); + job.affinity = field->value; + + } else if (field->name == "client_ip") { + job_bits |= (1 << eClientIP); + job.client_ip = field->value; + + } else if (field->name == "client_sid") { + job_bits |= (1 << eClientSessionID); + job.session_id = field->value; + + } else if (field->name == "mask") { + job_bits |= (1 << eJobMask); + job.mask = atoi(field->value.c_str()); + + } else if (field->name == "ncbi_phid") { + job_bits |= (1 << ePageHitID); + job.page_hit_id = field->value; + + } else if (field->name == "submitter_notif_host") { + job_bits |= (1 << eSubmitterNotifHost); + job.submitter.first = field->value; + + } else if (field->name == "submitter_notif_port") { + job_bits |= (1 << eSubmitterNotifPort); + job.submitter.second = static_cast(stoul(field->value)); + + // TODO: Remove after there are no NetSchedule servers of version 4.30.0 (with this typo) + } else if (field->name == "sumbitter_notif_host") { + job_bits |= (1 << eSubmitterNotifHost); + job.submitter.first = field->value; + } else if (field->name == "sumbitter_notif_port") { + job_bits |= (1 << eSubmitterNotifPort); + job.submitter.second = static_cast(stoul(field->value)); } + // TODO: End + if (job_bits == (1 << eNumberOfJobBits) - 1) break; } return !job.job_id.empty(); } -static bool s_DoParseGetJobResponse( - CNetScheduleJob& job, const string& response) -{ - // Server message format: - // JOB_KEY "input" "affinity" "client_ip session_id" mask auth_token - - // 1. Extract job ID. - const char* response_begin = response.c_str(); - const char* response_end = response_begin + response.length(); - - SKIP_SPACE(response_begin); - - if (*response_begin == 0) - return false; - - const char* ptr = response_begin; - - do - if (*++ptr == 0) - return false; - while (!isspace((unsigned char) (*ptr))); - - job.job_id.assign(response_begin, ptr - response_begin); - - while (isspace((unsigned char) *++ptr)) - ; - - try { - size_t field_len; - - // 2. Extract job input - job.input = NStr::ParseQuoted(CTempString(ptr, - response_end - ptr), &field_len); - - ptr += field_len; - SKIP_SPACE(ptr); - - // 3. Extract optional job affinity. - job.affinity = NStr::ParseQuoted(CTempString(ptr, - response_end - ptr), &field_len); - - ptr += field_len; - SKIP_SPACE(ptr); - - // 4. Extract optional "client_ip session_id". - string client_ip_and_session_id(NStr::ParseQuoted( - CTempString(ptr, response_end - ptr), &field_len)); - - NStr::SplitInTwo(client_ip_and_session_id, " ", - job.client_ip, job.session_id); - - ptr += field_len; - SKIP_SPACE(ptr); - - // 5. Parse job mask. - job.mask = atoi(ptr); - - while (!isspace((unsigned char) *ptr) && *ptr != '\0') - ++ptr; - - SKIP_SPACE(ptr); - - if (*ptr == '\0') { - ERR_POST("GET2: missing auth_token"); - return false; - } - - // 6. Retrieve auth token. - job.auth_token = ptr; - } - catch (CStringException& e) { - ERR_POST("Error while parsing GET2 response " << e); - return false; - } - - return true; -} - string s_GET2(CNetScheduleExecutor::EJobAffinityPreference affinity_preference); -bool g_ParseGetJobResponse(CNetScheduleJob& job, const string& response) +bool s_ParseGetJobResponse(CNetScheduleJob& job, const string& response) { if (response.empty()) return false; @@ -203,11 +128,8 @@ bool g_ParseGetJobResponse(CNetScheduleJob& job, const string& response) return s_DoParseGet2JobResponse(job, response); } catch (CUrlParserException&) { - if (s_DoParseGetJobResponse(job, response)) - return true; - NCBI_THROW(CNetScheduleException, eProtocolSyntaxError, - "Cannot parse server output for GET:\n" + response); + "Cannot parse server output for GET2:\n" + response); } } @@ -290,7 +212,7 @@ void SNetScheduleExecutorImpl::ClaimNewPreferredAffinity( CNetScheduleServerListener* listener = m_API->GetListener(); - CFastMutexGuard guard(listener->m_AffinitySubmissionMutex); + CFastMutexGuard sync_guard(listener->m_AffinitySubmissionMutex); listener->SetAffinitiesSynced(it.GetServer(), false); } @@ -343,7 +265,7 @@ bool SNetScheduleExecutorImpl::ExecGET(SNetServerImpl* server, exec_result, NULL, &get_cmd_listener); } - if (!g_ParseGetJobResponse(job, exec_result.response)) + if (!s_ParseGetJobResponse(job, exec_result.response)) return false; // Remember the server that issued this job. @@ -401,7 +323,7 @@ bool CNetScheduleExecutor::GetJob(CNetScheduleJob& job, cmd.erase(base_cmd.length()); m_Impl->m_NotificationHandler.CmdAppendTimeoutGroupAndClientInfo( cmd, deadline, m_Impl->m_JobGroup); - if (g_ParseGetJobResponse(job, server.ExecWithRetry(cmd, + if (s_ParseGetJobResponse(job, server.ExecWithRetry(cmd, false).response)) { // Remember the server that issued this job. job.server = server; @@ -472,7 +394,7 @@ string CNetScheduleNotificationHandler::MkBaseGETCmd( NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); ITERATE(list, token, affinity_tokens) { - SNetScheduleAPIImpl::VerifyAffinityAlphabet(*token); + limits::Check(*token); } cmd += " aff="; @@ -576,7 +498,7 @@ void CNetScheduleExecutor::PutResult(const CNetScheduleJob& job) string cmd("PUT2 job_key=" + job.job_id); - SNetScheduleAPIImpl::VerifyAuthTokenAlphabet(job.auth_token); + limits::Check(job.auth_token); cmd.append(" auth_token="); cmd.append(job.auth_token); @@ -625,7 +547,7 @@ void CNetScheduleExecutor::PutFailure(const CNetScheduleJob& job, string cmd("FPUT2 job_key=" + job.job_id); - SNetScheduleAPIImpl::VerifyAuthTokenAlphabet(job.auth_token); + limits::Check(job.auth_token); cmd.append(" auth_token="); cmd.append(job.auth_token); @@ -650,20 +572,20 @@ void CNetScheduleExecutor::Reschedule(const CNetScheduleJob& job) { string cmd("RESCHEDULE job_key=" + job.job_id); - SNetScheduleAPIImpl::VerifyAuthTokenAlphabet(job.auth_token); + limits::Check(job.auth_token); cmd += " auth_token="; cmd += job.auth_token; if (!job.affinity.empty()) { cmd += " aff=\""; - SNetScheduleAPIImpl::VerifyAffinityAlphabet(job.affinity); + limits::Check(job.affinity); cmd += NStr::PrintableString(job.affinity); cmd += '"'; } if (!job.group.empty()) { cmd += " group=\""; - SNetScheduleAPIImpl::VerifyJobGroupAlphabet(job.group); + limits::Check(job.group); cmd += NStr::PrintableString(job.group); cmd += '"'; } @@ -685,7 +607,7 @@ void SNetScheduleExecutorImpl::ReturnJob(const CNetScheduleJob& job, { string cmd("RETURN2 job_key=" + job.job_id); - SNetScheduleAPIImpl::VerifyAuthTokenAlphabet(job.auth_token); + limits::Check(job.auth_token); cmd.append(" auth_token="); cmd.append(job.auth_token); @@ -714,7 +636,7 @@ int SNetScheduleExecutorImpl::AppendAffinityTokens(string& cmd, ITERATE(vector, aff, *affs) { cmd.append(sep); - SNetScheduleAPIImpl::VerifyAffinityAlphabet(*aff); + limits::Check(*aff); cmd.append(*aff); sep = ","; } @@ -724,6 +646,11 @@ int SNetScheduleExecutorImpl::AppendAffinityTokens(string& cmd, if (action == eAddAffs) ITERATE(vector, aff, *affs) { + if (*aff == "-") { + NCBI_THROW(CNetScheduleException, eInvalidParameter, + "Affinity '-' cannot be added as a preferred one."); + } + m_PreferredAffinities.insert(*aff); } else diff --git a/c++/src/connect/services/netschedule_api_getjob.cpp b/c++/src/connect/services/netschedule_api_getjob.cpp index f6262f87..e3f37412 100644 --- a/c++/src/connect/services/netschedule_api_getjob.cpp +++ b/c++/src/connect/services/netschedule_api_getjob.cpp @@ -1,4 +1,4 @@ -/* $Id: netschedule_api_getjob.cpp 518714 2016-11-07 18:04:33Z ivanov $ +/* $Id: netschedule_api_getjob.cpp 518554 2016-11-04 13:37:00Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/connect/services/netschedule_api_getjob.hpp b/c++/src/connect/services/netschedule_api_getjob.hpp index 67fafd7d..a7fbe743 100644 --- a/c++/src/connect/services/netschedule_api_getjob.hpp +++ b/c++/src/connect/services/netschedule_api_getjob.hpp @@ -1,7 +1,7 @@ #ifndef CONN_SERVICES___NETSCHEDULE_API_GETJOB__HPP #define CONN_SERVICES___NETSCHEDULE_API_GETJOB__HPP -/* $Id: netschedule_api_getjob.hpp 518714 2016-11-07 18:04:33Z ivanov $ +/* $Id: netschedule_api_getjob.hpp 518554 2016-11-04 13:37:00Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/connect/services/netschedule_api_impl.hpp b/c++/src/connect/services/netschedule_api_impl.hpp index b3d14ee3..ce7eebdb 100644 --- a/c++/src/connect/services/netschedule_api_impl.hpp +++ b/c++/src/connect/services/netschedule_api_impl.hpp @@ -1,7 +1,7 @@ #ifndef CONN_SERVICES___NETSCHEDULE_API_IMPL__HPP #define CONN_SERVICES___NETSCHEDULE_API_IMPL__HPP -/* $Id: netschedule_api_impl.hpp 518714 2016-11-07 18:04:33Z ivanov $ +/* $Id: netschedule_api_impl.hpp 537390 2017-05-31 15:32:22Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -44,10 +44,93 @@ #include #include #include +#include BEGIN_NCBI_SCOPE +namespace grid { +namespace netschedule { +namespace limits { + +struct SClientNode +{ + static string Name() { return "client node ID"; } + static bool IsValidValue(const string&) { return false; } + static bool IsValidChar(char c) + { + return isalnum(c) || c == '_' || c == '-' || c == '.' || c == ':' || c == '@' || c == '|'; + } +}; + +struct SClientSession +{ + static string Name() { return "client session ID"; } + static bool IsValidValue(const string&) { return false; } + static bool IsValidChar(char c) + { + return isalnum(c) || c == '_' || c == '-' || c == '.' || c == ':' || c == '@' || c == '|'; + } +}; + +struct SQueueName +{ + static string Name() { return "queue name"; } + static bool IsValidValue(const string& s) + { + if (s.empty()) { + NCBI_THROW(CConfigException, eParameterMissing, "Queue name cannot be empty."); + } + if (s.front() == '_') { + NCBI_THROW(CConfigException, eInvalidParameter, "Queue name cannot start with underscore character."); + } + + return false; + } + static bool IsValidChar(char c) { return isalnum(c) || c == '_' || c == '-'; } +}; + +struct SJobGroup +{ + static string Name() { return "job group name"; } + static bool IsValidValue(const string& s) { return s == "-"; } + static bool IsValidChar(char c) { return isalnum(c) || c == '_' || c == '.'; } +}; + +struct SAffinity +{ + static string Name() { return "affinity token"; } + static bool IsValidValue(const string& s) { return s == "-"; } + static bool IsValidChar(char c) { return isalnum(c) || c == '_' || c == '.'; } +}; + +struct SAuthToken +{ + static string Name() { return "security token"; } + static bool IsValidValue(const string&) { return false; } + static bool IsValidChar(char c) { return isalnum(c) || c == '_' || c == '.'; } +}; + +void ThrowIllegalChar(const string&, const string&, char); + +template +void Check(const string& value) +{ + if (TValue::IsValidValue(value)) return; + + auto it = find_if_not(value.begin(), value.end(), TValue::IsValidChar); + + if (it != value.end()) { + ThrowIllegalChar(TValue::Name(), value, *it); + } +} + +} +} +} + +using namespace grid::netschedule; + //////////////////////////////////////////////////////////////////////////////// // @@ -55,8 +138,7 @@ BEGIN_NCBI_SCOPE #define SERVER_PARAMS_ASK_MAX_COUNT 100 inline -void g_AppendHitID(string& cmd, const string& sub_hit_id = - CDiagContext::GetRequestContext().GetCurrentSubHitID()) +void g_AppendHitID(string& cmd, const string& sub_hit_id) { cmd += " ncbi_phid=\""; cmd += sub_hit_id; @@ -64,8 +146,7 @@ void g_AppendHitID(string& cmd, const string& sub_hit_id = } inline -bool g_AppendClientIPAndSessionID(string& cmd, - const CRequestContext& req = CDiagContext::GetRequestContext()) +void g_AppendClientIPAndSessionID(string& cmd, const CRequestContext& req) { if (req.IsSetClientIP()) { cmd += " ip=\""; @@ -73,19 +154,12 @@ bool g_AppendClientIPAndSessionID(string& cmd, cmd += '"'; } - if (req.IsSetSessionID()) { - cmd += " sid=\""; - cmd += NStr::PrintableString(req.GetSessionID()); - cmd += '"'; - return true; - } - - return false; + cmd += " sid=\""; + cmd += NStr::PrintableString(req.GetSessionID()); + cmd += '"'; } -bool g_ParseGetJobResponse(CNetScheduleJob& job, const string& response); - inline string g_MakeBaseCmd(const string& cmd_name, const string& job_key) { string cmd(cmd_name); @@ -115,79 +189,44 @@ struct SNetScheduleServerProperties : public INetServerProperties class CNetScheduleConfigLoader { - class CErrorSuppressor; - public: - CNetScheduleConfigLoader( - const CTempString& prefix, - const CTempString& section); - - CConfig* Get(SNetScheduleAPIImpl* impl, CConfig* config, string& section); + CNetScheduleConfigLoader(ISynRegistry& registry, SRegSynonyms& sections, bool ns_conf = true); -protected: - virtual bool Transform(const CTempString& prefix, string& name); + bool operator()(SNetScheduleAPIImpl* impl); private: - typedef CNetScheduleAPI::TQueueParams TParams; - CConfig* Parse(const TParams& params, const CTempString& prefix); - - const CTempString m_Prefix; - const CTempString m_Section; -}; - -class CNetScheduleOwnConfigLoader : public CNetScheduleConfigLoader -{ -public: - CNetScheduleOwnConfigLoader(); + bool Transform(const string& prefix, string& name) const; -protected: - bool Transform(const CTempString& prefix, string& name); + ISynRegistry& m_Registry; + const SRegSynonyms& m_Sections; + const bool m_NsConf; + enum { eOff, eImplicit, eExplicit } m_Mode; }; class CNetScheduleServerListener : public INetServerConnectionListener { -private: - enum EMode { - fWnCompatible = (0 << 0), - fNonWnCompatible = (1 << 0), - fConfigLoading = (1 << 1), - fWorkerNode = fWnCompatible, - fNetSchedule = fNonWnCompatible, - }; - typedef int TMode; - - static TMode GetMode(bool wn, bool try_config) - { - if (wn) return fWorkerNode; - if (try_config) return fNetSchedule | fConfigLoading; - return fNetSchedule; - } - public: - CNetScheduleServerListener(bool wn, bool try_config) : - m_Mode(GetMode(wn, try_config)) - { - } + CNetScheduleServerListener(bool non_wn) : m_NonWn(non_wn) {} - void SetAuthString(SNetScheduleAPIImpl* impl); + void SetAuthString(const string& auth) { m_Auth = auth; } + string& Scope() { return m_Scope; } bool NeedToSubmitAffinities(SNetServerImpl* server_impl); void SetAffinitiesSynced(SNetServerImpl* server_impl, bool affs_synced); - static CRef x_GetServerProperties( - SNetServerImpl* server_impl); + static CRef x_GetServerProperties(SNetServerImpl* server_impl); - virtual CRef AllocServerProperties(); + CRef AllocServerProperties() override; - virtual void OnInit(CObject* api_impl, - CConfig* config, const string& config_section); - virtual void OnConnected(CNetServerConnection& connection); - virtual void OnError(const string& err_msg, CNetServer& server); - virtual void OnWarning(const string& warn_msg, CNetServer& server); + void OnInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections) override; + void OnConnected(CNetServerConnection& connection) override; + void OnError(const string& err_msg, CNetServer& server) override; + void OnWarning(const string& warn_msg, CNetServer& server) override; +private: string m_Auth; - CRef m_EventHandler; +public: CFastMutex m_ServerByNodeMutex; typedef map TServerByNode; TServerByNode m_ServerByNode; @@ -196,10 +235,8 @@ public: // preferred affinities from two threads. CFastMutex m_AffinitySubmissionMutex; - CNetScheduleAPI::EClientType m_ClientType = CNetScheduleAPI::eCT_Auto; - private: - const TMode m_Mode; + const bool m_NonWn; string m_Scope; }; @@ -282,8 +319,27 @@ struct SNetScheduleNotificationThread : public CThread struct SNetScheduleAPIImpl : public CObject { - SNetScheduleAPIImpl(CConfig* config, const string& section, - const string& service_name, const string& client_name, +private: + enum EMode { + fWnCompatible = (0 << 0), + fNonWnCompatible = (1 << 0), + fConfigLoading = (1 << 1), + fWorkerNode = fWnCompatible, + fNetSchedule = fNonWnCompatible, + }; + typedef int TMode; + + static TMode GetMode(bool wn, bool try_config) + { + if (wn) return fWorkerNode; + if (try_config) return fNetSchedule | fConfigLoading; + return fNetSchedule; + } + +public: + SNetScheduleAPIImpl(SConfigOrRegistry conf_or_reg, const string& section); + + SNetScheduleAPIImpl(const string& service_name, const string& client_name, const string& queue_name, bool wn = false, bool try_config = true); // Special constructor for CNetScheduleAPI::GetServer(). @@ -332,23 +388,6 @@ struct SNetScheduleAPIImpl : public CObject bool GetServerByNode(const string& ns_node, CNetServer* server); - static void VerifyJobGroupAlphabet(const string& job_group) - { - g_VerifyAlphabet(job_group, "job group name", eCC_BASE64_PI); - } - - static void VerifyAuthTokenAlphabet(const string& auth_token) - { - g_VerifyAlphabet(auth_token, "security token", eCC_BASE64_PI); - } - - static void VerifyAffinityAlphabet(const string& affinity) - { - g_VerifyAlphabet(affinity, "affinity token", eCC_BASE64_PI); - } - - static void VerifyQueueNameAlphabet(const string& queue_name); - void AllocNotificationThread(); void StartNotificationThread(); @@ -361,8 +400,25 @@ struct SNetScheduleAPIImpl : public CObject void UseOldStyleAuth(); void SetAuthParam(const string& param_name, const string& param_value); CCompoundIDPool GetCompoundIDPool() { return m_CompoundIDPool; } - void InitAffinities(CConfig* config, const string& section); + void Init(ISynRegistry& registry, SRegSynonyms& sections); + void InitAffinities(ISynRegistry& registry, const SRegSynonyms& sections); + string MakeAuthString(); + + struct SConfig + { + STimeout direct_output_connect_timeout; + + void Init(ISynRegistry& registry, SRegSynonyms& sections); + }; + + const SConfig& GetConfig() const { return m_Config; } +private: + const TMode m_Mode; + SConfig m_Config; + +public: + CNetScheduleAPI::EClientType m_ClientType = CNetScheduleAPI::eCT_Auto; CNetService m_Service; string m_Queue; @@ -377,13 +433,13 @@ struct SNetScheduleAPIImpl : public CObject long m_ServerParamsAskCount; CFastMutex m_FastMutex; - CNetScheduleExecutor::EJobAffinityPreference m_AffinityPreference; + CNetScheduleExecutor::EJobAffinityPreference m_AffinityPreference = CNetScheduleExecutor::eAnyJob; list m_AffinityList; CNetScheduleGetJob::TAffinityLadder m_AffinityLadder; string m_JobGroup; - unsigned m_JobTtl; + unsigned m_JobTtl = 0; bool m_UseEmbeddedStorage; @@ -403,13 +459,14 @@ struct SNetScheduleSubmitterImpl : public CObject unsigned wait_time, CNetServer* server = NULL); void FinalizeRead(const char* cmd_start, - const char* cmd_name, const string& job_id, const string& auth_token, const string& error_message); CNetScheduleAPI::EJobStatus SubmitJobAndWait(CNetScheduleJob& job, - unsigned wait_time, time_t* job_exptime = NULL); + unsigned wait_time, time_t* job_exptime = NULL, pair = {}); + + void AppendClientIPSessionIDHitID(string& cmd, const string& job_group); CNetScheduleAPI m_API; @@ -502,8 +559,6 @@ struct SNetScheduleJobReaderImpl : public CObject m_Impl.m_API->StartNotificationThread(); } - void SetJobGroup(const string& group_name); - void SetAffinity(const string& affinity); CNetScheduleJobReader::EReadNextJobResult ReadNextJob( CNetScheduleJob* job, CNetScheduleAPI::EJobStatus* job_status, @@ -522,8 +577,8 @@ private: m_Affinity(affinity), m_MoreJobs(false) { - SNetScheduleAPIImpl::VerifyJobGroupAlphabet(group); - SNetScheduleAPIImpl::VerifyAffinityAlphabet(affinity); + limits::Check(group); + limits::Check(affinity); } EState CheckState(); diff --git a/c++/src/connect/services/netschedule_api_reader.cpp b/c++/src/connect/services/netschedule_api_reader.cpp index 36b9e123..1f84cf60 100644 --- a/c++/src/connect/services/netschedule_api_reader.cpp +++ b/c++/src/connect/services/netschedule_api_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: netschedule_api_reader.cpp 518714 2016-11-07 18:04:33Z ivanov $ +/* $Id: netschedule_api_reader.cpp 525579 2017-01-25 17:33:11Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -212,28 +212,6 @@ bool SNetScheduleJobReaderImpl::CImpl::MoreJobs(const SEntry& entry) return entry.more_jobs; } -void SNetScheduleJobReaderImpl::SetJobGroup(const string& group_name) -{ - if (m_Impl.m_JobGroup.empty()) { - SNetScheduleAPIImpl::VerifyJobGroupAlphabet(group_name); - m_Impl.m_JobGroup = group_name; - } else { - NCBI_THROW(CNetScheduleException, eInvalidParameter, - "It's not allowed to change group"); - } -} - -void SNetScheduleJobReaderImpl::SetAffinity(const string& affinity) -{ - if (m_Impl.m_Affinity.empty()) { - SNetScheduleAPIImpl::VerifyAffinityAlphabet(affinity); - m_Impl.m_Affinity = affinity; - } else { - NCBI_THROW(CNetScheduleException, eInvalidParameter, - "It's not allowed to change affinity"); - } -} - CNetScheduleJobReader::EReadNextJobResult SNetScheduleJobReaderImpl::ReadNextJob( CNetScheduleJob* job, CNetScheduleAPI::EJobStatus* job_status, @@ -265,18 +243,6 @@ void SNetScheduleJobReaderImpl::InterruptReading() m_Impl.m_API->m_NotificationThread->m_ReadNotifications.InterruptWait(); } -void CNetScheduleJobReader::SetJobGroup(const string& group_name) -{ - _ASSERT(m_Impl); - m_Impl->SetJobGroup(group_name); -} - -void CNetScheduleJobReader::SetAffinity(const string& affinity) -{ - _ASSERT(m_Impl); - m_Impl->SetAffinity(affinity); -} - CNetScheduleJobReader::EReadNextJobResult CNetScheduleJobReader::ReadNextJob( CNetScheduleJob* job, CNetScheduleAPI::EJobStatus* job_status, diff --git a/c++/src/connect/services/netschedule_api_submitter.cpp b/c++/src/connect/services/netschedule_api_submitter.cpp index e1b66404..b245ef6b 100644 --- a/c++/src/connect/services/netschedule_api_submitter.cpp +++ b/c++/src/connect/services/netschedule_api_submitter.cpp @@ -1,4 +1,4 @@ -/* $Id: netschedule_api_submitter.cpp 507304 2016-07-18 16:15:49Z sadyrovr $ +/* $Id: netschedule_api_submitter.cpp 537390 2017-05-31 15:32:22Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,11 +37,22 @@ #include #include +#include + +#include + #include #include +#include +#include +#include +#include +#include BEGIN_NCBI_SCOPE +using namespace grid::netschedule; + #define FORCED_SST_INTERVAL_SEC 0 #define MAX_FORCED_SST_INTERVAL_SEC 3 #define FORCED_SST_INTERVAL_NANOSEC 500 * 1000 * 1000 @@ -62,7 +73,7 @@ static void s_SerializeJob(string& cmd, const CNetScheduleNewJob& job, } if (!job.affinity.empty()) { - SNetScheduleAPIImpl::VerifyAffinityAlphabet(job.affinity); + limits::Check(job.affinity); cmd.append(" aff="); cmd.append(job.affinity); } @@ -87,6 +98,21 @@ string CNetScheduleSubmitter::SubmitJob(CNetScheduleNewJob& job) return m_Impl->SubmitJobImpl(job, 0, 0); } +void SNetScheduleSubmitterImpl::AppendClientIPSessionIDHitID(string& cmd, const string& job_group) +{ + CRequestContext& req = CDiagContext::GetRequestContext(); + g_AppendClientIPAndSessionID(cmd, req); + + if (!job_group.empty()) { + limits::Check(job_group); + cmd.append(" group="); + cmd.append(job_group); + } + + m_UseNextSubHitID.ProperCommand(); + g_AppendHitID(cmd, m_UseNextSubHitID ? req.GetNextSubHitID() : req.GetCurrentSubHitID()); +} + string SNetScheduleSubmitterImpl::SubmitJobImpl(CNetScheduleNewJob& job, unsigned short udp_port, unsigned wait_time, CNetServer* server) { @@ -96,19 +122,7 @@ string SNetScheduleSubmitterImpl::SubmitJobImpl(CNetScheduleNewJob& job, string cmd = "SUBMIT "; s_SerializeJob(cmd, job, udp_port, wait_time); - - CRequestContext& req = CDiagContext::GetRequestContext(); - g_AppendClientIPAndSessionID(cmd, req); - - if (!job.group.empty()) { - SNetScheduleAPIImpl::VerifyJobGroupAlphabet(job.group); - cmd.append(" group="); - cmd.append(job.group); - } - - m_UseNextSubHitID.ProperCommand(); - g_AppendHitID(cmd, m_UseNextSubHitID ? - req.GetNextSubHitID() : req.GetCurrentSubHitID()); + AppendClientIPSessionIDHitID(cmd, job.group); CNetServer::SExecResult exec_result( m_API->m_Service.FindServerAndExec(cmd, false)); @@ -137,19 +151,7 @@ void CNetScheduleSubmitter::SubmitJobBatch(vector& jobs, // Batch submit command. string cmd = "BSUB"; - - CRequestContext& req = CDiagContext::GetRequestContext(); - g_AppendClientIPAndSessionID(cmd, req); - - if (!job_group.empty()) { - SNetScheduleAPIImpl::VerifyJobGroupAlphabet(job_group); - cmd.append(" group="); - cmd.append(job_group); - } - - m_Impl->m_UseNextSubHitID.ProperCommand(); - g_AppendHitID(cmd, m_Impl->m_UseNextSubHitID ? - req.GetNextSubHitID() : req.GetCurrentSubHitID()); + m_Impl->AppendClientIPSessionIDHitID(cmd, job_group); CNetServer::SExecResult exec_result( m_Impl->m_API->m_Service.FindServerAndExec(cmd, false)); @@ -221,7 +223,7 @@ void CNetScheduleSubmitter::SubmitJobBatch(vector& jobs, "Invalid server response. Batch answer format."); } - port = atoi(s); + port = static_cast(atoi(s)); if (port == 0) { NCBI_THROW(CNetServiceException, eProtocolError, "Invalid server response. Port=0."); @@ -313,7 +315,7 @@ bool CNetScheduleSubmitter::Read(string* job_id, string* auth_token, cmd += NStr::UIntToString(timeout); } if (!job_group.empty()) { - SNetScheduleAPIImpl::VerifyJobGroupAlphabet(job_group); + limits::Check(job_group); cmd += " group="; cmd += job_group; } @@ -327,7 +329,6 @@ bool CNetScheduleSubmitter::Read(string* job_id, string* auth_token, } void SNetScheduleSubmitterImpl::FinalizeRead(const char* cmd_start, - const char* cmd_name, const string& job_id, const string& auth_token, const string& error_message) @@ -351,21 +352,21 @@ void SNetScheduleSubmitterImpl::FinalizeRead(const char* cmd_start, void CNetScheduleSubmitter::ReadConfirm(const string& job_id, const string& auth_token) { - m_Impl->FinalizeRead("CFRM job_key=", "ReadConfirm", + m_Impl->FinalizeRead("CFRM job_key=", job_id, auth_token, kEmptyStr); } void CNetScheduleSubmitter::ReadRollback(const string& job_id, const string& auth_token) { - m_Impl->FinalizeRead("RDRB job_key=", "ReadRollback", + m_Impl->FinalizeRead("RDRB job_key=", job_id, auth_token, kEmptyStr); } void CNetScheduleSubmitter::ReadFail(const string& job_id, const string& auth_token, const string& error_message) { - m_Impl->FinalizeRead("FRED job_key=", "ReadFail", + m_Impl->FinalizeRead("FRED job_key=", job_id, auth_token, error_message); } @@ -401,6 +402,168 @@ bool CNetScheduleNotificationHandler::CheckJobStatusNotification( CNetScheduleAPI::eJobNotFound && attr_values[0] == job_id; } +bool CNetScheduleNotificationHandler::CheckJobStatusNotification(CNetScheduleAPI ns_api, CNetScheduleJob& job, + time_t* job_exptime, CNetScheduleAPI::EJobStatus& job_status, pair receiver) +{ + const char* const attr_names[] = {"job_key", "job_status", "worker_node_host", "worker_node_port"}; + array attr_values; + const string& received_job_id = attr_values[0]; + const string& received_job_status = attr_values[1]; + const string& worker_node_host = attr_values[2]; + const string& worker_node_port = attr_values[3]; + + g_ParseNSOutput(m_Message, attr_names, attr_values.data(), attr_values.size()); + + if (received_job_id != job.job_id) return false; + + const auto& timeout = ns_api->GetConfig().direct_output_connect_timeout; + + if (ReadOutput(job_status, receiver, worker_node_host, worker_node_port, timeout)) return true; + + switch (CNetScheduleAPI::StringToStatus(received_job_status)) { + case CNetScheduleAPI::eJobNotFound: + case CNetScheduleAPI::eRunning: + case CNetScheduleAPI::ePending: + return false; + + default: + job_status = ns_api.GetJobDetails(job, job_exptime); + return true; + } +} + +#ifdef NCBI_THREADS +bool CNetScheduleNotificationHandler::ReadOutput(CNetScheduleAPI::EJobStatus& job_status, + pair receiver, const string& worker_node_host, const string& worker_node_port, + const STimeout& timeout) +{ + if (!receiver.first || !receiver.second) return false; + + if (worker_node_host.empty() || worker_node_port.empty()) { + *receiver.first = false; + return false; + } + + const auto host = static_cast(stoul(worker_node_host)); + const auto port = static_cast(stoul(worker_node_port)); + unique_ptr socket; + + try { + // There is no CSocket::Connect(unsigned host...) and no CSocket::CSocket(const CSocket&), + // have to create on heap. + socket.reset(new CSocket(host, port, &timeout)); + } + catch (...) { + return false; + } + + mutex m; + condition_variable cv; + deque d; + bool done = false; + + auto reader = [&] { + CSocketReaderWriter socket_reader(socket.get()); + CTransmissionReader reader(&socket_reader); + array buf; + bool eof = false; + + while (!eof) { + char* data = buf.data(); + size_t to_read = buf.size(); + + while (!eof && to_read) { + ERW_Result status = eRW_Error; + size_t bytes_read = 0; + + try { + status = reader.Read(data, to_read, &bytes_read); + } + catch (...) { + } + + switch (status) { + case eRW_Success: + break; + + case eRW_Eof: + eof = true; + break; + + default: + eof = true; + bytes_read = 0; + break; + } + + data += bytes_read; + to_read -= bytes_read; + } + + unique_lock lock(m); + d.insert(d.end(), buf.cbegin(), buf.cbegin() + (buf.size() - to_read)); + + if (done) eof = true; + + done = eof; + lock.unlock(); + cv.notify_one(); + } + }; + + auto writer = [&] { + array buf; + bool eof = false; + + while (!eof) { + char* data = buf.data(); + size_t to_write = 0; + + { + unique_lock lock(m); + + if (!receiver.second->good()) { + done = true; + return; + } + + cv.wait(lock, [&]{ return d.size() || done; }); + + to_write = min(buf.size(), d.size()); + + if (to_write) { + copy_n(d.cbegin(), to_write, buf.begin()); + d.erase(d.begin(), d.begin() + to_write); + } + + eof = done; + } + + try { + receiver.second->write(data, to_write); + } + catch (...) { + receiver.second->setstate(ios_base::badbit); + } + } + }; + + thread t(reader); + writer(); + t.join(); + + job_status = CNetScheduleAPI::eDone; + *receiver.first = true; + return true; +} +#else +bool CNetScheduleNotificationHandler::ReadOutput(CNetScheduleAPI::EJobStatus&, + pair, const string&, const string&, const STimeout&) +{ + return false; +} +#endif + CNetScheduleAPI::EJobStatus CNetScheduleSubmitter::SubmitJobAndWait(CNetScheduleJob& job, unsigned wait_time) @@ -410,7 +573,7 @@ CNetScheduleSubmitter::SubmitJobAndWait(CNetScheduleJob& job, CNetScheduleAPI::EJobStatus SNetScheduleSubmitterImpl::SubmitJobAndWait(CNetScheduleJob& job, - unsigned wait_time, time_t* job_exptime) + unsigned wait_time, time_t* job_exptime, pair receiver) { CDeadline deadline(wait_time, 0); @@ -419,7 +582,7 @@ SNetScheduleSubmitterImpl::SubmitJobAndWait(CNetScheduleJob& job, submit_job_handler.SubmitJob(this, job, wait_time); return submit_job_handler.WaitForJobCompletion(job, - deadline, m_API, job_exptime); + deadline, m_API, job_exptime, receiver); } CNetScheduleAPI::EJobStatus @@ -440,7 +603,8 @@ CNetScheduleNotificationHandler::WaitForJobCompletion( CNetScheduleJob& job, CDeadline& deadline, CNetScheduleAPI ns_api, - time_t* job_exptime) + time_t* job_exptime, + pair receiver) { CNetScheduleAPI::EJobStatus status = CNetScheduleAPI::ePending; @@ -456,10 +620,7 @@ CNetScheduleNotificationHandler::WaitForJobCompletion( } if (WaitForNotification(timeout)) { - if (CheckJobStatusNotification(job.job_id, &status) && - status != CNetScheduleAPI::eRunning && - status != CNetScheduleAPI::ePending) - return ns_api.GetJobDetails(job, job_exptime); + if (CheckJobStatusNotification(ns_api, job, job_exptime, status, receiver)) return status; } else { // The wait has timed out - query the server directly. @@ -586,9 +747,7 @@ CNetScheduleNotificationHandler::WaitForJobEvent( void CNetScheduleSubmitter::CancelJob(const string& job_key) { string cmd(g_MakeBaseCmd("CANCEL", job_key)); - CRequestContext& req = CDiagContext::GetRequestContext(); - g_AppendClientIPAndSessionID(cmd, req); - g_AppendHitID(cmd, req.GetNextSubHitID()); + g_AppendClientIPSessionIDHitID(cmd, true); CNetServer::SExecResult exec_result; m_Impl->m_API->GetServer(job_key)->ConnectAndExec(cmd, false, exec_result); @@ -597,15 +756,13 @@ void CNetScheduleSubmitter::CancelJob(const string& job_key) void CNetScheduleSubmitter::CancelJobGroup(const string& job_group, const string& job_statuses) { - SNetScheduleAPIImpl::VerifyJobGroupAlphabet(job_group); + limits::Check(job_group); string cmd("CANCEL group=" + job_group); if (!job_statuses.empty()) { cmd.append(" status="); cmd.append(job_statuses); } - CRequestContext& req = CDiagContext::GetRequestContext(); - g_AppendClientIPAndSessionID(cmd, req); - g_AppendHitID(cmd, req.GetNextSubHitID()); + g_AppendClientIPSessionIDHitID(cmd, true); m_Impl->m_API->m_Service.ExecOnAllServers(cmd); } diff --git a/c++/src/connect/services/netschedule_key.cpp b/c++/src/connect/services/netschedule_key.cpp index 8a7cee4d..9acc0b0d 100644 --- a/c++/src/connect/services/netschedule_key.cpp +++ b/c++/src/connect/services/netschedule_key.cpp @@ -1,4 +1,4 @@ -/* $Id: netschedule_key.cpp 428820 2014-03-07 17:42:20Z kazimird $ +/* $Id: netschedule_key.cpp 525521 2017-01-25 14:15:15Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,7 +32,8 @@ #include -#include "util.hpp" +#include + #include "netschedule_api_impl.hpp" #include @@ -43,6 +44,8 @@ BEGIN_NCBI_SCOPE +using namespace grid::netschedule; + #define NS_KEY_V1_PREFIX "JSID_01_" #define NS_KEY_V1_PREFIX_LEN (sizeof(NS_KEY_V1_PREFIX) - 1) @@ -167,7 +170,7 @@ bool CNetScheduleKey::ParseJobKey(const string& key_str, CNetScheduleKeyGenerator::CNetScheduleKeyGenerator( const string& host, unsigned port, const string& queue_name) { - SNetScheduleAPIImpl::VerifyQueueNameAlphabet(queue_name); + limits::Check(queue_name); m_UseIPv4Addr = CSocketAPI::isip(host, true); if (m_UseIPv4Addr) @@ -179,7 +182,7 @@ CNetScheduleKeyGenerator::CNetScheduleKeyGenerator( string port_str(NStr::IntToString(port)); - unsigned queue_prefix_len = g_NumberOfUnderscoresPlusOne(queue_name); + auto queue_prefix_len = 1 + count(queue_name.begin(), queue_name.end(), '_'); m_V1HostPortQueue.reserve(1 + host.size() + 1 + port_str.size() + queue_prefix_len + queue_name.size()); diff --git a/c++/src/connect/services/netservice_api.cpp b/c++/src/connect/services/netservice_api.cpp index edfbae33..4bbd9d07 100644 --- a/c++/src/connect/services/netservice_api.cpp +++ b/c++/src/connect/services/netservice_api.cpp @@ -1,4 +1,4 @@ -/* $Id: netservice_api.cpp 512527 2016-08-31 18:05:30Z ivanov $ +/* $Id: netservice_api.cpp 540945 2017-07-12 15:49:46Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,6 +32,7 @@ #include "../ncbi_lbsmd.h" #include "../ncbi_servicep.h" +#include "../ncbi_comm.h" #include "netservice_api_impl.hpp" @@ -40,12 +41,15 @@ #include #include +#include +#include #include #include #include #include #include +#include #include #include @@ -56,6 +60,39 @@ BEGIN_NCBI_SCOPE +// The purpose of this class is to execute commands suppressing possible errors and avoiding retries +class SNetServiceImpl::CTry +{ + struct SHandler : public INetEventHandler + { + bool OnError(CException::TErrCode) { return true; } + }; + +public: + CTry(SNetServiceImpl* service) : + m_Service(service) + { + _ASSERT(m_Service); + Swap(new SHandler); + } + + ~CTry() + { + Swap(m_OriginalHandler); + } + +private: + void Swap(INetEventHandler* handler) + { + m_OriginalHandler = m_Service->SetEventHandler(handler); + swap(m_MaxRetries, m_Service->m_ConnectionMaxRetries); + } + + CNetRef m_Service; + CRef m_OriginalHandler; + unsigned m_MaxRetries = 0; +}; + void SDiscoveredServers::DeleteThis() { CNetService service(m_Service); @@ -280,20 +317,11 @@ SNetServerPoolImpl::SNetServerPoolImpl(INetServerConnectionListener* listener, bool old_style_auth) : m_Listener(listener), m_EnforcedServer(0, 0), - m_LBSMAffinityName(kEmptyStr), - m_LBSMAffinityValue(NULL), + m_MaxTotalTime(CTimeout::eInfinite), m_UseOldStyleAuth(old_style_auth) { } -void SNetServiceImpl::ZeroInit() -{ - m_ServiceType = CNetService::eServiceNotDefined; - m_DiscoveredServers = NULL; - m_ServerGroupPool = NULL; - m_LatestDiscoveryIteration = 0; -} - void SNetServiceImpl::Construct(SNetServerInPool* server) { m_ServiceType = CNetService::eSingleServerService; @@ -320,63 +348,159 @@ void SNetServiceImpl::Construct() #ifdef NCBI_GRID_XSITE_CONN_SUPPORT void CNetService::AllowXSiteConnections() { - m_Impl->AllowXSiteConnections(); + SNetServiceXSiteAPI::AllowXSiteConnections(); } bool CNetService::IsUsingXSiteProxy() { - return m_Impl->m_AllowXSiteConnections; + return SNetServiceXSiteAPI::IsUsingXSiteProxy(); +} + +static const char kXSiteFwd[] = "XSITEFWD"; + +void SNetServiceXSiteAPI::AllowXSiteConnections() +{ + const auto local_ip = CSocketAPI::GetLocalHostAddress(); + const auto local_domain = GetDomain(local_ip); + m_LocalDomain.store(local_domain); + m_AllowXSiteConnections.store(true); } -void SNetServiceImpl::AllowXSiteConnections() +bool SNetServiceXSiteAPI::IsUsingXSiteProxy() { - m_AllowXSiteConnections = true; + return m_AllowXSiteConnections.load(); +} - SConnNetInfo* net_info = ConnNetInfo_Create(SNetServerImpl::kXSiteFwd); +void SNetServiceXSiteAPI::InitXSite(ISynRegistry& registry, const SRegSynonyms& sections) +{ + if (registry.Get({ "netservice_api", sections }, "allow_xsite_conn", false)) { + AllowXSiteConnections(); + } +} - SSERV_Info* sinfo = SERV_GetInfo(SNetServerImpl::kXSiteFwd, - fSERV_Standalone, SERV_LOCALHOST, net_info); +void SNetServiceXSiteAPI::ConnectXSite(CSocket& socket, + SNetServerImpl::SConnectDeadline& deadline, + const SServerAddress& original) +{ + SServerAddress actual(original); + ticket_t ticket = 0; + + if (IsForeignAddr(actual.host)) { + union { + SFWDRequestReply rq; + char buffer[FWD_MAX_RR_SIZE + 1]; + }; + + memset(buffer, 0, sizeof(buffer)); + rq.host = actual.host; + rq.port = SOCK_HostToNetShort(actual.port); + rq.flag = SOCK_HostToNetShort(1); + _ASSERT(offsetof(SFWDRequestReply, text) + + sizeof(kXSiteFwd) < sizeof(buffer)); + memcpy(rq.text, kXSiteFwd, sizeof(kXSiteFwd)); + + size_t len = 0; + + CConn_ServiceStream svc(kXSiteFwd); + if (svc.write((const char*) &rq.ticket/*0*/, sizeof(rq.ticket)) && + svc.write(buffer, offsetof(SFWDRequestReply, text) + + sizeof(kXSiteFwd))) { + svc.read(buffer, sizeof(buffer) - 1); + len = (size_t) svc.gcount(); + _ASSERT(len < sizeof(buffer)); + } - ConnNetInfo_Destroy(net_info); + memset(buffer + len, 0, sizeof(buffer) - len); + + if (len < offsetof(SFWDRequestReply, text) || + (rq.flag & 0xF0F0) || rq.port == 0) { + const char* err; + if (len == 0) + err = "Connection refused"; + else if (len < offsetof(SFWDRequestReply, text)) + err = "Short response received"; + else if (!(rq.flag & 0xF0F0)) + err = rq.flag & 0x0F0F ? "Client rejected" : "Unknown error"; + else if (NStr::strncasecmp(buffer, "NCBI", 4) == 0) + err = buffer; + else if (rq.text[0]) + err = rq.text; + else + err = "Unspecified error"; + NCBI_THROW_FMT(CNetSrvConnException, eConnectionFailure, + "Error while acquiring an auth ticket from a " + "cross-site connection proxy: " << err); + } - if (sinfo == NULL) { - NCBI_THROW(CNetSrvConnException, eLBNameNotFound, - "Cannot find cross-site proxy"); + if (rq.ticket != 0) { + actual.host = rq.host; + actual.port = SOCK_NetToHostShort(rq.port); + } else { + SOCK sock; + actual.port = 0; + EIO_Status io_st = CONN_GetSOCK(svc.GetCONN(), &sock); + if (sock != NULL) + SOCK_CreateOnTop(sock, 0, &sock); + if (io_st != eIO_Success || sock == NULL) { + NCBI_THROW(CNetSrvConnException, eConnectionFailure, + "Error while connecting to proxy."); + } + socket.Reset(sock, eTakeOwnership, eCopyTimeoutsToSOCK); + } + ticket = rq.ticket; } - m_ColoNetwork = SOCK_NetToHostLong(sinfo->host) >> 16; + if (actual.port) { + SNetServerImpl::ConnectImpl(socket, deadline, actual, original); + } - free(sinfo); + if (ticket && socket.Write(&ticket, sizeof(ticket)) != eIO_Success) { + NCBI_THROW(CNetSrvConnException, eConnectionFailure, + "Error while sending proxy auth ticket."); + } } -#endif -CConfig* FindSection(const char* const* sections, const CConfig::TParamTree* tree, - string* section) +int SNetServiceXSiteAPI::GetDomain(unsigned int ip) { - _ASSERT(section); + TNCBI_IPv6Addr addr; + NcbiIPv4ToIPv6(&addr, ip, 0); + + SNcbiDomainInfo info; + NcbiIsLocalIPEx(&addr, &info); - if (section->empty()) { - *section = *sections++; + if (!info.num) { + NCBI_THROW(CNetSrvConnException, eLBNameNotFound, "Cannot determine local domain"); } + + return info.num; +} - for (;;) { - if (const CConfig::TParamTree* sub_tree = tree->FindSubNode(*section)) { - return new CConfig(sub_tree); - } +bool SNetServiceXSiteAPI::IsForeignAddr(unsigned int ip) +{ + if (!IsUsingXSiteProxy()) return false; - if (!*sections) { - break; - } + return m_LocalDomain != GetDomain(ip); +} - *section = *sections++; - } +atomic SNetServiceXSiteAPI::m_LocalDomain{0}; +atomic SNetServiceXSiteAPI::m_AllowXSiteConnections{false}; + +#else + +void SNetServiceXSiteAPI::InitXSite(ISynRegistry&, const SRegSynonyms&) +{ +} - return NULL; +void SNetServiceXSiteAPI::ConnectXSite(CSocket& socket, + SNetServerImpl::SConnectDeadline& deadline, + const SServerAddress& original) +{ + SNetServerImpl::ConnectImpl(socket, deadline, original, original); } -void SNetServiceImpl::Init(CObject* api_impl, const string& service_name, - CConfig* config, const string& config_section, - const char* const* default_config_sections) +#endif + +void SNetServiceImpl::Init(CObject* api_impl, const IRegistry* top_registry, SRegSynonyms sections) { _ASSERT(m_Listener); @@ -391,94 +515,66 @@ void SNetServiceImpl::Init(CObject* api_impl, const string& service_name, conn_initer.NoOp(); } - string section = config_section; - - auto_ptr app_reg_config; - auto_ptr param_tree; + CSynRegistry syn_registry; + CCachedSynRegistry registry(syn_registry); - if (config == NULL) { + { CMutexGuard guard(CNcbiApplication::GetInstanceMutex()); - CNcbiApplication* app = CNcbiApplication::Instance(); - CNcbiRegistry* reg; - if (app != NULL && (reg = &app->GetConfig()) != NULL) { - param_tree.reset(CConfig::ConvertRegToTree(*reg)); - app_reg_config.reset(FindSection(default_config_sections, - param_tree.get(), §ion)); - config = app_reg_config.get(); + if (CNcbiApplication* app = CNcbiApplication::Instance()) { + syn_registry.Add(app->GetConfig()); + } else { + syn_registry.Add(*new CEnvironmentRegistry); } - } else { - app_reg_config.reset(FindSection(default_config_sections, - config->GetTree(), §ion)); + } + + if (top_registry) syn_registry.Add(*top_registry); - if (app_reg_config.get()) { - config = app_reg_config.get(); + // Remove empty sections + for (auto it = sections.begin(); it != sections.end(); ) { + if (it->empty()) { + it = sections.erase(it); + } else { + ++it; } } - m_ServiceName = service_name; + if (sections.empty()) { + NCBI_THROW_FMT(CArgException, eNoValue, "Configuration section was not provided"); + } + NStr::TruncateSpacesInPlace(m_ServiceName); + // TODO: + // Do not check for emptiness and always read values (client, service, etc) from registry + // after values provided in ctors get into an underlying memory registry. + // Do not override explicitly set client name - if (config && m_ClientName.empty()) { - m_ClientName = config->GetString(section, "client_name", - CConfig::eErr_NoThrow); + if (m_ClientName.empty()) m_ClientName = registry.Get(sections, { "client_name", "client" }, ""); - if (m_ClientName.empty()) { - m_ClientName = config->GetString(section, "client", - CConfig::eErr_NoThrow); - } - } + m_Listener->OnPreInit(api_impl, registry, sections, m_ClientName); - if (CConfig *alt = m_Listener->OnPreInit(api_impl, config, §ion, - m_ClientName)) { - app_reg_config.reset(alt); - config = alt; - } + if (m_ServiceName.empty()) { + m_ServiceName = registry.Get(sections, { "service", "service_name" }, ""); - if (config != NULL) { if (m_ServiceName.empty()) { - m_ServiceName = config->GetString(section, "service", - CConfig::eErr_NoThrow, kEmptyStr); - if (m_ServiceName.empty()) - m_ServiceName = config->GetString(section, "service_name", - CConfig::eErr_NoThrow, kEmptyStr); - if (m_ServiceName.empty()) { - string host(config->GetString(section, "server", - CConfig::eErr_NoThrow, kEmptyStr)); - if (host.empty()) - host = config->GetString(section, "host", - CConfig::eErr_NoThrow, kEmptyStr); - string port = config->GetString(section, - "port", CConfig::eErr_NoThrow, kEmptyStr); - if (!host.empty() && !port.empty()) { - m_ServiceName = host + ":"; - m_ServiceName += port; - } - } + string host = registry.Get(sections, { "server", "host" }, ""); + string port = registry.Get(sections, "port", ""); + + if (!host.empty() && !port.empty()) m_ServiceName = host + ":" + port; } + } -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - if (config->GetBool(section, "allow_xsite_conn", - CConfig::eErr_NoThrow, false)) - AllowXSiteConnections(); -#endif + InitXSite(registry, sections); - m_UseSmartRetries = config->GetBool(section, - "smart_service_retries", CConfig::eErr_NoThrow, true); - m_ConnectionMaxRetries = config->GetInt(section, - "connection_max_retries", CConfig::eErr_NoThrow, -1); - double retry_delay = config->GetDouble(section, - "retry_delay", CConfig::eErr_NoThrow, -1); - m_ConnectionRetryDelay = retry_delay < 0? -1: - (int)SECONDS_DOUBLE_TO_MS_UL(retry_delay); - } - if ( m_ConnectionMaxRetries < 0 ) { - m_ConnectionMaxRetries = (int)TServConn_ConnMaxRetries::GetDefault(); - } - if ( m_ConnectionRetryDelay < 0 ) { - m_ConnectionRetryDelay = (int)s_GetRetryDelay(); - } + m_UseSmartRetries = registry.Get(sections, "smart_service_retries", true); + + int max_retries = registry.Get({ sections, "netservice_api" }, "connection_max_retries", CONNECTION_MAX_RETRIES); + m_ConnectionMaxRetries = max_retries >= 0 ? max_retries : CONNECTION_MAX_RETRIES; + + double retry_delay = registry.Get({ sections, "netservice_api" }, "retry_delay", RETRY_DELAY_DEFAULT); + if (retry_delay < 0) retry_delay = RETRY_DELAY_DEFAULT; + m_ConnectionRetryDelay = static_cast(retry_delay * kMilliSecondsPerSecond); if (m_ClientName.empty() || m_ClientName == "noname" || NStr::FindNoCase(m_ClientName, "unknown") != NPOS) { @@ -491,135 +587,103 @@ void SNetServiceImpl::Init(CObject* api_impl, const string& service_name, m_ClientName = app->GetProgramDisplayName(); } - m_ServerPool->Init(config, section, m_Listener.GetPointerOrNull()); + m_ServerPool->Init(registry, sections, m_Listener.GetPointerOrNull()); Construct(); - m_Listener->OnInit(api_impl, config, section); + m_Listener->OnInit(api_impl, registry, sections); } -void SNetServerPoolImpl::Init(CConfig* config, const string& section, - INetServerConnectionListener* listener) +void SNetServerPoolImpl::Init(ISynRegistry& registry, const SRegSynonyms& sections, INetServerConnectionListener* listener) { - if (config != NULL) { - if (m_LBSMAffinityName.empty()) - m_LBSMAffinityName = config->GetString(section, - "use_lbsm_affinity", CConfig::eErr_NoThrow, kEmptyStr); + int max_requests = CSimpleRebalanceStrategy::DefaultMaxRequests(); + double max_seconds = CSimpleRebalanceStrategy::DefaultMaxSeconds(); - unsigned long conn_timeout = s_SecondsToMilliseconds(config->GetString( - section, "connection_timeout", CConfig::eErr_NoThrow, "0"), 0); + const auto kConnTimeoutDefault = 2.0; + const auto kCommTimeoutDefault = 12.0; + const auto kFirstServerTimeoutDefault = 0.3; - NcbiMsToTimeout(&m_ConnTimeout, conn_timeout > 0 ? conn_timeout : - SECONDS_DOUBLE_TO_MS_UL(CONNECTION_TIMEOUT_DEFAULT)); + g_CTimeoutToSTimeout(CTimeout(kConnTimeoutDefault), m_ConnTimeout); + g_CTimeoutToSTimeout(CTimeout(kCommTimeoutDefault), m_CommTimeout); + g_CTimeoutToSTimeout(CTimeout(kFirstServerTimeoutDefault), m_FirstServerTimeout); + + m_LBSMAffinity.first = registry.Get(sections, "use_lbsm_affinity", ""); - unsigned long comm_timeout = s_SecondsToMilliseconds(config->GetString( - section, "communication_timeout", CConfig::eErr_NoThrow, "0"), 0); + // Get affinity value from the local LBSM configuration file. + if (!m_LBSMAffinity.first.empty()) { + m_LBSMAffinity.second = LBSMD_GetHostParameter(SERV_LOCALHOST, m_LBSMAffinity.first.c_str()); + } - if (comm_timeout > 0) - NcbiMsToTimeout(&m_CommTimeout, comm_timeout); - else - m_CommTimeout = s_GetDefaultCommTimeout(); + double conn_timeout = registry.Get(sections, "connection_timeout", kConnTimeoutDefault); + if (conn_timeout > 0) g_CTimeoutToSTimeout(CTimeout(conn_timeout), m_ConnTimeout); - unsigned long first_srv_timeout = s_SecondsToMilliseconds( - config->GetString(section, "first_server_timeout", - CConfig::eErr_NoThrow, "0"), 0); + double comm_timeout = registry.Get({ sections, "netservice_api" }, "communication_timeout", kCommTimeoutDefault); + if (comm_timeout > 0) g_CTimeoutToSTimeout(CTimeout(comm_timeout), m_CommTimeout); - if (first_srv_timeout > 0) - NcbiMsToTimeout(&m_FirstServerTimeout, first_srv_timeout); - else if (comm_timeout > 0) - m_FirstServerTimeout = m_CommTimeout; - else - NcbiMsToTimeout(&m_FirstServerTimeout, - SECONDS_DOUBLE_TO_MS_UL(FIRST_SERVER_TIMEOUT_DEFAULT)); - - m_ServerThrottlePeriod = config->GetInt(section, - "throttle_relaxation_period", CConfig::eErr_NoThrow, - THROTTLE_RELAXATION_PERIOD_DEFAULT); - - if (m_ServerThrottlePeriod > 0) { - string numerator_str, denominator_str; - - NStr::SplitInTwo(config->GetString(section, - "throttle_by_connection_error_rate", CConfig::eErr_NoThrow, - THROTTLE_BY_ERROR_RATE_DEFAULT), "/", - numerator_str, denominator_str); - - int numerator = NStr::StringToInt(numerator_str, - NStr::fConvErr_NoThrow | - NStr::fAllowLeadingSpaces | NStr::fAllowTrailingSpaces); - int denominator = NStr::StringToInt(denominator_str, - NStr::fConvErr_NoThrow | - NStr::fAllowLeadingSpaces | NStr::fAllowTrailingSpaces); - - if (denominator < 1) - denominator = 1; - else if (denominator > CONNECTION_ERROR_HISTORY_MAX) { - numerator = (numerator * CONNECTION_ERROR_HISTORY_MAX) / - denominator; - denominator = CONNECTION_ERROR_HISTORY_MAX; - } - - if (numerator < 0) - numerator = 0; + double first_srv_timeout = registry.Get(sections, "first_server_timeout", kFirstServerTimeoutDefault); - m_IOFailureThresholdNumerator = numerator; - m_IOFailureThresholdDenominator = denominator; + if (first_srv_timeout > 0) { + g_CTimeoutToSTimeout(CTimeout(first_srv_timeout), m_FirstServerTimeout); + } else if (comm_timeout > 0) { + m_FirstServerTimeout = m_CommTimeout; + } - try { - m_MaxConsecutiveIOFailures = config->GetInt(section, - "throttle_by_consecutive_connection_failures", - CConfig::eErr_NoThrow, 0); - } - catch (exception&) { - m_MaxConsecutiveIOFailures = config->GetInt(section, - "throttle_by_subsequent_connection_failures", - CConfig::eErr_NoThrow, - THROTTLE_BY_SUBSEQUENT_CONNECTION_FAILURES_DEFAULT); - } + double max_total_time = registry.Get(sections, "max_connection_time", 0.0); + if (max_total_time > 0) m_MaxTotalTime = CTimeout(max_total_time); - m_ThrottleUntilDiscoverable = config->GetBool(section, - "throttle_hold_until_active_in_lb", CConfig::eErr_NoThrow, - THROTTLE_HOLD_UNTIL_ACTIVE_IN_LB_DEFAULT); - } + max_requests = registry.Get(sections, "rebalance_requests", max_requests); + max_seconds = registry.Get(sections, "rebalance_time", max_seconds); - m_MaxConnectionTime = s_SecondsToMilliseconds(config->GetString(section, - "max_connection_time", CConfig::eErr_NoThrow, - NCBI_AS_STRING(MAX_CONNECTION_TIME_DEFAULT)), - SECONDS_DOUBLE_TO_MS_UL(MAX_CONNECTION_TIME_DEFAULT)); - - m_RebalanceStrategy = CreateSimpleRebalanceStrategy(*config, section); - } else { - NcbiMsToTimeout(&m_ConnTimeout, - SECONDS_DOUBLE_TO_MS_UL(CONNECTION_TIMEOUT_DEFAULT)); - m_CommTimeout = s_GetDefaultCommTimeout(); - - NcbiMsToTimeout(&m_FirstServerTimeout, - SECONDS_DOUBLE_TO_MS_UL(FIRST_SERVER_TIMEOUT_DEFAULT)); - - // Throttling parameters. - m_ServerThrottlePeriod = THROTTLE_RELAXATION_PERIOD_DEFAULT; - m_IOFailureThresholdNumerator = - THROTTLE_BY_ERROR_RATE_DEFAULT_NUMERATOR; - m_IOFailureThresholdDenominator = - THROTTLE_BY_ERROR_RATE_DEFAULT_DENOMINATOR; - m_MaxConsecutiveIOFailures = - THROTTLE_BY_SUBSEQUENT_CONNECTION_FAILURES_DEFAULT; - m_ThrottleUntilDiscoverable = THROTTLE_HOLD_UNTIL_ACTIVE_IN_LB_DEFAULT; - - m_MaxConnectionTime = - SECONDS_DOUBLE_TO_MS_UL(MAX_CONNECTION_TIME_DEFAULT); - - m_RebalanceStrategy = CreateDefaultRebalanceStrategy(); - } + m_ThrottleParams.Init(registry, sections); - // Get affinity value from the local LBSM configuration file. - if (!m_LBSMAffinityName.empty()) - m_LBSMAffinityValue = LBSMD_GetHostParameter(SERV_LOCALHOST, - m_LBSMAffinityName.c_str()); + m_RebalanceStrategy = new CSimpleRebalanceStrategy(max_requests, max_seconds); m_Listener = listener; } +void SNetServerPoolImpl::SThrottleParams::Init(ISynRegistry& registry, const SRegSynonyms& sections) +{ + m_ServerThrottlePeriod = registry.Get(sections, "throttle_relaxation_period", 0); + + if (m_ServerThrottlePeriod <= 0) return; + + m_MaxConsecutiveIOFailures = registry.Get(sections, + { "throttle_by_consecutive_connection_failures", "throttle_by_subsequent_connection_failures" }, 0); + + m_ThrottleUntilDiscoverable = registry.Get(sections, "throttle_hold_until_active_in_lb", false); + + // These values must correspond to each other + const auto default_error_rate = "0/1"; + m_IOFailureThresholdNumerator = 0; + m_IOFailureThresholdDenominator = 1; + + const string error_rate = registry.Get(sections, "throttle_by_connection_error_rate", default_error_rate); + + if (error_rate == default_error_rate || error_rate.empty()) return; + + string numerator_str, denominator_str; + + if (!NStr::SplitInTwo(error_rate, "/", numerator_str, denominator_str)) return; + + const auto flags = NStr::fConvErr_NoThrow | NStr::fAllowLeadingSpaces | NStr::fAllowTrailingSpaces; + + int numerator = NStr::StringToInt(numerator_str, flags); + int denominator = NStr::StringToInt(denominator_str, flags); + + if (numerator < 0) numerator = 0; + + if (denominator < 1) { + denominator = 1; + + } else if (denominator > CONNECTION_ERROR_HISTORY_MAX) { + numerator = (numerator * CONNECTION_ERROR_HISTORY_MAX) / denominator; + denominator = CONNECTION_ERROR_HISTORY_MAX; + } + + m_IOFailureThresholdNumerator = numerator; + m_IOFailureThresholdDenominator = denominator; +} + SDiscoveredServers* SNetServiceImpl::AllocServerGroup( unsigned discovery_iteration) { @@ -888,21 +952,20 @@ void SNetServiceImpl::DiscoverServersIfNeeded() // FIXME Retry logic can be removed as soon as LBSMD with // packet compression is installed universally. int try_count = TServConn_MaxFineLBNameRetries::GetDefault(); - //LOG_POST("lbname_retries: "<m_LBSMAffinityName.c_str(), - m_ServerPool->m_LBSMAffinityValue); - - ConnNetInfo_Destroy(net_info); + SERV_LOCALHOST, 0, 0.0, m_NetInfo.get(), NULL, 0, 0 /*false*/, + m_ServerPool->m_LBSMAffinity.first.c_str(), + m_ServerPool->m_LBSMAffinity.second); if (srv_it != 0 || --try_count < 0) break; @@ -910,7 +973,7 @@ void SNetServiceImpl::DiscoverServersIfNeeded() ERR_POST_X(4, "Could not find LB service name '" << m_ServiceName << "', will retry after delay"); - SleepMilliSec(s_GetRetryDelay()); + SleepMilliSec(m_ConnectionRetryDelay); } SDiscoveredServers* server_group = m_DiscoveredServers; @@ -1009,13 +1072,11 @@ void SNetServiceImpl::IterateUntilExecOK(const string& cmd, conn_listener = m_Listener; int retry_count = m_ConnectionMaxRetries; - //LOG_POST("retry_count = "< SNetServiceImpl::GetTryGuard() +{ + return make_shared(this); +} + void SNetServerPoolImpl::ResetServerConnections() { CFastMutexGuard server_mutex_lock(m_ServerMutex); @@ -1186,8 +1249,7 @@ SNetServerPoolImpl::~SNetServerPoolImpl() delete it->second; } - if (m_LBSMAffinityValue != NULL) - free((void*) m_LBSMAffinityValue); + if (m_LBSMAffinity.second) free(const_cast(m_LBSMAffinity.second)); } SNetServiceImpl::~SNetServiceImpl() @@ -1402,40 +1464,25 @@ CJsonNode g_ExecToJson(IExecToJson& exec_to_json, CNetService service, return result; } -namespace { - class CDummyServerConnectionListener : public INetServerConnectionListener +CNetService g_DiscoverService(const string& service_name, + const string& client_name) +{ + struct SNoOpConnectionListener : public INetServerConnectionListener { - public: - virtual CRef AllocServerProperties() + CRef AllocServerProperties() override { return CRef(new INetServerProperties); } - virtual void OnInit(CObject* /*api_impl*/, - CConfig* /*config*/, const string& /*config_section*/) - { - } - virtual void OnConnected(CNetServerConnection& /*connection*/) - { - } - virtual void OnError(const string& /*err_msg*/, CNetServer& /*server*/) - { - } - virtual void OnWarning(const string& /*warn_msg*/, - CNetServer& /*server*/) - { - } - }; -} -CNetService g_DiscoverService(const string& service_name, - const string& client_name) -{ - CNetService service(new SNetServiceImpl("Discovery", client_name, - new CDummyServerConnectionListener)); + void OnInit(CObject*, ISynRegistry&, SRegSynonyms&) override {} + void OnConnected(CNetServerConnection&) override {} + void OnError(const string&, CNetServer&) override {} + void OnWarning(const string&, CNetServer&) override {} + }; - static const char* const config_section[] = {"discovery", NULL}; + CNetService service(new SNetServiceImpl("Discovery", service_name, client_name, new SNoOpConnectionListener)); - service->Init(NULL, service_name, NULL, kEmptyStr, config_section); + service->Init(nullptr, nullptr, "discovery"); return service; } diff --git a/c++/src/connect/services/netservice_api_impl.hpp b/c++/src/connect/services/netservice_api_impl.hpp index 5c50460b..c791db1b 100644 --- a/c++/src/connect/services/netservice_api_impl.hpp +++ b/c++/src/connect/services/netservice_api_impl.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES___NETSERVICE_API_IMPL__HPP #define CONNECT_SERVICES___NETSERVICE_API_IMPL__HPP -/* $Id: netservice_api_impl.hpp 497092 2016-04-04 15:52:44Z sadyrovr $ +/* $Id: netservice_api_impl.hpp 537425 2017-05-31 17:34:36Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,8 +33,11 @@ #include "srv_connections_impl.hpp" #include "balancing.hpp" +#include #include +#include +#include BEGIN_NCBI_SCOPE @@ -87,17 +90,36 @@ struct SDiscoveredServers : public CObject struct NCBI_XCONNECT_EXPORT SNetServerPoolImpl : public CObject { + struct SThrottleParams + { + // The parameters below describe different conditions that trigger server throttling. + int m_MaxConsecutiveIOFailures; + + // Connection failure rate (numerator/denominator), which is when reached, triggers server throttling. + int m_IOFailureThresholdNumerator; + int m_IOFailureThresholdDenominator; // Cannot be greater than CONNECTION_ERROR_HISTORY_MAX + + // How many seconds the API should wait before attempting to connect to a misbehaving server again. + // Throttling is off if period is less or equal to zero. + int m_ServerThrottlePeriod; + + // Whether to check with LBSMD before re-enabling the server. + bool m_ThrottleUntilDiscoverable; + + void Init(ISynRegistry& registry, const SRegSynonyms& sections); + }; + // Construct a new object. SNetServerPoolImpl(INetServerConnectionListener* listener, bool old_style_auth); - void Init(CConfig* config, const string& section, - INetServerConnectionListener* listener); + void Init(ISynRegistry& registry, const SRegSynonyms& sections, INetServerConnectionListener* listener); SNetServerInPool* FindOrCreateServerImpl(const SServerAddress& server_address); CRef ReturnServer(SNetServerInPool* server_impl); void ResetServerConnections(); + const SThrottleParams& GetThrottleParams() const { return m_ThrottleParams; } virtual ~SNetServerPoolImpl(); @@ -107,24 +129,25 @@ struct NCBI_XCONNECT_EXPORT SNetServerPoolImpl : public CObject CRef m_RebalanceStrategy; - string m_LBSMAffinityName; - const char* m_LBSMAffinityValue; + // LBSM affinity name and value + pair m_LBSMAffinity; TNetServerByAddress m_Servers; CFastMutex m_ServerMutex; + // Connection timeout, which is used as the eIO_Open timeout in CSocket::Connect. STimeout m_ConnTimeout; + + // Communication timeout, upon reaching which the connection is closed on the client side. STimeout m_CommTimeout; - STimeout m_FirstServerTimeout; - int m_MaxConsecutiveIOFailures; - int m_IOFailureThresholdNumerator; - int m_IOFailureThresholdDenominator; - int m_ServerThrottlePeriod; - int m_MaxConnectionTime; - bool m_ThrottleUntilDiscoverable; + STimeout m_FirstServerTimeout; + CTimeout m_MaxTotalTime; bool m_UseOldStyleAuth; + +private: + SThrottleParams m_ThrottleParams; }; struct SNetServiceIteratorImpl : public CObject @@ -245,24 +268,38 @@ public: virtual ~IServiceTraversal() {} }; -struct NCBI_XCONNECT_EXPORT SNetServiceImpl : public CObject +struct SNetServiceXSiteAPI : public CObject +{ + static void InitXSite(ISynRegistry& registry, const SRegSynonyms& sections); + static void ConnectXSite(CSocket&, SNetServerImpl::SConnectDeadline&, + const SServerAddress&); + +#ifdef NCBI_GRID_XSITE_CONN_SUPPORT + static bool IsUsingXSiteProxy(); + static void AllowXSiteConnections(); + +private: + static bool IsForeignAddr(unsigned int ip); + static int GetDomain(unsigned int ip); + + static atomic m_LocalDomain; + static atomic m_AllowXSiteConnections; +#endif +}; + +struct NCBI_XCONNECT_EXPORT SNetServiceImpl : SNetServiceXSiteAPI { + class CTry; + // Construct a new object. - SNetServiceImpl(const string& api_name, const string& client_name, + SNetServiceImpl(const string& api_name, const string& service_name, const string& client_name, INetServerConnectionListener* listener, bool old_style_auth = false) : m_Listener(listener), m_ServerPool(new SNetServerPoolImpl(listener, old_style_auth)), -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - m_ColoNetwork(0), - m_AllowXSiteConnections(false), -#endif + m_ServiceName(service_name), m_APIName(api_name), - m_ClientName(client_name), - m_UseSmartRetries(true), - m_ConnectionMaxRetries(-1), - m_ConnectionRetryDelay(-1) + m_ClientName(client_name) { - ZeroInit(); } // Constructors for 'spawning'. @@ -270,45 +307,33 @@ struct NCBI_XCONNECT_EXPORT SNetServiceImpl : public CObject m_Listener(prototype->m_Listener), m_ServerPool(prototype->m_ServerPool), m_ServiceName(server->m_Address.AsString()), -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - m_ColoNetwork(prototype->m_ColoNetwork), - m_AllowXSiteConnections(prototype->m_AllowXSiteConnections), -#endif m_APIName(prototype->m_APIName), m_ClientName(prototype->m_ClientName), m_UseSmartRetries(prototype->m_UseSmartRetries), m_ConnectionMaxRetries(prototype->m_ConnectionMaxRetries), - m_ConnectionRetryDelay(prototype->m_ConnectionRetryDelay) + m_ConnectionRetryDelay(prototype->m_ConnectionRetryDelay), + m_NetInfo(prototype->m_NetInfo) { - ZeroInit(); Construct(server); } SNetServiceImpl(const string& service_name, SNetServiceImpl* prototype) : m_Listener(prototype->m_Listener), m_ServerPool(prototype->m_ServerPool), m_ServiceName(service_name), -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - m_ColoNetwork(prototype->m_ColoNetwork), - m_AllowXSiteConnections(prototype->m_AllowXSiteConnections), -#endif m_APIName(prototype->m_APIName), m_ClientName(prototype->m_ClientName), m_UseSmartRetries(prototype->m_UseSmartRetries), m_ConnectionMaxRetries(prototype->m_ConnectionMaxRetries), - m_ConnectionRetryDelay(prototype->m_ConnectionRetryDelay) + m_ConnectionRetryDelay(prototype->m_ConnectionRetryDelay), + m_NetInfo(prototype->m_NetInfo) { - ZeroInit(); Construct(); } - void ZeroInit(); - void Construct(SNetServerInPool* server); void Construct(); - void Init(CObject* api_impl, const string& service_name, - CConfig* config, const string& config_section, - const char* const* default_config_sections); + void Init(CObject* api_impl, const IRegistry* top_registry, SRegSynonyms sections); string MakeAuthString(); @@ -336,14 +361,16 @@ struct NCBI_XCONNECT_EXPORT SNetServiceImpl : public CObject const string& GetClientName() const { return m_ClientName; } -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - void AllowXSiteConnections(); - - bool IsColoAddr(unsigned int ip) const + CRef SetEventHandler(INetEventHandler* new_handler) { - return (SOCK_NetToHostLong(ip) >> 16) == m_ColoNetwork; + CRef old_handler(m_Listener->m_EventHandler.ReleaseOrNull()); + m_Listener->m_EventHandler.Reset(new_handler); + return old_handler; } -#endif + + unsigned GetConnectionMaxRetries() const { return m_ConnectionMaxRetries; } + unsigned long GetConnectionRetryDelay() const { return m_ConnectionRetryDelay; } + shared_ptr GetTryGuard(); virtual ~SNetServiceImpl(); @@ -354,17 +381,12 @@ struct NCBI_XCONNECT_EXPORT SNetServiceImpl : public CObject CNetServerPool m_ServerPool; string m_ServiceName; - CNetService::EServiceType m_ServiceType; + CNetService::EServiceType m_ServiceType = CNetService::eServiceNotDefined; CFastMutex m_DiscoveryMutex; - SDiscoveredServers* m_DiscoveredServers; - SDiscoveredServers* m_ServerGroupPool; - unsigned m_LatestDiscoveryIteration; - -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - unsigned int m_ColoNetwork; - bool m_AllowXSiteConnections; -#endif + SDiscoveredServers* m_DiscoveredServers = nullptr; + SDiscoveredServers* m_ServerGroupPool = nullptr; + unsigned m_LatestDiscoveryIteration = 0; private: string m_APIName; @@ -372,8 +394,10 @@ private: // connection parameters from config bool m_UseSmartRetries; - int m_ConnectionMaxRetries; - int m_ConnectionRetryDelay; + unsigned m_ConnectionMaxRetries; + unsigned long m_ConnectionRetryDelay; + + shared_ptr m_NetInfo; }; struct SNetServiceMap { diff --git a/c++/src/connect/services/netservice_params.cpp b/c++/src/connect/services/netservice_params.cpp index 2c591bcc..967a43eb 100644 --- a/c++/src/connect/services/netservice_params.cpp +++ b/c++/src/connect/services/netservice_params.cpp @@ -1,4 +1,4 @@ -/* $Id: netservice_params.cpp 478064 2015-09-03 16:58:00Z sadyrovr $ +/* $Id: netservice_params.cpp 544131 2017-08-18 13:35:50Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,18 +32,19 @@ */ #include +#include #include "netservice_params.hpp" +#include + BEGIN_NCBI_SCOPE NCBI_PARAM_DEF(bool, netservice_api, use_linger2, false); -NCBI_PARAM_DEF(unsigned int, netservice_api, connection_max_retries, 4); +NCBI_PARAM_DEF(unsigned int, netservice_api, connection_max_retries, CONNECTION_MAX_RETRIES); NCBI_PARAM_DEF(string, netservice_api, retry_delay, NCBI_AS_STRING(RETRY_DELAY_DEFAULT)); -NCBI_PARAM_DEF(string, netservice_api, communication_timeout, - NCBI_AS_STRING(COMMUNICATION_TIMEOUT_DEFAULT)); NCBI_PARAM_DEF(int, netservice_api, max_find_lbname_retries, 3); NCBI_PARAM_DEF(string, netcache_api, fallback_server, ""); NCBI_PARAM_DEF(int, netservice_api, max_connection_pool_size, 0); // unlimited @@ -53,9 +54,6 @@ NCBI_PARAM_DEF(bool, server, stop_on_job_errors, true); NCBI_PARAM_DEF(bool, server, allow_implicit_job_return, false); -static bool s_DefaultCommTimeout_Initialized = false; -static STimeout s_DefaultCommTimeout; - unsigned long s_SecondsToMilliseconds( const string& seconds, unsigned long default_value) { @@ -87,23 +85,6 @@ unsigned long s_SecondsToMilliseconds( return *ch == '\0' ? result * powers_of_ten[exponent] : default_value; } -STimeout s_GetDefaultCommTimeout() -{ - if (s_DefaultCommTimeout_Initialized) - return s_DefaultCommTimeout; - NcbiMsToTimeout(&s_DefaultCommTimeout, - s_SecondsToMilliseconds(TServConn_CommTimeout::GetDefault(), - SECONDS_DOUBLE_TO_MS_UL(COMMUNICATION_TIMEOUT_DEFAULT))); - s_DefaultCommTimeout_Initialized = true; - return s_DefaultCommTimeout; -} - -void s_SetDefaultCommTimeout(const STimeout& tm) -{ - s_DefaultCommTimeout = tm; - s_DefaultCommTimeout_Initialized = true; -} - unsigned long s_GetRetryDelay() { static unsigned long retry_delay; @@ -112,7 +93,7 @@ unsigned long s_GetRetryDelay() if (!retry_delay_is_set) { retry_delay = s_SecondsToMilliseconds(TServConn_RetryDelay::GetDefault(), - SECONDS_DOUBLE_TO_MS_UL(RETRY_DELAY_DEFAULT)); + RETRY_DELAY_DEFAULT * kMilliSecondsPerSecond); retry_delay_is_set = true; } @@ -120,4 +101,262 @@ unsigned long s_GetRetryDelay() return retry_delay; } +CConfigRegistry::CConfigRegistry(CConfig* config) : + m_Config(config) +{ +} + +void CConfigRegistry::Reset(CConfig* config) +{ + m_Config = config; + m_SubConfigs.clear(); +} + +bool CConfigRegistry::x_Empty(TFlags flags) const +{ + NCBI_ALWAYS_TROUBLE("Not implemented"); + return false; // Not reached +} + +CConfig* CConfigRegistry::GetSubConfig(const string& section) const +{ + auto it = m_SubConfigs.find(section); + + if (it != m_SubConfigs.end()) return it->second.get(); + + if (const CConfig::TParamTree* tree = m_Config->GetTree()) { + if (const CConfig::TParamTree* sub_tree = tree->FindSubNode(section)) { + unique_ptr sub_config(new CConfig(sub_tree)); + auto result = m_SubConfigs.emplace(section, move(sub_config)); + return result.first->second.get(); + } + } + + return m_Config; +} + +const string& CConfigRegistry::x_Get(const string& section, const string& name, TFlags) const +{ + _ASSERT(m_Config); + + try { + const auto& found = GetSubConfig(section); + return found ? found->GetString(section, name, CConfig::eErr_Throw) : kEmptyStr; + } + catch (CConfigException& ex) { + if (ex.GetErrCode() == CConfigException::eParameterMissing) return kEmptyStr; + + NCBI_RETHROW2(ex, CRegistryException, eErr, ex.GetMsg(), 0); + } +} + +bool CConfigRegistry::x_HasEntry(const string& section, const string& name, TFlags flags) const +{ + _ASSERT(m_Config); + + try { + const auto& found = GetSubConfig(section); + if (!found) return false; + found->GetString(section, name, CConfig::eErr_Throw); + } + catch (CConfigException& ex) { + if (ex.GetErrCode() == CConfigException::eParameterMissing) return false; + + NCBI_RETHROW2(ex, CRegistryException, eErr, ex.GetMsg(), 0); + } + + return true; +} + +const string& CConfigRegistry::x_GetComment(const string& section, const string& name, TFlags flags) const +{ + NCBI_ALWAYS_TROUBLE("Not implemented"); + return kEmptyStr; // Not reached +} + +void CConfigRegistry::x_Enumerate(const string& section, list& entries, TFlags flags) const +{ + NCBI_ALWAYS_TROUBLE("Not implemented"); +} + +void CSynRegistryImpl::Add(const IRegistry& registry) +{ + // Always add a registry as new top priority + m_Registry.Add(registry, ++m_Priority); +} + +template +TType CSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, TType default_value) +{ + _ASSERT(m_Priority); + _ASSERT(sections.size()); + _ASSERT(names.size()); + + for (const auto& section : sections) { + for (const auto& name : names) { + if (!HasImpl(section, name)) continue; + + try { + return m_Registry.GetValue(section, name, default_value, IRegistry::eThrow); + } + catch (CStringException& ex) { + LOG_POST(Warning << ex.what()); + } + catch (CRegistryException& ex) { + LOG_POST(Warning << ex.what()); + } + } + } + + return default_value; +} + +bool ISynRegistry::Has(const SRegSynonyms& sections, SRegSynonyms names) +{ + _ASSERT(sections.size()); + _ASSERT(names.size()); + + for (const auto& section : sections) { + for (const auto& name : names) { + if (HasImpl(section, name)) return true; + } + } + + return false; +} + +template string CSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, string default_value); +template bool CSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, bool default_value); +template int CSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, int default_value); +template double CSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, double default_value); + +class CCachedSynRegistryImpl::CCache +{ +public: + struct SValue + { + struct SValueHolder + { + template + operator TType() const + { + _ASSERT(typeid(TType).hash_code() == m_TypeHash); + return *static_cast(m_Value.get()); + } + + template + SValueHolder& operator=(TType value) + { + _ASSERT(m_TypeHash = typeid(TType).hash_code()); + m_Value = make_shared(value); + return *this; + } + + private: + size_t m_TypeHash = 0; + shared_ptr m_Value; + }; + + enum { New, Default, Read } type = New; + SValueHolder value; + }; + + using TValuePtr = shared_ptr; + using TValues = unordered_map>; + + bool Has(const SRegSynonyms& sections, SRegSynonyms names); + TValuePtr Get(const SRegSynonyms& sections, SRegSynonyms names); + +private: + TValuePtr Find(const SRegSynonyms& sections, SRegSynonyms names); + + TValues m_Values; +}; + +CCachedSynRegistryImpl::CCache::TValuePtr CCachedSynRegistryImpl::CCache::Find(const SRegSynonyms& sections, SRegSynonyms names) +{ + _ASSERT(sections.size()); + _ASSERT(names.size()); + + auto section = sections.front(); + auto name = names.front(); + auto& section_values = m_Values[section]; + auto found = section_values.find(name); + + return found != section_values.end() ? found->second : nullptr; +} + +bool CCachedSynRegistryImpl::CCache::Has(const SRegSynonyms& sections, SRegSynonyms names) +{ + auto found = Find(sections, names); + return found && found->type == SValue::Read; +} + +CCachedSynRegistryImpl::CCache::TValuePtr CCachedSynRegistryImpl::CCache::Get(const SRegSynonyms& sections, SRegSynonyms names) +{ + if (auto found = Find(sections, names)) return found; + + TValuePtr value(new SValue); + + for (auto& s : sections) { + for (auto& n : names) { + auto& sv = m_Values[s]; + + // If failed, corresponding parameter has already been read with a different set of synonyms + _VERIFY(sv.insert(make_pair(n, value)).second); + } + } + + return value; +} + +CCachedSynRegistryImpl::CCachedSynRegistryImpl(ISynRegistry& registry) : + m_Registry(registry), + m_Cache(new CCache) +{ +} + +CCachedSynRegistryImpl::~CCachedSynRegistryImpl() +{ +} + +void CCachedSynRegistryImpl::Add(const IRegistry& registry) +{ + m_Registry.Add(registry); +} + +template +TType CCachedSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, TType default_value) +{ + auto cached = m_Cache->Get(sections, names); + auto& cached_type = cached->type; + auto& cached_value = cached->value; + + // Has a non-default cached value + if (cached_type == CCache::SValue::Read) return cached_value; + + // Has a non-default value + if (m_Registry.Has(sections, names)) { + cached_type = CCache::SValue::Read; + cached_value = m_Registry.Get(sections, names, default_value); + + // Has no (default) value cached + } else if (cached_type == CCache::SValue::New) { + cached_type = CCache::SValue::Default; + cached_value = default_value; + } + + return cached_value; +} + +bool CCachedSynRegistryImpl::HasImpl(const string& section, const string& name) +{ + return (m_Cache->Has(section, name)) || m_Registry.Has(section, name); +} + +template string CCachedSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, string default_value); +template bool CCachedSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, bool default_value); +template int CCachedSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, int default_value); +template double CCachedSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, double default_value); + END_NCBI_SCOPE diff --git a/c++/src/connect/services/netservice_params.hpp b/c++/src/connect/services/netservice_params.hpp index 3893f678..7ab4b6fd 100644 --- a/c++/src/connect/services/netservice_params.hpp +++ b/c++/src/connect/services/netservice_params.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES__NETSERVICE_PARAMS_HPP #define CONNECT_SERVICES__NETSERVICE_PARAMS_HPP -/* $Id: netservice_params.hpp 478064 2015-09-03 16:58:00Z sadyrovr $ +/* $Id: netservice_params.hpp 544131 2017-08-18 13:35:50Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,69 +37,24 @@ #include #include +#include -// Delay between two successive connection attempts in seconds. -#define RETRY_DELAY_DEFAULT 1.0 - -// Connection timeout, which is used as the eIO_Open timeout -// in CSocket::Connect. -#define CONNECTION_TIMEOUT_DEFAULT 2.0 - -// Communication timeout, upon reaching which the connection -// is closed on the client side. -#define COMMUNICATION_TIMEOUT_DEFAULT 12.0 - -// How many seconds the API should wait before attempting to -// connect to a misbehaving server again. -#define THROTTLE_RELAXATION_PERIOD_DEFAULT 0 - -// The parameters below describe different conditions that -// trigger server throttling. -#define THROTTLE_BY_SUBSEQUENT_CONNECTION_FAILURES_DEFAULT 0 - -// A helper macro used in THROTTLE_BY_ERROR_RATE_DEFAULT. -#define NCBI_RATIO_AS_STRING(numerator, denominator) \ - NCBI_AS_STRING(numerator) "/" NCBI_AS_STRING(denominator) - -// Connection failure rate, which is when reached, triggers -// server throttling. -#define THROTTLE_BY_ERROR_RATE_DEFAULT_NUMERATOR 0 - -// THROTTLE_BY_ERROR_RATE_DEFAULT_DENOMINATOR cannot be greater -// than CONNECTION_ERROR_HISTORY_MAX. -#define THROTTLE_BY_ERROR_RATE_DEFAULT_DENOMINATOR 0 +#include -// The previous two parameters as a string. -#define THROTTLE_BY_ERROR_RATE_DEFAULT NCBI_RATIO_AS_STRING( \ - THROTTLE_BY_ERROR_RATE_DEFAULT_NUMERATOR, \ - THROTTLE_BY_ERROR_RATE_DEFAULT_DENOMINATOR) +// The number of connection attemps +#define CONNECTION_MAX_RETRIES 4 -// Whether to check with LBSMD before re-enabling the server. -#define THROTTLE_HOLD_UNTIL_ACTIVE_IN_LB_DEFAULT false +// Delay between two successive connection attempts in seconds. +#define RETRY_DELAY_DEFAULT 1.0 // The size of an internal array, which is used for calculation // of the connection failure rate. #define CONNECTION_ERROR_HISTORY_MAX 128 -// Maximum cumulative query time in seconds. -// The parameter is ignored if it's zero. -#define MAX_CONNECTION_TIME_DEFAULT 0.0 - -// The following two parameters define how often LBSMD -// is queried by default. -#define REBALANCE_TIME_DEFAULT 10.0 -#define REBALANCE_REQUESTS_DEFAULT 5000 - -#define FIRST_SERVER_TIMEOUT_DEFAULT 0.3 - #define COMMIT_JOB_INTERVAL_DEFAULT 2 BEGIN_NCBI_SCOPE -NCBI_PARAM_DECL(string, netservice_api, communication_timeout); -typedef NCBI_PARAM_TYPE(netservice_api, communication_timeout) - TServConn_CommTimeout; - NCBI_PARAM_DECL(unsigned int, netservice_api, connection_max_retries); typedef NCBI_PARAM_TYPE(netservice_api, connection_max_retries) TServConn_ConnMaxRetries; @@ -147,15 +102,205 @@ NCBI_PARAM_DECL(bool, server, allow_implicit_job_return); typedef NCBI_PARAM_TYPE(server, allow_implicit_job_return) TWorkerNode_AllowImplicitJobReturn; -#define SECONDS_DOUBLE_TO_MS_UL(seconds) ((unsigned long) (seconds * 1000.0)) - NCBI_XCONNECT_EXPORT unsigned long s_SecondsToMilliseconds( const string& seconds, unsigned long default_value); -NCBI_XCONNECT_EXPORT STimeout s_GetDefaultCommTimeout(); -NCBI_XCONNECT_EXPORT void s_SetDefaultCommTimeout(const STimeout& tm); NCBI_XCONNECT_EXPORT unsigned long s_GetRetryDelay(); +class NCBI_XCONNECT_EXPORT CConfigRegistry : public IRegistry +{ +public: + CConfigRegistry(CConfig* config = nullptr); + void Reset(CConfig* config = nullptr); + +private: + bool x_Empty(TFlags flags) const override; + const string& x_Get(const string& section, const string& name, TFlags flags) const override; + bool x_HasEntry(const string& section, const string& name, TFlags flags) const override; + const string& x_GetComment(const string& section, const string& name, TFlags flags) const override; + void x_Enumerate(const string& section, list& entries, TFlags flags) const override; + + CConfig* GetSubConfig(const string& section) const; + + CConfig* m_Config; + mutable map> m_SubConfigs; +}; + +// Convenience wrapper to support for both CConfig and IRegistry automatically +struct SConfigOrRegistry +{ + SConfigOrRegistry() : m_Registry(nullptr) {} + + SConfigOrRegistry(const IRegistry& registry) : m_Registry(®istry) {} + + SConfigOrRegistry(CConfig* config) : + m_Registry(config ? new CConfigRegistry(config) : nullptr) + { + } + + operator const IRegistry*() const { return m_Registry.GetPointer(); } + +private: + CRef m_Registry; +}; + +struct SRegSynonyms : vector +{ + using TBase = vector; + + SRegSynonyms(const char* v) : TBase({v}) {} + SRegSynonyms(const string& v) : TBase({v}) {} + + template + SRegSynonyms(initializer_list l) + { + for (auto& s : l) { + if (NotFound(s)) emplace_back(s); + } + } + + SRegSynonyms(initializer_list src) + { + auto i = back_inserter(*this); + auto f = [&](CTempString s) { return NotFound(s); }; + + for (auto& s : src) { + copy_if(s.begin(), s.end(), i, f); + } + } + +private: + bool NotFound(CTempString s) const { return find(begin(), end(), s) == end(); } +}; + +class NCBI_XCONNECT_EXPORT ISynRegistry +{ + template struct TR; + +public: + virtual ~ISynRegistry() {} + + // XXX: + // Since there is no such thing as a virtual template method, a workaround is used: + // Template methods (ISynRegistry::Get) call virtual methods (ISynRegistry::VGet). + // Their overrides (TSynRegistry::VGet) call actual implementations (TImpl::TGet). + + template + typename TR::T Get(const SRegSynonyms& sections, SRegSynonyms names, TType default_value) + { + return VGet(sections, names, static_cast::T>(default_value)); + } + + bool Has(const SRegSynonyms& sections, SRegSynonyms names); + + virtual void Add(const IRegistry& registry) = 0; + +protected: + virtual string VGet(const SRegSynonyms& sections, SRegSynonyms names, string default_value) = 0; + virtual bool VGet(const SRegSynonyms& sections, SRegSynonyms names, bool default_value) = 0; + virtual int VGet(const SRegSynonyms& sections, SRegSynonyms names, int default_value) = 0; + virtual double VGet(const SRegSynonyms& sections, SRegSynonyms names, double default_value) = 0; + + virtual bool HasImpl(const string& section, const string& name) = 0; +}; + +template struct ISynRegistry::TR { using T = TType; }; +template <> struct ISynRegistry::TR { using T = string; }; +template <> struct ISynRegistry::TR { using T = int; }; + +template +class TSynRegistry : public TImpl +{ +public: + template + TSynRegistry(TArgs&&... args) : TImpl(std::forward(args)...) {} + +protected: + string VGet(const SRegSynonyms& sections, SRegSynonyms names, string default_value) final; + bool VGet(const SRegSynonyms& sections, SRegSynonyms names, bool default_value) final; + int VGet(const SRegSynonyms& sections, SRegSynonyms names, int default_value) final; + double VGet(const SRegSynonyms& sections, SRegSynonyms names, double default_value) final; +}; + +class NCBI_XCONNECT_EXPORT CSynRegistryImpl : public ISynRegistry +{ +public: + void Add(const IRegistry& registry) override; + +protected: + template + TType TGet(const SRegSynonyms& sections, SRegSynonyms names, TType default_value); + + bool HasImpl(const string& section, const string& name) final + { + _ASSERT(m_Priority); + return m_Registry.HasEntry(section, name); + } + +private: + CCompoundRegistry m_Registry; + int m_Priority = 0; +}; + +using CSynRegistry = TSynRegistry; + +class NCBI_XCONNECT_EXPORT CCachedSynRegistryImpl : public ISynRegistry +{ + class CCache; + +public: + CCachedSynRegistryImpl(ISynRegistry& registry); + ~CCachedSynRegistryImpl(); + + void Add(const IRegistry& registry) override; + +protected: + template + TType TGet(const SRegSynonyms& sections, SRegSynonyms names, TType default_value); + + bool HasImpl(const string& section, const string& name) final; + +private: + ISynRegistry& m_Registry; + unique_ptr m_Cache; +}; + +using CCachedSynRegistry = TSynRegistry; + +extern template NCBI_XCONNECT_EXPORT string CSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, string default_value); +extern template NCBI_XCONNECT_EXPORT bool CSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, bool default_value); +extern template NCBI_XCONNECT_EXPORT int CSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, int default_value); +extern template NCBI_XCONNECT_EXPORT double CSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, double default_value); + +extern template NCBI_XCONNECT_EXPORT string CCachedSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, string default_value); +extern template NCBI_XCONNECT_EXPORT bool CCachedSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, bool default_value); +extern template NCBI_XCONNECT_EXPORT int CCachedSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, int default_value); +extern template NCBI_XCONNECT_EXPORT double CCachedSynRegistryImpl::TGet(const SRegSynonyms& sections, SRegSynonyms names, double default_value); + +template +string TSynRegistry::VGet(const SRegSynonyms& sections, SRegSynonyms names, string default_value) +{ + return TImpl::TGet(sections, names, default_value); +} + +template +bool TSynRegistry::VGet(const SRegSynonyms& sections, SRegSynonyms names, bool default_value) +{ + return TImpl::TGet(sections, names, default_value); +} + +template +int TSynRegistry::VGet(const SRegSynonyms& sections, SRegSynonyms names, int default_value) +{ + return TImpl::TGet(sections, names, default_value); +} + +template +double TSynRegistry::VGet(const SRegSynonyms& sections, SRegSynonyms names, double default_value) +{ + return TImpl::TGet(sections, names, default_value); +} + END_NCBI_SCOPE #endif /* CONNECT_SERVICES__NETSERVICE_PARAMS_HPP */ diff --git a/c++/src/connect/services/netstorage.cpp b/c++/src/connect/services/netstorage.cpp index 9c3a6c68..f428e0fa 100644 --- a/c++/src/connect/services/netstorage.cpp +++ b/c++/src/connect/services/netstorage.cpp @@ -1,4 +1,4 @@ -/* $Id: netstorage.cpp 505978 2016-06-30 15:57:38Z sadyrovr $ +/* $Id: netstorage.cpp 542376 2017-07-31 12:15:04Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -38,96 +38,284 @@ BEGIN_NCBI_SCOPE -struct SNetStorageObjectRWStream : public CRWStream +struct SEmbeddedStreamReaderWriter : IEmbeddedStreamReaderWriter { - SNetStorageObjectRWStream(SNetStorageObjectImpl* nst_object) : - CRWStream(nst_object, nst_object, /*buf_size*/ 0, /*buf*/ NULL, - CRWStreambuf::fLeakExceptions), - m_NetStorageObject(nst_object) + SEmbeddedStreamReaderWriter(SNetStorageObjectImpl& impl) : m_Impl(impl) {} + + ERW_Result Read(void* b, size_t c, size_t* r) override { return m_Impl->Read(b, c, r); } + ERW_Result PendingCount(size_t* c) override { return m_Impl->PendingCount(c); } + ERW_Result Write(const void* b, size_t c, size_t* w) override { return m_Impl->Write(b, c, w); } + ERW_Result Flush() override { return m_Impl->Flush(); } + void Close() override { m_Impl->Close(); } + void Abort() override { m_Impl->Abort(); } + +private: + SNetStorageObjectImpl& m_Impl; +}; + +// Ignore empty writes to iostream (CXX-8936) +struct SIoStreamEmbeddedStreamReaderWriter : SEmbeddedStreamReaderWriter +{ + SIoStreamEmbeddedStreamReaderWriter(SNetStorageObjectImpl& impl) : SEmbeddedStreamReaderWriter(impl) {} + + ERW_Result Write(const void* buf, size_t count, size_t* written) override + { + if (count) return SEmbeddedStreamReaderWriter::Write(buf, count, written); + + if (written) *written = 0; + return eRW_Success; + } +}; + +struct SNetStorageObjectRWStream : public CNcbiIostream +{ + SNetStorageObjectRWStream(SNetStorageObjectImpl* impl, IEmbeddedStreamReaderWriter *rw) : + CNcbiIostream(0), + m_Object(impl), + m_Sb(rw, rw, 1, nullptr, CRWStreambuf::fLeakExceptions) { + _ASSERT(impl); + _ASSERT(rw); + init(&m_Sb); } - virtual ~SNetStorageObjectRWStream() { flush(); } + ~SNetStorageObjectRWStream() override { m_Object.Close(); } - CNetStorageObject m_NetStorageObject; +private: + CNetStorageObject m_Object; + CRWStreambuf m_Sb; }; -string CNetStorageObject::GetLoc() +ERW_Result SNetStorageObjectOState::Read(void*, size_t, size_t*) +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling Read() while writing " << GetLoc()); +} + +ERW_Result SNetStorageObjectOState::PendingCount(size_t*) +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling PendingCount() while writing " << GetLoc()); +} + +bool SNetStorageObjectOState::Eof() +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling Eof() while writing " << GetLoc()); +} + +ERW_Result SNetStorageObjectIState::Write(const void*, size_t, size_t*) +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling Write() while reading " << GetLoc()); +} + +ERW_Result SNetStorageObjectIState::Flush() +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling Flush() while reading " << GetLoc()); +} + +Uint8 SNetStorageObjectIoState::GetSize() +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling GetSize() while reading/writing " << GetLoc()); +} + +list SNetStorageObjectIoState::GetAttributeList() const +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling GetAttributeList() while reading/writing " << GetLoc()); +} + +string SNetStorageObjectIoState::GetAttribute(const string&) const +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling GetAttribute() while reading/writing " << GetLoc()); +} + +void SNetStorageObjectIoState::SetAttribute(const string&, const string& ) +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling SetAttribute() while reading/writing " << GetLoc()); +} + +CNetStorageObjectInfo SNetStorageObjectIoState::GetInfo() +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling GetInfo() while reading/writing " << GetLoc()); +} + +void SNetStorageObjectIoState::SetExpiration(const CTimeout&) +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling SetExpiration() while reading/writing " << GetLoc()); +} + +string SNetStorageObjectIoState::FileTrack_Path() +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling FileTrack_Path() while reading/writing " << GetLoc()); +} + +string SNetStorageObjectIoState::Relocate(TNetStorageFlags, TNetStorageProgressCb) { - return m_Impl->GetLoc(); + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling Relocate() while reading/writing " << GetLoc()); +} + +bool SNetStorageObjectIoState::Exists() +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling Exists() while reading/writing " << GetLoc()); +} + +ENetStorageRemoveResult SNetStorageObjectIoState::Remove() +{ + NCBI_THROW_FMT(CNetStorageException, eInvalidArg, "Calling Remove() while reading/writing " << GetLoc()); +} + +string SNetStorageObjectIoMode::ToString(EApi api, EMth mth) +{ + if (api == eBuffer) { + if (mth == eRead) return "Read(buffer)"; + if (mth == eWrite) return "Write(buffer)"; + if (mth == eEof) return "Eof()"; + } + + if (api == eIoStream) { + return "GetRWStream()"; + } + + if (api == eIReaderIWriter) { + if (mth == eRead) return "GetReader()"; + if (mth == eWrite) return "GetWriter()"; + } + + if (api == eString) { + if (mth == eRead) return "Read(string)"; + if (mth == eWrite) return "Write(string)"; + } + + _ASSERT(false); + return ""; // Not reached +} + +void SNetStorageObjectIoMode::Throw(EApi api, EMth mth, string object_loc) +{ + NCBI_THROW_FMT(CNetStorageException, eNotSupported, + "Calling " << ToString(api, mth) << " after " << + ToString(m_Api, m_Mth) << " for " << object_loc); +} + +IEmbeddedStreamReaderWriter& SNetStorageObjectImpl::GetReaderWriter() +{ + if (!m_ReaderWriter) m_ReaderWriter.reset(new SEmbeddedStreamReaderWriter(*this)); + return *m_ReaderWriter; +} + +SNetStorageObjectImpl::~SNetStorageObjectImpl() +{ + try { + if (m_Current) m_Current->Close(); + } + NCBI_CATCH_ALL("Error while implicitly closing a NetStorage object."); +} + +CNcbiIostream* SNetStorageObjectImpl::GetRWStream() +{ + if (!m_IoStreamReaderWriter) m_IoStreamReaderWriter.reset(new SIoStreamEmbeddedStreamReaderWriter(*this)); + return new SNetStorageObjectRWStream(this, m_IoStreamReaderWriter.get()); +} + +void SNetStorageObjectImpl::Close() +{ + _ASSERT(m_Current); + m_IoMode.Reset(); + return m_Current->Close(); +} + +string CNetStorageObject::GetLoc() const +{ + return m_Impl--->GetLoc(); } size_t CNetStorageObject::Read(void* buffer, size_t buf_size) { size_t bytes_read; - m_Impl->Read(buffer, buf_size, &bytes_read); + m_Impl->SetIoMode(SNetStorageObjectIoMode::eBuffer, SNetStorageObjectIoMode::eRead); + m_Impl--->Read(buffer, buf_size, &bytes_read); return bytes_read; } void CNetStorageObject::Read(string* data) { - m_Impl->Read(data); + char buffer[64 * 1024]; + + data->resize(0); + size_t bytes_read; + + m_Impl->SetIoMode(SNetStorageObjectIoMode::eString, SNetStorageObjectIoMode::eRead); + + do { + m_Impl--->Read(buffer, sizeof(buffer), &bytes_read); + data->append(buffer, bytes_read); + } while (!m_Impl--->Eof()); + + Close(); } IReader& CNetStorageObject::GetReader() { - return m_Impl->GetReader(); + m_Impl->SetIoMode(SNetStorageObjectIoMode::eIReaderIWriter, SNetStorageObjectIoMode::eRead); + return m_Impl->GetReaderWriter(); } bool CNetStorageObject::Eof() { - return m_Impl->Eof(); + m_Impl->SetIoMode(SNetStorageObjectIoMode::eBuffer, SNetStorageObjectIoMode::eEof); + return m_Impl--->Eof(); } void CNetStorageObject::Write(const void* buffer, size_t buf_size) { - m_Impl->Write(buffer, buf_size, NULL); + m_Impl->SetIoMode(SNetStorageObjectIoMode::eBuffer, SNetStorageObjectIoMode::eWrite); + m_Impl--->Write(buffer, buf_size, NULL); } void CNetStorageObject::Write(const string& data) { - m_Impl->Write(data.data(), data.length(), NULL); + m_Impl->SetIoMode(SNetStorageObjectIoMode::eString, SNetStorageObjectIoMode::eWrite); + m_Impl--->Write(data.data(), data.length(), NULL); } IEmbeddedStreamWriter& CNetStorageObject::GetWriter() { - return m_Impl->GetWriter(); + m_Impl->SetIoMode(SNetStorageObjectIoMode::eIReaderIWriter, SNetStorageObjectIoMode::eWrite); + return m_Impl->GetReaderWriter(); } CNcbiIostream* CNetStorageObject::GetRWStream() { - return new SNetStorageObjectRWStream(m_Impl); + m_Impl->SetIoMode(SNetStorageObjectIoMode::eIoStream, SNetStorageObjectIoMode::eAnyMth); + return m_Impl->GetRWStream(); } Uint8 CNetStorageObject::GetSize() { - return m_Impl->GetSize(); + return m_Impl--->GetSize(); } CNetStorageObject::TAttributeList CNetStorageObject::GetAttributeList() const { - return m_Impl->GetAttributeList(); + return m_Impl--->GetAttributeList(); } string CNetStorageObject::GetAttribute(const string& attr_name) const { - return m_Impl->GetAttribute(attr_name); + return m_Impl--->GetAttribute(attr_name); } void CNetStorageObject::SetAttribute(const string& attr_name, const string& attr_value) { - m_Impl->SetAttribute(attr_name, attr_value); + m_Impl--->SetAttribute(attr_name, attr_value); } CNetStorageObjectInfo CNetStorageObject::GetInfo() { - return m_Impl->GetInfo(); + return m_Impl--->GetInfo(); } void CNetStorageObject::SetExpiration(const CTimeout& ttl) { - m_Impl->SetExpiration(ttl); + m_Impl--->SetExpiration(ttl); } void CNetStorageObject::Close() @@ -152,26 +340,22 @@ CNetStorageObject CNetStorage::Open(const string& object_loc) return m_Impl->Open(object_loc); } -CNetStorageObject CNetStorage::Open(const string& object_loc, - TNetStorageFlags /*flags*/) -{ - return m_Impl->Open(object_loc); -} - -string CNetStorage::Relocate(const string& object_loc, - TNetStorageFlags flags, TNetStorageProgressCb cb) +string CNetStorage::Relocate(const string& object_loc, TNetStorageFlags flags, TNetStorageProgressCb cb) { - return m_Impl->Relocate(object_loc, flags, cb); + auto object = Open(object_loc); + return object--->Relocate(flags, cb); } bool CNetStorage::Exists(const string& object_loc) { - return m_Impl->Exists(object_loc); + auto object = Open(object_loc); + return object--->Exists(); } ENetStorageRemoveResult CNetStorage::Remove(const string& object_loc) { - return m_Impl->Remove(object_loc); + auto object = Open(object_loc); + return object--->Remove(); } CNetStorageByKey::CNetStorageByKey(const string& init_string, @@ -192,34 +376,22 @@ string CNetStorageByKey::Relocate(const string& unique_key, TNetStorageFlags flags, TNetStorageFlags old_flags, TNetStorageProgressCb cb) { - SNetStorage::SLimits::Check(unique_key); - return m_Impl->Relocate(unique_key, flags, old_flags, cb); + auto object = Open(unique_key, old_flags); + return object--->Relocate(flags, cb); } bool CNetStorageByKey::Exists(const string& key, TNetStorageFlags flags) { - SNetStorage::SLimits::Check(key); - return m_Impl->Exists(key, flags); + auto object = Open(key, flags); + return object--->Exists(); } ENetStorageRemoveResult CNetStorageByKey::Remove(const string& key, TNetStorageFlags flags) { - SNetStorage::SLimits::Check(key); - return m_Impl->Remove(key, flags); -} - -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT -void g_AllowXSiteConnections(CNetStorage& netstorage) -{ - netstorage->AllowXSiteConnections(); -} - -void g_AllowXSiteConnections(CNetStorageByKey& netstorage) -{ - netstorage->AllowXSiteConnections(); + auto object = Open(key, flags); + return object--->Remove(); } -#endif inline CNetStorageException::EErrCode ConvertErrCode(CNetCacheException::TErrCode code) @@ -260,7 +432,7 @@ void g_ThrowNetStorageException(const CDiagCompileInfo& compile_info, CNetStorageObject_FileTrack_Path::CNetStorageObject_FileTrack_Path( CNetStorageObject object) - : m_Path(object->FileTrack_Path()) + : m_Path(object--->FileTrack_Path()) { } diff --git a/c++/src/connect/services/netstorage_direct_nc.cpp b/c++/src/connect/services/netstorage_direct_nc.cpp index 2a44199f..87f77e3b 100644 --- a/c++/src/connect/services/netstorage_direct_nc.cpp +++ b/c++/src/connect/services/netstorage_direct_nc.cpp @@ -1,4 +1,4 @@ -/* $Id: netstorage_direct_nc.cpp 504524 2016-06-15 23:50:37Z sadyrovr $ +/* $Id: netstorage_direct_nc.cpp 528688 2017-02-24 15:08:31Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -45,96 +45,79 @@ BEGIN_NCBI_SCOPE -string SNetStorage_NetCacheBlob::GetLoc() +ERW_Result SNetStorage_NetCacheBlob::Read(void* buffer, size_t buf_size, size_t* bytes_read) { - return m_BlobKey; -} - -void SNetStorage_NetCacheBlob::x_InitReader() -{ - if (m_State == eWriting) { - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot read a NetCache blob while writing to it"); - } - try { - m_NetCacheReader.reset(m_NetCacheAPI->GetPartReader( - m_BlobKey, 0, 0, &m_BlobSize, NULL)); + m_IState.reader.reset(m_NetCacheAPI->GetPartReader(m_BlobKey, 0, 0, nullptr, nullptr)); } NETSTORAGE_CONVERT_NETCACHEEXCEPTION("on reading " + m_BlobKey) - m_State = eReading; + EnterState(&m_IState); + return m_IState.Read(buffer, buf_size, bytes_read); } -ERW_Result SNetStorage_NetCacheBlob::Read(void* buffer, size_t buf_size, - size_t* bytes_read) +ERW_Result SNetStorage_NetCacheBlob::SIState::Read(void* buffer, size_t buf_size, size_t* bytes_read) { - if (m_State != eReading) - x_InitReader(); + ERW_Result rw_res = eRW_Success; try { - return g_ReadFromNetCache(m_NetCacheReader.get(), - reinterpret_cast(buffer), buf_size, bytes_read); + rw_res = reader->Read(buffer, buf_size, bytes_read); } - NETSTORAGE_CONVERT_NETCACHEEXCEPTION("on reading " + m_BlobKey) - return eRW_Error; // Not reached + NETSTORAGE_CONVERT_NETCACHEEXCEPTION("on reading " + reader->GetBlobID()) + + if ((rw_res != eRW_Success) && (rw_res != eRW_Eof)) { + NCBI_THROW_FMT(CNetStorageException, eIOError, + "I/O error while reading NetCache BLOB " << + reader->GetBlobID() << ": " << + g_RW_ResultToString(rw_res)); + } + + return rw_res; } ERW_Result SNetStorage_NetCacheBlob::PendingCount(size_t* count) { - if (m_State != eReading) { - *count = 0; - return eRW_Success; - } - return m_NetCacheReader->PendingCount(count); + *count = 0; + return eRW_Success; } -void SNetStorage_NetCacheBlob::Read(string* data) +ERW_Result SNetStorage_NetCacheBlob::SIState::PendingCount(size_t* count) { - try { - m_NetCacheAPI.ReadData(m_BlobKey, *data); - } - NETSTORAGE_CONVERT_NETCACHEEXCEPTION("on reading " + m_BlobKey) + return reader->PendingCount(count); } bool SNetStorage_NetCacheBlob::Eof() { - switch (m_State) { - case eReady: - return false; - - case eReading: - return m_NetCacheReader->Eof(); - - default: /* case eWriting: */ - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot read a NetCache blob while writing"); - } + return false; } -void SNetStorage_NetCacheBlob::x_InitWriter() +bool SNetStorage_NetCacheBlob::SIState::Eof() { - if (m_State == eReading) { - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot write a NetCache blob while reading"); - } + return reader->Eof(); +} +void SNetStorage_NetCacheBlob::StartWriting() +{ try { - m_NetCacheWriter.reset(m_NetCacheAPI.PutData(&m_BlobKey)); + m_OState.writer.reset(m_NetCacheAPI.PutData(&m_BlobKey)); } NETSTORAGE_CONVERT_NETCACHEEXCEPTION("on writing " + m_BlobKey) - m_State = eWriting; + EnterState(&m_OState); } ERW_Result SNetStorage_NetCacheBlob::Write(const void* buf_pos, size_t buf_size, size_t* bytes_written) { - if (m_State != eWriting) - x_InitWriter(); + StartWriting(); + return m_OState.Write(buf_pos, buf_size, bytes_written); +} +ERW_Result SNetStorage_NetCacheBlob::SOState::Write(const void* buf_pos, size_t buf_size, + size_t* bytes_written) +{ try { - return m_NetCacheWriter->Write(buf_pos, buf_size, bytes_written); + return writer->Write(buf_pos, buf_size, bytes_written); } NETSTORAGE_CONVERT_NETCACHEEXCEPTION("on writing " + m_BlobKey) return eRW_Error; // Not reached @@ -142,16 +125,18 @@ ERW_Result SNetStorage_NetCacheBlob::Write(const void* buf_pos, size_t buf_size, ERW_Result SNetStorage_NetCacheBlob::Flush() { - return m_State != eWriting ? eRW_Success : m_NetCacheWriter->Flush(); + return eRW_Success; +} + +ERW_Result SNetStorage_NetCacheBlob::SOState::Flush() +{ + return writer->Flush(); } Uint8 SNetStorage_NetCacheBlob::GetSize() { try { - if (m_State != eReading) - return m_NetCacheAPI.GetBlobSize(m_BlobKey); - else - return m_NetCacheReader->GetBlobSize(); + return m_NetCacheAPI.GetBlobSize(m_BlobKey); } NETSTORAGE_CONVERT_NETCACHEEXCEPTION("on accessing " + m_BlobKey) return 0; // Not reached @@ -232,56 +217,66 @@ string SNetStorage_NetCacheBlob::FileTrack_Path() ": not a FileTrack object"); } -void SNetStorage_NetCacheBlob::Close() +string SNetStorage_NetCacheBlob::Relocate(TNetStorageFlags, TNetStorageProgressCb) { - switch (m_State) { - case eReading: - m_State = eReady; - m_NetCacheReader.reset(); - break; - - case eWriting: - m_State = eReady; - m_NetCacheWriter->Close(); - m_NetCacheWriter.reset(); - break; - - default: - break; + NCBI_THROW_FMT(CNetStorageException, eNotSupported, m_BlobKey << + ": Relocate for NetCache blobs is not implemented"); +} + +bool SNetStorage_NetCacheBlob::Exists() +{ + try { + return m_NetCacheAPI.HasBlob(m_BlobKey); } + NETSTORAGE_CONVERT_NETCACHEEXCEPTION("on accessing " + m_BlobKey) + return false; // Not reached } -void SNetStorage_NetCacheBlob::Abort() +ENetStorageRemoveResult SNetStorage_NetCacheBlob::Remove() { - switch (m_State) { - case eReading: - m_State = eReady; - m_NetCacheReader.reset(); - break; - - case eWriting: - m_State = eReady; - m_NetCacheWriter->Abort(); - m_NetCacheWriter.reset(); - break; - - default: - break; + try { + if (m_NetCacheAPI.HasBlob(m_BlobKey)) { + m_NetCacheAPI.Remove(m_BlobKey); + return eNSTRR_Removed; + } } + NETSTORAGE_CONVERT_NETCACHEEXCEPTION("on removing " + m_BlobKey) + + return eNSTRR_NotFound; } -CNetStorageObject CDNCNetStorage::Create(CNetCacheAPI::TInstance nc_api) +void SNetStorage_NetCacheBlob::SIState::Close() { - auto_ptr result( - new SNetStorage_NetCacheBlob(nc_api, kEmptyStr)); - result->x_InitWriter(); - return result.release(); + ExitState(); + reader.reset(); } -CNetStorageObject CDNCNetStorage::Open(CNetCacheAPI::TInstance nc_api, - const string& blob_key) +void SNetStorage_NetCacheBlob::SOState::Close() +{ + ExitState(); + writer->Close(); + writer.reset(); +} + +void SNetStorage_NetCacheBlob::Close() +{ +} + +void SNetStorage_NetCacheBlob::SIState::Abort() +{ + ExitState(); + reader.reset(); +} + +void SNetStorage_NetCacheBlob::SOState::Abort() +{ + ExitState(); + writer->Abort(); + writer.reset(); +} + +void SNetStorage_NetCacheBlob::Abort() { - return new SNetStorage_NetCacheBlob(nc_api, blob_key); } END_NCBI_SCOPE diff --git a/c++/src/connect/services/netstorage_direct_nc.hpp b/c++/src/connect/services/netstorage_direct_nc.hpp index 146b3daf..74ed8bcf 100644 --- a/c++/src/connect/services/netstorage_direct_nc.hpp +++ b/c++/src/connect/services/netstorage_direct_nc.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES__NETSTORAGE_DIRECT_NC__HPP #define CONNECT_SERVICES__NETSTORAGE_DIRECT_NC__HPP -/* $Id: netstorage_direct_nc.hpp 493146 2016-02-24 17:38:53Z sadyrovr $ +/* $Id: netstorage_direct_nc.hpp 528865 2017-02-27 16:44:59Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -38,68 +38,87 @@ BEGIN_NCBI_SCOPE -struct SNetStorage_NetCacheBlob : public SNetStorageObjectImpl +struct SNetStorage_NetCacheBlob : public INetStorageObjectState { - enum EObjectIdentification { - eByGeneratedID, - eByUniqueKey +private: + struct SIState : public SNetStorageObjectIState + { + unique_ptr reader; + + ERW_Result Read(void* buf, size_t count, size_t* read) override; + ERW_Result PendingCount(size_t* count) override; + bool Eof() override; + + void Close() override; + void Abort() override; + + string GetLoc() const override { return m_BlobKey; } + + protected: + SIState(string& blob_key) : m_BlobKey(blob_key) {} + + private: + string& m_BlobKey; }; - enum EState { - eReady, - eReading, - eWriting + struct SOState : public SNetStorageObjectOState + { + unique_ptr writer; + + ERW_Result Write(const void* buf, size_t count, size_t* written) override; + ERW_Result Flush() override; + + void Close() override; + void Abort() override; + + string GetLoc() const override { return m_BlobKey; } + + protected: + SOState(string& blob_key) : m_BlobKey(blob_key) {} + + private: + string& m_BlobKey; }; - SNetStorage_NetCacheBlob(CNetCacheAPI::TInstance netcache_api, +public: + SNetStorage_NetCacheBlob(SNetStorageObjectImpl& fsm, CNetCacheAPI::TInstance netcache_api, const string& blob_key) : m_NetCacheAPI(netcache_api), m_BlobKey(blob_key), - m_State(SNetStorage_NetCacheBlob::eReady) + m_IState(fsm, m_BlobKey), + m_OState(fsm, m_BlobKey) { } - virtual ERW_Result Read(void* buf, size_t count, size_t* bytes_read); - virtual ERW_Result PendingCount(size_t* count); + ERW_Result Read(void* buf, size_t count, size_t* bytes_read) override; + ERW_Result PendingCount(size_t* count) override; - virtual ERW_Result Write(const void* buf, size_t count, - size_t* bytes_written); - virtual ERW_Result Flush(); - virtual void Close(); - virtual void Abort(); + ERW_Result Write(const void* buf, size_t count, size_t* bytes_written) override; + ERW_Result Flush() override; + void Close() override; + void Abort() override; - virtual string GetLoc(); - virtual void Read(string* data); - virtual bool Eof(); - virtual Uint8 GetSize(); - virtual list GetAttributeList() const; - virtual string GetAttribute(const string& attr_name) const; - virtual void SetAttribute(const string& attr_name, - const string& attr_value); - virtual CNetStorageObjectInfo GetInfo(); - virtual void SetExpiration(const CTimeout&); + string GetLoc() const override { return m_BlobKey; } + bool Eof() override; + Uint8 GetSize() override; + list GetAttributeList() const override; + string GetAttribute(const string& attr_name) const override; + void SetAttribute(const string& attr_name, const string& attr_value) override; + CNetStorageObjectInfo GetInfo() override; + void SetExpiration(const CTimeout&) override; - string FileTrack_Path(); + string FileTrack_Path() override; + string Relocate(TNetStorageFlags flags, TNetStorageProgressCb cb) override; + bool Exists() override; + ENetStorageRemoveResult Remove() override; - void x_InitReader(); - void x_InitWriter(); + void StartWriting(); +private: CNetCacheAPI m_NetCacheAPI; - string m_BlobKey; - EState m_State; - - auto_ptr m_NetCacheWriter; - auto_ptr m_NetCacheReader; - size_t m_BlobSize; -}; - -class CDNCNetStorage -{ -public: - static CNetStorageObject Create(CNetCacheAPI::TInstance nc_api); - static CNetStorageObject Open(CNetCacheAPI::TInstance nc_api, - const string& blob_key); + SNetStorageObjectState m_IState; + SNetStorageObjectState m_OState; }; END_NCBI_SCOPE diff --git a/c++/src/connect/services/netstorage_rpc.cpp b/c++/src/connect/services/netstorage_rpc.cpp index 54f6bfb5..802c4273 100644 --- a/c++/src/connect/services/netstorage_rpc.cpp +++ b/c++/src/connect/services/netstorage_rpc.cpp @@ -1,4 +1,4 @@ -/* $Id: netstorage_rpc.cpp 505978 2016-06-30 15:57:38Z sadyrovr $ +/* $Id: netstorage_rpc.cpp 533663 2017-04-18 19:29:12Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -42,13 +42,12 @@ #include #include +#include #define NCBI_USE_ERRCODE_X NetStorage_RPC #define NST_PROTOCOL_VERSION "1.0.0" -#define READ_CHUNK_SIZE (64 * 1024) - #define WRITE_BUFFER_SIZE (64 * 1024) #define READ_BUFFER_SIZE (64 * 1024) @@ -66,6 +65,9 @@ const char* CNetStorageException::GetErrCodeString() const case eServerError: return "eServerError"; case eTimeout: return "eTimeout"; case eExpired: return "eExpired"; + case eNotSupported: return "eNotSupported"; + case eInterrupted: return "eInterrupted"; + case eUnknown: return "eUnknown"; default: return CException::GetErrCodeString(); } } @@ -148,29 +150,7 @@ void CSendJsonOverSocket::x_SendOutputBuffer() } while (m_JSONWriter.NextOutputBuffer()); } -static void s_SendUTTPChunk(const char* chunk, size_t chunk_size, CSocket& sock) -{ - CUTTPWriter uttp_writer; - - char write_buffer[WRITE_BUFFER_SIZE]; - - uttp_writer.Reset(write_buffer, WRITE_BUFFER_SIZE); - - uttp_writer.SendChunk(chunk, chunk_size, false); - - const char* output_buffer; - size_t output_buffer_size; - - do { - uttp_writer.GetOutputBuffer(&output_buffer, &output_buffer_size); - s_WriteToSocket(sock, output_buffer, output_buffer_size); - } while (uttp_writer.NextOutputBuffer()); - - uttp_writer.GetOutputBuffer(&output_buffer, &output_buffer_size); - s_WriteToSocket(sock, output_buffer, output_buffer_size); -} - -static void s_SendEndOfData(CSocket& sock) +void s_SendUTTP(CSocket& sock, function f) { CUTTPWriter uttp_writer; @@ -178,7 +158,7 @@ static void s_SendEndOfData(CSocket& sock) uttp_writer.Reset(write_buffer, WRITE_BUFFER_SIZE); - uttp_writer.SendControlSymbol(END_OF_DATA_MARKER); + f(uttp_writer); const char* output_buffer; size_t output_buffer_size; @@ -192,14 +172,15 @@ static void s_SendEndOfData(CSocket& sock) s_WriteToSocket(sock, output_buffer, output_buffer_size); } -static void s_ReadSocket(CSocket& sock, void* buffer, - size_t buffer_size, size_t* bytes_read) +template +void s_ReadSocket(CSocket& sock, TContiguousContainer& buffer, CUTTPReader& uttp_reader) { EIO_Status status; + size_t bytes_read; - while ((status = sock.Read(buffer, - buffer_size, bytes_read)) == eIO_Interrupt) - /* no-op */; + do { + status = sock.Read(buffer.data(), buffer.size(), &bytes_read); + } while (status == eIO_Interrupt); if (status != eIO_Success) { // eIO_Timeout, eIO_Closed, eIO_InvalidArg, @@ -209,47 +190,8 @@ static void s_ReadSocket(CSocket& sock, void* buffer, sock.GetPeerAddress() << ". " "Socket status: " << IO_StatusStr(status) << '.'); } -} -class CReadJsonFromSocket -{ -public: - CJsonNode ReadMessage(CSocket& sock); - -private: - CUTTPReader m_UTTPReader; - CJsonOverUTTPReader m_JSONReader; -}; - -CJsonNode CReadJsonFromSocket::ReadMessage(CSocket& sock) -{ - try { - char read_buffer[READ_BUFFER_SIZE]; - - size_t bytes_read; - - do { - s_ReadSocket(sock, read_buffer, READ_BUFFER_SIZE, &bytes_read); - - m_UTTPReader.SetNewBuffer(read_buffer, bytes_read); - - } while (!m_JSONReader.ReadMessage(m_UTTPReader)); - } - catch (...) { - sock.Close(); - throw; - } - - if (m_UTTPReader.GetNextEvent() != CUTTPReader::eEndOfBuffer) { - string server_address(sock.GetPeerAddress()); - sock.Close(); - NCBI_THROW_FMT(CNetStorageException, eIOError, - "Extra bytes past message end while reading from " << - server_address << " after receiving " << - m_JSONReader.GetMessage().Repr() << '.'); - } - - return m_JSONReader.GetMessage(); + uttp_reader.SetNewBuffer(buffer.data(), bytes_read); } struct SIssue @@ -279,6 +221,13 @@ struct SIssue return os << " (" << message << ')'; } + operator string() const + { + ostringstream oss; + Print(oss); + return oss.str(); + } + struct SBuilder { SBuilder(const CJsonNode& node) : @@ -334,48 +283,39 @@ ostream& operator<< (ostream& os, const SIssue& issue) void s_ThrowError(Int8 code, Int8 sub_code, const string& err_msg) { - // Issues were reported by a NetStorage server v2.2.0 or later - if (sub_code != SIssue::kEmptySubCode) { - switch (code) { - case 3000: - code = sub_code; // CNetStorageServerError - break; - case 3010: - throw CNetServiceException(DIAG_COMPILE_INFO, 0, - static_cast(sub_code), - err_msg); - case 3020: - throw CNetStorageException(DIAG_COMPILE_INFO, 0, - static_cast(sub_code), - err_msg); - } + switch (code) { + case 3010: + throw CNetServiceException(DIAG_COMPILE_INFO, 0, + static_cast(sub_code), err_msg); + case 3020: + throw CNetStorageException(DIAG_COMPILE_INFO, 0, + static_cast(sub_code), err_msg); } - switch (code) { - case CNetStorageServerError::eNetStorageObjectNotFound: - case CNetStorageServerError::eRemoteObjectNotFound: - NCBI_THROW_FMT(CNetStorageException, eNotExists, err_msg); - break; - case CNetStorageServerError::eNetStorageObjectExpired: - NCBI_THROW_FMT(CNetStorageException, eExpired, err_msg); - break; - default: - NCBI_THROW_FMT(CNetStorageException, eServerError, err_msg); + switch (sub_code) { + case CNetStorageServerError::eNetStorageObjectNotFound: + case CNetStorageServerError::eRemoteObjectNotFound: + NCBI_THROW(CNetStorageException, eNotExists, err_msg); + + case CNetStorageServerError::eNetStorageObjectExpired: + NCBI_THROW(CNetStorageException, eExpired, err_msg); } + + NCBI_THROW(CNetStorageException, eServerError, err_msg); } -static void s_TrapErrors(const CJsonNode& request, - const CJsonNode& reply, CSocket& sock, - SNetStorage::SConfig::EErrMode err_mode) +void s_TrapErrors(const CJsonNode& request, const CJsonNode& reply, CNetServerConnection& conn, + SNetStorage::SConfig::EErrMode err_mode, INetServerConnectionListener& listener) { + CSocket& sock(conn->m_Socket); + CNetServer& server(conn->m_Server); const string server_address(sock.GetPeerAddress()); CJsonNode issues(reply.GetByKeyOrNull("Warnings")); if (issues) { for (CJsonIterator it = issues.Iterate(); it; ++it) { const SIssue issue(*it); - LOG_POST(Warning << "NetStorage server " << server_address << - " issued warning " << issue); + listener.OnWarning(issue, server); } } @@ -389,8 +329,7 @@ static void s_TrapErrors(const CJsonNode& request, if (err_mode == SNetStorage::SConfig::eLog) { for (CJsonIterator it = issues.Iterate(); it; ++it) { const SIssue issue(*it); - LOG_POST(Error << "NetStorage server " << server_address << - " issued error " << issue); + listener.OnError(issue, server); } } } else { @@ -431,22 +370,75 @@ static void s_TrapErrors(const CJsonNode& request, } } +CJsonNode s_ReadMessage(const CJsonNode& request, CNetServerConnection& conn, SNetStorage::SConfig::EErrMode err_mode, + INetServerConnectionListener& listener) +{ + CSocket& sock(conn->m_Socket); + CUTTPReader uttp_reader; + CJsonOverUTTPReader json_reader; + + try { + array read_buffer; + + do { + s_ReadSocket(sock, read_buffer, uttp_reader); + } while (!json_reader.ReadMessage(uttp_reader)); + } + catch (...) { + sock.Close(); + throw; + } + + if (uttp_reader.GetNextEvent() != CUTTPReader::eEndOfBuffer) { + string server_address(sock.GetPeerAddress()); + sock.Close(); + NCBI_THROW_FMT(CNetStorageException, eIOError, + "Extra bytes past message end while reading from " << + server_address << " after receiving " << + json_reader.GetMessage().Repr() << '.'); + } + + CJsonNode reply(json_reader.GetMessage()); + s_TrapErrors(request, reply, conn, err_mode, listener); + return reply; +} + +void s_SetStorageFlags(CJsonNode& node, TNetStorageFlags flags) +{ + CJsonNode storage_flags(CJsonNode::NewObjectNode()); + + if (flags & fNST_Fast) + storage_flags.SetBoolean("Fast", true); + if (flags & fNST_Persistent) + storage_flags.SetBoolean("Persistent", true); + if (flags & fNST_NetCache) + storage_flags.SetBoolean("NetCache", true); + if (flags & fNST_FileTrack) + storage_flags.SetBoolean("FileTrack", true); + if (flags & fNST_Movable) + storage_flags.SetBoolean("Movable", true); + if (flags & fNST_Cacheable) + storage_flags.SetBoolean("Cacheable", true); + if (flags & fNST_NoMetaData) + storage_flags.SetBoolean("NoMetaData", true); + + node.SetByKey("StorageFlags", storage_flags); +} + class CNetStorageServerListener : public INetServerConnectionListener { public: - CNetStorageServerListener(const CJsonNode& hello, - SNetStorage::SConfig::EErrMode err_mode) : + CNetStorageServerListener(const CJsonNode& hello, SNetStorage::SConfig::EErrMode err_mode) : m_Hello(hello), m_ErrMode(err_mode) { } - virtual CRef AllocServerProperties(); + CRef AllocServerProperties() override; - virtual void OnInit(CObject* api_impl, - CConfig* config, const string& config_section); - virtual void OnConnected(CNetServerConnection& connection); - virtual void OnError(const string& err_msg, CNetServer& server); - virtual void OnWarning(const string& warn_msg, CNetServer& server); + void OnInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections) override; + void OnConnected(CNetServerConnection& connection) override; + void OnError(const string& err_msg, CNetServer& server) override; + void OnWarning(const string& warn_msg, CNetServer& server) override; private: const CJsonNode m_Hello; @@ -458,147 +450,208 @@ CRef CNetStorageServerListener::AllocServerProperties() return CRef(new INetServerProperties); } -void CNetStorageServerListener::OnInit(CObject* /*api_impl*/, - CConfig* /*config*/, const string& /*config_section*/) +void CNetStorageServerListener::OnInit(CObject*, ISynRegistry&, SRegSynonyms&) { - //SNetStorageRPC* netstorage_rpc = static_cast(api_impl); } void CNetStorageServerListener::OnConnected( CNetServerConnection& connection) { - CSocket& sock(connection->m_Socket); - - CSendJsonOverSocket message_sender(sock); + CSendJsonOverSocket message_sender(connection->m_Socket); message_sender.SendMessage(m_Hello); - CReadJsonFromSocket message_reader; - - CJsonNode reply(message_reader.ReadMessage(sock)); - - s_TrapErrors(m_Hello, reply, sock, m_ErrMode); + s_ReadMessage(m_Hello, connection, m_ErrMode, *this); } -void CNetStorageServerListener::OnError(const string& /*err_msg*/, - CNetServer& /*server*/) +void CNetStorageServerListener::OnError(const string& err_msg, + CNetServer& server) { + LOG_POST(Error << "NetStorage server " << + server->m_ServerInPool->m_Address.AsString() << + " issued error " << err_msg); } void CNetStorageServerListener::OnWarning(const string& warn_msg, - CNetServer& /*server*/) + CNetServer& server) { + if (m_EventHandler) + m_EventHandler->OnWarning(warn_msg, server); + else { + LOG_POST(Warning << "NetStorage server " << + server->m_ServerInPool->m_Address.AsString() << + " issued warning " << warn_msg); + } } -struct SNetStorageObjectRPC : public SNetStorageObjectImpl +class CJsonOverUTTPExecHandler : public INetServerExecHandler { - enum EObjectIdentification { - eByGeneratedID, - eByUniqueKey - }; +public: + CJsonOverUTTPExecHandler(const CJsonNode& request) : m_Request(request) {} + + virtual void Exec(CNetServerConnection::TInstance conn_impl, + STimeout* timeout); + + CNetServerConnection GetConnection() const {return m_Connection;} + +private: + CJsonNode m_Request; + + CNetServerConnection m_Connection; +}; + +void CJsonOverUTTPExecHandler::Exec(CNetServerConnection::TInstance conn_impl, + STimeout* timeout) +{ + CTimeoutKeeper timeout_keeper(&conn_impl->m_Socket, timeout); + CSendJsonOverSocket sender(conn_impl->m_Socket); + + sender.SendMessage(m_Request); + + m_Connection = conn_impl; +} + +struct SNetStorageObjectRPC : public INetStorageObjectState +{ +private: + struct SContext + { + string locator; + const SNetStorage::SConfig::EErrMode m_ErrMode; + CRef m_Listener; + mutable CJsonNode m_OriginalRequest; + mutable CNetServerConnection m_Connection; + + SContext(SNetStorageRPC* netstorage_rpc, const string& object_loc) : + locator(object_loc), + m_ErrMode(netstorage_rpc->m_Config.err_mode), + m_Listener(netstorage_rpc->m_Service->m_Listener) + { + } - enum EState { - eReady, - eReading, - eWriting + void TrapErrors(const CJsonNode& reply) + { + s_TrapErrors(m_OriginalRequest, reply, m_Connection, m_ErrMode, *m_Listener); + } + + CJsonNode ReadMessage() + { + return s_ReadMessage(m_OriginalRequest, m_Connection, m_ErrMode, *m_Listener); + } }; - SNetStorageObjectRPC(SNetStorageRPC* netstorage_rpc, - CJsonNode::TInstance original_request, - CNetServerConnection::TInstance conn, - EObjectIdentification object_identification, - const string& object_loc_or_key, - TNetStorageFlags flags, - EState initial_state); + struct SIState : public SNetStorageObjectIState + { + ERW_Result Read(void* buf, size_t count, size_t* read) override; + ERW_Result PendingCount(size_t* count) override; + bool Eof() override; + + void Close() override; + void Abort() override; - virtual ~SNetStorageObjectRPC(); + string GetLoc() const override { return m_Context.locator; } - CJsonNode ExchangeUsingOwnService(const CJsonNode& request, - CNetServerConnection* conn = NULL, - CNetServer::TInstance server_to_use = NULL) const + void StartReading(); + + protected: + SIState(SContext& context) : m_Context(context) {} + + private: + void ReadConfirmation(); + void ReadSocket() { s_ReadSocket(m_Context.m_Connection->m_Socket, m_ReadBuffer, m_UTTPReader); } + + SContext& m_Context; + vector m_ReadBuffer; + CUTTPReader m_UTTPReader; + const char* m_CurrentChunk; + size_t m_CurrentChunkSize; + bool m_EOF; + }; + + struct SOState : public SNetStorageObjectOState { - return m_NetStorageRPC->Exchange(m_OwnService, - request, conn, server_to_use); - } + ERW_Result Write(const void* buf, size_t count, size_t* written) override; + ERW_Result Flush() override; - void ReadConfirmation(); - virtual ERW_Result Read(void* buf, size_t count, size_t* bytes_read); + void Close() override; + void Abort() override; - virtual ERW_Result Write(const void* buf, size_t count, - size_t* bytes_written); - virtual void Close(); + string GetLoc() const override { return m_Context.locator; } - virtual string GetLoc(); - virtual bool Eof(); - virtual Uint8 GetSize(); - virtual list GetAttributeList() const; - virtual string GetAttribute(const string& attr_name) const; - virtual void SetAttribute(const string& attr_name, - const string& attr_value); - virtual CNetStorageObjectInfo GetInfo(); - virtual void SetExpiration(const CTimeout&); + protected: + SOState(SContext& context) : m_Context(context) {} - string FileTrack_Path(); + private: + SContext& m_Context; + }; - CJsonNode x_MkRequest(const string& request_type) const; +public: + typedef function TBuilder; - CRef > m_NetStorageRPC; + SNetStorageObjectRPC(SNetStorageObjectImpl& fsm, SNetStorageRPC* netstorage_rpc, CNetService service, TBuilder builder, + const string& object_loc); - CNetService m_OwnService; + ERW_Result Read(void* buf, size_t count, size_t* bytes_read) override; + ERW_Result PendingCount(size_t* count) override; - CJsonNode m_OriginalRequest; - CNetServerConnection m_Connection; - char* m_ReadBuffer; - CUTTPReader m_UTTPReader; - const char* m_CurrentChunk; - size_t m_CurrentChunkSize; - EObjectIdentification m_ObjectIdentification; - string m_Locator; - string m_UniqueKey; - TNetStorageFlags m_Flags; - EState m_State; - bool m_EOF; -}; + ERW_Result Write(const void* buf, size_t count, size_t* bytes_written) override; + ERW_Result Flush() override; + void Close() override; + void Abort() override; -SNetStorageObjectRPC::SNetStorageObjectRPC(SNetStorageRPC* netstorage_rpc, - CJsonNode::TInstance original_request, - CNetServerConnection::TInstance conn, - EObjectIdentification object_identification, - const string& object_loc_or_key, - TNetStorageFlags flags, - EState initial_state) : - m_NetStorageRPC(netstorage_rpc), - m_OriginalRequest(original_request), - m_Connection(conn), - m_ReadBuffer(NULL), - m_ObjectIdentification(object_identification), - m_Flags(flags), - m_State(initial_state) -{ - if (object_identification == eByGeneratedID) { - m_OwnService = netstorage_rpc->GetServiceFromLocator(object_loc_or_key); - m_Locator = object_loc_or_key; - } else { - m_OwnService = netstorage_rpc->m_Service; - m_UniqueKey = object_loc_or_key; + string GetLoc() const override { return m_Context.locator; } + bool Eof() override; + Uint8 GetSize() override; + list GetAttributeList() const override; + string GetAttribute(const string& attr_name) const override; + void SetAttribute(const string& attr_name, const string& attr_value) override; + CNetStorageObjectInfo GetInfo() override; + void SetExpiration(const CTimeout&) override; + + string FileTrack_Path() override; + string Relocate(TNetStorageFlags flags, TNetStorageProgressCb cb) override; + bool Exists() override; + ENetStorageRemoveResult Remove() override; + + void StartWriting(CJsonNode::TInstance request, CNetServerConnection::TInstance conn); + +private: + CJsonNode Exchange() const + { + return m_NetStorageRPC->Exchange(m_OwnService, m_Context.m_OriginalRequest, &m_Context.m_Connection); } -} -SNetStorageObjectRPC::~SNetStorageObjectRPC() -{ - try { - Close(); + void MkRequest(const string& request_type) const + { + m_Context.m_OriginalRequest = m_Builder(request_type, m_Context.locator); } - NCBI_CATCH_ALL("Error while implicitly closing a NetStorage object."); - delete[] m_ReadBuffer; + CNetRef m_NetStorageRPC; + CNetService m_OwnService; + TBuilder m_Builder; + SContext m_Context; + SNetStorageObjectState m_IState; + SNetStorageObjectState m_OState; +}; + +void SNetStorageObjectRPC::StartWriting(CJsonNode::TInstance request, CNetServerConnection::TInstance conn) +{ + m_Context.m_OriginalRequest = request; + m_Context.m_Connection = conn; + EnterState(&m_OState); } -static const char* const s_NetStorageConfigSections[] = { - "netstorage_api", - NULL -}; + +SNetStorageObjectRPC::SNetStorageObjectRPC(SNetStorageObjectImpl& fsm, SNetStorageRPC* netstorage_rpc, CNetService service, + TBuilder builder, const string& object_loc) : + m_NetStorageRPC(netstorage_rpc), + m_OwnService(service), + m_Builder(builder), + m_Context(netstorage_rpc, object_loc), + m_IState(fsm, m_Context), + m_OState(fsm, m_Context) +{ +} SNetStorage::SConfig::EDefaultStorage SNetStorage::SConfig::GetDefaultStorage(const string& value) @@ -648,6 +701,10 @@ void SNetStorage::SConfig::ParseArg(const string& name, const string& value) client_name = value; else if (name == "err_mode") err_mode = GetErrMode(value); + else if (name == "ticket") + ticket = value; + else if (name == "hello_service") + hello_service = value; } void SNetStorage::SConfig::Validate(const string& init_string) @@ -703,22 +760,21 @@ void SNetStorage::SConfig::Validate(const string& init_string) default: /* eNoCreate */ break; } + + if (hello_service.empty()) hello_service = service; } SNetStorageRPC::SNetStorageRPC(const TConfig& config, TNetStorageFlags default_flags) : m_DefaultFlags(default_flags), m_Config(config) -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - , m_AllowXSiteConnections(false) -#endif { m_RequestNumber.Set(0); CJsonNode hello(MkStdRequest("HELLO")); hello.SetString("Client", m_Config.client_name); - hello.SetString("Service", m_Config.service); + hello.SetString("Service", m_Config.hello_service); if (!m_Config.metadata.empty()) hello.SetString("Metadata", m_Config.metadata); {{ @@ -728,15 +784,26 @@ SNetStorageRPC::SNetStorageRPC(const TConfig& config, hello.SetString("Application", app->GetProgramExecutablePath()); }} hello.SetString("ProtocolVersion", NST_PROTOCOL_VERSION); + if (!m_Config.ticket.empty()) hello.SetString("Ticket", m_Config.ticket); - m_Service = new SNetServiceImpl("NetStorageAPI", m_Config.client_name, + m_Service = new SNetServiceImpl("NetStorageAPI", m_Config.service, m_Config.client_name, new CNetStorageServerListener(hello, m_Config.err_mode)); - m_Service->Init(this, m_Config.service, - NULL, kEmptyStr, s_NetStorageConfigSections); + m_Service->Init(this, nullptr, "netstorage_api"); +} + +SNetStorageRPC::SNetStorageRPC(SNetServerInPool* server, + SNetStorageRPC* parent) : + m_DefaultFlags(parent->m_DefaultFlags), + m_Service(new SNetServiceImpl(server, parent->m_Service)), + m_Config(parent->m_Config), + m_CompoundIDPool(parent->m_CompoundIDPool), + m_NetCacheAPI(parent->m_NetCacheAPI), + m_ServiceMap(parent->m_ServiceMap) +{ } -CNetStorageObject SNetStorageRPC::Create(TNetStorageFlags flags) +SNetStorageObjectImpl* SNetStorageRPC::Create(TNetStorageFlags flags) { switch (m_Config.default_storage) { /* TConfig::eUndefined is overridden in the constructor */ @@ -746,7 +813,8 @@ CNetStorageObject SNetStorageRPC::Create(TNetStorageFlags flags) case TConfig::eNetCache: x_InitNetCacheAPI(); - return CDNCNetStorage::Create(m_NetCacheAPI); + return SNetStorageObjectImpl::CreateAndStart( + [&](SNetStorage_NetCacheBlob& s) { s.StartWriting(); }, m_NetCacheAPI, kEmptyStr); default: /* TConfig::eNoCreate */ NCBI_THROW_FMT(CNetStorageException, eAuthError, @@ -754,65 +822,78 @@ CNetStorageObject SNetStorageRPC::Create(TNetStorageFlags flags) } m_UseNextSubHitID.ProperCommand(); - CJsonNode request(MkStdRequest("CREATE")); - x_SetStorageFlags(request, GetFlags(flags)); + auto request = MkStdRequest("CREATE"); + s_SetStorageFlags(request, GetFlags(flags)); CNetServerConnection conn; + const auto reply = Exchange(m_Service, request, &conn); + const auto object_loc = reply.GetString("ObjectLoc"); + auto service = GetServiceIfLocator(object_loc); + auto builder = [this](const string& r, const string& l) { return MkObjectRequest(r, l); }; + auto starter = [&](SNetStorageObjectRPC& s) { s.StartWriting(request, conn); }; - string object_loc = Exchange(m_Service, - request, &conn).GetString("ObjectLoc"); - - return new SNetStorageObjectRPC(this, request, conn, - SNetStorageObjectRPC::eByGeneratedID, - object_loc, 0, SNetStorageObjectRPC::eWriting); + return SNetStorageObjectImpl::CreateAndStart(starter, this, service, builder, object_loc); } -CNetStorageObject SNetStorageRPC::Open(const string& object_loc) +SNetStorageObjectImpl* SNetStorageRPC::Open(const string& object_loc) { - if (x_NetCacheMode(object_loc)) - return CDNCNetStorage::Open(m_NetCacheAPI, object_loc); + auto service = GetServiceIfLocator(object_loc); - return new SNetStorageObjectRPC(this, NULL, NULL, - SNetStorageObjectRPC::eByGeneratedID, - object_loc, 0, SNetStorageObjectRPC::eReady); + if (!service) { + return SNetStorageObjectImpl::Create(m_NetCacheAPI, object_loc); + } + + auto builder = [this](const string& r, const string& l) { return MkObjectRequest(r, l); }; + + return SNetStorageObjectImpl::Create(this, service, builder, object_loc); } -string SNetStorageRPC::Relocate(const string& object_loc, - TNetStorageFlags flags, TNetStorageProgressCb /*cb*/) +string SNetStorageObjectRPC::Relocate(TNetStorageFlags flags, TNetStorageProgressCb cb) { - if (x_NetCacheMode(object_loc)) - NCBI_THROW_FMT(CNetStorageException, eNotSupported, object_loc << - ": Relocate for NetCache blobs is not implemented"); - - m_UseNextSubHitID.ProperCommand(); - CJsonNode request(MkObjectRequest("RELOCATE", object_loc)); + m_NetStorageRPC->m_UseNextSubHitID.ProperCommand(); + MkRequest("RELOCATE"); CJsonNode new_location(CJsonNode::NewObjectNode()); - x_SetStorageFlags(new_location, flags); + s_SetStorageFlags(new_location, flags); - request.SetByKey("NewLocation", new_location); + m_Context.m_OriginalRequest.SetByKey("NewLocation", new_location); - // TODO: CXX-8302 + // Always request progress report to avoid timing out on large objects + m_Context.m_OriginalRequest.SetBoolean("NeedProgressReport", true); - return Exchange(GetServiceFromLocator(object_loc), - request).GetString("ObjectLoc"); -} + CNetServer server(*m_OwnService.Iterate(CNetService::eRandomize)); -bool SNetStorageRPC::Exists(const string& object_loc) -{ - if (x_NetCacheMode(object_loc)) - try { - return m_NetCacheAPI.HasBlob(object_loc); + CJsonOverUTTPExecHandler json_over_uttp_sender(m_Context.m_OriginalRequest); + + server->TryExec(json_over_uttp_sender); + + m_Context.m_Connection = json_over_uttp_sender.GetConnection(); + + for (;;) { + CJsonNode reply(m_Context.ReadMessage()); + CJsonNode object_loc(reply.GetByKeyOrNull("ObjectLoc")); + + if (object_loc) return object_loc.AsString(); + + CJsonNode progress_info(reply.GetByKeyOrNull("ProgressInfo")); + + if (progress_info) { + if (cb) cb(progress_info); + } else { + NCBI_THROW_FMT(CNetStorageException, eServerError, "Unexpected JSON received: " << reply.Repr()); } - NETSTORAGE_CONVERT_NETCACHEEXCEPTION("on accessing " + object_loc) + } +} - CJsonNode request(MkObjectRequest("EXISTS", object_loc)); +bool SNetStorageObjectRPC::Exists() +{ + MkRequest("EXISTS"); try { - return Exchange(GetServiceFromLocator(object_loc), - request).GetBoolean("Exists"); + const auto reply = Exchange(); + return reply.GetBoolean("Exists"); } catch (CNetStorageException& e) { if (e.GetErrCode() != CNetStorageException::eExpired) throw; @@ -821,26 +902,14 @@ bool SNetStorageRPC::Exists(const string& object_loc) return false; } -ENetStorageRemoveResult SNetStorageRPC::Remove(const string& object_loc) +ENetStorageRemoveResult SNetStorageObjectRPC::Remove() { - if (x_NetCacheMode(object_loc)) { - try { - if (m_NetCacheAPI.HasBlob(object_loc)) { - m_NetCacheAPI.Remove(object_loc); - return eNSTRR_Removed; - } - } - NETSTORAGE_CONVERT_NETCACHEEXCEPTION("on removing " + object_loc) - - return eNSTRR_NotFound; - } - - m_UseNextSubHitID.ProperCommand(); - CJsonNode request(MkObjectRequest("DELETE", object_loc)); + m_NetStorageRPC->m_UseNextSubHitID.ProperCommand(); + MkRequest("DELETE"); try { - CJsonNode response(Exchange(GetServiceFromLocator(object_loc), request)); - CJsonNode not_found(response.GetByKeyOrNull("NotFound")); + const auto reply = Exchange(); + const auto not_found = reply.GetByKeyOrNull("NotFound"); return not_found && not_found.AsBoolean() ? eNSTRR_NotFound : eNSTRR_Removed; } @@ -851,35 +920,9 @@ ENetStorageRemoveResult SNetStorageRPC::Remove(const string& object_loc) return eNSTRR_NotFound; } -class CJsonOverUTTPExecHandler : public INetServerExecHandler -{ -public: - CJsonOverUTTPExecHandler(const CJsonNode& request) : m_Request(request) {} - - virtual void Exec(CNetServerConnection::TInstance conn_impl, - STimeout* timeout); - - CNetServerConnection GetConnection() const {return m_Connection;} - -private: - CJsonNode m_Request; - - CNetServerConnection m_Connection; -}; - -void CJsonOverUTTPExecHandler::Exec(CNetServerConnection::TInstance conn_impl, - STimeout* timeout) -{ - CSendJsonOverSocket sender(conn_impl->m_Socket); - - sender.SendMessage(m_Request); - - m_Connection = conn_impl; -} - CJsonNode SNetStorageRPC::Exchange(CNetService service, const CJsonNode& request, - CNetServerConnection* conn, + CNetServerConnection* pconn, CNetServer::TInstance server_to_use) const { CNetServer server(server_to_use != NULL ? server_to_use : @@ -890,40 +933,11 @@ CJsonNode SNetStorageRPC::Exchange(CNetService service, server->TryExec(json_over_uttp_sender); - CReadJsonFromSocket message_reader; + CNetServerConnection conn(json_over_uttp_sender.GetConnection()); - if (conn != NULL) - *conn = json_over_uttp_sender.GetConnection(); + if (pconn) *pconn = conn; - CSocket& sock = json_over_uttp_sender.GetConnection()->m_Socket; - - CJsonNode reply(message_reader.ReadMessage(sock)); - - s_TrapErrors(request, reply, sock, m_Config.err_mode); - - return reply; -} - -void SNetStorageRPC::x_SetStorageFlags(CJsonNode& node, TNetStorageFlags flags) -{ - CJsonNode storage_flags(CJsonNode::NewObjectNode()); - - if (flags & fNST_Fast) - storage_flags.SetBoolean("Fast", true); - if (flags & fNST_Persistent) - storage_flags.SetBoolean("Persistent", true); - if (flags & fNST_NetCache) - storage_flags.SetBoolean("NetCache", true); - if (flags & fNST_FileTrack) - storage_flags.SetBoolean("FileTrack", true); - if (flags & fNST_Movable) - storage_flags.SetBoolean("Movable", true); - if (flags & fNST_Cacheable) - storage_flags.SetBoolean("Cacheable", true); - if (flags & fNST_NoMetaData) - storage_flags.SetBoolean("NoMetaData", true); - - node.SetByKey("StorageFlags", storage_flags); + return s_ReadMessage(request, conn, m_Config.err_mode, *service->m_Listener); } CJsonNode SNetStorageRPC::MkStdRequest(const string& request_type) const @@ -943,14 +957,10 @@ CJsonNode SNetStorageRPC::MkStdRequest(const string& request_type) const new_request.SetString("SessionID", req.GetSessionID()); } - // TODO: - // Remove sending this after all NetStorage servers are updated to v2.2.0 - // (ncbi_phid is sent inside ncbi_context). - // GetNextSubHitID()/GetCurrentSubHitID()) must be still called though - // (without using returned value) to set appropriate value for ncbi_phid. - if (req.IsSetHitID()) { - new_request.SetString("ncbi_phid", m_UseNextSubHitID ? - req.GetNextSubHitID() : req.GetCurrentSubHitID()); + if (m_UseNextSubHitID) { + req.GetNextSubHitID(); + } else { + req.GetCurrentSubHitID(); } const auto format = CRequestContext_PassThrough::eFormat_UrlEncoded; @@ -984,289 +994,221 @@ CJsonNode SNetStorageRPC::MkObjectRequest(const string& request_type, user_key.SetString("UniqueID", unique_key); new_request.SetByKey("UserKey", user_key); - x_SetStorageFlags(new_request, GetFlags(flags)); + s_SetStorageFlags(new_request, GetFlags(flags)); return new_request; } -void SNetStorageRPC::x_InitNetCacheAPI() +CNetService SNetStorageRPC::GetServiceIfLocator(const string& object_loc) { - if (!m_NetCacheAPI) { - CNetCacheAPI nc_api(m_Config.nc_service, m_Config.client_name); - nc_api.SetCompoundIDPool(m_CompoundIDPool); - nc_api.SetDefaultParameters(nc_use_compound_id = true); + const bool direct_nc = m_Config.default_storage == TConfig::eNetCache; + auto IsBlobID = [&]() { return CNetCacheKey::ParseBlobKey(object_loc.data(), object_loc.length(), nullptr); }; -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - if (m_AllowXSiteConnections) { - nc_api.GetService().AllowXSiteConnections(); - } -#endif + if (direct_nc && IsBlobID()) return x_InitNetCacheAPI(); - m_NetCacheAPI = nc_api; + CCompoundID cid; + + try { + cid = m_CompoundIDPool.FromString(object_loc); } -} + catch (...) { + if (!direct_nc && IsBlobID()) return x_InitNetCacheAPI(); -bool SNetStorageRPC::x_NetCacheMode(const string& object_loc) -{ - if (!CNetCacheKey::ParseBlobKey(object_loc.data(), object_loc.length(), - NULL, m_CompoundIDPool)) - return false; + throw; + } - x_InitNetCacheAPI(); - return true; -} + if (cid.GetClass() == eCIC_NetCacheBlobKey) return x_InitNetCacheAPI(); -string SNetStorageObjectRPC::GetLoc() -{ - return m_Locator; -} + string service_name = CNetStorageObjectLoc::GetServiceName(cid); -void SNetStorageObjectRPC::ReadConfirmation() -{ - CSocket& sock = m_Connection->m_Socket; + if (service_name.empty()) + return m_Service; - CJsonOverUTTPReader json_reader; - try { - size_t bytes_read; + auto i = m_ServiceMap.find(service_name); - while (!json_reader.ReadMessage(m_UTTPReader)) { - s_ReadSocket(sock, m_ReadBuffer, - READ_BUFFER_SIZE, &bytes_read); + if (i != m_ServiceMap.end()) return i->second; - m_UTTPReader.SetNewBuffer(m_ReadBuffer, bytes_read); - } + CNetService service(m_Service.Clone(service_name)); + m_ServiceMap.insert(make_pair(service_name, service)); + return service; +} - if (m_UTTPReader.GetNextEvent() != CUTTPReader::eEndOfBuffer) { - NCBI_THROW_FMT(CNetStorageException, eIOError, - "Extra bytes past confirmation message " - "while reading " << m_Locator << " from " << - sock.GetPeerAddress() << '.'); - } - } - catch (...) { - m_UTTPReader.Reset(); - m_Connection->Close(); - throw; +EVoid SNetStorageRPC::x_InitNetCacheAPI() +{ + if (!m_NetCacheAPI) { + CNetCacheAPI nc_api(m_Config.nc_service, m_Config.client_name); + nc_api.SetCompoundIDPool(m_CompoundIDPool); + nc_api.SetDefaultParameters(nc_use_compound_id = true); + m_NetCacheAPI = nc_api; } - s_TrapErrors(m_OriginalRequest, json_reader.GetMessage(), sock, - m_NetStorageRPC->m_Config.err_mode); + return eVoid; } -ERW_Result SNetStorageObjectRPC::Read(void* buffer, size_t buf_size, - size_t* bytes_read) +void SNetStorageObjectRPC::SIState::ReadConfirmation() { - if (m_State == eWriting) { - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot read a NetStorage file while writing to it"); + if (m_UTTPReader.GetControlSymbol() != END_OF_DATA_MARKER) { + NCBI_THROW_FMT(CNetStorageException, eIOError, + "NetStorage API: invalid end-of-data-stream terminator: " << (int) m_UTTPReader.GetControlSymbol()); } - size_t bytes_read_local; - - if (m_State == eReady) { - m_OriginalRequest = x_MkRequest("READ"); + m_EOF = true; - if (m_ReadBuffer == NULL) - m_ReadBuffer = new char[READ_BUFFER_SIZE]; - - CNetServer server(*m_OwnService.Iterate(CNetService::eRandomize)); + CJsonOverUTTPReader json_reader; - CJsonOverUTTPExecHandler json_over_uttp_sender(m_OriginalRequest); + while (!json_reader.ReadMessage(m_UTTPReader)) { + ReadSocket(); + } - server->TryExec(json_over_uttp_sender); + if (m_UTTPReader.GetNextEvent() != CUTTPReader::eEndOfBuffer) { + NCBI_THROW_FMT(CNetStorageException, eIOError, + "Extra bytes past confirmation message " + "while reading " << m_Context.locator << " from " << + m_Context.m_Connection->m_Socket.GetPeerAddress() << '.'); + } - CSocket& sock = json_over_uttp_sender.GetConnection()->m_Socket; + m_Context.TrapErrors(json_reader.GetMessage()); +} - CJsonOverUTTPReader json_reader; +ERW_Result SNetStorageObjectRPC::Read(void* buffer, size_t buf_size, + size_t* bytes_read) +{ + MkRequest("READ"); - try { - do { - s_ReadSocket(sock, m_ReadBuffer, READ_BUFFER_SIZE, - &bytes_read_local); + CNetServer server(*m_OwnService.Iterate(CNetService::eRandomize)); - m_UTTPReader.SetNewBuffer(m_ReadBuffer, bytes_read_local); + CJsonOverUTTPExecHandler json_over_uttp_sender(m_Context.m_OriginalRequest); - } while (!json_reader.ReadMessage(m_UTTPReader)); - } - catch (...) { - m_UTTPReader.Reset(); - sock.Close(); - throw; - } + server->TryExec(json_over_uttp_sender); - s_TrapErrors(m_OriginalRequest, json_reader.GetMessage(), sock, - m_NetStorageRPC->m_Config.err_mode); + EnterState(&m_IState); + m_Context.m_Connection = json_over_uttp_sender.GetConnection(); + m_IState.StartReading(); - m_Connection = json_over_uttp_sender.GetConnection(); + return m_IState.Read(buffer, buf_size, bytes_read); +} - m_CurrentChunkSize = 0; +void SNetStorageObjectRPC::SIState::StartReading() +{ + m_ReadBuffer = vector(READ_BUFFER_SIZE); + m_UTTPReader.Reset(); + m_CurrentChunk = nullptr; + m_CurrentChunkSize = 0; + m_EOF = false; - m_State = eReading; - m_EOF = false; - } + CJsonOverUTTPReader json_reader; - char* buf_pos = reinterpret_cast(buffer); + try { + do { + ReadSocket(); + } while (!json_reader.ReadMessage(m_UTTPReader)); - if (m_CurrentChunkSize >= buf_size) { - if (buf_size > 0) { - memcpy(buf_pos, m_CurrentChunk, buf_size); - m_CurrentChunk += buf_size; - m_CurrentChunkSize -= buf_size; - } - if (bytes_read != NULL) - *bytes_read = buf_size; - return eRW_Success; + m_Context.TrapErrors(json_reader.GetMessage()); } - - if (m_CurrentChunkSize > 0) { - memcpy(buf_pos, m_CurrentChunk, m_CurrentChunkSize); - buf_pos += m_CurrentChunkSize; - buf_size -= m_CurrentChunkSize; + catch (...) { + Abort(); + throw; } +} - size_t bytes_copied = m_CurrentChunkSize; +ERW_Result SNetStorageObjectRPC::SIState::Read(void* buf_pos, size_t buf_size, size_t* bytes_read) +{ + if (bytes_read) *bytes_read = 0; - m_CurrentChunkSize = 0; + if (!m_CurrentChunkSize && m_EOF) return eRW_Eof; - if (m_EOF) { - if (bytes_read != NULL) - *bytes_read = bytes_copied; - return bytes_copied ? eRW_Success : eRW_Eof; - } + if (!buf_size) return eRW_Success; try { - while (buf_size > 0) { + while (!m_CurrentChunkSize) { switch (m_UTTPReader.GetNextEvent()) { case CUTTPReader::eChunkPart: case CUTTPReader::eChunk: m_CurrentChunk = m_UTTPReader.GetChunkPart(); m_CurrentChunkSize = m_UTTPReader.GetChunkPartSize(); - - if (m_CurrentChunkSize >= buf_size) { - memcpy(buf_pos, m_CurrentChunk, buf_size); - m_CurrentChunk += buf_size; - m_CurrentChunkSize -= buf_size; - if (bytes_read != NULL) - *bytes_read = bytes_copied + buf_size; - return eRW_Success; - } - - memcpy(buf_pos, m_CurrentChunk, m_CurrentChunkSize); - buf_pos += m_CurrentChunkSize; - buf_size -= m_CurrentChunkSize; - bytes_copied += m_CurrentChunkSize; - m_CurrentChunkSize = 0; - break; + continue; case CUTTPReader::eControlSymbol: - if (m_UTTPReader.GetControlSymbol() != END_OF_DATA_MARKER) { - NCBI_THROW_FMT(CNetStorageException, eIOError, - "NetStorage API: invalid end-of-data-stream " - "terminator: " << - (int) m_UTTPReader.GetControlSymbol()); - } - m_EOF = true; ReadConfirmation(); - if (bytes_read != NULL) - *bytes_read = bytes_copied; - return bytes_copied ? eRW_Success : eRW_Eof; + return eRW_Eof; case CUTTPReader::eEndOfBuffer: - s_ReadSocket(m_Connection->m_Socket, m_ReadBuffer, - READ_BUFFER_SIZE, &bytes_read_local); - - m_UTTPReader.SetNewBuffer(m_ReadBuffer, bytes_read_local); - break; + ReadSocket(); + continue; default: NCBI_THROW_FMT(CNetStorageException, eIOError, "NetStorage API: invalid UTTP status " - "while reading " << m_Locator); + "while reading " << m_Context.locator); } } - - if (bytes_read != NULL) - *bytes_read = bytes_copied; - return eRW_Success; } catch (...) { - m_State = eReady; - m_UTTPReader.Reset(); - m_Connection->Close(); - m_Connection = NULL; + Abort(); throw; } + + if (auto bytes_copied = min(m_CurrentChunkSize, buf_size)) { + memcpy(buf_pos, m_CurrentChunk, bytes_copied); + m_CurrentChunk += bytes_copied; + m_CurrentChunkSize -= bytes_copied; + + if (bytes_read) *bytes_read = bytes_copied; + } + + return eRW_Success; } bool SNetStorageObjectRPC::Eof() { - switch (m_State) { - case eReady: return false; +} - case eReading: - return m_CurrentChunkSize == 0 && m_EOF; - - default: /* case eWriting: */ - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot read a NetStorage file while writing"); - } +bool SNetStorageObjectRPC::SIState::Eof() +{ + return m_CurrentChunkSize == 0 && m_EOF; } ERW_Result SNetStorageObjectRPC::Write(const void* buf_pos, size_t buf_size, size_t* bytes_written) { - if (m_State == eReading) { - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot write a NetStorage file while reading"); - } - - if (m_State == eReady) { - m_NetStorageRPC->m_UseNextSubHitID.ProperCommand(); - m_OriginalRequest = x_MkRequest("WRITE"); + m_NetStorageRPC->m_UseNextSubHitID.ProperCommand(); + MkRequest("WRITE"); - m_Locator = ExchangeUsingOwnService(m_OriginalRequest, - &m_Connection).GetString("ObjectLoc"); + m_Context.locator = Exchange().GetString("ObjectLoc"); - m_State = eWriting; - } + EnterState(&m_OState); + return m_OState.Write(buf_pos, buf_size, bytes_written); +} +ERW_Result SNetStorageObjectRPC::SOState::Write(const void* buf_pos, size_t buf_size, size_t* bytes_written) +{ try { - s_SendUTTPChunk(reinterpret_cast(buf_pos), - buf_size, m_Connection->m_Socket); + const char* chunk = reinterpret_cast(buf_pos); + auto f = [&](CUTTPWriter& w) { w.SendChunk(chunk, buf_size, false); }; + s_SendUTTP(m_Context.m_Connection->m_Socket, f); + if (bytes_written != NULL) *bytes_written = buf_size; return eRW_Success; } catch (exception&) { - m_State = eReady; - m_Connection->Close(); - m_Connection = NULL; + Abort(); throw; } } Uint8 SNetStorageObjectRPC::GetSize() { - if (m_State != eReady) { - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot get object size while reading or writing"); - } - - CJsonNode request(x_MkRequest("GETSIZE")); + MkRequest("GETSIZE"); - return (Uint8) ExchangeUsingOwnService(request).GetInteger("Size"); + return (Uint8) Exchange().GetInteger("Size"); } list SNetStorageObjectRPC::GetAttributeList() const { - if (m_State != eReady) { - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot get object attribute while reading or writing"); - } - - CJsonNode request(x_MkRequest("GETATTRLIST")); + MkRequest("GETATTRLIST"); - CJsonNode reply(ExchangeUsingOwnService(request)); + CJsonNode reply(Exchange()); CJsonNode names(reply.GetByKeyOrNull("AttributeNames")); list result; @@ -1281,149 +1223,119 @@ list SNetStorageObjectRPC::GetAttributeList() const string SNetStorageObjectRPC::GetAttribute(const string& attr_name) const { - if (m_State != eReady) { - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot get object attribute while reading or writing"); - } + MkRequest("GETATTR"); - CJsonNode request(x_MkRequest("GETATTR")); + m_Context.m_OriginalRequest.SetString("AttrName", attr_name); - request.SetString("AttrName", attr_name); - - return ExchangeUsingOwnService(request).GetString("AttrValue"); + return Exchange().GetString("AttrValue"); } void SNetStorageObjectRPC::SetAttribute(const string& attr_name, const string& attr_value) { - if (m_State != eReady) { - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot set object attribute while reading or writing"); - } - - CJsonNode request(x_MkRequest("SETATTR")); + MkRequest("SETATTR"); - request.SetString("AttrName", attr_name); - request.SetString("AttrValue", attr_value); + m_Context.m_OriginalRequest.SetString("AttrName", attr_name); + m_Context.m_OriginalRequest.SetString("AttrValue", attr_value); - ExchangeUsingOwnService(request); + Exchange(); } CNetStorageObjectInfo SNetStorageObjectRPC::GetInfo() { - if (m_State != eReady) { - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot get object info while reading or writing"); - } - - CJsonNode request(x_MkRequest("GETOBJECTINFO")); + MkRequest("GETOBJECTINFO"); - return g_CreateNetStorageObjectInfo( - ExchangeUsingOwnService(request)); + return g_CreateNetStorageObjectInfo(Exchange()); } void SNetStorageObjectRPC::SetExpiration(const CTimeout& ttl) { - if (m_State != eReady) { - NCBI_THROW_FMT(CNetStorageException, eInvalidArg, - "Cannot set expiration while reading or writing"); - } + MkRequest("SETEXPTIME"); - CJsonNode request(x_MkRequest("SETEXPTIME")); - - if (ttl.IsFinite()) { - request.SetString("TTL", ttl.GetAsTimeSpan().AsString("dTh:m:s")); - } else { - request.SetString("TTL", "infinity"); - } + const auto ttl_str = ttl.IsFinite() ? ttl.GetAsTimeSpan().AsString("dTh:m:s") : "infinity"; + m_Context.m_OriginalRequest.SetString("TTL", ttl_str); - ExchangeUsingOwnService(request); + Exchange(); } string SNetStorageObjectRPC::FileTrack_Path() { - CJsonNode request(x_MkRequest("LOCKFTPATH")); + MkRequest("LOCKFTPATH"); - return ExchangeUsingOwnService(request).GetString("Path"); + return Exchange().GetString("Path"); } -void SNetStorageObjectRPC::Close() +struct SConnReset { - if (m_State == eReady) - return; - - CNetServerConnection conn_copy(m_Connection); - m_Connection = NULL; - - if (m_State == eReading) { - m_State = eReady; + CNetServerConnection& conn; + SConnReset(CNetServerConnection& c) : conn(c) {} + ~SConnReset() { conn = nullptr; } +}; - if (!m_EOF) { - m_UTTPReader.Reset(); - conn_copy->Close(); - } - } else { /* m_State == eWriting */ - m_State = eReady; +void SNetStorageObjectRPC::SIState::Close() +{ + SConnReset conn_reset(m_Context.m_Connection); - CSocket& sock = conn_copy->m_Socket; + ExitState(); + m_UTTPReader.Reset(); +} - s_SendEndOfData(sock); +void SNetStorageObjectRPC::SOState::Close() +{ + SConnReset conn_reset(m_Context.m_Connection); - CReadJsonFromSocket message_reader; + ExitState(); - s_TrapErrors(m_OriginalRequest, - message_reader.ReadMessage(sock), sock, - m_NetStorageRPC->m_Config.err_mode); - } + auto f = [](CUTTPWriter& w) { w.SendControlSymbol(END_OF_DATA_MARKER); }; + s_SendUTTP(m_Context.m_Connection->m_Socket, f); + m_Context.ReadMessage(); } -CJsonNode SNetStorageObjectRPC::x_MkRequest(const string& request_type) const +void SNetStorageObjectRPC::Close() { - if (m_ObjectIdentification == eByGeneratedID) - return m_NetStorageRPC->MkObjectRequest(request_type, m_Locator); - else - return m_NetStorageRPC->MkObjectRequest(request_type, - m_UniqueKey, m_Flags); } -ERW_Result SNetStorageObjectImpl::PendingCount(size_t* count) +ERW_Result SNetStorageObjectRPC::SIState::PendingCount(size_t* count) { *count = 0; return eRW_Success; } -ERW_Result SNetStorageObjectImpl::Flush() +ERW_Result SNetStorageObjectRPC::PendingCount(size_t* count) { + *count = 0; return eRW_Success; } -void SNetStorageObjectImpl::Abort() +ERW_Result SNetStorageObjectRPC::SOState::Flush() { - Close(); + return eRW_Success; } -IReader& SNetStorageObjectImpl::GetReader() +ERW_Result SNetStorageObjectRPC::Flush() { - return *this; + return eRW_Success; } -IEmbeddedStreamWriter& SNetStorageObjectImpl::GetWriter() +void SNetStorageObjectRPC::SIState::Abort() { - return *this; + SConnReset conn_reset(m_Context.m_Connection); + + ExitState(); + m_UTTPReader.Reset(); + m_Context.m_Connection->Close(); } -void SNetStorageObjectImpl::Read(string* data) +void SNetStorageObjectRPC::SOState::Abort() { - char buffer[READ_CHUNK_SIZE]; + SConnReset conn_reset(m_Context.m_Connection); - data->resize(0); - size_t bytes_read; - - do { - Read(buffer, sizeof(buffer), &bytes_read); - data->append(buffer, bytes_read); - } while (!Eof()); + ExitState(); + m_Context.m_Connection->Close(); +} +void SNetStorageObjectRPC::Abort() +{ Close(); } @@ -1432,21 +1344,9 @@ struct SNetStorageByKeyRPC : public SNetStorageByKeyImpl SNetStorageByKeyRPC(const TConfig& config, TNetStorageFlags default_flags); - virtual CNetStorageObject Open(const string& unique_key, - TNetStorageFlags flags); - virtual string Relocate(const string& unique_key, - TNetStorageFlags flags, TNetStorageFlags old_flags, - TNetStorageProgressCb cb); - virtual bool Exists(const string& key, TNetStorageFlags flags); - virtual ENetStorageRemoveResult Remove(const string& key, - TNetStorageFlags flags); - -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - void AllowXSiteConnections() { m_NetStorageRPC->AllowXSiteConnections(); } -#endif - - CRef > m_NetStorageRPC; + SNetStorageObjectImpl* Open(const string& unique_key, TNetStorageFlags flags) override; + + CNetRef m_NetStorageRPC; }; SNetStorageByKeyRPC::SNetStorageByKeyRPC(const TConfig& config, @@ -1459,68 +1359,15 @@ SNetStorageByKeyRPC::SNetStorageByKeyRPC(const TConfig& config, } } -CNetStorageObject SNetStorageByKeyRPC::Open(const string& unique_key, +SNetStorageObjectImpl* SNetStorageByKeyRPC::Open(const string& unique_key, TNetStorageFlags flags) { - return new SNetStorageObjectRPC(m_NetStorageRPC, NULL, NULL, - SNetStorageObjectRPC::eByUniqueKey, - unique_key, flags, SNetStorageObjectRPC::eReady); -} - -string SNetStorageByKeyRPC::Relocate(const string& unique_key, - TNetStorageFlags flags, TNetStorageFlags old_flags, - TNetStorageProgressCb /*cb*/) -{ - m_NetStorageRPC->m_UseNextSubHitID.ProperCommand(); - CJsonNode request(m_NetStorageRPC->MkObjectRequest( - "RELOCATE", unique_key, old_flags)); - - CJsonNode new_location(CJsonNode::NewObjectNode()); - - SNetStorageRPC::x_SetStorageFlags(new_location, flags); - - request.SetByKey("NewLocation", new_location); - - // TODO: CXX-8302 - - return m_NetStorageRPC->Exchange(m_NetStorageRPC->m_Service, - request).GetString("ObjectLoc"); -} - -bool SNetStorageByKeyRPC::Exists(const string& key, TNetStorageFlags flags) -{ - CJsonNode request(m_NetStorageRPC->MkObjectRequest("EXISTS", key, flags)); - - try { - return m_NetStorageRPC->Exchange(m_NetStorageRPC->m_Service, - request).GetBoolean("Exists"); - } - catch (CNetStorageException& e) { - if (e.GetErrCode() != CNetStorageException::eExpired) throw; - } - - return false; -} - -ENetStorageRemoveResult SNetStorageByKeyRPC::Remove(const string& key, - TNetStorageFlags flags) -{ - m_NetStorageRPC->m_UseNextSubHitID.ProperCommand(); - CJsonNode request(m_NetStorageRPC->MkObjectRequest("DELETE", key, flags)); - - try { - CJsonNode response( - m_NetStorageRPC->Exchange(m_NetStorageRPC->m_Service, request)); - - CJsonNode not_found(response.GetByKeyOrNull("NotFound")); - - return not_found && not_found.AsBoolean() ? eNSTRR_NotFound : eNSTRR_Removed; - } - catch (CNetStorageException& e) { - if (e.GetErrCode() != CNetStorageException::eExpired) throw; - } + auto& rpc = m_NetStorageRPC; + auto builder = [=](const string& r, const string&) { + return rpc->MkObjectRequest(r, unique_key, flags); + }; - return eNSTRR_NotFound; + return SNetStorageObjectImpl::Create(rpc, rpc->m_Service, builder, kEmptyStr); } struct SNetStorageAdminImpl : public CObject @@ -1530,8 +1377,7 @@ struct SNetStorageAdminImpl : public CObject { } - CRef > m_NetStorageRPC; + CNetRef m_NetStorageRPC; }; CNetStorageAdmin::CNetStorageAdmin(CNetStorage::TInstance netstorage_impl) : @@ -1556,6 +1402,21 @@ CJsonNode CNetStorageAdmin::ExchangeJson(const CJsonNode& request, request, conn, server_to_use); } +CNetStorageAdmin CNetStorageAdmin::GetServer(CNetServer::TInstance server) +{ + return new SNetStorageRPC(server->m_ServerInPool, m_Impl->m_NetStorageRPC); +} + +void CNetStorageAdmin::SetEventHandler(INetEventHandler* event_handler) +{ + m_Impl->m_NetStorageRPC->m_Service->SetEventHandler(event_handler); +} + +CNetStorageObject CNetStorageAdmin::Open(const string& object_loc) +{ + return m_Impl->m_NetStorageRPC->Open(object_loc); +} + SNetStorageImpl* SNetStorage::CreateImpl(const SConfig& config, TNetStorageFlags default_flags) { diff --git a/c++/src/connect/services/netstorage_rpc.hpp b/c++/src/connect/services/netstorage_rpc.hpp index 83c2a699..36e4725f 100644 --- a/c++/src/connect/services/netstorage_rpc.hpp +++ b/c++/src/connect/services/netstorage_rpc.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES__NETSTORAGE_RPC__HPP #define CONNECT_SERVICES__NETSTORAGE_RPC__HPP -/* $Id: netstorage_rpc.hpp 505978 2016-06-30 15:57:38Z sadyrovr $ +/* $Id: netstorage_rpc.hpp 528688 2017-02-24 15:08:31Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -43,43 +43,24 @@ BEGIN_NCBI_SCOPE struct SNetStorageRPC : public SNetStorageImpl { SNetStorageRPC(const TConfig& config, TNetStorageFlags default_flags); + SNetStorageRPC(SNetServerInPool* server, SNetStorageRPC* parent); - virtual CNetStorageObject Create(TNetStorageFlags flags); - virtual CNetStorageObject Open(const string& object_loc); - virtual string Relocate(const string& object_loc, TNetStorageFlags flags, - TNetStorageProgressCb cb); - virtual bool Exists(const string& object_loc); - virtual ENetStorageRemoveResult Remove(const string& object_loc); + SNetStorageObjectImpl* Create(TNetStorageFlags flags) override; + SNetStorageObjectImpl* Open(const string& object_loc) override; CJsonNode Exchange(CNetService service, const CJsonNode& request, CNetServerConnection* conn = NULL, CNetServer::TInstance server_to_use = NULL) const; - static void x_SetStorageFlags(CJsonNode& node, TNetStorageFlags flags); CJsonNode MkStdRequest(const string& request_type) const; CJsonNode MkObjectRequest(const string& request_type, const string& object_loc) const; CJsonNode MkObjectRequest(const string& request_type, const string& unique_key, TNetStorageFlags flags) const; - void x_InitNetCacheAPI(); - bool x_NetCacheMode(const string& object_loc); + EVoid x_InitNetCacheAPI(); - CNetService GetServiceFromLocator(const string& object_loc) - { - CNetStorageObjectLoc locator_struct(m_CompoundIDPool, object_loc); - string service_name = locator_struct.GetServiceName(); - - if (service_name.empty()) - return m_Service; - - // Clone will return itself if it has the same name and - // insert would not do anything if such entry already exists, - // so no need to check for existence. - CNetService service(m_Service.Clone(service_name)); - m_ServiceMap.insert(make_pair(service_name, service)); - return service; - } + CNetService GetServiceIfLocator(const string& object_loc); TNetStorageFlags GetFlags(TNetStorageFlags flags) const { @@ -104,18 +85,6 @@ public: private: map m_ServiceMap; - -public: -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - void AllowXSiteConnections() - { - m_AllowXSiteConnections = true; - m_Service.AllowXSiteConnections(); - if (m_NetCacheAPI) m_NetCacheAPI.GetService().AllowXSiteConnections(); - } - - bool m_AllowXSiteConnections; -#endif }; END_NCBI_SCOPE diff --git a/c++/src/connect/services/netstorageobjectinfo.cpp b/c++/src/connect/services/netstorageobjectinfo.cpp index 672d0fe7..f6c22309 100644 --- a/c++/src/connect/services/netstorageobjectinfo.cpp +++ b/c++/src/connect/services/netstorageobjectinfo.cpp @@ -1,4 +1,4 @@ -/* $Id: netstorageobjectinfo.cpp 516423 2016-10-13 14:58:14Z sadyrovr $ +/* $Id: netstorageobjectinfo.cpp 515524 2016-10-03 15:27:20Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -43,7 +43,6 @@ struct SData { TLocation location; string object_loc; - string object_key; CJsonNode object_loc_info; Uint8 file_size; CJsonNode st_info; @@ -51,13 +50,11 @@ struct SData SData() {} SData(TLocation l, const string& ol, - const string& ok, CJsonNode::TInstance li, Uint8 fs, CJsonNode::TInstance si) : location(l), object_loc(ol), - object_key(ok), object_loc_info(li), file_size(fs), st_info(si) @@ -171,7 +168,6 @@ void SLazyInitData::InitData() const string l(json.GetString("Location")); CJsonNode ol(json.GetByKeyOrNull("ObjectLoc")); - CJsonNode ok(json.GetByKeyOrNull("ObjectKey")); CJsonNode size(json.GetByKeyOrNull("Size")); location = @@ -179,7 +175,6 @@ void SLazyInitData::InitData() l == "FileTrack" ? eNFL_FileTrack : l == "NotFound" ? eNFL_NotFound : eNFL_Unknown; object_loc = ol ? ol.AsString() : kEmptyStr; - object_key = ok ? ol.AsString() : kEmptyStr; object_loc_info = json.GetByKey("ObjectLocInfo"); file_size = size ? (Uint8) size.AsInteger() : 0; st_info = json.GetByKeyOrNull("StorageSpecificInfo"); @@ -229,9 +224,6 @@ void SLazyInitData::InitJson() json.SetString("ObjectLoc", object_loc); - if (!object_key.empty()) - json.SetString("ObjectKey", object_key); - if (object_loc_info) json.SetByKey("ObjectLocInfo", object_loc_info); @@ -245,8 +237,7 @@ CNetStorageObjectInfo g_CreateNetStorageObjectInfo(const string& object_loc, Uint8 file_size, CJsonNode::TInstance storage_specific_info) { return new SNetStorageObjectInfoImpl(SData(location, object_loc, - object_loc_struct ? object_loc_struct->GetUniqueKey() : kEmptyStr, - object_loc_struct ? object_loc_struct->ToJSON() : NULL, + object_loc_struct ? object_loc_struct->ToJSON() : CJsonNode(), file_size, storage_specific_info)); } diff --git a/c++/src/connect/services/netstorageobjectloc.cpp b/c++/src/connect/services/netstorageobjectloc.cpp index f3a91cff..58afe622 100644 --- a/c++/src/connect/services/netstorageobjectloc.cpp +++ b/c++/src/connect/services/netstorageobjectloc.cpp @@ -1,4 +1,4 @@ -/* $Id: netstorageobjectloc.cpp 499705 2016-04-27 17:58:55Z sadyrovr $ +/* $Id: netstorageobjectloc.cpp 527983 2017-02-17 00:23:09Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -60,14 +60,11 @@ CNetStorageObjectLoc::CNetStorageObjectLoc(CCompoundIDPool::TInstance cid_pool, EFileTrackSite ft_site) : m_CompoundIDPool(cid_pool), m_LocatorFlags(x_StorageFlagsToLocatorFlags(flags, ft_site)), - m_ObjectID(0), - m_Location(eNFL_Unknown), m_AppDomain(app_domain), m_Timestamp(time(NULL)), m_Random(random_number), m_ShortUniqueKey(MakeShortUniqueKey()), m_UniqueKey(MakeUniqueKey()), - m_NCFlags(0), m_Dirty(true) { @@ -80,25 +77,22 @@ CNetStorageObjectLoc::CNetStorageObjectLoc(CCompoundIDPool::TInstance cid_pool, EFileTrackSite ft_site) : m_CompoundIDPool(cid_pool), m_LocatorFlags(x_StorageFlagsToLocatorFlags(flags, ft_site) | fLF_HasUserKey), - m_ObjectID(0), - m_Location(eNFL_Unknown), m_AppDomain(app_domain), m_ShortUniqueKey(unique_key), m_UniqueKey(MakeUniqueKey()), - m_NCFlags(0), m_Dirty(true) { } #define INVALID_LOC_ERROR_MSG "Invalid NetStorage object locator" -#define THROW_INVALID_LOC_ERROR(object_loc, msg) \ +#define THROW_INVALID_LOC_ERROR(cid, msg) \ NCBI_THROW_FMT(CNetStorageException, eInvalidArg, \ - msg " '" << (object_loc) << '\'') + msg " '" << cid.ToString() << '\'') #define VERIFY_FIELD_EXISTS(field) \ if (!(field)) { \ - THROW_INVALID_LOC_ERROR(object_loc, INVALID_LOC_ERROR_MSG); \ + THROW_INVALID_LOC_ERROR(cid, INVALID_LOC_ERROR_MSG); \ } ENetStorageObjectLocation s_LocationCodeToLocation(const string& location) @@ -117,46 +111,43 @@ ENetStorageObjectLocation s_LocationCodeToLocation(const string& location) CNetStorageObjectLoc::CNetStorageObjectLoc(CCompoundIDPool::TInstance cid_pool, const string& object_loc) : m_CompoundIDPool(cid_pool), - m_ObjectID(0), - m_Location(eNFL_Unknown), - m_NCFlags(0), m_Dirty(false), m_Locator(object_loc) { - Parse(object_loc); + auto cid = m_CompoundIDPool.FromString(object_loc); + Parse(cid, false); } -CNetStorageObjectLoc::CNetStorageObjectLoc(CCompoundIDPool::TInstance cid_pool, - const string& object_loc, TNetStorageAttrFlags flags) : - m_CompoundIDPool(cid_pool), - m_ObjectID(0), - m_Location(eNFL_Unknown), - m_NCFlags(0), - m_Dirty(false), - m_Locator(object_loc) +void CNetStorageObjectLoc::SetServiceName(const string& service_name) { - Parse(object_loc); - - if (flags != GetStorageAttrFlags()) { - m_Dirty = true; - m_LocatorFlags = (m_LocatorFlags & eLF_FieldFlags) | - x_StorageFlagsToLocatorFlags(flags); + if (service_name.empty() || + strchr(service_name.c_str(), ':') != NULL) + ClearLocatorFlags(fLF_NetStorageService); + else { + m_ServiceName = service_name; + SetLocatorFlags(fLF_NetStorageService); } + m_Dirty = true; } -void CNetStorageObjectLoc::Parse(const string& object_loc) +string CNetStorageObjectLoc::GetServiceName(CCompoundID cid) { - CCompoundID cid = m_CompoundIDPool.FromString(object_loc); + CNetStorageObjectLoc loc; + loc.Parse(cid, true); + return loc.m_ServiceName; +} +void CNetStorageObjectLoc::Parse(CCompoundID cid, bool service_name_only) +{ // Check the ID class. switch (cid.GetClass()) { case eCIC_NetStorageObjectLocV1: - THROW_INVALID_LOC_ERROR(object_loc, + THROW_INVALID_LOC_ERROR(cid, "Unsupported NetStorage object locator version"); case eCIC_NetStorageObjectLoc: break; default: - THROW_INVALID_LOC_ERROR(object_loc, INVALID_LOC_ERROR_MSG); + THROW_INVALID_LOC_ERROR(cid, INVALID_LOC_ERROR_MSG); } // Get locator flags. @@ -170,6 +161,8 @@ void CNetStorageObjectLoc::Parse(const string& object_loc) m_ServiceName = field.GetServiceName(); } + if (service_name_only) return; + // Restore object ID. if (m_LocatorFlags & fLF_HasObjectID) { VERIFY_FIELD_EXISTS(field = field.GetNextNeighbor()); @@ -201,7 +194,7 @@ void CNetStorageObjectLoc::Parse(const string& object_loc) // Not used, though has to be read to be backward-compatible if (m_LocatorFlags & fLF_Cacheable) { - field.GetNextNeighbor(); + field = field.GetNextNeighbor(); } // Find storage info (optional). @@ -214,9 +207,9 @@ void CNetStorageObjectLoc::Parse(const string& object_loc) // Restore storage-specific info. if (m_Location == eNFL_NetCache) { - // Get NetCache flags. + // Not used, though has to be read to be backward-compatible VERIFY_FIELD_EXISTS(field = field.GetNextNeighbor()); - m_NCFlags = (TNetCacheFlags) field.GetFlags(); + // Get the service name. VERIFY_FIELD_EXISTS(field = field.GetNextNeighbor()); m_NCServiceName = field.GetServiceName(); @@ -227,45 +220,23 @@ void CNetStorageObjectLoc::Parse(const string& object_loc) } } -void CNetStorageObjectLoc::SetLocation_NetCache( - const string& service_name, - bool allow_xsite_conn) +void CNetStorageObjectLoc::SetLocation(const string& nc_service_name) { - if (m_Location == eNFL_NetCache) return; - - m_Dirty = true; + // If NetCache + if (!nc_service_name.empty()) { + if (m_Location == eNFL_NetCache) return; - m_LocationCode = NETCACHE_STORAGE_CODE; - m_Location = eNFL_NetCache; - - m_NCServiceName = service_name; - - if (allow_xsite_conn) - m_NCFlags |= fNCF_AllowXSiteConn; - else - m_NCFlags &= ~(TNetCacheFlags) fNCF_AllowXSiteConn; - - // NB: FileTrack site must not be reset. -} + m_LocationCode = NETCACHE_STORAGE_CODE; + m_Location = eNFL_NetCache; + } else { + if (m_Location == eNFL_FileTrack) return; -void CNetStorageObjectLoc::SetLocation_FileTrack(EFileTrackSite ft_site) -{ - if (m_Location == eNFL_FileTrack) return; + m_LocationCode = FILETRACK_STORAGE_CODE; + m_Location = eNFL_FileTrack; + } m_Dirty = true; - - m_LocationCode = FILETRACK_STORAGE_CODE; - m_Location = eNFL_FileTrack; - - m_NCServiceName.clear(); - m_NCFlags = 0; - - m_LocatorFlags &= ~(TLocatorFlags) (fLF_DevEnv | fLF_QAEnv); - - if (ft_site == eFileTrack_DevSite) - m_LocatorFlags |= fLF_DevEnv; - else if (ft_site == eFileTrack_QASite) - m_LocatorFlags |= fLF_QAEnv; + m_NCServiceName = nc_service_name; } CNetStorageObjectLoc::EFileTrackSite CNetStorageObjectLoc::GetFileTrackSite() const @@ -318,7 +289,7 @@ void CNetStorageObjectLoc::x_Pack() const // Save object creation timestamp. cid.AppendTimestamp(m_Timestamp); // Save the random ID. - cid.AppendRandom(m_Random >> (sizeof(Uint4) * 8)); + cid.AppendRandom((Uint4)(m_Random >> (sizeof(Uint4) * 8))); cid.AppendRandom((Uint4) m_Random); } @@ -335,8 +306,8 @@ void CNetStorageObjectLoc::x_Pack() const switch (m_Location) { case eNFL_NetCache: - // Save NetCache flags. - cid.AppendFlags(m_NCFlags); + // Not used, though has to be written to be backward-compatible + cid.AppendFlags(0); // Save the service name. cid.AppendServiceName(m_NCServiceName); break; @@ -365,6 +336,16 @@ TNetStorageAttrFlags CNetStorageObjectLoc::GetStorageAttrFlags() const return flags; } +void CNetStorageObjectLoc::SetStorageAttrFlags(TNetStorageAttrFlags flags) +{ + const auto new_locator_flags = (m_LocatorFlags & eLF_FieldFlags) | x_StorageFlagsToLocatorFlags(flags); + + if (new_locator_flags != m_LocatorFlags) { + m_Dirty = true; + m_LocatorFlags = new_locator_flags; + } +} + CNetStorageObjectLoc::TLocatorFlags CNetStorageObjectLoc::x_StorageFlagsToLocatorFlags( TNetStorageAttrFlags storage_flags, @@ -406,6 +387,8 @@ void CNetStorageObjectLoc::ToJSON(CJsonNode& root) const if (m_LocatorFlags & fLF_NetStorageService) root.SetString("ServiceName", m_ServiceName); + root.SetString("ObjectKey", m_UniqueKey); + CJsonNode storage_flags(CJsonNode::NewObjectNode()); storage_flags.SetBoolean("Movable", @@ -425,8 +408,6 @@ void CNetStorageObjectLoc::ToJSON(CJsonNode& root) const switch (m_Location) { case eNFL_NetCache: storage_info.SetString("ServiceName", m_NCServiceName); - storage_info.SetBoolean("AllowXSiteConn", IsXSiteProxyAllowed()); - root.SetByKey("NetCache", storage_info); break; default: diff --git a/c++/src/connect/services/pack_int.cpp b/c++/src/connect/services/pack_int.cpp deleted file mode 100644 index 2e456ec0..00000000 --- a/c++/src/connect/services/pack_int.cpp +++ /dev/null @@ -1,146 +0,0 @@ -/* $Id: pack_int.cpp 461156 2015-03-06 16:43:46Z sadyrovr $ - * =========================================================================== - * - * PUBLIC DOMAIN NOTICE - * National Center for Biotechnology Information - * - * This software/database is a "United States Government Work" under the - * terms of the United States Copyright Act. It was written as part of - * the author's official duties as a United States Government employee and - * thus cannot be copyrighted. This software/database is freely available - * to the public for use. The National Library of Medicine and the U.S. - * Government have not placed any restriction on its use or reproduction. - * - * Although all reasonable efforts have been taken to ensure the accuracy - * and reliability of the software and data, the NLM and the U.S. - * Government do not and cannot warrant the performance or results that - * may be obtained by using this software or data. The NLM and the U.S. - * Government disclaim all warranties, express or implied, including - * warranties of performance, merchantability or fitness for any particular - * purpose. - * - * Please cite the author in any work or product based on this material. - * - * =========================================================================== - * - * Author: Dmitry Kazimirov - * - * File Description: Pack and unpack 64-bit unsigned integer to an - * architecture-independent binary array - * of length no more than 9 bytes. - * - */ - -#include - -#include "pack_int.hpp" - -#include - -#include - -BEGIN_NCBI_SCOPE - -unsigned g_PackInteger(void* dst, size_t dst_size, Uint8 number) -{ - if ((signed char) number >= 0 && (unsigned char) number == number) { - if (dst_size > 0) - *(unsigned char*) dst = (unsigned char) number; - return 1; - } - - unsigned char buffer[sizeof(number)]; - unsigned char *ptr = buffer + sizeof(buffer) - 1; - - *ptr = (unsigned char) number; - unsigned length = 1; - - Uint8 mask = 0x7F; - Uint8 mask_shift; - - while ((number >>= 8) > (mask_shift = (mask >> 1))) { - *--ptr = (unsigned char) number; - ++length; - mask = mask_shift; - } - - if (dst_size > length) { - *(unsigned char*) dst = (unsigned char) (~mask | number); - - memcpy(((unsigned char*) dst) + 1, ptr, length); - } - - return length + 1; -} - -#define REC_DATA \ -{ \ - REC(2, 0x00), REC(2, 0x01), REC(2, 0x02), REC(2, 0x03), REC(2, 0x04), \ - REC(2, 0x05), REC(2, 0x06), REC(2, 0x07), REC(2, 0x08), REC(2, 0x09), \ - REC(2, 0x0A), REC(2, 0x0B), REC(2, 0x0C), REC(2, 0x0D), REC(2, 0x0E), \ - REC(2, 0x0F), REC(2, 0x10), REC(2, 0x11), REC(2, 0x12), REC(2, 0x13), \ - REC(2, 0x14), REC(2, 0x15), REC(2, 0x16), REC(2, 0x17), REC(2, 0x18), \ - REC(2, 0x19), REC(2, 0x1A), REC(2, 0x1B), REC(2, 0x1C), REC(2, 0x1D), \ - REC(2, 0x1E), REC(2, 0x1F), REC(2, 0x20), REC(2, 0x21), REC(2, 0x22), \ - REC(2, 0x23), REC(2, 0x24), REC(2, 0x25), REC(2, 0x26), REC(2, 0x27), \ - REC(2, 0x28), REC(2, 0x29), REC(2, 0x2A), REC(2, 0x2B), REC(2, 0x2C), \ - REC(2, 0x2D), REC(2, 0x2E), REC(2, 0x2F), REC(2, 0x30), REC(2, 0x31), \ - REC(2, 0x32), REC(2, 0x33), REC(2, 0x34), REC(2, 0x35), REC(2, 0x36), \ - REC(2, 0x37), REC(2, 0x38), REC(2, 0x39), REC(2, 0x3A), REC(2, 0x3B), \ - REC(2, 0x3C), REC(2, 0x3D), REC(2, 0x3E), REC(2, 0x3F), REC(3, 0x00), \ - REC(3, 0x01), REC(3, 0x02), REC(3, 0x03), REC(3, 0x04), REC(3, 0x05), \ - REC(3, 0x06), REC(3, 0x07), REC(3, 0x08), REC(3, 0x09), REC(3, 0x0A), \ - REC(3, 0x0B), REC(3, 0x0C), REC(3, 0x0D), REC(3, 0x0E), REC(3, 0x0F), \ - REC(3, 0x10), REC(3, 0x11), REC(3, 0x12), REC(3, 0x13), REC(3, 0x14), \ - REC(3, 0x15), REC(3, 0x16), REC(3, 0x17), REC(3, 0x18), REC(3, 0x19), \ - REC(3, 0x1A), REC(3, 0x1B), REC(3, 0x1C), REC(3, 0x1D), REC(3, 0x1E), \ - REC(3, 0x1F), REC(4, 0x00), REC(4, 0x01), REC(4, 0x02), REC(4, 0x03), \ - REC(4, 0x04), REC(4, 0x05), REC(4, 0x06), REC(4, 0x07), REC(4, 0x08), \ - REC(4, 0x09), REC(4, 0x0A), REC(4, 0x0B), REC(4, 0x0C), REC(4, 0x0D), \ - REC(4, 0x0E), REC(4, 0x0F), REC(5, 0x00), REC(5, 0x01), REC(5, 0x02), \ - REC(5, 0x03), REC(5, 0x04), REC(5, 0x05), REC(5, 0x06), REC(5, 0x07), \ - REC(6, 0x00), REC(6, 0x01), REC(6, 0x02), REC(6, 0x03), REC(7, 0x00), \ - REC(7, 0x01), REC(8, 0x00), REC(9, 0x00) \ -} - -#define REC(length, bits) {length, (bits << 8)} - -struct SCodeRec -{ - unsigned length; - Uint8 bits; -} static const s_CodeRec[128] = REC_DATA; - -unsigned g_UnpackInteger(const void* src, size_t src_size, Uint8* number) -{ - const unsigned char* ptr = (const unsigned char*) src; - - if (src_size == 0) - return 0; - - _ASSERT(number); - - if ((signed char) *ptr >= 0) { - *number = (Uint8) *ptr; - return 1; - } - - SCodeRec acc = s_CodeRec[*ptr - 0x80]; - - if (src_size >= acc.length) { - unsigned count = acc.length - 1; - - for (;;) { - acc.bits += *++ptr; - if (--count == 0) { - *number = acc.bits; - break; - } - acc.bits <<= 8; - } - } - - return acc.length; -} - -END_NCBI_SCOPE diff --git a/c++/src/connect/services/pack_int.hpp b/c++/src/connect/services/pack_int.hpp deleted file mode 100644 index 2f34bb79..00000000 --- a/c++/src/connect/services/pack_int.hpp +++ /dev/null @@ -1,103 +0,0 @@ -/* $Id: pack_int.hpp 411931 2013-09-03 18:41:39Z kazimird $ - * =========================================================================== - * - * PUBLIC DOMAIN NOTICE - * National Center for Biotechnology Information - * - * This software/database is a "United States Government Work" under the - * terms of the United States Copyright Act. It was written as part of - * the author's official duties as a United States Government employee and - * thus cannot be copyrighted. This software/database is freely available - * to the public for use. The National Library of Medicine and the U.S. - * Government have not placed any restriction on its use or reproduction. - * - * Although all reasonable efforts have been taken to ensure the accuracy - * and reliability of the software and data, the NLM and the U.S. - * Government do not and cannot warrant the performance or results that - * may be obtained by using this software or data. The NLM and the U.S. - * Government disclaim all warranties, express or implied, including - * warranties of performance, merchantability or fitness for any particular - * purpose. - * - * Please cite the author in any work or product based on this material. - * - * =========================================================================== - * - * Author: Dmitry Kazimirov - * - * File Description: Pack and unpack 64-bit unsigned integer to an - * architecture-independent binary array - * of length no more than 9 bytes. - * - */ - -#ifndef CONNECT_SERVICES__PACK_INT__HPP -#define CONNECT_SERVICES__PACK_INT__HPP - -#include - -#include -#include - -#include - -BEGIN_NCBI_SCOPE - - -/// Save a 8-byte unsigned integer to a variable-length array of -/// up to 9 bytes. -/// -/// @param dst -/// Pointer to the receiving buffer. -/// @param dst_size -/// Size of the receiving buffer in bytes. If the buffer is too -/// small to store a particular number, the buffer will not be -/// changed, but the function will return the value that would -/// have been returned if the buffer was big enough. The caller -/// must check whether the returned value is greater than -/// 'dst_size'. This, of course, is not necessary if 'dst_size' -/// is guaranteed to be at least 9 bytes long, which is the -/// maximum possible packed length of an 8-byte number. -/// @param number -/// The integer to pack. -/// -/// @return -/// The number of bytes stored in the 'dst' buffer. Or the -/// number of bytes that would have been stored if the buffer -/// was big enough (see the dscription of 'dst_size'). -/// -/// @see g_UnpackInteger -/// -extern -unsigned g_PackInteger(void* dst, size_t dst_size, Uint8 number); - - -/// Unpack an unsigned integer from a byte array prepared by -/// g_PackInteger(). -/// -/// @param src -/// The source byte array. -/// @param src_size -/// Number of bytes available in 'src'. -/// @param number -/// Pointer to a variable where the integer originally passed -/// to g_PackInteger() will be stored. If 'src_size' bytes is -/// not enough to reconstitute the integer, the variable will -/// not be changed. -/// -/// @return -/// The length of the packed integer stored in 'src' regardless -/// of whether the integer was actually unpacked or not (in case -/// if 'src_size' was less that the value that g_PackInteger() -/// originally returned, see the description of the 'number' -/// argument). -/// -/// @see g_PackInteger -/// -extern -unsigned g_UnpackInteger(const void* src, size_t src_size, Uint8* number); - - -END_NCBI_SCOPE - -#endif /* CONNECT_SERVICES__PACK_INT__HPP */ diff --git a/c++/src/connect/services/remote_app.cpp b/c++/src/connect/services/remote_app.cpp index 7f46a1a8..b283e477 100644 --- a/c++/src/connect/services/remote_app.cpp +++ b/c++/src/connect/services/remote_app.cpp @@ -1,4 +1,4 @@ -/* $Id: remote_app.cpp 489744 2016-01-15 16:50:24Z sadyrovr $ +/* $Id: remote_app.cpp 537164 2017-05-26 15:34:57Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -36,8 +36,6 @@ #include #include -#include -#include #define NCBI_USE_ERRCODE_X ConnServ_Remote @@ -78,26 +76,23 @@ CNcbiOstream& CBlobStreamHelper::GetOStream(const string& fname /*= ""*/, EStdOutErrStorageType type /*= eBlobStorage*/, size_t max_inline_size /*= kMaxBlobInlineSize*/) { - if (!m_OStream.get()) { - _ASSERT(!m_IStream.get()); - m_Writer.reset(new CStringOrBlobStorageWriter( - max_inline_size, m_Storage, *m_Data)); - m_OStream.reset(new CWStream(m_Writer.get(), - 0, 0, CRWStreambuf::fLeakExceptions)); - m_OStream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); - *m_OStream << (int) type << " "; - WriteStrWithLen(*m_OStream, fname); + if (!m_GridWrite.stream) { + _ASSERT(!m_GridRead.stream); + + m_GridWrite(m_Storage, max_inline_size, *m_Data); + *m_GridWrite.stream << (int) type << " "; + WriteStrWithLen(*m_GridWrite.stream, fname); if (!fname.empty() && type == eLocalFile) { - m_OStream.reset(new CNcbiOfstream(fname.c_str())); - m_Writer.reset(); - if (!m_OStream->good()) { + m_GridWrite.stream.reset(new CNcbiOfstream(fname.c_str())); + m_GridWrite.writer.reset(); + if (!m_GridWrite.stream->good()) { NCBI_THROW(CFileException, eRelativePath, "Cannot open " + fname + " for output"); } - m_OStream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); + m_GridWrite.stream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); } } - return *m_OStream.get(); + return *m_GridWrite.stream; } int CBlobStreamHelper::x_GetTypeAndName(CNcbiIstream& istream, @@ -112,26 +107,22 @@ int CBlobStreamHelper::x_GetTypeAndName(CNcbiIstream& istream, CNcbiIstream& CBlobStreamHelper::GetIStream(string* fname /*= NULL*/, EStdOutErrStorageType* type /*= NULL*/) { - if (!m_IStream.get()) { - _ASSERT(!m_OStream.get()); - auto_ptr reader( - new CStringOrBlobStorageReader(*m_Data, m_Storage, m_DataSize)); - m_IStream.reset(new CRStream(reader.release(), - 0,0,CRWStreambuf::fOwnReader - | CRWStreambuf::fLeakExceptions)); - m_IStream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); + if (!m_GridRead.stream) { + _ASSERT(!m_GridWrite.stream); + + m_GridRead(m_Storage, *m_Data, m_DataSize); string name; int tmp = (int)eBlobStorage; try { - tmp = x_GetTypeAndName(*m_IStream, name); + tmp = x_GetTypeAndName(*m_GridRead.stream, name); } catch (...) { - if (!m_IStream->eof()) { + if (!m_GridRead.stream->eof()) { string msg = "Job output does not match remote_app output format"; ERR_POST_X(1, msg); - m_IStream.reset(new CNcbiIstrstream(msg.c_str())); + m_GridRead.stream.reset(new CNcbiIstrstream(msg.c_str())); } - return *m_IStream.get(); + return *m_GridRead.stream.get(); } if (fname) *fname = name; @@ -139,32 +130,23 @@ CNcbiIstream& CBlobStreamHelper::GetIStream(string* fname /*= NULL*/, if (!name.empty() && (EStdOutErrStorageType)tmp == eLocalFile) { auto_ptr fstr(new CNcbiIfstream(name.c_str())); if (fstr->good()) { - m_IStream.reset(fstr.release()); - m_IStream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); + m_GridRead.stream.reset(fstr.release()); + m_GridRead.stream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); } else { string msg = "Can not open " + name; msg += " for reading"; ERR_POST_X(2, msg); - m_IStream.reset(new CNcbiIstrstream(msg.c_str())); + m_GridRead.stream.reset(new CNcbiIstrstream(msg.c_str())); } } } - return *m_IStream.get(); + return *m_GridRead.stream; } void CBlobStreamHelper::Reset() { - m_IStream.reset(); - - if (m_OStream.get()) { - m_OStream->flush(); - m_OStream.reset(); - } - - if (m_Writer.get() != NULL) { - m_Writer->Close(); - m_Writer.reset(); - } + m_GridRead.Reset(); + m_GridWrite.Reset(true); } ////////////////////////////////////////////////////////////////////////////// // @@ -280,9 +262,9 @@ void CRemoteAppRequest::x_Deserialize(CNcbiIstream& is, TStoredFiles* files) + blobid; CNcbiOfstream of(nfname.c_str()); if (of.good()) { - auto_ptr is(GetNetCacheAPI().GetIStream(blobid)); - of << is->rdbuf(); - is.reset(); + auto_ptr blob_is(GetNetCacheAPI().GetIStream(blobid)); + of << blob_is->rdbuf(); + blob_is.reset(); s_ReplaceArg(args, fname, nfname); } } diff --git a/c++/src/connect/services/srv_connections.cpp b/c++/src/connect/services/srv_connections.cpp index 45f91d98..bf92bac8 100644 --- a/c++/src/connect/services/srv_connections.cpp +++ b/c++/src/connect/services/srv_connections.cpp @@ -1,4 +1,4 @@ -/* $Id: srv_connections.cpp 494943 2016-03-11 20:01:22Z sadyrovr $ +/* $Id: srv_connections.cpp 540944 2017-07-12 15:49:36Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -36,13 +36,8 @@ #include #include -#include -#include - #include -#include "../ncbi_comm.h" - #ifdef NCBI_OS_LINUX # include # include @@ -57,11 +52,6 @@ BEGIN_NCBI_SCOPE static const STimeout s_ZeroTimeout = {0, 0}; -#ifndef NCBI_OS_MSWIN -static const STimeout s_InternalConnectTimeout = {0, 250 * 1000}; -#else -static const STimeout s_InternalConnectTimeout = {1, 250 * 1000}; -#endif /////////////////////////////////////////////////////////////////////////// SNetServerMultilineCmdOutputImpl::~SNetServerMultilineCmdOutputImpl() @@ -101,6 +91,10 @@ bool CNetServerMultilineCmdOutput::ReadLine(string& output) } } +void INetServerConnectionListener::OnPreInit(CObject*, ISynRegistry&, SRegSynonyms&, string&) +{ +} + inline SNetServerConnectionImpl::SNetServerConnectionImpl( SNetServerImpl* server) : m_Server(server), @@ -119,9 +113,7 @@ void SNetServerConnectionImpl::DeleteThis() TFastMutexGuard guard( m_Server->m_ServerInPool->m_FreeConnectionListLock); - //int upper_limit = m_Server.m_Impl->m_MaxConnPoolSize; int upper_limit = TServConn_MaxConnPoolSize::GetDefault(); - //LOG_POST("pool size: "<m_ServerInPool-> m_FreeConnectionListSize < upper_limit) { @@ -154,7 +146,7 @@ void SNetServerConnectionImpl::ReadCmdOutputLine(string& result, CONNSERV_THROW_FMT(CNetSrvConnException, eReadTimeout, m_Server, "Communication timeout while reading" " (timeout=" << NcbiTimeoutToMs( - m_Socket.GetTimeout(eIO_Read)) / 1000.0 << "s)"); + m_Socket.GetTimeout(eIO_Read)) / 1000.0l << "s)"); break; case eIO_Closed: Abort(); @@ -237,36 +229,6 @@ void SNetServerConnectionImpl::WriteLine(const string& line) } } -namespace { - class CTimeoutKeeper - { - public: - CTimeoutKeeper(CSocket* sock, STimeout* timeout) - { - if (timeout == NULL) - m_Socket = NULL; - else { - m_Socket = sock; - m_ReadTimeout = *sock->GetTimeout(eIO_Read); - m_WriteTimeout = *sock->GetTimeout(eIO_Write); - sock->SetTimeout(eIO_ReadWrite, timeout); - } - } - - ~CTimeoutKeeper() - { - if (m_Socket != NULL) { - m_Socket->SetTimeout(eIO_Read, &m_ReadTimeout); - m_Socket->SetTimeout(eIO_Write, &m_WriteTimeout); - } - } - - CSocket* m_Socket; - STimeout m_ReadTimeout; - STimeout m_WriteTimeout; - }; -} - string CNetServerConnection::Exec(const string& cmd, bool multiline_output, STimeout* timeout, @@ -474,160 +436,93 @@ CNetServerConnection SNetServerImpl::GetConnectionFromPool() } } -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT -const char SNetServerImpl::kXSiteFwd[] = "XSITEFWD"; -#endif - -inline static bool operator <(const STimeout& t1, const STimeout& t2) -{ - return t1.sec == t2.sec ? t1.usec < t2.usec : t1.sec < t2.sec; -} - -inline ostream& operator<<(ostream& out, const STimeout& tm) -{ - return out << (tm.sec+tm.usec*1e-6); -} - -CNetServerConnection SNetServerImpl::Connect(STimeout* timeout, - INetServerConnectionListener* conn_listener) +struct SNetServerImpl::SConnectDeadline { - CNetServerConnection conn = new SNetServerConnectionImpl(this); - - EIO_Status io_st; - const STimeout& conn_timeout = timeout != NULL ? *timeout : - m_ServerInPool->m_ServerPool->m_ConnTimeout; - CDeadline deadline(conn_timeout.sec, conn_timeout.usec * 1000); - STimeout internal_timeout = conn_timeout < s_InternalConnectTimeout ? - conn_timeout : s_InternalConnectTimeout; + SConnectDeadline(const STimeout& conn_timeout) : + try_timeout(Min(conn_timeout , kMaxTryTimeout)), + deadline(CTimeout(conn_timeout.sec, conn_timeout.usec)) + {} - //LOG_POST("internal timeout: "<m_Address); + bool IsExpired() + { + CNanoTimeout remaining(deadline.GetRemainingTime()); -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - ticket_t ticket = 0; + if (remaining.IsZero()) return true; - if (m_Service->m_AllowXSiteConnections && - m_Service->IsColoAddr(m_ServerInPool->m_Address.host)) { - union { - SFWDRequestReply rq; - char buffer[FWD_MAX_RR_SIZE + 1]; - }; + remaining.Get(&try_timeout.sec, &try_timeout.usec); + try_timeout = Min(try_timeout, kMaxTryTimeout); + return false; + } - memset(buffer, 0, sizeof(buffer)); - rq.host = m_ServerInPool->m_Address.host; - rq.port = SOCK_HostToNetShort(m_ServerInPool->m_Address.port); - rq.flag = SOCK_HostToNetShort(1); - _ASSERT(offsetof(SFWDRequestReply, text) + - sizeof(kXSiteFwd) < sizeof(buffer)); - memcpy(rq.text, kXSiteFwd, sizeof(kXSiteFwd)); - - size_t len = 0; - - CConn_ServiceStream svc(kXSiteFwd); - if (svc.write((const char*) &rq.ticket/*0*/, sizeof(rq.ticket)) && - svc.write(buffer, offsetof(SFWDRequestReply, text) + - sizeof(kXSiteFwd))) { - svc.read(buffer, sizeof(buffer) - 1); - len = (size_t) svc.gcount(); - _ASSERT(len < sizeof(buffer)); - } +private: + static STimeout Min(const STimeout& t1, const STimeout& t2) + { + if (t1.sec < t2.sec) return t1; + if (t1.sec > t2.sec) return t2; + if (t1.usec < t2.usec) return t1; + return t2; + } - memset(buffer + len, 0, sizeof(buffer) - len); - - if (len < offsetof(SFWDRequestReply, text) || - (rq.flag & 0xF0F0) || rq.port == 0) { - const char* err; - if (len == 0) - err = "Connection refused"; - else if (len < offsetof(SFWDRequestReply, text)) - err = "Short response received"; - else if (!(rq.flag & 0xF0F0)) - err = rq.flag & 0x0F0F ? "Client rejected" : "Unknown error"; - else if (NStr::strncasecmp(buffer, "NCBI", 4) == 0) - err = buffer; - else if (rq.text[0]) - err = rq.text; - else - err = "Unspecified error"; - NCBI_THROW_FMT(CNetSrvConnException, eConnectionFailure, - "Error while acquiring an auth ticket from a " - "cross-site connection proxy: " << err); - } + STimeout try_timeout; + CDeadline deadline; - if (rq.ticket != 0) { - server_address.host = rq.host; - server_address.port = SOCK_NetToHostShort(rq.port); - } else { - SOCK sock; - server_address.port = 0; - io_st = CONN_GetSOCK(svc.GetCONN(), &sock); - if (sock != NULL) - SOCK_CreateOnTop(sock, 0, &sock); - if (io_st != eIO_Success || sock == NULL) { - NCBI_THROW(CNetSrvConnException, eConnectionFailure, - "Error while connecting to proxy."); - } - conn->m_Socket.Reset(sock, eTakeOwnership, eCopyTimeoutsToSOCK); - } - ticket = rq.ticket; - } + static const STimeout kMaxTryTimeout; +}; - if (server_address.port != 0) { +#ifndef NCBI_OS_MSWIN +const STimeout SNetServerImpl::SConnectDeadline::kMaxTryTimeout = {0, 250 * 1000}; +#else +const STimeout SNetServerImpl::SConnectDeadline::kMaxTryTimeout = {1, 250 * 1000}; #endif - STimeout remaining_timeout; +CNetServerConnection SNetServerImpl::Connect(STimeout* timeout, + INetServerConnectionListener* conn_listener) +{ + CNetServerConnection conn = new SNetServerConnectionImpl(this); + + auto& server_pool = m_ServerInPool->m_ServerPool; + SConnectDeadline deadline(timeout ? *timeout : server_pool->m_ConnTimeout); + auto& socket = conn->m_Socket; - do { - io_st = conn->m_Socket.Connect(CSocketAPI::ntoa( - server_address.host), server_address.port, - &internal_timeout, fSOCK_LogOff | fSOCK_KeepAlive); + SNetServiceXSiteAPI::ConnectXSite(socket, deadline, m_ServerInPool->m_Address); - deadline.GetRemainingTime().Get(&remaining_timeout.sec, - &remaining_timeout.usec); + m_ServerInPool->AdjustThrottlingParameters(SNetServerInPool::eCOR_Success); - if (remaining_timeout < internal_timeout) - internal_timeout = remaining_timeout; + socket.SetDataLogging(TServConn_ConnDataLogging::GetDefault() ? eOn : eOff); + socket.SetTimeout(eIO_ReadWrite, timeout ? timeout : + &server_pool->m_CommTimeout); + socket.DisableOSSendDelay(); + socket.SetReuseAddress(eOn); - } while (io_st == eIO_Timeout && (remaining_timeout.usec > 0 || - remaining_timeout.sec > 0)); + if (!conn_listener) conn_listener = m_Service->m_Listener; - if (io_st != eIO_Success) { - conn->m_Socket.Close(); + conn_listener->OnConnected(conn); - NCBI_THROW(CNetSrvConnException, eConnectionFailure, - FORMAT(m_ServerInPool->m_Address.AsString() << - ": Could not connect: " << IO_StatusStr(io_st))); - } + if (timeout) socket.SetTimeout(eIO_ReadWrite, &server_pool->m_CommTimeout); -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - } + return conn; +} - if (ticket != 0 && - conn->m_Socket.Write(&ticket, sizeof(ticket)) != eIO_Success) { - NCBI_THROW(CNetSrvConnException, eConnectionFailure, - "Error while sending proxy auth ticket."); - } -#endif +void SNetServerImpl::ConnectImpl(CSocket& socket, SConnectDeadline& deadline, + const SServerAddress& actual, const SServerAddress& original) +{ + EIO_Status io_st; - m_ServerInPool->AdjustThrottlingParameters(SNetServerInPool::eCOR_Success); + do { + io_st = socket.Connect(CSocketAPI::ntoa(actual.host), actual.port, + deadline.GetRemaining(), fSOCK_LogOff | fSOCK_KeepAlive); - //LOG_POST("comm timeout: "<<*(timeout != NULL ? timeout: &m_ServerInPool->m_ServerPool->m_CommTimeout)); - conn->m_Socket.SetDataLogging( - TServConn_ConnDataLogging::GetDefault() ? eOn : eOff); - conn->m_Socket.SetTimeout(eIO_ReadWrite, timeout != NULL ? timeout : - &m_ServerInPool->m_ServerPool->m_CommTimeout); - conn->m_Socket.DisableOSSendDelay(); - conn->m_Socket.SetReuseAddress(eOn); + } while (io_st == eIO_Timeout && !deadline.IsExpired()); - (conn_listener != NULL ? conn_listener : - m_Service->m_Listener)->OnConnected(conn); + if (io_st == eIO_Success) return; - if (timeout != NULL) - conn->m_Socket.SetTimeout(eIO_ReadWrite, - &m_ServerInPool->m_ServerPool->m_CommTimeout); + socket.Close(); - return conn; + NCBI_THROW(CNetSrvConnException, eConnectionFailure, + FORMAT(original.AsString() << + ": Could not connect: " << IO_StatusStr(io_st))); } void SNetServerImpl::TryExec(INetServerExecHandler& handler, @@ -723,20 +618,21 @@ void SNetServerImpl::ConnectAndExec(const string& cmd, void SNetServerInPool::AdjustThrottlingParameters(EConnOpResult op_result) { - if (m_ServerPool->m_ServerThrottlePeriod <= 0) + const auto& params = m_ServerPool->GetThrottleParams(); + + if (params.m_ServerThrottlePeriod <= 0) return; CFastMutexGuard guard(m_ThrottleLock); - if (m_ServerPool->m_MaxConsecutiveIOFailures > 0) { + if (params.m_MaxConsecutiveIOFailures > 0) { if (op_result != eCOR_Success) ++m_NumberOfConsecutiveIOFailures; - else if (m_NumberOfConsecutiveIOFailures < - m_ServerPool->m_MaxConsecutiveIOFailures) + else if (m_NumberOfConsecutiveIOFailures < params.m_MaxConsecutiveIOFailures) m_NumberOfConsecutiveIOFailures = 0; } - if (m_ServerPool->m_IOFailureThresholdNumerator > 0) { + if (params.m_IOFailureThresholdNumerator > 0) { if (m_IOFailureRegister[m_IOFailureRegisterIndex] != op_result) { if ((m_IOFailureRegister[m_IOFailureRegisterIndex] = op_result) == eCOR_Success) @@ -745,15 +641,16 @@ void SNetServerInPool::AdjustThrottlingParameters(EConnOpResult op_result) ++m_IOFailureCounter; } - if (++m_IOFailureRegisterIndex >= - m_ServerPool->m_IOFailureThresholdDenominator) + if (++m_IOFailureRegisterIndex >= params.m_IOFailureThresholdDenominator) m_IOFailureRegisterIndex = 0; } } void SNetServerInPool::CheckIfThrottled() { - if (m_ServerPool->m_ServerThrottlePeriod <= 0) + const auto& params = m_ServerPool->GetThrottleParams(); + + if (params.m_ServerThrottlePeriod <= 0) return; CFastMutexGuard guard(m_ThrottleLock); @@ -761,17 +658,15 @@ void SNetServerInPool::CheckIfThrottled() if (m_Throttled) { CTime current_time(GetFastLocalTime()); if (current_time >= m_ThrottledUntil && - (!m_ServerPool->m_ThrottleUntilDiscoverable || - m_DiscoveredAfterThrottling)) { + (!params.m_ThrottleUntilDiscoverable || m_DiscoveredAfterThrottling)) { ResetThrottlingParameters(); return; } NCBI_THROW(CNetSrvConnException, eServerThrottle, m_ThrottleMessage); } - if (m_ServerPool->m_MaxConsecutiveIOFailures > 0 && - m_NumberOfConsecutiveIOFailures >= - m_ServerPool->m_MaxConsecutiveIOFailures) { + if (params.m_MaxConsecutiveIOFailures > 0 && + m_NumberOfConsecutiveIOFailures >= params.m_MaxConsecutiveIOFailures) { m_Throttled = true; m_DiscoveredAfterThrottling = false; m_ThrottleMessage = "Server " + m_Address.AsString(); @@ -779,8 +674,8 @@ void SNetServerInPool::CheckIfThrottled() "of connection failures in a row"; } - if (m_ServerPool->m_IOFailureThresholdNumerator > 0 && - m_IOFailureCounter >= m_ServerPool->m_IOFailureThresholdNumerator) { + if (params.m_IOFailureThresholdNumerator > 0 && + m_IOFailureCounter >= params.m_IOFailureThresholdNumerator) { m_Throttled = true; m_DiscoveredAfterThrottling = false; m_ThrottleMessage = "Connection to server " + m_Address.AsString(); @@ -789,7 +684,7 @@ void SNetServerInPool::CheckIfThrottled() if (m_Throttled) { m_ThrottledUntil.SetCurrent(); - m_ThrottledUntil.AddSecond(m_ServerPool->m_ServerThrottlePeriod); + m_ThrottledUntil.AddSecond(params.m_ServerThrottlePeriod); NCBI_THROW(CNetSrvConnException, eServerThrottle, m_ThrottleMessage); } } @@ -808,14 +703,17 @@ CNetServer::SExecResult CNetServer::ExecWithRetry(const string& cmd, { CNetServer::SExecResult exec_result; - CTime max_connection_time(GetFastLocalTime()); - max_connection_time.AddNanoSecond( - m_Impl->m_ServerInPool->m_ServerPool->m_MaxConnectionTime * 1000000); + const CTimeout& max_total_time = m_Impl->m_ServerInPool->m_ServerPool->m_MaxTotalTime; + CDeadline deadline(max_total_time); unsigned attempt = 0; + auto& service = m_Impl->m_Service; if (conn_listener == NULL) - conn_listener = m_Impl->m_Service->m_Listener; + conn_listener = service->m_Listener; + + const auto max_retries = service->GetConnectionMaxRetries(); + const auto retry_delay = service->GetConnectionRetryDelay(); for (;;) { string warning; @@ -826,32 +724,26 @@ CNetServer::SExecResult CNetServer::ExecWithRetry(const string& cmd, return exec_result; } catch (CNetSrvConnException& e) { - if (++attempt > TServConn_ConnMaxRetries::GetDefault() || + if (++attempt > max_retries || e.GetErrCode() == CNetSrvConnException::eServerThrottle) throw; - if (m_Impl->m_ServerInPool->m_ServerPool->m_MaxConnectionTime > 0 && - max_connection_time <= GetFastLocalTime()) { + if (deadline.IsExpired()) { LOG_POST(Error << "Timeout (max_connection_time=" << - m_Impl->m_ServerInPool->m_ServerPool->m_MaxConnectionTime << - "); cmd=" << cmd << - "; exception=" << e.GetMsg()); + max_total_time.GetAsMilliSeconds() << "); cmd=" << cmd << "; exception=" << e.GetMsg()); throw; } warning = e.GetMsg(); } catch (CNetScheduleException& e) { - if (++attempt > TServConn_ConnMaxRetries::GetDefault() || + if (++attempt > max_retries || e.GetErrCode() != CNetScheduleException::eTryAgain) throw; - if (m_Impl->m_ServerInPool->m_ServerPool->m_MaxConnectionTime > 0 && - max_connection_time <= GetFastLocalTime()) { + if (deadline.IsExpired()) { LOG_POST(Error << "Timeout (max_connection_time=" << - m_Impl->m_ServerInPool->m_ServerPool->m_MaxConnectionTime << - "); cmd=" << cmd << - "; exception=" << e.GetMsg()); + max_total_time.GetAsMilliSeconds() << "); cmd=" << cmd << "; exception=" << e.GetMsg()); throw; } @@ -861,12 +753,11 @@ CNetServer::SExecResult CNetServer::ExecWithRetry(const string& cmd, warning += ", reconnecting: attempt "; warning += NStr::NumericToString(attempt); warning += " of "; - warning += NStr::NumericToString( - TServConn_ConnMaxRetries::GetDefault()); + warning += NStr::NumericToString(max_retries); conn_listener->OnWarning(warning, *this); - SleepMilliSec(s_GetRetryDelay()); + SleepMilliSec(retry_delay); } } diff --git a/c++/src/connect/services/srv_connections_impl.hpp b/c++/src/connect/services/srv_connections_impl.hpp index 9e63c2c6..12644c8f 100644 --- a/c++/src/connect/services/srv_connections_impl.hpp +++ b/c++/src/connect/services/srv_connections_impl.hpp @@ -1,7 +1,7 @@ #ifndef CONNECT_SERVICES___SRV_CONNECTIONS_IMPL__HPP #define CONNECT_SERVICES___SRV_CONNECTIONS_IMPL__HPP -/* $Id: srv_connections_impl.hpp 484804 2015-11-16 15:24:08Z sadyrovr $ +/* $Id: srv_connections_impl.hpp 533212 2017-04-13 17:50:40Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -71,20 +71,18 @@ class INetServerProperties : public CObject { }; -class INetServerConnectionListener : public CObject +struct INetServerConnectionListener : CObject { -public: virtual CRef AllocServerProperties() = 0; -// Event handlers. -public: - virtual CConfig* OnPreInit(CObject* api_impl, CConfig* config, - string* config_section, string& client_name) { return NULL; } - virtual void OnInit(CObject* api_impl, - CConfig* config, const string& config_section) = 0; + // Event handlers. + virtual void OnPreInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections, string& client_name); + virtual void OnInit(CObject* api_impl, ISynRegistry& registry, SRegSynonyms& sections) = 0; virtual void OnConnected(CNetServerConnection& connection) = 0; virtual void OnError(const string& err_msg, CNetServer& server) = 0; virtual void OnWarning(const string& warn_msg, CNetServer& server) = 0; + + CRef m_EventHandler; }; struct SNetServerConnectionImpl : public CObject @@ -251,6 +249,8 @@ struct SNetServerInfoImpl : public CObject struct SNetServerImpl : public CObject { + struct SConnectDeadline; + SNetServerImpl(CNetService::TInstance service, SNetServerInPool* server_in_pool) : m_Service(service), @@ -258,9 +258,6 @@ struct SNetServerImpl : public CObject { } - CNetServerConnection Connect(STimeout* timeout, - INetServerConnectionListener* conn_listener); - CNetServerConnection GetConnectionFromPool(); void TryExec(INetServerExecHandler& handler, @@ -274,12 +271,43 @@ struct SNetServerImpl : public CObject INetServerExecListener* exec_listener = NULL, INetServerConnectionListener* conn_listener = NULL); -#ifdef NCBI_GRID_XSITE_CONN_SUPPORT - static const char kXSiteFwd[]; -#endif + static void ConnectImpl(CSocket&, SConnectDeadline&, const SServerAddress&, + const SServerAddress&); CNetService m_Service; CRef m_ServerInPool; + +private: + CNetServerConnection Connect(STimeout* timeout, + INetServerConnectionListener* conn_listener); +}; + +class CTimeoutKeeper +{ +public: + CTimeoutKeeper(CSocket* sock, STimeout* timeout) + { + if (timeout == NULL) + m_Socket = NULL; + else { + m_Socket = sock; + m_ReadTimeout = *sock->GetTimeout(eIO_Read); + m_WriteTimeout = *sock->GetTimeout(eIO_Write); + sock->SetTimeout(eIO_ReadWrite, timeout); + } + } + + ~CTimeoutKeeper() + { + if (m_Socket != NULL) { + m_Socket->SetTimeout(eIO_Read, &m_ReadTimeout); + m_Socket->SetTimeout(eIO_Write, &m_WriteTimeout); + } + } + + CSocket* m_Socket; + STimeout m_ReadTimeout; + STimeout m_WriteTimeout; }; END_NCBI_SCOPE diff --git a/c++/src/connect/services/tmp_wn_info.cpp b/c++/src/connect/services/tmp_wn_info.cpp index 1c5762a6..65d48df7 100644 --- a/c++/src/connect/services/tmp_wn_info.cpp +++ b/c++/src/connect/services/tmp_wn_info.cpp @@ -1,4 +1,4 @@ -/* $Id: tmp_wn_info.cpp 504536 2016-06-16 12:42:34Z kazimird $ +/* $Id: tmp_wn_info.cpp 525520 2017-01-25 14:14:27Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -187,7 +187,7 @@ static void NormalizeStatKeyName(CTempString& key) key.assign(begin, end - begin); for (; begin < end; ++begin) - *begin = isalnum(*begin) ? tolower(*begin) : '_'; + *begin = isalnum(*begin) ? (char)tolower(*begin) : '_'; } bool s_FixMisplacedPID(CJsonNode& stat_info, CTempString& executable_path, @@ -309,7 +309,7 @@ static bool s_ExtractKey(const CTempString& line, { char c = line[i]; if (isalnum(c)) - key += tolower(c); + key += (char)tolower(c); else if (c == ' ' || c == '_' || c == '-') key += '_'; else if (c != ':' || key.empty()) diff --git a/c++/src/connect/services/util.cpp b/c++/src/connect/services/util.cpp index 107fcb52..ad9d9791 100644 --- a/c++/src/connect/services/util.cpp +++ b/c++/src/connect/services/util.cpp @@ -1,4 +1,4 @@ -/* $Id: util.cpp 485043 2015-11-18 14:43:31Z sadyrovr $ +/* $Id: util.cpp 525330 2017-01-23 18:16:35Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,8 +33,6 @@ #include -#include "util.hpp" - #include #include @@ -198,86 +196,4 @@ string g_NetService_TryResolveHost(const string& ip_or_hostname) return hostname; } -#define NOT_ALPHA(c) ((c < 'a' || c > 'z') && (c < 'A' || c > 'Z')) -#define NOT_DIGIT(c) (c < '0' || c > '9') - -bool g_CheckAlphabet(const string& str, const CTempString& param_name, - ECharacterClass char_class, char* bad_char) -{ - const char* ch = str.data(); - size_t len = str.length(); - - switch (char_class) { - case eCC_Alphabetic: - for (; len > 0; ++ch, --len) - if (NOT_ALPHA(*ch)) - break; - break; - - case eCC_Alphanumeric: - for (; len > 0; ++ch, --len) - if (NOT_ALPHA(*ch) && NOT_DIGIT(*ch)) - break; - break; - - case eCC_StrictId: - for (; len > 0; ++ch, --len) - if (NOT_ALPHA(*ch) && NOT_DIGIT(*ch) && *ch != '_') - break; - break; - - case eCC_BASE64URL: - for (; len > 0; ++ch, --len) - if (NOT_ALPHA(*ch) && NOT_DIGIT(*ch) && *ch != '_' && *ch != '-') - break; - break; - - case eCC_BASE64_PI: - for (; len > 0; ++ch, --len) - if (NOT_ALPHA(*ch) && NOT_DIGIT(*ch) && *ch != '_' && *ch != '.') - break; - break; - - case eCC_RelaxedId: - for (; len > 0; ++ch, --len) - if (NOT_ALPHA(*ch) && NOT_DIGIT(*ch) && *ch != '_' && - *ch != '-' && *ch != '.' && *ch != ':' && - *ch != '@' && *ch != '|') - break; - break; - } - - if (len != 0) { - *bad_char = *ch; - return false; - } - - return true; -} - -void g_VerifyAlphabet(const string& str, const CTempString& param_name, - ECharacterClass char_class) -{ - char bad_char; - - if (!g_CheckAlphabet(str, param_name, char_class, &bad_char)) { - NCBI_THROW_FMT(CConfigException, eParameterMissing, - "Invalid character '" << - NStr::PrintableString(CTempString(&bad_char, 1)) << - "' in the " << param_name << " \"" << - NStr::PrintableString(str) << "\"."); - } -} - -unsigned g_NumberOfUnderscoresPlusOne(const string& str) -{ - unsigned underscore_count = 1; - const char* underscore = strchr(str.c_str(), '_'); - while (underscore != NULL) { - ++underscore_count; - underscore = strchr(underscore + 1, '_'); - } - return underscore_count; -} - END_NCBI_SCOPE diff --git a/c++/src/connect/services/wn_commit_thread.cpp b/c++/src/connect/services/wn_commit_thread.cpp index 8ee2edef..5d89657b 100644 --- a/c++/src/connect/services/wn_commit_thread.cpp +++ b/c++/src/connect/services/wn_commit_thread.cpp @@ -1,4 +1,4 @@ -/* $Id: wn_commit_thread.cpp 470774 2015-06-18 19:13:47Z sadyrovr $ +/* $Id: wn_commit_thread.cpp 535664 2017-05-10 19:17:21Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -162,6 +162,7 @@ bool CJobCommitterThread::x_CommitJob(SWorkerNodeJobContextImpl* job_context) CRequestContextSwitcher request_state_guard(job_context->m_RequestContext); bool recycle_job_context = false; + m_WorkerNode->m_JobsInProgress.Update(job_context->m_Job); try { switch (job_context->m_JobCommitStatus) { @@ -219,10 +220,10 @@ bool CJobCommitterThread::x_CommitJob(SWorkerNodeJobContextImpl* job_context) } } - m_WorkerNode->m_JobsInProgress.Remove(job_context->m_Job.job_id); - - if (recycle_job_context) + if (recycle_job_context) { + m_WorkerNode->m_JobsInProgress.Remove(job_context->m_Job); job_context->x_PrintRequestStop(); + } return recycle_job_context; } diff --git a/c++/src/connect/services/wn_main_loop.cpp b/c++/src/connect/services/wn_main_loop.cpp index 1cc2c710..a65bb0c6 100644 --- a/c++/src/connect/services/wn_main_loop.cpp +++ b/c++/src/connect/services/wn_main_loop.cpp @@ -1,4 +1,4 @@ -/* $Id: wn_main_loop.cpp 518714 2016-11-07 18:04:33Z ivanov $ +/* $Id: wn_main_loop.cpp 537169 2017-05-26 15:43:05Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -38,11 +38,8 @@ #include #include -#include #include -#include - #define NCBI_USE_ERRCODE_X ConnServ_WorkerNode @@ -149,24 +146,24 @@ const string& CWorkerNodeJobContext::GetClientName() const return m_Impl->m_WorkerNode->GetClientName(); } +CNcbiIstream& SWorkerNodeJobContextImpl::GetIStream() +{ + return m_GridRead(m_NetCacheAPI, m_Job.input, &m_InputBlobSize); +} + CNcbiIstream& CWorkerNodeJobContext::GetIStream() { - IReader* reader = new CStringOrBlobStorageReader(GetJobInput(), - m_Impl->m_NetCacheAPI, &m_Impl->m_InputBlobSize); - m_Impl->m_RStream.reset(new CRStream(reader, 0, 0, - CRWStreambuf::fOwnReader | CRWStreambuf::fLeakExceptions)); - m_Impl->m_RStream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); - return *m_Impl->m_RStream; + return m_Impl->GetIStream(); } + +CNcbiOstream& SWorkerNodeJobContextImpl::GetOStream() +{ + return m_GridWrite(m_NetCacheAPI, m_WorkerNode->m_QueueEmbeddedOutputSize, m_WorkerNode->m_DirectOutput, m_Job); +} + CNcbiOstream& CWorkerNodeJobContext::GetOStream() { - m_Impl->m_Writer.reset(new CStringOrBlobStorageWriter( - m_Impl->m_WorkerNode->m_QueueEmbeddedOutputSize, - m_Impl->m_NetCacheAPI, GetJob().output)); - m_Impl->m_WStream.reset(new CWStream(m_Impl->m_Writer.get(), 0, 0, - CRWStreambuf::fLeakExceptions)); - m_Impl->m_WStream->exceptions(IOS_BASE::badbit | IOS_BASE::failbit); - return *m_Impl->m_WStream; + return m_Impl->GetOStream(); } void CWorkerNodeJobContext::CloseStreams() @@ -176,13 +173,8 @@ void CWorkerNodeJobContext::CloseStreams() m_Impl->m_StatusThrottler.Reset(1, CTimeSpan(m_Impl->m_WorkerNode->m_CheckStatusPeriod, 0)); - m_Impl->m_RStream.reset(); - m_Impl->m_WStream.reset(); - - if (m_Impl->m_Writer.get() != NULL) { - m_Impl->m_Writer->Close(); - m_Impl->m_Writer.reset(); - } + m_Impl->m_GridRead.Reset(); + m_Impl->m_GridWrite.Reset(); } NCBI_CATCH_ALL_X(61, "Could not close IO streams"); } @@ -421,8 +413,13 @@ void SWorkerNodeJobContextImpl::x_RunJob() CRequestContextSwitcher request_state_guard(m_RequestContext); - if (g_IsRequestStartEventEnabled()) - GetDiagContext().PrintRequestStart().Print("jid", m_Job.job_id); + if (g_IsRequestStartEventEnabled()) { + auto extra = GetDiagContext().PrintRequestStart(); + extra.Print("jid", m_Job.job_id); + + CNetScheduleKey key; + if (key.ParseJobKey(m_Job.job_id)) extra.Print("_queue", key.queue); + } m_RequestContext->SetAppState(eDiagAppState_Request); @@ -732,7 +729,8 @@ bool CMainLoopThread::x_GetNextJob(CNetScheduleJob& job) // Already executing this job, so do nothing // (and rely on that execution to report its result later) - if (!m_WorkerNode->m_JobsInProgress.Add(job.job_id)) { + if (!m_WorkerNode->m_JobsInProgress.Add(job)) { + LOG_POST(Warning << "Got already processing job " << job.job_id); return false; } diff --git a/c++/src/connect/services/wn_offline_mode.cpp b/c++/src/connect/services/wn_offline_mode.cpp index 480ca9d8..e0c20e8c 100644 --- a/c++/src/connect/services/wn_offline_mode.cpp +++ b/c++/src/connect/services/wn_offline_mode.cpp @@ -1,4 +1,4 @@ -/* $Id: wn_offline_mode.cpp 489744 2016-01-15 16:50:24Z sadyrovr $ +/* $Id: wn_offline_mode.cpp 512595 2016-09-01 15:29:40Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -74,8 +74,7 @@ public: }; -void SOfflineJobContextImpl::PutProgressMessage(const string& msg, - bool send_immediately, bool overwrite) +void SOfflineJobContextImpl::PutProgressMessage(const string&, bool, bool) { } @@ -84,7 +83,7 @@ CNetScheduleAdmin::EShutdownLevel SOfflineJobContextImpl::GetShutdownLevel() return CGridGlobals::GetInstance().GetShutdownLevel(); } -void SOfflineJobContextImpl::JobDelayExpiration(unsigned runtime_inc) +void SOfflineJobContextImpl::JobDelayExpiration(unsigned) { } diff --git a/c++/src/corelib/CMakeLists.corelib.lib.txt b/c++/src/corelib/CMakeLists.corelib.lib.txt new file mode 100644 index 00000000..90a0aaaa --- /dev/null +++ b/c++/src/corelib/CMakeLists.corelib.lib.txt @@ -0,0 +1,41 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/corelib/Makefile.corelib.lib +# +if (UNIX) + set(os_src ncbi_os_unix) +elseif (WIN32) + set(os_src ncbi_os_mswin) + +endif(UNIX) + + +add_library(xncbi + ${ncbicntr} blob_storage ddumpable env_reg metareg ncbi_config + ncbi_param ncbi_process ncbi_safe_static ncbi_signal ncbi_stack + ncbi_system ncbiapp ncbiargs ncbiatomic ${CMAKE_CURRENT_BINARY_DIR}/ncbicfg ncbidbg ncbidiag + ncbidiag_p ncbidll ncbienv ncbiexec ncbiexpt ncbifile ncbimempool + ncbimtx ncbiobj ncbireg ncbistr ncbistre ncbithr ncbitime obj_store + plugin_manager plugin_manager_store rwstreambuf stream_utils syslog + version request_ctx request_control expr ncbi_strings resource_info + interprocess_lock ncbi_autoinit perf_log ncbi_toolkit ncbierror ncbi_url + ncbi_cookies guard ncbi_message request_status + ${os_src} + +) + +target_link_libraries(xncbi + ${DL_LIBS} ${LIBS} +) + +if (${HAVE_LIBUNWIND}) + include_directories(${LIBUNWIND_INCLUDE}) + target_link_libraries(xncbi + ${LIBUNWIND_LIBS} + ) +endif () + +if (WIN32) + target_link_libraries(xncbi + DbgHelp + ) +endif() diff --git a/c++/src/corelib/CMakeLists.test_boost.lib.txt b/c++/src/corelib/CMakeLists.test_boost.lib.txt new file mode 100644 index 00000000..694ba8d4 --- /dev/null +++ b/c++/src/corelib/CMakeLists.test_boost.lib.txt @@ -0,0 +1,12 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/corelib/Makefile.test_boost.lib +# +add_library(test_boost + test_boost teamcity_messages +) +include_directories(SYSTEM ${BOOST_INCLUDE}) + +target_link_libraries(test_boost + xncbi +) + diff --git a/c++/src/corelib/CMakeLists.test_mt.lib.txt b/c++/src/corelib/CMakeLists.test_mt.lib.txt new file mode 100644 index 00000000..2511087d --- /dev/null +++ b/c++/src/corelib/CMakeLists.test_mt.lib.txt @@ -0,0 +1,11 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/corelib/Makefile.test_mt.lib +# +add_library(test_mt + test_mt +) + +target_link_libraries(test_mt + xncbi +) + diff --git a/c++/src/corelib/CMakeLists.txt b/c++/src/corelib/CMakeLists.txt new file mode 100644 index 00000000..474bac8b --- /dev/null +++ b/c++/src/corelib/CMakeLists.txt @@ -0,0 +1,11 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.corelib.lib.txt) +include(CMakeLists.test_mt.lib.txt) +include(CMakeLists.test_boost.lib.txt) + +# Recurse subdirectories +add_subdirectory(test ) diff --git a/c++/src/corelib/Makefile.corelib.lib b/c++/src/corelib/Makefile.corelib.lib index f7182c0d..17eff999 100644 --- a/c++/src/corelib/Makefile.corelib.lib +++ b/c++/src/corelib/Makefile.corelib.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.corelib.lib 472138 2015-07-07 16:07:55Z grichenk $ +# $Id: Makefile.corelib.lib 536786 2017-05-23 15:55:09Z ucko $ SRC = $(ncbicntr) blob_storage ddumpable env_reg metareg ncbi_config \ ncbi_param ncbi_process ncbi_safe_static ncbi_signal ncbi_stack \ @@ -8,7 +8,7 @@ SRC = $(ncbicntr) blob_storage ddumpable env_reg metareg ncbi_config \ plugin_manager plugin_manager_store rwstreambuf stream_utils \ syslog version request_ctx request_control expr ncbi_strings \ resource_info interprocess_lock ncbi_autoinit perf_log ncbi_toolkit \ - ncbierror ncbi_url ncbi_cookies guard ncbi_message + ncbierror ncbi_url ncbi_cookies guard ncbi_message request_status UNIX_SRC = ncbi_os_unix @@ -16,6 +16,8 @@ LIB = xncbi LIBS = $(DL_LIBS) $(ORIG_LIBS) +CPPFLAGS = $(LIBUNWIND_INCLUDE) $(ORIG_CPPFLAGS) + # Special build rules for WorkShop ncbicntr_workshop.o: $(srcdir)/ncbicntr_workshop.il $(srcdir)/ncbicntr_workshop.cpp $(CXX_WRAPPER) $(CXX) $(CXXFLAGS_ALL:-O%=) $(srcdir)/ncbicntr_workshop.il $(srcdir)/ncbicntr_workshop.cpp -o $@ $(CXX_FILTER) diff --git a/c++/src/corelib/blob_storage.cpp b/c++/src/corelib/blob_storage.cpp index 2028a304..855e270f 100644 --- a/c++/src/corelib/blob_storage.cpp +++ b/c++/src/corelib/blob_storage.cpp @@ -1,4 +1,4 @@ -/* $Id: blob_storage.cpp 460958 2015-03-04 17:53:33Z grichenk $ +/* $Id: blob_storage.cpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -77,7 +77,7 @@ IBlobStorage* CBlobStorageFactory::CreateInstance() typedef CPluginManagerGetter TCacheManagerStore; CRef cache_manager( TCacheManagerStore::Get() ); - //auto_ptr params( MakeParamTree() ); + //unique_ptr params( MakeParamTree() ); IBlobStorage* drv = NULL; _ASSERT( cache_manager ); diff --git a/c++/src/corelib/env_reg.cpp b/c++/src/corelib/env_reg.cpp index ce503b57..5b4623b7 100644 --- a/c++/src/corelib/env_reg.cpp +++ b/c++/src/corelib/env_reg.cpp @@ -1,4 +1,4 @@ -/* $Id: env_reg.cpp 507064 2016-07-14 15:29:09Z elisovdn $ +/* $Id: env_reg.cpp 517314 2016-10-24 13:35:15Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -342,7 +342,13 @@ bool CNcbiEnvRegMapper::EnvToReg(const string& env, string& section, if (env.size() <= kPfxLen || !NStr::StartsWith(env, sm_Prefix) ) { return false; } - SIZE_TYPE uu_pos = env.find("__", kPfxLen + 1); + // Make an offset until the first symbol that could be section name + // (alphanumeric character) + SIZE_TYPE section_start_pos = kPfxLen; + for ( ; section_start_pos < env.size(); section_start_pos++) { + if (isalnum(env[section_start_pos])) break; + } + SIZE_TYPE uu_pos = env.find("__", section_start_pos + 1); if (uu_pos == NPOS || uu_pos == env.size() - 2) { return false; } diff --git a/c++/src/corelib/ncbi_config.cpp b/c++/src/corelib/ncbi_config.cpp index b897dcc6..8caf0800 100644 --- a/c++/src/corelib/ncbi_config.cpp +++ b/c++/src/corelib/ncbi_config.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_config.cpp 486111 2015-12-01 17:17:39Z grichenk $ +/* $Id: ncbi_config.cpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -121,7 +121,7 @@ void s_ParseSubNodes(const string& sub_nodes, set sub_set; s_List2Set(sub_list, &sub_set); ITERATE(set, sub_it, sub_set) { - auto_ptr sub_node(new TParamTree); + unique_ptr sub_node(new TParamTree); size_t pos = sub_it->rfind('/'); if (pos == string::npos) { sub_node->GetKey() = *sub_it; @@ -234,7 +234,7 @@ ETreeTraverseCode SNodeNameUpdater::operator()(TParamTree& node, CConfig::TParamTree* CConfig::ConvertRegToTree(const IRegistry& reg) { - auto_ptr tree_root(new TParamTree); + unique_ptr tree_root(new TParamTree); list sections; reg.EnumerateSections(§ions); @@ -253,7 +253,7 @@ CConfig::TParamTree* CConfig::ConvertRegToTree(const IRegistry& reg) const string& section_name = *name_it; TParamTree* node_ptr; if (section_name.find('/') == string::npos) { - auto_ptr node(new TParamTree); + unique_ptr node(new TParamTree); node->GetKey() = section_name; tree_root->AddNode(node_ptr = node.release()); } else { @@ -344,7 +344,7 @@ CConfig::TParamTree* CConfig::ConvertRegToTree(const IRegistry& reg) TParamTree* node_ptr; if (section_name.find('/') == string::npos) { - auto_ptr node(new TParamTree); + unique_ptr node(new TParamTree); node->GetKey() = section_name; tree_root->AddNode(node_ptr = node.release()); } else { @@ -521,7 +521,7 @@ int CConfig::GetInt(const string& driver_name, ", incorrect parameter format:" + param_name + " : " + param + " " + ex.what(); - NCBI_THROW(CConfigException, eParameterMissing, msg); + NCBI_THROW(CConfigException, eInvalidParameter, msg); } else { string msg = "Configuration error " + driver_name + ", incorrect parameter format:" + @@ -561,7 +561,7 @@ Uint8 CConfig::GetDataSize(const string& driver_name, ", incorrect parameter format:" + param_name + " : " + param + " " + ex.what(); - NCBI_THROW(CConfigException, eParameterMissing, msg); + NCBI_THROW(CConfigException, eInvalidParameter, msg); } else { string msg = "Configuration error " + driver_name + ", incorrect parameter format:" + @@ -602,7 +602,7 @@ bool CConfig::GetBool(const string& driver_name, ", incorrect parameter format:" + param_name + " : " + param + ". " + ex.what(); - NCBI_THROW(CConfigException, eParameterMissing, msg); + NCBI_THROW(CConfigException, eInvalidParameter, msg); } else { string msg = "Configuration error " + driver_name + ", incorrect parameter format:" + @@ -642,7 +642,7 @@ double CConfig::GetDouble(const string& driver_name, ", incorrect parameter format:" + param_name + " : " + param + " " + ex.what(); - NCBI_THROW(CConfigException, eParameterMissing, msg); + NCBI_THROW(CConfigException, eInvalidParameter, msg); } else { string msg = "Configuration error " + driver_name + ", incorrect parameter format:" + diff --git a/c++/src/corelib/ncbi_cookies.cpp b/c++/src/corelib/ncbi_cookies.cpp index 03863b68..5a1adb19 100644 --- a/c++/src/corelib/ncbi_cookies.cpp +++ b/c++/src/corelib/ncbi_cookies.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_cookies.cpp 517040 2016-10-20 11:22:39Z ivanov $ +/* $Id: ncbi_cookies.cpp 516788 2016-10-18 13:03:49Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/corelib/ncbi_process.cpp b/c++/src/corelib/ncbi_process.cpp index 618271c0..ec918c3d 100644 --- a/c++/src/corelib/ncbi_process.cpp +++ b/c++/src/corelib/ncbi_process.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_process.cpp 486692 2015-12-09 12:49:29Z ivanov $ +/* $Id: ncbi_process.cpp 536050 2017-05-15 16:18:35Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -199,7 +199,7 @@ TPid CProcess::sx_GetPid(EGetPidFlag flag) static TPid s_CurrentPid = 0; static TPid s_ParentPid = 0; - if (CThread::GetSelf() == 0) { + if (CThread::IsMain()) { // For main thread always force caching of PIDs CFastMutexGuard guard(s_GetPidMutex); s_CurrentPid = getpid(); diff --git a/c++/src/corelib/ncbi_safe_static.cpp b/c++/src/corelib/ncbi_safe_static.cpp index a1e72dff..6714c265 100644 --- a/c++/src/corelib/ncbi_safe_static.cpp +++ b/c++/src/corelib/ncbi_safe_static.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_safe_static.cpp 463583 2015-03-30 18:05:28Z vasilche $ +/* $Id: ncbi_safe_static.cpp 536051 2017-05-15 16:21:49Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -80,7 +80,7 @@ CSafeStaticLifeSpan& CSafeStaticLifeSpan::GetDefault(void) // Protective mutex and the owner thread ID to avoid // multiple initializations and deadlocks -DEFINE_CLASS_STATIC_MUTEX(CSafeStaticPtr_Base::sm_Mutex); +DEFINE_CLASS_STATIC_MUTEX(CSafeStaticPtr_Base::sm_ClassMutex); int CSafeStaticPtr_Base::x_GetCreationOrder(void) @@ -93,8 +93,7 @@ int CSafeStaticPtr_Base::x_GetCreationOrder(void) CSafeStaticPtr_Base::~CSafeStaticPtr_Base(void) { if ( x_IsStdStatic() ) { - CMutexGuard guard(sm_Mutex); - x_Cleanup(guard); + x_Cleanup(); } } @@ -112,6 +111,16 @@ CSafeStaticGuard::TStack* CSafeStaticGuard::sm_Stack; int CSafeStaticGuard::sm_RefCount; +// CSafeStaticGuard reference counter +// On MSWin threads are killed before destruction of static objects in DLLs, so in +// most cases this check is useless. +#if defined(NCBI_WIN32_THREADS) +bool CSafeStaticGuard::sm_ChildThreadsCheck = false; +#else +bool CSafeStaticGuard::sm_ChildThreadsCheck = true; +#endif + + CSafeStaticGuard::CSafeStaticGuard(void) { // Initialize the guard only once @@ -122,13 +131,20 @@ CSafeStaticGuard::CSafeStaticGuard(void) sm_RefCount++; } + +void CSafeStaticGuard::DisableChildThreadsCheck() +{ + sm_ChildThreadsCheck = false; +} + + static CSafeStaticGuard* sh_CleanupGuard; CSafeStaticGuard::~CSafeStaticGuard(void) { - CMutexGuard guard(CSafeStaticPtr_Base::sm_Mutex); + CMutexGuard guard(CSafeStaticPtr_Base::sm_ClassMutex); // Protect CSafeStaticGuard destruction if ( sh_CleanupGuard ) { @@ -142,14 +158,23 @@ CSafeStaticGuard::~CSafeStaticGuard(void) } assert(sm_RefCount == 0); + if (sm_ChildThreadsCheck) { + if (const auto tc = CThread::GetThreadsCount()) { + string msg = "On static data destruction, child thread(s) still running: " + to_string(tc); + ERR_POST_X(1, Error << msg); + _ASSERT(CThread::GetThreadsCount() == 0); + } + } + for ( int pass = 0; pass < 3; ++pass ) { // Call Cleanup() for all variables registered TStack cur_Stack; swap(cur_Stack, *sm_Stack); + guard.Release(); NON_CONST_ITERATE(TStack, it, cur_Stack) { - (*it)->x_Cleanup(guard); - guard.Guard(CSafeStaticPtr_Base::sm_Mutex); + (*it)->x_Cleanup(); } + guard.Guard(CSafeStaticPtr_Base::sm_ClassMutex); } delete sm_Stack; diff --git a/c++/src/corelib/ncbi_stack.cpp b/c++/src/corelib/ncbi_stack.cpp index bad71b4f..49525aa7 100644 --- a/c++/src/corelib/ncbi_stack.cpp +++ b/c++/src/corelib/ncbi_stack.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_stack.cpp 500861 2016-05-09 16:32:20Z grichenk $ +/* $Id: ncbi_stack.cpp 536116 2017-05-15 20:46:38Z perkovan $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -38,7 +38,9 @@ # include // for additional test below #endif -#if defined NCBI_OS_MSWIN +#if defined HAVE_LIBUNWIND +# include "ncbi_stack_libunwind.cpp" +#elif defined NCBI_OS_MSWIN # if NCBI_PLATFORM_BITS == 64 # include "ncbi_stack_win64.cpp" # else diff --git a/c++/src/corelib/ncbi_stack_libunwind.cpp b/c++/src/corelib/ncbi_stack_libunwind.cpp new file mode 100644 index 00000000..4754ef3c --- /dev/null +++ b/c++/src/corelib/ncbi_stack_libunwind.cpp @@ -0,0 +1,120 @@ +/* $Id: ncbi_stack_libunwind.cpp 536269 2017-05-16 22:20:04Z perkovan $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Anton Perkov + * + */ + +#include +#define UNW_LOCAL_ONLY +#include +#if defined(HAVE_CXA_DEMANGLE) +# include +#endif +#include +#include + +BEGIN_NCBI_SCOPE + + +// Call this function to get a backtrace. +class CStackTraceImpl +{ +public: + CStackTraceImpl(void); + ~CStackTraceImpl(void); + + void Expand(CStackTrace::TStack& stack); + +private: + typedef void* TStackFrame; + typedef vector TStack; + + TStack m_Stack; +}; + + +CStackTraceImpl::CStackTraceImpl(void) +{ + m_Stack.resize(CStackTrace::s_GetStackTraceMaxDepth()); +} + + +CStackTraceImpl::~CStackTraceImpl(void) +{ +} + + +void CStackTraceImpl::Expand(CStackTrace::TStack& stack) +{ + unw_cursor_t cursor; + unw_context_t context; + + // Initialize cursor to current frame for local unwinding. + unw_getcontext(&context); + unw_init_local(&cursor, &context); + + // Unwind frames one by one, going up the frame stack. + while (unw_step(&cursor) > 0) { + CStackTrace::SStackFrameInfo info; + unw_word_t offset; + + char sym[256]; + if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0 && sym[0]) { + info.func = sym; + info.offs = offset; +#if defined(HAVE_CXA_DEMANGLE) + // use abi::__cxa_demangle + size_t len = 0; + char* buf = 0; + int status = 0; + buf = abi::__cxa_demangle(info.func.c_str(), + buf, &len, &status); + if ( !status ) { + info.func = buf; + free(buf); + } +#endif + } else { + info.func = "???"; + } + info.file = "???"; + + unw_proc_info_t u; + if (unw_get_proc_info(&cursor, &u) == 0) { + info.addr = (void*)(u.start_ip+offset); + if (info.addr) { + Dl_info dlinfo; + if (dladdr(info.addr, &dlinfo) != 0) { + info.module = dlinfo.dli_fname; + } + } + } + + stack.push_back(info); + } +} + +END_NCBI_SCOPE diff --git a/c++/src/corelib/ncbi_stack_linux.cpp b/c++/src/corelib/ncbi_stack_linux.cpp index c6dafb76..bd8cbc6b 100644 --- a/c++/src/corelib/ncbi_stack_linux.cpp +++ b/c++/src/corelib/ncbi_stack_linux.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_stack_linux.cpp 500861 2016-05-09 16:32:20Z grichenk $ +/* $Id: ncbi_stack_linux.cpp 536317 2017-05-17 15:37:03Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,7 +31,7 @@ #include #include -#if NCBI_COMPILER_VERSION >= 310 +#if defined(HAVE_CXA_DEMANGLE) # include #endif #include @@ -108,7 +108,7 @@ void CStackTraceImpl::Expand(CStackTrace::TStack& stack) // name demangling // if ( !info.func.empty() && info.func[0] == '_') { -#if NCBI_COMPILER_VERSION >= 310 +#if defined(HAVE_CXA_DEMANGLE) // use abi::__cxa_demangle size_t len = 0; char* buf = 0; diff --git a/c++/src/corelib/ncbi_stack_win32.cpp b/c++/src/corelib/ncbi_stack_win32.cpp index b69b5753..f07b6ef8 100644 --- a/c++/src/corelib/ncbi_stack_win32.cpp +++ b/c++/src/corelib/ncbi_stack_win32.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_stack_win32.cpp 500861 2016-05-09 16:32:20Z grichenk $ +/* $Id: ncbi_stack_win32.cpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -113,7 +113,7 @@ static bool s_FillModuleListTH32(TModules& modules, DWORD pid) }; const char* libname = dllname[0]; - auto_ptr dll; + unique_ptr dll; while (libname) { dll.reset(new CDll(libname, CDll::eLoadNow, CDll::eAutoUnload)); diff --git a/c++/src/corelib/ncbi_system.cpp b/c++/src/corelib/ncbi_system.cpp index f01663b4..96c86db1 100644 --- a/c++/src/corelib/ncbi_system.cpp +++ b/c++/src/corelib/ncbi_system.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_system.cpp 500405 2016-05-04 15:18:35Z ivanov $ +/* $Id: ncbi_system.cpp 525410 2017-01-24 15:14:24Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -65,6 +65,7 @@ extern "C" { # if defined(NCBI_OS_IRIX) # include # endif //NCBI_OS_IRIX +# include "ncbi_os_unix_p.hpp" # define USE_SETMEMLIMIT # define USE_SETCPULIMIT # define HAVE_MADVISE 1 @@ -87,6 +88,7 @@ extern "C" { # include # include # include +# include "ncbi_os_mswin_p.hpp" struct SProcessMemoryCounters { @@ -1210,4 +1212,16 @@ extern int GetProcessThreadCount(void) } +string GetProcessUserName(void) +{ +#if defined(NCBI_OS_UNIX) + return CUnixFeature::GetUserNameByUID(geteuid()); +#elif defined(NCBI_OS_MSWIN) + return CWinSecurity::GetUserName(); +#else + return string(); +#endif +} + + END_NCBI_SCOPE diff --git a/c++/src/corelib/ncbi_toolkit.cpp b/c++/src/corelib/ncbi_toolkit.cpp index e8cc30d9..c6d0803e 100644 --- a/c++/src/corelib/ncbi_toolkit.cpp +++ b/c++/src/corelib/ncbi_toolkit.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_toolkit.cpp 425986 2014-02-05 03:54:56Z lavr $ +/* $Id: ncbi_toolkit.cpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -201,8 +201,8 @@ public: ~CNcbiToolkit(void); private: - auto_ptr m_App; - auto_ptr m_DiagHandler; + unique_ptr m_App; + unique_ptr m_DiagHandler; }; diff --git a/c++/src/corelib/ncbi_url.cpp b/c++/src/corelib/ncbi_url.cpp index 4e9101b3..e8f12401 100644 --- a/c++/src/corelib/ncbi_url.cpp +++ b/c++/src/corelib/ncbi_url.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_url.cpp 518082 2016-10-31 17:19:46Z ivanov $ +/* $Id: ncbi_url.cpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -274,6 +274,26 @@ void CUrlArgs::SetValue(const string& name, const string& value) } +void CUrlArgs::AddValue(const string& name, const string& value) +{ + m_IsIndex = false; + m_Args.push_back(TArg(name, value)); +} + + +void CUrlArgs::SetUniqueValue(const string& name, const string& value) +{ + m_IsIndex = false; + iterator it = FindFirst(name); + while (it != m_Args.end()) { + iterator tmp = it; + it = FindNext(it); + m_Args.erase(tmp); + } + m_Args.push_back(TArg(name, value)); +} + + CUrlArgs::iterator CUrlArgs::x_Find(const string& name, const iterator& start) { @@ -331,6 +351,7 @@ CUrl& CUrl::operator=(const CUrl& url) m_User = url.m_User; m_Password = url.m_Password; m_Host = url.m_Host; + m_Service = url.m_Service; m_Port = url.m_Port; m_Path = url.m_Path; m_Fragment = url.m_Fragment; @@ -347,158 +368,147 @@ CUrl& CUrl::operator=(const CUrl& url) void CUrl::SetUrl(const string& orig_url, const IUrlEncoder* encoder) { - m_Scheme = kEmptyStr; + m_Scheme.clear(); m_IsGeneric = false; - m_User = kEmptyStr; - m_Password = kEmptyStr; - m_Host = kEmptyStr; - m_Port = kEmptyStr; - m_Path = kEmptyStr; - m_Fragment = kEmptyStr; - m_OrigArgs = kEmptyStr; + m_User.clear(); + m_Password.clear(); + m_Host.clear(); + m_Service.clear(); + m_Port.clear(); + m_Path.clear(); + m_Fragment.clear(); + m_OrigArgs.clear(); m_ArgsList.reset(); - string url; + string unparsed; if ( !encoder ) { encoder = GetDefaultEncoder(); } - SIZE_TYPE frag_pos = orig_url.find_last_of("#"); - if (frag_pos != NPOS) { - x_SetFragment(orig_url.substr(frag_pos + 1, orig_url.size()), *encoder); - url = orig_url.substr(0, frag_pos); - } - else { - url = orig_url; + // Special case - service name does not contain any URL reserved symbols + // (they must be URL-encoded). + if (orig_url.find_first_of(":/.?#") == NPOS) { + x_SetService(orig_url); + return; } - bool skip_host = false; - bool skip_path = false; - SIZE_TYPE beg = 0; - SIZE_TYPE pos = url.find_first_of(":@/?["); - - while ( beg < url.size() ) { - if (pos == NPOS) { - if ( !skip_host ) { - x_SetHost(url.substr(beg, url.size()), *encoder); - } - else if ( !skip_path ) { - x_SetPath(url.substr(beg, url.size()), *encoder); + // Parse scheme and authority (user info, host, port). + SIZE_TYPE pos = orig_url.find("//"); + SIZE_TYPE offset = 0; + string authority; + if (pos != NPOS) { + m_IsGeneric = true; + // Host is present, split into scheme/host/path. + if (pos > 0 && orig_url[pos - 1] == ':') { + // Scheme is present + x_SetScheme(orig_url.substr(0, pos - 1), *encoder); + } + pos += 2; + offset += pos; + unparsed = orig_url.substr(pos); + pos = unparsed.find_first_of("/?#"); + authority = unparsed.substr(0, pos); + if (pos != NPOS) { + unparsed = unparsed.substr(pos); + } + else { + unparsed.clear(); + } + string host; + pos = authority.find('@'); + if (pos != NPOS) { + offset += pos; + string user_info = authority.substr(0, pos); + host = authority.substr(pos + 1); + pos = user_info.find(':'); + if (pos != NPOS) { + x_SetUser(user_info.substr(0, pos), *encoder); + x_SetPassword(user_info.substr(pos + 1), *encoder); } else { - x_SetArgs(url.substr(beg, url.size()), *encoder); + x_SetUser(user_info, *encoder); } - break; - } - switch ( url[pos] ) { - case '[': // IPv6 address - { - SIZE_TYPE closing = url.find(']', pos); - if (closing == NPOS) { - NCBI_THROW2(CUrlParserException, eFormat, - "Unmatched '[' in the URL: \"" + url + "\"", pos); - } - beg = pos; - pos = url.find_first_of(":/?", closing); - break; + } + else { + host = authority; + } + string port; + // Find port position, if any. Take IPv6 into account. + if (!host.empty() && host[0] == '[') { + // IPv6 address - skip to the closing ] + pos = host.find(']'); + if (pos == NPOS) { + NCBI_THROW2(CUrlParserException, eFormat, + "Unmatched '[' in the URL: \"" + orig_url + "\"", pos + offset); } - case ':': // scheme: || user:password || host:port - { - if (url.substr(pos, 3) == "://") { - // scheme:// - x_SetScheme(url.substr(beg, pos - beg), *encoder); - beg = pos + 3; - m_IsGeneric = true; - if (m_Scheme == "file") { - // Special case - no further parsing, use the whole - // string as path. - x_SetPath(url.substr(beg), *encoder); - return; - } - pos = url.find_first_of(":@/?[", beg); - break; - } - // user:password@ || host:port... - SIZE_TYPE next = url.find_first_of("@/?[", pos + 1); - if (m_IsGeneric && next != NPOS && url[next] == '@') { - // user:password@ - x_SetUser(url.substr(beg, pos - beg), *encoder); - beg = pos + 1; - x_SetPassword(url.substr(beg, next - beg), *encoder); - beg = next + 1; - pos = url.find_first_of(":/?[", beg); - break; - } - // host:port || host:port/path || host:port?args - string host = url.substr(beg, pos - beg); - beg = pos + 1; - if (next == NPOS) { - next = url.size(); - } - try { - x_SetPort(url.substr(beg, next - beg), *encoder); - if ( !skip_host ) { - x_SetHost(host, *encoder); - } - } - catch (CStringException) { - if ( !m_IsGeneric ) { - x_SetScheme(host, *encoder); - x_SetPath(url.substr(beg, url.size()), *encoder); - beg = url.size(); - continue; - } - else { - NCBI_THROW2(CUrlParserException, eFormat, - "Invalid port value: \"" + url + "\"", beg+1); - } - } - skip_host = true; - beg = next; - if (next < url.size() && url[next] == '/') { - pos = url.find_first_of("?", beg); - } - else { - skip_path = true; - pos = next; - } - break; + if (pos + 1 < host.size() && host[pos + 1] == ':') { + pos++; } - case '@': // username@host - { - x_SetUser(url.substr(beg, pos - beg), *encoder); - beg = pos + 1; - pos = url.find_first_of(":/?[", beg); - break; + else { + pos = NPOS; } - case '/': // host/path - { - if ( !skip_host ) { - x_SetHost(url.substr(beg, pos - beg), *encoder); - skip_host = true; - } - beg = pos; - pos = url.find_first_of("?", beg); - break; + } + else { + pos = host.find(':'); + } + if (pos != NPOS) { + // Found port - make sure it's numeric. + try { + x_SetPort(host.substr(pos + 1), *encoder); } - case '?': - { - if ( !skip_host ) { - x_SetHost(url.substr(beg, pos - beg), *encoder); - skip_host = true; - } - else { - x_SetPath(url.substr(beg, pos - beg), *encoder); - skip_path = true; - } - beg = pos + 1; - x_SetArgs(url.substr(beg, url.size()), *encoder); - beg = url.size(); - pos = NPOS; - break; + catch (CStringException) { + NCBI_THROW2(CUrlParserException, eFormat, + "Invalid port value: \"" + orig_url + "\"", pos + 1); } + host.resize(pos); + } + if (NStr::EqualNocase(m_Scheme, NCBI_SCHEME_SERVICE)) { + x_SetService(host); + } + else { + x_SetHost(host, *encoder); + } + } + else { + // No authority, check scheme. + SIZE_TYPE scheme_end = orig_url.find(':'); + if (scheme_end != NPOS) { + x_SetScheme(orig_url.substr(0, scheme_end), *encoder); + unparsed = orig_url.substr(scheme_end + 1); } + else { + unparsed = orig_url; + } + } + + if ( unparsed.empty() ) return; + if (unparsed[0] == '/') { + // Path present + pos = unparsed.find_first_of("?#"); + x_SetPath(unparsed.substr(0, pos), *encoder); + // No args/fragment + if (pos == NPOS) return; + unparsed = unparsed.substr(pos); + } + + _ASSERT(!unparsed.empty()); + if (unparsed[0] == '?') { + // Arguments + pos = unparsed.find('#'); + x_SetArgs(unparsed.substr(1, pos - 1), *encoder); + if (pos == NPOS) return; + unparsed = unparsed.substr(pos); + } + // Fragment + _ASSERT(!unparsed.empty()); + if (unparsed[0] == '#') { + x_SetFragment(unparsed.substr(1), *encoder); + } + else { + // Non-generic URL - path does not contain /, no args or fragment. + // E.g. scheme:foo:bar + x_SetPath(unparsed, *encoder); } } @@ -512,25 +522,31 @@ string CUrl::ComposeUrl(CUrlArgs::EAmpEncoding amp_enc, string url; if ( !m_Scheme.empty() ) { url += m_Scheme; - url += m_IsGeneric ? "://" : ":"; + url += ":"; } - if ( !m_Host.empty() ) { - bool use_auth = false; - if ( !m_User.empty() ) { - url += encoder->EncodeUser(m_User); - use_auth = true; - } - if ( !m_Password.empty() ) { - url += ":" + encoder->EncodePassword(m_Password); - use_auth = true; - } - if ( use_auth ) { - url += "@"; - } + if (m_IsGeneric) { + url += "//"; + } + bool have_user_info = false; + if ( !m_User.empty() ) { + url += encoder->EncodeUser(m_User); + have_user_info = true; + } + if ( !m_Password.empty() ) { + url += ":" + encoder->EncodePassword(m_Password); + have_user_info = true; + } + if ( have_user_info ) { + url += "@"; + } + if ( !m_Service.empty() ) { + url += NStr::URLEncode(m_Service, NStr::eUrlEnc_ProcessMarkChars); + } + else if ( !m_Host.empty() ) { url += m_Host; - if ( !m_Port.empty() ) { - url += ":" + m_Port; - } + } + if ( !m_Port.empty() ) { + url += ":" + m_Port; } url += encoder->EncodePath(m_Path); if ( HaveArgs() ) { @@ -553,6 +569,115 @@ const CUrlArgs& CUrl::GetArgs(void) const } +void CUrl::Adjust(const CUrl& other, TAdjustFlags flags) +{ + static const int fUser_Mask = fUser_Replace | fUser_ReplaceIfEmpty; + static const int fPassword_Mask = fPassword_Replace | fPassword_ReplaceIfEmpty; + static const int fPath_Mask = fPath_Replace | fPath_Append; + static const int fFragment_Mask = fFragment_Replace | fFragment_ReplaceIfEmpty; + static const int fArgs_Mask = fArgs_Replace | fArgs_Append | fArgs_Merge; + + if ((flags & fUser_Mask) == fUser_Mask) { + NCBI_THROW(CUrlException, eFlags, "Multiple fUser_* flags are set."); + } + if ( !other.m_User.empty() ) { + if ((flags & fUser_ReplaceIfEmpty) && m_User.empty()) { + m_User = other.m_User; + } + else if (flags & fUser_Replace) { + m_User = other.m_User; + } + } + + if ((flags & fPassword_Mask) == fPassword_Mask) { + NCBI_THROW(CUrlException, eFlags, "Multiple fPassword_* flags are set."); + } + if ( !other.m_Password.empty() ) { + if ((flags & fPassword_ReplaceIfEmpty) && m_Password.empty()) { + m_Password = other.m_Password; + } + else if (flags & fPassword_Replace) { + m_Password = other.m_Password; + } + } + + if ((flags & fPath_Mask) == fPath_Mask) { + NCBI_THROW(CUrlException, eFlags, "Multiple fPath_* flags are set."); + } + if (flags & fPath_Replace) { + m_Path = other.m_Path; + } + else if ((flags & fPath_Append) && !other.m_Path.empty()) { + if ( m_Path.empty() ) { + m_Path = other.m_Path; + } + else { + size_t other_p = 0; + if (m_Path.back() == '/' && other.m_Path.front() == '/') { + other_p = 1; + } + m_Path.append(other.m_Path.substr(other_p)); + } + } + + if ((flags & fFragment_Mask) == fFragment_Mask) { + NCBI_THROW(CUrlException, eFlags, "Multiple fFragment_* flags are set."); + } + if ( !other.m_Fragment.empty() ) { + if ((flags & fFragment_ReplaceIfEmpty) && m_Fragment.empty()) { + m_Fragment = other.m_Fragment; + } + else if (flags & fFragment_Replace) { + m_Fragment = other.m_Fragment; + } + } + + switch (flags & fArgs_Mask) { + case 0: + break; + case fArgs_Replace: + m_OrigArgs = other.m_OrigArgs; + if ( other.m_ArgsList.get() ) { + m_ArgsList.reset(new CUrlArgs(*other.m_ArgsList)); + } else { + m_ArgsList.reset(); + } + break; + case fArgs_Append: + if ( other.m_ArgsList.get() ) { + if ( m_ArgsList.get() ) { + ITERATE(CUrlArgs::TArgs, it, other.m_ArgsList->GetArgs()) { + m_ArgsList->AddValue(it->name, it->value); + } + } + else { + m_ArgsList.reset(new CUrlArgs(*other.m_ArgsList)); + } + } + break; + case fArgs_Merge: + { + unique_ptr args(m_ArgsList.release()); + m_ArgsList.reset(new CUrlArgs()); + if ( args.get() ) { + // Copy existing arguments, if any, removing duplicate entries. + ITERATE(CUrlArgs::TArgs, it, args->GetArgs()) { + m_ArgsList->SetUniqueValue(it->name, it->value); + } + } + if ( other.m_ArgsList.get() ) { + ITERATE(CUrlArgs::TArgs, it, other.m_ArgsList->GetArgs()) { + m_ArgsList->SetUniqueValue(it->name, it->value); + } + } + break; + } + default: + // Several flags are set. + NCBI_THROW(CUrlException, eFlags, "Multiple fArgs_* flags are set."); + } +} + ////////////////////////////////////////////////////////////////////////////// // @@ -568,8 +693,8 @@ IUrlEncoder* CUrl::GetDefaultEncoder(void) bool CUrl::IsEmpty(void) const { - // At least one of host or path must be present. - return m_Host.empty() && m_Path.empty(); + // At least one of host, service or path must be present. + return m_Host.empty() && m_Service.empty() && m_Path.empty(); } diff --git a/c++/src/corelib/ncbi_version.xsd b/c++/src/corelib/ncbi_version.xsd new file mode 100644 index 00000000..f0c97795 --- /dev/null +++ b/c++/src/corelib/ncbi_version.xsd @@ -0,0 +1,95 @@ + + + + + + + $Id: ncbi_version.xsd 523179 2016-12-29 14:03:50Z grichenk $ + =========================================================================== + + PUBLIC DOMAIN NOTICE + National Center for Biotechnology Information + + This software/database is a "United States Government Work" under the + terms of the United States Copyright Act. It was written as part of + the author's official duties as a United States Government employee and + thus cannot be copyrighted. This software/database is freely available + to the public for use. The National Library of Medicine and the U.S. + Government have not placed any restriction on its use or reproduction. + + Although all reasonable efforts have been taken to ensure the accuracy + and reliability of the software and data, the NLM and the U.S. + Government do not and cannot warrant the performance or results that + may be obtained by using this software or data. The NLM and the U.S. + Government disclaim all warranties, express or implied, including + warranties of performance, merchantability or fitness for any particular + purpose. + + Please cite the author in any work or product based on this material. + + =========================================================================== + + Author: Aleksey Grichenko + + File Description: + Defines format of CVersion::PrintXml() output. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/c++/src/corelib/ncbiapp.cpp b/c++/src/corelib/ncbiapp.cpp index 6ab34acc..3c802a57 100644 --- a/c++/src/corelib/ncbiapp.cpp +++ b/c++/src/corelib/ncbiapp.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbiapp.cpp 518670 2016-11-07 15:25:48Z ivanov $ +/* $Id: ncbiapp.cpp 536050 2017-05-15 16:18:35Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -107,6 +107,7 @@ CNcbiApplication::CNcbiApplication(const SBuildInfo& build_info) m_LogFile(0), m_LogOptions(0) { + CThread::InitializeMainThreadId(); // Initialize UID and start timer GetDiagContext().GetUID(); GetDiagContext().InitMessages(size_t(-1)); @@ -324,7 +325,7 @@ void CNcbiApplication::x_TryInit(EAppDiagStream diag, // If the app still has no arg description - provide default one if (!m_DisableArgDesc && !m_ArgDesc.get()) { - auto_ptr arg_desc(new CArgDescriptions); + unique_ptr arg_desc(new CArgDescriptions); arg_desc->SetUsageContext (GetArguments().GetProgramBasename(), "This program has no mandatory arguments"); @@ -1193,6 +1194,7 @@ void CNcbiApplication::x_AddDefaultArgs(void) void CNcbiApplication::SetProgramDisplayName(const string& app_name) { + if (app_name.empty()) return; m_ProgramDisplayName = app_name; // Also set app_name in the diag context if ( GetDiagContext().GetAppName().empty() ) { @@ -1449,6 +1451,11 @@ void CNcbiApplication::x_HonorStandardSettings( IRegistry* reg) } } + // [DEBUG.GuardAgainstThreadsOnStaticDataDestruction] + if ( !reg->GetBool("DEBUG", "GuardAgainstThreadsOnStaticDataDestruction", true, 0, IRegistry::eErrPost) ) { + CSafeStaticGuard::DisableChildThreadsCheck(); + } + // CPU and memory limitations // [NCBI.HeapSizeLimit] diff --git a/c++/src/corelib/ncbiargs.cpp b/c++/src/corelib/ncbiargs.cpp index 9bb0822b..a3fa28cc 100644 --- a/c++/src/corelib/ncbiargs.cpp +++ b/c++/src/corelib/ncbiargs.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbiargs.cpp 500405 2016-05-04 15:18:35Z ivanov $ +/* $Id: ncbiargs.cpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -2229,7 +2229,7 @@ void CArgDescriptions::AddKey EType type, TFlags flags) { - auto_ptr arg(new CArgDesc_Key(name, + unique_ptr arg(new CArgDesc_Key(name, comment, type, flags, synopsis)); x_AddDesc(*arg); @@ -2244,7 +2244,7 @@ void CArgDescriptions::AddOptionalKey EType type, TFlags flags) { - auto_ptr arg(new CArgDesc_KeyOpt(name, + unique_ptr arg(new CArgDesc_KeyOpt(name, comment, type, flags, synopsis)); x_AddDesc(*arg); @@ -2262,7 +2262,7 @@ void CArgDescriptions::AddDefaultKey const string& env_var, const char* display_value) { - auto_ptr arg(new CArgDesc_KeyDef(name, + unique_ptr arg(new CArgDesc_KeyDef(name, comment, type, flags, synopsis, default_value, env_var, display_value)); x_AddDesc(*arg); @@ -2275,7 +2275,7 @@ void CArgDescriptions::AddFlag( const string& comment, CBoolEnum set_value) { - auto_ptr arg(new CArgDesc_Flag(name, comment, set_value == eFlagHasValueIfSet)); + unique_ptr arg(new CArgDesc_Flag(name, comment, set_value == eFlagHasValueIfSet)); x_AddDesc(*arg); arg.release(); } @@ -2287,7 +2287,7 @@ void CArgDescriptions::AddPositional( EType type, TFlags flags) { - auto_ptr arg(new CArgDesc_Pos(name, comment, type, flags)); + unique_ptr arg(new CArgDesc_Pos(name, comment, type, flags)); x_AddDesc(*arg); arg.release(); @@ -2300,7 +2300,7 @@ void CArgDescriptions::AddOpening( EType type, TFlags flags) { - auto_ptr arg(new CArgDesc_Opening(name, comment, type, flags)); + unique_ptr arg(new CArgDesc_Opening(name, comment, type, flags)); x_AddDesc(*arg); arg.release(); @@ -2313,7 +2313,7 @@ void CArgDescriptions::AddOptionalPositional( EType type, TFlags flags) { - auto_ptr arg + unique_ptr arg (new CArgDesc_PosOpt(name, comment, type, flags)); x_AddDesc(*arg); @@ -2330,7 +2330,7 @@ void CArgDescriptions::AddDefaultPositional( const string& env_var, const char* display_value) { - auto_ptr arg(new CArgDesc_PosDef(name, + unique_ptr arg(new CArgDesc_PosDef(name, comment, type, flags, default_value, env_var, display_value)); x_AddDesc(*arg); @@ -2357,7 +2357,7 @@ void CArgDescriptions::AddExtra( m_nExtra = n_mandatory; m_nExtraOpt = n_optional; - auto_ptr arg + unique_ptr arg (m_nExtra ? new CArgDesc_Pos (kEmptyStr, comment, type, flags) : new CArgDesc_PosOpt(kEmptyStr, comment, type, flags)); @@ -2370,7 +2370,7 @@ void CArgDescriptions::AddExtra( void CArgDescriptions::AddAlias(const string& alias, const string& arg_name) { - auto_ptrarg + unique_ptrarg (new CArgDesc_Alias(alias, arg_name, kEmptyStr)); x_AddDesc(*arg); @@ -2389,7 +2389,7 @@ void CArgDescriptions::AddNegatedFlagAlias(const string& alias, "Attempt to negate a non-flag argument: " + arg_name); } - auto_ptr arg(new CArgDesc_Alias(alias, arg_name, comment)); + unique_ptr arg(new CArgDesc_Alias(alias, arg_name, comment)); arg->SetNegativeFlag(true); x_AddDesc(*arg); diff --git a/c++/src/corelib/ncbidiag.cpp b/c++/src/corelib/ncbidiag.cpp index 617bd3b6..b7b5b049 100644 --- a/c++/src/corelib/ncbidiag.cpp +++ b/c++/src/corelib/ncbidiag.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbidiag.cpp 519554 2016-11-16 16:33:59Z ivanov $ +/* $Id: ncbidiag.cpp 536050 2017-05-15 16:18:35Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -64,7 +64,7 @@ BEGIN_NCBI_SCOPE static bool s_DiagUseRWLock = true; DEFINE_STATIC_MUTEX(s_DiagMutex); DEFINE_STATIC_MUTEX(s_DiagPostMutex); -static CSafeStatic s_DiagRWLock; +static CSafeStatic s_DiagRWLock(CSafeStaticLifeSpan(CSafeStaticLifeSpan::eLifeSpan_Long, 1)); static CSafeStatic s_ReopenEntered; DEFINE_STATIC_FAST_MUTEX(s_ApproveMutex); @@ -930,7 +930,7 @@ CDiagContextThreadData& CDiagContextThreadData::GetThreadData(void) // upon TLS cleanup. data = new CDiagContextThreadData; s_ThreadData.SetValue(data, CDiagContext::sx_ThreadDataTlsCleanup, - CThread::GetSelf() ? 0 : (void*)(1)); + !CThread::IsMain() ? 0 : (void*)(1)); } s_ThreadDataState = eInitialized; @@ -1958,6 +1958,24 @@ void CDiagContext::PrintStart(const string& message) // Print extra message. If ncbi_role and/or ncbi_location are set, // they will be logged by this extra. Otherwise nothing will be printed. Extra().PrintNcbiRoleAndLocation().Flush(); + + static const char* kCloudIdFile = "/etc/ncbi/cloudid"; + CFile cloudid(kCloudIdFile); + if ( cloudid.Exists() ) { + CDiagContext_Extra ex = Extra(); + CNcbiIfstream in(kCloudIdFile); + while (!in.eof() && in.good()) { + string s; + getline(in, s); + size_t sep = s.find('\t'); + if (sep == NPOS) continue; + string name = NStr::TruncateSpaces(s.substr(0, sep)); + string value = s.substr(sep + 1); + ex.Print(name, value); + } + ex.Flush(); + } + // Log hit id if already available. x_GetDefaultHitID(eHitID_NoCreate); } @@ -2102,7 +2120,7 @@ void CDiagContext_Extra::Flush(void) } } - auto_ptr ostr; + unique_ptr ostr; string s; if (m_EventType == SDiagMessage::eEvent_PerfLog) { ostr.reset(new CNcbiOstrstream); @@ -2644,15 +2662,15 @@ inline string s_ReadString(const char* filename) } -static CSafeStatic< auto_ptr > s_HostRole; -static CSafeStatic< auto_ptr > s_HostLocation; +static CSafeStatic< unique_ptr > s_HostRole; +static CSafeStatic< unique_ptr > s_HostLocation; const string& CDiagContext::GetHostRole(void) { if ( !s_HostRole->get() ) { CDiagLock lock(CDiagLock::eWrite); if ( !s_HostRole->get() ) { - auto_ptr role(new string); + unique_ptr role(new string); *role = s_ReadString("/etc/ncbi/role"); s_HostRole->reset(role.release()); } @@ -2666,7 +2684,7 @@ const string& CDiagContext::GetHostLocation(void) if ( !s_HostLocation->get() ) { CDiagLock lock(CDiagLock::eWrite); if ( !s_HostLocation->get() ) { - auto_ptr loc(new string); + unique_ptr loc(new string); *loc = s_ReadString("/etc/ncbi/location"); s_HostLocation->reset(loc.release()); } @@ -2943,7 +2961,7 @@ void CDiagContext::FlushMessages(CDiagHandler& handler) // Tee over STDERR - flushing will create duplicate messages return; } - auto_ptr tmp(m_Messages.release()); + unique_ptr tmp(m_Messages.release()); //ERR_POST_X(1, Note << "***** BEGIN COLLECTED MESSAGES *****"); NON_CONST_ITERATE(TMessages, it, *tmp.get()) { it->m_NoTee = true; // Do not tee duplicate messages to console. @@ -3707,7 +3725,7 @@ void CDiagBuffer::Flush(void) string message = CNcbiOstrstreamToString(*m_Stream); // Can not use Reset() without CNcbiDiag. m_Stream->rdbuf()->PUBSEEKOFF(0, IOS_BASE::beg, IOS_BASE::out); - _TRACE("Discarding junk data from CDiagBuffer: " << message); + // _TRACE("Discarding junk data from CDiagBuffer: " << message); } return; } @@ -4599,8 +4617,8 @@ void SDiagMessage::ParseDiagStream(CNcbiIstream& in, { string msg_str, line, last_msg_str; bool res = false; - auto_ptr msg; - auto_ptr last_msg; + unique_ptr msg; + unique_ptr last_msg; while ( in.good() ) { getline(in, line); // Dirty check for PID/TID/RID @@ -6137,7 +6155,7 @@ void CFileDiagHandler::SetOwnership(CStreamDiagHandler_Base* handler, bool own) static bool s_CreateHandler(const string& fname, - auto_ptr& handler) + unique_ptr& handler) { if ( fname.empty() || fname == "/dev/null") { handler.reset(); @@ -6147,7 +6165,7 @@ s_CreateHandler(const string& fname, handler.reset(new CStreamDiagHandler(&NcbiCerr, true, kLogName_Stderr)); return true; } - auto_ptr fh(new CFileHandleDiagHandler(fname)); + unique_ptr fh(new CFileHandleDiagHandler(fname)); if ( !fh->Valid() ) { ERR_POST_X(7, Info << "Failed to open log file: " << fname); return false; @@ -6162,8 +6180,8 @@ bool CFileDiagHandler::SetLogFile(const string& file_name, bool /*quick_flush*/) { bool special = s_IsSpecialLogName(file_name); - auto_ptr err_handler, log_handler, - trace_handler, perf_handler; + unique_ptr err_handler, log_handler, + trace_handler, perf_handler; switch ( file_type ) { case eDiagFile_All: { @@ -6839,7 +6857,7 @@ extern bool SetLogFile(const string& file_name, } else { // output to file - auto_ptr fhandler(new CFileDiagHandler()); + unique_ptr fhandler(new CFileDiagHandler()); if ( !fhandler->SetLogFile(file_name, eDiagFile_All, quick_flush) ) { ERR_POST_X(9, Info << "Failed to initialize log: " << file_name); return false; @@ -6858,7 +6876,7 @@ extern bool SetLogFile(const string& file_name, old_ownership = false; } // Install new handler, try to re-use the old one - auto_ptr fhandler(new CFileDiagHandler()); + unique_ptr fhandler(new CFileDiagHandler()); if ( sub_handler && file_type != eDiagFile_All) { // If we are going to set all handlers, no need to save the old one. if ( old_ownership ) { diff --git a/c++/src/corelib/ncbierror.cpp b/c++/src/corelib/ncbierror.cpp index dbf1215b..24c5ae7c 100644 --- a/c++/src/corelib/ncbierror.cpp +++ b/c++/src/corelib/ncbierror.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbierror.cpp 511430 2016-08-22 15:25:37Z ivanov $ +/* $Id: ncbierror.cpp 510803 2016-08-16 13:57:32Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/corelib/ncbiexec.cpp b/c++/src/corelib/ncbiexec.cpp index 4a29d6e4..c5c518ba 100644 --- a/c++/src/corelib/ncbiexec.cpp +++ b/c++/src/corelib/ncbiexec.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbiexec.cpp 486111 2015-12-01 17:17:39Z grichenk $ +/* $Id: ncbiexec.cpp 544803 2017-08-28 14:35:55Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -600,7 +600,7 @@ CExec::SpawnLPE(EMode mode, const char *cmdname, const char *argv, ...) #if defined(NCBI_OS_MSWIN) _flushall(); - status = NcbiSys_spawnve(s_GetRealMode(mode), _T_XCSTRING(cmdname), a_args, a_envs); + status = NcbiSys_spawnvpe(s_GetRealMode(mode), _T_XCSTRING(cmdname), a_args, a_envs); #elif defined(NCBI_OS_UNIX) status = s_SpawnUnix(eVPE, mode, cmdname, a_args, a_envs); #endif diff --git a/c++/src/corelib/ncbiexpt.cpp b/c++/src/corelib/ncbiexpt.cpp index 6f39bff7..e10f939c 100644 --- a/c++/src/corelib/ncbiexpt.cpp +++ b/c++/src/corelib/ncbiexpt.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbiexpt.cpp 476589 2015-08-20 13:11:52Z grichenk $ +/* $Id: ncbiexpt.cpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -653,7 +653,7 @@ void CExceptionReporter::ReportDefaultEx(int err_code, int err_subcode, return; const CException* cex = dynamic_cast(&ex); - auto_ptr wrapper; + unique_ptr wrapper; if ( !cex ) { wrapper.reset(new CExceptionWrapper(info, ex)); cex = wrapper.get(); @@ -742,7 +742,7 @@ const char* CInvalidParamException::GetErrCodeString(void) const { switch (GetErrCode()) { case eUndefined: return "eUndefined"; - case eInvalidCharacter: return "eNullPtr"; + case eInvalidCharacter: return "eInvalidCharacter"; default: return CException::GetErrCodeString(); } } diff --git a/c++/src/corelib/ncbifile.cpp b/c++/src/corelib/ncbifile.cpp index d5ac7ce0..9582b24f 100644 --- a/c++/src/corelib/ncbifile.cpp +++ b/c++/src/corelib/ncbifile.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbifile.cpp 515654 2016-10-04 18:38:59Z ivanov $ +/* $Id: ncbifile.cpp 546190 2017-09-14 16:01:12Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,6 @@ #if defined(NCBI_OS_MSWIN) # include "ncbi_os_mswin_p.hpp" -# include # include # include # include // for _O_* flags @@ -181,46 +181,46 @@ NCBI_PARAM_DEF_EX(bool, NCBI, FileAPILogging, DEFAULT_LOGGING_VALUE, eParam_NoThread, NCBI_CONFIG__FILEAPILOGGING); -#define LOG_ERROR(log_message) \ +#define LOG_ERROR(subcode, log_message) \ { \ int saved_error = errno; \ if (NCBI_PARAM_TYPE(NCBI, FileAPILogging)::GetDefault()) { \ - ERR_POST(log_message << ": " << _T_STDSTRING(NcbiSys_strerror(saved_error))); \ - } \ + ERR_POST_X(subcode, log_message << ": " << _T_STDSTRING(NcbiSys_strerror(saved_error))); \ + } \ errno = saved_error; \ } -#define LOG_ERROR_AND_RETURN(log_message) \ +#define LOG_ERROR_AND_RETURN(subcode, log_message) \ { \ if (NCBI_PARAM_TYPE(NCBI, FileAPILogging)::GetDefault()) { \ - ERR_POST(log_message); \ - } \ + ERR_POST_X(subcode, log_message); \ + } \ return false; \ } -#define LOG_ERROR_AND_RETURN_NCBI(log_message, ncbierr) \ +#define LOG_ERROR_AND_RETURN_NCBI(subcode, log_message, ncbierr) \ { \ if (NCBI_PARAM_TYPE(NCBI, FileAPILogging)::GetDefault()) { \ - ERR_POST(log_message); \ - } \ + ERR_POST_X(subcode, log_message); \ + } \ CNcbiError::Set(ncbierr, log_message); \ return false; \ } -#define LOG_ERROR_AND_RETURN_WIN(log_message) \ +#define LOG_ERROR_AND_RETURN_WIN(subcode, log_message) \ { \ if (NCBI_PARAM_TYPE(NCBI, FileAPILogging)::GetDefault()) { \ - ERR_POST(log_message); \ - } \ + ERR_POST_X(subcode, log_message); \ + } \ CNcbiError::SetFromWindowsError(log_message); \ return false; \ } -#define LOG_ERROR_AND_RETURN_ERRNO(log_message) \ +#define LOG_ERROR_AND_RETURN_ERRNO(subcode, log_message) \ { \ int saved_error = errno; \ if (NCBI_PARAM_TYPE(NCBI, FileAPILogging)::GetDefault()) { \ - ERR_POST(log_message << ": " << _T_STDSTRING(NcbiSys_strerror(saved_error))); \ + ERR_POST_X(subcode, log_message << ": " << _T_STDSTRING(NcbiSys_strerror(saved_error))); \ } \ CNcbiError::SetErrno(saved_error, log_message); \ errno = saved_error; \ @@ -326,6 +326,10 @@ CDirEntry::TMode CDirEntry::m_DefaultModeGlobal[eUnknown][4] = // Default backup suffix const char* CDirEntry::m_BackupSuffix = ".bak"; +// Part of the temporary name used for "safe copy" +static const char* kTmpSafeSuffix = ".tmp."; + + CDirEntry& CDirEntry::operator= (const CDirEntry& other) { @@ -531,6 +535,24 @@ bool CDirEntry::IsAbsolutePathEx(const string& path) } +string CDirEntry::GetNearestExistingParentDir(const string& path) +{ + CDirEntry entry(NormalizePath(path)); + + // Find closest existing directory + while (!entry.Exists()) { + string dir = entry.GetDir(); + if (dir.empty()) { + NCBI_THROW(CFileException, eNotExists, + "Failed to find existing containing directory for: " + + entry.GetPath()); + } + entry.Reset(dir); + } + return entry.GetPath(); +} + + /// Helper -- strips dir to parts: /// c:\a\b\ will be /// /usr/bin/ will be @@ -548,25 +570,21 @@ static void s_StripDir(const string& dir, vector * dir_parts) for (;;) { sep_pos = dir.find(sep, sep_pos); if (sep_pos == NPOS) { - dir_parts->push_back(string(dir, part_start, - dir.length() - part_start)); + dir_parts->push_back(string(dir, part_start, dir.length() - part_start)); break; } - // If path starts from '/' - it's a root directory if (sep_pos == 0) { dir_parts->push_back(string(1, sep)); } else { - dir_parts->push_back(string(dir, part_start, sep_pos -part_start)); + dir_parts->push_back(string(dir, part_start, sep_pos - part_start)); } - sep_pos++; part_start = sep_pos; if (sep_pos >= last_ind) { break; } } - } @@ -576,13 +594,11 @@ string CDirEntry::CreateRelativePath( const string& path_from, string path; // the result if ( !IsAbsolutePath(path_from) ) { - NCBI_THROW(CFileException, eRelativePath, - "path_from is not absolute path"); + NCBI_THROW(CFileException, eRelativePath, "path_from is not absolute path"); } if ( !IsAbsolutePath(path_to) ) { - NCBI_THROW(CFileException, eRelativePath, - "path_to is not absolute path"); + NCBI_THROW(CFileException, eRelativePath, "path_to is not absolute path"); } // Split and strip FROM @@ -591,8 +607,7 @@ string CDirEntry::CreateRelativePath( const string& path_from, vector dir_from_parts; s_StripDir(dir_from, &dir_from_parts); if ( dir_from_parts.empty() ) { - NCBI_THROW(CFileException, eRelativePath, - "path_from is empty path"); + NCBI_THROW(CFileException, eRelativePath, "path_from is empty path"); } // Split and strip TO @@ -603,8 +618,7 @@ string CDirEntry::CreateRelativePath( const string& path_from, vector dir_to_parts; s_StripDir(dir_to, &dir_to_parts); if ( dir_to_parts.empty() ) { - NCBI_THROW(CFileException, eRelativePath, - "path_to is empty path"); + NCBI_THROW(CFileException, eRelativePath, "path_to is empty path"); } // Platform-dependent compare mode @@ -618,16 +632,13 @@ string CDirEntry::CreateRelativePath( const string& path_from, if (NStr::Compare(dir_from_parts.front(), dir_to_parts.front(), DIR_PARTS_CMP_MODE) != 0) { - NCBI_THROW(CFileException, eRelativePath, - "roots of input paths are different"); + NCBI_THROW(CFileException, eRelativePath, "roots of input paths are different"); } size_t min_parts = min(dir_from_parts.size(), dir_to_parts.size()); size_t common_length = min_parts; for (size_t i = 0; i < min_parts; i++) { - if (NStr::Compare(dir_from_parts[i], - dir_to_parts[i], - DIR_PARTS_CMP_MODE) != 0) { + if (NStr::Compare(dir_from_parts[i], dir_to_parts[i], DIR_PARTS_CMP_MODE) != 0) { common_length = i; break; } @@ -649,9 +660,8 @@ string CDirEntry::CreateRelativePath( const string& path_from, string CDirEntry::CreateAbsolutePath(const string& path, ERelativeToWhat rtw) { if ( IsAbsolutePath(path) ) { - return path; + return NormalizePath(path); } - string result; #if defined(NCBI_OS_MSWIN) @@ -676,32 +686,29 @@ string CDirEntry::CreateAbsolutePath(const string& path, ERelativeToWhat rtw) #endif switch (rtw) { - case eRelativeToCwd: - result = ConcatPath(CDir::GetCwd(), path); - break; - case eRelativeToExe: - { - string dir; - SplitPath(CNcbiApplication::GetAppName(CNcbiApplication::eFullName), - &dir); - result = ConcatPath(dir, path); - if ( !CDirEntry(result).Exists() ) { - SplitPath(CNcbiApplication::GetAppName(CNcbiApplication::eRealName), - &dir); + case eRelativeToCwd: + result = ConcatPath(CDir::GetCwd(), path); + break; + case eRelativeToExe: + { + string dir; + SplitPath(CNcbiApplication::GetAppName(CNcbiApplication::eFullName), &dir); result = ConcatPath(dir, path); - } - break; - } + if ( !CDirEntry(result).Exists() ) { + SplitPath(CNcbiApplication::GetAppName(CNcbiApplication::eRealName), &dir); + result = ConcatPath(dir, path); + } + break; + } } - result = NormalizePath(result); - return result; + return NormalizePath(result); } string CDirEntry::CreateAbsolutePath(const string& path, const string& rtw) { - if (IsAbsolutePath(path)) { - return path; + if ( IsAbsolutePath(path) ) { + return NormalizePath(path); } #if defined(NCBI_OS_MSWIN) @@ -727,8 +734,6 @@ string CDirEntry::CreateAbsolutePath(const string& path, const string& rtw) "2nd parameter must represent absolute path: " + rtw); } return NormalizePath(ConcatPath(rtw, path)); - - } @@ -943,8 +948,7 @@ string CDirEntry::NormalizePath(const string& path, EFollowLinks follow_links) // Special cases if ( (head.size() == 0) || - (head.size() == 2 && head.front() == DIR_CURRENT && - head.back().empty()) ) { + (head.size() == 2 && head.front() == DIR_CURRENT && head.back().empty()) ) { // current dir return DIR_CURRENT; } @@ -962,8 +966,7 @@ bool CDirEntry::GetMode(TMode* user_mode, TMode* group_mode, { TNcbiSys_stat st; if (NcbiSys_stat(_T_XCSTRING(GetPath()), &st) != 0) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::GetMode():" - " stat() failed for " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(5, "CDirEntry::GetMode(): stat() failed for " + GetPath()); } ModeFromModeT(st.st_mode, user_mode, group_mode, other_mode, special); return true; @@ -1043,8 +1046,7 @@ bool CDirEntry::SetMode(TMode user_mode, TMode group_mode, if ( (flags & fIgnoreMissing) && (errno == ENOENT) ) { return true; } - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetMode():" - " stat() failed for " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(6, "CDirEntry::SetMode(): stat() failed for " + GetPath()); } ModeFromModeT(st.st_mode, &user, &group, &other); } @@ -1062,8 +1064,7 @@ bool CDirEntry::SetMode(TMode user_mode, TMode group_mode, if ( (flags & fIgnoreMissing) && (errno == ENOENT) ) { return true; } - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetMode():" - " chmod() failed for " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(7, "CDirEntry::SetMode(): chmod() failed for " + GetPath()); } return true; } @@ -1842,9 +1843,7 @@ bool CDirEntry::GetTime(CTime* modification, // Get file times using FindFile handle = FindFirstFile(_T_XCSTRING(GetPath()), &buf); if ( handle == INVALID_HANDLE_VALUE ) { - //LOG_ERROR_AND_RETURN("CDirEntry::GetTime():" - //" Cannot find " << GetPath()); - CNcbiError::SetFromWindowsError(GetPath()); + LOG_ERROR_AND_RETURN_WIN(8, "CDirEntry::GetTime(): Cannot find " + GetPath()); return false; } FindClose(handle); @@ -1852,19 +1851,15 @@ bool CDirEntry::GetTime(CTime* modification, // Convert file UTC times into CTime format if ( modification && !s_FileTimeToCTime(buf.ftLastWriteTime, *modification) ) { - LOG_ERROR_AND_RETURN_WIN("CDirEntry::GetTime():" - " Cannot get modification time for " - + GetPath()); + LOG_ERROR_AND_RETURN_WIN(9, "CDirEntry::GetTime(): Cannot get modification time for " + GetPath()); } if ( last_access && !s_FileTimeToCTime(buf.ftLastAccessTime, *last_access) ) { - LOG_ERROR_AND_RETURN_WIN("CDirEntry::GetTime():" - " Cannot get access time for " + GetPath()); + LOG_ERROR_AND_RETURN_WIN(9, "CDirEntry::GetTime(): Cannot get access time for " + GetPath()); } if ( creation && !s_FileTimeToCTime(buf.ftCreationTime, *creation) ) { - LOG_ERROR_AND_RETURN_WIN("CDirEntry::GetTime():" - " Cannot get creation time for " + GetPath()); + LOG_ERROR_AND_RETURN_WIN(9, "CDirEntry::GetTime(): Cannot get creation time for " + GetPath()); } return true; @@ -1872,7 +1867,7 @@ bool CDirEntry::GetTime(CTime* modification, struct SStat st; if ( !Stat(&st) ) { - //LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::GetTime(): Could not get time for " << GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(8, "CDirEntry::GetTime(): Cannot get time for " + GetPath()); return false; } if ( modification ) { @@ -1929,13 +1924,11 @@ bool CDirEntry::SetTime(const CTime* modification, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS /*for dirs*/, NULL); if ( h == INVALID_HANDLE_VALUE ) { - LOG_ERROR_AND_RETURN_WIN("CDirEntry::SetTime():" - " Cannot open " + GetPath()); + LOG_ERROR_AND_RETURN_WIN(10, "CDirEntry::SetTime(): Cannot open " + GetPath()); } if ( !SetFileTime(h, p_creation, p_last_access, p_modification) ) { CloseHandle(h); - LOG_ERROR_AND_RETURN_WIN("CDirEntry::SetTime():" - " Cannot set new time for " + GetPath()); + LOG_ERROR_AND_RETURN_WIN(11, "CDirEntry::SetTime(): Cannot set new time for " + GetPath()); } CloseHandle(h); @@ -1980,8 +1973,7 @@ bool CDirEntry::SetTime(const CTime* modification, bool ut_res = utimes(GetPath().c_str(), tvp) == 0; # endif if ( !ut_res ) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetTime():" - " Cannot change time for " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(12, "CDirEntry::SetTime(): Cannot change time for " + GetPath()); } return true; @@ -2004,8 +1996,7 @@ bool CDirEntry::SetTime(const CTime* modification, times.modtime = modification ? modification->GetTimeT() : x_modification; times.actime = last_access ? last_access->GetTimeT() : x_last_access; if ( utime(GetPath().c_str(), ×) != 0 ) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetTime():" - " Cannot change time for " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(12, "CDirEntry::SetTime(): Cannot change time for " + GetPath()); } return true; @@ -2021,8 +2012,7 @@ bool CDirEntry::GetTimeT(time_t* modification, { TNcbiSys_stat st; if (NcbiSys_stat(_T_XCSTRING(GetPath()), &st) != 0) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::GetTimeT():" - " stat() failed for " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(13, "CDirEntry::GetTimeT(): stat() failed for " + GetPath()); } if ( modification ) { *modification = st.st_mtime; @@ -2068,14 +2058,11 @@ bool CDirEntry::SetTimeT(const time_t* modification, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS /*for dirs*/, NULL); if ( h == INVALID_HANDLE_VALUE ) { - LOG_ERROR_AND_RETURN_WIN("CDirEntry::SetTimeT():" - " Cannot open " + GetPath()); - return false; + LOG_ERROR_AND_RETURN_WIN(14, "CDirEntry::SetTimeT(): Cannot open " + GetPath()); } if ( !SetFileTime(h, p_creation, p_last_access, p_modification) ) { CloseHandle(h); - LOG_ERROR_AND_RETURN_WIN("CDirEntry::SetTimeT():" - " Cannot set new time for " + GetPath()); + LOG_ERROR_AND_RETURN_WIN(15, "CDirEntry::SetTimeT(): Cannot change time for " + GetPath()); } CloseHandle(h); @@ -2102,8 +2089,7 @@ bool CDirEntry::SetTimeT(const time_t* modification, times.modtime = modification ? *modification : x_modification; times.actime = last_access ? *last_access : x_last_access; if ( utime(GetPath().c_str(), ×) != 0 ) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetTimeT():" - " Cannot change time for " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(15, "CDirEntry::SetTimeT(): Cannot change time for " + GetPath()); } return true; @@ -2115,9 +2101,7 @@ bool CDirEntry::Stat(struct SStat *buffer, EFollowLinks follow_links) const { if ( !buffer ) { errno = EFAULT; - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::Stat():" - " NULL stat buffer passed for " - + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(16, "CDirEntry::Stat(): NULL stat buffer passed for " + GetPath()); } int errcode; @@ -2323,6 +2307,25 @@ CDirEntry::EType CDirEntry::GetType(const TNcbiSys_stat& st) } +#if defined(NCBI_OS_MSWIN) + +// Windows-specific implementation. See default implementation in the .hpp file +bool CDirEntry::Exists(void) const +{ + HANDLE h = CreateFile(_T_XCSTRING(GetPath()), + GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS /*for dirs*/, NULL); + if (h == INVALID_HANDLE_VALUE) { + return false; + } + CloseHandle(h); + return true; +} + +#endif + + string CDirEntry::LookupLink(void) const { #ifdef NCBI_OS_MSWIN @@ -2331,7 +2334,7 @@ string CDirEntry::LookupLink(void) const #else // NCBI_OS_UNIX char buf[PATH_MAX]; string name; - int length = (int)readlink(GetPath().c_str(), buf, sizeof(buf)); + int length = (int)readlink(_T_XCSTRING(GetPath()), buf, sizeof(buf)); if (length > 0) { name.assign(buf, length); } @@ -2458,9 +2461,9 @@ bool CDirEntry::Rename(const string& newname, TRenameFlags flags) // The source entry must exists EType src_type = src.GetType(); if ( src_type == eUnknown ) { - LOG_ERROR_AND_RETURN_NCBI("CDirEntry::Rename():" - " Source path does not exist: " + src.GetPath(), - CNcbiError::eNoSuchFileOrDirectory); + LOG_ERROR_AND_RETURN_NCBI(17, "CDirEntry::Rename():" + " Source path does not exist: " + src.GetPath(), + CNcbiError::eNoSuchFileOrDirectory); } // Try to "move" in one atomic operation if possible to avoid race @@ -2485,7 +2488,7 @@ bool CDirEntry::Rename(const string& newname, TRenameFlags flags) // a symlink. So just dont use link() in this case and, // fall back to regular rename() instead. - if ( src_type != eLink && + if ( src_type == eFile && link(_T_XCSTRING(src.GetPath()), _T_XCSTRING(dst.GetPath())) == 0 ) { // Hard link successfully created, so we can just remove source file @@ -2505,18 +2508,18 @@ bool CDirEntry::Rename(const string& newname, TRenameFlags flags) if ( dst_type != eUnknown ) { // Can rename entries with different types? if ( F_ISSET(flags, fRF_EqualTypes) && (src_type != dst_type) ) { - LOG_ERROR_AND_RETURN_NCBI("CDirEntry::Rename():" - " Both source and destination exist" - " and have different types: " - + src.GetPath() + " and " + dst.GetPath(), - CNcbiError::eOperationNotPermitted); + LOG_ERROR_AND_RETURN_NCBI(18, "CDirEntry::Rename():" + " Both source and destination exist" + " and have different types: " + + src.GetPath() + " and " + dst.GetPath(), + CNcbiError::eOperationNotPermitted); } // Can overwrite entry? if ( !F_ISSET(flags, fRF_Overwrite) ) { - LOG_ERROR_AND_RETURN_NCBI("CDirEntry::Rename():" - " Destination path already exists: " - + dst.GetPath(), - CNcbiError::eOperationNotPermitted); + LOG_ERROR_AND_RETURN_NCBI(19, "CDirEntry::Rename():" + " Destination path already exists: " + + dst.GetPath(), + CNcbiError::eOperationNotPermitted); } // Rename only if destination is older, otherwise just remove source if ( F_ISSET(flags, fRF_Update) && !src.IsNewer(dst.GetPath(), 0)) { @@ -2524,12 +2527,11 @@ bool CDirEntry::Rename(const string& newname, TRenameFlags flags) } // Backup destination entry first if ( F_ISSET(flags, fRF_Backup) ) { - // Use new CDirEntry object for 'dst', because its path + // Use new CDirEntry object instead of 'dst', because its path // will be changed after backup CDirEntry dst_tmp(dst); if ( !dst_tmp.Backup(GetBackupSuffix(), eBackup_Rename) ) { - LOG_ERROR_AND_RETURN("CDirEntry::Rename():" - " Cannot backup " + dst.GetPath()); + LOG_ERROR_AND_RETURN(20, "CDirEntry::Rename(): Cannot backup " + dst.GetPath()); } } // Overwrite destination entry @@ -2545,8 +2547,7 @@ bool CDirEntry::Rename(const string& newname, TRenameFlags flags) // For consistency return FALSE if destination already exists. if ( dst.Exists() ) { // this means Remove has failed, and error is set already - LOG_ERROR_AND_RETURN("CDirEntry::Rename():" - " Destination path exists: " + GetPath()); + LOG_ERROR_AND_RETURN(21, "CDirEntry::Rename(): Destination path exists: " + GetPath()); } // Rename @@ -2558,16 +2559,13 @@ bool CDirEntry::Rename(const string& newname, TRenameFlags flags) #else if ( errno != EXDEV ) { #endif - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::Rename():" - " rename() failed for " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(21, "CDirEntry::Rename(): rename() failed for " + GetPath()); } // Note that rename() fails in the case of cross-device renaming. // So, try to make a copy and remove the original later. - auto_ptr - e(CDirEntry::CreateObject(src_type, src.GetPath())); + unique_ptr e(CDirEntry::CreateObject(src_type, src.GetPath())); if ( !e->Copy(dst.GetPath(), fCF_Recursive | fCF_PreserveAll ) ) { - auto_ptr - tmp(CDirEntry::CreateObject(src_type, dst.GetPath())); + unique_ptr tmp(CDirEntry::CreateObject(src_type, dst.GetPath())); tmp->Remove(eRecursive); return false; } @@ -2602,17 +2600,14 @@ bool CDirEntry::Remove(TRemoveFlags flags) const #if defined(NCBI_OS_MSWIN) case EACCES: if ( NCBI_PARAM_TYPE(NCBI, DeleteReadOnlyFiles)::GetDefault() ) { - if ( !SetMode(eDefault) ) { - CNcbiError::SetErrno(EACCES); - return false; - } - if ( NcbiSys_remove(_T_XCSTRING(GetPath())) == 0 ) + SetMode(eDefault); + if ( NcbiSys_remove(_T_XCSTRING(GetPath())) == 0 ) { return true; + } } #endif } - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::Remove():" - " remove() failed for " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(22, "CDirEntry::Remove(): remove() failed for " + GetPath()); } return true; } @@ -2728,12 +2723,10 @@ bool CDirEntry::IsIdentical(const string& entry_name, #if defined(NCBI_OS_UNIX) struct SStat st1, st2; if ( !Stat(&st1, follow_links) ) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::IsIdentical():" - " Cannot find " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(23, "CDirEntry::IsIdentical(): Cannot find " + GetPath()); } if ( !CDirEntry(entry_name).Stat(&st2, follow_links) ) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::IsIdentical():" - " Cannot find " + entry_name); + LOG_ERROR_AND_RETURN_ERRNO(23, "CDirEntry::IsIdentical(): Cannot find " + entry_name); } return st1.orig.st_dev == st2.orig.st_dev && st1.orig.st_ino == st2.orig.st_ino; @@ -2767,8 +2760,7 @@ bool CDirEntry::GetOwner(string* owner, string* group, errcode = lstat(GetPath().c_str(), &st); } if ( errcode != 0 ) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::GetOwner():" - " stat() failed for " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(24, "CDirEntry::GetOwner(): stat() failed for " + GetPath()); } if ( uid ) { @@ -2822,8 +2814,7 @@ bool CDirEntry::SetOwner(const string& owner, const string& group, unsigned int temp; if (!NStr::StringToNumeric(owner, &temp, NStr::fConvErr_NoThrow, 0)) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetOwner():" - " Invalid owner name " + owner); + LOG_ERROR_AND_RETURN_ERRNO(25, "CDirEntry::SetOwner(): Invalid owner name " + owner); } temp_uid = (uid_t) temp; } @@ -2841,8 +2832,7 @@ bool CDirEntry::SetOwner(const string& owner, const string& group, unsigned int temp; if (!NStr::StringToNumeric(group, &temp, NStr::fConvErr_NoThrow, 0)) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetOwner():" - " Invalid group name " + group); + LOG_ERROR_AND_RETURN_ERRNO(26, "CDirEntry::SetOwner(): Invalid group name " + group); } temp_gid = (gid_t) temp; } @@ -2855,17 +2845,13 @@ bool CDirEntry::SetOwner(const string& owner, const string& group, if (follow == eFollowLinks || GetType(eIgnoreLinks) != eLink) { if ( chown(GetPath().c_str(), temp_uid, temp_gid) ) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetOwner():" - " Cannot change owner for " - + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(27, "CDirEntry::SetOwner(): Cannot change owner for " + GetPath()); } } # if defined(HAVE_LCHOWN) else { if ( lchown(GetPath().c_str(), temp_uid, temp_gid) ) { - LOG_ERROR_AND_RETURN_ERRNO("CDirEntry::SetOwner():" - " Cannot change symlink owner for " - + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(28, "CDirEntry::SetOwner(): Cannot change symlink owner for " + GetPath()); } } # endif @@ -2963,7 +2949,7 @@ fstream* CDirEntry::CreateTmpFile(const string& filename, string tmpname = filename.empty() ? GetTmpName(eTmpFileCreate) : filename; if ( tmpname.empty() ) { string msg("CDirEntry::CreateTmpFile(): Cannot get temporary file name"); - LOG_ERROR(msg); + LOG_ERROR(29, msg); CNcbiError::Set(CNcbiError::eNoSuchFileOrDirectory, msg); return 0; } @@ -3038,8 +3024,7 @@ static bool s_CopyAttrs(const char* from, const char* to, CDirEntry::SStat st; if ( !CDirEntry(from).Stat(&st) ) { - LOG_ERROR_AND_RETURN_ERRNO(string("CDirEntry::s_CopyAttrs():") - + " stat() failed for " + from); + LOG_ERROR_AND_RETURN_ERRNO(30, string("CDirEntry::s_CopyAttrs():") + " stat() failed for " + from); } // Date/time. @@ -3054,13 +3039,11 @@ static bool s_CopyAttrs(const char* from, const char* to, tvp[1].tv_usec = st.mtime_nsec / 1000; # if defined(HAVE_LUTIMES) if (lutimes(to, tvp)) { - LOG_ERROR_AND_RETURN_ERRNO(string("CDirEntry::s_CopyAttrs():") - + " lutimes() failed for " + to); + LOG_ERROR_AND_RETURN_ERRNO(31, string("CDirEntry::s_CopyAttrs():") + " lutimes() failed for " + to); } # else if (utimes(to, tvp)) { - LOG_ERROR_AND_RETURN_ERRNO(string("CDirEntry::s_CopyAttrs():") - + " utimes() failed for " + to); + LOG_ERROR_AND_RETURN_ERRNO(32, string("CDirEntry::s_CopyAttrs():") + " utimes() failed for " + to); } # endif # else // !HAVE_UTIMES @@ -3070,8 +3053,7 @@ static bool s_CopyAttrs(const char* from, const char* to, times.actime = st.orig.st_atime; times.modtime = st.orig.st_mtime; if (utime(to, ×)) { - LOG_ERROR_AND_RETURN_ERRNO(string("CDirEntry::s_CopyAttrs():") - + " utime() failed for " + to); + LOG_ERROR_AND_RETURN_ERRNO(33, string("CDirEntry::s_CopyAttrs():") + " utime() failed for " + to); } # endif // HAVE_UTIMES } @@ -3085,8 +3067,7 @@ static bool s_CopyAttrs(const char* from, const char* to, # if defined(HAVE_LCHOWN) if ( lchown(to, st.orig.st_uid, st.orig.st_gid) ) { if (errno != EPERM) { - LOG_ERROR_AND_RETURN_ERRNO(string("CDirEntry::s_CopyAttrs():") - + " lchown() failed for " + to); + LOG_ERROR_AND_RETURN_ERRNO(34, string("CDirEntry::s_CopyAttrs():") + " lchown() failed for " + to); } } # endif @@ -3099,8 +3080,7 @@ static bool s_CopyAttrs(const char* from, const char* to, // strip the setuid/gid bits. if ( chown(to, st.orig.st_uid, st.orig.st_gid) ) { if ( errno != EPERM ) { - LOG_ERROR_AND_RETURN_ERRNO(string("CDirEntry::s_CopyAttrs():") - + " chown() failed for " + to); + LOG_ERROR_AND_RETURN_ERRNO(35, string("CDirEntry::s_CopyAttrs():") + " chown() failed for " + to); } st.orig.st_mode &= ~(S_ISUID | S_ISGID); } @@ -3111,8 +3091,7 @@ static bool s_CopyAttrs(const char* from, const char* to, if ( F_ISSET(flags, CDirEntry::fCF_PreservePerm) && type != CDirEntry::eLink ) { if ( chmod(to, st.orig.st_mode) ) { - LOG_ERROR_AND_RETURN_ERRNO(string("CDirEntry::s_CopyAttrs():") - + " chmod() failed for " + to); + LOG_ERROR_AND_RETURN_ERRNO(36, string("CDirEntry::s_CopyAttrs():") + " chmod() failed for " + to); } } return true; @@ -3123,8 +3102,7 @@ static bool s_CopyAttrs(const char* from, const char* to, CDirEntry efrom(from), eto(to); WIN32_FILE_ATTRIBUTE_DATA attr; - if ( !::GetFileAttributesEx(_T_XCSTRING(from), - GetFileExInfoStandard, &attr) ) { + if ( !::GetFileAttributesEx(_T_XCSTRING(from), GetFileExInfoStandard, &attr) ) { CNcbiError::SetFromWindowsError(); return false; } @@ -3136,24 +3114,19 @@ static bool s_CopyAttrs(const char* from, const char* to, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS /*for dirs*/, NULL); if ( h == INVALID_HANDLE_VALUE ) { - LOG_ERROR_AND_RETURN_WIN(string("CDirEntry::s_CopyAttrs():") - + " Cannot open " + to); + LOG_ERROR_AND_RETURN_WIN(37, string("CDirEntry::s_CopyAttrs():") + " Cannot open " + to); } - if ( !SetFileTime(h, &attr.ftCreationTime, &attr.ftLastAccessTime, - &attr.ftLastWriteTime) ) { + if ( !SetFileTime(h, &attr.ftCreationTime, &attr.ftLastAccessTime, &attr.ftLastWriteTime) ) { CloseHandle(h); - LOG_ERROR_AND_RETURN_WIN(string("CDirEntry::s_CopyAttrs():") - + " Cannot change time for " + to); + LOG_ERROR_AND_RETURN_WIN(38, string("CDirEntry::s_CopyAttrs():") + " Cannot change time for " + to); } CloseHandle(h); } // Permissions if ( F_ISSET(flags, CDirEntry::fCF_PreservePerm) ) { - if ( !::SetFileAttributes(_T_XCSTRING(to), - attr.dwFileAttributes) ) { - LOG_ERROR_AND_RETURN_WIN(string("CDirEntry::s_CopyAttrs():") - + " Cannot change pemissions for " + to); + if ( !::SetFileAttributes(_T_XCSTRING(to), attr.dwFileAttributes) ) { + LOG_ERROR_AND_RETURN_WIN(39, string("CDirEntry::s_CopyAttrs():") + " Cannot change pemissions for " + to); } } @@ -3189,7 +3162,7 @@ Int8 CFile::GetLength(void) const TNcbiSys_stat st; if (NcbiSys_stat(_T_XCSTRING(GetPath()), &st) != 0 || GetType(st) != eFile ) { - //LOG_ERROR("CFile:GetLength(): stat() failed for " << GetPath()); + //LOG_ERROR(40, "CFile:GetLength(): stat() failed for " << GetPath()); CNcbiError::SetFromErrno(GetPath()); return -1L; } @@ -3325,14 +3298,15 @@ bool CFile::Copy(const string& newname, TCopyFlags flags, size_t buf_size) const // The source file must exists EType src_type = src.GetType(); if ( src_type != eFile ) { - LOG_ERROR_AND_RETURN_NCBI("CFile::Copy():" - " Source is not a file: " + GetPath(), - CNcbiError::eNoSuchFileOrDirectory); + LOG_ERROR_AND_RETURN_NCBI(41, "CFile::Copy():" + " Source is not a file: " + GetPath(), + CNcbiError::eNoSuchFileOrDirectory); } - EType dst_type = dst.GetType(); - bool dst_exists = (dst_type != eUnknown); - + EType dst_type = dst.GetType(); + bool dst_exists = (dst_type != eUnknown); + string dst_safe_path; // saved path for fCF_Safe + // If destination exists... if ( dst_exists ) { // UNIX: check on copying file into yourself. @@ -3346,16 +3320,13 @@ bool CFile::Copy(const string& newname, TCopyFlags flags, size_t buf_size) const // Can copy entries with different types? // Destination must be a file too. if ( F_ISSET(flags, fCF_EqualTypes) && (src_type != dst_type) ) { - LOG_ERROR_AND_RETURN_NCBI("CFile::Copy():" - " Destination is not a file: " - + dst.GetPath(), - CNcbiError::eOperationNotPermitted); + LOG_ERROR_AND_RETURN_NCBI(41, "CFile::Copy(): Destination is not a file: " + dst.GetPath(), + CNcbiError::eOperationNotPermitted); } // Can overwrite entry? if ( !F_ISSET(flags, fCF_Overwrite) ) { - LOG_ERROR_AND_RETURN_NCBI("CFile::Copy():" - " Destination file exists: " - + dst.GetPath(), CNcbiError::eOperationNotPermitted); + LOG_ERROR_AND_RETURN_NCBI(42, "CFile::Copy(): Destination file exists: " + dst.GetPath(), + CNcbiError::eOperationNotPermitted); } // Copy only if destination is older if ( F_ISSET(flags, fCF_Update) && !src.IsNewer(dst.GetPath(),0) ) { @@ -3367,34 +3338,48 @@ bool CFile::Copy(const string& newname, TCopyFlags flags, size_t buf_size) const // will be changed after backup CDirEntry dst_tmp(dst); if ( !dst_tmp.Backup(GetBackupSuffix(), eBackup_Rename) ) { - LOG_ERROR_AND_RETURN("CFile::Copy():" - " Cannot backup " << dst.GetPath()); + LOG_ERROR_AND_RETURN(43, "CFile::Copy(): Cannot backup " + dst.GetPath()); } } } + // Safe copy -- copy to temporary file and rename later + if (F_ISSET(flags, fCF_Safe)) { + // Get new temporary name in the same directory + string path, name, ext; + SplitPath(dst.GetPath(), &path, &name, &ext); + string tmp = GetTmpNameEx(path.empty() ? CDir::GetCwd() : path, name + ext + kTmpSafeSuffix); + // Set new destination + dst_safe_path = dst.GetPath(); + dst.Reset(tmp); + } // Copy #if defined(NCBI_OS_MSWIN) if ( !::CopyFile(_T_XCSTRING(src.GetPath()), _T_XCSTRING(dst.GetPath()), FALSE) ) { - LOG_ERROR_AND_RETURN_WIN("CFile::Copy():" - " Cannot copy " - + src.GetPath() + " to " + dst.GetPath()); + dst.Remove(); + LOG_ERROR_AND_RETURN_WIN(44, "CFile::Copy(): Cannot copy " + src.GetPath() + " to " + dst.GetPath()); } #else if ( !s_CopyFile(src.GetPath().c_str(), dst.GetPath().c_str(), buf_size) ){ - LOG_ERROR_AND_RETURN("CFile::Copy():" - " Cannot copy " - << src.GetPath() << " to " << dst.GetPath()); + dst.Remove(); + LOG_ERROR_AND_RETURN(44, "CFile::Copy(): Cannot copy " << src.GetPath() << " to " + dst.GetPath()); } #endif + // Safe copy -- renaming + if (F_ISSET(flags, fCF_Safe)) { + if (!dst.Rename(dst_safe_path, fRF_Overwrite)) { + dst.Remove(); + LOG_ERROR_AND_RETURN_NCBI(45, "CFile:Copy():" + " Cannot rename temporary file " + dst.GetPath() + + " to " + dst_safe_path, CNcbiError::eIoError); + } + } // Verify copied data if ( F_ISSET(flags, fCF_Verify) && !src.Compare(dst.GetPath()) ) { - LOG_ERROR_AND_RETURN_NCBI("CFile::Copy():" - " Copy verification for " - + src.GetPath() + " and " + dst.GetPath() - + " failed", CNcbiError::eIoError); + LOG_ERROR_AND_RETURN_NCBI(46, "CFile::Copy(): Copy verification for " + src.GetPath() + + " and " + dst.GetPath() + " failed", CNcbiError::eIoError); } // Preserve attributes @@ -3506,10 +3491,8 @@ bool CFile::Compare(const string& filename, size_t buf_size) const equal = (s1 == s); } catch (CFileErrnoException& ex) { - string msg = string("Error comparing file ") + - GetPath() + " and " + filename + - " : " + ex.what(); - LOG_ERROR(msg); + string msg = string("Error comparing file ") + GetPath() + " and " + filename + " : " + ex.what(); + LOG_ERROR(47, msg); CNcbiError::SetErrno(ex.GetErrno(), msg); } if (buf1 != x_buf) { @@ -3546,7 +3529,7 @@ static bool s_GetHomeByUID(string& home) struct passwd* pwd; if ((pwd = getpwuid(getuid())) == 0) { - LOG_ERROR_AND_RETURN_ERRNO("s_GetHomeByUID(): getpwuid() failed"); + LOG_ERROR_AND_RETURN_ERRNO(48, "s_GetHomeByUID(): getpwuid() failed"); } home = pwd->pw_dir; return true; @@ -3559,16 +3542,14 @@ static bool s_GetHomeByLOGIN(string& home) if ( !(ptr = NcbiSys_getenv(_TX("USER"))) ) { if ( !(ptr = NcbiSys_getenv(_TX("LOGNAME"))) ) { if ( !(ptr = getlogin()) ) { - LOG_ERROR_AND_RETURN_ERRNO("s_GetHomeByLOGIN():" - " Unable to get user name"); + LOG_ERROR_AND_RETURN_ERRNO(49, "s_GetHomeByLOGIN(): Unable to get user name"); } } } // Get home dir for this user struct passwd* pwd = getpwnam(ptr); if ( !pwd || pwd->pw_dir[0] == '\0') { - LOG_ERROR_AND_RETURN_ERRNO("s_GetHomeByLOGIN():" - " getpwnam() failed"); + LOG_ERROR_AND_RETURN_ERRNO(50, "s_GetHomeByLOGIN(): getpwnam() failed"); } home = pwd->pw_dir; return true; @@ -3596,12 +3577,12 @@ string CDir::GetHome(void) } #elif defined(NCBI_OS_UNIX) // Try get home dir from environment variable - char* str = NcbiSys_getenv("HOME"); + char* str = NcbiSys_getenv(_TX("HOME")); if ( str ) { home = str; } else { // Try to retrieve the home dir -- first use user's ID, - // and if failed, then use user's login name. + // and if failed, then use user's login name. if ( !s_GetHomeByUID(home) ) { s_GetHomeByLOGIN(home); } @@ -3653,7 +3634,7 @@ string CDir::GetAppTmpDir(void) { // Get application specific temporary directory name string tmp = NCBI_PARAM_TYPE(NCBI, TmpDir)::GetThreadDefault(); - if (!tmp.empty()) { + if ( !tmp.empty() ) { return tmp; } // Use default TMP directory specified by OS @@ -3676,8 +3657,7 @@ bool CDir::SetCwd(const string& dir) { #if defined(NCBI_OS_UNIX) || defined(NCBI_OS_MSWIN) if ( NcbiSys_chdir(_T_XCSTRING(dir)) != 0 ) { - LOG_ERROR_AND_RETURN_ERRNO("CDir::SetCwd():" - " Cannot change directory to " + dir); + LOG_ERROR_AND_RETURN_ERRNO(51, "CDir::SetCwd(): Cannot change directory to " + dir); } return true; #else @@ -3828,7 +3808,7 @@ CDir::TEntries* CDir::GetEntriesPtr(const string& mask, CDir::TEntries CDir::GetEntries(const vector& masks, TGetEntriesFlags flags) const { - auto_ptr contents(GetEntriesPtr(masks, flags)); + unique_ptr contents(GetEntriesPtr(masks, flags)); return contents.get() ? *contents.get() : TEntries(); } @@ -3873,8 +3853,7 @@ CDir::TEntries* CDir::GetEntriesPtr(const vector& masks, s_SetFindFileError(); delete contents; if ( F_ISSET(flags, fThrowOnError) ) { - NCBI_THROW(CFileErrnoException, eFile, - string("Cannot read directory ") + base_path); + NCBI_THROW(CFileErrnoException, eFile, string("Cannot read directory ") + base_path); } return NULL; } @@ -3885,8 +3864,7 @@ CDir::TEntries* CDir::GetEntriesPtr(const vector& masks, if ( !dir ) { delete contents; if ( F_ISSET(flags, fThrowOnError) ) { - NCBI_THROW(CFileErrnoException, eFile, - string("Cannot read directory ") + base_path); + NCBI_THROW(CFileErrnoException, eFile, string("Cannot read directory ") + base_path); } return NULL; } @@ -3914,7 +3892,7 @@ CDir::TEntries* CDir::GetEntriesPtr(const vector& masks, CDir::TEntries CDir::GetEntries(const CMask& masks, TGetEntriesFlags flags) const { - auto_ptr contents(GetEntriesPtr(masks, flags)); + unique_ptr contents(GetEntriesPtr(masks, flags)); return contents.get() ? *contents.get() : TEntries(); } @@ -3948,9 +3926,7 @@ CDir::TEntries* CDir::GetEntriesPtr(const CMask& masks, s_SetFindFileError(); delete contents; if ( F_ISSET(flags, fThrowOnError) ) { - cout << "--> " << errno << endl; - NCBI_THROW(CFileErrnoException, eFile, - string("Cannot read directory ") + base_path); + NCBI_THROW(CFileErrnoException, eFile, string("Cannot read directory ") + base_path); } return NULL; } @@ -3961,8 +3937,7 @@ CDir::TEntries* CDir::GetEntriesPtr(const CMask& masks, if ( !dir ) { delete contents; if ( F_ISSET(flags, fThrowOnError) ) { - NCBI_THROW(CFileErrnoException, eFile, - string("Cannot read directory ") + base_path); + NCBI_THROW(CFileErrnoException, eFile, string("Cannot read directory ") + base_path); } return NULL; } @@ -3980,69 +3955,154 @@ CDir::TEntries* CDir::GetEntriesPtr(const CMask& masks, } -bool CDir::Create(void) const +// Helper function for CDir::Create[Path]() +inline bool s_DirCreate(const string&path, CDir::TCreateFlags flags, mode_t mode) { - TMode user_mode, group_mode, other_mode; - TSpecialModeBits special; - GetDefaultMode(&user_mode, &group_mode, &other_mode, &special); - mode_t mode = MakeModeT(user_mode, group_mode, other_mode, special); - -#if defined(NCBI_OS_MSWIN) errno = 0; - if ( NcbiSys_mkdir(_T_XCSTRING(GetPath())) != 0 && - errno != EEXIST ) { - LOG_ERROR_AND_RETURN_ERRNO(string("CDir::Create():") - + " Cannot create directory " + GetPath()); +#if defined(NCBI_OS_MSWIN) + int res = NcbiSys_mkdir(_T_XCSTRING(path)); +#elif defined(NCBI_OS_UNIX) + int res = NcbiSys_mkdir(_T_XCSTRING(path), mode); +#endif + if (res != 0) { + if (errno != EEXIST) { + LOG_ERROR_AND_RETURN_ERRNO(52, "CDir::Create(): Cannot create directory " + path); + } + // Entry with such name already exists, check its type + CDirEntry::EType type = CDirEntry(path).GetType(); + if (type == CDirEntry::eUnknown) { + LOG_ERROR_AND_RETURN(52, "CDir::Create(): Cannot create directory " + path); + } + if (type != CDirEntry::eDir) { + LOG_ERROR_AND_RETURN(53, "CDir::Create(): Path already exist and is not a directory " + path); + } + if (F_ISSET(flags, CDir::fCreate_ErrorIfExists)) { + LOG_ERROR_AND_RETURN(54, "CDir::Create(): Directory already exist " + path); + } + if (!F_ISSET(flags, CDir::fCreate_UpdateIfExists)) { + return true; + } } + // The permissions for the created directory is controlled by umask and is (mode & ~umask & 0777). + // We need to call chmod() directly if we need other behavior. -#elif defined(NCBI_OS_UNIX) - errno = 0; - // The permissions for the created directory are (mode & ~umask & 0777). - if ( NcbiSys_mkdir(GetPath().c_str(), mode) != 0 && errno != EEXIST ) { - LOG_ERROR_AND_RETURN_ERRNO(string("CDir::Create():") - + " Cannot create directory " + GetPath()); + _ASSERT(CDir::fCreate_Default == 0 && + CDir::fCreate_PermByUmask != 0 && + CDir::fCreate_PermAsParent != 0); + _ASSERT(!F_ISSET(flags, CDir::fCreate_PermByUmask | CDir::fCreate_PermAsParent)); + + if ( F_ISSET(flags, CDir::fCreate_PermByUmask) || + (!F_ISSET(flags, CDir::fCreate_PermByUmask) && !F_ISSET(flags, CDir::fCreate_PermAsParent) && + NCBI_PARAM_TYPE(NCBI, FileAPIHonorUmask)::GetDefault()) ) { + // nothing to do if (umask) or (default mode with "honor umask" global flag) + return true; + } + // Change directory permissions + if (NcbiSys_chmod(_T_XCSTRING(path), mode) != 0) { + LOG_ERROR_AND_RETURN_ERRNO(55, "CDir::Create(): Cannot set mode for directory " + path); + } + return true; +} + + +bool CDir::Create(TCreateFlags flags) const +{ + if (GetPath().empty()) { + LOG_ERROR_AND_RETURN(56, "CDir::Create(): Path is empty"); } - // so we need to call chmod() directly + mode_t mode = GetDefaultModeT(); + + // Get parent permissions + if (F_ISSET(flags, fCreate_PermAsParent)) { + CDir d(CreateAbsolutePath(GetPath())); + string path_up(d.GetDir()); + if ( path_up.empty() || path_up == d.GetPath() ) { + LOG_ERROR_AND_RETURN_ERRNO(57, "CDir::Create(): Cannot get parent directory for " + GetPath()); + } +#if defined(NCBI_OS_MSWIN) + // Special case -- stat() dont works if directory have trailing path + // separator, except it is a root directory with a disk name, like "C:\". + if (path_up.length() > 3) { + path_up = DeleteTrailingPathSeparator(path_up); + } #endif - if (! NCBI_PARAM_TYPE(NCBI, FileAPIHonorUmask)::GetDefault()) { - if ( NcbiSys_chmod(_T_XCSTRING(GetPath()), mode) != 0 ) { - LOG_ERROR_AND_RETURN_ERRNO(string("CDir::Create():") - + " Cannot set mode for directory " - + GetPath()); + TNcbiSys_stat st; + if (NcbiSys_stat(_T_XCSTRING(path_up), &st) != 0) { + LOG_ERROR_AND_RETURN_ERRNO(58, "CDir::Create(): Cannot get permissions for parent directory of " + GetPath()); } + mode = st.st_mode; } - return true; + return s_DirCreate(GetPath(), flags, mode); } -bool CDir::CreatePath(void) const +bool CDir::CreatePath(TCreateFlags flags) const { - if ( Exists() ) { - return true; + if (GetPath().empty()) { + LOG_ERROR_AND_RETURN(59, "CDir::CreatePath(): Path is empty"); } - string path(GetPath()); - if ( path.empty() ) { - return true; + string path(CreateAbsolutePath(GetPath())); + if (path.empty()) { + LOG_ERROR_AND_RETURN(60, "CDir::CreatePath(): Cannot create absolute path from " + path); } - if ( path[path.length()-1] == GetPathSeparator() ) { + if (path[path.length()-1] == GetPathSeparator()) { path.erase(path.length() - 1); } - string path_up = GetDir(); - if ( path_up == path ) { - // special case: unknown disk name - LOG_ERROR_AND_RETURN_NCBI(string("CDir::CreatePath():") - + " Disk name not specified: " + path, - CNcbiError::eInvalidArgument); - } - // Create a copy for this object to derive creation mode - CDir dir_up(*this); - dir_up.Reset(path_up); - // Create upper level path - if ( dir_up.CreatePath() ) { - // Create current subdirectory - return Create(); + + // Find all missed parts of the path + + CTempString tmp(path); // existent part of a path + std::list missed_parts; + + while (!tmp.empty() && !CDirEntry(tmp).Exists()) { + size_t pos = tmp.find_last_of(DIR_SEPARATORS); + if (pos == NPOS) { + break; + } + CTempString part(tmp.substr(pos+1)); + missed_parts.push_front(part); + tmp.erase(pos); } - return false; + + mode_t mode = GetDefaultModeT(); + + // Get parent permissions + if (F_ISSET(flags, fCreate_PermAsParent)) { + string parent; + if (missed_parts.empty()) { + parent.assign(CDir(tmp).GetDir()); + } else { + parent.assign(tmp); + } +#if defined(NCBI_OS_MSWIN) + // Special case -- for paths like "C:" add slash to represent a root directory + if (parent.length() == 2) { + parent += GetPathSeparator(); + } +#endif + TNcbiSys_stat st; + if (NcbiSys_stat(_T_XCSTRING(parent), &st) != 0) { + LOG_ERROR_AND_RETURN_ERRNO(61, "CDir::CreatePath(): Cannot get permissions for " + parent); + } + mode = st.st_mode; + } + + // Path exists? + if (missed_parts.empty()) { + // check existence and behave depends on flags + return s_DirCreate(path, flags, mode); + } + + // Create missed subdirectories + string p = tmp; + for (auto i : missed_parts) { + p += GetPathSeparator(); + p += i; + if (!s_DirCreate(p, flags, mode)) { + return false; + } + } + return true; } @@ -4060,26 +4120,31 @@ bool CDir::Copy(const string& newname, TCopyFlags flags, size_t buf_size) const // The source dir must exists EType src_type = src.GetType(); if ( src_type != eDir ) { - LOG_ERROR_AND_RETURN_NCBI("CDir::Copy():" - " Source is not a directory: " + src.GetPath(), - CNcbiError::eNoSuchFileOrDirectory); + LOG_ERROR_AND_RETURN_NCBI(62, "CDir::Copy(): Source is not a directory: " + src.GetPath(), + CNcbiError::eNoSuchFileOrDirectory); } - EType dst_type = dst.GetType(); - bool dst_exists = (dst_type != eUnknown); - + EType dst_type = dst.GetType(); + bool dst_exists = (dst_type != eUnknown); + bool need_create_dst = !dst_exists; + string dst_safe_path; // saved path for fCF_Safe + + // Safe copy? + // Don't use it if fCF_TopDirOnly is not specified. If target directory + // exists it will be just "updated" and safe copying will be applied + // on a file level for every copied entry. + bool need_safe_copy = F_ISSET(flags, fCF_Safe | fCF_TopDirOnly); + // If destination exists... if ( dst_exists ) { // Check on copying dir into yourself if ( src.IsIdentical(dst.GetPath()) ) { - LOG_ERROR_AND_RETURN_NCBI("CDir::Copy():" - " Source and destination are the same: " - + src.GetPath(), CNcbiError::eOperationNotPermitted); + LOG_ERROR_AND_RETURN_NCBI(63, "CDir::Copy(): Source and destination are the same: " + + src.GetPath(), CNcbiError::eOperationNotPermitted); } // Can rename entries with different types? if ( F_ISSET(flags, fCF_EqualTypes) && (src_type != dst_type) ) { - LOG_ERROR_AND_RETURN_NCBI("CDir::Copy():" - " Destination is not a directory: " - + dst.GetPath(), CNcbiError::eOperationNotPermitted); + LOG_ERROR_AND_RETURN_NCBI(64, "CDir::Copy(): Destination is not a directory: " + + dst.GetPath(), CNcbiError::eOperationNotPermitted); } // Some operation can be made for top directory only @@ -4087,68 +4152,84 @@ bool CDir::Copy(const string& newname, TCopyFlags flags, size_t buf_size) const if ( F_ISSET(flags, fCF_TopDirOnly) ) { // Can overwrite entry? if ( !F_ISSET(flags, fCF_Overwrite) ) { - LOG_ERROR_AND_RETURN_NCBI("CDir::Copy():" - " Destination directory already exists: " - + dst.GetPath(), CNcbiError::eOperationNotPermitted); + LOG_ERROR_AND_RETURN_NCBI(65, "CDir::Copy(): Destination directory already exists: " + + dst.GetPath(), CNcbiError::eOperationNotPermitted); } // Copy only if destination is older - if ( F_ISSET(flags, fCF_Update) && - !src.IsNewer(dst.GetPath(), 0) ) { + if ( F_ISSET(flags, fCF_Update) && !src.IsNewer(dst.GetPath(), 0) ) { return true; } - // Backup destination entry first - if ( F_ISSET(flags, fCF_Backup) ) { - // Use new CDirEntry object for 'dst', because its path + // Backup destination directory + if (F_ISSET(flags, fCF_Backup)) { + // Use new CDirEntry object instead of 'dst', because its path // will be changed after backup CDirEntry dst_tmp(dst); if ( !dst_tmp.Backup(GetBackupSuffix(), eBackup_Rename) ) { - LOG_ERROR_AND_RETURN("CDir::Copy():" - " Cannot backup destination" - " directory: " << dst.GetPath()); - } - // Create target directory - if ( !dst.CreatePath() ) { - LOG_ERROR_AND_RETURN("CDir::Copy():" - " Cannot create target directory: " << - dst.GetPath()); + LOG_ERROR_AND_RETURN(66, "CDir::Copy(): Cannot backup destination directory: " + dst.GetPath()); } + need_create_dst = true; } - // Remove unneeded flags. - // All dir entries can now be overwritten. - flags &= ~(fCF_TopDirOnly | fCF_Update | fCF_Backup); + // Clear flags not needed anymore. + // Keep fCF_Overwrite if it is set (fCF_Backup is a compound flag). + flags &= ~(fCF_TopDirOnly | (fCF_Backup - fCF_Overwrite)); } - } else { - // Create target directory + } + + // Safe copy for top directory -- copy to temporary directory in the same + // parent directory and rename later. + + if ( need_safe_copy ) { + // Get new temporary name in the same directory + string path, name, ext; + SplitPath(dst.GetPath(), &path, &name, &ext); + string tmp = GetTmpNameEx(path.empty() ? CDir::GetCwd() : path, name + ext + kTmpSafeSuffix); + // Set new destination + dst_safe_path = dst.GetPath(); + dst.Reset(tmp); + need_create_dst = true; + // Clear safe flag, we already have a temporary top directory + flags &= ~fCF_Safe; + } + + // Create target directory if needed + if ( need_create_dst ) { if ( !dst.CreatePath() ) { - LOG_ERROR_AND_RETURN("CDir::Copy():" - " Cannot create target directory: " - << dst.GetPath()); + LOG_ERROR_AND_RETURN(67, "CDir::Copy(): Cannot create " << + (dst_safe_path.empty() ? "target" : "temporary") << + " directory: " << dst.GetPath()); } } // Read all entries in source directory - auto_ptr - contents(src.GetEntriesPtr(kEmptyStr, fIgnoreRecursive)); - if (!contents.get()) { - LOG_ERROR_AND_RETURN("CDir::Copy():" - " Cannot get content of " << src.GetPath()); + unique_ptr contents(src.GetEntriesPtr(kEmptyStr, fIgnoreRecursive)); + if ( !contents.get() ) { + LOG_ERROR_AND_RETURN(68, "CDir::Copy(): Cannot get content of " + src.GetPath()); } // And copy each of them to target directory ITERATE(TEntries, e, *contents.get()) { CDirEntry& entry = **e; - if ( !F_ISSET(flags, fCF_Recursive) && - entry.IsDir(follow ? eFollowLinks : eIgnoreLinks)) { + if (!F_ISSET(flags, fCF_Recursive) && + entry.IsDir(follow ? eFollowLinks : eIgnoreLinks)) { continue; } // Copy entry - if ( !entry.CopyToDir(dst.GetPath(), flags, buf_size) ) { - LOG_ERROR_AND_RETURN("CDir::Copy():" - " Cannot copy " << entry.GetPath() << - " to directory " << dst.GetPath()); + if (!entry.CopyToDir(dst.GetPath(), flags, buf_size)) { + LOG_ERROR_AND_RETURN(69, "CDir::Copy():" + " Cannot copy " + entry.GetPath() + + " to directory " + dst.GetPath()); } } + // Safe copy for top directory -- renaming temporary to target + if (!dst_safe_path.empty()) { + if (!dst.Rename(dst_safe_path, fRF_Overwrite)) { + dst.Remove(); + LOG_ERROR_AND_RETURN(70, "CDir:Copy():" + " Cannot rename temporary directory " + dst.GetPath() + + " to " + dst_safe_path); + } + } // Preserve attributes if ( flags & fCF_PreserveAll ) { if ( !s_CopyAttrs(src.GetPath().c_str(), @@ -4158,7 +4239,7 @@ bool CDir::Copy(const string& newname, TCopyFlags flags, size_t buf_size) const } else { // Set default permissions for directory, if we should not // honor umask settings. - if (! NCBI_PARAM_TYPE(NCBI, FileAPIHonorUmask)::GetDefault()) { + if ( !NCBI_PARAM_TYPE(NCBI, FileAPIHonorUmask)::GetDefault()) { if ( !dst.SetMode(fDefault, fDefault, fDefault) ) { return false; } @@ -4173,23 +4254,33 @@ bool CDir::Remove(TRemoveFlags flags) const // Assumption _ASSERT(fDir_Self == fEntry); _ASSERT(eOnlyEmpty == fEntry); - + // Remove directory as empty if ( (flags & (fDir_All | fDir_Recursive)) == eOnlyEmpty ) { if ( NcbiSys_rmdir(_T_XCSTRING(GetPath())) != 0 ) { - LOG_ERROR_AND_RETURN_ERRNO("CDir::Remove():" - " Cannot remove (by implication empty)" - " directory " + GetPath()); + if ( (flags & fIgnoreMissing) && (errno == ENOENT) ) { + return true; + } + LOG_ERROR_AND_RETURN_ERRNO(71, "CDir::Remove():" + " Cannot remove (by implication empty)" + " directory " + GetPath()); } return true; } +#if !defined(NCBI_OS_MSWIN) + // Make directory writable for user to remove any entry inside + SetMode(CDirEntry::fWrite | CDirEntry::fModeAdd, + CDirEntry::fModeNoChange, + CDirEntry::fModeNoChange); +#endif + // Read all entries in directory - auto_ptr contents(GetEntriesPtr()); + unique_ptr contents(GetEntriesPtr()); if (!contents.get()) { - LOG_ERROR_AND_RETURN_ERRNO("CDir::Remove():" - " Cannot get content of " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(72, "CDir::Remove(): Cannot get content of " + GetPath()); } + // Remove each entry ITERATE(TEntries, entry, *contents.get()) { string name = (*entry)->GetName(); @@ -4227,11 +4318,13 @@ bool CDir::Remove(TRemoveFlags flags) const return false; } } + // Remove top directory - if ( (flags & fDir_Self) && - NcbiSys_rmdir(_T_XCSTRING(GetPath())) != 0 ) { - LOG_ERROR_AND_RETURN_ERRNO("CDir::Remove():" - " Cannot remove directory " + GetPath()); + if ( (flags & fDir_Self) && NcbiSys_rmdir(_T_XCSTRING(GetPath())) != 0 ) { + if ( (flags & fIgnoreMissing) && (errno == ENOENT) ) { + return true; + } + LOG_ERROR_AND_RETURN_ERRNO(73, "CDir::Remove(): Cannot remove directory " + GetPath()); } return true; } @@ -4251,10 +4344,9 @@ bool CDir::SetMode(TMode user_mode, TMode group_mode, } // Read all entries in directory - auto_ptr contents(GetEntriesPtr()); + unique_ptr contents(GetEntriesPtr()); if (!contents.get()) { - LOG_ERROR_AND_RETURN_ERRNO("CDir::SetMode():" - " Cannot get content of " + GetPath()); + LOG_ERROR_AND_RETURN_ERRNO(74, "CDir::SetMode(): Cannot get content of " + GetPath()); } // Process each entry ITERATE(TEntries, entry, *contents.get()) { @@ -4323,7 +4415,7 @@ bool CSymLink::Create(const string& path) const { #if defined(NCBI_OS_UNIX) char buf[PATH_MAX + 1]; - int len = (int) readlink(GetPath().c_str(), buf, sizeof(buf) - 1); + int len = (int)readlink(_T_XCSTRING(GetPath()), buf, sizeof(buf) - 1); if (len >= 0) { buf[len] = '\0'; if (strcmp(buf, path.c_str()) == 0) { @@ -4331,14 +4423,14 @@ bool CSymLink::Create(const string& path) const } } // Leave it to the kernel to decide whether the symlink can be recreated - if ( symlink(path.c_str(), GetPath().c_str()) == 0) { + if ( symlink(_T_XCSTRING(path), _T_XCSTRING(GetPath())) == 0 ) { return true; } - LOG_ERROR_AND_RETURN_ERRNO("CSymLink::Create(): failed: " + path); + LOG_ERROR_AND_RETURN_ERRNO(75, "CSymLink::Create(): failed: " + path); #else - LOG_ERROR_AND_RETURN_NCBI("CSymLink::Create():" - " Symbolic links not supported on this platform: " - + path, CNcbiError::eNotSupported); + LOG_ERROR_AND_RETURN_NCBI(76, "CSymLink::Create():" + " Symbolic links not supported on this platform: " + + path, CNcbiError::eNotSupported); #endif } @@ -4365,33 +4457,33 @@ bool CSymLink::Copy(const string& new_path, TCopyFlags flags, size_t buf_size) c // The source link must exists EType src_type = GetType(eIgnoreLinks); if ( src_type == eUnknown ) { - LOG_ERROR_AND_RETURN_NCBI("CSymLink::Copy():" - " Unknown entry type " + GetPath(), - CNcbiError::eNoSuchFileOrDirectory); + LOG_ERROR_AND_RETURN_NCBI(77, "CSymLink::Copy(): Unknown entry type " + GetPath(), + CNcbiError::eNoSuchFileOrDirectory); } CSymLink dst(new_path); - EType dst_type = dst.GetType(eIgnoreLinks); - bool dst_exists = (dst_type != eUnknown); + EType dst_type = dst.GetType(eIgnoreLinks); + bool dst_exists = (dst_type != eUnknown); + string dst_safe_path; // saved path for fCF_Safe // If destination exists... if ( dst_exists ) { // Check on copying link into yourself. if ( IsIdentical(dst.GetPath()) ) { - LOG_ERROR_AND_RETURN_NCBI("CSymLink::Copy():" - " Source and destination are the same: " - + GetPath(), CNcbiError::eInvalidArgument); + LOG_ERROR_AND_RETURN_NCBI(78, "CSymLink::Copy():" + " Source and destination are the same: " + GetPath(), + CNcbiError::eInvalidArgument); } // Can copy entries with different types? if ( F_ISSET(flags, fCF_EqualTypes) && (src_type != dst_type) ) { - LOG_ERROR_AND_RETURN_NCBI("CSymLink::Copy():" - " Cannot copy entries with different types: " - + GetPath(), CNcbiError::eOperationNotPermitted); + LOG_ERROR_AND_RETURN_NCBI(79, "CSymLink::Copy():" + " Cannot copy entries with different types: " + GetPath(), + CNcbiError::eOperationNotPermitted); } // Can overwrite entry? if ( !F_ISSET(flags, fCF_Overwrite) ) { - LOG_ERROR_AND_RETURN_NCBI("CSymLink::Copy():" - " Destination already exists: " - + dst.GetPath(), CNcbiError::eOperationNotPermitted); + LOG_ERROR_AND_RETURN_NCBI(80, "CSymLink::Copy():" + " Destination already exists: " + dst.GetPath(), + CNcbiError::eOperationNotPermitted); } // Copy only if destination is older if ( F_ISSET(flags, fCF_Update) && !IsNewer(dst.GetPath(), 0)) { @@ -4403,9 +4495,7 @@ bool CSymLink::Copy(const string& new_path, TCopyFlags flags, size_t buf_size) c // will be changed after backup CDirEntry dst_tmp(dst); if ( !dst_tmp.Backup(GetBackupSuffix(), eBackup_Rename) ) { - LOG_ERROR_AND_RETURN("CSymLink::Copy():" - " Cannot backup destination: " - << dst.GetPath()); + LOG_ERROR_AND_RETURN(81, "CSymLink::Copy(): Cannot backup destination: " + dst.GetPath()); } } // Overwrite destination entry @@ -4413,24 +4503,46 @@ bool CSymLink::Copy(const string& new_path, TCopyFlags flags, size_t buf_size) c dst.Remove(); } } - + // Safe copy -- create temporary symlink and rename later + if (F_ISSET(flags, fCF_Safe)) { + // Get new temporary name in the same directory + string path, name, ext; + SplitPath(dst.GetPath(), &path, &name, &ext); + string tmp = GetTmpNameEx(path.empty() ? CDir::GetCwd() : path, name + ext + kTmpSafeSuffix); + // Set new destination + dst_safe_path = dst.GetPath(); + dst.Reset(tmp); + } + else { + // Overwrite destination entry + if (dst_exists && F_ISSET(flags, fCF_Overwrite)) { + dst.Remove(); + } + } // Copy symbolic link (create new one) - char buf[PATH_MAX+1]; - int len = (int)readlink(GetPath().c_str(), buf, sizeof(buf)-1); - if ( len < 1 ) { - LOG_ERROR_AND_RETURN_ERRNO("CSymLink::Copy():" - " Cannot create new symbolic link to " - + GetPath()); + char buf[PATH_MAX + 1]; + int len = (int)readlink(_T_XCSTRING(GetPath()), buf, sizeof(buf)-1); + if (len < 1) { + LOG_ERROR_AND_RETURN_ERRNO(82, "CSymLink::Copy(): Cannot read symbolic link " + GetPath()); } buf[len] = '\0'; - if ( symlink(buf, new_path.c_str()) ) { - LOG_ERROR_AND_RETURN_ERRNO("CSymLink::Copy():" - " Cannot create new symbolic link to " - + GetPath()); + if (symlink(buf, _T_XCSTRING(dst.GetPath()))) { + LOG_ERROR_AND_RETURN_ERRNO(83, "CSymLink::Copy():" + " Cannot create symbolic link to " + dst.GetPath() + + " to " + string(buf)); } + // Safe copy -- renaming + if (F_ISSET(flags, fCF_Safe)) { + if (!dst.Rename(dst_safe_path, fRF_Overwrite)) { + dst.Remove(); + LOG_ERROR_AND_RETURN_NCBI(84, "CSymLink:Copy():" + " Cannot rename temporary symlink " + dst.GetPath() + + " to " + dst_safe_path, CNcbiError::eIoError); + } + } // Preserve attributes - if ( flags & fCF_PreserveAll ) { + if (flags & fCF_PreserveAll) { if (!s_CopyAttrs(GetPath().c_str(), new_path.c_str(), eLink, flags)) { return false; } @@ -4616,7 +4728,7 @@ void s_GetDiskSpace_PANFS(const string& path, if ( dlerr ) { msg = msg + " (" + dlerr + ")"; } - LOG_ERROR(msg); + LOG_ERROR(85, msg); CNcbiError::Set(CNcbiError::eUnknown, msg); if ( handle) { dlclose(handle); @@ -4660,7 +4772,7 @@ void s_GetDiskSpace_PANFS(const string& path, NCBI_THROW(CFileException, eFileSystemInfo, msg); } - LOG_ERROR(msg); + LOG_ERROR(86, msg); } } } @@ -5086,7 +5198,7 @@ CFileDeleteList::~CFileDeleteList() { ITERATE (TList, path, m_Paths) { if (!CDirEntry(*path).Remove(CDirEntry::eRecursiveIgnoreMissing)) { - ERR_POST(Warning << "CFileDeleteList: failed to remove path: " << *path); + ERR_POST_X(5, Warning << "CFileDeleteList: failed to remove path: " << *path); } } } @@ -5160,14 +5272,12 @@ const string& CTmpFile::GetFileName(void) const } -CNcbiIstream& CTmpFile::AsInputFile(EIfExists if_exists, - IOS_BASE::openmode mode) +CNcbiIstream& CTmpFile::AsInputFile(EIfExists if_exists, IOS_BASE::openmode mode) { if ( m_InFile.get() ) { switch (if_exists) { case eIfExists_Throw: - NCBI_THROW(CFileException, eTmpFile, - "AsInputFile() is already called"); + NCBI_THROW(CFileException, eTmpFile, "AsInputFile() is already called"); /*NOTREACHED*/ break; case eIfExists_Reset: @@ -5177,20 +5287,17 @@ CNcbiIstream& CTmpFile::AsInputFile(EIfExists if_exists, return *m_InFile; } } - mode |= IOS_BASE::in; - m_InFile.reset(new CNcbiIfstream(m_FileName.c_str())); + m_InFile.reset(new CNcbiIfstream(m_FileName.c_str(), IOS_BASE::in | mode)); return *m_InFile; } -CNcbiOstream& CTmpFile::AsOutputFile(EIfExists if_exists, - IOS_BASE::openmode mode) +CNcbiOstream& CTmpFile::AsOutputFile(EIfExists if_exists, IOS_BASE::openmode mode) { if ( m_OutFile.get() ) { switch (if_exists) { case eIfExists_Throw: - NCBI_THROW(CFileException, eTmpFile, - "AsOutputFile() is already called"); + NCBI_THROW(CFileException, eTmpFile, "AsOutputFile() is already called"); /*NOTREACHED*/ break; case eIfExists_Reset: @@ -5200,8 +5307,7 @@ CNcbiOstream& CTmpFile::AsOutputFile(EIfExists if_exists, return *m_OutFile; } } - mode |= IOS_BASE::out; - m_OutFile.reset(new CNcbiOfstream(m_FileName.c_str())); + m_OutFile.reset(new CNcbiOfstream(m_FileName.c_str(), IOS_BASE::out | mode)); return *m_OutFile; } @@ -5431,14 +5537,12 @@ bool CMemoryFileSegment::Flush(void) const #if defined(NCBI_OS_MSWIN) status = (FlushViewOfFile(m_DataPtrReal, m_LengthReal) != 0); if ( !status ) { - LOG_ERROR_AND_RETURN_WIN("CMemoryFileSegment::Flush():" - " Cannot flush memory segment"); + LOG_ERROR_AND_RETURN_WIN(87, "CMemoryFileSegment::Flush(): Cannot flush memory segment"); } #elif defined(NCBI_OS_UNIX) status = (msync((char*)m_DataPtrReal, m_LengthReal, MS_SYNC) == 0); if ( !status ) { - LOG_ERROR_AND_RETURN_ERRNO("CMemoryFileSegment::Flush():" - " Cannot flush memory segment"); + LOG_ERROR_AND_RETURN_ERRNO(87, "CMemoryFileSegment::Flush(): Cannot flush memory segment"); } #endif return status; @@ -5455,14 +5559,12 @@ bool CMemoryFileSegment::Unmap(void) #if defined(NCBI_OS_MSWIN) status = (UnmapViewOfFile(m_DataPtrReal) != 0); if (!status) { - LOG_ERROR_AND_RETURN_WIN("CMemoryFileSegment::Unmap():" - " Cannot unmap memory segment"); + LOG_ERROR_AND_RETURN_WIN(88, "CMemoryFileSegment::Unmap(): Cannot unmap memory segment"); } #elif defined(NCBI_OS_UNIX) status = (munmap((char*)m_DataPtrReal, (size_t) m_LengthReal) == 0); if (!status) { - LOG_ERROR_AND_RETURN_ERRNO("CMemoryFileSegment::Unmap():" - " Cannot unmap memory segment"); + LOG_ERROR_AND_RETURN_ERRNO(88, "CMemoryFileSegment::Unmap(): Cannot unmap memory segment"); } #endif if ( status ) { @@ -5591,8 +5693,7 @@ bool CMemoryFileMap::Unmap(void* ptr) } } if ( !status ) { - LOG_ERROR_AND_RETURN_ERRNO("CMemoryFileMap::Unmap():" - " Memory segment not found"); + LOG_ERROR_AND_RETURN_ERRNO(89, "CMemoryFileMap::Unmap(): Memory segment not found"); } return status; } @@ -5999,29 +6100,29 @@ void x_Glob(const string& path, else { if ( !found.empty() ) { ITERATE(std::list, it, found) { - x_Glob(CDirEntry::AddTrailingPathSeparator(*it), - parts, next, result, flags); + x_Glob(CDirEntry::AddTrailingPathSeparator(*it), parts, next, result, flags); } } else { - x_Glob(CDirEntry::AddTrailingPathSeparator(path + masks.front()), - parts, next, result, flags); + x_Glob(CDirEntry::AddTrailingPathSeparator(path + masks.front()), parts, next, result, flags); } } } -void FindFiles(const string& pattern, - std::list& result, - TFindFiles flags) +void FindFiles(const string& pattern, std::list& result, TFindFiles flags) { + TFindFiles find_type = flags & fFF_All; + if ( find_type == 0 ) { + flags |= fFF_All; + } + string kDirSep(1, CDirEntry::GetPathSeparator()); string abs_path = CDirEntry::CreateAbsolutePath(pattern); string search_path = kDirSep; std::list parts; - NStr::Split(abs_path, kDirSep, parts, - NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); + NStr::Split(abs_path, kDirSep, parts, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); if ( parts.empty() ) { return; } @@ -6068,6 +6169,70 @@ void FindFiles(const string& pattern, } +#define UNDEFINED_SORT_MODE (ESort)kMax_Int + +SCompareDirEntries::SCompareDirEntries(ESort s1) +{ + m_Sort[0] = s1; + m_Sort[1] = UNDEFINED_SORT_MODE; + m_Sort[2] = UNDEFINED_SORT_MODE; +} +SCompareDirEntries::SCompareDirEntries(ESort s1, ESort s2) +{ + m_Sort[0] = s1; + m_Sort[1] = s2; + m_Sort[2] = UNDEFINED_SORT_MODE; +} +SCompareDirEntries::SCompareDirEntries(ESort s1, ESort s2, ESort s3) +{ + m_Sort[0] = s1; + m_Sort[1] = s2; + m_Sort[2] = s3; +} + +bool SCompareDirEntries::operator()(const string& p1, const string& p2) +{ + // Default case + if (m_Sort[0] == ePath) { + return (p1 < p2); + } + string d1, n1, e1; + string d2, n2, e2; + CDirEntry::SplitPath(p1, &d1, &n1, &e1); + CDirEntry::SplitPath(p2, &d2, &n2, &e2); + + int nc = 0; + + for (int i = 0; i < 3; i++) { + if (m_Sort[i] == UNDEFINED_SORT_MODE) { + break; + } + switch (m_Sort[i]) { + case ePath: + // usually we shouldn't get here, so just compare and exit + return (p1 < p2); + case eDir: + nc = NStr::CompareCase(d1, d2); + break; + case eName: + nc = NStr::CompareCase(n1 + e1, n2 + e2); + break; + case eBase: + nc = NStr::CompareCase(n1, n2); + break; + case eExt: + nc = NStr::CompareCase(e1, e2); + break; + default: + NCBI_THROW(CCoreException, eInvalidArg, "Unknown sorting mode"); + } + if (nc != 0) + break; + } + return nc < 0; +} + + ////////////////////////////////////////////////////////////////////////////// // @@ -6316,27 +6481,47 @@ void CFileIO::Close(void) size_t CFileIO::Read(void* buf, size_t count) const { -#if defined(NCBI_OS_MSWIN) - DWORD n = 0; - if (count > ULONG_MAX) { - count = ULONG_MAX; + if (count == 0) { + return 0; } - if ( ::ReadFile(m_Handle, buf, (DWORD)count, &n, NULL) == 0 ) { - if (GetLastError() == ERROR_HANDLE_EOF) { - return 0; + char* ptr = (char*) buf; + +#if defined(NCBI_OS_MSWIN) + const DWORD kMax = numeric_limits::max(); +#elif defined(NCBI_OS_UNIX) + const ssize_t kMax = numeric_limits::max(); +#endif + + while (count) { +#if defined(NCBI_OS_MSWIN) + DWORD nmax = count > kMax ? kMax : (DWORD) count; + DWORD n = 0; + if ( ::ReadFile(m_Handle, ptr, nmax, &n, NULL) == 0 ) { + if (GetLastError() == ERROR_HANDLE_EOF) { + break; + } + NCBI_THROW(CFileErrnoException, eFileIO, "ReadFile() failed"); + } + if ( n == 0 ) { + break; } - NCBI_THROW(CFileErrnoException, eFileIO, "ReadFile() failed"); - } - return n; #elif defined(NCBI_OS_UNIX) - ssize_t n = 0; - while ((n = ::read(int(m_Handle), buf, count)) < 0) { - if (errno != EINTR) { + ssize_t nmax = count > kMax ? kMax : (ssize_t) count; + ssize_t n = ::read(int(m_Handle), ptr, nmax); + if (n == 0) { + break; + } + if ( n < 0 ) { + if (errno == EINTR) { + continue; + } NCBI_THROW(CFileErrnoException, eFileIO, "read() failed"); } - } - return n; #endif + count -= n; + ptr += n; + } + return ptr - (char*)buf; } @@ -6346,31 +6531,34 @@ size_t CFileIO::Write(const void* buf, size_t count) const return 0; } const char* ptr = (const char*) buf; - size_t n = count; - do { + #if defined(NCBI_OS_MSWIN) - DWORD n_write = n > ULONG_MAX ? ULONG_MAX : (DWORD) n; - DWORD n_written = 0; - if ( ::WriteFile(m_Handle, ptr, n_write, &n_written, NULL) == 0 ) { + const DWORD kMax = numeric_limits::max(); +#elif defined(NCBI_OS_UNIX) + const ssize_t kMax = numeric_limits::max(); +#endif + + while (count) { +#if defined(NCBI_OS_MSWIN) + DWORD nmax = count > kMax ? kMax : (DWORD) count; + DWORD n = 0; + if ( ::WriteFile(m_Handle, ptr, nmax, &n, NULL) == 0 ) { NCBI_THROW(CFileErrnoException, eFileIO, "WriteFile() failed"); } #elif defined(NCBI_OS_UNIX) - ssize_t n_written = ::write(int(m_Handle), ptr, n); - if (n_written == 0) { - NCBI_THROW(CFileErrnoException, eFileIO, "write() failed"); + ssize_t nmax = count > kMax ? kMax : (ssize_t) count; + ssize_t n = ::write(int(m_Handle), ptr, nmax); + if ( n < 0 && errno == EINTR ) { + continue; } - if ( n_written < 0 ) { - if (errno == EINTR) { - continue; - } + if ( n <= 0 ) { NCBI_THROW(CFileErrnoException, eFileIO, "write() failed"); } #endif - n -= n_written; - ptr += n_written; + count -= n; + ptr += n; } - while (n > 0); - return count; + return ptr - (char*)buf; } @@ -7031,7 +7219,7 @@ void CFileAPI::SetLogging(ESwitch on_off_default) { NCBI_PARAM_TYPE(NCBI, FileAPILogging)::SetDefault( on_off_default != eDefault ? - on_off_default != eOff : DEFAULT_LOGGING_VALUE); + on_off_default != eOff : DEFAULT_LOGGING_VALUE); } void CFileAPI::SetHonorUmask(ESwitch on_off_default) @@ -7047,4 +7235,6 @@ void CFileAPI::SetDeleteReadOnlyFiles(ESwitch on_off_default) on_off_default == eOn); } + END_NCBI_SCOPE + diff --git a/c++/src/corelib/ncbimtx.cpp b/c++/src/corelib/ncbimtx.cpp index 8e5614c6..041cdf2b 100644 --- a/c++/src/corelib/ncbimtx.cpp +++ b/c++/src/corelib/ncbimtx.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbimtx.cpp 505546 2016-06-27 13:14:02Z grichenk $ +/* $Id: ncbimtx.cpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1429,7 +1429,7 @@ CSemaphore::CSemaphore(unsigned int init_count, unsigned int max_count) "greater than max_count"); m_Sem = new SSemaphore; - auto_ptr auto_sem(m_Sem); + unique_ptr auto_sem(m_Sem); #if defined(NCBI_POSIX_THREADS) m_Sem->max_count = max_count; @@ -1995,8 +1995,6 @@ CSpinLock::Unlock(void) // CONDITION VARIABLE // -#if defined(NCBI_HAVE_CONDITIONAL_VARIABLE) - bool CConditionVariable::IsSupported(void) { return true; @@ -2004,9 +2002,12 @@ bool CConditionVariable::IsSupported(void) CConditionVariable::CConditionVariable(void) +#if defined(NCBI_THREADS) : m_WaitCounter(0), m_WaitMutex(NULL) +#endif // defined(NCBI_THREADS) { +#if defined(NCBI_THREADS) #if defined(NCBI_OS_MSWIN) InitializeConditionVariable(&m_ConditionVar); #else @@ -2032,11 +2033,13 @@ CConditionVariable::CConditionVariable(void) "CConditionVariable: unknown error"); } #endif +#endif // defined(NCBI_THREADS) } CConditionVariable::~CConditionVariable(void) { +#if defined(NCBI_THREADS) #if !defined(NCBI_OS_MSWIN) int res = pthread_cond_destroy(&m_ConditionVar); switch (res) { @@ -2057,9 +2060,11 @@ CConditionVariable::~CConditionVariable(void) } NCBI_TROUBLE("CConditionVariable: pthread_cond_destroy() failed"); #endif +#endif // defined(NCBI_THREADS) } +#if defined(NCBI_THREADS) template class CQuickAndDirtySamePointerGuard { @@ -2179,11 +2184,13 @@ bool CConditionVariable::x_WaitForSignal return true; } +#endif // defined(NCBI_THREADS) bool CConditionVariable::WaitForSignal(CMutex& mutex, const CDeadline& deadline) { +#if defined(NCBI_THREADS) SSystemMutex& sys_mtx = mutex; if (sys_mtx.m_Count != 1) { NCBI_THROW(CConditionVariableException, eMutexLockCount, @@ -2199,22 +2206,30 @@ bool CConditionVariable::WaitForSignal(CMutex& mutex, bool res = x_WaitForSignal(sys_mtx.m_Mutex, deadline); sys_mtx.Lock(SSystemFastMutex::ePseudo); return res; +#else + return true; +#endif // defined(NCBI_THREADS) } bool CConditionVariable::WaitForSignal(CFastMutex& mutex, const CDeadline& deadline) { +#if defined(NCBI_THREADS) SSystemFastMutex& sys_mtx = mutex; sys_mtx.Unlock(SSystemFastMutex::ePseudo); bool res = x_WaitForSignal(sys_mtx, deadline); sys_mtx.Lock(SSystemFastMutex::ePseudo); return res; +#else + return true; +#endif // defined(NCBI_THREADS) } void CConditionVariable::SignalSome(void) { +#if defined(NCBI_THREADS) #if defined(NCBI_OS_MSWIN) WakeConditionVariable(&m_ConditionVar); #else @@ -2230,11 +2245,13 @@ void CConditionVariable::SignalSome(void) } } #endif +#endif // defined(NCBI_THREADS) } void CConditionVariable::SignalAll(void) { +#if defined(NCBI_THREADS) #if defined(NCBI_OS_MSWIN) WakeAllConditionVariable(&m_ConditionVar); #else @@ -2250,10 +2267,9 @@ void CConditionVariable::SignalAll(void) } } #endif +#endif // defined(NCBI_THREADS) } -#endif /* NCBI_HAVE_CONDITIONAL_VARIABLE */ - const char* CConditionVariableException::GetErrCodeString(void) const { diff --git a/c++/src/corelib/ncbireg.cpp b/c++/src/corelib/ncbireg.cpp index 30d547fc..dfa5781b 100644 --- a/c++/src/corelib/ncbireg.cpp +++ b/c++/src/corelib/ncbireg.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbireg.cpp 507290 2016-07-18 15:24:29Z elisovdn $ +/* $Id: ncbireg.cpp 540943 2017-07-12 15:49:26Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -262,8 +262,11 @@ bool IRegistry::Write(CNcbiOstream& os, TFlags flags) const const string& IRegistry::Get(const string& section, const string& name, TFlags flags) const { + if (flags & fInternalCheckedAndLocked) return x_Get(section, name, flags); + x_CheckFlags("IRegistry::Get", flags, (TFlags)fLayerFlags | fInternalSpaces | fSectionlessEntries); + if ( !(flags & fTPFlags) ) { flags |= fTPFlags; } @@ -280,13 +283,15 @@ const string& IRegistry::Get(const string& section, const string& name, return kEmptyStr; } TReadGuard LOCK(*this); - return x_Get(clean_section, clean_name, flags); + return x_Get(clean_section, clean_name, flags | fInternalCheckedAndLocked); } bool IRegistry::HasEntry(const string& section, const string& name, TFlags flags) const { + if (flags & fInternalCheckedAndLocked) return x_HasEntry(section, name, flags); + x_CheckFlags("IRegistry::HasEntry", flags, (TFlags)fLayerFlags | fInternalSpaces | fCountCleared | fSections | fSectionlessEntries); @@ -309,7 +314,7 @@ bool IRegistry::HasEntry(const string& section, const string& name, return false; } TReadGuard LOCK(*this); - return x_HasEntry(clean_section, clean_name, flags); + return x_HasEntry(clean_section, clean_name, flags | fInternalCheckedAndLocked); } @@ -1573,7 +1578,7 @@ void CNcbiRegistry::x_Init(void) m_FileRegistry.Reset(new CTwoLayerRegistry(NULL, cf)); x_Add(*m_FileRegistry, ePriority_File, sm_FileRegName); - m_SysRegistry.Reset(new CTwoLayerRegistry(NULL, cf)); + m_SysRegistry.Reset(new CCompoundRWRegistry(cf)); x_Add(*m_SysRegistry, ePriority_Default - 1, sm_SysRegName); const TXChar* xoverride_path = NcbiSys_getenv(_TX("NCBI_CONFIG_OVERRIDES")); @@ -1834,7 +1839,9 @@ bool CCompoundRWRegistry::LoadBaseRegistries(TFlags flags, int metareg_flags, } _TRACE("LoadBaseRegistries(" << this << "): using " << s); NStr::Split(s, ", ", names, - NStr::fSplit_CanSingleQuote | NStr::fSplit_MergeDelims); + NStr::fSplit_CanSingleQuote | + NStr::fSplit_MergeDelimiters | + NStr::fSplit_Truncate); }} typedef pair > TNewBase; diff --git a/c++/src/corelib/ncbistr.cpp b/c++/src/corelib/ncbistr.cpp index b85d0a46..8f7bd688 100644 --- a/c++/src/corelib/ncbistr.cpp +++ b/c++/src/corelib/ncbistr.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbistr.cpp 511434 2016-08-22 15:26:41Z ivanov $ +/* $Id: ncbistr.cpp 536001 2017-05-15 13:28:41Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -2605,7 +2605,8 @@ SIZE_TYPE NStr::DoubleToStringPosix(double val, unsigned int precision, *buffer_pos++ = 'e'; *buffer_pos++ = exp_positive ? '+' : '-'; -#if defined(NCBI_OS_MSWIN) +//#if defined(NCBI_OS_MSWIN) +#if NCBI_COMPILER_MSVC && _MSC_VER < 1900 bool need_zeros = true; size_t need_digits = 3; #else @@ -3163,6 +3164,18 @@ void NStr::TrimPrefixInPlace(CTempString& str, const CTempString prefix, } +CTempString NStr::TrimPrefix_Unsafe(const CTempString str, const CTempString prefix, + ECase use_case) +{ + if (!str.length() || + !prefix.length() || + !Equal(str, 0, prefix.length(), prefix, use_case)) { + return str; + } + return CTempString(str.data() + prefix.length(), str.length() - prefix.length()); +} + + void NStr::TrimSuffixInPlace(string& str, const CTempString suffix, ECase use_case) { @@ -3180,23 +3193,38 @@ void NStr::TrimSuffixInPlace(CTempString& str, const CTempString suffix, { if (!str.length() || !suffix.length() || - !Equal(str, str.length() - suffix.length(), suffix.length(), suffix, use_case)) { + !Equal(str, str.length() - suffix.length(), suffix.length(), suffix, use_case)) { return; } str.erase(str.length() - suffix.length()); } +CTempString NStr::TrimSuffix_Unsafe(const CTempString str, const CTempString suffix, + ECase use_case) +{ + if (!str.length() || + !suffix.length() || + !Equal(str, str.length() - suffix.length(), suffix.length(), suffix, use_case)) { + return str; + } + return CTempString(str.data(), str.length() - suffix.length()); +} + + string& NStr::Replace(const string& src, const string& search, const string& replace, - string& dst, SIZE_TYPE start_pos, SIZE_TYPE max_replace) + string& dst, SIZE_TYPE start_pos, SIZE_TYPE max_replace, + SIZE_TYPE* num_replace) { // source and destination should not be the same if (&src == &dst) { NCBI_THROW2(CStringException, eBadArgs, "NStr::Replace(): source and destination are the same",0); } - if ( start_pos + search.size() > src.size() || search == replace ) { + if (num_replace) + *num_replace = 0; + if (start_pos + search.size() > src.size() || search == replace) { dst = src; return dst; } @@ -3238,10 +3266,12 @@ string& NStr::Replace(const string& src, copy(replace.begin(), replace.end(), dst_pos); dst_pos += replace.size(); start_pos += search.size(); - src_start = src.begin() + start_pos; + src_start = src.begin() + start_pos; } // Copy source's string tail to the place copy(src_start, src.end(), dst_pos); + if (num_replace) + *num_replace = n; } else { // Replacing string is shorter or have the same length. @@ -3254,6 +3284,8 @@ string& NStr::Replace(const string& src, break; dst.replace(start_pos, search.size(), replace); start_pos += replace.size(); + if (num_replace) + (*num_replace)++; } } return dst; @@ -3262,73 +3294,25 @@ string& NStr::Replace(const string& src, string NStr::Replace(const string& src, const string& search, const string& replace, - SIZE_TYPE start_pos, SIZE_TYPE max_replace) + SIZE_TYPE start_pos, SIZE_TYPE max_replace, + SIZE_TYPE* num_replace) { string dst; - Replace(src, search, replace, dst, start_pos, max_replace); + Replace(src, search, replace, dst, start_pos, max_replace, num_replace); return dst; } -#if 0 -static -string& _replace_reduct(string& src, - const string& search, const string& replace, - SIZE_TYPE start_pos, SIZE_TYPE max_replace) -{ - size_t remove_len = 0; - - const char* start_ptr = src.c_str() + start_pos; - char* write_pos = (char*) start_ptr; - - for (SIZE_TYPE count = 0; !(max_replace && count >= max_replace); count++) { - - const char* found = strstr(start_ptr, search.c_str()); - - SIZE_TYPE len = (found?found:(src.c_str() + src.size())) - start_ptr; - if (len && write_pos != start_ptr) - { - memcpy(write_pos, start_ptr, len); - } - - if (found == 0) - break; - - write_pos += len; - start_ptr = found + search.size(); - - if (replace.size() == 1) - { - *write_pos++ = replace[0]; - } else - if (replace.size() > 0) - { - memcpy(write_pos, replace.c_str(), replace.size()); - write_pos += replace.size(); - } - - remove_len += (search.size() - replace.size()); - } - - if (remove_len) - src.resize(src.size() - remove_len); - - return src; -} -#endif string& NStr::ReplaceInPlace(string& src, const string& search, const string& replace, - SIZE_TYPE start_pos, SIZE_TYPE max_replace) + SIZE_TYPE start_pos, SIZE_TYPE max_replace, + SIZE_TYPE* num_replace) { - if ( start_pos + search.size() > src.size() || - search == replace ) + if ( num_replace ) + *num_replace = 0; + if ( start_pos + search.size() > src.size() || search == replace ) return src; -#if 0 - if (search.size() >= replace.size()) - return _replace_reduct(src, search, replace, start_pos, max_replace); -#endif - bool equal_len = (search.size() == replace.size()); for (SIZE_TYPE count = 0; !(max_replace && count >= max_replace); count++){ start_pos = src.find(search, start_pos); @@ -3342,6 +3326,8 @@ string& NStr::ReplaceInPlace(string& src, src.replace(start_pos, search.size(), replace); } start_pos += replace.size(); + if (num_replace) + (*num_replace)++; } return src; } @@ -3364,6 +3350,15 @@ TContainer& s_Split(const TString& str, const TString& delim, return arr; } +#define CHECK_SPLIT_TEMPSTRING_FLAGS(where) \ + { \ + if ((flags & (NStr::fSplit_CanEscape | NStr::fSplit_CanQuote)) && !storage) { \ + NCBI_THROW2(CStringException, eBadArgs, \ + "NStr::" #where "(): the selected flags require non-NULL storage", 0); \ + } \ +} + + list& NStr::Split(const CTempString str, const CTempString delim, list& arr, TSplitFlags flags, vector* token_pos) @@ -3380,22 +3375,25 @@ vector& NStr::Split(const CTempString str, const CTempString delim, list& NStr::Split(const CTempString str, const CTempString delim, list& arr, TSplitFlags flags, - vector* token_pos) + vector* token_pos, CTempString_Storage* storage) { - return s_Split(str, delim, arr, flags, token_pos); + CHECK_SPLIT_TEMPSTRING_FLAGS(Split); + return s_Split(str, delim, arr, flags, token_pos, storage); } vector& NStr::Split(const CTempString str, const CTempString delim, vector& arr, TSplitFlags flags, - vector* token_pos) + vector* token_pos, CTempString_Storage* storage) { - return s_Split(str, delim, arr, flags, token_pos); + CHECK_SPLIT_TEMPSTRING_FLAGS(Split); + return s_Split(str, delim, arr, flags, token_pos, storage); } list& NStr::Split(const CTempString str, const CTempString delim, list& arr, TSplitFlags flags, vector* token_pos, CTempString_Storage* storage) { + CHECK_SPLIT_TEMPSTRING_FLAGS(Split); return s_Split(str, delim, arr, flags, token_pos, storage); } @@ -3403,6 +3401,7 @@ vector& NStr::Split(const CTempString str, const CTempString deli vector& arr, TSplitFlags flags, vector* token_pos, CTempString_Storage* storage) { + CHECK_SPLIT_TEMPSTRING_FLAGS(Split); return s_Split(str, delim, arr, flags, token_pos, storage); } @@ -3422,116 +3421,34 @@ vector& NStr::SplitByPattern(const CTempString str, const CTempString de list& NStr::SplitByPattern(const CTempString str, const CTempString delim, list& arr, TSplitFlags flags, - vector* token_pos) + vector* token_pos, CTempString_Storage* storage) { - return s_Split(str, delim, arr, fSplit_ByPattern | flags, token_pos); + CHECK_SPLIT_TEMPSTRING_FLAGS(SplitByPattern); + return s_Split(str, delim, arr, fSplit_ByPattern | flags, token_pos, storage); } vector& NStr::SplitByPattern(const CTempString str, const CTempString delim, vector& arr, TSplitFlags flags, - vector* token_pos) + vector* token_pos, CTempString_Storage* storage) { - return s_Split(str, delim, arr, fSplit_ByPattern | flags, token_pos); + CHECK_SPLIT_TEMPSTRING_FLAGS(SplitByPattern); + return s_Split(str, delim, arr, fSplit_ByPattern | flags, token_pos, storage); } list& NStr::SplitByPattern(const CTempString str, const CTempString delim, list& arr, TSplitFlags flags, - vector* token_pos) + vector* token_pos, CTempString_Storage* storage) { - return s_Split(str, delim, arr, fSplit_ByPattern | flags, token_pos); + CHECK_SPLIT_TEMPSTRING_FLAGS(SplitByPattern); + return s_Split(str, delim, arr, fSplit_ByPattern | flags, token_pos, storage); } vector& NStr::SplitByPattern(const CTempString str, const CTempString delim, vector& arr, TSplitFlags flags, - vector* token_pos) -{ - return s_Split(str, delim, arr, fSplit_ByPattern | flags, token_pos); -} - - - -/// @deprecated -list& NStr::Split(const CTempString str, - const CTempString delim, - list& arr, EMergeDelims merge, - vector* token_pos) -{ - vector arr2; - Split(str, delim, arr2, (TSplitFlags)merge, token_pos); - ITERATE (vector, it, arr2) { - arr.push_back(*it); - } - return arr; -} - -/// @deprecated -vector& NStr::Tokenize(const CTempString str, const CTempString delim, - vector& arr, TSplitFlags flags, - vector* token_pos) -{ - return s_Split(str, delim, arr, flags, token_pos); -} - -/// @deprecated -vector& NStr::Tokenize(const CTempString str, const CTempString delim, - vector& arr, EMergeDelims merge, - vector* token_pos) + vector* token_pos, CTempString_Storage* storage) { - return s_Split(str, delim, arr, (TSplitFlags)merge, token_pos); -} - -/// @deprecated -vector& NStr::Tokenize(const CTempString str, - const CTempString delim, - vector& arr, - TSplitFlags flags, - vector* token_pos, - CTempString_Storage* storage) -{ - return s_Split(str, delim, arr, flags, token_pos, storage); -} - -/// @deprecated -vector& NStr::Tokenize(const CTempString str, - const CTempString delim, - vector& arr, - EMergeDelims merge, - vector* token_pos) -{ - vector arr2; - Split(str, delim, arr2, (TSplitFlags)merge, token_pos); - arr.reserve(arr.size() + arr2.size()); - ITERATE (vector, it, arr2) { - arr.push_back(*it); - } - return arr; -} - - -/// @deprecated -vector& NStr::TokenizePattern(const CTempString str, - const CTempString delim, - vector& arr, - EMergeDelims merge, - vector* token_pos) -{ - return SplitByPattern(str, delim, arr, (TSplitFlags)merge, token_pos); -} - -/// @deprecated -vector& NStr::TokenizePattern(const CTempString str, - const CTempString delim, - vector& arr, - EMergeDelims merge, - vector* token_pos) -{ - vector arr2; - Split(str, delim, arr2, fSplit_ByPattern | (TSplitFlags)merge, token_pos); - arr.reserve(arr.size() + arr2.size()); - ITERATE (vector, it, arr2) { - arr.push_back(*it); - } - return arr; + CHECK_SPLIT_TEMPSTRING_FLAGS(SplitByPattern); + return s_Split(str, delim, arr, fSplit_ByPattern | flags, token_pos, storage); } @@ -3539,7 +3456,8 @@ bool NStr::SplitInTwo(const CTempString str, const CTempString delim, string& str1, string& str2, TSplitFlags flags) { CTempStringEx ts1, ts2; - bool result = SplitInTwo(str, delim, ts1, ts2, flags); + CTempString_Storage storage; + bool result = SplitInTwo(str, delim, ts1, ts2, flags, &storage); str1 = ts1; str2 = ts2; return result; @@ -3547,10 +3465,11 @@ bool NStr::SplitInTwo(const CTempString str, const CTempString delim, bool NStr::SplitInTwo(const CTempString str, const CTempString delim, - CTempString& str1, CTempString& str2, TSplitFlags flags) + CTempString& str1, CTempString& str2, TSplitFlags flags, + CTempString_Storage* storage) { CTempStringEx ts1, ts2; - bool result = SplitInTwo(str, delim, ts1, ts2, flags); + bool result = SplitInTwo(str, delim, ts1, ts2, flags, storage); str1 = ts1; str2 = ts2; return result; @@ -3559,14 +3478,9 @@ bool NStr::SplitInTwo(const CTempString str, const CTempString delim, bool NStr::SplitInTwo(const CTempString str, const CTempString delim, CTempStringEx& str1, CTempStringEx& str2, - TSplitFlags flags, - CTempString_Storage* storage) + TSplitFlags flags, CTempString_Storage* storage) { - if ((flags & (fSplit_CanEscape | fSplit_CanQuote)) && !storage) { - NCBI_THROW2(CStringException, eBadArgs, - "NStr::SplitInTwo(): the selected flags require non-NULL storage", - 0); - } + CHECK_SPLIT_TEMPSTRING_FLAGS(SplitInTwo); typedef CStrTokenize > TSplitter; @@ -3588,24 +3502,6 @@ bool NStr::SplitInTwo(const CTempString str, const CTempString delim, return delim_pos != NPOS; } -/// @deprecated -bool NStr::SplitInTwo(const CTempString str, - const CTempString delim, - string& str1, string& str2, EMergeDelims merge) { - return SplitInTwo(str, delim, str1, str2, (TSplitFlags)merge); -} - -// @deprecated -bool NStr::SplitInTwo(const CTempString str, const CTempString delim, - CTempString& str1, CTempString& str2, EMergeDelims merge) -{ - CTempStringEx tsx1, tsx2; - bool result = SplitInTwo(str, delim, tsx1, tsx2, (TSplitFlags)merge); - str1 = tsx1; - str2 = tsx2; - return result; -} - template string s_NStr_Join(const T& arr, const CTempString delim) @@ -3687,7 +3583,7 @@ string NStr::Join(const set& arr, const CTempString delim) string NStr::Sanitize(CTempString str, TSS_Flags flags) { - auto_ptr out; + unique_ptr out; SIZE_TYPE i; SIZE_TYPE pos = 0; // start position of the substring SIZE_TYPE n_good = 0; // length of substring (good symbols) @@ -3826,7 +3722,7 @@ static string s_PrintableString(const CTempString str, NStr::TPrintableMode mode, ELanguage lang) { - auto_ptr out; + unique_ptr out; SIZE_TYPE i, j = 0; for (i = 0; i < str.size(); i++) { @@ -7474,9 +7370,9 @@ bool CStrTokenizeBase::Advance(CTempStringList* part_collector, SIZE_TYPE* ptr_d // Each chunk covers the half-open interval [part_start, delim_pos). - while ( !done - && ((delim_pos = m_Str.find_first_of(m_InternalDelim, pos)) - != NPOS)) { + while ( !done && + ((delim_pos = m_Str.find_first_of(m_InternalDelim, pos)) != NPOS)) { + SIZE_TYPE next_start = pos = delim_pos + 1; bool handled = false; char c = m_Str[delim_pos]; @@ -7484,10 +7380,10 @@ bool CStrTokenizeBase::Advance(CTempStringList* part_collector, SIZE_TYPE* ptr_d if ((m_Flags & NStr::fSplit_CanEscape) != 0 && c == '\\') { // treat the following character literally if (++pos > m_Str.size()) { - NCBI_THROW2(CStringException, eFormat, "Unescaped trailing \\", - delim_pos); + NCBI_THROW2(CStringException, eFormat, "Unescaped trailing \\", delim_pos); } handled = true; + } else if ((m_Flags & NStr::fSplit_CanQuote) != 0) { if (active_quote != '\0') { if (c == active_quote) { @@ -7538,9 +7434,7 @@ bool CStrTokenizeBase::Advance(CTempStringList* part_collector, SIZE_TYPE* ptr_d } if (active_quote != '\0') { - NCBI_THROW2(CStringException, eFormat, - string("Unbalanced ") + active_quote, - quote_pos); + NCBI_THROW2(CStringException, eFormat, string("Unbalanced ") + active_quote, quote_pos); } if (delim_pos == NPOS) { diff --git a/c++/src/corelib/ncbistre.cpp b/c++/src/corelib/ncbistre.cpp index 31f1ca66..c808a5cf 100644 --- a/c++/src/corelib/ncbistre.cpp +++ b/c++/src/corelib/ncbistre.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbistre.cpp 488254 2015-12-29 13:56:26Z ivanov $ +/* $Id: ncbistre.cpp 524193 2017-01-10 15:19:40Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -413,6 +413,22 @@ CNcbiOstrstreamToString::operator string(void) const } +CNcbiOstream& operator<<(CNcbiOstream& out, const CNcbiOstrstreamToString& s) +{ +#ifdef NCBI_SHUN_OSTRSTREAM + out << s.m_Out.str(); +#else + SIZE_TYPE len = (SIZE_TYPE) s.m_Out.pcount(); + if ( len ) { + const char* str = s.m_Out.str(); + s.m_Out.freeze(false); + out.write(str, len); + } +#endif + return out; +} + + CNcbiOstream& operator<<(CNcbiOstream& out, CUpcaseStringConverter s) { ITERATE ( string, c, s.m_String ) { diff --git a/c++/src/corelib/ncbithr.cpp b/c++/src/corelib/ncbithr.cpp index 62050d16..a0b7ef40 100644 --- a/c++/src/corelib/ncbithr.cpp +++ b/c++/src/corelib/ncbithr.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbithr.cpp 467434 2015-05-13 16:41:39Z sadyrovr $ +/* $Id: ncbithr.cpp 536050 2017-05-15 16:18:35Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -149,7 +149,7 @@ CSafeStaticLifeSpan::eLifeSpan_Long); CUsedTlsBases& CUsedTlsBases::GetUsedTlsBases(void) { - if ( !CThread::GetSelf() ) + if ( CThread::IsMain() ) { return *s_MainUsedTlsBases; } @@ -418,6 +418,23 @@ static DECLARE_TLS_VAR(CThread*, sx_ThreadPtr); static DECLARE_TLS_VAR(CThread::TID, sx_ThreadId); static bool sm_MainThreadIdInitialized = false; static const CThread::TID kMainThreadId = ~CThread::TID(0); +static CThread::TID sx_MainThreadId = kMainThreadId; + + +DEFINE_STATIC_FAST_MUTEX(s_MainThreadIdMutex); + +CThread::TID sx_GetMainThreadId() +{ + CFastMutexGuard guard(s_MainThreadIdMutex); + return sx_MainThreadId; +} + + +void sx_SetMainThreadId(CThread::TID id) +{ + CFastMutexGuard guard(s_MainThreadIdMutex); + sx_MainThreadId = id; +} static int sx_GetNextThreadId(void) @@ -442,12 +459,25 @@ void CThread::x_InitializeThreadId(void) void CThread::InitializeMainThreadId(void) { // mark main thread +#if defined(NCBI_THREADS) + CFastMutexGuard guard(s_MainThreadIdMutex); +#endif + if ( sm_MainThreadIdInitialized ) { + if (sx_ThreadId != sx_MainThreadId) { + ERR_POST("Can not change main thread ID"); + } + return; + } #if defined(NCBI_THREADS) _ASSERT(!sx_ThreadPtr); - _ASSERT(!sx_ThreadId); + _ASSERT(sx_MainThreadId == kMainThreadId); #endif + if ( !sx_ThreadId ) { + // Not yet assigned - use the default value. + sx_ThreadId = kMainThreadId; + } + sx_MainThreadId = sx_ThreadId; sx_ThreadPtr = 0; - sx_ThreadId = kMainThreadId; sm_MainThreadIdInitialized = true; } @@ -462,13 +492,33 @@ CThread* CThread::GetCurrentThread(void) CThread::TID CThread::GetSelf(void) { TID id = sx_ThreadId; - if ( !id && sm_MainThreadIdInitialized ) { - // Info has not been set - this is a native thread, - // main thread is already assigned so we can assign new thread an ID. - sx_ThreadId = id = sx_GetNextThreadId(); + if ( !id ) { + // If main thread has not been set, consider current thread is the main one. + // Since sx_ThreadId is still zero, InitializeMainThreadId() will set it to + // kMainThreadId, so that the value returned by GetSelf() will be zero. + if (!sm_MainThreadIdInitialized) { + InitializeMainThreadId(); + id = sx_ThreadId; + } + else { + sx_ThreadId = id = sx_GetNextThreadId(); + } + } + // kMainThreadId is usually marker for main thread, but when using native threads + // and InitializeMainThreadId() to set main thread, the main thread id may be + // different and it's more reliable to use IsMain() rather than GetSelf() == 0. + return id == kMainThreadId ? 0 : id; +} + + +bool CThread::IsMain(void) +{ + TID id = sx_ThreadId; + if (!sm_MainThreadIdInitialized) { + InitializeMainThreadId(); + id = sx_ThreadId; } - // kMainThreadId is marker for main thread - return id == kMainThreadId? 0: id; + return sx_ThreadId == sx_GetMainThreadId(); } @@ -485,7 +535,7 @@ TWrapperRes CThread::Wrapper(TWrapperArg arg) // Set Toolkit thread ID. thread_obj->x_InitializeThreadId(); - xncbi_Validate(GetSelf() != 0, + xncbi_Validate(!IsMain(), "CThread::Wrapper() -- error assigning thread ID"); #if defined NCBI_THREAD_PID_WORKAROUND diff --git a/c++/src/corelib/ncbitime.cpp b/c++/src/corelib/ncbitime.cpp index e378fd9e..2164bda6 100644 --- a/c++/src/corelib/ncbitime.cpp +++ b/c++/src/corelib/ncbitime.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbitime.cpp 500405 2016-05-04 15:18:35Z ivanov $ +/* $Id: ncbitime.cpp 528465 2017-02-23 14:10:51Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -158,21 +158,22 @@ const char kFormatEscapeSymbol = '$'; } else { return false; } \ } -#define CHECK_RANGE_YEAR(value) CHECK_RANGE_EXCEPTION(value, "Year", 1583, kMax_Int) -#define CHECK_RANGE_MONTH(value) CHECK_RANGE_EXCEPTION(value, "Month", 1, 12) -#define CHECK_RANGE_DAY(value) CHECK_RANGE_EXCEPTION(value, "Day", 1, 31) -#define CHECK_RANGE_HOUR(value) CHECK_RANGE_EXCEPTION(value, "Hour", 0, 23) -#define CHECK_RANGE_MIN(value) CHECK_RANGE_EXCEPTION(value, "Minute", 0, 59) -#define CHECK_RANGE_SEC(value) CHECK_RANGE_EXCEPTION(value, "Second", 0, 61) -#define CHECK_RANGE_NSEC(value) CHECK_RANGE_EXCEPTION(value, "Nanosecond", 0, kNanoSecondsPerSecond - 1) +#define CHECK_RANGE_YEAR(value) CHECK_RANGE_EXCEPTION(value, "Year", 1583, kMax_Int) +#define CHECK_RANGE_MONTH(value) CHECK_RANGE_EXCEPTION(value, "Month", 1, 12) +#define CHECK_RANGE_DAY(value) CHECK_RANGE_EXCEPTION(value, "Day", 1, 31) +#define CHECK_RANGE_HOUR(value) CHECK_RANGE_EXCEPTION(value, "Hour", 0, 23) +#define CHECK_RANGE_MIN(value) CHECK_RANGE_EXCEPTION(value, "Minute", 0, 59) +#define CHECK_RANGE_SEC(value) CHECK_RANGE_EXCEPTION(value, "Second", 0, 61) +#define CHECK_RANGE_NSEC(value) CHECK_RANGE_EXCEPTION(value, "Nanosecond", 0, kNanoSecondsPerSecond - 1) -#define CHECK_RANGE2_YEAR(value, err) CHECK_RANGE2(value, "Year", 1583, kMax_Int, err) -#define CHECK_RANGE2_MONTH(value, err) CHECK_RANGE2(value, "Month", 1, 12, err) -#define CHECK_RANGE2_DAY(value, err) CHECK_RANGE2(value, "Day", 1, 31, err) -#define CHECK_RANGE2_HOUR(value, err) CHECK_RANGE2(value, "Hour", 0, 23, err) -#define CHECK_RANGE2_MIN(value, err) CHECK_RANGE2(value, "Minute", 0, 59, err) -#define CHECK_RANGE2_SEC(value, err) CHECK_RANGE2(value, "Second", 0, 61, err) -#define CHECK_RANGE2_NSEC(value, err) CHECK_RANGE2(value, "Nanosecond", 0, kNanoSecondsPerSecond - 1, err) +#define CHECK_RANGE2_YEAR(value, err) CHECK_RANGE2(value, "Year", 1583, kMax_Int, err) +#define CHECK_RANGE2_MONTH(value, err) CHECK_RANGE2(value, "Month", 1, 12, err) +#define CHECK_RANGE2_DAY(value, err) CHECK_RANGE2(value, "Day", 1, 31, err) +#define CHECK_RANGE2_HOUR24(value, err) CHECK_RANGE2(value, "Hour", 0, 23, err) +#define CHECK_RANGE2_HOUR12(value, err) CHECK_RANGE2(value, "Hour", 0, 12, err) +#define CHECK_RANGE2_MIN(value, err) CHECK_RANGE2(value, "Minute", 0, 59, err) +#define CHECK_RANGE2_SEC(value, err) CHECK_RANGE2(value, "Second", 0, 61, err) +#define CHECK_RANGE2_NSEC(value, err) CHECK_RANGE2(value, "Nanosecond", 0, kNanoSecondsPerSecond - 1, err) // Bitfilds setters (to avoid warnings) @@ -776,12 +777,12 @@ bool CTime::x_Init(const string& str, const CTimeFormat& format, EErrAction err_ is_day_present = true; break; case 'h': - CHECK_RANGE2_HOUR(value, err_action); + CHECK_RANGE2_HOUR24(value, err_action); SET_HOUR(value); is_time_present = true; break; case 'H': - CHECK_RANGE2_HOUR(value, err_action); + CHECK_RANGE2_HOUR12(value, err_action); SET_HOUR(value % 12); is_12hour = true; is_time_present = true; diff --git a/c++/src/corelib/request_ctx.cpp b/c++/src/corelib/request_ctx.cpp index 5178b2f1..19374ba3 100644 --- a/c++/src/corelib/request_ctx.cpp +++ b/c++/src/corelib/request_ctx.cpp @@ -1,4 +1,4 @@ -/* $Id: request_ctx.cpp 508783 2016-08-01 16:05:01Z ivanov $ +/* $Id: request_ctx.cpp 508631 2016-07-29 15:53:51Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/corelib/request_status.cpp b/c++/src/corelib/request_status.cpp new file mode 100644 index 00000000..bf92f071 --- /dev/null +++ b/c++/src/corelib/request_status.cpp @@ -0,0 +1,97 @@ +/* $Id: request_status.cpp 522984 2016-12-27 17:38:25Z grichenk $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Aleksey Grichenko + * + * File Description: + * CRequestStatus implementation. + * + */ + +#include +#include + + +/** @addtogroup Utility + * + * @{ + */ + +BEGIN_NCBI_SCOPE + + +string CRequestStatus::GetStdStatusMessage(ECode code) +{ + switch ( code ) { + case e100_Continue: return "Continue"; + case e101_SwitchingProtocols: return "Switching Protocols"; + case e200_Ok: return "OK"; + case e201_Created: return "Created"; + case e202_Accepted: return "Accepted"; + case e203_NonAuthInformation: return "Non-Authoritative Information"; + case e204_NoContent: return "No Content"; + case e205_ResetContent: return "Reset Content"; + case e206_PartialContent: return "Partial Content"; + case e299_PartialContentBrokenConnection: return "Partial Content Broken Connection"; + case e300_MultipleChoices: return "Multiple Choices"; + case e301_MovedPermanently: return "Moved Permanently"; + case e302_Found: return "Found"; + case e303_SeeOther: return "See Other"; + case e304_NotModified: return "Not Modified"; + case e305_UseProxy: return "Use Proxy"; + case e307_TemporaryRedirect: return "Temporary Redirect"; + case e400_BadRequest: return "Bad Request"; + case e401_Unauthorized: return "Unauthorized"; + case e402_PaymentRequired: return "Payment Required"; + case e403_Forbidden: return "Forbidden"; + case e404_NotFound: return "Not Found"; + case e405_MethodNotAllowed: return "Method Not Allowed"; + case e406_NotAcceptable: return "Not Acceptable"; + case e407_ProxyAuthRequired: return "Proxy Authentication Required"; + case e408_RequestTimeout: return "Request Timeout"; + case e409_Conflict: return "Conflict"; + case e410_Gone: return "Gone"; + case e411_LengthRequired: return "Length Required"; + case e412_PreconditionFailed: return "Precondition Failed"; + case e413_RequestEntityTooLarge: return "Request Entity Too Large"; + case e414_RequestURITooLong: return "Request-URI Too Long"; + case e415_UnsupportedMediaType: return "Unsupported Media Type"; + case e416_RangeNotSatisfiable: return "Requested Range Not Satisfiable"; + case e417_ExpectationFailed: return "Expectation Failed"; + case e499_BrokenConnection: return "Broken Connection"; + case e500_InternalServerError: return "Internal Server Error"; + case e501_NotImplemented: return "Not Implemented"; + case e502_BadGateway: return "Bad Gateway"; + case e503_ServiceUnavailable: return "Service Unavailable"; + case e504_GatewayTimeout: return "Gateway Timeout"; + case e505_HTTPVerNotSupported: return "HTTP Version Not Supported"; + } + return "Unknown HTTP status code"; +} + + +/* @} */ + +END_NCBI_SCOPE diff --git a/c++/src/corelib/rwstreambuf.cpp b/c++/src/corelib/rwstreambuf.cpp index 281df591..7d412b20 100644 --- a/c++/src/corelib/rwstreambuf.cpp +++ b/c++/src/corelib/rwstreambuf.cpp @@ -1,4 +1,4 @@ -/* $Id: rwstreambuf.cpp 463752 2015-04-01 14:15:52Z lavr $ +/* $Id: rwstreambuf.cpp 530261 2017-03-13 17:05:56Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -169,7 +169,7 @@ CRWStreambuf::CRWStreambuf(IReader* r, } -ERW_Result CRWStreambuf::x_pushback(void) +ERW_Result CRWStreambuf::x_Pushback(void) { if ( !m_Reader ) { _ASSERT(!gptr() && !egptr()); @@ -193,12 +193,12 @@ CRWStreambuf::~CRWStreambuf() try { // Flush only if data pending and no error if (!x_Err || x_ErrPos != x_GetPPos()) - x_sync(); + x_Sync(); setp(0, 0); } NCBI_CATCH_ALL_X(2, "Exception in ~CRWStreambuf() [IGNORED]"); try { // Push any data still unred in the buffer back to the device - ERW_Result result = x_pushback(); + ERW_Result result = x_Pushback(); if (result != eRW_Success && result != eRW_NotImplemented) { ERR_POST_X(13, Critical << "CRWStreambuf::~CRWStreambuf():" @@ -215,9 +215,9 @@ CNcbiStreambuf* CRWStreambuf::setbuf(CT_CHAR_TYPE* s, streamsize m) if (!s && !m) return this; - if (x_pushback() != eRW_Success) + if (x_Pushback() != eRW_Success) ERR_POST_X(3,Critical << "CRWStreambuf::setbuf(): Read data pending"); - if (x_sync() != 0) + if (x_Sync() != 0) ERR_POST_X(4,Critical << "CRWStreambuf::setbuf(): Write data pending"); setp(0, 0); @@ -423,7 +423,7 @@ CT_INT_TYPE CRWStreambuf::underflow(void) return CT_EOF; // flush output buffer, if tied up to it - if (!(m_Flags & fUntie) && x_sync() != 0) + if (!(m_Flags & fUntie) && x_Sync() != 0) return CT_EOF; #ifdef NCBI_COMPILER_MIPSPRO @@ -450,13 +450,12 @@ CT_INT_TYPE CRWStreambuf::underflow(void) } -streamsize CRWStreambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m) +streamsize CRWStreambuf::x_Read(CT_CHAR_TYPE* buf, streamsize m) { - if ( !m_Reader ) - return 0; + _ASSERT(m_Reader); // flush output buffer, if tied up to it - if (!(m_Flags & fUntie) && x_sync() != 0) + if (!(m_Flags & fUntie) && x_Sync() != 0) return 0; if (m < 0) @@ -471,19 +470,21 @@ streamsize CRWStreambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m) n_read = (size_t)(egptr() - gptr()); if (n_read > n) n_read = n; - memcpy(buf, gptr(), n_read); + if (buf) + memcpy(buf, gptr(), n_read); gbump(int(n_read)); - n -= n_read; + n -= n_read; if ( !n ) return (streamsize) n_read; - buf += n_read; + if (buf) + buf += n_read; } else n_read = 0; do { // next, read directly from the device - size_t x_toread = n && n < m_BufSize ? m_BufSize : n; - CT_CHAR_TYPE* x_buf = n < m_BufSize ? m_ReadBuf : buf; + size_t x_toread = !buf || (n && n < m_BufSize) ? m_BufSize : n; + CT_CHAR_TYPE* x_buf = !buf || ( n < m_BufSize) ? m_ReadBuf : buf; ERW_Result result = eRW_Success; size_t x_read = 0; @@ -500,7 +501,8 @@ streamsize CRWStreambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m) size_t xx_read = x_read; if (x_read > n) x_read = n; - memcpy(buf, m_ReadBuf, x_read); + if (buf) + memcpy(buf, m_ReadBuf, x_read); setg(m_ReadBuf, m_ReadBuf + x_read, m_ReadBuf + xx_read); } else { _ASSERT(x_read <= n); @@ -508,17 +510,24 @@ streamsize CRWStreambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m) memcpy(m_ReadBuf, buf + x_read - xx_read, xx_read); setg(m_ReadBuf, m_ReadBuf + xx_read, m_ReadBuf + xx_read); } - n_read += x_read; + n_read += x_read; if (result != eRW_Success) break; - buf += x_read; - n -= x_read; + if (buf) + buf += x_read; + n -= x_read; } while ( n ); return (streamsize) n_read; } +streamsize CRWStreambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m) +{ + return m_Reader ? x_Read(buf, m) : 0; +} + + streamsize CRWStreambuf::showmanyc(void) { _ASSERT(gptr() >= egptr()); @@ -528,7 +537,7 @@ streamsize CRWStreambuf::showmanyc(void) // flush output buffer, if tied up to it if (!(m_Flags & fUntie)) - x_sync(); + x_Sync(); size_t count = 0; ERW_Result result; @@ -560,15 +569,21 @@ int CRWStreambuf::sync(void) CT_POS_TYPE CRWStreambuf::seekoff(CT_OFF_TYPE off, IOS_BASE::seekdir whence, IOS_BASE::openmode which) { - if (off == 0 && whence == IOS_BASE::cur) { + if (whence == IOS_BASE::cur && off == 0) { + // tellg()/tellp() support switch (which) { - case IOS_BASE::out: - return x_GetPPos(); case IOS_BASE::in: return x_GetGPos(); + case IOS_BASE::out: + return x_GetPPos(); default: break; } + } else if (which == IOS_BASE::in + && ((whence == IOS_BASE::cur && (off > 0)) || + (whence == IOS_BASE::beg && (off -= x_GetGPos()) >= 0))){ + if (m_Reader && x_Read(0, (streamsize) off) == (streamsize) off) + return x_GetGPos(); } return (CT_POS_TYPE)((CT_OFF_TYPE)(-1L)); } diff --git a/c++/src/corelib/stream_utils.cpp b/c++/src/corelib/stream_utils.cpp index 4fa623ff..53b0f6bd 100644 --- a/c++/src/corelib/stream_utils.cpp +++ b/c++/src/corelib/stream_utils.cpp @@ -1,4 +1,4 @@ -/* $Id: stream_utils.cpp 504923 2016-06-20 20:21:48Z lavr $ +/* $Id: stream_utils.cpp 524096 2017-01-09 19:28:12Z lavr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -176,8 +176,8 @@ CT_POS_TYPE CPushback_Streambuf::seekoff(CT_OFF_TYPE off, IOS_BASE::openmode which) { if (whence == IOS_BASE::cur && (which & IOS_BASE::in)) { - if (off == 0 && which == IOS_BASE::in) { - // it's a call from tellg() + if (which == IOS_BASE::in && off == 0) { + // support call from tellg() CT_POS_TYPE ret = m_Sb->PUBSEEKOFF(0, IOS_BASE::cur, IOS_BASE::in); if (ret != (CT_POS_TYPE)((CT_OFF_TYPE)(-1L))) { off = (CT_OFF_TYPE)(egptr() - gptr()); diff --git a/c++/src/corelib/syslog.cpp b/c++/src/corelib/syslog.cpp index afc07fc8..06d39ec6 100644 --- a/c++/src/corelib/syslog.cpp +++ b/c++/src/corelib/syslog.cpp @@ -1,4 +1,4 @@ -/* $Id: syslog.cpp 460070 2015-02-24 19:18:49Z ucko $ +/* $Id: syslog.cpp 534306 2017-04-26 14:16:05Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -249,7 +249,7 @@ void CSysLog::x_Connect(void) #endif } -void CSysLog::HonorRegistrySettings(IRegistry* reg) +void CSysLog::HonorRegistrySettings(const IRegistry* reg) { if (reg == NULL && CNcbiApplication::Instance()) { reg = &CNcbiApplication::Instance()->GetConfig(); diff --git a/c++/src/corelib/teamcity_boost.cpp b/c++/src/corelib/teamcity_boost.cpp index 0578c0d3..487aafda 100644 --- a/c++/src/corelib/teamcity_boost.cpp +++ b/c++/src/corelib/teamcity_boost.cpp @@ -12,7 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * $Id: teamcity_boost.cpp 500448 2016-05-04 18:16:16Z ucko $ + * $Id: teamcity_boost.cpp 534856 2017-05-03 11:23:39Z ivanov $ */ #include @@ -34,7 +34,7 @@ #define CURRENT_TEST_NAME boost::unit_test_framework::framework::current_test_case().p_name #endif -#include "teamcity_messages.h" +#include namespace jetbrains { namespace teamcity { const std::string ASSERT_CTX = "Assertion occurred in a following context:"; diff --git a/c++/src/corelib/teamcity_messages.cpp b/c++/src/corelib/teamcity_messages.cpp index 85977ec3..c06d82d2 100644 --- a/c++/src/corelib/teamcity_messages.cpp +++ b/c++/src/corelib/teamcity_messages.cpp @@ -12,12 +12,12 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * $Id: teamcity_messages.cpp 500881 2016-05-09 17:50:16Z ucko $ + * $Id: teamcity_messages.cpp 534856 2017-05-03 11:23:39Z ivanov $ */ #include -#include "teamcity_messages.h" +#include #include #include diff --git a/c++/src/corelib/test_boost.cpp b/c++/src/corelib/test_boost.cpp index 6e8914b2..5560878b 100644 --- a/c++/src/corelib/test_boost.cpp +++ b/c++/src/corelib/test_boost.cpp @@ -1,4 +1,4 @@ -/* $Id: test_boost.cpp 520770 2016-12-01 15:44:45Z ivanov $ +/* $Id: test_boost.cpp 534439 2017-04-27 11:53:27Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -521,6 +521,10 @@ public: /// Check if there were any timeouted tests bool HasTestTimeouts(void); + /// Get the application's cached configuration parameters, accessible to read-write. + /// @sa GetConfig, GetRWConfig + CNcbiRegistry& GetTestRWConfig(void); + private: typedef list TUserFuncsList; @@ -1363,6 +1367,7 @@ CNcbiTestApplication::SetGloballyDisabled(void) // nothing else. printf("All tests are disabled in current configuration.\n" " (for autobuild scripts: NCBI_UNITTEST_DISABLED)\n"); + x_AddDummyTest(); } void @@ -1812,10 +1817,11 @@ CNcbiTestApplication::InitTestFramework(int argc, char* argv[]) // Call should be doubled to support manual adding of // test cases inside NCBITEST_INIT_TREE(). x_CollectAllTests(); -#if BOOST_VERSION < 105900 +#if BOOST_VERSION <= 105900 + // As of Boost.Test 3.0 (Boost 1.59.0), this check is prone + // to false positives. if (x_GetEnabledTestsCount() == 0) { SetGloballyDisabled(); - x_AddDummyTest(); } #endif #ifdef NCBI_COMPILER_WORKSHOP @@ -1849,6 +1855,12 @@ CNcbiTestApplication::HasTestTimeouts(void) return m_HasTestTimeouts; } +inline CNcbiRegistry& +CNcbiTestApplication::GetTestRWConfig(void) +{ + return GetRWConfig(); +} + void CNcbiTestsCollector::visit(but::test_case const& test) { @@ -2155,6 +2167,16 @@ NcbiTestSetGlobalSkipped(void) s_GetTestApp().SetGloballySkipped(); } +CNcbiApplication* NcbiTestGetAppInstance(void) +{ + return &s_GetTestApp(); +} + +CNcbiRegistry& NcbiTestGetRWConfig(void) +{ + return s_GetTestApp().GetTestRWConfig(); +} + CExprParser* NcbiTestGetIniParser(void) { diff --git a/c++/src/corelib/test_mt.cpp b/c++/src/corelib/test_mt.cpp index 1e1d2e26..6b7aa44e 100644 --- a/c++/src/corelib/test_mt.cpp +++ b/c++/src/corelib/test_mt.cpp @@ -1,4 +1,4 @@ -/* $Id: test_mt.cpp 488254 2015-12-29 13:56:26Z ivanov $ +/* $Id: test_mt.cpp 534857 2017-05-03 12:26:07Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -440,7 +440,7 @@ CThreadedApp::~CThreadedApp(void) void CThreadedApp::Init(void) { // Prepare command line descriptions - auto_ptr arg_desc(new CArgDescriptions); + unique_ptr arg_desc(new CArgDescriptions); // s_NumThreads arg_desc->AddDefaultKey diff --git a/c++/src/corelib/version.cpp b/c++/src/corelib/version.cpp index 2cdc97ef..0e7d6e09 100644 --- a/c++/src/corelib/version.cpp +++ b/c++/src/corelib/version.cpp @@ -1,4 +1,4 @@ -/* $Id: version.cpp 508166 2016-07-26 15:59:33Z elisovdn $ +/* $Id: version.cpp 523569 2017-01-04 19:13:48Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -190,6 +190,47 @@ string CVersionInfo::Print(void) const } +string CVersionInfo::PrintXml(void) const +{ + CNcbiOstrstream os; + os << "= 0) { + os << " major=\"" << m_Major << + "\" minor=\"" << (m_Minor >= 0 ? m_Minor : 0) << "\""; + if (m_PatchLevel >= 0) { + os << " patch_level=\"" << m_PatchLevel << "\""; + } + } + if ( !m_Name.empty() ) { + os << " name=\"" << NStr::XmlEncode(m_Name) << "\""; + } + os << "/>\n"; + return CNcbiOstrstreamToString(os); +} + + +string CVersionInfo::PrintJson(void) const +{ + CNcbiOstrstream os; + os << "{"; + bool need_separator = false; + if (m_Major >= 0) { + os << "\"major\": \"" << m_Major << + "\", \"minor\": \"" << (m_Minor >= 0 ? m_Minor : 0) << "\""; + if (m_PatchLevel >= 0) { + os << ", \"patch_level\": \"" << m_PatchLevel << "\""; + } + need_separator = true; + } + if ( !m_Name.empty() ) { + if ( need_separator ) os << ", "; + os << "\"name\": \"" << NStr::JsonEncode(m_Name) << "\""; + } + os << "}"; + return CNcbiOstrstreamToString(os); +} + + CVersionInfo::EMatch CVersionInfo::Match(const CVersionInfo& version_info) const { @@ -450,6 +491,24 @@ string CComponentVersionInfo::Print(void) const return CNcbiOstrstreamToString(os); } +string CComponentVersionInfo::PrintXml(void) const +{ + CNcbiOstrstream os; + os << "\n" << + CVersionInfo::PrintXml() << + "\n"; + return CNcbiOstrstreamToString(os); +} + +string CComponentVersionInfo::PrintJson(void) const +{ + CNcbiOstrstream os; + os << "{ \"name\": \"" << + NStr::JsonEncode(GetComponentName()) << + "\", \"version_info\": " << CVersionInfo::PrintJson() << "}"; + return CNcbiOstrstreamToString(os); +} + ///////////////////////////////////////////////////////////////////////////// // SBuildInfo @@ -461,6 +520,40 @@ SBuildInfo::SBuildInfo() { } + +string SBuildInfo::PrintXml(void) const +{ + CNcbiOstrstream os; + os << "\n"; + return CNcbiOstrstreamToString(os); +} + + +string SBuildInfo::PrintJson(void) const +{ + CNcbiOstrstream os; + bool need_separator = false; + os << "{"; + if ( !date.empty() ) { + os << "\"date\": \"" << NStr::JsonEncode(date) << "\""; + need_separator = true; + } + if ( !tag.empty() ) { + if ( need_separator ) os << ", "; + os << "\"tag\": \"" << NStr::JsonEncode(tag) << "\""; + } + os << "}"; + return CNcbiOstrstreamToString(os); +} + + ///////////////////////////////////////////////////////////////////////////// // CVersion @@ -607,4 +700,131 @@ string CVersion::Print(const string& appname, TPrintFlags flags) const } +string CVersion::PrintXml(const string& appname, TPrintFlags flags) const +{ + CNcbiOstrstream os; + + os << "\n" + "\n"; + + if (flags & fVersionInfo) { + if ( !appname.empty() ) { + os << "" << NStr::XmlEncode(appname) << "\n"; + } + os << m_VersionInfo->PrintXml(); + } + + if (flags & fComponents) { + ITERATE(vector< AutoPtr< CComponentVersionInfo> >, c, m_Components) { + os << (*c)->PrintXml(); + } + } + +#if NCBI_PACKAGE + if (flags & ( fPackageShort | fPackageFull )) { + os << "\n" << + GetPackageVersion().PrintXml() << + SBuildInfo().PrintXml(); + if (flags & fPackageFull) { + os << "" << NStr::XmlEncode(GetPackageConfig()) << "\n"; + } + os << "\n"; + } +#endif + +#ifdef NCBI_SIGNATURE + if (flags & fBuildSignature) { + os << "" << NStr::XmlEncode(NCBI_SIGNATURE) << "\n"; + } +#endif + + if (flags & fBuildInfo) { + os << m_BuildInfo.PrintXml(); + } + +#ifdef NCBI_TEAMCITY_BUILD_NUMBER + if (flags & fTCBuildNumber) { + os << "" << NStr::XmlEncode(NStr::NumericToString(NCBI_TEAMCITY_BUILD_NUMBER)) << + "\n"; + } +#endif /* NCBI_TEAMCITY_BUILD_NUMBER */ + + os << "\n"; + + return CNcbiOstrstreamToString(os); +} + + +string CVersion::PrintJson(const string& appname, TPrintFlags flags) const +{ + CNcbiOstrstream os; + bool need_separator = false; + + os << "{\n \"ncbi_version\": {\n"; + + if (flags & fVersionInfo) { + if ( !appname.empty() ) { + os << " \"appname\": \"" << NStr::JsonEncode(appname) << "\",\n"; + } + os << " \"version_info\": " << m_VersionInfo->PrintJson(); + need_separator = true; + } + + if (flags & fComponents) { + if ( need_separator ) os << ",\n"; + os << " \"components\": ["; + need_separator = false; + ITERATE(vector< AutoPtr< CComponentVersionInfo> >, c, m_Components) { + if ( need_separator ) os << ","; + os << "\n " << (*c)->PrintJson(); + need_separator = true; + } + os << "]"; + need_separator = true; + } + +#if NCBI_PACKAGE + if (flags & ( fPackageShort | fPackageFull )) { + if ( need_separator ) os << ",\n"; + os << " \"package\": {\n" << + " \"name\": \"" << NStr::JsonEncode(GetPackageName()) << "\",\n" << + " \"version_info\": " << GetPackageVersion().PrintJson() << ",\n" << + " \"build_info\": " << SBuildInfo().PrintJson(); + if (flags & fPackageFull) { + os << ",\n \"config\": \"" << NStr::JsonEncode(GetPackageConfig()) << "\""; + } + os << "}"; + need_separator = true; + } +#endif + +#ifdef NCBI_SIGNATURE + if (flags & fBuildSignature) { + if ( need_separator ) os << ",\n"; + os << " \"build_signature\": \"" << NStr::JsonEncode(NCBI_SIGNATURE) << "\""; + need_separator = true; + } +#endif + + if (flags & fBuildInfo) { + if ( need_separator ) os << ",\n"; + os << " \"build_info\": " << m_BuildInfo.PrintJson(); + need_separator = true; + } + +#ifdef NCBI_TEAMCITY_BUILD_NUMBER + if (flags & fTCBuildNumber) { + if ( need_separator ) os << ",\n"; + os << " \"teamcity_build_number\": \"" << + NStr::JsonEncode(NStr::NumericToString(NCBI_TEAMCITY_BUILD_NUMBER)) << "\""; + } +#endif /* NCBI_TEAMCITY_BUILD_NUMBER */ + + os << "\n }\n}\n"; + return CNcbiOstrstreamToString(os); +} + + END_NCBI_SCOPE diff --git a/c++/src/db/CMakeLists.txt b/c++/src/db/CMakeLists.txt new file mode 100644 index 00000000..217b48b5 --- /dev/null +++ b/c++/src/db/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory + +# Recurse subdirectories +add_subdirectory(sqlite) +add_subdirectory(bdb) diff --git a/c++/src/db/Makefile.in b/c++/src/db/Makefile.in new file mode 100644 index 00000000..e4fab252 --- /dev/null +++ b/c++/src/db/Makefile.in @@ -0,0 +1,13 @@ +################################# +# $Id: Makefile.in 163327 2009-06-15 15:40:12Z ivanovp $ +# Author: Pavel Ivanov (ivanovp@ncbi.nlm.nih.gov) +################################# + +# Meta-makefile for db code +################################# + +SUB_PROJ = sqlite bdb + + +srcdir = @srcdir@ +include @builddir@/Makefile.meta diff --git a/c++/src/db/sqlite/CMakeLists.sqlitewrapp.lib.txt b/c++/src/db/sqlite/CMakeLists.sqlitewrapp.lib.txt new file mode 100644 index 00000000..ff897d14 --- /dev/null +++ b/c++/src/db/sqlite/CMakeLists.sqlitewrapp.lib.txt @@ -0,0 +1,11 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/db/sqlite/Makefile.sqlitewrapp.lib +# +add_library(sqlitewrapp + sqlitewrapp +) +include_directories(SYSTEM ${SQLITE3_INCLUDE}) + +target_link_libraries(sqlitewrapp + xncbi ${SQLITE3_LIBS} +) diff --git a/c++/src/db/sqlite/CMakeLists.txt b/c++/src/db/sqlite/CMakeLists.txt new file mode 100644 index 00000000..f8bda729 --- /dev/null +++ b/c++/src/db/sqlite/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.sqlitewrapp.lib.txt) + diff --git a/c++/src/db/sqlite/Makefile.in b/c++/src/db/sqlite/Makefile.in new file mode 100644 index 00000000..f73d184a --- /dev/null +++ b/c++/src/db/sqlite/Makefile.in @@ -0,0 +1,9 @@ +# $Id: Makefile.in 163036 2009-06-11 16:16:17Z ivanovp $ + +# Meta-makefile ("XMLWrapp" project) +################################# + +LIB_PROJ = sqlitewrapp + +srcdir = @srcdir@ +include @builddir@/Makefile.meta diff --git a/c++/src/db/sqlite/Makefile.sqlitewrapp.lib b/c++/src/db/sqlite/Makefile.sqlitewrapp.lib new file mode 100644 index 00000000..2581b102 --- /dev/null +++ b/c++/src/db/sqlite/Makefile.sqlitewrapp.lib @@ -0,0 +1,15 @@ +# $Id: Makefile.sqlitewrapp.lib 468535 2015-05-26 13:23:32Z ucko $ + +SRC = sqlitewrapp +LIB = sqlitewrapp + +CPPFLAGS= $(ORIG_CPPFLAGS) $(SQLITE3_INCLUDE) +LIBS = $(SQLITE3_LIBS) $(ORIG_LIBS) + +REQUIRES = SQLITE3 + +WATCHERS = vakatov + + +USES_LIBRARIES = \ + $(SQLITE3_LIBS) xncbi diff --git a/c++/src/db/sqlite/sqlitewrapp.cpp b/c++/src/db/sqlite/sqlitewrapp.cpp new file mode 100644 index 00000000..a2ced3a0 --- /dev/null +++ b/c++/src/db/sqlite/sqlitewrapp.cpp @@ -0,0 +1,1049 @@ +/* $Id: sqlitewrapp.cpp 535286 2017-05-08 13:31:07Z ivanov $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Pavel Ivanov + * + * File Description: + * C++ wrapper for working with SQLite 3.6.14 or higher. + */ + +#include + +#include +#include +#include + +#include + +#include + + +BEGIN_NCBI_SCOPE + + +#define NCBI_USE_ERRCODE_X Db_Sqlite + + +/// Default size of database pages (maximum allowed in SQLite) +const int kSQLITE_DefPageSize = 32768; + + + +#define SQLITE_ERRMSG_STRM(handle, msg) \ + msg << ": [" << sqlite3_errcode(handle) << "] " << sqlite3_errmsg(handle) + +/// Convenient macro for throwing CSQLITE_Exception containing error message +/// from SQLite. +/// +/// @param type +/// Enum value from CSQLITE_Exception +/// @param handle +/// Connection handle where error happened +/// @param msg +/// Additional explanation of the error +#define SQLITE_THROW(type, handle, msg) \ + do { \ + CNcbiOstrstream ostr; \ + ostr << SQLITE_ERRMSG_STRM(handle, msg); \ + throw CSQLITE_Exception(DIAG_COMPILE_INFO, NULL, type, \ + CNcbiOstrstreamToString(ostr)); \ + } while (0) + +/// Same as SQLITE_THROW but for logging errors in places where throwing +/// exceptions is impossible. +/// +/// @param err_subcode +/// Error subcode for err_posting +/// @param handle +/// Connection handle where error happened +/// @param msg +/// Additional explanation of the error +#define SQLITE_LOG_ERROR(err_subcode, handle, msg) \ + ERR_POST_X(err_subcode, \ + SQLITE_ERRMSG_STRM(handle, msg)) + + +#ifdef HAVE_SQLITE3ASYNC_H + +/// Background thread for executing all asynchronous writes to database +/// if they exist. +class CSQLITE_AsyncWritesThread : public CThread +{ +protected: + virtual void* Main(void) + { + sqlite3async_run(); + return NULL; + } +}; + +#endif // HAVE_SQLITE3ASYNC_H + +#ifdef HAVE_SQLITE3_UNLOCK_NOTIFY + +/// Class helping make smart waits when database is locked by another thread +class CLockWaiter +{ +public: + CLockWaiter(void) : m_WaitSem(new CSemaphore(0, 1)) + {} + /// Wait for the database to unlock + void Wait(void) + { + m_WaitSem->Wait(); + } + /// Signal the thread that waits inside Wait() method that database was + /// unlocked + void SignalUnlock(void) + { + m_WaitSem->Post(); + } + +private: + /// Semaphore to wait on. Made auto-pointer to allow this object to be + /// used in stl containers. + AutoPtr m_WaitSem; +}; + + +/// Callback that will be called from sqlite3 when database is unlocked +static void +s_OnUnlockNotify(void** p_waiters, int n_waiters) +{ + for (int i = 0; i < n_waiters; ++i) { + CLockWaiter* waiter = reinterpret_cast(p_waiters[i]); + waiter->SignalUnlock(); + } +} + + +/// Set of all waiting helpers assigned to different sqlite3 connections. +/// This is needed to avoid construction/destruction of semaphores on each +/// wait for database to unlock. +static map s_LockWaiters; +/// Mutex for working with s_LockWaiters +DEFINE_STATIC_FAST_MUTEX(s_LockWaitersMutex); + +#endif // HAVE_SQLITE3_UNLOCK_NOTIFY + + +/// Unified handling of return codes from sqlite. Throw exception if +/// return code indicates some error, return SQLITE_BUSY if last operation +/// should be retried and return sqlite3_code itself if it is normal and +/// does not indicate any error. +static int +s_ProcessErrorCode(sqlite3* handle, + int sqlite3_code, + CSQLITE_Exception::EErrCode ex_code) +{ + switch (sqlite3_code) { + case SQLITE_OK: + case SQLITE_DONE: + case SQLITE_ROW: + break; + case SQLITE_BUSY: + SleepMilliSec(1); + break; +#ifdef HAVE_SQLITE3_UNLOCK_NOTIFY + case SQLITE_LOCKED: + case SQLITE_LOCKED_SHAREDCACHE: + CLockWaiter* waiter; + int ret; + {{ + CFastMutexGuard guard(s_LockWaitersMutex); + waiter = &s_LockWaiters[handle]; + }} + ret = sqlite3_unlock_notify(handle, &s_OnUnlockNotify, waiter); + if (ret == SQLITE_LOCKED) { + SQLITE_THROW(CSQLITE_Exception::eDeadLock, handle, + "Database is deadlocked"); + } + else { + waiter->Wait(); + } + sqlite3_code = SQLITE_BUSY; + break; +#endif // HAVE_SQLITE3_UNLOCK_NOTIFY + case SQLITE_CONSTRAINT: + SQLITE_THROW(CSQLITE_Exception::eConstraint, handle, + "Constraint violation in statement"); + default: + SQLITE_THROW(ex_code, handle, "Error from sqlite3"); + } + + return sqlite3_code; +} + + +/// Make call to sqlite3 function with automatic retry mechanism. +/// Result from call will be in sql_ret variable after macro. +/// +/// @param call +/// Function along with its parameters to call +/// @param conn_handle +/// SQLite connection handle that will be used in call +/// @param ex_type +/// Enum value from CSQLITE_Exception which will be thrown in case of +/// an error +/// @param err_msg +/// Error explanation to throw in case of an error +/// @param retry +/// Additional function call to make between retries +#define SQLITE_SAFE_CALL_EX(call, conn_handle, ex_type, err_msg, retry) \ + int sql_ret = SQLITE_ERROR; \ + do { \ + try { \ + sql_ret = call; \ + sql_ret = s_ProcessErrorCode(conn_handle, sql_ret, \ + CSQLITE_Exception::ex_type); \ + if (sql_ret == SQLITE_BUSY) { \ + retry; \ + } \ + } \ + catch (CSQLITE_Exception& ex) { \ + CNcbiOstrstream ostr; \ + ostr << err_msg; \ + NCBI_RETHROW_SAME(ex, CNcbiOstrstreamToString(ostr)); \ + } \ + } \ + while (sql_ret == SQLITE_BUSY) + +/// The same as SQLITE_SAFE_CALL_EX but without additional calls between +/// retries. +#define SQLITE_SAFE_CALL(sqlite_call, conn_handle, ex_type, err_msg) \ + SQLITE_SAFE_CALL_EX((sqlite_call), conn_handle, ex_type, err_msg, \ + (void)0) + + + +const char* +CSQLITE_Exception::GetErrCodeString(void) const +{ + switch (GetErrCode()) + { + case eUnknown: return "eUnknown"; + case eDBOpen: return "eDBOpen"; + case eStmtPrepare: return "eStmtPrepare"; + case eStmtFinalize: return "eStmtFinalize"; + case eStmtBind: return "eStmtBind"; + case eStmtStep: return "eStmtStep"; + case eStmtReset: return "eStmtReset"; + case eBlobOpen: return "eBlobOpen"; + case eBlobClose: return "eBlobClose"; + case eBlobRead: return "eBlobRead"; + case eBlobWrite: return "eBlobWrite"; + default: return CException::GetErrCodeString(); + } +} + + +#ifdef HAVE_SQLITE3ASYNC_H + +/// Background thread for executing all asynchronous writings to databases +static CSafeStatic< CRef > s_AsyncWritesThread; +DEFINE_STATIC_FAST_MUTEX(s_AsyncThreadInitMutex); + +void +CSQLITE_Global::RunAsyncWritesThread(void) +{ + if ( s_AsyncWritesThread->IsNull() ) { + CFastMutexGuard lock(s_AsyncThreadInitMutex); + if ( s_AsyncWritesThread->IsNull() ) { + *s_AsyncWritesThread = new CSQLITE_AsyncWritesThread(); + (*s_AsyncWritesThread)->Run(); + } + } +} + +void +CSQLITE_Global::SetAsyncWritesFileLocking(bool lock_files) +{ + if (sqlite3async_control(SQLITEASYNC_LOCKFILES, int(lock_files)) + != SQLITE_OK) + { + ERR_POST_X(7, "File locking for asynchronous writing mode is not set " + "because of an error"); + } +} + +#endif // HAVE_SQLITE3ASYNC_H + +void +CSQLITE_Global::Finalize(void) +{ +#ifdef HAVE_SQLITE3ASYNC_H + _VERIFY(sqlite3async_control(SQLITEASYNC_HALT, SQLITEASYNC_HALT_IDLE) + == SQLITE_OK); + if ( s_AsyncWritesThread->NotNull() ) { + CFastMutexGuard lock(s_AsyncThreadInitMutex); + if ( s_AsyncWritesThread->NotNull() ) { + (*s_AsyncWritesThread)->Join(); + s_AsyncWritesThread->Reset(); + } + } + sqlite3async_shutdown(); +#endif + + _VERIFY(sqlite3_shutdown() == SQLITE_OK); +} + +void +CSQLITE_Global::Initialize(void) +{ + _VERIFY(sqlite3_config(SQLITE_CONFIG_MEMSTATUS, 0) == SQLITE_OK); + _VERIFY(sqlite3_initialize() == SQLITE_OK); +#ifdef HAVE_SQLITE3ASYNC_H + _VERIFY(sqlite3async_initialize(NULL, 0) == SQLITE_OK); + _VERIFY(sqlite3async_control(SQLITEASYNC_HALT, SQLITEASYNC_HALT_NEVER) + == SQLITE_OK); +#endif +} + +void +CSQLITE_Global::EnableSharedCache(bool enable /* = true */) +{ +#if defined(NCBI_THREADS) && !defined(HAVE_SQLITE3_UNLOCK_NOTIFY) + if (enable) { + NCBI_THROW(CSQLITE_Exception, eBadCall, + "Cannot turn on shared cache because of lack of capabilities"); + } +#else + if (sqlite3_enable_shared_cache(enable) != SQLITE_OK) { + ERR_POST_X(9, "Setting for sharing cache is not set because of an error"); + } +#endif +} + +void +CSQLITE_Global::SetCustomPageCache(sqlite3_pcache_methods* methods) +{ + int res = sqlite3_config(SQLITE_CONFIG_PCACHE, methods); + if (res != SQLITE_OK) { + NCBI_THROW_FMT(CSQLITE_Exception, eBadCall, + "Custom page cache is not set, err_code = " << res); + } +} + +void +CSQLITE_Global::SetCustomMallocFuncs(sqlite3_mem_methods* methods) +{ + int res = sqlite3_config(SQLITE_CONFIG_MALLOC, methods); + if (res != SQLITE_OK) { + NCBI_THROW_FMT(CSQLITE_Exception, eBadCall, + "Custom malloc functions are not set, err_code = " << res); + } +} + +sqlite3_vfs* +CSQLITE_Global::GetDefaultVFS(void) +{ + return sqlite3_vfs_find(NULL); +} + +void +CSQLITE_Global::RegisterCustomVFS(sqlite3_vfs* vfs, bool set_default /*= true*/) +{ + int res = sqlite3_vfs_register(vfs, set_default); + if (res != SQLITE_OK) { + NCBI_THROW_FMT(CSQLITE_Exception, eBadCall, + "Custom VFS is not registered, err_code = " << res); + } +} + + + +CSQLITE_HandleFactory::CSQLITE_HandleFactory(CSQLITE_Connection* conn) + : m_Conn(conn) +{} + +sqlite3* +CSQLITE_HandleFactory::CreateObject(void) +{ + sqlite3* result = NULL; + const char* vfs = NULL; +#ifdef HAVE_SQLITE3ASYNC_H + if ((m_Conn->GetFlags() & CSQLITE_Connection::eAllWrites) + == CSQLITE_Connection::fWritesAsync) + { + vfs = SQLITEASYNC_VFSNAME; + } +#endif + try { + int flags = (m_Conn->GetFlags() & CSQLITE_Connection::fReadOnly) + ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE; + SQLITE_SAFE_CALL((sqlite3_open_v2(m_Conn->GetFileName().c_str(), + &result, + flags | SQLITE_OPEN_NOMUTEX, + vfs)), + result, eDBOpen, + "Error opening database '" + << m_Conn->GetFileName() << "'" + ); + _ASSERT(sql_ret == SQLITE_OK); + m_Conn->SetupNewConnection(result); + return result; + } + catch (CException&) { + if (result) + sqlite3_close(result); + throw; + } +} + +void +CSQLITE_HandleFactory::DeleteObject(sqlite3* handle) +{ + int ret = sqlite3_close(handle); + if (ret != SQLITE_OK) { + SQLITE_LOG_ERROR(4, handle, + "Cannot close connection"); + + while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED +#ifdef HAVE_SQLITE3_UNLOCK_NOTIFY + || ret == SQLITE_LOCKED_SHAREDCACHE +#endif + ) + { + sqlite3_stmt *stmt; + while( (stmt = sqlite3_next_stmt(handle, 0)) != NULL ) { + ret = sqlite3_finalize(stmt); + if (ret != SQLITE_OK) { + SQLITE_LOG_ERROR(1, handle, + "Cannot finalize statement"); + } + } + + ret = sqlite3_close(handle); + if (ret != SQLITE_OK) { + SQLITE_LOG_ERROR(5, handle, + "Failed retry closing connection"); + } + } + } + + if (ret != SQLITE_OK) { + SQLITE_LOG_ERROR(2, handle, + "Error closing database connection, " + "leaving it open"); + } +} + + + +void +CSQLITE_Connection::x_CheckFlagsValidity(TOperationFlags flags, + EOperationFlags mask) +{ + TOperationFlags fls = flags & mask; + if (fls & (fls - 1)) { + NCBI_THROW(CSQLITE_Exception, eWrongFlags, + "Incorrect flags in CSQLITE_Connection: 0x" + + NStr::IntToString(flags, 0, 16)); + } +} + +inline void +CSQLITE_Connection::x_ExecuteSql(sqlite3* handle, CTempString sql) +{ + CSQLITE_Statement stmt(handle, sql); + stmt.Execute(); +} + +CSQLITE_Connection::CSQLITE_Connection(CTempString file_name, + TOperationFlags flags/*=eDefaultFlags*/) + : m_FileName(file_name), + m_Flags(flags), + m_PageSize(kSQLITE_DefPageSize), + m_CacheSize(0), + m_HandlePool(CSQLITE_HandleFactory(this)), + m_InMemory(0) +{ + x_CheckFlagsValidity(flags, eAllMT); + x_CheckFlagsValidity(flags, eAllVacuum); + x_CheckFlagsValidity(flags, eAllJournal); + x_CheckFlagsValidity(flags, eAllSync); + x_CheckFlagsValidity(flags, eAllTemp); + x_CheckFlagsValidity(flags, eAllWrites); +} + + +CSQLITE_Connection::~CSQLITE_Connection(void) +{ + if ( m_InMemory ) { + m_HandlePool.Return(m_InMemory); + } +} + + +void +CSQLITE_Connection::SetupNewConnection(sqlite3* handle) +{ + sqlite3_extended_result_codes(handle, 1); + + if (m_Flags & fReadOnly) { + // The database is read-only, disable VACUUM pragma. + m_Flags &= ~eAllVacuum; + m_Flags |= fVacuumOff; + } + + x_ExecuteSql(handle, "PRAGMA read_uncommitted = 1"); + x_ExecuteSql(handle, "PRAGMA count_changes = 0"); + x_ExecuteSql(handle, "PRAGMA legacy_file_format = OFF"); + x_ExecuteSql(handle, "PRAGMA page_size = " + + NStr::IntToString(m_PageSize)); + x_ExecuteSql(handle, "PRAGMA cache_size = " + + NStr::IntToString(m_CacheSize)); + + switch (m_Flags & eAllTemp) { + case fTempToMemory: + x_ExecuteSql(handle, "PRAGMA temp_store = MEMORY"); + break; + case fTempToFile: + x_ExecuteSql(handle, "PRAGMA temp_store = FILE"); + break; + default: + // Evidently this will throw an exception + x_CheckFlagsValidity(m_Flags, eAllTemp); + } + switch (m_Flags & eAllJournal) { + case fJournalOff: + x_ExecuteSql(handle, "PRAGMA journal_mode = OFF"); + break; + case fJournalMemory: + x_ExecuteSql(handle, "PRAGMA journal_mode = MEMORY"); + break; + case fJournalPersist: + x_ExecuteSql(handle, "PRAGMA journal_mode = PERSIST"); + break; + case fJournalTruncate: + x_ExecuteSql(handle, "PRAGMA journal_mode = TRUNCATE"); + break; + case fJournalDelete: + x_ExecuteSql(handle, "PRAGMA journal_mode = DELETE"); + break; + default: + // Evidently this will throw an exception + x_CheckFlagsValidity(m_Flags, eAllJournal); + } + switch (m_Flags & eAllSync) { + case fSyncOff: + x_ExecuteSql(handle, "PRAGMA synchronous = OFF"); + break; + case fSyncOn: + x_ExecuteSql(handle, "PRAGMA synchronous = NORMAL"); + break; + case fSyncFull: + x_ExecuteSql(handle, "PRAGMA synchronous = FULL"); + break; + default: + // Evidently this will throw an exception + x_CheckFlagsValidity(m_Flags, eAllSync); + } + switch (m_Flags & eAllVacuum) { + case fVacuumOff: + x_ExecuteSql(handle, "PRAGMA auto_vacuum = NONE"); + break; + case fVacuumManual: + x_ExecuteSql(handle, "PRAGMA auto_vacuum = INCREMENTAL"); + break; + case fVacuumOn: + x_ExecuteSql(handle, "PRAGMA auto_vacuum = FULL"); + break; + default: + // Evidently this will throw an exception + x_CheckFlagsValidity(m_Flags, eAllSync); + } +} + +void +CSQLITE_Connection::SetFlags(TOperationFlags flags) +{ + if ((flags & eAllVacuum) != (m_Flags & eAllVacuum)) { + NCBI_THROW(CSQLITE_Exception, eWrongFlags, + "Cannot change vacuuming flags after database creation"); + } + + m_Flags = flags; + m_HandlePool.Clear(); +} + +CSQLITE_Statement* +CSQLITE_Connection::CreateVacuumStmt(size_t max_free_size) +{ + string sql("PRAGMA incremental_vacuum("); + sql += NStr::UInt8ToString((max_free_size + kSQLITE_DefPageSize - 1) + / kSQLITE_DefPageSize); + sql += ")"; + + return new CSQLITE_Statement(this, sql); +} + +void +CSQLITE_Connection::DeleteDatabase(void) +{ + m_HandlePool.Clear(); + CFile(m_FileName).Remove(); + // For simplification this hard-coded name is taken from SQLite. If it + // changed the name we would change it too. + CFile(m_FileName + "-journal").Remove(); +} + +DEFINE_STATIC_FAST_MUTEX(s_FileAccessMutex); + +CSQLITE_Connection* +CSQLITE_Connection::CreateInMemoryDatabase(CTempString file_name, bool shared) +{ + CFastMutexGuard guard(s_FileAccessMutex); + string dbname = shared ? "file::memory:?cache=shared" : ":memory:"; + CSQLITE_Connection fdb(file_name, fReadOnly); + unique_ptr mdb(new CSQLITE_Connection(dbname, + fExternalMT | fVacuumOff | fJournalOff | fSyncOff | fTempToMemory)); + + sqlite3* fh = fdb.LockHandle(); + sqlite3* mh = mdb->m_HandlePool.Get(); + try { + sqlite3_backup* backup = sqlite3_backup_init(mh, "main", fh, "main"); + if( backup ) { + sqlite3_backup_step(backup, -1); + sqlite3_backup_finish(backup); + } + fdb.UnlockHandle(fh); + if (sqlite3_errcode(mh) != SQLITE_OK) { + mdb->m_HandlePool.Return(mh); + return NULL; + } + mdb->m_InMemory = mh; + } + catch (...) { + fdb.UnlockHandle(fh); + mdb->m_HandlePool.Return(mh); + return NULL; + } + return mdb.release(); +} + + +CSQLITE_Statement::~CSQLITE_Statement(void) +{ + try { + x_Finalize(); + } + STD_CATCH_ALL_X(3, "Error in x_Finalize()"); + + if (m_ConnHandle && m_Conn) { + m_Conn->UnlockHandle(m_ConnHandle); + } +} + +void +CSQLITE_Statement::x_Prepare(CTempString sql) +{ + if (sql.empty()) { + return; + } + + if (!m_ConnHandle) { + m_ConnHandle = m_Conn->LockHandle(); + } + + SQLITE_SAFE_CALL((sqlite3_prepare_v2(m_ConnHandle, sql.data(), int(sql.size()), + &m_StmtHandle, NULL)), + m_ConnHandle, eStmtPrepare, + "Error preparing statement for \"" << sql << "\"" + ); + _ASSERT(sql_ret == SQLITE_OK); +} + +void +CSQLITE_Statement::x_Finalize(void) +{ + if (m_StmtHandle) { + SQLITE_SAFE_CALL(sqlite3_finalize(m_StmtHandle), + m_ConnHandle, eStmtFinalize, + "Cannot finalize statement"); + } +} + +#define STMT_BIND_IMPL(sql_type, str_type, index_and_val) \ + do { \ + _ASSERT(m_StmtHandle); \ + SQLITE_SAFE_CALL((NCBI_NAME2(sqlite3_bind_, sql_type) \ + (m_StmtHandle, index_and_val)), \ + m_ConnHandle, eStmtBind, \ + "Error binding " << #str_type \ + << " parameter N " << index \ + ); \ + _ASSERT(sql_ret == SQLITE_OK); \ + } while (0) \ +/**/ + +#define COMMA , + +#define STMT_BIND_NO_VAL(sql_type, str_type, index) \ + STMT_BIND_IMPL(sql_type, str_type, index) + +#define STMT_BIND(sql_type, str_type, index, val) \ + STMT_BIND_IMPL(sql_type, str_type, index COMMA val) + +#define STMT_BIND3(sql_type, str_type, index, val1, val2, val3) \ + STMT_BIND_IMPL(sql_type, str_type, index COMMA val1 COMMA val2 COMMA val3) + + +void +CSQLITE_Statement::Bind(int index, Int8 val) +{ + STMT_BIND(int64, Int8, index, val); +} + +void +CSQLITE_Statement::Bind(int index, double val) +{ + STMT_BIND(double, double, index, val); +} + +void +CSQLITE_Statement::Bind(int index, CTempString val) +{ + STMT_BIND3(text, string, index, + val.data(), int(val.size()), SQLITE_TRANSIENT); +} + +void +CSQLITE_Statement::Bind(int index, const char* data, size_t size) +{ + STMT_BIND3(text, static string, index, data, int(size), SQLITE_STATIC); +} + +void +CSQLITE_Statement::Bind(int index, const void* data, size_t size) +{ + STMT_BIND3(blob, blob, index, data, int(size), SQLITE_STATIC); +} + +void +CSQLITE_Statement::BindZeroedBlob(int index, size_t size) +{ + STMT_BIND(zeroblob, zeroed blob, index, int(size)); +} + +void +CSQLITE_Statement::BindNull(int index) +{ + STMT_BIND_NO_VAL(null, NULL, index); +} + +bool +CSQLITE_Statement::Step(void) +{ + _ASSERT(m_StmtHandle); + SQLITE_SAFE_CALL_EX(sqlite3_step(m_StmtHandle), + m_ConnHandle, eStmtStep, + "Error stepping through statement results", + sqlite3_reset(m_StmtHandle)); + _ASSERT(sql_ret == SQLITE_ROW || sql_ret == SQLITE_DONE); + return sql_ret == SQLITE_ROW; +} + +void +CSQLITE_Statement::Reset(void) +{ + if (!m_StmtHandle) { + return; + } + + SQLITE_SAFE_CALL(sqlite3_reset(m_StmtHandle), + m_ConnHandle, eStmtStep, + "Error reseting statement"); + _ASSERT(sql_ret == SQLITE_OK); +} + +void +CSQLITE_Statement::ClearBindings(void) +{ + if (!m_StmtHandle) { + return; + } + + SQLITE_SAFE_CALL(sqlite3_clear_bindings(m_StmtHandle), + m_ConnHandle, eStmtStep, + "Error clearing bindings"); + _ASSERT(sql_ret == SQLITE_OK); +} + +CStringUTF8 +CSQLITE_Statement::GetColumnName(int col_ind) const +{ + _ASSERT(m_StmtHandle); + const char* result = sqlite3_column_name(m_StmtHandle, col_ind); + if (!result) { + SQLITE_THROW(CSQLITE_Exception::eUnknown, m_ConnHandle, + "Error requesting column name"); + } + return CUtf8::AsUTF8(result, eEncoding_UTF8); +} + +string +CSQLITE_Statement::GetString(int col_ind) const +{ + _ASSERT(m_StmtHandle); + string result; + const unsigned char* buf = sqlite3_column_text(m_StmtHandle, col_ind); + size_t size = static_cast( + sqlite3_column_bytes(m_StmtHandle, col_ind)); + result.append(reinterpret_cast(buf), size); + return result; +} + +size_t +CSQLITE_Statement::GetBlobSize(int col_ind) const +{ + return (size_t)sqlite3_column_bytes(m_StmtHandle, col_ind); +} + +size_t +CSQLITE_Statement::GetBlob(int col_ind, void* buffer, size_t size) const +{ + _ASSERT(m_StmtHandle); + const void* buf = sqlite3_column_blob(m_StmtHandle, col_ind); + size_t buf_size = static_cast( + sqlite3_column_bytes(m_StmtHandle, col_ind)); + buf_size = min(buf_size, size); + memcpy(buffer, buf, buf_size); + return buf_size; +} + + +CSQLITE_StatementLock::~CSQLITE_StatementLock(void) +{ + try { + m_Stmt->Reset(); + } + catch (exception& ex) { + ERR_POST("Error resetting statement: " << ex.what()); + } +} + + + +/// Helper structure for opening the blob from CGuard<> +template +struct SSQLITE_BlobOpen +{ + void operator() (CSQLITE_Blob& blob) + { + blob.x_OpenBlob(readwrite); + } +}; + +/// Helper structure for closing the blob from CGuard<> +struct SSQLITE_BlobClose +{ + void operator() (CSQLITE_Blob& blob) + { + blob.x_CloseBlob(); + } +}; + +/// Guard opening blob for read-only access at construction and closing it +/// at destruction. +typedef CGuard, SSQLITE_BlobClose> TBlobReadGuard; +/// Guard opening blob for read-write access at construction and closing it +/// at destruction. +typedef CGuard, SSQLITE_BlobClose> TBlobWriteGuard; + + +#define BLOB_SAFE_CALL(blob_call, ex_type, err_msg) \ + SQLITE_SAFE_CALL((blob_call), m_ConnHandle, ex_type, \ + err_msg << " " << m_Table << "." << m_Column \ + << " where rowid = " << m_Rowid) + + +inline void +CSQLITE_Blob::x_Init(void) +{ + m_ConnHandle = NULL; + m_BlobHandle = NULL; + m_Size = 0; + m_Position = 0; +} + +CSQLITE_Blob::CSQLITE_Blob(CSQLITE_Connection* conn, + CTempString table, + CTempString column, + Int8 rowid) + : m_Conn(conn), + m_Database("main"), + m_Table(table), + m_Column(column), + m_Rowid(rowid) +{ + x_Init(); +} + +CSQLITE_Blob::CSQLITE_Blob(CSQLITE_Connection* conn, + CTempString db_name, + CTempString table, + CTempString column, + Int8 rowid) + : m_Conn(conn), + m_Database(db_name), + m_Table(table), + m_Column(column), + m_Rowid(rowid) +{ + x_Init(); +} + +void +CSQLITE_Blob::x_OpenBlob(bool readwrite /* = false */) +{ + if (!m_ConnHandle) { + m_ConnHandle = m_Conn->LockHandle(); + } + + BLOB_SAFE_CALL((sqlite3_blob_open(m_ConnHandle, + m_Database.c_str(), + m_Table.c_str(), + m_Column.c_str(), + m_Rowid, + readwrite, + &m_BlobHandle)), + eBlobOpen, "Error openning blob" + ); + _ASSERT(sql_ret == SQLITE_OK); + + if (m_Size == 0) { + m_Size = static_cast(sqlite3_blob_bytes(m_BlobHandle)); + } +} + +void +CSQLITE_Blob::x_CloseBlob(void) +{ + if (!m_BlobHandle) + return; + + BLOB_SAFE_CALL(sqlite3_blob_close(m_BlobHandle), + eBlobClose, "Error closing blob"); + _ASSERT(sql_ret == SQLITE_OK); + m_BlobHandle = NULL; +} + +size_t +CSQLITE_Blob::GetSize(void) +{ + if (m_Size == 0) { + TBlobReadGuard guard(*this); + + // m_Size will be automatically initialized + } + + return m_Size; +} + +size_t +CSQLITE_Blob::Read(void* buffer, size_t size) +{ + TBlobReadGuard guard(*this); + + _ASSERT(m_Size >= m_Position); + + if (size > m_Size - m_Position) { + size = m_Size - m_Position; + } + + BLOB_SAFE_CALL((sqlite3_blob_read(m_BlobHandle, + buffer, + static_cast(size), + static_cast(m_Position))), + eBlobRead, + "Error reading from position " << m_Position << " of blob" + ); + _ASSERT(sql_ret == SQLITE_OK); + m_Position += size; + + return size; +} + +void +CSQLITE_Blob::Write(const void* data, size_t size) +{ + if (size == 0) + return; + + // A bit of a trick to avoid opening/closing blob just for reading its + // size. Thus if size is 0 we open blob, automatically read size and then + // decide what we're gonna do. + if (m_Size == 0 || m_Position < m_Size) { + TBlobWriteGuard guard(*this); + + if (m_Position < m_Size) { + size_t to_write = min(m_Size - m_Position, size); + BLOB_SAFE_CALL((sqlite3_blob_write(m_BlobHandle, + data, int(to_write), + int(m_Position))), + eBlobWrite, + "Error writing to position " << m_Position + << " " << to_write << " bytes for blob" + ); + _ASSERT(sql_ret == SQLITE_OK); + + data = static_cast(data) + to_write; + size -= to_write; + m_Position += to_write; + } + } + + if (size != 0) { + if (!m_AppendStmt.get()) { + string sql("update "); + sql += m_Database; + sql += "."; + sql += m_Table; + sql += " set "; + sql += m_Column; + sql += "="; + sql += m_Column; + sql += "||?2 where rowid=?1"; + + _ASSERT(m_ConnHandle); + m_AppendStmt.reset(new CSQLITE_Statement(m_ConnHandle, sql)); + } + try { + m_AppendStmt->Bind(1, m_Rowid); + m_AppendStmt->Bind(2, data, size); + m_AppendStmt->Execute(); + } + catch (...) { + m_AppendStmt->Reset(); + throw; + } + m_AppendStmt->Reset(); + } +} + +END_NCBI_SCOPE diff --git a/c++/src/dbapi/CMakeLists.dbapi.lib.txt b/c++/src/dbapi/CMakeLists.dbapi.lib.txt new file mode 100644 index 00000000..fd029afa --- /dev/null +++ b/c++/src/dbapi/CMakeLists.dbapi.lib.txt @@ -0,0 +1,12 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/dbapi/Makefile.dbapi.lib +# +add_library(dbapi + variant active_obj dbapi driver_mgr err_handler ds_impl conn_impl + stmt_impl rs_impl rsmeta_impl cstmt_impl bytestreambuf blobstream + cursor_impl bulkinsert rw_impl +) + +target_link_libraries(dbapi + dbapi_driver +) diff --git a/c++/src/dbapi/CMakeLists.txt b/c++/src/dbapi/CMakeLists.txt new file mode 100644 index 00000000..d969c3e2 --- /dev/null +++ b/c++/src/dbapi/CMakeLists.txt @@ -0,0 +1,19 @@ +############################################################################## +# +# +if (APPLE) + #set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-framework,ApplicationServices -liconv") + #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wl,-framework,ApplicationServices -liconv") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-framework,ApplicationServices -liconv") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-framework,ApplicationServices -liconv -undefined dynamic_lookup") +endif (APPLE) + +# Include projects from this directory +include(CMakeLists.dbapi.lib.txt) + +# Recurse subdirectories +add_subdirectory(driver) +add_subdirectory(simple) +add_subdirectory(cache) +add_subdirectory(lang_bind) +add_subdirectory(test) diff --git a/c++/src/dbapi/bytestreambuf.hpp b/c++/src/dbapi/bytestreambuf.hpp index b716a7ae..ada50b47 100644 --- a/c++/src/dbapi/bytestreambuf.hpp +++ b/c++/src/dbapi/bytestreambuf.hpp @@ -1,7 +1,7 @@ #ifndef _BYTESTREAMBUF_HPP_ #define _BYTESTREAMBUF_HPP_ -/* $Id: bytestreambuf.hpp 426478 2014-02-10 19:48:45Z ucko $ +/* $Id: bytestreambuf.hpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -26,7 +26,7 @@ * * =========================================================================== * -* File Name: $Id: bytestreambuf.hpp 426478 2014-02-10 19:48:45Z ucko $ +* File Name: $Id: bytestreambuf.hpp 535289 2017-05-08 13:38:35Z ivanov $ * * Author: Michael Kholodov * @@ -70,7 +70,7 @@ private: CResultSet* m_rs; CDB_SendDataCmd* m_cmd; //int m_column; - auto_ptr m_AutoTrans; + unique_ptr m_AutoTrans; }; END_NCBI_SCOPE diff --git a/c++/src/dbapi/cache/CMakeLists.ncbi_xcache_dbapi.lib.txt b/c++/src/dbapi/cache/CMakeLists.ncbi_xcache_dbapi.lib.txt new file mode 100644 index 00000000..29007a1d --- /dev/null +++ b/c++/src/dbapi/cache/CMakeLists.ncbi_xcache_dbapi.lib.txt @@ -0,0 +1,11 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/dbapi/cache/Makefile.ncbi_xcache_dbapi.lib +# +add_library(ncbi_xcache_dbapi + dbapi_blob_cache dbapi_blob_cache_cf +) +include_directories(SYSTEM ${CMPRS_INCLUDE}) + +target_link_libraries(ncbi_xcache_dbapi + dbapi +) diff --git a/c++/src/dbapi/cache/CMakeLists.txt b/c++/src/dbapi/cache/CMakeLists.txt new file mode 100644 index 00000000..8a649ad8 --- /dev/null +++ b/c++/src/dbapi/cache/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.ncbi_xcache_dbapi.lib.txt) + +# Recurse subdirectories +add_subdirectory(test ) +add_subdirectory(admintool) diff --git a/c++/src/dbapi/cache/dbapi_blob_cache.cpp b/c++/src/dbapi/cache/dbapi_blob_cache.cpp index ebb68d0d..006e985f 100644 --- a/c++/src/dbapi/cache/dbapi_blob_cache.cpp +++ b/c++/src/dbapi/cache/dbapi_blob_cache.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_blob_cache.cpp 487444 2015-12-17 18:38:53Z ucko $ +/* $Id: dbapi_blob_cache.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -284,7 +284,7 @@ public: } private: - auto_ptr m_TmpFile; + unique_ptr m_TmpFile; string m_TempDir; string m_TempPrefix; @@ -311,7 +311,7 @@ public: const string& subkey, size_t buffer_size = kWriterBufferSize) : m_Cache(cache), - m_TmpFile(0), + m_TmpFile(nullptr), m_GoodStateFlag(true), m_Flushed(false), m_Conn(cache->GetConnection()), @@ -527,7 +527,7 @@ private: private: CDBAPI_Cache* m_Cache; - auto_ptr m_TmpFile; + unique_ptr m_TmpFile; string m_TempDir; string m_TempPrefix; bool m_GoodStateFlag; //!< Stream is in the good state @@ -619,7 +619,7 @@ void CDBAPI_Cache::Open(const string& driver, { CDriverManager &db_drv_man = CDriverManager::GetInstance(); IDataSource* ds = db_drv_man.CreateDs(driver); - auto_ptr conn(ds->CreateConnection()); // TODO: Add ownership flag + unique_ptr conn(ds->CreateConnection()); // TODO: Add ownership flag if (conn.get() == 0) { NCBI_THROW(CDBAPI_ICacheException, eConnectionError, "Cannot create connection"); @@ -845,7 +845,7 @@ IReader* CDBAPI_Cache::GetReadStream(const string& key, } } - auto_ptr rdr; + unique_ptr rdr; try { rdr.reset(new CDBAPI_CacheIReader(m_Conn, key, version, subkey, @@ -906,7 +906,7 @@ IWriter* CDBAPI_Cache::GetWriteStream(const string& key, Purge(key, subkey, 0, m_VersionFlag); } - auto_ptr wrt( + unique_ptr wrt( new CDBAPI_CacheIWriter(this, key, version, subkey, GetMemBufferSize())); wrt->SetTemps(m_TempDir, m_TempPrefix); diff --git a/c++/src/dbapi/cache/dbapi_blob_cache_cf.cpp b/c++/src/dbapi/cache/dbapi_blob_cache_cf.cpp index 077568f7..7f579367 100644 --- a/c++/src/dbapi/cache/dbapi_blob_cache_cf.cpp +++ b/c++/src/dbapi/cache/dbapi_blob_cache_cf.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_blob_cache_cf.cpp 369072 2012-07-16 16:49:52Z ivanov $ +/* $Id: dbapi_blob_cache_cf.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -107,7 +107,7 @@ ICache* CDBAPI_BlobCacheCF::CreateInstance( CVersionInfo version, const TPluginManagerParamTree* params) const { - auto_ptr drv; + unique_ptr drv; if (driver.empty() || driver == m_DriverName) { if (version.Match(NCBI_INTERFACE_VERSION(ICache)) != CVersionInfo::eNonCompatible) { diff --git a/c++/src/dbapi/driver/CMakeLists.dbapi_driver.lib.txt b/c++/src/dbapi/driver/CMakeLists.dbapi_driver.lib.txt new file mode 100644 index 00000000..29778d55 --- /dev/null +++ b/c++/src/dbapi/driver/CMakeLists.dbapi_driver.lib.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/dbapi/driver/Makefile.dbapi_driver.lib +# + +if (WIN32) + set(os_src ncbi_win_hook) +endif (WIN32) + +add_library(dbapi_driver + handle_stack numeric_convert parameters exception interfaces public + types memory_store pointer_pot driver_mgr dbapi_driver_conn_mgr + dbapi_conn_factory dbapi_svc_mapper dbapi_driver_utils dbapi_impl_cmd + dbapi_impl_connection dbapi_impl_context dbapi_impl_result + dbapi_driver_conn_params dbapi_driver_exception_storage + dbapi_object_convert dbapi_driver_convert dbapi_pool_balancer ${os_src} +) + +target_link_libraries(dbapi_driver + xncbi +) diff --git a/c++/src/dbapi/driver/CMakeLists.txt b/c++/src/dbapi/driver/CMakeLists.txt new file mode 100644 index 00000000..de014592 --- /dev/null +++ b/c++/src/dbapi/driver/CMakeLists.txt @@ -0,0 +1,24 @@ +############################################################################## +# +# +#link_directories( path/to/libs ) + +# Include projects from this directory +include(CMakeLists.dbapi_driver.lib.txt) + +# Recurse subdirectories +add_subdirectory(util) +add_subdirectory(ctlib) +add_subdirectory(ftds-default) +add_subdirectory(ftds64) +add_subdirectory(ftds95) +add_subdirectory(dblib) + +if (MySQL_FOUND) + add_subdirectory(mysql) +endif() + +if (${ODBC_FOUND}) +add_subdirectory(odbc) +endif (${ODBC_FOUND}) +add_subdirectory(samples) diff --git a/c++/src/dbapi/driver/Makefile.dbapi_driver.lib b/c++/src/dbapi/driver/Makefile.dbapi_driver.lib index 968e6b5c..86a0a878 100644 --- a/c++/src/dbapi/driver/Makefile.dbapi_driver.lib +++ b/c++/src/dbapi/driver/Makefile.dbapi_driver.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.dbapi_driver.lib 427418 2014-02-20 13:34:57Z gouriano $ +# $Id: Makefile.dbapi_driver.lib 548536 2017-10-16 15:16:58Z ivanov $ SRC = handle_stack numeric_convert parameters exception interfaces \ public types memory_store pointer_pot driver_mgr \ @@ -6,7 +6,7 @@ SRC = handle_stack numeric_convert parameters exception interfaces \ dbapi_driver_utils dbapi_impl_cmd dbapi_impl_connection \ dbapi_impl_context dbapi_impl_result dbapi_driver_conn_params \ dbapi_driver_exception_storage dbapi_object_convert \ - dbapi_driver_convert + dbapi_driver_convert dbapi_pool_balancer LIB = dbapi_driver diff --git a/c++/src/dbapi/driver/dbapi_conn_factory.cpp b/c++/src/dbapi/driver/dbapi_conn_factory.cpp index 5cda0b53..de7d7346 100644 --- a/c++/src/dbapi/driver/dbapi_conn_factory.cpp +++ b/c++/src/dbapi/driver/dbapi_conn_factory.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_conn_factory.cpp 507218 2016-07-15 19:45:42Z ucko $ +/* $Id: dbapi_conn_factory.cpp 548536 2017-10-16 15:16:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -23,7 +23,7 @@ * * =========================================================================== * -* Author: Sergey Sikorskiy +* Authors: Sergey Sikorskiy, Aaron Ucko * */ @@ -33,9 +33,11 @@ #include #include #include +#include #include #include #include +#include "dbapi_pool_balancer.hpp" #include #include @@ -355,21 +357,34 @@ CDBConnectionFactory::MakeDBConnection( } else { // Server name is already dispatched ... string single_server(params.GetParam("single_server")); + string is_pooled(params.GetParam("is_pooled")); // We probably need to re-dispatch it ... - if (single_server != "true" && GetMaxNumOfDispatches() && - rt_data.GetNumOfDispatches(params.GetServerName()) >= GetMaxNumOfDispatches()) { + if (single_server != "true" + && ((GetMaxNumOfDispatches() + && (rt_data.GetNumOfDispatches(params.GetServerName()) + >= GetMaxNumOfDispatches())) + || (dsp_srv->GetExpireTime() != 0 + && (CurrentTime(CTime::eUTC).GetTimeT() + > dsp_srv->GetExpireTime())))) { // We definitely need to re-dispatch it ... // Clean previous info ... rt_data.CleanExcluded(params.GetServerName()); rt_data.SetDispatchedServer(params.GetServerName(), TSvrRef()); + if (is_pooled == "true") { + rt_data.GetServerOptions(params.GetServerName()).clear(); + } + t_con.reset(DispatchServerName(opening_ctx, params)); + } else if (single_server != "true" && is_pooled == "true") { + // Don't fully redispatch, but keep the pool balanced t_con.reset(DispatchServerName(opening_ctx, params)); } else { // We do not need to re-dispatch it ... // Try to connect. try { + opening_ctx.last_tried.Reset(dsp_srv); // provisionally // I_DriverContext::SConnAttr cur_conn_attr(conn_attr); // cur_conn_attr.srv_name = dsp_srv->GetName(); CDB_DBLB_Delegate cur_params( @@ -401,8 +416,8 @@ CDBConnectionFactory::MakeDBConnection( // Check conn_status ... if (opening_ctx.conn_status == IConnValidator::eTempInvalidConn) { - rt_data.IncNumOfValidationFailures(params.GetServerName(), - dsp_srv); + rt_data.IncNumOfValidationFailures + (params.GetServerName(), opening_ctx.last_tried); } // Re-dispatch ... @@ -411,7 +426,8 @@ CDBConnectionFactory::MakeDBConnection( } else { // Dispatched server is already set, but calling of this method // will increase number of successful dispatches. - rt_data.SetDispatchedServer(params.GetServerName(), dsp_srv); + rt_data.SetDispatchedServer(params.GetServerName(), + opening_ctx.last_tried); } } } @@ -449,6 +465,15 @@ CDBConnectionFactory::DispatchServerName( unsigned int alternatives = GetMaxNumOfServerAlternatives(); list tried_servers; bool full_retry_made = false; + CRef balancer; + + if ( !do_not_dispatch && params.GetParam("is_pooled") == "true" + && !service_name.empty() ) { + balancer.Reset(new CDBPoolBalancer + (service_name, params.GetParam("pool_name"), + ctx.driver_ctx, + rt_data.GetServerOptions(service_name))); + } for ( ; !t_con && alternatives > 0; --alternatives ) { TSvrRef dsp_srv; @@ -461,9 +486,22 @@ CDBConnectionFactory::DispatchServerName( // This is possible when somebody uses a named connection pool. // In this case we even won't try to map it. else if (!service_name.empty()) { - dsp_srv = rt_data.GetDBServiceMapper().GetServer(service_name); + if (balancer.NotEmpty()) { + dsp_srv = balancer->GetServer(&t_con, params); + } + if (dsp_srv.Empty()) { + dsp_srv = rt_data.GetDispatchedServer(service_name); + } + if (dsp_srv.Empty()) { + dsp_srv = rt_data.GetDBServiceMapper().GetServer(service_name); + } - if (dsp_srv.Empty() && tried_servers.empty()) { + if (tried_servers.empty() + && (dsp_srv.Empty() + || (dsp_srv->GetName() == service_name + && dsp_srv->GetHost() == 0 + && dsp_srv->GetPort() == 0 + && !rt_data.GetExcluded(service_name).empty() ))) { _TRACE("List of servers for service " << service_name << " is exhausted. Giving excluded a try."); rt_data.CleanExcluded(service_name); @@ -494,6 +532,13 @@ CDBConnectionFactory::DispatchServerName( ITERATE(list, it, tried_servers) { rt_data.Exclude(service_name, *it); } + if (balancer.NotEmpty()) { + balancer.Reset + (new CDBPoolBalancer + (service_name, params.GetParam("pool_name"), + ctx.driver_ctx, + rt_data.GetServerOptions(service_name, true))); + } full_retry_made = true; continue; } @@ -533,7 +578,7 @@ CDBConnectionFactory::DispatchServerName( ctx.conn_status = IConnValidator::eInvalidConn; // We don't check value of conn_status inside of a loop below by design. - for (; !t_con && attepmpts > 0; --attepmpts) { + for (; attepmpts > 0; --attepmpts) { try { CDB_DBLB_Delegate cur_params( cur_srv_name, @@ -543,7 +588,11 @@ CDBConnectionFactory::DispatchServerName( cur_params.SetOpeningMsgHandlers() = ctx.handlers; t_con = MakeValidConnection(ctx, // curr_conn_attr, - cur_params); + cur_params, + t_con); + if (t_con != NULL) { + break; + } } catch (CDB_Exception& ex) { // m_Errors.push_back(ex.Clone()); ctx.handlers.PostMsg(&ex); @@ -574,11 +623,12 @@ CDBConnectionFactory::DispatchServerName( // Server might be temporarily unavailable ... // Check conn_status ... if (ctx.conn_status == IConnValidator::eTempInvalidConn) { - rt_data.IncNumOfValidationFailures(service_name, dsp_srv); + rt_data.IncNumOfValidationFailures(service_name, + ctx.last_tried); } else { // conn_status == IConnValidator::eInvalidConn - rt_data.Exclude(service_name, dsp_srv); - tried_servers.push_back(dsp_srv); + rt_data.Exclude(service_name, ctx.last_tried); + tried_servers.push_back(ctx.last_tried); } } } else { @@ -597,7 +647,8 @@ CDBConnectionFactory::DispatchServerName( CDB_Connection* CDBConnectionFactory::MakeValidConnection( SOpeningContext& ctx, - const CDBConnParams& params) + const CDBConnParams& params, + CDB_Connection* candidate) { _TRACE("Trying to connect to server '" << params.GetServerName() << "', host " << impl::ConvertN2A(params.GetHost()) @@ -609,10 +660,38 @@ CDBConnectionFactory::MakeValidConnection( ctx.tried.push_back(params.GetServerName()); } - auto_ptr conn(CtxMakeConnection(ctx.driver_ctx, params)); + unique_ptr conn; + try { + if (candidate == NULL) { + conn.reset(CtxMakeConnection(ctx.driver_ctx, params)); + } else { + conn.reset(candidate); + } + } catch (...) { + CRef validator = params.GetConnValidator(); + CRuntimeData& rt_data = GetRuntimeData(validator); + const string& service = params.GetServerName(); + ctx.last_tried.Reset(rt_data.GetDispatchedServer(service)); + if (ctx.last_tried.Empty()) { + ctx.last_tried.Reset + (new CDBServer(service, params.GetHost(), params.GetPort())); + } + throw; + } if (conn.get()) { + ctx.last_tried.Reset(new CDBServer(conn->ServerName(), + conn->Host(), conn->Port())); + if (conn->IsReusable() && !params.GetParam("pool_name").empty()) { + if (conn->Host() != 0) { + ctx.tried.back() = (impl::ConvertN2A(conn->Host()) + ':' + + NStr::NumericToString(conn->Port())); + } else { + ctx.tried.back() = conn->ServerName(); + } + } + if (conn->Host() == 0) { GetRuntimeData(params.GetConnValidator()).GetDBServiceMapper() .RecordServer(conn->GetExtraFeatures()); @@ -634,6 +713,10 @@ CDBConnectionFactory::MakeValidConnection( try { ctx.conn_status = validator.Validate(*conn); if (ctx.conn_status != IConnValidator::eValidConn) { + if (conn->IsReusable()) { + static_cast(conn->GetExtraFeatures()) + .m_Reusable = false; + } CDB_Exception ex(DIAG_COMPILE_INFO, NULL, CDB_Exception::EErrCode(0), "Validation failed against " @@ -649,6 +732,10 @@ CDBConnectionFactory::MakeValidConnection( = params.GetConnValidator()->ValidateException(ex); } if (ctx.conn_status != IConnValidator::eValidConn) { + if (conn->IsReusable()) { + static_cast(conn->GetExtraFeatures()) + .m_Reusable = false; + } // m_Errors.push_back(ex.Clone()); ctx.handlers.PostMsg(&ex); return NULL; @@ -668,6 +755,15 @@ CDBConnectionFactory::MakeValidConnection( conn->FinishOpening(); } else { + CRef validator = params.GetConnValidator(); + CRuntimeData& rt_data = GetRuntimeData(validator); + const string& service = params.GetServerName(); + ctx.last_tried.Reset(rt_data.GetDispatchedServer(service)); + if (ctx.last_tried.Empty()) { + ctx.last_tried.Reset + (new CDBServer(service, params.GetHost(), params.GetPort())); + } + m_Errors.push_back(new CDB_Exception(DIAG_COMPILE_INFO, NULL, CDB_Exception::EErrCode(0), "Parameters prohibited creating connection", eDiag_Error, 0)); } @@ -739,12 +835,13 @@ void CDBConnectionFactory::x_LogConnection(const SOpeningContext& ctx, CRef validator = params.GetConnValidator(); CRuntimeData& rt_data = GetRuntimeData(validator); const string& service = params.GetServerName(); - TSvrRef dsp_srv = rt_data.GetDispatchedServer(service); + TSvrRef dsp_srv = ctx.last_tried; CDiagContext_Extra extra = GetDiagContext().Extra(); string prefix = s_GetNextLogPrefix(); if (dsp_srv.Empty()) { + // Try rt_data.GetDispatchedServer(service) first? dsp_srv.Reset(&stub_dsp_srv); } @@ -854,6 +951,21 @@ m_DBServiceMapper(mapper) { } +IDBServiceMapper::TOptions& +CDBConnectionFactory::CRuntimeData::GetServerOptions(const string& svc_name, + bool force_refresh) +{ + auto& options = m_ServerOptionsMap[svc_name]; + if (force_refresh || options.empty()) { + m_DBServiceMapper->GetServerOptions(svc_name, &options); + // OK to leave empty if nothing turns up; service mappers can and + // do take responsibility for temporarily remembering negative + // results if checking from scratch is slow, and higher-level logic + // on this end falls back on GetServer as needed. + } + return options; +} + TSvrRef CDBConnectionFactory::CRuntimeData::GetDispatchedServer( const string& service_name @@ -912,6 +1024,9 @@ CDBConnectionFactory::CRuntimeData::IncNumOfValidationFailures( void CDBConnectionFactory::CRuntimeData::Exclude(const string& service_name, const TSvrRef& server) { + if (server.Empty()) { + return; + } GetDBServiceMapper().Exclude(service_name, server); if (server->GetHost() != 0) { string& excluded = m_ExclusionSummaryMap[service_name]; @@ -1105,10 +1220,10 @@ CTrivialConnValidator::Validate(CDB_Connection& conn) // Get current database name ... { - auto_ptr auto_stmt(conn.LangCmd("select db_name()")); + unique_ptr auto_stmt(conn.LangCmd("select db_name()")); auto_stmt->Send(); while (auto_stmt->HasMoreResults()) { - auto_ptr rs(auto_stmt->Result()); + unique_ptr rs(auto_stmt->Result()); if (rs.get() == NULL) { continue; @@ -1131,7 +1246,7 @@ CTrivialConnValidator::Validate(CDB_Connection& conn) } if (GetAttr() & eCheckSysobjects) { - auto_ptr set_cmd(conn.LangCmd("SELECT id FROM sysobjects")); + unique_ptr set_cmd(conn.LangCmd("SELECT id FROM sysobjects")); set_cmd->Send(); set_cmd->DumpResults(); } @@ -1154,7 +1269,7 @@ CTrivialConnValidator::Validate(CDB_Connection& conn) conn.SetDatabaseName(GetDBName()); if (GetAttr() & eCheckSysobjects) { - auto_ptr set_cmd(conn.LangCmd("SELECT id FROM sysobjects")); + unique_ptr set_cmd(conn.LangCmd("SELECT id FROM sysobjects")); set_cmd->Send(); set_cmd->DumpResults(); } diff --git a/c++/src/dbapi/driver/dbapi_driver_conn_mgr.cpp b/c++/src/dbapi/driver/dbapi_driver_conn_mgr.cpp index 4d57b0ac..96088ed8 100644 --- a/c++/src/dbapi/driver/dbapi_driver_conn_mgr.cpp +++ b/c++/src/dbapi/driver/dbapi_driver_conn_mgr.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_driver_conn_mgr.cpp 494417 2016-03-07 15:06:35Z ucko $ +/* $Id: dbapi_driver_conn_mgr.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -71,7 +71,7 @@ CDefaultConnectPolicy::MakeDBConnection( I_DriverContext& ctx, const CDBConnParams& params) { - auto_ptr conn(CtxMakeConnection(ctx, params)); + unique_ptr conn(CtxMakeConnection(ctx, params)); if (conn.get()) { CTrivialConnValidator use_db_validator( diff --git a/c++/src/dbapi/driver/dbapi_driver_conn_params.cpp b/c++/src/dbapi/driver/dbapi_driver_conn_params.cpp index f0ab89e5..018d4add 100644 --- a/c++/src/dbapi/driver/dbapi_driver_conn_params.cpp +++ b/c++/src/dbapi/driver/dbapi_driver_conn_params.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_driver_conn_params.cpp 515776 2016-10-05 17:33:35Z ivanov $ +/* $Id: dbapi_driver_conn_params.cpp 515251 2016-09-29 15:02:27Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/dbapi/driver/dbapi_driver_exception_storage.cpp b/c++/src/dbapi/driver/dbapi_driver_exception_storage.cpp index 0b622b83..2b39b4d8 100644 --- a/c++/src/dbapi/driver/dbapi_driver_exception_storage.cpp +++ b/c++/src/dbapi/driver/dbapi_driver_exception_storage.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_driver_exception_storage.cpp 440505 2014-07-14 19:00:33Z ucko $ +/* $Id: dbapi_driver_exception_storage.cpp 530219 2017-03-13 14:42:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -45,7 +45,7 @@ namespace impl ///////////////////////////////////////////////////////////////////////////// struct SNoLock { - void operator() (CDB_UserHandler::TExceptions& resource) const {} + void operator() (CDB_UserHandler::TExceptions& /*resource*/) const {} }; struct SUnLock diff --git a/c++/src/dbapi/driver/dbapi_driver_sample_base.cpp b/c++/src/dbapi/driver/dbapi_driver_sample_base.cpp index 0350d9b3..3bf34117 100644 --- a/c++/src/dbapi/driver/dbapi_driver_sample_base.cpp +++ b/c++/src/dbapi/driver/dbapi_driver_sample_base.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_driver_sample_base.cpp 441728 2014-07-28 15:00:40Z ucko $ +/* $Id: dbapi_driver_sample_base.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -80,7 +80,7 @@ void CDbapiDriverSampleApp::Init() { // Create command-line argument descriptions class - auto_ptr arg_desc(new CArgDescriptions); + unique_ptr arg_desc(new CArgDescriptions); // Specify USAGE context arg_desc->SetUsageContext(GetArguments().GetProgramBasename(), diff --git a/c++/src/dbapi/driver/dbapi_driver_utils.cpp b/c++/src/dbapi/driver/dbapi_driver_utils.cpp index be70dd64..30f191b8 100644 --- a/c++/src/dbapi/driver/dbapi_driver_utils.cpp +++ b/c++/src/dbapi/driver/dbapi_driver_utils.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_driver_utils.cpp 503691 2016-06-07 15:44:43Z ucko $ +/* $Id: dbapi_driver_utils.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -247,7 +247,7 @@ CDBParams& CDBBindedParams::Set( CDBParams* CDBBindedParams::SemiShallowClone(void) const { - auto_ptr p(m_Bindings->SemiShallowClone()); + unique_ptr p(m_Bindings->SemiShallowClone()); return new CDBBindedParams(*p.release(), eTakeOwnership); } @@ -452,7 +452,7 @@ CRowInfo_SP_SQL_Server::Initialize(void) const string db_name; string db_owner; string sp_name; - auto_ptr cmd; + unique_ptr cmd; { vector arr_param; @@ -499,7 +499,7 @@ CRowInfo_SP_SQL_Server::Initialize(void) const cmd->Send(); while (cmd->HasMoreResults()) { - auto_ptr res(cmd->Result()); + unique_ptr res(cmd->Result()); if (res.get() != NULL && res->ResultType() == eDB_RowResult ) { CDB_VarChar db_name_value; @@ -528,7 +528,7 @@ CRowInfo_SP_SQL_Server::Initialize(void) const } } - // auto_ptr sp(conn.RPC("sp_sproc_columns")); + // unique_ptr sp(conn.RPC("sp_sproc_columns")); // We cannot use CDB_RPCCmd here because of recursion ... sql = "exec " + db_name + "." + db_owner + ".sp_sproc_columns @procedure_name"; cmd.reset(conn.LangCmd(sql)); @@ -539,7 +539,7 @@ CRowInfo_SP_SQL_Server::Initialize(void) const cmd->Send(); while (cmd->HasMoreResults()) { - auto_ptr res(cmd->Result()); + unique_ptr res(cmd->Result()); if (res.get() != NULL && res->ResultType() == eDB_RowResult ) { CDB_VarChar column_name; diff --git a/c++/src/dbapi/driver/dbapi_impl_cmd.cpp b/c++/src/dbapi/driver/dbapi_impl_cmd.cpp index e6d8e8ef..31afc8b5 100644 --- a/c++/src/dbapi/driver/dbapi_impl_cmd.cpp +++ b/c++/src/dbapi/driver/dbapi_impl_cmd.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_impl_cmd.cpp 497635 2016-04-08 13:52:30Z ucko $ +/* $Id: dbapi_impl_cmd.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -155,7 +155,7 @@ CBaseCmd::DumpResults(void) { // Experimental ... while(HasMoreResults()) { - auto_ptr dbres(Result()); + unique_ptr dbres(Result()); if( dbres.get() ) { CDB_ResultProcessor* res_proc = GetConnImpl().GetResultProcessor(); @@ -341,7 +341,7 @@ CSendDataCmd::DumpResults(void) { // Experimental ... while(HasMoreResults()) { - auto_ptr dbres(Result()); + unique_ptr dbres(Result()); if( dbres.get() ) { CDB_ResultProcessor* res_proc = GetConnImpl().GetResultProcessor(); diff --git a/c++/src/dbapi/driver/dbapi_impl_connection.cpp b/c++/src/dbapi/driver/dbapi_impl_connection.cpp index 254f5cb5..3c857601 100644 --- a/c++/src/dbapi/driver/dbapi_impl_connection.cpp +++ b/c++/src/dbapi/driver/dbapi_impl_connection.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_impl_connection.cpp 512261 2016-08-29 17:14:32Z ivanov $ +/* $Id: dbapi_impl_connection.cpp 548536 2017-10-16 15:16:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -144,6 +144,22 @@ void CConnection::CheckCanOpen(void) // Check for maximum number of connections if (!CDbapiConnMgr::Instance().AddConnect()) { + // May be ineffective, particularly given that there's no + // pool_idle_time by default. + m_DriverContext->CloseOldIdleConns(1); + if (CDbapiConnMgr::Instance().AddConnect()) { + m_Opened = true; + return; + } else { + // Could perhaps try more specific parameters first, but if a + // matching connection were already available in the pool, DBAPI + // would normally have used it instead of establishing a new one. + m_DriverContext->CloseUnusedConnections(kEmptyStr, kEmptyStr, 1); + if (CDbapiConnMgr::Instance().AddConnect()) { + m_Opened = true; + return; + } + } const string conn_num = NStr::NumericToString(CDbapiConnMgr::Instance().GetMaxConnect()); const string msg = "Cannot create new connection: hit limit of " + conn_num @@ -171,11 +187,11 @@ CConnection::CalculateServerType(CDBConnParams::EServerType server_type) CMsgHandlerGuard guard(*this); try { - auto_ptr cmd(LangCmd("SELECT @@version")); + unique_ptr cmd(LangCmd("SELECT @@version")); cmd->Send(); while (cmd->HasMoreResults()) { - auto_ptr res(cmd->Result()); + unique_ptr res(cmd->Result()); if (res.get() != NULL && res->ResultType() == eDB_RowResult ) { CDB_VarChar version; @@ -373,7 +389,7 @@ CConnection::SetDatabaseName(const string& name) if (!name.empty()) { const string sql = "use " + name; - auto_ptr auto_stmt(LangCmd(sql)); + unique_ptr auto_stmt(LangCmd(sql)); auto_stmt->Send(); auto_stmt->DumpResults(); @@ -400,13 +416,22 @@ string CConnection::GetDriverName(void) const void CConnection::x_RecordServer(const CDBServer& server) { + CMutexGuard mg(eEmptyGuard); string new_name = ServerName().substr(0, ServerName().find(':')) + '@' + server.GetName(); _TRACE("Updating server metadata from " << ServerName() << '@' << ConvertN2A(m_Host) << ':' << m_Port << " to " << new_name); + + if (m_Reusable) { + mg.Guard(m_DriverContext->m_PoolMutex); + m_DriverContext->x_AdjustCounts(this, -1); + } m_ExceptionContext->server_name = new_name; m_Host = server.GetHost(); m_Port = server.GetPort(); + if (m_Reusable) { + m_DriverContext->x_AdjustCounts(this, 1); + } } } // namespace impl diff --git a/c++/src/dbapi/driver/dbapi_impl_context.cpp b/c++/src/dbapi/driver/dbapi_impl_context.cpp index 7fabedb2..1ae200c1 100644 --- a/c++/src/dbapi/driver/dbapi_impl_context.cpp +++ b/c++/src/dbapi/driver/dbapi_impl_context.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_impl_context.cpp 516380 2016-10-13 11:32:10Z ivanov $ +/* $Id: dbapi_impl_context.cpp 548536 2017-10-16 15:16:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -301,14 +301,52 @@ void CDriverContext::x_Recycle(CConnection* conn, bool conn_reusable) } #endif } else { + x_AdjustCounts(conn, -1); delete conn; } CloseOldIdleConns(1); } + +void CDriverContext::x_AdjustCounts(const CConnection* conn, int delta) +{ + if (delta != 0 && conn->IsReusable()) { + CMutexGuard mg(m_PoolMutex); + string server_name = conn->GetServerName(); + if (conn->Host() != 0 && server_name.find('@') == NPOS) { + server_name += '@' + ConvertN2A(conn->Host()); + if (conn->Port() != 0) { + server_name += ':' + NStr::NumericToString(conn->Port()); + } + } + _DEBUG_ARG(unsigned int pool_count =) + m_CountsByPool[conn->PoolName()][server_name] += delta; + _DEBUG_ARG(unsigned int service_count =) + m_CountsByService[conn->GetRequestedServer()][server_name] += delta; + _TRACE(server_name << " count += " << delta << " for pool " + << conn->PoolName() << " (" << pool_count << ") and service " + << conn->GetRequestedServer() << " (" << service_count << ')'); + } +} + + +void CDriverContext::x_GetCounts(const TCountsMap& main_map, + const string& name, TCounts* counts) const +{ + CMutexGuard mg(m_PoolMutex); + auto it = main_map.find(name); + if (it == main_map.end()) { + counts->clear(); + } else { + *counts = it->second; + } +} + + void CDriverContext::CloseUnusedConnections(const string& srv_name, - const string& pool_name) + const string& pool_name, + unsigned int max_closings) { CMutexGuard mg(m_PoolMutex); @@ -325,7 +363,11 @@ void CDriverContext::CloseUnusedConnections(const string& srv_name, it = m_NotInUse.erase(it); --it; + x_AdjustCounts(con, -1); delete con; + if (--max_closings == 0) { + break; + } } } @@ -377,11 +419,13 @@ unsigned int CDriverContext::NofConnections(const string& srv_name, return NofConnections(svr_ref, pool_name); } -CDB_Connection* CDriverContext::MakeCDBConnection(CConnection* connection) +CDB_Connection* CDriverContext::MakeCDBConnection(CConnection* connection, + int delta) { connection->m_CleanupTime.Clear(); CMutexGuard mg(m_PoolMutex); m_InUse.push_back(connection); + x_AdjustCounts(connection, delta); return new CDB_Connection(connection); } @@ -420,19 +464,22 @@ CDriverContext::MakePooledConnection(const CDBConnParams& params) // pool contains connections with appropriate server names only. if (pool_name == t_con->PoolName()) { it = m_NotInUse.erase(it); - if(t_con->Refresh()) { + CDB_Connection* dbcon = MakeCDBConnection(t_con, 0); + if (dbcon->Refresh()) { /* Future development ... if (!params.GetDatabaseName().empty()) { - return SetDatabase(MakeCDBConnection(t_con), params); + return SetDatabase(dbcon, params); } else { - return MakeCDBConnection(t_con); + return dbcon; } */ - - return MakeCDBConnection(t_con); + + return dbcon; } else { - delete t_con; + x_AdjustCounts(t_con, -1); + t_con->m_Reusable = false; + delete dbcon; } } } @@ -450,19 +497,22 @@ CDriverContext::MakePooledConnection(const CDBConnParams& params) if (server_name == t_con->ServerName() || server_name == t_con->GetRequestedServer()) { it = m_NotInUse.erase(it); - if (t_con->Refresh()) { + CDB_Connection* dbcon = MakeCDBConnection(t_con, 0); + if (dbcon->Refresh()) { /* Future development ... if (!params.GetDatabaseName().empty()) { - return SetDatabase(MakeCDBConnection(t_con), params); + return SetDatabase(dbcon, params); } else { - return MakeCDBConnection(t_con); + return dbcon; } */ - return MakeCDBConnection(t_con); + return dbcon; } else { - delete t_con; + x_AdjustCounts(t_con, -1); + t_con->m_Reusable = false; + delete dbcon; } } } @@ -499,10 +549,11 @@ CDriverContext::MakePooledConnection(const CDBConnParams& params) t_con = m_PoolSemConn; m_PoolSemConn = NULL; m_NotInUse.erase((++it).base()); + break; } } if (t_con != NULL) { - return MakeCDBConnection(t_con); + return MakeCDBConnection(t_con, 0); } } else #endif @@ -545,7 +596,7 @@ CDriverContext::MakePooledConnection(const CDBConnParams& params) CConnection* t_con = MakeIConnection(params); - return MakeCDBConnection(t_con); + return MakeCDBConnection(t_con, 1); } void @@ -554,6 +605,7 @@ CDriverContext::CloseAllConn(void) CMutexGuard mg(m_PoolMutex); // close all connections first ITERATE(TConnPool, it, m_NotInUse) { + x_AdjustCounts(*it, -1); delete *it; } m_NotInUse.clear(); @@ -569,11 +621,13 @@ CDriverContext::DeleteAllConn(void) CMutexGuard mg(m_PoolMutex); // close all connections first ITERATE(TConnPool, it, m_NotInUse) { + x_AdjustCounts(*it, -1); delete *it; } m_NotInUse.clear(); ITERATE(TConnPool, it, m_InUse) { + x_AdjustCounts(*it, -1); delete *it; } m_InUse.clear(); @@ -850,6 +904,10 @@ CDriverContext::ReadDBConfParams(const string& service_name, params->pool_name.append(1, '.'); params->pool_name.append("pool"); } + if (reg.HasEntry(section_name, "conn_pool_name", IRegistry::fCountCleared)) { + // params->flags += SDBConfParams::fPoolNameSet; + params->pool_name = reg.Get(section_name, "conn_pool_name"); + } if (reg.HasEntry(section_name, "conn_pool_minsize", IRegistry::fCountCleared)) { params->flags += SDBConfParams::fPoolMinSizeSet; params->pool_minsize = reg.Get(section_name, "conn_pool_minsize"); @@ -1139,6 +1197,7 @@ void CDriverContext::CloseConnsForPool(const string& pool_name) CConnection* t_con(*it); if (t_con->IsReusable() && pool_name == t_con->PoolName()) { m_NotInUse.erase(it); + x_AdjustCounts(t_con, -1); delete t_con; } } @@ -1166,6 +1225,7 @@ void CDriverContext::CloseOldIdleConns(unsigned int max_closings, } unsigned int n = NofConnections(TSvrRef(), pool_name_2); if (n > (*it)->m_PoolMinSize) { + x_AdjustCounts(*it, -1); delete *it; m_NotInUse.erase(it); if (--max_closings == 0) { diff --git a/c++/src/dbapi/driver/dbapi_pool_balancer.cpp b/c++/src/dbapi/driver/dbapi_pool_balancer.cpp new file mode 100644 index 00000000..99ad9f2f --- /dev/null +++ b/c++/src/dbapi/driver/dbapi_pool_balancer.cpp @@ -0,0 +1,407 @@ +/* $Id: dbapi_pool_balancer.cpp 548536 2017-10-16 15:16:58Z ivanov $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Aaron Ucko +* +* File Description: +* Help distribute connections within a pool across servers. +* +* =========================================================================== +*/ + +#include + +#include "dbapi_pool_balancer.hpp" +#include +#include +#include + +#include +#include + +#define NCBI_USE_ERRCODE_X Dbapi_PoolBalancer + +BEGIN_NCBI_SCOPE + +DEFINE_STATIC_FAST_MUTEX(s_RandomMutex); +static CSafeStatic s_RandomEngine; +static bool s_RandomnessSeeded; + +class CRandomGuard +{ +public: + CRandomGuard() + : m_MutexGuard(s_RandomMutex) + { + if ( !s_RandomnessSeeded ) { + random_device rdev; + s_RandomEngine->seed(rdev()); + s_RandomnessSeeded = true; + } + } + +private: + CFastMutexGuard m_MutexGuard; +}; + + +class CDBConnParams_DNC : public CDBConnParamsDelegate +{ +public: + CDBConnParams_DNC(const CDBConnParams& other) + : CDBConnParamsDelegate(other) + { } + + string GetParam(const string& key) const + { + if (key == "do_not_connect") { + return "true"; + } else { + return CDBConnParamsDelegate::GetParam(key); + } + } +}; + + + +CDBPoolBalancer::CDBPoolBalancer(const string& service_name, + const string& pool_name, + I_DriverContext& driver_ctx, + const IDBServiceMapper::TOptions& options) + : m_DriverCtx(driver_ctx), m_TotalCount(0U) +{ + bool is_ftds = NStr::StartsWith(driver_ctx.GetDriverName(), "ftds"); + for (auto it : options) { + CTempString name = it->GetName(); + auto key = impl::MakeEndpointKey(it->GetHost(), it->GetPort()); + if (key == 0 && name != service_name) { + key = x_NameToKey(name); + if (key != 0) { + if ( !is_ftds && name == it->GetName() ) { + continue; + } + it.Reset(new CDBServerOption(name, impl::GetHost(key), + impl::GetPort(key), + it->GetRanking(), it->GetState(), + it->GetExpireTime())); + } + } + _TRACE(service_name << ": " << key << " -> " << name << " per DBLB"); + auto& endpoint = m_Endpoints[key]; + double ranking = it->GetRanking(); + + if (it->IsPenalized()) { + ranking *= numeric_limits::epsilon(); + ++endpoint.penalty_level; + } + if (it->IsExcluded()) { + ranking *= numeric_limits::epsilon(); + ++endpoint.penalty_level; + } + + endpoint.ref = it; + endpoint.effective_ranking = ranking; + m_Rankings.insert(ranking); + } + + const impl::CDriverContext* ctx_impl + = dynamic_cast(&driver_ctx); + impl::CDriverContext::TCounts counts; + if (ctx_impl == NULL) { + ERR_POST_X(1, Warning << "Called with non-standard IDriverContext"); + } else if (pool_name.empty()) { + ctx_impl->GetCountsForService(service_name, &counts); + } else { + ctx_impl->GetCountsForPool(pool_name, &counts); + } + + for (const auto& cit : counts) { + if (cit.second == 0) { + continue; + } + CTempString name = cit.first; + auto key = x_NameToKey(name); + auto eit = m_Endpoints.lower_bound(key); + CTime exp(CTime::eEmpty, CTime::eUTC); + if ((eit == m_Endpoints.end() + || impl::GetHost(key) != impl::GetHost(eit->first) + || (impl::GetPort(key) != 0 + && impl::GetPort(key) != impl::GetPort(eit->first))) + && (is_ftds || key == 0 || name != cit.first)) { + _TRACE(service_name << ": " << key << " -> " << name + << " per existing connection(s)"); + eit = m_Endpoints.insert(eit, make_pair(key, SEndpointInfo())); + } + if ( eit != m_Endpoints.end() ) { + auto& endpoint = eit->second; + if (endpoint.ref.Empty()) { + static const double kRanking = numeric_limits::min(); + if (exp.IsEmpty()) { + exp.SetCurrent(); + exp.AddSecond(10); + } + endpoint.ref.Reset(new CDBServerOption + (name, impl::GetHost(key), + impl::GetPort(key), kRanking, + CDBServerOption::fState_Normal, + exp.GetTimeT())); + m_Rankings.insert(kRanking); + endpoint.effective_ranking = kRanking; + } + endpoint.actual_count += cit.second; + } + m_TotalCount += cit.second; + } +} + +TSvrRef CDBPoolBalancer::GetServer(CDB_Connection** conn, + const CDBConnParams& params) +{ + TSvrRef result; + impl::TEndpointKey conn_key = 0; + + // trivial if <= 1 endpoint + if (m_Endpoints.empty()) { + return result; + } else if (m_Endpoints.size() == 1) { + return TSvrRef(&*m_Endpoints.begin()->second.ref); + } + + double total_ranking = accumulate(m_Rankings.begin(), m_Rankings.end(), + 0.0); + if (total_ranking <= 0.0) { + ERR_POST_X(2, Info << "No positive rankings found"); + return result; + } + + if (/* m_TotalCount > 1 && */ conn != NULL) { + string pool_name = params.GetParam("pool_name"); + CDBConnParams_DNC dnc_params(params); + *conn = IDBConnectionFactory::CtxMakeConnection(m_DriverCtx, + dnc_params); + if (*conn != NULL) { + const string& server_name = (*conn)->ServerName(); + Uint4 host = (*conn)->Host(); + Uint2 port = (*conn)->Port(); + double excess; + bool keep = true; + conn_key = impl::MakeEndpointKey(host, port); + auto it = m_Endpoints.find(conn_key); + if (it == m_Endpoints.end()) { + ERR_POST_X(3, + "Unrecognized endpoint for existing connection to " + << impl::ConvertN2A(host) << ":" << port + << " (" << server_name << ')'); + excess = m_DriverCtx.NofConnections(server_name, pool_name); + result.Reset(&*it->second.ref); + } else { + double scale_factor = m_TotalCount / total_ranking; + excess = (it->second.actual_count + - it->second.effective_ranking * scale_factor); + time_t t = CurrentTime(CTime::eUTC).GetTimeT() + 10; + result.Reset(new CDBServer(server_name, host, port, t)); + } + _TRACE("Considering connection to " << impl::ConvertN2A(host) + << ":" << port << " (" << server_name + << ") for turnover; projected excess count " << excess); + if (excess > 0.0) { + string pool_max_str = params.GetParam("pool_maxsize"); + unsigned int pool_max = 0u; + if ( !pool_max_str.empty() && pool_max_str != "default") { + NStr::StringToNumeric(pool_max_str, &pool_max, + NStr::fConvErr_NoThrow); + } + if (pool_max == 0u) { + pool_max = m_TotalCount * 2; + } + CRandomGuard rg; + uniform_real_distribution urd(0.0, pool_max); + if (urd(*s_RandomEngine) <= excess) { + // defer turnover (endpoint may be reselected!) but + // speculatively update counts + keep = false; + --m_TotalCount; + if (it != m_Endpoints.end()) { + --it->second.actual_count; + } + } + } + if (keep) { + _TRACE("Sparing connection immediately"); + return result; + } + } + } + + vector options; + vector weights; + double scale_factor = (m_TotalCount + 1.0) / total_ranking; + _TRACE("Scale factor for new connection: " << (m_TotalCount + 1) << " / " + << total_ranking << " = " << scale_factor); + + for (auto& it : m_Endpoints) { + it.second.ideal_count = it.second.effective_ranking * scale_factor; + double d = it.second.ideal_count - it.second.actual_count; + _TRACE(it.first << " (" << it.second.ref->GetName() + << "): current count " << it.second.actual_count + << ", ideal count " << it.second.ideal_count << ", delta " << d + << (d > 0 ? " > 0" : " <= 0")); + if (d > 0) { + options.push_back(&it); + weights.push_back(d); + } + } + if (weights.empty()) { + ERR_POST_X(4, "No positive deltas"); + return result; + } + + CRandomGuard rg; +#if defined(NCBI_COMPILER_MSVC) && _MSC_VER < 1900 + // Work around limitation in VS 2013's discrete_distribution<> + // mitigated by a non-standard initializer_list<> constructor. + discrete_distribution<> dd( + initializer_list( + weights.data(), weights.data() + weights.size())); +#else + discrete_distribution<> dd(weights.begin(), weights.end()); +#endif + auto i = dd(*s_RandomEngine); + _TRACE("Picked " << options[i]->first << " (" + << options[i]->second.ref->GetName() << ')'); + if (conn != NULL && *conn != NULL) { + if (conn_key == options[i]->first) { + _TRACE("Sparing connection (endpoint reselected)"); + ++options[i]->second.actual_count; + ++m_TotalCount; + } else { + _TRACE("Proceeding to request turnover"); + const string& server_name = (*conn)->ServerName(); + bool was_reusable = (*conn)->IsReusable(); + delete *conn; + *conn = NULL; + if (was_reusable) { + // This call might not close the exact connection we + // considered, but closing any connection to the + // relevant server is sufficient here. + m_DriverCtx.CloseUnusedConnections + (server_name, params.GetParam("pool_name"), 1u); + } + } + } + // Penalize in case we have to retry + m_Rankings.erase(m_Rankings.find(options[i]->second.effective_ranking)); + ++options[i]->second.penalty_level; + options[i]->second.effective_ranking *= numeric_limits::epsilon(); + m_Rankings.insert(options[i]->second.effective_ranking); + return TSvrRef(&*options[i]->second.ref); +} + +impl::TEndpointKey CDBPoolBalancer::x_NameToKey(CTempString& name) const +{ + _TRACE(name); + CTempString address = name; + SIZE_TYPE pos = name.find_last_not_of("0123456789.:"); + if (pos != NPOS) { + if (name[pos] == '@') { + address = name.substr(pos + 1); + name = name.substr(0, pos); + } else { + for (const auto& it : m_Endpoints) { + if (it.first > 0 && it.second.ref->GetName() == name) { + _TRACE("Found at " << it.first); + return it.first; + } + } + return 0; + } + } + Uint2 port = 0; + pos = address.find(':'); + if (pos != NPOS) { + if ( !NStr::StringToNumeric(address.substr(pos + 1), &port, + NStr::fConvErr_NoThrow) ) { + ERR_POST_X(5, "Bad port number " << port); + return 0; + } + address = address.substr(0, pos); + } + union { // to help produce network byte order + Uint4 i; + Uint1 c[4]; + } host = { 0, }; +#if 0 // slow + vector v; + NStr::Split(address, ".", v); // slow :-/ + if (v.size() != 4) { + ERR_POST_X(6, "Wrong number of components in IP address " << address); + return 0; + } + for (int i = 0; i < 4; ++i) { + if ( !NStr::StringToNumeric(v[i], &host.c[i], + NStr::fConvErr_NoThrow) ) { + ERR_POST_X(7, "Bad IP address component " << v[i]); + return 0; + } + } +#else + if (count(address.begin(), address.end(), '.') != 3) { + ERR_POST_X(6, "Wrong number of components in IP address " << address); + return 0; + } + for (int i = 0; i < 4; ++i) { + CTempString component; + switch (i) { + case 0: + pos = address.find('.'); + component = address.substr(0, pos); + break; + case 1: case 2: + { + SIZE_TYPE pos2 = address.find('.', pos + 1); + component = address.substr(pos + 1, pos2 - pos - 1); + pos = pos2; + break; + } + case 3: + component = address.substr(pos + 1); + break; + default: + _TROUBLE; + } + if ( !NStr::StringToNumeric(component, &host.c[i], + NStr::fConvErr_NoThrow) ) { + ERR_POST_X(7, "Bad IP address component " << component); + return 0; + } + + } +#endif + _TRACE(impl::ConvertN2A(host.i) << ":" << port); + return impl::MakeEndpointKey(host.i, port); +} + + +END_NCBI_SCOPE diff --git a/c++/src/dbapi/driver/dbapi_pool_balancer.hpp b/c++/src/dbapi/driver/dbapi_pool_balancer.hpp new file mode 100644 index 00000000..8c5c15ba --- /dev/null +++ b/c++/src/dbapi/driver/dbapi_pool_balancer.hpp @@ -0,0 +1,82 @@ +#ifndef DBAPI_DRIVER___DBAPI_POOL_BALANCER__HPP +#define DBAPI_DRIVER___DBAPI_POOL_BALANCER__HPP + +/* $Id: dbapi_pool_balancer.hpp 548536 2017-10-16 15:16:58Z ivanov $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Aaron Ucko + * + */ + +/// @file dbapi_pool_balancer.hpp +/// Help distribute connections within a pool across servers. + +#include + +/** @addtogroup DBAPI + * + * @{ + */ + +BEGIN_NCBI_SCOPE + +class CDBPoolBalancer : public CObject +{ +public: + CDBPoolBalancer(const string& service_name, + const string& pool_name, + I_DriverContext& driver_ctx, + const IDBServiceMapper::TOptions& options); + + TSvrRef GetServer(CDB_Connection** conn, const CDBConnParams& params); + +private: + struct SEndpointInfo { + SEndpointInfo() + : effective_ranking(0.0), ideal_count(0.0), actual_count(0U), + penalty_level(0U) + { } + + CRef ref; + double effective_ranking; + double ideal_count; + unsigned int actual_count; + unsigned int penalty_level; + }; + typedef map TEndpoints; + + impl::TEndpointKey x_NameToKey(CTempString& name) const; + + TEndpoints m_Endpoints; + multiset m_Rankings; + I_DriverContext& m_DriverCtx; + unsigned int m_TotalCount; +}; + +END_NCBI_SCOPE + +/* @} */ + +#endif /* DBAPI_DRIVER___DBAPI_POOL_BALANCER__HPP */ diff --git a/c++/src/dbapi/driver/dbapi_svc_mapper.cpp b/c++/src/dbapi/driver/dbapi_svc_mapper.cpp index 7b2fa0ad..bdec0f92 100644 --- a/c++/src/dbapi/driver/dbapi_svc_mapper.cpp +++ b/c++/src/dbapi/driver/dbapi_svc_mapper.cpp @@ -1,4 +1,4 @@ -/* $Id: dbapi_svc_mapper.cpp 506715 2016-07-11 16:01:42Z ucko $ +/* $Id: dbapi_svc_mapper.cpp 548536 2017-10-16 15:16:58Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -253,6 +253,18 @@ CDBServiceMapperCoR::GetServersList(const string& service, list* serv_li } } +void +CDBServiceMapperCoR::GetServerOptions(const string& service, TOptions* options) +{ + CFastMutexGuard mg(m_Mtx); + + TDelegates::reverse_iterator dg_it = m_Delegates.rbegin(); + TDelegates::reverse_iterator dg_end = m_Delegates.rend(); + for (; options->empty() && dg_it != dg_end; ++dg_it) { + (*dg_it)->GetServerOptions(service, options); + } +} + bool CDBServiceMapperCoR::RecordServer(I_ConnectionExtra& extra) const diff --git a/c++/src/dbapi/driver/driver_mgr.cpp b/c++/src/dbapi/driver/driver_mgr.cpp index fad3d348..560dea74 100644 --- a/c++/src/dbapi/driver/driver_mgr.cpp +++ b/c++/src/dbapi/driver/driver_mgr.cpp @@ -1,4 +1,4 @@ -/* $Id: driver_mgr.cpp 403742 2013-06-18 15:26:09Z grichenk $ +/* $Id: driver_mgr.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -67,7 +67,7 @@ MakePluginManagerParamTree(const string& driver_name, const map* TPluginManagerParamTree* MakePluginManagerParamTree(const CDBConnParams& params) { - auto_ptr tr(new TPluginManagerParamTree); + unique_ptr tr(new TPluginManagerParamTree); tr->GetKey() = params.GetDriverName(); @@ -279,7 +279,7 @@ C_xDriverMgr::GetDriverContext( const string& driver_name, const map* attr) { - auto_ptr pt; + unique_ptr pt; const TPluginManagerParamTree* nd = NULL; if ( attr != NULL ) { @@ -372,7 +372,7 @@ Get_I_DriverContext(const string& driver_name, const map* attr) _ASSERT(ReaderManager); try { - auto_ptr pt; + unique_ptr pt; if ( attr != NULL ) { pt.reset( MakePluginManagerParamTree(driver_name, attr) ); @@ -412,7 +412,7 @@ I_DriverContext* MakeDriverContext(const CDBConnParams& params) _ASSERT(ReaderManager); try { - auto_ptr pt; + unique_ptr pt; pt.reset(MakePluginManagerParamTree(params)); _ASSERT( pt.get() ); diff --git a/c++/src/dbapi/driver/exception.cpp b/c++/src/dbapi/driver/exception.cpp index 659547b3..614389af 100644 --- a/c++/src/dbapi/driver/exception.cpp +++ b/c++/src/dbapi/driver/exception.cpp @@ -1,4 +1,4 @@ -/* $Id: exception.cpp 451134 2014-11-03 21:52:05Z ucko $ +/* $Id: exception.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -634,7 +634,7 @@ bool CDB_UserHandler::HandleAll(const TExceptions& /* exceptions */) return false; } -bool CDB_UserHandler::x_HandleAll(const TExceptions& exceptions) +bool CDB_UserHandler::x_HandleAll(const TExceptions& /* exceptions */) { #if 1 return false; @@ -913,7 +913,7 @@ void CDB_UserHandler_Deferred::Flush(EDiagSev max_severity) { CFastMutexGuard LOCK(m_Mutex); ERASE_ITERATE (TExceptions, it, m_SavedExceptions) { - auto_ptr ex(*it); + unique_ptr ex(*it); VECTOR_ERASE(it, m_SavedExceptions); if (ex->GetSeverity() > max_severity) { ex->SetSeverity(max_severity); diff --git a/c++/src/dbapi/driver/ncbi_win_hook.cpp b/c++/src/dbapi/driver/ncbi_win_hook.cpp index a6927379..27c71edc 100644 --- a/c++/src/dbapi/driver/ncbi_win_hook.cpp +++ b/c++/src/dbapi/driver/ncbi_win_hook.cpp @@ -1,4 +1,4 @@ -/* $Id: ncbi_win_hook.cpp 403742 2013-06-18 15:26:09Z grichenk $ +/* $Id: ncbi_win_hook.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -113,7 +113,7 @@ namespace NWinHook } protected: - auto_ptr m_pProcess; + unique_ptr m_pProcess; }; //////////////////////////////////////////////////////////////////////////// diff --git a/c++/src/dbapi/driver/odbc/CMakeLists.ncbi_xdbapi_odbc.lib.txt b/c++/src/dbapi/driver/odbc/CMakeLists.ncbi_xdbapi_odbc.lib.txt new file mode 100644 index 00000000..8cf2c7df --- /dev/null +++ b/c++/src/dbapi/driver/odbc/CMakeLists.ncbi_xdbapi_odbc.lib.txt @@ -0,0 +1,11 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/dbapi/driver/odbc/Makefile.ncbi_xdbapi_odbc.lib +# +add_library(ncbi_xdbapi_odbc + connection context cursor lang_cmd result rpc odbc_utils +) +include_directories(SYSTEM ${ODBC_INCLUDE}) + +target_link_libraries(ncbi_xdbapi_odbc + dbapi_driver ${ODBC_LIBS} +) diff --git a/c++/src/dbapi/driver/odbc/CMakeLists.txt b/c++/src/dbapi/driver/odbc/CMakeLists.txt new file mode 100644 index 00000000..283cd15e --- /dev/null +++ b/c++/src/dbapi/driver/odbc/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.ncbi_xdbapi_odbc.lib.txt) + +# Recurse subdirectories +add_subdirectory(samples) diff --git a/c++/src/dbapi/driver/odbc/context.cpp b/c++/src/dbapi/driver/odbc/context.cpp index 9d412276..594a231a 100644 --- a/c++/src/dbapi/driver/odbc/context.cpp +++ b/c++/src/dbapi/driver/odbc/context.cpp @@ -1,4 +1,4 @@ -/* $Id: context.cpp 450236 2014-10-23 18:15:34Z ucko $ +/* $Id: context.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -517,7 +517,7 @@ CDbapiOdbcCFBase::CreateInstance( CVersionInfo version, const TPluginManagerParamTree* params) const { - auto_ptr drv; + unique_ptr drv; if ( !driver.empty() && driver != m_DriverName ) { return 0; diff --git a/c++/src/dbapi/driver/odbc/cursor.cpp b/c++/src/dbapi/driver/odbc/cursor.cpp index a27fb3a3..d26d219e 100644 --- a/c++/src/dbapi/driver/odbc/cursor.cpp +++ b/c++/src/dbapi/driver/odbc/cursor.cpp @@ -1,4 +1,4 @@ -/* $Id: cursor.cpp 498292 2016-04-14 19:07:55Z ucko $ +/* $Id: cursor.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -137,7 +137,7 @@ bool CODBC_CursorCmd::Update(const string&, const string& upd_query) try { string buff = upd_query + " where current of " + GetCmdName(); - auto_ptr cmd( GetConnection().LangCmd(buff) ); + unique_ptr cmd( GetConnection().LangCmd(buff) ); cmd->Send(); cmd->DumpResults(); } catch (const CDB_Exception& e) { @@ -164,7 +164,7 @@ bool CODBC_CursorCmd::UpdateBlob(unsigned int item_num, CDB_Stream& data, { CDB_BlobDescriptor* desc = x_GetBlobDescriptor(item_num); if(desc == 0) return false; - auto_ptr g((I_BlobDescriptor*)desc); + unique_ptr g((I_BlobDescriptor*)desc); return GetConnection().SendData(*desc, data, log_it); } @@ -175,7 +175,7 @@ CDB_SendDataCmd* CODBC_CursorCmd::SendDataCmd(unsigned int item_num, size_t size { CDB_BlobDescriptor* desc = x_GetBlobDescriptor(item_num); if(desc == 0) return 0; - auto_ptr g((I_BlobDescriptor*)desc); + unique_ptr g((I_BlobDescriptor*)desc); return GetConnection().SendDataCmd((I_BlobDescriptor&)*desc, size, log_it, dump_results); @@ -189,7 +189,7 @@ bool CODBC_CursorCmd::Delete(const string& table_name) try { string buff = "delete " + table_name + " where current of " + GetCmdName(); - auto_ptr cmd(GetConnection().LangCmd(buff)); + unique_ptr cmd(GetConnection().LangCmd(buff)); cmd->Send(); cmd->DumpResults(); } catch (const CDB_Exception& e) { @@ -275,7 +275,7 @@ CDB_Result* CODBC_CursorCmdExpl::OpenCursor(void) SetCursorDeclared(); try { - auto_ptr stmt(GetConnection().xLangCmd("open " + GetCmdName())); + unique_ptr stmt(GetConnection().xLangCmd("open " + GetCmdName())); stmt->Send(); stmt->DumpResults(); @@ -304,7 +304,7 @@ bool CODBC_CursorCmdExpl::Update(const string&, const string& upd_query) string buff = upd_query + " where current of " + GetCmdName(); - auto_ptr cmd( GetConnection().LangCmd(buff) ); + unique_ptr cmd( GetConnection().LangCmd(buff) ); cmd->Send(); cmd->DumpResults(); } catch (const CDB_Exception& e) { @@ -332,7 +332,7 @@ bool CODBC_CursorCmdExpl::UpdateBlob(unsigned int item_num, CDB_Stream& data, { CDB_BlobDescriptor* desc = x_GetBlobDescriptor(item_num); if(desc == 0) return false; - auto_ptr g((I_BlobDescriptor*)desc); + unique_ptr g((I_BlobDescriptor*)desc); m_LCmd->Cancel(); @@ -345,7 +345,7 @@ CDB_SendDataCmd* CODBC_CursorCmdExpl::SendDataCmd(unsigned int item_num, size_t { CDB_BlobDescriptor* desc = x_GetBlobDescriptor(item_num); if(desc == 0) return 0; - auto_ptr g((I_BlobDescriptor*)desc); + unique_ptr g((I_BlobDescriptor*)desc); m_LCmd->Cancel(); @@ -363,7 +363,7 @@ bool CODBC_CursorCmdExpl::Delete(const string& table_name) string buff = "delete " + table_name + " where current of " + GetCmdName(); - auto_ptr cmd(GetConnection().LangCmd(buff)); + unique_ptr cmd(GetConnection().LangCmd(buff)); cmd->Send(); cmd->DumpResults(); } catch (const CDB_Exception& e) { @@ -386,7 +386,7 @@ bool CODBC_CursorCmdExpl::CloseCursor() if (CursorIsOpen()) { string buff = "close " + GetCmdName(); try { - auto_ptr cmd(GetConnection().xLangCmd(buff)); + unique_ptr cmd(GetConnection().xLangCmd(buff)); cmd->Send(); cmd->DumpResults(); @@ -402,7 +402,7 @@ bool CODBC_CursorCmdExpl::CloseCursor() string buff = "deallocate " + GetCmdName(); try { - auto_ptr cmd(GetConnection().xLangCmd(buff)); + unique_ptr cmd(GetConnection().xLangCmd(buff)); cmd->Send(); cmd->DumpResults(); diff --git a/c++/src/dbapi/driver/parameters.cpp b/c++/src/dbapi/driver/parameters.cpp index 154e81c2..073a2a0e 100644 --- a/c++/src/dbapi/driver/parameters.cpp +++ b/c++/src/dbapi/driver/parameters.cpp @@ -1,4 +1,4 @@ -/* $Id: parameters.cpp 487444 2015-12-17 18:38:53Z ucko $ +/* $Id: parameters.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -168,7 +168,7 @@ bool CDB_Params::SetParam(unsigned int param_no, const string& param_name, CDB_Params* CDB_Params::SemiShallowClone(void) const { - auto_ptr result(new CDB_Params); + unique_ptr result(new CDB_Params); SParam empty_param; ITERATE (deque, it, m_Params) { result->m_Params.push_back(empty_param); diff --git a/c++/src/dbapi/driver/public.cpp b/c++/src/dbapi/driver/public.cpp index 258f9a2d..f11057af 100644 --- a/c++/src/dbapi/driver/public.cpp +++ b/c++/src/dbapi/driver/public.cpp @@ -1,4 +1,4 @@ -/* $Id: public.cpp 497635 2016-04-08 13:52:30Z ucko $ +/* $Id: public.cpp 537459 2017-05-31 19:16:31Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -293,9 +293,14 @@ bool CDB_Connection::IsAlive() { if (m_ConnImpl == NULL || !m_ConnImpl->IsAlive()) { return false; + } else { + return x_IsAlive(); } +} - // Otherwise, try to confirm that the network connection hasn't closed. +bool CDB_Connection::x_IsAlive() +{ + // Try to confirm that the network connection hasn't closed. // (Done only when no separate network library is necessary.) // XXX - consider caching GetLowLevelHandle result, or at least // availability. @@ -409,7 +414,7 @@ void CDB_Connection::SetDatabaseName(const string& name) bool CDB_Connection::Refresh() { CHECK_CONNECTION(m_ConnImpl); - return m_ConnImpl->Refresh(); + return m_ConnImpl->Refresh() && x_IsAlive(); } const string& CDB_Connection::ServerName() const @@ -522,6 +527,15 @@ bool CDB_Connection::Abort() bool CDB_Connection::Close(void) { CHECK_CONNECTION(m_ConnImpl); + if (m_ConnImpl->IsReusable() && m_ConnImpl->IsAlive() && x_IsAlive() + && m_ConnImpl->GetServerType() != CDBConnParams::eSybaseOpenServer) { + unique_ptr lcmd(LangCmd("IF @@TRANCOUNT > 0 ROLLBACK")); + lcmd->Send(); + try { + lcmd->DumpResults(); + } catch (CDB_Exception&) { + } + } m_ConnImpl->Release(); m_ConnImpl = NULL; return true; @@ -1246,7 +1260,7 @@ CAutoTrans::CAutoTrans(const CSubject& subject) if (m_TranCount > 1) { m_SavepointName = "ncbi_dbapi_txn_" + NStr::NumericToString(reinterpret_cast(this), 0, 16); - auto_ptr auto_stmt + unique_ptr auto_stmt (m_Conn.LangCmd("SAVE TRANSACTION " + m_SavepointName)); auto_stmt->Send(); auto_stmt->DumpResults(); @@ -1286,7 +1300,7 @@ void CAutoTrans::BeginTransaction(void) { m_Conn.m_HasTransaction = true; - auto_ptr auto_stmt(m_Conn.LangCmd("BEGIN TRANSACTION")); + unique_ptr auto_stmt(m_Conn.LangCmd("BEGIN TRANSACTION")); auto_stmt->Send(); auto_stmt->DumpResults(); } @@ -1295,7 +1309,7 @@ CAutoTrans::BeginTransaction(void) void CAutoTrans::Commit(void) { - auto_ptr auto_stmt(m_Conn.LangCmd("COMMIT")); + unique_ptr auto_stmt(m_Conn.LangCmd("COMMIT")); auto_stmt->Send(); auto_stmt->DumpResults(); } @@ -1304,7 +1318,7 @@ CAutoTrans::Commit(void) void CAutoTrans::Rollback(void) { - auto_ptr auto_stmt + unique_ptr auto_stmt (m_Conn.LangCmd("ROLLBACK TRANSACTION " + m_SavepointName)); auto_stmt->Send(); auto_stmt->DumpResults(); @@ -1322,11 +1336,11 @@ int CAutoTrans::GetTranCount(void) { int result = 0; - auto_ptr auto_stmt(m_Conn.LangCmd("SELECT @@trancount as tc")); + unique_ptr auto_stmt(m_Conn.LangCmd("SELECT @@trancount as tc")); if (auto_stmt->Send()) { while(auto_stmt->HasMoreResults()) { - auto_ptr rs(auto_stmt->Result()); + unique_ptr rs(auto_stmt->Result()); if (rs.get() == NULL) { continue; diff --git a/c++/src/dbapi/err_handler.hpp b/c++/src/dbapi/err_handler.hpp index 79fa4bf2..8d88e12c 100644 --- a/c++/src/dbapi/err_handler.hpp +++ b/c++/src/dbapi/err_handler.hpp @@ -1,7 +1,7 @@ #ifndef _ERROR_HANDLER_HPP_ #define _ERROR_HANDLER_HPP_ -/* $Id: err_handler.hpp 343796 2011-11-09 18:12:57Z ivanovp $ +/* $Id: err_handler.hpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -26,7 +26,7 @@ * * =========================================================================== * -* File Name: $Id: err_handler.hpp 343796 2011-11-09 18:12:57Z ivanovp $ +* File Name: $Id: err_handler.hpp 535289 2017-05-08 13:38:35Z ivanov $ * * Author: Michael Kholodov * @@ -57,7 +57,7 @@ public: } private: - auto_ptr m_ex; + unique_ptr m_ex; }; END_NCBI_SCOPE diff --git a/c++/src/dbapi/rs_impl.cpp b/c++/src/dbapi/rs_impl.cpp index 59770e08..81f46948 100644 --- a/c++/src/dbapi/rs_impl.cpp +++ b/c++/src/dbapi/rs_impl.cpp @@ -1,4 +1,4 @@ -/* $Id: rs_impl.cpp 498292 2016-04-14 19:07:55Z ucko $ +/* $Id: rs_impl.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -23,7 +23,7 @@ * * =========================================================================== * -* File Name: $Id: rs_impl.cpp 498292 2016-04-14 19:07:55Z ucko $ +* File Name: $Id: rs_impl.cpp 535289 2017-05-08 13:38:35Z ivanov $ * * Author: Michael Kholodov * @@ -366,7 +366,7 @@ CNcbiOstream& CResultSet::xGetBlobOStream(CDB_Connection *cdb_conn, m_rs->ReadItem(0, 0); - auto_ptr desc(m_rs->GetBlobDescriptor()); + unique_ptr desc(m_rs->GetBlobDescriptor()); if(desc.get() == NULL) { #ifdef _DEBUG NcbiCerr << "CResultSet::GetBlobOStream(): zero IT Descriptor" << endl; diff --git a/c++/src/dbapi/rw_impl.hpp b/c++/src/dbapi/rw_impl.hpp index 2ccbe88d..3d57ba88 100644 --- a/c++/src/dbapi/rw_impl.hpp +++ b/c++/src/dbapi/rw_impl.hpp @@ -1,7 +1,7 @@ #ifndef _RW_IMPL_HPP_ #define _RW_IMPL_HPP_ -/* $Id: rw_impl.hpp 497635 2016-04-08 13:52:30Z ucko $ +/* $Id: rw_impl.hpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -90,7 +90,7 @@ private: CDB_SendDataCmd *m_dataCmd; bool m_destroy; CDB_Connection *m_cdbConn; - auto_ptr m_AutoTrans; + unique_ptr m_AutoTrans; size_t m_BytesNeeded; }; diff --git a/c++/src/dbapi/stmt_impl.cpp b/c++/src/dbapi/stmt_impl.cpp index 4f468ca7..eb4c1103 100644 --- a/c++/src/dbapi/stmt_impl.cpp +++ b/c++/src/dbapi/stmt_impl.cpp @@ -1,4 +1,4 @@ -/* $Id: stmt_impl.cpp 497635 2016-04-08 13:52:30Z ucko $ +/* $Id: stmt_impl.cpp 535289 2017-05-08 13:38:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -23,7 +23,7 @@ * * =========================================================================== * -* File Name: $Id: stmt_impl.cpp 497635 2016-04-08 13:52:30Z ucko $ +* File Name: $Id: stmt_impl.cpp 535289 2017-05-08 13:38:35Z ivanov $ * * Author: Michael Kholodov * @@ -364,7 +364,7 @@ void CStatement::PurgeResults() while (HasMoreResults()) { if (HasRows()) { - auto_ptr rs( GetResultSet() ); + unique_ptr rs( GetResultSet() ); if (rs.get()) { // Is it necessary??? while (rs->Next()) { diff --git a/c++/src/html/CMakeLists.html.lib.txt b/c++/src/html/CMakeLists.html.lib.txt new file mode 100644 index 00000000..d7e64913 --- /dev/null +++ b/c++/src/html/CMakeLists.html.lib.txt @@ -0,0 +1,11 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/html/Makefile.html.lib +# +add_library(xhtml + node html htmlhelper page pager selection components commentdiag + indentstream html_exception writer_htmlenc +) + +target_link_libraries(xhtml + xncbi +) diff --git a/c++/src/html/CMakeLists.txt b/c++/src/html/CMakeLists.txt new file mode 100644 index 00000000..9ff6b253 --- /dev/null +++ b/c++/src/html/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.html.lib.txt) + +# Recurse subdirectories +add_subdirectory(test ) +add_subdirectory(demo ) diff --git a/c++/src/html/page.cpp b/c++/src/html/page.cpp index 77ef4ea6..caf013d3 100644 --- a/c++/src/html/page.cpp +++ b/c++/src/html/page.cpp @@ -1,4 +1,4 @@ -/* $Id: page.cpp 415994 2013-10-23 12:49:27Z ivanov $ +/* $Id: page.cpp 534860 2017-05-03 12:47:52Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -350,7 +350,7 @@ CNCBINode* CHTMLPage::CreateTemplate(CNcbiOstream* out, CNCBINode::TMode mode) // Print and return node {{ - auto_ptr node(new CHTMLText(*pstr)); + unique_ptr node(new CHTMLText(*pstr)); if ( out ) { node->Print(*out, mode); } @@ -421,7 +421,7 @@ CNCBINode* CHTMLPage::x_PrintTemplate(CNcbiIstream& is, CNcbiOstream* out, string str; char buf[kBufferSize]; - auto_ptr node(new CNCBINode); + unique_ptr node(new CNCBINode); while (is) { is.read(buf, sizeof(buf)); diff --git a/c++/src/misc/CMakeLists.txt b/c++/src/misc/CMakeLists.txt index 087ff6aa..f62b54fe 100644 --- a/c++/src/misc/CMakeLists.txt +++ b/c++/src/misc/CMakeLists.txt @@ -12,7 +12,6 @@ add_subdirectory_optional(grid_cgi) add_subdirectory_optional(xmlwrapp) add_subdirectory_optional(eutils_client) add_subdirectory_optional(hydra_client) -add_subdirectory_optional(discrepancy_report) add_subdirectory_optional(discrepancy) add_subdirectory_optional(xmlreaders) add_subdirectory_optional(hgvs) @@ -20,3 +19,7 @@ add_subdirectory_optional(netstorage) add_subdirectory_optional(jsonwrapp) add_subdirectory_optional(biosample_util) add_subdirectory_optional(data_loaders_util) + +if (LAPACK_FOUND) + add_subdirectory_optional(lapackwrapp) +endif() diff --git a/c++/src/misc/Makefile.in b/c++/src/misc/Makefile.in index 933d731b..bc6e7cab 100644 --- a/c++/src/misc/Makefile.in +++ b/c++/src/misc/Makefile.in @@ -1,9 +1,10 @@ -# $Id: Makefile.in 506528 2016-07-08 11:48:54Z dicuccio $ +# $Id: Makefile.in 542115 2017-07-26 15:20:27Z ucko $ SUB_PROJ = third_party third_party_static clog grid_cgi xmlwrapp \ - eutils_client hydra_client discrepancy_report discrepancy xmlreaders \ + eutils_client hydra_client discrepancy xmlreaders \ hgvs netstorage jsonwrapp biosample_util \ - data_loaders_util lapackwrapp + data_loaders_util lapackwrapp pmcidconv_client \ + grpc_integration EXPENDABLE_SUB_PROJ = cgi_redirect srcdir = @srcdir@ diff --git a/c++/src/misc/third_party/CMakeLists.txt b/c++/src/misc/third_party/CMakeLists.txt index de7e2243..4644f8d1 100644 --- a/c++/src/misc/third_party/CMakeLists.txt +++ b/c++/src/misc/third_party/CMakeLists.txt @@ -1,5 +1,5 @@ ############################################################################## -# CMakeLists.txt autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/misc/third_party/Makefile.in +# # # Include projects from this directory diff --git a/c++/src/misc/third_party_static/CMakeLists.txt b/c++/src/misc/third_party_static/CMakeLists.txt index fbec35ce..4644f8d1 100644 --- a/c++/src/misc/third_party_static/CMakeLists.txt +++ b/c++/src/misc/third_party_static/CMakeLists.txt @@ -1,5 +1,5 @@ ############################################################################## -# CMakeLists.txt autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/misc/third_party_static/Makefile.in +# # # Include projects from this directory diff --git a/c++/src/objects/CMakeLists.txt b/c++/src/objects/CMakeLists.txt new file mode 100644 index 00000000..fe20c660 --- /dev/null +++ b/c++/src/objects/CMakeLists.txt @@ -0,0 +1,104 @@ +############################################################################## +# +# + +# Include projects from this directory + +# Recurse subdirectories +add_subdirectory(access) +add_subdirectory(biblio) +add_subdirectory(biotree) +add_subdirectory(blast) +add_subdirectory(blastdb) +add_subdirectory(blastxml) +add_subdirectory(blastxml2) +add_subdirectory(cdd) +add_subdirectory(cn3d) +add_subdirectory(coords) +add_subdirectory(docsum) +add_subdirectory(entrez2) +add_subdirectory(entrezgene) +add_subdirectory(featdef) +add_subdirectory(gbproj) +add_subdirectory(gbseq) +add_subdirectory(general) +add_subdirectory(genesbyloc) +add_subdirectory(genomecoll) +add_subdirectory(homologene) +add_subdirectory(id1) +add_subdirectory(id2) +add_subdirectory(insdseq) +add_subdirectory(macro) +add_subdirectory(medlars) +add_subdirectory(medline) +add_subdirectory(mim) +add_subdirectory(mla) +add_subdirectory(mmdb) +add_subdirectory(ncbimime) +add_subdirectory(objprt) +add_subdirectory(omssa) +add_subdirectory(pcassay) +add_subdirectory(pcsubstance) +add_subdirectory(proj) +add_subdirectory(pub) +add_subdirectory(pubmed) +add_subdirectory(remap) +add_subdirectory(scoremat) +add_subdirectory(seq) +add_subdirectory(seqcode) +add_subdirectory(seqedit) +add_subdirectory(seqset) +add_subdirectory(seqsplit) +add_subdirectory(seqtest) +add_subdirectory(submit) +add_subdirectory(taxon1) +add_subdirectory(taxon3) +add_subdirectory(tinyseq) +add_subdirectory(trackmgr) +add_subdirectory(valerr) +add_subdirectory(valid) +add_subdirectory(variation) +add_subdirectory(varrep) + +# +# ASN dependencies: +# All centralized below +# + +add_dependencies(biblio general-lib) +add_dependencies(biotree seq) +add_dependencies(blastdb seq) +add_dependencies(cdd general-lib biblio pub seqset seq mmdb cn3d scoremat) +add_dependencies(entrezgene seq general-lib pub) +add_dependencies(gbseq seq) +add_dependencies(gencoll_client genome_collection) +add_dependencies(genome_collection general-lib seq) +add_dependencies(homologene general-lib seq) +add_dependencies(id1 seq seqset) +add_dependencies(id2 seqsplit seq) +add_dependencies(medlars general-lib biblio) +add_dependencies(medline general-lib biblio) +add_dependencies(mla biblio medline medlars pubmed pub) +add_dependencies(mmdb general-lib pub biblio seqset seq) +add_dependencies(ncbimime general-lib biblio pub medline seq seqset mmdb cn3d cdd) +add_dependencies(omssa seq) +add_dependencies(pcassay general-lib pub seq pcsubstance) +add_dependencies(pcsubstance general-lib pub) +add_dependencies(proj general-lib biblio pubmed seq seqset) +add_dependencies(pub general-lib biblio medline) +add_dependencies(pubmed general-lib biblio medline) +add_dependencies(remap seq) +add_dependencies(scoremat seqset general-lib) +add_dependencies(seqedit seq) +add_dependencies(seq general-lib pub biblio) +add_dependencies(seqset general-lib biblio medline seq) +add_dependencies(seqsplit seq) +add_dependencies(seqtest general-lib seq) +add_dependencies(submit general-lib biblio seq seqset) +add_dependencies(taxon1 seq) +add_dependencies(taxon3 seq) +add_dependencies(trackmgr seq) +add_dependencies(variation seq) +add_dependencies(xnetblast seqset scoremat seq) + + diff --git a/c++/src/objects/access/CMakeLists.access.asn.txt b/c++/src/objects/access/CMakeLists.access.asn.txt new file mode 100644 index 00000000..032c6fdd --- /dev/null +++ b/c++/src/objects/access/CMakeLists.access.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/access/Makefile.access.lib +# + +set(MODULE access) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/access) + +set(MODULE_EXT "asn") +add_library(access ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(access + xser +) \ No newline at end of file diff --git a/c++/src/objects/access/CMakeLists.txt b/c++/src/objects/access/CMakeLists.txt new file mode 100644 index 00000000..f4fb4e1c --- /dev/null +++ b/c++/src/objects/access/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.access.asn.txt) + diff --git a/c++/src/objects/biblio/CMakeLists.biblio.asn.txt b/c++/src/objects/biblio/CMakeLists.biblio.asn.txt new file mode 100644 index 00000000..253812eb --- /dev/null +++ b/c++/src/objects/biblio/CMakeLists.biblio.asn.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/biblio/Makefile.biblio.lib +# + +set(MODULE biblio) +set(MODULE_IMPORT ) +set(MODULE_PATH ) + +set(MODULE_EXT "asn") +add_library(biblio ${MODULE}__ ${MODULE}___ citation_base) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(biblio + general-lib +) + diff --git a/c++/src/objects/biblio/CMakeLists.txt b/c++/src/objects/biblio/CMakeLists.txt new file mode 100644 index 00000000..7ebe4de1 --- /dev/null +++ b/c++/src/objects/biblio/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.biblio.asn.txt) + diff --git a/c++/src/objects/biotree/CMakeLists.biotree.asn.txt b/c++/src/objects/biotree/CMakeLists.biotree.asn.txt new file mode 100644 index 00000000..e50a5dc8 --- /dev/null +++ b/c++/src/objects/biotree/CMakeLists.biotree.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/biotree/Makefile.biotree.lib +# + +set(MODULE biotree) +set(MODULE_IMPORT objects/general/general) +set(MODULE_PATH objects/biotree) + +set(MODULE_EXT "asn") +add_library(biotree ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(biotree + general-lib +) \ No newline at end of file diff --git a/c++/src/objects/biotree/CMakeLists.txt b/c++/src/objects/biotree/CMakeLists.txt new file mode 100644 index 00000000..827551e7 --- /dev/null +++ b/c++/src/objects/biotree/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.biotree.asn.txt) + diff --git a/c++/src/objects/biotree/biotree.asn b/c++/src/objects/biotree/biotree.asn index e07dd736..3c678742 100644 --- a/c++/src/objects/biotree/biotree.asn +++ b/c++/src/objects/biotree/biotree.asn @@ -1,4 +1,4 @@ ---$Revision: 480916 $ +--$Revision: 525541 $ --********************************************************************* -- -- biotree.asn @@ -38,7 +38,7 @@ NodeFeatureSet ::= SET OF NodeFeature NodeFeature ::= SEQUENCE { featureid INTEGER, - value VisibleString + value UTF8String } diff --git a/c++/src/objects/blast/CMakeLists.blast.asn.txt b/c++/src/objects/blast/CMakeLists.blast.asn.txt new file mode 100644 index 00000000..91ec843b --- /dev/null +++ b/c++/src/objects/blast/CMakeLists.blast.asn.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/blast/Makefile.blast.lib +# + +set(MODULE blast) +set(MODULE_IMPORT objects/scoremat/scoremat objects/seq/seq objects/seqset/seqset objects/seqloc/seqloc objects/seqalign/seqalign) +set(MODULE_PATH objects/blast) + +set(MODULE_EXT "asn") +add_library(xnetblast ${MODULE}__ ${MODULE}___ names) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + + +target_link_libraries(xnetblast + scoremat +) diff --git a/c++/src/objects/blast/CMakeLists.txt b/c++/src/objects/blast/CMakeLists.txt new file mode 100644 index 00000000..948c51d4 --- /dev/null +++ b/c++/src/objects/blast/CMakeLists.txt @@ -0,0 +1,8 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xnetblastcli.lib.txt) +include(CMakeLists.blast.asn.txt) + diff --git a/c++/src/objects/blast/CMakeLists.xnetblastcli.lib.txt b/c++/src/objects/blast/CMakeLists.xnetblastcli.lib.txt new file mode 100644 index 00000000..fa66008d --- /dev/null +++ b/c++/src/objects/blast/CMakeLists.xnetblastcli.lib.txt @@ -0,0 +1,12 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/blast/Makefile.xnetblastcli.lib +# +add_library(xnetblastcli + blastclient blastclient_ +) + +#SET_TARGET_PROPERTIES(xnetblastcli PROPERTIES LINKER_LANGUAGE CXX) + +target_link_libraries(xnetblastcli + xconnect xnetblast +) diff --git a/c++/src/objects/blastdb/CMakeLists.blastdb.asn.txt b/c++/src/objects/blastdb/CMakeLists.blastdb.asn.txt new file mode 100644 index 00000000..15c7d22a --- /dev/null +++ b/c++/src/objects/blastdb/CMakeLists.blastdb.asn.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/blastdb/Makefile.blastdb.lib +# + +set(MODULE blastdb) +set(MODULE_IMPORT objects/seqloc/seqloc) +set(MODULE_PATH objects/blastdb) + +set(MODULE_EXT "asn") +add_library("${MODULE}" ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq xnetblast +) diff --git a/c++/src/objects/blastdb/CMakeLists.txt b/c++/src/objects/blastdb/CMakeLists.txt new file mode 100644 index 00000000..f59bf98c --- /dev/null +++ b/c++/src/objects/blastdb/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.blastdb.asn.txt) + diff --git a/c++/src/objects/blastxml/CMakeLists.blastxml.asn.txt b/c++/src/objects/blastxml/CMakeLists.blastxml.asn.txt new file mode 100644 index 00000000..20e16f1c --- /dev/null +++ b/c++/src/objects/blastxml/CMakeLists.blastxml.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/blastxml/Makefile.blastxml.lib +# + +set(MODULE blastxml) +set(MODULE_IMPORT ) +set(MODULE_PATH ) + +set(MODULE_EXT "asn") +add_library(blastxml ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(blastxml + xser +) \ No newline at end of file diff --git a/c++/src/objects/blastxml/CMakeLists.txt b/c++/src/objects/blastxml/CMakeLists.txt new file mode 100644 index 00000000..0c5649d6 --- /dev/null +++ b/c++/src/objects/blastxml/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.blastxml.asn.txt) + diff --git a/c++/src/objects/blastxml2/CMakeLists.blastxml2.asn.txt b/c++/src/objects/blastxml2/CMakeLists.blastxml2.asn.txt new file mode 100644 index 00000000..8f158bca --- /dev/null +++ b/c++/src/objects/blastxml2/CMakeLists.blastxml2.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/blastxml2/Makefile.blastxml2.lib +# + +set(MODULE blastxml2) +set(MODULE_IMPORT ) +set(MODULE_PATH ) + +set(MODULE_EXT "asn") +add_library(blastxml2 ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(blastxml2 + xser +) \ No newline at end of file diff --git a/c++/src/objects/blastxml2/CMakeLists.txt b/c++/src/objects/blastxml2/CMakeLists.txt new file mode 100644 index 00000000..c3a6c0c1 --- /dev/null +++ b/c++/src/objects/blastxml2/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.blastxml2.asn.txt) + diff --git a/c++/src/objects/cdd/CMakeLists.cdd.asn.txt b/c++/src/objects/cdd/CMakeLists.cdd.asn.txt new file mode 100644 index 00000000..042bab53 --- /dev/null +++ b/c++/src/objects/cdd/CMakeLists.cdd.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/cdd/Makefile.cdd.lib +# + +set(MODULE cdd) +set(MODULE_IMPORT objects/general/general objects/biblio/biblio objects/pub/pub objects/seq/seq objects/seqset/seqset objects/seqloc/seqloc objects/seqfeat/seqfeat objects/seqalign/seqalign objects/mmdb1/mmdb1 objects/mmdb2/mmdb2 objects/mmdb3/mmdb3 objects/cn3d/cn3d objects/scoremat/scoremat) +set(MODULE_PATH objects/cdd) + +set(MODULE_EXT "asn") +add_library(cdd ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + cn3d scoremat +) + +target_link_libraries(cdd + cn3d scoremat +) \ No newline at end of file diff --git a/c++/src/objects/cdd/CMakeLists.txt b/c++/src/objects/cdd/CMakeLists.txt new file mode 100644 index 00000000..1a063747 --- /dev/null +++ b/c++/src/objects/cdd/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.cdd.asn.txt) + diff --git a/c++/src/objects/cdd/Makefile.cdd.lib b/c++/src/objects/cdd/Makefile.cdd.lib index 248407ea..454644cb 100644 --- a/c++/src/objects/cdd/Makefile.cdd.lib +++ b/c++/src/objects/cdd/Makefile.cdd.lib @@ -1,6 +1,7 @@ LIB = cdd SRC = cdd__ cdd___ +DLL_LIB = cn3d scoremat USES_LIBRARIES = \ cn3d scoremat diff --git a/c++/src/objects/cn3d/CMakeLists.cn3d.asn.txt b/c++/src/objects/cn3d/CMakeLists.cn3d.asn.txt new file mode 100644 index 00000000..1d5725f9 --- /dev/null +++ b/c++/src/objects/cn3d/CMakeLists.cn3d.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/cn3d/Makefile.cn3d.lib +# + +set(MODULE cn3d) +set(MODULE_IMPORT objects/mmdb1/mmdb1) +set(MODULE_PATH objects/cn3d) + +set(MODULE_EXT "asn") +add_library(cn3d ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + mmdb +) + +target_link_libraries(cn3d + mmdb +) \ No newline at end of file diff --git a/c++/src/objects/cn3d/CMakeLists.txt b/c++/src/objects/cn3d/CMakeLists.txt new file mode 100644 index 00000000..b6f76e76 --- /dev/null +++ b/c++/src/objects/cn3d/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.cn3d.asn.txt) + diff --git a/c++/src/objects/coords/CMakeLists.objcoords.asn.txt b/c++/src/objects/coords/CMakeLists.objcoords.asn.txt new file mode 100644 index 00000000..9928005b --- /dev/null +++ b/c++/src/objects/coords/CMakeLists.objcoords.asn.txt @@ -0,0 +1,21 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/coords/Makefile.objcoords.lib +# + +set(MODULE objcoords) +set(MODULE_IMPORT ) +set(MODULE_PATH ) +set(MODULE_PATH_RELATIVE "objects/coords") + +set(MODULE_EXT "asn") +add_library(objcoords ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(objcoords + xser +) \ No newline at end of file diff --git a/c++/src/objects/coords/CMakeLists.txt b/c++/src/objects/coords/CMakeLists.txt new file mode 100644 index 00000000..af37dacd --- /dev/null +++ b/c++/src/objects/coords/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.objcoords.asn.txt) + diff --git a/c++/src/objects/docsum/CMakeLists.docsum.asn.txt b/c++/src/objects/docsum/CMakeLists.docsum.asn.txt new file mode 100644 index 00000000..64c1047d --- /dev/null +++ b/c++/src/objects/docsum/CMakeLists.docsum.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/docsum/Makefile.docsum.lib +# + +set(MODULE docsum) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/docsum) + +set(MODULE_EXT "asn") +add_library(docsum ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(docsum + xser +) \ No newline at end of file diff --git a/c++/src/objects/docsum/CMakeLists.txt b/c++/src/objects/docsum/CMakeLists.txt new file mode 100644 index 00000000..0df96df0 --- /dev/null +++ b/c++/src/objects/docsum/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.docsum.asn.txt) + diff --git a/c++/src/objects/docsum/docsum.def b/c++/src/objects/docsum/docsum.def index cb6425bc..82fdeb71 100644 --- a/c++/src/objects/docsum/docsum.def +++ b/c++/src/objects/docsum/docsum.def @@ -4,3 +4,8 @@ _export = NCBI_DOCSUM_EXPORT [ExchangeSet] summary.attlist.totalSeqLength._type=Int8 +[Ss] +attlist.ssId._type=Int8 + +[Rs] +sequence.attlist.exemplarSs._type=Int8 diff --git a/c++/src/objects/entrez2/CMakeLists.entrez2.asn.txt b/c++/src/objects/entrez2/CMakeLists.entrez2.asn.txt new file mode 100644 index 00000000..ae55663f --- /dev/null +++ b/c++/src/objects/entrez2/CMakeLists.entrez2.asn.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/entrez2/Makefile.entrez2.lib +# + +set(MODULE entrez2) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/entrez2) + +set(MODULE_EXT "asn") +add_library(entrez2 ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(entrez2 + xser +) + diff --git a/c++/src/objects/entrez2/CMakeLists.entrez2cli.lib.txt b/c++/src/objects/entrez2/CMakeLists.entrez2cli.lib.txt new file mode 100644 index 00000000..0102d482 --- /dev/null +++ b/c++/src/objects/entrez2/CMakeLists.entrez2cli.lib.txt @@ -0,0 +1,10 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/entrez2/Makefile.entrez2cli.lib +# +add_library(entrez2cli + entrez2_client entrez2_client_ +) + +target_link_libraries(entrez2cli + entrez2 xconnect +) diff --git a/c++/src/objects/entrez2/CMakeLists.txt b/c++/src/objects/entrez2/CMakeLists.txt new file mode 100644 index 00000000..90b7153a --- /dev/null +++ b/c++/src/objects/entrez2/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.entrez2cli.lib.txt) +include(CMakeLists.entrez2.asn.txt) + +# Recurse subdirectories +add_subdirectory(demo ) diff --git a/c++/src/objects/entrez2/Makefile.entrez2cli.lib b/c++/src/objects/entrez2/Makefile.entrez2cli.lib index 934a3f1f..2bfb592b 100644 --- a/c++/src/objects/entrez2/Makefile.entrez2cli.lib +++ b/c++/src/objects/entrez2/Makefile.entrez2cli.lib @@ -5,6 +5,7 @@ ASN_DEP = entrez2 LIB = entrez2cli SRC = entrez2_client entrez2_client_ +DLL_LIB = entrez2 xconnect USES_LIBRARIES = \ entrez2 xconnect diff --git a/c++/src/objects/entrezgene/CMakeLists.entrezgene.asn.txt b/c++/src/objects/entrezgene/CMakeLists.entrezgene.asn.txt new file mode 100644 index 00000000..eba66eb0 --- /dev/null +++ b/c++/src/objects/entrezgene/CMakeLists.entrezgene.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/entrezgene/Makefile.entrezgene.lib +# + +set(MODULE entrezgene) +set(MODULE_IMPORT objects/seqfeat/seqfeat objects/general/general objects/seqloc/seqloc objects/pub/pub) +set(MODULE_PATH objects/entrezgene) + +set(MODULE_EXT "asn") +add_library(entrezgene ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(entrezgene + seq +) \ No newline at end of file diff --git a/c++/src/objects/entrezgene/CMakeLists.txt b/c++/src/objects/entrezgene/CMakeLists.txt new file mode 100644 index 00000000..834d6015 --- /dev/null +++ b/c++/src/objects/entrezgene/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.entrezgene.asn.txt) + diff --git a/c++/src/objects/entrezgene/entrezgene.asn b/c++/src/objects/entrezgene/entrezgene.asn index 163783de..a2adfd0f 100644 --- a/c++/src/objects/entrezgene/entrezgene.asn +++ b/c++/src/objects/entrezgene/entrezgene.asn @@ -1,4 +1,4 @@ ---$Revision: 463081 $ +--$Revision: 529107 $ --********************************************************************** -- -- NCBI Entrezgene @@ -119,6 +119,10 @@ Gene-commentary ::= SEQUENCE { gene-group (23), -- for relationship sets (such as pseudogene / parent gene) assembly (24), -- for full assembly accession assembly-unit (25), -- for the assembly unit corresponding to the refseq + c-region (26), + d-segment (27), + j-segment (28), + v-segment (29), comment (254) , other (255) } , diff --git a/c++/src/objects/featdef/CMakeLists.featdef.asn.txt b/c++/src/objects/featdef/CMakeLists.featdef.asn.txt new file mode 100644 index 00000000..affbc3d4 --- /dev/null +++ b/c++/src/objects/featdef/CMakeLists.featdef.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/featdef/Makefile.featdef.lib +# + +set(MODULE featdef) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/featdef) + +set(MODULE_EXT "asn") +add_library(featdef ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(featdef + xser +) \ No newline at end of file diff --git a/c++/src/objects/featdef/CMakeLists.txt b/c++/src/objects/featdef/CMakeLists.txt new file mode 100644 index 00000000..dcb26f12 --- /dev/null +++ b/c++/src/objects/featdef/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.featdef.asn.txt) + diff --git a/c++/src/objects/gbproj/CMakeLists.gbproj.asn.txt b/c++/src/objects/gbproj/CMakeLists.gbproj.asn.txt new file mode 100644 index 00000000..940ba514 --- /dev/null +++ b/c++/src/objects/gbproj/CMakeLists.gbproj.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/gbproj/Makefile.gbproj.lib +# + +set(MODULE gbproj) +set(MODULE_IMPORT objects/seq/seq objects/seqloc/seqloc objects/seqset/seqset objects/general/general objects/submit/submit objects/seqalign/seqalign) +set(MODULE_PATH objects/gbproj) + +set(MODULE_EXT "asn") +add_library(gbproj ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + submit +) + +target_link_libraries(gbproj + submit xconnect +) \ No newline at end of file diff --git a/c++/src/objects/gbproj/CMakeLists.txt b/c++/src/objects/gbproj/CMakeLists.txt new file mode 100644 index 00000000..3002c981 --- /dev/null +++ b/c++/src/objects/gbproj/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.gbproj.asn.txt) + diff --git a/c++/src/objects/gbseq/CMakeLists.gbseq.asn.txt b/c++/src/objects/gbseq/CMakeLists.gbseq.asn.txt new file mode 100644 index 00000000..86ce6119 --- /dev/null +++ b/c++/src/objects/gbseq/CMakeLists.gbseq.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/gbseq/Makefile.gbseq.lib +# + +set(MODULE gbseq) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/gbseq) + +set(MODULE_EXT "asn") +add_library(gbseq ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(gbseq + xser +) \ No newline at end of file diff --git a/c++/src/objects/gbseq/CMakeLists.txt b/c++/src/objects/gbseq/CMakeLists.txt new file mode 100644 index 00000000..d26689cf --- /dev/null +++ b/c++/src/objects/gbseq/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.gbseq.asn.txt) + diff --git a/c++/src/objects/general/CMakeLists.general.asn.txt b/c++/src/objects/general/CMakeLists.general.asn.txt new file mode 100644 index 00000000..6acd3c57 --- /dev/null +++ b/c++/src/objects/general/CMakeLists.general.asn.txt @@ -0,0 +1,19 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/general-lib/Makefile.general.lib +# + +set(MODULE general) +set(MODULE_IMPORT ) +set(MODULE_PATH ) + +set(MODULE_EXT "asn") +add_library(general-lib ${MODULE}__ ${MODULE}___ uoconv) +set_target_properties(general-lib PROPERTIES OUTPUT_NAME general) + + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(general-lib + xser +) + diff --git a/c++/src/objects/general/CMakeLists.txt b/c++/src/objects/general/CMakeLists.txt new file mode 100644 index 00000000..8301595b --- /dev/null +++ b/c++/src/objects/general/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.general.asn.txt) + +# Recurse subdirectories +add_subdirectory(test ) +add_subdirectory(unit_test ) diff --git a/c++/src/objects/general/Dbtag.cpp b/c++/src/objects/general/Dbtag.cpp index c4d2aa87..3aabf56a 100644 --- a/c++/src/objects/general/Dbtag.cpp +++ b/c++/src/objects/general/Dbtag.cpp @@ -1,4 +1,4 @@ -/* $Id: Dbtag.cpp 512465 2016-08-31 11:24:52Z ivanov $ +/* $Id: Dbtag.cpp 547026 2017-09-25 17:22:25Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -81,10 +81,12 @@ static const TDbxrefPair kApprovedDbXrefs[] = { { "CGD", CDbtag::eDbtagType_CGD }, { "CK", CDbtag::eDbtagType_CK }, { "COG", CDbtag::eDbtagType_COG }, + { "ECOCYC", CDbtag::eDbtagType_ECOCYC }, { "ENSEMBL", CDbtag::eDbtagType_ENSEMBL }, { "ERIC", CDbtag::eDbtagType_ERIC }, { "ESTLIB", CDbtag::eDbtagType_ESTLIB }, { "EcoGene", CDbtag::eDbtagType_EcoGene }, + { "Ensembl", CDbtag::eDbtagType_Ensembl }, { "EnsemblGenomes", CDbtag::eDbtagType_EnsemblGenomes }, { "EnsemblGenomes-Gn", CDbtag::eDbtagType_EnsemblGenomes_Gn }, { "EnsemblGenomes-Tr", CDbtag::eDbtagType_EnsemblGenomes_Tr }, @@ -137,6 +139,7 @@ static const TDbxrefPair kApprovedDbXrefs[] = { { "PIR", CDbtag::eDbtagType_PIR }, { "PSEUDO", CDbtag::eDbtagType_PSEUDO }, { "Pathema", CDbtag::eDbtagType_Pathema }, + { "PeptideAtlas", CDbtag::eDbtagType_PeptideAtlas }, { "Phytozome", CDbtag::eDbtagType_Phytozome }, { "PomBase", CDbtag::eDbtagType_PomBase }, { "PseudoCap", CDbtag::eDbtagType_PseudoCap }, @@ -144,6 +147,7 @@ static const TDbxrefPair kApprovedDbXrefs[] = { { "RATMAP", CDbtag::eDbtagType_RATMAP }, { "RFAM", CDbtag::eDbtagType_RFAM }, { "RGD", CDbtag::eDbtagType_RGD }, + { "RNAcentral", CDbtag::eDbtagType_RNAcentral }, { "RZPD", CDbtag::eDbtagType_RZPD }, { "RiceGenes", CDbtag::eDbtagType_RiceGenes }, { "SEED", CDbtag::eDbtagType_SEED }, @@ -188,12 +192,13 @@ static const TDbxrefPair kApprovedRefSeqDbXrefs[] = { { "CCDS", CDbtag::eDbtagType_CCDS }, { "CGNC", CDbtag::eDbtagType_CGNC }, { "CloneID", CDbtag::eDbtagType_CloneID }, - { "ECOCYC", CDbtag::eDbtagType_ECOCYC }, + { "EPDnew", CDbtag::eDbtagType_EPDnew }, { "HPM", CDbtag::eDbtagType_HPM }, { "HPRD", CDbtag::eDbtagType_HPRD }, { "LRG", CDbtag::eDbtagType_LRG }, { "NASONIABASE", CDbtag::eDbtagType_NASONIABASE }, { "PBR", CDbtag::eDbtagType_PBR }, + { "PeptideAtlas", CDbtag::eDbtagType_PeptideAtlas }, { "REBASE", CDbtag::eDbtagType_REBASE }, { "RefSeq", CDbtag::eDbtagType_RefSeq }, { "SK-FST", CDbtag::eDbtagType_SK_FST }, @@ -491,28 +496,36 @@ CDbtag::TDbtagGroup CDbtag::GetDBFlags (string& correct_caps) const ITERATE (TDbxrefTypeMap, it, sc_ApprovedDb) { if ( NStr::EqualNocase(db, it->first) ) { - correct_caps = it->first; + if ( correct_caps.empty() || ! NStr::EqualCase(db, correct_caps) ) { + correct_caps = it->first; + } rsult |= fGenBank; } } ITERATE (TDbxrefTypeMap, it, sc_ApprovedRefSeqDb) { if ( NStr::EqualNocase(db, it->first) ) { - correct_caps = it->first; + if ( correct_caps.empty() || ! NStr::EqualCase(db, correct_caps) ) { + correct_caps = it->first; + } rsult |= fRefSeq; } } ITERATE (TDbxrefTypeMap, it, sc_ApprovedSrcDb) { if ( NStr::EqualNocase(db, it->first) ) { - correct_caps = it->first; + if ( correct_caps.empty() || ! NStr::EqualCase(db, correct_caps) ) { + correct_caps = it->first; + } rsult |= fSrc; } } ITERATE (TDbxrefTypeMap, it, sc_ApprovedProbeDb) { if ( NStr::EqualNocase(db, it->first) ) { - correct_caps = it->first; + if ( correct_caps.empty() || ! NStr::EqualCase(db, correct_caps) ) { + correct_caps = it->first; + } rsult |= fProbe; } } @@ -584,7 +597,7 @@ static const TDbtUrl sc_url_prefix[] = { { CDbtag::eDbtagType_EcoGene, "https://www.ecogene.org/gene/" }, { CDbtag::eDbtagType_FANTOM_DB, "https://fantom.gsc.riken.jp/db/annotate/main.cgi?masterid=" }, { CDbtag::eDbtagType_FBOL, "http://www.fungalbarcoding.org/BioloMICS.aspx?Table=Fungal%20barcodes&Fields=All&Rec=" }, // https not available tested 7/13/2016 - { CDbtag::eDbtagType_FLYBASE, "http://flybase.bio.indiana.edu/.bin/fbidq.html?" }, // https not available, http site “experiencing problems” tested 7/13/2016 + { CDbtag::eDbtagType_FLYBASE, "http://flybase.org/reports/" }, // https not available, http site “experiencing problems” tested 7/13/2016 { CDbtag::eDbtagType_Fungorum, "http://www.indexfungorum.org/Names/NamesRecord.asp?RecordID=" }, // https not available tested 7/13/2016 { CDbtag::eDbtagType_GABI, "https://www.gabipd.org/database/cgi-bin/GreenCards.pl.cgi?Mode=ShowSequence&App=ncbi&SequenceId=" }, { CDbtag::eDbtagType_GEO, "https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=" }, @@ -656,11 +669,11 @@ static const TDbtUrl sc_url_prefix[] = { { CDbtag::eDbtagType_VBASE2, "http://www.vbase2.org/vgene.php?id=" }, // https not available tested 7/13/2016 { CDbtag::eDbtagType_VBRC, "http://vbrc.org/query.asp?web_view=curation&web_id=" }, // https not available tested 7/13/2016 { CDbtag::eDbtagType_VectorBase, "https://www.vectorbase.org/Genome/BRCGene/?feature=" }, - { CDbtag::eDbtagType_Vega, "http://vega.sanger.ac.uk/id/" }, + { CDbtag::eDbtagType_Vega, "http://vega.archive.ensembl.org/id/" }, { CDbtag::eDbtagType_WorfDB, "http://worfdb.dfci.harvard.edu/search.pl?form=1&search=" }, { CDbtag::eDbtagType_WormBase, "https://www.wormbase.org/search/gene/" }, { CDbtag::eDbtagType_Xenbase, "https://www.xenbase.org/gene/showgene.do?method=display&geneId=" }, - { CDbtag::eDbtagType_ZFIN, "https://zfin.org/cgi-bin/webdriver?MIval=aa-markerview.apg&OID=" }, + { CDbtag::eDbtagType_ZFIN, "https://zfin.org/" }, { CDbtag::eDbtagType_axeldb, "http://www.dkfz-heidelberg.de/tbi/services/axeldb/clone/xenopus?name=" }, // https not available tested 7/13/2016 { CDbtag::eDbtagType_dbClone, "https://www.ncbi.nlm.nih.gov/sites/entrez?db=clone&cmd=Retrieve&list_uids=" }, { CDbtag::eDbtagType_dbCloneLib, "https://www.ncbi.nlm.nih.gov/sites/entrez?db=clonelib&cmd=Retrieve&list_uids=" }, @@ -690,10 +703,14 @@ static const TDbtUrl sc_url_prefix[] = { { CDbtag::eDbtagType_BioSample, "https://www.ncbi.nlm.nih.gov/biosample/" }, { CDbtag::eDbtagType_ISHAM_ITS, "http://its.mycologylab.org/BioloMICS.aspx?Table=Sequences&ExactMatch=T&Name=MITS" }, // https not available tested 7/13/2016 { CDbtag::eDbtagType_I5KNAL, "https://i5k.nal.usda.gov/" }, - { CDbtag::eDbtagType_VISTA, "http://enhancer.lbl.gov/cgi-bin/dbxref.pl?id=" }, // https not available tested 7/13/2016 + { CDbtag::eDbtagType_VISTA, "https://enhancer.lbl.gov/cgi-bin/dbxref.pl?id=" }, // https not available tested 7/13/2016 { CDbtag::eDbtagType_BEI, "https://www.beiresources.org/Catalog/animalViruses/" }, { CDbtag::eDbtagType_Araport, "https://www.araport.org/locus/" }, { CDbtag::eDbtagType_VGNC, "http://vertebrate.genenames.org/data/gene-symbol-report/#!/vgnc_id/VGNC:" }, // https not available tested 7/13/2016 + { CDbtag::eDbtagType_RNAcentral, "http://rnacentral.org/rna/" }, + { CDbtag::eDbtagType_PeptideAtlas, "https://db.systemsbiology.net/sbeams/cgi/PeptideAtlas/Search?action=GO&search_key=" }, + { CDbtag::eDbtagType_EPDnew, "http://epd.vital-it.ch/cgi-bin/get_doc?format=genome&entry=" }, + { CDbtag::eDbtagType_Ensembl, "http://www.ensembl.org/id/" }, // url seems incorrect, includes msg user has been redirected and “Error 404 Page not found” tested 7/13/2016 }; typedef CStaticPairArrayMap TUrlPrefixMap; @@ -992,12 +1009,37 @@ string CDbtag::GetUrl(const string & genus, break; + case CDbtag::eDbtagType_IFO: + if (!tag.empty()){ + while (tag.size() < SIZE_TYPE(8)){ + tag = '0' + tag; + } + } + break; + + case eDbtagType_ISHAM_ITS: if (NStr::StartsWith(tag, "MITS", NStr::eNocase)) { tag = tag.substr(4); } break; + case CDbtag::eDbtagType_EPDnew: + if( ! genus.empty() && ! species.empty() ) { + string abbrev = ""; + if (NStr::Equal (genus, "Homo") && NStr::Equal (species, "sapiens")) { + abbrev = "hg"; + } else { + string gen = genus; + string spc = species; + gen = NStr::ToLower(gen); + spc = NStr::ToLower(spc); + abbrev = gen.substr(0, 1) + spc.substr(0, 1); + } + tag += "&db=" + abbrev; + } + break; + default: break; } diff --git a/c++/src/objects/general/Name_std.cpp b/c++/src/objects/general/Name_std.cpp index 8308ae1f..4cdf4aaa 100644 --- a/c++/src/objects/general/Name_std.cpp +++ b/c++/src/objects/general/Name_std.cpp @@ -1,4 +1,4 @@ -/* $Id: Name_std.cpp 509242 2016-08-04 14:12:34Z ivanov $ +/* $Id: Name_std.cpp 508532 2016-07-28 17:21:31Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/genesbyloc/CMakeLists.genesbyloc.asn.txt b/c++/src/objects/genesbyloc/CMakeLists.genesbyloc.asn.txt new file mode 100644 index 00000000..3d23b124 --- /dev/null +++ b/c++/src/objects/genesbyloc/CMakeLists.genesbyloc.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/genesbyloc/Makefile.genesbyloc.lib +# + +set(MODULE genesbyloc) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/genesbyloc) + +set(MODULE_EXT "asn") +add_library(genesbyloc ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(genesbyloc + xser +) \ No newline at end of file diff --git a/c++/src/objects/genesbyloc/CMakeLists.txt b/c++/src/objects/genesbyloc/CMakeLists.txt new file mode 100644 index 00000000..d934baec --- /dev/null +++ b/c++/src/objects/genesbyloc/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.genesbyloc.asn.txt) + diff --git a/c++/src/objects/genomecoll/CMakeLists.gencoll_client.asn.txt b/c++/src/objects/genomecoll/CMakeLists.gencoll_client.asn.txt new file mode 100644 index 00000000..7759b7c1 --- /dev/null +++ b/c++/src/objects/genomecoll/CMakeLists.gencoll_client.asn.txt @@ -0,0 +1,25 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/genomecoll/Makefile.gencoll_client.lib +# + +set(MODULE gencoll_client) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/genomecoll) +set(MODULE_PATH_RELATIVE objects/genomecoll) + +set(MODULE_EXT "asn") +add_library(gencoll_client ${MODULE}__ ${MODULE}___ genomic_collections_cli genomic_collections_cli_ cached_assembly) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +SET_SOURCE_FILES_PROPERTIES(genomic_collections_cli_ PROPERTIES GENERATED 1) +SET_TARGET_PROPERTIES(gencoll_client PROPERTIES LINKER_LANGUAGE CXX) + + +target_link_libraries(${MODULE} + genome_collection xcompress +) + +target_link_libraries(gencoll_client + genome_collection xcompress xconnect +) \ No newline at end of file diff --git a/c++/src/objects/genomecoll/CMakeLists.genome_collection.asn.txt b/c++/src/objects/genomecoll/CMakeLists.genome_collection.asn.txt new file mode 100644 index 00000000..0dc34696 --- /dev/null +++ b/c++/src/objects/genomecoll/CMakeLists.genome_collection.asn.txt @@ -0,0 +1,21 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/genomecoll/Makefile.genome_collection.lib +# + +set(MODULE genome_collection) +set(MODULE_IMPORT objects/general/general objects/seqloc/seqloc objects/seqfeat/seqfeat objects/seq/seq) +set(MODULE_PATH objects/genome_collection) +set(MODULE_PATH_RELATIVE objects/genomecoll) + +set(MODULE_EXT "asn") +add_library(genome_collection ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(genome_collection + seq +) \ No newline at end of file diff --git a/c++/src/objects/genomecoll/CMakeLists.txt b/c++/src/objects/genomecoll/CMakeLists.txt new file mode 100644 index 00000000..ceabce48 --- /dev/null +++ b/c++/src/objects/genomecoll/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.genome_collection.asn.txt) +include(CMakeLists.gencoll_client.asn.txt) + +# Recurse subdirectories +add_subdirectory(gc_cli ) diff --git a/c++/src/objects/genomecoll/GC_Assembly.cpp b/c++/src/objects/genomecoll/GC_Assembly.cpp index f71fd883..70af18db 100644 --- a/c++/src/objects/genomecoll/GC_Assembly.cpp +++ b/c++/src/objects/genomecoll/GC_Assembly.cpp @@ -1,4 +1,4 @@ -/* $Id: GC_Assembly.cpp 504372 2016-06-14 18:01:03Z shchekot $ +/* $Id: GC_Assembly.cpp 526869 2017-02-07 19:31:53Z mozese2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -64,6 +64,7 @@ BEGIN_objects_SCOPE // namespace ncbi::objects:: // constructor CGC_Assembly::CGC_Assembly(void) +: m_TargetSet(NULL) { } @@ -350,13 +351,17 @@ void CGC_Assembly::PostRead() } -void CGC_Assembly::CreateHierarchy() +void CGC_Assembly::CreateHierarchy(CGC_Assembly *target_set) { //LOG_POST(Error << "CGC_Assembly::CreateHierarchy()"); /// /// generate the up-links as needed /// + if (target_set == NULL) { + target_set = this; + } + m_TargetSet = target_set; if (IsUnit()) { x_Index(*this); } @@ -365,21 +370,23 @@ void CGC_Assembly::CreateHierarchy() switch (set.GetSet_type()) { case CGC_AssemblySet::eSet_type_assembly_set: /// each sub-assembly is its own entity and acts as its own root - set.SetPrimary_assembly().CreateHierarchy(); + set.SetPrimary_assembly().CreateHierarchy(target_set); if (set.IsSetMore_assemblies()) { NON_CONST_ITERATE (CGC_AssemblySet::TMore_assemblies, it, set.SetMore_assemblies()) { - (*it)->CreateHierarchy(); + (*it)->CreateHierarchy(target_set); } } break; case CGC_AssemblySet::eSet_type_full_assembly: /// we are the root + set.SetPrimary_assembly().m_TargetSet = target_set; set.SetPrimary_assembly().x_Index(*this); if (set.IsSetMore_assemblies()) { NON_CONST_ITERATE (CGC_AssemblySet::TMore_assemblies, it, set.SetMore_assemblies()) { + (*it)->m_TargetSet = target_set; (*it)->x_Index(*this); } } @@ -723,6 +730,28 @@ void CGC_Assembly::GetMolecules(list< CConstRef >& molecules, s_Extract(*this, molecules, subset); } +CConstRef CGC_Assembly::GetTargetSet() const +{ + return CConstRef(m_TargetSet); +} + +bool CGC_Assembly::IsTargetSetReference() const +{ + if (IsUnit() && GetUnit().GetFullAssembly().GetPointer() != this) { + /// Assembly unit which is part of a multi-unit assembly + return GetUnit().GetFullAssembly()->IsTargetSetReference(); + } else if (IsAssembly_set() && GetAssembly_set().GetSet_type() == + CGC_AssemblySet::eSet_type_assembly_set) + { + NCBI_THROW(CException, eUnknown, + "IsTargetSetReference() called on target set"); + } else { + /// Full assembly + return m_TargetSet == this || + &m_TargetSet->GetAssembly_set().GetPrimary_assembly() + == this; + } +} END_objects_SCOPE // namespace ncbi::objects:: diff --git a/c++/src/objects/genomecoll/GC_AssemblyUnit.cpp b/c++/src/objects/genomecoll/GC_AssemblyUnit.cpp index bedf9910..82b62921 100644 --- a/c++/src/objects/genomecoll/GC_AssemblyUnit.cpp +++ b/c++/src/objects/genomecoll/GC_AssemblyUnit.cpp @@ -1,4 +1,4 @@ -/* $Id: GC_AssemblyUnit.cpp 346674 2011-12-08 18:37:59Z dicuccio $ +/* $Id: GC_AssemblyUnit.cpp 526869 2017-02-07 19:31:53Z mozese2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -104,6 +104,12 @@ CConstRef CGC_AssemblyUnit::GetFullAssembly() const return CConstRef(m_Assembly); } +bool CGC_AssemblyUnit::IsPrimaryUnit() const +{ + return m_Assembly->IsUnit() || + &m_Assembly->GetAssembly_set().GetPrimary_assembly().GetUnit() + == this; +} END_objects_SCOPE // namespace ncbi::objects:: diff --git a/c++/src/objects/genomecoll/Makefile.in b/c++/src/objects/genomecoll/Makefile.in index 39797e3c..52e0c557 100644 --- a/c++/src/objects/genomecoll/Makefile.in +++ b/c++/src/objects/genomecoll/Makefile.in @@ -1,5 +1,5 @@ ASN_PROJ = genome_collection gencoll_client -SUB_PROJ = test +SUB_PROJ = gc_cli srcdir = @srcdir@ include @builddir@/Makefile.meta diff --git a/c++/src/objects/genomecoll/cached_assembly.cpp b/c++/src/objects/genomecoll/cached_assembly.cpp index 28ed2f67..568299fe 100644 --- a/c++/src/objects/genomecoll/cached_assembly.cpp +++ b/c++/src/objects/genomecoll/cached_assembly.cpp @@ -126,56 +126,6 @@ void CompressAssembly(string& blob, CRef assembly, CCompressStream .Print("blob-size", blob.size()); } -static -const string& EnsureCompression(string& blob, CCompressStream::EMethod cur_method, CCompressStream::EMethod new_method) -{ - if(cur_method == new_method) - return blob; - - CStopWatch sw(CStopWatch::eStart); - - LOG_POST(Info << "Changing compression from " << cur_method << " to " << new_method); - - CNcbiIstrstream in(blob.data(), blob.size()); - CDecompressIStream from_stream(in, cur_method); - CNcbiOstrstream out; - CCompressOStream to_stream(out, new_method); - - to_stream << from_stream.rdbuf(); - to_stream.Finalize(); - - const string new_blob = CNcbiOstrstreamToString(out); - - sw.Stop(); - LOG_POST(Info << "Compression done - processed: " << to_stream.GetProcessedSize() << ", old size:" << blob.size() << ", new size: " << to_stream.GetOutputSize()); - - GetDiagContext().Extra().Print("Change-assembly-compression-time", sw.Elapsed() * 1000) // need millisecond - .Print("compress-method-old", cur_method) - .Print("compress-method-new", new_method) - .Print("blob-size-old", blob.size()) - .Print("blob-size-new", new_blob.size()); - - blob = new_blob; - - return blob; -} - -const string& CCachedAssembly::Blob(CCompressStream::EMethod neededCompression) -{ - _ASSERT(neededCompression == CCompressStream::eBZip2 || neededCompression == CCompressStream::eZip); - LOG_POST(Info << "Requested blob with compression: " << neededCompression); - - if (ValidBlob(m_blob.size())) - return EnsureCompression(m_blob, Compression(m_blob), neededCompression); //TODO: remove it once all be switched to new gc_access (conversion will be done inside CGencollCache) - - if (m_assembly) - CompressAssembly(m_blob, m_assembly, neededCompression); - else - m_blob.clear(); - - return m_blob; -} - const string& CCachedAssembly::Blob() { if (ValidBlob(m_blob.size())) diff --git a/c++/src/objects/genomecoll/gc_cli/CMakeLists.gc_cli.app.txt b/c++/src/objects/genomecoll/gc_cli/CMakeLists.gc_cli.app.txt new file mode 100644 index 00000000..6981eced --- /dev/null +++ b/c++/src/objects/genomecoll/gc_cli/CMakeLists.gc_cli.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/genomecoll/test/Makefile.gc_cli.app +# +add_executable(gc_cli-app + gc_cli +) + +set_target_properties(gc_cli-app PROPERTIES OUTPUT_NAME gc_cli) + +target_link_libraries(gc_cli-app + gencoll_client +) + diff --git a/c++/src/objects/genomecoll/gc_cli/CMakeLists.txt b/c++/src/objects/genomecoll/gc_cli/CMakeLists.txt new file mode 100644 index 00000000..858b9a83 --- /dev/null +++ b/c++/src/objects/genomecoll/gc_cli/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.gc_cli.app.txt) + diff --git a/c++/src/objects/genomecoll/gc_cli/Makefile.gc_cli.app b/c++/src/objects/genomecoll/gc_cli/Makefile.gc_cli.app new file mode 100644 index 00000000..41fab3f3 --- /dev/null +++ b/c++/src/objects/genomecoll/gc_cli/Makefile.gc_cli.app @@ -0,0 +1,34 @@ +# $Id: Makefile.gc_cli.app 536233 2017-05-16 19:00:07Z shchekot $ +# +# Makefile: Makefile.gc_cli.app +# +# This file was originally generated by shell script "new_project" (r179222) +# Mon Dec 28 14:49:23 EST 2009 +# + +### BASIC PROJECT SETTINGS +APP = gc_cli +SRC = gc_cli +# OBJ = + +LIB_ = gencoll_client genome_collection $(SEQ_LIBS) pub medline biblio \ + general xser xconnect $(COMPRESS_LIBS) xutil xncbi + + +LIB = $(LIB_:%=%$(STATIC)) + +### EXAMPLES OF OTHER SETTINGS THAT MIGHT BE OF INTEREST +# CPPFLAGS = $(ORIG_CPPFLAGS) $(NCBI_C_INCLUDE) +# CFLAGS = $(FAST_CFLAGS) +# CXXFLAGS = $(FAST_CXXFLAGS) +# +# LIB_OR_DLL = dll + +CPPFLAGS = $(ORIG_CPPFLAGS) +LIBS = $(CMPRS_LIBS) $(NETWORK_LIBS) $(ORIG_LIBS) + +CHECK_CMD = gc_cli get-assembly -acc GCF_000001405.27 --mode AssemblyOnly /CHECK_NAME=test_gencoll_svc_ASSM +CHECK_CMD = gc_cli get-assembly-by-sequence -acc NC_002008.4 /CHECK_NAME=test_gencoll_svc_ASSM_BY_SEQ +CHECK_CMD = gc_cli get-chrtype-valid -type eChromosome -loc eMacronuclear /CHECK_NAME=test_gencoll_svc_TYPELOC + +WATCHERS = akimchi shchekot diff --git a/c++/src/objects/genomecoll/gc_cli/Makefile.in b/c++/src/objects/genomecoll/gc_cli/Makefile.in new file mode 100644 index 00000000..0cdae462 --- /dev/null +++ b/c++/src/objects/genomecoll/gc_cli/Makefile.in @@ -0,0 +1,16 @@ +# +# Makefile: /net/freezer/vol/export3/gpipe-dev/kumarv2/rec7/trunk/internal/c++/src/internal/gpipe/gencoll/src/gc_load_utils/Makefile.in +# +# This file was originally generated by shell script "new_project" (r179222) +# Mon Dec 28 14:49:23 EST 2009 +# + +# $Id: Makefile.in 532967 2017-04-11 18:25:28Z shchekot $ + +# Meta-makefile +################################# + +APP_PROJ = gc_cli + +srcdir = @srcdir@ +include @builddir@/Makefile.meta diff --git a/c++/src/objects/genomecoll/gc_cli/gc_cli.cpp b/c++/src/objects/genomecoll/gc_cli/gc_cli.cpp new file mode 100644 index 00000000..54d8178a --- /dev/null +++ b/c++/src/objects/genomecoll/gc_cli/gc_cli.cpp @@ -0,0 +1,377 @@ +/* $Id: gc_cli.cpp 536238 2017-05-16 19:10:50Z shchekot $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Vinay Kumar + * + * File Description: + * Client for accessing the genomic_collection service. + * + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +using namespace ncbi; +using namespace ncbi::objects; +using namespace std; + +class CGenollService : public CGenomicCollectionsService +{ +public: + CGenollService(const string& cgi_url, bool nocache) + : cgiUrl(cgi_url + (nocache ? "?nocache=true" :"")) + { + } + + CGenollService(bool nocache) + { + if(nocache) + { + string service_name(GetService()); + CNcbiApplication::Instance()->SetEnvironment().Set((NStr::ToUpper(service_name) + "_CONN_ARGS").c_str(), "nocache=true"); + } + } + +private: + virtual string x_GetURL() { return cgiUrl; } + + virtual void x_Connect() + { + CUrlArgs args(m_RetryCtx.GetArgs()); + if(args.IsSetValue("cache_request_id")) + cout << "cache_request_id=" << args.GetValue("cache_request_id") << endl; + +#ifdef _DEBUG + LOG_POST(Info << "Connecting to url:" << x_GetURL().c_str()); +#endif + if(x_GetURL().empty()) + CGenomicCollectionsService::x_Connect(); + else + x_ConnectURL(x_GetURL()); + } + + const string cgiUrl; +}; + +class CDirectCGIExec : public CGenomicCollectionsService +{ +public: + CDirectCGIExec(const string& cgi_path, bool nocache) + : cgiPath(cgi_path) + { + if(nocache) + { + cgiArgs.push_back("-nocache"); + cgiArgs.push_back("true"); + } + } + + virtual void Ask(const CGCClientRequest& request, CGCClientResponse& reply) + { + cout << "\nDirectly invoking CGI with following post request :\n" << MSerial_AsnText << request << endl; + + ostringstream errStr; + stringstream outStr(ios::in|ios::out|ios::binary); + stringstream inStr (ios::in|ios::out|ios::binary); + inStr << MSerial_AsnBinary << request; + + int exitCode = -1; + const char* env[] = {"REQUEST_METHOD=POST", 0}; + + CPipe::EFinish retVal = CPipe::ExecWait(cgiPath, cgiArgs, inStr, outStr, errStr, exitCode, kEmptyStr, env); + + if(retVal != CPipe::eDone || exitCode != 0) + { + cout << "Process Killed or Aborted. CPipe::ExecWait return value " << retVal + << ". Process Exit code: " << exitCode << endl; + exit(exitCode); + } + + cout << "OutStream size = " << outStr.str().size() << endl; + + cout << "ErrStream >>>>>>>>>" << endl + << errStr.str() << endl + << "<<<<<<<<< ErrStream" << endl; + + SkipHeader(outStr); + + outStr >> MSerial_AsnBinary >> reply; + } + +private: + const string cgiPath; + vector cgiArgs; + + void SkipHeader(istream& is) + { + char buffer[1000]; + bool discarding = true; int linesDiscarded = 0; + while(discarding) + { + is.getline(buffer, sizeof(buffer)-1); + discarding = !( (strlen(buffer) == 0) || (strlen(buffer) == 1 && buffer[0] == 13)); + if(discarding) + cout << "Discarding header line " << ++linesDiscarded << " : " << buffer << endl; + } + } +}; + + +class CClientGenomicCollectionsSvcApplication : public CNcbiApplication +{ +private: + virtual void Init(void); + virtual int Run(void); + + int RunWithService(CGenomicCollectionsService& service, const CArgs& args, CNcbiOstream& ostr); +}; + +void CClientGenomicCollectionsSvcApplication::Init(void) +{ + auto AddCommonArgs = [](CArgDescriptions* arg_desc) + { + arg_desc->AddOptionalKey("url", "url_to_service", "URL to genemic collections service.cgi", CArgDescriptions::eString); + arg_desc->AddOptionalKey("cgi", "path_to_cgi", "Directly calls the CGI instead of using the gencoll client", CArgDescriptions::eString); + arg_desc->SetDependency("cgi", arg_desc->eExcludes, "url"); + arg_desc->AddDefaultKey("o", "OutputFile", "File for report", CArgDescriptions::eOutputFile, "-"); + arg_desc->AddDefaultKey( "f", "format", "Output Format. - ASN1 or XML", CArgDescriptions::eString, "ASN1"); + arg_desc->SetConstraint("f", &(*new CArgAllow_Strings,"XML","XML1","xml","xml1","ASN.1","ASN1","asn1","asn.1")); + arg_desc->AddFlag("nocache", "Do not use database cache; force fresh data"); + }; + + auto AddSeqAcc = [](CArgDescriptions* arg_desc) + { + arg_desc->AddKey("acc", "ACC_VER", "Comma-separated list of sequences", CArgDescriptions::eString); + arg_desc->AddKey("acc_file", "acc_file", "File with list of sequences - one per line", CArgDescriptions::eInputFile); + arg_desc->SetDependency("acc_file", arg_desc->eExcludes, "acc"); + }; + + auto AddAccRelId = [&](CArgDescriptions* arg_desc) + { + arg_desc->AddKey("acc", "ACC_VER", "Comma-separated list of assembly accessions", CArgDescriptions::eString); + arg_desc->AddKey("acc_file", "acc_file", "File with list of assembly accessions - one per line", CArgDescriptions::eInputFile); + arg_desc->SetDependency("acc_file", arg_desc->eExcludes, "acc"); + arg_desc->AddKey("rel_id", "release_id", "Comma-separated list of assembly release id's'", CArgDescriptions::eInteger); + arg_desc->SetDependency("rel_id", arg_desc->eExcludes, "acc"); + arg_desc->SetDependency("rel_id", arg_desc->eExcludes, "acc_file"); + }; + + auto AddFilterSort = [](CArgDescriptions* arg_desc) + { + arg_desc->AddOptionalKey("-filter", "filter", "Get assembly by sequence - filter", CArgDescriptions::eString); + arg_desc->AddOptionalKey("-sort", "sort", "Get assembly by sequence - sort", CArgDescriptions::eString); + }; + + auto_ptr cmds_desc(new CCommandArgDescriptions()); + cmds_desc->SetUsageContext(GetArguments().GetProgramBasename(), "Genomic Collections Service client application"); + + auto_ptr arg_desc(new CArgDescriptions); + arg_desc->SetUsageContext("", "Validate chromosome type and location"); + arg_desc->AddKey("type", "chr_type", "chromosome type", CArgDescriptions::eString); + arg_desc->AddKey("loc", "chr_loc", "chromosome location", CArgDescriptions::eString); + AddCommonArgs(arg_desc.get()); + cmds_desc->AddCommand("get-chrtype-valid", arg_desc.release(), "vc"); + + arg_desc.reset(new CArgDescriptions); + arg_desc->SetUsageContext("", "Get assembly"); + arg_desc->AddDefaultKey("-mode", "AllSequences", "Assembly retrieval mode", CArgDescriptions::eString, "AssemblyOnly"); + AddAccRelId(arg_desc.get()); + AddCommonArgs(arg_desc.get()); + cmds_desc->AddCommand("get-assembly", arg_desc.release(), "ga"); + + arg_desc.reset(new CArgDescriptions); + arg_desc->SetUsageContext("", "Get assemblies containing sequence"); + arg_desc->AddFlag("top_asm", "Return top assembly only"); + AddSeqAcc(arg_desc.get()); + AddFilterSort(arg_desc.get()); + AddCommonArgs(arg_desc.get()); + cmds_desc->AddCommand("get-assembly-by-sequence", arg_desc.release(), "gas"); + + arg_desc.reset(new CArgDescriptions); + arg_desc->SetUsageContext("", "Get assemblies equivalent to a given one"); + arg_desc->AddKey("acc", "ACC_VER", "Assembly accession", CArgDescriptions::eString); + arg_desc->AddKey("equiv", "equivalency", "Get equivalent assemblies - equivalency type", CArgDescriptions::eInteger); + AddCommonArgs(arg_desc.get()); + cmds_desc->AddCommand("get-equivalent-assemblies", arg_desc.release(), "gea"); + + SetupArgDescriptions(cmds_desc.release()); +} + +///////////////////////////////////////////////////////////////////////////// +int CClientGenomicCollectionsSvcApplication::Run(void) +{ + const CArgs& args = GetArgs(); + CNcbiOstream& ostr = args["o"].AsOutputFile(); + + if(args["f"] && NStr::FindNoCase(args["f"].AsString(),"XML") != NPOS) + ostr << MSerial_Xml; + else + ostr << MSerial_AsnText; + + CRef service; + + if(args["cgi"]) service.Reset(new CDirectCGIExec(args["cgi"].AsString(), args["nocache"])); + else if(args["url"]) service.Reset(new CGenollService(args["url"].AsString(), args["nocache"])); + else service.Reset(new CGenollService(args["nocache"])); + + return RunWithService(*service, args, ostr); +} + +static +CGC_AssemblyDesc* GetAssebmlyDesc(CRef& assembly) +{ + return assembly->IsAssembly_set() && assembly->GetAssembly_set().IsSetDesc() ? &assembly->SetAssembly_set().SetDesc() : + assembly->IsUnit() && assembly->GetUnit().IsSetDesc() ? &assembly->SetUnit().SetDesc() : + NULL; + +} + +static +bool isVersionsObject(CRef desc) +{ + return desc->IsUser() && + desc->GetUser().IsSetType() && + desc->GetUser().GetType().IsStr() && + desc->GetUser().GetType().GetStr() == "versions"; +} + +static +CRef RemoveVersions(CRef assembly) +{ + CGC_AssemblyDesc* desc = GetAssebmlyDesc(assembly); + if (desc && desc->CanGetDescr()) + { + list< CRef >& l = desc->SetDescr().Set(); + l.erase(remove_if(l.begin(), l.end(), + isVersionsObject), + l.end()); + } + + return assembly; +} + +static list GetIDs(const string& ids) +{ + list id_list; + NStr::Split(ids, ";,", id_list, NStr::fSplit_Tokenize); + return id_list; +} + +static list GetIDsFromFile(CNcbiIstream& istr) +{ + list accessions; + string line; + while (NcbiGetlineEOL(istr, line)) { + NStr::TruncateSpacesInPlace(line); + if (line.empty() || line[0] == '#') { + continue; + } + accessions.push_back(line); + } + return accessions; +} + +static list GetAccessions(const CArgs& args) +{ + return args["acc"].HasValue() ? GetIDs(args["acc"].AsString()) : + args["acc_file"].HasValue() ? GetIDsFromFile(args["acc_file"].AsInputFile()) : + list(); +} + +int CClientGenomicCollectionsSvcApplication::RunWithService(CGenomicCollectionsService& service, const CArgs& args, CNcbiOstream& ostr) +{ + try { + if(args.GetCommand() == "get-chrtype-valid") + { + ostr << service.ValidateChrType(args["type"].AsString(), args["loc"].AsString()); + } + else if(args.GetCommand() == "get-assembly") + { + if (args["acc"] || args["acc_file"]) + for (auto acc: GetAccessions(args)) ostr << *RemoveVersions(service.GetAssembly(acc, args["-mode"].AsString())); + else if (args["rel_id"]) + for (auto rel_id: GetIDs(args["rel_id"].AsString())) ostr << *RemoveVersions(service.GetAssembly(NStr::StringToInt(rel_id), args["-mode"].AsString())); + else + ERR_POST(Error << "Either accession or release id should be provided"); + } + else if(args.GetCommand() == "get-assembly-by-sequence") + { + list filter_s; + NStr::Split(args["filter"] ? args["filter"].AsString() : "all", ",", filter_s, NStr::fSplit_Tokenize); + + const int filter = accumulate(filter_s.begin(), filter_s.end(), 0, [](int acc, const string& f) + { + return acc | ENUM_METHOD_NAME(EGCClient_GetAssemblyBySequenceFilter)()->FindValue(f); + }); + const int sort = args["sort"] ? CGCClient_GetAssemblyBySequenceRequest::ENUM_METHOD_NAME(ESort)()->FindValue(args["sort"].AsString()) : CGCClient_GetAssemblyBySequenceRequest::eSort_default; + + if (args["top_asm"].HasValue()) + ostr << *service.FindOneAssemblyBySequences(GetAccessions(args), filter, CGCClient_GetAssemblyBySequenceRequest::ESort(sort)); + else + ostr << *service.FindAssembliesBySequences(GetAccessions(args), filter, CGCClient_GetAssemblyBySequenceRequest::ESort(sort)); + } + else if(args.GetCommand() == "get-equivalent-assemblies") + { + ostr << *service.GetEquivalentAssemblies(args["acc"].AsString(), args["equiv"].AsInteger()); + } + } catch (CException& ex) { + ERR_POST(Error << "Caught an exception from client library ..." << ex.what()); + return 1; + } + + return 0; +} + +int main(int argc, const char* argv[]) +{ + GetDiagContext().SetOldPostFormat(false); + return CClientGenomicCollectionsSvcApplication().AppMain(argc, argv); +} diff --git a/c++/src/objects/genomecoll/genomic_collections_cli.cpp b/c++/src/objects/genomecoll/genomic_collections_cli.cpp index da9c1c7e..d4e9fa0d 100644 --- a/c++/src/objects/genomecoll/genomic_collections_cli.cpp +++ b/c++/src/objects/genomecoll/genomic_collections_cli.cpp @@ -1,4 +1,4 @@ -/* $Id: genomic_collections_cli.cpp 512198 2016-08-29 14:17:45Z ivanov $ +/* $Id: genomic_collections_cli.cpp 547389 2017-09-28 17:14:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -56,6 +56,18 @@ BEGIN_NCBI_SCOPE BEGIN_objects_SCOPE + +CGCServiceException::CGCServiceException(const CDiagCompileInfo& diag, const objects::CGCClient_Error& srv_error) + : CGCServiceException(diag, nullptr, + CGCServiceException::EErrCode(srv_error.CanGetError_id() ? srv_error.GetError_id() : CException::eInvalid), + srv_error.GetDescription()) +{} + +const char* CGCServiceException::GetErrCodeString(void) const +{ + return CGCClient_Error::ENUM_METHOD_NAME(EError_id)()->FindName((int)GetErrCode(), true).c_str(); +} + static const STimeout kTimeout = {600, 0}; CGenomicCollectionsService::CGenomicCollectionsService() @@ -80,95 +92,6 @@ static void ValidateAsmAccession(const string& acc) NCBI_THROW(CException, eUnknown, "Invalid accession format: " + acc); } -CRef CGenomicCollectionsService::GetAssembly(const string& acc_, - int level, - int asmAttrFlags, - int chrAttrFlags, - int scafAttrFlags, - int compAttrFlags) -{ - string acc = NStr::TruncateSpaces(acc_); - ValidateAsmAccession(acc); - - CGCClient_GetAssemblyRequest req; - CGCClientResponse reply; - - req.SetAccession(acc); - req.SetLevel(level); - req.SetAssm_flags(asmAttrFlags); - req.SetChrom_flags(chrAttrFlags); - req.SetScaf_flags(scafAttrFlags); - req.SetComponent_flags(compAttrFlags); - - LogRequest(req); - - try { - return AskGet_assembly(req, &reply); - } catch (CException& ex) { - if(reply.IsSrvr_error()) { - NCBI_THROW(CException, eUnknown, reply.GetSrvr_error().GetDescription()); - } - throw; - } -} - - -CRef CGenomicCollectionsService::GetAssembly(int releaseId, - int level, - int asmAttrFlags, - int chrAttrFlags, - int scafAttrFlags, - int compAttrFlags) -{ - CGCClient_GetAssemblyRequest req; - CGCClientResponse reply; - - req.SetRelease_id(releaseId); - req.SetLevel(level); - req.SetAssm_flags(asmAttrFlags); - req.SetChrom_flags(chrAttrFlags); - req.SetScaf_flags(scafAttrFlags); - req.SetComponent_flags(compAttrFlags); - - LogRequest(req); - - try { - return AskGet_assembly(req, &reply); - } catch (CException& ex) { - if(reply.IsSrvr_error()) { - NCBI_THROW(CException, eUnknown, reply.GetSrvr_error().GetDescription()); - } - throw; - } -} - -static string ToStringMode(CGCClient_GetAssemblyRequest::EAssemblyMode mode) -{ - switch (mode) { - case CGCClient_GetAssemblyRequest::eAssemblyMode_assembly_only: return "AssemblyOnly"; - case CGCClient_GetAssemblyRequest::eAssemblyMode_eukaryotic_annotation: return "EukAnnotation"; - case CGCClient_GetAssemblyRequest::eAssemblyMode_prokaryotic_annotation: return "ProkAnnotation"; - case CGCClient_GetAssemblyRequest::eAssemblyMode_entrez_indexing: return "EntrezIndexing"; - case CGCClient_GetAssemblyRequest::eAssemblyMode_assembly_backend: return "AssemblyBackend"; - case CGCClient_GetAssemblyRequest::eAssemblyMode_sequence_names: return "SequenceNames"; - case CGCClient_GetAssemblyRequest::eAssemblyMode_ftp_export: return "AllSequencesWithAlignments"; - default: NCBI_THROW(CException, eUnknown, "GetAssembly: Illegal mode passed."); - } -} - -CRef CGenomicCollectionsService::GetAssembly(const string& acc_, CGCClient_GetAssemblyRequest::EAssemblyMode mode) -{ - string acc = NStr::TruncateSpaces(acc_); - ValidateAsmAccession(acc); - - return GetAssembly(acc, ToStringMode(mode)); -} - -CRef CGenomicCollectionsService::GetAssembly(int releaseId, CGCClient_GetAssemblyRequest::EAssemblyMode mode) -{ - return GetAssembly(releaseId, ToStringMode(mode)); -} - CRef CGenomicCollectionsService::GetAssembly(const string& acc_, const string& mode) { string acc = NStr::TruncateSpaces(acc_); @@ -185,9 +108,8 @@ CRef CGenomicCollectionsService::GetAssembly(const string& acc_, c try { return CCachedAssembly(AskGet_assembly_blob(req, &reply)).Assembly(); } catch (CException& ex) { - if(reply.IsSrvr_error()) { - NCBI_THROW(CException, eUnknown, reply.GetSrvr_error().GetDescription()); - } + if (reply.IsSrvr_error()) + throw CGCServiceException(DIAG_COMPILE_INFO, reply.GetSrvr_error()); throw; } } @@ -205,9 +127,8 @@ CRef CGenomicCollectionsService::GetAssembly(int releaseId, const try { return CCachedAssembly(AskGet_assembly_blob(req, &reply)).Assembly(); } catch (CException& ex) { - if(reply.IsSrvr_error()) { - NCBI_THROW(CException, eUnknown, reply.GetSrvr_error().GetDescription()); - } + if (reply.IsSrvr_error()) + throw CGCServiceException(DIAG_COMPILE_INFO, reply.GetSrvr_error()); throw; } } @@ -225,92 +146,12 @@ string CGenomicCollectionsService::ValidateChrType(const string& chrType, const try { return AskGet_chrtype_valid(req, &reply); } catch (CException& ex) { - if(reply.IsSrvr_error()) { - NCBI_THROW(CException, eUnknown, reply.GetSrvr_error().GetDescription()); - } - throw; - } -} - - -CRef CGenomicCollectionsService::FindBestAssembly(const string& seq_id, int filter_type, int sort_type) -{ - CGCClient_FindBestAssemblyRequest req; - CGCClientResponse reply; - - req.SetSeq_id_acc().push_back(seq_id); - req.SetFilter(filter_type); - req.SetSort(sort_type); - req.SetAssembly_return_limit(1); - - LogRequest(req); - - try { - CRef assm = AskGet_best_assembly(req, &reply); - - return assm->CanGetAssemblies() && !assm->GetAssemblies().empty() ? - CRef(&assm->SetAssemblies().front()->SetAssembly()) : - CRef(); - } catch (const CException& ex) { - if(reply.IsSrvr_error()) { - NCBI_REPORT_EXCEPTION(reply.GetSrvr_error().GetDescription(), ex); - } + if (reply.IsSrvr_error()) + throw CGCServiceException(DIAG_COMPILE_INFO, reply.GetSrvr_error()); throw; } } - -CRef CGenomicCollectionsService::FindBestAssembly(const list& seq_id, int filter_type, int sort_type) -{ - CGCClient_FindBestAssemblyRequest req; - CGCClientResponse reply; - - req.SetSeq_id_acc().assign(seq_id.begin(), seq_id.end()); - req.SetFilter(filter_type); - req.SetSort(sort_type); - req.SetAssembly_return_limit(1); - - LogRequest(req); - - try { - CRef assm = AskGet_best_assembly(req, &reply); - - return assm->CanGetAssemblies() && !assm->GetAssemblies().empty() ? - CRef(assm->SetAssemblies().front()) : - CRef(); - } catch (const CException& ex) { - if(reply.IsSrvr_error()) { - NCBI_REPORT_EXCEPTION(reply.GetSrvr_error().GetDescription().c_str(), ex); - } - throw; - } -} - - -CRef CGenomicCollectionsService::FindAllAssemblies(const list& seq_id, int filter_type, int sort_type) -{ - CGCClient_FindBestAssemblyRequest req; - CGCClientResponse reply; - - req.SetSeq_id_acc().assign(seq_id.begin(), seq_id.end()); - req.SetFilter(filter_type); - req.SetSort(sort_type); - - LogRequest(req); - - try { - CRef assm = AskGet_best_assembly(req, &reply); - - return assm; - } catch (const CException& ex) { - if(reply.IsSrvr_error()) { - NCBI_REPORT_EXCEPTION(reply.GetSrvr_error().GetDescription(), ex); - } - throw; - } -} - - CRef CGenomicCollectionsService::FindOneAssemblyBySequences(const string& sequence_acc, int filter, CGCClient_GetAssemblyBySequenceRequest::ESort sort) { CRef asmseq_info(FindOneAssemblyBySequences(list(1, sequence_acc), filter, sort)); @@ -355,16 +196,12 @@ CRef CGenomicCollectionsService::FindAssemblie LogRequest(req); try { - CRef assm = AskGet_assembly_by_sequence(req, &reply); - - return assm; + return AskGet_assembly_by_sequence(req, &reply); } catch (const CException& ex) { - if(reply.IsSrvr_error()) { - NCBI_REPORT_EXCEPTION(reply.GetSrvr_error().GetDescription(), ex); - } + if (reply.IsSrvr_error()) + throw CGCServiceException(DIAG_COMPILE_INFO, reply.GetSrvr_error()); throw; } - return CRef(); } @@ -379,13 +216,10 @@ CRef CGenomicCollectionsService::GetEquivalentAs LogRequest(req); try { - CRef assm = AskGet_equivalent_assemblies(req, &reply); - - return assm; + return AskGet_equivalent_assemblies(req, &reply); } catch (const CException& ex) { - if(reply.IsSrvr_error()) { - NCBI_REPORT_EXCEPTION(reply.GetSrvr_error().GetDescription(), ex); - } + if (reply.IsSrvr_error()) + throw CGCServiceException(DIAG_COMPILE_INFO, reply.GetSrvr_error()); throw; } } diff --git a/c++/src/objects/homologene/CMakeLists.homologene.asn.txt b/c++/src/objects/homologene/CMakeLists.homologene.asn.txt new file mode 100644 index 00000000..e5884a9f --- /dev/null +++ b/c++/src/objects/homologene/CMakeLists.homologene.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/homologene/Makefile.homologene.lib +# + +set(MODULE homologene) +set(MODULE_IMPORT objects/general/general objects/seqalign/seqalign objects/seqloc/seqloc) +set(MODULE_PATH internal/homologene) + +set(MODULE_EXT "asn") +add_library(homologene ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(homologene + seq +) \ No newline at end of file diff --git a/c++/src/objects/homologene/CMakeLists.txt b/c++/src/objects/homologene/CMakeLists.txt new file mode 100644 index 00000000..567580a5 --- /dev/null +++ b/c++/src/objects/homologene/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.homologene.asn.txt) + diff --git a/c++/src/objects/id1/CMakeLists.id1.asn.txt b/c++/src/objects/id1/CMakeLists.id1.asn.txt new file mode 100644 index 00000000..dd44f786 --- /dev/null +++ b/c++/src/objects/id1/CMakeLists.id1.asn.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/id1/Makefile.id1.lib +# + +set(MODULE id1) +set(MODULE_IMPORT objects/seqloc/seqloc objects/seqset/seqset objects/seq/seq) +set(MODULE_PATH objects/id1) + +set(MODULE_EXT "asn") +add_library(id1 ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(id1 + seqset +) + diff --git a/c++/src/objects/id1/CMakeLists.id1cli.lib.txt b/c++/src/objects/id1/CMakeLists.id1cli.lib.txt new file mode 100644 index 00000000..9733ffba --- /dev/null +++ b/c++/src/objects/id1/CMakeLists.id1cli.lib.txt @@ -0,0 +1,11 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/id1/Makefile.id1cli.lib +# +add_library(id1cli + id1_client id1_client_ +) + +target_link_libraries(id1cli + id1 xconnect +) + diff --git a/c++/src/objects/id1/CMakeLists.txt b/c++/src/objects/id1/CMakeLists.txt new file mode 100644 index 00000000..f1278db1 --- /dev/null +++ b/c++/src/objects/id1/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.id1cli.lib.txt) +include(CMakeLists.id1.asn.txt) + +# Recurse subdirectories +add_subdirectory(test ) diff --git a/c++/src/objects/id2/CMakeLists.id2.asn.txt b/c++/src/objects/id2/CMakeLists.id2.asn.txt new file mode 100644 index 00000000..ea65e830 --- /dev/null +++ b/c++/src/objects/id2/CMakeLists.id2.asn.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/id2/Makefile.id2.lib +# + +set(MODULE id2) +set(MODULE_IMPORT objects/seqsplit/seqsplit objects/seqloc/seqloc) +set(MODULE_PATH objects/id2) + +set(MODULE_EXT "asn") +add_library(id2 ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(id2 + seqsplit +) + diff --git a/c++/src/objects/id2/CMakeLists.id2cli.lib.txt b/c++/src/objects/id2/CMakeLists.id2cli.lib.txt new file mode 100644 index 00000000..9a702055 --- /dev/null +++ b/c++/src/objects/id2/CMakeLists.id2cli.lib.txt @@ -0,0 +1,11 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/id2/Makefile.id2cli.lib +# + +add_library(id2cli + id2_client id2_client_ +) + +target_link_libraries(id2cli + id2 xconnect +) diff --git a/c++/src/objects/id2/CMakeLists.txt b/c++/src/objects/id2/CMakeLists.txt new file mode 100644 index 00000000..c066be13 --- /dev/null +++ b/c++/src/objects/id2/CMakeLists.txt @@ -0,0 +1,8 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.id2cli.lib.txt) +include(CMakeLists.id2.asn.txt) + diff --git a/c++/src/objects/id2/ID2_Reply_Data.cpp b/c++/src/objects/id2/ID2_Reply_Data.cpp new file mode 100644 index 00000000..b3c5a87d --- /dev/null +++ b/c++/src/objects/id2/ID2_Reply_Data.cpp @@ -0,0 +1,83 @@ +/* $Id: ID2_Reply_Data.cpp 534721 2017-05-01 18:13:51Z grichenk $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: ....... + * + * File Description: + * ....... + * + * Remark: + * This code was originally generated by application DATATOOL + * using the following specifications: + * 'id2.asn'. + */ + +// standard includes +#include + +// generated includes +#include + +// generated classes + +BEGIN_NCBI_SCOPE + +BEGIN_objects_SCOPE // namespace ncbi::objects:: + +// destructor +CID2_Reply_Data::~CID2_Reply_Data(void) +{ +} + + +COctetStringSequenceWriter::COctetStringSequenceWriter(TOctetStringSequence& out) + : m_Output(out) +{ +} + +ERW_Result COctetStringSequenceWriter::Write(const void* buffer, + size_t count, + size_t* written) +{ + const char* data = static_cast(buffer); + m_Output.push_back(new TOctetString(data, data+count)); + if ( written ) { + *written = count; + } + return eRW_Success; +} + + +ERW_Result COctetStringSequenceWriter::Flush(void) +{ + return eRW_Success; +} + + +END_objects_SCOPE // namespace ncbi::objects:: + +END_NCBI_SCOPE + +/* Original file checksum: lines: 57, chars: 1731, CRC32: 5659d7c6 */ diff --git a/c++/src/objects/id2/ID2_Request_Packet.cpp b/c++/src/objects/id2/ID2_Request_Packet.cpp index f240aea6..71133d48 100644 --- a/c++/src/objects/id2/ID2_Request_Packet.cpp +++ b/c++/src/objects/id2/ID2_Request_Packet.cpp @@ -1,4 +1,4 @@ -/* $Id: ID2_Request_Packet.cpp 486265 2015-12-02 19:22:44Z vasilche $ +/* $Id: ID2_Request_Packet.cpp 528532 2017-02-23 17:27:58Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -65,6 +65,26 @@ CID2ProcessorResolver::~CID2ProcessorResolver(void) } +CID2ProcessorContext::CID2ProcessorContext(void) +{ +} + + +CID2ProcessorContext::~CID2ProcessorContext(void) +{ +} + + +CID2ProcessorPacketContext::CID2ProcessorPacketContext(void) +{ +} + + +CID2ProcessorPacketContext::~CID2ProcessorPacketContext(void) +{ +} + + CID2Processor::CID2Processor(void) { } @@ -75,6 +95,55 @@ CID2Processor::~CID2Processor(void) } +CID2Processor::TReplies +CID2Processor::ProcessSomeRequests(CID2_Request_Packet& /*packet*/, + CID2ProcessorResolver* /*resolver*/) +{ + return TReplies(); +} + + +bool CID2Processor::ProcessRequest(TReplies& /*replies*/, + CID2_Request& /*request*/, + CID2ProcessorResolver* /*resolver*/) +{ + return false; +} + + +bool CID2Processor::NeedToProcessReplies(void) const +{ + return false; +} + + +CRef CID2Processor::CreateContext(void) +{ + return null; +} + + +CRef +CID2Processor::ProcessPacket(CID2ProcessorContext* /*context*/, + CID2_Request_Packet& packet, + TReplies& replies) +{ + // redirect to old interface by default + replies = move(ProcessSomeRequests(packet)); + return null; +} + + +void CID2Processor::ProcessReply(CID2ProcessorContext* /*context*/, + CID2ProcessorPacketContext* /*packet_context*/, + CID2_Reply& reply, + TReplies& replies) +{ + // copy the original reply by default + replies.push_back(Ref(&reply)); +} + + END_objects_SCOPE // namespace ncbi::objects:: diff --git a/c++/src/objects/id2/id2.asn b/c++/src/objects/id2/id2.asn index 8745bea4..1bc6b895 100644 --- a/c++/src/objects/id2/id2.asn +++ b/c++/src/objects/id2/id2.asn @@ -1,4 +1,4 @@ ---$Revision: 484952 $ +--$Revision: 535051 $ --******************************************************************** -- -- Network Id server network access @@ -16,7 +16,7 @@ NCBI-ID2Access DEFINITIONS ::= BEGIN -EXPORTS ID2-Blob-State; +EXPORTS ID2-Blob-State, ID2-Blob-Id; IMPORTS Seq-id, Seq-loc FROM NCBI-Seqloc ID2S-Chunk-Id, ID2S-Seq-annot-Info FROM NCBI-Seq-split; diff --git a/c++/src/objects/insdseq/CMakeLists.insdseq.asn.txt b/c++/src/objects/insdseq/CMakeLists.insdseq.asn.txt new file mode 100644 index 00000000..6a58168d --- /dev/null +++ b/c++/src/objects/insdseq/CMakeLists.insdseq.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/insdseq/Makefile.insdseq.lib +# + +set(MODULE insdseq) +set(MODULE_IMPORT ) +set(MODULE_PATH ) + +set(MODULE_EXT "asn") +add_library(insdseq ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(insdseq + xser +) \ No newline at end of file diff --git a/c++/src/objects/insdseq/CMakeLists.txt b/c++/src/objects/insdseq/CMakeLists.txt new file mode 100644 index 00000000..b558df36 --- /dev/null +++ b/c++/src/objects/insdseq/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.insdseq.asn.txt) + diff --git a/c++/src/objects/macro/CMakeLists.macro.asn.txt b/c++/src/objects/macro/CMakeLists.macro.asn.txt new file mode 100644 index 00000000..c443ad09 --- /dev/null +++ b/c++/src/objects/macro/CMakeLists.macro.asn.txt @@ -0,0 +1,24 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/macro/Makefile.macro.lib +# + +set(MODULE macro) +set(MODULE_IMPORT ) +set(MODULE_PATH ) + +set(MODULE_EXT "asn") +add_library(macro ${MODULE}__ ${MODULE}___) +add_dependencies(macro + genome_collection seqset +) + + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(macro + seq +) \ No newline at end of file diff --git a/c++/src/objects/macro/CMakeLists.txt b/c++/src/objects/macro/CMakeLists.txt new file mode 100644 index 00000000..b6b69dc3 --- /dev/null +++ b/c++/src/objects/macro/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.macro.asn.txt) + +# Recurse subdirectories +add_subdirectory(unit_test ) diff --git a/c++/src/objects/macro/Location_constraint.cpp b/c++/src/objects/macro/Location_constraint.cpp index 695379c8..990b325e 100644 --- a/c++/src/objects/macro/Location_constraint.cpp +++ b/c++/src/objects/macro/Location_constraint.cpp @@ -1,4 +1,4 @@ -/* $Id: Location_constraint.cpp 459331 2015-02-17 21:53:17Z dicuccio $ +/* $Id: Location_constraint.cpp 539880 2017-06-28 14:56:36Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -57,17 +57,15 @@ CLocation_constraint::~CLocation_constraint(void) { } -bool CLocation_constraint :: x_IsLocationConstraintEmpty() const +bool CLocation_constraint :: IsEmpty() const { - if (GetStrand() != eStrand_constraint_any - || GetSeq_type() != eSeqtype_constraint_any - || GetPartial5() != ePartial_constraint_either - || GetPartial3() != ePartial_constraint_either - || GetLocation_type() != eLocation_type_constraint_any - || (CanGetEnd5() - && GetEnd5().Which() != CLocation_pos_constraint::e_not_set) - || (CanGetEnd3() - && GetEnd3().Which() != CLocation_pos_constraint::e_not_set)) { + if ((IsSetStrand() && GetStrand() != eStrand_constraint_any) + || (IsSetSeq_type() && GetSeq_type() != eSeqtype_constraint_any) + || (IsSetPartial5() && GetPartial5() != ePartial_constraint_either) + || (IsSetPartial3() && GetPartial3() != ePartial_constraint_either) + || (IsSetLocation_type() && GetLocation_type() != eLocation_type_constraint_any) + || (IsSetEnd5() && GetEnd5().Which() != CLocation_pos_constraint::e_not_set) + || (IsSetEnd3() && GetEnd3().Which() != CLocation_pos_constraint::e_not_set)) { return false; } return true; @@ -162,45 +160,43 @@ bool CLocation_constraint :: x_DoesLocationMatchDistanceConstraint(CConstRef IsSetLength() ? bioseq->GetLength() : 0) - pos - 1; + // pre-check to see if bioseq is required + if (loc.IsSetStrand() && loc.GetStrand() == eNa_strand_minus) { + if (IsSetEnd5() && !bioseq) { + return false; + } + } else { + if (IsSetEnd3() && !bioseq) { + return false; + } } - if (loc.GetStrand() == eNa_strand_minus) { - if (CanGetEnd5()) { - if (bioseq.Empty()) { + TSeqPos loc_upstream = loc.GetStart(eExtreme_Positional); + TSeqPos loc_downstream = loc.GetStop(eExtreme_Positional); + TSeqPos downstream_dist = bioseq->GetLength() - loc_downstream; + + if (loc.IsSetStrand() && loc.GetStrand() == eNa_strand_minus) { + if (IsSetEnd5() && !GetEnd5().Match(downstream_dist)) { return false; } - else { - if (!GetEnd5().Match(pos2)) { - return false; - } + if (IsSetEnd3() && !GetEnd3().Match(loc_upstream)) { + return false; } - } - if (CanGetEnd3()) { - return GetEnd3().Match(pos); - } - } - else - { - if (CanGetEnd5() && !GetEnd5().Match(pos)) { - return false; - } - if (CanGetEnd3()) { - if (bioseq.Empty()) { - return false; + } else { + if (IsSetEnd5() && !GetEnd5().Match(loc_upstream)) { + return false; + } + if (IsSetEnd3() && !GetEnd3().Match(downstream_dist)) { + return false; } - return GetEnd3().Match(pos2); - } } + return true; }; bool CLocation_constraint :: Match(const CSeq_feat& feat, CConstRef feat_to, CConstRef feat_bioseq) const { - if (x_IsLocationConstraintEmpty()) { + if (IsEmpty()) { return true; } @@ -241,6 +237,7 @@ bool CLocation_constraint :: Match(const CSeq_feat& feat, CConstRef return true; }; + END_objects_SCOPE // namespace ncbi::objects:: END_NCBI_SCOPE diff --git a/c++/src/objects/macro/Search_func.cpp b/c++/src/objects/macro/Search_func.cpp index 051a429b..4c90ec16 100644 --- a/c++/src/objects/macro/Search_func.cpp +++ b/c++/src/objects/macro/Search_func.cpp @@ -1,4 +1,4 @@ -/* $Id: Search_func.cpp 450811 2014-10-30 17:34:54Z vasilche $ +/* $Id: Search_func.cpp 547096 2017-09-26 12:04:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,23 +34,16 @@ * 'macro.asn'. */ -// standard includes #include - -// generated includes #include -// generated classes +///// This file is included in macro__.cpp (sic!), so these statics are visible elsewhere +static const char* digit_str = "0123456789"; +static const char* alpha_str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; BEGIN_NCBI_SCOPE - BEGIN_objects_SCOPE // namespace ncbi::objects:: -// destructor -CSearch_func::~CSearch_func(void) -{ -} - bool CSearch_func :: Empty() const { switch (Which()) { @@ -94,7 +87,7 @@ bool CSearch_func :: x_StringMayContainPlural(const string& str) const return false; } vector arr; - arr = NStr::Tokenize(str, " ,", arr, NStr::eMergeDelims); + arr = NStr::Split(str, " ,", arr, NStr::fSplit_Tokenize); if (arr.size() == 1) { // doesn't have ', ', or the last char is ', ' len = arr[0].size(); if (len == 1) { @@ -299,14 +292,14 @@ bool CSearch_func :: x_ContainsThreeOrMoreNumbersTogether(const string& str) con string sch_str(str), strtmp; while (!sch_str.empty()) { - p = sch_str.find_first_of(m_digit_str); + p = sch_str.find_first_of(digit_str); if (p == string::npos) { break; } strtmp = CTempString(sch_str).substr(0, p); if (p && ( x_PrecededByOkPrefix(strtmp) || x_InWordBeforeCytochromeOrCoenzyme (strtmp))) { - p2 = sch_str.find_first_not_of(m_digit_str, p+1); + p2 = sch_str.find_first_not_of(digit_str, p+1); if (p2 != string::npos) { sch_str = CTempString(sch_str).substr(p2); num_digits = 0; @@ -342,7 +335,7 @@ bool CSearch_func :: x_StringContainsUnderscore(const string& str) const string strtmp; vector arr; - arr = NStr::Tokenize(str, "_", arr); + arr = NStr::Split(str, "_", arr, 0); for (unsigned i=0; i< arr.size() - 1; i++) { strtmp = arr[i+1]; // strtmp was changed in the FollowedByFamily @@ -374,7 +367,7 @@ bool CSearch_func :: x_IsPrefixPlusNumbers(const string& str, const string& pref return false; } - size_t digit_len = str.find_first_not_of(m_digit_str, pattern_len); + size_t digit_len = str.find_first_not_of(digit_str, pattern_len); if (digit_len != string::npos && digit_len == str.size()) { return true; } diff --git a/c++/src/objects/macro/Simple_replace.cpp b/c++/src/objects/macro/Simple_replace.cpp index 2d4f2166..28f68244 100644 --- a/c++/src/objects/macro/Simple_replace.cpp +++ b/c++/src/objects/macro/Simple_replace.cpp @@ -1,4 +1,4 @@ -/* $Id: Simple_replace.cpp 439441 2014-06-30 14:35:37Z chenj $ +/* $Id: Simple_replace.cpp 535524 2017-05-09 17:15:10Z kachalos $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -89,7 +89,7 @@ bool SkipWeasel(string& str) } vector tokens; - NStr::Tokenize(str, " ", tokens); + NStr::Split(str, " ", tokens, 0); bool rval = false; while (tokens.size() > 0 && s_IsWeaselWord(tokens[0])) { diff --git a/c++/src/objects/macro/String_constraint.cpp b/c++/src/objects/macro/String_constraint.cpp index f42881e4..e9c8c919 100644 --- a/c++/src/objects/macro/String_constraint.cpp +++ b/c++/src/objects/macro/String_constraint.cpp @@ -1,4 +1,4 @@ -/* $Id: String_constraint.cpp 510214 2016-08-11 15:06:21Z ivanov $ +/* $Id: String_constraint.cpp 547096 2017-09-26 12:04:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,25 +34,14 @@ * 'macro.asn'. */ -// standard includes #include - -// generated includes #include #include #include -// generated classes - BEGIN_NCBI_SCOPE - BEGIN_objects_SCOPE // namespace ncbi::objects:: -// destructor -CString_constraint::~CString_constraint(void) -{ -} - bool CString_constraint :: Empty() const { if (GetIs_all_caps() || @@ -169,7 +158,7 @@ static const char* weasels[] = { "unique" }; -bool CString_constraint::x_IsWeasel(const string& str) const +bool CString_constraint::x_IsWeasel(const CTempString& str) const { size_t n = ArraySize(weasels); for (size_t i = 0; i < n; i++) { @@ -180,24 +169,20 @@ bool CString_constraint::x_IsWeasel(const string& str) const return false; }; -string CString_constraint :: x_SkipWeasel(const string& str) const + +string CString_constraint::x_SkipWeasel(const string& str) const { - if (str.empty()) { - return kEmptyStr; - } - string ret_str; - vector arr; - arr = NStr::Tokenize(str, " ", arr); - - bool found = false; - while (!arr.empty() && x_IsWeasel(arr[0])) { - arr.erase(arr.begin()); - found = true; - } + string ret_str; + list arr; + arr = NStr::Split(str, " ", arr, 0); + + bool found = false; + while (!arr.empty() && x_IsWeasel(arr.front())) { + arr.erase(arr.begin()); + found = true; + } - ret_str = found ? NStr::Join(arr, " ") : str; - - return ret_str; + return found ? NStr::Join(arr, " ") : str; }; bool CString_constraint :: x_CaseNCompareEqual(string str1, string str2, size_t len1, bool case_sensitive) const @@ -437,7 +422,7 @@ bool CString_constraint :: x_GetSpanFromHyphenInString(const string& str, size_t bool CString_constraint :: x_StringIsPositiveAllDigits(const string& str) const { - if (str.find_first_not_of(m_digit_str) != string::npos) { + if (str.find_first_not_of(digit_str) != string::npos) { return false; } @@ -469,7 +454,7 @@ bool CString_constraint :: x_IsStringInSpan(const string& str, const string& fir } } else if (x_StringIsPositiveAllDigits(second)) { - prefix_len = first.find_first_of(m_digit_str) + 1; + prefix_len = first.find_first_of(digit_str) + 1; new_str = CTempString(str).substr(prefix_len - 1); new_first = CTempString(first).substr(prefix_len - 1); @@ -521,11 +506,11 @@ bool CString_constraint :: x_IsStringInSpan(const string& str, const string& fir /* determine whether there is a suffix */ size_t idx1, idx2, idx_str; string suf1, suf2, sub_str; - idx1 = first.find_first_not_of(m_digit_str); + idx1 = first.find_first_not_of(digit_str); suf1 = CTempString(first).substr(prefix_len + idx1); - idx2 = second.find_first_not_of(m_digit_str); + idx2 = second.find_first_not_of(digit_str); suf2 = CTempString(second).substr(prefix_len + idx2); - idx_str = str.find_first_not_of(m_digit_str); + idx_str = str.find_first_not_of(digit_str); sub_str = CTempString(str).substr(prefix_len + idx_str); if (suf1 == suf2 && suf1 == sub_str) { /* suffixes match */ @@ -552,12 +537,12 @@ bool CString_constraint :: x_IsStringInSpanInList (const string& str, const stri return false; } - size_t idx = str.find_first_not_of(m_alpha_str); + size_t idx = str.find_first_not_of(alpha_str); if (idx == string::npos) { return false; } - idx = CTempString(str).substr(idx).find_first_not_of(m_digit_str); + idx = CTempString(str).substr(idx).find_first_not_of(digit_str); /* find ranges */ size_t hyphen = list.find('-'); @@ -605,9 +590,9 @@ bool CString_constraint :: x_DoesSingleStringMatchConstraint(const string& str) } else { string tmp_match = CanGetMatch_text() ? GetMatch_text() : kEmptyStr; - if (GetIgnore_weasel()) { - tmp_match = x_SkipWeasel(tmp_match); - } + //if (GetIgnore_weasel()) { + // tmp_match = x_SkipWeasel(tmp_match); + //} if (GetMatch_location() != eString_location_inlist && CanGetIgnore_words()){ rval = x_AdvancedStringMatch(str, tmp_match); } else { @@ -770,5 +755,3 @@ bool CString_constraint::ReplaceStringConstraintPortionInString(string& val, con END_objects_SCOPE // namespace ncbi::objects:: END_NCBI_SCOPE - -/* Original file checksum: lines: 57, chars: 1744, CRC32: 7f791d1c */ diff --git a/c++/src/objects/macro/Suspect_rule.cpp b/c++/src/objects/macro/Suspect_rule.cpp index 1d29ac02..e03d1be8 100644 --- a/c++/src/objects/macro/Suspect_rule.cpp +++ b/c++/src/objects/macro/Suspect_rule.cpp @@ -1,4 +1,4 @@ -/* $Id: Suspect_rule.cpp 513456 2016-09-12 14:18:13Z ivanov $ +/* $Id: Suspect_rule.cpp 547096 2017-09-26 12:04:35Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,37 +34,691 @@ * 'macro.asn'. */ -// standard includes -#include -// generated includes +#include #include -// generated classes - BEGIN_NCBI_SCOPE - BEGIN_objects_SCOPE // namespace ncbi::objects:: -// destructor -CSuspect_rule::~CSuspect_rule(void) + +static bool IsStringConstraintEmpty(const CString_constraint* constraint) +{ + if (!constraint) { + return true; + } + if (constraint->GetIs_all_caps() || constraint->GetIs_all_lower()|| constraint->GetIs_all_punct()) { + return false; + } + if (!constraint->CanGetMatch_text() || constraint->GetMatch_text().empty()) { + return true; + } + return false; +}; + + +static const string SkipWeasel(const string& str) +{ + static CSafeStatic< vector > weasels; + DEFINE_STATIC_FAST_MUTEX(sx_WeaselVecMutex); + { + CFastMutexGuard guard(sx_WeaselVecMutex); + if (weasels->empty()) { + NStr::Split( + "candidate,hypothetical,novel,possible,potential,predicted," + "probable,putative,uncharacterized,unique", + ",", *weasels, 0); + } + } + + if (str.empty()) { + return kEmptyStr; + } + string ret_str; + vector arr; + arr = NStr::Split(str, " ", arr, 0); + if (arr.size() == 1) { + return str; + } + int i; + unsigned len, len_w; + bool find_w; + for (i=0; i< (int)(arr.size() - 1); i++) { + len = arr[i].size(); + find_w = false; + ITERATE (vector , it, *weasels) { + len_w = (*it).size(); + if (len != len_w || !NStr::EqualNocase(arr[i], 0, len, *it)) { + continue; + } + else { + find_w = true; + break; + } + } + if (!find_w) { + break; + } + } + for ( ; i< (int)(arr.size()-1); i++) { + ret_str += arr[i] + ' '; + } + ret_str += arr[arr.size()-1]; + return (ret_str); +} + + +bool IsAllCaps(const string& str) +{ + string up_str = str; + //if (up_str.find_first_not_of(alpha_str) != string::npos) return false; + up_str = NStr::ToUpper(up_str); + if (up_str == str) return true; + else return false; +} + + +bool IsAllLowerCase(const string& str) { + string low_str = str; + //if (low_str.find_first_not_of(alpha_str) != string::npos) return false; + low_str = NStr::ToLower(low_str); + if (low_str == str) return true; + else return false; } -bool CSuspect_rule :: StringMatchesSuspectProductRule(const string& str) const + +bool IsAllPunctuation(const string& str) { - // CSearch_func: only about string - const CSearch_func& func = GetFind(); - if (!func.Empty() && !func.Match(str)) { - return false; - } - else if (CanGetExcept()) { - const CSearch_func& exc_func = GetExcept(); - if (!exc_func.Empty() && exc_func.Match(str)) { - return false; - } - } - return true; + for (unsigned i=0; i< str.size(); i++) { + if (!ispunct(str[i])) return false; + } + return true; +} + + +static bool CaseNCompareEqual(string str1, string str2, unsigned len1, bool case_sensitive) +{ + if (!len1) { + return false; + } + string comp_str1, comp_str2; + comp_str1 = CTempString(str1).substr(0, len1); + comp_str2 = CTempString(str2).substr(0, len1); + if (case_sensitive) { + return (comp_str1 == comp_str2); + } + else { + return (NStr::EqualNocase(comp_str1, 0, len1, comp_str2)); + } +}; + + +static bool AdvancedStringCompare(const string& str, const string& str_match, const CString_constraint* str_cons, bool is_start, unsigned* ini_target_match_len = 0) +{ + if (!str_cons) { + return true; + } + + size_t pos_match = 0, pos_str = 0; + bool wd_case, whole_wd, word_start_m, word_start_s; + bool match = true, recursive_match = false; + unsigned len_m = str_match.size(), len_s = str.size(), target_match_len=0; + string cp_m, cp_s; + bool ig_space = str_cons->GetIgnore_space(); + bool ig_punct = str_cons->GetIgnore_punct(); + bool str_case = str_cons->GetCase_sensitive(); + EString_location loc = str_cons->GetMatch_location(); + unsigned len1, len2; + char ch1, ch2; + vector word_word; + bool has_word = !(str_cons->GetIgnore_words().Get().empty()); + string strtmp; + ITERATE (list >, it, str_cons->GetIgnore_words().Get()) { + strtmp = ((*it)->CanGetWord()) ? (*it)->GetWord() : kEmptyStr; + word_word.push_back(strtmp); + } + + unsigned i; + while (match && pos_match < len_m && pos_str < len_s && !recursive_match) { + cp_m = CTempString(str_match).substr(pos_match); + cp_s = CTempString(str).substr(pos_str); + + /* first, check to see if we're skipping synonyms */ + i=0; + if (has_word) { + ITERATE (list >, it, str_cons->GetIgnore_words().Get()) { + wd_case = (*it)->GetCase_sensitive(); + whole_wd = (*it)->GetWhole_word(); + len1 = word_word[i].size(); + //text match + if (CaseNCompareEqual(word_word[i++], cp_m, len1, wd_case)) { + word_start_m = (!pos_match && is_start) || !isalpha(str_match[pos_match - 1]); + ch1 = (cp_m.size() <= len1) ? ' ' : cp_m[len1]; + + // whole word mch + if (!whole_wd || (!isalpha(ch1) && word_start_m)) { + if ( !(*it)->CanGetSynonyms() || (*it)->GetSynonyms().empty()) { + if (AdvancedStringCompare(cp_s, CTempString(cp_m).substr(len1), str_cons, word_start_m, &target_match_len)) { + recursive_match = true; + break; + } + } + else { + ITERATE (list , sit, (*it)->GetSynonyms()) { + len2 = (*sit).size(); + + // text match + if (CaseNCompareEqual(*sit, cp_s, len2, wd_case)) { + word_start_s = (!pos_str && is_start) || !isalpha(str[pos_str - 1]); + ch2 = (cp_s.size() <= len2) ? ' ' : cp_s[len2]; + // whole word match + if (!whole_wd || (!isalpha(ch2) && word_start_s)) { + if (AdvancedStringCompare(CTempString(cp_s).substr(len2), CTempString(cp_m).substr(len1), str_cons, word_start_m & word_start_s, &target_match_len)) { + recursive_match = true; + break; + } + } + } + } + } + } + } + } + } + + if (!recursive_match) { + if (CaseNCompareEqual(cp_m, cp_s, 1, str_case)) { + pos_match++; + pos_str++; + target_match_len++; + } + else if ( ig_space && (isspace(cp_m[0]) || isspace(cp_s[0])) ) { + if (isspace(cp_m[0])) { + pos_match++; + } + if (isspace(cp_s[0])) { + pos_str++; + target_match_len++; + } + } + else if (ig_punct && ( ispunct(cp_m[0]) || ispunct(cp_s[0]) )) { + if (ispunct(cp_m[0])) { + pos_match++; + } + if (ispunct(cp_s[0])) { + pos_str++; + target_match_len++; + } + } + else { + match = false; + } + } + } + + if (match && !recursive_match) { + while (pos_str < str.size() && ((ig_space && isspace(str[pos_str])) || (ig_punct && ispunct(str[pos_str])))) { + pos_str++; + target_match_len++; + } + while (pos_match < str_match.size() && ((ig_space && isspace(str_match[pos_match])) || (ig_punct && ispunct(str_match[pos_match])))) { + pos_match++; + } + + if (pos_match < str_match.size()) { + match = false; + } + else if ((loc == eString_location_ends || loc == eString_location_equals) && pos_str < len_s) { + match = false; + } + else if (str_cons->GetWhole_word() && (!is_start || (pos_str < len_s && isalpha (str[pos_str])))) { + match = false; + } + } + if (match && ini_target_match_len) { + *ini_target_match_len += target_match_len; + } + return match; +} + + +static bool AdvancedStringMatch(const string& str, const CString_constraint* str_cons) +{ + if (!str_cons) { + return true; + } + bool rval = false; + string match_text = str_cons->CanGetMatch_text() ? str_cons->GetMatch_text() : kEmptyStr; + + if (AdvancedStringCompare(str, match_text, str_cons, true)) { + return true; + } + else if (str_cons->GetMatch_location() == eString_location_starts || str_cons->GetMatch_location() == eString_location_equals) { + return false; + } + else { + size_t pos = 1; + unsigned len = str.size(); + while (!rval && pos < len) { + if (str_cons->GetWhole_word()) { + while (pos < len && isalpha (str[pos-1])) pos++; + } + if (pos < len) { + if (AdvancedStringCompare(CTempString(str).substr(pos), match_text, str_cons, true)) rval = true; + else pos++; + } + } + } + return rval; +} + + +static bool DisallowCharacter(const char ch, bool disallow_slash) +{ + if (isalpha(ch) || isdigit(ch) || ch == '_' || ch == '-') { + return true; + } + else if (disallow_slash && ch == '/') { + return true; + } + return false; +} + + +static string StripUnimportantCharacters(const string& str, bool strip_space, bool strip_punct) +{ + if (str.empty()) { + return kEmptyStr; + } + string result; + result.reserve(str.size()); + string::const_iterator it = str.begin(); + do { + if ((strip_space && isspace(*it)) || (strip_punct && ispunct(*it))) { + } + else { + result += *it; + } + } while (++it != str.end()); + + return result; +} + + +static bool IsWholeWordMatch(const string& start, const size_t& found, const unsigned& match_len, bool disallow_slash = false) +{ + bool rval = true; + unsigned after_idx; + + if (!match_len) { + rval = true; + } + else if (start.empty() || found == string::npos) { + rval = false; + } + else { + if (found) { + if (DisallowCharacter(start[found-1], disallow_slash)) { + return false; + } + } + after_idx = found + match_len; + if (after_idx < start.size() && DisallowCharacter(start[after_idx], disallow_slash)) { + rval = false; + } + } + return rval; +} + + +static bool GetSpanFromHyphenInString(const string& str, const size_t& hyphen, string& first, string& second) +{ + if (!hyphen) { + return false; + } + + /* find range start */ + size_t cp = str.substr(0, hyphen-1).find_last_not_of(' '); + if (cp != string::npos) { + cp = str.substr(0, cp).find_last_not_of(" ,;"); + } + if (cp == string::npos) { + cp = 0; + } + + unsigned len = hyphen - cp; + first = CTempString(str).substr(cp, len); + NStr::TruncateSpacesInPlace(first); + + /* find range end */ + cp = str.find_first_not_of(' ', hyphen+1); + if (cp != string::npos) { + cp = str.find_first_not_of(" ,;"); + } + if (cp == string::npos) { + cp = str.size() -1; + } + + len = cp - hyphen; + if (!isspace (str[cp])) { + len--; + } + second = CTempString(str).substr(hyphen+1, len); + NStr::TruncateSpacesInPlace(second); + + bool rval = true; + if (first.empty() || second.empty()) { + rval = false; + } + else if (!isdigit (first[first.size() - 1]) || !isdigit (second[second.size() - 1])) { + /* if this is a span, then neither end point can end with anything other than a number */ + rval = false; + } + if (!rval) { + first = second = kEmptyStr; + } + return rval; +} + + +static bool StringIsPositiveAllDigits(const string& str) +{ + if (str.find_first_not_of(digit_str) != string::npos) { + return false; + } + return true; +}; + + +static bool IsStringInSpan(const string& str, const string& first, const string& second) +{ + string new_first, new_second, new_str; + if (str.empty()) { + return false; + } + else if (str == first || str == second) { + return true; + } + else if (first.empty() || second.empty()) { + return false; + } + + int str_num, first_num, second_num; + str_num = first_num = second_num = 0; + bool rval = false; + size_t prefix_len; + string comp_str1, comp_str2; + if (StringIsPositiveAllDigits(first)) { + if (StringIsPositiveAllDigits (str) && StringIsPositiveAllDigits (second)) { + str_num = NStr::StringToUInt (str); + first_num = NStr::StringToUInt (first); + second_num = NStr::StringToUInt (second); + if ((str_num > first_num && str_num < second_num) || (str_num > second_num && str_num < first_num)) { + rval = true; + } + } + } + else if (StringIsPositiveAllDigits(second)) { + prefix_len = first.find_first_of(digit_str) + 1; + + new_str = CTempString(str).substr(prefix_len - 1); + new_first = CTempString(first).substr(prefix_len - 1); + comp_str1 = CTempString(str).substr(0, prefix_len); + comp_str2 = CTempString(first).substr(0, prefix_len); + if (comp_str1 == comp_str2 && StringIsPositiveAllDigits (new_str) && StringIsPositiveAllDigits (new_first)) { + first_num = NStr::StringToUInt(new_first); + second_num = NStr::StringToUInt (second); + str_num = NStr::StringToUInt (str); + if ((str_num > first_num && str_num < second_num) || (str_num > second_num && str_num < first_num)) { + rval = true; + } + } + } + else { + /* determine length of prefix */ + prefix_len = 0; + while (prefix_len < first.size() && prefix_len < second.size() && first[prefix_len] == second[prefix_len]) { + prefix_len ++; + } + prefix_len ++; + + comp_str1 = CTempString(str).substr(0, prefix_len); + comp_str2 = CTempString(first).substr(0, prefix_len); + if (prefix_len <= first.size() && prefix_len <= second.size() && isdigit (first[prefix_len-1]) && isdigit (second[prefix_len-1]) && comp_str1 == comp_str2) { + new_first = CTempString(first).substr(prefix_len); + new_second = CTempString(second).substr(prefix_len); + new_str = CTempString(str).substr(prefix_len); + if (StringIsPositiveAllDigits (new_first) && StringIsPositiveAllDigits (new_second) && StringIsPositiveAllDigits (new_str)) { + first_num = NStr::StringToUInt(new_first); + second_num = NStr::StringToUInt (new_second); + str_num = NStr::StringToUInt (new_str); + if ((str_num > first_num && str_num < second_num) || (str_num > second_num && str_num < first_num)) { + rval = true; + } + } + else { + /* determine whether there is a suffix */ + size_t idx1, idx2, idx_str; + string suf1, suf2, sub_str; + idx1 = first.find_first_not_of(digit_str); + suf1 = CTempString(first).substr(prefix_len + idx1); + idx2 = second.find_first_not_of(digit_str); + suf2 = CTempString(second).substr(prefix_len + idx2); + idx_str = str.find_first_not_of(digit_str); + sub_str = CTempString(str).substr(prefix_len + idx_str); + if (suf1 == suf2 && suf1 == sub_str) { + /* suffixes match */ + first_num = NStr::StringToUInt(CTempString(first).substr(prefix_len, idx1)); + second_num = NStr::StringToUInt(CTempString(second).substr(prefix_len, idx2)); + str_num = NStr::StringToUInt(CTempString(str).substr(prefix_len, idx_str)); + if ((str_num > first_num && str_num < second_num) || (str_num > second_num && str_num < first_num)) { + rval = true; + } + } + } + } + } + return rval; +} + + +static bool IsStringInSpanInList(const string& str, const string& list) +{ + if (list.empty() || str.empty()) { + return false; + } + + size_t idx = str.find_first_not_of(alpha_str); + if (idx == string::npos) { + return false; + } + + idx = CTempString(str).substr(idx).find_first_not_of(digit_str); + + /* find ranges */ + size_t hyphen = list.find('-'); + bool rval = false; + string range_start, range_end; + while (hyphen != string::npos && !rval) { + if (!hyphen) { + hyphen = CTempString(list).substr(1).find('-'); + } + else { + if (GetSpanFromHyphenInString(list, hyphen, range_start, range_end)) { + if (IsStringInSpan(str, range_start, range_end)) { + rval = true; + } + } + hyphen = list.find('-', hyphen + 1); + } + } + return rval; +} + + +static bool DoesSingleStringMatchConstraint(const string& str, const CString_constraint* str_cons) +{ + bool rval = false; + string tmp_match; + CString_constraint tmp_cons; + + string this_str(str); + if (!str_cons) { + return true; + } + if (str.empty()) { + return false; + } + if (IsStringConstraintEmpty(str_cons)) { + rval = true; + } + else { + if (str_cons->GetIgnore_weasel()) { + this_str = SkipWeasel(str); + } + if (str_cons->GetIs_all_caps() && !IsAllCaps(this_str)) { + rval = false; + } + else if (str_cons->GetIs_all_lower() && !IsAllLowerCase(this_str)) { + rval = false; + } + else if (str_cons->GetIs_all_punct() && !IsAllPunctuation(this_str)) { + rval = false; + } + else if (!str_cons->CanGetMatch_text() ||str_cons->GetMatch_text().empty()) { + rval = true; + } + else { + tmp_cons.Assign(*str_cons); + tmp_match = tmp_cons.CanGetMatch_text() ? tmp_cons.GetMatch_text() : kEmptyStr; + if (str_cons->GetIgnore_weasel()) { + tmp_cons.SetMatch_text(SkipWeasel(str_cons->GetMatch_text())); + } + if ((str_cons->GetMatch_location() != eString_location_inlist) && str_cons->CanGetIgnore_words()) { + tmp_cons.SetMatch_text(tmp_match); + rval = AdvancedStringMatch(str, &tmp_cons); + } + else { + string search(this_str), pattern(tmp_cons.GetMatch_text()); + bool ig_space = str_cons->GetIgnore_space(); + bool ig_punct = str_cons->GetIgnore_punct(); + if ( (str_cons->GetMatch_location() != eString_location_inlist) && (ig_space || ig_punct)) { + search = StripUnimportantCharacters(search, ig_space, ig_punct); + pattern = StripUnimportantCharacters(pattern, ig_space, ig_punct); + } + + size_t pFound = str_cons->GetCase_sensitive() ? search.find(pattern) : NStr::FindNoCase(search, pattern); + switch (str_cons->GetMatch_location()) { + case eString_location_contains: + if (string::npos == pFound) { + rval = false; + } + else if (str_cons->GetWhole_word()) { + rval = IsWholeWordMatch (search, pFound, pattern.size()); + while (!rval && pFound != string::npos) { + pFound = (str_cons->GetCase_sensitive()) ? + search.find(pattern, pFound+1): + NStr::FindNoCase(search, pattern, pFound+1); + rval = (pFound != string::npos)? + IsWholeWordMatch (search, pFound, pattern.size()): + false; + } + } + else { + rval = true; + } + break; + case eString_location_starts: + if (!pFound) { + rval = (str_cons->GetWhole_word()) ? IsWholeWordMatch (search, pFound, pattern.size()) : true; + } + break; + case eString_location_ends: + while (pFound != string::npos && !rval) { + if ((pFound + pattern.size()) == search.size()) { + rval = str_cons->GetWhole_word() ? IsWholeWordMatch (search, pFound, pattern.size()): true; + /* stop the search, we're at the end of the string */ + pFound = string::npos; + } + else { + if (pattern.empty()) { + pFound = false; + } + else { + pFound = str_cons->GetCase_sensitive() ? search.find(pattern, pFound+1) : NStr::FindNoCase(search, pattern, pFound+1); + } + } + } + break; + case eString_location_equals: + if (str_cons->GetCase_sensitive() && search==pattern) { + rval= true; + } + else if (!str_cons->GetCase_sensitive() && NStr::EqualNocase(search, pattern)) { + rval = true; + } + break; + case eString_location_inlist: + pFound = (str_cons->GetCase_sensitive())? + pattern.find(search) : NStr::FindNoCase(pattern, search); + if (pFound == string::npos) { + rval = false; + } + else { + rval = IsWholeWordMatch(pattern, pFound, search.size(), true); + while (!rval && pFound != string::npos) { + pFound = (str_cons->GetCase_sensitive()) ? CTempString(pattern).substr(pFound + 1).find(search) : NStr::FindNoCase(CTempString(pattern).substr(pFound + 1), search); + if (pFound != string::npos) { + rval = IsWholeWordMatch(pattern, pFound, str.size(), true); + } + } + } + if (!rval) { + /* look for spans */ + rval = IsStringInSpanInList (search, pattern); + } + break; + default: break; + } + } + } + } + return rval; +} + + +bool CSuspect_rule::StringMatchesSuspectProductRule(const string& str) const +{ + // CSearch_func: only about string + const CSearch_func& func = GetFind(); + if (!func.Empty() && !func.Match(str)) { + return false; + } + if (CanGetExcept()) { + const CSearch_func& exc_func = GetExcept(); + if (!exc_func.Empty() && exc_func.Match(str)) { + return false; + } + } + if (CanGetFeat_constraint()) { + const CConstraint_choice_set& conset = GetFeat_constraint(); + ITERATE (list >, it, conset.Get()) { + if ((*it)->Which() != CConstraint_choice::e_String) { + cout << "Bad suspect rule constraint!\n"; + continue; + } + const CString_constraint& constr = (*it)->GetString(); + bool b = DoesSingleStringMatchConstraint (str, &constr); + if (constr.GetNot_present()) { + b = !b; + } + if (!b) { + return false; + } + } + } + return true; }; @@ -186,6 +840,8 @@ string CSuspect_rule::SummarizeSearchFunc(const CSearch_func& func) const case CSearch_func::e_Has_term: //if (short_version) summ = "contains " + strtmp; return "contains \'" + func.GetHas_term() + "\' at start or separated from other letters by numbers, spaces, or punctuation, but does not also contain 'domain'"; + default: + break; } return "Unknown search function"; } @@ -200,6 +856,8 @@ string CSuspect_rule::SummarizeEndDistance(const CLocation_pos_constraint& pos) return "no more than " + NStr::IntToString(pos.GetMax_dist_from_end()); case CLocation_pos_constraint::e_Min_dist_from_end: return "no less than " + NStr::IntToString(pos.GetMin_dist_from_end()); + default: + break; } return kEmptyStr; } @@ -385,6 +1043,8 @@ string CSuspect_rule::SummarizeConstraint(const CConstraint_choice& choice) cons return "[[TRANSLATION CONSTRAINT]]"; //phrase = SummarizeTranslationConstraint (cons_choice.GetTranslation()); break; + default: + break; } return kEmptyStr; } diff --git a/c++/src/objects/macro/Suspect_rule_set.cpp b/c++/src/objects/macro/Suspect_rule_set.cpp index 17f433e8..c280177f 100644 --- a/c++/src/objects/macro/Suspect_rule_set.cpp +++ b/c++/src/objects/macro/Suspect_rule_set.cpp @@ -1,4 +1,4 @@ -/* $Id: Suspect_rule_set.cpp 467165 2015-05-11 13:55:19Z kachalos $ +/* $Id: Suspect_rule_set.cpp 542461 2017-07-31 17:34:25Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -59,6 +59,7 @@ DEFINE_STATIC_FAST_MUTEX(s_OrganelleProductRulesMutex); static CRef s_OrganelleProductRules; static bool s_ProductRulesInitialized = false; +static string s_ProductRulesFileName; DEFINE_STATIC_FAST_MUTEX(s_ProductRulesMutex); static CRef s_ProductRules; @@ -79,12 +80,14 @@ static void s_InitializeOrganelleProductRules(const string& name) string file = name.empty() ? g_FindDataFile("organelle_products.prt") : name; if ( !file.empty() ) { + LOG_POST("Reading from " + file + " for organelle products"); auto_ptr in; in.reset(CObjectIStream::Open(file, eSerial_AsnText)); string header = in->ReadFileHeader(); in->Read(ObjectInfo(*s_OrganelleProductRules), CObjectIStream::eNoFileHeader); } if (!s_OrganelleProductRules->IsSet()) { + LOG_POST("Falling back on built-in data for organelle products"); size_t num_lines = sizeof (s_Defaultorganelleproducts) / sizeof (char *); string all_rules = ""; for (size_t i = 0; i < num_lines; i++) { @@ -101,19 +104,22 @@ static void s_InitializeOrganelleProductRules(const string& name) static void s_InitializeProductRules(const string& name) { CFastMutexGuard GUARD(s_ProductRulesMutex); - if (s_ProductRulesInitialized) { + if (s_ProductRulesInitialized && name == s_ProductRulesFileName) { return; } s_ProductRules.Reset(new CSuspect_rule_set()); + s_ProductRulesFileName = name; string file = name.empty() ? g_FindDataFile("product_rules.prt") : name; if ( !file.empty() ) { + LOG_POST("Reading from " + file + " for suspect product rules"); auto_ptr in; in.reset(CObjectIStream::Open(file, eSerial_AsnText)); string header = in->ReadFileHeader(); in->Read(ObjectInfo(*s_ProductRules), CObjectIStream::eNoFileHeader); } if (!s_ProductRules->IsSet()) { + LOG_POST("Falling back on built-in data for suspect product rules"); size_t num_lines = sizeof (s_Defaultproductrules) / sizeof (char *); string all_rules = ""; for (size_t i = 0; i < num_lines; i++) { diff --git a/c++/src/objects/macro/product_rules.inc b/c++/src/objects/macro/product_rules.inc index d4b53f13..8e1a9eb8 100644 --- a/c++/src/objects/macro/product_rules.inc +++ b/c++/src/objects/macro/product_rules.inc @@ -1,4 +1,4 @@ -/* $Id: product_rules.inc 507924 2016-07-22 15:32:29Z kachalos $ +/* $Id: product_rules.inc 528155 2017-02-21 14:28:37Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -23,7 +23,7 @@ * * =========================================================================== * - * Author: NCBI developers + * Author: Jonathan Kans et al. * * File Description: * Built-in copy of product_rules.prt. @@ -5377,7 +5377,7 @@ static const char* const s_Defaultproductrules[] = { " case-sensitive FALSE ,", " ignore-space FALSE ,", " ignore-punct FALSE ,", - " whole-word FALSE ,", + " whole-word TRUE ,", " not-present FALSE ,", " is-all-caps FALSE ,", " is-all-lower FALSE ,", @@ -10793,6 +10793,31 @@ static const char* const s_Defaultproductrules[] = { " {", " find", " string-constraint {", + " match-text \"memrbane\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel FALSE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"membrane\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", " match-text \"Methionine\" ,", " match-location equals ,", " case-sensitive FALSE ,", @@ -15667,6 +15692,31 @@ static const char* const s_Defaultproductrules[] = { " {", " find", " string-constraint {", + " match-text \"putatiuve\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel FALSE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"putative\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", " match-text \"putaitve\" ,", " match-location contains ,", " case-sensitive FALSE ,", @@ -21901,7 +21951,7 @@ static const char* const s_Defaultproductrules[] = { " ignore-weasel TRUE ,", " is-first-cap FALSE ,", " is-first-each-cap FALSE } ,", - " rule-type none ,", + " rule-type database ,", " fatal TRUE } ,", " {", " find", @@ -21927,5 +21977,538 @@ static const char* const s_Defaultproductrules[] = { " whole-string FALSE ,", " weasel-to-putative FALSE } ,", " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"prootein\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel FALSE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"protein\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"polymersae\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word TRUE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel FALSE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"polymerase\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"nulcease\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"nuclease\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"hypothetical-related protein\" ,", + " match-location equals ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type hypothetical ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"hypothetical protein\" ,", + " whole-string TRUE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"residue\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " except", + " string-constraint {", + " match-text \"dihydrolipoyllysine-residue\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel FALSE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type description ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"proteins of 100 residues with WXG\" ,", + " match-location equals ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type hypothetical ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"hypothetical protein\" ,", + " whole-string TRUE ,", + " weasel-to-putative FALSE } ,", + " move-to-note TRUE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"no hit\" ,", + " match-location equals ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type hypothetical ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"hypothetical protein\" ,", + " whole-string TRUE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"protein of 100 residues with WXG\" ,", + " match-location equals ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type hypothetical ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"hypothetical protein\" ,", + " whole-string TRUE ,", + " weasel-to-putative FALSE } ,", + " move-to-note TRUE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"subnuit\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word TRUE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"subunit\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"repessor\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word TRUE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"repressor\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"strucural\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"structural\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"Anopheles\" ,", + " match-location equals ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type remove-organism-name ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"hypothetical protein\" ,", + " whole-string TRUE ,", + " weasel-to-putative FALSE } ,", + " move-to-note TRUE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"Arabidopsis\" ,", + " match-location equals ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type remove-organism-name ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"hypothetical protein\" ,", + " whole-string TRUE ,", + " weasel-to-putative FALSE } ,", + " move-to-note TRUE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"scafold\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"scaffold\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"pupative\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"putative\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"unnamed protein product-like\" ,", + " match-location equals ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type hypothetical ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"hypothetical protein\" ,", + " whole-string TRUE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"glyosyltransferase\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"glycosyltransferase\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"14-3-3\" ,", + " match-location equals ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"14-3-3 protein\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"parolog\" ,", + " match-location contains ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type typo ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"paralog\" ,", + " whole-string FALSE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"unassigned protein\" ,", + " match-location equals ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type hypothetical ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"hypothetical protein\" ,", + " whole-string TRUE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", + " fatal FALSE } ,", + " {", + " find", + " string-constraint {", + " match-text \"to fill in\" ,", + " match-location equals ,", + " case-sensitive FALSE ,", + " ignore-space FALSE ,", + " ignore-punct FALSE ,", + " whole-word FALSE ,", + " not-present FALSE ,", + " is-all-caps FALSE ,", + " is-all-lower FALSE ,", + " is-all-punct FALSE ,", + " ignore-weasel TRUE ,", + " is-first-cap FALSE ,", + " is-first-each-cap FALSE } ,", + " rule-type hypothetical ,", + " replace {", + " replace-func", + " simple-replace {", + " replace \"hypothetical protein\" ,", + " whole-string TRUE ,", + " weasel-to-putative FALSE } ,", + " move-to-note FALSE } ,", " fatal FALSE } }" }; diff --git a/c++/src/objects/macro/product_rules.prt b/c++/src/objects/macro/product_rules.prt index 06f1abfe..737e419a 100644 --- a/c++/src/objects/macro/product_rules.prt +++ b/c++/src/objects/macro/product_rules.prt @@ -5344,7 +5344,7 @@ Suspect-rule-set ::= { case-sensitive FALSE , ignore-space FALSE , ignore-punct FALSE , - whole-word FALSE , + whole-word TRUE , not-present FALSE , is-all-caps FALSE , is-all-lower FALSE , @@ -10757,6 +10757,31 @@ Suspect-rule-set ::= { weasel-to-putative FALSE } , move-to-note FALSE } , fatal FALSE } , + { + find + string-constraint { + match-text "memrbane" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel FALSE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "membrane" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , { find string-constraint { @@ -15631,6 +15656,31 @@ Suspect-rule-set ::= { weasel-to-putative FALSE } , move-to-note FALSE } , fatal FALSE } , + { + find + string-constraint { + match-text "putatiuve" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel FALSE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "putative" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , { find string-constraint { @@ -21868,7 +21918,7 @@ Suspect-rule-set ::= { ignore-weasel TRUE , is-first-cap FALSE , is-first-each-cap FALSE } , - rule-type none , + rule-type database , fatal TRUE } , { find @@ -21894,4 +21944,539 @@ Suspect-rule-set ::= { whole-string FALSE , weasel-to-putative FALSE } , move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "prootein" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel FALSE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "protein" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "polymersae" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word TRUE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel FALSE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "polymerase" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "nulcease" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "nuclease" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "hypothetical-related protein" , + match-location equals , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type hypothetical , + replace { + replace-func + simple-replace { + replace "hypothetical protein" , + whole-string TRUE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "residue" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + except + string-constraint { + match-text "dihydrolipoyllysine-residue" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel FALSE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type description , + fatal FALSE } , + { + find + string-constraint { + match-text "proteins of 100 residues with WXG" , + match-location equals , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type hypothetical , + replace { + replace-func + simple-replace { + replace "hypothetical protein" , + whole-string TRUE , + weasel-to-putative FALSE } , + move-to-note TRUE } , + fatal FALSE } , + { + find + string-constraint { + match-text "no hit" , + match-location equals , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type hypothetical , + replace { + replace-func + simple-replace { + replace "hypothetical protein" , + whole-string TRUE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "protein of 100 residues with WXG" , + match-location equals , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type hypothetical , + replace { + replace-func + simple-replace { + replace "hypothetical protein" , + whole-string TRUE , + weasel-to-putative FALSE } , + move-to-note TRUE } , + fatal FALSE } , + { + find + string-constraint { + match-text "subnuit" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word TRUE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "subunit" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "repessor" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word TRUE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "repressor" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "strucural" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "structural" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "Anopheles" , + match-location equals , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type remove-organism-name , + replace { + replace-func + simple-replace { + replace "hypothetical protein" , + whole-string TRUE , + weasel-to-putative FALSE } , + move-to-note TRUE } , + fatal FALSE } , + { + find + string-constraint { + match-text "Arabidopsis" , + match-location equals , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type remove-organism-name , + replace { + replace-func + simple-replace { + replace "hypothetical protein" , + whole-string TRUE , + weasel-to-putative FALSE } , + move-to-note TRUE } , + fatal FALSE } , + { + find + string-constraint { + match-text "scafold" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "scaffold" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "pupative" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "putative" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "unnamed protein product-like" , + match-location equals , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type hypothetical , + replace { + replace-func + simple-replace { + replace "hypothetical protein" , + whole-string TRUE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "glyosyltransferase" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "glycosyltransferase" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "14-3-3" , + match-location equals , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "14-3-3 protein" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "parolog" , + match-location contains , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type typo , + replace { + replace-func + simple-replace { + replace "paralog" , + whole-string FALSE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "unassigned protein" , + match-location equals , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type hypothetical , + replace { + replace-func + simple-replace { + replace "hypothetical protein" , + whole-string TRUE , + weasel-to-putative FALSE } , + move-to-note FALSE } , + fatal FALSE } , + { + find + string-constraint { + match-text "to fill in" , + match-location equals , + case-sensitive FALSE , + ignore-space FALSE , + ignore-punct FALSE , + whole-word FALSE , + not-present FALSE , + is-all-caps FALSE , + is-all-lower FALSE , + is-all-punct FALSE , + ignore-weasel TRUE , + is-first-cap FALSE , + is-first-each-cap FALSE } , + rule-type hypothetical , + replace { + replace-func + simple-replace { + replace "hypothetical protein" , + whole-string TRUE , + weasel-to-putative FALSE } , + move-to-note FALSE } , fatal FALSE } } + + diff --git a/c++/src/objects/medlars/CMakeLists.medlars.asn.txt b/c++/src/objects/medlars/CMakeLists.medlars.asn.txt new file mode 100644 index 00000000..5980057e --- /dev/null +++ b/c++/src/objects/medlars/CMakeLists.medlars.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/medlars/Makefile.medlars.lib +# + +set(MODULE medlars) +set(MODULE_IMPORT objects/general/general objects/biblio/biblio) +set(MODULE_PATH objects/medlars) + +set(MODULE_EXT "asn") +add_library(medlars ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + pubmed +) + +target_link_libraries(medlars + biblio +) \ No newline at end of file diff --git a/c++/src/objects/medlars/CMakeLists.txt b/c++/src/objects/medlars/CMakeLists.txt new file mode 100644 index 00000000..c2d71839 --- /dev/null +++ b/c++/src/objects/medlars/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.medlars.asn.txt) + diff --git a/c++/src/objects/medline/CMakeLists.medline.asn.txt b/c++/src/objects/medline/CMakeLists.medline.asn.txt new file mode 100644 index 00000000..80676664 --- /dev/null +++ b/c++/src/objects/medline/CMakeLists.medline.asn.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/medline/Makefile.medline.lib +# + +set(MODULE medline) +set(MODULE_IMPORT objects/general/general objects/biblio/biblio) +set(MODULE_PATH objects/medline) + +set(MODULE_EXT "asn") +add_library(medline ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(medline + biblio +) + diff --git a/c++/src/objects/medline/CMakeLists.txt b/c++/src/objects/medline/CMakeLists.txt new file mode 100644 index 00000000..659fb8bd --- /dev/null +++ b/c++/src/objects/medline/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.medline.asn.txt) + diff --git a/c++/src/objects/mim/CMakeLists.mim.asn.txt b/c++/src/objects/mim/CMakeLists.mim.asn.txt new file mode 100644 index 00000000..ee294da7 --- /dev/null +++ b/c++/src/objects/mim/CMakeLists.mim.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/mim/Makefile.mim.lib +# + +set(MODULE mim) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/mim) + +set(MODULE_EXT "asn") +add_library(mim ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(mim + xser +) \ No newline at end of file diff --git a/c++/src/objects/mim/CMakeLists.txt b/c++/src/objects/mim/CMakeLists.txt new file mode 100644 index 00000000..2c558c0c --- /dev/null +++ b/c++/src/objects/mim/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.mim.asn.txt) + diff --git a/c++/src/objects/mla/CMakeLists.mla.asn.txt b/c++/src/objects/mla/CMakeLists.mla.asn.txt new file mode 100644 index 00000000..b27a6d6a --- /dev/null +++ b/c++/src/objects/mla/CMakeLists.mla.asn.txt @@ -0,0 +1,21 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/mla/Makefile.mla.lib +# + +set(MODULE mla) +set(MODULE_IMPORT objects/ /biblio objects/medline/medline objects/medlars/medlars objects/pubmed/pubmed objects/pub/pub) +set(MODULE_PATH objects/mla) + +set(MODULE_EXT "asn") +add_library(mla ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + + +target_link_libraries(${MODULE} + medlars pub +) + +target_link_libraries(mla + medlars pub pubmed +) \ No newline at end of file diff --git a/c++/src/objects/mla/CMakeLists.mlacli.lib.txt b/c++/src/objects/mla/CMakeLists.mlacli.lib.txt new file mode 100644 index 00000000..1d2e2449 --- /dev/null +++ b/c++/src/objects/mla/CMakeLists.mlacli.lib.txt @@ -0,0 +1,10 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/mla/Makefile.mlacli.lib +# +add_library(mlacli + mla_client mla_client_ +) + +target_link_libraries(mlacli + mla xconnect +) diff --git a/c++/src/objects/mla/CMakeLists.txt b/c++/src/objects/mla/CMakeLists.txt new file mode 100644 index 00000000..555ebd9a --- /dev/null +++ b/c++/src/objects/mla/CMakeLists.txt @@ -0,0 +1,8 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.mlacli.lib.txt) +include(CMakeLists.mla.asn.txt) + diff --git a/c++/src/objects/mmdb/CMakeLists.mmdb.lib.txt b/c++/src/objects/mmdb/CMakeLists.mmdb.lib.txt new file mode 100644 index 00000000..30306414 --- /dev/null +++ b/c++/src/objects/mmdb/CMakeLists.mmdb.lib.txt @@ -0,0 +1,21 @@ +# +# Autogenerated from /net/nasan50/vol/gpipe_dev/dicuccio/cpp-toolkit/cpp-cmake/src/objects/mmdb/Makefile.mmdb.lib +# +set(MODULE_IMPORT ) +set(MODULE_EXT "asn") + +set(ASN mmdb1 mmdb2 mmdb3) + +foreach(ASN_FILE ${ASN}) + set(MODULE ${ASN_FILE}) + set(MODULE_PATH objects/${ASN_FILE}) + set(MODULE_PATH_RELATIVE "objects/${ASN_FILE}") + RunDatatool("${ASN_FILE}" "${MODULE_IMPORT}") + SET(MODULE_FILES ${MODULE_FILES} ${NEW_MODULE_FILES}) +endforeach(ASN_FILE) + +add_library(mmdb ${MODULE_FILES}) + +target_link_libraries(mmdb + seq +) diff --git a/c++/src/objects/mmdb/CMakeLists.txt b/c++/src/objects/mmdb/CMakeLists.txt new file mode 100644 index 00000000..31fb3b24 --- /dev/null +++ b/c++/src/objects/mmdb/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.mmdb.lib.txt) + diff --git a/c++/src/objects/mmdb/Makefile.mmdb.lib b/c++/src/objects/mmdb/Makefile.mmdb.lib index f5886c56..a8d6d456 100644 --- a/c++/src/objects/mmdb/Makefile.mmdb.lib +++ b/c++/src/objects/mmdb/Makefile.mmdb.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.mmdb.lib 427424 2014-02-20 13:38:50Z gouriano $ +# $Id: Makefile.mmdb.lib 536933 2017-05-24 16:39:14Z ucko $ WATCHERS = ucko @@ -9,6 +9,7 @@ CPPFLAGS = -I$(srcdir) -I$(top_srcdir)/src/objects/mmdb $(ORIG_CPPFLAGS) LIB = mmdb SRC = $(ASN:%=%__) $(ASN:%=%___) +DLL_LIB = $(SEQ_LIBS) USES_LIBRARIES = \ $(SEQ_LIBS) pub diff --git a/c++/src/objects/ncbimime/CMakeLists.ncbimime.asn.txt b/c++/src/objects/ncbimime/CMakeLists.ncbimime.asn.txt new file mode 100644 index 00000000..b9a47d4d --- /dev/null +++ b/c++/src/objects/ncbimime/CMakeLists.ncbimime.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/ncbimime/Makefile.ncbimime.lib +# + +set(MODULE ncbimime) +set(MODULE_IMPORT objects/general/general objects/ /biblio objects/pub/pub objects/medline/medline objects/seq/seq objects/seqset/seqset objects/seqloc/seqloc objects/seqfeat/seqfeat objects/mmdb1/mmdb1 objects/mmdb2/mmdb2 objects/mmdb3/mmdb3 objects/cn3d/cn3d objects/cdd/cdd) +set(MODULE_PATH objects/ncbimime) + +set(MODULE_EXT "asn") +add_library(ncbimime ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + cdd cn3d seqset +) + +target_link_libraries(ncbimime + cdd +) \ No newline at end of file diff --git a/c++/src/objects/ncbimime/CMakeLists.txt b/c++/src/objects/ncbimime/CMakeLists.txt new file mode 100644 index 00000000..15c9518a --- /dev/null +++ b/c++/src/objects/ncbimime/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.ncbimime.asn.txt) + +# Recurse subdirectories +add_subdirectory(test ) diff --git a/c++/src/objects/objprt/CMakeLists.objprt.asn.txt b/c++/src/objects/objprt/CMakeLists.objprt.asn.txt new file mode 100644 index 00000000..bd202fa5 --- /dev/null +++ b/c++/src/objects/objprt/CMakeLists.objprt.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/objprt/Makefile.objprt.lib +# + +set(MODULE objprt) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/objprt) + +set(MODULE_EXT "asn") +add_library(objprt ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(objprt + xser +) \ No newline at end of file diff --git a/c++/src/objects/objprt/CMakeLists.txt b/c++/src/objects/objprt/CMakeLists.txt new file mode 100644 index 00000000..955903a8 --- /dev/null +++ b/c++/src/objects/objprt/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.objprt.asn.txt) + diff --git a/c++/src/objects/omssa/CMakeLists.omssa.asn.txt b/c++/src/objects/omssa/CMakeLists.omssa.asn.txt new file mode 100644 index 00000000..e5e1203d --- /dev/null +++ b/c++/src/objects/omssa/CMakeLists.omssa.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/omssa/Makefile.omssa.lib +# + +set(MODULE omssa) +set(MODULE_IMPORT objects/seq/seq) +set(MODULE_PATH objects/omssa) + +set(MODULE_EXT "asn") +add_library(omssa ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(omssa + seq +) \ No newline at end of file diff --git a/c++/src/objects/omssa/CMakeLists.txt b/c++/src/objects/omssa/CMakeLists.txt new file mode 100644 index 00000000..7ea59642 --- /dev/null +++ b/c++/src/objects/omssa/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.omssa.asn.txt) + diff --git a/c++/src/objects/omssa/Makefile.omssa.lib b/c++/src/objects/omssa/Makefile.omssa.lib index 6df2ebfe..0c1195a6 100644 --- a/c++/src/objects/omssa/Makefile.omssa.lib +++ b/c++/src/objects/omssa/Makefile.omssa.lib @@ -3,6 +3,7 @@ APP_DEP = seq LIB = omssa SRC = omssa__ omssa___ +DLL_LIB = $(SEQ_LIBS) USES_LIBRARIES = \ $(SEQ_LIBS) pub diff --git a/c++/src/objects/pcassay/CMakeLists.pcassay.asn.txt b/c++/src/objects/pcassay/CMakeLists.pcassay.asn.txt new file mode 100644 index 00000000..3db5f403 --- /dev/null +++ b/c++/src/objects/pcassay/CMakeLists.pcassay.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/pcassay/Makefile.pcassay.lib +# + +set(MODULE pcassay) +set(MODULE_IMPORT objects/general/general objects/pub/pub objects/seqfeat/seqfeat objects/pcsubstance/pcsubstance) +set(MODULE_PATH objects/pcassay/pcassay) + +set(MODULE_EXT "asn") +add_library(pcassay ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + pcsubstance seq +) + +target_link_libraries(pcassay + pcsubstance seq +) \ No newline at end of file diff --git a/c++/src/objects/pcassay/CMakeLists.txt b/c++/src/objects/pcassay/CMakeLists.txt new file mode 100644 index 00000000..18da5ee8 --- /dev/null +++ b/c++/src/objects/pcassay/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.pcassay.asn.txt) + diff --git a/c++/src/objects/pcsubstance/CMakeLists.pcsubstance.asn.txt b/c++/src/objects/pcsubstance/CMakeLists.pcsubstance.asn.txt new file mode 100644 index 00000000..a4ac8d70 --- /dev/null +++ b/c++/src/objects/pcsubstance/CMakeLists.pcsubstance.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/pcsubstance/Makefile.pcsubstance.lib +# + +set(MODULE pcsubstance) +set(MODULE_IMPORT objects/general/general objects/pub/pub) +set(MODULE_PATH objects/pcsubstance) + +set(MODULE_EXT "asn") +add_library(pcsubstance ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + pub +) + +target_link_libraries(pcsubstance + pub +) \ No newline at end of file diff --git a/c++/src/objects/pcsubstance/CMakeLists.txt b/c++/src/objects/pcsubstance/CMakeLists.txt new file mode 100644 index 00000000..4ea57477 --- /dev/null +++ b/c++/src/objects/pcsubstance/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.pcsubstance.asn.txt) + diff --git a/c++/src/objects/proj/CMakeLists.proj.asn.txt b/c++/src/objects/proj/CMakeLists.proj.asn.txt new file mode 100644 index 00000000..7f352661 --- /dev/null +++ b/c++/src/objects/proj/CMakeLists.proj.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/proj/Makefile.proj.lib +# + +set(MODULE proj) +set(MODULE_IMPORT objects/general/general objects/biblio/biblio objects/pubmed/pubmed objects/seqloc/seqloc objects/seq/seq objects/seqset/seqset) +set(MODULE_PATH objects/proj) + +set(MODULE_EXT "asn") +add_library(proj ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + pubmed seqset +) + +target_link_libraries(proj + pubmed seqset +) \ No newline at end of file diff --git a/c++/src/objects/proj/CMakeLists.txt b/c++/src/objects/proj/CMakeLists.txt new file mode 100644 index 00000000..6c2e68d0 --- /dev/null +++ b/c++/src/objects/proj/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.proj.asn.txt) + diff --git a/c++/src/objects/pub/CMakeLists.pub.asn.txt b/c++/src/objects/pub/CMakeLists.pub.asn.txt new file mode 100644 index 00000000..5ee57436 --- /dev/null +++ b/c++/src/objects/pub/CMakeLists.pub.asn.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/pub/Makefile.pub.lib +# + +set(MODULE pub) +set(MODULE_IMPORT objects/general/general objects/ /biblio objects/medline/medline) +set(MODULE_PATH objects/pub) + +set(MODULE_EXT "asn") +add_library(pub ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(pub + medline +) diff --git a/c++/src/objects/pub/CMakeLists.txt b/c++/src/objects/pub/CMakeLists.txt new file mode 100644 index 00000000..cb1c8aa4 --- /dev/null +++ b/c++/src/objects/pub/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.pub.asn.txt) + diff --git a/c++/src/objects/pub/Pub.cpp b/c++/src/objects/pub/Pub.cpp index 4ad65cdb..1bc5d870 100644 --- a/c++/src/objects/pub/Pub.cpp +++ b/c++/src/objects/pub/Pub.cpp @@ -1,4 +1,4 @@ -/* $Id: Pub.cpp 498027 2016-04-12 18:56:44Z grichenk $ +/* $Id: Pub.cpp 548112 2017-10-10 17:31:15Z fukanchi $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -197,6 +197,30 @@ const CAuth_list& CPub::GetAuthors (void) const } } +CAuth_list& CPub::SetAuthors (void) +{ + switch (Which()) { + case CPub::e_Gen : + return (SetGen().SetAuthors()); + case CPub::e_Sub : + return (SetSub().SetAuthors()); + case CPub::e_Article : + return (SetArticle().SetAuthors()); + case CPub::e_Book : + return (SetBook().SetAuthors()); + case CPub::e_Proc : + return (SetProc().SetBook().SetAuthors()); + case CPub::e_Patent : + return (SetPatent().SetAuthors()); + case CPub::e_Man : + return (SetMan().SetCit().SetAuthors()); + default : + NCBI_THROW(CSerialException, eNotImplemented, + "CPub::SetAuthors: unsupported entry type " + + SelectionName(Which())); + } +} + void CPub::GetTitles( TOneTitleRefVec & out_title, size_t iMaxToGet ) const diff --git a/c++/src/objects/pubmed/CMakeLists.pubmed.asn.txt b/c++/src/objects/pubmed/CMakeLists.pubmed.asn.txt new file mode 100644 index 00000000..34aae22b --- /dev/null +++ b/c++/src/objects/pubmed/CMakeLists.pubmed.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/pubmed/Makefile.pubmed.lib +# + +set(MODULE pubmed) +set(MODULE_IMPORT objects/general/general objects/ /biblio objects/medline/medline) +set(MODULE_PATH objects/pubmed) + +set(MODULE_EXT "asn") +add_library(pubmed ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + medline +) + +target_link_libraries(pubmed + medline +) \ No newline at end of file diff --git a/c++/src/objects/pubmed/CMakeLists.txt b/c++/src/objects/pubmed/CMakeLists.txt new file mode 100644 index 00000000..59513c2e --- /dev/null +++ b/c++/src/objects/pubmed/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.pubmed.asn.txt) + diff --git a/c++/src/objects/remap/CMakeLists.remap.asn.txt b/c++/src/objects/remap/CMakeLists.remap.asn.txt new file mode 100644 index 00000000..ee48791c --- /dev/null +++ b/c++/src/objects/remap/CMakeLists.remap.asn.txt @@ -0,0 +1,21 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/remap/Makefile.remap.lib +# + +set(MODULE remap) +set(MODULE_IMPORT objects/seqloc/seqloc) +set(MODULE_PATH objects/remap) + +set(MODULE_EXT "asn") +add_library(remap ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(remap + seq +) \ No newline at end of file diff --git a/c++/src/objects/remap/CMakeLists.remapcli.lib.txt b/c++/src/objects/remap/CMakeLists.remapcli.lib.txt new file mode 100644 index 00000000..8c639f06 --- /dev/null +++ b/c++/src/objects/remap/CMakeLists.remapcli.lib.txt @@ -0,0 +1,10 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/remap/Makefile.remapcli.lib +# +add_library(remapcli + remap_client remap_client_ +) + +target_link_libraries(remapcli + remap xconnect +) diff --git a/c++/src/objects/remap/CMakeLists.txt b/c++/src/objects/remap/CMakeLists.txt new file mode 100644 index 00000000..0e633144 --- /dev/null +++ b/c++/src/objects/remap/CMakeLists.txt @@ -0,0 +1,8 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.remapcli.lib.txt) +include(CMakeLists.remap.asn.txt) + diff --git a/c++/src/objects/scoremat/CMakeLists.scoremat.asn.txt b/c++/src/objects/scoremat/CMakeLists.scoremat.asn.txt new file mode 100644 index 00000000..9c1502bc --- /dev/null +++ b/c++/src/objects/scoremat/CMakeLists.scoremat.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/scoremat/Makefile.scoremat.lib +# + +set(MODULE scoremat) +set(MODULE_IMPORT objects/seqset/seqset objects/general/general) +set(MODULE_PATH objects/scoremat) + +set(MODULE_EXT "asn") +add_library(scoremat ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seqset +) + +target_link_libraries(scoremat + seqset +) \ No newline at end of file diff --git a/c++/src/objects/scoremat/CMakeLists.txt b/c++/src/objects/scoremat/CMakeLists.txt new file mode 100644 index 00000000..1026adcf --- /dev/null +++ b/c++/src/objects/scoremat/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.scoremat.asn.txt) + diff --git a/c++/src/objects/seq/CMakeLists.seq.asn.txt b/c++/src/objects/seq/CMakeLists.seq.asn.txt new file mode 100644 index 00000000..82a3fd6d --- /dev/null +++ b/c++/src/objects/seq/CMakeLists.seq.asn.txt @@ -0,0 +1,26 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/seq/Makefile.seq.lib +# + +#set(MODULE_IMPORT objects/general/general objects/ /biblio objects/pub/pub objects/medline/medline objects/seqloc/seqloc objects/seqblock/seqblock objects/seqalign/seqalign objects/seqfeat/seqfeat objects/seqres/seqres objects/seqtable/seqtable) +set(MODULE_EXT "asn") +set(ASN seq seqalign seqblock seqfeat seqloc seqres seqtable) + + +foreach(ASN_FILE ${ASN}) + set(MODULE ${ASN_FILE}) + set(MODULE_PATH_RELATIVE "objects/${ASN_FILE}") + RunDatatool("${ASN_FILE}" "${MODULE_IMPORT}") + # + SET(MODULE_FILES ${MODULE_FILES} ${NEW_MODULE_FILES}) +endforeach(ASN_FILE) + +add_library(seq ${MODULE_FILES} + seqport_util seq_id_tree seq_id_handle seq_id_mapper + seq_loc_mapper_base seq_align_mapper_base seqlocinfo + sofa_map so_map seq_loc_from_string seq_loc_reverse_complementer) + +target_link_libraries(seq + pub seqcode sequtil +) + diff --git a/c++/src/objects/seq/CMakeLists.txt b/c++/src/objects/seq/CMakeLists.txt new file mode 100644 index 00000000..dcfef274 --- /dev/null +++ b/c++/src/objects/seq/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.seq.asn.txt) + +# Recurse subdirectories +add_subdirectory(test ) +add_subdirectory(unit_test ) diff --git a/c++/src/objects/seq/Delta_ext.cpp b/c++/src/objects/seq/Delta_ext.cpp index 4f3423a5..2822499a 100644 --- a/c++/src/objects/seq/Delta_ext.cpp +++ b/c++/src/objects/seq/Delta_ext.cpp @@ -1,4 +1,4 @@ -/* $Id: Delta_ext.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: Delta_ext.cpp 513588 2016-09-13 13:46:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seq/Makefile.seq.lib b/c++/src/objects/seq/Makefile.seq.lib index 444f61dd..13497d63 100644 --- a/c++/src/objects/seq/Makefile.seq.lib +++ b/c++/src/objects/seq/Makefile.seq.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.seq.lib 468535 2015-05-26 13:23:32Z ucko $ +# $Id: Makefile.seq.lib 534224 2017-04-25 16:19:24Z ludwigf $ ASN = seq seqalign seqblock seqfeat seqloc seqres seqtable @@ -9,12 +9,12 @@ CPPFLAGS = -I$(srcdir) -I$(top_srcdir)/src/objects/seq $(ORIG_CPPFLAGS) LIB = seq SRC = $(ASN:%=%__) $(ASN:%=%___) seqport_util \ seq_id_tree seq_id_handle seq_id_mapper \ - seq_loc_mapper_base seq_align_mapper_base seqlocinfo sofa_map \ + seq_loc_mapper_base seq_align_mapper_base seqlocinfo sofa_map so_map \ seq_loc_from_string seq_loc_reverse_complementer DLL_LIB = seqcode pub general xser sequtil -WATCHERS = vasilche grichenk +WATCHERS = vasilche grichenk bollin ludwigf USES_LIBRARIES = \ diff --git a/c++/src/objects/seq/Seq_gap.cpp b/c++/src/objects/seq/Seq_gap.cpp index abd42370..0448dc01 100644 --- a/c++/src/objects/seq/Seq_gap.cpp +++ b/c++/src/objects/seq/Seq_gap.cpp @@ -1,4 +1,4 @@ -/* $Id: Seq_gap.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: Seq_gap.cpp 513588 2016-09-13 13:46:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seq/Seq_inst.cpp b/c++/src/objects/seq/Seq_inst.cpp index 39633644..e22e9683 100644 --- a/c++/src/objects/seq/Seq_inst.cpp +++ b/c++/src/objects/seq/Seq_inst.cpp @@ -1,4 +1,4 @@ -/* $Id: Seq_inst.cpp 519218 2016-11-14 16:06:51Z ivanov $ +/* $Id: Seq_inst.cpp 547969 2017-10-06 15:32:34Z fukanchi $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -86,7 +86,7 @@ string CSeq_inst::GetMoleculeClass(CSeq_inst::EMol mol) #define CONVERT_AA_CODING_TO_STR(encoding) \ case CSeq_data::e_##encoding: \ - CSeqConvert::Convert(seq_data.Get##encoding().Get(), CSeqUtil::e_##encoding, 0, length, str, CSeqUtil::e_Iupacaa); \ + CSeqConvert::Convert(seq_data.Get##encoding().Get(), CSeqUtil::e_##encoding, 0, length, str, CSeqUtil::e_Ncbieaa); \ break; @@ -154,7 +154,11 @@ bool CSeq_inst::ConvertDeltaToRaw() } SetRepr(objects::CSeq_inst::eRepr_raw); if (IsAa()) { - SetSeq_data().SetIupacaa() = objects::CIUPACaa(iupacna); + if (NStr::Find(iupacna, "*") != NPOS || NStr::Find(iupacna, "-") != NPOS) { + SetSeq_data().SetNcbieaa() = objects::CNCBIeaa(iupacna); + } else { + SetSeq_data().SetIupacaa() = objects::CIUPACaa(iupacna); + } } else { SetSeq_data().SetIupacna() = objects::CIUPACna(iupacna); } diff --git a/c++/src/objects/seq/seq_id_handle.cpp b/c++/src/objects/seq/seq_id_handle.cpp index 4cfb5026..617ef54a 100644 --- a/c++/src/objects/seq/seq_id_handle.cpp +++ b/c++/src/objects/seq/seq_id_handle.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_id_handle.cpp 499612 2016-04-26 18:53:35Z vasilche $ +/* $Id: seq_id_handle.cpp 536936 2017-05-24 16:55:33Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -188,14 +188,19 @@ bool CSeq_id_Handle::operator==(const CSeq_id& id) const } -TIntId CSeq_id_Handle::CompareOrdered(const CSeq_id_Handle& id) const +int CSeq_id_Handle::CompareOrdered(const CSeq_id_Handle& id) const { // small optimization to avoid creation of temporary CSeq_id objects - if ( TIntId diff = Which() - id.Which() ) { + if ( int diff = Which() - id.Which() ) { return diff; } if ( IsGi() && id.IsGi() ) { - return GetGi() - id.GetGi(); + if ( GetGi() < id.GetGi() ) { + return -1; + } + else { + return GetGi() > id.GetGi(); + } } return GetSeqId()->CompareOrdered(*id.GetSeqId()); } @@ -310,9 +315,17 @@ string GetLabel(const vector& ids) { string ret; CSeq_id_Handle best_id; - int best_score = kMax_Int; + int best_score = CSeq_id::kMaxScore; +#ifdef _DEBUG + TGi gi = ZERO_GI; +#endif ITERATE ( vector, it, ids ) { CConstRef id = it->GetSeqId(); +#ifdef _DEBUG + if (it->IsGi()) { + gi = id->GetGi(); + } +#endif int score = id->TextScore(); if ( score < best_score ) { best_score = score; @@ -321,6 +334,16 @@ string GetLabel(const vector& ids) } if ( best_id ) { ret = GetLabel(best_id); +#ifdef _DEBUG + if ( gi != ZERO_GI && !best_id.IsGi() ) { + CConstRef best_seq_id = best_id.GetSeqId(); + const CTextseq_id* txt_id = best_seq_id->GetTextseq_Id(); + if ( txt_id && !txt_id->IsSetVersion() ) { + ERR_POST("Using version-less accession " << txt_id->GetAccession() + << " instead of GI " << gi); + } + } +#endif } return ret; } @@ -330,9 +353,17 @@ string GetLabel(const vector >& ids) { string ret; const CSeq_id* best_id = 0; - int best_score = kMax_Int; + int best_score = CSeq_id::kMaxScore; +#ifdef _DEBUG + TGi gi = ZERO_GI; +#endif ITERATE ( vector >, it, ids ) { const CSeq_id& id = **it; +#ifdef _DEBUG + if (id.IsGi()) { + gi = id.GetGi(); + } +#endif int score = id.TextScore(); if ( score < best_score ) { best_score = score; @@ -341,6 +372,15 @@ string GetLabel(const vector >& ids) } if ( best_id ) { ret = GetLabel(*best_id); +#ifdef _DEBUG + if ( gi != ZERO_GI && !best_id->IsGi() ) { + const CTextseq_id* txt_id = best_id->GetTextseq_Id(); + if ( txt_id && !txt_id->IsSetVersion() ) { + ERR_POST("Using version-less accession " << txt_id->GetAccession() + << " instead of GI " << gi); + } + } +#endif } return ret; } diff --git a/c++/src/objects/seq/seq_id_tree.cpp b/c++/src/objects/seq/seq_id_tree.cpp index 42e15f5e..cd2df470 100644 --- a/c++/src/objects/seq/seq_id_tree.cpp +++ b/c++/src/objects/seq/seq_id_tree.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_id_tree.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: seq_id_tree.cpp 535845 2017-05-11 21:36:46Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1618,25 +1618,11 @@ CSeq_id_Handle CSeq_id_Local_Tree::FindInfo(const CSeq_id& id) const CSeq_id_Handle CSeq_id_Local_Tree::FindOrCreate(const CSeq_id& id) { - _ASSERT(id.IsLocal()); const CObject_id& oid = id.GetLocal(); TWriteLockGuard guard(m_TreeLock); - CSeq_id_Info* info = x_FindInfo(oid); - + CSeq_id_Info*& info = oid.IsStr()? m_ByStr[oid.GetStr()]: m_ById[oid.GetId()]; if ( !info ) { info = CreateInfo(id); - if ( oid.IsStr() ) { - _VERIFY(m_ByStr.insert(TByStr::value_type(oid.GetStr(), - info)).second); - } - else if ( oid.IsId() ) { - _VERIFY(m_ById.insert(TById::value_type(oid.GetId(), - info)).second); - } - else { - NCBI_THROW(CSeq_id_MapperException, eEmptyError, - "Can not create index for an empty local seq-id"); - } } return CSeq_id_Handle(info); } diff --git a/c++/src/objects/seq/seq_id_tree.hpp b/c++/src/objects/seq/seq_id_tree.hpp index 0b9ef7ee..b0ed64b9 100644 --- a/c++/src/objects/seq/seq_id_tree.hpp +++ b/c++/src/objects/seq/seq_id_tree.hpp @@ -1,7 +1,7 @@ #ifndef OBJECTS_OBJMGR___SEQ_ID_TREE__HPP #define OBJECTS_OBJMGR___SEQ_ID_TREE__HPP -/* $Id: seq_id_tree.hpp 502271 2016-05-23 18:52:46Z vasilche $ +/* $Id: seq_id_tree.hpp 535901 2017-05-12 18:05:49Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -56,6 +56,7 @@ #include #include #include +#include BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) @@ -67,6 +68,31 @@ class CSeq_id_Info; class CSeq_id_Mapper; class CSeq_id_Which_Tree; +struct PHashNocase { + static char get_hash(char c) + { + // In ids only ASCII characters are allowed, and in ASCII + // upper and lower cases differ only by one bit. + // So for efficiency it's enough to reset that bit + // instead of using more complex tolower(). + return c&~32; + //return tolower(c); + } + size_t operator()(const string& s) const + { + size_t h = s.size(); + for ( auto c : s ) + h = h*17 + get_hash(c); + return h; + } +}; +struct PEqualNocase { + bool operator()(const string& s1, const string& s2) const + { + return NStr::EqualNocase(s1, s2); + } +}; + //////////////////////////////////////////////////////////////////// // // CSeq_id_***_Tree:: @@ -652,7 +678,7 @@ private: virtual void x_Unindex(const CSeq_id_Info* info); CSeq_id_Info* x_FindInfo(const CObject_id& oid) const; - typedef map TByStr; + typedef unordered_map TByStr; typedef map TById; TByStr m_ByStr; @@ -785,7 +811,7 @@ private: struct STagMap { public: - typedef map TByStr; + typedef unordered_map TByStr; typedef map TById; TByStr m_ByStr; TById m_ById; diff --git a/c++/src/objects/seq/seq_loc_from_string.cpp b/c++/src/objects/seq/seq_loc_from_string.cpp index a7375f33..7a75ac4f 100644 --- a/c++/src/objects/seq/seq_loc_from_string.cpp +++ b/c++/src/objects/seq/seq_loc_from_string.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_loc_from_string.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: seq_loc_from_string.cpp 513588 2016-09-13 13:46:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seq/seq_loc_mapper_base.cpp b/c++/src/objects/seq/seq_loc_mapper_base.cpp index eacacbc0..36aa7c22 100644 --- a/c++/src/objects/seq/seq_loc_mapper_base.cpp +++ b/c++/src/objects/seq/seq_loc_mapper_base.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_loc_mapper_base.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: seq_loc_mapper_base.cpp 543871 2017-08-15 12:17:04Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -733,6 +733,24 @@ CSeq_loc_Mapper_Base::CSeq_loc_Mapper_Base(const CSeq_align& map_align, } +CSeq_loc_Mapper_Base::CSeq_loc_Mapper_Base(const CSeq_id& from_id, + const CSeq_id& to_id, + const CSeq_align& map_align, + CSeq_loc_Mapper_Options options) + : m_MergeFlag(eMergeNone), + m_GapFlag(eGapPreserve), + m_MiscFlags(fTrimSplicedSegs), + m_Partial(false), + m_LastTruncated(false), + m_Mappings(new CMappingRanges), + m_CurrentGroup(0), + m_FuzzOption(0), + m_MapOptions(options) +{ + x_InitializeAlign(map_align, to_id, &from_id); +} + + CSeq_loc_Mapper_Base::CSeq_loc_Mapper_Base(const CSeq_align& map_align, const CSeq_id& to_id, TMapOptions opts, @@ -768,6 +786,24 @@ CSeq_loc_Mapper_Base::CSeq_loc_Mapper_Base(const CSeq_align& map_align, } +CSeq_loc_Mapper_Base::CSeq_loc_Mapper_Base(size_t from_row, + size_t to_row, + const CSeq_align& map_align, + CSeq_loc_Mapper_Options options) + : m_MergeFlag(eMergeNone), + m_GapFlag(eGapPreserve), + m_MiscFlags(fTrimSplicedSegs), + m_Partial(false), + m_LastTruncated(false), + m_Mappings(new CMappingRanges), + m_CurrentGroup(0), + m_FuzzOption(0), + m_MapOptions(options) +{ + x_InitializeAlign(map_align, to_row, from_row); +} + + CSeq_loc_Mapper_Base::CSeq_loc_Mapper_Base(const CSeq_align& map_align, size_t to_row, TMapOptions opts, @@ -1291,16 +1327,26 @@ bool CSeq_loc_Mapper_Base::x_IsSynonym(const CSeq_id& id, void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, - const CSeq_id& to_id) + const CSeq_id& to_id, + const CSeq_id* from_id) { IMapper_Sequence_Info::TSynonyms to_syn; + unique_ptr from_syn; CSeq_id_Handle to_idh = CSeq_id_Handle::GetHandle(to_id); CollectSynonyms(to_idh, to_syn); - x_InitializeAlign(map_align, to_syn); + if ( from_id ) { + CSeq_id_Handle from_idh = CSeq_id_Handle::GetHandle(*from_id); + from_syn.reset(new IMapper_Sequence_Info::TSynonyms); + CollectSynonyms(from_idh, *from_syn); + } + x_InitializeAlign(map_align, to_syn, from_syn.get()); } +const size_t kInvalidRow = size_t(-1); + void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, - const TSynonyms& to_ids) + const TSynonyms& to_ids, + const TSynonyms* from_ids) { // When finding the destination row, the first row with required seq-id // is used. Do not check if there are multiple rows with the same id. @@ -1309,45 +1355,63 @@ void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, { const TDendiag& diags = map_align.GetSegs().GetDendiag(); ITERATE(TDendiag, diag_it, diags) { - size_t to_row = size_t(-1); + size_t to_row = kInvalidRow; + size_t from_row = kInvalidRow; for (size_t i = 0; i < (*diag_it)->GetIds().size(); ++i) { if ( x_IsSynonym(*(*diag_it)->GetIds()[i], to_ids) ) { to_row = i; - break; + if (!from_ids || from_row != kInvalidRow) break; + } + if (from_ids && x_IsSynonym(*(*diag_it)->GetIds()[i], *from_ids)) { + from_row = i; + if (to_row != kInvalidRow) break; } } - if (to_row == size_t(-1)) { + if (to_row == kInvalidRow) { NCBI_THROW(CAnnotMapperException, eBadAlignment, "Target ID not found in the alignment"); } + if (from_ids && from_row == kInvalidRow) { + NCBI_THROW(CAnnotMapperException, eBadAlignment, + "Source ID not found in the alignment"); + } // Each diag forms a separate group. See SetMergeBySeg(). m_CurrentGroup++; - x_InitAlign(**diag_it, to_row); + x_InitAlign(**diag_it, to_row, from_row); } break; } case CSeq_align::C_Segs::e_Denseg: { const CDense_seg& dseg = map_align.GetSegs().GetDenseg(); - size_t to_row = size_t(-1); + size_t to_row = kInvalidRow; + size_t from_row = kInvalidRow; for (size_t i = 0; i < dseg.GetIds().size(); ++i) { if ( x_IsSynonym(*dseg.GetIds()[i], to_ids) ) { to_row = i; - break; + if (!from_ids || from_row != kInvalidRow) break; + } + if (from_ids && x_IsSynonym(*dseg.GetIds()[i], *from_ids)) { + from_row = i; + if (to_row != kInvalidRow) break; } } - if (to_row == size_t(-1)) { + if (to_row == kInvalidRow) { NCBI_THROW(CAnnotMapperException, eBadAlignment, "Target ID not found in the alignment"); } - x_InitAlign(dseg, to_row); + if (from_ids && from_row == kInvalidRow) { + NCBI_THROW(CAnnotMapperException, eBadAlignment, + "Source ID not found in the alignment"); + } + x_InitAlign(dseg, to_row, from_row); break; } case CSeq_align::C_Segs::e_Std: { const TStd& std_segs = map_align.GetSegs().GetStd(); ITERATE(TStd, std_seg, std_segs) { - size_t to_row = size_t(-1); + size_t to_row = kInvalidRow; if ((*std_seg)->IsSetIds() && !(*std_seg)->GetIds().empty()) { for (size_t i = 0; i < (*std_seg)->GetIds().size(); ++i) { if ( x_IsSynonym(*(*std_seg)->GetIds()[i], to_ids) ) { @@ -1356,7 +1420,7 @@ void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, } } } - if (to_row == size_t(-1)) { + if (to_row == kInvalidRow) { // The id is not found or 'ids' is missing in the std-seg. // Try to parse seq-locs. for (size_t i = 0; i < (*std_seg)->GetLoc().size(); ++i) { @@ -1367,7 +1431,7 @@ void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, } } } - if (to_row == size_t(-1)) { + if (to_row == kInvalidRow) { NCBI_THROW(CAnnotMapperException, eBadAlignment, "Target ID not found in the alignment"); } @@ -1380,18 +1444,27 @@ void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, case CSeq_align::C_Segs::e_Packed: { const CPacked_seg& pseg = map_align.GetSegs().GetPacked(); - size_t to_row = size_t(-1); + size_t to_row = kInvalidRow; + size_t from_row = kInvalidRow; for (size_t i = 0; i < pseg.GetIds().size(); ++i) { if ( x_IsSynonym(*pseg.GetIds()[i], to_ids) ) { to_row = i; - break; + if (!from_ids || from_row != kInvalidRow) break; + } + if (from_ids && x_IsSynonym(*pseg.GetIds()[i], *from_ids)) { + from_row = i; + if (to_row != kInvalidRow) break; } } - if (to_row == size_t(-1)) { + if (to_row == kInvalidRow) { NCBI_THROW(CAnnotMapperException, eBadAlignment, "Target ID not found in the alignment"); } - x_InitAlign(pseg, to_row); + if (from_ids && from_row == kInvalidRow) { + NCBI_THROW(CAnnotMapperException, eBadAlignment, + "Source ID not found in the alignment"); + } + x_InitAlign(pseg, to_row, from_row); break; } case CSeq_align::C_Segs::e_Disc: @@ -1435,7 +1508,8 @@ void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, - size_t to_row) + size_t to_row, + size_t from_row) { switch ( map_align.GetSegs().Which() ) { case CSeq_align::C_Segs::e_Dendiag: @@ -1444,14 +1518,14 @@ void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, ITERATE(TDendiag, diag_it, diags) { // Each diag forms a separate group. See SetMergeBySeg(). m_CurrentGroup++; - x_InitAlign(**diag_it, to_row); + x_InitAlign(**diag_it, to_row, from_row); } break; } case CSeq_align::C_Segs::e_Denseg: { const CDense_seg& dseg = map_align.GetSegs().GetDenseg(); - x_InitAlign(dseg, to_row); + x_InitAlign(dseg, to_row, from_row); break; } case CSeq_align::C_Segs::e_Std: @@ -1467,7 +1541,7 @@ void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, case CSeq_align::C_Segs::e_Packed: { const CPacked_seg& pseg = map_align.GetSegs().GetPacked(); - x_InitAlign(pseg, to_row); + x_InitAlign(pseg, to_row, from_row); break; } case CSeq_align::C_Segs::e_Disc: @@ -1477,7 +1551,7 @@ void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, ITERATE(CSeq_align_set::Tdata, aln, aln_set.Get()) { // Each sub-alignment forms a separate group. See SetMergeBySeg(). m_CurrentGroup++; - x_InitializeAlign(**aln, to_row); + x_InitializeAlign(**aln, to_row, from_row); } break; } @@ -1507,7 +1581,9 @@ void CSeq_loc_Mapper_Base::x_InitializeAlign(const CSeq_align& map_align, } -void CSeq_loc_Mapper_Base::x_InitAlign(const CDense_diag& diag, size_t to_row) +void CSeq_loc_Mapper_Base::x_InitAlign(const CDense_diag& diag, + size_t to_row, + size_t from_row) { // Check the alignment for consistency. Adjust invalid values, show // warnings if this happens. @@ -1547,6 +1623,9 @@ void CSeq_loc_Mapper_Base::x_InitAlign(const CDense_diag& diag, size_t to_row) if (row == to_row) { continue; } + if (from_row != kInvalidRow && from_row != row) { + continue; + } const CSeq_id& src_id = *diag.GetIds()[row]; ESeqType src_type = GetSeqTypeById(src_id); int src_width = (src_type == eSeq_prot) ? 3 : 1; @@ -1567,7 +1646,8 @@ void CSeq_loc_Mapper_Base::x_InitAlign(const CDense_diag& diag, size_t to_row) void CSeq_loc_Mapper_Base::x_InitAlign(const CDense_seg& denseg, - size_t to_row) + size_t to_row, + size_t from_row) { // Check the alignment for consistency. Adjust invalid values, show // warnings if this happens. @@ -1612,6 +1692,9 @@ void CSeq_loc_Mapper_Base::x_InitAlign(const CDense_seg& denseg, if (row == to_row) { continue; } + if (from_row != kInvalidRow && from_row != row) { + continue; + } const CSeq_id& src_id = *denseg.GetIds()[row]; ESeqType src_type = GetSeqTypeById(src_id); @@ -1713,7 +1796,9 @@ void CSeq_loc_Mapper_Base::x_InitAlign(const CStd_seg& sseg, size_t to_row) } -void CSeq_loc_Mapper_Base::x_InitAlign(const CPacked_seg& pseg, size_t to_row) +void CSeq_loc_Mapper_Base::x_InitAlign(const CPacked_seg& pseg, + size_t to_row, + size_t from_row) { // Check the alignment for consistency. Adjust invalid values, show // warnings if this happens. @@ -1757,6 +1842,9 @@ void CSeq_loc_Mapper_Base::x_InitAlign(const CPacked_seg& pseg, size_t to_row) if (row == to_row) { continue; } + if (from_row != kInvalidRow && from_row != row) { + continue; + } const CSeq_id& src_id = *pseg.GetIds()[row]; ESeqType src_type = GetSeqTypeById(src_id); int src_width = (src_type == eSeq_prot) ? 3 : 1; diff --git a/c++/src/objects/seq/so_map.cpp b/c++/src/objects/seq/so_map.cpp new file mode 100644 index 00000000..dc779f86 --- /dev/null +++ b/c++/src/objects/seq/so_map.cpp @@ -0,0 +1,1230 @@ +/* $Id: so_map.cpp 543910 2017-08-15 14:53:43Z ivanov $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Authors: Frank Ludwig + * + * File Description: Sequence Ontology Type Mapping + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BEGIN_NCBI_SCOPE +USING_SCOPE(objects); + +// ---------------------------------------------------------------------------- +bool CompareNoCase::operator()( + const string& lhs, + const string& rhs) const +// ---------------------------------------------------------------------------- +{ + string::const_iterator pLhs = lhs.begin(); + string::const_iterator pRhs = rhs.begin(); + while (pLhs != lhs.end() && pRhs != rhs.end() && + tolower(*pLhs) == tolower(*pRhs)) { + ++pLhs; + ++pRhs; + } + if (pLhs == lhs.end()) { + return (pRhs != rhs.end()); + } + if (pRhs == rhs.end()) { + return false; + } + return (tolower(*pLhs) < tolower(*pRhs)); +}; + +// ---------------------------------------------------------------------------- +CSoMap::TYPEMAP CSoMap::mMapSoTypeToId; +// ---------------------------------------------------------------------------- + +// ---------------------------------------------------------------------------- +CSoMap::TYPEMAP CSoMap::mMapSoIdToType = { +// ---------------------------------------------------------------------------- + {"SO:0000001", "region"}, + {"SO:0000002", "sequece_secondary_structure"}, + {"SO:0000005", "satellite_DNA"}, + {"SO:0000013", "scRNA"}, + {"SO:0000035", "riboswitch"}, + {"SO:0000036", "matrix_attachment_site"}, + {"SO:0000037", "locus_control_region"}, + {"SO:0000104", "polypeptide"}, + {"SO:0000110", "sequence_feature"}, + {"SO:0000139", "ribosome_entry_site"}, + {"SO:0000140", "attenuator"}, + {"SO:0000141", "terminator"}, + {"SO:0000147", "exon"}, + {"SO:0000165", "enhancer"}, + {"SO:0000167", "promoter"}, + {"SO:0000172", "CAAT_signal"}, + {"SO:0000173", "GC_rich_promoter_region"}, + {"SO:0000174", "TATA_box"}, + {"SO:0000175", "minus_10_signal"}, + {"SO:0000176", "minus_35_signal"}, + {"SO:0000178", "operon"}, + {"SO:0000185", "primary_transcript"}, + {"SO:0000188", "intron"}, + {"SO:0000204", "five_prime_UTR"}, + {"SO:0000205", "three_prime_UTR"}, + {"SO:0000234", "mRNA"}, + {"SO:0000252", "rRNA"}, + {"SO:0000253", "tRNA"}, + {"SO:0000274", "snRNA"}, + {"SO:0000275", "snoRNA"}, + {"SO:0000276", "miRNA"}, + {"SO:0000286", "long_terminal_repeat"}, + {"SO:0000289", "microsatellite"}, + {"SO:0000294", "inverted_repeat"}, + {"SO:0000296", "origin_of_replication"}, + {"SO:0000297", "D_loop"}, + {"SO:0000298", "recombination_feature"}, + {"SO:0000305", "modified_DNA_base"}, + {"SO:0000313", "stem_loop"}, + {"SO:0000314", "direct_repeat"}, + {"SO:0000315", "TSS"}, + {"SO:0000316", "CDS"}, + {"SO:0000330", "conserved_region"}, + {"SO:0000331", "STS"}, + {"SO:0000336", "pseudogene"}, + {"SO:0000374", "ribozyme"}, + {"SO:0000380", "hammerhead_ribozyme"}, + {"SO:0000385", "RNase_MRP_RNA"}, + {"SO:0000386", "RNase_P_RNA"}, + {"SO:0000404", "vault_RNA"}, + {"SO:0000405", "Y_RNA"}, + {"SO:0000409", "binding_site"}, + {"SO:0000410", "protein_binding_site"}, + {"SO:0000413", "sequence_difference"}, + {"SO:0000418", "signal_peptide"}, + {"SO:0000419", "mature_protein_region"}, + {"SO:0000433", "non_LTR_retrotransposon_polymeric_tract"}, + {"SO:0000454", "rasiRNA"}, + {"SO:0000458", "D_gene_segment"}, + {"SO:0000466", "V_gene_segment"}, + {"SO:0000470", "J_gene_segment"}, + {"SO:0000478", "C_gene_segment"}, + {"SO:0000516", "pseudogenic_transcript"}, + {"SO:0000551", "polyA_signal_sequence"}, + {"SO:0000553", "polyA_site"}, + {"SO:0000577", "centromere"}, + {"SO:0000584", "tmRNA"}, + {"SO:0000588", "autocatalytically_spliced_intron"}, + {"SO:0000590", "SRP_RNA"}, + {"SO:0000602", "guide_RNA"}, + {"SO:0000624", "telomere"}, + {"SO:0000625", "silencer"}, + {"SO:0000627", "insulator"}, + {"SO:0000644", "antisense_RNA"}, + {"SO:0000646", "siRNA"}, + {"SO:0000655", "ncRNA"}, + {"SO:0000657", "repeat_region"}, + {"SO:0000658", "dispersed_repeat"}, + {"SO:0000673", "transcript"}, + {"SO:0000685", "DNAsel_hypersensitive_site"}, + {"SO:0000704", "gene"}, + {"SO:0000705", "tandem_repeat"}, + {"SO:0000714", "nucleotide_motif"}, + {"SO:0000723", "iDNA"}, + {"SO:0000724", "oriT"}, + {"SO:0000725", "transit_peptide"}, + {"SO:0000730", "gap"}, + {"SO:0000777", "pseudogenic_rRNA"}, + {"SO:0000778", "pseudogenic_tRNA"}, + {"SO:0001021", "chromosome_preakpoint"}, + {"SO:0001035", "piRNA"}, + {"SO:0001037", "mobile_genetic_element"}, + {"SO:0001055", "transcriptional_cis_regulatory_region"}, + {"SO:0001059", "sequence_alteration"}, + {"SO:0001062", "propeptide"}, + {"SO:0001086", "sequence_uncertainty"}, + {"SO:0001087", "cross_link"}, + {"SO:0001088", "disulfide_bond"}, + {"SO:0001268", "recoding_stimulatory_region"}, + {"SO:0001411", "biological_region"}, + {"SO:0001484", "X_element_combinatorical_repeat"}, + {"SO:0001485", "Y_prime_element"}, + {"SO:0001496", "telomeric_repeat"}, + {"SO:0001649", "nested_repeat"}, + {"SO:0001682", "replication_regulatory_region"}, + {"SO:0001797", "centromeric_repeat"}, + {"SO:0001833", "V_region"}, + {"SO:0001835", "N_region"}, + {"SO:0001836", "S_region"}, + {"SO:0001877", "lnc_RNA"}, + {"SO:0001917", "CAGE_cluster"}, + {"SO:0002020", "boundary_element"}, + {"SO:0002072", "sequence_comparison"}, + {"SO:0002087", "pseudogenic_CDS"}, + {"SO:0002094", "non_allelic_homologous_recombination_region"}, + {"SO:0002154", "mitotic_recombination_region"}, + {"SO:0002155", "meiotic_recombination_region"}, + {"SO:0005836", "regulatory_region"}, + {"SO:0005850", "primary_binding_site"}, + + {"SO:0000000", ""}, + //{"SO:UNKNOWN", "replication_start_site"}, + //{"SO:UNKNOWN", "nucleotide_site"}, + //{"SO:UNKNOWN", "nucleotide_cleavage_site"}, + //{"SO:UNKNOWN", "repeat_instability_region"}, +}; + +// ---------------------------------------------------------------------------- +CSoMap::FEATFUNCMAP CSoMap::mMapFeatFunc = { +// ---------------------------------------------------------------------------- + {"CAGE_cluster", CSoMap::xFeatureMakeMiscFeature}, + {"CAAT_signal", CSoMap::xFeatureMakeRegulatory}, + {"CDS", CSoMap::xFeatureMakeCds}, + {"C_gene_segment", CSoMap::xFeatureMakeImp}, + {"DNAsel_hypersensitive_site", CSoMap::xFeatureMakeRegulatory}, + {"D_loop", CSoMap::xFeatureMakeImp}, + {"D_gene_segment", CSoMap::xFeatureMakeImp}, + {"GC_rich_promoter_region", CSoMap::xFeatureMakeRegulatory}, + {"J_gene_segment", CSoMap::xFeatureMakeImp}, + {"N_region", CSoMap::xFeatureMakeImp}, + {"RNase_MRP_RNA", CSoMap::xFeatureMakeNcRna}, + {"RNase_P_RNA", CSoMap::xFeatureMakeNcRna}, + {"SRP_RNA", CSoMap::xFeatureMakeNcRna}, + {"STS", CSoMap::xFeatureMakeImp}, + {"S_region", CSoMap::xFeatureMakeImp}, + {"TATA_box", CSoMap::xFeatureMakeRegulatory}, + {"V_gene_segment", CSoMap::xFeatureMakeImp}, + {"V_region", CSoMap::xFeatureMakeImp}, + {"X_element_combinatorical_repeat", CSoMap::xFeatureMakeRepeatRegion}, + {"Y_RNA", CSoMap::xFeatureMakeNcRna}, + {"Y_prime_element", CSoMap::xFeatureMakeRepeatRegion}, + {"antisense_RNA", CSoMap::xFeatureMakeNcRna}, + {"attenuator", CSoMap::xFeatureMakeRegulatory}, + {"autocatalytically_spliced_intron", CSoMap::xFeatureMakeNcRna}, + {"binding_site", CSoMap::xFeatureMakeImp}, + {"biological_region", CSoMap::xFeatureMakeRegion}, + {"boundary_element", CSoMap::xFeatureMakeRegulatory}, + {"centromere", CSoMap::xFeatureMakeImp}, + {"centromeric_repeat", CSoMap::xFeatureMakeRepeatRegion}, + {"chromosome_breakpoint", CSoMap::xFeatureMakeMiscRecomb}, + {"conserved_region", CSoMap::xFeatureMakeMiscFeature}, + {"direct_repeat", CSoMap::xFeatureMakeRepeatRegion}, + {"dispersed_repeat", CSoMap::xFeatureMakeRepeatRegion}, + {"enhancer", CSoMap::xFeatureMakeRegulatory}, + {"exon", CSoMap::xFeatureMakeImp}, + {"five_prime_UTR", CSoMap::xFeatureMakeImp}, + {"gap", CSoMap::xFeatureMakeImp}, + {"gene", CSoMap::xFeatureMakeGene}, + {"guide_RNA", CSoMap::xFeatureMakeNcRna}, + {"hammerhead_ribozyme", CSoMap::xFeatureMakeNcRna}, + {"iDNA", CSoMap::xFeatureMakeImp}, + {"insulator", CSoMap::xFeatureMakeRegulatory}, + {"intron", CSoMap::xFeatureMakeImp}, + {"inverted_repeat", CSoMap::xFeatureMakeRepeatRegion}, + {"lnc_RNA", CSoMap::xFeatureMakeNcRna}, + {"locus_control_region", CSoMap::xFeatureMakeRegulatory}, + {"long_terminal_repeat", CSoMap::xFeatureMakeRepeatRegion}, + {"mRNA", CSoMap::xFeatureMakeRna}, + {"matrix_attachment_region", CSoMap::xFeatureMakeRegulatory}, + {"mature_protein_region", CSoMap::xFeatureMakeImp}, + {"meiotic_recombination_region", CSoMap::xFeatureMakeMiscRecomb}, + {"miRNA", CSoMap::xFeatureMakeNcRna}, + {"microsatellite", CSoMap::xFeatureMakeRepeatRegion}, + {"minisatellite", CSoMap::xFeatureMakeRepeatRegion}, + {"minus_10_signal", CSoMap::xFeatureMakeRegulatory}, + {"minus_35_signal", CSoMap::xFeatureMakeRegulatory}, + {"mitotic_recombination_region", CSoMap::xFeatureMakeMiscRecomb}, + {"mobile_genetic_element", CSoMap::xFeatureMakeImp}, + {"modified_DNA_base", CSoMap::xFeatureMakeImp}, + {"ncRNA", CSoMap::xFeatureMakeNcRna}, + {"nested_repeat", CSoMap::xFeatureMakeRepeatRegion}, + {"non_allelic_homologous_recombination", CSoMap::xFeatureMakeMiscRecomb}, + {"non_LTR_retrotransposon_polymeric_tract", CSoMap::xFeatureMakeRepeatRegion}, + {"nucleotide_motif", CSoMap::xFeatureMakeMiscFeature}, + {"nucleotide_cleavage_site", CSoMap::xFeatureMakeMiscFeature}, + {"nucleotide_site", CSoMap::xFeatureMakeMiscFeature}, + {"operon", CSoMap::xFeatureMakeImp}, + {"oriT", CSoMap::xFeatureMakeImp}, + {"origin_of_replication", CSoMap::xFeatureMakeImp}, + {"piRNA", CSoMap::xFeatureMakeNcRna}, + {"polyA_signal_sequence", CSoMap::xFeatureMakeRegulatory}, + {"polyA_site", CSoMap::xFeatureMakeImp}, + {"primary_transcript", CSoMap::xFeatureMakeImp}, + {"primer_binding_site", CSoMap::xFeatureMakeImp}, + {"promoter", CSoMap::xFeatureMakeRegulatory}, + //{"propeptide", CSoMap::xFeatureMakeImp}, + {"protein_binding_site", CSoMap::xFeatureMakeImp}, + {"pseudogene", CSoMap::xFeatureMakeGene}, + {"pseudogenic_CDS", CSoMap::xFeatureMakeCds}, + {"pseudogenic_rRNA", CSoMap::xFeatureMakeRna}, + {"pseudogenic_tRNA", CSoMap::xFeatureMakeRna}, + {"pseudogenic_transcript", CSoMap::xFeatureMakeMiscRna}, + {"rRNA", CSoMap::xFeatureMakeRna}, + {"rasiRNA", CSoMap::xFeatureMakeNcRna}, + {"recoding_stimulatory_region", CSoMap::xFeatureMakeRegulatory}, + {"recombination_feature", CSoMap::xFeatureMakeMiscRecomb}, + {"region", CSoMap::xFeatureMakeImp}, + {"regulatory_region", CSoMap::xFeatureMakeRegulatory}, + {"repeat_instability_region", CSoMap::xFeatureMakeMiscFeature}, + {"repeat_region", CSoMap::xFeatureMakeRepeatRegion}, + {"replication_regulatory_region", CSoMap::xFeatureMakeRegulatory}, + {"replication_start_site", CSoMap::xFeatureMakeMiscFeature}, + {"ribosome_entry_site", CSoMap::xFeatureMakeRegulatory}, + {"riboswitch", CSoMap::xFeatureMakeRegulatory}, + {"ribozyme", CSoMap::xFeatureMakeNcRna}, + {"satellite_DNA", CSoMap::xFeatureMakeRepeatRegion}, + {"scRNA", CSoMap::xFeatureMakeNcRna}, + {"sequence_alteration", CSoMap::xFeatureMakeImp}, + {"sequence_comparison", CSoMap::xFeatureMakeMiscFeature}, + {"sequence_difference", CSoMap::xFeatureMakeImp}, + {"sequence_feature", CSoMap::xFeatureMakeMiscFeature}, + {"sequence_secondary_structure", CSoMap::xFeatureMakeImp}, + {"sequence_uncertainty", CSoMap::xFeatureMakeImp}, + {"siRNA", CSoMap::xFeatureMakeNcRna}, + {"signal_peptide", CSoMap::xFeatureMakeImp}, + {"silencer", CSoMap::xFeatureMakeRegulatory}, + {"snRNA", CSoMap::xFeatureMakeNcRna}, + {"snoRNA", CSoMap::xFeatureMakeNcRna}, + {"stem_loop", CSoMap::xFeatureMakeImp}, + {"tRNA", CSoMap::xFeatureMakeRna}, + {"tandem_repeat", CSoMap::xFeatureMakeRepeatRegion}, + {"telomerase_RNA", CSoMap::xFeatureMakeNcRna}, + {"telomere", CSoMap::xFeatureMakeImp}, + {"telomeric_repeat", CSoMap::xFeatureMakeRepeatRegion}, + {"terminator", CSoMap::xFeatureMakeRegulatory}, + {"tmRNA", CSoMap::xFeatureMakeRna}, + {"transcript", CSoMap::xFeatureMakeMiscRna}, + {"transcriptional_cis_regulatory_region", CSoMap::xFeatureMakeRegulatory}, + {"transcription_start_site", CSoMap::xFeatureMakeMiscFeature}, + {"transit_peptide", CSoMap::xFeatureMakeImp}, + {"three_prime_UTR", CSoMap::xFeatureMakeImp}, + {"vault_RNA", CSoMap::xFeatureMakeNcRna}, +}; + + +// ---------------------------------------------------------------------------- +bool CSoMap::GetSupportedSoTerms( + vector& supported_terms) +// ---------------------------------------------------------------------------- +{ + supported_terms.clear(); + for (auto term: CSoMap::mMapFeatFunc) { + supported_terms.push_back(term.first); + } + std::sort(supported_terms.begin(), supported_terms.end()); + return true; +} + +// ---------------------------------------------------------------------------- +string CSoMap::SoIdToType( + const string& sofa_id) +// ---------------------------------------------------------------------------- +{ + TYPEENTRY type_it = CSoMap::mMapSoIdToType.find(sofa_id); + if (type_it == CSoMap::mMapSoIdToType.end()) { + return ""; + } + return type_it->second; +} + +// ---------------------------------------------------------------------------- +string CSoMap::SoTypeToId( + const string& so_type) +// ---------------------------------------------------------------------------- +{ + if (CSoMap::mMapSoTypeToId.empty()) { + for (TYPEENTRY cit = CSoMap::mMapSoIdToType.begin(); + cit != CSoMap::mMapSoIdToType.end(); + ++cit) { + CSoMap::mMapSoTypeToId[cit->second] = cit->first; + } + } + TYPEENTRY id_it = mMapSoTypeToId.find(so_type); + if (id_it == CSoMap::mMapSoTypeToId.end()) { + return ""; + } + return id_it->second; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::SoTypeToFeature( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + string resolved_so_type = ResolveSoAlias(so_type); + FEATFUNCENTRY it = mMapFeatFunc.find(resolved_so_type); + if (it != mMapFeatFunc.end()) { + return (it->second)(resolved_so_type, feature); + } + return xFeatureMakeRegion(so_type, feature); +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeGene( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + feature.SetData().SetGene(); + if (so_type == "pseudogene") { + feature.SetPseudo(true); + } + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeRna( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + static const map mTypeToRna = { + {"mRNA", CRNA_ref::eType_mRNA}, + {"rRNA", CRNA_ref::eType_rRNA}, + {"pseudogenic_rRNA", CRNA_ref::eType_rRNA}, + {"tRNA", CRNA_ref::eType_tRNA}, + {"pseudogenic_tRNA", CRNA_ref::eType_tRNA}, + {"tmRNA", CRNA_ref::eType_tmRNA}, + }; + auto it = mTypeToRna.find(so_type); + feature.SetData().SetRna().SetType(it->second); + if(NStr::StartsWith(so_type, "pseudogenic_")) { + feature.SetPseudo(true); + } + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeNcRna( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + static const map mTypeToClass = { + {"ncRNA", "other"}, + }; + feature.SetData().SetRna().SetType(CRNA_ref::eType_ncRNA); + CRef qual(new CGb_qual); + qual->SetQual("ncRNA_class"); + auto it = mTypeToClass.find(so_type); + if (it == mTypeToClass.end()) { + qual->SetVal(so_type); + } + else { + qual->SetVal(it->second); + } + feature.SetQual().push_back(qual); + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeCds( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + feature.SetData().SetCdregion(); + if (so_type=="pseudogenic_CDS") { + feature.SetPseudo(true); + } + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeProt( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + static const map + mTypeToProcessed = { + {"mature_protein_region", CProt_ref::eProcessed_mature}, + {"propeptide", CProt_ref::eProcessed_propeptide}, + }; + auto cit = mTypeToProcessed.find(so_type); + if (cit == mTypeToProcessed.end()) { + return false; + } + feature.SetData().SetProt().SetProcessed(cit->second); + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeMiscFeature( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + static const map mapTypeToQual = { + {"TSS", "transcription_start_site"}, + }; + feature.SetData().SetImp().SetKey("misc_feature"); + if (so_type == "sequence_feature") { + return true; + } + CRef feat_class(new CGb_qual); + feat_class->SetQual("feat_class"); + auto cit = mapTypeToQual.find(so_type); + if (cit == mapTypeToQual.end()) { + feat_class->SetVal(so_type); + } + else { + feat_class->SetVal(cit->second); + } + feature.SetQual().push_back(feat_class); + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeMiscRecomb( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + static const map mapTypeToQual = { + {"meiotic_recombination_region", "meiotic"}, + {"mitotic_recombination_region", "mitotic"}, + {"non_allelic_homologous_recombination", "non_allelic_homologous"}, + {"recombination_feature", "other"}, + }; + feature.SetData().SetImp().SetKey("misc_recomb"); + CRef recombination_class(new CGb_qual); + recombination_class->SetQual("recombination_class"); + auto cit = mapTypeToQual.find(so_type); + if (cit == mapTypeToQual.end()) { + recombination_class->SetVal(so_type); + } + else { + recombination_class->SetVal(cit->second); + } + feature.SetQual().push_back(recombination_class); + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeMiscRna( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + feature.SetData().SetImp().SetKey("misc_RNA"); + if (so_type=="pseudogenic_transcript") { + feature.SetPseudo(true); + } + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeImp( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + static const map mapTypeToKey = { + {"C_gene_segment", "C_region"}, + {"D_gene_segment", "D_segment"}, + {"D_loop", "D-loop"}, + {"J_gene_segment", "J_segment"}, + {"V_gene_segment", "V_segment"}, + {"binding_site", "misc_binding"}, + {"five_prime_UTR", "5\'UTR"}, + {"long_terminal_repeat", "LTR"}, + {"mature_protein_region", "mat_peptide"}, + {"mobile_genetic_element", "mobile_element"}, + {"modified_DNA_base", "modified_base"}, + {"origin_of_replication", "rep_origin"}, + {"primary_transcript", "prim_transcript"}, + {"primer_binding_site", "primer_bind"}, + {"protein_binding_site", "protein_bind"}, + {"region", "source"}, + {"sequence_alteration", "variation"}, + {"sequence_difference", "misc_difference"}, + {"sequence_secondary_structure", "misc_structure"}, + {"sequence_uncertainty", "unsure"}, + {"signal_peptide", "sig_peptide"}, + {"three_prime_UTR", "3\'UTR"}, + }; + auto cit = mapTypeToKey.find(so_type); + if (cit == mapTypeToKey.end()) { + feature.SetData().SetImp().SetKey(so_type); + } + else { + feature.SetData().SetImp().SetKey(cit->second); + } + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeRegion( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + feature.SetData().SetRegion(); + CRef qual(new CGb_qual("SO_type", so_type)); + feature.SetQual().push_back(qual); + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeRegulatory( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + static const map mapTypeToQual = { + {"DNAsel_hypersensitive_site", "DNase_I_hypersensitive_site"}, + {"GC_rich_promoter_region", "GC_signal"}, + {"boundary_element", "insulator"}, + {"regulatory_region", "other"}, + {"ribosome_entry_site", "ribosome_binding_site"}, + }; + feature.SetData().SetImp().SetKey("regulatory"); + CRef regulatory_class(new CGb_qual); + regulatory_class->SetQual("regulatory_class"); + auto cit = mapTypeToQual.find(so_type); + if (cit == mapTypeToQual.end()) { + regulatory_class->SetVal(so_type); + } + else { + regulatory_class->SetVal(cit->second); + } + feature.SetQual().push_back(regulatory_class); + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xFeatureMakeRepeatRegion( + const string& so_type, + CSeq_feat& feature) +// ---------------------------------------------------------------------------- +{ + static const map mapTypeToSatellite = { + {"microsatellite", "microsatellite"}, + {"minisatellite", "minisatellite"}, + {"satellite_DNA", "satellite"}, + }; + static const map mapTypeToRptType = { + {"tandem_repeat", "tandem"}, + {"inverted_repeat", "inverted"}, + {"direct_repeat", "direct"}, + {"nested_repeat", "nested"}, + {"non_LTR_retrotransposon_polymeric_tract", "non_ltr_retrotransposon_polymeric_tract"}, + {"X_element_combinatorial_repeat", "x_element_combinatorial_repeat"}, + {"Y_prime_element", "y_prime_element"}, + {"repeat_region", "other"}, + }; + feature.SetData().SetImp().SetKey("repeat_region"); + + CRef qual(new CGb_qual); + auto cit = mapTypeToSatellite.find(so_type); + if (cit != mapTypeToSatellite.end()) { + qual->SetQual("satellite"); + qual->SetVal(cit->second); + } + else { + qual->SetQual("rpt_type"); + cit = mapTypeToRptType.find(so_type); + if (cit == mapTypeToRptType.end()) { + qual->SetVal(so_type); + } + else { + qual->SetVal(cit->second); + } + } + feature.SetQual().push_back(qual); + return true; +} + + +// ---------------------------------------------------------------------------- +CSoMap::TYPEFUNCMAP CSoMap::mMapTypeFunc = { +// ---------------------------------------------------------------------------- + {CSeqFeatData::eSubtype_3UTR, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_5UTR, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_assembly_gap, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_C_region, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_cdregion, CSoMap::xMapCds}, + {CSeqFeatData::eSubtype_centromere, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_conflict, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_D_loop, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_D_segment, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_exon, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_gap, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_gene, CSoMap::xMapGene}, + {CSeqFeatData::eSubtype_10_signal, CSoMap::xMapGene}, + {CSeqFeatData::eSubtype_iDNA, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_intron, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_J_segment, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_LTR, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_mat_peptide, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_misc_binding, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_misc_difference, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_misc_feature, CSoMap::xMapMiscFeature}, + {CSeqFeatData::eSubtype_misc_recomb, CSoMap::xMapMiscRecomb}, + {CSeqFeatData::eSubtype_misc_RNA, CSoMap::xMapRna}, + {CSeqFeatData::eSubtype_misc_structure, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_mobile_element, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_modified_base, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_mRNA, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_N_region, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_ncRNA, CSoMap::xMapNcRna}, + {CSeqFeatData::eSubtype_operon, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_oriT, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_otherRNA, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_polyA_site, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_preRNA, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_precursor_RNA, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_prim_transcript, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_primer_bind, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_propeptide, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_protein_bind, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_region, CSoMap::xMapRegion}, + {CSeqFeatData::eSubtype_regulatory, CSoMap::xMapRegulatory}, + {CSeqFeatData::eSubtype_rep_origin, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_repeat_region, CSoMap::xMapRepeatRegion}, + {CSeqFeatData::eSubtype_rRNA, CSoMap::xMapRna}, + {CSeqFeatData::eSubtype_S_region, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_sig_peptide, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_source, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_stem_loop, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_STS, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_snRNA, CSoMap::xMapNcRna}, + {CSeqFeatData::eSubtype_snoRNA, CSoMap::xMapNcRna}, + {CSeqFeatData::eSubtype_telomere, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_tmRNA, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_transit_peptide, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_tRNA, CSoMap::xMapRna}, + {CSeqFeatData::eSubtype_unsure, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_V_region, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_V_segment, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_variation, CSoMap::xMapGeneric}, + + {CSeqFeatData::eSubtype_attenuator, CSoMap::xMapGeneric}, + {CSeqFeatData::eSubtype_enhancer, xMapGeneric}, + {CSeqFeatData::eSubtype_promoter, xMapGeneric}, + {CSeqFeatData::eSubtype_terminator, CSoMap::xMapGeneric}, + + {CSeqFeatData::eSubtype_bond, CSoMap::xMapBond}, +}; + +// ---------------------------------------------------------------------------- +bool CSoMap::FeatureToSoType( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + auto subtype = feature.GetData().GetSubtype(); + TYPEFUNCENTRY cit = mMapTypeFunc.find(subtype); + if (cit == mMapTypeFunc.end()) { + return false; + } + return (cit->second)(feature, so_type); +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapGeneric( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + static const map mapSubtypeToSoType = { + {CSeqFeatData::eSubtype_3UTR, "three_prime_UTR"}, + {CSeqFeatData::eSubtype_5UTR, "five_prime_UTR"}, + {CSeqFeatData::eSubtype_assembly_gap, "assemply_gap"}, + {CSeqFeatData::eSubtype_C_region, "C_gene_segment"}, + {CSeqFeatData::eSubtype_centromere, "centromere"}, + {CSeqFeatData::eSubtype_conflict, "sequence_conflict"}, + {CSeqFeatData::eSubtype_D_loop, "D_loop"}, + {CSeqFeatData::eSubtype_D_segment, "D_gene_segment"}, + {CSeqFeatData::eSubtype_exon, "exon"}, + {CSeqFeatData::eSubtype_enhancer, "enhancer"}, + {CSeqFeatData::eSubtype_gap, "gap"}, + {CSeqFeatData::eSubtype_iDNA, "iDNA"}, + {CSeqFeatData::eSubtype_intron, "intron"}, + {CSeqFeatData::eSubtype_J_segment, "J_gene_segment"}, + {CSeqFeatData::eSubtype_LTR, "long_terminal_repeat"}, + {CSeqFeatData::eSubtype_mat_peptide, "mature_protein_region"}, + {CSeqFeatData::eSubtype_misc_binding, "binding_site"}, + {CSeqFeatData::eSubtype_misc_difference, "sequence_difference"}, + {CSeqFeatData::eSubtype_misc_structure, "sequence_secondary_structure"}, + {CSeqFeatData::eSubtype_mobile_element, "mobile_genetic_element"}, + {CSeqFeatData::eSubtype_modified_base, "modified_DNA_base"}, + {CSeqFeatData::eSubtype_mRNA, "mRNA"}, + {CSeqFeatData::eSubtype_N_region, "N_region"}, + {CSeqFeatData::eSubtype_operon, "operon"}, + {CSeqFeatData::eSubtype_oriT, "oriT"}, + {CSeqFeatData::eSubtype_otherRNA, "transcript"}, + {CSeqFeatData::eSubtype_polyA_site, "polyA_site"}, + {CSeqFeatData::eSubtype_precursor_RNA, "primary_transcript"}, + {CSeqFeatData::eSubtype_preRNA, "primary_transcript"}, + {CSeqFeatData::eSubtype_prim_transcript, "primary_transcript"}, + {CSeqFeatData::eSubtype_primer_bind, "primer_binding_site"}, + {CSeqFeatData::eSubtype_promoter, "promoter"}, + {CSeqFeatData::eSubtype_propeptide, "propeptide"}, + {CSeqFeatData::eSubtype_protein_bind, "protein_binding_site"}, + {CSeqFeatData::eSubtype_rep_origin, "origin_of_replication"}, + {CSeqFeatData::eSubtype_S_region, "S_region"}, + {CSeqFeatData::eSubtype_sig_peptide, "signal_peptide"}, + {CSeqFeatData::eSubtype_source, "region"}, + {CSeqFeatData::eSubtype_stem_loop, "stem_loop"}, + {CSeqFeatData::eSubtype_STS, "STS"}, + {CSeqFeatData::eSubtype_telomere, "telomere"}, + {CSeqFeatData::eSubtype_terminator, "terminator"}, + {CSeqFeatData::eSubtype_tmRNA, "tmRNA"}, + {CSeqFeatData::eSubtype_transit_peptide, "transit_peptide"}, + {CSeqFeatData::eSubtype_unsure, "sequence_uncertainty"}, + {CSeqFeatData::eSubtype_V_region, "V_region"}, + {CSeqFeatData::eSubtype_V_segment, "V_gene_segment"}, + {CSeqFeatData::eSubtype_variation, "sequence_alteration"}, + //{CSeqFeatData::eSubtype_attenuator, "attenuator"}, + }; + auto subtype = feature.GetData().GetSubtype(); + auto cit = mapSubtypeToSoType.find(subtype); + if (cit != mapSubtypeToSoType.end()) { + so_type = cit->second; + return true; + } + return false; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapRegion( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + so_type = "biological_region"; + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapCds( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + if (feature.IsSetPseudo() && feature.GetPseudo()) { + so_type = "pseudogenic_CDS"; + return true; + } + for (auto qual: feature.GetQual()) { + if (qual->GetQual() == "pseudo" || qual->GetQual() == "pseudogene") { + so_type = "pseudogenic_CDS"; + return true; + } + } + so_type = "CDS"; + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapGene( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + if (feature.IsSetPseudo() && feature.GetPseudo()) { + so_type = "pseudogene"; + return true; + } + for (auto qual: feature.GetQual()) { + if (qual->GetQual() == "pseudo" || qual->GetQual() == "pseudogene") { + so_type = "pseudogene"; + return true; + } + } + so_type = "gene"; + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapRna( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + static const map mapSubtypeStraight = { + {CSeqFeatData::eSubtype_misc_RNA, "transcript"}, + {CSeqFeatData::eSubtype_rRNA, "rRNA"}, + {CSeqFeatData::eSubtype_tRNA, "tRNA"}, + }; + static const map mapSubtypePseudo = { + {CSeqFeatData::eSubtype_misc_RNA, "pseudogenic_transcript"}, + {CSeqFeatData::eSubtype_rRNA, "pseudogenic_rRNA"}, + {CSeqFeatData::eSubtype_tRNA, "pseudogenic_tRNA"}, + }; + + auto subtype = feature.GetData().GetSubtype(); + if (feature.IsSetPseudo() && feature.GetPseudo()) { + auto cit = mapSubtypePseudo.find(subtype); + if (cit == mapSubtypePseudo.end()) { + return false; + } + so_type = cit->second; + return true; + } + if (feature.IsSetPseudo() && !feature.GetPseudo()) { + auto cit = mapSubtypeStraight.find(subtype); + if (cit == mapSubtypeStraight.end()) { + return false; + } + so_type = cit->second; + return true; + } + + for (auto qual: feature.GetQual()) { + if (qual->GetQual() == "pseudo" || qual->GetQual() == "pseudogene") { + auto cit = mapSubtypePseudo.find(subtype); + if (cit == mapSubtypePseudo.end()) { + return false; + } + so_type = cit->second; + return true; + } + } + auto cit = mapSubtypeStraight.find(subtype); + if (cit == mapSubtypeStraight.end()) { + return false; + } + so_type = cit->second; + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapMiscFeature( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + map mapFeatClassToSoType = { + {"transcription_start_site", "TSS"}, + {"other", "sequence_feature"}, + }; + string feat_class = feature.GetNamedQual("feat_class"); + if (feat_class.empty()) { + so_type = "sequence_feature"; + return true; + } + auto cit = mapFeatClassToSoType.find(feat_class); + if (cit == mapFeatClassToSoType.end()) { + so_type = feat_class; + return true; + } + so_type = cit->second; + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapMiscRecomb( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + map mapRecombClassToSoType = { + {"meiotic", "meiotic_recombination_region"}, + {"mitotic", "mitotic_recombination_region"}, + {"non_allelic_homologous", "non_allelic_homologous_recombination_region"}, + {"meiotic_recombination", "meiotic_recombination_region"}, + {"mitotic_recombination", "mitotic_recombination_region"}, + {"non_allelic_homologous_recombination", "non_allelic_homologous_recombination_region"}, + {"other", "recombination_region"}, + }; + string recomb_class = feature.GetNamedQual("recombination_class"); + if (recomb_class.empty()) { + so_type = "recombination_region"; + return true; + } + auto cit = mapRecombClassToSoType.find(recomb_class); + if (cit == mapRecombClassToSoType.end()) { + auto validClasses = CSeqFeatData::GetRecombinationClassList(); + auto valid = std::find(validClasses.begin(), validClasses.end(), recomb_class); + if (valid == validClasses.end()) { + so_type = "recombination_region"; + } + else { + so_type = recomb_class; + } + return true; + } + so_type = cit->second; + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapOtherRna( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + so_type = "transcript"; + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapNcRna( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + map mapNcRnaClassToSoType = { + {"antisense_RNA", "antisense_RNA"}, + {"autocatalytically_spliced_intron", "autocatalytically_spliced_intron"}, + {"guide_RNA", "guide_RNA"}, + {"hammerhead_ribozyme", "hammerhead_ribozyme"}, + {"lncRNA", "lnc_RNA"}, + {"miRNA", "miRNA"}, + {"other", "ncRNA"}, + {"piRNA", "piRNA"}, + {"rasiRNA", "rasiRNA"}, + {"ribozyme", "ribozyme"}, + {"RNase_MRP_RNA", "RNase_MRP_RNA"}, + {"RNase_P_RNA", "RNase_P_RNA"}, + {"scRNA", "scRNA"}, + {"siRNA", "siRNA"}, + {"snRNA", "snRNA"}, + {"snoRNA", "snoRNA"}, + {"SRP_RNA", "SRP_RNA"}, + {"telomerase_RNA", "telomerase_RNA"}, + {"vault_RNA", "vault_RNA"}, + {"Y_RNA", "Y_RNA"}, + }; + string ncrna_class = feature.GetNamedQual("ncRNA_class"); + if (ncrna_class.empty()) { + if (feature.IsSetData() && + feature.GetData().IsRna() && + feature.GetData().GetRna().IsSetExt() && + feature.GetData().GetRna().GetExt().IsGen() && + feature.GetData().GetRna().GetExt().GetGen().IsSetClass()) { + ncrna_class = feature.GetData().GetRna().GetExt().GetGen().GetClass(); + if (ncrna_class == "classRNA") { + ncrna_class = "ncRNA"; + } + } + } + if (ncrna_class.empty()) { + if (feature.IsSetData() && + feature.GetData().IsRna() && + feature.GetData().GetRna().IsSetType()) { + auto ncrna_type = feature.GetData().GetRna().GetType(); + ncrna_class = CRNA_ref::GetRnaTypeName(ncrna_type); + } + } + if (ncrna_class.empty()) { + ncrna_class = "ncRNA"; + return true; + } + auto cit = mapNcRnaClassToSoType.find(ncrna_class); + if (cit == mapNcRnaClassToSoType.end()) { + so_type = "ncRNA"; + return true; + } + so_type = cit->second; + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapRegulatory( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + map mapRegulatoryClassToSoType = { + {"DNase_I_hypersensitive_site", "DNaseI_hypersensitive_site"}, + {"GC_signal", "GC_rich_promoter_region"}, + {"enhancer_blocking_element", "regulatory_region"}, + {"imprinting_control_region", "regulatory_region"}, + {"matrix_attachment_region", "matrix_attachment_site"}, + {"other", "regulatory_region"}, + {"response_element", "regulatory_region"}, + {"ribosome_binding_site", "ribosome_entry_site"}, + }; + + string regulatory_class = feature.GetNamedQual("regulatory_class"); + if (regulatory_class.empty()) { + so_type = "regulatory_region"; + return true; + } + auto cit = mapRegulatoryClassToSoType.find(regulatory_class); + if (cit == mapRegulatoryClassToSoType.end()) { + auto validClasses = CSeqFeatData::GetRegulatoryClassList(); + auto valid = std::find( + validClasses.begin(), validClasses.end(), regulatory_class); + if (valid == validClasses.end()) { + so_type = "regulatory_region"; + } + else { + so_type = regulatory_class; + } + return true; + } + so_type = cit->second; + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapBond( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + map mapBondTypeToSoType = { + {"disulfide", "disulfide_bond"}, + {"xlink", "cross_link"}, + }; + string bond_type = feature.GetNamedQual("bond_type"); + if (bond_type.empty()) { + return false; + } + auto cit = mapBondTypeToSoType.find(bond_type); + if (cit == mapBondTypeToSoType.end()) { + so_type = bond_type; + return true; + } + so_type = cit->second; + return true; +} + +// ---------------------------------------------------------------------------- +bool CSoMap::xMapRepeatRegion( + const CSeq_feat& feature, + string& so_type) +// ---------------------------------------------------------------------------- +{ + map mapSatelliteToSoType = { + {"satellite", "satellite_DNA"}, + {"microsatellite", "microsatellite"}, + {"minisatellite", "minisatellite"}, + }; + string satellite = feature.GetNamedQual("satellite"); + if (!satellite.empty()) { + auto cit = mapSatelliteToSoType.find(satellite); + if (cit == mapSatelliteToSoType.end()) { + return false; + } + so_type = cit->second; + return true; + } + + map mapRptTypeToSoType = { + {"tandem", "tandem_repeat"}, + {"inverted", "inverted_repeat"}, + {"flanking", "repeat_region"}, + {"terminal", "repeat_region"}, + {"direct", "direct_repeat"}, + {"dispersed", "dispersed_repeat"}, + {"nested", "nested_repeat"}, + {"non_ltr_retrotransposon_polymeric_tract", "non_LTR_retrotransposon_polymeric_tract"}, + {"x_element_combinatorical_repeat", "X_element_combinatorical_repeat"}, + {"y_prime_element", "Y_prime_element"}, + {"other", "repeat_region"}, + }; + string rpt_type = feature.GetNamedQual("rpt_type"); + if (rpt_type.empty()) { + so_type = "repeat_region"; + return true; + } + auto cit = mapRptTypeToSoType.find(rpt_type); + if (cit == mapRptTypeToSoType.end()) { + so_type = rpt_type; + return true; + } + so_type = cit->second; + return true; +} + +// ---------------------------------------------------------------------------- +CSoMap::SOALIASMAP CSoMap::mMapSoAliases = { +// ---------------------------------------------------------------------------- + {"-10_signal", "minus_10_signal"}, + {"-35_signal", "minus_35_signal"}, + {"3'UTR", "three_prime_UTR"}, + {"3'clip", "three_prime_clip"}, + {"5'UTR", "five_prime_UTR"}, + {"5'clip", "five_prime_clip"}, + {"C_region", "C_gene_segment"}, + {"D-loop", "D_loop"}, + {"D_segment", "D_gene_segment"}, + {"GC_signal", "GC_rich_promoter_region"}, + {"J_segment", "J_gene_segment"}, + {"LTR", "long_terminal_repeat"}, + {"RBS", "ribosome_entry_site"}, + {"TATA_signal", "TATA_box"}, + {"V_segment", "V_gene_segment"}, + {"assembly_gap", "gap"}, + {"Comment", "remark"}, + {"conflict", "sequence_conflict"}, + {"mat_peptide_nt", "mature_protein_region"}, + {"mat_peptide", "mature_protein_region"}, + {"misc_binding", "binding_site"}, + {"misc_difference", "sequence_difference"}, + {"misc_feature", "sequence_feature"}, + {"misc_recomb", "recombination_feature"}, + {"misc_signal", "regulatory_region"}, + {"misc_structure", "sequence_secondary_structure"}, + {"mobile_element", "mobile_genetic_element"}, + {"modified_base", "modified_DNA_base"}, + {"misc_RNA", "transcript"}, + {"polyA_signal", "polyA_signal_sequence"}, + {"pre_RNA", "primary_transcript"}, + {"precursor_RNA", "primary_transcript"}, + {"proprotein", "immature_peptide_region"}, + {"prim_transcript", "primary_transcript"}, + {"primer_bind", "primer_binding_site"}, + {"Protein", "polypeptide"}, + {"protein_bind", "protein_binding_site"}, + {"SecStr", "sequence_secondary_structure"}, + {"rep_origin", "origin_of_replication"}, + {"Rsite", "restriction_enzyme_cut_site"}, + {"satellite", "satellite_DNA"}, + {"Shine_Dalgarno_sequence", "ribosome_entry_site"}, + {"sig_peptide_nt", "signal_peptide"}, + {"sig_peptide", "signal_peptide"}, + {"Site", "site"}, + {"Site-ref", "site"}, + {"transit_peptide_nt", "transit_peptide"}, + {"unsure", "sequence_uncertainty"}, + {"variation", "sequence_alteration"}, + {"VariationRef", "sequence_alteration"}, + {"virion", "viral_sequence"}, +}; + +// ---------------------------------------------------------------------------- +string CSoMap::ResolveSoAlias( + const string& alias) +// ---------------------------------------------------------------------------- +{ + ALIASENTRY cit = mMapSoAliases.find(alias); + if (cit == mMapSoAliases.end()) { + return alias; + } + return cit->second; +} + +END_NCBI_SCOPE diff --git a/c++/src/objects/seq/sofa_map.cpp b/c++/src/objects/seq/sofa_map.cpp index 2fd8e2c6..cc2199ab 100644 --- a/c++/src/objects/seq/sofa_map.cpp +++ b/c++/src/objects/seq/sofa_map.cpp @@ -1,4 +1,4 @@ -/* $Id: sofa_map.cpp 520684 2016-11-30 18:52:55Z ivanov $ +/* $Id: sofa_map.cpp 533585 2017-04-18 13:44:28Z ludwigf $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -41,6 +41,168 @@ USING_SCOPE(objects); #define GT( a, b ) CFeatListItem( CSeqFeatData::a, CSeqFeatData::b, "", "" ) +CSofaMap::TYPEMAP CSofaMap::mMapSofaTypeToId; + +CSofaMap::TYPEMAP CSofaMap::mMapSofaIdToType = { + {"SO:0000001", "region"}, + {"SO:0000002", "sequece_secondary_structure"}, + {"SO:0000005", "satellite_DNA"}, + {"SO:0000013", "scRNA"}, + {"SO:0000035", "riboswitch"}, + {"SO:0000036", "matrix_attachment_site"}, + {"SO:0000037", "locus_control_region"}, + {"SO:0000104", "polypeptide"}, + {"SO:0000110", "sequence_feature"}, + {"SO:0000139", "ribosome_entry_site"}, + {"SO:0000140", "attenuator"}, + {"SO:0000141", "terminator"}, + {"SO:0000147", "exon"}, + {"SO:0000165", "enhancer"}, + {"SO:0000167", "promoter"}, + {"SO:0000172", "CAAT_signal"}, + {"SO:0000173", "GC_rich_promoter_region"}, + {"SO:0000174", "TATA_box"}, + {"SO:0000175", "minus_10_signal"}, + {"SO:0000176", "minus_35_signal"}, + {"SO:0000178", "operon"}, + {"SO:0000185", "primary_transcript"}, + {"SO:0000188", "intron"}, + {"SO:0000204", "five_prime_UTR"}, + {"SO:0000205", "three_prime_UTR"}, + {"SO:0000234", "mRNA"}, + {"SO:0000252", "rRNA"}, + {"SO:0000253", "tRNA"}, + {"SO:0000274", "snRNA"}, + {"SO:0000275", "snoRNA"}, + {"SO:0000276", "miRNA"}, + {"SO:0000286", "long_terminal_repeat"}, + {"SO:0000289", "microsatellite"}, + {"SO:0000294", "inverted_repeat"}, + {"SO:0000296", "origin_of_replication"}, + {"SO:0000297", "D_loop"}, + {"SO:0000298", "recombination_feature"}, + {"SO:0000305", "modified_DNA_base"}, + {"SO:0000313", "stem_loop"}, + {"SO:0000314", "direct_repeat"}, + {"SO:0000315", "TSS"}, + {"SO:0000316", "CDS"}, + {"SO:0000330", "conserved_region"}, + {"SO:0000331", "STS"}, + {"SO:0000336", "pseudogene"}, + {"SO:0000374", "ribozyme"}, + {"SO:0000380", "hammerhead_ribozyme"}, + {"SO:0000385", "RNase_MRP_RNA"}, + {"SO:0000386", "RNase_P_RNA"}, + {"SO:0000404", "vault_RNA"}, + {"SO:0000405", "Y_RNA"}, + {"SO:0000409", "binding_site"}, + {"SO:0000410", "protein_binding_site"}, + {"SO:0000413", "sequence_difference"}, + {"SO:0000418", "signal_peptide"}, + {"SO:0000419", "mature_protein_region"}, + {"SO:0000433", "non_LTR_retrotransposon_polymeric_tract"}, + {"SO:0000454", "rasiRNA"}, + {"SO:0000458", "D_gene_segment"}, + {"SO:0000466", "V_gene_segment"}, + {"SO:0000470", "J_gene_segment"}, + {"SO:0000478", "C_gene_segment"}, + {"SO:0000516", "pseudogenic_transcript"}, + {"SO:0000551", "polyA_signal_sequence"}, + {"SO:0000553", "polyA_site"}, + {"SO:0000577", "centromere"}, + {"SO:0000584", "tmRNA"}, + {"SO:0000588", "autocatalytically_spliced_intron"}, + {"SO:0000590", "SRP_RNA"}, + {"SO:0000602", "guide_RNA"}, + {"SO:0000624", "telomere"}, + {"SO:0000625", "silencer"}, + {"SO:0000627", "insulator"}, + {"SO:0000644", "antisense_RNA"}, + {"SO:0000646", "siRNA"}, + {"SO:0000655", "ncRNA"}, + {"SO:0000657", "repeat_region"}, + {"SO:0000658", "dispersed_repeat"}, + {"SO:0000673", "transcript"}, + {"SO:0000685", "DNAsel_hypersensitive_site"}, + {"SO:0000704", "gene"}, + {"SO:0000705", "tandem_repeat"}, + {"SO:0000714", "nucleotide_motif"}, + {"SO:0000723", "iDNA"}, + {"SO:0000724", "oriT"}, + {"SO:0000725", "transit_peptide"}, + {"SO:0000730", "gap"}, + {"SO:0000777", "pseudogenic_rRNA"}, + {"SO:0000778", "pseudogenic_tRNA"}, + {"SO:0001021", "chromosome_preakpoint"}, + {"SO:0001035", "piRNA"}, + {"SO:0001037", "mobile_genetic_element"}, + {"SO:0001055", "transcriptional_cis_regulatory_region"}, + {"SO:0001059", "sequence_alteration"}, + {"SO:0001062", "propeptide"}, + {"SO:0001086", "sequence_uncertainty"}, + {"SO:0001087", "cross_link"}, + {"SO:0001088", "disulfide_bond"}, + {"SO:0001268", "recoding_stimulatory_region"}, + {"SO:0001411", "biological_region"}, + {"SO:0001484", "X_element_combinatorical_repeat"}, + {"SO:0001485", "Y_prime_element"}, + {"SO:0001496", "telomeric_repeat"}, + {"SO:0001649", "nested_repeat"}, + {"SO:0001682", "replication_regulatory_region"}, + {"SO:0001797", "centromeric_repeat"}, + {"SO:0001833", "V_region"}, + {"SO:0001835", "N_region"}, + {"SO:0001836", "S_region"}, + {"SO:0001877", "lnc_RNA"}, + {"SO:0001917", "CAGE_cluster"}, + {"SO:0002020", "boundary_element"}, + {"SO:0002072", "sequence_comparison"}, + {"SO:0002087", "pseudogenic_CDS"}, + {"SO:0002094", "non_allelic_homologous_recombination_region"}, + {"SO:0002154", "mitotic_recombination_region"}, + {"SO:0002155", "meiotic_recombination_region"}, + {"SO:0005836", "regulatory_region"}, + {"SO:0005850", "primary_binding_site"}, + + {"SO:0000000", ""}, + //{"SO:UNKNOWN", "replication_start_site"}, + //{"SO:UNKNOWN", "nucleotide_site"}, + //{"SO:UNKNOWN", "nucleotide_cleavage_site"}, + //{"SO:UNKNOWN", "repeat_instability_region"}, +}; + +// ---------------------------------------------------------------------------- +string CSofaMap::SofaIdToType( + const string& sofa_id) +// ---------------------------------------------------------------------------- +{ + TYPEENTRY type_it = CSofaMap::mMapSofaIdToType.find(sofa_id); + if (type_it == CSofaMap::mMapSofaIdToType.end()) { + return ""; + } + return type_it->second; +} + +// ---------------------------------------------------------------------------- +string CSofaMap::SofaTypeToId( + const string& sofa_type) +// ---------------------------------------------------------------------------- +{ + if (CSofaMap::mMapSofaTypeToId.empty()) { + for (TYPEENTRY cit = CSofaMap::mMapSofaIdToType.begin(); + cit != CSofaMap::mMapSofaIdToType.end(); + ++cit) { + CSofaMap::mMapSofaTypeToId[cit->second] = cit->first; + } + } + TYPEENTRY id_it = mMapSofaTypeToId.find(sofa_type); + if (id_it == CSofaMap::mMapSofaTypeToId.end()) { + return ""; + } + return id_it->second; +} + + void CSofaMap::x_Init() { m_default = SofaType( 1, "region" ); @@ -71,7 +233,7 @@ void CSofaMap::x_Init() m_Map[ GT( e_Imp, eSubtype_D_loop ) ] = SofaType( 297, "D_loop" ); m_Map[ GT( e_Imp, eSubtype_D_segment ) ] = SofaType( 458, "D_gene_segment" ); m_Map[ GT( e_Imp, eSubtype_exon ) ] = SofaType( 147, "exon" ); - m_Map[ GT( e_Imp, eSubtype_GC_signal ) ] = SofaType( 173, "GC_rich_promoter" ); + m_Map[ GT( e_Imp, eSubtype_GC_signal ) ] = SofaType( 173, "GC_rich_promoter_region" ); m_Map[ GT( e_Imp, eSubtype_J_segment ) ] = SofaType( 470, "J_gene_segment" ); m_Map[ GT( e_Imp, eSubtype_LTR ) ] = SofaType( 286, "long_terminal_repeat" ); m_Map[ GT( e_Imp, eSubtype_N_region ) ] = SofaType( 1835, "N_region" ); diff --git a/c++/src/objects/seqalign/Seq_align.cpp b/c++/src/objects/seqalign/Seq_align.cpp index f5f2af53..50155cc5 100644 --- a/c++/src/objects/seqalign/Seq_align.cpp +++ b/c++/src/objects/seqalign/Seq_align.cpp @@ -1,4 +1,4 @@ -/* $Id: Seq_align.cpp 461118 2015-03-06 13:29:39Z grichenk $ +/* $Id: Seq_align.cpp 539794 2017-06-27 16:53:25Z mozese2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -438,9 +438,9 @@ static const char* const sc_ScoreHelpText[] = { "Count of negatives; protein-to-DNA score", "Count of mismatches", "Number of gap bases in the alignment", - "Percent identity (0.0-100.0); count each base in a gap as a mismatch", + "Percent identity (0.0-100.0); count each base in a gap in any row as a mismatch", "Percent identity (0.0-100.0); don't count gaps", - "Percent identity (0.0-100.0); count a gap of any length as a mismatch of length 1", + "Percent identity (0.0-100.0); count a gap of any length in any row as a mismatch of length 1", "Percentage of query sequence aligned to subject (0.0-100.0)", "Blast-style sum_e", "Composition-adjustment method from BLAST", @@ -1584,13 +1584,18 @@ TSeqPos CSeq_align::GetNumGapOpeningsWithinRanges( return s_GetGapCount(*this, row, ranges, false); } -TSeqPos CSeq_align::GetNumFrameshifts(TDim row) const +static TSeqPos s_GetNumFrameshifts(const CSeq_align& align, CSeq_align::TDim row, + const CRangeCollection &ranges) { + if (ranges.empty()) { + return 0; + } + TSeqPos retval = 0; - switch (GetSegs().Which()) { + switch (align.GetSegs().Which()) { case CSeq_align::TSegs::e_Denseg: {{ - const CDense_seg& ds = GetSegs().GetDenseg(); + const CDense_seg& ds = align.GetSegs().GetDenseg(); for (CDense_seg::TNumseg i = 0; i < ds.GetNumseg(); ++i) { bool is_gapped = false; for (CDense_seg::TDim j = 0; j < ds.GetDim(); ++j) { @@ -1600,8 +1605,26 @@ TSeqPos CSeq_align::GetNumFrameshifts(TDim row) const break; } } - if (is_gapped && ds.GetLens()[i] % 3) { - ++retval; + if (is_gapped) { + TSeqPos gap_len = ds.GetLens()[i]; + if (!ranges.begin()->IsWhole()) { + TSignedSeqPos gap_start = ds.GetStarts()[i * ds.GetDim()]; + if (gap_start >= 0) { + gap_len = s_IntersectionLength(ranges, + TSeqRange(gap_start, gap_start + gap_len - 1)); + } else { + gap_start = ds.GetStarts()[(i-1) * ds.GetDim()] + + ds.GetLens()[i-1]; + if (s_IntersectionLength(ranges, + TSeqRange(gap_start, gap_start)) == 0) + { + gap_len = 0; + } + } + } + if (gap_len % 3) { + ++retval; + } } } }} @@ -1611,18 +1634,18 @@ TSeqPos CSeq_align::GetNumFrameshifts(TDim row) const {{ CConstRef last_align; ITERATE(CSeq_align::TSegs::TDisc::Tdata, iter, - GetSegs().GetDisc().Get()) { + align.GetSegs().GetDisc().Get()) { retval += (*iter)->GetNumFrameshifts(row); for (int j = 0; j <= 1; ++j) { if (last_align && (row < 0 || row == j)) { bool reverse = last_align->GetSeqStart(j) > (*iter)->GetSeqStart(j); - int gap_size = + TSeqRange gap( + reverse ? (*iter)->GetSeqStop(j) + 1 + : last_align->GetSeqStop(j) + 1, reverse ? last_align->GetSeqStart(j) - 1 - : (*iter)->GetSeqStart(j) - 1; - gap_size -= reverse ? (*iter)->GetSeqStop(j) - : last_align->GetSeqStop(j); - if (gap_size % 3) { + : (*iter)->GetSeqStart(j) - 1); + if (s_IntersectionLength(ranges, gap) % 3) { ++retval; } } @@ -1635,23 +1658,23 @@ TSeqPos CSeq_align::GetNumFrameshifts(TDim row) const case CSeq_align::TSegs::e_Spliced: {{ bool is_minus[] = { - GetSegs().GetSpliced().CanGetProduct_strand() - && GetSegs().GetSpliced().GetProduct_strand() + align.GetSegs().GetSpliced().CanGetProduct_strand() + && align.GetSegs().GetSpliced().GetProduct_strand() == eNa_strand_minus, - GetSegs().GetSpliced().CanGetGenomic_strand() - && GetSegs().GetSpliced().GetGenomic_strand() + align.GetSegs().GetSpliced().CanGetGenomic_strand() + && align.GetSegs().GetSpliced().GetGenomic_strand() == eNa_strand_minus }; CConstRef last_exon; - vector last_edge_insertions(2); - ITERATE (CSpliced_seg::TExons, iter, GetSegs().GetSpliced().GetExons()) { + vector last_edge_insertions(2, 0); + ITERATE (CSpliced_seg::TExons, iter, align.GetSegs().GetSpliced().GetExons()) { const CSpliced_exon& exon = **iter; vector edge_insertions(2, 0); - for (TDim r = 0; r < 2; ++r) { + for (CSeq_align::TDim r = 0; r < 2; ++r) { if (row != r) { CRangeCollection insertions = exon.GetRowSeq_insertions( - r, GetSegs().GetSpliced()); + r, align.GetSegs().GetSpliced(), ranges); vector edges; edges.push_back(TSeqRange(exon.GetRowSeq_range(r,true).GetFrom(), exon.GetRowSeq_range(r,true).GetFrom())); @@ -1688,12 +1711,10 @@ TSeqPos CSeq_align::GetNumFrameshifts(TDim row) const ? exon : *last_exon; const CSpliced_exon &higher_exon = is_minus[0] ? *last_exon : exon; - TSeqPos gap_start = - lower_exon.GetProduct_end().AsSeqPos() + 1; - TSeqPos gap_end = - higher_exon.GetProduct_start().AsSeqPos(); - if (gap_end >= gap_start && - (gap_end - gap_start + last_edge_insertions[0]) % 3) + TSeqRange gap(lower_exon.GetProduct_end().AsSeqPos() + 1, + higher_exon.GetProduct_start().AsSeqPos() - 1); + if ((s_IntersectionLength(ranges, gap) + + last_edge_insertions[0]) % 3) { ++retval; } @@ -1713,6 +1734,25 @@ TSeqPos CSeq_align::GetNumFrameshifts(TDim row) const return retval; } +TSeqPos CSeq_align::GetNumFrameshifts(TDim row) const +{ + return s_GetNumFrameshifts(*this, row, + CRangeCollection(TSeqRange::GetWhole())); +} + +TSeqPos CSeq_align::GetNumFrameshiftsWithinRange( + const TSeqRange &range, TDim row) const +{ + return s_GetNumFrameshifts(*this, row, CRangeCollection(range)); +} + +TSeqPos CSeq_align::GetNumFrameshiftsWithinRanges( + const CRangeCollection &ranges, TDim row) const +{ + return s_GetNumFrameshifts(*this, row, ranges); +} + + CRangeCollection CSeq_align::GetAlignedBases(TDim row) const { CRangeCollection ranges; diff --git a/c++/src/objects/seqalign/Sparse_align.cpp b/c++/src/objects/seqalign/Sparse_align.cpp index 663fea76..7ccc19ec 100644 --- a/c++/src/objects/seqalign/Sparse_align.cpp +++ b/c++/src/objects/seqalign/Sparse_align.cpp @@ -1,4 +1,4 @@ -/* $Id: Sparse_align.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: Sparse_align.cpp 513588 2016-09-13 13:46:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seqalign/Sparse_seg.cpp b/c++/src/objects/seqalign/Sparse_seg.cpp index 536b7747..1184319e 100644 --- a/c++/src/objects/seqalign/Sparse_seg.cpp +++ b/c++/src/objects/seqalign/Sparse_seg.cpp @@ -1,4 +1,4 @@ -/* $Id: Sparse_seg.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: Sparse_seg.cpp 513588 2016-09-13 13:46:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seqalign/Spliced_seg.cpp b/c++/src/objects/seqalign/Spliced_seg.cpp index 74f74de2..2d6664fb 100644 --- a/c++/src/objects/seqalign/Spliced_seg.cpp +++ b/c++/src/objects/seqalign/Spliced_seg.cpp @@ -1,4 +1,4 @@ -/* $Id: Spliced_seg.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: Spliced_seg.cpp 513588 2016-09-13 13:46:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seqalign/Std_seg.cpp b/c++/src/objects/seqalign/Std_seg.cpp index e18cf460..e5e196a0 100644 --- a/c++/src/objects/seqalign/Std_seg.cpp +++ b/c++/src/objects/seqalign/Std_seg.cpp @@ -1,4 +1,4 @@ -/* $Id: Std_seg.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: Std_seg.cpp 513588 2016-09-13 13:46:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seqcode/CMakeLists.seqcode.asn.txt b/c++/src/objects/seqcode/CMakeLists.seqcode.asn.txt new file mode 100644 index 00000000..2e86fdc4 --- /dev/null +++ b/c++/src/objects/seqcode/CMakeLists.seqcode.asn.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/seqcode/Makefile.seqcode.lib +# + +set(MODULE seqcode) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/seqcode) + +set(MODULE_EXT "asn") +add_library(seqcode ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(seqcode + xser +) diff --git a/c++/src/objects/seqcode/CMakeLists.txt b/c++/src/objects/seqcode/CMakeLists.txt new file mode 100644 index 00000000..605bc551 --- /dev/null +++ b/c++/src/objects/seqcode/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.seqcode.asn.txt) + diff --git a/c++/src/objects/seqedit/CMakeLists.seqedit.asn.txt b/c++/src/objects/seqedit/CMakeLists.seqedit.asn.txt new file mode 100644 index 00000000..979cc69c --- /dev/null +++ b/c++/src/objects/seqedit/CMakeLists.seqedit.asn.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/seqedit/Makefile.seqedit.lib +# + +set(MODULE seqedit) +set(MODULE_IMPORT objects/general/general objects/seqloc/seqloc objects/seqset/seqset objects/seq/seq objects/seqalign/seqalign objects/seqfeat/seqfeat objects/seqres/seqres) +set(MODULE_PATH objects/seqedit) + +set(MODULE_EXT "asn") +add_library(seqedit ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(seqedit + seqset +) diff --git a/c++/src/objects/seqedit/CMakeLists.txt b/c++/src/objects/seqedit/CMakeLists.txt new file mode 100644 index 00000000..f9bd9521 --- /dev/null +++ b/c++/src/objects/seqedit/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.seqedit.asn.txt) + diff --git a/c++/src/objects/seqfeat/BioSource.cpp b/c++/src/objects/seqfeat/BioSource.cpp index 9ed35f1e..b98c4919 100644 --- a/c++/src/objects/seqfeat/BioSource.cpp +++ b/c++/src/objects/seqfeat/BioSource.cpp @@ -1,4 +1,4 @@ -/* $Id: BioSource.cpp 518950 2016-11-09 16:44:44Z ivanov $ +/* $Id: BioSource.cpp 547249 2017-09-27 17:35:12Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -505,6 +505,13 @@ string CBioSource::GetBioprojectType (void) const } } + if (IsSetOrg() && GetOrg().IsSetLineage()) { + const string& lineage = GetOrg().GetLineage(); + if (NStr::FindNoCase(lineage, "viruses") != string::npos || + NStr::FindNoCase(lineage, "viroids") != string::npos) { + return "eSegment"; + } + } return "eChromosome"; } @@ -515,10 +522,28 @@ string CBioSource::GetBioprojectLocation(void) const return "eNuclearProkaryote"; } - if (IsSetGenome()) { + const string& bioprojecttype = GetBioprojectType(); + if (NStr::Equal(bioprojecttype, "eSegment")) { + if (IsSetOrg() && GetOrg().IsSetLineage()) { + const string& lineage = GetOrg().GetLineage(); + if (NStr::FindNoCase(lineage, "viruses") != string::npos) { + return "eVirionPhage"; + } else if (NStr::FindNoCase(lineage, "viroids") != string::npos) { + return "eViroid"; + } + } + return "eOther"; + } + + if (!IsSetGenome()) { + return "eNuclearProkaryote"; + } else { switch (GetGenome()) { case CBioSource::eGenome_unknown: case CBioSource::eGenome_genomic: + case CBioSource::eGenome_chromosome: + case CBioSource::eGenome_plasmid: + case CBioSource::eGenome_extrachrom: return "eNuclearProkaryote"; break; case CBioSource::eGenome_mitochondrion: @@ -527,9 +552,6 @@ string CBioSource::GetBioprojectLocation(void) const case CBioSource::eGenome_kinetoplast: return "eKinetoplast"; break; - case CBioSource::eGenome_chromosome: - return "eNuclearProkaryote"; - break; case CBioSource::eGenome_chloroplast: return "eChloroplast"; break; @@ -542,17 +564,23 @@ string CBioSource::GetBioprojectLocation(void) const case CBioSource::eGenome_macronuclear: return "eMacronuclear"; break; - case CBioSource::eGenome_extrachrom: - return "eNuclearProkaryote"; - break; case CBioSource::eGenome_cyanelle: return "eCyanelle"; break; case CBioSource::eGenome_proviral: + case CBioSource::eGenome_endogenous_virus: return "eProviralProphage"; break; case CBioSource::eGenome_virion: - return "eVirionPhage"; + if (IsSetOrg() && GetOrg().IsSetLineage()) { + const string& lineage = GetOrg().GetLineage(); + if (NStr::FindNoCase(lineage, "viruses") != string::npos) { + return "eVirionPhage"; + } else if (NStr::FindNoCase(lineage, "viroids") != string::npos) { + return "eViroid"; + } + } + return "eOther"; break; case CBioSource::eGenome_nucleomorph: return "eNucleomorph"; @@ -566,22 +594,23 @@ string CBioSource::GetBioprojectLocation(void) const case CBioSource::eGenome_proplastid: return "eProplastid"; break; - case CBioSource::eGenome_endogenous_virus: - return "eOther"; - break; case CBioSource::eGenome_hydrogenosome: return "eHydrogenosome"; break; case CBioSource::eGenome_chromatophore: return "eChromatophore"; break; + case CBioSource::eGenome_transposon: + case CBioSource::eGenome_insertion_seq: + return "eOther"; + break; } } - if (NStr::Equal(GetBioprojectType(), "ePlasmid")) { + if (!NStr::Equal(bioprojecttype, "eSegment")) { return "eNuclearProkaryote"; } - return kEmptyStr; + return "eOther"; } static const char* kDisableStrainForwardAttrib = "nomodforward"; @@ -677,6 +706,9 @@ void CBioSource::UpdateWithBioSample(const CBioSource& biosample, bool force, bo NCBI_THROW(CException, eUnknown, "Conflicts found"); } + COrgName_Base::TMod mods; + CBioSource_Base::TSubtype subtypes; + ITERATE(TFieldDiffList, it, diffs) { if (NStr::EqualNocase((*it)->GetFieldName(), "Organism Name")) { SetOrg().SetTaxname((*it)->GetSampleVal()); @@ -697,23 +729,26 @@ void CBioSource::UpdateWithBioSample(const CBioSource& biosample, bool force, bo } try { COrgMod::TSubtype subtype = COrgMod::GetSubtypeValue((*it)->GetFieldName()); - RemoveOrgMod(subtype); - + if (!NStr::IsBlank((*it)->GetSrcVal())) { + RemoveOrgMod(subtype, (*it)->GetSrcVal()); + } if (!NStr::IsBlank(sample_val)) { CRef mod(new COrgMod()); mod->SetSubtype(subtype); mod->SetSubname(sample_val); - SetOrg().SetOrgname().SetMod().push_back(mod); + mods.push_back(mod); } } catch (...) { try { CSubSource::TSubtype subtype = CSubSource::GetSubtypeValue((*it)->GetFieldName()); - RemoveSubSource(subtype); + if (!NStr::IsBlank((*it)->GetSrcVal())) { + RemoveSubSource(subtype, (*it)->GetSrcVal()); + } if (!NStr::IsBlank(sample_val)) { CRef sub(new CSubSource()); sub->SetSubtype(subtype); sub->SetName(sample_val); - SetSubtype().push_back(sub); + subtypes.push_back(sub); } } catch (...) { NCBI_THROW(CException, eUnknown, "Unknown field name"); @@ -722,6 +757,14 @@ void CBioSource::UpdateWithBioSample(const CBioSource& biosample, bool force, bo } } + if (!mods.empty()) { + SetOrg().SetOrgname().SetMod().splice(SetOrg().SetOrgname().SetMod().end(), mods); + } + + if (!subtypes.empty()) { + SetSubtype().splice(SetSubtype().end(), subtypes); + } + AutoFix(); } @@ -1037,7 +1080,9 @@ bool CBioSource::ShouldIgnoreConflict(const string& label, string src_val, strin break; } } +#if 0 // special handling for lat-lon + // commented out for SQD-4173 if (!rval && NStr::EqualNocase(label, "lat-lon")) { bool src_format_correct, src_precision_correct, src_lat_in_range, src_lon_in_range; @@ -1057,6 +1102,7 @@ bool CBioSource::ShouldIgnoreConflict(const string& label, string src_val, strin rval = true; } } +#endif // special handling for collection-date if (!rval && NStr::EqualNocase(label, "collection-date")) { try { @@ -1087,6 +1133,59 @@ bool CBioSource::ShouldIgnoreConflict(const string& label, string src_val, strin } +void CompareValLists(TFieldDiffList& list, const string& val_name, bool is_local_copy, const vector& list1, const vector& list2) +{ + vector matched1; + for (size_t i = 0; i < list1.size(); i++) { + matched1.push_back(false); + } + + vector matched2; + for (size_t i = 0; i < list2.size(); i++) { + matched2.push_back(false); + } + for (size_t i = 0; i < list1.size(); i++) { + bool found = false; + for (size_t j = 0; j < list2.size(); j++) { + if (matched2[j]) { + // already in use + } else if (CBioSource::ShouldIgnoreConflict(val_name, list1[i], list2[j], is_local_copy)) { + matched2[j] = true; + found = true; + break; + } + } + if (found) { + matched1[i] = true; + } + } + for (size_t i = 0; i < list1.size(); i++) { + if (!matched1[i]) { + bool reported = false; + for (size_t j = 0; j < list2.size(); j++) { + if (!matched2[j]) { + CRef diff(new CFieldDiff(val_name, list1[i], list2[j])); + list.push_back(diff); + reported = true; + matched2[j] = true; + break; + } + } + if (!reported) { + CRef diff(new CFieldDiff(val_name, list1[i], "")); + list.push_back(diff); + } + } + } + for (size_t j = 0; j < list2.size(); j++) { + if (!matched2[j]) { + CRef diff(new CFieldDiff(val_name, "", list2[j])); + list.push_back(diff); + } + } +} + + void GetFieldDiffsFromNameValLists(TFieldDiffList& list, CBioSource::TNameValList& list1, CBioSource::TNameValList& list2, @@ -1094,29 +1193,41 @@ void GetFieldDiffsFromNameValLists(TFieldDiffList& list, { CBioSource::TNameValList::iterator it1 = list1.begin(); CBioSource::TNameValList::iterator it2 = list2.begin(); + vector matched; while (it1 != list1.end() && it2 != list2.end()) { int cmp = NStr::Compare(it1->first, it2->first); - if (cmp == 0) { - if (!CBioSource::ShouldIgnoreConflict(it1->first, it1->second, it2->second, is_local_copy)) { - CRef diff(new CFieldDiff(it1->first, it1->second, it2->second)); - list.push_back(diff); - } - it1++; - it2++; - } else if (cmp < 0) { + if (cmp < 0) { if (!CBioSource::ShouldIgnoreConflict(it1->first, it1->second, "", is_local_copy)) { CRef diff(new CFieldDiff(it1->first, it1->second, "")); list.push_back(diff); } it1++; - } else { - // cmp > 0 + } else if (cmp > 0) { if (!CBioSource::ShouldIgnoreConflict(it2->first, "", it2->second, is_local_copy)) { CRef diff(new CFieldDiff(it2->first, "", it2->second)); list.push_back(diff); } it2++; + } else { + // cmp == 0 + const string& val_name = it1->first; + vector v1; + vector v2; + v1.push_back(it1->second); + v2.push_back(it2->second); + it1++; + it2++; + while (it1 != list1.end() && NStr::Equal(it1->first, val_name)) { + v1.push_back(it1->second); + it1++; + } + while (it2 != list2.end() && NStr::Equal(it2->first, val_name)) { + v2.push_back(it2->second); + it2++; + } + + CompareValLists(list, val_name, is_local_copy, v1, v2); } } while (it1 != list1.end()) { @@ -1206,7 +1317,8 @@ TFieldDiffList CBioSource::GetBiosampleDiffs(const CBioSource& biosample, bool i sort(sample_list.begin(), sample_list.end(), s_CompareNameVals); GetFieldDiffsFromNameValLists(rval, src_list, sample_list, is_local_copy); - x_RemoveNameElementDiffs(biosample, rval); + // commented out, SQD-4222 + //x_RemoveNameElementDiffs(biosample, rval); if (x_ShouldIgnoreNoteForBiosample() && biosample.x_ShouldIgnoreNoteForBiosample()) { RemoveDiffByName(rval, "orgmod_note"); @@ -1471,6 +1583,29 @@ bool CBioSource::RemoveSubSource(int subtype) } +bool CBioSource::RemoveSubSource(int subtype, const string& val) +{ + bool rval = false; + + if (IsSetSubtype()) { + CBioSource::TSubtype::iterator it = SetSubtype().begin(); + while (it != SetSubtype().end()) { + if ((*it)->IsSetSubtype() && (*it)->GetSubtype() == subtype && + (*it)->IsSetName() && NStr::Equal((*it)->GetName(), val)) { + it = SetSubtype().erase(it); + rval = true; + } else { + it++; + } + } + if (GetSubtype().empty()) { + ResetSubtype(); + } + } + return rval; +} + + bool CBioSource::RemoveOrgMod(int subtype) { bool rval = false; @@ -1493,6 +1628,29 @@ bool CBioSource::RemoveOrgMod(int subtype) } +bool CBioSource::RemoveOrgMod(int subtype, const string& val) +{ + bool rval = false; + + if (IsSetOrg() && GetOrg().IsSetOrgname() && GetOrg().GetOrgname().IsSetMod()) { + COrgName::TMod::iterator it = SetOrg().SetOrgname().SetMod().begin(); + while (it != SetOrg().SetOrgname().SetMod().end()) { + if ((*it)->IsSetSubtype() && (*it)->GetSubtype() == subtype && + (*it)->IsSetSubname() && NStr::Equal((*it)->GetSubname(), val)) { + it = SetOrg().SetOrgname().SetMod().erase(it); + rval = true; + } else { + it++; + } + } + if (GetOrg().GetOrgname().GetMod().empty()) { + SetOrg().SetOrgname().ResetMod(); + } + } + return rval; +} + + bool CBioSource::FixEnvironmentalSample() { bool has_env_sample = false; @@ -1791,19 +1949,10 @@ bool CBioSource::FixGenomeForQualifiers() #define MAKE_COMMON_INT(o1,o2,o3,Field) \ if (o1.IsSet##Field() && o2.IsSet##Field() && o1.Get##Field() == o2.Get##Field()) o3.Set##Field(o1.Get##Field()); -CRef CBioSource::MakeCommon( const CBioSource& other) const -{ - if (!IsSetOrg() || !other.IsSetOrg()) { - return CRef(NULL); - } - - CRef common_org = GetOrg().MakeCommon(other.GetOrg()); - if (!common_org) { - return CRef(NULL); - } +CRef CBioSource::MakeCommonExceptOrg(const CBioSource& other) const +{ CRef common_src(new CBioSource()); - common_src->SetOrg().Assign(*common_org); // copy common subtypes if (IsSetSubtype() && other.IsSetSubtype()) { @@ -1825,7 +1974,7 @@ CRef CBioSource::MakeCommon( const CBioSource& other) const MAKE_COMMON_INT((*this), other, (*common_src), Genome); MAKE_COMMON_INT((*this), other, (*common_src), Origin); - + if (IsSetPcr_primers() && other.IsSetPcr_primers() && GetPcr_primers().Equals(other.GetPcr_primers())) { common_src->SetPcr_primers().Assign(GetPcr_primers()); } @@ -1834,6 +1983,24 @@ CRef CBioSource::MakeCommon( const CBioSource& other) const } +CRef CBioSource::MakeCommon( const CBioSource& other) const +{ + if (!IsSetOrg() || !other.IsSetOrg()) { + return CRef(NULL); + } + + CRef common_org = GetOrg().MakeCommon(other.GetOrg()); + if (!common_org) { + return CRef(NULL); + } + + CRef common_src = MakeCommonExceptOrg(other); + common_src->SetOrg().Assign(*common_org); + + return common_src; +} + + bool CBioSource::HasSubtype(CSubSource::TSubtype subtype) const { if (!IsSetSubtype()) { diff --git a/c++/src/objects/seqfeat/Delta_item.cpp b/c++/src/objects/seqfeat/Delta_item.cpp index 39239df4..779a94e1 100644 --- a/c++/src/objects/seqfeat/Delta_item.cpp +++ b/c++/src/objects/seqfeat/Delta_item.cpp @@ -1,4 +1,4 @@ -/* $Id: Delta_item.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: Delta_item.cpp 513588 2016-09-13 13:46:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seqfeat/Gb_qual.cpp b/c++/src/objects/seqfeat/Gb_qual.cpp index 0fc9b1eb..c43110fe 100644 --- a/c++/src/objects/seqfeat/Gb_qual.cpp +++ b/c++/src/objects/seqfeat/Gb_qual.cpp @@ -1,4 +1,4 @@ -/* $Id: Gb_qual.cpp 518672 2016-11-07 15:40:15Z ivanov $ +/* $Id: Gb_qual.cpp 530452 2017-03-15 13:15:00Z dobronad $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -202,6 +202,58 @@ CGb_qual::GetSetOfLegalRepeatTypes(void) return sc_LegalRepeatTypes; } +static string GetRptTypeValue(const string& val, bool& open_bracket, bool& close_bracket) +{ + string ret = val; + NStr::TruncateSpacesInPlace(ret); + + open_bracket = NStr::StartsWith(ret, "("); + close_bracket = NStr::EndsWith(ret, ")"); + + if (open_bracket) { + ret = ret.substr(1); + } + if (close_bracket) { + ret.pop_back(); + } + NStr::TruncateSpacesInPlace(ret); + + return ret; +} + +bool CGb_qual::FixRptTypeValue(string& val) +{ + const TLegalRepeatTypeSet& repeat_types = GetSetOfLegalRepeatTypes(); + + string origin = val; + + // look for list of values + vector rpt_types; + NStr::Split(val, ",", rpt_types, NStr::fSplit_NoMergeDelims); + + NON_CONST_ITERATE(vector, it, rpt_types) { + bool open_bracket = false, + close_bracket = false; + + string v = GetRptTypeValue(*it, open_bracket, close_bracket); + + auto correct_val_it = repeat_types.find(v.c_str()); + if (correct_val_it != repeat_types.end()) { + v = *correct_val_it; + if (open_bracket) { + v = "(" + v; + } + if (close_bracket) { + v += ")"; + } + } + + *it = v; + } + + val = NStr::Join(rpt_types, ","); + return origin != val; +} bool CGb_qual::IsValidRptTypeValue(const string& val) { @@ -213,15 +265,12 @@ bool CGb_qual::IsValidRptTypeValue(const string& val) vector rpt_types; NStr::Split(val, ",", rpt_types, NStr::fSplit_NoMergeDelims); ITERATE(vector, it, rpt_types) { - string v = (*it); - NStr::TruncateSpacesInPlace(v); - if (NStr::StartsWith(v, "(")) { - v = v.substr(1); - } - if (NStr::EndsWith(v, ")")) { - v = v.substr(0, v.length() - 1); - } - NStr::TruncateSpacesInPlace(v); + + bool open_bracket = false, + close_bracket = false; + + string v = GetRptTypeValue(*it, open_bracket, close_bracket); + if (repeat_types.find(v.c_str()) == repeat_types.end()) { error = true; break; @@ -262,15 +311,28 @@ bool CGb_qual::IsValidPseudogeneValue(const string& val) } } +bool CGb_qual::FixPseudogeneValue(string& val) +{ + const TLegalPseudogeneSet& pseudogenes = GetSetOfLegalPseudogenes(); + auto pseudogene_val = pseudogenes.find(val.c_str()); + + string original = val;; + if (pseudogene_val != pseudogenes.end()) { + val = *pseudogene_val; + } + + return val != original; +} + const CGb_qual::TLegalRecombinationClassSet & CGb_qual::GetSetOfLegalRecombinationClassValues(void) { static const char * misc_recombs[] = { "chromosome_breakpoint", - "meiotic_recombination", - "mitotic_recombination", - "non_allelic_homologous_recombination" + "meiotic", + "mitotic", + "non_allelic_homologous" }; @@ -280,6 +342,30 @@ CGb_qual::GetSetOfLegalRecombinationClassValues(void) return sc_LegalRecombinationClass; } +bool CGb_qual::FixRecombinationClassValue(string& val) +{ + static const CTempString PREFIX_OTHER("other:"); + static const map SUBSTITUTION_MAP = { + { "meiotic_recombination", "meiotic" }, + { "mitotic_recombination", "mitotic" }, + { "non_allelic_homologous_recombination", "non_allelic_homologous" } + }; + + string original = val; + + NStr::ToLower(val); + if (NStr::StartsWith(val, PREFIX_OTHER)) { + val = val.substr(PREFIX_OTHER.size()); + } + + auto substitute = SUBSTITUTION_MAP.find(val); + if (substitute != SUBSTITUTION_MAP.end()) { + val = substitute->second; + } + + return original != val; +} + // constructor CInferencePrefixList::CInferencePrefixList(void) @@ -325,36 +411,42 @@ void CInferencePrefixList::GetPrefixAndRemainder (const string& inference, strin static const char* s_LegalMobileElementStrings[] = { - "transposon", - "retrotransposon", - "integron", - "superintegron", "insertion sequence", + "integron", + "LINE", + "MITE", "non-LTR retrotransposon", + "other", "P-element", - "transposable element", + "retrotransposon", "SINE", - "MITE", - "LINE", - "other" + "superintegron", + "transposable element", + "transposon" }; +typedef CStaticArraySet TLegalMobileElementStrings; +DEFINE_STATIC_ARRAY_MAP(TLegalMobileElementStrings, + sc_LegalMobileElementStrings, s_LegalMobileElementStrings); + void CGb_qual::GetMobileElementValueElements(const string& val, string& element_type, string& element_name) { element_type.clear(); element_name.clear(); - for (size_t i = 0; i < ArraySize(s_LegalMobileElementStrings); ++i) { - if (NStr::StartsWith(val, s_LegalMobileElementStrings[i], NStr::eNocase)) { - element_name = val.substr(strlen(s_LegalMobileElementStrings[i])); - if (!NStr::IsBlank(element_name) && - (!NStr::StartsWith(element_name, ":") || NStr::Equal(element_name, ":"))) { - element_name.clear(); - } else { - element_type = s_LegalMobileElementStrings[i]; - } - break; + + size_t pos = NStr::Find(val, ":"); + if (pos == string::npos) { + TLegalMobileElementStrings::const_iterator it = sc_LegalMobileElementStrings.find(val.c_str()); + if (it != sc_LegalMobileElementStrings.end()) { + element_type = *it; } + } else { + TLegalMobileElementStrings::const_iterator it = sc_LegalMobileElementStrings.find(val.substr(0, pos).c_str()); + if (it != sc_LegalMobileElementStrings.end()) { + element_type = *it; + element_name = val.substr(pos + 1); + } } } @@ -374,6 +466,28 @@ bool CGb_qual::IsLegalMobileElementValue(const string& val) } +bool CGb_qual::FixMobileElementValue(string& val) +{ + bool rval = false; + string element_type; + string element_name; + GetMobileElementValueElements(val, element_type, element_name); + if (!NStr::IsBlank(element_type)) { + string new_val; + if (NStr::IsBlank(element_name)) { + new_val = element_type; + } else { + new_val = element_type + ":" + element_name; + } + if (!NStr::Equal(val, new_val)) { + val = new_val; + rval = true; + } + } + return rval; +} + + static const char* s_IllegalQualNameStrings[] = { "anticodon", "citation", @@ -413,6 +527,44 @@ static string s_FindInArray(const string &val, const char **arr) return result; } +static const char *kInferenceDBChoices[] = { + "GenBank", + "EMBL", + "DDBJ", + "INSD", + "RefSeq", + "UniProt", + "Other", + "\0" }; + +size_t kNumInferenceDBChoices = sizeof(kInferenceDBChoices) / sizeof(char *); + +typedef SStaticPair TInferenceTypeSynonymPairElem; +static const TInferenceTypeSynonymPairElem k_inference_type_synonym_pair_map[] = { + { "ab initio prediction", "ab initio prediction" }, + { "alignment", "alignment" }, + { "nucleotide motif", "nucleotide motif" }, + { "profile", "profile" }, + { "protein motif", "protein motif" }, + { "similar to AA", "similar to AA sequence" }, + { "similar to AA sequence", "similar to AA sequence" }, + { "similar to DNA", "similar to DNA sequence" }, + { "similar to DNA sequence", "similar to DNA sequence" }, + { "similar to EST", "similar to RNA sequence, EST" }, + { "similar to mRNA", "similar to RNA sequence, mRNA" }, + { "similar to RNA", "similar to RNA sequence" }, + { "similar to RNA sequence", "similar to RNA sequence" }, + { "similar to RNA sequence, EST", "similar to RNA sequence, EST" }, + { "similar to RNA sequence, mRNA", "similar to RNA sequence, mRNA" }, + { "similar to RNA sequence, other", "similar to RNA sequence, other" }, + { "similar to sequence", "similar to sequence" } +}; + + +typedef CStaticArrayMap TInferenceTypeSynonymPairMap; +DEFINE_STATIC_ARRAY_MAP(TInferenceTypeSynonymPairMap, sc_InferenceTypeSynonymPairMap, k_inference_type_synonym_pair_map); + + void CGb_qual::ParseInferenceString(string val, string &category, string &type_str, bool &is_same_species, string &database, string &accession, string &program, string &version, string &acc_list) { @@ -432,57 +584,34 @@ void CGb_qual::ParseInferenceString(string val, string &category, string &type_s } } - static const char *types[] = { - "similar to sequence", - "similar to protein", - "similar to DNA", - "similar to RNA", - "similar to mRNA", - "similar to EST", - "similar to other RNA", - "profile", - "nucleotide motif", - "protein motif", - "ab initio prediction", - "alignment", - "\0"}; type_str.clear(); is_same_species = false; - // start with 1 - first item is blank - for (unsigned int i = 0; types[i][0] != '\0'; i++) - { - if (NStr::StartsWith(val, types[i], NStr::eNocase)) - { - type_str = types[i]; - val = val.substr(strlen(types[i])); + TInferenceTypeSynonymPairMap::const_iterator match = sc_InferenceTypeSynonymPairMap.end(); + ITERATE(TInferenceTypeSynonymPairMap, it, sc_InferenceTypeSynonymPairMap) { + if (strlen(it->first) > type_str.length() && NStr::StartsWith(val, it->first, NStr::eNocase)) { + type_str = it->first; + match = it; + } + } + if (match != sc_InferenceTypeSynonymPairMap.end()) { + type_str = match->second; + val = val.substr(strlen(match->first)); + NStr::TruncateSpacesInPlace(val); + if (NStr::StartsWith(val, "(same species)", NStr::eNocase)) { + is_same_species = true; + val = val.substr(14); NStr::TruncateSpacesInPlace(val); - if (NStr::StartsWith(val, "(same species)", NStr::eNocase)) { - is_same_species = true; - val = val.substr(14); - NStr::TruncateSpacesInPlace(val); - } + } if (NStr::StartsWith(val, ":")) { - val = val.substr(1); - NStr::TruncateSpacesInPlace(val); - } - break; + val = val.substr(1); + NStr::TruncateSpacesInPlace(val); } } // add type-dependent extra data if (NStr::StartsWith(type_str, "similar to ")) { - static const char *choices[] = { - "GenBank", - "EMBL", - "DDBJ", - "INSD", - "RefSeq", - "UniProt", - "Other", - "\0"}; - NStr::TruncateSpacesInPlace(val); while (NStr::StartsWith(val, "|")) { val = val.substr(1); @@ -490,7 +619,7 @@ void CGb_qual::ParseInferenceString(string val, string &category, string &type_s } size_t pos = NStr::Find(val, ":"); if (pos == NPOS) { - database = s_FindInArray(val, choices); + database = s_FindInArray(val, kInferenceDBChoices); if (database.empty()) accession = val; else @@ -498,7 +627,7 @@ void CGb_qual::ParseInferenceString(string val, string &category, string &type_s } else { string part1 = val.substr(0, pos); string part2 = val.substr(pos + 1); - database = s_FindInArray(part1, choices); + database = s_FindInArray(part1, kInferenceDBChoices); if (!database.empty()) { accession = part2; @@ -619,6 +748,30 @@ string CGb_qual::CleanupAndRepairInference( const string &orig_inference ) ReplaceIfNotFound(inference, "DESCRIPTION:", "DESCRIPTION: "); ReplaceIfNotFound(inference, "EXISTENCE:", "EXISTENCE: "); + for (size_t i = 0; i < kNumInferenceDBChoices - 1; i++) { + string find = kInferenceDBChoices[i]; + find += ": "; + string replace = kInferenceDBChoices[i]; + replace += ":"; + NStr::ReplaceInPlace(inference, find, replace); + } + NStr::ReplaceInPlace(inference, "UniProtKB: ", "UniProtKB:"); + + ITERATE(TInferenceTypeSynonymPairMap, it, sc_InferenceTypeSynonymPairMap) { + string find = it->first; + find += ": "; + string replace = it->second; + replace += ":"; + NStr::ReplaceInPlace(inference, find, replace); + } + for (size_t i = 0; i < ArraySize(valid_inf_prefixes); i++) { + string find = valid_inf_prefixes[i]; + find += ": "; + string replace = valid_inf_prefixes[i]; + replace += ":"; + NStr::ReplaceInPlace(inference, find, replace); + } + return inference; } diff --git a/c++/src/objects/seqfeat/Genetic_code_table.cpp b/c++/src/objects/seqfeat/Genetic_code_table.cpp index b57b0cfa..1ce7f82b 100644 --- a/c++/src/objects/seqfeat/Genetic_code_table.cpp +++ b/c++/src/objects/seqfeat/Genetic_code_table.cpp @@ -1,4 +1,4 @@ -/* $Id: Genetic_code_table.cpp 516784 2016-10-18 12:18:08Z ivanov $ +/* $Id: Genetic_code_table.cpp 537787 2017-06-03 16:46:26Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -156,6 +156,7 @@ void CTrans_table::x_InitFsaTransl (const string *ncbieaa, for (i = 0; i <= 4096; i++) { m_AminoAcid [i] = 'X'; m_OrfStart [i] = '-'; + m_OrfStop [i] = '-'; } // lookup amino acid for each codon in genetic code table @@ -224,11 +225,14 @@ void CTrans_table::x_InitFsaTransl (const string *ncbieaa, } } - // assign amino acid and orf start + // assign amino acid if (aa != '\0') { m_AminoAcid [st] = aa; } - if (orf != '\0') { + // assign orf start/stop + if (orf == '*') { + m_OrfStop [st] = orf; + } else if (orf != '\0') { m_OrfStart [st] = orf; } } @@ -505,7 +509,7 @@ const CTrans_table& CGen_code_table_imp::GetTransTable (int id) if ( size_t(id) < m_TransTablesById.size ()) { CRef< CTrans_table> tbl = m_TransTablesById [id]; if (tbl != 0) { - // already in list, already initialized, so return + // already in list, already initialized, so return return *tbl; } } @@ -518,7 +522,7 @@ const CTrans_table& CGen_code_table_imp::GetTransTable (int id) if ( size_t(id) < m_TransTablesById.size ()) { CRef< CTrans_table> tbl = m_TransTablesById [id]; if (tbl != 0) { - // already in list, already initialized, so return + // already in list, already initialized, so return return *tbl; } } @@ -528,18 +532,18 @@ const CTrans_table& CGen_code_table_imp::GetTransTable (int id) ITERATE (CGenetic_code::Tdata, gcd, (*gcl)->Get ()) { if ((*gcd)->IsId () && (*gcd)->GetId () == id) { - // found proper genetic code, so create new trans table - CRef< CTrans_table> tbl(new CTrans_table (**gcl)); + // found proper genetic code, so create new trans table + CRef< CTrans_table> tbl(new CTrans_table (**gcl)); - // extend size of translation table list, if necessary - if ( size_t(id) >= m_TransTablesById.size ()) { - m_TransTablesById.resize (id + 1); - } + // extend size of translation table list, if necessary + if ( size_t(id) >= m_TransTablesById.size ()) { + m_TransTablesById.resize (id + 1); + } - // add new table to list of translation tables - m_TransTablesById [id] = tbl; + // add new table to list of translation tables + m_TransTablesById [id] = tbl; - return *tbl; + return *tbl; } } } @@ -638,7 +642,7 @@ const string& CGen_code_table_imp::GetSncbieaa(const CGenetic_code& gc) const // standard genetic code // // ncbieaa "FFLLSSSSYY**CC*WLLLLPPPPHHQQRRRRIIIMTTTTNNKKSSRRVVVVAAAADDEEGGGG" -// sncbieaa "---M---------------M---------------M----------------------------" +// sncbieaa "---M------**--*----M---------------M----------------------------" // // -- Base1 TTTTTTTTTTTTTTTTCCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAGGGGGGGGGGGGGGGG // -- Base2 TTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGGTTTTCCCCAAAAGGGG diff --git a/c++/src/objects/seqfeat/OrgMod.cpp b/c++/src/objects/seqfeat/OrgMod.cpp index b7d33808..aa8971c7 100644 --- a/c++/src/objects/seqfeat/OrgMod.cpp +++ b/c++/src/objects/seqfeat/OrgMod.cpp @@ -1,4 +1,4 @@ -/* $Id: OrgMod.cpp 515540 2016-10-03 16:03:50Z ivanov $ +/* $Id: OrgMod.cpp 540674 2017-07-10 15:05:56Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -158,42 +158,39 @@ bool COrgMod::HoldsInstitutionCode(const TSubtype stype) bool COrgMod::ParseStructuredVoucher(const string& str, string& inst, string& coll, string& id) { - if (NStr::IsBlank(str) || str.length() < 3) { - return false; - } - + if (NStr::IsBlank(str)) { + return false; + } + inst = kEmptyStr; + coll = kEmptyStr; + id = kEmptyStr; size_t pos = NStr::Find(str, ":"); if (pos == string::npos) { - return false; + id = str; + return true; } inst = str.substr(0, pos); id = str.substr(pos + 1); - coll.clear(); pos = NStr::Find(id, ":"); if (pos != string::npos) { coll = id.substr(0, pos); id = id.substr(pos + 1); } - if (NStr::IsBlank(inst) || NStr::IsBlank(id)) { - return false; - } else { - return true; - } + return true; } // ===== biomaterial, and culture-collection BioSource subsource modifiers ================ -typedef map TInstitutionCodeMap; - -static TInstitutionCodeMap s_BiomaterialInstitutionCodeMap; -static TInstitutionCodeMap s_SpecimenVoucherInstitutionCodeMap; -static TInstitutionCodeMap s_CultureCollectionInstitutionCodeMap; +static COrgMod::TInstitutionCodeMap s_BiomaterialInstitutionCodeMap; +static COrgMod::TInstitutionCodeMap s_SpecimenVoucherInstitutionCodeMap; +static COrgMod::TInstitutionCodeMap s_CultureCollectionInstitutionCodeMap; // holds all the data in the specific ones above -static TInstitutionCodeMap s_CompleteInstitutionCodeMap; -static TInstitutionCodeMap s_CompleteInstitutionFullNameMap; -static TInstitutionCodeMap s_InstitutionCodeTypeMap; +static COrgMod::TInstitutionCodeMap s_CompleteInstitutionCodeMap; +static COrgMod::TInstitutionCodeMap s_CompleteInstitutionFullNameMap; +static COrgMod::TInstitutionCodeMap s_InstitutionCodeTypeMap; +static COrgMod::TInstitutionCodeMap s_InstitutionCodeSynonymsMap; static bool s_InstitutionCollectionCodeMapInitialized = false; DEFINE_STATIC_FAST_MUTEX(s_InstitutionCollectionCodeMutex); @@ -204,7 +201,7 @@ static void s_ProcessInstitutionCollectionCodeLine(const CTempString& line) { vector tokens; NStr::Split(line, "\t", tokens, NStr::fSplit_NoMergeDelims); - if (tokens.size() != 3) { + if (tokens.size() < 2) { // ERR_POST_X(1, Warning << "Bad format in institution_codes.txt entry " << line // << "; disregarding"); } else { @@ -232,6 +229,15 @@ static void s_ProcessInstitutionCollectionCodeLine(const CTempString& line) s_CompleteInstitutionCodeMap[tokens[0]] = tokens[2]; s_CompleteInstitutionFullNameMap[tokens[2]] = tokens[0]; s_InstitutionCodeTypeMap[tokens[0]] = tokens[1]; + if (tokens.size() > 3 && !NStr::IsBlank(tokens[3])) { + NStr::TruncateSpacesInPlace(tokens[3]); + vector synonyms; + NStr::Split(tokens[3], ",", synonyms, NStr::fSplit_NoMergeDelims); + NON_CONST_ITERATE(vector, s, synonyms) { + NStr::TruncateSpacesInPlace(*s); + s_InstitutionCodeSynonymsMap[*s] = tokens[0]; + } + } } } @@ -251,14 +257,14 @@ static void s_InitializeInstitutionCollectionCodeMaps(void) } if (lr.Empty()) { -// ERR_POST_X(2, Info << "s_InitializeInstitutionCollectionCodeMaps: " -// "falling back on built-in data."); + LOG_POST("Falling back on built-in data for institution code list."); size_t num_codes = sizeof (kInstitutionCollectionCodeList) / sizeof (char *); for (size_t i = 0; i < num_codes; i++) { const char *p = kInstitutionCollectionCodeList[i]; s_ProcessInstitutionCollectionCodeLine(p); } } else { + LOG_POST("Reading from " + file + " for instition code list."); do { s_ProcessInstitutionCollectionCodeLine(*++*lr); } while ( !lr->AtEOF() ); @@ -268,52 +274,90 @@ static void s_InitializeInstitutionCollectionCodeMaps(void) } -bool COrgMod::IsInstitutionCodeValid(const string& inst_coll, string &voucher_type, bool& is_miscapitalized, string& correct_cap, bool& needs_country, bool& erroneous_country) +COrgMod::TInstitutionCodeMap::iterator COrgMod::FindInstitutionCode(const string& inst_coll, TInstitutionCodeMap& code_map, + bool& is_miscapitalized, string& correct_cap, bool& needs_country, bool& erroneous_country) { - bool rval = false; - - is_miscapitalized = false; - needs_country = false; - erroneous_country = false; - correct_cap.clear(); - - s_InitializeInstitutionCollectionCodeMaps(); - - TInstitutionCodeMap::iterator it = s_InstitutionCodeTypeMap.find(inst_coll); - if (it != s_InstitutionCodeTypeMap.end()) { - if (NStr::EqualCase (it->first, inst_coll)) { - } else if (NStr::EqualNocase (it->first, inst_coll)) { + TInstitutionCodeMap::iterator it = code_map.find(inst_coll); + if (it != code_map.end()) { + if (NStr::EqualCase(it->first, inst_coll)) { + } else if (NStr::EqualNocase(it->first, inst_coll)) { is_miscapitalized = true; } - voucher_type = it->second; correct_cap = it->first; - rval = true; + return it; } else { size_t pos = NStr::Find(inst_coll, "<"); if (pos == string::npos) { string check = inst_coll + "<"; - it = s_InstitutionCodeTypeMap.begin(); - while (!rval && it != s_InstitutionCodeTypeMap.end()) { + it = code_map.begin(); + while (it != code_map.end()) { if (NStr::StartsWith(it->first, check, NStr::eNocase)) { needs_country = true; - rval = true; if (!NStr::StartsWith(it->first, check, NStr::eCase)) { is_miscapitalized = true; } correct_cap = it->first.substr(0, inst_coll.length()); + return it; } ++it; } } else { string inst_sub = inst_coll.substr(0, pos); - it = s_InstitutionCodeTypeMap.find(inst_sub); - if (it != s_InstitutionCodeTypeMap.end()) { + it = code_map.find(inst_sub); + if (it != code_map.end()) { erroneous_country = true; - rval = true; + return it; } } } - return rval; + return code_map.end(); +} + + +bool COrgMod::IsInstitutionCodeValid(const string& inst_coll, string &voucher_type, bool& is_miscapitalized, string& correct_cap, bool& needs_country, bool& erroneous_country) +{ + is_miscapitalized = false; + needs_country = false; + erroneous_country = false; + correct_cap.clear(); + + s_InitializeInstitutionCollectionCodeMaps(); + + TInstitutionCodeMap::iterator ic = FindInstitutionCode(inst_coll, s_InstitutionCodeTypeMap, is_miscapitalized, correct_cap, needs_country, erroneous_country); + if (ic != s_InstitutionCodeTypeMap.end()) { + if (needs_country) { + // check to see if non-country-requiring code is in synonyms + bool syn_is_miscapitalized = false; + string syn_correct_cap = ""; + bool syn_needs_country = false; + bool syn_erroneous_country = false; + TInstitutionCodeMap::iterator it = FindInstitutionCode(inst_coll, + s_InstitutionCodeSynonymsMap, syn_is_miscapitalized, syn_correct_cap, + syn_needs_country, syn_erroneous_country); + if (it != s_InstitutionCodeSynonymsMap.end() && !syn_needs_country) { + TInstitutionCodeMap::iterator is = s_InstitutionCodeTypeMap.find(it->second); + if (is != s_InstitutionCodeTypeMap.end()) { + is_miscapitalized = syn_is_miscapitalized; + correct_cap = syn_correct_cap; + needs_country = syn_needs_country; + erroneous_country = syn_erroneous_country; + voucher_type = is->second; + return true; + } + } + } + voucher_type = ic->second; + return true; + } + ic = FindInstitutionCode(inst_coll, s_InstitutionCodeSynonymsMap, is_miscapitalized, correct_cap, needs_country, erroneous_country); + if (ic != s_InstitutionCodeSynonymsMap.end()) { + TInstitutionCodeMap::iterator it = s_InstitutionCodeTypeMap.find(ic->second); + if (it != s_InstitutionCodeTypeMap.end()) { + voucher_type = it->second; + } + return true; + } + return false; } @@ -361,14 +405,15 @@ COrgMod::IsStructuredVoucherValid(const string& val, const string& v_type) string inst_coll; string id; - if (!ParseStructuredVoucher(val, inst_code, coll_code, id)) { - string rval = kEmptyStr; - if (NStr::IsBlank(inst_code)) { - rval = kMissingInst; - } - if (NStr::IsBlank(id)) { - rval = NStr::IsBlank(rval) ? kMissingId : rval + "\n" + kMissingId; - } + ParseStructuredVoucher(val, inst_code, coll_code, id); + string rval = kEmptyStr; + if (NStr::IsBlank(inst_code)) { + rval = kMissingInst; + } + if (NStr::IsBlank(id)) { + rval = NStr::IsBlank(rval) ? kMissingId : rval + "\n" + kMissingId; + } + if (!NStr::IsBlank(rval)) { return rval; } @@ -454,7 +499,7 @@ string COrgMod::MakeStructuredVoucher(const string& inst, const string& coll, co // more letters followed by a series of digits, optionally separated // by space, and if the series of letters looks up as a valid // institution code. -bool FindInstCodeAndSpecID(TInstitutionCodeMap& code_map, string& val) +bool FindInstCodeAndSpecID(COrgMod::TInstitutionCodeMap& code_map, string& val) { // nothing to do if value is blank if (NStr::IsBlank(val)) { @@ -489,7 +534,7 @@ bool FindInstCodeAndSpecID(TInstitutionCodeMap& code_map, string& val) } bool rval = false; - TInstitutionCodeMap::iterator it = code_map.find(inst_code); + COrgMod::TInstitutionCodeMap::iterator it = code_map.find(inst_code); if (it != code_map.end()) { val = inst_code + ":" + remainder; rval = true; @@ -519,6 +564,41 @@ bool COrgMod::AddStructureToVoucher(string& val, const string& v_type) } +bool COrgMod::RescueInstFromParentheses(string& val, const string& voucher_type) +{ + bool rval = false; + + if (!NStr::EndsWith(val, ")")) { + return false; + } + size_t colon_pos = NStr::Find(val, ":"); + if (colon_pos != 0 && colon_pos != string::npos) { + return false; + } + size_t pos = NStr::Find(val, "(", NStr::eNocase, NStr::eReverseSearch); + if (pos == string::npos) { + return false; + } + string inst = val.substr(pos + 1, val.length() - pos - 2); + bool miscap = false, needs_country = false, wrong_country = false; + string capfix; + + string v_type = voucher_type; + if (IsInstitutionCodeValid(inst, v_type, miscap, capfix, needs_country, wrong_country)) { + if (colon_pos == 0) { + val = inst + val.substr(0, pos); + } else { + val = inst + ":" + val.substr(0, pos); + } + NStr::TruncateSpacesInPlace(val); + rval = true; + } + + + return rval; +} + + bool COrgMod::FixStructuredVoucher(string& val, const string& v_type) { @@ -526,9 +606,13 @@ COrgMod::FixStructuredVoucher(string& val, const string& v_type) string coll_code; string id; - if (!ParseStructuredVoucher(val, inst_code, coll_code, id) - || NStr::IsBlank(inst_code)) { - return AddStructureToVoucher(val, v_type); + ParseStructuredVoucher(val, inst_code, coll_code, id); + if (NStr::IsBlank(inst_code)) { + if (AddStructureToVoucher(val, v_type)) { + return true; + } else { + return RescueInstFromParentheses(val, v_type); + } } bool rval = false; bool found = false; @@ -594,13 +678,15 @@ string COrgMod::CheckMultipleVouchers(const vector& vouchers) { ITERATE(vector, it, vouchers) { string inst1, coll1, id1; - if (!COrgMod::ParseStructuredVoucher(*it, inst1, coll1, id1)) continue; + COrgMod::ParseStructuredVoucher(*it, inst1, coll1, id1); + if (NStr::IsBlank(inst1)) continue; if (NStr::EqualNocase(inst1, "personal") || NStr::EqualCase(coll1, "DNA")) continue; vector::const_iterator it_next = it; for (++it_next; it_next != vouchers.end(); ++it_next) { string inst2, coll2, id2; - if (!COrgMod::ParseStructuredVoucher(*it_next, inst2, coll2, id2)) continue; + COrgMod::ParseStructuredVoucher(*it_next, inst2, coll2, id2); + if (NStr::IsBlank(inst2)) continue; if (NStr::EqualNocase(inst2, "personal") || NStr::EqualCase(coll2, "DNA")) continue; if (!NStr::EqualNocase (inst1, inst2) || NStr::IsBlank(inst1)) continue; return NStr::EqualNocase(coll1, coll2) && !NStr::IsBlank(coll1) ? "Multiple vouchers with same institution:collection" : "Multiple vouchers with same institution"; @@ -823,11 +909,41 @@ string COrgMod::FixHostCapitalization(const string& value) } +typedef map THostFixMap; + +const static THostFixMap s_hostFixupMap = { + { "-", "missing" }, + { "No", "missing" }, + { "no", "missing" }, + { "None", "missing" }, + { "none", "missing" }, + { "NA", "not available" }, + { "N/A", "not available" }, + { "n/a", "not available" }, + { "free-living", "natural / free-living" }, + { "natural", "natural / free-living" }, + { "not available", "not available" }, + { "not collected", "not collected" }, + { "not applicable", "not applicable" }, + { "NR", "not applicable" }, + { "not known", "unknown" }, + { "other", "missing" }, + { "misc", "missing" }, + { "not determined", "unknown" }, + { "unknown", "unknown" }, + { "not available: to be reported later", "not available" }, + { "obscured", "obscured" }, + { "human", "Homo sapiens" }, + { "homo sapiens", "Homo sapiens" } +}; + string COrgMod::FixHost(const string& value) { string fix = value; - if (NStr::EqualNocase(fix, "human")) { - fix = "Homo sapiens"; + + auto possible_fix = s_hostFixupMap.find(value); + if (possible_fix != s_hostFixupMap.end()) { + fix = possible_fix->second; } return fix; @@ -924,12 +1040,7 @@ bool COrgMod::RemoveAbbreviation() if (IsSetSubtype() && IsSetSubname()) { string& val = SetSubname(); switch (GetSubtype()) { - case eSubtype_strain: case eSubtype_serovar: - if (NStr::StartsWith(val, "subsp. ")) { - val = val.substr(7); - any_change = true; - } if (NStr::StartsWith(val, "serovar ")) { val = val.substr(8); any_change = true; @@ -980,6 +1091,103 @@ bool COrgMod::IsUnexpectedViralOrgModQualifier() const } +static const string sValidTypeMaterialPrefixes[] = { + "type material", + "type strain", + "reference material", + "reference strain", + "neotype strain", + "paralectotype", + "hapantotype" + "allotype", + "culture from reference material", + "culture from type material", + "ex-type", + "culture from hapantotype", + "pathotype strain" +}; + +static const int sNumValidTypeMaterialPrefixes = sizeof(sValidTypeMaterialPrefixes) / sizeof(string); + +static const string sValidCultureTypeMaterialPrefixes[] = { + "paratype", + "neotype", + "lectotype", + "isosyntype", + "isotype", + "isoparatype", + "isoneotype", + "isolectotype", + "holotype", + "epitype", + "syntype", + "isoepitype" +}; + +static const int sNumValidCultureTypeMaterialPrefixes = sizeof(sValidCultureTypeMaterialPrefixes) / sizeof(string); + +bool COrgMod::IsValidTypeMaterial(const string& type_material) +{ + for (int i = 0; i < sNumValidTypeMaterialPrefixes; i++) { + if (NStr::StartsWith(type_material, sValidTypeMaterialPrefixes[i])) { + return true; + } + } + + for (int i = 0; i < sNumValidCultureTypeMaterialPrefixes; i++) { + if (NStr::StartsWith(type_material, sValidCultureTypeMaterialPrefixes[i])) { + return true; + } else if (NStr::StartsWith(type_material, "culture from " + sValidCultureTypeMaterialPrefixes[i])) { + return true; + } else if (NStr::StartsWith(type_material, "ex-" + sValidCultureTypeMaterialPrefixes[i])) { + return true; + } + } + return false; +} + + +static const string sINSDCTypeMaterialPrefixes[] = { + "type strain", + "neotype strain", + "holotype", + "paratype", + "neotype", + "allotype", + "hapanotype", + "syntype", + "lectotype", + "paralectotype", + "isotype", + "epitype", + "isosyntype", + "ex-type", + "reference strain", + "type material" +}; + +static const int sNumINSDCTypeMaterialPrefixes = sizeof(sINSDCTypeMaterialPrefixes) / sizeof(string); + +// note that the INSDC definition is currently lagging behind what is considered +// valid for taxonomy +bool COrgMod::IsINSDCValidTypeMaterial(const string& type_material) +{ + if (NStr::IsBlank(type_material)) { + return false; + } + + for (int i = 0; iempty() && IsSetLineage()) { *lineage = GetLineage(); } - + if ( !IsSetName() ) { return false; } const TName& name = GetName(); + name_out.clear(); switch (name.Which()) { - case C_Name::e_Binomial: case C_Name::e_Namedhybrid: - { - const CBinomialOrgName& bin = (name.IsBinomial() ? name.GetBinomial() - : name.GetNamedhybrid()); - name_out = bin.GetGenus(); + case C_Name::e_Namedhybrid: { + const CBinomialOrgName& bin = name.GetNamedhybrid(); + name_out += bin.GetGenus(); + if( bin.IsSetSpecies() ) { + name_out += " x "; + name_out += bin.GetSpecies(); + } + return true; + } + case C_Name::e_Binomial: { + const CBinomialOrgName& bin = name.GetBinomial(); if (bin.IsSetSpecies()) { - name_out += ' ' + bin.GetSpecies(); - if (bin.IsSetSubspecies()) { - name_out += ' ' + bin.GetSubspecies(); - } + string sSpecies = bin.GetSpecies(); + if( sSpecies.find(" ") != string::npos && + !( NStr::StartsWith(sSpecies,"sp. ") || + NStr::StartsWith(sSpecies,"species ") ) ) { + // When species epithet is complex -- occurs when genus name doesn't coincide with beginning of species name + name_out += sSpecies; + } else { // Simple case with single genus and species epithets + if (bin.IsSetSubspecies() && !NStr::TruncateSpaces(bin.GetSubspecies()).empty()) { + string sSubspecies = NStr::TruncateSpaces(bin.GetSubspecies()); + bool bSubspIndicator = NStr::StartsWith(sSubspecies, "subsp. ") || + NStr::StartsWith(sSubspecies, "ssp. ") || + NStr::StartsWith(sSubspecies, "subspecies "); + if( sSubspecies.find(" ") != string::npos && !bSubspIndicator ) { + // When subspecies epithet is complex -- occurs when species name doesn't coincide with beginning of subspecies name + name_out += sSubspecies; + } else { // Simple case with single sub-species epithet + name_out += bin.GetGenus(); + name_out += ' ' + bin.GetSpecies(); + if( !bSubspIndicator ) { + string sNomenclature; + bool bZooCode = false; + if( GetNomenclature( sNomenclature ) ) { + bZooCode = sNomenclature == "Z"; + } else { // we still have to support old nomenclature-less orgnames + string sLineage = lineage ? *lineage : IsSetLineage() ? GetLineage() : NcbiEmptyString; + bZooCode = sLineage.find("Metazoa;") != string::npos || + sLineage.find("Slopalinida;") != string::npos || + sLineage.find("Blastocystis;") != string::npos; + } + if( !bZooCode ) { + name_out += " subsp."; + } else { // check if subspecies is well-specified + if( sSubspecies.find_first_not_of("abcdefghijklmnopqrstuvwxyz-") != string::npos || + sSubspecies[0] == '-' ) { + name_out += " ssp."; + } + } + } + name_out += ' ' + sSubspecies; + } + } else { // No subspecies + name_out += bin.GetGenus(); + name_out += ' ' + bin.GetSpecies(); + } + if( IsSetMod() ) { // Add variety and forma to flat name -- those are valid classification categories + ITERATE (COrgName::TMod, it, GetMod()) { + if( (*it)->GetSubtype() == COrgMod::eSubtype_variety ) { + name_out += " var. "; + name_out += (*it)->GetSubname(); + break; + } + } + ITERATE (COrgName::TMod, it, GetMod()) { + if( (*it)->GetSubtype() == COrgMod::eSubtype_forma ) { + name_out += " f. "; + name_out += (*it)->GetSubname(); + break; + } else if( (*it)->GetSubtype() == COrgMod::eSubtype_forma_specialis ) { + name_out += " f.sp. "; + name_out += (*it)->GetSubname(); + break; + } + } + } + } } return true; } @@ -87,11 +155,26 @@ bool COrgName::GetFlatName(string& name_out, string* lineage) const case COrgName::C_Name::e_Hybrid: { + string tmp; + string delim; + string sLineage = lineage ? *lineage : IsSetLineage() ? GetLineage() : NcbiEmptyString; ITERATE (CMultiOrgName::Tdata, it, name.GetHybrid().Get()) { - if ((*it)->GetFlatName(name_out, lineage)) { - return true; - } + tmp.clear(); + if ((*it)->GetFlatName(tmp, &sLineage)) { + name_out += delim; + if( (*it)->IsSetName() && (*it)->GetName().IsHybrid() ) { + name_out += '('; + name_out += tmp; + name_out += ')'; + } else { + name_out += tmp; + } + delim = " x "; + } else { + return false; + } } + return true; } case COrgName::C_Name::e_Partial: @@ -114,9 +197,9 @@ bool COrgName::GetFlatName(string& name_out, string* lineage) const // Presence of flag name in the strings means 'true' value for the flag. const CTempString s_flagDelim = ";"; -void COrgName::x_SetAttribFlag( const string& name ) +void COrgName::x_SetAttribFlag( const string& name, bool bStartsWith ) { - if( !x_GetAttribFlag( name ) ) { + if( !x_GetAttribFlag( name, bStartsWith ) ) { if( IsSetAttrib() && !GetAttrib().empty() ) { SetAttrib().append(s_flagDelim).append(name); } else { @@ -125,7 +208,7 @@ void COrgName::x_SetAttribFlag( const string& name ) } } -void COrgName::x_ResetAttribFlag( const string& name ) +void COrgName::x_ResetAttribFlag( const string& name, bool bStartsWith ) { if( !name.empty() && IsSetAttrib() ) { const string& attr = GetAttrib(); @@ -133,7 +216,8 @@ void COrgName::x_ResetAttribFlag( const string& name ) NStr::Split(attr, s_flagDelim, lVals, NStr::fSplit_Tokenize); for( list< CTempString >::iterator i = lVals.begin(), li = lVals.end(); i != li; ) { NStr::TruncateSpacesInPlace( *i ); - if( NStr::EqualNocase( *i, name ) ) { + if( (!bStartsWith && NStr::EqualNocase( *i, name )) || + (bStartsWith && NStr::StartsWith( *i, name, NStr::eNocase )) ) { i = lVals.erase( i ); } else { ++i; @@ -146,7 +230,26 @@ void COrgName::x_ResetAttribFlag( const string& name ) } } -bool COrgName::x_GetAttribFlag( const string& name ) const +bool COrgName::x_GetAttribFlag( const string& name, bool bStartsWith ) const +{ + if( !name.empty() && IsSetAttrib() ) { + const string& attr = GetAttrib(); + list< CTempString > lVals; + NStr::Split(attr, s_flagDelim, lVals, NStr::fSplit_Tokenize); + NON_CONST_ITERATE( list< CTempString >, i, lVals ) { + NStr::TruncateSpacesInPlace( *i ); + if( (!bStartsWith && NStr::EqualNocase( *i, name )) || + (bStartsWith && NStr::StartsWith( *i, name, NStr::eNocase )) ) { + return true; + } + } + } + return false; +} + +// Getting attribute value for pairs like attrname=value; +// value cannot contain ';' +bool COrgName::x_GetAttribValue( const string& name, string& sValue ) const { if( !name.empty() && IsSetAttrib() ) { const string& attr = GetAttrib(); @@ -154,7 +257,9 @@ bool COrgName::x_GetAttribFlag( const string& name ) const NStr::Split(attr, s_flagDelim, lVals, NStr::fSplit_Tokenize); NON_CONST_ITERATE( list< CTempString >, i, lVals ) { NStr::TruncateSpacesInPlace( *i ); - if( NStr::EqualNocase( *i, name ) ) { + if( NStr::StartsWith( *i, name, NStr::eNocase ) && + i->size() > name.size() && (*i)[name.size()] == '=' ) { + sValue.assign( i->substr(name.size()+1) ); return true; } } @@ -193,6 +298,24 @@ void COrgName::SetUncultured( bool bUncultured ) } } +// Modifier forwarding flag. Used during org-ref lookup to enable/disable +// modifier forwarding. If set modifier forwarding is disabled. +// Flag is kept along with other flags in orgname.attrib field +// (see comments to x_SetAttribFlag() function) +bool COrgName::IsModifierForwardingDisabled() const +{ + return x_GetAttribFlag( "nomodforward" ); +} + +void COrgName::DisableModifierForwarding() +{ + x_SetAttribFlag( "nomodforward" ); +} + +void COrgName::EnableModifierForwarding() +{ + x_ResetAttribFlag( "nomodforward" ); +} #define MAKE_COMMON(o1,o2,o3,Field) if (o1.IsSet##Field() && o2.IsSet##Field() && NStr::Equal(o1.Get##Field(), o2.Get##Field())) o3.Set##Field(o1.Get##Field()); #define MAKE_COMMON_INT(o1,o2,o3,Field) if (o1.IsSet##Field() && o2.IsSet##Field() && o1.Get##Field() == o2.Get##Field()) o3.Set##Field(o1.Get##Field()); @@ -243,6 +366,52 @@ CRef COrgName::MakeCommon(const COrgName& other) const return common; } +// Nomenclature information stored in attrib field as string in following format: +// nomenclature=[BPVZ]*; +bool COrgName::GetNomenclature( string& result ) const +{ + return x_GetAttribValue( "nomenclature", result ); +} + +// returns false if value is unsupported +bool COrgName::SetNomenclature( const string& nomenclature ) +{ + // Analyze value. Make sure it consists of [BPVZ] + char norm_nom[4]; + memset( norm_nom, 0, sizeof(norm_nom) ); + ITERATE( string, ci, nomenclature ) { + switch( *ci ) { + case 'b': case 'B': norm_nom[0] = 'B'; break; + case 'p': case 'P': norm_nom[1] = 'P'; break; + case 'v': case 'V': norm_nom[2] = 'V'; break; + case 'z': case 'Z': norm_nom[3] = 'Z'; break; + default: return false; + } + } + string sNewVal; + for( size_t i = 0; i < sizeof(norm_nom); ++i ) { + if( norm_nom[i] != 0 ) { + sNewVal += norm_nom[i]; + } + } + + string sOldVal; + if( GetNomenclature( sOldVal ) ) { + if( sOldVal == sNewVal ) { + return true; // already set to this value + } else { + ResetNomenclature(); + } + } + x_SetAttribFlag( string("nomenclature=")+sNewVal ); + return true; +} + +// returns false if value is unsupported +void COrgName::ResetNomenclature() +{ + x_ResetAttribFlag( "nomenclature=", true ); +} END_objects_SCOPE // namespace ncbi::objects:: diff --git a/c++/src/objects/seqfeat/Org_ref.cpp b/c++/src/objects/seqfeat/Org_ref.cpp index a4c42b9d..f741824f 100644 --- a/c++/src/objects/seqfeat/Org_ref.cpp +++ b/c++/src/objects/seqfeat/Org_ref.cpp @@ -1,4 +1,4 @@ -/* $Id: Org_ref.cpp 471648 2015-06-30 12:36:49Z kornbluh $ +/* $Id: Org_ref.cpp 542757 2017-08-02 14:34:04Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -23,10 +23,10 @@ * * =========================================================================== * - * Author: ....... + * Author: NCBI Staff * * File Description: - * ....... + * Convenience methods for COrg_ref object * * Remark: * This code was originally generated by application DATATOOL @@ -66,6 +66,7 @@ void COrg_ref::GetLabel(string* label) const } static const char* const s_taxonName = "taxon" ; +static const string s_nomenclature = "nomenclature="; int COrg_ref::GetTaxId() const @@ -338,6 +339,261 @@ CRef COrg_ref::MakeCommon(const COrg_ref& other) const } +typedef map, PNocase> TOrgrefMap; +static TOrgrefMap s_OrgRefMap; +static vector s_CommonTaxnameList; +static bool s_OrgRefMapInitialized = false; +DEFINE_STATIC_FAST_MUTEX(s_OrgRefMapMutex); + +// automatically generated include file +#include "common_tax.inc" + +static void s_ProcessOrgRefMapLine(const CTempString& line) +{ + vector tokens; + NStr::Split(line, "\t", tokens, NStr::fSplit_NoMergeDelims); + if (tokens.size() != 8) { + // ERR_POST_X(1, Warning << "Bad format in common_tax.txt entry " << line + // << "; disregarding"); + } else { + NON_CONST_ITERATE(vector, t, tokens) { + NStr::TruncateSpacesInPlace(*t); + if (NStr::Equal(*t, "-")) { + *t = kEmptyStr; + } + } + + s_CommonTaxnameList.push_back(tokens[0]); + CRef org(new COrg_ref()); + org->SetTaxname(tokens[0]); + if (!NStr::IsBlank(tokens[1])) { + org->SetCommon(tokens[1]); + } + + if (!NStr::IsBlank(tokens[2])) { + try { + org->SetOrgname().SetGcode(NStr::StringToNonNegativeInt(tokens[2])); + } catch (CException& ex) { + } + } + if (!NStr::IsBlank(tokens[3])) { + try { + org->SetOrgname().SetMgcode(NStr::StringToNonNegativeInt(tokens[3])); + } catch (CException& ex) { + } + } + if (!NStr::IsBlank(tokens[4])) { + try { + org->SetOrgname().SetPgcode(NStr::StringToNonNegativeInt(tokens[4])); + } catch (CException& ex) { + } + } + + if (!NStr::IsBlank(tokens[5])) { + try { + CReftaxon(new CDbtag()); + taxon->SetDb("taxon"); + taxon->SetTag().SetId(NStr::StringToNonNegativeInt(tokens[5])); + org->SetDb().push_back(taxon); + } catch (CException& ex) { + } + } + + if (!NStr::IsBlank(tokens[6])) { + org->SetOrgname().SetDiv(tokens[6]); + } + + if (!NStr::IsBlank(tokens[7])) { + org->SetOrgname().SetLineage(tokens[7]); + } + + s_OrgRefMap[tokens[0]] = org; + } +} + + +static void s_InitializeOrgRefMap(void) +{ + CFastMutexGuard GUARD(s_OrgRefMapMutex); + if (s_OrgRefMapInitialized) { + return; + } + string file = g_FindDataFile("common_tax.txt"); + CRef lr; + if (!file.empty()) { + LOG_POST("Reading from " + file + " for popular organisms."); + try { + lr = ILineReader::New(file); + } NCBI_CATCH("s_InitializeOrgRefMap") + } else { + LOG_POST("Falling back on built-in data for popular organisms."); + } + + if (lr.Empty()) { + size_t num_orgrefs = sizeof(kOrgRefList) / sizeof(char *); + for (size_t i = 0; i < num_orgrefs; i++) { + const char *p = kOrgRefList[i]; + s_ProcessOrgRefMapLine(p); + } + } else { + do { + s_ProcessOrgRefMapLine(*++*lr); + } while (!lr->AtEOF()); + } + + s_OrgRefMapInitialized = true; +} + + +CConstRef COrg_ref::TableLookup(const string& taxname) +{ + s_InitializeOrgRefMap(); + TOrgrefMap::iterator it = s_OrgRefMap.find(taxname); + if (it != s_OrgRefMap.end()) { + return CConstRef(it->second.GetPointer()); + } + return CConstRef(NULL); +} + + +bool COrg_ref::UpdateFromTable() +{ + if (!IsSetTaxname() || NStr::IsBlank(GetTaxname())) { + return false; + } + CConstRef lookup = TableLookup(GetTaxname()); + if (lookup) { + if (lookup->IsSetCommon() && !NStr::IsBlank(lookup->GetCommon())) { + SetCommon(lookup->GetCommon()); + } + if (lookup->IsSetGcode()) { + SetOrgname().SetGcode(lookup->GetGcode()); + } + if (lookup->IsSetMgcode()) { + SetOrgname().SetMgcode(lookup->GetMgcode()); + } + if (lookup->IsSetDivision()) { + SetOrgname().SetDiv(lookup->GetDivision()); + } + if (lookup->IsSetDb()) { + CObject_id::TId taxid = 0; + ITERATE(TDb, it, lookup->GetDb()) { + if ((*it)->IsSetDb() && + (*it)->IsSetTag() && + (*it)->GetTag().IsId() && + NStr::Equal((*it)->GetDb(), "taxon")) { + taxid = (*it)->GetTag().GetId(); + break; + } + } + if (taxid > 0) { + SetTaxId(taxid); + } + } + if (lookup->IsSetLineage()) { + SetOrgname().SetLineage(lookup->GetOrgname().GetLineage()); + } + return true; + } else { + return false; + } +} + + +const vector& COrg_ref::GetTaxnameList() +{ + s_InitializeOrgRefMap(); + return s_CommonTaxnameList; +} + + +void COrg_ref::CleanForGenBank() +{ + ResetSyn(); +} + +#define NO_FLAG(a,f) (( a & f ) == 0) + +void COrg_ref::FilterOutParts( fOrgref_parts to_remain ) +{ + if( to_remain == eOrgref_all ) { + return; + } else if( to_remain == eOrgref_nothing ) { + Reset(); + } else { + if( NO_FLAG( to_remain, eOrgref_taxname ) && IsSetTaxname() ) { + ResetTaxname(); + } + if( NO_FLAG( to_remain, eOrgref_common ) && IsSetCommon() ) { + ResetCommon(); + } + if( NO_FLAG( to_remain, eOrgref_mod ) && IsSetMod() ) { + ResetMod(); + } + if( IsSetDb() ) { + if( NO_FLAG( to_remain, eOrgref_db_all ) ) { + ResetDb(); + } else { + if( NO_FLAG( to_remain, eOrgref_db_taxid ) ) { + TDb& lDbTags = SetDb(); + for(TDb::iterator i = lDbTags.begin(); i != lDbTags.end(); ) { + if( *i && i->GetObject().GetDb() == s_taxonName ) { + i = lDbTags.erase( i ); + } else { + ++i; + } + } + } + } + } + if( NO_FLAG( to_remain, eOrgref_syn ) && IsSetSyn() ) { + ResetSyn(); + } + if( IsSetOrgname() ) { + if( NO_FLAG( to_remain, eOrgref_on_all ) ) { + ResetOrgname(); + } else { + COrgName& on = SetOrgname(); + if( NO_FLAG( to_remain, eOrgref_on_name ) && on.IsSetName() ) { + on.ResetName(); + } + if( NO_FLAG( to_remain, eOrgref_on_mod ) && on.IsSetMod() ) { + on.ResetMod(); + } + if( on.IsSetAttrib() ) { + if( NO_FLAG( to_remain, eOrgref_on_attr_all ) ) { + on.ResetAttrib(); + } else { + if( NO_FLAG( to_remain, eOrgref_on_attr_nofwd ) && on.IsModifierForwardingDisabled() ) { + on.EnableModifierForwarding(); + } + if( NO_FLAG( to_remain, eOrgref_on_attr_nom ) ) { + on.ResetNomenclature(); + } + } + } + if( NO_FLAG( to_remain, eOrgref_on_lin ) && on.IsSetLineage() ) { + on.ResetLineage(); + } + if( NO_FLAG( to_remain, eOrgref_on_gc ) && on.IsSetGcode() ) { + on.ResetGcode(); + } + if( NO_FLAG( to_remain, eOrgref_on_mgc ) && on.IsSetMgcode() ) { + on.ResetMgcode(); + } + if( NO_FLAG( to_remain, eOrgref_on_pgc ) && on.IsSetPgcode() ) { + on.ResetPgcode(); + } + if( NO_FLAG( to_remain, eOrgref_on_div ) && on.IsSetDiv() ) { + on.ResetDiv(); + } + + } + } + } +} + + END_objects_SCOPE // namespace ncbi::objects:: END_NCBI_SCOPE diff --git a/c++/src/objects/seqfeat/Prot_ref.cpp b/c++/src/objects/seqfeat/Prot_ref.cpp index a49bc6d3..222e7cb7 100644 --- a/c++/src/objects/seqfeat/Prot_ref.cpp +++ b/c++/src/objects/seqfeat/Prot_ref.cpp @@ -1,4 +1,4 @@ -/* $Id: Prot_ref.cpp 489218 2016-01-11 15:30:48Z bollin $ +/* $Id: Prot_ref.cpp 527196 2017-02-10 13:36:16Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -126,17 +126,20 @@ static CProt_ref::EECNumberFileStatus s_LoadECNumberTable(const string& dir, con { CRef lr; CProt_ref::EECNumberFileStatus rval = CProt_ref::eECFile_not_attempted; - + string file = kEmptyStr; if ( !dir.empty() ) { + file = CDirEntry::MakePath(dir, "ecnum_" + name, "txt"); lr.Reset(ILineReader::New (CDirEntry::MakePath(dir, "ecnum_" + name, "txt"))); rval = CProt_ref::eECFile_not_found; } if (lr.Empty()) { + LOG_POST("Reading " + name + " EC number data from built-in table"); while (fallback_count--) { s_ProcessECNumberLine(*fallback++, status); } } else { + LOG_POST("Reading " + name + " EC number data from " + file); rval = CProt_ref::eECFile_not_read; do { s_ProcessECNumberLine(*++*lr, status); @@ -163,8 +166,9 @@ static void s_InitializeECNumberMaps(void) dir = CDirEntry::AddTrailingPathSeparator(CDirEntry(file).GetDir()); } if (dir.empty()) { - ERR_POST_X(2, Info << "s_InitializeECNumberMaps: " - "falling back on built-in data."); + LOG_POST("s_InitializeECNumberMaps: reading specific EC Numbers from built-in data."); + } else { + LOG_POST("s_InitializeECNumberMaps: reading specific EC Numbers from " + file); } } #define LOAD_EC(x) s_LoadECNumberTable \ diff --git a/c++/src/objects/seqfeat/RNA_gen.cpp b/c++/src/objects/seqfeat/RNA_gen.cpp index 1317ea67..900a2757 100644 --- a/c++/src/objects/seqfeat/RNA_gen.cpp +++ b/c++/src/objects/seqfeat/RNA_gen.cpp @@ -1,4 +1,4 @@ -/* $Id: RNA_gen.cpp 451322 2014-11-05 19:23:13Z kans $ +/* $Id: RNA_gen.cpp 544094 2017-08-17 17:21:31Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -52,39 +52,70 @@ CRNA_gen::~CRNA_gen(void) { } + +static const char* const kAcceptedClasses[] = { + "antisense_RNA", + "autocatalytically_spliced_intron", + "guide_RNA", + "hammerhead_ribozyme", + "lncRNA", + "miRNA", + "other", + "piRNA", + "rasiRNA", + "ribozyme", + "RNase_MRP_RNA", + "RNase_P_RNA", + "scRNA", + "siRNA", + "snoRNA", + "snRNA", + "SRP_RNA", + "telomerase_RNA", + "vault_RNA", + "Y_RNA", +}; +typedef CStaticArraySet TAcceptedClasses; +DEFINE_STATIC_ARRAY_MAP(TAcceptedClasses, + sc_AcceptedClasses, kAcceptedClasses); + +vector CRNA_gen::GetncRNAClassList() +{ + vector choices; + + TAcceptedClasses::const_iterator it = sc_AcceptedClasses.begin(); + while (it != sc_AcceptedClasses.end()) { + choices.push_back(*it); + ++it; + } + return choices; +} + + +bool CRNA_gen::IsLegalClass(const string& val) +{ + TAcceptedClasses::const_iterator it = + sc_AcceptedClasses.find(val.c_str()); + return (it != sc_AcceptedClasses.end()); +} + +bool CRNA_gen::FixncRNAClassValue(string& val) +{ + TAcceptedClasses::const_iterator it = + sc_AcceptedClasses.find(val.c_str()); + + string original = val; + if (it != sc_AcceptedClasses.end()) { + val = *it; + } + + return original != val; +} + bool CRNA_gen::IsLegalClass() const { if (IsSetClass()) { - static const char* const kAcceptedClasses[] = { - "antisense_RNA", - "autocatalytically_spliced_intron", - "guide_RNA", - "hammerhead_ribozyme", - "lncRNA", - "miRNA", - "other", - "piRNA", - "rasiRNA", - "ribozyme", - "RNase_MRP_RNA", - "RNase_P_RNA", - "scRNA", - "siRNA", - "snoRNA", - "snRNA", - "SRP_RNA", - "stRNA", - "telomerase_RNA", - "vault_RNA", - "Y_RNA", - }; - typedef CStaticArraySet TAcceptedClasses; - DEFINE_STATIC_ARRAY_MAP(TAcceptedClasses, - sc_AcceptedClasses, kAcceptedClasses); - - TAcceptedClasses::const_iterator it = - sc_AcceptedClasses.find(GetClass().c_str()); - return (it != sc_AcceptedClasses.end()); + return IsLegalClass(GetClass()); } return false; } diff --git a/c++/src/objects/seqfeat/SeqFeatData.cpp b/c++/src/objects/seqfeat/SeqFeatData.cpp index 20ec5447..a1239680 100644 --- a/c++/src/objects/seqfeat/SeqFeatData.cpp +++ b/c++/src/objects/seqfeat/SeqFeatData.cpp @@ -1,4 +1,4 @@ -/* $Id: SeqFeatData.cpp 514391 2016-09-21 15:38:23Z ivanov $ +/* $Id: SeqFeatData.cpp 544558 2017-08-24 11:54:42Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -123,6 +123,7 @@ static const SImportEntry kImportTable[] = { { "prim_transcript", CSeqFeatData::eSubtype_prim_transcript }, { "primer_bind", CSeqFeatData::eSubtype_primer_bind }, { "promoter", CSeqFeatData::eSubtype_promoter }, + { "propeptide", CSeqFeatData::eSubtype_propeptide }, { "protein_bind", CSeqFeatData::eSubtype_protein_bind }, { "regulatory", CSeqFeatData::eSubtype_regulatory }, { "rep_origin", CSeqFeatData::eSubtype_rep_origin }, @@ -189,7 +190,7 @@ static const TProtInfoPair kProtInfoPairs[] = { PROT_INFO_PAIR(mature, mat_peptide_aa, "Prot", "mat_peptide"), PROT_INFO_PAIR(signal_peptide, sig_peptide_aa, "Prot", "sig_peptide"), PROT_INFO_PAIR(transit_peptide, transit_peptide_aa, "Prot", "transit_peptide"), - PROT_INFO_PAIR(propeptide, propeptide, "Prot", "propeptide") + PROT_INFO_PAIR(propeptide, propeptide_aa, "Prot", "propeptide") }; typedef CStaticPairArrayMapsecond; } +bool CSeqFeatData::CanHaveGene(CSeqFeatData::ESubtype subtype) +{ + switch(subtype) { + case eSubtype_cdregion: + case eSubtype_mRNA: + case eSubtype_tRNA: + case eSubtype_rRNA: + case eSubtype_otherRNA: + case eSubtype_ncRNA: + case eSubtype_tmRNA: + return true; + default: + break; + } + return false; +} + typedef map TSubtypeValueToNameMap; static TSubtypeValueToNameMap* s_CreateSubtypeValueToNameMap(void) { // if this assertion fails, it means this function might be out // of date. Don't just fix the assert, make sure the function is // up to date. - _ASSERT( 105 == CSeqFeatData::eSubtype_max ); + _ASSERT( 106 == CSeqFeatData::eSubtype_max ); auto_ptr pAnswerMap( new TSubtypeValueToNameMap ); // created from inverse of sm_FeatKeys @@ -725,8 +744,9 @@ static const SSubtypeInfo s_subtype_info[] = { SUBTYPE_INFO( e_Imp, eSubtype_telomere, 101), SUBTYPE_INFO( e_Imp, eSubtype_assembly_gap, 102), SUBTYPE_INFO( e_Imp, eSubtype_regulatory, 103), - SUBTYPE_INFO( e_Prot, eSubtype_propeptide, 104), - SUBTYPE_INFO( e_not_set, eSubtype_max, 105), + SUBTYPE_INFO( e_Imp, eSubtype_propeptide, 104), + SUBTYPE_INFO( e_Prot, eSubtype_propeptide_aa, 105), + SUBTYPE_INFO( e_not_set, eSubtype_max, 106), SUBTYPE_INFO( e_not_set, eSubtype_any, 255) }; static const size_t s_subtype_count = @@ -768,7 +788,6 @@ void CSeqFeatData::s_InitSubtypesTable(void) for (int sub = eSubtype_prot; sub <= eSubtype_transit_peptide_aa; ++sub) { table[ESubtype(sub)] = e_Prot; } - table[eSubtype_propeptide] = e_Prot; for (int sub = eSubtype_preRNA; sub <= eSubtype_otherRNA; ++sub) { table[ESubtype(sub)] = e_Rna; } @@ -780,7 +799,8 @@ void CSeqFeatData::s_InitSubtypesTable(void) for ( const SImportEntry* p = kImportTable; p != kImportTableEnd; ++p ) { table[p->m_Subtype] = e_Imp; } - table[eSubtype_propeptide] = e_Prot; + table[eSubtype_propeptide] = e_Imp; + table[eSubtype_propeptide_aa] = e_Prot; sx_SubtypesTableInitialized = true; @@ -855,7 +875,6 @@ START_SUBTYPE(gene) ADD_QUAL(product); ADD_QUAL(pseudo); ADD_QUAL(pseudogene); - ADD_QUAL(standard_name); ADD_QUAL(trans_splicing); ADD_QUAL(usedin); END_SUBTYPE @@ -2984,6 +3003,34 @@ START_SUBTYPE(propeptide) ADD_QUAL(usedin); END_SUBTYPE +START_SUBTYPE(propeptide_aa) + ADD_QUAL(EC_number); + ADD_QUAL(allele); + ADD_QUAL(calculated_mol_wt); + ADD_QUAL(citation); + ADD_QUAL(db_xref); + ADD_QUAL(derived_from); + ADD_QUAL(evidence); + ADD_QUAL(exception); + ADD_QUAL(experiment); + ADD_QUAL(function); + ADD_QUAL(gene); + ADD_QUAL(gene_synonym); + ADD_QUAL(inference); + ADD_QUAL(label); + ADD_QUAL(locus_tag); + ADD_QUAL(map); + ADD_QUAL(name); + ADD_QUAL(note); + ADD_QUAL(old_locus_tag); + ADD_QUAL(product); + ADD_QUAL(protein_id); + ADD_QUAL(pseudo); + ADD_QUAL(pseudogene); + ADD_QUAL(standard_name); + ADD_QUAL(usedin); +END_SUBTYPE + #undef START_SUBTYPE #undef ADD_QUAL #undef END_SUBTYPE @@ -3066,6 +3113,7 @@ static const TQualPair kQualPairs[] = { { CSeqFeatData::eQual_culture_collection, "culture_collection" }, { CSeqFeatData::eQual_cyanelle, "cyanelle" }, { CSeqFeatData::eQual_db_xref, "db_xref" }, + { CSeqFeatData::eQual_derived_from, "derived_from" }, { CSeqFeatData::eQual_dev_stage, "dev_stage" }, { CSeqFeatData::eQual_direction, "direction" }, { CSeqFeatData::eQual_EC_number, "EC_number" }, @@ -3085,6 +3133,7 @@ static const TQualPair kQualPairs[] = { { CSeqFeatData::eQual_germline, "germline" }, { CSeqFeatData::eQual_haplogroup, "haplogroup" }, { CSeqFeatData::eQual_haplotype, "haplotype" }, + { CSeqFeatData::eQual_heterogen, "heterogen" }, { CSeqFeatData::eQual_host, "host" }, { CSeqFeatData::eQual_identified_by, "identified_by" }, { CSeqFeatData::eQual_inference, "inference" }, @@ -3108,6 +3157,7 @@ static const TQualPair kQualPairs[] = { { CSeqFeatData::eQual_mod_base, "mod_base" }, { CSeqFeatData::eQual_mol_type, "mol_type" }, { CSeqFeatData::eQual_name, "name" }, + { CSeqFeatData::eQual_nomenclature, "nomenclature" }, { CSeqFeatData::eQual_ncRNA_class, "ncRNA_class" }, { CSeqFeatData::eQual_note, "note" }, { CSeqFeatData::eQual_number, "number" }, @@ -3138,6 +3188,7 @@ static const TQualPair kQualPairs[] = { { CSeqFeatData::eQual_rpt_unit_range, "rpt_unit_range" }, { CSeqFeatData::eQual_rpt_unit_seq, "rpt_unit_seq" }, { CSeqFeatData::eQual_satellite, "satellite" }, + { CSeqFeatData::eQual_sec_str_type, "sec_str_type" }, { CSeqFeatData::eQual_segment, "segment" }, { CSeqFeatData::eQual_sequenced_mol, "sequenced_mol" }, { CSeqFeatData::eQual_serotype, "serotype" }, @@ -3164,7 +3215,8 @@ static const TQualPair kQualPairs[] = { { CSeqFeatData::eQual_UniProtKB_evidence, "UniProtKB_evidence" }, { CSeqFeatData::eQual_usedin, "usedin" }, { CSeqFeatData::eQual_variety, "variety" }, - { CSeqFeatData::eQual_virion, "virion" } + { CSeqFeatData::eQual_virion, "virion" }, + { CSeqFeatData::eQual_whole_replicon, "whole_replicon" } }; typedef CStaticPairArrayMap TQualsMap; @@ -3927,6 +3979,35 @@ vector CSeqFeatData::GetRegulatoryClassList() return choices; } +bool CSeqFeatData::FixRegulatoryClassValue(string& val) +{ + static vector regulatory_class_values; + if (regulatory_class_values.empty()) { + regulatory_class_values = GetRegulatoryClassList(); + } + + string original = val; + + const string* valid_val = NStr::FindNoCase(regulatory_class_values, val); + if (valid_val != nullptr) { + val = *valid_val; + } + + return original != val; +} + +vector CSeqFeatData::GetRecombinationClassList() +{ + vector choices; + + choices.push_back("meiotic"); + choices.push_back("mitotic"); + choices.push_back("non_allelic_homologous"); + choices.push_back("chromosome_breakpoint"); + + return choices; +} + bool CSeqFeatData::IsDiscouragedSubtype(ESubtype subtype) { switch(subtype) { @@ -3996,7 +4077,7 @@ static const SFeatListItem sc_ConfigItemInit[] = { { CSeqFeatData::e_Prot, CSeqFeatData::eSubtype_mat_peptide_aa, "Mature Peptide AA", "Mat-Peptide AA" }, { CSeqFeatData::e_Prot, CSeqFeatData::eSubtype_sig_peptide_aa, "Signal Peptide AA", "Sig-Peptide AA" }, { CSeqFeatData::e_Prot, CSeqFeatData::eSubtype_transit_peptide_aa, "Transit Peptide AA", "Transit-Peptide AA" }, - { CSeqFeatData::e_Prot, CSeqFeatData::eSubtype_propeptide, "ProPeptide", "ProPeptide" }, + { CSeqFeatData::e_Prot, CSeqFeatData::eSubtype_propeptide_aa, "ProPeptide AA", "ProPeptide" }, { CSeqFeatData::e_Rna, CSeqFeatData::eSubtype_any, "RNA, All" , "RNA Master" }, { CSeqFeatData::e_Rna, CSeqFeatData::eSubtype_preRNA, "precursor_RNA", "precursor_RNA" }, @@ -4414,7 +4495,7 @@ CSeqFeatData::EFeatureLocationAllowed CSeqFeatData::AllowedFeatureLocation(ESubt case eSubtype_mat_peptide_aa: case eSubtype_sig_peptide_aa: case eSubtype_transit_peptide_aa: - case eSubtype_propeptide: + case eSubtype_propeptide_aa: case eSubtype_bond: case eSubtype_psec_str: rval = eFeatureLocationAllowed_ProtOnly; @@ -4521,6 +4602,7 @@ bool CSeqFeatData::ShouldRepresentAsGbqual (CSeqFeatData::ESubtype feat_subtype, if (feat_subtype == CSeqFeatData::eSubtype_mat_peptide || feat_subtype == CSeqFeatData::eSubtype_sig_peptide || feat_subtype == CSeqFeatData::eSubtype_transit_peptide + || feat_subtype == CSeqFeatData::eSubtype_propeptide || feat_subtype == CSeqFeatData::eSubtype_C_region || feat_subtype == CSeqFeatData::eSubtype_D_segment || feat_subtype == CSeqFeatData::eSubtype_exon @@ -4613,6 +4695,40 @@ bool CSeqFeatData::ShouldRepresentAsGbqual (CSeqFeatData::ESubtype feat_subtype, return ShouldRepresentAsGbqual(feat_subtype, CSeqFeatData::GetQualifierType(qual.GetQual())); } + +bool CSeqFeatData::FixImportKey(string& key) +{ + if (NStr::EqualNocase(key, "allele") || + NStr::EqualNocase(key, "mutation")) { + key = "variation"; + return true; + } else if (NStr::EqualNocase(key, "Import") || + NStr::EqualNocase(key, "virion")) { + key = "misc_feature"; + return true; + } else if (NStr::EqualNocase(key, "repeat_unit")) { + key = "repeat_region"; + return true; + } else if (NStr::EqualNocase(key, "misc_bind")) { + key = "misc_binding"; + return true; + } + const SImportEntry* start = kImportTable; + while (start < kImportTableEnd) { + if (NStr::EqualNocase(key, start->m_Name)) { + if (!NStr::Equal(key, start->m_Name)) { + key = start->m_Name; + return true; + } else { + return false; + } + } + ++start; + } + return false; +} + + END_objects_SCOPE // namespace ncbi::objects:: END_NCBI_SCOPE diff --git a/c++/src/objects/seqfeat/Seq_feat.cpp b/c++/src/objects/seqfeat/Seq_feat.cpp index f32e7377..8af761d9 100644 --- a/c++/src/objects/seqfeat/Seq_feat.cpp +++ b/c++/src/objects/seqfeat/Seq_feat.cpp @@ -1,4 +1,4 @@ -/* $Id: Seq_feat.cpp 518385 2016-11-02 17:27:05Z ivanov $ +/* $Id: Seq_feat.cpp 518014 2016-10-31 12:23:17Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seqfeat/SubSource.cpp b/c++/src/objects/seqfeat/SubSource.cpp index 294980a2..83e740ca 100644 --- a/c++/src/objects/seqfeat/SubSource.cpp +++ b/c++/src/objects/seqfeat/SubSource.cpp @@ -1,4 +1,4 @@ -/* $Id: SubSource.cpp 520189 2016-11-23 16:34:24Z ivanov $ +/* $Id: SubSource.cpp 543049 2017-08-07 11:53:06Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -564,27 +564,34 @@ string CSubSource::FixDateFormat (const string& orig_date) // HH:MM // HH // Followed by either Z or +hh:mm to indicate an offset from Zulu -bool CSubSource::IsISOFormatTime(const string& orig_time, int& hour, int& min, int& sec) +bool CSubSource::IsISOFormatTime(const string& orig_time, int& hour, int& min, int& sec, bool require_time_zone) { int offset_hour = 0; int offset_min = 0; size_t suffix = NStr::Find(orig_time, "Z"); if (suffix == NPOS) { suffix = NStr::Find(orig_time, "+"); - if (suffix == NPOS || - orig_time.substr(suffix).length() != 6 || - !isdigit((unsigned char)orig_time[suffix + 1]) || - !isdigit((unsigned char)orig_time[suffix + 2]) || - orig_time[suffix + 3] != ':' || - !isdigit((unsigned char)orig_time[suffix + 4]) || - !isdigit((unsigned char)orig_time[suffix + 5])) { - return false; - } - try { - offset_hour = NStr::StringToInt(orig_time.substr(suffix + 1, 2)); - offset_min = NStr::StringToInt(orig_time.substr(suffix + 4, 2)); - } catch (...) { - return false; + if (suffix == NPOS) { + if (require_time_zone) { + return false; + } else { + suffix = orig_time.length(); + } + } else { + if (orig_time.substr(suffix).length() != 6 || + !isdigit((unsigned char)orig_time[suffix + 1]) || + !isdigit((unsigned char)orig_time[suffix + 2]) || + orig_time[suffix + 3] != ':' || + !isdigit((unsigned char)orig_time[suffix + 4]) || + !isdigit((unsigned char)orig_time[suffix + 5])) { + return false; + } + try { + offset_hour = NStr::StringToInt(orig_time.substr(suffix + 1, 2)); + offset_min = NStr::StringToInt(orig_time.substr(suffix + 4, 2)); + } catch (...) { + return false; + } } } if (suffix != 2 && suffix != 5 && suffix != 8) { @@ -691,6 +698,44 @@ bool CSubSource::IsISOFormatDateOnly (const string& cpy) return rval; } + +bool CSubSource::x_IsFixableIsoDate(const string& orig_date) +{ + string cpy = orig_date; + NStr::TruncateSpacesInPlace(cpy); + size_t time_pos = NStr::Find(cpy, "T"); + bool rval = false; + if (time_pos == NPOS) { + rval = false; + } else { + if (!IsISOFormatDateOnly(cpy.substr(0, time_pos))) { + rval = false; + } else { + int h, m, s; + if (IsISOFormatTime(cpy.substr(time_pos + 1), h, m, s, true)) { + // already fine, not fixable + rval = false; + } else { + rval = IsISOFormatTime(cpy.substr(time_pos + 1), h, m, s, false); + } + } + } + return rval; +} + + +string CSubSource::x_RemoveIsoTime(const string& orig_date) +{ + string cpy = orig_date; + NStr::TruncateSpacesInPlace(cpy); + size_t time_pos = NStr::Find(cpy, "T"); + if (time_pos != NPOS) { + cpy = cpy.substr(0, time_pos); + } + return cpy; +} + + bool CSubSource::IsISOFormatDate(const string& orig_date) { string cpy = orig_date; @@ -839,6 +884,8 @@ string CSubSource::FixDateFormat (const string& test, bool month_first, bool& mo if (IsISOFormatDate(orig_date)) { return orig_date; + } else if (x_IsFixableIsoDate(orig_date)) { + return x_RemoveIsoTime(orig_date); } string reformatted_date; @@ -885,6 +932,9 @@ string CSubSource::FixDateFormat (const string& test, bool month_first, bool& mo // already have month, error return kEmptyStr; } + if (one_token.length() > 3) { + one_token = one_token.substr(0, 3); + } try { int month_num = CTime::MonthNameToNum(one_token); found = true; @@ -1014,7 +1064,7 @@ string CSubSource::FixDateFormat (const string& test, bool month_first, bool& mo } } - if (year > 31 && year < 100 && num_original_tokens > 1) { + if (year > 0 && year < 100 && num_original_tokens > 1) { // try to guess year from two-digit year provided, // only if it could not possibly be a day of the month // and if there were at least two tokens provided @@ -1174,6 +1224,42 @@ void CSubSource::IsCorrectLatLonFormat (string lat_lon, bool& format_correct, bo } +string CSubSource::FixLatLonPrecision(const string& orig) +{ + bool format_correct = false; + bool precision_correct = false; + bool lat_in_range = false; + bool lon_in_range = false; + double lat_value = 0.0; + double lon_value = 0.0; + IsCorrectLatLonFormat(orig, format_correct, precision_correct, + lat_in_range, lon_in_range, + lat_value, lon_value); + if (!format_correct || !lat_in_range || !lon_in_range || precision_correct) { + return orig; + } + vector pieces; + NStr::Split(orig, " ", pieces, NStr::fSplit_NoMergeDelims); + if (pieces.size() > 3) { + int precision_lat = x_GetPrecision(pieces[0]); + int precision_lon = x_GetPrecision(pieces[2]); + if (precision_lat > 4) { + precision_lat = 4; + } + if (precision_lon > 4) { + precision_lon = 4; + } + + char reformatted[1000]; + sprintf(reformatted, "%.*lf %c %.*lf %c", precision_lat, fabs(lat_value), pieces[1].c_str()[0], + precision_lon, fabs(lon_value), pieces[3].c_str()[0]); + string new_val = reformatted; + return reformatted; + } + return kEmptyStr; +} + + static void s_TrimInternalSpaces (string& token) { size_t pos; @@ -1221,6 +1307,72 @@ static void s_RemoveLeadingZeros(string& token) } +bool s_AddTokenToVal(double& val, const string& num_str, size_t num_sep, size_t& prec) +{ + double this_val = NStr::StringToDouble(num_str, NStr::fConvErr_NoThrow); + if (errno != 0) { + return false; + } + + if (num_sep == 0) { + val += this_val; + } else if (num_sep == 1) { + if (this_val >= 60.0) { + // too big to be minutes + return false; + } + val += (this_val) / (60.0); + prec += 2; + } else if (num_sep == 2) { + if (this_val >= 60.0) { + // too big to be seconds + return false; + } + val += (this_val) / (3600.0); + prec += 2; + } else { + // too many separators + return false; + } + size_t p_pos = NStr::Find(num_str, "."); + if (p_pos != NPOS) { + prec += num_str.substr(p_pos + 1).length(); + } + + return true; +} + + +string s_StringFromValAndPrec(double val, size_t prec) +{ + if (prec > 0) { + double mult = pow((double)10.0, int(prec)); + bool round_down = true; + double remainder = (val * mult) - floor(val * mult); + if (remainder > 0.5) { + round_down = false; + } + double tmp; + if (round_down) { + tmp = floor(val * mult); + } else { + tmp = ceil(val * mult); + } + val = tmp / mult; + } + string val_str = NStr::NumericToString(val, NStr::fDoubleFixed); + size_t pos = NStr::Find(val_str, "."); + if (pos != NPOS && prec > 0) { + while (val_str.substr(pos + 1).length() < prec) { + val_str += "0"; + } + if (val_str.substr(pos + 1).length() > prec) { + val_str = val_str.substr(0, pos + prec + 1); + } + } + return val_str; +} + static string s_GetNumFromLatLonToken (string token, const string& default_dir) { NStr::TruncateSpacesInPlace(token); @@ -1251,14 +1403,15 @@ static string s_GetNumFromLatLonToken (string token, const string& default_dir) if (NStr::IsBlank(dir)) { dir = s_GetDefaultDir(is_negative, default_dir); } else if (is_negative) { - return kEmptyStr; + // ignore the dash + is_negative = false; } size_t pos = 0; double val = 0; size_t num_sep = 0, prev_start = 0; size_t prec = 0; - bool seen_period = false; + size_t num_period = 0; bool last_is_sep = false; while (pos < token.length()) { @@ -1269,30 +1422,23 @@ static string s_GetNumFromLatLonToken (string token, const string& default_dir) return kEmptyStr; } string num_str = token.substr(prev_start, pos - prev_start); - double this_val = NStr::StringToDouble (num_str); - if (num_sep == 0) { - val += this_val; - } else if (num_sep == 1) { - val += (this_val) / (60.0); - prec += 2; - } else if (num_sep == 2) { - val += (this_val) / (3600.0); - prec += 2; - } else { + if (!s_AddTokenToVal(val, num_str, num_sep, prec)) { // too many separators return kEmptyStr; } - size_t p_pos = NStr::Find (num_str, "."); - if (p_pos != NPOS) { - prec += num_str.substr(p_pos + 1).length(); - } num_sep++; pos++; prev_start = pos; last_is_sep = true; } else if (ch == '\'') { + if (num_period > 1) { + return kEmptyStr; + } string num_str = token.substr(prev_start, pos - prev_start); - double this_val = NStr::StringToDouble (num_str); + double this_val = NStr::StringToDouble(num_str, NStr::fConvErr_NoThrow); + if (errno != 0) { + return kEmptyStr; + } if (token[pos + 1] == '\'') { if (num_sep > 2) { // already found seconds @@ -1336,81 +1482,63 @@ static string s_GetNumFromLatLonToken (string token, const string& default_dir) pos++; last_is_sep = false; } else if (ch == '.') { - if (seen_period) { + if (num_period > 0 && num_sep > 0) { return kEmptyStr; } - seen_period = true; + num_period++; pos++; last_is_sep = false; } else { return kEmptyStr; } } + if (num_sep == 0 && num_period > 1) { + list pieces; + NStr::Split(token, ".", pieces, 0); + num_sep = 0; + ITERATE(list, it, pieces) { + if (!s_AddTokenToVal(val, *it, num_sep, prec)) { + // too many separators + return kEmptyStr; + } + num_sep++; + } + string val_str = s_StringFromValAndPrec(val, prec); + + if (!NStr::IsBlank(dir)) { + val_str = val_str + " " + dir; + } + return val_str; + } else if (num_period > 1) { + return kEmptyStr; + } if (num_sep > 0 && !last_is_sep) { // if there have been separators, but the last value is not a separator, - if (num_sep == 2 && !seen_period) { + if (num_sep == 2 && num_period == 0) { // if we have seen minutes but not seconds we'll treat this last value as seconds + } else if (num_sep == 1) { + // we'll treat this last value as minutes } else { // otherwise this is a bad format return kEmptyStr; } } - s_RemoveLeadingZeros(token); - if (prev_start == 0) { if (!NStr::IsBlank(dir)) { token = token + " " + dir; } + s_RemoveLeadingZeros(token); return token; } else { if (prev_start < pos) { string num_str = token.substr(prev_start, pos - prev_start); - - double this_val = NStr::StringToDouble (num_str); - if (num_sep == 0) { - val += this_val; - } else if (num_sep == 1) { - val += (this_val) / (60.0); - prec += 2; - } else if (num_sep == 2) { - val += (this_val) / (3600.0); - prec += 2; - } else { + if (!s_AddTokenToVal(val, num_str, num_sep, prec)) { // too many separators return kEmptyStr; } - size_t p_pos = NStr::Find (num_str, "."); - if (p_pos != NPOS) { - prec += num_str.substr(p_pos + 1).length(); - } - } - if (prec > 0) { - double mult = pow ((double)10.0, int(prec)); - bool round_down = true; - double remainder = (val * mult) - floor (val * mult); - if (remainder > 0.5) { - round_down = false; - } - double tmp; - if (round_down) { - tmp = floor(val * mult); - } else { - tmp = ceil(val * mult); - } - val = tmp / mult; - } - string val_str = NStr::NumericToString (val, NStr::fDoubleFixed); - pos = NStr::Find (val_str, "."); - if (pos != NPOS && prec > 0) { - while (val_str.substr(pos + 1).length() < prec) { - val_str += "0"; - } - if (val_str.substr(pos + 1).length() > prec) { - val_str = val_str.substr (0, pos + prec + 1); - } } - + string val_str = s_StringFromValAndPrec(val, prec); if (!NStr::IsBlank(dir)) { val_str = val_str + " " + dir; @@ -1481,6 +1609,11 @@ string CSubSource::FixLatLonFormat (string orig_lat_lon, bool guess) } cpy = orig_lat_lon; + + // remove containing quotes + if (NStr::StartsWith(cpy, "\"") && NStr::EndsWith(cpy, "\"")) { + cpy = cpy.substr(1, cpy.length() - 2); + } // replace all 'O' (capital o) following non-alpha characters with '0' (zero) pos = NStr::Find (cpy, "O"); @@ -1510,6 +1643,7 @@ string CSubSource::FixLatLonFormat (string orig_lat_lon, bool guess) // replace all '#' with ' ' NStr::ReplaceInPlace (cpy, "#", " "); + NStr::ReplaceInPlace(cpy, "\"", "''"); // now make all letters uppercase (note, do not do this before converting 'o' and 'O'( cpy = NStr::ToUpper (cpy); @@ -1576,6 +1710,7 @@ string CSubSource::FixLatLonFormat (string orig_lat_lon, bool guess) NStr::ReplaceInPlace (cpy, "_", " "); NStr::ReplaceInPlace (cpy, "&", " "); NStr::ReplaceInPlace (cpy, " ", " "); // double-spaces become single spaces + NStr::ReplaceInPlace (cpy, " . ", "."); // space before and after period is eliminated size_t lat_pos = NStr::Find (cpy, "LAT"); size_t lon_pos = NStr::Find (cpy, "LO"); @@ -2046,7 +2181,7 @@ string CSubSource::ValidateLatLonCountry (const string& input_countryname, strin if (m_LatLonWaterMap->IsCountryInLatLon(country, lat_value, lon_value)) { return kEmptyStr; } - } else if (NStr::EqualNocase (country, "Palestine") || NStr::EqualNocase (country, "State of Palestine")) { + } else if (NStr::EqualNocase (country, "State of Palestine")) { } else { // report unrecognized country return kEmptyStr; @@ -2064,8 +2199,7 @@ string CSubSource::ValidateLatLonCountry (const string& input_countryname, strin if (NStr::EqualNocase (country, "USA") && NStr::EqualNocase (cguess, "Puerto Rico")) { return kEmptyStr; } - if ((NStr::EqualNocase (country, "Palestine") || - NStr::EqualNocase (country, "State of Palestine")) && + if (NStr::EqualNocase (country, "State of Palestine") && (NStr::EqualNocase (cguess, "Gaza Strip") || NStr::EqualNocase (cguess, "West Bank"))) { return kEmptyStr; @@ -2090,8 +2224,7 @@ string CSubSource::ValidateLatLonCountry (const string& input_countryname, strin } if (!flags && !m_LatLonCountryMap->IsNearLatLon(lat_value, lon_value, 20.0, neardist, country) - && !m_LatLonWaterMap->IsNearLatLon(lat_value, lon_value, 20.0, neardist, country) - && (! NStr::IsBlank (cguess)) && NStr::IsBlank (wguess)) { + && !m_LatLonWaterMap->IsNearLatLon(lat_value, lon_value, 20.0, neardist, country)) { /* do not flip from water */ CLatLonCountryId *adjust_id = x_CalculateLatLonId(lon_value, lat_value, country, province); adjusted_flags = adjust_id == NULL ? 0 : adjust_id->Classify(country, province); @@ -2805,7 +2938,6 @@ static const char* const s_Countries[] = { "Pacific Ocean", "Pakistan", "Palau", - "Palestine", "Palmyra Atoll", "Panama", "Papua New Guinea", @@ -3720,369 +3852,131 @@ string CCountries::CountryFixupItem(const string &input, bool capitalize_after_c } return new_country; } - -const char * sm_KnownDevStageWords[] = { - "adult", - "egg", - "juvenile", - "larva", + +// SubSource Qual Fixups +typedef SStaticPair TStaticQualFixPair; +typedef CStaticPairArrayMap TStaticQualFixMap; + +static const TStaticQualFixPair kDevStagePairs[] = { + { "adult", "adult" }, + { "egg", "egg" }, + { "juvenile", "juvenile" }, + { "larva", "larva" } }; +DEFINE_STATIC_ARRAY_MAP(TStaticQualFixMap, sc_DevStagePairs, kDevStagePairs); + string CSubSource::FixDevStageCapitalization(const string& value) { string fix = value; - size_t max = sizeof(sm_KnownDevStageWords) / sizeof(const char*); - for (size_t i = 0; i < max; i++) { - if (NStr::EqualNocase(fix, sm_KnownDevStageWords[i])) { - fix = sm_KnownDevStageWords[i]; - break; - } + TStaticQualFixMap::const_iterator it = sc_DevStagePairs.find(value.c_str()); + if (it != sc_DevStagePairs.end()) { + fix = it->second; } return fix; } -const char * sm_CellTypeWords[] = { - "hemocyte", - "hepatocyte", - "lymphocyte", - "neuroblast", +static const TStaticQualFixPair kCellTypePairs[] = { + { "hemocyte", "hemocyte" }, + { "hepatocyte", "hepatocyte" }, + { "lymphocyte", "lymphocyte" }, + { "neuroblast", "neuroblast" } }; +DEFINE_STATIC_ARRAY_MAP(TStaticQualFixMap, sc_CellTypePairs, kCellTypePairs); string CSubSource::FixCellTypeCapitalization(const string& value) { string fix = value; - size_t max = sizeof(sm_CellTypeWords) / sizeof(const char*); - for (size_t i = 0; i < max; i++) { - if (NStr::EqualNocase(fix, sm_CellTypeWords[i])) { - fix = sm_CellTypeWords[i]; - break; - } + TStaticQualFixMap::const_iterator it = sc_CellTypePairs.find(value.c_str()); + if (it != sc_CellTypePairs.end()) { + fix = it->second; } return fix; + } +DEFINE_STATIC_FAST_MUTEX(s_QualFixMutex); +typedef map TQualFixMap; -const char * sm_KnownIsolationAndTissueTypeWords[] = { - "abdomen", - "abdominal fluid", - "acne", - "activated sludge", - "adductor muscle", - "agricultural soil", - "air", - "amniotic fluid", - "antenna", - "aspirate", - "bile", - "biofilm", - "blood", - "blood cells", - "blood sample", - "body fluid", - "bone", - "bovine feces", - "bovine milk", - "brain", - "brain abscess", - "brain tissue", - "branch", - "bronchial mucosa", - "bronchoalveolar lavage", - "buccal epithelial cells", - "buccal mucosa", - "buccal swab", - "bursa", - "callus", - "cave sediment", - "cave sediments", - "cerebellum", - "cerebrospinal fluid", - "cervix", - "cheese", - "clinical", - "clinical isolate", - "clinical isolates", - "clinical sample", - "clinical samples", - "cloaca", - "cloacal swab", - "compost", - "coral reef", - "corn rhizosphere", - "cornea", - "cotton rhizosphere", - "dairy cow rumen", - "distillery", - "drinking water", - "ear", - "egg", - "embryogenic callus", - "epithelium", - "esophageal mucosa", - "estuarine water", - "estuarine waters", - "eye", - "fecal", - "fecal sample", - "fecal samples", - "feces", - "fermented food", - "fermented soybeans", - "fetal brain", - "fin", - "fin wound", - "fish eggs", - "flooded rice soil", - "flower", - "food", - "food product", - "food sample", - "food samples", - "forest", - "forest soil", - "freshwater stream", - "fruit", - "fruitbody", - "fruiting body", - "gastric mucosa", - "gastrointestinal tract", - "genital cells", - "genitals", - "gill", - "gills", - "goat milk", - "head", - "head kidney", - "heart", - "heart blood", - "hemocyte", - "hepatocyte", - "hepatopancreas", - "horse", - "horse", - "hot spring", - "hot springs", - "human plasma", - "human skin", - "infected leaf", - "inflorescence", - "intestinal mucosa", - "intestine", - "intestines", - "kidney", - "kimchi", - "lake", - "lake sediment", - "lake soil", - "lake water", - "leaf", - "leaves", - "lentil", - "liver", - "liver abscess", - "lung", - "lymph node", - "lymphocyte", - "maize", - "mammary gland", - "mangrove sediment", - "mangrove sediments", - "manure", - "marine environment", - "marine sediment", - "marine sediments", - "marine water", - "mature leaf", - "meat", - "midgut", - "milk", - "mitral valve", - "mouth wound", - "mucosa", - "mucus", - "muscle", - "muscle tissue", - "mycelium", - "nasal mucosa", - "nasal sample", - "nasal samples", - "nasal swab", - "nasopharyngeal aspirate", - "nasopharyngeal swab", - "nasopharynx", - "nest", - "neuroblast", - "nodule", - "nodules", - "nose swab", - "olfactory mucosa", - "oral fluid", - "oral lexion", - "oral mucosa", - "ovary", - "oviduct", - "paddy soil", - "parietal cortex", - "patient", - "pericardial", - "pharnyx", - "placenta", - "plasma", - "pleopod", - "pleopods", - "pleura", - "pod", - "purulent fluid", - "respiratory tract", - "rhizosphere", - "rhizosphere soil", - "rice rhizosphere", - "rice soil", - "river sediment", - "river sediments", - "river water", - "root", - "root nodule", - "root nodules", - "root tip", - "root tips", - "roots", - "rumen", - "saliva", - "salivary gland", - "saltern soil", - "seafood", - "seawater", - "sediment", - "sediments", - "seedling", - "seedling roots", - "sera", - "serum", - "sesame seeds", - "shrimp pond", - "skeletal muscle", - "skin", - "skin lesion", - "sludge", - "soil", - "spindle leaf", - "spleen", - "sputum", - "stem", - "stem base", - "stems", - "stomach", - "stool", - "stool sample", - "stool samples", - "strawberry", - "swab", - "swamp soil", - "tail", - "tentacle", - "testes", - "testis", - "textile wastewater", - "throat", - "throat swab", - "throat wash", - "thymus", - "trachea", - "tracheal aspirate", - "tracheal swab", - "turfgrass", - "urine", - "uterine mucosa", - "wastewater", - "water", - "white clover", - "whole blood", - "whole cell/tissue lysate", - "wound", - "yogurt", -}; +static TQualFixMap s_IsolationSourceMap; +static bool s_QualFixupMapsInitialized = false; - -const char * sm_KnownIsolationSourceWords[] = { - "adductor muscle", - "aquaculture water", - "bile", - "bitumen", - "bone marrow", - "brain biopsy", - "buffy coat", - "cabbage leaves", - "catfish", - "Channel catfish", - "compost soil", - "crown", - "curd sample", - "dairy farm soil", - "farm soil", - "field soil", - "fish intestine", - "freshwater", - "fruit body", - "groundwater", - "hepatic bile duct", - "hepatic biliary duct", - "hot marine salterns", - "human skin", - "lake isolate", - "lake mud", - "mangrove soil", - "midgut", - "pond sediment", - "pond water", - "poultry farm soil", - "river sand", - "saline lake", - "sewage sludge", - "soda lake", - "soil rhizosphere", - "soil sample", - "solar saltern", - "solar salterns", - "sulphur spring", - "surface water", - "tannery waste", - "tannery waste effluent", - "tissue biopsy", - "twig", - "underground water", - "vegetable", - "vegetables", -}; +static void s_ProcessQualMapLine(const CTempString& line, TQualFixMap& qual_map) +{ + vector tokens; + NStr::Split(line, "\t", tokens, NStr::fSplit_NoMergeDelims); + if (tokens.size() > 1) { + qual_map[tokens[0]] = tokens[1]; + } +} -string CSubSource::FixIsolationSourceCapitalization(const string& value) +void s_AddOneDataFile(const string& file_name, const string& data_name, + const char **built_in, size_t num_built_in, + TQualFixMap& qual_map) { - string fix = value; + string file = g_FindDataFile(file_name); + CRef lr; + if (!file.empty()) { + try { + lr = ILineReader::New(file); + } NCBI_CATCH("s_InitializeQualMaps") + } - size_t max = sizeof(sm_KnownIsolationSourceWords) / sizeof(const char*); - for (size_t i = 0; i < max; i++) { - if (NStr::EqualNocase(fix, sm_KnownIsolationSourceWords[i])) { - fix = sm_KnownIsolationSourceWords[i]; - break; + if (lr.Empty()) { + if (built_in == NULL) { + ERR_POST(Note << "No data for " + data_name); + } else { + ERR_POST(Note << "Falling back on built-in data for " + data_name); + for (size_t i = 0; i < num_built_in; i++) { + const char *p = built_in[i]; + s_ProcessQualMapLine(p, qual_map); + } } + } else { + ERR_POST(Note << "Reading from " + file + " for " + data_name); + do { + s_ProcessQualMapLine(*++*lr, qual_map); + } while (!lr->AtEOF()); } +} - max = sizeof(sm_KnownIsolationAndTissueTypeWords) / sizeof(const char*); - for (size_t i = 0; i < max; i++) { - if (NStr::EqualNocase(fix, sm_KnownIsolationAndTissueTypeWords[i])) { - fix = sm_KnownIsolationAndTissueTypeWords[i]; - break; - } +#include "isolation_sources.inc" + +static void s_InitializeQualMaps(void) +{ + CFastMutexGuard GUARD(s_QualFixMutex); + if (s_QualFixupMapsInitialized) { + return; + } + + // tissue types + s_AddOneDataFile("isolation_sources.txt", "isolation sources", (const char **)k_isolation_sources, sizeof(k_isolation_sources) / sizeof(char *), s_IsolationSourceMap); + s_QualFixupMapsInitialized = true; +} + + + + + +string CSubSource::FixIsolationSourceCapitalization(const string& value) +{ + string fix = value; + + s_InitializeQualMaps(); + + TQualFixMap::iterator it = s_IsolationSourceMap.find(value); + if (it != s_IsolationSourceMap.end()) { + return it->second; } - max = sizeof(sm_ValidSexQualifierTokens) / sizeof(const char*); + size_t max = sizeof(sm_ValidSexQualifierTokens) / sizeof(const char*); for (size_t i = 0; i < max; i++) { if (NStr::EqualNocase(fix, sm_ValidSexQualifierTokens[i])) { fix = sm_ValidSexQualifierTokens[i]; @@ -4102,15 +3996,14 @@ string CSubSource::FixTissueTypeCapitalization(const string& value) { string fix = value; - size_t max = sizeof(sm_KnownIsolationAndTissueTypeWords) / sizeof(const char*); - for (size_t i = 0; i < max; i++) { - if (NStr::EqualNocase(fix, sm_KnownIsolationAndTissueTypeWords[i])) { - fix = sm_KnownIsolationAndTissueTypeWords[i]; - break; - } + s_InitializeQualMaps(); + TQualFixMap::iterator it = s_IsolationSourceMap.find(value); + if (it != s_IsolationSourceMap.end()) { + return it->second; } - max = sizeof(sm_ValidSexQualifierTokens) / sizeof(const char*); + + size_t max = sizeof(sm_ValidSexQualifierTokens) / sizeof(const char*); for (size_t i = 0; i < max; i++) { if (NStr::EqualNocase(fix, sm_ValidSexQualifierTokens[i])) { fix = sm_ValidSexQualifierTokens[i]; @@ -4649,6 +4542,7 @@ static const size_t k_NumLatLonWaterText = ArraySize(s_DefaultLatLonWaterText); void CLatLonCountryMap::x_InitFromDefaultList(const char * const *list, int num) { + ERR_POST(Note << "Falling back on built-in data for latlon / water data."); // initialize list of country lines m_CountryLineList.clear(); m_Scale = 20.0; @@ -4684,7 +4578,7 @@ bool CLatLonCountryMap::x_InitFromFile(const string& filename) if (NStr::IsBlank (fname)) { return false; } - + ERR_POST(Note << "Reading from " + filename + " for latlon/water data."); CRef lr = ILineReader::New (fname); if (lr.Empty()) { return false; diff --git a/c++/src/objects/seqfeat/Trna_ext.cpp b/c++/src/objects/seqfeat/Trna_ext.cpp index 7c130da5..bb761c8a 100644 --- a/c++/src/objects/seqfeat/Trna_ext.cpp +++ b/c++/src/objects/seqfeat/Trna_ext.cpp @@ -1,4 +1,4 @@ -/* $Id: Trna_ext.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: Trna_ext.cpp 513588 2016-09-13 13:46:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seqfeat/Variation_ref.cpp b/c++/src/objects/seqfeat/Variation_ref.cpp index 7ee67a16..90f6ea10 100644 --- a/c++/src/objects/seqfeat/Variation_ref.cpp +++ b/c++/src/objects/seqfeat/Variation_ref.cpp @@ -1,4 +1,4 @@ -/* $Id: Variation_ref.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: Variation_ref.cpp 513588 2016-09-13 13:46:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seqfeat/cell_line.inc b/c++/src/objects/seqfeat/cell_line.inc index d25336d4..884088ea 100644 --- a/c++/src/objects/seqfeat/cell_line.inc +++ b/c++/src/objects/seqfeat/cell_line.inc @@ -1,4 +1,4 @@ -/* $Id: cell_line.inc 458797 2015-02-10 15:36:36Z bollin $ +/* $Id: cell_line.inc 530081 2017-03-10 18:09:40Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,479 +31,502 @@ */ static const char* const kCellLine[] = { - "222 Homo sapiens PA1 Human", - "2474/90 Homo sapiens HT-29 Human", - "2563 (MAC-21) Homo sapiens HeLa Human", - "2957/90 Homo sapiens HT-29 Human", - "3051/80 Homo sapiens HT-29 Human", - "41M Homo sapiens OAW 28 Human", - "A2008 Homo sapiens ME-180 Human", - "ACC2 Homo sapiens HeLa Human", - "ACC3 Homo sapiens HeLa Human", - "ACCM Homo sapiens HeLa Human", - "ACCNS Homo sapiens Unknown Mouse", - "ACCS Homo sapiens T-24 Human", - "ADLC-5M2 Homo sapiens HeLa Human", - "Aedes aegypti, Suitor's clone Mosquito Unknown Moth, Antheraea eucalypti", - "Aedes vexans culture Mosquito Unknown Moth, Antheraea eucalypti", - "AG-F Homo sapiens CCRF-CEM Human", - "AKI Homo sapiens HeLa Human", - "ALVA-31 Homo sapiens PC-3 Human", - "ALVA-41 Homo sapiens PC-3 Human", - "ALVA-55 Homo sapiens PC-3 Human", - "ALVA-101 Homo sapiens PC-3 Human", - "AMDURII Homo sapiens LLC-PK1 Pig, Sus scrofa", - "AO Homo sapiens HeLa Human", - "ARO Homo sapiens HT-29 Human", - "ARO81-1 Homo sapiens HT-29 Human", - "AV3 Homo sapiens HeLa Human", - "AZ521 Homo sapiens HuTu 80 Human", - "B2-17 Homo sapiens U-251 MG Human", - "BCC1/KMC Homo sapiens HeLa Human", - "BE-13 Homo sapiens PEER Human", - "BG-1 Homo sapiens MCF-7 Human", - "BHP 10-3 Homo sapiens TPC-1 Human", - "BHP 14-9 Homo sapiens M14 Human", - "BHP 17-10 Homo sapiens M14 Human", - "BHP 2-7 Homo sapiens TPC-1 Human", - "BHP 5-16 Homo sapiens M14 Human", - "BHP 7-13 Homo sapiens TPC-1 Human", - "BIC-1 Homo sapiens SW-480, SW-620 Human", - "BLIN-1 (also subclone 1E8) Homo sapiens NALM-6 Human", - "BM-1604 Homo sapiens DU-145 Human", - "BrCA 5 Homo sapiens HeLa Human", - "BSCC-93 Homo sapiens DJM-1 Human", - "BT-B Homo sapiens HeLa Human", - "C13 Homo sapiens ME-180 Human", - "C16 (MRC-5 derivative) Homo sapiens HeLa Human", - "C-433 Homo sapiens RD-ES Human", - "CAC2 Homo sapiens Unknown Rat", - "CaMa (clone 15) Homo sapiens Unknown Syrian hamster and mouse", - "CaOV Homo sapiens HeLa Human", - "Caov-2 Homo sapiens NIH:OVCAR-2 Human", - "CaVe Homo sapiens HeLa Human", - "CCL3 Homo sapiens Unknown Mouse", - "CH1, CH1cisR Homo sapiens PA1 Human", - "Chang liver Homo sapiens HeLa Human", - "CHB Homo sapiens Unknown Rat", - "CHP-100 Homo sapiens IMR-32 Human", - "CHP-234 Homo sapiens Unknown Human", - "Clom 15 Homo sapiens Unknown Rat", - "Clone 1-5c-4 Homo sapiens HeLa Human", - "Clone-16 Homo sapiens Unknown Syrian hamster", - "Clone 1A Oncorhynchus mykiss CHSE-214 Chinook salmon, Oncorhynchus tschawytscha", - "CMP Homo sapiens HeLa Human", - "CMPII C2 Homo sapiens HeLa Human", - "CNDT2 Homo sapiens Unknown Human", - "CO (= COLE) Homo sapiens CCRF-CEM Human", - "COLO-587 Homo sapiens COLO-320DM Human", - "COLO-677 Homo sapiens RPMI-8226 Human", - "COLO-818 Homo sapiens COLO-800 Human", - "CoLo-TC Homo sapiens COLO-205 Human", - "Culisita inornata culture Mosquito Unknown Moth, Antheraea eucalypti", - "D18T Homo sapiens HeLa Human", - "D98/AH Homo sapiens HeLa Human", - "D98/AH2 Clone B Homo sapiens HeLa Human", - "DAMI Homo sapiens HEL Human", - "DAPT Homo sapiens HeLa Human", - "DD Homo sapiens K-562 Human", - "Det30A Homo sapiens HeLa Human", - "Detroit-6 (Det6) Homo sapiens HeLa Human", - "Detroit-98 Homo sapiens HeLa Human", - "Detroit 98/AG Homo sapiens HeLa Human", - "Detroit 98/AH-2 Homo sapiens HeLa Human", - "Detroit 98/AH-R Homo sapiens HeLa Human", - "Detroit 98s Homo sapiens HeLa Human", - "DM12 (Tu-167 derivative) Homo sapiens UM-SCC-1 Human", - "DM14 (Tu-167 derivative) Homo sapiens UM-SCC-1 Human", - "DRO Homo sapiens A-375 Human", - "DRO90-1 Homo sapiens A-375 Human", - "DuPro-1 Homo sapiens PC-3 Human", - "EB33 Homo sapiens HeLa Human", - "ECC-1 Homo sapiens Ishikawa Human", - "ECTC Bos taurus Vero Monkey, African green (Cercopithecus aethiops)", - "ECV-304 Homo sapiens T-24 Human", - "ED27 Homo sapiens HeLa Human", - "EEK Equus caballus NSK Pig, Sus scrofa", - "EH Homo sapiens HK Human", - "EJ-1 Homo sapiens T-24 Human", - "Ej138 Homo sapiens T-24 Human", - "ElCo Homo sapiens HeLa Human", - "EPC Cyprinus carpio Unknown Fathead minnow, Pimephales promelas", - "EPLC3-2M1 Homo sapiens HeLa Human", - "EPLC-65 Homo sapiens HeLa Human", - "ESP1 Homo sapiens HeLa Human", - "ETK-1 Homo sapiens SSP-25 Human", - "EU-1 Homo sapiens REH Human", - "EU-7 Homo sapiens CCRF-CEM Human", - "EUE Homo sapiens HeLa Human", - "EVLC2 Homo sapiens Unknown Human", - "F2-4E5 Homo sapiens SK-HEP-1 Human", - "F2-5B6 Homo sapiens SK-HEP-1 Human", - "F255A4 Homo sapiens HeLa Human", - "FB2 Homo sapiens TPC-1 Human", - "Fitz-HSA Canis lupus familiaris DEN-HSA Dog, Canis familiaris", - "FL Homo sapiens HeLa Human", - "Flow 13000 Homo sapiens MRC-5 Human", - "Flow 5000 Homo sapiens Flow 1000 Human", - "Flow 6000 Homo sapiens Flow 1000 Human", - "Flow 7000 Homo sapiens Flow 3000 Human", - "FQ Homo sapiens OMK-210 Monkey, Owl (Aotus trivirgatus)", - "G-11 (HBT-3 derivative) Homo sapiens HeLa Human", - "GHE Homo sapiens T-24 Human", - "Girardi heart Homo sapiens HeLa Human", - "GM1312 Homo sapiens Correct name, incorrect cell type Human", - "GOS-3 Homo sapiens U-343 MG Human", - "GPS-M Cavia porcellus Strain L-M Mouse", - "GPS-PD Cavia porcellus Strain L-M Mouse", - "GREF-X Homo sapiens Unknown Rat", - "GT3TKB Homo sapiens RERF-LC-A1 Human", - "H249 Homo sapiens H69 Human", - "H-494 Homo sapiens HeLa Human", - "H7D7A and derivatives Homo sapiens HepG2 Human", - "H7D7B and derivatives Homo sapiens HepG2 Human", - "H7D7C and derivatives Homo sapiens HepG2 Human", - "H7D7D and derivatives Homo sapiens HepG2 Human", - "HAG Homo sapiens T-24 Human", - "HBC Homo sapiens Unknown Rat", - "HBL-100 Homo sapiens Unknown Human", - "HBT-3 Homo sapiens HeLa Human", - "HBT-39b Homo sapiens HeLa Human", - "HBT-E (HBT-3 clone) Homo sapiens HeLa Human", - "HCE Homo sapiens HeLa Human", - "HCu-10 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human", - "HCu-18 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human", - "HCu-22 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human", - "HCu-27 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human", - "HCu-33 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human", - "HCu-37 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human", - "HCu-39 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human", - "HCV-29Tmv (HCV-29 derivative) Homo sapiens T-24 Human", - "HEC-155 Homo sapiens HEC-180 Human", - "HEC-180 Homo sapiens HEC-155 Human", - "HEK Homo sapiens HeLa Human", - "HEK/HRV (HEK derivative) Homo sapiens HeLa Human", - "HEL-R66 Homo sapiens Unknown Monkey, African green (Cercopithecus aethiops)", - "HEp-2 (H.Ep.-2) Homo sapiens HeLa Human", - "Hep-2C Homo sapiens HeLa Human", - "Hep2 (Clone 2B) Homo sapiens HeLa Human", - "HES Homo sapiens HeLa Human", - "HIMEG-1 Homo sapiens HL-60 Human", - "HKB-1 Homo sapiens Unknown Human", - "HKMUS Homo sapiens SKG-II-SF Human", - "HKMUS-SF Homo sapiens SKG-II-SF Human", - "HL111783 Homo sapiens HeLa Human", - "HMV-1 Homo sapiens HeLa Human", - "HPB-MLT Homo sapiens HPB-ALL Human", - "HPC-36M (HPC-36 derivative) Homo sapiens HeLa Human", - "hPTC Homo sapiens Unknown Pig, Sus scrofa", - "Hs 677.St Homo sapiens Unknown Mouse", - "HSC-41 Homo sapiens HSC-42 Human", - "HSG Homo sapiens HeLa Human", - "HSG-AZA1 Homo sapiens HeLa Human", - "HSG-AZA3 Homo sapiens HeLa Human", - "HSGc-C5 Homo sapiens HeLa Human", - "HS-SULTAN Homo sapiens JIJOYE Human", - "HSY Homo sapiens HeLa Human", - "hTERT-EEC Homo sapiens MCF-7 Human", - "Hu1734 Homo sapiens HCV-29 Human", - "Hu456 Homo sapiens T-24 Human", - "Hu549 Homo sapiens T-24 Human", - "Hu609 Homo sapiens J82 Human", - "Hu609Tmv (Hu609 derivative) Homo sapiens T-24 Human", - "Hu961a, Hu961t (Hu961 derivatives) Homo sapiens T-24 Human", - "HuKo39 Homo sapiens HeLa Human", - "HuL-1 Homo sapiens HeLa Human", - "Hut Homo sapiens HeLa Human", - "IMC-2 Homo sapiens HeLa Human", - "IMC-3 Homo sapiens HeLa Human", - "IMC-4 Homo sapiens HeLa Human", - "Intestine 407 (Int-407, HEI) Homo sapiens HeLa Human", - "IPDDC-A2 Homo sapiens Unknown Rat", - "IPRB Homo sapiens Unknown Rat", - "IPTP/98 Homo sapiens Unknown Rat", - "IST-1 Homo sapiens SK-OV-3 Human", - "J-111 Homo sapiens HeLa Human", - "J96 Homo sapiens HeLa Human", - "JCA-1 Homo sapiens T-24 Human", - "JHC Homo sapiens HeLa Human", - "JHU012 Homo sapiens JHU022 Human", - "JHU013 (JHU012 derivative) Homo sapiens FaDu Human", - "JHU019 Homo sapiens PC-3 Human", - "JHU028 Homo sapiens A549 Human", - "JHT (JHC derivative) Homo sapiens HeLa Human", - "JMAR (Tu-167 derivative) Homo sapiens UM-SCC-1 Human", - "JOSK-I Homo sapiens U-937 Human", - "JOSK-K Homo sapiens U-937 Human", - "JOSK-M Homo sapiens U-937 Human", - "JOSK-S Homo sapiens U-937 Human", - "JTC-17 Homo sapiens HeLa Human", - "JTC-3 Homo sapiens HeLa Human", - "K051 Homo sapiens K-562 Human", - "K1 Homo sapiens GLAG-66 Human", - "K2 Homo sapiens GLAG-66 Human", - "KAK1 Homo sapiens HT-29 Human", - "KAT10 Homo sapiens HT-29 Human", - "KAT4 Homo sapiens HT-29 Human", - "KAT5 Homo sapiens HT-29 Human", - "KAT50 Homo sapiens HT-29 Human", - "KAT7 Homo sapiens HT-29 Human", - "KB Homo sapiens HeLa Human", - "KB-3-1 Homo sapiens HeLa Human", - "KB-V1 Homo sapiens HeLa Human", - "KCI-MOH1 Homo sapiens HPAC Human", - "KM-3 Homo sapiens REH Human", - "KM3 Homo sapiens Unknown Rat", - "KMS-21-BM Homo sapiens Unknown Human", - "KMT-2 Homo sapiens KG-1 Human", - "KNS-89 Homo sapiens U-251 MG Human", - "KOSC-3 Homo sapiens Ca9-22 Human", - "KP-1N Homo sapiens PANC-1 Human", - "KPB-M15 Homo sapiens KYO-1 Human", - "KPL-1 Homo sapiens MCF-7 Human", - "KP-P1 Homo sapiens HeLa Human", - "KSY-1 Homo sapiens T-24 Human", - "KU7 Homo sapiens HeLa Human", - "KU-YS Homo sapiens KU-SN Human", - "L-132 Homo sapiens HeLa Human", - "L-41 (J96 derivative) Homo sapiens HeLa Human", - "LED-Ti Homo sapiens HeLa Human", - "LLC-15MB Homo sapiens M14 Human", - "LN-319 Homo sapiens LN-992 Human", - "LN-443 Homo sapiens LN-444 Human", - "LR10.6 Homo sapiens NALM-6 Human", - "LT-1 Frog, grass TH and FHM TH = box turtle; FHM = fathead minnow", - "LU Homo sapiens HeLa Human", - "LU 106 Homo sapiens HeLa Human", - "Lu-130 Homo sapiens Lu-134A, B Human", - "M10T Homo sapiens HeLa Human", - "M4A4 and derivatives (MDA-MB-435 derivatives) Homo sapiens M14 Human", - "MA-1 Homo sapiens Pfeiffer Human", - "MA-104 Macaca mulatta Vero? Monkey, African green (Cercopithecus aethiops)", - "MA-111 Oryctolagus cuniculus Vero? Monkey, African green (Cercopithecus aethiops)", - "MA-160 Homo sapiens HeLa Human", - "Mash-1 Homo sapiens MMac Human", - "MaTu Homo sapiens HeLa Human", - "MC-4000 Homo sapiens HeLa Human", - "McCoy Homo sapiens Strain L Mouse", - "MCF-7/AdrR (NCI/ADR-RES) Homo sapiens OVCAR-8 Human", - "MDA-MB-435 Homo sapiens M14 Human", - "MDA-N (MDA-MB-435 derivative) Homo sapiens M14 Human", - "MDS Homo sapiens JURKAT Human", - "MEL-HO Homo sapiens Unknown, does not match other cell line from same donor Human", - "ME-WEI Homo sapiens Unknown, does not match other cell line from same donor Human", - "MGH-U1 (EJ) Homo sapiens T-24 Human", - "MGH-U2 (HM) Homo sapiens T-24 Human", - "MHH-225 Homo sapiens JURKAT Human", - "Minnesota EE Homo sapiens HeLa Human", - "MKB-1 Homo sapiens CCRF-CEM Human", - "MKN28 Homo sapiens MKN74 Human", - "MOBS-1 Homo sapiens U-937 Human", - "MOLT-15 Homo sapiens CTV-1 Human", - "MPanc-96 Homo sapiens AsPC-1 Human", - "MRO87-1 Homo sapiens HT-29 Human", - "MS (Monkey Stable) Monkey HeLa Human", - "MT-1 Homo sapiens HeLa Human", - "MUTZ-1 Homo sapiens Namalwa Human", - "MV522 Homo sapiens HT-29 Human", - "NC-37 Homo sapiens Raji Human", - "NCC16 Homo sapiens PHK16-0b Human", - "NCI/ADR-RES (MCF-7/AdrR) Homo sapiens OVCAR-8 Human", - "NCI-H1264 Homo sapiens NCI-H157 Human", - "NCI-H1304 Homo sapiens NCI-H1870 Human", - "NCI-H1514 Homo sapiens Unknown Human", - "NCI-H157 Homo sapiens NCI-H1264 Human", - "NCI-H1622 Homo sapiens Unknown Human", - "NCI-H1870 Homo sapiens NCI-H1304 Human", - "NCI-H249 Homo sapiens NCI-H69 Human", - "NCI-H513 Homo sapiens NCI-H125 Human", - "NCI-H592 Homo sapiens NCI-H69 Human", - "NCI-H60 Homo sapiens NCI-N417 Human", - "NCI-H630 Homo sapiens Mixture Human", - "NCI-H738 Homo sapiens Unknown Human", - "NCOL-1 Homo sapiens LoVo Human", - "NCTC 2544 Homo sapiens HeLa Human", - "NCTC 3075 Homo sapiens HeLa Human", - "ND-1 Homo sapiens DU-145 Human", - "NM2C5 and derivatives (MDA-MB-435 derivatives) Homo sapiens M14 Human", - "NOI-90 Homo sapiens REH Human", - "NOSE06 Homo sapiens DOV-13 Human", - "NOSE07 Homo sapiens DOV-13 Human", - "NPA87 Homo sapiens M14 Human", - "NS-3 Homo sapiens COLO 201 Human", - "OCUM-6 Homo sapiens OCUM-11 Human", - "OE Homo sapiens HeLa Human", - "OF Homo sapiens HeLa Human", - "OLGA-PH-J/92 [OL-J/92] Orconectes limosus Unknown Unknown, similar to amoeba species", - "ONCO-DG-1 Homo sapiens OVCAR-3 Human", - "OS 187 Homo sapiens HCT-15 Human", - "OST Homo sapiens HeLa Human", - "OU-AML-1 Homo sapiens OCI/AML2 Human", - "OU-AML-2 Homo sapiens OCI/AML2 Human", - "OU-AML-3 Homo sapiens OCI/AML2 Human", - "OU-AML-4 Homo sapiens OCI/AML2 Human", - "OU-AML-5 Homo sapiens OCI/AML2 Human", - "OU-AML-6 Homo sapiens OCI/AML2 Human", - "OU-AML-7 Homo sapiens OCI/AML2 Human", - "OU-AML-8 Homo sapiens OCI/AML2 Human", - "OV-1063 Homo sapiens Unknown Human", - "OV2008, OV2008/C13 Homo sapiens ME-180 Human", - "Ovary1847 Homo sapiens NIH:OVCAR-8 Human", - "OVMIU Homo sapiens OVSAYO Human", - "P1-1A3 Homo sapiens SK-HEP-1 Human", - "P1-4D6 Homo sapiens SK-HEP-1 Human", - "P39/TSUGANE (P39/TSU) Homo sapiens HL-60 Human", - "PBEI Homo sapiens NALM-6 Human", - "PC-93 Homo sapiens HeLa Human", - "PC-MDS Homo sapiens K-562 Human", - "PCI-22A Homo sapiens Unknown, does not match other cell line from same donor Human", - "PCI-22B Homo sapiens Unknown, does not match other cell line from same donor Human", - "PCI-3 Homo sapiens PC-3 Human", - "PEAZ-1 Homo sapiens HT-1080 Human", - "PH61-N Homo sapiens MIA PaCa-2 Human", - "PLB-985 Homo sapiens HL-60 Human", - "PPC-1 Homo sapiens PC-3 Human", - "PSV811 Homo sapiens WI-38 Human", - "RAMAK-1 Homo sapiens T-24 Human", - "RB Homo sapiens OMK-210 Monkey, Owl (Aotus trivirgatus)", - "RBHF-1 Homo sapiens Unknown Non-human", - "RC-2A Homo sapiens CCRF-CEM Human", - "RED-3 Homo sapiens HL-60 Human", - "REH-6 Homo sapiens Unknown Mouse", - "REPC Homo sapiens Hep 3B Human", - "RERF-LC-MA Homo sapiens SK-MES-1 Human", - "RERF-LC-OK Homo sapiens Marcus Human", - "RGC-5 Rat 661W Mouse", - "RM-10 Homo sapiens K-562 Human", - "RMUG-L Homo sapiens SNG-II Human", - "RO-D81-1 Homo sapiens HT-29 Human", - "RO-H85-1 Homo sapiens 647-V Human", - "RPMI-4788 Homo sapiens HeLa Human", - "RPMI-6666 Homo sapiens Correct name, incorrect cell type Human", - "RPTC-1 Homo sapiens TPC-1 Human", - "RS-1 Homo sapiens K-562 Human", - "RTSG Homo sapiens SNG-II Human", - "RY Homo sapiens Unknown Monkey", - "SA4 Homo sapiens HeLa Human", - "SAM-1 Homo sapiens K-562 Human", - "SAML-1 Homo sapiens U-937 Human", - "SBC-2 Homo sapiens HeLa Human", - "SBC-7 Homo sapiens HeLa Human", - "SCCTF Homo sapiens SCCKN Human", - "SCLC-16H Homo sapiens SCLC-21/22H Human", - "SCLC-24H Homo sapiens SCLC-21/22H Human", - "SEG-1 Homo sapiens NCI-H460 Human", - "SF767 Homo sapiens ME-180 Human", - "SH-2 Homo sapiens HeLa Human", - "SH-3 Homo sapiens HeLa Human", - "SJPL Sus scrofa Unknown Monkey, African green (Cercopithecus aethiops)", - "SK-GT-5 Homo sapiens SK-GT-2 Human", - "SK-MG-1 Homo sapiens Marcus Human", - "SK-N-MC Homo sapiens Unknown Human", - "SK-OV-4 Homo sapiens C-33A Human", - "SK-OV-6 Homo sapiens C-33A Human", - "SKW-3 Homo sapiens KE-37 Human", - "SLK Homo sapiens Caki-1 Human", - "SNB-19 Homo sapiens U-251 MG Human", - "SPI-801 Homo sapiens K-562 Human", - "SPI-802 Homo sapiens K-562 Human", - "SpR Homo sapiens OMK-210 Monkey, Owl (Aotus trivirgatus)", - "SQ-5 Homo sapiens HeLa Human", - "SR-91 Homo sapiens AML-193 Human", - "SW-527 Homo sapiens SW-480, SW-620 Human", - "SW-598 Homo sapiens SW-480, SW-620 Human", - "SW-608 Homo sapiens SW-480, SW-620 Human", - "SW-613 Homo sapiens SW-480, SW-620 Human", - "SW-732 Homo sapiens SW-480, SW-620 Human", - "SW-733 Homo sapiens SW-480, SW-620 Human", - "T-1 Homo sapiens HeLa Human", - "T1 Homo sapiens HeLa Human", - "T-33 Homo sapiens K-562 Human", - "T404 Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human", - "T406 (oral SCC) **Different cell line exists with same name: T406 (glioblastoma)** Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human", - "T409 Homo sapiens UM-SCC-1 Human", - "T-9 (WI-38 derivative) Homo sapiens HeLa Human", - "TCO-1 Homo sapiens TCO-2 Human", - "TDL-1 Homo sapiens P3JHR-1 Human", - "TDL-2 Homo sapiens P3JHR-1 Human", - "TDL-3 Homo sapiens RPMI 1788 Human", - "TDL-4 Homo sapiens Raji Human", - "TE-12 Homo sapiens TE-2, TE-3, TE-12 or TE-13 (genetically identical) Human", - "TE-13 Homo sapiens TE-2, TE-3, TE-12 or TE-13 (genetically identical) Human", - "TE-2 Homo sapiens TE-2, TE-3, TE-12 or TE-13 (genetically identical) Human", - "TE-3 Homo sapiens TE-2, TE-3, TE-12 or TE-13 (genetically identical) Human", - "TE671 Homo sapiens RD Human", - "TE671 Subline No.2 Homo sapiens RD Human", - "TE-7 Homo sapiens TE-2, TE-3, TE-12 or TE-13 (genetically identical) Human", - "TEC61 Homo sapiens JEG3 Human", - "TK-1 Homo sapiens U-251 MG Human", - "TI-1 Homo sapiens K-562 Human", - "TMH-1 Homo sapiens IHH-4 Human", - "TMM Homo sapiens Correct name, incorrect cell type Human", - "TSU-Pr1 Homo sapiens T-24 Human", - "Tu-138 Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human", - "Tu-158LN Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human", - "Tu-159 Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human", - "Tu-167 Homo sapiens UM-SCC-1 Human", - "Tu-182 Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human", - "Tu-212 Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human", - "Tu-212LN Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human", - "TuWi Homo sapiens HeLa Human", - "U-118 MG Homo sapiens U-138 MG Human", - "UM-UC-2 Homo sapiens T-24 Human", - "UM-UC-3-GFP (UM-UC-3 derivative) Homo sapiens Unknown, NOT UM-UC-3 Human", - "UPES/C Homo sapiens Unknown Rat", - "UPHHJA Homo sapiens Unknown Rat", - "UTMB-460 Homo sapiens CCRF-CEM Human", - "VC312R Homo sapiens Unknown Mixed, human + mouse", - "VM-CUB-III Homo sapiens VM-CUB-I Human", - "WiDr Homo sapiens HT-29 Human", - "WISH Homo sapiens HeLa Human", - "WKD Homo sapiens HeLa Human", - "Wong-Kilbourne Homo sapiens HeLa Human", - "WRL 68 Homo sapiens HeLa Human", - "WSU-ALCL Homo sapiens CCRF-CEM Human", - "WSU-CLL Homo sapiens REH Human", - "YAA Homo sapiens U-937 Human", - "YAP Homo sapiens U-937 Human", - "YJ Homo sapiens HL-60 Human", - "YMB-1 Homo sapiens ZR-75-1 Human", - "YMB-1-E Homo sapiens ZR-75-1 Human", - "1483 Homo sapiens UM-SCC-1 Human", - "183 Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human", - "207 (EU-2) Homo sapiens REH and SUP-B2 Human", - "B10XI Gallus gallus Unknown Pig, Sus scrofa", - "B6 Gallus gallus Unknown Pig, Sus scrofa", - "BJA-B Homo sapiens HeLa Human", - "BT-20 Homo sapiens HeLa Human", - "Ca9-22 Homo sapiens MSK-922 Human", - "COLO-720E Homo sapiens COLO684, COLO685, COLO704 Human", - "D-17 Canis lupus familiaris Moresco Dog, Canis familiaris", - "EB-3 Homo sapiens Daudi Human", - "FU-RPNT-2 Homo sapiens FU-RPNT-1 Human", - "Grey Canis lupus familiaris Unknown Human", - "HPB-ALL Homo sapiens JURKAT Human", - "IPEC Sus scrofa Unknown Cow", - "J-82 Homo sapiens T-24 Human", - "JHH-1 Homo sapiens Unknown Mouse", - "KARPAS-45 Homo sapiens Unknown Human", - "KBM-3 Homo sapiens HL-60 Human", - "KE-37 Homo sapiens CCRF-CEM Human", - "L-540 Homo sapiens CCRF-CEM Human", - "MB-02 Homo sapiens HU-3 Human", - "MDA1986LN Homo sapiens UM-SCC-1 Human", - "MDA686LN Homo sapiens UM-SCC-1 Human", - "MDA686TU Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human", - "MKN-7 Homo sapiens Unknown Human", - "NCI-H929 Homo sapiens K-562 Human", - "Parks Canis lupus familiaris Unknown Human", - "RMG-II Homo sapiens RMG-I Human", - "RPMI-8402 Homo sapiens Unknown Human", - "RT4 Homo sapiens HeLa Human", - "T3M-12 Homo sapiens T3M-1 Human", - "U-373 MG Homo sapiens U-251 MG Human", - "U-937 Homo sapiens Unknown Human", - "UROtsa Homo sapiens T-24 Human", - "UT-7 Homo sapiens U-937 Human", - "Yamada Canis lupus familiaris Unknown Mouse" + "1483\tHomo sapiens\tUM-SCC-1\tHuman", + "183\tHomo sapiens\tT404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical)\tHuman", + "1E8\tHomo sapiens\tNALM-6\tHomo sapiens\t", + "2008/C13*5.25\tHomo sapiens\tME-180\tHomo sapiens", + "207 (EU-2)\tHomo sapiens\tREH and SUP-B2\tHuman", + "222\tHomo sapiens\tPA1\tHuman", + "2474/90\tHomo sapiens\tHT-29\tHuman", + "2563 (MAC-21)\tHomo sapiens\tHeLa\tHuman", + "2957/90\tHomo sapiens\tHT-29\tHuman", + "3051/80\tHomo sapiens\tHT-29\tHuman", + "41M\tHomo sapiens\tOAW 28\tHuman", + "A172TR3\tHomo sapiens\tU-251 MG\tHomo sapiens\t", + "A2008\tHomo sapiens\tME-180\tHuman", + "ACC2\tHomo sapiens\tHeLa\tHuman", + "ACC3\tHomo sapiens\tHeLa\tHuman", + "ACCM\tHomo sapiens\tHeLa\tHuman", + "ACCNS\tHomo sapiens\tUnknown\tMouse", + "ACCS\tHomo sapiens\tT-24\tHuman", + "ADLC-5M2\tHomo sapiens\tHeLa\tHuman", + "AG-F\tHomo sapiens\tCCRF-CEM\tHuman", + "AKI\tHomo sapiens\tHeLa\tHuman", + "ALVA-101\tHomo sapiens\tPC-3\tHuman", + "ALVA-31\tHomo sapiens\tPC-3\tHuman", + "ALVA-41\tHomo sapiens\tPC-3\tHuman", + "ALVA-55\tHomo sapiens\tPC-3\tHuman", + "AMDURII\tHomo sapiens\tLLC-PK1\tPig, Sus scrofa", + "AO\tHomo sapiens\tHeLa\tHuman", + "ARO\tHomo sapiens\tHT-29\tHuman", + "ARO81-1\tHomo sapiens\tHT-29\tHuman", + "AV3\tHomo sapiens\tHeLa\tHuman", + "AZ521\tHomo sapiens\tHuTu 80\tHuman", + "Aedes aegypti, Suitor's clone\tMosquito\tUnknown\tMoth, Antheraea eucalypti", + "Aedes vexans culture\tMosquito\tUnknown\tMoth, Antheraea eucalypti", + "Ao38\tAscalapha odorata \tunknown\tTrichoplusia ni\t", + "B10XI\tGallus gallus\tUnknown\tPig, Sus scrofa", + "B2-17\tHomo sapiens\tU-251 MG\tHuman", + "B6\tGallus gallus\tUnknown\tPig, Sus scrofa", + "BCC1/KMC\tHomo sapiens\tHeLa\tHuman", + "BE-13\tHomo sapiens\tPEER\tHuman", + "BG-1\tHomo sapiens\tMCF-7\tHuman", + "BHP 10-3\tHomo sapiens\tTPC-1\tHuman", + "BHP 14-9\tHomo sapiens\tM14\tHuman", + "BHP 17-10\tHomo sapiens\tM14\tHuman", + "BHP 2-7\tHomo sapiens\tTPC-1\tHuman", + "BHP 5-16\tHomo sapiens\tM14\tHuman", + "BHP 7-13\tHomo sapiens\tTPC-1\tHuman", + "BIC-1\tHomo sapiens\tSW-480, SW-620\tHuman", + "BJA-B\tHomo sapiens\tHeLa\tHuman", + "BLIN-1 (also subclone 1E8)\tHomo sapiens\tNALM-6\tHuman", + "BM-1604\tHomo sapiens\tDU-145\tHuman", + "BSCC-93\tHomo sapiens\tDJM-1\tHuman", + "BT-20\tHomo sapiens\tHeLa\tHuman", + "BT-B\tHomo sapiens\tHeLa\tHuman", + "BTI-Tnao38\tAscalapha odorata \tunknown\tTrichoplusia ni\t", + "BrCA 5\tHomo sapiens\tHeLa\tHuman", + "C-433\tHomo sapiens\tRD-ES\tHuman", + "C13\tHomo sapiens\tME-180\tHomo sapiens\t", + "C13\tHomo sapiens\tME-180\tHuman", + "C16 (MRC-5 derivative)\tHomo sapiens\tHeLa\tHuman", + "CAC2\tHomo sapiens\tUnknown\tRat", + "CCL3\tHomo sapiens\tUnknown\tMouse", + "CH1, CH1cisR\tHomo sapiens\tPA1\tHuman", + "CHB\tHomo sapiens\tUnknown\tRat", + "CHP-100\tHomo sapiens\tIMR-32\tHuman", + "CHP-234\tHomo sapiens\tUnknown\tHuman", + "CMP\tHomo sapiens\tHeLa\tHuman", + "CMPII C2\tHomo sapiens\tHeLa\tHuman", + "CNDT2\tHomo sapiens\tUnknown\tHuman", + "CNE-1\tHomo sapiens\tHeLa\tHomo sapiens\t", + "CNE-2\tHomo sapiens\tHeLa\tHomo sapiens\t", + "CO (= COLE)\tHomo sapiens\tCCRF-CEM\tHuman", + "COLO-587\tHomo sapiens\tCOLO-320DM\tHuman", + "COLO-677\tHomo sapiens\tRPMI-8226\tHuman", + "COLO-720E\tHomo sapiens\tCOLO684, COLO685, COLO704\tHuman", + "COLO-818\tHomo sapiens\tCOLO-800\tHuman", + "Ca9-22\tHomo sapiens\tMSK-922\tHuman", + "CaMa (clone 15)\tHomo sapiens\tUnknown\tSyrian hamster and mouse", + "CaOV\tHomo sapiens\tHeLa\tHuman", + "CaVe\tHomo sapiens\tHeLa\tHuman", + "Caov-2\tHomo sapiens\tNIH:OVCAR-2\tHuman", + "Chang liver\tHomo sapiens\tHeLa\tHuman", + "Clom 15\tHomo sapiens\tUnknown\tRat", + "Clone 1-5c-4\tHomo sapiens\tHeLa\tHuman", + "Clone 1A\tOncorhynchus mykiss\tCHSE-214\tChinook salmon, Oncorhynchus tschawytscha", + "Clone-16\tHomo sapiens\tUnknown\tSyrian hamster", + "CoLo-TC\tHomo sapiens\tCOLO-205\tHuman", + "Culisita inornata culture\tMosquito\tUnknown\tMoth, Antheraea eucalypti", + "D-17\tCanis lupus familiaris\tMoresco\tDog, Canis familiaris", + "D-54 MG\tHomo sapiens\tA-172\tHomo sapiens\t", + "D18T\tHomo sapiens\tHeLa\tHuman", + "D98/AH\tHomo sapiens\tHeLa\tHuman", + "D98/AH2 Clone B\tHomo sapiens\tHeLa\tHuman", + "DAMI\tHomo sapiens\tHEL\tHuman", + "DAPT\tHomo sapiens\tHeLa\tHuman", + "DD\tHomo sapiens\tK-562\tHuman", + "DM12 (Tu-167 derivative)\tHomo sapiens\tUM-SCC-1\tHuman", + "DM14 (Tu-167 derivative)\tHomo sapiens\tUM-SCC-1\tHuman", + "DRO\tHomo sapiens\tA-375\tHuman", + "DRO90-1\tHomo sapiens\tA-375\tHuman", + "Det30A\tHomo sapiens\tHeLa\tHuman", + "Detroit 98/AG\tHomo sapiens\tHeLa\tHuman", + "Detroit 98/AH-2\tHomo sapiens\tHeLa\tHuman", + "Detroit 98/AH-R\tHomo sapiens\tHeLa\tHuman", + "Detroit 98s\tHomo sapiens\tHeLa\tHuman", + "Detroit-6 (Det6)\tHomo sapiens\tHeLa\tHuman", + "Detroit-98\tHomo sapiens\tHeLa\tHuman", + "DuPro-1\tHomo sapiens\tPC-3\tHuman", + "EB-3\tHomo sapiens\tDaudi\tHuman", + "EB33\tHomo sapiens\tHeLa\tHuman", + "ECC-1\tHomo sapiens\tIshikawa\tHuman", + "ECTC\tBos taurus\tVero\tMonkey, African green (Cercopithecus aethiops)", + "ECV-304\tHomo sapiens\tT-24\tHuman", + "ED27\tHomo sapiens\tHeLa\tHuman", + "EEK\tEquus caballus\tNSK\tPig, Sus scrofa", + "EH\tHomo sapiens\tHK\tHuman", + "EJ-1\tHomo sapiens\tT-24\tHuman", + "EPC\tCyprinus carpio\tUnknown\tFathead minnow, Pimephales promelas", + "EPLC-65\tHomo sapiens\tHeLa\tHuman", + "EPLC3-2M1\tHomo sapiens\tHeLa\tHuman", + "ESP1\tHomo sapiens\tHeLa\tHuman", + "ETK-1\tHomo sapiens\tSSP-25\tHuman", + "EU-1\tHomo sapiens\tREH\tHuman", + "EU-7\tHomo sapiens\tCCRF-CEM\tHuman", + "EUE\tHomo sapiens\tHeLa\tHuman", + "EVLC2\tHomo sapiens\tUnknown\tHuman", + "Ej138\tHomo sapiens\tT-24\tHuman", + "ElCo\tHomo sapiens\tHeLa\tHuman", + "F2-4E5\tHomo sapiens\tSK-HEP-1\tHuman", + "F2-5B6\tHomo sapiens\tSK-HEP-1\tHuman", + "F255A4\tHomo sapiens\tHeLa\tHuman", + "FB2\tHomo sapiens\tTPC-1\tHuman", + "FL\tHomo sapiens\tHeLa\tHuman", + "FQ\tHomo sapiens\tOMK-210\tMonkey, Owl (Aotus trivirgatus)", + "FU-RPNT-2\tHomo sapiens\tFU-RPNT-1\tHuman", + "Fitz-HSA \tCanis lupus familiaris\tDEN-HSA \tDog, Canis familiaris", + "Flow 13000\tHomo sapiens\tMRC-5\tHuman", + "Flow 5000\tHomo sapiens\tFlow 1000\tHuman", + "Flow 6000\tHomo sapiens\tFlow 1000\tHuman", + "Flow 7000\tHomo sapiens\tFlow 3000\tHuman", + "G-11 (HBT-3 derivative)\tHomo sapiens\tHeLa\tHuman", + "GHE\tHomo sapiens\tT-24\tHuman", + "GM1312\tHomo sapiens\tCorrect name, incorrect cell type\tHuman", + "GOS-3\tHomo sapiens\tU-343 MG\tHuman", + "GPS-M\tCavia porcellus\tStrain L-M\tMouse", + "GPS-PD\tCavia porcellus\tStrain L-M\tMouse", + "GREF-X\tHomo sapiens\tUnknown\tRat", + "GT3TKB\tHomo sapiens\tRERF-LC-A1\tHuman", + "Girardi heart\tHomo sapiens\tHeLa\tHuman", + "Grey\tCanis lupus familiaris\tUnknown\tHuman", + "H-494\tHomo sapiens\tHeLa\tHuman", + "H249\tHomo sapiens\tH69\tHuman", + "H7D7A and derivatives\tHomo sapiens\tHepG2\tHuman", + "H7D7B and derivatives\tHomo sapiens\tHepG2\tHuman", + "H7D7C and derivatives\tHomo sapiens\tHepG2\tHuman", + "H7D7D and derivatives\tHomo sapiens\tHepG2\tHuman", + "HAC15\tHomo sapiens\tNCI-H295R\tHomo sapiens\t", + "HAG\tHomo sapiens\tT-24\tHuman", + "HBC\tHomo sapiens\tUnknown\tRat", + "HBL-100\tHomo sapiens\tUnknown\tHuman", + "HBT-3\tHomo sapiens\tHeLa\tHuman", + "HBT-39b\tHomo sapiens\tHeLa\tHuman", + "HBT-E (HBT-3 clone)\tHomo sapiens\tHeLa\tHuman", + "HCE\tHomo sapiens\tHeLa\tHuman", + "HCV-29Tmv (HCV-29 derivative)\tHomo sapiens\tT-24\tHuman", + "HCu-10\tHomo sapiens\tHcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical)\tHuman", + "HCu-18\tHomo sapiens\tHcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical)\tHuman", + "HCu-22\tHomo sapiens\tHcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical)\tHuman", + "HCu-27\tHomo sapiens\tHcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical)\tHuman", + "HCu-33\tHomo sapiens\tHcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical)\tHuman", + "HCu-37\tHomo sapiens\tHcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical)\tHuman", + "HCu-39\tHomo sapiens\tHcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical)\tHuman", + "HEC-155\tHomo sapiens\tHEC-180\tHuman", + "HEC-180\tHomo sapiens\tHEC-155\tHuman", + "HEK\tHomo sapiens\tHeLa\tHuman", + "HEK/HRV (HEK derivative)\tHomo sapiens\tHeLa\tHuman", + "HEL-R66\tHomo sapiens\tUnknown\tMonkey, African green (Cercopithecus aethiops)", + "HES\tHomo sapiens\tHeLa\tHuman", + "HEp-2 (H.Ep.-2)\tHomo sapiens\tHeLa\tHuman", + "HIMEG-1\tHomo sapiens\tHL-60\tHuman", + "HKB-1\tHomo sapiens\tUnknown\tHuman", + "HKMUS\tHomo sapiens\tSKG-II-SF\tHuman", + "HKMUS-SF\tHomo sapiens\tSKG-II-SF\tHuman", + "HL111783\tHomo sapiens\tHeLa\tHuman", + "HMV-1\tHomo sapiens\tHeLa\tHuman", + "HPB-ALL\tHomo sapiens\tJURKAT\tHuman", + "HPB-MLT\tHomo sapiens\tHPB-ALL\tHuman", + "HPC-36M (HPC-36 derivative)\tHomo sapiens\tHeLa\tHuman", + "HS-SULTAN\tHomo sapiens\tJIJOYE\tHuman", + "HSC-41\tHomo sapiens\tHSC-42\tHuman", + "HSG\tHomo sapiens\tHeLa\tHuman", + "HSG-AZA1\tHomo sapiens\tHeLa\tHuman", + "HSG-AZA3\tHomo sapiens\tHeLa\tHuman", + "HSGc-C5\tHomo sapiens\tHeLa\tHuman", + "HSY\tHomo sapiens\tHeLa\tHuman", + "Hep-2C\tHomo sapiens\tHeLa\tHuman", + "Hep2 (Clone 2B)\tHomo sapiens\tHeLa\tHuman", + "Hs 677.St\tHomo sapiens\tUnknown\tMouse", + "Hu1734\tHomo sapiens\tHCV-29\tHuman", + "Hu456\tHomo sapiens\tT-24\tHuman", + "Hu549\tHomo sapiens\tT-24\tHuman", + "Hu609\tHomo sapiens\tJ82\tHuman", + "Hu609Tmv (Hu609 derivative)\tHomo sapiens\tT-24\tHuman", + "Hu961a, Hu961t (Hu961 derivatives)\tHomo sapiens\tT-24\tHuman", + "HuKo39\tHomo sapiens\tHeLa\tHuman", + "HuL-1\tHomo sapiens\tHeLa\tHuman", + "Hut\tHomo sapiens\tHeLa\tHuman", + "IMC-2\tHomo sapiens\tHeLa\tHuman", + "IMC-3\tHomo sapiens\tHeLa\tHuman", + "IMC-4\tHomo sapiens\tHeLa\tHuman", + "IPDDC-A2\tHomo sapiens\tUnknown\tRat", + "IPEC\tSus scrofa\tUnknown\tCow", + "IPRB\tHomo sapiens\tUnknown\tRat", + "IPRI-OL-11\tOrgyia leucostigma\tIPRI-CF-124\tChoristoneura fumiferana\t", + "IPRI-OL-7\tOrgyia leucostigma\tIPRI-CF-124\tChoristoneura fumiferana\t", + "IPTP/98\tHomo sapiens\tUnknown\tRat", + "IST-1\tHomo sapiens\tSK-OV-3\tHuman", + "Intestine 407 (Int-407, HEI)\tHomo sapiens\tHeLa\tHuman", + "J-111\tHomo sapiens\tHeLa\tHuman", + "J-82\tHomo sapiens\tT-24\tHuman", + "J96\tHomo sapiens\tHeLa\tHuman", + "JCA-1\tHomo sapiens\tT-24\tHuman", + "JHC\tHomo sapiens\tHeLa\tHuman", + "JHH-1\tHomo sapiens\tUnknown\tMouse", + "JHT (JHC derivative)\tHomo sapiens\tHeLa\tHuman", + "JHU012\tHomo sapiens\tJHU022\tHuman", + "JHU013 (JHU012 derivative)\tHomo sapiens\tFaDu\tHuman", + "JHU019\tHomo sapiens\tPC-3\tHuman", + "JHU028\tHomo sapiens\tA549\tHuman", + "JMAR (Tu-167 derivative)\tHomo sapiens\tUM-SCC-1\tHuman", + "JOSK-I\tHomo sapiens\tU-937\tHuman", + "JOSK-K\tHomo sapiens\tU-937\tHuman", + "JOSK-M\tHomo sapiens\tU-937\tHuman", + "JOSK-S\tHomo sapiens\tU-937\tHuman", + "JTC-17\tHomo sapiens\tHeLa\tHuman", + "JTC-3\tHomo sapiens\tHeLa\tHuman", + "K051\tHomo sapiens\tK-562\tHuman", + "K1\tHomo sapiens\tGLAG-66\tHuman", + "K2\tHomo sapiens\tGLAG-66\tHuman", + "KAK1\tHomo sapiens\tHT-29\tHuman", + "KARPAS-45\tHomo sapiens\tUnknown\tHuman", + "KAT10\tHomo sapiens\tHT-29\tHuman", + "KAT4\tHomo sapiens\tHT-29\tHuman", + "KAT5\tHomo sapiens\tHT-29\tHuman", + "KAT50\tHomo sapiens\tHT-29\tHuman", + "KAT7\tHomo sapiens\tHT-29\tHuman", + "KB\tHomo sapiens\tHeLa\tHuman", + "KB-3-1\tHomo sapiens\tHeLa\tHuman", + "KB-V1\tHomo sapiens\tHeLa\tHuman", + "KBM-3\tHomo sapiens\tHL-60\tHuman", + "KCI-MOH1\tHomo sapiens\tHPAC\tHuman", + "KE-37\tHomo sapiens\tCCRF-CEM\tHuman", + "KM-3\tHomo sapiens\tREH\tHuman", + "KM20\tHomo sapiens\tHT-29\tHomo sapiens\t", + "KM20L2\tHomo sapiens\tHT-29\tHomo sapiens\t", + "KM3\tHomo sapiens\tUnknown\tRat", + "KMS-21-BM\tHomo sapiens\tUnknown\tHuman", + "KMT-2\tHomo sapiens\tKG-1\tHuman", + "KNS-89\tHomo sapiens\tU-251 MG\tHuman", + "KOSC-3\tHomo sapiens\tCa9-22\tHuman", + "KP-1N\tHomo sapiens\tPANC-1\tHuman", + "KP-P1\tHomo sapiens\tHeLa\tHuman", + "KPB-M15\tHomo sapiens\tKYO-1\tHuman", + "KPL-1\tHomo sapiens\tMCF-7\tHuman", + "KSY-1\tHomo sapiens\tT-24\tHuman", + "KU-YS\tHomo sapiens\tKU-SN\tHuman", + "KU7\tHomo sapiens\tHeLa\tHuman", + "L-132\tHomo sapiens\tHeLa\tHuman", + "L-41 (J96 derivative)\tHomo sapiens\tHeLa\tHuman", + "L-540\tHomo sapiens\tCCRF-CEM\tHuman", + "LC5\tHomo sapiens\tHeLa\tHomo sapiens\t", + "LC5-HIV\tHomo sapiens\tHeLa\tHomo sapiens\t", + "LED-Ti\tHomo sapiens\tHeLa\tHuman", + "LLC-15MB\tHomo sapiens\tM14\tHuman", + "LN-319\tHomo sapiens\tLN-992\tHuman", + "LN-443\tHomo sapiens\tLN-444\tHuman", + "LR10.6\tHomo sapiens\tNALM-6\tHuman", + "LT-1\tFrog, grass\tTH and FHM\tTH = box turtle; FHM = fathead minnow", + "LU\tHomo sapiens\tHeLa\tHuman", + "LU 106\tHomo sapiens\tHeLa\tHuman", + "Lu-130\tHomo sapiens\tLu-134A, B\tHuman", + "M10T\tHomo sapiens\tHeLa\tHuman", + "M4A4 and derivatives (MDA-MB-435 derivatives)\tHomo sapiens\tM14\tHuman", + "MA-1\tHomo sapiens\tPfeiffer\tHuman", + "MA-104\tMacaca mulatta\tVero?\tMonkey, African green (Cercopithecus aethiops)", + "MA-111\tOryctolagus cuniculus\tVero?\tMonkey, African green (Cercopithecus aethiops)", + "MA-160\tHomo sapiens\tHeLa\tHuman", + "MB-02\tHomo sapiens\tHU-3\tHuman", + "MC-4000\tHomo sapiens\tHeLa\tHuman", + "MCF-7/AdrR (NCI/ADR-RES)\tHomo sapiens\tOVCAR-8\tHuman", + "MDA-MB-435\tHomo sapiens\tM14\tHuman", + "MDA-N (MDA-MB-435 derivative)\tHomo sapiens\tM14\tHuman", + "MDA1986LN\tHomo sapiens\tUM-SCC-1\tHuman", + "MDA686LN\tHomo sapiens\tUM-SCC-1\tHuman", + "MDA686TU\tHomo sapiens\tT404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical)\tHuman", + "MDS\tHomo sapiens\tJURKAT\tHuman", + "ME-WEI\tHomo sapiens\tUnknown, does not match other cell line from same donor\tHuman", + "MEL-HO\tHomo sapiens\tUnknown, does not match other cell line from same donor\tHuman", + "MGH-U1 (EJ)\tHomo sapiens\tT-24\tHuman", + "MGH-U2 (HM)\tHomo sapiens\tT-24\tHuman", + "MHH-225\tHomo sapiens\tJURKAT\tHuman", + "MKB-1\tHomo sapiens\tCCRF-CEM\tHuman", + "MKN-7\tHomo sapiens\tUnknown\tHuman", + "MKN28\tHomo sapiens\tMKN74\tHuman", + "MOBS-1\tHomo sapiens\tU-937\tHuman", + "MOLT-15\tHomo sapiens\tCTV-1\tHuman", + "MPanc-96\tHomo sapiens\tAsPC-1\tHuman", + "MRO87-1\tHomo sapiens\tHT-29\tHuman", + "MS (Monkey Stable)\tMonkey\tHeLa\tHuman", + "MT-1\tHomo sapiens\tHeLa\tHuman", + "MT-3\tHomo sapiens\tLS-174T (LS-180 derivative)\tHomo sapiens\t", + "MUTZ-1\tHomo sapiens\tNamalwa\tHuman", + "MV522\tHomo sapiens\tHT-29\tHuman", + "MaTu\tHomo sapiens\tHeLa\tHuman", + "Mash-1\tHomo sapiens\tMMac\tHuman", + "McCoy\tHomo sapiens\tStrain L\tMouse", + "Minnesota EE\tHomo sapiens\tHeLa\tHuman", + "NC-37\tHomo sapiens\tRaji\tHuman", + "NCC16\tHomo sapiens\tPHK16-0b\tHuman", + "NCI-H1264\tHomo sapiens\tNCI-H157\tHuman", + "NCI-H1304\tHomo sapiens\tNCI-H1870\tHuman", + "NCI-H1514\tHomo sapiens\tUnknown\tHuman", + "NCI-H157\tHomo sapiens\tNCI-H1264\tHuman", + "NCI-H1622\tHomo sapiens\tUnknown\tHuman", + "NCI-H1870\tHomo sapiens\tNCI-H1304\tHuman", + "NCI-H249\tHomo sapiens\tNCI-H69\tHuman", + "NCI-H513\tHomo sapiens\tNCI-H125\tHuman", + "NCI-H592\tHomo sapiens\tNCI-H69\tHuman", + "NCI-H60\tHomo sapiens\tNCI-N417\tHuman", + "NCI-H630\tHomo sapiens\tMixture\tHuman", + "NCI-H738\tHomo sapiens\tUnknown\tHuman", + "NCI-H929\tHomo sapiens\tK-562\tHuman", + "NCI/ADR-RES (MCF-7/AdrR)\tHomo sapiens\tOVCAR-8\tHuman", + "NCOL-1\tHomo sapiens\tLoVo\tHuman", + "NCTC 2544\tHomo sapiens\tHeLa\tHuman", + "NCTC 3075\tHomo sapiens\tHeLa\tHuman", + "ND-1\tHomo sapiens\tDU-145\tHuman", + "NM2C5 and derivatives (MDA-MB-435 derivatives)\tHomo sapiens\tM14\tHuman", + "NOI-90\tHomo sapiens\tREH\tHuman", + "NOSE06\tHomo sapiens\tDOV-13\tHuman", + "NOSE07\tHomo sapiens\tDOV-13\tHuman", + "NPA87\tHomo sapiens\tM14\tHuman", + "NS-3\tHomo sapiens\tCOLO 201\tHuman", + "OCM-3\tHomo sapiens\tSK-MEL-28\tHomo sapiens\t", + "OCM-8\tHomo sapiens\tSK-MEL-28\tHomo sapiens\t", + "OCUM-6\tHomo sapiens\tOCUM-11\tHuman", + "OE\tHomo sapiens\tHeLa\tHuman", + "OF\tHomo sapiens\tHeLa\tHuman", + "OLGA-PH-J/92 [OL-J/92]\tOrconectes limosus\tUnknown\tUnknown, similar to amoeba species", + "ONCO-DG-1\tHomo sapiens\tOVCAR-3\tHuman", + "OS 187\tHomo sapiens\tHCT-15\tHuman", + "OST\tHomo sapiens\tHeLa\tHuman", + "OU-AML-1\tHomo sapiens\tOCI/AML2\tHuman", + "OU-AML-2\tHomo sapiens\tOCI/AML2\tHuman", + "OU-AML-3\tHomo sapiens\tOCI/AML2\tHuman", + "OU-AML-4\tHomo sapiens\tOCI/AML2\tHuman", + "OU-AML-5\tHomo sapiens\tOCI/AML2\tHuman", + "OU-AML-6\tHomo sapiens\tOCI/AML2\tHuman", + "OU-AML-7\tHomo sapiens\tOCI/AML2\tHuman", + "OU-AML-8\tHomo sapiens\tOCI/AML2\tHuman", + "OV-1063\tHomo sapiens\tUnknown\tHuman", + "OV2008, OV2008/C13\tHomo sapiens\tME-180\tHuman", + "OV2008/C13\tHomo sapiens\tME-180\tHomo sapiens\t", + "OVMIU\tHomo sapiens\tOVSAYO\tHuman", + "Ovary1847\tHomo sapiens\tNIH:OVCAR-8\tHuman", + "P1-1A3\tHomo sapiens\tSK-HEP-1\tHuman", + "P1-4D6\tHomo sapiens\tSK-HEP-1\tHuman", + "P39/TSUGANE (P39/TSU)\tHomo sapiens\tHL-60\tHuman", + "PBEI\tHomo sapiens\tNALM-6\tHuman", + "PC-93\tHomo sapiens\tHeLa\tHuman", + "PC-MDS\tHomo sapiens\tK-562\tHuman", + "PCI-22A\tHomo sapiens\tUnknown, does not match other cell line from same donor\tHuman", + "PCI-22B\tHomo sapiens\tUnknown, does not match other cell line from same donor\tHuman", + "PCI-3\tHomo sapiens\tPC-3\tHuman", + "PEAZ-1\tHomo sapiens\tHT-1080\tHuman", + "PH61-N\tHomo sapiens\tMIA PaCa-2\tHuman", + "PLB-985\tHomo sapiens\tHL-60\tHuman", + "PPC-1\tHomo sapiens\tPC-3\tHuman", + "PSV811\tHomo sapiens\tWI-38\tHuman", + "Panc 01.28\tHomo sapiens\tPanc 01.28, Panc 06.03\tHomo sapiens\t", + "Panc 06.03\tHomo sapiens\tPanc 01.28, Panc 06.03\tHomo sapiens\t", + "Parks\tCanis lupus familiaris\tUnknown\tHuman", + "RAMAK-1\tHomo sapiens\tT-24\tHuman", + "RB\tHomo sapiens\tOMK-210\tMonkey, Owl (Aotus trivirgatus)", + "RBHF-1\tHomo sapiens\tUnknown\tNon-human", + "RC-2A\tHomo sapiens\tCCRF-CEM\tHuman", + "RED-3\tHomo sapiens\tHL-60\tHuman", + "REH-6\tHomo sapiens\tUnknown\tMouse", + "REPC\tHomo sapiens\tHep 3B\tHuman", + "RERF-LC-MA\tHomo sapiens\tSK-MES-1\tHuman", + "RERF-LC-OK\tHomo sapiens\tMarcus\tHuman", + "RGC-5\tRat\t661W\tMouse", + "RM-10\tHomo sapiens\tK-562\tHuman", + "RMG-II\tHomo sapiens\tRMG-I\tHuman", + "RMUG-L\tHomo sapiens\tSNG-II\tHuman", + "RO-D81-1\tHomo sapiens\tHT-29\tHuman", + "RO-H85-1\tHomo sapiens\t647-V\tHuman", + "RPMI-4788\tHomo sapiens\tHeLa\tHuman", + "RPMI-6666\tHomo sapiens\tCorrect name, incorrect cell type\tHuman", + "RPMI-8402\tHomo sapiens\tUnknown\tHuman", + "RPTC-1\tHomo sapiens\tTPC-1\tHuman", + "RS-1\tHomo sapiens\tK-562\tHuman", + "RT4\tHomo sapiens\tHeLa\tHuman", + "RTSG\tHomo sapiens\tSNG-II\tHuman", + "RY\tHomo sapiens\tUnknown\tMonkey", + "SA4\tHomo sapiens\tHeLa\tHuman", + "SAM-1\tHomo sapiens\tK-562\tHuman", + "SAML-1\tHomo sapiens\tU-937\tHuman", + "SBC-2\tHomo sapiens\tHeLa\tHuman", + "SBC-7\tHomo sapiens\tHeLa\tHuman", + "SCCTF\tHomo sapiens\tSCCKN\tHuman", + "SCLC-16H\tHomo sapiens\tSCLC-21/22H\tHuman", + "SCLC-24H\tHomo sapiens\tSCLC-21/22H\tHuman", + "SEG-1\tHomo sapiens\tNCI-H460\tHuman", + "SF767\tHomo sapiens\tME-180\tHuman", + "SH-2\tHomo sapiens\tHeLa\tHuman", + "SH-3\tHomo sapiens\tHeLa\tHuman", + "SJPL\tSus scrofa\tUnknown\tMonkey, African green (Cercopithecus aethiops)", + "SK-GT-5\tHomo sapiens\tSK-GT-2\tHuman", + "SK-MG-1\tHomo sapiens\tMarcus\tHuman", + "SK-N-MC\tHomo sapiens\tUnknown\tHuman", + "SK-OV-4\tHomo sapiens\tC-33A\tHuman", + "SK-OV-6\tHomo sapiens\tC-33A\tHuman", + "SKW-3\tHomo sapiens\tKE-37\tHuman", + "SLK\tHomo sapiens\tCaki-1\tHuman", + "SNB-19\tHomo sapiens\tU-251 MG\tHuman", + "SPI-801\tHomo sapiens\tK-562\tHuman", + "SPI-802\tHomo sapiens\tK-562\tHuman", + "SQ-5\tHomo sapiens\tHeLa\tHuman", + "SR-91\tHomo sapiens\tAML-193\tHuman", + "SW-527\tHomo sapiens\tSW-480, SW-620\tHuman", + "SW-598\tHomo sapiens\tSW-480, SW-620\tHuman", + "SW-608\tHomo sapiens\tSW-480, SW-620\tHuman", + "SW-613\tHomo sapiens\tSW-480, SW-620\tHuman", + "SW-732\tHomo sapiens\tSW-480, SW-620\tHuman", + "SW-733\tHomo sapiens\tSW-480, SW-620\tHuman", + "SpR\tHomo sapiens\tOMK-210\tMonkey, Owl (Aotus trivirgatus)", + "T-1\tHomo sapiens\tHeLa\tHuman", + "T-33\tHomo sapiens\tK-562\tHuman", + "T-9 (WI-38 derivative)\tHomo sapiens\tHeLa\tHuman", + "T1\tHomo sapiens\tHeLa\tHuman", + "T3M-12\tHomo sapiens\tT3M-1\tHuman", + "T404\tHomo sapiens\tT404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical)\tHuman", + "T406 (oral SCC) **Different cell line exists with same name: T406 (glioblastoma)**\tHomo sapiens\tT404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical)\tHuman", + "T409\tHomo sapiens\tUM-SCC-1\tHuman", + "TCO-1\tHomo sapiens\tTCO-2\tHuman", + "TDL-1\tHomo sapiens\tP3JHR-1\tHuman", + "TDL-2\tHomo sapiens\tP3JHR-1\tHuman", + "TDL-3\tHomo sapiens\tRPMI 1788\tHuman", + "TDL-4\tHomo sapiens\tRaji\tHuman", + "TE-12\tHomo sapiens\tTE-2, TE-3, TE-12 or TE-13 (genetically identical)\tHuman", + "TE-13\tHomo sapiens\tTE-2, TE-3, TE-12 or TE-13 (genetically identical)\tHuman", + "TE-2\tHomo sapiens\tTE-2, TE-3, TE-12 or TE-13 (genetically identical)\tHuman", + "TE-3\tHomo sapiens\tTE-2, TE-3, TE-12 or TE-13 (genetically identical)\tHuman", + "TE-7\tHomo sapiens\tTE-2, TE-3, TE-12 or TE-13 (genetically identical)\tHuman", + "TE671\tHomo sapiens\tRD\tHuman", + "TE671 Subline No.2\tHomo sapiens\tRD\tHuman", + "TEC61\tHomo sapiens\tJEG3\tHuman", + "TI-1\tHomo sapiens\tK-562\tHuman", + "TK-1\tHomo sapiens\tU-251 MG\tHuman", + "TMH-1\tHomo sapiens\tIHH-4\tHuman", + "TMM\tHomo sapiens\tCorrect name, incorrect cell type\tHuman", + "TSU-Pr1\tHomo sapiens\tT-24\tHuman", + "Tu-138\tHomo sapiens\tT404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical)\tHuman", + "Tu-158LN\tHomo sapiens\tT404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical)\tHuman", + "Tu-159\tHomo sapiens\tT404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical)\tHuman", + "Tu-167\tHomo sapiens\tUM-SCC-1\tHuman", + "Tu-182\tHomo sapiens\tT404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical)\tHuman", + "Tu-212\tHomo sapiens\tT404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical)\tHuman", + "Tu-212LN\tHomo sapiens\tT404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical)\tHuman", + "TuWi\tHomo sapiens\tHeLa\tHuman", + "U-118 MG\tHomo sapiens\tU-138 MG\tHuman", + "U-373 MG\tHomo sapiens\tU-251 MG\tHuman", + "U-937\tHomo sapiens\tUnknown\tHuman", + "U251-TR3\tHomo sapiens\tU-251 MG\tHomo sapiens\t", + "UM-UC-2\tHomo sapiens\tT-24\tHuman", + "UM-UC-3-GFP (UM-UC-3 derivative)\tHomo sapiens\tUnknown, NOT UM-UC-3\tHuman", + "UPES/C\tHomo sapiens\tUnknown\tRat", + "UPHHJA\tHomo sapiens\tUnknown\tRat", + "UROtsa\tHomo sapiens\tT-24\tHuman", + "UT-7\tHomo sapiens\tU-937\tHuman", + "UTMB-460\tHomo sapiens\tCCRF-CEM\tHuman", + "VC312R\tHomo sapiens\tUnknown\tMixed, human + mouse", + "VM-CUB-III\tHomo sapiens\tVM-CUB-I\tHuman", + "WISH\tHomo sapiens\tHeLa\tHuman", + "WKD\tHomo sapiens\tHeLa\tHuman", + "WRL 68\tHomo sapiens\tHeLa\tHuman", + "WSU-ALCL\tHomo sapiens\tCCRF-CEM\tHuman", + "WSU-CLL\tHomo sapiens\tREH\tHuman", + "WiDr\tHomo sapiens\tHT-29\tHuman", + "Wong-Kilbourne\tHomo sapiens\tHeLa\tHuman", + "YAA\tHomo sapiens\tU-937\tHuman", + "YAP\tHomo sapiens\tU-937\tHuman", + "YJ\tHomo sapiens\tHL-60\tHuman", + "YMB-1\tHomo sapiens\tZR-75-1\tHuman", + "YMB-1-E\tHomo sapiens\tZR-75-1\tHuman", + "Yamada\tCanis lupus familiaris\tUnknown\tMouse", + "hPTC\tHomo sapiens\tUnknown\tPig, Sus scrofa", + "hTERT-EEC\tHomo sapiens\tMCF-7\tHuman" }; diff --git a/c++/src/objects/seqfeat/cell_line.txt b/c++/src/objects/seqfeat/cell_line.txt index b6a88442..4062ba07 100644 --- a/c++/src/objects/seqfeat/cell_line.txt +++ b/c++/src/objects/seqfeat/cell_line.txt @@ -1,9 +1,15 @@ +1483 Homo sapiens UM-SCC-1 Human +183 Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human +1E8 Homo sapiens NALM-6 Homo sapiens +2008/C13*5.25 Homo sapiens ME-180 Homo sapiens +207 (EU-2) Homo sapiens REH and SUP-B2 Human 222 Homo sapiens PA1 Human 2474/90 Homo sapiens HT-29 Human 2563 (MAC-21) Homo sapiens HeLa Human 2957/90 Homo sapiens HT-29 Human 3051/80 Homo sapiens HT-29 Human 41M Homo sapiens OAW 28 Human +A172TR3 Homo sapiens U-251 MG Homo sapiens A2008 Homo sapiens ME-180 Human ACC2 Homo sapiens HeLa Human ACC3 Homo sapiens HeLa Human @@ -11,21 +17,24 @@ ACCM Homo sapiens HeLa Human ACCNS Homo sapiens Unknown Mouse ACCS Homo sapiens T-24 Human ADLC-5M2 Homo sapiens HeLa Human -Aedes aegypti, Suitor's clone Mosquito Unknown Moth, Antheraea eucalypti -Aedes vexans culture Mosquito Unknown Moth, Antheraea eucalypti AG-F Homo sapiens CCRF-CEM Human AKI Homo sapiens HeLa Human +ALVA-101 Homo sapiens PC-3 Human ALVA-31 Homo sapiens PC-3 Human ALVA-41 Homo sapiens PC-3 Human ALVA-55 Homo sapiens PC-3 Human -ALVA-101 Homo sapiens PC-3 Human AMDURII Homo sapiens LLC-PK1 Pig, Sus scrofa AO Homo sapiens HeLa Human ARO Homo sapiens HT-29 Human ARO81-1 Homo sapiens HT-29 Human AV3 Homo sapiens HeLa Human AZ521 Homo sapiens HuTu 80 Human +Aedes aegypti, Suitor's clone Mosquito Unknown Moth, Antheraea eucalypti +Aedes vexans culture Mosquito Unknown Moth, Antheraea eucalypti +Ao38 Ascalapha odorata unknown Trichoplusia ni +B10XI Gallus gallus Unknown Pig, Sus scrofa B2-17 Homo sapiens U-251 MG Human +B6 Gallus gallus Unknown Pig, Sus scrofa BCC1/KMC Homo sapiens HeLa Human BE-13 Homo sapiens PEER Human BG-1 Homo sapiens MCF-7 Human @@ -36,56 +45,67 @@ BHP 2-7 Homo sapiens TPC-1 Human BHP 5-16 Homo sapiens M14 Human BHP 7-13 Homo sapiens TPC-1 Human BIC-1 Homo sapiens SW-480, SW-620 Human +BJA-B Homo sapiens HeLa Human BLIN-1 (also subclone 1E8) Homo sapiens NALM-6 Human BM-1604 Homo sapiens DU-145 Human -BrCA 5 Homo sapiens HeLa Human BSCC-93 Homo sapiens DJM-1 Human +BT-20 Homo sapiens HeLa Human BT-B Homo sapiens HeLa Human +BTI-Tnao38 Ascalapha odorata unknown Trichoplusia ni +BrCA 5 Homo sapiens HeLa Human +C-433 Homo sapiens RD-ES Human +C13 Homo sapiens ME-180 Homo sapiens C13 Homo sapiens ME-180 Human C16 (MRC-5 derivative) Homo sapiens HeLa Human -C-433 Homo sapiens RD-ES Human CAC2 Homo sapiens Unknown Rat -CaMa (clone 15) Homo sapiens Unknown Syrian hamster and mouse -CaOV Homo sapiens HeLa Human -Caov-2 Homo sapiens NIH:OVCAR-2 Human -CaVe Homo sapiens HeLa Human CCL3 Homo sapiens Unknown Mouse CH1, CH1cisR Homo sapiens PA1 Human -Chang liver Homo sapiens HeLa Human CHB Homo sapiens Unknown Rat CHP-100 Homo sapiens IMR-32 Human CHP-234 Homo sapiens Unknown Human -Clom 15 Homo sapiens Unknown Rat -Clone 1-5c-4 Homo sapiens HeLa Human -Clone-16 Homo sapiens Unknown Syrian hamster -Clone 1A Oncorhynchus mykiss CHSE-214 Chinook salmon, Oncorhynchus tschawytscha CMP Homo sapiens HeLa Human CMPII C2 Homo sapiens HeLa Human CNDT2 Homo sapiens Unknown Human +CNE-1 Homo sapiens HeLa Homo sapiens +CNE-2 Homo sapiens HeLa Homo sapiens CO (= COLE) Homo sapiens CCRF-CEM Human COLO-587 Homo sapiens COLO-320DM Human COLO-677 Homo sapiens RPMI-8226 Human +COLO-720E Homo sapiens COLO684, COLO685, COLO704 Human COLO-818 Homo sapiens COLO-800 Human +Ca9-22 Homo sapiens MSK-922 Human +CaMa (clone 15) Homo sapiens Unknown Syrian hamster and mouse +CaOV Homo sapiens HeLa Human +CaVe Homo sapiens HeLa Human +Caov-2 Homo sapiens NIH:OVCAR-2 Human +Chang liver Homo sapiens HeLa Human +Clom 15 Homo sapiens Unknown Rat +Clone 1-5c-4 Homo sapiens HeLa Human +Clone 1A Oncorhynchus mykiss CHSE-214 Chinook salmon, Oncorhynchus tschawytscha +Clone-16 Homo sapiens Unknown Syrian hamster CoLo-TC Homo sapiens COLO-205 Human Culisita inornata culture Mosquito Unknown Moth, Antheraea eucalypti +D-17 Canis lupus familiaris Moresco Dog, Canis familiaris +D-54 MG Homo sapiens A-172 Homo sapiens D18T Homo sapiens HeLa Human D98/AH Homo sapiens HeLa Human D98/AH2 Clone B Homo sapiens HeLa Human DAMI Homo sapiens HEL Human DAPT Homo sapiens HeLa Human DD Homo sapiens K-562 Human +DM12 (Tu-167 derivative) Homo sapiens UM-SCC-1 Human +DM14 (Tu-167 derivative) Homo sapiens UM-SCC-1 Human +DRO Homo sapiens A-375 Human +DRO90-1 Homo sapiens A-375 Human Det30A Homo sapiens HeLa Human -Detroit-6 (Det6) Homo sapiens HeLa Human -Detroit-98 Homo sapiens HeLa Human Detroit 98/AG Homo sapiens HeLa Human Detroit 98/AH-2 Homo sapiens HeLa Human Detroit 98/AH-R Homo sapiens HeLa Human Detroit 98s Homo sapiens HeLa Human -DM12 (Tu-167 derivative) Homo sapiens UM-SCC-1 Human -DM14 (Tu-167 derivative) Homo sapiens UM-SCC-1 Human -DRO Homo sapiens A-375 Human -DRO90-1 Homo sapiens A-375 Human +Detroit-6 (Det6) Homo sapiens HeLa Human +Detroit-98 Homo sapiens HeLa Human DuPro-1 Homo sapiens PC-3 Human +EB-3 Homo sapiens Daudi Human EB33 Homo sapiens HeLa Human ECC-1 Homo sapiens Ishikawa Human ECTC Bos taurus Vero Monkey, African green (Cercopithecus aethiops) @@ -94,43 +114,46 @@ ED27 Homo sapiens HeLa Human EEK Equus caballus NSK Pig, Sus scrofa EH Homo sapiens HK Human EJ-1 Homo sapiens T-24 Human -Ej138 Homo sapiens T-24 Human -ElCo Homo sapiens HeLa Human EPC Cyprinus carpio Unknown Fathead minnow, Pimephales promelas -EPLC3-2M1 Homo sapiens HeLa Human EPLC-65 Homo sapiens HeLa Human +EPLC3-2M1 Homo sapiens HeLa Human ESP1 Homo sapiens HeLa Human ETK-1 Homo sapiens SSP-25 Human EU-1 Homo sapiens REH Human EU-7 Homo sapiens CCRF-CEM Human EUE Homo sapiens HeLa Human EVLC2 Homo sapiens Unknown Human +Ej138 Homo sapiens T-24 Human +ElCo Homo sapiens HeLa Human F2-4E5 Homo sapiens SK-HEP-1 Human F2-5B6 Homo sapiens SK-HEP-1 Human F255A4 Homo sapiens HeLa Human FB2 Homo sapiens TPC-1 Human -Fitz-HSA Canis lupus familiaris DEN-HSA Dog, Canis familiaris FL Homo sapiens HeLa Human +FQ Homo sapiens OMK-210 Monkey, Owl (Aotus trivirgatus) +FU-RPNT-2 Homo sapiens FU-RPNT-1 Human +Fitz-HSA Canis lupus familiaris DEN-HSA Dog, Canis familiaris Flow 13000 Homo sapiens MRC-5 Human Flow 5000 Homo sapiens Flow 1000 Human Flow 6000 Homo sapiens Flow 1000 Human Flow 7000 Homo sapiens Flow 3000 Human -FQ Homo sapiens OMK-210 Monkey, Owl (Aotus trivirgatus) G-11 (HBT-3 derivative) Homo sapiens HeLa Human GHE Homo sapiens T-24 Human -Girardi heart Homo sapiens HeLa Human GM1312 Homo sapiens Correct name, incorrect cell type Human GOS-3 Homo sapiens U-343 MG Human GPS-M Cavia porcellus Strain L-M Mouse GPS-PD Cavia porcellus Strain L-M Mouse GREF-X Homo sapiens Unknown Rat GT3TKB Homo sapiens RERF-LC-A1 Human -H249 Homo sapiens H69 Human +Girardi heart Homo sapiens HeLa Human +Grey Canis lupus familiaris Unknown Human H-494 Homo sapiens HeLa Human +H249 Homo sapiens H69 Human H7D7A and derivatives Homo sapiens HepG2 Human H7D7B and derivatives Homo sapiens HepG2 Human H7D7C and derivatives Homo sapiens HepG2 Human H7D7D and derivatives Homo sapiens HepG2 Human +HAC15 Homo sapiens NCI-H295R Homo sapiens HAG Homo sapiens T-24 Human HBC Homo sapiens Unknown Rat HBL-100 Homo sapiens Unknown Human @@ -138,6 +161,7 @@ HBT-3 Homo sapiens HeLa Human HBT-39b Homo sapiens HeLa Human HBT-E (HBT-3 clone) Homo sapiens HeLa Human HCE Homo sapiens HeLa Human +HCV-29Tmv (HCV-29 derivative) Homo sapiens T-24 Human HCu-10 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human HCu-18 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human HCu-22 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human @@ -145,34 +169,32 @@ HCu-27 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (ge HCu-33 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human HCu-37 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human HCu-39 Homo sapiens Hcu-10, Hcu-18, Hcu-22, Hcu-27, Hcu-33, Hcu-37 or Hcu-39 (genetically identical) Human -HCV-29Tmv (HCV-29 derivative) Homo sapiens T-24 Human HEC-155 Homo sapiens HEC-180 Human HEC-180 Homo sapiens HEC-155 Human HEK Homo sapiens HeLa Human HEK/HRV (HEK derivative) Homo sapiens HeLa Human HEL-R66 Homo sapiens Unknown Monkey, African green (Cercopithecus aethiops) -HEp-2 (H.Ep.-2) Homo sapiens HeLa Human -Hep-2C Homo sapiens HeLa Human -Hep2 (Clone 2B) Homo sapiens HeLa Human HES Homo sapiens HeLa Human +HEp-2 (H.Ep.-2) Homo sapiens HeLa Human HIMEG-1 Homo sapiens HL-60 Human HKB-1 Homo sapiens Unknown Human HKMUS Homo sapiens SKG-II-SF Human HKMUS-SF Homo sapiens SKG-II-SF Human HL111783 Homo sapiens HeLa Human HMV-1 Homo sapiens HeLa Human +HPB-ALL Homo sapiens JURKAT Human HPB-MLT Homo sapiens HPB-ALL Human HPC-36M (HPC-36 derivative) Homo sapiens HeLa Human -hPTC Homo sapiens Unknown Pig, Sus scrofa -Hs 677.St Homo sapiens Unknown Mouse +HS-SULTAN Homo sapiens JIJOYE Human HSC-41 Homo sapiens HSC-42 Human HSG Homo sapiens HeLa Human HSG-AZA1 Homo sapiens HeLa Human HSG-AZA3 Homo sapiens HeLa Human HSGc-C5 Homo sapiens HeLa Human -HS-SULTAN Homo sapiens JIJOYE Human HSY Homo sapiens HeLa Human -hTERT-EEC Homo sapiens MCF-7 Human +Hep-2C Homo sapiens HeLa Human +Hep2 (Clone 2B) Homo sapiens HeLa Human +Hs 677.St Homo sapiens Unknown Mouse Hu1734 Homo sapiens HCV-29 Human Hu456 Homo sapiens T-24 Human Hu549 Homo sapiens T-24 Human @@ -185,20 +207,25 @@ Hut Homo sapiens HeLa Human IMC-2 Homo sapiens HeLa Human IMC-3 Homo sapiens HeLa Human IMC-4 Homo sapiens HeLa Human -Intestine 407 (Int-407, HEI) Homo sapiens HeLa Human IPDDC-A2 Homo sapiens Unknown Rat +IPEC Sus scrofa Unknown Cow IPRB Homo sapiens Unknown Rat +IPRI-OL-11 Orgyia leucostigma IPRI-CF-124 Choristoneura fumiferana +IPRI-OL-7 Orgyia leucostigma IPRI-CF-124 Choristoneura fumiferana IPTP/98 Homo sapiens Unknown Rat IST-1 Homo sapiens SK-OV-3 Human +Intestine 407 (Int-407, HEI) Homo sapiens HeLa Human J-111 Homo sapiens HeLa Human +J-82 Homo sapiens T-24 Human J96 Homo sapiens HeLa Human JCA-1 Homo sapiens T-24 Human JHC Homo sapiens HeLa Human +JHH-1 Homo sapiens Unknown Mouse +JHT (JHC derivative) Homo sapiens HeLa Human JHU012 Homo sapiens JHU022 Human JHU013 (JHU012 derivative) Homo sapiens FaDu Human JHU019 Homo sapiens PC-3 Human JHU028 Homo sapiens A549 Human -JHT (JHC derivative) Homo sapiens HeLa Human JMAR (Tu-167 derivative) Homo sapiens UM-SCC-1 Human JOSK-I Homo sapiens U-937 Human JOSK-K Homo sapiens U-937 Human @@ -210,6 +237,7 @@ K051 Homo sapiens K-562 Human K1 Homo sapiens GLAG-66 Human K2 Homo sapiens GLAG-66 Human KAK1 Homo sapiens HT-29 Human +KARPAS-45 Homo sapiens Unknown Human KAT10 Homo sapiens HT-29 Human KAT4 Homo sapiens HT-29 Human KAT5 Homo sapiens HT-29 Human @@ -218,22 +246,29 @@ KAT7 Homo sapiens HT-29 Human KB Homo sapiens HeLa Human KB-3-1 Homo sapiens HeLa Human KB-V1 Homo sapiens HeLa Human +KBM-3 Homo sapiens HL-60 Human KCI-MOH1 Homo sapiens HPAC Human +KE-37 Homo sapiens CCRF-CEM Human KM-3 Homo sapiens REH Human +KM20 Homo sapiens HT-29 Homo sapiens +KM20L2 Homo sapiens HT-29 Homo sapiens KM3 Homo sapiens Unknown Rat KMS-21-BM Homo sapiens Unknown Human KMT-2 Homo sapiens KG-1 Human KNS-89 Homo sapiens U-251 MG Human KOSC-3 Homo sapiens Ca9-22 Human KP-1N Homo sapiens PANC-1 Human +KP-P1 Homo sapiens HeLa Human KPB-M15 Homo sapiens KYO-1 Human KPL-1 Homo sapiens MCF-7 Human -KP-P1 Homo sapiens HeLa Human KSY-1 Homo sapiens T-24 Human -KU7 Homo sapiens HeLa Human KU-YS Homo sapiens KU-SN Human +KU7 Homo sapiens HeLa Human L-132 Homo sapiens HeLa Human L-41 (J96 derivative) Homo sapiens HeLa Human +L-540 Homo sapiens CCRF-CEM Human +LC5 Homo sapiens HeLa Homo sapiens +LC5-HIV Homo sapiens HeLa Homo sapiens LED-Ti Homo sapiens HeLa Human LLC-15MB Homo sapiens M14 Human LN-319 Homo sapiens LN-992 Human @@ -249,21 +284,22 @@ MA-1 Homo sapiens Pfeiffer Human MA-104 Macaca mulatta Vero? Monkey, African green (Cercopithecus aethiops) MA-111 Oryctolagus cuniculus Vero? Monkey, African green (Cercopithecus aethiops) MA-160 Homo sapiens HeLa Human -Mash-1 Homo sapiens MMac Human -MaTu Homo sapiens HeLa Human +MB-02 Homo sapiens HU-3 Human MC-4000 Homo sapiens HeLa Human -McCoy Homo sapiens Strain L Mouse MCF-7/AdrR (NCI/ADR-RES) Homo sapiens OVCAR-8 Human MDA-MB-435 Homo sapiens M14 Human MDA-N (MDA-MB-435 derivative) Homo sapiens M14 Human +MDA1986LN Homo sapiens UM-SCC-1 Human +MDA686LN Homo sapiens UM-SCC-1 Human +MDA686TU Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human MDS Homo sapiens JURKAT Human -MEL-HO Homo sapiens Unknown, does not match other cell line from same donor Human ME-WEI Homo sapiens Unknown, does not match other cell line from same donor Human +MEL-HO Homo sapiens Unknown, does not match other cell line from same donor Human MGH-U1 (EJ) Homo sapiens T-24 Human MGH-U2 (HM) Homo sapiens T-24 Human MHH-225 Homo sapiens JURKAT Human -Minnesota EE Homo sapiens HeLa Human MKB-1 Homo sapiens CCRF-CEM Human +MKN-7 Homo sapiens Unknown Human MKN28 Homo sapiens MKN74 Human MOBS-1 Homo sapiens U-937 Human MOLT-15 Homo sapiens CTV-1 Human @@ -271,11 +307,15 @@ MPanc-96 Homo sapiens AsPC-1 Human MRO87-1 Homo sapiens HT-29 Human MS (Monkey Stable) Monkey HeLa Human MT-1 Homo sapiens HeLa Human +MT-3 Homo sapiens LS-174T (LS-180 derivative) Homo sapiens MUTZ-1 Homo sapiens Namalwa Human MV522 Homo sapiens HT-29 Human +MaTu Homo sapiens HeLa Human +Mash-1 Homo sapiens MMac Human +McCoy Homo sapiens Strain L Mouse +Minnesota EE Homo sapiens HeLa Human NC-37 Homo sapiens Raji Human NCC16 Homo sapiens PHK16-0b Human -NCI/ADR-RES (MCF-7/AdrR) Homo sapiens OVCAR-8 Human NCI-H1264 Homo sapiens NCI-H157 Human NCI-H1304 Homo sapiens NCI-H1870 Human NCI-H1514 Homo sapiens Unknown Human @@ -288,6 +328,8 @@ NCI-H592 Homo sapiens NCI-H69 Human NCI-H60 Homo sapiens NCI-N417 Human NCI-H630 Homo sapiens Mixture Human NCI-H738 Homo sapiens Unknown Human +NCI-H929 Homo sapiens K-562 Human +NCI/ADR-RES (MCF-7/AdrR) Homo sapiens OVCAR-8 Human NCOL-1 Homo sapiens LoVo Human NCTC 2544 Homo sapiens HeLa Human NCTC 3075 Homo sapiens HeLa Human @@ -298,6 +340,8 @@ NOSE06 Homo sapiens DOV-13 Human NOSE07 Homo sapiens DOV-13 Human NPA87 Homo sapiens M14 Human NS-3 Homo sapiens COLO 201 Human +OCM-3 Homo sapiens SK-MEL-28 Homo sapiens +OCM-8 Homo sapiens SK-MEL-28 Homo sapiens OCUM-6 Homo sapiens OCUM-11 Human OE Homo sapiens HeLa Human OF Homo sapiens HeLa Human @@ -315,8 +359,9 @@ OU-AML-7 Homo sapiens OCI/AML2 Human OU-AML-8 Homo sapiens OCI/AML2 Human OV-1063 Homo sapiens Unknown Human OV2008, OV2008/C13 Homo sapiens ME-180 Human -Ovary1847 Homo sapiens NIH:OVCAR-8 Human +OV2008/C13 Homo sapiens ME-180 Homo sapiens OVMIU Homo sapiens OVSAYO Human +Ovary1847 Homo sapiens NIH:OVCAR-8 Human P1-1A3 Homo sapiens SK-HEP-1 Human P1-4D6 Homo sapiens SK-HEP-1 Human P39/TSUGANE (P39/TSU) Homo sapiens HL-60 Human @@ -331,6 +376,9 @@ PH61-N Homo sapiens MIA PaCa-2 Human PLB-985 Homo sapiens HL-60 Human PPC-1 Homo sapiens PC-3 Human PSV811 Homo sapiens WI-38 Human +Panc 01.28 Homo sapiens Panc 01.28, Panc 06.03 Homo sapiens +Panc 06.03 Homo sapiens Panc 01.28, Panc 06.03 Homo sapiens +Parks Canis lupus familiaris Unknown Human RAMAK-1 Homo sapiens T-24 Human RB Homo sapiens OMK-210 Monkey, Owl (Aotus trivirgatus) RBHF-1 Homo sapiens Unknown Non-human @@ -342,13 +390,16 @@ RERF-LC-MA Homo sapiens SK-MES-1 Human RERF-LC-OK Homo sapiens Marcus Human RGC-5 Rat 661W Mouse RM-10 Homo sapiens K-562 Human +RMG-II Homo sapiens RMG-I Human RMUG-L Homo sapiens SNG-II Human RO-D81-1 Homo sapiens HT-29 Human RO-H85-1 Homo sapiens 647-V Human RPMI-4788 Homo sapiens HeLa Human RPMI-6666 Homo sapiens Correct name, incorrect cell type Human +RPMI-8402 Homo sapiens Unknown Human RPTC-1 Homo sapiens TPC-1 Human RS-1 Homo sapiens K-562 Human +RT4 Homo sapiens HeLa Human RTSG Homo sapiens SNG-II Human RY Homo sapiens Unknown Monkey SA4 Homo sapiens HeLa Human @@ -374,7 +425,6 @@ SLK Homo sapiens Caki-1 Human SNB-19 Homo sapiens U-251 MG Human SPI-801 Homo sapiens K-562 Human SPI-802 Homo sapiens K-562 Human -SpR Homo sapiens OMK-210 Monkey, Owl (Aotus trivirgatus) SQ-5 Homo sapiens HeLa Human SR-91 Homo sapiens AML-193 Human SW-527 Homo sapiens SW-480, SW-620 Human @@ -383,13 +433,15 @@ SW-608 Homo sapiens SW-480, SW-620 Human SW-613 Homo sapiens SW-480, SW-620 Human SW-732 Homo sapiens SW-480, SW-620 Human SW-733 Homo sapiens SW-480, SW-620 Human +SpR Homo sapiens OMK-210 Monkey, Owl (Aotus trivirgatus) T-1 Homo sapiens HeLa Human -T1 Homo sapiens HeLa Human T-33 Homo sapiens K-562 Human +T-9 (WI-38 derivative) Homo sapiens HeLa Human +T1 Homo sapiens HeLa Human +T3M-12 Homo sapiens T3M-1 Human T404 Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human T406 (oral SCC) **Different cell line exists with same name: T406 (glioblastoma)** Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human T409 Homo sapiens UM-SCC-1 Human -T-9 (WI-38 derivative) Homo sapiens HeLa Human TCO-1 Homo sapiens TCO-2 Human TDL-1 Homo sapiens P3JHR-1 Human TDL-2 Homo sapiens P3JHR-1 Human @@ -399,12 +451,12 @@ TE-12 Homo sapiens TE-2, TE-3, TE-12 or TE-13 (genetically identical) Human TE-13 Homo sapiens TE-2, TE-3, TE-12 or TE-13 (genetically identical) Human TE-2 Homo sapiens TE-2, TE-3, TE-12 or TE-13 (genetically identical) Human TE-3 Homo sapiens TE-2, TE-3, TE-12 or TE-13 (genetically identical) Human +TE-7 Homo sapiens TE-2, TE-3, TE-12 or TE-13 (genetically identical) Human TE671 Homo sapiens RD Human TE671 Subline No.2 Homo sapiens RD Human -TE-7 Homo sapiens TE-2, TE-3, TE-12 or TE-13 (genetically identical) Human TEC61 Homo sapiens JEG3 Human -TK-1 Homo sapiens U-251 MG Human TI-1 Homo sapiens K-562 Human +TK-1 Homo sapiens U-251 MG Human TMH-1 Homo sapiens IHH-4 Human TMM Homo sapiens Correct name, incorrect cell type Human TSU-Pr1 Homo sapiens T-24 Human @@ -417,59 +469,30 @@ Tu-212 Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212 Tu-212LN Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human TuWi Homo sapiens HeLa Human U-118 MG Homo sapiens U-138 MG Human +U-373 MG Homo sapiens U-251 MG Human +U-937 Homo sapiens Unknown Human +U251-TR3 Homo sapiens U-251 MG Homo sapiens UM-UC-2 Homo sapiens T-24 Human UM-UC-3-GFP (UM-UC-3 derivative) Homo sapiens Unknown, NOT UM-UC-3 Human UPES/C Homo sapiens Unknown Rat UPHHJA Homo sapiens Unknown Rat +UROtsa Homo sapiens T-24 Human +UT-7 Homo sapiens U-937 Human UTMB-460 Homo sapiens CCRF-CEM Human VC312R Homo sapiens Unknown Mixed, human + mouse VM-CUB-III Homo sapiens VM-CUB-I Human -WiDr Homo sapiens HT-29 Human WISH Homo sapiens HeLa Human WKD Homo sapiens HeLa Human -Wong-Kilbourne Homo sapiens HeLa Human WRL 68 Homo sapiens HeLa Human WSU-ALCL Homo sapiens CCRF-CEM Human WSU-CLL Homo sapiens REH Human +WiDr Homo sapiens HT-29 Human +Wong-Kilbourne Homo sapiens HeLa Human YAA Homo sapiens U-937 Human YAP Homo sapiens U-937 Human YJ Homo sapiens HL-60 Human YMB-1 Homo sapiens ZR-75-1 Human YMB-1-E Homo sapiens ZR-75-1 Human -1483 Homo sapiens UM-SCC-1 Human -183 Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human -207 (EU-2) Homo sapiens REH and SUP-B2 Human -B10XI Gallus gallus Unknown Pig, Sus scrofa -B6 Gallus gallus Unknown Pig, Sus scrofa -BJA-B Homo sapiens HeLa Human -BT-20 Homo sapiens HeLa Human -Ca9-22 Homo sapiens MSK-922 Human -COLO-720E Homo sapiens COLO684, COLO685, COLO704 Human -D-17 Canis lupus familiaris Moresco Dog, Canis familiaris -EB-3 Homo sapiens Daudi Human -FU-RPNT-2 Homo sapiens FU-RPNT-1 Human -Grey Canis lupus familiaris Unknown Human -HPB-ALL Homo sapiens JURKAT Human -IPEC Sus scrofa Unknown Cow -J-82 Homo sapiens T-24 Human -JHH-1 Homo sapiens Unknown Mouse -KARPAS-45 Homo sapiens Unknown Human -KBM-3 Homo sapiens HL-60 Human -KE-37 Homo sapiens CCRF-CEM Human -L-540 Homo sapiens CCRF-CEM Human -MB-02 Homo sapiens HU-3 Human -MDA1986LN Homo sapiens UM-SCC-1 Human -MDA686LN Homo sapiens UM-SCC-1 Human -MDA686TU Homo sapiens T404, T406, Tu-138, Tu-158LN, Tu-159, Tu-182, Tu-212, Tu-212LN (genetically identical) Human -MKN-7 Homo sapiens Unknown Human -NCI-H929 Homo sapiens K-562 Human -Parks Canis lupus familiaris Unknown Human -RMG-II Homo sapiens RMG-I Human -RPMI-8402 Homo sapiens Unknown Human -RT4 Homo sapiens HeLa Human -T3M-12 Homo sapiens T3M-1 Human -U-373 MG Homo sapiens U-251 MG Human -U-937 Homo sapiens Unknown Human -UROtsa Homo sapiens T-24 Human -UT-7 Homo sapiens U-937 Human Yamada Canis lupus familiaris Unknown Mouse +hPTC Homo sapiens Unknown Pig, Sus scrofa +hTERT-EEC Homo sapiens MCF-7 Human diff --git a/c++/src/objects/seqfeat/common_tax.inc b/c++/src/objects/seqfeat/common_tax.inc new file mode 100644 index 00000000..a7a99496 --- /dev/null +++ b/c++/src/objects/seqfeat/common_tax.inc @@ -0,0 +1,934 @@ +/* $Id: common_tax.inc 523138 2016-12-28 19:53:42Z bollin $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Colleen Bollin + * + * File Description: + * Built-in copy of common_tax.txt. + * + */ + +static const char* const kOrgRefList[] = { + "Acacia koa\t-\t1\t1\t11\t468172\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Mimosoideae; Acacieae; Acacia", + "Acanthisitta chloris\trifleman\t1\t2\t-\t57068\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Acanthisittidae; Acanthisitta", + "Acanthoscurria geniculata\t-\t1\t5\t-\t575412\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Araneae; Mygalomorphae; Theraphosidae; Acanthoscurria", + "Acinetobacter baumannii\t-\t11\t0\t-\t470\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Pseudomonadales; Moraxellaceae; Acinetobacter; Acinetobacter calcoaceticus/baumannii complex", + "Acinetobacter pittii\t-\t11\t0\t-\t48296\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Pseudomonadales; Moraxellaceae; Acinetobacter; Acinetobacter calcoaceticus/baumannii complex", + "Acinonyx jubatus\tcheetah\t1\t2\t-\t32536\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Feliformia; Felidae; Acinonychinae; Acinonyx", + "Acropora cervicornis\t-\t1\t4\t-\t6130\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Astrocoeniina; Acroporidae; Acropora", + "Acropora digitifera\t-\t1\t4\t-\t70779\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Astrocoeniina; Acroporidae; Acropora", + "Acropora millepora\t-\t1\t4\t-\t45264\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Astrocoeniina; Acroporidae; Acropora", + "Actias selene\tIndian moon moth\t1\t5\t-\t37776\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Saturniini; Actias", + "Acyrthosiphon pisum\tpea aphid\t1\t5\t-\t7029\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Sternorrhyncha; Aphidiformes; Aphidomorpha; Aphidoidea; Aphididae; Aphidinae; Macrosiphini; Acyrthosiphon", + "Adineta vaga\t-\t1\t5\t-\t104782\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Rotifera; Bdelloidea; Adinetida; Adinetidae; Adineta", + "Aedes aegypti\tyellow fever mosquito\t1\t5\t-\t7159\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Culicomorpha; Culicoidea; Culicidae; Culicinae; Aedini; Aedes; Stegomyia", + "Aedes albopictus\tAsian tiger mosquito\t1\t5\t-\t7160\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Culicomorpha; Culicoidea; Culicidae; Culicinae; Aedini; Aedes; Stegomyia", + "Aegilops tauschii\t-\t1\t1\t11\t37682\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Triticinae; Aegilops", + "Aethina tumida\tsmall hive beetle\t1\t5\t-\t116153\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Cucujoidea; Nitidulidae; Nitidulinae; Aethina", + "Agapanthus praecox subsp. orientalis\t-\t1\t1\t11\t547170\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Amaryllidaceae; Agapanthoideae; Agapanthus; Agapanthus praecox", + "Agave deserti\t-\t1\t1\t11\t382119\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Asparagaceae; Agavoideae; Agave", + "Agave tequilana\t-\t1\t1\t11\t386106\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Asparagaceae; Agavoideae; Agave", + "Agrilus planipennis\temerald ash borer\t1\t5\t-\t224129\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Elateriformia; Buprestoidea; Buprestidae; Agrilinae; Agrilus", + "Agrotis segetum\tturnip moth\t1\t5\t-\t47767\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Noctuinae; Agrotis", + "Ailuropoda melanoleuca\tgiant panda\t1\t2\t-\t9646\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Ursidae; Ailuropoda", + "Alexandrium tamarense\t-\t1\t4\t11\t2926\tPLN\tcellular organisms; Eukaryota; Alveolata; Dinophyceae; Gonyaulacales; Gonyaulacaceae; Alexandrium", + "Alligator mississippiensis\tAmerican alligator\t1\t2\t-\t8496\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Crocodylia; Alligatoridae; Alligatorinae; Alligator", + "Alligator sinensis\tChinese alligator\t1\t2\t-\t38654\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Crocodylia; Alligatoridae; Alligatorinae; Alligator", + "Allium cepa\tonion\t1\t1\t11\t4679\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Amaryllidaceae; Allioideae; Allieae; Allium", + "Allium fistulosum\tWelsh onion\t1\t1\t11\t35875\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Amaryllidaceae; Allioideae; Allieae; Allium", + "Allium sativum\tgarlic\t1\t1\t11\t4682\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Amaryllidaceae; Allioideae; Allieae; Allium", + "Amaranthus tricolor\t-\t1\t1\t11\t29722\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Amaranthaceae; Amaranthus", + "Amazona vittata\tPuerto Rican parrot\t1\t2\t-\t241585\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Psittaciformes; Psittacidae; Amazona", + "Ameiurus nebulosus\tbrown bullhead\t1\t2\t-\t27778\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Characiphysae; Siluriformes; Siluroidei; Ictaluridae; Ameiurus", + "Amoebidium parasiticum JAP-7-2\t-\t1\t4\t-\t1069442\tINV\tcellular organisms; Eukaryota; Opisthokonta; Opisthokonta incertae sedis; Ichthyosporea; Ichthyophonida; Amoebidiaceae; Amoebidium; Amoebidium parasiticum", + "Anas platyrhynchos\tmallard\t1\t2\t-\t8839\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Anseriformes; Anatidae; Anas", + "Ancylostoma ceylanicum\t-\t1\t5\t-\t53326\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Ancylostomatoidea; Ancylostomatidae; Ancylostomatinae; Ancylostoma", + "Ancylostoma duodenale\t-\t1\t5\t-\t51022\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Ancylostomatoidea; Ancylostomatidae; Ancylostomatinae; Ancylostoma", + "Anguilla anguilla\tEuropean eel\t1\t2\t-\t7936\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Elopocephalai; Elopocephala; Elopomorpha; Anguilliformes; Anguillidae; Anguilla", + "Anguilla japonica\tJapanese eel\t1\t2\t-\t7937\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Elopocephalai; Elopocephala; Elopomorpha; Anguilliformes; Anguillidae; Anguilla", + "Anisakis simplex\therring worm\t1\t5\t-\t6269\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Ascaridida; Ascaridoidea; Anisakidae; Anisakis; Anisakis simplex complex", + "Anneissia japonica\t-\t1\t9\t-\t1529436\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Pelmatozoa; Crinoidea; Articulata; Comatulida; Comatulidae; Comatulinae; Anneissia", + "Annulipalpia sp. AD-2013\t-\t1\t5\t-\t1499517\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Trichoptera; Annulipalpia; Unclassified Annulipalpia", + "Anolis carolinensis\tgreen anole\t1\t2\t-\t28377\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Unidentata; Episquamata; Toxicofera; Iguania; Iguanidae; Polychrotinae; Anolis", + "Anopheles funestus\tAfrican malaria mosquito\t1\t5\t-\t62324\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Culicomorpha; Culicoidea; Culicidae; Anophelinae; Anopheles; Cellia; Myzomyia; funestus group; funestus subgroup", + "Anopheles gambiae\tAfrican malaria mosquito\t1\t5\t-\t7165\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Culicomorpha; Culicoidea; Culicidae; Anophelinae; Anopheles; Cellia; Pyretophorus; gambiae species complex", + "Anopheles sinensis\t-\t1\t5\t-\t74873\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Culicomorpha; Culicoidea; Culicidae; Anophelinae; Anopheles; Anopheles; Laticorn; Myzorhynchus; hyrcanus group", + "Anoplophora glabripennis\tAsian longhorned beetle\t1\t5\t-\t217634\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Chrysomeloidea; Cerambycidae; Lamiinae; Lamiini; Anoplophora", + "Anoplopoma fimbria\tsablefish\t1\t2\t-\t229290\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Perciformes; Cottioidei; Anoplopomatales; Anoplopomatidae; Anoplopoma", + "Anser cygnoides domesticus\t-\t1\t2\t-\t381198\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Anseriformes; Anatidae; Anser; Anser cygnoides", + "Antheraea assama\tIndian muga silkmoth\t1\t5\t-\t91021\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Saturniini; Antheraea", + "Antheraea pernyi\tChinese oak silkmoth\t1\t5\t-\t7119\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Saturniini; Antheraea", + "Antheraea yamamai\tJapanese oak silkmoth\t1\t5\t-\t7121\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Saturniini; Antheraea", + "Anthopleura elegantissima\tclonal anemone\t1\t4\t-\t6110\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Actiniaria; Nynantheae; Actiniidae; Anthopleura", + "Anthoxanthum odoratum\t-\t1\t1\t11\t29661\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Poodae; Poeae; Poeae Chloroplast Group 1 (Aveneae type); Anthoxanthinae; Anthoxanthum", + "Anthurium andraeanum\t-\t1\t1\t11\t226677\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Alismatales; Araceae; Pothoideae; Potheae; Anthurium", + "Aotus nancymaae\tMa's night monkey\t1\t2\t-\t37293\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Platyrrhini; Aotidae; Aotus", + "Apaloderma vittatum\tbar-tailed trogon\t1\t2\t-\t57397\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Trogoniformes; Trogonidae; Apaloderma", + "Aphelocoma californica obscura\t-\t1\t2\t-\t947029\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Corvoidea; Corvidae; Aphelocoma; Aphelocoma californica", + "Aphyosemion striatum\t-\t1\t2\t-\t60296\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Aphyosemion", + "Apis cerana\tAsiatic honeybee\t1\t5\t-\t7461\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Apinae; Apini; Apis", + "Apis florea\tlittle honeybee\t1\t5\t-\t7463\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Apinae; Apini; Apis", + "Apis mellifera\thoney bee\t1\t5\t-\t7460\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Apinae; Apini; Apis", + "Aplysia californica\tCalifornia sea hare\t1\t5\t-\t6500\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Heterobranchia; Euthyneura; Euopisthobranchia; Aplysiomorpha; Aplysioidea; Aplysiidae; Aplysia", + "Apostichopus japonicus\tJapanese sea cucumber\t1\t9\t-\t307972\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Holothuroidea; Aspidochirotacea; Aspidochirotida; Stichopodidae; Apostichopus", + "Apteryx australis mantelli\t-\t1\t2\t-\t202946\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Palaeognathae; Apterygiformes; Apterygidae; Apteryx; Apteryx australis", + "Aquila chrysaetos canadensis\t-\t1\t2\t-\t216574\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Falconiformes; Accipitridae; Accipitrinae; Aquila; Aquila chrysaetos", + "Ara macao\tscarlet macaw\t1\t2\t-\t176014\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Psittaciformes; Psittacidae; Ara", + "Arabidopsis lyrata subsp. lyrata\t-\t1\t1\t11\t81972\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Camelineae; Arabidopsis; Arabidopsis lyrata", + "Arabidopsis thaliana\tthale cress\t1\t1\t11\t3702\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Camelineae; Arabidopsis", + "Arachis duranensis\t-\t1\t1\t11\t130453\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Dalbergieae; Arachis", + "Arachis hypogaea\tpeanut\t1\t1\t11\t3818\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Dalbergieae; Arachis", + "Arachis hypogaea var. vulgaris\t-\t1\t1\t11\t925390\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Dalbergieae; Arachis; Arachis hypogaea; Arachis hypogaea subsp. fastigiata", + "Arachis ipaensis\t-\t1\t1\t11\t130454\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Dalbergieae; Arachis", + "Araucaria cunninghamii\t-\t1\t1\t11\t56994\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Araucariales; Araucariaceae; Araucaria", + "Archaeopsylla erinacei\t-\t1\t5\t-\t48909\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Siphonaptera; Pulicomorpha; Pulicoidea; Pulicidae; Archaeopsyllinae; Archaeopsylla", + "Aretaon asperrimus\tthorny stick insect\t1\t5\t-\t173775\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Phasmatodea; Verophasmatodea; Areolatae; Bacilloidea; Heteropterygidae; Obriminae; Obrimini; Aretaon", + "Argochrysis armilla\t-\t1\t5\t-\t1317734\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Chrysidoidea; Chrysididae; Chrysidinae; Chrysidini; Argochrysis", + "Argulus siamensis\t-\t1\t5\t-\t1167309\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Branchiura; Arguloida; Argulidae; Argulus", + "Arion vulgaris\t-\t1\t5\t-\t1028688\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Heterobranchia; Euthyneura; Panpulmonata; Eupulmonata; Stylommatophora; Sigmurethra; Arionoidea; Arionidae; Arion", + "Artemisia annua\tsweet wormwood\t1\t1\t11\t35608\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Asteroideae; Anthemideae; Artemisiinae; Artemisia", + "artificial sequences\t-\t11\t0\t11\t81077\tSYN\tother sequences", + "Arundo donax\tgiant reed\t1\t1\t11\t35708\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Arundinoideae; Arundineae; Arundo", + "Ascaris suum\tpig roundworm\t1\t5\t-\t6253\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Ascaridida; Ascaridoidea; Ascarididae; Ascaris", + "Aspergillus oryzae\t-\t1\t4\t-\t5062\tPLN\tcellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Ascomycota; saccharomyceta; Pezizomycotina; leotiomyceta; Eurotiomycetes; Eurotiomycetidae; Eurotiales; Aspergillaceae; Aspergillus", + "Aspidistra saxicola\t-\t1\t1\t11\t1197444\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Asparagaceae; Nolinoideae; Aspidistra", + "Astacus astacus\tbroad-fingered crayfish\t1\t5\t-\t6715\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Astacidea; Astacoidea; Astacidae; Astacus", + "Astacus leptodactylus\tnarrow-clawed crayfish\t1\t5\t-\t6717\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Astacidea; Astacoidea; Astacidae; Astacus", + "Asterias amurensis\t-\t1\t9\t-\t7602\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Asterias", + "Asterias forbesi\tForbes's starfish\t1\t9\t-\t7603\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Asterias", + "Asterias rubens\tEuropean starfish\t1\t9\t-\t7604\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Asterias", + "Astyanax mexicanus\tMexican tetra\t1\t2\t-\t7994\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Characiphysae; Characiformes; Characoidei; Characidae; Characidae incertae sedis; Astyanax clade; Astyanax", + "Athetis lepigone\t-\t1\t5\t-\t1223490\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Noctuinae; Athetis", + "Atractaspis aterrima\tmole viper\t1\t2\t-\t1355159\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Unidentata; Episquamata; Toxicofera; Serpentes; Colubroidea; Lamprophiidae; Atractaspidinae; Atractaspis", + "Aurelia aurita\tmoon jelly\t1\t4\t-\t6145\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Scyphozoa; Semaeostomeae; Ulmaridae; Aurelia", + "Austrofundulus limnaeus\t-\t1\t2\t-\t52670\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Rivulidae; Austrofundulus", + "Avena sativa\toat\t1\t1\t11\t4498\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Poodae; Poeae; Aveninae; Avena", + "Avicennia marina\t-\t1\t1\t11\t82927\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Acanthaceae; Avicennioideae; Avicennia", + "Bacillus cereus\t-\t11\t0\t-\t1396\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Bacillales; Bacillaceae; Bacillus; Bacillus cereus group", + "Bacillus licheniformis\t-\t11\t0\t-\t1402\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Bacillales; Bacillaceae; Bacillus; Bacillus subtilis group", + "Bactrocera cucurbitae\tmelon fly\t1\t5\t-\t28588\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Dacini; Bactrocera; Zeugodacus", + "Bactrocera dorsalis\toriental fruit fly\t1\t5\t-\t27457\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Dacini; Bactrocera; Bactrocera; Bactrocera dorsalis species complex", + "Bactrocera latifrons\t-\t1\t5\t-\t174628\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Dacini; Bactrocera; Bactrocera", + "Bactrocera minax\tOriental citrus fly\t1\t5\t-\t104690\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Dacini; Bactrocera; Tetradacus", + "Bactrocera oleae\tolive fruit fly\t1\t5\t-\t104688\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Dacini; Bactrocera; Daculus", + "Balaenoptera acutorostrata scammoni\t-\t1\t2\t-\t310752\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Cetacea; Mysticeti; Balaenopteridae; Balaenoptera; Balaenoptera acutorostrata", + "Balaenoptera bonaerensis\tAntarctic minke whale\t1\t2\t-\t33556\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Cetacea; Mysticeti; Balaenopteridae; Balaenoptera", + "Balearica regulorum gibbericeps\tEast African grey crowned-crane\t1\t2\t-\t100784\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gruiformes; Gruidae; Balearica; Balearica regulorum", + "Banksia hookeriana\t-\t1\t1\t11\t199770\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; stem eudicotyledons; Proteales; Proteaceae; Banksia", + "Bdellocephala annandalei\t-\t1\t9\t-\t1421413\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Rhabditophora; Seriata; Tricladida; Continenticola; Planarioidea; Dendrocoelidae; Bdellocephala", + "Bemisia tabaci\t-\t1\t5\t-\t7038\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Sternorrhyncha; Aleyrodiformes; Aleyrodoidea; Aleyrodidae; Aleyrodinae; Bemisia", + "Beta vulgaris\t-\t1\t1\t11\t161934\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Chenopodiaceae; Betoideae; Beta", + "Beta vulgaris subsp. vulgaris\t-\t1\t1\t11\t3555\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Chenopodiaceae; Betoideae; Beta; Beta vulgaris", + "Betula platyphylla\t-\t1\t1\t11\t78630\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fagales; Betulaceae; Betula", + "Biomphalaria glabrata\t-\t1\t5\t-\t6526\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Heterobranchia; Euthyneura; Panpulmonata; Hygrophila; Planorboidea; Planorbidae; Biomphalaria", + "Bison bison bison\t-\t1\t2\t-\t43346\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Bovinae; Bison; Bison bison", + "Bithynia siamensis goniomphalos\t-\t1\t5\t-\t479249\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Caenogastropoda; Hypsogastropoda; Littorinimorpha; Truncatelloidea; Bithyniidae; Bithynia; Bithynia siamensis", + "Boechera gunnisoniana\t-\t1\t1\t11\t93888\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Boechereae; Boechera", + "Bombina bombina\tfire-bellied toad\t1\t2\t-\t8345\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Bombinatoridae; Bombina", + "Bombina orientalis\t-\t1\t2\t-\t8346\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Bombinatoridae; Bombina", + "Bombina variegata scabra\t-\t1\t2\t-\t251232\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Bombinatoridae; Bombina; Bombina variegata", + "Bombina variegata variegata\t-\t1\t2\t-\t191472\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Bombinatoridae; Bombina; Bombina variegata", + "Bombus impatiens\tcommon eastern bumble bee\t1\t5\t-\t132113\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Bombinae; Bombini; Bombus; Pyrobombus", + "Bombus insularis\t-\t1\t5\t-\t207637\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Bombinae; Bombini; Bombus; Psithyrus", + "Bombus terrestris\tbuff-tailed bumblebee\t1\t5\t-\t30195\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Bombinae; Bombini; Bombus; Bombus", + "Bombyx mori\tdomestic silkworm\t1\t5\t-\t7091\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Bombycidae; Bombycinae; Bombyx", + "Bordetella pertussis\t-\t11\t0\t-\t520\tBCT\tcellular organisms; Bacteria; Proteobacteria; Betaproteobacteria; Burkholderiales; Alcaligenaceae; Bordetella", + "Bos mutus\twild yak\t1\t2\t-\t72004\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Bovinae; Bos", + "Bos taurus\tcattle\t1\t2\t-\t9913\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Bovinae; Bos", + "Botryococcus braunii\t-\t1\t1\t11\t38881\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Chlorophyta; Trebouxiophyceae; Trebouxiophyceae incertae sedis; Botryococcaceae; Botryococcus", + "Brachionus calyciflorus\t-\t1\t5\t-\t104777\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Rotifera; Monogononta; Pseudotrocha; Ploima; Brachionidae; Brachionus", + "Brachycistis timberlakei\t-\t1\t5\t-\t1317728\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Tiphiidae; Brachycistidinae; Brachycistis", + "Brachypodium distachyon\tstiff brome\t1\t1\t11\t15368\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Brachypodieae; Brachypodium", + "Bragasellus peltatus\t-\t1\t5\t-\t1282048\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Bragasellus", + "Branchiostoma lanceolatum\tamphioxus\t1\t5\t-\t7740\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Cephalochordata; Branchiostomidae; Branchiostoma", + "Brassica juncea\t-\t1\t1\t11\t3707\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica", + "Brassica napus\trape\t1\t1\t11\t3708\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica", + "Brassica oleracea var. capitata\tcabbage\t1\t1\t11\t3716\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica; Brassica oleracea", + "Brassica oleracea var. oleracea\t-\t1\t1\t11\t109376\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica; Brassica oleracea", + "Brassica rapa\tfield mustard\t1\t1\t11\t3711\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica", + "Brassica rapa subsp. pekinensis\tChinese cabbage\t1\t1\t11\t51351\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica; Brassica rapa", + "Brassica rapa x Raphanus sativus\t-\t1\t1\t11\t1417620\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica x Raphanus", + "Brassicogethes aeneus\t-\t1\t5\t-\t1431903\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Cucujoidea; Nitidulidae; Meligethinae; Brassicogethes", + "Brugia malayi\t-\t1\t5\t-\t6279\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Spirurida; Filarioidea; Onchocercidae; Brugia", + "Bubalus bubalis\twater buffalo\t1\t2\t-\t89462\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Bovinae; Bubalus", + "Buceros rhinoceros silvestris\t-\t1\t2\t-\t175836\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Bucerotiformes; Bucerotidae; Buceros; Buceros rhinoceros", + "Burkholderia ubonensis\t-\t11\t0\t-\t101571\tBCT\tcellular organisms; Bacteria; Proteobacteria; Betaproteobacteria; Burkholderiales; Burkholderiaceae; Burkholderia", + "Caenorhabditis elegans\t-\t1\t5\t-\t6239\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Rhabditoidea; Rhabditidae; Peloderinae; Caenorhabditis", + "Caenorhabditis remanei\t-\t1\t5\t-\t31234\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Rhabditoidea; Rhabditidae; Peloderinae; Caenorhabditis", + "Cajanus cajan\tpigeon pea\t1\t1\t11\t3821\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Cajanus", + "Calanus finmarchicus\t-\t1\t5\t-\t6837\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Gymnoplea; Calanoida; Calanidae; Calanus", + "Calanus glacialis\t-\t1\t5\t-\t113644\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Gymnoplea; Calanoida; Calanidae; Calanus", + "Calidris pugnax\truff\t1\t2\t-\t198806\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Charadriiformes; Scolopacidae; Calidris", + "Caligus rogercresseyi\t-\t1\t5\t-\t217165\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Podoplea; Siphonostomatoida; Caligidae; Caligus", + "Callithrix jacchus\twhite-tufted-ear marmoset\t1\t2\t-\t9483\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Platyrrhini; Cebidae; Callitrichinae; Callithrix", + "Callorhinchus milii\telephant shark\t1\t2\t-\t7868\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Chondrichthyes; Holocephali; Chimaeriformes; Callorhinchidae; Callorhinchus", + "Calypte anna\tAnna's hummingbird\t1\t2\t-\t9244\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Trochiliformes; Trochilidae; Calypte", + "Camelina sativa\tfalse flax\t1\t1\t11\t90675\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Camelineae; Camelina", + "Camellia oleifera\t-\t1\t1\t11\t385388\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Ericales; Theaceae; Camellia", + "Camellia sinensis\t-\t1\t1\t11\t4442\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Ericales; Theaceae; Camellia", + "Camellia sinensis var. sinensis\t-\t1\t1\t11\t542762\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Ericales; Theaceae; Camellia; Camellia sinensis", + "Camelus bactrianus\tBactrian camel\t1\t2\t-\t9837\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Tylopoda; Camelidae; Camelus", + "Camelus dromedarius\tArabian camel\t1\t2\t-\t9838\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Tylopoda; Camelidae; Camelus", + "Camelus ferus\tWild Bactrian camel\t1\t2\t-\t419612\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Tylopoda; Camelidae; Camelus", + "Camponotus floridanus\tFlorida carpenter ant\t1\t5\t-\t104421\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Camponotini; Camponotus", + "Camptotheca acuminata\t-\t1\t1\t11\t16922\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Cornales; Nyssaceae; Camptotheca", + "Campylobacter coli\t-\t11\t0\t-\t195\tBCT\tcellular organisms; Bacteria; Proteobacteria; delta/epsilon subdivisions; Epsilonproteobacteria; Campylobacterales; Campylobacteraceae; Campylobacter", + "Campylobacter jejuni\t-\t11\t0\t-\t197\tBCT\tcellular organisms; Bacteria; Proteobacteria; delta/epsilon subdivisions; Epsilonproteobacteria; Campylobacterales; Campylobacteraceae; Campylobacter", + "Canis lupus familiaris\tdog\t1\t2\t-\t9615\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Canidae; Canis; Canis lupus", + "Cannabis sativa\themp\t1\t1\t11\t3483\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Cannabaceae; Cannabis", + "Capra hircus\tgoat\t1\t2\t-\t9925\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Caprinae; Capra", + "Caprimulgus carolinensis\tchuck-will's-widow\t1\t2\t-\t279965\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Caprimulgiformes; Caprimulgidae; Caprimulginae; Caprimulgus", + "Capsella rubella\t-\t1\t1\t11\t81985\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Camelineae; Capsella", + "Capsicum annuum\t-\t1\t1\t11\t4072\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Capsiceae; Capsicum", + "Carabus granulatus\t-\t1\t5\t-\t118799\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Adephaga; Caraboidea; Carabidae; Carabinae; Carabini; Carabina; Carabus; Carabus", + "Caragana korshinskii\t-\t1\t1\t11\t220689\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Caraganeae; Caragana", + "Cariama cristata\tred-legged seriema\t1\t2\t-\t54380\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gruiformes; Cariamidae; Cariama", + "Carlito syrichta\tPhilippine tarsier\t1\t2\t-\t1868482\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Tarsiiformes; Tarsiidae; Carlito", + "Catharanthus roseus\tMadagascar periwinkle\t1\t1\t11\t4058\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Apocynaceae; Rauvolfioideae; Vinceae; Catharanthinae; Catharanthus", + "Cathartes aura\tturkey vulture\t1\t2\t-\t43455\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Ciconiiformes; Cathartidae; Cathartes", + "Cavia porcellus\tdomestic guinea pig\t1\t2\t-\t10141\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Caviidae; Cavia", + "Cebus capucinus imitator\t-\t1\t2\t-\t1737458\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Platyrrhini; Cebidae; Cebinae; Cebus; Cebus capucinus", + "Cecidomyiidae sp. BOLD-2016\t-\t1\t5\t-\t1881751\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Bibionomorpha; Sciaroidea; Cecidomyiidae; unclassified Cecidomyiidae", + "Cenchrus americanus\t-\t1\t1\t11\t4543\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Panicodae; Paniceae; Cenchrinae; Cenchrus", + "Centris flavifrons\t-\t1\t5\t-\t360639\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Anthophorinae; Centridini; Centris", + "Cephalotaxus hainanensis\t-\t1\t1\t11\t191701\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Cupressales; Taxaceae; Cephalotaxus", + "Cerapachys biroi\tclonal raider ant\t1\t5\t-\t443821\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Cerapachyinae; Cerapachyini; Cerapachys", + "Ceratina calcarata\t-\t1\t5\t-\t156304\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Xylocopinae; Ceratinini; Ceratina; Zadontomerus", + "Ceratitis capitata\tMediterranean fruit fly\t1\t5\t-\t7213\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Ceratitidini; Ceratitis; Ceratitis", + "Ceratotherium simum simum\tsouthern white rhinoceros\t1\t2\t-\t73337\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Perissodactyla; Rhinocerotidae; Ceratotherium; Ceratotherium simum", + "Cercis gigantea\t-\t1\t1\t11\t183790\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Cercideae; Cercis", + "Cercocebus atys\tsooty mangabey\t1\t2\t-\t9531\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Cercocebus", + "Chaetura pelagica\tchimney swift\t1\t2\t-\t8897\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Apodiformes; Apodidae; Chaetura", + "Charadrius vociferus\tkilldeer\t1\t2\t-\t50402\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Charadriiformes; Charadriidae; Charadrius", + "Chelonia mydas\tgreen sea turtle\t1\t2\t-\t8469\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Testudines; Cryptodira; Durocryptodira; Americhelydia; Chelonioidea; Cheloniidae; Chelonia", + "Cherax quadricarinatus\t-\t1\t5\t-\t27406\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Astacidea; Parastacoidea; Parastacidae; Cherax", + "Chilo suppressalis\tstriped riceborer\t1\t5\t-\t168631\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Pyraloidea; Crambidae; Crambinae; Chilo", + "Chinavia ubica\t-\t1\t5\t-\t1497372\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Neohemiptera; Prosorrhyncha; Heteroptera; Euheteroptera; Neoheteroptera; Panheteroptera; Pentatomomorpha; Pentatomoidea; Pentatomidae; Pentatominae; Chinavia", + "Chinchilla lanigera\tlong-tailed chinchilla\t1\t2\t-\t34839\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Chinchillidae; Chinchilla", + "Chlamydia trachomatis\t-\t11\t0\t-\t813\tBCT\tcellular organisms; Bacteria; PVC group; Chlamydiae; Chlamydiia; Chlamydiales; Chlamydiaceae; Chlamydia/Chlamydophila group; Chlamydia", + "Chlamydotis macqueenii\tMacqueen's bustard\t1\t2\t-\t187382\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gruiformes; Otididae; Chlamydotis", + "Chlorella sorokiniana\t-\t1\t1\t11\t3076\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Chlorophyta; Trebouxiophyceae; Chlorellales; Chlorellaceae; Chlorella", + "Chloris chloris\tEuropean greenfinch\t1\t2\t-\t37601\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Passeroidea; Fringillidae; Carduelinae; Chloris", + "Chlorocebus sabaeus\tgreen monkey\t1\t2\t-\t60711\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Chlorocebus", + "Chorispora bungeana\t-\t1\t1\t11\t238895\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Chorisporeae; Chorispora", + "Chromolaena odorata\t-\t1\t1\t11\t103745\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Asteroideae; Heliantheae alliance; Eupatorieae; Chromolaena", + "Chrysemys picta bellii\twestern painted turtle\t1\t2\t-\t8478\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Testudines; Cryptodira; Durocryptodira; Testudinoidea; Emydidae; Chrysemys; Chrysemys picta", + "Chrysochloris asiatica\tCape golden mole\t1\t2\t-\t185453\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Chrysochloridae; Chrysochlorinae; Chrysochloris", + "Chrysopa pallens\t-\t1\t5\t-\t417485\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Neuropterida; Neuroptera; Chrysopidae; Chrysopa", + "Chyphotes mellipes\t-\t1\t5\t-\t292179\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Bradynobaenidae; Chyphotinae; Chyphotes", + "Cicer arietinum\tchickpea\t1\t1\t11\t3827\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Cicereae; Cicer", + "Ciona intestinalis\tvase tunicate\t1\t13\t-\t7719\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Tunicata; Ascidiacea; Enterogona; Phlebobranchia; Cionidae; Ciona", + "Citrus clementina\t-\t1\t1\t11\t85681\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Sapindales; Rutaceae; Aurantioideae; Citrus", + "Citrus sinensis\tsweet orange\t1\t1\t11\t2711\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Sapindales; Rutaceae; Aurantioideae; Citrus", + "Clostridioides difficile\t-\t11\t0\t-\t1496\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Clostridia; Clostridiales; Peptostreptococcaceae; Clostridioides", + "Clostridium botulinum\t-\t11\t0\t-\t1491\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Clostridia; Clostridiales; Clostridiaceae; Clostridium", + "Clupea harengus\tAtlantic herring\t1\t2\t-\t7950\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Clupei; Clupeiformes; Clupeoidei; Clupeidae; Clupeinae; Clupea", + "Cocos nucifera\tcoconut palm\t1\t1\t11\t13894\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Arecales; Arecaceae; Arecoideae; Cocoseae; Attaleinae; Cocos", + "Colaphellus bowringi\t-\t1\t5\t-\t561076\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Chrysomeloidea; Chrysomelidae; Chrysomelinae; Chrysomelini; Colaphellus", + "Colius striatus\tspeckled mousebird\t1\t2\t-\t57412\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Coliiformes; Coliidae; Colius", + "Colobus angolensis palliatus\t-\t1\t2\t-\t336983\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Colobinae; Colobus; Colobus angolensis", + "Columba livia\trock pigeon\t1\t2\t-\t8932\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Columbiformes; Columbidae; Columba", + "Condylura cristata\tstar-nosed mole\t1\t2\t-\t143302\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Insectivora; Talpidae; Condylura", + "Copidosoma floridanum\t-\t1\t5\t-\t29053\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Chaldicoidea group; Chalcidoidea; Encyrtidae; Encyrtinae; Copidosoma", + "Corchorus capsularis\t-\t1\t1\t11\t210143\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Malvales; Malvaceae; Grewioideae; Apeibeae; Corchorus", + "Corvus brachyrhynchos\tAmerican crow\t1\t2\t-\t85066\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Corvoidea; Corvidae; Corvus", + "Corvus cornix cornix\t-\t1\t2\t-\t932674\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Corvoidea; Corvidae; Corvus; Corvus cornix", + "Corydalinae sp. KMRSPBM-2012\t-\t1\t5\t-\t1247484\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Neuropterida; Megaloptera; Corydalidae; Corydalinae; unclassified Corydalinae", + "Corylus avellana\t-\t1\t1\t11\t13451\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fagales; Betulaceae; Corylus", + "Costus pictus\t-\t1\t1\t11\t168183\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Zingiberales; Costaceae; Costus", + "Coturnix japonica\tJapanese quail\t1\t2\t-\t93934\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Galliformes; Phasianidae; Perdicinae; Coturnix", + "Crassostrea angulata\t-\t1\t5\t-\t558553\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Pteriomorphia; Ostreoida; Ostreoidea; Ostreidae; Crassostrea", + "Crassostrea gigas\tPacific oyster\t1\t5\t-\t29159\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Pteriomorphia; Ostreoida; Ostreoidea; Ostreidae; Crassostrea", + "Crataegus pinnatifida\t-\t1\t1\t11\t510735\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Maleae; Crataegus", + "Crepidula fornicata\t-\t1\t5\t-\t176853\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Caenogastropoda; Hypsogastropoda; Littorinimorpha; Calyptraeoidea; Calyptraeidae; Crepidula", + "Cricetulus griseus\tChinese hamster\t1\t2\t-\t10029\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Cricetidae; Cricetinae; Cricetulus", + "Crioscolia alcione\t-\t1\t5\t-\t1317732\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Scoliidae; Crioscolia", + "Ctenomys sociabilis\tsocial tuco-tuco\t1\t2\t-\t43321\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Ctenomyidae; Ctenomys", + "Cucumis melo\tmuskmelon\t1\t1\t11\t3656\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Cucurbitales; Cucurbitaceae; Benincaseae; Cucumis", + "Cucumis sativus\tcucumber\t1\t1\t11\t3659\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Cucurbitales; Cucurbitaceae; Benincaseae; Cucumis", + "Cunninghamia lanceolata\t-\t1\t1\t11\t28977\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Cupressales; Cupressaceae; Cunninghamia", + "Curcuma longa\tturmeric\t1\t1\t11\t136217\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Zingiberales; Zingiberaceae; Curcuma", + "Cuscuta pentagona\t-\t1\t1\t11\t112407\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Convolvulaceae; Cuscuteae; Cuscuta; Grammica; Cuscuta sect. Cleistogrammica", + "Cylicostephanus goldi\t-\t1\t5\t-\t71465\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Strongyloidea; Strongylidae; Cyathostominae; Cylicostephanus", + "Cynoglossus semilaevis\ttongue sole\t1\t2\t-\t244447\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Carangaria; Pleuronectiformes; Pleuronectoidei; Cynoglossidae; Cynoglossinae; Cynoglossus", + "Cynopterus sphinx\tIndian short-nosed fruit bat\t1\t2\t-\t9400\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Megachiroptera; Pteropodidae; Pteropodinae; Cynopterus", + "Cypridininae sp. BMR-2011\t-\t1\t5\t-\t1032739\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Ostracoda; Myodocopa; Myodocopida; Cypridinoidea; Cypridinidae; unclassified Cypridinidae", + "Cyprinodon variegatus\tsheepshead minnow\t1\t2\t-\t28743\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Cyprinodontidae; Cyprinodontinae; Cyprinodontini; Cyprinodon", + "Cyprinus carpio\tcommon carp\t1\t2\t-\t7962\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Cyprinus", + "Dahlia pinnata\t-\t1\t1\t11\t101596\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Asteroideae; Heliantheae alliance; Coreopsideae; Dahlia", + "Danio rerio\tzebrafish\t1\t2\t-\t7955\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Danio", + "Daphnia magna\t-\t1\t5\t-\t35525\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Branchiopoda; Phyllopoda; Diplostraca; Cladocera; Anomopoda; Daphniidae; Daphnia", + "Dastarcus helophoroides\t-\t1\t5\t-\t1169899\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Cucujoidea; Bothrideridae; Dastarcus", + "Dasypus novemcinctus\tnine-banded armadillo\t1\t2\t-\t9361\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Xenarthra; Cingulata; Dasypodidae; Dasypus", + "Daucus carota subsp. sativus\t-\t1\t1\t11\t79200\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Apiales; Apiineae; Apiaceae; Apioideae; Scandiceae; Daucinae; Daucus; Daucus sect. Daucus; Daucus carota", + "Dendroctonus ponderosae\tmountain pine beetle\t1\t5\t-\t77166\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Curculionoidea; Curculionidae; Scolytinae; Dendroctonus", + "Dermacentor variabilis\tAmerican dog tick\t1\t5\t-\t34621\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Ixodida; Ixodoidea; Ixodidae; Rhipicephalinae; Dermacentor", + "Dermanyssus gallinae\t-\t1\t5\t-\t34641\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Mesostigmata; Monogynaspida; Gamasina; Dermanyssoidea; Dermanyssidae; Dermanyssus", + "Dianthus caryophyllus\tclove pink\t1\t1\t11\t3570\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Caryophyllaceae; Caryophylleae; Dianthus", + "Diaphorina citri\tAsian citrus psyllid\t1\t5\t-\t121845\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Sternorrhyncha; Psylliformes; Psylloidea; Psyllidae; Diaphorina", + "Dicrocoelium dendriticum\t-\t1\t9\t-\t57078\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Plagiorchiida; Xiphidiata; Plagiorchioidea; Dicrocoeliidae; Dicrocoelium", + "Dinobryon sp. LO226KS\t-\t1\t1\t11\t1825119\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; Chromulinales; Dinobryaceae; Dinobryon", + "Dinoponera quadriceps\t-\t1\t5\t-\t609295\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Ponerinae; Ponerini; Dinoponera", + "Diospyros lotus\t-\t1\t1\t11\t55363\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Ericales; Ebenaceae; Diospyros", + "Diphyllobothrium latum\t-\t1\t9\t-\t60516\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Cestoda; Eucestoda; Diphyllobothriidea; Diphyllobothriidae; Diphyllobothrium", + "Dipodomys ordii\tOrd's kangaroo rat\t1\t2\t-\t10020\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Heteromyidae; Dipodomyinae; Dipodomys", + "Dorcoceras hygrometricum\t-\t1\t1\t11\t472368\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Gesneriaceae; Didymocarpoideae; Trichosporeae; Loxocarpinae; Dorcoceras", + "Drosophila ananassae\t-\t1\t5\t-\t7217\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; ananassae subgroup; ananassae species complex", + "Drosophila grimshawi\t-\t1\t5\t-\t7222\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Hawaiian Drosophila; picture wing clade; grimshawi clade; grimshawi group; grimshawi subgroup", + "Drosophila melanogaster\tfruit fly\t1\t5\t-\t7227\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; melanogaster subgroup", + "Drosophila miranda\t-\t1\t5\t-\t7229\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; obscura group; pseudoobscura subgroup", + "Drosophila mojavensis\t-\t1\t5\t-\t7230\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Drosophila; repleta group; mulleri subgroup; mojavensis species complex", + "Drosophila persimilis\t-\t1\t5\t-\t7234\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; obscura group; pseudoobscura subgroup", + "Drosophila pseudoobscura pseudoobscura\t-\t1\t5\t-\t46245\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; obscura group; pseudoobscura subgroup; Drosophila pseudoobscura", + "Drosophila rhopaloa\t-\t1\t5\t-\t1041015\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; rhopaloa subgroup", + "Drosophila sechellia\t-\t1\t5\t-\t7238\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; melanogaster subgroup", + "Drosophila simulans\t-\t1\t5\t-\t7240\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; melanogaster subgroup", + "Drosophila suzukii\t-\t1\t5\t-\t28584\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; suzukii subgroup", + "Drosophila virilis\t-\t1\t5\t-\t7244\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Drosophila; virilis group", + "Drosophila willistoni\t-\t1\t5\t-\t7260\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; willistoni group; willistoni subgroup", + "Drosophila yakuba\t-\t1\t5\t-\t7245\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; melanogaster subgroup", + "Dugesia japonica\t-\t1\t9\t-\t6161\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Rhabditophora; Seriata; Tricladida; Continenticola; Geoplanoidea; Dugesiidae; Dugesia", + "Echinarachnius parma\t-\t1\t9\t-\t869203\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Euechinoidea; Gnathostomata; Clypeasteroida; Echinarachniidae; Echinarachnius", + "Echinaster spinulosus\t-\t1\t9\t-\t1451296\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Spinulosacea; Spinulosida; Echinasteridae; Echinaster", + "Echinops telfairi\tsmall Madagascar hedgehog\t1\t2\t-\t9371\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Tenrecidae; Tenrecinae; Echinops", + "Echinostoma caproni\t-\t1\t9\t-\t27848\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Plagiorchiida; Echinostomata; Echinostomatoidea; Echinostomatidae; Echinostoma", + "Eidolon helvum\tstraw-colored fruit bat\t1\t2\t-\t77214\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Megachiroptera; Pteropodidae; Pteropodinae; Eidolon", + "Eimeria mitis\t-\t1\t4\t4\t44415\tINV\tcellular organisms; Eukaryota; Alveolata; Apicomplexa; Conoidasida; Coccidia; Eucoccidiorida; Eimeriorina; Eimeriidae; Eimeria", + "Elaeis guineensis\tAfrican oil palm\t1\t1\t11\t51953\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Arecales; Arecaceae; Arecoideae; Cocoseae; Elaeidinae; Elaeis", + "Elephantulus edwardii\tCape elephant shrew\t1\t2\t-\t28737\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Macroscelidea; Macroscelididae; Elephantulus", + "Elliptio complanata\teastern elliptio\t1\t5\t-\t55832\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Palaeoheterodonta; Unionoida; Unionoidea; Unionidae; Ambleminae; Elliptio", + "Elodea nuttallii\t-\t1\t1\t11\t55313\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Alismatales; Hydrocharitaceae; Elodea", + "Emiliania huxleyi CCMP1516\t-\t1\t4\t11\t280463\tPLN\tcellular organisms; Eukaryota; Haptophyceae; Isochrysidales; Noelaerhabdaceae; Emiliania; Emiliania huxleyi", + "Enterobacter cloacae\t-\t11\t0\t-\t550\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Enterobacter; Enterobacter cloacae complex", + "Enterococcus faecalis\t-\t11\t0\t-\t1351\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Enterococcaceae; Enterococcus", + "Enterococcus faecium\t-\t11\t0\t-\t1352\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Enterococcaceae; Enterococcus", + "Epipyxis sp. PR26KG\t-\t1\t1\t11\t1825121\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; Chromulinales; Dinobryaceae; Epipyxis", + "Eptesicus fuscus\tbig brown bat\t1\t2\t-\t29078\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Vespertilionidae; Eptesicus", + "Equus asinus\tass\t1\t2\t-\t9793\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Perissodactyla; Equidae; Equus; Asinus", + "Equus caballus\thorse\t1\t2\t-\t9796\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Perissodactyla; Equidae; Equus; Equus", + "Equus przewalskii\tPrzewalski's horse\t1\t2\t-\t9798\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Perissodactyla; Equidae; Equus; Equus", + "Erinaceus europaeus\twestern European hedgehog\t1\t2\t-\t9365\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Insectivora; Erinaceidae; Erinaceinae; Erinaceus", + "Eriocheir sinensis\tChinese mitten crab\t1\t5\t-\t95602\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Brachyura; Eubrachyura; Thoracotremata; Grapsoidea; Varunidae; Eriocheir", + "Erythranthe guttata\tspotted monkey flower\t1\t1\t11\t4155\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Phrymaceae; Erythranthe", + "Escherichia coli\t-\t11\t0\t-\t562\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Escherichia", + "Esox lucius\tnorthern pike\t1\t2\t-\t8010\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Protacanthopterygii; Esociformes; Esocidae; Esox", + "Eucalyptus camaldulensis\tMurray red gum\t1\t1\t11\t34316\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Myrtales; Myrtaceae; Myrtoideae; Eucalypteae; Eucalyptus", + "Eucalyptus grandis\t-\t1\t1\t11\t71139\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Myrtales; Myrtaceae; Myrtoideae; Eucalypteae; Eucalyptus", + "Eucidaris tribuloides\t-\t1\t9\t-\t7632\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Perischoechinoidea; Cidaroida; Cidaridae; Eucidaris", + "Eucyclops serrulatus\t-\t1\t5\t-\t84317\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Podoplea; Cyclopoida; Cyclopidae; Eucyclops", + "Eufriesea mexicana\t-\t1\t5\t-\t516756\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Bombinae; Euglossini; Eufriesea", + "Eurypyga helias\tsunbittern\t1\t2\t-\t54383\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gruiformes; Eurypygidae; Eurypyga", + "Eustoma exaltatum subsp. russellianum\t-\t1\t1\t11\t52518\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Gentianaceae; Chironieae; Eustoma; Eustoma exaltatum", + "Evechinus chloroticus\t-\t1\t9\t-\t137513\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Euechinoidea; Echinacea; Echinoida; Echinometridae; Evechinus", + "Exaiptasia pallida\t-\t1\t4\t-\t1720309\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Actiniaria; Aiptasiidae; Exaiptasia", + "Exoneura robusta\t-\t1\t5\t-\t175328\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Xylocopinae; Allodapini; Exoneura", + "Extatosoma tiaratum\tgiant prickly stick insect\t1\t5\t-\t7024\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Phasmatodea; Verophasmatodea; Anareolatae; Phasmatidae; Tropidoderinae; Extatosoma", + "Fagopyrum esculentum\tcommon buckwheat\t1\t1\t11\t3617\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Polygonaceae; Polygonoideae; Fagopyreae; Fagopyrum", + "Falco cherrug\tSaker falcon\t1\t2\t-\t345164\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Falconiformes; Falconidae; Falco", + "Falco peregrinus\tperegrine falcon\t1\t2\t-\t8954\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Falconiformes; Falconidae; Falco", + "Fasciola hepatica\tliver fluke\t1\t9\t-\t6192\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Plagiorchiida; Echinostomata; Echinostomatoidea; Fasciolidae; Fasciola", + "Felis catus\tdomestic cat\t1\t2\t-\t9685\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Feliformia; Felidae; Felinae; Felis", + "Ficedula albicollis\tcollared flycatcher\t1\t2\t-\t59894\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Muscicapidae; Ficedula", + "Ficus carica\tcommon fig\t1\t1\t11\t3494\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Moraceae; Ficus", + "fish metagenome\t-\t11\t2\t11\t496924\tENV\tunclassified sequences; metagenomes; organismal metagenomes", + "Folsomia candida\t-\t1\t5\t-\t158441\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Collembola; Collembola; Entomobryomorpha; Isotomoidea; Isotomidae; Proisotominae; Folsomia", + "Fopius arisanus\t-\t1\t5\t-\t64838\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Ichneumonoidea; Braconidae; Opiinae; Fopius", + "Formica aquilonia\t-\t1\t5\t-\t258703\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica", + "Formica cinerea\t-\t1\t5\t-\t609761\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica", + "Formica exsecta\t-\t1\t5\t-\t72781\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica", + "Formica fusca\t-\t1\t5\t-\t72779\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica", + "Formica pratensis\t-\t1\t5\t-\t221681\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica", + "Formica pressilabris\t-\t1\t5\t-\t609858\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica", + "Formica truncorum\t-\t1\t5\t-\t72783\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica", + "Fragaria vesca subsp. vesca\t-\t1\t1\t11\t101020\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Rosoideae; Potentilleae; Fragariinae; Fragaria; Fragaria vesca", + "Fragaria x ananassa\tstrawberry\t1\t1\t11\t3747\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Rosoideae; Potentilleae; Fragariinae; Fragaria", + "Frankliniella occidentalis\twestern flower thrips\t1\t5\t-\t133901\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Thysanoptera; Terebrantia; Thripoidea; Thripidae; Thripinae; Frankliniella", + "Fraxinus excelsior\tEuropean ash\t1\t1\t11\t38873\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Oleaceae; Oleeae; Fraxinus", + "Fukomys damarensis\tDamara mole-rat\t1\t2\t-\t885580\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Bathyergidae; Fukomys", + "Fulmarus glacialis\tnorthern fulmar\t1\t2\t-\t30455\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Procellariiformes; Procellariidae; Procellariinae; Fulmarus", + "Fundulus grandis\tGulf killifish\t1\t2\t-\t34779\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Fundulidae; Fundulus", + "Fundulus heteroclitus\tmummichog\t1\t2\t-\t8078\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Fundulidae; Fundulus", + "Gadus morhua\tAtlantic cod\t1\t2\t-\t8049\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Paracanthomorphacea; Zeiogadaria; Gadariae; Gadiformes; Gadoidei; Gadidae; Gadus", + "Galeopterus variegatus\tSunda flying lemur\t1\t2\t-\t482537\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Dermoptera; Cynocephalidae; Galeopterus", + "Gallus gallus\tchicken\t1\t2\t-\t9031\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Galliformes; Phasianidae; Phasianinae; Gallus", + "Gammarus chevreuxi\t-\t1\t5\t-\t732109\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Amphipoda; Senticaudata; Gammarida; Gammaridira; Gammaroidea; Gammaridae; Gammarus", + "Gardenia jasminoides\t-\t1\t1\t11\t114476\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Rubiaceae; Ixoroideae; Gardenieae; Gardenia", + "Gavia stellata\tred-throated loon\t1\t2\t-\t37040\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gaviiformes; Gaviidae; Gavia", + "Gavialis gangeticus\tGharial\t1\t2\t-\t94835\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Crocodylia; Longirostres; Gavialidae; Gavialinae; Gavialis", + "Gekko japonicus\t-\t1\t2\t-\t146911\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Gekkota; Gekkonidae; Gekkoninae; Gekko", + "Geminigera cryophila\t-\t1\t1\t11\t46947\tPLN\tcellular organisms; Eukaryota; Cryptophyta; Pyrenomonadales; Geminigeraceae; Geminigera", + "Gene trapping vector VICTR76\t-\t11\t0\t11\t447635\tSYN\tother sequences; artificial sequences; vectors", + "Gentiana macrophylla\t-\t1\t1\t11\t50765\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Gentianaceae; Gentianeae; Gentiana", + "Geospiza fortis\tmedium ground-finch\t1\t2\t-\t48883\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Thraupidae; Geospiza", + "Gerbera hybrid cultivar\t-\t1\t1\t11\t18101\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Mutisioideae; Mutisieae; Gerbera", + "Gigaspora margarita\t-\t1\t4\t-\t4874\tPLN\tcellular organisms; Eukaryota; Opisthokonta; Fungi; Mucoromycota; Glomeromycotina; Glomeromycetes; Diversisporales; Gigasporaceae; Gigaspora", + "Glomeris pustulata\t-\t1\t5\t-\t1288506\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Myriapoda; Diplopoda; Pentazonia; Glomerida; Glomeridae; Glomeris", + "Glossoscolex paulistus\t-\t1\t5\t-\t1046353\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Annelida; Clitellata; Oligochaeta; Haplotaxida; Lumbricina; Glossoscolecidae; Glossoscolex", + "Glycera dibranchiata\t-\t1\t5\t-\t6350\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Annelida; Polychaeta; Palpata; Aciculata; Phyllodocida; Glyceridae; Glycera", + "Glycine max\tsoybean\t1\t1\t11\t3847\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Glycine; Soja", + "Gongylonema pulchrum\t-\t1\t5\t-\t637853\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Spirurida; Spiruroidea; Gongylonematidae; Gongylonema", + "Gorilla gorilla gorilla\twestern lowland gorilla\t1\t2\t-\t9595\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Gorilla; Gorilla gorilla", + "Gossypium arboreum\t-\t1\t1\t11\t29729\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Malvales; Malvaceae; Malvoideae; Gossypium", + "Gossypium hirsutum\t-\t1\t1\t11\t3635\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Malvales; Malvaceae; Malvoideae; Gossypium", + "Gossypium raimondii\t-\t1\t1\t11\t29730\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Malvales; Malvaceae; Malvoideae; Gossypium", + "Graminella nigrifrons\t-\t1\t5\t-\t30127\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Clypeorrhyncha; Membracoidea; Cicadellidae; Deltocephalinae; Graminella", + "gut metagenome\t-\t11\t2\t11\t749906\tENV\tunclassified sequences; metagenomes; organismal metagenomes", + "Habropoda laboriosa\t-\t1\t5\t-\t597456\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Anthophorinae; Anthophorini; Habropoda", + "Haliaeetus albicilla\twhite-tailed eagle\t1\t2\t-\t8969\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Falconiformes; Accipitridae; Accipitrinae; Haliaeetus", + "Halyomorpha halys\tbrown marmorated stink bug\t1\t5\t-\t286706\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Neohemiptera; Prosorrhyncha; Heteroptera; Euheteroptera; Neoheteroptera; Panheteroptera; Pentatomomorpha; Pentatomoidea; Pentatomidae; Pentatominae; Halyomorpha", + "Hammondia hammondi\t-\t1\t4\t4\t99158\tINV\tcellular organisms; Eukaryota; Alveolata; Apicomplexa; Conoidasida; Coccidia; Eucoccidiorida; Eimeriorina; Sarcocystidae; Hammondia", + "Haplochromis burtoni\tBurton's mouthbrooder\t1\t2\t-\t8153\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Haplochromini; Haplochromis", + "Harpegnathos saltator\tJerdon's jumping ant\t1\t5\t-\t610380\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Ponerinae; Ponerini; Harpegnathos", + "Helicobacter pylori\t-\t11\t0\t-\t210\tBCT\tcellular organisms; Bacteria; Proteobacteria; delta/epsilon subdivisions; Epsilonproteobacteria; Campylobacterales; Helicobacteraceae; Helicobacter", + "Helicoverpa assulta\t-\t1\t5\t-\t52344\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Heliothinae; Helicoverpa", + "Heligmosomoides polygyrus\t-\t1\t5\t-\t6339\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Trichostrongyloidea; Heligmosomatidae; Heligmosomoides", + "Henricia sp. AR-2014\t-\t1\t9\t-\t1462731\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Spinulosacea; Spinulosida; Echinasteridae; Henricia", + "Hepatitis B virus\t-\t1\t0\t-\t10407\tVRL\tViruses; Retro-transcribing viruses; Hepadnaviridae; Orthohepadnavirus", + "Hepatitis C virus\t-\t1\t0\t-\t11103\tVRL\tViruses; ssRNA viruses; ssRNA positive-strand viruses, no DNA stage; Flaviviridae; Hepacivirus", + "Heterocephalus glaber\tnaked mole-rat\t1\t2\t-\t10181\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Bathyergidae; Heterocephalus", + "Heterodera glycines\tsoybean cyst nematode\t1\t5\t-\t51029\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Tylenchida; Tylenchina; Tylenchoidea; Heteroderidae; Heteroderinae; Heterodera", + "Hevea brasiliensis\t-\t1\t1\t11\t3981\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Euphorbiaceae; Crotonoideae; Micrandreae; Hevea", + "Homalodisca liturata\t-\t1\t5\t-\t320908\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Clypeorrhyncha; Membracoidea; Cicadellidae; Cicadellinae; unclassified Cicadellinae; Homalodisca", + "Homalodisca vitripennis\tglassy-winged sharpshooter\t1\t5\t-\t197043\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Clypeorrhyncha; Membracoidea; Cicadellidae; Cicadellinae; unclassified Cicadellinae; Homalodisca", + "Homo sapiens\thuman\t1\t2\t-\t9606\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Homo", + "Hordeum pubiflorum\t-\t1\t1\t11\t112521\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Hordeinae; Hordeum", + "Hordeum vulgare\t-\t1\t1\t11\t4513\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Hordeinae; Hordeum", + "Hordeum vulgare subsp. vulgare\tdomesticated barley\t1\t1\t11\t112509\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Hordeinae; Hordeum; Hordeum vulgare", + "human gut metagenome\t-\t11\t2\t11\t408170\tENV\tunclassified sequences; metagenomes; organismal metagenomes", + "Human immunodeficiency virus 1\t-\t1\t0\t-\t11676\tVRL\tViruses; Retro-transcribing viruses; Retroviridae; Orthoretrovirinae; Lentivirus; Primate lentivirus group", + "Humulus lupulus\tEuropean hop\t1\t1\t11\t3486\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Cannabaceae; Humulus", + "Humulus lupulus var. cordifolius\t-\t1\t1\t11\t278022\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Cannabaceae; Humulus; Humulus lupulus", + "Humulus lupulus var. lupulus\t-\t1\t1\t11\t1571165\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Cannabaceae; Humulus; Humulus lupulus", + "Hyalella azteca\t-\t1\t5\t-\t294128\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Amphipoda; Senticaudata; Talitrida; Talitroidea; Hyalellidae; Hyalella", + "Hyas araneus\t-\t1\t5\t-\t361634\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Brachyura; Eubrachyura; Heterotremata; Majoidea; Majidae; Hyas", + "Hydra vulgaris\t-\t1\t4\t-\t6087\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Hydrozoa; Hydroidolina; Anthoathecata; Aplanulata; Hydridae; Hydra", + "Hydractinia symbiolongicarpus\t-\t1\t4\t-\t13093\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Hydrozoa; Hydroidolina; Anthoathecata; Filifera; Hydractiniidae; Hydractinia", + "Hynobius chinensis\tChinese salamander\t1\t2\t-\t288313\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Caudata; Cryptobranchoidea; Hynobiidae; Hynobius; Hynobius", + "Hynobius retardatus\tHokkaido salamander\t1\t2\t-\t36312\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Caudata; Cryptobranchoidea; Hynobiidae; Hynobius; Satobius", + "Hypsizygus marmoreus\t-\t1\t4\t-\t39966\tPLN\tcellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Basidiomycota; Agaricomycotina; Agaricomycetes; Agaricomycetidae; Agaricales; Lyophyllaceae; Hypsizygus", + "Ictalurus punctatus\tchannel catfish\t1\t2\t-\t7998\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Characiphysae; Siluriformes; Siluroidei; Ictaluridae; Ictalurus", + "Ictidomys tridecemlineatus\tthirteen-lined ground squirrel\t1\t2\t-\t43179\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Sciuridae; Xerinae; Marmotini; Ictidomys", + "Ipomoea batatas\tsweet potato\t1\t1\t11\t4120\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Convolvulaceae; Ipomoeeae; Ipomoea", + "Ipomoea nil\tJapanese morning glory\t1\t1\t11\t35883\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Convolvulaceae; Ipomoeeae; Ipomoea", + "Ipomoea purpurea\tcommon morning-glory\t1\t1\t11\t4121\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Convolvulaceae; Ipomoeeae; Ipomoea", + "Ipomoea trifida\t-\t1\t1\t11\t35884\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Convolvulaceae; Ipomoeeae; Ipomoea", + "Ixodes ricinus\tcastor bean tick\t1\t5\t-\t34613\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Ixodida; Ixodoidea; Ixodidae; Ixodinae; Ixodes", + "Ixodes scapularis\tblack-legged tick\t1\t5\t-\t6945\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Ixodida; Ixodoidea; Ixodidae; Ixodinae; Ixodes", + "Jaculus jaculus\tlesser Egyptian jerboa\t1\t2\t-\t51337\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Dipodidae; Dipodinae; Jaculus", + "Jatropha curcas\t-\t1\t1\t11\t180498\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Euphorbiaceae; Crotonoideae; Jatropheae; Jatropha", + "Juglans regia\tEnglish walnut\t1\t1\t11\t51240\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fagales; Juglandaceae; Juglans", + "Karelinia caspia\t-\t1\t1\t11\t313960\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Asteroideae; Inuleae; Plucheinae; Karelinia", + "Kerria lacca\tcommon lac scale\t1\t5\t-\t473130\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Sternorrhyncha; Aphidiformes; Coccoidea; Kerriidae; Kerria", + "Klebsiella pneumoniae\t-\t11\t0\t-\t573\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Klebsiella", + "Kryptolebias marmoratus\tmangrove rivulus\t1\t2\t-\t37003\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Rivulidae; Kryptolebias", + "Lactuca sativa\t-\t1\t1\t11\t4236\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Cichorioideae; Cichorieae; Lactucinae; Lactuca", + "Lactuca serriola\t-\t1\t1\t11\t75943\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Cichorioideae; Cichorieae; Lactucinae; Lactuca", + "Lagenaria siceraria\twhite-flowered gourd\t1\t1\t11\t3668\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Cucurbitales; Cucurbitaceae; Benincaseae; Lagenaria", + "Landoltia punctata\t-\t1\t1\t11\t50518\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Alismatales; Araceae; Lemnoideae; Landoltia", + "Larimichthys crocea\tlarge yellow croaker\t1\t2\t-\t215358\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Eupercaria incertae sedis; Sciaenidae; Larimichthys", + "Larix kaempferi\t-\t1\t1\t11\t54800\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Larix", + "Lasius neglectus\t-\t1\t5\t-\t111072\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Lasiini; Lasius; Lasius", + "Lasius turcicus\t-\t1\t5\t-\t235463\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Lasiini; Lasius; Lasius", + "Lates calcarifer\tbarramundi perch\t1\t2\t-\t8187\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Carangaria; Carangiaria incertae sedis; Centropomidae; Lates", + "Lathyrus sativus\t-\t1\t1\t11\t3860\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Fabeae; Lathyrus", + "Latimeria chalumnae\tcoelacanth\t1\t2\t-\t7897\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Coelacanthimorpha; Coelacanthiformes; Coelacanthidae; Latimeria", + "Latimeria menadoensis\tMenado coelacanth\t1\t2\t-\t106881\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Coelacanthimorpha; Coelacanthiformes; Coelacanthidae; Latimeria", + "Latrodectus hesperus\twestern black widow\t1\t5\t-\t256737\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Araneae; Araneomorphae; Entelegynae; Orbiculariae; Araneoidea; Theridiidae; Latrodectus", + "Legionella pneumophila\t-\t11\t0\t-\t446\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Legionellales; Legionellaceae; Legionella", + "Lepeophtheirus salmonis\tsalmon louse\t1\t5\t-\t72036\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Podoplea; Siphonostomatoida; Caligidae; Lepeophtheirus", + "Lepidonotothen nudifrons\tyellowfin notie\t1\t2\t-\t83203\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Perciformes; Notothenioidei; Nototheniidae; Lepidonotothen", + "Lepidothrix coronata\tblue-crowned manakin\t1\t2\t-\t321398\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Pipridae; Lepidothrix", + "Lepisosteus oculatus\tspotted gar\t1\t2\t-\t7918\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Holostei; Semionotiformes; Lepisosteidae; Lepisosteus", + "Leptasterias sp. AR-2014\t-\t1\t9\t-\t1462732\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Leptasterias", + "Leptonychotes weddellii\tWeddell seal\t1\t2\t-\t9713\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Phocidae; Leptonychotes", + "Leptosomus discolor\tcuckoo roller\t1\t2\t-\t188344\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Coraciiformes; Leptosomidae; Leptosomus", + "Leptospira interrogans\t-\t11\t0\t-\t173\tBCT\tcellular organisms; Bacteria; Spirochaetes; Spirochaetia; Leptospirales; Leptospiraceae; Leptospira", + "Limnephilus lunatus\t-\t1\t5\t-\t1218281\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Trichoptera; Integripalpia; Plenitentoria; Limnephiloidea; Limnephilidae; Limnephilinae; Limnephilini; Limnephilus", + "Limnoperna fortunei\t-\t1\t5\t-\t356393\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Pteriomorphia; Mytiloida; Mytiloidea; Mytilidae; Mytilinae; Limnoperna", + "Limulus polyphemus\tAtlantic horseshoe crab\t1\t5\t-\t6850\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Merostomata; Xiphosura; Limulidae; Limulus", + "Linepithema humile\tArgentine ant\t1\t5\t-\t83485\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Dolichoderinae; Linepithema", + "Lingula anatina\t-\t1\t5\t-\t7574\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Brachiopoda; Linguliformea; Lingulata; Lingulida; Linguloidea; Lingulidae; Lingula", + "Lingulodinium polyedrum\t-\t1\t4\t11\t160621\tPLN\tcellular organisms; Eukaryota; Alveolata; Dinophyceae; Gonyaulacales; Lingulodinium", + "Lipotes vexillifer\tYangtze River dolphin\t1\t2\t-\t118797\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Cetacea; Odontoceti; Lipotidae; Lipotes", + "Listeria monocytogenes\t-\t11\t0\t-\t1639\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Bacillales; Listeriaceae; Listeria", + "Litchi chinensis\t-\t1\t1\t11\t151069\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Sapindales; Sapindaceae; Litchi", + "Litopenaeus vannamei\tPacific white shrimp\t1\t5\t-\t6689\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Dendrobranchiata; Penaeoidea; Penaeidae; Litopenaeus", + "Loa loa\teye worm\t1\t5\t-\t7209\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Spirurida; Filarioidea; Onchocercidae; Loa", + "Lolium perenne\t-\t1\t1\t11\t4522\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Poodae; Poeae; Poeae Chloroplast Group 2 (Poeae type); Loliinae; Lolium", + "Lotus corniculatus\t-\t1\t1\t11\t47247\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Loteae; Lotus", + "Loxodonta africana\tAfrican savanna elephant\t1\t2\t-\t9785\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Proboscidea; Elephantidae; Loxodonta", + "Luidia clathrata\t-\t1\t9\t-\t133437\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Valvatacea; Paxillosida; Luidiidae; Luidia", + "Lupinus angustifolius\tnarrow-leaved blue lupine\t1\t1\t11\t3871\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Genisteae; Lupinus", + "Lygodium japonicum\t-\t1\t1\t11\t13824\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Moniliformopses; Polypodiidae; Schizaeales; Lygodiaceae; Lygodium", + "Lygus hesperus\tlygus bug\t1\t5\t-\t30085\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Neohemiptera; Prosorrhyncha; Heteroptera; Euheteroptera; Neoheteroptera; Panheteroptera; Cimicomorpha; Cimicoidea; Miridae; Mirinae; Mirini; Lygus", + "Lymnaea stagnalis\tgreat pond snail\t1\t5\t-\t6523\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Heterobranchia; Euthyneura; Panpulmonata; Hygrophila; Lymnaeoidea; Lymnaeidae; Lymnaea", + "Lynx pardinus\tSpanish lynx\t1\t2\t-\t191816\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Feliformia; Felidae; Felinae; Lynx", + "Lytechinus variegatus\tgreen sea urchin\t1\t9\t-\t7654\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Euechinoidea; Echinacea; Temnopleuroida; Toxopneustidae; Lytechinus", + "Macaca fascicularis\tcrab-eating macaque\t1\t2\t-\t9541\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Macaca", + "Macaca mulatta\tRhesus monkey\t1\t2\t-\t9544\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Macaca", + "Macaca nemestrina\tpig-tailed macaque\t1\t2\t-\t9545\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Macaca", + "Macropus eugenii\ttammar wallaby\t1\t2\t-\t9315\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Metatheria; Diprotodontia; Macropodidae; Macropus", + "Malus domestica\tapple\t1\t1\t11\t3750\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Maleae; Malus", + "Manacus vitellinus\tgolden-collared manakin\t1\t2\t-\t328815\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Pipridae; Manacus", + "Mandrillus leucophaeus\tdrill\t1\t2\t-\t9568\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Mandrillus", + "Mangifera indica\tmango\t1\t1\t11\t29780\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Sapindales; Anacardiaceae; Mangifera", + "Manihot esculenta\tcassava\t1\t1\t11\t3983\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Euphorbiaceae; Crotonoideae; Manihoteae; Manihot", + "Manis javanica\tMalayan pangolin\t1\t2\t-\t9974\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Pholidota; Manidae; Manis", + "marine metagenome\t-\t11\t2\t11\t408172\tENV\tunclassified sequences; metagenomes; ecological metagenomes", + "marine sediment metagenome\t-\t11\t2\t11\t412755\tENV\tunclassified sequences; metagenomes; ecological metagenomes", + "Marmota marmota marmota\tAlpine marmot\t1\t2\t-\t9994\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Sciuridae; Xerinae; Marmotini; Marmota; Marmota marmota", + "Marthasterias glacialis\tspiny starfish\t1\t9\t-\t7609\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Marthasterias", + "Maylandia zebra\tzebra mbuna\t1\t2\t-\t106582\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Haplochromini; Maylandia; Maylandia zebra complex", + "Medauroidea extradentata\t-\t1\t5\t-\t614211\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Phasmatodea; Verophasmatodea; Anareolatae; Phasmatidae; Phasmatinae; Clitumnini; Medauroidea", + "Medicago sativa\t-\t1\t1\t11\t3879\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Trifolieae; Medicago", + "Medicago truncatula\tbarrel medic\t1\t1\t11\t3880\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Trifolieae; Medicago", + "Megachile rotundata\talfalfa leafcutting bee\t1\t5\t-\t143995\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Megachilidae; Megachilinae; Megachilini; Megachile", + "Megaderma lyra\tIndian false vampire\t1\t2\t-\t9413\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Megadermatidae; Megaderma", + "Megajapyx sp. UVienna-2012\t-\t1\t5\t-\t1136246\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Diplura; Diplura; Dicellurata; Japygoidea; Japygidae; Japyginae; Megajapyx", + "Megaselia scalaris\t-\t1\t5\t-\t36166\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Aschiza; Platypezoidea; Phoridae; Metopininae; Megaseliini; Megaselia", + "Meleagris gallopavo\tturkey\t1\t2\t-\t9103\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Galliformes; Phasianidae; Meleagridinae; Meleagris", + "Melopsittacus undulatus\tbudgerigar\t1\t2\t-\t13146\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Psittaciformes; Psittaculidae; Melopsittacus", + "Mengenilla moldrzyki\t-\t1\t5\t-\t1155016\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Strepsiptera; Mengenillidia; Mengenilloidea; Mengenillidae; Mengenilla", + "Meretrix meretrix\tAsiatic hard clam\t1\t5\t-\t291251\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Heteroconchia; Euheterodonta; Veneroida; Veneroidea; Veneridae; Meretrix", + "Merops nubicus\tcarmine bee-eater\t1\t2\t-\t57421\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Coraciiformes; Meropidae; Merops", + "Mesembryanthemum crystallinum\tcommon iceplant\t1\t1\t11\t3544\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Aizoaceae; Mesembryanthemum; Cryophytum", + "Mesitornis unicolor\tbrown roatelo\t1\t2\t-\t54374\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gruiformes; Mesitornithidae; Mesitornis", + "Mesocricetus auratus\tgolden hamster\t1\t2\t-\t10036\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Cricetidae; Cricetinae; Mesocricetus", + "Metaseiulus occidentalis\twestern predatory mite\t1\t5\t-\t34638\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Mesostigmata; Monogynaspida; Gamasina; Phytoseioidea; Phytoseiidae; Typhlodrominae; Metaseiulus", + "Microcebus murinus\tgray mouse lemur\t1\t2\t-\t30608\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Strepsirrhini; Lemuriformes; Cheirogaleidae; Microcebus", + "Microplitis demolitor\t-\t1\t5\t-\t69319\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Ichneumonoidea; Braconidae; Microgastrinae; Microplitis", + "Micropterix calthella\t-\t1\t5\t-\t41027\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Zeugloptera; Micropterigidae; Micropterix", + "Micropterus floridanus\tFlorida bass\t1\t2\t-\t225391\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Centrarchiformes; Centrarchoidei; Centrarchidae; Micropterus", + "Micropterus salmoides\tlargemouth bass\t1\t2\t-\t27706\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Centrarchiformes; Centrarchoidei; Centrarchidae; Micropterus", + "Micropterus salmoides salmoides\tnorthern largemouth bass\t1\t2\t-\t489037\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Centrarchiformes; Centrarchoidei; Centrarchidae; Micropterus; Micropterus salmoides", + "Microtus ochrogaster\tprairie vole\t1\t2\t-\t79684\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Cricetidae; Arvicolinae; Microtus", + "Miichthys miiuy\tMi-iuy croaker\t1\t2\t-\t240162\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Eupercaria incertae sedis; Sciaenidae; Miichthys", + "mine drainage metagenome\t-\t11\t2\t11\t410659\tENV\tunclassified sequences; metagenomes; ecological metagenomes", + "Mischocyttarus flavitarsis\t-\t1\t5\t-\t231975\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Vespidae; Polistinae; Mischocyttarini; Mischocyttarus", + "Momordica charantia\t-\t1\t1\t11\t3673\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Cucurbitales; Cucurbitaceae; Momordiceae; Momordica", + "Moniezia expansa\tsheep tapeworm\t1\t9\t-\t28841\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Cestoda; Eucestoda; Cyclophyllidea; Anoplocephalidae; Moniezia", + "Monodelphis domestica\tgray short-tailed opossum\t1\t2\t-\t13616\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Metatheria; Didelphimorphia; Didelphidae; Didelphinae; Monodelphis", + "Monomorium chinense\t-\t1\t5\t-\t482359\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Solenopsidini; Monomorium", + "Monomorium pharaonis\tpharaoh ant\t1\t5\t-\t307658\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Solenopsidini; Monomorium", + "Morone chrysops\twhite bass\t1\t2\t-\t46259\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Eupercaria incertae sedis; Moronidae; Morone", + "Morone saxatilis\tstriped sea-bass\t1\t2\t-\t34816\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Eupercaria incertae sedis; Moronidae; Morone", + "Morus notabilis\t-\t1\t1\t11\t981085\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Moraceae; Morus", + "Mus musculus\thouse mouse\t1\t2\t-\t10090\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Muridae; Murinae; Mus; Mus", + "Musa ABB Group\t-\t1\t1\t11\t214693\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Zingiberales; Musaceae; Musa; Musa x paradisiaca", + "Musa acuminata AAA Group\tdessert banana\t1\t1\t11\t214697\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Zingiberales; Musaceae; Musa; Musa acuminata", + "Musa acuminata subsp. malaccensis\twild Malaysian banana\t1\t1\t11\t214687\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Zingiberales; Musaceae; Musa; Musa acuminata", + "Musca domestica\thouse fly\t1\t5\t-\t7370\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Calyptratae; Muscoidea; Muscidae; Muscinae; Muscini; Musca; Musca", + "Mustela putorius furo\tdomestic ferret\t1\t2\t-\t9669\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Mustelidae; Mustelinae; Mustela; Mustela putorius", + "Mycobacterium abscessus\t-\t11\t0\t-\t36809\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Actinobacteria; Actinobacteria; Corynebacteriales; Mycobacteriaceae; Mycobacterium; Mycobacterium chelonae group; Mycobacterium abscessus subgroup", + "Mycobacterium tuberculosis\t-\t11\t0\t-\t1773\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Actinobacteria; Actinobacteria; Corynebacteriales; Mycobacteriaceae; Mycobacterium; Mycobacterium tuberculosis complex", + "Myotis brandtii\tBrandt's bat\t1\t2\t-\t109478\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Vespertilionidae; Myotis", + "Myotis davidii\t-\t1\t2\t-\t225400\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Vespertilionidae; Myotis", + "Myotis lucifugus\tlittle brown bat\t1\t2\t-\t59463\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Vespertilionidae; Myotis", + "Myotis ricketti\tRickett's big-footed Myotis\t1\t2\t-\t203696\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Vespertilionidae; Myotis", + "Myrionecta rubra\t-\t1\t4\t11\t283649\tINV\tcellular organisms; Eukaryota; Alveolata; Ciliophora; Intramacronucleata; Litostomatea; Haptoria; Cyclotrichida; Mesodiniidae; Myrionecta", + "Myrmica rubra\t-\t1\t5\t-\t106198\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Myrmicini; Myrmica", + "Myrmica ruginodis\t-\t1\t5\t-\t34708\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Myrmicini; Myrmica", + "Myrmica sulcinodis\t-\t1\t5\t-\t229918\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Myrmicini; Myrmica", + "Mytilus galloprovincialis\tMediterranean mussel\t1\t5\t-\t29158\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Pteriomorphia; Mytiloida; Mytiloidea; Mytilidae; Mytilinae; Mytilus", + "Nannochorista philpotti\t-\t1\t5\t-\t1260225\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Mecoptera; Nannochoristidae; Nannochorista", + "Nannospalax galili\tUpper Galilee mountains blind mole rat\t1\t2\t-\t1026970\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Spalacidae; Spalacinae; Nannospalax", + "Nanorana parkeri\t-\t1\t2\t-\t125878\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Neobatrachia; Ranoidea; Dicroglossidae; Dicroglossinae; Nanorana", + "Nasonia vitripennis\tjewel wasp\t1\t5\t-\t7425\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Chaldicoidea group; Chalcidoidea; Pteromalidae; Pteromalinae; Nasonia", + "Necator americanus\t-\t1\t5\t-\t51031\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Ancylostomatoidea; Ancylostomatidae; Bunostominae; Necator", + "Neisseria gonorrhoeae\t-\t11\t0\t-\t485\tBCT\tcellular organisms; Bacteria; Proteobacteria; Betaproteobacteria; Neisseriales; Neisseriaceae; Neisseria", + "Neisseria meningitidis\t-\t11\t0\t-\t487\tBCT\tcellular organisms; Bacteria; Proteobacteria; Betaproteobacteria; Neisseriales; Neisseriaceae; Neisseria", + "Nelumbo nucifera\tsacred lotus\t1\t1\t11\t4432\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; stem eudicotyledons; Proteales; Nelumbonaceae; Nelumbo", + "Nematostella vectensis\tstarlet sea anemone\t1\t4\t-\t45351\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Actiniaria; Edwardsiidae; Nematostella", + "Neolamarckia cadamba\t-\t1\t1\t11\t153762\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Rubiaceae; Cinchonoideae; Naucleeae; Neolamarckia", + "Neolamprologus brichardi\t-\t1\t2\t-\t32507\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Lamprologini; Neolamprologus", + "Nestor notabilis\tKea\t1\t2\t-\t176057\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Psittaciformes; Psittacidae; Nestor", + "Nicotiana attenuata\t-\t1\t1\t11\t49451\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Nicotianoideae; Nicotianeae; Nicotiana", + "Nicotiana benthamiana\t-\t1\t1\t11\t4100\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Nicotianoideae; Nicotianeae; Nicotiana", + "Nicotiana sylvestris\twood tobacco\t1\t1\t11\t4096\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Nicotianoideae; Nicotianeae; Nicotiana", + "Nicotiana tabacum\tcommon tobacco\t1\t1\t11\t4097\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Nicotianoideae; Nicotianeae; Nicotiana", + "Nicotiana tomentosiformis\t-\t1\t1\t11\t4098\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Nicotianoideae; Nicotianeae; Nicotiana", + "Nicrophorus vespilloides\t-\t1\t5\t-\t110193\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Staphyliniformia; Staphylinoidea; Silphidae; Nicrophorinae; Nicrophorus", + "Nilaparvata lugens\tbrown planthopper\t1\t5\t-\t108931\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Neohemiptera; Archaeorrhyncha; Fulgoroidea; Delphacidae; Delphacinae; Nilaparvata", + "Nipponia nippon\tcrested ibis\t1\t2\t-\t128390\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Pelecaniformes; Threskiornithidae; Nipponia", + "Nitella hyalina\t-\t1\t1\t11\t181804\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Charophyceae; Charales; Characeae; Nitella", + "Nitella mirabilis\t-\t1\t1\t11\t231897\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Charophyceae; Charales; Characeae; Nitella", + "Noccaea caerulescens\t-\t1\t1\t11\t107243\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Coluteocarpeae; Noccaea", + "Nomascus leucogenys\tnorthern white-cheeked gibbon\t1\t2\t-\t61853\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hylobatidae; Nomascus", + "Nothobranchius furzeri\tturquoise killifish\t1\t2\t-\t105023\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius", + "Nothobranchius kadleci\t-\t1\t2\t-\t1051664\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius", + "Nothobranchius korthausae\t-\t1\t2\t-\t1143690\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius", + "Nothobranchius kuhntae\tBeira killifish\t1\t2\t-\t321403\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius", + "Nothobranchius pienaari\t-\t1\t2\t-\t704102\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius", + "Nothobranchius rachovii\tbluefin notho\t1\t2\t-\t451742\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius", + "Notholithocarpus densiflorus\t-\t1\t1\t11\t165545\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fagales; Fagaceae; Notholithocarpus", + "Notothenia coriiceps\tblack rockcod\t1\t2\t-\t8208\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Perciformes; Notothenioidei; Nototheniidae; Notothenia", + "Numida meleagris\thelmeted guineafowl\t1\t2\t-\t8996\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Galliformes; Numididae; Numida", + "Nylanderia pubens\t-\t1\t5\t-\t613973\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Lasiini; Nylanderia", + "Ochotona princeps\tAmerican pika\t1\t2\t-\t9978\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Lagomorpha; Ochotonidae; Ochotona", + "Ochromonas sp. LO244K-D\t-\t1\t1\t11\t1825117\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; Chromulinales; Chromulinaceae; Ochromonas", + "Octodon degus\tdegu\t1\t2\t-\t10160\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Octodontidae; Octodon", + "Octopus bimaculoides\t-\t1\t5\t-\t37653\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Cephalopoda; Coleoidea; Neocoleoidea; Octopodiformes; Octopoda; Incirrata; Octopodidae; Octopus", + "Odobenus rosmarus divergens\tPacific walrus\t1\t2\t-\t9708\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Odobenidae; Odobenus; Odobenus rosmarus", + "Oenococcus oeni\t-\t11\t0\t-\t1247\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Leuconostocaceae; Oenococcus", + "Oesophagostomum dentatum\t-\t1\t5\t-\t61180\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Strongyloidea; Cloacinidae; Oesophagostomum", + "Olavius algarvensis\t-\t1\t5\t-\t188229\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Annelida; Clitellata; Oligochaeta; Haplotaxida; Tubificina; Tubificidae; Phallodrilinae; Olavius", + "Olea europaea\tcommon olive\t1\t1\t11\t4146\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Oleaceae; Oleeae; Olea", + "Onchocerca flexuosa\t-\t1\t5\t-\t387005\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Spirurida; Filarioidea; Onchocercidae; Onchocerca", + "Oncidium hybrid cultivar\t-\t1\t1\t11\t141207\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Orchidaceae; Epidendroideae; Cymbidieae; Oncidiinae; Oncidium", + "Oncorhynchus masou masou\tcherry salmon\t1\t2\t-\t90313\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Protacanthopterygii; Salmoniformes; Salmonidae; Salmoninae; Oncorhynchus; Oncorhynchus masou", + "Oncorhynchus mykiss\trainbow trout\t1\t2\t-\t8022\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Protacanthopterygii; Salmoniformes; Salmonidae; Salmoninae; Oncorhynchus", + "Onthophagus nigriventris\t-\t1\t5\t-\t476074\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Scarabaeiformia; Scarabaeoidea; Scarabaeidae; Scarabaeinae; Scarabaeinae incertae sedis; Onthophagus", + "Ophiocoma echinata\t-\t1\t9\t-\t331088\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Ophiuroidea; Ophiuridea; Ophiurida; Ophiurina; Gnathophiurina; Ophiocomidae; Ophiocominae; Ophiocoma", + "Ophthalmotilapia ventralis\t-\t1\t2\t-\t27755\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Ectodini; Ophthalmotilapia", + "Opisthorchis viverrini\t-\t1\t9\t-\t6198\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Opisthorchiida; Opisthorchiata; Opisthorchiidae; Opisthorchis", + "Orchesella cincta\t-\t1\t5\t-\t48709\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Collembola; Collembola; Entomobryomorpha; Entomobryoidea; Entomobryidae; Orchesellinae; Orchesella", + "Oreochromis niloticus\tNile tilapia\t1\t2\t-\t8128\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Oreochromini; Oreochromis", + "Ornithorhynchus anatinus\tplatypus\t1\t2\t-\t9258\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Prototheria; Monotremata; Ornithorhynchidae; Ornithorhynchus", + "Oropsylla silantiewi\t-\t1\t5\t-\t1461318\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Siphonaptera; Ceratophyllomorpha; Ceratophylloidea; Ceratophyllidae; Oropsylla", + "Orycteropus afer afer\t-\t1\t2\t-\t1230840\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Tubulidentata; Orycteropodidae; Orycteropus; Orycteropus afer", + "Oryctolagus cuniculus\trabbit\t1\t2\t-\t9986\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Lagomorpha; Leporidae; Oryctolagus", + "Oryza brachyantha\tmalo sina\t1\t1\t11\t4533\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Oryzoideae; Oryzeae; Oryzinae; Oryza", + "Oryza sativa\trice\t1\t1\t11\t4530\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Oryzoideae; Oryzeae; Oryzinae; Oryza", + "Oryza sativa Indica Group\tlong-grained rice\t1\t1\t11\t39946\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Oryzoideae; Oryzeae; Oryzinae; Oryza; Oryza sativa", + "Oryza sativa Japonica Group\tJapanese rice\t1\t1\t11\t39947\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Oryzoideae; Oryzeae; Oryzinae; Oryza; Oryza sativa", + "Oryzias latipes\tJapanese medaka\t1\t2\t-\t8090\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Beloniformes; Adrianichthyoidei; Adrianichthyidae; Oryziinae; Oryzias", + "Osmia cornuta\t-\t1\t5\t-\t185587\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Megachilidae; Megachilinae; Osmiini; Osmia", + "Ostrinia furnacalis\tAsian corn borer\t1\t5\t-\t93504\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Pyraloidea; Crambidae; Pyraustinae; Ostrinia", + "Ostrinia nubilalis\tEuropean corn borer\t1\t5\t-\t29057\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Pyraloidea; Crambidae; Pyraustinae; Ostrinia", + "Otolemur garnettii\tsmall-eared galago\t1\t2\t-\t30611\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Strepsirrhini; Lorisiformes; Galagidae; Otolemur", + "Ovis aries\tsheep\t1\t2\t-\t9940\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Caprinae; Ovis", + "Ovis aries musimon\tmouflon\t1\t2\t-\t9938\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Caprinae; Ovis; Ovis aries", + "Pachycladon fastigiatum\t-\t1\t1\t11\t106774\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Microlepidieae; Pachycladon", + "Pachypsylla venusta\thackberry petiole gall psyllid\t1\t5\t-\t38123\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Sternorrhyncha; Psylliformes; Psylloidea; Psyllidae; Pachypsylla", + "Paeonia lactiflora\tChinese peony\t1\t1\t11\t35924\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Saxifragales; Paeoniaceae; Paeonia", + "Pan paniscus\tpygmy chimpanzee\t1\t2\t-\t9597\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Pan", + "Pan troglodytes\tchimpanzee\t1\t2\t-\t9598\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Pan", + "Pan troglodytes troglodytes\t-\t1\t2\t-\t37011\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Pan; Pan troglodytes", + "Pan troglodytes verus\t-\t1\t2\t-\t37012\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Pan; Pan troglodytes", + "Panax ginseng\t-\t1\t1\t11\t4054\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Apiales; Apiineae; Araliaceae; Panax", + "Panicum hallii var. filipes\t-\t1\t1\t11\t907226\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Panicodae; Paniceae; Panicinae; Panicum; Panicum hallii", + "Panthera tigris altaica\tAmur tiger\t1\t2\t-\t74533\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Feliformia; Felidae; Pantherinae; Panthera; Panthera tigris", + "Pantholops hodgsonii\tchiru\t1\t2\t-\t59538\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Antilopinae; Pantholops", + "Papilio machaon\tcommon yellow swallowtail\t1\t5\t-\t76193\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Papilionoidea; Papilionidae; Papilioninae; Papilionini; Papilio", + "Papilio xuthus\tAsian swallowtail\t1\t5\t-\t66420\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Papilionoidea; Papilionidae; Papilioninae; Papilionini; Papilio", + "Papio anubis\tolive baboon\t1\t2\t-\t9555\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Papio", + "Papio hamadryas\thamadryas baboon\t1\t2\t-\t9557\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Papio", + "Paramecium tetraurelia strain d4-2\t-\t6\t4\t11\t412030\tINV\tcellular organisms; Eukaryota; Alveolata; Ciliophora; Intramacronucleata; Oligohymenophorea; Peniculida; Parameciidae; Paramecium; Paramecium tetraurelia", + "Parascaris equorum\t-\t1\t5\t-\t6256\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Ascaridida; Ascaridoidea; Ascarididae; Parascaris", + "Parasteatoda tepidariorum\tcommon house spider\t1\t5\t-\t114398\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Araneae; Araneomorphae; Entelegynae; Orbiculariae; Araneoidea; Theridiidae; Parasteatoda", + "Parus major\tGreat Tit\t1\t2\t-\t9157\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Paridae; Parus", + "Patiria miniata\tbat star\t1\t9\t-\t46514\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Valvatacea; Valvatida; Asterinidae; Patiria", + "Patiria pectinifera\t-\t1\t9\t-\t7594\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Valvatacea; Valvatida; Asterinidae; Patiria", + "Pecten maximus\t-\t1\t5\t-\t6579\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Pteriomorphia; Pectinoida; Pectinoidea; Pectinidae; Pecten", + "Pedospumella encystans\t-\t1\t1\t11\t1117030\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; Chromulinales; Chromulinaceae; Pedospumella", + "Pelecanus crispus\tDalmatian pelican\t1\t2\t-\t36300\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Pelecaniformes; Pelecanidae; Pelecanus", + "Pelodiscus sinensis\tChinese soft-shelled turtle\t1\t2\t-\t13735\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Testudines; Cryptodira; Trionychia; Trionychidae; Pelodiscus", + "Penaeus monodon\tblack tiger shrimp\t1\t5\t-\t6687\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Dendrobranchiata; Penaeoidea; Penaeidae; Penaeus", + "Pepsis grossa\t-\t1\t5\t-\t1317727\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Pompiloidea; Pompilidae; Pepsinae; Pepsis", + "Perkinsus marinus ATCC 50983\t-\t1\t4\t11\t423536\tINV\tcellular organisms; Eukaryota; Alveolata; Perkinsea; Perkinsida; Perkinsidae; Perkinsus; Perkinsus marinus", + "Peromyscus maniculatus bairdii\tprairie deer mouse\t1\t2\t-\t230844\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Cricetidae; Neotominae; Peromyscus; Peromyscus maniculatus", + "Persicaria minor\t-\t1\t1\t11\t488003\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Polygonaceae; Polygonoideae; Persicarieae; Persicaria", + "Petunia integrifolia subsp. inflata\t-\t1\t1\t11\t212142\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Petunioideae; Petunia; Petunia integrifolia", + "Phaethon lepturus\twhite-tailed tropicbird\t1\t2\t-\t97097\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Pelecaniformes; Phaethontidae; Phaethon", + "Phalacrocorax carbo\tgreat cormorant\t1\t2\t-\t9209\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Pelecaniformes; Phalacrocoracidae; Phalacrocorax", + "Phalaenopsis aphrodite\t-\t1\t1\t11\t212056\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Orchidaceae; Epidendroideae; Vandeae; Aeridinae; Phalaenopsis", + "Phaseolus vulgaris\t-\t1\t1\t11\t3885\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Phaseolus", + "Phoca largha\tspotted seal\t1\t2\t-\t39090\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Phocidae; Phoca", + "Phoenicopterus ruber ruber\t-\t1\t2\t-\t9218\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Phoenicopteriformes; Phoenicopteridae; Phoenicopterus; Phoenicopterus ruber", + "Phoenix dactylifera\tdate palm\t1\t1\t11\t42345\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Arecales; Arecaceae; Coryphoideae; Phoeniceae; Phoenix", + "Physalis alkekengi var. franchetii\t-\t1\t1\t11\t221454\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Physaleae; Physalis; Physalis alkekengi", + "Physalis peruviana\t-\t1\t1\t11\t126903\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Physaleae; Physalis", + "Physcomitrella patens\t-\t1\t1\t11\t3218\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Bryophyta; Bryophytina; Bryopsida; Funariidae; Funariales; Funariaceae; Physcomitrella", + "Physeter catodon\tsperm whale\t1\t2\t-\t9755\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Cetacea; Odontoceti; Physeteridae; Physeter", + "Phytophthora cambivora\t-\t1\t1\t11\t53983\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Oomycetes; Peronosporales; Phytophthora", + "Phytophthora cinnamomi\t-\t1\t1\t11\t4785\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Oomycetes; Peronosporales; Phytophthora", + "Phytophthora x alni\t-\t1\t1\t11\t299392\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Oomycetes; Peronosporales; Phytophthora", + "Picea glauca\twhite spruce\t1\t1\t11\t3330\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Picea", + "Picoides pubescens\tdowny woodpecker\t1\t2\t-\t118200\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Piciformes; Picidae; Picoides", + "Pinus massoniana\t-\t1\t1\t11\t88730\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Pinus; Pinus", + "Pinus sylvestris\tScots pine\t1\t1\t11\t3349\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Pinus; Pinus", + "Pinus taeda\tloblolly pine\t1\t1\t11\t3352\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Pinus; Pinus", + "Pisaster ochraceus\tpurple sea star\t1\t9\t-\t7612\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Pisaster", + "Pisum sativum\tpea\t1\t1\t11\t3888\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Fabeae; Pisum", + "Pisum sativum subsp. sativum\t-\t1\t1\t11\t208194\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Fabeae; Pisum; Pisum sativum", + "Plakobranchus ocellatus\t-\t1\t5\t-\t259542\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Heterobranchia; Euthyneura; Panpulmonata; Sacoglossa; Placobranchoidea; Placobranchidae; Plakobranchus", + "Plasmodium falciparum\tmalaria parasite P. falciparum\t1\t4\t11\t5833\tINV\tcellular organisms; Eukaryota; Alveolata; Apicomplexa; Aconoidasida; Haemosporida; Plasmodiidae; Plasmodium; Plasmodium (Laverania)", + "Plecoglossus altivelis\tayu\t1\t2\t-\t61084\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Stomiatii; Osmeriformes; Plecoglossidae; Plecoglossus", + "Plecoglossus altivelis altivelis\t-\t1\t2\t-\t281464\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Stomiatii; Osmeriformes; Plecoglossidae; Plecoglossus; Plecoglossus altivelis", + "Plukenetia volubilis\t-\t1\t1\t11\t316893\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Euphorbiaceae; Acalyphoideae; Plukenetieae; Plukenetia", + "Plutella xylostella\tdiamondback moth\t1\t5\t-\t51655\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Yponomeutoidea; Plutellidae; Plutella", + "Poa infirma\t-\t1\t1\t11\t165094\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Poodae; Poeae; Poeae Chloroplast Group 2 (Poeae type); Poinae; Poa", + "Poa supina\t-\t1\t1\t11\t289064\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Poodae; Poeae; Poeae Chloroplast Group 2 (Poeae type); Poinae; Poa", + "Podiceps cristatus\tgreat crested grebe\t1\t2\t-\t345573\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Podicipediformes; Podicipedidae; Podiceps", + "Poecilia formosa\tAmazon molly\t1\t2\t-\t48698\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Poecilia", + "Poecilia latipinna\tsailfin molly\t1\t2\t-\t48699\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Poecilia", + "Poecilia mexicana\t-\t1\t2\t-\t48701\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Poecilia", + "Poecilia reticulata\tguppy\t1\t2\t-\t8081\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Poecilia", + "Poeciliopsis prolifica\tblackstripe livebearer\t1\t2\t-\t188132\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Poeciliopsis", + "Pogonus chalceus\t-\t1\t5\t-\t235516\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Adephaga; Caraboidea; Carabidae; Trechinae; Pogonini; Pogonus", + "Pohlia nutans\t-\t1\t1\t11\t140635\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Bryophyta; Bryophytina; Bryopsida; Bryidae; Bryanae; Bryales; Mniaceae; Pohlia", + "Polistes canadensis\t-\t1\t5\t-\t91411\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Vespidae; Polistinae; Polistini; Polistes", + "Polistes metricus\t-\t1\t5\t-\t91422\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Vespidae; Polistinae; Polistini; Polistes", + "Pongo abelii\tSumatran orangutan\t1\t2\t-\t9601\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Ponginae; Pongo", + "Populus euphratica\tEuphrates poplar\t1\t1\t11\t75702\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Salicaceae; Saliceae; Populus", + "Populus trichocarpa\tblack cottonwood\t1\t1\t11\t3694\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Salicaceae; Saliceae; Populus", + "Porites australiensis\t-\t1\t4\t-\t51061\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Fungiina; Poritidae; Porites", + "Poterioochromonas sp. DS\t-\t1\t1\t11\t519425\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Synurophyceae; Ochromonadales; Ochromonadaceae; Poterioochromonas", + "Priapulus caudatus\t-\t1\t5\t-\t37621\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Scalidophora; Priapulida; Priapulidae; Priapulus", + "Proasellus aragonensis\t-\t1\t5\t-\t1281939\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus arthrodilus\t-\t1\t5\t-\t1281940\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus assaforensis\t-\t1\t5\t-\t1282049\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus cantabricus\t-\t1\t5\t-\t1281948\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus cavaticus\t-\t1\t5\t-\t1281949\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus coiffaiti\t-\t1\t5\t-\t1281953\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus coxalis\t-\t1\t5\t-\t63229\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus ebrensis\t-\t1\t5\t-\t1281961\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus escolai\t-\t1\t5\t-\t1281963\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus grafi\t-\t1\t5\t-\t1281973\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus granadensis\t-\t1\t5\t-\t1281974\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus hercegovinensis\t-\t1\t5\t-\t1281977\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus ibericus\t-\t1\t5\t-\t1281981\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus jaloniacus\t-\t1\t5\t-\t1281986\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus karamani\t-\t1\t5\t-\t1281987\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus margalefi\t-\t1\t5\t-\t1281998\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus meridianus\t-\t1\t5\t-\t1282001\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus ortizi\t-\t1\t5\t-\t1282012\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus racovitzai\t-\t1\t5\t-\t1282023\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus rectus\t-\t1\t5\t-\t1282025\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus solanasi\t-\t1\t5\t-\t1282031\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Proasellus spelaeus\t-\t1\t5\t-\t1282033\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus", + "Procambarus clarkii\tred swamp crayfish\t1\t5\t-\t6728\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Astacidea; Astacoidea; Cambaridae; Cambarinae; Procambarus", + "Procotyla fluviatilis\t-\t1\t9\t-\t231627\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Rhabditophora; Seriata; Tricladida; Continenticola; Planarioidea; Dendrocoelidae; Procotyla", + "Propithecus coquereli\tCoquerel's sifaka\t1\t2\t-\t379532\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Strepsirrhini; Lemuriformes; Indriidae; Propithecus", + "Prosopis alba\t-\t1\t1\t11\t207710\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Mimosoideae; Mimoseae; Prosopis", + "Protobothrops mucrosquamatus\t-\t1\t2\t-\t103944\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Unidentata; Episquamata; Toxicofera; Serpentes; Colubroidea; Viperidae; Crotalinae; Protobothrops", + "Protopolystoma xenopodis\t-\t1\t9\t-\t117903\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Monogenea; Polyopisthocotylea; Polystomatidae; Protopolystoma", + "Prunus armeniaca\tapricot\t1\t1\t11\t36596\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Amygdaleae; Prunus", + "Prunus mume\tJapanese apricot\t1\t1\t11\t102107\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Amygdaleae; Prunus", + "Prunus persica\tpeach\t1\t1\t11\t3760\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Amygdaleae; Prunus", + "Prymnesium parvum\t-\t1\t1\t11\t97485\tPLN\tcellular organisms; Eukaryota; Haptophyceae; Prymnesiales; Prymnesiaceae; Prymnesium", + "Pseudacris regilla\tPacific treefrog\t1\t2\t-\t47562\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Neobatrachia; Hyloidea; Hylidae; Hylinae; Hylini; Pseudacris", + "Pseudodiploria strigosa\t-\t1\t4\t-\t1428006\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Faviina; Mussidae; Faviinae; Pseudodiploria", + "Pseudomasaris vespoides\t-\t1\t5\t-\t1317726\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Vespidae; Masarinae; Masarini; Pseudomasaris", + "Pseudomonas aeruginosa\t-\t11\t0\t-\t287\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Pseudomonadales; Pseudomonadaceae; Pseudomonas; Pseudomonas aeruginosa group", + "Pseudopodoces humilis\tTibetan ground-tit\t1\t2\t-\t181119\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Paridae; Pseudopodoces", + "Pseudotsuga menziesii var. menziesii\t-\t1\t1\t11\t278161\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Pseudotsuga; Pseudotsuga menziesii", + "Pteridium aquilinum subsp. aquilinum\t-\t1\t1\t11\t104588\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Moniliformopses; Polypodiidae; Polypodiales; Dennstaedtiaceae; Pteridium; Pteridium aquilinum", + "Pterocles gutturalis\tyellow-throated sandgrouse\t1\t2\t-\t240206\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Ciconiiformes; Pteroclidae; Pterocles", + "Pteronotus parnellii\tParnell's mustached bat\t1\t2\t-\t59476\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Mormoopidae; Pteronotus", + "Pteropus alecto\tblack flying fox\t1\t2\t-\t9402\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Megachiroptera; Pteropodidae; Pteropodinae; Pteropus", + "Pteropus vampyrus\tlarge flying fox\t1\t2\t-\t132908\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Megachiroptera; Pteropodidae; Pteropodinae; Pteropus", + "Ptychodera flava\t-\t1\t9\t-\t63121\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Hemichordata; Enteropneusta; Ptychoderidae; Ptychodera", + "Puccinia psidii\t-\t1\t4\t-\t181123\tPLN\tcellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Basidiomycota; Pucciniomycotina; Pucciniomycetes; Pucciniales; Pucciniaceae; Puccinia", + "Pundamilia nyererei\t-\t1\t2\t-\t303518\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Haplochromini; Pundamilia", + "Punica granatum\tpomegranate\t1\t1\t11\t22663\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Myrtales; Lythraceae; Punica", + "Pygocentrus nattereri\tred-bellied piranha\t1\t2\t-\t42514\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Characiphysae; Characiformes; Characoidei; Serrasalmidae; Pygocentrus", + "Pygoscelis adeliae\tAdelie penguin\t1\t2\t-\t9238\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Sphenisciformes; Spheniscidae; Pygoscelis", + "Pyrodinium bahamense var. compressum\t-\t1\t4\t11\t73916\tPLN\tcellular organisms; Eukaryota; Alveolata; Dinophyceae; Gonyaulacales; Goniodomataceae; Pyrodinium; Pyrodinium bahamense", + "Pyrus communis\tpear\t1\t1\t11\t23211\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Maleae; Pyrus", + "Pyrus x bretschneideri\tChinese white pear\t1\t1\t11\t225117\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Maleae; Pyrus", + "Python bivittatus\tBurmese python\t1\t2\t-\t176946\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Unidentata; Episquamata; Toxicofera; Serpentes; Henophidia; Pythonidae; Python", + "Quercus suber\t-\t1\t1\t11\t58331\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fagales; Fagaceae; Quercus", + "Ramulus artemis\t-\t1\t5\t-\t1390046\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Phasmatodea; Verophasmatodea; Anareolatae; Phasmatidae; Phasmatinae; Clitumnini; Ramulus", + "Rana clamitans\tbronze frog\t1\t2\t-\t145282\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Neobatrachia; Ranoidea; Ranidae; Rana; Aquarana", + "Raphanus sativus\tradish\t1\t1\t11\t3726\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Raphanus", + "Rattus norvegicus\tNorway rat\t1\t2\t-\t10116\tROD\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Muridae; Murinae; Rattus", + "Rauvolfia serpentina\tserpentwood\t1\t1\t11\t4060\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Apocynaceae; Rauvolfioideae; Vinceae; Rauvolfiinae; Rauvolfia", + "Reaumuria trigyna\t-\t1\t1\t11\t1091135\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Tamaricaceae; Reaumuria", + "Rhagoletis zephyria\tsnowberry fruit fly\t1\t5\t-\t28612\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Trypetinae; Carpomyini; Carpomyina; Rhagoletis", + "Rhinolophus ferrumequinum\tgreater horseshoe bat\t1\t2\t-\t59479\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Rhinolophidae; Rhinolophinae; Rhinolophus", + "Rhinopithecus bieti\tblack snub-nosed monkey\t1\t2\t-\t61621\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Colobinae; Rhinopithecus", + "Rhinopithecus roxellana\tgolden snub-nosed monkey\t1\t2\t-\t61622\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Colobinae; Rhinopithecus", + "Rhipicephalus sanguineus\tbrown dog tick\t1\t5\t-\t34632\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Ixodida; Ixodoidea; Ixodidae; Rhipicephalinae; Rhipicephalus; Rhipicephalus; Rhipicephalus sanguineus group", + "Rhizoctonia solani AG-1 IA\t-\t1\t4\t-\t983506\tPLN\tcellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Basidiomycota; Agaricomycotina; Agaricomycetes; Agaricomycetes incertae sedis; Cantharellales; Ceratobasidiaceae; Rhizoctonia; Rhizoctonia solani", + "Rhodinia newara\t-\t1\t5\t-\t1579501\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Saturniini; Rhodinia", + "Ricinus communis\tcastor bean\t1\t1\t11\t3988\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Euphorbiaceae; Acalyphoideae; Acalypheae; Ricinus", + "Romanomermis culicivorax\t-\t1\t5\t-\t13658\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Enoplea; Dorylaimia; Mermithida; Mermithoidea; Mermithidae; Romanomermis", + "Rousettus aegyptiacus\tEgyptian rousette\t1\t2\t-\t9407\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Megachiroptera; Pteropodidae; Pteropodinae; Rousettus", + "Rubus hybrid cultivar\t-\t1\t1\t11\t564016\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Rosoideae; Rosoideae unplaced; Rubus", + "Rumex palustris\t-\t1\t1\t11\t50298\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Polygonaceae; Polygonoideae; Rumiceae; Rumex", + "Saccharomyces cerevisiae\tbaker's yeast\t1\t3\t-\t4932\tPLN\tcellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Ascomycota; saccharomyceta; Saccharomycotina; Saccharomycetes; Saccharomycetales; Saccharomycetaceae; Saccharomyces", + "Saccharomyces pastorianus\t-\t1\t3\t-\t27292\tPLN\tcellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Ascomycota; saccharomyceta; Saccharomycotina; Saccharomycetes; Saccharomycetales; Saccharomycetaceae; Saccharomyces", + "Saccoglossus kowalevskii\t-\t1\t9\t-\t10224\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Hemichordata; Enteropneusta; Harrimaniidae; Saccoglossus", + "Saimiri boliviensis boliviensis\tBolivian squirrel monkey\t1\t2\t-\t39432\tPRI\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Platyrrhini; Cebidae; Saimiriinae; Saimiri; Saimiri boliviensis", + "Salicornia europaea\t-\t1\t1\t11\t206448\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Chenopodiaceae; Salicornioideae; Salicornia", + "Salmo salar\tAtlantic salmon\t1\t2\t-\t8030\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Protacanthopterygii; Salmoniformes; Salmonidae; Salmoninae; Salmo", + "Salmonella enterica\t-\t11\t0\t-\t28901\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Salmonella", + "Salmonella enterica subsp. enterica serovar Typhi\t-\t11\t0\t-\t90370\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Salmonella; Salmonella enterica; Salmonella enterica subsp. enterica", + "Salmonella enterica subsp. enterica serovar Typhimurium\t-\t11\t0\t-\t90371\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Salmonella; Salmonella enterica; Salmonella enterica subsp. enterica", + "Salmonella enterica subsp. enterica serovar Typhimurium str. DT104\t-\t11\t0\t-\t85569\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Salmonella; Salmonella enterica; Salmonella enterica subsp. enterica; Salmonella enterica subsp. enterica serovar Typhimurium", + "Samia ricini\tIndian eri silkmoth\t1\t5\t-\t63990\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Attacini; Samia", + "Sarcophilus harrisii\tTasmanian devil\t1\t2\t-\t9305\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Metatheria; Dasyuromorphia; Dasyuridae; Sarcophilus", + "Sarsinebalia urgorrii\t-\t1\t5\t-\t1032695\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Phyllocarida; Leptostraca; Nebaliidae; Sarsinebalia", + "Saussurea involucrata\t-\t1\t1\t11\t200489\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Carduoideae; Cardueae; Carduinae; Saussurea", + "Sceliphron caementarium\t-\t1\t5\t-\t253855\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Sphecoidea; Sphecidae; Sphecinae; Sceliphrini; Sceliphrina; Sceliphron", + "Schistocephalus solidus\t-\t1\t9\t-\t70667\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Cestoda; Eucestoda; Diphyllobothriidea; Diphyllobothriidae; Schistocephalus", + "Schistosoma curassoni\t-\t1\t9\t-\t6186\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma", + "Schistosoma haematobium\t-\t1\t9\t-\t6185\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma", + "Schistosoma japonicum\t-\t1\t9\t-\t6182\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma", + "Schistosoma mansoni\t-\t1\t9\t-\t6183\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma", + "Schistosoma mattheei\t-\t1\t9\t-\t31246\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma", + "Schistosoma rodhaini\t-\t1\t9\t-\t6188\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma", + "Schmidtea mediterranea\t-\t1\t9\t-\t79327\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Rhabditophora; Seriata; Tricladida; Continenticola; Geoplanoidea; Dugesiidae; Schmidtea", + "Sclerodactyla briareus\t-\t1\t9\t-\t7710\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Holothuroidea; Dendrochirotacea; Dendrochirotida; Sclerodactylidae; Sclerodactyla", + "Scleropages formosus\tAsian bonytongue\t1\t2\t-\t113540\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Osteoglossocephala; Osteoglossomorpha; Osteoglossiformes; Osteoglossidae; Scleropages", + "Sclerotinia homoeocarpa\t-\t1\t4\t-\t38483\tPLN\tcellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Ascomycota; saccharomyceta; Pezizomycotina; leotiomyceta; sordariomyceta; Leotiomycetes; Helotiales; Sclerotiniaceae; Sclerotinia", + "Scophthalmus maximus\tturbot\t1\t2\t-\t52904\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Carangaria; Pleuronectiformes; Pleuronectoidei; Scophthalmidae; Scophthalmus", + "Scylla olivacea\torange mud crab\t1\t5\t-\t85551\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Brachyura; Eubrachyura; Heterotremata; Portunoidea; Portunidae; Scylla", + "Sebastes nigrocinctus\ttiger rockfish\t1\t2\t-\t72089\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Perciformes; Scorpaenoidei; Sebastidae; Sebastinae; Sebastes", + "Secale cereale\trye\t1\t1\t11\t4550\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Hordeinae; Secale", + "Sedum alfredii\t-\t1\t1\t11\t439688\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Saxifragales; Crassulaceae; Sedum", + "Selaginella moellendorffii\t-\t1\t1\t11\t88036\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Lycopodiidae; Selaginellales; Selaginellaceae; Selaginella", + "Serinus canaria\tcommon canary\t1\t2\t-\t9135\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Passeroidea; Fringillidae; Carduelinae; Serinus", + "Sesamum indicum\tsesame\t1\t1\t11\t4182\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Pedaliaceae; Sesamum", + "Setaria italica\tfoxtail millet\t1\t1\t11\t4555\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Panicodae; Paniceae; Cenchrinae; Setaria", + "Shigella sonnei\t-\t11\t0\t-\t624\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Shigella", + "Silene latifolia\t-\t1\t1\t11\t37657\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Caryophyllaceae; Sileneae; Silene", + "Simian immunodeficiency virus\t-\t1\t0\t-\t11723\tVRL\tViruses; Retro-transcribing viruses; Retroviridae; Orthoretrovirinae; Lentivirus; Primate lentivirus group", + "Sinocyclocheilus angustiporus\t-\t1\t2\t-\t307947\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Sinocyclocheilus", + "Sinocyclocheilus anophthalmus\teyeless golden-line fish\t1\t2\t-\t307955\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Sinocyclocheilus", + "Sinocyclocheilus anshuiensis\t-\t1\t2\t-\t1608454\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Sinocyclocheilus", + "Sinocyclocheilus grahami\t-\t1\t2\t-\t75366\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Sinocyclocheilus", + "Sinocyclocheilus rhinocerous\t-\t1\t2\t-\t307959\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Sinocyclocheilus", + "Sinopodophyllum hexandrum\t-\t1\t1\t11\t93608\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; stem eudicotyledons; Ranunculales; Berberidaceae; Podophylloideae; Sinopodophyllum", + "Sipyloidea sipylus\t-\t1\t5\t-\t202427\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Phasmatodea; Verophasmatodea; Anareolatae; Diapheromeridae; Necrosciinae; Sipyloidea", + "soil metagenome\t-\t11\t2\t11\t410658\tENV\tunclassified sequences; metagenomes; ecological metagenomes", + "Solanum chacoense\tChaco potato\t1\t1\t11\t4108\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum", + "Solanum lycopersicum\ttomato\t1\t1\t11\t4081\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum; Lycopersicon", + "Solanum melongena\teggplant\t1\t1\t11\t4111\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum", + "Solanum pennellii\t-\t1\t1\t11\t28526\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum; Lycopersicon", + "Solanum torvum\t-\t1\t1\t11\t119830\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum", + "Solanum tuberosum\tpotato\t1\t1\t11\t4113\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum", + "Solenopsis invicta\tred fire ant\t1\t5\t-\t13686\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Solenopsidini; Solenopsis", + "Sorex araneus\tEuropean shrew\t1\t2\t-\t42254\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Insectivora; Soricidae; Soricinae; Sorex", + "Sorghum bicolor\tsorghum\t1\t1\t11\t4558\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Andropogonodae; Andropogoneae; Sorghinae; Sorghum", + "Speleonectes cf. tulumensis BMR-2011\t-\t1\t5\t-\t1032549\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Remipedia; Nectiopoda; Speleonectidae; Speleonectes", + "Sphaerechinus granularis\t-\t1\t9\t-\t39374\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Euechinoidea; Echinacea; Temnopleuroida; Toxopneustidae; Sphaerechinus", + "Sphaeroforma arctica JP610\t-\t1\t1\t-\t667725\tINV\tcellular organisms; Eukaryota; Opisthokonta; Opisthokonta incertae sedis; Ichthyosporea; Ichthyophonida; Sphaeroforma; Sphaeroforma arctica", + "Sphaeropthalma orestes\t-\t1\t5\t-\t374941\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Pompiloidea; Mutillidae; Sphaeropthalminae; Sphaeropthalma", + "Spinacia oleracea\tspinach\t1\t1\t11\t3562\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Chenopodiaceae; Chenopodioideae; Anserineae; Spinacia", + "Spirometra erinaceieuropaei\t-\t1\t9\t-\t99802\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Cestoda; Eucestoda; Diphyllobothriidea; Diphyllobothriidae; Spirometra", + "Spodoptera exigua\tbeet armyworm\t1\t5\t-\t7107\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Amphipyrinae; Spodoptera", + "Spodoptera frugiperda\tfall armyworm\t1\t5\t-\t7108\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Amphipyrinae; Spodoptera", + "Spumella vulgaris\t-\t1\t1\t11\t1117031\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; Chromulinales; Chromulinaceae; Spumella", + "Spumella-like flagellate JBC/S23\t-\t1\t1\t11\t293195\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; unclassified Chrysophyceae; Spumella-like flagellate JB", + "Spumella-like flagellate JBNZ39\t-\t1\t1\t11\t293202\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; unclassified Chrysophyceae; Spumella-like flagellate JB", + "Staphylococcus aureus\t-\t11\t0\t-\t1280\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Bacillales; Staphylococcaceae; Staphylococcus", + "Staphylococcus epidermidis\t-\t11\t0\t-\t1282\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Bacillales; Staphylococcaceae; Staphylococcus", + "Stegastes partitus\tbicolor damselfish\t1\t2\t-\t144197\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Ovalentaria incertae sedis; Pomacentridae; Stegastes", + "Stegodyphus mimosarum\t-\t1\t5\t-\t407821\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Araneae; Araneomorphae; Entelegynae; Eresoidea; Eresidae; Stegodyphus", + "Stenotrophomonas maltophilia\t-\t11\t0\t-\t40324\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Xanthomonadales; Xanthomonadaceae; Stenotrophomonas; Stenotrophomonas maltophilia group", + "Stigmatomma oregonense\t-\t1\t5\t-\t602440\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Amblyoponinae; Stigmatomma", + "Stomoxys calcitrans\tstable fly\t1\t5\t-\t35570\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Calyptratae; Muscoidea; Muscidae; Muscinae; Stomoxyini; Stomoxys", + "Streptococcus agalactiae\t-\t11\t0\t-\t1311\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Streptococcaceae; Streptococcus", + "Streptococcus equi subsp. equi\t-\t11\t0\t-\t148942\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Streptococcaceae; Streptococcus; Streptococcus dysgalactiae group; Streptococcus equi", + "Streptococcus pneumoniae\t-\t11\t0\t-\t1313\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Streptococcaceae; Streptococcus", + "Streptococcus suis\t-\t11\t0\t-\t1307\tBCT\tcellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Streptococcaceae; Streptococcus", + "Strongylocentrotus purpuratus\tpurple sea urchin\t1\t9\t-\t7668\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Euechinoidea; Echinacea; Echinoida; Strongylocentrotidae; Strongylocentrotus", + "Strongylus vulgaris\t-\t1\t5\t-\t40348\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Strongyloidea; Strongylidae; Strongylinae; Strongylus", + "Struthio camelus australis\t-\t1\t2\t-\t441894\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Palaeognathae; Struthioniformes; Struthionidae; Struthio; Struthio camelus", + "Stylophora pistillata\t-\t1\t4\t-\t50429\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Astrocoeniina; Pocilloporidae; Stylophora", + "Sus scrofa\tpig\t1\t2\t-\t9823\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Suina; Suidae; Sus", + "Symbiodinium sp. A1\t-\t1\t4\t11\t503409\tPLN\tcellular organisms; Eukaryota; Alveolata; Dinophyceae; Suessiales; Symbiodiniaceae; Symbiodinium; Symbiodinium sp. clades; Symbiodinium sp. clade A", + "Symbiodinium sp. A2\t-\t1\t4\t11\t765178\tPLN\tcellular organisms; Eukaryota; Alveolata; Dinophyceae; Suessiales; Symbiodiniaceae; Symbiodinium; Symbiodinium sp. clades; Symbiodinium sp. clade A", + "Symbiodinium sp. B2\t-\t1\t4\t11\t154560\tPLN\tcellular organisms; Eukaryota; Alveolata; Dinophyceae; Suessiales; Symbiodiniaceae; Symbiodinium; Symbiodinium sp. clades; Symbiodinium sp. clade B", + "Symphylella vulgaris\t-\t1\t5\t-\t1288507\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Myriapoda; Symphyla; Scolopendrellidae; Symphylella", + "synthetic construct\t-\t11\t0\t11\t32630\tSYN\tother sequences; artificial sequences", + "Synura sp. LO234KE\t-\t1\t1\t11\t1825120\tPLN\tcellular organisms; Eukaryota; Stramenopiles; Synurophyceae; Synurales; Mallomonadaceae; Synura", + "Taeniopygia guttata\tzebra finch\t1\t2\t-\t59729\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Passeroidea; Estrildidae; Estrildinae; Taeniopygia", + "Takifugu rubripes\ttorafugu\t1\t2\t-\t31033\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Tetraodontiformes; Tetraodontoidei; Tetradontoidea; Tetraodontidae; Takifugu", + "Tarenaya hassleriana\t-\t1\t1\t11\t28532\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Cleomaceae; Tarenaya", + "Tauraco erythrolophus\tred-crested turaco\t1\t2\t-\t121530\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Musophagiformes; Musophagidae; Tauraco", + "Taxus wallichiana var. chinensis\t-\t1\t1\t11\t29808\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Cupressales; Taxaceae; Taxus; Taxus wallichiana", + "Telenomus podisi\t-\t1\t5\t-\t408256\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Platygastroidea; Scelionidae; Telenominae; Telenomus", + "Teleogryllus commodus\t-\t1\t5\t-\t672150\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Orthoptera; Ensifera; Grylloidea; Gryllidae; Gryllinae; Teleogryllus", + "Teleopsis dalmanni\t-\t1\t5\t-\t139649\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Diopsoidea; Diopsidae; Teleopsis", + "Teleopsis whitei\t-\t1\t5\t-\t139651\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Diopsoidea; Diopsidae; Teleopsis", + "Termitomyces clypeatus MTCC 5091\t-\t1\t4\t-\t1282671\tPLN\tcellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Basidiomycota; Agaricomycotina; Agaricomycetes; Agaricomycetidae; Agaricales; Lyophyllaceae; Termitomyces; Termitomyces clypeatus", + "Tetramorium bicarinatum\t-\t1\t5\t-\t219812\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Tetramoriini; Tetramorium", + "Tetranychus urticae\ttwo-spotted spider mite\t1\t5\t-\t32264\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Acariformes; Trombidiformes; Prostigmata; Eleutherengona; Raphignathae; Tetranychoidea; Tetranychidae; Tetranychus", + "Tetraodon nigroviridis\tspotted green pufferfish\t1\t2\t-\t99883\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Tetraodontiformes; Tetraodontoidei; Tetradontoidea; Tetraodontidae; Tetraodon", + "Tetraselmis subcordiformis\t-\t1\t1\t11\t3161\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Chlorophyta; Chlorodendrophyceae; Chlorodendrales; Chlorodendraceae; Tetraselmis", + "Thamnophis sirtalis\t-\t1\t2\t-\t35019\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Unidentata; Episquamata; Toxicofera; Serpentes; Colubroidea; Colubridae; Natricinae; Thamnophis", + "Theobroma cacao\tcacao\t1\t1\t11\t3641\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Malvales; Malvaceae; Byttnerioideae; Theobroma", + "Thermobia domestica\tfirebrat\t1\t5\t-\t89055\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Zygentoma; Lepismatidae; Thermobia", + "Tigriopus californicus\t-\t1\t5\t-\t6832\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Podoplea; Harpacticoida; Harpacticidae; Tigriopus", + "Tinamus guttatus\twhite-throated tinamou\t1\t2\t-\t94827\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Palaeognathae; Tinamiformes; Tinamidae; Tinamus", + "Trachemys scripta elegans\t-\t1\t2\t-\t31138\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Testudines; Cryptodira; Durocryptodira; Testudinoidea; Emydidae; Trachemys; Trachemys scripta", + "Trachymyrmex cornetzi\t-\t1\t5\t-\t471704\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Attini; Trachymyrmex", + "Trematomus bernacchii\temerald rockcod\t1\t2\t-\t40690\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Perciformes; Notothenioidei; Nototheniidae; Trematomus", + "Trichechus manatus latirostris\tFlorida manatee\t1\t2\t-\t127582\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Sirenia; Trichechidae; Trichechus; Trichechus manatus", + "Trichinella spiralis\t-\t1\t5\t-\t6334\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Enoplea; Dorylaimia; Trichocephalida; Trichinellidae; Trichinella", + "Trichobilharzia regenti\t-\t1\t9\t-\t157069\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Trichobilharzia", + "Trichomonas vaginalis G3\t-\t1\t0\t11\t412133\tINV\tcellular organisms; Eukaryota; Parabasalia; Trichomonadida; Trichomonadidae; Trichomonas; Trichomonas vaginalis", + "Trichoplusia ni\tcabbage looper\t1\t5\t-\t7111\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Plusiinae; Trichoplusia", + "Trifolium pratense\t-\t1\t1\t11\t57577\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Trifolieae; Trifolium", + "Tripterygion delaisi\t-\t1\t2\t-\t57862\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Blenniimorphae; Blenniiformes; Blennioidei; Tripterygiidae; Tripterygiinae; Tripterygion", + "Tripterygium wilfordii\t-\t1\t1\t11\t458696\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Celastrales; Celastraceae; Tripterygium", + "Triticum aestivum\tbread wheat\t1\t1\t11\t4565\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Triticinae; Triticum", + "Triticum turgidum\t-\t1\t1\t11\t4571\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Triticinae; Triticum", + "Triticum urartu\t-\t1\t1\t11\t4572\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Triticinae; Triticum", + "Trypanosoma cruzi strain CL Brener\t-\t1\t4\t11\t353153\tINV\tcellular organisms; Eukaryota; Euglenozoa; Kinetoplastida; Trypanosomatidae; Trypanosoma; Schizotrypanum; Trypanosoma cruzi", + "Tupaia chinensis\tChinese tree shrew\t1\t2\t-\t246437\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Scandentia; Tupaiidae; Tupaia", + "Turritopsis sp. SK-2016\t-\t1\t4\t-\t1784781\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Hydrozoa; Hydroidolina; Anthoathecata; Filifera; Oceaniidae; Turritopsis", + "Tursiops truncatus\tbottlenosed dolphin\t1\t2\t-\t9739\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Cetacea; Odontoceti; Delphinidae; Tursiops", + "Tyto alba\tbarn owl\t1\t2\t-\t56313\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Strigiformes; Tytonidae; Tyto", + "uncultured archaeon\t-\t11\t0\t-\t115547\tENV\tcellular organisms; Archaea; environmental samples", + "uncultured bacterium\t-\t11\t0\t-\t77133\tENV\tcellular organisms; Bacteria; environmental samples", + "uncultured eukaryote\t-\t1\t1\t11\t100272\tENV\tcellular organisms; Eukaryota; environmental samples", + "uncultured fungus\t-\t1\t4\t-\t175245\tENV\tcellular organisms; Eukaryota; Opisthokonta; Fungi; environmental samples", + "uncultured microorganism\t-\t11\t2\t11\t358574\tENV\tunclassified sequences; environmental samples", + "uncultured Neocallimastigales\t-\t1\t0\t-\t325898\tENV\tcellular organisms; Eukaryota; Opisthokonta; Fungi; Neocallimastigomycota; Neocallimastigomycetes; Neocallimastigales; environmental samples", + "uncultured organism\t-\t11\t2\t11\t155900\tENV\tunclassified sequences; environmental samples", + "uncultured prokaryote\t-\t11\t0\t11\t198431\tENV\tunclassified sequences; environmental samples; prokaryotic environmental samples", + "uncultured Pseudomonas sp.\t-\t11\t0\t-\t114707\tENV\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Pseudomonadales; Pseudomonadaceae; Pseudomonas; environmental samples", + "uncultured soil bacterium\t-\t11\t0\t-\t164851\tENV\tcellular organisms; Bacteria; environmental samples", + "unidentified\t-\t1\t2\t11\t32644\tUNA\tunclassified sequences", + "unidentified bacterium\t-\t11\t0\t-\t1826778\tBCT\tcellular organisms; Bacteria; unclassified Bacteria; unclassified Bacteria (miscellaneous)", + "Ursus maritimus\tpolar bear\t1\t2\t-\t29073\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Ursidae; Ursus", + "Vaccinium macrocarpon\t-\t1\t1\t11\t13750\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Ericales; Ericaceae; Vaccinioideae; Vaccinieae; Vaccinium", + "Vibrio cholerae\t-\t11\t0\t-\t666\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Vibrionales; Vibrionaceae; Vibrio", + "Vibrio parahaemolyticus\t-\t11\t0\t-\t670\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Vibrionales; Vibrionaceae; Vibrio; Vibrio harveyi group", + "Vicia faba\tfava bean\t1\t1\t11\t3906\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Fabeae; Vicia", + "Vicugna pacos\talpaca\t1\t2\t-\t30538\tMAM\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Tylopoda; Camelidae; Vicugna", + "Vigna angularis\tadzuki bean\t1\t1\t11\t3914\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Vigna", + "Vigna radiata\t-\t1\t1\t11\t157791\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Vigna", + "Vigna radiata var. radiata\tmung bean\t1\t1\t11\t3916\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Vigna; Vigna radiata", + "Villosa lienosa\t-\t1\t5\t-\t326719\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Palaeoheterodonta; Unionoida; Unionoidea; Unionidae; Unioninae; Villosa", + "Vitis vinifera\twine grape\t1\t1\t11\t29760\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; rosids incertae sedis; Vitales; Vitaceae; Vitis", + "Vollenhovia emeryi\t-\t1\t5\t-\t411798\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Stenammini; Vollenhovia", + "Wasmannia auropunctata\tlittle fire ant\t1\t5\t-\t64793\tINV\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Blepharidattini; Wasmannia", + "Withania somnifera\t-\t1\t1\t11\t126910\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Physaleae; Withania", + "Xanthomonas citri pv. citri\t-\t11\t0\t-\t434928\tBCT\tcellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Xanthomonadales; Xanthomonadaceae; Xanthomonas; Xanthomonas citri group; Xanthomonas citri", + "Xenopus laevis\tAfrican clawed frog\t1\t2\t-\t8355\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Pipoidea; Pipidae; Xenopodinae; Xenopus; Xenopus", + "Xenopus tropicalis\ttropical clawed frog\t1\t2\t-\t8364\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Pipoidea; Pipidae; Xenopodinae; Xenopus; Silurana", + "Xiphophorus maculatus\tsouthern platyfish\t1\t2\t-\t8083\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Xiphophorus", + "Zantedeschia aethiopica\t-\t1\t1\t11\t69721\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Alismatales; Araceae; Philodendroideae; Zantedeschieae; Zantedeschia", + "Zea mays\t-\t1\t1\t11\t4577\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Andropogonodae; Andropogoneae; Tripsacinae; Zea", + "Zea mays subsp. mays\tmaize\t1\t1\t11\t381124\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Andropogonodae; Andropogoneae; Tripsacinae; Zea; Zea mays", + "Ziziphus jujuba\t-\t1\t1\t11\t326968\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rhamnaceae; Paliureae; Ziziphus", + "Zonotrichia albicollis\twhite-throated sparrow\t1\t2\t-\t44394\tVRT\tcellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Passerellidae; Zonotrichia", + "Zostera noltei\t-\t1\t1\t11\t55326\tPLN\tcellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Alismatales; Zosteraceae; Zostera" +}; diff --git a/c++/src/objects/seqfeat/common_tax.txt b/c++/src/objects/seqfeat/common_tax.txt new file mode 100644 index 00000000..5e0a3622 --- /dev/null +++ b/c++/src/objects/seqfeat/common_tax.txt @@ -0,0 +1,900 @@ +Acacia koa - 1 1 11 468172 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Mimosoideae; Acacieae; Acacia +Acanthisitta chloris rifleman 1 2 - 57068 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Acanthisittidae; Acanthisitta +Acanthoscurria geniculata - 1 5 - 575412 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Araneae; Mygalomorphae; Theraphosidae; Acanthoscurria +Acinetobacter baumannii - 11 0 - 470 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Pseudomonadales; Moraxellaceae; Acinetobacter; Acinetobacter calcoaceticus/baumannii complex +Acinetobacter pittii - 11 0 - 48296 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Pseudomonadales; Moraxellaceae; Acinetobacter; Acinetobacter calcoaceticus/baumannii complex +Acinonyx jubatus cheetah 1 2 - 32536 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Feliformia; Felidae; Acinonychinae; Acinonyx +Acropora cervicornis - 1 4 - 6130 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Astrocoeniina; Acroporidae; Acropora +Acropora digitifera - 1 4 - 70779 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Astrocoeniina; Acroporidae; Acropora +Acropora millepora - 1 4 - 45264 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Astrocoeniina; Acroporidae; Acropora +Actias selene Indian moon moth 1 5 - 37776 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Saturniini; Actias +Acyrthosiphon pisum pea aphid 1 5 - 7029 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Sternorrhyncha; Aphidiformes; Aphidomorpha; Aphidoidea; Aphididae; Aphidinae; Macrosiphini; Acyrthosiphon +Adineta vaga - 1 5 - 104782 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Rotifera; Bdelloidea; Adinetida; Adinetidae; Adineta +Aedes aegypti yellow fever mosquito 1 5 - 7159 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Culicomorpha; Culicoidea; Culicidae; Culicinae; Aedini; Aedes; Stegomyia +Aedes albopictus Asian tiger mosquito 1 5 - 7160 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Culicomorpha; Culicoidea; Culicidae; Culicinae; Aedini; Aedes; Stegomyia +Aegilops tauschii - 1 1 11 37682 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Triticinae; Aegilops +Aethina tumida small hive beetle 1 5 - 116153 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Cucujoidea; Nitidulidae; Nitidulinae; Aethina +Agapanthus praecox subsp. orientalis - 1 1 11 547170 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Amaryllidaceae; Agapanthoideae; Agapanthus; Agapanthus praecox +Agave deserti - 1 1 11 382119 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Asparagaceae; Agavoideae; Agave +Agave tequilana - 1 1 11 386106 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Asparagaceae; Agavoideae; Agave +Agrilus planipennis emerald ash borer 1 5 - 224129 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Elateriformia; Buprestoidea; Buprestidae; Agrilinae; Agrilus +Agrotis segetum turnip moth 1 5 - 47767 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Noctuinae; Agrotis +Ailuropoda melanoleuca giant panda 1 2 - 9646 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Ursidae; Ailuropoda +Alexandrium tamarense - 1 4 11 2926 PLN cellular organisms; Eukaryota; Alveolata; Dinophyceae; Gonyaulacales; Gonyaulacaceae; Alexandrium +Alligator mississippiensis American alligator 1 2 - 8496 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Crocodylia; Alligatoridae; Alligatorinae; Alligator +Alligator sinensis Chinese alligator 1 2 - 38654 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Crocodylia; Alligatoridae; Alligatorinae; Alligator +Allium cepa onion 1 1 11 4679 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Amaryllidaceae; Allioideae; Allieae; Allium +Allium fistulosum Welsh onion 1 1 11 35875 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Amaryllidaceae; Allioideae; Allieae; Allium +Allium sativum garlic 1 1 11 4682 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Amaryllidaceae; Allioideae; Allieae; Allium +Amaranthus tricolor - 1 1 11 29722 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Amaranthaceae; Amaranthus +Amazona vittata Puerto Rican parrot 1 2 - 241585 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Psittaciformes; Psittacidae; Amazona +Ameiurus nebulosus brown bullhead 1 2 - 27778 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Characiphysae; Siluriformes; Siluroidei; Ictaluridae; Ameiurus +Amoebidium parasiticum JAP-7-2 - 1 4 - 1069442 INV cellular organisms; Eukaryota; Opisthokonta; Opisthokonta incertae sedis; Ichthyosporea; Ichthyophonida; Amoebidiaceae; Amoebidium; Amoebidium parasiticum +Anas platyrhynchos mallard 1 2 - 8839 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Anseriformes; Anatidae; Anas +Ancylostoma ceylanicum - 1 5 - 53326 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Ancylostomatoidea; Ancylostomatidae; Ancylostomatinae; Ancylostoma +Ancylostoma duodenale - 1 5 - 51022 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Ancylostomatoidea; Ancylostomatidae; Ancylostomatinae; Ancylostoma +Anguilla anguilla European eel 1 2 - 7936 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Elopocephalai; Elopocephala; Elopomorpha; Anguilliformes; Anguillidae; Anguilla +Anguilla japonica Japanese eel 1 2 - 7937 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Elopocephalai; Elopocephala; Elopomorpha; Anguilliformes; Anguillidae; Anguilla +Anisakis simplex herring worm 1 5 - 6269 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Ascaridida; Ascaridoidea; Anisakidae; Anisakis; Anisakis simplex complex +Anneissia japonica - 1 9 - 1529436 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Pelmatozoa; Crinoidea; Articulata; Comatulida; Comatulidae; Comatulinae; Anneissia +Annulipalpia sp. AD-2013 - 1 5 - 1499517 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Trichoptera; Annulipalpia; Unclassified Annulipalpia +Anolis carolinensis green anole 1 2 - 28377 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Unidentata; Episquamata; Toxicofera; Iguania; Iguanidae; Polychrotinae; Anolis +Anopheles funestus African malaria mosquito 1 5 - 62324 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Culicomorpha; Culicoidea; Culicidae; Anophelinae; Anopheles; Cellia; Myzomyia; funestus group; funestus subgroup +Anopheles gambiae African malaria mosquito 1 5 - 7165 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Culicomorpha; Culicoidea; Culicidae; Anophelinae; Anopheles; Cellia; Pyretophorus; gambiae species complex +Anopheles sinensis - 1 5 - 74873 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Culicomorpha; Culicoidea; Culicidae; Anophelinae; Anopheles; Anopheles; Laticorn; Myzorhynchus; hyrcanus group +Anoplophora glabripennis Asian longhorned beetle 1 5 - 217634 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Chrysomeloidea; Cerambycidae; Lamiinae; Lamiini; Anoplophora +Anoplopoma fimbria sablefish 1 2 - 229290 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Perciformes; Cottioidei; Anoplopomatales; Anoplopomatidae; Anoplopoma +Anser cygnoides domesticus - 1 2 - 381198 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Anseriformes; Anatidae; Anser; Anser cygnoides +Antheraea assama Indian muga silkmoth 1 5 - 91021 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Saturniini; Antheraea +Antheraea pernyi Chinese oak silkmoth 1 5 - 7119 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Saturniini; Antheraea +Antheraea yamamai Japanese oak silkmoth 1 5 - 7121 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Saturniini; Antheraea +Anthopleura elegantissima clonal anemone 1 4 - 6110 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Actiniaria; Nynantheae; Actiniidae; Anthopleura +Anthoxanthum odoratum - 1 1 11 29661 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Poodae; Poeae; Poeae Chloroplast Group 1 (Aveneae type); Anthoxanthinae; Anthoxanthum +Anthurium andraeanum - 1 1 11 226677 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Alismatales; Araceae; Pothoideae; Potheae; Anthurium +Aotus nancymaae Ma's night monkey 1 2 - 37293 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Platyrrhini; Aotidae; Aotus +Apaloderma vittatum bar-tailed trogon 1 2 - 57397 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Trogoniformes; Trogonidae; Apaloderma +Aphelocoma californica obscura - 1 2 - 947029 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Corvoidea; Corvidae; Aphelocoma; Aphelocoma californica +Aphyosemion striatum - 1 2 - 60296 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Aphyosemion +Apis cerana Asiatic honeybee 1 5 - 7461 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Apinae; Apini; Apis +Apis florea little honeybee 1 5 - 7463 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Apinae; Apini; Apis +Apis mellifera honey bee 1 5 - 7460 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Apinae; Apini; Apis +Aplysia californica California sea hare 1 5 - 6500 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Heterobranchia; Euthyneura; Euopisthobranchia; Aplysiomorpha; Aplysioidea; Aplysiidae; Aplysia +Apostichopus japonicus Japanese sea cucumber 1 9 - 307972 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Holothuroidea; Aspidochirotacea; Aspidochirotida; Stichopodidae; Apostichopus +Apteryx australis mantelli - 1 2 - 202946 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Palaeognathae; Apterygiformes; Apterygidae; Apteryx; Apteryx australis +Aquila chrysaetos canadensis - 1 2 - 216574 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Falconiformes; Accipitridae; Accipitrinae; Aquila; Aquila chrysaetos +Ara macao scarlet macaw 1 2 - 176014 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Psittaciformes; Psittacidae; Ara +Arabidopsis lyrata subsp. lyrata - 1 1 11 81972 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Camelineae; Arabidopsis; Arabidopsis lyrata +Arabidopsis thaliana thale cress 1 1 11 3702 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Camelineae; Arabidopsis +Arachis duranensis - 1 1 11 130453 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Dalbergieae; Arachis +Arachis hypogaea peanut 1 1 11 3818 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Dalbergieae; Arachis +Arachis hypogaea var. vulgaris - 1 1 11 925390 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Dalbergieae; Arachis; Arachis hypogaea; Arachis hypogaea subsp. fastigiata +Arachis ipaensis - 1 1 11 130454 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Dalbergieae; Arachis +Araucaria cunninghamii - 1 1 11 56994 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Araucariales; Araucariaceae; Araucaria +Archaeopsylla erinacei - 1 5 - 48909 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Siphonaptera; Pulicomorpha; Pulicoidea; Pulicidae; Archaeopsyllinae; Archaeopsylla +Aretaon asperrimus thorny stick insect 1 5 - 173775 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Phasmatodea; Verophasmatodea; Areolatae; Bacilloidea; Heteropterygidae; Obriminae; Obrimini; Aretaon +Argochrysis armilla - 1 5 - 1317734 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Chrysidoidea; Chrysididae; Chrysidinae; Chrysidini; Argochrysis +Argulus siamensis - 1 5 - 1167309 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Branchiura; Arguloida; Argulidae; Argulus +Arion vulgaris - 1 5 - 1028688 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Heterobranchia; Euthyneura; Panpulmonata; Eupulmonata; Stylommatophora; Sigmurethra; Arionoidea; Arionidae; Arion +Artemisia annua sweet wormwood 1 1 11 35608 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Asteroideae; Anthemideae; Artemisiinae; Artemisia +artificial sequences - 11 0 11 81077 SYN other sequences +Arundo donax giant reed 1 1 11 35708 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Arundinoideae; Arundineae; Arundo +Ascaris suum pig roundworm 1 5 - 6253 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Ascaridida; Ascaridoidea; Ascarididae; Ascaris +Aspergillus oryzae - 1 4 - 5062 PLN cellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Ascomycota; saccharomyceta; Pezizomycotina; leotiomyceta; Eurotiomycetes; Eurotiomycetidae; Eurotiales; Aspergillaceae; Aspergillus +Aspidistra saxicola - 1 1 11 1197444 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Asparagaceae; Nolinoideae; Aspidistra +Astacus astacus broad-fingered crayfish 1 5 - 6715 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Astacidea; Astacoidea; Astacidae; Astacus +Astacus leptodactylus narrow-clawed crayfish 1 5 - 6717 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Astacidea; Astacoidea; Astacidae; Astacus +Asterias amurensis - 1 9 - 7602 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Asterias +Asterias forbesi Forbes's starfish 1 9 - 7603 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Asterias +Asterias rubens European starfish 1 9 - 7604 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Asterias +Astyanax mexicanus Mexican tetra 1 2 - 7994 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Characiphysae; Characiformes; Characoidei; Characidae; Characidae incertae sedis; Astyanax clade; Astyanax +Athetis lepigone - 1 5 - 1223490 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Noctuinae; Athetis +Atractaspis aterrima mole viper 1 2 - 1355159 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Unidentata; Episquamata; Toxicofera; Serpentes; Colubroidea; Lamprophiidae; Atractaspidinae; Atractaspis +Aurelia aurita moon jelly 1 4 - 6145 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Scyphozoa; Semaeostomeae; Ulmaridae; Aurelia +Austrofundulus limnaeus - 1 2 - 52670 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Rivulidae; Austrofundulus +Avena sativa oat 1 1 11 4498 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Poodae; Poeae; Aveninae; Avena +Avicennia marina - 1 1 11 82927 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Acanthaceae; Avicennioideae; Avicennia +Bacillus cereus - 11 0 - 1396 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Bacillales; Bacillaceae; Bacillus; Bacillus cereus group +Bacillus licheniformis - 11 0 - 1402 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Bacillales; Bacillaceae; Bacillus; Bacillus subtilis group +Bactrocera cucurbitae melon fly 1 5 - 28588 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Dacini; Bactrocera; Zeugodacus +Bactrocera dorsalis oriental fruit fly 1 5 - 27457 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Dacini; Bactrocera; Bactrocera; Bactrocera dorsalis species complex +Bactrocera latifrons - 1 5 - 174628 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Dacini; Bactrocera; Bactrocera +Bactrocera minax Oriental citrus fly 1 5 - 104690 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Dacini; Bactrocera; Tetradacus +Bactrocera oleae olive fruit fly 1 5 - 104688 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Dacini; Bactrocera; Daculus +Balaenoptera acutorostrata scammoni - 1 2 - 310752 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Cetacea; Mysticeti; Balaenopteridae; Balaenoptera; Balaenoptera acutorostrata +Balaenoptera bonaerensis Antarctic minke whale 1 2 - 33556 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Cetacea; Mysticeti; Balaenopteridae; Balaenoptera +Balearica regulorum gibbericeps East African grey crowned-crane 1 2 - 100784 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gruiformes; Gruidae; Balearica; Balearica regulorum +Banksia hookeriana - 1 1 11 199770 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; stem eudicotyledons; Proteales; Proteaceae; Banksia +Bdellocephala annandalei - 1 9 - 1421413 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Rhabditophora; Seriata; Tricladida; Continenticola; Planarioidea; Dendrocoelidae; Bdellocephala +Bemisia tabaci - 1 5 - 7038 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Sternorrhyncha; Aleyrodiformes; Aleyrodoidea; Aleyrodidae; Aleyrodinae; Bemisia +Beta vulgaris - 1 1 11 161934 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Chenopodiaceae; Betoideae; Beta +Beta vulgaris subsp. vulgaris - 1 1 11 3555 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Chenopodiaceae; Betoideae; Beta; Beta vulgaris +Betula platyphylla - 1 1 11 78630 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fagales; Betulaceae; Betula +Biomphalaria glabrata - 1 5 - 6526 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Heterobranchia; Euthyneura; Panpulmonata; Hygrophila; Planorboidea; Planorbidae; Biomphalaria +Bison bison bison - 1 2 - 43346 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Bovinae; Bison; Bison bison +Bithynia siamensis goniomphalos - 1 5 - 479249 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Caenogastropoda; Hypsogastropoda; Littorinimorpha; Truncatelloidea; Bithyniidae; Bithynia; Bithynia siamensis +Boechera gunnisoniana - 1 1 11 93888 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Boechereae; Boechera +Bombina bombina fire-bellied toad 1 2 - 8345 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Bombinatoridae; Bombina +Bombina orientalis - 1 2 - 8346 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Bombinatoridae; Bombina +Bombina variegata scabra - 1 2 - 251232 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Bombinatoridae; Bombina; Bombina variegata +Bombina variegata variegata - 1 2 - 191472 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Bombinatoridae; Bombina; Bombina variegata +Bombus impatiens common eastern bumble bee 1 5 - 132113 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Bombinae; Bombini; Bombus; Pyrobombus +Bombus insularis - 1 5 - 207637 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Bombinae; Bombini; Bombus; Psithyrus +Bombus terrestris buff-tailed bumblebee 1 5 - 30195 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Bombinae; Bombini; Bombus; Bombus +Bombyx mori domestic silkworm 1 5 - 7091 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Bombycidae; Bombycinae; Bombyx +Bordetella pertussis - 11 0 - 520 BCT cellular organisms; Bacteria; Proteobacteria; Betaproteobacteria; Burkholderiales; Alcaligenaceae; Bordetella +Bos mutus wild yak 1 2 - 72004 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Bovinae; Bos +Bos taurus cattle 1 2 - 9913 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Bovinae; Bos +Botryococcus braunii - 1 1 11 38881 PLN cellular organisms; Eukaryota; Viridiplantae; Chlorophyta; Trebouxiophyceae; Trebouxiophyceae incertae sedis; Botryococcaceae; Botryococcus +Brachionus calyciflorus - 1 5 - 104777 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Rotifera; Monogononta; Pseudotrocha; Ploima; Brachionidae; Brachionus +Brachycistis timberlakei - 1 5 - 1317728 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Tiphiidae; Brachycistidinae; Brachycistis +Brachypodium distachyon stiff brome 1 1 11 15368 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Brachypodieae; Brachypodium +Bragasellus peltatus - 1 5 - 1282048 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Bragasellus +Branchiostoma lanceolatum amphioxus 1 5 - 7740 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Cephalochordata; Branchiostomidae; Branchiostoma +Brassica juncea - 1 1 11 3707 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica +Brassica napus rape 1 1 11 3708 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica +Brassica oleracea var. capitata cabbage 1 1 11 3716 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica; Brassica oleracea +Brassica oleracea var. oleracea - 1 1 11 109376 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica; Brassica oleracea +Brassica rapa field mustard 1 1 11 3711 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica +Brassica rapa subsp. pekinensis Chinese cabbage 1 1 11 51351 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica; Brassica rapa +Brassica rapa x Raphanus sativus - 1 1 11 1417620 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Brassica x Raphanus +Brassicogethes aeneus - 1 5 - 1431903 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Cucujoidea; Nitidulidae; Meligethinae; Brassicogethes +Brugia malayi - 1 5 - 6279 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Spirurida; Filarioidea; Onchocercidae; Brugia +Bubalus bubalis water buffalo 1 2 - 89462 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Bovinae; Bubalus +Buceros rhinoceros silvestris - 1 2 - 175836 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Bucerotiformes; Bucerotidae; Buceros; Buceros rhinoceros +Burkholderia ubonensis - 11 0 - 101571 BCT cellular organisms; Bacteria; Proteobacteria; Betaproteobacteria; Burkholderiales; Burkholderiaceae; Burkholderia +Caenorhabditis elegans - 1 5 - 6239 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Rhabditoidea; Rhabditidae; Peloderinae; Caenorhabditis +Caenorhabditis remanei - 1 5 - 31234 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Rhabditoidea; Rhabditidae; Peloderinae; Caenorhabditis +Cajanus cajan pigeon pea 1 1 11 3821 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Cajanus +Calanus finmarchicus - 1 5 - 6837 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Gymnoplea; Calanoida; Calanidae; Calanus +Calanus glacialis - 1 5 - 113644 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Gymnoplea; Calanoida; Calanidae; Calanus +Calidris pugnax ruff 1 2 - 198806 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Charadriiformes; Scolopacidae; Calidris +Caligus rogercresseyi - 1 5 - 217165 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Podoplea; Siphonostomatoida; Caligidae; Caligus +Callithrix jacchus white-tufted-ear marmoset 1 2 - 9483 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Platyrrhini; Cebidae; Callitrichinae; Callithrix +Callorhinchus milii elephant shark 1 2 - 7868 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Chondrichthyes; Holocephali; Chimaeriformes; Callorhinchidae; Callorhinchus +Calypte anna Anna's hummingbird 1 2 - 9244 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Trochiliformes; Trochilidae; Calypte +Camelina sativa false flax 1 1 11 90675 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Camelineae; Camelina +Camellia oleifera - 1 1 11 385388 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Ericales; Theaceae; Camellia +Camellia sinensis - 1 1 11 4442 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Ericales; Theaceae; Camellia +Camellia sinensis var. sinensis - 1 1 11 542762 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Ericales; Theaceae; Camellia; Camellia sinensis +Camelus bactrianus Bactrian camel 1 2 - 9837 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Tylopoda; Camelidae; Camelus +Camelus dromedarius Arabian camel 1 2 - 9838 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Tylopoda; Camelidae; Camelus +Camelus ferus Wild Bactrian camel 1 2 - 419612 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Tylopoda; Camelidae; Camelus +Camponotus floridanus Florida carpenter ant 1 5 - 104421 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Camponotini; Camponotus +Camptotheca acuminata - 1 1 11 16922 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Cornales; Nyssaceae; Camptotheca +Campylobacter coli - 11 0 - 195 BCT cellular organisms; Bacteria; Proteobacteria; delta/epsilon subdivisions; Epsilonproteobacteria; Campylobacterales; Campylobacteraceae; Campylobacter +Campylobacter jejuni - 11 0 - 197 BCT cellular organisms; Bacteria; Proteobacteria; delta/epsilon subdivisions; Epsilonproteobacteria; Campylobacterales; Campylobacteraceae; Campylobacter +Canis lupus familiaris dog 1 2 - 9615 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Canidae; Canis; Canis lupus +Cannabis sativa hemp 1 1 11 3483 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Cannabaceae; Cannabis +Capra hircus goat 1 2 - 9925 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Caprinae; Capra +Caprimulgus carolinensis chuck-will's-widow 1 2 - 279965 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Caprimulgiformes; Caprimulgidae; Caprimulginae; Caprimulgus +Capsella rubella - 1 1 11 81985 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Camelineae; Capsella +Capsicum annuum - 1 1 11 4072 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Capsiceae; Capsicum +Carabus granulatus - 1 5 - 118799 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Adephaga; Caraboidea; Carabidae; Carabinae; Carabini; Carabina; Carabus; Carabus +Caragana korshinskii - 1 1 11 220689 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Caraganeae; Caragana +Cariama cristata red-legged seriema 1 2 - 54380 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gruiformes; Cariamidae; Cariama +Carlito syrichta Philippine tarsier 1 2 - 1868482 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Tarsiiformes; Tarsiidae; Carlito +Catharanthus roseus Madagascar periwinkle 1 1 11 4058 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Apocynaceae; Rauvolfioideae; Vinceae; Catharanthinae; Catharanthus +Cathartes aura turkey vulture 1 2 - 43455 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Ciconiiformes; Cathartidae; Cathartes +Cavia porcellus domestic guinea pig 1 2 - 10141 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Caviidae; Cavia +Cebus capucinus imitator - 1 2 - 1737458 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Platyrrhini; Cebidae; Cebinae; Cebus; Cebus capucinus +Cecidomyiidae sp. BOLD-2016 - 1 5 - 1881751 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Nematocera; Bibionomorpha; Sciaroidea; Cecidomyiidae; unclassified Cecidomyiidae +Cenchrus americanus - 1 1 11 4543 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Panicodae; Paniceae; Cenchrinae; Cenchrus +Centris flavifrons - 1 5 - 360639 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Anthophorinae; Centridini; Centris +Cephalotaxus hainanensis - 1 1 11 191701 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Cupressales; Taxaceae; Cephalotaxus +Cerapachys biroi clonal raider ant 1 5 - 443821 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Cerapachyinae; Cerapachyini; Cerapachys +Ceratina calcarata - 1 5 - 156304 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Xylocopinae; Ceratinini; Ceratina; Zadontomerus +Ceratitis capitata Mediterranean fruit fly 1 5 - 7213 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Dacinae; Ceratitidini; Ceratitis; Ceratitis +Ceratotherium simum simum southern white rhinoceros 1 2 - 73337 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Perissodactyla; Rhinocerotidae; Ceratotherium; Ceratotherium simum +Cercis gigantea - 1 1 11 183790 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Cercideae; Cercis +Cercocebus atys sooty mangabey 1 2 - 9531 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Cercocebus +Chaetura pelagica chimney swift 1 2 - 8897 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Apodiformes; Apodidae; Chaetura +Charadrius vociferus killdeer 1 2 - 50402 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Charadriiformes; Charadriidae; Charadrius +Chelonia mydas green sea turtle 1 2 - 8469 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Testudines; Cryptodira; Durocryptodira; Americhelydia; Chelonioidea; Cheloniidae; Chelonia +Cherax quadricarinatus - 1 5 - 27406 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Astacidea; Parastacoidea; Parastacidae; Cherax +Chilo suppressalis striped riceborer 1 5 - 168631 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Pyraloidea; Crambidae; Crambinae; Chilo +Chinavia ubica - 1 5 - 1497372 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Neohemiptera; Prosorrhyncha; Heteroptera; Euheteroptera; Neoheteroptera; Panheteroptera; Pentatomomorpha; Pentatomoidea; Pentatomidae; Pentatominae; Chinavia +Chinchilla lanigera long-tailed chinchilla 1 2 - 34839 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Chinchillidae; Chinchilla +Chlamydia trachomatis - 11 0 - 813 BCT cellular organisms; Bacteria; PVC group; Chlamydiae; Chlamydiia; Chlamydiales; Chlamydiaceae; Chlamydia/Chlamydophila group; Chlamydia +Chlamydotis macqueenii Macqueen's bustard 1 2 - 187382 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gruiformes; Otididae; Chlamydotis +Chlorella sorokiniana - 1 1 11 3076 PLN cellular organisms; Eukaryota; Viridiplantae; Chlorophyta; Trebouxiophyceae; Chlorellales; Chlorellaceae; Chlorella +Chloris chloris European greenfinch 1 2 - 37601 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Passeroidea; Fringillidae; Carduelinae; Chloris +Chlorocebus sabaeus green monkey 1 2 - 60711 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Chlorocebus +Chorispora bungeana - 1 1 11 238895 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Chorisporeae; Chorispora +Chromolaena odorata - 1 1 11 103745 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Asteroideae; Heliantheae alliance; Eupatorieae; Chromolaena +Chrysemys picta bellii western painted turtle 1 2 - 8478 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Testudines; Cryptodira; Durocryptodira; Testudinoidea; Emydidae; Chrysemys; Chrysemys picta +Chrysochloris asiatica Cape golden mole 1 2 - 185453 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Chrysochloridae; Chrysochlorinae; Chrysochloris +Chrysopa pallens - 1 5 - 417485 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Neuropterida; Neuroptera; Chrysopidae; Chrysopa +Chyphotes mellipes - 1 5 - 292179 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Bradynobaenidae; Chyphotinae; Chyphotes +Cicer arietinum chickpea 1 1 11 3827 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Cicereae; Cicer +Ciona intestinalis vase tunicate 1 13 - 7719 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Tunicata; Ascidiacea; Enterogona; Phlebobranchia; Cionidae; Ciona +Citrus clementina - 1 1 11 85681 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Sapindales; Rutaceae; Aurantioideae; Citrus +Citrus sinensis sweet orange 1 1 11 2711 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Sapindales; Rutaceae; Aurantioideae; Citrus +Clostridioides difficile - 11 0 - 1496 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Clostridia; Clostridiales; Peptostreptococcaceae; Clostridioides +Clostridium botulinum - 11 0 - 1491 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Clostridia; Clostridiales; Clostridiaceae; Clostridium +Clupea harengus Atlantic herring 1 2 - 7950 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Clupei; Clupeiformes; Clupeoidei; Clupeidae; Clupeinae; Clupea +Cocos nucifera coconut palm 1 1 11 13894 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Arecales; Arecaceae; Arecoideae; Cocoseae; Attaleinae; Cocos +Colaphellus bowringi - 1 5 - 561076 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Chrysomeloidea; Chrysomelidae; Chrysomelinae; Chrysomelini; Colaphellus +Colius striatus speckled mousebird 1 2 - 57412 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Coliiformes; Coliidae; Colius +Colobus angolensis palliatus - 1 2 - 336983 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Colobinae; Colobus; Colobus angolensis +Columba livia rock pigeon 1 2 - 8932 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Columbiformes; Columbidae; Columba +Condylura cristata star-nosed mole 1 2 - 143302 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Insectivora; Talpidae; Condylura +Copidosoma floridanum - 1 5 - 29053 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Chaldicoidea group; Chalcidoidea; Encyrtidae; Encyrtinae; Copidosoma +Corchorus capsularis - 1 1 11 210143 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Malvales; Malvaceae; Grewioideae; Apeibeae; Corchorus +Corvus brachyrhynchos American crow 1 2 - 85066 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Corvoidea; Corvidae; Corvus +Corvus cornix cornix - 1 2 - 932674 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Corvoidea; Corvidae; Corvus; Corvus cornix +Corydalinae sp. KMRSPBM-2012 - 1 5 - 1247484 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Neuropterida; Megaloptera; Corydalidae; Corydalinae; unclassified Corydalinae +Corylus avellana - 1 1 11 13451 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fagales; Betulaceae; Corylus +Costus pictus - 1 1 11 168183 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Zingiberales; Costaceae; Costus +Coturnix japonica Japanese quail 1 2 - 93934 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Galliformes; Phasianidae; Perdicinae; Coturnix +Crassostrea angulata - 1 5 - 558553 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Pteriomorphia; Ostreoida; Ostreoidea; Ostreidae; Crassostrea +Crassostrea gigas Pacific oyster 1 5 - 29159 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Pteriomorphia; Ostreoida; Ostreoidea; Ostreidae; Crassostrea +Crataegus pinnatifida - 1 1 11 510735 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Maleae; Crataegus +Crepidula fornicata - 1 5 - 176853 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Caenogastropoda; Hypsogastropoda; Littorinimorpha; Calyptraeoidea; Calyptraeidae; Crepidula +Cricetulus griseus Chinese hamster 1 2 - 10029 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Cricetidae; Cricetinae; Cricetulus +Crioscolia alcione - 1 5 - 1317732 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Scoliidae; Crioscolia +Ctenomys sociabilis social tuco-tuco 1 2 - 43321 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Ctenomyidae; Ctenomys +Cucumis melo muskmelon 1 1 11 3656 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Cucurbitales; Cucurbitaceae; Benincaseae; Cucumis +Cucumis sativus cucumber 1 1 11 3659 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Cucurbitales; Cucurbitaceae; Benincaseae; Cucumis +Cunninghamia lanceolata - 1 1 11 28977 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Cupressales; Cupressaceae; Cunninghamia +Curcuma longa turmeric 1 1 11 136217 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Zingiberales; Zingiberaceae; Curcuma +Cuscuta pentagona - 1 1 11 112407 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Convolvulaceae; Cuscuteae; Cuscuta; Grammica; Cuscuta sect. Cleistogrammica +Cylicostephanus goldi - 1 5 - 71465 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Strongyloidea; Strongylidae; Cyathostominae; Cylicostephanus +Cynoglossus semilaevis tongue sole 1 2 - 244447 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Carangaria; Pleuronectiformes; Pleuronectoidei; Cynoglossidae; Cynoglossinae; Cynoglossus +Cynopterus sphinx Indian short-nosed fruit bat 1 2 - 9400 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Megachiroptera; Pteropodidae; Pteropodinae; Cynopterus +Cypridininae sp. BMR-2011 - 1 5 - 1032739 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Ostracoda; Myodocopa; Myodocopida; Cypridinoidea; Cypridinidae; unclassified Cypridinidae +Cyprinodon variegatus sheepshead minnow 1 2 - 28743 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Cyprinodontidae; Cyprinodontinae; Cyprinodontini; Cyprinodon +Cyprinus carpio common carp 1 2 - 7962 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Cyprinus +Dahlia pinnata - 1 1 11 101596 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Asteroideae; Heliantheae alliance; Coreopsideae; Dahlia +Danio rerio zebrafish 1 2 - 7955 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Danio +Daphnia magna - 1 5 - 35525 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Branchiopoda; Phyllopoda; Diplostraca; Cladocera; Anomopoda; Daphniidae; Daphnia +Dastarcus helophoroides - 1 5 - 1169899 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Cucujoidea; Bothrideridae; Dastarcus +Dasypus novemcinctus nine-banded armadillo 1 2 - 9361 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Xenarthra; Cingulata; Dasypodidae; Dasypus +Daucus carota subsp. sativus - 1 1 11 79200 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Apiales; Apiineae; Apiaceae; Apioideae; Scandiceae; Daucinae; Daucus; Daucus sect. Daucus; Daucus carota +Dendroctonus ponderosae mountain pine beetle 1 5 - 77166 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Cucujiformia; Curculionoidea; Curculionidae; Scolytinae; Dendroctonus +Dermacentor variabilis American dog tick 1 5 - 34621 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Ixodida; Ixodoidea; Ixodidae; Rhipicephalinae; Dermacentor +Dermanyssus gallinae - 1 5 - 34641 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Mesostigmata; Monogynaspida; Gamasina; Dermanyssoidea; Dermanyssidae; Dermanyssus +Dianthus caryophyllus clove pink 1 1 11 3570 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Caryophyllaceae; Caryophylleae; Dianthus +Diaphorina citri Asian citrus psyllid 1 5 - 121845 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Sternorrhyncha; Psylliformes; Psylloidea; Psyllidae; Diaphorina +Dicrocoelium dendriticum - 1 9 - 57078 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Plagiorchiida; Xiphidiata; Plagiorchioidea; Dicrocoeliidae; Dicrocoelium +Dinobryon sp. LO226KS - 1 1 11 1825119 PLN cellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; Chromulinales; Dinobryaceae; Dinobryon +Dinoponera quadriceps - 1 5 - 609295 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Ponerinae; Ponerini; Dinoponera +Diospyros lotus - 1 1 11 55363 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Ericales; Ebenaceae; Diospyros +Diphyllobothrium latum - 1 9 - 60516 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Cestoda; Eucestoda; Diphyllobothriidea; Diphyllobothriidae; Diphyllobothrium +Dipodomys ordii Ord's kangaroo rat 1 2 - 10020 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Heteromyidae; Dipodomyinae; Dipodomys +Dorcoceras hygrometricum - 1 1 11 472368 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Gesneriaceae; Didymocarpoideae; Trichosporeae; Loxocarpinae; Dorcoceras +Drosophila ananassae - 1 5 - 7217 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; ananassae subgroup; ananassae species complex +Drosophila grimshawi - 1 5 - 7222 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Hawaiian Drosophila; picture wing clade; grimshawi clade; grimshawi group; grimshawi subgroup +Drosophila melanogaster fruit fly 1 5 - 7227 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; melanogaster subgroup +Drosophila miranda - 1 5 - 7229 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; obscura group; pseudoobscura subgroup +Drosophila mojavensis - 1 5 - 7230 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Drosophila; repleta group; mulleri subgroup; mojavensis species complex +Drosophila persimilis - 1 5 - 7234 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; obscura group; pseudoobscura subgroup +Drosophila pseudoobscura pseudoobscura - 1 5 - 46245 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; obscura group; pseudoobscura subgroup; Drosophila pseudoobscura +Drosophila rhopaloa - 1 5 - 1041015 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; rhopaloa subgroup +Drosophila sechellia - 1 5 - 7238 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; melanogaster subgroup +Drosophila simulans - 1 5 - 7240 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; melanogaster subgroup +Drosophila suzukii - 1 5 - 28584 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; suzukii subgroup +Drosophila virilis - 1 5 - 7244 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Drosophila; virilis group +Drosophila willistoni - 1 5 - 7260 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; willistoni group; willistoni subgroup +Drosophila yakuba - 1 5 - 7245 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Ephydroidea; Drosophilidae; Drosophilinae; Drosophilini; Drosophila; Sophophora; melanogaster group; melanogaster subgroup +Dugesia japonica - 1 9 - 6161 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Rhabditophora; Seriata; Tricladida; Continenticola; Geoplanoidea; Dugesiidae; Dugesia +Echinarachnius parma - 1 9 - 869203 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Euechinoidea; Gnathostomata; Clypeasteroida; Echinarachniidae; Echinarachnius +Echinaster spinulosus - 1 9 - 1451296 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Spinulosacea; Spinulosida; Echinasteridae; Echinaster +Echinops telfairi small Madagascar hedgehog 1 2 - 9371 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Tenrecidae; Tenrecinae; Echinops +Echinostoma caproni - 1 9 - 27848 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Plagiorchiida; Echinostomata; Echinostomatoidea; Echinostomatidae; Echinostoma +Eidolon helvum straw-colored fruit bat 1 2 - 77214 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Megachiroptera; Pteropodidae; Pteropodinae; Eidolon +Eimeria mitis - 1 4 4 44415 INV cellular organisms; Eukaryota; Alveolata; Apicomplexa; Conoidasida; Coccidia; Eucoccidiorida; Eimeriorina; Eimeriidae; Eimeria +Elaeis guineensis African oil palm 1 1 11 51953 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Arecales; Arecaceae; Arecoideae; Cocoseae; Elaeidinae; Elaeis +Elephantulus edwardii Cape elephant shrew 1 2 - 28737 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Macroscelidea; Macroscelididae; Elephantulus +Elliptio complanata eastern elliptio 1 5 - 55832 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Palaeoheterodonta; Unionoida; Unionoidea; Unionidae; Ambleminae; Elliptio +Elodea nuttallii - 1 1 11 55313 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Alismatales; Hydrocharitaceae; Elodea +Emiliania huxleyi CCMP1516 - 1 4 11 280463 PLN cellular organisms; Eukaryota; Haptophyceae; Isochrysidales; Noelaerhabdaceae; Emiliania; Emiliania huxleyi +Enterobacter cloacae - 11 0 - 550 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Enterobacter; Enterobacter cloacae complex +Enterococcus faecalis - 11 0 - 1351 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Enterococcaceae; Enterococcus +Enterococcus faecium - 11 0 - 1352 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Enterococcaceae; Enterococcus +Epipyxis sp. PR26KG - 1 1 11 1825121 PLN cellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; Chromulinales; Dinobryaceae; Epipyxis +Eptesicus fuscus big brown bat 1 2 - 29078 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Vespertilionidae; Eptesicus +Equus asinus ass 1 2 - 9793 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Perissodactyla; Equidae; Equus; Asinus +Equus caballus horse 1 2 - 9796 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Perissodactyla; Equidae; Equus; Equus +Equus przewalskii Przewalski's horse 1 2 - 9798 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Perissodactyla; Equidae; Equus; Equus +Erinaceus europaeus western European hedgehog 1 2 - 9365 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Insectivora; Erinaceidae; Erinaceinae; Erinaceus +Eriocheir sinensis Chinese mitten crab 1 5 - 95602 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Brachyura; Eubrachyura; Thoracotremata; Grapsoidea; Varunidae; Eriocheir +Erythranthe guttata spotted monkey flower 1 1 11 4155 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Phrymaceae; Erythranthe +Escherichia coli - 11 0 - 562 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Escherichia +Esox lucius northern pike 1 2 - 8010 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Protacanthopterygii; Esociformes; Esocidae; Esox +Eucalyptus camaldulensis Murray red gum 1 1 11 34316 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Myrtales; Myrtaceae; Myrtoideae; Eucalypteae; Eucalyptus +Eucalyptus grandis - 1 1 11 71139 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Myrtales; Myrtaceae; Myrtoideae; Eucalypteae; Eucalyptus +Eucidaris tribuloides - 1 9 - 7632 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Perischoechinoidea; Cidaroida; Cidaridae; Eucidaris +Eucyclops serrulatus - 1 5 - 84317 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Podoplea; Cyclopoida; Cyclopidae; Eucyclops +Eufriesea mexicana - 1 5 - 516756 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Bombinae; Euglossini; Eufriesea +Eurypyga helias sunbittern 1 2 - 54383 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gruiformes; Eurypygidae; Eurypyga +Eustoma exaltatum subsp. russellianum - 1 1 11 52518 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Gentianaceae; Chironieae; Eustoma; Eustoma exaltatum +Evechinus chloroticus - 1 9 - 137513 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Euechinoidea; Echinacea; Echinoida; Echinometridae; Evechinus +Exaiptasia pallida - 1 4 - 1720309 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Actiniaria; Aiptasiidae; Exaiptasia +Exoneura robusta - 1 5 - 175328 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Xylocopinae; Allodapini; Exoneura +Extatosoma tiaratum giant prickly stick insect 1 5 - 7024 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Phasmatodea; Verophasmatodea; Anareolatae; Phasmatidae; Tropidoderinae; Extatosoma +Fagopyrum esculentum common buckwheat 1 1 11 3617 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Polygonaceae; Polygonoideae; Fagopyreae; Fagopyrum +Falco cherrug Saker falcon 1 2 - 345164 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Falconiformes; Falconidae; Falco +Falco peregrinus peregrine falcon 1 2 - 8954 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Falconiformes; Falconidae; Falco +Fasciola hepatica liver fluke 1 9 - 6192 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Plagiorchiida; Echinostomata; Echinostomatoidea; Fasciolidae; Fasciola +Felis catus domestic cat 1 2 - 9685 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Feliformia; Felidae; Felinae; Felis +Ficedula albicollis collared flycatcher 1 2 - 59894 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Muscicapidae; Ficedula +Ficus carica common fig 1 1 11 3494 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Moraceae; Ficus +fish metagenome - 11 2 11 496924 ENV unclassified sequences; metagenomes; organismal metagenomes +Folsomia candida - 1 5 - 158441 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Collembola; Collembola; Entomobryomorpha; Isotomoidea; Isotomidae; Proisotominae; Folsomia +Fopius arisanus - 1 5 - 64838 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Ichneumonoidea; Braconidae; Opiinae; Fopius +Formica aquilonia - 1 5 - 258703 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica +Formica cinerea - 1 5 - 609761 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica +Formica exsecta - 1 5 - 72781 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica +Formica fusca - 1 5 - 72779 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica +Formica pratensis - 1 5 - 221681 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica +Formica pressilabris - 1 5 - 609858 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica +Formica truncorum - 1 5 - 72783 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Formicini; Formica +Fragaria vesca subsp. vesca - 1 1 11 101020 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Rosoideae; Potentilleae; Fragariinae; Fragaria; Fragaria vesca +Fragaria x ananassa strawberry 1 1 11 3747 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Rosoideae; Potentilleae; Fragariinae; Fragaria +Frankliniella occidentalis western flower thrips 1 5 - 133901 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Thysanoptera; Terebrantia; Thripoidea; Thripidae; Thripinae; Frankliniella +Fraxinus excelsior European ash 1 1 11 38873 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Oleaceae; Oleeae; Fraxinus +Fukomys damarensis Damara mole-rat 1 2 - 885580 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Bathyergidae; Fukomys +Fulmarus glacialis northern fulmar 1 2 - 30455 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Procellariiformes; Procellariidae; Procellariinae; Fulmarus +Fundulus grandis Gulf killifish 1 2 - 34779 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Fundulidae; Fundulus +Fundulus heteroclitus mummichog 1 2 - 8078 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Fundulidae; Fundulus +Gadus morhua Atlantic cod 1 2 - 8049 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Paracanthomorphacea; Zeiogadaria; Gadariae; Gadiformes; Gadoidei; Gadidae; Gadus +Galeopterus variegatus Sunda flying lemur 1 2 - 482537 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Dermoptera; Cynocephalidae; Galeopterus +Gallus gallus chicken 1 2 - 9031 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Galliformes; Phasianidae; Phasianinae; Gallus +Gammarus chevreuxi - 1 5 - 732109 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Amphipoda; Senticaudata; Gammarida; Gammaridira; Gammaroidea; Gammaridae; Gammarus +Gardenia jasminoides - 1 1 11 114476 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Rubiaceae; Ixoroideae; Gardenieae; Gardenia +Gavia stellata red-throated loon 1 2 - 37040 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gaviiformes; Gaviidae; Gavia +Gavialis gangeticus Gharial 1 2 - 94835 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Crocodylia; Longirostres; Gavialidae; Gavialinae; Gavialis +Gekko japonicus - 1 2 - 146911 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Gekkota; Gekkonidae; Gekkoninae; Gekko +Geminigera cryophila - 1 1 11 46947 PLN cellular organisms; Eukaryota; Cryptophyta; Pyrenomonadales; Geminigeraceae; Geminigera +Gene trapping vector VICTR76 - 11 0 11 447635 SYN other sequences; artificial sequences; vectors +Gentiana macrophylla - 1 1 11 50765 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Gentianaceae; Gentianeae; Gentiana +Geospiza fortis medium ground-finch 1 2 - 48883 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Thraupidae; Geospiza +Gerbera hybrid cultivar - 1 1 11 18101 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Mutisioideae; Mutisieae; Gerbera +Gigaspora margarita - 1 4 - 4874 PLN cellular organisms; Eukaryota; Opisthokonta; Fungi; Mucoromycota; Glomeromycotina; Glomeromycetes; Diversisporales; Gigasporaceae; Gigaspora +Glomeris pustulata - 1 5 - 1288506 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Myriapoda; Diplopoda; Pentazonia; Glomerida; Glomeridae; Glomeris +Glossoscolex paulistus - 1 5 - 1046353 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Annelida; Clitellata; Oligochaeta; Haplotaxida; Lumbricina; Glossoscolecidae; Glossoscolex +Glycera dibranchiata - 1 5 - 6350 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Annelida; Polychaeta; Palpata; Aciculata; Phyllodocida; Glyceridae; Glycera +Glycine max soybean 1 1 11 3847 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Glycine; Soja +Gongylonema pulchrum - 1 5 - 637853 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Spirurida; Spiruroidea; Gongylonematidae; Gongylonema +Gorilla gorilla gorilla western lowland gorilla 1 2 - 9595 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Gorilla; Gorilla gorilla +Gossypium arboreum - 1 1 11 29729 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Malvales; Malvaceae; Malvoideae; Gossypium +Gossypium hirsutum - 1 1 11 3635 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Malvales; Malvaceae; Malvoideae; Gossypium +Gossypium raimondii - 1 1 11 29730 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Malvales; Malvaceae; Malvoideae; Gossypium +Graminella nigrifrons - 1 5 - 30127 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Clypeorrhyncha; Membracoidea; Cicadellidae; Deltocephalinae; Graminella +gut metagenome - 11 2 11 749906 ENV unclassified sequences; metagenomes; organismal metagenomes +Habropoda laboriosa - 1 5 - 597456 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Apidae; Anthophorinae; Anthophorini; Habropoda +Haliaeetus albicilla white-tailed eagle 1 2 - 8969 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Falconiformes; Accipitridae; Accipitrinae; Haliaeetus +Halyomorpha halys brown marmorated stink bug 1 5 - 286706 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Neohemiptera; Prosorrhyncha; Heteroptera; Euheteroptera; Neoheteroptera; Panheteroptera; Pentatomomorpha; Pentatomoidea; Pentatomidae; Pentatominae; Halyomorpha +Hammondia hammondi - 1 4 4 99158 INV cellular organisms; Eukaryota; Alveolata; Apicomplexa; Conoidasida; Coccidia; Eucoccidiorida; Eimeriorina; Sarcocystidae; Hammondia +Haplochromis burtoni Burton's mouthbrooder 1 2 - 8153 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Haplochromini; Haplochromis +Harpegnathos saltator Jerdon's jumping ant 1 5 - 610380 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Ponerinae; Ponerini; Harpegnathos +Helicobacter pylori - 11 0 - 210 BCT cellular organisms; Bacteria; Proteobacteria; delta/epsilon subdivisions; Epsilonproteobacteria; Campylobacterales; Helicobacteraceae; Helicobacter +Helicoverpa assulta - 1 5 - 52344 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Heliothinae; Helicoverpa +Heligmosomoides polygyrus - 1 5 - 6339 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Trichostrongyloidea; Heligmosomatidae; Heligmosomoides +Henricia sp. AR-2014 - 1 9 - 1462731 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Spinulosacea; Spinulosida; Echinasteridae; Henricia +Hepatitis B virus - 1 0 - 10407 VRL Viruses; Retro-transcribing viruses; Hepadnaviridae; Orthohepadnavirus +Hepatitis C virus - 1 0 - 11103 VRL Viruses; ssRNA viruses; ssRNA positive-strand viruses, no DNA stage; Flaviviridae; Hepacivirus +Heterocephalus glaber naked mole-rat 1 2 - 10181 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Bathyergidae; Heterocephalus +Heterodera glycines soybean cyst nematode 1 5 - 51029 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Tylenchida; Tylenchina; Tylenchoidea; Heteroderidae; Heteroderinae; Heterodera +Hevea brasiliensis - 1 1 11 3981 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Euphorbiaceae; Crotonoideae; Micrandreae; Hevea +Homalodisca liturata - 1 5 - 320908 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Clypeorrhyncha; Membracoidea; Cicadellidae; Cicadellinae; unclassified Cicadellinae; Homalodisca +Homalodisca vitripennis glassy-winged sharpshooter 1 5 - 197043 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Clypeorrhyncha; Membracoidea; Cicadellidae; Cicadellinae; unclassified Cicadellinae; Homalodisca +Homo sapiens human 1 2 - 9606 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Homo +Hordeum pubiflorum - 1 1 11 112521 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Hordeinae; Hordeum +Hordeum vulgare - 1 1 11 4513 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Hordeinae; Hordeum +Hordeum vulgare subsp. vulgare domesticated barley 1 1 11 112509 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Hordeinae; Hordeum; Hordeum vulgare +human gut metagenome - 11 2 11 408170 ENV unclassified sequences; metagenomes; organismal metagenomes +Human immunodeficiency virus 1 - 1 0 - 11676 VRL Viruses; Retro-transcribing viruses; Retroviridae; Orthoretrovirinae; Lentivirus; Primate lentivirus group +Humulus lupulus European hop 1 1 11 3486 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Cannabaceae; Humulus +Humulus lupulus var. cordifolius - 1 1 11 278022 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Cannabaceae; Humulus; Humulus lupulus +Humulus lupulus var. lupulus - 1 1 11 1571165 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Cannabaceae; Humulus; Humulus lupulus +Hyalella azteca - 1 5 - 294128 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Amphipoda; Senticaudata; Talitrida; Talitroidea; Hyalellidae; Hyalella +Hyas araneus - 1 5 - 361634 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Brachyura; Eubrachyura; Heterotremata; Majoidea; Majidae; Hyas +Hydra vulgaris - 1 4 - 6087 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Hydrozoa; Hydroidolina; Anthoathecata; Aplanulata; Hydridae; Hydra +Hydractinia symbiolongicarpus - 1 4 - 13093 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Hydrozoa; Hydroidolina; Anthoathecata; Filifera; Hydractiniidae; Hydractinia +Hynobius chinensis Chinese salamander 1 2 - 288313 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Caudata; Cryptobranchoidea; Hynobiidae; Hynobius; Hynobius +Hynobius retardatus Hokkaido salamander 1 2 - 36312 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Caudata; Cryptobranchoidea; Hynobiidae; Hynobius; Satobius +Hypsizygus marmoreus - 1 4 - 39966 PLN cellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Basidiomycota; Agaricomycotina; Agaricomycetes; Agaricomycetidae; Agaricales; Lyophyllaceae; Hypsizygus +Ictalurus punctatus channel catfish 1 2 - 7998 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Characiphysae; Siluriformes; Siluroidei; Ictaluridae; Ictalurus +Ictidomys tridecemlineatus thirteen-lined ground squirrel 1 2 - 43179 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Sciuridae; Xerinae; Marmotini; Ictidomys +Ipomoea batatas sweet potato 1 1 11 4120 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Convolvulaceae; Ipomoeeae; Ipomoea +Ipomoea nil Japanese morning glory 1 1 11 35883 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Convolvulaceae; Ipomoeeae; Ipomoea +Ipomoea purpurea common morning-glory 1 1 11 4121 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Convolvulaceae; Ipomoeeae; Ipomoea +Ipomoea trifida - 1 1 11 35884 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Convolvulaceae; Ipomoeeae; Ipomoea +Ixodes ricinus castor bean tick 1 5 - 34613 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Ixodida; Ixodoidea; Ixodidae; Ixodinae; Ixodes +Ixodes scapularis black-legged tick 1 5 - 6945 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Ixodida; Ixodoidea; Ixodidae; Ixodinae; Ixodes +Jaculus jaculus lesser Egyptian jerboa 1 2 - 51337 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Dipodidae; Dipodinae; Jaculus +Jatropha curcas - 1 1 11 180498 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Euphorbiaceae; Crotonoideae; Jatropheae; Jatropha +Juglans regia English walnut 1 1 11 51240 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fagales; Juglandaceae; Juglans +Karelinia caspia - 1 1 11 313960 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Asteroideae; Inuleae; Plucheinae; Karelinia +Kerria lacca common lac scale 1 5 - 473130 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Sternorrhyncha; Aphidiformes; Coccoidea; Kerriidae; Kerria +Klebsiella pneumoniae - 11 0 - 573 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Klebsiella +Kryptolebias marmoratus mangrove rivulus 1 2 - 37003 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Rivulidae; Kryptolebias +Lactuca sativa - 1 1 11 4236 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Cichorioideae; Cichorieae; Lactucinae; Lactuca +Lactuca serriola - 1 1 11 75943 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Cichorioideae; Cichorieae; Lactucinae; Lactuca +Lagenaria siceraria white-flowered gourd 1 1 11 3668 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Cucurbitales; Cucurbitaceae; Benincaseae; Lagenaria +Landoltia punctata - 1 1 11 50518 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Alismatales; Araceae; Lemnoideae; Landoltia +Larimichthys crocea large yellow croaker 1 2 - 215358 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Eupercaria incertae sedis; Sciaenidae; Larimichthys +Larix kaempferi - 1 1 11 54800 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Larix +Lasius neglectus - 1 5 - 111072 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Lasiini; Lasius; Lasius +Lasius turcicus - 1 5 - 235463 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Lasiini; Lasius; Lasius +Lates calcarifer barramundi perch 1 2 - 8187 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Carangaria; Carangiaria incertae sedis; Centropomidae; Lates +Lathyrus sativus - 1 1 11 3860 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Fabeae; Lathyrus +Latimeria chalumnae coelacanth 1 2 - 7897 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Coelacanthimorpha; Coelacanthiformes; Coelacanthidae; Latimeria +Latimeria menadoensis Menado coelacanth 1 2 - 106881 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Coelacanthimorpha; Coelacanthiformes; Coelacanthidae; Latimeria +Latrodectus hesperus western black widow 1 5 - 256737 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Araneae; Araneomorphae; Entelegynae; Orbiculariae; Araneoidea; Theridiidae; Latrodectus +Legionella pneumophila - 11 0 - 446 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Legionellales; Legionellaceae; Legionella +Lepeophtheirus salmonis salmon louse 1 5 - 72036 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Podoplea; Siphonostomatoida; Caligidae; Lepeophtheirus +Lepidonotothen nudifrons yellowfin notie 1 2 - 83203 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Perciformes; Notothenioidei; Nototheniidae; Lepidonotothen +Lepidothrix coronata blue-crowned manakin 1 2 - 321398 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Pipridae; Lepidothrix +Lepisosteus oculatus spotted gar 1 2 - 7918 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Holostei; Semionotiformes; Lepisosteidae; Lepisosteus +Leptasterias sp. AR-2014 - 1 9 - 1462732 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Leptasterias +Leptonychotes weddellii Weddell seal 1 2 - 9713 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Phocidae; Leptonychotes +Leptosomus discolor cuckoo roller 1 2 - 188344 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Coraciiformes; Leptosomidae; Leptosomus +Leptospira interrogans - 11 0 - 173 BCT cellular organisms; Bacteria; Spirochaetes; Spirochaetia; Leptospirales; Leptospiraceae; Leptospira +Limnephilus lunatus - 1 5 - 1218281 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Trichoptera; Integripalpia; Plenitentoria; Limnephiloidea; Limnephilidae; Limnephilinae; Limnephilini; Limnephilus +Limnoperna fortunei - 1 5 - 356393 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Pteriomorphia; Mytiloida; Mytiloidea; Mytilidae; Mytilinae; Limnoperna +Limulus polyphemus Atlantic horseshoe crab 1 5 - 6850 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Merostomata; Xiphosura; Limulidae; Limulus +Linepithema humile Argentine ant 1 5 - 83485 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Dolichoderinae; Linepithema +Lingula anatina - 1 5 - 7574 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Brachiopoda; Linguliformea; Lingulata; Lingulida; Linguloidea; Lingulidae; Lingula +Lingulodinium polyedrum - 1 4 11 160621 PLN cellular organisms; Eukaryota; Alveolata; Dinophyceae; Gonyaulacales; Lingulodinium +Lipotes vexillifer Yangtze River dolphin 1 2 - 118797 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Cetacea; Odontoceti; Lipotidae; Lipotes +Listeria monocytogenes - 11 0 - 1639 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Bacillales; Listeriaceae; Listeria +Litchi chinensis - 1 1 11 151069 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Sapindales; Sapindaceae; Litchi +Litopenaeus vannamei Pacific white shrimp 1 5 - 6689 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Dendrobranchiata; Penaeoidea; Penaeidae; Litopenaeus +Loa loa eye worm 1 5 - 7209 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Spirurida; Filarioidea; Onchocercidae; Loa +Lolium perenne - 1 1 11 4522 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Poodae; Poeae; Poeae Chloroplast Group 2 (Poeae type); Loliinae; Lolium +Lotus corniculatus - 1 1 11 47247 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Loteae; Lotus +Loxodonta africana African savanna elephant 1 2 - 9785 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Proboscidea; Elephantidae; Loxodonta +Luidia clathrata - 1 9 - 133437 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Valvatacea; Paxillosida; Luidiidae; Luidia +Lupinus angustifolius narrow-leaved blue lupine 1 1 11 3871 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Genisteae; Lupinus +Lygodium japonicum - 1 1 11 13824 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Moniliformopses; Polypodiidae; Schizaeales; Lygodiaceae; Lygodium +Lygus hesperus lygus bug 1 5 - 30085 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Neohemiptera; Prosorrhyncha; Heteroptera; Euheteroptera; Neoheteroptera; Panheteroptera; Cimicomorpha; Cimicoidea; Miridae; Mirinae; Mirini; Lygus +Lymnaea stagnalis great pond snail 1 5 - 6523 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Heterobranchia; Euthyneura; Panpulmonata; Hygrophila; Lymnaeoidea; Lymnaeidae; Lymnaea +Lynx pardinus Spanish lynx 1 2 - 191816 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Feliformia; Felidae; Felinae; Lynx +Lytechinus variegatus green sea urchin 1 9 - 7654 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Euechinoidea; Echinacea; Temnopleuroida; Toxopneustidae; Lytechinus +Macaca fascicularis crab-eating macaque 1 2 - 9541 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Macaca +Macaca mulatta Rhesus monkey 1 2 - 9544 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Macaca +Macaca nemestrina pig-tailed macaque 1 2 - 9545 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Macaca +Macropus eugenii tammar wallaby 1 2 - 9315 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Metatheria; Diprotodontia; Macropodidae; Macropus +Malus domestica apple 1 1 11 3750 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Maleae; Malus +Manacus vitellinus golden-collared manakin 1 2 - 328815 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Pipridae; Manacus +Mandrillus leucophaeus drill 1 2 - 9568 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Mandrillus +Mangifera indica mango 1 1 11 29780 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Sapindales; Anacardiaceae; Mangifera +Manihot esculenta cassava 1 1 11 3983 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Euphorbiaceae; Crotonoideae; Manihoteae; Manihot +Manis javanica Malayan pangolin 1 2 - 9974 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Pholidota; Manidae; Manis +marine metagenome - 11 2 11 408172 ENV unclassified sequences; metagenomes; ecological metagenomes +marine sediment metagenome - 11 2 11 412755 ENV unclassified sequences; metagenomes; ecological metagenomes +Marmota marmota marmota Alpine marmot 1 2 - 9994 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Sciuridae; Xerinae; Marmotini; Marmota; Marmota marmota +Marthasterias glacialis spiny starfish 1 9 - 7609 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Marthasterias +Maylandia zebra zebra mbuna 1 2 - 106582 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Haplochromini; Maylandia; Maylandia zebra complex +Medauroidea extradentata - 1 5 - 614211 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Phasmatodea; Verophasmatodea; Anareolatae; Phasmatidae; Phasmatinae; Clitumnini; Medauroidea +Medicago sativa - 1 1 11 3879 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Trifolieae; Medicago +Medicago truncatula barrel medic 1 1 11 3880 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Trifolieae; Medicago +Megachile rotundata alfalfa leafcutting bee 1 5 - 143995 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Megachilidae; Megachilinae; Megachilini; Megachile +Megaderma lyra Indian false vampire 1 2 - 9413 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Megadermatidae; Megaderma +Megajapyx sp. UVienna-2012 - 1 5 - 1136246 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Diplura; Diplura; Dicellurata; Japygoidea; Japygidae; Japyginae; Megajapyx +Megaselia scalaris - 1 5 - 36166 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Aschiza; Platypezoidea; Phoridae; Metopininae; Megaseliini; Megaselia +Meleagris gallopavo turkey 1 2 - 9103 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Galliformes; Phasianidae; Meleagridinae; Meleagris +Melopsittacus undulatus budgerigar 1 2 - 13146 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Psittaciformes; Psittaculidae; Melopsittacus +Mengenilla moldrzyki - 1 5 - 1155016 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Strepsiptera; Mengenillidia; Mengenilloidea; Mengenillidae; Mengenilla +Meretrix meretrix Asiatic hard clam 1 5 - 291251 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Heteroconchia; Euheterodonta; Veneroida; Veneroidea; Veneridae; Meretrix +Merops nubicus carmine bee-eater 1 2 - 57421 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Coraciiformes; Meropidae; Merops +Mesembryanthemum crystallinum common iceplant 1 1 11 3544 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Aizoaceae; Mesembryanthemum; Cryophytum +Mesitornis unicolor brown roatelo 1 2 - 54374 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Gruiformes; Mesitornithidae; Mesitornis +Mesocricetus auratus golden hamster 1 2 - 10036 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Cricetidae; Cricetinae; Mesocricetus +Metaseiulus occidentalis western predatory mite 1 5 - 34638 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Mesostigmata; Monogynaspida; Gamasina; Phytoseioidea; Phytoseiidae; Typhlodrominae; Metaseiulus +Microcebus murinus gray mouse lemur 1 2 - 30608 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Strepsirrhini; Lemuriformes; Cheirogaleidae; Microcebus +Microplitis demolitor - 1 5 - 69319 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Ichneumonoidea; Braconidae; Microgastrinae; Microplitis +Micropterix calthella - 1 5 - 41027 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Zeugloptera; Micropterigidae; Micropterix +Micropterus floridanus Florida bass 1 2 - 225391 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Centrarchiformes; Centrarchoidei; Centrarchidae; Micropterus +Micropterus salmoides largemouth bass 1 2 - 27706 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Centrarchiformes; Centrarchoidei; Centrarchidae; Micropterus +Micropterus salmoides salmoides northern largemouth bass 1 2 - 489037 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Centrarchiformes; Centrarchoidei; Centrarchidae; Micropterus; Micropterus salmoides +Microtus ochrogaster prairie vole 1 2 - 79684 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Cricetidae; Arvicolinae; Microtus +Miichthys miiuy Mi-iuy croaker 1 2 - 240162 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Eupercaria incertae sedis; Sciaenidae; Miichthys +mine drainage metagenome - 11 2 11 410659 ENV unclassified sequences; metagenomes; ecological metagenomes +Mischocyttarus flavitarsis - 1 5 - 231975 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Vespidae; Polistinae; Mischocyttarini; Mischocyttarus +Momordica charantia - 1 1 11 3673 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Cucurbitales; Cucurbitaceae; Momordiceae; Momordica +Moniezia expansa sheep tapeworm 1 9 - 28841 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Cestoda; Eucestoda; Cyclophyllidea; Anoplocephalidae; Moniezia +Monodelphis domestica gray short-tailed opossum 1 2 - 13616 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Metatheria; Didelphimorphia; Didelphidae; Didelphinae; Monodelphis +Monomorium chinense - 1 5 - 482359 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Solenopsidini; Monomorium +Monomorium pharaonis pharaoh ant 1 5 - 307658 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Solenopsidini; Monomorium +Morone chrysops white bass 1 2 - 46259 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Eupercaria incertae sedis; Moronidae; Morone +Morone saxatilis striped sea-bass 1 2 - 34816 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Eupercaria incertae sedis; Moronidae; Morone +Morus notabilis - 1 1 11 981085 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Moraceae; Morus +Mus musculus house mouse 1 2 - 10090 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Muridae; Murinae; Mus; Mus +Musa ABB Group - 1 1 11 214693 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Zingiberales; Musaceae; Musa; Musa x paradisiaca +Musa acuminata AAA Group dessert banana 1 1 11 214697 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Zingiberales; Musaceae; Musa; Musa acuminata +Musa acuminata subsp. malaccensis wild Malaysian banana 1 1 11 214687 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Zingiberales; Musaceae; Musa; Musa acuminata +Musca domestica house fly 1 5 - 7370 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Calyptratae; Muscoidea; Muscidae; Muscinae; Muscini; Musca; Musca +Mustela putorius furo domestic ferret 1 2 - 9669 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Mustelidae; Mustelinae; Mustela; Mustela putorius +Mycobacterium abscessus - 11 0 - 36809 BCT cellular organisms; Bacteria; Terrabacteria group; Actinobacteria; Actinobacteria; Corynebacteriales; Mycobacteriaceae; Mycobacterium; Mycobacterium chelonae group; Mycobacterium abscessus subgroup +Mycobacterium tuberculosis - 11 0 - 1773 BCT cellular organisms; Bacteria; Terrabacteria group; Actinobacteria; Actinobacteria; Corynebacteriales; Mycobacteriaceae; Mycobacterium; Mycobacterium tuberculosis complex +Myotis brandtii Brandt's bat 1 2 - 109478 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Vespertilionidae; Myotis +Myotis davidii - 1 2 - 225400 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Vespertilionidae; Myotis +Myotis lucifugus little brown bat 1 2 - 59463 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Vespertilionidae; Myotis +Myotis ricketti Rickett's big-footed Myotis 1 2 - 203696 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Vespertilionidae; Myotis +Myrionecta rubra - 1 4 11 283649 INV cellular organisms; Eukaryota; Alveolata; Ciliophora; Intramacronucleata; Litostomatea; Haptoria; Cyclotrichida; Mesodiniidae; Myrionecta +Myrmica rubra - 1 5 - 106198 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Myrmicini; Myrmica +Myrmica ruginodis - 1 5 - 34708 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Myrmicini; Myrmica +Myrmica sulcinodis - 1 5 - 229918 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Myrmicini; Myrmica +Mytilus galloprovincialis Mediterranean mussel 1 5 - 29158 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Pteriomorphia; Mytiloida; Mytiloidea; Mytilidae; Mytilinae; Mytilus +Nannochorista philpotti - 1 5 - 1260225 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Mecoptera; Nannochoristidae; Nannochorista +Nannospalax galili Upper Galilee mountains blind mole rat 1 2 - 1026970 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Spalacidae; Spalacinae; Nannospalax +Nanorana parkeri - 1 2 - 125878 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Neobatrachia; Ranoidea; Dicroglossidae; Dicroglossinae; Nanorana +Nasonia vitripennis jewel wasp 1 5 - 7425 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Chaldicoidea group; Chalcidoidea; Pteromalidae; Pteromalinae; Nasonia +Necator americanus - 1 5 - 51031 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Ancylostomatoidea; Ancylostomatidae; Bunostominae; Necator +Neisseria gonorrhoeae - 11 0 - 485 BCT cellular organisms; Bacteria; Proteobacteria; Betaproteobacteria; Neisseriales; Neisseriaceae; Neisseria +Neisseria meningitidis - 11 0 - 487 BCT cellular organisms; Bacteria; Proteobacteria; Betaproteobacteria; Neisseriales; Neisseriaceae; Neisseria +Nelumbo nucifera sacred lotus 1 1 11 4432 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; stem eudicotyledons; Proteales; Nelumbonaceae; Nelumbo +Nematostella vectensis starlet sea anemone 1 4 - 45351 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Actiniaria; Edwardsiidae; Nematostella +Neolamarckia cadamba - 1 1 11 153762 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Rubiaceae; Cinchonoideae; Naucleeae; Neolamarckia +Neolamprologus brichardi - 1 2 - 32507 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Lamprologini; Neolamprologus +Nestor notabilis Kea 1 2 - 176057 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Psittaciformes; Psittacidae; Nestor +Nicotiana attenuata - 1 1 11 49451 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Nicotianoideae; Nicotianeae; Nicotiana +Nicotiana benthamiana - 1 1 11 4100 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Nicotianoideae; Nicotianeae; Nicotiana +Nicotiana sylvestris wood tobacco 1 1 11 4096 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Nicotianoideae; Nicotianeae; Nicotiana +Nicotiana tabacum common tobacco 1 1 11 4097 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Nicotianoideae; Nicotianeae; Nicotiana +Nicotiana tomentosiformis - 1 1 11 4098 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Nicotianoideae; Nicotianeae; Nicotiana +Nicrophorus vespilloides - 1 5 - 110193 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Staphyliniformia; Staphylinoidea; Silphidae; Nicrophorinae; Nicrophorus +Nilaparvata lugens brown planthopper 1 5 - 108931 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Euhemiptera; Neohemiptera; Archaeorrhyncha; Fulgoroidea; Delphacidae; Delphacinae; Nilaparvata +Nipponia nippon crested ibis 1 2 - 128390 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Pelecaniformes; Threskiornithidae; Nipponia +Nitella hyalina - 1 1 11 181804 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Charophyceae; Charales; Characeae; Nitella +Nitella mirabilis - 1 1 11 231897 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Charophyceae; Charales; Characeae; Nitella +Noccaea caerulescens - 1 1 11 107243 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Coluteocarpeae; Noccaea +Nomascus leucogenys northern white-cheeked gibbon 1 2 - 61853 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hylobatidae; Nomascus +Nothobranchius furzeri turquoise killifish 1 2 - 105023 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius +Nothobranchius kadleci - 1 2 - 1051664 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius +Nothobranchius korthausae - 1 2 - 1143690 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius +Nothobranchius kuhntae Beira killifish 1 2 - 321403 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius +Nothobranchius pienaari - 1 2 - 704102 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius +Nothobranchius rachovii bluefin notho 1 2 - 451742 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Aplocheiloidei; Nothobranchiidae; Nothobranchius +Notholithocarpus densiflorus - 1 1 11 165545 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fagales; Fagaceae; Notholithocarpus +Notothenia coriiceps black rockcod 1 2 - 8208 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Perciformes; Notothenioidei; Nototheniidae; Notothenia +Numida meleagris helmeted guineafowl 1 2 - 8996 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Galloanserae; Galliformes; Numididae; Numida +Nylanderia pubens - 1 5 - 613973 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Formicinae; Lasiini; Nylanderia +Ochotona princeps American pika 1 2 - 9978 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Lagomorpha; Ochotonidae; Ochotona +Ochromonas sp. LO244K-D - 1 1 11 1825117 PLN cellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; Chromulinales; Chromulinaceae; Ochromonas +Octodon degus degu 1 2 - 10160 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Hystricognathi; Octodontidae; Octodon +Octopus bimaculoides - 1 5 - 37653 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Cephalopoda; Coleoidea; Neocoleoidea; Octopodiformes; Octopoda; Incirrata; Octopodidae; Octopus +Odobenus rosmarus divergens Pacific walrus 1 2 - 9708 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Odobenidae; Odobenus; Odobenus rosmarus +Oenococcus oeni - 11 0 - 1247 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Leuconostocaceae; Oenococcus +Oesophagostomum dentatum - 1 5 - 61180 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Strongyloidea; Cloacinidae; Oesophagostomum +Olavius algarvensis - 1 5 - 188229 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Annelida; Clitellata; Oligochaeta; Haplotaxida; Tubificina; Tubificidae; Phallodrilinae; Olavius +Olea europaea common olive 1 1 11 4146 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Oleaceae; Oleeae; Olea +Onchocerca flexuosa - 1 5 - 387005 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Spirurida; Filarioidea; Onchocercidae; Onchocerca +Oncidium hybrid cultivar - 1 1 11 141207 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Orchidaceae; Epidendroideae; Cymbidieae; Oncidiinae; Oncidium +Oncorhynchus masou masou cherry salmon 1 2 - 90313 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Protacanthopterygii; Salmoniformes; Salmonidae; Salmoninae; Oncorhynchus; Oncorhynchus masou +Oncorhynchus mykiss rainbow trout 1 2 - 8022 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Protacanthopterygii; Salmoniformes; Salmonidae; Salmoninae; Oncorhynchus +Onthophagus nigriventris - 1 5 - 476074 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Polyphaga; Scarabaeiformia; Scarabaeoidea; Scarabaeidae; Scarabaeinae; Scarabaeinae incertae sedis; Onthophagus +Ophiocoma echinata - 1 9 - 331088 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Ophiuroidea; Ophiuridea; Ophiurida; Ophiurina; Gnathophiurina; Ophiocomidae; Ophiocominae; Ophiocoma +Ophthalmotilapia ventralis - 1 2 - 27755 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Ectodini; Ophthalmotilapia +Opisthorchis viverrini - 1 9 - 6198 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Opisthorchiida; Opisthorchiata; Opisthorchiidae; Opisthorchis +Orchesella cincta - 1 5 - 48709 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Collembola; Collembola; Entomobryomorpha; Entomobryoidea; Entomobryidae; Orchesellinae; Orchesella +Oreochromis niloticus Nile tilapia 1 2 - 8128 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Oreochromini; Oreochromis +Ornithorhynchus anatinus platypus 1 2 - 9258 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Prototheria; Monotremata; Ornithorhynchidae; Ornithorhynchus +Oropsylla silantiewi - 1 5 - 1461318 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Siphonaptera; Ceratophyllomorpha; Ceratophylloidea; Ceratophyllidae; Oropsylla +Orycteropus afer afer - 1 2 - 1230840 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Tubulidentata; Orycteropodidae; Orycteropus; Orycteropus afer +Oryctolagus cuniculus rabbit 1 2 - 9986 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Lagomorpha; Leporidae; Oryctolagus +Oryza brachyantha malo sina 1 1 11 4533 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Oryzoideae; Oryzeae; Oryzinae; Oryza +Oryza sativa rice 1 1 11 4530 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Oryzoideae; Oryzeae; Oryzinae; Oryza +Oryza sativa Indica Group long-grained rice 1 1 11 39946 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Oryzoideae; Oryzeae; Oryzinae; Oryza; Oryza sativa +Oryza sativa Japonica Group Japanese rice 1 1 11 39947 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Oryzoideae; Oryzeae; Oryzinae; Oryza; Oryza sativa +Oryzias latipes Japanese medaka 1 2 - 8090 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Beloniformes; Adrianichthyoidei; Adrianichthyidae; Oryziinae; Oryzias +Osmia cornuta - 1 5 - 185587 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Apoidea; Megachilidae; Megachilinae; Osmiini; Osmia +Ostrinia furnacalis Asian corn borer 1 5 - 93504 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Pyraloidea; Crambidae; Pyraustinae; Ostrinia +Ostrinia nubilalis European corn borer 1 5 - 29057 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Pyraloidea; Crambidae; Pyraustinae; Ostrinia +Otolemur garnettii small-eared galago 1 2 - 30611 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Strepsirrhini; Lorisiformes; Galagidae; Otolemur +Ovis aries sheep 1 2 - 9940 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Caprinae; Ovis +Ovis aries musimon mouflon 1 2 - 9938 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Caprinae; Ovis; Ovis aries +Pachycladon fastigiatum - 1 1 11 106774 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Microlepidieae; Pachycladon +Pachypsylla venusta hackberry petiole gall psyllid 1 5 - 38123 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Paraneoptera; Hemiptera; Sternorrhyncha; Psylliformes; Psylloidea; Psyllidae; Pachypsylla +Paeonia lactiflora Chinese peony 1 1 11 35924 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Saxifragales; Paeoniaceae; Paeonia +Pan paniscus pygmy chimpanzee 1 2 - 9597 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Pan +Pan troglodytes chimpanzee 1 2 - 9598 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Pan +Pan troglodytes troglodytes - 1 2 - 37011 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Pan; Pan troglodytes +Pan troglodytes verus - 1 2 - 37012 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Homininae; Pan; Pan troglodytes +Panax ginseng - 1 1 11 4054 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Apiales; Apiineae; Araliaceae; Panax +Panicum hallii var. filipes - 1 1 11 907226 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Panicodae; Paniceae; Panicinae; Panicum; Panicum hallii +Panthera tigris altaica Amur tiger 1 2 - 74533 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Feliformia; Felidae; Pantherinae; Panthera; Panthera tigris +Pantholops hodgsonii chiru 1 2 - 59538 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Ruminantia; Pecora; Bovidae; Antilopinae; Pantholops +Papilio machaon common yellow swallowtail 1 5 - 76193 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Papilionoidea; Papilionidae; Papilioninae; Papilionini; Papilio +Papilio xuthus Asian swallowtail 1 5 - 66420 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Papilionoidea; Papilionidae; Papilioninae; Papilionini; Papilio +Papio anubis olive baboon 1 2 - 9555 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Papio +Papio hamadryas hamadryas baboon 1 2 - 9557 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Cercopithecinae; Papio +Paramecium tetraurelia strain d4-2 - 6 4 11 412030 INV cellular organisms; Eukaryota; Alveolata; Ciliophora; Intramacronucleata; Oligohymenophorea; Peniculida; Parameciidae; Paramecium; Paramecium tetraurelia +Parascaris equorum - 1 5 - 6256 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Ascaridida; Ascaridoidea; Ascarididae; Parascaris +Parasteatoda tepidariorum common house spider 1 5 - 114398 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Araneae; Araneomorphae; Entelegynae; Orbiculariae; Araneoidea; Theridiidae; Parasteatoda +Parus major Great Tit 1 2 - 9157 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Paridae; Parus +Patiria miniata bat star 1 9 - 46514 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Valvatacea; Valvatida; Asterinidae; Patiria +Patiria pectinifera - 1 9 - 7594 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Valvatacea; Valvatida; Asterinidae; Patiria +Pecten maximus - 1 5 - 6579 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Pteriomorphia; Pectinoida; Pectinoidea; Pectinidae; Pecten +Pedospumella encystans - 1 1 11 1117030 PLN cellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; Chromulinales; Chromulinaceae; Pedospumella +Pelecanus crispus Dalmatian pelican 1 2 - 36300 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Pelecaniformes; Pelecanidae; Pelecanus +Pelodiscus sinensis Chinese soft-shelled turtle 1 2 - 13735 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Testudines; Cryptodira; Trionychia; Trionychidae; Pelodiscus +Penaeus monodon black tiger shrimp 1 5 - 6687 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Dendrobranchiata; Penaeoidea; Penaeidae; Penaeus +Pepsis grossa - 1 5 - 1317727 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Pompiloidea; Pompilidae; Pepsinae; Pepsis +Perkinsus marinus ATCC 50983 - 1 4 11 423536 INV cellular organisms; Eukaryota; Alveolata; Perkinsea; Perkinsida; Perkinsidae; Perkinsus; Perkinsus marinus +Peromyscus maniculatus bairdii prairie deer mouse 1 2 - 230844 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Cricetidae; Neotominae; Peromyscus; Peromyscus maniculatus +Persicaria minor - 1 1 11 488003 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Polygonaceae; Polygonoideae; Persicarieae; Persicaria +Petunia integrifolia subsp. inflata - 1 1 11 212142 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Petunioideae; Petunia; Petunia integrifolia +Phaethon lepturus white-tailed tropicbird 1 2 - 97097 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Pelecaniformes; Phaethontidae; Phaethon +Phalacrocorax carbo great cormorant 1 2 - 9209 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Pelecaniformes; Phalacrocoracidae; Phalacrocorax +Phalaenopsis aphrodite - 1 1 11 212056 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; Asparagales; Orchidaceae; Epidendroideae; Vandeae; Aeridinae; Phalaenopsis +Phaseolus vulgaris - 1 1 11 3885 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Phaseolus +Phoca largha spotted seal 1 2 - 39090 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Phocidae; Phoca +Phoenicopterus ruber ruber - 1 2 - 9218 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Phoenicopteriformes; Phoenicopteridae; Phoenicopterus; Phoenicopterus ruber +Phoenix dactylifera date palm 1 1 11 42345 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Arecales; Arecaceae; Coryphoideae; Phoeniceae; Phoenix +Physalis alkekengi var. franchetii - 1 1 11 221454 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Physaleae; Physalis; Physalis alkekengi +Physalis peruviana - 1 1 11 126903 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Physaleae; Physalis +Physcomitrella patens - 1 1 11 3218 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Bryophyta; Bryophytina; Bryopsida; Funariidae; Funariales; Funariaceae; Physcomitrella +Physeter catodon sperm whale 1 2 - 9755 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Cetacea; Odontoceti; Physeteridae; Physeter +Phytophthora cambivora - 1 1 11 53983 PLN cellular organisms; Eukaryota; Stramenopiles; Oomycetes; Peronosporales; Phytophthora +Phytophthora cinnamomi - 1 1 11 4785 PLN cellular organisms; Eukaryota; Stramenopiles; Oomycetes; Peronosporales; Phytophthora +Phytophthora x alni - 1 1 11 299392 PLN cellular organisms; Eukaryota; Stramenopiles; Oomycetes; Peronosporales; Phytophthora +Picea glauca white spruce 1 1 11 3330 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Picea +Picoides pubescens downy woodpecker 1 2 - 118200 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Piciformes; Picidae; Picoides +Pinus massoniana - 1 1 11 88730 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Pinus; Pinus +Pinus sylvestris Scots pine 1 1 11 3349 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Pinus; Pinus +Pinus taeda loblolly pine 1 1 11 3352 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Pinus; Pinus +Pisaster ochraceus purple sea star 1 9 - 7612 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Asterozoa; Asteroidea; Forcipulatacea; Forcipulatida; Asteriidae; Pisaster +Pisum sativum pea 1 1 11 3888 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Fabeae; Pisum +Pisum sativum subsp. sativum - 1 1 11 208194 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Fabeae; Pisum; Pisum sativum +Plakobranchus ocellatus - 1 5 - 259542 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Gastropoda; Heterobranchia; Euthyneura; Panpulmonata; Sacoglossa; Placobranchoidea; Placobranchidae; Plakobranchus +Plasmodium falciparum malaria parasite P. falciparum 1 4 11 5833 INV cellular organisms; Eukaryota; Alveolata; Apicomplexa; Aconoidasida; Haemosporida; Plasmodiidae; Plasmodium; Plasmodium (Laverania) +Plecoglossus altivelis ayu 1 2 - 61084 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Stomiatii; Osmeriformes; Plecoglossidae; Plecoglossus +Plecoglossus altivelis altivelis - 1 2 - 281464 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Stomiatii; Osmeriformes; Plecoglossidae; Plecoglossus; Plecoglossus altivelis +Plukenetia volubilis - 1 1 11 316893 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Euphorbiaceae; Acalyphoideae; Plukenetieae; Plukenetia +Plutella xylostella diamondback moth 1 5 - 51655 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Yponomeutoidea; Plutellidae; Plutella +Poa infirma - 1 1 11 165094 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Poodae; Poeae; Poeae Chloroplast Group 2 (Poeae type); Poinae; Poa +Poa supina - 1 1 11 289064 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Poodae; Poeae; Poeae Chloroplast Group 2 (Poeae type); Poinae; Poa +Podiceps cristatus great crested grebe 1 2 - 345573 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Podicipediformes; Podicipedidae; Podiceps +Poecilia formosa Amazon molly 1 2 - 48698 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Poecilia +Poecilia latipinna sailfin molly 1 2 - 48699 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Poecilia +Poecilia mexicana - 1 2 - 48701 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Poecilia +Poecilia reticulata guppy 1 2 - 8081 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Poecilia +Poeciliopsis prolifica blackstripe livebearer 1 2 - 188132 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Poeciliopsis +Pogonus chalceus - 1 5 - 235516 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Coleoptera; Adephaga; Caraboidea; Carabidae; Trechinae; Pogonini; Pogonus +Pohlia nutans - 1 1 11 140635 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Bryophyta; Bryophytina; Bryopsida; Bryidae; Bryanae; Bryales; Mniaceae; Pohlia +Polistes canadensis - 1 5 - 91411 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Vespidae; Polistinae; Polistini; Polistes +Polistes metricus - 1 5 - 91422 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Vespidae; Polistinae; Polistini; Polistes +Pongo abelii Sumatran orangutan 1 2 - 9601 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Hominoidea; Hominidae; Ponginae; Pongo +Populus euphratica Euphrates poplar 1 1 11 75702 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Salicaceae; Saliceae; Populus +Populus trichocarpa black cottonwood 1 1 11 3694 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Salicaceae; Saliceae; Populus +Porites australiensis - 1 4 - 51061 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Fungiina; Poritidae; Porites +Poterioochromonas sp. DS - 1 1 11 519425 PLN cellular organisms; Eukaryota; Stramenopiles; Synurophyceae; Ochromonadales; Ochromonadaceae; Poterioochromonas +Priapulus caudatus - 1 5 - 37621 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Scalidophora; Priapulida; Priapulidae; Priapulus +Proasellus aragonensis - 1 5 - 1281939 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus arthrodilus - 1 5 - 1281940 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus assaforensis - 1 5 - 1282049 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus cantabricus - 1 5 - 1281948 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus cavaticus - 1 5 - 1281949 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus coiffaiti - 1 5 - 1281953 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus coxalis - 1 5 - 63229 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus ebrensis - 1 5 - 1281961 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus escolai - 1 5 - 1281963 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus grafi - 1 5 - 1281973 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus granadensis - 1 5 - 1281974 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus hercegovinensis - 1 5 - 1281977 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus ibericus - 1 5 - 1281981 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus jaloniacus - 1 5 - 1281986 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus karamani - 1 5 - 1281987 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus margalefi - 1 5 - 1281998 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus meridianus - 1 5 - 1282001 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus ortizi - 1 5 - 1282012 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus racovitzai - 1 5 - 1282023 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus rectus - 1 5 - 1282025 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus solanasi - 1 5 - 1282031 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Proasellus spelaeus - 1 5 - 1282033 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Peracarida; Isopoda; Asellota; Aselloidea; Asellidae; Proasellus +Procambarus clarkii red swamp crayfish 1 5 - 6728 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Astacidea; Astacoidea; Cambaridae; Cambarinae; Procambarus +Procotyla fluviatilis - 1 9 - 231627 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Rhabditophora; Seriata; Tricladida; Continenticola; Planarioidea; Dendrocoelidae; Procotyla +Propithecus coquereli Coquerel's sifaka 1 2 - 379532 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Strepsirrhini; Lemuriformes; Indriidae; Propithecus +Prosopis alba - 1 1 11 207710 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Mimosoideae; Mimoseae; Prosopis +Protobothrops mucrosquamatus - 1 2 - 103944 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Unidentata; Episquamata; Toxicofera; Serpentes; Colubroidea; Viperidae; Crotalinae; Protobothrops +Protopolystoma xenopodis - 1 9 - 117903 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Monogenea; Polyopisthocotylea; Polystomatidae; Protopolystoma +Prunus armeniaca apricot 1 1 11 36596 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Amygdaleae; Prunus +Prunus mume Japanese apricot 1 1 11 102107 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Amygdaleae; Prunus +Prunus persica peach 1 1 11 3760 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Amygdaleae; Prunus +Prymnesium parvum - 1 1 11 97485 PLN cellular organisms; Eukaryota; Haptophyceae; Prymnesiales; Prymnesiaceae; Prymnesium +Pseudacris regilla Pacific treefrog 1 2 - 47562 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Neobatrachia; Hyloidea; Hylidae; Hylinae; Hylini; Pseudacris +Pseudodiploria strigosa - 1 4 - 1428006 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Faviina; Mussidae; Faviinae; Pseudodiploria +Pseudomasaris vespoides - 1 5 - 1317726 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Vespidae; Masarinae; Masarini; Pseudomasaris +Pseudomonas aeruginosa - 11 0 - 287 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Pseudomonadales; Pseudomonadaceae; Pseudomonas; Pseudomonas aeruginosa group +Pseudopodoces humilis Tibetan ground-tit 1 2 - 181119 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Paridae; Pseudopodoces +Pseudotsuga menziesii var. menziesii - 1 1 11 278161 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Pinales; Pinaceae; Pseudotsuga; Pseudotsuga menziesii +Pteridium aquilinum subsp. aquilinum - 1 1 11 104588 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Moniliformopses; Polypodiidae; Polypodiales; Dennstaedtiaceae; Pteridium; Pteridium aquilinum +Pterocles gutturalis yellow-throated sandgrouse 1 2 - 240206 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Ciconiiformes; Pteroclidae; Pterocles +Pteronotus parnellii Parnell's mustached bat 1 2 - 59476 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Mormoopidae; Pteronotus +Pteropus alecto black flying fox 1 2 - 9402 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Megachiroptera; Pteropodidae; Pteropodinae; Pteropus +Pteropus vampyrus large flying fox 1 2 - 132908 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Megachiroptera; Pteropodidae; Pteropodinae; Pteropus +Ptychodera flava - 1 9 - 63121 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Hemichordata; Enteropneusta; Ptychoderidae; Ptychodera +Puccinia psidii - 1 4 - 181123 PLN cellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Basidiomycota; Pucciniomycotina; Pucciniomycetes; Pucciniales; Pucciniaceae; Puccinia +Pundamilia nyererei - 1 2 - 303518 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Cichlomorphae; Cichliformes; Cichlidae; African cichlids; Pseudocrenilabrinae; Haplochromini; Pundamilia +Punica granatum pomegranate 1 1 11 22663 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Myrtales; Lythraceae; Punica +Pygocentrus nattereri red-bellied piranha 1 2 - 42514 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Characiphysae; Characiformes; Characoidei; Serrasalmidae; Pygocentrus +Pygoscelis adeliae Adelie penguin 1 2 - 9238 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Sphenisciformes; Spheniscidae; Pygoscelis +Pyrodinium bahamense var. compressum - 1 4 11 73916 PLN cellular organisms; Eukaryota; Alveolata; Dinophyceae; Gonyaulacales; Goniodomataceae; Pyrodinium; Pyrodinium bahamense +Pyrus communis pear 1 1 11 23211 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Maleae; Pyrus +Pyrus x bretschneideri Chinese white pear 1 1 11 225117 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Maloideae; Maleae; Pyrus +Python bivittatus Burmese python 1 2 - 176946 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Unidentata; Episquamata; Toxicofera; Serpentes; Henophidia; Pythonidae; Python +Quercus suber - 1 1 11 58331 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fagales; Fagaceae; Quercus +Ramulus artemis - 1 5 - 1390046 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Phasmatodea; Verophasmatodea; Anareolatae; Phasmatidae; Phasmatinae; Clitumnini; Ramulus +Rana clamitans bronze frog 1 2 - 145282 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Neobatrachia; Ranoidea; Ranidae; Rana; Aquarana +Raphanus sativus radish 1 1 11 3726 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Brassicaceae; Brassiceae; Raphanus +Rattus norvegicus Norway rat 1 2 - 10116 ROD cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Glires; Rodentia; Sciurognathi; Muroidea; Muridae; Murinae; Rattus +Rauvolfia serpentina serpentwood 1 1 11 4060 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Gentianales; Apocynaceae; Rauvolfioideae; Vinceae; Rauvolfiinae; Rauvolfia +Reaumuria trigyna - 1 1 11 1091135 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Tamaricaceae; Reaumuria +Rhagoletis zephyria snowberry fruit fly 1 5 - 28612 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Tephritoidea; Tephritidae; Trypetinae; Carpomyini; Carpomyina; Rhagoletis +Rhinolophus ferrumequinum greater horseshoe bat 1 2 - 59479 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Microchiroptera; Rhinolophidae; Rhinolophinae; Rhinolophus +Rhinopithecus bieti black snub-nosed monkey 1 2 - 61621 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Colobinae; Rhinopithecus +Rhinopithecus roxellana golden snub-nosed monkey 1 2 - 61622 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Catarrhini; Cercopithecoidea; Cercopithecidae; Colobinae; Rhinopithecus +Rhipicephalus sanguineus brown dog tick 1 5 - 34632 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Parasitiformes; Ixodida; Ixodoidea; Ixodidae; Rhipicephalinae; Rhipicephalus; Rhipicephalus; Rhipicephalus sanguineus group +Rhizoctonia solani AG-1 IA - 1 4 - 983506 PLN cellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Basidiomycota; Agaricomycotina; Agaricomycetes; Agaricomycetes incertae sedis; Cantharellales; Ceratobasidiaceae; Rhizoctonia; Rhizoctonia solani +Rhodinia newara - 1 5 - 1579501 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Saturniini; Rhodinia +Ricinus communis castor bean 1 1 11 3988 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Malpighiales; Euphorbiaceae; Acalyphoideae; Acalypheae; Ricinus +Romanomermis culicivorax - 1 5 - 13658 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Enoplea; Dorylaimia; Mermithida; Mermithoidea; Mermithidae; Romanomermis +Rousettus aegyptiacus Egyptian rousette 1 2 - 9407 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Chiroptera; Megachiroptera; Pteropodidae; Pteropodinae; Rousettus +Rubus hybrid cultivar - 1 1 11 564016 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rosaceae; Rosoideae; Rosoideae unplaced; Rubus +Rumex palustris - 1 1 11 50298 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Polygonaceae; Polygonoideae; Rumiceae; Rumex +Saccharomyces cerevisiae baker's yeast 1 3 - 4932 PLN cellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Ascomycota; saccharomyceta; Saccharomycotina; Saccharomycetes; Saccharomycetales; Saccharomycetaceae; Saccharomyces +Saccharomyces pastorianus - 1 3 - 27292 PLN cellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Ascomycota; saccharomyceta; Saccharomycotina; Saccharomycetes; Saccharomycetales; Saccharomycetaceae; Saccharomyces +Saccoglossus kowalevskii - 1 9 - 10224 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Hemichordata; Enteropneusta; Harrimaniidae; Saccoglossus +Saimiri boliviensis boliviensis Bolivian squirrel monkey 1 2 - 39432 PRI cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Primates; Haplorrhini; Simiiformes; Platyrrhini; Cebidae; Saimiriinae; Saimiri; Saimiri boliviensis +Salicornia europaea - 1 1 11 206448 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Chenopodiaceae; Salicornioideae; Salicornia +Salmo salar Atlantic salmon 1 2 - 8030 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Protacanthopterygii; Salmoniformes; Salmonidae; Salmoninae; Salmo +Salmonella enterica - 11 0 - 28901 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Salmonella +Salmonella enterica subsp. enterica serovar Typhi - 11 0 - 90370 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Salmonella; Salmonella enterica; Salmonella enterica subsp. enterica +Salmonella enterica subsp. enterica serovar Typhimurium - 11 0 - 90371 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Salmonella; Salmonella enterica; Salmonella enterica subsp. enterica +Salmonella enterica subsp. enterica serovar Typhimurium str. DT104 - 11 0 - 85569 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Salmonella; Salmonella enterica; Salmonella enterica subsp. enterica; Salmonella enterica subsp. enterica serovar Typhimurium +Samia ricini Indian eri silkmoth 1 5 - 63990 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Bombycoidea; Saturniidae; Saturniinae; Attacini; Samia +Sarcophilus harrisii Tasmanian devil 1 2 - 9305 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Metatheria; Dasyuromorphia; Dasyuridae; Sarcophilus +Sarsinebalia urgorrii - 1 5 - 1032695 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Phyllocarida; Leptostraca; Nebaliidae; Sarsinebalia +Saussurea involucrata - 1 1 11 200489 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; campanulids; Asterales; Asteraceae; Carduoideae; Cardueae; Carduinae; Saussurea +Sceliphron caementarium - 1 5 - 253855 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Sphecoidea; Sphecidae; Sphecinae; Sceliphrini; Sceliphrina; Sceliphron +Schistocephalus solidus - 1 9 - 70667 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Cestoda; Eucestoda; Diphyllobothriidea; Diphyllobothriidae; Schistocephalus +Schistosoma curassoni - 1 9 - 6186 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma +Schistosoma haematobium - 1 9 - 6185 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma +Schistosoma japonicum - 1 9 - 6182 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma +Schistosoma mansoni - 1 9 - 6183 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma +Schistosoma mattheei - 1 9 - 31246 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma +Schistosoma rodhaini - 1 9 - 6188 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Schistosoma +Schmidtea mediterranea - 1 9 - 79327 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Rhabditophora; Seriata; Tricladida; Continenticola; Geoplanoidea; Dugesiidae; Schmidtea +Sclerodactyla briareus - 1 9 - 7710 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Holothuroidea; Dendrochirotacea; Dendrochirotida; Sclerodactylidae; Sclerodactyla +Scleropages formosus Asian bonytongue 1 2 - 113540 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Osteoglossocephala; Osteoglossomorpha; Osteoglossiformes; Osteoglossidae; Scleropages +Sclerotinia homoeocarpa - 1 4 - 38483 PLN cellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Ascomycota; saccharomyceta; Pezizomycotina; leotiomyceta; sordariomyceta; Leotiomycetes; Helotiales; Sclerotiniaceae; Sclerotinia +Scophthalmus maximus turbot 1 2 - 52904 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Carangaria; Pleuronectiformes; Pleuronectoidei; Scophthalmidae; Scophthalmus +Scylla olivacea orange mud crab 1 5 - 85551 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Malacostraca; Eumalacostraca; Eucarida; Decapoda; Pleocyemata; Brachyura; Eubrachyura; Heterotremata; Portunoidea; Portunidae; Scylla +Sebastes nigrocinctus tiger rockfish 1 2 - 72089 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Perciformes; Scorpaenoidei; Sebastidae; Sebastinae; Sebastes +Secale cereale rye 1 1 11 4550 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Hordeinae; Secale +Sedum alfredii - 1 1 11 439688 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Saxifragales; Crassulaceae; Sedum +Selaginella moellendorffii - 1 1 11 88036 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Lycopodiidae; Selaginellales; Selaginellaceae; Selaginella +Serinus canaria common canary 1 2 - 9135 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Passeroidea; Fringillidae; Carduelinae; Serinus +Sesamum indicum sesame 1 1 11 4182 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Lamiales; Pedaliaceae; Sesamum +Setaria italica foxtail millet 1 1 11 4555 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Panicodae; Paniceae; Cenchrinae; Setaria +Shigella sonnei - 11 0 - 624 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Enterobacterales; Enterobacteriaceae; Shigella +Silene latifolia - 1 1 11 37657 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Caryophyllaceae; Sileneae; Silene +Simian immunodeficiency virus - 1 0 - 11723 VRL Viruses; Retro-transcribing viruses; Retroviridae; Orthoretrovirinae; Lentivirus; Primate lentivirus group +Sinocyclocheilus angustiporus - 1 2 - 307947 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Sinocyclocheilus +Sinocyclocheilus anophthalmus eyeless golden-line fish 1 2 - 307955 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Sinocyclocheilus +Sinocyclocheilus anshuiensis - 1 2 - 1608454 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Sinocyclocheilus +Sinocyclocheilus grahami - 1 2 - 75366 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Sinocyclocheilus +Sinocyclocheilus rhinocerous - 1 2 - 307959 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Otomorpha; Ostariophysi; Otophysi; Cypriniphysae; Cypriniformes; Cyprinoidea; Cyprinidae; Sinocyclocheilus +Sinopodophyllum hexandrum - 1 1 11 93608 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; stem eudicotyledons; Ranunculales; Berberidaceae; Podophylloideae; Sinopodophyllum +Sipyloidea sipylus - 1 5 - 202427 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Phasmatodea; Verophasmatodea; Anareolatae; Diapheromeridae; Necrosciinae; Sipyloidea +soil metagenome - 11 2 11 410658 ENV unclassified sequences; metagenomes; ecological metagenomes +Solanum chacoense Chaco potato 1 1 11 4108 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum +Solanum lycopersicum tomato 1 1 11 4081 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum; Lycopersicon +Solanum melongena eggplant 1 1 11 4111 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum +Solanum pennellii - 1 1 11 28526 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum; Lycopersicon +Solanum torvum - 1 1 11 119830 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum +Solanum tuberosum potato 1 1 11 4113 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Solaneae; Solanum +Solenopsis invicta red fire ant 1 5 - 13686 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Solenopsidini; Solenopsis +Sorex araneus European shrew 1 2 - 42254 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Insectivora; Soricidae; Soricinae; Sorex +Sorghum bicolor sorghum 1 1 11 4558 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Andropogonodae; Andropogoneae; Sorghinae; Sorghum +Speleonectes cf. tulumensis BMR-2011 - 1 5 - 1032549 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Remipedia; Nectiopoda; Speleonectidae; Speleonectes +Sphaerechinus granularis - 1 9 - 39374 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Euechinoidea; Echinacea; Temnopleuroida; Toxopneustidae; Sphaerechinus +Sphaeroforma arctica JP610 - 1 1 - 667725 INV cellular organisms; Eukaryota; Opisthokonta; Opisthokonta incertae sedis; Ichthyosporea; Ichthyophonida; Sphaeroforma; Sphaeroforma arctica +Sphaeropthalma orestes - 1 5 - 374941 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Pompiloidea; Mutillidae; Sphaeropthalminae; Sphaeropthalma +Spinacia oleracea spinach 1 1 11 3562 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; Caryophyllales; Chenopodiaceae; Chenopodioideae; Anserineae; Spinacia +Spirometra erinaceieuropaei - 1 9 - 99802 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Cestoda; Eucestoda; Diphyllobothriidea; Diphyllobothriidae; Spirometra +Spodoptera exigua beet armyworm 1 5 - 7107 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Amphipyrinae; Spodoptera +Spodoptera frugiperda fall armyworm 1 5 - 7108 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Amphipyrinae; Spodoptera +Spumella vulgaris - 1 1 11 1117031 PLN cellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; Chromulinales; Chromulinaceae; Spumella +Spumella-like flagellate JBC/S23 - 1 1 11 293195 PLN cellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; unclassified Chrysophyceae; Spumella-like flagellate JB +Spumella-like flagellate JBNZ39 - 1 1 11 293202 PLN cellular organisms; Eukaryota; Stramenopiles; Chrysophyceae; unclassified Chrysophyceae; Spumella-like flagellate JB +Staphylococcus aureus - 11 0 - 1280 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Bacillales; Staphylococcaceae; Staphylococcus +Staphylococcus epidermidis - 11 0 - 1282 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Bacillales; Staphylococcaceae; Staphylococcus +Stegastes partitus bicolor damselfish 1 2 - 144197 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Ovalentaria incertae sedis; Pomacentridae; Stegastes +Stegodyphus mimosarum - 1 5 - 407821 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Araneae; Araneomorphae; Entelegynae; Eresoidea; Eresidae; Stegodyphus +Stenotrophomonas maltophilia - 11 0 - 40324 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Xanthomonadales; Xanthomonadaceae; Stenotrophomonas; Stenotrophomonas maltophilia group +Stigmatomma oregonense - 1 5 - 602440 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Amblyoponinae; Stigmatomma +Stomoxys calcitrans stable fly 1 5 - 35570 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Calyptratae; Muscoidea; Muscidae; Muscinae; Stomoxyini; Stomoxys +Streptococcus agalactiae - 11 0 - 1311 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Streptococcaceae; Streptococcus +Streptococcus equi subsp. equi - 11 0 - 148942 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Streptococcaceae; Streptococcus; Streptococcus dysgalactiae group; Streptococcus equi +Streptococcus pneumoniae - 11 0 - 1313 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Streptococcaceae; Streptococcus +Streptococcus suis - 11 0 - 1307 BCT cellular organisms; Bacteria; Terrabacteria group; Firmicutes; Bacilli; Lactobacillales; Streptococcaceae; Streptococcus +Strongylocentrotus purpuratus purple sea urchin 1 9 - 7668 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Echinodermata; Eleutherozoa; Echinozoa; Echinoidea; Euechinoidea; Echinacea; Echinoida; Strongylocentrotidae; Strongylocentrotus +Strongylus vulgaris - 1 5 - 40348 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Chromadorea; Rhabditida; Strongylida; Strongyloidea; Strongylidae; Strongylinae; Strongylus +Struthio camelus australis - 1 2 - 441894 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Palaeognathae; Struthioniformes; Struthionidae; Struthio; Struthio camelus +Stylophora pistillata - 1 4 - 50429 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Anthozoa; Hexacorallia; Scleractinia; Astrocoeniina; Pocilloporidae; Stylophora +Sus scrofa pig 1 2 - 9823 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Suina; Suidae; Sus +Symbiodinium sp. A1 - 1 4 11 503409 PLN cellular organisms; Eukaryota; Alveolata; Dinophyceae; Suessiales; Symbiodiniaceae; Symbiodinium; Symbiodinium sp. clades; Symbiodinium sp. clade A +Symbiodinium sp. A2 - 1 4 11 765178 PLN cellular organisms; Eukaryota; Alveolata; Dinophyceae; Suessiales; Symbiodiniaceae; Symbiodinium; Symbiodinium sp. clades; Symbiodinium sp. clade A +Symbiodinium sp. B2 - 1 4 11 154560 PLN cellular organisms; Eukaryota; Alveolata; Dinophyceae; Suessiales; Symbiodiniaceae; Symbiodinium; Symbiodinium sp. clades; Symbiodinium sp. clade B +Symphylella vulgaris - 1 5 - 1288507 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Myriapoda; Symphyla; Scolopendrellidae; Symphylella +synthetic construct - 11 0 11 32630 SYN other sequences; artificial sequences +Synura sp. LO234KE - 1 1 11 1825120 PLN cellular organisms; Eukaryota; Stramenopiles; Synurophyceae; Synurales; Mallomonadaceae; Synura +Taeniopygia guttata zebra finch 1 2 - 59729 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Passeroidea; Estrildidae; Estrildinae; Taeniopygia +Takifugu rubripes torafugu 1 2 - 31033 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Tetraodontiformes; Tetraodontoidei; Tetradontoidea; Tetraodontidae; Takifugu +Tarenaya hassleriana - 1 1 11 28532 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Brassicales; Cleomaceae; Tarenaya +Tauraco erythrolophus red-crested turaco 1 2 - 121530 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Musophagiformes; Musophagidae; Tauraco +Taxus wallichiana var. chinensis - 1 1 11 29808 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Acrogymnospermae; Pinidae; Cupressales; Taxaceae; Taxus; Taxus wallichiana +Telenomus podisi - 1 5 - 408256 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Platygastroidea; Scelionidae; Telenominae; Telenomus +Teleogryllus commodus - 1 5 - 672150 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Orthopteroidea; Orthoptera; Ensifera; Grylloidea; Gryllidae; Gryllinae; Teleogryllus +Teleopsis dalmanni - 1 5 - 139649 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Diopsoidea; Diopsidae; Teleopsis +Teleopsis whitei - 1 5 - 139651 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Diptera; Brachycera; Muscomorpha; Eremoneura; Cyclorrhapha; Schizophora; Acalyptratae; Diopsoidea; Diopsidae; Teleopsis +Termitomyces clypeatus MTCC 5091 - 1 4 - 1282671 PLN cellular organisms; Eukaryota; Opisthokonta; Fungi; Dikarya; Basidiomycota; Agaricomycotina; Agaricomycetes; Agaricomycetidae; Agaricales; Lyophyllaceae; Termitomyces; Termitomyces clypeatus +Tetramorium bicarinatum - 1 5 - 219812 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Tetramoriini; Tetramorium +Tetranychus urticae two-spotted spider mite 1 5 - 32264 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Chelicerata; Arachnida; Acari; Acariformes; Trombidiformes; Prostigmata; Eleutherengona; Raphignathae; Tetranychoidea; Tetranychidae; Tetranychus +Tetraodon nigroviridis spotted green pufferfish 1 2 - 99883 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Tetraodontiformes; Tetraodontoidei; Tetradontoidea; Tetraodontidae; Tetraodon +Tetraselmis subcordiformis - 1 1 11 3161 PLN cellular organisms; Eukaryota; Viridiplantae; Chlorophyta; Chlorodendrophyceae; Chlorodendrales; Chlorodendraceae; Tetraselmis +Thamnophis sirtalis - 1 2 - 35019 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Lepidosauria; Squamata; Bifurcata; Unidentata; Episquamata; Toxicofera; Serpentes; Colubroidea; Colubridae; Natricinae; Thamnophis +Theobroma cacao cacao 1 1 11 3641 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; malvids; Malvales; Malvaceae; Byttnerioideae; Theobroma +Thermobia domestica firebrat 1 5 - 89055 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Zygentoma; Lepismatidae; Thermobia +Tigriopus californicus - 1 5 - 6832 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Crustacea; Maxillopoda; Copepoda; Neocopepoda; Podoplea; Harpacticoida; Harpacticidae; Tigriopus +Tinamus guttatus white-throated tinamou 1 2 - 94827 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Palaeognathae; Tinamiformes; Tinamidae; Tinamus +Trachemys scripta elegans - 1 2 - 31138 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Testudines; Cryptodira; Durocryptodira; Testudinoidea; Emydidae; Trachemys; Trachemys scripta +Trachymyrmex cornetzi - 1 5 - 471704 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Attini; Trachymyrmex +Trematomus bernacchii emerald rockcod 1 2 - 40690 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Eupercaria; Perciformes; Notothenioidei; Nototheniidae; Trematomus +Trichechus manatus latirostris Florida manatee 1 2 - 127582 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Afrotheria; Sirenia; Trichechidae; Trichechus; Trichechus manatus +Trichinella spiralis - 1 5 - 6334 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Nematoda; Enoplea; Dorylaimia; Trichocephalida; Trichinellidae; Trichinella +Trichobilharzia regenti - 1 9 - 157069 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Platyhelminthes; Trematoda; Digenea; Strigeidida; Schistosomatoidea; Schistosomatidae; Trichobilharzia +Trichomonas vaginalis G3 - 1 0 11 412133 INV cellular organisms; Eukaryota; Parabasalia; Trichomonadida; Trichomonadidae; Trichomonas; Trichomonas vaginalis +Trichoplusia ni cabbage looper 1 5 - 7111 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Amphiesmenoptera; Lepidoptera; Glossata; Neolepidoptera; Heteroneura; Ditrysia; Obtectomera; Noctuoidea; Noctuidae; Plusiinae; Trichoplusia +Trifolium pratense - 1 1 11 57577 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Trifolieae; Trifolium +Tripterygion delaisi - 1 2 - 57862 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Blenniimorphae; Blenniiformes; Blennioidei; Tripterygiidae; Tripterygiinae; Tripterygion +Tripterygium wilfordii - 1 1 11 458696 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Celastrales; Celastraceae; Tripterygium +Triticum aestivum bread wheat 1 1 11 4565 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Triticinae; Triticum +Triticum turgidum - 1 1 11 4571 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Triticinae; Triticum +Triticum urartu - 1 1 11 4572 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; BOP clade; Pooideae; Triticodae; Triticeae; Triticinae; Triticum +Trypanosoma cruzi strain CL Brener - 1 4 11 353153 INV cellular organisms; Eukaryota; Euglenozoa; Kinetoplastida; Trypanosomatidae; Trypanosoma; Schizotrypanum; Trypanosoma cruzi +Tupaia chinensis Chinese tree shrew 1 2 - 246437 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Euarchontoglires; Scandentia; Tupaiidae; Tupaia +Turritopsis sp. SK-2016 - 1 4 - 1784781 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Cnidaria; Hydrozoa; Hydroidolina; Anthoathecata; Filifera; Oceaniidae; Turritopsis +Tursiops truncatus bottlenosed dolphin 1 2 - 9739 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Cetacea; Odontoceti; Delphinidae; Tursiops +Tyto alba barn owl 1 2 - 56313 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Strigiformes; Tytonidae; Tyto +uncultured archaeon - 11 0 - 115547 ENV cellular organisms; Archaea; environmental samples +uncultured bacterium - 11 0 - 77133 ENV cellular organisms; Bacteria; environmental samples +uncultured eukaryote - 1 1 11 100272 ENV cellular organisms; Eukaryota; environmental samples +uncultured fungus - 1 4 - 175245 ENV cellular organisms; Eukaryota; Opisthokonta; Fungi; environmental samples +uncultured microorganism - 11 2 11 358574 ENV unclassified sequences; environmental samples +uncultured Neocallimastigales - 1 0 - 325898 ENV cellular organisms; Eukaryota; Opisthokonta; Fungi; Neocallimastigomycota; Neocallimastigomycetes; Neocallimastigales; environmental samples +uncultured organism - 11 2 11 155900 ENV unclassified sequences; environmental samples +uncultured prokaryote - 11 0 11 198431 ENV unclassified sequences; environmental samples; prokaryotic environmental samples +uncultured Pseudomonas sp. - 11 0 - 114707 ENV cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Pseudomonadales; Pseudomonadaceae; Pseudomonas; environmental samples +uncultured soil bacterium - 11 0 - 164851 ENV cellular organisms; Bacteria; environmental samples +unidentified - 1 2 11 32644 UNA unclassified sequences +unidentified bacterium - 11 0 - 1826778 BCT cellular organisms; Bacteria; unclassified Bacteria; unclassified Bacteria (miscellaneous) +Ursus maritimus polar bear 1 2 - 29073 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Carnivora; Caniformia; Ursidae; Ursus +Vaccinium macrocarpon - 1 1 11 13750 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; Ericales; Ericaceae; Vaccinioideae; Vaccinieae; Vaccinium +Vibrio cholerae - 11 0 - 666 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Vibrionales; Vibrionaceae; Vibrio +Vibrio parahaemolyticus - 11 0 - 670 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Vibrionales; Vibrionaceae; Vibrio; Vibrio harveyi group +Vicia faba fava bean 1 1 11 3906 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Fabeae; Vicia +Vicugna pacos alpaca 1 2 - 30538 MAM cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Mammalia; Theria; Eutheria; Boreoeutheria; Laurasiatheria; Cetartiodactyla; Tylopoda; Camelidae; Vicugna +Vigna angularis adzuki bean 1 1 11 3914 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Vigna +Vigna radiata - 1 1 11 157791 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Vigna +Vigna radiata var. radiata mung bean 1 1 11 3916 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Fabales; Fabaceae; Papilionoideae; Phaseoleae; Vigna; Vigna radiata +Villosa lienosa - 1 5 - 326719 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Lophotrochozoa; Mollusca; Bivalvia; Palaeoheterodonta; Unionoida; Unionoidea; Unionidae; Unioninae; Villosa +Vitis vinifera wine grape 1 1 11 29760 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; rosids incertae sedis; Vitales; Vitaceae; Vitis +Vollenhovia emeryi - 1 5 - 411798 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Stenammini; Vollenhovia +Wasmannia auropunctata little fire ant 1 5 - 64793 INV cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Protostomia; Ecdysozoa; Panarthropoda; Arthropoda; Mandibulata; Pancrustacea; Hexapoda; Insecta; Dicondylia; Pterygota; Neoptera; Endopterygota; Hymenoptera; Apocrita; Aculeata; Vespoidea; Formicidae; Myrmicinae; Blepharidattini; Wasmannia +Withania somnifera - 1 1 11 126910 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; asterids; lamiids; Solanales; Solanaceae; Solanoideae; Physaleae; Withania +Xanthomonas citri pv. citri - 11 0 - 434928 BCT cellular organisms; Bacteria; Proteobacteria; Gammaproteobacteria; Xanthomonadales; Xanthomonadaceae; Xanthomonas; Xanthomonas citri group; Xanthomonas citri +Xenopus laevis African clawed frog 1 2 - 8355 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Pipoidea; Pipidae; Xenopodinae; Xenopus; Xenopus +Xenopus tropicalis tropical clawed frog 1 2 - 8364 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amphibia; Batrachia; Anura; Pipoidea; Pipidae; Xenopodinae; Xenopus; Silurana +Xiphophorus maculatus southern platyfish 1 2 - 8083 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Actinopterygii; Actinopteri; Neopterygii; Teleostei; Osteoglossocephalai; Clupeocephala; Euteleosteomorpha; Neoteleostei; Eurypterygia; Ctenosquamata; Acanthomorphata; Euacanthomorphacea; Percomorphaceae; Ovalentaria; Atherinomorphae; Cyprinodontiformes; Cyprinodontoidei; Poeciliidae; Poeciliinae; Xiphophorus +Zantedeschia aethiopica - 1 1 11 69721 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Alismatales; Araceae; Philodendroideae; Zantedeschieae; Zantedeschia +Zea mays - 1 1 11 4577 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Andropogonodae; Andropogoneae; Tripsacinae; Zea +Zea mays subsp. mays maize 1 1 11 381124 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Petrosaviidae; commelinids; Poales; Poaceae; PACMAD clade; Panicoideae; Andropogonodae; Andropogoneae; Tripsacinae; Zea; Zea mays +Ziziphus jujuba - 1 1 11 326968 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; eudicotyledons; Gunneridae; Pentapetalae; rosids; fabids; Rosales; Rhamnaceae; Paliureae; Ziziphus +Zonotrichia albicollis white-throated sparrow 1 2 - 44394 VRT cellular organisms; Eukaryota; Opisthokonta; Metazoa; Eumetazoa; Bilateria; Deuterostomia; Chordata; Craniata; Vertebrata; Gnathostomata; Teleostomi; Euteleostomi; Sarcopterygii; Dipnotetrapodomorpha; Tetrapoda; Amniota; Sauropsida; Sauria; Archelosauria; Archosauria; Dinosauria; Saurischia; Theropoda; Coelurosauria; Aves; Neognathae; Passeriformes; Passerellidae; Zonotrichia +Zostera noltei - 1 1 11 55326 PLN cellular organisms; Eukaryota; Viridiplantae; Streptophyta; Streptophytina; Embryophyta; Tracheophyta; Euphyllophyta; Spermatophyta; Magnoliophyta; Mesangiospermae; Liliopsida; Alismatales; Zosteraceae; Zostera diff --git a/c++/src/objects/seqfeat/ecnum_ambiguous.inc b/c++/src/objects/seqfeat/ecnum_ambiguous.inc index 8e7d1795..875f4e18 100644 --- a/c++/src/objects/seqfeat/ecnum_ambiguous.inc +++ b/c++/src/objects/seqfeat/ecnum_ambiguous.inc @@ -1,4 +1,4 @@ -/* $Id: ecnum_ambiguous.inc 483918 2015-11-04 22:53:59Z kans $ +/* $Id: ecnum_ambiguous.inc 540671 2017-07-10 15:05:11Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,742 +31,748 @@ */ static const char* const kECNum_ambiguous[] = { - "1.-.-.- Oxidoreductases", - "1.n.n.n Oxidoreductases", - "1.1.-.- Acting on the CH-OH group of donors", - "1.1.n.n Acting on the CH-OH group of donors", - "1.1.1.- With NAD(+) or NADP(+) as acceptor", - "1.1.1.n With NAD(+) or NADP(+) as acceptor", - "1.1.2.- With a cytochrome as acceptor", - "1.1.2.n With a cytochrome as acceptor", - "1.1.3.- With oxygen as acceptor", - "1.1.3.n With oxygen as acceptor", - "1.1.4.- With a disulfide as acceptor", - "1.1.4.n With a disulfide as acceptor", - "1.1.5.- With a quinone or similar compound as acceptor", - "1.1.5.n With a quinone or similar compound as acceptor", - "1.1.9.- With a copper protein as acceptor", - "1.1.9.n With a copper protein as acceptor", - "1.1.98.- With other, known, acceptors", - "1.1.98.n With other, known, acceptors", - "1.1.99.- With other acceptors", - "1.1.99.n With other acceptors", - "1.2.-.- Acting on the aldehyde or oxo group of donors", - "1.2.n.n Acting on the aldehyde or oxo group of donors", - "1.2.1.- With NAD(+) or NADP(+) as acceptor", - "1.2.1.n With NAD(+) or NADP(+) as acceptor", - "1.2.2.- With a cytochrome as acceptor", - "1.2.2.n With a cytochrome as acceptor", - "1.2.3.- With oxygen as acceptor", - "1.2.3.n With oxygen as acceptor", - "1.2.4.- With a disulfide as acceptor", - "1.2.4.n With a disulfide as acceptor", - "1.2.5.- With a quinone or similar compound as acceptor", - "1.2.5.n With a quinone or similar compound as acceptor", - "1.2.7.- With an iron-sulfur protein as acceptor", - "1.2.7.n With an iron-sulfur protein as acceptor", - "1.2.98.- With other, known, acceptors", - "1.2.98.n With other, known, acceptors", - "1.2.99.- With other acceptors", - "1.2.99.n With other acceptors", - "1.3.-.- Acting on the CH-CH group of donors", - "1.3.n.n Acting on the CH-CH group of donors", - "1.3.1.- With NAD(+) or NADP(+) as acceptor", - "1.3.1.n With NAD(+) or NADP(+) as acceptor", - "1.3.2.- With a cytochrome as acceptor", - "1.3.2.n With a cytochrome as acceptor", - "1.3.3.- With oxygen as acceptor", - "1.3.3.n With oxygen as acceptor", - "1.3.4.- With a disulfide as acceptor", - "1.3.4.n With a disulfide as acceptor", - "1.3.5.- With a quinone or related compound as acceptor", - "1.3.5.n With a quinone or related compound as acceptor", - "1.3.7.- With an iron-sulfur protein as acceptor", - "1.3.7.n With an iron-sulfur protein as acceptor", - "1.3.8.- With a flavin as acceptor", - "1.3.8.n With a flavin as acceptor", - "1.3.98.- With other, known, acceptors", - "1.3.98.n With other, known, acceptors", - "1.3.99.- With other acceptors", - "1.3.99.n With other acceptors", - "1.4.-.- Acting on the CH-NH(2) group of donors", - "1.4.n.n Acting on the CH-NH(2) group of donors", - "1.4.1.- With NAD(+) or NADP(+) as acceptor", - "1.4.1.n With NAD(+) or NADP(+) as acceptor", - "1.4.2.- With a cytochrome as acceptor", - "1.4.2.n With a cytochrome as acceptor", - "1.4.3.- With oxygen as acceptor", - "1.4.3.n With oxygen as acceptor", - "1.4.4.- With a disulfide as acceptor", - "1.4.4.n With a disulfide as acceptor", - "1.4.5.- With a quinone or similar compound as acceptor", - "1.4.5.n With a quinone or similar compound as acceptor", - "1.4.7.- With an iron-sulfur protein as acceptor", - "1.4.7.n With an iron-sulfur protein as acceptor", - "1.4.9.- With a copper protein as acceptor", - "1.4.9.n With a copper protein as acceptor", - "1.4.98.- With other, known, acceptors", - "1.4.98.n With other, known, acceptors", - "1.4.99.- With other acceptors", - "1.4.99.n With other acceptors", - "1.5.-.- Acting on the CH-NH group of donors", - "1.5.n.n Acting on the CH-NH group of donors", - "1.5.1.- With NAD(+) or NADP(+) as acceptor", - "1.5.1.n With NAD(+) or NADP(+) as acceptor", - "1.5.3.- With oxygen as acceptor", - "1.5.3.n With oxygen as acceptor", - "1.5.4.- With a disulfide as acceptor", - "1.5.4.n With a disulfide as acceptor", - "1.5.5.- With a quinone or similar compound as acceptor", - "1.5.5.n With a quinone or similar compound as acceptor", - "1.5.7.- With an iron-sulfur protein as acceptor", - "1.5.7.n With an iron-sulfur protein as acceptor", - "1.5.8.- With a flavin as acceptor", - "1.5.8.n With a flavin as acceptor", - "1.5.98.- With other, known, acceptors", - "1.5.98.n With other, known, acceptors", - "1.5.99.- With other acceptors", - "1.5.99.n With other acceptors", - "1.6.-.- Acting on NADH or NADPH", - "1.6.n.n Acting on NADH or NADPH", - "1.6.1.- With NAD(+) or NADP(+) as acceptor", - "1.6.1.n With NAD(+) or NADP(+) as acceptor", - "1.6.2.- With a heme protein as acceptor", - "1.6.2.n With a heme protein as acceptor", - "1.6.3.- With oxygen as acceptor", - "1.6.3.n With oxygen as acceptor", - "1.6.4.- With a disulfide as acceptor", - "1.6.4.n With a disulfide as acceptor", - "1.6.5.- With a quinone or similar compound as acceptor", - "1.6.5.n With a quinone or similar compound as acceptor", - "1.6.6.- With a nitrogenous group as acceptor", - "1.6.6.n With a nitrogenous group as acceptor", - "1.6.7.- With a iron-sulfur protein as acceptor", - "1.6.7.n With a iron-sulfur protein as acceptor", - "1.6.8.- With a flavin as acceptor", - "1.6.8.n With a flavin as acceptor", - "1.6.99.- With other acceptors", - "1.6.99.n With other acceptors", - "1.7.-.- Acting on other nitrogenous compounds as donors", - "1.7.n.n Acting on other nitrogenous compounds as donors", - "1.7.1.- With NAD(+) or NADP(+) as acceptor", - "1.7.1.n With NAD(+) or NADP(+) as acceptor", - "1.7.2.- With a cytochrome as acceptor", - "1.7.2.n With a cytochrome as acceptor", - "1.7.3.- With oxygen as acceptor", - "1.7.3.n With oxygen as acceptor", - "1.7.5.- With a quinone or similar compound as acceptor", - "1.7.5.n With a quinone or similar compound as acceptor", - "1.7.6.- With a nitrogenous group as acceptor", - "1.7.6.n With a nitrogenous group as acceptor", - "1.7.7.- With an iron-sulfur protein as acceptor", - "1.7.7.n With an iron-sulfur protein as acceptor", - "1.7.9.- With a copper protein as acceptor", - "1.7.9.n With a copper protein as acceptor", - "1.7.99.- With other acceptors", - "1.7.99.n With other acceptors", - "1.8.-.- Acting on a sulfur group of donors", - "1.8.n.n Acting on a sulfur group of donors", - "1.8.1.- With NAD(+) or NADP(+) as acceptor", - "1.8.1.n With NAD(+) or NADP(+) as acceptor", - "1.8.2.- With a cytochrome as acceptor", - "1.8.2.n With a cytochrome as acceptor", - "1.8.3.- With oxygen as acceptor", - "1.8.3.n With oxygen as acceptor", - "1.8.4.- With a disulfide as acceptor", - "1.8.4.n With a disulfide as acceptor", - "1.8.5.- With a quinone or similar compound as acceptor", - "1.8.5.n With a quinone or similar compound as acceptor", - "1.8.6.- With an nitrogenous group as acceptor", - "1.8.6.n With an nitrogenous group as acceptor", - "1.8.7.- With an iron-sulfur protein as acceptor", - "1.8.7.n With an iron-sulfur protein as acceptor", - "1.8.98.- With other, known, acceptors", - "1.8.98.n With other, known, acceptors", - "1.8.99.- With other acceptors", - "1.8.99.n With other acceptors", - "1.9.-.- Acting on a heme group of donors", - "1.9.n.n Acting on a heme group of donors", - "1.9.3.- With oxygen as acceptor", - "1.9.3.n With oxygen as acceptor", - "1.9.6.- With a nitrogenous group as acceptor", - "1.9.6.n With a nitrogenous group as acceptor", - "1.9.98.- With other, known, acceptors", - "1.9.98.n With other, known, acceptors", - "1.9.99.- With other acceptors", - "1.9.99.n With other acceptors", - "1.10.-.- Acting on diphenols and related substances as donors", - "1.10.n.n Acting on diphenols and related substances as donors", - "1.10.1.- With NAD(+) or NADP(+) as acceptor", - "1.10.1.n With NAD(+) or NADP(+) as acceptor", - "1.10.2.- With a cytochrome as acceptor", - "1.10.2.n With a cytochrome as acceptor", - "1.10.3.- With oxygen as acceptor", - "1.10.3.n With oxygen as acceptor", - "1.10.5.- With a quinone or related compound as acceptor", - "1.10.5.n With a quinone or related compound as acceptor", - "1.10.9.- With a copper protein as acceptor", - "1.10.9.n With a copper protein as acceptor", - "1.10.98.- With other, known, acceptors", - "1.10.98.n With other, known, acceptors", - "1.10.99.- With other acceptors", - "1.10.99.n With other acceptors", - "1.11.-.- Acting on a peroxide as acceptor", - "1.11.n.n Acting on a peroxide as acceptor", - "1.11.1.- Peroxidases", - "1.11.1.n Peroxidases", - "1.11.2.- With H(2)O(2) as acceptor, one oxygen atom of which is incorporated into the product", - "1.11.2.n With H(2)O(2) as acceptor, one oxygen atom of which is incorporated into the product", - "1.12.-.- Acting on hydrogen as donors", - "1.12.n.n Acting on hydrogen as donors", - "1.12.1.- With NAD(+) or NADP(+) as acceptor", - "1.12.1.n With NAD(+) or NADP(+) as acceptor", - "1.12.2.- With a cytochrome as acceptor", - "1.12.2.n With a cytochrome as acceptor", - "1.12.5.- With a quinone or similar compound as acceptor", - "1.12.5.n With a quinone or similar compound as acceptor", - "1.12.7.- With an iron-sulfur protein as acceptor", - "1.12.7.n With an iron-sulfur protein as acceptor", - "1.12.98.- With other, known, acceptors", - "1.12.98.n With other, known, acceptors", - "1.12.99.- With other acceptors", - "1.12.99.n With other acceptors", - "1.13.-.- Acting on single donors with incorporation of molecular oxygen (oxygenases). The oxygen incorporated need not be derived from O(2)", - "1.13.n.n Acting on single donors with incorporation of molecular oxygen (oxygenases). The oxygen incorporated need not be derived from O(2)", - "1.13.1.- With NADH or NADPH as one donor", - "1.13.1.n With NADH or NADPH as one donor", - "1.13.11.- With incorporation of two atoms of oxygen", - "1.13.11.n With incorporation of two atoms of oxygen", - "1.13.12.- With incorporation of one atom of oxygen (internal monooxygenases or internal mixed function oxidases)", - "1.13.12.n With incorporation of one atom of oxygen (internal monooxygenases or internal mixed function oxidases)", - "1.13.99.- Miscellaneous", - "1.13.99.n Miscellaneous", - "1.14.-.- Acting on paired donors, with incorporation or reduction of molecular oxygen. The oxygen incorporated need not be derived from O(2)", - "1.14.n.n Acting on paired donors, with incorporation or reduction of molecular oxygen. The oxygen incorporated need not be derived from O(2)", - "1.14.1.- With NADH or NADPH as one donor", - "1.14.1.n With NADH or NADPH as one donor", - "1.14.2.- With ascorbate as one donor", - "1.14.2.n With ascorbate as one donor", - "1.14.3.- With reduced pteridine as one donor", - "1.14.3.n With reduced pteridine as one donor", - "1.14.11.- With 2-oxoglutarate as one donor, and incorporation of one atom each of oxygen into both donors", - "1.14.11.n With 2-oxoglutarate as one donor, and incorporation of one atom each of oxygen into both donors", - "1.14.12.- With NADH or NADPH as one donor, and incorporation of two atoms of oxygen into one donor", - "1.14.12.n With NADH or NADPH as one donor, and incorporation of two atoms of oxygen into one donor", - "1.14.13.- With NADH or NADPH as one donor, and incorporation of one atom of oxygen", - "1.14.13.n With NADH or NADPH as one donor, and incorporation of one atom of oxygen", - "1.14.14.- With reduced flavin or flavoprotein as one donor, and incorporation of one atom of oxygen", - "1.14.14.n With reduced flavin or flavoprotein as one donor, and incorporation of one atom of oxygen", - "1.14.15.- With reduced iron-sulfur protein as one donor, and incorporation of one atom of oxygen", - "1.14.15.n With reduced iron-sulfur protein as one donor, and incorporation of one atom of oxygen", - "1.14.16.- With reduced pteridine as one donor, and incorporation of one atom of oxygen", - "1.14.16.n With reduced pteridine as one donor, and incorporation of one atom of oxygen", - "1.14.17.- With reduced ascorbate as one donor, and incorporation of one atom of oxygen", - "1.14.17.n With reduced ascorbate as one donor, and incorporation of one atom of oxygen", - "1.14.18.- With another compound as one donor, and incorporation of one atom of oxygen", - "1.14.18.n With another compound as one donor, and incorporation of one atom of oxygen", - "1.14.19.- With oxidation of a pair of donors resulting in the reduction of molecular oxygen to two molecules of water", - "1.14.19.n With oxidation of a pair of donors resulting in the reduction of molecular oxygen to two molecules of water", - "1.14.20.- With 2-oxoglutarate as one donor, and the other dehydrogenated", - "1.14.20.n With 2-oxoglutarate as one donor, and the other dehydrogenated", - "1.14.21.- With NADH or NADPH as one donor, and the other dehydrogenated", - "1.14.21.n With NADH or NADPH as one donor, and the other dehydrogenated", - "1.14.99.- Miscellaneous", - "1.14.99.n Miscellaneous", - "1.15.-.- Acting on superoxide as acceptor", - "1.15.n.n Acting on superoxide as acceptor", - "1.15.1.- Acting on superoxide as acceptor", - "1.15.1.n Acting on superoxide as acceptor", - "1.16.-.- Oxidizing metal ions", - "1.16.n.n Oxidizing metal ions", - "1.16.1.- With NAD(+) or NADP(+) as acceptor", - "1.16.1.n With NAD(+) or NADP(+) as acceptor", - "1.16.3.- With oxygen as acceptor", - "1.16.3.n With oxygen as acceptor", - "1.16.5.- With a quinone or similar compound as acceptor", - "1.16.5.n With a quinone or similar compound as acceptor", - "1.16.8.- With a flavin as acceptor", - "1.16.8.n With a flavin as acceptor", - "1.16.9.- With a copper protein as acceptor", - "1.16.9.n With a copper protein as acceptor", - "1.16.98.- With other known acceptors", - "1.16.98.n With other known acceptors", - "1.17.-.- Acting on CH or CH(2) groups", - "1.17.n.n Acting on CH or CH(2) groups", - "1.17.1.- With NAD(+) or NADP(+) as acceptor", - "1.17.1.n With NAD(+) or NADP(+) as acceptor", - "1.17.2.- With a cytochrome as acceptor", - "1.17.2.n With a cytochrome as acceptor", - "1.17.3.- With oxygen as acceptor", - "1.17.3.n With oxygen as acceptor", - "1.17.4.- With a disulfide as acceptor", - "1.17.4.n With a disulfide as acceptor", - "1.17.5.- With a quinone or similar compound as acceptor", - "1.17.5.n With a quinone or similar compound as acceptor", - "1.17.7.- With an iron-sulfur protein as acceptor", - "1.17.7.n With an iron-sulfur protein as acceptor", - "1.17.98.- With other, known, acceptors", - "1.17.98.n With other, known, acceptors", - "1.17.99.- With other acceptors", - "1.17.99.n With other acceptors", - "1.18.-.- Acting on iron-sulfur proteins as donors", - "1.18.n.n Acting on iron-sulfur proteins as donors", - "1.18.1.- With NAD(+) or NADP(+) as acceptor", - "1.18.1.n With NAD(+) or NADP(+) as acceptor", - "1.18.2.- With dinitrogen as acceptor", - "1.18.2.n With dinitrogen as acceptor", - "1.18.3.- With H(+) as acceptor", - "1.18.3.n With H(+) as acceptor", - "1.18.6.- With dinitrogen as acceptor", - "1.18.6.n With dinitrogen as acceptor", - "1.18.96.- With other, known, acceptors", - "1.18.96.n With other, known, acceptors", - "1.18.99.- With H(+) as acceptor", - "1.18.99.n With H(+) as acceptor", - "1.19.-.- Acting on reduced flavodoxin as donor", - "1.19.n.n Acting on reduced flavodoxin as donor", - "1.19.6.- With dinitrogen as acceptor", - "1.19.6.n With dinitrogen as acceptor", - "1.20.-.- Acting on phosphorus or arsenic in donors", - "1.20.n.n Acting on phosphorus or arsenic in donors", - "1.20.1.- With NAD(+) or NADP(+) as acceptor", - "1.20.1.n With NAD(+) or NADP(+) as acceptor", - "1.20.2.- With a cytochrome as acceptor", - "1.20.2.n With a cytochrome as acceptor", - "1.20.4.- With disulfide as acceptor", - "1.20.4.n With disulfide as acceptor", - "1.20.9.- With a copper protein as acceptor", - "1.20.9.n With a copper protein as acceptor", - "1.20.98.- With other, known acceptors", - "1.20.98.n With other, known acceptors", - "1.20.99.- With other acceptors", - "1.20.99.n With other acceptors", - "1.21.-.- Catalyzing the reaction X-H + Y-H = 'X-Y'", - "1.21.n.n Catalyzing the reaction X-H + Y-H = 'X-Y'", - "1.21.1.- With NAD(+) or NADP(+) as acceptor", - "1.21.1.n With NAD(+) or NADP(+) as acceptor", - "1.21.3.- With oxygen as acceptor", - "1.21.3.n With oxygen as acceptor", - "1.21.4.- With a disulfide as acceptor", - "1.21.4.n With a disulfide as acceptor", - "1.21.98.- With other, known acceptors", - "1.21.98.n With other, known acceptors", - "1.21.99.- With other acceptors", - "1.21.99.n With other acceptors", - "1.22.-.- Acting on halogen in donors", - "1.22.n.n Acting on halogen in donors", - "1.22.1.- With NAD(+) or NADP(+) as acceptor", - "1.22.1.n With NAD(+) or NADP(+) as acceptor", - "1.23.-.- Reducing C-O-C group as acceptor", - "1.23.n.n Reducing C-O-C group as acceptor", - "1.23.1.- With NADH or NADPH as donor", - "1.23.1.n With NADH or NADPH as donor", - "1.23.5.- With a quinone or similar compound as acceptor", - "1.23.5.n With a quinone or similar compound as acceptor", - "1.97.-.- Other oxidoreductases", - "1.97.n.n Other oxidoreductases", - "1.97.1.- Other oxidoreductases", - "1.97.1.n Other oxidoreductases", - "1.98.-.- Enzymes using H(2) as reductant", - "1.98.n.n Enzymes using H(2) as reductant", - "1.98.1.- Other oxidoreductases", - "1.98.1.n Other oxidoreductases", - "1.99.-.- Other enzymes using O(2) as oxidant", - "1.99.n.n Other enzymes using O(2) as oxidant", - "1.99.1.- Hydroxylases", - "1.99.1.n Hydroxylases", - "1.99.2.- Oxygenases", - "1.99.2.n Oxygenases", - "2.-.-.- Transferases", - "2.n.n.n Transferases", - "2.1.-.- Transferring one-carbon groups", - "2.1.n.n Transferring one-carbon groups", - "2.1.1.- Methyltransferases", - "2.1.1.n Methyltransferases", - "2.1.2.- Hydroxymethyl-, formyl- and related transferases", - "2.1.2.n Hydroxymethyl-, formyl- and related transferases", - "2.1.3.- Carboxy- and carbamoyltransferases", - "2.1.3.n Carboxy- and carbamoyltransferases", - "2.1.4.- Amidinotransferases", - "2.1.4.n Amidinotransferases", - "2.2.-.- Transferring aldehyde or ketonic groups", - "2.2.n.n Transferring aldehyde or ketonic groups", - "2.2.1.- Transketolases and transaldolases", - "2.2.1.n Transketolases and transaldolases", - "2.3.-.- Acyltransferases", - "2.3.n.n Acyltransferases", - "2.3.1.- Transferring groups other than amino-acyl groups", - "2.3.1.n Transferring groups other than amino-acyl groups", - "2.3.2.- Aminoacyltransferases", - "2.3.2.n Aminoacyltransferases", - "2.3.3.- Acyl groups converted into alkyl groups on transfer", - "2.3.3.n Acyl groups converted into alkyl groups on transfer", - "2.4.-.- Glycosyltransferases", - "2.4.n.n Glycosyltransferases", - "2.4.1.- Hexosyltransferases", - "2.4.1.n Hexosyltransferases", - "2.4.2.- Pentosyltransferases", - "2.4.2.n Pentosyltransferases", - "2.4.99.- Transferring other glycosyl groups", - "2.4.99.n Transferring other glycosyl groups", - "2.5.-.- Transferring alkyl or aryl groups, other than methyl groups", - "2.5.n.n Transferring alkyl or aryl groups, other than methyl groups", - "2.5.1.- Transferring alkyl or aryl groups, other than methyl groups", - "2.5.1.n Transferring alkyl or aryl groups, other than methyl groups", - "2.6.-.- Transferring nitrogenous groups", - "2.6.n.n Transferring nitrogenous groups", - "2.6.1.- Transaminases", - "2.6.1.n Transaminases", - "2.6.2.- Amidinotransferases", - "2.6.2.n Amidinotransferases", - "2.6.3.- Oximinotransferases", - "2.6.3.n Oximinotransferases", - "2.6.99.- Transferring other nitrogenous groups", - "2.6.99.n Transferring other nitrogenous groups", - "2.7.-.- Transferring phosphorus-containing groups", - "2.7.n.n Transferring phosphorus-containing groups", - "2.7.1.- Phosphotransferases with an alcohol group as acceptor", - "2.7.1.n Phosphotransferases with an alcohol group as acceptor", - "2.7.2.- Phosphotransferases with a carboxy group as acceptor", - "2.7.2.n Phosphotransferases with a carboxy group as acceptor", - "2.7.3.- Phosphotransferases with a nitrogenous group as acceptor", - "2.7.3.n Phosphotransferases with a nitrogenous group as acceptor", - "2.7.4.- Phosphotransferases with a phosphate group as acceptor", - "2.7.4.n Phosphotransferases with a phosphate group as acceptor", - "2.7.5.- Phosphotransferases with regeneration of donors, apparently catalyzing intramolecular transfers", - "2.7.5.n Phosphotransferases with regeneration of donors, apparently catalyzing intramolecular transfers", - "2.7.6.- Diphosphotransferases", - "2.7.6.n Diphosphotransferases", - "2.7.7.- Nucleotidyltransferases", - "2.7.7.n Nucleotidyltransferases", - "2.7.8.- Transferases for other substituted phosphate groups", - "2.7.8.n Transferases for other substituted phosphate groups", - "2.7.9.- Phosphotransferases with paired acceptors", - "2.7.9.n Phosphotransferases with paired acceptors", - "2.7.10.- Protein-tyrosine kinases", - "2.7.10.n Protein-tyrosine kinases", - "2.7.11.- Protein-serine/threonine kinases", - "2.7.11.n Protein-serine/threonine kinases", - "2.7.12.- Dual-specificity kinases (those acting on Ser/Thr and Tyr residues)", - "2.7.12.n Dual-specificity kinases (those acting on Ser/Thr and Tyr residues)", - "2.7.13.- Protein-histidine kinases", - "2.7.13.n Protein-histidine kinases", - "2.7.14.- Protein-arginine kinases", - "2.7.14.n Protein-arginine kinases", - "2.7.99.- Other protein kinases", - "2.7.99.n Other protein kinases", - "2.8.-.- Transferring sulfur-containing groups", - "2.8.n.n Transferring sulfur-containing groups", - "2.8.1.- Sulfurtransferases", - "2.8.1.n Sulfurtransferases", - "2.8.2.- Sulfotransferases", - "2.8.2.n Sulfotransferases", - "2.8.3.- CoA-transferases", - "2.8.3.n CoA-transferases", - "2.8.4.- Transferring alkylthio groups", - "2.8.4.n Transferring alkylthio groups", - "2.9.-.- Transferring selenium-containing groups", - "2.9.n.n Transferring selenium-containing groups", - "2.9.1.- Selenotransferases", - "2.9.1.n Selenotransferases", - "2.10.-.- Transferring molybdenum- or tungsten-containing groups", - "2.10.n.n Transferring molybdenum- or tungsten-containing groups", - "2.10.1.- Molybdenumtransferases or tungstentransferases with sulfide groups as acceptors", - "2.10.1.n Molybdenumtransferases or tungstentransferases with sulfide groups as acceptors", - "3.-.-.- Hydrolases", - "3.n.n.n Hydrolases", - "3.1.-.- Acting on ester bonds", - "3.1.n.n Acting on ester bonds", - "3.1.1.- Carboxylic ester hydrolases", - "3.1.1.n Carboxylic ester hydrolases", - "3.1.2.- Thiolester hydrolases", - "3.1.2.n Thiolester hydrolases", - "3.1.3.- Phosphoric monoester hydrolases", - "3.1.3.n Phosphoric monoester hydrolases", - "3.1.4.- Phosphoric diester hydrolases", - "3.1.4.n Phosphoric diester hydrolases", - "3.1.5.- Triphosphoric monoester hydrolases", - "3.1.5.n Triphosphoric monoester hydrolases", - "3.1.6.- Sulfuric ester hydrolases", - "3.1.6.n Sulfuric ester hydrolases", - "3.1.7.- Diphosphoric monoester hydrolases", - "3.1.7.n Diphosphoric monoester hydrolases", - "3.1.8.- Phosphoric triester hydrolases", - "3.1.8.n Phosphoric triester hydrolases", - "3.1.11.- Exodeoxyribonucleases producing 5'-phosphomonoesters", - "3.1.11.n Exodeoxyribonucleases producing 5'-phosphomonoesters", - "3.1.12.- Exodeoxyribonucleases producing 3'-phosphomonoesters", - "3.1.12.n Exodeoxyribonucleases producing 3'-phosphomonoesters", - "3.1.13.- Exoribonucleases producing 5'-phosphomonoesters", - "3.1.13.n Exoribonucleases producing 5'-phosphomonoesters", - "3.1.14.- Exoribonucleases producing 3'-phosphomonoesters", - "3.1.14.n Exoribonucleases producing 3'-phosphomonoesters", - "3.1.15.- Exonucleases active with either ribo- or deoxyribonucleic acids and producing 5'-phosphomonoesters", - "3.1.15.n Exonucleases active with either ribo- or deoxyribonucleic acids and producing 5'-phosphomonoesters", - "3.1.16.- Exonucleases active with either ribo- or deoxyribonucleic acids and producing 3'-phosphomonoesters", - "3.1.16.n Exonucleases active with either ribo- or deoxyribonucleic acids and producing 3'-phosphomonoesters", - "3.1.21.- Endodeoxyribonucleases producing 5'-phosphomonoesters", - "3.1.21.n Endodeoxyribonucleases producing 5'-phosphomonoesters", - "3.1.22.- Endodeoxyribonucleases producing other than 5'-phosphomonoesters", - "3.1.22.n Endodeoxyribonucleases producing other than 5'-phosphomonoesters", - "3.1.23.- Site specific endodeoxyribonucleases: cleavage is sequence specific", - "3.1.23.n Site specific endodeoxyribonucleases: cleavage is sequence specific", - "3.1.24.- Site specific endodeoxyribonucleases: cleavage is not sequence specific", - "3.1.24.n Site specific endodeoxyribonucleases: cleavage is not sequence specific", - "3.1.25.- Site-specific endodeoxyribonucleases specific for altered bases", - "3.1.25.n Site-specific endodeoxyribonucleases specific for altered bases", - "3.1.26.- Endoribonucleases producing 5'-phosphomonoesters", - "3.1.26.n Endoribonucleases producing 5'-phosphomonoesters", - "3.1.27.- Endoribonucleases producing other than 5'-phosphomonoesters", - "3.1.27.n Endoribonucleases producing other than 5'-phosphomonoesters", - "3.1.30.- Endoribonucleases active with either ribo- or deoxyribonucleic acids and producing 5'-phosphomonoesters", - "3.1.30.n Endoribonucleases active with either ribo- or deoxyribonucleic acids and producing 5'-phosphomonoesters", - "3.1.31.- Endoribonucleases active with either ribo- or deoxyribonucleic acids and producing 3'-phosphomonoesters", - "3.1.31.n Endoribonucleases active with either ribo- or deoxyribonucleic acids and producing 3'-phosphomonoesters", - "3.2.-.- Glycosylases", - "3.2.n.n Glycosylases", - "3.2.1.- Glycosidases, i.e. enzymes hydrolyzing O- and S-glycosyl compounds", - "3.2.1.n Glycosidases, i.e. enzymes hydrolyzing O- and S-glycosyl compounds", - "3.2.2.- Hydrolyzing N-glycosyl compounds", - "3.2.2.n Hydrolyzing N-glycosyl compounds", - "3.2.3.- Hydrolyzing S-glycosyl compounds", - "3.2.3.n Hydrolyzing S-glycosyl compounds", - "3.3.-.- Acting on ether bonds", - "3.3.n.n Acting on ether bonds", - "3.3.1.- Thioether and trialkylsulfonium hydrolases", - "3.3.1.n Thioether and trialkylsulfonium hydrolases", - "3.3.2.- Ether hydrolases", - "3.3.2.n Ether hydrolases", - "3.4.-.- Acting on peptide bonds (peptidases)", - "3.4.n.n Acting on peptide bonds (peptidases)", - "3.4.1.- alpha-Amino-acyl-peptide hydrolases", - "3.4.1.n alpha-Amino-acyl-peptide hydrolases", - "3.4.2.- Peptidyl-amino-acid hydrolases", - "3.4.2.n Peptidyl-amino-acid hydrolases", - "3.4.3.- Dipeptide hydrolases", - "3.4.3.n Dipeptide hydrolases", - "3.4.4.- Peptidyl peptide hydrolases", - "3.4.4.n Peptidyl peptide hydrolases", - "3.4.11.- Aminopeptidases", - "3.4.11.n Aminopeptidases", - "3.4.12.- Peptidylamino-acid hydrolases or acylamino-acid hydrolases", - "3.4.12.n Peptidylamino-acid hydrolases or acylamino-acid hydrolases", - "3.4.13.- Dipeptidases", - "3.4.13.n Dipeptidases", - "3.4.14.- Dipeptidyl-peptidases and tripeptidyl-peptidases", - "3.4.14.n Dipeptidyl-peptidases and tripeptidyl-peptidases", - "3.4.15.- Peptidyl-dipeptidases", - "3.4.15.n Peptidyl-dipeptidases", - "3.4.16.- Serine-type carboxypeptidases", - "3.4.16.n Serine-type carboxypeptidases", - "3.4.17.- Metallocarboxypeptidases", - "3.4.17.n Metallocarboxypeptidases", - "3.4.18.- Cysteine-type carboxypeptidases", - "3.4.18.n Cysteine-type carboxypeptidases", - "3.4.19.- Omega peptidases", - "3.4.19.n Omega peptidases", - "3.4.21.- Serine endopeptidases", - "3.4.21.n Serine endopeptidases", - "3.4.22.- Cysteine endopeptidases", - "3.4.22.n Cysteine endopeptidases", - "3.4.23.- Aspartic endopeptidases", - "3.4.23.n Aspartic endopeptidases", - "3.4.24.- Metalloendopeptidases", - "3.4.24.n Metalloendopeptidases", - "3.4.25.- Threonine endopeptidases", - "3.4.25.n Threonine endopeptidases", - "3.4.99.- Endopeptidases of unknown catalytic mechanism", - "3.4.99.n Endopeptidases of unknown catalytic mechanism", - "3.5.-.- Acting on carbon-nitrogen bonds, other than peptide bonds", - "3.5.n.n Acting on carbon-nitrogen bonds, other than peptide bonds", - "3.5.1.- In linear amides", - "3.5.1.n In linear amides", - "3.5.2.- In cyclic amides", - "3.5.2.n In cyclic amides", - "3.5.3.- In linear amidines", - "3.5.3.n In linear amidines", - "3.5.4.- In cyclic amidines", - "3.5.4.n In cyclic amidines", - "3.5.5.- In nitriles", - "3.5.5.n In nitriles", - "3.5.99.- In other compounds", - "3.5.99.n In other compounds", - "3.6.-.- Acting on acid anhydrides", - "3.6.n.n Acting on acid anhydrides", - "3.6.1.- In phosphorus-containing anhydrides", - "3.6.1.n In phosphorus-containing anhydrides", - "3.6.2.- In sulfonyl-containing anhydrides", - "3.6.2.n In sulfonyl-containing anhydrides", - "3.6.3.- Acting on acid anhydrides; catalyzing transmembrane movement of substances", - "3.6.3.n Acting on acid anhydrides; catalyzing transmembrane movement of substances", - "3.6.4.- Acting on ATP; involved in cellular and subcellular movement", - "3.6.4.n Acting on ATP; involved in cellular and subcellular movement", - "3.6.5.- Acting on GTP; involved in cellular and subcellular movement", - "3.6.5.n Acting on GTP; involved in cellular and subcellular movement", - "3.7.-.- Acting on carbon-carbon bonds", - "3.7.n.n Acting on carbon-carbon bonds", - "3.7.1.- In ketonic substances", - "3.7.1.n In ketonic substances", - "3.8.-.- Acting on halide bonds", - "3.8.n.n Acting on halide bonds", - "3.8.1.- In C-halide compounds", - "3.8.1.n In C-halide compounds", - "3.8.2.- In P-halide compounds", - "3.8.2.n In P-halide compounds", - "3.9.-.- Acting on phosphorus-nitrogen bonds", - "3.9.n.n Acting on phosphorus-nitrogen bonds", - "3.9.1.- Acting on phosphorus-nitrogen bonds", - "3.9.1.n Acting on phosphorus-nitrogen bonds", - "3.10.-.- Acting on sulfur-nitrogen bonds", - "3.10.n.n Acting on sulfur-nitrogen bonds", - "3.10.1.- Acting on sulfur-nitrogen bonds", - "3.10.1.n Acting on sulfur-nitrogen bonds", - "3.11.-.- Acting on carbon-phosphorus bonds", - "3.11.n.n Acting on carbon-phosphorus bonds", - "3.11.1.- Acting on carbon-phosphorus bonds", - "3.11.1.n Acting on carbon-phosphorus bonds", - "3.12.-.- Acting on sulfur-sulfur bonds", - "3.12.n.n Acting on sulfur-sulfur bonds", - "3.12.1.- Acting on sulfur-sulfur bonds", - "3.12.1.n Acting on sulfur-sulfur bonds", - "3.13.-.- Acting on carbon-sulfur bonds", - "3.13.n.n Acting on carbon-sulfur bonds", - "3.13.1.- Acting on carbon-sulfur bonds", - "3.13.1.n Acting on carbon-sulfur bonds", - "4.-.-.- Lyases", - "4.n.n.n Lyases", - "4.1.-.- Carbon-carbon lyases", - "4.1.n.n Carbon-carbon lyases", - "4.1.1.- Carboxy-lyases", - "4.1.1.n Carboxy-lyases", - "4.1.2.- Aldehyde-lyases", - "4.1.2.n Aldehyde-lyases", - "4.1.3.- Oxo-acid-lyases", - "4.1.3.n Oxo-acid-lyases", - "4.1.99.- Other carbon-carbon lyases", - "4.1.99.n Other carbon-carbon lyases", - "4.2.-.- Carbon-oxygen lyases", - "4.2.n.n Carbon-oxygen lyases", - "4.2.1.- Hydro-lyases", - "4.2.1.n Hydro-lyases", - "4.2.2.- Acting on polysaccharides", - "4.2.2.n Acting on polysaccharides", - "4.2.3.- Acting on phosphates", - "4.2.3.n Acting on phosphates", - "4.2.99.- Other carbon-oxygen lyases", - "4.2.99.n Other carbon-oxygen lyases", - "4.3.-.- Carbon-nitrogen lyases", - "4.3.n.n Carbon-nitrogen lyases", - "4.3.1.- Ammonia-lyases", - "4.3.1.n Ammonia-lyases", - "4.3.2.- Lyases acting on amides, amidines, etc", - "4.3.2.n Lyases acting on amides, amidines, etc", - "4.3.3.- Amine-lyases", - "4.3.3.n Amine-lyases", - "4.3.99.- Other carbon-nitrogen lyases", - "4.3.99.n Other carbon-nitrogen lyases", - "4.4.-.- Carbon-sulfur lyases", - "4.4.n.n Carbon-sulfur lyases", - "4.4.1.- Carbon-sulfur lyases", - "4.4.1.n Carbon-sulfur lyases", - "4.5.-.- Carbon-halide lyases", - "4.5.n.n Carbon-halide lyases", - "4.5.1.- Carbon-halide lyases", - "4.5.1.n Carbon-halide lyases", - "4.6.-.- Phosphorus-oxygen lyases", - "4.6.n.n Phosphorus-oxygen lyases", - "4.6.1.- Phosphorus-oxygen lyases", - "4.6.1.n Phosphorus-oxygen lyases", - "4.7.-.- Carbon-phosphorus lyases", - "4.7.n.n Carbon-phosphorus lyases", - "4.7.1.- Carbon-phosphorus lyases", - "4.7.1.n Carbon-phosphorus lyases", - "4.99.-.- Other lyases", - "4.99.n.n Other lyases", - "4.99.1.- Other lyases", - "4.99.1.n Other lyases", - "5.-.-.- Isomerases", - "5.n.n.n Isomerases", - "5.1.-.- Racemases and epimerases", - "5.1.n.n Racemases and epimerases", - "5.1.1.- Acting on amino acids and derivatives", - "5.1.1.n Acting on amino acids and derivatives", - "5.1.2.- Acting on hydroxy acids and derivatives", - "5.1.2.n Acting on hydroxy acids and derivatives", - "5.1.3.- Acting on carbohydrates and derivatives", - "5.1.3.n Acting on carbohydrates and derivatives", - "5.1.99.- Acting on other compounds", - "5.1.99.n Acting on other compounds", - "5.2.-.- Cis-trans-isomerases", - "5.2.n.n Cis-trans-isomerases", - "5.2.1.- Cis-trans isomerases", - "5.2.1.n Cis-trans isomerases", - "5.3.-.- Intramolecular oxidoreductases", - "5.3.n.n Intramolecular oxidoreductases", - "5.3.1.- Interconverting aldoses and ketoses", - "5.3.1.n Interconverting aldoses and ketoses", - "5.3.2.- Interconverting keto- and enol-groups", - "5.3.2.n Interconverting keto- and enol-groups", - "5.3.3.- Transposing C=C bonds", - "5.3.3.n Transposing C=C bonds", - "5.3.4.- Transposing S-S bonds", - "5.3.4.n Transposing S-S bonds", - "5.3.99.- Other intramolecular oxidoreductases", - "5.3.99.n Other intramolecular oxidoreductases", - "5.4.-.- Intramolecular transferases", - "5.4.n.n Intramolecular transferases", - "5.4.1.- Transferring acyl groups", - "5.4.1.n Transferring acyl groups", - "5.4.2.- Phosphotransferases (phosphomutases)", - "5.4.2.n Phosphotransferases (phosphomutases)", - "5.4.3.- Transferring amino groups", - "5.4.3.n Transferring amino groups", - "5.4.4.- Transferring hydroxy groups", - "5.4.4.n Transferring hydroxy groups", - "5.4.99.- Transferring other groups", - "5.4.99.n Transferring other groups", - "5.5.-.- Intramolecular lyases", - "5.5.n.n Intramolecular lyases", - "5.5.1.- Intramolecular lyases", - "5.5.1.n Intramolecular lyases", - "5.99.-.- Other isomerases", - "5.99.n.n Other isomerases", - "5.99.1.- Other isomerases", - "5.99.1.n Other isomerases", - "6.-.-.- Ligases", - "6.n.n.n Ligases", - "6.1.-.- Forming carbon-oxygen bonds", - "6.1.n.n Forming carbon-oxygen bonds", - "6.1.1.- Ligases forming aminoacyl-tRNA and related compounds", - "6.1.1.n Ligases forming aminoacyl-tRNA and related compounds", - "6.1.2.- Acid--alcohol ligases (ester synthases)", - "6.1.2.n Acid--alcohol ligases (ester synthases)", - "6.2.-.- Forming carbon-sulfur bonds", - "6.2.n.n Forming carbon-sulfur bonds", - "6.2.1.- Acid--thiol ligases", - "6.2.1.n Acid--thiol ligases", - "6.3.-.- Forming carbon-nitrogen bonds", - "6.3.n.n Forming carbon-nitrogen bonds", - "6.3.1.- Acid--ammonia (or amine) ligases (amide synthases)", - "6.3.1.n Acid--ammonia (or amine) ligases (amide synthases)", - "6.3.2.- Acid--amino-acid ligases (peptide synthases)", - "6.3.2.n Acid--amino-acid ligases (peptide synthases)", - "6.3.3.- Cyclo-ligases", - "6.3.3.n Cyclo-ligases", - "6.3.4.- Other carbon--nitrogen ligases", - "6.3.4.n Other carbon--nitrogen ligases", - "6.3.5.- Carbon--nitrogen ligases with glutamine as amido-N-donor", - "6.3.5.n Carbon--nitrogen ligases with glutamine as amido-N-donor", - "6.4.-.- Forming carbon-carbon bonds", - "6.4.n.n Forming carbon-carbon bonds", - "6.4.1.- Forming carbon-carbon bonds", - "6.4.1.n Forming carbon-carbon bonds", - "6.5.-.- Forming phosphoric ester bonds", - "6.5.n.n Forming phosphoric ester bonds", - "6.5.1.- Forming phosphoric ester bonds", - "6.5.1.n Forming phosphoric ester bonds", - "6.6.-.- Forming nitrogen-metal bonds", - "6.6.n.n Forming nitrogen-metal bonds", - "6.6.1.- Forming coordination complexes", - "6.6.1.n Forming coordination complexes" + "1.-.-.-\tOxidoreductases", + "1.n.n.n\tOxidoreductases", + "1.1.-.-\tActing on the CH-OH group of donors", + "1.1.n.n\tActing on the CH-OH group of donors", + "1.1.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.1.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.1.2.-\tWith a cytochrome as acceptor", + "1.1.2.n\tWith a cytochrome as acceptor", + "1.1.3.-\tWith oxygen as acceptor", + "1.1.3.n\tWith oxygen as acceptor", + "1.1.4.-\tWith a disulfide as acceptor", + "1.1.4.n\tWith a disulfide as acceptor", + "1.1.5.-\tWith a quinone or similar compound as acceptor", + "1.1.5.n\tWith a quinone or similar compound as acceptor", + "1.1.9.-\tWith a copper protein as acceptor", + "1.1.9.n\tWith a copper protein as acceptor", + "1.1.98.-\tWith other, known, acceptors", + "1.1.98.n\tWith other, known, acceptors", + "1.1.99.-\tWith other acceptors", + "1.1.99.n\tWith other acceptors", + "1.2.-.-\tActing on the aldehyde or oxo group of donors", + "1.2.n.n\tActing on the aldehyde or oxo group of donors", + "1.2.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.2.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.2.2.-\tWith a cytochrome as acceptor", + "1.2.2.n\tWith a cytochrome as acceptor", + "1.2.3.-\tWith oxygen as acceptor", + "1.2.3.n\tWith oxygen as acceptor", + "1.2.4.-\tWith a disulfide as acceptor", + "1.2.4.n\tWith a disulfide as acceptor", + "1.2.5.-\tWith a quinone or similar compound as acceptor", + "1.2.5.n\tWith a quinone or similar compound as acceptor", + "1.2.7.-\tWith an iron-sulfur protein as acceptor", + "1.2.7.n\tWith an iron-sulfur protein as acceptor", + "1.2.98.-\tWith other, known, acceptors", + "1.2.98.n\tWith other, known, acceptors", + "1.2.99.-\tWith other acceptors", + "1.2.99.n\tWith other acceptors", + "1.3.-.-\tActing on the CH-CH group of donors", + "1.3.n.n\tActing on the CH-CH group of donors", + "1.3.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.3.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.3.2.-\tWith a cytochrome as acceptor", + "1.3.2.n\tWith a cytochrome as acceptor", + "1.3.3.-\tWith oxygen as acceptor", + "1.3.3.n\tWith oxygen as acceptor", + "1.3.4.-\tWith a disulfide as acceptor", + "1.3.4.n\tWith a disulfide as acceptor", + "1.3.5.-\tWith a quinone or related compound as acceptor", + "1.3.5.n\tWith a quinone or related compound as acceptor", + "1.3.7.-\tWith an iron-sulfur protein as acceptor", + "1.3.7.n\tWith an iron-sulfur protein as acceptor", + "1.3.8.-\tWith a flavin as acceptor", + "1.3.8.n\tWith a flavin as acceptor", + "1.3.98.-\tWith other, known, acceptors", + "1.3.98.n\tWith other, known, acceptors", + "1.3.99.-\tWith other acceptors", + "1.3.99.n\tWith other acceptors", + "1.4.-.-\tActing on the CH-NH(2) group of donors", + "1.4.n.n\tActing on the CH-NH(2) group of donors", + "1.4.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.4.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.4.2.-\tWith a cytochrome as acceptor", + "1.4.2.n\tWith a cytochrome as acceptor", + "1.4.3.-\tWith oxygen as acceptor", + "1.4.3.n\tWith oxygen as acceptor", + "1.4.4.-\tWith a disulfide as acceptor", + "1.4.4.n\tWith a disulfide as acceptor", + "1.4.5.-\tWith a quinone or similar compound as acceptor", + "1.4.5.n\tWith a quinone or similar compound as acceptor", + "1.4.7.-\tWith an iron-sulfur protein as acceptor", + "1.4.7.n\tWith an iron-sulfur protein as acceptor", + "1.4.9.-\tWith a copper protein as acceptor", + "1.4.9.n\tWith a copper protein as acceptor", + "1.4.98.-\tWith other, known, acceptors", + "1.4.98.n\tWith other, known, acceptors", + "1.4.99.-\tWith other acceptors", + "1.4.99.n\tWith other acceptors", + "1.5.-.-\tActing on the CH-NH group of donors", + "1.5.n.n\tActing on the CH-NH group of donors", + "1.5.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.5.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.5.3.-\tWith oxygen as acceptor", + "1.5.3.n\tWith oxygen as acceptor", + "1.5.4.-\tWith a disulfide as acceptor", + "1.5.4.n\tWith a disulfide as acceptor", + "1.5.5.-\tWith a quinone or similar compound as acceptor", + "1.5.5.n\tWith a quinone or similar compound as acceptor", + "1.5.7.-\tWith an iron-sulfur protein as acceptor", + "1.5.7.n\tWith an iron-sulfur protein as acceptor", + "1.5.8.-\tWith a flavin as acceptor", + "1.5.8.n\tWith a flavin as acceptor", + "1.5.98.-\tWith other, known, acceptors", + "1.5.98.n\tWith other, known, acceptors", + "1.5.99.-\tWith other acceptors", + "1.5.99.n\tWith other acceptors", + "1.6.-.-\tActing on NADH or NADPH", + "1.6.n.n\tActing on NADH or NADPH", + "1.6.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.6.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.6.2.-\tWith a heme protein as acceptor", + "1.6.2.n\tWith a heme protein as acceptor", + "1.6.3.-\tWith oxygen as acceptor", + "1.6.3.n\tWith oxygen as acceptor", + "1.6.4.-\tWith a disulfide as acceptor", + "1.6.4.n\tWith a disulfide as acceptor", + "1.6.5.-\tWith a quinone or similar compound as acceptor", + "1.6.5.n\tWith a quinone or similar compound as acceptor", + "1.6.6.-\tWith a nitrogenous group as acceptor", + "1.6.6.n\tWith a nitrogenous group as acceptor", + "1.6.7.-\tWith a iron-sulfur protein as acceptor", + "1.6.7.n\tWith a iron-sulfur protein as acceptor", + "1.6.8.-\tWith a flavin as acceptor", + "1.6.8.n\tWith a flavin as acceptor", + "1.6.99.-\tWith other acceptors", + "1.6.99.n\tWith other acceptors", + "1.7.-.-\tActing on other nitrogenous compounds as donors", + "1.7.n.n\tActing on other nitrogenous compounds as donors", + "1.7.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.7.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.7.2.-\tWith a cytochrome as acceptor", + "1.7.2.n\tWith a cytochrome as acceptor", + "1.7.3.-\tWith oxygen as acceptor", + "1.7.3.n\tWith oxygen as acceptor", + "1.7.5.-\tWith a quinone or similar compound as acceptor", + "1.7.5.n\tWith a quinone or similar compound as acceptor", + "1.7.6.-\tWith a nitrogenous group as acceptor", + "1.7.6.n\tWith a nitrogenous group as acceptor", + "1.7.7.-\tWith an iron-sulfur protein as acceptor", + "1.7.7.n\tWith an iron-sulfur protein as acceptor", + "1.7.9.-\tWith a copper protein as acceptor", + "1.7.9.n\tWith a copper protein as acceptor", + "1.7.99.-\tWith other acceptors", + "1.7.99.n\tWith other acceptors", + "1.8.-.-\tActing on a sulfur group of donors", + "1.8.n.n\tActing on a sulfur group of donors", + "1.8.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.8.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.8.2.-\tWith a cytochrome as acceptor", + "1.8.2.n\tWith a cytochrome as acceptor", + "1.8.3.-\tWith oxygen as acceptor", + "1.8.3.n\tWith oxygen as acceptor", + "1.8.4.-\tWith a disulfide as acceptor", + "1.8.4.n\tWith a disulfide as acceptor", + "1.8.5.-\tWith a quinone or similar compound as acceptor", + "1.8.5.n\tWith a quinone or similar compound as acceptor", + "1.8.6.-\tWith an nitrogenous group as acceptor", + "1.8.6.n\tWith an nitrogenous group as acceptor", + "1.8.7.-\tWith an iron-sulfur protein as acceptor", + "1.8.7.n\tWith an iron-sulfur protein as acceptor", + "1.8.98.-\tWith other, known, acceptors", + "1.8.98.n\tWith other, known, acceptors", + "1.8.99.-\tWith other acceptors", + "1.8.99.n\tWith other acceptors", + "1.9.-.-\tActing on a heme group of donors", + "1.9.n.n\tActing on a heme group of donors", + "1.9.3.-\tWith oxygen as acceptor", + "1.9.3.n\tWith oxygen as acceptor", + "1.9.6.-\tWith a nitrogenous group as acceptor", + "1.9.6.n\tWith a nitrogenous group as acceptor", + "1.9.98.-\tWith other, known, acceptors", + "1.9.98.n\tWith other, known, acceptors", + "1.9.99.-\tWith other acceptors", + "1.9.99.n\tWith other acceptors", + "1.10.-.-\tActing on diphenols and related substances as donors", + "1.10.n.n\tActing on diphenols and related substances as donors", + "1.10.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.10.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.10.2.-\tWith a cytochrome as acceptor", + "1.10.2.n\tWith a cytochrome as acceptor", + "1.10.3.-\tWith oxygen as acceptor", + "1.10.3.n\tWith oxygen as acceptor", + "1.10.5.-\tWith a quinone or related compound as acceptor", + "1.10.5.n\tWith a quinone or related compound as acceptor", + "1.10.9.-\tWith a copper protein as acceptor", + "1.10.9.n\tWith a copper protein as acceptor", + "1.10.98.-\tWith other, known, acceptors", + "1.10.98.n\tWith other, known, acceptors", + "1.10.99.-\tWith other acceptors", + "1.10.99.n\tWith other acceptors", + "1.11.-.-\tActing on a peroxide as acceptor", + "1.11.n.n\tActing on a peroxide as acceptor", + "1.11.1.-\tPeroxidases", + "1.11.1.n\tPeroxidases", + "1.11.2.-\tWith H(2)O(2) as acceptor, one oxygen atom of which is incorporated into the product", + "1.11.2.n\tWith H(2)O(2) as acceptor, one oxygen atom of which is incorporated into the product", + "1.12.-.-\tActing on hydrogen as donors", + "1.12.n.n\tActing on hydrogen as donors", + "1.12.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.12.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.12.2.-\tWith a cytochrome as acceptor", + "1.12.2.n\tWith a cytochrome as acceptor", + "1.12.5.-\tWith a quinone or similar compound as acceptor", + "1.12.5.n\tWith a quinone or similar compound as acceptor", + "1.12.7.-\tWith an iron-sulfur protein as acceptor", + "1.12.7.n\tWith an iron-sulfur protein as acceptor", + "1.12.98.-\tWith other, known, acceptors", + "1.12.98.n\tWith other, known, acceptors", + "1.12.99.-\tWith other acceptors", + "1.12.99.n\tWith other acceptors", + "1.13.-.-\tActing on single donors with incorporation of molecular oxygen (oxygenases). The oxygen incorporated need not be derived from O(2)", + "1.13.n.n\tActing on single donors with incorporation of molecular oxygen (oxygenases). The oxygen incorporated need not be derived from O(2)", + "1.13.1.-\tWith NADH or NADPH as one donor", + "1.13.1.n\tWith NADH or NADPH as one donor", + "1.13.11.-\tWith incorporation of two atoms of oxygen", + "1.13.11.n\tWith incorporation of two atoms of oxygen", + "1.13.12.-\tWith incorporation of one atom of oxygen (internal monooxygenases or internal mixed function oxidases)", + "1.13.12.n\tWith incorporation of one atom of oxygen (internal monooxygenases or internal mixed function oxidases)", + "1.13.99.-\tMiscellaneous", + "1.13.99.n\tMiscellaneous", + "1.14.-.-\tActing on paired donors, with incorporation or reduction of molecular oxygen. The oxygen incorporated need not be derived from O(2)", + "1.14.n.n\tActing on paired donors, with incorporation or reduction of molecular oxygen. The oxygen incorporated need not be derived from O(2)", + "1.14.1.-\tWith NADH or NADPH as one donor", + "1.14.1.n\tWith NADH or NADPH as one donor", + "1.14.2.-\tWith ascorbate as one donor", + "1.14.2.n\tWith ascorbate as one donor", + "1.14.3.-\tWith reduced pteridine as one donor", + "1.14.3.n\tWith reduced pteridine as one donor", + "1.14.11.-\tWith 2-oxoglutarate as one donor, and incorporation of one atom each of oxygen into both donors", + "1.14.11.n\tWith 2-oxoglutarate as one donor, and incorporation of one atom each of oxygen into both donors", + "1.14.12.-\tWith NADH or NADPH as one donor, and incorporation of two atoms of oxygen into one donor", + "1.14.12.n\tWith NADH or NADPH as one donor, and incorporation of two atoms of oxygen into one donor", + "1.14.13.-\tWith NADH or NADPH as one donor, and incorporation of one atom of oxygen", + "1.14.13.n\tWith NADH or NADPH as one donor, and incorporation of one atom of oxygen", + "1.14.14.-\tWith reduced flavin or flavoprotein as one donor, and incorporation of one atom of oxygen", + "1.14.14.n\tWith reduced flavin or flavoprotein as one donor, and incorporation of one atom of oxygen", + "1.14.15.-\tWith reduced iron-sulfur protein as one donor, and incorporation of one atom of oxygen", + "1.14.15.n\tWith reduced iron-sulfur protein as one donor, and incorporation of one atom of oxygen", + "1.14.16.-\tWith reduced pteridine as one donor, and incorporation of one atom of oxygen", + "1.14.16.n\tWith reduced pteridine as one donor, and incorporation of one atom of oxygen", + "1.14.17.-\tWith reduced ascorbate as one donor, and incorporation of one atom of oxygen", + "1.14.17.n\tWith reduced ascorbate as one donor, and incorporation of one atom of oxygen", + "1.14.18.-\tWith another compound as one donor, and incorporation of one atom of oxygen", + "1.14.18.n\tWith another compound as one donor, and incorporation of one atom of oxygen", + "1.14.19.-\tWith oxidation of a pair of donors resulting in the reduction of molecular oxygen to two molecules of water", + "1.14.19.n\tWith oxidation of a pair of donors resulting in the reduction of molecular oxygen to two molecules of water", + "1.14.20.-\tWith 2-oxoglutarate as one donor, and the other dehydrogenated", + "1.14.20.n\tWith 2-oxoglutarate as one donor, and the other dehydrogenated", + "1.14.21.-\tWith NADH or NADPH as one donor, and the other dehydrogenated", + "1.14.21.n\tWith NADH or NADPH as one donor, and the other dehydrogenated", + "1.14.99.-\tMiscellaneous", + "1.14.99.n\tMiscellaneous", + "1.15.-.-\tActing on superoxide as acceptor", + "1.15.n.n\tActing on superoxide as acceptor", + "1.15.1.-\tActing on superoxide as acceptor", + "1.15.1.n\tActing on superoxide as acceptor", + "1.16.-.-\tOxidizing metal ions", + "1.16.n.n\tOxidizing metal ions", + "1.16.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.16.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.16.3.-\tWith oxygen as acceptor", + "1.16.3.n\tWith oxygen as acceptor", + "1.16.5.-\tWith a quinone or similar compound as acceptor", + "1.16.5.n\tWith a quinone or similar compound as acceptor", + "1.16.8.-\tWith a flavin as acceptor", + "1.16.8.n\tWith a flavin as acceptor", + "1.16.9.-\tWith a copper protein as acceptor", + "1.16.9.n\tWith a copper protein as acceptor", + "1.16.98.-\tWith other known acceptors", + "1.16.98.n\tWith other known acceptors", + "1.17.-.-\tActing on CH or CH(2) groups", + "1.17.n.n\tActing on CH or CH(2) groups", + "1.17.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.17.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.17.2.-\tWith a cytochrome as acceptor", + "1.17.2.n\tWith a cytochrome as acceptor", + "1.17.3.-\tWith oxygen as acceptor", + "1.17.3.n\tWith oxygen as acceptor", + "1.17.4.-\tWith a disulfide as acceptor", + "1.17.4.n\tWith a disulfide as acceptor", + "1.17.5.-\tWith a quinone or similar compound as acceptor", + "1.17.5.n\tWith a quinone or similar compound as acceptor", + "1.17.7.-\tWith an iron-sulfur protein as acceptor", + "1.17.7.n\tWith an iron-sulfur protein as acceptor", + "1.17.8.-\tWith a flavin as acceptor", + "1.17.8.n\tWith a flavin as acceptor", + "1.17.98.-\tWith other, known, acceptors", + "1.17.98.n\tWith other, known, acceptors", + "1.17.99.-\tWith other acceptors", + "1.17.99.n\tWith other acceptors", + "1.18.-.-\tActing on iron-sulfur proteins as donors", + "1.18.n.n\tActing on iron-sulfur proteins as donors", + "1.18.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.18.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.18.2.-\tWith dinitrogen as acceptor", + "1.18.2.n\tWith dinitrogen as acceptor", + "1.18.3.-\tWith H(+) as acceptor", + "1.18.3.n\tWith H(+) as acceptor", + "1.18.6.-\tWith dinitrogen as acceptor", + "1.18.6.n\tWith dinitrogen as acceptor", + "1.18.96.-\tWith other, known, acceptors", + "1.18.96.n\tWith other, known, acceptors", + "1.18.99.-\tWith H(+) as acceptor", + "1.18.99.n\tWith H(+) as acceptor", + "1.19.-.-\tActing on reduced flavodoxin as donor", + "1.19.n.n\tActing on reduced flavodoxin as donor", + "1.19.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.19.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.19.6.-\tWith dinitrogen as acceptor", + "1.19.6.n\tWith dinitrogen as acceptor", + "1.20.-.-\tActing on phosphorus or arsenic in donors", + "1.20.n.n\tActing on phosphorus or arsenic in donors", + "1.20.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.20.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.20.2.-\tWith a cytochrome as acceptor", + "1.20.2.n\tWith a cytochrome as acceptor", + "1.20.4.-\tWith disulfide as acceptor", + "1.20.4.n\tWith disulfide as acceptor", + "1.20.9.-\tWith a copper protein as acceptor", + "1.20.9.n\tWith a copper protein as acceptor", + "1.20.98.-\tWith other, known acceptors", + "1.20.98.n\tWith other, known acceptors", + "1.20.99.-\tWith other acceptors", + "1.20.99.n\tWith other acceptors", + "1.21.-.-\tCatalyzing the reaction X-H + Y-H = 'X-Y'", + "1.21.n.n\tCatalyzing the reaction X-H + Y-H = 'X-Y'", + "1.21.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.21.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.21.3.-\tWith oxygen as acceptor", + "1.21.3.n\tWith oxygen as acceptor", + "1.21.4.-\tWith a disulfide as acceptor", + "1.21.4.n\tWith a disulfide as acceptor", + "1.21.98.-\tWith other, known acceptors", + "1.21.98.n\tWith other, known acceptors", + "1.21.99.-\tWith other acceptors", + "1.21.99.n\tWith other acceptors", + "1.22.-.-\tActing on halogen in donors", + "1.22.n.n\tActing on halogen in donors", + "1.22.1.-\tWith NAD(+) or NADP(+) as acceptor", + "1.22.1.n\tWith NAD(+) or NADP(+) as acceptor", + "1.23.-.-\tReducing C-O-C group as acceptor", + "1.23.n.n\tReducing C-O-C group as acceptor", + "1.23.1.-\tWith NADH or NADPH as donor", + "1.23.1.n\tWith NADH or NADPH as donor", + "1.23.5.-\tWith a quinone or similar compound as acceptor", + "1.23.5.n\tWith a quinone or similar compound as acceptor", + "1.97.-.-\tOther oxidoreductases", + "1.97.n.n\tOther oxidoreductases", + "1.97.1.-\tOther oxidoreductases", + "1.97.1.n\tOther oxidoreductases", + "1.98.-.-\tEnzymes using H(2) as reductant", + "1.98.n.n\tEnzymes using H(2) as reductant", + "1.98.1.-\tOther oxidoreductases", + "1.98.1.n\tOther oxidoreductases", + "1.99.-.-\tOther enzymes using O(2) as oxidant", + "1.99.n.n\tOther enzymes using O(2) as oxidant", + "1.99.1.-\tHydroxylases", + "1.99.1.n\tHydroxylases", + "1.99.2.-\tOxygenases", + "1.99.2.n\tOxygenases", + "2.-.-.-\tTransferases", + "2.n.n.n\tTransferases", + "2.1.-.-\tTransferring one-carbon groups", + "2.1.n.n\tTransferring one-carbon groups", + "2.1.1.-\tMethyltransferases", + "2.1.1.n\tMethyltransferases", + "2.1.2.-\tHydroxymethyl-, formyl- and related transferases", + "2.1.2.n\tHydroxymethyl-, formyl- and related transferases", + "2.1.3.-\tCarboxy- and carbamoyltransferases", + "2.1.3.n\tCarboxy- and carbamoyltransferases", + "2.1.4.-\tAmidinotransferases", + "2.1.4.n\tAmidinotransferases", + "2.1.5.-\tMethylenetransferases", + "2.1.5.n\tMethylenetransferases", + "2.2.-.-\tTransferring aldehyde or ketonic groups", + "2.2.n.n\tTransferring aldehyde or ketonic groups", + "2.2.1.-\tTransketolases and transaldolases", + "2.2.1.n\tTransketolases and transaldolases", + "2.3.-.-\tAcyltransferases", + "2.3.n.n\tAcyltransferases", + "2.3.1.-\tTransferring groups other than amino-acyl groups", + "2.3.1.n\tTransferring groups other than amino-acyl groups", + "2.3.2.-\tAminoacyltransferases", + "2.3.2.n\tAminoacyltransferases", + "2.3.3.-\tAcyl groups converted into alkyl groups on transfer", + "2.3.3.n\tAcyl groups converted into alkyl groups on transfer", + "2.4.-.-\tGlycosyltransferases", + "2.4.n.n\tGlycosyltransferases", + "2.4.1.-\tHexosyltransferases", + "2.4.1.n\tHexosyltransferases", + "2.4.2.-\tPentosyltransferases", + "2.4.2.n\tPentosyltransferases", + "2.4.99.-\tTransferring other glycosyl groups", + "2.4.99.n\tTransferring other glycosyl groups", + "2.5.-.-\tTransferring alkyl or aryl groups, other than methyl groups", + "2.5.n.n\tTransferring alkyl or aryl groups, other than methyl groups", + "2.5.1.-\tTransferring alkyl or aryl groups, other than methyl groups", + "2.5.1.n\tTransferring alkyl or aryl groups, other than methyl groups", + "2.6.-.-\tTransferring nitrogenous groups", + "2.6.n.n\tTransferring nitrogenous groups", + "2.6.1.-\tTransaminases", + "2.6.1.n\tTransaminases", + "2.6.2.-\tAmidinotransferases", + "2.6.2.n\tAmidinotransferases", + "2.6.3.-\tOximinotransferases", + "2.6.3.n\tOximinotransferases", + "2.6.99.-\tTransferring other nitrogenous groups", + "2.6.99.n\tTransferring other nitrogenous groups", + "2.7.-.-\tTransferring phosphorus-containing groups", + "2.7.n.n\tTransferring phosphorus-containing groups", + "2.7.1.-\tPhosphotransferases with an alcohol group as acceptor", + "2.7.1.n\tPhosphotransferases with an alcohol group as acceptor", + "2.7.2.-\tPhosphotransferases with a carboxy group as acceptor", + "2.7.2.n\tPhosphotransferases with a carboxy group as acceptor", + "2.7.3.-\tPhosphotransferases with a nitrogenous group as acceptor", + "2.7.3.n\tPhosphotransferases with a nitrogenous group as acceptor", + "2.7.4.-\tPhosphotransferases with a phosphate group as acceptor", + "2.7.4.n\tPhosphotransferases with a phosphate group as acceptor", + "2.7.5.-\tPhosphotransferases with regeneration of donors, apparently catalyzing intramolecular transfers", + "2.7.5.n\tPhosphotransferases with regeneration of donors, apparently catalyzing intramolecular transfers", + "2.7.6.-\tDiphosphotransferases", + "2.7.6.n\tDiphosphotransferases", + "2.7.7.-\tNucleotidyltransferases", + "2.7.7.n\tNucleotidyltransferases", + "2.7.8.-\tTransferases for other substituted phosphate groups", + "2.7.8.n\tTransferases for other substituted phosphate groups", + "2.7.9.-\tPhosphotransferases with paired acceptors", + "2.7.9.n\tPhosphotransferases with paired acceptors", + "2.7.10.-\tProtein-tyrosine kinases", + "2.7.10.n\tProtein-tyrosine kinases", + "2.7.11.-\tProtein-serine/threonine kinases", + "2.7.11.n\tProtein-serine/threonine kinases", + "2.7.12.-\tDual-specificity kinases (those acting on Ser/Thr and Tyr residues)", + "2.7.12.n\tDual-specificity kinases (those acting on Ser/Thr and Tyr residues)", + "2.7.13.-\tProtein-histidine kinases", + "2.7.13.n\tProtein-histidine kinases", + "2.7.14.-\tProtein-arginine kinases", + "2.7.14.n\tProtein-arginine kinases", + "2.7.99.-\tOther protein kinases", + "2.7.99.n\tOther protein kinases", + "2.8.-.-\tTransferring sulfur-containing groups", + "2.8.n.n\tTransferring sulfur-containing groups", + "2.8.1.-\tSulfurtransferases", + "2.8.1.n\tSulfurtransferases", + "2.8.2.-\tSulfotransferases", + "2.8.2.n\tSulfotransferases", + "2.8.3.-\tCoA-transferases", + "2.8.3.n\tCoA-transferases", + "2.8.4.-\tTransferring alkylthio groups", + "2.8.4.n\tTransferring alkylthio groups", + "2.9.-.-\tTransferring selenium-containing groups", + "2.9.n.n\tTransferring selenium-containing groups", + "2.9.1.-\tSelenotransferases", + "2.9.1.n\tSelenotransferases", + "2.10.-.-\tTransferring molybdenum- or tungsten-containing groups", + "2.10.n.n\tTransferring molybdenum- or tungsten-containing groups", + "2.10.1.-\tMolybdenumtransferases or tungstentransferases with sulfide groups as acceptors", + "2.10.1.n\tMolybdenumtransferases or tungstentransferases with sulfide groups as acceptors", + "3.-.-.-\tHydrolases", + "3.n.n.n\tHydrolases", + "3.1.-.-\tActing on ester bonds", + "3.1.n.n\tActing on ester bonds", + "3.1.1.-\tCarboxylic ester hydrolases", + "3.1.1.n\tCarboxylic ester hydrolases", + "3.1.2.-\tThiolester hydrolases", + "3.1.2.n\tThiolester hydrolases", + "3.1.3.-\tPhosphoric monoester hydrolases", + "3.1.3.n\tPhosphoric monoester hydrolases", + "3.1.4.-\tPhosphoric diester hydrolases", + "3.1.4.n\tPhosphoric diester hydrolases", + "3.1.5.-\tTriphosphoric monoester hydrolases", + "3.1.5.n\tTriphosphoric monoester hydrolases", + "3.1.6.-\tSulfuric ester hydrolases", + "3.1.6.n\tSulfuric ester hydrolases", + "3.1.7.-\tDiphosphoric monoester hydrolases", + "3.1.7.n\tDiphosphoric monoester hydrolases", + "3.1.8.-\tPhosphoric triester hydrolases", + "3.1.8.n\tPhosphoric triester hydrolases", + "3.1.11.-\tExodeoxyribonucleases producing 5'-phosphomonoesters", + "3.1.11.n\tExodeoxyribonucleases producing 5'-phosphomonoesters", + "3.1.12.-\tExodeoxyribonucleases producing 3'-phosphomonoesters", + "3.1.12.n\tExodeoxyribonucleases producing 3'-phosphomonoesters", + "3.1.13.-\tExoribonucleases producing 5'-phosphomonoesters", + "3.1.13.n\tExoribonucleases producing 5'-phosphomonoesters", + "3.1.14.-\tExoribonucleases producing 3'-phosphomonoesters", + "3.1.14.n\tExoribonucleases producing 3'-phosphomonoesters", + "3.1.15.-\tExonucleases active with either ribo- or deoxyribonucleic acids and producing 5'-phosphomonoesters", + "3.1.15.n\tExonucleases active with either ribo- or deoxyribonucleic acids and producing 5'-phosphomonoesters", + "3.1.16.-\tExonucleases active with either ribo- or deoxyribonucleic acids and producing 3'-phosphomonoesters", + "3.1.16.n\tExonucleases active with either ribo- or deoxyribonucleic acids and producing 3'-phosphomonoesters", + "3.1.21.-\tEndodeoxyribonucleases producing 5'-phosphomonoesters", + "3.1.21.n\tEndodeoxyribonucleases producing 5'-phosphomonoesters", + "3.1.22.-\tEndodeoxyribonucleases producing other than 5'-phosphomonoesters", + "3.1.22.n\tEndodeoxyribonucleases producing other than 5'-phosphomonoesters", + "3.1.23.-\tSite specific endodeoxyribonucleases: cleavage is sequence specific", + "3.1.23.n\tSite specific endodeoxyribonucleases: cleavage is sequence specific", + "3.1.24.-\tSite specific endodeoxyribonucleases: cleavage is not sequence specific", + "3.1.24.n\tSite specific endodeoxyribonucleases: cleavage is not sequence specific", + "3.1.25.-\tSite-specific endodeoxyribonucleases specific for altered bases", + "3.1.25.n\tSite-specific endodeoxyribonucleases specific for altered bases", + "3.1.26.-\tEndoribonucleases producing 5'-phosphomonoesters", + "3.1.26.n\tEndoribonucleases producing 5'-phosphomonoesters", + "3.1.27.-\tEndoribonucleases producing other than 5'-phosphomonoesters", + "3.1.27.n\tEndoribonucleases producing other than 5'-phosphomonoesters", + "3.1.30.-\tEndoribonucleases active with either ribo- or deoxyribonucleic acids and producing 5'-phosphomonoesters", + "3.1.30.n\tEndoribonucleases active with either ribo- or deoxyribonucleic acids and producing 5'-phosphomonoesters", + "3.1.31.-\tEndoribonucleases active with either ribo- or deoxyribonucleic acids and producing 3'-phosphomonoesters", + "3.1.31.n\tEndoribonucleases active with either ribo- or deoxyribonucleic acids and producing 3'-phosphomonoesters", + "3.2.-.-\tGlycosylases", + "3.2.n.n\tGlycosylases", + "3.2.1.-\tGlycosidases, i.e. enzymes hydrolyzing O- and S-glycosyl compounds", + "3.2.1.n\tGlycosidases, i.e. enzymes hydrolyzing O- and S-glycosyl compounds", + "3.2.2.-\tHydrolyzing N-glycosyl compounds", + "3.2.2.n\tHydrolyzing N-glycosyl compounds", + "3.2.3.-\tHydrolyzing S-glycosyl compounds", + "3.2.3.n\tHydrolyzing S-glycosyl compounds", + "3.3.-.-\tActing on ether bonds", + "3.3.n.n\tActing on ether bonds", + "3.3.1.-\tThioether and trialkylsulfonium hydrolases", + "3.3.1.n\tThioether and trialkylsulfonium hydrolases", + "3.3.2.-\tEther hydrolases", + "3.3.2.n\tEther hydrolases", + "3.4.-.-\tActing on peptide bonds (peptidases)", + "3.4.n.n\tActing on peptide bonds (peptidases)", + "3.4.1.-\talpha-Amino-acyl-peptide hydrolases", + "3.4.1.n\talpha-Amino-acyl-peptide hydrolases", + "3.4.2.-\tPeptidyl-amino-acid hydrolases", + "3.4.2.n\tPeptidyl-amino-acid hydrolases", + "3.4.3.-\tDipeptide hydrolases", + "3.4.3.n\tDipeptide hydrolases", + "3.4.4.-\tPeptidyl peptide hydrolases", + "3.4.4.n\tPeptidyl peptide hydrolases", + "3.4.11.-\tAminopeptidases", + "3.4.11.n\tAminopeptidases", + "3.4.12.-\tPeptidylamino-acid hydrolases or acylamino-acid hydrolases", + "3.4.12.n\tPeptidylamino-acid hydrolases or acylamino-acid hydrolases", + "3.4.13.-\tDipeptidases", + "3.4.13.n\tDipeptidases", + "3.4.14.-\tDipeptidyl-peptidases and tripeptidyl-peptidases", + "3.4.14.n\tDipeptidyl-peptidases and tripeptidyl-peptidases", + "3.4.15.-\tPeptidyl-dipeptidases", + "3.4.15.n\tPeptidyl-dipeptidases", + "3.4.16.-\tSerine-type carboxypeptidases", + "3.4.16.n\tSerine-type carboxypeptidases", + "3.4.17.-\tMetallocarboxypeptidases", + "3.4.17.n\tMetallocarboxypeptidases", + "3.4.18.-\tCysteine-type carboxypeptidases", + "3.4.18.n\tCysteine-type carboxypeptidases", + "3.4.19.-\tOmega peptidases", + "3.4.19.n\tOmega peptidases", + "3.4.21.-\tSerine endopeptidases", + "3.4.21.n\tSerine endopeptidases", + "3.4.22.-\tCysteine endopeptidases", + "3.4.22.n\tCysteine endopeptidases", + "3.4.23.-\tAspartic endopeptidases", + "3.4.23.n\tAspartic endopeptidases", + "3.4.24.-\tMetalloendopeptidases", + "3.4.24.n\tMetalloendopeptidases", + "3.4.25.-\tThreonine endopeptidases", + "3.4.25.n\tThreonine endopeptidases", + "3.4.99.-\tEndopeptidases of unknown catalytic mechanism", + "3.4.99.n\tEndopeptidases of unknown catalytic mechanism", + "3.5.-.-\tActing on carbon-nitrogen bonds, other than peptide bonds", + "3.5.n.n\tActing on carbon-nitrogen bonds, other than peptide bonds", + "3.5.1.-\tIn linear amides", + "3.5.1.n\tIn linear amides", + "3.5.2.-\tIn cyclic amides", + "3.5.2.n\tIn cyclic amides", + "3.5.3.-\tIn linear amidines", + "3.5.3.n\tIn linear amidines", + "3.5.4.-\tIn cyclic amidines", + "3.5.4.n\tIn cyclic amidines", + "3.5.5.-\tIn nitriles", + "3.5.5.n\tIn nitriles", + "3.5.99.-\tIn other compounds", + "3.5.99.n\tIn other compounds", + "3.6.-.-\tActing on acid anhydrides", + "3.6.n.n\tActing on acid anhydrides", + "3.6.1.-\tIn phosphorus-containing anhydrides", + "3.6.1.n\tIn phosphorus-containing anhydrides", + "3.6.2.-\tIn sulfonyl-containing anhydrides", + "3.6.2.n\tIn sulfonyl-containing anhydrides", + "3.6.3.-\tActing on acid anhydrides; catalyzing transmembrane movement of substances", + "3.6.3.n\tActing on acid anhydrides; catalyzing transmembrane movement of substances", + "3.6.4.-\tActing on ATP; involved in cellular and subcellular movement", + "3.6.4.n\tActing on ATP; involved in cellular and subcellular movement", + "3.6.5.-\tActing on GTP; involved in cellular and subcellular movement", + "3.6.5.n\tActing on GTP; involved in cellular and subcellular movement", + "3.7.-.-\tActing on carbon-carbon bonds", + "3.7.n.n\tActing on carbon-carbon bonds", + "3.7.1.-\tIn ketonic substances", + "3.7.1.n\tIn ketonic substances", + "3.8.-.-\tActing on halide bonds", + "3.8.n.n\tActing on halide bonds", + "3.8.1.-\tIn C-halide compounds", + "3.8.1.n\tIn C-halide compounds", + "3.8.2.-\tIn P-halide compounds", + "3.8.2.n\tIn P-halide compounds", + "3.9.-.-\tActing on phosphorus-nitrogen bonds", + "3.9.n.n\tActing on phosphorus-nitrogen bonds", + "3.9.1.-\tActing on phosphorus-nitrogen bonds", + "3.9.1.n\tActing on phosphorus-nitrogen bonds", + "3.10.-.-\tActing on sulfur-nitrogen bonds", + "3.10.n.n\tActing on sulfur-nitrogen bonds", + "3.10.1.-\tActing on sulfur-nitrogen bonds", + "3.10.1.n\tActing on sulfur-nitrogen bonds", + "3.11.-.-\tActing on carbon-phosphorus bonds", + "3.11.n.n\tActing on carbon-phosphorus bonds", + "3.11.1.-\tActing on carbon-phosphorus bonds", + "3.11.1.n\tActing on carbon-phosphorus bonds", + "3.12.-.-\tActing on sulfur-sulfur bonds", + "3.12.n.n\tActing on sulfur-sulfur bonds", + "3.12.1.-\tActing on sulfur-sulfur bonds", + "3.12.1.n\tActing on sulfur-sulfur bonds", + "3.13.-.-\tActing on carbon-sulfur bonds", + "3.13.n.n\tActing on carbon-sulfur bonds", + "3.13.1.-\tActing on carbon-sulfur bonds", + "3.13.1.n\tActing on carbon-sulfur bonds", + "4.-.-.-\tLyases", + "4.n.n.n\tLyases", + "4.1.-.-\tCarbon-carbon lyases", + "4.1.n.n\tCarbon-carbon lyases", + "4.1.1.-\tCarboxy-lyases", + "4.1.1.n\tCarboxy-lyases", + "4.1.2.-\tAldehyde-lyases", + "4.1.2.n\tAldehyde-lyases", + "4.1.3.-\tOxo-acid-lyases", + "4.1.3.n\tOxo-acid-lyases", + "4.1.99.-\tOther carbon-carbon lyases", + "4.1.99.n\tOther carbon-carbon lyases", + "4.2.-.-\tCarbon-oxygen lyases", + "4.2.n.n\tCarbon-oxygen lyases", + "4.2.1.-\tHydro-lyases", + "4.2.1.n\tHydro-lyases", + "4.2.2.-\tActing on polysaccharides", + "4.2.2.n\tActing on polysaccharides", + "4.2.3.-\tActing on phosphates", + "4.2.3.n\tActing on phosphates", + "4.2.99.-\tOther carbon-oxygen lyases", + "4.2.99.n\tOther carbon-oxygen lyases", + "4.3.-.-\tCarbon-nitrogen lyases", + "4.3.n.n\tCarbon-nitrogen lyases", + "4.3.1.-\tAmmonia-lyases", + "4.3.1.n\tAmmonia-lyases", + "4.3.2.-\tLyases acting on amides, amidines, etc", + "4.3.2.n\tLyases acting on amides, amidines, etc", + "4.3.3.-\tAmine-lyases", + "4.3.3.n\tAmine-lyases", + "4.3.99.-\tOther carbon-nitrogen lyases", + "4.3.99.n\tOther carbon-nitrogen lyases", + "4.4.-.-\tCarbon-sulfur lyases", + "4.4.n.n\tCarbon-sulfur lyases", + "4.4.1.-\tCarbon-sulfur lyases", + "4.4.1.n\tCarbon-sulfur lyases", + "4.5.-.-\tCarbon-halide lyases", + "4.5.n.n\tCarbon-halide lyases", + "4.5.1.-\tCarbon-halide lyases", + "4.5.1.n\tCarbon-halide lyases", + "4.6.-.-\tPhosphorus-oxygen lyases", + "4.6.n.n\tPhosphorus-oxygen lyases", + "4.6.1.-\tPhosphorus-oxygen lyases", + "4.6.1.n\tPhosphorus-oxygen lyases", + "4.7.-.-\tCarbon-phosphorus lyases", + "4.7.n.n\tCarbon-phosphorus lyases", + "4.7.1.-\tCarbon-phosphorus lyases", + "4.7.1.n\tCarbon-phosphorus lyases", + "4.99.-.-\tOther lyases", + "4.99.n.n\tOther lyases", + "4.99.1.-\tOther lyases", + "4.99.1.n\tOther lyases", + "5.-.-.-\tIsomerases", + "5.n.n.n\tIsomerases", + "5.1.-.-\tRacemases and epimerases", + "5.1.n.n\tRacemases and epimerases", + "5.1.1.-\tActing on amino acids and derivatives", + "5.1.1.n\tActing on amino acids and derivatives", + "5.1.2.-\tActing on hydroxy acids and derivatives", + "5.1.2.n\tActing on hydroxy acids and derivatives", + "5.1.3.-\tActing on carbohydrates and derivatives", + "5.1.3.n\tActing on carbohydrates and derivatives", + "5.1.99.-\tActing on other compounds", + "5.1.99.n\tActing on other compounds", + "5.2.-.-\tCis-trans-isomerases", + "5.2.n.n\tCis-trans-isomerases", + "5.2.1.-\tCis-trans isomerases", + "5.2.1.n\tCis-trans isomerases", + "5.3.-.-\tIntramolecular oxidoreductases", + "5.3.n.n\tIntramolecular oxidoreductases", + "5.3.1.-\tInterconverting aldoses and ketoses", + "5.3.1.n\tInterconverting aldoses and ketoses", + "5.3.2.-\tInterconverting keto- and enol-groups", + "5.3.2.n\tInterconverting keto- and enol-groups", + "5.3.3.-\tTransposing C=C bonds", + "5.3.3.n\tTransposing C=C bonds", + "5.3.4.-\tTransposing S-S bonds", + "5.3.4.n\tTransposing S-S bonds", + "5.3.99.-\tOther intramolecular oxidoreductases", + "5.3.99.n\tOther intramolecular oxidoreductases", + "5.4.-.-\tIntramolecular transferases", + "5.4.n.n\tIntramolecular transferases", + "5.4.1.-\tTransferring acyl groups", + "5.4.1.n\tTransferring acyl groups", + "5.4.2.-\tPhosphotransferases (phosphomutases)", + "5.4.2.n\tPhosphotransferases (phosphomutases)", + "5.4.3.-\tTransferring amino groups", + "5.4.3.n\tTransferring amino groups", + "5.4.4.-\tTransferring hydroxy groups", + "5.4.4.n\tTransferring hydroxy groups", + "5.4.99.-\tTransferring other groups", + "5.4.99.n\tTransferring other groups", + "5.5.-.-\tIntramolecular lyases", + "5.5.n.n\tIntramolecular lyases", + "5.5.1.-\tIntramolecular lyases", + "5.5.1.n\tIntramolecular lyases", + "5.99.-.-\tOther isomerases", + "5.99.n.n\tOther isomerases", + "5.99.1.-\tOther isomerases", + "5.99.1.n\tOther isomerases", + "6.-.-.-\tLigases", + "6.n.n.n\tLigases", + "6.1.-.-\tForming carbon-oxygen bonds", + "6.1.n.n\tForming carbon-oxygen bonds", + "6.1.1.-\tLigases forming aminoacyl-tRNA and related compounds", + "6.1.1.n\tLigases forming aminoacyl-tRNA and related compounds", + "6.1.2.-\tAcid--alcohol ligases (ester synthases)", + "6.1.2.n\tAcid--alcohol ligases (ester synthases)", + "6.2.-.-\tForming carbon-sulfur bonds", + "6.2.n.n\tForming carbon-sulfur bonds", + "6.2.1.-\tAcid--thiol ligases", + "6.2.1.n\tAcid--thiol ligases", + "6.3.-.-\tForming carbon-nitrogen bonds", + "6.3.n.n\tForming carbon-nitrogen bonds", + "6.3.1.-\tAcid--ammonia (or amine) ligases (amide synthases)", + "6.3.1.n\tAcid--ammonia (or amine) ligases (amide synthases)", + "6.3.2.-\tAcid--amino-acid ligases (peptide synthases)", + "6.3.2.n\tAcid--amino-acid ligases (peptide synthases)", + "6.3.3.-\tCyclo-ligases", + "6.3.3.n\tCyclo-ligases", + "6.3.4.-\tOther carbon--nitrogen ligases", + "6.3.4.n\tOther carbon--nitrogen ligases", + "6.3.5.-\tCarbon--nitrogen ligases with glutamine as amido-N-donor", + "6.3.5.n\tCarbon--nitrogen ligases with glutamine as amido-N-donor", + "6.4.-.-\tForming carbon-carbon bonds", + "6.4.n.n\tForming carbon-carbon bonds", + "6.4.1.-\tForming carbon-carbon bonds", + "6.4.1.n\tForming carbon-carbon bonds", + "6.5.-.-\tForming phosphoric ester bonds", + "6.5.n.n\tForming phosphoric ester bonds", + "6.5.1.-\tForming phosphoric ester bonds", + "6.5.1.n\tForming phosphoric ester bonds", + "6.6.-.-\tForming nitrogen-metal bonds", + "6.6.n.n\tForming nitrogen-metal bonds", + "6.6.1.-\tForming coordination complexes", + "6.6.1.n\tForming coordination complexes" }; diff --git a/c++/src/objects/seqfeat/ecnum_ambiguous.txt b/c++/src/objects/seqfeat/ecnum_ambiguous.txt index d8d761a4..8ad28cbb 100644 --- a/c++/src/objects/seqfeat/ecnum_ambiguous.txt +++ b/c++/src/objects/seqfeat/ecnum_ambiguous.txt @@ -272,6 +272,8 @@ 1.17.5.n With a quinone or similar compound as acceptor 1.17.7.- With an iron-sulfur protein as acceptor 1.17.7.n With an iron-sulfur protein as acceptor +1.17.8.- With a flavin as acceptor +1.17.8.n With a flavin as acceptor 1.17.98.- With other, known, acceptors 1.17.98.n With other, known, acceptors 1.17.99.- With other acceptors @@ -292,6 +294,8 @@ 1.18.99.n With H(+) as acceptor 1.19.-.- Acting on reduced flavodoxin as donor 1.19.n.n Acting on reduced flavodoxin as donor +1.19.1.- With NAD(+) or NADP(+) as acceptor +1.19.1.n With NAD(+) or NADP(+) as acceptor 1.19.6.- With dinitrogen as acceptor 1.19.6.n With dinitrogen as acceptor 1.20.-.- Acting on phosphorus or arsenic in donors @@ -356,6 +360,8 @@ 2.1.3.n Carboxy- and carbamoyltransferases 2.1.4.- Amidinotransferases 2.1.4.n Amidinotransferases +2.1.5.- Methylenetransferases +2.1.5.n Methylenetransferases 2.2.-.- Transferring aldehyde or ketonic groups 2.2.n.n Transferring aldehyde or ketonic groups 2.2.1.- Transketolases and transaldolases diff --git a/c++/src/objects/seqfeat/ecnum_deleted.inc b/c++/src/objects/seqfeat/ecnum_deleted.inc index d0c79314..e40f9f58 100644 --- a/c++/src/objects/seqfeat/ecnum_deleted.inc +++ b/c++/src/objects/seqfeat/ecnum_deleted.inc @@ -1,4 +1,4 @@ -/* $Id: ecnum_deleted.inc 492647 2016-02-18 22:32:30Z kans $ +/* $Id: ecnum_deleted.inc 532100 2017-03-31 16:44:57Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -85,6 +85,7 @@ static const char* const kECNum_deleted[] = { "2.4.1.154", "2.4.1.235", "2.6.1.20", + "2.6.1.68", "2.6.1.69", "2.7.1.9", "2.7.1.57", @@ -96,6 +97,7 @@ static const char* const kECNum_deleted[] = { "3.1.1.21", "3.1.2.9", "3.1.2.15", + "3.1.3.13", "3.1.3.61", "3.1.4.24", "3.1.4.26", diff --git a/c++/src/objects/seqfeat/ecnum_deleted.txt b/c++/src/objects/seqfeat/ecnum_deleted.txt index 8cc8e74b..421ac96d 100644 --- a/c++/src/objects/seqfeat/ecnum_deleted.txt +++ b/c++/src/objects/seqfeat/ecnum_deleted.txt @@ -52,6 +52,7 @@ 2.4.1.154 2.4.1.235 2.6.1.20 +2.6.1.68 2.6.1.69 2.7.1.9 2.7.1.57 @@ -63,6 +64,7 @@ 3.1.1.21 3.1.2.9 3.1.2.15 +3.1.3.13 3.1.3.61 3.1.4.24 3.1.4.26 diff --git a/c++/src/objects/seqfeat/ecnum_replaced.inc b/c++/src/objects/seqfeat/ecnum_replaced.inc index 8caa3c23..9c18c27e 100644 --- a/c++/src/objects/seqfeat/ecnum_replaced.inc +++ b/c++/src/objects/seqfeat/ecnum_replaced.inc @@ -1,4 +1,4 @@ -/* $Id: ecnum_replaced.inc 502608 2016-05-25 20:34:40Z kans $ +/* $Id: ecnum_replaced.inc 540671 2017-07-10 15:05:11Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,950 +31,992 @@ */ static const char* const kECNum_replaced[] = { - "1.1.1.5 1.1.1.303 1.1.1.304", - "1.1.1.63 1.1.1.239", - "1.1.1.68 1.5.1.20", - "1.1.1.70 1.2.1.3", - "1.1.1.89 1.1.1.86", - "1.1.1.109 1.3.1.28", - "1.1.1.139 1.1.1.21", - "1.1.1.155 1.1.1.87", - "1.1.1.158 1.3.1.98", - "1.1.1.171 1.5.1.20", - "1.1.1.180 1.1.1.131", - "1.1.1.182 1.1.1.198 1.1.1.227 1.1.1.228", - "1.1.1.204 1.17.1.4", - "1.1.1.242 1.3.1.69", - "1.1.1.246 1.1.1.348 4.2.1.139", - "1.1.1.249 2.5.1.46", - "1.1.1.253 1.5.1.33", - "1.1.1.n1 1.1.1.305", - "1.1.1.n2 1.1.1.300", - "1.1.1.n3 1.1.1.336", - "1.1.1.n6 1.1.1.369", - "1.1.1.n7 1.1.1.320", - "1.1.1.n8 1.1.1.366", - "1.1.1.n9 1.1.1.365", - "1.1.1.n10 1.1.1.301", - "1.1.1.n13 1.1.1.330", - "1.1.1.n14 1.1.1.347", - "1.1.2.1 1.1.5.3", - "1.1.3.1 1.1.3.15", - "1.1.3.2 1.13.12.4", - "1.1.3.22 1.17.3.2", - "1.1.3.24 1.3.3.12", - "1.1.3.25 1.1.99.18", - "1.1.3.26 1.21.3.2", - "1.1.3.32 1.14.21.1", - "1.1.3.33 1.14.21.2", - "1.1.3.34 1.14.21.3", - "1.1.3.35 1.14.21.4", - "1.1.3.36 1.14.21.5", - "1.1.4.1 1.17.4.4", - "1.1.4.2 1.17.4.5", - "1.1.98.1 1.1.9.1", - "1.1.99.5 1.1.5.3", - "1.1.99.8 1.1.2.7 1.1.2.8", - "1.1.99.10 1.1.5.9", - "1.1.99.15 1.5.1.20", - "1.1.99.16 1.1.5.4", - "1.1.99.17 1.1.5.2", - "1.1.99.19 1.17.99.4", - "1.1.99.23 1.1.2.6", - "1.1.99.25 1.1.5.8", - "1.1.99.34 1.1.98.2", - "1.2.1.1 1.1.1.284 4.4.1.22", - "1.2.1.14 1.1.1.205", - "1.2.1.34 1.1.1.131", - "1.2.1.35 1.1.1.203", - "1.2.1.37 1.17.1.4", - "1.2.1.45 1.1.1.312", - "1.2.1.55 1.1.1.279", - "1.2.1.56 1.1.1.280", - "1.2.1.66 1.1.1.306", - "1.2.1.n1 1.2.1.77", - "1.2.1.n3 1.2.1.86", - "1.2.3.2 1.17.3.2", - "1.2.3.11 1.2.3.1", - "1.2.3.12 1.14.13.82", - "1.2.4.3 1.2.4.4", - "1.2.7.9 1.2.7.3", - "1.2.99.1 1.17.99.4", - "1.2.99.3 1.2.5.2", - "1.2.99.4 1.2.98.1", - "1.3.1.4 1.3.1.22", - "1.3.1.26 1.17.1.8", - "1.3.1.30 1.3.1.22", - "1.3.1.35 1.14.19.22", - "1.3.1.50 1.1.1.252", - "1.3.1.52 1.3.8.5", - "1.3.1.63 1.21.1.2", - "1.3.1.80 1.3.7.12", - "1.3.1.n1 1.3.1.87", - "1.3.2.1 1.3.8.1", - "1.3.2.2 1.3.8.7", - "1.3.3.1 1.3.98.1", - "1.3.3.2 1.14.19.20", - "1.3.7.10 1.14.19.8", - "1.3.98.2 1.3.4.1", - "1.3.99.2 1.3.8.1", - "1.3.99.3 1.3.8.7 1.3.8.8 1.3.8.9", - "1.3.99.7 1.3.8.6", - "1.3.99.9 1.21.99.1", - "1.3.99.10 1.3.8.4", - "1.3.99.11 1.3.5.2", - "1.3.99.13 1.3.8.8", - "1.3.99.15 1.3.7.8", - "1.3.99.20 1.3.7.9", - "1.3.99.21 1.3.8.3", - "1.3.99.34 1.3.7.11", - "1.3.99.n2 4.1.99.19", - "1.3.99.n3 1.3.99.36", - "1.4.1.6 1.21.4.1", - "1.4.3.6 1.4.3.21 1.4.3.22", - "1.4.3.9 1.4.3.4", - "1.4.3.17 1.3.3.10", - "1.4.4.1 1.21.4.1", - "1.4.98.1 1.4.9.1", - "1.4.99.1 1.4.99.6", - "1.4.99.3 1.4.9.1", - "1.4.99.4 1.4.9.2", - "1.5.1.4 1.5.1.3", - "1.5.1.12 1.2.1.88", - "1.5.1.13 1.17.1.5", - "1.5.1.14 1.5.1.21", - "1.5.1.29 1.5.1.38 1.5.1.39 1.5.1.41", - "1.5.1.35 1.2.1.19", - "1.5.3.8 1.3.3.8", - "1.5.3.9 1.21.3.3", - "1.5.3.11 1.5.3.13 1.5.3.14 1.5.3.15 1.5.3.16 1.5.3.17", - "1.5.3.n1 1.5.3.16", - "1.5.3.n2 1.5.3.16", - "1.5.3.n3 1.5.3.13 1.5.3.16", - "1.5.3.n4 1.5.3.13", - "1.5.3.n5 1.5.3.16", - "1.5.3.n6 1.5.3.14 1.5.3.15", - "1.5.3.n7 1.5.3.14 1.5.3.15", - "1.5.3.n8 1.5.3.14 1.5.3.15", - "1.5.3.n9 1.5.3.14 1.5.3.15", - "1.5.3.n10 1.5.3.13", - "1.5.99.1 1.5.8.3", - "1.5.99.2 1.5.8.4", - "1.5.99.7 1.5.8.2", - "1.5.99.8 1.5.5.2", - "1.5.99.9 1.5.98.1", - "1.5.99.10 1.5.8.1", - "1.5.99.11 1.5.98.2", - "1.6.2.1 1.6.99.3", - "1.6.4.1 1.8.1.6", - "1.6.4.2 1.8.1.7", - "1.6.4.3 1.8.1.4", - "1.6.4.4 1.8.1.8", - "1.6.4.5 1.8.1.9", - "1.6.4.6 1.8.1.10", - "1.6.4.7 1.8.1.11", - "1.6.4.8 1.8.1.12", - "1.6.4.9 1.8.1.13", - "1.6.4.10 1.8.1.14", - "1.6.6.1 1.7.1.1", - "1.6.6.2 1.7.1.2", - "1.6.6.3 1.7.1.3", - "1.6.6.4 1.7.1.4", - "1.6.6.5 1.7.2.1", - "1.6.6.6 1.7.1.5", - "1.6.6.7 1.7.1.6", - "1.6.6.8 1.7.1.7", - "1.6.6.10 1.7.1.9", - "1.6.6.11 1.7.1.10", - "1.6.6.12 1.7.1.11", - "1.6.6.13 1.7.1.12", - "1.6.7.1 1.18.1.2", - "1.6.7.2 1.18.1.1", - "1.6.8.1 1.5.1.38 1.5.1.39 1.5.1.41", - "1.6.8.2 1.5.1.30", - "1.6.99.2 1.6.5.2", - "1.6.99.4 1.18.1.2", - "1.6.99.5 1.6.5.11", - "1.6.99.6 1.6.5.10", - "1.6.99.7 1.5.1.34", - "1.6.99.8 1.16.1.3", - "1.6.99.9 1.16.1.4", - "1.6.99.10 1.5.1.34", - "1.6.99.11 1.16.1.5", - "1.6.99.12 1.16.1.6", - "1.6.99.13 1.16.1.7", - "1.7.3.4 1.7.2.6 1.7.3.6", - "1.7.99.3 1.7.2.1", - "1.7.99.5 1.5.1.20", - "1.7.99.6 1.7.2.4", - "1.7.99.7 1.7.2.5", - "1.8.4.5 1.8.4.13 1.8.4.14", - "1.8.4.6 1.8.4.11", - "1.8.6.1 2.5.1.18", - "1.8.99.4 1.8.4.8", - "1.9.3.2 1.7.2.1", - "1.9.99.1 1.9.98.1", - "1.10.3.7 1.21.3.4", - "1.10.3.8 1.21.3.5", - "1.10.99.1 1.10.9.1", - "1.10.99.2 1.10.5.1", - "1.10.99.3 1.23.5.1", - "1.11.1.4 1.13.11.11", - "1.12.1.1 1.12.7.2", - "1.12.7.1 1.12.7.2", - "1.12.99.1 1.12.98.1", - "1.12.99.3 1.12.5.1", - "1.12.99.4 1.12.98.2", - "1.12.99.5 1.13.11.47", - "1.13.1.1 1.13.11.1", - "1.13.1.2 1.13.11.2", - "1.13.1.3 1.13.11.3", - "1.13.1.4 1.13.11.4", - "1.13.1.5 1.13.11.5", - "1.13.1.6 1.13.11.6", - "1.13.1.8 1.13.11.8", - "1.13.1.9 1.13.11.9", - "1.13.1.10 1.13.11.10", - "1.13.1.11 1.13.99.1", - "1.13.1.12 1.13.11.11", - "1.13.1.13 1.13.11.12", - "1.13.11.21 1.13.11.63", - "1.13.11.32 1.13.12.16", - "1.13.11.44 1.13.11.60 5.4.4.6", - "1.13.11.n1 1.13.11.74", - "1.13.11.n2 1.13.11.63", - "1.13.12.11 1.14.13.8", - "1.13.12.12 1.13.11.67", - "1.13.12.14 1.14.13.122", - "1.13.99.2 1.14.12.10", - "1.13.99.4 1.14.12.9", - "1.13.99.5 1.13.11.47", - "1.14.1.1 1.14.14.1", - "1.14.1.2 1.14.13.9", - "1.14.1.3 1.14.14.17 5.4.99.7", - "1.14.1.4 1.14.99.2", - "1.14.1.5 1.14.13.5", - "1.14.1.6 1.14.15.4", - "1.14.1.7 1.14.14.19", - "1.14.1.8 1.14.14.16", - "1.14.1.10 1.14.99.11", - "1.14.2.1 1.14.17.1", - "1.14.2.2 1.13.11.27", - "1.14.3.1 1.14.16.1", - "1.14.11.5 1.14.11.6", - "1.14.11.n1 1.14.11.39", - "1.14.12.2 1.14.13.35", - "1.14.12.6 1.14.13.66", - "1.14.12.20 1.14.15.17", - "1.14.12.21 1.14.13.208", - "1.14.12.n1 1.14.13.208", - "1.14.13.3 1.14.14.9", - "1.14.13.15 1.14.15.15", - "1.14.13.17 1.14.14.23", - "1.14.13.26 1.14.18.4", - "1.14.13.45 1.14.18.2", - "1.14.13.60 1.14.13.100", - "1.14.13.86 1.14.13.136", - "1.14.13.95 1.14.18.8", - "1.14.13.98 1.14.14.25", - "1.14.13.99 1.14.14.26", - "1.14.13.126 1.14.15.16", - "1.14.13.132 1.14.14.17", - "1.14.13.159 1.14.14.24", - "1.14.13.164 1.13.11.65", - "1.14.13.169 1.14.18.5", - "1.14.13.n1 1.14.13.124", - "1.14.13.n2 1.14.13.125", - "1.14.13.n3 1.14.13.127", - "1.14.13.n4 1.14.15.16", - "1.14.13.n9 1.14.13.149", - "1.14.14.2 1.14.14.1", - "1.14.14.4 1.14.15.7", - "1.14.14.6 1.14.13.111", - "1.14.14.7 1.14.19.9", - "1.14.14.n1 1.14.99.46", - "1.14.15.2 1.14.13.162", - "1.14.17.2 1.14.18.1", - "1.14.19.7 1.11.1.23", - "1.14.19.n1 1.14.19.4", - "1.14.19.n2 1.14.19.5", - "1.14.19.n3 1.14.19.6", - "1.14.21.6 1.14.19.20", - "1.14.99.3 1.14.14.18", - "1.14.99.5 1.14.19.1", - "1.14.99.6 1.14.19.2", - "1.14.99.7 1.14.14.17", - "1.14.99.8 1.14.14.1", - "1.14.99.9 1.14.14.19", - "1.14.99.10 1.14.14.16", - "1.14.99.13 1.14.13.23", - "1.14.99.16 1.14.13.72", - "1.14.99.17 1.14.16.5", - "1.14.99.25 1.14.19.3", - "1.14.99.28 1.14.13.151", - "1.14.99.30 1.3.5.6", - "1.14.99.31 1.14.19.24", - "1.14.99.32 1.14.19.5", - "1.14.99.33 1.14.19.39", - "1.14.99.40 1.13.11.79", - "1.14.99.41 1.13.11.75", - "1.14.99.n1 1.13.11.75", - "1.14.99.n2 1.13.11.71", - "1.14.99.n3 1.14.99.42", - "1.14.99.n5 1.13.11.70", - "1.16.98.1 1.16.9.1", - "1.17.1.2 1.17.7.4", - "1.17.1.6 1.17.98.1", - "1.17.1.7 1.2.1.91", - "1.17.4.3 1.17.7.1", - "1.17.99.5 1.17.98.1", - "1.18.2.1 1.18.6.1", - "1.18.3.1 1.12.7.2", - "1.18.96.1 1.15.1.2", - "1.18.99.1 1.12.7.2", - "1.20.98.1 1.20.9.1", - "1.21.3.9 1.21.98.2", - "1.21.99.2 1.21.98.1", - "1.22.1.1 1.21.1.1", - "1.97.1.3 1.12.98.4", - "1.97.1.5 1.20.4.1", - "1.97.1.6 1.20.99.1", - "1.97.1.7 1.20.4.2", - "1.97.1.10 1.21.99.4", - "1.97.1.11 1.21.99.3", - "1.98.1.1 1.12.7.2", - "1.99.1.1 1.14.14.1", - "1.99.1.2 1.14.16.1", - "1.99.1.5 1.14.13.9", - "1.99.1.7 1.14.15.4", - "1.99.1.9 1.14.14.19", - "1.99.1.11 1.14.14.16", - "1.99.1.13 1.14.14.17 5.4.99.7", - "1.99.1.14 1.13.11.27", - "1.99.2.1 1.13.11.12", - "1.99.2.2 1.13.11.1", - "1.99.2.3 1.13.11.3", - "1.99.2.4 1.13.11.4", - "1.99.2.5 1.13.11.5", - "1.99.2.6 1.13.99.1", - "2.1.1.23 2.1.1.319 2.1.1.320 2.1.1.321 2.1.1.322", - "2.1.1.24 2.1.1.77 2.1.1.80 2.1.1.100", - "2.1.1.29 2.1.1.202 2.1.1.203 2.1.1.204", - "2.1.1.31 2.1.1.221 2.1.1.228", - "2.1.1.32 2.1.1.213 2.1.1.214 2.1.1.215 2.1.1.216", - "2.1.1.36 2.1.1.217 2.1.1.218 2.1.1.219 2.1.1.220", - "2.1.1.48 2.1.1.181 2.1.1.182 2.1.1.183 2.1.1.184", - "2.1.1.51 2.1.1.187 2.1.1.188", - "2.1.1.52 2.1.1.171 2.1.1.172 2.1.1.173 2.1.1.174", - "2.1.1.58 2.1.1.57", - "2.1.1.66 2.1.1.230", - "2.1.1.73 2.1.1.37", - "2.1.1.81 2.1.1.49", - "2.1.1.92 2.1.1.69", - "2.1.1.93 2.1.1.70", - "2.1.1.124 2.1.1.319 2.1.1.320 2.1.1.321 2.1.1.322", - "2.1.1.125 2.1.1.319 2.1.1.320 2.1.1.321 2.1.1.322", - "2.1.1.126 2.1.1.319 2.1.1.320 2.1.1.321 2.1.1.322", - "2.1.1.134 2.1.1.129", - "2.1.1.135 1.16.1.8", - "2.1.1.149 2.1.1.267", - "2.1.1.n2 2.1.1.211", - "2.1.1.n3 2.1.1.280", - "2.1.1.n5 2.1.1.244", - "2.1.1.n6 2.1.1.255", - "2.1.1.n9 2.1.1.274", - "2.1.1.n10 2.1.1.278", - "2.1.1.n13 2.1.1.301", - "2.1.1.n14 2.1.1.300", - "2.1.1.n15 2.1.1.298", - "2.1.1.n16 2.1.1.297", - "2.1.2.6 2.1.2.5", - "2.1.2.12 2.1.1.74", - "2.1.2.n1 2.1.2.13", - "2.1.3.13 6.1.2.2", - "2.1.3.14 6.1.2.2", - "2.3.1.55 2.3.1.82", - "2.3.1.104 2.3.1.25", - "2.3.1.119 1.1.1.330 1.3.1.93 2.3.1.199 4.2.1.134", - "2.3.1.n1 2.3.1.191", - "2.3.1.n8 2.3.1.199", - "2.3.1.n9 2.3.1.211", - "2.3.1.n10 2.3.1.222", - "2.3.1.n11 2.3.1.223", - "2.4.1.3 2.4.1.25", - "2.4.1.42 2.4.1.17", - "2.4.1.51 2.4.1.101 2.4.1.143 2.4.1.144 2.4.1.145", - "2.4.1.55 2.7.8.14", - "2.4.1.59 2.4.1.17", - "2.4.1.61 2.4.1.17", - "2.4.1.72 2.4.2.24", - "2.4.1.76 2.4.1.17", - "2.4.1.77 2.4.1.17", - "2.4.1.84 2.4.1.17", - "2.4.1.89 2.4.1.69", - "2.4.1.93 4.2.2.18", - "2.4.1.98 2.4.1.90", - "2.4.1.107 2.4.1.17", - "2.4.1.108 2.4.1.17", - "2.4.1.112 2.4.1.186", - "2.4.1.119 2.4.99.18", - "2.4.1.124 2.4.1.87", - "2.4.1.130 2.4.1.258 2.4.1.259 2.4.1.260 2.4.1.261", - "2.4.1.151 2.4.1.87", - "2.4.1.169 2.4.2.39", - "2.4.1.200 4.2.2.17", - "2.4.1.204 2.4.2.40", - "2.4.1.233 2.4.1.115", - "2.4.1.n1 2.4.1.245", - "2.4.1.n3 2.4.1.250", - "2.4.1.n4 2.4.1.131", - "2.4.1.n5 2.4.99.16", - "2.4.2.11 6.3.4.21", - "2.4.2.13 2.5.1.6", - "2.4.2.23 2.4.2.2 2.4.2.3 2.4.2.4", - "2.4.2.n1 2.4.2.43", - "2.5.1.8 2.5.1.75", - "2.5.1.11 2.5.1.84 2.5.1.85", - "2.5.1.12 2.5.1.18", - "2.5.1.13 2.5.1.18", - "2.5.1.14 2.5.1.18", - "2.5.1.33 2.5.1.82 2.5.1.83", - "2.5.1.37 4.4.1.20", - "2.5.1.40 4.2.3.9", - "2.5.1.64 2.2.1.9 4.2.99.20", - "2.5.1.n1 2.2.1.9", - "2.5.1.n2 2.5.1.81", - "2.5.1.n3 2.5.1.73", - "2.5.1.n4 2.5.1.112", - "2.5.1.n5 2.5.1.113", - "2.5.1.n6 2.5.1.105", - "2.5.1.n7 2.5.1.108", - "2.5.1.n8 2.5.1.115", - "2.6.1.10 2.6.1.21", - "2.6.1.25 2.6.1.24", - "2.6.1.53 1.4.1.13", - "2.6.1.61 2.6.1.40", - "2.6.1.91 2.6.1.34", - "2.6.1.n1 2.6.1.87", - "2.6.1.n2 2.6.1.105", - "2.6.2.1 2.1.4.1", - "2.6.99.4 2.3.1.234", - "2.7.1.37 2.7.11.1 2.7.11.8 2.7.11.9 2.7.11.10 2.7.11.11 2.7.11.12 2.7.11.13 2.7.11.21 2.7.11.22 2.7.11.24 2.7.11.25 2.7.11.30 2.7.12.1", - "2.7.1.38 2.7.11.19", - "2.7.1.69 2.7.1.191", - "2.7.1.70 2.7.11.1", - "2.7.1.75 2.7.1.21", - "2.7.1.96 2.7.1.86", - "2.7.1.97 2.7.11.14", - "2.7.1.99 2.7.11.2", - "2.7.1.104 2.7.99.1", - "2.7.1.109 2.7.11.31", - "2.7.1.110 2.7.11.3", - "2.7.1.111 2.7.11.27", - "2.7.1.112 2.7.10.1 2.7.10.2", - "2.7.1.115 2.7.11.4", - "2.7.1.116 2.7.11.5", - "2.7.1.117 2.7.11.18", - "2.7.1.120 2.7.11.17", - "2.7.1.123 2.7.11.17", - "2.7.1.124 2.7.11.6", - "2.7.1.125 2.7.11.14", - "2.7.1.126 2.7.11.15", - "2.7.1.128 2.7.11.27", - "2.7.1.129 2.7.11.7", - "2.7.1.131 2.7.11.29", - "2.7.1.132 2.7.11.28", - "2.7.1.133 2.7.1.134", - "2.7.1.135 2.7.11.26", - "2.7.1.139 2.7.1.134", - "2.7.1.141 2.7.11.23", - "2.7.1.152 2.7.4.21", - "2.7.1.155 2.7.4.24", - "2.7.1.n1 2.7.1.170", - "2.7.1.n2 2.7.1.161", - "2.7.1.n3 2.7.1.164", - "2.7.1.n4 2.7.1.173", - "2.7.1.n5 2.7.1.174", - "2.7.1.n6 2.7.1.163", - "2.7.1.n7 2.7.1.176", - "2.7.1.n8 2.7.1.175", - "2.7.2.5 6.3.4.16", - "2.7.2.9 6.3.5.5", - "2.7.3.11 2.7.13.1", - "2.7.3.12 2.7.13.2", - "2.7.4.5 2.7.4.14", - "2.7.4.n1 2.7.4.27", - "2.7.4.n2 2.7.4.28", - "2.7.5.1 5.4.2.2", - "2.7.5.2 5.4.2.3", - "2.7.5.3 5.4.2.11 5.4.2.12", - "2.7.5.4 5.4.2.4", - "2.7.5.5 5.4.2.5", - "2.7.5.6 5.4.2.7", - "2.7.5.7 5.4.2.8", - "2.7.7.16 3.1.27.5", - "2.7.7.17 3.1.27.1", - "2.7.7.21 2.7.7.72", - "2.7.7.25 2.7.7.72", - "2.7.7.26 3.1.27.3", - "2.7.7.29 2.7.7.28", - "2.7.7.54 6.3.2.40", - "2.7.7.55 6.3.2.40", - "2.7.7.63 6.3.1.20", - "2.7.7.n2 2.7.7.67", - "2.7.7.n3 2.7.7.73", - "2.7.7.n4 2.7.7.80", - "2.7.7.n5 2.7.7.75", - "2.7.8.16 2.7.8.2", - "2.7.8.25 2.4.2.52", - "2.7.8.30 2.4.2.53", - "2.7.8.n1 2.4.2.53", - "2.7.8.n2 2.7.8.33", - "2.7.11.n1 2.7.11.32", - "2.7.11.n2 2.7.11.33", - "2.8.1.n1 2.8.1.11", - "2.8.2.12 2.8.2.8", - "2.8.2.n1 2.8.2.20", - "2.9.1.n1 2.9.1.2", - "3.1.1.12 3.1.1.1", - "3.1.1.16 3.1.1.24 5.3.3.4", - "3.1.1.18 3.1.1.17", - "3.1.1.62 3.5.1.47", - "3.1.1.69 3.5.1.89", - "3.1.1.n1 3.5.1.103", - "3.1.2.8 3.1.2.6", - "3.1.2.24 3.13.1.3", - "3.1.2.n1 3.1.2.28", - "3.1.2.n2 3.1.2.30", - "3.1.3.30 3.1.3.31", - "3.1.3.65 3.1.3.64", - "3.1.3.n1 3.1.3.86", - "3.1.3.n2 3.1.3.84", - "3.1.3.n3 3.1.3.78", - "3.1.3.n4 3.1.3.87", - "3.1.3.n5 3.1.3.93", - "3.1.3.n6 3.1.3.96", - "3.1.4.5 3.1.21.1", - "3.1.4.6 3.1.22.1", - "3.1.4.7 3.1.31.1", - "3.1.4.8 3.1.27.3", - "3.1.4.9 3.1.30.2", - "3.1.4.10 4.6.1.13", - "3.1.4.15 2.7.7.89", - "3.1.4.18 3.1.16.1", - "3.1.4.19 3.1.13.3", - "3.1.4.20 3.1.13.1", - "3.1.4.21 3.1.30.1", - "3.1.4.22 3.1.27.5", - "3.1.4.23 3.1.27.1", - "3.1.4.25 3.1.11.1", - "3.1.4.27 3.1.11.2", - "3.1.4.28 3.1.11.3", - "3.1.4.30 3.1.21.2", - "3.1.4.31 3.1.11.4", - "3.1.4.36 3.1.4.43", - "3.1.4.47 4.6.1.14", - "3.1.4.n1 3.1.4.53", - "3.1.7.4 4.2.1.133 4.2.3.141", - "3.1.22.3 3.1.21.7", - "3.1.23.1 3.1.21.4", - "3.1.23.2 3.1.21.4", - "3.1.23.3 3.1.21.4", - "3.1.23.4 3.1.21.4", - "3.1.23.5 3.1.21.4", - "3.1.23.6 3.1.21.4", - "3.1.23.7 3.1.21.4", - "3.1.23.8 3.1.21.4", - "3.1.23.9 3.1.21.4", - "3.1.23.10 3.1.21.4", - "3.1.23.11 3.1.21.4", - "3.1.23.12 3.1.21.4", - "3.1.23.13 3.1.21.4", - "3.1.23.14 3.1.21.4", - "3.1.23.15 3.1.21.4", - "3.1.23.16 3.1.21.4", - "3.1.23.17 3.1.21.4", - "3.1.23.18 3.1.21.4", - "3.1.23.19 3.1.21.4", - "3.1.23.20 3.1.21.4", - "3.1.23.21 3.1.21.4", - "3.1.23.22 3.1.21.4", - "3.1.23.23 3.1.21.4", - "3.1.23.24 3.1.21.4", - "3.1.23.25 3.1.21.4", - "3.1.23.26 3.1.21.4", - "3.1.23.27 3.1.21.4", - "3.1.23.28 3.1.21.4", - "3.1.23.29 3.1.21.4", - "3.1.23.30 3.1.21.4", - "3.1.23.31 3.1.21.4", - "3.1.23.32 3.1.21.4", - "3.1.23.33 3.1.21.4", - "3.1.23.34 3.1.21.4", - "3.1.23.35 3.1.21.4", - "3.1.23.36 3.1.21.4", - "3.1.23.37 3.1.21.4", - "3.1.23.38 3.1.21.4", - "3.1.23.39 3.1.21.4", - "3.1.23.40 3.1.21.4", - "3.1.23.41 3.1.21.4", - "3.1.23.42 3.1.21.4", - "3.1.23.43 3.1.21.4", - "3.1.23.44 3.1.21.4", - "3.1.23.45 3.1.21.4", - "3.1.23.46 3.1.21.4", - "3.1.23.47 3.1.21.4", - "3.1.23.48 3.1.21.4", - "3.1.23.49 3.1.21.4", - "3.1.23.50 3.1.21.4", - "3.1.23.51 3.1.21.4", - "3.1.23.52 3.1.21.4", - "3.1.23.53 3.1.21.4", - "3.1.23.54 3.1.21.4", - "3.1.23.55 3.1.21.4", - "3.1.23.56 3.1.21.4", - "3.1.23.57 3.1.21.4", - "3.1.23.58 3.1.21.4", - "3.1.23.59 3.1.21.4", - "3.1.24.1 3.1.21.3", - "3.1.24.2 3.1.21.3", - "3.1.24.3 3.1.21.5", - "3.1.24.4 3.1.21.5", - "3.1.25.2 4.2.99.18", - "3.1.26.n1 3.1.26.12", - "3.1.27.9 4.6.1.16", - "3.2.1.12 3.2.1.54", - "3.2.1.13 3.2.1.54", - "3.2.1.29 3.2.1.52", - "3.2.1.30 3.2.1.52", - "3.2.1.34 3.2.1.35", - "3.2.1.69 3.2.1.41", - "3.2.1.79 3.2.1.55", - "3.2.1.110 3.2.1.97", - "3.2.1.138 4.2.2.15", - "3.2.1.148 4.4.1.21", - "3.2.1.160 3.2.1.155", - "3.2.2.18 3.5.1.52", - "3.2.3.1 3.2.1.147", - "3.3.1.3 4.4.1.21", - "3.3.2.3 3.3.2.9 3.3.2.10", - "3.4.1.1 3.4.11.1", - "3.4.1.2 3.4.11.2", - "3.4.1.3 3.4.11.4", - "3.4.1.4 3.4.11.5", - "3.4.2.1 3.4.17.1", - "3.4.2.2 3.4.17.2", - "3.4.2.3 3.4.17.4", - "3.4.3.1 3.4.13.18 3.4.13.19", - "3.4.3.2 3.4.13.18 3.4.13.19", - "3.4.3.3 3.4.13.18 3.4.13.20", - "3.4.3.4 3.4.13.5", - "3.4.3.5 3.4.11.2", - "3.4.3.6 3.4.13.18 3.4.13.19", - "3.4.3.7 3.4.13.9", - "3.4.4.1 3.4.23.1", - "3.4.4.2 3.4.23.2", - "3.4.4.3 3.4.23.4", - "3.4.4.4 3.4.21.4", - "3.4.4.5 3.4.21.1", - "3.4.4.6 3.4.21.1", - "3.4.4.7 3.4.21.36 3.4.21.37", - "3.4.4.8 3.4.21.9", - "3.4.4.9 3.4.14.1", - "3.4.4.10 3.4.22.2", - "3.4.4.11 3.4.22.6", - "3.4.4.12 3.4.22.3", - "3.4.4.13 3.4.21.5", - "3.4.4.14 3.4.21.7", - "3.4.4.15 3.4.23.15", - "3.4.4.16 3.4.21.62 3.4.21.63 3.4.21.64 3.4.21.65 3.4.21.66 3.4.21.67", - "3.4.4.17 3.4.21.103 3.4.23.20 3.4.23.21 3.4.23.22 3.4.23.23 3.4.23.24 3.4.23.25 3.4.23.26 3.4.23.28 3.4.23.29 3.4.23.30", - "3.4.4.18 3.4.22.10", - "3.4.4.19 3.4.24.3", - "3.4.4.20 3.4.22.8", - "3.4.4.21 3.4.21.34", - "3.4.4.22 3.4.23.3", - "3.4.4.23 3.4.23.5", - "3.4.4.24 3.4.22.32 3.4.22.33", - "3.4.11.8 3.4.19.3", - "3.4.11.n1 3.4.11.24", - "3.4.12.1 3.4.16.5 3.4.16.6", - "3.4.12.2 3.4.17.1", - "3.4.12.3 3.4.17.2", - "3.4.12.4 3.4.16.2", - "3.4.12.5 3.5.1.28", - "3.4.12.6 3.4.17.8", - "3.4.12.7 3.4.17.3", - "3.4.12.8 3.4.17.4", - "3.4.12.10 3.4.19.9", - "3.4.12.11 3.4.17.6", - "3.4.12.12 3.4.16.5 3.4.16.6", - "3.4.13.1 3.4.13.18 3.4.13.19", - "3.4.13.2 3.4.13.18 3.4.13.19", - "3.4.13.3 3.4.13.18 3.4.13.20", - "3.4.13.6 3.4.11.2", - "3.4.13.8 3.4.13.18 3.4.13.19", - "3.4.13.10 3.4.19.5", - "3.4.13.11 3.4.13.18 3.4.13.19", - "3.4.13.13 3.4.13.18 3.4.13.20", - "3.4.13.15 3.4.13.18 3.4.13.19", - "3.4.14.3 3.4.19.1", - "3.4.14.8 3.4.14.9 3.4.14.10", - "3.4.15.2 3.4.19.2", - "3.4.15.3 3.4.15.5", - "3.4.16.1 3.4.16.5 3.4.16.6", - "3.4.16.3 3.4.16.5 3.4.16.6", - "3.4.17.7 3.5.1.28", - "3.4.17.9 3.4.17.4", - "3.4.19.8 3.4.17.21", - "3.4.19.10 3.5.1.28", - "3.4.21.8 3.4.21.34 3.4.21.35", - "3.4.21.11 3.4.21.36 3.4.21.37", - "3.4.21.13 3.4.16.5 3.4.16.6", - "3.4.21.14 3.4.21.62 3.4.21.63 3.4.21.64 3.4.21.65 3.4.21.67", - "3.4.21.15 3.4.21.63", - "3.4.21.28 3.4.21.74", - "3.4.21.29 3.4.21.74", - "3.4.21.30 3.4.21.74", - "3.4.21.31 3.4.21.68 3.4.21.73", - "3.4.21.44 3.4.21.43", - "3.4.21.87 3.4.23.49", - "3.4.22.4 3.4.22.32 3.4.22.33", - "3.4.22.5 3.4.22.33", - "3.4.22.9 3.4.21.48", - "3.4.22.11 3.4.24.56", - "3.4.22.12 3.4.19.9", - "3.4.22.17 3.4.22.52 3.4.22.53", - "3.4.22.18 3.4.21.26", - "3.4.22.19 3.4.24.15", - "3.4.22.21 3.4.25.1", - "3.4.22.22 3.4.24.37", - "3.4.22.23 3.4.21.61", - "3.4.23.6 3.4.21.103 3.4.23.18 3.4.23.19 3.4.23.20 3.4.23.21 3.4.23.22 3.4.23.23 3.4.23.24 3.4.23.25 3.4.23.26 3.4.23.28 3.4.23.30", - "3.4.23.7 3.4.23.20", - "3.4.23.8 3.4.23.25", - "3.4.23.9 3.4.23.21", - "3.4.23.10 3.4.23.22", - "3.4.23.27 3.4.21.103", - "3.4.23.33 3.4.21.101", - "3.4.23.37 3.4.21.100", - "3.4.24.4 3.4.24.25 3.4.24.26 3.4.24.27 3.4.24.28 3.4.24.29 3.4.24.30 3.4.24.31 3.4.24.32 3.4.24.39 3.4.24.40", - "3.4.24.5 3.4.22.52 3.4.22.53 3.4.25.1", - "3.4.24.8 3.4.24.3", - "3.4.99.1 3.4.23.28", - "3.4.99.4 3.4.23.12", - "3.4.99.5 3.4.24.3", - "3.4.99.6 3.4.24.21", - "3.4.99.10 3.4.24.56", - "3.4.99.13 3.4.24.32", - "3.4.99.19 3.4.23.15", - "3.4.99.22 3.4.24.29", - "3.4.99.25 3.4.23.21", - "3.4.99.26 3.4.21.68 3.4.21.73", - "3.4.99.28 3.4.21.60", - "3.4.99.30 3.4.24.20", - "3.4.99.31 3.4.24.15", - "3.4.99.32 3.4.24.20", - "3.4.99.35 3.4.23.36", - "3.4.99.36 3.4.21.89", - "3.4.99.38 3.4.23.17", - "3.4.99.41 3.4.24.64", - "3.4.99.43 3.4.23.42", - "3.4.99.44 3.4.24.55", - "3.4.99.45 3.4.24.56", - "3.4.99.46 3.4.25.1", - "3.5.1.34 3.4.13.5", - "3.5.1.37 3.5.1.26", - "3.5.1.45 6.3.4.6", - "3.5.1.80 3.5.1.25", - "3.5.1.n1 3.5.1.108", - "3.5.1.n2 3.5.1.99", - "3.5.1.n4 3.5.1.110", - "3.5.2.8 3.5.2.6", - "3.5.3.19 3.5.1.116", - "3.5.4.14 3.5.4.5", - "3.5.4.n1 3.5.4.31", - "3.5.4.n2 3.5.4.39", - "3.5.5.3 4.2.1.104", - "3.6.1.4 3.6.1.3", - "3.6.1.30 3.6.1.59 3.6.1.62", - "3.6.1.32 3.6.4.1", - "3.6.1.33 3.6.4.2", - "3.6.1.34 3.6.3.14", - "3.6.1.35 3.6.3.6", - "3.6.1.36 3.6.3.10", - "3.6.1.37 3.6.3.9", - "3.6.1.38 3.6.3.8", - "3.6.1.46 3.6.5.1", - "3.6.1.47 3.6.5.2", - "3.6.1.48 3.6.5.3", - "3.6.1.49 3.6.5.4", - "3.6.1.50 3.6.5.5", - "3.6.1.51 3.6.5.6", - "3.6.1.n4 3.6.1.67", - "3.6.1.n5 3.6.1.54", - "3.6.3.13 3.6.3.1", - "3.6.3.45 3.6.3.44", - "3.6.3.n1 3.6.3.54", - "3.7.1.15 4.2.1.138", - "3.7.1.16 3.3.2.12", - "3.7.1.n1 3.7.1.14", - "3.7.1.n2 3.7.1.22", - "3.8.1.4 1.21.99.4", - "3.8.2.1 3.1.8.2", - "4.1.1.10 4.1.1.12", - "4.1.1.26 4.1.1.28", - "4.1.1.27 4.1.1.28", - "4.1.1.n1 4.1.1.97", - "4.1.1.n2 4.1.1.94", - "4.1.2.1 4.1.3.16", - "4.1.2.7 4.1.2.13", - "4.1.2.15 2.5.1.54", - "4.1.2.16 2.5.1.55", - "4.1.2.31 4.1.3.16", - "4.1.2.37 4.1.2.46 4.1.2.47", - "4.1.2.39 4.1.2.46 4.1.2.47", - "4.1.2.n1 4.1.2.44", - "4.1.2.n3 4.1.2.53", - "4.1.2.n4 4.1.2.52", - "4.1.2.n5 2.2.1.10", - "4.1.2.n6 4.1.2.56", - "4.1.3.2 2.3.3.9", - "4.1.3.5 2.3.3.10", - "4.1.3.7 2.3.3.1", - "4.1.3.8 2.3.3.8", - "4.1.3.9 2.3.3.11", - "4.1.3.10 2.3.3.7", - "4.1.3.11 2.3.3.12", - "4.1.3.12 2.3.3.13", - "4.1.3.15 2.2.1.5", - "4.1.3.18 2.2.1.6", - "4.1.3.19 2.5.1.56", - "4.1.3.20 2.5.1.57", - "4.1.3.21 2.3.3.14", - "4.1.3.23 2.3.3.2", - "4.1.3.28 2.3.3.3", - "4.1.3.29 2.3.3.4", - "4.1.3.31 2.3.3.5", - "4.1.3.33 2.3.3.6", - "4.1.3.37 2.2.1.7", - "4.1.3.n1 4.1.3.43", - "4.1.99.4 3.5.99.7", - "4.1.99.6 4.2.3.6", - "4.1.99.7 4.2.3.9", - "4.1.99.8 4.2.3.119 4.2.3.120", - "4.1.99.9 4.2.3.15", - "4.1.99.10 4.2.3.16", - "4.1.99.21 4.2.3.153", - "4.2.1.4 4.2.1.3", - "4.2.1.13 4.3.1.17", - "4.2.1.14 4.3.1.18", - "4.2.1.15 4.4.1.1", - "4.2.1.16 4.3.1.19", - "4.2.1.21 4.2.1.22", - "4.2.1.26 4.3.1.9", - "4.2.1.29 4.99.1.6", - "4.2.1.37 3.3.2.4", - "4.2.1.38 4.3.1.20", - "4.2.1.52 4.3.3.7", - "4.2.1.58 4.2.1.59", - "4.2.1.60 4.2.1.59", - "4.2.1.61 4.2.1.59", - "4.2.1.63 3.3.2.9 3.3.2.10", - "4.2.1.64 3.3.2.9 3.3.2.10", - "4.2.1.71 4.2.1.27", - "4.2.1.72 4.1.1.78", - "4.2.1.86 4.2.1.98", - "4.2.1.89 2.8.3.21 4.2.1.149", - "4.2.1.102 4.2.1.100", - "4.2.1.n1 4.2.1.126", - "4.2.1.n2 4.2.1.134", - "4.2.2.4 4.2.2.20 4.2.2.21", - "4.2.3.14 4.2.3.119 4.2.3.120", - "4.2.3.n1 4.2.3.38", - "4.2.3.n3 4.2.3.56", - "4.2.3.n4 4.2.3.117", - "4.2.3.n5 4.2.3.52", - "4.2.3.n6 4.2.3.113", - "4.2.3.n7 4.2.3.119", - "4.2.3.n8 4.2.3.103", - "4.2.3.n9 4.2.3.44", - "4.2.3.n10 4.2.3.62", - "4.2.3.n12 4.2.3.65", - "4.2.3.n13 4.2.3.75", - "4.2.3.n14 4.2.3.118", - "4.2.99.1 4.2.2.1", - "4.2.99.2 4.2.3.1", - "4.2.99.3 4.2.2.2", - "4.2.99.4 4.2.2.3", - "4.2.99.6 4.2.2.5 4.2.2.20 4.2.2.21", - "4.2.99.7 4.2.3.2", - "4.2.99.8 2.5.1.47", - "4.2.99.9 2.5.1.48", - "4.2.99.10 2.5.1.49", - "4.2.99.11 4.2.3.3", - "4.2.99.13 2.5.1.50", - "4.2.99.14 2.5.1.51", - "4.2.99.15 2.5.1.52", - "4.2.99.16 2.5.1.53", - "4.2.99.17 2.5.1.51", - "4.2.99.19 4.4.1.23", - "4.2.99.n1 4.2.99.20", - "4.3.1.5 4.3.1.23 4.3.1.24 4.3.1.25", - "4.3.1.8 2.5.1.61", - "4.3.1.21 4.3.1.9", - "4.3.1.26 1.21.98.2", - "4.3.3.n1 4.1.99.20", - "4.3.99.1 4.2.1.104", - "4.4.1.7 2.5.1.18", - "4.4.1.18 1.8.3.5", - "4.6.1.3 4.2.3.4", - "4.6.1.4 4.2.3.5", - "4.6.1.5 4.2.3.7", - "4.6.1.7 4.2.3.8", - "4.6.1.8 4.2.3.10", - "4.6.1.9 4.2.3.11", - "4.6.1.10 4.2.3.12", - "4.6.1.11 4.2.3.13", - "5.1.1.n1 5.1.1.20", - "5.1.3.n1 5.1.3.24", - "5.1.3.n2 5.1.3.29", - "5.1.3.n3 5.1.3.32", - "5.2.1.7 3.1.1.64", - "5.3.1.10 3.5.99.6", - "5.3.1.19 2.6.1.16", - "5.3.1.n1 5.3.1.30", - "5.3.1.n2 5.3.1.29", - "5.3.2.n1 5.3.2.5", - "5.3.3.15 5.3.2.7", - "5.3.3.16 5.3.2.8", - "5.3.99.n1 5.3.99.11", - "5.4.1.2 5.4.99.61", - "5.4.2.1 5.4.2.11 5.4.2.12", - "5.4.99.6 5.4.4.2", - "5.4.99.10 5.4.99.11", - "5.4.99.n1 5.4.99.39", - "5.4.99.n2 5.4.99.41", - "5.5.1.21 4.2.1.133", - "5.5.1.n1 5.4.99.62", - "5.5.1.n2 5.5.1.19", - "6.1.1.n1 6.3.1.13", - "6.1.1.n2 6.1.1.27", - "6.2.1.21 6.2.1.30", - "6.2.1.29 6.2.1.7", - "6.2.1.n1 6.2.1.37", - "6.3.1.3 6.3.4.13", - "6.3.1.16 6.3.3.6", - "6.3.2.15 6.3.2.10", - "6.3.2.19 2.3.2.23 2.3.2.27 6.2.1.45", - "6.3.2.22 6.3.1.14", - "6.3.2.27 6.3.2.38 6.3.2.39", - "6.3.2.28 6.3.2.49", - "6.3.2.n1 6.3.2.37", - "6.3.2.n2 6.3.1.19", - "6.3.2.n4 6.3.2.43", - "6.3.2.n5 6.3.2.44", - "6.3.2.n6 6.3.2.41", - "6.3.4.1 6.3.5.2", - "6.3.5.8 2.6.1.85" + "1.1.1.5\t1.1.1.303\t1.1.1.304", + "1.1.1.63\t1.1.1.239", + "1.1.1.68\t1.5.1.20", + "1.1.1.70\t1.2.1.3", + "1.1.1.89\t1.1.1.86", + "1.1.1.109\t1.3.1.28", + "1.1.1.139\t1.1.1.21", + "1.1.1.155\t1.1.1.87", + "1.1.1.158\t1.3.1.98", + "1.1.1.171\t1.5.1.20", + "1.1.1.180\t1.1.1.131", + "1.1.1.182\t1.1.1.198\t1.1.1.227\t1.1.1.228", + "1.1.1.204\t1.17.1.4", + "1.1.1.242\t1.3.1.69", + "1.1.1.246\t1.1.1.348\t4.2.1.139", + "1.1.1.249\t2.5.1.46", + "1.1.1.253\t1.5.1.33", + "1.1.1.n1\t1.1.1.305", + "1.1.1.n2\t1.1.1.300", + "1.1.1.n3\t1.1.1.336", + "1.1.1.n6\t1.1.1.369", + "1.1.1.n7\t1.1.1.320", + "1.1.1.n8\t1.1.1.366", + "1.1.1.n9\t1.1.1.365", + "1.1.1.n10\t1.1.1.301", + "1.1.1.n13\t1.1.1.330", + "1.1.1.n14\t1.1.1.347", + "1.1.2.1\t1.1.5.3", + "1.1.3.1\t1.1.3.15", + "1.1.3.2\t1.13.12.4", + "1.1.3.22\t1.17.3.2", + "1.1.3.24\t1.3.3.12", + "1.1.3.25\t1.1.99.18", + "1.1.3.26\t1.21.3.2", + "1.1.3.32\t1.14.21.1", + "1.1.3.33\t1.14.21.2", + "1.1.3.34\t1.14.21.3", + "1.1.3.35\t1.14.21.4", + "1.1.3.36\t1.14.21.5", + "1.1.4.1\t1.17.4.4", + "1.1.4.2\t1.17.4.5", + "1.1.98.1\t1.1.9.1", + "1.1.99.5\t1.1.5.3", + "1.1.99.8\t1.1.2.7\t1.1.2.8", + "1.1.99.10\t1.1.5.9", + "1.1.99.15\t1.5.1.20", + "1.1.99.16\t1.1.5.4", + "1.1.99.17\t1.1.5.2", + "1.1.99.19\t1.17.99.4", + "1.1.99.23\t1.1.2.6", + "1.1.99.25\t1.1.5.8", + "1.1.99.34\t1.1.98.2", + "1.2.1.1\t1.1.1.284\t4.4.1.22", + "1.2.1.14\t1.1.1.205", + "1.2.1.34\t1.1.1.131", + "1.2.1.35\t1.1.1.203", + "1.2.1.37\t1.17.1.4", + "1.2.1.45\t1.1.1.312", + "1.2.1.55\t1.1.1.279", + "1.2.1.56\t1.1.1.280", + "1.2.1.66\t1.1.1.306", + "1.2.1.n1\t1.2.1.77", + "1.2.1.n3\t1.2.1.86", + "1.2.3.2\t1.17.3.2", + "1.2.3.11\t1.2.3.1", + "1.2.3.12\t1.14.13.82", + "1.2.4.3\t1.2.4.4", + "1.2.7.9\t1.2.7.3", + "1.2.99.1\t1.17.99.4", + "1.2.99.2\t1.2.7.4", + "1.2.99.3\t1.2.5.2", + "1.2.99.4\t1.2.98.1", + "1.3.1.4\t1.3.1.22", + "1.3.1.26\t1.17.1.8", + "1.3.1.30\t1.3.1.22", + "1.3.1.35\t1.14.19.22", + "1.3.1.50\t1.1.1.252", + "1.3.1.52\t1.3.8.5", + "1.3.1.63\t1.21.1.2", + "1.3.1.80\t1.3.7.12", + "1.3.1.n1\t1.3.1.87", + "1.3.2.1\t1.3.8.1", + "1.3.2.2\t1.3.8.7", + "1.3.3.1\t1.3.98.1", + "1.3.3.2\t1.14.19.20", + "1.3.7.10\t1.14.19.8", + "1.3.98.2\t1.3.4.1", + "1.3.99.2\t1.3.8.1", + "1.3.99.3\t1.3.8.7\t1.3.8.8\t1.3.8.9", + "1.3.99.7\t1.3.8.6", + "1.3.99.9\t1.21.99.1", + "1.3.99.10\t1.3.8.4", + "1.3.99.11\t1.3.5.2", + "1.3.99.13\t1.3.8.8", + "1.3.99.15\t1.3.7.8", + "1.3.99.20\t1.3.7.9", + "1.3.99.21\t1.3.8.3", + "1.3.99.22\t1.3.98.3", + "1.3.99.34\t1.3.7.11", + "1.3.99.35\t1.3.7.15", + "1.3.99.n2\t4.1.99.19", + "1.3.99.n3\t1.3.99.36", + "1.4.1.6\t1.21.4.1", + "1.4.3.6\t1.4.3.21\t1.4.3.22", + "1.4.3.9\t1.4.3.4", + "1.4.3.17\t1.3.3.10", + "1.4.4.1\t1.21.4.1", + "1.4.98.1\t1.4.9.1", + "1.4.99.1\t1.4.99.6", + "1.4.99.3\t1.4.9.1", + "1.4.99.4\t1.4.9.2", + "1.5.1.4\t1.5.1.3", + "1.5.1.12\t1.2.1.88", + "1.5.1.13\t1.17.1.5", + "1.5.1.14\t1.5.1.21", + "1.5.1.29\t1.5.1.38\t1.5.1.39\t1.5.1.41", + "1.5.1.35\t1.2.1.19", + "1.5.3.8\t1.3.3.8", + "1.5.3.9\t1.21.3.3", + "1.5.3.11\t1.5.3.13\t1.5.3.14\t1.5.3.15\t1.5.3.16\t1.5.3.17", + "1.5.3.n1\t1.5.3.16", + "1.5.3.n2\t1.5.3.16", + "1.5.3.n3\t1.5.3.13\t1.5.3.16", + "1.5.3.n4\t1.5.3.13", + "1.5.3.n5\t1.5.3.16", + "1.5.3.n6\t1.5.3.14\t1.5.3.15", + "1.5.3.n7\t1.5.3.14\t1.5.3.15", + "1.5.3.n8\t1.5.3.14\t1.5.3.15", + "1.5.3.n9\t1.5.3.14\t1.5.3.15", + "1.5.3.n10\t1.5.3.13", + "1.5.99.1\t1.5.8.3", + "1.5.99.2\t1.5.8.4", + "1.5.99.7\t1.5.8.2", + "1.5.99.8\t1.5.5.2", + "1.5.99.9\t1.5.98.1", + "1.5.99.10\t1.5.8.1", + "1.5.99.11\t1.5.98.2", + "1.6.2.1\t1.6.99.3", + "1.6.4.1\t1.8.1.6", + "1.6.4.2\t1.8.1.7", + "1.6.4.3\t1.8.1.4", + "1.6.4.4\t1.8.1.8", + "1.6.4.5\t1.8.1.9", + "1.6.4.6\t1.8.1.10", + "1.6.4.7\t1.8.1.11", + "1.6.4.8\t1.8.1.12", + "1.6.4.9\t1.8.1.13", + "1.6.4.10\t1.8.1.14", + "1.6.6.1\t1.7.1.1", + "1.6.6.2\t1.7.1.2", + "1.6.6.3\t1.7.1.3", + "1.6.6.4\t1.7.1.4", + "1.6.6.5\t1.7.2.1", + "1.6.6.6\t1.7.1.5", + "1.6.6.7\t1.7.1.6", + "1.6.6.8\t1.7.1.7", + "1.6.6.10\t1.7.1.9", + "1.6.6.11\t1.7.1.10", + "1.6.6.12\t1.7.1.11", + "1.6.6.13\t1.7.1.12", + "1.6.7.1\t1.18.1.2", + "1.6.7.2\t1.18.1.1", + "1.6.8.1\t1.5.1.38\t1.5.1.39\t1.5.1.41", + "1.6.8.2\t1.5.1.30", + "1.6.99.2\t1.6.5.2", + "1.6.99.4\t1.18.1.2", + "1.6.99.5\t1.6.5.11", + "1.6.99.6\t1.6.5.10", + "1.6.99.7\t1.5.1.34", + "1.6.99.8\t1.16.1.3", + "1.6.99.9\t1.16.1.4", + "1.6.99.10\t1.5.1.34", + "1.6.99.11\t1.16.1.5", + "1.6.99.12\t1.16.1.6", + "1.6.99.13\t1.16.1.7", + "1.7.3.4\t1.7.2.6\t1.7.3.6", + "1.7.99.3\t1.7.2.1", + "1.7.99.5\t1.5.1.20", + "1.7.99.6\t1.7.2.4", + "1.7.99.7\t1.7.2.5", + "1.7.99.8\t1.7.2.8", + "1.8.4.5\t1.8.4.13\t1.8.4.14", + "1.8.4.6\t1.8.4.11", + "1.8.6.1\t2.5.1.18", + "1.8.99.3\t1.8.99.5", + "1.8.99.4\t1.8.4.8", + "1.9.3.2\t1.7.2.1", + "1.9.99.1\t1.9.98.1", + "1.10.3.7\t1.21.3.4", + "1.10.3.8\t1.21.3.5", + "1.10.99.1\t1.10.9.1", + "1.10.99.2\t1.10.5.1", + "1.10.99.3\t1.23.5.1", + "1.11.1.4\t1.13.11.11", + "1.12.1.1\t1.12.7.2", + "1.12.7.1\t1.12.7.2", + "1.12.99.1\t1.12.98.1", + "1.12.99.3\t1.12.5.1", + "1.12.99.4\t1.12.98.2", + "1.12.99.5\t1.13.11.47", + "1.13.1.1\t1.13.11.1", + "1.13.1.2\t1.13.11.2", + "1.13.1.3\t1.13.11.3", + "1.13.1.4\t1.13.11.4", + "1.13.1.5\t1.13.11.5", + "1.13.1.6\t1.13.11.6", + "1.13.1.8\t1.13.11.8", + "1.13.1.9\t1.13.11.9", + "1.13.1.10\t1.13.11.10", + "1.13.1.11\t1.13.99.1", + "1.13.1.12\t1.13.11.11", + "1.13.1.13\t1.13.11.12", + "1.13.11.21\t1.13.11.63", + "1.13.11.32\t1.13.12.16", + "1.13.11.44\t1.13.11.60\t5.4.4.6", + "1.13.11.n1\t1.13.11.74", + "1.13.11.n2\t1.13.11.63", + "1.13.12.11\t1.14.13.8", + "1.13.12.12\t1.13.11.67", + "1.13.12.14\t1.14.13.122", + "1.13.99.2\t1.14.12.10", + "1.13.99.4\t1.14.12.9", + "1.13.99.5\t1.13.11.47", + "1.14.1.1\t1.14.14.1", + "1.14.1.2\t1.14.13.9", + "1.14.1.3\t1.14.14.17\t5.4.99.7", + "1.14.1.4\t1.14.99.2", + "1.14.1.5\t1.14.13.5", + "1.14.1.6\t1.14.15.4", + "1.14.1.7\t1.14.14.19", + "1.14.1.8\t1.14.14.16", + "1.14.1.10\t1.14.99.11", + "1.14.2.1\t1.14.17.1", + "1.14.2.2\t1.13.11.27", + "1.14.3.1\t1.14.16.1", + "1.14.11.5\t1.14.11.6", + "1.14.11.n1\t1.14.11.39", + "1.14.11.n3\t1.14.11.56", + "1.14.12.2\t1.14.13.35", + "1.14.12.6\t1.14.13.66", + "1.14.12.20\t1.14.15.17", + "1.14.12.21\t1.14.13.208", + "1.14.12.n1\t1.14.13.208", + "1.14.13.3\t1.14.14.9", + "1.14.13.13\t1.14.15.18", + "1.14.13.15\t1.14.15.15", + "1.14.13.17\t1.14.14.23", + "1.14.13.26\t1.14.18.4", + "1.14.13.41\t1.14.14.36", + "1.14.13.45\t1.14.18.2", + "1.14.13.60\t1.14.14.29", + "1.14.13.68\t1.14.14.37", + "1.14.13.86\t1.14.13.136", + "1.14.13.90\t1.14.15.21", + "1.14.13.95\t1.14.18.8", + "1.14.13.98\t1.14.14.25", + "1.14.13.99\t1.14.14.26", + "1.14.13.100\t1.14.14.29", + "1.14.13.117\t1.14.14.39", + "1.14.13.118\t1.14.14.38", + "1.14.13.124\t1.14.14.40", + "1.14.13.126\t1.14.15.16", + "1.14.13.132\t1.14.14.17", + "1.14.13.159\t1.14.14.24", + "1.14.13.164\t1.13.11.65", + "1.14.13.169\t1.14.18.5", + "1.14.13.207\t1.14.14.31", + "1.14.13.n1\t1.14.14.40", + "1.14.13.n2\t1.14.13.125", + "1.14.13.n3\t1.14.13.127", + "1.14.13.n4\t1.14.15.16", + "1.14.13.n5\t1.14.14.42", + "1.14.13.n8\t1.14.14.41", + "1.14.13.n9\t1.14.13.149", + "1.14.14.2\t1.14.14.1", + "1.14.14.4\t1.14.15.7", + "1.14.14.6\t1.14.13.111", + "1.14.14.7\t1.14.19.9", + "1.14.14.n1\t1.14.99.46", + "1.14.15.2\t1.14.13.162", + "1.14.17.2\t1.14.18.1", + "1.14.19.7\t1.11.1.23", + "1.14.19.n1\t1.14.19.4", + "1.14.19.n2\t1.14.19.5", + "1.14.19.n3\t1.14.19.6", + "1.14.21.6\t1.14.19.20", + "1.14.99.3\t1.14.14.18", + "1.14.99.5\t1.14.19.1", + "1.14.99.6\t1.14.19.2", + "1.14.99.7\t1.14.14.17", + "1.14.99.8\t1.14.14.1", + "1.14.99.9\t1.14.14.19", + "1.14.99.10\t1.14.14.16", + "1.14.99.13\t1.14.13.23", + "1.14.99.16\t1.14.13.72", + "1.14.99.17\t1.14.16.5", + "1.14.99.25\t1.14.19.3", + "1.14.99.27\t1.17.3.4", + "1.14.99.28\t1.14.13.151", + "1.14.99.30\t1.3.5.6", + "1.14.99.31\t1.14.19.24", + "1.14.99.32\t1.14.19.5", + "1.14.99.33\t1.14.19.39", + "1.14.99.36\t1.13.11.63", + "1.14.99.40\t1.13.11.79", + "1.14.99.41\t1.13.11.75", + "1.14.99.n1\t1.13.11.75", + "1.14.99.n2\t1.13.11.71", + "1.14.99.n3\t1.14.99.42", + "1.14.99.n5\t1.13.11.70", + "1.16.98.1\t1.16.9.1", + "1.17.1.2\t1.17.7.4", + "1.17.1.6\t1.1.1.395", + "1.17.1.7\t1.2.1.91", + "1.17.4.3\t1.17.7.1", + "1.17.98.1\t1.1.1.395", + "1.17.99.5\t1.1.1.395", + "1.18.2.1\t1.18.6.1", + "1.18.3.1\t1.12.7.2", + "1.18.96.1\t1.15.1.2", + "1.18.99.1\t1.12.7.2", + "1.20.98.1\t1.20.9.1", + "1.21.3.9\t1.21.98.2", + "1.21.99.2\t1.21.98.1", + "1.22.1.1\t1.21.1.1", + "1.97.1.3\t1.12.98.4", + "1.97.1.5\t1.20.4.1", + "1.97.1.6\t1.20.99.1", + "1.97.1.7\t1.20.4.2", + "1.97.1.8\t1.21.99.5", + "1.97.1.10\t1.21.99.4", + "1.97.1.11\t1.21.99.3", + "1.98.1.1\t1.12.7.2", + "1.99.1.1\t1.14.14.1", + "1.99.1.2\t1.14.16.1", + "1.99.1.5\t1.14.13.9", + "1.99.1.7\t1.14.15.4", + "1.99.1.9\t1.14.14.19", + "1.99.1.11\t1.14.14.16", + "1.99.1.13\t1.14.14.17\t5.4.99.7", + "1.99.1.14\t1.13.11.27", + "1.99.2.1\t1.13.11.12", + "1.99.2.2\t1.13.11.1", + "1.99.2.3\t1.13.11.3", + "1.99.2.4\t1.13.11.4", + "1.99.2.5\t1.13.11.5", + "1.99.2.6\t1.13.99.1", + "2.1.1.23\t2.1.1.319\t2.1.1.320\t2.1.1.321\t2.1.1.322", + "2.1.1.24\t2.1.1.77\t2.1.1.80\t2.1.1.100", + "2.1.1.29\t2.1.1.202\t2.1.1.203\t2.1.1.204", + "2.1.1.31\t2.1.1.221\t2.1.1.228", + "2.1.1.32\t2.1.1.213\t2.1.1.214\t2.1.1.215\t2.1.1.216", + "2.1.1.36\t2.1.1.217\t2.1.1.218\t2.1.1.219\t2.1.1.220", + "2.1.1.48\t2.1.1.181\t2.1.1.182\t2.1.1.183\t2.1.1.184", + "2.1.1.51\t2.1.1.187\t2.1.1.188", + "2.1.1.52\t2.1.1.171\t2.1.1.172\t2.1.1.173\t2.1.1.174", + "2.1.1.58\t2.1.1.57", + "2.1.1.66\t2.1.1.230", + "2.1.1.73\t2.1.1.37", + "2.1.1.81\t2.1.1.49", + "2.1.1.92\t2.1.1.69", + "2.1.1.93\t2.1.1.70", + "2.1.1.124\t2.1.1.319\t2.1.1.320\t2.1.1.321\t2.1.1.322", + "2.1.1.125\t2.1.1.319\t2.1.1.320\t2.1.1.321\t2.1.1.322", + "2.1.1.126\t2.1.1.319\t2.1.1.320\t2.1.1.321\t2.1.1.322", + "2.1.1.134\t2.1.1.129", + "2.1.1.135\t1.16.1.8", + "2.1.1.149\t2.1.1.267", + "2.1.1.n2\t2.1.1.211", + "2.1.1.n3\t2.1.1.280", + "2.1.1.n5\t2.1.1.244", + "2.1.1.n6\t2.1.1.255", + "2.1.1.n9\t2.1.1.274", + "2.1.1.n10\t2.1.1.278", + "2.1.1.n12\t2.1.1.329", + "2.1.1.n13\t2.1.1.301", + "2.1.1.n14\t2.1.1.300", + "2.1.1.n15\t2.1.1.298", + "2.1.1.n16\t2.1.1.297", + "2.1.2.6\t2.1.2.5", + "2.1.2.12\t2.1.1.74", + "2.1.2.n1\t2.1.2.13", + "2.1.3.13\t6.1.2.2", + "2.1.3.14\t6.1.2.2", + "2.3.1.55\t2.3.1.82", + "2.3.1.88\t2.3.1.254\t2.3.1.255\t2.3.1.256\t2.3.1.257\t2.3.1.258\t2.3.1.259", + "2.3.1.104\t2.3.1.25", + "2.3.1.119\t1.1.1.330\t1.3.1.93\t2.3.1.199\t4.2.1.134", + "2.3.1.154\t2.3.1.176", + "2.3.1.n1\t2.3.1.191", + "2.3.1.n8\t2.3.1.199", + "2.3.1.n9\t2.3.1.211", + "2.3.1.n10\t2.3.1.222", + "2.3.1.n11\t2.3.1.223", + "2.4.1.3\t2.4.1.25", + "2.4.1.42\t2.4.1.17", + "2.4.1.45\t2.4.1.47", + "2.4.1.51\t2.4.1.101\t2.4.1.143\t2.4.1.144\t2.4.1.145", + "2.4.1.55\t2.7.8.14", + "2.4.1.59\t2.4.1.17", + "2.4.1.61\t2.4.1.17", + "2.4.1.72\t2.4.2.24", + "2.4.1.76\t2.4.1.17", + "2.4.1.77\t2.4.1.17", + "2.4.1.84\t2.4.1.17", + "2.4.1.89\t2.4.1.69", + "2.4.1.93\t4.2.2.18", + "2.4.1.98\t2.4.1.90", + "2.4.1.107\t2.4.1.17", + "2.4.1.108\t2.4.1.17", + "2.4.1.112\t2.4.1.186", + "2.4.1.119\t2.4.99.18", + "2.4.1.124\t2.4.1.87", + "2.4.1.130\t2.4.1.258\t2.4.1.259\t2.4.1.260\t2.4.1.261", + "2.4.1.151\t2.4.1.87", + "2.4.1.157\t2.4.1.336\t2.4.1.337", + "2.4.1.163\t2.4.1.149", + "2.4.1.169\t2.4.2.39", + "2.4.1.200\t4.2.2.17", + "2.4.1.204\t2.4.2.40", + "2.4.1.233\t2.4.1.115", + "2.4.1.307\t2.4.1.122", + "2.4.1.n1\t2.4.1.245", + "2.4.1.n3\t2.4.1.250", + "2.4.1.n4\t2.4.1.131", + "2.4.1.n5\t2.4.99.16", + "2.4.2.11\t6.3.4.21", + "2.4.2.13\t2.5.1.6", + "2.4.2.23\t2.4.2.2\t2.4.2.3\t2.4.2.4", + "2.4.2.n1\t2.4.2.43", + "2.4.99.11\t2.4.99.1", + "2.5.1.8\t2.5.1.75", + "2.5.1.11\t2.5.1.84\t2.5.1.85", + "2.5.1.12\t2.5.1.18", + "2.5.1.13\t2.5.1.18", + "2.5.1.14\t2.5.1.18", + "2.5.1.33\t2.5.1.82\t2.5.1.83", + "2.5.1.37\t4.4.1.20", + "2.5.1.40\t4.2.3.9", + "2.5.1.64\t2.2.1.9\t4.2.99.20", + "2.5.1.n1\t2.2.1.9", + "2.5.1.n2\t2.5.1.81", + "2.5.1.n3\t2.5.1.73", + "2.5.1.n4\t2.5.1.112", + "2.5.1.n5\t2.5.1.113", + "2.5.1.n6\t2.5.1.105", + "2.5.1.n7\t2.5.1.108", + "2.5.1.n8\t2.5.1.115", + "2.6.1.10\t2.6.1.21", + "2.6.1.25\t2.6.1.24", + "2.6.1.53\t1.4.1.13", + "2.6.1.61\t2.6.1.40", + "2.6.1.91\t2.6.1.34", + "2.6.1.n1\t2.6.1.87", + "2.6.1.n2\t2.6.1.105", + "2.6.2.1\t2.1.4.1", + "2.6.99.4\t2.3.1.234", + "2.7.1.37\t2.7.11.1\t2.7.11.8\t2.7.11.9\t2.7.11.10\t2.7.11.11\t2.7.11.12\t2.7.11.13\t2.7.11.21\t2.7.11.22\t2.7.11.24\t2.7.11.25\t2.7.11.30\t2.7.12.1", + "2.7.1.38\t2.7.11.19", + "2.7.1.69\t2.7.1.191\t2.7.1.192\t2.7.1.193\t2.7.1.194\t2.7.1.195\t2.7.1.196\t2.7.1.197\t2.7.1.198\t2.7.1.199\t2.7.1.200\t2.7.1.201\t2.7.1.202\t2.7.1.203\t2.7.1.204\t2.7.1.205\t2.7.1.206\t2.7.1.207\t2.7.1.208", + "2.7.1.70\t2.7.11.1", + "2.7.1.75\t2.7.1.21", + "2.7.1.96\t2.7.1.86", + "2.7.1.97\t2.7.11.14", + "2.7.1.99\t2.7.11.2", + "2.7.1.104\t2.7.99.1", + "2.7.1.109\t2.7.11.31", + "2.7.1.110\t2.7.11.3", + "2.7.1.111\t2.7.11.27", + "2.7.1.112\t2.7.10.1\t2.7.10.2", + "2.7.1.115\t2.7.11.4", + "2.7.1.116\t2.7.11.5", + "2.7.1.117\t2.7.11.18", + "2.7.1.120\t2.7.11.17", + "2.7.1.123\t2.7.11.17", + "2.7.1.124\t2.7.11.6", + "2.7.1.125\t2.7.11.14", + "2.7.1.126\t2.7.11.15", + "2.7.1.128\t2.7.11.27", + "2.7.1.129\t2.7.11.7", + "2.7.1.131\t2.7.11.29", + "2.7.1.132\t2.7.11.28", + "2.7.1.133\t2.7.1.134", + "2.7.1.135\t2.7.11.26", + "2.7.1.139\t2.7.1.134", + "2.7.1.141\t2.7.11.23", + "2.7.1.152\t2.7.4.21", + "2.7.1.155\t2.7.4.24", + "2.7.1.n1\t2.7.1.170", + "2.7.1.n2\t2.7.1.161", + "2.7.1.n3\t2.7.1.164", + "2.7.1.n4\t2.7.1.173", + "2.7.1.n5\t2.7.1.174", + "2.7.1.n6\t2.7.1.163", + "2.7.1.n7\t2.7.1.176", + "2.7.1.n8\t2.7.1.175", + "2.7.2.5\t6.3.4.16", + "2.7.2.9\t6.3.5.5", + "2.7.3.11\t2.7.13.1", + "2.7.3.12\t2.7.13.2", + "2.7.4.5\t2.7.4.14", + "2.7.4.30\t2.7.8.43", + "2.7.4.n1\t2.7.4.27", + "2.7.4.n2\t2.7.4.28", + "2.7.5.1\t5.4.2.2", + "2.7.5.2\t5.4.2.3", + "2.7.5.3\t5.4.2.11\t5.4.2.12", + "2.7.5.4\t5.4.2.4", + "2.7.5.5\t5.4.2.5", + "2.7.5.6\t5.4.2.7", + "2.7.5.7\t5.4.2.8", + "2.7.7.16\t3.1.27.5", + "2.7.7.17\t3.1.27.1", + "2.7.7.21\t2.7.7.72", + "2.7.7.25\t2.7.7.72", + "2.7.7.26\t3.1.27.3", + "2.7.7.29\t2.7.7.28", + "2.7.7.54\t6.3.2.40", + "2.7.7.55\t6.3.2.40", + "2.7.7.63\t6.3.1.20", + "2.7.7.n2\t2.7.7.67", + "2.7.7.n3\t2.7.7.73", + "2.7.7.n4\t2.7.7.80", + "2.7.7.n5\t2.7.7.75", + "2.7.8.16\t2.7.8.2", + "2.7.8.25\t2.4.2.52", + "2.7.8.30\t2.4.2.53", + "2.7.8.n1\t2.4.2.53", + "2.7.8.n2\t2.7.8.33", + "2.7.11.n1\t2.7.11.32", + "2.7.11.n2\t2.7.11.33", + "2.8.1.n1\t2.8.1.11", + "2.8.2.12\t2.8.2.8", + "2.8.2.n1\t2.8.2.20", + "2.9.1.n1\t2.9.1.2", + "3.1.1.12\t3.1.1.1", + "3.1.1.16\t3.1.1.24\t5.3.3.4", + "3.1.1.18\t3.1.1.17", + "3.1.1.62\t3.5.1.47", + "3.1.1.69\t3.5.1.89", + "3.1.1.n1\t3.5.1.103", + "3.1.2.8\t3.1.2.6", + "3.1.2.24\t3.13.1.3", + "3.1.2.26\t2.8.3.25", + "3.1.2.n1\t3.1.2.28", + "3.1.2.n2\t3.1.2.30", + "3.1.3.30\t3.1.3.31", + "3.1.3.65\t3.1.3.64", + "3.1.3.98\t3.6.1.68", + "3.1.3.n1\t3.1.3.86", + "3.1.3.n2\t3.1.3.84", + "3.1.3.n3\t3.1.3.78", + "3.1.3.n4\t3.1.3.87", + "3.1.3.n5\t3.1.3.93", + "3.1.3.n6\t3.1.3.96", + "3.1.4.5\t3.1.21.1", + "3.1.4.6\t3.1.22.1", + "3.1.4.7\t3.1.31.1", + "3.1.4.8\t3.1.27.3", + "3.1.4.9\t3.1.30.2", + "3.1.4.10\t4.6.1.13", + "3.1.4.15\t2.7.7.89", + "3.1.4.18\t3.1.16.1", + "3.1.4.19\t3.1.13.3", + "3.1.4.20\t3.1.13.1", + "3.1.4.21\t3.1.30.1", + "3.1.4.22\t3.1.27.5", + "3.1.4.23\t3.1.27.1", + "3.1.4.25\t3.1.11.1", + "3.1.4.27\t3.1.11.2", + "3.1.4.28\t3.1.11.3", + "3.1.4.30\t3.1.21.2", + "3.1.4.31\t3.1.11.4", + "3.1.4.36\t3.1.4.43", + "3.1.4.47\t4.6.1.14", + "3.1.4.n1\t3.1.4.53", + "3.1.7.4\t4.2.1.133\t4.2.3.141", + "3.1.22.3\t3.1.21.7", + "3.1.23.1\t3.1.21.4", + "3.1.23.2\t3.1.21.4", + "3.1.23.3\t3.1.21.4", + "3.1.23.4\t3.1.21.4", + "3.1.23.5\t3.1.21.4", + "3.1.23.6\t3.1.21.4", + "3.1.23.7\t3.1.21.4", + "3.1.23.8\t3.1.21.4", + "3.1.23.9\t3.1.21.4", + "3.1.23.10\t3.1.21.4", + "3.1.23.11\t3.1.21.4", + "3.1.23.12\t3.1.21.4", + "3.1.23.13\t3.1.21.4", + "3.1.23.14\t3.1.21.4", + "3.1.23.15\t3.1.21.4", + "3.1.23.16\t3.1.21.4", + "3.1.23.17\t3.1.21.4", + "3.1.23.18\t3.1.21.4", + "3.1.23.19\t3.1.21.4", + "3.1.23.20\t3.1.21.4", + "3.1.23.21\t3.1.21.4", + "3.1.23.22\t3.1.21.4", + "3.1.23.23\t3.1.21.4", + "3.1.23.24\t3.1.21.4", + "3.1.23.25\t3.1.21.4", + "3.1.23.26\t3.1.21.4", + "3.1.23.27\t3.1.21.4", + "3.1.23.28\t3.1.21.4", + "3.1.23.29\t3.1.21.4", + "3.1.23.30\t3.1.21.4", + "3.1.23.31\t3.1.21.4", + "3.1.23.32\t3.1.21.4", + "3.1.23.33\t3.1.21.4", + "3.1.23.34\t3.1.21.4", + "3.1.23.35\t3.1.21.4", + "3.1.23.36\t3.1.21.4", + "3.1.23.37\t3.1.21.4", + "3.1.23.38\t3.1.21.4", + "3.1.23.39\t3.1.21.4", + "3.1.23.40\t3.1.21.4", + "3.1.23.41\t3.1.21.4", + "3.1.23.42\t3.1.21.4", + "3.1.23.43\t3.1.21.4", + "3.1.23.44\t3.1.21.4", + "3.1.23.45\t3.1.21.4", + "3.1.23.46\t3.1.21.4", + "3.1.23.47\t3.1.21.4", + "3.1.23.48\t3.1.21.4", + "3.1.23.49\t3.1.21.4", + "3.1.23.50\t3.1.21.4", + "3.1.23.51\t3.1.21.4", + "3.1.23.52\t3.1.21.4", + "3.1.23.53\t3.1.21.4", + "3.1.23.54\t3.1.21.4", + "3.1.23.55\t3.1.21.4", + "3.1.23.56\t3.1.21.4", + "3.1.23.57\t3.1.21.4", + "3.1.23.58\t3.1.21.4", + "3.1.23.59\t3.1.21.4", + "3.1.24.1\t3.1.21.3", + "3.1.24.2\t3.1.21.3", + "3.1.24.3\t3.1.21.5", + "3.1.24.4\t3.1.21.5", + "3.1.25.2\t4.2.99.18", + "3.1.26.n1\t3.1.26.12", + "3.1.27.9\t4.6.1.16", + "3.2.1.12\t3.2.1.54", + "3.2.1.13\t3.2.1.54", + "3.2.1.29\t3.2.1.52", + "3.2.1.30\t3.2.1.52", + "3.2.1.34\t3.2.1.35", + "3.2.1.69\t3.2.1.41", + "3.2.1.79\t3.2.1.55", + "3.2.1.110\t3.2.1.97", + "3.2.1.138\t4.2.2.15", + "3.2.1.148\t4.4.1.21", + "3.2.1.160\t3.2.1.155", + "3.2.2.18\t3.5.1.52", + "3.2.3.1\t3.2.1.147", + "3.3.1.3\t4.4.1.21", + "3.3.2.3\t3.3.2.9\t3.3.2.10", + "3.3.2.5\t3.3.2.2", + "3.4.1.1\t3.4.11.1", + "3.4.1.2\t3.4.11.2", + "3.4.1.3\t3.4.11.4", + "3.4.1.4\t3.4.11.5", + "3.4.2.1\t3.4.17.1", + "3.4.2.2\t3.4.17.2", + "3.4.2.3\t3.4.17.4", + "3.4.3.1\t3.4.13.18\t3.4.13.19", + "3.4.3.2\t3.4.13.18\t3.4.13.19", + "3.4.3.3\t3.4.13.18\t3.4.13.20", + "3.4.3.4\t3.4.13.5", + "3.4.3.5\t3.4.11.2", + "3.4.3.6\t3.4.13.18\t3.4.13.19", + "3.4.3.7\t3.4.13.9", + "3.4.4.1\t3.4.23.1", + "3.4.4.2\t3.4.23.2", + "3.4.4.3\t3.4.23.4", + "3.4.4.4\t3.4.21.4", + "3.4.4.5\t3.4.21.1", + "3.4.4.6\t3.4.21.1", + "3.4.4.7\t3.4.21.36\t3.4.21.37", + "3.4.4.8\t3.4.21.9", + "3.4.4.9\t3.4.14.1", + "3.4.4.10\t3.4.22.2", + "3.4.4.11\t3.4.22.6", + "3.4.4.12\t3.4.22.3", + "3.4.4.13\t3.4.21.5", + "3.4.4.14\t3.4.21.7", + "3.4.4.15\t3.4.23.15", + "3.4.4.16\t3.4.21.62\t3.4.21.63\t3.4.21.64\t3.4.21.65\t3.4.21.66\t3.4.21.67", + "3.4.4.17\t3.4.21.103\t3.4.23.20\t3.4.23.21\t3.4.23.22\t3.4.23.23\t3.4.23.24\t3.4.23.25\t3.4.23.26\t3.4.23.28\t3.4.23.29\t3.4.23.30", + "3.4.4.18\t3.4.22.10", + "3.4.4.19\t3.4.24.3", + "3.4.4.20\t3.4.22.8", + "3.4.4.21\t3.4.21.34", + "3.4.4.22\t3.4.23.3", + "3.4.4.23\t3.4.23.5", + "3.4.4.24\t3.4.22.32\t3.4.22.33", + "3.4.11.8\t3.4.19.3", + "3.4.11.n1\t3.4.11.24", + "3.4.12.1\t3.4.16.5\t3.4.16.6", + "3.4.12.2\t3.4.17.1", + "3.4.12.3\t3.4.17.2", + "3.4.12.4\t3.4.16.2", + "3.4.12.5\t3.5.1.28", + "3.4.12.6\t3.4.17.8", + "3.4.12.7\t3.4.17.3", + "3.4.12.8\t3.4.17.4", + "3.4.12.10\t3.4.19.9", + "3.4.12.11\t3.4.17.6", + "3.4.12.12\t3.4.16.5\t3.4.16.6", + "3.4.13.1\t3.4.13.18\t3.4.13.19", + "3.4.13.2\t3.4.13.18\t3.4.13.19", + "3.4.13.3\t3.4.13.18\t3.4.13.20", + "3.4.13.6\t3.4.11.2", + "3.4.13.8\t3.4.13.18\t3.4.13.19", + "3.4.13.10\t3.4.19.5", + "3.4.13.11\t3.4.13.18\t3.4.13.19", + "3.4.13.13\t3.4.13.18\t3.4.13.20", + "3.4.13.15\t3.4.13.18\t3.4.13.19", + "3.4.14.3\t3.4.19.1", + "3.4.14.8\t3.4.14.9\t3.4.14.10", + "3.4.15.2\t3.4.19.2", + "3.4.15.3\t3.4.15.5", + "3.4.16.1\t3.4.16.5\t3.4.16.6", + "3.4.16.3\t3.4.16.5\t3.4.16.6", + "3.4.17.7\t3.5.1.28", + "3.4.17.9\t3.4.17.4", + "3.4.19.8\t3.4.17.21", + "3.4.19.10\t3.5.1.28", + "3.4.21.8\t3.4.21.34\t3.4.21.35", + "3.4.21.11\t3.4.21.36\t3.4.21.37", + "3.4.21.13\t3.4.16.5\t3.4.16.6", + "3.4.21.14\t3.4.21.62\t3.4.21.63\t3.4.21.64\t3.4.21.65\t3.4.21.67", + "3.4.21.15\t3.4.21.63", + "3.4.21.28\t3.4.21.74", + "3.4.21.29\t3.4.21.74", + "3.4.21.30\t3.4.21.74", + "3.4.21.31\t3.4.21.68\t3.4.21.73", + "3.4.21.44\t3.4.21.43", + "3.4.21.87\t3.4.23.49", + "3.4.22.4\t3.4.22.32\t3.4.22.33", + "3.4.22.5\t3.4.22.33", + "3.4.22.9\t3.4.21.48", + "3.4.22.11\t3.4.24.56", + "3.4.22.12\t3.4.19.9", + "3.4.22.17\t3.4.22.52\t3.4.22.53", + "3.4.22.18\t3.4.21.26", + "3.4.22.19\t3.4.24.15", + "3.4.22.21\t3.4.25.1", + "3.4.22.22\t3.4.24.37", + "3.4.22.23\t3.4.21.61", + "3.4.23.6\t3.4.21.103\t3.4.23.18\t3.4.23.19\t3.4.23.20\t3.4.23.21\t3.4.23.22\t3.4.23.23\t3.4.23.24\t3.4.23.25\t3.4.23.26\t3.4.23.28\t3.4.23.30", + "3.4.23.7\t3.4.23.20", + "3.4.23.8\t3.4.23.25", + "3.4.23.9\t3.4.23.21", + "3.4.23.10\t3.4.23.22", + "3.4.23.27\t3.4.21.103", + "3.4.23.33\t3.4.21.101", + "3.4.23.37\t3.4.21.100", + "3.4.24.4\t3.4.24.25\t3.4.24.26\t3.4.24.27\t3.4.24.28\t3.4.24.29\t3.4.24.30\t3.4.24.31\t3.4.24.32\t3.4.24.39\t3.4.24.40", + "3.4.24.5\t3.4.22.52\t3.4.22.53\t3.4.25.1", + "3.4.24.8\t3.4.24.3", + "3.4.24.88\t3.4.19.15", + "3.4.99.1\t3.4.23.28", + "3.4.99.4\t3.4.23.12", + "3.4.99.5\t3.4.24.3", + "3.4.99.6\t3.4.24.21", + "3.4.99.10\t3.4.24.56", + "3.4.99.13\t3.4.24.32", + "3.4.99.19\t3.4.23.15", + "3.4.99.22\t3.4.24.29", + "3.4.99.25\t3.4.23.21", + "3.4.99.26\t3.4.21.68\t3.4.21.73", + "3.4.99.28\t3.4.21.60", + "3.4.99.30\t3.4.24.20", + "3.4.99.31\t3.4.24.15", + "3.4.99.32\t3.4.24.20", + "3.4.99.35\t3.4.23.36", + "3.4.99.36\t3.4.21.89", + "3.4.99.38\t3.4.23.17", + "3.4.99.41\t3.4.24.64", + "3.4.99.43\t3.4.23.42", + "3.4.99.44\t3.4.24.55", + "3.4.99.45\t3.4.24.56", + "3.4.99.46\t3.4.25.1", + "3.5.1.34\t3.4.13.5", + "3.5.1.37\t3.5.1.26", + "3.5.1.45\t6.3.4.6", + "3.5.1.80\t3.5.1.25", + "3.5.1.n1\t3.5.1.108", + "3.5.1.n2\t3.5.1.99", + "3.5.1.n4\t3.5.1.110", + "3.5.2.8\t3.5.2.6", + "3.5.3.19\t3.5.1.116", + "3.5.4.14\t3.5.4.5", + "3.5.4.n1\t3.5.4.31", + "3.5.4.n2\t3.5.4.39", + "3.5.4.n3\t3.5.4.45", + "3.5.5.3\t4.2.1.104", + "3.5.99.3\t3.5.4.43", + "3.5.99.4\t3.5.4.42", + "3.6.1.4\t3.6.1.3", + "3.6.1.19\t3.6.1.9", + "3.6.1.30\t3.6.1.59\t3.6.1.62", + "3.6.1.32\t3.6.4.1", + "3.6.1.33\t3.6.4.2", + "3.6.1.34\t3.6.3.14", + "3.6.1.35\t3.6.3.6", + "3.6.1.36\t3.6.3.10", + "3.6.1.37\t3.6.3.9", + "3.6.1.38\t3.6.3.8", + "3.6.1.46\t3.6.5.1", + "3.6.1.47\t3.6.5.2", + "3.6.1.48\t3.6.5.3", + "3.6.1.49\t3.6.5.4", + "3.6.1.50\t3.6.5.5", + "3.6.1.51\t3.6.5.6", + "3.6.1.n4\t3.6.1.67", + "3.6.1.n5\t3.6.1.54", + "3.6.3.13\t3.6.3.1", + "3.6.3.45\t3.6.3.44", + "3.6.3.n1\t3.6.3.54", + "3.7.1.15\t4.2.1.138", + "3.7.1.16\t3.3.2.12", + "3.7.1.n1\t3.7.1.14", + "3.7.1.n2\t3.7.1.22", + "3.8.1.4\t1.21.99.4", + "3.8.2.1\t3.1.8.2", + "4.1.1.10\t4.1.1.12", + "4.1.1.26\t4.1.1.28", + "4.1.1.27\t4.1.1.28", + "4.1.1.n1\t4.1.1.97", + "4.1.1.n2\t4.1.1.94", + "4.1.2.1\t4.1.3.16", + "4.1.2.7\t4.1.2.13", + "4.1.2.15\t2.5.1.54", + "4.1.2.16\t2.5.1.55", + "4.1.2.30\t1.14.14.32", + "4.1.2.31\t4.1.3.16", + "4.1.2.37\t4.1.2.46\t4.1.2.47", + "4.1.2.39\t4.1.2.46\t4.1.2.47", + "4.1.2.n1\t4.1.2.44", + "4.1.2.n3\t4.1.2.53", + "4.1.2.n4\t4.1.2.52", + "4.1.2.n5\t2.2.1.10", + "4.1.2.n6\t4.1.2.56", + "4.1.3.2\t2.3.3.9", + "4.1.3.5\t2.3.3.10", + "4.1.3.7\t2.3.3.1", + "4.1.3.8\t2.3.3.8", + "4.1.3.9\t2.3.3.11", + "4.1.3.10\t2.3.3.7", + "4.1.3.11\t2.3.3.12", + "4.1.3.12\t2.3.3.13", + "4.1.3.15\t2.2.1.5", + "4.1.3.18\t2.2.1.6", + "4.1.3.19\t2.5.1.56", + "4.1.3.20\t2.5.1.57", + "4.1.3.21\t2.3.3.14", + "4.1.3.23\t2.3.3.2", + "4.1.3.28\t2.3.3.3", + "4.1.3.29\t2.3.3.4", + "4.1.3.31\t2.3.3.5", + "4.1.3.33\t2.3.3.6", + "4.1.3.37\t2.2.1.7", + "4.1.3.n1\t4.1.3.43", + "4.1.99.4\t3.5.99.7", + "4.1.99.6\t4.2.3.6", + "4.1.99.7\t4.2.3.9", + "4.1.99.8\t4.2.3.119\t4.2.3.120", + "4.1.99.9\t4.2.3.15", + "4.1.99.10\t4.2.3.16", + "4.1.99.18\t4.1.99.22\t4.6.1.17", + "4.1.99.21\t4.2.3.153", + "4.2.1.4\t4.2.1.3", + "4.2.1.13\t4.3.1.17", + "4.2.1.14\t4.3.1.18", + "4.2.1.15\t4.4.1.1", + "4.2.1.16\t4.3.1.19", + "4.2.1.21\t4.2.1.22", + "4.2.1.26\t4.3.1.9", + "4.2.1.29\t4.99.1.6", + "4.2.1.37\t3.3.2.4", + "4.2.1.38\t4.3.1.20", + "4.2.1.52\t4.3.3.7", + "4.2.1.58\t4.2.1.59", + "4.2.1.60\t4.2.1.59", + "4.2.1.61\t4.2.1.59", + "4.2.1.63\t3.3.2.9\t3.3.2.10", + "4.2.1.64\t3.3.2.9\t3.3.2.10", + "4.2.1.71\t4.2.1.27", + "4.2.1.72\t4.1.1.78", + "4.2.1.86\t4.2.1.98", + "4.2.1.89\t2.8.3.21\t4.2.1.149", + "4.2.1.102\t4.2.1.100", + "4.2.1.n1\t4.2.1.126", + "4.2.1.n2\t4.2.1.134", + "4.2.2.4\t4.2.2.20\t4.2.2.21", + "4.2.3.14\t4.2.3.119\t4.2.3.120", + "4.2.3.n1\t4.2.3.38", + "4.2.3.n3\t4.2.3.56", + "4.2.3.n4\t4.2.3.117", + "4.2.3.n5\t4.2.3.52", + "4.2.3.n6\t4.2.3.113", + "4.2.3.n7\t4.2.3.119", + "4.2.3.n8\t4.2.3.103", + "4.2.3.n9\t4.2.3.44", + "4.2.3.n10\t4.2.3.62", + "4.2.3.n12\t4.2.3.65", + "4.2.3.n13\t4.2.3.75", + "4.2.3.n14\t4.2.3.118", + "4.2.99.1\t4.2.2.1", + "4.2.99.2\t4.2.3.1", + "4.2.99.3\t4.2.2.2", + "4.2.99.4\t4.2.2.3", + "4.2.99.6\t4.2.2.5\t4.2.2.20\t4.2.2.21", + "4.2.99.7\t4.2.3.2", + "4.2.99.8\t2.5.1.47", + "4.2.99.9\t2.5.1.48", + "4.2.99.10\t2.5.1.49", + "4.2.99.11\t4.2.3.3", + "4.2.99.13\t2.5.1.50", + "4.2.99.14\t2.5.1.51", + "4.2.99.15\t2.5.1.52", + "4.2.99.16\t2.5.1.53", + "4.2.99.17\t2.5.1.51", + "4.2.99.19\t4.4.1.23", + "4.2.99.n1\t4.2.99.20", + "4.3.1.5\t4.3.1.23\t4.3.1.24\t4.3.1.25", + "4.3.1.8\t2.5.1.61", + "4.3.1.21\t4.3.1.9", + "4.3.1.26\t1.21.98.2", + "4.3.3.n1\t4.1.99.20", + "4.3.99.1\t4.2.1.104", + "4.4.1.7\t2.5.1.18", + "4.4.1.18\t1.8.3.5", + "4.6.1.3\t4.2.3.4", + "4.6.1.4\t4.2.3.5", + "4.6.1.5\t4.2.3.7", + "4.6.1.7\t4.2.3.8", + "4.6.1.8\t4.2.3.10", + "4.6.1.9\t4.2.3.11", + "4.6.1.10\t4.2.3.12", + "4.6.1.11\t4.2.3.13", + "5.1.1.n1\t5.1.1.20", + "5.1.3.n1\t5.1.3.24", + "5.1.3.n2\t5.1.3.29", + "5.1.3.n3\t5.1.3.32", + "5.2.1.7\t3.1.1.64", + "5.3.1.10\t3.5.99.6", + "5.3.1.19\t2.6.1.16", + "5.3.1.n1\t5.3.1.30", + "5.3.1.n2\t5.3.1.29", + "5.3.2.n1\t5.3.2.5", + "5.3.3.15\t5.3.2.7", + "5.3.3.16\t5.3.2.8", + "5.3.3.20\t5.4.99.64", + "5.3.99.n1\t5.3.99.11", + "5.4.1.2\t5.4.99.61", + "5.4.2.1\t5.4.2.11\t5.4.2.12", + "5.4.99.6\t5.4.4.2", + "5.4.99.10\t5.4.99.11", + "5.4.99.n1\t5.4.99.39", + "5.4.99.n2\t5.4.99.41", + "5.5.1.21\t4.2.1.133", + "5.5.1.n1\t5.4.99.62", + "5.5.1.n2\t5.5.1.19", + "6.1.1.n1\t6.3.1.13", + "6.1.1.n2\t6.1.1.27", + "6.2.1.21\t6.2.1.30", + "6.2.1.29\t6.2.1.7", + "6.2.1.n1\t6.2.1.37", + "6.3.1.3\t6.3.4.13", + "6.3.1.16\t6.3.3.6", + "6.3.2.15\t6.3.2.10", + "6.3.2.19\t2.3.2.23\t2.3.2.27\t6.2.1.45", + "6.3.2.21\t2.3.2.27\t6.2.1.45", + "6.3.2.22\t6.3.1.14", + "6.3.2.27\t6.3.2.38\t6.3.2.39\t", + "6.3.2.28\t6.3.2.49", + "6.3.2.n1\t6.3.2.37", + "6.3.2.n2\t6.3.1.19", + "6.3.2.n4\t6.3.2.43", + "6.3.2.n5\t6.3.2.44", + "6.3.2.n6\t6.3.2.41", + "6.3.4.1\t6.3.5.2", + "6.3.5.8\t2.6.1.85" }; diff --git a/c++/src/objects/seqfeat/ecnum_replaced.txt b/c++/src/objects/seqfeat/ecnum_replaced.txt index cc01d7d8..1a548606 100644 --- a/c++/src/objects/seqfeat/ecnum_replaced.txt +++ b/c++/src/objects/seqfeat/ecnum_replaced.txt @@ -67,6 +67,7 @@ 1.2.4.3 1.2.4.4 1.2.7.9 1.2.7.3 1.2.99.1 1.17.99.4 +1.2.99.2 1.2.7.4 1.2.99.3 1.2.5.2 1.2.99.4 1.2.98.1 1.3.1.4 1.3.1.22 @@ -94,7 +95,9 @@ 1.3.99.15 1.3.7.8 1.3.99.20 1.3.7.9 1.3.99.21 1.3.8.3 +1.3.99.22 1.3.98.3 1.3.99.34 1.3.7.11 +1.3.99.35 1.3.7.15 1.3.99.n2 4.1.99.19 1.3.99.n3 1.3.99.36 1.4.1.6 1.21.4.1 @@ -175,9 +178,11 @@ 1.7.99.5 1.5.1.20 1.7.99.6 1.7.2.4 1.7.99.7 1.7.2.5 +1.7.99.8 1.7.2.8 1.8.4.5 1.8.4.13 1.8.4.14 1.8.4.6 1.8.4.11 1.8.6.1 2.5.1.18 +1.8.99.3 1.8.99.5 1.8.99.4 1.8.4.8 1.9.3.2 1.7.2.1 1.9.99.1 1.9.98.1 @@ -230,30 +235,42 @@ 1.14.3.1 1.14.16.1 1.14.11.5 1.14.11.6 1.14.11.n1 1.14.11.39 +1.14.11.n3 1.14.11.56 1.14.12.2 1.14.13.35 1.14.12.6 1.14.13.66 1.14.12.20 1.14.15.17 1.14.12.21 1.14.13.208 1.14.12.n1 1.14.13.208 1.14.13.3 1.14.14.9 +1.14.13.13 1.14.15.18 1.14.13.15 1.14.15.15 1.14.13.17 1.14.14.23 1.14.13.26 1.14.18.4 +1.14.13.41 1.14.14.36 1.14.13.45 1.14.18.2 -1.14.13.60 1.14.13.100 +1.14.13.60 1.14.14.29 +1.14.13.68 1.14.14.37 1.14.13.86 1.14.13.136 +1.14.13.90 1.14.15.21 1.14.13.95 1.14.18.8 1.14.13.98 1.14.14.25 1.14.13.99 1.14.14.26 +1.14.13.100 1.14.14.29 +1.14.13.117 1.14.14.39 +1.14.13.118 1.14.14.38 +1.14.13.124 1.14.14.40 1.14.13.126 1.14.15.16 1.14.13.132 1.14.14.17 1.14.13.159 1.14.14.24 1.14.13.164 1.13.11.65 1.14.13.169 1.14.18.5 -1.14.13.n1 1.14.13.124 +1.14.13.207 1.14.14.31 +1.14.13.n1 1.14.14.40 1.14.13.n2 1.14.13.125 1.14.13.n3 1.14.13.127 1.14.13.n4 1.14.15.16 +1.14.13.n5 1.14.14.42 +1.14.13.n8 1.14.14.41 1.14.13.n9 1.14.13.149 1.14.14.2 1.14.14.1 1.14.14.4 1.14.15.7 @@ -278,11 +295,13 @@ 1.14.99.16 1.14.13.72 1.14.99.17 1.14.16.5 1.14.99.25 1.14.19.3 +1.14.99.27 1.17.3.4 1.14.99.28 1.14.13.151 1.14.99.30 1.3.5.6 1.14.99.31 1.14.19.24 1.14.99.32 1.14.19.5 1.14.99.33 1.14.19.39 +1.14.99.36 1.13.11.63 1.14.99.40 1.13.11.79 1.14.99.41 1.13.11.75 1.14.99.n1 1.13.11.75 @@ -291,10 +310,11 @@ 1.14.99.n5 1.13.11.70 1.16.98.1 1.16.9.1 1.17.1.2 1.17.7.4 -1.17.1.6 1.17.98.1 +1.17.1.6 1.1.1.395 1.17.1.7 1.2.1.91 1.17.4.3 1.17.7.1 -1.17.99.5 1.17.98.1 +1.17.98.1 1.1.1.395 +1.17.99.5 1.1.1.395 1.18.2.1 1.18.6.1 1.18.3.1 1.12.7.2 1.18.96.1 1.15.1.2 @@ -307,6 +327,7 @@ 1.97.1.5 1.20.4.1 1.97.1.6 1.20.99.1 1.97.1.7 1.20.4.2 +1.97.1.8 1.21.99.5 1.97.1.10 1.21.99.4 1.97.1.11 1.21.99.3 1.98.1.1 1.12.7.2 @@ -351,6 +372,7 @@ 2.1.1.n6 2.1.1.255 2.1.1.n9 2.1.1.274 2.1.1.n10 2.1.1.278 +2.1.1.n12 2.1.1.329 2.1.1.n13 2.1.1.301 2.1.1.n14 2.1.1.300 2.1.1.n15 2.1.1.298 @@ -361,8 +383,10 @@ 2.1.3.13 6.1.2.2 2.1.3.14 6.1.2.2 2.3.1.55 2.3.1.82 +2.3.1.88 2.3.1.254 2.3.1.255 2.3.1.256 2.3.1.257 2.3.1.258 2.3.1.259 2.3.1.104 2.3.1.25 2.3.1.119 1.1.1.330 1.3.1.93 2.3.1.199 4.2.1.134 +2.3.1.154 2.3.1.176 2.3.1.n1 2.3.1.191 2.3.1.n8 2.3.1.199 2.3.1.n9 2.3.1.211 @@ -370,6 +394,7 @@ 2.3.1.n11 2.3.1.223 2.4.1.3 2.4.1.25 2.4.1.42 2.4.1.17 +2.4.1.45 2.4.1.47 2.4.1.51 2.4.1.101 2.4.1.143 2.4.1.144 2.4.1.145 2.4.1.55 2.7.8.14 2.4.1.59 2.4.1.17 @@ -388,10 +413,13 @@ 2.4.1.124 2.4.1.87 2.4.1.130 2.4.1.258 2.4.1.259 2.4.1.260 2.4.1.261 2.4.1.151 2.4.1.87 +2.4.1.157 2.4.1.336 2.4.1.337 +2.4.1.163 2.4.1.149 2.4.1.169 2.4.2.39 2.4.1.200 4.2.2.17 2.4.1.204 2.4.2.40 2.4.1.233 2.4.1.115 +2.4.1.307 2.4.1.122 2.4.1.n1 2.4.1.245 2.4.1.n3 2.4.1.250 2.4.1.n4 2.4.1.131 @@ -400,6 +428,7 @@ 2.4.2.13 2.5.1.6 2.4.2.23 2.4.2.2 2.4.2.3 2.4.2.4 2.4.2.n1 2.4.2.43 +2.4.99.11 2.4.99.1 2.5.1.8 2.5.1.75 2.5.1.11 2.5.1.84 2.5.1.85 2.5.1.12 2.5.1.18 @@ -428,7 +457,7 @@ 2.6.99.4 2.3.1.234 2.7.1.37 2.7.11.1 2.7.11.8 2.7.11.9 2.7.11.10 2.7.11.11 2.7.11.12 2.7.11.13 2.7.11.21 2.7.11.22 2.7.11.24 2.7.11.25 2.7.11.30 2.7.12.1 2.7.1.38 2.7.11.19 -2.7.1.69 2.7.1.191 +2.7.1.69 2.7.1.191 2.7.1.192 2.7.1.193 2.7.1.194 2.7.1.195 2.7.1.196 2.7.1.197 2.7.1.198 2.7.1.199 2.7.1.200 2.7.1.201 2.7.1.202 2.7.1.203 2.7.1.204 2.7.1.205 2.7.1.206 2.7.1.207 2.7.1.208 2.7.1.70 2.7.11.1 2.7.1.75 2.7.1.21 2.7.1.96 2.7.1.86 @@ -470,6 +499,7 @@ 2.7.3.11 2.7.13.1 2.7.3.12 2.7.13.2 2.7.4.5 2.7.4.14 +2.7.4.30 2.7.8.43 2.7.4.n1 2.7.4.27 2.7.4.n2 2.7.4.28 2.7.5.1 5.4.2.2 @@ -511,10 +541,12 @@ 3.1.1.n1 3.5.1.103 3.1.2.8 3.1.2.6 3.1.2.24 3.13.1.3 +3.1.2.26 2.8.3.25 3.1.2.n1 3.1.2.28 3.1.2.n2 3.1.2.30 3.1.3.30 3.1.3.31 3.1.3.65 3.1.3.64 +3.1.3.98 3.6.1.68 3.1.3.n1 3.1.3.86 3.1.3.n2 3.1.3.84 3.1.3.n3 3.1.3.78 @@ -625,6 +657,7 @@ 3.2.3.1 3.2.1.147 3.3.1.3 4.4.1.21 3.3.2.3 3.3.2.9 3.3.2.10 +3.3.2.5 3.3.2.2 3.4.1.1 3.4.11.1 3.4.1.2 3.4.11.2 3.4.1.3 3.4.11.4 @@ -728,6 +761,7 @@ 3.4.24.4 3.4.24.25 3.4.24.26 3.4.24.27 3.4.24.28 3.4.24.29 3.4.24.30 3.4.24.31 3.4.24.32 3.4.24.39 3.4.24.40 3.4.24.5 3.4.22.52 3.4.22.53 3.4.25.1 3.4.24.8 3.4.24.3 +3.4.24.88 3.4.19.15 3.4.99.1 3.4.23.28 3.4.99.4 3.4.23.12 3.4.99.5 3.4.24.3 @@ -762,8 +796,12 @@ 3.5.4.14 3.5.4.5 3.5.4.n1 3.5.4.31 3.5.4.n2 3.5.4.39 +3.5.4.n3 3.5.4.45 3.5.5.3 4.2.1.104 +3.5.99.3 3.5.4.43 +3.5.99.4 3.5.4.42 3.6.1.4 3.6.1.3 +3.6.1.19 3.6.1.9 3.6.1.30 3.6.1.59 3.6.1.62 3.6.1.32 3.6.4.1 3.6.1.33 3.6.4.2 @@ -798,6 +836,7 @@ 4.1.2.7 4.1.2.13 4.1.2.15 2.5.1.54 4.1.2.16 2.5.1.55 +4.1.2.30 1.14.14.32 4.1.2.31 4.1.3.16 4.1.2.37 4.1.2.46 4.1.2.47 4.1.2.39 4.1.2.46 4.1.2.47 @@ -832,6 +871,7 @@ 4.1.99.8 4.2.3.119 4.2.3.120 4.1.99.9 4.2.3.15 4.1.99.10 4.2.3.16 +4.1.99.18 4.1.99.22 4.6.1.17 4.1.99.21 4.2.3.153 4.2.1.4 4.2.1.3 4.2.1.13 4.3.1.17 @@ -915,6 +955,7 @@ 5.3.2.n1 5.3.2.5 5.3.3.15 5.3.2.7 5.3.3.16 5.3.2.8 +5.3.3.20 5.4.99.64 5.3.99.n1 5.3.99.11 5.4.1.2 5.4.99.61 5.4.2.1 5.4.2.11 5.4.2.12 @@ -934,8 +975,9 @@ 6.3.1.16 6.3.3.6 6.3.2.15 6.3.2.10 6.3.2.19 2.3.2.23 2.3.2.27 6.2.1.45 +6.3.2.21 2.3.2.27 6.2.1.45 6.3.2.22 6.3.1.14 -6.3.2.27 6.3.2.38 6.3.2.39 +6.3.2.27 6.3.2.38 6.3.2.39 6.3.2.28 6.3.2.49 6.3.2.n1 6.3.2.37 6.3.2.n2 6.3.1.19 diff --git a/c++/src/objects/seqfeat/ecnum_specific.inc b/c++/src/objects/seqfeat/ecnum_specific.inc index 074a3cd2..5e9afdc7 100644 --- a/c++/src/objects/seqfeat/ecnum_specific.inc +++ b/c++/src/objects/seqfeat/ecnum_specific.inc @@ -1,4 +1,4 @@ -/* $Id: ecnum_specific.inc 514388 2016-09-21 15:37:12Z ivanov $ +/* $Id: ecnum_specific.inc 540671 2017-07-10 15:05:11Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,5804 +31,5995 @@ */ static const char* const kECNum_specific[] = { - "1.1.1.1 Alcohol dehydrogenase", - "1.1.1.2 Alcohol dehydrogenase (NADP(+))", - "1.1.1.3 Homoserine dehydrogenase", - "1.1.1.4 (R,R)-butanediol dehydrogenase", - "1.1.1.6 Glycerol dehydrogenase", - "1.1.1.7 Propanediol-phosphate dehydrogenase", - "1.1.1.8 Glycerol-3-phosphate dehydrogenase (NAD(+))", - "1.1.1.9 D-xylulose reductase", - "1.1.1.10 L-xylulose reductase", - "1.1.1.11 D-arabinitol 4-dehydrogenase", - "1.1.1.12 L-arabinitol 4-dehydrogenase", - "1.1.1.13 L-arabinitol 2-dehydrogenase", - "1.1.1.14 L-iditol 2-dehydrogenase", - "1.1.1.15 D-iditol 2-dehydrogenase", - "1.1.1.16 Galactitol 2-dehydrogenase", - "1.1.1.17 Mannitol-1-phosphate 5-dehydrogenase", - "1.1.1.18 Inositol 2-dehydrogenase", - "1.1.1.19 Glucuronate reductase", - "1.1.1.20 Glucuronolactone reductase", - "1.1.1.21 Aldehyde reductase", - "1.1.1.22 UDP-glucose 6-dehydrogenase", - "1.1.1.23 Histidinol dehydrogenase", - "1.1.1.24 Quinate dehydrogenase", - "1.1.1.25 Shikimate dehydrogenase", - "1.1.1.26 Glyoxylate reductase", - "1.1.1.27 L-lactate dehydrogenase", - "1.1.1.28 D-lactate dehydrogenase", - "1.1.1.29 Glycerate dehydrogenase", - "1.1.1.30 3-hydroxybutyrate dehydrogenase", - "1.1.1.31 3-hydroxyisobutyrate dehydrogenase", - "1.1.1.32 Mevaldate reductase", - "1.1.1.33 Mevaldate reductase (NADPH)", - "1.1.1.34 Hydroxymethylglutaryl-CoA reductase (NADPH)", - "1.1.1.35 3-hydroxyacyl-CoA dehydrogenase", - "1.1.1.36 Acetoacetyl-CoA reductase", - "1.1.1.37 Malate dehydrogenase", - "1.1.1.38 Malate dehydrogenase (oxaloacetate-decarboxylating)", - "1.1.1.39 Malate dehydrogenase (decarboxylating)", - "1.1.1.40 Malate dehydrogenase (oxaloacetate-decarboxylating) (NADP(+))", - "1.1.1.41 Isocitrate dehydrogenase (NAD(+))", - "1.1.1.42 Isocitrate dehydrogenase (NADP(+))", - "1.1.1.43 Phosphogluconate 2-dehydrogenase", - "1.1.1.44 Phosphogluconate dehydrogenase (NADP(+)-dependent, decarboxylating)", - "1.1.1.45 L-gulonate 3-dehydrogenase", - "1.1.1.46 L-arabinose 1-dehydrogenase", - "1.1.1.47 Glucose 1-dehydrogenase (NAD(P)(+))", - "1.1.1.48 D-galactose 1-dehydrogenase", - "1.1.1.49 Glucose-6-phosphate dehydrogenase (NADP(+))", - "1.1.1.50 3-alpha-hydroxysteroid 3-dehydrogenase (Si-specific)", - "1.1.1.51 3(or 17)-beta-hydroxysteroid dehydrogenase", - "1.1.1.52 3-alpha-hydroxycholanate dehydrogenase (NAD(+))", - "1.1.1.53 3-alpha(or 20-beta)-hydroxysteroid dehydrogenase", - "1.1.1.54 Allyl-alcohol dehydrogenase", - "1.1.1.55 Lactaldehyde reductase (NADPH)", - "1.1.1.56 Ribitol 2-dehydrogenase", - "1.1.1.57 Fructuronate reductase", - "1.1.1.58 Tagaturonate reductase", - "1.1.1.59 3-hydroxypropionate dehydrogenase", - "1.1.1.60 2-hydroxy-3-oxopropionate reductase", - "1.1.1.61 4-hydroxybutyrate dehydrogenase", - "1.1.1.62 17-beta-estradiol 17-dehydrogenase", - "1.1.1.64 Testosterone 17-beta-dehydrogenase (NADP(+))", - "1.1.1.65 Pyridoxine 4-dehydrogenase", - "1.1.1.66 Omega-hydroxydecanoate dehydrogenase", - "1.1.1.67 Mannitol 2-dehydrogenase", - "1.1.1.69 Gluconate 5-dehydrogenase", - "1.1.1.71 Alcohol dehydrogenase (NAD(P)(+))", - "1.1.1.72 Glycerol dehydrogenase (NADP(+))", - "1.1.1.73 Octanol dehydrogenase", - "1.1.1.75 (R)-aminopropanol dehydrogenase", - "1.1.1.76 (S,S)-butanediol dehydrogenase", - "1.1.1.77 Lactaldehyde reductase", - "1.1.1.78 Methylglyoxal reductase (NADH)", - "1.1.1.79 Glyoxylate reductase (NADP(+))", - "1.1.1.80 Isopropanol dehydrogenase (NADP(+))", - "1.1.1.81 Hydroxypyruvate reductase", - "1.1.1.82 Malate dehydrogenase (NADP(+))", - "1.1.1.83 D-malate dehydrogenase (decarboxylating)", - "1.1.1.84 Dimethylmalate dehydrogenase", - "1.1.1.85 3-isopropylmalate dehydrogenase", - "1.1.1.86 Ketol-acid reductoisomerase (NADP(+))", - "1.1.1.87 Homoisocitrate dehydrogenase", - "1.1.1.88 Hydroxymethylglutaryl-CoA reductase", - "1.1.1.90 Aryl-alcohol dehydrogenase", - "1.1.1.91 Aryl-alcohol dehydrogenase (NADP(+))", - "1.1.1.92 Oxaloglycolate reductase (decarboxylating)", - "1.1.1.93 Tartrate dehydrogenase", - "1.1.1.94 Glycerol-3-phosphate dehydrogenase (NAD(P)(+))", - "1.1.1.95 Phosphoglycerate dehydrogenase", - "1.1.1.96 Diiodophenylpyruvate reductase", - "1.1.1.97 3-hydroxybenzyl-alcohol dehydrogenase", - "1.1.1.98 (R)-2-hydroxy-fatty-acid dehydrogenase", - "1.1.1.99 (S)-2-hydroxy-fatty-acid dehydrogenase", - "1.1.1.100 3-oxoacyl-[acyl-carrier-protein] reductase", - "1.1.1.101 Acylglycerone-phosphate reductase", - "1.1.1.102 3-dehydrosphinganine reductase", - "1.1.1.103 L-threonine 3-dehydrogenase", - "1.1.1.104 4-oxoproline reductase", - "1.1.1.105 All-trans-retinol dehydrogenase (NAD(+))", - "1.1.1.106 Pantoate 4-dehydrogenase", - "1.1.1.107 Pyridoxal 4-dehydrogenase", - "1.1.1.108 Carnitine 3-dehydrogenase", - "1.1.1.110 Indolelactate dehydrogenase", - "1.1.1.111 3-(imidazol-5-yl)lactate dehydrogenase", - "1.1.1.112 Indanol dehydrogenase", - "1.1.1.113 L-xylose 1-dehydrogenase", - "1.1.1.114 Apiose 1-reductase", - "1.1.1.115 Ribose 1-dehydrogenase (NADP(+))", - "1.1.1.116 D-arabinose 1-dehydrogenase (NAD(+))", - "1.1.1.117 D-arabinose 1-dehydrogenase (NAD(P)(+))", - "1.1.1.118 Glucose 1-dehydrogenase (NAD(+))", - "1.1.1.119 Glucose 1-dehydrogenase (NADP(+))", - "1.1.1.120 Galactose 1-dehydrogenase (NADP(+))", - "1.1.1.121 Aldose 1-dehydrogenase (NAD(+))", - "1.1.1.122 D-threo-aldose 1-dehydrogenase", - "1.1.1.123 Sorbose 5-dehydrogenase (NADP(+))", - "1.1.1.124 Fructose 5-dehydrogenase (NADP(+))", - "1.1.1.125 2-deoxy-D-gluconate 3-dehydrogenase", - "1.1.1.126 2-dehydro-3-deoxy-D-gluconate 6-dehydrogenase", - "1.1.1.127 2-dehydro-3-deoxy-D-gluconate 5-dehydrogenase", - "1.1.1.129 L-threonate 3-dehydrogenase", - "1.1.1.130 3-dehydro-L-gulonate 2-dehydrogenase", - "1.1.1.131 Mannuronate reductase", - "1.1.1.132 GDP-mannose 6-dehydrogenase", - "1.1.1.133 dTDP-4-dehydrorhamnose reductase", - "1.1.1.134 dTDP-6-deoxy-L-talose 4-dehydrogenase", - "1.1.1.135 GDP-6-deoxy-D-talose 4-dehydrogenase", - "1.1.1.136 UDP-N-acetylglucosamine 6-dehydrogenase", - "1.1.1.137 Ribitol-5-phosphate 2-dehydrogenase", - "1.1.1.138 Mannitol 2-dehydrogenase (NADP(+))", - "1.1.1.140 Sorbitol-6-phosphate 2-dehydrogenase", - "1.1.1.141 15-hydroxyprostaglandin dehydrogenase (NAD(+))", - "1.1.1.142 D-pinitol dehydrogenase", - "1.1.1.143 Sequoyitol dehydrogenase", - "1.1.1.144 Perillyl-alcohol dehydrogenase", - "1.1.1.145 3-beta-hydroxy-Delta(5)-steroid dehydrogenase", - "1.1.1.146 11-beta-hydroxysteroid dehydrogenase", - "1.1.1.147 16-alpha-hydroxysteroid dehydrogenase", - "1.1.1.148 Estradiol 17-alpha-dehydrogenase", - "1.1.1.149 20-alpha-hydroxysteroid dehydrogenase", - "1.1.1.150 21-hydroxysteroid dehydrogenase (NAD(+))", - "1.1.1.151 21-hydroxysteroid dehydrogenase (NADP(+))", - "1.1.1.152 3-alpha-hydroxy-5-beta-androstane-17-one 3-alpha-dehydrogenase", - "1.1.1.153 Sepiapterin reductase (L-erythro-7,8-dihydrobiopterin forming)", - "1.1.1.154 Ureidoglycolate dehydrogenase", - "1.1.1.156 Glycerol 2-dehydrogenase (NADP(+))", - "1.1.1.157 3-hydroxybutyryl-CoA dehydrogenase", - "1.1.1.159 7-alpha-hydroxysteroid dehydrogenase", - "1.1.1.160 Dihydrobunolol dehydrogenase", - "1.1.1.162 Erythrulose reductase", - "1.1.1.163 Cyclopentanol dehydrogenase", - "1.1.1.164 Hexadecanol dehydrogenase", - "1.1.1.165 2-alkyn-1-ol dehydrogenase", - "1.1.1.166 Hydroxycyclohexanecarboxylate dehydrogenase", - "1.1.1.167 Hydroxymalonate dehydrogenase", - "1.1.1.168 2-dehydropantolactone reductase (Re-specific)", - "1.1.1.169 2-dehydropantoate 2-reductase", - "1.1.1.170 3-beta-hydroxysteroid-4-alpha-carboxylate 3-dehydrogenase (decarboxylating)", - "1.1.1.172 2-oxoadipate reductase", - "1.1.1.173 L-rhamnose 1-dehydrogenase", - "1.1.1.174 Cyclohexane-1,2-diol dehydrogenase", - "1.1.1.175 D-xylose 1-dehydrogenase", - "1.1.1.176 12-alpha-hydroxysteroid dehydrogenase", - "1.1.1.177 Glycerol-3-phosphate 1-dehydrogenase (NADP(+))", - "1.1.1.178 3-hydroxy-2-methylbutyryl-CoA dehydrogenase", - "1.1.1.179 D-xylose 1-dehydrogenase (NADP(+))", - "1.1.1.181 Cholest-5-ene-3-beta,7-alpha-diol 3-beta-dehydrogenase", - "1.1.1.183 Geraniol dehydrogenase (NADP(+))", - "1.1.1.184 Carbonyl reductase (NADPH)", - "1.1.1.185 L-glycol dehydrogenase", - "1.1.1.186 dTDP-galactose 6-dehydrogenase", - "1.1.1.187 GDP-4-dehydro-D-rhamnose reductase", - "1.1.1.188 Prostaglandin-F synthase", - "1.1.1.189 Prostaglandin-E(2) 9-reductase", - "1.1.1.190 Indole-3-acetaldehyde reductase (NADH)", - "1.1.1.191 Indole-3-acetaldehyde reductase (NADPH)", - "1.1.1.192 Long-chain-alcohol dehydrogenase", - "1.1.1.193 5-amino-6-(5-phosphoribosylamino)uracil reductase", - "1.1.1.194 Coniferyl-alcohol dehydrogenase", - "1.1.1.195 Cinnamyl-alcohol dehydrogenase", - "1.1.1.196 15-hydroxyprostaglandin-D dehydrogenase (NADP(+))", - "1.1.1.197 15-hydroxyprostaglandin dehydrogenase (NADP(+))", - "1.1.1.198 (+)-borneol dehydrogenase", - "1.1.1.199 (S)-usnate reductase", - "1.1.1.200 Aldose-6-phosphate reductase (NADPH)", - "1.1.1.201 7-beta-hydroxysteroid dehydrogenase (NADP(+))", - "1.1.1.202 1,3-propanediol dehydrogenase", - "1.1.1.203 Uronate dehydrogenase", - "1.1.1.205 IMP dehydrogenase", - "1.1.1.206 Tropinone reductase I", - "1.1.1.207 (-)-menthol dehydrogenase", - "1.1.1.208 (+)-neomenthol dehydrogenase", - "1.1.1.209 3(or 17)-alpha-hydroxysteroid dehydrogenase", - "1.1.1.210 3-beta-(or 20-alpha)-hydroxysteroid dehydrogenase", - "1.1.1.211 Long-chain-3-hydroxyacyl-CoA dehydrogenase", - "1.1.1.212 3-oxoacyl-[acyl-carrier-protein] reductase (NADH)", - "1.1.1.213 3-alpha-hydroxysteroid dehydrogenase (Re-specific)", - "1.1.1.214 2-dehydropantolactone reductase (Si-specific)", - "1.1.1.215 Gluconate 2-dehydrogenase", - "1.1.1.216 Farnesol dehydrogenase", - "1.1.1.217 Benzyl-2-methyl-hydroxybutyrate dehydrogenase", - "1.1.1.218 Morphine 6-dehydrogenase", - "1.1.1.219 Dihydrokaempferol 4-reductase", - "1.1.1.220 6-pyruvoyltetrahydropterin 2'-reductase", - "1.1.1.221 Vomifoliol dehydrogenase", - "1.1.1.222 (R)-4-hydroxyphenyllactate dehydrogenase", - "1.1.1.223 Isopiperitenol dehydrogenase", - "1.1.1.224 Mannose-6-phosphate 6-reductase", - "1.1.1.225 Chlordecone reductase", - "1.1.1.226 4-hydroxycyclohexanecarboxylate dehydrogenase", - "1.1.1.227 (-)-borneol dehydrogenase", - "1.1.1.228 (+)-sabinol dehydrogenase", - "1.1.1.229 Diethyl 2-methyl-3-oxosuccinate reductase", - "1.1.1.230 3-alpha-hydroxyglycyrrhetinate dehydrogenase", - "1.1.1.231 15-hydroxyprostaglandin-I dehydrogenase (NADP(+))", - "1.1.1.232 15-hydroxyicosatetraenoate dehydrogenase", - "1.1.1.233 N-acylmannosamine 1-dehydrogenase", - "1.1.1.234 Flavanone 4-reductase", - "1.1.1.235 8-oxocoformycin reductase", - "1.1.1.236 Tropinone reductase II", - "1.1.1.237 Hydroxyphenylpyruvate reductase", - "1.1.1.238 12-beta-hydroxysteroid dehydrogenase", - "1.1.1.239 3-alpha-(17-beta)-hydroxysteroid dehydrogenase (NAD(+))", - "1.1.1.240 N-acetylhexosamine 1-dehydrogenase", - "1.1.1.241 6-endo-hydroxycineole dehydrogenase", - "1.1.1.243 Carveol dehydrogenase", - "1.1.1.244 Methanol dehydrogenase", - "1.1.1.245 Cyclohexanol dehydrogenase", - "1.1.1.247 Codeinone reductase (NADPH)", - "1.1.1.248 Salutaridine reductase (NADPH)", - "1.1.1.250 D-arabinitol 2-dehydrogenase", - "1.1.1.251 Galactitol-1-phosphate 5-dehydrogenase", - "1.1.1.252 Tetrahydroxynaphthalene reductase", - "1.1.1.254 (S)-carnitine 3-dehydrogenase", - "1.1.1.255 Mannitol dehydrogenase", - "1.1.1.256 Fluoren-9-ol dehydrogenase", - "1.1.1.257 4-(hydroxymethyl)benzenesulfonate dehydrogenase", - "1.1.1.258 6-hydroxyhexanoate dehydrogenase", - "1.1.1.259 3-hydroxypimeloyl-CoA dehydrogenase", - "1.1.1.260 Sulcatone reductase", - "1.1.1.261 sn-glycerol-1-phosphate dehydrogenase", - "1.1.1.262 4-hydroxythreonine-4-phosphate dehydrogenase", - "1.1.1.263 1,5-anhydro-D-fructose reductase", - "1.1.1.264 L-idonate 5-dehydrogenase (NAD(P)(+))", - "1.1.1.265 3-methylbutanal reductase", - "1.1.1.266 dTDP-4-dehydro-6-deoxyglucose reductase", - "1.1.1.267 1-deoxy-D-xylulose-5-phosphate reductoisomerase", - "1.1.1.268 2-(R)-hydroxypropyl-CoM dehydrogenase", - "1.1.1.269 2-(S)-hydroxypropyl-CoM dehydrogenase", - "1.1.1.270 3-beta-hydroxysteroid 3-dehydrogenase", - "1.1.1.271 GDP-L-fucose synthase", - "1.1.1.272 D-2-hydroxyacid dehydrogenase (NADP(+))", - "1.1.1.273 Vellosimine dehydrogenase", - "1.1.1.274 2,5-didehydrogluconate reductase (2-dehydro-D-gluconate-forming)", - "1.1.1.275 (+)-trans-carveol dehydrogenase", - "1.1.1.276 Serine 3-dehydrogenase (NADP(+))", - "1.1.1.277 3-beta-hydroxy-5-beta-steroid dehydrogenase", - "1.1.1.278 3-beta-hydroxy-5-alpha-steroid dehydrogenase", - "1.1.1.279 (R)-3-hydroxyacid-ester dehydrogenase", - "1.1.1.280 (S)-3-hydroxyacid-ester dehydrogenase", - "1.1.1.281 GDP-4-dehydro-6-deoxy-D-mannose reductase", - "1.1.1.282 Quinate/shikimate dehydrogenase", - "1.1.1.283 Methylglyoxal reductase (NADPH)", - "1.1.1.284 S-(hydroxymethyl)glutathione dehydrogenase", - "1.1.1.285 3''-deamino-3''-oxonicotianamine reductase", - "1.1.1.286 Isocitrate--homoisocitrate dehydrogenase", - "1.1.1.287 D-arabinitol dehydrogenase (NADP(+))", - "1.1.1.288 Xanthoxin dehydrogenase", - "1.1.1.289 Sorbose reductase", - "1.1.1.290 4-phosphoerythronate dehydrogenase", - "1.1.1.291 2-hydroxymethylglutarate dehydrogenase", - "1.1.1.292 1,5-anhydro-D-fructose reductase (1,5-anhydro-D-mannitol-forming)", - "1.1.1.294 Chlorophyll(ide) b reductase", - "1.1.1.295 Momilactone-A synthase", - "1.1.1.296 Dihydrocarveol dehydrogenase", - "1.1.1.297 Limonene-1,2-diol dehydrogenase", - "1.1.1.298 3-hydroxypropionate dehydrogenase (NADP(+))", - "1.1.1.299 Malate dehydrogenase (NAD(P)(+))", - "1.1.1.300 NADP-retinol dehydrogenase", - "1.1.1.301 D-arabitol-phosphate dehydrogenase", - "1.1.1.302 2,5-diamino-6-(ribosylamino)-4(3H)-pyrimidinone 5'-phosphate reductase", - "1.1.1.303 Diacetyl reductase ((R)-acetoin forming)", - "1.1.1.304 Diacetyl reductase ((S)-acetoin forming)", - "1.1.1.305 UDP-glucuronic acid oxidase (UDP-4-keto-hexauronic acid decarboxylating)", - "1.1.1.306 S-(hydroxymethyl)mycothiol dehydrogenase", - "1.1.1.307 D-xylose reductase", - "1.1.1.308 Sulfopropanediol 3-dehydrogenase", - "1.1.1.309 Phosphonoacetaldehyde reductase (NADH)", - "1.1.1.310 (S)-sulfolactate dehydrogenase", - "1.1.1.311 (S)-1-phenylethanol dehydrogenase", - "1.1.1.312 2-hydroxy-4-carboxymuconate semialdehyde hemiacetal dehydrogenase", - "1.1.1.313 Sulfoacetaldehyde reductase", - "1.1.1.314 Germacrene A alcohol dehydrogenase", - "1.1.1.315 11-cis-retinol dehydrogenase", - "1.1.1.316 L-galactose 1-dehydrogenase", - "1.1.1.317 Perakine reductase", - "1.1.1.318 Eugenol synthase", - "1.1.1.319 Isoeugenol synthase", - "1.1.1.320 Benzil reductase ((S)-benzoin forming)", - "1.1.1.321 Benzil reductase ((R)-benzoin forming)", - "1.1.1.322 (-)-endo-fenchol dehydrogenase", - "1.1.1.323 (+)-thujan-3-ol dehydrogenase", - "1.1.1.324 8-hydroxygeraniol dehydrogenase", - "1.1.1.325 Sepiapterin reductase (L-threo-7,8-dihydrobiopterin forming)", - "1.1.1.326 Zerumbone synthase", - "1.1.1.327 5-exo-hydroxycamphor dehydrogenase", - "1.1.1.328 Nicotine blue oxidoreductase", - "1.1.1.329 2-deoxy-scyllo-inosamine dehydrogenase", - "1.1.1.330 Very-long-chain 3-oxoacyl-CoA reductase", - "1.1.1.331 Secoisolariciresinol dehydrogenase", - "1.1.1.332 Chanoclavine-I dehydrogenase", - "1.1.1.333 Decaprenylphospho-beta-D-erythro-pentofuranosid-2-ulose 2-reductase", - "1.1.1.334 Methylecgonone reductase", - "1.1.1.335 UDP-N-acetyl-2-amino-2-deoxyglucuronate dehydrogenase", - "1.1.1.336 UDP-N-acetyl-D-mannosamine dehydrogenase", - "1.1.1.337 L-2-hydroxycarboxylate dehydrogenase (NAD(+))", - "1.1.1.338 (2R)-3-sulfolactate dehydrogenase (NADP(+))", - "1.1.1.339 dTDP-6-deoxy-L-talose 4-dehydrogenase (NAD(+))", - "1.1.1.340 1-deoxy-11-beta-hydroxypentalenate dehydrogenase", - "1.1.1.341 CDP-abequose synthase", - "1.1.1.342 CDP-paratose synthase", - "1.1.1.343 Phosphogluconate dehydrogenase (NAD(+)-dependent, decarboxylating)", - "1.1.1.344 dTDP-6-deoxy-L-talose 4-dehydrogenase (NAD(P)(+))", - "1.1.1.345 D-2-hydroxyacid dehydrogenase (NAD(+))", - "1.1.1.346 2,5-didehydrogluconate reductase (2-dehydro-L-gulonate-forming)", - "1.1.1.347 Geraniol dehydrogenase (NAD(+))", - "1.1.1.348 Vestitone reductase", - "1.1.1.349 Norsolorinic acid ketoreductase", - "1.1.1.350 Ureidoglycolate dehydrogenase (NAD(+))", - "1.1.1.351 Phosphogluconate dehydrogenase (NAD(P)(+)-dependent, decarboxylating)", - "1.1.1.352 5'-hydroxyaverantin dehydrogenase", - "1.1.1.353 Versiconal hemiacetal acetate reductase", - "1.1.1.354 Farnesol dehydrogenase (NAD(+))", - "1.1.1.355 2'-dehydrokanamycin reductase", - "1.1.1.356 GDP-L-colitose synthase", - "1.1.1.357 3-alpha-hydroxysteroid 3-dehydrogenase", - "1.1.1.358 2-dehydropantolactone reductase", - "1.1.1.359 Aldose 1-dehydrogenase (NAD(P)(+))", - "1.1.1.360 Glucose/galactose 1-dehydrogenase", - "1.1.1.361 Glucose-6-phosphate 3-dehydrogenase", - "1.1.1.362 Aklaviketone reductase", - "1.1.1.363 Glucose-6-phosphate dehydrogenase (NAD(P)(+))", - "1.1.1.364 dTDP-4-dehydro-6-deoxy-alpha-D-gulose 4-ketoreductase", - "1.1.1.365 D-galacturonate reductase", - "1.1.1.366 L-idonate 5-dehydrogenase (NAD(+))", - "1.1.1.367 UDP-2-acetamido-2,6-beta-L-arabino-hexul-4-ose reductase", - "1.1.1.368 6-hydroxycyclohex-1-ene-1-carbonyl-CoA dehydrogenase", - "1.1.1.369 D-chiro-inositol 1-dehydrogenase", - "1.1.1.370 Scyllo-inositol 2-dehydrogenase (NAD(+))", - "1.1.1.371 Scyllo-inositol 2-dehydrogenase (NADP(+))", - "1.1.1.372 D/L-glyceraldehyde reductase", - "1.1.1.373 Sulfolactaldehyde 3-reductase", - "1.1.1.374 UDP-N-acetylglucosamine 3-dehydrogenase", - "1.1.1.375 L-2-hydroxycarboxylate dehydrogenase (NAD(P)(+))", - "1.1.1.376 L-arabinose 1-dehydrogenase (NAD(P)(+))", - "1.1.1.377 L-rhamnose 1-dehydrogenase (NADP(+))", - "1.1.1.378 L-rhamnose 1-dehydrogenase (NAD(P)(+))", - "1.1.1.379 (R)-mandelate dehydrogenase", - "1.1.1.380 L-gulonate 5-dehydrogenase", - "1.1.1.381 3-hydroxy acid dehydrogenase", - "1.1.1.382 Ketol-acid reductoisomerase (NAD(+))", - "1.1.1.383 Ketol-acid reductoisomerase (NAD(P)(+))", - "1.1.1.384 dTDP-3,4-didehydro-2,6-dideoxy-alpha-D-glucose 3-reductase", - "1.1.1.385 Dihydroanticapsin 7-dehydrogenase", - "1.1.1.386 Ipsdienol dehydrogenase", - "1.1.1.387 L-serine 3-dehydrogenase (NAD(+))", - "1.1.1.388 Glucose-6-phosphate dehydrogenase (NAD(+))", - "1.1.1.389 2-dehydro-3-deoxy-L-galactonate 5-dehydrogenase", - "1.1.1.390 Sulfoquinovose 1-dehydrogenase", - "1.1.1.391 3-beta-hydroxycholanate 3-dehydrogenase (NAD(+))", - "1.1.1.392 3-alpha-hydroxycholanate dehydrogenase (NADP(+))", - "1.1.1.393 3-beta-hydroxycholanate 3-dehydrogenase (NADP(+))", - "1.1.1.394 Aurachin B dehydrogenase", - "1.1.1.n4 (-)-trans-carveol dehydrogenase", - "1.1.1.n5 3-methylmalate dehydrogenase", - "1.1.1.n11 Succinic semialdehyde reductase", - "1.1.1.n12 (3R)-hydroxyacyl-CoA dehydrogenase", - "1.1.2.2 Mannitol dehydrogenase (cytochrome)", - "1.1.2.3 L-lactate dehydrogenase (cytochrome)", - "1.1.2.4 D-lactate dehydrogenase (cytochrome)", - "1.1.2.5 D-lactate dehydrogenase (cytochrome c-553)", - "1.1.2.6 Polyvinyl alcohol dehydrogenase (cytochrome)", - "1.1.2.7 Methanol dehydrogenase (cytochrome c)", - "1.1.2.8 Alcohol dehydrogenase (cytochrome c)", - "1.1.3.4 Glucose oxidase", - "1.1.3.5 Hexose oxidase", - "1.1.3.6 Cholesterol oxidase", - "1.1.3.7 Aryl-alcohol oxidase", - "1.1.3.8 L-gulonolactone oxidase", - "1.1.3.9 Galactose oxidase", - "1.1.3.10 Pyranose oxidase", - "1.1.3.11 L-sorbose oxidase", - "1.1.3.12 Pyridoxine 4-oxidase", - "1.1.3.13 Alcohol oxidase", - "1.1.3.14 Catechol oxidase (dimerizing)", - "1.1.3.15 (S)-2-hydroxy-acid oxidase", - "1.1.3.16 Ecdysone oxidase", - "1.1.3.17 Choline oxidase", - "1.1.3.18 Secondary-alcohol oxidase", - "1.1.3.19 4-hydroxymandelate oxidase (decarboxylating)", - "1.1.3.20 Long-chain-alcohol oxidase", - "1.1.3.21 Glycerol-3-phosphate oxidase", - "1.1.3.23 Thiamine oxidase", - "1.1.3.27 Hydroxyphytanate oxidase", - "1.1.3.28 Nucleoside oxidase", - "1.1.3.29 N-acylhexosamine oxidase", - "1.1.3.30 Polyvinyl-alcohol oxidase", - "1.1.3.37 D-arabinono-1,4-lactone oxidase", - "1.1.3.38 Vanillyl-alcohol oxidase", - "1.1.3.39 Nucleoside oxidase (H(2)O(2)-forming)", - "1.1.3.40 D-mannitol oxidase", - "1.1.3.41 Alditol oxidase", - "1.1.3.42 Prosolanapyrone-II oxidase", - "1.1.3.43 Paromamine 6'-oxidase", - "1.1.3.44 6'''-hydroxyneomycin C oxidase", - "1.1.3.45 Aclacinomycin-N oxidase", - "1.1.3.46 4-hydroxymandelate oxidase", - "1.1.3.47 5-(hydroxymethyl)furfural oxidase", - "1.1.3.48 3-deoxy-alpha-D-manno-octulosonate 8-oxidase", - "1.1.5.2 Quinoprotein glucose dehydrogenase (PQQ, quinone)", - "1.1.5.3 Glycerol-3-phosphate dehydrogenase", - "1.1.5.4 Malate dehydrogenase (quinone)", - "1.1.5.5 Alcohol dehydrogenase (quinone)", - "1.1.5.6 Formate dehydrogenase-N", - "1.1.5.7 Cyclic alcohol dehydrogenase (quinone)", - "1.1.5.8 Quinate dehydrogenase (quinone)", - "1.1.5.9 Glucose 1-dehydrogenase (FAD, quinone)", - "1.1.5.10 D-2-hydroxyacid dehydrogenase (quinone)", - "1.1.5.n1 Quinoprotein inositol dehydrogenase", - "1.1.9.1 Alcohol dehydrogenase (azurin)", - "1.1.98.2 Glucose-6-phosphate dehydrogenase (coenzyme-F420)", - "1.1.98.3 Decaprenylphospho-beta-D-ribofuranose 2-dehydrogenase", - "1.1.98.4 F420H(2):quinone oxidoreductase", - "1.1.98.5 Secondary-alcohol dehydrogenase (coenzyme-F420)", - "1.1.99.1 Choline dehydrogenase", - "1.1.99.2 L-2-hydroxyglutarate dehydrogenase", - "1.1.99.3 Gluconate 2-dehydrogenase (acceptor)", - "1.1.99.4 Dehydrogluconate dehydrogenase", - "1.1.99.6 D-lactate dehydrogenase (acceptor)", - "1.1.99.7 Lactate--malate transhydrogenase", - "1.1.99.9 Pyridoxine 5-dehydrogenase", - "1.1.99.11 Fructose 5-dehydrogenase", - "1.1.99.12 Sorbose dehydrogenase", - "1.1.99.13 Glucoside 3-dehydrogenase", - "1.1.99.14 Glycolate dehydrogenase", - "1.1.99.18 Cellobiose dehydrogenase (acceptor)", - "1.1.99.20 Alkan-1-ol dehydrogenase (acceptor)", - "1.1.99.21 D-sorbitol dehydrogenase (acceptor)", - "1.1.99.22 Glycerol dehydrogenase (acceptor)", - "1.1.99.24 Hydroxyacid-oxoacid transhydrogenase", - "1.1.99.26 3-hydroxycyclohexanone dehydrogenase", - "1.1.99.27 (R)-pantolactone dehydrogenase (flavin)", - "1.1.99.28 Glucose-fructose oxidoreductase", - "1.1.99.29 Pyranose dehydrogenase (acceptor)", - "1.1.99.30 2-oxo-acid reductase", - "1.1.99.31 (S)-mandelate dehydrogenase", - "1.1.99.32 L-sorbose 1-dehydrogenase", - "1.1.99.33 Formate dehydrogenase (acceptor)", - "1.1.99.35 Soluble quinoprotein glucose dehydrogenase", - "1.1.99.36 Alcohol dehydrogenase (nicotinoprotein)", - "1.1.99.37 Methanol dehydrogenase (nicotinoprotein)", - "1.1.99.38 2-deoxy-scyllo-inosamine dehydrogenase (AdoMet-dependent)", - "1.1.99.39 D-2-hydroxyglutarate dehydrogenase", - "1.2.1.2 Formate dehydrogenase", - "1.2.1.3 Aldehyde dehydrogenase (NAD(+))", - "1.2.1.4 Aldehyde dehydrogenase (NADP(+))", - "1.2.1.5 Aldehyde dehydrogenase (NAD(P)(+))", - "1.2.1.7 Benzaldehyde dehydrogenase (NADP(+))", - "1.2.1.8 Betaine-aldehyde dehydrogenase", - "1.2.1.9 Glyceraldehyde-3-phosphate dehydrogenase (NADP(+))", - "1.2.1.10 Acetaldehyde dehydrogenase (acetylating)", - "1.2.1.11 Aspartate-semialdehyde dehydrogenase", - "1.2.1.12 Glyceraldehyde-3-phosphate dehydrogenase (phosphorylating)", - "1.2.1.13 Glyceraldehyde-3-phosphate dehydrogenase (NADP(+)) (phosphorylating)", - "1.2.1.15 Malonate-semialdehyde dehydrogenase", - "1.2.1.16 Succinate-semialdehyde dehydrogenase (NAD(P)(+))", - "1.2.1.17 Glyoxylate dehydrogenase (acylating)", - "1.2.1.18 Malonate-semialdehyde dehydrogenase (acetylating)", - "1.2.1.19 Aminobutyraldehyde dehydrogenase", - "1.2.1.20 Glutarate-semialdehyde dehydrogenase", - "1.2.1.21 Glycolaldehyde dehydrogenase", - "1.2.1.22 Lactaldehyde dehydrogenase", - "1.2.1.23 2-oxoaldehyde dehydrogenase (NAD(+))", - "1.2.1.24 Succinate-semialdehyde dehydrogenase (NAD(+))", - "1.2.1.25 2-oxoisovalerate dehydrogenase (acylating)", - "1.2.1.26 2,5-dioxovalerate dehydrogenase", - "1.2.1.27 Methylmalonate-semialdehyde dehydrogenase (CoA acylating)", - "1.2.1.28 Benzaldehyde dehydrogenase (NAD(+))", - "1.2.1.29 Aryl-aldehyde dehydrogenase", - "1.2.1.30 Aryl-aldehyde dehydrogenase (NADP(+))", - "1.2.1.31 L-aminoadipate-semialdehyde dehydrogenase", - "1.2.1.32 Aminomuconate-semialdehyde dehydrogenase", - "1.2.1.33 (R)-dehydropantoate dehydrogenase", - "1.2.1.36 Retinal dehydrogenase", - "1.2.1.38 N-acetyl-gamma-glutamyl-phosphate reductase", - "1.2.1.39 Phenylacetaldehyde dehydrogenase", - "1.2.1.41 Glutamate-5-semialdehyde dehydrogenase", - "1.2.1.42 Hexadecanal dehydrogenase (acylating)", - "1.2.1.43 Formate dehydrogenase (NADP(+))", - "1.2.1.44 Cinnamoyl-CoA reductase", - "1.2.1.46 Formaldehyde dehydrogenase", - "1.2.1.47 4-trimethylammoniobutyraldehyde dehydrogenase", - "1.2.1.48 Long-chain-aldehyde dehydrogenase", - "1.2.1.49 2-oxoaldehyde dehydrogenase (NADP(+))", - "1.2.1.50 Long-chain-fatty-acyl-CoA reductase", - "1.2.1.51 Pyruvate dehydrogenase (NADP(+))", - "1.2.1.52 Oxoglutarate dehydrogenase (NADP(+))", - "1.2.1.53 4-hydroxyphenylacetaldehyde dehydrogenase", - "1.2.1.54 Gamma-guanidinobutyraldehyde dehydrogenase", - "1.2.1.57 Butanal dehydrogenase", - "1.2.1.58 Phenylglyoxylate dehydrogenase (acylating)", - "1.2.1.59 Glyceraldehyde-3-phosphate dehydrogenase (NAD(P)(+)) (phosphorylating)", - "1.2.1.60 5-carboxymethyl-2-hydroxymuconic-semialdehyde dehydrogenase", - "1.2.1.61 4-hydroxymuconic-semialdehyde dehydrogenase", - "1.2.1.62 4-formylbenzenesulfonate dehydrogenase", - "1.2.1.63 6-oxohexanoate dehydrogenase", - "1.2.1.64 4-hydroxybenzaldehyde dehydrogenase (NAD(+))", - "1.2.1.65 Salicylaldehyde dehydrogenase", - "1.2.1.67 Vanillin dehydrogenase", - "1.2.1.68 Coniferyl-aldehyde dehydrogenase", - "1.2.1.69 Fluoroacetaldehyde dehydrogenase", - "1.2.1.70 Glutamyl-tRNA reductase", - "1.2.1.71 Succinylglutamate-semialdehyde dehydrogenase", - "1.2.1.72 Erythrose-4-phosphate dehydrogenase", - "1.2.1.73 Sulfoacetaldehyde dehydrogenase", - "1.2.1.74 Abieta-7,13-dien-18-al dehydrogenase", - "1.2.1.75 Malonyl CoA reductase (malonate semialdehyde-forming)", - "1.2.1.76 Succinate-semialdehyde dehydrogenase (acetylating)", - "1.2.1.77 3,4-dehydroadipyl-CoA semialdehyde dehydrogenase (NADP(+))", - "1.2.1.78 2-formylbenzoate dehydrogenase", - "1.2.1.79 Succinate-semialdehyde dehydrogenase (NADP(+))", - "1.2.1.80 Long-chain acyl-[acyl-carrier-protein] reductase", - "1.2.1.81 Sulfoacetaldehyde dehydrogenase (acylating)", - "1.2.1.82 Beta-apo-4'-carotenal oxygenase", - "1.2.1.83 3-succinoylsemialdehyde-pyridine dehydrogenase", - "1.2.1.84 Alcohol-forming fatty acyl-CoA reductase", - "1.2.1.85 2-hydroxymuconate-6-semialdehyde dehydrogenase", - "1.2.1.86 Geranial dehydrogenase", - "1.2.1.87 Propanal dehydrogenase (CoA-propanoylating)", - "1.2.1.88 L-glutamate gamma-semialdehyde dehydrogenase", - "1.2.1.89 D-glyceraldehyde dehydrogenase (NADP(+))", - "1.2.1.90 Glyceraldehyde-3-phosphate dehydrogenase (NAD(P)(+))", - "1.2.1.91 3-oxo-5,6-dehydrosuberyl-CoA semialdehyde dehydrogenase", - "1.2.1.92 3,6-anhydro-alpha-L-galactose dehydrogenase", - "1.2.1.93 Formate dehydrogenase (NAD(+), ferredoxin)", - "1.2.1.94 Farnesal dehydrogenase", - "1.2.1.95 L-2-aminoadipate reductase", - "1.2.1.96 4-hydroxybenzaldehyde dehydrogenase (NADP(+))", - "1.2.1.97 3-sulfolactaldehyde dehydrogenase", - "1.2.1.n2 Fatty acyl-CoA reductase", - "1.2.2.1 Formate dehydrogenase (cytochrome)", - "1.2.2.3 Formate dehydrogenase (cytochrome c-553)", - "1.2.2.4 Carbon-monoxide dehydrogenase (cytochrome b-561)", - "1.2.3.1 Aldehyde oxidase", - "1.2.3.3 Pyruvate oxidase", - "1.2.3.4 Oxalate oxidase", - "1.2.3.5 Glyoxylate oxidase", - "1.2.3.6 Pyruvate oxidase (CoA-acetylating)", - "1.2.3.7 Indole-3-acetaldehyde oxidase", - "1.2.3.8 Pyridoxal oxidase", - "1.2.3.9 Aryl-aldehyde oxidase", - "1.2.3.13 4-hydroxyphenylpyruvate oxidase", - "1.2.3.14 Abscisic-aldehyde oxidase", - "1.2.4.1 Pyruvate dehydrogenase (acetyl-transferring)", - "1.2.4.2 Oxoglutarate dehydrogenase (succinyl-transferring)", - "1.2.4.4 3-methyl-2-oxobutanoate dehydrogenase (2-methylpropanoyl-transferring)", - "1.2.5.1 Pyruvate dehydrogenase (quinone)", - "1.2.5.2 Aldehyde dehydrogenase (quinone)", - "1.2.5.3 Aerobic carbon monoxide dehydrogenase", - "1.2.7.1 Pyruvate synthase", - "1.2.7.3 2-oxoglutarate synthase", - "1.2.7.4 Anaerobic carbon-monoxide dehydrogenase", - "1.2.7.5 Aldehyde ferredoxin oxidoreductase", - "1.2.7.6 Glyceraldehyde-3-phosphate dehydrogenase (ferredoxin)", - "1.2.7.7 3-methyl-2-oxobutanoate dehydrogenase (ferredoxin)", - "1.2.7.8 Indolepyruvate ferredoxin oxidoreductase", - "1.2.7.10 Oxalate oxidoreductase", - "1.2.7.11 2-oxoacid oxidoreductase (ferredoxin)", - "1.2.98.1 Formaldehyde dismutase", - "1.2.99.2 Carbon-monoxide dehydrogenase (acceptor)", - "1.2.99.5 Formylmethanofuran dehydrogenase", - "1.2.99.6 Carboxylate reductase", - "1.2.99.7 Aldehyde dehydrogenase (FAD-independent)", - "1.2.99.8 Glyceraldehyde dehydrogenase (FAD-containing)", - "1.2.99.9 Formate dehydrogenase (coenzyme F420)", - "1.3.1.1 Dihydrouracil dehydrogenase (NAD(+))", - "1.3.1.2 Dihydropyrimidine dehydrogenase (NADP(+))", - "1.3.1.3 Delta(4)-3-oxosteroid 5-beta-reductase", - "1.3.1.5 Cucurbitacin Delta(23)-reductase", - "1.3.1.6 Fumarate reductase (NADH)", - "1.3.1.7 Meso-tartrate dehydrogenase", - "1.3.1.8 Acyl-CoA dehydrogenase (NADP(+))", - "1.3.1.9 Enoyl-[acyl-carrier-protein] reductase (NADH)", - "1.3.1.10 Enoyl-[acyl-carrier-protein] reductase (NADPH, Si-specific)", - "1.3.1.11 2-coumarate reductase", - "1.3.1.12 Prephenate dehydrogenase", - "1.3.1.13 Prephenate dehydrogenase (NADP(+))", - "1.3.1.14 Dihydroorotate dehydrogenase (NAD(+))", - "1.3.1.15 Dihydroorotate dehydrogenase (NADP(+))", - "1.3.1.16 Beta-nitroacrylate reductase", - "1.3.1.17 3-methyleneoxindole reductase", - "1.3.1.18 Kynurenate-7,8-dihydrodiol dehydrogenase", - "1.3.1.19 Cis-1,2-dihydrobenzene-1,2-diol dehydrogenase", - "1.3.1.20 Trans-1,2-dihydrobenzene-1,2-diol dehydrogenase", - "1.3.1.21 7-dehydrocholesterol reductase", - "1.3.1.22 3-oxo-5-alpha-steroid 4-dehydrogenase (NADP(+))", - "1.3.1.24 Biliverdin reductase", - "1.3.1.25 1,6-dihydroxycyclohexa-2,4-diene-1-carboxylate dehydrogenase", - "1.3.1.27 2-hexadecenal reductase", - "1.3.1.28 2,3-dihydro-2,3-dihydroxybenzoate dehydrogenase", - "1.3.1.29 Cis-1,2-dihydro-1,2-dihydroxynaphthalene dehydrogenase", - "1.3.1.31 2-enoate reductase", - "1.3.1.32 Maleylacetate reductase", - "1.3.1.33 Protochlorophyllide reductase", - "1.3.1.34 2,4-dienoyl-CoA reductase (NADPH)", - "1.3.1.36 Geissoschizine dehydrogenase", - "1.3.1.37 Cis-2-enoyl-CoA reductase (NADPH)", - "1.3.1.38 Trans-2-enoyl-CoA reductase (NADPH)", - "1.3.1.39 Enoyl-[acyl-carrier-protein] reductase (NADPH, Re-specific)", - "1.3.1.40 2-hydroxy-6-oxo-6-phenylhexa-2,4-dienoate reductase", - "1.3.1.41 Xanthommatin reductase", - "1.3.1.42 12-oxophytodienoate reductase", - "1.3.1.43 Arogenate dehydrogenase", - "1.3.1.44 Trans-2-enoyl-CoA reductase (NAD(+))", - "1.3.1.45 2'-hydroxyisoflavone reductase", - "1.3.1.46 Biochanin-A reductase", - "1.3.1.47 Alpha-santonin 1,2-reductase", - "1.3.1.48 15-oxoprostaglandin 13-reductase", - "1.3.1.49 Cis-3,4-dihydrophenanthrene-3,4-diol dehydrogenase", - "1.3.1.51 2'-hydroxydaidzein reductase", - "1.3.1.53 (3S,4R)-3,4-dihydroxycyclohexa-1,5-diene-1,4-dicarboxylate dehydrogenase", - "1.3.1.54 Precorrin-6A reductase", - "1.3.1.56 Cis-2,3-dihydrobiphenyl-2,3-diol dehydrogenase", - "1.3.1.57 Phloroglucinol reductase", - "1.3.1.58 2,3-dihydroxy-2,3-dihydro-p-cumate dehydrogenase", - "1.3.1.60 Dibenzothiophene dihydrodiol dehydrogenase", - "1.3.1.62 Pimeloyl-CoA dehydrogenase", - "1.3.1.64 Phthalate 4,5-cis-dihydrodiol dehydrogenase", - "1.3.1.65 5,6-dihydroxy-3-methyl-2-oxo-1,2,5,6-tetrahydroquinoline dehydrogenase", - "1.3.1.66 Cis-dihydroethylcatechol dehydrogenase", - "1.3.1.67 Cis-1,2-dihydroxy-4-methylcyclohexa-3,5-diene-1-carboxylate dehydrogenase", - "1.3.1.68 1,2-dihydroxy-6-methylcyclohexa-3,5-dienecarboxylate dehydrogenase", - "1.3.1.69 Zeatin reductase", - "1.3.1.70 Delta(14)-sterol reductase", - "1.3.1.71 Delta(24(24(1)))-sterol reductase", - "1.3.1.72 Delta(24)-sterol reductase", - "1.3.1.73 1,2-dihydrovomilenine reductase", - "1.3.1.74 2-alkenal reductase (NAD(P)(+))", - "1.3.1.75 Divinyl chlorophyllide a 8-vinyl-reductase", - "1.3.1.76 Precorrin-2 dehydrogenase", - "1.3.1.77 Anthocyanidin reductase", - "1.3.1.78 Arogenate dehydrogenase (NADP(+))", - "1.3.1.79 Arogenate dehydrogenase (NAD(P)(+))", - "1.3.1.81 (+)-pulegone reductase", - "1.3.1.82 (-)-isopiperitenone reductase", - "1.3.1.83 Geranylgeranyl diphosphate reductase", - "1.3.1.84 Acrylyl-CoA reductase (NADPH)", - "1.3.1.85 Crotonyl-CoA carboxylase/reductase", - "1.3.1.86 Crotonyl-CoA reductase", - "1.3.1.87 3-(cis-5,6-dihydroxycyclohexa-1,3-dien-1-yl)propanoate dehydrogenase", - "1.3.1.88 tRNA-dihydrouridine(16/17) synthase (NAD(P)(+))", - "1.3.1.89 tRNA-dihydrouridine(47) synthase (NAD(P)(+))", - "1.3.1.90 tRNA-dihydrouridine(20a/20b) synthase (NAD(P)(+))", - "1.3.1.91 tRNA-dihydrouridine(20) synthase (NAD(P)(+))", - "1.3.1.92 Artemisinic aldehyde Delta(11(13)) reductase", - "1.3.1.93 Very-long-chain enoyl-CoA reductase", - "1.3.1.94 Polyprenol reductase", - "1.3.1.95 Acryloyl-CoA reductase (NADH)", - "1.3.1.96 Botryococcus squalene synthase", - "1.3.1.97 Botryococcene synthase", - "1.3.1.98 UDP-N-acetylmuramate dehydrogenase", - "1.3.1.99 Iridoid synthase", - "1.3.1.100 Chanoclavine-I aldehyde reductase", - "1.3.1.101 2,3-bis-O-geranylgeranyl-sn-glycerol 1-phosphate reductase (NAD(P)H)", - "1.3.1.102 2-alkenal reductase (NADP(+))", - "1.3.1.103 2-haloacrylate reductase", - "1.3.1.104 Enoyl-[acyl-carrier-protein] reductase", - "1.3.1.105 2-methylene-furan-3-one reductase", - "1.3.1.106 Cobalt-precorrin-6A reductase", - "1.3.1.107 Sanguinarine reductase", - "1.3.1.108 Caffeoyl-CoA reductase", - "1.3.1.109 Butanoyl-CoA dehydrogenase (NAD(+),ferredoxin)", - "1.3.1.110 Lactate dehydrogenase (NAD(+),ferredoxin)", - "1.3.1.111 Geranylgeranyl-bacteriochlorophyllide a reductase", - "1.3.1.n2 Camalexin synthase", - "1.3.1.n3 Curcumin reductase", - "1.3.2.3 L-galactonolactone dehydrogenase", - "1.3.3.3 Coproporphyrinogen oxidase", - "1.3.3.4 Protoporphyrinogen oxidase", - "1.3.3.5 Bilirubin oxidase", - "1.3.3.6 Acyl-CoA oxidase", - "1.3.3.7 Dihydrouracil oxidase", - "1.3.3.8 Tetrahydroberberine oxidase", - "1.3.3.9 Secologanin synthase", - "1.3.3.10 Tryptophan alpha,beta-oxidase", - "1.3.3.11 Pyrroloquinoline-quinone synthase", - "1.3.3.12 L-galactonolactone oxidase", - "1.3.3.13 Albonoursin synthase", - "1.3.3.14 Aclacinomycin-A oxidase", - "1.3.4.1 Fumarate reductase (CoM/CoB)", - "1.3.5.1 Succinate dehydrogenase (quinone)", - "1.3.5.2 Dihydroorotate dehydrogenase (quinone)", - "1.3.5.3 Protoporphyrinogen IX dehydrogenase (menaquinone)", - "1.3.5.4 Fumarate reductase (quinol)", - "1.3.5.5 15-cis-phytoene desaturase", - "1.3.5.6 9,9'-di-cis-zeta-carotene desaturase", - "1.3.7.1 6-hydroxynicotinate reductase", - "1.3.7.2 15,16-dihydrobiliverdin:ferredoxin oxidoreductase", - "1.3.7.3 Phycoerythrobilin:ferredoxin oxidoreductase", - "1.3.7.4 Phytochromobilin:ferredoxin oxidoreductase", - "1.3.7.5 Phycocyanobilin:ferredoxin oxidoreductase", - "1.3.7.6 Phycoerythrobilin synthase", - "1.3.7.7 Ferredoxin:protochlorophyllide reductase (ATP-dependent)", - "1.3.7.8 Benzoyl-CoA reductase", - "1.3.7.9 4-hydroxybenzoyl-CoA reductase", - "1.3.7.11 2,3-bis-O-geranylgeranyl-sn-glycero-phospholipid reductase", - "1.3.7.12 Red chlorophyll catabolite reductase", - "1.3.8.1 Short-chain acyl-CoA dehydrogenase", - "1.3.8.2 4,4'-diapophytoene desaturase (4,4'-diapolycopene-forming)", - "1.3.8.3 (R)-benzylsuccinyl-CoA dehydrogenase", - "1.3.8.4 Isovaleryl-CoA dehydrogenase", - "1.3.8.5 2-methyl-branched-chain-enoyl-CoA reductase", - "1.3.8.6 Glutaryl-CoA dehydrogenase (ETF)", - "1.3.8.7 Medium-chain acyl-CoA dehydrogenase", - "1.3.8.8 Long-chain-acyl-CoA dehydrogenase", - "1.3.8.9 Very-long-chain acyl-CoA dehydrogenase", - "1.3.8.10 Cyclohex-1-ene-1-carbonyl-CoA dehydrogenase", - "1.3.8.11 Cyclohexane-1-carbonyl-CoA dehydrogenase", - "1.3.8.12 (2S)-methylsuccinyl-CoA dehydrogenase", - "1.3.98.1 Dihydroorotate oxidase (fumarate)", - "1.3.99.4 3-oxosteroid 1-dehydrogenase", - "1.3.99.5 3-oxo-5-alpha-steroid 4-dehydrogenase (acceptor)", - "1.3.99.6 3-oxo-5-beta-steroid 4-dehydrogenase", - "1.3.99.8 2-furoyl-CoA dehydrogenase", - "1.3.99.12 2-methylacyl-CoA dehydrogenase", - "1.3.99.14 Cyclohexanone dehydrogenase", - "1.3.99.16 Isoquinoline 1-oxidoreductase", - "1.3.99.17 Quinoline 2-oxidoreductase", - "1.3.99.18 Quinaldate 4-oxidoreductase", - "1.3.99.19 Quinoline-4-carboxylate 2-oxidoreductase", - "1.3.99.22 Coproporphyrinogen dehydrogenase", - "1.3.99.23 All-trans-retinol 13,14-reductase", - "1.3.99.24 2-amino-4-deoxychorismate dehydrogenase", - "1.3.99.25 Carvone reductase", - "1.3.99.26 All-trans-zeta-carotene desaturase", - "1.3.99.27 1-hydroxycarotenoid 3,4-desaturase", - "1.3.99.28 Phytoene desaturase (neurosporene-forming)", - "1.3.99.29 Phytoene desaturase (zeta-carotene-forming)", - "1.3.99.30 Phytoene desaturase (3,4-didehydrolycopene-forming)", - "1.3.99.31 Phytoene desaturase (lycopene-forming)", - "1.3.99.32 Glutaryl-CoA dehydrogenase (acceptor)", - "1.3.99.33 Urocanate reductase", - "1.3.99.35 Chlorophyllide a reductase", - "1.3.99.36 Cypemycin cysteine dehydrogenase (decarboxylating)", - "1.3.99.37 1-hydroxy-2-isopentenylcarotenoid 3,4-desaturase", - "1.3.99.n1 3-hydroxybenzoyl-CoA reductase", - "1.4.1.1 Alanine dehydrogenase", - "1.4.1.2 Glutamate dehydrogenase", - "1.4.1.3 Glutamate dehydrogenase (NAD(P)(+))", - "1.4.1.4 Glutamate dehydrogenase (NADP(+))", - "1.4.1.5 L-amino-acid dehydrogenase", - "1.4.1.7 Serine 2-dehydrogenase", - "1.4.1.8 Valine dehydrogenase (NADP(+))", - "1.4.1.9 Leucine dehydrogenase", - "1.4.1.10 Glycine dehydrogenase", - "1.4.1.11 L-erythro-3,5-diaminohexanoate dehydrogenase", - "1.4.1.12 2,4-diaminopentanoate dehydrogenase", - "1.4.1.13 Glutamate synthase (NADPH)", - "1.4.1.14 Glutamate synthase (NADH)", - "1.4.1.15 Lysine dehydrogenase", - "1.4.1.16 Diaminopimelate dehydrogenase", - "1.4.1.17 N-methylalanine dehydrogenase", - "1.4.1.18 Lysine 6-dehydrogenase", - "1.4.1.19 Tryptophan dehydrogenase", - "1.4.1.20 Phenylalanine dehydrogenase", - "1.4.1.21 Aspartate dehydrogenase", - "1.4.1.23 Valine dehydrogenase (NAD(+))", - "1.4.1.24 3-dehydroquinate synthase II", - "1.4.2.1 Glycine dehydrogenase (cytochrome)", - "1.4.3.1 D-aspartate oxidase", - "1.4.3.2 L-amino-acid oxidase", - "1.4.3.3 D-amino-acid oxidase", - "1.4.3.4 Monoamine oxidase", - "1.4.3.5 Pyridoxal 5'-phosphate synthase", - "1.4.3.7 D-glutamate oxidase", - "1.4.3.8 Ethanolamine oxidase", - "1.4.3.10 Putrescine oxidase", - "1.4.3.11 L-glutamate oxidase", - "1.4.3.12 Cyclohexylamine oxidase", - "1.4.3.13 Protein-lysine 6-oxidase", - "1.4.3.14 L-lysine oxidase", - "1.4.3.15 D-glutamate(D-aspartate) oxidase", - "1.4.3.16 L-aspartate oxidase", - "1.4.3.19 Glycine oxidase", - "1.4.3.20 L-lysine 6-oxidase", - "1.4.3.21 Primary-amine oxidase", - "1.4.3.22 Diamine oxidase", - "1.4.3.23 7-chloro-L-tryptophan oxidase", - "1.4.3.24 Pseudooxynicotine oxidase", - "1.4.4.2 Glycine dehydrogenase (aminomethyl-transferring)", - "1.4.5.1 D-amino acid dehydrogenase (quinone)", - "1.4.7.1 Glutamate synthase (ferredoxin)", - "1.4.9.1 Methylamine dehydrogenase (amicyanin)", - "1.4.9.2 Aralkylamine dehydrogenase (azurin)", - "1.4.99.2 Taurine dehydrogenase", - "1.4.99.5 Glycine dehydrogenase (cyanide-forming)", - "1.4.99.6 D-arginine dehydrogenase", - "1.5.1.1 1-piperideine-2-carboxylate/1-pyrroline-2-carboxylate reductase (NAD(P)H)", - "1.5.1.2 Pyrroline-5-carboxylate reductase", - "1.5.1.3 Dihydrofolate reductase", - "1.5.1.5 Methylenetetrahydrofolate dehydrogenase (NADP(+))", - "1.5.1.6 Formyltetrahydrofolate dehydrogenase", - "1.5.1.7 Saccharopine dehydrogenase (NAD(+), L-lysine-forming)", - "1.5.1.8 Saccharopine dehydrogenase (NADP(+), L-lysine-forming)", - "1.5.1.9 Saccharopine dehydrogenase (NAD(+), L-glutamate-forming)", - "1.5.1.10 Saccharopine dehydrogenase (NADP(+), L-glutamate-forming)", - "1.5.1.11 D-octopine dehydrogenase", - "1.5.1.15 Methylenetetrahydrofolate dehydrogenase (NAD(+))", - "1.5.1.16 D-lysopine dehydrogenase", - "1.5.1.17 Alanopine dehydrogenase", - "1.5.1.18 Ephedrine dehydrogenase", - "1.5.1.19 D-nopaline dehydrogenase", - "1.5.1.20 Methylenetetrahydrofolate reductase (NAD(P)H)", - "1.5.1.21 1-piperideine-2-carboxylate/1-pyrroline-2-carboxylate reductase (NADPH)", - "1.5.1.22 Strombine dehydrogenase", - "1.5.1.23 Tauropine dehydrogenase", - "1.5.1.24 N(5)-(carboxyethyl)ornithine synthase", - "1.5.1.25 Thiomorpholine-carboxylate dehydrogenase", - "1.5.1.26 Beta-alanopine dehydrogenase", - "1.5.1.27 1,2-dehydroreticulinium reductase (NADPH)", - "1.5.1.28 Opine dehydrogenase", - "1.5.1.30 Flavin reductase (NADPH)", - "1.5.1.31 Berberine reductase", - "1.5.1.32 Vomilenine reductase", - "1.5.1.33 Pteridine reductase", - "1.5.1.34 6,7-dihydropteridine reductase", - "1.5.1.36 Flavin reductase (NADH)", - "1.5.1.37 FAD reductase (NADH)", - "1.5.1.38 FMN reductase (NADPH)", - "1.5.1.39 FMN reductase (NAD(P)H)", - "1.5.1.40 8-hydroxy-5-deazaflavin:NADPH oxidoreductase", - "1.5.1.41 Riboflavin reductase (NAD(P)H)", - "1.5.1.42 FMN reductase (NADH)", - "1.5.1.43 Carboxynorspermidine synthase", - "1.5.1.44 Festuclavine dehydrogenase", - "1.5.1.45 FAD reductase (NAD(P)H)", - "1.5.1.46 Agroclavine dehydrogenase", - "1.5.1.47 Dihydromethanopterin reductase (NAD(P)(+))", - "1.5.1.48 2-methyl-1-pyrroline reductase", - "1.5.1.49 1-pyrroline-2-carboxylate reductase (NAD(P)H)", - "1.5.1.50 Dihydromonapterin reductase", - "1.5.3.1 Sarcosine oxidase", - "1.5.3.2 N-methyl-L-amino-acid oxidase", - "1.5.3.4 N(6)-methyl-lysine oxidase", - "1.5.3.5 (S)-6-hydroxynicotine oxidase", - "1.5.3.6 (R)-6-hydroxynicotine oxidase", - "1.5.3.7 L-pipecolate oxidase", - "1.5.3.10 Dimethylglycine oxidase", - "1.5.3.12 Dihydrobenzophenanthridine oxidase", - "1.5.3.13 N(1)-acetylpolyamine oxidase", - "1.5.3.14 Polyamine oxidase (propane-1,3-diamine-forming)", - "1.5.3.15 N(8)-acetylspermidine oxidase (propane-1,3-diamine-forming)", - "1.5.3.16 Spermine oxidase", - "1.5.3.17 Non-specific polyamine oxidase", - "1.5.3.18 L-saccharopine oxidase", - "1.5.3.19 4-methylaminobutanoate oxidase (formaldehyde-forming)", - "1.5.3.20 N-alkylglycine oxidase", - "1.5.3.21 4-methylaminobutanoate oxidase (methylamine-forming)", - "1.5.3.22 Coenzyme F420H(2) oxidase", - "1.5.4.1 Pyrimidodiazepine synthase", - "1.5.5.1 Electron-transferring-flavoprotein dehydrogenase", - "1.5.5.2 Proline dehydrogenase", - "1.5.7.1 Methylenetetrahydrofolate reductase (ferredoxin)", - "1.5.7.2 Coenzyme F420 oxidoreductase (ferredoxin)", - "1.5.8.1 Dimethylamine dehydrogenase", - "1.5.8.2 Trimethylamine dehydrogenase", - "1.5.8.3 Sarcosine dehydrogenase", - "1.5.8.4 Dimethylglycine dehydrogenase", - "1.5.98.1 Methylenetetrahydromethanopterin dehydrogenase", - "1.5.98.2 5,10-methylenetetrahydromethanopterin reductase", - "1.5.99.3 L-pipecolate dehydrogenase", - "1.5.99.4 Nicotine dehydrogenase", - "1.5.99.5 Methylglutamate dehydrogenase", - "1.5.99.6 Spermidine dehydrogenase", - "1.5.99.12 Cytokinin dehydrogenase", - "1.5.99.13 D-proline dehydrogenase", - "1.5.99.14 6-hydroxypseudooxynicotine dehydrogenase", - "1.5.99.15 Dihydromethanopterin reductase (acceptor)", - "1.6.1.1 NAD(P)(+) transhydrogenase (Si-specific)", - "1.6.1.2 NAD(P)(+) transhydrogenase (Re/Si-specific)", - "1.6.1.3 NAD(P)(+) transhydrogenase", - "1.6.1.4 NAD(P)(+) transhydrogenase (ferredoxin)", - "1.6.1.5 Proton-translocating NAD(P)(+) transhydrogenase", - "1.6.2.2 Cytochrome-b5 reductase", - "1.6.2.4 NADPH--hemoprotein reductase", - "1.6.2.5 NADPH--cytochrome-c2 reductase", - "1.6.2.6 Leghemoglobin reductase", - "1.6.3.1 NAD(P)H oxidase (H(2)O(2)-forming)", - "1.6.3.2 NAD(P)H oxidase (H(2)O-forming)", - "1.6.3.3 NADH oxidase (H(2)O(2)-forming)", - "1.6.3.4 NADH oxidase (H(2)O-forming)", - "1.6.3.5 Renalase", - "1.6.5.2 NAD(P)H dehydrogenase (quinone)", - "1.6.5.3 NADH:ubiquinone reductase (H(+)-translocating)", - "1.6.5.4 Monodehydroascorbate reductase (NADH)", - "1.6.5.5 NADPH:quinone reductase", - "1.6.5.6 p-benzoquinone reductase (NADPH)", - "1.6.5.7 2-hydroxy-1,4-benzoquinone reductase", - "1.6.5.8 NADH:ubiquinone reductase (Na(+)-transporting)", - "1.6.5.9 NADH:ubiquinone reductase (non-electrogenic)", - "1.6.5.10 NADPH dehydrogenase (quinone)", - "1.6.5.11 NADH dehydrogenase (quinone)", - "1.6.5.12 Demethylphylloquinone reductase", - "1.6.6.9 Trimethylamine-N-oxide reductase", - "1.6.99.1 NADPH dehydrogenase", - "1.6.99.3 NADH dehydrogenase", - "1.6.99.n1 NADPH dehydrogenase (coenzyme F420 dependent)", - "1.7.1.1 Nitrate reductase (NADH)", - "1.7.1.2 Nitrate reductase (NAD(P)H)", - "1.7.1.3 Nitrate reductase (NADPH)", - "1.7.1.4 Nitrite reductase (NAD(P)H)", - "1.7.1.5 Hyponitrite reductase", - "1.7.1.6 Azobenzene reductase", - "1.7.1.7 GMP reductase", - "1.7.1.9 Nitroquinoline-N-oxide reductase", - "1.7.1.10 Hydroxylamine reductase (NADH)", - "1.7.1.11 4-(dimethylamino)phenylazoxybenzene reductase", - "1.7.1.12 N-hydroxy-2-acetamidofluorene reductase", - "1.7.1.13 PreQ(1) synthase", - "1.7.1.14 Nitric oxide reductase (NAD(P)(+), nitrous oxide-forming)", - "1.7.1.15 Nitrite reductase (NADH)", - "1.7.2.1 Nitrite reductase (NO-forming)", - "1.7.2.2 Nitrite reductase (cytochrome; ammonia-forming)", - "1.7.2.3 Trimethylamine-N-oxide reductase (cytochrome c)", - "1.7.2.4 Nitrous-oxide reductase", - "1.7.2.5 Nitric-oxide reductase (cytochrome c)", - "1.7.2.6 Hydroxylamine dehydrogenase", - "1.7.3.1 Nitroalkane oxidase", - "1.7.3.2 Acetylindoxyl oxidase", - "1.7.3.3 Factor independent urate hydroxylase", - "1.7.3.5 3-aci-nitropropanoate oxidase", - "1.7.3.6 Hydroxylamine oxidase (cytochrome)", - "1.7.5.1 Nitrate reductase (quinone)", - "1.7.5.2 Nitric oxide reductase (menaquinol)", - "1.7.6.1 Nitrite dismutase", - "1.7.7.1 Ferredoxin--nitrite reductase", - "1.7.7.2 Ferredoxin--nitrate reductase", - "1.7.99.1 Hydroxylamine reductase", - "1.7.99.4 Nitrate reductase", - "1.7.99.8 Hydrazine oxidoreductase", - "1.8.1.2 Assimilatory sulfite reductase (NADPH)", - "1.8.1.3 Hypotaurine dehydrogenase", - "1.8.1.4 Dihydrolipoyl dehydrogenase", - "1.8.1.5 2-oxopropyl-CoM reductase (carboxylating)", - "1.8.1.6 Cystine reductase", - "1.8.1.7 Glutathione-disulfide reductase", - "1.8.1.8 Protein-disulfide reductase", - "1.8.1.9 Thioredoxin-disulfide reductase", - "1.8.1.10 CoA-glutathione reductase", - "1.8.1.11 Asparagusate reductase", - "1.8.1.12 Trypanothione-disulfide reductase", - "1.8.1.13 Bis-gamma-glutamylcystine reductase", - "1.8.1.14 CoA-disulfide reductase", - "1.8.1.15 Mycothione reductase", - "1.8.1.16 Glutathione amide reductase", - "1.8.1.17 Dimethylsulfone reductase", - "1.8.1.18 NAD(P)H sulfur oxidoreductase (CoA-dependent)", - "1.8.1.19 Sulfide dehydrogenase", - "1.8.2.1 Sulfite dehydrogenase", - "1.8.2.2 Thiosulfate dehydrogenase", - "1.8.2.3 Sulfide-cytochrome-c reductase (flavocytochrome c)", - "1.8.2.4 Dimethyl sulfide:cytochrome c2 reductase", - "1.8.3.1 Sulfite oxidase", - "1.8.3.2 Thiol oxidase", - "1.8.3.3 Glutathione oxidase", - "1.8.3.4 Methanethiol oxidase", - "1.8.3.5 Prenylcysteine oxidase", - "1.8.3.6 Farnesylcysteine lyase", - "1.8.4.1 Glutathione--homocystine transhydrogenase", - "1.8.4.2 Protein-disulfide reductase (glutathione)", - "1.8.4.3 Glutathione--CoA-glutathione transhydrogenase", - "1.8.4.4 Glutathione--cystine transhydrogenase", - "1.8.4.7 Enzyme-thiol transhydrogenase (glutathione-disulfide)", - "1.8.4.8 Phosphoadenylyl-sulfate reductase (thioredoxin)", - "1.8.4.9 Adenylyl-sulfate reductase (glutathione)", - "1.8.4.10 Adenylyl-sulfate reductase (thioredoxin)", - "1.8.4.11 Peptide-methionine (S)-S-oxide reductase", - "1.8.4.12 Peptide-methionine (R)-S-oxide reductase", - "1.8.4.13 L-methionine (S)-S-oxide reductase", - "1.8.4.14 L-methionine (R)-S-oxide reductase", - "1.8.5.1 Glutathione dehydrogenase (ascorbate)", - "1.8.5.2 Thiosulfate dehydrogenase (quinone)", - "1.8.5.3 Dimethylsulfoxide reductase", - "1.8.5.4 Sulfide:quinone reductase", - "1.8.7.1 Assimilatory sulfite reductase (ferredoxin)", - "1.8.7.2 Ferredoxin:thioredoxin reductase", - "1.8.98.1 CoB--CoM heterodisulfide reductase", - "1.8.98.2 Sulfiredoxin", - "1.8.98.3 Sulfite reductase (coenzyme F420)", - "1.8.99.2 Adenylyl-sulfate reductase", - "1.8.99.3 Hydrogensulfite reductase", - "1.8.99.5 Dissimilatory sulfite reductase", - "1.9.3.1 Cytochrome-c oxidase", - "1.9.6.1 Nitrate reductase (cytochrome)", - "1.9.98.1 Iron--cytochrome-c reductase", - "1.10.1.1 Trans-acenaphthene-1,2-diol dehydrogenase", - "1.10.2.1 L-ascorbate--cytochrome-b5 reductase", - "1.10.2.2 Quinol--cytochrome-c reductase", - "1.10.3.1 Catechol oxidase", - "1.10.3.2 Laccase", - "1.10.3.3 L-ascorbate oxidase", - "1.10.3.4 o-aminophenol oxidase", - "1.10.3.5 3-hydroxyanthranilate oxidase", - "1.10.3.6 Rifamycin-B oxidase", - "1.10.3.9 Photosystem II", - "1.10.3.10 Ubiquinol oxidase (H(+)-transporting)", - "1.10.3.11 Ubiquinol oxidase (non-electrogenic)", - "1.10.3.12 Menaquinol oxidase (H(+)-transporting)", - "1.10.3.13 Caldariellaquinol oxidase (H(+)-transporting)", - "1.10.3.14 Ubiquinol oxidase (electrogenic, non H(+)-transporting)", - "1.10.3.15 Grixazone synthase", - "1.10.5.1 Ribosyldihydronicotinamide dehydrogenase (quinone)", - "1.10.9.1 Plastoquinol--plastocyanin reductase", - "1.11.1.1 NADH peroxidase", - "1.11.1.2 NADPH peroxidase", - "1.11.1.3 Fatty-acid peroxidase", - "1.11.1.5 Cytochrome-c peroxidase", - "1.11.1.6 Catalase", - "1.11.1.7 Peroxidase", - "1.11.1.8 Iodide peroxidase", - "1.11.1.9 Glutathione peroxidase", - "1.11.1.10 Chloride peroxidase", - "1.11.1.11 L-ascorbate peroxidase", - "1.11.1.12 Phospholipid-hydroperoxide glutathione peroxidase", - "1.11.1.13 Manganese peroxidase", - "1.11.1.14 Lignin peroxidase", - "1.11.1.15 Peroxiredoxin", - "1.11.1.16 Versatile peroxidase", - "1.11.1.17 Glutathione amide-dependent peroxidase", - "1.11.1.18 Bromide peroxidase", - "1.11.1.19 Dye decolorizing peroxidase", - "1.11.1.20 Prostamide/prostaglandin F(2-alpha) synthase", - "1.11.1.21 Catalase peroxidase", - "1.11.1.22 Hydroperoxy fatty acid reductase", - "1.11.1.23 (S)-2-hydroxypropylphosphonic acid epoxidase", - "1.11.2.1 Unspecific peroxygenase", - "1.11.2.2 Myeloperoxidase", - "1.11.2.3 Plant seed peroxygenase", - "1.11.2.4 Fatty-acid peroxygenase", - "1.11.2.5 3-methyl-L-tyrosine peroxygenase", - "1.12.1.2 Hydrogen dehydrogenase", - "1.12.1.3 Hydrogen dehydrogenase (NADP(+))", - "1.12.1.4 Hydrogenase (NAD(+), ferredoxin)", - "1.12.1.5 Hydrogen dehydrogenase (NAD(P)(+))", - "1.12.2.1 Cytochrome-c3 hydrogenase", - "1.12.5.1 Hydrogen:quinone oxidoreductase", - "1.12.7.2 Ferredoxin hydrogenase", - "1.12.98.1 Coenzyme F420 hydrogenase", - "1.12.98.2 5,10-methenyltetrahydromethanopterin hydrogenase", - "1.12.98.3 Methanosarcina-phenazine hydrogenase", - "1.12.98.4 Sulfhydrogenase", - "1.12.99.6 Hydrogenase (acceptor)", - "1.13.11.1 Catechol 1,2-dioxygenase", - "1.13.11.2 Catechol 2,3-dioxygenase", - "1.13.11.3 Protocatechuate 3,4-dioxygenase", - "1.13.11.4 Gentisate 1,2-dioxygenase", - "1.13.11.5 Homogentisate 1,2-dioxygenase", - "1.13.11.6 3-hydroxyanthranilate 3,4-dioxygenase", - "1.13.11.8 Protocatechuate 4,5-dioxygenase", - "1.13.11.9 2,5-dihydroxypyridine 5,6-dioxygenase", - "1.13.11.10 7,8-dihydroxykynurenate 8,8a-dioxygenase", - "1.13.11.11 Tryptophan 2,3-dioxygenase", - "1.13.11.12 Linoleate 13S-lipoxygenase", - "1.13.11.14 2,3-dihydroxybenzoate 3,4-dioxygenase", - "1.13.11.15 3,4-dihydroxyphenylacetate 2,3-dioxygenase", - "1.13.11.16 3-carboxyethylcatechol 2,3-dioxygenase", - "1.13.11.17 Indole 2,3-dioxygenase", - "1.13.11.18 Persulfide dioxygenase", - "1.13.11.19 Cysteamine dioxygenase", - "1.13.11.20 Cysteine dioxygenase", - "1.13.11.22 Caffeate 3,4-dioxygenase", - "1.13.11.23 2,3-dihydroxyindole 2,3-dioxygenase", - "1.13.11.24 Quercetin 2,3-dioxygenase", - "1.13.11.25 3,4-dihydroxy-9,10-secoandrosta-1,3,5(10)-triene-9,17-dione 4,5-dioxygenase", - "1.13.11.26 Peptide-tryptophan 2,3-dioxygenase", - "1.13.11.27 4-hydroxyphenylpyruvate dioxygenase", - "1.13.11.28 2,3-dihydroxybenzoate 2,3-dioxygenase", - "1.13.11.29 Stizolobate synthase", - "1.13.11.30 Stizolobinate synthase", - "1.13.11.31 Arachidonate 12-lipoxygenase", - "1.13.11.33 Arachidonate 15-lipoxygenase", - "1.13.11.34 Arachidonate 5-lipoxygenase", - "1.13.11.35 Pyrogallol 1,2-oxygenase", - "1.13.11.36 Chloridazon-catechol dioxygenase", - "1.13.11.37 Hydroxyquinol 1,2-dioxygenase", - "1.13.11.38 1-hydroxy-2-naphthoate 1,2-dioxygenase", - "1.13.11.39 Biphenyl-2,3-diol 1,2-dioxygenase", - "1.13.11.40 Arachidonate 8-lipoxygenase", - "1.13.11.41 2,4'-dihydroxyacetophenone dioxygenase", - "1.13.11.43 Lignostilbene alpha-beta-dioxygenase", - "1.13.11.45 Linoleate 11-lipoxygenase", - "1.13.11.46 4-hydroxymandelate synthase", - "1.13.11.47 3-hydroxy-4-oxoquinoline 2,4-dioxygenase", - "1.13.11.48 3-hydroxy-2-methylquinolin-4-one 2,4-dioxygenase", - "1.13.11.49 Chlorite O(2)-lyase", - "1.13.11.50 Acetylacetone-cleaving enzyme", - "1.13.11.51 9-cis-epoxycarotenoid dioxygenase", - "1.13.11.52 Indoleamine 2,3-dioxygenase", - "1.13.11.53 Acireductone dioxygenase (Ni(2+)-requiring)", - "1.13.11.54 Acireductone dioxygenase (Fe(2+)-requiring)", - "1.13.11.55 Sulfur oxygenase/reductase", - "1.13.11.56 1,2-dihydroxynaphthalene dioxygenase", - "1.13.11.57 Gallate dioxygenase", - "1.13.11.58 Linoleate 9S-lipoxygenase", - "1.13.11.59 Torulene dioxygenase", - "1.13.11.60 Linoleate 8R-lipoxygenase", - "1.13.11.61 Linolenate 9R-lipoxygenase", - "1.13.11.62 Linoleate 10R-lipoxygenase", - "1.13.11.63 Beta-carotene 15,15'-dioxygenase", - "1.13.11.64 5-nitrosalicylate dioxygenase", - "1.13.11.65 Carotenoid isomerooxygenase", - "1.13.11.66 Hydroquinone 1,2-dioxygenase", - "1.13.11.67 8'-apo-beta-carotenoid 14',13'-cleaving dioxygenase", - "1.13.11.68 9-cis-beta-carotene 9',10'-cleaving dioxygenase", - "1.13.11.69 Carlactone synthase", - "1.13.11.70 All-trans-10'-apo-beta-carotenal 13,14-cleaving dioxygenase", - "1.13.11.71 Carotenoid-9',10'-cleaving dioxygenase", - "1.13.11.72 2-hydroxyethylphosphonate dioxygenase", - "1.13.11.73 Methylphosphonate synthase", - "1.13.11.74 2-aminophenol 1,6-dioxygenase", - "1.13.11.75 All-trans-8'-apo-beta-carotenal 15,15'-oxygenase", - "1.13.11.76 2-amino-5-chlorophenol 1,6-dioxygenase", - "1.13.11.77 Oleate 10S-lipoxygenase", - "1.13.11.78 2-amino-1-hydroxyethylphosphonate dioxygenase (glycine-forming)", - "1.13.11.79 5,6-dimethylbenzimidazole synthase", - "1.13.11.80 (3,5-dihydroxyphenyl)acetyl-CoA 1,2-dioxygenase", - "1.13.11.81 7,8-dihydroneopterin oxygenase", - "1.13.11.82 8'-apo-carotenoid 13,14-cleaving dioxygenase", - "1.13.12.1 Arginine 2-monooxygenase", - "1.13.12.2 Lysine 2-monooxygenase", - "1.13.12.3 Tryptophan 2-monooxygenase", - "1.13.12.4 Lactate 2-monooxygenase", - "1.13.12.5 Renilla-luciferin 2-monooxygenase", - "1.13.12.6 Cypridina-luciferin 2-monooxygenase", - "1.13.12.7 Photinus-luciferin 4-monooxygenase (ATP-hydrolyzing)", - "1.13.12.8 Watasenia-luciferin 2-monooxygenase", - "1.13.12.9 Phenylalanine 2-monooxygenase", - "1.13.12.13 Oplophorus-luciferin 2-monooxygenase", - "1.13.12.15 3,4-dihydroxyphenylalanine oxidative deaminase", - "1.13.12.16 Nitronate monooxygenase", - "1.13.12.17 Dichloroarcyriaflavin A synthase", - "1.13.12.18 Dinoflagellate luciferase", - "1.13.12.19 2-oxuglutarate dioxygenase (ethylene-forming)", - "1.13.12.20 Noranthrone monooxygenase", - "1.13.12.21 Tetracenomycin-F1 monooxygenase", - "1.13.12.22 Deoxynogalonate monooxygenase", - "1.13.99.1 Inositol oxygenase", - "1.13.99.3 Tryptophan 2'-dioxygenase", - "1.14.11.1 Gamma-butyrobetaine dioxygenase", - "1.14.11.2 Procollagen-proline dioxygenase", - "1.14.11.3 Pyrimidine-deoxynucleoside 2'-dioxygenase", - "1.14.11.4 Procollagen-lysine 5-dioxygenase", - "1.14.11.6 Thymine dioxygenase", - "1.14.11.7 Procollagen-proline 3-dioxygenase", - "1.14.11.8 Trimethyllysine dioxygenase", - "1.14.11.9 Flavanone 3-dioxygenase", - "1.14.11.10 Pyrimidine-deoxynucleoside 1'-dioxygenase", - "1.14.11.11 Hyoscyamine (6S)-dioxygenase", - "1.14.11.12 Gibberellin-44 dioxygenase", - "1.14.11.13 Gibberellin 2-beta-dioxygenase", - "1.14.11.14 6-beta-hydroxyhyoscyamine epoxidase", - "1.14.11.15 Gibberellin 3-beta-dioxygenase", - "1.14.11.16 Peptide-aspartate beta-dioxygenase", - "1.14.11.17 Taurine dioxygenase", - "1.14.11.18 Phytanoyl-CoA dioxygenase", - "1.14.11.19 Leucocyanidin oxygenase", - "1.14.11.20 Deacetoxyvindoline 4-hydroxylase", - "1.14.11.21 Clavaminate synthase", - "1.14.11.22 Flavone synthase", - "1.14.11.23 Flavonol synthase", - "1.14.11.24 2'-deoxymugineic-acid 2'-dioxygenase", - "1.14.11.25 Mugineic-acid 3-dioxygenase", - "1.14.11.26 Deacetoxycephalosporin-C hydroxylase", - "1.14.11.27 [Histone H3]-lysine-36 demethylase", - "1.14.11.28 Proline 3-hydroxylase", - "1.14.11.29 Hypoxia-inducible factor-proline dioxygenase", - "1.14.11.30 Hypoxia-inducible factor-asparagine dioxygenase", - "1.14.11.31 Thebaine 6-O-demethylase", - "1.14.11.32 Codeine 3-O-demethylase", - "1.14.11.33 DNA oxidative demethylase", - "1.14.11.34 2-oxoglutarate/L-arginine monooxygenase/decarboxylase (succinate-forming)", - "1.14.11.35 1-deoxypentalenic acid 11-beta-hydroxylase", - "1.14.11.36 Pentalenolactone F synthase", - "1.14.11.37 Kanamycin B dioxygenase", - "1.14.11.38 Verruculogen synthase", - "1.14.11.39 L-asparagine oxygenase", - "1.14.11.40 Enduracididine beta-hydroxylase", - "1.14.11.41 L-arginine hydroxylase", - "1.14.11.42 tRNA(Phe) (7-(3-amino-3-carboxypropyl)wyosine(37)-C(2))-hydroxylase", - "1.14.11.43 (S)-dichlorprop dioxygenase (2-oxoglutarate)", - "1.14.11.44 (R)-dichlorprop dioxygenase (2-oxoglutarate)", - "1.14.11.45 L-isoleucine 4-hydroxylase", - "1.14.11.46 2-aminoethylphosphonate dioxygenase", - "1.14.11.47 50S ribosomal protein L16 3-hydroxylase", - "1.14.11.48 Xanthine dioxygenase", - "1.14.11.49 Uridine-5'-phosphate dioxygenase", - "1.14.11.50 (-)-deoxypodophyllotoxin synthase", - "1.14.11.n2 Methylcytosine dioxygenase", - "1.14.11.n3 L-proline cis-4-hydroxylase", - "1.14.11.n4 Ankyrin-repeat-histidine dioxagenase", - "1.14.12.1 Anthranilate 1,2-dioxygenase (deaminating, decarboxylating)", - "1.14.12.3 Benzene 1,2-dioxygenase", - "1.14.12.4 3-hydroxy-2-methylpyridinecarboxylate dioxygenase", - "1.14.12.5 5-pyridoxate dioxygenase", - "1.14.12.7 Phthalate 4,5-dioxygenase", - "1.14.12.8 4-sulfobenzoate 3,4-dioxygenase", - "1.14.12.9 4-chlorophenylacetate 3,4-dioxygenase", - "1.14.12.10 Benzoate 1,2-dioxygenase", - "1.14.12.11 Toluene dioxygenase", - "1.14.12.12 Naphthalene 1,2-dioxygenase", - "1.14.12.13 2-halobenzoate 1,2-dioxygenase", - "1.14.12.14 2-aminobenzenesulfonate 2,3-dioxygenase", - "1.14.12.15 Terephthalate 1,2-dioxygenase", - "1.14.12.16 2-hydroxyquinoline 5,6-dioxygenase", - "1.14.12.17 Nitric oxide dioxygenase", - "1.14.12.18 Biphenyl 2,3-dioxygenase", - "1.14.12.19 3-phenylpropanoate dioxygenase", - "1.14.12.22 Carbazole 1,9a-dioxygenase", - "1.14.12.23 Nitroarene dioxygenase", - "1.14.12.24 2,4-dinitrotoluene dioxygenase", - "1.14.13.1 Salicylate 1-monooxygenase", - "1.14.13.2 4-hydroxybenzoate 3-monooxygenase", - "1.14.13.4 Melilotate 3-monooxygenase", - "1.14.13.5 Imidazoleacetate 4-monooxygenase", - "1.14.13.6 Orcinol 2-monooxygenase", - "1.14.13.7 Phenol 2-monooxygenase (NADPH)", - "1.14.13.8 Flavin-containing monooxygenase", - "1.14.13.9 Kynurenine 3-monooxygenase", - "1.14.13.10 2,6-dihydroxypyridine 3-monooxygenase", - "1.14.13.11 Trans-cinnamate 4-monooxygenase", - "1.14.13.12 Benzoate 4-monooxygenase", - "1.14.13.13 Calcidiol 1-monooxygenase", - "1.14.13.14 Trans-cinnamate 2-monooxygenase", - "1.14.13.16 Cyclopentanone monooxygenase", - "1.14.13.18 4-hydroxyphenylacetate 1-monooxygenase", - "1.14.13.19 Taxifolin 8-monooxygenase", - "1.14.13.20 2,4-dichlorophenol 6-monooxygenase", - "1.14.13.21 Flavonoid 3'-monooxygenase", - "1.14.13.22 Cyclohexanone monooxygenase", - "1.14.13.23 3-hydroxybenzoate 4-monooxygenase", - "1.14.13.24 3-hydroxybenzoate 6-monooxygenase", - "1.14.13.25 Methane monooxygenase (soluble)", - "1.14.13.27 4-aminobenzoate 1-monooxygenase", - "1.14.13.28 3,9-dihydroxypterocarpan 6A-monooxygenase", - "1.14.13.29 4-nitrophenol 2-monooxygenase", - "1.14.13.30 Leukotriene-B(4) 20-monooxygenase", - "1.14.13.31 2-nitrophenol 2-monooxygenase", - "1.14.13.32 Albendazole monooxygenase", - "1.14.13.33 4-hydroxybenzoate 3-monooxygenase (NAD(P)H)", - "1.14.13.34 Leukotriene-E(4) 20-monooxygenase", - "1.14.13.35 Anthranilate 3-monooxygenase (deaminating)", - "1.14.13.36 5-O-(4-coumaroyl)-D-quinate 3'-monooxygenase", - "1.14.13.37 Methyltetrahydroprotoberberine 14-monooxygenase", - "1.14.13.38 Anhydrotetracycline monooxygenase", - "1.14.13.39 Nitric-oxide synthase (NADPH)", - "1.14.13.40 Anthraniloyl-CoA monooxygenase", - "1.14.13.41 Tyrosine N-monooxygenase", - "1.14.13.43 Questin monooxygenase", - "1.14.13.44 2-hydroxybiphenyl 3-monooxygenase", - "1.14.13.46 (-)-menthol monooxygenase", - "1.14.13.47 (S)-limonene 3-monooxygenase", - "1.14.13.48 (S)-limonene 6-monooxygenase", - "1.14.13.49 (S)-limonene 7-monooxygenase", - "1.14.13.50 Pentachlorophenol monooxygenase", - "1.14.13.51 6-oxocineole dehydrogenase", - "1.14.13.52 Isoflavone 3'-hydroxylase", - "1.14.13.53 4'-methoxyisoflavone 2'-hydroxylase", - "1.14.13.54 Ketosteroid monooxygenase", - "1.14.13.55 Protopine 6-monooxygenase", - "1.14.13.56 Dihydrosanguinarine 10-monooxygenase", - "1.14.13.57 Dihydrochelirubine 12-monooxygenase", - "1.14.13.58 Benzoyl-CoA 3-monooxygenase", - "1.14.13.59 L-lysine N(6)-monooxygenase (NADPH)", - "1.14.13.61 2-hydroxyquinoline 8-monooxygenase", - "1.14.13.62 4-hydroxyquinoline 3-monooxygenase", - "1.14.13.63 3-hydroxyphenylacetate 6-hydroxylase", - "1.14.13.64 4-hydroxybenzoate 1-hydroxylase", - "1.14.13.66 2-hydroxycyclohexanone 2-monooxygenase", - "1.14.13.67 Quinine 3-monooxygenase", - "1.14.13.68 4-hydroxyphenylacetaldehyde oxime monooxygenase", - "1.14.13.69 Alkene monooxygenase", - "1.14.13.70 Sterol 14-alpha-demethylase", - "1.14.13.71 N-methylcoclaurine 3'-monooxygenase", - "1.14.13.72 Methylsterol monooxygenase", - "1.14.13.73 Tabersonine 16-hydroxylase", - "1.14.13.74 7-deoxyloganin 7-hydroxylase", - "1.14.13.75 Vinorine hydroxylase", - "1.14.13.76 Taxane 10-beta-hydroxylase", - "1.14.13.77 Taxane 13-alpha-hydroxylase", - "1.14.13.78 Ent-kaurene oxidase", - "1.14.13.79 Ent-kaurenoic acid oxidase", - "1.14.13.80 (R)-limonene 6-monooxygenase", - "1.14.13.81 Magnesium-protoporphyrin IX monomethyl ester (oxidative) cyclase", - "1.14.13.82 Vanillate monooxygenase", - "1.14.13.83 Precorrin-3B synthase", - "1.14.13.84 4-hydroxyacetophenone monooxygenase", - "1.14.13.85 Glyceollin synthase", - "1.14.13.87 Licodione synthase", - "1.14.13.88 Flavonoid 3',5'-hydroxylase", - "1.14.13.89 Isoflavone 2'-hydroxylase", - "1.14.13.90 Zeaxanthin epoxidase", - "1.14.13.91 Deoxysarpagine hydroxylase", - "1.14.13.92 Phenylacetone monooxygenase", - "1.14.13.93 (+)-abscisic acid 8'-hydroxylase", - "1.14.13.94 Lithocholate 6-beta-hydroxylase", - "1.14.13.96 5-beta-cholestane-3-alpha,7-alpha-diol 12-alpha-hydroxylase", - "1.14.13.97 Taurochenodeoxycholate 6-alpha-hydroxylase", - "1.14.13.100 25/26-hydroxycholesterol 7-alpha-hydroxylase", - "1.14.13.101 Senecionine N-oxygenase", - "1.14.13.102 Psoralen synthase", - "1.14.13.103 8-dimethylallylnaringenin 2'-hydroxylase", - "1.14.13.104 (+)-menthofuran synthase", - "1.14.13.105 Monocyclic monoterpene ketone monooxygenase", - "1.14.13.106 Epi-isozizaene 5-monooxygenase", - "1.14.13.107 Limonene 1,2-monooxygenase", - "1.14.13.108 Abieta-7,13-diene hydroxylase", - "1.14.13.109 Abieta-7,13-dien-18-ol hydroxylase", - "1.14.13.110 Geranylgeraniol 18-hydroxylase", - "1.14.13.111 Methanesulfonate monooxygenase", - "1.14.13.112 3-epi-6-deoxocathasterone 23-monooxygenase", - "1.14.13.113 FAD-dependent urate hydroxylase", - "1.14.13.114 6-hydroxynicotinate 3-monooxygenase", - "1.14.13.115 Angelicin synthase", - "1.14.13.116 Geranylhydroquinone 3''-hydroxylase", - "1.14.13.117 Isoleucine N-monooxygenase", - "1.14.13.118 Valine N-monooxygenase", - "1.14.13.119 5-epiaristolochene 1,3-dihydroxylase", - "1.14.13.120 Costunolide synthase", - "1.14.13.121 Premnaspirodiene oxygenase", - "1.14.13.122 Chlorophyllide-a oxygenase", - "1.14.13.123 Germacrene A hydroxylase", - "1.14.13.124 Phenylalanine N-monooxygenase", - "1.14.13.125 Tryptophan N-monooxygenase", - "1.14.13.127 3-(3-hydroxy-phenyl)propanoic acid hydroxylase", - "1.14.13.128 7-methylxanthine demethylase", - "1.14.13.129 Beta-carotene 3-hydroxylase", - "1.14.13.130 Pyrrole-2-carboxylate monooxygenase", - "1.14.13.131 Dimethyl-sulfide monooxygenase", - "1.14.13.133 Pentalenene oxygenase", - "1.14.13.134 Beta-amyrin 11-oxidase", - "1.14.13.135 1-hydroxy-2-naphthoate hydroxylase", - "1.14.13.136 2-hydroxyisoflavanone synthase", - "1.14.13.137 Indole-2-monooxygenase", - "1.14.13.138 Indolin-2-one monooxygenase", - "1.14.13.139 3-hydroxyindolin-2-one monooxygenase", - "1.14.13.140 2-hydroxy-1,4-benzoxazin-3-one monooxygenase", - "1.14.13.141 Cholest-4-en-3-one 26-monooxygenase", - "1.14.13.142 3-ketosteroid 9-alpha-monooxygenase", - "1.14.13.143 Ent-isokaurene C2-hydroxylase", - "1.14.13.144 9-beta-pimara-7,15-diene oxidase", - "1.14.13.145 Ent-cassa-12,15-diene 11-hydroxylase", - "1.14.13.146 Taxoid 14-beta-hydroxylase", - "1.14.13.147 Taxoid 7-beta-hydroxylase", - "1.14.13.148 Trimethylamine monooxygenase", - "1.14.13.149 Phenylacetyl-CoA 1,2-epoxidase", - "1.14.13.150 Alpha-humulene 10-hydroxylase", - "1.14.13.151 Linalool 8-monooxygenase", - "1.14.13.152 Geraniol 8-hydroxylase", - "1.14.13.153 (+)-sabinene 3-hydroxylase", - "1.14.13.154 Erythromycin 12 hydroxylase", - "1.14.13.155 Alpha-pinene monooxygenase", - "1.14.13.156 1,8-cineole 2-endo-monooxygenase", - "1.14.13.157 1,8-cineole 2-exo-monooxygenase", - "1.14.13.158 Amorpha-4,11-diene 12 monooxygenase", - "1.14.13.160 (2,2,3-trimethyl-5-oxocyclopent-3-enyl)acetyl-CoA 1,5-monooxygenase", - "1.14.13.161 (+)-camphor 6-exo-hydroxylase", - "1.14.13.162 2,5-diketocamphane 1,2-monooxygenase", - "1.14.13.163 6-hydroxy-3-succinoylpyridine 3-monooxygenase", - "1.14.13.165 Nitric-oxide synthase (NAD(P)H)", - "1.14.13.166 4-nitrocatechol 4-monooxygenase", - "1.14.13.167 4-nitrophenol 4-monooxygenase", - "1.14.13.168 Indole-3-pyruvate monooxygenase", - "1.14.13.170 Pentalenolactone D synthase", - "1.14.13.171 Neopentalenolactone D synthase", - "1.14.13.172 Salicylate 5-hydroxylase", - "1.14.13.173 11-oxo-beta-amyrin 30-oxidase", - "1.14.13.174 Averantin hydroxylase", - "1.14.13.175 Aflatoxin B synthase", - "1.14.13.176 Tryprostatin B 6-hydroxylase", - "1.14.13.177 Fumitremorgin C monooxygenase", - "1.14.13.178 Methylxanthine N(1)-demethylase", - "1.14.13.179 Methylxanthine N(3)-demethylase", - "1.14.13.180 Aklavinone 12-hydroxylase", - "1.14.13.181 13-deoxydaunorubicin hydroxylase", - "1.14.13.182 2-heptyl-3-hydroxy-4(1H)-quinolone synthase", - "1.14.13.183 Dammarenediol 12-hydroxylase", - "1.14.13.184 Protopanaxadiol 6-hydroxylase", - "1.14.13.185 Pikromycin synthase", - "1.14.13.186 20-oxo-5-O-mycaminosyltylactone 23-monooxygenase", - "1.14.13.187 L-evernosamine nitrososynthase", - "1.14.13.188 6-deoxyerythronolide B hydroxylase", - "1.14.13.189 5-methyl-1-naphthoate 3-hydroxylase", - "1.14.13.190 Ferruginol synthase", - "1.14.13.191 Ent-sandaracopimaradiene 3-hydroxylase", - "1.14.13.192 Oryzalexin E synthase", - "1.14.13.193 Oryzalexin D synthase", - "1.14.13.194 Phylloquinone omega-hydroxylase", - "1.14.13.195 L-ornithine N(5)-monooxygenase (NADPH)", - "1.14.13.196 L-ornithine N(5)-monooxygenase (NAD(P)H)", - "1.14.13.197 Dihydromonacolin L hydroxylase", - "1.14.13.198 Monacolin L hydroxylase", - "1.14.13.199 Docosahexaenoic acid omega-hydroxylase", - "1.14.13.200 Tetracenomycin A2 monooxygenase-diooxygenase", - "1.14.13.201 Beta-amyrin 28-monooxygenase", - "1.14.13.202 Methyl farnesoate epoxidase", - "1.14.13.203 Farnesoate epoxidase", - "1.14.13.204 Long-chain acyl-CoA omega-monooxygenase", - "1.14.13.205 Long-chain fatty acid omega-monooxygenase", - "1.14.13.206 Laurate 7-monooxygenase", - "1.14.13.207 Ipsdienol synthase", - "1.14.13.208 Benzoyl-CoA 2,3-epoxidase", - "1.14.13.209 Salicyloyl-CoA 5-hydroxylase", - "1.14.13.210 4-methyl-5-nitrocatechol 5-monooxygenase", - "1.14.13.211 Rifampicin monooxygenase", - "1.14.13.212 1,3,7-trimethyluric acid 5-monooxygenase", - "1.14.13.213 Bursehernin 5'-monooxygenase", - "1.14.13.214 (-)-4'-demethyl-deoxypodophyllotoxin 4-hydroxylase", - "1.14.13.215 Protoasukamycin 4-monooxygenase", - "1.14.13.216 Asperlicin C monooxygenase", - "1.14.13.217 Protodeoxyviolaceinate monooxygenase", - "1.14.13.n5 Dihomomethionine N-hydroxylase", - "1.14.13.n6 Hexahomomethionine N-hydroxylase", - "1.14.13.n7 4-nitrophenol 2-hydroxylase", - "1.14.13.n8 2-methylbutanal oxime monooxygenase", - "1.14.14.1 Unspecific monooxygenase", - "1.14.14.3 Alkanal monooxygenase (FMN-linked)", - "1.14.14.5 Alkanesulfonate monooxygenase", - "1.14.14.8 Anthranilate 3-monooxygenase (FAD)", - "1.14.14.9 4-hydroxyphenylacetate 3-monooxygenase", - "1.14.14.10 Nitrilotriacetate monooxygenase", - "1.14.14.11 Styrene monooxygenase", - "1.14.14.12 3-hydroxy-9,10-secoandrosta-1,3,5(10)-triene-9,17-dione monooxygenase", - "1.14.14.13 4-(gamma-L-glutamylamino)butanoyl-[BtrI acyl-carrier protein] monooxygenase", - "1.14.14.14 Aromatase", - "1.14.14.15 (3S)-3-amino-3-(3-chloro-4-hydroxyphenyl)propanoyl-[peptidyl-carrier protein SgcC2] monooxygenase", - "1.14.14.16 Steroid 21-monooxygenase", - "1.14.14.17 Squalene monooxygenase", - "1.14.14.18 Heme oxygenase (biliverdin-producing)", - "1.14.14.19 Steroid 17-alpha-monooxygenase", - "1.14.14.20 Phenol 2-monooxygenase (FADH(2))", - "1.14.14.21 Dibenzothiophene monooxygenase", - "1.14.14.22 Dibenzothiophene sulfone monooxygenase", - "1.14.14.23 Cholesterol 7-alpha-monooxygenase", - "1.14.14.24 Vitamin D 25-hydroxylase", - "1.14.14.25 Cholesterol 24-hydroxylase", - "1.14.14.26 24-hydroxycholesterol 7-alpha-hydroxylase", - "1.14.15.1 Camphor 5-monooxygenase", - "1.14.15.3 Alkane 1-monooxygenase", - "1.14.15.4 Steroid 11-beta-monooxygenase", - "1.14.15.5 Corticosterone 18-monooxygenase", - "1.14.15.6 Cholesterol monooxygenase (side-chain-cleaving)", - "1.14.15.7 Choline monooxygenase", - "1.14.15.8 Steroid 15-beta-monooxygenase", - "1.14.15.9 Spheroidene monooxygenase", - "1.14.15.10 (+)-camphor 6-endo-hydroxylase", - "1.14.15.11 Pentalenic acid synthase", - "1.14.15.12 Pimeloyl-[acyl-carrier protein] synthase", - "1.14.15.13 Pulcherriminic acid synthase", - "1.14.15.14 Methyl-branched lipid omega-hydroxylase", - "1.14.15.15 Cholestanetriol 26-monooxygenase", - "1.14.15.16 Vitamin D(3) 24-hydroxylase", - "1.14.15.17 Pheophorbide a oxygenase", - "1.14.16.1 Phenylalanine 4-monooxygenase", - "1.14.16.2 Tyrosine 3-monooxygenase", - "1.14.16.3 Anthranilate 3-monooxygenase", - "1.14.16.4 Tryptophan 5-monooxygenase", - "1.14.16.5 Alkylglycerol monooxygenase", - "1.14.16.6 Mandelate 4-monooxygenase", - "1.14.16.7 Phenylalanine 3-monooxygenase", - "1.14.17.1 Dopamine beta-monooxygenase", - "1.14.17.3 Peptidylglycine monooxygenase", - "1.14.17.4 Aminocyclopropanecarboxylate oxidase", - "1.14.18.1 Tyrosinase", - "1.14.18.2 CMP-N-acetylneuraminate monooxygenase", - "1.14.18.3 Methane monooxygenase (particulate)", - "1.14.18.4 Phosphatidylcholine 12-monooxygenase", - "1.14.18.5 Sphingolipid C4-monooxygenase", - "1.14.18.6 4-hydroxysphinganine ceramide fatty acyl 2-hydroxylase", - "1.14.18.7 Dihydroceramide fatty acyl 2-hydroxylase", - "1.14.18.8 7-alpha-hydroxycholest-4-en-3-one 12-alpha-hydroxylase", - "1.14.19.1 Stearoyl-CoA 9-desaturase", - "1.14.19.2 Stearoyl-[acyl-carrier-protein] 9-desaturase", - "1.14.19.3 Acyl-CoA 6-desaturase", - "1.14.19.4 Acyl-lipid (11-3)-desaturase", - "1.14.19.5 Acyl-CoA 11-(Z)-desaturase", - "1.14.19.6 Acyl-CoA (9+3)-desaturase", - "1.14.19.8 Pentalenolactone synthase", - "1.14.19.9 Tryptophan 7-halogenase", - "1.14.19.10 Icosanoyl-CoA 5-desaturase", - "1.14.19.11 Acyl-[acyl-carrier-protein] 4-desaturase", - "1.14.19.12 Acyl-lipid omega-(9-4) desaturase", - "1.14.19.13 Acyl-CoA 15-desaturase", - "1.14.19.14 Linoleoyl-lipid Delta(9) conjugase", - "1.14.19.15 (11Z)-hexadec-11-enoyl-CoA conjugase", - "1.14.19.16 Linoleoyl-lipid Delta(12) conjugase (11E,13Z-forming)", - "1.14.19.17 Sphingolipid 4-desaturase", - "1.14.19.18 Sphingolipid 8-(E)-desaturase", - "1.14.19.19 Sphingolipid 10-desaturase", - "1.14.19.20 Delta(7)-sterol 5(6)-desaturase", - "1.14.19.21 Cholesterol 7-desaturase", - "1.14.19.22 Acyl-lipid omega-6 desaturase (cytochrome b5)", - "1.14.19.23 Acyl-lipid (n+3)-(Z)-desaturase (ferredoxin)", - "1.14.19.24 Acyl-CoA 11-(E)-desaturase", - "1.14.19.25 Acyl-lipid omega-3 desaturase (cytochrome b5)", - "1.14.19.26 Acyl-[acyl-carrier-protein] 6-desaturase", - "1.14.19.27 sn-2 palmitoyl-lipid 9-desaturase", - "1.14.19.28 sn-1 stearoyl-lipid 9-desaturase", - "1.14.19.29 Sphingolipid 8-(E/Z)-desaturase", - "1.14.19.30 Acyl-lipid (8-3)-desaturase", - "1.14.19.31 Acyl-lipid (7-3)-desaturase", - "1.14.19.32 Palmitoyl-CoA 14-(E/Z)-desaturase", - "1.14.19.33 Delta(12) acyl-lipid conjugase (11E,13E-forming)", - "1.14.19.34 Acyl-lipid (9+3)-(E)-desaturase", - "1.14.19.35 sn-2 acyl-lipid omega-3 desaturase (ferredoxin)", - "1.14.19.36 sn-1 acyl-lipid omega-3 desaturase (ferredoxin)", - "1.14.19.37 Acyl-CoA 5-desaturase", - "1.14.19.38 Acyl-lipid Delta(6)-acetylenase", - "1.14.19.39 Acyl-lipid Delta(12)-acetylenase", - "1.14.19.40 Hex-5-enoyl-[acyl-carrier protein] acetylenase", - "1.14.19.41 Sterol 22-desaturase", - "1.14.19.42 Palmitoyl-[glycerolipid] 7-desaturase", - "1.14.19.43 Palmitoyl-[glycerolipid] 3-(E)-desaturase", - "1.14.19.44 Acyl-CoA (8-3)-desaturase", - "1.14.19.45 sn-1 oleoyl-lipid 12-desaturase", - "1.14.19.46 sn-1 linoleoyl-lipid 6-desaturase", - "1.14.19.47 Acyl-lipid (9-3)-desaturase", - "1.14.19.n4 Stearoyl-CoA 9-desaturase", - "1.14.19.n5 Versicolorin B desaturase", - "1.14.20.1 Deacetoxycephalosporin-C synthase", - "1.14.20.2 2,4-dihydroxy-1,4-benzoxazin-3-one-glucoside dioxygenase", - "1.14.20.3 (5R)-carbapenem-3-carboxylate synthase", - "1.14.21.1 (S)-stylopine synthase", - "1.14.21.2 (S)-cheilanthifoline synthase", - "1.14.21.3 Berbamunine synthase", - "1.14.21.4 Salutaridine synthase", - "1.14.21.5 (S)-canadine synthase", - "1.14.21.7 Biflaviolin synthase", - "1.14.21.8 Pseudobaptigenin synthase", - "1.14.21.9 Mycocyclosin synthase", - "1.14.21.10 Fumitremorgin C synthase", - "1.14.21.11 (-)-pluviatolide synthase", - "1.14.99.1 Prostaglandin-endoperoxide synthase", - "1.14.99.2 Kynurenine 7,8-hydroxylase", - "1.14.99.4 Progesterone monooxygenase", - "1.14.99.11 Estradiol 6-beta-monooxygenase", - "1.14.99.12 Androst-4-ene-3,17-dione monooxygenase", - "1.14.99.14 Progesterone 11-alpha-monooxygenase", - "1.14.99.15 4-methoxybenzoate monooxygenase (O-demethylating)", - "1.14.99.19 Plasmanylethanolamine desaturase", - "1.14.99.20 Phylloquinone monooxygenase (2,3-epoxidizing)", - "1.14.99.21 Latia-luciferin monooxygenase (demethylating)", - "1.14.99.22 Ecdysone 20-monooxygenase", - "1.14.99.23 3-hydroxybenzoate 2-monooxygenase", - "1.14.99.24 Steroid 9-alpha-monooxygenase", - "1.14.99.26 2-hydroxypyridine 5-monooxygenase", - "1.14.99.27 Juglone 3-monooxygenase", - "1.14.99.29 Deoxyhypusine monooxygenase", - "1.14.99.34 Monoprenyl isoflavone epoxidase", - "1.14.99.35 Thiophene-2-carbonyl-CoA monooxygenase", - "1.14.99.36 Beta-carotene 15,15'-monooxygenase", - "1.14.99.37 Taxadiene 5-alpha-hydroxylase", - "1.14.99.38 Cholesterol 25-hydroxylase", - "1.14.99.39 Ammonia monooxygenase", - "1.14.99.42 Zeaxanthin 7,8-dioxygenase", - "1.14.99.43 Beta-amyrin 24-hydroxylase", - "1.14.99.44 Diapolycopene oxygenase", - "1.14.99.45 Carotene epsilon-monooxygenase", - "1.14.99.46 Pyrimidine monooxygenase", - "1.14.99.47 (+)-larreatricin hydroxylase", - "1.14.99.48 Heme oxygenase (staphylobilin-producing)", - "1.14.99.49 2-hydroxy-5-methyl-1-naphthoate 7-hydroxylase", - "1.14.99.50 Gamma-glutamyl hercynylcysteine S-oxide synthase", - "1.14.99.51 Hercynylcysteine S-oxide synthase", - "1.14.99.52 L-cysteinyl-L-histidinylsulfoxide synthase", - "1.14.99.n4 Carotenoid 9,10-dioxygenase", - "1.15.1.1 Superoxide dismutase", - "1.15.1.2 Superoxide reductase", - "1.16.1.1 Mercury(II) reductase", - "1.16.1.2 Diferric-transferrin reductase", - "1.16.1.3 Aquacobalamin reductase", - "1.16.1.4 Cob(II)alamin reductase", - "1.16.1.5 Aquacobalamin reductase (NADPH)", - "1.16.1.6 Cyanocobalamin reductase (cyanide-eliminating)", - "1.16.1.7 Ferric-chelate reductase (NADH)", - "1.16.1.8 [Methionine synthase] reductase", - "1.16.1.9 Ferric-chelate reductase (NADPH)", - "1.16.1.10 Ferric-chelate reductase (NAD(P)H)", - "1.16.3.1 Ferroxidase", - "1.16.3.2 Bacterial non-heme ferritin", - "1.16.5.1 Ascorbate ferrireductase (transmembrane)", - "1.16.8.1 Cob(II)yrinic acid a,c-diamide reductase", - "1.16.9.1 Iron:rusticyanin reductase", - "1.17.1.1 CDP-4-dehydro-6-deoxyglucose reductase", - "1.17.1.3 Leucoanthocyanidin reductase", - "1.17.1.4 Xanthine dehydrogenase", - "1.17.1.5 Nicotinate dehydrogenase", - "1.17.1.8 4-hydroxy-tetrahydrodipicolinate reductase", - "1.17.2.1 Nicotinate dehydrogenase (cytochrome)", - "1.17.2.2 Lupanine 17-hydroxylase (cytochrome c)", - "1.17.3.1 Pteridine oxidase", - "1.17.3.2 Xanthine oxidase", - "1.17.3.3 6-hydroxynicotinate dehydrogenase", - "1.17.4.1 Ribonucleoside-diphosphate reductase", - "1.17.4.2 Ribonucleoside-triphosphate reductase", - "1.17.4.4 Vitamin-K-epoxide reductase (warfarin-sensitive)", - "1.17.4.5 Vitamin-K-epoxide reductase (warfarin-insensitive)", - "1.17.5.1 Phenylacetyl-CoA dehydrogenase", - "1.17.5.2 Caffeine dehydrogenase", - "1.17.7.1 (E)-4-hydroxy-3-methylbut-2-enyl-diphosphate synthase (ferredoxin)", - "1.17.7.2 7-hydroxymethyl chlorophyll a reductase", - "1.17.7.3 (E)-4-hydroxy-3-methylbut-2-enyl-diphosphate synthase (flavodoxin)", - "1.17.7.4 4-hydroxy-3-methylbut-2-enyl diphosphate reductase", - "1.17.98.1 Bile-acid 7-alpha-dehydroxylase", - "1.17.99.1 4-methylphenol dehydrogenase (hydroxylating)", - "1.17.99.2 Ethylbenzene hydroxylase", - "1.17.99.3 3-alpha,7-alpha,12-alpha-trihydroxy-5-beta-cholestanoyl-CoA 24-hydroxylase", - "1.17.99.4 Uracil/thymine dehydrogenase", - "1.17.99.6 Epoxyqueuosine reductase", - "1.18.1.1 Rubredoxin--NAD(+) reductase", - "1.18.1.2 Ferredoxin--NADP(+) reductase", - "1.18.1.3 Ferredoxin--NAD(+) reductase", - "1.18.1.4 Rubredoxin--NAD(P)(+) reductase", - "1.18.1.5 Putidaredoxin--NAD(+) reductase", - "1.18.1.6 Adrenodoxin-NADP(+) reductase", - "1.18.1.7 Ferredoxin--NAD(P)(+) reductase (naphthalene dioxygenase ferredoxin-specific)", - "1.18.1.8 Ferredoxin-NAD(+) oxidoreductase (Na(+)-transporting)", - "1.18.6.1 Nitrogenase", - "1.19.6.1 Nitrogenase (flavodoxin)", - "1.20.1.1 Phosphonate dehydrogenase", - "1.20.2.1 Arsenate reductase (cytochrome c)", - "1.20.4.1 Arsenate reductase (glutaredoxin)", - "1.20.4.2 Methylarsonate reductase", - "1.20.4.3 Mycoredoxin", - "1.20.4.4 Arsenate reductase (thioredoxin)", - "1.20.9.1 Arsenate reductase (azurin)", - "1.20.99.1 Arsenate reductase (donor)", - "1.21.1.1 Iodotyrosine deiodinase", - "1.21.1.2 2,4-dichlorobenzoyl-CoA reductase", - "1.21.3.1 Isopenicillin-N synthase", - "1.21.3.2 Columbamine oxidase", - "1.21.3.3 Reticuline oxidase", - "1.21.3.4 Sulochrin oxidase ((+)-bisdechlorogeodin-forming)", - "1.21.3.5 Sulochrin oxidase ((-)-bisdechlorogeodin-forming)", - "1.21.3.6 Aureusidin synthase", - "1.21.3.7 Tetrahydrocannabinolic acid synthase", - "1.21.3.8 Cannabidiolic acid synthase", - "1.21.4.1 D-proline reductase (dithiol)", - "1.21.4.2 Glycine reductase", - "1.21.4.3 Sarcosine reductase", - "1.21.4.4 Betaine reductase", - "1.21.98.1 Cyclic dehypoxanthinyl futalosine synthase", - "1.21.98.2 Dichlorochromopyrrolate synthase", - "1.21.99.1 Beta-cyclopiazonate dehydrogenase", - "1.21.99.3 Thyroxine 5-deiodinase", - "1.21.99.4 Thyroxine 5'-deiodinase", - "1.23.1.1 (+)-pinoresinol reductase", - "1.23.1.2 (+)-lariciresinol reductase", - "1.23.1.3 (-)-pinoresinol reductase", - "1.23.1.4 (-)-lariciresinol reductase", - "1.23.5.1 Violaxanthin de-epoxidase", - "1.97.1.1 Chlorate reductase", - "1.97.1.2 Pyrogallol hydroxytransferase", - "1.97.1.4 [Formate-C-acetyltransferase]-activating enzyme", - "1.97.1.8 Tetrachloroethene reductive dehalogenase", - "1.97.1.9 Selenate reductase", - "1.97.1.12 Photosystem I", - "2.1.1.1 Nicotinamide N-methyltransferase", - "2.1.1.2 Guanidinoacetate N-methyltransferase", - "2.1.1.3 Thetin--homocysteine S-methyltransferase", - "2.1.1.4 Acetylserotonin O-methyltransferase", - "2.1.1.5 Betaine--homocysteine S-methyltransferase", - "2.1.1.6 Catechol O-methyltransferase", - "2.1.1.7 Nicotinate N-methyltransferase", - "2.1.1.8 Histamine N-methyltransferase", - "2.1.1.9 Thiol S-methyltransferase", - "2.1.1.10 Homocysteine S-methyltransferase", - "2.1.1.11 Magnesium protoporphyrin IX methyltransferase", - "2.1.1.12 Methionine S-methyltransferase", - "2.1.1.13 Methionine synthase", - "2.1.1.14 5-methyltetrahydropteroyltriglutamate--homocysteine S-methyltransferase", - "2.1.1.15 Fatty-acid O-methyltransferase", - "2.1.1.16 Methylene-fatty-acyl-phospholipid synthase", - "2.1.1.17 Phosphatidylethanolamine N-methyltransferase", - "2.1.1.18 Polysaccharide O-methyltransferase", - "2.1.1.19 Trimethylsulfonium--tetrahydrofolate N-methyltransferase", - "2.1.1.20 Glycine N-methyltransferase", - "2.1.1.21 Methylamine--glutamate N-methyltransferase", - "2.1.1.22 Carnosine N-methyltransferase", - "2.1.1.25 Phenol O-methyltransferase", - "2.1.1.26 Iodophenol O-methyltransferase", - "2.1.1.27 Tyramine N-methyltransferase", - "2.1.1.28 Phenylethanolamine N-methyltransferase", - "2.1.1.33 tRNA (guanine(46)-N(7))-methyltransferase", - "2.1.1.34 tRNA (guanosine(18)-2'-O)-methyltransferase", - "2.1.1.35 tRNA (uracil(54)-C(5))-methyltransferase", - "2.1.1.37 DNA (cytosine-5-)-methyltransferase", - "2.1.1.38 O-demethylpuromycin O-methyltransferase", - "2.1.1.39 Inositol 3-methyltransferase", - "2.1.1.40 Inositol 1-methyltransferase", - "2.1.1.41 Sterol 24-C-methyltransferase", - "2.1.1.42 Flavone 3'-O-methyltransferase", - "2.1.1.43 Histone-lysine N-methyltransferase", - "2.1.1.44 L-histidine N(alpha)-methyltransferase", - "2.1.1.45 Thymidylate synthase", - "2.1.1.46 Isoflavone 4'-O-methyltransferase", - "2.1.1.47 Indolepyruvate C-methyltransferase", - "2.1.1.49 Amine N-methyltransferase", - "2.1.1.50 Loganate O-methyltransferase", - "2.1.1.53 Putrescine N-methyltransferase", - "2.1.1.54 Deoxycytidylate C-methyltransferase", - "2.1.1.55 tRNA (adenine-N(6)-)-methyltransferase", - "2.1.1.56 mRNA (guanine-N(7)-)-methyltransferase", - "2.1.1.57 Methyltransferase cap1", - "2.1.1.59 [Cytochrome c]-lysine N-methyltransferase", - "2.1.1.60 Calmodulin-lysine N-methyltransferase", - "2.1.1.61 tRNA (5-methylaminomethyl-2-thiouridylate)-methyltransferase", - "2.1.1.62 mRNA (2'-O-methyladenosine-N(6)-)-methyltransferase", - "2.1.1.63 Methylated-DNA--[protein]-cysteine S-methyltransferase", - "2.1.1.64 3-demethylubiquinol 3-O-methyltransferase", - "2.1.1.65 Licodione 2'-O-methyltransferase", - "2.1.1.67 Thiopurine S-methyltransferase", - "2.1.1.68 Caffeate O-methyltransferase", - "2.1.1.69 5-hydroxyfuranocoumarin 5-O-methyltransferase", - "2.1.1.70 8-hydroxyfuranocoumarin 8-O-methyltransferase", - "2.1.1.71 Phosphatidyl-N-methylethanolamine N-methyltransferase", - "2.1.1.72 Site-specific DNA-methyltransferase (adenine-specific)", - "2.1.1.74 Methylenetetrahydrofolate--tRNA-(uracil(54)-C(5))-methyltransferase (FADH(2)-oxidizing)", - "2.1.1.75 Apigenin 4'-O-methyltransferase", - "2.1.1.76 Quercetin 3-O-methyltransferase", - "2.1.1.77 Protein-L-isoaspartate(D-aspartate) O-methyltransferase", - "2.1.1.78 Isoorientin 3'-O-methyltransferase", - "2.1.1.79 Cyclopropane-fatty-acyl-phospholipid synthase", - "2.1.1.80 Protein-glutamate O-methyltransferase", - "2.1.1.82 3-methylquercetin 7-O-methyltransferase", - "2.1.1.83 3,7-dimethylquercetin 4'-O-methyltransferase", - "2.1.1.84 Methylquercetagetin 6-O-methyltransferase", - "2.1.1.85 Protein-histidine N-methyltransferase", - "2.1.1.86 Tetrahydromethanopterin S-methyltransferase", - "2.1.1.87 Pyridine N-methyltransferase", - "2.1.1.88 8-hydroxyquercetin 8-O-methyltransferase", - "2.1.1.89 Tetrahydrocolumbamine 2-O-methyltransferase", - "2.1.1.90 Methanol--corrinoid protein Co-methyltransferase", - "2.1.1.91 Isobutyraldoxime O-methyltransferase", - "2.1.1.94 Tabersonine 16-O-methyltransferase", - "2.1.1.95 Tocopherol O-methyltransferase", - "2.1.1.96 Thioether S-methyltransferase", - "2.1.1.97 3-hydroxyanthranilate 4-C-methyltransferase", - "2.1.1.98 Diphthine synthase", - "2.1.1.99 3-hydroxy-16-methoxy-2,3-dihydrotabersonine N-methyltransferase", - "2.1.1.100 Protein-S-isoprenylcysteine O-methyltransferase", - "2.1.1.101 Macrocin O-methyltransferase", - "2.1.1.102 Demethylmacrocin O-methyltransferase", - "2.1.1.103 Phosphoethanolamine N-methyltransferase", - "2.1.1.104 Caffeoyl-CoA O-methyltransferase", - "2.1.1.105 N-benzoyl-4-hydroxyanthranilate 4-O-methyltransferase", - "2.1.1.106 Tryptophan 2-C-methyltransferase", - "2.1.1.107 Uroporphyrinogen-III C-methyltransferase", - "2.1.1.108 6-hydroxymellein O-methyltransferase", - "2.1.1.109 Demethylsterigmatocystin 6-O-methyltransferase", - "2.1.1.110 Sterigmatocystin 8-O-methyltransferase", - "2.1.1.111 Anthranilate N-methyltransferase", - "2.1.1.112 Glucuronoxylan 4-O-methyltransferase", - "2.1.1.113 Site-specific DNA-methyltransferase (cytosine-N(4)-specific)", - "2.1.1.114 Polyprenyldihydroxybenzoate methyltransferase", - "2.1.1.115 (RS)-1-benzyl-1,2,3,4-tetrahydroisoquinoline N-methyltransferase", - "2.1.1.116 3'-hydroxy-N-methyl-(S)-coclaurine 4'-O-methyltransferase", - "2.1.1.117 (S)-scoulerine 9-O-methyltransferase", - "2.1.1.118 Columbamine O-methyltransferase", - "2.1.1.119 10-hydroxydihydrosanguinarine 10-O-methyltransferase", - "2.1.1.120 12-hydroxydihydrochelirubine 12-O-methyltransferase", - "2.1.1.121 6-O-methylnorlaudanosoline 5'-O-methyltransferase", - "2.1.1.122 (S)-tetrahydroprotoberberine N-methyltransferase", - "2.1.1.123 [Cytochrome c]-methionine S-methyltransferase", - "2.1.1.127 [Ribulose-bisphosphate carboxylase]-lysine N-methyltransferase", - "2.1.1.128 (RS)-norcoclaurine 6-O-methyltransferase", - "2.1.1.129 Inositol 4-methyltransferase", - "2.1.1.130 Precorrin-2 C(20)-methyltransferase", - "2.1.1.131 Precorrin-3B C(17)-methyltransferase", - "2.1.1.132 Precorrin-6B C(5,15)-methyltransferase (decarboxylating)", - "2.1.1.133 Precorrin-4 C(11)-methyltransferase", - "2.1.1.136 Chlorophenol O-methyltransferase", - "2.1.1.137 Arsenite methyltransferase", - "2.1.1.139 3'-demethylstaurosporine O-methyltransferase", - "2.1.1.140 (S)-coclaurine-N-methyltransferase", - "2.1.1.141 Jasmonate O-methyltransferase", - "2.1.1.142 Cycloartenol 24-C-methyltransferase", - "2.1.1.143 24-methylenesterol C-methyltransferase", - "2.1.1.144 Trans-aconitate 2-methyltransferase", - "2.1.1.145 Trans-aconitate 3-methyltransferase", - "2.1.1.146 (Iso)eugenol O-methyltransferase", - "2.1.1.147 Corydaline synthase", - "2.1.1.148 Thymidylate synthase (FAD)", - "2.1.1.150 Isoflavone 7-O-methyltransferase", - "2.1.1.151 Cobalt-factor II C(20)-methyltransferase", - "2.1.1.152 Precorrin-6A synthase (deacetylating)", - "2.1.1.153 Vitexin 2''-O-rhamnoside 7-O-methyltransferase", - "2.1.1.154 Isoliquiritigenin 2'-O-methyltransferase", - "2.1.1.155 Kaempferol 4'-O-methyltransferase", - "2.1.1.156 Glycine/sarcosine N-methyltransferase", - "2.1.1.157 Sarcosine/dimethylglycine N-methyltransferase", - "2.1.1.158 7-methylxanthosine synthase", - "2.1.1.159 Theobromine synthase", - "2.1.1.160 Caffeine synthase", - "2.1.1.161 Dimethylglycine N-methyltransferase", - "2.1.1.162 Glycine/sarcosine/dimethylglycine N-methyltransferase", - "2.1.1.163 Demethylmenaquinone methyltransferase", - "2.1.1.164 Demethylrebeccamycin-D-glucose O-methyltransferase", - "2.1.1.165 Methyl halide transferase", - "2.1.1.166 23S rRNA (uridine(2552)-2'-O)-methyltransferase", - "2.1.1.167 27S pre-rRNA (guanosine(2922)-2'-O)-methyltransferase", - "2.1.1.168 21S rRNA (uridine(2791)-2'-O)-methyltransferase", - "2.1.1.169 Tricetin 3',4',5'-O-trimethyltransferase", - "2.1.1.170 16S rRNA (guanine(527)-N(7))-methyltransferase", - "2.1.1.171 16S rRNA (guanine(966)-N(2))-methyltransferase", - "2.1.1.172 16S rRNA (guanine(1207)-N(2))-methyltransferase", - "2.1.1.173 23S rRNA (guanine(2445)-N(2))-methyltransferase", - "2.1.1.174 23S rRNA (guanine(1835)-N(2))-methyltransferase", - "2.1.1.175 Tricin synthase", - "2.1.1.176 16S rRNA (cytosine(967)-C(5))-methyltransferase", - "2.1.1.177 23S rRNA (pseudouridine(1915)-N(3))-methyltransferase", - "2.1.1.178 16S rRNA (cytosine(1407)-C(5))-methyltransferase", - "2.1.1.179 16S rRNA (guanine(1405)-N(7))-methyltransferase", - "2.1.1.180 16S rRNA (adenine(1408)-N(1))-methyltransferase", - "2.1.1.181 23S rRNA (adenine(1618)-N(6))-methyltransferase", - "2.1.1.182 16S rRNA (adenine(1518)-N(6)/adenine(1519)-N(6))-dimethyltransferase", - "2.1.1.183 18S rRNA (adenine(1779)-N(6)/adenine(1780)-N(6))-dimethyltransferase", - "2.1.1.184 23S rRNA (adenine(2085)-N(6))-dimethyltransferase", - "2.1.1.185 23S rRNA (guanosine(2251)-2'-O)-methyltransferase", - "2.1.1.186 23S rRNA (cytidine(2498)-2'-O)-methyltransferase", - "2.1.1.187 23S rRNA (guanine(745)-N(1))-methyltransferase", - "2.1.1.188 23S rRNA (guanine(748)-N(1))-methyltransferase", - "2.1.1.189 23S rRNA (uracil(747)-C(5))-methyltransferase", - "2.1.1.190 23S rRNA (uracil(1939)-C(5))-methyltransferase", - "2.1.1.191 23S rRNA (cytosine(1962)-C(5))-methyltransferase", - "2.1.1.192 23S rRNA (adenine(2503)-C(2))-methyltransferase", - "2.1.1.193 16S rRNA (uracil(1498)-N(3))-methyltransferase", - "2.1.1.195 Cobalt-precorrin-5B (C(1))-methyltransferase", - "2.1.1.196 Cobalt-precorrin-6B (C(15))-methyltransferase (decarboxylating)", - "2.1.1.197 Malonyl-[acyl-carrier protein] O-methyltransferase", - "2.1.1.198 16S rRNA (cytidine(1402)-2'-O)-methyltransferase", - "2.1.1.199 16S rRNA (cytosine(1402)-N(4))-methyltransferase", - "2.1.1.200 tRNA (cytidine(32)/uridine(32)-2'-O)-methyltransferase", - "2.1.1.201 2-methoxy-6-polyprenyl-1,4-benzoquinol methylase", - "2.1.1.202 Multisite-specific tRNA:(cytosine-C(5))-methyltransferase", - "2.1.1.203 tRNA (cytosine(34)-C(5))-methyltransferase", - "2.1.1.204 tRNA (cytosine(38)-C(5))-methyltransferase", - "2.1.1.205 tRNA (cytidine(32)/guanosine(34)-2'-O)-methyltransferase", - "2.1.1.206 tRNA (cytidine(56)-2'-O)-methyltransferase", - "2.1.1.207 tRNA (cytidine(34)-2'-O)-methyltransferase", - "2.1.1.208 23S rRNA (uridine(2479)-2'-O)-methyltransferase", - "2.1.1.209 23S rRNA (guanine(2535)-N(1))-methyltransferase", - "2.1.1.210 Demethylspheroidene O-methyltransferase", - "2.1.1.211 tRNA(Ser) (uridine(44)-2'-O)-methyltransferase", - "2.1.1.212 2,7,4'-trihydroxyisoflavanone 4'-O-methyltransferase", - "2.1.1.213 tRNA (guanine(10)-N(2))-dimethyltransferase", - "2.1.1.214 tRNA (guanine(10)-N(2))-methyltransferase", - "2.1.1.215 tRNA (guanine(26)-N(2)/guanine(27)-N(2))-dimethyltransferase", - "2.1.1.216 tRNA (guanine(26)-N(2))-dimethyltransferase", - "2.1.1.217 tRNA (adenine(22)-N(1))-methyltransferase", - "2.1.1.218 tRNA (adenine(9)-N(1))-methyltransferase", - "2.1.1.219 tRNA (adenine(57)-N(1)/adenine(58)-N(1))-methyltransferase", - "2.1.1.220 tRNA (adenine(58)-N(1))-methyltransferase", - "2.1.1.221 tRNA (guanine(9)-N(1))-methyltransferase", - "2.1.1.222 2-polyprenyl-6-hydroxyphenol methylase", - "2.1.1.223 tRNA(1)(Val) (adenine(37)-N(6))-methyltransferase", - "2.1.1.224 23S rRNA (adenine(2503)-C(8))-methyltransferase", - "2.1.1.225 tRNA:m(4)X modification enzyme", - "2.1.1.226 23S rRNA (cytidine(1920)-2'-O)-methyltransferase", - "2.1.1.227 16S rRNA (cytidine(1409)-2'-O)-methyltransferase", - "2.1.1.228 tRNA (guanine(37)-N(1))-methyltransferase", - "2.1.1.229 tRNA (carboxymethyluridine(34)-5-O)-methyltransferase", - "2.1.1.230 23S rRNA (adenosine(1067)-2'-O)-methyltransferase", - "2.1.1.231 Flavonoid 4'-O-methyltransferase", - "2.1.1.232 Naringenin 7-O-methyltransferase", - "2.1.1.233 [Phosphatase 2A protein]-leucine-carboxy methyltransferase", - "2.1.1.234 dTDP-3-amino-3,4,6-trideoxy-alpha-D-glucopyranose N,N-dimethyltransferase", - "2.1.1.235 dTDP-3-amino-3,6-dideoxy-alpha-D-glucopyranose N,N-dimethyltransferase", - "2.1.1.236 dTDP-3-amino-3,6-dideoxy-alpha-D-galactopyranose N,N-dimethyltransferase", - "2.1.1.237 Mycinamicin III 3''-O-methyltransferase", - "2.1.1.238 Mycinamicin VI 2''-O-methyltransferase", - "2.1.1.239 L-olivosyl-oleandolide 3-O-methyltransferase", - "2.1.1.240 Trans-resveratrol di-O-methyltransferase", - "2.1.1.241 2,4,7-trihydroxy-1,4-benzoxazin-3-one-glucoside 7-O-methyltransferase", - "2.1.1.242 16S rRNA (guanine(1516)-N(2))-methyltransferase", - "2.1.1.243 2-ketoarginine methyltransferase", - "2.1.1.244 Protein N-terminal methyltransferase", - "2.1.1.245 5-methyltetrahydrosarcinapterin:corrinoid/iron-sulfur protein Co-methyltransferase", - "2.1.1.246 [Methyl-Co(III) methanol-specific corrinoid protein]:coenzyme M methyltransferase", - "2.1.1.247 [Methyl-Co(III) methylamine-specific corrinoid protein]:coenzyme M methyltransferase", - "2.1.1.248 [Methylamine--corrinoid protein] Co-methyltransferase", - "2.1.1.249 [Dimethylamine--corrinoid protein] Co-methyltransferase", - "2.1.1.250 [Trimethylamine--corrinoid protein] Co-methyltransferase", - "2.1.1.251 Methylated-thiol--coenzyme M methyltransferase", - "2.1.1.252 Tetramethylammonium--corrinoid protein Co-methyltransferase", - "2.1.1.253 [Methyl-Co(III) tetramethylammonium-specific corrinoid protein]:coenzyme M methyltransferase", - "2.1.1.254 Erythromycin 3''-O-methyltransferase", - "2.1.1.255 Geranyl diphosphate 2-C-methyltransferase", - "2.1.1.256 tRNA (guanine(6)-N(2))-methyltransferase", - "2.1.1.257 tRNA (pseudouridine(54)-N(1))-methyltransferase", - "2.1.1.258 5-methyltetrahydrofolate:corrinoid/iron-sulfur protein Co-methyltransferase", - "2.1.1.259 [Fructose-bisphosphate aldolase]-lysine N-methyltransferase", - "2.1.1.260 rRNA small subunit pseudouridine methyltransferase Nep1", - "2.1.1.261 4-dimethylallyltryptophan N-methyltransferase", - "2.1.1.262 Squalene methyltransferase", - "2.1.1.263 Botryococcene C-methyltransferase", - "2.1.1.264 23S rRNA (guanine(2069)-N(7))-methyltransferase", - "2.1.1.265 Tellurite methyltransferase", - "2.1.1.266 23S rRNA (adenine(2030)-N(6))-methyltransferase", - "2.1.1.267 Flavonoid 3',5'-methyltransferase", - "2.1.1.268 tRNA(Thr) (cytosine(32)-N(3))-methyltransferase", - "2.1.1.269 Dimethylsulfoniopropionate demethylase", - "2.1.1.270 (+)-6a-hydroxymaackiain 3-O-methyltransferase", - "2.1.1.271 Cobalt-precorrin-4 methyltransferase", - "2.1.1.272 Cobalt-factor III methyltransferase", - "2.1.1.273 Benzoate O-methyltransferase", - "2.1.1.274 Salicylate carboxymethyltransferase", - "2.1.1.275 Gibberellin A(9) O-methyltransferase", - "2.1.1.276 Gibberellin A(4) carboxyl methyltransferase", - "2.1.1.277 Anthranilate O-methyltransferase", - "2.1.1.278 Indole-3-acetate O-methyltransferase", - "2.1.1.279 Trans-anol O-methyltransferase", - "2.1.1.280 Selenocysteine Se-methyltransferase", - "2.1.1.281 Phenylpyruvate C(3)-methyltransferase", - "2.1.1.282 tRNA(Phe) 7-((3-amino-3-carboxypropyl)-4-demethylwyosine(37)-N(4))-methyltransferase", - "2.1.1.283 Emodin O-methyltransferase", - "2.1.1.284 8-demethylnovobiocic acid C(8)-methyltransferase", - "2.1.1.285 Demethyldecarbamoylnovobiocin O-methyltransferase", - "2.1.1.286 25S rRNA (adenine(2142)-N(1))-methyltransferase", - "2.1.1.287 25S rRNA (adenine(645)-N(1))-methyltransferase", - "2.1.1.288 Aklanonic acid methyltransferase", - "2.1.1.289 Cobalt-precorrin-7 (C(5))-methyltransferase", - "2.1.1.290 tRNA(Phe) (7-(3-amino-3-carboxypropyl)wyosine(37)-O)-methyltransferase", - "2.1.1.291 (R,S)-reticuline 7-O-methyltransferase", - "2.1.1.292 Carminomycin 4-O-methyltransferase", - "2.1.1.293 6-hydroxytryprostatin B O-methyltransferase", - "2.1.1.294 3-O-phospho-polymannosyl GlcNAc-diphospho-ditrans,octacis-undecaprenol 3-phospho-methyltransferase", - "2.1.1.295 2-methyl-6-phytyl-1,4-hydroquinone methyltransferase", - "2.1.1.296 Methyltransferase cap2", - "2.1.1.297 Peptide chain release factor N(5)-glutamine methyltransferase", - "2.1.1.298 Ribosomal protein L3 N(5)-glutamine methyltransferase", - "2.1.1.299 Protein N-terminal monomethyltransferase", - "2.1.1.300 Pavine N-methyltransferase", - "2.1.1.301 Cypemycin N-terminal methyltransferase", - "2.1.1.302 3-hydroxy-5-methyl-1-naphthoate 3-O-methyltransferase", - "2.1.1.303 2,7-dihydroxy-5-methyl-1-naphthoate 7-O-methyltransferase", - "2.1.1.304 L-tyrosine C(3)-methyltransferase", - "2.1.1.305 8-demethyl-8-alpha-L-rhamnosyl tetracenomycin-C 2'-O-methyltransferase", - "2.1.1.306 8-demethyl-8-(2-methoxy-alpha-L-rhamnosyl)-tetracenomycin-C 3'-O-methyltransferase", - "2.1.1.307 8-demethyl-8-(2,3-dimethoxy-alpha-L-rhamnosyl)-tetracenomycin-C 4'-O-methyltransferase", - "2.1.1.308 2-hydroxyethylphosphonate methyltransferase", - "2.1.1.309 18S rRNA (guanine(1575)-N(7))-methyltransferase", - "2.1.1.310 25S rRNA (cytosine(2870)-C(5))-methyltransferase", - "2.1.1.311 25S rRNA (cytosine(2278)-C(5))-methyltransferase", - "2.1.1.312 25S rRNA (uracil(2843)-N(3))-methyltransferase", - "2.1.1.313 25S rRNA (uracil(2634)-N(3))-methyltransferase", - "2.1.1.314 Diphthine methyl ester synthase", - "2.1.1.315 27-O-demethylrifamycin SV methyltransferase", - "2.1.1.316 Mitomycin 6-O-methyltransferase", - "2.1.1.317 Sphingolipid C(9)-methyltransferase", - "2.1.1.318 [Trehalose-6-phosphate synthase]-L-cysteine S-methyltransferase", - "2.1.1.319 Type I protein arginine methyltransferase", - "2.1.1.320 Type II protein arginine methyltransferase", - "2.1.1.321 Type III protein arginine methyltransferase", - "2.1.1.322 Type IV protein arginine methyltransferase", - "2.1.1.323 (-)-pluviatolide 4-O-methyltransferase", - "2.1.1.324 dTDP-4-amino-2,3,4,6-tetradeoxy-D-glucose N,N-dimethyltransferase", - "2.1.1.n1 Resorcinol O-methyltransferase", - "2.1.1.n4 Thiocyanate methyltransferase", - "2.1.1.n7 5-pentadecatrienyl resorcinol O-methyltransferase", - "2.1.1.n8 Small RNA 2'-O-methyltransferase", - "2.1.1.n11 Methylphosphotriester-DNA--[protein]-cysteine S-methyltransferase", - "2.1.1.n12 2-phytyl-1,4-naphtoquinone methyltransferase", - "2.1.2.1 Glycine hydroxymethyltransferase", - "2.1.2.2 Phosphoribosylglycinamide formyltransferase", - "2.1.2.3 Phosphoribosylaminoimidazolecarboxamide formyltransferase", - "2.1.2.4 Glycine formimidoyltransferase", - "2.1.2.5 Glutamate formimidoyltransferase", - "2.1.2.7 D-alanine 2-hydroxymethyltransferase", - "2.1.2.8 Deoxycytidylate 5-hydroxymethyltransferase", - "2.1.2.9 Methionyl-tRNA formyltransferase", - "2.1.2.10 Aminomethyltransferase", - "2.1.2.11 3-methyl-2-oxobutanoate hydroxymethyltransferase", - "2.1.2.13 UDP-4-amino-4-deoxy-L-arabinose formyltransferase", - "2.1.3.1 Methylmalonyl-CoA carboxytransferase", - "2.1.3.2 Aspartate carbamoyltransferase", - "2.1.3.3 Ornithine carbamoyltransferase", - "2.1.3.5 Oxamate carbamoyltransferase", - "2.1.3.6 Putrescine carbamoyltransferase", - "2.1.3.7 3-hydroxymethylcephem carbamoyltransferase", - "2.1.3.8 Lysine carbamoyltransferase", - "2.1.3.9 N-acetylornithine carbamoyltransferase", - "2.1.3.10 Malonyl-S-ACP:biotin-protein carboxyltransferase", - "2.1.3.11 N-succinylornithine carbamoyltransferase", - "2.1.3.12 Decarbamoylnovobiocin carbamoyltransferase", - "2.1.4.1 Glycine amidinotransferase", - "2.1.4.2 Scyllo-inosamine-4-phosphate amidinotransferase", - "2.2.1.1 Transketolase", - "2.2.1.2 Transaldolase", - "2.2.1.3 Formaldehyde transketolase", - "2.2.1.4 Acetoin--ribose-5-phosphate transaldolase", - "2.2.1.5 2-hydroxy-3-oxoadipate synthase", - "2.2.1.6 Acetolactate synthase", - "2.2.1.7 1-deoxy-D-xylulose-5-phosphate synthase", - "2.2.1.8 Fluorothreonine transaldolase", - "2.2.1.9 2-succinyl-5-enolpyruvyl-6-hydroxy-3-cyclohexene-1-carboxylic-acid synthase", - "2.2.1.10 2-amino-3,7-dideoxy-D-threo-hept-6-ulosonate synthase", - "2.2.1.11 6-deoxy-5-ketofructose 1-phosphate synthase", - "2.2.1.12 3-acetyloctanal synthase", - "2.3.1.1 Amino-acid N-acetyltransferase", - "2.3.1.2 Imidazole N-acetyltransferase", - "2.3.1.3 Glucosamine N-acetyltransferase", - "2.3.1.4 Glucosamine-phosphate N-acetyltransferase", - "2.3.1.5 Arylamine N-acetyltransferase", - "2.3.1.6 Choline O-acetyltransferase", - "2.3.1.7 Carnitine O-acetyltransferase", - "2.3.1.8 Phosphate acetyltransferase", - "2.3.1.9 Acetyl-CoA C-acetyltransferase", - "2.3.1.10 Hydrogen-sulfide S-acetyltransferase", - "2.3.1.11 Thioethanolamine S-acetyltransferase", - "2.3.1.12 Dihydrolipoyllysine-residue acetyltransferase", - "2.3.1.13 Glycine N-acyltransferase", - "2.3.1.14 Glutamine N-phenylacetyltransferase", - "2.3.1.15 Glycerol-3-phosphate 1-O-acyltransferase", - "2.3.1.16 Acetyl-CoA C-acyltransferase", - "2.3.1.17 Aspartate N-acetyltransferase", - "2.3.1.18 Galactoside O-acetyltransferase", - "2.3.1.19 Phosphate butyryltransferase", - "2.3.1.20 Diacylglycerol O-acyltransferase", - "2.3.1.21 Carnitine O-palmitoyltransferase", - "2.3.1.22 2-acylglycerol O-acyltransferase", - "2.3.1.23 1-acylglycerophosphocholine O-acyltransferase", - "2.3.1.24 Sphingosine N-acyltransferase", - "2.3.1.25 Plasmalogen synthase", - "2.3.1.26 Sterol O-acyltransferase", - "2.3.1.27 Cortisol O-acetyltransferase", - "2.3.1.28 Chloramphenicol O-acetyltransferase", - "2.3.1.29 Glycine C-acetyltransferase", - "2.3.1.30 Serine O-acetyltransferase", - "2.3.1.31 Homoserine O-acetyltransferase", - "2.3.1.32 Lysine N-acetyltransferase", - "2.3.1.33 Histidine N-acetyltransferase", - "2.3.1.34 D-tryptophan N-acetyltransferase", - "2.3.1.35 Glutamate N-acetyltransferase", - "2.3.1.36 D-amino-acid N-acetyltransferase", - "2.3.1.37 5-aminolevulinate synthase", - "2.3.1.38 [Acyl-carrier-protein] S-acetyltransferase", - "2.3.1.39 [Acyl-carrier-protein] S-malonyltransferase", - "2.3.1.40 Acyl-[acyl-carrier-protein]--phospholipid O-acyltransferase", - "2.3.1.41 Beta-ketoacyl-[acyl-carrier-protein] synthase I", - "2.3.1.42 Glycerone-phosphate O-acyltransferase", - "2.3.1.43 Phosphatidylcholine--sterol O-acyltransferase", - "2.3.1.44 N-acetylneuraminate 4-O-acetyltransferase", - "2.3.1.45 N-acetylneuraminate 7-O(or 9-O)-acetyltransferase", - "2.3.1.46 Homoserine O-succinyltransferase", - "2.3.1.47 8-amino-7-oxononanoate synthase", - "2.3.1.48 Histone acetyltransferase", - "2.3.1.49 Deacetyl-[citrate-(pro-3S)-lyase] S-acetyltransferase", - "2.3.1.50 Serine C-palmitoyltransferase", - "2.3.1.51 1-acylglycerol-3-phosphate O-acyltransferase", - "2.3.1.52 2-acylglycerol-3-phosphate O-acyltransferase", - "2.3.1.53 Phenylalanine N-acetyltransferase", - "2.3.1.54 Formate C-acetyltransferase", - "2.3.1.56 Aromatic-hydroxylamine O-acetyltransferase", - "2.3.1.57 Diamine N-acetyltransferase", - "2.3.1.58 2,3-diaminopropionate N-oxalyltransferase", - "2.3.1.59 Gentamicin 2'-N-acetyltransferase", - "2.3.1.60 Gentamicin 3-N-acetyltransferase", - "2.3.1.61 Dihydrolipoyllysine-residue succinyltransferase", - "2.3.1.62 2-acylglycerophosphocholine O-acyltransferase", - "2.3.1.63 1-alkylglycerophosphocholine O-acyltransferase", - "2.3.1.64 Agmatine N(4)-coumaroyltransferase", - "2.3.1.65 Bile acid-CoA:amino acid N-acyltransferase", - "2.3.1.66 Leucine N-acetyltransferase", - "2.3.1.67 1-alkylglycerophosphocholine O-acetyltransferase", - "2.3.1.68 Glutamine N-acyltransferase", - "2.3.1.69 Monoterpenol O-acetyltransferase", - "2.3.1.71 Glycine N-benzoyltransferase", - "2.3.1.72 Indoleacetylglucose--inositol O-acyltransferase", - "2.3.1.73 Diacylglycerol--sterol O-acyltransferase", - "2.3.1.74 Naringenin-chalcone synthase", - "2.3.1.75 Long-chain-alcohol O-fatty-acyltransferase", - "2.3.1.76 Retinol O-fatty-acyltransferase", - "2.3.1.77 Triacylglycerol--sterol O-acyltransferase", - "2.3.1.78 Heparan-alpha-glucosaminide N-acetyltransferase", - "2.3.1.79 Maltose O-acetyltransferase", - "2.3.1.80 Cysteine-S-conjugate N-acetyltransferase", - "2.3.1.81 Aminoglycoside N(3)-acetyltransferase", - "2.3.1.82 Aminoglycoside 6'-N-acetyltransferase", - "2.3.1.83 Phosphatidylcholine--dolichol O-acyltransferase", - "2.3.1.84 Alcohol O-acetyltransferase", - "2.3.1.85 Fatty-acid synthase", - "2.3.1.86 Fatty-acyl-CoA synthase", - "2.3.1.87 Aralkylamine N-acetyltransferase", - "2.3.1.88 Peptide alpha-N-acetyltransferase", - "2.3.1.89 Tetrahydrodipicolinate N-acetyltransferase", - "2.3.1.90 Beta-glucogallin O-galloyltransferase", - "2.3.1.91 Sinapoylglucose--choline O-sinapoyltransferase", - "2.3.1.92 Sinapoylglucose--malate O-sinapoyltransferase", - "2.3.1.93 13-hydroxylupanine O-tigloyltransferase", - "2.3.1.94 6-deoxyerythronolide-B synthase", - "2.3.1.95 Trihydroxystilbene synthase", - "2.3.1.96 Glycoprotein N-palmitoyltransferase", - "2.3.1.97 Glycylpeptide N-tetradecanoyltransferase", - "2.3.1.98 Chlorogenate--glucarate O-hydroxycinnamoyltransferase", - "2.3.1.99 Quinate O-hydroxycinnamoyltransferase", - "2.3.1.100 [Myelin-proteolipid] O-palmitoyltransferase", - "2.3.1.101 Formylmethanofuran--tetrahydromethanopterin N-formyltransferase", - "2.3.1.102 N(6)-hydroxylysine O-acetyltransferase", - "2.3.1.103 Sinapoylglucose--sinapoylglucose O-sinapoyltransferase", - "2.3.1.105 Alkylglycerophosphate 2-O-acetyltransferase", - "2.3.1.106 Tartronate O-hydroxycinnamoyltransferase", - "2.3.1.107 Deacetylvindoline O-acetyltransferase", - "2.3.1.108 Alpha-tubulin N-acetyltransferase", - "2.3.1.109 Arginine N-succinyltransferase", - "2.3.1.110 Tyramine N-feruloyltransferase", - "2.3.1.111 Mycocerosate synthase", - "2.3.1.112 D-tryptophan N-malonyltransferase", - "2.3.1.113 Anthranilate N-malonyltransferase", - "2.3.1.114 3,4-dichloroaniline N-malonyltransferase", - "2.3.1.115 Isoflavone-7-O-beta-glucoside 6''-O-malonyltransferase", - "2.3.1.116 Flavonol-3-O-beta-glucoside O-malonyltransferase", - "2.3.1.117 2,3,4,5-tetrahydropyridine-2,6-dicarboxylate N-succinyltransferase", - "2.3.1.118 N-hydroxyarylamine O-acetyltransferase", - "2.3.1.121 1-alkenylglycerophosphoethanolamine O-acyltransferase", - "2.3.1.122 Trehalose O-mycolyltransferase", - "2.3.1.123 Dolichol O-acyltransferase", - "2.3.1.125 1-alkyl-2-acetylglycerol O-acyltransferase", - "2.3.1.126 Isocitrate O-dihydroxycinnamoyltransferase", - "2.3.1.127 Ornithine N-benzoyltransferase", - "2.3.1.128 Ribosomal-protein-alanine N-acetyltransferase", - "2.3.1.129 Acyl-[acyl-carrier-protein]--UDP-N-acetylglucosamine O-acyltransferase", - "2.3.1.130 Galactarate O-hydroxycinnamoyltransferase", - "2.3.1.131 Glucarate O-hydroxycinnamoyltransferase", - "2.3.1.132 Glucarolactone O-hydroxycinnamoyltransferase", - "2.3.1.133 Shikimate O-hydroxycinnamoyltransferase", - "2.3.1.134 Galactolipid O-acyltransferase", - "2.3.1.135 Phosphatidylcholine--retinol O-acyltransferase", - "2.3.1.136 Polysialic-acid O-acetyltransferase", - "2.3.1.137 Carnitine O-octanoyltransferase", - "2.3.1.138 Putrescine N-hydroxycinnamoyltransferase", - "2.3.1.139 Ecdysone O-acyltransferase", - "2.3.1.140 Rosmarinate synthase", - "2.3.1.141 Galactosylacylglycerol O-acyltransferase", - "2.3.1.142 Glycoprotein O-fatty-acyltransferase", - "2.3.1.143 Beta-glucogallin--tetrakisgalloylglucose O-galloyltransferase", - "2.3.1.144 Anthranilate N-benzoyltransferase", - "2.3.1.145 Piperidine N-piperoyltransferase", - "2.3.1.146 Pinosylvin synthase", - "2.3.1.147 Glycerophospholipid arachidonoyl-transferase (CoA-independent)", - "2.3.1.148 Glycerophospholipid acyltransferase (CoA-dependent)", - "2.3.1.149 Platelet-activating factor acetyltransferase", - "2.3.1.150 Salutaridinol 7-O-acetyltransferase", - "2.3.1.151 2,3',4,6-tetrahydroxybenzophenone synthase", - "2.3.1.152 Alcohol O-cinnamoyltransferase", - "2.3.1.153 Anthocyanin 5-(6'''-hydroxycinnamoyltransferase)", - "2.3.1.154 Propionyl-CoA C(2)-trimethyltridecanoyltransferase", - "2.3.1.155 Acetyl-CoA C-myristoyltransferase", - "2.3.1.156 Phloroisovalerophenone synthase", - "2.3.1.157 Glucosamine-1-phosphate N-acetyltransferase", - "2.3.1.158 Phospholipid:diacylglycerol acyltransferase", - "2.3.1.159 Acridone synthase", - "2.3.1.160 Vinorine synthase", - "2.3.1.161 Lovastatin nonaketide synthase", - "2.3.1.162 Taxadien-5-alpha-ol O-acetyltransferase", - "2.3.1.163 10-hydroxytaxane O-acetyltransferase", - "2.3.1.164 Isopenicillin-N N-acyltransferase", - "2.3.1.165 6-methylsalicylic acid synthase", - "2.3.1.166 2-alpha-hydroxytaxane 2-O-benzoyltransferase", - "2.3.1.167 10-deacetylbaccatin III 10-O-acetyltransferase", - "2.3.1.168 Dihydrolipoyllysine-residue (2-methylpropanoyl)transferase", - "2.3.1.169 CO-methylating acetyl-CoA synthase", - "2.3.1.170 6'-deoxychalcone synthase", - "2.3.1.171 Anthocyanin 6''-O-malonyltransferase", - "2.3.1.172 Anthocyanin 5-O-glucoside 6'''-O-malonyltransferase", - "2.3.1.173 Flavonol-3-O-triglucoside O-coumaroyltransferase", - "2.3.1.174 3-oxoadipyl-CoA thiolase", - "2.3.1.175 Deacetylcephalosporin-C acetyltransferase", - "2.3.1.176 Propanoyl-CoA C-acyltransferase", - "2.3.1.177 3,5-dihydroxybiphenyl synthase", - "2.3.1.178 Diaminobutyrate acetyltransferase", - "2.3.1.179 Beta-ketoacyl-[acyl-carrier-protein] synthase II", - "2.3.1.180 Beta-ketoacyl-[acyl-carrier-protein] synthase III", - "2.3.1.181 Lipoyl(octanoyl) transferase", - "2.3.1.182 (R)-citramalate synthase", - "2.3.1.183 Phosphinothricin acetyltransferase", - "2.3.1.184 Acyl-homoserine-lactone synthase", - "2.3.1.185 Tropine acyltransferase", - "2.3.1.186 Pseudotropine acyltransferase", - "2.3.1.187 Acetyl-S-ACP:malonate ACP transferase", - "2.3.1.188 Omega-hydroxypalmitate O-feruloyl transferase", - "2.3.1.189 Mycothiol synthase", - "2.3.1.190 Acetoin dehydrogenase", - "2.3.1.191 UDP-3-O-(3-hydroxymyristoyl)glucosamine N-acyltransferase", - "2.3.1.192 Glycine N-phenylacetyltransferase", - "2.3.1.193 tRNA(Met) cytidine acetyltransferase", - "2.3.1.194 Acetoacetyl-CoA synthase", - "2.3.1.195 (Z)-3-hexen-1-ol acetyltransferase", - "2.3.1.196 Benzyl alcohol O-benzoyltransferase", - "2.3.1.197 dTDP-3-amino-3,6-dideoxy-alpha-D-galactopyranose 3-N-acetyltransferase", - "2.3.1.198 Glycerol-3-phosphate 2-O-acyltransferase", - "2.3.1.199 Very-long-chain 3-oxoacyl-CoA synthase", - "2.3.1.200 Lipoyl amidotransferase", - "2.3.1.201 UDP-2-acetamido-3-amino-2,3-dideoxy-glucuronate N-acetyltransferase", - "2.3.1.202 UDP-4-amino-4,6-dideoxy-N-acetyl-beta-L-altrosamine N-acetyltransferase", - "2.3.1.203 UDP-N-acetylbacillosamine N-acetyltransferase", - "2.3.1.204 Octanoyl-[GcvH]:protein N-octanoyltransferase", - "2.3.1.205 Fumigaclavine B O-acetyltransferase", - "2.3.1.206 3,5,7-trioxododecanoyl-CoA synthase", - "2.3.1.207 Beta-ketodecanoyl-[acyl-carrier-protein] synthase", - "2.3.1.208 4-hydroxycoumarin synthase", - "2.3.1.209 dTDP-4-amino-4,6-dideoxy-D-glucose acyltransferase", - "2.3.1.210 dTDP-4-amino-4,6-dideoxy-D-galactose acyltransferase", - "2.3.1.211 Bisdemethoxycurcumin synthase", - "2.3.1.212 Benzalacetone synthase", - "2.3.1.213 Cyanidin 3-O-(6-O-glucosyl-2-O-xylosylgalactoside) 6'''-O-hydroxycinnamoyltransferase", - "2.3.1.214 Pelargonidin 3-O-(6-caffeoylglucoside) 5-O-(6-O-malonylglucoside) 4'''-malonyltransferase", - "2.3.1.215 Anthocyanidin 3-O-glucoside 6''-O-acyltransferase", - "2.3.1.216 5,7-dihydroxy-2-methylchromone synthase", - "2.3.1.217 Curcumin synthase", - "2.3.1.218 Phenylpropanoylacetyl-CoA synthase", - "2.3.1.219 Demethoxycurcumin synthase", - "2.3.1.220 2,4,6-trihydroxybenzophenone synthase", - "2.3.1.221 Noranthrone synthase", - "2.3.1.222 Phosphate propanoyltransferase", - "2.3.1.223 3-oxo-5,6-didehydrosuberyl-CoA thiolase", - "2.3.1.224 Acetyl-CoA-benzylalcohol acetyltransferase", - "2.3.1.225 Protein S-acyltransferase", - "2.3.1.226 Carboxymethylproline synthase", - "2.3.1.227 GDP-perosamine N-acetyltransferase", - "2.3.1.228 Isovaleryl-homoserine lactone synthase", - "2.3.1.229 4-coumaroyl-homoserine lactone synthase", - "2.3.1.230 2-heptyl-4(1H)-quinolone synthase", - "2.3.1.231 tRNA(Phe) (7-(3-amino-3-(methoxycarbonyl)propyl)wyosine(37)-N)-methoxycarbonyltransferase", - "2.3.1.232 Methanol O-anthraniloyltransferase", - "2.3.1.233 1,3,6,8-tetrahydroxynaphthalene synthase", - "2.3.1.234 N(6)-L-threonylcarbamoyladenine synthase", - "2.3.1.235 Tetracenomycin F2 synthase", - "2.3.1.236 5-methylnaphthoic acid synthase", - "2.3.1.237 Neocarzinostatin naphthoate synthase", - "2.3.1.238 Monacolin J acid methylbutanoate transferase", - "2.3.1.239 10-deoxymethynolide syntase", - "2.3.1.240 Narbonolide synthase", - "2.3.1.241 Kdo(2)-lipid IV(A) lauroyltransferase", - "2.3.1.242 Kdo(2)-lipid IV(A) palmitoleoyltransferase", - "2.3.1.243 Lauroyl-Kdo(2)-lipid IV(A) myristoyltransferase", - "2.3.1.244 2-methylbutanoate polyketide synthase", - "2.3.1.245 3-hydroxy-5-phosphonooxypentane-2,4-dione thiolase", - "2.3.1.246 3,5-dihydroxyphenylacetyl-CoA synthase", - "2.3.1.247 3-keto-5-aminohexanoate cleavage enzyme", - "2.3.1.248 Spermidine disinapoyl transferase", - "2.3.1.249 Spermidine dicoumaroyl transferase", - "2.3.1.250 [Wnt protein] O-palmitoleoyl transferase", - "2.3.1.251 Lipid IV(A) palmitoyltransferase", - "2.3.1.n2 Phosphate acyltransferase", - "2.3.1.n3 Glycerol-3-phosphate acyltransferase (acyl-phosphate transferring)", - "2.3.1.n4 1-acyl-sn-glycerol-3-phosphate acyltransferase", - "2.3.1.n5 Glycerol-3-phosphate acyltransferase (acyl-[acyl-carrier-protein]-transferring)", - "2.3.1.n6 1-acylglycerophosphoserine O-acyltransferase", - "2.3.1.n7 1-acylglycerophosphoethanolamine O-acyltransferase", - "2.3.1.n12 Sinapoyl-beta-D-glucose:anthocyanin sinapoyltransferase", - "2.3.2.1 D-glutamyltransferase", - "2.3.2.2 Gamma-glutamyltransferase", - "2.3.2.3 Lysyltransferase", - "2.3.2.4 Gamma-glutamylcyclotransferase", - "2.3.2.5 Glutaminyl-peptide cyclotransferase", - "2.3.2.6 Leucyltransferase", - "2.3.2.7 Aspartyltransferase", - "2.3.2.8 Arginyltransferase", - "2.3.2.9 Agaritine gamma-glutamyltransferase", - "2.3.2.10 UDP-N-acetylmuramoylpentapeptide-lysine N(6)-alanyltransferase", - "2.3.2.11 Alanylphosphatidylglycerol synthase", - "2.3.2.12 Peptidyltransferase", - "2.3.2.13 Protein-glutamine gamma-glutamyltransferase", - "2.3.2.14 D-alanine gamma-glutamyltransferase", - "2.3.2.15 Glutathione gamma-glutamylcysteinyltransferase", - "2.3.2.16 Lipid II:glycine glycyltransferase", - "2.3.2.17 N-acetylmuramoyl-L-alanyl-D-glutamyl-L-lysyl-(N(6)-glycyl)-D-alanyl-D-alanine-diphosphoundecaprenyl-N-acetylglucosamine:glycine glycyltransferase", - "2.3.2.18 N-acetylmuramoyl-L-alanyl-D-glutamyl-L-lysyl-(N(6)-triglycine)-D-alanyl-D-alanine-diphosphoundecaprenyl-N-acetylglucosamine:glycine glycyltransferase", - "2.3.2.19 Ribostamycin:4-(gamma-L-glutamylamino)-(S)-2-hydroxybutanoyl-[BtrI acyl-carrier protein] 4-(gamma-L-glutamylamino)-(S)-2-hydroxybutanoate transferase", - "2.3.2.20 Cyclo(L-leucyl-L-phenylalanyl) synthase", - "2.3.2.21 Cyclo(L-tyrosyl-L-tyrosyl) synthase", - "2.3.2.22 Cyclo(L-leucyl-L-leucyl) synthase", - "2.3.2.23 E2 ubiquitin-conjugating enzyme", - "2.3.2.24 (E3-independent) E2 ubiquitin-conjugating enzyme", - "2.3.2.25 N-terminal E2 ubiquitin-conjugating enzyme", - "2.3.2.26 HECT-type E3 ubiquitin transferase", - "2.3.2.27 RING-type E3 ubiquitin transferase", - "2.3.2.28 L-allo-isoleucyltransferase", - "2.3.3.1 Citrate (Si)-synthase", - "2.3.3.2 Decylcitrate synthase", - "2.3.3.3 Citrate (Re)-synthase", - "2.3.3.4 Decylhomocitrate synthase", - "2.3.3.5 2-methylcitrate synthase", - "2.3.3.6 2-ethylmalate synthase", - "2.3.3.7 3-ethylmalate synthase", - "2.3.3.8 ATP citrate synthase", - "2.3.3.9 Malate synthase", - "2.3.3.10 Hydroxymethylglutaryl-CoA synthase", - "2.3.3.11 2-hydroxyglutarate synthase", - "2.3.3.12 3-propylmalate synthase", - "2.3.3.13 2-isopropylmalate synthase", - "2.3.3.14 Homocitrate synthase", - "2.3.3.15 Sulfoacetaldehyde acetyltransferase", - "2.3.3.16 Citrate synthase (unknown stereospecificity)", - "2.4.1.1 Glycogen phosphorylase", - "2.4.1.2 Dextrin dextranase", - "2.4.1.4 Amylosucrase", - "2.4.1.5 Dextransucrase", - "2.4.1.7 Sucrose phosphorylase", - "2.4.1.8 Maltose phosphorylase", - "2.4.1.9 Inulosucrase", - "2.4.1.10 Levansucrase", - "2.4.1.11 Glycogen(starch) synthase", - "2.4.1.12 Cellulose synthase (UDP-forming)", - "2.4.1.13 Sucrose synthase", - "2.4.1.14 Sucrose-phosphate synthase", - "2.4.1.15 Alpha,alpha-trehalose-phosphate synthase (UDP-forming)", - "2.4.1.16 Chitin synthase", - "2.4.1.17 Glucuronosyltransferase", - "2.4.1.18 1,4-alpha-glucan branching enzyme", - "2.4.1.19 Cyclomaltodextrin glucanotransferase", - "2.4.1.20 Cellobiose phosphorylase", - "2.4.1.21 Starch synthase", - "2.4.1.22 Lactose synthase", - "2.4.1.23 Sphingosine beta-galactosyltransferase", - "2.4.1.24 1,4-alpha-glucan 6-alpha-glucosyltransferase", - "2.4.1.25 4-alpha-glucanotransferase", - "2.4.1.26 DNA alpha-glucosyltransferase", - "2.4.1.27 DNA beta-glucosyltransferase", - "2.4.1.28 Glucosyl-DNA beta-glucosyltransferase", - "2.4.1.29 Cellulose synthase (GDP-forming)", - "2.4.1.30 1,3-beta-oligoglucan phosphorylase", - "2.4.1.31 Laminaribiose phosphorylase", - "2.4.1.32 Glucomannan 4-beta-mannosyltransferase", - "2.4.1.33 Mannuronan synthase", - "2.4.1.34 1,3-beta-glucan synthase", - "2.4.1.35 Phenol beta-glucosyltransferase", - "2.4.1.36 Alpha,alpha-trehalose-phosphate synthase (GDP-forming)", - "2.4.1.37 Fucosylgalactoside 3-alpha-galactosyltransferase", - "2.4.1.38 Beta-N-acetylglucosaminylglycopeptide beta-1,4-galactosyltransferase", - "2.4.1.39 Steroid N-acetylglucosaminyltransferase", - "2.4.1.40 Glycoprotein-fucosylgalactoside alpha-N-acetylgalactosaminyltransferase", - "2.4.1.41 Polypeptide N-acetylgalactosaminyltransferase", - "2.4.1.43 Polygalacturonate 4-alpha-galacturonosyltransferase", - "2.4.1.44 Lipopolysaccharide 3-alpha-galactosyltransferase", - "2.4.1.45 2-hydroxyacylsphingosine 1-beta-galactosyltransferase", - "2.4.1.46 Monogalactosyldiacylglycerol synthase", - "2.4.1.47 N-acylsphingosine galactosyltransferase", - "2.4.1.48 Heteroglycan alpha-mannosyltransferase", - "2.4.1.49 Cellodextrin phosphorylase", - "2.4.1.50 Procollagen galactosyltransferase", - "2.4.1.52 Poly(glycerol-phosphate) alpha-glucosyltransferase", - "2.4.1.53 Poly(ribitol-phosphate) beta-glucosyltransferase", - "2.4.1.54 Undecaprenyl-phosphate mannosyltransferase", - "2.4.1.56 Lipopolysaccharide N-acetylglucosaminyltransferase", - "2.4.1.57 Phosphatidylinositol alpha-mannosyltransferase", - "2.4.1.58 Lipopolysaccharide glucosyltransferase I", - "2.4.1.60 Abequosyltransferase", - "2.4.1.62 Ganglioside galactosyltransferase", - "2.4.1.63 Linamarin synthase", - "2.4.1.64 Alpha,alpha-trehalose phosphorylase", - "2.4.1.65 3-galactosyl-N-acetylglucosaminide 4-alpha-L-fucosyltransferase", - "2.4.1.66 Procollagen glucosyltransferase", - "2.4.1.67 Galactinol--raffinose galactosyltransferase", - "2.4.1.68 Glycoprotein 6-alpha-L-fucosyltransferase", - "2.4.1.69 Galactoside 2-alpha-L-fucosyltransferase", - "2.4.1.70 Poly(ribitol-phosphate) N-acetylglucosaminyltransferase", - "2.4.1.71 Arylamine glucosyltransferase", - "2.4.1.73 Lipopolysaccharide glucosyltransferase II", - "2.4.1.74 Glycosaminoglycan galactosyltransferase", - "2.4.1.78 Phosphopolyprenol glucosyltransferase", - "2.4.1.79 Globotriaosylceramide 3-beta-N-acetylgalactosaminyltransferase", - "2.4.1.80 Ceramide glucosyltransferase", - "2.4.1.81 Flavone 7-O-beta-glucosyltransferase", - "2.4.1.82 Galactinol--sucrose galactosyltransferase", - "2.4.1.83 Dolichyl-phosphate beta-D-mannosyltransferase", - "2.4.1.85 Cyanohydrin beta-glucosyltransferase", - "2.4.1.86 Glucosaminylgalactosylglucosylceramide beta-galactosyltransferase", - "2.4.1.87 N-acetyllactosaminide 3-alpha-galactosyltransferase", - "2.4.1.88 Globoside alpha-N-acetylgalactosaminyltransferase", - "2.4.1.90 N-acetyllactosamine synthase", - "2.4.1.91 Flavonol 3-O-glucosyltransferase", - "2.4.1.92 (N-acetylneuraminyl)-galactosylglucosylceramide N-acetylgalactosaminyltransferase", - "2.4.1.94 Protein N-acetylglucosaminyltransferase", - "2.4.1.95 Bilirubin-glucuronoside glucuronosyltransferase", - "2.4.1.96 sn-glycerol-3-phosphate 1-galactosyltransferase", - "2.4.1.97 1,3-beta-D-glucan phosphorylase", - "2.4.1.99 Sucrose:sucrose fructosyltransferase", - "2.4.1.100 2,1-fructan:2,1-fructan 1-fructosyltransferase", - "2.4.1.101 Alpha-1,3-mannosyl-glycoprotein 2-beta-N-acetylglucosaminyltransferase", - "2.4.1.102 Beta-1,3-galactosyl-O-glycosyl-glycoprotein beta-1,6-N-acetylglucosaminyltransferase", - "2.4.1.103 Alizarin 2-beta-glucosyltransferase", - "2.4.1.104 o-dihydroxycoumarin 7-O-glucosyltransferase", - "2.4.1.105 Vitexin beta-glucosyltransferase", - "2.4.1.106 Isovitexin beta-glucosyltransferase", - "2.4.1.109 Dolichyl-phosphate-mannose--protein mannosyltransferase", - "2.4.1.110 tRNA-queuosine beta-mannosyltransferase", - "2.4.1.111 Coniferyl-alcohol glucosyltransferase", - "2.4.1.113 Alpha-1,4-glucan-protein synthase (ADP-forming)", - "2.4.1.114 2-coumarate O-beta-glucosyltransferase", - "2.4.1.115 Anthocyanidin 3-O-glucosyltransferase", - "2.4.1.116 Cyanidin 3-O-rutinoside 5-O-glucosyltransferase", - "2.4.1.117 Dolichyl-phosphate beta-glucosyltransferase", - "2.4.1.118 Cytokinin 7-beta-glucosyltransferase", - "2.4.1.120 Sinapate 1-glucosyltransferase", - "2.4.1.121 Indole-3-acetate beta-glucosyltransferase", - "2.4.1.122 Glycoprotein-N-acetylgalactosamine 3-beta-galactosyltransferase", - "2.4.1.123 Inositol 3-alpha-galactosyltransferase", - "2.4.1.125 Sucrose--1,6-alpha-glucan 3(6)-alpha-glucosyltransferase", - "2.4.1.126 Hydroxycinnamate 4-beta-glucosyltransferase", - "2.4.1.127 Monoterpenol beta-glucosyltransferase", - "2.4.1.128 Scopoletin glucosyltransferase", - "2.4.1.129 Peptidoglycan glycosyltransferase", - "2.4.1.131 GDP-Man:Man(3)GlcNAc(2)-PP-dolichol alpha-1,2-mannosyltransferase", - "2.4.1.132 GDP-Man:Man(1)GlcNAc(2)-PP-dolichol alpha-1,3-mannosyltransferase", - "2.4.1.133 Xylosylprotein 4-beta-galactosyltransferase", - "2.4.1.134 Galactosylxylosylprotein 3-beta-galactosyltransferase", - "2.4.1.135 Galactosylgalactosylxylosylprotein 3-beta-glucuronosyltransferase", - "2.4.1.136 Gallate 1-beta-glucosyltransferase", - "2.4.1.137 sn-glycerol-3-phosphate 2-alpha-galactosyltransferase", - "2.4.1.138 Mannotetraose 2-alpha-N-acetylglucosaminyltransferase", - "2.4.1.139 Maltose synthase", - "2.4.1.140 Alternansucrase", - "2.4.1.141 N-acetylglucosaminyldiphosphodolichol N-acetylglucosaminyltransferase", - "2.4.1.142 Chitobiosyldiphosphodolichol beta-mannosyltransferase", - "2.4.1.143 Alpha-1,6-mannosyl-glycoprotein 2-beta-N-acetylglucosaminyltransferase", - "2.4.1.144 Beta-1,4-mannosyl-glycoprotein 4-beta-N-acetylglucosaminyltransferase", - "2.4.1.145 Alpha-1,3-mannosyl-glycoprotein 4-beta-N-acetylglucosaminyltransferase", - "2.4.1.146 Beta-1,3-galactosyl-O-glycosyl-glycoprotein beta-1,3-N-acetylglucosaminyltransferase", - "2.4.1.147 Acetylgalactosaminyl-O-glycosyl-glycoprotein beta-1,3-N-acetylglucosaminyltransferase", - "2.4.1.148 Acetylgalactosaminyl-O-glycosyl-glycoprotein beta-1,6-N-acetylglucosaminyltransferase", - "2.4.1.149 N-acetyllactosaminide beta-1,3-N-acetylglucosaminyltransferase", - "2.4.1.150 N-acetyllactosaminide beta-1,6-N-acetylglucosaminyl-transferase", - "2.4.1.152 4-galactosyl-N-acetylglucosaminide 3-alpha-L-fucosyltransferase", - "2.4.1.153 UDP-N-acetylglucosamine--dolichyl-phosphate N-acetylglucosaminyltransferase", - "2.4.1.155 Alpha-1,6-mannosyl-glycoprotein 6-beta-N-acetylglucosaminyltransferase", - "2.4.1.156 Indolylacetyl-myo-inositol galactosyltransferase", - "2.4.1.157 1,2-diacylglycerol 3-glucosyltransferase", - "2.4.1.158 13-hydroxydocosanoate 13-beta-glucosyltransferase", - "2.4.1.159 Flavonol-3-O-glucoside L-rhamnosyltransferase", - "2.4.1.160 Pyridoxine 5'-O-beta-D-glucosyltransferase", - "2.4.1.161 Oligosaccharide 4-alpha-D-glucosyltransferase", - "2.4.1.162 Aldose beta-D-fructosyltransferase", - "2.4.1.163 Beta-galactosyl-N-acetylglucosaminylgalactosylglucosyl-ceramide beta-1,3-acetylglucosaminyltransferase", - "2.4.1.164 Galactosyl-N-acetylglucosaminylgalactosylglucosyl-ceramide beta-1,6-N-acetylglucosaminyltransferase", - "2.4.1.165 N-acetylneuraminylgalactosylglucosylceramide beta-1,4-N-acetylgalactosaminyltransferase", - "2.4.1.166 Raffinose--raffinose alpha-galactosyltransferase", - "2.4.1.167 Sucrose 6(F)-alpha-galactosyltransferase", - "2.4.1.168 Xyloglucan 4-glucosyltransferase", - "2.4.1.170 Isoflavone 7-O-glucosyltransferase", - "2.4.1.171 Methyl-ONN-azoxymethanol beta-D-glucosyltransferase", - "2.4.1.172 Salicyl-alcohol beta-D-glucosyltransferase", - "2.4.1.173 Sterol 3-beta-glucosyltransferase", - "2.4.1.174 Glucuronylgalactosylproteoglycan 4-beta-N-acetylgalactosaminyltransferase", - "2.4.1.175 Glucuronosyl-N-acetylgalactosaminyl-proteoglycan 4-beta-N-acetylgalactosaminyltransferase", - "2.4.1.176 Gibberellin beta-D-glucosyltransferase", - "2.4.1.177 Cinnamate beta-D-glucosyltransferase", - "2.4.1.178 Hydroxymandelonitrile glucosyltransferase", - "2.4.1.179 Lactosylceramide beta-1,3-galactosyltransferase", - "2.4.1.180 Lipopolysaccharide N-acetylmannosaminouronosyltransferase", - "2.4.1.181 Hydroxyanthraquinone glucosyltransferase", - "2.4.1.182 Lipid-A-disaccharide synthase", - "2.4.1.183 Alpha-1,3-glucan synthase", - "2.4.1.184 Galactolipid galactosyltransferase", - "2.4.1.185 Flavanone 7-O-beta-glucosyltransferase", - "2.4.1.186 Glycogenin glucosyltransferase", - "2.4.1.187 N-acetylglucosaminyldiphosphoundecaprenol N-acetyl-beta-D-mannosaminyltransferase", - "2.4.1.188 N-acetylglucosaminyldiphosphoundecaprenol glucosyltransferase", - "2.4.1.189 Luteolin 7-O-glucuronosyltransferase", - "2.4.1.190 Luteolin-7-O-glucuronide 2''-O-glucuronosyltransferase", - "2.4.1.191 Luteolin-7-O-diglucuronide 4'-O-glucuronosyltransferase", - "2.4.1.192 Nuatigenin 3-beta-glucosyltransferase", - "2.4.1.193 Sarsapogenin 3-beta-glucosyltransferase", - "2.4.1.194 4-hydroxybenzoate 4-O-beta-D-glucosyltransferase", - "2.4.1.195 N-hydroxythioamide S-beta-glucosyltransferase", - "2.4.1.196 Nicotinate glucosyltransferase", - "2.4.1.197 High-mannose-oligosaccharide beta-1,4-N-acetylglucosaminyltransferase", - "2.4.1.198 Phosphatidylinositol N-acetylglucosaminyltransferase", - "2.4.1.199 Beta-mannosylphosphodecaprenol--mannooligosaccharide 6-mannosyltransferase", - "2.4.1.201 Alpha-1,6-mannosyl-glycoprotein 4-beta-N-acetylglucosaminyltransferase", - "2.4.1.202 2,4-dihydroxy-7-methoxy-2H-1,4-benzoxazin-3(4H)-one 2-D-glucosyltransferase", - "2.4.1.203 Trans-zeatin O-beta-D-glucosyltransferase", - "2.4.1.205 Galactogen 6-beta-galactosyltransferase", - "2.4.1.206 Lactosylceramide 1,3-N-acetyl-beta-D-glucosaminyltransferase", - "2.4.1.207 Xyloglucan:xyloglucosyl transferase", - "2.4.1.208 Diglucosyl diacylglycerol synthase (1,2-linking)", - "2.4.1.209 Cis-p-coumarate glucosyltransferase", - "2.4.1.210 Limonoid glucosyltransferase", - "2.4.1.211 1,3-beta-galactosyl-N-acetylhexosamine phosphorylase", - "2.4.1.212 Hyaluronan synthase", - "2.4.1.213 Glucosylglycerol-phosphate synthase", - "2.4.1.214 Glycoprotein 3-alpha-L-fucosyltransferase", - "2.4.1.215 Cis-zeatin O-beta-D-glucosyltransferase", - "2.4.1.216 Trehalose 6-phosphate phosphorylase", - "2.4.1.217 Mannosyl-3-phosphoglycerate synthase", - "2.4.1.218 Hydroquinone glucosyltransferase", - "2.4.1.219 Vomilenine glucosyltransferase", - "2.4.1.220 Indoxyl-UDPG glucosyltransferase", - "2.4.1.221 Peptide-O-fucosyltransferase", - "2.4.1.222 O-fucosylpeptide 3-beta-N-acetylglucosaminyltransferase", - "2.4.1.223 Glucuronyl-galactosyl-proteoglycan 4-alpha-N-acetylglucosaminyltransferase", - "2.4.1.224 Glucuronosyl-N-acetylglucosaminyl-proteoglycan 4-alpha-N-acetylglucosaminyltransferase", - "2.4.1.225 N-acetylglucosaminyl-proteoglycan 4-beta-glucuronosyltransferase", - "2.4.1.226 N-acetylgalactosaminyl-proteoglycan 3-beta-glucuronosyltransferase", - "2.4.1.227 Undecaprenyldiphospho-muramoylpentapeptide beta-N-acetylglucosaminyltransferase", - "2.4.1.228 Lactosylceramide 4-alpha-galactosyltransferase", - "2.4.1.229 [Skp1-protein]-hydroxyproline N-acetylglucosaminyltransferase", - "2.4.1.230 Kojibiose phosphorylase", - "2.4.1.231 Alpha,alpha-trehalose phosphorylase (configuration-retaining)", - "2.4.1.232 Initiation-specific alpha-1,6-mannosyltransferase", - "2.4.1.234 Kaempferol 3-O-galactosyltransferase", - "2.4.1.236 Flavanone 7-O-glucoside 2''-O-beta-L-rhamnosyltransferase", - "2.4.1.237 Flavonol 7-O-beta-glucosyltransferase", - "2.4.1.238 Delphinidin 3,5-di-O-glucoside 3'-O-glucosyltransferase", - "2.4.1.239 Flavonol-3-O-glucoside glucosyltransferase", - "2.4.1.240 Flavonol-3-O-glycoside glucosyltransferase", - "2.4.1.241 Digalactosyldiacylglycerol synthase", - "2.4.1.242 NDP-glucose--starch glucosyltransferase", - "2.4.1.243 6(G)-fructosyltransferase", - "2.4.1.244 N-acetyl-beta-glucosaminyl-glycoprotein 4-beta-N-acetylgalactosaminyltransferase", - "2.4.1.245 Alpha,alpha-trehalose synthase", - "2.4.1.246 Mannosylfructose-phosphate synthase", - "2.4.1.247 Beta-D-galactosyl-(1->4)-L-rhamnose phosphorylase", - "2.4.1.248 Cycloisomaltooligosaccharide glucanotransferase", - "2.4.1.249 Delphinidin 3',5'-O-glucosyltransferase", - "2.4.1.250 D-inositol-3-phosphate glycosyltransferase", - "2.4.1.251 GlcA-beta-(1->2)-D-Man-alpha-(1->3)-D-Glc-beta-(1->4)-D-Glc-alpha-1-diphospho-ditrans,octacis-undecaprenol 4-beta-mannosyltransferase", - "2.4.1.252 GDP-mannose:cellobiosyl-diphosphopolyprenol alpha-mannosyltransferase", - "2.4.1.253 Baicalein 7-O-glucuronosyltransferase", - "2.4.1.254 Cyanidin-3-O-glucoside 2''-O-glucuronosyltransferase", - "2.4.1.255 Protein O-GlcNAc transferase", - "2.4.1.256 Dolichyl-P-Glc:Glc(2)Man(9)GlcNAc(2)-PP-dolichol alpha-1,2-glucosyltransferase", - "2.4.1.257 GDP-Man:Man(2)GlcNAc(2)-PP-dolichol alpha-1,6-mannosyltransferase", - "2.4.1.258 Dolichyl-P-Man:Man(5)GlcNAc(2)-PP-dolichol alpha-1,3-mannosyltransferase", - "2.4.1.259 Dolichyl-P-Man:Man(6)GlcNAc(2)-PP-dolichol alpha-1,2-mannosyltransferase", - "2.4.1.260 Dolichyl-P-Man:Man(7)GlcNAc(2)-PP-dolichol alpha-1,6-mannosyltransferase", - "2.4.1.261 Dolichyl-P-Man:Man(8)GlcNAc(2)-PP-dolichol alpha-1,2-mannosyltransferase", - "2.4.1.262 Soyasapogenol glucuronosyltransferase", - "2.4.1.263 Abscisate beta-glucosyltransferase", - "2.4.1.264 D-man-alpha-(1->3)-D-Glc-beta-(1->4)-D-Glc-alpha-1-diphosphoundecaprenol 2-beta-glucuronyltransferase", - "2.4.1.265 Dolichyl-P-Glc:Glc(1)Man(9)GlcNAc(2)-PP-dolichol alpha-1,3-glucosyltransferase", - "2.4.1.266 Glucosyl-3-phosphoglycerate synthase", - "2.4.1.267 Dolichyl-P-Glc:Man(9)GlcNAc(2)-PP-dolichol alpha-1,3-glucosyltransferase", - "2.4.1.268 Glucosylglycerate synthase", - "2.4.1.269 Mannosylglycerate synthase", - "2.4.1.270 Mannosylglucosyl-3-phosphoglycerate synthase", - "2.4.1.271 Crocetin glucosyltransferase", - "2.4.1.272 Soyasapogenol B glucuronide galactosyltransferase", - "2.4.1.273 Soyasaponin III rhamnosyltransferase", - "2.4.1.274 Glucosylceramide beta-1,4-galactosyltransferase", - "2.4.1.275 Neolactotriaosylceramide beta-1,4-galactosyltransferase", - "2.4.1.276 Zeaxanthin glucosyltransferase", - "2.4.1.277 10-deoxymethynolide desosaminyltransferase", - "2.4.1.278 3-alpha-mycarosylerythronolide B desosaminyl transferase", - "2.4.1.279 Nigerose phosphorylase", - "2.4.1.280 N,N'-diacetylchitobiose phosphorylase", - "2.4.1.281 4-O-beta-D-mannosyl-D-glucose phosphorylase", - "2.4.1.282 3-O-alpha-D-glucosyl-L-rhamnose phosphorylase", - "2.4.1.283 2-deoxystreptamine N-acetyl-D-glucosaminyltransferase", - "2.4.1.284 2-deoxystreptamine glucosyltransferase", - "2.4.1.285 UDP-GlcNAc:ribostamycin N-acetylglucosaminyltransferase", - "2.4.1.286 Chalcone 4'-O-glucosyltransferase", - "2.4.1.287 Rhamnopyranosyl-N-acetylglucosaminyl-diphospho-decaprenol beta-1,3/1,4-galactofuranosyltransferase", - "2.4.1.288 Galactofuranosylgalactofuranosylrhamnosyl-N-acetylglucosaminyl-diphospho-decaprenol beta-1,5/1,6-galactofuranosyltransferase", - "2.4.1.289 N-acetylglucosaminyl-diphospho-decaprenol L-rhamnosyltransferase", - "2.4.1.290 N,N'-diacetylbacillosaminyl-diphospho-undecaprenol alpha-1,3-N-acetylgalactosaminyltransferase", - "2.4.1.291 N-acetylgalactosamine-N,N'-diacetylbacillosaminyl-diphospho-undecaprenol 4-alpha-N-acetylgalactosaminyltransferase", - "2.4.1.292 GalNAc-alpha-(1->4)-GalNAc-alpha-(1->3)-diNAcBac-PP-undecaprenol alpha-1,4-N-acetyl-D-galactosaminyltransferase", - "2.4.1.293 GalNAc(5)-diNAcBac-PP-undecaprenol beta-1,3-glucosyltransferase", - "2.4.1.294 Cyanidin 3-O-galactosyltransferase", - "2.4.1.295 Anthocyanin 3-O-sambubioside 5-O-glucosyltransferase", - "2.4.1.296 Anthocyanidin 3-O-coumaroylrutinoside 5-O-glucosyltransferase", - "2.4.1.297 Anthocyanidin 3-O-glucoside 2''-O-glucosyltransferase", - "2.4.1.298 Anthocyanidin 3-O-glucoside 5-O-glucosyltransferase", - "2.4.1.299 Cyanidin 3-O-glucoside 5-O-glucosyltransferase (acyl-glucose)", - "2.4.1.300 Cyanidin 3-O-glucoside 7-O-glucosyltransferase (acyl-glucose)", - "2.4.1.301 2'-deamino-2'-hydroxyneamine 1-alpha-D-kanosaminyltransferase", - "2.4.1.302 L-demethylnoviosyl transferase", - "2.4.1.303 UDP-Gal:alpha-D-GlcNAc-diphosphoundecaprenol beta-1,3-galactosyltransferase", - "2.4.1.304 UDP-Gal:alpha-D-GlcNAc-diphosphoundecaprenol beta-1,4-galactosyltransferase", - "2.4.1.305 UDP-Glc:alpha-D-GlcNAc-glucosaminyl-diphosphoundecaprenol beta-1,3-glucosyltransferase", - "2.4.1.306 UDP-GalNAc:alpha-D-GalNAc-diphosphoundecaprenol alpha-1,3-N-acetylgalactosaminyltransferase", - "2.4.1.307 UDP-Gal:alpha-D-GalNAc-1,3-alpha-D-GalNAc-diphosphoundecaprenol beta-1,3-galactosyltransferase", - "2.4.1.308 GDP-Fuc:beta-D-Gal-1,3-alpha-D-GalNAc-1,3-alpha-GalNAc-diphosphoundecaprenol alpha-1,2-fucosyltransferase", - "2.4.1.309 UDP-Gal:alpha-L-Fuc-1,2-beta-Gal-1,3-alpha-GalNAc-1,3-alpha-GalNAc-diphosphoundecaprenol alpha-1,3-galactosyltransferase", - "2.4.1.310 Vancomycin aglycone glucosyltransferase", - "2.4.1.311 dTDP-epi-vancosaminyltransferase", - "2.4.1.312 Protein O-mannose beta-1,4-N-acetylglucosaminyltransferase", - "2.4.1.313 Protein O-mannose beta-1,3-N-acetylgalactosaminyltransferase", - "2.4.1.314 Ginsenoside Rd glucosyltransferase", - "2.4.1.315 Diglucosyl diacylglycerol synthase (1,6-linking)", - "2.4.1.316 Tylactone mycaminosyltransferase", - "2.4.1.317 O-mycaminosyltylonolide 6-deoxyallosyltransferase", - "2.4.1.318 Demethyllactenocin mycarosyltransferase", - "2.4.1.319 Beta-1,4-mannooligosaccharide phosphorylase", - "2.4.1.320 1,4-beta-mannosyl-N-acetylglucosamine phosphorylase", - "2.4.1.321 Cellobionic acid phosphorylase", - "2.4.1.322 Devancosaminyl-vancomycin vancosaminetransferase", - "2.4.1.323 7-deoxyloganetic acid glucosyltransferase", - "2.4.1.324 7-deoxyloganetin glucosyltransferase", - "2.4.1.325 TDP-N-acetylfucosamine:lipid II N-acetylfucosaminyltransferase", - "2.4.1.326 Aklavinone 7-L-rhodosaminyltransferase", - "2.4.1.327 Aclacinomycin-T 2-deoxy-L-fucose transferase", - "2.4.1.328 Erythronolide mycarosyltransferase", - "2.4.1.329 Sucrose 6(F)-phosphate phosphorylase", - "2.4.1.330 Beta-D-glucosyl crocetin beta-1,6-glucosyltransferase", - "2.4.1.331 8-demethyltetracenomycin C L-rhamnosyltransferase", - "2.4.1.332 1,2-alpha-glucosylglycerol phosphorylase", - "2.4.1.333 1,2-beta-oligoglucan phosphorylase", - "2.4.1.334 1,3-alpha-oligoglucan phosphorylase", - "2.4.1.335 Dolichyl N-acetyl-alpha-D-glucosaminyl phosphate 3-beta-D-2,3-diacetamido-2,3-dideoxy-beta-D-glucuronosyltransferase", - "2.4.1.336 Monoglucosyldiacylglycerol synthase", - "2.4.1.337 1,2-diacylglycerol 3-alpha-glucosyltransferase", - "2.4.1.n2 Loliose synthase", - "2.4.2.1 Purine-nucleoside phosphorylase", - "2.4.2.2 Pyrimidine-nucleoside phosphorylase", - "2.4.2.3 Uridine phosphorylase", - "2.4.2.4 Thymidine phosphorylase", - "2.4.2.5 Nucleoside ribosyltransferase", - "2.4.2.6 Nucleoside deoxyribosyltransferase", - "2.4.2.7 Adenine phosphoribosyltransferase", - "2.4.2.8 Hypoxanthine phosphoribosyltransferase", - "2.4.2.9 Uracil phosphoribosyltransferase", - "2.4.2.10 Orotate phosphoribosyltransferase", - "2.4.2.12 Nicotinamide phosphoribosyltransferase", - "2.4.2.14 Amidophosphoribosyltransferase", - "2.4.2.15 Guanosine phosphorylase", - "2.4.2.16 Urate-ribonucleotide phosphorylase", - "2.4.2.17 ATP phosphoribosyltransferase", - "2.4.2.18 Anthranilate phosphoribosyltransferase", - "2.4.2.19 Nicotinate-nucleotide diphosphorylase (carboxylating)", - "2.4.2.20 Dioxotetrahydropyrimidine phosphoribosyltransferase", - "2.4.2.21 Nicotinate-nucleotide--dimethylbenzimidazole phosphoribosyltransferase", - "2.4.2.22 Xanthine phosphoribosyltransferase", - "2.4.2.24 1,4-beta-D-xylan synthase", - "2.4.2.25 Flavone apiosyltransferase", - "2.4.2.26 Protein xylosyltransferase", - "2.4.2.27 dTDP-dihydrostreptose--streptidine-6-phosphate dihydrostreptosyltransferase", - "2.4.2.28 S-methyl-5'-thioadenosine phosphorylase", - "2.4.2.29 tRNA-guanine(34) transglycosylase", - "2.4.2.30 NAD(+) ADP-ribosyltransferase", - "2.4.2.31 NAD(+)--protein-arginine ADP-ribosyltransferase", - "2.4.2.32 Dolichyl-phosphate D-xylosyltransferase", - "2.4.2.33 Dolichyl-xylosyl-phosphate--protein xylosyltransferase", - "2.4.2.34 Indolylacetylinositol arabinosyltransferase", - "2.4.2.35 Flavonol-3-O-glycoside xylosyltransferase", - "2.4.2.36 NAD(+)--diphthamide ADP-ribosyltransferase", - "2.4.2.37 NAD(+)--dinitrogen-reductase ADP-D-ribosyltransferase", - "2.4.2.38 Glycoprotein 2-beta-D-xylosyltransferase", - "2.4.2.39 Xyloglucan 6-xylosyltransferase", - "2.4.2.40 Zeatin O-beta-D-xylosyltransferase", - "2.4.2.41 Xylogalacturonan beta-1,3-xylosyltransferase", - "2.4.2.42 UDP-D-xylose:beta-D-glucoside alpha-1,3-D-xylosyltransferase", - "2.4.2.43 Lipid IV(A) 4-amino-4-deoxy-L-arabinosyltransferase", - "2.4.2.44 S-methyl-5'-thioinosine phosphorylase", - "2.4.2.45 Decaprenyl-phosphate phosphoribosyltransferase", - "2.4.2.46 Galactan 5-O-arabinofuranosyltransferase", - "2.4.2.47 Arabinofuranan 3-O-arabinosyltransferase", - "2.4.2.48 tRNA-guanine(15) transglycosylase", - "2.4.2.49 Neamine phosphoribosyltransferase", - "2.4.2.50 Cyanidin 3-O-galactoside 2''-O-xylosyltransferase", - "2.4.2.51 Anthocyanidin 3-O-glucoside 2'''-O-xylosyltransferase", - "2.4.2.52 Triphosphoribosyl-dephospho-CoA synthase", - "2.4.2.53 Undecaprenyl-phosphate 4-deoxy-4-formamido-L-arabinose transferase", - "2.4.2.54 Beta-ribofuranosylphenol 5'-phosphate synthase", - "2.4.2.55 Nicotinate D-ribonucleotide:phenol phospho-D-ribosyltransferase", - "2.4.2.56 Kaempferol 3-O-xylosyltransferase", - "2.4.2.57 AMP phosphorylase", - "2.4.2.n2 Glucoside xylosyltransferase", - "2.4.2.n3 Xyloside xylosyltransferase", - "2.4.99.1 Beta-galactoside alpha-2,6-sialyltransferase", - "2.4.99.2 Monosialoganglioside sialyltransferase", - "2.4.99.3 Alpha-N-acetylgalactosaminide alpha-2,6-sialyltransferase", - "2.4.99.4 Beta-galactoside alpha-2,3-sialyltransferase", - "2.4.99.5 Galactosyldiacylglycerol alpha-2,3-sialyltransferase", - "2.4.99.6 N-acetyllactosaminide alpha-2,3-sialyltransferase", - "2.4.99.7 Alpha-N-acetylneuraminyl-2,3-beta-galactosyl-1,3-N-acetylgalactosaminide 6-alpha-sialyltransferase", - "2.4.99.8 Alpha-N-acetylneuraminate alpha-2,8-sialyltransferase", - "2.4.99.9 Lactosylceramide alpha-2,3-sialyltransferase", - "2.4.99.10 Neolactotetraosylceramide alpha-2,3-sialyltransferase", - "2.4.99.11 Lactosylceramide alpha-2,6-N-sialyltransferase", - "2.4.99.12 Lipid IV(A) 3-deoxy-D-manno-octulosonic acid transferase", - "2.4.99.13 (Kdo)-lipid IV(A) 3-deoxy-D-manno-octulosonic acid transferase", - "2.4.99.14 (Kdo)(2)-lipid IV(A) (2-8) 3-deoxy-D-manno-octulosonic acid transferase", - "2.4.99.15 (Kdo)(3)-lipid IV(A) (2-4) 3-deoxy-D-manno-octulosonic acid transferase", - "2.4.99.16 Starch synthase (maltosyl-transferring)", - "2.4.99.17 S-adenosylmethionine:tRNA ribosyltransferase-isomerase", - "2.4.99.18 Dolichyl-diphosphooligosaccharide--protein glycotransferase", - "2.4.99.19 Undecaprenyl-diphosphooligosaccharide--protein glycotransferase", - "2.4.99.20 2'-phospho-ADP-ribosyl cyclase/2'-phospho-cyclic-ADP-ribose transferase", - "2.4.99.21 Dolichyl-phosphooligosaccharide-protein glycotransferase", - "2.5.1.1 Dimethylallyltranstransferase", - "2.5.1.2 Thiamine pyridinylase", - "2.5.1.3 Thiamine phosphate synthase", - "2.5.1.4 Adenosylmethionine cyclotransferase", - "2.5.1.5 Galactose-6-sulfurylase", - "2.5.1.6 Methionine adenosyltransferase", - "2.5.1.7 UDP-N-acetylglucosamine 1-carboxyvinyltransferase", - "2.5.1.9 Riboflavin synthase", - "2.5.1.10 (2E,6E)-farnesyl diphosphate synthase", - "2.5.1.15 Dihydropteroate synthase", - "2.5.1.16 Spermidine synthase", - "2.5.1.17 Cob(I)yrinic acid a,c-diamide adenosyltransferase", - "2.5.1.18 Glutathione transferase", - "2.5.1.19 3-phosphoshikimate 1-carboxyvinyltransferase", - "2.5.1.20 Rubber cis-polyprenylcistransferase", - "2.5.1.21 Squalene synthase", - "2.5.1.22 Spermine synthase", - "2.5.1.23 Sym-norspermidine synthase", - "2.5.1.24 Discadenine synthase", - "2.5.1.25 tRNA-uridine aminocarboxypropyltransferase", - "2.5.1.26 Alkylglycerone-phosphate synthase", - "2.5.1.27 Adenylate dimethylallyltransferase (AMP-dependent)", - "2.5.1.28 Dimethylallylcistransferase", - "2.5.1.29 Geranylgeranyl diphosphate synthase", - "2.5.1.30 Heptaprenyl diphosphate synthase", - "2.5.1.31 Ditrans,polycis-undecaprenyl-diphosphate synthase ((2E,6E)-farnesyl-diphosphate specific)", - "2.5.1.32 15-cis-phytoene synthase", - "2.5.1.34 4-dimethylallyltryptophan synthase", - "2.5.1.35 Aspulvinone dimethylallyltransferase", - "2.5.1.36 Trihydroxypterocarpan dimethylallyltransferase", - "2.5.1.38 Isonocardicin synthase", - "2.5.1.39 4-hydroxybenzoate polyprenyltransferase", - "2.5.1.41 Phosphoglycerol geranylgeranyltransferase", - "2.5.1.42 Geranylgeranylglycerol-phosphate geranylgeranyltransferase", - "2.5.1.43 Nicotianamine synthase", - "2.5.1.44 Homospermidine synthase", - "2.5.1.45 Homospermidine synthase (spermidine-specific)", - "2.5.1.46 Deoxyhypusine synthase", - "2.5.1.47 Cysteine synthase", - "2.5.1.48 Cystathionine gamma-synthase", - "2.5.1.49 O-acetylhomoserine aminocarboxypropyltransferase", - "2.5.1.50 Zeatin 9-aminocarboxyethyltransferase", - "2.5.1.51 Beta-pyrazolylalanine synthase", - "2.5.1.52 L-mimosine synthase", - "2.5.1.53 Uracilylalanine synthase", - "2.5.1.54 3-deoxy-7-phosphoheptulonate synthase", - "2.5.1.55 3-deoxy-8-phosphooctulonate synthase", - "2.5.1.56 N-acetylneuraminate synthase", - "2.5.1.57 N-acylneuraminate-9-phosphate synthase", - "2.5.1.58 Protein farnesyltransferase", - "2.5.1.59 Protein geranylgeranyltransferase type I", - "2.5.1.60 Protein geranylgeranyltransferase type II", - "2.5.1.61 Hydroxymethylbilane synthase", - "2.5.1.62 Chlorophyll synthase", - "2.5.1.63 Adenosyl-fluoride synthase", - "2.5.1.65 O-phosphoserine sulfhydrylase", - "2.5.1.66 N(2)-(2-carboxyethyl)arginine synthase", - "2.5.1.67 Chrysanthemyl diphosphate synthase", - "2.5.1.68 (2Z,6E)-farnesyl diphosphate synthase", - "2.5.1.69 Lavandulyl diphosphate synthase", - "2.5.1.70 Naringenin 8-dimethylallyltransferase", - "2.5.1.71 Leachianone-G 2''-dimethylallyltransferase", - "2.5.1.72 Quinolinate synthase", - "2.5.1.73 O-phospho-L-seryl-tRNA:Cys-tRNA synthase", - "2.5.1.74 1,4-dihydroxy-2-naphthoate polyprenyltransferase", - "2.5.1.75 tRNA dimethylallyltransferase", - "2.5.1.76 Cysteate synthase", - "2.5.1.77 7,8-didemethyl-8-hydroxy-5-deazariboflavin synthase", - "2.5.1.78 6,7-dimethyl-8-ribityllumazine synthase", - "2.5.1.79 Thermospermine synthase", - "2.5.1.80 7-dimethylallyltryptophan synthase", - "2.5.1.81 Geranylfarnesyl diphosphate synthase", - "2.5.1.82 Hexaprenyl diphosphate synthase (geranylgeranyl-diphosphate specific)", - "2.5.1.83 Hexaprenyl-diphosphate synthase ((2E,6E)-farnesyl-diphosphate specific)", - "2.5.1.84 All-trans-nonaprenyl-diphosphate synthase (geranyl-diphosphate specific)", - "2.5.1.85 All-trans-nonaprenyl-diphosphate synthase (geranylgeranyl-diphosphate specific)", - "2.5.1.86 Trans,polycis-decaprenyl diphosphate synthase", - "2.5.1.87 Ditrans,polycis-polyprenyl diphosphate synthase ((2E,6E)-farnesyl diphosphate specific)", - "2.5.1.88 Trans,polycis-polyprenyl diphosphate synthase ((2Z,6E)-farnesyl diphosphate specific)", - "2.5.1.89 Tritrans,polycis-undecaprenyl-diphosphate synthase (geranylgeranyl-diphosphate specific)", - "2.5.1.90 All-trans-octaprenyl-diphosphate synthase", - "2.5.1.91 All-trans-decaprenyl-diphosphate synthase", - "2.5.1.92 (2Z,6Z)-farnesyl diphosphate synthase", - "2.5.1.93 4-hydroxybenzoate geranyltransferase", - "2.5.1.94 Adenosyl-chloride synthase", - "2.5.1.95 Xanthan pyruvate transferase", - "2.5.1.96 4,4'-diapophytoene synthase", - "2.5.1.97 Pseudaminic acid synthase", - "2.5.1.98 Rhizobium leguminosarum exopolysaccharide glucosyl ketal-pyruvate-transferase", - "2.5.1.99 All-trans-phytoene synthase", - "2.5.1.100 Fumigaclavine A dimethylallyltransferase", - "2.5.1.101 N,N'-diacetyllegionaminate synthase", - "2.5.1.102 Geranylpyrophosphate--olivetolic acid geranyltransferase", - "2.5.1.103 Presqualene diphosphate synthase", - "2.5.1.104 N(1)-aminopropylagmatine synthase", - "2.5.1.105 7,8-dihydropterin-6-yl-methyl-4-(beta-D-ribofuranosyl)aminobenzene 5'-phosphate synthase", - "2.5.1.106 Tryprostatin B synthase", - "2.5.1.107 Verruculogen prenyltransferase", - "2.5.1.108 2-(3-amino-3-carboxypropyl)histidine synthase", - "2.5.1.109 Brevianamide F prenyltransferase (deoxybrevianamide E-forming)", - "2.5.1.110 12-alpha,13-alpha-dihydroxyfumitremorgin C prenyltransferase", - "2.5.1.111 4-hydroxyphenylpyruvate 3-dimethylallyltransferase", - "2.5.1.112 Adenylate dimethylallyltransferase (ADP/ATP-dependent)", - "2.5.1.113 [CysO sulfur-carrier protein]-thiocarboxylate-dependent cysteine synthase", - "2.5.1.114 tRNA(Phe) (4-demethylwyosine(37)-C(7)) aminocarboxypropyltransferase", - "2.5.1.115 Homogentisate phytyltransferase", - "2.5.1.116 Homogentisate geranylgeranyltransferase", - "2.5.1.117 Homogentisate solanesyltransferase", - "2.5.1.118 Beta-(isoxazolin-5-on-2-yl)-L-alanine synthase", - "2.5.1.119 Beta-(isoxazolin-5-on-4-yl)-L-alanine synthase", - "2.5.1.120 Aminodeoxyfutalosine synthase", - "2.5.1.121 5,10-dihydrophenazine-1-carboxylate 9-dimethylallyltransferase", - "2.5.1.122 4-O-dimethylallyl-L-tyrosine synthase", - "2.5.1.123 Flaviolin linalyltransferase", - "2.5.1.124 6-linalyl-2-O,3-dimethylflaviolin synthase", - "2.5.1.125 7-geranyloxy-5-hydroxy-2-methoxy-3-methylnaphthalene-1,4-dione synthase", - "2.5.1.126 Norspermine synthase", - "2.5.1.127 Caldopentamine synthase", - "2.5.1.128 N(4)-bis(aminopropyl)spermidine synthase", - "2.5.1.129 Flavin prenyltransferase", - "2.5.1.130 2-carboxy-1,4-naphthoquinone phytyltransferase", - "2.5.1.131 (4-(4-(2-(gamma-L-glutamylamino)ethyl)phenoxymethyl)furan-2-yl)methanamine synthase", - "2.5.1.n9 Heptaprenylglyceryl phosphate synthase", - "2.6.1.1 Aspartate transaminase", - "2.6.1.2 Alanine transaminase", - "2.6.1.3 Cysteine transaminase", - "2.6.1.4 Glycine transaminase", - "2.6.1.5 Tyrosine transaminase", - "2.6.1.6 Leucine transaminase", - "2.6.1.7 Kynurenine--oxoglutarate transaminase", - "2.6.1.8 2,5-diaminovalerate transaminase", - "2.6.1.9 Histidinol-phosphate transaminase", - "2.6.1.11 Acetylornithine transaminase", - "2.6.1.12 Alanine--oxo-acid transaminase", - "2.6.1.13 Ornithine aminotransferase", - "2.6.1.14 Asparagine--oxo-acid transaminase", - "2.6.1.15 Glutamine--pyruvate transaminase", - "2.6.1.16 Glutamine--fructose-6-phosphate transaminase (isomerizing)", - "2.6.1.17 Succinyldiaminopimelate transaminase", - "2.6.1.18 Beta-alanine--pyruvate transaminase", - "2.6.1.19 4-aminobutyrate--2-oxoglutarate transaminase", - "2.6.1.21 D-amino-acid transaminase", - "2.6.1.22 (S)-3-amino-2-methylpropionate transaminase", - "2.6.1.23 4-hydroxyglutamate transaminase", - "2.6.1.24 Diiodotyrosine transaminase", - "2.6.1.26 Thyroid-hormone transaminase", - "2.6.1.27 Tryptophan transaminase", - "2.6.1.28 Tryptophan--phenylpyruvate transaminase", - "2.6.1.29 Diamine transaminase", - "2.6.1.30 Pyridoxamine--pyruvate transaminase", - "2.6.1.31 Pyridoxamine--oxaloacetate transaminase", - "2.6.1.32 Valine--3-methyl-2-oxovalerate transaminase", - "2.6.1.33 dTDP-4-amino-4,6-dideoxy-D-glucose transaminase", - "2.6.1.34 UDP-N-acetylbacillosamine transaminase", - "2.6.1.35 Glycine--oxaloacetate transaminase", - "2.6.1.36 L-lysine 6-transaminase", - "2.6.1.37 2-aminoethylphosphonate--pyruvate transaminase", - "2.6.1.38 Histidine transaminase", - "2.6.1.39 2-aminoadipate transaminase", - "2.6.1.40 (R)-3-amino-2-methylpropionate--pyruvate transaminase", - "2.6.1.41 D-methionine--pyruvate transaminase", - "2.6.1.42 Branched-chain-amino-acid transaminase", - "2.6.1.43 Aminolevulinate transaminase", - "2.6.1.44 Alanine--glyoxylate transaminase", - "2.6.1.45 Serine--glyoxylate transaminase", - "2.6.1.46 Diaminobutyrate--pyruvate transaminase", - "2.6.1.47 Alanine--oxomalonate transaminase", - "2.6.1.48 5-aminovalerate transaminase", - "2.6.1.49 Dihydroxyphenylalanine transaminase", - "2.6.1.50 Glutamine--scyllo-inositol transaminase", - "2.6.1.51 Serine--pyruvate transaminase", - "2.6.1.52 Phosphoserine transaminase", - "2.6.1.54 Pyridoxamine-phosphate transaminase", - "2.6.1.55 Taurine--2-oxoglutarate transaminase", - "2.6.1.56 1D-1-guanidino-3-amino-1,3-dideoxy-scyllo-inositol transaminase", - "2.6.1.57 Aromatic-amino-acid transaminase", - "2.6.1.58 Phenylalanine(histidine) transaminase", - "2.6.1.59 dTDP-4-amino-4,6-dideoxygalactose transaminase", - "2.6.1.60 Aromatic-amino-acid--glyoxylate transaminase", - "2.6.1.62 Adenosylmethionine--8-amino-7-oxononanoate transaminase", - "2.6.1.63 Kynurenine--glyoxylate transaminase", - "2.6.1.64 Glutamine--phenylpyruvate transaminase", - "2.6.1.65 N(6)-acetyl-beta-lysine transaminase", - "2.6.1.66 Valine--pyruvate transaminase", - "2.6.1.67 2-aminohexanoate transaminase", - "2.6.1.68 Ornithine(lysine) transaminase", - "2.6.1.70 Aspartate--phenylpyruvate transaminase", - "2.6.1.71 Lysine--pyruvate 6-transaminase", - "2.6.1.72 D-4-hydroxyphenylglycine transaminase", - "2.6.1.73 Methionine--glyoxylate transaminase", - "2.6.1.74 Cephalosporin-C transaminase", - "2.6.1.75 Cysteine-conjugate transaminase", - "2.6.1.76 Diaminobutyrate--2-oxoglutarate transaminase", - "2.6.1.77 Taurine--pyruvate aminotransferase", - "2.6.1.78 Aspartate--prephenate aminotransferase", - "2.6.1.79 Glutamate--prephenate aminotransferase", - "2.6.1.80 Nicotianamine aminotransferase", - "2.6.1.81 Succinylornithine transaminase", - "2.6.1.82 Putrescine aminotransferase", - "2.6.1.83 LL-diaminopimelate aminotransferase", - "2.6.1.84 Arginine--pyruvate transaminase", - "2.6.1.85 Aminodeoxychorismate synthase", - "2.6.1.86 2-amino-4-deoxychorismate synthase", - "2.6.1.87 UDP-4-amino-4-deoxy-L-arabinose aminotransferase", - "2.6.1.88 Methionine transaminase", - "2.6.1.89 dTDP-3-amino-3,6-dideoxy-alpha-D-glucopyranose transaminase", - "2.6.1.90 dTDP-3-amino-3,6-dideoxy-alpha-D-galactopyranose transaminase", - "2.6.1.92 UDP-4-amino-4,6-dideoxy-N-acetyl-beta-L-altrosamine transaminase", - "2.6.1.93 Neamine transaminase", - "2.6.1.94 2'-deamino-2'-hydroxyneamine transaminase", - "2.6.1.95 Neomycin C transaminase", - "2.6.1.96 4-aminobutyrate--pyruvate transaminase", - "2.6.1.97 Archaeosine synthase", - "2.6.1.98 UDP-2-acetamido-2-deoxy-ribo-hexuluronate aminotransferase", - "2.6.1.99 L-tryptophan--pyruvate aminotransferase", - "2.6.1.100 L-glutamine:2-deoxy-scyllo-inosose aminotransferase", - "2.6.1.101 L-glutamine:3-amino-2,3-dideoxy-scyllo-inosose aminotransferase", - "2.6.1.102 GDP-perosamine synthase", - "2.6.1.103 (S)-3,5-dihydroxyphenylglycine transaminase", - "2.6.1.104 3-dehydro-glucose-6-phosphate--glutamate transaminase", - "2.6.1.105 Lysine--8-amino-7-oxononanoate transaminase", - "2.6.1.106 dTDP-3-amino-3,4,6-trideoxy-alpha-D-glucose transaminase", - "2.6.1.107 Beta-methylphenylalanine transaminase", - "2.6.1.108 (5-formylfuran-3-yl)methyl phosphate transaminase", - "2.6.1.109 8-amino-3,8-dideoxy-alpha-D-manno-octulosonate transaminase", - "2.6.1.110 dTDP-4-dehydro-2,3,6-trideoxy-D-glucose 4-aminotransferase", - "2.6.3.1 Oximinotransferase", - "2.6.99.1 dATP(dGTP)--DNA purinetransferase", - "2.6.99.2 Pyridoxine 5'-phosphate synthase", - "2.6.99.3 O-ureido-L-serine synthase", - "2.7.1.1 Hexokinase", - "2.7.1.2 Glucokinase", - "2.7.1.3 Ketohexokinase", - "2.7.1.4 Fructokinase", - "2.7.1.5 Rhamnulokinase", - "2.7.1.6 Galactokinase", - "2.7.1.7 Mannokinase", - "2.7.1.8 Glucosamine kinase", - "2.7.1.10 Phosphoglucokinase", - "2.7.1.11 6-phosphofructokinase", - "2.7.1.12 Gluconokinase", - "2.7.1.13 Dehydrogluconokinase", - "2.7.1.14 Sedoheptulokinase", - "2.7.1.15 Ribokinase", - "2.7.1.16 Ribulokinase", - "2.7.1.17 Xylulokinase", - "2.7.1.18 Phosphoribokinase", - "2.7.1.19 Phosphoribulokinase", - "2.7.1.20 Adenosine kinase", - "2.7.1.21 Thymidine kinase", - "2.7.1.22 Ribosylnicotinamide kinase", - "2.7.1.23 NAD(+) kinase", - "2.7.1.24 Dephospho-CoA kinase", - "2.7.1.25 Adenylyl-sulfate kinase", - "2.7.1.26 Riboflavin kinase", - "2.7.1.27 Erythritol kinase", - "2.7.1.28 Triokinase", - "2.7.1.29 Glycerone kinase", - "2.7.1.30 Glycerol kinase", - "2.7.1.31 Glycerate 3-kinase", - "2.7.1.32 Choline kinase", - "2.7.1.33 Pantothenate kinase", - "2.7.1.34 Pantetheine kinase", - "2.7.1.35 Pyridoxal kinase", - "2.7.1.36 Mevalonate kinase", - "2.7.1.39 Homoserine kinase", - "2.7.1.40 Pyruvate kinase", - "2.7.1.41 Glucose-1-phosphate phosphodismutase", - "2.7.1.42 Riboflavin phosphotransferase", - "2.7.1.43 Glucuronokinase", - "2.7.1.44 Galacturonokinase", - "2.7.1.45 2-dehydro-3-deoxygluconokinase", - "2.7.1.46 L-arabinokinase", - "2.7.1.47 D-ribulokinase", - "2.7.1.48 Uridine kinase", - "2.7.1.49 Hydroxymethylpyrimidine kinase", - "2.7.1.50 Hydroxyethylthiazole kinase", - "2.7.1.51 L-fuculokinase", - "2.7.1.52 Fucokinase", - "2.7.1.53 L-xylulokinase", - "2.7.1.54 D-arabinokinase", - "2.7.1.55 Allose kinase", - "2.7.1.56 1-phosphofructokinase", - "2.7.1.58 2-dehydro-3-deoxygalactonokinase", - "2.7.1.59 N-acetylglucosamine kinase", - "2.7.1.60 N-acylmannosamine kinase", - "2.7.1.61 Acyl-phosphate--hexose phosphotransferase", - "2.7.1.62 Phosphoramidate--hexose phosphotransferase", - "2.7.1.63 Polyphosphate--glucose phosphotransferase", - "2.7.1.64 Inositol 3-kinase", - "2.7.1.65 Scyllo-inosamine 4-kinase", - "2.7.1.66 Undecaprenol kinase", - "2.7.1.67 1-phosphatidylinositol 4-kinase", - "2.7.1.68 1-phosphatidylinositol-4-phosphate 5-kinase", - "2.7.1.71 Shikimate kinase", - "2.7.1.72 Streptomycin 6-kinase", - "2.7.1.73 Inosine kinase", - "2.7.1.74 Deoxycytidine kinase", - "2.7.1.76 Deoxyadenosine kinase", - "2.7.1.77 Nucleoside phosphotransferase", - "2.7.1.78 Polynucleotide 5'-hydroxyl-kinase", - "2.7.1.79 Diphosphate--glycerol phosphotransferase", - "2.7.1.80 Diphosphate--serine phosphotransferase", - "2.7.1.81 Hydroxylysine kinase", - "2.7.1.82 Ethanolamine kinase", - "2.7.1.83 Pseudouridine kinase", - "2.7.1.84 Alkylglycerone kinase", - "2.7.1.85 Beta-glucoside kinase", - "2.7.1.86 NADH kinase", - "2.7.1.87 Streptomycin 3''-kinase", - "2.7.1.88 Dihydrostreptomycin-6-phosphate 3'-alpha-kinase", - "2.7.1.89 Thiamine kinase", - "2.7.1.90 Diphosphate--fructose-6-phosphate 1-phosphotransferase", - "2.7.1.91 Sphinganine kinase", - "2.7.1.92 5-dehydro-2-deoxygluconokinase", - "2.7.1.93 Alkylglycerol kinase", - "2.7.1.94 Acylglycerol kinase", - "2.7.1.95 Kanamycin kinase", - "2.7.1.100 S-methyl-5-thioribose kinase", - "2.7.1.101 Tagatose kinase", - "2.7.1.102 Hamamelose kinase", - "2.7.1.103 Viomycin kinase", - "2.7.1.105 6-phosphofructo-2-kinase", - "2.7.1.106 Glucose-1,6-bisphosphate synthase", - "2.7.1.107 Diacylglycerol kinase (ATP)", - "2.7.1.108 Dolichol kinase", - "2.7.1.113 Deoxyguanosine kinase", - "2.7.1.114 AMP--thymidine kinase", - "2.7.1.118 ADP--thymidine kinase", - "2.7.1.119 Hygromycin-B 7''-O-kinase", - "2.7.1.121 Phosphoenolpyruvate--glycerone phosphotransferase", - "2.7.1.122 Xylitol kinase", - "2.7.1.127 Inositol-trisphosphate 3-kinase", - "2.7.1.130 Tetraacyldisaccharide 4'-kinase", - "2.7.1.134 Inositol-tetrakisphosphate 1-kinase", - "2.7.1.136 Macrolide 2'-kinase", - "2.7.1.137 Phosphatidylinositol 3-kinase", - "2.7.1.138 Ceramide kinase", - "2.7.1.140 Inositol-tetrakisphosphate 5-kinase", - "2.7.1.142 Glycerol-3-phosphate--glucose phosphotransferase", - "2.7.1.143 Diphosphate-purine nucleoside kinase", - "2.7.1.144 Tagatose-6-phosphate kinase", - "2.7.1.145 Deoxynucleoside kinase", - "2.7.1.146 ADP-specific phosphofructokinase", - "2.7.1.147 ADP-specific glucokinase", - "2.7.1.148 4-(cytidine 5'-diphospho)-2-C-methyl-D-erythritol kinase", - "2.7.1.149 1-phosphatidylinositol-5-phosphate 4-kinase", - "2.7.1.150 1-phosphatidylinositol-3-phosphate 5-kinase", - "2.7.1.151 Inositol-polyphosphate multikinase", - "2.7.1.153 Phosphatidylinositol-4,5-bisphosphate 3-kinase", - "2.7.1.154 Phosphatidylinositol-4-phosphate 3-kinase", - "2.7.1.156 Adenosylcobinamide kinase", - "2.7.1.157 N-acetylgalactosamine kinase", - "2.7.1.158 Inositol-pentakisphosphate 2-kinase", - "2.7.1.159 Inositol-1,3,4-trisphosphate 5/6-kinase", - "2.7.1.160 2'-phosphotransferase", - "2.7.1.161 CTP-dependent riboflavin kinase", - "2.7.1.162 N-acetylhexosamine 1-kinase", - "2.7.1.163 Hygromycin B 4-O-kinase", - "2.7.1.164 O-phosphoseryl-tRNA(Sec) kinase", - "2.7.1.165 Glycerate 2-kinase", - "2.7.1.166 3-deoxy-D-manno-octulosonic acid kinase", - "2.7.1.167 D-glycero-beta-D-manno-heptose-7-phosphate kinase", - "2.7.1.168 D-glycero-alpha-D-manno-heptose-7-phosphate kinase", - "2.7.1.169 Pantoate kinase", - "2.7.1.170 Anhydro-N-acetylmuramic acid kinase", - "2.7.1.171 Protein-fructosamine 3-kinase", - "2.7.1.172 Protein-ribulosamine 3-kinase", - "2.7.1.173 Nicotinate riboside kinase", - "2.7.1.174 Diacylglycerol kinase (CTP)", - "2.7.1.175 Maltokinase", - "2.7.1.176 UDP-N-acetylglucosamine kinase", - "2.7.1.177 L-threonine kinase", - "2.7.1.178 2-dehydro-3-deoxyglucono/galactono-kinase", - "2.7.1.179 Kanosamine kinase", - "2.7.1.180 FAD:protein FMN transferase", - "2.7.1.181 Polymannosyl GlcNAc-diphospho-ditrans,octacis-undecaprenol kinase", - "2.7.1.182 Phytol kinase", - "2.7.1.183 Glycoprotein-mannosyl O(6)-kinase", - "2.7.1.184 Sulfofructose kinase", - "2.7.1.185 Mevalonate 3-kinase", - "2.7.1.186 Mevalonate-3-phosphate 5-kinase", - "2.7.1.187 Acarbose 7(IV)-phosphotransferase", - "2.7.1.188 2-epi-5-epi-valiolone 7-kinase", - "2.7.1.189 Autoinducer-2 kinase", - "2.7.1.190 Aminoglycoside 2''-phosphotransferase", - "2.7.1.191 Protein-N(pi)-phosphohistidine--D-mannose phosphotransferase", - "2.7.1.192 Protein-N(pi)-phosphohistidine--N-acetylmuramate phosphotransferase", - "2.7.1.193 Protein-N(pi)-phosphohistidine--N-acetyl-D-glucosamine phosphotransferase", - "2.7.1.194 Protein-N(pi)-phosphohistidine--L-ascorbate phosphotransferase", - "2.7.1.195 Protein-N(pi)-phosphohistidine--2-O-alpha-mannosyl-D-glycerate phosphotransferase", - "2.7.1.196 Protein-N(pi)-phosphohistidine--N,N'-diacetylchitobiose phosphotransferase", - "2.7.1.197 Protein-N(pi)-phosphohistidine--D-mannitol phosphotransferase", - "2.7.1.198 Protein-N(pi)-phosphohistidine--D-sorbitol phosphotransferase", - "2.7.1.199 Protein-N(pi)-phosphohistidine--D-glucose phosphotransferase", - "2.7.1.200 Protein-N(pi)-phosphohistidine--galactitol phosphotransferase", - "2.7.1.201 Protein-N(pi)-phosphohistidine--trehalose phosphotransferase", - "2.7.1.202 Protein-N(pi)-phosphohistidine--D-fructose phosphotransferase", - "2.7.1.203 Protein-N(pi)-phosphohistidine--D-glucosaminate phosphotransferase", - "2.7.1.204 Protein-N(pi)-phosphohistidine--D-galactose phosphotransferase", - "2.7.1.205 Protein-N(pi)-phosphohistidine--D-cellobiose phosphotransferase", - "2.7.1.206 Protein-N(pi)-phosphohistidine--L-sorbose phosphotransferase", - "2.7.1.207 Protein-N(pi)-phosphohistidine--lactose phosphotransferase", - "2.7.1.208 Protein-N(pi)-phosphohistidine--maltose phosphotransferase", - "2.7.2.1 Acetate kinase", - "2.7.2.2 Carbamate kinase", - "2.7.2.3 Phosphoglycerate kinase", - "2.7.2.4 Aspartate kinase", - "2.7.2.6 Formate kinase", - "2.7.2.7 Butyrate kinase", - "2.7.2.8 Acetylglutamate kinase", - "2.7.2.10 Phosphoglycerate kinase (GTP)", - "2.7.2.11 Glutamate 5-kinase", - "2.7.2.12 Acetate kinase (diphosphate)", - "2.7.2.13 Glutamate 1-kinase", - "2.7.2.14 Branched-chain-fatty-acid kinase", - "2.7.2.15 Propionate kinase", - "2.7.3.1 Guanidinoacetate kinase", - "2.7.3.2 Creatine kinase", - "2.7.3.3 Arginine kinase", - "2.7.3.4 Taurocyamine kinase", - "2.7.3.5 Lombricine kinase", - "2.7.3.6 Hypotaurocyamine kinase", - "2.7.3.7 Opheline kinase", - "2.7.3.8 Ammonia kinase", - "2.7.3.9 Phosphoenolpyruvate--protein phosphotransferase", - "2.7.3.10 Agmatine kinase", - "2.7.4.1 Polyphosphate kinase", - "2.7.4.2 Phosphomevalonate kinase", - "2.7.4.3 Adenylate kinase", - "2.7.4.4 Nucleoside-phosphate kinase", - "2.7.4.6 Nucleoside-diphosphate kinase", - "2.7.4.7 Phosphomethylpyrimidine kinase", - "2.7.4.8 Guanylate kinase", - "2.7.4.9 dTMP kinase", - "2.7.4.10 Nucleoside-triphosphate--adenylate kinase", - "2.7.4.11 (Deoxy)adenylate kinase", - "2.7.4.12 T(2)-induced deoxynucleotide kinase", - "2.7.4.13 (Deoxy)nucleoside-phosphate kinase", - "2.7.4.14 UMP/CMP kinase", - "2.7.4.15 Thiamine-diphosphate kinase", - "2.7.4.16 Thiamine-phosphate kinase", - "2.7.4.17 3-phosphoglyceroyl-phosphate--polyphosphate phosphotransferase", - "2.7.4.18 Farnesyl-diphosphate kinase", - "2.7.4.19 5-methyldeoxycytidine-5'-phosphate kinase", - "2.7.4.20 Dolichyl-diphosphate--polyphosphate phosphotransferase", - "2.7.4.21 Inositol-hexakisphosphate kinase", - "2.7.4.22 UMP kinase", - "2.7.4.23 Ribose 1,5-bisphosphate phosphokinase", - "2.7.4.24 Diphosphoinositol-pentakisphosphate kinase", - "2.7.4.25 (d)CMP kinase", - "2.7.4.26 Isopentenyl phosphate kinase", - "2.7.4.27 ([Pyruvate, phosphate dikinase] phosphate) phosphotransferase", - "2.7.4.28 ([Pyruvate, water dikinase] phosphate) phosphotransferase", - "2.7.4.29 Kdo(2)-lipid A phosphotransferase", - "2.7.4.30 Lipid A phosphoethanolamine transferase", - "2.7.4.31 (5-(aminomethyl)furan-3-yl)methyl phosphate kinase", - "2.7.6.1 Ribose-phosphate diphosphokinase", - "2.7.6.2 Thiamine diphosphokinase", - "2.7.6.3 2-amino-4-hydroxy-6-hydroxymethyldihydropteridine diphosphokinase", - "2.7.6.4 Nucleotide diphosphokinase", - "2.7.6.5 GTP diphosphokinase", - "2.7.7.1 Nicotinamide-nucleotide adenylyltransferase", - "2.7.7.2 FAD synthetase", - "2.7.7.3 Pantetheine-phosphate adenylyltransferase", - "2.7.7.4 Sulfate adenylyltransferase", - "2.7.7.5 Sulfate adenylyltransferase (ADP)", - "2.7.7.6 DNA-directed RNA polymerase", - "2.7.7.7 DNA-directed DNA polymerase", - "2.7.7.8 Polyribonucleotide nucleotidyltransferase", - "2.7.7.9 UTP--glucose-1-phosphate uridylyltransferase", - "2.7.7.10 UTP--hexose-1-phosphate uridylyltransferase", - "2.7.7.11 UTP--xylose-1-phosphate uridylyltransferase", - "2.7.7.12 UDP-glucose--hexose-1-phosphate uridylyltransferase", - "2.7.7.13 Mannose-1-phosphate guanylyltransferase", - "2.7.7.14 Ethanolamine-phosphate cytidylyltransferase", - "2.7.7.15 Choline-phosphate cytidylyltransferase", - "2.7.7.18 Nicotinate-nucleotide adenylyltransferase", - "2.7.7.19 Polynucleotide adenylyltransferase", - "2.7.7.22 Mannose-1-phosphate guanylyltransferase (GDP)", - "2.7.7.23 UDP-N-acetylglucosamine diphosphorylase", - "2.7.7.24 Glucose-1-phosphate thymidylyltransferase", - "2.7.7.27 Glucose-1-phosphate adenylyltransferase", - "2.7.7.28 Nucleoside-triphosphate-aldose-1-phosphate nucleotidyltransferase", - "2.7.7.30 Fucose-1-phosphate guanylyltransferase", - "2.7.7.31 DNA nucleotidylexotransferase", - "2.7.7.32 Galactose-1-phosphate thymidylyltransferase", - "2.7.7.33 Glucose-1-phosphate cytidylyltransferase", - "2.7.7.34 Glucose-1-phosphate guanylyltransferase", - "2.7.7.35 Ribose-5-phosphate adenylyltransferase", - "2.7.7.36 Aldose-1-phosphate adenylyltransferase", - "2.7.7.37 Aldose-1-phosphate nucleotidyltransferase", - "2.7.7.38 3-deoxy-manno-octulosonate cytidylyltransferase", - "2.7.7.39 Glycerol-3-phosphate cytidylyltransferase", - "2.7.7.40 D-ribitol-5-phosphate cytidylyltransferase", - "2.7.7.41 Phosphatidate cytidylyltransferase", - "2.7.7.42 [Glutamate--ammonia-ligase] adenylyltransferase", - "2.7.7.43 N-acylneuraminate cytidylyltransferase", - "2.7.7.44 Glucuronate-1-phosphate uridylyltransferase", - "2.7.7.45 Guanosine-triphosphate guanylyltransferase", - "2.7.7.46 Gentamicin 2''-nucleotidyltransferase", - "2.7.7.47 Streptomycin 3''-adenylyltransferase", - "2.7.7.48 RNA-directed RNA polymerase", - "2.7.7.49 RNA-directed DNA polymerase", - "2.7.7.50 mRNA guanylyltransferase", - "2.7.7.51 Adenylylsulfate--ammonia adenylyltransferase", - "2.7.7.52 RNA uridylyltransferase", - "2.7.7.53 ATP adenylyltransferase", - "2.7.7.56 tRNA nucleotidyltransferase", - "2.7.7.57 N-methylphosphoethanolamine cytidylyltransferase", - "2.7.7.58 (2,3-dihydroxybenzoyl)adenylate synthase", - "2.7.7.59 [Protein-PII] uridylyltransferase", - "2.7.7.60 2-C-methyl-D-erythritol 4-phosphate cytidylyltransferase", - "2.7.7.61 Citrate lyase holo-[acyl-carrier protein] synthase", - "2.7.7.62 Adenosylcobinamide-phosphate guanylyltransferase", - "2.7.7.64 UTP-monosaccharide-1-phosphate uridylyltransferase", - "2.7.7.65 Diguanylate cyclase", - "2.7.7.66 Malonate decarboxylase holo-[acyl-carrier protein] synthase", - "2.7.7.67 CDP-2,3-bis-(O-geranylgeranyl)-sn-glycerol synthase", - "2.7.7.68 2-phospho-L-lactate guanylyltransferase", - "2.7.7.69 GDP-L-galactose phosphorylase", - "2.7.7.70 D-glycero-beta-D-manno-heptose 1-phosphate adenylyltransferase", - "2.7.7.71 D-glycero-alpha-D-manno-heptose 1-phosphate guanylyltransferase", - "2.7.7.72 CCA tRNA nucleotidyltransferase", - "2.7.7.73 Sulfur carrier protein ThiS adenylyltransferase", - "2.7.7.74 1L-myo-inositol 1-phosphate cytidylyltransferase", - "2.7.7.75 Molybdopterin adenylyltransferase", - "2.7.7.76 Molybdenum cofactor cytidylyltransferase", - "2.7.7.77 Molybdenum cofactor guanylyltransferase", - "2.7.7.78 GDP-D-glucose phosphorylase", - "2.7.7.79 tRNA(His) guanylyltransferase", - "2.7.7.80 Molybdopterin-synthase adenylyltransferase", - "2.7.7.81 Pseudaminic acid cytidylyltransferase", - "2.7.7.82 CMP-N,N'-diacetyllegionaminic acid synthase", - "2.7.7.83 UDP-N-acetylgalactosamine diphosphorylase", - "2.7.7.84 2'-5' oligoadenylate synthase", - "2.7.7.85 Diadenylate cyclase", - "2.7.7.86 Cyclic GMP-AMP synthase", - "2.7.7.87 L-threonylcarbamoyladenylate synthase", - "2.7.7.88 GDP polyribonucleotidyltransferase", - "2.7.7.89 [Glutamate--ammonia ligase]-adenylyl-L-tyrosine phosphorylase", - "2.7.7.90 CMP-8-amino-3,8-dideoxy-manno-octulosonate cytidylyltransferase", - "2.7.7.n1 Adenosine monophosphate-protein transferase", - "2.7.7.n6 Guanine phosphate-protein transferase", - "2.7.8.1 Ethanolaminephosphotransferase", - "2.7.8.2 Diacylglycerol cholinephosphotransferase", - "2.7.8.3 Ceramide cholinephosphotransferase", - "2.7.8.4 Serine-phosphoethanolamine synthase", - "2.7.8.5 CDP-diacylglycerol--glycerol-3-phosphate 3-phosphatidyltransferase", - "2.7.8.6 Undecaprenyl-phosphate galactose phosphotransferase", - "2.7.8.7 Holo-[acyl-carrier-protein] synthase", - "2.7.8.8 CDP-diacylglycerol--serine O-phosphatidyltransferase", - "2.7.8.9 Phosphomannan mannosephosphotransferase", - "2.7.8.10 Sphingosine cholinephosphotransferase", - "2.7.8.11 CDP-diacylglycerol--inositol 3-phosphatidyltransferase", - "2.7.8.12 CDP-glycerol glycerophosphotransferase", - "2.7.8.13 Phospho-N-acetylmuramoyl-pentapeptide-transferase", - "2.7.8.14 CDP-ribitol ribitolphosphotransferase", - "2.7.8.15 UDP-N-acetylglucosamine--dolichyl-phosphate N-acetylglucosaminephosphotransferase", - "2.7.8.17 UDP-N-acetylglucosamine--lysosomal-enzyme N-acetylglucosaminephosphotransferase", - "2.7.8.18 UDP-galactose--UDP-N-acetylglucosamine galactose phosphotransferase", - "2.7.8.19 UDP-glucose--glycoprotein glucose phosphotransferase", - "2.7.8.20 Phosphatidylglycerol--membrane-oligosaccharide glycerophosphotransferase", - "2.7.8.21 Membrane-oligosaccharide glycerophosphotransferase", - "2.7.8.22 1-alkenyl-2-acylglycerol choline phosphotransferase", - "2.7.8.23 Carboxyvinyl-carboxyphosphonate phosphorylmutase", - "2.7.8.24 Phosphatidylcholine synthase", - "2.7.8.26 Adenosylcobinamide-GDP ribazoletransferase", - "2.7.8.27 Sphingomyelin synthase", - "2.7.8.28 2-phospho-L-lactate transferase", - "2.7.8.29 L-serine-phosphatidylethanolamine phosphatidyltransferase", - "2.7.8.31 Undecaprenyl-phosphate glucose phosphotransferase", - "2.7.8.32 3-O-alpha-D-mannopyranosyl-alpha-D-mannopyranose xylosylphosphotransferase", - "2.7.8.33 UDP-N-acetylglucosamine--undecaprenyl-phosphate N-acetylglucosaminephosphotransferase", - "2.7.8.34 CDP-L-myo-inositol myo-inositolphosphotransferase", - "2.7.8.35 UDP-N-acetylglucosamine--decaprenyl-phosphate N-acetylglucosaminephosphotransferase", - "2.7.8.36 Undecaprenyl phosphate N,N'-diacetylbacillosamine 1-phosphate transferase", - "2.7.8.37 Alpha-D-ribose 1-methylphosphonate 5-triphosphate synthase", - "2.7.8.38 Archaetidylserine synthase", - "2.7.8.39 Archaetidylinositol phosphate synthase", - "2.7.8.40 UDP-N-acetylgalactosamine-undecaprenyl-phosphate N-acetylgalactosaminephosphotransferase", - "2.7.8.41 Cardiolipin synthase (CMP-forming)", - "2.7.8.42 Kdo(2)-lipid A phosphoethanolamine 7''-transferase", - "2.7.8.n3 Ceramide phosphoethanolamine synthase", - "2.7.9.1 Pyruvate, phosphate dikinase", - "2.7.9.2 Pyruvate, water dikinase", - "2.7.9.3 Selenide, water dikinase", - "2.7.9.4 Alpha-glucan, water dikinase", - "2.7.9.5 Phosphoglucan, water dikinase", - "2.7.10.1 Receptor protein-tyrosine kinase", - "2.7.10.2 Non-specific protein-tyrosine kinase", - "2.7.11.1 Non-specific serine/threonine protein kinase", - "2.7.11.2 [Pyruvate dehydrogenase (acetyl-transferring)] kinase", - "2.7.11.3 Dephospho-[reductase kinase] kinase", - "2.7.11.4 [3-methyl-2-oxobutanoate dehydrogenase (acetyl-transferring)] kinase", - "2.7.11.5 [Isocitrate dehydrogenase (NADP(+))] kinase", - "2.7.11.6 [Tyrosine 3-monooxygenase] kinase", - "2.7.11.7 [Myosin heavy-chain] kinase", - "2.7.11.8 Fas-activated serine/threonine kinase", - "2.7.11.9 [Goodpasture-antigen-binding protein] kinase", - "2.7.11.10 I-kappa-B kinase", - "2.7.11.11 cAMP-dependent protein kinase", - "2.7.11.12 cGMP-dependent protein kinase", - "2.7.11.13 Protein kinase C", - "2.7.11.14 Rhodopsin kinase", - "2.7.11.15 [Beta-adrenergic-receptor] kinase", - "2.7.11.16 [G-protein-coupled receptor] kinase", - "2.7.11.17 Calcium/calmodulin-dependent protein kinase", - "2.7.11.18 [Myosin light-chain] kinase", - "2.7.11.19 Phosphorylase kinase", - "2.7.11.20 [Elongation factor 2] kinase", - "2.7.11.21 Polo kinase", - "2.7.11.22 Cyclin-dependent kinase", - "2.7.11.23 [RNA-polymerase]-subunit kinase", - "2.7.11.24 Mitogen-activated protein kinase", - "2.7.11.25 Mitogen-activated protein kinase kinase kinase", - "2.7.11.26 [Tau protein] kinase", - "2.7.11.27 [Acetyl-CoA carboxylase] kinase", - "2.7.11.28 Tropomyosin kinase", - "2.7.11.29 [Low-density-lipoprotein receptor] kinase", - "2.7.11.30 Receptor protein serine/threonine kinase", - "2.7.11.31 [Hydroxymethylglutaryl-CoA reductase (NADPH)] kinase", - "2.7.11.32 [Pyruvate, phosphate dikinase] kinase", - "2.7.11.33 [Pyruvate, water dikinase] kinase", - "2.7.12.1 Dual-specificity kinase", - "2.7.12.2 Mitogen-activated protein kinase kinase", - "2.7.13.1 Protein-histidine pros-kinase", - "2.7.13.2 Protein-histidine tele-kinase", - "2.7.13.3 Histidine kinase", - "2.7.14.1 Protein arginine kinase", - "2.7.99.1 Triphosphate--protein phosphotransferase", - "2.8.1.1 Thiosulfate sulfurtransferase", - "2.8.1.2 3-mercaptopyruvate sulfurtransferase", - "2.8.1.3 Thiosulfate--thiol sulfurtransferase", - "2.8.1.4 tRNA sulfurtransferase", - "2.8.1.5 Thiosulfate--dithiol sulfurtransferase", - "2.8.1.6 Biotin synthase", - "2.8.1.7 Cysteine desulfurase", - "2.8.1.8 Lipoyl synthase", - "2.8.1.9 Molybdenum cofactor sulfurtransferase", - "2.8.1.10 Thiazole synthase", - "2.8.1.11 Molybdopterin-synthase sulfurtransferase", - "2.8.1.12 Molybdopterin synthase", - "2.8.1.13 tRNA-uridine 2-sulfurtransferase", - "2.8.1.14 tRNA-5-taurinomethyluridine 2-sulfurtransferase", - "2.8.2.1 Aryl sulfotransferase", - "2.8.2.2 Alcohol sulfotransferase", - "2.8.2.3 Amine sulfotransferase", - "2.8.2.4 Estrone sulfotransferase", - "2.8.2.5 Chondroitin 4-sulfotransferase", - "2.8.2.6 Choline sulfotransferase", - "2.8.2.7 UDP-N-acetylgalactosamine-4-sulfate sulfotransferase", - "2.8.2.8 [Heparan sulfate]-glucosamine N-sulfotransferase", - "2.8.2.9 Tyrosine-ester sulfotransferase", - "2.8.2.10 Renilla-luciferin sulfotransferase", - "2.8.2.11 Galactosylceramide sulfotransferase", - "2.8.2.13 Psychosine sulfotransferase", - "2.8.2.14 Bile-salt sulfotransferase", - "2.8.2.15 Steroid sulfotransferase", - "2.8.2.16 Thiol sulfotransferase", - "2.8.2.17 Chondroitin 6-sulfotransferase", - "2.8.2.18 Cortisol sulfotransferase", - "2.8.2.19 Triglucosylalkylacylglycerol sulfotransferase", - "2.8.2.20 Protein-tyrosine sulfotransferase", - "2.8.2.21 Keratan sulfotransferase", - "2.8.2.22 Aryl-sulfate sulfotransferase", - "2.8.2.23 [Heparan sulfate]-glucosamine 3-sulfotransferase 1", - "2.8.2.24 Desulfoglucosinolate sulfotransferase", - "2.8.2.25 Flavonol 3-sulfotransferase", - "2.8.2.26 Quercetin-3-sulfate 3'-sulfotransferase", - "2.8.2.27 Quercetin-3-sulfate 4'-sulfotransferase", - "2.8.2.28 Quercetin-3,3'-bissulfate 7-sulfotransferase", - "2.8.2.29 [Heparan sulfate]-glucosamine 3-sulfotransferase 2", - "2.8.2.30 [Heparan sulfate]-glucosamine 3-sulfotransferase 3", - "2.8.2.31 Petromyzonol sulfotransferase", - "2.8.2.32 Scymnol sulfotransferase", - "2.8.2.33 N-acetylgalactosamine 4-sulfate 6-O-sulfotransferase", - "2.8.2.34 Glycochenodeoxycholate sulfotransferase", - "2.8.2.35 Dermatan 4-sulfotransferase", - "2.8.2.36 Desulfo-A47934 sulfotransferase", - "2.8.2.37 Trehalose 2-sulfotransferase", - "2.8.2.n2 Thyroxine sulfotransferase", - "2.8.3.1 Propionate CoA-transferase", - "2.8.3.2 Oxalate CoA-transferase", - "2.8.3.3 Malonate CoA-transferase", - "2.8.3.5 3-oxoacid CoA-transferase", - "2.8.3.6 3-oxoadipate CoA-transferase", - "2.8.3.8 Acetate CoA-transferase", - "2.8.3.9 Butyrate--acetoacetate CoA-transferase", - "2.8.3.10 Citrate CoA-transferase", - "2.8.3.11 Citramalate CoA-transferase", - "2.8.3.12 Glutaconate CoA-transferase", - "2.8.3.13 Succinate--hydroxymethylglutarate CoA-transferase", - "2.8.3.14 5-hydroxypentanoate CoA-transferase", - "2.8.3.15 Succinyl-CoA:(R)-benzylsuccinate CoA-transferase", - "2.8.3.16 Formyl-CoA transferase", - "2.8.3.17 Cinnamoyl-CoA:phenyllactate CoA-transferase", - "2.8.3.18 Succinyl-CoA:acetate CoA-transferase", - "2.8.3.19 CoA:oxalate CoA-transferase", - "2.8.3.20 Succinyl-CoA--D-citramalate CoA-transferase", - "2.8.3.21 L-carnitine CoA-transferase", - "2.8.3.22 Succinyl-CoA--L-malate CoA-transferase", - "2.8.3.23 Caffeate CoA-transferase", - "2.8.4.1 Coenzyme-B sulfoethylthiotransferase", - "2.8.4.2 Arsenate-mycothiol transferase", - "2.8.4.3 tRNA-2-methylthio-N(6)-dimethylallyladenosine synthase", - "2.8.4.4 [Ribosomal protein S12] (aspartate(89)-C(3))-methylthiotransferase", - "2.8.4.5 tRNA (N(6)-L-threonylcarbamoyladenosine(37)-C(2))-methylthiotransferase", - "2.9.1.1 L-seryl-tRNA(Sec) selenium transferase", - "2.9.1.2 O-phospho-L-seryl-tRNA(Sec):L-selenocysteinyl-tRNA synthase", - "2.10.1.1 Molybdopterin molybdotransferase", - "3.1.1.1 Carboxylesterase", - "3.1.1.2 Arylesterase", - "3.1.1.3 Triacylglycerol lipase", - "3.1.1.4 Phospholipase A(2)", - "3.1.1.5 Lysophospholipase", - "3.1.1.6 Acetylesterase", - "3.1.1.7 Acetylcholinesterase", - "3.1.1.8 Cholinesterase", - "3.1.1.10 Tropinesterase", - "3.1.1.11 Pectinesterase", - "3.1.1.13 Sterol esterase", - "3.1.1.14 Chlorophyllase", - "3.1.1.15 L-arabinonolactonase", - "3.1.1.17 Gluconolactonase", - "3.1.1.19 Uronolactonase", - "3.1.1.20 Tannase", - "3.1.1.22 Hydroxybutyrate-dimer hydrolase", - "3.1.1.23 Acylglycerol lipase", - "3.1.1.24 3-oxoadipate enol-lactonase", - "3.1.1.25 1,4-lactonase", - "3.1.1.26 Galactolipase", - "3.1.1.27 4-pyridoxolactonase", - "3.1.1.28 Acylcarnitine hydrolase", - "3.1.1.29 Aminoacyl-tRNA hydrolase", - "3.1.1.30 D-arabinonolactonase", - "3.1.1.31 6-phosphogluconolactonase", - "3.1.1.32 Phospholipase A(1)", - "3.1.1.33 6-acetylglucose deacetylase", - "3.1.1.34 Lipoprotein lipase", - "3.1.1.35 Dihydrocoumarin hydrolase", - "3.1.1.36 Limonin-D-ring-lactonase", - "3.1.1.37 Steroid-lactonase", - "3.1.1.38 Triacetate-lactonase", - "3.1.1.39 Actinomycin lactonase", - "3.1.1.40 Orsellinate-depside hydrolase", - "3.1.1.41 Cephalosporin-C deacetylase", - "3.1.1.42 Chlorogenate hydrolase", - "3.1.1.43 Alpha-amino-acid esterase", - "3.1.1.44 4-methyloxaloacetate esterase", - "3.1.1.45 Carboxymethylenebutenolidase", - "3.1.1.46 Deoxylimonate A-ring-lactonase", - "3.1.1.47 1-alkyl-2-acetylglycerophosphocholine esterase", - "3.1.1.48 Fusarinine-C ornithinesterase", - "3.1.1.49 Sinapine esterase", - "3.1.1.50 Wax-ester hydrolase", - "3.1.1.51 Phorbol-diester hydrolase", - "3.1.1.52 Phosphatidylinositol deacylase", - "3.1.1.53 Sialate O-acetylesterase", - "3.1.1.54 Acetoxybutynylbithiophene deacetylase", - "3.1.1.55 Acetylsalicylate deacetylase", - "3.1.1.56 Methylumbelliferyl-acetate deacetylase", - "3.1.1.57 2-pyrone-4,6-dicarboxylate lactonase", - "3.1.1.58 N-acetylgalactosaminoglycan deacetylase", - "3.1.1.59 Juvenile-hormone esterase", - "3.1.1.60 Bis(2-ethylhexyl)phthalate esterase", - "3.1.1.61 Protein-glutamate methylesterase", - "3.1.1.63 11-cis-retinyl-palmitate hydrolase", - "3.1.1.64 Retinoid isomerohydrolase", - "3.1.1.65 L-rhamnono-1,4-lactonase", - "3.1.1.66 5-(3,4-diacetoxybut-1-ynyl)-2,2'-bithiophene deacetylase", - "3.1.1.67 Fatty-acyl-ethyl-ester synthase", - "3.1.1.68 Xylono-1,4-lactonase", - "3.1.1.70 Cetraxate benzylesterase", - "3.1.1.71 Acetylalkylglycerol acetylhydrolase", - "3.1.1.72 Acetylxylan esterase", - "3.1.1.73 Feruloyl esterase", - "3.1.1.74 Cutinase", - "3.1.1.75 Poly(3-hydroxybutyrate) depolymerase", - "3.1.1.76 Poly(3-hydroxyoctanoate) depolymerase", - "3.1.1.77 Acyloxyacyl hydrolase", - "3.1.1.78 Polyneuridine-aldehyde esterase", - "3.1.1.79 Hormone-sensitive lipase", - "3.1.1.80 Acetylajmaline esterase", - "3.1.1.81 Quorum-quenching N-acyl-homoserine lactonase", - "3.1.1.82 Pheophorbidase", - "3.1.1.83 Monoterpene epsilon-lactone hydrolase", - "3.1.1.84 Cocaine esterase", - "3.1.1.85 Pimeloyl-[acyl-carrier protein] methyl ester esterase", - "3.1.1.86 Rhamnogalacturonan acetylesterase", - "3.1.1.87 Fumonisin B1 esterase", - "3.1.1.88 Pyrethroid hydrolase", - "3.1.1.89 Protein phosphatase methylesterase-1", - "3.1.1.90 All-trans-retinyl ester 13-cis isomerohydrolase", - "3.1.1.91 2-oxo-3-(5-oxofuran-2-ylidene)propanoate lactonase", - "3.1.1.92 4-sulfomuconolactone hydrolase", - "3.1.1.93 Mycophenolic acid acyl-glucuronide esterase", - "3.1.1.94 Versiconal hemiacetal acetate esterase", - "3.1.1.95 Aclacinomycin methylesterase", - "3.1.1.96 D-aminoacyl-tRNA deacylase", - "3.1.1.97 Methylated diphthine methylhydrolase", - "3.1.1.98 [Wnt protein] O-palmitoleoyl-L-serine hydrolase", - "3.1.1.99 6-deoxy-6-sulfogluconolactonase", - "3.1.1.n2 Protein-S-isoprenylcysteine alpha-carbonyl methylesterase", - "3.1.2.1 Acetyl-CoA hydrolase", - "3.1.2.2 Palmitoyl-CoA hydrolase", - "3.1.2.3 Succinyl-CoA hydrolase", - "3.1.2.4 3-hydroxyisobutyryl-CoA hydrolase", - "3.1.2.5 Hydroxymethylglutaryl-CoA hydrolase", - "3.1.2.6 Hydroxyacylglutathione hydrolase", - "3.1.2.7 Glutathione thiolesterase", - "3.1.2.10 Formyl-CoA hydrolase", - "3.1.2.11 Acetoacetyl-CoA hydrolase", - "3.1.2.12 S-formylglutathione hydrolase", - "3.1.2.13 S-succinylglutathione hydrolase", - "3.1.2.14 Oleoyl-[acyl-carrier-protein] hydrolase", - "3.1.2.16 Citrate-lyase deacetylase", - "3.1.2.17 (S)-methylmalonyl-CoA hydrolase", - "3.1.2.18 ADP-dependent short-chain-acyl-CoA hydrolase", - "3.1.2.19 ADP-dependent medium-chain-acyl-CoA hydrolase", - "3.1.2.20 Acyl-CoA hydrolase", - "3.1.2.21 Dodecanoyl-[acyl-carrier-protein] hydrolase", - "3.1.2.22 Palmitoyl-protein hydrolase", - "3.1.2.23 4-hydroxybenzoyl-CoA thioesterase", - "3.1.2.25 Phenylacetyl-CoA hydrolase", - "3.1.2.26 Bile-acid-CoA hydrolase", - "3.1.2.27 Choloyl-CoA hydrolase", - "3.1.2.28 1,4-dihydroxy-2-naphthoyl-CoA hydrolase", - "3.1.2.29 Fluoroacetyl-CoA thioesterase", - "3.1.2.30 (3S)-malyl-CoA thioesterase", - "3.1.2.31 Dihydromonacolin L-[lovastatin nonaketide synthase] thioesterase", - "3.1.3.1 Alkaline phosphatase", - "3.1.3.2 Acid phosphatase", - "3.1.3.3 Phosphoserine phosphatase", - "3.1.3.4 Phosphatidate phosphatase", - "3.1.3.5 5'-nucleotidase", - "3.1.3.6 3'-nucleotidase", - "3.1.3.7 3'(2'),5'-bisphosphate nucleotidase", - "3.1.3.8 3-phytase", - "3.1.3.9 Glucose-6-phosphatase", - "3.1.3.10 Glucose-1-phosphatase", - "3.1.3.11 Fructose-bisphosphatase", - "3.1.3.12 Trehalose-phosphatase", - "3.1.3.13 Bisphosphoglycerate phosphatase", - "3.1.3.14 Methylphosphothioglycerate phosphatase", - "3.1.3.15 Histidinol-phosphatase", - "3.1.3.16 Protein-serine/threonine phosphatase", - "3.1.3.17 [Phosphorylase] phosphatase", - "3.1.3.18 Phosphoglycolate phosphatase", - "3.1.3.19 Glycerol-2-phosphatase", - "3.1.3.20 Phosphoglycerate phosphatase", - "3.1.3.21 Glycerol-1-phosphatase", - "3.1.3.22 Mannitol-1-phosphatase", - "3.1.3.23 Sugar-phosphatase", - "3.1.3.24 Sucrose-phosphate phosphatase", - "3.1.3.25 Inositol-phosphate phosphatase", - "3.1.3.26 4-phytase", - "3.1.3.27 Phosphatidylglycerophosphatase", - "3.1.3.28 ADP-phosphoglycerate phosphatase", - "3.1.3.29 N-acylneuraminate-9-phosphatase", - "3.1.3.31 Nucleotidase", - "3.1.3.32 Polynucleotide 3'-phosphatase", - "3.1.3.33 Polynucleotide 5'-phosphatase", - "3.1.3.34 Deoxynucleotide 3'-phosphatase", - "3.1.3.35 Thymidylate 5'-phosphatase", - "3.1.3.36 Phosphoinositide 5-phosphatase", - "3.1.3.37 Sedoheptulose-bisphosphatase", - "3.1.3.38 3-phosphoglycerate phosphatase", - "3.1.3.39 Streptomycin-6-phosphatase", - "3.1.3.40 Guanidinodeoxy-scyllo-inositol-4-phosphatase", - "3.1.3.41 4-nitrophenylphosphatase", - "3.1.3.42 [Glycogen-synthase-D] phosphatase", - "3.1.3.43 [Pyruvate dehydrogenase (acetyl-transferring)]-phosphatase", - "3.1.3.44 [Acetyl-CoA carboxylase]-phosphatase", - "3.1.3.45 3-deoxy-manno-octulosonate-8-phosphatase", - "3.1.3.46 Fructose-2,6-bisphosphate 2-phosphatase", - "3.1.3.47 [Hydroxymethylglutaryl-CoA reductase (NADPH)]-phosphatase", - "3.1.3.48 Protein-tyrosine-phosphatase", - "3.1.3.49 [Pyruvate kinase]-phosphatase", - "3.1.3.50 Sorbitol-6-phosphatase", - "3.1.3.51 Dolichyl-phosphatase", - "3.1.3.52 [3-methyl-2-oxobutanoate dehydrogenase (2-methylpropanoyl-transferring)]-phosphatase", - "3.1.3.53 [Myosin-light-chain] phosphatase", - "3.1.3.54 Fructose-2,6-bisphosphate 6-phosphatase", - "3.1.3.55 Caldesmon-phosphatase", - "3.1.3.56 Inositol-polyphosphate 5-phosphatase", - "3.1.3.57 Inositol-1,4-bisphosphate 1-phosphatase", - "3.1.3.58 Sugar-terminal-phosphatase", - "3.1.3.59 Alkylacetylglycerophosphatase", - "3.1.3.60 Phosphoenolpyruvate phosphatase", - "3.1.3.62 Multiple inositol-polyphosphate phosphatase", - "3.1.3.63 2-carboxy-D-arabinitol-1-phosphatase", - "3.1.3.64 Phosphatidylinositol-3-phosphatase", - "3.1.3.66 Phosphatidylinositol-3,4-bisphosphate 4-phosphatase", - "3.1.3.67 Phosphatidylinositol-3,4,5-trisphosphate 3-phosphatase", - "3.1.3.68 2-deoxyglucose-6-phosphatase", - "3.1.3.69 Glucosylglycerol 3-phosphatase", - "3.1.3.70 Mannosyl-3-phosphoglycerate phosphatase", - "3.1.3.71 2-phosphosulfolactate phosphatase", - "3.1.3.72 5-phytase", - "3.1.3.73 Adenosylcobalamin/alpha-ribazole phosphatase", - "3.1.3.74 Pyridoxal phosphatase", - "3.1.3.75 Phosphoethanolamine/phosphocholine phosphatase", - "3.1.3.76 Lipid-phosphate phosphatase", - "3.1.3.77 Acireductone synthase", - "3.1.3.78 Phosphatidylinositol-4,5-bisphosphate 4-phosphatase", - "3.1.3.79 Mannosylfructose-phosphate phosphatase", - "3.1.3.80 2,3-bisphosphoglycerate 3-phosphatase", - "3.1.3.81 Diacylglycerol diphosphate phosphatase", - "3.1.3.82 D-glycero-beta-D-manno-heptose 1,7-bisphosphate 7-phosphatase", - "3.1.3.83 D-glycero-alpha-D-manno-heptose-1,7-bisphosphate 7-phosphatase", - "3.1.3.84 ADP-ribose 1''-phosphate phosphatase", - "3.1.3.85 Glucosyl-3-phosphoglycerate phosphatase", - "3.1.3.86 Phosphatidylinositol-3,4,5-trisphosphate 5-phosphatase", - "3.1.3.87 2-hydroxy-3-keto-5-methylthiopentenyl-1-phosphate phosphatase", - "3.1.3.88 5''-phosphoribostamycin phosphatase", - "3.1.3.89 5'-deoxynucleotidase", - "3.1.3.90 Maltose 6'-phosphate phosphatase", - "3.1.3.91 7-methylguanosine nucleotidase", - "3.1.3.92 Kanosamine-6-phosphate phosphatase", - "3.1.3.93 L-galactose 1-phosphate phosphatase", - "3.1.3.94 D-galactose 1-phosphate phosphatase", - "3.1.3.95 Phosphatidylinositol-3,5-bisphosphate 3-phosphatase", - "3.1.3.96 Pseudouridine 5'-phosphatase", - "3.1.3.97 3',5'-nucleoside bisphosphate phosphatase", - "3.1.3.98 Geranyl diphosphate phosphohydrolase", - "3.1.3.99 IMP-specific 5'-nucleotidase", - "3.1.3.100 Thiamine phosphate phosphatase", - "3.1.4.1 Phosphodiesterase I", - "3.1.4.2 Glycerophosphocholine phosphodiesterase", - "3.1.4.3 Phospholipase C", - "3.1.4.4 Phospholipase D", - "3.1.4.11 Phosphoinositide phospholipase C", - "3.1.4.12 Sphingomyelin phosphodiesterase", - "3.1.4.13 Serine-ethanolaminephosphate phosphodiesterase", - "3.1.4.14 [Acyl-carrier-protein] phosphodiesterase", - "3.1.4.16 2',3'-cyclic-nucleotide 2'-phosphodiesterase", - "3.1.4.17 3',5'-cyclic-nucleotide phosphodiesterase", - "3.1.4.35 3',5'-cyclic-GMP phosphodiesterase", - "3.1.4.37 2',3'-cyclic-nucleotide 3'-phosphodiesterase", - "3.1.4.38 Glycerophosphocholine cholinephosphodiesterase", - "3.1.4.39 Alkylglycerophosphoethanolamine phosphodiesterase", - "3.1.4.40 CMP-N-acylneuraminate phosphodiesterase", - "3.1.4.41 Sphingomyelin phosphodiesterase D", - "3.1.4.42 Glycerol-1,2-cyclic-phosphate 2-phosphodiesterase", - "3.1.4.43 Glycerophosphoinositol inositolphosphodiesterase", - "3.1.4.44 Glycerophosphoinositol glycerophosphodiesterase", - "3.1.4.45 N-acetylglucosamine-1-phosphodiester alpha-N-acetylglucosaminidase", - "3.1.4.46 Glycerophosphodiester phosphodiesterase", - "3.1.4.48 Dolichylphosphate-glucose phosphodiesterase", - "3.1.4.49 Dolichylphosphate-mannose phosphodiesterase", - "3.1.4.50 Glycosylphosphatidylinositol phospholipase D", - "3.1.4.51 Glucose-1-phospho-D-mannosylglycoprotein phosphodiesterase", - "3.1.4.52 Cyclic-guanylate-specific phosphodiesterase", - "3.1.4.53 3',5'-cyclic-AMP phosphodiesterase", - "3.1.4.54 N-acetylphosphatidylethanolamine-hydrolyzing phospholipase D", - "3.1.4.55 Phosphoribosyl 1,2-cyclic phosphate phosphodiesterase", - "3.1.4.56 7,8-dihydroneopterin 2',3'-cyclic phosphate phosphodiesterase", - "3.1.4.57 Phosphoribosyl 1,2-cyclic phosphate 1,2-diphosphodiesterase", - "3.1.5.1 dGTPase", - "3.1.6.1 Arylsulfatase", - "3.1.6.2 Steryl-sulfatase", - "3.1.6.3 Glycosulfatase", - "3.1.6.4 N-acetylgalactosamine-6-sulfatase", - "3.1.6.6 Choline-sulfatase", - "3.1.6.7 Cellulose-polysulfatase", - "3.1.6.8 Cerebroside-sulfatase", - "3.1.6.9 Chondro-4-sulfatase", - "3.1.6.10 Chondro-6-sulfatase", - "3.1.6.11 Disulfoglucosamine-6-sulfatase", - "3.1.6.12 N-acetylgalactosamine-4-sulfatase", - "3.1.6.13 Iduronate-2-sulfatase", - "3.1.6.14 N-acetylglucosamine-6-sulfatase", - "3.1.6.15 N-sulfoglucosamine-3-sulfatase", - "3.1.6.16 Monomethyl-sulfatase", - "3.1.6.17 D-lactate-2-sulfatase", - "3.1.6.18 Glucuronate-2-sulfatase", - "3.1.6.19 (R)-specific secondary-alkylsulfatase", - "3.1.7.1 Prenyl-diphosphatase", - "3.1.7.2 Guanosine-3',5'-bis(diphosphate) 3'-diphosphatase", - "3.1.7.3 Monoterpenyl-diphosphatase", - "3.1.7.5 Geranylgeranyl diphosphate diphosphatase", - "3.1.7.6 Farnesyl diphosphatase", - "3.1.7.7 Drimenol cyclase", - "3.1.7.8 Tuberculosinol synthase", - "3.1.7.9 Isotuberculosinol synthase", - "3.1.7.10 (13E)-labda-7,13-dien-15-ol synthase", - "3.1.7.11 Geranyl diphosphate diphosphatase", - "3.1.8.1 Aryldialkylphosphatase", - "3.1.8.2 Diisopropyl-fluorophosphatase", - "3.1.11.1 Exodeoxyribonuclease I", - "3.1.11.2 Exodeoxyribonuclease III", - "3.1.11.3 Exodeoxyribonuclease (lambda-induced)", - "3.1.11.4 Exodeoxyribonuclease (phage SP3-induced)", - "3.1.11.5 Exodeoxyribonuclease V", - "3.1.11.6 Exodeoxyribonuclease VII", - "3.1.12.1 5' to 3' exodeoxyribonuclease (nucleoside 3'-phosphate-forming)", - "3.1.13.1 Exoribonuclease II", - "3.1.13.2 Exoribonuclease H", - "3.1.13.3 Oligonucleotidase", - "3.1.13.4 Poly(A)-specific ribonuclease", - "3.1.13.5 Ribonuclease D", - "3.1.14.1 Yeast ribonuclease", - "3.1.15.1 Venom exonuclease", - "3.1.16.1 Spleen exonuclease", - "3.1.21.1 Deoxyribonuclease I", - "3.1.21.2 Deoxyribonuclease IV", - "3.1.21.3 Type I site-specific deoxyribonuclease", - "3.1.21.4 Type II site-specific deoxyribonuclease", - "3.1.21.5 Type III site-specific deoxyribonuclease", - "3.1.21.6 CC-preferring endodeoxyribonuclease", - "3.1.21.7 Deoxyribonuclease V", - "3.1.21.8 T(4) deoxyribonuclease II", - "3.1.21.9 T(4) deoxyribonuclease IV", - "3.1.22.1 Deoxyribonuclease II", - "3.1.22.2 Aspergillus deoxyribonuclease K(1)", - "3.1.22.4 Crossover junction endodeoxyribonuclease", - "3.1.22.5 Deoxyribonuclease X", - "3.1.25.1 Deoxyribonuclease (pyrimidine dimer)", - "3.1.26.1 Physarum polycephalum ribonuclease", - "3.1.26.2 Ribonuclease alpha", - "3.1.26.3 Ribonuclease III", - "3.1.26.4 Ribonuclease H", - "3.1.26.5 Ribonuclease P", - "3.1.26.6 Ribonuclease IV", - "3.1.26.7 Ribonuclease P4", - "3.1.26.8 Ribonuclease M5", - "3.1.26.9 Ribonuclease (poly-(U)-specific)", - "3.1.26.10 Ribonuclease IX", - "3.1.26.11 Ribonuclease Z", - "3.1.26.12 Ribonuclease E", - "3.1.26.13 Retroviral ribonuclease H", - "3.1.26.n2 Argonaute-2", - "3.1.27.1 Ribonuclease T(2)", - "3.1.27.2 Bacillus subtilis ribonuclease", - "3.1.27.3 Ribonuclease T(1)", - "3.1.27.4 Ribonuclease U(2)", - "3.1.27.5 Pancreatic ribonuclease", - "3.1.27.6 Enterobacter ribonuclease", - "3.1.27.7 Ribonuclease F", - "3.1.27.8 Ribonuclease V", - "3.1.27.10 rRNA endonuclease", - "3.1.30.1 Aspergillus nuclease S(1)", - "3.1.30.2 Serratia marcescens nuclease", - "3.1.31.1 Micrococcal nuclease", - "3.2.1.1 Alpha-amylase", - "3.2.1.2 Beta-amylase", - "3.2.1.3 Glucan 1,4-alpha-glucosidase", - "3.2.1.4 Cellulase", - "3.2.1.6 Endo-1,3(4)-beta-glucanase", - "3.2.1.7 Inulinase", - "3.2.1.8 Endo-1,4-beta-xylanase", - "3.2.1.10 Oligo-1,6-glucosidase", - "3.2.1.11 Dextranase", - "3.2.1.14 Chitinase", - "3.2.1.15 Polygalacturonase", - "3.2.1.17 Lysozyme", - "3.2.1.18 Exo-alpha-sialidase", - "3.2.1.20 Alpha-glucosidase", - "3.2.1.21 Beta-glucosidase", - "3.2.1.22 Alpha-galactosidase", - "3.2.1.23 Beta-galactosidase", - "3.2.1.24 Alpha-mannosidase", - "3.2.1.25 Beta-mannosidase", - "3.2.1.26 Beta-fructofuranosidase", - "3.2.1.28 Alpha,alpha-trehalase", - "3.2.1.31 Beta-glucuronidase", - "3.2.1.32 Endo-1,3-beta-xylanase", - "3.2.1.33 Amylo-alpha-1,6-glucosidase", - "3.2.1.35 Hyaluronoglucosaminidase", - "3.2.1.36 Hyaluronoglucuronidase", - "3.2.1.37 Xylan 1,4-beta-xylosidase", - "3.2.1.38 Beta-D-fucosidase", - "3.2.1.39 Glucan endo-1,3-beta-D-glucosidase", - "3.2.1.40 Alpha-L-rhamnosidase", - "3.2.1.41 Pullulanase", - "3.2.1.42 GDP-glucosidase", - "3.2.1.43 Beta-L-rhamnosidase", - "3.2.1.44 Fucoidanase", - "3.2.1.45 Glucosylceramidase", - "3.2.1.46 Galactosylceramidase", - "3.2.1.47 Galactosylgalactosylglucosylceramidase", - "3.2.1.48 Sucrose alpha-glucosidase", - "3.2.1.49 Alpha-N-acetylgalactosaminidase", - "3.2.1.50 Alpha-N-acetylglucosaminidase", - "3.2.1.51 Alpha-L-fucosidase", - "3.2.1.52 Beta-N-acetylhexosaminidase", - "3.2.1.53 Beta-N-acetylgalactosaminidase", - "3.2.1.54 Cyclomaltodextrinase", - "3.2.1.55 Non-reducing end alpha-L-arabinofuranosidase", - "3.2.1.56 Glucuronosyl-disulfoglucosamine glucuronidase", - "3.2.1.57 Isopullulanase", - "3.2.1.58 Glucan 1,3-beta-glucosidase", - "3.2.1.59 Glucan endo-1,3-alpha-glucosidase", - "3.2.1.60 Glucan 1,4-alpha-maltotetraohydrolase", - "3.2.1.61 Mycodextranase", - "3.2.1.62 Glycosylceramidase", - "3.2.1.63 1,2-alpha-L-fucosidase", - "3.2.1.64 2,6-beta-fructan 6-levanbiohydrolase", - "3.2.1.65 Levanase", - "3.2.1.66 Quercitrinase", - "3.2.1.67 Galacturan 1,4-alpha-galacturonidase", - "3.2.1.68 Isoamylase", - "3.2.1.70 Glucan 1,6-alpha-glucosidase", - "3.2.1.71 Glucan endo-1,2-beta-glucosidase", - "3.2.1.72 Xylan 1,3-beta-xylosidase", - "3.2.1.73 Licheninase", - "3.2.1.74 Glucan 1,4-beta-glucosidase", - "3.2.1.75 Glucan endo-1,6-beta-glucosidase", - "3.2.1.76 L-iduronidase", - "3.2.1.77 Mannan 1,2-(1,3)-alpha-mannosidase", - "3.2.1.78 Mannan endo-1,4-beta-mannosidase", - "3.2.1.80 Fructan beta-fructosidase", - "3.2.1.81 Beta-agarase", - "3.2.1.82 Exo-poly-alpha-galacturonosidase", - "3.2.1.83 Kappa-carrageenase", - "3.2.1.84 Glucan 1,3-alpha-glucosidase", - "3.2.1.85 6-phospho-beta-galactosidase", - "3.2.1.86 6-phospho-beta-glucosidase", - "3.2.1.87 Capsular-polysaccharide endo-1,3-alpha-galactosidase", - "3.2.1.88 Non-reducing end beta-L-arabinopyranosidase", - "3.2.1.89 Arabinogalactan endo-beta-1,4-galactanase", - "3.2.1.91 Cellulose 1,4-beta-cellobiosidase (non-reducing end)", - "3.2.1.92 Peptidoglycan beta-N-acetylmuramidase", - "3.2.1.93 Alpha,alpha-phosphotrehalase", - "3.2.1.94 Glucan 1,6-alpha-isomaltosidase", - "3.2.1.95 Dextran 1,6-alpha-isomaltotriosidase", - "3.2.1.96 Mannosyl-glycoprotein endo-beta-N-acetylglucosaminidase", - "3.2.1.97 Endo-alpha-N-acetylgalactosaminidase", - "3.2.1.98 Glucan 1,4-alpha-maltohexaosidase", - "3.2.1.99 Arabinan endo-1,5-alpha-L-arabinosidase", - "3.2.1.100 Mannan 1,4-mannobiosidase", - "3.2.1.101 Mannan endo-1,6-alpha-mannosidase", - "3.2.1.102 Blood-group-substance endo-1,4-beta-galactosidase", - "3.2.1.103 Keratan-sulfate endo-1,4-beta-galactosidase", - "3.2.1.104 Steryl-beta-glucosidase", - "3.2.1.105 3-alpha-(S)-strictosidine beta-glucosidase", - "3.2.1.106 Mannosyl-oligosaccharide glucosidase", - "3.2.1.107 Protein-glucosylgalactosylhydroxylysine glucosidase", - "3.2.1.108 Lactase", - "3.2.1.109 Endogalactosaminidase", - "3.2.1.111 1,3-alpha-L-fucosidase", - "3.2.1.112 2-deoxyglucosidase", - "3.2.1.113 Mannosyl-oligosaccharide 1,2-alpha-mannosidase", - "3.2.1.114 Mannosyl-oligosaccharide 1,3-1,6-alpha-mannosidase", - "3.2.1.115 Branched-dextran exo-1,2-alpha-glucosidase", - "3.2.1.116 Glucan 1,4-alpha-maltotriohydrolase", - "3.2.1.117 Amygdalin beta-glucosidase", - "3.2.1.118 Prunasin beta-glucosidase", - "3.2.1.119 Vicianin beta-glucosidase", - "3.2.1.120 Oligoxyloglucan beta-glycosidase", - "3.2.1.121 Polymannuronate hydrolase", - "3.2.1.122 Maltose-6'-phosphate glucosidase", - "3.2.1.123 Endoglycosylceramidase", - "3.2.1.124 3-deoxy-2-octulosonidase", - "3.2.1.125 Raucaffricine beta-glucosidase", - "3.2.1.126 Coniferin beta-glucosidase", - "3.2.1.127 1,6-alpha-L-fucosidase", - "3.2.1.128 Glycyrrhizinate beta-glucuronidase", - "3.2.1.129 Endo-alpha-sialidase", - "3.2.1.130 Glycoprotein endo-alpha-1,2-mannosidase", - "3.2.1.131 Xylan alpha-1,2-glucuronosidase", - "3.2.1.132 Chitosanase", - "3.2.1.133 Glucan 1,4-alpha-maltohydrolase", - "3.2.1.134 Difructose-anhydride synthase", - "3.2.1.135 Neopullulanase", - "3.2.1.136 Glucuronoarabinoxylan endo-1,4-beta-xylanase", - "3.2.1.137 Mannan exo-1,2-1,6-alpha-mannosidase", - "3.2.1.139 Alpha-glucuronidase", - "3.2.1.140 Lacto-N-biosidase", - "3.2.1.141 4-alpha-D-((1->4)-alpha-D-glucano)trehalose trehalohydrolase", - "3.2.1.142 Limit dextrinase", - "3.2.1.143 Poly(ADP-ribose) glycohydrolase", - "3.2.1.144 3-deoxyoctulosonase", - "3.2.1.145 Galactan 1,3-beta-galactosidase", - "3.2.1.146 Beta-galactofuranosidase", - "3.2.1.147 Thioglucosidase", - "3.2.1.149 Beta-primeverosidase", - "3.2.1.150 Oligoxyloglucan reducing-end-specific cellobiohydrolase", - "3.2.1.151 Xyloglucan-specific endo-beta-1,4-glucanase", - "3.2.1.152 Mannosylglycoprotein endo-beta-mannosidase", - "3.2.1.153 Fructan beta-(2,1)-fructosidase", - "3.2.1.154 Fructan beta-(2,6)-fructosidase", - "3.2.1.155 Xyloglucan-specific exo-beta-1,4-glucanase", - "3.2.1.156 Oligosaccharide reducing-end xylanase", - "3.2.1.157 Iota-carrageenase", - "3.2.1.158 Alpha-agarase", - "3.2.1.159 Alpha-neoagaro-oligosaccharide hydrolase", - "3.2.1.161 Beta-apiosyl-beta-glucosidase", - "3.2.1.162 Lambda-carrageenase", - "3.2.1.163 1,6-alpha-D-mannosidase", - "3.2.1.164 Galactan endo-1,6-beta-galactosidase", - "3.2.1.165 Exo-1,4-beta-D-glucosaminidase", - "3.2.1.166 Heparanase", - "3.2.1.167 Baicalin-beta-D-glucuronidase", - "3.2.1.168 Hesperidin 6-O-alpha-L-rhamnosyl-beta-D-glucosidase", - "3.2.1.169 Protein O-GlcNAcase", - "3.2.1.170 Mannosylglycerate hydrolase", - "3.2.1.171 Rhamnogalacturonan hydrolase", - "3.2.1.172 Unsaturated rhamnogalacturonyl hydrolase", - "3.2.1.173 Rhamnogalacturonan galacturonohydrolase", - "3.2.1.174 Rhamnogalacturonan rhamnohydrolase", - "3.2.1.175 Beta-D-glucopyranosyl abscisate beta-glucosidase", - "3.2.1.176 Cellulose 1,4-beta-cellobiosidase (reducing end)", - "3.2.1.177 Alpha-D-xyloside xylohydrolase", - "3.2.1.178 Beta-porphyranase", - "3.2.1.179 Gellan tetrasaccharide unsaturated glucuronyl hydrolase", - "3.2.1.180 Unsaturated chondroitin disaccharide hydrolase", - "3.2.1.181 Galactan endo-beta-1,3-galactanase", - "3.2.1.182 4-hydroxy-7-methoxy-3-oxo-3,4-dihydro-2H-1,4-benzoxazin-2-yl glucoside beta-D-glucosidase", - "3.2.1.183 UDP-N-acetylglucosamine 2-epimerase (hydrolyzing)", - "3.2.1.184 UDP-N,N'-diacetylbacillosamine 2-epimerase (hydrolyzing)", - "3.2.1.185 Non-reducing end beta-L-arabinofuranosidase", - "3.2.1.186 Protodioscin 26-O-beta-D-glucosidase", - "3.2.1.187 (Ara-f)(3)-Hyp beta-L-arabinobiosidase", - "3.2.1.188 Avenacosidase", - "3.2.1.189 Dioscin glycosidase (diosgenin-forming)", - "3.2.1.190 Dioscin glycosidase (3-O-beta-D-Glc-diosgenin-forming)", - "3.2.1.191 Ginsenosidase type III", - "3.2.1.192 Ginsenoside Rb1 beta-glucosidase", - "3.2.1.193 Ginsenosidase type I", - "3.2.1.194 Ginsenosidase type IV", - "3.2.1.195 20-O-multi-glycoside ginsenosidase", - "3.2.1.196 Limit dextrin alpha-1,6-maltotetraose-hydrolase", - "3.2.1.n1 Blood group B branched chain alpha-1,3-galactosidase", - "3.2.1.n2 Blood group B linear chain alpha-1,3-galactosidase", - "3.2.1.n3 Dictyostelium lysozyme A", - "3.2.2.1 Purine nucleosidase", - "3.2.2.2 Inosine nucleosidase", - "3.2.2.3 Uridine nucleosidase", - "3.2.2.4 AMP nucleosidase", - "3.2.2.5 NAD(+) glycohydrolase", - "3.2.2.6 ADP-ribosyl cyclase/cyclic ADP-ribose hydrolase", - "3.2.2.7 Adenosine nucleosidase", - "3.2.2.8 Ribosylpyrimidine nucleosidase", - "3.2.2.9 Adenosylhomocysteine nucleosidase", - "3.2.2.10 Pyrimidine-5'-nucleotide nucleosidase", - "3.2.2.11 Beta-aspartyl-N-acetylglucosaminidase", - "3.2.2.12 Inosinate nucleosidase", - "3.2.2.13 1-methyladenosine nucleosidase", - "3.2.2.14 NMN nucleosidase", - "3.2.2.15 DNA-deoxyinosine glycosylase", - "3.2.2.16 Methylthioadenosine nucleosidase", - "3.2.2.17 Deoxyribodipyrimidine endonucleosidase", - "3.2.2.19 [Protein ADP-ribosylarginine] hydrolase", - "3.2.2.20 DNA-3-methyladenine glycosylase I", - "3.2.2.21 DNA-3-methyladenine glycosylase II", - "3.2.2.22 rRNA N-glycosylase", - "3.2.2.23 DNA-formamidopyrimidine glycosylase", - "3.2.2.24 ADP-ribosyl-[dinitrogen reductase] hydrolase", - "3.2.2.25 N-methyl nucleosidase", - "3.2.2.26 Futalosine hydrolase", - "3.2.2.27 Uracil-DNA glycosylase", - "3.2.2.28 Double-stranded uracil-DNA glycosylase", - "3.2.2.29 Thymine-DNA glycosylase", - "3.2.2.30 Aminodeoxyfutalosine nucleosidase", - "3.2.2.n1 Cytokinin riboside 5'-monophosphate phosphoribohydrolase", - "3.3.1.1 Adenosylhomocysteinase", - "3.3.1.2 Adenosylmethionine hydrolase", - "3.3.2.1 Isochorismatase", - "3.3.2.2 Alkenylglycerophosphocholine hydrolase", - "3.3.2.4 Trans-epoxysuccinate hydrolase", - "3.3.2.5 Alkenylglycerophosphoethanolamine hydrolase", - "3.3.2.6 Leukotriene-A(4) hydrolase", - "3.3.2.7 Hepoxilin-epoxide hydrolase", - "3.3.2.8 Limonene-1,2-epoxide hydrolase", - "3.3.2.9 Microsomal epoxide hydrolase", - "3.3.2.10 Soluble epoxide hydrolase", - "3.3.2.11 Cholesterol-5,6-oxide hydrolase", - "3.3.2.12 Oxepin-CoA hydrolase", - "3.3.2.13 Chorismatase", - "3.3.2.14 2,4-dinitroanisole O-demethylase", - "3.4.11.1 Leucyl aminopeptidase", - "3.4.11.2 Membrane alanyl aminopeptidase", - "3.4.11.3 Cystinyl aminopeptidase", - "3.4.11.4 Tripeptide aminopeptidase", - "3.4.11.5 Prolyl aminopeptidase", - "3.4.11.6 Aminopeptidase B", - "3.4.11.7 Glutamyl aminopeptidase", - "3.4.11.9 Xaa-Pro aminopeptidase", - "3.4.11.10 Bacterial leucyl aminopeptidase", - "3.4.11.13 Clostridial aminopeptidase", - "3.4.11.14 Cytosol alanyl aminopeptidase", - "3.4.11.15 Aminopeptidase Y", - "3.4.11.16 Xaa-Trp aminopeptidase", - "3.4.11.17 Tryptophanyl aminopeptidase", - "3.4.11.18 Methionyl aminopeptidase", - "3.4.11.19 D-stereospecific aminopeptidase", - "3.4.11.20 Aminopeptidase Ey", - "3.4.11.21 Aspartyl aminopeptidase", - "3.4.11.22 Aminopeptidase I", - "3.4.11.23 PepB aminopeptidase", - "3.4.11.24 Aminopeptidase S", - "3.4.11.25 Beta-peptidyl aminopeptidase", - "3.4.11.26 Intermediate cleaving peptidase 55", - "3.4.13.4 Xaa-Arg dipeptidase", - "3.4.13.5 Xaa-methyl-His dipeptidase", - "3.4.13.7 Glu-Glu dipeptidase", - "3.4.13.9 Xaa-Pro dipeptidase", - "3.4.13.12 Met-Xaa dipeptidase", - "3.4.13.17 Non-stereospecific dipeptidase", - "3.4.13.18 Cytosol nonspecific dipeptidase", - "3.4.13.19 Membrane dipeptidase", - "3.4.13.20 Beta-Ala-His dipeptidase", - "3.4.13.21 Dipeptidase E", - "3.4.13.22 D-Ala-D-Ala dipeptidase", - "3.4.14.1 Dipeptidyl-peptidase I", - "3.4.14.2 Dipeptidyl-peptidase II", - "3.4.14.4 Dipeptidyl-peptidase III", - "3.4.14.5 Dipeptidyl-peptidase IV", - "3.4.14.6 Dipeptidyl-dipeptidase", - "3.4.14.9 Tripeptidyl-peptidase I", - "3.4.14.10 Tripeptidyl-peptidase II", - "3.4.14.11 Xaa-Pro dipeptidyl-peptidase", - "3.4.14.12 Xaa-Xaa-Pro tripeptidyl-peptidase", - "3.4.14.13 Gamma-D-glutamyl-L-lysine dipeptidyl-peptidase", - "3.4.15.1 Peptidyl-dipeptidase A", - "3.4.15.4 Peptidyl-dipeptidase B", - "3.4.15.5 Peptidyl-dipeptidase Dcp", - "3.4.15.6 Cyanophycinase", - "3.4.16.2 Lysosomal Pro-Xaa carboxypeptidase", - "3.4.16.4 Serine-type D-Ala-D-Ala carboxypeptidase", - "3.4.16.5 Carboxypeptidase C", - "3.4.16.6 Carboxypeptidase D", - "3.4.17.1 Carboxypeptidase A", - "3.4.17.2 Carboxypeptidase B", - "3.4.17.3 Lysine carboxypeptidase", - "3.4.17.4 Gly-Xaa carboxypeptidase", - "3.4.17.6 Alanine carboxypeptidase", - "3.4.17.8 Muramoylpentapeptide carboxypeptidase", - "3.4.17.10 Carboxypeptidase E", - "3.4.17.11 Glutamate carboxypeptidase", - "3.4.17.12 Carboxypeptidase M", - "3.4.17.13 Muramoyltetrapeptide carboxypeptidase", - "3.4.17.14 Zinc D-Ala-D-Ala carboxypeptidase", - "3.4.17.15 Carboxypeptidase A2", - "3.4.17.16 Membrane Pro-Xaa carboxypeptidase", - "3.4.17.17 Tubulinyl-Tyr carboxypeptidase", - "3.4.17.18 Carboxypeptidase T", - "3.4.17.19 Carboxypeptidase Taq", - "3.4.17.20 Carboxypeptidase U", - "3.4.17.21 Glutamate carboxypeptidase II", - "3.4.17.22 Metallocarboxypeptidase D", - "3.4.17.23 Angiotensin-converting enzyme 2", - "3.4.17.n1 [CysO]-cysteine peptidase", - "3.4.18.1 Cathepsin X", - "3.4.19.1 Acylaminoacyl-peptidase", - "3.4.19.2 Peptidyl-glycinamidase", - "3.4.19.3 Pyroglutamyl-peptidase I", - "3.4.19.5 Beta-aspartyl-peptidase", - "3.4.19.6 Pyroglutamyl-peptidase II", - "3.4.19.7 N-formylmethionyl-peptidase", - "3.4.19.9 Gamma-glutamyl hydrolase", - "3.4.19.11 Gamma-D-glutamyl-meso-diaminopimelate peptidase", - "3.4.19.12 Ubiquitinyl hydrolase 1", - "3.4.19.13 Glutathione hydrolase", - "3.4.19.14 Leukotriene-C(4) hydrolase", - "3.4.21.1 Chymotrypsin", - "3.4.21.2 Chymotrypsin C", - "3.4.21.3 Metridin", - "3.4.21.4 Trypsin", - "3.4.21.5 Thrombin", - "3.4.21.6 Coagulation factor Xa", - "3.4.21.7 Plasmin", - "3.4.21.9 Enteropeptidase", - "3.4.21.10 Acrosin", - "3.4.21.12 Alpha-lytic endopeptidase", - "3.4.21.19 Glutamyl endopeptidase", - "3.4.21.20 Cathepsin G", - "3.4.21.21 Coagulation factor VIIa", - "3.4.21.22 Coagulation factor IXa", - "3.4.21.25 Cucumisin", - "3.4.21.26 Prolyl oligopeptidase", - "3.4.21.27 Coagulation factor XIa", - "3.4.21.32 Brachyurin", - "3.4.21.34 Plasma kallikrein", - "3.4.21.35 Tissue kallikrein", - "3.4.21.36 Pancreatic elastase", - "3.4.21.37 Leukocyte elastase", - "3.4.21.38 Coagulation factor XIIa", - "3.4.21.39 Chymase", - "3.4.21.41 Complement subcomponent C1r", - "3.4.21.42 Complement subcomponent C1s", - "3.4.21.43 Classical-complement-pathway C3/C5 convertase", - "3.4.21.45 Complement factor I", - "3.4.21.46 Complement factor D", - "3.4.21.47 Alternative-complement-pathway C3/C5 convertase", - "3.4.21.48 Cerevisin", - "3.4.21.49 Hypodermin C", - "3.4.21.50 Lysyl endopeptidase", - "3.4.21.53 Endopeptidase La", - "3.4.21.54 Gamma-renin", - "3.4.21.55 Venombin AB", - "3.4.21.57 Leucyl endopeptidase", - "3.4.21.59 Tryptase", - "3.4.21.60 Scutelarin", - "3.4.21.61 Kexin", - "3.4.21.62 Subtilisin", - "3.4.21.63 Oryzin", - "3.4.21.64 Peptidase K", - "3.4.21.65 Thermomycolin", - "3.4.21.66 Thermitase", - "3.4.21.67 Endopeptidase So", - "3.4.21.68 T-plasminogen activator", - "3.4.21.69 Protein C (activated)", - "3.4.21.70 Pancreatic endopeptidase E", - "3.4.21.71 Pancreatic elastase II", - "3.4.21.72 IgA-specific serine endopeptidase", - "3.4.21.73 U-plasminogen activator", - "3.4.21.74 Venombin A", - "3.4.21.75 Furin", - "3.4.21.76 Myeloblastin", - "3.4.21.77 Semenogelase", - "3.4.21.78 Granzyme A", - "3.4.21.79 Granzyme B", - "3.4.21.80 Streptogrisin A", - "3.4.21.81 Streptogrisin B", - "3.4.21.82 Glutamyl endopeptidase II", - "3.4.21.83 Oligopeptidase B", - "3.4.21.84 Limulus clotting factor C", - "3.4.21.85 Limulus clotting factor B", - "3.4.21.86 Limulus clotting enzyme", - "3.4.21.88 Repressor LexA", - "3.4.21.89 Signal peptidase I", - "3.4.21.90 Togavirin", - "3.4.21.91 Flavivirin", - "3.4.21.92 Endopeptidase Clp", - "3.4.21.93 Proprotein convertase 1", - "3.4.21.94 Proprotein convertase 2", - "3.4.21.95 Snake venom factor V activator", - "3.4.21.96 Lactocepin", - "3.4.21.97 Assemblin", - "3.4.21.98 Hepacivirin", - "3.4.21.99 Spermosin", - "3.4.21.100 Sedolisin", - "3.4.21.101 Xanthomonalisin", - "3.4.21.102 C-terminal processing peptidase", - "3.4.21.103 Physarolisin", - "3.4.21.104 Mannan-binding lectin-associated serine protease-2", - "3.4.21.105 Rhomboid protease", - "3.4.21.106 Hepsin", - "3.4.21.107 Peptidase Do", - "3.4.21.108 HtrA2 peptidase", - "3.4.21.109 Matriptase", - "3.4.21.110 C5a peptidase", - "3.4.21.111 Aqualysin 1", - "3.4.21.112 Site-1 protease", - "3.4.21.113 Pestivirus NS3 polyprotein peptidase", - "3.4.21.114 Equine arterivirus serine peptidase", - "3.4.21.115 Infectious pancreatic necrosis birnavirus Vp4 peptidase", - "3.4.21.116 SpoIVB peptidase", - "3.4.21.117 Stratum corneum chymotryptic enzyme", - "3.4.21.118 Kallikrein 8", - "3.4.21.119 Kallikrein 13", - "3.4.21.120 Oviductin", - "3.4.21.121 Lys-Lys/Arg-Xaa endopeptidase", - "3.4.22.1 Cathepsin B", - "3.4.22.2 Papain", - "3.4.22.3 Ficain", - "3.4.22.6 Chymopapain", - "3.4.22.7 Asclepain", - "3.4.22.8 Clostripain", - "3.4.22.10 Streptopain", - "3.4.22.14 Actinidain", - "3.4.22.15 Cathepsin L", - "3.4.22.16 Cathepsin H", - "3.4.22.24 Cathepsin T", - "3.4.22.25 Glycyl endopeptidase", - "3.4.22.26 Cancer procoagulant", - "3.4.22.27 Cathepsin S", - "3.4.22.28 Picornain 3C", - "3.4.22.29 Picornain 2A", - "3.4.22.30 Caricain", - "3.4.22.31 Ananain", - "3.4.22.32 Stem bromelain", - "3.4.22.33 Fruit bromelain", - "3.4.22.34 Legumain", - "3.4.22.35 Histolysain", - "3.4.22.36 Caspase-1", - "3.4.22.37 Gingipain R", - "3.4.22.38 Cathepsin K", - "3.4.22.39 Adenain", - "3.4.22.40 Bleomycin hydrolase", - "3.4.22.41 Cathepsin F", - "3.4.22.42 Cathepsin O", - "3.4.22.43 Cathepsin V", - "3.4.22.44 Nuclear-inclusion-a endopeptidase", - "3.4.22.45 Helper-component proteinase", - "3.4.22.46 L-peptidase", - "3.4.22.47 Gingipain K", - "3.4.22.48 Staphopain", - "3.4.22.49 Separase", - "3.4.22.50 V-cath endopeptidase", - "3.4.22.51 Cruzipain", - "3.4.22.52 Calpain-1", - "3.4.22.53 Calpain-2", - "3.4.22.54 Calpain-3", - "3.4.22.55 Caspase-2", - "3.4.22.56 Caspase-3", - "3.4.22.57 Caspase-4", - "3.4.22.58 Caspase-5", - "3.4.22.59 Caspase-6", - "3.4.22.60 Caspase-7", - "3.4.22.61 Caspase-8", - "3.4.22.62 Caspase-9", - "3.4.22.63 Caspase-10", - "3.4.22.64 Caspase-11", - "3.4.22.65 Peptidase 1 (mite)", - "3.4.22.66 Calicivirin", - "3.4.22.67 Zingipain", - "3.4.22.68 Ulp1 peptidase", - "3.4.22.69 SARS coronavirus main proteinase", - "3.4.22.70 Sortase A", - "3.4.22.71 Sortase B", - "3.4.23.1 Pepsin A", - "3.4.23.2 Pepsin B", - "3.4.23.3 Gastricsin", - "3.4.23.4 Chymosin", - "3.4.23.5 Cathepsin D", - "3.4.23.12 Nepenthesin", - "3.4.23.15 Renin", - "3.4.23.16 HIV-1 retropepsin", - "3.4.23.17 Pro-opiomelanocortin converting enzyme", - "3.4.23.18 Aspergillopepsin I", - "3.4.23.19 Aspergillopepsin II", - "3.4.23.20 Penicillopepsin", - "3.4.23.21 Rhizopuspepsin", - "3.4.23.22 Endothiapepsin", - "3.4.23.23 Mucorpepsin", - "3.4.23.24 Candidapepsin", - "3.4.23.25 Saccharopepsin", - "3.4.23.26 Rhodotorulapepsin", - "3.4.23.28 Acrocylindropepsin", - "3.4.23.29 Polyporopepsin", - "3.4.23.30 Pycnoporopepsin", - "3.4.23.31 Scytalidopepsin A", - "3.4.23.32 Scytalidopepsin B", - "3.4.23.34 Cathepsin E", - "3.4.23.35 Barrierpepsin", - "3.4.23.36 Signal peptidase II", - "3.4.23.38 Plasmepsin I", - "3.4.23.39 Plasmepsin II", - "3.4.23.40 Phytepsin", - "3.4.23.41 Yapsin 1", - "3.4.23.42 Thermopsin", - "3.4.23.43 Prepilin peptidase", - "3.4.23.44 Nodavirus endopeptidase", - "3.4.23.45 Memapsin 1", - "3.4.23.46 Memapsin 2", - "3.4.23.47 HIV-2 retropepsin", - "3.4.23.48 Plasminogen activator Pla", - "3.4.23.49 Omptin", - "3.4.23.50 Human endogenous retrovirus K endopeptidase", - "3.4.23.51 HycI peptidase", - "3.4.23.52 Preflagellin peptidase", - "3.4.24.1 Atrolysin A", - "3.4.24.3 Microbial collagenase", - "3.4.24.6 Leucolysin", - "3.4.24.7 Interstitial collagenase", - "3.4.24.11 Neprilysin", - "3.4.24.12 Envelysin", - "3.4.24.13 IgA-specific metalloendopeptidase", - "3.4.24.14 Procollagen N-endopeptidase", - "3.4.24.15 Thimet oligopeptidase", - "3.4.24.16 Neurolysin", - "3.4.24.17 Stromelysin 1", - "3.4.24.18 Meprin A", - "3.4.24.19 Procollagen C-endopeptidase", - "3.4.24.20 Peptidyl-Lys metalloendopeptidase", - "3.4.24.21 Astacin", - "3.4.24.22 Stromelysin 2", - "3.4.24.23 Matrilysin", - "3.4.24.24 Gelatinase A", - "3.4.24.25 Vibriolysin", - "3.4.24.26 Pseudolysin", - "3.4.24.27 Thermolysin", - "3.4.24.28 Bacillolysin", - "3.4.24.29 Aureolysin", - "3.4.24.30 Coccolysin", - "3.4.24.31 Mycolysin", - "3.4.24.32 Beta-lytic metalloendopeptidase", - "3.4.24.33 Peptidyl-Asp metalloendopeptidase", - "3.4.24.34 Neutrophil collagenase", - "3.4.24.35 Gelatinase B", - "3.4.24.36 Leishmanolysin", - "3.4.24.37 Saccharolysin", - "3.4.24.38 Gametolysin", - "3.4.24.39 Deuterolysin", - "3.4.24.40 Serralysin", - "3.4.24.41 Atrolysin B", - "3.4.24.42 Atrolysin C", - "3.4.24.43 Atroxase", - "3.4.24.44 Atrolysin E", - "3.4.24.45 Atrolysin F", - "3.4.24.46 Adamalysin", - "3.4.24.47 Horrilysin", - "3.4.24.48 Ruberlysin", - "3.4.24.49 Bothropasin", - "3.4.24.50 Bothrolysin", - "3.4.24.51 Ophiolysin", - "3.4.24.52 Trimerelysin I", - "3.4.24.53 Trimerelysin II", - "3.4.24.54 Mucrolysin", - "3.4.24.55 Pitrilysin", - "3.4.24.56 Insulysin", - "3.4.24.57 O-sialoglycoprotein endopeptidase", - "3.4.24.58 Russellysin", - "3.4.24.59 Mitochondrial intermediate peptidase", - "3.4.24.60 Dactylysin", - "3.4.24.61 Nardilysin", - "3.4.24.62 Magnolysin", - "3.4.24.63 Meprin B", - "3.4.24.64 Mitochondrial processing peptidase", - "3.4.24.65 Macrophage elastase", - "3.4.24.66 Choriolysin L", - "3.4.24.67 Choriolysin H", - "3.4.24.68 Tentoxilysin", - "3.4.24.69 Bontoxilysin", - "3.4.24.70 Oligopeptidase A", - "3.4.24.71 Endothelin-converting enzyme 1", - "3.4.24.72 Fibrolase", - "3.4.24.73 Jararhagin", - "3.4.24.74 Fragilysin", - "3.4.24.75 Lysostaphin", - "3.4.24.76 Flavastacin", - "3.4.24.77 Snapalysin", - "3.4.24.78 GPR endopeptidase", - "3.4.24.79 Pappalysin-1", - "3.4.24.80 Membrane-type matrix metalloproteinase-1", - "3.4.24.81 ADAM10 endopeptidase", - "3.4.24.82 ADAMTS-4 endopeptidase", - "3.4.24.83 Anthrax lethal factor endopeptidase", - "3.4.24.84 Ste24 endopeptidase", - "3.4.24.85 S2P endopeptidase", - "3.4.24.86 ADAM 17 endopeptidase", - "3.4.24.87 ADAMTS13 endopeptidase", - "3.4.24.88 Desampylase", - "3.4.24.89 Pro-Pro endopeptidase", - "3.4.25.1 Proteasome endopeptidase complex", - "3.4.25.2 HslU--HslV peptidase", - "3.5.1.1 Asparaginase", - "3.5.1.2 Glutaminase", - "3.5.1.3 Omega-amidase", - "3.5.1.4 Amidase", - "3.5.1.5 Urease", - "3.5.1.6 Beta-ureidopropionase", - "3.5.1.7 Ureidosuccinase", - "3.5.1.8 Formylaspartate deformylase", - "3.5.1.9 Arylformamidase", - "3.5.1.10 Formyltetrahydrofolate deformylase", - "3.5.1.11 Penicillin amidase", - "3.5.1.12 Biotinidase", - "3.5.1.13 Aryl-acylamidase", - "3.5.1.14 N-acyl-aliphatic-L-amino acid amidohydrolase", - "3.5.1.15 Aspartoacylase", - "3.5.1.16 Acetylornithine deacetylase", - "3.5.1.17 Acyl-lysine deacylase", - "3.5.1.18 Succinyl-diaminopimelate desuccinylase", - "3.5.1.19 Nicotinamidase", - "3.5.1.20 Citrullinase", - "3.5.1.21 N-acetyl-beta-alanine deacetylase", - "3.5.1.22 Pantothenase", - "3.5.1.23 Ceramidase", - "3.5.1.24 Choloylglycine hydrolase", - "3.5.1.25 N-acetylglucosamine-6-phosphate deacetylase", - "3.5.1.26 N(4)-(beta-N-acetylglucosaminyl)-L-asparaginase", - "3.5.1.28 N-acetylmuramoyl-L-alanine amidase", - "3.5.1.29 2-(acetamidomethylene)succinate hydrolase", - "3.5.1.30 5-aminopentanamidase", - "3.5.1.31 Formylmethionine deformylase", - "3.5.1.32 Hippurate hydrolase", - "3.5.1.33 N-acetylglucosamine deacetylase", - "3.5.1.35 D-glutaminase", - "3.5.1.36 N-methyl-2-oxoglutaramate hydrolase", - "3.5.1.38 Glutamin-(asparagin-)ase", - "3.5.1.39 Alkylamidase", - "3.5.1.40 Acylagmatine amidase", - "3.5.1.41 Chitin deacetylase", - "3.5.1.42 Nicotinamide-nucleotide amidase", - "3.5.1.43 Peptidyl-glutaminase", - "3.5.1.44 Protein-glutamine glutaminase", - "3.5.1.46 6-aminohexanoate-oligomer exohydrolase", - "3.5.1.47 N-acetyldiaminopimelate deacetylase", - "3.5.1.48 Acetylspermidine deacetylase", - "3.5.1.49 Formamidase", - "3.5.1.50 Pentanamidase", - "3.5.1.51 4-acetamidobutyryl-CoA deacetylase", - "3.5.1.52 Peptide-N(4)-(N-acetyl-beta-glucosaminyl)asparagine amidase", - "3.5.1.53 N-carbamoylputrescine amidase", - "3.5.1.54 Allophanate hydrolase", - "3.5.1.55 Long-chain-fatty-acyl-glutamate deacylase", - "3.5.1.56 N,N-dimethylformamidase", - "3.5.1.57 Tryptophanamidase", - "3.5.1.58 N-benzyloxycarbonylglycine hydrolase", - "3.5.1.59 N-carbamoylsarcosine amidase", - "3.5.1.60 N-(long-chain-acyl)ethanolamine deacylase", - "3.5.1.61 Mimosinase", - "3.5.1.62 Acetylputrescine deacetylase", - "3.5.1.63 4-acetamidobutyrate deacetylase", - "3.5.1.64 N(alpha)-benzyloxycarbonylleucine hydrolase", - "3.5.1.65 Theanine hydrolase", - "3.5.1.66 2-(hydroxymethyl)-3-(acetamidomethylene)succinate hydrolase", - "3.5.1.67 4-methyleneglutaminase", - "3.5.1.68 N-formylglutamate deformylase", - "3.5.1.69 Glycosphingolipid deacylase", - "3.5.1.70 Aculeacin-A deacylase", - "3.5.1.71 N-feruloylglycine deacylase", - "3.5.1.72 D-benzoylarginine-4-nitroanilide amidase", - "3.5.1.73 Carnitinamidase", - "3.5.1.74 Chenodeoxycholoyltaurine hydrolase", - "3.5.1.75 Urethanase", - "3.5.1.76 Arylalkyl acylamidase", - "3.5.1.77 N-carbamoyl-D-amino-acid hydrolase", - "3.5.1.78 Glutathionylspermidine amidase", - "3.5.1.79 Phthalyl amidase", - "3.5.1.81 N-acyl-D-amino-acid deacylase", - "3.5.1.82 N-acyl-D-glutamate deacylase", - "3.5.1.83 N-acyl-D-aspartate deacylase", - "3.5.1.84 Biuret amidohydrolase", - "3.5.1.85 (S)-N-acetyl-1-phenylethylamine hydrolase", - "3.5.1.86 Mandelamide amidase", - "3.5.1.87 N-carbamoyl-L-amino-acid hydrolase", - "3.5.1.88 Peptide deformylase", - "3.5.1.89 N-acetylglucosaminylphosphatidylinositol deacetylase", - "3.5.1.90 Adenosylcobinamide hydrolase", - "3.5.1.91 N-substituted formamide deformylase", - "3.5.1.92 Pantetheine hydrolase", - "3.5.1.93 Glutaryl-7-aminocephalosporanic-acid acylase", - "3.5.1.94 Gamma-glutamyl-gamma-aminobutyrate hydrolase", - "3.5.1.95 N-malonylurea hydrolase", - "3.5.1.96 Succinylglutamate desuccinylase", - "3.5.1.97 Acyl-homoserine-lactone acylase", - "3.5.1.98 Histone deacetylase", - "3.5.1.99 Fatty acid amide hydrolase", - "3.5.1.100 (R)-amidase", - "3.5.1.101 L-proline amide hydrolase", - "3.5.1.102 2-amino-5-formylamino-6-ribosylaminopyrimidin-4(3H)-one 5'-monophosphate deformylase", - "3.5.1.103 N-acetyl-1-D-myo-inositol-2-amino-2-deoxy-alpha-D-glucopyranoside deacetylase", - "3.5.1.104 Peptidoglycan-N-acetylglucosamine deacetylase", - "3.5.1.105 Chitin disaccharide deacetylase", - "3.5.1.106 N-formylmaleamate deformylase", - "3.5.1.107 Maleamate amidohydrolase", - "3.5.1.108 UDP-3-O-acyl-N-acetylglucosamine deacetylase", - "3.5.1.109 Sphingomyelin deacylase", - "3.5.1.110 Peroxyureidoacrylate/ureidoacrylate amidohydrolase", - "3.5.1.111 2-oxoglutaramate amidase", - "3.5.1.112 2'-N-acetylparomamine deacetylase", - "3.5.1.113 2'''-acetyl-6'''-hydroxyneomycin C deacetylase", - "3.5.1.114 N-acyl-aromatic-L-amino acid amidohydrolase", - "3.5.1.115 Mycothiol S-conjugate amidase", - "3.5.1.116 Ureidoglycolate amidohydrolase", - "3.5.1.117 6-aminohexanoate-oligomer endohydrolase", - "3.5.1.118 Gamma-glutamyl hercynylcysteine S-oxide hydrolase", - "3.5.1.119 Pup amidohydrolase", - "3.5.1.n3 4-deoxy-4-formamido-L-arabinose-phosphoundecaprenol deformylase", - "3.5.2.1 Barbiturase", - "3.5.2.2 Dihydropyrimidinase", - "3.5.2.3 Dihydroorotase", - "3.5.2.4 Carboxymethylhydantoinase", - "3.5.2.5 Allantoinase", - "3.5.2.6 Beta-lactamase", - "3.5.2.7 Imidazolonepropionase", - "3.5.2.9 5-oxoprolinase (ATP-hydrolyzing)", - "3.5.2.10 Creatininase", - "3.5.2.11 L-lysine-lactamase", - "3.5.2.12 6-aminohexanoate-cyclic-dimer hydrolase", - "3.5.2.13 2,5-dioxopiperazine hydrolase", - "3.5.2.14 N-methylhydantoinase (ATP-hydrolyzing)", - "3.5.2.15 Cyanuric acid amidohydrolase", - "3.5.2.16 Maleimide hydrolase", - "3.5.2.17 Hydroxyisourate hydrolase", - "3.5.2.18 Enamidase", - "3.5.2.19 Streptothricin hydrolase", - "3.5.2.20 Isatin hydrolase", - "3.5.3.1 Arginase", - "3.5.3.2 Guanidinoacetase", - "3.5.3.3 Creatinase", - "3.5.3.4 Allantoicase", - "3.5.3.5 Formimidoylaspartate deiminase", - "3.5.3.6 Arginine deiminase", - "3.5.3.7 Guanidinobutyrase", - "3.5.3.8 Formimidoylglutamase", - "3.5.3.9 Allantoate deiminase", - "3.5.3.10 D-arginase", - "3.5.3.11 Agmatinase", - "3.5.3.12 Agmatine deiminase", - "3.5.3.13 Formimidoylglutamate deiminase", - "3.5.3.14 Amidinoaspartase", - "3.5.3.15 Protein-arginine deiminase", - "3.5.3.16 Methylguanidinase", - "3.5.3.17 Guanidinopropionase", - "3.5.3.18 Dimethylargininase", - "3.5.3.20 Diguanidinobutanase", - "3.5.3.21 Methylenediurea deaminase", - "3.5.3.22 Proclavaminate amidinohydrolase", - "3.5.3.23 N-succinylarginine dihydrolase", - "3.5.3.24 N(1)-aminopropylagmatine ureohydrolase", - "3.5.3.25 N(omega)-hydroxy-L-arginine amidinohydrolase", - "3.5.3.26 (S)-ureidoglycine aminohydrolase", - "3.5.4.1 Cytosine deaminase", - "3.5.4.2 Adenine deaminase", - "3.5.4.3 Guanine deaminase", - "3.5.4.4 Adenosine deaminase", - "3.5.4.5 Cytidine deaminase", - "3.5.4.6 AMP deaminase", - "3.5.4.7 ADP deaminase", - "3.5.4.8 Aminoimidazolase", - "3.5.4.9 Methenyltetrahydrofolate cyclohydrolase", - "3.5.4.10 IMP cyclohydrolase", - "3.5.4.11 Pterin deaminase", - "3.5.4.12 dCMP deaminase", - "3.5.4.13 dCTP deaminase", - "3.5.4.15 Guanosine deaminase", - "3.5.4.16 GTP cyclohydrolase I", - "3.5.4.17 Adenosine-phosphate deaminase", - "3.5.4.18 ATP deaminase", - "3.5.4.19 Phosphoribosyl-AMP cyclohydrolase", - "3.5.4.20 Pyrithiamine deaminase", - "3.5.4.21 Creatinine deaminase", - "3.5.4.22 1-pyrroline-4-hydroxy-2-carboxylate deaminase", - "3.5.4.23 Blasticidin-S deaminase", - "3.5.4.24 Sepiapterin deaminase", - "3.5.4.25 GTP cyclohydrolase II", - "3.5.4.26 Diaminohydroxyphosphoribosylaminopyrimidine deaminase", - "3.5.4.27 Methenyltetrahydromethanopterin cyclohydrolase", - "3.5.4.28 S-adenosylhomocysteine deaminase", - "3.5.4.29 GTP cyclohydrolase IIa", - "3.5.4.30 dCTP deaminase (dUMP-forming)", - "3.5.4.31 S-methyl-5'-thioadenosine deaminase", - "3.5.4.32 8-oxoguanine deaminase", - "3.5.4.33 tRNA(adenine(34)) deaminase", - "3.5.4.34 tRNA(Ala)(adenine(37)) deaminase", - "3.5.4.35 tRNA(cytosine(8)) deaminase", - "3.5.4.36 mRNA(cytosine(6666)) deaminase", - "3.5.4.37 Double-stranded RNA adenine deaminase", - "3.5.4.38 Single-stranded DNA cytosine deaminase", - "3.5.4.39 GTP cyclohydrolase IV", - "3.5.4.40 Aminodeoxyfutalosine deaminase", - "3.5.4.41 5'-deoxyadenosine deaminase", - "3.5.4.n3 Melamine deaminase", - "3.5.5.1 Nitrilase", - "3.5.5.2 Ricinine nitrilase", - "3.5.5.4 Cyanoalanine nitrilase", - "3.5.5.5 Arylacetonitrilase", - "3.5.5.6 Bromoxynil nitrilase", - "3.5.5.7 Aliphatic nitrilase", - "3.5.5.8 Thiocyanate hydrolase", - "3.5.99.1 Riboflavinase", - "3.5.99.2 Aminopyrimidine aminohydrolase", - "3.5.99.3 Hydroxydechloroatrazine ethylaminohydrolase", - "3.5.99.4 N-isopropylammelide isopropylaminohydrolase", - "3.5.99.5 2-aminomuconate deaminase", - "3.5.99.6 Glucosamine-6-phosphate deaminase", - "3.5.99.7 1-aminocyclopropane-1-carboxylate deaminase", - "3.5.99.8 5-nitroanthranilic acid aminohydrolase", - "3.5.99.9 2-nitroimidazole nitrohydrolase", - "3.5.99.10 2-iminobutanoate/2-iminopropanoate deaminase", - "3.6.1.1 Inorganic diphosphatase", - "3.6.1.2 Trimetaphosphatase", - "3.6.1.3 Adenosinetriphosphatase", - "3.6.1.5 Apyrase", - "3.6.1.6 Nucleoside diphosphate phosphatase", - "3.6.1.7 Acylphosphatase", - "3.6.1.8 ATP diphosphatase", - "3.6.1.9 Nucleotide diphosphatase", - "3.6.1.10 Endopolyphosphatase", - "3.6.1.11 Exopolyphosphatase", - "3.6.1.12 dCTP diphosphatase", - "3.6.1.13 ADP-ribose diphosphatase", - "3.6.1.14 Adenosine-tetraphosphatase", - "3.6.1.15 Nucleoside-triphosphate phosphatase", - "3.6.1.16 CDP-glycerol diphosphatase", - "3.6.1.17 Bis(5'-nucleosyl)-tetraphosphatase (asymmetrical)", - "3.6.1.18 FAD diphosphatase", - "3.6.1.19 Nucleoside-triphosphate diphosphatase", - "3.6.1.20 5'-acylphosphoadenosine hydrolase", - "3.6.1.21 ADP-sugar diphosphatase", - "3.6.1.22 NAD(+) diphosphatase", - "3.6.1.23 dUTP diphosphatase", - "3.6.1.24 Nucleoside phosphoacylhydrolase", - "3.6.1.25 Triphosphatase", - "3.6.1.26 CDP-diacylglycerol diphosphatase", - "3.6.1.27 Undecaprenyl-diphosphate phosphatase", - "3.6.1.28 Thiamine-triphosphatase", - "3.6.1.29 Bis(5'-adenosyl)-triphosphatase", - "3.6.1.31 Phosphoribosyl-ATP diphosphatase", - "3.6.1.39 Thymidine-triphosphatase", - "3.6.1.40 Guanosine-5'-triphosphate,3'-diphosphate diphosphatase", - "3.6.1.41 Bis(5'-nucleosyl)-tetraphosphatase (symmetrical)", - "3.6.1.42 Guanosine-diphosphatase", - "3.6.1.43 Dolichyldiphosphatase", - "3.6.1.44 Oligosaccharide-diphosphodolichol diphosphatase", - "3.6.1.45 UDP-sugar diphosphatase", - "3.6.1.52 Diphosphoinositol-polyphosphate diphosphatase", - "3.6.1.53 Mn(2+)-dependent ADP-ribose/CDP-alcohol diphosphatase", - "3.6.1.54 UDP-2,3-diacylglucosamine diphosphatase", - "3.6.1.55 8-oxo-dGTP diphosphatase", - "3.6.1.56 2-hydroxy-dATP diphosphatase", - "3.6.1.57 UDP-2,4-diacetamido-2,4,6-trideoxy-beta-L-altropyranose hydrolase", - "3.6.1.58 8-oxo-dGDP phosphatase", - "3.6.1.59 5'-(N(7)-methyl 5'-triphosphoguanosine)-[mRNA] diphosphatase", - "3.6.1.60 Diadenosine hexaphosphate hydrolase (AMP-forming)", - "3.6.1.61 Diadenosine hexaphosphate hydrolase (ATP-forming)", - "3.6.1.62 5'-(N(7)-methylguanosine 5'-triphospho)-[mRNA] hydrolase", - "3.6.1.63 Alpha-D-ribose 1-methylphosphonate 5-triphosphate diphosphatase", - "3.6.1.64 Inosine diphosphate phosphatase", - "3.6.1.65 (d)CTP diphosphatase", - "3.6.1.66 XTP/dITP diphosphatase", - "3.6.1.67 Dihydroneopterin triphosphate diphosphatase", - "3.6.1.n1 D-tyrosyl-tRNA(Tyr) hydrolase", - "3.6.1.n2 L-cysteinyl-tRNA(Pro)", - "3.6.1.n3 L-cysteinyl-tRNA(Cys) hydrolase", - "3.6.2.1 Adenylylsulfatase", - "3.6.2.2 Phosphoadenylylsulfatase", - "3.6.3.1 Phospholipid-translocating ATPase", - "3.6.3.2 Magnesium-importing ATPase", - "3.6.3.3 Cadmium-exporting ATPase", - "3.6.3.4 Cu(2+)-exporting ATPase", - "3.6.3.5 Zinc-exporting ATPase", - "3.6.3.6 Proton-exporting ATPase", - "3.6.3.7 Sodium-exporting ATPase", - "3.6.3.8 Calcium-transporting ATPase", - "3.6.3.9 Sodium/potassium-exchanging ATPase", - "3.6.3.10 Hydrogen/potassium-exchanging ATPase", - "3.6.3.11 Chloride-transporting ATPase", - "3.6.3.12 Potassium-transporting ATPase", - "3.6.3.14 H(+)-transporting two-sector ATPase", - "3.6.3.15 Sodium-transporting two-sector ATPase", - "3.6.3.16 Arsenite-transporting ATPase", - "3.6.3.17 Monosaccharide-transporting ATPase", - "3.6.3.18 Oligosaccharide-transporting ATPase", - "3.6.3.19 Maltose-transporting ATPase", - "3.6.3.20 Glycerol-3-phosphate-transporting ATPase", - "3.6.3.21 Polar-amino-acid-transporting ATPase", - "3.6.3.22 Nonpolar-amino-acid-transporting ATPase", - "3.6.3.23 Oligopeptide-transporting ATPase", - "3.6.3.24 Nickel-transporting ATPase", - "3.6.3.25 Sulfate-transporting ATPase", - "3.6.3.26 Nitrate-transporting ATPase", - "3.6.3.27 Phosphate-transporting ATPase", - "3.6.3.28 Phosphonate-transporting ATPase", - "3.6.3.29 Molybdate-transporting ATPase", - "3.6.3.30 Fe(3+)-transporting ATPase", - "3.6.3.31 Polyamine-transporting ATPase", - "3.6.3.32 Quaternary-amine-transporting ATPase", - "3.6.3.33 Vitamin B12-transporting ATPase", - "3.6.3.34 Iron-chelate-transporting ATPase", - "3.6.3.35 Manganese-transporting ATPase", - "3.6.3.36 Taurine-transporting ATPase", - "3.6.3.37 Guanine-transporting ATPase", - "3.6.3.38 Capsular-polysaccharide-transporting ATPase", - "3.6.3.39 Lipopolysaccharide-transporting ATPase", - "3.6.3.40 Teichoic-acid-transporting ATPase", - "3.6.3.41 Heme-transporting ATPase", - "3.6.3.42 Beta-glucan-transporting ATPase", - "3.6.3.43 Peptide-transporting ATPase", - "3.6.3.44 Xenobiotic-transporting ATPase", - "3.6.3.46 Cadmium-transporting ATPase", - "3.6.3.47 Fatty-acyl-CoA-transporting ATPase", - "3.6.3.48 Alpha-factor-transporting ATPase", - "3.6.3.49 Channel-conductance-controlling ATPase", - "3.6.3.50 Protein-secreting ATPase", - "3.6.3.51 Mitochondrial protein-transporting ATPase", - "3.6.3.52 Chloroplast protein-transporting ATPase", - "3.6.3.53 Ag(+)-exporting ATPase", - "3.6.3.54 Cu(+) exporting ATPase", - "3.6.3.55 Tungstate-importing ATPase", - "3.6.4.1 Myosin ATPase", - "3.6.4.2 Dynein ATPase", - "3.6.4.3 Microtubule-severing ATPase", - "3.6.4.4 Plus-end-directed kinesin ATPase", - "3.6.4.5 Minus-end-directed kinesin ATPase", - "3.6.4.6 Vesicle-fusing ATPase", - "3.6.4.7 Peroxisome-assembly ATPase", - "3.6.4.8 Proteasome ATPase", - "3.6.4.9 Chaperonin ATPase", - "3.6.4.10 Non-chaperonin molecular chaperone ATPase", - "3.6.4.11 Nucleoplasmin ATPase", - "3.6.4.12 DNA helicase", - "3.6.4.13 RNA helicase", - "3.6.5.1 Heterotrimeric G-protein GTPase", - "3.6.5.2 Small monomeric GTPase", - "3.6.5.3 Protein-synthesizing GTPase", - "3.6.5.4 Signal-recognition-particle GTPase", - "3.6.5.5 Dynamin GTPase", - "3.6.5.6 Tubulin GTPase", - "3.6.5.n1 Elongation factor 4", - "3.7.1.1 Oxaloacetase", - "3.7.1.2 Fumarylacetoacetase", - "3.7.1.3 Kynureninase", - "3.7.1.4 Phloretin hydrolase", - "3.7.1.5 Acylpyruvate hydrolase", - "3.7.1.6 Acetylpyruvate hydrolase", - "3.7.1.7 Beta-diketone hydrolase", - "3.7.1.8 2,6-dioxo-6-phenylhexa-3-enoate hydrolase", - "3.7.1.9 2-hydroxymuconate-6-semialdehyde hydrolase", - "3.7.1.10 Cyclohexane-1,3-dione hydrolase", - "3.7.1.11 Cyclohexane-1,2-dione hydrolase", - "3.7.1.12 Cobalt-precorrin 5A hydrolase", - "3.7.1.13 2-hydroxy-6-oxo-6-(2-aminophenyl)hexa-2,4-dienoate hydrolase", - "3.7.1.14 2-hydroxy-6-oxonona-2,4-dienedioate hydrolase", - "3.7.1.17 4,5-9,10-diseco-3-hydroxy-5,9,17-trioxoandrosta-1(10),2-diene-4-oate hydrolase", - "3.7.1.18 6-oxocamphor hydrolase", - "3.7.1.19 2,6-dihydroxypseudooxynicotine hydrolase", - "3.7.1.20 3-fumarylpyruvate hydrolase", - "3.7.1.21 6-oxocyclohex-1-ene-1-carbonyl-CoA hydratase", - "3.7.1.22 3D-(3,5/4)-trihydroxycyclohexane-1,2-dione acylhydrolase (decyclizing)", - "3.7.1.23 Maleylpyruvate hydrolase", - "3.8.1.1 Alkylhalidase", - "3.8.1.2 (S)-2-haloacid dehalogenase", - "3.8.1.3 Haloacetate dehalogenase", - "3.8.1.5 Haloalkane dehalogenase", - "3.8.1.6 4-chlorobenzoate dehalogenase", - "3.8.1.7 4-chlorobenzoyl-CoA dehalogenase", - "3.8.1.8 Atrazine chlorohydrolase", - "3.8.1.9 (R)-2-haloacid dehalogenase", - "3.8.1.10 2-haloacid dehalogenase (configuration-inverting)", - "3.8.1.11 2-haloacid dehalogenase (configuration-retaining)", - "3.9.1.1 Phosphoamidase", - "3.9.1.2 Protein arginine phosphatase", - "3.9.1.3 Phosphohistidine phosphatase", - "3.10.1.1 N-sulfoglucosamine sulfohydrolase", - "3.10.1.2 Cyclamate sulfohydrolase", - "3.11.1.1 Phosphonoacetaldehyde hydrolase", - "3.11.1.2 Phosphonoacetate hydrolase", - "3.11.1.3 Phosphonopyruvate hydrolase", - "3.12.1.1 Trithionate hydrolase", - "3.13.1.1 UDP-sulfoquinovose synthase", - "3.13.1.3 2'-hydroxybiphenyl-2-sulfinate desulfinase", - "3.13.1.4 3-sulfinopropanoyl-CoA desulfinase", - "4.1.1.1 Pyruvate decarboxylase", - "4.1.1.2 Oxalate decarboxylase", - "4.1.1.3 Oxaloacetate decarboxylase", - "4.1.1.4 Acetoacetate decarboxylase", - "4.1.1.5 Acetolactate decarboxylase", - "4.1.1.6 Aconitate decarboxylase", - "4.1.1.7 Benzoylformate decarboxylase", - "4.1.1.8 Oxalyl-CoA decarboxylase", - "4.1.1.9 Malonyl-CoA decarboxylase", - "4.1.1.11 Aspartate 1-decarboxylase", - "4.1.1.12 Aspartate 4-decarboxylase", - "4.1.1.14 Valine decarboxylase", - "4.1.1.15 Glutamate decarboxylase", - "4.1.1.16 Hydroxyglutamate decarboxylase", - "4.1.1.17 Ornithine decarboxylase", - "4.1.1.18 Lysine decarboxylase", - "4.1.1.19 Arginine decarboxylase", - "4.1.1.20 Diaminopimelate decarboxylase", - "4.1.1.21 Phosphoribosylaminoimidazole carboxylase", - "4.1.1.22 Histidine decarboxylase", - "4.1.1.23 Orotidine-5'-phosphate decarboxylase", - "4.1.1.24 Aminobenzoate decarboxylase", - "4.1.1.25 Tyrosine decarboxylase", - "4.1.1.28 Aromatic-L-amino-acid decarboxylase", - "4.1.1.29 Sulfinoalanine decarboxylase", - "4.1.1.30 Pantothenoylcysteine decarboxylase", - "4.1.1.31 Phosphoenolpyruvate carboxylase", - "4.1.1.32 Phosphoenolpyruvate carboxykinase (GTP)", - "4.1.1.33 Diphosphomevalonate decarboxylase", - "4.1.1.34 Dehydro-L-gulonate decarboxylase", - "4.1.1.35 UDP-glucuronate decarboxylase", - "4.1.1.36 Phosphopantothenoylcysteine decarboxylase", - "4.1.1.37 Uroporphyrinogen decarboxylase", - "4.1.1.38 Phosphoenolpyruvate carboxykinase (diphosphate)", - "4.1.1.39 Ribulose-bisphosphate carboxylase", - "4.1.1.40 Hydroxypyruvate decarboxylase", - "4.1.1.41 Methylmalonyl-CoA decarboxylase", - "4.1.1.42 Carnitine decarboxylase", - "4.1.1.43 Phenylpyruvate decarboxylase", - "4.1.1.44 4-carboxymuconolactone decarboxylase", - "4.1.1.45 Aminocarboxymuconate-semialdehyde decarboxylase", - "4.1.1.46 o-pyrocatechuate decarboxylase", - "4.1.1.47 Tartronate-semialdehyde synthase", - "4.1.1.48 Indole-3-glycerol-phosphate synthase", - "4.1.1.49 Phosphoenolpyruvate carboxykinase (ATP)", - "4.1.1.50 Adenosylmethionine decarboxylase", - "4.1.1.51 3-hydroxy-2-methylpyridine-4,5-dicarboxylate 4-decarboxylase", - "4.1.1.52 6-methylsalicylate decarboxylase", - "4.1.1.53 Phenylalanine decarboxylase", - "4.1.1.54 Dihydroxyfumarate decarboxylase", - "4.1.1.55 4,5-dihydroxyphthalate decarboxylase", - "4.1.1.56 3-oxolaurate decarboxylase", - "4.1.1.57 Methionine decarboxylase", - "4.1.1.58 Orsellinate decarboxylase", - "4.1.1.59 Gallate decarboxylase", - "4.1.1.60 Stipitatonate decarboxylase", - "4.1.1.61 4-hydroxybenzoate decarboxylase", - "4.1.1.62 Gentisate decarboxylase", - "4.1.1.63 Protocatechuate decarboxylase", - "4.1.1.64 2,2-dialkylglycine decarboxylase (pyruvate)", - "4.1.1.65 Phosphatidylserine decarboxylase", - "4.1.1.66 Uracil-5-carboxylate decarboxylase", - "4.1.1.67 UDP-galacturonate decarboxylase", - "4.1.1.68 5-oxopent-3-ene-1,2,5-tricarboxylate decarboxylase", - "4.1.1.69 3,4-dihydroxyphthalate decarboxylase", - "4.1.1.70 Glutaconyl-CoA decarboxylase", - "4.1.1.71 2-oxoglutarate decarboxylase", - "4.1.1.72 Branched-chain-2-oxoacid decarboxylase", - "4.1.1.73 Tartrate decarboxylase", - "4.1.1.74 Indolepyruvate decarboxylase", - "4.1.1.75 5-guanidino-2-oxopentanoate decarboxylase", - "4.1.1.76 Arylmalonate decarboxylase", - "4.1.1.77 2-oxo-3-hexenedioate decarboxylase", - "4.1.1.78 Acetylenedicarboxylate decarboxylase", - "4.1.1.79 Sulfopyruvate decarboxylase", - "4.1.1.80 4-hydroxyphenylpyruvate decarboxylase", - "4.1.1.81 Threonine-phosphate decarboxylase", - "4.1.1.82 Phosphonopyruvate decarboxylase", - "4.1.1.83 4-hydroxyphenylacetate decarboxylase", - "4.1.1.84 D-dopachrome decarboxylase", - "4.1.1.85 3-dehydro-L-gulonate-6-phosphate decarboxylase", - "4.1.1.86 Diaminobutyrate decarboxylase", - "4.1.1.87 Malonyl-S-ACP decarboxylase", - "4.1.1.88 Biotin-independent malonate decarboxylase", - "4.1.1.89 Biotin-dependent malonate decarboxylase", - "4.1.1.90 Peptidyl-glutamate 4-carboxylase", - "4.1.1.91 Salicylate decarboxylase", - "4.1.1.92 Indole-3-carboxylate decarboxylase", - "4.1.1.93 Pyrrole-2-carboxylate decarboxylase", - "4.1.1.94 Ethylmalonyl-CoA decarboxylase", - "4.1.1.95 L-glutamyl-[BtrI acyl-carrier protein] decarboxylase", - "4.1.1.96 Carboxynorspermidine decarboxylase", - "4.1.1.97 2-oxo-4-hydroxy-4-carboxy-5-ureidoimidazoline decarboxylase", - "4.1.1.98 4-hydroxy-3-polyprenylbenzoate decarboxylase", - "4.1.1.99 Phosphomevalonate decarboxylase", - "4.1.1.100 Prephenate decarboxylase", - "4.1.1.101 Malolactic enzyme", - "4.1.1.102 Phenacrylate decarboxylase", - "4.1.2.2 Ketotetrose-phosphate aldolase", - "4.1.2.4 Deoxyribose-phosphate aldolase", - "4.1.2.5 L-threonine aldolase", - "4.1.2.8 Indole-3-glycerol-phosphate lyase", - "4.1.2.9 Phosphoketolase", - "4.1.2.10 (R)-mandelonitrile lyase", - "4.1.2.11 Hydroxymandelonitrile lyase", - "4.1.2.12 2-dehydropantoate aldolase", - "4.1.2.13 Fructose-bisphosphate aldolase", - "4.1.2.14 2-dehydro-3-deoxy-phosphogluconate aldolase", - "4.1.2.17 L-fuculose-phosphate aldolase", - "4.1.2.18 2-dehydro-3-deoxy-L-pentonate aldolase", - "4.1.2.19 Rhamnulose-1-phosphate aldolase", - "4.1.2.20 2-dehydro-3-deoxyglucarate aldolase", - "4.1.2.21 2-dehydro-3-deoxy-6-phosphogalactonate aldolase", - "4.1.2.22 Fructose-6-phosphate phosphoketolase", - "4.1.2.23 3-deoxy-D-manno-octulosonate aldolase", - "4.1.2.24 Dimethylaniline-N-oxide aldolase", - "4.1.2.25 Dihydroneopterin aldolase", - "4.1.2.26 Phenylserine aldolase", - "4.1.2.27 Sphinganine-1-phosphate aldolase", - "4.1.2.28 2-dehydro-3-deoxy-D-pentonate aldolase", - "4.1.2.29 5-dehydro-2-deoxyphosphogluconate aldolase", - "4.1.2.30 17-alpha-hydroxyprogesterone aldolase", - "4.1.2.32 Trimethylamine-oxide aldolase", - "4.1.2.33 Fucosterol-epoxide lyase", - "4.1.2.34 4-(2-carboxyphenyl)-2-oxobut-3-enoate aldolase", - "4.1.2.35 Propioin synthase", - "4.1.2.36 Lactate aldolase", - "4.1.2.38 Benzoin aldolase", - "4.1.2.40 Tagatose-bisphosphate aldolase", - "4.1.2.41 Vanillin synthase", - "4.1.2.42 D-threonine aldolase", - "4.1.2.43 3-hexulose-6-phosphate synthase", - "4.1.2.44 2,3-epoxybenzoyl-CoA dihydrolase", - "4.1.2.45 Trans-o-hydroxybenzylidenepyruvate hydratase-aldolase", - "4.1.2.46 Aliphatic (R)-hydroxynitrile lyase", - "4.1.2.47 (S)-hydroxynitrile lyase", - "4.1.2.48 Low-specificity L-threonine aldolase", - "4.1.2.49 L-allo-threonine aldolase", - "4.1.2.50 6-carboxytetrahydropterin synthase", - "4.1.2.51 2-dehydro-3-deoxy-D-gluconate aldolase", - "4.1.2.52 4-hydroxy-2-oxoheptanedioate aldolase", - "4.1.2.53 2-keto-3-deoxy-L-rhamnonate aldolase", - "4.1.2.54 L-threo-3-deoxy-hexylosonate aldolase", - "4.1.2.55 2-dehydro-3-deoxy-phosphogluconate/2-dehydro-3-deoxy-6-phosphogalactonate aldolase", - "4.1.2.56 2-amino-4,5-dihydroxy-6-oxo-7-(phosphonooxy)heptanoate synthase", - "4.1.2.57 Sulfofructosephosphate aldolase", - "4.1.2.58 2-dehydro-3,6-dideoxy-6-sulfogluconate aldolase", - "4.1.2.n2 2-hydroxyphytanoyl-CoA lyase", - "4.1.3.1 Isocitrate lyase", - "4.1.3.3 N-acetylneuraminate lyase", - "4.1.3.4 Hydroxymethylglutaryl-CoA lyase", - "4.1.3.6 Citrate (pro-3S)-lyase", - "4.1.3.13 Oxalomalate lyase", - "4.1.3.14 L-erythro-3-hydroxyaspartate aldolase", - "4.1.3.16 4-hydroxy-2-oxoglutarate aldolase", - "4.1.3.17 4-hydroxy-4-methyl-2-oxoglutarate aldolase", - "4.1.3.22 Citramalate lyase", - "4.1.3.24 Malyl-CoA lyase", - "4.1.3.25 (S)-citramalyl-CoA lyase", - "4.1.3.26 3-hydroxy-3-isohexenylglutaryl-CoA lyase", - "4.1.3.27 Anthranilate synthase", - "4.1.3.30 Methylisocitrate lyase", - "4.1.3.32 2,3-dimethylmalate lyase", - "4.1.3.34 Citryl-CoA lyase", - "4.1.3.35 (1-hydroxycyclohexan-1-yl)acetyl-CoA lyase", - "4.1.3.36 1,4-dihydroxy-2-naphthoyl-CoA synthase", - "4.1.3.38 Aminodeoxychorismate lyase", - "4.1.3.39 4-hydroxy-2-oxovalerate aldolase", - "4.1.3.40 Chorismate lyase", - "4.1.3.41 3-hydroxy-D-aspartate aldolase", - "4.1.3.42 (4S)-4-hydroxy-2-oxoglutarate aldolase", - "4.1.3.43 4-hydroxy-2-oxohexanoate aldolase", - "4.1.3.44 tRNA 4-demethylwyosine synthase (AdoMet-dependent)", - "4.1.3.45 3-hydroxybenzoate synthase", - "4.1.3.46 (R)-citramalyl-CoA lyase", - "4.1.99.1 Tryptophanase", - "4.1.99.2 Tyrosine phenol-lyase", - "4.1.99.3 Deoxyribodipyrimidine photo-lyase", - "4.1.99.5 Aldehyde oxygenase (deformylating)", - "4.1.99.11 Benzylsuccinate synthase", - "4.1.99.12 3,4-dihydroxy-2-butanone-4-phosphate synthase", - "4.1.99.13 (6-4)DNA photolyase", - "4.1.99.14 Spore photoproduct lyase", - "4.1.99.16 Geosmin synthase", - "4.1.99.17 Phosphomethylpyrimidine synthase", - "4.1.99.18 Cyclic pyranopterin phosphate synthase", - "4.1.99.19 2-iminoacetate synthase", - "4.1.99.20 3-amino-4-hydroxybenzoate synthase", - "4.2.1.1 Carbonate dehydratase", - "4.2.1.2 Fumarate hydratase", - "4.2.1.3 Aconitate hydratase", - "4.2.1.5 Arabinonate dehydratase", - "4.2.1.6 Galactonate dehydratase", - "4.2.1.7 Altronate dehydratase", - "4.2.1.8 Mannonate dehydratase", - "4.2.1.9 Dihydroxy-acid dehydratase", - "4.2.1.10 3-dehydroquinate dehydratase", - "4.2.1.11 Phosphopyruvate hydratase", - "4.2.1.12 Phosphogluconate dehydratase", - "4.2.1.17 Enoyl-CoA hydratase", - "4.2.1.18 Methylglutaconyl-CoA hydratase", - "4.2.1.19 Imidazoleglycerol-phosphate dehydratase", - "4.2.1.20 Tryptophan synthase", - "4.2.1.22 Cystathionine beta-synthase", - "4.2.1.24 Porphobilinogen synthase", - "4.2.1.25 L-arabinonate dehydratase", - "4.2.1.27 Acetylenecarboxylate hydratase", - "4.2.1.28 Propanediol dehydratase", - "4.2.1.30 Glycerol dehydratase", - "4.2.1.31 Maleate hydratase", - "4.2.1.32 L(+)-tartrate dehydratase", - "4.2.1.33 3-isopropylmalate dehydratase", - "4.2.1.34 (S)-2-methylmalate dehydratase", - "4.2.1.35 (R)-2-methylmalate dehydratase", - "4.2.1.36 Homoaconitate hydratase", - "4.2.1.39 Gluconate dehydratase", - "4.2.1.40 Glucarate dehydratase", - "4.2.1.41 5-dehydro-4-deoxyglucarate dehydratase", - "4.2.1.42 Galactarate dehydratase", - "4.2.1.43 2-dehydro-3-deoxy-L-arabinonate dehydratase", - "4.2.1.44 Myo-inosose-2 dehydratase", - "4.2.1.45 CDP-glucose 4,6-dehydratase", - "4.2.1.46 dTDP-glucose 4,6-dehydratase", - "4.2.1.47 GDP-mannose 4,6-dehydratase", - "4.2.1.48 D-glutamate cyclase", - "4.2.1.49 Urocanate hydratase", - "4.2.1.50 Pyrazolylalanine synthase", - "4.2.1.51 Prephenate dehydratase", - "4.2.1.53 Oleate hydratase", - "4.2.1.54 Lactoyl-CoA dehydratase", - "4.2.1.55 3-hydroxybutyryl-CoA dehydratase", - "4.2.1.56 Itaconyl-CoA hydratase", - "4.2.1.57 Isohexenylglutaconyl-CoA hydratase", - "4.2.1.59 3-hydroxyacyl-[acyl-carrier-protein] dehydratase", - "4.2.1.62 5-alpha-hydroxysteroid dehydratase", - "4.2.1.65 3-cyanoalanine hydratase", - "4.2.1.66 Cyanide hydratase", - "4.2.1.67 D-fuconate dehydratase", - "4.2.1.68 L-fuconate dehydratase", - "4.2.1.69 Cyanamide hydratase", - "4.2.1.70 Pseudouridylate synthase", - "4.2.1.73 Protoaphin-aglucone dehydratase (cyclizing)", - "4.2.1.74 Long-chain-enoyl-CoA hydratase", - "4.2.1.75 Uroporphyrinogen-III synthase", - "4.2.1.76 UDP-glucose 4,6-dehydratase", - "4.2.1.77 Trans-L-3-hydroxyproline dehydratase", - "4.2.1.78 (S)-norcoclaurine synthase", - "4.2.1.79 2-methylcitrate dehydratase", - "4.2.1.80 2-oxopent-4-enoate hydratase", - "4.2.1.81 D(-)-tartrate dehydratase", - "4.2.1.82 Xylonate dehydratase", - "4.2.1.83 4-oxalmesaconate hydratase", - "4.2.1.84 Nitrile hydratase", - "4.2.1.85 Dimethylmaleate hydratase", - "4.2.1.87 Octopamine dehydratase", - "4.2.1.88 (R)-synephrine", - "4.2.1.90 L-rhamnonate dehydratase", - "4.2.1.91 Arogenate dehydratase", - "4.2.1.92 Hydroperoxide dehydratase", - "4.2.1.93 ATP-dependent NAD(P)H-hydrate dehydratase", - "4.2.1.94 Scytalone dehydratase", - "4.2.1.95 Kievitone hydratase", - "4.2.1.96 4a-hydroxytetrahydrobiopterin dehydratase", - "4.2.1.97 Phaseollidin hydratase", - "4.2.1.98 16-alpha-hydroxyprogesterone dehydratase", - "4.2.1.99 2-methylisocitrate dehydratase", - "4.2.1.100 Cyclohexa-1,5-dienecarbonyl-CoA hydratase", - "4.2.1.101 Trans-feruloyl-CoA hydratase", - "4.2.1.103 Cyclohexyl-isocyanide hydratase", - "4.2.1.104 Cyanase", - "4.2.1.105 2-hydroxyisoflavanone dehydratase", - "4.2.1.106 Bile-acid 7-alpha-dehydratase", - "4.2.1.107 3-alpha,7-alpha,12-alpha-trihydroxy-5-beta-cholest-24-enoyl-CoA hydratase", - "4.2.1.108 Ectoine synthase", - "4.2.1.109 Methylthioribulose 1-phosphate dehydratase", - "4.2.1.110 Aldos-2-ulose dehydratase", - "4.2.1.111 1,5-anhydro-D-fructose dehydratase", - "4.2.1.112 Acetylene hydratase", - "4.2.1.113 o-succinylbenzoate synthase", - "4.2.1.114 Methanogen homoaconitase", - "4.2.1.115 UDP-N-acetylglucosamine 4,6-dehydratase (inverting)", - "4.2.1.116 3-hydroxypropionyl-CoA dehydratase", - "4.2.1.117 2-methylcitrate dehydratase (2-methyl-trans-aconitate forming)", - "4.2.1.118 3-dehydroshikimate dehydratase", - "4.2.1.119 Enoyl-CoA hydratase 2", - "4.2.1.120 4-hydroxybutanoyl-CoA dehydratase", - "4.2.1.121 Colneleate synthase", - "4.2.1.122 Tryptophan synthase (indole-salvaging)", - "4.2.1.123 Tetrahymanol synthase", - "4.2.1.124 Arabidiol synthase", - "4.2.1.125 Dammarenediol II synthase", - "4.2.1.126 N-acetylmuramic acid 6-phosphate etherase", - "4.2.1.127 Linalool dehydratase", - "4.2.1.128 Lupan-3-beta,20-diol synthase", - "4.2.1.129 Squalene--hopanol cyclase", - "4.2.1.130 D-lactate dehydratase", - "4.2.1.131 Carotenoid 1,2-hydratase", - "4.2.1.132 2-hydroxyhexa-2,4-dienoate hydratase", - "4.2.1.133 Copal-8-ol diphosphate hydratase", - "4.2.1.134 Very-long-chain (3R)-3-hydroxyacyl-CoA dehydratase", - "4.2.1.135 UDP-N-acetylglucosamine 4,6-dehydratase (configuration-retaining)", - "4.2.1.136 ADP-dependent NAD(P)H-hydrate dehydratase", - "4.2.1.137 Sporulenol synthase", - "4.2.1.138 (+)-caryolan-1-ol synthase", - "4.2.1.139 Medicarpin synthase", - "4.2.1.140 Gluconate/galactonate dehydratase", - "4.2.1.141 2-dehydro-3-deoxy-D-arabinonate dehydratase", - "4.2.1.142 5'-oxoaverantin cyclase", - "4.2.1.143 Versicolorin B synthase", - "4.2.1.144 3-amino-5-hydroxybenzoate synthase", - "4.2.1.145 Capreomycidine synthase", - "4.2.1.146 L-galactonate dehydratase", - "4.2.1.147 5,6,7,8-tetrahydromethanopterin hydro-lyase", - "4.2.1.148 2-methylfumaryl-CoA hydratase", - "4.2.1.149 Crotonobetainyl-CoA hydratase", - "4.2.1.150 Short-chain-enoyl-CoA hydratase", - "4.2.1.151 Chorismate dehydratase", - "4.2.1.152 Hydroperoxy icosatetraenoate dehydratase", - "4.2.1.153 3-methylfumaryl-CoA hydratase", - "4.2.1.154 Tetracenomycin F2 cyclase", - "4.2.1.155 Methylthioacryloyl-CoA hydratase", - "4.2.1.156 L-talarate dehydratase", - "4.2.1.157 (R)-2-hydroxyisocaproyl-CoA dehydratase", - "4.2.1.158 Galactarate dehydratase (D-threo-forming)", - "4.2.1.159 dTDP-4-dehydro-6-deoxy-alpha-D-glucopyranose 2,3-dehydratase", - "4.2.1.160 2,5-diamino-6-(5-phospho-D-ribosylamino)pyrimidin-4(3H)-one isomerase/dehydratase", - "4.2.1.161 Bisanhydrobacterioruberin hydratase", - "4.2.1.162 6-deoxy-6-sulfo-D-gluconate dehydratase", - "4.2.1.163 2-oxo-hept-4-ene-1,7-dioate hydratase", - "4.2.2.1 Hyaluronate lyase", - "4.2.2.2 Pectate lyase", - "4.2.2.3 Mannuronate-specific alginate lyase", - "4.2.2.5 Chondroitin AC lyase", - "4.2.2.6 Oligogalacturonide lyase", - "4.2.2.7 Heparin lyase", - "4.2.2.8 Heparin-sulfate lyase", - "4.2.2.9 Pectate disaccharide-lyase", - "4.2.2.10 Pectin lyase", - "4.2.2.11 Guluronate-specific alginate lyase", - "4.2.2.12 Xanthan lyase", - "4.2.2.13 Exo-(1->4)-alpha-D-glucan lyase", - "4.2.2.14 Glucuronan lyase", - "4.2.2.15 Anhydrosialidase", - "4.2.2.16 Levan fructotransferase (DFA-IV-forming)", - "4.2.2.17 Inulin fructotransferase (DFA-I-forming)", - "4.2.2.18 Inulin fructotransferase (DFA-III-forming)", - "4.2.2.19 Chondroitin B lyase", - "4.2.2.20 Chondroitin-sulfate-ABC endolyase", - "4.2.2.21 Chondroitin-sulfate-ABC exolyase", - "4.2.2.22 Pectate trisaccharide-lyase", - "4.2.2.23 Rhamnogalacturonan endolyase", - "4.2.2.24 Rhamnogalacturonan exolyase", - "4.2.2.25 Gellan lyase", - "4.2.2.26 Oligo-alginate lyase", - "4.2.2.n1 Peptidoglycan lytic exotransglycosylase", - "4.2.2.n2 Peptidoglycan lytic endotransglycosylase", - "4.2.3.1 Threonine synthase", - "4.2.3.2 Ethanolamine-phosphate phospho-lyase", - "4.2.3.3 Methylglyoxal synthase", - "4.2.3.4 3-dehydroquinate synthase", - "4.2.3.5 Chorismate synthase", - "4.2.3.6 Trichodiene synthase", - "4.2.3.7 Pentalenene synthase", - "4.2.3.8 Casbene synthase", - "4.2.3.9 Aristolochene synthase", - "4.2.3.10 (-)-endo-fenchol synthase", - "4.2.3.11 Sabinene-hydrate synthase", - "4.2.3.12 6-pyruvoyltetrahydropterin synthase", - "4.2.3.13 (+)-delta-cadinene synthase", - "4.2.3.15 Myrcene synthase", - "4.2.3.16 (4S)-limonene synthase", - "4.2.3.17 Taxadiene synthase", - "4.2.3.18 Abieta-7,13-diene synthase", - "4.2.3.19 Ent-kaurene synthase", - "4.2.3.20 (R)-limonene synthase", - "4.2.3.21 Vetispiradiene synthase", - "4.2.3.22 Germacradienol synthase", - "4.2.3.23 Germacrene-A synthase", - "4.2.3.24 Amorpha-4,11-diene synthase", - "4.2.3.25 S-linalool synthase", - "4.2.3.26 R-linalool synthase", - "4.2.3.27 Isoprene synthase", - "4.2.3.28 Ent-cassa-12,15-diene synthase", - "4.2.3.29 Ent-sandaracopimaradiene synthase", - "4.2.3.30 Ent-pimara-8(14),15-diene synthase", - "4.2.3.31 Ent-pimara-9(11),15-diene synthase", - "4.2.3.32 Levopimaradiene synthase", - "4.2.3.33 Stemar-13-ene synthase", - "4.2.3.34 Stemod-13(17)-ene synthase", - "4.2.3.35 Syn-pimara-7,15-diene synthase", - "4.2.3.36 Terpentetriene synthase", - "4.2.3.37 Epi-isozizaene synthase", - "4.2.3.38 Alpha-bisabolene synthase", - "4.2.3.39 Epi-cedrol synthase", - "4.2.3.40 (Z)-gamma-bisabolene synthase", - "4.2.3.41 Elisabethatriene synthase", - "4.2.3.42 Aphidicolan-16-beta-ol synthase", - "4.2.3.43 Fusicocca-2,10(14)-diene synthase", - "4.2.3.44 Isopimara-7,15-diene synthase", - "4.2.3.45 Phyllocladan-16-alpha-ol synthase", - "4.2.3.46 Alpha-farnesene synthase", - "4.2.3.47 Beta-farnesene synthase", - "4.2.3.48 (3S,6E)-nerolidol synthase", - "4.2.3.49 (3R,6E)-nerolidol synthase", - "4.2.3.50 (+)-alpha-santalene synthase ((2Z,6Z)-farnesyl diphosphate cyclizing)", - "4.2.3.51 Beta-phellandrene synthase (neryl-diphosphate-cyclizing)", - "4.2.3.52 (4S)-beta-phellandrene synthase (geranyl-diphosphate-cyclizing)", - "4.2.3.53 (+)-endo-beta-bergamotene synthase ((2Z,6Z)-farnesyl diphosphate cyclizing)", - "4.2.3.54 (-)-endo-alpha-bergamotene synthase ((2Z,6Z)-farnesyl diphosphate cyclizing)", - "4.2.3.55 (S)-beta-bisabolene synthase", - "4.2.3.56 Gamma-humulene synthase", - "4.2.3.57 (-)-beta-caryophyllene synthase", - "4.2.3.58 Longifolene synthase", - "4.2.3.59 (E)-gamma-bisabolene synthase", - "4.2.3.60 Germacrene C synthase", - "4.2.3.61 5-epiaristolochene synthase", - "4.2.3.62 (-)-gamma-cadinene synthase ((2Z,6E)-farnesyl diphosphate cyclizing)", - "4.2.3.63 (+)-cubenene synthase", - "4.2.3.64 (+)-epicubenol synthase", - "4.2.3.65 Zingiberene synthase", - "4.2.3.66 Beta-selinene cyclase", - "4.2.3.67 Cis-muuroladiene synthase", - "4.2.3.68 Beta-eudesmol synthase", - "4.2.3.69 (+)-alpha-barbatene synthase", - "4.2.3.70 Patchoulol synthase", - "4.2.3.71 (E,E)-germacrene B synthase", - "4.2.3.72 Alpha-gurjunene synthase", - "4.2.3.73 Valencene synthase", - "4.2.3.74 Presilphiperfolanol synthase", - "4.2.3.75 (-)-germacrene D synthase", - "4.2.3.76 (+)-delta-selinene synthase", - "4.2.3.77 (+)-germacrene D synthase", - "4.2.3.78 Beta-chamigrene synthase", - "4.2.3.79 Thujopsene synthase", - "4.2.3.80 Alpha-longipinene synthase", - "4.2.3.81 Exo-alpha-bergamotene synthase", - "4.2.3.82 Alpha-santalene synthase", - "4.2.3.83 Beta-santalene synthase", - "4.2.3.84 10-epi-gamma-eudesmol synthase", - "4.2.3.85 Alpha-eudesmol synthase", - "4.2.3.86 7-epi-alpha-selinene synthase", - "4.2.3.87 Alpha-guaiene synthase", - "4.2.3.88 Viridiflorene synthase", - "4.2.3.89 (+)-beta-caryophyllene synthase", - "4.2.3.90 5-epi-alpha-selinene synthase", - "4.2.3.91 Cubebol synthase", - "4.2.3.92 (+)-gamma-cadinene synthase", - "4.2.3.93 Delta-guaiene synthase", - "4.2.3.94 Gamma-curcumene synthase", - "4.2.3.95 (-)-alpha-cuprenene synthase", - "4.2.3.96 Avermitilol synthase", - "4.2.3.97 (-)-delta-cadinene synthase", - "4.2.3.98 (+)-T-muurolol synthase", - "4.2.3.99 Labdatriene synthase", - "4.2.3.100 Bicyclogermacrene synthase", - "4.2.3.101 7-epi-sesquithujene synthase", - "4.2.3.102 Sesquithujene synthase", - "4.2.3.103 Ent-isokaurene synthase", - "4.2.3.104 Alpha-humulene synthase", - "4.2.3.105 Tricyclene synthase", - "4.2.3.106 (E)-beta-ocimene synthase", - "4.2.3.107 (+)-car-3-ene synthase", - "4.2.3.108 1,8-cineole synthase", - "4.2.3.109 (-)-sabinene synthase", - "4.2.3.110 (+)-sabinene synthase", - "4.2.3.111 (-)-alpha-terpineol synthase", - "4.2.3.112 (+)-alpha-terpineol synthase", - "4.2.3.113 Terpinolene synthase", - "4.2.3.114 Gamma-terpinene synthase", - "4.2.3.115 Alpha-terpinene synthase", - "4.2.3.116 (+)-camphene synthase", - "4.2.3.117 (-)-camphene synthase", - "4.2.3.118 2-methylisoborneol synthase", - "4.2.3.119 (-)-alpha-pinene synthase", - "4.2.3.120 (-)-beta-pinene synthase", - "4.2.3.121 (+)-alpha-pinene synthase", - "4.2.3.122 (+)-beta-pinene synthase", - "4.2.3.123 Beta-sesquiphellandrene synthase", - "4.2.3.124 2-deoxy-scyllo-inosose synthase", - "4.2.3.125 Alpha-muurolene synthase", - "4.2.3.126 Gamma-muurolene synthase", - "4.2.3.127 Beta-copaene synthase", - "4.2.3.128 Beta-cubebene synthase", - "4.2.3.129 (+)-sativene synthase", - "4.2.3.130 Tetraprenyl-beta-curcumene synthase", - "4.2.3.131 Miltiradiene synthase", - "4.2.3.132 Neoabietadiene synthase", - "4.2.3.133 Alpha-copaene synthase", - "4.2.3.134 5-phosphonooxy-L-lysine phospho-lyase", - "4.2.3.135 Delta(6)-protoilludene synthase", - "4.2.3.136 Alpha-isocomene synthase", - "4.2.3.137 (E)-2-epi-beta-caryophyllene synthase", - "4.2.3.138 (+)-epi-alpha-bisabolol synthase", - "4.2.3.139 Valerena-4,7(11)-diene synthase", - "4.2.3.140 Cis-abienol synthase", - "4.2.3.141 Sclareol synthase", - "4.2.3.142 7-epizingiberene synthase ((2Z,6Z)-farnesyl diphosphate cyclizing)", - "4.2.3.143 Kunzeaol synthase", - "4.2.3.144 Geranyllinalool synthase", - "4.2.3.145 Ophiobolin F synthase", - "4.2.3.146 Cyclooctat-9-en-7-ol synthase", - "4.2.3.147 Pimaradiene synthase", - "4.2.3.148 Cembrene C synthase", - "4.2.3.149 Nephthenol synthase", - "4.2.3.150 Cembrene A synthase", - "4.2.3.151 Pentamethylcyclopentadecatrienol synthase", - "4.2.3.152 2-epi-5-epi-valiolone synthase", - "4.2.3.153 (5-formylfuran-3-yl)methyl phosphate synthase", - "4.2.3.n2 Delta-selinene synthase", - "4.2.3.n11 Selinene synthase", - "4.2.99.12 Carboxymethyloxysuccinate lyase", - "4.2.99.18 DNA-(apurinic or apyrimidinic site) lyase", - "4.2.99.20 2-succinyl-6-hydroxy-2,4-cyclohexadiene-1-carboxylate synthase", - "4.2.99.21 Isochorismate lyase", - "4.2.99.22 Tuliposide A-converting enzyme", - "4.2.99.23 Tuliposide B-converting enzyme", - "4.3.1.1 Aspartate ammonia-lyase", - "4.3.1.2 Methylaspartate ammonia-lyase", - "4.3.1.3 Histidine ammonia-lyase", - "4.3.1.4 Formimidoyltetrahydrofolate cyclodeaminase", - "4.3.1.6 Beta-alanyl-CoA ammonia-lyase", - "4.3.1.7 Ethanolamine ammonia-lyase", - "4.3.1.9 Glucosaminate ammonia-lyase", - "4.3.1.10 Serine-sulfate ammonia-lyase", - "4.3.1.12 Ornithine cyclodeaminase", - "4.3.1.13 Carbamoyl-serine ammonia-lyase", - "4.3.1.14 3-aminobutyryl-CoA ammonia-lyase", - "4.3.1.15 Diaminopropionate ammonia-lyase", - "4.3.1.16 Threo-3-hydroxy-L-aspartate ammonia-lyase", - "4.3.1.17 L-serine ammonia-lyase", - "4.3.1.18 D-serine ammonia-lyase", - "4.3.1.19 Threonine ammonia-lyase", - "4.3.1.20 Erythro-3-hydroxy-L-aspartate ammonia-lyase", - "4.3.1.22 3,4-dihydroxyphenylalanine reductive deaminase", - "4.3.1.23 Tyrosine ammonia-lyase", - "4.3.1.24 Phenylalanine ammonia-lyase", - "4.3.1.25 Phenylalanine/tyrosine ammonia-lyase", - "4.3.1.27 Threo-3-hydroxy-D-aspartate ammonia-lyase", - "4.3.1.28 L-lysine cyclodeaminase", - "4.3.1.29 D-glucosaminate-6-phosphate ammonia lyase", - "4.3.1.30 dTDP-4-amino-4,6-dideoxy-D-glucose ammonia-lyase", - "4.3.2.1 Argininosuccinate lyase", - "4.3.2.2 Adenylosuccinate lyase", - "4.3.2.3 Ureidoglycolate lyase", - "4.3.2.4 Purine imidazole-ring cyclase", - "4.3.2.5 Peptidylamidoglycolate lyase", - "4.3.2.6 Gamma-L-glutamyl-butirosin B gamma-glutamyl cyclotransferase", - "4.3.3.1 3-ketovalidoxylamine C-N-lyase", - "4.3.3.2 Strictosidine synthase", - "4.3.3.3 Deacetylisoipecoside synthase", - "4.3.3.4 Deacetylipecoside synthase", - "4.3.3.5 4'-demethylrebeccamycin synthase", - "4.3.3.6 Pyridoxal 5'-phosphate synthase (glutamine hydrolyzing)", - "4.3.3.7 4-hydroxy-tetrahydrodipicolinate synthase", - "4.3.99.2 Carboxybiotin decarboxylase", - "4.3.99.3 7-carboxy-7-deazaguanine synthase", - "4.3.99.4 Choline trimethylamine-lyase", - "4.4.1.1 Cystathionine gamma-lyase", - "4.4.1.2 Homocysteine desulfhydrase", - "4.4.1.3 Dimethylpropiothetin dethiomethylase", - "4.4.1.4 Alliin lyase", - "4.4.1.5 Lactoylglutathione lyase", - "4.4.1.6 S-alkylcysteine lyase", - "4.4.1.8 Cystathionine beta-lyase", - "4.4.1.9 L-3-cyanoalanine synthase", - "4.4.1.10 Cysteine lyase", - "4.4.1.11 Methionine gamma-lyase", - "4.4.1.13 Cysteine-S-conjugate beta-lyase", - "4.4.1.14 1-aminocyclopropane-1-carboxylate synthase", - "4.4.1.15 D-cysteine desulfhydrase", - "4.4.1.16 Selenocysteine lyase", - "4.4.1.17 Holocytochrome-c synthase", - "4.4.1.19 Phosphosulfolactate synthase", - "4.4.1.20 Leukotriene-C(4) synthase", - "4.4.1.21 S-ribosylhomocysteine lyase", - "4.4.1.22 S-(hydroxymethyl)glutathione synthase", - "4.4.1.23 2-hydroxypropyl-CoM lyase", - "4.4.1.24 (2R)-sulfolactate sulfo-lyase", - "4.4.1.25 L-cysteate sulfo-lyase", - "4.4.1.26 Olivetolic acid cyclase", - "4.4.1.27 Carbon disulfide lyase", - "4.4.1.28 L-cysteine desulfidase", - "4.4.1.29 Phycobiliprotein cysteine-84 phycobilin lyase", - "4.4.1.30 Phycobiliprotein beta-cysteine-155 phycobilin lyase", - "4.4.1.31 Phycoerythrocyanin alpha-cysteine-84 phycoviolobilin lyase/isomerase", - "4.4.1.32 C-phycocyanin alpha-cysteine-84 phycocyanobilin lyase", - "4.4.1.33 R-phycocyanin alpha-cysteine-84 phycourobilin lyase/isomerase", - "4.5.1.1 DDT-dehydrochlorinase", - "4.5.1.2 3-chloro-D-alanine dehydrochlorinase", - "4.5.1.3 Dichloromethane dehalogenase", - "4.5.1.4 L-2-amino-4-chloropent-4-enoate dehydrochlorinase", - "4.5.1.5 S-carboxymethylcysteine synthase", - "4.6.1.1 Adenylate cyclase", - "4.6.1.2 Guanylate cyclase", - "4.6.1.6 Cytidylate cyclase", - "4.6.1.12 2-C-methyl-D-erythritol 2,4-cyclodiphosphate synthase", - "4.6.1.13 Phosphatidylinositol diacylglycerol-lyase", - "4.6.1.14 Glycosylphosphatidylinositol diacylglycerol-lyase", - "4.6.1.15 FAD-AMP lyase (cyclizing)", - "4.6.1.16 tRNA-intron lyase", - "4.7.1.1 Alpha-D-ribose 1-methylphosphonate 5-phosphate C-P-lyase", - "4.99.1.1 Protoporphyrin ferrochelatase", - "4.99.1.2 Alkylmercury lyase", - "4.99.1.3 Sirohydrochlorin cobaltochelatase", - "4.99.1.4 Sirohydrochlorin ferrochelatase", - "4.99.1.5 Aliphatic aldoxime dehydratase", - "4.99.1.6 Indoleacetaldoxime dehydratase", - "4.99.1.7 Phenylacetaldoxime dehydratase", - "4.99.1.8 Heme ligase", - "5.1.1.1 Alanine racemase", - "5.1.1.2 Methionine racemase", - "5.1.1.3 Glutamate racemase", - "5.1.1.4 Proline racemase", - "5.1.1.5 Lysine racemase", - "5.1.1.6 Threonine racemase", - "5.1.1.7 Diaminopimelate epimerase", - "5.1.1.8 4-hydroxyproline epimerase", - "5.1.1.9 Arginine racemase", - "5.1.1.10 Amino-acid racemase", - "5.1.1.11 Phenylalanine racemase (ATP-hydrolyzing)", - "5.1.1.12 Ornithine racemase", - "5.1.1.13 Aspartate racemase", - "5.1.1.14 Nocardicin-A epimerase", - "5.1.1.15 2-aminohexano-6-lactam racemase", - "5.1.1.16 Protein-serine epimerase", - "5.1.1.17 Isopenicillin-N epimerase", - "5.1.1.18 Serine racemase", - "5.1.1.19 O-ureido-serine racemase", - "5.1.1.20 L-Ala-D/L-Glu epimerase", - "5.1.1.21 Isoleucine 2-epimerase", - "5.1.2.1 Lactate racemase", - "5.1.2.2 Mandelate racemase", - "5.1.2.3 3-hydroxybutyryl-CoA epimerase", - "5.1.2.4 Acetoin racemase", - "5.1.2.5 Tartrate epimerase", - "5.1.2.6 Isocitrate epimerase", - "5.1.3.1 Ribulose-phosphate 3-epimerase", - "5.1.3.2 UDP-glucose 4-epimerase", - "5.1.3.3 Aldose 1-epimerase", - "5.1.3.4 L-ribulose-5-phosphate 4-epimerase", - "5.1.3.5 UDP-arabinose 4-epimerase", - "5.1.3.6 UDP-glucuronate 4-epimerase", - "5.1.3.7 UDP-N-acetylglucosamine 4-epimerase", - "5.1.3.8 N-acylglucosamine 2-epimerase", - "5.1.3.9 N-acylglucosamine-6-phosphate 2-epimerase", - "5.1.3.10 CDP-paratose 2-epimerase", - "5.1.3.11 Cellobiose epimerase", - "5.1.3.12 UDP-glucuronate 5'-epimerase", - "5.1.3.13 dTDP-4-dehydrorhamnose 3,5-epimerase", - "5.1.3.14 UDP-N-acetylglucosamine 2-epimerase (non-hydrolyzing)", - "5.1.3.15 Glucose-6-phosphate 1-epimerase", - "5.1.3.16 UDP-glucosamine 4-epimerase", - "5.1.3.17 Heparosan-N-sulfate-glucuronate 5-epimerase", - "5.1.3.18 GDP-mannose 3,5-epimerase", - "5.1.3.19 Chondroitin-glucuronate 5-epimerase", - "5.1.3.20 ADP-glyceromanno-heptose 6-epimerase", - "5.1.3.21 Maltose epimerase", - "5.1.3.22 L-ribulose-5-phosphate 3-epimerase", - "5.1.3.23 UDP-2,3-diacetamido-2,3-dideoxyglucuronic acid 2-epimerase", - "5.1.3.24 N-acetylneuraminate epimerase", - "5.1.3.25 dTDP-L-rhamnose 4-epimerase", - "5.1.3.26 N-acetyl-alpha-D-glucosaminyl-diphospho-ditrans,octacis-undecaprenol 4-epimerase", - "5.1.3.27 dTDP-4-dehydro-6-deoxy-D-glucose 3-epimerase", - "5.1.3.28 UDP-N-acetyl-L-fucosamine synthase", - "5.1.3.29 L-fucose mutarotase", - "5.1.3.30 D-psicose 3-epimerase", - "5.1.3.31 D-tagatose 3-epimerase", - "5.1.3.32 L-rhamnose mutarotase", - "5.1.3.33 2-epi-5-epi-valiolone epimerase", - "5.1.3.34 Monoglucosyldiacylglycerol epimerase", - "5.1.3.35 2-epi-5-epi-valiolone 7-phosphate 2-epimerase", - "5.1.3.36 Heparosan-glucuronate 5-epimerase", - "5.1.3.37 Mannuronan 5-epimerase", - "5.1.99.1 Methylmalonyl-CoA epimerase", - "5.1.99.2 16-hydroxysteroid epimerase", - "5.1.99.3 Allantoin racemase", - "5.1.99.4 Alpha-methylacyl-CoA racemase", - "5.1.99.5 Hydantoin racemase", - "5.1.99.6 NAD(P)H-hydrate epimerase", - "5.1.99.7 Dihydroneopterin triphosphate 2'-epimerase", - "5.1.99.8 7,8-dihydroneopterin epimerase", - "5.2.1.1 Maleate isomerase", - "5.2.1.2 Maleylacetoacetate isomerase", - "5.2.1.4 Maleylpyruvate isomerase", - "5.2.1.5 Linoleate isomerase", - "5.2.1.6 Furylfuramide isomerase", - "5.2.1.8 Peptidylprolyl isomerase", - "5.2.1.9 Farnesol 2-isomerase", - "5.2.1.10 2-chloro-4-carboxymethylenebut-2-en-1,4-olide isomerase", - "5.2.1.12 Zeta-carotene isomerase", - "5.2.1.13 Prolycopene isomerase", - "5.2.1.14 Beta-carotene isomerase", - "5.3.1.1 Triose-phosphate isomerase", - "5.3.1.3 D-arabinose isomerase", - "5.3.1.4 L-arabinose isomerase", - "5.3.1.5 Xylose isomerase", - "5.3.1.6 Ribose-5-phosphate isomerase", - "5.3.1.7 Mannose isomerase", - "5.3.1.8 Mannose-6-phosphate isomerase", - "5.3.1.9 Glucose-6-phosphate isomerase", - "5.3.1.12 Glucuronate isomerase", - "5.3.1.13 Arabinose-5-phosphate isomerase", - "5.3.1.14 L-rhamnose isomerase", - "5.3.1.15 D-lyxose ketol-isomerase", - "5.3.1.16 1-(5-phosphoribosyl)-5-((5-phosphoribosylamino)methylideneamino)imidazole-4-carboxamide isomerase", - "5.3.1.17 5-dehydro-4-deoxy-D-glucuronate isomerase", - "5.3.1.20 Ribose isomerase", - "5.3.1.21 Corticosteroid side-chain-isomerase", - "5.3.1.22 Hydroxypyruvate isomerase", - "5.3.1.23 S-methyl-5-thioribose-1-phosphate isomerase", - "5.3.1.24 Phosphoribosylanthranilate isomerase", - "5.3.1.25 L-fucose isomerase", - "5.3.1.26 Galactose-6-phosphate isomerase", - "5.3.1.27 6-phospho-3-hexuloisomerase", - "5.3.1.28 D-sedoheptulose 7-phosphate isomerase", - "5.3.1.29 Ribose 1,5-bisphosphate isomerase", - "5.3.1.30 5-deoxy-glucuronate isomerase", - "5.3.1.31 Sulfoquinovose isomerase", - "5.3.1.32 (4S)-4-hydroxy-5-phosphonooxypentane-2,3-dione isomerase", - "5.3.2.1 Phenylpyruvate tautomerase", - "5.3.2.2 Oxaloacetate tautomerase", - "5.3.2.3 TDP-4-oxo-6-deoxy-alpha-D-glucose-3,4-oxoisomerase (dTDP-3-dehydro-6-deoxy-alpha-D-galactopyranose-forming)", - "5.3.2.4 TDP-4-oxo-6-deoxy-alpha-D-glucose-3,4-oxoisomerase (dTDP-3-dehydro-6-deoxy-alpha-D-glucopyranose-forming)", - "5.3.2.5 2,3-diketo-5-methylthiopentyl-1-phosphate enolase", - "5.3.2.6 2-hydroxymuconate tautomerase", - "5.3.2.7 Ascopyrone tautomerase", - "5.3.2.8 4-oxalomesaconate tautomerase", - "5.3.3.1 Steroid Delta-isomerase", - "5.3.3.2 Isopentenyl-diphosphate Delta-isomerase", - "5.3.3.3 Vinylacetyl-CoA Delta-isomerase", - "5.3.3.4 Muconolactone Delta-isomerase", - "5.3.3.5 Cholestenol Delta-isomerase", - "5.3.3.6 Methylitaconate Delta-isomerase", - "5.3.3.7 Aconitate Delta-isomerase", - "5.3.3.8 Dodecenoyl-CoA isomerase", - "5.3.3.9 Prostaglandin-A(1) Delta-isomerase", - "5.3.3.10 5-carboxymethyl-2-hydroxymuconate Delta-isomerase", - "5.3.3.11 Isopiperitenone Delta-isomerase", - "5.3.3.12 L-dopachrome isomerase", - "5.3.3.13 Polyenoic fatty acid isomerase", - "5.3.3.14 Trans-2-decenoyl-[acyl-carrier-protein] isomerase", - "5.3.3.17 Trans-2,3-dihydro-3-hydroxyanthranilate isomerase", - "5.3.3.18 2-(1,2-epoxy-1,2-dihydrophenyl)acetyl-CoA isomerase", - "5.3.3.19 3-((4R)-4-hydroxycyclohexa-1,5-dien-1-yl)-2-oxopropanoate isomerase", - "5.3.4.1 Protein disulfide-isomerase", - "5.3.99.2 Prostaglandin-D synthase", - "5.3.99.3 Prostaglandin-E synthase", - "5.3.99.4 Prostaglandin-I synthase", - "5.3.99.5 Thromboxane-A synthase", - "5.3.99.6 Allene-oxide cyclase", - "5.3.99.7 Styrene-oxide isomerase", - "5.3.99.8 Capsanthin/capsorubin synthase", - "5.3.99.9 Neoxanthin synthase", - "5.3.99.10 Thiazole tautomerase", - "5.3.99.11 2-keto-myo-inositol isomerase", - "5.4.1.1 Lysolecithin acylmutase", - "5.4.1.3 2-methylfumaryl-CoA isomerase", - "5.4.1.4 D-galactarolactone isomerase", - "5.4.2.2 Phosphoglucomutase (alpha-D-glucose-1,6-bisphosphate-dependent)", - "5.4.2.3 Phosphoacetylglucosamine mutase", - "5.4.2.4 Bisphosphoglycerate mutase", - "5.4.2.5 Phosphoglucomutase (glucose-cofactor)", - "5.4.2.6 Beta-phosphoglucomutase", - "5.4.2.7 Phosphopentomutase", - "5.4.2.8 Phosphomannomutase", - "5.4.2.9 Phosphoenolpyruvate mutase", - "5.4.2.10 Phosphoglucosamine mutase", - "5.4.2.11 Phosphoglycerate mutase (2,3-diphosphoglycerate-dependent)", - "5.4.2.12 Phosphoglycerate mutase (2,3-diphosphoglycerate-independent)", - "5.4.3.2 Lysine 2,3-aminomutase", - "5.4.3.3 Beta-lysine 5,6-aminomutase", - "5.4.3.4 D-lysine 5,6-aminomutase", - "5.4.3.5 D-ornithine 4,5-aminomutase", - "5.4.3.6 Tyrosine 2,3-aminomutase", - "5.4.3.7 Leucine 2,3-aminomutase", - "5.4.3.8 Glutamate-1-semialdehyde 2,1-aminomutase", - "5.4.3.9 Glutamate 2,3-aminomutase", - "5.4.3.10 Phenylalanine aminomutase (L-beta-phenylalanine forming)", - "5.4.3.11 Phenylalanine aminomutase (D-beta-phenylalanine forming)", - "5.4.4.1 (Hydroxyamino)benzene mutase", - "5.4.4.2 Isochorismate synthase", - "5.4.4.3 3-(hydroxyamino)phenol mutase", - "5.4.4.4 Geraniol isomerase", - "5.4.4.5 9,12-octadecadienoate 8-hydroperoxide 8R-isomerase", - "5.4.4.6 9,12-octadecadienoate 8-hydroperoxide 8S-isomerase", - "5.4.4.7 Hydroperoxy icosatetraenoate isomerase", - "5.4.99.1 Methylaspartate mutase", - "5.4.99.2 Methylmalonyl-CoA mutase", - "5.4.99.3 2-acetolactate mutase", - "5.4.99.4 2-methyleneglutarate mutase", - "5.4.99.5 Chorismate mutase", - "5.4.99.7 Lanosterol synthase", - "5.4.99.8 Cycloartenol synthase", - "5.4.99.9 UDP-galactopyranose mutase", - "5.4.99.11 Isomaltulose synthase", - "5.4.99.12 tRNA pseudouridine(38-40) synthase", - "5.4.99.13 Isobutyryl-CoA mutase", - "5.4.99.14 4-carboxymethyl-4-methylbutenolide mutase", - "5.4.99.15 (1->4)-alpha-D-glucan 1-alpha-D-glucosylmutase", - "5.4.99.16 Maltose alpha-D-glucosyltransferase", - "5.4.99.17 Squalene--hopene cyclase", - "5.4.99.18 5-(carboxyamino)imidazole ribonucleotide mutase", - "5.4.99.19 16S rRNA pseudouridine(516) synthase", - "5.4.99.20 23S rRNA pseudouridine(2457) synthase", - "5.4.99.21 23S rRNA pseudouridine(2604) synthase", - "5.4.99.22 23S rRNA pseudouridine(2605) synthase", - "5.4.99.23 23S rRNA pseudouridine(1911/1915/1917) synthase", - "5.4.99.24 23S rRNA pseudouridine(955/2504/2580) synthase", - "5.4.99.25 tRNA pseudouridine(55) synthase", - "5.4.99.26 tRNA pseudouridine(65) synthase", - "5.4.99.27 tRNA pseudouridine(13) synthase", - "5.4.99.28 tRNA pseudouridine(32) synthase", - "5.4.99.29 23S rRNA pseudouridine(746) synthase", - "5.4.99.30 UDP-arabinopyranose mutase", - "5.4.99.31 Thalianol synthase", - "5.4.99.32 Protostadienol synthase", - "5.4.99.33 Cucurbitadienol synthase", - "5.4.99.34 Germanicol synthase", - "5.4.99.35 Taraxerol synthase", - "5.4.99.36 Isomultiflorenol synthase", - "5.4.99.37 Dammaradiene synthase", - "5.4.99.38 Camelliol C synthase", - "5.4.99.39 Beta-amyrin synthase", - "5.4.99.40 Alpha-amyrin synthase", - "5.4.99.41 Lupeol synthase", - "5.4.99.42 tRNA pseudouridine(31) synthase", - "5.4.99.43 21S rRNA pseudouridine(2819) synthase", - "5.4.99.44 Mitochondrial tRNA pseudouridine(27/28) synthase", - "5.4.99.45 tRNA pseudouridine(38/39) synthase", - "5.4.99.46 Shionone synthase", - "5.4.99.47 Parkeol synthase", - "5.4.99.48 Achilleol B synthase", - "5.4.99.49 Glutinol synthase", - "5.4.99.50 Friedelin synthase", - "5.4.99.51 Baccharis oxide synthase", - "5.4.99.52 Alpha-seco-amyrin synthase", - "5.4.99.53 Marneral synthase", - "5.4.99.54 Beta-seco-amyrin synthase", - "5.4.99.55 Delta-amyrin synthase", - "5.4.99.56 Tirucalladienol synthase", - "5.4.99.57 Baruol synthase", - "5.4.99.58 Methylornithine synthase", - "5.4.99.59 dTDP-fucopyranose mutase", - "5.4.99.60 Cobalt-precorrin-8 methylmutase", - "5.4.99.61 Precorrin-8X methylmutase", - "5.4.99.62 D-ribose pyranase", - "5.4.99.63 Ethylmalonyl-CoA mutase", - "5.5.1.1 Muconate cycloisomerase", - "5.5.1.2 3-carboxy-cis,cis-muconate cycloisomerase", - "5.5.1.3 Tetrahydroxypteridine cycloisomerase", - "5.5.1.4 Inositol-3-phosphate synthase", - "5.5.1.5 Carboxy-cis,cis-muconate cyclase", - "5.5.1.6 Chalcone isomerase", - "5.5.1.7 Chloromuconate cycloisomerase", - "5.5.1.8 (+)-bornyl diphosphate synthase", - "5.5.1.9 Cycloeucalenol cycloisomerase", - "5.5.1.10 Alpha-pinene-oxide decyclase", - "5.5.1.11 Dichloromuconate cycloisomerase", - "5.5.1.12 Copalyl diphosphate synthase", - "5.5.1.13 Ent-copalyl diphosphate synthase", - "5.5.1.14 Syn-copalyl-diphosphate synthase", - "5.5.1.15 Terpentedienyl-diphosphate synthase", - "5.5.1.16 Halimadienyl-diphosphate synthase", - "5.5.1.17 (S)-beta-macrocarpene synthase", - "5.5.1.18 Lycopene epsilon-cyclase", - "5.5.1.19 Lycopene beta-cyclase", - "5.5.1.20 Prosolanapyrone-III cycloisomerase", - "5.5.1.22 (-)-bornyl diphosphate synthase", - "5.5.1.23 Aklanonic acid methyl ester cyclase", - "5.5.1.24 Tocopherol cyclase", - "5.5.1.25 3,6-anhydro-L-galactonate cycloisomerase", - "5.5.1.26 Nogalonic acid methyl ester cyclase", - "5.5.1.27 D-galactarolactone cycloisomerase", - "5.99.1.1 Thiocyanate isomerase", - "5.99.1.2 DNA topoisomerase", - "5.99.1.3 DNA topoisomerase (ATP-hydrolyzing)", - "5.99.1.4 2-hydroxychromene-2-carboxylate isomerase", - "6.1.1.1 Tyrosine--tRNA ligase", - "6.1.1.2 Tryptophan--tRNA ligase", - "6.1.1.3 Threonine--tRNA ligase", - "6.1.1.4 Leucine--tRNA ligase", - "6.1.1.5 Isoleucine--tRNA ligase", - "6.1.1.6 Lysine--tRNA ligase", - "6.1.1.7 Alanine--tRNA ligase", - "6.1.1.9 Valine--tRNA ligase", - "6.1.1.10 Methionine--tRNA ligase", - "6.1.1.11 Serine--tRNA ligase", - "6.1.1.12 Aspartate--tRNA ligase", - "6.1.1.13 D-alanine--poly(phosphoribitol) ligase", - "6.1.1.14 Glycine--tRNA ligase", - "6.1.1.15 Proline--tRNA ligase", - "6.1.1.16 Cysteine--tRNA ligase", - "6.1.1.17 Glutamate--tRNA ligase", - "6.1.1.18 Glutamine--tRNA ligase", - "6.1.1.19 Arginine--tRNA ligase", - "6.1.1.20 Phenylalanine--tRNA ligase", - "6.1.1.21 Histidine--tRNA ligase", - "6.1.1.22 Asparagine--tRNA ligase", - "6.1.1.23 Aspartate--tRNA(Asn) ligase", - "6.1.1.24 Glutamate--tRNA(Gln) ligase", - "6.1.1.26 Pyrrolysine--tRNA(Pyl) ligase", - "6.1.1.27 O-phosphoserine--tRNA ligase", - "6.1.2.1 D-alanine--(R)-lactate ligase", - "6.1.2.2 Nebramycin 5' synthase", - "6.2.1.1 Acetate--CoA ligase", - "6.2.1.2 Butyrate--CoA ligase", - "6.2.1.3 Long-chain-fatty-acid--CoA ligase", - "6.2.1.4 Succinate--CoA ligase (GDP-forming)", - "6.2.1.5 Succinate--CoA ligase (ADP-forming)", - "6.2.1.6 Glutarate--CoA ligase", - "6.2.1.7 Cholate--CoA ligase", - "6.2.1.8 Oxalate--CoA ligase", - "6.2.1.9 Malate--CoA ligase", - "6.2.1.10 Acid--CoA ligase (GDP-forming)", - "6.2.1.11 Biotin--CoA ligase", - "6.2.1.12 4-coumarate--CoA ligase", - "6.2.1.13 Acetate--CoA ligase (ADP-forming)", - "6.2.1.14 6-carboxyhexanoate--CoA ligase", - "6.2.1.15 Arachidonate--CoA ligase", - "6.2.1.16 Acetoacetate--CoA ligase", - "6.2.1.17 Propionate--CoA ligase", - "6.2.1.18 Citrate--CoA ligase", - "6.2.1.19 Long-chain-fatty-acid--luciferin-component ligase", - "6.2.1.20 Long-chain-fatty-acid--[acyl-carrier-protein] ligase", - "6.2.1.22 [Citrate (pro-3S)-lyase] ligase", - "6.2.1.23 Dicarboxylate--CoA ligase", - "6.2.1.24 Phytanate--CoA ligase", - "6.2.1.25 Benzoate--CoA ligase", - "6.2.1.26 o-succinylbenzoate--CoA ligase", - "6.2.1.27 4-hydroxybenzoate--CoA ligase", - "6.2.1.28 3-alpha,7-alpha-dihydroxy-5-beta-cholestanate--CoA ligase", - "6.2.1.30 Phenylacetate--CoA ligase", - "6.2.1.31 2-furoate--CoA ligase", - "6.2.1.32 Anthranilate--CoA ligase", - "6.2.1.33 4-chlorobenzoate--CoA ligase", - "6.2.1.34 Trans-feruloyl-CoA synthase", - "6.2.1.35 ACP-SH:acetate ligase", - "6.2.1.36 3-hydroxypropionyl-CoA synthase", - "6.2.1.37 3-hydroxybenzoate--CoA ligase", - "6.2.1.38 (2,2,3-trimethyl-5-oxocyclopent-3-enyl)acetyl-CoA synthase", - "6.2.1.39 [Butirosin acyl-carrier protein]--L-glutamate ligase", - "6.2.1.40 4-hydroxybutyrate--CoA ligase", - "6.2.1.41 3-((3aS,4S,7aS)-7a-methyl-1,5-dioxo-octahydro-1H-inden-4-yl)propanoate--CoA ligase", - "6.2.1.42 3-oxocholest-4-en-26-oate--CoA ligase", - "6.2.1.43 2-hydroxy-7-methoxy-5-methyl-1-naphthoate--CoA ligase", - "6.2.1.44 3-(methylthio)propionyl--CoA ligase", - "6.2.1.45 E1 ubiquitin-activating enzyme", - "6.2.1.46 L-allo-isoleucine:holo-[CmaA peptidyl-carrier protein] ligase", - "6.2.1.n2 Amino acid--[acyl-carrier-protein] ligase", - "6.2.1.n3 Malonate--CoA ligase", - "6.3.1.1 Aspartate--ammonia ligase", - "6.3.1.2 Glutamate--ammonia ligase", - "6.3.1.4 Aspartate--ammonia ligase (ADP-forming)", - "6.3.1.5 NAD(+) synthase", - "6.3.1.6 Glutamate--ethylamine ligase", - "6.3.1.7 4-methyleneglutamate--ammonia ligase", - "6.3.1.8 Glutathionylspermidine synthase", - "6.3.1.9 Trypanothione synthase", - "6.3.1.10 Adenosylcobinamide-phosphate synthase", - "6.3.1.11 Glutamate--putrescine ligase", - "6.3.1.12 D-aspartate ligase", - "6.3.1.13 L-cysteine:1D-myo-inositol 2-amino-2-deoxy-alpha-D-glucopyranoside ligase", - "6.3.1.14 Diphthine--ammonia ligase", - "6.3.1.15 8-demethylnovobiocic acid synthase", - "6.3.1.17 Beta-citrylglutamate synthase", - "6.3.1.18 Gamma-glutamylanilide synthase", - "6.3.1.19 Prokaryotic ubiquitin-like protein ligase", - "6.3.1.20 Lipoate--protein ligase", - "6.3.2.1 Pantoate--beta-alanine ligase (AMP-forming)", - "6.3.2.2 Glutamate--cysteine ligase", - "6.3.2.3 Glutathione synthase", - "6.3.2.4 D-alanine--D-alanine ligase", - "6.3.2.5 Phosphopantothenate--cysteine ligase", - "6.3.2.6 Phosphoribosylaminoimidazolesuccinocarboxamide synthase", - "6.3.2.7 UDP-N-acetylmuramoyl-L-alanyl-D-glutamate--L-lysine ligase", - "6.3.2.8 UDP-N-acetylmuramate--L-alanine ligase", - "6.3.2.9 UDP-N-acetylmuramoyl-L-alanine--D-glutamate ligase", - "6.3.2.10 UDP-N-acetylmuramoyl-tripeptide--D-alanyl-D-alanine ligase", - "6.3.2.11 Carnosine synthase", - "6.3.2.12 Dihydrofolate synthase", - "6.3.2.13 UDP-N-acetylmuramoyl-L-alanyl-D-glutamate--2,6-diaminopimelate ligase", - "6.3.2.14 Enterobactin synthase", - "6.3.2.16 D-alanine--alanyl-poly(glycerolphosphate) ligase", - "6.3.2.17 Tetrahydrofolate synthase", - "6.3.2.18 Gamma-glutamylhistamine synthase", - "6.3.2.20 Indoleacetate--lysine synthetase", - "6.3.2.21 Ubiquitin--calmodulin ligase", - "6.3.2.23 Homoglutathione synthase", - "6.3.2.24 Tyrosine--arginine ligase", - "6.3.2.25 Tubulin--tyrosine ligase", - "6.3.2.26 N-(5-amino-5-carboxypentanoyl)-L-cysteinyl-D-valine synthase", - "6.3.2.29 Cyanophycin synthase (L-aspartate-adding)", - "6.3.2.30 Cyanophycin synthase (L-arginine-adding)", - "6.3.2.31 Coenzyme F420-0:L-glutamate ligase", - "6.3.2.32 Coenzyme gamma-F420-2:alpha-L-glutamate ligase", - "6.3.2.33 Tetrahydrosarcinapterin synthase", - "6.3.2.34 Coenzyme F420-1:gamma-L-glutamate ligase", - "6.3.2.35 D-alanine--D-serine ligase", - "6.3.2.36 4-phosphopantoate--beta-alanine ligase", - "6.3.2.37 UDP-N-acetylmuramoyl-L-alanyl-D-glutamate--D-lysine ligase", - "6.3.2.38 N(2)-citryl-N(6)-acetyl-N(6)-hydroxylysine synthase", - "6.3.2.39 Aerobactin synthase", - "6.3.2.40 Cyclopeptine synthase", - "6.3.2.41 N-acetylaspartylglutamate synthase", - "6.3.2.42 N-acetylaspartylglutamylglutamate synthase", - "6.3.2.43 [Lysine-biosynthesis-protein LysW]--L-2-aminoadipate ligase", - "6.3.2.44 Pantoate--beta-alanine ligase (ADP-forming)", - "6.3.2.45 UDP-N-acetylmuramate L-alanyl-gamma-D-glutamyl-meso-2,6-diaminoheptanedioate ligase", - "6.3.2.46 Fumarate--(S)-2,3-diaminopropanoate ligase", - "6.3.2.47 Dapdiamide A synthase", - "6.3.2.48 L-arginine-specific L-amino acid ligase", - "6.3.2.49 L-alanine--L-anticapsin ligase", - "6.3.2.n3 ISG15--protein ligase", - "6.3.3.1 Phosphoribosylformylglycinamidine cyclo-ligase", - "6.3.3.2 5-formyltetrahydrofolate cyclo-ligase", - "6.3.3.3 Dethiobiotin synthase", - "6.3.3.4 (Carboxyethyl)arginine beta-lactam-synthase", - "6.3.3.5 O-ureido-D-serine cyclo-ligase", - "6.3.3.6 Carbapenam-3-carboxylate synthase", - "6.3.4.2 CTP synthase (glutamine hydrolyzing)", - "6.3.4.3 Formate--tetrahydrofolate ligase", - "6.3.4.4 Adenylosuccinate synthase", - "6.3.4.5 Argininosuccinate synthase", - "6.3.4.6 Urea carboxylase", - "6.3.4.7 Ribose-5-phosphate--ammonia ligase", - "6.3.4.8 Imidazoleacetate--phosphoribosyldiphosphate ligase", - "6.3.4.9 Biotin--[methylmalonyl-CoA-carboxytransferase] ligase", - "6.3.4.10 Biotin--[propionyl-CoA-carboxylase (ATP-hydrolyzing)] ligase", - "6.3.4.11 Biotin--[methylcrotonoyl-CoA-carboxylase] ligase", - "6.3.4.12 Glutamate--methylamine ligase", - "6.3.4.13 Phosphoribosylamine--glycine ligase", - "6.3.4.14 Biotin carboxylase", - "6.3.4.15 Biotin--[acetyl-CoA-carboxylase] ligase", - "6.3.4.16 Carbamoyl-phosphate synthase (ammonia)", - "6.3.4.17 Formate--dihydrofolate ligase", - "6.3.4.18 5-(carboxyamino)imidazole ribonucleotide synthase", - "6.3.4.19 tRNA(Ile)-lysidine synthetase", - "6.3.4.20 7-cyano-7-deazaguanine synthase", - "6.3.4.21 Nicotinate phosphoribosyltransferase", - "6.3.4.22 tRNA(Ile)(2)-agmatinylcytidine synthase", - "6.3.4.23 Formate--phosphoribosylaminoimidazolecarboxamide ligase", - "6.3.4.24 Tyramine--L-glutamate ligase", - "6.3.5.1 NAD(+) synthase (glutamine-hydrolyzing)", - "6.3.5.2 GMP synthase (glutamine-hydrolyzing)", - "6.3.5.3 Phosphoribosylformylglycinamidine synthase", - "6.3.5.4 Asparagine synthase (glutamine-hydrolyzing)", - "6.3.5.5 Carbamoyl-phosphate synthase (glutamine-hydrolyzing)", - "6.3.5.6 Asparaginyl-tRNA synthase (glutamine-hydrolyzing)", - "6.3.5.7 Glutaminyl-tRNA synthase (glutamine-hydrolyzing)", - "6.3.5.9 Hydrogenobyrinic acid a,c-diamide synthase (glutamine-hydrolyzing)", - "6.3.5.10 Adenosylcobyric acid synthase (glutamine-hydrolyzing)", - "6.3.5.11 Cobyrinate a,c-diamide synthase (glutamine-hydrolyzing)", - "6.4.1.1 Pyruvate carboxylase", - "6.4.1.2 Acetyl-CoA carboxylase", - "6.4.1.3 Propionyl-CoA carboxylase", - "6.4.1.4 Methylcrotonoyl-CoA carboxylase", - "6.4.1.5 Geranoyl-CoA carboxylase", - "6.4.1.6 Acetone carboxylase", - "6.4.1.7 2-oxoglutarate carboxylase", - "6.4.1.8 Acetophenone carboxylase", - "6.5.1.1 DNA ligase (ATP)", - "6.5.1.2 DNA ligase (NAD(+))", - "6.5.1.3 RNA ligase (ATP)", - "6.5.1.4 RNA 3'-terminal-phosphate cyclase (ATP)", - "6.5.1.5 RNA 3'-terminal-phosphate cyclase (GTP)", - "6.5.1.6 DNA ligase (ATP or NAD(+))", - "6.5.1.7 DNA ligase (ATP, ADP or GTP)", - "6.6.1.1 Magnesium chelatase", - "6.6.1.2 Cobaltochelatase" + "1.1.1.1\tAlcohol dehydrogenase", + "1.1.1.2\tAlcohol dehydrogenase (NADP(+))", + "1.1.1.3\tHomoserine dehydrogenase", + "1.1.1.4\t(R,R)-butanediol dehydrogenase", + "1.1.1.6\tGlycerol dehydrogenase", + "1.1.1.7\tPropanediol-phosphate dehydrogenase", + "1.1.1.8\tGlycerol-3-phosphate dehydrogenase (NAD(+))", + "1.1.1.9\tD-xylulose reductase", + "1.1.1.10\tL-xylulose reductase", + "1.1.1.11\tD-arabinitol 4-dehydrogenase", + "1.1.1.12\tL-arabinitol 4-dehydrogenase", + "1.1.1.13\tL-arabinitol 2-dehydrogenase", + "1.1.1.14\tL-iditol 2-dehydrogenase", + "1.1.1.15\tD-iditol 2-dehydrogenase", + "1.1.1.16\tGalactitol 2-dehydrogenase", + "1.1.1.17\tMannitol-1-phosphate 5-dehydrogenase", + "1.1.1.18\tInositol 2-dehydrogenase", + "1.1.1.19\tGlucuronate reductase", + "1.1.1.20\tGlucuronolactone reductase", + "1.1.1.21\tAldehyde reductase", + "1.1.1.22\tUDP-glucose 6-dehydrogenase", + "1.1.1.23\tHistidinol dehydrogenase", + "1.1.1.24\tQuinate dehydrogenase", + "1.1.1.25\tShikimate dehydrogenase", + "1.1.1.26\tGlyoxylate reductase", + "1.1.1.27\tL-lactate dehydrogenase", + "1.1.1.28\tD-lactate dehydrogenase", + "1.1.1.29\tGlycerate dehydrogenase", + "1.1.1.30\t3-hydroxybutyrate dehydrogenase", + "1.1.1.31\t3-hydroxyisobutyrate dehydrogenase", + "1.1.1.32\tMevaldate reductase", + "1.1.1.33\tMevaldate reductase (NADPH)", + "1.1.1.34\tHydroxymethylglutaryl-CoA reductase (NADPH)", + "1.1.1.35\t3-hydroxyacyl-CoA dehydrogenase", + "1.1.1.36\tAcetoacetyl-CoA reductase", + "1.1.1.37\tMalate dehydrogenase", + "1.1.1.38\tMalate dehydrogenase (oxaloacetate-decarboxylating)", + "1.1.1.39\tMalate dehydrogenase (decarboxylating)", + "1.1.1.40\tMalate dehydrogenase (oxaloacetate-decarboxylating) (NADP(+))", + "1.1.1.41\tIsocitrate dehydrogenase (NAD(+))", + "1.1.1.42\tIsocitrate dehydrogenase (NADP(+))", + "1.1.1.43\tPhosphogluconate 2-dehydrogenase", + "1.1.1.44\tPhosphogluconate dehydrogenase (NADP(+)-dependent, decarboxylating)", + "1.1.1.45\tL-gulonate 3-dehydrogenase", + "1.1.1.46\tL-arabinose 1-dehydrogenase", + "1.1.1.47\tGlucose 1-dehydrogenase (NAD(P)(+))", + "1.1.1.48\tD-galactose 1-dehydrogenase", + "1.1.1.49\tGlucose-6-phosphate dehydrogenase (NADP(+))", + "1.1.1.50\t3-alpha-hydroxysteroid 3-dehydrogenase (Si-specific)", + "1.1.1.51\t3(or 17)-beta-hydroxysteroid dehydrogenase", + "1.1.1.52\t3-alpha-hydroxycholanate dehydrogenase (NAD(+))", + "1.1.1.53\t3-alpha(or 20-beta)-hydroxysteroid dehydrogenase", + "1.1.1.54\tAllyl-alcohol dehydrogenase", + "1.1.1.55\tLactaldehyde reductase (NADPH)", + "1.1.1.56\tRibitol 2-dehydrogenase", + "1.1.1.57\tFructuronate reductase", + "1.1.1.58\tTagaturonate reductase", + "1.1.1.59\t3-hydroxypropionate dehydrogenase", + "1.1.1.60\t2-hydroxy-3-oxopropionate reductase", + "1.1.1.61\t4-hydroxybutyrate dehydrogenase", + "1.1.1.62\t17-beta-estradiol 17-dehydrogenase", + "1.1.1.64\tTestosterone 17-beta-dehydrogenase (NADP(+))", + "1.1.1.65\tPyridoxine 4-dehydrogenase", + "1.1.1.66\tOmega-hydroxydecanoate dehydrogenase", + "1.1.1.67\tMannitol 2-dehydrogenase", + "1.1.1.69\tGluconate 5-dehydrogenase", + "1.1.1.71\tAlcohol dehydrogenase (NAD(P)(+))", + "1.1.1.72\tGlycerol dehydrogenase (NADP(+))", + "1.1.1.73\tOctanol dehydrogenase", + "1.1.1.75\t(R)-aminopropanol dehydrogenase", + "1.1.1.76\t(S,S)-butanediol dehydrogenase", + "1.1.1.77\tLactaldehyde reductase", + "1.1.1.78\tMethylglyoxal reductase (NADH)", + "1.1.1.79\tGlyoxylate reductase (NADP(+))", + "1.1.1.80\tIsopropanol dehydrogenase (NADP(+))", + "1.1.1.81\tHydroxypyruvate reductase", + "1.1.1.82\tMalate dehydrogenase (NADP(+))", + "1.1.1.83\tD-malate dehydrogenase (decarboxylating)", + "1.1.1.84\tDimethylmalate dehydrogenase", + "1.1.1.85\t3-isopropylmalate dehydrogenase", + "1.1.1.86\tKetol-acid reductoisomerase (NADP(+))", + "1.1.1.87\tHomoisocitrate dehydrogenase", + "1.1.1.88\tHydroxymethylglutaryl-CoA reductase", + "1.1.1.90\tAryl-alcohol dehydrogenase", + "1.1.1.91\tAryl-alcohol dehydrogenase (NADP(+))", + "1.1.1.92\tOxaloglycolate reductase (decarboxylating)", + "1.1.1.93\tTartrate dehydrogenase", + "1.1.1.94\tGlycerol-3-phosphate dehydrogenase (NAD(P)(+))", + "1.1.1.95\tPhosphoglycerate dehydrogenase", + "1.1.1.96\tDiiodophenylpyruvate reductase", + "1.1.1.97\t3-hydroxybenzyl-alcohol dehydrogenase", + "1.1.1.98\t(R)-2-hydroxy-fatty-acid dehydrogenase", + "1.1.1.99\t(S)-2-hydroxy-fatty-acid dehydrogenase", + "1.1.1.100\t3-oxoacyl-[acyl-carrier-protein] reductase", + "1.1.1.101\tAcylglycerone-phosphate reductase", + "1.1.1.102\t3-dehydrosphinganine reductase", + "1.1.1.103\tL-threonine 3-dehydrogenase", + "1.1.1.104\t4-oxoproline reductase", + "1.1.1.105\tAll-trans-retinol dehydrogenase (NAD(+))", + "1.1.1.106\tPantoate 4-dehydrogenase", + "1.1.1.107\tPyridoxal 4-dehydrogenase", + "1.1.1.108\tCarnitine 3-dehydrogenase", + "1.1.1.110\tIndolelactate dehydrogenase", + "1.1.1.111\t3-(imidazol-5-yl)lactate dehydrogenase", + "1.1.1.112\tIndanol dehydrogenase", + "1.1.1.113\tL-xylose 1-dehydrogenase", + "1.1.1.114\tApiose 1-reductase", + "1.1.1.115\tRibose 1-dehydrogenase (NADP(+))", + "1.1.1.116\tD-arabinose 1-dehydrogenase (NAD(+))", + "1.1.1.117\tD-arabinose 1-dehydrogenase (NAD(P)(+))", + "1.1.1.118\tGlucose 1-dehydrogenase (NAD(+))", + "1.1.1.119\tGlucose 1-dehydrogenase (NADP(+))", + "1.1.1.120\tGalactose 1-dehydrogenase (NADP(+))", + "1.1.1.121\tAldose 1-dehydrogenase (NAD(+))", + "1.1.1.122\tD-threo-aldose 1-dehydrogenase", + "1.1.1.123\tSorbose 5-dehydrogenase (NADP(+))", + "1.1.1.124\tFructose 5-dehydrogenase (NADP(+))", + "1.1.1.125\t2-deoxy-D-gluconate 3-dehydrogenase", + "1.1.1.126\t2-dehydro-3-deoxy-D-gluconate 6-dehydrogenase", + "1.1.1.127\t2-dehydro-3-deoxy-D-gluconate 5-dehydrogenase", + "1.1.1.129\tL-threonate 3-dehydrogenase", + "1.1.1.130\t3-dehydro-L-gulonate 2-dehydrogenase", + "1.1.1.131\tMannuronate reductase", + "1.1.1.132\tGDP-mannose 6-dehydrogenase", + "1.1.1.133\tdTDP-4-dehydrorhamnose reductase", + "1.1.1.134\tdTDP-6-deoxy-L-talose 4-dehydrogenase", + "1.1.1.135\tGDP-6-deoxy-D-talose 4-dehydrogenase", + "1.1.1.136\tUDP-N-acetylglucosamine 6-dehydrogenase", + "1.1.1.137\tRibitol-5-phosphate 2-dehydrogenase", + "1.1.1.138\tMannitol 2-dehydrogenase (NADP(+))", + "1.1.1.140\tSorbitol-6-phosphate 2-dehydrogenase", + "1.1.1.141\t15-hydroxyprostaglandin dehydrogenase (NAD(+))", + "1.1.1.142\tD-pinitol dehydrogenase", + "1.1.1.143\tSequoyitol dehydrogenase", + "1.1.1.144\tPerillyl-alcohol dehydrogenase", + "1.1.1.145\t3-beta-hydroxy-Delta(5)-steroid dehydrogenase", + "1.1.1.146\t11-beta-hydroxysteroid dehydrogenase", + "1.1.1.147\t16-alpha-hydroxysteroid dehydrogenase", + "1.1.1.148\tEstradiol 17-alpha-dehydrogenase", + "1.1.1.149\t20-alpha-hydroxysteroid dehydrogenase", + "1.1.1.150\t21-hydroxysteroid dehydrogenase (NAD(+))", + "1.1.1.151\t21-hydroxysteroid dehydrogenase (NADP(+))", + "1.1.1.152\t3-alpha-hydroxy-5-beta-androstane-17-one 3-alpha-dehydrogenase", + "1.1.1.153\tSepiapterin reductase (L-erythro-7,8-dihydrobiopterin forming)", + "1.1.1.154\tUreidoglycolate dehydrogenase", + "1.1.1.156\tGlycerol 2-dehydrogenase (NADP(+))", + "1.1.1.157\t3-hydroxybutyryl-CoA dehydrogenase", + "1.1.1.159\t7-alpha-hydroxysteroid dehydrogenase", + "1.1.1.160\tDihydrobunolol dehydrogenase", + "1.1.1.162\tErythrulose reductase", + "1.1.1.163\tCyclopentanol dehydrogenase", + "1.1.1.164\tHexadecanol dehydrogenase", + "1.1.1.165\t2-alkyn-1-ol dehydrogenase", + "1.1.1.166\tHydroxycyclohexanecarboxylate dehydrogenase", + "1.1.1.167\tHydroxymalonate dehydrogenase", + "1.1.1.168\t2-dehydropantolactone reductase (Re-specific)", + "1.1.1.169\t2-dehydropantoate 2-reductase", + "1.1.1.170\t3-beta-hydroxysteroid-4-alpha-carboxylate 3-dehydrogenase (decarboxylating)", + "1.1.1.172\t2-oxoadipate reductase", + "1.1.1.173\tL-rhamnose 1-dehydrogenase", + "1.1.1.174\tCyclohexane-1,2-diol dehydrogenase", + "1.1.1.175\tD-xylose 1-dehydrogenase", + "1.1.1.176\t12-alpha-hydroxysteroid dehydrogenase", + "1.1.1.177\tGlycerol-3-phosphate 1-dehydrogenase (NADP(+))", + "1.1.1.178\t3-hydroxy-2-methylbutyryl-CoA dehydrogenase", + "1.1.1.179\tD-xylose 1-dehydrogenase (NADP(+))", + "1.1.1.181\tCholest-5-ene-3-beta,7-alpha-diol 3-beta-dehydrogenase", + "1.1.1.183\tGeraniol dehydrogenase (NADP(+))", + "1.1.1.184\tCarbonyl reductase (NADPH)", + "1.1.1.185\tL-glycol dehydrogenase", + "1.1.1.186\tdTDP-galactose 6-dehydrogenase", + "1.1.1.187\tGDP-4-dehydro-D-rhamnose reductase", + "1.1.1.188\tProstaglandin-F synthase", + "1.1.1.189\tProstaglandin-E(2) 9-reductase", + "1.1.1.190\tIndole-3-acetaldehyde reductase (NADH)", + "1.1.1.191\tIndole-3-acetaldehyde reductase (NADPH)", + "1.1.1.192\tLong-chain-alcohol dehydrogenase", + "1.1.1.193\t5-amino-6-(5-phosphoribosylamino)uracil reductase", + "1.1.1.194\tConiferyl-alcohol dehydrogenase", + "1.1.1.195\tCinnamyl-alcohol dehydrogenase", + "1.1.1.196\t15-hydroxyprostaglandin-D dehydrogenase (NADP(+))", + "1.1.1.197\t15-hydroxyprostaglandin dehydrogenase (NADP(+))", + "1.1.1.198\t(+)-borneol dehydrogenase", + "1.1.1.199\t(S)-usnate reductase", + "1.1.1.200\tAldose-6-phosphate reductase (NADPH)", + "1.1.1.201\t7-beta-hydroxysteroid dehydrogenase (NADP(+))", + "1.1.1.202\t1,3-propanediol dehydrogenase", + "1.1.1.203\tUronate dehydrogenase", + "1.1.1.205\tIMP dehydrogenase", + "1.1.1.206\tTropinone reductase I", + "1.1.1.207\t(-)-menthol dehydrogenase", + "1.1.1.208\t(+)-neomenthol dehydrogenase", + "1.1.1.209\t3(or 17)-alpha-hydroxysteroid dehydrogenase", + "1.1.1.210\t3-beta-(or 20-alpha)-hydroxysteroid dehydrogenase", + "1.1.1.211\tLong-chain-3-hydroxyacyl-CoA dehydrogenase", + "1.1.1.212\t3-oxoacyl-[acyl-carrier-protein] reductase (NADH)", + "1.1.1.213\t3-alpha-hydroxysteroid dehydrogenase (Re-specific)", + "1.1.1.214\t2-dehydropantolactone reductase (Si-specific)", + "1.1.1.215\tGluconate 2-dehydrogenase", + "1.1.1.216\tFarnesol dehydrogenase", + "1.1.1.217\tBenzyl-2-methyl-hydroxybutyrate dehydrogenase", + "1.1.1.218\tMorphine 6-dehydrogenase", + "1.1.1.219\tDihydroflavanol 4-reductase", + "1.1.1.220\t6-pyruvoyltetrahydropterin 2'-reductase", + "1.1.1.221\tVomifoliol dehydrogenase", + "1.1.1.222\t(R)-4-hydroxyphenyllactate dehydrogenase", + "1.1.1.223\tIsopiperitenol dehydrogenase", + "1.1.1.224\tMannose-6-phosphate 6-reductase", + "1.1.1.225\tChlordecone reductase", + "1.1.1.226\t4-hydroxycyclohexanecarboxylate dehydrogenase", + "1.1.1.227\t(-)-borneol dehydrogenase", + "1.1.1.228\t(+)-sabinol dehydrogenase", + "1.1.1.229\tDiethyl 2-methyl-3-oxosuccinate reductase", + "1.1.1.230\t3-alpha-hydroxyglycyrrhetinate dehydrogenase", + "1.1.1.231\t15-hydroxyprostaglandin-I dehydrogenase (NADP(+))", + "1.1.1.232\t15-hydroxyicosatetraenoate dehydrogenase", + "1.1.1.233\tN-acylmannosamine 1-dehydrogenase", + "1.1.1.234\tFlavanone 4-reductase", + "1.1.1.235\t8-oxocoformycin reductase", + "1.1.1.236\tTropinone reductase II", + "1.1.1.237\tHydroxyphenylpyruvate reductase", + "1.1.1.238\t12-beta-hydroxysteroid dehydrogenase", + "1.1.1.239\t3-alpha-(17-beta)-hydroxysteroid dehydrogenase (NAD(+))", + "1.1.1.240\tN-acetylhexosamine 1-dehydrogenase", + "1.1.1.241\t6-endo-hydroxycineole dehydrogenase", + "1.1.1.243\tCarveol dehydrogenase", + "1.1.1.244\tMethanol dehydrogenase", + "1.1.1.245\tCyclohexanol dehydrogenase", + "1.1.1.247\tCodeinone reductase (NADPH)", + "1.1.1.248\tSalutaridine reductase (NADPH)", + "1.1.1.250\tD-arabinitol 2-dehydrogenase", + "1.1.1.251\tGalactitol-1-phosphate 5-dehydrogenase", + "1.1.1.252\tTetrahydroxynaphthalene reductase", + "1.1.1.254\t(S)-carnitine 3-dehydrogenase", + "1.1.1.255\tMannitol dehydrogenase", + "1.1.1.256\tFluoren-9-ol dehydrogenase", + "1.1.1.257\t4-(hydroxymethyl)benzenesulfonate dehydrogenase", + "1.1.1.258\t6-hydroxyhexanoate dehydrogenase", + "1.1.1.259\t3-hydroxypimeloyl-CoA dehydrogenase", + "1.1.1.260\tSulcatone reductase", + "1.1.1.261\tsn-glycerol-1-phosphate dehydrogenase", + "1.1.1.262\t4-hydroxythreonine-4-phosphate dehydrogenase", + "1.1.1.263\t1,5-anhydro-D-fructose reductase", + "1.1.1.264\tL-idonate 5-dehydrogenase (NAD(P)(+))", + "1.1.1.265\t3-methylbutanal reductase", + "1.1.1.266\tdTDP-4-dehydro-6-deoxyglucose reductase", + "1.1.1.267\t1-deoxy-D-xylulose-5-phosphate reductoisomerase", + "1.1.1.268\t2-(R)-hydroxypropyl-CoM dehydrogenase", + "1.1.1.269\t2-(S)-hydroxypropyl-CoM dehydrogenase", + "1.1.1.270\t3-beta-hydroxysteroid 3-dehydrogenase", + "1.1.1.271\tGDP-L-fucose synthase", + "1.1.1.272\tD-2-hydroxyacid dehydrogenase (NADP(+))", + "1.1.1.273\tVellosimine dehydrogenase", + "1.1.1.274\t2,5-didehydrogluconate reductase (2-dehydro-D-gluconate-forming)", + "1.1.1.275\t(+)-trans-carveol dehydrogenase", + "1.1.1.276\tSerine 3-dehydrogenase (NADP(+))", + "1.1.1.277\t3-beta-hydroxy-5-beta-steroid dehydrogenase", + "1.1.1.278\t3-beta-hydroxy-5-alpha-steroid dehydrogenase", + "1.1.1.279\t(R)-3-hydroxyacid-ester dehydrogenase", + "1.1.1.280\t(S)-3-hydroxyacid-ester dehydrogenase", + "1.1.1.281\tGDP-4-dehydro-6-deoxy-D-mannose reductase", + "1.1.1.282\tQuinate/shikimate dehydrogenase", + "1.1.1.283\tMethylglyoxal reductase (NADPH)", + "1.1.1.284\tS-(hydroxymethyl)glutathione dehydrogenase", + "1.1.1.285\t3''-deamino-3''-oxonicotianamine reductase", + "1.1.1.286\tIsocitrate--homoisocitrate dehydrogenase", + "1.1.1.287\tD-arabinitol dehydrogenase (NADP(+))", + "1.1.1.288\tXanthoxin dehydrogenase", + "1.1.1.289\tSorbose reductase", + "1.1.1.290\t4-phosphoerythronate dehydrogenase", + "1.1.1.291\t2-hydroxymethylglutarate dehydrogenase", + "1.1.1.292\t1,5-anhydro-D-fructose reductase (1,5-anhydro-D-mannitol-forming)", + "1.1.1.294\tChlorophyll(ide) b reductase", + "1.1.1.295\tMomilactone-A synthase", + "1.1.1.296\tDihydrocarveol dehydrogenase", + "1.1.1.297\tLimonene-1,2-diol dehydrogenase", + "1.1.1.298\t3-hydroxypropionate dehydrogenase (NADP(+))", + "1.1.1.299\tMalate dehydrogenase (NAD(P)(+))", + "1.1.1.300\tNADP-retinol dehydrogenase", + "1.1.1.301\tD-arabitol-phosphate dehydrogenase", + "1.1.1.302\t2,5-diamino-6-(ribosylamino)-4(3H)-pyrimidinone 5'-phosphate reductase", + "1.1.1.303\tDiacetyl reductase ((R)-acetoin forming)", + "1.1.1.304\tDiacetyl reductase ((S)-acetoin forming)", + "1.1.1.305\tUDP-glucuronic acid oxidase (UDP-4-keto-hexauronic acid decarboxylating)", + "1.1.1.306\tS-(hydroxymethyl)mycothiol dehydrogenase", + "1.1.1.307\tD-xylose reductase", + "1.1.1.308\tSulfopropanediol 3-dehydrogenase", + "1.1.1.309\tPhosphonoacetaldehyde reductase (NADH)", + "1.1.1.310\t(S)-sulfolactate dehydrogenase", + "1.1.1.311\t(S)-1-phenylethanol dehydrogenase", + "1.1.1.312\t2-hydroxy-4-carboxymuconate semialdehyde hemiacetal dehydrogenase", + "1.1.1.313\tSulfoacetaldehyde reductase", + "1.1.1.314\tGermacrene A alcohol dehydrogenase", + "1.1.1.315\t11-cis-retinol dehydrogenase", + "1.1.1.316\tL-galactose 1-dehydrogenase", + "1.1.1.317\tPerakine reductase", + "1.1.1.318\tEugenol synthase", + "1.1.1.319\tIsoeugenol synthase", + "1.1.1.320\tBenzil reductase ((S)-benzoin forming)", + "1.1.1.321\tBenzil reductase ((R)-benzoin forming)", + "1.1.1.322\t(-)-endo-fenchol dehydrogenase", + "1.1.1.323\t(+)-thujan-3-ol dehydrogenase", + "1.1.1.324\t8-hydroxygeraniol dehydrogenase", + "1.1.1.325\tSepiapterin reductase (L-threo-7,8-dihydrobiopterin forming)", + "1.1.1.326\tZerumbone synthase", + "1.1.1.327\t5-exo-hydroxycamphor dehydrogenase", + "1.1.1.328\tNicotine blue oxidoreductase", + "1.1.1.329\t2-deoxy-scyllo-inosamine dehydrogenase", + "1.1.1.330\tVery-long-chain 3-oxoacyl-CoA reductase", + "1.1.1.331\tSecoisolariciresinol dehydrogenase", + "1.1.1.332\tChanoclavine-I dehydrogenase", + "1.1.1.333\tDecaprenylphospho-beta-D-erythro-pentofuranosid-2-ulose 2-reductase", + "1.1.1.334\tMethylecgonone reductase", + "1.1.1.335\tUDP-N-acetyl-2-amino-2-deoxyglucuronate dehydrogenase", + "1.1.1.336\tUDP-N-acetyl-D-mannosamine dehydrogenase", + "1.1.1.337\tL-2-hydroxycarboxylate dehydrogenase (NAD(+))", + "1.1.1.338\t(2R)-3-sulfolactate dehydrogenase (NADP(+))", + "1.1.1.339\tdTDP-6-deoxy-L-talose 4-dehydrogenase (NAD(+))", + "1.1.1.340\t1-deoxy-11-beta-hydroxypentalenate dehydrogenase", + "1.1.1.341\tCDP-abequose synthase", + "1.1.1.342\tCDP-paratose synthase", + "1.1.1.343\tPhosphogluconate dehydrogenase (NAD(+)-dependent, decarboxylating)", + "1.1.1.344\tdTDP-6-deoxy-L-talose 4-dehydrogenase (NAD(P)(+))", + "1.1.1.345\tD-2-hydroxyacid dehydrogenase (NAD(+))", + "1.1.1.346\t2,5-didehydrogluconate reductase (2-dehydro-L-gulonate-forming)", + "1.1.1.347\tGeraniol dehydrogenase (NAD(+))", + "1.1.1.348\tVestitone reductase", + "1.1.1.349\tNorsolorinic acid ketoreductase", + "1.1.1.350\tUreidoglycolate dehydrogenase (NAD(+))", + "1.1.1.351\tPhosphogluconate dehydrogenase (NAD(P)(+)-dependent, decarboxylating)", + "1.1.1.352\t5'-hydroxyaverantin dehydrogenase", + "1.1.1.353\tVersiconal hemiacetal acetate reductase", + "1.1.1.354\tFarnesol dehydrogenase (NAD(+))", + "1.1.1.355\t2'-dehydrokanamycin reductase", + "1.1.1.356\tGDP-L-colitose synthase", + "1.1.1.357\t3-alpha-hydroxysteroid 3-dehydrogenase", + "1.1.1.358\t2-dehydropantolactone reductase", + "1.1.1.359\tAldose 1-dehydrogenase (NAD(P)(+))", + "1.1.1.360\tGlucose/galactose 1-dehydrogenase", + "1.1.1.361\tGlucose-6-phosphate 3-dehydrogenase", + "1.1.1.362\tAklaviketone reductase", + "1.1.1.363\tGlucose-6-phosphate dehydrogenase (NAD(P)(+))", + "1.1.1.364\tdTDP-4-dehydro-6-deoxy-alpha-D-gulose 4-ketoreductase", + "1.1.1.365\tD-galacturonate reductase", + "1.1.1.366\tL-idonate 5-dehydrogenase (NAD(+))", + "1.1.1.367\tUDP-2-acetamido-2,6-beta-L-arabino-hexul-4-ose reductase", + "1.1.1.368\t6-hydroxycyclohex-1-ene-1-carbonyl-CoA dehydrogenase", + "1.1.1.369\tD-chiro-inositol 1-dehydrogenase", + "1.1.1.370\tScyllo-inositol 2-dehydrogenase (NAD(+))", + "1.1.1.371\tScyllo-inositol 2-dehydrogenase (NADP(+))", + "1.1.1.372\tD/L-glyceraldehyde reductase", + "1.1.1.373\tSulfolactaldehyde 3-reductase", + "1.1.1.374\tUDP-N-acetylglucosamine 3-dehydrogenase", + "1.1.1.375\tL-2-hydroxycarboxylate dehydrogenase (NAD(P)(+))", + "1.1.1.376\tL-arabinose 1-dehydrogenase (NAD(P)(+))", + "1.1.1.377\tL-rhamnose 1-dehydrogenase (NADP(+))", + "1.1.1.378\tL-rhamnose 1-dehydrogenase (NAD(P)(+))", + "1.1.1.379\t(R)-mandelate dehydrogenase", + "1.1.1.380\tL-gulonate 5-dehydrogenase", + "1.1.1.381\t3-hydroxy acid dehydrogenase", + "1.1.1.382\tKetol-acid reductoisomerase (NAD(+))", + "1.1.1.383\tKetol-acid reductoisomerase (NAD(P)(+))", + "1.1.1.384\tdTDP-3,4-didehydro-2,6-dideoxy-alpha-D-glucose 3-reductase", + "1.1.1.385\tDihydroanticapsin 7-dehydrogenase", + "1.1.1.386\tIpsdienol dehydrogenase", + "1.1.1.387\tL-serine 3-dehydrogenase (NAD(+))", + "1.1.1.388\tGlucose-6-phosphate dehydrogenase (NAD(+))", + "1.1.1.389\t2-dehydro-3-deoxy-L-galactonate 5-dehydrogenase", + "1.1.1.390\tSulfoquinovose 1-dehydrogenase", + "1.1.1.391\t3-beta-hydroxycholanate 3-dehydrogenase (NAD(+))", + "1.1.1.392\t3-alpha-hydroxycholanate dehydrogenase (NADP(+))", + "1.1.1.393\t3-beta-hydroxycholanate 3-dehydrogenase (NADP(+))", + "1.1.1.394\tAurachin B dehydrogenase", + "1.1.1.395\t3-alpha-hydroxybile acid CoA 3-dehydrogenase", + "1.1.1.396\tBacteriochlorophyllide-a dehydrogenase", + "1.1.1.397\tBeta-methylindole-3-pyruvate reductase", + "1.1.1.398\t2-glutathionyl-2-methylbut-3-en-1-ol dehydrogenase", + "1.1.1.399\t2-oxoglutarate reductase", + "1.1.1.400\t2-methyl-1,2-propanediol dehydrogenase", + "1.1.1.401\t2-dehydro-3-deoxy-L-rhamnonate dehydrogenase (NAD(+))", + "1.1.1.402\tD-erythritol 1-phosphate dehydrogenase", + "1.1.1.403\tD-threitol dehydrogenase (NAD(+))", + "1.1.1.404\tTetrachlorobenzoquinone reductase", + "1.1.1.405\tRibitol-5-phosphate 2-dehydrogenase (NADP(+))", + "1.1.1.406\tGalactitol 2-dehydrogenase (L-tagatose-forming)", + "1.1.1.407\tD-altritol 5-dehydrogenase", + "1.1.1.n4\t(-)-trans-carveol dehydrogenase", + "1.1.1.n5\t3-methylmalate dehydrogenase", + "1.1.1.n11\tSuccinic semialdehyde reductase", + "1.1.1.n12\t(3R)-hydroxyacyl-CoA dehydrogenase", + "1.1.2.2\tMannitol dehydrogenase (cytochrome)", + "1.1.2.3\tL-lactate dehydrogenase (cytochrome)", + "1.1.2.4\tD-lactate dehydrogenase (cytochrome)", + "1.1.2.5\tD-lactate dehydrogenase (cytochrome c-553)", + "1.1.2.6\tPolyvinyl alcohol dehydrogenase (cytochrome)", + "1.1.2.7\tMethanol dehydrogenase (cytochrome c)", + "1.1.2.8\tAlcohol dehydrogenase (cytochrome c)", + "1.1.2.9\t1-butanol dehydrogenase (cytochrome c)", + "1.1.3.4\tGlucose oxidase", + "1.1.3.5\tHexose oxidase", + "1.1.3.6\tCholesterol oxidase", + "1.1.3.7\tAryl-alcohol oxidase", + "1.1.3.8\tL-gulonolactone oxidase", + "1.1.3.9\tGalactose oxidase", + "1.1.3.10\tPyranose oxidase", + "1.1.3.11\tL-sorbose oxidase", + "1.1.3.12\tPyridoxine 4-oxidase", + "1.1.3.13\tAlcohol oxidase", + "1.1.3.14\tCatechol oxidase (dimerizing)", + "1.1.3.15\t(S)-2-hydroxy-acid oxidase", + "1.1.3.16\tEcdysone oxidase", + "1.1.3.17\tCholine oxidase", + "1.1.3.18\tSecondary-alcohol oxidase", + "1.1.3.19\t4-hydroxymandelate oxidase (decarboxylating)", + "1.1.3.20\tLong-chain-alcohol oxidase", + "1.1.3.21\tGlycerol-3-phosphate oxidase", + "1.1.3.23\tThiamine oxidase", + "1.1.3.27\tHydroxyphytanate oxidase", + "1.1.3.28\tNucleoside oxidase", + "1.1.3.29\tN-acylhexosamine oxidase", + "1.1.3.30\tPolyvinyl-alcohol oxidase", + "1.1.3.37\tD-arabinono-1,4-lactone oxidase", + "1.1.3.38\tVanillyl-alcohol oxidase", + "1.1.3.39\tNucleoside oxidase (H(2)O(2)-forming)", + "1.1.3.40\tD-mannitol oxidase", + "1.1.3.41\tAlditol oxidase", + "1.1.3.42\tProsolanapyrone-II oxidase", + "1.1.3.43\tParomamine 6'-oxidase", + "1.1.3.44\t6'''-hydroxyneomycin C oxidase", + "1.1.3.45\tAclacinomycin-N oxidase", + "1.1.3.46\t4-hydroxymandelate oxidase", + "1.1.3.47\t5-(hydroxymethyl)furfural oxidase", + "1.1.3.48\t3-deoxy-alpha-D-manno-octulosonate 8-oxidase", + "1.1.3.49\t(R)-mandelonitrile oxidase", + "1.1.5.2\tQuinoprotein glucose dehydrogenase (PQQ, quinone)", + "1.1.5.3\tGlycerol-3-phosphate dehydrogenase", + "1.1.5.4\tMalate dehydrogenase (quinone)", + "1.1.5.5\tAlcohol dehydrogenase (quinone)", + "1.1.5.6\tFormate dehydrogenase-N", + "1.1.5.7\tCyclic alcohol dehydrogenase (quinone)", + "1.1.5.8\tQuinate dehydrogenase (quinone)", + "1.1.5.9\tGlucose 1-dehydrogenase (FAD, quinone)", + "1.1.5.10\tD-2-hydroxyacid dehydrogenase (quinone)", + "1.1.5.11\t1-butanol dehydrogenase (quinone)", + "1.1.5.12\tD-lactate dehydrogenase (quinone)", + "1.1.5.n1\tQuinoprotein inositol dehydrogenase", + "1.1.9.1\tAlcohol dehydrogenase (azurin)", + "1.1.98.2\tGlucose-6-phosphate dehydrogenase (coenzyme-F420)", + "1.1.98.3\tDecaprenylphospho-beta-D-ribofuranose 2-dehydrogenase", + "1.1.98.4\tF420H(2):quinone oxidoreductase", + "1.1.98.5\tSecondary-alcohol dehydrogenase (coenzyme-F420)", + "1.1.98.6\tRibonucleoside-triphosphate reductase (formate)", + "1.1.99.1\tCholine dehydrogenase", + "1.1.99.2\tL-2-hydroxyglutarate dehydrogenase", + "1.1.99.3\tGluconate 2-dehydrogenase (acceptor)", + "1.1.99.4\tDehydrogluconate dehydrogenase", + "1.1.99.6\tD-lactate dehydrogenase (acceptor)", + "1.1.99.7\tLactate--malate transhydrogenase", + "1.1.99.9\tPyridoxine 5-dehydrogenase", + "1.1.99.11\tFructose 5-dehydrogenase", + "1.1.99.12\tSorbose dehydrogenase", + "1.1.99.13\tGlucoside 3-dehydrogenase", + "1.1.99.14\tGlycolate dehydrogenase", + "1.1.99.18\tCellobiose dehydrogenase (acceptor)", + "1.1.99.20\tAlkan-1-ol dehydrogenase (acceptor)", + "1.1.99.21\tD-sorbitol dehydrogenase (acceptor)", + "1.1.99.22\tGlycerol dehydrogenase (acceptor)", + "1.1.99.24\tHydroxyacid-oxoacid transhydrogenase", + "1.1.99.26\t3-hydroxycyclohexanone dehydrogenase", + "1.1.99.27\t(R)-pantolactone dehydrogenase (flavin)", + "1.1.99.28\tGlucose-fructose oxidoreductase", + "1.1.99.29\tPyranose dehydrogenase (acceptor)", + "1.1.99.30\t2-oxo-acid reductase", + "1.1.99.31\t(S)-mandelate dehydrogenase", + "1.1.99.32\tL-sorbose 1-dehydrogenase", + "1.1.99.33\tFormate dehydrogenase (acceptor)", + "1.1.99.35\tSoluble quinoprotein glucose dehydrogenase", + "1.1.99.36\tAlcohol dehydrogenase (nicotinoprotein)", + "1.1.99.37\tMethanol dehydrogenase (nicotinoprotein)", + "1.1.99.38\t2-deoxy-scyllo-inosamine dehydrogenase (AdoMet-dependent)", + "1.1.99.39\tD-2-hydroxyglutarate dehydrogenase", + "1.1.99.40\t(R)-2-hydroxyglutarate--pyruvate transhydrogenase", + "1.2.1.2\tFormate dehydrogenase", + "1.2.1.3\tAldehyde dehydrogenase (NAD(+))", + "1.2.1.4\tAldehyde dehydrogenase (NADP(+))", + "1.2.1.5\tAldehyde dehydrogenase (NAD(P)(+))", + "1.2.1.7\tBenzaldehyde dehydrogenase (NADP(+))", + "1.2.1.8\tBetaine-aldehyde dehydrogenase", + "1.2.1.9\tGlyceraldehyde-3-phosphate dehydrogenase (NADP(+))", + "1.2.1.10\tAcetaldehyde dehydrogenase (acetylating)", + "1.2.1.11\tAspartate-semialdehyde dehydrogenase", + "1.2.1.12\tGlyceraldehyde-3-phosphate dehydrogenase (phosphorylating)", + "1.2.1.13\tGlyceraldehyde-3-phosphate dehydrogenase (NADP(+)) (phosphorylating)", + "1.2.1.15\tMalonate-semialdehyde dehydrogenase", + "1.2.1.16\tSuccinate-semialdehyde dehydrogenase (NAD(P)(+))", + "1.2.1.17\tGlyoxylate dehydrogenase (acylating)", + "1.2.1.18\tMalonate-semialdehyde dehydrogenase (acetylating)", + "1.2.1.19\tAminobutyraldehyde dehydrogenase", + "1.2.1.20\tGlutarate-semialdehyde dehydrogenase", + "1.2.1.21\tGlycolaldehyde dehydrogenase", + "1.2.1.22\tLactaldehyde dehydrogenase", + "1.2.1.23\t2-oxoaldehyde dehydrogenase (NAD(+))", + "1.2.1.24\tSuccinate-semialdehyde dehydrogenase (NAD(+))", + "1.2.1.25\t2-oxoisovalerate dehydrogenase (acylating)", + "1.2.1.26\t2,5-dioxovalerate dehydrogenase", + "1.2.1.27\tMethylmalonate-semialdehyde dehydrogenase (CoA acylating)", + "1.2.1.28\tBenzaldehyde dehydrogenase (NAD(+))", + "1.2.1.29\tAryl-aldehyde dehydrogenase", + "1.2.1.30\tAryl-aldehyde dehydrogenase (NADP(+))", + "1.2.1.31\tL-aminoadipate-semialdehyde dehydrogenase", + "1.2.1.32\tAminomuconate-semialdehyde dehydrogenase", + "1.2.1.33\t(R)-dehydropantoate dehydrogenase", + "1.2.1.36\tRetinal dehydrogenase", + "1.2.1.38\tN-acetyl-gamma-glutamyl-phosphate reductase", + "1.2.1.39\tPhenylacetaldehyde dehydrogenase", + "1.2.1.41\tGlutamate-5-semialdehyde dehydrogenase", + "1.2.1.42\tHexadecanal dehydrogenase (acylating)", + "1.2.1.43\tFormate dehydrogenase (NADP(+))", + "1.2.1.44\tCinnamoyl-CoA reductase", + "1.2.1.46\tFormaldehyde dehydrogenase", + "1.2.1.47\t4-trimethylammoniobutyraldehyde dehydrogenase", + "1.2.1.48\tLong-chain-aldehyde dehydrogenase", + "1.2.1.49\t2-oxoaldehyde dehydrogenase (NADP(+))", + "1.2.1.50\tLong-chain-fatty-acyl-CoA reductase", + "1.2.1.51\tPyruvate dehydrogenase (NADP(+))", + "1.2.1.52\tOxoglutarate dehydrogenase (NADP(+))", + "1.2.1.53\t4-hydroxyphenylacetaldehyde dehydrogenase", + "1.2.1.54\tGamma-guanidinobutyraldehyde dehydrogenase", + "1.2.1.57\tButanal dehydrogenase", + "1.2.1.58\tPhenylglyoxylate dehydrogenase (acylating)", + "1.2.1.59\tGlyceraldehyde-3-phosphate dehydrogenase (NAD(P)(+)) (phosphorylating)", + "1.2.1.60\t5-carboxymethyl-2-hydroxymuconic-semialdehyde dehydrogenase", + "1.2.1.61\t4-hydroxymuconic-semialdehyde dehydrogenase", + "1.2.1.62\t4-formylbenzenesulfonate dehydrogenase", + "1.2.1.63\t6-oxohexanoate dehydrogenase", + "1.2.1.64\t4-hydroxybenzaldehyde dehydrogenase (NAD(+))", + "1.2.1.65\tSalicylaldehyde dehydrogenase", + "1.2.1.67\tVanillin dehydrogenase", + "1.2.1.68\tConiferyl-aldehyde dehydrogenase", + "1.2.1.69\tFluoroacetaldehyde dehydrogenase", + "1.2.1.70\tGlutamyl-tRNA reductase", + "1.2.1.71\tSuccinylglutamate-semialdehyde dehydrogenase", + "1.2.1.72\tErythrose-4-phosphate dehydrogenase", + "1.2.1.73\tSulfoacetaldehyde dehydrogenase", + "1.2.1.74\tAbieta-7,13-dien-18-al dehydrogenase", + "1.2.1.75\tMalonyl CoA reductase (malonate semialdehyde-forming)", + "1.2.1.76\tSuccinate-semialdehyde dehydrogenase (acetylating)", + "1.2.1.77\t3,4-dehydroadipyl-CoA semialdehyde dehydrogenase (NADP(+))", + "1.2.1.78\t2-formylbenzoate dehydrogenase", + "1.2.1.79\tSuccinate-semialdehyde dehydrogenase (NADP(+))", + "1.2.1.80\tLong-chain acyl-[acyl-carrier-protein] reductase", + "1.2.1.81\tSulfoacetaldehyde dehydrogenase (acylating)", + "1.2.1.82\tBeta-apo-4'-carotenal oxygenase", + "1.2.1.83\t3-succinoylsemialdehyde-pyridine dehydrogenase", + "1.2.1.84\tAlcohol-forming fatty acyl-CoA reductase", + "1.2.1.85\t2-hydroxymuconate-6-semialdehyde dehydrogenase", + "1.2.1.86\tGeranial dehydrogenase", + "1.2.1.87\tPropanal dehydrogenase (CoA-propanoylating)", + "1.2.1.88\tL-glutamate gamma-semialdehyde dehydrogenase", + "1.2.1.89\tD-glyceraldehyde dehydrogenase (NADP(+))", + "1.2.1.90\tGlyceraldehyde-3-phosphate dehydrogenase (NAD(P)(+))", + "1.2.1.91\t3-oxo-5,6-dehydrosuberyl-CoA semialdehyde dehydrogenase", + "1.2.1.92\t3,6-anhydro-alpha-L-galactose dehydrogenase", + "1.2.1.93\tFormate dehydrogenase (NAD(+), ferredoxin)", + "1.2.1.94\tFarnesal dehydrogenase", + "1.2.1.95\tL-2-aminoadipate reductase", + "1.2.1.96\t4-hydroxybenzaldehyde dehydrogenase (NADP(+))", + "1.2.1.97\t3-sulfolactaldehyde dehydrogenase", + "1.2.1.98\t2-hydroxy-2-methylpropanal dehydrogenase", + "1.2.1.n2\tFatty acyl-CoA reductase", + "1.2.2.1\tFormate dehydrogenase (cytochrome)", + "1.2.2.3\tFormate dehydrogenase (cytochrome c-553)", + "1.2.2.4\tCarbon-monoxide dehydrogenase (cytochrome b-561)", + "1.2.3.1\tAldehyde oxidase", + "1.2.3.3\tPyruvate oxidase", + "1.2.3.4\tOxalate oxidase", + "1.2.3.5\tGlyoxylate oxidase", + "1.2.3.6\tPyruvate oxidase (CoA-acetylating)", + "1.2.3.7\tIndole-3-acetaldehyde oxidase", + "1.2.3.8\tPyridoxal oxidase", + "1.2.3.9\tAryl-aldehyde oxidase", + "1.2.3.13\t4-hydroxyphenylpyruvate oxidase", + "1.2.3.14\tAbscisic-aldehyde oxidase", + "1.2.3.15\t(Methyl)glyoxal oxidase", + "1.2.4.1\tPyruvate dehydrogenase (acetyl-transferring)", + "1.2.4.2\tOxoglutarate dehydrogenase (succinyl-transferring)", + "1.2.4.4\t3-methyl-2-oxobutanoate dehydrogenase (2-methylpropanoyl-transferring)", + "1.2.5.1\tPyruvate dehydrogenase (quinone)", + "1.2.5.2\tAldehyde dehydrogenase (quinone)", + "1.2.5.3\tAerobic carbon monoxide dehydrogenase", + "1.2.7.1\tPyruvate synthase", + "1.2.7.3\t2-oxoglutarate synthase", + "1.2.7.4\tAnaerobic carbon-monoxide dehydrogenase", + "1.2.7.5\tAldehyde ferredoxin oxidoreductase", + "1.2.7.6\tGlyceraldehyde-3-phosphate dehydrogenase (ferredoxin)", + "1.2.7.7\t3-methyl-2-oxobutanoate dehydrogenase (ferredoxin)", + "1.2.7.8\tIndolepyruvate ferredoxin oxidoreductase", + "1.2.7.10\tOxalate oxidoreductase", + "1.2.7.11\t2-oxoacid oxidoreductase (ferredoxin)", + "1.2.98.1\tFormaldehyde dismutase", + "1.2.99.5\tFormylmethanofuran dehydrogenase", + "1.2.99.6\tCarboxylate reductase", + "1.2.99.7\tAldehyde dehydrogenase (FAD-independent)", + "1.2.99.8\tGlyceraldehyde dehydrogenase (FAD-containing)", + "1.2.99.9\tFormate dehydrogenase (coenzyme F420)", + "1.3.1.1\tDihydrouracil dehydrogenase (NAD(+))", + "1.3.1.2\tDihydropyrimidine dehydrogenase (NADP(+))", + "1.3.1.3\tDelta(4)-3-oxosteroid 5-beta-reductase", + "1.3.1.5\tCucurbitacin Delta(23)-reductase", + "1.3.1.6\tFumarate reductase (NADH)", + "1.3.1.7\tMeso-tartrate dehydrogenase", + "1.3.1.8\tAcyl-CoA dehydrogenase (NADP(+))", + "1.3.1.9\tEnoyl-[acyl-carrier-protein] reductase (NADH)", + "1.3.1.10\tEnoyl-[acyl-carrier-protein] reductase (NADPH, Si-specific)", + "1.3.1.11\t2-coumarate reductase", + "1.3.1.12\tPrephenate dehydrogenase", + "1.3.1.13\tPrephenate dehydrogenase (NADP(+))", + "1.3.1.14\tDihydroorotate dehydrogenase (NAD(+))", + "1.3.1.15\tDihydroorotate dehydrogenase (NADP(+))", + "1.3.1.16\tBeta-nitroacrylate reductase", + "1.3.1.17\t3-methyleneoxindole reductase", + "1.3.1.18\tKynurenate-7,8-dihydrodiol dehydrogenase", + "1.3.1.19\tCis-1,2-dihydrobenzene-1,2-diol dehydrogenase", + "1.3.1.20\tTrans-1,2-dihydrobenzene-1,2-diol dehydrogenase", + "1.3.1.21\t7-dehydrocholesterol reductase", + "1.3.1.22\t3-oxo-5-alpha-steroid 4-dehydrogenase (NADP(+))", + "1.3.1.24\tBiliverdin reductase", + "1.3.1.25\t1,6-dihydroxycyclohexa-2,4-diene-1-carboxylate dehydrogenase", + "1.3.1.27\t2-hexadecenal reductase", + "1.3.1.28\t2,3-dihydro-2,3-dihydroxybenzoate dehydrogenase", + "1.3.1.29\tCis-1,2-dihydro-1,2-dihydroxynaphthalene dehydrogenase", + "1.3.1.31\t2-enoate reductase", + "1.3.1.32\tMaleylacetate reductase", + "1.3.1.33\tProtochlorophyllide reductase", + "1.3.1.34\t2,4-dienoyl-CoA reductase (NADPH)", + "1.3.1.36\tGeissoschizine dehydrogenase", + "1.3.1.37\tCis-2-enoyl-CoA reductase (NADPH)", + "1.3.1.38\tTrans-2-enoyl-CoA reductase (NADPH)", + "1.3.1.39\tEnoyl-[acyl-carrier-protein] reductase (NADPH, Re-specific)", + "1.3.1.40\t2-hydroxy-6-oxo-6-phenylhexa-2,4-dienoate reductase", + "1.3.1.41\tXanthommatin reductase", + "1.3.1.42\t12-oxophytodienoate reductase", + "1.3.1.43\tArogenate dehydrogenase", + "1.3.1.44\tTrans-2-enoyl-CoA reductase (NAD(+))", + "1.3.1.45\t2'-hydroxyisoflavone reductase", + "1.3.1.46\tBiochanin-A reductase", + "1.3.1.47\tAlpha-santonin 1,2-reductase", + "1.3.1.48\t15-oxoprostaglandin 13-reductase", + "1.3.1.49\tCis-3,4-dihydrophenanthrene-3,4-diol dehydrogenase", + "1.3.1.51\t2'-hydroxydaidzein reductase", + "1.3.1.53\t(3S,4R)-3,4-dihydroxycyclohexa-1,5-diene-1,4-dicarboxylate dehydrogenase", + "1.3.1.54\tPrecorrin-6A reductase", + "1.3.1.56\tCis-2,3-dihydrobiphenyl-2,3-diol dehydrogenase", + "1.3.1.57\tPhloroglucinol reductase", + "1.3.1.58\t2,3-dihydroxy-2,3-dihydro-p-cumate dehydrogenase", + "1.3.1.60\tDibenzothiophene dihydrodiol dehydrogenase", + "1.3.1.62\tPimeloyl-CoA dehydrogenase", + "1.3.1.64\tPhthalate 4,5-cis-dihydrodiol dehydrogenase", + "1.3.1.65\t5,6-dihydroxy-3-methyl-2-oxo-1,2,5,6-tetrahydroquinoline dehydrogenase", + "1.3.1.66\tCis-dihydroethylcatechol dehydrogenase", + "1.3.1.67\tCis-1,2-dihydroxy-4-methylcyclohexa-3,5-diene-1-carboxylate dehydrogenase", + "1.3.1.68\t1,2-dihydroxy-6-methylcyclohexa-3,5-dienecarboxylate dehydrogenase", + "1.3.1.69\tZeatin reductase", + "1.3.1.70\tDelta(14)-sterol reductase", + "1.3.1.71\tDelta(24(24(1)))-sterol reductase", + "1.3.1.72\tDelta(24)-sterol reductase", + "1.3.1.73\t1,2-dihydrovomilenine reductase", + "1.3.1.74\t2-alkenal reductase (NAD(P)(+))", + "1.3.1.75\t3,8-divinyl protochlorophyllide a 8-vinyl-reductase (NADPH)", + "1.3.1.76\tPrecorrin-2 dehydrogenase", + "1.3.1.77\tAnthocyanidin reductase ((2R,3R)-flavan-3-ol-forming)", + "1.3.1.78\tArogenate dehydrogenase (NADP(+))", + "1.3.1.79\tArogenate dehydrogenase (NAD(P)(+))", + "1.3.1.81\t(+)-pulegone reductase", + "1.3.1.82\t(-)-isopiperitenone reductase", + "1.3.1.83\tGeranylgeranyl diphosphate reductase", + "1.3.1.84\tAcrylyl-CoA reductase (NADPH)", + "1.3.1.85\tCrotonyl-CoA carboxylase/reductase", + "1.3.1.86\tCrotonyl-CoA reductase", + "1.3.1.87\t3-(cis-5,6-dihydroxycyclohexa-1,3-dien-1-yl)propanoate dehydrogenase", + "1.3.1.88\ttRNA-dihydrouridine(16/17) synthase (NAD(P)(+))", + "1.3.1.89\ttRNA-dihydrouridine(47) synthase (NAD(P)(+))", + "1.3.1.90\ttRNA-dihydrouridine(20a/20b) synthase (NAD(P)(+))", + "1.3.1.91\ttRNA-dihydrouridine(20) synthase (NAD(P)(+))", + "1.3.1.92\tArtemisinic aldehyde Delta(11(13)) reductase", + "1.3.1.93\tVery-long-chain enoyl-CoA reductase", + "1.3.1.94\tPolyprenol reductase", + "1.3.1.95\tAcryloyl-CoA reductase (NADH)", + "1.3.1.96\tBotryococcus squalene synthase", + "1.3.1.97\tBotryococcene synthase", + "1.3.1.98\tUDP-N-acetylmuramate dehydrogenase", + "1.3.1.99\tIridoid synthase", + "1.3.1.100\tChanoclavine-I aldehyde reductase", + "1.3.1.101\t2,3-bis-O-geranylgeranyl-sn-glycerol 1-phosphate reductase (NAD(P)H)", + "1.3.1.102\t2-alkenal reductase (NADP(+))", + "1.3.1.103\t2-haloacrylate reductase", + "1.3.1.104\tEnoyl-[acyl-carrier-protein] reductase", + "1.3.1.105\t2-methylene-furan-3-one reductase", + "1.3.1.106\tCobalt-precorrin-6A reductase", + "1.3.1.107\tSanguinarine reductase", + "1.3.1.108\tCaffeoyl-CoA reductase", + "1.3.1.109\tButanoyl-CoA dehydrogenase (NAD(+),ferredoxin)", + "1.3.1.110\tLactate dehydrogenase (NAD(+),ferredoxin)", + "1.3.1.111\tGeranylgeranyl-bacteriochlorophyllide a reductase", + "1.3.1.112\tAnthocyanidin reductase ((2S)-flavan-3-ol-forming)", + "1.3.1.n2\tCamalexin synthase", + "1.3.1.n3\tCurcumin reductase", + "1.3.2.3\tL-galactonolactone dehydrogenase", + "1.3.3.3\tCoproporphyrinogen oxidase", + "1.3.3.4\tProtoporphyrinogen oxidase", + "1.3.3.5\tBilirubin oxidase", + "1.3.3.6\tAcyl-CoA oxidase", + "1.3.3.7\tDihydrouracil oxidase", + "1.3.3.8\tTetrahydroberberine oxidase", + "1.3.3.9\tSecologanin synthase", + "1.3.3.10\tTryptophan alpha,beta-oxidase", + "1.3.3.11\tPyrroloquinoline-quinone synthase", + "1.3.3.12\tL-galactonolactone oxidase", + "1.3.3.13\tAlbonoursin synthase", + "1.3.3.14\tAclacinomycin-A oxidase", + "1.3.3.15\tCoproporphyrinogen III oxidase (coproporphyrin-forming)", + "1.3.4.1\tFumarate reductase (CoM/CoB)", + "1.3.5.1\tSuccinate dehydrogenase (quinone)", + "1.3.5.2\tDihydroorotate dehydrogenase (quinone)", + "1.3.5.3\tProtoporphyrinogen IX dehydrogenase (menaquinone)", + "1.3.5.4\tFumarate reductase (quinol)", + "1.3.5.5\t15-cis-phytoene desaturase", + "1.3.5.6\t9,9'-di-cis-zeta-carotene desaturase", + "1.3.7.1\t6-hydroxynicotinate reductase", + "1.3.7.2\t15,16-dihydrobiliverdin:ferredoxin oxidoreductase", + "1.3.7.3\tPhycoerythrobilin:ferredoxin oxidoreductase", + "1.3.7.4\tPhytochromobilin:ferredoxin oxidoreductase", + "1.3.7.5\tPhycocyanobilin:ferredoxin oxidoreductase", + "1.3.7.6\tPhycoerythrobilin synthase", + "1.3.7.7\tFerredoxin:protochlorophyllide reductase (ATP-dependent)", + "1.3.7.8\tBenzoyl-CoA reductase", + "1.3.7.9\t4-hydroxybenzoyl-CoA reductase", + "1.3.7.11\t2,3-bis-O-geranylgeranyl-sn-glycero-phospholipid reductase", + "1.3.7.12\tRed chlorophyll catabolite reductase", + "1.3.7.13\t3,8-divinyl protochlorophyllide a 8-vinyl-reductase (ferredoxin)", + "1.3.7.14\t3,8-divinyl chlorophyllide a reductase", + "1.3.7.15\tChlorophyllide a reductase", + "1.3.8.1\tShort-chain acyl-CoA dehydrogenase", + "1.3.8.2\t4,4'-diapophytoene desaturase (4,4'-diapolycopene-forming)", + "1.3.8.3\t(R)-benzylsuccinyl-CoA dehydrogenase", + "1.3.8.4\tIsovaleryl-CoA dehydrogenase", + "1.3.8.5\t2-methyl-branched-chain-enoyl-CoA reductase", + "1.3.8.6\tGlutaryl-CoA dehydrogenase (ETF)", + "1.3.8.7\tMedium-chain acyl-CoA dehydrogenase", + "1.3.8.8\tLong-chain-acyl-CoA dehydrogenase", + "1.3.8.9\tVery-long-chain acyl-CoA dehydrogenase", + "1.3.8.10\tCyclohex-1-ene-1-carbonyl-CoA dehydrogenase", + "1.3.8.11\tCyclohexane-1-carbonyl-CoA dehydrogenase", + "1.3.8.12\t(2S)-methylsuccinyl-CoA dehydrogenase", + "1.3.8.13\tCrotonobetainyl-CoA reductase", + "1.3.98.1\tDihydroorotate oxidase (fumarate)", + "1.3.98.3\tCoproporphyrinogen dehydrogenase", + "1.3.98.4\t5a,11a-dehydrotetracycline reductase", + "1.3.99.4\t3-oxosteroid 1-dehydrogenase", + "1.3.99.5\t3-oxo-5-alpha-steroid 4-dehydrogenase (acceptor)", + "1.3.99.6\t3-oxo-5-beta-steroid 4-dehydrogenase", + "1.3.99.8\t2-furoyl-CoA dehydrogenase", + "1.3.99.12\t2-methylacyl-CoA dehydrogenase", + "1.3.99.14\tCyclohexanone dehydrogenase", + "1.3.99.16\tIsoquinoline 1-oxidoreductase", + "1.3.99.17\tQuinoline 2-oxidoreductase", + "1.3.99.18\tQuinaldate 4-oxidoreductase", + "1.3.99.19\tQuinoline-4-carboxylate 2-oxidoreductase", + "1.3.99.23\tAll-trans-retinol 13,14-reductase", + "1.3.99.24\t2-amino-4-deoxychorismate dehydrogenase", + "1.3.99.25\tCarvone reductase", + "1.3.99.26\tAll-trans-zeta-carotene desaturase", + "1.3.99.27\t1-hydroxycarotenoid 3,4-desaturase", + "1.3.99.28\tPhytoene desaturase (neurosporene-forming)", + "1.3.99.29\tPhytoene desaturase (zeta-carotene-forming)", + "1.3.99.30\tPhytoene desaturase (3,4-didehydrolycopene-forming)", + "1.3.99.31\tPhytoene desaturase (lycopene-forming)", + "1.3.99.32\tGlutaryl-CoA dehydrogenase (acceptor)", + "1.3.99.33\tUrocanate reductase", + "1.3.99.36\tCypemycin cysteine dehydrogenase (decarboxylating)", + "1.3.99.37\t1-hydroxy-2-isopentenylcarotenoid 3,4-desaturase", + "1.3.99.38\tMenaquinone-9-beta-reductase", + "1.3.99.n1\t3-hydroxybenzoyl-CoA reductase", + "1.4.1.1\tAlanine dehydrogenase", + "1.4.1.2\tGlutamate dehydrogenase", + "1.4.1.3\tGlutamate dehydrogenase (NAD(P)(+))", + "1.4.1.4\tGlutamate dehydrogenase (NADP(+))", + "1.4.1.5\tL-amino-acid dehydrogenase", + "1.4.1.7\tSerine 2-dehydrogenase", + "1.4.1.8\tValine dehydrogenase (NADP(+))", + "1.4.1.9\tLeucine dehydrogenase", + "1.4.1.10\tGlycine dehydrogenase", + "1.4.1.11\tL-erythro-3,5-diaminohexanoate dehydrogenase", + "1.4.1.12\t2,4-diaminopentanoate dehydrogenase", + "1.4.1.13\tGlutamate synthase (NADPH)", + "1.4.1.14\tGlutamate synthase (NADH)", + "1.4.1.15\tLysine dehydrogenase", + "1.4.1.16\tDiaminopimelate dehydrogenase", + "1.4.1.17\tN-methylalanine dehydrogenase", + "1.4.1.18\tLysine 6-dehydrogenase", + "1.4.1.19\tTryptophan dehydrogenase", + "1.4.1.20\tPhenylalanine dehydrogenase", + "1.4.1.21\tAspartate dehydrogenase", + "1.4.1.23\tValine dehydrogenase (NAD(+))", + "1.4.1.24\t3-dehydroquinate synthase II", + "1.4.1.25\tL-arginine dehydrogenase", + "1.4.1.26\t2,4-diaminopentanoate dehydrogenase (NAD(+))", + "1.4.2.1\tGlycine dehydrogenase (cytochrome)", + "1.4.3.1\tD-aspartate oxidase", + "1.4.3.2\tL-amino-acid oxidase", + "1.4.3.3\tD-amino-acid oxidase", + "1.4.3.4\tMonoamine oxidase", + "1.4.3.5\tPyridoxal 5'-phosphate synthase", + "1.4.3.7\tD-glutamate oxidase", + "1.4.3.8\tEthanolamine oxidase", + "1.4.3.10\tPutrescine oxidase", + "1.4.3.11\tL-glutamate oxidase", + "1.4.3.12\tCyclohexylamine oxidase", + "1.4.3.13\tProtein-lysine 6-oxidase", + "1.4.3.14\tL-lysine oxidase", + "1.4.3.15\tD-glutamate(D-aspartate) oxidase", + "1.4.3.16\tL-aspartate oxidase", + "1.4.3.19\tGlycine oxidase", + "1.4.3.20\tL-lysine 6-oxidase", + "1.4.3.21\tPrimary-amine oxidase", + "1.4.3.22\tDiamine oxidase", + "1.4.3.23\t7-chloro-L-tryptophan oxidase", + "1.4.3.24\tPseudooxynicotine oxidase", + "1.4.3.25\tL-arginine oxidase", + "1.4.4.2\tGlycine dehydrogenase (aminomethyl-transferring)", + "1.4.5.1\tD-amino acid dehydrogenase (quinone)", + "1.4.7.1\tGlutamate synthase (ferredoxin)", + "1.4.9.1\tMethylamine dehydrogenase (amicyanin)", + "1.4.9.2\tAralkylamine dehydrogenase (azurin)", + "1.4.99.2\tTaurine dehydrogenase", + "1.4.99.5\tGlycine dehydrogenase (cyanide-forming)", + "1.4.99.6\tD-arginine dehydrogenase", + "1.5.1.1\t1-piperideine-2-carboxylate/1-pyrroline-2-carboxylate reductase (NAD(P)H)", + "1.5.1.2\tPyrroline-5-carboxylate reductase", + "1.5.1.3\tDihydrofolate reductase", + "1.5.1.5\tMethylenetetrahydrofolate dehydrogenase (NADP(+))", + "1.5.1.6\tFormyltetrahydrofolate dehydrogenase", + "1.5.1.7\tSaccharopine dehydrogenase (NAD(+), L-lysine-forming)", + "1.5.1.8\tSaccharopine dehydrogenase (NADP(+), L-lysine-forming)", + "1.5.1.9\tSaccharopine dehydrogenase (NAD(+), L-glutamate-forming)", + "1.5.1.10\tSaccharopine dehydrogenase (NADP(+), L-glutamate-forming)", + "1.5.1.11\tD-octopine dehydrogenase", + "1.5.1.15\tMethylenetetrahydrofolate dehydrogenase (NAD(+))", + "1.5.1.16\tD-lysopine dehydrogenase", + "1.5.1.17\tAlanopine dehydrogenase", + "1.5.1.18\tEphedrine dehydrogenase", + "1.5.1.19\tD-nopaline dehydrogenase", + "1.5.1.20\tMethylenetetrahydrofolate reductase (NAD(P)H)", + "1.5.1.21\t1-piperideine-2-carboxylate/1-pyrroline-2-carboxylate reductase (NADPH)", + "1.5.1.22\tStrombine dehydrogenase", + "1.5.1.23\tTauropine dehydrogenase", + "1.5.1.24\tN(5)-(carboxyethyl)ornithine synthase", + "1.5.1.25\tThiomorpholine-carboxylate dehydrogenase", + "1.5.1.26\tBeta-alanopine dehydrogenase", + "1.5.1.27\t1,2-dehydroreticulinium reductase (NADPH)", + "1.5.1.28\tOpine dehydrogenase", + "1.5.1.30\tFlavin reductase (NADPH)", + "1.5.1.31\tBerberine reductase", + "1.5.1.32\tVomilenine reductase", + "1.5.1.33\tPteridine reductase", + "1.5.1.34\t6,7-dihydropteridine reductase", + "1.5.1.36\tFlavin reductase (NADH)", + "1.5.1.37\tFAD reductase (NADH)", + "1.5.1.38\tFMN reductase (NADPH)", + "1.5.1.39\tFMN reductase (NAD(P)H)", + "1.5.1.40\t8-hydroxy-5-deazaflavin:NADPH oxidoreductase", + "1.5.1.41\tRiboflavin reductase (NAD(P)H)", + "1.5.1.42\tFMN reductase (NADH)", + "1.5.1.43\tCarboxynorspermidine synthase", + "1.5.1.44\tFestuclavine dehydrogenase", + "1.5.1.45\tFAD reductase (NAD(P)H)", + "1.5.1.46\tAgroclavine dehydrogenase", + "1.5.1.47\tDihydromethanopterin reductase (NAD(P)(+))", + "1.5.1.48\t2-methyl-1-pyrroline reductase", + "1.5.1.49\t1-pyrroline-2-carboxylate reductase (NAD(P)H)", + "1.5.1.50\tDihydromonapterin reductase", + "1.5.1.51\tN-((2S)-2-amino-2-carboxyethyl)-L-glutamate dehydrogenase", + "1.5.3.1\tSarcosine oxidase", + "1.5.3.2\tN-methyl-L-amino-acid oxidase", + "1.5.3.4\tN(6)-methyl-lysine oxidase", + "1.5.3.5\t(S)-6-hydroxynicotine oxidase", + "1.5.3.6\t(R)-6-hydroxynicotine oxidase", + "1.5.3.7\tL-pipecolate oxidase", + "1.5.3.10\tDimethylglycine oxidase", + "1.5.3.12\tDihydrobenzophenanthridine oxidase", + "1.5.3.13\tN(1)-acetylpolyamine oxidase", + "1.5.3.14\tPolyamine oxidase (propane-1,3-diamine-forming)", + "1.5.3.15\tN(8)-acetylspermidine oxidase (propane-1,3-diamine-forming)", + "1.5.3.16\tSpermine oxidase", + "1.5.3.17\tNon-specific polyamine oxidase", + "1.5.3.18\tL-saccharopine oxidase", + "1.5.3.19\t4-methylaminobutanoate oxidase (formaldehyde-forming)", + "1.5.3.20\tN-alkylglycine oxidase", + "1.5.3.21\t4-methylaminobutanoate oxidase (methylamine-forming)", + "1.5.3.22\tCoenzyme F420H(2) oxidase", + "1.5.3.23\tGlyphosate oxidoreductase", + "1.5.4.1\tPyrimidodiazepine synthase", + "1.5.5.1\tElectron-transferring-flavoprotein dehydrogenase", + "1.5.5.2\tProline dehydrogenase", + "1.5.7.1\tMethylenetetrahydrofolate reductase (ferredoxin)", + "1.5.7.2\tCoenzyme F420 oxidoreductase (ferredoxin)", + "1.5.8.1\tDimethylamine dehydrogenase", + "1.5.8.2\tTrimethylamine dehydrogenase", + "1.5.8.3\tSarcosine dehydrogenase", + "1.5.8.4\tDimethylglycine dehydrogenase", + "1.5.98.1\tMethylenetetrahydromethanopterin dehydrogenase", + "1.5.98.2\t5,10-methylenetetrahydromethanopterin reductase", + "1.5.99.3\tL-pipecolate dehydrogenase", + "1.5.99.4\tNicotine dehydrogenase", + "1.5.99.5\tMethylglutamate dehydrogenase", + "1.5.99.6\tSpermidine dehydrogenase", + "1.5.99.12\tCytokinin dehydrogenase", + "1.5.99.13\tD-proline dehydrogenase", + "1.5.99.14\t6-hydroxypseudooxynicotine dehydrogenase", + "1.5.99.15\tDihydromethanopterin reductase (acceptor)", + "1.6.1.1\tNAD(P)(+) transhydrogenase (Si-specific)", + "1.6.1.2\tNAD(P)(+) transhydrogenase (Re/Si-specific)", + "1.6.1.3\tNAD(P)(+) transhydrogenase", + "1.6.1.4\tNAD(P)(+) transhydrogenase (ferredoxin)", + "1.6.1.5\tProton-translocating NAD(P)(+) transhydrogenase", + "1.6.2.2\tCytochrome-b5 reductase", + "1.6.2.4\tNADPH--hemoprotein reductase", + "1.6.2.5\tNADPH--cytochrome-c2 reductase", + "1.6.2.6\tLeghemoglobin reductase", + "1.6.3.1\tNAD(P)H oxidase (H(2)O(2)-forming)", + "1.6.3.2\tNAD(P)H oxidase (H(2)O-forming)", + "1.6.3.3\tNADH oxidase (H(2)O(2)-forming)", + "1.6.3.4\tNADH oxidase (H(2)O-forming)", + "1.6.3.5\tRenalase", + "1.6.5.2\tNAD(P)H dehydrogenase (quinone)", + "1.6.5.3\tNADH:ubiquinone reductase (H(+)-translocating)", + "1.6.5.4\tMonodehydroascorbate reductase (NADH)", + "1.6.5.5\tNADPH:quinone reductase", + "1.6.5.6\tp-benzoquinone reductase (NADPH)", + "1.6.5.7\t2-hydroxy-1,4-benzoquinone reductase", + "1.6.5.8\tNADH:ubiquinone reductase (Na(+)-transporting)", + "1.6.5.9\tNADH:ubiquinone reductase (non-electrogenic)", + "1.6.5.10\tNADPH dehydrogenase (quinone)", + "1.6.5.11\tNADH dehydrogenase (quinone)", + "1.6.5.12\tDemethylphylloquinone reductase", + "1.6.6.9\tTrimethylamine-N-oxide reductase", + "1.6.99.1\tNADPH dehydrogenase", + "1.6.99.3\tNADH dehydrogenase", + "1.6.99.n1\tNADPH dehydrogenase (coenzyme F420 dependent)", + "1.7.1.1\tNitrate reductase (NADH)", + "1.7.1.2\tNitrate reductase (NAD(P)H)", + "1.7.1.3\tNitrate reductase (NADPH)", + "1.7.1.4\tNitrite reductase (NAD(P)H)", + "1.7.1.5\tHyponitrite reductase", + "1.7.1.6\tAzobenzene reductase", + "1.7.1.7\tGMP reductase", + "1.7.1.9\tNitroquinoline-N-oxide reductase", + "1.7.1.10\tHydroxylamine reductase (NADH)", + "1.7.1.11\t4-(dimethylamino)phenylazoxybenzene reductase", + "1.7.1.12\tN-hydroxy-2-acetamidofluorene reductase", + "1.7.1.13\tPreQ(1) synthase", + "1.7.1.14\tNitric oxide reductase (NAD(P)(+), nitrous oxide-forming)", + "1.7.1.15\tNitrite reductase (NADH)", + "1.7.2.1\tNitrite reductase (NO-forming)", + "1.7.2.2\tNitrite reductase (cytochrome; ammonia-forming)", + "1.7.2.3\tTrimethylamine-N-oxide reductase (cytochrome c)", + "1.7.2.4\tNitrous-oxide reductase", + "1.7.2.5\tNitric-oxide reductase (cytochrome c)", + "1.7.2.6\tHydroxylamine dehydrogenase", + "1.7.2.7\tHydrazine synthase", + "1.7.2.8\tHydrazine dehydrogenase", + "1.7.3.1\tNitroalkane oxidase", + "1.7.3.2\tAcetylindoxyl oxidase", + "1.7.3.3\tFactor independent urate hydroxylase", + "1.7.3.5\t3-aci-nitropropanoate oxidase", + "1.7.3.6\tHydroxylamine oxidase (cytochrome)", + "1.7.5.1\tNitrate reductase (quinone)", + "1.7.5.2\tNitric oxide reductase (menaquinol)", + "1.7.6.1\tNitrite dismutase", + "1.7.7.1\tFerredoxin--nitrite reductase", + "1.7.7.2\tFerredoxin--nitrate reductase", + "1.7.99.1\tHydroxylamine reductase", + "1.7.99.4\tNitrate reductase", + "1.8.1.2\tAssimilatory sulfite reductase (NADPH)", + "1.8.1.3\tHypotaurine dehydrogenase", + "1.8.1.4\tDihydrolipoyl dehydrogenase", + "1.8.1.5\t2-oxopropyl-CoM reductase (carboxylating)", + "1.8.1.6\tCystine reductase", + "1.8.1.7\tGlutathione-disulfide reductase", + "1.8.1.8\tProtein-disulfide reductase", + "1.8.1.9\tThioredoxin-disulfide reductase", + "1.8.1.10\tCoA-glutathione reductase", + "1.8.1.11\tAsparagusate reductase", + "1.8.1.12\tTrypanothione-disulfide reductase", + "1.8.1.13\tBis-gamma-glutamylcystine reductase", + "1.8.1.14\tCoA-disulfide reductase", + "1.8.1.15\tMycothione reductase", + "1.8.1.16\tGlutathione amide reductase", + "1.8.1.17\tDimethylsulfone reductase", + "1.8.1.18\tNAD(P)H sulfur oxidoreductase (CoA-dependent)", + "1.8.1.19\tSulfide dehydrogenase", + "1.8.2.1\tSulfite dehydrogenase (cytochrome)", + "1.8.2.2\tThiosulfate dehydrogenase", + "1.8.2.3\tSulfide-cytochrome-c reductase (flavocytochrome c)", + "1.8.2.4\tDimethyl sulfide:cytochrome c2 reductase", + "1.8.2.5\tThiosulfate reductase (cytochrome)", + "1.8.3.1\tSulfite oxidase", + "1.8.3.2\tThiol oxidase", + "1.8.3.3\tGlutathione oxidase", + "1.8.3.4\tMethanethiol oxidase", + "1.8.3.5\tPrenylcysteine oxidase", + "1.8.3.6\tFarnesylcysteine lyase", + "1.8.4.1\tGlutathione--homocystine transhydrogenase", + "1.8.4.2\tProtein-disulfide reductase (glutathione)", + "1.8.4.3\tGlutathione--CoA-glutathione transhydrogenase", + "1.8.4.4\tGlutathione--cystine transhydrogenase", + "1.8.4.7\tEnzyme-thiol transhydrogenase (glutathione-disulfide)", + "1.8.4.8\tPhosphoadenylyl-sulfate reductase (thioredoxin)", + "1.8.4.9\tAdenylyl-sulfate reductase (glutathione)", + "1.8.4.10\tAdenylyl-sulfate reductase (thioredoxin)", + "1.8.4.11\tPeptide-methionine (S)-S-oxide reductase", + "1.8.4.12\tPeptide-methionine (R)-S-oxide reductase", + "1.8.4.13\tL-methionine (S)-S-oxide reductase", + "1.8.4.14\tL-methionine (R)-S-oxide reductase", + "1.8.5.1\tGlutathione dehydrogenase (ascorbate)", + "1.8.5.2\tThiosulfate dehydrogenase (quinone)", + "1.8.5.3\tDimethylsulfoxide reductase", + "1.8.5.4\tSulfide:quinone reductase", + "1.8.5.5\tThiosulfate reductase (quinone)", + "1.8.5.6\tSulfite dehydrogenase (quinone)", + "1.8.5.7\tGlutathionyl-hydroquinone reductase", + "1.8.7.1\tAssimilatory sulfite reductase (ferredoxin)", + "1.8.7.2\tFerredoxin:thioredoxin reductase", + "1.8.98.1\tCoB--CoM heterodisulfide reductase", + "1.8.98.2\tSulfiredoxin", + "1.8.98.3\tSulfite reductase (coenzyme F420)", + "1.8.99.2\tAdenylyl-sulfate reductase", + "1.8.99.5\tDissimilatory sulfite reductase", + "1.9.3.1\tCytochrome-c oxidase", + "1.9.6.1\tNitrate reductase (cytochrome)", + "1.9.98.1\tIron--cytochrome-c reductase", + "1.10.1.1\tTrans-acenaphthene-1,2-diol dehydrogenase", + "1.10.2.1\tL-ascorbate--cytochrome-b5 reductase", + "1.10.2.2\tQuinol--cytochrome-c reductase", + "1.10.3.1\tCatechol oxidase", + "1.10.3.2\tLaccase", + "1.10.3.3\tL-ascorbate oxidase", + "1.10.3.4\to-aminophenol oxidase", + "1.10.3.5\t3-hydroxyanthranilate oxidase", + "1.10.3.6\tRifamycin-B oxidase", + "1.10.3.9\tPhotosystem II", + "1.10.3.10\tUbiquinol oxidase (H(+)-transporting)", + "1.10.3.11\tUbiquinol oxidase (non-electrogenic)", + "1.10.3.12\tMenaquinol oxidase (H(+)-transporting)", + "1.10.3.13\tCaldariellaquinol oxidase (H(+)-transporting)", + "1.10.3.14\tUbiquinol oxidase (electrogenic, non H(+)-transporting)", + "1.10.3.15\tGrixazone synthase", + "1.10.3.16\tDihydrophenazinedicarboxylate synthase", + "1.10.5.1\tRibosyldihydronicotinamide dehydrogenase (quinone)", + "1.10.9.1\tPlastoquinol--plastocyanin reductase", + "1.11.1.1\tNADH peroxidase", + "1.11.1.2\tNADPH peroxidase", + "1.11.1.3\tFatty-acid peroxidase", + "1.11.1.5\tCytochrome-c peroxidase", + "1.11.1.6\tCatalase", + "1.11.1.7\tPeroxidase", + "1.11.1.8\tIodide peroxidase", + "1.11.1.9\tGlutathione peroxidase", + "1.11.1.10\tChloride peroxidase", + "1.11.1.11\tL-ascorbate peroxidase", + "1.11.1.12\tPhospholipid-hydroperoxide glutathione peroxidase", + "1.11.1.13\tManganese peroxidase", + "1.11.1.14\tLignin peroxidase", + "1.11.1.15\tPeroxiredoxin", + "1.11.1.16\tVersatile peroxidase", + "1.11.1.17\tGlutathione amide-dependent peroxidase", + "1.11.1.18\tBromide peroxidase", + "1.11.1.19\tDye decolorizing peroxidase", + "1.11.1.20\tProstamide/prostaglandin F(2-alpha) synthase", + "1.11.1.21\tCatalase peroxidase", + "1.11.1.22\tHydroperoxy fatty acid reductase", + "1.11.1.23\t(S)-2-hydroxypropylphosphonic acid epoxidase", + "1.11.2.1\tUnspecific peroxygenase", + "1.11.2.2\tMyeloperoxidase", + "1.11.2.3\tPlant seed peroxygenase", + "1.11.2.4\tFatty-acid peroxygenase", + "1.11.2.5\t3-methyl-L-tyrosine peroxygenase", + "1.12.1.2\tHydrogen dehydrogenase", + "1.12.1.3\tHydrogen dehydrogenase (NADP(+))", + "1.12.1.4\tHydrogenase (NAD(+), ferredoxin)", + "1.12.1.5\tHydrogen dehydrogenase (NAD(P)(+))", + "1.12.2.1\tCytochrome-c3 hydrogenase", + "1.12.5.1\tHydrogen:quinone oxidoreductase", + "1.12.7.2\tFerredoxin hydrogenase", + "1.12.98.1\tCoenzyme F420 hydrogenase", + "1.12.98.2\t5,10-methenyltetrahydromethanopterin hydrogenase", + "1.12.98.3\tMethanosarcina-phenazine hydrogenase", + "1.12.98.4\tSulfhydrogenase", + "1.12.99.6\tHydrogenase (acceptor)", + "1.13.11.1\tCatechol 1,2-dioxygenase", + "1.13.11.2\tCatechol 2,3-dioxygenase", + "1.13.11.3\tProtocatechuate 3,4-dioxygenase", + "1.13.11.4\tGentisate 1,2-dioxygenase", + "1.13.11.5\tHomogentisate 1,2-dioxygenase", + "1.13.11.6\t3-hydroxyanthranilate 3,4-dioxygenase", + "1.13.11.8\tProtocatechuate 4,5-dioxygenase", + "1.13.11.9\t2,5-dihydroxypyridine 5,6-dioxygenase", + "1.13.11.10\t7,8-dihydroxykynurenate 8,8a-dioxygenase", + "1.13.11.11\tTryptophan 2,3-dioxygenase", + "1.13.11.12\tLinoleate 13S-lipoxygenase", + "1.13.11.14\t2,3-dihydroxybenzoate 3,4-dioxygenase", + "1.13.11.15\t3,4-dihydroxyphenylacetate 2,3-dioxygenase", + "1.13.11.16\t3-carboxyethylcatechol 2,3-dioxygenase", + "1.13.11.17\tIndole 2,3-dioxygenase", + "1.13.11.18\tPersulfide dioxygenase", + "1.13.11.19\tCysteamine dioxygenase", + "1.13.11.20\tCysteine dioxygenase", + "1.13.11.22\tCaffeate 3,4-dioxygenase", + "1.13.11.23\t2,3-dihydroxyindole 2,3-dioxygenase", + "1.13.11.24\tQuercetin 2,3-dioxygenase", + "1.13.11.25\t3,4-dihydroxy-9,10-secoandrosta-1,3,5(10)-triene-9,17-dione 4,5-dioxygenase", + "1.13.11.26\tPeptide-tryptophan 2,3-dioxygenase", + "1.13.11.27\t4-hydroxyphenylpyruvate dioxygenase", + "1.13.11.28\t2,3-dihydroxybenzoate 2,3-dioxygenase", + "1.13.11.29\tStizolobate synthase", + "1.13.11.30\tStizolobinate synthase", + "1.13.11.31\tArachidonate 12-lipoxygenase", + "1.13.11.33\tArachidonate 15-lipoxygenase", + "1.13.11.34\tArachidonate 5-lipoxygenase", + "1.13.11.35\tPyrogallol 1,2-oxygenase", + "1.13.11.36\tChloridazon-catechol dioxygenase", + "1.13.11.37\tHydroxyquinol 1,2-dioxygenase", + "1.13.11.38\t1-hydroxy-2-naphthoate 1,2-dioxygenase", + "1.13.11.39\tBiphenyl-2,3-diol 1,2-dioxygenase", + "1.13.11.40\tArachidonate 8-lipoxygenase", + "1.13.11.41\t2,4'-dihydroxyacetophenone dioxygenase", + "1.13.11.43\tLignostilbene alpha-beta-dioxygenase", + "1.13.11.45\tLinoleate 11-lipoxygenase", + "1.13.11.46\t4-hydroxymandelate synthase", + "1.13.11.47\t3-hydroxy-4-oxoquinoline 2,4-dioxygenase", + "1.13.11.48\t3-hydroxy-2-methylquinolin-4-one 2,4-dioxygenase", + "1.13.11.49\tChlorite O(2)-lyase", + "1.13.11.50\tAcetylacetone-cleaving enzyme", + "1.13.11.51\t9-cis-epoxycarotenoid dioxygenase", + "1.13.11.52\tIndoleamine 2,3-dioxygenase", + "1.13.11.53\tAcireductone dioxygenase (Ni(2+)-requiring)", + "1.13.11.54\tAcireductone dioxygenase (Fe(2+)-requiring)", + "1.13.11.55\tSulfur oxygenase/reductase", + "1.13.11.56\t1,2-dihydroxynaphthalene dioxygenase", + "1.13.11.57\tGallate dioxygenase", + "1.13.11.58\tLinoleate 9S-lipoxygenase", + "1.13.11.59\tTorulene dioxygenase", + "1.13.11.60\tLinoleate 8R-lipoxygenase", + "1.13.11.61\tLinolenate 9R-lipoxygenase", + "1.13.11.62\tLinoleate 10R-lipoxygenase", + "1.13.11.63\tBeta-carotene 15,15'-dioxygenase", + "1.13.11.64\t5-nitrosalicylate dioxygenase", + "1.13.11.65\tCarotenoid isomerooxygenase", + "1.13.11.66\tHydroquinone 1,2-dioxygenase", + "1.13.11.67\t8'-apo-beta-carotenoid 14',13'-cleaving dioxygenase", + "1.13.11.68\t9-cis-beta-carotene 9',10'-cleaving dioxygenase", + "1.13.11.69\tCarlactone synthase", + "1.13.11.70\tAll-trans-10'-apo-beta-carotenal 13,14-cleaving dioxygenase", + "1.13.11.71\tCarotenoid-9',10'-cleaving dioxygenase", + "1.13.11.72\t2-hydroxyethylphosphonate dioxygenase", + "1.13.11.73\tMethylphosphonate synthase", + "1.13.11.74\t2-aminophenol 1,6-dioxygenase", + "1.13.11.75\tAll-trans-8'-apo-beta-carotenal 15,15'-oxygenase", + "1.13.11.76\t2-amino-5-chlorophenol 1,6-dioxygenase", + "1.13.11.77\tOleate 10S-lipoxygenase", + "1.13.11.78\t2-amino-1-hydroxyethylphosphonate dioxygenase (glycine-forming)", + "1.13.11.79\t5,6-dimethylbenzimidazole synthase", + "1.13.11.80\t(3,5-dihydroxyphenyl)acetyl-CoA 1,2-dioxygenase", + "1.13.11.81\t7,8-dihydroneopterin oxygenase", + "1.13.11.82\t8'-apo-carotenoid 13,14-cleaving dioxygenase", + "1.13.12.1\tArginine 2-monooxygenase", + "1.13.12.2\tLysine 2-monooxygenase", + "1.13.12.3\tTryptophan 2-monooxygenase", + "1.13.12.4\tLactate 2-monooxygenase", + "1.13.12.5\tRenilla-luciferin 2-monooxygenase", + "1.13.12.6\tCypridina-luciferin 2-monooxygenase", + "1.13.12.7\tPhotinus-luciferin 4-monooxygenase (ATP-hydrolyzing)", + "1.13.12.8\tWatasenia-luciferin 2-monooxygenase", + "1.13.12.9\tPhenylalanine 2-monooxygenase", + "1.13.12.13\tOplophorus-luciferin 2-monooxygenase", + "1.13.12.15\t3,4-dihydroxyphenylalanine oxidative deaminase", + "1.13.12.16\tNitronate monooxygenase", + "1.13.12.17\tDichloroarcyriaflavin A synthase", + "1.13.12.18\tDinoflagellate luciferase", + "1.13.12.19\t2-oxuglutarate dioxygenase (ethylene-forming)", + "1.13.12.20\tNoranthrone monooxygenase", + "1.13.12.21\tTetracenomycin-F1 monooxygenase", + "1.13.12.22\tDeoxynogalonate monooxygenase", + "1.13.99.1\tInositol oxygenase", + "1.13.99.3\tTryptophan 2'-dioxygenase", + "1.14.11.1\tGamma-butyrobetaine dioxygenase", + "1.14.11.2\tProcollagen-proline dioxygenase", + "1.14.11.3\tPyrimidine-deoxynucleoside 2'-dioxygenase", + "1.14.11.4\tProcollagen-lysine 5-dioxygenase", + "1.14.11.6\tThymine dioxygenase", + "1.14.11.7\tProcollagen-proline 3-dioxygenase", + "1.14.11.8\tTrimethyllysine dioxygenase", + "1.14.11.9\tFlavanone 3-dioxygenase", + "1.14.11.10\tPyrimidine-deoxynucleoside 1'-dioxygenase", + "1.14.11.11\tHyoscyamine (6S)-dioxygenase", + "1.14.11.12\tGibberellin-44 dioxygenase", + "1.14.11.13\tGibberellin 2-beta-dioxygenase", + "1.14.11.14\t6-beta-hydroxyhyoscyamine epoxidase", + "1.14.11.15\tGibberellin 3-beta-dioxygenase", + "1.14.11.16\tPeptide-aspartate beta-dioxygenase", + "1.14.11.17\tTaurine dioxygenase", + "1.14.11.18\tPhytanoyl-CoA dioxygenase", + "1.14.11.19\tAnthocyanidin synthase", + "1.14.11.20\tDeacetoxyvindoline 4-hydroxylase", + "1.14.11.21\tClavaminate synthase", + "1.14.11.22\tFlavone synthase", + "1.14.11.23\tFlavonol synthase", + "1.14.11.24\t2'-deoxymugineic-acid 2'-dioxygenase", + "1.14.11.25\tMugineic-acid 3-dioxygenase", + "1.14.11.26\tDeacetoxycephalosporin-C hydroxylase", + "1.14.11.27\t[Histone H3]-lysine-36 demethylase", + "1.14.11.28\tProline 3-hydroxylase", + "1.14.11.29\tHypoxia-inducible factor-proline dioxygenase", + "1.14.11.30\tHypoxia-inducible factor-asparagine dioxygenase", + "1.14.11.31\tThebaine 6-O-demethylase", + "1.14.11.32\tCodeine 3-O-demethylase", + "1.14.11.33\tDNA oxidative demethylase", + "1.14.11.34\t2-oxoglutarate/L-arginine monooxygenase/decarboxylase (succinate-forming)", + "1.14.11.35\t1-deoxypentalenic acid 11-beta-hydroxylase", + "1.14.11.36\tPentalenolactone F synthase", + "1.14.11.37\tKanamycin B dioxygenase", + "1.14.11.38\tVerruculogen synthase", + "1.14.11.39\tL-asparagine oxygenase", + "1.14.11.40\tEnduracididine beta-hydroxylase", + "1.14.11.41\tL-arginine hydroxylase", + "1.14.11.42\ttRNA(Phe) (7-(3-amino-3-carboxypropyl)wyosine(37)-C(2))-hydroxylase", + "1.14.11.43\t(S)-dichlorprop dioxygenase (2-oxoglutarate)", + "1.14.11.44\t(R)-dichlorprop dioxygenase (2-oxoglutarate)", + "1.14.11.45\tL-isoleucine 4-hydroxylase", + "1.14.11.46\t2-aminoethylphosphonate dioxygenase", + "1.14.11.47\t50S ribosomal protein L16 3-hydroxylase", + "1.14.11.48\tXanthine dioxygenase", + "1.14.11.49\tUridine-5'-phosphate dioxygenase", + "1.14.11.50\t(-)-deoxypodophyllotoxin synthase", + "1.14.11.51\tDNA N(6)-methyladenine demethylase", + "1.14.11.52\tValidamycin A dioxygenase", + "1.14.11.53\tmRNA N(6)-methyladenine demethylase", + "1.14.11.54\tmRNA N(1)-methyladenine demethylase", + "1.14.11.55\tEctoine hydroxylase", + "1.14.11.56\tL-proline cis-4-hydroxylase", + "1.14.11.57\tL-proline trans-4-hydroxylase", + "1.14.11.n2\tMethylcytosine dioxygenase", + "1.14.11.n4\tAnkyrin-repeat-histidine dioxagenase", + "1.14.12.1\tAnthranilate 1,2-dioxygenase (deaminating, decarboxylating)", + "1.14.12.3\tBenzene 1,2-dioxygenase", + "1.14.12.4\t3-hydroxy-2-methylpyridinecarboxylate dioxygenase", + "1.14.12.5\t5-pyridoxate dioxygenase", + "1.14.12.7\tPhthalate 4,5-dioxygenase", + "1.14.12.8\t4-sulfobenzoate 3,4-dioxygenase", + "1.14.12.9\t4-chlorophenylacetate 3,4-dioxygenase", + "1.14.12.10\tBenzoate 1,2-dioxygenase", + "1.14.12.11\tToluene dioxygenase", + "1.14.12.12\tNaphthalene 1,2-dioxygenase", + "1.14.12.13\t2-halobenzoate 1,2-dioxygenase", + "1.14.12.14\t2-aminobenzenesulfonate 2,3-dioxygenase", + "1.14.12.15\tTerephthalate 1,2-dioxygenase", + "1.14.12.16\t2-hydroxyquinoline 5,6-dioxygenase", + "1.14.12.17\tNitric oxide dioxygenase", + "1.14.12.18\tBiphenyl 2,3-dioxygenase", + "1.14.12.19\t3-phenylpropanoate dioxygenase", + "1.14.12.22\tCarbazole 1,9a-dioxygenase", + "1.14.12.23\tNitroarene dioxygenase", + "1.14.12.24\t2,4-dinitrotoluene dioxygenase", + "1.14.12.25\tp-cumate 2,3-dioxygenase", + "1.14.13.1\tSalicylate 1-monooxygenase", + "1.14.13.2\t4-hydroxybenzoate 3-monooxygenase", + "1.14.13.4\tMelilotate 3-monooxygenase", + "1.14.13.5\tImidazoleacetate 4-monooxygenase", + "1.14.13.6\tOrcinol 2-monooxygenase", + "1.14.13.7\tPhenol 2-monooxygenase (NADPH)", + "1.14.13.8\tFlavin-containing monooxygenase", + "1.14.13.9\tKynurenine 3-monooxygenase", + "1.14.13.10\t2,6-dihydroxypyridine 3-monooxygenase", + "1.14.13.11\tTrans-cinnamate 4-monooxygenase", + "1.14.13.12\tBenzoate 4-monooxygenase", + "1.14.13.14\tTrans-cinnamate 2-monooxygenase", + "1.14.13.16\tCyclopentanone monooxygenase", + "1.14.13.18\t4-hydroxyphenylacetate 1-monooxygenase", + "1.14.13.19\tTaxifolin 8-monooxygenase", + "1.14.13.20\t2,4-dichlorophenol 6-monooxygenase", + "1.14.13.21\tFlavonoid 3'-monooxygenase", + "1.14.13.22\tCyclohexanone monooxygenase", + "1.14.13.23\t3-hydroxybenzoate 4-monooxygenase", + "1.14.13.24\t3-hydroxybenzoate 6-monooxygenase", + "1.14.13.25\tMethane monooxygenase (soluble)", + "1.14.13.27\t4-aminobenzoate 1-monooxygenase", + "1.14.13.28\t3,9-dihydroxypterocarpan 6A-monooxygenase", + "1.14.13.29\t4-nitrophenol 2-monooxygenase", + "1.14.13.30\tLeukotriene-B(4) 20-monooxygenase", + "1.14.13.31\t2-nitrophenol 2-monooxygenase", + "1.14.13.32\tAlbendazole monooxygenase", + "1.14.13.33\t4-hydroxybenzoate 3-monooxygenase (NAD(P)H)", + "1.14.13.34\tLeukotriene-E(4) 20-monooxygenase", + "1.14.13.35\tAnthranilate 3-monooxygenase (deaminating)", + "1.14.13.36\t5-O-(4-coumaroyl)-D-quinate 3'-monooxygenase", + "1.14.13.37\tMethyltetrahydroprotoberberine 14-monooxygenase", + "1.14.13.38\tAnhydrotetracycline 6-monooxygenase", + "1.14.13.39\tNitric-oxide synthase (NADPH)", + "1.14.13.40\tAnthraniloyl-CoA monooxygenase", + "1.14.13.43\tQuestin monooxygenase", + "1.14.13.44\t2-hydroxybiphenyl 3-monooxygenase", + "1.14.13.46\t(-)-menthol monooxygenase", + "1.14.13.47\t(S)-limonene 3-monooxygenase", + "1.14.13.48\t(S)-limonene 6-monooxygenase", + "1.14.13.49\t(S)-limonene 7-monooxygenase", + "1.14.13.50\tPentachlorophenol monooxygenase", + "1.14.13.51\t6-oxocineole dehydrogenase", + "1.14.13.52\tIsoflavone 3'-hydroxylase", + "1.14.13.53\t4'-methoxyisoflavone 2'-hydroxylase", + "1.14.13.54\tKetosteroid monooxygenase", + "1.14.13.55\tProtopine 6-monooxygenase", + "1.14.13.56\tDihydrosanguinarine 10-monooxygenase", + "1.14.13.57\tDihydrochelirubine 12-monooxygenase", + "1.14.13.58\tBenzoyl-CoA 3-monooxygenase", + "1.14.13.59\tL-lysine N(6)-monooxygenase (NADPH)", + "1.14.13.61\t2-hydroxyquinoline 8-monooxygenase", + "1.14.13.62\t4-hydroxyquinoline 3-monooxygenase", + "1.14.13.63\t3-hydroxyphenylacetate 6-hydroxylase", + "1.14.13.64\t4-hydroxybenzoate 1-hydroxylase", + "1.14.13.66\t2-hydroxycyclohexanone 2-monooxygenase", + "1.14.13.67\tQuinine 3-monooxygenase", + "1.14.13.69\tAlkene monooxygenase", + "1.14.13.70\tSterol 14-alpha-demethylase", + "1.14.13.71\tN-methylcoclaurine 3'-monooxygenase", + "1.14.13.72\tMethylsterol monooxygenase", + "1.14.13.73\tTabersonine 16-hydroxylase", + "1.14.13.74\t7-deoxyloganin 7-hydroxylase", + "1.14.13.75\tVinorine hydroxylase", + "1.14.13.76\tTaxane 10-beta-hydroxylase", + "1.14.13.77\tTaxane 13-alpha-hydroxylase", + "1.14.13.78\tEnt-kaurene oxidase", + "1.14.13.79\tEnt-kaurenoic acid oxidase", + "1.14.13.80\t(R)-limonene 6-monooxygenase", + "1.14.13.81\tMagnesium-protoporphyrin IX monomethyl ester (oxidative) cyclase", + "1.14.13.82\tVanillate monooxygenase", + "1.14.13.83\tPrecorrin-3B synthase", + "1.14.13.84\t4-hydroxyacetophenone monooxygenase", + "1.14.13.85\tGlyceollin synthase", + "1.14.13.87\tLicodione synthase", + "1.14.13.88\tFlavonoid 3',5'-hydroxylase", + "1.14.13.89\tIsoflavone 2'-hydroxylase", + "1.14.13.91\tDeoxysarpagine hydroxylase", + "1.14.13.92\tPhenylacetone monooxygenase", + "1.14.13.93\t(+)-abscisic acid 8'-hydroxylase", + "1.14.13.94\tLithocholate 6-beta-hydroxylase", + "1.14.13.96\t5-beta-cholestane-3-alpha,7-alpha-diol 12-alpha-hydroxylase", + "1.14.13.97\tTaurochenodeoxycholate 6-alpha-hydroxylase", + "1.14.13.101\tSenecionine N-oxygenase", + "1.14.13.102\tPsoralen synthase", + "1.14.13.103\t8-dimethylallylnaringenin 2'-hydroxylase", + "1.14.13.104\t(+)-menthofuran synthase", + "1.14.13.105\tMonocyclic monoterpene ketone monooxygenase", + "1.14.13.106\tEpi-isozizaene 5-monooxygenase", + "1.14.13.107\tLimonene 1,2-monooxygenase", + "1.14.13.108\tAbieta-7,13-diene hydroxylase", + "1.14.13.109\tAbieta-7,13-dien-18-ol hydroxylase", + "1.14.13.110\tGeranylgeraniol 18-hydroxylase", + "1.14.13.111\tMethanesulfonate monooxygenase (NADH)", + "1.14.13.112\t3-epi-6-deoxocathasterone 23-monooxygenase", + "1.14.13.113\tFAD-dependent urate hydroxylase", + "1.14.13.114\t6-hydroxynicotinate 3-monooxygenase", + "1.14.13.115\tAngelicin synthase", + "1.14.13.116\tGeranylhydroquinone 3''-hydroxylase", + "1.14.13.119\t5-epiaristolochene 1,3-dihydroxylase", + "1.14.13.120\tCostunolide synthase", + "1.14.13.121\tPremnaspirodiene oxygenase", + "1.14.13.122\tChlorophyllide a oxygenase", + "1.14.13.123\tGermacrene A hydroxylase", + "1.14.13.125\tTryptophan N-monooxygenase", + "1.14.13.127\t3-(3-hydroxy-phenyl)propanoic acid hydroxylase", + "1.14.13.128\t7-methylxanthine demethylase", + "1.14.13.129\tBeta-carotene 3-hydroxylase", + "1.14.13.130\tPyrrole-2-carboxylate monooxygenase", + "1.14.13.131\tDimethyl-sulfide monooxygenase", + "1.14.13.133\tPentalenene oxygenase", + "1.14.13.134\tBeta-amyrin 11-oxidase", + "1.14.13.135\t1-hydroxy-2-naphthoate hydroxylase", + "1.14.13.136\t2-hydroxyisoflavanone synthase", + "1.14.13.137\tIndole-2-monooxygenase", + "1.14.13.138\tIndolin-2-one monooxygenase", + "1.14.13.139\t3-hydroxyindolin-2-one monooxygenase", + "1.14.13.140\t2-hydroxy-1,4-benzoxazin-3-one monooxygenase", + "1.14.13.141\tCholest-4-en-3-one 26-monooxygenase ((25S)-3-oxocholest-4-en-26-oate forming)", + "1.14.13.142\t3-ketosteroid 9-alpha-monooxygenase", + "1.14.13.143\tEnt-isokaurene C2-hydroxylase", + "1.14.13.144\t9-beta-pimara-7,15-diene oxidase", + "1.14.13.145\tEnt-cassa-12,15-diene 11-hydroxylase", + "1.14.13.146\tTaxoid 14-beta-hydroxylase", + "1.14.13.147\tTaxoid 7-beta-hydroxylase", + "1.14.13.148\tTrimethylamine monooxygenase", + "1.14.13.149\tPhenylacetyl-CoA 1,2-epoxidase", + "1.14.13.150\tAlpha-humulene 10-hydroxylase", + "1.14.13.151\tLinalool 8-monooxygenase", + "1.14.13.152\tGeraniol 8-hydroxylase", + "1.14.13.153\t(+)-sabinene 3-hydroxylase", + "1.14.13.154\tErythromycin 12 hydroxylase", + "1.14.13.155\tAlpha-pinene monooxygenase", + "1.14.13.156\t1,8-cineole 2-endo-monooxygenase", + "1.14.13.157\t1,8-cineole 2-exo-monooxygenase", + "1.14.13.158\tAmorpha-4,11-diene 12 monooxygenase", + "1.14.13.160\t(2,2,3-trimethyl-5-oxocyclopent-3-enyl)acetyl-CoA 1,5-monooxygenase", + "1.14.13.161\t(+)-camphor 6-exo-hydroxylase", + "1.14.13.162\t2,5-diketocamphane 1,2-monooxygenase", + "1.14.13.163\t6-hydroxy-3-succinoylpyridine 3-monooxygenase", + "1.14.13.165\tNitric-oxide synthase (NAD(P)H)", + "1.14.13.166\t4-nitrocatechol 4-monooxygenase", + "1.14.13.167\t4-nitrophenol 4-monooxygenase", + "1.14.13.168\tIndole-3-pyruvate monooxygenase", + "1.14.13.170\tPentalenolactone D synthase", + "1.14.13.171\tNeopentalenolactone D synthase", + "1.14.13.172\tSalicylate 5-hydroxylase", + "1.14.13.173\t11-oxo-beta-amyrin 30-oxidase", + "1.14.13.174\tAverantin hydroxylase", + "1.14.13.175\tAflatoxin B synthase", + "1.14.13.176\tTryprostatin B 6-hydroxylase", + "1.14.13.177\tFumitremorgin C monooxygenase", + "1.14.13.178\tMethylxanthine N(1)-demethylase", + "1.14.13.179\tMethylxanthine N(3)-demethylase", + "1.14.13.180\tAklavinone 12-hydroxylase", + "1.14.13.181\t13-deoxydaunorubicin hydroxylase", + "1.14.13.182\t2-heptyl-3-hydroxy-4(1H)-quinolone synthase", + "1.14.13.183\tDammarenediol 12-hydroxylase", + "1.14.13.184\tProtopanaxadiol 6-hydroxylase", + "1.14.13.185\tPikromycin synthase", + "1.14.13.186\t20-oxo-5-O-mycaminosyltylactone 23-monooxygenase", + "1.14.13.187\tL-evernosamine nitrososynthase", + "1.14.13.188\t6-deoxyerythronolide B hydroxylase", + "1.14.13.189\t5-methyl-1-naphthoate 3-hydroxylase", + "1.14.13.190\tFerruginol synthase", + "1.14.13.191\tEnt-sandaracopimaradiene 3-hydroxylase", + "1.14.13.192\tOryzalexin E synthase", + "1.14.13.193\tOryzalexin D synthase", + "1.14.13.194\tPhylloquinone omega-hydroxylase", + "1.14.13.195\tL-ornithine N(5)-monooxygenase (NADPH)", + "1.14.13.196\tL-ornithine N(5)-monooxygenase (NAD(P)H)", + "1.14.13.197\tDihydromonacolin L hydroxylase", + "1.14.13.198\tMonacolin L hydroxylase", + "1.14.13.199\tDocosahexaenoic acid omega-hydroxylase", + "1.14.13.200\tTetracenomycin A2 monooxygenase-diooxygenase", + "1.14.13.201\tBeta-amyrin 28-monooxygenase", + "1.14.13.202\tMethyl farnesoate epoxidase", + "1.14.13.203\tFarnesoate epoxidase", + "1.14.13.204\tLong-chain acyl-CoA omega-monooxygenase", + "1.14.13.205\tLong-chain fatty acid omega-monooxygenase", + "1.14.13.206\tLaurate 7-monooxygenase", + "1.14.13.208\tBenzoyl-CoA 2,3-epoxidase", + "1.14.13.209\tSalicyloyl-CoA 5-hydroxylase", + "1.14.13.210\t4-methyl-5-nitrocatechol 5-monooxygenase", + "1.14.13.211\tRifampicin monooxygenase", + "1.14.13.212\t1,3,7-trimethyluric acid 5-monooxygenase", + "1.14.13.213\tBursehernin 5'-monooxygenase", + "1.14.13.214\t(-)-4'-demethyl-deoxypodophyllotoxin 4-hydroxylase", + "1.14.13.215\tProtoasukamycin 4-monooxygenase", + "1.14.13.216\tAsperlicin C monooxygenase", + "1.14.13.217\tProtodeoxyviolaceinate monooxygenase", + "1.14.13.218\t5-methylphenazine-1-carboxylate 1-monooxygenase", + "1.14.13.219\tResorcinol 4-hydroxylase (NADPH)", + "1.14.13.220\tResorcinol 4-hydroxylase (NADH)", + "1.14.13.221\tCholest-4-en-3-one 26-monooxygenase ((25R)-3-oxocholest-4-en-26-oate forming)", + "1.14.13.222\tAurachin C monooxygenase/isomerase", + "1.14.13.223\t3-hydroxy-4-methyl-anthranilyl-[aryl-carrier protein] 5-monooxygenase", + "1.14.13.224\tViolacein synthase", + "1.14.13.225\tF-actin monooxygenase", + "1.14.13.226\tAcetone monooxygenase (methyl acetate-forming)", + "1.14.13.227\tPropane 2-monooxygenase", + "1.14.13.228\tJasmomic acid 12-hydroxylase", + "1.14.13.229\tTert-butanol monooxygenase", + "1.14.13.230\tButane monooxygenase (soluble)", + "1.14.13.231\tTetracycline 11a-monooxygenase", + "1.14.13.232\t6-methylpretetramide 4-monooxygenase", + "1.14.13.233\t4-hydroxy-6-methylpretetramide 12a-monooxygenase", + "1.14.13.234\t12-dehydrotetracycline 5-monooxygenase", + "1.14.13.n6\tHexahomomethionine N-hydroxylase", + "1.14.13.n7\t4-nitrophenol 2-hydroxylase", + "1.14.14.1\tUnspecific monooxygenase", + "1.14.14.3\tBacterial luciferase", + "1.14.14.5\tAlkanesulfonate monooxygenase", + "1.14.14.8\tAnthranilate 3-monooxygenase (FAD)", + "1.14.14.9\t4-hydroxyphenylacetate 3-monooxygenase", + "1.14.14.10\tNitrilotriacetate monooxygenase", + "1.14.14.11\tStyrene monooxygenase", + "1.14.14.12\t3-hydroxy-9,10-secoandrosta-1,3,5(10)-triene-9,17-dione monooxygenase", + "1.14.14.13\t4-(gamma-L-glutamylamino)butanoyl-[BtrI acyl-carrier protein] monooxygenase", + "1.14.14.14\tAromatase", + "1.14.14.15\t(3S)-3-amino-3-(3-chloro-4-hydroxyphenyl)propanoyl-[peptidyl-carrier protein SgcC2] monooxygenase", + "1.14.14.16\tSteroid 21-monooxygenase", + "1.14.14.17\tSqualene monooxygenase", + "1.14.14.18\tHeme oxygenase (biliverdin-producing)", + "1.14.14.19\tSteroid 17-alpha-monooxygenase", + "1.14.14.20\tPhenol 2-monooxygenase (FADH(2))", + "1.14.14.21\tDibenzothiophene monooxygenase", + "1.14.14.22\tDibenzothiophene sulfone monooxygenase", + "1.14.14.23\tCholesterol 7-alpha-monooxygenase", + "1.14.14.24\tVitamin D 25-hydroxylase", + "1.14.14.25\tCholesterol 24-hydroxylase", + "1.14.14.26\t24-hydroxycholesterol 7-alpha-hydroxylase", + "1.14.14.27\tResorcinol 4-hydroxylase (FADH(2))", + "1.14.14.28\tLong-chain alkane monooxygenase", + "1.14.14.29\t25/26-hydroxycholesterol 7-alpha-hydroxylase", + "1.14.14.30\tIsobutylamine N-monooxygenase", + "1.14.14.31\tIpsdienol synthase", + "1.14.14.32\t17-alpha-hydroxyprogesterone deacetylase", + "1.14.14.33\tEthylenediaminetetraacetate monooxygenase", + "1.14.14.34\tMethanesulfonate monooxygenase (FMNH(2))", + "1.14.14.35\tDimethylsulfone monooxygenase", + "1.14.14.36\tTyrosine N-monooxygenase", + "1.14.14.37\t4-hydroxyphenylacetaldehyde oxime monooxygenase", + "1.14.14.38\tValine N-monooxygenase", + "1.14.14.39\tIsoleucine N-monooxygenase", + "1.14.14.40\tPhenylalanine N-monooxygenase", + "1.14.14.41\t(E)-2-methylbutanal oxime monooxygenase", + "1.14.14.42\tHomomethionine N-monooxygenase", + "1.14.14.43\t(Methylsulfanyl)alkanaldoxime N-monooxygenase", + "1.14.15.1\tCamphor 5-monooxygenase", + "1.14.15.3\tAlkane 1-monooxygenase", + "1.14.15.4\tSteroid 11-beta-monooxygenase", + "1.14.15.5\tCorticosterone 18-monooxygenase", + "1.14.15.6\tCholesterol monooxygenase (side-chain-cleaving)", + "1.14.15.7\tCholine monooxygenase", + "1.14.15.8\tSteroid 15-beta-monooxygenase", + "1.14.15.9\tSpheroidene monooxygenase", + "1.14.15.10\t(+)-camphor 6-endo-hydroxylase", + "1.14.15.11\tPentalenic acid synthase", + "1.14.15.12\tPimeloyl-[acyl-carrier protein] synthase", + "1.14.15.13\tPulcherriminic acid synthase", + "1.14.15.14\tMethyl-branched lipid omega-hydroxylase", + "1.14.15.15\tCholestanetriol 26-monooxygenase", + "1.14.15.16\tVitamin D(3) 24-hydroxylase", + "1.14.15.17\tPheophorbide a oxygenase", + "1.14.15.18\tCalcidiol 1-monooxygenase", + "1.14.15.19\tC-19 steroid 1-alpha-hydroxylase", + "1.14.15.20\tHeme oxygenase (biliverdin-producing, ferredoxin)", + "1.14.15.21\tZeaxanthin epoxidase", + "1.14.15.22\tVitamin D 1,25-hydroxylase", + "1.14.16.1\tPhenylalanine 4-monooxygenase", + "1.14.16.2\tTyrosine 3-monooxygenase", + "1.14.16.3\tAnthranilate 3-monooxygenase", + "1.14.16.4\tTryptophan 5-monooxygenase", + "1.14.16.5\tAlkylglycerol monooxygenase", + "1.14.16.6\tMandelate 4-monooxygenase", + "1.14.16.7\tPhenylalanine 3-monooxygenase", + "1.14.17.1\tDopamine beta-monooxygenase", + "1.14.17.3\tPeptidylglycine monooxygenase", + "1.14.17.4\tAminocyclopropanecarboxylate oxidase", + "1.14.18.1\tTyrosinase", + "1.14.18.2\tCMP-N-acetylneuraminate monooxygenase", + "1.14.18.3\tMethane monooxygenase (particulate)", + "1.14.18.4\tPhosphatidylcholine 12-monooxygenase", + "1.14.18.5\tSphingolipid C4-monooxygenase", + "1.14.18.6\t4-hydroxysphinganine ceramide fatty acyl 2-hydroxylase", + "1.14.18.7\tDihydroceramide fatty acyl 2-hydroxylase", + "1.14.18.8\t7-alpha-hydroxycholest-4-en-3-one 12-alpha-hydroxylase", + "1.14.19.1\tStearoyl-CoA 9-desaturase", + "1.14.19.2\tStearoyl-[acyl-carrier-protein] 9-desaturase", + "1.14.19.3\tAcyl-CoA 6-desaturase", + "1.14.19.4\tAcyl-lipid (11-3)-desaturase", + "1.14.19.5\tAcyl-CoA 11-(Z)-desaturase", + "1.14.19.6\tAcyl-CoA (9+3)-desaturase", + "1.14.19.8\tPentalenolactone synthase", + "1.14.19.9\tTryptophan 7-halogenase", + "1.14.19.10\tIcosanoyl-CoA 5-desaturase", + "1.14.19.11\tAcyl-[acyl-carrier-protein] 4-desaturase", + "1.14.19.12\tAcyl-lipid omega-(9-4) desaturase", + "1.14.19.13\tAcyl-CoA 15-desaturase", + "1.14.19.14\tLinoleoyl-lipid Delta(9) conjugase", + "1.14.19.15\t(11Z)-hexadec-11-enoyl-CoA conjugase", + "1.14.19.16\tLinoleoyl-lipid Delta(12) conjugase (11E,13Z-forming)", + "1.14.19.17\tSphingolipid 4-desaturase", + "1.14.19.18\tSphingolipid 8-(E)-desaturase", + "1.14.19.19\tSphingolipid 10-desaturase", + "1.14.19.20\tDelta(7)-sterol 5(6)-desaturase", + "1.14.19.21\tCholesterol 7-desaturase", + "1.14.19.22\tAcyl-lipid omega-6 desaturase (cytochrome b5)", + "1.14.19.23\tAcyl-lipid (n+3)-(Z)-desaturase (ferredoxin)", + "1.14.19.24\tAcyl-CoA 11-(E)-desaturase", + "1.14.19.25\tAcyl-lipid omega-3 desaturase (cytochrome b5)", + "1.14.19.26\tAcyl-[acyl-carrier-protein] 6-desaturase", + "1.14.19.27\tsn-2 palmitoyl-lipid 9-desaturase", + "1.14.19.28\tsn-1 stearoyl-lipid 9-desaturase", + "1.14.19.29\tSphingolipid 8-(E/Z)-desaturase", + "1.14.19.30\tAcyl-lipid (8-3)-desaturase", + "1.14.19.31\tAcyl-lipid (7-3)-desaturase", + "1.14.19.32\tPalmitoyl-CoA 14-(E/Z)-desaturase", + "1.14.19.33\tDelta(12) acyl-lipid conjugase (11E,13E-forming)", + "1.14.19.34\tAcyl-lipid (9+3)-(E)-desaturase", + "1.14.19.35\tsn-2 acyl-lipid omega-3 desaturase (ferredoxin)", + "1.14.19.36\tsn-1 acyl-lipid omega-3 desaturase (ferredoxin)", + "1.14.19.37\tAcyl-CoA 5-desaturase", + "1.14.19.38\tAcyl-lipid Delta(6)-acetylenase", + "1.14.19.39\tAcyl-lipid Delta(12)-acetylenase", + "1.14.19.40\tHex-5-enoyl-[acyl-carrier protein] acetylenase", + "1.14.19.41\tSterol 22-desaturase", + "1.14.19.42\tPalmitoyl-[glycerolipid] 7-desaturase", + "1.14.19.43\tPalmitoyl-[glycerolipid] 3-(E)-desaturase", + "1.14.19.44\tAcyl-CoA (8-3)-desaturase", + "1.14.19.45\tsn-1 oleoyl-lipid 12-desaturase", + "1.14.19.46\tsn-1 linoleoyl-lipid 6-desaturase", + "1.14.19.47\tAcyl-lipid (9-3)-desaturase", + "1.14.19.48\tTert-amyl alcohol desaturase", + "1.14.19.49\tTetracycline 7-halogenase", + "1.14.19.50\tNoroxomaritidine synthase", + "1.14.19.n4\tStearoyl-CoA 9-desaturase", + "1.14.19.n5\tVersicolorin B desaturase", + "1.14.20.1\tDeacetoxycephalosporin-C synthase", + "1.14.20.2\t2,4-dihydroxy-1,4-benzoxazin-3-one-glucoside dioxygenase", + "1.14.20.3\t(5R)-carbapenem-3-carboxylate synthase", + "1.14.21.1\t(S)-stylopine synthase", + "1.14.21.2\t(S)-cheilanthifoline synthase", + "1.14.21.3\tBerbamunine synthase", + "1.14.21.4\tSalutaridine synthase", + "1.14.21.5\t(S)-canadine synthase", + "1.14.21.7\tBiflaviolin synthase", + "1.14.21.8\tPseudobaptigenin synthase", + "1.14.21.9\tMycocyclosin synthase", + "1.14.21.10\tFumitremorgin C synthase", + "1.14.21.11\t(-)-pluviatolide synthase", + "1.14.21.12\t(S)-nandinine synthase", + "1.14.99.1\tProstaglandin-endoperoxide synthase", + "1.14.99.2\tKynurenine 7,8-hydroxylase", + "1.14.99.4\tProgesterone monooxygenase", + "1.14.99.11\tEstradiol 6-beta-monooxygenase", + "1.14.99.12\tAndrost-4-ene-3,17-dione monooxygenase", + "1.14.99.14\tProgesterone 11-alpha-monooxygenase", + "1.14.99.15\t4-methoxybenzoate monooxygenase (O-demethylating)", + "1.14.99.19\tPlasmanylethanolamine desaturase", + "1.14.99.20\tPhylloquinone monooxygenase (2,3-epoxidizing)", + "1.14.99.21\tLatia-luciferin monooxygenase (demethylating)", + "1.14.99.22\tEcdysone 20-monooxygenase", + "1.14.99.23\t3-hydroxybenzoate 2-monooxygenase", + "1.14.99.24\tSteroid 9-alpha-monooxygenase", + "1.14.99.26\t2-hydroxypyridine 5-monooxygenase", + "1.14.99.29\tDeoxyhypusine monooxygenase", + "1.14.99.34\tMonoprenyl isoflavone epoxidase", + "1.14.99.35\tThiophene-2-carbonyl-CoA monooxygenase", + "1.14.99.37\tTaxadiene 5-alpha-hydroxylase", + "1.14.99.38\tCholesterol 25-hydroxylase", + "1.14.99.39\tAmmonia monooxygenase", + "1.14.99.42\tZeaxanthin 7,8-dioxygenase", + "1.14.99.43\tBeta-amyrin 24-hydroxylase", + "1.14.99.44\tDiapolycopene oxygenase", + "1.14.99.45\tCarotene epsilon-monooxygenase", + "1.14.99.46\tPyrimidine monooxygenase", + "1.14.99.47\t(+)-larreatricin hydroxylase", + "1.14.99.48\tHeme oxygenase (staphylobilin-producing)", + "1.14.99.49\t2-hydroxy-5-methyl-1-naphthoate 7-hydroxylase", + "1.14.99.50\tGamma-glutamyl hercynylcysteine S-oxide synthase", + "1.14.99.51\tHercynylcysteine S-oxide synthase", + "1.14.99.52\tL-cysteinyl-L-histidinylsulfoxide synthase", + "1.14.99.53\tLytic chitin monooxygenase", + "1.14.99.n4\tCarotenoid 9,10-dioxygenase", + "1.15.1.1\tSuperoxide dismutase", + "1.15.1.2\tSuperoxide reductase", + "1.16.1.1\tMercury(II) reductase", + "1.16.1.2\tDiferric-transferrin reductase", + "1.16.1.3\tAquacobalamin reductase", + "1.16.1.4\tCob(II)alamin reductase", + "1.16.1.5\tAquacobalamin reductase (NADPH)", + "1.16.1.6\tCyanocobalamin reductase (cyanide-eliminating)", + "1.16.1.7\tFerric-chelate reductase (NADH)", + "1.16.1.8\t[Methionine synthase] reductase", + "1.16.1.9\tFerric-chelate reductase (NADPH)", + "1.16.1.10\tFerric-chelate reductase (NAD(P)H)", + "1.16.3.1\tFerroxidase", + "1.16.3.2\tBacterial non-heme ferritin", + "1.16.5.1\tAscorbate ferrireductase (transmembrane)", + "1.16.8.1\tCob(II)yrinic acid a,c-diamide reductase", + "1.16.9.1\tIron:rusticyanin reductase", + "1.17.1.1\tCDP-4-dehydro-6-deoxyglucose reductase", + "1.17.1.3\tLeucoanthocyanidin reductase", + "1.17.1.4\tXanthine dehydrogenase", + "1.17.1.5\tNicotinate dehydrogenase", + "1.17.1.8\t4-hydroxy-tetrahydrodipicolinate reductase", + "1.17.2.1\tNicotinate dehydrogenase (cytochrome)", + "1.17.2.2\tLupanine 17-hydroxylase (cytochrome c)", + "1.17.3.1\tPteridine oxidase", + "1.17.3.2\tXanthine oxidase", + "1.17.3.3\t6-hydroxynicotinate dehydrogenase", + "1.17.3.4\tJuglone 3-hydroxylase", + "1.17.4.1\tRibonucleoside-diphosphate reductase", + "1.17.4.2\tRibonucleoside-triphosphate reductase (thioredoxin)", + "1.17.4.4\tVitamin-K-epoxide reductase (warfarin-sensitive)", + "1.17.4.5\tVitamin-K-epoxide reductase (warfarin-insensitive)", + "1.17.5.1\tPhenylacetyl-CoA dehydrogenase", + "1.17.5.2\tCaffeine dehydrogenase", + "1.17.7.1\t(E)-4-hydroxy-3-methylbut-2-enyl-diphosphate synthase (ferredoxin)", + "1.17.7.2\t7-hydroxymethyl chlorophyll a reductase", + "1.17.7.3\t(E)-4-hydroxy-3-methylbut-2-enyl-diphosphate synthase (flavodoxin)", + "1.17.7.4\t4-hydroxy-3-methylbut-2-enyl diphosphate reductase", + "1.17.8.1\tHydroxysqualene dehydroxylase", + "1.17.98.2\tBacteriochlorophyllide c C-7(1)-hydroxylase", + "1.17.99.1\t4-methylphenol dehydrogenase (hydroxylating)", + "1.17.99.2\tEthylbenzene hydroxylase", + "1.17.99.3\t3-alpha,7-alpha,12-alpha-trihydroxy-5-beta-cholestanoyl-CoA 24-hydroxylase", + "1.17.99.4\tUracil/thymine dehydrogenase", + "1.17.99.6\tEpoxyqueuosine reductase", + "1.18.1.1\tRubredoxin--NAD(+) reductase", + "1.18.1.2\tFerredoxin--NADP(+) reductase", + "1.18.1.3\tFerredoxin--NAD(+) reductase", + "1.18.1.4\tRubredoxin--NAD(P)(+) reductase", + "1.18.1.5\tPutidaredoxin--NAD(+) reductase", + "1.18.1.6\tAdrenodoxin-NADP(+) reductase", + "1.18.1.7\tFerredoxin--NAD(P)(+) reductase (naphthalene dioxygenase ferredoxin-specific)", + "1.18.1.8\tFerredoxin-NAD(+) oxidoreductase (Na(+)-transporting)", + "1.18.6.1\tNitrogenase", + "1.19.1.1\tFlavodoxin--NADP(+) reductase", + "1.19.6.1\tNitrogenase (flavodoxin)", + "1.20.1.1\tPhosphonate dehydrogenase", + "1.20.2.1\tArsenate reductase (cytochrome c)", + "1.20.4.1\tArsenate reductase (glutaredoxin)", + "1.20.4.2\tMethylarsonate reductase", + "1.20.4.3\tMycoredoxin", + "1.20.4.4\tArsenate reductase (thioredoxin)", + "1.20.9.1\tArsenate reductase (azurin)", + "1.20.99.1\tArsenate reductase (donor)", + "1.21.1.1\tIodotyrosine deiodinase", + "1.21.1.2\t2,4-dichlorobenzoyl-CoA reductase", + "1.21.3.1\tIsopenicillin-N synthase", + "1.21.3.2\tColumbamine oxidase", + "1.21.3.3\tReticuline oxidase", + "1.21.3.4\tSulochrin oxidase ((+)-bisdechlorogeodin-forming)", + "1.21.3.5\tSulochrin oxidase ((-)-bisdechlorogeodin-forming)", + "1.21.3.6\tAureusidin synthase", + "1.21.3.7\tTetrahydrocannabinolic acid synthase", + "1.21.3.8\tCannabidiolic acid synthase", + "1.21.4.1\tD-proline reductase (dithiol)", + "1.21.4.2\tGlycine reductase", + "1.21.4.3\tSarcosine reductase", + "1.21.4.4\tBetaine reductase", + "1.21.98.1\tCyclic dehypoxanthinyl futalosine synthase", + "1.21.98.2\tDichlorochromopyrrolate synthase", + "1.21.98.3\tAnaerobic magnesium-protoporphyrin IX monomethyl ester cyclase", + "1.21.99.1\tBeta-cyclopiazonate dehydrogenase", + "1.21.99.3\tThyroxine 5-deiodinase", + "1.21.99.4\tThyroxine 5'-deiodinase", + "1.21.99.5\tTetrachloroethene reductive dehalogenase", + "1.23.1.1\t(+)-pinoresinol reductase", + "1.23.1.2\t(+)-lariciresinol reductase", + "1.23.1.3\t(-)-pinoresinol reductase", + "1.23.1.4\t(-)-lariciresinol reductase", + "1.23.5.1\tViolaxanthin de-epoxidase", + "1.97.1.1\tChlorate reductase", + "1.97.1.2\tPyrogallol hydroxytransferase", + "1.97.1.4\t[Formate-C-acetyltransferase]-activating enzyme", + "1.97.1.9\tSelenate reductase", + "1.97.1.12\tPhotosystem I", + "2.1.1.1\tNicotinamide N-methyltransferase", + "2.1.1.2\tGuanidinoacetate N-methyltransferase", + "2.1.1.3\tThetin--homocysteine S-methyltransferase", + "2.1.1.4\tAcetylserotonin O-methyltransferase", + "2.1.1.5\tBetaine--homocysteine S-methyltransferase", + "2.1.1.6\tCatechol O-methyltransferase", + "2.1.1.7\tNicotinate N-methyltransferase", + "2.1.1.8\tHistamine N-methyltransferase", + "2.1.1.9\tThiol S-methyltransferase", + "2.1.1.10\tHomocysteine S-methyltransferase", + "2.1.1.11\tMagnesium protoporphyrin IX methyltransferase", + "2.1.1.12\tMethionine S-methyltransferase", + "2.1.1.13\tMethionine synthase", + "2.1.1.14\t5-methyltetrahydropteroyltriglutamate--homocysteine S-methyltransferase", + "2.1.1.15\tFatty-acid O-methyltransferase", + "2.1.1.16\tMethylene-fatty-acyl-phospholipid synthase", + "2.1.1.17\tPhosphatidylethanolamine N-methyltransferase", + "2.1.1.18\tPolysaccharide O-methyltransferase", + "2.1.1.19\tTrimethylsulfonium--tetrahydrofolate N-methyltransferase", + "2.1.1.20\tGlycine N-methyltransferase", + "2.1.1.21\tMethylamine--glutamate N-methyltransferase", + "2.1.1.22\tCarnosine N-methyltransferase", + "2.1.1.25\tPhenol O-methyltransferase", + "2.1.1.26\tIodophenol O-methyltransferase", + "2.1.1.27\tTyramine N-methyltransferase", + "2.1.1.28\tPhenylethanolamine N-methyltransferase", + "2.1.1.33\ttRNA (guanine(46)-N(7))-methyltransferase", + "2.1.1.34\ttRNA (guanosine(18)-2'-O)-methyltransferase", + "2.1.1.35\ttRNA (uracil(54)-C(5))-methyltransferase", + "2.1.1.37\tDNA (cytosine-5-)-methyltransferase", + "2.1.1.38\tO-demethylpuromycin O-methyltransferase", + "2.1.1.39\tInositol 3-methyltransferase", + "2.1.1.40\tInositol 1-methyltransferase", + "2.1.1.41\tSterol 24-C-methyltransferase", + "2.1.1.42\tFlavone 3'-O-methyltransferase", + "2.1.1.43\tHistone-lysine N-methyltransferase", + "2.1.1.44\tL-histidine N(alpha)-methyltransferase", + "2.1.1.45\tThymidylate synthase", + "2.1.1.46\tIsoflavone 4'-O-methyltransferase", + "2.1.1.47\tIndolepyruvate C-methyltransferase", + "2.1.1.49\tAmine N-methyltransferase", + "2.1.1.50\tLoganate O-methyltransferase", + "2.1.1.53\tPutrescine N-methyltransferase", + "2.1.1.54\tDeoxycytidylate C-methyltransferase", + "2.1.1.55\ttRNA (adenine-N(6)-)-methyltransferase", + "2.1.1.56\tmRNA (guanine-N(7)-)-methyltransferase", + "2.1.1.57\tMethyltransferase cap1", + "2.1.1.59\t[Cytochrome c]-lysine N-methyltransferase", + "2.1.1.60\tCalmodulin-lysine N-methyltransferase", + "2.1.1.61\ttRNA (5-methylaminomethyl-2-thiouridylate)-methyltransferase", + "2.1.1.62\tmRNA (2'-O-methyladenosine-N(6)-)-methyltransferase", + "2.1.1.63\tMethylated-DNA--[protein]-cysteine S-methyltransferase", + "2.1.1.64\t3-demethylubiquinol 3-O-methyltransferase", + "2.1.1.65\tLicodione 2'-O-methyltransferase", + "2.1.1.67\tThiopurine S-methyltransferase", + "2.1.1.68\tCaffeate O-methyltransferase", + "2.1.1.69\t5-hydroxyfuranocoumarin 5-O-methyltransferase", + "2.1.1.70\t8-hydroxyfuranocoumarin 8-O-methyltransferase", + "2.1.1.71\tPhosphatidyl-N-methylethanolamine N-methyltransferase", + "2.1.1.72\tSite-specific DNA-methyltransferase (adenine-specific)", + "2.1.1.74\tMethylenetetrahydrofolate--tRNA-(uracil(54)-C(5))-methyltransferase (FADH(2)-oxidizing)", + "2.1.1.75\tApigenin 4'-O-methyltransferase", + "2.1.1.76\tQuercetin 3-O-methyltransferase", + "2.1.1.77\tProtein-L-isoaspartate(D-aspartate) O-methyltransferase", + "2.1.1.78\tIsoorientin 3'-O-methyltransferase", + "2.1.1.79\tCyclopropane-fatty-acyl-phospholipid synthase", + "2.1.1.80\tProtein-glutamate O-methyltransferase", + "2.1.1.82\t3-methylquercetin 7-O-methyltransferase", + "2.1.1.83\t3,7-dimethylquercetin 4'-O-methyltransferase", + "2.1.1.84\tMethylquercetagetin 6-O-methyltransferase", + "2.1.1.85\tProtein-histidine N-methyltransferase", + "2.1.1.86\tTetrahydromethanopterin S-methyltransferase", + "2.1.1.87\tPyridine N-methyltransferase", + "2.1.1.88\t8-hydroxyquercetin 8-O-methyltransferase", + "2.1.1.89\tTetrahydrocolumbamine 2-O-methyltransferase", + "2.1.1.90\tMethanol--corrinoid protein Co-methyltransferase", + "2.1.1.91\tIsobutyraldoxime O-methyltransferase", + "2.1.1.94\tTabersonine 16-O-methyltransferase", + "2.1.1.95\tTocopherol O-methyltransferase", + "2.1.1.96\tThioether S-methyltransferase", + "2.1.1.97\t3-hydroxyanthranilate 4-C-methyltransferase", + "2.1.1.98\tDiphthine synthase", + "2.1.1.99\t3-hydroxy-16-methoxy-2,3-dihydrotabersonine N-methyltransferase", + "2.1.1.100\tProtein-S-isoprenylcysteine O-methyltransferase", + "2.1.1.101\tMacrocin O-methyltransferase", + "2.1.1.102\tDemethylmacrocin O-methyltransferase", + "2.1.1.103\tPhosphoethanolamine N-methyltransferase", + "2.1.1.104\tCaffeoyl-CoA O-methyltransferase", + "2.1.1.105\tN-benzoyl-4-hydroxyanthranilate 4-O-methyltransferase", + "2.1.1.106\tTryptophan 2-C-methyltransferase", + "2.1.1.107\tUroporphyrinogen-III C-methyltransferase", + "2.1.1.108\t6-hydroxymellein O-methyltransferase", + "2.1.1.109\tDemethylsterigmatocystin 6-O-methyltransferase", + "2.1.1.110\tSterigmatocystin 8-O-methyltransferase", + "2.1.1.111\tAnthranilate N-methyltransferase", + "2.1.1.112\tGlucuronoxylan 4-O-methyltransferase", + "2.1.1.113\tSite-specific DNA-methyltransferase (cytosine-N(4)-specific)", + "2.1.1.114\tPolyprenyldihydroxybenzoate methyltransferase", + "2.1.1.115\t(RS)-1-benzyl-1,2,3,4-tetrahydroisoquinoline N-methyltransferase", + "2.1.1.116\t3'-hydroxy-N-methyl-(S)-coclaurine 4'-O-methyltransferase", + "2.1.1.117\t(S)-scoulerine 9-O-methyltransferase", + "2.1.1.118\tColumbamine O-methyltransferase", + "2.1.1.119\t10-hydroxydihydrosanguinarine 10-O-methyltransferase", + "2.1.1.120\t12-hydroxydihydrochelirubine 12-O-methyltransferase", + "2.1.1.121\t6-O-methylnorlaudanosoline 5'-O-methyltransferase", + "2.1.1.122\t(S)-tetrahydroprotoberberine N-methyltransferase", + "2.1.1.123\t[Cytochrome c]-methionine S-methyltransferase", + "2.1.1.127\t[Ribulose-bisphosphate carboxylase]-lysine N-methyltransferase", + "2.1.1.128\t(RS)-norcoclaurine 6-O-methyltransferase", + "2.1.1.129\tInositol 4-methyltransferase", + "2.1.1.130\tPrecorrin-2 C(20)-methyltransferase", + "2.1.1.131\tPrecorrin-3B C(17)-methyltransferase", + "2.1.1.132\tPrecorrin-6B C(5,15)-methyltransferase (decarboxylating)", + "2.1.1.133\tPrecorrin-4 C(11)-methyltransferase", + "2.1.1.136\tChlorophenol O-methyltransferase", + "2.1.1.137\tArsenite methyltransferase", + "2.1.1.139\t3'-demethylstaurosporine O-methyltransferase", + "2.1.1.140\t(S)-coclaurine-N-methyltransferase", + "2.1.1.141\tJasmonate O-methyltransferase", + "2.1.1.142\tCycloartenol 24-C-methyltransferase", + "2.1.1.143\t24-methylenesterol C-methyltransferase", + "2.1.1.144\tTrans-aconitate 2-methyltransferase", + "2.1.1.145\tTrans-aconitate 3-methyltransferase", + "2.1.1.146\t(Iso)eugenol O-methyltransferase", + "2.1.1.147\tCorydaline synthase", + "2.1.1.148\tThymidylate synthase (FAD)", + "2.1.1.150\tIsoflavone 7-O-methyltransferase", + "2.1.1.151\tCobalt-factor II C(20)-methyltransferase", + "2.1.1.152\tPrecorrin-6A synthase (deacetylating)", + "2.1.1.153\tVitexin 2''-O-rhamnoside 7-O-methyltransferase", + "2.1.1.154\tIsoliquiritigenin 2'-O-methyltransferase", + "2.1.1.155\tKaempferol 4'-O-methyltransferase", + "2.1.1.156\tGlycine/sarcosine N-methyltransferase", + "2.1.1.157\tSarcosine/dimethylglycine N-methyltransferase", + "2.1.1.158\t7-methylxanthosine synthase", + "2.1.1.159\tTheobromine synthase", + "2.1.1.160\tCaffeine synthase", + "2.1.1.161\tDimethylglycine N-methyltransferase", + "2.1.1.162\tGlycine/sarcosine/dimethylglycine N-methyltransferase", + "2.1.1.163\tDemethylmenaquinone methyltransferase", + "2.1.1.164\tDemethylrebeccamycin-D-glucose O-methyltransferase", + "2.1.1.165\tMethyl halide transferase", + "2.1.1.166\t23S rRNA (uridine(2552)-2'-O)-methyltransferase", + "2.1.1.167\t27S pre-rRNA (guanosine(2922)-2'-O)-methyltransferase", + "2.1.1.168\t21S rRNA (uridine(2791)-2'-O)-methyltransferase", + "2.1.1.169\tTricetin 3',4',5'-O-trimethyltransferase", + "2.1.1.170\t16S rRNA (guanine(527)-N(7))-methyltransferase", + "2.1.1.171\t16S rRNA (guanine(966)-N(2))-methyltransferase", + "2.1.1.172\t16S rRNA (guanine(1207)-N(2))-methyltransferase", + "2.1.1.173\t23S rRNA (guanine(2445)-N(2))-methyltransferase", + "2.1.1.174\t23S rRNA (guanine(1835)-N(2))-methyltransferase", + "2.1.1.175\tTricin synthase", + "2.1.1.176\t16S rRNA (cytosine(967)-C(5))-methyltransferase", + "2.1.1.177\t23S rRNA (pseudouridine(1915)-N(3))-methyltransferase", + "2.1.1.178\t16S rRNA (cytosine(1407)-C(5))-methyltransferase", + "2.1.1.179\t16S rRNA (guanine(1405)-N(7))-methyltransferase", + "2.1.1.180\t16S rRNA (adenine(1408)-N(1))-methyltransferase", + "2.1.1.181\t23S rRNA (adenine(1618)-N(6))-methyltransferase", + "2.1.1.182\t16S rRNA (adenine(1518)-N(6)/adenine(1519)-N(6))-dimethyltransferase", + "2.1.1.183\t18S rRNA (adenine(1779)-N(6)/adenine(1780)-N(6))-dimethyltransferase", + "2.1.1.184\t23S rRNA (adenine(2085)-N(6))-dimethyltransferase", + "2.1.1.185\t23S rRNA (guanosine(2251)-2'-O)-methyltransferase", + "2.1.1.186\t23S rRNA (cytidine(2498)-2'-O)-methyltransferase", + "2.1.1.187\t23S rRNA (guanine(745)-N(1))-methyltransferase", + "2.1.1.188\t23S rRNA (guanine(748)-N(1))-methyltransferase", + "2.1.1.189\t23S rRNA (uracil(747)-C(5))-methyltransferase", + "2.1.1.190\t23S rRNA (uracil(1939)-C(5))-methyltransferase", + "2.1.1.191\t23S rRNA (cytosine(1962)-C(5))-methyltransferase", + "2.1.1.192\t23S rRNA (adenine(2503)-C(2))-methyltransferase", + "2.1.1.193\t16S rRNA (uracil(1498)-N(3))-methyltransferase", + "2.1.1.195\tCobalt-precorrin-5B (C(1))-methyltransferase", + "2.1.1.196\tCobalt-precorrin-6B (C(15))-methyltransferase (decarboxylating)", + "2.1.1.197\tMalonyl-[acyl-carrier protein] O-methyltransferase", + "2.1.1.198\t16S rRNA (cytidine(1402)-2'-O)-methyltransferase", + "2.1.1.199\t16S rRNA (cytosine(1402)-N(4))-methyltransferase", + "2.1.1.200\ttRNA (cytidine(32)/uridine(32)-2'-O)-methyltransferase", + "2.1.1.201\t2-methoxy-6-polyprenyl-1,4-benzoquinol methylase", + "2.1.1.202\tMultisite-specific tRNA:(cytosine-C(5))-methyltransferase", + "2.1.1.203\ttRNA (cytosine(34)-C(5))-methyltransferase", + "2.1.1.204\ttRNA (cytosine(38)-C(5))-methyltransferase", + "2.1.1.205\ttRNA (cytidine(32)/guanosine(34)-2'-O)-methyltransferase", + "2.1.1.206\ttRNA (cytidine(56)-2'-O)-methyltransferase", + "2.1.1.207\ttRNA (cytidine(34)-2'-O)-methyltransferase", + "2.1.1.208\t23S rRNA (uridine(2479)-2'-O)-methyltransferase", + "2.1.1.209\t23S rRNA (guanine(2535)-N(1))-methyltransferase", + "2.1.1.210\tDemethylspheroidene O-methyltransferase", + "2.1.1.211\ttRNA(Ser) (uridine(44)-2'-O)-methyltransferase", + "2.1.1.212\t2,7,4'-trihydroxyisoflavanone 4'-O-methyltransferase", + "2.1.1.213\ttRNA (guanine(10)-N(2))-dimethyltransferase", + "2.1.1.214\ttRNA (guanine(10)-N(2))-methyltransferase", + "2.1.1.215\ttRNA (guanine(26)-N(2)/guanine(27)-N(2))-dimethyltransferase", + "2.1.1.216\ttRNA (guanine(26)-N(2))-dimethyltransferase", + "2.1.1.217\ttRNA (adenine(22)-N(1))-methyltransferase", + "2.1.1.218\ttRNA (adenine(9)-N(1))-methyltransferase", + "2.1.1.219\ttRNA (adenine(57)-N(1)/adenine(58)-N(1))-methyltransferase", + "2.1.1.220\ttRNA (adenine(58)-N(1))-methyltransferase", + "2.1.1.221\ttRNA (guanine(9)-N(1))-methyltransferase", + "2.1.1.222\t2-polyprenyl-6-hydroxyphenol methylase", + "2.1.1.223\ttRNA(1)(Val) (adenine(37)-N(6))-methyltransferase", + "2.1.1.224\t23S rRNA (adenine(2503)-C(8))-methyltransferase", + "2.1.1.225\ttRNA:m(4)X modification enzyme", + "2.1.1.226\t23S rRNA (cytidine(1920)-2'-O)-methyltransferase", + "2.1.1.227\t16S rRNA (cytidine(1409)-2'-O)-methyltransferase", + "2.1.1.228\ttRNA (guanine(37)-N(1))-methyltransferase", + "2.1.1.229\ttRNA (carboxymethyluridine(34)-5-O)-methyltransferase", + "2.1.1.230\t23S rRNA (adenosine(1067)-2'-O)-methyltransferase", + "2.1.1.231\tFlavonoid 4'-O-methyltransferase", + "2.1.1.232\tNaringenin 7-O-methyltransferase", + "2.1.1.233\t[Phosphatase 2A protein]-leucine-carboxy methyltransferase", + "2.1.1.234\tdTDP-3-amino-3,4,6-trideoxy-alpha-D-glucopyranose N,N-dimethyltransferase", + "2.1.1.235\tdTDP-3-amino-3,6-dideoxy-alpha-D-glucopyranose N,N-dimethyltransferase", + "2.1.1.236\tdTDP-3-amino-3,6-dideoxy-alpha-D-galactopyranose N,N-dimethyltransferase", + "2.1.1.237\tMycinamicin III 3''-O-methyltransferase", + "2.1.1.238\tMycinamicin VI 2''-O-methyltransferase", + "2.1.1.239\tL-olivosyl-oleandolide 3-O-methyltransferase", + "2.1.1.240\tTrans-resveratrol di-O-methyltransferase", + "2.1.1.241\t2,4,7-trihydroxy-1,4-benzoxazin-3-one-glucoside 7-O-methyltransferase", + "2.1.1.242\t16S rRNA (guanine(1516)-N(2))-methyltransferase", + "2.1.1.243\t2-ketoarginine methyltransferase", + "2.1.1.244\tProtein N-terminal methyltransferase", + "2.1.1.245\t5-methyltetrahydrosarcinapterin:corrinoid/iron-sulfur protein Co-methyltransferase", + "2.1.1.246\t[Methyl-Co(III) methanol-specific corrinoid protein]:coenzyme M methyltransferase", + "2.1.1.247\t[Methyl-Co(III) methylamine-specific corrinoid protein]:coenzyme M methyltransferase", + "2.1.1.248\t[Methylamine--corrinoid protein] Co-methyltransferase", + "2.1.1.249\t[Dimethylamine--corrinoid protein] Co-methyltransferase", + "2.1.1.250\t[Trimethylamine--corrinoid protein] Co-methyltransferase", + "2.1.1.251\tMethylated-thiol--coenzyme M methyltransferase", + "2.1.1.252\tTetramethylammonium--corrinoid protein Co-methyltransferase", + "2.1.1.253\t[Methyl-Co(III) tetramethylammonium-specific corrinoid protein]:coenzyme M methyltransferase", + "2.1.1.254\tErythromycin 3''-O-methyltransferase", + "2.1.1.255\tGeranyl diphosphate 2-C-methyltransferase", + "2.1.1.256\ttRNA (guanine(6)-N(2))-methyltransferase", + "2.1.1.257\ttRNA (pseudouridine(54)-N(1))-methyltransferase", + "2.1.1.258\t5-methyltetrahydrofolate:corrinoid/iron-sulfur protein Co-methyltransferase", + "2.1.1.259\t[Fructose-bisphosphate aldolase]-lysine N-methyltransferase", + "2.1.1.260\trRNA small subunit pseudouridine methyltransferase Nep1", + "2.1.1.261\t4-dimethylallyltryptophan N-methyltransferase", + "2.1.1.262\tSqualene methyltransferase", + "2.1.1.263\tBotryococcene C-methyltransferase", + "2.1.1.264\t23S rRNA (guanine(2069)-N(7))-methyltransferase", + "2.1.1.265\tTellurite methyltransferase", + "2.1.1.266\t23S rRNA (adenine(2030)-N(6))-methyltransferase", + "2.1.1.267\tFlavonoid 3',5'-methyltransferase", + "2.1.1.268\ttRNA(Thr) (cytosine(32)-N(3))-methyltransferase", + "2.1.1.269\tDimethylsulfoniopropionate demethylase", + "2.1.1.270\t(+)-6a-hydroxymaackiain 3-O-methyltransferase", + "2.1.1.271\tCobalt-precorrin-4 methyltransferase", + "2.1.1.272\tCobalt-factor III methyltransferase", + "2.1.1.273\tBenzoate O-methyltransferase", + "2.1.1.274\tSalicylate carboxymethyltransferase", + "2.1.1.275\tGibberellin A(9) O-methyltransferase", + "2.1.1.276\tGibberellin A(4) carboxyl methyltransferase", + "2.1.1.277\tAnthranilate O-methyltransferase", + "2.1.1.278\tIndole-3-acetate O-methyltransferase", + "2.1.1.279\tTrans-anol O-methyltransferase", + "2.1.1.280\tSelenocysteine Se-methyltransferase", + "2.1.1.281\tPhenylpyruvate C(3)-methyltransferase", + "2.1.1.282\ttRNA(Phe) 7-((3-amino-3-carboxypropyl)-4-demethylwyosine(37)-N(4))-methyltransferase", + "2.1.1.283\tEmodin O-methyltransferase", + "2.1.1.284\t8-demethylnovobiocic acid C(8)-methyltransferase", + "2.1.1.285\tDemethyldecarbamoylnovobiocin O-methyltransferase", + "2.1.1.286\t25S rRNA (adenine(2142)-N(1))-methyltransferase", + "2.1.1.287\t25S rRNA (adenine(645)-N(1))-methyltransferase", + "2.1.1.288\tAklanonic acid methyltransferase", + "2.1.1.289\tCobalt-precorrin-7 (C(5))-methyltransferase", + "2.1.1.290\ttRNA(Phe) (7-(3-amino-3-carboxypropyl)wyosine(37)-O)-methyltransferase", + "2.1.1.291\t(R,S)-reticuline 7-O-methyltransferase", + "2.1.1.292\tCarminomycin 4-O-methyltransferase", + "2.1.1.293\t6-hydroxytryprostatin B O-methyltransferase", + "2.1.1.294\t3-O-phospho-polymannosyl GlcNAc-diphospho-ditrans,octacis-undecaprenol 3-phospho-methyltransferase", + "2.1.1.295\t2-methyl-6-phytyl-1,4-hydroquinone methyltransferase", + "2.1.1.296\tMethyltransferase cap2", + "2.1.1.297\tPeptide chain release factor N(5)-glutamine methyltransferase", + "2.1.1.298\tRibosomal protein L3 N(5)-glutamine methyltransferase", + "2.1.1.299\tProtein N-terminal monomethyltransferase", + "2.1.1.300\tPavine N-methyltransferase", + "2.1.1.301\tCypemycin N-terminal methyltransferase", + "2.1.1.302\t3-hydroxy-5-methyl-1-naphthoate 3-O-methyltransferase", + "2.1.1.303\t2,7-dihydroxy-5-methyl-1-naphthoate 7-O-methyltransferase", + "2.1.1.304\tL-tyrosine C(3)-methyltransferase", + "2.1.1.305\t8-demethyl-8-alpha-L-rhamnosyl tetracenomycin-C 2'-O-methyltransferase", + "2.1.1.306\t8-demethyl-8-(2-methoxy-alpha-L-rhamnosyl)-tetracenomycin-C 3'-O-methyltransferase", + "2.1.1.307\t8-demethyl-8-(2,3-dimethoxy-alpha-L-rhamnosyl)-tetracenomycin-C 4'-O-methyltransferase", + "2.1.1.308\t2-hydroxyethylphosphonate methyltransferase", + "2.1.1.309\t18S rRNA (guanine(1575)-N(7))-methyltransferase", + "2.1.1.310\t25S rRNA (cytosine(2870)-C(5))-methyltransferase", + "2.1.1.311\t25S rRNA (cytosine(2278)-C(5))-methyltransferase", + "2.1.1.312\t25S rRNA (uracil(2843)-N(3))-methyltransferase", + "2.1.1.313\t25S rRNA (uracil(2634)-N(3))-methyltransferase", + "2.1.1.314\tDiphthine methyl ester synthase", + "2.1.1.315\t27-O-demethylrifamycin SV methyltransferase", + "2.1.1.316\tMitomycin 6-O-methyltransferase", + "2.1.1.317\tSphingolipid C(9)-methyltransferase", + "2.1.1.318\t[Trehalose-6-phosphate synthase]-L-cysteine S-methyltransferase", + "2.1.1.319\tType I protein arginine methyltransferase", + "2.1.1.320\tType II protein arginine methyltransferase", + "2.1.1.321\tType III protein arginine methyltransferase", + "2.1.1.322\tType IV protein arginine methyltransferase", + "2.1.1.323\t(-)-pluviatolide 4-O-methyltransferase", + "2.1.1.324\tdTDP-4-amino-2,3,4,6-tetradeoxy-D-glucose N,N-dimethyltransferase", + "2.1.1.325\tJuvenile hormone-III synthase", + "2.1.1.326\tN-acetyl-demethylphosphinothricin P-methyltransferase", + "2.1.1.327\tPhenazine-1-carboxylate N-methyltransferase", + "2.1.1.328\tN-demethylindolmycin N-methyltransferase", + "2.1.1.329\tDemethylphylloquinol methyltransferase", + "2.1.1.330\t5'-demethylyatein 5'-O-methyltransferase", + "2.1.1.331\tBacteriochlorophyllide d C-12(1)-methyltransferase", + "2.1.1.332\tBacteriochlorophyllide d C-8(2)-methyltransferase", + "2.1.1.333\tBacteriochlorophyllide d C-20 methyltransferase", + "2.1.1.334\tMethanethiol S-methyltransferase", + "2.1.1.335\t4-amino-anhydrotetracycline N(4)-methyltransferase", + "2.1.1.336\tNorbelladine O-methyltransferase", + "2.1.1.337\tReticuline N-methyltransferase", + "2.1.1.338\tDesmethylxanthohumol 6'-O-methyltransferase", + "2.1.1.339\tXanthohumol 4'-O-methyltransferase", + "2.1.1.n1\tResorcinol O-methyltransferase", + "2.1.1.n4\tThiocyanate methyltransferase", + "2.1.1.n7\t5-pentadecatrienyl resorcinol O-methyltransferase", + "2.1.1.n8\tSmall RNA 2'-O-methyltransferase", + "2.1.1.n11\tMethylphosphotriester-DNA--[protein]-cysteine S-methyltransferase", + "2.1.2.1\tGlycine hydroxymethyltransferase", + "2.1.2.2\tPhosphoribosylglycinamide formyltransferase", + "2.1.2.3\tPhosphoribosylaminoimidazolecarboxamide formyltransferase", + "2.1.2.4\tGlycine formimidoyltransferase", + "2.1.2.5\tGlutamate formimidoyltransferase", + "2.1.2.7\tD-alanine 2-hydroxymethyltransferase", + "2.1.2.8\tDeoxycytidylate 5-hydroxymethyltransferase", + "2.1.2.9\tMethionyl-tRNA formyltransferase", + "2.1.2.10\tAminomethyltransferase", + "2.1.2.11\t3-methyl-2-oxobutanoate hydroxymethyltransferase", + "2.1.2.13\tUDP-4-amino-4-deoxy-L-arabinose formyltransferase", + "2.1.3.1\tMethylmalonyl-CoA carboxytransferase", + "2.1.3.2\tAspartate carbamoyltransferase", + "2.1.3.3\tOrnithine carbamoyltransferase", + "2.1.3.5\tOxamate carbamoyltransferase", + "2.1.3.6\tPutrescine carbamoyltransferase", + "2.1.3.7\t3-hydroxymethylcephem carbamoyltransferase", + "2.1.3.8\tLysine carbamoyltransferase", + "2.1.3.9\tN-acetylornithine carbamoyltransferase", + "2.1.3.10\tMalonyl-S-ACP:biotin-protein carboxyltransferase", + "2.1.3.11\tN-succinylornithine carbamoyltransferase", + "2.1.3.12\tDecarbamoylnovobiocin carbamoyltransferase", + "2.1.4.1\tGlycine amidinotransferase", + "2.1.4.2\tScyllo-inosamine-4-phosphate amidinotransferase", + "2.2.1.1\tTransketolase", + "2.2.1.2\tTransaldolase", + "2.2.1.3\tFormaldehyde transketolase", + "2.2.1.4\tAcetoin--ribose-5-phosphate transaldolase", + "2.2.1.5\t2-hydroxy-3-oxoadipate synthase", + "2.2.1.6\tAcetolactate synthase", + "2.2.1.7\t1-deoxy-D-xylulose-5-phosphate synthase", + "2.2.1.8\tFluorothreonine transaldolase", + "2.2.1.9\t2-succinyl-5-enolpyruvyl-6-hydroxy-3-cyclohexene-1-carboxylic-acid synthase", + "2.2.1.10\t2-amino-3,7-dideoxy-D-threo-hept-6-ulosonate synthase", + "2.2.1.11\t6-deoxy-5-ketofructose 1-phosphate synthase", + "2.2.1.12\t3-acetyloctanal synthase", + "2.3.1.1\tAmino-acid N-acetyltransferase", + "2.3.1.2\tImidazole N-acetyltransferase", + "2.3.1.3\tGlucosamine N-acetyltransferase", + "2.3.1.4\tGlucosamine-phosphate N-acetyltransferase", + "2.3.1.5\tArylamine N-acetyltransferase", + "2.3.1.6\tCholine O-acetyltransferase", + "2.3.1.7\tCarnitine O-acetyltransferase", + "2.3.1.8\tPhosphate acetyltransferase", + "2.3.1.9\tAcetyl-CoA C-acetyltransferase", + "2.3.1.10\tHydrogen-sulfide S-acetyltransferase", + "2.3.1.11\tThioethanolamine S-acetyltransferase", + "2.3.1.12\tDihydrolipoyllysine-residue acetyltransferase", + "2.3.1.13\tGlycine N-acyltransferase", + "2.3.1.14\tGlutamine N-phenylacetyltransferase", + "2.3.1.15\tGlycerol-3-phosphate 1-O-acyltransferase", + "2.3.1.16\tAcetyl-CoA C-acyltransferase", + "2.3.1.17\tAspartate N-acetyltransferase", + "2.3.1.18\tGalactoside O-acetyltransferase", + "2.3.1.19\tPhosphate butyryltransferase", + "2.3.1.20\tDiacylglycerol O-acyltransferase", + "2.3.1.21\tCarnitine O-palmitoyltransferase", + "2.3.1.22\t2-acylglycerol O-acyltransferase", + "2.3.1.23\t1-acylglycerophosphocholine O-acyltransferase", + "2.3.1.24\tSphingosine N-acyltransferase", + "2.3.1.25\tPlasmalogen synthase", + "2.3.1.26\tSterol O-acyltransferase", + "2.3.1.27\tCortisol O-acetyltransferase", + "2.3.1.28\tChloramphenicol O-acetyltransferase", + "2.3.1.29\tGlycine C-acetyltransferase", + "2.3.1.30\tSerine O-acetyltransferase", + "2.3.1.31\tHomoserine O-acetyltransferase", + "2.3.1.32\tLysine N-acetyltransferase", + "2.3.1.33\tHistidine N-acetyltransferase", + "2.3.1.34\tD-tryptophan N-acetyltransferase", + "2.3.1.35\tGlutamate N-acetyltransferase", + "2.3.1.36\tD-amino-acid N-acetyltransferase", + "2.3.1.37\t5-aminolevulinate synthase", + "2.3.1.38\t[Acyl-carrier-protein] S-acetyltransferase", + "2.3.1.39\t[Acyl-carrier-protein] S-malonyltransferase", + "2.3.1.40\tAcyl-[acyl-carrier-protein]--phospholipid O-acyltransferase", + "2.3.1.41\tBeta-ketoacyl-[acyl-carrier-protein] synthase I", + "2.3.1.42\tGlycerone-phosphate O-acyltransferase", + "2.3.1.43\tPhosphatidylcholine--sterol O-acyltransferase", + "2.3.1.44\tN-acetylneuraminate 4-O-acetyltransferase", + "2.3.1.45\tN-acetylneuraminate 7-O(or 9-O)-acetyltransferase", + "2.3.1.46\tHomoserine O-succinyltransferase", + "2.3.1.47\t8-amino-7-oxononanoate synthase", + "2.3.1.48\tHistone acetyltransferase", + "2.3.1.49\tDeacetyl-[citrate-(pro-3S)-lyase] S-acetyltransferase", + "2.3.1.50\tSerine C-palmitoyltransferase", + "2.3.1.51\t1-acylglycerol-3-phosphate O-acyltransferase", + "2.3.1.52\t2-acylglycerol-3-phosphate O-acyltransferase", + "2.3.1.53\tPhenylalanine N-acetyltransferase", + "2.3.1.54\tFormate C-acetyltransferase", + "2.3.1.56\tAromatic-hydroxylamine O-acetyltransferase", + "2.3.1.57\tDiamine N-acetyltransferase", + "2.3.1.58\t2,3-diaminopropionate N-oxalyltransferase", + "2.3.1.59\tGentamicin 2'-N-acetyltransferase", + "2.3.1.60\tGentamicin 3-N-acetyltransferase", + "2.3.1.61\tDihydrolipoyllysine-residue succinyltransferase", + "2.3.1.62\t2-acylglycerophosphocholine O-acyltransferase", + "2.3.1.63\t1-alkylglycerophosphocholine O-acyltransferase", + "2.3.1.64\tAgmatine N(4)-coumaroyltransferase", + "2.3.1.65\tBile acid-CoA:amino acid N-acyltransferase", + "2.3.1.66\tLeucine N-acetyltransferase", + "2.3.1.67\t1-alkylglycerophosphocholine O-acetyltransferase", + "2.3.1.68\tGlutamine N-acyltransferase", + "2.3.1.69\tMonoterpenol O-acetyltransferase", + "2.3.1.71\tGlycine N-benzoyltransferase", + "2.3.1.72\tIndoleacetylglucose--inositol O-acyltransferase", + "2.3.1.73\tDiacylglycerol--sterol O-acyltransferase", + "2.3.1.74\tNaringenin-chalcone synthase", + "2.3.1.75\tLong-chain-alcohol O-fatty-acyltransferase", + "2.3.1.76\tRetinol O-fatty-acyltransferase", + "2.3.1.77\tTriacylglycerol--sterol O-acyltransferase", + "2.3.1.78\tHeparan-alpha-glucosaminide N-acetyltransferase", + "2.3.1.79\tMaltose O-acetyltransferase", + "2.3.1.80\tCysteine-S-conjugate N-acetyltransferase", + "2.3.1.81\tAminoglycoside N(3)-acetyltransferase", + "2.3.1.82\tAminoglycoside 6'-N-acetyltransferase", + "2.3.1.83\tPhosphatidylcholine--dolichol O-acyltransferase", + "2.3.1.84\tAlcohol O-acetyltransferase", + "2.3.1.85\tFatty-acid synthase", + "2.3.1.86\tFatty-acyl-CoA synthase", + "2.3.1.87\tAralkylamine N-acetyltransferase", + "2.3.1.89\tTetrahydrodipicolinate N-acetyltransferase", + "2.3.1.90\tBeta-glucogallin O-galloyltransferase", + "2.3.1.91\tSinapoylglucose--choline O-sinapoyltransferase", + "2.3.1.92\tSinapoylglucose--malate O-sinapoyltransferase", + "2.3.1.93\t13-hydroxylupanine O-tigloyltransferase", + "2.3.1.94\t6-deoxyerythronolide-B synthase", + "2.3.1.95\tTrihydroxystilbene synthase", + "2.3.1.96\tGlycoprotein N-palmitoyltransferase", + "2.3.1.97\tGlycylpeptide N-tetradecanoyltransferase", + "2.3.1.98\tChlorogenate--glucarate O-hydroxycinnamoyltransferase", + "2.3.1.99\tQuinate O-hydroxycinnamoyltransferase", + "2.3.1.100\t[Myelin-proteolipid] O-palmitoyltransferase", + "2.3.1.101\tFormylmethanofuran--tetrahydromethanopterin N-formyltransferase", + "2.3.1.102\tN(6)-hydroxylysine O-acetyltransferase", + "2.3.1.103\tSinapoylglucose--sinapoylglucose O-sinapoyltransferase", + "2.3.1.105\tAlkylglycerophosphate 2-O-acetyltransferase", + "2.3.1.106\tTartronate O-hydroxycinnamoyltransferase", + "2.3.1.107\tDeacetylvindoline O-acetyltransferase", + "2.3.1.108\tAlpha-tubulin N-acetyltransferase", + "2.3.1.109\tArginine N-succinyltransferase", + "2.3.1.110\tTyramine N-feruloyltransferase", + "2.3.1.111\tMycocerosate synthase", + "2.3.1.112\tD-tryptophan N-malonyltransferase", + "2.3.1.113\tAnthranilate N-malonyltransferase", + "2.3.1.114\t3,4-dichloroaniline N-malonyltransferase", + "2.3.1.115\tIsoflavone-7-O-beta-glucoside 6''-O-malonyltransferase", + "2.3.1.116\tFlavonol-3-O-beta-glucoside O-malonyltransferase", + "2.3.1.117\t2,3,4,5-tetrahydropyridine-2,6-dicarboxylate N-succinyltransferase", + "2.3.1.118\tN-hydroxyarylamine O-acetyltransferase", + "2.3.1.121\t1-alkenylglycerophosphoethanolamine O-acyltransferase", + "2.3.1.122\tTrehalose O-mycolyltransferase", + "2.3.1.123\tDolichol O-acyltransferase", + "2.3.1.125\t1-alkyl-2-acetylglycerol O-acyltransferase", + "2.3.1.126\tIsocitrate O-dihydroxycinnamoyltransferase", + "2.3.1.127\tOrnithine N-benzoyltransferase", + "2.3.1.128\tRibosomal-protein-alanine N-acetyltransferase", + "2.3.1.129\tAcyl-[acyl-carrier-protein]--UDP-N-acetylglucosamine O-acyltransferase", + "2.3.1.130\tGalactarate O-hydroxycinnamoyltransferase", + "2.3.1.131\tGlucarate O-hydroxycinnamoyltransferase", + "2.3.1.132\tGlucarolactone O-hydroxycinnamoyltransferase", + "2.3.1.133\tShikimate O-hydroxycinnamoyltransferase", + "2.3.1.134\tGalactolipid O-acyltransferase", + "2.3.1.135\tPhosphatidylcholine--retinol O-acyltransferase", + "2.3.1.136\tPolysialic-acid O-acetyltransferase", + "2.3.1.137\tCarnitine O-octanoyltransferase", + "2.3.1.138\tPutrescine N-hydroxycinnamoyltransferase", + "2.3.1.139\tEcdysone O-acyltransferase", + "2.3.1.140\tRosmarinate synthase", + "2.3.1.141\tGalactosylacylglycerol O-acyltransferase", + "2.3.1.142\tGlycoprotein O-fatty-acyltransferase", + "2.3.1.143\tBeta-glucogallin--tetrakisgalloylglucose O-galloyltransferase", + "2.3.1.144\tAnthranilate N-benzoyltransferase", + "2.3.1.145\tPiperidine N-piperoyltransferase", + "2.3.1.146\tPinosylvin synthase", + "2.3.1.147\tGlycerophospholipid arachidonoyl-transferase (CoA-independent)", + "2.3.1.148\tGlycerophospholipid acyltransferase (CoA-dependent)", + "2.3.1.149\tPlatelet-activating factor acetyltransferase", + "2.3.1.150\tSalutaridinol 7-O-acetyltransferase", + "2.3.1.151\t2,3',4,6-tetrahydroxybenzophenone synthase", + "2.3.1.152\tAlcohol O-cinnamoyltransferase", + "2.3.1.153\tAnthocyanin 5-(6'''-hydroxycinnamoyltransferase)", + "2.3.1.155\tAcetyl-CoA C-myristoyltransferase", + "2.3.1.156\tPhloroisovalerophenone synthase", + "2.3.1.157\tGlucosamine-1-phosphate N-acetyltransferase", + "2.3.1.158\tPhospholipid:diacylglycerol acyltransferase", + "2.3.1.159\tAcridone synthase", + "2.3.1.160\tVinorine synthase", + "2.3.1.161\tLovastatin nonaketide synthase", + "2.3.1.162\tTaxadien-5-alpha-ol O-acetyltransferase", + "2.3.1.163\t10-hydroxytaxane O-acetyltransferase", + "2.3.1.164\tIsopenicillin-N N-acyltransferase", + "2.3.1.165\t6-methylsalicylic acid synthase", + "2.3.1.166\t2-alpha-hydroxytaxane 2-O-benzoyltransferase", + "2.3.1.167\t10-deacetylbaccatin III 10-O-acetyltransferase", + "2.3.1.168\tDihydrolipoyllysine-residue (2-methylpropanoyl)transferase", + "2.3.1.169\tCO-methylating acetyl-CoA synthase", + "2.3.1.170\t6'-deoxychalcone synthase", + "2.3.1.171\tAnthocyanin 6''-O-malonyltransferase", + "2.3.1.172\tAnthocyanin 5-O-glucoside 6'''-O-malonyltransferase", + "2.3.1.173\tFlavonol-3-O-triglucoside O-coumaroyltransferase", + "2.3.1.174\t3-oxoadipyl-CoA thiolase", + "2.3.1.175\tDeacetylcephalosporin-C acetyltransferase", + "2.3.1.176\tPropanoyl-CoA C-acyltransferase", + "2.3.1.177\t3,5-dihydroxybiphenyl synthase", + "2.3.1.178\tDiaminobutyrate acetyltransferase", + "2.3.1.179\tBeta-ketoacyl-[acyl-carrier-protein] synthase II", + "2.3.1.180\tBeta-ketoacyl-[acyl-carrier-protein] synthase III", + "2.3.1.181\tLipoyl(octanoyl) transferase", + "2.3.1.182\t(R)-citramalate synthase", + "2.3.1.183\tPhosphinothricin acetyltransferase", + "2.3.1.184\tAcyl-homoserine-lactone synthase", + "2.3.1.185\tTropine acyltransferase", + "2.3.1.186\tPseudotropine acyltransferase", + "2.3.1.187\tAcetyl-S-ACP:malonate ACP transferase", + "2.3.1.188\tOmega-hydroxypalmitate O-feruloyl transferase", + "2.3.1.189\tMycothiol synthase", + "2.3.1.190\tAcetoin dehydrogenase", + "2.3.1.191\tUDP-3-O-(3-hydroxymyristoyl)glucosamine N-acyltransferase", + "2.3.1.192\tGlycine N-phenylacetyltransferase", + "2.3.1.193\ttRNA(Met) cytidine acetyltransferase", + "2.3.1.194\tAcetoacetyl-CoA synthase", + "2.3.1.195\t(Z)-3-hexen-1-ol acetyltransferase", + "2.3.1.196\tBenzyl alcohol O-benzoyltransferase", + "2.3.1.197\tdTDP-3-amino-3,6-dideoxy-alpha-D-galactopyranose 3-N-acetyltransferase", + "2.3.1.198\tGlycerol-3-phosphate 2-O-acyltransferase", + "2.3.1.199\tVery-long-chain 3-oxoacyl-CoA synthase", + "2.3.1.200\tLipoyl amidotransferase", + "2.3.1.201\tUDP-2-acetamido-3-amino-2,3-dideoxy-glucuronate N-acetyltransferase", + "2.3.1.202\tUDP-4-amino-4,6-dideoxy-N-acetyl-beta-L-altrosamine N-acetyltransferase", + "2.3.1.203\tUDP-N-acetylbacillosamine N-acetyltransferase", + "2.3.1.204\tOctanoyl-[GcvH]:protein N-octanoyltransferase", + "2.3.1.205\tFumigaclavine B O-acetyltransferase", + "2.3.1.206\t3,5,7-trioxododecanoyl-CoA synthase", + "2.3.1.207\tBeta-ketodecanoyl-[acyl-carrier-protein] synthase", + "2.3.1.208\t4-hydroxycoumarin synthase", + "2.3.1.209\tdTDP-4-amino-4,6-dideoxy-D-glucose acyltransferase", + "2.3.1.210\tdTDP-4-amino-4,6-dideoxy-D-galactose acyltransferase", + "2.3.1.211\tBisdemethoxycurcumin synthase", + "2.3.1.212\tBenzalacetone synthase", + "2.3.1.213\tCyanidin 3-O-(6-O-glucosyl-2-O-xylosylgalactoside) 6'''-O-hydroxycinnamoyltransferase", + "2.3.1.214\tPelargonidin 3-O-(6-caffeoylglucoside) 5-O-(6-O-malonylglucoside) 4'''-malonyltransferase", + "2.3.1.215\tAnthocyanidin 3-O-glucoside 6''-O-acyltransferase", + "2.3.1.216\t5,7-dihydroxy-2-methylchromone synthase", + "2.3.1.217\tCurcumin synthase", + "2.3.1.218\tPhenylpropanoylacetyl-CoA synthase", + "2.3.1.219\tDemethoxycurcumin synthase", + "2.3.1.220\t2,4,6-trihydroxybenzophenone synthase", + "2.3.1.221\tNoranthrone synthase", + "2.3.1.222\tPhosphate propanoyltransferase", + "2.3.1.223\t3-oxo-5,6-didehydrosuberyl-CoA thiolase", + "2.3.1.224\tAcetyl-CoA-benzylalcohol acetyltransferase", + "2.3.1.225\tProtein S-acyltransferase", + "2.3.1.226\tCarboxymethylproline synthase", + "2.3.1.227\tGDP-perosamine N-acetyltransferase", + "2.3.1.228\tIsovaleryl-homoserine lactone synthase", + "2.3.1.229\t4-coumaroyl-homoserine lactone synthase", + "2.3.1.230\t2-heptyl-4(1H)-quinolone synthase", + "2.3.1.231\ttRNA(Phe) (7-(3-amino-3-(methoxycarbonyl)propyl)wyosine(37)-N)-methoxycarbonyltransferase", + "2.3.1.232\tMethanol O-anthraniloyltransferase", + "2.3.1.233\t1,3,6,8-tetrahydroxynaphthalene synthase", + "2.3.1.234\tN(6)-L-threonylcarbamoyladenine synthase", + "2.3.1.235\tTetracenomycin F2 synthase", + "2.3.1.236\t5-methylnaphthoic acid synthase", + "2.3.1.237\tNeocarzinostatin naphthoate synthase", + "2.3.1.238\tMonacolin J acid methylbutanoate transferase", + "2.3.1.239\t10-deoxymethynolide syntase", + "2.3.1.240\tNarbonolide synthase", + "2.3.1.241\tKdo(2)-lipid IV(A) lauroyltransferase", + "2.3.1.242\tKdo(2)-lipid IV(A) palmitoleoyltransferase", + "2.3.1.243\tLauroyl-Kdo(2)-lipid IV(A) myristoyltransferase", + "2.3.1.244\t2-methylbutanoate polyketide synthase", + "2.3.1.245\t3-hydroxy-5-phosphonooxypentane-2,4-dione thiolase", + "2.3.1.246\t3,5-dihydroxyphenylacetyl-CoA synthase", + "2.3.1.247\t3-keto-5-aminohexanoate cleavage enzyme", + "2.3.1.248\tSpermidine disinapoyl transferase", + "2.3.1.249\tSpermidine dicoumaroyl transferase", + "2.3.1.250\t[Wnt protein] O-palmitoleoyl transferase", + "2.3.1.251\tLipid IV(A) palmitoyltransferase", + "2.3.1.252\tMycolipanoate synthase", + "2.3.1.253\tPhloroglucinol synthase", + "2.3.1.254\tN-terminal methionine N(alpha)-acetyltransferase NatB", + "2.3.1.255\tN-terminal amino-acid N(alpha)-acetyltransferase NatA", + "2.3.1.256\tN-terminal methionine N(alpha)-acetyltransferase NatC", + "2.3.1.257\tN-terminal L-serine N(alpha)-acetyltransferase NatD", + "2.3.1.258\tN-terminal methionine N(alpha)-acetyltransferase NatE", + "2.3.1.259\tN-terminal methionine N(alpha)-acetyltransferase NatF", + "2.3.1.260\tTetracycline polyketide synthase", + "2.3.1.261\t(4-hydroxyphenyl)alkanoate synthase", + "2.3.1.262\tAnthraniloyl-CoA anthraniloyltransferase", + "2.3.1.263\t2-amino-4-oxopentanoate thiolase", + "2.3.1.n2\tPhosphate acyltransferase", + "2.3.1.n3\tGlycerol-3-phosphate acyltransferase (acyl-phosphate transferring)", + "2.3.1.n4\t1-acyl-sn-glycerol-3-phosphate acyltransferase", + "2.3.1.n5\tGlycerol-3-phosphate acyltransferase (acyl-[acyl-carrier-protein]-transferring)", + "2.3.1.n6\t1-acylglycerophosphoserine O-acyltransferase", + "2.3.1.n7\t1-acylglycerophosphoethanolamine O-acyltransferase", + "2.3.1.n12\tSinapoyl-beta-D-glucose:anthocyanin sinapoyltransferase", + "2.3.2.1\tD-glutamyltransferase", + "2.3.2.2\tGamma-glutamyltransferase", + "2.3.2.3\tLysyltransferase", + "2.3.2.4\tGamma-glutamylcyclotransferase", + "2.3.2.5\tGlutaminyl-peptide cyclotransferase", + "2.3.2.6\tLysine/arginine leucyltransferase", + "2.3.2.7\tAspartyltransferase", + "2.3.2.8\tArginyltransferase", + "2.3.2.9\tAgaritine gamma-glutamyltransferase", + "2.3.2.10\tUDP-N-acetylmuramoylpentapeptide-lysine N(6)-alanyltransferase", + "2.3.2.11\tAlanylphosphatidylglycerol synthase", + "2.3.2.12\tPeptidyltransferase", + "2.3.2.13\tProtein-glutamine gamma-glutamyltransferase", + "2.3.2.14\tD-alanine gamma-glutamyltransferase", + "2.3.2.15\tGlutathione gamma-glutamylcysteinyltransferase", + "2.3.2.16\tLipid II:glycine glycyltransferase", + "2.3.2.17\tN-acetylmuramoyl-L-alanyl-D-glutamyl-L-lysyl-(N(6)-glycyl)-D-alanyl-D-alanine-diphosphoundecaprenyl-N-acetylglucosamine:glycine glycyltransferase", + "2.3.2.18\tN-acetylmuramoyl-L-alanyl-D-glutamyl-L-lysyl-(N(6)-triglycine)-D-alanyl-D-alanine-diphosphoundecaprenyl-N-acetylglucosamine:glycine glycyltransferase", + "2.3.2.19\tRibostamycin:4-(gamma-L-glutamylamino)-(S)-2-hydroxybutanoyl-[BtrI acyl-carrier protein] 4-(gamma-L-glutamylamino)-(S)-2-hydroxybutanoate transferase", + "2.3.2.20\tCyclo(L-leucyl-L-phenylalanyl) synthase", + "2.3.2.21\tCyclo(L-tyrosyl-L-tyrosyl) synthase", + "2.3.2.22\tCyclo(L-leucyl-L-leucyl) synthase", + "2.3.2.23\tE2 ubiquitin-conjugating enzyme", + "2.3.2.24\t(E3-independent) E2 ubiquitin-conjugating enzyme", + "2.3.2.25\tN-terminal E2 ubiquitin-conjugating enzyme", + "2.3.2.26\tHECT-type E3 ubiquitin transferase", + "2.3.2.27\tRING-type E3 ubiquitin transferase", + "2.3.2.28\tL-allo-isoleucyltransferase", + "2.3.2.29\tAspartate/glutamate leucyltransferase", + "2.3.3.1\tCitrate (Si)-synthase", + "2.3.3.2\tDecylcitrate synthase", + "2.3.3.3\tCitrate (Re)-synthase", + "2.3.3.4\tDecylhomocitrate synthase", + "2.3.3.5\t2-methylcitrate synthase", + "2.3.3.6\t2-ethylmalate synthase", + "2.3.3.7\t3-ethylmalate synthase", + "2.3.3.8\tATP citrate synthase", + "2.3.3.9\tMalate synthase", + "2.3.3.10\tHydroxymethylglutaryl-CoA synthase", + "2.3.3.11\t2-hydroxyglutarate synthase", + "2.3.3.12\t3-propylmalate synthase", + "2.3.3.13\t2-isopropylmalate synthase", + "2.3.3.14\tHomocitrate synthase", + "2.3.3.15\tSulfoacetaldehyde acetyltransferase", + "2.3.3.16\tCitrate synthase (unknown stereospecificity)", + "2.3.3.17\tMethylthioalkylmalate synthase", + "2.3.3.18\t2-phosphinomethylmalate synthase", + "2.4.1.1\tGlycogen phosphorylase", + "2.4.1.2\tDextrin dextranase", + "2.4.1.4\tAmylosucrase", + "2.4.1.5\tDextransucrase", + "2.4.1.7\tSucrose phosphorylase", + "2.4.1.8\tMaltose phosphorylase", + "2.4.1.9\tInulosucrase", + "2.4.1.10\tLevansucrase", + "2.4.1.11\tGlycogen(starch) synthase", + "2.4.1.12\tCellulose synthase (UDP-forming)", + "2.4.1.13\tSucrose synthase", + "2.4.1.14\tSucrose-phosphate synthase", + "2.4.1.15\tAlpha,alpha-trehalose-phosphate synthase (UDP-forming)", + "2.4.1.16\tChitin synthase", + "2.4.1.17\tGlucuronosyltransferase", + "2.4.1.18\t1,4-alpha-glucan branching enzyme", + "2.4.1.19\tCyclomaltodextrin glucanotransferase", + "2.4.1.20\tCellobiose phosphorylase", + "2.4.1.21\tStarch synthase", + "2.4.1.22\tLactose synthase", + "2.4.1.23\tSphingosine beta-galactosyltransferase", + "2.4.1.24\t1,4-alpha-glucan 6-alpha-glucosyltransferase", + "2.4.1.25\t4-alpha-glucanotransferase", + "2.4.1.26\tDNA alpha-glucosyltransferase", + "2.4.1.27\tDNA beta-glucosyltransferase", + "2.4.1.28\tGlucosyl-DNA beta-glucosyltransferase", + "2.4.1.29\tCellulose synthase (GDP-forming)", + "2.4.1.30\t1,3-beta-oligoglucan phosphorylase", + "2.4.1.31\tLaminaribiose phosphorylase", + "2.4.1.32\tGlucomannan 4-beta-mannosyltransferase", + "2.4.1.33\tMannuronan synthase", + "2.4.1.34\t1,3-beta-glucan synthase", + "2.4.1.35\tPhenol beta-glucosyltransferase", + "2.4.1.36\tAlpha,alpha-trehalose-phosphate synthase (GDP-forming)", + "2.4.1.37\tFucosylgalactoside 3-alpha-galactosyltransferase", + "2.4.1.38\tBeta-N-acetylglucosaminylglycopeptide beta-1,4-galactosyltransferase", + "2.4.1.39\tSteroid N-acetylglucosaminyltransferase", + "2.4.1.40\tGlycoprotein-fucosylgalactoside alpha-N-acetylgalactosaminyltransferase", + "2.4.1.41\tPolypeptide N-acetylgalactosaminyltransferase", + "2.4.1.43\tPolygalacturonate 4-alpha-galacturonosyltransferase", + "2.4.1.44\tLipopolysaccharide 3-alpha-galactosyltransferase", + "2.4.1.46\tMonogalactosyldiacylglycerol synthase", + "2.4.1.47\tN-acylsphingosine galactosyltransferase", + "2.4.1.48\tHeteroglycan alpha-mannosyltransferase", + "2.4.1.49\tCellodextrin phosphorylase", + "2.4.1.50\tProcollagen galactosyltransferase", + "2.4.1.52\tPoly(glycerol-phosphate) alpha-glucosyltransferase", + "2.4.1.53\tPoly(ribitol-phosphate) beta-glucosyltransferase", + "2.4.1.54\tUndecaprenyl-phosphate mannosyltransferase", + "2.4.1.56\tLipopolysaccharide N-acetylglucosaminyltransferase", + "2.4.1.57\tPhosphatidylinositol alpha-mannosyltransferase", + "2.4.1.58\tLipopolysaccharide glucosyltransferase I", + "2.4.1.60\tAbequosyltransferase", + "2.4.1.62\tGanglioside galactosyltransferase", + "2.4.1.63\tLinamarin synthase", + "2.4.1.64\tAlpha,alpha-trehalose phosphorylase", + "2.4.1.65\t3-galactosyl-N-acetylglucosaminide 4-alpha-L-fucosyltransferase", + "2.4.1.66\tProcollagen glucosyltransferase", + "2.4.1.67\tGalactinol--raffinose galactosyltransferase", + "2.4.1.68\tGlycoprotein 6-alpha-L-fucosyltransferase", + "2.4.1.69\tType 1 galactoside alpha-(1,2)-fucosyltransferase", + "2.4.1.70\tPoly(ribitol-phosphate) N-acetylglucosaminyltransferase", + "2.4.1.71\tArylamine glucosyltransferase", + "2.4.1.73\tLipopolysaccharide glucosyltransferase II", + "2.4.1.74\tGlycosaminoglycan galactosyltransferase", + "2.4.1.78\tPhosphopolyprenol glucosyltransferase", + "2.4.1.79\tGlobotriaosylceramide 3-beta-N-acetylgalactosaminyltransferase", + "2.4.1.80\tCeramide glucosyltransferase", + "2.4.1.81\tFlavone 7-O-beta-glucosyltransferase", + "2.4.1.82\tGalactinol--sucrose galactosyltransferase", + "2.4.1.83\tDolichyl-phosphate beta-D-mannosyltransferase", + "2.4.1.85\tCyanohydrin beta-glucosyltransferase", + "2.4.1.86\tGlucosaminylgalactosylglucosylceramide beta-galactosyltransferase", + "2.4.1.87\tN-acetyllactosaminide 3-alpha-galactosyltransferase", + "2.4.1.88\tGloboside alpha-N-acetylgalactosaminyltransferase", + "2.4.1.90\tN-acetyllactosamine synthase", + "2.4.1.91\tFlavonol 3-O-glucosyltransferase", + "2.4.1.92\t(N-acetylneuraminyl)-galactosylglucosylceramide N-acetylgalactosaminyltransferase", + "2.4.1.94\tProtein N-acetylglucosaminyltransferase", + "2.4.1.95\tBilirubin-glucuronoside glucuronosyltransferase", + "2.4.1.96\tsn-glycerol-3-phosphate 1-galactosyltransferase", + "2.4.1.97\t1,3-beta-D-glucan phosphorylase", + "2.4.1.99\tSucrose:sucrose fructosyltransferase", + "2.4.1.100\t2,1-fructan:2,1-fructan 1-fructosyltransferase", + "2.4.1.101\tAlpha-1,3-mannosyl-glycoprotein 2-beta-N-acetylglucosaminyltransferase", + "2.4.1.102\tBeta-1,3-galactosyl-O-glycosyl-glycoprotein beta-1,6-N-acetylglucosaminyltransferase", + "2.4.1.103\tAlizarin 2-beta-glucosyltransferase", + "2.4.1.104\to-dihydroxycoumarin 7-O-glucosyltransferase", + "2.4.1.105\tVitexin beta-glucosyltransferase", + "2.4.1.106\tIsovitexin beta-glucosyltransferase", + "2.4.1.109\tDolichyl-phosphate-mannose--protein mannosyltransferase", + "2.4.1.110\ttRNA-queuosine beta-mannosyltransferase", + "2.4.1.111\tConiferyl-alcohol glucosyltransferase", + "2.4.1.113\tAlpha-1,4-glucan-protein synthase (ADP-forming)", + "2.4.1.114\t2-coumarate O-beta-glucosyltransferase", + "2.4.1.115\tAnthocyanidin 3-O-glucosyltransferase", + "2.4.1.116\tCyanidin 3-O-rutinoside 5-O-glucosyltransferase", + "2.4.1.117\tDolichyl-phosphate beta-glucosyltransferase", + "2.4.1.118\tCytokinin 7-beta-glucosyltransferase", + "2.4.1.120\tSinapate 1-glucosyltransferase", + "2.4.1.121\tIndole-3-acetate beta-glucosyltransferase", + "2.4.1.122\tN-acetylgalactosaminide beta-1,3-galactosyltransferase", + "2.4.1.123\tInositol 3-alpha-galactosyltransferase", + "2.4.1.125\tSucrose--1,6-alpha-glucan 3(6)-alpha-glucosyltransferase", + "2.4.1.126\tHydroxycinnamate 4-beta-glucosyltransferase", + "2.4.1.127\tMonoterpenol beta-glucosyltransferase", + "2.4.1.128\tScopoletin glucosyltransferase", + "2.4.1.129\tPeptidoglycan glycosyltransferase", + "2.4.1.131\tGDP-Man:Man(3)GlcNAc(2)-PP-dolichol alpha-1,2-mannosyltransferase", + "2.4.1.132\tGDP-Man:Man(1)GlcNAc(2)-PP-dolichol alpha-1,3-mannosyltransferase", + "2.4.1.133\tXylosylprotein 4-beta-galactosyltransferase", + "2.4.1.134\tGalactosylxylosylprotein 3-beta-galactosyltransferase", + "2.4.1.135\tGalactosylgalactosylxylosylprotein 3-beta-glucuronosyltransferase", + "2.4.1.136\tGallate 1-beta-glucosyltransferase", + "2.4.1.137\tsn-glycerol-3-phosphate 2-alpha-galactosyltransferase", + "2.4.1.138\tMannotetraose 2-alpha-N-acetylglucosaminyltransferase", + "2.4.1.139\tMaltose synthase", + "2.4.1.140\tAlternansucrase", + "2.4.1.141\tN-acetylglucosaminyldiphosphodolichol N-acetylglucosaminyltransferase", + "2.4.1.142\tChitobiosyldiphosphodolichol beta-mannosyltransferase", + "2.4.1.143\tAlpha-1,6-mannosyl-glycoprotein 2-beta-N-acetylglucosaminyltransferase", + "2.4.1.144\tBeta-1,4-mannosyl-glycoprotein 4-beta-N-acetylglucosaminyltransferase", + "2.4.1.145\tAlpha-1,3-mannosyl-glycoprotein 4-beta-N-acetylglucosaminyltransferase", + "2.4.1.146\tBeta-1,3-galactosyl-O-glycosyl-glycoprotein beta-1,3-N-acetylglucosaminyltransferase", + "2.4.1.147\tAcetylgalactosaminyl-O-glycosyl-glycoprotein beta-1,3-N-acetylglucosaminyltransferase", + "2.4.1.148\tAcetylgalactosaminyl-O-glycosyl-glycoprotein beta-1,6-N-acetylglucosaminyltransferase", + "2.4.1.149\tN-acetyllactosaminide beta-1,3-N-acetylglucosaminyltransferase", + "2.4.1.150\tN-acetyllactosaminide beta-1,6-N-acetylglucosaminyl-transferase", + "2.4.1.152\t4-galactosyl-N-acetylglucosaminide 3-alpha-L-fucosyltransferase", + "2.4.1.153\tUDP-N-acetylglucosamine--dolichyl-phosphate N-acetylglucosaminyltransferase", + "2.4.1.155\tAlpha-1,6-mannosyl-glycoprotein 6-beta-N-acetylglucosaminyltransferase", + "2.4.1.156\tIndolylacetyl-myo-inositol galactosyltransferase", + "2.4.1.158\t13-hydroxydocosanoate 13-beta-glucosyltransferase", + "2.4.1.159\tFlavonol-3-O-glucoside L-rhamnosyltransferase", + "2.4.1.160\tPyridoxine 5'-O-beta-D-glucosyltransferase", + "2.4.1.161\tOligosaccharide 4-alpha-D-glucosyltransferase", + "2.4.1.162\tAldose beta-D-fructosyltransferase", + "2.4.1.164\tGalactosyl-N-acetylglucosaminylgalactosylglucosyl-ceramide beta-1,6-N-acetylglucosaminyltransferase", + "2.4.1.165\tN-acetylneuraminylgalactosylglucosylceramide beta-1,4-N-acetylgalactosaminyltransferase", + "2.4.1.166\tRaffinose--raffinose alpha-galactosyltransferase", + "2.4.1.167\tSucrose 6(F)-alpha-galactosyltransferase", + "2.4.1.168\tXyloglucan 4-glucosyltransferase", + "2.4.1.170\tIsoflavone 7-O-glucosyltransferase", + "2.4.1.171\tMethyl-ONN-azoxymethanol beta-D-glucosyltransferase", + "2.4.1.172\tSalicyl-alcohol beta-D-glucosyltransferase", + "2.4.1.173\tSterol 3-beta-glucosyltransferase", + "2.4.1.174\tGlucuronylgalactosylproteoglycan 4-beta-N-acetylgalactosaminyltransferase", + "2.4.1.175\tGlucuronosyl-N-acetylgalactosaminyl-proteoglycan 4-beta-N-acetylgalactosaminyltransferase", + "2.4.1.176\tGibberellin beta-D-glucosyltransferase", + "2.4.1.177\tCinnamate beta-D-glucosyltransferase", + "2.4.1.178\tHydroxymandelonitrile glucosyltransferase", + "2.4.1.179\tLactosylceramide beta-1,3-galactosyltransferase", + "2.4.1.180\tLipopolysaccharide N-acetylmannosaminouronosyltransferase", + "2.4.1.181\tHydroxyanthraquinone glucosyltransferase", + "2.4.1.182\tLipid-A-disaccharide synthase", + "2.4.1.183\tAlpha-1,3-glucan synthase", + "2.4.1.184\tGalactolipid galactosyltransferase", + "2.4.1.185\tFlavanone 7-O-beta-glucosyltransferase", + "2.4.1.186\tGlycogenin glucosyltransferase", + "2.4.1.187\tN-acetylglucosaminyldiphosphoundecaprenol N-acetyl-beta-D-mannosaminyltransferase", + "2.4.1.188\tN-acetylglucosaminyldiphosphoundecaprenol glucosyltransferase", + "2.4.1.189\tLuteolin 7-O-glucuronosyltransferase", + "2.4.1.190\tLuteolin-7-O-glucuronide 2''-O-glucuronosyltransferase", + "2.4.1.191\tLuteolin-7-O-diglucuronide 4'-O-glucuronosyltransferase", + "2.4.1.192\tNuatigenin 3-beta-glucosyltransferase", + "2.4.1.193\tSarsapogenin 3-beta-glucosyltransferase", + "2.4.1.194\t4-hydroxybenzoate 4-O-beta-D-glucosyltransferase", + "2.4.1.195\tN-hydroxythioamide S-beta-glucosyltransferase", + "2.4.1.196\tNicotinate glucosyltransferase", + "2.4.1.197\tHigh-mannose-oligosaccharide beta-1,4-N-acetylglucosaminyltransferase", + "2.4.1.198\tPhosphatidylinositol N-acetylglucosaminyltransferase", + "2.4.1.199\tBeta-mannosylphosphodecaprenol--mannooligosaccharide 6-mannosyltransferase", + "2.4.1.201\tAlpha-1,6-mannosyl-glycoprotein 4-beta-N-acetylglucosaminyltransferase", + "2.4.1.202\t2,4-dihydroxy-7-methoxy-2H-1,4-benzoxazin-3(4H)-one 2-D-glucosyltransferase", + "2.4.1.203\tTrans-zeatin O-beta-D-glucosyltransferase", + "2.4.1.205\tGalactogen 6-beta-galactosyltransferase", + "2.4.1.206\tLactosylceramide 1,3-N-acetyl-beta-D-glucosaminyltransferase", + "2.4.1.207\tXyloglucan:xyloglucosyl transferase", + "2.4.1.208\tDiglucosyl diacylglycerol synthase (1,2-linking)", + "2.4.1.209\tCis-p-coumarate glucosyltransferase", + "2.4.1.210\tLimonoid glucosyltransferase", + "2.4.1.211\t1,3-beta-galactosyl-N-acetylhexosamine phosphorylase", + "2.4.1.212\tHyaluronan synthase", + "2.4.1.213\tGlucosylglycerol-phosphate synthase", + "2.4.1.214\tGlycoprotein 3-alpha-L-fucosyltransferase", + "2.4.1.215\tCis-zeatin O-beta-D-glucosyltransferase", + "2.4.1.216\tTrehalose 6-phosphate phosphorylase", + "2.4.1.217\tMannosyl-3-phosphoglycerate synthase", + "2.4.1.218\tHydroquinone glucosyltransferase", + "2.4.1.219\tVomilenine glucosyltransferase", + "2.4.1.220\tIndoxyl-UDPG glucosyltransferase", + "2.4.1.221\tPeptide-O-fucosyltransferase", + "2.4.1.222\tO-fucosylpeptide 3-beta-N-acetylglucosaminyltransferase", + "2.4.1.223\tGlucuronosyl-galactosyl-proteoglycan 4-alpha-N-acetylglucosaminyltransferase", + "2.4.1.224\tGlucuronosyl-N-acetylglucosaminyl-proteoglycan 4-alpha-N-acetylglucosaminyltransferase", + "2.4.1.225\tN-acetylglucosaminyl-proteoglycan 4-beta-glucuronosyltransferase", + "2.4.1.226\tN-acetylgalactosaminyl-proteoglycan 3-beta-glucuronosyltransferase", + "2.4.1.227\tUndecaprenyldiphospho-muramoylpentapeptide beta-N-acetylglucosaminyltransferase", + "2.4.1.228\tLactosylceramide 4-alpha-galactosyltransferase", + "2.4.1.229\t[Skp1-protein]-hydroxyproline N-acetylglucosaminyltransferase", + "2.4.1.230\tKojibiose phosphorylase", + "2.4.1.231\tAlpha,alpha-trehalose phosphorylase (configuration-retaining)", + "2.4.1.232\tInitiation-specific alpha-1,6-mannosyltransferase", + "2.4.1.234\tKaempferol 3-O-galactosyltransferase", + "2.4.1.236\tFlavanone 7-O-glucoside 2''-O-beta-L-rhamnosyltransferase", + "2.4.1.237\tFlavonol 7-O-beta-glucosyltransferase", + "2.4.1.238\tDelphinidin 3,5-di-O-glucoside 3'-O-glucosyltransferase", + "2.4.1.239\tFlavonol-3-O-glucoside glucosyltransferase", + "2.4.1.240\tFlavonol-3-O-glycoside glucosyltransferase", + "2.4.1.241\tDigalactosyldiacylglycerol synthase", + "2.4.1.242\tNDP-glucose--starch glucosyltransferase", + "2.4.1.243\t6(G)-fructosyltransferase", + "2.4.1.244\tN-acetyl-beta-glucosaminyl-glycoprotein 4-beta-N-acetylgalactosaminyltransferase", + "2.4.1.245\tAlpha,alpha-trehalose synthase", + "2.4.1.246\tMannosylfructose-phosphate synthase", + "2.4.1.247\tBeta-D-galactosyl-(1->4)-L-rhamnose phosphorylase", + "2.4.1.248\tCycloisomaltooligosaccharide glucanotransferase", + "2.4.1.249\tDelphinidin 3',5'-O-glucosyltransferase", + "2.4.1.250\tD-inositol-3-phosphate glycosyltransferase", + "2.4.1.251\tGlcA-beta-(1->2)-D-Man-alpha-(1->3)-D-Glc-beta-(1->4)-D-Glc-alpha-1-diphospho-ditrans,octacis-undecaprenol 4-beta-mannosyltransferase", + "2.4.1.252\tGDP-mannose:cellobiosyl-diphosphopolyprenol alpha-mannosyltransferase", + "2.4.1.253\tBaicalein 7-O-glucuronosyltransferase", + "2.4.1.254\tCyanidin-3-O-glucoside 2''-O-glucuronosyltransferase", + "2.4.1.255\tProtein O-GlcNAc transferase", + "2.4.1.256\tDolichyl-P-Glc:Glc(2)Man(9)GlcNAc(2)-PP-dolichol alpha-1,2-glucosyltransferase", + "2.4.1.257\tGDP-Man:Man(2)GlcNAc(2)-PP-dolichol alpha-1,6-mannosyltransferase", + "2.4.1.258\tDolichyl-P-Man:Man(5)GlcNAc(2)-PP-dolichol alpha-1,3-mannosyltransferase", + "2.4.1.259\tDolichyl-P-Man:Man(6)GlcNAc(2)-PP-dolichol alpha-1,2-mannosyltransferase", + "2.4.1.260\tDolichyl-P-Man:Man(7)GlcNAc(2)-PP-dolichol alpha-1,6-mannosyltransferase", + "2.4.1.261\tDolichyl-P-Man:Man(8)GlcNAc(2)-PP-dolichol alpha-1,2-mannosyltransferase", + "2.4.1.262\tSoyasapogenol glucuronosyltransferase", + "2.4.1.263\tAbscisate beta-glucosyltransferase", + "2.4.1.264\tD-man-alpha-(1->3)-D-Glc-beta-(1->4)-D-Glc-alpha-1-diphosphoundecaprenol 2-beta-glucuronosyltransferase", + "2.4.1.265\tDolichyl-P-Glc:Glc(1)Man(9)GlcNAc(2)-PP-dolichol alpha-1,3-glucosyltransferase", + "2.4.1.266\tGlucosyl-3-phosphoglycerate synthase", + "2.4.1.267\tDolichyl-P-Glc:Man(9)GlcNAc(2)-PP-dolichol alpha-1,3-glucosyltransferase", + "2.4.1.268\tGlucosylglycerate synthase", + "2.4.1.269\tMannosylglycerate synthase", + "2.4.1.270\tMannosylglucosyl-3-phosphoglycerate synthase", + "2.4.1.271\tCrocetin glucosyltransferase", + "2.4.1.272\tSoyasapogenol B glucuronide galactosyltransferase", + "2.4.1.273\tSoyasaponin III rhamnosyltransferase", + "2.4.1.274\tGlucosylceramide beta-1,4-galactosyltransferase", + "2.4.1.275\tNeolactotriaosylceramide beta-1,4-galactosyltransferase", + "2.4.1.276\tZeaxanthin glucosyltransferase", + "2.4.1.277\t10-deoxymethynolide desosaminyltransferase", + "2.4.1.278\t3-alpha-mycarosylerythronolide B desosaminyl transferase", + "2.4.1.279\tNigerose phosphorylase", + "2.4.1.280\tN,N'-diacetylchitobiose phosphorylase", + "2.4.1.281\t4-O-beta-D-mannosyl-D-glucose phosphorylase", + "2.4.1.282\t3-O-alpha-D-glucosyl-L-rhamnose phosphorylase", + "2.4.1.283\t2-deoxystreptamine N-acetyl-D-glucosaminyltransferase", + "2.4.1.284\t2-deoxystreptamine glucosyltransferase", + "2.4.1.285\tUDP-GlcNAc:ribostamycin N-acetylglucosaminyltransferase", + "2.4.1.286\tChalcone 4'-O-glucosyltransferase", + "2.4.1.287\tRhamnopyranosyl-N-acetylglucosaminyl-diphospho-decaprenol beta-1,4/1,5-galactofuranosyltransferase", + "2.4.1.288\tGalactofuranosylgalactofuranosylrhamnosyl-N-acetylglucosaminyl-diphospho-decaprenol beta-1,5/1,6-galactofuranosyltransferase", + "2.4.1.289\tN-acetylglucosaminyl-diphospho-decaprenol L-rhamnosyltransferase", + "2.4.1.290\tN,N'-diacetylbacillosaminyl-diphospho-undecaprenol alpha-1,3-N-acetylgalactosaminyltransferase", + "2.4.1.291\tN-acetylgalactosamine-N,N'-diacetylbacillosaminyl-diphospho-undecaprenol 4-alpha-N-acetylgalactosaminyltransferase", + "2.4.1.292\tGalNAc-alpha-(1->4)-GalNAc-alpha-(1->3)-diNAcBac-PP-undecaprenol alpha-1,4-N-acetyl-D-galactosaminyltransferase", + "2.4.1.293\tGalNAc(5)-diNAcBac-PP-undecaprenol beta-1,3-glucosyltransferase", + "2.4.1.294\tCyanidin 3-O-galactosyltransferase", + "2.4.1.295\tAnthocyanin 3-O-sambubioside 5-O-glucosyltransferase", + "2.4.1.296\tAnthocyanidin 3-O-coumaroylrutinoside 5-O-glucosyltransferase", + "2.4.1.297\tAnthocyanidin 3-O-glucoside 2''-O-glucosyltransferase", + "2.4.1.298\tAnthocyanidin 3-O-glucoside 5-O-glucosyltransferase", + "2.4.1.299\tCyanidin 3-O-glucoside 5-O-glucosyltransferase (acyl-glucose)", + "2.4.1.300\tCyanidin 3-O-glucoside 7-O-glucosyltransferase (acyl-glucose)", + "2.4.1.301\t2'-deamino-2'-hydroxyneamine 1-alpha-D-kanosaminyltransferase", + "2.4.1.302\tL-demethylnoviosyl transferase", + "2.4.1.303\tUDP-Gal:alpha-D-GlcNAc-diphosphoundecaprenol beta-1,3-galactosyltransferase", + "2.4.1.304\tUDP-Gal:alpha-D-GlcNAc-diphosphoundecaprenol beta-1,4-galactosyltransferase", + "2.4.1.305\tUDP-Glc:alpha-D-GlcNAc-glucosaminyl-diphosphoundecaprenol beta-1,3-glucosyltransferase", + "2.4.1.306\tUDP-GalNAc:alpha-D-GalNAc-diphosphoundecaprenol alpha-1,3-N-acetylgalactosaminyltransferase", + "2.4.1.308\tGDP-Fuc:beta-D-Gal-1,3-alpha-D-GalNAc-1,3-alpha-GalNAc-diphosphoundecaprenol alpha-1,2-fucosyltransferase", + "2.4.1.309\tUDP-Gal:alpha-L-Fuc-1,2-beta-Gal-1,3-alpha-GalNAc-1,3-alpha-GalNAc-diphosphoundecaprenol alpha-1,3-galactosyltransferase", + "2.4.1.310\tVancomycin aglycone glucosyltransferase", + "2.4.1.311\tdTDP-epi-vancosaminyltransferase", + "2.4.1.312\tProtein O-mannose beta-1,4-N-acetylglucosaminyltransferase", + "2.4.1.313\tProtein O-mannose beta-1,3-N-acetylgalactosaminyltransferase", + "2.4.1.314\tGinsenoside Rd glucosyltransferase", + "2.4.1.315\tDiglucosyl diacylglycerol synthase (1,6-linking)", + "2.4.1.316\tTylactone mycaminosyltransferase", + "2.4.1.317\tO-mycaminosyltylonolide 6-deoxyallosyltransferase", + "2.4.1.318\tDemethyllactenocin mycarosyltransferase", + "2.4.1.319\tBeta-1,4-mannooligosaccharide phosphorylase", + "2.4.1.320\t1,4-beta-mannosyl-N-acetylglucosamine phosphorylase", + "2.4.1.321\tCellobionic acid phosphorylase", + "2.4.1.322\tDevancosaminyl-vancomycin vancosaminetransferase", + "2.4.1.323\t7-deoxyloganetic acid glucosyltransferase", + "2.4.1.324\t7-deoxyloganetin glucosyltransferase", + "2.4.1.325\tTDP-N-acetylfucosamine:lipid II N-acetylfucosaminyltransferase", + "2.4.1.326\tAklavinone 7-L-rhodosaminyltransferase", + "2.4.1.327\tAclacinomycin-T 2-deoxy-L-fucose transferase", + "2.4.1.328\tErythronolide mycarosyltransferase", + "2.4.1.329\tSucrose 6(F)-phosphate phosphorylase", + "2.4.1.330\tBeta-D-glucosyl crocetin beta-1,6-glucosyltransferase", + "2.4.1.331\t8-demethyltetracenomycin C L-rhamnosyltransferase", + "2.4.1.332\t1,2-alpha-glucosylglycerol phosphorylase", + "2.4.1.333\t1,2-beta-oligoglucan phosphorylase", + "2.4.1.334\t1,3-alpha-oligoglucan phosphorylase", + "2.4.1.335\tDolichyl N-acetyl-alpha-D-glucosaminyl phosphate 3-beta-D-2,3-diacetamido-2,3-dideoxy-beta-D-glucuronosyltransferase", + "2.4.1.336\tMonoglucosyldiacylglycerol synthase", + "2.4.1.337\t1,2-diacylglycerol 3-alpha-glucosyltransferase", + "2.4.1.338\tValidoxylamine A glucosyltransferase", + "2.4.1.339\tBeta-1,2-mannobiose phosphorylase", + "2.4.1.340\t1,2-beta-oligomannan phosphorylase", + "2.4.1.341\tAlpha-1,2-colitosyltransferase", + "2.4.1.342\tAlpha-maltose-1-phosphate synthase", + "2.4.1.343\tUDP-Gal:alpha-D-GlcNAc-diphosphoundecaprenol alpha-1,3-galactosyltransferase", + "2.4.1.344\tType 2 galactoside alpha-(1,2)-fucosyltransferase", + "2.4.1.n2\tLoliose synthase", + "2.4.2.1\tPurine-nucleoside phosphorylase", + "2.4.2.2\tPyrimidine-nucleoside phosphorylase", + "2.4.2.3\tUridine phosphorylase", + "2.4.2.4\tThymidine phosphorylase", + "2.4.2.5\tNucleoside ribosyltransferase", + "2.4.2.6\tNucleoside deoxyribosyltransferase", + "2.4.2.7\tAdenine phosphoribosyltransferase", + "2.4.2.8\tHypoxanthine phosphoribosyltransferase", + "2.4.2.9\tUracil phosphoribosyltransferase", + "2.4.2.10\tOrotate phosphoribosyltransferase", + "2.4.2.12\tNicotinamide phosphoribosyltransferase", + "2.4.2.14\tAmidophosphoribosyltransferase", + "2.4.2.15\tGuanosine phosphorylase", + "2.4.2.16\tUrate-ribonucleotide phosphorylase", + "2.4.2.17\tATP phosphoribosyltransferase", + "2.4.2.18\tAnthranilate phosphoribosyltransferase", + "2.4.2.19\tNicotinate-nucleotide diphosphorylase (carboxylating)", + "2.4.2.20\tDioxotetrahydropyrimidine phosphoribosyltransferase", + "2.4.2.21\tNicotinate-nucleotide--dimethylbenzimidazole phosphoribosyltransferase", + "2.4.2.22\tXanthine phosphoribosyltransferase", + "2.4.2.24\t1,4-beta-D-xylan synthase", + "2.4.2.25\tFlavone apiosyltransferase", + "2.4.2.26\tProtein xylosyltransferase", + "2.4.2.27\tdTDP-dihydrostreptose--streptidine-6-phosphate dihydrostreptosyltransferase", + "2.4.2.28\tS-methyl-5'-thioadenosine phosphorylase", + "2.4.2.29\ttRNA-guanine(34) transglycosylase", + "2.4.2.30\tNAD(+) ADP-ribosyltransferase", + "2.4.2.31\tNAD(+)--protein-arginine ADP-ribosyltransferase", + "2.4.2.32\tDolichyl-phosphate D-xylosyltransferase", + "2.4.2.33\tDolichyl-xylosyl-phosphate--protein xylosyltransferase", + "2.4.2.34\tIndolylacetylinositol arabinosyltransferase", + "2.4.2.35\tFlavonol-3-O-glycoside xylosyltransferase", + "2.4.2.36\tNAD(+)--diphthamide ADP-ribosyltransferase", + "2.4.2.37\tNAD(+)--dinitrogen-reductase ADP-D-ribosyltransferase", + "2.4.2.38\tGlycoprotein 2-beta-D-xylosyltransferase", + "2.4.2.39\tXyloglucan 6-xylosyltransferase", + "2.4.2.40\tZeatin O-beta-D-xylosyltransferase", + "2.4.2.41\tXylogalacturonan beta-1,3-xylosyltransferase", + "2.4.2.42\tUDP-D-xylose:beta-D-glucoside alpha-1,3-D-xylosyltransferase", + "2.4.2.43\tLipid IV(A) 4-amino-4-deoxy-L-arabinosyltransferase", + "2.4.2.44\tS-methyl-5'-thioinosine phosphorylase", + "2.4.2.45\tDecaprenyl-phosphate phosphoribosyltransferase", + "2.4.2.46\tGalactan 5-O-arabinofuranosyltransferase", + "2.4.2.47\tArabinofuranan 3-O-arabinosyltransferase", + "2.4.2.48\ttRNA-guanine(15) transglycosylase", + "2.4.2.49\tNeamine phosphoribosyltransferase", + "2.4.2.50\tCyanidin 3-O-galactoside 2''-O-xylosyltransferase", + "2.4.2.51\tAnthocyanidin 3-O-glucoside 2'''-O-xylosyltransferase", + "2.4.2.52\tTriphosphoribosyl-dephospho-CoA synthase", + "2.4.2.53\tUndecaprenyl-phosphate 4-deoxy-4-formamido-L-arabinose transferase", + "2.4.2.54\tBeta-ribofuranosylphenol 5'-phosphate synthase", + "2.4.2.55\tNicotinate D-ribonucleotide:phenol phospho-D-ribosyltransferase", + "2.4.2.56\tKaempferol 3-O-xylosyltransferase", + "2.4.2.57\tAMP phosphorylase", + "2.4.2.58\tHydroxyproline O-arabinosyltransferase", + "2.4.2.n2\tGlucoside xylosyltransferase", + "2.4.2.n3\tXyloside xylosyltransferase", + "2.4.99.1\tBeta-galactoside alpha-(2,6)-sialyltransferase", + "2.4.99.2\tMonosialoganglioside sialyltransferase", + "2.4.99.3\tAlpha-N-acetylgalactosaminide alpha-2,6-sialyltransferase", + "2.4.99.4\tBeta-galactoside alpha-2,3-sialyltransferase", + "2.4.99.5\tGalactosyldiacylglycerol alpha-2,3-sialyltransferase", + "2.4.99.6\tN-acetyllactosaminide alpha-2,3-sialyltransferase", + "2.4.99.7\tAlpha-N-acetylneuraminyl-2,3-beta-galactosyl-1,3-N-acetylgalactosaminide 6-alpha-sialyltransferase", + "2.4.99.8\tAlpha-N-acetylneuraminate alpha-2,8-sialyltransferase", + "2.4.99.9\tLactosylceramide alpha-2,3-sialyltransferase", + "2.4.99.10\tNeolactotetraosylceramide alpha-2,3-sialyltransferase", + "2.4.99.12\tLipid IV(A) 3-deoxy-D-manno-octulosonic acid transferase", + "2.4.99.13\t(Kdo)-lipid IV(A) 3-deoxy-D-manno-octulosonic acid transferase", + "2.4.99.14\t(Kdo)(2)-lipid IV(A) (2-8) 3-deoxy-D-manno-octulosonic acid transferase", + "2.4.99.15\t(Kdo)(3)-lipid IV(A) (2-4) 3-deoxy-D-manno-octulosonic acid transferase", + "2.4.99.16\tStarch synthase (maltosyl-transferring)", + "2.4.99.17\tS-adenosylmethionine:tRNA ribosyltransferase-isomerase", + "2.4.99.18\tDolichyl-diphosphooligosaccharide--protein glycotransferase", + "2.4.99.19\tUndecaprenyl-diphosphooligosaccharide--protein glycotransferase", + "2.4.99.20\t2'-phospho-ADP-ribosyl cyclase/2'-phospho-cyclic-ADP-ribose transferase", + "2.4.99.21\tDolichyl-phosphooligosaccharide-protein glycotransferase", + "2.5.1.1\tDimethylallyltranstransferase", + "2.5.1.2\tThiamine pyridinylase", + "2.5.1.3\tThiamine phosphate synthase", + "2.5.1.4\tAdenosylmethionine cyclotransferase", + "2.5.1.5\tGalactose-6-sulfurylase", + "2.5.1.6\tMethionine adenosyltransferase", + "2.5.1.7\tUDP-N-acetylglucosamine 1-carboxyvinyltransferase", + "2.5.1.9\tRiboflavin synthase", + "2.5.1.10\t(2E,6E)-farnesyl diphosphate synthase", + "2.5.1.15\tDihydropteroate synthase", + "2.5.1.16\tSpermidine synthase", + "2.5.1.17\tCob(I)yrinic acid a,c-diamide adenosyltransferase", + "2.5.1.18\tGlutathione transferase", + "2.5.1.19\t3-phosphoshikimate 1-carboxyvinyltransferase", + "2.5.1.20\tRubber cis-polyprenylcistransferase", + "2.5.1.21\tSqualene synthase", + "2.5.1.22\tSpermine synthase", + "2.5.1.23\tSym-norspermidine synthase", + "2.5.1.24\tDiscadenine synthase", + "2.5.1.25\ttRNA-uridine aminocarboxypropyltransferase", + "2.5.1.26\tAlkylglycerone-phosphate synthase", + "2.5.1.27\tAdenylate dimethylallyltransferase (AMP-dependent)", + "2.5.1.28\tDimethylallylcistransferase", + "2.5.1.29\tGeranylgeranyl diphosphate synthase", + "2.5.1.30\tHeptaprenyl diphosphate synthase", + "2.5.1.31\tDitrans,polycis-undecaprenyl-diphosphate synthase ((2E,6E)-farnesyl-diphosphate specific)", + "2.5.1.32\t15-cis-phytoene synthase", + "2.5.1.34\t4-dimethylallyltryptophan synthase", + "2.5.1.35\tAspulvinone dimethylallyltransferase", + "2.5.1.36\tTrihydroxypterocarpan dimethylallyltransferase", + "2.5.1.38\tIsonocardicin synthase", + "2.5.1.39\t4-hydroxybenzoate polyprenyltransferase", + "2.5.1.41\tPhosphoglycerol geranylgeranyltransferase", + "2.5.1.42\tGeranylgeranylglycerol-phosphate geranylgeranyltransferase", + "2.5.1.43\tNicotianamine synthase", + "2.5.1.44\tHomospermidine synthase", + "2.5.1.45\tHomospermidine synthase (spermidine-specific)", + "2.5.1.46\tDeoxyhypusine synthase", + "2.5.1.47\tCysteine synthase", + "2.5.1.48\tCystathionine gamma-synthase", + "2.5.1.49\tO-acetylhomoserine aminocarboxypropyltransferase", + "2.5.1.50\tZeatin 9-aminocarboxyethyltransferase", + "2.5.1.51\tBeta-pyrazolylalanine synthase", + "2.5.1.52\tL-mimosine synthase", + "2.5.1.53\tUracilylalanine synthase", + "2.5.1.54\t3-deoxy-7-phosphoheptulonate synthase", + "2.5.1.55\t3-deoxy-8-phosphooctulonate synthase", + "2.5.1.56\tN-acetylneuraminate synthase", + "2.5.1.57\tN-acylneuraminate-9-phosphate synthase", + "2.5.1.58\tProtein farnesyltransferase", + "2.5.1.59\tProtein geranylgeranyltransferase type I", + "2.5.1.60\tProtein geranylgeranyltransferase type II", + "2.5.1.61\tHydroxymethylbilane synthase", + "2.5.1.62\tChlorophyll synthase", + "2.5.1.63\tAdenosyl-fluoride synthase", + "2.5.1.65\tO-phosphoserine sulfhydrylase", + "2.5.1.66\tN(2)-(2-carboxyethyl)arginine synthase", + "2.5.1.67\tChrysanthemyl diphosphate synthase", + "2.5.1.68\t(2Z,6E)-farnesyl diphosphate synthase", + "2.5.1.69\tLavandulyl diphosphate synthase", + "2.5.1.70\tNaringenin 8-dimethylallyltransferase", + "2.5.1.71\tLeachianone-G 2''-dimethylallyltransferase", + "2.5.1.72\tQuinolinate synthase", + "2.5.1.73\tO-phospho-L-seryl-tRNA:Cys-tRNA synthase", + "2.5.1.74\t1,4-dihydroxy-2-naphthoate polyprenyltransferase", + "2.5.1.75\ttRNA dimethylallyltransferase", + "2.5.1.76\tCysteate synthase", + "2.5.1.77\t7,8-didemethyl-8-hydroxy-5-deazariboflavin synthase", + "2.5.1.78\t6,7-dimethyl-8-ribityllumazine synthase", + "2.5.1.79\tThermospermine synthase", + "2.5.1.80\t7-dimethylallyltryptophan synthase", + "2.5.1.81\tGeranylfarnesyl diphosphate synthase", + "2.5.1.82\tHexaprenyl diphosphate synthase (geranylgeranyl-diphosphate specific)", + "2.5.1.83\tHexaprenyl-diphosphate synthase ((2E,6E)-farnesyl-diphosphate specific)", + "2.5.1.84\tAll-trans-nonaprenyl-diphosphate synthase (geranyl-diphosphate specific)", + "2.5.1.85\tAll-trans-nonaprenyl-diphosphate synthase (geranylgeranyl-diphosphate specific)", + "2.5.1.86\tTrans,polycis-decaprenyl diphosphate synthase", + "2.5.1.87\tDitrans,polycis-polyprenyl diphosphate synthase ((2E,6E)-farnesyl diphosphate specific)", + "2.5.1.88\tTrans,polycis-polyprenyl diphosphate synthase ((2Z,6E)-farnesyl diphosphate specific)", + "2.5.1.89\tTritrans,polycis-undecaprenyl-diphosphate synthase (geranylgeranyl-diphosphate specific)", + "2.5.1.90\tAll-trans-octaprenyl-diphosphate synthase", + "2.5.1.91\tAll-trans-decaprenyl-diphosphate synthase", + "2.5.1.92\t(2Z,6Z)-farnesyl diphosphate synthase", + "2.5.1.93\t4-hydroxybenzoate geranyltransferase", + "2.5.1.94\tAdenosyl-chloride synthase", + "2.5.1.95\tXanthan pyruvate transferase", + "2.5.1.96\t4,4'-diapophytoene synthase", + "2.5.1.97\tPseudaminic acid synthase", + "2.5.1.98\tRhizobium leguminosarum exopolysaccharide glucosyl ketal-pyruvate-transferase", + "2.5.1.99\tAll-trans-phytoene synthase", + "2.5.1.100\tFumigaclavine A dimethylallyltransferase", + "2.5.1.101\tN,N'-diacetyllegionaminate synthase", + "2.5.1.102\tGeranylpyrophosphate--olivetolic acid geranyltransferase", + "2.5.1.103\tPresqualene diphosphate synthase", + "2.5.1.104\tN(1)-aminopropylagmatine synthase", + "2.5.1.105\t7,8-dihydropterin-6-yl-methyl-4-(beta-D-ribofuranosyl)aminobenzene 5'-phosphate synthase", + "2.5.1.106\tTryprostatin B synthase", + "2.5.1.107\tVerruculogen prenyltransferase", + "2.5.1.108\t2-(3-amino-3-carboxypropyl)histidine synthase", + "2.5.1.109\tBrevianamide F prenyltransferase (deoxybrevianamide E-forming)", + "2.5.1.110\t12-alpha,13-alpha-dihydroxyfumitremorgin C prenyltransferase", + "2.5.1.111\t4-hydroxyphenylpyruvate 3-dimethylallyltransferase", + "2.5.1.112\tAdenylate dimethylallyltransferase (ADP/ATP-dependent)", + "2.5.1.113\t[CysO sulfur-carrier protein]-thiocarboxylate-dependent cysteine synthase", + "2.5.1.114\ttRNA(Phe) (4-demethylwyosine(37)-C(7)) aminocarboxypropyltransferase", + "2.5.1.115\tHomogentisate phytyltransferase", + "2.5.1.116\tHomogentisate geranylgeranyltransferase", + "2.5.1.117\tHomogentisate solanesyltransferase", + "2.5.1.118\tBeta-(isoxazolin-5-on-2-yl)-L-alanine synthase", + "2.5.1.119\tBeta-(isoxazolin-5-on-4-yl)-L-alanine synthase", + "2.5.1.120\tAminodeoxyfutalosine synthase", + "2.5.1.121\t5,10-dihydrophenazine-1-carboxylate 9-dimethylallyltransferase", + "2.5.1.122\t4-O-dimethylallyl-L-tyrosine synthase", + "2.5.1.123\tFlaviolin linalyltransferase", + "2.5.1.124\t6-linalyl-2-O,3-dimethylflaviolin synthase", + "2.5.1.125\t7-geranyloxy-5-hydroxy-2-methoxy-3-methylnaphthalene-1,4-dione synthase", + "2.5.1.126\tNorspermine synthase", + "2.5.1.127\tCaldopentamine synthase", + "2.5.1.128\tN(4)-bis(aminopropyl)spermidine synthase", + "2.5.1.129\tFlavin prenyltransferase", + "2.5.1.130\t2-carboxy-1,4-naphthoquinone phytyltransferase", + "2.5.1.131\t(4-(4-(2-(gamma-L-glutamylamino)ethyl)phenoxymethyl)furan-2-yl)methanamine synthase", + "2.5.1.132\t3-deoxy-D-glycero-D-galacto-nononate 9-phosphate synthase", + "2.5.1.133\tBacteriochlorophyll a synthase", + "2.5.1.134\tCystathionine beta-synthase (O-acetyl-L-serine)", + "2.5.1.135\tValidamine 7-phosphate valienyltransferase", + "2.5.1.136\t2-acylphloroglucinol 4-prenyltransferase", + "2.5.1.137\t2-acyl-4-prenylphloroglucinol 6-prenyltransferase", + "2.5.1.138\tCoumarin 8-geranyltransferase", + "2.5.1.139\tUmbelliferone 6-dimethylallyltransferase", + "2.5.1.n9\tHeptaprenylglyceryl phosphate synthase", + "2.6.1.1\tAspartate transaminase", + "2.6.1.2\tAlanine transaminase", + "2.6.1.3\tCysteine transaminase", + "2.6.1.4\tGlycine transaminase", + "2.6.1.5\tTyrosine transaminase", + "2.6.1.6\tLeucine transaminase", + "2.6.1.7\tKynurenine--oxoglutarate transaminase", + "2.6.1.8\t2,5-diaminovalerate transaminase", + "2.6.1.9\tHistidinol-phosphate transaminase", + "2.6.1.11\tAcetylornithine transaminase", + "2.6.1.12\tAlanine--oxo-acid transaminase", + "2.6.1.13\tOrnithine aminotransferase", + "2.6.1.14\tAsparagine--oxo-acid transaminase", + "2.6.1.15\tGlutamine--pyruvate transaminase", + "2.6.1.16\tGlutamine--fructose-6-phosphate transaminase (isomerizing)", + "2.6.1.17\tSuccinyldiaminopimelate transaminase", + "2.6.1.18\tBeta-alanine--pyruvate transaminase", + "2.6.1.19\t4-aminobutyrate--2-oxoglutarate transaminase", + "2.6.1.21\tD-amino-acid transaminase", + "2.6.1.22\t(S)-3-amino-2-methylpropionate transaminase", + "2.6.1.23\t4-hydroxyglutamate transaminase", + "2.6.1.24\tDiiodotyrosine transaminase", + "2.6.1.26\tThyroid-hormone transaminase", + "2.6.1.27\tTryptophan transaminase", + "2.6.1.28\tTryptophan--phenylpyruvate transaminase", + "2.6.1.29\tDiamine transaminase", + "2.6.1.30\tPyridoxamine--pyruvate transaminase", + "2.6.1.31\tPyridoxamine--oxaloacetate transaminase", + "2.6.1.32\tValine--3-methyl-2-oxovalerate transaminase", + "2.6.1.33\tdTDP-4-amino-4,6-dideoxy-D-glucose transaminase", + "2.6.1.34\tUDP-N-acetylbacillosamine transaminase", + "2.6.1.35\tGlycine--oxaloacetate transaminase", + "2.6.1.36\tL-lysine 6-transaminase", + "2.6.1.37\t2-aminoethylphosphonate--pyruvate transaminase", + "2.6.1.38\tHistidine transaminase", + "2.6.1.39\t2-aminoadipate transaminase", + "2.6.1.40\t(R)-3-amino-2-methylpropionate--pyruvate transaminase", + "2.6.1.41\tD-methionine--pyruvate transaminase", + "2.6.1.42\tBranched-chain-amino-acid transaminase", + "2.6.1.43\tAminolevulinate transaminase", + "2.6.1.44\tAlanine--glyoxylate transaminase", + "2.6.1.45\tSerine--glyoxylate transaminase", + "2.6.1.46\tDiaminobutyrate--pyruvate transaminase", + "2.6.1.47\tAlanine--oxomalonate transaminase", + "2.6.1.48\t5-aminovalerate transaminase", + "2.6.1.49\tDihydroxyphenylalanine transaminase", + "2.6.1.50\tGlutamine--scyllo-inositol transaminase", + "2.6.1.51\tSerine--pyruvate transaminase", + "2.6.1.52\tPhosphoserine transaminase", + "2.6.1.54\tPyridoxamine-phosphate transaminase", + "2.6.1.55\tTaurine--2-oxoglutarate transaminase", + "2.6.1.56\t1D-1-guanidino-3-amino-1,3-dideoxy-scyllo-inositol transaminase", + "2.6.1.57\tAromatic-amino-acid transaminase", + "2.6.1.58\tPhenylalanine(histidine) transaminase", + "2.6.1.59\tdTDP-4-amino-4,6-dideoxygalactose transaminase", + "2.6.1.60\tAromatic-amino-acid--glyoxylate transaminase", + "2.6.1.62\tAdenosylmethionine--8-amino-7-oxononanoate transaminase", + "2.6.1.63\tKynurenine--glyoxylate transaminase", + "2.6.1.64\tGlutamine--phenylpyruvate transaminase", + "2.6.1.65\tN(6)-acetyl-beta-lysine transaminase", + "2.6.1.66\tValine--pyruvate transaminase", + "2.6.1.67\t2-aminohexanoate transaminase", + "2.6.1.70\tAspartate--phenylpyruvate transaminase", + "2.6.1.71\tLysine--pyruvate 6-transaminase", + "2.6.1.72\tD-4-hydroxyphenylglycine transaminase", + "2.6.1.73\tMethionine--glyoxylate transaminase", + "2.6.1.74\tCephalosporin-C transaminase", + "2.6.1.75\tCysteine-conjugate transaminase", + "2.6.1.76\tDiaminobutyrate--2-oxoglutarate transaminase", + "2.6.1.77\tTaurine--pyruvate aminotransferase", + "2.6.1.78\tAspartate--prephenate aminotransferase", + "2.6.1.79\tGlutamate--prephenate aminotransferase", + "2.6.1.80\tNicotianamine aminotransferase", + "2.6.1.81\tSuccinylornithine transaminase", + "2.6.1.82\tPutrescine aminotransferase", + "2.6.1.83\tLL-diaminopimelate aminotransferase", + "2.6.1.84\tArginine--pyruvate transaminase", + "2.6.1.85\tAminodeoxychorismate synthase", + "2.6.1.86\t2-amino-4-deoxychorismate synthase", + "2.6.1.87\tUDP-4-amino-4-deoxy-L-arabinose aminotransferase", + "2.6.1.88\tMethionine transaminase", + "2.6.1.89\tdTDP-3-amino-3,6-dideoxy-alpha-D-glucopyranose transaminase", + "2.6.1.90\tdTDP-3-amino-3,6-dideoxy-alpha-D-galactopyranose transaminase", + "2.6.1.92\tUDP-4-amino-4,6-dideoxy-N-acetyl-beta-L-altrosamine transaminase", + "2.6.1.93\tNeamine transaminase", + "2.6.1.94\t2'-deamino-2'-hydroxyneamine transaminase", + "2.6.1.95\tNeomycin C transaminase", + "2.6.1.96\t4-aminobutyrate--pyruvate transaminase", + "2.6.1.97\tArchaeosine synthase", + "2.6.1.98\tUDP-2-acetamido-2-deoxy-ribo-hexuluronate aminotransferase", + "2.6.1.99\tL-tryptophan--pyruvate aminotransferase", + "2.6.1.100\tL-glutamine:2-deoxy-scyllo-inosose aminotransferase", + "2.6.1.101\tL-glutamine:3-amino-2,3-dideoxy-scyllo-inosose aminotransferase", + "2.6.1.102\tGDP-perosamine synthase", + "2.6.1.103\t(S)-3,5-dihydroxyphenylglycine transaminase", + "2.6.1.104\t3-dehydro-glucose-6-phosphate--glutamate transaminase", + "2.6.1.105\tLysine--8-amino-7-oxononanoate transaminase", + "2.6.1.106\tdTDP-3-amino-3,4,6-trideoxy-alpha-D-glucose transaminase", + "2.6.1.107\tBeta-methylphenylalanine transaminase", + "2.6.1.108\t(5-formylfuran-3-yl)methyl phosphate transaminase", + "2.6.1.109\t8-amino-3,8-dideoxy-alpha-D-manno-octulosonate transaminase", + "2.6.1.110\tdTDP-4-dehydro-2,3,6-trideoxy-D-glucose 4-aminotransferase", + "2.6.1.111\t3-aminobutanoyl-CoA transaminase", + "2.6.1.112\t(S)-ureidoglycine--glyoxylate transaminase", + "2.6.3.1\tOximinotransferase", + "2.6.99.1\tdATP(dGTP)--DNA purinetransferase", + "2.6.99.2\tPyridoxine 5'-phosphate synthase", + "2.6.99.3\tO-ureido-L-serine synthase", + "2.7.1.1\tHexokinase", + "2.7.1.2\tGlucokinase", + "2.7.1.3\tKetohexokinase", + "2.7.1.4\tFructokinase", + "2.7.1.5\tRhamnulokinase", + "2.7.1.6\tGalactokinase", + "2.7.1.7\tMannokinase", + "2.7.1.8\tGlucosamine kinase", + "2.7.1.10\tPhosphoglucokinase", + "2.7.1.11\t6-phosphofructokinase", + "2.7.1.12\tGluconokinase", + "2.7.1.13\tDehydrogluconokinase", + "2.7.1.14\tSedoheptulokinase", + "2.7.1.15\tRibokinase", + "2.7.1.16\tRibulokinase", + "2.7.1.17\tXylulokinase", + "2.7.1.18\tPhosphoribokinase", + "2.7.1.19\tPhosphoribulokinase", + "2.7.1.20\tAdenosine kinase", + "2.7.1.21\tThymidine kinase", + "2.7.1.22\tRibosylnicotinamide kinase", + "2.7.1.23\tNAD(+) kinase", + "2.7.1.24\tDephospho-CoA kinase", + "2.7.1.25\tAdenylyl-sulfate kinase", + "2.7.1.26\tRiboflavin kinase", + "2.7.1.27\tErythritol kinase (D-erythritol 4-phosphate-forming)", + "2.7.1.28\tTriokinase", + "2.7.1.29\tGlycerone kinase", + "2.7.1.30\tGlycerol kinase", + "2.7.1.31\tGlycerate 3-kinase", + "2.7.1.32\tCholine kinase", + "2.7.1.33\tPantothenate kinase", + "2.7.1.34\tPantetheine kinase", + "2.7.1.35\tPyridoxal kinase", + "2.7.1.36\tMevalonate kinase", + "2.7.1.39\tHomoserine kinase", + "2.7.1.40\tPyruvate kinase", + "2.7.1.41\tGlucose-1-phosphate phosphodismutase", + "2.7.1.42\tRiboflavin phosphotransferase", + "2.7.1.43\tGlucuronokinase", + "2.7.1.44\tGalacturonokinase", + "2.7.1.45\t2-dehydro-3-deoxygluconokinase", + "2.7.1.46\tL-arabinokinase", + "2.7.1.47\tD-ribulokinase", + "2.7.1.48\tUridine kinase", + "2.7.1.49\tHydroxymethylpyrimidine kinase", + "2.7.1.50\tHydroxyethylthiazole kinase", + "2.7.1.51\tL-fuculokinase", + "2.7.1.52\tFucokinase", + "2.7.1.53\tL-xylulokinase", + "2.7.1.54\tD-arabinokinase", + "2.7.1.55\tAllose kinase", + "2.7.1.56\t1-phosphofructokinase", + "2.7.1.58\t2-dehydro-3-deoxygalactonokinase", + "2.7.1.59\tN-acetylglucosamine kinase", + "2.7.1.60\tN-acylmannosamine kinase", + "2.7.1.61\tAcyl-phosphate--hexose phosphotransferase", + "2.7.1.62\tPhosphoramidate--hexose phosphotransferase", + "2.7.1.63\tPolyphosphate--glucose phosphotransferase", + "2.7.1.64\tInositol 3-kinase", + "2.7.1.65\tScyllo-inosamine 4-kinase", + "2.7.1.66\tUndecaprenol kinase", + "2.7.1.67\t1-phosphatidylinositol 4-kinase", + "2.7.1.68\t1-phosphatidylinositol-4-phosphate 5-kinase", + "2.7.1.71\tShikimate kinase", + "2.7.1.72\tStreptomycin 6-kinase", + "2.7.1.73\tInosine kinase", + "2.7.1.74\tDeoxycytidine kinase", + "2.7.1.76\tDeoxyadenosine kinase", + "2.7.1.77\tNucleoside phosphotransferase", + "2.7.1.78\tPolynucleotide 5'-hydroxyl-kinase", + "2.7.1.79\tDiphosphate--glycerol phosphotransferase", + "2.7.1.80\tDiphosphate--serine phosphotransferase", + "2.7.1.81\tHydroxylysine kinase", + "2.7.1.82\tEthanolamine kinase", + "2.7.1.83\tPseudouridine kinase", + "2.7.1.84\tAlkylglycerone kinase", + "2.7.1.85\tBeta-glucoside kinase", + "2.7.1.86\tNADH kinase", + "2.7.1.87\tStreptomycin 3''-kinase", + "2.7.1.88\tDihydrostreptomycin-6-phosphate 3'-alpha-kinase", + "2.7.1.89\tThiamine kinase", + "2.7.1.90\tDiphosphate--fructose-6-phosphate 1-phosphotransferase", + "2.7.1.91\tSphingosine kinase", + "2.7.1.92\t5-dehydro-2-deoxygluconokinase", + "2.7.1.93\tAlkylglycerol kinase", + "2.7.1.94\tAcylglycerol kinase", + "2.7.1.95\tKanamycin kinase", + "2.7.1.100\tS-methyl-5-thioribose kinase", + "2.7.1.101\tTagatose kinase", + "2.7.1.102\tHamamelose kinase", + "2.7.1.103\tViomycin kinase", + "2.7.1.105\t6-phosphofructo-2-kinase", + "2.7.1.106\tGlucose-1,6-bisphosphate synthase", + "2.7.1.107\tDiacylglycerol kinase (ATP)", + "2.7.1.108\tDolichol kinase", + "2.7.1.113\tDeoxyguanosine kinase", + "2.7.1.114\tAMP--thymidine kinase", + "2.7.1.118\tADP--thymidine kinase", + "2.7.1.119\tHygromycin-B 7''-O-kinase", + "2.7.1.121\tPhosphoenolpyruvate--glycerone phosphotransferase", + "2.7.1.122\tXylitol kinase", + "2.7.1.127\tInositol-trisphosphate 3-kinase", + "2.7.1.130\tTetraacyldisaccharide 4'-kinase", + "2.7.1.134\tInositol-tetrakisphosphate 1-kinase", + "2.7.1.136\tMacrolide 2'-kinase", + "2.7.1.137\tPhosphatidylinositol 3-kinase", + "2.7.1.138\tCeramide kinase", + "2.7.1.140\tInositol-tetrakisphosphate 5-kinase", + "2.7.1.142\tGlycerol-3-phosphate--glucose phosphotransferase", + "2.7.1.143\tDiphosphate-purine nucleoside kinase", + "2.7.1.144\tTagatose-6-phosphate kinase", + "2.7.1.145\tDeoxynucleoside kinase", + "2.7.1.146\tADP-specific phosphofructokinase", + "2.7.1.147\tADP-specific glucokinase", + "2.7.1.148\t4-(cytidine 5'-diphospho)-2-C-methyl-D-erythritol kinase", + "2.7.1.149\t1-phosphatidylinositol-5-phosphate 4-kinase", + "2.7.1.150\t1-phosphatidylinositol-3-phosphate 5-kinase", + "2.7.1.151\tInositol-polyphosphate multikinase", + "2.7.1.153\tPhosphatidylinositol-4,5-bisphosphate 3-kinase", + "2.7.1.154\tPhosphatidylinositol-4-phosphate 3-kinase", + "2.7.1.156\tAdenosylcobinamide kinase", + "2.7.1.157\tN-acetylgalactosamine kinase", + "2.7.1.158\tInositol-pentakisphosphate 2-kinase", + "2.7.1.159\tInositol-1,3,4-trisphosphate 5/6-kinase", + "2.7.1.160\t2'-phosphotransferase", + "2.7.1.161\tCTP-dependent riboflavin kinase", + "2.7.1.162\tN-acetylhexosamine 1-kinase", + "2.7.1.163\tHygromycin B 4-O-kinase", + "2.7.1.164\tO-phosphoseryl-tRNA(Sec) kinase", + "2.7.1.165\tGlycerate 2-kinase", + "2.7.1.166\t3-deoxy-D-manno-octulosonic acid kinase", + "2.7.1.167\tD-glycero-beta-D-manno-heptose-7-phosphate kinase", + "2.7.1.168\tD-glycero-alpha-D-manno-heptose-7-phosphate kinase", + "2.7.1.169\tPantoate kinase", + "2.7.1.170\tAnhydro-N-acetylmuramic acid kinase", + "2.7.1.171\tProtein-fructosamine 3-kinase", + "2.7.1.172\tProtein-ribulosamine 3-kinase", + "2.7.1.173\tNicotinate riboside kinase", + "2.7.1.174\tDiacylglycerol kinase (CTP)", + "2.7.1.175\tMaltokinase", + "2.7.1.176\tUDP-N-acetylglucosamine kinase", + "2.7.1.177\tL-threonine kinase", + "2.7.1.178\t2-dehydro-3-deoxyglucono/galactono-kinase", + "2.7.1.179\tKanosamine kinase", + "2.7.1.180\tFAD:protein FMN transferase", + "2.7.1.181\tPolymannosyl GlcNAc-diphospho-ditrans,octacis-undecaprenol kinase", + "2.7.1.182\tPhytol kinase", + "2.7.1.183\tGlycoprotein-mannosyl O(6)-kinase", + "2.7.1.184\tSulfofructose kinase", + "2.7.1.185\tMevalonate 3-kinase", + "2.7.1.186\tMevalonate-3-phosphate 5-kinase", + "2.7.1.187\tAcarbose 7(IV)-phosphotransferase", + "2.7.1.188\t2-epi-5-epi-valiolone 7-kinase", + "2.7.1.189\tAutoinducer-2 kinase", + "2.7.1.190\tAminoglycoside 2''-phosphotransferase", + "2.7.1.191\tProtein-N(pi)-phosphohistidine--D-mannose phosphotransferase", + "2.7.1.192\tProtein-N(pi)-phosphohistidine--N-acetylmuramate phosphotransferase", + "2.7.1.193\tProtein-N(pi)-phosphohistidine--N-acetyl-D-glucosamine phosphotransferase", + "2.7.1.194\tProtein-N(pi)-phosphohistidine--L-ascorbate phosphotransferase", + "2.7.1.195\tProtein-N(pi)-phosphohistidine--2-O-alpha-mannosyl-D-glycerate phosphotransferase", + "2.7.1.196\tProtein-N(pi)-phosphohistidine--N,N'-diacetylchitobiose phosphotransferase", + "2.7.1.197\tProtein-N(pi)-phosphohistidine--D-mannitol phosphotransferase", + "2.7.1.198\tProtein-N(pi)-phosphohistidine--D-sorbitol phosphotransferase", + "2.7.1.199\tProtein-N(pi)-phosphohistidine--D-glucose phosphotransferase", + "2.7.1.200\tProtein-N(pi)-phosphohistidine--galactitol phosphotransferase", + "2.7.1.201\tProtein-N(pi)-phosphohistidine--trehalose phosphotransferase", + "2.7.1.202\tProtein-N(pi)-phosphohistidine--D-fructose phosphotransferase", + "2.7.1.203\tProtein-N(pi)-phosphohistidine--D-glucosaminate phosphotransferase", + "2.7.1.204\tProtein-N(pi)-phosphohistidine--D-galactose phosphotransferase", + "2.7.1.205\tProtein-N(pi)-phosphohistidine--D-cellobiose phosphotransferase", + "2.7.1.206\tProtein-N(pi)-phosphohistidine--L-sorbose phosphotransferase", + "2.7.1.207\tProtein-N(pi)-phosphohistidine--lactose phosphotransferase", + "2.7.1.208\tProtein-N(pi)-phosphohistidine--maltose phosphotransferase", + "2.7.1.209\tL-erythrulose 4-kinase", + "2.7.1.210\tD-erythrulose 4-kinase", + "2.7.1.211\tProtein-N(pi)-phosphohistidine--sucrose phosphotransferase", + "2.7.1.212\tAlpha-D-ribose-1-phosphate 5-kinase (ADP)", + "2.7.1.213\tCytidine kinase", + "2.7.1.214\tC(7)-cyclitol 7-kinase", + "2.7.1.215\tErythritol kinase (D-erythritol 1-phosphate-forming)", + "2.7.1.216\tFarnesol kinase", + "2.7.2.1\tAcetate kinase", + "2.7.2.2\tCarbamate kinase", + "2.7.2.3\tPhosphoglycerate kinase", + "2.7.2.4\tAspartate kinase", + "2.7.2.6\tFormate kinase", + "2.7.2.7\tButyrate kinase", + "2.7.2.8\tAcetylglutamate kinase", + "2.7.2.10\tPhosphoglycerate kinase (GTP)", + "2.7.2.11\tGlutamate 5-kinase", + "2.7.2.12\tAcetate kinase (diphosphate)", + "2.7.2.13\tGlutamate 1-kinase", + "2.7.2.14\tBranched-chain-fatty-acid kinase", + "2.7.2.15\tPropionate kinase", + "2.7.3.1\tGuanidinoacetate kinase", + "2.7.3.2\tCreatine kinase", + "2.7.3.3\tArginine kinase", + "2.7.3.4\tTaurocyamine kinase", + "2.7.3.5\tLombricine kinase", + "2.7.3.6\tHypotaurocyamine kinase", + "2.7.3.7\tOpheline kinase", + "2.7.3.8\tAmmonia kinase", + "2.7.3.9\tPhosphoenolpyruvate--protein phosphotransferase", + "2.7.3.10\tAgmatine kinase", + "2.7.4.1\tPolyphosphate kinase", + "2.7.4.2\tPhosphomevalonate kinase", + "2.7.4.3\tAdenylate kinase", + "2.7.4.4\tNucleoside-phosphate kinase", + "2.7.4.6\tNucleoside-diphosphate kinase", + "2.7.4.7\tPhosphooxymethylpyrimidine kinase", + "2.7.4.8\tGuanylate kinase", + "2.7.4.9\tdTMP kinase", + "2.7.4.10\tNucleoside-triphosphate--adenylate kinase", + "2.7.4.11\t(Deoxy)adenylate kinase", + "2.7.4.12\tT(2)-induced deoxynucleotide kinase", + "2.7.4.13\t(Deoxy)nucleoside-phosphate kinase", + "2.7.4.14\tUMP/CMP kinase", + "2.7.4.15\tThiamine-diphosphate kinase", + "2.7.4.16\tThiamine-phosphate kinase", + "2.7.4.17\t3-phosphoglyceroyl-phosphate--polyphosphate phosphotransferase", + "2.7.4.18\tFarnesyl-diphosphate kinase", + "2.7.4.19\t5-methyldeoxycytidine-5'-phosphate kinase", + "2.7.4.20\tDolichyl-diphosphate--polyphosphate phosphotransferase", + "2.7.4.21\tInositol-hexakisphosphate kinase", + "2.7.4.22\tUMP kinase", + "2.7.4.23\tRibose 1,5-bisphosphate phosphokinase", + "2.7.4.24\tDiphosphoinositol-pentakisphosphate kinase", + "2.7.4.25\t(d)CMP kinase", + "2.7.4.26\tIsopentenyl phosphate kinase", + "2.7.4.27\t([Pyruvate, phosphate dikinase] phosphate) phosphotransferase", + "2.7.4.28\t([Pyruvate, water dikinase] phosphate) phosphotransferase", + "2.7.4.29\tKdo(2)-lipid A phosphotransferase", + "2.7.4.31\t(5-(aminomethyl)furan-3-yl)methyl phosphate kinase", + "2.7.4.32\tFarnesyl phosphate kinase", + "2.7.6.1\tRibose-phosphate diphosphokinase", + "2.7.6.2\tThiamine diphosphokinase", + "2.7.6.3\t2-amino-4-hydroxy-6-hydroxymethyldihydropteridine diphosphokinase", + "2.7.6.4\tNucleotide diphosphokinase", + "2.7.6.5\tGTP diphosphokinase", + "2.7.7.1\tNicotinamide-nucleotide adenylyltransferase", + "2.7.7.2\tFAD synthetase", + "2.7.7.3\tPantetheine-phosphate adenylyltransferase", + "2.7.7.4\tSulfate adenylyltransferase", + "2.7.7.5\tSulfate adenylyltransferase (ADP)", + "2.7.7.6\tDNA-directed RNA polymerase", + "2.7.7.7\tDNA-directed DNA polymerase", + "2.7.7.8\tPolyribonucleotide nucleotidyltransferase", + "2.7.7.9\tUTP--glucose-1-phosphate uridylyltransferase", + "2.7.7.10\tUTP--hexose-1-phosphate uridylyltransferase", + "2.7.7.11\tUTP--xylose-1-phosphate uridylyltransferase", + "2.7.7.12\tUDP-glucose--hexose-1-phosphate uridylyltransferase", + "2.7.7.13\tMannose-1-phosphate guanylyltransferase", + "2.7.7.14\tEthanolamine-phosphate cytidylyltransferase", + "2.7.7.15\tCholine-phosphate cytidylyltransferase", + "2.7.7.18\tNicotinate-nucleotide adenylyltransferase", + "2.7.7.19\tPolynucleotide adenylyltransferase", + "2.7.7.22\tMannose-1-phosphate guanylyltransferase (GDP)", + "2.7.7.23\tUDP-N-acetylglucosamine diphosphorylase", + "2.7.7.24\tGlucose-1-phosphate thymidylyltransferase", + "2.7.7.27\tGlucose-1-phosphate adenylyltransferase", + "2.7.7.28\tNucleoside-triphosphate-aldose-1-phosphate nucleotidyltransferase", + "2.7.7.30\tFucose-1-phosphate guanylyltransferase", + "2.7.7.31\tDNA nucleotidylexotransferase", + "2.7.7.32\tGalactose-1-phosphate thymidylyltransferase", + "2.7.7.33\tGlucose-1-phosphate cytidylyltransferase", + "2.7.7.34\tGlucose-1-phosphate guanylyltransferase", + "2.7.7.35\tADP ribose phosphorylase", + "2.7.7.36\tAldose-1-phosphate adenylyltransferase", + "2.7.7.37\tAldose-1-phosphate nucleotidyltransferase", + "2.7.7.38\t3-deoxy-manno-octulosonate cytidylyltransferase", + "2.7.7.39\tGlycerol-3-phosphate cytidylyltransferase", + "2.7.7.40\tD-ribitol-5-phosphate cytidylyltransferase", + "2.7.7.41\tPhosphatidate cytidylyltransferase", + "2.7.7.42\t[Glutamine synthetase] adenylyltransferase", + "2.7.7.43\tN-acylneuraminate cytidylyltransferase", + "2.7.7.44\tGlucuronate-1-phosphate uridylyltransferase", + "2.7.7.45\tGuanosine-triphosphate guanylyltransferase", + "2.7.7.46\tGentamicin 2''-nucleotidyltransferase", + "2.7.7.47\tStreptomycin 3''-adenylyltransferase", + "2.7.7.48\tRNA-directed RNA polymerase", + "2.7.7.49\tRNA-directed DNA polymerase", + "2.7.7.50\tmRNA guanylyltransferase", + "2.7.7.51\tAdenylylsulfate--ammonia adenylyltransferase", + "2.7.7.52\tRNA uridylyltransferase", + "2.7.7.53\tATP adenylyltransferase", + "2.7.7.56\ttRNA nucleotidyltransferase", + "2.7.7.57\tN-methylphosphoethanolamine cytidylyltransferase", + "2.7.7.58\t(2,3-dihydroxybenzoyl)adenylate synthase", + "2.7.7.59\t[Protein-PII] uridylyltransferase", + "2.7.7.60\t2-C-methyl-D-erythritol 4-phosphate cytidylyltransferase", + "2.7.7.61\tCitrate lyase holo-[acyl-carrier protein] synthase", + "2.7.7.62\tAdenosylcobinamide-phosphate guanylyltransferase", + "2.7.7.64\tUTP-monosaccharide-1-phosphate uridylyltransferase", + "2.7.7.65\tDiguanylate cyclase", + "2.7.7.66\tMalonate decarboxylase holo-[acyl-carrier protein] synthase", + "2.7.7.67\tCDP-2,3-bis-(O-geranylgeranyl)-sn-glycerol synthase", + "2.7.7.68\t2-phospho-L-lactate guanylyltransferase", + "2.7.7.69\tGDP-L-galactose phosphorylase", + "2.7.7.70\tD-glycero-beta-D-manno-heptose 1-phosphate adenylyltransferase", + "2.7.7.71\tD-glycero-alpha-D-manno-heptose 1-phosphate guanylyltransferase", + "2.7.7.72\tCCA tRNA nucleotidyltransferase", + "2.7.7.73\tSulfur carrier protein ThiS adenylyltransferase", + "2.7.7.74\t1L-myo-inositol 1-phosphate cytidylyltransferase", + "2.7.7.75\tMolybdopterin adenylyltransferase", + "2.7.7.76\tMolybdenum cofactor cytidylyltransferase", + "2.7.7.77\tMolybdenum cofactor guanylyltransferase", + "2.7.7.78\tGDP-D-glucose phosphorylase", + "2.7.7.79\ttRNA(His) guanylyltransferase", + "2.7.7.80\tMolybdopterin-synthase adenylyltransferase", + "2.7.7.81\tPseudaminic acid cytidylyltransferase", + "2.7.7.82\tCMP-N,N'-diacetyllegionaminic acid synthase", + "2.7.7.83\tUDP-N-acetylgalactosamine diphosphorylase", + "2.7.7.84\t2'-5' oligoadenylate synthase", + "2.7.7.85\tDiadenylate cyclase", + "2.7.7.86\tCyclic GMP-AMP synthase", + "2.7.7.87\tL-threonylcarbamoyladenylate synthase", + "2.7.7.88\tGDP polyribonucleotidyltransferase", + "2.7.7.89\t[Glutamine synthetase]-adenylyl-L-tyrosine phosphorylase", + "2.7.7.90\t8-amino-3,8-dideoxy-manno-octulosonate cytidylyltransferase", + "2.7.7.91\tValienol-1-phosphate guanylyltransferase", + "2.7.7.92\t3-deoxy-D-glycero-D-galacto-nononate cytidylyltransferase", + "2.7.7.93\tPhosphonoformate cytidylyltransferase", + "2.7.7.94\t4-hydroxyphenylalkanoate adenylyltransferase", + "2.7.7.95\tMycocerosic acid adenylyltransferase", + "2.7.7.96\tADP-D-ribose pyrophosphorylase", + "2.7.7.97\t3-hydroxy-4-methylanthranilate adenylyltransferase", + "2.7.7.98\t4-hydroxybenzoate adenylyltransferase", + "2.7.7.n1\tAdenosine monophosphate-protein transferase", + "2.7.7.n6\tGuanine phosphate-protein transferase", + "2.7.8.1\tEthanolaminephosphotransferase", + "2.7.8.2\tDiacylglycerol cholinephosphotransferase", + "2.7.8.3\tCeramide cholinephosphotransferase", + "2.7.8.4\tSerine-phosphoethanolamine synthase", + "2.7.8.5\tCDP-diacylglycerol--glycerol-3-phosphate 1-phosphatidyltransferase", + "2.7.8.6\tUndecaprenyl-phosphate galactose phosphotransferase", + "2.7.8.7\tHolo-[acyl-carrier-protein] synthase", + "2.7.8.8\tCDP-diacylglycerol--serine O-phosphatidyltransferase", + "2.7.8.9\tPhosphomannan mannosephosphotransferase", + "2.7.8.10\tSphingosine cholinephosphotransferase", + "2.7.8.11\tCDP-diacylglycerol--inositol 3-phosphatidyltransferase", + "2.7.8.12\tTeichoic acid poly(glycerol phosphate) polymerase", + "2.7.8.13\tPhospho-N-acetylmuramoyl-pentapeptide-transferase", + "2.7.8.14\tCDP-ribitol ribitolphosphotransferase", + "2.7.8.15\tUDP-N-acetylglucosamine--dolichyl-phosphate N-acetylglucosaminephosphotransferase", + "2.7.8.17\tUDP-N-acetylglucosamine--lysosomal-enzyme N-acetylglucosaminephosphotransferase", + "2.7.8.18\tUDP-galactose--UDP-N-acetylglucosamine galactose phosphotransferase", + "2.7.8.19\tUDP-glucose--glycoprotein glucose phosphotransferase", + "2.7.8.20\tPhosphatidylglycerol--membrane-oligosaccharide glycerophosphotransferase", + "2.7.8.21\tMembrane-oligosaccharide glycerophosphotransferase", + "2.7.8.22\t1-alkenyl-2-acylglycerol choline phosphotransferase", + "2.7.8.23\tCarboxyvinyl-carboxyphosphonate phosphorylmutase", + "2.7.8.24\tPhosphatidylcholine synthase", + "2.7.8.26\tAdenosylcobinamide-GDP ribazoletransferase", + "2.7.8.27\tSphingomyelin synthase", + "2.7.8.28\t2-phospho-L-lactate transferase", + "2.7.8.29\tL-serine-phosphatidylethanolamine phosphatidyltransferase", + "2.7.8.31\tUndecaprenyl-phosphate glucose phosphotransferase", + "2.7.8.32\t3-O-alpha-D-mannopyranosyl-alpha-D-mannopyranose xylosylphosphotransferase", + "2.7.8.33\tUDP-N-acetylglucosamine--undecaprenyl-phosphate N-acetylglucosaminephosphotransferase", + "2.7.8.34\tCDP-L-myo-inositol myo-inositolphosphotransferase", + "2.7.8.35\tUDP-N-acetylglucosamine--decaprenyl-phosphate N-acetylglucosaminephosphotransferase", + "2.7.8.36\tUndecaprenyl phosphate N,N'-diacetylbacillosamine 1-phosphate transferase", + "2.7.8.37\tAlpha-D-ribose 1-methylphosphonate 5-triphosphate synthase", + "2.7.8.38\tArchaetidylserine synthase", + "2.7.8.39\tArchaetidylinositol phosphate synthase", + "2.7.8.40\tUDP-N-acetylgalactosamine-undecaprenyl-phosphate N-acetylgalactosaminephosphotransferase", + "2.7.8.41\tCardiolipin synthase (CMP-forming)", + "2.7.8.42\tKdo(2)-lipid A phosphoethanolamine 7''-transferase", + "2.7.8.43\tLipid A phosphoethanolamine transferase", + "2.7.8.44\tTeichoic acid glycerol-phosphate primase", + "2.7.8.45\tTeichoic acid glycerol-phosphate transferase", + "2.7.8.46\tTeichoic acid ribitol-phosphate primase", + "2.7.8.47\tTeichoic acid ribitol-phosphate polymerase", + "2.7.8.n3\tCeramide phosphoethanolamine synthase", + "2.7.9.1\tPyruvate, phosphate dikinase", + "2.7.9.2\tPyruvate, water dikinase", + "2.7.9.3\tSelenide, water dikinase", + "2.7.9.4\tAlpha-glucan, water dikinase", + "2.7.9.5\tPhosphoglucan, water dikinase", + "2.7.10.1\tReceptor protein-tyrosine kinase", + "2.7.10.2\tNon-specific protein-tyrosine kinase", + "2.7.11.1\tNon-specific serine/threonine protein kinase", + "2.7.11.2\t[Pyruvate dehydrogenase (acetyl-transferring)] kinase", + "2.7.11.3\tDephospho-[reductase kinase] kinase", + "2.7.11.4\t[3-methyl-2-oxobutanoate dehydrogenase (acetyl-transferring)] kinase", + "2.7.11.5\t[Isocitrate dehydrogenase (NADP(+))] kinase", + "2.7.11.6\t[Tyrosine 3-monooxygenase] kinase", + "2.7.11.7\t[Myosin heavy-chain] kinase", + "2.7.11.8\tFas-activated serine/threonine kinase", + "2.7.11.9\t[Goodpasture-antigen-binding protein] kinase", + "2.7.11.10\tI-kappa-B kinase", + "2.7.11.11\tcAMP-dependent protein kinase", + "2.7.11.12\tcGMP-dependent protein kinase", + "2.7.11.13\tProtein kinase C", + "2.7.11.14\tRhodopsin kinase", + "2.7.11.15\t[Beta-adrenergic-receptor] kinase", + "2.7.11.16\t[G-protein-coupled receptor] kinase", + "2.7.11.17\tCalcium/calmodulin-dependent protein kinase", + "2.7.11.18\t[Myosin light-chain] kinase", + "2.7.11.19\tPhosphorylase kinase", + "2.7.11.20\t[Elongation factor 2] kinase", + "2.7.11.21\tPolo kinase", + "2.7.11.22\tCyclin-dependent kinase", + "2.7.11.23\t[RNA-polymerase]-subunit kinase", + "2.7.11.24\tMitogen-activated protein kinase", + "2.7.11.25\tMitogen-activated protein kinase kinase kinase", + "2.7.11.26\t[Tau protein] kinase", + "2.7.11.27\t[Acetyl-CoA carboxylase] kinase", + "2.7.11.28\tTropomyosin kinase", + "2.7.11.29\t[Low-density-lipoprotein receptor] kinase", + "2.7.11.30\tReceptor protein serine/threonine kinase", + "2.7.11.31\t[Hydroxymethylglutaryl-CoA reductase (NADPH)] kinase", + "2.7.11.32\t[Pyruvate, phosphate dikinase] kinase", + "2.7.11.33\t[Pyruvate, water dikinase] kinase", + "2.7.12.1\tDual-specificity kinase", + "2.7.12.2\tMitogen-activated protein kinase kinase", + "2.7.13.1\tProtein-histidine pros-kinase", + "2.7.13.2\tProtein-histidine tele-kinase", + "2.7.13.3\tHistidine kinase", + "2.7.14.1\tProtein arginine kinase", + "2.7.99.1\tTriphosphate--protein phosphotransferase", + "2.8.1.1\tThiosulfate sulfurtransferase", + "2.8.1.2\t3-mercaptopyruvate sulfurtransferase", + "2.8.1.3\tThiosulfate--thiol sulfurtransferase", + "2.8.1.4\ttRNA sulfurtransferase", + "2.8.1.5\tThiosulfate--dithiol sulfurtransferase", + "2.8.1.6\tBiotin synthase", + "2.8.1.7\tCysteine desulfurase", + "2.8.1.8\tLipoyl synthase", + "2.8.1.9\tMolybdenum cofactor sulfurtransferase", + "2.8.1.10\tThiazole synthase", + "2.8.1.11\tMolybdopterin synthase sulfurtransferase", + "2.8.1.12\tMolybdopterin synthase", + "2.8.1.13\ttRNA-uridine 2-sulfurtransferase", + "2.8.1.14\ttRNA-5-taurinomethyluridine 2-sulfurtransferase", + "2.8.2.1\tAryl sulfotransferase", + "2.8.2.2\tAlcohol sulfotransferase", + "2.8.2.3\tAmine sulfotransferase", + "2.8.2.4\tEstrone sulfotransferase", + "2.8.2.5\tChondroitin 4-sulfotransferase", + "2.8.2.6\tCholine sulfotransferase", + "2.8.2.7\tUDP-N-acetylgalactosamine-4-sulfate sulfotransferase", + "2.8.2.8\t[Heparan sulfate]-glucosamine N-sulfotransferase", + "2.8.2.9\tTyrosine-ester sulfotransferase", + "2.8.2.10\tRenilla-luciferin sulfotransferase", + "2.8.2.11\tGalactosylceramide sulfotransferase", + "2.8.2.13\tPsychosine sulfotransferase", + "2.8.2.14\tBile-salt sulfotransferase", + "2.8.2.15\tSteroid sulfotransferase", + "2.8.2.16\tThiol sulfotransferase", + "2.8.2.17\tChondroitin 6-sulfotransferase", + "2.8.2.18\tCortisol sulfotransferase", + "2.8.2.19\tTriglucosylalkylacylglycerol sulfotransferase", + "2.8.2.20\tProtein-tyrosine sulfotransferase", + "2.8.2.21\tKeratan sulfotransferase", + "2.8.2.22\tAryl-sulfate sulfotransferase", + "2.8.2.23\t[Heparan sulfate]-glucosamine 3-sulfotransferase 1", + "2.8.2.24\tDesulfoglucosinolate sulfotransferase", + "2.8.2.25\tFlavonol 3-sulfotransferase", + "2.8.2.26\tQuercetin-3-sulfate 3'-sulfotransferase", + "2.8.2.27\tQuercetin-3-sulfate 4'-sulfotransferase", + "2.8.2.28\tQuercetin-3,3'-bissulfate 7-sulfotransferase", + "2.8.2.29\t[Heparan sulfate]-glucosamine 3-sulfotransferase 2", + "2.8.2.30\t[Heparan sulfate]-glucosamine 3-sulfotransferase 3", + "2.8.2.31\tPetromyzonol sulfotransferase", + "2.8.2.32\tScymnol sulfotransferase", + "2.8.2.33\tN-acetylgalactosamine 4-sulfate 6-O-sulfotransferase", + "2.8.2.34\tGlycochenodeoxycholate sulfotransferase", + "2.8.2.35\tDermatan 4-sulfotransferase", + "2.8.2.36\tDesulfo-A47934 sulfotransferase", + "2.8.2.37\tTrehalose 2-sulfotransferase", + "2.8.2.n2\tThyroxine sulfotransferase", + "2.8.3.1\tPropionate CoA-transferase", + "2.8.3.2\tOxalate CoA-transferase", + "2.8.3.3\tMalonate CoA-transferase", + "2.8.3.5\t3-oxoacid CoA-transferase", + "2.8.3.6\t3-oxoadipate CoA-transferase", + "2.8.3.8\tAcetate CoA-transferase", + "2.8.3.9\tButyrate--acetoacetate CoA-transferase", + "2.8.3.10\tCitrate CoA-transferase", + "2.8.3.11\tCitramalate CoA-transferase", + "2.8.3.12\tGlutaconate CoA-transferase", + "2.8.3.13\tSuccinate--hydroxymethylglutarate CoA-transferase", + "2.8.3.14\t5-hydroxypentanoate CoA-transferase", + "2.8.3.15\tSuccinyl-CoA:(R)-benzylsuccinate CoA-transferase", + "2.8.3.16\tFormyl-CoA transferase", + "2.8.3.17\tCinnamoyl-CoA:phenyllactate CoA-transferase", + "2.8.3.18\tSuccinyl-CoA:acetate CoA-transferase", + "2.8.3.19\tCoA:oxalate CoA-transferase", + "2.8.3.20\tSuccinyl-CoA--D-citramalate CoA-transferase", + "2.8.3.21\tL-carnitine CoA-transferase", + "2.8.3.22\tSuccinyl-CoA--L-malate CoA-transferase", + "2.8.3.23\tCaffeate CoA-transferase", + "2.8.3.24\t(R)-2-hydroxy-4-methylpentanoate CoA-transferase", + "2.8.3.25\tBile acid CoA-transferase", + "2.8.4.1\tCoenzyme-B sulfoethylthiotransferase", + "2.8.4.2\tArsenate-mycothiol transferase", + "2.8.4.3\ttRNA-2-methylthio-N(6)-dimethylallyladenosine synthase", + "2.8.4.4\t[Ribosomal protein S12] (aspartate(89)-C(3))-methylthiotransferase", + "2.8.4.5\ttRNA (N(6)-L-threonylcarbamoyladenosine(37)-C(2))-methylthiotransferase", + "2.9.1.1\tL-seryl-tRNA(Sec) selenium transferase", + "2.9.1.2\tO-phospho-L-seryl-tRNA(Sec):L-selenocysteinyl-tRNA synthase", + "2.10.1.1\tMolybdopterin molybdotransferase", + "3.1.1.1\tCarboxylesterase", + "3.1.1.2\tArylesterase", + "3.1.1.3\tTriacylglycerol lipase", + "3.1.1.4\tPhospholipase A(2)", + "3.1.1.5\tLysophospholipase", + "3.1.1.6\tAcetylesterase", + "3.1.1.7\tAcetylcholinesterase", + "3.1.1.8\tCholinesterase", + "3.1.1.10\tTropinesterase", + "3.1.1.11\tPectinesterase", + "3.1.1.13\tSterol esterase", + "3.1.1.14\tChlorophyllase", + "3.1.1.15\tL-arabinonolactonase", + "3.1.1.17\tGluconolactonase", + "3.1.1.19\tUronolactonase", + "3.1.1.20\tTannase", + "3.1.1.22\tHydroxybutyrate-dimer hydrolase", + "3.1.1.23\tAcylglycerol lipase", + "3.1.1.24\t3-oxoadipate enol-lactonase", + "3.1.1.25\t1,4-lactonase", + "3.1.1.26\tGalactolipase", + "3.1.1.27\t4-pyridoxolactonase", + "3.1.1.28\tAcylcarnitine hydrolase", + "3.1.1.29\tAminoacyl-tRNA hydrolase", + "3.1.1.30\tD-arabinonolactonase", + "3.1.1.31\t6-phosphogluconolactonase", + "3.1.1.32\tPhospholipase A(1)", + "3.1.1.33\t6-acetylglucose deacetylase", + "3.1.1.34\tLipoprotein lipase", + "3.1.1.35\tDihydrocoumarin hydrolase", + "3.1.1.36\tLimonin-D-ring-lactonase", + "3.1.1.37\tSteroid-lactonase", + "3.1.1.38\tTriacetate-lactonase", + "3.1.1.39\tActinomycin lactonase", + "3.1.1.40\tOrsellinate-depside hydrolase", + "3.1.1.41\tCephalosporin-C deacetylase", + "3.1.1.42\tChlorogenate hydrolase", + "3.1.1.43\tAlpha-amino-acid esterase", + "3.1.1.44\t4-methyloxaloacetate esterase", + "3.1.1.45\tCarboxymethylenebutenolidase", + "3.1.1.46\tDeoxylimonate A-ring-lactonase", + "3.1.1.47\t1-alkyl-2-acetylglycerophosphocholine esterase", + "3.1.1.48\tFusarinine-C ornithinesterase", + "3.1.1.49\tSinapine esterase", + "3.1.1.50\tWax-ester hydrolase", + "3.1.1.51\tPhorbol-diester hydrolase", + "3.1.1.52\tPhosphatidylinositol deacylase", + "3.1.1.53\tSialate O-acetylesterase", + "3.1.1.54\tAcetoxybutynylbithiophene deacetylase", + "3.1.1.55\tAcetylsalicylate deacetylase", + "3.1.1.56\tMethylumbelliferyl-acetate deacetylase", + "3.1.1.57\t2-pyrone-4,6-dicarboxylate lactonase", + "3.1.1.58\tN-acetylgalactosaminoglycan deacetylase", + "3.1.1.59\tJuvenile-hormone esterase", + "3.1.1.60\tBis(2-ethylhexyl)phthalate esterase", + "3.1.1.61\tProtein-glutamate methylesterase", + "3.1.1.63\t11-cis-retinyl-palmitate hydrolase", + "3.1.1.64\tRetinoid isomerohydrolase", + "3.1.1.65\tL-rhamnono-1,4-lactonase", + "3.1.1.66\t5-(3,4-diacetoxybut-1-ynyl)-2,2'-bithiophene deacetylase", + "3.1.1.67\tFatty-acyl-ethyl-ester synthase", + "3.1.1.68\tXylono-1,4-lactonase", + "3.1.1.70\tCetraxate benzylesterase", + "3.1.1.71\tAcetylalkylglycerol acetylhydrolase", + "3.1.1.72\tAcetylxylan esterase", + "3.1.1.73\tFeruloyl esterase", + "3.1.1.74\tCutinase", + "3.1.1.75\tPoly(3-hydroxybutyrate) depolymerase", + "3.1.1.76\tPoly(3-hydroxyoctanoate) depolymerase", + "3.1.1.77\tAcyloxyacyl hydrolase", + "3.1.1.78\tPolyneuridine-aldehyde esterase", + "3.1.1.79\tHormone-sensitive lipase", + "3.1.1.80\tAcetylajmaline esterase", + "3.1.1.81\tQuorum-quenching N-acyl-homoserine lactonase", + "3.1.1.82\tPheophorbidase", + "3.1.1.83\tMonoterpene epsilon-lactone hydrolase", + "3.1.1.84\tCocaine esterase", + "3.1.1.85\tPimeloyl-[acyl-carrier protein] methyl ester esterase", + "3.1.1.86\tRhamnogalacturonan acetylesterase", + "3.1.1.87\tFumonisin B1 esterase", + "3.1.1.88\tPyrethroid hydrolase", + "3.1.1.89\tProtein phosphatase methylesterase-1", + "3.1.1.90\tAll-trans-retinyl ester 13-cis isomerohydrolase", + "3.1.1.91\t2-oxo-3-(5-oxofuran-2-ylidene)propanoate lactonase", + "3.1.1.92\t4-sulfomuconolactone hydrolase", + "3.1.1.93\tMycophenolic acid acyl-glucuronide esterase", + "3.1.1.94\tVersiconal hemiacetal acetate esterase", + "3.1.1.95\tAclacinomycin methylesterase", + "3.1.1.96\tD-aminoacyl-tRNA deacylase", + "3.1.1.97\tMethylated diphthine methylhydrolase", + "3.1.1.98\t[Wnt protein] O-palmitoleoyl-L-serine hydrolase", + "3.1.1.99\t6-deoxy-6-sulfogluconolactonase", + "3.1.1.100\tChlorophyllide a hydrolase", + "3.1.1.101\tPoly(ethylene terephthalate) hydrolase", + "3.1.1.102\tMono(ethylene terephthalate) hydrolase", + "3.1.1.n2\tProtein-S-isoprenylcysteine alpha-carbonyl methylesterase", + "3.1.2.1\tAcetyl-CoA hydrolase", + "3.1.2.2\tPalmitoyl-CoA hydrolase", + "3.1.2.3\tSuccinyl-CoA hydrolase", + "3.1.2.4\t3-hydroxyisobutyryl-CoA hydrolase", + "3.1.2.5\tHydroxymethylglutaryl-CoA hydrolase", + "3.1.2.6\tHydroxyacylglutathione hydrolase", + "3.1.2.7\tGlutathione thiolesterase", + "3.1.2.10\tFormyl-CoA hydrolase", + "3.1.2.11\tAcetoacetyl-CoA hydrolase", + "3.1.2.12\tS-formylglutathione hydrolase", + "3.1.2.13\tS-succinylglutathione hydrolase", + "3.1.2.14\tOleoyl-[acyl-carrier-protein] hydrolase", + "3.1.2.16\tCitrate-lyase deacetylase", + "3.1.2.17\t(S)-methylmalonyl-CoA hydrolase", + "3.1.2.18\tADP-dependent short-chain-acyl-CoA hydrolase", + "3.1.2.19\tADP-dependent medium-chain-acyl-CoA hydrolase", + "3.1.2.20\tAcyl-CoA hydrolase", + "3.1.2.21\tDodecanoyl-[acyl-carrier-protein] hydrolase", + "3.1.2.22\tPalmitoyl-protein hydrolase", + "3.1.2.23\t4-hydroxybenzoyl-CoA thioesterase", + "3.1.2.25\tPhenylacetyl-CoA hydrolase", + "3.1.2.27\tCholoyl-CoA hydrolase", + "3.1.2.28\t1,4-dihydroxy-2-naphthoyl-CoA hydrolase", + "3.1.2.29\tFluoroacetyl-CoA thioesterase", + "3.1.2.30\t(3S)-malyl-CoA thioesterase", + "3.1.2.31\tDihydromonacolin L-[lovastatin nonaketide synthase] thioesterase", + "3.1.2.32\t2-aminobenzoylacetyl-CoA thioesterase", + "3.1.3.1\tAlkaline phosphatase", + "3.1.3.2\tAcid phosphatase", + "3.1.3.3\tPhosphoserine phosphatase", + "3.1.3.4\tPhosphatidate phosphatase", + "3.1.3.5\t5'-nucleotidase", + "3.1.3.6\t3'-nucleotidase", + "3.1.3.7\t3'(2'),5'-bisphosphate nucleotidase", + "3.1.3.8\t3-phytase", + "3.1.3.9\tGlucose-6-phosphatase", + "3.1.3.10\tGlucose-1-phosphatase", + "3.1.3.11\tFructose-bisphosphatase", + "3.1.3.12\tTrehalose-phosphatase", + "3.1.3.14\tMethylphosphothioglycerate phosphatase", + "3.1.3.15\tHistidinol-phosphatase", + "3.1.3.16\tProtein-serine/threonine phosphatase", + "3.1.3.17\t[Phosphorylase] phosphatase", + "3.1.3.18\tPhosphoglycolate phosphatase", + "3.1.3.19\tGlycerol-2-phosphatase", + "3.1.3.20\tPhosphoglycerate phosphatase", + "3.1.3.21\tGlycerol-1-phosphatase", + "3.1.3.22\tMannitol-1-phosphatase", + "3.1.3.23\tSugar-phosphatase", + "3.1.3.24\tSucrose-phosphate phosphatase", + "3.1.3.25\tInositol-phosphate phosphatase", + "3.1.3.26\t4-phytase", + "3.1.3.27\tPhosphatidylglycerophosphatase", + "3.1.3.28\tADP-phosphoglycerate phosphatase", + "3.1.3.29\tN-acylneuraminate-9-phosphatase", + "3.1.3.31\tNucleotidase", + "3.1.3.32\tPolynucleotide 3'-phosphatase", + "3.1.3.33\tPolynucleotide 5'-phosphatase", + "3.1.3.34\tDeoxynucleotide 3'-phosphatase", + "3.1.3.35\tThymidylate 5'-phosphatase", + "3.1.3.36\tPhosphoinositide 5-phosphatase", + "3.1.3.37\tSedoheptulose-bisphosphatase", + "3.1.3.38\t3-phosphoglycerate phosphatase", + "3.1.3.39\tStreptomycin-6-phosphatase", + "3.1.3.40\tGuanidinodeoxy-scyllo-inositol-4-phosphatase", + "3.1.3.41\t4-nitrophenylphosphatase", + "3.1.3.42\t[Glycogen-synthase-D] phosphatase", + "3.1.3.43\t[Pyruvate dehydrogenase (acetyl-transferring)]-phosphatase", + "3.1.3.44\t[Acetyl-CoA carboxylase]-phosphatase", + "3.1.3.45\t3-deoxy-manno-octulosonate-8-phosphatase", + "3.1.3.46\tFructose-2,6-bisphosphate 2-phosphatase", + "3.1.3.47\t[Hydroxymethylglutaryl-CoA reductase (NADPH)]-phosphatase", + "3.1.3.48\tProtein-tyrosine-phosphatase", + "3.1.3.49\t[Pyruvate kinase]-phosphatase", + "3.1.3.50\tSorbitol-6-phosphatase", + "3.1.3.51\tDolichyl-phosphatase", + "3.1.3.52\t[3-methyl-2-oxobutanoate dehydrogenase (2-methylpropanoyl-transferring)]-phosphatase", + "3.1.3.53\t[Myosin-light-chain] phosphatase", + "3.1.3.54\tFructose-2,6-bisphosphate 6-phosphatase", + "3.1.3.55\tCaldesmon-phosphatase", + "3.1.3.56\tInositol-polyphosphate 5-phosphatase", + "3.1.3.57\tInositol-1,4-bisphosphate 1-phosphatase", + "3.1.3.58\tSugar-terminal-phosphatase", + "3.1.3.59\tAlkylacetylglycerophosphatase", + "3.1.3.60\tPhosphoenolpyruvate phosphatase", + "3.1.3.62\tMultiple inositol-polyphosphate phosphatase", + "3.1.3.63\t2-carboxy-D-arabinitol-1-phosphatase", + "3.1.3.64\tPhosphatidylinositol-3-phosphatase", + "3.1.3.66\tPhosphatidylinositol-3,4-bisphosphate 4-phosphatase", + "3.1.3.67\tPhosphatidylinositol-3,4,5-trisphosphate 3-phosphatase", + "3.1.3.68\t2-deoxyglucose-6-phosphatase", + "3.1.3.69\tGlucosylglycerol 3-phosphatase", + "3.1.3.70\tMannosyl-3-phosphoglycerate phosphatase", + "3.1.3.71\t2-phosphosulfolactate phosphatase", + "3.1.3.72\t5-phytase", + "3.1.3.73\tAdenosylcobalamin/alpha-ribazole phosphatase", + "3.1.3.74\tPyridoxal phosphatase", + "3.1.3.75\tPhosphoethanolamine/phosphocholine phosphatase", + "3.1.3.76\tLipid-phosphate phosphatase", + "3.1.3.77\tAcireductone synthase", + "3.1.3.78\tPhosphatidylinositol-4,5-bisphosphate 4-phosphatase", + "3.1.3.79\tMannosylfructose-phosphate phosphatase", + "3.1.3.80\t2,3-bisphosphoglycerate 3-phosphatase", + "3.1.3.81\tDiacylglycerol diphosphate phosphatase", + "3.1.3.82\tD-glycero-beta-D-manno-heptose 1,7-bisphosphate 7-phosphatase", + "3.1.3.83\tD-glycero-alpha-D-manno-heptose-1,7-bisphosphate 7-phosphatase", + "3.1.3.84\tADP-ribose 1''-phosphate phosphatase", + "3.1.3.85\tGlucosyl-3-phosphoglycerate phosphatase", + "3.1.3.86\tPhosphatidylinositol-3,4,5-trisphosphate 5-phosphatase", + "3.1.3.87\t2-hydroxy-3-keto-5-methylthiopentenyl-1-phosphate phosphatase", + "3.1.3.88\t5''-phosphoribostamycin phosphatase", + "3.1.3.89\t5'-deoxynucleotidase", + "3.1.3.90\tMaltose 6'-phosphate phosphatase", + "3.1.3.91\t7-methylguanosine nucleotidase", + "3.1.3.92\tKanosamine-6-phosphate phosphatase", + "3.1.3.93\tL-galactose 1-phosphate phosphatase", + "3.1.3.94\tD-galactose 1-phosphate phosphatase", + "3.1.3.95\tPhosphatidylinositol-3,5-bisphosphate 3-phosphatase", + "3.1.3.96\tPseudouridine 5'-phosphatase", + "3.1.3.97\t3',5'-nucleoside bisphosphate phosphatase", + "3.1.3.99\tIMP-specific 5'-nucleotidase", + "3.1.3.100\tThiamine phosphate phosphatase", + "3.1.3.101\tValidoxylamine A 7'-phosphate phosphatase", + "3.1.3.102\tFMN hydrolase", + "3.1.3.103\t3-deoxy-D-glycero-D-galacto-nonulopyranosonate 9-phosphatase", + "3.1.3.104\t5-amino-6-(5-phospho-D-ribitylamino)uracil phosphatase", + "3.1.4.1\tPhosphodiesterase I", + "3.1.4.2\tGlycerophosphocholine phosphodiesterase", + "3.1.4.3\tPhospholipase C", + "3.1.4.4\tPhospholipase D", + "3.1.4.11\tPhosphoinositide phospholipase C", + "3.1.4.12\tSphingomyelin phosphodiesterase", + "3.1.4.13\tSerine-ethanolaminephosphate phosphodiesterase", + "3.1.4.14\t[Acyl-carrier-protein] phosphodiesterase", + "3.1.4.16\t2',3'-cyclic-nucleotide 2'-phosphodiesterase", + "3.1.4.17\t3',5'-cyclic-nucleotide phosphodiesterase", + "3.1.4.35\t3',5'-cyclic-GMP phosphodiesterase", + "3.1.4.37\t2',3'-cyclic-nucleotide 3'-phosphodiesterase", + "3.1.4.38\tGlycerophosphocholine cholinephosphodiesterase", + "3.1.4.39\tAlkylglycerophosphoethanolamine phosphodiesterase", + "3.1.4.40\tCMP-N-acylneuraminate phosphodiesterase", + "3.1.4.41\tSphingomyelin phosphodiesterase D", + "3.1.4.42\tGlycerol-1,2-cyclic-phosphate 2-phosphodiesterase", + "3.1.4.43\tGlycerophosphoinositol inositolphosphodiesterase", + "3.1.4.44\tGlycerophosphoinositol glycerophosphodiesterase", + "3.1.4.45\tN-acetylglucosamine-1-phosphodiester alpha-N-acetylglucosaminidase", + "3.1.4.46\tGlycerophosphodiester phosphodiesterase", + "3.1.4.48\tDolichylphosphate-glucose phosphodiesterase", + "3.1.4.49\tDolichylphosphate-mannose phosphodiesterase", + "3.1.4.50\tGlycosylphosphatidylinositol phospholipase D", + "3.1.4.51\tGlucose-1-phospho-D-mannosylglycoprotein phosphodiesterase", + "3.1.4.52\tCyclic-guanylate-specific phosphodiesterase", + "3.1.4.53\t3',5'-cyclic-AMP phosphodiesterase", + "3.1.4.54\tN-acetylphosphatidylethanolamine-hydrolyzing phospholipase D", + "3.1.4.55\tPhosphoribosyl 1,2-cyclic phosphate phosphodiesterase", + "3.1.4.56\t7,8-dihydroneopterin 2',3'-cyclic phosphate phosphodiesterase", + "3.1.4.57\tPhosphoribosyl 1,2-cyclic phosphate 1,2-diphosphodiesterase", + "3.1.5.1\tdGTPase", + "3.1.6.1\tArylsulfatase", + "3.1.6.2\tSteryl-sulfatase", + "3.1.6.3\tGlycosulfatase", + "3.1.6.4\tN-acetylgalactosamine-6-sulfatase", + "3.1.6.6\tCholine-sulfatase", + "3.1.6.7\tCellulose-polysulfatase", + "3.1.6.8\tCerebroside-sulfatase", + "3.1.6.9\tChondro-4-sulfatase", + "3.1.6.10\tChondro-6-sulfatase", + "3.1.6.11\tDisulfoglucosamine-6-sulfatase", + "3.1.6.12\tN-acetylgalactosamine-4-sulfatase", + "3.1.6.13\tIduronate-2-sulfatase", + "3.1.6.14\tN-acetylglucosamine-6-sulfatase", + "3.1.6.15\tN-sulfoglucosamine-3-sulfatase", + "3.1.6.16\tMonomethyl-sulfatase", + "3.1.6.17\tD-lactate-2-sulfatase", + "3.1.6.18\tGlucuronate-2-sulfatase", + "3.1.6.19\t(R)-specific secondary-alkylsulfatase", + "3.1.7.1\tPrenyl-diphosphatase", + "3.1.7.2\tGuanosine-3',5'-bis(diphosphate) 3'-diphosphatase", + "3.1.7.3\tMonoterpenyl-diphosphatase", + "3.1.7.5\tGeranylgeranyl diphosphate diphosphatase", + "3.1.7.6\tFarnesyl diphosphatase", + "3.1.7.7\tDrimenol cyclase", + "3.1.7.8\tTuberculosinol synthase", + "3.1.7.9\tIsotuberculosinol synthase", + "3.1.7.10\t(13E)-labda-7,13-dien-15-ol synthase", + "3.1.7.11\tGeranyl diphosphate diphosphatase", + "3.1.8.1\tAryldialkylphosphatase", + "3.1.8.2\tDiisopropyl-fluorophosphatase", + "3.1.11.1\tExodeoxyribonuclease I", + "3.1.11.2\tExodeoxyribonuclease III", + "3.1.11.3\tExodeoxyribonuclease (lambda-induced)", + "3.1.11.4\tExodeoxyribonuclease (phage SP3-induced)", + "3.1.11.5\tExodeoxyribonuclease V", + "3.1.11.6\tExodeoxyribonuclease VII", + "3.1.11.7\tAdenosine-5'-diphospho-5'-(DNA) diphosphatase", + "3.1.11.8\tGuaosine-5'-diphospho-5'-(DNA) diphosphatase", + "3.1.12.1\t5' to 3' exodeoxyribonuclease (nucleoside 3'-phosphate-forming)", + "3.1.12.2\tDNA-3'-diphospho-5'-guanosine diphosphatase", + "3.1.13.1\tExoribonuclease II", + "3.1.13.2\tExoribonuclease H", + "3.1.13.3\tOligonucleotidase", + "3.1.13.4\tPoly(A)-specific ribonuclease", + "3.1.13.5\tRibonuclease D", + "3.1.14.1\tYeast ribonuclease", + "3.1.15.1\tVenom exonuclease", + "3.1.16.1\tSpleen exonuclease", + "3.1.21.1\tDeoxyribonuclease I", + "3.1.21.2\tDeoxyribonuclease IV", + "3.1.21.3\tType I site-specific deoxyribonuclease", + "3.1.21.4\tType II site-specific deoxyribonuclease", + "3.1.21.5\tType III site-specific deoxyribonuclease", + "3.1.21.6\tCC-preferring endodeoxyribonuclease", + "3.1.21.7\tDeoxyribonuclease V", + "3.1.21.8\tT(4) deoxyribonuclease II", + "3.1.21.9\tT(4) deoxyribonuclease IV", + "3.1.22.1\tDeoxyribonuclease II", + "3.1.22.2\tAspergillus deoxyribonuclease K(1)", + "3.1.22.4\tCrossover junction endodeoxyribonuclease", + "3.1.22.5\tDeoxyribonuclease X", + "3.1.25.1\tDeoxyribonuclease (pyrimidine dimer)", + "3.1.26.1\tPhysarum polycephalum ribonuclease", + "3.1.26.2\tRibonuclease alpha", + "3.1.26.3\tRibonuclease III", + "3.1.26.4\tRibonuclease H", + "3.1.26.5\tRibonuclease P", + "3.1.26.6\tRibonuclease IV", + "3.1.26.7\tRibonuclease P4", + "3.1.26.8\tRibonuclease M5", + "3.1.26.9\tRibonuclease (poly-(U)-specific)", + "3.1.26.10\tRibonuclease IX", + "3.1.26.11\tRibonuclease Z", + "3.1.26.12\tRibonuclease E", + "3.1.26.13\tRetroviral ribonuclease H", + "3.1.26.n2\tArgonaute-2", + "3.1.27.1\tRibonuclease T(2)", + "3.1.27.2\tBacillus subtilis ribonuclease", + "3.1.27.3\tRibonuclease T(1)", + "3.1.27.4\tRibonuclease U(2)", + "3.1.27.5\tPancreatic ribonuclease", + "3.1.27.6\tEnterobacter ribonuclease", + "3.1.27.7\tRibonuclease F", + "3.1.27.8\tRibonuclease V", + "3.1.27.10\trRNA endonuclease", + "3.1.30.1\tAspergillus nuclease S(1)", + "3.1.30.2\tSerratia marcescens nuclease", + "3.1.31.1\tMicrococcal nuclease", + "3.2.1.1\tAlpha-amylase", + "3.2.1.2\tBeta-amylase", + "3.2.1.3\tGlucan 1,4-alpha-glucosidase", + "3.2.1.4\tCellulase", + "3.2.1.6\tEndo-1,3(4)-beta-glucanase", + "3.2.1.7\tInulinase", + "3.2.1.8\tEndo-1,4-beta-xylanase", + "3.2.1.10\tOligo-1,6-glucosidase", + "3.2.1.11\tDextranase", + "3.2.1.14\tChitinase", + "3.2.1.15\tPolygalacturonase", + "3.2.1.17\tLysozyme", + "3.2.1.18\tExo-alpha-sialidase", + "3.2.1.20\tAlpha-glucosidase", + "3.2.1.21\tBeta-glucosidase", + "3.2.1.22\tAlpha-galactosidase", + "3.2.1.23\tBeta-galactosidase", + "3.2.1.24\tAlpha-mannosidase", + "3.2.1.25\tBeta-mannosidase", + "3.2.1.26\tBeta-fructofuranosidase", + "3.2.1.28\tAlpha,alpha-trehalase", + "3.2.1.31\tBeta-glucuronidase", + "3.2.1.32\tEndo-1,3-beta-xylanase", + "3.2.1.33\tAmylo-alpha-1,6-glucosidase", + "3.2.1.35\tHyaluronoglucosaminidase", + "3.2.1.36\tHyaluronoglucuronidase", + "3.2.1.37\tXylan 1,4-beta-xylosidase", + "3.2.1.38\tBeta-D-fucosidase", + "3.2.1.39\tGlucan endo-1,3-beta-D-glucosidase", + "3.2.1.40\tAlpha-L-rhamnosidase", + "3.2.1.41\tPullulanase", + "3.2.1.42\tGDP-glucosidase", + "3.2.1.43\tBeta-L-rhamnosidase", + "3.2.1.44\tFucoidanase", + "3.2.1.45\tGlucosylceramidase", + "3.2.1.46\tGalactosylceramidase", + "3.2.1.47\tGalactosylgalactosylglucosylceramidase", + "3.2.1.48\tSucrose alpha-glucosidase", + "3.2.1.49\tAlpha-N-acetylgalactosaminidase", + "3.2.1.50\tAlpha-N-acetylglucosaminidase", + "3.2.1.51\tAlpha-L-fucosidase", + "3.2.1.52\tBeta-N-acetylhexosaminidase", + "3.2.1.53\tBeta-N-acetylgalactosaminidase", + "3.2.1.54\tCyclomaltodextrinase", + "3.2.1.55\tNon-reducing end alpha-L-arabinofuranosidase", + "3.2.1.56\tGlucuronosyl-disulfoglucosamine glucuronidase", + "3.2.1.57\tIsopullulanase", + "3.2.1.58\tGlucan 1,3-beta-glucosidase", + "3.2.1.59\tGlucan endo-1,3-alpha-glucosidase", + "3.2.1.60\tGlucan 1,4-alpha-maltotetraohydrolase", + "3.2.1.61\tMycodextranase", + "3.2.1.62\tGlycosylceramidase", + "3.2.1.63\t1,2-alpha-L-fucosidase", + "3.2.1.64\t2,6-beta-fructan 6-levanbiohydrolase", + "3.2.1.65\tLevanase", + "3.2.1.66\tQuercitrinase", + "3.2.1.67\tGalacturan 1,4-alpha-galacturonidase", + "3.2.1.68\tIsoamylase", + "3.2.1.70\tGlucan 1,6-alpha-glucosidase", + "3.2.1.71\tGlucan endo-1,2-beta-glucosidase", + "3.2.1.72\tXylan 1,3-beta-xylosidase", + "3.2.1.73\tLicheninase", + "3.2.1.74\tGlucan 1,4-beta-glucosidase", + "3.2.1.75\tGlucan endo-1,6-beta-glucosidase", + "3.2.1.76\tL-iduronidase", + "3.2.1.77\tMannan 1,2-(1,3)-alpha-mannosidase", + "3.2.1.78\tMannan endo-1,4-beta-mannosidase", + "3.2.1.80\tFructan beta-fructosidase", + "3.2.1.81\tBeta-agarase", + "3.2.1.82\tExo-poly-alpha-galacturonosidase", + "3.2.1.83\tKappa-carrageenase", + "3.2.1.84\tGlucan 1,3-alpha-glucosidase", + "3.2.1.85\t6-phospho-beta-galactosidase", + "3.2.1.86\t6-phospho-beta-glucosidase", + "3.2.1.87\tCapsular-polysaccharide endo-1,3-alpha-galactosidase", + "3.2.1.88\tNon-reducing end beta-L-arabinopyranosidase", + "3.2.1.89\tArabinogalactan endo-beta-1,4-galactanase", + "3.2.1.91\tCellulose 1,4-beta-cellobiosidase (non-reducing end)", + "3.2.1.92\tPeptidoglycan beta-N-acetylmuramidase", + "3.2.1.93\tAlpha,alpha-phosphotrehalase", + "3.2.1.94\tGlucan 1,6-alpha-isomaltosidase", + "3.2.1.95\tDextran 1,6-alpha-isomaltotriosidase", + "3.2.1.96\tMannosyl-glycoprotein endo-beta-N-acetylglucosaminidase", + "3.2.1.97\tEndo-alpha-N-acetylgalactosaminidase", + "3.2.1.98\tGlucan 1,4-alpha-maltohexaosidase", + "3.2.1.99\tArabinan endo-1,5-alpha-L-arabinosidase", + "3.2.1.100\tMannan 1,4-mannobiosidase", + "3.2.1.101\tMannan endo-1,6-alpha-mannosidase", + "3.2.1.102\tBlood-group-substance endo-1,4-beta-galactosidase", + "3.2.1.103\tKeratan-sulfate endo-1,4-beta-galactosidase", + "3.2.1.104\tSteryl-beta-glucosidase", + "3.2.1.105\t3-alpha-(S)-strictosidine beta-glucosidase", + "3.2.1.106\tMannosyl-oligosaccharide glucosidase", + "3.2.1.107\tProtein-glucosylgalactosylhydroxylysine glucosidase", + "3.2.1.108\tLactase", + "3.2.1.109\tEndogalactosaminidase", + "3.2.1.111\t1,3-alpha-L-fucosidase", + "3.2.1.112\t2-deoxyglucosidase", + "3.2.1.113\tMannosyl-oligosaccharide 1,2-alpha-mannosidase", + "3.2.1.114\tMannosyl-oligosaccharide 1,3-1,6-alpha-mannosidase", + "3.2.1.115\tBranched-dextran exo-1,2-alpha-glucosidase", + "3.2.1.116\tGlucan 1,4-alpha-maltotriohydrolase", + "3.2.1.117\tAmygdalin beta-glucosidase", + "3.2.1.118\tPrunasin beta-glucosidase", + "3.2.1.119\tVicianin beta-glucosidase", + "3.2.1.120\tOligoxyloglucan beta-glycosidase", + "3.2.1.121\tPolymannuronate hydrolase", + "3.2.1.122\tMaltose-6'-phosphate glucosidase", + "3.2.1.123\tEndoglycosylceramidase", + "3.2.1.124\t3-deoxy-2-octulosonidase", + "3.2.1.125\tRaucaffricine beta-glucosidase", + "3.2.1.126\tConiferin beta-glucosidase", + "3.2.1.127\t1,6-alpha-L-fucosidase", + "3.2.1.128\tGlycyrrhizinate beta-glucuronidase", + "3.2.1.129\tEndo-alpha-sialidase", + "3.2.1.130\tGlycoprotein endo-alpha-1,2-mannosidase", + "3.2.1.131\tXylan alpha-1,2-glucuronosidase", + "3.2.1.132\tChitosanase", + "3.2.1.133\tGlucan 1,4-alpha-maltohydrolase", + "3.2.1.134\tDifructose-anhydride synthase", + "3.2.1.135\tNeopullulanase", + "3.2.1.136\tGlucuronoarabinoxylan endo-1,4-beta-xylanase", + "3.2.1.137\tMannan exo-1,2-1,6-alpha-mannosidase", + "3.2.1.139\tAlpha-glucuronidase", + "3.2.1.140\tLacto-N-biosidase", + "3.2.1.141\t4-alpha-D-((1->4)-alpha-D-glucano)trehalose trehalohydrolase", + "3.2.1.142\tLimit dextrinase", + "3.2.1.143\tPoly(ADP-ribose) glycohydrolase", + "3.2.1.144\t3-deoxyoctulosonase", + "3.2.1.145\tGalactan 1,3-beta-galactosidase", + "3.2.1.146\tBeta-galactofuranosidase", + "3.2.1.147\tThioglucosidase", + "3.2.1.149\tBeta-primeverosidase", + "3.2.1.150\tOligoxyloglucan reducing-end-specific cellobiohydrolase", + "3.2.1.151\tXyloglucan-specific endo-beta-1,4-glucanase", + "3.2.1.152\tMannosylglycoprotein endo-beta-mannosidase", + "3.2.1.153\tFructan beta-(2,1)-fructosidase", + "3.2.1.154\tFructan beta-(2,6)-fructosidase", + "3.2.1.155\tXyloglucan-specific exo-beta-1,4-glucanase", + "3.2.1.156\tOligosaccharide reducing-end xylanase", + "3.2.1.157\tIota-carrageenase", + "3.2.1.158\tAlpha-agarase", + "3.2.1.159\tAlpha-neoagaro-oligosaccharide hydrolase", + "3.2.1.161\tBeta-apiosyl-beta-glucosidase", + "3.2.1.162\tLambda-carrageenase", + "3.2.1.163\t1,6-alpha-D-mannosidase", + "3.2.1.164\tGalactan endo-1,6-beta-galactosidase", + "3.2.1.165\tExo-1,4-beta-D-glucosaminidase", + "3.2.1.166\tHeparanase", + "3.2.1.167\tBaicalin-beta-D-glucuronidase", + "3.2.1.168\tHesperidin 6-O-alpha-L-rhamnosyl-beta-D-glucosidase", + "3.2.1.169\tProtein O-GlcNAcase", + "3.2.1.170\tMannosylglycerate hydrolase", + "3.2.1.171\tRhamnogalacturonan hydrolase", + "3.2.1.172\tUnsaturated rhamnogalacturonyl hydrolase", + "3.2.1.173\tRhamnogalacturonan galacturonohydrolase", + "3.2.1.174\tRhamnogalacturonan rhamnohydrolase", + "3.2.1.175\tBeta-D-glucopyranosyl abscisate beta-glucosidase", + "3.2.1.176\tCellulose 1,4-beta-cellobiosidase (reducing end)", + "3.2.1.177\tAlpha-D-xyloside xylohydrolase", + "3.2.1.178\tBeta-porphyranase", + "3.2.1.179\tGellan tetrasaccharide unsaturated glucuronosyl hydrolase", + "3.2.1.180\tUnsaturated chondroitin disaccharide hydrolase", + "3.2.1.181\tGalactan endo-beta-1,3-galactanase", + "3.2.1.182\t4-hydroxy-7-methoxy-3-oxo-3,4-dihydro-2H-1,4-benzoxazin-2-yl glucoside beta-D-glucosidase", + "3.2.1.183\tUDP-N-acetylglucosamine 2-epimerase (hydrolyzing)", + "3.2.1.184\tUDP-N,N'-diacetylbacillosamine 2-epimerase (hydrolyzing)", + "3.2.1.185\tNon-reducing end beta-L-arabinofuranosidase", + "3.2.1.186\tProtodioscin 26-O-beta-D-glucosidase", + "3.2.1.187\t(Ara-f)(3)-Hyp beta-L-arabinobiosidase", + "3.2.1.188\tAvenacosidase", + "3.2.1.189\tDioscin glycosidase (diosgenin-forming)", + "3.2.1.190\tDioscin glycosidase (3-O-beta-D-Glc-diosgenin-forming)", + "3.2.1.191\tGinsenosidase type III", + "3.2.1.192\tGinsenoside Rb1 beta-glucosidase", + "3.2.1.193\tGinsenosidase type I", + "3.2.1.194\tGinsenosidase type IV", + "3.2.1.195\t20-O-multi-glycoside ginsenosidase", + "3.2.1.196\tLimit dextrin alpha-1,6-maltotetraose-hydrolase", + "3.2.1.197\tBeta-1,2-mannosidase", + "3.2.1.198\tAlpha-mannan endo-1,2-alpha-mannanase", + "3.2.1.199\tSulfoquinovosidase", + "3.2.1.200\tExo-chitinase (non-reducing end)", + "3.2.1.201\tExo-chitinase (reducing end)", + "3.2.1.202\tEndo-chitodextinase", + "3.2.1.n1\tBlood group B branched chain alpha-1,3-galactosidase", + "3.2.1.n2\tBlood group B linear chain alpha-1,3-galactosidase", + "3.2.1.n3\tDictyostelium lysozyme A", + "3.2.2.1\tPurine nucleosidase", + "3.2.2.2\tInosine nucleosidase", + "3.2.2.3\tUridine nucleosidase", + "3.2.2.4\tAMP nucleosidase", + "3.2.2.5\tNAD(+) glycohydrolase", + "3.2.2.6\tADP-ribosyl cyclase/cyclic ADP-ribose hydrolase", + "3.2.2.7\tAdenosine nucleosidase", + "3.2.2.8\tRibosylpyrimidine nucleosidase", + "3.2.2.9\tAdenosylhomocysteine nucleosidase", + "3.2.2.10\tPyrimidine-5'-nucleotide nucleosidase", + "3.2.2.11\tBeta-aspartyl-N-acetylglucosaminidase", + "3.2.2.12\tInosinate nucleosidase", + "3.2.2.13\t1-methyladenosine nucleosidase", + "3.2.2.14\tNMN nucleosidase", + "3.2.2.15\tDNA-deoxyinosine glycosylase", + "3.2.2.16\tMethylthioadenosine nucleosidase", + "3.2.2.17\tDeoxyribodipyrimidine endonucleosidase", + "3.2.2.19\t[Protein ADP-ribosylarginine] hydrolase", + "3.2.2.20\tDNA-3-methyladenine glycosylase I", + "3.2.2.21\tDNA-3-methyladenine glycosylase II", + "3.2.2.22\trRNA N-glycosylase", + "3.2.2.23\tDNA-formamidopyrimidine glycosylase", + "3.2.2.24\tADP-ribosyl-[dinitrogen reductase] hydrolase", + "3.2.2.25\tN-methyl nucleosidase", + "3.2.2.26\tFutalosine hydrolase", + "3.2.2.27\tUracil-DNA glycosylase", + "3.2.2.28\tDouble-stranded uracil-DNA glycosylase", + "3.2.2.29\tThymine-DNA glycosylase", + "3.2.2.30\tAminodeoxyfutalosine nucleosidase", + "3.2.2.n1\tCytokinin riboside 5'-monophosphate phosphoribohydrolase", + "3.3.1.1\tAdenosylhomocysteinase", + "3.3.1.2\tAdenosylmethionine hydrolase", + "3.3.2.1\tIsochorismatase", + "3.3.2.2\tLysoplasmalogenase", + "3.3.2.4\tTrans-epoxysuccinate hydrolase", + "3.3.2.6\tLeukotriene-A(4) hydrolase", + "3.3.2.7\tHepoxilin-epoxide hydrolase", + "3.3.2.8\tLimonene-1,2-epoxide hydrolase", + "3.3.2.9\tMicrosomal epoxide hydrolase", + "3.3.2.10\tSoluble epoxide hydrolase", + "3.3.2.11\tCholesterol-5,6-oxide hydrolase", + "3.3.2.12\tOxepin-CoA hydrolase", + "3.3.2.13\tChorismatase", + "3.3.2.14\t2,4-dinitroanisole O-demethylase", + "3.3.2.15\tTrans-2,3-dihydro-3-hydroxyanthranilic acid synthase", + "3.4.11.1\tLeucyl aminopeptidase", + "3.4.11.2\tMembrane alanyl aminopeptidase", + "3.4.11.3\tCystinyl aminopeptidase", + "3.4.11.4\tTripeptide aminopeptidase", + "3.4.11.5\tProlyl aminopeptidase", + "3.4.11.6\tAminopeptidase B", + "3.4.11.7\tGlutamyl aminopeptidase", + "3.4.11.9\tXaa-Pro aminopeptidase", + "3.4.11.10\tBacterial leucyl aminopeptidase", + "3.4.11.13\tClostridial aminopeptidase", + "3.4.11.14\tCytosol alanyl aminopeptidase", + "3.4.11.15\tAminopeptidase Y", + "3.4.11.16\tXaa-Trp aminopeptidase", + "3.4.11.17\tTryptophanyl aminopeptidase", + "3.4.11.18\tMethionyl aminopeptidase", + "3.4.11.19\tD-stereospecific aminopeptidase", + "3.4.11.20\tAminopeptidase Ey", + "3.4.11.21\tAspartyl aminopeptidase", + "3.4.11.22\tAminopeptidase I", + "3.4.11.23\tPepB aminopeptidase", + "3.4.11.24\tAminopeptidase S", + "3.4.11.25\tBeta-peptidyl aminopeptidase", + "3.4.11.26\tIntermediate cleaving peptidase 55", + "3.4.13.4\tXaa-Arg dipeptidase", + "3.4.13.5\tXaa-methyl-His dipeptidase", + "3.4.13.7\tGlu-Glu dipeptidase", + "3.4.13.9\tXaa-Pro dipeptidase", + "3.4.13.12\tMet-Xaa dipeptidase", + "3.4.13.17\tNon-stereospecific dipeptidase", + "3.4.13.18\tCytosol nonspecific dipeptidase", + "3.4.13.19\tMembrane dipeptidase", + "3.4.13.20\tBeta-Ala-His dipeptidase", + "3.4.13.21\tDipeptidase E", + "3.4.13.22\tD-Ala-D-Ala dipeptidase", + "3.4.14.1\tDipeptidyl-peptidase I", + "3.4.14.2\tDipeptidyl-peptidase II", + "3.4.14.4\tDipeptidyl-peptidase III", + "3.4.14.5\tDipeptidyl-peptidase IV", + "3.4.14.6\tDipeptidyl-dipeptidase", + "3.4.14.9\tTripeptidyl-peptidase I", + "3.4.14.10\tTripeptidyl-peptidase II", + "3.4.14.11\tXaa-Pro dipeptidyl-peptidase", + "3.4.14.12\tXaa-Xaa-Pro tripeptidyl-peptidase", + "3.4.14.13\tGamma-D-glutamyl-L-lysine dipeptidyl-peptidase", + "3.4.15.1\tPeptidyl-dipeptidase A", + "3.4.15.4\tPeptidyl-dipeptidase B", + "3.4.15.5\tPeptidyl-dipeptidase Dcp", + "3.4.15.6\tCyanophycinase", + "3.4.16.2\tLysosomal Pro-Xaa carboxypeptidase", + "3.4.16.4\tSerine-type D-Ala-D-Ala carboxypeptidase", + "3.4.16.5\tCarboxypeptidase C", + "3.4.16.6\tCarboxypeptidase D", + "3.4.17.1\tCarboxypeptidase A", + "3.4.17.2\tCarboxypeptidase B", + "3.4.17.3\tLysine carboxypeptidase", + "3.4.17.4\tGly-Xaa carboxypeptidase", + "3.4.17.6\tAlanine carboxypeptidase", + "3.4.17.8\tMuramoylpentapeptide carboxypeptidase", + "3.4.17.10\tCarboxypeptidase E", + "3.4.17.11\tGlutamate carboxypeptidase", + "3.4.17.12\tCarboxypeptidase M", + "3.4.17.13\tMuramoyltetrapeptide carboxypeptidase", + "3.4.17.14\tZinc D-Ala-D-Ala carboxypeptidase", + "3.4.17.15\tCarboxypeptidase A2", + "3.4.17.16\tMembrane Pro-Xaa carboxypeptidase", + "3.4.17.17\tTubulinyl-Tyr carboxypeptidase", + "3.4.17.18\tCarboxypeptidase T", + "3.4.17.19\tCarboxypeptidase Taq", + "3.4.17.20\tCarboxypeptidase U", + "3.4.17.21\tGlutamate carboxypeptidase II", + "3.4.17.22\tMetallocarboxypeptidase D", + "3.4.17.23\tAngiotensin-converting enzyme 2", + "3.4.17.n1\t[CysO sulfur-carrier protein]-S-L-cysteine hydrolase", + "3.4.18.1\tCathepsin X", + "3.4.19.1\tAcylaminoacyl-peptidase", + "3.4.19.2\tPeptidyl-glycinamidase", + "3.4.19.3\tPyroglutamyl-peptidase I", + "3.4.19.5\tBeta-aspartyl-peptidase", + "3.4.19.6\tPyroglutamyl-peptidase II", + "3.4.19.7\tN-formylmethionyl-peptidase", + "3.4.19.9\tGamma-glutamyl hydrolase", + "3.4.19.11\tGamma-D-glutamyl-meso-diaminopimelate peptidase", + "3.4.19.12\tUbiquitinyl hydrolase 1", + "3.4.19.13\tGlutathione hydrolase", + "3.4.19.14\tLeukotriene-C(4) hydrolase", + "3.4.19.15\tDesampylase", + "3.4.21.1\tChymotrypsin", + "3.4.21.2\tChymotrypsin C", + "3.4.21.3\tMetridin", + "3.4.21.4\tTrypsin", + "3.4.21.5\tThrombin", + "3.4.21.6\tCoagulation factor Xa", + "3.4.21.7\tPlasmin", + "3.4.21.9\tEnteropeptidase", + "3.4.21.10\tAcrosin", + "3.4.21.12\tAlpha-lytic endopeptidase", + "3.4.21.19\tGlutamyl endopeptidase", + "3.4.21.20\tCathepsin G", + "3.4.21.21\tCoagulation factor VIIa", + "3.4.21.22\tCoagulation factor IXa", + "3.4.21.25\tCucumisin", + "3.4.21.26\tProlyl oligopeptidase", + "3.4.21.27\tCoagulation factor XIa", + "3.4.21.32\tBrachyurin", + "3.4.21.34\tPlasma kallikrein", + "3.4.21.35\tTissue kallikrein", + "3.4.21.36\tPancreatic elastase", + "3.4.21.37\tLeukocyte elastase", + "3.4.21.38\tCoagulation factor XIIa", + "3.4.21.39\tChymase", + "3.4.21.41\tComplement subcomponent C1r", + "3.4.21.42\tComplement subcomponent C1s", + "3.4.21.43\tClassical-complement-pathway C3/C5 convertase", + "3.4.21.45\tComplement factor I", + "3.4.21.46\tComplement factor D", + "3.4.21.47\tAlternative-complement-pathway C3/C5 convertase", + "3.4.21.48\tCerevisin", + "3.4.21.49\tHypodermin C", + "3.4.21.50\tLysyl endopeptidase", + "3.4.21.53\tEndopeptidase La", + "3.4.21.54\tGamma-renin", + "3.4.21.55\tVenombin AB", + "3.4.21.57\tLeucyl endopeptidase", + "3.4.21.59\tTryptase", + "3.4.21.60\tScutelarin", + "3.4.21.61\tKexin", + "3.4.21.62\tSubtilisin", + "3.4.21.63\tOryzin", + "3.4.21.64\tPeptidase K", + "3.4.21.65\tThermomycolin", + "3.4.21.66\tThermitase", + "3.4.21.67\tEndopeptidase So", + "3.4.21.68\tT-plasminogen activator", + "3.4.21.69\tProtein C (activated)", + "3.4.21.70\tPancreatic endopeptidase E", + "3.4.21.71\tPancreatic elastase II", + "3.4.21.72\tIgA-specific serine endopeptidase", + "3.4.21.73\tU-plasminogen activator", + "3.4.21.74\tVenombin A", + "3.4.21.75\tFurin", + "3.4.21.76\tMyeloblastin", + "3.4.21.77\tSemenogelase", + "3.4.21.78\tGranzyme A", + "3.4.21.79\tGranzyme B", + "3.4.21.80\tStreptogrisin A", + "3.4.21.81\tStreptogrisin B", + "3.4.21.82\tGlutamyl endopeptidase II", + "3.4.21.83\tOligopeptidase B", + "3.4.21.84\tLimulus clotting factor C", + "3.4.21.85\tLimulus clotting factor B", + "3.4.21.86\tLimulus clotting enzyme", + "3.4.21.88\tRepressor LexA", + "3.4.21.89\tSignal peptidase I", + "3.4.21.90\tTogavirin", + "3.4.21.91\tFlavivirin", + "3.4.21.92\tEndopeptidase Clp", + "3.4.21.93\tProprotein convertase 1", + "3.4.21.94\tProprotein convertase 2", + "3.4.21.95\tSnake venom factor V activator", + "3.4.21.96\tLactocepin", + "3.4.21.97\tAssemblin", + "3.4.21.98\tHepacivirin", + "3.4.21.99\tSpermosin", + "3.4.21.100\tSedolisin", + "3.4.21.101\tXanthomonalisin", + "3.4.21.102\tC-terminal processing peptidase", + "3.4.21.103\tPhysarolisin", + "3.4.21.104\tMannan-binding lectin-associated serine protease-2", + "3.4.21.105\tRhomboid protease", + "3.4.21.106\tHepsin", + "3.4.21.107\tPeptidase Do", + "3.4.21.108\tHtrA2 peptidase", + "3.4.21.109\tMatriptase", + "3.4.21.110\tC5a peptidase", + "3.4.21.111\tAqualysin 1", + "3.4.21.112\tSite-1 protease", + "3.4.21.113\tPestivirus NS3 polyprotein peptidase", + "3.4.21.114\tEquine arterivirus serine peptidase", + "3.4.21.115\tInfectious pancreatic necrosis birnavirus Vp4 peptidase", + "3.4.21.116\tSpoIVB peptidase", + "3.4.21.117\tStratum corneum chymotryptic enzyme", + "3.4.21.118\tKallikrein 8", + "3.4.21.119\tKallikrein 13", + "3.4.21.120\tOviductin", + "3.4.21.121\tLys-Lys/Arg-Xaa endopeptidase", + "3.4.22.1\tCathepsin B", + "3.4.22.2\tPapain", + "3.4.22.3\tFicain", + "3.4.22.6\tChymopapain", + "3.4.22.7\tAsclepain", + "3.4.22.8\tClostripain", + "3.4.22.10\tStreptopain", + "3.4.22.14\tActinidain", + "3.4.22.15\tCathepsin L", + "3.4.22.16\tCathepsin H", + "3.4.22.24\tCathepsin T", + "3.4.22.25\tGlycyl endopeptidase", + "3.4.22.26\tCancer procoagulant", + "3.4.22.27\tCathepsin S", + "3.4.22.28\tPicornain 3C", + "3.4.22.29\tPicornain 2A", + "3.4.22.30\tCaricain", + "3.4.22.31\tAnanain", + "3.4.22.32\tStem bromelain", + "3.4.22.33\tFruit bromelain", + "3.4.22.34\tLegumain", + "3.4.22.35\tHistolysain", + "3.4.22.36\tCaspase-1", + "3.4.22.37\tGingipain R", + "3.4.22.38\tCathepsin K", + "3.4.22.39\tAdenain", + "3.4.22.40\tBleomycin hydrolase", + "3.4.22.41\tCathepsin F", + "3.4.22.42\tCathepsin O", + "3.4.22.43\tCathepsin V", + "3.4.22.44\tNuclear-inclusion-a endopeptidase", + "3.4.22.45\tHelper-component proteinase", + "3.4.22.46\tL-peptidase", + "3.4.22.47\tGingipain K", + "3.4.22.48\tStaphopain", + "3.4.22.49\tSeparase", + "3.4.22.50\tV-cath endopeptidase", + "3.4.22.51\tCruzipain", + "3.4.22.52\tCalpain-1", + "3.4.22.53\tCalpain-2", + "3.4.22.54\tCalpain-3", + "3.4.22.55\tCaspase-2", + "3.4.22.56\tCaspase-3", + "3.4.22.57\tCaspase-4", + "3.4.22.58\tCaspase-5", + "3.4.22.59\tCaspase-6", + "3.4.22.60\tCaspase-7", + "3.4.22.61\tCaspase-8", + "3.4.22.62\tCaspase-9", + "3.4.22.63\tCaspase-10", + "3.4.22.64\tCaspase-11", + "3.4.22.65\tPeptidase 1 (mite)", + "3.4.22.66\tCalicivirin", + "3.4.22.67\tZingipain", + "3.4.22.68\tUlp1 peptidase", + "3.4.22.69\tSARS coronavirus main proteinase", + "3.4.22.70\tSortase A", + "3.4.22.71\tSortase B", + "3.4.23.1\tPepsin A", + "3.4.23.2\tPepsin B", + "3.4.23.3\tGastricsin", + "3.4.23.4\tChymosin", + "3.4.23.5\tCathepsin D", + "3.4.23.12\tNepenthesin", + "3.4.23.15\tRenin", + "3.4.23.16\tHIV-1 retropepsin", + "3.4.23.17\tPro-opiomelanocortin converting enzyme", + "3.4.23.18\tAspergillopepsin I", + "3.4.23.19\tAspergillopepsin II", + "3.4.23.20\tPenicillopepsin", + "3.4.23.21\tRhizopuspepsin", + "3.4.23.22\tEndothiapepsin", + "3.4.23.23\tMucorpepsin", + "3.4.23.24\tCandidapepsin", + "3.4.23.25\tSaccharopepsin", + "3.4.23.26\tRhodotorulapepsin", + "3.4.23.28\tAcrocylindropepsin", + "3.4.23.29\tPolyporopepsin", + "3.4.23.30\tPycnoporopepsin", + "3.4.23.31\tScytalidopepsin A", + "3.4.23.32\tScytalidopepsin B", + "3.4.23.34\tCathepsin E", + "3.4.23.35\tBarrierpepsin", + "3.4.23.36\tSignal peptidase II", + "3.4.23.38\tPlasmepsin I", + "3.4.23.39\tPlasmepsin II", + "3.4.23.40\tPhytepsin", + "3.4.23.41\tYapsin 1", + "3.4.23.42\tThermopsin", + "3.4.23.43\tPrepilin peptidase", + "3.4.23.44\tNodavirus endopeptidase", + "3.4.23.45\tMemapsin 1", + "3.4.23.46\tMemapsin 2", + "3.4.23.47\tHIV-2 retropepsin", + "3.4.23.48\tPlasminogen activator Pla", + "3.4.23.49\tOmptin", + "3.4.23.50\tHuman endogenous retrovirus K endopeptidase", + "3.4.23.51\tHycI peptidase", + "3.4.23.52\tPreflagellin peptidase", + "3.4.24.1\tAtrolysin A", + "3.4.24.3\tMicrobial collagenase", + "3.4.24.6\tLeucolysin", + "3.4.24.7\tInterstitial collagenase", + "3.4.24.11\tNeprilysin", + "3.4.24.12\tEnvelysin", + "3.4.24.13\tIgA-specific metalloendopeptidase", + "3.4.24.14\tProcollagen N-endopeptidase", + "3.4.24.15\tThimet oligopeptidase", + "3.4.24.16\tNeurolysin", + "3.4.24.17\tStromelysin 1", + "3.4.24.18\tMeprin A", + "3.4.24.19\tProcollagen C-endopeptidase", + "3.4.24.20\tPeptidyl-Lys metalloendopeptidase", + "3.4.24.21\tAstacin", + "3.4.24.22\tStromelysin 2", + "3.4.24.23\tMatrilysin", + "3.4.24.24\tGelatinase A", + "3.4.24.25\tVibriolysin", + "3.4.24.26\tPseudolysin", + "3.4.24.27\tThermolysin", + "3.4.24.28\tBacillolysin", + "3.4.24.29\tAureolysin", + "3.4.24.30\tCoccolysin", + "3.4.24.31\tMycolysin", + "3.4.24.32\tBeta-lytic metalloendopeptidase", + "3.4.24.33\tPeptidyl-Asp metalloendopeptidase", + "3.4.24.34\tNeutrophil collagenase", + "3.4.24.35\tGelatinase B", + "3.4.24.36\tLeishmanolysin", + "3.4.24.37\tSaccharolysin", + "3.4.24.38\tGametolysin", + "3.4.24.39\tDeuterolysin", + "3.4.24.40\tSerralysin", + "3.4.24.41\tAtrolysin B", + "3.4.24.42\tAtrolysin C", + "3.4.24.43\tAtroxase", + "3.4.24.44\tAtrolysin E", + "3.4.24.45\tAtrolysin F", + "3.4.24.46\tAdamalysin", + "3.4.24.47\tHorrilysin", + "3.4.24.48\tRuberlysin", + "3.4.24.49\tBothropasin", + "3.4.24.50\tBothrolysin", + "3.4.24.51\tOphiolysin", + "3.4.24.52\tTrimerelysin I", + "3.4.24.53\tTrimerelysin II", + "3.4.24.54\tMucrolysin", + "3.4.24.55\tPitrilysin", + "3.4.24.56\tInsulysin", + "3.4.24.57\tO-sialoglycoprotein endopeptidase", + "3.4.24.58\tRussellysin", + "3.4.24.59\tMitochondrial intermediate peptidase", + "3.4.24.60\tDactylysin", + "3.4.24.61\tNardilysin", + "3.4.24.62\tMagnolysin", + "3.4.24.63\tMeprin B", + "3.4.24.64\tMitochondrial processing peptidase", + "3.4.24.65\tMacrophage elastase", + "3.4.24.66\tChoriolysin L", + "3.4.24.67\tChoriolysin H", + "3.4.24.68\tTentoxilysin", + "3.4.24.69\tBontoxilysin", + "3.4.24.70\tOligopeptidase A", + "3.4.24.71\tEndothelin-converting enzyme 1", + "3.4.24.72\tFibrolase", + "3.4.24.73\tJararhagin", + "3.4.24.74\tFragilysin", + "3.4.24.75\tLysostaphin", + "3.4.24.76\tFlavastacin", + "3.4.24.77\tSnapalysin", + "3.4.24.78\tGPR endopeptidase", + "3.4.24.79\tPappalysin-1", + "3.4.24.80\tMembrane-type matrix metalloproteinase-1", + "3.4.24.81\tADAM10 endopeptidase", + "3.4.24.82\tADAMTS-4 endopeptidase", + "3.4.24.83\tAnthrax lethal factor endopeptidase", + "3.4.24.84\tSte24 endopeptidase", + "3.4.24.85\tS2P endopeptidase", + "3.4.24.86\tADAM 17 endopeptidase", + "3.4.24.87\tADAMTS13 endopeptidase", + "3.4.24.89\tPro-Pro endopeptidase", + "3.4.25.1\tProteasome endopeptidase complex", + "3.4.25.2\tHslU--HslV peptidase", + "3.5.1.1\tAsparaginase", + "3.5.1.2\tGlutaminase", + "3.5.1.3\tOmega-amidase", + "3.5.1.4\tAmidase", + "3.5.1.5\tUrease", + "3.5.1.6\tBeta-ureidopropionase", + "3.5.1.7\tUreidosuccinase", + "3.5.1.8\tFormylaspartate deformylase", + "3.5.1.9\tArylformamidase", + "3.5.1.10\tFormyltetrahydrofolate deformylase", + "3.5.1.11\tPenicillin amidase", + "3.5.1.12\tBiotinidase", + "3.5.1.13\tAryl-acylamidase", + "3.5.1.14\tN-acyl-aliphatic-L-amino acid amidohydrolase", + "3.5.1.15\tAspartoacylase", + "3.5.1.16\tAcetylornithine deacetylase", + "3.5.1.17\tAcyl-lysine deacylase", + "3.5.1.18\tSuccinyl-diaminopimelate desuccinylase", + "3.5.1.19\tNicotinamidase", + "3.5.1.20\tCitrullinase", + "3.5.1.21\tN-acetyl-beta-alanine deacetylase", + "3.5.1.22\tPantothenase", + "3.5.1.23\tCeramidase", + "3.5.1.24\tCholoylglycine hydrolase", + "3.5.1.25\tN-acetylglucosamine-6-phosphate deacetylase", + "3.5.1.26\tN(4)-(beta-N-acetylglucosaminyl)-L-asparaginase", + "3.5.1.28\tN-acetylmuramoyl-L-alanine amidase", + "3.5.1.29\t2-(acetamidomethylene)succinate hydrolase", + "3.5.1.30\t5-aminopentanamidase", + "3.5.1.31\tFormylmethionine deformylase", + "3.5.1.32\tHippurate hydrolase", + "3.5.1.33\tN-acetylglucosamine deacetylase", + "3.5.1.35\tD-glutaminase", + "3.5.1.36\tN-methyl-2-oxoglutaramate hydrolase", + "3.5.1.38\tGlutamin-(asparagin-)ase", + "3.5.1.39\tAlkylamidase", + "3.5.1.40\tAcylagmatine amidase", + "3.5.1.41\tChitin deacetylase", + "3.5.1.42\tNicotinamide-nucleotide amidase", + "3.5.1.43\tPeptidyl-glutaminase", + "3.5.1.44\tProtein-glutamine glutaminase", + "3.5.1.46\t6-aminohexanoate-oligomer exohydrolase", + "3.5.1.47\tN-acetyldiaminopimelate deacetylase", + "3.5.1.48\tAcetylspermidine deacetylase", + "3.5.1.49\tFormamidase", + "3.5.1.50\tPentanamidase", + "3.5.1.51\t4-acetamidobutyryl-CoA deacetylase", + "3.5.1.52\tPeptide-N(4)-(N-acetyl-beta-glucosaminyl)asparagine amidase", + "3.5.1.53\tN-carbamoylputrescine amidase", + "3.5.1.54\tAllophanate hydrolase", + "3.5.1.55\tLong-chain-fatty-acyl-glutamate deacylase", + "3.5.1.56\tN,N-dimethylformamidase", + "3.5.1.57\tTryptophanamidase", + "3.5.1.58\tN-benzyloxycarbonylglycine hydrolase", + "3.5.1.59\tN-carbamoylsarcosine amidase", + "3.5.1.60\tN-(long-chain-acyl)ethanolamine deacylase", + "3.5.1.61\tMimosinase", + "3.5.1.62\tAcetylputrescine deacetylase", + "3.5.1.63\t4-acetamidobutyrate deacetylase", + "3.5.1.64\tN(alpha)-benzyloxycarbonylleucine hydrolase", + "3.5.1.65\tTheanine hydrolase", + "3.5.1.66\t2-(hydroxymethyl)-3-(acetamidomethylene)succinate hydrolase", + "3.5.1.67\t4-methyleneglutaminase", + "3.5.1.68\tN-formylglutamate deformylase", + "3.5.1.69\tGlycosphingolipid deacylase", + "3.5.1.70\tAculeacin-A deacylase", + "3.5.1.71\tN-feruloylglycine deacylase", + "3.5.1.72\tD-benzoylarginine-4-nitroanilide amidase", + "3.5.1.73\tCarnitinamidase", + "3.5.1.74\tChenodeoxycholoyltaurine hydrolase", + "3.5.1.75\tUrethanase", + "3.5.1.76\tArylalkyl acylamidase", + "3.5.1.77\tN-carbamoyl-D-amino-acid hydrolase", + "3.5.1.78\tGlutathionylspermidine amidase", + "3.5.1.79\tPhthalyl amidase", + "3.5.1.81\tN-acyl-D-amino-acid deacylase", + "3.5.1.82\tN-acyl-D-glutamate deacylase", + "3.5.1.83\tN-acyl-D-aspartate deacylase", + "3.5.1.84\tBiuret amidohydrolase", + "3.5.1.85\t(S)-N-acetyl-1-phenylethylamine hydrolase", + "3.5.1.86\tMandelamide amidase", + "3.5.1.87\tN-carbamoyl-L-amino-acid hydrolase", + "3.5.1.88\tPeptide deformylase", + "3.5.1.89\tN-acetylglucosaminylphosphatidylinositol deacetylase", + "3.5.1.90\tAdenosylcobinamide hydrolase", + "3.5.1.91\tN-substituted formamide deformylase", + "3.5.1.92\tPantetheine hydrolase", + "3.5.1.93\tGlutaryl-7-aminocephalosporanic-acid acylase", + "3.5.1.94\tGamma-glutamyl-gamma-aminobutyrate hydrolase", + "3.5.1.95\tN-malonylurea hydrolase", + "3.5.1.96\tSuccinylglutamate desuccinylase", + "3.5.1.97\tAcyl-homoserine-lactone acylase", + "3.5.1.98\tHistone deacetylase", + "3.5.1.99\tFatty acid amide hydrolase", + "3.5.1.100\t(R)-amidase", + "3.5.1.101\tL-proline amide hydrolase", + "3.5.1.102\t2-amino-5-formylamino-6-ribosylaminopyrimidin-4(3H)-one 5'-monophosphate deformylase", + "3.5.1.103\tN-acetyl-1-D-myo-inositol-2-amino-2-deoxy-alpha-D-glucopyranoside deacetylase", + "3.5.1.104\tPeptidoglycan-N-acetylglucosamine deacetylase", + "3.5.1.105\tChitin disaccharide deacetylase", + "3.5.1.106\tN-formylmaleamate deformylase", + "3.5.1.107\tMaleamate amidohydrolase", + "3.5.1.108\tUDP-3-O-acyl-N-acetylglucosamine deacetylase", + "3.5.1.109\tSphingomyelin deacylase", + "3.5.1.110\tPeroxyureidoacrylate/ureidoacrylate amidohydrolase", + "3.5.1.111\t2-oxoglutaramate amidase", + "3.5.1.112\t2'-N-acetylparomamine deacetylase", + "3.5.1.113\t2'''-acetyl-6'''-hydroxyneomycin C deacetylase", + "3.5.1.114\tN-acyl-aromatic-L-amino acid amidohydrolase", + "3.5.1.115\tMycothiol S-conjugate amidase", + "3.5.1.116\tUreidoglycolate amidohydrolase", + "3.5.1.117\t6-aminohexanoate-oligomer endohydrolase", + "3.5.1.118\tGamma-glutamyl hercynylcysteine S-oxide hydrolase", + "3.5.1.119\tPup amidohydrolase", + "3.5.1.120\t2-aminomuconate deaminase (2-hydroxymuconate-forming)", + "3.5.1.121\tProtein N-terminal asparagine amidohydrolase", + "3.5.1.122\tProtein N-terminal glutamine amidohydrolase", + "3.5.1.123\tGamma-glutamylanilide hydrolase", + "3.5.1.124\tProtein deglycase", + "3.5.1.125\tN(2)-acetyl-L-2,4-diaminobutanoate deacetylase", + "3.5.1.126\tOxamate amidohydrolase", + "3.5.1.127\tJasmonoyl-L-amino acid hydrolase", + "3.5.1.n3\t4-deoxy-4-formamido-L-arabinose-phosphoundecaprenol deformylase", + "3.5.2.1\tBarbiturase", + "3.5.2.2\tDihydropyrimidinase", + "3.5.2.3\tDihydroorotase", + "3.5.2.4\tCarboxymethylhydantoinase", + "3.5.2.5\tAllantoinase", + "3.5.2.6\tBeta-lactamase", + "3.5.2.7\tImidazolonepropionase", + "3.5.2.9\t5-oxoprolinase (ATP-hydrolyzing)", + "3.5.2.10\tCreatininase", + "3.5.2.11\tL-lysine-lactamase", + "3.5.2.12\t6-aminohexanoate-cyclic-dimer hydrolase", + "3.5.2.13\t2,5-dioxopiperazine hydrolase", + "3.5.2.14\tN-methylhydantoinase (ATP-hydrolyzing)", + "3.5.2.15\tCyanuric acid amidohydrolase", + "3.5.2.16\tMaleimide hydrolase", + "3.5.2.17\tHydroxyisourate hydrolase", + "3.5.2.18\tEnamidase", + "3.5.2.19\tStreptothricin hydrolase", + "3.5.2.20\tIsatin hydrolase", + "3.5.3.1\tArginase", + "3.5.3.2\tGuanidinoacetase", + "3.5.3.3\tCreatinase", + "3.5.3.4\tAllantoicase", + "3.5.3.5\tFormimidoylaspartate deiminase", + "3.5.3.6\tArginine deiminase", + "3.5.3.7\tGuanidinobutyrase", + "3.5.3.8\tFormimidoylglutamase", + "3.5.3.9\tAllantoate deiminase", + "3.5.3.10\tD-arginase", + "3.5.3.11\tAgmatinase", + "3.5.3.12\tAgmatine deiminase", + "3.5.3.13\tFormimidoylglutamate deiminase", + "3.5.3.14\tAmidinoaspartase", + "3.5.3.15\tProtein-arginine deiminase", + "3.5.3.16\tMethylguanidinase", + "3.5.3.17\tGuanidinopropionase", + "3.5.3.18\tDimethylargininase", + "3.5.3.20\tDiguanidinobutanase", + "3.5.3.21\tMethylenediurea deaminase", + "3.5.3.22\tProclavaminate amidinohydrolase", + "3.5.3.23\tN-succinylarginine dihydrolase", + "3.5.3.24\tN(1)-aminopropylagmatine ureohydrolase", + "3.5.3.25\tN(omega)-hydroxy-L-arginine amidinohydrolase", + "3.5.3.26\t(S)-ureidoglycine aminohydrolase", + "3.5.4.1\tCytosine deaminase", + "3.5.4.2\tAdenine deaminase", + "3.5.4.3\tGuanine deaminase", + "3.5.4.4\tAdenosine deaminase", + "3.5.4.5\tCytidine deaminase", + "3.5.4.6\tAMP deaminase", + "3.5.4.7\tADP deaminase", + "3.5.4.8\tAminoimidazolase", + "3.5.4.9\tMethenyltetrahydrofolate cyclohydrolase", + "3.5.4.10\tIMP cyclohydrolase", + "3.5.4.11\tPterin deaminase", + "3.5.4.12\tdCMP deaminase", + "3.5.4.13\tdCTP deaminase", + "3.5.4.15\tGuanosine deaminase", + "3.5.4.16\tGTP cyclohydrolase I", + "3.5.4.17\tAdenosine-phosphate deaminase", + "3.5.4.18\tATP deaminase", + "3.5.4.19\tPhosphoribosyl-AMP cyclohydrolase", + "3.5.4.20\tPyrithiamine deaminase", + "3.5.4.21\tCreatinine deaminase", + "3.5.4.22\t1-pyrroline-4-hydroxy-2-carboxylate deaminase", + "3.5.4.23\tBlasticidin-S deaminase", + "3.5.4.24\tSepiapterin deaminase", + "3.5.4.25\tGTP cyclohydrolase II", + "3.5.4.26\tDiaminohydroxyphosphoribosylaminopyrimidine deaminase", + "3.5.4.27\tMethenyltetrahydromethanopterin cyclohydrolase", + "3.5.4.28\tS-adenosylhomocysteine deaminase", + "3.5.4.29\tGTP cyclohydrolase IIa", + "3.5.4.30\tdCTP deaminase (dUMP-forming)", + "3.5.4.31\tS-methyl-5'-thioadenosine deaminase", + "3.5.4.32\t8-oxoguanine deaminase", + "3.5.4.33\ttRNA(adenine(34)) deaminase", + "3.5.4.34\ttRNA(Ala)(adenine(37)) deaminase", + "3.5.4.35\ttRNA(cytosine(8)) deaminase", + "3.5.4.36\tmRNA(cytosine(6666)) deaminase", + "3.5.4.37\tDouble-stranded RNA adenine deaminase", + "3.5.4.38\tSingle-stranded DNA cytosine deaminase", + "3.5.4.39\tGTP cyclohydrolase IV", + "3.5.4.40\tAminodeoxyfutalosine deaminase", + "3.5.4.41\t5'-deoxyadenosine deaminase", + "3.5.4.42\tN-isopropylammelide isopropylaminohydrolase", + "3.5.4.43\tHydroxydechloroatrazine ethylaminohydrolase", + "3.5.4.44\tEctoine hydrolase", + "3.5.4.45\tMelamine deaminase", + "3.5.4.46\tcAMP deaminase", + "3.5.5.1\tNitrilase", + "3.5.5.2\tRicinine nitrilase", + "3.5.5.4\tCyanoalanine nitrilase", + "3.5.5.5\tArylacetonitrilase", + "3.5.5.6\tBromoxynil nitrilase", + "3.5.5.7\tAliphatic nitrilase", + "3.5.5.8\tThiocyanate hydrolase", + "3.5.99.1\tRiboflavinase", + "3.5.99.2\tAminopyrimidine aminohydrolase", + "3.5.99.5\t2-aminomuconate deaminase", + "3.5.99.6\tGlucosamine-6-phosphate deaminase", + "3.5.99.7\t1-aminocyclopropane-1-carboxylate deaminase", + "3.5.99.8\t5-nitroanthranilic acid aminohydrolase", + "3.5.99.9\t2-nitroimidazole nitrohydrolase", + "3.5.99.10\t2-iminobutanoate/2-iminopropanoate deaminase", + "3.6.1.1\tInorganic diphosphatase", + "3.6.1.2\tTrimetaphosphatase", + "3.6.1.3\tAdenosinetriphosphatase", + "3.6.1.5\tApyrase", + "3.6.1.6\tNucleoside diphosphate phosphatase", + "3.6.1.7\tAcylphosphatase", + "3.6.1.8\tATP diphosphatase", + "3.6.1.9\tNucleotide diphosphatase", + "3.6.1.10\tEndopolyphosphatase", + "3.6.1.11\tExopolyphosphatase", + "3.6.1.12\tdCTP diphosphatase", + "3.6.1.13\tADP-ribose diphosphatase", + "3.6.1.14\tAdenosine-tetraphosphatase", + "3.6.1.15\tNucleoside-triphosphate phosphatase", + "3.6.1.16\tCDP-glycerol diphosphatase", + "3.6.1.17\tBis(5'-nucleosyl)-tetraphosphatase (asymmetrical)", + "3.6.1.18\tFAD diphosphatase", + "3.6.1.20\t5'-acylphosphoadenosine hydrolase", + "3.6.1.21\tADP-sugar diphosphatase", + "3.6.1.22\tNAD(+) diphosphatase", + "3.6.1.23\tdUTP diphosphatase", + "3.6.1.24\tNucleoside phosphoacylhydrolase", + "3.6.1.25\tTriphosphatase", + "3.6.1.26\tCDP-diacylglycerol diphosphatase", + "3.6.1.27\tUndecaprenyl-diphosphate phosphatase", + "3.6.1.28\tThiamine-triphosphatase", + "3.6.1.29\tBis(5'-adenosyl)-triphosphatase", + "3.6.1.31\tPhosphoribosyl-ATP diphosphatase", + "3.6.1.39\tThymidine-triphosphatase", + "3.6.1.40\tGuanosine-5'-triphosphate,3'-diphosphate diphosphatase", + "3.6.1.41\tBis(5'-nucleosyl)-tetraphosphatase (symmetrical)", + "3.6.1.42\tGuanosine-diphosphatase", + "3.6.1.43\tDolichyldiphosphatase", + "3.6.1.44\tOligosaccharide-diphosphodolichol diphosphatase", + "3.6.1.45\tUDP-sugar diphosphatase", + "3.6.1.52\tDiphosphoinositol-polyphosphate diphosphatase", + "3.6.1.53\tMn(2+)-dependent ADP-ribose/CDP-alcohol diphosphatase", + "3.6.1.54\tUDP-2,3-diacylglucosamine diphosphatase", + "3.6.1.55\t8-oxo-dGTP diphosphatase", + "3.6.1.56\t2-hydroxy-dATP diphosphatase", + "3.6.1.57\tUDP-2,4-diacetamido-2,4,6-trideoxy-beta-L-altropyranose hydrolase", + "3.6.1.58\t8-oxo-dGDP phosphatase", + "3.6.1.59\t5'-(N(7)-methyl 5'-triphosphoguanosine)-[mRNA] diphosphatase", + "3.6.1.60\tDiadenosine hexaphosphate hydrolase (AMP-forming)", + "3.6.1.61\tDiadenosine hexaphosphate hydrolase (ATP-forming)", + "3.6.1.62\t5'-(N(7)-methylguanosine 5'-triphospho)-[mRNA] hydrolase", + "3.6.1.63\tAlpha-D-ribose 1-methylphosphonate 5-triphosphate diphosphatase", + "3.6.1.64\tInosine diphosphate phosphatase", + "3.6.1.65\t(d)CTP diphosphatase", + "3.6.1.66\tXTP/dITP diphosphatase", + "3.6.1.67\tDihydroneopterin triphosphate diphosphatase", + "3.6.1.68\tGeranyl diphosphate phosphohydrolase", + "3.6.1.n1\tD-tyrosyl-tRNA(Tyr) hydrolase", + "3.6.1.n2\tL-cysteinyl-tRNA(Pro)", + "3.6.1.n3\tL-cysteinyl-tRNA(Cys) hydrolase", + "3.6.2.1\tAdenylylsulfatase", + "3.6.2.2\tPhosphoadenylylsulfatase", + "3.6.3.1\tPhospholipid-translocating ATPase", + "3.6.3.2\tMagnesium-importing ATPase", + "3.6.3.3\tCadmium-exporting ATPase", + "3.6.3.4\tCu(2+)-exporting ATPase", + "3.6.3.5\tZinc-exporting ATPase", + "3.6.3.6\tProton-exporting ATPase", + "3.6.3.7\tSodium-exporting ATPase", + "3.6.3.8\tCalcium-transporting ATPase", + "3.6.3.9\tSodium/potassium-exchanging ATPase", + "3.6.3.10\tHydrogen/potassium-exchanging ATPase", + "3.6.3.11\tChloride-transporting ATPase", + "3.6.3.12\tPotassium-transporting ATPase", + "3.6.3.14\tH(+)-transporting two-sector ATPase", + "3.6.3.15\tSodium-transporting two-sector ATPase", + "3.6.3.16\tArsenite-transporting ATPase", + "3.6.3.17\tMonosaccharide-transporting ATPase", + "3.6.3.18\tOligosaccharide-transporting ATPase", + "3.6.3.19\tMaltose-transporting ATPase", + "3.6.3.20\tGlycerol-3-phosphate-transporting ATPase", + "3.6.3.21\tPolar-amino-acid-transporting ATPase", + "3.6.3.22\tNonpolar-amino-acid-transporting ATPase", + "3.6.3.23\tOligopeptide-transporting ATPase", + "3.6.3.24\tNickel-transporting ATPase", + "3.6.3.25\tSulfate-transporting ATPase", + "3.6.3.26\tNitrate-transporting ATPase", + "3.6.3.27\tPhosphate-transporting ATPase", + "3.6.3.28\tPhosphonate-transporting ATPase", + "3.6.3.29\tMolybdate-transporting ATPase", + "3.6.3.30\tFe(3+)-transporting ATPase", + "3.6.3.31\tPolyamine-transporting ATPase", + "3.6.3.32\tQuaternary-amine-transporting ATPase", + "3.6.3.33\tVitamin B12-transporting ATPase", + "3.6.3.34\tIron-chelate-transporting ATPase", + "3.6.3.35\tManganese-transporting ATPase", + "3.6.3.36\tTaurine-transporting ATPase", + "3.6.3.37\tGuanine-transporting ATPase", + "3.6.3.38\tCapsular-polysaccharide-transporting ATPase", + "3.6.3.39\tLipopolysaccharide-transporting ATPase", + "3.6.3.40\tTeichoic-acid-transporting ATPase", + "3.6.3.41\tHeme-transporting ATPase", + "3.6.3.42\tBeta-glucan-transporting ATPase", + "3.6.3.43\tPeptide-transporting ATPase", + "3.6.3.44\tXenobiotic-transporting ATPase", + "3.6.3.46\tCadmium-transporting ATPase", + "3.6.3.47\tFatty-acyl-CoA-transporting ATPase", + "3.6.3.48\tAlpha-factor-transporting ATPase", + "3.6.3.49\tChannel-conductance-controlling ATPase", + "3.6.3.50\tProtein-secreting ATPase", + "3.6.3.51\tMitochondrial protein-transporting ATPase", + "3.6.3.52\tChloroplast protein-transporting ATPase", + "3.6.3.53\tAg(+)-exporting ATPase", + "3.6.3.54\tCu(+) exporting ATPase", + "3.6.3.55\tTungstate-importing ATPase", + "3.6.4.1\tMyosin ATPase", + "3.6.4.2\tDynein ATPase", + "3.6.4.3\tMicrotubule-severing ATPase", + "3.6.4.4\tPlus-end-directed kinesin ATPase", + "3.6.4.5\tMinus-end-directed kinesin ATPase", + "3.6.4.6\tVesicle-fusing ATPase", + "3.6.4.7\tPeroxisome-assembly ATPase", + "3.6.4.8\tProteasome ATPase", + "3.6.4.9\tChaperonin ATPase", + "3.6.4.10\tNon-chaperonin molecular chaperone ATPase", + "3.6.4.11\tNucleoplasmin ATPase", + "3.6.4.12\tDNA helicase", + "3.6.4.13\tRNA helicase", + "3.6.5.1\tHeterotrimeric G-protein GTPase", + "3.6.5.2\tSmall monomeric GTPase", + "3.6.5.3\tProtein-synthesizing GTPase", + "3.6.5.4\tSignal-recognition-particle GTPase", + "3.6.5.5\tDynamin GTPase", + "3.6.5.6\tTubulin GTPase", + "3.6.5.n1\tElongation factor 4", + "3.7.1.1\tOxaloacetase", + "3.7.1.2\tFumarylacetoacetase", + "3.7.1.3\tKynureninase", + "3.7.1.4\tPhloretin hydrolase", + "3.7.1.5\tAcylpyruvate hydrolase", + "3.7.1.6\tAcetylpyruvate hydrolase", + "3.7.1.7\tBeta-diketone hydrolase", + "3.7.1.8\t2,6-dioxo-6-phenylhexa-3-enoate hydrolase", + "3.7.1.9\t2-hydroxymuconate-6-semialdehyde hydrolase", + "3.7.1.10\tCyclohexane-1,3-dione hydrolase", + "3.7.1.11\tCyclohexane-1,2-dione hydrolase", + "3.7.1.12\tCobalt-precorrin 5A hydrolase", + "3.7.1.13\t2-hydroxy-6-oxo-6-(2-aminophenyl)hexa-2,4-dienoate hydrolase", + "3.7.1.14\t2-hydroxy-6-oxonona-2,4-dienedioate hydrolase", + "3.7.1.17\t4,5-9,10-diseco-3-hydroxy-5,9,17-trioxoandrosta-1(10),2-diene-4-oate hydrolase", + "3.7.1.18\t6-oxocamphor hydrolase", + "3.7.1.19\t2,6-dihydroxypseudooxynicotine hydrolase", + "3.7.1.20\t3-fumarylpyruvate hydrolase", + "3.7.1.21\t6-oxocyclohex-1-ene-1-carbonyl-CoA hydratase", + "3.7.1.22\t3D-(3,5/4)-trihydroxycyclohexane-1,2-dione acylhydrolase (decyclizing)", + "3.7.1.23\tMaleylpyruvate hydrolase", + "3.8.1.1\tAlkylhalidase", + "3.8.1.2\t(S)-2-haloacid dehalogenase", + "3.8.1.3\tHaloacetate dehalogenase", + "3.8.1.5\tHaloalkane dehalogenase", + "3.8.1.6\t4-chlorobenzoate dehalogenase", + "3.8.1.7\t4-chlorobenzoyl-CoA dehalogenase", + "3.8.1.8\tAtrazine chlorohydrolase", + "3.8.1.9\t(R)-2-haloacid dehalogenase", + "3.8.1.10\t2-haloacid dehalogenase (configuration-inverting)", + "3.8.1.11\t2-haloacid dehalogenase (configuration-retaining)", + "3.9.1.1\tPhosphoamidase", + "3.9.1.2\tProtein arginine phosphatase", + "3.9.1.3\tPhosphohistidine phosphatase", + "3.10.1.1\tN-sulfoglucosamine sulfohydrolase", + "3.10.1.2\tCyclamate sulfohydrolase", + "3.11.1.1\tPhosphonoacetaldehyde hydrolase", + "3.11.1.2\tPhosphonoacetate hydrolase", + "3.11.1.3\tPhosphonopyruvate hydrolase", + "3.12.1.1\tTrithionate hydrolase", + "3.13.1.1\tUDP-sulfoquinovose synthase", + "3.13.1.3\t2'-hydroxybiphenyl-2-sulfinate desulfinase", + "3.13.1.4\t3-sulfinopropanoyl-CoA desulfinase", + "4.1.1.1\tPyruvate decarboxylase", + "4.1.1.2\tOxalate decarboxylase", + "4.1.1.3\tOxaloacetate decarboxylase", + "4.1.1.4\tAcetoacetate decarboxylase", + "4.1.1.5\tAcetolactate decarboxylase", + "4.1.1.6\tAconitate decarboxylase", + "4.1.1.7\tBenzoylformate decarboxylase", + "4.1.1.8\tOxalyl-CoA decarboxylase", + "4.1.1.9\tMalonyl-CoA decarboxylase", + "4.1.1.11\tAspartate 1-decarboxylase", + "4.1.1.12\tAspartate 4-decarboxylase", + "4.1.1.14\tValine decarboxylase", + "4.1.1.15\tGlutamate decarboxylase", + "4.1.1.16\tHydroxyglutamate decarboxylase", + "4.1.1.17\tOrnithine decarboxylase", + "4.1.1.18\tLysine decarboxylase", + "4.1.1.19\tArginine decarboxylase", + "4.1.1.20\tDiaminopimelate decarboxylase", + "4.1.1.21\tPhosphoribosylaminoimidazole carboxylase", + "4.1.1.22\tHistidine decarboxylase", + "4.1.1.23\tOrotidine-5'-phosphate decarboxylase", + "4.1.1.24\tAminobenzoate decarboxylase", + "4.1.1.25\tTyrosine decarboxylase", + "4.1.1.28\tAromatic-L-amino-acid decarboxylase", + "4.1.1.29\tSulfinoalanine decarboxylase", + "4.1.1.30\tPantothenoylcysteine decarboxylase", + "4.1.1.31\tPhosphoenolpyruvate carboxylase", + "4.1.1.32\tPhosphoenolpyruvate carboxykinase (GTP)", + "4.1.1.33\tDiphosphomevalonate decarboxylase", + "4.1.1.34\tDehydro-L-gulonate decarboxylase", + "4.1.1.35\tUDP-glucuronate decarboxylase", + "4.1.1.36\tPhosphopantothenoylcysteine decarboxylase", + "4.1.1.37\tUroporphyrinogen decarboxylase", + "4.1.1.38\tPhosphoenolpyruvate carboxykinase (diphosphate)", + "4.1.1.39\tRibulose-bisphosphate carboxylase", + "4.1.1.40\tHydroxypyruvate decarboxylase", + "4.1.1.41\tMethylmalonyl-CoA decarboxylase", + "4.1.1.42\tCarnitine decarboxylase", + "4.1.1.43\tPhenylpyruvate decarboxylase", + "4.1.1.44\t4-carboxymuconolactone decarboxylase", + "4.1.1.45\tAminocarboxymuconate-semialdehyde decarboxylase", + "4.1.1.46\to-pyrocatechuate decarboxylase", + "4.1.1.47\tTartronate-semialdehyde synthase", + "4.1.1.48\tIndole-3-glycerol-phosphate synthase", + "4.1.1.49\tPhosphoenolpyruvate carboxykinase (ATP)", + "4.1.1.50\tAdenosylmethionine decarboxylase", + "4.1.1.51\t3-hydroxy-2-methylpyridine-4,5-dicarboxylate 4-decarboxylase", + "4.1.1.52\t6-methylsalicylate decarboxylase", + "4.1.1.53\tPhenylalanine decarboxylase", + "4.1.1.54\tDihydroxyfumarate decarboxylase", + "4.1.1.55\t4,5-dihydroxyphthalate decarboxylase", + "4.1.1.56\t3-oxolaurate decarboxylase", + "4.1.1.57\tMethionine decarboxylase", + "4.1.1.58\tOrsellinate decarboxylase", + "4.1.1.59\tGallate decarboxylase", + "4.1.1.60\tStipitatonate decarboxylase", + "4.1.1.61\t4-hydroxybenzoate decarboxylase", + "4.1.1.62\tGentisate decarboxylase", + "4.1.1.63\tProtocatechuate decarboxylase", + "4.1.1.64\t2,2-dialkylglycine decarboxylase (pyruvate)", + "4.1.1.65\tPhosphatidylserine decarboxylase", + "4.1.1.66\tUracil-5-carboxylate decarboxylase", + "4.1.1.67\tUDP-galacturonate decarboxylase", + "4.1.1.68\t5-oxopent-3-ene-1,2,5-tricarboxylate decarboxylase", + "4.1.1.69\t3,4-dihydroxyphthalate decarboxylase", + "4.1.1.70\tGlutaconyl-CoA decarboxylase", + "4.1.1.71\t2-oxoglutarate decarboxylase", + "4.1.1.72\tBranched-chain-2-oxoacid decarboxylase", + "4.1.1.73\tTartrate decarboxylase", + "4.1.1.74\tIndolepyruvate decarboxylase", + "4.1.1.75\t5-guanidino-2-oxopentanoate decarboxylase", + "4.1.1.76\tArylmalonate decarboxylase", + "4.1.1.77\t2-oxo-3-hexenedioate decarboxylase", + "4.1.1.78\tAcetylenedicarboxylate decarboxylase", + "4.1.1.79\tSulfopyruvate decarboxylase", + "4.1.1.80\t4-hydroxyphenylpyruvate decarboxylase", + "4.1.1.81\tThreonine-phosphate decarboxylase", + "4.1.1.82\tPhosphonopyruvate decarboxylase", + "4.1.1.83\t4-hydroxyphenylacetate decarboxylase", + "4.1.1.84\tD-dopachrome decarboxylase", + "4.1.1.85\t3-dehydro-L-gulonate-6-phosphate decarboxylase", + "4.1.1.86\tDiaminobutyrate decarboxylase", + "4.1.1.87\tMalonyl-S-ACP decarboxylase", + "4.1.1.88\tBiotin-independent malonate decarboxylase", + "4.1.1.89\tBiotin-dependent malonate decarboxylase", + "4.1.1.90\tPeptidyl-glutamate 4-carboxylase", + "4.1.1.91\tSalicylate decarboxylase", + "4.1.1.92\tIndole-3-carboxylate decarboxylase", + "4.1.1.93\tPyrrole-2-carboxylate decarboxylase", + "4.1.1.94\tEthylmalonyl-CoA decarboxylase", + "4.1.1.95\tL-glutamyl-[BtrI acyl-carrier protein] decarboxylase", + "4.1.1.96\tCarboxynorspermidine decarboxylase", + "4.1.1.97\t2-oxo-4-hydroxy-4-carboxy-5-ureidoimidazoline decarboxylase", + "4.1.1.98\t4-hydroxy-3-polyprenylbenzoate decarboxylase", + "4.1.1.99\tPhosphomevalonate decarboxylase", + "4.1.1.100\tPrephenate decarboxylase", + "4.1.1.101\tMalolactic enzyme", + "4.1.1.102\tPhenacrylate decarboxylase", + "4.1.1.103\tGamma-resorcylate decarboxylase", + "4.1.2.2\tKetotetrose-phosphate aldolase", + "4.1.2.4\tDeoxyribose-phosphate aldolase", + "4.1.2.5\tL-threonine aldolase", + "4.1.2.8\tIndole-3-glycerol-phosphate lyase", + "4.1.2.9\tPhosphoketolase", + "4.1.2.10\t(R)-mandelonitrile lyase", + "4.1.2.11\tHydroxymandelonitrile lyase", + "4.1.2.12\t2-dehydropantoate aldolase", + "4.1.2.13\tFructose-bisphosphate aldolase", + "4.1.2.14\t2-dehydro-3-deoxy-phosphogluconate aldolase", + "4.1.2.17\tL-fuculose-phosphate aldolase", + "4.1.2.18\t2-dehydro-3-deoxy-L-pentonate aldolase", + "4.1.2.19\tRhamnulose-1-phosphate aldolase", + "4.1.2.20\t2-dehydro-3-deoxyglucarate aldolase", + "4.1.2.21\t2-dehydro-3-deoxy-6-phosphogalactonate aldolase", + "4.1.2.22\tFructose-6-phosphate phosphoketolase", + "4.1.2.23\t3-deoxy-D-manno-octulosonate aldolase", + "4.1.2.24\tDimethylaniline-N-oxide aldolase", + "4.1.2.25\tDihydroneopterin aldolase", + "4.1.2.26\tPhenylserine aldolase", + "4.1.2.27\tSphinganine-1-phosphate aldolase", + "4.1.2.28\t2-dehydro-3-deoxy-D-pentonate aldolase", + "4.1.2.29\t5-dehydro-2-deoxyphosphogluconate aldolase", + "4.1.2.32\tTrimethylamine-oxide aldolase", + "4.1.2.33\tFucosterol-epoxide lyase", + "4.1.2.34\t4-(2-carboxyphenyl)-2-oxobut-3-enoate aldolase", + "4.1.2.35\tPropioin synthase", + "4.1.2.36\tLactate aldolase", + "4.1.2.38\tBenzoin aldolase", + "4.1.2.40\tTagatose-bisphosphate aldolase", + "4.1.2.41\tVanillin synthase", + "4.1.2.42\tD-threonine aldolase", + "4.1.2.43\t3-hexulose-6-phosphate synthase", + "4.1.2.44\t2,3-epoxybenzoyl-CoA dihydrolase", + "4.1.2.45\tTrans-o-hydroxybenzylidenepyruvate hydratase-aldolase", + "4.1.2.46\tAliphatic (R)-hydroxynitrile lyase", + "4.1.2.47\t(S)-hydroxynitrile lyase", + "4.1.2.48\tLow-specificity L-threonine aldolase", + "4.1.2.49\tL-allo-threonine aldolase", + "4.1.2.50\t6-carboxytetrahydropterin synthase", + "4.1.2.51\t2-dehydro-3-deoxy-D-gluconate aldolase", + "4.1.2.52\t4-hydroxy-2-oxoheptanedioate aldolase", + "4.1.2.53\t2-keto-3-deoxy-L-rhamnonate aldolase", + "4.1.2.54\tL-threo-3-deoxy-hexylosonate aldolase", + "4.1.2.55\t2-dehydro-3-deoxy-phosphogluconate/2-dehydro-3-deoxy-6-phosphogalactonate aldolase", + "4.1.2.56\t2-amino-4,5-dihydroxy-6-oxo-7-(phosphonooxy)heptanoate synthase", + "4.1.2.57\tSulfofructosephosphate aldolase", + "4.1.2.58\t2-dehydro-3,6-dideoxy-6-sulfogluconate aldolase", + "4.1.2.n2\t2-hydroxyphytanoyl-CoA lyase", + "4.1.3.1\tIsocitrate lyase", + "4.1.3.3\tN-acetylneuraminate lyase", + "4.1.3.4\tHydroxymethylglutaryl-CoA lyase", + "4.1.3.6\tCitrate (pro-3S)-lyase", + "4.1.3.13\tOxalomalate lyase", + "4.1.3.14\tL-erythro-3-hydroxyaspartate aldolase", + "4.1.3.16\t4-hydroxy-2-oxoglutarate aldolase", + "4.1.3.17\t4-hydroxy-4-methyl-2-oxoglutarate aldolase", + "4.1.3.22\tCitramalate lyase", + "4.1.3.24\tMalyl-CoA lyase", + "4.1.3.25\t(S)-citramalyl-CoA lyase", + "4.1.3.26\t3-hydroxy-3-isohexenylglutaryl-CoA lyase", + "4.1.3.27\tAnthranilate synthase", + "4.1.3.30\tMethylisocitrate lyase", + "4.1.3.32\t2,3-dimethylmalate lyase", + "4.1.3.34\tCitryl-CoA lyase", + "4.1.3.35\t(1-hydroxycyclohexan-1-yl)acetyl-CoA lyase", + "4.1.3.36\t1,4-dihydroxy-2-naphthoyl-CoA synthase", + "4.1.3.38\tAminodeoxychorismate lyase", + "4.1.3.39\t4-hydroxy-2-oxovalerate aldolase", + "4.1.3.40\tChorismate lyase", + "4.1.3.41\t3-hydroxy-D-aspartate aldolase", + "4.1.3.42\t(4S)-4-hydroxy-2-oxoglutarate aldolase", + "4.1.3.43\t4-hydroxy-2-oxohexanoate aldolase", + "4.1.3.44\ttRNA 4-demethylwyosine synthase (AdoMet-dependent)", + "4.1.3.45\t3-hydroxybenzoate synthase", + "4.1.3.46\t(R)-citramalyl-CoA lyase", + "4.1.99.1\tTryptophanase", + "4.1.99.2\tTyrosine phenol-lyase", + "4.1.99.3\tDeoxyribodipyrimidine photo-lyase", + "4.1.99.5\tAldehyde oxygenase (deformylating)", + "4.1.99.11\tBenzylsuccinate synthase", + "4.1.99.12\t3,4-dihydroxy-2-butanone-4-phosphate synthase", + "4.1.99.13\t(6-4)DNA photolyase", + "4.1.99.14\tSpore photoproduct lyase", + "4.1.99.16\tGeosmin synthase", + "4.1.99.17\tPhosphomethylpyrimidine synthase", + "4.1.99.19\t2-iminoacetate synthase", + "4.1.99.20\t3-amino-4-hydroxybenzoate synthase", + "4.1.99.22\tGTP 3',8-cyclase", + "4.2.1.1\tCarbonic anhydrase", + "4.2.1.2\tFumarate hydratase", + "4.2.1.3\tAconitate hydratase", + "4.2.1.5\tArabinonate dehydratase", + "4.2.1.6\tGalactonate dehydratase", + "4.2.1.7\tAltronate dehydratase", + "4.2.1.8\tMannonate dehydratase", + "4.2.1.9\tDihydroxy-acid dehydratase", + "4.2.1.10\t3-dehydroquinate dehydratase", + "4.2.1.11\tPhosphopyruvate hydratase", + "4.2.1.12\tPhosphogluconate dehydratase", + "4.2.1.17\tEnoyl-CoA hydratase", + "4.2.1.18\tMethylglutaconyl-CoA hydratase", + "4.2.1.19\tImidazoleglycerol-phosphate dehydratase", + "4.2.1.20\tTryptophan synthase", + "4.2.1.22\tCystathionine beta-synthase", + "4.2.1.24\tPorphobilinogen synthase", + "4.2.1.25\tL-arabinonate dehydratase", + "4.2.1.27\tAcetylenecarboxylate hydratase", + "4.2.1.28\tPropanediol dehydratase", + "4.2.1.30\tGlycerol dehydratase", + "4.2.1.31\tMaleate hydratase", + "4.2.1.32\tL(+)-tartrate dehydratase", + "4.2.1.33\t3-isopropylmalate dehydratase", + "4.2.1.34\t(S)-2-methylmalate dehydratase", + "4.2.1.35\t(R)-2-methylmalate dehydratase", + "4.2.1.36\tHomoaconitate hydratase", + "4.2.1.39\tGluconate dehydratase", + "4.2.1.40\tGlucarate dehydratase", + "4.2.1.41\t5-dehydro-4-deoxyglucarate dehydratase", + "4.2.1.42\tGalactarate dehydratase", + "4.2.1.43\t2-dehydro-3-deoxy-L-arabinonate dehydratase", + "4.2.1.44\tMyo-inosose-2 dehydratase", + "4.2.1.45\tCDP-glucose 4,6-dehydratase", + "4.2.1.46\tdTDP-glucose 4,6-dehydratase", + "4.2.1.47\tGDP-mannose 4,6-dehydratase", + "4.2.1.48\tD-glutamate cyclase", + "4.2.1.49\tUrocanate hydratase", + "4.2.1.50\tPyrazolylalanine synthase", + "4.2.1.51\tPrephenate dehydratase", + "4.2.1.53\tOleate hydratase", + "4.2.1.54\tLactoyl-CoA dehydratase", + "4.2.1.55\t3-hydroxybutyryl-CoA dehydratase", + "4.2.1.56\tItaconyl-CoA hydratase", + "4.2.1.57\tIsohexenylglutaconyl-CoA hydratase", + "4.2.1.59\t3-hydroxyacyl-[acyl-carrier-protein] dehydratase", + "4.2.1.62\t5-alpha-hydroxysteroid dehydratase", + "4.2.1.65\t3-cyanoalanine hydratase", + "4.2.1.66\tCyanide hydratase", + "4.2.1.67\tD-fuconate dehydratase", + "4.2.1.68\tL-fuconate dehydratase", + "4.2.1.69\tCyanamide hydratase", + "4.2.1.70\tPseudouridylate synthase", + "4.2.1.73\tProtoaphin-aglucone dehydratase (cyclizing)", + "4.2.1.74\tLong-chain-enoyl-CoA hydratase", + "4.2.1.75\tUroporphyrinogen-III synthase", + "4.2.1.76\tUDP-glucose 4,6-dehydratase", + "4.2.1.77\tTrans-L-3-hydroxyproline dehydratase", + "4.2.1.78\t(S)-norcoclaurine synthase", + "4.2.1.79\t2-methylcitrate dehydratase", + "4.2.1.80\t2-oxopent-4-enoate hydratase", + "4.2.1.81\tD(-)-tartrate dehydratase", + "4.2.1.82\tXylonate dehydratase", + "4.2.1.83\t4-oxalmesaconate hydratase", + "4.2.1.84\tNitrile hydratase", + "4.2.1.85\tDimethylmaleate hydratase", + "4.2.1.87\tOctopamine dehydratase", + "4.2.1.88\t(R)-synephrine", + "4.2.1.90\tL-rhamnonate dehydratase", + "4.2.1.91\tArogenate dehydratase", + "4.2.1.92\tHydroperoxide dehydratase", + "4.2.1.93\tATP-dependent NAD(P)H-hydrate dehydratase", + "4.2.1.94\tScytalone dehydratase", + "4.2.1.95\tKievitone hydratase", + "4.2.1.96\t4a-hydroxytetrahydrobiopterin dehydratase", + "4.2.1.97\tPhaseollidin hydratase", + "4.2.1.98\t16-alpha-hydroxyprogesterone dehydratase", + "4.2.1.99\t2-methylisocitrate dehydratase", + "4.2.1.100\tCyclohexa-1,5-dienecarbonyl-CoA hydratase", + "4.2.1.101\tTrans-feruloyl-CoA hydratase", + "4.2.1.103\tCyclohexyl-isocyanide hydratase", + "4.2.1.104\tCyanase", + "4.2.1.105\t2-hydroxyisoflavanone dehydratase", + "4.2.1.106\tBile-acid 7-alpha-dehydratase", + "4.2.1.107\t3-alpha,7-alpha,12-alpha-trihydroxy-5-beta-cholest-24-enoyl-CoA hydratase", + "4.2.1.108\tEctoine synthase", + "4.2.1.109\tMethylthioribulose 1-phosphate dehydratase", + "4.2.1.110\tAldos-2-ulose dehydratase", + "4.2.1.111\t1,5-anhydro-D-fructose dehydratase", + "4.2.1.112\tAcetylene hydratase", + "4.2.1.113\to-succinylbenzoate synthase", + "4.2.1.114\tMethanogen homoaconitase", + "4.2.1.115\tUDP-N-acetylglucosamine 4,6-dehydratase (inverting)", + "4.2.1.116\t3-hydroxypropionyl-CoA dehydratase", + "4.2.1.117\t2-methylcitrate dehydratase (2-methyl-trans-aconitate forming)", + "4.2.1.118\t3-dehydroshikimate dehydratase", + "4.2.1.119\tEnoyl-CoA hydratase 2", + "4.2.1.120\t4-hydroxybutanoyl-CoA dehydratase", + "4.2.1.121\tColneleate synthase", + "4.2.1.122\tTryptophan synthase (indole-salvaging)", + "4.2.1.123\tTetrahymanol synthase", + "4.2.1.124\tArabidiol synthase", + "4.2.1.125\tDammarenediol II synthase", + "4.2.1.126\tN-acetylmuramic acid 6-phosphate etherase", + "4.2.1.127\tLinalool dehydratase", + "4.2.1.128\tLupan-3-beta,20-diol synthase", + "4.2.1.129\tSqualene--hopanol cyclase", + "4.2.1.130\tD-lactate dehydratase", + "4.2.1.131\tCarotenoid 1,2-hydratase", + "4.2.1.132\t2-hydroxyhexa-2,4-dienoate hydratase", + "4.2.1.133\tCopal-8-ol diphosphate hydratase", + "4.2.1.134\tVery-long-chain (3R)-3-hydroxyacyl-CoA dehydratase", + "4.2.1.135\tUDP-N-acetylglucosamine 4,6-dehydratase (configuration-retaining)", + "4.2.1.136\tADP-dependent NAD(P)H-hydrate dehydratase", + "4.2.1.137\tSporulenol synthase", + "4.2.1.138\t(+)-caryolan-1-ol synthase", + "4.2.1.139\tMedicarpin synthase", + "4.2.1.140\tGluconate/galactonate dehydratase", + "4.2.1.141\t2-dehydro-3-deoxy-D-arabinonate dehydratase", + "4.2.1.142\t5'-oxoaverantin cyclase", + "4.2.1.143\tVersicolorin B synthase", + "4.2.1.144\t3-amino-5-hydroxybenzoate synthase", + "4.2.1.145\tCapreomycidine synthase", + "4.2.1.146\tL-galactonate dehydratase", + "4.2.1.147\t5,6,7,8-tetrahydromethanopterin hydro-lyase", + "4.2.1.148\t2-methylfumaryl-CoA hydratase", + "4.2.1.149\tCrotonobetainyl-CoA hydratase", + "4.2.1.150\tShort-chain-enoyl-CoA hydratase", + "4.2.1.151\tChorismate dehydratase", + "4.2.1.152\tHydroperoxy icosatetraenoate dehydratase", + "4.2.1.153\t3-methylfumaryl-CoA hydratase", + "4.2.1.154\tTetracenomycin F2 cyclase", + "4.2.1.155\tMethylthioacryloyl-CoA hydratase", + "4.2.1.156\tL-talarate dehydratase", + "4.2.1.157\t(R)-2-hydroxyisocaproyl-CoA dehydratase", + "4.2.1.158\tGalactarate dehydratase (D-threo-forming)", + "4.2.1.159\tdTDP-4-dehydro-6-deoxy-alpha-D-glucopyranose 2,3-dehydratase", + "4.2.1.160\t2,5-diamino-6-(5-phospho-D-ribosylamino)pyrimidin-4(3H)-one isomerase/dehydratase", + "4.2.1.161\tBisanhydrobacterioruberin hydratase", + "4.2.1.162\t6-deoxy-6-sulfo-D-gluconate dehydratase", + "4.2.1.163\t2-oxo-hept-4-ene-1,7-dioate hydratase", + "4.2.1.164\tdTDP-4-dehydro-2,6-dideoxy-D-glucose 3-dehydratase", + "4.2.1.165\tChlorophyllide a 3(1)-hydratase", + "4.2.1.166\tPhosphinomethylmalate isomerase", + "4.2.1.167\t(R)-2-hydroxyglutaryl-CoA dehydratase", + "4.2.1.168\tGDP-4-dehydro-6-deoxy-alpha-D-mannose 3-dehydratase", + "4.2.1.169\t3-vinylbacteriochlorophyllide d 3(1)-hydratase", + "4.2.1.170\t2-(omega-methylthio)alkylmalate dehydratase", + "4.2.1.171\tCis-l-3-hydroxyproline dehydratase", + "4.2.2.1\tHyaluronate lyase", + "4.2.2.2\tPectate lyase", + "4.2.2.3\tMannuronate-specific alginate lyase", + "4.2.2.5\tChondroitin AC lyase", + "4.2.2.6\tOligogalacturonide lyase", + "4.2.2.7\tHeparin lyase", + "4.2.2.8\tHeparin-sulfate lyase", + "4.2.2.9\tPectate disaccharide-lyase", + "4.2.2.10\tPectin lyase", + "4.2.2.11\tGuluronate-specific alginate lyase", + "4.2.2.12\tXanthan lyase", + "4.2.2.13\tExo-(1->4)-alpha-D-glucan lyase", + "4.2.2.14\tGlucuronan lyase", + "4.2.2.15\tAnhydrosialidase", + "4.2.2.16\tLevan fructotransferase (DFA-IV-forming)", + "4.2.2.17\tInulin fructotransferase (DFA-I-forming)", + "4.2.2.18\tInulin fructotransferase (DFA-III-forming)", + "4.2.2.19\tChondroitin B lyase", + "4.2.2.20\tChondroitin-sulfate-ABC endolyase", + "4.2.2.21\tChondroitin-sulfate-ABC exolyase", + "4.2.2.22\tPectate trisaccharide-lyase", + "4.2.2.23\tRhamnogalacturonan endolyase", + "4.2.2.24\tRhamnogalacturonan exolyase", + "4.2.2.25\tGellan lyase", + "4.2.2.26\tOligo-alginate lyase", + "4.2.2.n1\tPeptidoglycan lytic exotransglycosylase", + "4.2.2.n2\tPeptidoglycan lytic endotransglycosylase", + "4.2.3.1\tThreonine synthase", + "4.2.3.2\tEthanolamine-phosphate phospho-lyase", + "4.2.3.3\tMethylglyoxal synthase", + "4.2.3.4\t3-dehydroquinate synthase", + "4.2.3.5\tChorismate synthase", + "4.2.3.6\tTrichodiene synthase", + "4.2.3.7\tPentalenene synthase", + "4.2.3.8\tCasbene synthase", + "4.2.3.9\tAristolochene synthase", + "4.2.3.10\t(-)-endo-fenchol synthase", + "4.2.3.11\tSabinene-hydrate synthase", + "4.2.3.12\t6-pyruvoyltetrahydropterin synthase", + "4.2.3.13\t(+)-delta-cadinene synthase", + "4.2.3.15\tMyrcene synthase", + "4.2.3.16\t(4S)-limonene synthase", + "4.2.3.17\tTaxadiene synthase", + "4.2.3.18\tAbieta-7,13-diene synthase", + "4.2.3.19\tEnt-kaurene synthase", + "4.2.3.20\t(R)-limonene synthase", + "4.2.3.21\tVetispiradiene synthase", + "4.2.3.22\tGermacradienol synthase", + "4.2.3.23\tGermacrene-A synthase", + "4.2.3.24\tAmorpha-4,11-diene synthase", + "4.2.3.25\tS-linalool synthase", + "4.2.3.26\tR-linalool synthase", + "4.2.3.27\tIsoprene synthase", + "4.2.3.28\tEnt-cassa-12,15-diene synthase", + "4.2.3.29\tEnt-sandaracopimaradiene synthase", + "4.2.3.30\tEnt-pimara-8(14),15-diene synthase", + "4.2.3.31\tEnt-pimara-9(11),15-diene synthase", + "4.2.3.32\tLevopimaradiene synthase", + "4.2.3.33\tStemar-13-ene synthase", + "4.2.3.34\tStemod-13(17)-ene synthase", + "4.2.3.35\tSyn-pimara-7,15-diene synthase", + "4.2.3.36\tTerpentetriene synthase", + "4.2.3.37\tEpi-isozizaene synthase", + "4.2.3.38\tAlpha-bisabolene synthase", + "4.2.3.39\tEpi-cedrol synthase", + "4.2.3.40\t(Z)-gamma-bisabolene synthase", + "4.2.3.41\tElisabethatriene synthase", + "4.2.3.42\tAphidicolan-16-beta-ol synthase", + "4.2.3.43\tFusicocca-2,10(14)-diene synthase", + "4.2.3.44\tIsopimara-7,15-diene synthase", + "4.2.3.45\tPhyllocladan-16-alpha-ol synthase", + "4.2.3.46\tAlpha-farnesene synthase", + "4.2.3.47\tBeta-farnesene synthase", + "4.2.3.48\t(3S,6E)-nerolidol synthase", + "4.2.3.49\t(3R,6E)-nerolidol synthase", + "4.2.3.50\t(+)-alpha-santalene synthase ((2Z,6Z)-farnesyl diphosphate cyclizing)", + "4.2.3.51\tBeta-phellandrene synthase (neryl-diphosphate-cyclizing)", + "4.2.3.52\t(4S)-beta-phellandrene synthase (geranyl-diphosphate-cyclizing)", + "4.2.3.53\t(+)-endo-beta-bergamotene synthase ((2Z,6Z)-farnesyl diphosphate cyclizing)", + "4.2.3.54\t(-)-endo-alpha-bergamotene synthase ((2Z,6Z)-farnesyl diphosphate cyclizing)", + "4.2.3.55\t(S)-beta-bisabolene synthase", + "4.2.3.56\tGamma-humulene synthase", + "4.2.3.57\t(-)-beta-caryophyllene synthase", + "4.2.3.58\tLongifolene synthase", + "4.2.3.59\t(E)-gamma-bisabolene synthase", + "4.2.3.60\tGermacrene C synthase", + "4.2.3.61\t5-epiaristolochene synthase", + "4.2.3.62\t(-)-gamma-cadinene synthase ((2Z,6E)-farnesyl diphosphate cyclizing)", + "4.2.3.63\t(+)-cubenene synthase", + "4.2.3.64\t(+)-epicubenol synthase", + "4.2.3.65\tZingiberene synthase", + "4.2.3.66\tBeta-selinene cyclase", + "4.2.3.67\tCis-muuroladiene synthase", + "4.2.3.68\tBeta-eudesmol synthase", + "4.2.3.69\t(+)-alpha-barbatene synthase", + "4.2.3.70\tPatchoulol synthase", + "4.2.3.71\t(E,E)-germacrene B synthase", + "4.2.3.72\tAlpha-gurjunene synthase", + "4.2.3.73\tValencene synthase", + "4.2.3.74\tPresilphiperfolanol synthase", + "4.2.3.75\t(-)-germacrene D synthase", + "4.2.3.76\t(+)-delta-selinene synthase", + "4.2.3.77\t(+)-germacrene D synthase", + "4.2.3.78\tBeta-chamigrene synthase", + "4.2.3.79\tThujopsene synthase", + "4.2.3.80\tAlpha-longipinene synthase", + "4.2.3.81\tExo-alpha-bergamotene synthase", + "4.2.3.82\tAlpha-santalene synthase", + "4.2.3.83\tBeta-santalene synthase", + "4.2.3.84\t10-epi-gamma-eudesmol synthase", + "4.2.3.85\tAlpha-eudesmol synthase", + "4.2.3.86\t7-epi-alpha-selinene synthase", + "4.2.3.87\tAlpha-guaiene synthase", + "4.2.3.88\tViridiflorene synthase", + "4.2.3.89\t(+)-beta-caryophyllene synthase", + "4.2.3.90\t5-epi-alpha-selinene synthase", + "4.2.3.91\tCubebol synthase", + "4.2.3.92\t(+)-gamma-cadinene synthase", + "4.2.3.93\tDelta-guaiene synthase", + "4.2.3.94\tGamma-curcumene synthase", + "4.2.3.95\t(-)-alpha-cuprenene synthase", + "4.2.3.96\tAvermitilol synthase", + "4.2.3.97\t(-)-delta-cadinene synthase", + "4.2.3.98\t(+)-T-muurolol synthase", + "4.2.3.99\tLabdatriene synthase", + "4.2.3.100\tBicyclogermacrene synthase", + "4.2.3.101\t7-epi-sesquithujene synthase", + "4.2.3.102\tSesquithujene synthase", + "4.2.3.103\tEnt-isokaurene synthase", + "4.2.3.104\tAlpha-humulene synthase", + "4.2.3.105\tTricyclene synthase", + "4.2.3.106\t(E)-beta-ocimene synthase", + "4.2.3.107\t(+)-car-3-ene synthase", + "4.2.3.108\t1,8-cineole synthase", + "4.2.3.109\t(-)-sabinene synthase", + "4.2.3.110\t(+)-sabinene synthase", + "4.2.3.111\t(-)-alpha-terpineol synthase", + "4.2.3.112\t(+)-alpha-terpineol synthase", + "4.2.3.113\tTerpinolene synthase", + "4.2.3.114\tGamma-terpinene synthase", + "4.2.3.115\tAlpha-terpinene synthase", + "4.2.3.116\t(+)-camphene synthase", + "4.2.3.117\t(-)-camphene synthase", + "4.2.3.118\t2-methylisoborneol synthase", + "4.2.3.119\t(-)-alpha-pinene synthase", + "4.2.3.120\t(-)-beta-pinene synthase", + "4.2.3.121\t(+)-alpha-pinene synthase", + "4.2.3.122\t(+)-beta-pinene synthase", + "4.2.3.123\tBeta-sesquiphellandrene synthase", + "4.2.3.124\t2-deoxy-scyllo-inosose synthase", + "4.2.3.125\tAlpha-muurolene synthase", + "4.2.3.126\tGamma-muurolene synthase", + "4.2.3.127\tBeta-copaene synthase", + "4.2.3.128\tBeta-cubebene synthase", + "4.2.3.129\t(+)-sativene synthase", + "4.2.3.130\tTetraprenyl-beta-curcumene synthase", + "4.2.3.131\tMiltiradiene synthase", + "4.2.3.132\tNeoabietadiene synthase", + "4.2.3.133\tAlpha-copaene synthase", + "4.2.3.134\t5-phosphonooxy-L-lysine phospho-lyase", + "4.2.3.135\tDelta(6)-protoilludene synthase", + "4.2.3.136\tAlpha-isocomene synthase", + "4.2.3.137\t(E)-2-epi-beta-caryophyllene synthase", + "4.2.3.138\t(+)-epi-alpha-bisabolol synthase", + "4.2.3.139\tValerena-4,7(11)-diene synthase", + "4.2.3.140\tCis-abienol synthase", + "4.2.3.141\tSclareol synthase", + "4.2.3.142\t7-epizingiberene synthase ((2Z,6Z)-farnesyl diphosphate cyclizing)", + "4.2.3.143\tKunzeaol synthase", + "4.2.3.144\tGeranyllinalool synthase", + "4.2.3.145\tOphiobolin F synthase", + "4.2.3.146\tCyclooctat-9-en-7-ol synthase", + "4.2.3.147\tPimaradiene synthase", + "4.2.3.148\tCembrene C synthase", + "4.2.3.149\tNephthenol synthase", + "4.2.3.150\tCembrene A synthase", + "4.2.3.151\tPentamethylcyclopentadecatrienol synthase", + "4.2.3.152\t2-epi-5-epi-valiolone synthase", + "4.2.3.153\t(5-formylfuran-3-yl)methyl phosphate synthase", + "4.2.3.154\tDemethyl-4-deoxygadusol synthase", + "4.2.3.155\t2-epi-valiolone synthase", + "4.2.3.156\tHydroxysqualene synthase", + "4.2.3.n2\tDelta-selinene synthase", + "4.2.3.n11\tSelinene synthase", + "4.2.99.12\tCarboxymethyloxysuccinate lyase", + "4.2.99.18\tDNA-(apurinic or apyrimidinic site) lyase", + "4.2.99.20\t2-succinyl-6-hydroxy-2,4-cyclohexadiene-1-carboxylate synthase", + "4.2.99.21\tIsochorismate lyase", + "4.2.99.22\tTuliposide A-converting enzyme", + "4.2.99.23\tTuliposide B-converting enzyme", + "4.3.1.1\tAspartate ammonia-lyase", + "4.3.1.2\tMethylaspartate ammonia-lyase", + "4.3.1.3\tHistidine ammonia-lyase", + "4.3.1.4\tFormimidoyltetrahydrofolate cyclodeaminase", + "4.3.1.6\tBeta-alanyl-CoA ammonia-lyase", + "4.3.1.7\tEthanolamine ammonia-lyase", + "4.3.1.9\tGlucosaminate ammonia-lyase", + "4.3.1.10\tSerine-sulfate ammonia-lyase", + "4.3.1.12\tOrnithine cyclodeaminase", + "4.3.1.13\tCarbamoyl-serine ammonia-lyase", + "4.3.1.14\t3-aminobutyryl-CoA ammonia-lyase", + "4.3.1.15\tDiaminopropionate ammonia-lyase", + "4.3.1.16\tThreo-3-hydroxy-L-aspartate ammonia-lyase", + "4.3.1.17\tL-serine ammonia-lyase", + "4.3.1.18\tD-serine ammonia-lyase", + "4.3.1.19\tThreonine ammonia-lyase", + "4.3.1.20\tErythro-3-hydroxy-L-aspartate ammonia-lyase", + "4.3.1.22\t3,4-dihydroxyphenylalanine reductive deaminase", + "4.3.1.23\tTyrosine ammonia-lyase", + "4.3.1.24\tPhenylalanine ammonia-lyase", + "4.3.1.25\tPhenylalanine/tyrosine ammonia-lyase", + "4.3.1.27\tThreo-3-hydroxy-D-aspartate ammonia-lyase", + "4.3.1.28\tL-lysine cyclodeaminase", + "4.3.1.29\tD-glucosaminate-6-phosphate ammonia lyase", + "4.3.1.30\tdTDP-4-amino-4,6-dideoxy-D-glucose ammonia-lyase", + "4.3.1.31\tL-tryptophan ammonia lyase", + "4.3.2.1\tArgininosuccinate lyase", + "4.3.2.2\tAdenylosuccinate lyase", + "4.3.2.3\tUreidoglycolate lyase", + "4.3.2.4\tPurine imidazole-ring cyclase", + "4.3.2.5\tPeptidylamidoglycolate lyase", + "4.3.2.6\tGamma-L-glutamyl-butirosin B gamma-glutamyl cyclotransferase", + "4.3.3.1\t3-ketovalidoxylamine C-N-lyase", + "4.3.3.2\tStrictosidine synthase", + "4.3.3.3\tDeacetylisoipecoside synthase", + "4.3.3.4\tDeacetylipecoside synthase", + "4.3.3.5\t4'-demethylrebeccamycin synthase", + "4.3.3.6\tPyridoxal 5'-phosphate synthase (glutamine hydrolyzing)", + "4.3.3.7\t4-hydroxy-tetrahydrodipicolinate synthase", + "4.3.99.2\tCarboxybiotin decarboxylase", + "4.3.99.3\t7-carboxy-7-deazaguanine synthase", + "4.3.99.4\tCholine trimethylamine-lyase", + "4.4.1.1\tCystathionine gamma-lyase", + "4.4.1.2\tHomocysteine desulfhydrase", + "4.4.1.3\tDimethylpropiothetin dethiomethylase", + "4.4.1.4\tAlliin lyase", + "4.4.1.5\tLactoylglutathione lyase", + "4.4.1.6\tS-alkylcysteine lyase", + "4.4.1.8\tCystathionine beta-lyase", + "4.4.1.9\tL-3-cyanoalanine synthase", + "4.4.1.10\tCysteine lyase", + "4.4.1.11\tMethionine gamma-lyase", + "4.4.1.13\tCysteine-S-conjugate beta-lyase", + "4.4.1.14\t1-aminocyclopropane-1-carboxylate synthase", + "4.4.1.15\tD-cysteine desulfhydrase", + "4.4.1.16\tSelenocysteine lyase", + "4.4.1.17\tHolocytochrome-c synthase", + "4.4.1.19\tPhosphosulfolactate synthase", + "4.4.1.20\tLeukotriene-C(4) synthase", + "4.4.1.21\tS-ribosylhomocysteine lyase", + "4.4.1.22\tS-(hydroxymethyl)glutathione synthase", + "4.4.1.23\t2-hydroxypropyl-CoM lyase", + "4.4.1.24\t(2R)-sulfolactate sulfo-lyase", + "4.4.1.25\tL-cysteate sulfo-lyase", + "4.4.1.26\tOlivetolic acid cyclase", + "4.4.1.27\tCarbon disulfide lyase", + "4.4.1.28\tL-cysteine desulfidase", + "4.4.1.29\tPhycobiliprotein cysteine-84 phycobilin lyase", + "4.4.1.30\tPhycobiliprotein beta-cysteine-155 phycobilin lyase", + "4.4.1.31\tPhycoerythrocyanin alpha-cysteine-84 phycoviolobilin lyase/isomerase", + "4.4.1.32\tC-phycocyanin alpha-cysteine-84 phycocyanobilin lyase", + "4.4.1.33\tR-phycocyanin alpha-cysteine-84 phycourobilin lyase/isomerase", + "4.4.1.34\tIsoprene-epoxide--glutathione S-transferase", + "4.4.1.35\tL-cystine beta-lyase", + "4.5.1.1\tDDT-dehydrochlorinase", + "4.5.1.2\t3-chloro-D-alanine dehydrochlorinase", + "4.5.1.3\tDichloromethane dehalogenase", + "4.5.1.4\tL-2-amino-4-chloropent-4-enoate dehydrochlorinase", + "4.5.1.5\tS-carboxymethylcysteine synthase", + "4.6.1.1\tAdenylate cyclase", + "4.6.1.2\tGuanylate cyclase", + "4.6.1.6\tCytidylate cyclase", + "4.6.1.12\t2-C-methyl-D-erythritol 2,4-cyclodiphosphate synthase", + "4.6.1.13\tPhosphatidylinositol diacylglycerol-lyase", + "4.6.1.14\tGlycosylphosphatidylinositol diacylglycerol-lyase", + "4.6.1.15\tFAD-AMP lyase (cyclizing)", + "4.6.1.16\ttRNA-intron lyase", + "4.6.1.17\tCyclic pyranopterin monophosphate synthase", + "4.7.1.1\tAlpha-D-ribose 1-methylphosphonate 5-phosphate C-P-lyase", + "4.99.1.1\tProtoporphyrin ferrochelatase", + "4.99.1.2\tAlkylmercury lyase", + "4.99.1.3\tSirohydrochlorin cobaltochelatase", + "4.99.1.4\tSirohydrochlorin ferrochelatase", + "4.99.1.5\tAliphatic aldoxime dehydratase", + "4.99.1.6\tIndoleacetaldoxime dehydratase", + "4.99.1.7\tPhenylacetaldoxime dehydratase", + "4.99.1.8\tHeme ligase", + "4.99.1.9\tCoproporphyrin ferrochelatase", + "5.1.1.1\tAlanine racemase", + "5.1.1.2\tMethionine racemase", + "5.1.1.3\tGlutamate racemase", + "5.1.1.4\tProline racemase", + "5.1.1.5\tLysine racemase", + "5.1.1.6\tThreonine racemase", + "5.1.1.7\tDiaminopimelate epimerase", + "5.1.1.8\t4-hydroxyproline epimerase", + "5.1.1.9\tArginine racemase", + "5.1.1.10\tAmino-acid racemase", + "5.1.1.11\tPhenylalanine racemase (ATP-hydrolyzing)", + "5.1.1.12\tOrnithine racemase", + "5.1.1.13\tAspartate racemase", + "5.1.1.14\tNocardicin-A epimerase", + "5.1.1.15\t2-aminohexano-6-lactam racemase", + "5.1.1.16\tProtein-serine epimerase", + "5.1.1.17\tIsopenicillin-N epimerase", + "5.1.1.18\tSerine racemase", + "5.1.1.19\tO-ureido-serine racemase", + "5.1.1.20\tL-Ala-D/L-Glu epimerase", + "5.1.1.21\tIsoleucine 2-epimerase", + "5.1.1.22\t4-hydroxyproline betaine 2-epimerase", + "5.1.2.1\tLactate racemase", + "5.1.2.2\tMandelate racemase", + "5.1.2.3\t3-hydroxybutyryl-CoA epimerase", + "5.1.2.4\tAcetoin racemase", + "5.1.2.5\tTartrate epimerase", + "5.1.2.6\tIsocitrate epimerase", + "5.1.2.7\tTagaturonate epimerase", + "5.1.3.1\tRibulose-phosphate 3-epimerase", + "5.1.3.2\tUDP-glucose 4-epimerase", + "5.1.3.3\tAldose 1-epimerase", + "5.1.3.4\tL-ribulose-5-phosphate 4-epimerase", + "5.1.3.5\tUDP-arabinose 4-epimerase", + "5.1.3.6\tUDP-glucuronate 4-epimerase", + "5.1.3.7\tUDP-N-acetylglucosamine 4-epimerase", + "5.1.3.8\tN-acylglucosamine 2-epimerase", + "5.1.3.9\tN-acylglucosamine-6-phosphate 2-epimerase", + "5.1.3.10\tCDP-paratose 2-epimerase", + "5.1.3.11\tCellobiose epimerase", + "5.1.3.12\tUDP-glucuronate 5'-epimerase", + "5.1.3.13\tdTDP-4-dehydrorhamnose 3,5-epimerase", + "5.1.3.14\tUDP-N-acetylglucosamine 2-epimerase (non-hydrolyzing)", + "5.1.3.15\tGlucose-6-phosphate 1-epimerase", + "5.1.3.16\tUDP-glucosamine 4-epimerase", + "5.1.3.17\tHeparosan-N-sulfate-glucuronate 5-epimerase", + "5.1.3.18\tGDP-mannose 3,5-epimerase", + "5.1.3.19\tChondroitin-glucuronate 5-epimerase", + "5.1.3.20\tADP-glyceromanno-heptose 6-epimerase", + "5.1.3.21\tMaltose epimerase", + "5.1.3.22\tL-ribulose-5-phosphate 3-epimerase", + "5.1.3.23\tUDP-2,3-diacetamido-2,3-dideoxyglucuronic acid 2-epimerase", + "5.1.3.24\tN-acetylneuraminate epimerase", + "5.1.3.25\tdTDP-L-rhamnose 4-epimerase", + "5.1.3.26\tN-acetyl-alpha-D-glucosaminyl-diphospho-ditrans,octacis-undecaprenol 4-epimerase", + "5.1.3.27\tdTDP-4-dehydro-6-deoxy-D-glucose 3-epimerase", + "5.1.3.28\tUDP-N-acetyl-L-fucosamine synthase", + "5.1.3.29\tL-fucose mutarotase", + "5.1.3.30\tD-psicose 3-epimerase", + "5.1.3.31\tD-tagatose 3-epimerase", + "5.1.3.32\tL-rhamnose mutarotase", + "5.1.3.33\t2-epi-5-epi-valiolone epimerase", + "5.1.3.34\tMonoglucosyldiacylglycerol epimerase", + "5.1.3.35\t2-epi-5-epi-valiolone 7-phosphate 2-epimerase", + "5.1.3.36\tHeparosan-glucuronate 5-epimerase", + "5.1.3.37\tMannuronan 5-epimerase", + "5.1.3.38\tD-erythrulose 1-phosphate 3-epimerase", + "5.1.3.39\tL-erythrulose 4-phosphate epimerase", + "5.1.3.40\tD-tagatose 6-phosphate 4-epimerase", + "5.1.99.1\tMethylmalonyl-CoA epimerase", + "5.1.99.2\t16-hydroxysteroid epimerase", + "5.1.99.3\tAllantoin racemase", + "5.1.99.4\tAlpha-methylacyl-CoA racemase", + "5.1.99.5\tHydantoin racemase", + "5.1.99.6\tNAD(P)H-hydrate epimerase", + "5.1.99.7\tDihydroneopterin triphosphate 2'-epimerase", + "5.1.99.8\t7,8-dihydroneopterin epimerase", + "5.2.1.1\tMaleate isomerase", + "5.2.1.2\tMaleylacetoacetate isomerase", + "5.2.1.4\tMaleylpyruvate isomerase", + "5.2.1.5\tLinoleate isomerase", + "5.2.1.6\tFurylfuramide isomerase", + "5.2.1.8\tPeptidylprolyl isomerase", + "5.2.1.9\tFarnesol 2-isomerase", + "5.2.1.10\t2-chloro-4-carboxymethylenebut-2-en-1,4-olide isomerase", + "5.2.1.12\tZeta-carotene isomerase", + "5.2.1.13\tProlycopene isomerase", + "5.2.1.14\tBeta-carotene isomerase", + "5.3.1.1\tTriose-phosphate isomerase", + "5.3.1.3\tD-arabinose isomerase", + "5.3.1.4\tL-arabinose isomerase", + "5.3.1.5\tXylose isomerase", + "5.3.1.6\tRibose-5-phosphate isomerase", + "5.3.1.7\tMannose isomerase", + "5.3.1.8\tMannose-6-phosphate isomerase", + "5.3.1.9\tGlucose-6-phosphate isomerase", + "5.3.1.12\tGlucuronate isomerase", + "5.3.1.13\tArabinose-5-phosphate isomerase", + "5.3.1.14\tL-rhamnose isomerase", + "5.3.1.15\tD-lyxose ketol-isomerase", + "5.3.1.16\t1-(5-phosphoribosyl)-5-((5-phosphoribosylamino)methylideneamino)imidazole-4-carboxamide isomerase", + "5.3.1.17\t5-dehydro-4-deoxy-D-glucuronate isomerase", + "5.3.1.20\tRibose isomerase", + "5.3.1.21\tCorticosteroid side-chain-isomerase", + "5.3.1.22\tHydroxypyruvate isomerase", + "5.3.1.23\tS-methyl-5-thioribose-1-phosphate isomerase", + "5.3.1.24\tPhosphoribosylanthranilate isomerase", + "5.3.1.25\tL-fucose isomerase", + "5.3.1.26\tGalactose-6-phosphate isomerase", + "5.3.1.27\t6-phospho-3-hexuloisomerase", + "5.3.1.28\tD-sedoheptulose 7-phosphate isomerase", + "5.3.1.29\tRibose 1,5-bisphosphate isomerase", + "5.3.1.30\t5-deoxy-glucuronate isomerase", + "5.3.1.31\tSulfoquinovose isomerase", + "5.3.1.32\t(4S)-4-hydroxy-5-phosphonooxypentane-2,3-dione isomerase", + "5.3.1.33\tL-erythrulose 1-phosphate isomerase", + "5.3.1.34\tD-erythrulose 4-phosphate isomerase", + "5.3.2.1\tPhenylpyruvate tautomerase", + "5.3.2.2\tOxaloacetate tautomerase", + "5.3.2.3\tTDP-4-oxo-6-deoxy-alpha-D-glucose-3,4-oxoisomerase (dTDP-3-dehydro-6-deoxy-alpha-D-galactopyranose-forming)", + "5.3.2.4\tTDP-4-oxo-6-deoxy-alpha-D-glucose-3,4-oxoisomerase (dTDP-3-dehydro-6-deoxy-alpha-D-glucopyranose-forming)", + "5.3.2.5\t2,3-diketo-5-methylthiopentyl-1-phosphate enolase", + "5.3.2.6\t2-hydroxymuconate tautomerase", + "5.3.2.7\tAscopyrone tautomerase", + "5.3.2.8\t4-oxalomesaconate tautomerase", + "5.3.3.1\tSteroid Delta-isomerase", + "5.3.3.2\tIsopentenyl-diphosphate Delta-isomerase", + "5.3.3.3\tVinylacetyl-CoA Delta-isomerase", + "5.3.3.4\tMuconolactone Delta-isomerase", + "5.3.3.5\tCholestenol Delta-isomerase", + "5.3.3.6\tMethylitaconate Delta-isomerase", + "5.3.3.7\tAconitate Delta-isomerase", + "5.3.3.8\tDodecenoyl-CoA isomerase", + "5.3.3.9\tProstaglandin-A(1) Delta-isomerase", + "5.3.3.10\t5-carboxymethyl-2-hydroxymuconate Delta-isomerase", + "5.3.3.11\tIsopiperitenone Delta-isomerase", + "5.3.3.12\tL-dopachrome isomerase", + "5.3.3.13\tPolyenoic fatty acid isomerase", + "5.3.3.14\tTrans-2-decenoyl-[acyl-carrier-protein] isomerase", + "5.3.3.17\tTrans-2,3-dihydro-3-hydroxyanthranilate isomerase", + "5.3.3.18\t2-(1,2-epoxy-1,2-dihydrophenyl)acetyl-CoA isomerase", + "5.3.3.19\t3-((4R)-4-hydroxycyclohexa-1,5-dien-1-yl)-2-oxopropanoate isomerase", + "5.3.4.1\tProtein disulfide-isomerase", + "5.3.99.2\tProstaglandin-D synthase", + "5.3.99.3\tProstaglandin-E synthase", + "5.3.99.4\tProstaglandin-I synthase", + "5.3.99.5\tThromboxane-A synthase", + "5.3.99.6\tAllene-oxide cyclase", + "5.3.99.7\tStyrene-oxide isomerase", + "5.3.99.8\tCapsanthin/capsorubin synthase", + "5.3.99.9\tNeoxanthin synthase", + "5.3.99.10\tThiazole tautomerase", + "5.3.99.11\t2-keto-myo-inositol isomerase", + "5.4.1.1\tLysolecithin acylmutase", + "5.4.1.3\t2-methylfumaryl-CoA isomerase", + "5.4.1.4\tD-galactarolactone isomerase", + "5.4.2.2\tPhosphoglucomutase (alpha-D-glucose-1,6-bisphosphate-dependent)", + "5.4.2.3\tPhosphoacetylglucosamine mutase", + "5.4.2.4\tBisphosphoglycerate mutase", + "5.4.2.5\tPhosphoglucomutase (glucose-cofactor)", + "5.4.2.6\tBeta-phosphoglucomutase", + "5.4.2.7\tPhosphopentomutase", + "5.4.2.8\tPhosphomannomutase", + "5.4.2.9\tPhosphoenolpyruvate mutase", + "5.4.2.10\tPhosphoglucosamine mutase", + "5.4.2.11\tPhosphoglycerate mutase (2,3-diphosphoglycerate-dependent)", + "5.4.2.12\tPhosphoglycerate mutase (2,3-diphosphoglycerate-independent)", + "5.4.3.2\tLysine 2,3-aminomutase", + "5.4.3.3\tBeta-lysine 5,6-aminomutase", + "5.4.3.4\tD-lysine 5,6-aminomutase", + "5.4.3.5\tD-ornithine 4,5-aminomutase", + "5.4.3.6\tTyrosine 2,3-aminomutase", + "5.4.3.7\tLeucine 2,3-aminomutase", + "5.4.3.8\tGlutamate-1-semialdehyde 2,1-aminomutase", + "5.4.3.9\tGlutamate 2,3-aminomutase", + "5.4.3.10\tPhenylalanine aminomutase (L-beta-phenylalanine forming)", + "5.4.3.11\tPhenylalanine aminomutase (D-beta-phenylalanine forming)", + "5.4.4.1\t(Hydroxyamino)benzene mutase", + "5.4.4.2\tIsochorismate synthase", + "5.4.4.3\t3-(hydroxyamino)phenol mutase", + "5.4.4.4\tGeraniol isomerase", + "5.4.4.5\t9,12-octadecadienoate 8-hydroperoxide 8R-isomerase", + "5.4.4.6\t9,12-octadecadienoate 8-hydroperoxide 8S-isomerase", + "5.4.4.7\tHydroperoxy icosatetraenoate isomerase", + "5.4.99.1\tMethylaspartate mutase", + "5.4.99.2\tMethylmalonyl-CoA mutase", + "5.4.99.3\t2-acetolactate mutase", + "5.4.99.4\t2-methyleneglutarate mutase", + "5.4.99.5\tChorismate mutase", + "5.4.99.7\tLanosterol synthase", + "5.4.99.8\tCycloartenol synthase", + "5.4.99.9\tUDP-galactopyranose mutase", + "5.4.99.11\tIsomaltulose synthase", + "5.4.99.12\ttRNA pseudouridine(38-40) synthase", + "5.4.99.13\tIsobutyryl-CoA mutase", + "5.4.99.14\t4-carboxymethyl-4-methylbutenolide mutase", + "5.4.99.15\t(1->4)-alpha-D-glucan 1-alpha-D-glucosylmutase", + "5.4.99.16\tMaltose alpha-D-glucosyltransferase", + "5.4.99.17\tSqualene--hopene cyclase", + "5.4.99.18\t5-(carboxyamino)imidazole ribonucleotide mutase", + "5.4.99.19\t16S rRNA pseudouridine(516) synthase", + "5.4.99.20\t23S rRNA pseudouridine(2457) synthase", + "5.4.99.21\t23S rRNA pseudouridine(2604) synthase", + "5.4.99.22\t23S rRNA pseudouridine(2605) synthase", + "5.4.99.23\t23S rRNA pseudouridine(1911/1915/1917) synthase", + "5.4.99.24\t23S rRNA pseudouridine(955/2504/2580) synthase", + "5.4.99.25\ttRNA pseudouridine(55) synthase", + "5.4.99.26\ttRNA pseudouridine(65) synthase", + "5.4.99.27\ttRNA pseudouridine(13) synthase", + "5.4.99.28\ttRNA pseudouridine(32) synthase", + "5.4.99.29\t23S rRNA pseudouridine(746) synthase", + "5.4.99.30\tUDP-arabinopyranose mutase", + "5.4.99.31\tThalianol synthase", + "5.4.99.32\tProtostadienol synthase", + "5.4.99.33\tCucurbitadienol synthase", + "5.4.99.34\tGermanicol synthase", + "5.4.99.35\tTaraxerol synthase", + "5.4.99.36\tIsomultiflorenol synthase", + "5.4.99.37\tDammaradiene synthase", + "5.4.99.38\tCamelliol C synthase", + "5.4.99.39\tBeta-amyrin synthase", + "5.4.99.40\tAlpha-amyrin synthase", + "5.4.99.41\tLupeol synthase", + "5.4.99.42\ttRNA pseudouridine(31) synthase", + "5.4.99.43\t21S rRNA pseudouridine(2819) synthase", + "5.4.99.44\tMitochondrial tRNA pseudouridine(27/28) synthase", + "5.4.99.45\ttRNA pseudouridine(38/39) synthase", + "5.4.99.46\tShionone synthase", + "5.4.99.47\tParkeol synthase", + "5.4.99.48\tAchilleol B synthase", + "5.4.99.49\tGlutinol synthase", + "5.4.99.50\tFriedelin synthase", + "5.4.99.51\tBaccharis oxide synthase", + "5.4.99.52\tAlpha-seco-amyrin synthase", + "5.4.99.53\tMarneral synthase", + "5.4.99.54\tBeta-seco-amyrin synthase", + "5.4.99.55\tDelta-amyrin synthase", + "5.4.99.56\tTirucalladienol synthase", + "5.4.99.57\tBaruol synthase", + "5.4.99.58\tMethylornithine synthase", + "5.4.99.59\tdTDP-fucopyranose mutase", + "5.4.99.60\tCobalt-precorrin-8 methylmutase", + "5.4.99.61\tPrecorrin-8X methylmutase", + "5.4.99.62\tD-ribose pyranase", + "5.4.99.63\tEthylmalonyl-CoA mutase", + "5.4.99.64\t2-hydroxyisobutanoyl-CoA mutase", + "5.5.1.1\tMuconate cycloisomerase", + "5.5.1.2\t3-carboxy-cis,cis-muconate cycloisomerase", + "5.5.1.3\tTetrahydroxypteridine cycloisomerase", + "5.5.1.4\tInositol-3-phosphate synthase", + "5.5.1.5\tCarboxy-cis,cis-muconate cyclase", + "5.5.1.6\tChalcone isomerase", + "5.5.1.7\tChloromuconate cycloisomerase", + "5.5.1.8\t(+)-bornyl diphosphate synthase", + "5.5.1.9\tCycloeucalenol cycloisomerase", + "5.5.1.10\tAlpha-pinene-oxide decyclase", + "5.5.1.11\tDichloromuconate cycloisomerase", + "5.5.1.12\tCopalyl diphosphate synthase", + "5.5.1.13\tEnt-copalyl diphosphate synthase", + "5.5.1.14\tSyn-copalyl-diphosphate synthase", + "5.5.1.15\tTerpentedienyl-diphosphate synthase", + "5.5.1.16\tHalimadienyl-diphosphate synthase", + "5.5.1.17\t(S)-beta-macrocarpene synthase", + "5.5.1.18\tLycopene epsilon-cyclase", + "5.5.1.19\tLycopene beta-cyclase", + "5.5.1.20\tProsolanapyrone-III cycloisomerase", + "5.5.1.22\t(-)-bornyl diphosphate synthase", + "5.5.1.23\tAklanonic acid methyl ester cyclase", + "5.5.1.24\tTocopherol cyclase", + "5.5.1.25\t3,6-anhydro-L-galactonate cycloisomerase", + "5.5.1.26\tNogalonic acid methyl ester cyclase", + "5.5.1.27\tD-galactarolactone cycloisomerase", + "5.99.1.1\tThiocyanate isomerase", + "5.99.1.2\tDNA topoisomerase", + "5.99.1.3\tDNA topoisomerase (ATP-hydrolyzing)", + "5.99.1.4\t2-hydroxychromene-2-carboxylate isomerase", + "6.1.1.1\tTyrosine--tRNA ligase", + "6.1.1.2\tTryptophan--tRNA ligase", + "6.1.1.3\tThreonine--tRNA ligase", + "6.1.1.4\tLeucine--tRNA ligase", + "6.1.1.5\tIsoleucine--tRNA ligase", + "6.1.1.6\tLysine--tRNA ligase", + "6.1.1.7\tAlanine--tRNA ligase", + "6.1.1.9\tValine--tRNA ligase", + "6.1.1.10\tMethionine--tRNA ligase", + "6.1.1.11\tSerine--tRNA ligase", + "6.1.1.12\tAspartate--tRNA ligase", + "6.1.1.13\tD-alanine--poly(phosphoribitol) ligase", + "6.1.1.14\tGlycine--tRNA ligase", + "6.1.1.15\tProline--tRNA ligase", + "6.1.1.16\tCysteine--tRNA ligase", + "6.1.1.17\tGlutamate--tRNA ligase", + "6.1.1.18\tGlutamine--tRNA ligase", + "6.1.1.19\tArginine--tRNA ligase", + "6.1.1.20\tPhenylalanine--tRNA ligase", + "6.1.1.21\tHistidine--tRNA ligase", + "6.1.1.22\tAsparagine--tRNA ligase", + "6.1.1.23\tAspartate--tRNA(Asn) ligase", + "6.1.1.24\tGlutamate--tRNA(Gln) ligase", + "6.1.1.26\tPyrrolysine--tRNA(Pyl) ligase", + "6.1.1.27\tO-phosphoserine--tRNA ligase", + "6.1.2.1\tD-alanine--(R)-lactate ligase", + "6.1.2.2\tNebramycin 5' synthase", + "6.2.1.1\tAcetate--CoA ligase", + "6.2.1.2\tButyrate--CoA ligase", + "6.2.1.3\tLong-chain-fatty-acid--CoA ligase", + "6.2.1.4\tSuccinate--CoA ligase (GDP-forming)", + "6.2.1.5\tSuccinate--CoA ligase (ADP-forming)", + "6.2.1.6\tGlutarate--CoA ligase", + "6.2.1.7\tCholate--CoA ligase", + "6.2.1.8\tOxalate--CoA ligase", + "6.2.1.9\tMalate--CoA ligase", + "6.2.1.10\tAcid--CoA ligase (GDP-forming)", + "6.2.1.11\tBiotin--CoA ligase", + "6.2.1.12\t4-coumarate--CoA ligase", + "6.2.1.13\tAcetate--CoA ligase (ADP-forming)", + "6.2.1.14\t6-carboxyhexanoate--CoA ligase", + "6.2.1.15\tArachidonate--CoA ligase", + "6.2.1.16\tAcetoacetate--CoA ligase", + "6.2.1.17\tPropionate--CoA ligase", + "6.2.1.18\tCitrate--CoA ligase", + "6.2.1.19\tLong-chain-fatty-acid--protein ligase", + "6.2.1.20\tLong-chain-fatty-acid--[acyl-carrier-protein] ligase", + "6.2.1.22\t[Citrate (pro-3S)-lyase] ligase", + "6.2.1.23\tDicarboxylate--CoA ligase", + "6.2.1.24\tPhytanate--CoA ligase", + "6.2.1.25\tBenzoate--CoA ligase", + "6.2.1.26\to-succinylbenzoate--CoA ligase", + "6.2.1.27\t4-hydroxybenzoate--CoA ligase", + "6.2.1.28\t3-alpha,7-alpha-dihydroxy-5-beta-cholestanate--CoA ligase", + "6.2.1.30\tPhenylacetate--CoA ligase", + "6.2.1.31\t2-furoate--CoA ligase", + "6.2.1.32\tAnthranilate--CoA ligase", + "6.2.1.33\t4-chlorobenzoate--CoA ligase", + "6.2.1.34\tTrans-feruloyl-CoA synthase", + "6.2.1.35\tAcetate--[acyl-carrier protein] ligase", + "6.2.1.36\t3-hydroxypropionyl-CoA synthase", + "6.2.1.37\t3-hydroxybenzoate--CoA ligase", + "6.2.1.38\t(2,2,3-trimethyl-5-oxocyclopent-3-enyl)acetyl-CoA synthase", + "6.2.1.39\t[Butirosin acyl-carrier protein]--L-glutamate ligase", + "6.2.1.40\t4-hydroxybutyrate--CoA ligase", + "6.2.1.41\t3-((3aS,4S,7aS)-7a-methyl-1,5-dioxo-octahydro-1H-inden-4-yl)propanoate--CoA ligase", + "6.2.1.42\t3-oxocholest-4-en-26-oate--CoA ligase", + "6.2.1.43\t2-hydroxy-7-methoxy-5-methyl-1-naphthoate--CoA ligase", + "6.2.1.44\t3-(methylthio)propionyl--CoA ligase", + "6.2.1.45\tE1 ubiquitin-activating enzyme", + "6.2.1.46\tL-allo-isoleucine--holo-[CmaA peptidyl-carrier protein] ligase", + "6.2.1.47\tMedium-chain-fatty-acid--(acyl-carrier-protein) ligase", + "6.2.1.48\tCarnitine-CoA ligase", + "6.2.1.n2\tAmino acid--[acyl-carrier-protein] ligase", + "6.2.1.n3\tMalonate--CoA ligase", + "6.3.1.1\tAspartate--ammonia ligase", + "6.3.1.2\tGlutamine synthetase", + "6.3.1.4\tAspartate--ammonia ligase (ADP-forming)", + "6.3.1.5\tNAD(+) synthase", + "6.3.1.6\tGlutamate--ethylamine ligase", + "6.3.1.7\t4-methyleneglutamate--ammonia ligase", + "6.3.1.8\tGlutathionylspermidine synthase", + "6.3.1.9\tTrypanothione synthase", + "6.3.1.10\tAdenosylcobinamide-phosphate synthase", + "6.3.1.11\tGlutamate--putrescine ligase", + "6.3.1.12\tD-aspartate ligase", + "6.3.1.13\tL-cysteine:1D-myo-inositol 2-amino-2-deoxy-alpha-D-glucopyranoside ligase", + "6.3.1.14\tDiphthine--ammonia ligase", + "6.3.1.15\t8-demethylnovobiocic acid synthase", + "6.3.1.17\tBeta-citrylglutamate synthase", + "6.3.1.18\tGamma-glutamylanilide synthase", + "6.3.1.19\tProkaryotic ubiquitin-like protein ligase", + "6.3.1.20\tLipoate--protein ligase", + "6.3.2.1\tPantoate--beta-alanine ligase (AMP-forming)", + "6.3.2.2\tGlutamate--cysteine ligase", + "6.3.2.3\tGlutathione synthase", + "6.3.2.4\tD-alanine--D-alanine ligase", + "6.3.2.5\tPhosphopantothenate--cysteine ligase", + "6.3.2.6\tPhosphoribosylaminoimidazolesuccinocarboxamide synthase", + "6.3.2.7\tUDP-N-acetylmuramoyl-L-alanyl-D-glutamate--L-lysine ligase", + "6.3.2.8\tUDP-N-acetylmuramate--L-alanine ligase", + "6.3.2.9\tUDP-N-acetylmuramoyl-L-alanine--D-glutamate ligase", + "6.3.2.10\tUDP-N-acetylmuramoyl-tripeptide--D-alanyl-D-alanine ligase", + "6.3.2.11\tCarnosine synthase", + "6.3.2.12\tDihydrofolate synthase", + "6.3.2.13\tUDP-N-acetylmuramoyl-L-alanyl-D-glutamate--2,6-diaminopimelate ligase", + "6.3.2.14\tEnterobactin synthase", + "6.3.2.16\tD-alanine--alanyl-poly(glycerolphosphate) ligase", + "6.3.2.17\tTetrahydrofolate synthase", + "6.3.2.18\tGamma-glutamylhistamine synthase", + "6.3.2.20\tIndoleacetate--lysine synthetase", + "6.3.2.23\tHomoglutathione synthase", + "6.3.2.24\tTyrosine--arginine ligase", + "6.3.2.25\tTubulin--tyrosine ligase", + "6.3.2.26\tN-(5-amino-5-carboxypentanoyl)-L-cysteinyl-D-valine synthase", + "6.3.2.29\tCyanophycin synthase (L-aspartate-adding)", + "6.3.2.30\tCyanophycin synthase (L-arginine-adding)", + "6.3.2.31\tCoenzyme F420-0:L-glutamate ligase", + "6.3.2.32\tCoenzyme gamma-F420-2:alpha-L-glutamate ligase", + "6.3.2.33\tTetrahydrosarcinapterin synthase", + "6.3.2.34\tCoenzyme F420-1:gamma-L-glutamate ligase", + "6.3.2.35\tD-alanine--D-serine ligase", + "6.3.2.36\t4-phosphopantoate--beta-alanine ligase", + "6.3.2.37\tUDP-N-acetylmuramoyl-L-alanyl-D-glutamate--D-lysine ligase", + "6.3.2.38\tN(2)-citryl-N(6)-acetyl-N(6)-hydroxylysine synthase", + "6.3.2.39\tAerobactin synthase", + "6.3.2.40\tCyclopeptine synthase", + "6.3.2.41\tN-acetylaspartylglutamate synthase", + "6.3.2.42\tN-acetylaspartylglutamylglutamate synthase", + "6.3.2.43\t[Lysine-biosynthesis-protein LysW]--L-2-aminoadipate ligase", + "6.3.2.44\tPantoate--beta-alanine ligase (ADP-forming)", + "6.3.2.45\tUDP-N-acetylmuramate L-alanyl-gamma-D-glutamyl-meso-2,6-diaminoheptanedioate ligase", + "6.3.2.46\tFumarate--(S)-2,3-diaminopropanoate ligase", + "6.3.2.47\tDapdiamide synthase", + "6.3.2.48\tL-arginine-specific L-amino acid ligase", + "6.3.2.49\tL-alanine--L-anticapsin ligase", + "6.3.2.n3\tISG15--protein ligase", + "6.3.3.1\tPhosphoribosylformylglycinamidine cyclo-ligase", + "6.3.3.2\t5-formyltetrahydrofolate cyclo-ligase", + "6.3.3.3\tDethiobiotin synthase", + "6.3.3.4\t(Carboxyethyl)arginine beta-lactam-synthase", + "6.3.3.5\tO-ureido-D-serine cyclo-ligase", + "6.3.3.6\tCarbapenam-3-carboxylate synthase", + "6.3.4.2\tCTP synthase (glutamine hydrolyzing)", + "6.3.4.3\tFormate--tetrahydrofolate ligase", + "6.3.4.4\tAdenylosuccinate synthase", + "6.3.4.5\tArgininosuccinate synthase", + "6.3.4.6\tUrea carboxylase", + "6.3.4.7\tRibose-5-phosphate--ammonia ligase", + "6.3.4.8\tImidazoleacetate--phosphoribosyldiphosphate ligase", + "6.3.4.9\tBiotin--[methylmalonyl-CoA-carboxytransferase] ligase", + "6.3.4.10\tBiotin--[propionyl-CoA-carboxylase (ATP-hydrolyzing)] ligase", + "6.3.4.11\tBiotin--[methylcrotonoyl-CoA-carboxylase] ligase", + "6.3.4.12\tGlutamate--methylamine ligase", + "6.3.4.13\tPhosphoribosylamine--glycine ligase", + "6.3.4.14\tBiotin carboxylase", + "6.3.4.15\tBiotin--[acetyl-CoA-carboxylase] ligase", + "6.3.4.16\tCarbamoyl-phosphate synthase (ammonia)", + "6.3.4.17\tFormate--dihydrofolate ligase", + "6.3.4.18\t5-(carboxyamino)imidazole ribonucleotide synthase", + "6.3.4.19\ttRNA(Ile)-lysidine synthetase", + "6.3.4.20\t7-cyano-7-deazaguanine synthase", + "6.3.4.21\tNicotinate phosphoribosyltransferase", + "6.3.4.22\ttRNA(Ile)(2)-agmatinylcytidine synthase", + "6.3.4.23\tFormate--phosphoribosylaminoimidazolecarboxamide ligase", + "6.3.4.24\tTyramine--L-glutamate ligase", + "6.3.5.1\tNAD(+) synthase (glutamine-hydrolyzing)", + "6.3.5.2\tGMP synthase (glutamine-hydrolyzing)", + "6.3.5.3\tPhosphoribosylformylglycinamidine synthase", + "6.3.5.4\tAsparagine synthase (glutamine-hydrolyzing)", + "6.3.5.5\tCarbamoyl-phosphate synthase (glutamine-hydrolyzing)", + "6.3.5.6\tAsparaginyl-tRNA synthase (glutamine-hydrolyzing)", + "6.3.5.7\tGlutaminyl-tRNA synthase (glutamine-hydrolyzing)", + "6.3.5.9\tHydrogenobyrinic acid a,c-diamide synthase (glutamine-hydrolyzing)", + "6.3.5.10\tAdenosylcobyric acid synthase (glutamine-hydrolyzing)", + "6.3.5.11\tCobyrinate a,c-diamide synthase (glutamine-hydrolyzing)", + "6.4.1.1\tPyruvate carboxylase", + "6.4.1.2\tAcetyl-CoA carboxylase", + "6.4.1.3\tPropionyl-CoA carboxylase", + "6.4.1.4\tMethylcrotonoyl-CoA carboxylase", + "6.4.1.5\tGeranoyl-CoA carboxylase", + "6.4.1.6\tAcetone carboxylase", + "6.4.1.7\t2-oxoglutarate carboxylase", + "6.4.1.8\tAcetophenone carboxylase", + "6.5.1.1\tDNA ligase (ATP)", + "6.5.1.2\tDNA ligase (NAD(+))", + "6.5.1.3\tRNA ligase (ATP)", + "6.5.1.4\tRNA 3'-terminal-phosphate cyclase (ATP)", + "6.5.1.5\tRNA 3'-terminal-phosphate cyclase (GTP)", + "6.5.1.6\tDNA ligase (ATP or NAD(+))", + "6.5.1.7\tDNA ligase (ATP, ADP or GTP)", + "6.5.1.8\t3'-phosphate/5'-hydroxy nucleic acid ligase", + "6.6.1.1\tMagnesium chelatase", + "6.6.1.2\tCobaltochelatase" }; diff --git a/c++/src/objects/seqfeat/ecnum_specific.txt b/c++/src/objects/seqfeat/ecnum_specific.txt index 4442b0ff..ef32dbb3 100644 --- a/c++/src/objects/seqfeat/ecnum_specific.txt +++ b/c++/src/objects/seqfeat/ecnum_specific.txt @@ -200,7 +200,7 @@ 1.1.1.216 Farnesol dehydrogenase 1.1.1.217 Benzyl-2-methyl-hydroxybutyrate dehydrogenase 1.1.1.218 Morphine 6-dehydrogenase -1.1.1.219 Dihydrokaempferol 4-reductase +1.1.1.219 Dihydroflavanol 4-reductase 1.1.1.220 6-pyruvoyltetrahydropterin 2'-reductase 1.1.1.221 Vomifoliol dehydrogenase 1.1.1.222 (R)-4-hydroxyphenyllactate dehydrogenase @@ -371,6 +371,19 @@ 1.1.1.392 3-alpha-hydroxycholanate dehydrogenase (NADP(+)) 1.1.1.393 3-beta-hydroxycholanate 3-dehydrogenase (NADP(+)) 1.1.1.394 Aurachin B dehydrogenase +1.1.1.395 3-alpha-hydroxybile acid CoA 3-dehydrogenase +1.1.1.396 Bacteriochlorophyllide-a dehydrogenase +1.1.1.397 Beta-methylindole-3-pyruvate reductase +1.1.1.398 2-glutathionyl-2-methylbut-3-en-1-ol dehydrogenase +1.1.1.399 2-oxoglutarate reductase +1.1.1.400 2-methyl-1,2-propanediol dehydrogenase +1.1.1.401 2-dehydro-3-deoxy-L-rhamnonate dehydrogenase (NAD(+)) +1.1.1.402 D-erythritol 1-phosphate dehydrogenase +1.1.1.403 D-threitol dehydrogenase (NAD(+)) +1.1.1.404 Tetrachlorobenzoquinone reductase +1.1.1.405 Ribitol-5-phosphate 2-dehydrogenase (NADP(+)) +1.1.1.406 Galactitol 2-dehydrogenase (L-tagatose-forming) +1.1.1.407 D-altritol 5-dehydrogenase 1.1.1.n4 (-)-trans-carveol dehydrogenase 1.1.1.n5 3-methylmalate dehydrogenase 1.1.1.n11 Succinic semialdehyde reductase @@ -382,6 +395,7 @@ 1.1.2.6 Polyvinyl alcohol dehydrogenase (cytochrome) 1.1.2.7 Methanol dehydrogenase (cytochrome c) 1.1.2.8 Alcohol dehydrogenase (cytochrome c) +1.1.2.9 1-butanol dehydrogenase (cytochrome c) 1.1.3.4 Glucose oxidase 1.1.3.5 Hexose oxidase 1.1.3.6 Cholesterol oxidase @@ -417,6 +431,7 @@ 1.1.3.46 4-hydroxymandelate oxidase 1.1.3.47 5-(hydroxymethyl)furfural oxidase 1.1.3.48 3-deoxy-alpha-D-manno-octulosonate 8-oxidase +1.1.3.49 (R)-mandelonitrile oxidase 1.1.5.2 Quinoprotein glucose dehydrogenase (PQQ, quinone) 1.1.5.3 Glycerol-3-phosphate dehydrogenase 1.1.5.4 Malate dehydrogenase (quinone) @@ -426,12 +441,15 @@ 1.1.5.8 Quinate dehydrogenase (quinone) 1.1.5.9 Glucose 1-dehydrogenase (FAD, quinone) 1.1.5.10 D-2-hydroxyacid dehydrogenase (quinone) +1.1.5.11 1-butanol dehydrogenase (quinone) +1.1.5.12 D-lactate dehydrogenase (quinone) 1.1.5.n1 Quinoprotein inositol dehydrogenase 1.1.9.1 Alcohol dehydrogenase (azurin) 1.1.98.2 Glucose-6-phosphate dehydrogenase (coenzyme-F420) 1.1.98.3 Decaprenylphospho-beta-D-ribofuranose 2-dehydrogenase 1.1.98.4 F420H(2):quinone oxidoreductase 1.1.98.5 Secondary-alcohol dehydrogenase (coenzyme-F420) +1.1.98.6 Ribonucleoside-triphosphate reductase (formate) 1.1.99.1 Choline dehydrogenase 1.1.99.2 L-2-hydroxyglutarate dehydrogenase 1.1.99.3 Gluconate 2-dehydrogenase (acceptor) @@ -461,6 +479,7 @@ 1.1.99.37 Methanol dehydrogenase (nicotinoprotein) 1.1.99.38 2-deoxy-scyllo-inosamine dehydrogenase (AdoMet-dependent) 1.1.99.39 D-2-hydroxyglutarate dehydrogenase +1.1.99.40 (R)-2-hydroxyglutarate--pyruvate transhydrogenase 1.2.1.2 Formate dehydrogenase 1.2.1.3 Aldehyde dehydrogenase (NAD(+)) 1.2.1.4 Aldehyde dehydrogenase (NADP(+)) @@ -547,6 +566,7 @@ 1.2.1.95 L-2-aminoadipate reductase 1.2.1.96 4-hydroxybenzaldehyde dehydrogenase (NADP(+)) 1.2.1.97 3-sulfolactaldehyde dehydrogenase +1.2.1.98 2-hydroxy-2-methylpropanal dehydrogenase 1.2.1.n2 Fatty acyl-CoA reductase 1.2.2.1 Formate dehydrogenase (cytochrome) 1.2.2.3 Formate dehydrogenase (cytochrome c-553) @@ -561,6 +581,7 @@ 1.2.3.9 Aryl-aldehyde oxidase 1.2.3.13 4-hydroxyphenylpyruvate oxidase 1.2.3.14 Abscisic-aldehyde oxidase +1.2.3.15 (Methyl)glyoxal oxidase 1.2.4.1 Pyruvate dehydrogenase (acetyl-transferring) 1.2.4.2 Oxoglutarate dehydrogenase (succinyl-transferring) 1.2.4.4 3-methyl-2-oxobutanoate dehydrogenase (2-methylpropanoyl-transferring) @@ -577,7 +598,6 @@ 1.2.7.10 Oxalate oxidoreductase 1.2.7.11 2-oxoacid oxidoreductase (ferredoxin) 1.2.98.1 Formaldehyde dismutase -1.2.99.2 Carbon-monoxide dehydrogenase (acceptor) 1.2.99.5 Formylmethanofuran dehydrogenase 1.2.99.6 Carboxylate reductase 1.2.99.7 Aldehyde dehydrogenase (FAD-independent) @@ -646,9 +666,9 @@ 1.3.1.72 Delta(24)-sterol reductase 1.3.1.73 1,2-dihydrovomilenine reductase 1.3.1.74 2-alkenal reductase (NAD(P)(+)) -1.3.1.75 Divinyl chlorophyllide a 8-vinyl-reductase +1.3.1.75 3,8-divinyl protochlorophyllide a 8-vinyl-reductase (NADPH) 1.3.1.76 Precorrin-2 dehydrogenase -1.3.1.77 Anthocyanidin reductase +1.3.1.77 Anthocyanidin reductase ((2R,3R)-flavan-3-ol-forming) 1.3.1.78 Arogenate dehydrogenase (NADP(+)) 1.3.1.79 Arogenate dehydrogenase (NAD(P)(+)) 1.3.1.81 (+)-pulegone reductase @@ -682,6 +702,7 @@ 1.3.1.109 Butanoyl-CoA dehydrogenase (NAD(+),ferredoxin) 1.3.1.110 Lactate dehydrogenase (NAD(+),ferredoxin) 1.3.1.111 Geranylgeranyl-bacteriochlorophyllide a reductase +1.3.1.112 Anthocyanidin reductase ((2S)-flavan-3-ol-forming) 1.3.1.n2 Camalexin synthase 1.3.1.n3 Curcumin reductase 1.3.2.3 L-galactonolactone dehydrogenase @@ -697,6 +718,7 @@ 1.3.3.12 L-galactonolactone oxidase 1.3.3.13 Albonoursin synthase 1.3.3.14 Aclacinomycin-A oxidase +1.3.3.15 Coproporphyrinogen III oxidase (coproporphyrin-forming) 1.3.4.1 Fumarate reductase (CoM/CoB) 1.3.5.1 Succinate dehydrogenase (quinone) 1.3.5.2 Dihydroorotate dehydrogenase (quinone) @@ -715,6 +737,9 @@ 1.3.7.9 4-hydroxybenzoyl-CoA reductase 1.3.7.11 2,3-bis-O-geranylgeranyl-sn-glycero-phospholipid reductase 1.3.7.12 Red chlorophyll catabolite reductase +1.3.7.13 3,8-divinyl protochlorophyllide a 8-vinyl-reductase (ferredoxin) +1.3.7.14 3,8-divinyl chlorophyllide a reductase +1.3.7.15 Chlorophyllide a reductase 1.3.8.1 Short-chain acyl-CoA dehydrogenase 1.3.8.2 4,4'-diapophytoene desaturase (4,4'-diapolycopene-forming) 1.3.8.3 (R)-benzylsuccinyl-CoA dehydrogenase @@ -727,7 +752,10 @@ 1.3.8.10 Cyclohex-1-ene-1-carbonyl-CoA dehydrogenase 1.3.8.11 Cyclohexane-1-carbonyl-CoA dehydrogenase 1.3.8.12 (2S)-methylsuccinyl-CoA dehydrogenase +1.3.8.13 Crotonobetainyl-CoA reductase 1.3.98.1 Dihydroorotate oxidase (fumarate) +1.3.98.3 Coproporphyrinogen dehydrogenase +1.3.98.4 5a,11a-dehydrotetracycline reductase 1.3.99.4 3-oxosteroid 1-dehydrogenase 1.3.99.5 3-oxo-5-alpha-steroid 4-dehydrogenase (acceptor) 1.3.99.6 3-oxo-5-beta-steroid 4-dehydrogenase @@ -738,7 +766,6 @@ 1.3.99.17 Quinoline 2-oxidoreductase 1.3.99.18 Quinaldate 4-oxidoreductase 1.3.99.19 Quinoline-4-carboxylate 2-oxidoreductase -1.3.99.22 Coproporphyrinogen dehydrogenase 1.3.99.23 All-trans-retinol 13,14-reductase 1.3.99.24 2-amino-4-deoxychorismate dehydrogenase 1.3.99.25 Carvone reductase @@ -750,9 +777,9 @@ 1.3.99.31 Phytoene desaturase (lycopene-forming) 1.3.99.32 Glutaryl-CoA dehydrogenase (acceptor) 1.3.99.33 Urocanate reductase -1.3.99.35 Chlorophyllide a reductase 1.3.99.36 Cypemycin cysteine dehydrogenase (decarboxylating) 1.3.99.37 1-hydroxy-2-isopentenylcarotenoid 3,4-desaturase +1.3.99.38 Menaquinone-9-beta-reductase 1.3.99.n1 3-hydroxybenzoyl-CoA reductase 1.4.1.1 Alanine dehydrogenase 1.4.1.2 Glutamate dehydrogenase @@ -776,6 +803,8 @@ 1.4.1.21 Aspartate dehydrogenase 1.4.1.23 Valine dehydrogenase (NAD(+)) 1.4.1.24 3-dehydroquinate synthase II +1.4.1.25 L-arginine dehydrogenase +1.4.1.26 2,4-diaminopentanoate dehydrogenase (NAD(+)) 1.4.2.1 Glycine dehydrogenase (cytochrome) 1.4.3.1 D-aspartate oxidase 1.4.3.2 L-amino-acid oxidase @@ -797,6 +826,7 @@ 1.4.3.22 Diamine oxidase 1.4.3.23 7-chloro-L-tryptophan oxidase 1.4.3.24 Pseudooxynicotine oxidase +1.4.3.25 L-arginine oxidase 1.4.4.2 Glycine dehydrogenase (aminomethyl-transferring) 1.4.5.1 D-amino acid dehydrogenase (quinone) 1.4.7.1 Glutamate synthase (ferredoxin) @@ -849,6 +879,7 @@ 1.5.1.48 2-methyl-1-pyrroline reductase 1.5.1.49 1-pyrroline-2-carboxylate reductase (NAD(P)H) 1.5.1.50 Dihydromonapterin reductase +1.5.1.51 N-((2S)-2-amino-2-carboxyethyl)-L-glutamate dehydrogenase 1.5.3.1 Sarcosine oxidase 1.5.3.2 N-methyl-L-amino-acid oxidase 1.5.3.4 N(6)-methyl-lysine oxidase @@ -867,6 +898,7 @@ 1.5.3.20 N-alkylglycine oxidase 1.5.3.21 4-methylaminobutanoate oxidase (methylamine-forming) 1.5.3.22 Coenzyme F420H(2) oxidase +1.5.3.23 Glyphosate oxidoreductase 1.5.4.1 Pyrimidodiazepine synthase 1.5.5.1 Electron-transferring-flavoprotein dehydrogenase 1.5.5.2 Proline dehydrogenase @@ -935,6 +967,8 @@ 1.7.2.4 Nitrous-oxide reductase 1.7.2.5 Nitric-oxide reductase (cytochrome c) 1.7.2.6 Hydroxylamine dehydrogenase +1.7.2.7 Hydrazine synthase +1.7.2.8 Hydrazine dehydrogenase 1.7.3.1 Nitroalkane oxidase 1.7.3.2 Acetylindoxyl oxidase 1.7.3.3 Factor independent urate hydroxylase @@ -947,7 +981,6 @@ 1.7.7.2 Ferredoxin--nitrate reductase 1.7.99.1 Hydroxylamine reductase 1.7.99.4 Nitrate reductase -1.7.99.8 Hydrazine oxidoreductase 1.8.1.2 Assimilatory sulfite reductase (NADPH) 1.8.1.3 Hypotaurine dehydrogenase 1.8.1.4 Dihydrolipoyl dehydrogenase @@ -966,10 +999,11 @@ 1.8.1.17 Dimethylsulfone reductase 1.8.1.18 NAD(P)H sulfur oxidoreductase (CoA-dependent) 1.8.1.19 Sulfide dehydrogenase -1.8.2.1 Sulfite dehydrogenase +1.8.2.1 Sulfite dehydrogenase (cytochrome) 1.8.2.2 Thiosulfate dehydrogenase 1.8.2.3 Sulfide-cytochrome-c reductase (flavocytochrome c) 1.8.2.4 Dimethyl sulfide:cytochrome c2 reductase +1.8.2.5 Thiosulfate reductase (cytochrome) 1.8.3.1 Sulfite oxidase 1.8.3.2 Thiol oxidase 1.8.3.3 Glutathione oxidase @@ -992,13 +1026,15 @@ 1.8.5.2 Thiosulfate dehydrogenase (quinone) 1.8.5.3 Dimethylsulfoxide reductase 1.8.5.4 Sulfide:quinone reductase +1.8.5.5 Thiosulfate reductase (quinone) +1.8.5.6 Sulfite dehydrogenase (quinone) +1.8.5.7 Glutathionyl-hydroquinone reductase 1.8.7.1 Assimilatory sulfite reductase (ferredoxin) 1.8.7.2 Ferredoxin:thioredoxin reductase 1.8.98.1 CoB--CoM heterodisulfide reductase 1.8.98.2 Sulfiredoxin 1.8.98.3 Sulfite reductase (coenzyme F420) 1.8.99.2 Adenylyl-sulfate reductase -1.8.99.3 Hydrogensulfite reductase 1.8.99.5 Dissimilatory sulfite reductase 1.9.3.1 Cytochrome-c oxidase 1.9.6.1 Nitrate reductase (cytochrome) @@ -1019,6 +1055,7 @@ 1.10.3.13 Caldariellaquinol oxidase (H(+)-transporting) 1.10.3.14 Ubiquinol oxidase (electrogenic, non H(+)-transporting) 1.10.3.15 Grixazone synthase +1.10.3.16 Dihydrophenazinedicarboxylate synthase 1.10.5.1 Ribosyldihydronicotinamide dehydrogenase (quinone) 1.10.9.1 Plastoquinol--plastocyanin reductase 1.11.1.1 NADH peroxidase @@ -1173,7 +1210,7 @@ 1.14.11.16 Peptide-aspartate beta-dioxygenase 1.14.11.17 Taurine dioxygenase 1.14.11.18 Phytanoyl-CoA dioxygenase -1.14.11.19 Leucocyanidin oxygenase +1.14.11.19 Anthocyanidin synthase 1.14.11.20 Deacetoxyvindoline 4-hydroxylase 1.14.11.21 Clavaminate synthase 1.14.11.22 Flavone synthase @@ -1205,8 +1242,14 @@ 1.14.11.48 Xanthine dioxygenase 1.14.11.49 Uridine-5'-phosphate dioxygenase 1.14.11.50 (-)-deoxypodophyllotoxin synthase +1.14.11.51 DNA N(6)-methyladenine demethylase +1.14.11.52 Validamycin A dioxygenase +1.14.11.53 mRNA N(6)-methyladenine demethylase +1.14.11.54 mRNA N(1)-methyladenine demethylase +1.14.11.55 Ectoine hydroxylase +1.14.11.56 L-proline cis-4-hydroxylase +1.14.11.57 L-proline trans-4-hydroxylase 1.14.11.n2 Methylcytosine dioxygenase -1.14.11.n3 L-proline cis-4-hydroxylase 1.14.11.n4 Ankyrin-repeat-histidine dioxagenase 1.14.12.1 Anthranilate 1,2-dioxygenase (deaminating, decarboxylating) 1.14.12.3 Benzene 1,2-dioxygenase @@ -1228,6 +1271,7 @@ 1.14.12.22 Carbazole 1,9a-dioxygenase 1.14.12.23 Nitroarene dioxygenase 1.14.12.24 2,4-dinitrotoluene dioxygenase +1.14.12.25 p-cumate 2,3-dioxygenase 1.14.13.1 Salicylate 1-monooxygenase 1.14.13.2 4-hydroxybenzoate 3-monooxygenase 1.14.13.4 Melilotate 3-monooxygenase @@ -1239,7 +1283,6 @@ 1.14.13.10 2,6-dihydroxypyridine 3-monooxygenase 1.14.13.11 Trans-cinnamate 4-monooxygenase 1.14.13.12 Benzoate 4-monooxygenase -1.14.13.13 Calcidiol 1-monooxygenase 1.14.13.14 Trans-cinnamate 2-monooxygenase 1.14.13.16 Cyclopentanone monooxygenase 1.14.13.18 4-hydroxyphenylacetate 1-monooxygenase @@ -1261,10 +1304,9 @@ 1.14.13.35 Anthranilate 3-monooxygenase (deaminating) 1.14.13.36 5-O-(4-coumaroyl)-D-quinate 3'-monooxygenase 1.14.13.37 Methyltetrahydroprotoberberine 14-monooxygenase -1.14.13.38 Anhydrotetracycline monooxygenase +1.14.13.38 Anhydrotetracycline 6-monooxygenase 1.14.13.39 Nitric-oxide synthase (NADPH) 1.14.13.40 Anthraniloyl-CoA monooxygenase -1.14.13.41 Tyrosine N-monooxygenase 1.14.13.43 Questin monooxygenase 1.14.13.44 2-hydroxybiphenyl 3-monooxygenase 1.14.13.46 (-)-menthol monooxygenase @@ -1287,7 +1329,6 @@ 1.14.13.64 4-hydroxybenzoate 1-hydroxylase 1.14.13.66 2-hydroxycyclohexanone 2-monooxygenase 1.14.13.67 Quinine 3-monooxygenase -1.14.13.68 4-hydroxyphenylacetaldehyde oxime monooxygenase 1.14.13.69 Alkene monooxygenase 1.14.13.70 Sterol 14-alpha-demethylase 1.14.13.71 N-methylcoclaurine 3'-monooxygenase @@ -1308,14 +1349,12 @@ 1.14.13.87 Licodione synthase 1.14.13.88 Flavonoid 3',5'-hydroxylase 1.14.13.89 Isoflavone 2'-hydroxylase -1.14.13.90 Zeaxanthin epoxidase 1.14.13.91 Deoxysarpagine hydroxylase 1.14.13.92 Phenylacetone monooxygenase 1.14.13.93 (+)-abscisic acid 8'-hydroxylase 1.14.13.94 Lithocholate 6-beta-hydroxylase 1.14.13.96 5-beta-cholestane-3-alpha,7-alpha-diol 12-alpha-hydroxylase 1.14.13.97 Taurochenodeoxycholate 6-alpha-hydroxylase -1.14.13.100 25/26-hydroxycholesterol 7-alpha-hydroxylase 1.14.13.101 Senecionine N-oxygenase 1.14.13.102 Psoralen synthase 1.14.13.103 8-dimethylallylnaringenin 2'-hydroxylase @@ -1326,20 +1365,17 @@ 1.14.13.108 Abieta-7,13-diene hydroxylase 1.14.13.109 Abieta-7,13-dien-18-ol hydroxylase 1.14.13.110 Geranylgeraniol 18-hydroxylase -1.14.13.111 Methanesulfonate monooxygenase +1.14.13.111 Methanesulfonate monooxygenase (NADH) 1.14.13.112 3-epi-6-deoxocathasterone 23-monooxygenase 1.14.13.113 FAD-dependent urate hydroxylase 1.14.13.114 6-hydroxynicotinate 3-monooxygenase 1.14.13.115 Angelicin synthase 1.14.13.116 Geranylhydroquinone 3''-hydroxylase -1.14.13.117 Isoleucine N-monooxygenase -1.14.13.118 Valine N-monooxygenase 1.14.13.119 5-epiaristolochene 1,3-dihydroxylase 1.14.13.120 Costunolide synthase 1.14.13.121 Premnaspirodiene oxygenase -1.14.13.122 Chlorophyllide-a oxygenase +1.14.13.122 Chlorophyllide a oxygenase 1.14.13.123 Germacrene A hydroxylase -1.14.13.124 Phenylalanine N-monooxygenase 1.14.13.125 Tryptophan N-monooxygenase 1.14.13.127 3-(3-hydroxy-phenyl)propanoic acid hydroxylase 1.14.13.128 7-methylxanthine demethylase @@ -1354,7 +1390,7 @@ 1.14.13.138 Indolin-2-one monooxygenase 1.14.13.139 3-hydroxyindolin-2-one monooxygenase 1.14.13.140 2-hydroxy-1,4-benzoxazin-3-one monooxygenase -1.14.13.141 Cholest-4-en-3-one 26-monooxygenase +1.14.13.141 Cholest-4-en-3-one 26-monooxygenase ((25S)-3-oxocholest-4-en-26-oate forming) 1.14.13.142 3-ketosteroid 9-alpha-monooxygenase 1.14.13.143 Ent-isokaurene C2-hydroxylase 1.14.13.144 9-beta-pimara-7,15-diene oxidase @@ -1417,7 +1453,6 @@ 1.14.13.204 Long-chain acyl-CoA omega-monooxygenase 1.14.13.205 Long-chain fatty acid omega-monooxygenase 1.14.13.206 Laurate 7-monooxygenase -1.14.13.207 Ipsdienol synthase 1.14.13.208 Benzoyl-CoA 2,3-epoxidase 1.14.13.209 Salicyloyl-CoA 5-hydroxylase 1.14.13.210 4-methyl-5-nitrocatechol 5-monooxygenase @@ -1428,12 +1463,27 @@ 1.14.13.215 Protoasukamycin 4-monooxygenase 1.14.13.216 Asperlicin C monooxygenase 1.14.13.217 Protodeoxyviolaceinate monooxygenase -1.14.13.n5 Dihomomethionine N-hydroxylase +1.14.13.218 5-methylphenazine-1-carboxylate 1-monooxygenase +1.14.13.219 Resorcinol 4-hydroxylase (NADPH) +1.14.13.220 Resorcinol 4-hydroxylase (NADH) +1.14.13.221 Cholest-4-en-3-one 26-monooxygenase ((25R)-3-oxocholest-4-en-26-oate forming) +1.14.13.222 Aurachin C monooxygenase/isomerase +1.14.13.223 3-hydroxy-4-methyl-anthranilyl-[aryl-carrier protein] 5-monooxygenase +1.14.13.224 Violacein synthase +1.14.13.225 F-actin monooxygenase +1.14.13.226 Acetone monooxygenase (methyl acetate-forming) +1.14.13.227 Propane 2-monooxygenase +1.14.13.228 Jasmomic acid 12-hydroxylase +1.14.13.229 Tert-butanol monooxygenase +1.14.13.230 Butane monooxygenase (soluble) +1.14.13.231 Tetracycline 11a-monooxygenase +1.14.13.232 6-methylpretetramide 4-monooxygenase +1.14.13.233 4-hydroxy-6-methylpretetramide 12a-monooxygenase +1.14.13.234 12-dehydrotetracycline 5-monooxygenase 1.14.13.n6 Hexahomomethionine N-hydroxylase 1.14.13.n7 4-nitrophenol 2-hydroxylase -1.14.13.n8 2-methylbutanal oxime monooxygenase 1.14.14.1 Unspecific monooxygenase -1.14.14.3 Alkanal monooxygenase (FMN-linked) +1.14.14.3 Bacterial luciferase 1.14.14.5 Alkanesulfonate monooxygenase 1.14.14.8 Anthranilate 3-monooxygenase (FAD) 1.14.14.9 4-hydroxyphenylacetate 3-monooxygenase @@ -1454,6 +1504,23 @@ 1.14.14.24 Vitamin D 25-hydroxylase 1.14.14.25 Cholesterol 24-hydroxylase 1.14.14.26 24-hydroxycholesterol 7-alpha-hydroxylase +1.14.14.27 Resorcinol 4-hydroxylase (FADH(2)) +1.14.14.28 Long-chain alkane monooxygenase +1.14.14.29 25/26-hydroxycholesterol 7-alpha-hydroxylase +1.14.14.30 Isobutylamine N-monooxygenase +1.14.14.31 Ipsdienol synthase +1.14.14.32 17-alpha-hydroxyprogesterone deacetylase +1.14.14.33 Ethylenediaminetetraacetate monooxygenase +1.14.14.34 Methanesulfonate monooxygenase (FMNH(2)) +1.14.14.35 Dimethylsulfone monooxygenase +1.14.14.36 Tyrosine N-monooxygenase +1.14.14.37 4-hydroxyphenylacetaldehyde oxime monooxygenase +1.14.14.38 Valine N-monooxygenase +1.14.14.39 Isoleucine N-monooxygenase +1.14.14.40 Phenylalanine N-monooxygenase +1.14.14.41 (E)-2-methylbutanal oxime monooxygenase +1.14.14.42 Homomethionine N-monooxygenase +1.14.14.43 (Methylsulfanyl)alkanaldoxime N-monooxygenase 1.14.15.1 Camphor 5-monooxygenase 1.14.15.3 Alkane 1-monooxygenase 1.14.15.4 Steroid 11-beta-monooxygenase @@ -1470,6 +1537,11 @@ 1.14.15.15 Cholestanetriol 26-monooxygenase 1.14.15.16 Vitamin D(3) 24-hydroxylase 1.14.15.17 Pheophorbide a oxygenase +1.14.15.18 Calcidiol 1-monooxygenase +1.14.15.19 C-19 steroid 1-alpha-hydroxylase +1.14.15.20 Heme oxygenase (biliverdin-producing, ferredoxin) +1.14.15.21 Zeaxanthin epoxidase +1.14.15.22 Vitamin D 1,25-hydroxylase 1.14.16.1 Phenylalanine 4-monooxygenase 1.14.16.2 Tyrosine 3-monooxygenase 1.14.16.3 Anthranilate 3-monooxygenase @@ -1534,6 +1606,9 @@ 1.14.19.45 sn-1 oleoyl-lipid 12-desaturase 1.14.19.46 sn-1 linoleoyl-lipid 6-desaturase 1.14.19.47 Acyl-lipid (9-3)-desaturase +1.14.19.48 Tert-amyl alcohol desaturase +1.14.19.49 Tetracycline 7-halogenase +1.14.19.50 Noroxomaritidine synthase 1.14.19.n4 Stearoyl-CoA 9-desaturase 1.14.19.n5 Versicolorin B desaturase 1.14.20.1 Deacetoxycephalosporin-C synthase @@ -1549,6 +1624,7 @@ 1.14.21.9 Mycocyclosin synthase 1.14.21.10 Fumitremorgin C synthase 1.14.21.11 (-)-pluviatolide synthase +1.14.21.12 (S)-nandinine synthase 1.14.99.1 Prostaglandin-endoperoxide synthase 1.14.99.2 Kynurenine 7,8-hydroxylase 1.14.99.4 Progesterone monooxygenase @@ -1563,11 +1639,9 @@ 1.14.99.23 3-hydroxybenzoate 2-monooxygenase 1.14.99.24 Steroid 9-alpha-monooxygenase 1.14.99.26 2-hydroxypyridine 5-monooxygenase -1.14.99.27 Juglone 3-monooxygenase 1.14.99.29 Deoxyhypusine monooxygenase 1.14.99.34 Monoprenyl isoflavone epoxidase 1.14.99.35 Thiophene-2-carbonyl-CoA monooxygenase -1.14.99.36 Beta-carotene 15,15'-monooxygenase 1.14.99.37 Taxadiene 5-alpha-hydroxylase 1.14.99.38 Cholesterol 25-hydroxylase 1.14.99.39 Ammonia monooxygenase @@ -1582,6 +1656,7 @@ 1.14.99.50 Gamma-glutamyl hercynylcysteine S-oxide synthase 1.14.99.51 Hercynylcysteine S-oxide synthase 1.14.99.52 L-cysteinyl-L-histidinylsulfoxide synthase +1.14.99.53 Lytic chitin monooxygenase 1.14.99.n4 Carotenoid 9,10-dioxygenase 1.15.1.1 Superoxide dismutase 1.15.1.2 Superoxide reductase @@ -1610,8 +1685,9 @@ 1.17.3.1 Pteridine oxidase 1.17.3.2 Xanthine oxidase 1.17.3.3 6-hydroxynicotinate dehydrogenase +1.17.3.4 Juglone 3-hydroxylase 1.17.4.1 Ribonucleoside-diphosphate reductase -1.17.4.2 Ribonucleoside-triphosphate reductase +1.17.4.2 Ribonucleoside-triphosphate reductase (thioredoxin) 1.17.4.4 Vitamin-K-epoxide reductase (warfarin-sensitive) 1.17.4.5 Vitamin-K-epoxide reductase (warfarin-insensitive) 1.17.5.1 Phenylacetyl-CoA dehydrogenase @@ -1620,7 +1696,8 @@ 1.17.7.2 7-hydroxymethyl chlorophyll a reductase 1.17.7.3 (E)-4-hydroxy-3-methylbut-2-enyl-diphosphate synthase (flavodoxin) 1.17.7.4 4-hydroxy-3-methylbut-2-enyl diphosphate reductase -1.17.98.1 Bile-acid 7-alpha-dehydroxylase +1.17.8.1 Hydroxysqualene dehydroxylase +1.17.98.2 Bacteriochlorophyllide c C-7(1)-hydroxylase 1.17.99.1 4-methylphenol dehydrogenase (hydroxylating) 1.17.99.2 Ethylbenzene hydroxylase 1.17.99.3 3-alpha,7-alpha,12-alpha-trihydroxy-5-beta-cholestanoyl-CoA 24-hydroxylase @@ -1635,6 +1712,7 @@ 1.18.1.7 Ferredoxin--NAD(P)(+) reductase (naphthalene dioxygenase ferredoxin-specific) 1.18.1.8 Ferredoxin-NAD(+) oxidoreductase (Na(+)-transporting) 1.18.6.1 Nitrogenase +1.19.1.1 Flavodoxin--NADP(+) reductase 1.19.6.1 Nitrogenase (flavodoxin) 1.20.1.1 Phosphonate dehydrogenase 1.20.2.1 Arsenate reductase (cytochrome c) @@ -1660,9 +1738,11 @@ 1.21.4.4 Betaine reductase 1.21.98.1 Cyclic dehypoxanthinyl futalosine synthase 1.21.98.2 Dichlorochromopyrrolate synthase +1.21.98.3 Anaerobic magnesium-protoporphyrin IX monomethyl ester cyclase 1.21.99.1 Beta-cyclopiazonate dehydrogenase 1.21.99.3 Thyroxine 5-deiodinase 1.21.99.4 Thyroxine 5'-deiodinase +1.21.99.5 Tetrachloroethene reductive dehalogenase 1.23.1.1 (+)-pinoresinol reductase 1.23.1.2 (+)-lariciresinol reductase 1.23.1.3 (-)-pinoresinol reductase @@ -1671,7 +1751,6 @@ 1.97.1.1 Chlorate reductase 1.97.1.2 Pyrogallol hydroxytransferase 1.97.1.4 [Formate-C-acetyltransferase]-activating enzyme -1.97.1.8 Tetrachloroethene reductive dehalogenase 1.97.1.9 Selenate reductase 1.97.1.12 Photosystem I 2.1.1.1 Nicotinamide N-methyltransferase @@ -1974,12 +2053,26 @@ 2.1.1.322 Type IV protein arginine methyltransferase 2.1.1.323 (-)-pluviatolide 4-O-methyltransferase 2.1.1.324 dTDP-4-amino-2,3,4,6-tetradeoxy-D-glucose N,N-dimethyltransferase +2.1.1.325 Juvenile hormone-III synthase +2.1.1.326 N-acetyl-demethylphosphinothricin P-methyltransferase +2.1.1.327 Phenazine-1-carboxylate N-methyltransferase +2.1.1.328 N-demethylindolmycin N-methyltransferase +2.1.1.329 Demethylphylloquinol methyltransferase +2.1.1.330 5'-demethylyatein 5'-O-methyltransferase +2.1.1.331 Bacteriochlorophyllide d C-12(1)-methyltransferase +2.1.1.332 Bacteriochlorophyllide d C-8(2)-methyltransferase +2.1.1.333 Bacteriochlorophyllide d C-20 methyltransferase +2.1.1.334 Methanethiol S-methyltransferase +2.1.1.335 4-amino-anhydrotetracycline N(4)-methyltransferase +2.1.1.336 Norbelladine O-methyltransferase +2.1.1.337 Reticuline N-methyltransferase +2.1.1.338 Desmethylxanthohumol 6'-O-methyltransferase +2.1.1.339 Xanthohumol 4'-O-methyltransferase 2.1.1.n1 Resorcinol O-methyltransferase 2.1.1.n4 Thiocyanate methyltransferase 2.1.1.n7 5-pentadecatrienyl resorcinol O-methyltransferase 2.1.1.n8 Small RNA 2'-O-methyltransferase 2.1.1.n11 Methylphosphotriester-DNA--[protein]-cysteine S-methyltransferase -2.1.1.n12 2-phytyl-1,4-naphtoquinone methyltransferase 2.1.2.1 Glycine hydroxymethyltransferase 2.1.2.2 Phosphoribosylglycinamide formyltransferase 2.1.2.3 Phosphoribosylaminoimidazolecarboxamide formyltransferase @@ -2101,7 +2194,6 @@ 2.3.1.85 Fatty-acid synthase 2.3.1.86 Fatty-acyl-CoA synthase 2.3.1.87 Aralkylamine N-acetyltransferase -2.3.1.88 Peptide alpha-N-acetyltransferase 2.3.1.89 Tetrahydrodipicolinate N-acetyltransferase 2.3.1.90 Beta-glucogallin O-galloyltransferase 2.3.1.91 Sinapoylglucose--choline O-sinapoyltransferase @@ -2163,7 +2255,6 @@ 2.3.1.151 2,3',4,6-tetrahydroxybenzophenone synthase 2.3.1.152 Alcohol O-cinnamoyltransferase 2.3.1.153 Anthocyanin 5-(6'''-hydroxycinnamoyltransferase) -2.3.1.154 Propionyl-CoA C(2)-trimethyltridecanoyltransferase 2.3.1.155 Acetyl-CoA C-myristoyltransferase 2.3.1.156 Phloroisovalerophenone synthase 2.3.1.157 Glucosamine-1-phosphate N-acetyltransferase @@ -2261,6 +2352,18 @@ 2.3.1.249 Spermidine dicoumaroyl transferase 2.3.1.250 [Wnt protein] O-palmitoleoyl transferase 2.3.1.251 Lipid IV(A) palmitoyltransferase +2.3.1.252 Mycolipanoate synthase +2.3.1.253 Phloroglucinol synthase +2.3.1.254 N-terminal methionine N(alpha)-acetyltransferase NatB +2.3.1.255 N-terminal amino-acid N(alpha)-acetyltransferase NatA +2.3.1.256 N-terminal methionine N(alpha)-acetyltransferase NatC +2.3.1.257 N-terminal L-serine N(alpha)-acetyltransferase NatD +2.3.1.258 N-terminal methionine N(alpha)-acetyltransferase NatE +2.3.1.259 N-terminal methionine N(alpha)-acetyltransferase NatF +2.3.1.260 Tetracycline polyketide synthase +2.3.1.261 (4-hydroxyphenyl)alkanoate synthase +2.3.1.262 Anthraniloyl-CoA anthraniloyltransferase +2.3.1.263 2-amino-4-oxopentanoate thiolase 2.3.1.n2 Phosphate acyltransferase 2.3.1.n3 Glycerol-3-phosphate acyltransferase (acyl-phosphate transferring) 2.3.1.n4 1-acyl-sn-glycerol-3-phosphate acyltransferase @@ -2273,7 +2376,7 @@ 2.3.2.3 Lysyltransferase 2.3.2.4 Gamma-glutamylcyclotransferase 2.3.2.5 Glutaminyl-peptide cyclotransferase -2.3.2.6 Leucyltransferase +2.3.2.6 Lysine/arginine leucyltransferase 2.3.2.7 Aspartyltransferase 2.3.2.8 Arginyltransferase 2.3.2.9 Agaritine gamma-glutamyltransferase @@ -2296,6 +2399,7 @@ 2.3.2.26 HECT-type E3 ubiquitin transferase 2.3.2.27 RING-type E3 ubiquitin transferase 2.3.2.28 L-allo-isoleucyltransferase +2.3.2.29 Aspartate/glutamate leucyltransferase 2.3.3.1 Citrate (Si)-synthase 2.3.3.2 Decylcitrate synthase 2.3.3.3 Citrate (Re)-synthase @@ -2312,6 +2416,8 @@ 2.3.3.14 Homocitrate synthase 2.3.3.15 Sulfoacetaldehyde acetyltransferase 2.3.3.16 Citrate synthase (unknown stereospecificity) +2.3.3.17 Methylthioalkylmalate synthase +2.3.3.18 2-phosphinomethylmalate synthase 2.4.1.1 Glycogen phosphorylase 2.4.1.2 Dextrin dextranase 2.4.1.4 Amylosucrase @@ -2353,7 +2459,6 @@ 2.4.1.41 Polypeptide N-acetylgalactosaminyltransferase 2.4.1.43 Polygalacturonate 4-alpha-galacturonosyltransferase 2.4.1.44 Lipopolysaccharide 3-alpha-galactosyltransferase -2.4.1.45 2-hydroxyacylsphingosine 1-beta-galactosyltransferase 2.4.1.46 Monogalactosyldiacylglycerol synthase 2.4.1.47 N-acylsphingosine galactosyltransferase 2.4.1.48 Heteroglycan alpha-mannosyltransferase @@ -2373,7 +2478,7 @@ 2.4.1.66 Procollagen glucosyltransferase 2.4.1.67 Galactinol--raffinose galactosyltransferase 2.4.1.68 Glycoprotein 6-alpha-L-fucosyltransferase -2.4.1.69 Galactoside 2-alpha-L-fucosyltransferase +2.4.1.69 Type 1 galactoside alpha-(1,2)-fucosyltransferase 2.4.1.70 Poly(ribitol-phosphate) N-acetylglucosaminyltransferase 2.4.1.71 Arylamine glucosyltransferase 2.4.1.73 Lipopolysaccharide glucosyltransferase II @@ -2414,7 +2519,7 @@ 2.4.1.118 Cytokinin 7-beta-glucosyltransferase 2.4.1.120 Sinapate 1-glucosyltransferase 2.4.1.121 Indole-3-acetate beta-glucosyltransferase -2.4.1.122 Glycoprotein-N-acetylgalactosamine 3-beta-galactosyltransferase +2.4.1.122 N-acetylgalactosaminide beta-1,3-galactosyltransferase 2.4.1.123 Inositol 3-alpha-galactosyltransferase 2.4.1.125 Sucrose--1,6-alpha-glucan 3(6)-alpha-glucosyltransferase 2.4.1.126 Hydroxycinnamate 4-beta-glucosyltransferase @@ -2445,13 +2550,11 @@ 2.4.1.153 UDP-N-acetylglucosamine--dolichyl-phosphate N-acetylglucosaminyltransferase 2.4.1.155 Alpha-1,6-mannosyl-glycoprotein 6-beta-N-acetylglucosaminyltransferase 2.4.1.156 Indolylacetyl-myo-inositol galactosyltransferase -2.4.1.157 1,2-diacylglycerol 3-glucosyltransferase 2.4.1.158 13-hydroxydocosanoate 13-beta-glucosyltransferase 2.4.1.159 Flavonol-3-O-glucoside L-rhamnosyltransferase 2.4.1.160 Pyridoxine 5'-O-beta-D-glucosyltransferase 2.4.1.161 Oligosaccharide 4-alpha-D-glucosyltransferase 2.4.1.162 Aldose beta-D-fructosyltransferase -2.4.1.163 Beta-galactosyl-N-acetylglucosaminylgalactosylglucosyl-ceramide beta-1,3-acetylglucosaminyltransferase 2.4.1.164 Galactosyl-N-acetylglucosaminylgalactosylglucosyl-ceramide beta-1,6-N-acetylglucosaminyltransferase 2.4.1.165 N-acetylneuraminylgalactosylglucosylceramide beta-1,4-N-acetylgalactosaminyltransferase 2.4.1.166 Raffinose--raffinose alpha-galactosyltransferase @@ -2508,7 +2611,7 @@ 2.4.1.220 Indoxyl-UDPG glucosyltransferase 2.4.1.221 Peptide-O-fucosyltransferase 2.4.1.222 O-fucosylpeptide 3-beta-N-acetylglucosaminyltransferase -2.4.1.223 Glucuronyl-galactosyl-proteoglycan 4-alpha-N-acetylglucosaminyltransferase +2.4.1.223 Glucuronosyl-galactosyl-proteoglycan 4-alpha-N-acetylglucosaminyltransferase 2.4.1.224 Glucuronosyl-N-acetylglucosaminyl-proteoglycan 4-alpha-N-acetylglucosaminyltransferase 2.4.1.225 N-acetylglucosaminyl-proteoglycan 4-beta-glucuronosyltransferase 2.4.1.226 N-acetylgalactosaminyl-proteoglycan 3-beta-glucuronosyltransferase @@ -2547,7 +2650,7 @@ 2.4.1.261 Dolichyl-P-Man:Man(8)GlcNAc(2)-PP-dolichol alpha-1,2-mannosyltransferase 2.4.1.262 Soyasapogenol glucuronosyltransferase 2.4.1.263 Abscisate beta-glucosyltransferase -2.4.1.264 D-man-alpha-(1->3)-D-Glc-beta-(1->4)-D-Glc-alpha-1-diphosphoundecaprenol 2-beta-glucuronyltransferase +2.4.1.264 D-man-alpha-(1->3)-D-Glc-beta-(1->4)-D-Glc-alpha-1-diphosphoundecaprenol 2-beta-glucuronosyltransferase 2.4.1.265 Dolichyl-P-Glc:Glc(1)Man(9)GlcNAc(2)-PP-dolichol alpha-1,3-glucosyltransferase 2.4.1.266 Glucosyl-3-phosphoglycerate synthase 2.4.1.267 Dolichyl-P-Glc:Man(9)GlcNAc(2)-PP-dolichol alpha-1,3-glucosyltransferase @@ -2570,7 +2673,7 @@ 2.4.1.284 2-deoxystreptamine glucosyltransferase 2.4.1.285 UDP-GlcNAc:ribostamycin N-acetylglucosaminyltransferase 2.4.1.286 Chalcone 4'-O-glucosyltransferase -2.4.1.287 Rhamnopyranosyl-N-acetylglucosaminyl-diphospho-decaprenol beta-1,3/1,4-galactofuranosyltransferase +2.4.1.287 Rhamnopyranosyl-N-acetylglucosaminyl-diphospho-decaprenol beta-1,4/1,5-galactofuranosyltransferase 2.4.1.288 Galactofuranosylgalactofuranosylrhamnosyl-N-acetylglucosaminyl-diphospho-decaprenol beta-1,5/1,6-galactofuranosyltransferase 2.4.1.289 N-acetylglucosaminyl-diphospho-decaprenol L-rhamnosyltransferase 2.4.1.290 N,N'-diacetylbacillosaminyl-diphospho-undecaprenol alpha-1,3-N-acetylgalactosaminyltransferase @@ -2590,7 +2693,6 @@ 2.4.1.304 UDP-Gal:alpha-D-GlcNAc-diphosphoundecaprenol beta-1,4-galactosyltransferase 2.4.1.305 UDP-Glc:alpha-D-GlcNAc-glucosaminyl-diphosphoundecaprenol beta-1,3-glucosyltransferase 2.4.1.306 UDP-GalNAc:alpha-D-GalNAc-diphosphoundecaprenol alpha-1,3-N-acetylgalactosaminyltransferase -2.4.1.307 UDP-Gal:alpha-D-GalNAc-1,3-alpha-D-GalNAc-diphosphoundecaprenol beta-1,3-galactosyltransferase 2.4.1.308 GDP-Fuc:beta-D-Gal-1,3-alpha-D-GalNAc-1,3-alpha-GalNAc-diphosphoundecaprenol alpha-1,2-fucosyltransferase 2.4.1.309 UDP-Gal:alpha-L-Fuc-1,2-beta-Gal-1,3-alpha-GalNAc-1,3-alpha-GalNAc-diphosphoundecaprenol alpha-1,3-galactosyltransferase 2.4.1.310 Vancomycin aglycone glucosyltransferase @@ -2621,6 +2723,13 @@ 2.4.1.335 Dolichyl N-acetyl-alpha-D-glucosaminyl phosphate 3-beta-D-2,3-diacetamido-2,3-dideoxy-beta-D-glucuronosyltransferase 2.4.1.336 Monoglucosyldiacylglycerol synthase 2.4.1.337 1,2-diacylglycerol 3-alpha-glucosyltransferase +2.4.1.338 Validoxylamine A glucosyltransferase +2.4.1.339 Beta-1,2-mannobiose phosphorylase +2.4.1.340 1,2-beta-oligomannan phosphorylase +2.4.1.341 Alpha-1,2-colitosyltransferase +2.4.1.342 Alpha-maltose-1-phosphate synthase +2.4.1.343 UDP-Gal:alpha-D-GlcNAc-diphosphoundecaprenol alpha-1,3-galactosyltransferase +2.4.1.344 Type 2 galactoside alpha-(1,2)-fucosyltransferase 2.4.1.n2 Loliose synthase 2.4.2.1 Purine-nucleoside phosphorylase 2.4.2.2 Pyrimidine-nucleoside phosphorylase @@ -2676,9 +2785,10 @@ 2.4.2.55 Nicotinate D-ribonucleotide:phenol phospho-D-ribosyltransferase 2.4.2.56 Kaempferol 3-O-xylosyltransferase 2.4.2.57 AMP phosphorylase +2.4.2.58 Hydroxyproline O-arabinosyltransferase 2.4.2.n2 Glucoside xylosyltransferase 2.4.2.n3 Xyloside xylosyltransferase -2.4.99.1 Beta-galactoside alpha-2,6-sialyltransferase +2.4.99.1 Beta-galactoside alpha-(2,6)-sialyltransferase 2.4.99.2 Monosialoganglioside sialyltransferase 2.4.99.3 Alpha-N-acetylgalactosaminide alpha-2,6-sialyltransferase 2.4.99.4 Beta-galactoside alpha-2,3-sialyltransferase @@ -2688,7 +2798,6 @@ 2.4.99.8 Alpha-N-acetylneuraminate alpha-2,8-sialyltransferase 2.4.99.9 Lactosylceramide alpha-2,3-sialyltransferase 2.4.99.10 Neolactotetraosylceramide alpha-2,3-sialyltransferase -2.4.99.11 Lactosylceramide alpha-2,6-N-sialyltransferase 2.4.99.12 Lipid IV(A) 3-deoxy-D-manno-octulosonic acid transferase 2.4.99.13 (Kdo)-lipid IV(A) 3-deoxy-D-manno-octulosonic acid transferase 2.4.99.14 (Kdo)(2)-lipid IV(A) (2-8) 3-deoxy-D-manno-octulosonic acid transferase @@ -2821,6 +2930,14 @@ 2.5.1.129 Flavin prenyltransferase 2.5.1.130 2-carboxy-1,4-naphthoquinone phytyltransferase 2.5.1.131 (4-(4-(2-(gamma-L-glutamylamino)ethyl)phenoxymethyl)furan-2-yl)methanamine synthase +2.5.1.132 3-deoxy-D-glycero-D-galacto-nononate 9-phosphate synthase +2.5.1.133 Bacteriochlorophyll a synthase +2.5.1.134 Cystathionine beta-synthase (O-acetyl-L-serine) +2.5.1.135 Validamine 7-phosphate valienyltransferase +2.5.1.136 2-acylphloroglucinol 4-prenyltransferase +2.5.1.137 2-acyl-4-prenylphloroglucinol 6-prenyltransferase +2.5.1.138 Coumarin 8-geranyltransferase +2.5.1.139 Umbelliferone 6-dimethylallyltransferase 2.5.1.n9 Heptaprenylglyceryl phosphate synthase 2.6.1.1 Aspartate transaminase 2.6.1.2 Alanine transaminase @@ -2884,7 +3001,6 @@ 2.6.1.65 N(6)-acetyl-beta-lysine transaminase 2.6.1.66 Valine--pyruvate transaminase 2.6.1.67 2-aminohexanoate transaminase -2.6.1.68 Ornithine(lysine) transaminase 2.6.1.70 Aspartate--phenylpyruvate transaminase 2.6.1.71 Lysine--pyruvate 6-transaminase 2.6.1.72 D-4-hydroxyphenylglycine transaminase @@ -2925,6 +3041,8 @@ 2.6.1.108 (5-formylfuran-3-yl)methyl phosphate transaminase 2.6.1.109 8-amino-3,8-dideoxy-alpha-D-manno-octulosonate transaminase 2.6.1.110 dTDP-4-dehydro-2,3,6-trideoxy-D-glucose 4-aminotransferase +2.6.1.111 3-aminobutanoyl-CoA transaminase +2.6.1.112 (S)-ureidoglycine--glyoxylate transaminase 2.6.3.1 Oximinotransferase 2.6.99.1 dATP(dGTP)--DNA purinetransferase 2.6.99.2 Pyridoxine 5'-phosphate synthase @@ -2954,7 +3072,7 @@ 2.7.1.24 Dephospho-CoA kinase 2.7.1.25 Adenylyl-sulfate kinase 2.7.1.26 Riboflavin kinase -2.7.1.27 Erythritol kinase +2.7.1.27 Erythritol kinase (D-erythritol 4-phosphate-forming) 2.7.1.28 Triokinase 2.7.1.29 Glycerone kinase 2.7.1.30 Glycerol kinase @@ -3012,7 +3130,7 @@ 2.7.1.88 Dihydrostreptomycin-6-phosphate 3'-alpha-kinase 2.7.1.89 Thiamine kinase 2.7.1.90 Diphosphate--fructose-6-phosphate 1-phosphotransferase -2.7.1.91 Sphinganine kinase +2.7.1.91 Sphingosine kinase 2.7.1.92 5-dehydro-2-deoxygluconokinase 2.7.1.93 Alkylglycerol kinase 2.7.1.94 Acylglycerol kinase @@ -3103,6 +3221,14 @@ 2.7.1.206 Protein-N(pi)-phosphohistidine--L-sorbose phosphotransferase 2.7.1.207 Protein-N(pi)-phosphohistidine--lactose phosphotransferase 2.7.1.208 Protein-N(pi)-phosphohistidine--maltose phosphotransferase +2.7.1.209 L-erythrulose 4-kinase +2.7.1.210 D-erythrulose 4-kinase +2.7.1.211 Protein-N(pi)-phosphohistidine--sucrose phosphotransferase +2.7.1.212 Alpha-D-ribose-1-phosphate 5-kinase (ADP) +2.7.1.213 Cytidine kinase +2.7.1.214 C(7)-cyclitol 7-kinase +2.7.1.215 Erythritol kinase (D-erythritol 1-phosphate-forming) +2.7.1.216 Farnesol kinase 2.7.2.1 Acetate kinase 2.7.2.2 Carbamate kinase 2.7.2.3 Phosphoglycerate kinase @@ -3131,7 +3257,7 @@ 2.7.4.3 Adenylate kinase 2.7.4.4 Nucleoside-phosphate kinase 2.7.4.6 Nucleoside-diphosphate kinase -2.7.4.7 Phosphomethylpyrimidine kinase +2.7.4.7 Phosphooxymethylpyrimidine kinase 2.7.4.8 Guanylate kinase 2.7.4.9 dTMP kinase 2.7.4.10 Nucleoside-triphosphate--adenylate kinase @@ -3154,8 +3280,8 @@ 2.7.4.27 ([Pyruvate, phosphate dikinase] phosphate) phosphotransferase 2.7.4.28 ([Pyruvate, water dikinase] phosphate) phosphotransferase 2.7.4.29 Kdo(2)-lipid A phosphotransferase -2.7.4.30 Lipid A phosphoethanolamine transferase 2.7.4.31 (5-(aminomethyl)furan-3-yl)methyl phosphate kinase +2.7.4.32 Farnesyl phosphate kinase 2.7.6.1 Ribose-phosphate diphosphokinase 2.7.6.2 Thiamine diphosphokinase 2.7.6.3 2-amino-4-hydroxy-6-hydroxymethyldihydropteridine diphosphokinase @@ -3188,14 +3314,14 @@ 2.7.7.32 Galactose-1-phosphate thymidylyltransferase 2.7.7.33 Glucose-1-phosphate cytidylyltransferase 2.7.7.34 Glucose-1-phosphate guanylyltransferase -2.7.7.35 Ribose-5-phosphate adenylyltransferase +2.7.7.35 ADP ribose phosphorylase 2.7.7.36 Aldose-1-phosphate adenylyltransferase 2.7.7.37 Aldose-1-phosphate nucleotidyltransferase 2.7.7.38 3-deoxy-manno-octulosonate cytidylyltransferase 2.7.7.39 Glycerol-3-phosphate cytidylyltransferase 2.7.7.40 D-ribitol-5-phosphate cytidylyltransferase 2.7.7.41 Phosphatidate cytidylyltransferase -2.7.7.42 [Glutamate--ammonia-ligase] adenylyltransferase +2.7.7.42 [Glutamine synthetase] adenylyltransferase 2.7.7.43 N-acylneuraminate cytidylyltransferase 2.7.7.44 Glucuronate-1-phosphate uridylyltransferase 2.7.7.45 Guanosine-triphosphate guanylyltransferase @@ -3239,22 +3365,30 @@ 2.7.7.86 Cyclic GMP-AMP synthase 2.7.7.87 L-threonylcarbamoyladenylate synthase 2.7.7.88 GDP polyribonucleotidyltransferase -2.7.7.89 [Glutamate--ammonia ligase]-adenylyl-L-tyrosine phosphorylase -2.7.7.90 CMP-8-amino-3,8-dideoxy-manno-octulosonate cytidylyltransferase +2.7.7.89 [Glutamine synthetase]-adenylyl-L-tyrosine phosphorylase +2.7.7.90 8-amino-3,8-dideoxy-manno-octulosonate cytidylyltransferase +2.7.7.91 Valienol-1-phosphate guanylyltransferase +2.7.7.92 3-deoxy-D-glycero-D-galacto-nononate cytidylyltransferase +2.7.7.93 Phosphonoformate cytidylyltransferase +2.7.7.94 4-hydroxyphenylalkanoate adenylyltransferase +2.7.7.95 Mycocerosic acid adenylyltransferase +2.7.7.96 ADP-D-ribose pyrophosphorylase +2.7.7.97 3-hydroxy-4-methylanthranilate adenylyltransferase +2.7.7.98 4-hydroxybenzoate adenylyltransferase 2.7.7.n1 Adenosine monophosphate-protein transferase 2.7.7.n6 Guanine phosphate-protein transferase 2.7.8.1 Ethanolaminephosphotransferase 2.7.8.2 Diacylglycerol cholinephosphotransferase 2.7.8.3 Ceramide cholinephosphotransferase 2.7.8.4 Serine-phosphoethanolamine synthase -2.7.8.5 CDP-diacylglycerol--glycerol-3-phosphate 3-phosphatidyltransferase +2.7.8.5 CDP-diacylglycerol--glycerol-3-phosphate 1-phosphatidyltransferase 2.7.8.6 Undecaprenyl-phosphate galactose phosphotransferase 2.7.8.7 Holo-[acyl-carrier-protein] synthase 2.7.8.8 CDP-diacylglycerol--serine O-phosphatidyltransferase 2.7.8.9 Phosphomannan mannosephosphotransferase 2.7.8.10 Sphingosine cholinephosphotransferase 2.7.8.11 CDP-diacylglycerol--inositol 3-phosphatidyltransferase -2.7.8.12 CDP-glycerol glycerophosphotransferase +2.7.8.12 Teichoic acid poly(glycerol phosphate) polymerase 2.7.8.13 Phospho-N-acetylmuramoyl-pentapeptide-transferase 2.7.8.14 CDP-ribitol ribitolphosphotransferase 2.7.8.15 UDP-N-acetylglucosamine--dolichyl-phosphate N-acetylglucosaminephosphotransferase @@ -3282,6 +3416,11 @@ 2.7.8.40 UDP-N-acetylgalactosamine-undecaprenyl-phosphate N-acetylgalactosaminephosphotransferase 2.7.8.41 Cardiolipin synthase (CMP-forming) 2.7.8.42 Kdo(2)-lipid A phosphoethanolamine 7''-transferase +2.7.8.43 Lipid A phosphoethanolamine transferase +2.7.8.44 Teichoic acid glycerol-phosphate primase +2.7.8.45 Teichoic acid glycerol-phosphate transferase +2.7.8.46 Teichoic acid ribitol-phosphate primase +2.7.8.47 Teichoic acid ribitol-phosphate polymerase 2.7.8.n3 Ceramide phosphoethanolamine synthase 2.7.9.1 Pyruvate, phosphate dikinase 2.7.9.2 Pyruvate, water dikinase @@ -3340,7 +3479,7 @@ 2.8.1.8 Lipoyl synthase 2.8.1.9 Molybdenum cofactor sulfurtransferase 2.8.1.10 Thiazole synthase -2.8.1.11 Molybdopterin-synthase sulfurtransferase +2.8.1.11 Molybdopterin synthase sulfurtransferase 2.8.1.12 Molybdopterin synthase 2.8.1.13 tRNA-uridine 2-sulfurtransferase 2.8.1.14 tRNA-5-taurinomethyluridine 2-sulfurtransferase @@ -3402,6 +3541,8 @@ 2.8.3.21 L-carnitine CoA-transferase 2.8.3.22 Succinyl-CoA--L-malate CoA-transferase 2.8.3.23 Caffeate CoA-transferase +2.8.3.24 (R)-2-hydroxy-4-methylpentanoate CoA-transferase +2.8.3.25 Bile acid CoA-transferase 2.8.4.1 Coenzyme-B sulfoethylthiotransferase 2.8.4.2 Arsenate-mycothiol transferase 2.8.4.3 tRNA-2-methylthio-N(6)-dimethylallyladenosine synthase @@ -3502,6 +3643,9 @@ 3.1.1.97 Methylated diphthine methylhydrolase 3.1.1.98 [Wnt protein] O-palmitoleoyl-L-serine hydrolase 3.1.1.99 6-deoxy-6-sulfogluconolactonase +3.1.1.100 Chlorophyllide a hydrolase +3.1.1.101 Poly(ethylene terephthalate) hydrolase +3.1.1.102 Mono(ethylene terephthalate) hydrolase 3.1.1.n2 Protein-S-isoprenylcysteine alpha-carbonyl methylesterase 3.1.2.1 Acetyl-CoA hydrolase 3.1.2.2 Palmitoyl-CoA hydrolase @@ -3524,12 +3668,12 @@ 3.1.2.22 Palmitoyl-protein hydrolase 3.1.2.23 4-hydroxybenzoyl-CoA thioesterase 3.1.2.25 Phenylacetyl-CoA hydrolase -3.1.2.26 Bile-acid-CoA hydrolase 3.1.2.27 Choloyl-CoA hydrolase 3.1.2.28 1,4-dihydroxy-2-naphthoyl-CoA hydrolase 3.1.2.29 Fluoroacetyl-CoA thioesterase 3.1.2.30 (3S)-malyl-CoA thioesterase 3.1.2.31 Dihydromonacolin L-[lovastatin nonaketide synthase] thioesterase +3.1.2.32 2-aminobenzoylacetyl-CoA thioesterase 3.1.3.1 Alkaline phosphatase 3.1.3.2 Acid phosphatase 3.1.3.3 Phosphoserine phosphatase @@ -3542,7 +3686,6 @@ 3.1.3.10 Glucose-1-phosphatase 3.1.3.11 Fructose-bisphosphatase 3.1.3.12 Trehalose-phosphatase -3.1.3.13 Bisphosphoglycerate phosphatase 3.1.3.14 Methylphosphothioglycerate phosphatase 3.1.3.15 Histidinol-phosphatase 3.1.3.16 Protein-serine/threonine phosphatase @@ -3624,9 +3767,12 @@ 3.1.3.95 Phosphatidylinositol-3,5-bisphosphate 3-phosphatase 3.1.3.96 Pseudouridine 5'-phosphatase 3.1.3.97 3',5'-nucleoside bisphosphate phosphatase -3.1.3.98 Geranyl diphosphate phosphohydrolase 3.1.3.99 IMP-specific 5'-nucleotidase 3.1.3.100 Thiamine phosphate phosphatase +3.1.3.101 Validoxylamine A 7'-phosphate phosphatase +3.1.3.102 FMN hydrolase +3.1.3.103 3-deoxy-D-glycero-D-galacto-nonulopyranosonate 9-phosphatase +3.1.3.104 5-amino-6-(5-phospho-D-ribitylamino)uracil phosphatase 3.1.4.1 Phosphodiesterase I 3.1.4.2 Glycerophosphocholine phosphodiesterase 3.1.4.3 Phospholipase C @@ -3695,7 +3841,10 @@ 3.1.11.4 Exodeoxyribonuclease (phage SP3-induced) 3.1.11.5 Exodeoxyribonuclease V 3.1.11.6 Exodeoxyribonuclease VII +3.1.11.7 Adenosine-5'-diphospho-5'-(DNA) diphosphatase +3.1.11.8 Guaosine-5'-diphospho-5'-(DNA) diphosphatase 3.1.12.1 5' to 3' exodeoxyribonuclease (nucleoside 3'-phosphate-forming) +3.1.12.2 DNA-3'-diphospho-5'-guanosine diphosphatase 3.1.13.1 Exoribonuclease II 3.1.13.2 Exoribonuclease H 3.1.13.3 Oligonucleotidase @@ -3905,7 +4054,7 @@ 3.2.1.176 Cellulose 1,4-beta-cellobiosidase (reducing end) 3.2.1.177 Alpha-D-xyloside xylohydrolase 3.2.1.178 Beta-porphyranase -3.2.1.179 Gellan tetrasaccharide unsaturated glucuronyl hydrolase +3.2.1.179 Gellan tetrasaccharide unsaturated glucuronosyl hydrolase 3.2.1.180 Unsaturated chondroitin disaccharide hydrolase 3.2.1.181 Galactan endo-beta-1,3-galactanase 3.2.1.182 4-hydroxy-7-methoxy-3-oxo-3,4-dihydro-2H-1,4-benzoxazin-2-yl glucoside beta-D-glucosidase @@ -3923,6 +4072,12 @@ 3.2.1.194 Ginsenosidase type IV 3.2.1.195 20-O-multi-glycoside ginsenosidase 3.2.1.196 Limit dextrin alpha-1,6-maltotetraose-hydrolase +3.2.1.197 Beta-1,2-mannosidase +3.2.1.198 Alpha-mannan endo-1,2-alpha-mannanase +3.2.1.199 Sulfoquinovosidase +3.2.1.200 Exo-chitinase (non-reducing end) +3.2.1.201 Exo-chitinase (reducing end) +3.2.1.202 Endo-chitodextinase 3.2.1.n1 Blood group B branched chain alpha-1,3-galactosidase 3.2.1.n2 Blood group B linear chain alpha-1,3-galactosidase 3.2.1.n3 Dictyostelium lysozyme A @@ -3959,9 +4114,8 @@ 3.3.1.1 Adenosylhomocysteinase 3.3.1.2 Adenosylmethionine hydrolase 3.3.2.1 Isochorismatase -3.3.2.2 Alkenylglycerophosphocholine hydrolase +3.3.2.2 Lysoplasmalogenase 3.3.2.4 Trans-epoxysuccinate hydrolase -3.3.2.5 Alkenylglycerophosphoethanolamine hydrolase 3.3.2.6 Leukotriene-A(4) hydrolase 3.3.2.7 Hepoxilin-epoxide hydrolase 3.3.2.8 Limonene-1,2-epoxide hydrolase @@ -3971,6 +4125,7 @@ 3.3.2.12 Oxepin-CoA hydrolase 3.3.2.13 Chorismatase 3.3.2.14 2,4-dinitroanisole O-demethylase +3.3.2.15 Trans-2,3-dihydro-3-hydroxyanthranilic acid synthase 3.4.11.1 Leucyl aminopeptidase 3.4.11.2 Membrane alanyl aminopeptidase 3.4.11.3 Cystinyl aminopeptidase @@ -4043,7 +4198,7 @@ 3.4.17.21 Glutamate carboxypeptidase II 3.4.17.22 Metallocarboxypeptidase D 3.4.17.23 Angiotensin-converting enzyme 2 -3.4.17.n1 [CysO]-cysteine peptidase +3.4.17.n1 [CysO sulfur-carrier protein]-S-L-cysteine hydrolase 3.4.18.1 Cathepsin X 3.4.19.1 Acylaminoacyl-peptidase 3.4.19.2 Peptidyl-glycinamidase @@ -4056,6 +4211,7 @@ 3.4.19.12 Ubiquitinyl hydrolase 1 3.4.19.13 Glutathione hydrolase 3.4.19.14 Leukotriene-C(4) hydrolase +3.4.19.15 Desampylase 3.4.21.1 Chymotrypsin 3.4.21.2 Chymotrypsin C 3.4.21.3 Metridin @@ -4335,7 +4491,6 @@ 3.4.24.85 S2P endopeptidase 3.4.24.86 ADAM 17 endopeptidase 3.4.24.87 ADAMTS13 endopeptidase -3.4.24.88 Desampylase 3.4.24.89 Pro-Pro endopeptidase 3.4.25.1 Proteasome endopeptidase complex 3.4.25.2 HslU--HslV peptidase @@ -4453,6 +4608,14 @@ 3.5.1.117 6-aminohexanoate-oligomer endohydrolase 3.5.1.118 Gamma-glutamyl hercynylcysteine S-oxide hydrolase 3.5.1.119 Pup amidohydrolase +3.5.1.120 2-aminomuconate deaminase (2-hydroxymuconate-forming) +3.5.1.121 Protein N-terminal asparagine amidohydrolase +3.5.1.122 Protein N-terminal glutamine amidohydrolase +3.5.1.123 Gamma-glutamylanilide hydrolase +3.5.1.124 Protein deglycase +3.5.1.125 N(2)-acetyl-L-2,4-diaminobutanoate deacetylase +3.5.1.126 Oxamate amidohydrolase +3.5.1.127 Jasmonoyl-L-amino acid hydrolase 3.5.1.n3 4-deoxy-4-formamido-L-arabinose-phosphoundecaprenol deformylase 3.5.2.1 Barbiturase 3.5.2.2 Dihydropyrimidinase @@ -4538,7 +4701,11 @@ 3.5.4.39 GTP cyclohydrolase IV 3.5.4.40 Aminodeoxyfutalosine deaminase 3.5.4.41 5'-deoxyadenosine deaminase -3.5.4.n3 Melamine deaminase +3.5.4.42 N-isopropylammelide isopropylaminohydrolase +3.5.4.43 Hydroxydechloroatrazine ethylaminohydrolase +3.5.4.44 Ectoine hydrolase +3.5.4.45 Melamine deaminase +3.5.4.46 cAMP deaminase 3.5.5.1 Nitrilase 3.5.5.2 Ricinine nitrilase 3.5.5.4 Cyanoalanine nitrilase @@ -4548,8 +4715,6 @@ 3.5.5.8 Thiocyanate hydrolase 3.5.99.1 Riboflavinase 3.5.99.2 Aminopyrimidine aminohydrolase -3.5.99.3 Hydroxydechloroatrazine ethylaminohydrolase -3.5.99.4 N-isopropylammelide isopropylaminohydrolase 3.5.99.5 2-aminomuconate deaminase 3.5.99.6 Glucosamine-6-phosphate deaminase 3.5.99.7 1-aminocyclopropane-1-carboxylate deaminase @@ -4573,7 +4738,6 @@ 3.6.1.16 CDP-glycerol diphosphatase 3.6.1.17 Bis(5'-nucleosyl)-tetraphosphatase (asymmetrical) 3.6.1.18 FAD diphosphatase -3.6.1.19 Nucleoside-triphosphate diphosphatase 3.6.1.20 5'-acylphosphoadenosine hydrolase 3.6.1.21 ADP-sugar diphosphatase 3.6.1.22 NAD(+) diphosphatase @@ -4608,6 +4772,7 @@ 3.6.1.65 (d)CTP diphosphatase 3.6.1.66 XTP/dITP diphosphatase 3.6.1.67 Dihydroneopterin triphosphate diphosphatase +3.6.1.68 Geranyl diphosphate phosphohydrolase 3.6.1.n1 D-tyrosyl-tRNA(Tyr) hydrolase 3.6.1.n2 L-cysteinyl-tRNA(Pro) 3.6.1.n3 L-cysteinyl-tRNA(Cys) hydrolase @@ -4827,6 +4992,7 @@ 4.1.1.100 Prephenate decarboxylase 4.1.1.101 Malolactic enzyme 4.1.1.102 Phenacrylate decarboxylase +4.1.1.103 Gamma-resorcylate decarboxylase 4.1.2.2 Ketotetrose-phosphate aldolase 4.1.2.4 Deoxyribose-phosphate aldolase 4.1.2.5 L-threonine aldolase @@ -4850,7 +5016,6 @@ 4.1.2.27 Sphinganine-1-phosphate aldolase 4.1.2.28 2-dehydro-3-deoxy-D-pentonate aldolase 4.1.2.29 5-dehydro-2-deoxyphosphogluconate aldolase -4.1.2.30 17-alpha-hydroxyprogesterone aldolase 4.1.2.32 Trimethylamine-oxide aldolase 4.1.2.33 Fucosterol-epoxide lyase 4.1.2.34 4-(2-carboxyphenyl)-2-oxobut-3-enoate aldolase @@ -4914,10 +5079,10 @@ 4.1.99.14 Spore photoproduct lyase 4.1.99.16 Geosmin synthase 4.1.99.17 Phosphomethylpyrimidine synthase -4.1.99.18 Cyclic pyranopterin phosphate synthase 4.1.99.19 2-iminoacetate synthase 4.1.99.20 3-amino-4-hydroxybenzoate synthase -4.2.1.1 Carbonate dehydratase +4.1.99.22 GTP 3',8-cyclase +4.2.1.1 Carbonic anhydrase 4.2.1.2 Fumarate hydratase 4.2.1.3 Aconitate hydratase 4.2.1.5 Arabinonate dehydratase @@ -5058,6 +5223,14 @@ 4.2.1.161 Bisanhydrobacterioruberin hydratase 4.2.1.162 6-deoxy-6-sulfo-D-gluconate dehydratase 4.2.1.163 2-oxo-hept-4-ene-1,7-dioate hydratase +4.2.1.164 dTDP-4-dehydro-2,6-dideoxy-D-glucose 3-dehydratase +4.2.1.165 Chlorophyllide a 3(1)-hydratase +4.2.1.166 Phosphinomethylmalate isomerase +4.2.1.167 (R)-2-hydroxyglutaryl-CoA dehydratase +4.2.1.168 GDP-4-dehydro-6-deoxy-alpha-D-mannose 3-dehydratase +4.2.1.169 3-vinylbacteriochlorophyllide d 3(1)-hydratase +4.2.1.170 2-(omega-methylthio)alkylmalate dehydratase +4.2.1.171 Cis-l-3-hydroxyproline dehydratase 4.2.2.1 Hyaluronate lyase 4.2.2.2 Pectate lyase 4.2.2.3 Mannuronate-specific alginate lyase @@ -5237,6 +5410,9 @@ 4.2.3.151 Pentamethylcyclopentadecatrienol synthase 4.2.3.152 2-epi-5-epi-valiolone synthase 4.2.3.153 (5-formylfuran-3-yl)methyl phosphate synthase +4.2.3.154 Demethyl-4-deoxygadusol synthase +4.2.3.155 2-epi-valiolone synthase +4.2.3.156 Hydroxysqualene synthase 4.2.3.n2 Delta-selinene synthase 4.2.3.n11 Selinene synthase 4.2.99.12 Carboxymethyloxysuccinate lyase @@ -5270,6 +5446,7 @@ 4.3.1.28 L-lysine cyclodeaminase 4.3.1.29 D-glucosaminate-6-phosphate ammonia lyase 4.3.1.30 dTDP-4-amino-4,6-dideoxy-D-glucose ammonia-lyase +4.3.1.31 L-tryptophan ammonia lyase 4.3.2.1 Argininosuccinate lyase 4.3.2.2 Adenylosuccinate lyase 4.3.2.3 Ureidoglycolate lyase @@ -5316,6 +5493,8 @@ 4.4.1.31 Phycoerythrocyanin alpha-cysteine-84 phycoviolobilin lyase/isomerase 4.4.1.32 C-phycocyanin alpha-cysteine-84 phycocyanobilin lyase 4.4.1.33 R-phycocyanin alpha-cysteine-84 phycourobilin lyase/isomerase +4.4.1.34 Isoprene-epoxide--glutathione S-transferase +4.4.1.35 L-cystine beta-lyase 4.5.1.1 DDT-dehydrochlorinase 4.5.1.2 3-chloro-D-alanine dehydrochlorinase 4.5.1.3 Dichloromethane dehalogenase @@ -5329,6 +5508,7 @@ 4.6.1.14 Glycosylphosphatidylinositol diacylglycerol-lyase 4.6.1.15 FAD-AMP lyase (cyclizing) 4.6.1.16 tRNA-intron lyase +4.6.1.17 Cyclic pyranopterin monophosphate synthase 4.7.1.1 Alpha-D-ribose 1-methylphosphonate 5-phosphate C-P-lyase 4.99.1.1 Protoporphyrin ferrochelatase 4.99.1.2 Alkylmercury lyase @@ -5338,6 +5518,7 @@ 4.99.1.6 Indoleacetaldoxime dehydratase 4.99.1.7 Phenylacetaldoxime dehydratase 4.99.1.8 Heme ligase +4.99.1.9 Coproporphyrin ferrochelatase 5.1.1.1 Alanine racemase 5.1.1.2 Methionine racemase 5.1.1.3 Glutamate racemase @@ -5359,12 +5540,14 @@ 5.1.1.19 O-ureido-serine racemase 5.1.1.20 L-Ala-D/L-Glu epimerase 5.1.1.21 Isoleucine 2-epimerase +5.1.1.22 4-hydroxyproline betaine 2-epimerase 5.1.2.1 Lactate racemase 5.1.2.2 Mandelate racemase 5.1.2.3 3-hydroxybutyryl-CoA epimerase 5.1.2.4 Acetoin racemase 5.1.2.5 Tartrate epimerase 5.1.2.6 Isocitrate epimerase +5.1.2.7 Tagaturonate epimerase 5.1.3.1 Ribulose-phosphate 3-epimerase 5.1.3.2 UDP-glucose 4-epimerase 5.1.3.3 Aldose 1-epimerase @@ -5402,6 +5585,9 @@ 5.1.3.35 2-epi-5-epi-valiolone 7-phosphate 2-epimerase 5.1.3.36 Heparosan-glucuronate 5-epimerase 5.1.3.37 Mannuronan 5-epimerase +5.1.3.38 D-erythrulose 1-phosphate 3-epimerase +5.1.3.39 L-erythrulose 4-phosphate epimerase +5.1.3.40 D-tagatose 6-phosphate 4-epimerase 5.1.99.1 Methylmalonyl-CoA epimerase 5.1.99.2 16-hydroxysteroid epimerase 5.1.99.3 Allantoin racemase @@ -5448,6 +5634,8 @@ 5.3.1.30 5-deoxy-glucuronate isomerase 5.3.1.31 Sulfoquinovose isomerase 5.3.1.32 (4S)-4-hydroxy-5-phosphonooxypentane-2,3-dione isomerase +5.3.1.33 L-erythrulose 1-phosphate isomerase +5.3.1.34 D-erythrulose 4-phosphate isomerase 5.3.2.1 Phenylpyruvate tautomerase 5.3.2.2 Oxaloacetate tautomerase 5.3.2.3 TDP-4-oxo-6-deoxy-alpha-D-glucose-3,4-oxoisomerase (dTDP-3-dehydro-6-deoxy-alpha-D-galactopyranose-forming) @@ -5576,6 +5764,7 @@ 5.4.99.61 Precorrin-8X methylmutase 5.4.99.62 D-ribose pyranase 5.4.99.63 Ethylmalonyl-CoA mutase +5.4.99.64 2-hydroxyisobutanoyl-CoA mutase 5.5.1.1 Muconate cycloisomerase 5.5.1.2 3-carboxy-cis,cis-muconate cycloisomerase 5.5.1.3 Tetrahydroxypteridine cycloisomerase @@ -5651,7 +5840,7 @@ 6.2.1.16 Acetoacetate--CoA ligase 6.2.1.17 Propionate--CoA ligase 6.2.1.18 Citrate--CoA ligase -6.2.1.19 Long-chain-fatty-acid--luciferin-component ligase +6.2.1.19 Long-chain-fatty-acid--protein ligase 6.2.1.20 Long-chain-fatty-acid--[acyl-carrier-protein] ligase 6.2.1.22 [Citrate (pro-3S)-lyase] ligase 6.2.1.23 Dicarboxylate--CoA ligase @@ -5665,7 +5854,7 @@ 6.2.1.32 Anthranilate--CoA ligase 6.2.1.33 4-chlorobenzoate--CoA ligase 6.2.1.34 Trans-feruloyl-CoA synthase -6.2.1.35 ACP-SH:acetate ligase +6.2.1.35 Acetate--[acyl-carrier protein] ligase 6.2.1.36 3-hydroxypropionyl-CoA synthase 6.2.1.37 3-hydroxybenzoate--CoA ligase 6.2.1.38 (2,2,3-trimethyl-5-oxocyclopent-3-enyl)acetyl-CoA synthase @@ -5676,11 +5865,13 @@ 6.2.1.43 2-hydroxy-7-methoxy-5-methyl-1-naphthoate--CoA ligase 6.2.1.44 3-(methylthio)propionyl--CoA ligase 6.2.1.45 E1 ubiquitin-activating enzyme -6.2.1.46 L-allo-isoleucine:holo-[CmaA peptidyl-carrier protein] ligase +6.2.1.46 L-allo-isoleucine--holo-[CmaA peptidyl-carrier protein] ligase +6.2.1.47 Medium-chain-fatty-acid--(acyl-carrier-protein) ligase +6.2.1.48 Carnitine-CoA ligase 6.2.1.n2 Amino acid--[acyl-carrier-protein] ligase 6.2.1.n3 Malonate--CoA ligase 6.3.1.1 Aspartate--ammonia ligase -6.3.1.2 Glutamate--ammonia ligase +6.3.1.2 Glutamine synthetase 6.3.1.4 Aspartate--ammonia ligase (ADP-forming) 6.3.1.5 NAD(+) synthase 6.3.1.6 Glutamate--ethylamine ligase @@ -5715,7 +5906,6 @@ 6.3.2.17 Tetrahydrofolate synthase 6.3.2.18 Gamma-glutamylhistamine synthase 6.3.2.20 Indoleacetate--lysine synthetase -6.3.2.21 Ubiquitin--calmodulin ligase 6.3.2.23 Homoglutathione synthase 6.3.2.24 Tyrosine--arginine ligase 6.3.2.25 Tubulin--tyrosine ligase @@ -5738,7 +5928,7 @@ 6.3.2.44 Pantoate--beta-alanine ligase (ADP-forming) 6.3.2.45 UDP-N-acetylmuramate L-alanyl-gamma-D-glutamyl-meso-2,6-diaminoheptanedioate ligase 6.3.2.46 Fumarate--(S)-2,3-diaminopropanoate ligase -6.3.2.47 Dapdiamide A synthase +6.3.2.47 Dapdiamide synthase 6.3.2.48 L-arginine-specific L-amino acid ligase 6.3.2.49 L-alanine--L-anticapsin ligase 6.3.2.n3 ISG15--protein ligase @@ -5796,5 +5986,6 @@ 6.5.1.5 RNA 3'-terminal-phosphate cyclase (GTP) 6.5.1.6 DNA ligase (ATP or NAD(+)) 6.5.1.7 DNA ligase (ATP, ADP or GTP) +6.5.1.8 3'-phosphate/5'-hydroxy nucleic acid ligase 6.6.1.1 Magnesium chelatase 6.6.1.2 Cobaltochelatase diff --git a/c++/src/objects/seqfeat/institution_codes.inc b/c++/src/objects/seqfeat/institution_codes.inc index d4800d52..a41a9d93 100644 --- a/c++/src/objects/seqfeat/institution_codes.inc +++ b/c++/src/objects/seqfeat/institution_codes.inc @@ -1,4 +1,4 @@ -/* $Id: institution_codes.inc 520430 2016-11-28 18:25:59Z ivanov $ +/* $Id: institution_codes.inc 548845 2017-10-18 15:21:56Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,7579 +31,7653 @@ */ static const char* const kInstitutionCollectionCodeList[] = { -"A s Arnold Arboretum, Harvard University", -"AA s Ministry of Science, Academy of Sciences", -"AAC c Arignar Anna College", -"AAH s Arnold Arboretum, Harvard University", -"AAPI s Plant Industry Laboratory", -"AAR s Reliquae Aaronsohnianae", -"AARI s Anatolian Agricultural Research Institute", -"AAS s British Antarctic Survey", -"AASU s Armstrong State University", -"AAU s University of Aarhus, Institute of Biological Sciences", -"AAU s Addis Ababa University, Department of Biology", -"AAU:A s Addis Ababa University, Department of Biology, Amphibian collection", -"AAUB s Anhui Agricultural University, Department of Basic Courses", -"AAUF s Anhui Agricultural University, Forest Utilization Faculty", -"ABB c Asian Bacterial Bank", -"ABD s University of Aberdeen, Plant and Soil Science Department", -"ABDAM s Aberdeen Art Gallery and Museum", -"ABDC s Aba Institute for Drug Control", -"ABDF s University of Aberdeen, Forestry Department", -"ABDH s United Arab Emirates University, Department of Biology", -"ABDM s Marischal College, University of Aberdeen", -"ABFM s The Barnes Foundation Arboretum", -"ABH s Universidad de Alicante, Centro Iberoamericano de la Biodiversidad (CIBIO)", -"ABI s Centre ORSTOM d'Adiopodoume", -"ABKMI c Department of Applied Biology, Faculty of science", -"ABL s Adviesbureau voor Bryologie en Lichenologie", -"ABN s Radley College", -"ABO s Aboyne Castle", -"ABRC b Arabidopsis Biological Resource Center", -"ABRIICC c ABRIICC Agricultural Biotechnology Research Institute of Iran Culture collection", -"ABRN s Centre for Ecology and Hydrology", -"ABS sc University of Wales, Botany Department", -"ABS s Archbold Biological Station", -"ABSH s Southern Illinois Universitiy, Department of Plant Biology", -"ABSL s University of Minnesota, American Bryological and Lichenological Society", -"ABSM s Duke University, Botany Department", -"ABT s Laboratoire de Biologie Vegetale et d'Ecologie Forestiere", -"ABTC s Australian Biological Tissue Collection, South Australian Museum", -"ABU s Ahmadu Bello University Herbarium", -"AC s Amherst College", -"ACA s Agricultural University of Athens", -"ACA-DC c Greek Coordinated Collections of Microorganisms", -"ACAD s Acadia University, K. C. Irving Environmental Science Centre & Harriet Irving Botanical Gardens", -"ACAD sb Australian Centre for Ancient DNA", -"ACAM c The Australian Collection of Antarctic Microorganisms, Cooperative Research Center for the Antarctic and Southern Ocean Environment", -"ACAP s Aquaculture Center of Aomori Prefecture", -"ACBC s Agriculture Canada Research Station", -"ACBR c Austrian Center of Biological Resources and Applied Mycology", -"ACBV s Agriculture Canada Research Station, The Aphids of British Columbia", -"ACC s Oak Hill Park Museum", -"ACCC c Agricultural Culture Collection of China", -"ACD s Alemaya University of Agriculture", -"ACE s Anhui College of Education, Biology Department", -"ACE s Arachnid Collection of Egypt", -"ACH c Mycology Culture Collection, Women's and Children's Hospital", -"ACHE s Institute of Terrestrial Ecology", -"ACK s Agriculture and Agri-Food Canada", -"ACM c Australian Collection of Microorganisms", -"ACM s Anhui College of Traditional Chinese Medicine, Chinese Materia Medica Department", -"ACNB s Agriculture Canada Research Station", -"ACNS s Agriculture Canada Nova Scotia", -"ACOI c Coimbra Collection of Algae", -"ACOR s Universidad Nacional de Cordoba", -"ACTC s Austin College", -"ACU s Abilene Christian University", -"ACUNHC s Abilene Christian University, Natural History Collection", -"AD s Plant Biodiversity Centre", -"ADA s Herbarium, Department of Agriculture, South Australia", -"ADMONT s Benediktinerstift Admont", -"ADO s Kirikkale University, Biology Department", -"ADR s Adrian College, Biology Department", -"ADRZ s Rudjer Boskovic Institute, CIM-Botany", -"ADSH s Arachnology Division", -"ADT s Antarctic Division", -"ADU s University of Adelaide, Botany Department", -"ADUG s Geology Department, University of Adelaide", -"ADUZ s Zoology Department, University of Adelaide", -"ADW s University of Adelaide", -"AEF s University of Ankara, Department of Pharmaceutical Botany", -"AEI s American Entomological Institute", -"AEIC s American Entomological Institute", -"AES s Herbarium, Agricultural and Forestry Experiment Station, University of Alaska", -"AESB s Agriculture Experiment Station", -"AFAQ s Amateur Fisheries Association of Queensland", -"AFES s Maritimes Forest Research Centre", -"AFGMC s Alaska Department of Fish and Game", -"AFS s University of Michigan", -"AFSDU s Suleyman Demirel University, Agricultural Faculty", -"AFTC s Alaska Frozen Tissue Collection", -"AGRITEC b AGRITEC, Ltd.", -"AGRL s Lethbridge Research Station", -"AGU s Astrakhan State University", -"AGUAT s Universidad de San Carlos", -"AGUCH s Facultad de Ciencias Agronomicas de la Universidad de Chile", -"AH s Universidad de Alcala, Departamento de Biologia Vegetal", -"AHBC s Dixie College", -"AHF s Allan Hancock Foundation, University of Southern California", -"AHFH s University of Southern California", -"AHLDA c Animal Health Division Culture Collection", -"AHMA s Agharkar Research Institute, Maharashtra Association for the Cultivation of Science, Botany Group", -"AHNU s Anhui Normal University Conservation Genetics Lab", -"AHS s Austin High School", -"AHU c AHU Culture Collection", -"AHUC s University of California, Agronomy and Range Science Department", -"AIB s Anhui Institute of Biology", -"AIBU s Abant Izzet Baysal Ueniversitesi, Biyoloji Boeluemue", -"AICH s Aichi Kyoiku University, Biology Department", -"AIM s Auckland Institute and Museum", -"AIMS s Australian Institute of Marine Science", -"AIS s Academie imperial des Sciences", -"AISIY s Armenian Institute for the Scientific Investigation of Cattle Breeding and Veterinary, Department of Meadows and Pastures", -"AIX s Museum d'Histoire Naturelle d'Aix-en-Provence", -"AJ c Central Research Laboratories", -"AJBC s Atkins Jardin Botanico de Cienfuegos", -"AJOU s Ajou University, Biological Sciences Department", -"AK s Auckland War Memorial Museum", -"AKPM s Akita Prefectural Museum", -"AKSU h Aksaray University", -"AKU c Faculty of Agriculture", -"AKU s University of Auckland, School of Biological Sciences", -"AL s Universite d'Alger", -"ALA s Herbarium, University of Alaska Museum of the North", -"ALA s University of Alabama Museum of Natural History", -"ALAJ s Herbarium, University of Alaska SE", -"ALAM s Adams State College, Biology Department", -"ALB s Civico Museo Archeologico e di Scienze Naturali Federico Eusebio", -"ALBA s Universidad de Castilla, La Mancha, Departamento de Ciencia y Tecnologia Agroforestal", -"ALBC s Albion College, Biology Department", -"ALBU s Rocky Mountain Forest and Range Experiment Station", -"ALCB s Universidade Federal da Bahia, Campus Universitario de Ondina", -"ALCP c Algotheque du Laboratoire de Cryptogamie", -"ALD s Alderney Society and Museum", -"ALEX s University of Alexandria, Department of Botany", -"ALF s Campus International de Baillarguet, Departement d'Elevage et de Medecine Veterinaire", -"ALGOBANK c ALGOBANK", -"ALGU s Universidade do Algarve", -"ALIRU c Australian Legume Inoculants Research Unit", -"ALK s Alnwick Scientific and Mechanical Institution", -"ALM s Museum National Historie Naturelle", -"ALM s Art Gallery and Museum, Central Library", -"ALMA s Alma College, Biology Department", -"ALME s Estacion Experimental de Zonas Aridas", -"ALN s Alnwick Botanical Society", -"ALNHS s Natural Heritage Section-ALDCNR", -"ALT s Curtis Museum", -"ALTA s University of Alberta, Biological Sciences Department", -"ALTB s University of Barnaul, Altai State University", -"ALU s Alabama Museum of Natural History", -"ALUH s Alzahra University", -"AM sb Australian Museum", -"AM:Arachnology s Australian Museum, Invertebrate Collections: Arachnology", -"AM:EBU sb Australian Museum, Evolutionary Biology Unit Tissue Collection", -"AM:Entomology s Australian Museum, Invertebrate Collections: Entomology", -"AM:Herpetology s Australian Museum, Vertebrate Collections: Herpetology", -"AM:Ichthyology s Australian Museum, Vertebrate Collections: Ichthyology", -"AM:Malacology s Australian Museum, Invertebrate Collections: Malacology", -"AM:Mammalogy s Australian Museum, Vertebrate Collections: Mammalogy", -"AM:Marine_Invertebrates s Australian Museum, Invertebrate Collections: Marine and other invertebrates", -"AM:Mineralogy s Australian Museum, Earth Sciences: Mineralogy and Petrology Collection", -"AM:Ornithology s Australian Museum, Vertebrate Collections: Ornithology", -"AM:Palaeontology s Australian Museum, Palaeontology Collection", -"AM s Acatushun Museum at the Estancia Haberton", -"AM s Asenovgrad Paleontology Museum", -"AMAL s Anniston Museum of Natural History", -"AMAZ s Universidad Nacional de la Amazonia Peruana", -"AMB s Associazione Micologica Bresadola", -"AMC c Department of Biologics Research", -"AMCC s Ambrose Monell Cryo Collection, American Museum of Natural History", -"AMCL s Macapa, Museu Territorial de Historia Natural \"Angelo Moreira da Costa Lima\"", -"AMD s Hugo de Vries-Laboratory, University of Amsterdam", -"AMDE s Brathay Field Centre for Exploration and Field Studies", -"AMES s Harvard University", -"AMG s Albany Museum", -"AMGS s Albany Museum", -"AMH s Agharkar Research Institute, Mycology and Plant Pathology Department", -"AMMRL c Australian National Reference Laboratory in Medical Mycology", -"AMMS s Academy of Military Medical Sciences", -"AMNH sb American Museum of Natural History", -"AMNH:Fish s American Museum of Natural History, Ichthyology Collection", -"AMNH:Herp s American Museum of Natural History, Herpetology collection", -"AMNH:ORN s American Museum of Natural History, Ornithology Collection", -"AMNH s Icelandic Institute of Natural History, Akureyri Division", -"AMNZ s Auckland Institute and Museum", -"AMO s Herbario AMO", -"AMP c Australian Mycological Panel", -"AMP s Ampleforth College", -"AMS s Australian Museum", -"AMSA s Albany Museum", -"AMUZ s Aligarh Muslim University", -"ANA s Orange County Department of Agriculture", -"ANACC c Australian National Algae Culture Collection", -"ANC s Universita di Ancona, Dipartimento di Biotecnologie Agrarie ed Ambientali", -"ANCB s Museo Nacional de Historia Natural, La Paz", -"AND s Slezske zemske muzeum Opava, Arboretum Nopvy Dvur, Dendrology Department", -"ANDA s Andalas University", -"ANDES s La Universidad de Los Andes", -"ANDES:A s La Universidad de Los Andes, Amphibian Collection", -"ANDES:O s La Universidad de Los Andes, Ornithology Collection", -"ANES s Anadolu University, Biology Department", -"ANFC s Australian National Fish Collection", -"ANFM s Associazione Naturalisti Forlivesi Pro Museo", -"ANG s Arboretum de la Maulevrie", -"ANGU s Instituto Nacional de Tecnologia Agropecuaria", -"ANGUC s Universite Catholiques de l'Ouest", -"ANH s Andong National University, School of Bioresource Science", -"ANHC s Arkansas Natural Heritage Commission", -"ANIC s Australian National Insect Collection", -"ANK s Ankara Ueniversitesi, Biyoloji Boeluemue", -"ANKO s Forest Research Institute, Turkey", -"ANLW s Amt Der Niederosterreichischen Landsregierung", -"ANMR c Asian Network on Microbial Researches", -"ANSM s Universidad Autonoma Agraria Antonio Narro, Departamento de Botanica", -"ANSP s Academy of Natural Sciences of Philadelphia", -"ANSP:Malacology s Academy of Natural Sciences of Philadelphia, Malacology Collection", -"ANTU s Changbai Mountain National Nature Reserve Administration Bureau", -"ANU s Australian National University", -"ANU s Anhui University, Biology Department", -"ANUB s Anhui Normal University, Biology Department", -"ANUC s Australian National University, Chemistry Department", -"ANUG s Anhui Normal University, Geography Department", -"ANWC s Australian National Wildlife Collection", -"AO s Museo Regionale di Scienze Naturali della Valle d'Aosta", -"APCC c Antarctic Protistan Culture Collection (Woods Hole Oceanographic Institution)", -"APCR s Arkansas Tech University, Biological Sciences Department", -"APEI s Agriculture Canada Research Station", -"APH s Society of Apothecaries", -"APHA sc Animal and Plant Health Agency", -"APHI s U.S. Department of Agriculture, Animal and Plant Health Inspection Service", -"APIY s Abovian Pedagogical Institute, Botany Department", -"APM s Algonquin Provincial Park, Algonquin Visitor Centre", -"APMJ s Aomori Prefectural Museum", -"APP s Parco Nazionale del Gran Sasso e Monti della Laga - Universita di Camerino, Centro Richerche Floristiche dell'Appennino", -"APSC s Austin Peay State University, Biology Department", -"AQC s Aquinas College, Biology Department", -"AQP s Estudios Fitogeograficos del Peru", -"AQUI s Universita degli Studi di L'Aquila, Dipartimento di Scienze Ambientali", -"AR s Pomor State University", -"ARAGO s Universite Pierre et Marie Curie", -"ARAN s Alto de Zorroaga s.n., Departamento de Botanica", -"ARB s Salahiddin University, Biology Department", -"ARBH s Arbroath Scientific and Natural History Society", -"ARC s Universidad Nacional del Comahue, Facultad de Ciencias Agrarias", -"ARC s Atlantic Reference Centre", -"ARCH s Archbold Biological Station", -"ARCM s Atlantic Reference Centre", -"ARER s Associazione Romana di Entomologia", -"ARG s Argotti Botanic Garden", -"ARIZ s University of Arizona, Department of Plant Sciences", -"ARK s University of Arkansas", -"ARKH s Chingan State Nature Reserve", -"ARM s County Museum", -"ARMFN s Armagh Field Naturalists' Society", -"ARRI s Ayurveda Regional Research Institute", -"ARSEF c ARS Collection of Entomopathogenic Fungi", -"ARTH s Artvin Coruh University", -"ARUN s Botanical Survey of India, Arunachal Pradesh Regional Centre", -"AS c China General Microbiological Culture Collection Center", -"AS s Paleontological Collection", -"AS s Jardin Botanico", -"ASAY s Academy of Science of Armenia", -"ASC s Northern Arizona University, Biological Sciences Department", -"ASCC s Adams State College Collection", -"ASCU s Agricultural Scientific Collections Unit", -"ASDM s Arizona-Sonora Museum", -"ASE s Universidade Federal de Sergipe, Departamento de Biologia", -"ASH s National Institute of Deserts Flora and Fauna", -"ASIB c Algensammlung am Institut fur Botanik", -"ASINC b Agricultural Science Institute of North-Central Vietnam", -"ASIO s Academia Sinica Institute of Oceanology", -"ASIZB s Academia Sinica Institute of Zoology, Beijing", -"ASIZP s Academia Sinica Institute of Zoology, Ichthyology Collection", -"ASIZT s Academia Sinica Institute of Zoology, Taipei", -"ASM s Arts and Science University", -"ASNHC s Angelo State Natural History Collection", -"ASSAM s Botanical Survey of India, Eastern Circle", -"ASSL s Academy of Sciences", -"AST s University of Aston", -"ASTC s Stephen F. Austin State University, Biology Department", -"ASTN s Ashton-under-Lyne Linnean Botanical Society", -"ASTU s Assiut University", -"ASU s School of Life Sciences, Arizona State University", -"ASUA s Ain Shams University", -"ASUF s Rocky Mountain Research Station, USDA Forest Service", -"ASUMC s Arizona State University, Mammal Collection", -"ASUMZ s Arkansas State University, Collection of Recent Mammals", -"ASUT s Frank M. Hasbrouck Insect Collection", -"ASW s South Valley University, Botany Department", -"ASW c Culture Collection of Algae at the University of Vienna", -"ATA s Atatuerk Ueniversitesi", -"ATCC c American Type Culture Collection", -"ATH s Goulandris Natural History Museum", -"ATHU s National and Kapodistrian University of Athens, Biology Department", -"ATHUM c ATHUM Culture Collection of Fungi", -"ATSC b Australian Tree Seed Centre", -"ATU c Dept.of Biotechnology University of Tokyo", -"AU s Xiamen University, Biology Department", -"AUA s Auburn University, Biological Sciences Department", -"AUB s Andrews University", -"AUBH s Athabasca University", -"AUBL s Museum of Natural History, Beirut", -"AUBSN s All-Union Botanical Society", -"AUCE s El Azhar University", -"AUEM s Auburn University Entomological Museum", -"AUG s Augustana College, Biology Department", -"AUGD s Department of Geology and Petroleum Geology", -"AUH s Agriculture University Herbarium", -"AUM s Auburn University Museum", -"AUMC c Assiut University Mycological Centre Culture Collection", -"AURO s Auroville Foundation", -"AUSPGRIS b Australian Plant Genetic Resource Information Service", -"AUT s Museum d'Histoire Naturelle", -"AUW s Acadia University, Wildlife Museum", -"AV s Museum Requien", -"AVCH s City of Alexandria", -"AVE s Universidade de Aveiro, Departamento de Biologia", -"AVU s Vrije Universiteit, Department of Systematic Botany", -"AWH s Dr. Henri Van Heurck Museum", -"AWL s Abitibi Paper Company", -"AWQC c Australian Water Quality Centre", -"AWRI c The Australian Wine Research Institute", -"AYBY s Buckinghamshire County Museum Technical Centre", -"AYDN s Adnan Menderes University, Department of Biology", -"AYR s South Ayrshire Council", -"AZ s Museu Carlos Machado, Natural History Department", -"AZAN s Akademia Nauk Azerbaijana-Bulgarian Academy of Science of Azerbaijan", -"AZB s Herbario Ruy Telles Palhinha - Universidade Dos Acores", -"AZU s Universidade dos Acores, Departamento de Ciencias Agrarias", -"AZUS s Citrus College, Biological Sciences Department", -"B s Berlin Botanic Garden and Botanical Museum", -"BA s Museo Argentino de Ciencias Naturales Bernardino Rivadavia", -"BAA s Universidad de Buenos Aires, Facultad de Agronomia", -"BAAC s Musee de Beni Abbes", -"BAB s Instituto Nacional de Tecnologia Agropecuaria, Instituto de Recursos Biologicos", -"BABY s B. A. Bennett Herbarium, Yukon Government", -"BAC s Beijing Agricultural College", -"BAC s Bacup Natural History Society", -"BACC c Brucella AFSSA Culture Collection", -"BACH s Botswana College of Agriculture", -"BACP s CEFYBO, Unidad Botanica", -"BAE s Willis Museum and Art Gallery", -"BAF s Universidad de Buenos Aires, Facultad de Farmacia y Bioquimica", -"BAFC sc Universidad de Buenos Aires, Departamento de Ciencias Biologicas", -"BAG s Ministry of Agriculture", -"BAH s Empresa Baiana de Desenvolvimento Agricola", -"BAH s Biologische Anstalt Helgoland Marine Station", -"BAI s Instituto Forestal Nacional (IFONA), Centro Forestal Castelar", -"BAIL s Conservatoire Botanique National de Bailleul", -"BAJ s Instituto Municipal de Botanica, Parque Pte. Dr. Nicolas Avellaneda", -"BAK s Academy of Sciences of Azerbaijan", -"BAL s INTA, EEA Balcarce, Catedra de Botanica Agricola", -"BALT s Towson University, Department of Biological Sciences", -"BAMU s Dr. Babasaheb Ambedkar Marathwada University", -"BAN s Banaras Hindu University, Botany Department", -"BANG s Universite de Bangui,", -"BAP s Oxford Botanic Garden", -"BAR s University of the West Indies, Department of Biological and Chemical Sciences", -"BARC s Systematic Botany and Mycology Laboratory, USDA/ARS", -"BARO s Maharaja Sayajirao University of Baroda, Botany Department", -"BART s Bartlett Arboretum", -"BAS s Bulgarian Academy of Science", -"BAS s Herbarium, Botanisches Institut, Universitat Basel", -"BASBG s Universitaet Basel, Basler Botanische Gesellschaft", -"BASSA s Museo Civico, Bassano del Grappa", -"BASU s Bu-Ali Sina University", -"BAT s Bagshaw Museum", -"BATA s Instituto Nacional de Desarollo Forestal", -"BATH s Bath Natural History Society", -"BATHG s Geology Museum", -"BATU s Batumi Botanical Garden, Botany Department", -"BAU s Beijing Agricultural University", -"BAV s Slovenskej akademie vied", -"BAY s Museum d'Histoire Naturelle de Bayonne", -"BAYLU s Baylor University, Biology Department", -"BB s Universidad Nacional del Sur, Departamento de Agronomia", -"BB s Buffalo Bill Museum", -"BBB s Universidad Nacional del Sur, Departamento de Biologia, Bioquimica y Farmacia", -"BBF s Conservatoire Botanique National de Midi-Pyrenees, Conservatoire botanique pyreneen", -"BBG s Birmingham Botanical Gardens", -"BBH s National Science and Technology Development Agency", -"BBLF c Institut fur Pflanzenschutz im Forst", -"BBLM s Boise District Bureau of Land Management", -"BBNP s Big Bend National Park", -"BBPP c Bacteriology Branch, Plant Pathology and Microbiology Division, Department of Agricultural Science", -"BBS s University of Suriname", -"BBSUK s National Museum and Gallery, Department of Biodiversity and Systematic Biology", -"BC s Institut Botanic de Barcelona", -"BCB s Universitat Autonoma de Barcelona, Unitat de Botanica", -"BCC s Universitat de Barcelona, Departament de Biologia Vegetal (Unitat de Botanica)", -"BCC c BIOTEC Culture Collection", -"BCCDC c BC Centre for Disease Control", -"BCCM/DCG c The Belgian Co-ordinated Collections of Micro-organisms / DCG Diatoms Collection", -"BCCM/IHEM c The Belgian Co-ordinated Collections of Micro-organisms / IHEM Biomedical Fungi and Yeasts Collection", -"BCCM/ITM c The Belgian Co-ordinated Collections of Micro-organisms / ITM Mycobacteria Collection", -"BCCM/LMBP c Belgian Coordinated Collections of Microorganisms / LMBP Plasmid Collection", -"BCCM/MUCL c The Belgian Co-ordinated Collections of Micro-organisms / MUCL (Agro)Industrial Fungi & Yeasts Collection", -"BCCM/ULC c The Belgian Co-ordinated Collections of Micro-organisms / ULC Polar cyanobacteria", -"BCCN c Brucella Culture Collection", -"BCCUSP c Brazilian Cyanobacteria Collection - University of Sao Paulo", -"BCF s Universitat de Barcelona, Laboratori de Botanica", -"BCFH s Bureau of Commercial Fisheries", -"BCH s Berry College", -"BCKN s Blackburn Museum and Art Gallery", -"BCL s Bates College, Biology Department", -"BCM s Campus Universitario de Tafira, Departamento de Biologia", -"BCM s Brooklyn Children's Museum", -"BCMEX s Universidad Autonoma de Baja California, Reg. MX-HR-007-BC", -"BCMM s Beijing College of Traditional Chinese Medicine", -"BCN s Universitat de Barcelona", -"BCNP s Bryce Canyon National Park", -"BCPM s British Columbia Provincial Museum", -"BCRC c Bioresource Collection and Research Center", -"BCRJ c Rio de Janeiro Cell Bank (Banco de Celulas do Rio de Janeiro)", -"BCRU s Universidad Nacional del Comahue, Departamento de Botanica", -"BCTC s Birmingham Central Technical College", -"BCU s Chulalongkorn University, Botany Department", -"BCUE s Department of Biology, Ch'ongju University of Education", -"BCUZ s Basque Country University, Laboratory of Zoology", -"BCW s Bedford College, University of London", -"BCWL s Biological Control of Weeds Laboratory-Europe", -"BDD s University of Bradford, Biology Department", -"BDI s Putnam Museum of History and Natural Science, Natural History Department", -"BDIARI sc Bahri Dagdas International Agricultural Research Institute", -"BDK s North Hertfordshire Museums Service, Natural History Department", -"BDLU s Laurentian University", -"BDMU s McMaster University", -"BDPA s Arboretum, Bolestraszyce - Zamek, Department of Physiography", -"BDUC s University of Calgary", -"BDUW s University of Waterloo", -"BDUZ c Biological Sciences", -"BDWC s University of Windsor", -"BDWL s Wilfred Laurier University", -"BDWR s Bridgewater College, Biology Department", -"BEAN s Bridge of Allan Museum", -"BED s Bedford Public Library", -"BEDF s New England Wild Flower Society", -"BEDPL s Bedford Public Library", -"BEG c International Bank for the Glomeromycota", -"BEGO s Beth Gordon Institute", -"BEI s American University of Beirut, Biology Department", -"BEI c Microbiology and Infectious Diseases Resources (BEI Resources)", -"BEL s Ulster Museum, Botany Department", -"BELC s Beloit College, Biology Department", -"BELUM s Ulster Museum, Belfast", -"BELZ s Zapovednik Belogorje State Nature Reserve", -"BENH s British Entomological and Natural History Society", -"BENIN s Universite National du Benin", -"BEO s Natural History Museum, Botany Department", -"BEOU s University of Belgrade, Faculty of Biology", -"BER s Orto Botanico de Bergamo \"Lorenzo Rota\"", -"BEREA s Berea College, Biology Department", -"BERN s University of Bern", -"BESA s Museum d'Histoire naturelle de Besancon", -"BESM s Bvumbwe Experiment Station", -"BEV s Borough of Beverley Art Gallery and Museum", -"BEX s Bexhill Museum", -"BFBI s Biologisches Forschunsstation Burgenland", -"BFD s Bedfordshire Natural History Society", -"BFDL s Forest Products Laboratory", -"BFIC s Museum National d'Histoire Naturelle", -"BFRS s Blodgett Forest Research Station", -"BFT s Queen's University, Botany Department", -"BFUS s University of Sofia, Biology Faculty", -"BFY s John Innes Horticultural Institution", -"BG s University of Bergen, Botanical Museum", -"BGAAS s Botanical Garden of the Armenian Academy of Sciences, Flora and Vegetation Department", -"BGHan s Bundesanstalf fuer Geowissenschaften und Rohstoffe", -"BGIV c Banco de Glomeromycota In Vitro (Bank of Glomeromycota In Vitro)", -"BGM s Bath Geology Museum (now the Royal Literary and Scientific Institution)", -"BGR s Bundesanstalt fur Geowissenschaften und Rohstoffe", -"BGS s British Geological Survey", -"BGSC c Bacillus Genetic Stock Center", -"BGSU s Bowling Green State University, Biological Sciences Department", -"BH s Cornell University, Department of Plant Biology", -"BHAG s T. M. Bhagalpur University, Botany Department", -"BHAV s Central Salt and Marine Chemicals Research Institute", -"BHCB s Universidade Federal de Minas Gerais, Departamento de Botanica", -"BHD s Williamson Art Gallery and Museum", -"BHDL s Wirral Central Area Reference Library", -"BHDS s Birkenhead School", -"BHM s University of Birmingham, Birmingham Natural Society", -"BHM s Black Hills Museum of Natural History", -"BHMG s Instituto Agronomico", -"BHMH s Universidade Federal de Minas Gerais, Museu de Historia Natural", -"BHO s Ohio University, Environmental and Plant Biology Department", -"BHSC s Black Hills State University, Biology Department", -"BHU s Humboldt-Universitaet zu Berlin, Institut fuer Biologie", -"BHUPM s Museum fuer Naturkunde, Institut fuer Palaeontologie", -"BHUPP s Banaras Hindu University, Mycology and Plant Pathology Department", -"BHZB s Fundacao Zoo-Botanica de Belo Horizonte", -"BI s Istituto Ortobotanico", -"BIA s British Institute of Archaeology", -"BIDA s Boise State University", -"BIE s Instituto di Entomologia", -"BIEL s Universitaet Bielefeld, Abteilung Oekologie", -"BIGU s Universidad de San Carlos de Guatemala, Departamento de Botanica", -"BIL s Forest Research Institute, Natural Forest Department", -"BILAS s Institute of Botany", -"BIM s Birmingham Natural History and Microscopical Society", -"BIM c Belarus National Academy of Sciences", -"BING s State University of New York, Biological Sciences Department", -"BIO s Universidad del Pais Vasco/EHU, Departamento de Biologia Vegetal y Ecologia (Botanica)", -"BioCC c BioCC BioCen Culture Collection", -"BIOT s Regional Center for Tropical Biology", -"BIOUG s Biodiversity Institute of Ontario, University of Guelph", -"BIRA s Birmingham Museums and Art Gallery, Curatorial Services", -"BIRDI b Biotechnology Research & Development Institute Vietnam", -"BIRM s University of Birmingham", -"BISH s Bishop Museum, Department of Natural Sciences", -"BITU s Department of Biology, Faculty of Science, Toyama University", -"BIUB s Mongolian Academy of Sciences", -"BJ h Bi Jie University", -"BJA s University of Burundi, Biology Department", -"BJFC s Beijing Forestry University", -"BJM s Beijing Natural History Museum", -"BJRI b Gene bank at Bangladesh Jute Research Institute", -"BJTC s Capital Normal University, Biology Department", -"BK s Bangkok Herbarium", -"BKF s Royal Forest Department", -"BKL s Brooklyn Botanic Garden", -"BKNU s Kunsan National University", -"BLA s Fundacao Estadual de Pesquisa Agropecuaria", -"BLAT s St. Xavier's College, Botany Department", -"BLCU s Bee Biology and Systematics Laboratory", -"BLFU s University of the Free State, Department of Botany and Genetics", -"BLGA s Burgenlandisches Landesmuseum", -"BLH s Cranbrook Institute of Science", -"BLIH s Biological Laboratory Imperial Household of Japan", -"BLMAR h Bureau of Land Management Arcata Field Office", -"BLMLK s Bureau of Land Management", -"BLMPR h Bureau of Land Management, Prineville Field Office", -"BLT s Belfast Natural History and Philosophical Society", -"BLUZ s Museo de Biologia", -"BLWG c Bayerische Landesanstalt fur Weinbau und Gartenbau", -"BLY s Harvey Institute, Barnsley Naturalist and Scientific Society", -"BM s The Natural History Museum, Herbarium", -"BM s Bristol Museum", -"BMAM s Beijing Natural History Museum", -"BMARI b Bandaranayake Memorial Ayurvedic Research Institute", -"BMB s Booth Museum of Natural History", -"BMBN s Booth Museum of Natural History", -"BMCC c Brittany Microbe Culture collection", -"BMFM-UNAM c Culture Collection of Fungal Pathogens Strains from the Basic Mycology Laboratory of the Department of Microbiology and Parasitology, Faculty of Medicine, UNAM", -"BMGB s Barbados Museum and Historical Society", -"BMH s Bournemouth Natural Science Society Museum, herbarium", -"BMHP s Bermuda Department of Agriculture and Fisheries", -"BMKB s Brunei Museum", -"BMM s Buergermeister Mueller, Museum", -"BMNH s Natural History Museum, London", -"BMNH:ENT s Natural History Museum, London, Entomology collection", -"BMNHC s Burpee Museum of Natural History", -"BMPS s Bristol Museum and Philosophical Society", -"BMR s Bureau of Mineral Resources", -"BMRP s Burpee Museum Rockford Paleontology", -"BMSA s National Museum Bloemfontein", -"BMSC s Buffalo Museum of Science", -"BMUK s Bolton Museum", -"BNA c National Bank of Algae", -"BNA s British (Empire) Naturalists' Association", -"BNBE s YMCA Hostel", -"BNFF s Banff Museum", -"BNFH h U.S. Forest Service, Bitterroot National Forest", -"BNH s Nassau Botanical Gardens, Department of Agriculture", -"BNHD s Bengal Natural History Museum", -"BNHM s Beijing Natural History Museum", -"BNHM s Bombay Natural History Museum", -"BNHS s Bombay Natural History Society", -"BNI c Bernhard Nocht Institute for Tropical Medicine", -"BNL s Bundesamt fuer Naturschutz", -"BNM c Banco Nacional Microorganismos (National Bank of Microorganisms)", -"BNP s Banff Park Museum", -"BNPL s Brighton Public Library", -"BNRH s Buffelskloof Nature Reserve", -"BNS s Bristol Museum and Art Gallery", -"BNU s Beijing Normal University, Biology Department", -"BO s Herbarium Bogoriense", -"BOC s Bingham Oceanographic Collection", -"BOCH s Ruhr-Universitaet Bochum, Spezielle Botanik", -"BOD s University of Oxford", -"BOG s Universidad de La Salle", -"BOGOS b Botanical Garden of Osnabruck University", -"BOIS s Rocky Mountain Research Station", -"BOL s University of Cape Town, Botany Department", -"BOLO s Universita di Bologna", -"BOLV s Nacional Forestal Martin Cardenas", -"BON s Bolton Museum, Art Gallery and Aquarium", -"BONB s Bolton Botanical Society", -"BONL s Bolton Linnean Society", -"BONN s Botanisches Institut und Botanischer Garten der Universitaet Bonn", -"BOON s Appalachian State University, Biology Department", -"BOR s Guermonprez Museum", -"BORD s Jardin Botanique de la Ville de Bordeaux", -"BORH s Universiti Malaysia Sabah", -"BORN s Institute for Tropical Biology and Conservation, Borneensis", -"BOROK c The Collection of algae", -"BOSC s Boston State College, Biology Department", -"BOTU s Universidade Estadual Paulista, Departamento de Botanica", -"BOUM s Museum d'Histoire Naturelle de Bourges", -"BOZ s Naturmuseum Suedtirol/Museo Scienze Naturali Alto Adige", -"BP s Hungarian Natural History Museum, Botanical Department", -"BPBM s Bernice P. Bishop Museum", -"BPBM:Fish s Bernice P. Bishop Museum, Fish Collection", -"BPBM:IZ s Bernice P. Bishop Museum, Invertebrate Zoology", -"BPI sc U.S. National Fungus Collections, Systematic Botany and Mycology Laboratory", -"BPI s Bernard Price Institute for Palaeontological Research", -"BPIC c Benaki Phytopathological Institute Collection", -"BPL s Museum of Barnstaple & North Devon", -"BPM s Beipiao Paleontological Museum", -"BPPT-ESC c BPPT Ethanol-Single Cell Protein-Fructose Syrup Technical Unit", -"BPS s California Department of Food and Agriculture", -"BPU s Eoetvoes Lorand University, Department of Plant Taxonomy and Ecology", -"BR s Botanic Garden Meise", -"BR c Embrapa Agrobiology Diazothrophic Microbial Culture Collection", -"BRA s Slovak National Museum, Botany Department", -"BRAD s University of Bradford, Biology Department", -"BRC s Botanical Record Club", -"BRCC c USDA-ARS Rhizobium Germplasm Resource Collection", -"BRCH s Botanical Research Center", -"BRE s Universite", -"BREE s Braintree and Bocking Natural History Club", -"BREG s Vorarlberger Naturschau", -"BREM s Uebersee-Museum", -"BRFL s City of Birmingham Reference Library", -"BRFM c Banque de Ressources Fongiques de Marseille", -"BRG s University of Guyana, Biology Department", -"BRGE s Laboratoire de Genetique des Plantes Superieures", -"BRH s Ministry of Natural Resources, Local Government, and the Environment", -"BRI s Brisbane Botanic Gardens Mt Coot-tha", -"BRIP sc The Plant Pathology Herbarium, Department of Agriculture, Fisheries and Forestry", -"BRIST s University of Bristol, Botany Department", -"BRISTM s Bristol Museum and Art Gallery", -"BRIT s Botanical Research Institute of Texas", -"BRIU s University of Queensland, Botany Department", -"BRL s Bristol City Library", -"BRLU s Universite Libre de Bruxelles", -"BRM s Alfred-Wegener-Institut fuer Polar- und Meeresforschung", -"BRMI s Birmingham and Midland Institute", -"BRN s Sexey's School", -"BRNL s Mendel University of Agriculture and Forestry, Department of Forest Botany, Dendrology, and Typology", -"BRNM s Moravian Museum, Botany Department", -"BRNU s Masaryk University, Department of Botany", -"BROC s State University of New York, Biological Sciences Department", -"BRS s Agriculture and Agri-Food Canada", -"BRSL s Wroclaw University, Botany Department", -"BRSMG s Department of Geology", -"BRSN s University of Wales, Bangor Research Unit", -"BRSU h Bryansk State University", -"BRTN s Brighton Natural History Society", -"BRU s Brown University", -"BRUN s Brunei Forestry Centre", -"BRV s Colecciones paleontologicas del Departamento de Geociencias de la Universidad Nacional de Colombia", -"BRVU s Vrije Universiteit Brussel", -"BRWK s Berwick-upon-Tweed Museum", -"BRY s Brigham Young University", -"BSA s Botanical Survey of India, Central Circle", -"BSB s Freie Universitaet Berlin, Institut fuer Biologie - Systematische Botanik und Pflanzengeographie", -"BSC s Centro Oriental de Ecosistemas y Biodiversidad", -"BSCA s Anza-Borrego Desert State Park", -"BSCVC s Bemidji State University, Vertebrate Collections", -"BSD s Botanical Survey of India, Northern Circle", -"BSE s Moyse's Hall Museum", -"BSHC s Botanical Survey of India, Sikkim Himalayan Circle", -"BSI s Botanical Survey of India, Western Circle, Ministry of Environment and Forests", -"BSID h Botanical Survey of India", -"BSIP s Ministry of Natural Resources, Department of Forests, Environment, and Conservation", -"BSIS s Botanical Survey of India, Industrial Section", -"BSJO s Botanical Survey of India, Arid Zone Circle", -"BSKU s Kochi University", -"BSL s Botanical Society of London", -"BSM s Berliner Staatisches Museum", -"BSMB c Bacteriology and Soil Microbiology Branch", -"BSMP s Department of Agriculture, Bureau of Science", -"BSN s Boston University, Biology Department", -"BSNH s Boston Society of Natural History", -"BSNS s Buffalo Society of Natural Sciences", -"BSPG s Bayerische Staatssammlung fuer Palaeontologie und Geologie", -"BSRA s University of Basrah, Biology Department", -"BSRM s Biological Station Reference Museum at Porto Novo", -"BST s Belfast Naturalists' Field Club", -"BSTN s Boothstown Botanical Society", -"BSU s Belgorod State University, Department of Botany", -"BSUH s Ball State University, Biology Department", -"BSUMC s Ball State University, Mammal Collection", -"BTCC c Bulgarian Type Culture Collection", -"BTCC c Biotechnology Culture Collection Institution Pusat Penelitian dan Pengembangan Bioteknologi-LIPI", -"BTH s Museum, Bath Royal Literary and Scientific Institution", -"BTJW s Bridger Teton National Forest", -"BTN s Booth Museum of Natural History", -"BTT s Burton-upon-Trent Natural History and Archaeological Society", -"BTU s Technische Universitaet Berlin", -"BU h Brock University", -"BUA s University of Baghdad, Plant Protection Department", -"BUAG s University of Agronomical Sciences and Veterinary Medicine, Botany and Plant Physiology Department", -"BUC s Universitatea din Bucuresti", -"BUCA s Institute of Biology, Romanian Academy", -"BUCF s Forest Research and Management Institute", -"BUCM s Institute of Biology, Romanian Academy", -"BUCSAV c Biologicky Ustav", -"BUE s University of Baghdad, Biology Department", -"BUEN s Proteccion de la Naturaleza", -"BUF s Buffalo Museum of Science", -"BUH s University of Baghdad, Biology Department", -"BUHGC s Barton-on-Humber Grammar School", -"BUHR s Baysgarth Museum", -"BUL s Natural History Museum of Zimbabwe", -"BULQ s Bishop's University", -"BULU s Uludag University, Biology Department", -"BUNH s University of Baghdad", -"BUNS s University of Novi Sad, Department of Biology and Ecology", -"BUPL s Bucknell University, Biology Department", -"BURD s University of Burdwan, Botany Department", -"BURI h Banasthali University", -"BURP s Burpee Museum of Natural History", -"BUS s University of Miami, Biology Department", -"BUT s Butler University", -"BUTC s Boston University", -"BVC s Buena Vista College", -"BVS h Transylvania University of Brasov", -"BYBS s Bungay Botanical Society", -"BYDG s Technical-Agriculture Academy, Department of Botany and Ecology", -"BYU s Monte L. Bean Life Science Museum", -"BZ s Herbarium Bogoriense", -"BZCM h Bozhou Vocational and Technical College", -"BZF s Forest Research and Development Center and Nature Conservation", -"BZM s Museum fur Naturkunde, Berlin", -"BZT s Biological Institute Titograd", -"C s Botanical Museum, Natural History Museum of Denmark", -"CA s Chicago Academy of Sciences", -"CABI c CABI Genetic Resource Collection", -"CACA s Carlsbad Caverns National Park", -"CACC c China Antibiotic Culture Collection Center", -"CACS s Chicago Academy of Sciences, Department of Biology", -"CAEN s Jardin Botanique de la Ville de Caen", -"CAES s Connecticut Agriculture Experiment Station", -"CAF s Chinese Academy of Forestry", -"CAFB s Northern Forestry Centre, Canadian Forest Service", -"CAG s Universita di Cagliari", -"CAH s University of Zimbabwe, Biological Sciences Department", -"CAHS s Crispus Attucks High School", -"CAHUP s University of the Philippines Los Banos", -"CAI s Cairo University, Botany Department", -"CAIA s Ain Shams University, Department of Botany", -"CAIH s Desert Research Center, Mataria, Plant Ecology", -"CAIM s Agricultural Research Center", -"CAIM c Collection of Aquatic Important Microorganisms", -"CAIRC s National Research Centre, Plant Chemistry and Systematics Department", -"CAIRCC c CAIRCC", -"CAIRNS s c/o North Queensland Naturalists' Club", -"CAL s Botanical Survey of India", -"CALI s University of Calicut, Botany Department", -"CALP s University of the Philippines at Los Banos", -"CALU c Collection of Algae in Leningrad, St. Petersburg, State University", -"CALVIN h Calvin College", -"CAM s Central Australian Museum", -"CAM s St. John's College", -"CAME s Universita di Camerino, Dipartimento de Botanica ed Ecologia", -"CAMS c Centre for Applied Mycological Studies", -"CAMU s Cameron University, Department of Biological Sciences", -"CAN s Canadian Museum of Nature, Vascular Plant Section", -"CANA s Canadian Museum of Nature, Phycology Section", -"CANB s Australian National Herbarium, Canberra", -"CANI s Canisius College, Biology Department", -"CANL s Canadian Museum of Nature, Lichenology Section", -"CANM s Canadian Museum of Nature, Bryology Section", -"CANT s South China Agricultural University, Forestry Department", -"CANTY s Canterbury Museum", -"CANU s University of Canterbury, Department of Plant and Microbial Sciences", -"CAPM c Collection of Animal Pathogenic Microorganisms", -"CAR s Museo de Historia Natural La Salle, Departamento de Botanica", -"CARAN h Herbarium Carautanum", -"CARD s Caribbean Agricultural Research Institute", -"CARE s Caribbean Epidemiology Centre", -"CARI s Cukurova Agricultural Research Institute", -"CARL s Carleton College, Biology Department", -"CARM s Carmarthen County Museum", -"CARS s University of Surinam, Center for Agricultural Research", -"CART s Carthage College, Biology Department", -"CAS s California Academy of Sciences", -"CAS-IU s California Academy of Science, Indiana University Collection", -"CAS-SU s California Academy of Sciences, Stanford University Collection", -"CAS:ANTH s California Academy of Sciences, Anthropology Collection", -"CAS:BOT s California Academy of Sciences, Botany Collection", -"CAS:DIA s California Academy of Sciences, Diatom collection", -"CAS:DS s California Academy of Sciences, Dudley Stanford Collection", -"CAS:EGG s California Academy of Sciences, Egg & Nest Collection", -"CAS:ENT s California Academy of Sciences, Entomology collection", -"CAS:HERP s California Academy of Sciences, Herpetology collection", -"CAS:ICH s California Academy of Sciences, Ichthyology collection", -"CAS:IU s California Academy of Sciences, Indiana University fish collection", -"CAS:IZ s California Academy of Sciences, Invertebrate Zoology collection", -"CAS:MAM s California Academy of Sciences, Mammalogy Collection", -"CAS:ORN s California Academy of Sciences, Ornithology Collection", -"CAS:SU s California Academy of Sciences, Stanford University Collection of fish", -"CAS:SUA s California Academy of Sciences, Stanford University Collection of amphibians", -"CAS:SUR s California Academy of Sciences, Stanford University Collection of reptiles", -"CAS:TYPE s California Academy of Sciences, Entomology Type Collection", -"CASM s Chicago Academy of Sciences, Museum of Natural History", -"CASMB s Centre of Advanced Study in Marine Biology", -"CASS s Chinese Academy of Sciences, Shenyang", -"CAT s Universita di Catania, Dipartimento di Botanica e Orto Botanico", -"CATA h Catalina Island Conservancy", -"CATH h Catholicate College", -"CATIE s Tropical Agricultural Research and Training Center (CATIE), Plant Production Department", -"CAU s China Agricultural University", -"CAUP s Universidad del Cauca", -"CAUP c Collection of Algae of Charles University, Prague", -"CAUSC s Universidade Federal de Santa Catarina Centro de Agrarias", -"CAVA s University of California at Berkeley", -"CAY s Institut de Recherche pour le Developpement (IRD)", -"CAYM s National Trust for the Cayman Islands", -"CB c The CB Rhizobium Collection", -"CB s Jihoceske Muzeum", -"CBAS c Bacteria Collection of Environmemt and Health (Colecao de Bacterias do Ambiente e Saude)", -"CBD s Collezione Ittiologica Balma-Delmastro", -"CBD c USF Center for Biological Defense", -"CBF s Coleccion Boliviana de Fauna", -"CBFS s University of South Bohemia, Department of Botany", -"CBG s Australian National Botanic Gardens", -"CBM s Natural History Museum and Institute", -"CBM:ZC s Natural History Museum and Institute, Zoological Collection", -"CBMAI c Brazilian Collection of Microorganisms from the Environment and Industry (Colecao Brasileira de Microrganismos de Ambiente e Industria)", -"CBNM s Cedar Breaks National Monument", -"CBNSA h Conservatoire botanique national Sud-Atlantique", -"CBPF h Conservatoire Botanique Pierre Fabre", -"CBS sc Centraalbureau voor Schimmelcultures, Fungal and Yeast Collection", -"CBSIZA s Caspian Biological Station Institute of Zoology", -"CBTCCCAS c The Cell Bank of Type Culture Collection of Chinese Academy of Sciences", -"CBU s Cape Breton University", -"CBU s Chungbuk National University, School of Life Science", -"CBY s Royal Museum and Art Gallery", -"CC c CSIRO Canberra Rhizobium Collection", -"CCA-Marburg c Culture Collection of Algae at the University of Marburg", -"CCAC s Universidade Federal do Ceara, Centro Ciencias Agrarias", -"CCAC c Culture Collection of Algae at the University of Cologne", -"CCALA c Culture Collection of Autotrophic Organisms", -"CCAP c Culture Collection of Algae and Protozoa", -"CCARM c Culture Collection of Antimirobial Resistant Microorganisms", -"CCAU s Central China Agricultural University", -"CCB c Colecao de Culturas de Basidiomicetos", -"CCB s Central College, Bangalore", -"CCBAS c Culture Collection of Basidiomycetes", -"CCBAU c Culture Collection, Beijing Agricultural University", -"CCC c Culture Collection of Clavicipitaceae", -"CCC c Cyanobacterial Culture Collection, National Centre for Conservation and Utilisation of Blue Green Algae", -"CCCC s Carthage College", -"CCCIEB c Culture Collections of Microorgansisms of Center of Genetic Engineering and Biotechnology", -"CCCM c Canadian Center for the Culture of Microorganisms", -"CCCR h Federal University of Tocantins", -"CCCryo c Culture Collection of Cryophilic Algae", -"CCCS c Culture Collection of Ciliates and their Symbionts", -"CCCZ s University of Malawi", -"CCDB s Crustacean Collection of the Department of Biology", -"CCDM c Culture Collection of Department of Microbiology", -"CCDM c Culture Collection of Dairy Microorganisms Laktoflora", -"CCDMBI c Culture Collection, Department of Microbiology", -"CCEB c Culture Collection of Entomogenous Bacteria", -"CCEC s Museum, Centre de Conservation et d'Etude des Collections", -"CCF c Colleccion de Cuttivos Finlay", -"CCF c Culture Collection of Fungi", -"CCFC c Canadian Collection of Fungal Cultures", -"CCFEE c Culture Collection of Fungi From Extreme Environments", -"CCFHE s Cornwall College of Further and Higher Education, Natural Sciences Department", -"CCFL s Chad National Museum", -"CCFVB c Facultat de Veterinaria, Universitat Autonoma de Barcelona", -"CCG s Chengdu College of Geology", -"CCG s University of Cape Coast, Botany Department", -"CCGB c Cole(e7)o de Culturas do G(ea)ero Bacillus e G(ea)eros Correlatos", -"CCGVCC c China Centre for General Viruses Culture Collection", -"CCH h University of Arizona South, Agricultural Extension Service", -"CCIAL c Cultures Cells for Institute Adolfo Lutz", -"CCIBSO c Culture Collection IBSO", -"CCIM c Culture Collection of Industrial Microorganisms", -"CCM c Czech Collection of Microorganisms", -"CCM-A c Coleccion de Cultivos Microbianos", -"CCM s Changchun College of Traditional Chinese Medicine, Department of Chinese Materia Medica", -"CCM s Carter County Museum", -"CCMAC c Culture Collection of Macromycetes (Basidiomycotina and Ascomycotina)", -"CCMCU c Culture Collection of Microorganisms", -"CCMF c University of Portsmouth", -"CCMGE s Chernyshev Central Museum of Geological Explorations,Collections of the Department of Herpetology, Zoological Institute of the Russian Academy of Sciences", -"CCMH h Concordia College", -"CCMI c Culture Collection of Industrial Microorganisms", -"CCML s Coleccion Ictiologica del Departamento de Ciencias Marinas de la Universidad de la Laguna", -"CCMM c Moroccan Coordinated Collections of Microorganisms", -"CCMP c Provasoli-Guillard National Center for Marine Algae and Microiota", -"CCNH s Central Michigan University, Center for Cultural and Natural History", -"CCNL s Connecticut College, Botany Department", -"CCNP s Carlsbad, Carlsbad Caverns National Park", -"CCNP c Culture Collection of Northern Poland", -"CCNU s Central China Normal University, Biology Department", -"CCO s Carleton University, Biology Department", -"CCOS c Culture Collection of Switzerland", -"CCPF c Collection of Phytopathogenic Fungi", -"CCR s Chichester District Museum", -"CCRI c Collection du Centre de Recherche en Infectiologie", -"CCRI scb The Central Coffee Research Institute", -"CCSIIA c Culture Collection of Sichuan Industrial Institute Antibiotics", -"CCSRL s Centro Studi e Ricerche Ligabue", -"CCSU s Central Connecticut State University, Biological Sciences Department", -"CCT c Colecao de Culturas Tropical", -"CCTCC c China Center for Type Culture Collection", -"CCTM c Centre de Collection de Type Microbien, Institut de Microbiologie, Universite de Lausanne", -"CCTR c Culture Collection Trutnov", -"CCTS h Universidade Federal de Sao Carlos", -"CCTU c Culture Collection of Tabriz University", -"CCUF s Universidade Federal de Alagoas, Centro de Ciencias Biologicas", -"CCUG c Culture Collection, University of Goteborg, Department of Clinical Bacteriology", -"CCVC s Centenary College, Vertebrate Collection", -"CCVCC c China Center For Virus Culture Collection", -"CCW s Casper College", -"CCY c Culture Collection Yerseke, Department of Marine Microbiology", -"CCY c Culture Collection of Yeasts, Slovak Academy of Sciences, Institute of Chemistry", -"CDA c Canadian Department of Agriculture", -"CDA s California Department of Food and Agriculture", -"CDBB c Coleccion Nacional de Cepas Microbianas y Cultivos Celulares", -"CDBI s Chengdu Institute of Biology", -"CDC c Centers for Disease Control and Prevention", -"CDC s Changdu Institute for Drug Control", -"CDCM s Chengdu College of Traditional Chinese Medicine", -"CDFM s Cardiff Museum", -"CDFN s Canadian Forest Service - Atlantic", -"CDN s Whitgift School", -"CDRI s Central Drug Research Institute", -"CDRS s Invertebrate Collection", -"CDS s Charles Darwin Research Station, Botany Department", -"CEAM s Centro de Entomologica y Acarologia", -"CEB s Tadulako University", -"CEBU s University of San Carlos, Biology Department", -"CECT c Coleccion Espanola de Cultivos Tipo", -"CEDD s International Center for Ethnomedicine and Drug Development", -"CEDiT s Centre of Excellence for Dinophyte Taxonomy", -"CEEF s Escuela Nacional de Ciencias Forestales", -"CEET s El Colegio de la Frontera Sur, Colleccion de Insectos Asociados a Plantas Cultivadas en la Frontera Sur", -"CEL s University of Illinois, Crop Sciences Department", -"CELM s Coleccion Entomologica \"Luis Maria Murillo\"", -"CELMS c Collection of Environmental and Laboratory Microbial Strains", -"CEMBP s Centre of Excellence in Marine Biology", -"CEN s Genetic Resources and Biotechnology (CENARGEN), EMBRAPA", -"CENA s Centro de Energia Nuclear na Agricultura, Universidade de Sao Paulo", -"CENA s Centro Nacional de Proteccion Vegetal", -"CENACUMI c Centro Nacional de Cultivos Microbianos (National Center For Microbial Cultures)", -"CENG s Centro Experimental de Nueva Guinea", -"CEP c Entomopathogenic Fungal Culture Collection of Argentina", -"CEPEC s CEPEC, CEPLAC", -"CEPH b Foundation Jean Dausset (CEPH)", -"CEPIM c Centro per gli Enterobatteri Patogeni per l'Italia Meridionale", -"CEPM c CEPM- Centre d'Etudes sur le Polymorphisme des Micro-organismes", -"CERL/BIC s United States Army, Biological Inventory Collection", -"CERN s University", -"CES s The Centre for Ecological Sciences, Indian Institute of Science", -"CESJ s Universidade Federal de Juiz de Fora, Departamento de Botanica", -"CESK s Muzeum Teainska", -"CEST s Central Experiment Station", -"CET s Centro de Estudios Tropicales", -"CETESB c Setor de Pesquisa Tecnologica de Sistemas de Tratamento de Efluentes Domesticos", -"CEU s Collage of Eastern Utah", -"CFB s Northern Forestry Centre, Canadian Forest Service", -"CFBH s Celio F.B. Haddad Herpetological Collection, Departamento de Zoologia, Universidade Estadual Paulista", -"CFBP c Collection Francaise des Bacteries Phytopathogenes", -"CFCC cb China Forestry Culture Collection Center", -"CFI s Genetic Resources and Biotechnology (CENARGEN), EMBRAPA", -"CFIA h Canadian Food Inspection Agency", -"CFMR sc Center for Forest Mycology Research", -"CFN s Clifton College, Biology Department", -"CFNL s Universidad Autonoma de Nuevo Leon", -"CFQ c Cepario de la Facultad de Quimica", -"CFRB s Chinese Academy of Forestry, Forest Research Institute", -"CFS s Canadian Forest Service, Pacific Forest Research Centre", -"CFSHB s North Coast Regional Botanic Gardens", -"CFUA s Universidad Austral de Chile", -"CG c Embrapa Collection of Fungi of Invertebrates", -"CGC b Caenorhabditis Genetics Center", -"CGE s University of Cambridge, Department of Plant Sciences", -"CGEC s China Entomological Research Institute", -"CGG s Cambridge University Botanic Garden", -"CGH s National Museum of Prague", -"CGMCC c China General Microbiological Culture Collection Center, Chinese Academy of Sciences", -"CGMS s Universidade Federal de Mato Grosso do Sul, Departamento de Biologia", -"CGN s Centre for Genetic Resources, The Netherlands", -"CGRIS b Chinese Crop Germplasm Resources Information Network", -"CGSC c E. coli Genetic Stock Center", -"CH s Circulo Herpetologico de Panama", -"CH-AG c Collection de Recherche", -"CHA s Hebei Agrotechnical Teachers College", -"CHAB s Far East Forestry Research Institute", -"CHAF s Chaffey College, Biology Department", -"CHAM s I.N.T.A., E.E.A. La Rioja", -"CHAP s Universidad Autonoma Chapingo", -"CHAPA s Colegio de Postgraduados, Botanica, IRENAT", -"CHARL s Charleston Museum", -"CHAS s Chicago Academy of Sciences", -"CHAS s Southern Research Station", -"CHBG s Christchurch Botanic Gardens", -"CHE s Societe Nationale des Sciences Naturelles et Mathematiques de Cherbourg", -"CHEB s Regional Museum Cheb", -"CHEL s Chelsea Physic Garden", -"CHELB s Cheltenham College for Boys", -"CHEP s Escuela Superior Politecnica del Chimborazo", -"CHER s Yu. Fedcovich Chernivtsi State University, Botany Department", -"CHFD s Chelmsford and Essex Museum", -"CHI s University of Illinois, Biological Sciences Department", -"CHIA s National Chiayi Agricultural College, Forestry Department", -"CHIC s Chicago Botanic Garden, Research Department", -"CHINM s Instituto Nacional de Microbiologia", -"CHIOC s Helminthological Collection of Oswaldo Cruz Institute (Coleccion. Helmintologica del Instituto Oswaldo Cruz)", -"CHIP s Instituto de Historia Natural, Departamento de Botanica", -"CHIS s Academy of Sciences of Moldova", -"CHISA s University of Agriculture", -"CHL s Cheltenham Grammar School", -"CHM s Cheltenham Art Gallery and Museum", -"CHM s Charleston Museum", -"CHNCB s Centre d'Historia Natural de la Conca de Barbera", -"CHOCO s Universidad Tecnologica del Choco", -"CHOM s Okresni muzeum Chomutov", -"CHPU s Chelyabinsk State Pedagogical University, Botany Department", -"CHR s Allan Herbarium", -"CHRB s Rutgers University - Cook College", -"CHRG s Grosvenor Museum", -"CHSC s California State University, Biological Sciences Department", -"CHT s Cheltenham College", -"CHUG s Garyounis University, Botany Department", -"CHULA c Microbiology Department Faculty of Science", -"CHUNB s University of Brasilia Herpetological Collection", -"CHUR s Buendner Natur-Museum", -"CI s Carnegie Institution of Washington, Plant Biology Department", -"CIAN s Instituto Nacional de Investigaciones Forestales, Agricolas y Pecuarias (INIFAP)", -"CIAN s Centro de Investigaciones Agricolas Nortoeste", -"CIAT b Centro Internacional de Agricultura Tropical (International Center for Tropical Agriculture)", -"CIAT:Bean b Centro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Bean Collection", -"CIAT:Cassava b Centro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Cassava Collection", -"CIAT:Forage b Centro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Forages Collection", -"CIAT:Rhizobium c Centro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Rhizobium Collection", -"CIB s Chengdu Institute of Biology", -"CIB s Centro de Investigaciones Biologicas del Noroeste, S.C. (Mexico)", -"CIB s Universidad Veracruzana", -"CIBC s International Institute of Biological Control", -"CIBIO s Centro de Investigacao em Biodiversidade e Recursos Geneticos", -"CIBM s Centro Invest. Biol. Noroeste", -"CIC s Albertson College of Idaho, Biology Department", -"CICC c China Center for Industrial Culture Collection", -"CICESE s Centro de Investigacion Cientifica y de Educacion Superior de Ensenada", -"CICIM c Culture and Information Centre of Industrial Microorganisms of China's Univeristies", -"CICIMAR s Centro Interdisciplinario de Ciencias Marinas", -"CICV c Centro de Investigaciones en Ciencias Veterinarias", -"CICY s Centro de Investigacion Cientifica de Yucatan, A.C. (CICY)", -"CIDA s Albertson College, Museum of Natural History", -"CIECRO s County Record Office, Cambridgeshire", -"CIES c Centro de Investigacion, Experimentacion y Servicios del Champinon", -"CIFE s Central Institute of Fisheries Education", -"CIIDIR s Instituto Politecnico Nacional", -"CIJC s Muzeului Judetean Covasna, Collection of Insects", -"CIMAP s Central Institute of Medicinal and Aromatic Plants", -"CIMAR s Universidad Catolica de Valparaiso, Centro de Investigaciones del Mar", -"CIMI s Centro Interdisciplinario de Investigacion para el Desarrollo Integral Regional (CIIDIR) IPN-Michoacan", -"CIMMYT scb International Maize and Wheat Improvement Center", -"CIMNH s Albertson College of Idaho, Orma J. Smith Museum of Natural History", -"CIMSC c Collezione Instituto di Microbiologia", -"CINC s University of Cincinnati, Biological Sciences Department", -"CIP c Pasteur Institute Collection, Biological Resource Center of Pasteur Institute (CRBIP)", -"CIP s Centro de Investigaciones Pesqueras", -"CIP c International Potato Center", -"CIP b Centro Internacional de las Papas", -"CIPDE c Collection of Insect Pathogens, Dept. of Entomology", -"CIPT c Collection Institut Pasteur Tuberculose", -"CIQR s El Colegio de la Frontera Sur", -"CIR s Royal Agricultural College", -"CIRAD sb Centre de Cooperation Internationale en Recherche Agronomique pour le Developpement", -"CIRUV s Coleccion Ictiologica de Referencia de la Universidad del Valle", -"CIS s Academia Sinica and State Planning Commission", -"CIS s California Insect Survey", -"CIS s Cranbrook Institute of Science", -"CISM c Verticillium dahliae from cotton", -"CISM c NifTAL Rhizobium Collection (Asia Center)", -"CIT s Citrus Research Institute", -"CITA s The Citadel, Biology Department", -"CIUC s Centro Interdipartimentale dell'Universita Museo di Storia Naturale e del Territorio", -"CIZ s Centro de Investigaciones Zoologicas", -"CKE s Calke Abbey", -"CL s Babes-Bolyai University", -"CLA s Universitatea de Stiinte Agricole si Medicina Veterinara", -"CLARK h Dr. Charles F. and Wilhelmina Husser Clark Herbarium", -"CLCB s Laboratorul de Ecologie", -"CLCC s Augustana University College", -"CLD s Cleveland Literary and Philosophical Society", -"CLE s Tullie House Museum", -"CLEMS s Clemson University, Biological Sciences Department", -"CLEV s Cleveland Museum of Natural History", -"CLEY s Coastal Ecology Research Station", -"CLF s Institut des Universitaires et Musee Lecoq", -"CLI s Literary and Philosophical Institution of Chatham", -"CLIB c Collection de Levures d'Interet Biotechnologique Collection of Yeasts of Biotechnological Interest", -"CLIOC c Colecao de Leishmania do Instituto Oswaldo Cruz", -"CLM s Cleveland Museum of Natural History, Botany Department", -"CLMP s Department of Conservation & Land Management", -"CLNP s Crater Lake National Park", -"CLOE s Clitheroe Castle Museum", -"CLP s Forest Products Research and Development Institute, Department of Science and Technology", -"CLQCA c Coleccion de Levaduras quito catolica", -"CLR s All Saint's Church, Colchester Borough Council", -"CLU s Universita della Calabria", -"CM s Carnegie Museum of Natural History", -"CM-IEA s Universidad Autonoma de Tamaulipas (Mexico)", -"CM-MBM-UAC s Coleccion Mastozoologica de la Museo de Biodiversidad Maya, Universidad Autonoma de Campeche", -"CM-UMSNH s Universidad de Michoacan (Mexico)", -"CM:M s Carnegie Museum of Natural History, Section of Mammals", -"CM:O s Carnegie Museum of Natural History, Section of Birds", -"CM s Chongqing Museum", -"CMA s Crayford Manor House Adult Education Centre", -"CMBGCAS c Collection of Marine Biological Germplasm", -"CMBK s The City Museum and Art Gallery, Department of Natural History", -"CMBY s Camberley Museum", -"CMC s Coleccion Mastozoologica del Centro de Investigacion en Biodiversidad y Conservacion,Universidad Autonoma del Estado de Morelos", -"CMC s Canterbury Museum", -"CMC s Central Michigan University, Department of Biology", -"CMCC c National Center for Medical Culture Collections", -"CMCNA s Museo de Ciencias Naturales y Antropologicas \"Prof. A. Serrano\"", -"CMDM-PUJ c Coleccion Microorganismos Departamento Microbiologia", -"CMEI s Clements' Museum of Exotic Insects", -"CMFRI s See FMRI", -"CMGP s Central Museum of Geological Prospecting", -"CMIZASDPRK s Custody Museum", -"CMKKU c Clinical Diagnostic Microbiology Srinagarind Hospital, Faculty of Medicine", -"CML s Universidad Nacional de Tucuman, Coleccion de Mamiferos Lillo (Argentina)", -"CML c Colecao Micologica de Lavras", -"CMM s Bradford Art Galleries and Museums, Natural Sciences Department", -"CMM c Culture Collection of Phytopathogenic Fungi (Colecao de Culturas de Fungos Fitopatogenicos Prof. Maria Menezes)", -"CMMC c China Marine Microbe Collection", -"CMMED c Center for Marine Microbial Ecology & Diversity Collection", -"CMMEX s Universidad Autonoma de Baja California", -"CMMF h Jardin botanique de Montreal", -"CMMI s Chinese Academy of Traditional Medicine", -"CMML s Colorado State University Herbarium", -"CMN s Canadian Museum of Nature", -"CMN:Annelid s Canadian Museum of Nature, Annelid Collection", -"CMN:Bird s Canadian Museum of Nature, Bird Collection", -"CMN:Crustacean s Canadian Museum of Nature, Crustacean Collection", -"CMN:Fish s Canadian Museum of Nature, Fish Collection", -"CMN:GenInvert s Canadian Museum of Nature, General Invertebrate Collextion", -"CMN:Herp s Canadian Museum of Nature, Amphibian and Reptile Collection", -"CMN:Insect s Canadian Museum of Nature, Insect Collection", -"CMN:Mammal s Canadian Museum of Nature, Mammal Collection", -"CMN:Mollusc s Canadian Museum of Nature, Mollusc Collection", -"CMN:Parasite s Canadian Museum of Nature, Parasite Collection", -"CMNAR s Canadian Museum of Nature, Amphibian and Reptile Collection", -"CMNC s Canadian Museum of Nature, Neotropical Cerambycidae Collection", -"CMNFI s Canadian Museum of Nature, Fish Collection", -"CMNH s The Cleveland Museum of Natural History", -"CMNS s Museum of Natural History, Shanghai", -"CMNZ s Canterbury Museum", -"CMPH h Colegio de Postgraduados", -"CMPR h Centre for Medicinal Plants Research", -"CMS h Christian Missionary Society College", -"CMSK s City Museum, Sheffield", -"CMSU s Central Missouri State University", -"CMU s Chiang Mai University", -"CMUB h Chiang Mai University", -"CMUH h Central Mindanao University", -"CMUT s Chiang Mai University", -"CMV s Centre Marie-Victorin", -"CMW c Forestry and Agricultural Biotechnology Institute, University of Pretoria, Pretoria", -"CMY s R. G. Kar Medical College, Botany Department", -"CN s Universite de Caen", -"CN c Wellcome Collection of Bacteria, Burroughs Wellcome Research Laboratories", -"CNC s Canadian National Collection of Insects, Arachnids, and Nematodes", -"CNC:Arachnida s Canadian National Collection of Insects, Arachnids, and Nematodes, Arachnida (Mites, Ticks, Spiders)", -"CNC:Coleoptera s Canadian National Collection of Insects, Arachnids, and Nematodes, Coleoptera (Beetles)", -"CNC:Diptera s Canadian National Collection of Insects, Arachnids, and Nematodes, Diptera (Flies)", -"CNC:Hemiptera Canadian National Collection of Insects, Arachnids, and Nematodes, ", -"CNC:Hymenoptera s Canadian National Collection of Insects, Arachnids, and Nematodes, Hymenoptera (Sawflies, Parasitic Wasps, Ants, Wasps, Bees)", -"CNC:Lepidoptera s Canadian National Collection of Insects, Arachnids, and Nematodes, Lepidoptera (Butterflies, Moths)", -"CNC:Miscellaneous s Canadian National Collection of Insects, Arachnids, and Nematodes, Miscellaneous Insect Orders", -"CNC:Nematoda s Canadian National Collection of Insects, Arachnids, and Nematodes, Nematoda (Roundworms)", -"CNCI s Canadian National Collection Insects", -"CNCM c Collection Nationale de Cultures de Microorganismes", -"CNCTC c Czech National Collection of Type Cultures", -"CNE s Victoria Jubilee Museum", -"CNEN-LABPC c Laboratorio de Pocos de Caldas", -"CNF s Croatian Mycological Society", -"CNH h Canakkale Onsekiz Mart University", -"CNHM s Croatian Natural History Museum, Botany Department", -"CNHM s Cincinnati Museum of Natural History", -"CNHP s Beijing Natural History Museum", -"CNHS s Croydon Natural History and Scientific Society", -"CNM s Cheltenham Naturalists' Association", -"CNM-CM c Filamentous fungus collection of the Spanish National Center for Microbiology", -"CNM s Centro Nacional de Microbiologia", -"CNMC s Colorado National Monument", -"CNMS s Colombo National Museum", -"CNMT h Universidade Federal de Mato Grosso", -"CNPO h Embrapa Pecuaria Sul", -"CNPS s Centro Nacional de Pesquisas da Soja", -"CNPSo c Culture Collection of Diazotrophic and Plant Growth Promoting Bacteria of Embrapa Soja", -"CNR h Crimean Natural Reserve", -"CNRO s Centre National de Recherches Oceanographiques", -"CNRS s Centre National de la Recherche Scientifique", -"CNRZ c Centre National de Recherches Zootechniques", -"CNS s Australian Tropical Herbarium", -"CNSF h Centre National de Semences Forestieres", -"CNU s Capital Normal University, College of Life Sciences", -"CNU s Chungnam National University", -"CNU s Chonbuk National University", -"CNUK h Chungnam National University", -"CNWGRGL b Chinese National Waterfowl Germplasm Resources Gene Library", -"CO s Museum National d'Histoire Naturelle, Department of Marine Biology", -"COA s Herbario, Universidad de Cordoba - Jardin Botanico de Cordoba", -"COA s College of the Atlantic, Museum", -"COAD c Colecao Octavio de Almeida Drumond", -"COAH s Herbario Amazonico Colombiano (Instituto Amazonico de Investigaciones Cientificas SINCHI)", -"COCA s Comision Tecnico Consultiva de Coeficientes de Agostadero (COTECOCA)", -"COCAZ h Coconino National Forest Herbarium", -"COCH s Universidad Mayor de San Simon, Departamento de Botanica", -"COCO s Colorado College, Biology Department", -"CODAGEM s Universidad Autonoma del Estado de Mexico", -"CODIMAR c Centro de Investigaciones Biologicas del Noroeste", -"COFC s Universidad de Cordoba, Departamento de Biologia Vegetal", -"COI s University of Coimbra", -"COL s Universidad Nacional de Colombia", -"COLG s Columbus State University, Biology Department", -"COLM s Colorado National Monument", -"COLO s University of Colorado", -"COLOM s Colorado State Museum", -"COM s Colombo Museum", -"CON s Bristol, Clifton and West of England Zoological Society's Gardens", -"CONC s Universidad de Concepcion, Departamento de Botanica", -"CONN s University of Connecticut, Department of Ecology and Evolutionary Biology", -"CONV s Converse College, Biology Department", -"COP s Coleccion Ornitologica Phelps", -"COR s Universidade Federal de Mato Grosso do Sul, Departamento de Ciencias do Ambiente", -"CORB s Corchester School", -"CORBIDI s Centro de Ornitologia y Biodiversidad", -"CORD s Universidad Nacional de Cordoba, Facultad de Ciencias Exactas, Fisicas y Naturales", -"Coriell cb Coriell Institute for Medical Research", -"CORO s IUTAG, Departamento de Investigacion", -"CORT s State University of New York College at Cortland, Biological Sciences Department", -"CORU s Universidad Veracruzana, Campus Cordoba", -"COV s Herbert Art Gallery and Museum", -"COVY s Coventry and District Natural History Society", -"CP s Royal Veterinary and Agricultural University, Plant Biology Department", -"CPAC c Centro de Pesquisas Agropecuarias do Cerrado", -"CPAP s Centro de Pesquisas Agropecuarias do Tropico Umido", -"CPAP s Herbario, Centro de Pesquisas Agropecuarias do Pantanal, EMBRAPA", -"CPATU s Centro de Pesquisa Agroflorestal da Amazonia Oriental-Embrapa", -"CPB s National Institute for the Control of Pharmaceutical and Biological Products", -"CPC c Culture collection of Pedro Crous", -"CPCC c Canadian Phycological Culture Centre", -"CPDC s Centro de Pesquisas do Cacau", -"CPF s KwaZulu-Natal Nature Conservation Service", -"CPH s University of the Pacific, Biological Sciences Department", -"CPHS c WHO/FAO/OIE Collaborating Centre for Reference and Research on Leptospirosis, Western Pacific Region", -"CPM s Christoffel Park Museum", -"CPMM s Dr. Alvaro de Castro Provincial Museum", -"CPNP s Cuc Phuong National Park", -"CPPIPP c Collection of Plant Pathogens", -"CPPLIP s Centro de Pesquisas Paleontologias Llewellyn Ivor Price", -"CPRC s University of Puerto Rico, Caribbean Primate Research Center Museum", -"CPRR c Laboratorio de Doenca de Chagas", -"CPS s University of Puget Sound, Slater Museum of Natural History", -"CPS s Wyoming-Colorado Paleontological Society", -"CPSC s University of Puget Sound", -"CPSU s California Polytechnic State University, San Luis Obispo", -"CPU s China Pharmaceutical University", -"CPUN s Universidad Nacional de Cajamarca, Departamento de Biologia", -"CPUP s California Polytechnic University", -"CPZ c Centro Panamericano de Zoonosis", -"CQBG s Chongqing Botanical Garden", -"CQNM s Chongqing Natural History Museum", -"CR s Museo Nacional de Costa Rica", -"CRA-CIN c Consiglio per la Ricerca e sperimentazione in Agricoltura - Centro ricerche per le Colture Industriali ( Research Centre for Industrial Crops)", -"CRA-COLMIA c Collezione Nazionale di Microrganismi di interesse Agrario ed Industriale ed Ambientale - COL.MIA", -"CRA-OLI b Centro di Ricerca per l'Olivicoltura e l'Industria Olearia", -"CRA-PAV c Centro di Ricerca per la Patologia Vegetale", -"CRAF s University of Craiova, Phytopathology Department", -"CRAI s University of Craiova", -"CRBF c Collection de genomes d'organismes symbiotiques", -"CRBK s Cranbrook School", -"CRBY s Crosby Library", -"CRCA s Instituto dos Cereais", -"CRCM s Washington State University, Charles R. Conner Museum", -"CRCM:Bird s Washington State University, Charles R. Conner Museum, bird collection", -"CRCM:Mammal s Washington State University, Charles R. Conner Museum, Mammal Collection", -"CRD s Instituto Politecnico Nacional, Coleccion Cientifica de Fauna Silvestre (Mexico)", -"CRE s Costa Rica Expeditions", -"CRE s University of Southern California", -"CREG s Instituto Tecnologico Agropecuario de Jalisco", -"CRGF c Collection de Recursos Geneticos Fungicos, Instituto de Ecologia y Systematica", -"CRH s Centre de Recherche en Hydrobiologie", -"CRI s Universidade do Extremo Sul Catarinense, Bairro Universitario", -"CRIFC s Central Research Institute for Field Crops in Turkey", -"CRK s University College, Plant Science Department", -"CRL c Centro de Referencia Para Lactobacilos", -"CRLA s Crater Lake National Park, Museum and Archives Collections", -"CRMC s College of the Redwoods, Mendocino Coast Campus, Biological Sciences Department", -"CRMM s Centre de Recherche sur les Mammiferes Marins", -"CRO s Wellington College", -"CRP s I.N.T.A., E.E.A. Bariloche", -"CRRHA s Centre Regional de Recherches en Hydrobiologie Appliquee", -"CS c CSIRO Collection of Living Micro-algae", -"CS s Musee des Dinosaures d'Esperaza (Aude)", -"CS s Colorado State University, Biology Department", -"CSAT s Colegio de Postgraduados, Campus Tabasco", -"CSAU s National Agrarian University, Southern Branch \"Crimean Agrotechnological University\", Department of Botany, Plant Physiology and Genetics", -"CSB s St. John's University/College of Saint Benedict, Biology Department", -"CSC s Colegio del Sagrado Corazon", -"CSC-CLCH c Centro Substrati Cellulari, Cell Lines Collection and Hybridomas", -"CSCA s California State Collection of Arthropods", -"CSCC c CSIRO Starter Culture Collection", -"CSCCE s Chadron State College, Entomology Collection", -"CSCCV s Chadron State College, Collection of Vertebrates", -"CSCN s Chadron State College", -"CSCS s Cebu State College of Science and Technology, Agricultural Biology Laboratory", -"CSCS s California State University, Turlock", -"CSDS s Desert Studies Center", -"CSFI s Central-South Forestry University", -"CSGP s Servicos Geologicos de Portugal", -"CSGT s Collegio San Giuseppe", -"CSH s Shanghai Chenshan Botanical Garden", -"CSIR c Council for Scientific and Industrial Research", -"CSIRO s Commonwealth Science & Industrial Research Organization", -"CSIRO:Ichthyology s Commonwealth Science & Industrial Research Organization, Australian National Fish Collection", -"CSLA s California State University, Department of Biological Sciences", -"CSLB s California State University at Long Beach", -"CSMA c Centro di Studio dei Microorganismi Autotrofi - CNR", -"CSPM s Colegio Lasalle Palma de Mallorca", -"CSPU s California State Polytechnic University, Biological Sciences Department", -"CSPUP s California State Polytechnic University, Pomona", -"CSR s Caucasus State Nature Biosphere Reserve", -"CSTIU s Faculty of Science, University of Tokyo", -"CSU s Colorado State University", -"CSU s University of Central Oklahoma, Biology Department", -"CSUC s California State University, Chico, Vertebrate Museum", -"CSUCI h California State University Channel Islands", -"CSUF s California State University, Fresno", -"CSUH h Chelyabinsk State University", -"CSULB s California State University, Long Beach", -"CSUN s California State University, Northridge", -"CSUNIV h Charleston Southern University", -"CSUR c Collection de Souches de l'Unite des Rickettsies", -"CSUSB h California State University, San Bernardino", -"CSUTC s Colorado State University, Mammalogy Teaching Collection", -"CSVFC s Caradoc and Severn Valley Field Club", -"CT s University of Cape Town, Botany Department", -"CTC h Chongqing Normal University", -"CTES s Instituto de Botanica del Nordeste", -"CTESN s Universidad Nacional del Nordeste", -"CTM c Centre de Biotechnologie de Sfax culture collection", -"CTN s Free Library and Museum", -"CTNRC s Thai National Reference Collections", -"CTS s Chongqing Teachers College", -"CTY s Canterbury Literary and Philosophical Institution", -"CU sb Cornell University", -"CUAC s Clemson University", -"CUBK s Department of Biology, Chonbuk National University", -"CUC c Cepario de la Universidad de Concepcion de Chile", -"CUE s Cairo University", -"CUETM c Collection Unite Ecotoxicologie Microbienne, INSERM", -"CUFH s Cumhuriyet University, Biology Department", -"CUG s Collection Universite Poitiers", -"CUH s Calcutta University, Botany Department", -"CUHK sc Biology Department, Chinese University of Hong Kong", -"CUI s Central College, Iowa", -"CUIC s Cornell University, Invertebrate Collections", -"CUMV s Cornell University Museum of Vertebrates", -"CUMV:Amph s Cornell University Museum of Vertebrates, Amphibian Collection", -"CUMV:Bird s Cornell University Museum of Vertebrates, Bird Collection", -"CUMV:Fish s Cornell University Museum of Vertebrates, Fish Collection", -"CUMV:Mamm s Cornell University Museum of Vertebrates, Mammal Collection", -"CUMV:Rept s Cornell University Museum of Vertebrates, Reptile Collection", -"CUMZ s Carleton University, Museum of Zoology", -"CUMZ s Cameroon University, Museum of Zoology", -"CUMZ s Chulalongkorn University Museum of Natural History", -"CUMZ:R s Chulalongkorn University Museum of Natural History, Reptile Collection", -"CUMZ s Cambridge University, Museum of Zoology", -"CUNRC s Universidad Nacional de Rio Cuarto, Coleccion de Mamiferos (Argentina)", -"CUP s Cornell University, Plant Pathology Herbarium", -"CUP s Catholic University of Peking", -"CUP s Charles University", -"CURLA h Centro Universitario Regional del Litoral Atlantico", -"CUS s Cusino Wildlife Research Station, Natural Resources Department", -"CUSC s Clemson University, Vertebrate Collections", -"CUVC s Universidad del Valle, Departamento de Biologia", -"CUW s Clark University, Biology Department", -"CUWM s Clark University", -"CUZ s Universidad Nacional San Antonio Abad del Cusco", -"CV s Municipal Museum of Chungking", -"CVCC c Center for Veterinary Culture Collection", -"CVCC c China Veterinary Culture Collection", -"CVCM c Centro Venezolano de Colecciones de Microorganismos", -"CVCW s Clinch Valley College, University of Virginia, Biology Department", -"CVM s City Museum, Natural History Department", -"CVRD s Reserva Natural da Vale do Rio Doce", -"CVUL s Universite Laval, Collection de Vertebres", -"CVULA s Coleccion Vertebrados, Facultad de Ciencias, La Hechicera, Universidad de los Andes", -"CWB s Kharkov State University", -"CWC s Central Wyoming College", -"CWDR s Cawdor Castle", -"CWU s V. N. Karasin National University", -"CY c Centre des Yersinia", -"CYN s Chipstead Valley Primary School", -"CYP s Ministry of Agriculture, Natural Resources and Environment, Forestry Department", -"CZAA s Catedra de Zoologia Agricola", -"CZACC s Coleccion Zoologia, Academia de Ciencias de Cuba", -"CZH h Hanshan Normal University", -"CZIP s Universidad de Magallanes, Instituto de la Patagonia (Chile)", -"CZL s Centro de Zoologia", -"CZRMA s Coleccion Zoologica Regional (Mammalia) del Instituto de Historia Natural y Ecologia", -"CZUAA s Universidad Autonoma de Aguascalientes (Mexico)", -"CZUG s Universidad de Guadalajara,Centro de Estudios en Zoologia, Entomologia", -"DABUH s University of Helsinki, Department of Applied Biology", -"DABZ s Department of Agriculture, Zimbabwe", -"DACB s Bangladesh National Herbarium", -"DACL s London Research Centre", -"DACT c Dept. Agricult. Chem. Technol.", -"DAFH s Department of Agriculture and Fisheries", -"DAG h Mountain Botanical Garden of the Dagestan Scientific Centre", -"DAKAR s Universite Cheikh Anta Diop, Departement de Biologie Vegetale", -"DAL s Dalhousie University, Biology Department", -"DANV s Umweltamt Darmstadt", -"DAO s Agriculture and Agri-Food Canada", -"DAOM sc National Mycological Herbarium, Agriculture and Agri-Food Canada", -"DAR c Plant Pathology Herbarium", -"DARI s Insect Collection, New South Wales Department of Agriculture", -"DAS s Agriculture and Agri-Food Canada", -"DASF s Department of Agriculture, Stock and Fisheries", -"DAU h University of Daugavpils", -"DAV s University of California, Plant Biology", -"DAVFP s Pacific Forestry Centre, Canadian Forest Service", -"DAVH s University of California, Environmental Horticulture Department", -"DAWES h The Dawes Arboretum", -"DBAI s Instituto de Ciencias Biologicas", -"DBAU s Universidade Santa Ursula", -"DBC s University College, Botany Department", -"DBCUCH s Universidad de Chile, Departamento de Biologia Celular y Genetica", -"DBFFEUCS s Departamento de Biologia de la Faculdad de Filosofia y Educacion de la Universidad de Chile", -"DBG s Denver Botanic Gardens", -"DBKKU1 c Department of Biology, Faculty of Science", -"DBKKU2 c Department of Biology, Faculty of Science", -"DBKKU3 c Department of Biology, Faculty of Science", -"DBM c Department of Biochemistry and Microbiology", -"DBMU c Boonchird lab, Department of Biotechnology, Mahidol University", -"DBMU2 c Panbangred lab, Department of Biotechnology, Mahidol University", -"DBN s National Botanic Gardens", -"DBS c Department of Biological Culture Collection", -"DBSE s Universidade Federale Sergipe", -"DBSNU s Department of Biology, Shaanxi Normal University", -"DBUA c Zoological Collection of the Biology Department, University of the Azores", -"DBUM-IPT c Department of Biochemistry, Faculty of Medicine, University of Malaya", -"DBUP c Algal Culture Collection", -"DBV c Division of Standardisation", -"DBVPG c Industrial Yeasts Collection", -"DBY s City of Derby Museum and Art Gallery", -"DCBU s Universidade Federal de Sao Carlos", -"DCCBC cb Dunaliella Culture Collection at Brooklyn College", -"DCDS s Dipartimento di Coltivazione e Difesa delle Specie Legnose dell'Universita, Sezione Entomologia Agraria", -"DCH s Davidson College, Biology Department", -"DCMB s Universidade do Amazonas", -"DCMD s Derby City Museum and Art Gallery", -"DCMP s Universidade Federal do Parana", -"DCN-UNRC s Departamento de Ciencias Naturales, Universidad Nacional de Rio Cuarto", -"DCPC s DominicusCirillus[deceased]", -"DCR s Doncaster Museum and Art Gallery", -"DD s Forest Research Institute, Indian Council of Forestry Research and Education, Systematic Botany Discipline", -"DDFF s Departamento de Defensa Fitossanitarista", -"DDMS h Fundacao Universidade Federal da Grande Dourados", -"DE s Debrecen University, Botany Department", -"DE-CSIRO c CSIRO Insect Pathogen Culture Collection", -"DEBU s Ontario Insect Collection, University of Guelph", -"DECA s Agnes Scott College, Biology Department", -"DECV s Douglas Ecological Consultants", -"DEE s McManus Galleries, Natural History Department", -"DEES s Universidade de Sao Paulo, Piracicaba", -"DEFS s Universidade de Sao Paulo", -"DEI s Senckenberg Deutsches Entomologisches Institut", -"DEIB s Deutsches Entomologisches Institut", -"DEK s Northern Illinois University, Biological Sciences Department", -"DELS s University of Delaware, Plant Science Department", -"DELTA s Delta Waterfowl and Wetlands Research Station", -"DEN s Denison University, Biology Department", -"DENA s Watt Institute", -"DENF s Grand Mesa-Uncompahgre-Gunnison Natonal Forests", -"DENH s University of New Hampshire", -"DERM s Intermountain Experiment Station", -"DES sb Desert Botanical Garden, Research Department", -"DEV h St. Joseph's College", -"DEVA s Death Valley National Park", -"DEWV s Davis and Elkins College, Biology and Environmental Science Department", -"DEZA s Dipartimento di Entomologia e Zoologia Agraria dell'Universita", -"DEZC s Dipartimento di Entomologia e Zoologia Applicate all'Ambiente \"Carlo Vidano\"", -"DFCZ s Forest Research Institute, Malawi", -"DFD s Dartford Borough Museum", -"DFEC s Desert Forestry Experimental Centre", -"DFEC s Department of Forestry and Environmental Science, State University of New York", -"DFF c Forest Pathology Culture Collection, Pacific Forest Research Centre", -"DFLC s Escola Superior de Agricultura", -"DFP c DFP Culture Collection", -"DFRU s University of New Brunswick", -"DFS s Dumfries and Galloway Natural History and Antiquarian Society", -"DFSM s Dumfries Museum", -"DFV s Division of Fisheres", -"DGBU s Department of Geology, Pusan National University", -"DGN s Darlington Museum", -"DGR b Division of Genomic Resources, University of New Mexico", -"DGR:Bird s Division of Genomic Resources, University of New Mexico, bird tissue collection", -"DGR:Ento s Division of Genomic Resources, University of New Mexico, entomology tissue collection", -"DGR:Fish s Division of Genomic Resources, University of New Mexico, fish tissue collection", -"DGR:Herp s Division of Genomic Resources, University of New Mexico, herpetology tissue collection", -"DGR:Mamm s Division of Genomic Resources, University of New Mexico, mammal tissue collection", -"DGS s The Manx Museum", -"DGU h Daegu University", -"DGUB c Department of Genetics, University of Bratislava", -"DH s Hobart and William Smith Colleges, Biology Department", -"DHISUB s Department of Hydrobiology and Ichthyology, Sofia Univiversity", -"DHL s University of Louisville, Biology Department", -"DHM s University of Durham, Botany Department", -"DHMB s Department of Harbours and Marine", -"DHNS s Dunbartonshire Natural History Society", -"DI s Universite de Bourgogne, Laboratoire de Phytobiologie Cellulaire", -"DIA s Museu do Dundo", -"DIAM h Universidade Federal dos Vales do Jequitinhonha e Mucuri", -"DIN s Museum National d'Histoire Naturelle", -"DINH s Delta Institute of Natural History", -"DINO s Dinosaur National Monument", -"DIS s Dinamation International Society", -"DISCA s Estacion Biologica de Rancho Grande, Ministerio del Ambiente y Recursos Naturales Renovables", -"DISKO s Danish Arctic Station", -"DiSTA s Phytoplasma Collection University of Bologn", -"DIX s Dixie College, Natural History Museum", -"DKG s Juniper Hall Field Centre", -"DLF s Stetson University, Biology Department", -"DLU h Da Lat University", -"DLY s Dudley and Midland Geological and Scientific Society and Field Club", -"DM s Dominion Museum", -"DM s The Dinosaur Museum", -"DMB s Durban Museum", -"DMBC s Dominick Moth and Butterfly Collection", -"DMBUK c Department of Microbiology, Univeristy of Kelaniya", -"DMCCUS c School of Biological Sciences Culture Collection", -"DMCMU2 c Department of Microbiology, Faculty of Medicine", -"DMCU c Microbiology Department, Faculty of Science", -"DMDC s Douala Museum", -"DMFS s Crichton Royal Institution Museum", -"DMHN h The University of Newcastle", -"DMIV c Department of Microbiology and Immunology", -"DMKKU1 c Department of Microbiology, Faculty of Medicine", -"DMKKU2 c Department of Microbiology, Faculty of Medical Science", -"DMKU c Department of Microbiology Kasetsart University", -"DMMU1 c Department of Microbiology, Faculty of Science", -"DMMU3 c Department of Microbiology, Faculty of Medicine Siriraj Hospital", -"DMMZ c Department of Medical Microbiology, University of Zurich", -"DMNH s Delaware Museum of Natural History", -"DMNH s Dayton Museum of Natural History, Biology Department", -"DMNS s Denver Museum of Nature and Science", -"DMNS:Bird s Denver Museum of Nature and Science, Ornithology Collections", -"DMNS:Mamm s Denver Museum of Nature and Science, Mammology Collection", -"DMPMC c Department of Microbiology, University of Western Australia", -"DMSA s Durban Museum", -"DMSC s Medicinal Plants Research Institute, Department of Medical Sciences", -"DMSP s Davis Mountains State Park", -"DMSRDE c DMSRDE Culture Collection", -"DMST c Culture Collection for Medical Microorganism, Department of Medical Sciences", -"DMTH s Britannia Royal Naval College", -"DMU s Mithila University, Botany Department", -"DMUIJ c Department of Microbiology, Jakarta Pusat", -"DMUP c Microbiology and Biophysics Charles University", -"DMUR c Department of Mycology", -"DMVB c Department of Microbiology, Veterinary Branch of National Strain Collection", -"DNA s Department of Natural Resources, Environment and the Arts", -"DNAP h Department of Primary Industry and Fisheries", -"DNATAX b DNA-TAX", -"DNHM s Dalian Museum of Natural History", -"DNHM s Dinosaur Natural History Museum", -"DNPM s Setor de Paleontologia do Departamento Nacional de Producao Mineral", -"DNS s Dundee Naturalists' Society", -"DNZ h Donetsk Botanical Garden of the National Academy of Sciences of Ukraine", -"DO s Societe d'Agriculture Sciences et Arts", -"DOA c Department Of Agriculture, Thailand", -"DOMO s Collegio Mellerio Rosmini", -"DOR s Dorset County Museum", -"DORC s Dorset County Museum", -"DORCM s Dorset Royal County Museum", -"DORT s Botanischer Garten Rombergpark, Stadt Dortmund", -"DOV s Delaware State University, Department of Agriculture and Natural Resources", -"DPBA s Departamento de Patologia Vegetal", -"DPC c Dairy Products Research Center Culture Collection Teagasc", -"DPIC s Belo Horizonte, Instituto de Ciencias Biologicas", -"DPIH s Department of Primary Industry (formerly DAHT)", -"DPIQM s Department of Primary Industries", -"DPIWE-FHU c Fish Disease Culture Collection", -"DPMWA s Dorthy Page Museum of Wasilla", -"DPNC s Denison Pequotsepos Nature Center", -"DPPC s Department of Agriculture, Taiwan", -"DPU s DePauw University, Botany and Bacteriology Department", -"DPUA c Departamento de Patologia/ICB", -"DPUP s Universidade Federal de Maringa", -"DQTC s Daqing Teachers College, Biology Department", -"DR s Technische Universitaet Dresden", -"DS s California Academy of Sciences, Botany Department", -"DSC s Delta State University, Biological Sciences Department", -"DSC c Dicty Stock Center", -"DSEC s Universidade Federal da Paraiba", -"DSIR s Department of Scientific and Industrial Research", -"DSM c Deutsche Sammlung von Mikroorganismen und Zellkulturen GmbH", -"DSM s University of Dar es Salaam, Botany Department", -"DSMZ c Deutsche Sammlung von Mikroorganismen und Zellkulture", -"DSP s Fitzsimon's Snake Park", -"DSSC b Drosophila Species Stock Center", -"DSU s Dnipropetrovsk National University, Department of Geobotany, Soil, and Ecology", -"DSY s Dewsbury Museum", -"DTE h Centro de Investigaciones Cientificas y Transferencia de Tecnologia a la Produccion (CICyTTP-CONICET)", -"DTIC s Departamento Parasitologia", -"DTN s Darlington and Teesdale Naturalists' Field Club", -"DU s Duke University Vertebrate Collection", -"DUB s National Botanic Gardens", -"DUBN s Dublin Naturalists' Field Club", -"DUE s University of Dundee", -"DUF s University of Dicle, Biological Department, Botany", -"DUGAND h Universidad del Atlantico", -"DUH s University of Delhi, Botany Department", -"DUIS s Universitaet Duisburg, Fachbereich 6, Botanik", -"DUKE s Duke University, Biology Department", -"DUL s University of Minnesota, Biology Department", -"DUM c Delhi University Mycological Herbarium", -"DUM s Zooligical Museum of Science and Art Faculty", -"DUOF h Duzce University", -"DUP h Dumlupinar University", -"DUR s Southeastern Oklahoma State University, Biological Sciences Department", -"DUSS s Universitaet Duesseldorf", -"DVBID c Division Vector-Borne Infectious Diseases", -"DVCC s Diablo Valley College", -"DVCM s Diablo Valley College Museum", -"DVM s Diablo Valley College, Biology Department", -"DVNM s Death Valley National Monument", -"DVR s Dover Corporation Museum", -"DVZUT s Department of Vertebrate Zoology", -"DWC s West Chester University, Biology Department", -"DWN s Darwen Library", -"DWP h Disney Wilderness Preserve/The Nature Conservancy", -"DWT c Wood Technology and Forest Research Division", -"DWU s Dakota Wesleyan University, Biology Department", -"DZCU s Calcutta University", -"DZIB s Universidade Estadual de Campinas", -"DZKU s Department of Biology, Shaanxi Normal University", -"DZMU s Department of Zoology, Monash University", -"DZS s Devizes Museum", -"DZSASP s Departamento de Zoologia, Secretaria da Agricultura", -"DZUC s Departamento de Zoologia da Universidade de Coimbra", -"DZUFRGS s Departamento de Zoologia da Universidade Federal do Rio Grande do Sul", -"DZUH s Departamento de Zoologia, Universidad de Havana", -"DZUL s Departamento de Zoologia, Universidad de La Laguna", -"DZUP s Universidade Federal do Parana, Museu de Entomologia Pe. Jesus Santiago Moure", -"DZVMLP s Departamento Cientifico de Zoologia de Vertebrados", -"DZVU s Universidad de Uruguay", -"E sb Royal Botanic Garden Edinburgh", -"EA s National Museums of Kenya", -"EAA s Estonian Agricultural University", -"EAC s Universidade Federal do Ceara, Departamento de Biologia", -"EAFM h Instituto Federal de Educacao, Ciencia e Tecnologia do Amazonas", -"EALA h Jardin Botanique d'Eala", -"EAN s Universidade Federal da Paraiba, Campus III - CCA, Departamento de Fitotecnia", -"EAP s Escuela Agricola Panamericana", -"EAPZ s Escuela Agricola Panamericana", -"EAR s Earlham College, Biology Department", -"EATRO c Uganda Trypanosomiasis Research Organization", -"EBA s Edinburgh Academy Field Centre", -"EBCC s Universidad Nacional Autonoma de Mexico, Estacion de Biologia \"Chamela\"", -"EBD s Estacion Biologica de Donana", -"EBDS s Estacion Biologica de Donana", -"EBE s Eastbourne Museum", -"EBF s Hubei Forestry Institute", -"EBH s Botanical Society of Edinburgh", -"EBL h Ecosystem Research and Development Bureau", -"EBMC s Universidad de Chile", -"EBMTV s Estacion de Biologia Marina del Instituto Tecnologico de Veracruz", -"EBNHS s Edinburgh Natural History Society", -"EBRG s Museo de la Estacion Biologia de Rancho Grande", -"EBUAP s Laboratorio de Herpetologia, Escuela de Biologia, Benemerita Universidad Autonoma de Puebla", -"EBUM s Universidad Michoacana de San Nicolas de Hidalgo", -"EBV s Laboratoire de Biologie Generale et de Botanique", -"ECACC c European Collection of Authenticated Cell Cultures", -"ECENT s East Central University", -"ECH s Elmira College", -"ECK h Buffalo State College", -"ECM s Hubei College of Traditional Chinese Medicine, Department of Chinese Materia Medica", -"ECNB s Escuela Nacional Ciencias", -"ECO-SC-M s Coleccion Mastozoologica de El Colegio de la Frontera Sur Unidad San Cristobal de las Casas, Chiapas", -"ECOCHM s Coleccion de Mamiferos del Museo de Zoologia-ECOSUR", -"ECOL s Collection du Laborataire d'Ecologie", -"ECOMAR s ECOMAR lab University of Reunion", -"ECON s Harvard University", -"ECOSCM s Coleccion Mastozoologica de El Colegio de la Frontera Sur, Unidad San Cristobal", -"ECOSUR s El Colegio de la Frontera Sur (Mexico)", -"ECSC s East Central University, Biology Department", -"ECSFI s East China Sea Fisheries Institute", -"ECU h Edith Cowan University", -"ECUAMZ h Universidad Estatal Amazonica", -"ECUH h East Carolina University", -"ECWP h Emirates Centre for Wildlife Propagation", -"EDC s Hubei Institute for Drug Control", -"EDH s Plinian Society", -"EDNC s Raleigh, North Carolina Department of Agriculture", -"EDTU h Trakya Universitesi", -"EEBP s Estacao Experimental de Biologia e Piscicultura de Pirassununga", -"EELM s Estacion Experimental Agricola de la Molina", -"EERU s Economic Entomology Research Unit", -"EFC s Escola de Florestas", -"EFCC s Epping Forest Conservation Centre", -"EFH s Forestry Commission", -"EFM s Epping Forest Museum, Corporation of London", -"EFWM s Department of Entomology", -"EGE s Ege University", -"EGE-MACC c Ege - Microalgae Culture Collection", -"EGH s University of Edinburgh", -"EGHB s University of Edinburgh", -"EGHF s University of Edinburgh, Forestry and Natural Resources Department", -"EGNP s Homestead, Everglades National Park", -"EGR s Eszterhazy Karoly College, Botany Department", -"EHCV s Emory and Henry College, Biology Department", -"EHH s Universite d'Etat d'Haiti", -"EI s Universidade Federal Rural do Rio de Janeiro", -"EIF s Universidad de Chile, Departamento de Silvicultura", -"EIHU s Entomological Institute, Hokkaido University", -"EINS s Ecuadorian Institute of Natural Sciences", -"EISC s Shaanxi Agricultural University, Entomological Institute", -"EIU s Eastern Illinois University, Biological Sciences Department", -"EJ s ?Ein Yabrud collection catalogue entries at The Hebrew University", -"EKU s Eastern Kentucky University", -"EKY s Eastern Kentucky University, Biological Sciences Department", -"ELCAK s Entomological Laboratory, College of Agriculture", -"ELH h Bureau of Land Management, Eagle Lake Field Office", -"ELM s East London Museum", -"ELMF s Augusta, Maine Forest Service", -"ELN s Elgin Museum", -"ELRG s Central Washington University, Biological Sciences Department", -"ELS s Aldenham School, Biology Department", -"ELVE s National Station for Plant Breeding", -"EM s Universidade Federal de Ouro Preto", -"EMA s Sichuan School of Chinese Materia Medica", -"EMAG s Ernst-Moritz Arndt Collection, Museum der Stadt Greifswald", -"EMAU s Ernst-Moritz-Arndt-Universitat Greifswald", -"EMBT s Department of Agriculture, Thailand", -"EMC s Eastern Michigan University, Biology Department", -"EMCC c Egypt Microbial Culture Collection", -"EMEC s Essig Museum of Entomology", -"EMET s Faculty of Agriculture, Entomology Museum", -"EMMA s Universidad Politecnica de Madrid, Unidad Docente Botanica, Departamento Silvopascicultura", -"EMNH h The Everhart Museum of Natural History, Science & Art", -"EMPARN c Empresa de Pesquisa Agropecuaria do Rio Grande do Norte", -"EMU s Eastern Michigan University, T. L. Hankinson Vertebrate Museum", -"EMUS s Utah State University", -"ENAG s Universidad Nacional Agraria, Departamento de Ciencias Basicas", -"ENCB-IPN c Coleccion de cultivos de la Escuela Nacional de Ciencias Biologicas", -"ENCB s Universidad de Autonoma de Baja California", -"ENCB s Instituto Politecnico Nacional", -"ENG s Royal Holloway College, University of London, Botany Department", -"ENIH s National Institute of Health", -"ENLC h Eastern Nevada Landscape Coalition", -"ENMU s Eastern New Mexico University, Natural History Museum", -"ENMUNHM s Eastern New Mexico University, Natural History Museum", -"ENP s Everglades National Park", -"ENS s Hubei College for Nationalities, Forestry Department", -"ENSJ s Escuela Normal Superior de Jalisco", -"ENT s Herbarium, Ministry of Natural Resources, Uganda", -"ENTOMOFOR s Collection of necrophagous Fauna of the Forensic Entomology Laboratory (Basque Country University)", -"EONJ s Upsala College, Biology Department", -"EOSC s Eastern Oregon University, Biology Department", -"EOSCVM s Eastern Oregon State College, Vertebrate Museum", -"EOSTS s Official Seed Testing Station, Agricultural Scientific Services, Department of Agriculture and Fisheries for Scotland", -"EPAL s Entomology Collection, Punjab Agricultural University", -"EPHR s Snow College, Biology Department", -"EPM s Epsom College Museum", -"EPN s Escuela Polytecnica Nacional", -"EPRL s University of Puerto Rico", -"EPU h Centre de Formation et de Recherche en Conservation Forestiere", -"ER s Universitaet Erlangen-Nuernberg, Geobotanik", -"ERA s Universidad Nacional de Entre Rios, Botanica Sistematica", -"ERAEP c Radiation Ecology Section, Biological Science Division, Office of Atomic Energy for Peace", -"ERCB s Yerevan State University, Botany Department", -"ERCH h Erciyes University", -"ERCULE c European Rumen Ciliate Culture Collection, Rowett Research Institute", -"ERE s Institute of Botany of the National Academy of Sciences of Armenia, Department of Plant Taxonomy and Geography", -"EREM s Institute of Botany of the National Academy of Sciences of Armenia, Mycology Department", -"ERH s Borough of Erith Museum", -"ERHM s Yerevan State University, Botany Department", -"ERSAF s Regional Agency for Agriculture and Forestry Services", -"ERZ s Fuerstin-Eugenie-Institut fuer Arzneipflanzenforschung", -"ESA s Universidade de Sao Paulo, Departamento de Botanica", -"ESAL s Universidade Federal de Lavras, Departamento de Biologia", -"ESAP c Instituto Zimotecnico-Z", -"ESEC s Entomological Society of Egypt", -"ESK s Seker Enstituesue", -"ESN s Ecole des Sciences de Niamey", -"ESNHS s Scottish Natural History Society", -"ESRC s Nova Scotia Department Natural Resources", -"ESRN s Escola Superior de Agricultura", -"ESS s Universitaet Essen", -"ESSE s Anadolu University", -"ESUG s University of Guam", -"ESUW s University of Wyoming Insect Museum and Gallery", -"ET s East Texas State University", -"ETE s El Colegio de la Frontera Sur, Coleccion de insectos Asociados a Plantas Cultivadas en la Frontera Sur", -"ETH c Kultursammlungen der Eidgenosische Technische Hochschule", -"ETH s Addis Ababa University, Biology Department", -"ETHZ s Eidgenoessische Technische Hochschule-Zentrum", -"ETL h Lake Forest College", -"ETN s Eton College Museum", -"ETNH h Jarvis Christian College", -"ETON h Eton College Museum", -"ETST s Texas A&M University, Biology Department", -"ETSU s East Tennessee State University, Biological Sciences Department", -"EU s Hubei University, Biology Department", -"EUB s Laboratory of Biology, Faculty of Science, Ehime University", -"EUMJ s Ehime University", -"EUQ s Department of Entomology, Queensland University", -"EUSL c Eastern University", -"EVA c European Virus Archive", -"EVCV s Erster Vorarlberger Coleopterische Verein", -"EVE h The Evergreen State College", -"EVMU s Everhart Museum, Natural History Department", -"EWH s Ewha Womans University", -"EWM h Elizabeth Winston Mize Herbarium", -"EWNHM s Ewha Womens University, Natural History Museum", -"EX c The Culture Collection of Extremophilic Fungi", -"EXN s Exton Hall", -"EXR s University of Exeter, Biological Sciences Department", -"F s Field Museum of Natural History, Botany Department", -"FAA h Universidad Nacional del Centro de la Provincia de Buenos Aires", -"FABR s Harmas de J. H. Fabre", -"FACHB c Freshwater Algae Culture Collection", -"FACS s Fujian Agricultural College", -"FAK s Department of Fisheries, Faculty of Agriculture", -"FAKOU s Faculty of Agriculture, Kochi Univerisity", -"FAKU s Kyoto University", -"FAN s Museum of Fanjingshan National Nature Reserve", -"FAR s University of Tarbiat-Moaallem, Biology Department", -"FARM s Longwood University, Department of Natural Sciences", -"FAU s Florida Atlantic University, Biological Sciences Department", -"FAUC s Universidad de Caldas, Departamento de Recursos Naturales", -"FAUN s Universidad de Narino", -"FAVU s Universidade Federal do Rio Grande do Sul, Faculdade Agronomia e Veterenaria", -"FB s Albert-Ludwigs Universitaet, Institut fuer Biologie II", -"FBA s Freshwater Biological Association", -"FBC s University of Sierra Leone, Fourah Bay College, Botany Department", -"FBCS s Universidad Autonoma de Baja California Sur, Museo de Historia Natural", -"FBGMU c Faculty of Biology Gadjah Mada University", -"FBMN s Museum fuer Naturkunde", -"FBQ s Fisheries Branch, Departement of Primary Industries", -"FBUB s Universitat Bielefeld", -"FBWA s Forstlichen Bundsversuchsanstalt", -"FC-DPV s Departmento de Paleontologia, Facultad de Ciencias", -"FCAB s Pontificia Universidade Catolica do Rio de Janeiro, Nucleo Interdisciplinar de Meio Ambiente", -"FCAP s Universidade Federal do Para", -"FCBP c First Fungal Culture Bank of Pakistan", -"FCDA s Fresno County Department of Agriculture", -"FCL c Fungal Culture Collection of Lublin", -"FCLR s Fundacion Cientifica Los Roques", -"FCM s Facultad de Ciencias Marinas", -"FCME s Universidad Nacional Autonoma de Mexico, Ciudad Universitaria, Departamento de Biologia", -"FCMM s Universidad Nacional Autonoma de Mexico, Facultad de Ciencias", -"FCNI s Forest Commission of N.S.W.", -"FCO s Universidad de Oviedo, Departamento de Biologia de Organismos y Sistemas", -"FCQ s Universidad Nacional de Asuncion, Departamento de Botanica, Direccion de Investigacion", -"FCRM s Fisheries College Reference Museum", -"FCT c FCT (Forestry Commission Tasmania)", -"FCTH s Forestry Commission of Tasmania", -"FCU s Fukien Christian University", -"FCUG c Fungal Cultures University of Goteborg", -"FDA c US Food and Drug Administration", -"FDC c Forsyth Dental Center", -"FDG s Guyana Forestry Commission", -"FDLW s University of Wisconsin Center, Biology Department", -"FDNR s Florida Department of Natural Resources", -"FDUC s Fairleigh Dickinson University [collection transferred to FSCA].", -"FDVC s De La Villa, Francisco", -"FEN h Lycee Felix Esclangon, Region PACA", -"FER s Universita de Ferrara, Dipartimento di Biologia - Sezione di Botanica", -"FERM c Patent and Bio-Resource Center, National Institute of Advanced Industrial Science and Technology (AIST)", -"FEZA s Universidad Nacional Autonoma de Mexico, Carrera de Biologia", -"FFB s Atlantic Forestry Centre, Canadian Forest Service", -"FFBNM h Florissant Fossil Beds National Monument", -"FFCL s Nossa Senhora do Patrocinia", -"FFR s Forfar Museum and Art Gallery, Meffan Institute", -"FFS s University of Stellenbosch", -"FFSUC s Faculty of Forestry Sciences", -"FG s Palaontologische Hauptsammlung der Bergakadmie", -"FGC s Grassland Research Institute, Chinese Academy of Agricultural Sciences", -"FGG s Faculty of Geology and Geophysis", -"FGGUB s Facultatea de Geologie si Geofisca", -"FGIC s Francois Genier", -"FGSC c Fungal Genetics Stock Center", -"FH s The Farlow Herbarium, Harvard University Herbaria", -"FH s Fort Hays", -"FHI s Forestry Research Institute of Nigeria", -"FHK s Divisional Forest Office", -"FHKS s Fort Hays State University", -"FHKSC s Fort Hays State University", -"FHL s Friday Harbor Laboratories, University of Washington", -"FHO s University of Oxford, Department of Plant Sciences", -"FHSM s Fort Hays Sternberg Museum", -"FI s Museo di Storia Naturale dell'Universita", -"FIAF s Universita degli Studi di Firenze, Dipartimento di Biologia Vegetale", -"FICB s Forest Research Centre", -"FIDS s Great Lakes Forest Research Laboratory, Forest Insect and Disease Survey", -"FIEC s Freshwater Institute", -"FIJI s University of the South Pacific", -"FIOC s Fundacao Instituto Oswaldo Cruz", -"FIP s Florida Institute of Paleontology", -"FIPF s Universita di Firenze", -"FIPIA s Institut Teknologi Bandung, Jurusan Biologi", -"FJFC s Fujian Forestry College", -"FJSI s Fujian Institute of Subtropical Botany", -"FKE s Folk Museum", -"FKEN s Folkestone Natural History Society", -"FLACC c Free-Living Amoebae Culture Collection", -"FLAS s Florida Museum of Natural History Herbarium", -"FLC s Fort Lewis College", -"FLD s Fort Lewis College, Biology Department", -"FLIN s Flinders University", -"FLK s Falkirk District Council Museum", -"FLOR s Universidade Federal de Santa Catarina, Departamento de Botanica", -"FLSP s Oscar Scherer State Park", -"FM s Fan Memorial Institute of Biology", -"FM s Department of Nature, Fujian Province Museum", -"FMB s Instituto Alexander von Humboldt", -"FMC s North Museum of Natural History and Science", -"FMH s Goddard College", -"FMJ c Faculty of Medicine, Juntendo University", -"FML s Fundacion Miguel Lillo", -"FMM s Muzeum Beskyd", -"FMNH s Field Museum of Natural History", -"FMNH:ARTH s Field Museum of Natural History, Arthropod Collection", -"FMNH:AVES s Field Museum of Natural History, Ornithology Collection", -"FMNH:HERP s Field Museum of Natural History, Herpetology Collection", -"FMNH:ICHTHY s Field Museum of Natural History, Ichthyology Collection", -"FMNH:INVRT s Field Museum of Natural History, Invertebrate Collection", -"FMNH:MAMM s Field Museum of Natural History, Mammal Collection", -"FMNH s Finnish Museum of Natural History", -"FMP s Fujian Academy of Traditional Chinese Medicine and Pharmacology", -"FMPC s Fairbanks Museum and Planetarium Collection", -"FMR c Facultad de Medicina", -"FMRI s Central Marine Fisheries Marine Research Institute", -"FMSS s Parque Zoological Nacional \"Finca Modelo\", Natural History Museum", -"FMUH h Francis Marion University", -"FNCC c Food and Nutrition Culture Collection", -"FNFR s Fishlake National Forest", -"FNLO s Fremont National Forest", -"FNM s Fries Natuurmuseum", -"FNML s Fries Natuurhistorisch Museum", -"FNP s Fundy National Park", -"FNPS s South Florida Collections Management Center, Everglades National Park", -"FNU s Fujian Normal University", -"FNU s Nagasaki University - Fisheries", -"FOF h National University of Laos", -"FOR s Forssa Museum of Natural History", -"FOSJ s Fisheries and Oceans Biological Station", -"FPDB s Universidad de Puerto Rico, Departamento de Ciencias Marinas", -"FPF s Rocky Mountain Research Station, USDA Forest Service", -"FPM s Fukui Prefectural Museum", -"FPRL s Building Research Establishment", -"FQH s Fort Qu'Appelle Herbarium", -"FR sb Forschungsinstitut Senckenberg", -"FRC s Institute of Forest Genetics and Tree Breeding", -"FRC c Fusarium Research Center", -"FRCL s Fisheries Research Centre", -"FRCS s Forest Research Centre", -"FRDC b Fruit Tree Research & Development Center of ThuaThien-Hue-Vietnam", -"FRI s Australian National Herbarium, Division of Forestry and Forest Products, CSIRO", -"FRI c Food Research Institute, Ministry of Agriculture, Forestry and Fisheries", -"FRI c Food Research Institute, Bratislava, Slovakia", -"FRIHP s Fisheries Research Institute of Hunan Province", -"FRIM s Forest Research Institute, Malaysia", -"FRLC s Forest Insect and Disease Survey Reference Collection", -"FRLH s Foundation for Revitalisation of Local Health Traditions, Research Department", -"FRLM s Faculty of Fisheries, Mie University", -"FRM s Friends University, Fellow-Reeve Museum of History and Science", -"FRNZ s Forest Research Institute, New Zealand", -"FRP s Palmengarten", -"FRR c Food Science Australia, Ryde", -"FRS s Falconer Museum", -"FRSKU s Kyoto University, Fisheries Research Station", -"FRU s National Academy of Science, Kyrgyzstan, Laboratory of Flora", -"FSAG s Faculte des Sciences Agronomiques de Gembloux", -"FSC c Fredericton Stock Culture Collection", -"FSC s California State University, Biology Department", -"FSCA s Florida State Collection of Arthropods, Florida Department of Agriculture and Consumer Services, Division of Plant Industry", -"FSCL s Florida Southern College, Biology Department", -"FSFRL s Far Seas Fisheries Research Laboratory", -"FSIU s Laboratory of Fisheries, Department of Oceanography", -"FSL s Collections de la Faculte des Sciences de Lyon", -"FSLF s Rocky Mountain Forest and Range Experiment Station", -"FSMC s Florida State Museum", -"FSP-USP s Faculdade de Saude Publica, Universidade de Sao Paulo", -"FSSR s Forest Service, USDA, Biological and Physical Resources Unit", -"FSU s Florida State University, Department of Biological Science", -"FSUM s Florida State University Museum", -"FSUMC s Frostburg State University, Mammal Collection", -"FSUNS c Faculty of Science, The University of Novi Sad", -"FT s Centro Studi Erbario Tropicale, Universita degli Studi di Firenze", -"FTCC c Food Technology Culture Collection", -"FTCMU c Department of Food Science and Technology, Faculty of Agriculture", -"FTG sb Fairchild Tropical Botanic Garden", -"FTI c Centro de Biotecnologia e Quimica-CEBIQ", -"FTOH h Forestry Training Institute, Olmotonyi", -"FTS s Fuzhou Teachers College, Biology Department", -"FTU s University of Central Florida, Biology Department", -"FU s Fudan University, Department of Biology", -"FU s Kyushu University, Department of Forest and Forest Products Sciences", -"FUB s Frei Universitat", -"FUE s Fukuoka University of Education", -"FUEL s Universidade Estadual de Londrina, Departamento de Biologia Animal e Vegetal", -"FUGR s Furman University, Biology Department", -"FUH s Firat Ueniversitesi", -"FUK h Fukui Botanical Garden", -"FULD s Verein fuer Naturkunde in Osthessen", -"FUMH s Ferdowsi University", -"FUMT s University of Tokyo", -"FURB h Universidade Regional de Blumenau", -"FUS s Fudan University, Biology Department", -"FUSC c Flinders University Smut Collection", -"FVCC s Flathead Valley Community College, Biology Department", -"FW s Texas Christian University, Biology Department", -"FWM s Fort Worth Museum of Science and History, Science Department", -"FWMSH s Fort Worth Museum of Science & History", -"FWRI s Florida Fish and Wildlife Research Institute", -"FWRI:Ichthyology s Florida Fish and Wildlife Research Institute, Ichthyology Collection", -"FWRI:Invertebrate s Florida Fish and Wildlife Research Institute, Invertebrate Collection", -"FWRI:SEAMAP c Florida Fish and Wildlife Research Institute, SEAMAP Ichthyoplankton Collection", -"FWVA s Fairmont State University, Biology Department", -"G s Conservatoire et Jardin botaniques de la Ville de Geneve", -"GA s University of Georgia, Plant Biology Department", -"GAB s National Museum, Monuments, and Art Gallery", -"GABAS s Centre d'Etude et de Conservation des Resources Vegetales", -"GAC s Guangxi Agricultural University, Forestry Department", -"GACP s Guizhou Agricultural College, Department of Plant Protection", -"GADI h Grootfontein Agricultural Development Institute", -"GAES s Georgia Agricultural Experiment Station", -"GAFS s Ganzhou Forestry School", -"GAI s Folk Museum", -"GALW s National University of Ireland, Galway, Botany Department", -"GAM s University of Georgia", -"GAM c Grupo Actinomicetales Merida Facultad de Medicina", -"GAP h Conservatoire Botanique National Alpin", -"GAS s Georgia Southern University, Department of Biology", -"GAT s Institute of Plant Genetics and Crop Plant Research", -"GAUA s Guangxi University", -"GAUBA s Australian National University, Division of Botany and Zoology", -"GAUF s Gansu Agricultural University", -"GAW s Eastern Botanical Society of Glasgow", -"GAZI s Gazi Ueniversitesi, Biyoloji Boeluemue", -"GB s Goeteborg University, Department of Plant and Environmental Sciences", -"GBFM s Universidad de Panama", -"GBG b Goteburg Botanical Garden", -"GBH h Herbarium of Geo. B. Hinton", -"GBNM s Glacier Bay National Park and Preserve Museum", -"GBY s Grimsby Arts and Natural History", -"GC s University of Ghana, Botany Department", -"GC s Goucher College", -"GCL c Central Laboratories", -"GCM s University College of Ghana", -"GCM s Government College, Department of Zoology", -"GCNP s Grand Canyon National Park", -"GCRL s Gulf Coast Research Laboratory", -"GCTP s Global Colosseum", -"GCU h Gachon University", -"GDA s Universidad de Granada", -"GDAC s Universidad de Granada, Departamento de Biologia Vegetal, Botanica", -"GDB h Herbarium de Gerard de Belair", -"GDGM s Guangdong Institute of Microbiology", -"GDMA s Medical University of Gdansk, Department of Biology and Pharmaceutical Botany", -"GDMCC c Guangdong Microbial Culture Collection Center", -"GDMM s Guangdong Institute of Chinese Materia Medica", -"GDMP s Guangdong Medical and Pharmaceutical College, Pharmacy Department", -"GDOR s Museo Civico di Storia Naturale Giacomo Doria", -"GE s Universita di Genova", -"GEIC s Guangdong Entomology Institute", -"GENT s Gent University, Biology Department", -"GEO s Emory University, Biology Department", -"GES s Gesneriad Research Foundation", -"GESU s State University of New York, Biology Department", -"GF s Guizhou Academy of Forestry", -"GFBI s Gymnasium der Franziskaner in Bozen [= Bolzano]", -"GFC s University of Great Falls, Biology Department", -"GFCC c Goa University Fungus Culture Collection and Research Unit", -"GFJP s Universidade do Estado de Minas Gerais", -"GFND s University of North Dakota, Biology Department", -"GFRC s Golestan Fisheries Research Centre", -"GFS s Guizhou Forestry School", -"GFT h Grumeti Fund Tanzania", -"GFW s Ernst-Moritz-Arndt-Universitaet, Botanisches Institut und Botanischer Garten", -"GGB s Gesneriad Gardens", -"GGM s Gosudarstvennyi Geologicheskii Musei - State Geological Museum", -"GGO s University of Strathclyde, Biology Department", -"GGW s Botanical Society of Glasgow", -"GH s Harvard University (The Gray Herbarium)", -"GHD s Shipley Art Gallery and Saltwell Tower Museum", -"GHG s Council for Geosciences", -"GHPG s Harold Porter National Botanical Garden", -"GHRI s Guy Harvey Research Institute", -"GHS s George Heriot's School, Biology Department", -"GI s Justus-Liebig-Universitat Giessen", -"GI-SPS s Geological Institute, Section of Palaeontology and Stratigraphy", -"GIFU s Herbarium of Gifu Pharmaceutical University", -"GINCO h Agriculture and Agri-Food Canada", -"GIUV s Geological Institute, University of Vienna", -"GJO s Steiermaerkisches Landesmuseum Joanneum, Botany Department", -"GKAR s Karoo National Botanical Garden", -"GL s University of Glasgow, Botany Department", -"GLA h George Landis Arboretum", -"GLAC s Glacier National Park, Glacier Collection", -"GLAHM s University of Glasgow, Hunterian Museum", -"GLAM s Art Gallery and Museum, Natural History Department", -"GLANH s Hunterian Museum", -"GLEN s Rappahannock Community College", -"GLFR s Great Lakes Forest Research Centre", -"GLG s Trinity College", -"GLLB s Laurel Bank School", -"GLM s Staatliches Museum fuer Naturkunde Goerlitz", -"GLMC s Guilin Medical College, Pharmacy Department", -"GLNP s Glacier National Park", -"GLO s Natural History Society of Glasglow", -"GLOW s Lowveld National Botanical Garden", -"GLR s Gloucester City Museum and Art Gallery", -"GLW s Andersonian Naturalists' Society", -"GM s Museum of Southeastern Moravia", -"GMACC c Laboratory of Molecular Genetics and Breeding of Edible Mushrooms", -"GMAU s Geological Museum of Amsterdam University", -"GMBL s College of Charleston", -"GMC s Guangxi Medical College", -"GMCE s Grosvenor Museum", -"GMDRC h Granite Mountains Desert Research Center", -"GMH s Sammlung Jacobi des Geiseltalmuseum Halle", -"GMHH s Geological Museum of Heilongjang Province", -"GML s Gorgas Memorial Laboratory", -"GML s Gaylord Memorial Laboratory Museum", -"GMNGZ s Glasgow Museum and Art Galleries", -"GMNH-PV s Paleo-Vertebrate Collection", -"GMNH s Museum d'Histoire Naturelle", -"GMNH s Georgia Museum of Natural History", -"GMNHJ h Gunma Museum of Natural History", -"GMNP s Gros Morne National Park", -"GMS s Hopkins Marine Station, Stanford University, Biological Sciences Department", -"GMU s N. P. Ogariov Mordovia State University, Department of Botany and Plant Physiology", -"GMUF s George Mason University, Department of Environmental Science and Policy 5F2", -"GMUG s Universitat Gottingen, Geologisches-Palaatologisches Museum", -"GMUM s Institut fuer Palaeontologie und Geologisches Museum der Universitat", -"GMUV s Geological Museum, University of Vienna", -"GNA s Gannan Arboretum of Jiangxi", -"GNDUH h Guru Nanak Dev University", -"GNE c Genentech", -"GNHM s Goulandris Natural History Museum", -"GNHNA s Gallery of Natural History and Native Art", -"GNHS s Guildford Natural History Society", -"GNM s Gothenburg Museum of Natural History (Goteborgs Naturhistoriska Museum)", -"GNU s Guangxi Normal University, Biology Department", -"GNUB s Guizhou Normal University, Biology Department", -"GNUC s Gyeongsang National University, Biology Department", -"GNUG s Guizhou Normal University, Geography Department", -"GO s Philosophical Society", -"GOD s Charterhouse School Museum", -"GOE s Institut und Museum fuer Geologie und Palaeontologie", -"GOE s Goole Scientific Society", -"GOET s Herbarium Universitat Gottingen", -"GOFS s Free State National Botanical Garden", -"GOPU h Gaziosmanpasa University", -"GOW s Clydebank High School", -"GP s Instituto de Geociencias, Universidade de Sao Paulo", -"GPA s Grande Prairie Regional College, Science Department", -"GPI s Geologisch-Palaeontologisches Institut", -"GPIH s Geologisch-Palaeontologiches Institut der Universitt Haemburg", -"GPIM s Lehreinheit Palaeontologisches, Institut fuer Geowissenschaften", -"GPIT s Institut und Museum fur Geologie und Palaeontologie, Universitat Tuebingen", -"GPM s Gifu prefectural Museum", -"GPM:B s Gifu prefectural Museum, Gifu prefectural Museum herbarium", -"GPM:Z s Gifu prefectural Museum, Gifu prefectural Museum Zoological collection", -"GPMK s Geologisch-Palaontologisches Institut und Museum", -"GPPT s Plant Protection Institute", -"GR s Universite J. Fourier - Grenoble I, Botanique", -"GRA s Albany Museum", -"GRCAMC s Grand Canyon National Park Museum Collection", -"GRCH s Colgate University, Biology Department", -"GREE s University of Northern Colorado, Department of Biological Sciences", -"GRI s Grinnell College, Biology Department", -"GRIF s Griffith University", -"GRJC s Grand Rapids Junior College", -"GRK s McLean Museum and Art Gallery", -"GRM s Museum d'Histoire Naturelle de Grenoble", -"GRMP s Central Geological Research Museum", -"GRO s State University of Groningen, Department of Plant Biology", -"GRPM s Public Museum of Grand Rapids", -"GRS s Gezira Research Station", -"GRSM s Great Smoky Mountains National Park", -"GRSU s Yanka Kupala Grodno State University, Department of Botany", -"GRSW s Desert Ecological Research Unit", -"GRTE h Grand Teton National Park", -"GSAT s The Geological Survey of Alabama", -"GSC s Geological Survey of Canada", -"GSDNM s Great Sand Dunes National Monument", -"GSFS s Gansu Forestry School", -"GSI s Geological Survey of India", -"GSM s Geologic Museum", -"GSMNP s Great Smoky Mountains National Park", -"GSN s Geological Survey of Nambia", -"GSO s Glasgow Society of Field Naturalists'", -"GSP s Geological Survey of Portugal", -"GSU s F. Scorina Gomel State University, Department of Botany and Plant Physiology", -"GSW s Georgia Southwestern State University, Biology Department", -"GTC c Gifu Type Culture Collection", -"GTC-GIFU c Gifu Type Culture Collection (GTC), Gifu University Culture Collection (GIFU)", -"GTM s Grantham Museum", -"GTNP s Grand Teton National Park", -"GTV s Gregorio T. Velasquez Phycological Herbarium", -"GU s Gotland University, Department of Biology", -"GU-IITG s for Gauhati University- Indian Institute of Technology Guwahati", -"GUA s DIVEA, DEP, FEEMA, FEEMA", -"GUAD s Institut National de la Recherche Agronomique and Parc National de Guadeloupe", -"GUADA s Universidad Autonoma de Guadalajara", -"GUAM s University of Guam, Biology Department", -"GUAT s Herbario Ulises Roja", -"GUAY s Universidad de Guayaquil", -"GUBH h Gauhati University", -"GUBIOTJT c Freshwater microalgae collection and culture laboratory", -"GUCM h Guangzhou University of Chinese Medicine", -"GUH s HNB Garhwal University, Botany Department", -"GUL h Suleyman Demirel University", -"GUM s Glasgow University Museum (Hunter Museum)", -"GUM s Mycological herbarium of University of Guilan", -"GUMACC c Gotheburg University Marine Algal Culture Collection", -"GUYN s Fundacion Jardin Botanico del Orinoco", -"GVF s George Vanderbilt Foundation", -"GVSC s Grand Valley State University, Biology Department", -"GW s West of Scotland College of Agriculture, Botany Department", -"GXCM s Guangxi Traditional Chinese Medicine University, Pharmacy Department", -"GXDC s Guangxi Institute for Drug Control", -"GXEM s Guangxi Institute of Ethnomedicine", -"GXF s Guangxi Institute of Forest Survey and Design", -"GXFI s Guangxi Forestry Institute", -"GXFS s Guangxi Forestry School", -"GXMG s Guangxi Medicinal Botanic Garden", -"GXMI s Guangxi Institute of Traditional Medical and Pharmaceutical Sciences", -"GXNM s Guangxi Natural History Museum, Herbarium", -"GXSP s Guangxi School of Pharmacy", -"GZAC s Guizhou Agricultural College, Forestry Department", -"GZM s Giessener Zoologisches Museum", -"GZTM s Guizhou Institute of Traditional Chinese Medicine", -"GZU s Karl-Franzens-Universitaet Graz", -"H s University of Helsinki", -"H-GSP s Howard University-Geological Survey of Pakistan Project", -"HA s Universidad del Azuay, Escuela de Biologia del Medio Ambiente", -"HABA s Academia de Ciencias Medicas, Fisicas y Naturales de La Habana", -"HABAYC s University of Mary Hardin-Baylor, Biology Department", -"HABE s Instituto de Biologia, Departamento de Ecologia", -"HAC s Instituto de Ecologia y Sistematica", -"HACC s Academia de Ciencias Camagueey", -"HACW s Department of Fishery, Huazhong Agriculture Collection", -"HAF s Hainan Forestry Institute", -"HAH h Hoyt Arboretum", -"HAI h University of Haifa", -"HAJB s Jardin Botanico Nacional", -"HAJU h Herbario Dr. Armando Jesus Urquiola", -"HAK s Hokkaido University, Faculty of Fisheries", -"HAKS s Hakgala Botanic Gardens", -"HAL s Martin-Luther-Universitaet", -"HALA s University of Alabama, Biological Sciences Department", -"HALE h Haleakala National Park", -"HALLE s Zoologisches Institut der Martin-Luther Universitaet", -"HALLST s Botanische Station", -"HALN h State Agency for Environmental Protection Saxony-Anhalt", -"HALX s Halifax Literary and Philosophical Society", -"HAM s Royal Botanical Gardens", -"HAMAB s Instituto de Pesquisas Cientificas e Tecnologicas do Estado do Amapa", -"HAMBI c HAMBI Culture Collection", -"HAMU s University of Newcastle upon Tyne", -"HAN s Universitaet Hannover", -"HANC h National Aquarium of Cuba", -"HANU s Harbin Normal University, Biology Department", -"HAO s Universidad Privada Antenor Orrego", -"HAQ s Institut der Technische Hochschule (RWTH), Institut fuer Biologie I", -"HAS s Fundacao Zoobotanica do Rio Grande do Sul", -"HAST s Research Center for Biodiversity, Academia Sinica", -"HASU s Universidade do Vale do Rio dos Sinos - CCS/ Centro 2", -"HAU h Alzahra University", -"HAUH s Haryana Agricultural University", -"HAVI s Eastern Mennonite University, Biology Department", -"HAVO s Hawaii Volcanoes National Park", -"HAW s University of Hawaii, Botany Department", -"HAX s Belle Vue Museum", -"HAY s California State University, Biological Sciences Department", -"HB s Herbarium Bradeanum", -"HBA h National Botanic Garden of Latvia", -"HBARC h Bhabha Atomic Research Centre", -"HBAU s Hebei Agricultural University", -"HBAUD s Hebei Agricultural University, Handan Branch, Agriculture Department", -"HBBS s Museo Civico di Scienze Naturali", -"HBC s Henry Brockhouse Collection", -"HBDC s Hebei Institute for Drug Control", -"HBFC s Hebei Forestry College, Basic Courses Department", -"HBFH s Harbor Branch Oceanographic Institution, Marine Botany Department", -"HBG s Institut fuer Allgemeine Botanik", -"HBG b Hiroshima Botanical Garden", -"HBI s Institute of Hydrobiology, Chinese Academy of Sciences, Phycology Department", -"HBIL s Institut d'Estudis Ilerdencs", -"HBNU s Hebei Normal University, Biology Department", -"HBOM s Harbor Branch Oceanographic Museum", -"HBR s Universidade Federal de Santa Catarina", -"HBRA h Universidade Federal do Para, Campus Braganca", -"HBUM s College of Life Sciences Hebei Univesity, Baoding", -"HC s Hangchow Christian College", -"HCAT s University of Tabriz, Landscape Department", -"HCB s Universidade de Santa Cruz do Sul, Departamento de Biologia", -"HCCA s Hastings College", -"HCCN h National Institute of Agricultural Science and Technology", -"HCCV s Hastings College, Collection of Vertebrates", -"HCDAL h Universidade Regional do Cariri", -"HCEN s Universidad Nacional del Centro del Peru", -"HCF h Universidade Tecnologica Federal do Parana", -"HCH s Lewis-Clark State College, Natural Sciences Department", -"HCHM s Hope College, Biology Department", -"HCIB s Centro de Investigaciones Biologicas del Noroeste, S. C.", -"HCIO s Indian Agricultural Research Institute", -"HCMS s Hampshire County Council Museums Service", -"HCMZ s Hope College", -"HCNHSC s Ohio Historical Society, Natural History Synoptic Collection", -"HCOA s College of the Atlantic, Herbarium", -"HCOM h Centre d'Oceanologie de Marseille - University of Aix-Marseille II", -"HCT s Taiwan Forestry Research Institute", -"HCTR s Hoogstraal Center for Tick Research", -"HDCF h Department of Forestry Science", -"HDD s Tolson Museum, Natural History Department", -"HDJF h Universidade Federal dos Vales do Jequitinhonha e Mucuri", -"HDOA s Hawaii Department of Agriculture", -"HDSM s University of Massachusetts Dartmouth", -"HDTC s Huddersfield Technical College", -"HEAC s Henan Agricultural University", -"HEB s Hebden Bridge Literary and Scientific Society", -"HEBI s Henan Academy of Sciences", -"HECM s Henan College of Traditional Chinese Medicine", -"HEFG s l'Ecole de Faune de Garoua", -"HEH s Escuela Nacional de Ciencias Forestales, Departamento de Investigacion Forestal Aplicada", -"HEID s Universitaet Heidelberg, Heidelberger Institut fuer Pflanzenwissenschaften", -"HEL s University of Helsinki, Section of Botany", -"HEM h Universidad de Ciencias y Artes de Chiapas", -"HEMS s Haslemere Educational Museum", -"HENA s Escuela Nacional de Agricultura", -"HEND s Henderson State University, Biology Department", -"HENNU s Henan Normal University", -"HENU s Henan Normal University, Biology Department", -"HEPH s Jardim Botanico de Brasilia", -"HER c Felix d'Herelle Reference Center for Bacterial Viruses", -"HER s Hermanus Botanical Society", -"HERBAM h Universidade do Estado de Mato Grosso", -"HERT h Fundacao Universidade Estadual do Ceara", -"HERZ s Herzen State Pedagogical University of Russia, Department of Botany", -"HERZU s Universidad del Zulia", -"HEUS h Universidad de Sucre", -"HF s Universidade Federal do Para", -"HFB s Hainan Forestry Bureau", -"HFBG s Forestry Botanical Garden of Heilongjiang", -"HFCC c Flagellate Culture Collection, University of Cologne", -"HFD s Hereford Museum", -"HFLA h Sapienza University of Rome - Scuola di Specializzazione in Beni Naturali e Territoriali", -"HFN h Herbarium Frisicum", -"HFP c Hokkaido Forest Products Research Institute", -"HFR s Finnish Forest Research Institute", -"HFRI s Hunan Forestry Research Institute", -"HFSL h Centro de Ensino, Faculdade Sao Lucas Ltda.", -"HFU s Herbarium of Fayoum University", -"HFV s Universidad Austral de Chile, Instituto de Produccion y Sanidad Vegetal", -"HFX s Bankfield Museum and Art Gallery", -"HGAS s Guizhou Academy of Sciences, Plant Taxonomy Group", -"HGCRL s Gulf Coast Research Laboratory", -"HGI s Universitat de Girona, Unitat de Biologia Vegetal", -"HGM s Hunan Geological Museum", -"HGOM h Universidad Autonoma del Estado de Hidalgo", -"HGS s Public Museum and Art Gallery, St. John's Place", -"HGTC s Huanggang Teachers College, Biology Department", -"HGU h Khakass State University", -"HH h Instituto de Investigaciones de la Amazonia Peruana", -"HHBG s Hangzhou Botanical Garden", -"HHC s University of Helsinki, Horticulture Department", -"HHH s Hartwick College", -"HHM s Collyer's School", -"HHU s Hallym University", -"HHUA s Universidad Nacional de Huanuco Hermilio Valdizan", -"HHUF s Hirosaki University, Laboratory of Plant Pathology", -"HIB s Wuhan Institute of Botany", -"HIBG h Hiroshima Botanical Garden", -"HIC s University of Kentucky, Department of Entomology, Hymenoptera Institute Collection", -"HIFP s French Institute", -"HILL s Sir Harold Hillier Gardens", -"HIMC s Inner Mongolia University", -"HIN s Hitchin Priory", -"HIP s Universidad de Magallanes", -"HIPC s Instituto Superior Pedagogico Jose Marti, Departamento de Biologia", -"HIRO s Hiroshima University, Biological Science Department", -"HIRU s Okayama University of Science", -"HISA h Universidade Estadual Paulista", -"HITBC s Xishuangbanna Tropical Botanical Garden, Chinese Academy of Sciences", -"HIUW s Hygiene-Institut der Universitaet", -"HIWNT s Hampshire and Isle of Wight Naturalists' Trust Ltd.", -"HJBC h Jardin Botanico Culiacan", -"HJBL s Escuela Nacional de Ciencias Forestales", -"HJBS s Fundacio Jardi Botanic de Soller", -"HK s Agriculture, Fisheries, and Conservation Department", -"HKAS s Cryptogamic Herbarium of Kunming Institute of Botany, Chinese Academy of Sciences", -"HKBU s Hong Kong Baptist University, Biology Department", -"HKFRS s Hong Kong Fisheries Research Station", -"HKGL s Naturwissenschaftliche Sammlungen des Kantons Glarus", -"HKI c Hans-Knoll Institute", -"HKM h University of Comoros", -"HKS h Research Center of Agricultural and Natural Resources Kurdistan Province", -"HKU s University of Hong Kong, Ecology and Biodiversity Department", -"HKUCC c The University of Hong Kong Culture Collection", -"HL s Houghton Lake Wildlife Research Station, Natural Resources Department", -"HLA s Harold L. Lyon Arboretum", -"HLCM s Heilongjiang College of Traditional Chinese Medicine, Department of Chinese Materia Medica", -"HLD s Hessisches Landesmuseum", -"HLDG h Las Cruces Biological Station, Organization for Tropical Studies", -"HLL s Queen's Gardens, College of Higher Education, Natural Science Department", -"HLMA s Town Docks Museum, Hull City Corporation", -"HLMD s Hessisches Landesmuseum Darmstadt", -"HLNM s Heilongjiang Provincial Museum", -"HLO s Vlastivedne Muzeum v Hlohovci", -"HLSD h Hillsdale College", -"HLU s University of Hull, Botany Department", -"HLUC s Universita degli Studi della Basilicata, Dipartimento di Biologia Difesa e Biotecnologie Agroforestali", -"HLUL s University of Hull", -"HLX s Ovenden Naturalists' Society", -"HM s Humbolt Museum", -"HM s Hastings Museum", -"HMAR h Universidade Federal do Ceara", -"HMAS sc Institute of Microbiology, Academia Sinica", -"HMC s Jardin Botanico de Las Tunas", -"HME s Haslemere Educational Museum", -"HMGBH h Giardini Botanici Hanbury / Hanbury Botanic Gardens", -"HMH s Hoebarth Museum Horn", -"HMIM h Jardi Botanic Marimurtra", -"HMJAU sc Herbarium of Mycology of Jilin Agricultural University", -"HMLN s District Museum", -"HMM s Horsham Museum", -"HMMNH h Macedonian Museum of Natural History", -"HMN s Humbolt Museum fur Naturkunde, East Berlin", -"HMNH s Hayashibara Museum of Natural History", -"HMNR h Mordovian State Nature Reserve", -"HMNS s Houston Museum of Natural Science", -"HMNT s Hancock Museum, Newcastle University", -"HMP s Hornonitrianske muzeum, Department of Natural History", -"HMS s Embrapa Gado de Corte", -"HMUG s Hunterian Museum", -"HN s National Center for Natural Sciences and Technology, Botany Department", -"HNBU s Institut de l'Environnement et de Recherche Agricola (INERA)", -"HNCMB c Hungarian National Collection of Medical Bacteria", -"HNG h Universite. Gamal Abdel Nasser de Conakry", -"HNH s Dartmouth College, Biological Sciences Department", -"HNHH s Heilongjiang Natural History Museum", -"HNHM s Hungarian Natural History Museum (Termeszettudomanyi Muzeum)", -"HNHM:Moll c Hungarian Natural History Museum (Termeszettudomanyi Muzeum), Mollusca Collection", -"HNHM s Hannam University, Department of Biology", -"HNHPS h Hunan Hupingshan National Nature Reserve", -"HNHR s University of California, Hastings Natural History Reservation", -"HNIP s Hanoi College of Pharmacy", -"HNL h Conseil National des Sciences", -"HNM h Ecole Normale Superieure de Nouakchott", -"HNMN s Universidad Centroamericana", -"HNN s Horniman Museum of Natural History", -"HNNU s Hunan Normal University, Botany Department", -"HNPGBI h Seed and Plant Improvement Institute", -"HNR s Heilongjiang Academy of Sciences", -"HNT s Huntington Botanical Gardens", -"HNTS s Vlastivedne muzeum", -"HNU s Hunan Normal University", -"HNU s Vietnam National University, Department of Botany", -"HNUB s Northeastern University, Biology Department", -"HNUL h Northwestern University Inc.", -"HNWP s Northwest Plateau Institute of Biology, Chinese Academy of Sciences", -"HNWU s Nebraska Wesleyan University, Biology Department", -"HO s Tasmanian Museum & Art Gallery", -"HOH s Universitaet Hohenheim (210)", -"HOLZ s Paleontological Collection", -"HOMP s Okresni muzeum Pribram Brezove Hory", -"HON s Sichuan Grassland Research Institute", -"HOU s University of Houston", -"HOXA h Estacion biologica del Jardin Botanico de Missouri", -"HPAN h University of the State of Mato Grosso, UNEMAT", -"HPBR h Universidade Regional Integrada do Alto Uruguai e das Missoes", -"HPC s Howard Payne University, Biology Department", -"HPD s Hampstead Scientific Society", -"HPDL s Hampstead Public Library", -"HPH s Monroe County Department of Parks", -"HPL h Jardim Botanico Plantarum", -"HPM s Houston Museum of Natural Science", -"HPNP h Pumat National Park", -"HPP s University of Helsinki, Plant Biology Department", -"HPPR s Instituto Superior Pedagogico de Pinar del Rio, Departamento de Biologia", -"HPSU s Portland State University, Biology Department", -"HPU s High Point University, Biology Department", -"HPU s Hawaii Pacific University", -"HPUJ s Pontificia Universidad Javeriana", -"HPVC s Universidad Pedagogico Felix Varela,, Departamento de Biologia", -"HR s Muzeum Vychodnich Cech", -"HRB s IBGE", -"HRCB s Universidade Estadual Paulista", -"HREC h Hopland Research & Extension Center", -"HRJ s Universidade do Estado do Rio de Janeiro, Departamento de Biologia Animal e Vegetal", -"HRP s Universidad Nacional de La Patagonia, Departamento Biologia General", -"HSB s Universidad Mayor Real y Pontificia de San Francisco Xavier de Chuquisaca", -"HSBU h Shahid Beheshti University", -"HSC s Humboldt State University, Biological Sciences Department", -"HSCC c Culture Collection of the Research and Development Department", -"HSI s University of Helsinki, Silviculture Department", -"HSIB s Shanxi Institute of Biology, Botany Department", -"HSIC s Ministry of Natural Resources, Solomon Islands", -"HSM s Christ's Hospital, Biology Department", -"HSMC h Whyte Thorne Botanic Garden", -"HSNU s East China Normal University, Biology Department", -"HSP h Instituto Cientifico Michael Owen Dillon", -"HSS s Development, Technological and Investigacion Service, Forest Production Department", -"HSTM h Universidade Federal do Oeste do Para", -"HSU s Humboldt State University", -"HSU s Hardin-Simmons University, Biology Department", -"HSUCV s Hardin-Simmons University, Collection of Vertebrates", -"HSUD h Station of Nature Research and Environmental Education", -"HSUE s Natural History Museum, Addis Ababa", -"HSUMZ s Henderson State University, Museum of Zoology", -"HSUVM s Humboldt State University Vertebrate Museum", -"HTC s Hangzhou Normal College, Biology Department", -"HTD s College Natural History Society", -"HTE s Queen Ethelburga's School", -"HTGN s Norris Museum and Library", -"HTIN s Universidad Nacional Agraria de la Selva", -"HTN s Hitchin Museum", -"HTO s Universidade Federal do Tocantins, Nucleo de Estudos Ambientais", -"HTTU s Tennessee Technological University, Biology Department", -"HTU s University of Taiz, Biology Department", -"HTW h Universidad Nacional de la Patagonia San Juan Bosco", -"HU s University of Zhejiang", -"HUA s Universidad de Antioquia, Centro de Investigaciones", -"HUAA s Universidad Autonoma de Aquascalientes, Departamento de Biologia", -"HUAL s Universidad de Almeria, Departamento de Biologia Vegetal y Ecologia", -"HUAP s Herbario, Universidad Autonoma de Puebla", -"HUAZ h Universidad de la Amazonia", -"HUB s Hacettepe University, Botany Department", -"HUBE s Golden West College, Biology/Life Sciences Department", -"HUBO s Universita degli Studi di Bologna", -"HUC s Universidad de Cordoba, Departamento de Biologia", -"HUCM s Hunan College of Traditional Chinese Medicine, Department of Chinese Materia Medica", -"HUCP s Pontifica Universidade Catolica do Parana, Departamento de Ciencias Biologicas", -"HUCS h University of Caxias do Sul", -"HUDC s Howard University, Biology Department", -"HUE s Hunan Education College, Biology Department", -"HUEF s Hacettepe Ueniversitesi", -"HUEFS s Universidade Estadual de Feira de Santana, Departamento de Ciencias Biologicas", -"HUEG h Universidade Estadual de Goias", -"HUEM s Universidade Estadual de Maringa, Departamento de Biologia", -"HUESB h Universidade Estadual do Sudoeste da Bahia-Campus de Jequie", -"HUESBVC h Universidade Estadual do Sudoeste da Bahia-Vitoria da Conquista", -"HUF s Hunan Forestry School", -"HUFABC h Universidade Federal do ABC", -"HUFSJ h Universidade Federal de Sao Joao del-Rei", -"HUFU s Universidade Federal de Uberlandia, Instituto de Biologia", -"HUIC s Hacettepe University Ichthyological Collection", -"HUIF s Hunan Forestry Institute", -"HUJ s Hebrew University of Jerusalem", -"HUJ:INV s Hebrew University of Jerusalem, Invertebrate collection", -"HUKUK c Culture Collection of Animal Cells", -"HUL s Fine Arts Museum", -"HULE s Universidad Nacional Autonoma de Nicaragua, Departamento de Biologia", -"HUM s Humbolt University Zoologischen Museum", -"HUMC h Universidade de Mogi das Cruzes", -"HUMO s Universidad Autonoma del Estado de Morelos, Centro de Educacion Ambiental e Investigacion Sierra de Huautla", -"HUMP s Muzeum v Humpolci", -"HUMZ s Hokkaido University, Laboratory of Marine Zoology", -"HUNEB h Universidade do Estado da Bahia", -"HUNT h Huntington University", -"HUP h Hazara University", -"HUPG s State University of Ponta Grossa, Departamento de Biologia", -"HUQ s Universidad del Quindio", -"HURB h Universidade Federal do Reconcavo da Bahia", -"HURG s Universidade do Rio Grande, Departamento de Ciencias Morfo-Biologicas", -"HUS h Siauliai University", -"HUSA s Universidad Nacional de San Agustin de Arequipa, Facultad de Ciencias Biologicas y Agropecuarias, Area de Biomedicas", -"HUSC h Universidade Santa Cecilia - UNISANTA", -"HUSEC c Konsiliarlabor fur Hamolytisch-Uramisches Syndrom", -"HUST s Hunan University of Science and Technology, School of Life Sciences", -"HUT c HUT Culture Collection", -"HUT s Herbarium Truxillense, Universidad Nacional de La Libertad-Trujillo", -"HUTB s Hainan University", -"HUTI h Universidad Tecnologica Indoamerica", -"HUTM s Hunan Academy of Traditional Chinese Medicine and Pharmacy", -"HUTO s Fundacao Universidade do Tocantins , UNITINS", -"HUTPL s Universidad Tecnica Particular De Loja", -"HUVA h Universidade Estadual Vale do Acarau", -"HVASF h Universidade Federal do Vale do Sao Francisco", -"HVR s Universidade de Tras-os-Montes e Alto Douro", -"HWA s Southwest Agricultural University, Department of Biological Basic Courses", -"HWB s Harrow School, Biology Department", -"HWBA s Benedictine College, Biology Department", -"HWD s Hollinwood Botanists' and Field Naturalists' Society", -"HWML s Howard W. Manter Laboratory of Parasitology", -"HXBH s Fundacao CETEC", -"HXC s Hendrix College, Biology Department", -"HY s Osmania University, Botany Department", -"HYD s Heywood and District Botanical Society", -"HYO s Museum of Nature and Human Activities", -"Hyogo s Museum of Nature and Human Activities", -"HZI c Helmholtz Zentrum fur Infektionsforschung (Helmholtz Centre for Infection Research)", -"HZM s Museum of Natural History (Hrvatski Zooloski Muzej)", -"HZMZ s Hrvatski Narodni Zooloski Muzej", -"HZTC s Hanzhong Teachers College, Biology Department", -"HZU s Zhejiang University", -"I s Universitatea Al. I. Cuza Iasi", -"IA s University of Iowa, Department of Biological Sciences", -"IAA s Instituto Antarctico Argentinao, Direccion Nacional del Antartico", -"IAAA s Instituto do Acucar e do Alcool", -"IABH s Al-Bayt University, Biology Department", -"IABHU scb Institute for Amphibian Biology, Graduate School of Science, Hiroshima University", -"IAC s Instituto Agronomico de Campinas", -"IACC s Instituto Agronomico de Campinas", -"IACM s Instituto Agronomico", -"IADIZA-CM s Instituto Argentino de Investigaciones de las Zonas Aridas", -"IAFB c Collection of Industrial Microorganisms", -"IAGB s Universitatea Al. I. Cuza Iasi", -"IAL s Herbario, Centro Nacional de Pesquisa de Mandioca e Fruticultura, EMBRAPA", -"IAL c Secao de Colecao de Culturas", -"IALCEL c Secao de Culturas Celulares", -"IALMIC c Micoteca do Insituto Adolfo Lutz", -"IAM c IAM Culture Collection, Center for Cellular and Molecular Research", -"IAN s Embrapa Amazonia Oriental", -"IAPG s Institute of Animal Physiology and Genetics, Academy of Sciences of the Czech Republic", -"IARI sb Indian Agricultural Research Institute", -"IASI s Universitatea Agronomica, Disciplina de Botanica", -"IAUGH h Islamic Azad University Garmsar", -"IAUH h Islamic Azad University", -"IAUM h Islamic Azad University of Mashhad", -"IAUNT h Islamica Azad University, North Tehran Branch", -"IAV sb Institut Agronomique et Veterinaire Hassan II, Departement d'Ecologie Vegetale", -"IAVH s Instituto de Ivestigacion de los Recursos Biologicos Alexander von Humboldt", -"IB s Universitaet Innsbruck", -"IBA s Instituto Asturiano de Taxonomia y Ecologia Vegetal", -"IBA c Collection of Microorganisms Producing Antibiotics", -"IBAR h Ibaraki University", -"IBAUNC s Universidad Nacional de Cuyo, Instituto de Biologia Animal", -"IBE s Institute for Botanical Exploration", -"IBE s Institut de Biologia Evolutiva, (CSIC-UPF)", -"IBEF s Museum of the Izumi Board of Education", -"IBF s Tiroler Landesmuseum Ferdinandeum", -"IBGE s Reserva Ecologica do IBGE", -"IBH s Universidad Nacional Autonoma de Mexico, Instituto de Biologia", -"IBI s Instituto Biologico, Laboratorio de Micologia", -"IBIR s Institutul Agronomic", -"IBIW s I. D. Papanin Institute for Biology of Inland Waters", -"IBK s Guangxi Institute of Botany", -"IBL s Independent Biological Laboratories", -"IBL c Botanical Institute, Lisbon Faculty of Sciences", -"IBL c Insect Biocontrol Laboratory (USDA-ARS, Beltsville)", -"IBLP s Instytut Badawczy Lesnictwa", -"IBMUNC s Universidad Nacional de Cuyo, Instituto de Biologia Animal", -"IBP s Instituto de Biologia do Parana", -"IBPPM c Institute of Biochemistry and Physiology of Plants and Microorganisms of the Russian Academy of Sciences", -"IBRC sc Iranian Biological Resource Center", -"IBRP s Instituto Biologico de Ribeirao Preto", -"IBRP s Institute for Breeding Research, Tokyo University of Agriculture", -"IBS s Irish Biogeographical Society", -"IBSBF c Biological Institute Culture Collection of Phytopathogenic Bacteria", -"IBSC s South China Botanical Garden", -"IBSD s Dinghushan Biosphere Reserve", -"IBSP s Instituto Biologico de Sao Paulo", -"IBT c IBT Culture Collection of Fungi, Mycology Group, Technical University of Denmark", -"IBTS s Institutul de Biologie, Tr. Savulescu", -"IBUG s Universidad de Guadalajara", -"IBUNAM s Instituto de Biologia, Universidad Nacional Autonoma de Mexico", -"IBUNAM:CFB b Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion de Fotocolectas Biologicas", -"IBUNAM:CNAC s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Acaros", -"IBUNAM:CNAN s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Aracnidos", -"IBUNAM:CNAR s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Anfibios y Reptiles", -"IBUNAM:CNAV s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Aves", -"IBUNAM:CNCR s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Crustaceos", -"IBUNAM:CNHE s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Helmintos", -"IBUNAM:CNIN s Coleccion Nacional de Insectos, Universidad Nacional Autonoma de Mexico", -"IBUNAM:CNIN s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Insectos", -"IBUNAM:CNMA s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Mamiferos", -"IBUNAM:CNMO s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Moluscos", -"IBUNAM:CNPE s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Peces", -"IBUNAM:MEXU s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Herbario Nacional", -"IBUP s Institute of Biology", -"IBUS s Universidade Federal do Rio de Janeiro", -"IBUT s Instituto Butanta", -"IBY s Botanical Institute of Guangxi", -"ICA s Instituto Colombiano Agropecuario, Tibaitata", -"ICARDA sb International Center for Agricultural Research in the Dry Areas", -"ICBB c ICBB Culture Collection for Microorganisms and Cell Culture", -"ICBU s Bishop's University, Natural History Museum", -"ICCF c Collection of Industrial Microorganisms", -"ICEB s Eurouniversity", -"ICEL s Icelandic Institute of Natural History", -"ICF s INIFAP", -"ICFC c IIB-INTECH Collection of Fungal Cultures", -"ICGC s Istituto Calasanzio", -"ICHUM s Invertebrate Collection of the Hokkaido University Museum", -"ICIS s Idaho Museum of Natural History", -"ICM s Instituto de Ciencias del Mar", -"ICMP c International Collection of Micro-organisms from Plants", -"ICN s Universidade Federal do Rio Grande do Sul, Departamento de Botanica", -"ICN s Instituto de Ciencias Naturales, Museo de Historia Natural", -"ICP s Islamia College, University of Peshawar, Botany Department", -"ICPB c International Collection of Phytopathogenic Bacteria", -"ICPPB s International Collection of Plant Pathogenic Bacteria", -"ICPR s Biological Control Research Institute", -"ICRC s Insect Control and Research", -"ICRG s Institute of Entomology", -"ICRI s Zhonghan (Sun Yat-Sen) University, Research Institute of Entomology", -"ICRISAT b International Crops Research for the Semi-Arid Tropics", -"ICS-CC c Infection Control Services , National Health Laboratory Service 3", -"ICST s Imperial College of Science, Technology & Medicine, Department of Biological Sciences", -"ICUI s University of Iowa", -"ICVI s The Volcani Center", -"ID s University of Idaho, Biological Sciences Department", -"IDAC cb The International Depositary Authority of Canada", -"IDEA s Instituto de Agronomia", -"IDF s University of Idaho", -"IDS s Idaho State University, Biological Sciences Department", -"IE sc Cepario de Hongos del Instituto de Ecologia", -"IEA s Instituto DI Entomologia Agraria", -"IEAB s Istituto di Entomologia Agraria dell'Universita", -"IEAM s Istituto di Entomologia dell'Universita degli Studi [= Istituto di Entomologia Agraria dell'Universita, Milan]", -"IEAP s Istituto di Entomologia Agraria dell'Universita", -"IEAPM c Instituto de Estudos do Mar \"Almirante Paulo Moreira\"", -"IEAS s Institute of Entomology", -"IEAU s Istituto di Entomologia Agraria dell'Universita", -"IEB s Instituto de Ecologia, A.C.", -"IEBC c International Entomopathogenic Bacillus Centre (WHO)", -"IEBR s Institute of Ecology and Biological Resources", -"IEC s Centre D'Etude sur les Ressources Vegetales", -"IECA s Czech Academy of Science, Institute of Entomology", -"IEEUACH s Universidad Austral de Chile, Instituto de Ecologia y Evolucion", -"IEGG s Universita di Bologna, Istituto di Entomologia \"Guido Grandi\"", -"IEGM c Regional Specialized Collection of Alkanotrophic Microorganisms", -"IEI s Institut d'Estudis Ilerdencs", -"IEM c Czech National Collection of Type Cultures", -"IEME s Institute for Evolution, Morphology, and Ecology of Animals", -"IEMM s Instituto de Ecologia", -"IENU s Istituto di Entomologia, Universita degli Studi", -"IEPA s Istituto di Entomologia Agraria dell'Universita", -"IER h Institut d'Economie Rurale", -"IEUC s Istituto di Entomologia Agraria dell'Universita Cattolica", -"IEUP s Istituto di Entomologia, Universita degli Studi", -"IEVB s Institut de Zoologie [Institut Ed. Van Beneden]", -"IFAM c Institut fur Allgemeine Mikrobiologie", -"IFAN s Institut Fondamental d'Afrique Noire", -"IFBM c Streptokokken Sammlung", -"IFE s Obafemi Awolowo University, Botany Department", -"IFFB s Institut fuer Forstenentomologie und Forstschutz", -"IFG s Institute of Forest Genetics", -"IFGD s Idaho Fish and Game", -"IFGH s Idaho Fish and Game Department", -"IFGP s Pacific Southwest Research Station, USDA Forest Service", -"IFI s Imperial Fisheries Institute", -"IFM c IFM Quality Services Pty Ltd", -"IFM c Research Center for Pathogenic Fungi and Microbial Toxicoses, Chiba University", -"IFO c Institute for Fermentation", -"IFP s Institute of Applied Ecology, Academia Sinica", -"IFRD h Research Institute of Resource Insects", -"IFRDCC c International Fungal Research and Development Culture Collection", -"IFREMER s Institut Francais pour l'Etude de la Mer", -"IFRI s Indian Forest Research Institute", -"IFRPD c Institute of Food Research and Product Development, Kasetsart University", -"IFSA s Instituto Florestal", -"IG s Institute of Geology", -"IGB sb Israel Plant Gene Bank", -"IGC c Portuguese Yeast Culture Collection", -"IGCAGS s Institute of geology, Chinese Academy of Geological Science", -"IGCU s Instituto de Geologia, Ciudad Universitaria", -"IGESALQ c Colecao Microorganismos", -"IGF s Instituto di Geologia e Paleontologia", -"IGGDC h Institute of Geology and Geophysics, Chinese Academy of Sciences", -"IGL s Institute fuer Geowissenschaften Leoben", -"IGM s Instituto de Geologia", -"IGM s Geological Institute, Mongolian Academy of Sciences", -"IGPH s Institut fuer Geologie und Palaeontologie der Universitat Hannover", -"IGUS s Universitat des Saarlandes", -"IGWH s Institut fuer Geowissenschaften aus dem Martin-Lurther- Universitat", -"IH s Instituto de Segunda Ensenanza de La Habana", -"IHASW s Institute of Hydrobiology, Academia Sinica", -"IHB s Institute of Hydrobiology, Chinese Academy of Sciences", -"IHCAS s Museum of Institute of Hydrobiology, Chainese Academy of Sciences", -"IHEM c Scientific Institute of Public Health, Mycology Section", -"IHUG s Institut fuer Hygiene der Iniversitaet", -"IIBM-UNAM c Industrial Culture Collection", -"IIBUV s Investigaciones Biologicas de la Universidad Veracruzana (Mexico)", -"IICT s Centro de Zoologia do I.I.C.T.", -"IID c Laboratory Culture Collection", -"IIES s Instituto Investigaciones Entomologicas Salta", -"IIPB s Instituto de Ciencias del Mar", -"IITA b International Institute of Tropical Agriculture", -"IJ s Institute of Jamaica", -"IJFM c Instituto Jaime Ferran de Microbiologia Consejo Superior de Investigaciones Cientificas", -"IJSM s Institute of Jamaica, Natural History Museum", -"IK s Zoological Institute, Ukrainian Academy of Sciences", -"ILCA s International Livestock Research Institute", -"ILF s Iflracombe Museum", -"ILH s Iowa Lakeside Laboratory", -"ILL sc University of Illinois, Plant Biology Department", -"ILLS s Illinois Natural History Survey", -"ILMA s Istituto Leonardo Murialdo", -"ILPLA s Museo de La Plata, Instituto de Limnologia", -"IM s Instituto de Segunda Ensenanza de Matanzas", -"IM s Indian Museum", -"IMAGE b The I.M.A.G.E Consortium", -"IMARPE s Instituto del Mar del Peru", -"IMAS c Institute for Marine and Antarctic Studies", -"IMAU c Inner Mongolia Agricultural University, Key Laboratory of Dairy Biotechnology and Engineering", -"IMC s Sichuan Academy of Traditional Chinese Medicine and Pharmacy", -"IMCC c Inha Microbe Culture Collection, Inha University", -"IMCN s Instituto Vallecaucano de Investigaciones Cientificas", -"IMD c Industrial Microbiology Dublin", -"IMD s Institute of Medicinal Plant Development, Chinese Academy of Medical Sciences", -"IMDC s Inner Mongolia Institute for Drug Control", -"IMDY s Chinese Academy of Medical Sciences, Yunnan Branch", -"IMET c National Kurturensammlung fuer Mikroorganismen", -"IMFA s Inner Mongolia Academy of Forestry", -"IMI sc CABI Bioscience Genetic Resource Collection", -"IML s Instituto Miguel Lillo", -"IMLA s Fundacion e Instituto Miguel Lillo", -"IMM s Chinese Academy of Medical Science", -"IMM s Inner Mongolian Museum", -"IMMH c Collection of Animal Viruses", -"IMMIB c Culture Collection of the Institute of Medical Microbiology and Immunology of the University of Bonn", -"IMPC s Sichuan Academy of Traditional Chinese Medicine and Pharmacy", -"IMRU c Waksman Institute of Microbiology", -"IMS s Institute of Marine Sciences", -"IMS s University of North Carolina at Chapel Hill", -"IMSNU c Institute of Microbiology, Seoul National University", -"IMSSM s Instituto Mexicano del Seguro Social", -"IMT c Micoteca do Instituto de Medicina Tropical de Sao Paulo", -"IMT s Imperial Museum", -"IMTU s Institute of Medicine, Community Medicine Department", -"IMUFRJ c Instituto de Microbiologia of Universidade Federal do Rio de Janeiro", -"IMVS c IMVS Culture Collection", -"IMYZA c Instituto de Microbiologia y Zoologia Agricola", -"INA s Instituto Nun'Alvres, Departamento de Biologia", -"INA c Culture Collection of the Institute of New Antibiotics", -"INALI s Instituto Limnologia", -"INB s Instituto Nacional de Biodiversidad, Departamento de Botanica", -"INBC s Instituto Nacional de Biodiversidad (INBio)", -"INBio s National Biodiversity Institute, Costa Rica", -"INBP s Inventorio Biologico Nacional [Museo Nacional de Historia Natural del Paraguay]", -"INC s Instituto Nacional de Cultura, Museo de Ciencias Naturales (Panama)", -"INCQS c Fundacao Oswaldo Cruz-FIOCRUZ", -"IND s Indiana University, Department of Biology", -"IND-AN s Amphibian Collection", -"IND-M s La Unidad de Investigacion \"Federico Medem\"-Inderena (Colombia)", -"INDRE c Pathogen Fungi and Actinomycetes Collection", -"INEGI s Instituto Nacional de Estadistica Geografia e Informatica, Departamento de Botanica", -"INEP h Institute of the Industrial Ecology Problems of the North of Kola Science Center of the Russian Academy of Sciences.", -"INER s Istituto Nazionale di Entomologia", -"INFYB s Instituto Nacional de Farmacologia y Bromatologia, Farmacobotanica", -"INGU h Ingush State University", -"INH s Institut National d'Horticulture, Departement de Sciences Biologiques", -"INHM s Iraq Natural History Museum", -"INHS s Illinois Natural History Survey", -"INIA s Instituto Nacional de Investigaciones Forestales y Agropecurias", -"INIA b El Instituto de Investigaciones Agropecuarias", -"INIA b Instituto Nacional de Investigacion y Tecnologia Agraria y Alimentaria", -"INIBP s Instituto Nacional de Investigaciones Biologico Pesqueras", -"INIDA s Instituto Nacional de Investigacao e Desenvolvimento Agrario - Cape Verde", -"INIDEP s Instituto Nacional de Investigacion y Desarrollo Pesquero", -"INIF c Coleccion de Microhongos", -"INIFAT c INIFAT Fungus Collection", -"INIP s Instituto Nacional de Investigacao das Pescas", -"INIR s Coleccion de Termitas Mexicanas", -"INLA s INIA Subestacion Experimental Control Biologico La Cruz", -"INM s Ibaraki Nature Museum", -"INMI c Institute of Microbiology, Russian Academy of Sciences", -"INPA s Instituto Nacional de Pesquisas da Amazonia", -"INPA:CR s Instituto Nacional de Pesquisas da Amazonia, Crustacea Collection", -"INPA:H s Instituto Nacional de Pesquisas da Amazonia, Collection of Amphibians and Reptiles", -"INPA:LMM c Instituto Nacional de Pesquisas da Amazonia, Laboratorio de Micologia Medica Divisao de Microbiologia e Nutricao", -"INPC s National Pusa Collections", -"INRA b Institut National de la Recherche Agronomique", -"INRA:CGAB cb Institut National de la Recherche Agronomique, Collection of Germplasms of Agaricus bisporus", -"Insitute of Biology and Soil Science, Russian Academy of Sciences s Insitute of Biology and Soil Science, Russian Academy of Sciences", -"INU h Inonu University", -"INV s Inverness Museum and Art Gallery", -"INVA s Invergordon Academy", -"INVAM c International Culture Collection of (Vesicular) Arbuscular Mycorrhizal Fungi", -"INVEMAR s Instituto de Investigaciones Marinas de Punta de Betin", -"IO s Instituto Oceanografico da Universidade de Sao Paulo", -"IO s Instituto de Oceanografia da Universidade de Lisboa", -"IOAN s Shirshov Institute of Oceanography", -"IOC c Colecao de Culturas de Fungos do Instituto Oswaldo Cruz", -"IOCAS s Institute of Oceanology, Chinese Academy of Scineces", -"IOEB c Bacterial Collection", -"IOH s Academia de Ciencias", -"IOM s Institute of Oceanology, Academy of Sciences", -"IOPM s Izu Oceanic Park Museum", -"IORD s Takai University, Institute of Oceanic Research and Development", -"IOS s Institute of Oceanographic Sciences", -"IOUSP c Marine Microalgae Culture Collection", -"IOWA s University of Iowa, Museum of Natural History", -"IPA s Empresa Pernambucana de Pesquisa Agropecuaria, IPA", -"IPA:germplasm bank b Empresa Pernambucana de Pesquisa Agropecuaria, IPA, ", -"IPAE s Institute of Plant and Animal Ecology Ural Branch of Russian Academy of Sciences", -"IPB s Instituto Paranaense de Botanica", -"IPB s Institut fuer Palaeontologie", -"IPBIR b Integrated Primate Biomaterials and Information Resource", -"IPCN s Instituto Patagonico de Ciencias Naturales", -"IPEE RAS s A.N. Severtzov Institute of Ecology and Evolution, Russian Academy of Sciences", -"IPEF s Institut fuer Pflanzenschutzforschung", -"IPFUB s Institute for Paleontology of the Freie Universitat", -"IPGR b Institute for Plant Genetic Resources", -"IPHG s Institut fur Palaeontologie und Historische Geologie", -"IPK sb Leibniz Institute of Plant Genetics and Crop Plant Research", -"IPKUP s Paleontologiscsky Institute", -"IPLA c Instituto de Productos Lacteos de Asturias", -"IPMB s Institut fur Pharmazie und Molekulare Biotechnologie", -"IPMC s Institut Paleontologic Dr. M. Crusfafont Sabadell", -"IPMGO s Institut fur Paleontologie und Museum, Gottingen Universitat", -"IPMY s Universidad Pedagogica Libertador, Nucleo Maracay, Departamento de Biologia", -"IPN s Instituto Politecnico Nacional", -"IPO s Plant Research International", -"IPPAS c Culture Collection of Microalgae IPPAS", -"IPRN s Instituto de Pesquisas de Recursos Naturais Renovaveis", -"IPS s Ipswich Museum", -"IPSLI s Ipswich Literary Institute", -"IPSM s Ipswich Museum", -"IPSN s Instituto de Paleontologia de Sabadella", -"IPT c Agrupamento de Biotecnologia, Culture Collection of Microorganisms", -"IPTB s Instituto de Pesquisas Tecnologicas", -"IPUW s Institut fuer Palaeontologie der Universitaet Wien", -"IPW s Instutut fuer Palaeontologie der Uinversitaet Wurzburg", -"IQW h Senckenberg Forschungsinstitut und Naturmuseen", -"IRAG s Institut National de la Recherche Agronomique de Antilles et Guyane", -"IRAI h Parque da Ciencia Newton Freire Maia", -"IRAN sc Iranian Research Institute of Plant Protection, Department of Botany", -"IRBR s Universidad de Oriente, Departamento de Biologia", -"IRCW s Madison, University of Wisconsin", -"IRD s Institut de Recherche pour le Developpement", -"IRDA s Agriculture Department", -"IREC s Institut de Recherches Entomologique de la Caribe", -"IRGC b International Rice Genebank Collection", -"IRK s Siberian Institute of Plant Physiology and Biochemistry", -"IRKU s Irkutsk State University, Department of Botany and Genetics", -"IRP s Isle Royale National Park", -"IRRI sb International Rice Research Institute", -"IRSAC s Institute de Recherche Scientific en Afrique Centrale", -"IRSC s Institut de Recherches Scientifiques au Congo", -"IRSM s Institut Recherche Scientifique de Madagascar", -"IRSN s Institut Royal des Sciences Naturelles de Belgique", -"IRSNB s Institut Royal des Sciences Naturelles de Belgique", -"IRVC s University of California, UCI Arboretum Mail", -"IS s University of Molise, Department of Science and Technology for Environment and Territory", -"ISAB s Istituto Sant'Antonio dei Padri Francescani", -"ISAR s Academy of Science", -"ISAS s Kunming Institute of Zoology", -"ISB s Institute of Spelology \"Emile Racovita\"", -"ISBB s Institutul de Stiinte Biologice", -"ISBC s Institute of Soil Biology, Academy of Science of the Czech Republic", -"ISBC:CMF cb Institute of Soil Biology, Academy of Science of the Czech Republic, Collection of Microscopic Fungi", -"ISC c International Salmonella Centre (W.H.O.)", -"ISC s Iowa State University, Botany Department", -"ISCM s Institut Scientifique Cheripen", -"ISE h Universidade Federal de Sergipe, Campus Professor Alberto Carvalho", -"ISEA s Institute of Systematics and Evolution of Animals", -"ISEAK s Instytut Systematyki i Ewolucji Zwierz", -"ISEM s Institut des Sciences de l'Evolution Montpellier ", -"ISER s Institutul Speologie Emil G. Racovita", -"ISH s Institut fuer Seefischerei", -"ISI s Geological Museum, Indian Statistical Institute", -"ISIS s Naturforschende Gesellschaft Isis", -"ISKW h Ishikawa Museum of Natural History", -"ISL s Quaid-I-Azam University, Biological Sciences Department", -"ISM s Illinois State Museum", -"ISMAR h Consiglio Nazionale delle Ricerche, Istituto di Scienze Marine", -"ISMC s Indiana Department of Natural Resources", -"ISNHC s State Historical Society of Iowa", -"ISNP s Istituto Sperimentale per la Nutrizione delle Piante", -"ISP c International Cooperative Project for Description and Deposition of Type Cultures", -"ISPaVe c Istituto Sperimentale per la Patologia Vegetale", -"ISRA s Royal Academy", -"ISRI c Indonesian Sugar Research Institute, Pusat Penelitian Perkebunan Gula Indonesia", -"ISS c Institute of Soil Science Collection of Bacteria", -"ISTC s University of Northern Iowa, Biology Department", -"ISTE s University of Istanbul, Department of Pharmaceutical Botany", -"ISTF s Istanbul University, Botany Department", -"ISTO s University of Istanbul, Orman Fakueltesi", -"ISTPM s Institut Scientifique et Technique des Peches Maritimes", -"ISU s Illinois State University, Biological Sciences Department", -"ISU s Indiana State University", -"ISUC s Normal, Illinois State University", -"ISUI s Iowa State University", -"ISUVC s Indiana State University", -"ISZA s Istituto Sperimentale per la Zoologia Agraria", -"ISZP s Institute of Systematic Zoology", -"ITAE s Istituto Tecnico Agrario Enologico", -"ITAL c Banco de Fermentos Lacticos", -"ITALSL c Secao de Leite e Derivados", -"ITALSM c Secao de Microbiologia", -"ITBCC c Institute of Technology Bandung Culture Collection", -"ITBZC s Institute of Tropical Biology, Zoology Collection", -"ITC b International Transit Centre", -"ITCC c Indian Type Culture Collection", -"ITCC s Istituto Tecnico Stattale \"Camillo Cavour\"", -"ITCO s Istituto Tecnico Commerciale \"Oronzio Gabriele Costa\"", -"ITCV s Instituto Tecnologico de Ciudad Victoria, Departamento de Micologia", -"ITD c Coleccion de Cepas Microbianas", -"ITDI c Industrial Technology Development Institute", -"ITEM c Institute of Toxins and Mycotoxins from Plant Parasites", -"ITG c ITG", -"ITH c W.H.O./F.A.O. Collaborating Centre for Reference and Research on Leptospirosis", -"ITHA s Instituut voor Tropische Hygiene", -"ITIC s Universidad de El Salvador, Escuela de Biologia", -"ITLJ s National Institute of Agro-environmental Sciences", -"ITMH h Muhimbili University of Health and Allied Sciences", -"ITMM s Instituto Tecnologico de Monterrey", -"IU s Indiana University", -"IUI s Inha University, Biology Department", -"IUIC s Indiana University", -"IUK s Universite de Kinshasa, Departement de Biologie", -"IUM s Iwate University, Biology Department", -"IUP s Indiana University of Pennsylvania, Biology Department", -"IUQ s Laboratorio de Ictiologia", -"IVAU s Instituut Voor Aardwetenschappen", -"IVB s Institute of Vertebrate Biology, Academy of Sciences of the Czech Republic", -"IVF s Chinese Academy of Agricultural Sciences", -"IVGU h Ivanovo State University", -"IVIC s Instituto Venezolano de Investigaciones Cientificas", -"IVPP s Institute of Vertebrate Paleontology and Paleoanthropology", -"IZ c Departamento de Tecnologia Rural", -"IZ s Instituto de Zoologia", -"IZ s Institute of Zoology", -"IZ s Aegean Agricultural Research Institute, Department of Plant Genetic Resources", -"IZA s Universita di l'Aguila, Instituto di Zoologia", -"IZAC s Universidad Nacional de La Rioja-Sede Chamical", -"IZAC s Academia de Ciencias de Cuba, Instituto de Zoologia", -"IZAS s Institut Zoologii Akademii Nauk Ukraini - Institute of Zoology of the Academy of Sciences of Ukraine", -"IZASK s Institue of Zoology of the Kazakh Academy of Sciences", -"IZBE s Institute of Zoology and Botany", -"IZBT s L'Institut de Zoologie et Botanique de Tartu", -"IZCAS s Institute of Zoology, Chinese Academy of Sciences", -"IZCR s Istituto di Zoologia", -"IZEF s Ege Ueniversitesi, Farmasoetik Botanik Kuersuesue", -"IZET-UCV s Instituto de Zoologia y Ecologia Tropical", -"IZGAS s Georgian Academy of Sciences, Insititute of Zoology", -"IZPAN s Zoological Institute, Polish Academy of Sciences", -"IZPC s Universidade do Porto", -"IZSI s Istituto di Zoologia", -"IZSSA c Collection of Experimental Zooprophylactic Institute of Sardinia (Istituto Zooprofilattico Sperimentale della Sardegna \"G.Pegreffi\", Sassari))", -"IZTA s Universidad Nacional Autonoma de Mexico, Iztacala, Jefatura de Biologia", -"IZUA s Universidad Austral de Chile, Instituto de Zoologia", -"IZUC s Universidad de Concepcion, Instituto de Zoologia", -"IZUCS s Universita DI Cagliari", -"IZUE s Universitat -Erlangen-Nurnberg", -"IZUG s Istituto di Zoologia dell'Universita", -"IZUI s Institut fuer Zoologie der Universitat Innsbruck", -"IZUM s Istituto di Zoologia dell'Universita", -"IZUP s Istituto di Zoologia dell'Universita", -"IZUW s Institut fuer Zoologie der Universitat Wien", -"IZW s Institut Zoologii", -"IZWU s Paleozology Department, Institute of Zoology, Worclaw University", -"J s University of the Witwatersrand, Botany Department", -"JA s Consejeria de Medio Ambiente (Junta de Andalucia), Direccion General de Gestion del Medio Natural", -"JAC s University of Jodhpur, Botany Department", -"JACA s Instituto Pirenaico de Ecologia, CSIC", -"JAEN s Universidad de Jaen, Botanica", -"JAS s Jiangxi Academy of Sciences", -"JATH s University of Szeged", -"JAUM s Jardin Botanico Joaquin Antonio Uribe", -"JAY s Fondation Cognacq-Jay", -"JBAG s Jardin Botanico Atlantico, Ayuntamiento de Gijon", -"JBB h Jardin Botanico Jose Celestino Mutis", -"JBC b Francisco Javier Clavijero Botanic Garden", -"JBCC h Alaska State Museum", -"JBG s Johannesburg Botanic Garden", -"JBGP s Jardin Botanico Guillermo Pineres", -"JBL s Jardin Botanico Lankester, Universidad de Costa Rica", -"JBN s Jardin Botanico Nacional", -"JBSD s Jardin Botanico Nacional Dr. Rafael M. Moscoso", -"JBVN s Jardin Botanique de la Ville de Nice, Service des Espaces Verts", -"JBVPF sb Jardin botanique de la Ville de Paris", -"JBWM s J.B. Wallis Museum of Entomology", -"JCB s St. Joseph's College", -"JCE s Jiangxi College of Education, Biology Department", -"JCM c Japan Collection of Microorganisms", -"JCRB c Japanese Collection of Research Bioresources Cell Bank", -"JCT c James Cook Townsville", -"JE s Herbarium Haussknecht, Jena", -"JEF s Indiana University Southeast, Biology Department", -"JEL c Joyce E. Longcore Chytrid Collection at the University of Maine", -"JEL s Latvian Agricultural Academy, Plant Protection Department", -"JEPS s University of California, Jepson Herbarium", -"JES h Universidad Autonoma Chapingo", -"JESW s John Evelyn Society's Museum", -"JEY s Boys' Grammar School, Victoria College", -"JF s Jonkershoek Forestry Research Centre, Environment Affairs Department", -"JFBM s James Ford Bell Museum of Natural History", -"JHH s New York State Herbarium", -"JHS h Regional Research Institute", -"JHWU s Wittenberg University, Biology Department", -"JIC b John Innes Centre", -"JII s John Innes Institute", -"JIU s Jishou University, Biology Department", -"JJF s Jiujiang Forestry Institute", -"JJT s Jiujiang Teachers College, Biology Department", -"JJU s Jeonju University", -"JLFC s Forestry College of Beihua University, Forestry Department", -"JLMP s Jilin Academy of Traditional Chinese Medicine and Materia Medica", -"JM s Jura Museum, Eichstatt", -"JME h Jura-Museum Eichstatt", -"JMM s Earlham College, Joseph Moore Museum", -"JMRC c Jena Microbial Resource Collection", -"JMRC:SF c Jena Microbial Resource Collection, Subcollection Fungi", -"JMSMC s Jiamusi Medical College, Department of Pharmacy", -"JMUH s James Madison University, Department of Biology", -"JN s Jinggang Mountain Nature Reserve", -"JNR s Jiulian Mountain Nature Reserve, Administration Department", -"JNU s Ji Nan University", -"JNU s Chonbuk National University, Faculty of Biological Sciences", -"JNUB h Jeju National University", -"JOE s University of Joensuu, Biology Department", -"JOI h Universidade da Regiao de Joinville", -"JOMU h John Muir National Historic Site", -"JONK s Jonkershoek Herbarium", -"JOTR h Joshua Tree National Park", -"JP s Phyletisches Museum Jena", -"JPB s Universidade Federal da Paraiba, Cidade Universitaria, Departamento de Sistematica e Ecologia", -"JPMP s Janus Pannonius Museum", -"JPU s Janus Pannonius University, Botany Department", -"JRAU s University of Johannesburg, Department of Botany and Plant Biotechnology", -"JROH h Jasper Ridge Biological Preserve, Stanford University", -"JRY s Jersey College for Girls", -"JSHC s Jay S. Haft Collection", -"JSMPE s Joint Soviet Mongolian Paleontolgical Expedition", -"JSPC s Shandong University, Biology Department", -"JSPC s J. Rusek Collection", -"JSU s Jacksonville State University, Biology Department", -"JSY s Museum and Art Gallery of La Societe Jersiaise", -"JTNM s Joshua Tree National Monument", -"JTPC s Colorado Entomological Museum (formerly John T. Polhemus collection)", -"JU s Jinan University", -"JUA s Universidad Nacional de Jujuy, Facultad de Ciencias Agrarias", -"JUG s Jiwaji University, Botany Department", -"JUJ s Hebei Agricultural University", -"JVC s Jardin Botanico Canario Viera y Clavijo", -"JVR s Universidad Nacional", -"JXAU s Jiangxi Agricultural University, Forestry Department", -"JXCM s Jiangxi College of Traditional Chinese Medicine, Pharmacy Department", -"JXF s Jiangxi Forestry Institute", -"JXM s Jiangxi Institute of Materia Medica", -"JXU s Jiangxi University, Biology Department", -"JYV s University of Jyvaeskylae, Natural History Department", -"K sb Royal Botanic Gardens, Kew", -"K(M) s Mycology Collection of Kew Royal Botanical Gardens", -"KA s Vytautas Magnus University", -"KABA s University of Kabul", -"KAC c Kalmar Algae Collection", -"KACC c Korean Agricultural Culture Collection", -"KAG s Kagoshima University Museum", -"KAGS s Kagoshima University, Biology Department", -"KAI s Henan University, Biology Department", -"KAMA s Yokohama University", -"KANA s Kanazawa University", -"KAND h Kandalaksha State Nature Reserve", -"KANU s University of Kansas", -"KAR s University of Tehran, Horticulture Department", -"KARI s Kenya Agricultural Research Institute", -"KARS s Kawanda Agricultural Research Station", -"KAS s Universitaet Gesamthochschule Kassel, Morphologie und Systematik der Pflanzen", -"KASH s University of Kashmir", -"KASSEL s Naturkundemuseum im Ottoneum", -"KATH s Department of Plant Resources", -"KATO s Karadeniz Technical University, Department of Forest Botany", -"KAUM s Kagoshima University Museum", -"KAUM:I s Kagoshima University Museum, Ichthyology Collection", -"KAW s Kawanda Research Station, Department of Agriculture", -"KAZ s Kazan State University", -"KB s National Biological Resources Center, Department of Biological Sciences", -"KBAI s Kuban Agricultural State University, Department of Biology and Ecology", -"KBG b Kyoto Botanical Garden", -"KBHG s H. M. Berbekov Kabardian-Balkarian State University, Department of Botany", -"KBRYO s Centre College of Kentucky", -"KBSMS s Kellogg Biological Station, Michigan State University", -"KBT s Stewarty Museum", -"KCCM c Korean Culture Center of Microorganisms, Department of Food Engineering", -"KCFS s King's College", -"KCK s Dick Institute", -"KCLB c Korean Cell Line Bank", -"KCOM c Korean Collection for Oral Microbiology", -"KCS s University of London, King's College, Botany Department", -"KCTC c Korean Collection for Type Cultures", -"KDL s Kendal Museum", -"KDR s Bewdley Museum", -"KE s Kent State University, Biological Sciences Department", -"KEF s Kunming Edible Fungi Institute", -"KEI s University of Transkei, Botany Department", -"KEIU s Korea University", -"KEM s University of Kemerovo, Department of Botany", -"KEMC c Korea Environmental Microorganism Center, Kyonggi University", -"KEMH c KEMH/PMH Culture collection", -"KEN s Longwood Gardens, Horticulture Department", -"KEND s Kendal Natural History Society", -"KEP s Forest Research Institute Malaysia", -"KESC s Keene State College, Department of Biology", -"KEVO s University of Turku", -"KF h Kerman University of Medical Sciences", -"KFBG h Kadoorie Farm and Botanic Garden", -"KFCC c Korean Federation of Culture Collection", -"KFI s Hongnung Arboretum, Silviculture Department", -"KFRI s Kerala Forest Research Institute", -"KFRS s Kanudi Fisheries Research Station", -"KFTA s Saint Petersburg State S. M. Kirov Forest Technology Academy, Botany and Dendrology Department", -"KFUH s King Faisal University, Chemistry and Botany Department", -"KG h International Phytochemistry Research and Production Institute", -"KGU s Geology and Mineralogy Museum", -"KGY s Cliffe Castle Art Gallery and Museum", -"KH s Korea National Arboretum", -"KHA s Institute for Water and Ecology Problems, Far East Branch, Russian Academy of Sciences, Laboratory of Plant Ecology", -"KHD s Denver Botanic Gardens", -"KHER s Kherson Pedagogical University, Botany Department", -"KHF s Forest Research and Education Institute, Soba", -"KHMM s Kultur Historisches Museum", -"KHMS s Muzeum `umavy", -"KHOR s Pamir Biological Institute", -"KHU s University of Khartoum, Botany Department", -"KHUG s Aussenstelle der Universitaet", -"KHUS s Kyung Hee University, Biology Department", -"KIEL s Christian-Albrechts-Universitaet Kiel", -"KIFB s Korean Institute of Freshwater Biology", -"KIOM h Korea Institute of Oriental Medicine", -"KIP h Institut National pour l'Etude et la Recherche Agronomique", -"KIRI s University of Rhode Island, Department of Biological Sciences", -"KIS h Universite de Kisangani", -"KISA h Institut Congolais pour la Conservation de la Nature", -"KIT c Laboratorium voor Tropische Hygiene", -"KIUJ s Kyusu University", -"KIZ s Kunming Institute of Zoology, Chinese Academy of Sciences", -"KKFC s Kasetsart University Kamphaengsaen campus Fungus Collection", -"KKM s Kirkleatham Museum", -"KKU s Herbarium, Department of Biology, Khon Kaen University", -"KKUA s Khon Kaen University", -"KKUK s Kon-Kuk University", -"KL s Landesmuseum fuer Kaernten", -"KLA s Herbarium, Department of Agriculture, Malaysia", -"KLE s University of Keele, Biological Sciences Department", -"KLGU s Kaliningrad State University, Department of Botany and Plant Ecology", -"KLH s K. E. Tsiolkovsky Kaluga State Pedagogical University, Department of Botany and Ecology", -"KLN s Lynn Museum and Art Gallery", -"KLU s University of Malaya", -"KM s Kelowna Museum", -"KM s Sprava Krkonoaskeho narodniho parku", -"KM s Muzeum Przyrodnicze Uniwersytetu Jagiellonskiego", -"KM s Kotel'nich Museum", -"KMG s McGregor Museum", -"KMK s Kraevedscheskii Musei Kishineva - Museum of Regional Study", -"KMK s Kaffarian Museum", -"KMKV s Karlovarske muzeum", -"KMM c Collection of Marine Microorganisms", -"KMMA s Royal Museum for Central Africa", -"KMMCC c Korea Marine Microalgae Culture Center", -"KMN s Adger Museum of Natural History and Botanical Garden, Botany Department", -"KMNH s Kitakyushu Museum and Institute of Natural History, Botany Department", -"KMU s Karl-Marx-Universitat Leipzeg", -"KMV s Kunming Municipal Museum", -"KMVC s Krajske Muzeum Vychodnich Cech", -"KNFY s Klamath National Forest, Resources Department", -"KNH h Kongju National University", -"KNHM s The Educational Science Museum [=Kuwait Natural History Museum?]", -"KNK s Northern Kentucky University, Department of Biological Sciences", -"KNL s Kinneil Museum", -"KNOX s Knox College, Department of Biology", -"KNP s South African National Parks, Scientific Services", -"KNU s Kyungpook National University, Biology Department", -"KNUC s Kangweon National University", -"KNUH s Kyung-Nam University, Biology Department", -"KNWR s Kenai National Wildlife Refuge", -"KNWR:Ento s Kenai National Wildlife Refuge, Entomology Collection", -"KNWR:Herb s Kenai National Wildlife Refuge, Herbarium", -"KNY s Literary and Scientific Institution of Kilkenny", -"KNYA s Selcuk Ueniversitesi, Biyoloji Boeluemue", -"KO s P. J. Safarik University", -"KOCH s Kochi University, Department of Natural Environmental Science", -"KOELN s Universitaet Koeln, Arbeitsgruppe Geobotanik und Phytotaxonomie", -"KONL s Bodensee-Naturmuseum", -"KOPRI c Korean Polar Research Institute", -"KOPRI:KCCPM c Korean Polar Research Institute, KOPRI Culture Collection of Polar Microorganisms", -"KOR s Institute of Dendrology", -"KOS c Collection of Salmonella Microorganisms", -"KPABG s Polar-Alpine Botanical Garden-Institute, Department of Flora and Vegetation", -"KPBG s Kings Park and Botanic Garden, Botanic Gardens and Parks Authority", -"KPE s Kyungpook Earth, Kyungpook National University", -"KPM s Kanagawa Prefectural Museum of Natural History", -"KPM-NI s Kanagawa Prefectural Museum of Natural History", -"KPMC s Kalamazoo, Kalamazoo Public Museum", -"KR s Staatliches Museum fuer Naturkunde Karlsruhe", -"KRA s Jagiellonian University", -"KRAM s Polish Academy of Sciences, Department of Plant Systematics", -"KRAS s Krasnoyarsk State Pedagogical University, Department of Botany", -"KRB h Kebun Raya Bogor", -"KRDY s Kirkcaldy Museum and Art Gallery", -"KRF s V. N. Sukachev Institute of Forest and Wood", -"KRG s Westfield Museum", -"KRIB s Korea Research Institute of Bioscience and Biotechnology, Plant Diversity Research Center", -"KRMS s Sternwarte Kremsmuenster, Stift", -"KRP sb Kebun Raya Purwodadi (Purwodadi Botanic Gardens, Indonesia)", -"KRSF s Koronivia Research Station", -"KRSU s Krasnoyarsk State University, Department of Biogeocoenology", -"KSAN s South African National Parks", -"KSBS s Lawrence, University of Kansas, State Biological Survey of Kansas", -"KSC s Kansas State University", -"KSEM s Kansas Snow Entomological Museum", -"KSHS s Kochi Senior High School", -"KSK s Fitz Part Museum and Art Gallery", -"KSO s Tweedside Physical and Antiquarian Society Museum", -"KSP s Pittsburg State University, Biology Department", -"KSPI h Kostanay State Pedagogical Institute", -"KSRV s Khosrov State Reserve", -"KSTC s Emporia State University", -"KSU s King Saud University, Botany and Microbiology Department", -"KSUC s Kansas State University", -"KSUP s King Saud University", -"KTC s Pedagogical University, Botany Department", -"KTG s Kettering and District Naturalists' Society and Field Club", -"KTU s University of Silesia, Department of Plant Systematics", -"KTUH s Kuwait University, Botany and Microbiology Department", -"KU s University of Kansas Natural History Museum", -"KU-MACC c Kobe University Macroalgal Culture Collection", -"KU:H s University of Kansas Natural History Museum, Herpetology Collection", -"KU:I s University of Kansas Natural History Museum, Ichthyology collection", -"KU:IP s University of Kansas Natural History Museum, Invertebrate Paleontology Collection", -"KU:IT sb University of Kansas Natural History Museum, Ichthyology tissue collection", -"KU:IZ s University of Kansas Natural History Museum, Invertebrate Zoology Collection", -"KU:M s University of Kansas Natural History Museum, Mammology Collection", -"KU:O s University of Kansas Natural History Museum, Ornithology Collection", -"KU:PB s University of Kansas Natural History Museum, Paleobotany Collection", -"KU:VP s University of Kansas Natural History Museum, Vertebrate Paleontology Collection", -"KU s Kwangsi University", -"KUBL s Yoshida College, Biological Laboratory", -"KUEC s Kyushu University Entomology Collection", -"KUEL s Kyushu University, Entomology Laboratory", -"KUFC c Kasetsart University Fungus Collection", -"KUFS h Kabul University", -"KUH s University of Karachi, Botany Department", -"KUHE s Kyoto University, Graduate School of Human and Environmental Studies", -"KUIC s Kagoshima University", -"KUKENS c Centre for Research and Application of Culture Collections of Microorganisms", -"KUKI s Kurukshetra University", -"KUM s Resource Management Support Center", -"KUMA s Kumamoto University, Biology Department", -"KUMF s Kasetsart University Museum of Fisheries", -"KUN s Kunming Institute of Botany, Chinese Academy of Sciences", -"KUNE s Kunming Institute of Ecology, Academia Sinica", -"KUO s Kuopio Natural History Museum", -"KURS s Kursk State University, Department of Botany", -"KUS s Korea University, Biology Department", -"KUU s University of Science and Technology", -"KUW h Kakatiya University", -"KUZ s Zoological Collection of the Kyoto University", -"KUZC s Kyushu University, Zoological Collection", -"KVCH s Kivach Nature Reserve", -"KW s National Academy of Sciences of Ukraine", -"KWHA s Ukrainian National Academy of Sciences", -"KWHU h O. V. Fomin Botanical Garden of National Taras Schevchenko University of Kiev", -"KWNU s Kangwon National University, Biology Department", -"KWP s Kenelm W. Philip Collection, University of Alaska Museum of the North", -"KWP:Ento s Kenelm W. Philip Collection, University of Alaska Museum of the North, Lepidoptera collection", -"KY s University of Kentucky", -"KYM s University of Helsinki, Kymenlaakso Society of Naturalists", -"KYO s Kyoto University, Botany Department", -"KYUM s Kyushu University Museum", -"L sb National Herbarium of the Netherlands (NHN)", -"LA s University of California", -"LABCC c Lactic acid bacteria culture collection", -"LAC s Xian Institute of Lacquer", -"LACM s Natural History Museum of Los Angeles County", -"LACM:Crustacea s Natural History Museum of Los Angeles County, Crustacea Department", -"LACM:Echinoderms s Natural History Museum of Los Angeles County, Echinoderms Department", -"LACM:Entomology s Natural History Museum of Los Angeles County, Entomology Department", -"LACM:Herpetology s Natural History Museum of Los Angeles County, Section of Herpetology", -"LACM:Ichthyology s Natural History Museum of Los Angeles County, Ichthyology Department", -"LACM:Malacology s Natural History Museum of Los Angeles County, Malacology Department", -"LACM:Mammalogy s Natural History Museum of Los Angeles County, Mammalogy Department", -"LACM:Ornithology s Natural History Museum of Los Angeles County, Ornithology Department", -"LAE s Papua New Guinea Forest Research Institute", -"LAF s University of Louisiana at Lafayette, Biology Department", -"LAGO s Pacific Northwest Forest and Range Experiment Station", -"LAGU s Asociacion Jardin Botanico La Laguna, Urbanizacion Plan de La Laguna", -"LAH s University of the Punjab, Botany Department", -"LAJC s Otero Junior College, Biology Department", -"LAM s Natural History Museum of Los Angeles County, Botanical Studies", -"LAME s Lake Mead National Recreation Area", -"LAMU s Lamar University, Biology Department", -"LAN s Lancing College, Biology Department", -"LANC s University of Lancaster, Department of Biological Sciences", -"LAPC s Pierce College, Life Sciences Department", -"LAPL s Lapland State Biosphere Reserve", -"LARRI s Living Aquatic Resources Research Institute", -"LASCA s The Los Angeles County Arboretum", -"LAT s Saint Vincent College, Biology Department", -"LATV s University of Latvia, Laboratory of Botany", -"LAU s Musee et Jardins Botaniques Cantonaux", -"LAUN s Launceston College", -"LAUS s Launceston Museum", -"LAV s Dauntsey's School", -"LAVO s Lassen Volcanic National Park", -"LBC s University of the Philippines at Los Banos", -"LBG c Institute for Agricultural Bacteriology and Fermentation Biology", -"LBG s Lushan Botanical Garden", -"LBIT s Laboratoire de Biologie des Insectes", -"LBL s M. Curie-Sklodowska University, Department of Biology and Earth Science", -"LBLC s M. Curie-Sklodowska University", -"LBM c Laboratorio de Biologia Molecula Depto de Biologia Celular", -"LBM s Lake Biwa Museum", -"LBN s Lembaga Biologi Nasional", -"LBRP s Laboratorio de Biodiversidade de Recursos Pesqueiros", -"LBUCH s Laboratorio de Biologia", -"LBV s CENAREST", -"LC h Lewis & Clark College", -"LCC c Labatt Culture Collection, Technology Development", -"LCC c University of Warmia and Mazury in Olsztyn", -"LCDI s Luther College, Biology Department", -"LCEU s Lane Community College", -"LCF s I.N.T.A.", -"LCFM s Musee d'Histoire Naturelle", -"LCG s Leamington College for Girls", -"LCH s Letchworth Museum and Art Gallery", -"LCM s Universidad de Chile, Laboratorio de Citogenetica de Mamiferos", -"LCMI s Loyola College", -"LCN s Lincoln City and County Museum", -"LCO s International Red Locust Control Organization for Central and Southern Africa", -"LCP c Fungal Strain Collection, Laboratory of Cryptogamy", -"LCR s Ratcliffe College", -"LCS s International Red Locust Control Service", -"LCU s Catholic University of America", -"LCVA s Lakeland College, Environmental Sciences Department", -"LD s Botanical Museum, Lunds University", -"LDL s Ludlow Museum", -"LDM s Latvian Natural Histotry Museum, department of Entomology", -"LDPC s L. Deharveng, Universite Paul Sabatier", -"LDS s University of Leeds", -"LDSN s Leeds Naturalists' Club", -"LDSP s Leeds Philosophical and Literary Society Museum", -"LE c Servico de Microbiologia e Imunologia", -"LE s V. L. Komarov Botanical Institute", -"LEA s University of Lethbridge, Biological Sciences Department", -"LEB s Universidad de Leon, Departamento de Biologia, Botanica", -"LEB s Entomological Society of Latvia", -"LEC s Universita degli Studi di Lecce, Dipartimento di Biologia", -"LECB s Saint Petersburg State University, Botany Department", -"LEDLIE h Patricia Ledlie Herbarium", -"LEF s Economic Forestry Institute of Liaoning Province", -"LEH h Lehigh University", -"LEI s Leicester Literary and Philosophical Society", -"LeishCryoBank c International Cryobank of Leishmania", -"LEIUG s Department of Geology Leicester University", -"LEMA s Universite du Maine", -"LEMQ s Lyman Entomological Museum, McGill University,", -"LEMT s Ege University, Lodos Entomological Museum", -"LENUD s Lenin University of Dagestan, Botany Department", -"LEP s All-Union Institute for Plant Protection", -"LES s Leeds City Museum, Natural History Department", -"LET s Letchworth Naturalist's Society", -"LEUN s Bischoefliches Gymnasium Josephinum", -"LEV s Ministry of Agriculture and Fisheries, Plant Protection Centre", -"LEYN s Leyton Reference Library", -"LFBKU s Laboratory of Fishery Biology", -"LFCC s Lord Fairfax Community College, Natural Resources Department", -"LFG s Centre de Recherche de la Nature, des Forets et du Bois", -"LFM s Merseyside County Museums (formerly Liverpool Free Museum)", -"LG s Universite de Liege, Departement de Botanique", -"LGBH s Loughborough Public Library", -"LGEMA s Laboratorio de Genetica e Evolucao Molecular de Aves, Universidade de Sao Paulo", -"LGHF s Universite de Liege", -"LGICT s Laboratoire de Geologie de l'Institut Catholique de Toulouse", -"LGM s Leningrad School of Mines", -"LGM-USP c Departamento de Microbiologia Lab. de Genetica de Microrganismos", -"LGO s Columbia University", -"LGPUT s Laboratory of Geology and Palaeontology", -"LGU s Leningrad State University", -"LHMS b Leslie Hill Molecular Systematics Laboratory", -"LHT s Lahti City Museum", -"LI s Oberoesterreichischen Landesmuseums, Botanische Abteilung", -"LI:EVAR s Oberoesterreichischen Landesmuseums, Botanische Abteilung, Evertebrata Varia (Invertebrates other than Insects)", -"LI:INS s Oberoesterreichischen Landesmuseums, Botanische Abteilung, Insect collection", -"LI:VERT s Oberoesterreichischen Landesmuseums, Botanische Abteilung, Vertebrate collection", -"LIA c Cryobank of Microorganisms", -"LIAIP s Laboratory of Ichthyology", -"LIB s University of Liberia", -"LICPP s The Crown Prince's Palace", -"LIG s Sociedade de Geografia de Lisboa", -"LIH-UNAM c Culture Collection of Histoplasma capsulatum Strains from the Fungal Immunology Laboratory of the Department of Microbiology and Parasitology, Faculty of Medicine, UNAM", -"LIHUBA s Universidad de Buenos Aires, Laboratorio de Investigaciones Herpetologicas", -"LIL s Fundacion Miguel Lillo", -"LILLE s Institut Catholique de Lille, Laboratoire de Biologie Vegetale", -"LIM s Severoceske muzeum", -"LIMFC s Limerick Field Club", -"LIMK s Limerick Museum", -"LIMO h Universite de Limoges", -"LIN-SB c Limnological Institute, Siberian Branch, Russian Academy of Sciences", -"LINC s Lincoln University, Plant Sciences Group", -"LINCO h Linfield College", -"LINF s Shanxi Normal University, Biology Department", -"LINHM s Long Island Natural History Museum", -"LINN s Linnean Society of London", -"LIP s Universite de Lille, Departement de Botanique", -"LIPIMC c Lembaga Ilmu Pengetahuan Indonesia, Indonesian Institute for Sciences", -"LIPP c Leptospirotheque", -"LIRP s Laboratorio de Ictiologia, Faculdade de Filosofia", -"LISC s Instituto de Investigacao Cientifica Tropical", -"LISE s Estacao Agronomica Nacional", -"LISFA s Instituto Nacional de Investigacao Agraria, Departamento Ecologia, Recursos Naturais e Ambiente", -"LISI s Instituto Superior de Agronomia", -"LISJC s Jardim-Museu Agricola Tropical", -"LISM s Missao de Estudos Agronomicos do Ultramar", -"LISU s Museu Nacional de Historia Natural", -"LISVA s Ministerio da Educacao", -"LIT s Okresni vlastivedne muzeum", -"LIUSP s Laboratorio de Ictiogenetica, Universidade de Sao Paulo", -"LIV s Liverpool Museum", -"LIVC s Liverpool Botanic Garden", -"LIVCM s Liverpool County Museum", -"LIVNFC s Liverpool Naturalists' Field Club", -"LIVU s Hartley Botanical Laboratories", -"LJC c Coleccion de fitopatogenos de cultivos horticolas", -"LJF h Slovenian Forestry Institute", -"LJM s Prirodoslovni Muzej Slovenije", -"LJS h Scientific Research Centre", -"LJU s University of Ljubljana, Botany Department", -"LKHD s Lakehead University, Biology Department", -"LL s University of Texas at Austin, Plant Resources Center", -"LLANOS h Universidad de los Llanos", -"LLC s Our Lady of the Lake University, Biology Department", -"LLN s Lincolnshire Naturalists' Union", -"LLO s Lloyd Library and Museum", -"LM s Seccao de Botanica e Ecologia", -"LMA s National Institute of Agronomic Research, Botany Department", -"LMAD s Lobbecke Museum und Aquazoo", -"LMC s Instituto de Investigacao Cientifica de Mozambique", -"LMCH c Laboratoire de Microbiologie", -"LMD c Laboratorium voor Microbiologie der Landbouwhogeschool", -"LMG c Belgian Coordinated Collections of Microorganisms/ LMG Bacteria Collection", -"LMJ s Landesmuseum Joanneum Graz", -"LMJ s Centro de Investigacao Cientifica Algodoeira, Botanical Department", -"LMKG s Landesmuseum fur Karnten", -"LMND s Landessammlungen fuer Naturkunde", -"LMNH s Museum d'Histoire naturelle", -"LMO h Landesmuseum Natur und Mensch", -"LMRZ s Livingstone Museum", -"LMS c Carolina Biological Supply Company", -"LMSZ s Latvian University, Museum of Systemic Zoology", -"LMU s Eduardo Mondlane University, Department of Biological Sciences", -"LMZG s Local Museum", -"LNAF s Liaoning Academy of Forestry", -"LNAU h Luhansk National Agrarian University", -"LNCM s Liaoning College of Traditional Chinese Medicine", -"LNCN h Lincoln Memorial University", -"LNHS s London Natural History Society", -"LNK s Landessammlungen fuer Naturkunde", -"LNKD s Landessammlung fuer Naturkunde", -"LNMD s Landessammlungen fuer Naturkunde", -"LNMO s Oldenburg, Landesmuseum Natur und Mensch", -"LNNU s Liaoning Normal University, Biology Department", -"LNPV c Laboratoire National de la Protection des Vegetaux", -"LO s Type Collection", -"LOB s California State University, Biological Sciences Department", -"LOC s Occidental College, Biology Department", -"LOCK c Centre of Industrial Microorganisms Collection", -"LOD s Lodz University, Department of Geobotany and Plant Ecology", -"LOJA s Universidad Nacional de Loja, Departamento de Botanica y Ecologia", -"LOMA s La Sierra University, Biology Department", -"LON s Lembaga Oseanologie Nasional", -"LOU s C.I.T.A.-Xunta de Galicia", -"LP s Museo de La Plata, Herbario", -"LP s Laboratory of Palaeontology", -"LPA s Jardin Botanico Canario Viera y Clavijo", -"LPAG s Universidad Nacional de La Plata, Area de Botanica", -"LPB s Herbario Nacional de Bolivia", -"LPC h Museo de La Plata", -"LPD s Laboratorio de Botanica de la Direccion de Agricultura", -"LPFU s Lehrstuhl fur Palaontologie", -"LPL s The University", -"LPN s Littlehampton Museum", -"LPS s Universidad Nacional de La Plata, Instituto de Botanica Carlos Spegazzini", -"LPSC c La Plata Spegazzini Collection", -"LPSP s Lumus Pond State Park, Whale Wallow Nature Center", -"LPUB s Laboratorul de Paleontologie", -"LPUP s Laboratoire de Parasitologie", -"LPVM s Laboratoire de Paleontologie des Vertebres et de Paleontologie", -"LPVPH s Laboratoire de Paleontologie des Vertebres et de Paleontologie Humaine", -"LR s Museum d'Histoire Naturelle", -"LRL s Historic Society of Lancashire and Cheshire", -"LRS s Agriculture Research Center, Land Resource Sciences Section", -"LRTE s La Retraite (Convent School)", -"LRU s University of Arkansas at Little Rock, Biology Department", -"LS s Colegio de La Salle", -"LS s Linnean Society of London", -"LSA s Lytham St. Annes Public Library", -"LSAM s Louisiana State Arthropod Museum", -"LSC s Lyndon State College, Natural Sciences Department", -"LSCR s Organization for Tropical Studies, La Selva Biological Station", -"LSDC s Liangshan Institute for Drug Control", -"LSHB c Biochemistry Department", -"LSHI s Universite Nationale du Zaire", -"LSN s Lord Wandsworth College Natural History Museum", -"LSP s Lake Superior Provincial Park", -"LSR s Leicestershire Museums Service", -"LSRFC s Leicestershire Flora Committee", -"LSSC s Lake Superior State College", -"LSTM c Department of Parasitology", -"LSU s Louisiana State University, Biological Sciences Department", -"LSUHC s La Sierra University, Herpetological Collection", -"LSUM s Louisiana State University, Biological Sciences Department", -"LSUMZ s Louisiana State University, Musuem of Zoology", -"LSUMZ:FrozenTissue s Louisiana State University, Musuem of Zoology, Frozen Tissue Collection", -"LSUMZ:Herpetology s Louisiana State University, Musuem of Zoology, Herpetology Collection", -"LSUMZ:Ichthyology s Louisiana State University, Musuem of Zoology, Ichthyology Collection", -"LSUMZ:Mammalogy s Louisiana State University, Musuem of Zoology, Mammal Collection", -"LSUMZ:Ornithology s Louisiana State University, Musuem of Zoology, Bird Collection", -"LSUS s Museum of Life Sciences, Louisiana State University", -"LT s Universite de Montreal", -"LTB s La Trobe University, Botany Department", -"LTCC-IOC c Leishmania Type Culture Collection", -"LTH s Museum of Louth Naturalists' Antiquity and Literary Society", -"LTHP s Louth Public Library", -"LTI c Cryobank of Microorganisms-Destructors", -"LTM s Tekovske muzeum", -"LTN s Luton Museum and Art Gallery", -"LTR s University of Leicester, Biology Department", -"LTU s Louisiana Tech University", -"LU s Lingnan University", -"LU s St. Petersburg University", -"LUA s Instituto de Investigacao Agronomica", -"LUAI s ex-Centro Nacional de Investigacao Cientifica (CNIC)", -"LUB s Naturhistorisches Museum zu Luebeck", -"LUBA s Instituto Superior de Ciencias da Educacao", -"LUBEE b Lubee Bat Conservancy", -"LUCAS s Francesc de Lucas i Alcover", -"LUCCA s Comune di Lucca", -"LUCH s Musee du Pays de Luchon", -"LUD s Ludlow Natural History Society", -"LUG s Museo cantonale di storia naturale", -"LUGO s Universidad de Satniago de Compostela, Departamento de Produccion Vegetal", -"LUH s University of Lagos, Biological Sciences Department, Botany Unit", -"LUH c Leiden University Medical Center", -"LUKI h Institut National pour l'Etude et la Recherche Agronomiques", -"LUNZ s Lincoln University Entomology Research Museum", -"LUQ s Laval University", -"LUS s Lushan Botanical Garden", -"LUSC h Universidade do Estado de Santa Catarina", -"LUW s Landbouwuniversiteit Wageningen, Department of Entomology", -"LUX s Musee national d'histoire naturelle", -"LV s Catholic University of Leuven, Laboratory of Plant Systematics", -"LVNP s Lassen Volcanic National Park", -"LVP-GSC s Laboratory of Vertebrate Paleontology", -"LW s Ivan Franko National University of Lviv, Botany Department", -"LWA s Agricultural Experiment Station", -"LWD s Museum Dzieduszyckich", -"LWG s National Botanical Research Institute", -"LWI h Centre de Recherche en Sciences Naturelles (CRSN/Lwiro)", -"LWKS s Institute of Ecology of the Carpathians", -"LWL s LWL-Museum fuer Naturkunde", -"LWL:DNA b LWL-Museum fuer Naturkunde, LWL-DNA- und Gewebearchiv", -"LWS s Museum of Natural History, Lviv", -"LWSM s Lewes Museum, Ann of Cleves House", -"LWU s University of Lucknow, Botany Department", -"LY c Laboratoire de Mycologie associe au CNRS", -"LYAC s Laiyang Agricultural College, Department of Basic Courses", -"LYCC c Lallemand Yeast Culture Collection", -"LycoCC c The Lycoming College Culture Collection", -"LYD s Mpumalanga Parks Board", -"LYJB s Jardin Botanique de Lyon", -"LYN s Lynchburg College, Biology Department", -"LZ s Universitaet Leipzig", -"LZAH s Lanzhou Institute of Animal Science, Chinese Academy of Agricultural Sciences", -"LZD s Lanzhou Institute of Desert Research, Academia Sinica", -"LZFD s Laboratoire Zoologique", -"LZLP s Universidade de Lisboa", -"LZU s Lanzhou University", -"LZUH s Laboratoire de Zoologie, Universite de Hanoi", -"M s Botanische Staatssammlung Muenchen", -"MA s Real Jardin Botanico", -"MA:Algae s Real Jardin Botanico, Algae collection", -"MA:Fungi s Real Jardin Botanico, Fungi collection", -"MA:FunHist s Real Jardin Botanico, Historical fungi colleciton", -"MA:Hepat s Real Jardin Botanico, Liverwort collection", -"MA:Lichen s Real Jardin Botanico, Lichen collection", -"MA:Musci s Real Jardin Botanico, Bryophyte collection", -"MAA s Escuela Tecnica Superior de Ingenieros Agronomos, Departamento de Produccion Vegetal", -"MAAS s Natuurhistorisch Museum Maastricht, Botany Department", -"MAC s Instituto do Meio Ambiente", -"MAC-APU s Ministerio de Agricultura y Cria", -"MAC-PAY s Ministerio de Agricultura y Cria", -"MACA s Parque da Reserva de Siac Pai van Coloane Island", -"MACB s Universidad Complutense, Departamento de Biologia Vegetal 1", -"MACF s California State University, Biological Science Department", -"MACLPI s Ministerio de Agricultura y Cria, Seccion de Pesca Interior y Piscicultura", -"MACN s Museo Argentino de Ciencias Naturales Bernardino Rivadavia", -"MACN-RN s Museo Argentino de Cicencis Naturales, Coleccion Rio Negro", -"MACNCH s Museo Argentino de Ciencias Naturales", -"MACO s Marlborough College, Biology Department", -"MAD s Madras Museum", -"MAD s Forest Products Laboratory", -"MADJ s Jardim Botanico da Madeira", -"MADM s Museu Municipal do Funchal", -"MADS s Museu de Historia Natural do Seminario do Funchal", -"MAF s Universidad Complutense, Departamento de Biologia Vegetal II", -"MAFF c MAFF Genebank, Ministry of Agriculture Forestry and Fisheries", -"MAFF s Colo-i-Suva Silvicultural Station", -"MAFI s Magyar Allami Foeldtani Intezet, Budapest - Hungarian Geological Survey", -"MAFST s Instituto Forestal de la Moncloa", -"MAG s Institute of Biological Problems of the North", -"MAGB s National Museum and Art Gallery, Gaberone", -"MAGD s Northern Territory Museum of Arts and Sciences", -"MAGNT s Museums and Art Galleries of the Northern Territory", -"MAGNT:A s Museums and Art Galleries of the Northern Territory, Arachnid Collection", -"MAGNT:C s Museums and Art Galleries of the Northern Territory, Cnidarian Collection", -"MAGNT:Cr s Museums and Art Galleries of the Northern Territory, Crustacean Collection", -"MAGNT:D s Museums and Art Galleries of the Northern Territory, Minor Invertebrate Collection", -"MAGNT:E s Museums and Art Galleries of the Northern Territory, Ascidian Collection", -"MAGNT:G s Museums and Art Galleries of the Northern Territory, Bryozoan Collection", -"MAGNT:I s Museums and Art Galleries of the Northern Territory, Insect Collection", -"MAGNT:M s Museums and Art Galleries of the Northern Territory, Myriapod Collection", -"MAGNT:N s Museums and Art Galleries of the Northern Territory, Pycnogonid Collection", -"MAGNT:P s Museums and Art Galleries of the Northern Territory, Malacology Collection", -"MAGNT:Q s Museums and Art Galleries of the Northern Territory, Echinoderm Collection", -"MAGNT:R s Museums and Art Galleries of the Northern Territory, Herpetology Collection", -"MAGNT:S s Museums and Art Galleries of the Northern Territory, Fish Collection", -"MAGNT:T s Museums and Art Galleries of the Northern Territory, Bird Collection", -"MAGNT:U s Museums and Art Galleries of the Northern Territory, Mammal Collection", -"MAGNT:W s Museums and Art Galleries of the Northern Territory, Annelid Collection", -"MAGNT:Z s Museums and Art Galleries of the Northern Territory, Poriferan Collection", -"MAH s Department of Agricultural Research", -"MAIA s Instituto Nacional de Investigaciones Agrarias, Departamento de Ecologia", -"MAIC s Mediterranean Agronomic Institute of Chania, Department of Natural Products", -"MAINE s University of Maine, Department of Biological Sciences", -"MAIS s Institut d'Elevage et de Medecine Veterinaire des Pays Tropicaux, Departement de Botanique", -"MAK s Tokyo Metropolitan University", -"MAKAR s Institut Planina i More", -"MAKFUNGI s Fungi Macedonici", -"MAL s Botanic Gardens of Malawi", -"MALA s Malaspina University, Biology Department", -"MALC s Museu Municipal de la Vila d'Alcover", -"MALS s Manti-LaSal National Forest", -"MAMU s University of Sydney, Macleay Museum", -"MAN s Universitas Cenderawasih", -"MANCH s University of Manchester", -"MAND s Agricultural College and Research Institute", -"MANK s Minnesota State University-Mankato, Department of Biological Sciences", -"MAO c Mircen Afrique Ouest", -"MAPA s Museu Anchieta Porto Alegra", -"MAPR s University of Puerto Rico, Mayagueez Campus, Biology Department", -"MAR c Grasslands Rhizobium Collection", -"MARDI h Malaysian Agricultural Research and Development Institute", -"MARE s Marmara University, Department of Pharmaceutical Botany", -"MARI h Mari State University", -"MARK h Cadi Ayyad University", -"MARO s Marylhurst College", -"MARS s Universite de Provence Centre St-Charles, case 4", -"MARSSJ s Universite Paul Cezanne", -"MARY s University of Maryland", -"MASE s Maseru Experiment Station", -"MASS s University of Massachusetts, Biology Department", -"MATSU s Ehime University, Forestry Department", -"MAU s Mauritius Sugar Industry Research Institute", -"MAUAM h Universidad Autonoma de Madrid", -"MAY s Adygean State University, Department of Botany", -"MB s Museum of Natural History of Humboldt-University", -"MB s Philipps-Universitaet, Spezielle Botanik", -"MB s Universidade de Lisboa, Museu Bocage", -"MBA s Environmental Protection Agency", -"MBAB s Museo Biblioteca Archivio", -"MBAC s Museo del Dipartimento di Biologia Animale dell'Universita", -"MBAP s Museo del Dipartimento di Biologia Animale dell'Universita", -"MBBJ s Museum Zoologicum Bogoriense, Entomology Collection", -"MBC sb Montgomery Botanical Center", -"MBCG s Museo di Scienze Naturali \"Enrico Caffi\"", -"MBCSC s Marine Biodiversity Collection of South China Sea, Chinese Academy of Sciences", -"MBCSC:Fish s Marine Biodiversity Collection of South China Sea, Chinese Academy of Sciences, Fish Collection", -"Mbg s Fachberich Geowissenschaften", -"MBH s Marlborough College", -"MBIC c Marine Biotechnology Institute Culture Collection", -"MBK s Kochi Prefectural Makino Botanical Garden, Botany Department", -"MBL s Museu Nacional de Historia Natural", -"MBM s Museu Botanico Municipal", -"MBM s San Jose State University, Museum of Birds and Mammals", -"MBM s Marjorie Barrick Museum", -"MBML s Museu de Biologia Mello Leitao", -"MBMU c Institute of Molecular Biology and Genetics (IMBG), Mahidol University", -"MBR s Museo Argention de Ciencias Naturales \"Bernardino Rivadavia\"", -"MBS s Manchester Banksian Society", -"MBSL s Royal Medico-Botanical Society", -"MBSN s Museo Brembano di Scienze Naturali", -"MBUCV s Museo de Biologia de la Universidad Central de Venezuela", -"MBZH s Museo y Biblioteca de la Zoologia", -"MC s Museo de Cipolleti", -"MCA s Muhlenberg College, Biology Department", -"MCAS s Museo Civico Archeologico e di Scienze Naturali \"F. Eusebio\"", -"MCBR s Museo Civico \"Baldassarre Romano\"", -"MCC c Microbial Culture Collection", -"MCC-UPLB c Microbial Culture Collection", -"MCCB s Museo Civico \"Craveri\"", -"MCCC c Marine Culture Collection of China", -"MCCI s Museo Civico di Storia Natural de Carmognola", -"MCCM c Medical Culture Collection Marburg", -"MCCM s Madras Christian College", -"MCD s Muzeul Civilizatiei Dacice si Romane Deva", -"MCDNL h McDaniel College", -"MCES s Museum of the Center for Entomological Studies", -"MCF h Sts. Cyril and Methodius University", -"MCF-PVPH s Museo Carmen Funes", -"MCFB s Museo de la Cienica Fundacion", -"MCFM s Museo Civico \"Francesco Mina Palumbo\"", -"MCFS s Museo Civico di Storia Naturale, Ferrara", -"MCG s Museo Civico DI Storia Naturale 'Giacomo Doria'", -"McGMK s McGregor Memorial Museum", -"MCGS s Museo Civico \"Giuseppe Scarabelli\"", -"MCITM c Bacterial Culture Collection", -"MCIZ s Museo Cambria, Istituto di Zoologia dell'Universita", -"MCJ s Missouri Southern State College, Biology Department", -"MCLSBB s Museo Colegio La Salle Bonanova de Barcelona", -"MCM(CMFRI) s Reference Collection", -"MCM s Hamilton College, McMaster University, Biology Department", -"MCM s Institut de Paleontologie, Museum d'Histoire naturelle", -"MCM c MACS Collection of Microorganisms", -"MCM s Museu Carlos Machado", -"MCMC s Museo de Historia Natural de la Ciudad de Mexico", -"McMJ s Mc Master University", -"MCMS s Museo Civico di Storia Naturale, Morgegno", -"MCN s McNeese State University, Biology Department", -"MCNA s Museo de Ciencias naturals de Alava", -"MCNC s Museo de Ciencias Naturales", -"MCNG s Museo de Ciencias Naturales de la UNELLEZ en Guanare", -"MCNPV s Fundacao Zoobotanica do Rio Grande do Sul", -"MCNS s Universidad Nacional de Salta, Facultad de Ciencias Naturales", -"MCNV s Museo Civico di Storia Naturale, Venice", -"MCNZ s Porto Alegre, Museu de Ciencias Naturais da Fundacao Zoo-Botanica do Rio Grande do Sul", -"MCP s Pontificia Universidade Catolica do Rio Grande do Sul", -"MCP s Massachusetts College of Pharmacy and Allied Health Sciences, Biological Sciences Department", -"MCPM s Milwaukee City Public Museum", -"MCPPV s Museu de Ciencias e Tecnologia", -"MCPUCRGS s Museu de Ciencias da Pontificia Universidade Catolica do Rio Grande do Sul", -"MCR s Manchester Literary and Philosophical Society", -"MCRA s Sezione Archeologia, Storia e Scienze Naturali", -"MCRBS s Manchester Botanical and Horticultural Society", -"MCSB s Museo Civico di Scienze Naturali", -"MCSC s Colorado Springs, May Natural History Museum", -"MCSF s Museo Civico di Scienze Naturali", -"MCSG s Museo Civico di Storia Naturale, Grosseto", -"MCSN s Museo Civico di Storia Naturale \"Giacomo Doria\"", -"MCSN s Museo Civico di Storia Naturale, Verona", -"MCSNC s Museo Civico di Storia Naturale, Carmagnola", -"MCSNIO s Museo Civico di Scienze Naturali di Induno Olona", -"MCST s Museo Civico di Storia Naturale, Trieste", -"MCT s Michigan Technological University, Biological Sciences Department", -"MCTC s Michigan Technological University, Biological Sciences Department", -"MCTF s Michigan Technological University", -"MCTP s Museu de Ciencias", -"MCVE s Museo di Storia Naturale di Venezia", -"MCVM s Museo Civico, Villa Mirabello", -"MCW s Milton College, Biology Department", -"MCZ s Museum of Comparative Zoology, Harvard University", -"MCZ:Cryo s Museum of Comparative Zoology, Harvard University, Cryogenic Collection", -"MCZ:Ent s Museum of Comparative Zoology, Harvard University, Entomology Collection", -"MCZ:Herp s Museum of Comparative Zoology, Harvard University, Herpetology Collection", -"MCZ:Ich s Museum of Comparative Zoology, Harvard University, Ichthyology Collection", -"MCZ:IP s Museum of Comparative Zoology, Harvard University, Invertebrate Paleontology Collection", -"MCZ:IZ s Museum of Comparative Zoology, Harvard University, Invertebrate Zoology Collection", -"MCZ:Mala s Museum of Comparative Zoology, Harvard University, Malacology Collection", -"MCZ:Mamm s Museum of Comparative Zoology, Harvard University, Mammalogy Collection", -"MCZ:Orn s Museum of Comparative Zoology, Harvard University, Ornithology Collection", -"MCZR s Museo Civico di Zoologia", -"MD s Museu Regional do Dundo", -"MD s Museum Donaueschingen", -"MDC c Microbial Depository Center (National Microbial Culture Collection of the Republic of Armenia)", -"MDE s Musee des Dinosaures in Esperaza", -"MDFW s Massachusetts Division of Fisheries and Wildlife", -"MDH s Dorman Museum", -"MDH c Michigan Department of Health", -"MDI h Malaysian Agricultural Research and Development Institute", -"MDKY s Morehead State University, Biological and Environmental Sciences Department", -"MDLA s Museu do Dundo", -"MDM s Mifune Dinosaur Museum", -"MDNR s Manitoba Conservation", -"MDP s Museum de Poligny", -"MDRG s Museum voor Dierkunde, Rijksuniversiteit", -"MDTN s Middleton Botanical Society", -"MDUG s Universidad Guanajuato, Museo Alfredo Duges", -"MDZAU s Museum Deptartment of Zoology", -"MECB s Universidade Federal de Pelotas, Museu Entomologico Ceslau Biezanko", -"MECG s Medical Entomology Collection Gallery", -"MECN s Museo Ecuadoriano de Ciencias Naturales", -"MEDEL s Universidad Nacional de Colombia - Sede de Medellin, Departamento de Biologia", -"MEFLG s Museo Entomologico Francisco Luis Gallego", -"MEL s Royal Botanic Gardens Melbourne", -"MELG s Geology Department, University of Melbourne", -"MELIT h Bogdan Khmel'nysckyi State Pedagogical University of Melitopol'", -"MELU s University of Melbourne", -"MEM s University of Memphis, Biology Department", -"MEMO s Instituto Tecnologico y de Estudios Superiores de Monterrey, Departamento de Recursos Naturales", -"MEN s UNCuyo, Catedra de Botanica Agricola, Departamento de Ciencias Biologicas", -"MEPAN s Museum of Evolution, Polish Academy of Sciences", -"MER s Universidad de Los Andes", -"MERC s Universidad de Los Andes, Centro Jardin Botanico", -"MERCA h Mercer Arboretum and Botanic Gardens", -"MERF s Universidad de Los Andes", -"MERL s Instituto Argentino de Investigaciones de las Zonas Aridas (CRICYTME)", -"MESA s Mesa State College, Biology Department", -"MEUC s Universidad de Chile", -"MEX s Museo de Historia Natural de la Ciudad de Mexico", -"MEXU s Herbario Nacional de Mexico, Universidad Nacional Autonoma de Mexico", -"MFA s Museo Provincial de Ciencias Naturales Florentino Ameghino, Seccion Botanica", -"MFA-ZV-M s Museo Florentino Ameghino, Coleccion de Mastozoologia (Argentina)", -"MFAP s Archaeology and Palaeontology", -"MFB s Southern Research Station", -"MFC c Matsushima Fungus Collection", -"MFGC c Margot Forde Germplasm Centre, AgResearch GrasslandsWar", -"MFLB s Marine Fisheries Laboratory", -"MFLU sc Mae Fah Laung University Herbarium", -"MFLUCC c Mae Fah Luang University Culture Collection", -"MfN s Museum fur Naturkunde", -"MFNB s Museo Friulano di Storia Naturale", -"MFP s Museo Felipe Poey", -"MFRU s Malawi Fisheries Research Unit", -"MFS s Museo dei Fisiocritici", -"MFSN s Museo Friulano di Storia Naturale of Udine", -"MFU s Museo Friulano di Storia Naturale", -"MFUM s Museum of Ferdowsi University of Mashhad", -"MFUW s Chinzombo Research Station, Chinzombo Wildlife Research Station", -"MFW s Museum Freriks", -"MG s Museu Paraense Emilio Goeldi, Departamento de Botanica", -"MG s Museum of Zoology", -"MGA s Instituto Pedagogico de Varones", -"MGAB s Muzeul de Istorie Naturala \"Grigore Antipa\"", -"MGAP s Museu Anchieta", -"MGB s Museo de Geologia (del Seminario Diocesano) de Barcelona", -"MGC s Universidad de Malaga, Departamento de Biologia Vegetal", -"MGDL s Museum d'Histoire Naturalle du Grand-Duchy de Luxembourg", -"MGF s Museum George Frey", -"MGFT s Museum G. Frey", -"MGH s Museum Godeffroy", -"MGHF s Museo Geologico H. Fuenzalida", -"MGHNL s Musee Guimet d'Histoire Naturelle de Lyon", -"MGHSJ s Matuyama Girl's High School", -"MGI s Geological Institute of the Mongolian Academy of Sciences", -"MGL s Musee Geologique de Lausanne", -"MGR s University of Michigan", -"MGRI s Moscow Geological Prospecting Institute", -"MGS s Upper Silesian Museum, Department of Natural History", -"MGSI s Museum of the Geological Survey of Iran", -"MGSP s Museum of the Geological Survey of Portugal", -"MGUG s Museum fuer Geologie und Palaontologie der Georg-August-Universitat", -"MGUH s Museum Geologicum Universitatis Hafniensis", -"MGUP s Museo Geologico della Universita Pisa", -"MGUV s Museo del Departamento de Geologia, Universidad de Valencia", -"MGUWR s Institute of Geological Sciences, University of Wroclaw", -"MH s Naturhistorisches Museum, Basel", -"MH s Tamil Nadu Agricultural University", -"MHA s Main Botanical Garden of the Russian Academy of Sciences", -"MHES h Museo de Historia Natural de El Salvador", -"MHH c Institute of Virology", -"MHL s Mildenhall and District Museum", -"MHM s Malham Tarn Field Centre", -"MHMN s Museu Historic Municipal de Novelda", -"MHNA s Museum d'Histoire Naturelle d'Autun", -"MHNB s Museum d'Histoire Naturelle de Bale", -"MHNC s Musee d'Histoire Naturelle - La Chaux-de-Fonds", -"MHNC s Museo de Historia Natural de Concepcion (Chile)", -"MHNCI s Museu de Historia Natural Capao de Imbuia (Brazil)", -"MHNCSJ s Museo de Historia Natural", -"MHNES s Museo de Historia Natural de El Salvador", -"MHNG s Natural History Museum of Geneva", -"MHNG:Herp s Natural History Museum of Geneva, Herpetology collection", -"MHNG:Invertebrate s Natural History Museum of Geneva, Invertebrate collection", -"MHNI s Museu Hist. Naturales Universidade Federal Minas Gerais", -"MHNJP s Universidad Nacional Mayor de San Marcos", -"MHNL s Musee Guimet d'Histoire Naturelle de Lyon", -"MHNLR s Museum d'Histoire Naturelle", -"MHNLS s Coleccion de Mastozoologia, Museo de Historia Natural de La Salle", -"MHNM s Museo Nacional de Historia Natural y Antropologia", -"MHNN s Neuchatel Musee d'Histoire Naturel", -"MHNN s Musee d'Histoire Naturalle", -"MHNNICE s Mueusm d'Histoire Naturelle de Nice", -"MHNP s Museum d'Histoire Naturelle Perpignan", -"MHNSM s Museo de Historia Natural, Universidad Nacional Mayor de San Marcos", -"MHNT s Museum d'Histoire Naturelle Toulouse", -"MHNUNC s Departamento de Ictiologia del Museo de Historia Natural de la Universidad Nacional de Colombia", -"MHNV s Museo de Historia Natural de Valparaiso", -"MHP s Fort Hays State University, Sternberg Museum of Natural History", -"MHU s Makerere University, Botany Department", -"MHUA s Museo de Herpetologia de la Universidad de Antioquia", -"MHV s Musee de Haute Volta", -"MHWK s Much Wenlock Museum", -"MI s Universita degli Studi di Milano, Dipartimento di Biologia", -"MIB s University of Milano - Bicocca, Department of Biotechnology and Biosciences", -"MIB:ZPL s University of Milano - Bicocca, Department of Biotechnology and Biosciences, ZooPlantLab", -"MIC s Mar Ivanios College (Zoology museum)", -"MICG h Universidad de San Carlos de Guatemala", -"MICH s University of Michigan", -"MICKKU c MICKKU Culture Collection", -"MID s Middlebury College, Biology Department", -"MII s Museum of Irish Industry", -"MIKU s Marine Biological Institute, Kyoto University", -"MIL s Milwaukee Public Museum", -"MIM s Minusinsk N. M. Martjanov Regional Museum", -"MIMB s Museum of the Institute of Marine Biology", -"MIMM s Mauritius Institute", -"MIN s University of Minnesota", -"MINC s Universidad Politecnica", -"MINI s Muzeul de Istoria Naturala", -"MIPV s Universita degli Studi di Milano, Laboratorio di Micologia e Batteriologia Fitopathologica", -"MIRR h Museu Integrado de Roraima", -"MISR s Macaulay Land Use Research Institute", -"MISS s University of Mississippi, Department of Biology", -"MISSA s Mississippi State University, Department of Biological Sciences", -"MISU h Minot State University", -"MIT c Massachusetts Institute of Technology", -"MIWG s Museum of he Isle of Wight Geology", -"MIZA s Museuo del Instituto de Zoologia Agricola", -"MIZL s Musee de l'Institut de Zoologie", -"MIZT s Universita di Torino", -"MJ s Muzeum Vysociny", -"MJCM s Museo de Ciencias Naturales y Antropologicas \"Prof. Juan C.Moyano\" (Argentina)", -"MJG s Museo Jorge Gerhold", -"MJG s Landesmuseum Joanneum", -"MJG s Johannes Gutenberg-Universitaet", -"MJH s Muzeul Judetean Hunedoara", -"MJMO s Universidad Centro Occidental, Decanato de Agronomia", -"MJS s Xiaolongshan Forestry Experiment Bureau", -"MJSD s Museum-Jardin des Sciences", -"MK s National Museum of Kenya", -"MKMEL h Herbarium Melovskiorum", -"MKNDC h Institute of Biology", -"MKNH h Institute of Biology", -"ML s Musee de Lectoure", -"MLAV s Musees de Laval", -"MLGU h Institut National pour l'Etude et la Recherche Agronomiques", -"MLLD c Microbiological Research Laboratory, Soil and Water Section, Department of Land Development", -"MLMJI c Department of Plant Protection, Faculty of Agricultural Production", -"MLP s Museo de La Plata", -"MLRU c Microbiology Laboratory, Department of Biology, Faculty of Science", -"MLS s Marine Laboratory Sydney", -"MLS s Museo del Instituto de La Salle", -"MLS s Lathallan Preparatory School", -"MLUH s Martin Luther Universitat", -"MLY s Arboretum Mlynany", -"MLZ s Moore Laboratory of Zoology, Occidental College", -"MLZ:Bird s Moore Laboratory of Zoology, Occidental College, Bird Collection", -"MLZ:Mamm s Moore Laboratory of Zoology, Occidental College, Mammal Collection", -"MM s Manitoba Museum", -"MM s Museo del Mar", -"MM s Magdeburg Museum", -"MM s University of Montpellier", -"MMB s Moravske Muzeum", -"MMBC s Moravske Muzeum [Moravian Museum]", -"MMBS s Mukaishima Marine Biological Station", -"MMCC c MARDI Microbial Culture Collection", -"MMChPV s Museo Municipal El Chocon", -"MMCM s Museum of Malawi", -"MMF s Museu Municipal do Funchal", -"MMG s Museo Marino de la Isla de Gorgona", -"MMH s Municipal Museum", -"MMI s Regionalni muzeum", -"MMK s McGregor Museum", -"MMKZ s Alexander McGregor Memorial Museum", -"MML c Medical Microbiological Laboratory", -"MMMN s Manitoba Museum of Man and Nature, Botany Department", -"MMMZ s Mutare Museum", -"MMNH s Mongolian Museum of Natural History", -"MMNH s Bell Museum of Natural History", -"MMNHS s Macedonian Museum of Natural History", -"MMNS s Mississippi Museum of Natural Science", -"MMP s Museo de Mar del Plata (Argentina)", -"MMRF c Marine Microbial Reference Facility", -"MMS s Montshire Museum of Science", -"MMTT s Iran National Museum of Natural History", -"MMUE s Museum of Manchester University", -"MMUS s Macleay Museum, University of Sydney", -"MN s Museu Nacional, Universidade Federal do Rio de Janeiro", -"MNA s Museum of Northern Arizona", -"MNA s The Museo Nazionale dell'Antartide (Italian National Antarctic Museum in Genoa).", -"MNAV s Museo Naturalistico-Archeologico", -"MNB s Museum fuer Naturkunde der Humboldt-Universitaet", -"MNCE s Museu de Historia Natural Capao da Embuia", -"MNCN sb Museo Nacional de Ciencias Naturales", -"MNCN:ADN sb Museo Nacional de Ciencias Naturales, Coleccion de Tejidos y ADN", -"MNCN:Ent s Museo Nacional de Ciencias Naturales, Coleccion de entomologia", -"MNCN:Herpeto s Museo Nacional de Ciencias Naturales, Coleccion de anfibios y reptiles", -"MNCN:ICTIO s Museo Nacional de Ciencias Naturales, Coleccion de ictiologia", -"MNCN:Inverte s Museo Nacional de Ciencias Naturales, Coleccion de invertebrados", -"MNCN:Malac s Museo Nacional de Ciencias Naturales, Coleccion de malacologia", -"MNCN:Mam s Museo Nacional de Ciencias Naturales, Colession de mamiferos", -"MNCN:Ornit s Museo Nacional de Ciencias Naturales, Coleccion de aves", -"MNCR s Museo Nacional de Costa Rica", -"MND s Museum Natura Docet", -"MNDG s Museo Nacional \"David J. Guzman\"", -"MNE s Maidstone Museum and Art Gallery", -"MNFD s Museum fuer Naturkunde", -"MNG s Sammlung Eisfeld des Museums der Natur Gotha", -"MNGA s Muzeul National de Istorie Natural \"Grigore Antipa\"", -"MNGC s Museo Nacional de Historia Natural, Guatemala City", -"MNH s Musei Nacionalis Hungarici", -"MNHCI s Museu de Historia Natural Capao da Imbuia", -"MNHM s Naturhistorisches Museum Mainz/Landessammlung fuer Naturkunde Rheinland-Pfalz", -"MNHM s John May Museum of Natural History", -"MNHN s Museum National d'Histoire Naturelle", -"MNHN:IC s Museum National d'Histoire Naturelle, Ichtyologie collection", -"MNHN:IM s Museum National d'Histoire Naturelle, Marine Invertebrate Collection", -"MNHN:IU s Museum National d'Histoire Naturelle, Crustacean collection", -"MNHN:M s Museum National d'Histoire Naturelle, Mammal collection", -"MNHN:P s Museum National d'Histoire Naturelle, Paleontology Collection", -"MNHN s Museo Nacional de Historia Natural, Departamento de Colecciones", -"MNHN s Museo Nacional de Historia Natural de Montevideo", -"MNHNCH s Museo Nacional de Historia Natural de Chile", -"MNHNCU s Museo Nacional de Historia Natural, Havana", -"MNHNJP s Universidad Nacional Mayor de San Marcos", -"MNHNLES s Museum National d'Histoire Naturelle Lesotho", -"MNHNM s Museo Nacional de Historia Natural, Mexico City", -"MNHNP s Museo Nacional de Historia Natural del Paraguay", -"MNHNSD s Museo Nacional de Historia Natural, Santo Domingo", -"MNHNUL s Museu Nacional de Historia Natural de Universidade de Lisboa", -"MNHP s Princeton University", -"MNHS s Manchester Natural History Society", -"MNK s Museo de Historia Natural \"Noel Kempff Mercado\"", -"MNK:A s Museo de Historia Natural \"Noel Kempff Mercado\", Amphibian Collection", -"MNK:R s Museo de Historia Natural \"Noel Kempff Mercado\", Reptile Collection", -"MNKS s Milton Keynes Development Corporation", -"MNMB s Magyar Nenzeti Museum", -"MNMS s Museo Nacional de Ciencias Naturales", -"MNN s Musee National du Niger", -"MNNC s Museo Nacional de Historia Natural, Santiago", -"MNNHN s Museum National d'Historie Naturelle", -"MNNW s Museum fuer Naturkunde", -"MNRJ s Museu Nacional/Universidade Federal de Rio de Janeiro", -"MNSB s Museum of Natural Sciences", -"MNSL s Museum of Natural Sciences", -"MNUFR s Mongolian National University", -"MNVD h Museum fur Naturkunde und Vorgeschichte Dessau", -"MNVL s Museum d'Histoire Naturelle de Ville de Lille", -"MNZ s Museum of New Zealand Te Papa Tongarewa", -"MO s Missouri Botanical Garden", -"MOAR s Morris Arboretum, University of Pennsylvania, Botany Department", -"MOBR h Estacion de Investigaciones Marinas de Margarita, Fundacion La Salle de Ciencias Naturales", -"MOC s Western Oregon University, Biology Department", -"MOD s Universita degli Studi di Modena e Reggio Emilia, Dipartimento de Biologia Animale", -"MODNR s Division of State Parks, Department of Natural Resources", -"MOFUNG s Museu Oceanogr. Fundacao Univerdidade Rio Grande", -"MOG s National Range Agency", -"MOL s Universidad Nacional Agraria La Molina, Departamento Academico de Biologia", -"MOLA c Microbial Observatory of the Laboratoire Arago", -"MOM s Musee Oceanographique Monaco", -"MONA s Musee Oceanographique de Monaco", -"MONT s Montana State University", -"MONTU s University of Montana", -"MONZ s Museum of New Zealand", -"MOR s Morton Arboretum, Research Department", -"MOR s Museum of the Rockies", -"MOS s College of Agriculture and Forestry", -"MOSG s Muzeul Orasului Sf. Gheorghe", -"MOSI s Museum of Science and Industry", -"MOSM s All-Russian Research Institute of Medicinal and Aromatic Plants", -"MOSN s Museo Ornitologico e di Scienze Naturali", -"MOSP s Moscow State Pedagogical University, Botany Department", -"MOSS h Universidade Federal Rural do Semi-Arido", -"MOT s Mote Marine Laboratory", -"MOTH s Museum of the Hemispheres", -"MOUFPE s Oceanographic Museum of the Federal University of Pernambuco", -"MOVC s Cornell College, Biology Department", -"MOVI s Museu Oceanografico do Vale do Itajai", -"MP s Vychodoceske muzeum Pardubice", -"MP s Mohonk Preserve, Inc.", -"MP s Transvaal Museum", -"MPA s Ecole National Superieure Agronomique, Biologie et Pathologie Vegetales", -"MPC s Monterey Peninsula College, Life Science Museum", -"MPCA s Museo Provincial \"Carlos Ameghino\"", -"MPCNyO s Museo Provincial de Ciencias Naturales, Puerto Madryn", -"MPCRM s Museo Paleontologico Cittadino della Rocca", -"MPE s F. R. Long Herbarium", -"MPEF-PV s Muso Paleontologico Egidio Fergulio", -"MPEG s Museu Paraense Emilio Goeldi", -"MPEP s Musee de Paleontologie et de l'evolution", -"MPGB s Museum of Portuguese Guinea", -"MPH h Shahid Behershti University", -"MPKV c Biological Nitrogen Fixation Project College of Agriculture", -"MPL s Musee de Port Louis", -"MPLN s Museo Provinciale di Storia Naturale", -"MPM s Milwaukee Public Museum", -"MPM s Meguro Parasitological Museum", -"MPMP s National Museum of the Philippines", -"MPN s Massey University, Ecology Group", -"MPPD s University of Minnesota, Plant Pathology Department", -"MPPE s Paletnologica ed Etnologico dei Padri Francescani", -"MPR s Mount Makulu Pasture Research Station", -"MPSC s Museu de Paleontologia de Santana do Cariri", -"MPSN s Museo Provinciale di Scienze Naturali", -"MPSP s Museu Paulista", -"MPSU c Department of Microbiology, Songkla University", -"MPT s Museuo Provincial de Teurel", -"MPU s Universite Montpellier II", -"MPUC s Pontificia Universidade Catolica do Rio Grande do Sul, Laboratorio de Botanica", -"MPUM s Museo Paleontologia Universita degli Studi di Milano", -"MPUN s Museo Paleontologicom", -"MPUNR s Departamento de Geologia, Universidad de Chile", -"MPV s Museo Paleontologico Municipal de Valencia", -"MPZ s Museo Paleontologico de la Universidad de Zaragoza", -"MQ s Gansu Institute of Desert Control", -"MQU s Macquarie University", -"MRA s Museo Requieu", -"MRA c Malaria Research and Reference Reagent Resource Center", -"MRAC s Musee Royal de l'Afrique Centrale", -"MRC c TUBITAK Marmara Research Center Culture Collection", -"MRC s Rocky Mountain Research Station", -"MRC c National Research Institute for Nutritional Diseases", -"MRCA s Musee Royal de l'Afrique Centrale", -"MRCN s Museu Rio-Grandense de Ciencias Naturais", -"MRD s Moorhead State University, Biology Department", -"MRF s Museum of Histoire naturelle", -"MRGS s Museu do Rio Grande do Sul", -"MRI s Murray Royal Institution", -"MRNP s Mount Rainier National Park", -"MRSC s Mount Makulu Central Research Station", -"MRSH s Matopos Research Station", -"MRSN s Museo Regionale di Scienze Naturali", -"MRSN c Multidrug Resistant Organism Repository and Surveillance Network", -"MRSP s Museo Regionale di Scienze Naturali, St. Pierre", -"MRST s Museo Regionale di Storia Naturale, Terrasini", -"MS s Universita di Messina, Dipartimento di Scienze Botaniche", -"MSA s Museum of Science and Art", -"MSB s Museum of Southwestern Biology", -"MSB:Bird s Museum of Southwestern Biology, Bird Collection", -"MSB:Fishes s Museum of Southwestern Biology, Fish Collection", -"MSB:Herp s Museum of Southwestern Biology, Herpetology Collection", -"MSB:Mamm s Museum of Southwestern Biology, Mammal Collection", -"MSB:Para s Museum of Southwestern Biology, Parasitology Collection", -"MSB s Museum Sophia", -"MSB s Ludwig-Maximilians-Universitaet", -"MSC s Michigan State University, Botany and Plant Pathology Department", -"MSCL c Microbial Strain Collection of Latvia", -"MSCMU c Microbiology Section, Chiang Mai University (MSCMU)", -"MSCW s Mississippi University for Women", -"MSDB s Museo di Storia Naturale \"Don Bosco\"", -"MSDS c Microbiology Section, Biological Science Division, Department of Science Services", -"MSE s Angus Museums", -"MSEM s Museu Geologic del Seminari de Barcelona", -"MSEN s Montrose Natural History and Antiquarian Society", -"MSF s Sauriermuseum Frick", -"MSGP s Nusee des Services Geologiques du Portugal", -"MSI h Marine Science Institute, University of the Philippines", -"MSIE s Museum of Shanghai", -"MSINR s Museum Sichuan Institute of Natural Resources", -"MSIR s Mauritius Sugar Industry", -"MSJC s St. Joseph's College, Natural History Museum", -"MSK s National Academy of Sciences of Belarus, Flora and Systematic Laboratory", -"MSKH s Central Botanical Garden", -"MSKU s Belarusian State University, Botany Department", -"MSL s Royal Medical Society of London", -"MSLH s Chinese University of Hong Kong, Marine Sciences Laboratory", -"MSLY s Mossley Botanical Society", -"MSM s Marine Science Museum, Tokai Univ.", -"MSM s University of Puerto Rico, Marino Puertorriqueno", -"MSNA s Museo di Storia Naturale e Arte Archeologica", -"MSNG s Museo Civico di Storia Naturale di Genova 'Giacomo Doria'", -"MSNM s Museo Civico di Storia Naturale di Milano", -"MSNO s Museum des Sciences Naturelles", -"MSNP s Museo di Scienze Naturali", -"MSNT s Museo Regionale di Scienze Naturali, Torino", -"MSNT:FAZC s Museo Regionale di Scienze Naturali, Torino, Franco Andreone Zoological Collection", -"MSNT s Museo Civico DI Storia Naturale DI Torino", -"MSNU s Museo di Storia Naturale dell'Universita", -"MSNV s Museo Civico di Storia Naturale di Venezia", -"MSNVR s Museo Civico di Storia Naturale di Verona", -"MSPC s Museo di Storia Naturale \"Pietro Calderini\"", -"MSPP c Mycology Section, Plant Pathology and Microbiology Division, Department of Agricultural Science", -"MSSC s Midwestern State University", -"MSTFM s Middle School of the Third Factory Machinery", -"MSTR s Westfaelisches Museum fuer Naturkunde", -"MSU c Acetobacter", -"MSU s Michigan State University Museum", -"MSUB s Montana State University", -"MSUD s I. I. Mecynikov State University of Odessa, Department of Morphology and Systematics of Plants", -"MSUH s University of Mosul, Biology Department", -"MSUMC s Murray State University", -"MSUMZ s Memphis State University", -"MSUN s Westfaelische Wilhelms-Universitaet", -"MSUT s Museum of Natural History, Tirane", -"MSUZ s Mississippi State University, Zoological Collections", -"MSV s Museum der Stadt Villach", -"MT s Universite de Montreal", -"MT s Mus. Tinro, Vladyvostok", -"MTA s Maden Tetkik ve Arama Enstituesue", -"MTCC c Microbial Type Culture Collection & Gene Bank", -"MTCHT h Mar Thoma College", -"MTD s Museum of Zoology Senckenberg Dresden", -"MTD:T s Museum of Zoology Senckenberg Dresden, Tissue collection", -"MTD:TD s Museum of Zoology Senckenberg Dresden, Herpetological Tissue Collection", -"MTDO h Chiba University", -"MTEC s Montana State University", -"MTJB s Jardin botanique de Montreal", -"MTKD s Staatliches Museum fuer Tierkunde", -"MTKKU c Department of Clinical Microbiology, Faculty of Medical Technology", -"MTMG s McGill University, Macdonald Campus, Plant Science Department", -"MTN s Malton Field Naturalists' Society", -"MTQA s Museum of Tropical Queensland", -"MTSN s Trento Museum of Natural Sciences", -"MTSU s Middle Tennessee State University, Biology Department", -"MTUF s University Museum, Tokyo University of Fisheries", -"MU c Mugla University Collection of Microorganisms", -"MU s Miami University, Botany Department, Willard Sherman Turrell Herbarium", -"MU s Midwestern University", -"MUACC c Murdoch University Algal Culture Collection", -"MUAF c Culture collection of Mendel University of Agriculture and Forestry in Brno", -"MUB s Universidad de Murcia, Departamento de Biologia Vegetal, Botanica", -"MUCC c Murdoch University Culture Collection", -"MUCC c Mie University Culture Collection (Culture Collection, Laboratory of Plant Pathology)", -"MUCL c Mycotheque de l'Universite Catholique de Louvain", -"MUCPv s Museo de la Universidad Nacional del Comahue", -"MUCR s Museo de Insectos", -"MUCV s Monash University, Biological Sciences Department", -"MUDH s The Hague, Museon", -"MUFE s University of Marmara, Department of Botany", -"MUFM s Manipur University Fish Museum", -"MUFS s Department of Animal Science, Miyazaki University", -"MUGM s Museo de Ciencias Naturales, Coleccion \"Gustavo Orces\" (Ecuador)", -"MUGT s Museo de Ciencias Naturales de la Universidad de Guayaquil", -"MUH h Mirpur University of Science & Technology", -"MUHW s Marshall University, Biological Sciences Department", -"MUJ s Museo Javeriano de Historia Natural, Laboratoriao de Entomologia", -"MUL c Department of Microbiology MUL-B 250", -"MULU s Museum Ludovicae Ulricae, Zoology Institute of the University of Uppsala", -"MUM c Micoteca da Universidade do Minho", -"MUMF s Department of Life Sciences", -"MUMH s Mie University Mycological Herbarium", -"MUMZ s University of Missouri, Museum of Zoology", -"MUNC s St. John's, Memorial University of Newfoundland", -"MUNZ s Massey University", -"MUO s Stovall Museum of Science and History", -"MUP s Universidade do Porto, Museu do Historia Natural", -"MUR s Murray State University, Department of Biological Sciences", -"MURD s Murdoch University", -"MURU s Murdoch University", -"MUS s Muskingum College, Biology Department", -"MUSA s Universidad Nacional de San Agustin, Museo de Historia Natural (Peru)", -"MUSK s Muskegon Community College, Life Science Department", -"MUSM s Museo de Historia Natural de la Universidad Nacional Mayor de San Marcos en Lima", -"MUSN s Museo Universitario di Storia Naturale e della Strumentazione Scientifica", -"MUST h Al-Mustansiriya University", -"MUT c Mycotheca Universitatis Taurinensis", -"MUZ h King Abdulaziz City for Science and Technology", -"MV s University of Montana Museum", -"MVC s University of Charleston, Natural Sciences Department", -"MVDA s Ministerio de Ganaderia y Agricultura", -"MVEN s Naturhistorisch Museum", -"MVFA s Universidad de la Republica, Laboratorio de Botanica", -"MVFQ s Universidad de la Republica, Catedra de Botanica Farmaceutica", -"MVHC s Universidad de la Republica, Seccion Micologia", -"MVJB s Museo y Jardin Botanico", -"MVM s Museo Nacional de Historia Natural, Departamento de Botanica", -"MVMA s Museum of Victoria", -"MVN s Public Library", -"MVNP s Mesa Verde National Park", -"MVP s Museum of Vicotria", -"MVSC s Millersville University, Biology Department", -"MVUP s Museo de Vertebrados de la Universidad de Panama", -"MVZ s Museum of Vertebrate Zoology, University of California at Berkeley", -"MVZ:Bird s Museum of Vertebrate Zoology, University of California at Berkeley, Bird Collection", -"MVZ:Egg s Museum of Vertebrate Zoology, University of California at Berkeley, Egg Collection", -"MVZ:Herp s Museum of Vertebrate Zoology, University of California at Berkeley, Herpetology Collection", -"MVZ:Hild s Museum of Vertebrate Zoology, University of California at Berkeley, Milton Hildebrand collection", -"MVZ:Img b Museum of Vertebrate Zoology, University of California at Berkeley, Image Collection", -"MVZ:Mamm s Museum of Vertebrate Zoology, University of California at Berkeley, Mammal Collection", -"MVZ:Page b Museum of Vertebrate Zoology, University of California at Berkeley, Notebook Page Collection", -"MW s Museum Wasmann", -"MW sb Moscow State University Herbarium", -"MWC s Museum of Western Colorado", -"MWCF s Mary Washington College, Department of Biology", -"MWFB s University of California, Davis, Museum of Wildlife and Fisheries Biology", -"MWG s Moscow State University, Department of Biogeography", -"MWI s Western Illinois University, Biological Sciences Department", -"MWNH s Museum Wiesbaden, Department of Natural Science", -"MWSJ s Missouri Western State College, Biology Department", -"MWSU s Midwestern State University", -"MY s Universidad Central de Venezuela, Botanica", -"MYDC s Mianyang Institute for Drug Control", -"MYF s Universidad Central de Venezuela", -"MZ-ICACH s Instituto de Ciencias y Artes de Chiapas, Museo Zoologico (Mexico)", -"MZ s Jihomoravske muzeum Znojmo", -"MZ s Museum of the Earth, Polish Academy of Sciences", -"MZAF s Museo Zoologico dell'Accademia dei Fisiocritici", -"MZB s Museum Zoologicum Bogoriense", -"MZB:Amp s Museum Zoologicum Bogoriense, Amphibian Collection", -"MZB:Ornith s Museum Zoologicum Bogoriense, Ornithology Collection", -"MZBL s Museo de Zoologica", -"MZBS s Museo Zoologia", -"MZCP s Universidade de Coimbra", -"MZCR s Museo de Zoologia", -"MZFC s Museo de Zoologia \"Alfonso L. Herrera\"", -"MZFN s Museo Zoologico dell'Universita \"Federico II\"", -"MZGZ s Museum Zoologia del Giardino Zoologico", -"MZH s Zoolgical Museum, Finnish Museum of Natural History", -"MZKI c Microbial Culture Collection of National Institute of Chemistry", -"MZL s Musee Zoologique", -"MZLS s Musee Zoologique", -"MZLU s Lund University", -"MZN s Musee Zoologie", -"MZNA s Universidad de Navarra, Museum of Zoology", -"MZNC s Universidad Nacional de Cordoba, Museo de Zoología", -"MZP s Muzeum Ziemi Polska Akademia Nauk", -"MZPW s Polish Academy of Science, Museum of the Institute of Zoology", -"MZRF s Museo Zangheri di Storia Naturale della Romagna", -"MZRO s Museo Civico di Storia Naturale \"P. Zangheri\"", -"MZS s Universite de Strasbourg, Musee de Zoologie", -"MZSF s Universite de Strasbourg, Museum Zoologique", -"MZSP s Sao Paulo, Museu de Zoologia da Universidade de Sao Paulo", -"MZTG s Museum Zoologia", -"MZUABCS s Museo de Zoologia de la Universidad Automica de Baja California Sur", -"MZUB s Museo di Zoologia", -"MZUC s Museo de Zoologia, Universidad de Concepcion", -"MZUC s Universita di Cagliari", -"MZUCR s Universidad de Costa Rica, Museo de Zoologia", -"MZUEL s Museu de Zoologia da Universidade Estadual de Londrina", -"MZUESC s Museu de Zoologia da Universidade Estadual de Santa Cruz", -"MZUF s Museo Zoologico La Specola, Universita di Firenze", -"MZUN s Museo Zoologico di Universita degli Studi", -"MZUNAP s Museo de Zoologia de la Universidad Nacional de la Amazonia Peruana", -"MZUP s Museo Zoologia", -"MZUP s Museo Zoologico di Universita degli Studi", -"MZUR s Museo di Zoologia dell'Universita di Roma \"La Sapienza\"", -"MZUR:BAU s Museo di Zoologia dell'Universita di Roma \"La Sapienza\", Zoological collection of the Department of Biology and Biotechnology", -"MZUS s Musee de Zoologie de l'Universite de Strasbourg", -"MZUSP s Museu de Zoologia da Universidade de Sao Paulo", -"MZUT s Museo di Zoologia, Instituto di Zoologia e Anatomia Comparata Universita di Torino", -"MZUT s Museo e Instituto DI Zoologia Sistematica dell' UniversitaDI Torino", -"MZUTH s Museum of Zoology, University of Thessaloniki", -"MZUVN s Musee Zool. Univ. et Ville de Nancy", -"MZV s Muzeum i Instytut Zoologii", -"MZV s Zoological Museum Varsovite", -"MZYU s Museum of Zoology, Yunnan University", -"N s Nanjing University, Biology Department", -"NA s United States National Arboretum, USDA/ARS", -"NABG s Botanical Garden", -"NAC s Nagano Nature Conservation Research Institute", -"NAI s University of Nairobi, Botany Department", -"NAIC s National Agricultural Insect Collection", -"NAKU h Namik Kemal University", -"NAM s Facultes Universitaires Notre-Dame de la Paix", -"NAN s Nantong Teachers College, Biology Department", -"NAP s Institute of Zoology, Academia Sinica (formerly National Academy of Peiping)", -"NAP s Universita Degli Studi di Napoli Federico II, Dipartimento di Biologia Vegetale", -"NARA s National Aquatic Resources Agency", -"NARI s National Agricultural Research Institute", -"NARL s National Agricultural Research Laboratories", -"NAS s Institute of Botany, Jiangsu Province and Chinese Academy of Sciences", -"NASC b European Arabidopsis Stock Centre", -"NASC s Massachusetts College of Liberal Arts, Biology Department", -"NAT s Seale-Hayne Agricultural College", -"NATC s Northwestern State University, Biological Sciences Department", -"NAU s Nanjing Agricultural University, Department of Plant Science", -"NAUF s Northern Arizona University", -"NAUJ s Nanjing, Nanjing Agricultural University", -"NAUVM s Northern Arizona University, Museum of Vertebrates", -"NAVA s Navajo Natural Heritage Program, Navajo Department of Fish & Wildlife", -"NBAIM c National Bureau of Agriculturally Important Microorganisms", -"NBFGR s National Bureau of Fish Genetic Resources (Indian Council of Agricultural Research)", -"NBFGR:CHN s National Bureau of Fish Genetic Resources (Indian Council of Agricultural Research), Cochin Unit", -"NBG s National Botanical Institute", -"NBGB sb National Botanical Garden, Belgium", -"NBIMCC c National Bank for Industrial Microorganisms and Cell Cultures", -"NBM s New Brunswick Museum", -"NBMB s St. John's, New Brunswick Museum", -"NBME s National Butterfly Museum (Saruman Museum)", -"NBNM s National Park Service", -"NBPC s National Birds of Prey Centre", -"NBPGR b National Bureau of Plant Genetic Resources", -"NBRC c NITE Biological Resource Center", -"NBRP b National Bio-Resource Project", -"NBSB s National Biomonitoring Specimen Bank, U.S. Geological Survey", -"NBSB:Bird s National Biomonitoring Specimen Bank, U.S. Geological Survey, bird collection", -"NBSB:Mamm s National Biomonitoring Specimen Bank, U.S. Geological Survey, mammal tissue collection", -"NBSI s Biologische Station Neusiedler See", -"NBV s Koninklijke Nederlandse Botanische Vereniging", -"NBY s Newbury District Museum", -"NBYC s Newberry College, Department of Biology", -"NCAIM c National Collection of Agricultural and Industrial Microorganisms", -"NCAM c National Collection of Agricultural Microorganisms", -"NCAS s Rutgers University, Biological Sciences Department", -"NCATG s North Carolina A & T State University, Biology Department", -"NCAW s North-West College of Agriculture", -"NCB c National Culture Bank", -"NCBS s Yale University, Connecticut Botanical Society", -"NCC c Nantes Culture Collection", -"NCC s Sonoma State University, Biology Department", -"NCCB c The Netherlands Culture Collection of Bacteria", -"NCCBH s Nature Conservancy Council, Balloch", -"NCCE s Nature Conservancy Council, Edinburgh", -"NCCH s Nature Conservancy Council", -"NCCN s Nature Conservancy Council, Norwich", -"NCCP c National Culture Collection for Pathogens", -"NCCP c National Culture Collection of Pakistan", -"NCCPF c National Culture Collection of Pathogenic Fungi", -"NCDC c National Collection of Dairy Cultures", -"NCE s University of Newcastle upon Tyne, School of Biological Sciences", -"NCFB c National Collection of Food Bacteria", -"NCH s Norwich Botanical Society", -"NCHU s National Chung Hsing University", -"NCHU:ZOOL s National Chung Hsing University, Department of Life Science", -"NCIM c National Collection of Industrial Microorganisms", -"NCIMB c National Collections of Industrial Food and Marine Bacteria (incorporating the NCFB)", -"NCIP s Pusat Penelitian dan Pengembangan Oseanologi", -"NCKU s National Cheng-Kung University, Biology Department", -"NCLN s New College", -"NCMA s Raleigh, North Carolina Department of Environmental Health and Natural Resources", -"NCMH c The North Carolina Memorial Hostital", -"NCMK s Norwich Castle Museum", -"NCP h National Collection of Passiflora", -"NCPF c National Collection of Pathogenic Fungi", -"NCPPB c National Collection of Plant Pathogenic Bacteria", -"NCPV c National Collection of Pathogenic Viruses", -"NCS s North Carolina State University", -"NCSC c National Center of Streptococcus Collection, Department of Microbiology, Faculty of Medical Science", -"NCSC s North Carolina State University, Botany Department", -"NCSLG h North Carolina State University", -"NCSM s North Carolina Museum of Natural Sciences", -"NCSU s North Carolina State University Collections", -"NCTC c National Collection of Type Cultures", -"NCU s University of North Carolina, North Carolina Botanical Garden", -"NCUT s Nicolaus Copernicus University", -"NCWRF c National Collection of Wood Rotting Fungi", -"NCY s Conservatoire et Jardins Botaniques de Nancy", -"NCYC c National Collection of Yeast Cultures", -"ND s University of Notre Dame, Department of Biological Sciences", -"NDA s North Dakota State University, Animal and Range Sciences Department", -"NDAA s Orange, New South Wales Department of Agriculture", -"NDAT s Department of Agriculture, Tunisia", -"NDFC s Newfoundland Department of Forestry", -"NDG s University of Notre Dame, Department of Biological Sciences", -"NDO s Division of Forest Research, Forest Department", -"NDSR s National Drosophila Species Resource Center", -"NDSU s North Dakota State University", -"NDTC s Ningde Teachers College, Biology Department", -"NE s University of New England", -"NEB s University of Nebraska State Museum", -"NEBC s Harvard University", -"NEBK h University of Nebraska at Kearney", -"NEFI s Northeastern Forestry University, Forestry Department", -"NEM c Faculte de Medecine Necker-Enfants Malades", -"NEMO s Truman State University", -"NEMSU s Truman State University", -"NEMU s Newark Museum", -"NENU s Northeast Normal University, Biology Department", -"NEPCC c North East Pacific Culture Collection", -"NESH s University of Nevada", -"NEU s Universite de Neuchatel, Laboratoire de botanique evolutive", -"NEUN h Near East University", -"NEW s University of Newcastle", -"NEWHM s Hancock Museum", -"NEZ s Museum, Zoology Department, University of New England", -"NF s Nanjing Forestry University, Forest Resources and Environment", -"NFCCI c National Fungal Culture Collection of India", -"NFCCP c National Fungal Culture Collection of Pakistan", -"NFLD s Memorial University of Newfoundland, Biology Department", -"NFM s Newfoundland Museum", -"NFO s Niagara Parks Botanical Gardens and School of Horticulture", -"NFRC s Northern Forest Research Centre", -"NFRDI c National Fisheries Research & Development Institute", -"NFRI c Norwegian Forest Research Institute", -"NFRN s Canadian Forest Service, NRCan", -"NGBB h Nezahat Gokyigit Botanik Bahcesi", -"NGCPR h Naoroji Godrej Centre for Plant Research", -"NGI s Nanjing Geographical Institute", -"NGM s Bromley House Library", -"NGMC s National Geological Museum of China", -"NGR c Plant Pathology", -"NH s South African National Biodiversity Institute", -"NHA s University of New Hampshire, Plant Biology Department", -"NHCP h National Bureau of Plant Genetic Resources", -"NHES s Connecticut Agricultural Experiment Station, Entomology Department", -"NHG s Naturhistorische Gesellschaft e. V., Abteilung Botanik", -"NHI h Natural History Institute", -"NHIC s Ontario Ministry of Natural Resources", -"NHL c National Institute of Hygienic Sciences", -"NHM s Naturhistorisches Museum, Bern", -"NHM s University of Nottingham, Botany Department", -"NHMA s Natural History Museum, Denmark", -"NHMB s Naturhistorisches Museum, Basel", -"NHMB s Natural History Museum Bucharest", -"NHMBe s Naturhistorisches Museum Bern", -"NHMC s Natural History Museum of Crete, University of Crete, Department of Botany", -"NHMC s Natural History Museum, Rangoon", -"NHME s Natuurhistorisch Museum", -"NHMF h Natural History Museum Fribourg", -"NHMG s Natural History Museum of Guangxi", -"NHMG s Goteborgs Naturhistoriska Museet", -"NHMK s Landesmuseum fuer Karnten", -"NHML s Natural History Museum, Tripoli", -"NHMM s Natuurhistorische Museum Maastricht", -"NHMM-LS s Naturhistorisches Museum/Landessammlung fuer Naturkunde Rheinland-Pfalz", -"NHMN s Nottingham Natural History Museum (Wollaton Hall)", -"NHMR s Natural History Museum Rijeka", -"NHMR s Natural History Museum, Reykjavik", -"NHMR s Natuurhistorisch Museum", -"NHMS h Natural History Museum Split", -"NHMTU s Natural History Museum, Tribhuvan University", -"NHMUK sb Natural History Museum, London", -"NHMUK s Natural History Museum, Karachi", -"NHMW s Naturhistorisches Museum, Wien", -"NHNC s La Chaux-de-Fons", -"NHNE s New England College, Biology Department", -"NHR h Institute of Scientific and Technological Research (IRST)", -"NHRI s Islandic Museum of Natural History", -"NHRM s Naturhistoriska Rijkmuseet", -"NHRS s Swedish Museum of Natural History, Entomology Collections", -"NHSD s Natural History Society of Dublin", -"NHST s Museum of Natural History, Reunion", -"NHT s Tropical Pesticides Research Institute", -"NHV s Institut fuer Landwirtschaftliche Botanik", -"NI c Nagao Institute", -"NI s Slovenska pol'nohospodarska Univerzita, Katedra botaniky", -"NIAB b National Institute of Agricultural Botany", -"NIAES c National Institute for Agro-Environmental Sciences", -"NIAH c National Institute of Animal Health", -"NIAID c National Institute of Allergy and Infectious Diseases", -"NIAS sb National Institute of Agrobiological Sciences", -"NIBH c National Institute of Bioscience and Human-Technology", -"NIBR scb National Institute of Biological Resources", -"NIBSC b National Institute for Biological Standards and Control", -"NICC s National Insect Collection", -"NICD s Malaria Research Center", -"NICE s Museum d'Histoire Naturelle", -"NICH s Hattori Botanical Laboratory", -"NIES c Microbial Culture Collection", -"NIFI s National Inland Fisheries Institute", -"NIFRS s National Research Institute of Fisheries Science", -"NIG s Nanjing Geographical Institute", -"NIGL s Nanjing Institute of Geography and Limnology", -"NIGP s Naking Institute of Geology and Palaeontology", -"NIHHS h National Institute of Horticultural and Herbal Science, RDA", -"NIM h Museum d'histoire naturelle de Nimes", -"NIMM h National Institute of Medicinal Materials", -"NINF s Newfoundland Insectarium", -"NIO s National Institute of Oceanography", -"NIOCC c National Institute of Oceanography Culture Collection", -"NIPH c National Institute of Public Health, Collection A. Nemec", -"NIPR s National Institute of Polar Research, Biological Data Department", -"NIT s Jardim Botanico de Niteroi", -"NIVA c Culture Collection of Algae (NIVA)", -"NIWA s National Institute of Water and Atmospheric Research", -"NJ s Njala University College", -"NJM s Okresni vlastivedne muzeum", -"NJM c Nippon Veterinary and Animal Science University", -"NJNU s Nanjing Normal University, Biology Department", -"NJSM s New Jersey State Museum", -"NKA c Nationales Konsiliarlabor fur Adenoviren", -"NKMC s National Kweiyang Medical College", -"NKME s Naturkundemuseum Erfurt", -"NKMU s Nankai University Museum", -"NKU s Nankai University, Biology Department", -"NKUM s Nankai University", -"NLEC s Neal L. Evenhuis", -"NLH s Agricultural University of Norway, Department of Biology and Nature Conservation", -"NLHD s Niedersachsisches Landesmuseum", -"NLPS s Nottingham Literary and Philosophical Society", -"NLSN s Notre Dame University, Biological Sciences Department", -"NLU s University of Louisiana at Monroe, Museum of Natural History", -"NLUH s University of the Philippines College Baguio", -"NM s Northern Michigan University, Biology Department", -"NMAC s Inner Mongolia Agricultural University, Department of Pratacultural Science", -"NMAG s Naturhistorisches Museum, Augsburg", -"NMB s Naturhistorishes Museum", -"NMB s National Museum, Bloemfontein", -"NMB:P s National Museum, Bloemfontein, The Protozoan collection of the National Museum", -"NMBA s National Museum, Buenos Aires", -"NMBA s Naturhistorisches Museum der Benediktiner-Abtei", -"NMBA s Naturhistorisches Museum, Basel", -"NMBE s Naturhistorisches Museum der Burgergemeinde Bern", -"NMBO s National Museum, Bloemfontein", -"NMBT h Natuurmuseum Brabant", -"NMBZ s Natural History Museum of Zimbabwe", -"NMC s New Mexico State University, Department of Biology", -"NMC s Canadian Museum of Nature", -"NMCC c North Maharashtra Microbial Culture Collection Centre", -"NMCDC s Inner Mongolia Center for Endemic Disease Control and Research", -"NMCI s Noto Marine Center Ishikawa Prefecture", -"NMCI:AR s Noto Marine Center Ishikawa Prefecture, Arthropoda collection", -"NMCI:EC s Noto Marine Center Ishikawa Prefecture, Echinodermata", -"NMCI:IV s Noto Marine Center Ishikawa Prefecture, Invertebrata", -"NMCI:MO s Noto Marine Center Ishikawa Prefecture, Mollusca collection", -"NMCI:P s Noto Marine Center Ishikawa Prefecture, Pisces and Coelenterata", -"NMCI:S s Noto Marine Center Ishikawa Prefecture, Sea weed", -"NMCL s Naturkunde-Museum", -"NMCR s New Mexico State University, Department of Animal and Range Sciences", -"NME s Sammlung des Naturkundemseum Erfurt", -"NMED s New Mexico Environment Department", -"NMEG s Naturkundesmuseum", -"NMFC s Inner Mongolia Forestry College, Desert Control and Utilization Department", -"NMFSH s National Marine Fisheries Service", -"NMG s Naturhistoriska Riksmuseet", -"NMI s National Museum of Ireland", -"NMI c Bacteria collection of National Institute of Public Health, National Medicines Institute, Poland", -"NMID s National Museum of Ireland", -"NMK s National Museums of Kenya", -"NMKE s National Museum of Kenya", -"NMKL s National Museum of Malaysia", -"NML c National Microbiology Laboratory, Public Health Agency of Canada", -"NMLS s Natur-Museum Luzern", -"NMLU s Natur-Museum Luzern, Botany Department", -"NMMA s Nantucket Maria Mitchell Association, Natural Sciences Department", -"NMMBP s National Museum of Marine Biology and Aquarium", -"NMMH s North Manchurian Museum", -"NMML s National Marine Mammal Laboratory", -"NMMNH s New Mexico Museum of Natural History and Science", -"NMMNH:Mamm s New Mexico Museum of Natural History and Science, Mammal collection", -"NMN s Northamptonshire Natural History Society", -"NMND s National Museum of Natural History, New Delhi", -"NMNH s National Museum of Natural History, New Delhi", -"NMNHI s National Museum of Natural History, New Delhi", -"NMNK s National Museum of Nepal", -"NMNL h Natuurmuseum Nijmegen e.o.", -"NMNS s National Museum of Natural Science", -"NMNW s National Museum of Namibia", -"NMNZ s National Museum of New Zealand", -"NMNZ:AI s National Museum of New Zealand, Insects", -"NMNZ:AM s National Museum of New Zealand, Amphibians", -"NMNZ:AS s National Museum of New Zealand, Spiders", -"NMNZ:CR s National Museum of New Zealand, Crustacea", -"NMNZ:M s National Museum of New Zealand, Molluscs", -"NMNZ:MM s National Museum of New Zealand, Marine Mammals", -"NMNZ:OR s National Museum of New Zealand, Birds", -"NMNZ:P s National Museum of New Zealand, Fish", -"NMNZ:RE s National Museum of New Zealand, Reptiles", -"NMNZ:S s National Museum of New Zealand, Fossil Vertebrates", -"NMNZ:TS s National Museum of New Zealand, Tissue Collection", -"NMNZ:TSA s National Museum of New Zealand, Tissue Collection", -"NMP s National Museum (Prague)", -"NMP s Natal Museum", -"NMPC s National Museum Prague", -"NMPC:ENT s National Museum Prague, Entomology Collection", -"NMPG s Zhejiang Institute of Traditional Chinese Medicine", -"NMPG s Museum der Natur-Gotha", -"NMPI s Division of Plant Industry", -"NMQR s National Museum, Bloemfontein", -"NMR h Semyung University", -"NMRC c Naval Medical Research Center", -"NMRC:RDD c Naval Medical Research Center, Rickettsial Diseases Division", -"NMS s National Museums of Scotland", -"NMS-G s National Museums of Scotland - Geology & Zoology", -"NMSA s Natal Museum", -"NMSL s National Museum of Sri Lanka", -"NMSR s Naturhistorisches Museum im Thueringer Landes museum Heidecksburg zu Rudolstadt", -"NMSU s Northwest Missouri State University, Biology Department", -"NMSU s New Mexico State University", -"NMTC s Inner Mongolia Normal University, Biology Department", -"NMTT s National Museum and Art Gallery, Port-of-Spain", -"NMV s Museum Victoria", -"NMV:A s Museum Victoria, Ichthyology", -"NMV:AV s Museum Victoria, Entomology - Australian Voucher Specimens", -"NMV:B s Museum Victoria, Ornithology", -"NMV:BE s Museum Victoria, Ornithology - Eggs", -"NMV:BUP s Museum Victoria, Buprestidae", -"NMV:C s Museum Victoria, Mammology", -"NMV:COL s Museum Victoria, Coleoptera", -"NMV:D s Museum Victoria, Herpetology", -"NMV:DIP s Museum Victoria, Diptera", -"NMV:DTB s Museum Victoria, Ornithology - Donald Thompson Collection", -"NMV:DTD s Museum Victoria, Herpetology - Donald Thompson Collection", -"NMV:F s Museum Victoria, Invertebrates Collection", -"NMV:G b Museum Victoria, DNA Products", -"NMV:H s Museum Victoria, Hygrobatidae", -"NMV:HEM s Museum Victoria, Hemiptera", -"NMV:HET s Museum Victoria, Heteroptera", -"NMV:HLW s Museum Victoria, Ornithology - H.L. White Collection", -"NMV:HYM s Museum Victoria, Hymenoptera", -"NMV:ISO s Museum Victoria, Isoptera", -"NMV:J s Museum Victoria, Crustacea", -"NMV:K s Museum Victoria, Arachnology", -"NMV:LEP s Museum Victoria, Lepidoptera", -"NMV:MEC s Museum Victoria, Mecoptera", -"NMV:MEG s Museum Victoria, Megaloptera", -"NMV:NEU s Museum Victoria, Neuroptera", -"NMV:NOH s Museum Victoria, Northofagus Project", -"NMV:ODO s Museum Victoria, Odonata", -"NMV:P s Museum Victoria, Paleontology & Paleobotany", -"NMV:T s Museum Victoria, Entomlogy Type Collection", -"NMV:TRI s Museum Victoria, Trichoptera", -"NMV:Z s Museum Victoria, Tissue Collection", -"NMV s Nakagawa Museum at Nakagawa-cho", -"NMW s Naturhistorisches Museum, Wien", -"NMW s National Museums & Galleries of Wales, Department of Biodiversity and Systematic Biology", -"NMWC s National Museum of Wales", -"NMWZ s National Museum of Wales", -"NMZB s National Museum of Zimbabwe", -"NMZL s National Museum of Zambia", -"NNA s Nanning Arboretum", -"NNHMK s National Natural History Museum of the Ukraine", -"NNKN s Noordbrabants Natuurmuseum", -"NNM s Nationaal Natuurhistroisch Museum", -"NNMN s Nationaal Natuurhistorisch Museum Naturalis", -"NNSU s N. I. Lobachevsky Nizhni Novgorod State University, Department of Botany", -"NO s Tulane University, Department of Ecology and Evolutionary Biology", -"NOAA s National Oceanic and Atmospeheric Administration", -"NOAA:MarFor s National Oceanic and Atmospeheric Administration, Marine Forensics", -"NOAS s New Orleans Academy of Science", -"NOCC s National Orchid Conservation Center", -"NODCAR c marwa mokhtar Abd Rabo", -"NoF c The Fungus Culture Collection of the Northern Forestry Centre", -"NOI s Nanhai Oceanographic Institute", -"NOLS s University of New Orleans, Biological Sciences Department", -"NOSU s Northeastern State University, Natural Sciences and Mathematics Department", -"NOT s Nottingham City Natural History Museum", -"NOTM s University of Nottingham, Manuscript Department", -"NOU s Institut de Recherche pour le Developpement, Botany and Applied Ecology Department", -"NPA s Nanjing Institute of Geology and Paleontology, Academia Sinica", -"NPB s Natal Parks, Game, and Fish Preservation Board, Research Section", -"NPC s National Pusa Collection", -"NPIB s Northwest Plateau Institute of Biology", -"NPP c N.P.P", -"NPRI s Seoul National University", -"NPS s United States National Park Service", -"NPSC s Northern Prairie Science Center", -"NPT s Newport Museum and Art Gallery", -"NPWRC s Northern Prairie Research Center", -"NR h Institute of Forest Ecology Slovak Academy of Sciences", -"NRC c Division of Biological Sciences, National Research Council of Canada", -"NRC s National Research Centre", -"NRCC s National Research Council of Canada", -"NRCS c National Reference Center for Streptococci in Aachen", -"NRIBAS s National Research Institute of Biology, Academia Sinica", -"NRIC c NODAI Research Institute Culture Collection", -"NRL c Neisseria Reference Laboratory", -"NRM s Swedish Museum of Natural History", -"NRN s Nairn Literary Society Library, Public Library", -"NRNZ s Northland Regional Museum", -"NRPSU c Department of Agro-industry, Faculty of Natural Resources", -"NRRL c Agricultural Research Service Culture Collection", -"NRRL:MOLD sc Agricultural Research Service Culture Collection, ", -"NRRL:PROK sc Agricultural Research Service Culture Collection, ", -"NRRL:YEAST sc Agricultural Research Service Culture Collection, ", -"NRS s Naturhistoriska Riksmuseet", -"NRWC s N. R. Whitney Collection", -"NRZM c German Reference Center for Meningococci", -"NS s Central Siberian Botanical Garden", -"NSAC s Nova Scotia Agricultural College, Department of Environmental Sciences", -"NSCA s North Scotland College of Agriculture", -"NSCNFB c Novi Sad Collection of Nitrogen Fixing Bacteria", -"NSCPM c National State Collection of Pathogenic Microorganisms", -"NSDA s Nevada Division of Agriculture", -"NSK s Siberian Central Botanical Garden, Laboratory for Plant Systematics and Floristic Genesis", -"NSM s Nova Scotia Museum of Natural History", -"NSM s Sun Yat-Sen Tomb and Memorial Park Commission", -"NSM s NSM-PV, National Science Museum", -"NSMC s Nova Scotia Museum", -"NSMC s Nevada State Museum", -"NSMHS s Nevada State Museum and Historical Society", -"NSMK s National Science Museum", -"NSMT s National Museum of Nature and Science, Tokyo", -"NSMW s Naturwissenschftlich Sammlung, Museum Wiesbaden", -"NSNR s Nova Scotia Department of Natural Resources", -"NSPM s Nova Scotia Museum of Natural History", -"NSRF s Nova Scotia Research Foundation", -"NSS s University of Liverpool Botanic Gardens", -"NSU s Northeastern State University, Biological Collections", -"NSUL s Northwestern State University of Louisiana", -"NSW s Royal Botanic Gardens", -"NSWA s New South Wales Department of Agriculture", -"NSWF s State Forests of New South Wales", -"NSWGS s Geological Survey of New South Wales", -"NSYU s National Sun Yat-sen University", -"NT s Department of Natural Resources, Environment and the Arts", -"NTCCI c Culture Collection, Microbiology and Cell Biology Laboratory", -"NTDPIF s Northern Territory Department of Primary Industry and Fisheries", -"NTLN s County Record Office, County Archives Department", -"NTM s Museum and Art Gallery of the Northern Territory", -"NTM s Museum d'Histoire Naturelle de Nantes", -"NTN s Central Museum and Art Gallery", -"NTNU s National Taiwan Normal University", -"NTNU-VM s Norwegian University of Science and Technology, Museum of Natural History and Archaeology", -"NTOU sc Institute of Marine Biology, National Taiwan Ocean University", -"NTS s Nevada Operations Office, U.S. Department of Energy", -"NTSC s University of North Texas, Biological Sciences Department", -"NTUC s National Taiwan University", -"NTUF s National Taiwan University, Forestry Department", -"NTUM s National Taiwan University", -"NTUMA s National Taiwan University", -"NU c Department of Microbiology, Faculty of Science", -"NU s University of Natal, School of Botany and Zoology", -"NUA c Department of Microbiology, National University of Athens", -"NUM s Nagoya University", -"NUOL s National University of Laos", -"NUSDM c Department of Microbiology, National University of Singapore", -"NUSMBS s Niigata University, Sado Marine Biological Station", -"NUV s Norwich University, Biology and Life Sciences Department", -"NUVC s Northeastern University, Vertebrate Collection", -"NVDA s Nevada State Department of Agriculture", -"NVMC s Nevada State Museum", -"NVRL s Naturforschende Verein in Riga", -"NVRW s Naturhistorisches Verein der Preussische Rheinland und Westfalens", -"NWAU s North-West Agricultural University", -"NWC s University of Northern Iowa, Nixon Wilson Collection", -"NWC b National Willows Collection", -"NWFC sb Northwest University of Agriculture Forestry Science & Technology", -"NWH s Norfolk Museums and Archaeology Service, Natural History Department", -"NWK s Newark District Council Museum", -"NWMSU s Northwest Missouri State University", -"NWOSU s Northwestern Oklahoma State University, Biology Department", -"NWSW s Naturwissenschaftliche Sammlungen der Stadt Winterthur", -"NWT s Harper Adams Agricultural College", -"NWTC s Northwest Normal University", -"NWU s Northwestern University, Botany Department", -"NWUB s Northwest Normal University, Biology Department", -"NX s Universidade do Estado de Mato Grosso - Campus de Nova Xavantina, Departamento de Ciencias Biologicas", -"NXAC s Ningxia Agricultural College", -"NXF s Ningxia Academy of Agriculture and Forestry Sciences", -"NY s New York Botanical Garden", -"NYA s Nanyue Arboretum", -"NYAS s Silvicultural Research Station", -"NYBG s New York Botanical Garden", -"NYS s New York State Museum", -"NYSM s New York State Museum", -"NYZS s New York Zoological Society", -"NZAC s New Zealand Arthropod Collection", -"NZCS s University, National Zoological Collection of Suriname", -"NZFRI s New Zealand Forest Research Institute Limited", -"NZFS c Forest Research Culture Collection", -"NZG s National Zoological Gardens of South Africa", -"NZOI s New Zealand Oceanographic Institute", -"NZRD c New Zealand Reference Culture Collection of Microorganisms, Dairy Section", -"NZRM c New Zealand Reference Culture Collection, Medical Section", -"NZRP c New Zealand Reference Culture Collection and Soil Section", -"NZSI s Zoological Survey of India, National Zoological Collection", -"O s Botanical Museum, Natural History Museum, Oslo", -"OAC s OAC Herbarium, Biodiversity Institute of Ontario", -"OAKL s Oakland Museum of California, Natural Sciences Department", -"OAMB s Open Air Museum of Ethnography and Natural Sciences", -"OAX s Instituto Politecnico Nacional (CIIDIR-Oax., I.P.N.)", -"OAXM s Centro Interdisciplinario de Estudios, Coleccion Mastozoologica (Mexico)", -"OB h Station Umwelt- und Natur Oberhausen", -"OBG s The Oman Botanic Garden", -"OBI s California Polytechnic State University, Biological Sciences Department", -"OBPF s Planting Fields Arboretum State Historic Park", -"OC s Oberlin College, Biology Department", -"OCHA s Ochanomizu University", -"OCLA s University of Science and Arts of Oklahoma", -"OCM c Oregon Collection of Methanogens", -"OCNF s Ochoco National Forest", -"OCSA s Veterinary Research Institute", -"OCU h Oklahoma City University", -"ODAC s Oregon Department of Agriculture", -"ODU s Old Dominion University, Department of Biological Sciences", -"OFC s Orielton Field Centre", -"OGDF s Forest Service Region 4, USDA", -"OGL b Ocean Genome Legacy", -"OGL:OGR b Ocean Genome Legacy, Ocean Genome Resource", -"OGU s Odesskij Gosudarstvennij Universitet", -"OH s Agricultural Museum of Praha", -"OHBR s Ontario Hydro", -"OHHI h Orel State University", -"OHM s Oldham Microscopical and Natural History Society", -"OHN s Regionherbariet i Oskarshamn", -"OHSC s Ohio Historical Society", -"OKA s Oksky State Biosphere Reserve", -"OKAY s Okayama University of Science, Department of Biosphere-Geosphere System Science", -"OKL s University of Oklahoma, Botany and Microbiology Department/ Oklahoma Biological Survey", -"OKLA s Oklahoma State University, Botany Department", -"OL s Palacky University, Botany Department", -"OLAN s Ministerio de Recursos Naturales", -"OLD s Universitat Oldenburg", -"OLDM s Libraries, Art Galleries and Museums", -"OLDS s Olds College, Horticulture Department", -"OLE s Oundle School, Biology Department", -"OLM s Vlastivedne muzeum v Olomouci", -"OLML s Oberoesterreichisches Landesmuseum", -"OLP s Univerzity Palackeho, Katedra biologie", -"OLS h University of Warmia and Mazury", -"OLTC s Teachers Training College, Botany Department", -"OLV s Olivet College, Biology Department", -"OLYM h Olympic National Park", -"OM s Otago Museum", -"OMA s University of Nebraska Omaha, Biology Department", -"OMC s Catalogues in Otago Museum", -"OMC s Mills College, Biology Department", -"OMJ s Okresni muzeum a galerie", -"OMKH s Oblastni muzeum Kutna Hora", -"OMNH s Osaka Museum of Natural History", -"OMNH s Oklahoma Museum of Natural History", -"OMNHN s The Sam Noble Oklahoma State Museum of Natural History", -"OMNHO s Osaka Museum of Natural History", -"OMNO s Oklahoma Museum of Natural History", -"OMNZ s Otago Museum", -"OMP s Polabske muzeum v Podebradech", -"OMPB s Osservatorio per le Malattie delle Piante per la Regione Emilia-Romagna", -"OMPG s Osservatorio per le Malattie delle Piante per le Province di Genova e La Spezia", -"OMPS s Osservatorio per le Malattie delle Piante per la Sardegna", -"OMSK h Omsk Pedagogical Univeristy", -"OMSKM s Omsk State Agrarian University, Department of Forestry and Plant Conservation", -"OMUB s Ondokuz Mayis University, Biology Department", -"ON s Oman Natural History Museum", -"ONNC s Office de la Recherche Scientifique et Technique d'Outre-Mer", -"ONP s Olympic National Park", -"ONPC s Olympic National Park", -"OOM s Kameyama Botanical Garden", -"OP s Silesian Museum", -"OPANM s Otdel Paleontologii i Biostratigrafii Akademii Nauk Moldovkoi Republiki", -"OPM s Okinawa Prefectual Museum", -"ORE s University of Oregon, Biology Department", -"OREB s Karolinska Hoegre Allmaenna Laeroverket", -"ORI s Ocean Research Institute", -"ORIS s Institute of Steppe of the Ural branch of Russian Academy of Sciences", -"ORIT s University of Tokyo", -"ORM s Musee des Sciences Naturelles, Departement de Botanique", -"ORS c Culture Collection of the Laboratory of Soil Microbiology, ORSTOM", -"ORSAY sb Universite Paris-Sud - Parc Botanique de Launay", -"ORSC s Office de la Recherche Scientifique et Technique d'Outre-Mer", -"ORST s Office de la Recherche Scientifique et Technique d'Outre-Mer", -"ORSTOM s Office de la Recherche scientifique et Technique Outre-mer", -"ORT s Instituto Canario de Investigaciones Agrarias (ICIA)", -"ORTN s Orton Hall", -"ORU s Oral Roberts University, Biology Department", -"OS s Ohio State University", -"OS s Oregon State University", -"OSA s Osaka Museum of Natural History", -"OSAC s Oregon State Arthropod Collection", -"OSAL s Ohio State University Acarology Laboratory", -"OSB s Society of Botanists", -"OSBU s Universitat Osnabruck, Spezielle Botanik", -"OSC s Oregon State University, Botany and Plant Pathology Department", -"OSEC s K.C Emerson Museum", -"OSH s University of Wisconsin Oshkosh, Biology and Microbiology Department", -"OSI s Ordnance Survey of Ireland", -"OSM s Ostravske muzeum", -"OSM s Ohio State University Museum", -"OSMC s St. Martin's College, Biology Department", -"OSN s Museum am Schoelerberg, Natur und Umwelt", -"OSTR h University of Ostrava", -"OSU s Ohio State University", -"OSU s Oklahoma State University, Collection of Vertebrates", -"OSUC s Oregon State University", -"OSUF s Oregon State University, Department of Wood Science and Engineering", -"OSUFW s Oregon State University, Department of Fisheries and Wildlife Mammal Collection", -"OSUMZ s Ohio State University, Museum of Biological Diversity", -"OSUO s Oregon State University, School of Oceanography", -"OSUS s Oklahoma State University", -"OSW h State University of New York at Oswego", -"OSWY s Oswestry Museum", -"OTA s University of Otago, Botany Department", -"OTF s Canadian Forest Service", -"OTM s Otago Museum", -"OTM s Old Trail Museum", -"OTSC s Organization for Tropical Studies", -"OTT s University of Ottawa, Biology Department", -"OU s Fossil Catalgoue in the Geology Museum", -"OUA s Universite de Ouagadougou", -"OULU s University of Oulu, Biology Department", -"OUM s Oxford University Museum of Natural History", -"OUPR s Universidade Federal de Ouro Preto, Campus Universitario", -"OUSM s Oklahoma University Stovall Museum", -"OUT c Department of Biotechnology", -"OUVC s Ohio University Vertebrate Collection", -"OVMB s Okresni vlastivedne muzeum", -"OWU s Ohio Wesleyan University, Botany-Microbiology Department", -"OXD s Wadham College", -"OXF s University of Oxford, Department of Plant Sciences", -"OXM s Magdalen College Library", -"P s Herbier National de Paris", -"PA h Universidade Federal do Oeste do Para", -"PAC s Pennsylvania State University, Biology Department", -"PACA s Instituto Anchietano de Pesquisas/UNISINOS", -"PACMA s Pennsylvania State University, Biology Department", -"PAD s Universita degli Studi di Padova, Centro Interdipartimentale Musei Scientifici", -"PADA s Pennsylvania Department of Agriculture", -"PAE s Stiftung Herbarium Paul Aellen, Universitat Basel", -"PAL s Universita degli Studi di Palermo, Dipartimento de Scienze Botaniche", -"PALEON s Wyoming Dinosaur International Society", -"PAM s Pennsylvania Department of Agriculture", -"PAMC c Polar and Alpine Microbial Collection", -"PAMG s Empresa de Pesquisa Agropecuaria de Minas Gerais (EPAMIG), Departamento de Pesquisa", -"PAMP s Universidad de Navarra, Departamento de Botanica", -"PAMUH h Pamukkale University", -"PAN s Panjab University, Botany Department", -"PAP s Musee de Tahiti et des Iles", -"PAR s Museo de Ciencias Naturales y Antropologicas Prof. Antonio Serrano, Departamento de Botanica", -"PARMA s Universita degli Studi di Parma", -"PAS s Java Sugar Experimental Station", -"PASA s Pasadena City College, Life Sciences Department", -"PASG s Paleontological Section of the Georgian Academy of Sciences", -"PASM s Palomar College, Life Sciences Department", -"PASSM s Peabody Academy of Science", -"PAT s Museum National d'Histoire Naturelle", -"PAUH s University of Texas-Pan American, Biology Department", -"PAUMC s Pan American University, Mammal Collection", -"PAUP s Punjab Agricultural University", -"PAV s Universita di Pavia, Dipartimento de Ecologia del Territorio", -"PAY s Paisley Philosophical Institute", -"PBB h Research Center for the Conservation of Natural Resources University and Phu An Botanic Gardens", -"PBC c Pacific Bacterial Collection", -"PBF c Perum Bio Farma", -"PBH s Peterborough City Museum", -"PBL s Botanical Survey of India, Andaman & Nicobar Circle", -"PBM s Mahidol University, Department of Pharmaceutical Botany", -"PBP s Patagonia Botanical Park", -"PBS s Chambers Institute, Tweeddale Museum", -"PBZT s Parc Botanique et Zoologique de Tsimbazaza", -"PC s Museum National d'Histoire Naturelle", -"PCC c Pasteur Culture Collection of Cyanobacteria", -"PCE h Hugh Nicholson and Tony Abbott Herbarium", -"PCH s Prestwich and Pilkington Botanical Society", -"PCM s Presidency College, Botany Department", -"PCM c Polish Collection of Microorganisms", -"PCMB b The Pacific Center for Molecular Biodiversity", -"PCNZ s Lincoln Plant Health Station", -"PCU s Museum National d'Histoire Naturelle", -"PCU c Department of Microbiology, Faculty of Pharmaceutical Sciences", -"PD c Dutch Plant Protection Service, Culture Collection of Plant Pathogenic Bacteria", -"PDA s Royal Botanic Gardens, Department of Agriculture", -"PDBK b Plant DNA Bank in Korea", -"PDD s New Zealand Fungal and Plant Disease Herbarium", -"PDTFAU s Paleoantropoloji Dil ve Tarih Cografya Facueltesi", -"PE s Institute of Botany, Chinese Academy of Sciences", -"PECA s Pratt Education Center and Aquarium", -"PECS s Janus Pannonius Museum, Natural History Department", -"PEFO s Petrified Forest", -"PEI cb Paul-Ehrlich-Institut", -"PEI s Agriculture and Agri-Food Canada", -"PEL sc Universidade Federal de Pelotas, Departamento de Botanica", -"PEL:LIPP c Universidade Federal de Pelotas, Departamento de Botanica, Laboratory Plant-Pathogen Interaction", -"PEM s Beijing Medical University, Botany Department", -"PEM s Port Elizabeth Museum", -"PEN s Penrith Museum", -"PENN s University of Pennsylvania Herbarium", -"PER h City Museum", -"PERM s University of Perm, Botany Department", -"PERTH s Western Australian Herbarium", -"PERU s Universita di Perugia, Dipartimento di Biologia Vegetale", -"PES s University of Peshawar, Natural Drug Division", -"PESA s Centro Ricerche Floristiche Marche", -"PET s National University of Peking Teachers' College", -"PEU s University of Port Elizabeth, Botany Department", -"PEUFR s Universidade Federal Rural de Pernambuco, Departamento de Biologia", -"PEY s Peking University, Biology Department", -"PFC s Pfeiffer University, Biology Department", -"PFCA s Pacific Forestry Centre Arthropod Reference Collection", -"PFES s Petawawa National Forestry Institute, Canadian Forest Service", -"PFI s Percy FitzPatrick Institute of African Ornithology", -"PFRA s Tree Nursery", -"PFRS s Pacific Southwest Forest and Range Experiment Station", -"PFSS s Petrified Forest National Park", -"PG h Plant Gateway", -"PGC c Peterhof Genetic Collection of Microalgae", -"PGFA s Pyatigorsk State Pharmaceutical Academy, Botany Department", -"PGL s Preussiche Geologische Landesanstalt", -"PGM s Pacific Grove Museum of Natural History", -"PGMNH s Pacific Grove Museum of Natural History", -"PGR c Plant Gene Resources of Canada national and international base and active collections", -"PGRC b Plant Gene Resources of Canada", -"PGRC:CN b Plant Gene Resources of Canada, Canadian National Plant Germplasm System", -"PGSC c Pseudomonas Genetic Stock Center", -"PH s Academy of Natural Sciences, Botany Department", -"PHA s Pharmaceutical Society of Great Britain", -"PHARM h Southern Cross University", -"PHBL c Philip Harris Biological Ltd.", -"PHEL s Plant Health and Environment Laboratory", -"PHEO h Karadag Natural Reserve", -"PHG s Peper Harow", -"PHH h University of Science,Ho Chi Minh City Vietnam National University", -"PHIL s University of the Sciences in Philadelphia, Biological Sciences Department", -"PI s Institut und Museum fuer Geologie und Palaeontologie", -"PI s Universita di Pisa, Dipartimento di Scienze Botaniche", -"PI s Paleontological Institute", -"PIAGR h University of Pisa", -"PICRC h Palau International Coral Reef Center", -"PIHG s Florida Department of Agriculture and Consumer Services", -"PIHU s Paleontological Institut of Helsingfors", -"PIKN s Koronivia Research Station", -"PIMUI s Palaeontologische Institut und Museum der Universitaet in Innsbruck", -"PIMUZ s Palaontologisches Institut und Museum der Universitat Zurich", -"PIN s Philosophical Institution of Newport", -"PIN s Paleontological Institute, Russian Academy of Sciences", -"PINN s Pinnacles National Monument", -"PIR c Bulgarian Research Culture Collection", -"PISR s Pechora-Ilych State Reserve, Russia", -"PIUU s Paleontological Institut, University of Uppsala", -"PKDC s Divisao de Museu de Historia Natural", -"PKM s V. G. Belinsk Pedagogical Institute of Penza", -"PL s Zapadoceske muzeum", -"PLAT h State University of New York, College at Plattsburgh", -"PLES h Plyos State Museum", -"PLFV s Principality of Liechtenstein", -"PLH s Plymouth City Museum and Art Gallery", -"PLP h Institute of Himalayan Bioresource Technology", -"PLU h Pacific Lutheran University", -"PLY sc Plymouth Institution and Athenaeum", -"PLYMOUTH c Plymouth Culture Collection", -"PLYP s University of Plymouth, Department of Biological Sciences", -"PM s Peabody Essex Museum, Natural History Department", -"PM s Pratt Museum", -"PM s Putnam Museum of History and Natural Science", -"PMA s Provincial Museum of Alberta", -"PMA s Universidad de Panama", -"PMAA s Palaeontological Collections, Provincial Museum and Achieves of Alberta", -"PMAE s Royal Alberta Museum", -"PMAG s Perth Museum and Art Gallery", -"PMAM s Beijing Natural History Museum", -"PMAU s Peterborough Museum and Art Gallery", -"PMB s Prirodnjacki Muzej Srpske Zemije", -"PMBC s Phuket Marine Biological Centre", -"PMFP s Papeete Museum", -"PMG s Horto Florestal", -"PMG s Paisley Museum of Geological Collection", -"PMH s City Museum and Records Office", -"PMHPS s Portsmouth Philosophical Society", -"PMHU s Palaontologisches Museum", -"PMIG s Phyletisches Museum", -"PMJ s Phyletisches Museum", -"PMK s Pugachev Regional Museum", -"PMK s Podunajske muzeum", -"PMNH s Pakistan Museum of Natural History", -"PMNH s Peabody Museum of Natural History", -"PMNH s Pratt Museum of Natural History", -"PMQ s Public Museum", -"PMR s Prirodoslovni muzej Rijeka", -"PMS s Prirodonamen Muzej Skopje", -"PMS s Pacific Marine Station", -"PMS s Peabody Essex Museum", -"PMSD s Pettigrew Museum", -"PMSL s Slovenian Museum of Natural History (Prirodosloveni Muzej Slovenije)", -"PMSP s Prefeitura do Municipio de Sao Paulo, Departamento de Parques e Areas Verdes", -"PMU s Paleontological Museum of Undory", -"PMU s Paleontological Museum of Uppsala", -"PMV s Provincial Museum", -"PNBG s University of the Philippines", -"PNCM-BIOTECH c Philippine National Collection of Microorganisms", -"PND h Dr. Shivaram Karantha Pilikula Nisarga Dhama", -"PNG s Division of Primary Industry", -"PNGM s National Museum and Art Gallery, Port Moresby", -"PNH s Philippine National Herbarium", -"PNICMM-INP s Instituto Nacional de la Pesca (Mexico)", -"PNL s Polytechnic of North London, Food and Biological Sciences Department", -"PNM s Philippine National Museum", -"PNPC s Chickasaw National Recreational Area [formerly Platt National Park]", -"PNZ s Penlee House Museum", -"PO s Universidade do Porto, Departamento de Botanica", -"PO s Collection of the Zoological Institute of the Russian Academy of Sciences", -"POFS s Forest Service, USDA", -"POKM s Penza Regional Local History Museum", -"POKM s Perm Regional Lore Museum", -"POL-F s Pollichia, Pfalzmuseum fur Naturkunde Thallichtenberg", -"POLL s Pfalzmuseum fuer Naturkunde", -"POM s Pomona College", -"POP s Tatranske muzeum v Poprade", -"POR s Universita degli Studi di Napoli", -"PORE s Point Reyes National Seashore", -"PORT s BioCentro-UNELLEZ", -"PORUN s Universita degli Studi di Napoli, Dip Ar Bo Pa Ve - Sezione Botanica", -"POZ s Adam Mickiewicz University, Department of Plant Taxonomy", -"POZG s Adam Mickiewicz University, Department of Geobotany", -"POZM s Adam Mickiewicz University, Department of Plant Ecology and Environment Protection", -"POZNB s Agricultural Academy, Botany Department", -"POZW s Adam Mickiewicz University", -"PPC h Palawan State University", -"PPCC c Plant Pathology Culture Collection", -"PPCC s Plant Protection Centre Collection", -"PPCD s West Virginia Department of Agriculture", -"PPDD s Ministry of Agriculture", -"PPFI s Pakistan Forest Institute", -"PPHM s Panhandle-Plains Historical Museum", -"PPI s National Pingtung University of Science and Technology, Department of Forestry", -"PPIHAS c Mycology Collection", -"PPIU s M. Utemisov Western Kazakhstanian State University, V. V. Ivanov Department of Botany", -"PPKMI c Plant Production Technology Department, Faculty of Agricultural Technology", -"PPKU1 c Department of Plant Pathology, Faculty of Agriculture, Thailand", -"PPKU2 c Department of Plant Pathology, Faculty of Agriculture, Thailand", -"PPKU3 c Department of Plant Pathology, Faculty of Agriculture, Thailand", -"PPKU4 c Department of Plant Pathology, Faculty of Agriculture, Thailand", -"PPKU5 c Department of Plant Pathology, Faculty of Agriculture, Thailand", -"PPKU6 c Department of Plant Pathology, Faculty of Agriculture, Thailand", -"PPL s Agricultural Development and Advisory Service, Harpenden Laboratory", -"PPNP s Point Pelee National Park", -"PPPO s Pusat Penelitian dan Pengembangan Oseanologi", -"PPPPB c ARC-Plant Protection Research Institute, Plant Pathogenic and Plant Protecting Bacteria", -"PPRI c ARC-Plant Protection Research Institute, National Collection of Fungi: Culture Collection", -"PPRL h USDA-ARS Poisonous Plant Research Lab", -"PPRZ s Plant Protection Research Institute", -"PPSIO s P. P. Shirshov Institute of Oceanology", -"PPU h Perm State Teacher Training University", -"PQFC b Phu Qui's Fruit Tree Center-Vietnam", -"PR s National Museum in Prague, Department of Botany", -"PRA s Institute of Botany, Academy of Sciences", -"PRB s Prague Botanical Garden", -"PRC s Charles University, Botany Department", -"PRE s National Botanical Institute - Pretoria", -"PREM s Plant Protection Research Institute, Biosystematics Division, Mycology Unit", -"PRF s South African Forestry Research Institute, Environment Affairs Department", -"PRG s Universidad Nacional Pedro Ruiz Gallo", -"PRH s Perthshire Society of Natural Science", -"PRI s College of Eastern Utah, Biology Department", -"PRICO s University of Puerto Rico", -"PRL c Prairie Regional Laboratory", -"PRM s National Museum, Mycological Department", -"PROIMI c Planta Piloto de Procesos Industriales Microbiologicos", -"PRU s University of Pretoria, Botany Department", -"PRV s Porvoo Museum of Natural History", -"PSAE s Alberta Environmental Centre", -"PSGB s University of Bradford, Pharmacy Department", -"PSK h Pskov State University", -"PSM s University of Puget Sound, James R. Slater Museum of Natural History", -"PSO s Universidad de Narino", -"PSP s Parasitic Seed Plants", -"PSS s Philosophical Society of Southampton", -"PSS s Paleontology and Stratigraphic Section of the Geological Institute of the Mongolian Academy of Sciences", -"PSU s Prince of Songkla University, Biology Department", -"PSU s Portland State University, Vertebrate Biology Museum", -"PSU:Mamm s Portland State University, Vertebrate Biology Museum, Mammal Collection", -"PSU s Pennsylvania State University", -"PSUB s University of Botswana", -"PSUC s Frost Entomological Museum", -"PSUMC s Pittsburg State University", -"PSY s Paisley Museum", -"PTBG s National Tropical Botanical Garden", -"PTCC c Pakistan Type Culture Collections", -"PTCCI c Persian Type Culture Collection", -"PTH s Perth Museum and Art Gallery, Herbarium", -"PTHL s Literary and Antiquarian Society of Perth", -"PTIS s Potato Introduction Station", -"PTN s Ellesmere Chambers", -"PTTC c Pranakorn Teacher Training College, Department of Biology, Faculty of Science and Technology", -"PTZ s Karelian Scientific Centre, Russian Academy of Sciences", -"PU s Princeton University", -"PU-HI s Department of Palaeontology, Universidad Complutense of Madrid", -"PUA s Pacific Union College, Biology Department", -"PUC s Beijing University", -"PUC s North-West University", -"PUCMNH s Pacific Union College, Museum of Natural History", -"PUCP s Punjab University", -"PUH s University of the Philippines, Institute of Biology", -"PUL s Purdue University, Department of Botany and Plant Pathology", -"PUM s Universita DI Pisa", -"PUN s Punjabi University, Botany Department", -"PUO s Portland University", -"PUP s University of Peshawar, Botany Department", -"PUR s Purdue University, Department of Botany and Plant Pathology", -"PURC s Purdue University", -"PUS s Puslinch House", -"PUSC s University of Southern Colorado, Life Sciences Department", -"PVB h Institute of Ecology of the Volga River Basin, Russian Academy of Science", -"PVF c Pusat Veterinaria Farma", -"PVGB c Plant Virus GenBank", -"PVHR s Universite Paris VI", -"PVL s Paleontologia de Vertebrados Lillo", -"PVNH s ORSTOM", -"PVPH s Paleontolga de Vertebrados", -"PVSJ s Museo do Ciencias Naturles", -"PW s Paleontological Collections", -"PWRC s Patuxent Wildlife Research Center", -"PWU h V.G.Korolenko Poltava National Pedagogical University", -"PY s Centro de Estudios y Colecciones Biologicas para la Conservacion", -"PYCC c Portuguese Yeast Culture Collection", -"PYU s Yunnan University, Laboratory of Pteridophyta", -"PZL s Penzance Library", -"PZV s Petrozavodsk State University, Department of Botany and Plant Physiology", -"Q s Universidad Central", -"QAME s Direccion Nacional Forestal, Ministerio de Agricultura y Ganaderia", -"QAP s Universidad Central", -"QBG s Queen Sirikit Botanic Garden", -"QC s National Museum of Natural History, Bulawayo", -"QCA s Pontificia Universidad Catolica del Ecuador, Departamento de Biologia", -"QCAZ s Museo de Zoologia, Pontifica Universidad Catolica del Ecuador", -"QCAZ:A s Museo de Zoologia, Pontifica Universidad Catolica del Ecuador, Amphibian Collection", -"QCAZ:R s Museo de Zoologia, Pontifica Universidad Catolica del Ecuador, Reptile Collection", -"QCNE s Herbario Nacional del Ecuador", -"QD s Ocean University of China", -"QDC s Qinghai Institute for Drug Control", -"QDPC s Queensland Department of Primary Industries", -"QDPI s Queensland Department of Primary Industries", -"QEF s Universite Laval, Laboratoire d'ecologie forestiere", -"QF s Institute of Forestry", -"QFA s Universite Laval", -"QFB s Laurentian Forestry Centre, Canadian Forest Service", -"QFBE s Laurentian Forestry Centre, Canadian Forest Service", -"QFMQ s Queenstown Museum", -"QFS s Universite Laval", -"QG s General Grassland Station of Qinghai", -"QIBX s Qinghai Institute of Biology", -"QIMR s Queensland Institute of Medical Research", -"QK s Queen's University, Biology Department", -"QM s Queensland Museum", -"QM s U.S. Army Natick Research and Development Center", -"QM s Queen Victoria Museum", -"QMB s Queensland Museum, Brisbane", -"QMC s Queen Mary College", -"QMEX s Universidad Autonoma de Queretaro, Centro Universitario", -"QMOR s Collection Entomologique Ouellet-Robert", -"QMP s Musee du Quebec", -"QPAR s Ministere du Tourisme de la Chasse et de la Peche du Quebec, Laboratoire de Recherches", -"QPH s Seminaire de Quebec", -"QPIM s Department of Primary Industries", -"QPLS s Biblioteca Ecuatoriana Aurelio Espinosa Polit", -"QPNRA s Programa Nacional de Regionalizacion, Ministerio de Agricultura y Ganaderia, Departamento de Ecologia", -"QRS s Australian National Herbarium, Division of Plant Industry, CSIRO", -"QSA s Institut de technologie agroalimentaire", -"QTC s Qiqihar Teachers College, Biology Department", -"QUA s Qinghai University, Agriculture Department", -"QUC s Universite Laval, Departement de biologie", -"QUE s Complexe scientifique", -"QUSF s Universidad San Francisco de Quito, Biology Department", -"QVG s Queen Victoria Museum", -"QVM s Queen Victoria Museum", -"QVMS s Queen Victoria Memorial Museum", -"QWA s University of the North, Qwa Qwa Campus", -"QYTC s Qingyang Teachers College, Biology Department", -"R s Universidade Federal do Rio de Janeiro, Departamento de Botanica", -"R s Departamento de Geologia, Universidad de Chile", -"RAB s Institut Scientifique, Departement de Botanique et d'Ecologie Vegetale", -"RAF s Myanmar Forest Herbarium", -"RAM s Ramsey Public Library", -"RAME s Royal Albert Memorial Museum", -"RAMK s Ramkhamhaeng University, Biology Department", -"RAMM s Royal Albert Memorial Museum, Leisure and Tourism Department", -"RANG s Yangon University", -"RANK h Research Center of Agriculture and Natural Resources of Kermanshah province", -"RARS s Regina Research Station", -"RAS s Union of Burma Applied Research Institute, Pharmaceutical Department", -"RAU s Laboratoire de Biologie Vegetale", -"RAW s Pakistan Agricultural Research Council", -"RB s Jardim Botanico do Rio de Janeiro", -"RBCM s Royal British Columbia Museum", -"RBCM:Mamm s Royal British Columbia Museum, Mammal Collection", -"RBE s Universidade Federal Rural do Rio de Janeiro", -"RBF c Raiffeisen Bioforschung", -"RBINS s Royal Belgian Institute of Natural Sciences", -"RBR s Universidade Federal Rural do Rio de Janeiro, Departamento de Botanica", -"RBS s Royal Botanic Society", -"RBY s East Divisional Library", -"RCAM s Rutgers University, Biology Department", -"RCAT c Regional Collection of Animal Viruses and Tissue Cultures", -"RCB c RIKEN Cell Bank", -"RCC c Roscoff Culture Collection", -"RCDM c Republican Centre for Deposition of Microorganisms of the National Academy of Sciences and Ministry of Education and Science of Armenia", -"RCHM s Rochdale Museum Service", -"RCHP s Rochdale Equitable Pioneers' Memorial Museum", -"RCMC s Rockford College", -"RCN s Richmond Naturalists' Field Club", -"RCR s Rochester Public Museum", -"RCS s Royal College of Surgeons", -"RCSL s Royal College of Surgeons", -"RCVC h Universidad Nacional de Rio Cuarto", -"RDAF s Research Department South East Asian Fisheries Development Centre", -"RDG s Reading Museum and Archive Service", -"RDS s Royal Dublin Society", -"RE s Liaoning Reed Science Institute", -"RED s University of Redlands, Biology Department", -"REDM s Reading Museum and Archive Service", -"REED h Reed College", -"REG s Universitaet Regensburg, Regensburgische Botanische Gesellschaft", -"REGGIO h Universita Mediterranea di Reggio Calabria", -"RELC s INIFAP-SAGAR", -"REN s Campus Scientifique de Beaulieu, Laboratoire de Botanique", -"RENO s University of Nevada, Environmental and Resource Sciences Department", -"RENZ s Universitaet Basel, The Swiss Orchid Foundation", -"REP s Desert Experiment Station of the W.I.R.", -"RESC s Shasta College", -"REU s Universite de la Reunion", -"RFA s Universidade Federal do Rio de Janeiro, Departamento de Botanica", -"RFE s Radcliffe Literary and Scientific Society Museum", -"RFFP h Universidade do Estado do Rio de Janeiro", -"RFNS s Rochdale Field Naturalists' Society", -"RGM s Nationaal Natuurhistorisch Museum Leiden", -"RGMC s Musee Royal de l'Afrique Centrale", -"RGY s Rugby School Natural History Society Museum", -"Rh-EF s Museum of Grannat", -"RHK h St. Berchmans College", -"RHLCY s Reservoir of Heilongtan", -"RHM s Public Reference Library", -"RHMC s Red House Museum", -"RHMD s National Institute of Science Communication", -"RHMU c Department of Pathology, Faculty of Medical Science, Ramathibordi Hospital", -"RHS c Plant Pathology, The Royal Horticultural Society", -"RHT s St. Joseph's College", -"RI s Rudjer Boskovic Institute", -"RIA c The Russia Research Institute for Antibiotics Culture Collection", -"RIB c National Research Institute of Brewing, Tax Administration Agency", -"RIBM c Research Institute for Brewing and Malting", -"RICK s Brigham Young University - Idaho, Department of Biology", -"RICP c Crop Research Institute", -"RIFAV b Research Institute for Fruits and Vegetables", -"RIFFL s Research Institute of Freshwater Fisheries", -"RIFY c Institute of Enology and Viticulture, Yamanashi University", -"RIG s University of Latvia, Department of Botany and Ecology", -"RIGB s Latvian State Center of Plant Protection", -"RIGG s University of Latvia", -"RIM s L'Ecole d'Agriculture", -"RIMD c Research Institute for Microbial Diseases, Research Center for Emerging Infectious Diseases", -"RIN s Research Institute for Nature Management, Botany Department", -"RIOC s Universidad Nacional de Rio Cuarto", -"RIPO c Plant Virus Collection", -"RITFC c Research Institute for Tobacco and Fibre Crops", -"RIVE c Research Institute for Viticulture and Enology", -"RIVE s University of Wisconsin, Biology Department", -"RIY s National Agriculture and Water Research Center", -"RIZ s Instituto de Zootecnia", -"RKT h Regional Research Institute (Ayurveda)", -"RLS s Royal Latin School", -"RM s McGill University, Redpath Museum", -"RM c Rumen Microorganisms", -"RM s Raffles Museum", -"RM s University of Wyoming Herbarium", -"RMA c R. M. Alden Research Lab", -"RMBL s Rocky Mountain Biological Laboratory", -"RMBR s Raffles Museum of Biodiversity Research", -"RMCA s Royal Museum for Central Africa", -"RMDRC s Rocky Mountain Dinosaur Resource Center", -"RMF c Rocky Mountain Herbarium, Fungi", -"RMFM s Richmond Marine Fossils Museum", -"RMNH s Naturalis Biodiversity Center", -"RMNH:ACA s Naturalis Biodiversity Center, Acari collection", -"RMNH:AVES s Naturalis Biodiversity Center, bird collection", -"RMNH:BRA s Naturalis Biodiversity Center, brachiopod collection", -"RMNH:BRY s Naturalis Biodiversity Center, bryozoan collection", -"RMNH:COEL s Naturalis Biodiversity Center, Coelomate collection", -"RMNH:CRUS s Naturalis Biodiversity Center, crustacean collection", -"RMNH:CRUS.D s Naturalis Biodiversity Center, decapod collection", -"RMNH:INS s Naturalis Biodiversity Center, Insect collection", -"RMNH:MAM s Naturalis Biodiversity Center, Mammal collection", -"RMNH:MOL s Naturalis Biodiversity Center, mollusc collection", -"RMNH:PISC s Naturalis Biodiversity Center, fish collection", -"RMNH:POR s Naturalis Biodiversity Center, poriferan collection", -"RMNHD s Naturalis Biodiversity Center", -"RMNP s Riding Mountain National Park", -"RMRC b Regional Medical Research Centre", -"RMS s University of Wyoming Herbarium", -"RMSC s Rocky Mountain Forest and Range Experiment Station", -"RMSCC c Roche Molecular Systems Culture Collection", -"RMTV h University of Rome Tor Vergata", -"RMWC s Randolph-Macon Woman's College, Biology Department", -"RNG s University of Reading", -"RNMUT s Republic Nature Museum of Uzbekistan", -"RO s Universita degli Studi di Roma La Sapienza, Dipartimento di Biologia Vegetale", -"ROAN s Virginia Western Community College, Biology Department", -"ROCH s Rochester Academy of Science", -"ROHB s Cattedra di Micologia, Dipartimento di Biologia Vegetale", -"ROIG s Estacion Experimental de Plantas Medicinales Dr. Juan T. Roig", -"ROM s Royal Ontario Museum", -"ROM:ENT s Royal Ontario Museum, Entomology collection", -"ROM:HERP s Royal Ontario Museum, Herpetology collection", -"ROM:ICH s Royal Ontario Museum, Fish collection", -"ROM:IZ s Royal Ontario Museum, Invertebrate Zoology Collection", -"ROM:MAM s Royal Ontario Museum, Mammal Collection", -"ROM:ORN s Royal Ontario Museum, Ornithology Collection", -"ROME s Royal Ontario Museum, Entomology Collection", -"ROML s National University of Lesotho, Biology Department", -"ROMO s Rocky Mountain National Park", -"RON h Universidade Federal de Rondonia", -"ROO s Agricultural Research Council-Range and Forage Institute", -"ROPA s Sonoma State University, Biology Department", -"ROPV s Istituto Sperimentale per la Patologia Vegetale", -"ROST s Universitaet Rostock", -"ROV s Museo Civico di Rovereto", -"ROZ s Stredoceske muzeum", -"RPM s Reading Public Museum", -"RPMH s Roemer Pelizaeus Museum Hildesheim", -"RPN s Ripon Mechanics Institute", -"RPPMC s Rondeau Provincial Park", -"RPPR s Internationl Institute of Tropical Forestry", -"RPSC s Rio Palenque Science Center", -"RPSP s Universidade de Sao Paulo", -"RPTN s Repton School, Biology Department", -"RRCBI s Regional Research Centre (Ay.)", -"RRIASR c Fungal Pathogens of Hevea Rubber in Sri Lanka", -"RRJ c RRL , Jammu INDIA", -"RRLB s Regional Research Laboratory", -"RRLH s Regional Research Laboratory", -"RSA s Rancho Santa Ana Botanic Garden", -"RSCS c Medical Culture Collection", -"RSDR s Desert Institute, Turkmenistan Academy of Sciences", -"RSKK c Refik Saydam National Type Culture Collection-RSKK", -"RSM s Royal Saskatchewan Museum", -"RSM s Royal Scottish Museum", -"RSU h Ryazan State University", -"RSY s Buteshire Natural History Society, The Museum", -"RTE s Holmesdale Natural History Club Museum", -"RTHM s Munidipal Museum and Art Gallery", -"RTMP s Royal Tyrell Museum of Paleontology", -"RU s University of Reading, Agricultural Botany Department", -"RUBL s University of Rajasthan, Botany Department", -"RUDZ s Rhodes University", -"RUEB s Eidgenoessische Technische Hochschule ETH", -"RUH s Rhodes University, Botany Department", -"RUHV s Radford University, Biology Department", -"RUIC s Rutgers University", -"RUMF s University Museum, University of the Ryukyus", -"RUNYON s Robert Runyon Herbarium", -"RUPP h Royal University of Phnom Penh", -"RUSI s J.L.B. Smith Institute of Ichthyology (formerly of Rhodes University)", -"RUSU s Universidade Santa Ursula", -"RUT s Douglass College, Rutgers University, Biological Sciences Department", -"RUTPP s Cook College, Rutgers University, Plant Pathology Department", -"RUY s Mid-Staffordshire Field Club", -"RV c Collection of Leptospira Strains", -"RV s Molotov State University of Rostov, Botany Department", -"RVP s Museo Provincial de Historia Natural de La Pampa (Argentina)", -"RWBG s Rostov State University", -"RWC s State University of New York, Roosevelt Wildlife Collection", -"RWDN s University of Glasgow Field Station", -"RWPM s Roger Williams Park Museum of Natural History", -"RYCC c Roseworthy Yeast Culture Collection", -"RYD s School of Art", -"RYU s University of the Ryukyus, Biology Department", -"S s Swedish Museum of Natural History, Botany Departments", -"SA s Museum national d'Histoire Naturelle, Laboratiore de Paleontologie", -"SAAR s Zentrum fuer Biodokumentation des Saarlandes", -"SAAS s Saasveld, Port Elizabeth Technikon", -"SAB s Society of Amateur Botanists", -"SACA s South-west Agricultural University", -"SACC s St. Ambrose College", -"SACL s Santa Clara University, Biology Department", -"SACON s Salim Ali Centre for Ornithology and Natural History", -"SACS s Shenyang Agricultural College", -"SACT s California State University, Biological Sciences Department", -"SAF h Department of Agricultural and Forest Sciences", -"SAFB s University of Saskatchewan, Forestry Department", -"SAFU s University of San Francisco", -"SAG c Sammlung von Algenkulturen at Universitat Gottingen", -"SAG c Coleccion de Micoligica Laboratorio Regional, Servicio Agricola y Ganadero", -"SAIAB sb South African Institute of Aquatic Biodiversity", -"SAIM s South African Institute for Medical Research", -"SAIMR s South African Institute for Medical Research", -"SAITP c School of Pharmacy and Medical Sciences, University of South Australia", -"SAK s Institute of Marine Geology and Geophysics, Far East Branch, Island Ecological Problems Department", -"SAKH s Sakhalin Botanical Garden", -"SAL s Kansas Wesleyan University, Biology Department", -"SALA s Universidad de Salamanca, Departamento de Botanica", -"SALAF s Universidad de Salamanca", -"SALF s Salford Royal Free Museum and Library", -"SALFM s Salford Natural History Museum, Salford City Council", -"SALLE s Instituto Geobiologico La Salle", -"SAM s South African Museum", -"SAMA sb South Australian Museum", -"SAMC s Iziko Museum of Capetown", -"SAMF h Samford University", -"SAMU s Savaria Museum, Department of Natural History", -"SAN s Forest Research Centre, Forest Department", -"SANBI s South African National Biodiversity Institute", -"SANC s South African National Collection of Insects", -"SANT s Universidad de Santiago de Compostela", -"SANT:Algae s Universidad de Santiago de Compostela, algae collection", -"SANT:Bryo s Universidad de Santiago de Compostela, bryophyte collection", -"SANT:Lich s Universidad de Santiago de Compostela, lichen collection", -"SANU s Shaanxi Normal University, Biology Department", -"SAO s Sammlung Oberli", -"SAP s Herbarium of Graduate School of Science, Hokkaido University", -"SAPA s Hokkaido University Museum (Fungal collection)", -"SAPCL s St. Andrews Presbyterian College, Biology Department", -"SAPS s Hokkaido University Museum (Plant collection)", -"SAPT h Hokkaido University Botanic Garden", -"SAR s Department of Forestry", -"SARA s Zemaljski Muzej Bosne I. Herzegovine", -"SARAT s Department of Morphology and Systematic Botany", -"SARBG h Saratov State University Botanical Garden", -"SARC s Roanoke College, Biology Department", -"SARI s Sakarya Agricultural Research Institute", -"SAS s Sammlung Arnhardt des Museums Schloss Wilhelmsburg Schmalkalden", -"SASK s University of Saskatchewan, Plant Sciences Department", -"SASSA s Universita di Sassari, Dipartimento di Scienze del Farmaco", -"SASSC b SENDAI Arabidopsis Seed Stock Center", -"SASY s Institute for Biological Problems of Cryolithozone", -"SAT s Angelo State University, Biology Department", -"SAU s Sichuan Agricultural University, Department of Basic Courses", -"SAU s Southern Arkansas University", -"SAUF s Sichuan Agricultural University, Forestry Department", -"SAUT s Sichuan Agricultural University", -"SAV s Institute of Botany, Slovak Academy of Sciences", -"SAWV s Salem International University, Department of Bioscience", -"SB s Saint Bernard Abbey", -"SBBG s Santa Barbara Botanic Garden", -"SBC s University of California, Biological Sciences Department", -"SBCC s Santa Barbara City College, Department of Biological Sciences", -"SBCM s San Bernardino County Museum", -"SBDE s Sino-Belgian Dinosaur expedition", -"SBG s Botanical Garden of Stavropol State University, Botany Department", -"SBH s S Blair Hedges Collection", -"SBKA s Stiftssammlungen des Benediktinerstiftskrems-Munster", -"SBM s Sabah Museum", -"SBM s Santa Barbara Museum of Natural History", -"SBMN s Santa Barbara Museum of Natural History", -"SBMNH s Santa Barbara Museum of Natural History", -"SBNHM s Santa Barbara Natural History Museum", -"SBP s Station Biologique de Paimpont", -"SBSC s Robert A. Vines Environmental Science Center", -"SBSFU c School of Biological Sciences", -"SBT s Bergius Foundation", -"SBU s Saint Bonaventure University, Biology Department", -"SBUG c Department of Biology of the University of Greifswald", -"SBY s Salisbury and South Wiltshire Museum", -"SC s Salem College, Biology Department", -"SCA s Limbe Botanical & Zoological Gardens", -"SCAC s South China Agricultural College", -"SCAR s Wood End Museum", -"SCARB s Boys' High School", -"SCB s Station Centrale de Boukoko", -"SCCAP c Scandinavian Culture Collection of Algae and Protozoa", -"SCCBC s Selkirk College, Environmental Sciences and Technologies Department", -"SCCN h Scott Christian College", -"SCDH s South Carolina Department of Health and Environmental Control", -"SCFI s Sichuan Academy of Forestry", -"SCFQ s Service canadien de la faune", -"SCFS h University of California-Berkeley, Sagehen Creek Field Station", -"SCH s Museum zu Allerheiligen", -"SCHG s George Museum", -"SCHN s Smith College, Biological Sciences Department", -"SCIEA s South China Institute of Endangered Animals", -"SCL s St. Cloud State University, Department of Biological Sciences", -"SCM s Sheffield City Museums", -"SCN s Sociedad de Ciencias Naturales \"La Salle\"", -"SCNHM s Southwestern College, Natural History Museum", -"SCNU s Sichuan Normal University, Biology Department", -"SCP h Sociedad Cientifica del Paraguay", -"SCPS s Scarborough Philosophical and Archaeological Society Museum", -"SCR s Scripps Institution of Oceanography, Herbarium", -"SCS s Agriculture and Agri-Food Canada, Semiarid Prairie", -"SCSC s Saint Cloud State University", -"SCSFRI s South China Sea Fisheries Research Institute", -"SCSG h South China Sea Institute of Oceanology, Academia Sinica", -"SCSIO s South China Sea Institute of Oceanology, Academia Sinica", -"SCSM s South Carolina State Museum", -"SCT s Friend's School", -"SCTCC c Sichuan Type Culture Collection", -"SCU s Shandong Christian University", -"SCUF s Universidade Federal de Santa Catarina", -"SCUI h Suez Canal University", -"SCV b State Collection of Viruses", -"SCZ s Smithsonian Tropical Research Institute", -"SD s Herbarium, San Diego Natural History Museum", -"SDAKS s South Dakota State University", -"SDAU s Shandong Agricultural University", -"SDC s South Dakota State University, Department of Biology", -"SDCM s Shandong College of Traditional Chinese Medicine", -"SDFI s Shandong Forestry Institute", -"SDFS s Shandong Forestry School", -"SDI s Southend Institute", -"SDM s Stroud and District Museum", -"SDM s San Diego Mesa College, Botany Department", -"SDMP s Shandong Institute of Traditional Chinese Medicine and Materia Medica", -"SDN s Borough of Thamesdown Museum and Art Gallery", -"SDNCU cb The Specimen Depository of the Graduate School of Natural Sciences, Nagoya City University", -"SDNH s Malkerns Agricultural Research Station", -"SDNHM s San Diego Natural History Museum", -"SDNU s Shandong Normal University, Biology Department", -"SDSM s South Dakota School of Mines and Technology", -"SDSU s San Diego State University", -"SDSU:Arthropods s San Diego State University, Museum of Biodiversity Terrestrial Arthropod Collection", -"SDSU:Birds s San Diego State University, Museum of Biodiversity Birds Collection", -"SDSU:Fish s San Diego State University, Museum of Biodiversity Fish Collection", -"SDSU:Greenhouse b San Diego State University, Greenhouse", -"SDSU:Herbarium s San Diego State University, Herbarium", -"SDSU:Herps s San Diego State University, Museum of Biodiversity Amphibians & Reptiles Collection", -"SDSU:Mammals s San Diego State University, Museum of Biodiversity Mammal Collection", -"SDSU s Severin-McDaniel Insect Collection", -"SDU s University of South Dakota, Department of Biology", -"SEAARI s South Eastern Anatolian Agricultural Research Institute", -"SEAC s Estacion Experimental de Agricolas de la Campara", -"SEAMEO c Seameo-Biotrop", -"SEAN s Museo Entomologico", -"SEBR c Sanofi ELF Biorecherches", -"SECM s Science Education Center", -"SEFES s Southeastern Forest Experiment Station", -"SEFSC s Southeast Fisheries Science Center", -"SEFSC:MMMGL s Southeast Fisheries Science Center, Marine Mammal Molecular Genetics Laboratory", -"SEHU s Hokkaido University Insect Collection", -"SEIG s Societa Entomologica Italiana", -"SEL s Marie Selby Botanical Gardens", -"SELU s Southeastern Louisiana University, Biological Sciences Department", -"SEMC s Snow Entomological Museum", -"SEMIA c Colecao de Culturas de Rhizobium da Fepagro", -"SEMK s Snow Entomological Museum", -"SEMM s Station Experimental de la Maboke", -"SEMO s Southeast Missouri State University, Department of Biology", -"SERC s Smithsonian Environmental Research Center", -"SERG s Institut de Recherche Agronomique de Guinee", -"SERO s Sociedad para el Estudio de los Recursos Bioticos de Oaxaca", -"SERTC s Southeastern Regional Taxonomic Center", -"SES s Southeastern Shanxi Teachers School, Biochemistry Department", -"SETON s Philmont Scout Ranch, Seton Memorial Library", -"SEV s Universidad de Sevilla, Departamento de Biologia Vegetal y Ecologia", -"SEVF s Universidad de Sevilla, Departamento de Botanica", -"SEY s Seychelles Natural History Museum", -"SF s Universidad Nacional del Litoral", -"SFAC s Stephen F. Austin State University", -"SFB s Salgues Foundation of Brignoles for Development of Biological Sciences", -"SFC s Laboratory of Fishes", -"SFD s Sheffield Galleries and Museums Trust, City Museum", -"SFDK s Sarawak Forestry Department", -"SFDL s Sheffield Literary and Philosophical Society", -"SFDN s Sheffield Naturalists' Club", -"SFI b Slovenian Forestry Institute", -"SFPA s Fundacao Estadual de Pesquisa Agropecuaria", -"SFRF s Forest Service, Region 5, USDA", -"SFRP s Southern Research Station", -"SFRS s Sea Fisheries Research Station", -"SFS s Universite de Sherbrooke, Departement de biologie", -"SFSU s San Francisco State University, Department of Biology", -"SFT s Stowlangtoft Hall", -"SFU s Shanghai Fisheries University", -"SFUC s Simon Fraser University", -"SFUV s Simon Fraser University, Biological Sciences Department", -"SFV s California State University, Department of Biology", -"SFVS s San Fernando Valley State University", -"SG s Shanghai Botanical Garden", -"SGBH s Museum of Staffordshire County", -"SGE s Stamford Park Museum", -"SGEL s Stalybridge Library", -"SGGS s The Museum", -"SGGW s Warsaw University of Life Sciences", -"SGMA s Universidade Nova de Lisboa", -"SGN h Southern Institute of Ecology", -"SGO s Herbario, Museo Nacional de Historia Natural, Santiago", -"SGSC c Salmonella Genetic Stock Centre", -"SGWG s Sammlung der Sektion Geologische Wissenschaften der Ernst-Moritz-Arndt University", -"SH s Academia Sinica", -"SHB s Shanghai Baptist College", -"SHC s Sacred Heart College", -"SHCP s Southern Highlands Conservation Programme", -"SHCT s Shanghai Teachers College of Technology, Biology Department", -"SHD s University of Sheffield, Botany Department", -"SHDC s Shanghai Institute for Drug Control", -"SHG s Sohag University, Botany Department", -"SHI s Herbarium, Shihezi University", -"SHIN s Shinshu University", -"SHJ s St. John's University", -"SHM s Shanghai Museum of Natural History, Botanical Department", -"SHM s Siouxland Heritage Museum", -"SHMC s Luther College, Sherman A. Hoslett Museum of Natural History", -"SHMH s Universite l'Aurore, Musee Heude", -"SHMI s Shanghai Institute of Materia Medica, Chinese Academy of Sciences, Phytochemistry Department", -"SHMU s Shanghai Medical University", -"SHOR s Shorter College, Biology Department", -"SHSND s North Dakota Heritage Center", -"SHST s Sam Houston State University, Department of Biological Sciences", -"SHSU s Sam Houston State University, Vertebrate Natural History Collection", -"SHTC s California State University, Biology Department", -"SHTU s Shanghai Teachers University, Biology Department", -"SHY s Rowley's House Museum", -"SHYAN s Shropshire Archaeological and Natural History Society", -"SHYB s Shrewsbury School", -"SHYL s Shrewsbury School", -"SHYN s Shrewsbury Natural History Society", -"SHYP s Shrewsbury Public Library", -"SI s Instituto de Botanica Darwinion", -"SIAC s Sichuan Institute of Agriculture", -"SIAC s Accademia dei Fisiocritici Onlus", -"SIB s Sibiu Natural History Museum", -"SIBAC s Southwest Institute of Biology", -"SIBS h Institute of Biology of the Southern Seas", -"SICH s Simpson College, Biology and Environmental Sciences Department", -"SIEMEA s Severtsov Insitute for Evolutionary Morphology and Animal Ecology", -"SIENA s Universita di Siena, Dipartimento di Scienze Ambientali \"G. Sarfatti\"", -"SIF s Senckenbergisches Institut", -"SIFS s Sichuan Forestry School", -"SIGMA s Station Internationale de Geobotanique Mediterraneenne et Alpine", -"SIIS s Staten Island Institute of Arts and Sciences", -"SIM s Staten Island Institute of Arts and Sciences, Science Department", -"SIMF s Taurida National University, Botany Department", -"SIMS s Sherkin Island Marine Station", -"SING s Singapore Botanic Gardens", -"SINU s National University of Singapore, Biological Sciences Department", -"SIO s Scripps Institution of Oceanography", -"SIO:BIC s Scripps Institution of Oceanography, Benthic Invertebrates Collection", -"SITC s Sichuan Teachers College, Biology Department", -"SIU s Southern Illinois University, Plant Biology Department", -"SIUC s Research Museum of Zoology, Southern Illinois University at Carbondale", -"SIUC:H s Research Museum of Zoology, Southern Illinois University at Carbondale, Herpetology Collection", -"SIUCM s Southern Illinois University", -"SIUE s Southern Illinois University, Edwardsville", -"SIZK s Schmaulhausen Institute of Zoology", -"SJ s Departamento de Recursos Naturales y Ambientales", -"SJAC s San Joaquin County Agriculture Commissioner", -"SJC s Sir John Cass College, Chemistry and Biology Department", -"SJCA s St. John's College", -"SJCRY s St. John's College of Ripon and York", -"SJER s United States Forest Service, San Joaquin Experimental Range", -"SJFM s Fairbanks Museum and Planetarium", -"SJNM s San Juan College", -"SJPC s Sergei J. Paramonov personal collection -- destroyed", -"SJRP s UNESP, Campus Sao Jose Rio Preto, Departamento Zoologia e Botanica", -"SJSC s San Jose State University, J. Gordon Edwards Museum of Entomology", -"SJSU s San Jose State University, Biological Sciences Department", -"SJUBC s Saint John's University, Biology Collections", -"SK s Katedralskolan", -"SKK s Sung Kyun Kwan University, Biological Sciences Department", -"SKM s Skokholm Field Centre", -"SKN s Craven Museum Service", -"SKR s Latvian Research Institute of Agriculture, Plant Protection Department", -"SKT s Stockport Heritage Services", -"SKU s Sri Krishnadevaraya University, Botany Department", -"SKUK c Simpanan Kultur Universiti Kebangsaan", -"SL s University of Sierra Leone, Njala University College, Biological Sciences Department", -"SLBI s South London Botanical Institute", -"SLC s East High School, Science Department", -"SLFC s Slapton Ley Field Centre", -"SlgInnsb s Paleontological Collection", -"SLJG s Steiermarkisches Landesmuseum Joanneum", -"SLL s Societe Linneenne de Lyon", -"SLO s Komenskeho University, Katedra botaniky", -"SLPM s Universidad Autonoma de San Luis Potosi", -"SLRO s Slippery Rock University, Biology Department", -"SLSC s St. Louis, St. Louis Science Center", -"SLSK s St. Leonard's and St. Katherine's Schools", -"SLTC s Teachers College, Botany Department", -"SLU s Laurentian University, Biology Department", -"SLU s Southeastern Louisiana University, Vertebrate Museum", -"SLUB s St. Louis University Museum", -"SLUBGH h Shah Abdul Latif University", -"SLUM s Saint Louis University Museum Ichthylogy Collection", -"SM s Chongqing Municipal Academy of Chinese Materia Medica", -"SM s Senckenberg Museum", -"SM s Schwegler Museum", -"SM s Sarawak Museum", -"SM s Sanford Museum Collections", -"SM s Strecker Museum, Baylor University", -"SMAG s Southland Museum and Art Gallery", -"SMAO s Simao Forestry Bureau", -"SMB s Marianske Muzeum, Natural History Department", -"SMBB s Stredoslovenske muzeum", -"SMBL s Seto Marine Biological Laboratory, Kyoto University", -"SMC s Sedgwick Museum", -"SMCC c Subsurface Microbial Culture Collection", -"SMCC-W c Subsurface Microbial Culture Collection--Western Branch", -"SMCW s Saint Michael's College, Biology Department", -"SMDB s Universidade Federal de Santa Maria, Departamento de Biologia", -"SME s Station Marine d'Endoume", -"SME s Sedgwick Museum of Geology", -"SMF s Forschungsinstitut und Natur-Museum Senckenberg", -"SMF s Universidad Nacional Mayor de San Marcos", -"SMH s Saint Meinrad College of Liberal Arts, Biology Department", -"SMI s Prince Rupert Forest Region, Research Section", -"SMIP c Secao de Maricultura", -"SMJM s Sabah Museum", -"SMK s Sarawak Museum", -"SMKM s Selangor Museum", -"SMM s Science Museum of Minnesota", -"SMMC s Second Military Medical College", -"SMN s Simao District National Medical and Pharmaceutical Institute", -"SMNG s Senckenberg Museum fuer Naturkunde Goerlitz", -"SMNH s Saskatchewan Museum of Natural History", -"SMNH s Steinhardt Museum of Natural History", -"SMNH s Swedish Museum of Natural History", -"SMNH s State Museum of Natural History", -"SMNH s Schmidt Museum of Natural History, Emporia State University", -"SMNK s Staatliches Museum fuer Naturkunde Karlsruhe (State Museum of Natural History)", -"SMNS s Staatliches Museum fuer Naturkund Stuttgart", -"SMOC s Slezske Muzeum Opava", -"SMP s Surinaams Museum", -"SMP s The State Museum of Pennsylvania", -"SMPM s Science Museum of Minnesota", -"SMR s Samara State University, Department for Ecology, Botany, and Nature Protection", -"SMRG c Soil Microbiology Research Group, Division of Soil Science, Department of Agriculture", -"SMRS s Stavropol Museum of Regional Studies", -"SMS s Missouri State University, Department of Biology", -"SMSM s Sarawak Museum", -"SMTP s Swedish Malaise Trap Project", -"SMTWA c School of Medical Technology Western Australia", -"SMU s St. Mary's University", -"SMU s Sangmiung University", -"SMU s Shuler Museum of Paleontology, Southern Methodist University", -"SMVM s National Archives and Museum", -"SMW s School of Medicine for Women", -"SMW s State Museum", -"SMWN s State Museum", -"SMWU s Sang Miung Women's University", -"SN s South China Normal University, Biology Department", -"SNC s Saint Norbert College", -"SNCBSH s State of North Carolina Biological Station", -"SNGM s Coleccion Paleontologica", -"SNHM s Sudan Natural History Museum", -"SNHS s Guildford Museum", -"SNM s Slovak National Museum", -"SNM s Western New Mexico University, Department of Natural Sciences", -"SNMB s Staatliches Naturhistorisches Museum", -"SNMBR s Staatliches Naturhistorisches Museum in Braunschweig", -"SNMC s Slovenske Narodne Muzeum", -"SNMG s Staatliches Museum fuer Naturkunde", -"SNMH h Sree Narayana Mangalam College", -"SNMNH s Saudi Arabian National Museum of Natural History", -"SNOMNH s Sam Nobel Oklahoma Museum of Natural History", -"SNP s Sabah Parks, Botany Section", -"SNPH s Sehlabathebe National Park", -"SNSD s Senckenberg Natural History Collections Dresden, Museum of Zoology", -"SNSD:Moll s Senckenberg Natural History Collections Dresden, Museum of Zoology, ", -"SNU s Seoul National University, School of Biological Sciences", -"SNUA s Seoul National University, The Arboretum", -"SNW s Shropshire and North Wales Natural History and Antiquarian Society", -"SO s Sofia University \"St. Kliment Ohridski\", Botany Department", -"SOA s Agricultural University of Plovdiv, Botany Department", -"SOB s Husite Museum Tabor", -"SOC s Southern Oregon University, Biology Department", -"SOF h Sofyivka National Dendrological Park", -"SOFM s National Museum of Natural History, Sofia", -"SOFRI b Southern Fruit Research Institute Vietnam", -"SOGS s Pal. Coll, Sokoto State Government Palaeontological Collection", -"SOIC s Natural History Museum, National Insect Collection", -"SOKO s Okresni muzeum Sokolov (Regional Muzeum), Botany Department", -"SOM s Bulgarian Academy of Sciences", -"SOMF s Bulgarian Academy of Sciences", -"SORO h Universidade Federal de Sao Carlos, campus Sorocaba", -"SOSCMVNH s Southern Oregon State College, Museum of Vertebrate Natural History", -"SOSN s Silesian Medical School in Katowice, Department of Pharmaceutical Botany", -"SOSSRC s Save Our Seas Shark Research Center, Nova Southeastern University", -"SOTO s College of the Ozarks, Biology Department", -"SOTON s Southampton University", -"SOUT s Long Island University", -"SP s Instituto de Botanica", -"SPA s Swedish Museum of Natural History, Section for Palaeobotany", -"SPAL s Municipio di Reggio Emilia, Musei Civici", -"SPB s Universidade de Sao Paulo", -"SPC s Seattle Pacific University, Biology Department, Suite 205", -"SPF s Universidade de Sao Paulo, Departamento de Botanica", -"SPFR s Universidade de Sao Paulo, Departamento de Biologia", -"SPH s Fox Research Forest", -"SPI s Stavropol Pedagogical Institute, Botany Department", -"SPL s Palynological Laboratory", -"SPLT s South Plains College, Science Department", -"SPM s Sabah Parks", -"SPMCC c Sungei Putih Microbial Culture Collection", -"SPMO c Salt Plains Microbial Observatory", -"SPMS s University of South Florida", -"SPN s Southampton University, Biology Department", -"SPNRI s Sichuan Province, Natural Resources Institute", -"SPR s Springfield Science Museum, Natural Science Department", -"SPRY s Burton Constable Foundation", -"SPSF s Instituto Florestal", -"SPSU h St. Petersburg State University", -"SPT s Botanic Gardens Museum", -"SPTS s Southport Scientific Society", -"SPWH s Marine Biological Laboratory", -"SQB h Societe quebecoise de bryologie", -"SQF s Universidad de Chile, Laboratorio de Botanica, Escuela de Quimica y Farmacia", -"SQUH h Sultan Qaboos University", -"SR s Sichuan Institute of Natural Resources", -"SRAICC c SRAI's culture collection", -"SRCG s Baylor University", -"SRD s Passmore Edwards Museum", -"SRF s Shangrao Forestry Institute", -"SRFA s Universidad Nacional de La Pampa", -"SRGH s Botanic Garden", -"SRI s Serengetti Research Institute", -"SRNP s Insects of the Area Conservacion Guanacaste, northwestern Costa Rica", -"SRP s Boise State University, Biology Department", -"SRR s Koninklijke Shell (Shell Research N.V.)", -"SRRC c Southern Regional Research Center, Agricultural Research Service, United States Department of Agriculture", -"SRS h Universidade do Sul de Santa Catarina", -"SRSC s Sul Ross State University, Department of Biology", -"SRSU s Sul Ross State University", -"SS s Universita di Sassari, Dipartimento di Botanica ed Ecologia Vegetale", -"SSC s Sacramento State University", -"SSCMU c Soil Science and Conservation Department Faculty of Agriculture", -"SSCN s Musum of the Biological Laboratory", -"SSD s Sammlung Simon des Stattlichen Museum fur Mineralogie und Geologie Dresden", -"SSF s Sammlung des Senckenbrug-Museum", -"SSI c Statens Serum Institute", -"SSIC c Collaborating Centre for Reference and Research on Escherichia and Klebsiella", -"SSJC s San Joaquin County, Agriculture Department", -"SSKKU c Department of Soil Science, Faculty of Agriculture", -"SSL s Sammlung Langenhan an der Sektion Geophysik der Karl-Marx-Universitat Lepzig", -"SSLP s Rocky Mountain Research Station", -"SSM s Savannah Science Museum", -"SSM s Springfield Science Museum", -"SSMF s Great Lakes Forestry Centre, Canadian Forest Service", -"SSMJI c Science Section, Department of General Education, Faculty of Agricultural Business", -"SSMM s Shanxi School of Chinese Materia Medica", -"SSMS s Suriname State Museum", -"SSNR s Societa per GL Studi Naturalistica della Romagna", -"SSOFM s Sanabe Shizenkan Open Field Museum", -"SSPW s Perivale Wood Nature Reserve", -"SSU s Saratov State University", -"SSUC s Pontificia Universidad Catolica de Chile, Departamento de Ecologia", -"ST s Suzhou Teachers College, Biology Department", -"STA s University of St. Andrews, School of Environmental and Evolutionary Biology", -"STAL s Verulamium Museum", -"STAR s Arkansas State University, Biological Sciences Department", -"STASH s St. Beuno's College", -"STB s St. Bartholomew's Hospital", -"STC s Sichuan Teacher's College", -"STCR s Universite de la Reunion", -"STD s Prittlewell Priory Museum", -"STDCM s Southend Central Museum", -"STE s National Botanical Institute", -"STE-U c Culture collection of the Department of Plant Pathology, University of Stellenbosch", -"STEU sc University of Stellenbosch, Botany Department", -"STFX s St. Francis Xavier University, Biology Department", -"STG s St. Martin's Convent", -"STI s Stirling Smith Art Gallery and Museum", -"STIU s University of Stirling, Biological Sciences Department", -"STK s Stoke-on-Trent Athenaeum", -"STL s Instituto Nacional de Limnologia, Departamento Macrofitas", -"STM s Stettinger Museum", -"STM c Laboratoire des Symbioses Tropicales et Mediterraneennes", -"STM s Streatham Antiquarian and Natural History Society", -"STMC s School of Tropical Medicine", -"STNF h Shasta-Trinity National Forest", -"STO s The Potteries Museum & Art Gallery", -"STP s La Societe Guernesiaise, Priaulx Library", -"STPCM s Island Museum, Candie Gardens", -"STPE s Florida Marine Research Institute, Florida Department of Environmental Protection", -"STPH h Direccao Geral do Ambiente, Cabinet of Environment, Ministry of Natural Resources and Environment", -"STPS s St. Paul's School", -"STR s Institut de Botanique", -"STRI sc Smithsonian Tropical Research Institute", -"STRI:ICBG-Panama c Smithsonian Tropical Research Institute, International Cooperative Biodiversity Groups", -"STS s Stromness Museum", -"STT s St. Thomas's Hospital Medical School Library", -"STU s Staatliches Museum fuer Naturkunde Stuttgart", -"STUM s Santo Tomas University Museum", -"SU s Suzhou University", -"SU s Stanford University", -"SU s Oregon State University", -"SUA s Sokoine University of Agriculture, Forest Biology Department", -"SUB s Universitat Bonn", -"SUCEA s The University at Albany", -"SUCH s Sukhumi Botanical Garden of Georgian Academy of Sciences", -"SUCN s State University of California", -"SUCO s State University of New York, College at Oneonta, Biology Department", -"SUD s Stroud and District Museum", -"SUEL s Natural History Museum of Bakony Mountains", -"SUF s Shimonoseki University of Fisheries", -"SUFA h Sulaimania University", -"SUFAF h Siirt University Flora and Fauna Center", -"SUHC s Salisbury University, Department of Biology", -"SUK s Shivaji University Kolhapur", -"SUM s Okresni vlastivedne muzeum v Sumperku", -"SUM s Stellenbosch University", -"SUN s Sunderland Museum", -"SUND s Sunderland Natural History and Antiquarian Society", -"SUNIV s University of Stockholm", -"SUNY s State University of New York", -"SUNYO s State University of New York at Oneonta", -"SURCO h Universidad Surcolombiana", -"SUU h Southern Utah University", -"SUVA s University of the South Pacific", -"SUVM s Shippensburg University, Vertebrate Museum", -"SUWS s University of Wisconsin-Superior, Department of Biology and Earth Science", -"SV s Antigua Estacion Experimental Agronomica", -"SVCK c Sammlung von Conjugaten Kulturen", -"SVER s Institute of Plant and Animal Ecology, Laboratory of Plant Ecology and Geobotany", -"SVG s Arkeologisk museum i Stavanger", -"SVIEC c Secao de Virus", -"SVUTY h Sri Venkateswara University", -"SVVC s Seminario Vescovile", -"SWA s Swansea Museum", -"SWAT h University of Swat Pakistan", -"SWAU s Southwest Agricultural University, Horticulture Department", -"SWBR s Sweet Briar College, Biology Department", -"SWC s Sammlung des Cambridge, University of Zoology", -"SWC s Swarthmore College, Biology Department", -"SWCTU s Southwest Teachers University, Biology Department", -"SWE s Chandos House, Stowe School", -"SWF s Florida Gulf Coast University", -"SWFC s Southwest Forestry College", -"SWFSC s Southwest Fisheries Science Center", -"SWGC h Grenfell Campus, Memorial University of Newfoundland", -"SWIBASC s Academia Sinica", -"SWMT s Rhodes College, Biology Department", -"SWN s Saffron Walden Museum", -"SWNHS s Saffron Walden Horticultural Society", -"SWRS s Southwestern Research Station", -"SWSL s USDA/ARS, Southern Weed Science Research Unit", -"SWT s Southwest Texas State University, Department of Biology", -"SWTN s Swinton and Pendlebury Botanical Society", -"SWU h Sungshin Women's University", -"SWU2 c Department of Biology, Faculty of Science", -"SXAU s Shanxi Agricultural University, Forestry Department", -"SXDC s Shaanxi Institute for Drug Control", -"SXIM h Shaanxi Institute of Microbiology", -"SXMP s Shaanxi Academy of Traditional Chinese Medicine and Pharmacology", -"SXU s Shanxi University, Biology Department", -"SY s Shenyang Municipal Academy of Landscape Gardening", -"SYAU s Shenyang Agricultural University", -"SYAUF s Shenyang Agricultural University, Forestry Department", -"SYD s University of Sydney", -"SYKO s Komi Scientific Centre, Ural Division, Russian Academy of Sciences, Department of Geobotany and Plant Cover Restoration", -"SYKT s Syktyvkar State University, Botany Department", -"SYPC s Shenyang College of Pharmacy, Pharmaceutical Botany Department", -"SYR s Syracuse University, Plant Sciences Department", -"SYRF s State University of New York", -"SYS s Sun Yatsen University, Biology Department", -"SYS:Z s Sun Yatsen University, Biology Department, Zoology Collection", -"SYSBM s The Museum of Biology Sun Yat-sen University", -"SYSU s National Sun Yat-Sen University, Department of Biological Sciences", -"SYT s Stonyhurst College", -"SZ s Sichuan University, Biological Department", -"SZB s Haus der Natur", -"SZCU s Department of Systematic Zoology", -"SZCZ h University of Szczecin", -"SZE s Mora Ferenc Museum, Natural Science Department", -"SZE s Zoology Department, Aegean University, Science Faculty", -"SZG s Shenzhen Fairy Lake Botanical Garden", -"SZL s Landesherbar von Salzburg", -"SZM s Saitama Zoogeographical Museum", -"SZMC c Szeged Microbiological Collection", -"SZMN s Siberian Zoological Museum", -"SZPT s Shenzhen Polytechnic", -"SZPT:ENT s Shenzhen Polytechnic, Entomology Collection", -"SZU s University of Salzburg, Department of Organismic Biology", -"SZUB h University of Szczecin", -"T s Tavera, Department of Geology and Geophysics", -"TA s Timescale Adventures Research and Interpretive Center", -"TAA s Estonian Agricultural University, Institute of Agricultural and Environmental Sciences", -"TAAM s Institute of Agricultural and Environmental Sciences of the Estonian University of Life Sciences", -"TAC s Tarleton State University, Biological Sciences Department", -"TAD s Botanical Institute of the Tajikistan Academy of Sciences, Department of Flora and Systematics of Higher Plants", -"TAES s Texas A&M University, Department of Rangeland Ecology and Management", -"TAFIRI s Tanzania Fisheries Research Institute", -"TAI s National Taiwan University, Institute of Ecology and Evolutionary Biology", -"TAIC s Texas A&M University-Kingsville, Department of Biology", -"TAIE h Endemic Species Research Institute", -"TAIF s Taiwan Forestry Research Institute", -"TAIM s Taiwan Museum", -"TAIU s Texas A&M University - Kingsville, Texas A&I Collections", -"TAK s Lenin State University", -"TAL h Jardin botanique de Talence", -"TALE s Laboratoire Geologique", -"TALL s Tallinn Botanic Garden, Department of Environmental Education", -"TAM s Estonian Museum of Natural History, Botany Department", -"TAMA c Mycology & Metabolic Diversity Research Center, Tamagawa University Research Institute", -"TAMU s Texas A&M University, Biology Department", -"TAN s Parc de Tsimbazaza, Departement Botanique", -"TANE s Tanta University, Botany Department", -"TAR s Consiglio Nazionale delle Ricerche", -"TARI s Taiwan Agricultural Research Institute", -"TARI s Research Institute of Forests and Rangelands, Botanical Department", -"TARI s Trakya Agricultural Research Institute", -"TASH s National Academy of Science, Uzbekistan", -"TASM s Uzbek Academy of Sciences, Laboratory of Mycology", -"TAU s Aristotle University of Thessaloniki, Biology Department", -"TAU s Tel-Aviv University", -"TAUF s Aristotle University of Thessaloniki, Department of Forestry and Natural Environment", -"TAWES h Maryland Department of Natural Resources", -"TB s Tbilisi State University, Botany Department", -"TBG b Tsukuba Botanical Garden", -"TBGT s Tropical Botanic Garden and Research Institute", -"TBI s Georgian Academy of Sciences", -"TBIP s Research Institute of Plant Protection", -"TBPH h Iovel Kutateladze Institute of Pharmacochemistry", -"TBY s Tenby Museum", -"TCB s National Chung Hsing University, Botany Department", -"TCC/USP c Trypanosomatid Culture Collection, University of Sao Paulo", -"TCD s Trinity College", -"TCDL s Trinity College Library, Manuscript Department", -"TCDU b Trinity College, Dublin University, Department of Zoology DNA repository", -"TCDU s Ministry of Animal Industry and Fisheries", -"TCF s National Chung Hsing University, Forestry Department", -"TCFB c Tasmanian Collection of Fish Bacteria", -"TCMM c Thai Collection of Medical Microorganism, Department of Pathology, Faculty of Veterinary Science", -"TCNM s Timpanogos Cave National Monument", -"TCSW s Texas Women's University, Biology Department", -"TCWC s Texas Cooperative Wildlife Collection", -"TCWC:Birds s Texas Cooperative Wildlife Collection, Collection of Birds", -"TCWC:Fish s Texas Cooperative Wildlife Collection, Collection of Fishes", -"TCWC:Herp s Texas Cooperative Wildlife Collection, Collection of Amphibians and Reptiles", -"TCWC:Invrt s Texas Cooperative Wildlife Collection, Collection of Marine Invertebrate", -"TCWC:Mamm s Texas Cooperative Wildlife Collection, Mammal collection", -"TDA s Department of Agriculture, Tasmania", -"TDAH s Tasmanian Department of Agriculture", -"TDMP s Ta-Dzong Museum", -"TDN s Todmorden Botanical Society", -"TDNA b Toulouse DNA databank", -"TDY s Tyldesley Natural History Society", -"TEA s Tea Research Institute", -"TEB s Teberda State Reserve", -"TECLA s Centro Nacional de Tecnologia Agropecuaria", -"TEF s Centre National de la Recherche Appliquee au Developement Rural, Departement des Recherches Forestieres et Piscicoles", -"TEFH s Universidad Nacional Autonoma de Honduras, Departamento de Biologia", -"TEH s University of Tehran", -"TELA s Tel Aviv University, Botany Department", -"TELY s Tate Library", -"TENHS s Toynbee Natural History Society", -"TENN s Department of Ecology and Evolutionary Biology, University of Tennessee", -"TEPB s Universidade Federal do Piaui, Departamento de Biologia", -"TER s Indiana State University, Life Science Department", -"TESC s The Evergreen State College", -"TESRI s Taiwan Endemic Species Research Institute", -"TEU s Teikyo University, Education Department", -"TEUI h U.S. Forest Service Southwest Region, Terrestrial Ecological Unit Inventory", -"TEX s University of Texas at Austin, Plant Resources Center", -"TEXA s Blackland Experiment Station", -"TF s Forestry and Forest Products Research Institute", -"TF s Department of Mineral Resources", -"TFA s Forestry and Forest Products Research Institute", -"TFAV s Servicio Autonomo para el Desarrollo Ambiental del Estado Amazonas", -"TFC s Universidad de La Laguna, Departamento de Biologia Vegetal (Botanica)", -"TFC c Tartu Fungal Culture Collection", -"TFD s Tanzania Forestry Research Institute", -"TFDA s Tasmanian Fisheries Development Authority", -"TFIC s Tasmanian Forest Insect Collection", -"TFM s Forestry and Forest Products Research Institute", -"TFMC s Museo de Ciencias Naturales de Santa Cruz de Tenerife", -"TFRI s Taiwan Fisheries Research Institute", -"TGM s Janashia State Museum of Georgia", -"TGPI s Tiraspolskij Gosudarstvennij Pedagogiceskij Institut", -"TGRC b C.M. Rick Tomato Genetics Resource Center", -"TGU h University of Montenegro", -"TH s University of Tokyo", -"THBC s Technische Hochschule", -"THIB s Nicholls State University, Department of Biological Sciences", -"THIM s National Biodiversity Centre", -"THL s Grierson Museum", -"THO s Robert Dick Museum Library", -"THRI s Sequoia and Kings Canyon National Parks", -"THS s Tsumura Laboratory", -"THUP s Tunghai University", -"TI s Herbarium of the Department of Botany, University of Tokyo", -"TIC s California Department of Fish and Game", -"TIE s Tianjin Natural History Museum, Botany Department", -"TIK s Agricultural Research Centre, Plant Pathology Department", -"TIMGP s Institut und Museum fuer Geologie und Palaeontologie der Unversitaet", -"TIMJ s Tainai Insect Museum", -"TIMM c Institute of Medical Mycology", -"TIPR s Institute of Pharmaceutical Research", -"TISTR c TISTR Culture Collection Bangkok MIRCEN", -"TIU s Tokyo Imperial University, Science College Museum", -"TJDC s Tianjin Municipal Institute for Drug Control, Department of Traditional Chinese Medicine", -"TJMP s Tianjin Institute of Medical and Pharmaceutical Sciences", -"TK s Tomsk State University", -"TK s Coleccion de mamiferos del Centro Interdisciplinario de Investigacion para el Desarrollo Integral Regional Unidad Durango", -"TKB s University of Tsukuba", -"TKNM s Twickenham Girls' School", -"TKPM s Tokushima Prefectural Museum", -"TKU s Tokyo Kyoiku University", -"TL s Universite Paul Sabatier", -"TLA s Ecole Nationale Superieure Agronomique", -"TLF s Universite Paul Sabatier", -"TLHR s Thueringer Landesmuseum Heidecksburg", -"TLJ s Universite Paul-Sabatier", -"TLM s Museum d'Histoire Naturelle de Toulouse", -"TLMF s Tiroler Landesmuseum Ferdinandeum", -"TLON s Museum d'Histoire Naturelle", -"TLP s Faculte de Medecine, Chaire de Botanique", -"TLS s Tunbridge Wells Museum and Art Gallery", -"TLXM s Universidad Autonoma de Tlaxcala", -"TM s Teylers Museum, Paleontologische", -"TM s Slovak National Museum", -"TM s Transvaal Museum", -"TMAG s Tasmanian Museum & Art Gallery", -"TMAL s Tameside Metropolitan Borough Museum", -"TMBS s Tatsuo Tanaka Memorial Biological Laboratory", -"TMC s Tate Museum Collection", -"TMC c Trudeau Mycobacterial Culture Collection, Trudeau Institute", -"TMC c The Mollicutes Collection", -"TMDU s Tokyo Medical and Dental University", -"TMFE s Elasmobranchii Collection of the Department of Fisheries, Tokai University", -"TMH s Tasmanian Museum and Art Gallery", -"TMHN s Teyler Museum", -"TMI s Tottori Mycological Institute", -"TMM s Texas Memorial Museum", -"TMMC s Texas Memorial Museum", -"TMNH s Tianjin Museum of Natural History", -"TMP s Tampere Museums", -"TMP s Transvaal Museum", -"TMRC h Shahid Beheshti University of Medical Sciences", -"TMS s Toleco Museum of Health and Natural History", -"TMSA s Transvaal Museum", -"TMTC s Taiwan Provincial Museum", -"TNAU s Tamil Nadu Agricultural University", -"TNFC s Tynside Naturalists' Field Club", -"TNFS s USDA Forest Service, Alaska Region", -"TNHC s Texas Memorial Museum, Texas Natural History Collection", -"TNHM s University of Texas", -"TNM s National Museum of Natural Science, Botany Department", -"TNP s Museum of Tatra National Park", -"TNS s National Science Museum, Department of Botany", -"TNSC s Thierry Neef de Sainval", -"TNSC s Trailside Nature and Science Center", -"TNSM s Thailand Natural History Museum", -"TNU s National Taiwan Normal University, Herbarium", -"TNZ s Tianjin Nat. Hist. Mus.", -"TO s Universita degli Studi di Torino, Dipartimento di Biologia Vegetale", -"TOD s Todmorden Free Library", -"TOFO s University of Tokyo, Section of Forest Botany", -"TOGO s Universite du Lome, Laboratoire de Botanique et Ecologie Vegetale", -"TOGR s Museo di Storia Naturale Don Bosco", -"TOHO s Toho University", -"TOKE s Tokyo University of Education", -"TOLI s Universidad del Tolima, Departamento de Biologia", -"TOM s Istituto Missioni Consolata", -"TOM c Tomicus collection Canadian Forest Service", -"TON h Ministry of Agriculture and Food, Forestry and Fisheries", -"TONG s Tonghua Teachers College, Biology Department", -"TOR s Torquay Museum", -"TOU h University of Tours", -"TOYA s Toyama Science Museum, Botany Department", -"TPI s The Pirbright Institute", -"TPI:ENT s The Pirbright Institute, Entomology collection", -"TPII s Thanksgiving Point Institute", -"TPNG s Department of Primary Industry", -"TPV s Prairie View A & M University, Biology Department", -"TR s Museo Tridentino di Scienze Naturali", -"TRA s American Plant Life Society", -"TRD s Ancient House Museum", -"TRE s Trencianske muzeum, Scientific Department", -"TRES s Tresco Abbey", -"TRH s Norwegian University of Science and Technology, Department of Natural History", -"TRIN s The National Herbarium of Trinidad and Tobago", -"TRM s Vlastivedne muzeum Trutnov", -"TRN s N. Copernicus University", -"TRO s Royal Horticultural Society of Cornwall", -"TROM s University of Tromsoe, Botanical Department", -"TROY s Troy State University, Department of Biological and Environmental Sciences", -"TRPM h Tottori Prefectural Museum", -"TRT s Royal Ontario Museum, Department of Natural History", -"TRTC s Royal Ontario Museum, Center for Biodiversity and Conservation Biology", -"TRTE s Erindale College, University of Toronto, Department of Biology", -"TRTS s Scarborough College, University of Toronto, Botany Department", -"TRU s Royal Cornwall Museum", -"TRV s Transvaal Museum", -"TS s National University of Shandong, Biology Department", -"TSB s Universita degli Studi di Trieste, Dipartimento di Biologia", -"TSC s Tarleton State University, Tarleton State Collection", -"TsGM s Central Geological Museum", -"TSH h University of Tsukuba", -"TSM s Erbario, Museo Civico di Storia Naturale, Trieste", -"TSMHN s Teylers Strichtina Museum", -"TsNIGRI s Tsentralny Nauchno-Issledovatelskii Geolgo-Razvedochni Muzei (Chernyshev's Central Museum of Geological Exploration)", -"TSSMC s Teton Science School", -"TSTN s Troston Hall", -"TSU s Miye University", -"TSY c Laboratory of Mycology, Division of Microbiology", -"TTC s Texas Tech University, Biological Sciences Department", -"TTCC s Texas Tech University", -"TTMB s Termeszettudomanyi Muzeum", -"TTN s Somerset County Museum", -"TTRS s Tall Timbers Research Station, Fire Ecology Laboratory", -"TTU s Texas Tech University, Museum", -"TTY s Westonbirt School", -"TU s Institut fur Geologie und Palaontologie, Technische Universitat Braunschweig", -"TU s University of Tartu, Botanical and Mycological Museum", -"TU s Tulane University, Museum of Natural History", -"TU:Birds s Tulane University, Museum of Natural History, Ornithological Collection", -"TU:Fish s Tulane University, Museum of Natural History, Fish Collection", -"TU:Herptiles s Tulane University, Museum of Natural History, Amphibian And Reptile Collection", -"TU:Invertebrates s Tulane University, Museum of Natural History, Invertebrate Collection", -"TU:Mammals s Tulane University, Museum of Natural History, Mammal Collection", -"TUAT s Tokyo University of Agriculture", -"TUB s Eberhard-Karls-Universitaet Tuebingen, Institut fuer Biologie I", -"TUBSB b Tohoku University Brassica Seed Bank", -"TUC s University of Arizona, Ecology and Evolutionary Biology Department", -"TUCH s Tribhuvan University, Central Department of Botany", -"TUCIM c TU Wien collection of industrial microorganisms", -"TUCIM: c TU Wien collection of industrial microorganisms, ", -"TUFC s Tottori University Fungal Culture Collection", -"TUFIL s Tokyo University of Fisheries, Ichthyological Laboratory", -"TUFT s Tufts University, Biology Department", -"TUH s Tehran University, Department of Biology", -"TULE s Tokyo University of Agriculture & Technology", -"TULS s University of Tulsa", -"TULV s Jardin Botanico Juan Maria Cespedes", -"TUM h Technische Universitat Munchen", -"TUMH s Tottori Fungus/Mushroom Resource and Research Center", -"TUN s Universite de Tunis, Laboratoire de Biologie Vegetale", -"TUNG s Tunghai University, Biology Department", -"TUP s Trent University, Biology Department", -"TUPH s Institute of Public Health Research", -"TUR s University of Turku", -"TURA s Aabo Akademi University, Biology Department", -"TURP s Turpan Eremophytes Botanical Garden", -"TUS s Tohoku University, Biological Institute", -"TUSG s Tohoku University", -"TUT s Daejeon University, Department of Biology", -"TUTC s Tunghai University", -"TUZ s Tartu University Zoological Department", -"TV s Centro de Estratigrafia e Paleobiologia da Universidade Nova de Lisboa", -"TVBG s Tver State University", -"TVY s Turvey Abbey", -"TWC s Texas Wesleyan College, Museum of Zoology", -"TWRA s Tennessee Wildlife Resources Agency", -"TYF s Shangxi Forestry Institute", -"TYM h Botanic Gardens of Toyama", -"TZM s National Science Museum", -"U s Nationaal Herbarium Nederland, Utrecht University branch", -"UA s Department of Historical Geology and Paleontology", -"UA s University of Alabama Collection", -"UA s University of Arizona", -"UAAAC s University of Alaska Anchorage Avian Collection", -"UAAH s Herbarium, Department of Biological Sciences, University of Alaska Anchorage", -"UAAM s The Arthropod Museum, University of Arkansas", -"UAB s Universidad Autonoma de Barcelona", -"UABC s Universidad Autonoma de Baja California", -"UABCS s Universidad Nacional Autonoma de Baja California Sur (Mexico)", -"UABD s University of Alabama", -"UAC s University of Calgary, Department of Biological Sciences", -"UACC s Univeridad Autonoma de Chapingo", -"UACCC c University of Alabama Chytrid Culture Collection", -"UADBA s University dAntananarivo, Department de Biologie Animale", -"UADY s Universidad Autonoma de Yucatan, Departamento de Botanica", -"UAEM s Univeridad Autonoma de Morelos", -"UAEU s United Arab Emirates University", -"UAGC s Universidad Autonoma de Guerrero, Area de Ciencias Naturales", -"UAIC s University of Abidjan", -"UAIC s University of Alabama, Ichthyological Collection", -"UAIC s University of Arizona", -"UALRVC s University of Arkansas at Little Rock, Vertebrate Collection", -"UAM s University of Alaska, Museum of the North", -"UAM:Bird s University of Alaska, Museum of the North, Bird Collection", -"UAM:Bryo s University of Alaska, Museum of the North, Bryozoan Collection", -"UAM:Crus s University of Alaska, Museum of the North, Marine Arthropod Collection", -"UAM:Ento s University of Alaska, Museum of the North, Insect Collection", -"UAM:ES s University of Alaska, Museum of the North, Earth Science", -"UAM:Fish s University of Alaska, Museum of the North, Fish Collection", -"UAM:Herb s University of Alaska, Museum of the North, UAM Herbarium", -"UAM:Herp s University of Alaska, Museum of the North, Amphibian and Reptile Collection", -"UAM:Mamm s University of Alaska, Museum of the North, Mammal Collection", -"UAM:Moll s University of Alaska, Museum of the North, Mollusc Collection", -"UAM:Paleo s University of Alaska, Museum of the North, paleontology collection", -"UAM c Universidad Autonoma De Madrid culture collection of cyanobacteria", -"UAM s University of Alabama, Malacology Collection", -"UAM s University of Arkansas at Monticello", -"UAM s Universidad de los Andes, Facultad de Ciencias", -"UAMH scb University of Alberta Microfungus Collection and Herbarium", -"UAMI s Universidad Autonoma Metropolitana, Unidad Iztapalapa (Mexico)", -"UAMIZ s Universidad Autonoma Metropolitana, Iztapalapa, Departamento de Biologia", -"UAMM s Universidad de los Andes", -"UAMZ s University of Alberta Museum of Zoology", -"UAMZC s University of Arkansas, Museum Zoological Collections", -"UANL s Universidad Autonoma de Nuevo Leon", -"UAPC h University of Alberta", -"UARK s University of Arkansas", -"UAS s Universidad Autonoma de Sinaloa", -"UAS-B s University of Agricultural Sciences Bangalore", -"UASB s University of Agricultural Sciences, Bangalore", -"UASC s Museo de Historia Natural \"Noel Kempff Mercado\"", -"UASK s Ukrainian Academy of Science", -"UASM s University of Alberta, E.H. Strickland Entomological Museum", -"UAT s Universidad Autonoma de Tamaulipas", -"UAVP s University of Alberta, Laboratory for Vertebrate Paleontology", -"UAWC b Union of Agricultural Work Committees", -"UAY s Universidad Autonoma de Yucatan, Facultad de Medicina Veterinaria y Zootecnia", -"UAZ s University of Arizona", -"UB sc University of Brasilia Herbarium", -"UB s Laboratoire de Biostratigraphie", -"UBA s Mongolian Academy of Sciences", -"UBC s Beaty Biodiversity Museum, University of British Columbia", -"UBC:CTC s Beaty Biodiversity Museum, University of British Columbia, Cowan Tetrapod Collection", -"UBC:Fish s Beaty Biodiversity Museum, University of British Columbia, Fish Collection", -"UBCC c University of Barcelona Culture Collection", -"UBCZ s University of British Columbia, Spencer Entomological Museum", -"UBDH h Universiti Brunei Darussalam", -"UBJTL s Universidad Bogota Jorge Tadeo Lozano", -"UBL s Universite du Benin", -"UBOCC c Universite de Bretagne Occidentale", -"UBT s Oekologisch-Botanischer Garten", -"UBU s Mongolian State University, Botany Department", -"UC scb University of Canberra Wildlife Tissue Collection", -"UC s University of California, University Herbarium", -"UC c Upjohn Culture Collection", -"UCAC s University of Central Arkansas, Department of Biology", -"UCAM s Universidad Autonoma de Campeche", -"UCB s University of California at Berkeley", -"UCBG s University of Botswana, Department of Biological Sciences", -"UCBL s Centre de Paleontologie Stratigraphique et Paleoecologie", -"UCBMG c University of California Berkeley Mycogarden", -"UCC s University of Cincinnati", -"UCC s University College Cork", -"UCCC s Universidad de Concepcion, Museo de Zoologia", -"UCCM c University of Calabar Collection of Microorganisms", -"UCD scb University of California, Davis", -"UCDBA s University of Chicago", -"UCFC s University of Central Florida", -"UCGC s University of Colorado, Geological Museum", -"UCGE c Unit Cell of Genetic Engineering, Department of Biochemistry", -"UCH h Universidad Autonoma de Chiriqui", -"UCHT s University of Tennessee, Chattanooga, Department of Biological and Environmental Sciences", -"UCI s University of Ibadan, Botany and Microbiology Department", -"UCJ s Universite d'Abidjan, Departemente de Botanique", -"UCL c Catholic University of Louvain", -"UCL s University College London", -"UCLA s University of California at Los Angeles", -"UCLAF c HMR/Romainville", -"UCLGMZ s Grant Museum of Zoology and Comparative Anatomy", -"UCLZ s University College London", -"UCM s Universidad Complutense Madrid", -"UCM c Ukrainian Collection of Microorganisms, Zabolotny Institute of Microbiology and Virology", -"UCM s University of Colorado Museum", -"UCM:Bird s University of Colorado Museum, University of Colorado Museum Bird Collection", -"UCM:Fish s University of Colorado Museum, University of Colorado Museum Fish collection", -"UCM:Herp s University of Colorado Museum, University of Colorado Museum Amplibian and Reptile collection", -"UCM:Mamm s University of Colorado Museum, University of Colorado Museum Mammal Collection", -"UCMC s University of Colorado Museum", -"UCME s Faculdad de Biologia, Departamento de Zoologia", -"UCMM s Pontificia Universidad Catolica Madre y Maestra", -"UCMP s University of California Museum of Paleontology", -"UCMS s Storrs, University of Connecticut", -"UCNW s University of Wales", -"UCNZ s University of Canterbury", -"UCOB s Universidad Centroccidental Lisandro Alvarado, Departamento de Ciencias Biologicas", -"UCOCV s University of Central Oklahoma, Collection of Vertebrates", -"UCONN s University of Connecticut", -"UCP s Universidad del Cauca", -"UCPC s Universidad del Cauca", -"UCR s Universidad de Costa Rica, Museo de Zoologia", -"UCR s University of California, Riverside", -"UCR:ENT s University of California, Riverside, Entomology Collection", -"UCS s University of Connecticut", -"UCS s Union College, Department of Biological Sciences", -"UCSA s University College of Swansea, Botany Department", -"UCSB s University of California, Santa Barbara", -"UCSC s University of California, Department of Environmental Studies", -"UCSW s University College, Botany Department", -"UCVC s Universidad Catolica de Valparaiso", -"UCWI s University of the West Indies, Department of Life Sciences", -"UDBC s Universidad Distrital", -"UDCC s University of Delaware", -"UDEL s University of Delaware", -"UDM s Museo Friulano di Storia Naturale", -"UDO s Universidad de Oriente", -"UDONECI s Universidad de Oriente", -"UDSM s University of Dar es Salaam", -"UDU s Udmurt State University, Department of Biology and Chemistry", -"UDW s University of Durban-Westville, Botany Department", -"UEA s University of East Anglia", -"UEC s Universidade Estadual de Campinas, Departamento de Botanica", -"UEFS s Laboratorio de Ictiologia", -"UENF s Universidade Estadual do Norte Fluminense", -"UESC h Universidade Estadual de Santa Cruz", -"UESS s Universidad de El Salvador", -"UEVH s Universidade de Evora, Departamento de Biologia", -"UF sb University of Florida Museum of Natural History", -"UF/FGS s Florida Geological Survey", -"UF:Herpetology s University of Florida Museum of Natural History, Herpetology Collection", -"UF:Ichthyology s University of Florida Museum of Natural History, Fish Collection", -"UF:Invertebrate s University of Florida Museum of Natural History, Invertebrate Zoology and Malacology Collection", -"UF:Mammalogy s University of Florida Museum of Natural History, Mammalogy Collection", -"UF:Ornithology s University of Florida Museum of Natural History, Ornithology Skins and Skeletons Collection", -"UF:Porifera s University of Florida Museum of Natural History, ", -"UFA s Ufa Scientific Centre, Russian Academy of Sciences", -"UFACPZ h Universidade Federal do Acre/Parque Zoobotanico", -"UFC s Universidade Federal do Ceara, Departamento de Biologia", -"UFES s Universidade Federal do Espirito Santo", -"UFG s Universidade Federal de Goias, Unidade de Conservacao", -"UFH s University of Fort Hare, Botany Department", -"UFHNH s Utah Field House of Natural History State Park", -"UFJF s Universidade Federal de Juiz de Fora", -"UFMA s Universidade Federal do Maranhao, Curso de Farmacia", -"UFMG s Universidade Federal de Minas Gerais", -"UFMI s Universidade Federal de Mato Grosso, Instituto de Biociencias", -"UFMT s Universidade Federal de Mato Grosso", -"UFNH s Utah Field House Natural History [address unknown]", -"UFOP s Universidade Federal de Ouro Preto", -"UFP s Universidade Federal de Pernambuco, Departamento de Botanica", -"UFPB s Departamento de Sistematica e Ecologia", -"UFPEDA c Universidade Federal de Pernambuco", -"UFRG s Instituto de Biologia", -"UFRGS s Universidade Federale do Rio Grande do Sul", -"UFRJ sc Herbario e Colecao Fitopathologica \"Verlande Duarte Silveira\"", -"UFRJ s Departramento de Zoologia, Universidade Federal do Rio de Janeiro", -"UFRJIM c Departamento de Microbiologia Medica", -"UFRN s Universidade Federal do Rio Grande do Norte", -"UFRR h Universidade Federal de Roraima", -"UFS s Nyabyeya Forestry College, Department of Environmental Forestry", -"UFSC s Universidade Federal de Santa Catarina", -"UFScarCC c Freshwater Microalgae Collection Cultures", -"UFU h Ural Federal University", -"UFVB s Vicosa, Universidade Federal de Vicosa, Museum of Entomology", -"UG s Museo del Departamento de Estratigrafia y Paleontologia", -"UG s University of Ghana", -"UGAMNH s University of Georgia Museum of Natural History", -"UGCA s University of Georgia", -"UGDA s Gdansk University, Department of Plant Taxonomy and Nature Conservation", -"UGDZ s University of Guelph, Department of Zoology", -"UGG s University of Guam", -"UGGE s Universidad de Guayaquil", -"UGGG s University of Guyana", -"UGM s University of Guam", -"UGMD s Zoology Museum of the University of Ghent", -"UH s University of Hawaii", -"UHCC c University of Helsinki Cyanobacteria Culture Collection", -"UHI s Ussishkin House, Botany Department", -"UHM s Manoa, College of Tropical Agriculture, Department of Entomology", -"UI s University of Ibadan", -"UI s Bureau of Land Management", -"UICC c University of Indonesia Culture Collection", -"UIDA s University of Idaho, Bird and Mammal Museum", -"UIM s University of Idaho", -"UIMNH s University of Illinois, Museum of Natural History", -"UIS s Universidad Industrial de Santander, Departamento de Biologia", -"UIS:H s Universidad Industrial de Santander, Departamento de Biologia, Collecion Herpetologica", -"UISMHN s Universidad Industrial de Santander, Museo de Historia Natural", -"UJAT s Universidad Juarez Autonoma de Tabasco", -"UJB c University of Jaffna Botany", -"UJIM s University of Jordan Insect Museum", -"UK s University of Kentucky", -"UKEN s University of Kentucky", -"UKKP c Universiti Kebangsaan Kultur Perubatan", -"UKKY s University of Kunming", -"UKM s Universitaetsklinikum Muenster", -"UKMB s Universiti Kebangsaan Malaysia, Botany Department", -"UKMHC s Universiti Kebangsaan Malaysia", -"UKMHC:HC s Universiti Kebangsaan Malaysia, Herpetological Collection", -"UKMS s Universiti Kebangsaan Malaysia, Kampus Sabah", -"UKMS s Sudan Natural History Museum", -"UKS s University of Khartoum", -"UKSPI s Ust-Kamenogorsk State Pedagogical Institute, Botany Department", -"UL s University of Louisville", -"ULABG s Universidad de los Andes, Laboratorio de Biogeografia", -"ULCI s Universidad de la Laguna", -"ULF s Universite Laval, Departement des Sciences forestieres", -"ULKY s University of Louisville", -"ULLZ s University of Louisiana at Layafette Zoological Collection", -"ULM s Universitaet Ulm, Abteilung Systematische Botanik und Oekologie", -"ULMG s University of Leipzig", -"ULN s University of Lagos", -"ULQC s University of Laval", -"ULS s Universidad de La Serena, Departamento de Biologia", -"ULT s Al-Faateh University, Botany Department", -"ULV s Universidad Central de Las Villas", -"UM s University of Marburg", -"UM s University of Memphis, Mammal Collection", -"UM s Umtali Museum", -"UMA s University of Massachusetts, Museum of Zoology", -"UMAN s University of Manitoba, Zoological Collection", -"UMB s Uebersee-Museums", -"UMBB s Uebersee-Museum, Bremen or Department of Zoology, University of Bremen", -"UMBC s Univeristy of Malawi", -"UMBS s University of Michigan", -"UMD s University of Minnesota, Duluth", -"UMDC s University of Maryland", -"UMDE s University of Maine", -"UME s Umeaa University", -"UMEC s University of Massachusetts", -"UMED s University of Moi", -"UMF s University of Miami", -"UMF s University of Maine, Farmington", -"UMF s University of Michigan, Biology Department", -"UMFFTD c Food and Fermentation Technology Division, University of Mumbai", -"UMFK s University of Maine at Fort Kent, Biology Department", -"UMH s Universidad Miguel Hernandez, Departamento de Biologia Aplicada", -"UMHB s University of Mary Hardin-Baylor", -"UMIC s University of Mississippi", -"UMIM s Univeristy of Miami Ichthyological Museum", -"UMIP c Collection de Champignons et Actinomycetes Pathogenes", -"UMKC s University of Missouri", -"UMKL s University of Malaysia", -"UMKU s Uganda Museum", -"UMM h University of Maine at Machias", -"UMML s University of Miami Marine Laboratory", -"UMMP s University of Michigan", -"UMMZ s University of Michigan, Museum of Zoology", -"UMMZ:MC s University of Michigan, Museum of Zoology, Mollusk Collection", -"UMNH s Utah Museum of Natural History", -"UMNH:Mamm s Utah Museum of Natural History, Mammal collection", -"UMO s University Museum of Natural History", -"UMO s University of Maine", -"UMO s Dunn-Palmer Herbarium, University of Missouri, Museum Support Center", -"UMOC s University of Missouri, Museum of Zoology", -"UMRC c University of Minnesota Rhizobium Collection", -"UMRM s W.R. Enns Entomology Museum", -"UMS s Universiti Malaysia Sabah", -"UMSA s Instituto de Ecologia", -"UMSP s University of Minnesota", -"UMSS s Universidad Mayor de San Simon, Facultad de Ciencias y Tecnologia, Centro de Biodiversidad, Zoologia,Laboratorio de Ictiologia", -"UMT s Mutare Museum", -"UMUT s University Museum, University of Tokyo", -"UMUTZ s Department of Zoology, University Museum", -"UMZ s Univesity Museum of Zoology, Cambridge University", -"UMZC s University Museum of Zoology Cambridge", -"UMZM s University of Montana, Zoological Museum", -"UN s University of Nebraska", -"UNA s University of Alabama, Department of Biological Sciences", -"UNAB s Universidad Nacional, Facultad de Agronomia", -"UNAC s Universidad Nacional Agraria", -"UNAD s Universidad Nacional Agraria", -"UNAF s University of North Alabama, Department of Biology", -"UNAH s Universidad Nacional Autonoma de Honduras", -"UNAM s Universidad Nacional Autonoma de Mexico", -"UNAM:CNAC s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Acaros", -"UNAM:CNAN s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Aracnidos", -"UNAM:CNAR s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Anfibios", -"UNAM:CNAV s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Aves", -"UNAM:CNCR s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Crustaceos", -"UNAM:CNHE s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Helmintos", -"UNAM:CNIN s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Insectos", -"UNAM:CNMA s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Mamiferos", -"UNAM:CNMO s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Moluscos", -"UNAM:CNPE s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Peces", -"UNAM:CNPGG s Universidad Nacional Autonoma de Mexico, Coleccion Nacional del Phylum Porifera Gerardo Green", -"UNAN s Universidad Nacional Autonoma de Nicaragua", -"UNB s Connell Memorial Herbarium", -"UNC-B s University of Northern Colorado", -"UNCA h University of North Carolina at Asheville", -"UNCB s Universidad Nacional de Colombia, Insituto de Ciencias Naturales de la Universidad Nacional", -"UNCC s Universidad Nacional de Caldas, Museo de Historia Natural", -"UNCC s University of North Carolina, Biology Department", -"UNCG c University of North Carolina at Greensboro", -"UNCM s Museo de Entomologia \"Francisco Luis Gallego\"", -"UNCP s Universidad Nacional de Colombia", -"UNCW s University of North Carolina at Wilmington", -"UND s University of North Dakota, Vertebrate Museum", -"UNDH s University of Natal Durban", -"UNEFM s Universidad Experimental Francisco de Miranda", -"UNEVR s University of Nevada, Museum of Biology", -"UNEX s Universidad de Extremadura, Departamento de Botanica", -"UNEX:FECRGA c Universidad de Extremadura, Departamento de Botanica, Fungal Endophytes Collection of the Research Group of Agronomy", -"UNH s University of New Hampshire", -"UNI s University of Northern Iowa", -"UNIMAS s Universiti Malaysia Sarawak", -"UNIN s University of the North, Botany Department", -"UNIP s Universidade Paulista, Laboratorio de Botanica", -"UNIQEM c Institute of Microbiology, Russian Academy of Sciences", -"UNITEC h Unitec Institute of Technology", -"UNL s Universidad Autonoma de Nuevo Leon", -"UNL s Centro de Estratigrafia e Paleobiologia da Universidade Nova de Lisboa", -"UNL s University of Nebraska State Museum", -"UNLO s Universidad Nacional Experimental de los Llanos Occidental", -"UNLP s Universidad Nacional de La Plata", -"UNLV s University of Nevada, Las Vegas, Department of Biological Sciences", -"UNM s University of New Mexico, Department of Biology", -"UNMC s University of New Mexico", -"UNMDP s Universidad Nacional de Mar del Plata, Mar del Plata, Argentina", -"UNN s University of Nigeria, Botany Department", -"UNNF s Universite de Nancy", -"UNO s University of Nebraska at Omaha", -"UNOAL s University of Northern Alabama", -"UNOVC s University of New Orleans", -"UNPSJB-Pv s Universidad Nacional de la Patagonia", -"UNR s Universidad Nacional de Rosario, Botanica y Ecologia Vegetal", -"UNR s University of Nevada, Museum of Biology", -"UNS s University of Science, Ho Chi Minh City, Vietnam", -"UNSA s University of Natal", -"UNSL s Universidad Nacional de San Luis", -"UNSM s University of Nebraska State Museum", -"UNSW c Microbiology Culture Collection, University of New South Wales", -"UNSW s John T. Waterhouse Herbarium", -"UNT s Universidad nacional de Tucumn", -"UNWH s University of North-West, Biological Sciences Department", -"UO s University of Oklahoma", -"UO s University of Ostrava", -"UOA/HCPF c UOA/HCPF University of Athens/Hellenic Collection of Pathogenic Fungi", -"UOG s University of Guelph", -"UOG:BIO b University of Guelph, Biodiversity Institute of Ontario", -"UOG:DEBU s University of Guelph, Ontario Insect Collection", -"UOIC s University of Oregon", -"UOJ s Universidad del Oriente, Departamento de Agronomia", -"UOM s University of Missouri", -"UOMNH s University of Oregon, Museum of Natural History", -"UOMZ s University of Oklahoma, Stovall Museum of Zoology", -"UOP s University of Opole", -"UOPJ s Osaka Prefecture University", -"UOS s University of the South, Biology Department", -"UP s University of Papua and New Guinea", -"UPA s University of Patras, Department of Plant Biology", -"UPCB s Universidade Federal do Parana, Departamento de Botanica", -"UPCC c Natural Sciences Research Institute Culture Collection", -"UPCT h Universidad Politecnica De Cartagena", -"UPEI s University of Prince Edward Island, Biology Department", -"UPF s Universite de Polynesie Francaise Herbarium", -"UPIE b Unidad de Patologia Infecciosa y Epidemiologia", -"UPLB s Museum of Natural History, University of the Philippines", -"UPM s Departement des Siences de la Terre", -"UPM s Universiti Pertanian Malaysia, Biology Department", -"UPM s Udory Paleontological Museum", -"UPMR c Rhizobium Collection", -"UPMSI s Marine Science Institute", -"UPNA s Universidad Publica de Navarra, Departamento de Ciencias del Medio Natural", -"UPNG s University of Papua New Guinea, Division of Biological Sciences", -"UPOL s University Palacky Olomouc", -"UPOS s Universidad Pablo de Olavide, Ciencias Ambientales (Botanica)", -"UPP s Uppingham School Museum", -"UPPC s University of the Philippines", -"UPR s Puerto Rico Botanic Garden, University of Puerto Rico", -"UPRG s Universidad Nacional \"Pedro Ruiz Gallo\"", -"UPRM c University of Puerto Rico at Mayagueez, Rhizobium Culture Collection", -"UPRP s University of Puerto Rico at Rio Piedras", -"UPRRP s University of Puerto Rico, Biology Department", -"UPS s Uppsala University, Museum of Evolution, Botany Section (Fytoteket)", -"UPSA s University of Pretoria", -"UPSC c Fungal Culture Collection at the Botanical Museum", -"UPSU s Ulyanovsk State Pedagogical University, Department of Botany", -"UPSV s Uppsala University, Department of Plant Ecology", -"UPTC s Universidad Pedogogica y Tecnologica de Colombia, Escuela de Ciencias Biologicas", -"UPVB s Departamento de Geologia, Universidad del Pais Vasco", -"UPVLP s Laboratorio de Paleontolgia of the Universdad del Pais Vasco/Euskal Herriko Unibersitatea", -"UQAM s Universite du Quebec a Montreal, Departement des Sciences biologiques", -"UQAR s Universite du Quebec a Rimouski, Departement de biologie", -"UQIC s University of Queensland Insect Collection", -"UQTR s Universite du Quebec a Trois-Rivieres, Departement de chimie-biologie", -"URB s Ryukyu University Department of Zoology", -"URIC s University of Rhode Island", -"URIMC s University of Rhode Island, Mammal Collection", -"URM c Universidade Federal de Pernambuco", -"URM s University of the Ryukyus", -"URMU s Museo Nacional de Historia Natural, Montevideo", -"URO s University of the Ryukyus", -"URP s Museo de Historia Natural, Universidad Ricardo Palma", -"URT s Universita degli Studi di Roma Tre, Dipartimento di Biologia", -"URV s University of Richmond, Biology Department", -"US s Smithsonian Institution, Department of Botany", -"US s University of Stellenbosch", -"USA s University of South Alabama", -"USAC s University of Western Australia", -"USAC s Universidad de San Carlos de Guatemala", -"USAM s University of South Alabama, Department of Biological Sciences", -"USANHC s University of South Alabama, Vertebrate Natural History Collection", -"USAS s University of Regina, Biology Department", -"USB c Bacterial collection of Universita degli studi della basilicata, Dipartimento di Biologia", -"USBCF s U. S. Bureau of Commercial Fisheries", -"USBS s School of Biological Sciences, University of Science", -"USC s University of Southern California, Biological Sciences Department", -"USCC s University of Southern Colorado", -"USCG s Universidad de San Carlos de Guatemala", -"USCH s University of South Carolina, Department of Biological Sciences", -"USCP s University of San Carlos", -"USCS s University of South Carolina, Science and Mathematics Department", -"USCWH s United Services College", -"USD s Universidad Autonoma de Santo Domingo", -"USD s University of South Dakota", -"USDA sb United States Department of Agriculture", -"USDA:CFRA b United States Department of Agriculture, Corvallis Fragaria Catalog", -"USDA:GRIN b United States Department of Agriculture, Germplasm Resources Information Network", -"USDA:NCGR b United States Department of Agriculture, National Clonal Germplasm Repository", -"USDA:NSGC sb United States Department of Agriculture, National Small Grains Collection", -"USDA:PGRU sb United States Department of Agriculture, Plant Genetic Resources Unit", -"USDA:USNPC s United States Department of Agriculture, US National Parasite Collection", -"USDAK s W. H. Over State Museum", -"USF s University of South Florida, Biology Department", -"USF:CBD c University of South Florida, Biology Department, Center for Biological Defense", -"USFC s U. S. Fish Commission", -"USFS s Rocky Mountain Forest and Range Experiment Station", -"USGS s U.S. Geological Survey", -"USGS:ASC s U.S. Geological Survey, Alaska Science Center", -"USH s Ushaw College", -"USI s University of Southern Indiana", -"USJ s Universidad de Costa Rica", -"USLH s University of Louisiana Lafayette, Department of Renewable Resources", -"USM s Universiti Sains Malaysia", -"USM:VCRU s Universiti Sains Malaysia, Vector Control Research Unit", -"USM s Universidad Nacional Mayor de San Marcos, Museo de Historia Natural, Herbario", -"USMMC s Universiti Sains Malaysia Mollusc Collection", -"USMP h Universiti Sains Malaysia", -"USMS s University of Southern Mississippi, Department of Biological Sciences", -"USNC s Smithsonian Institution, Paleobiology Department", -"USNM sb National Museum of Natural History, Smithsonian Institution", -"USNM:Birds s National Museum of Natural History, Smithsonian Institution, Division of Birds", -"USNM:ENT s National Museum of Natural History, Smithsonian Institution, Entomology Collection", -"USNM:FISH s National Museum of Natural History, Smithsonian Institution, National Fish Collection", -"USNM:Herp s National Museum of Natural History, Smithsonian Institution, Division of Amphibians and Reptiles", -"USNM:IZ s National Museum of Natural History, Smithsonian Institution, Department of Invertebrate Zoology", -"USNM:LAB b National Museum of Natural History, Smithsonian Institution, Laboratories of Analytical Biology", -"USNM:MAMM s National Museum of Natural History, Smithsonian Institution, Division of Mammals", -"USNTC s U.S. National Tick Collection", -"USON s Universidad de Sonora, Departamento de Investigaciones Cientificas y Technologicas", -"USP s Universidade de Sao Paulo", -"USP s Universidad San Pablo-CEU (Departamento de Biologia Vegetal (seccion Botanica)", -"USP s University of the South Pacific", -"USPIY s K. D. Ushinsky Yaroslavl State Pedagogical University, Department of Botany", -"USRC s University of Regina", -"USRCB c Ukrainian Scientific-Research Cell Bank.", -"USSC s U.S. Soil Conservation Service", -"USTF s Technologische Faculteit", -"USTK s University of Science and Technology, Museum of Natural History", -"USU s United States Department of Agriculture", -"USUUB h Utah State University Uintah Basin", -"USZ s Universidad Autonoma Gabriel Rene Moreno", -"UT s University of Tennessee", -"UT s University of Utah Herbarium", -"UTA s University of Texas at Arlington", -"UTA:A s University of Texas at Arlington, Amphibian Collection", -"UTA:R s University of Texas at Arlington, Reptile collection", -"UTAI s Tel Aviv University", -"UTC s Utah State University, Biology Department", -"UTCI s University of Tennessee at Chattanooga Insect Collection", -"UTD s University of Texas, Plant Resources Center", -"UTE s University of Tartu", -"UTEP s University of Texas at El Paso, Centennial Museum", -"UTEP:Herp s University of Texas at El Paso, Centennial Museum, Herpetology Collection", -"UTEX c The Culture Collection of Algae at the University of Texas Austin", -"UTG s University of Tuebingen", -"UTGD s Geology Department, The University of Tasmania", -"UTHSC c University of Texas Health Science Center", -"UTIM s University of Tennessee Insect Museum", -"UTKI s University of Teheran", -"UTLH s University of Technology, Human Sciences Department", -"UTLPA s University of Texas at Austin, Laboratory of Physical Anthropology", -"UTMC s Universidad del Magdalena", -"UTMZ s University of Tennessee, Museum of Zoology", -"UTV s Universita degli Studi della Tuscia, Dipartimento di Agrobiologia e Agrochimica", -"UTZM s University of Tsukubo", -"UU s University of Uppsala", -"UU s Uzhgorod State University, Botany Department", -"UU s University of Utah, Department of Biology", -"UUC c Janet A. Robertson Collection of Ureaplasma urealyticum Cultures", -"UUDE h Buryat State University", -"UUH s Institute of General and Experimental Biology, Department of Floristics and Geobotany", -"UUVP s University of Utah, Vertebrate Paleontology", -"UUZM s Uppsala University, Zoological Museum", -"UV s University of Valparaiso", -"UV s Departamento de Biologia de la Universidad del Valle", -"UVA s Geological Institute of the University of Amsterdam", -"UVAL s Universidad del Valle de Guatemala", -"UVC s Coleccion de Anfibios y Reptiles, Universidad del Valle, Cali", -"UVCC s University of Vermont", -"UVCE s Colecao Entomologica, Laboratorio de Entomologia Sistematica", -"UVCO s Universidad de Valle", -"UVG s Universidad del Valle", -"UVGC s Collecion de Artropodos", -"UVIC s University of Victoria, Biology Department", -"UVM s Zadock Thompson Natural History Collection, University of Vermont", -"UVP s Utah State Vertebrate Paleontology Collection", -"UVSC s Utah Valley State College, Biology Department", -"UVST s Southwest Texas Junior College, Biology Department", -"UVV s Universita di Venezia, Dipartimento de Scienze Ambientali", -"UW s University of Washington Fish Collection", -"UWA s University of Western Australia, Botany Department", -"UWAL h University of West Alabama", -"UWBM s University of Washington, Burke Museum", -"UWBM:Mamm s University of Washington, Burke Museum, Burke Museum's mammal collection", -"UWBM:ORN s University of Washington, Burke Museum, Ornithology Collection", -"UWC s University of the Western Cape, Botany Department", -"UWCC c University of Washington Culture Collection", -"UWCP s University of Wroclaw", -"UWEC s University of Wisconsin, Department of Biology", -"UWFP s University of West Florida, Department of Biology", -"UWGB s University of Wisconsin-Green Bay, MAC 212", -"UWI s University of the West Indies (Trinidad and Tobago)", -"UWIC s University of the West Indies, Trinidad and Tobago", -"UWIJ s University of the West Indies, Jamaica", -"UWIZM s The University of the West Indies Zoology Museum", -"UWJ s University of Wisconsin, Biology Department", -"UWL s University of Wisconsin, Biology Department", -"UWM s University of Wisconsin, Biological Sciences Department", -"UWMA s University of Wisconsin, Milwaukee, Department of Anthropology", -"UWMIL s University of Wisconsin, Milwaukee, Department of Biological Sciences", -"UWO c University of Western Ontario", -"UWOC s University of Western Ontario", -"UWP s University of Wrocklaw", -"UWPG s University of Winnipeg, Biology Department", -"UWSP s University of Wisconsin-Stevens Point,", -"UWW s University of Wisconsin - Whitewater, Biological Sciences Department", -"UWYMV s University of Wyoming Museum of Vertebrates", -"UWYMV:Bird s University of Wyoming Museum of Vertebrates, Bird Collection", -"UWYMV:Fish s University of Wyoming Museum of Vertebrates, Fish Collection", -"UWYMV:Herp s University of Wyoming Museum of Vertebrates, Herpetology Collection", -"UWYMV:Mamm s University of Wyoming Museum of Vertebrates, Mammal Collection", -"UWZM s University of Wisconsin, Zoological Museum", -"UYIC s Instituto de Biologia", -"UZ s Herbario de la Universidad de Zaragoza", -"UZA s Unidad de Zoologia Aplicada, Departamento de Ecologia", -"UZIU s Uppsala University", -"UZL s University of Zambia, Biological Sciences Department", -"UZMC s Universidad del Zulia", -"UZMH s University Museum (Zoology)", -"UZMO s Zoologisk Museum", -"V s Royal British Columbia Museum - Herbarium", -"VA s University of Virginia", -"VAB s Universitat de Valencia, Departamento de Biologia Vegetal", -"VAIC s Victorian Agricultural Insect Collection", -"VAL sb Universitat de Valencia (Jardin Botanico de Valencia)", -"VALA s Universidad Politecnica, Departamento de Botanica", -"VALD s Universidad Austral de Chile, Instituto de Botanica", -"VALLE s Universidad Nacional de Colombia, Departamento de Ciencias Basicas", -"VALPL s Universidad de Playa Ancha, Departamento de Biologia y Quimica", -"VAN s Societe Polymathique du Morbihan", -"VANF s Yuezuencue Yil University, Biology Section", -"VAS s Vassar College, Biology Department", -"VBCM s Universidad Complutense de Madrid", -"VBGI s Botanical Garden-Institute", -"VBI s Institute of Ecology and Botany of the Hungarian Academy of Sciences, Botanical Department", -"VCRC c Volcani Center Rhizobium Collection (VCRC)", -"VCU s Virginia Commonwealth University, Biology Department", -"VDAC s Virginia Department of Agriculture and Consumer Services", -"VDAM s Institute of Plant Science", -"VDB s Vanderbilt University, Department of Biological Sciences", -"VECTOR sc State Research Center of Virology and Biotechnology", -"VEN s Fundacion Instituto Botanico de Venezuela Dr. Tobias Lasser", -"VENDA s Thohoyandou Botanical Gardens, Department of Agriculture, Land & Environment", -"VER s Herbario, Museo Civico di Storia Naturale, Verona", -"VETMED s University of Veterinary Medicine", -"VF s Universidad de Valencia, Departamento de Biologia Vegetal, Botanica", -"VFM h Forest Inventory and Planning Institute", -"VFWD s Vermont Fish and Wildlife Department", -"VFWO h U.S. Fish and Wildlife Service, Ventura Fish and Wildlife Office", -"VGZ s Voronezh State Biosphere Reserve, Research Department", -"VH h Vivekanand Arts Sardar Dalipsingh Commerce and Science College", -"VHS c Vegetation Health Service ( Phytophthora cultures )", -"VI c Mykotektet, National Veterinary Institute", -"VI s Gotlands Fornsal", -"VIA s FONAIAP-CENIAP", -"VIAM c Institute of Applied Microbiology, University of Agricultural Sciences", -"VIAY s Veterinarian Institute of Armenia, Botany Department", -"VIC s Universidade Federal de Vicosa, Departamento de Biologia Vegetal", -"VICA s Agriculture Department", -"VICF s Forestry Department", -"VICH s Plant Protection Department", -"VIES h Federal University of Espirito Santo", -"VIL s Universite de Paris-Sud", -"VIMS s Virginia Institute of Marine Science", -"VIST s University of the Virgin Islands, Natural Resources Program", -"VIT s Museo de Ciencias Naturales de Alava, Departamento de Botanica", -"VIZR c Collection for plant protection, All-Russian Institute of Plant Protection", -"VKM c All-Russian Collection of Microorganisms", -"VKPM c Russian National Collection of Industrial Microorganisms", -"VLA s Far Eastern Branch, Russian Academy of Sciences, Botany Department", -"VM s Okresni vlastivedne muzeum", -"VMI h Virginia Military Institute", -"VMIL s Virginia Military Institute, Biology Department", -"VMKSC s Kearney State University, Vertebrate Museum", -"VMM s Vanderbilt Marine Museum", -"VMNH s Virginia Museum of Natural History", -"VMSL s I.N.T.A., E.E.A. San Luis, Pastizales Naturales", -"VNC s Los Angeles Valley College, Life Sciences Department", -"VNF h Vietnam Forestry Herbarium", -"VNGA s Vorarlberger Naturschau", -"VNIRO s Institute of Oceanography", -"VNM h Institute of Tropical Biology", -"VNMN s Vietnam National Museum of Nature", -"VOA s Ostrobothnian Museum", -"VOR s Voronezh State University, Biology and Plant Ecology Department", -"VORB h Botanical Garden Dr. B.M. Kozo-Polyansky, Voronezh State University", -"VORG s Voronezh State University, Faculty of Geography and Geoecology", -"VPB c Veterinary Pathology and Bacteriology Collection", -"VPCI c Fungal Culture Collection", -"VPI sc Virginia Polytechnic Institute and State University", -"VPIC s Virginia Polytechnic Institute and State University", -"VPIMM s Virginia Polytechnic University, Mammal Museum", -"VPM s Volgograd Provincial Museum", -"VPRI c Victoria Department of Primary Industries, Plant Disease Herbarium", -"VRLI c Department of Virology", -"VSC s Valdosta State University, Biology Department", -"VSC-L s Lyndon State College, Mammal Collection", -"VSCA s Visayas State College of Agriculture", -"VSM s Det Kgl. Norske Videnskabers Selskab Museet", -"VSM s Eastern Slovakian (Vychodoslovenske) Museum, Natural History Department", -"VSRI s N.I. Vavilov All-Russian Scientific Research Instiutte of Plant Industry", -"VSUH s Virginia State University, Life Sciences Department", -"VT s Pringle Herbarium, University of Vermont", -"VTA h Jardin Botanique de la Villa Thuret", -"VTB c Banco de Celulas Humanas e Animais Laboratorio de Patologia Celular e Molecular", -"VTCC c Vietnam Type Culture Collection, Center of Biotechnology", -"VTT c VTT Biotechnology, Culture Collection", -"VU s Voronezh State University", -"VUT c School of Veterinary Medicine, Faculty of Agriculture", -"VUW s Victoria University", -"VUWE s Victoria University", -"VYH c Finnish Environment Institute (SYKE)", -"VYM s Muzeum Vyakovska", -"W s Naturhistorisches Museum Wien, Department of Botany", -"WA s Herbarium, Faculty of Biology, University of Warsaw", -"WAB s Wabash College, Biological Sciences Department", -"WABG h University of Warsaw Botanic Garden", -"WAC c Department of Agriculture Western Australia Plant Pathogen Collection", -"WACA s Walnut Canyon National Monument", -"WACA s Work Amber Collection", -"WACC c Western Australian Culture Collection", -"WADA s Western Australia Department of Agriculture", -"WAG s Wageningen University", -"WAHO s Institute of Horticultural Plant Breeding, Department of Biosystematics", -"WAI h Waimea Valley", -"WAIK s University of Waikato, Biological Sciences Department", -"WAITE c Insect Pathology Pathogen Collection", -"WAL c Wadsworth Anaerobe Laboratory, Wadsworth Hospital Center", -"WAM s Western Australian Museum", -"WAMP s Western Australian Museum", -"WAN s Forest Research Station", -"WANF s Wasatch-Cache National Forest", -"WAPA h War in the Pacific National Historical Park", -"WAR s Warwickshire Museum, Natural History Department", -"WARC c New Zealand Reference Culture Collection", -"WARK s Western Illinois University, Biology Department", -"WARM s Central Missouri State University, Biology Department", -"WARMS s Warwickshire Museum, Natural History Department", -"WARS s Wildlife Advisory and Research Service", -"WASH s Washburn University, Biology Department", -"WAT s University of Waterloo, Biology Department", -"WAU s Wau Ecology Institute", -"WAUF s Warsaw Agricultural University, Department of Plant Pathology", -"WAVI s Colby College, Biology Department", -"WB s Universitaet Wuerzburg", -"WB c Department of Bacteriology, University of Wisconsin", -"WBCH s Wisbech and Fenland Museum", -"WBG s Waimea Botanical Garden", -"WBM s Universitaet Wuerzburg", -"WBR s Laboratoire de Paleontologie, Unversite de Montpellier", -"WBS s Landbouwuniversiteit", -"WCE s University of London, Westfield College, Biology Department", -"WCH s Greenwich Borough Museum", -"WCL s Willesden Borough Council", -"WCP s Walla Walla College, Biological Sciences Department", -"WCR s Winchester City Museum", -"WCRP s Winchester Public Library", -"WCSBG h West China Subalpine Botanical Garden", -"WCSU s Western Connecticut State University, Department of Biological and Environmental Sciences", -"WCU s West China University of Medical Sciences", -"WCUH s Western Carolina University, Department of Biology", -"WCUM c Working Collection", -"WCUUM s West China Union University", -"WCW s Whitman College, Department of Biology", -"WDds c Raul Lopez Sanchez", -"WDNE s Bureau of Land Management, Winnemucca District", -"WECO s Wesleyan University, Biology Department", -"WEIC s Wau Ecology Institute", -"WELC s Wellesley College, Biological Sciences Department", -"WELT s Museum of New Zealand Te Papa Tongarewa", -"WELTU s Victoria University of Wellington", -"WERN s Werneth Park Study Centre and Natural History Museum", -"WET s Wartburg College, Biology Department", -"WFBM s W.F. Barr Entomological Collection", -"WFBVA s Federal Forest Research Centre Vienna, Department of Vegetation Science", -"WFIS s Wagner Free Institute of Science", -"WFU s Wake Forest University, Biology Department", -"WFUVC s Wake Forest University, Vertebrate Collection", -"WGC s State University of West Georgia, Biology Department", -"WGCH h Wilton Garden Club", -"WGD s Washington Game Department", -"WGMM s Woodspring Museum", -"WGRC b Wheat Genetics Resource Center", -"WGRS s Western Ghat Regional Station of the Zoological Survey of India at Calicut", -"WH s Wuhan University", -"WHB s Universitaet fuer Bodenkultur", -"WHIT s Whittier College, Biology Department", -"WHM s West Highland Museum", -"WHN s Whitehaven Museum", -"WHOI s Woods Hole Oceanographic Institution", -"WHY s Whitby Museum", -"WHYNC s Whytby Naturalists' Club", -"WI s Vilnius University, Botany and Genetics Department", -"WIAP s Wistar Institute of Anatomy", -"WIB s Ministry of Environment and Parks, Resource Quality Section", -"WIBF s West Indian Beetle Fauna Project Collection", -"WIBG s Windward Islands Banana Grower's Association", -"WICA s Wind Cave National Park", -"WICH h Wichita State University", -"WIES s Museum Wiesbaden", -"WII s Wildlife Institute of India, Department of Habitat Ecology", -"WILLI s The College of William and Mary, Department of Biology", -"WILLU s Willamette University", -"WIN s University of Manitoba, Botany Department", -"WINC s Waite Insect & Nematode Collection", -"WIND s National Botanical Research Institute", -"WINDM s Delta Marsh Field Station (University of Manitoba)", -"WINF s Forestry and Rural Developmen Department", -"WINFM s Forestry and Rural Developmen Department", -"WINO s Saint Mary's College, Biology Department", -"WINU h Winthrop University", -"WIR sb N. I. Vavilov Institute of Plant Industry, Department of Introduction and Systematics", -"WIS s University of Wisconsin, Botany Department", -"WIU s Western Illinois University, Museum of Natural History", -"WIUC s Western Illinois University", -"WJC s William Jewell College, Biology Department", -"WKD s Wakefield Museum", -"WKDS s Wakefield Grammar School", -"WKSU s Western Kentucky State University", -"WKU s Western Kentucky University, Department of Biology", -"WL s Wolong Nature Reserve", -"WLH s Wilberforce Library", -"WLK s British Columbia Ministry of Forests", -"WLMH s West Lake Musuem", -"WLU s Wilfrid Laurier University, Biology Department", -"WM s Gezira Research Station", -"WMGC s Gordon College, Biology Department", -"WMM s Witte Memorial Museum", -"WMNH s Wakayama Prefectural Museum of Natural History", -"WMS s Wakes Museum", -"WMU s Western Michigan University, Biological Sciences Department", -"WMW s Vestry House Museum", -"WNC s University of North Carolina Wilmington, Department of Biology and Marine Biology", -"WNHM s Oklahoma Baptist University, Webster Natural History Museum", -"WNLM s Niederoesterreichisches Landesmuseum", -"WNMU s Western New Mexico University Museum", -"WNMU:Bird s Western New Mexico University Museum, bird collection", -"WNMU:Fish s Western New Mexico University Museum, fish collection", -"WNMU:Mamm s Western New Mexico University Museum, mammal collection", -"WNRE s Whiteshell Nuclear Research Establishment", -"WNS s Wiesbaden Naturwissenschaftliche Sammlung der Stadt", -"WNU s Northwest University, Biology Department", -"WOCB s University of Windsor, Biological Sciences Department", -"WOCSB b Wheeler Orchid Collection and Species Bank", -"WOH s Southwestern Oklahoma State University, Biology Department", -"WOLL s University of Wollongong, Department of Biological Sciences", -"WOS s City Museum and Art Gallery", -"WOSNH s Worcestershire Natural History Society Museum", -"WPBS c WPBS Rhizobium Collection", -"WPC cb World Phytophthora Genetic Resource Collection", -"WPH s Waterton Lakes National Park", -"WPL s Whitechapel Museum", -"WPMM s State Museum of Pennsylvania", -"WRC b Wildlife Research Center of Kyoto University", -"WRHM s Institute of Terrestrial Ecology", -"WRL c The Wellcome Bacterial Collection", -"WRN s Warrington Museum and Art Gallery", -"WRNFC s Warrington Field Naturalists' Club", -"WRO s University of Bristol, Long Ashton Research Station", -"WRSL s Wroclaw University, Botany Department", -"WS s Washington State University", -"WSBC s Wichita State University", -"WSBC c Research collection of Bacillus cereus group species", -"WSC s Westfield State College, Museum and Herbarium", -"WSCH s Westfield State College, Biology Department", -"WSCO s Weber State University, Botany Department", -"WSF c Wisconsin Soil Fungi Collection", -"WSFA s Wilmington College, Biology Department", -"WSL b Swiss Federal Institute for Forest, Snow and Landscape Research", -"WSLC c Research collection of Listeria (Weihenstephan Microbial Strain Collection)", -"WSM s Weston-super-Mare Museum and Art Gallery", -"WSM c Western Australian Soil Microbiology culture collection, Murdoch. University", -"WSNM s White Sands National Monument", -"WSP s Washington State University, Plant Pathology Department", -"WSRP s University of Podlasie, Botany Department", -"WSU s Weber State University, Bird and Mammal Collection", -"WSU s Washington State University", -"WSUMNH s Wayne State University, Museum of Natural History", -"WSY s Royal Horticultural Society's Gardens", -"WTR s Winchester College, Biology Department", -"WTS s West Texas A&M University, Department of Life, Earth and Environmental Sciences", -"WTSU s West Texas A&M University, Natural History Collection", -"WTU s University of Washington", -"WTUH s University of Washington Botanic Gardens, College of Forest Resources", -"WU s Universitaet Wien", -"WU s Wayland University", -"WUD s Wayne State University, Biological Sciences Department", -"WUH s Wuhu School of Traditional Chinese Medicine", -"WUK s Northwestern Institute of Botany", -"WUM s University of Witwatersrand", -"WUME s Willamette University", -"WUP h Department of Pharmacognosy, Universitat Wien", -"WVA s West Virginia University, Biology Department", -"WVBS s West Virginia Biological Survey", -"WVDH c West Virginia Hygienic Laboratory", -"WVIT s West Virginia University, Biology Department", -"WVMS s Marshall University, West Virginia Mammal Survey", -"WVN s Whitehaven Scientific Association", -"WVUC s West Virginia University", -"WVW s West Virginia Wesleyan College, Biology Department", -"WWB s Western Washington University, Biology Department", -"WWC h Warren Wilson College", -"WWF s Welder Wildlife Foundation", -"WWM s Werner Wildlife Museum", -"WWSP s Weymouth Woods Sandhills Nature Preserve", -"WXDC s Wanxian Institute of Drug Control", -"WXM s North East Wales Institute, Department of Natural Science", -"WYAC s University of Wyoming, Range Ecology and Watershed Management Department", -"WYCO s Wytheville Community College, Biology Department", -"WYE s University of London, Wye College", -"XAG s Xinjiang Academy of Animal Sciences", -"XAL s Instituto de Ecologia, A.C.", -"XALU s Universidad Veracruzana", -"XBGH s Xian Botanical Garden", -"XCH s St. Xavier's College, Botany Department", -"XFCFC s Xiamen Fisheries College", -"XIAS s Xichang Agricultural School", -"XIN s Southwestern Guizhou Institute of Forestry", -"XJA s Xinjiang Agricultural University", -"XJBI s Xinjiang Institute of Ecology and Geography", -"XJDC s Xinjiang Institute for Drug Control", -"XJFA s Xinjiang Academy of Forestry Sciences", -"XJNU s Xinjiang Normal University, Biology Department", -"XJU s Xinjiang University, Biology Department", -"XJUG s Xinjiang University, Geography Department", -"XM s Xinjiang Medical College, Pharmacy Department", -"XMU s Xiamen University", -"XNC s Department of Biology, Xinxiang Normal College", -"XOLO s Universidad Autonoma Chapingo, Departamento de Fitotecnia", -"XTNM s Xinjiang Institute of Traditional Chinese and Minorities Medicine", -"XUM s Hope Department of Entomology", -"XYTC s Xinyang Teachers College, Biology Department", -"XZ s Tibet Plateau Institute of Biology", -"XZDC s Tibet Institute for Drug Control", -"XZTC s Xuzhou Teachers College, Biology Department", -"Y s Yale University, Samuel Jones Record Memorial Collection", -"YA s National Herbarium of Cameroon", -"YAF s Yunnan Academy of Forestry", -"YAI s Armenian Agricultural Academy, Botany Department", -"YAK s Forest Survey and Design Institute", -"YALT s The State Nikita Botanical Gardens, Flora and Vegetation", -"YAM s Yamaguchi University, Plant Pathology Department", -"YAMA h Yamagata Prefectural Museum", -"YAR s Yaroslavl State University, Department of Biology and Ecology", -"YBDC s Yibin Institute for Drug Control", -"YBI s Institut National pour l'Etude et la Recherche Agronomique, Departement de Botanique", -"YBLF c Yamanouchi Pharmaceutical Co., Ltd.", -"YCE s Yunnan College of Education, Biology Department", -"YCH s Yavapai College, Biology Department", -"YCM s Yokosuka City Museum", -"YCP s Yunnan Laboratory for Conservation of Rare, Endangered & Endemic Forest Plants, State Forestry Administration", -"YDC s Yunnan Institute for Drug Control", -"YELLO s Yellowstone National Park", -"YEO s Yeovil Museum", -"YF s Yanbei Forestry Institute", -"YFS s Yunnan Forestry School", -"YFTC s Yale Fish Tissue Collection", -"YH s Lutheran College", -"YHB s Yukon Heritage Board , Paleontology Collections", -"YIM c Yunnan Institute of Microbiology", -"YIM s Yunnan Institute of Pharmacology", -"YIO s Yamashina Institute for Ornithology", -"YK s Bootham School", -"YKN s Yorkshire Naturalists' Trust Limited", -"YL s Northwest Sci-tech University of Agriculture and Forestry", -"YLD s Yulin Institute of Desert Control Research", -"YM c Strains Collection of Yunnan Institute of Microbiology, Yunnan University, China", -"YM s York Museum", -"YM s National Park Service, Yosemite National Park", -"YMF s Key Laboratory of Industrial Microbiology & Fermentation Technology", -"YMUK s The Yorkshire Museum", -"YNP s The Yosemite Museum", -"YNU s Yokohama National University", -"YNUB s Yunnan Normal University, Biology Department", -"YNUGI s Yokohama National University - Geological Institute", -"YNUH s Yeungnam University, Biology Department", -"YOLA s Mari State University, Department of Plant Biology", -"YPM s Yale Peabody Museum of Natural History", -"YPM/PU s Princeton University Collection in Yale Peabody Museum", -"YPM:ENT s Yale Peabody Museum of Natural History, Entomology Collection", -"YPM:HER s Yale Peabody Museum of Natural History, Herpetology Collection", -"YPM:ICH s Yale Peabody Museum of Natural History, Ichthyology Collection", -"YPM:IZ s Yale Peabody Museum of Natural History, Invertebrate Zoology Collection", -"YPM:MAM s Yale Peabody Museum of Natural History, Mammology Collection", -"YPM:ORN s Yale Peabody Museum of Natural History, Ornithology Collection", -"YPMC s Yellowstone National Park", -"YRK s Yorkshire Museum, Biology Department", -"YU s Yunnan University", -"YU s Department of Earth and Environmental Sciences, Yarmouk University", -"YU s Yale University, Botany Division", -"YUC s INIREB", -"YUKU s Yunnan University, Biology Department", -"YUO s Youngstown State University, Biological Sciences Department", -"YUTO s York University, Biology Department", -"YXDC s Yuxi District Institute for Drug Control", -"YZU s Yuzhou University", -"Z s Universitaet Zuerich", -"ZA s University of Zagreb, Botany Department", -"ZAD s Mount Makulu Research Station", -"ZAGR s University of Zagreb", -"ZAHO s University of Zagreb, Botany Department", -"ZAR s Institut de Paleontologie du Museum National d'Historie Naturelle", -"ZAU s Zhejiang Agricultural University", -"ZAUC s Zhejian Agricultural University", -"ZBMM s Maharaja's College, Zoology and Botany Museum", -"ZCA s Zhelimu College of Animal Husbandry, Range Science Department", -"ZCM s Shetland Museum", -"ZDC s Zhejiang Institute for Drug Control", -"ZDEU s Zoology Department, Ege University", -"ZDKU s Kharkiv National University", -"ZDM s Zigong dinosaur Museum", -"ZEA s Universidad de Guadalajara, Centro Universitario de la Costa Sur, Departamento de Ecologia y Recursos Naturales", -"ZFMK sb Zoologisches Forschungsmuseum Alexander Koenig", -"ZFMK:COL s Zoologisches Forschungsmuseum Alexander Koenig, Coleoptera collection", -"ZFMK:FSJF s Zoologisches Forschungsmuseum Alexander Koenig, fish collection of Jeorg Freyhof", -"ZFMK:ICH s Zoologisches Forschungsmuseum Alexander Koenig, Ichthyological Collection", -"ZFSN s Laboratoire de Zoologie de la Faculte Des Sciences", -"ZGLC s Natural History Museum, Limassol", -"ZHAN s Zhanjiang Teachers College, Biology Department", -"ZhM s Zhejinag Museum", -"ZIA s National Academy of Sciences of Armenia", -"ZIAN s Zoological Institute, Academy of Sciences", -"ZICUP s Zoological Institute Charles University", -"ZIHU s Hiroshima University, Zoological Institute", -"ZIK s Ukrainian Academy of Sciences, Zoological Institute", -"ZIKU s Zoological Institute, Kochi University", -"ZIL s Academy of Sciences, Zoological Institute", -"ZIM c ZIM Culture Collection of Industrial Microorganisms", -"ZIN s Zoological Institute of the Russian Academy of Sciences", -"ZIS s Universitaet Saarbruecken", -"ZISB s Institute of Zoology", -"ZISP s Zoological Institute, Russian Academy of Sciences", -"ZIT s Grusinian Academy of Sciences", -"ZITIU s Zoological Institute, Tokyo Imperial University", -"ZIUG s Zoologisches Institut", -"ZIUL s Zoologisches Institut der Universitaet", -"ZIUN s Universita DI Napoli", -"ZIUS s Zoologisches Institute der Universitat", -"ZIUS s Zoologiska Institutionen", -"ZIUT s Department of Zoology, Faculty of Science, University of Tokyo", -"ZIUU s Uppsala Universitet, Zoologiska Museum", -"ZIUW s Universitaet Wien, Zoologisches Institut", -"ZIUZ s Zagreb University", -"ZJFC s Zhejiang Forestry College, Forestry Department", -"ZJFI s Zhejiang Forestry Institute, Bamboo Department", -"ZJMA s Zhejiang Academy of Medical Sciences", -"ZJU b Zhejiang University College of Sciences", -"ZLMU s Meijo University", -"ZLSYU s Zoological Laboratory", -"ZLVG c Culture collection of the Laboratory of Forest Protection at the Slovenian Forestry Institute", -"ZM s Zhejiang Museum of Natural History", -"ZMA s Universiteit van Amsterdam, Zoologisch Museum", -"ZMAN s Instituut voor Taxonomische Zoologie, Zoologisch Museum", -"ZMAU s Zoological Museum Andhra University", -"ZMB s Zoologisches Museum der Humboldt-Universitaet zu Berlin", -"ZMBJ s Banding Zoological Museum", -"ZMBN s Museum of Zoology at the University of Bergen, Invertebrate Collection", -"ZMC s Deptment of Biology, Zunyi Medical College", -"ZMFMIB s Zoologial Museum Fan Memorial Institute of Biology", -"ZMG s Zoologisches Museum der Universitat Gottingen", -"ZMG s Zoologischen Museums Greifswald", -"ZMH s Zoologisches Museum Hamburg", -"ZMHB s Museum fuer Naturkunde der Humboldt-Universitat", -"ZMHU s Zoologisches Museum der Humboldt Universitaet", -"ZMJU s Zoological Museum, Jagiellonian University", -"ZMK s Zoologisches Museum der Universitat Kiel", -"ZMK s Zoological Museum, Copenhagen", -"ZMK s Zoological Musem, Kristiania", -"ZMKR s Koenigsberg Zoologisches Museum", -"ZMKU s Kiev Zoological Museum", -"ZMKU s Zoological Museum, Kasetsart University", -"ZML s St Petersburg State University", -"ZMLP s University of Punjab", -"ZMLU s Lunds Universitet, Zoologiska Institutionen", -"ZMMGU s Zoological Museum", -"ZMMU s Zoological Museum, Moscow Lomonosov State University", -"ZMMU:Birds s Zoological Museum, Moscow Lomonosov State University, Bird Collection", -"ZMMU:Fishes s Zoological Museum, Moscow Lomonosov State University, Fishes Collection", -"ZMMU:Herps s Zoological Museum, Moscow Lomonosov State University, Ampibia and Reptilia Collection", -"ZMMU:Insects s Zoological Museum, Moscow Lomonosov State University, Insects Collection", -"ZMMU:Invertebrates s Zoological Museum, Moscow Lomonosov State University, Invertebrates Collection", -"ZMMU:Mamm s Zoological Museum, Moscow Lomonosov State University, Mammal Collection", -"ZMNH s Zhejiang Museum of Natural History", -"ZMO s Zoology Museum, Oxford University", -"ZMS s Zentralmuseum Senckenberg (SENCKENBERG world of biodiversity)", -"ZMSZ s Zemaljski Mujski", -"ZMT s Zapadomoravske muzeum v Trebici", -"ZMT s Georgian State Museum, Zoological Section", -"ZMTAU s Zoological Museum Tel Aviv University", -"ZMU s Zhejiang Medical University, Pharmacy Department", -"ZMUA s Zooligal Museum, University of Amoy", -"ZMUA s Zoological Museum, University of Athens", -"ZMUAS s Zoological Museum Ukrainian Academy of Sciences", -"ZMUB s Museum of Zoology at the University of Bergen, Vertebrate collections", -"ZMUB:BIRD s Museum of Zoology at the University of Bergen, Vertebrate collections, Bird collection", -"ZMUB:HERP s Museum of Zoology at the University of Bergen, Vertebrate collections, Herptile collection", -"ZMUB:ICHT s Museum of Zoology at the University of Bergen, Vertebrate collections, Fish Collections", -"ZMUB:MAMM s Museum of Zoology at the University of Bergen, Vertebrate collections, Mammal collection", -"ZMUC sb Zoological Museum, University of Copenhagen", -"ZMUD s University of Dhaka, Zoology Museum", -"ZMUH s Zoologisches Institut und Zoologisches Museum, Universitat Hamburg", -"ZMUH s Zoological Museum, University of Hanoi", -"ZMUI s Zoological Museum, University of Istanbul", -"ZMUL s Universitetets Lund, Zoologiska Museet", -"ZMUN s Zoology, Natural History Museum, University of Oslo", -"ZMUO s University of Oulu Zoological Museum", -"ZMUO s Universitetets I Oslo, Zoologisk Museum", -"ZMUP s Zoological Museum of the University of Patras", -"ZMUT s University of Tokyo, Department of Zoology", -"ZMUU s Uppsala Universitet, Zoologiska Museet", -"ZMUZ s Zoologisches Museum der Universitaet Zuerich", -"ZNG h Bulent Ecevit University", -"ZNM s Zhejiang Natural Museum", -"ZNP s Zion National Park", -"ZNPC s Springdale, Zion National Park", -"ZNU s Zhejiang Normal University, Biology Department", -"ZOM s Herbarium, Department of Agriculture, Malawi", -"ZPAL s Zoological Institute of Paleobiology, Polish Academy of Sciences", -"ZPB s Institute of Conservation and Natural History of the Soutpansberg", -"ZRC s Zoological Reference Collection, National University of Singapore", -"ZSBS s Zoologische Sammlung des Bayerischen Staates", -"ZSI-CRS s Zoological Survey of India, Central Regional Station", -"ZSI-E s Zoological Survey of India", -"ZSI-M s Zoological Survey of India", -"ZSI-NRS s Zoological Survey of India", -"ZSI-SRS s Zoological Survey of India, Southern Regional Station", -"ZSI-WRS s Zoological Survey of India", -"ZSIC s Zoological Survey of India", -"ZSLC s Zoological Society of London", -"ZSM sb Zoologisches Staatssammlung Munchen", -"ZSM/CMK s Zoologische Museum Staatssammlung", -"ZSM/LIPI s Zoologische Museum Staatssammlung", -"ZSM:Lep s Zoologisches Staatssammlung Munchen, Lepidoptera", -"ZSM:Mol s Zoologisches Staatssammlung Munchen, Mollusca", -"ZSMC s Zoologische Staatssammlung", -"ZSP s Zoological Survey of Pakistan", -"ZSP s Zoological Society of Philadelphia", -"ZSS s Sukkulenten-Sammlung Zuerich", -"ZT s Eidgenoessische Technische Hochschule Zuerich", -"ZTNH s University of Vermont, Zadock Thompson Natural History Collections", -"ZTS s Institute of Nature Conservation, Polish Academy of Sciences, Tatra Field Station", -"ZUAB s Zoologia--Universidad Autonoma de Barcelona", -"ZUAC s University of Antananarivo", -"ZUEC s Museu de Zoologia da Universidade Estadual de Campinas", -"ZUFES s Universidad Federal do Espirito Santo", -"ZUFRJ s Departamento de Zoolgia, Instituto de Biologia", -"ZUFSM s Universidade Federal de Santa Maria, Laboratorio de Herpetologia", -"ZULU s University of Zululand, Botany Department", -"ZUMT s Department of Zoology, University Museum", -"ZUTC s Zoological Museum University of Tehran", -"ZV s Technical University, Department of Phytology", -"ZVC s Depto. de Zoologia Vertebrados de la Facultad de Humanidades y Ciencias", -"ZVCB s Vertebrate Collection, Facultad de Ciencias, Universidad de la Republica", -"ZVS s Bundesamt fuer Naturschutz", -"ZY h Zunyi Normal College", -"ZYTC s Zhangye Teachers College, Chemistry-Biology Department", -"ZZN c Zavod za naravoslovje", -"ZZSZ s Zoology Department, Faculty of Natural Sciences, University of Zagreb" +" DZSJRP\ts\tDepartmento de Zoologia e Botanica, Universidade Estadual Paulista\t\t", +"A\ts\tArnold Arboretum, Harvard University\t\t", +"AA\ts\tMinistry of Science, Academy of Sciences\t\t", +"AAC\tc\tArignar Anna College\t\t", +"AAH\ts\tArnold Arboretum, Harvard University\t\t", +"AAPI\ts\tPlant Industry Laboratory\t\t", +"AAR\ts\tReliquae Aaronsohnianae\t\t", +"AARI\ts\tAnatolian Agricultural Research Institute\t\t", +"AAS\ts\tBritish Antarctic Survey\t\t", +"AASU\ts\tArmstrong State University\t\t", +"AAU\ts\tUniversity of Aarhus, Institute of Biological Sciences\t\t", +"AAU\ts\tAddis Ababa University, Department of Biology\t\t", +"AAU:A\ts\tAddis Ababa University, Department of Biology, Amphibian collection", +"AAUB\ts\tAnhui Agricultural University, Department of Basic Courses\t\t", +"AAUF\ts\tAnhui Agricultural University, Forest Utilization Faculty\t\t", +"ABB\tc\tAsian Bacterial Bank\t\t", +"ABD\ts\tUniversity of Aberdeen, Plant and Soil Science Department\t\t", +"ABDAM\ts\tAberdeen Art Gallery and Museum\t\t", +"ABDC\ts\tAba Institute for Drug Control\t\t", +"ABDF\ts\tUniversity of Aberdeen, Forestry Department\t\t", +"ABDH\ts\tUnited Arab Emirates University, Department of Biology\t\t", +"ABDM\ts\tMarischal College, University of Aberdeen\t\t", +"ABFM\ts\tThe Barnes Foundation Arboretum\t\t", +"ABH\ts\tUniversidad de Alicante, Centro Iberoamericano de la Biodiversidad (CIBIO)\t\t", +"ABI\ts\tCentre ORSTOM d'Adiopodoume\t\t", +"ABKMI\tc\tDepartment of Applied Biology, Faculty of science\t\t", +"ABL\ts\tAdviesbureau voor Bryologie en Lichenologie\t\t", +"ABN\ts\tRadley College\t\t", +"ABO\ts\tAboyne Castle\t\t", +"ABRC\tb\tArabidopsis Biological Resource Center\t\t", +"ABRIICC\tc\tABRIICC Agricultural Biotechnology Research Institute of Iran Culture collection\t\t", +"ABRN\ts\tCentre for Ecology and Hydrology\t\t", +"ABS\tsc\tAberystwyth University, Institute of Biological, Environmental and Rural Sciences\t\t", +"ABS\ts\tArchbold Biological Station\t\t", +"ABSH\ts\tSouthern Illinois Universitiy, Department of Plant Biology\t\t", +"ABSL\ts\tUniversity of Minnesota, American Bryological and Lichenological Society\t\t", +"ABSM\ts\tDuke University, Botany Department\t\t", +"ABT\ts\tLaboratoire de Biologie Vegetale et d'Ecologie Forestiere\t\t", +"ABTC\ts\tAustralian Biological Tissue Collection, South Australian Museum\tSAMA:ABTC", +"ABU\ts\tAhmadu Bello University Herbarium\t\t", +"AC\ts\tAmherst College\t\t", +"ACA\ts\tAgricultural University of Athens\t\t", +"ACA-DC\tc\tGreek Coordinated Collections of Microorganisms\t\t", +"ACAD\ts\tAcadia University, K. C. Irving Environmental Science Centre & Harriet Irving Botanical Gardens\t\t", +"ACAD\tsb\tAustralian Centre for Ancient DNA\t\t", +"ACAM\tc\tThe Australian Collection of Antarctic Microorganisms, Cooperative Research Center for the Antarctic and Southern Ocean Environment\t\t", +"ACAP\ts\tAquaculture Center of Aomori Prefecture\t\t", +"ACBC\ts\tAgriculture Canada Research Station\t\t", +"ACBR\tc\tAustrian Center of Biological Resources and Applied Mycology\t\t", +"ACBV\ts\tAgriculture Canada Research Station, The Aphids of British Columbia\t\t", +"ACC\ts\tOak Hill Park Museum\t\t", +"ACCC\tc\tAgricultural Culture Collection of China\t\t", +"ACD\ts\tAlemaya University of Agriculture\t\t", +"ACE\ts\tAnhui College of Education, Biology Department\t\t", +"ACE\ts\tArachnid Collection of Egypt\t\t", +"ACH\tc\tNational Mycology Reference Centre, SA Pathology\t\t", +"ACHE\ts\tInstitute of Terrestrial Ecology\t\t", +"ACK\ts\tAgriculture and Agri-Food Canada\t\t", +"ACM\tc\tAustralian Collection of Microorganisms\t\t", +"ACM\ts\tAnhui College of Traditional Chinese Medicine, Chinese Materia Medica Department\t\t", +"ACNB\ts\tAgriculture Canada Research Station\t\t", +"ACNS\ts\tAgriculture Canada Nova Scotia\t\t", +"ACOI\tc\tCoimbra Collection of Algae\t\t", +"ACOR\ts\tUniversidad Nacional de Cordoba\t\t", +"ACTC\ts\tAustin College\t\t", +"ACU\ts\tAbilene Christian University\t\t", +"ACUNHC\ts\tAbilene Christian University, Natural History Collection\t\t", +"AD\ts\tPlant Biodiversity Centre\t\t", +"ADA\ts\tHerbarium, Department of Agriculture, South Australia\t\t", +"ADMONT\ts\tBenediktinerstift Admont\t\t", +"ADO\ts\tKirikkale University, Biology Department\t\t", +"ADR\ts\tAdrian College, Biology Department\t\t", +"ADRZ\ts\tRudjer Boskovic Institute, CIM-Botany\t\t", +"ADSH\ts\tArachnology Division\t\t", +"ADT\ts\tAntarctic Division\t\t", +"ADU\ts\tUniversity of Adelaide, Botany Department\t\t", +"ADUG\ts\tGeology Department, University of Adelaide\t\t", +"ADUZ\ts\tZoology Department, University of Adelaide\t\t", +"ADW\ts\tUniversity of Adelaide\t\t", +"AEF\ts\tUniversity of Ankara, Department of Pharmaceutical Botany\t\t", +"AEI\ts\tAmerican Entomological Institute\t\t", +"AEIC\ts\tAmerican Entomological Institute\t\t", +"AES\ts\tHerbarium, Agricultural and Forestry Experiment Station, University of Alaska\t\t", +"AESB\ts\tAgriculture Experiment Station\t\t", +"AFAQ\ts\tAmateur Fisheries Association of Queensland\t\t", +"AFES\ts\tMaritimes Forest Research Centre\t\t", +"AFGMC\ts\tAlaska Department of Fish and Game\t\t", +"AFS\ts\tUniversity of Michigan\t\t", +"AFSDU\ts\tSuleyman Demirel University, Agricultural Faculty\t\t", +"AFTC\ts\tAlaska Frozen Tissue Collection\t\t", +"AGRITEC\tb\tAGRITEC, Ltd.\t\t", +"AGRL\ts\tLethbridge Research Station\t\t", +"AGU\ts\tAstrakhan State University\t\t", +"AGUAT\ts\tUniversidad de San Carlos\t\t", +"AGUCH\ts\tFacultad de Ciencias Agronomicas de la Universidad de Chile\t\t", +"AH\ts\tUniversidad de Alcala, Departamento de Biologia Vegetal\t\t", +"AHBC\ts\tDixie College\t\t", +"AHF\ts\tAllan Hancock Foundation, University of Southern California\t\t", +"AHFH\ts\tUniversity of Southern California\t\t", +"AHLDA\tc\tAnimal Health Division Culture Collection\t\t", +"AHMA\ts\tAgharkar Research Institute, Maharashtra Association for the Cultivation of Science, Botany Group\t\t", +"AHNU\ts\tAnhui Normal University Conservation Genetics Lab\t\t", +"AHS\ts\tAustin High School\t\t", +"AHU\tc\tAHU Culture Collection\t\t", +"AHUC\ts\tUniversity of California, Agronomy and Range Science Department\t\t", +"AIB\ts\tAnhui Institute of Biology\t\t", +"AIBU\ts\tAbant Izzet Baysal Ueniversitesi, Biyoloji Boeluemue\t\t", +"AICH\ts\tAichi Kyoiku University, Biology Department\t\t", +"AIM\ts\tAuckland Institute and Museum\tAMNZ", +"AIMS\ts\tAustralian Institute of Marine Science\t\t", +"AIS\ts\tAcademie imperial des Sciences\t\t", +"AISIY\ts\tArmenian Institute for the Scientific Investigation of Cattle Breeding and Veterinary, Department of Meadows and Pastures\t\t", +"AIX\ts\tMuseum d'Histoire Naturelle d'Aix-en-Provence\t\t", +"AJ\tc\tCentral Research Laboratories\t\t", +"AJBC\ts\tAtkins Jardin Botanico de Cienfuegos\t\t", +"AJOU\ts\tAjou University, Biological Sciences Department\t\t", +"AK\ts\tAuckland War Memorial Museum\t\t", +"AKPM\ts\tAkita Prefectural Museum\t\t", +"AKSU\th\tAksaray University\t\t", +"AKU\tc\tFaculty of Agriculture\t\t", +"AKU\ts\tUniversity of Auckland, School of Biological Sciences\t\t", +"AL\ts\tUniversite d'Alger\t\t", +"ALA\ts\tHerbarium, University of Alaska Museum of the North\t\t", +"ALA\ts\tUniversity of Alabama Museum of Natural History\t\t", +"ALAJ\ts\tHerbarium, University of Alaska SE\t\t", +"ALAM\ts\tAdams State College, Biology Department\t\t", +"ALB\ts\tCivico Museo Archeologico e di Scienze Naturali Federico Eusebio\t\t", +"ALBA\ts\tUniversidad de Castilla, La Mancha, Departamento de Ciencia y Tecnologia Agroforestal\t\t", +"ALBC\ts\tAlbion College, Biology Department\t\t", +"ALBU\ts\tRocky Mountain Forest and Range Experiment Station\t\t", +"ALCB\ts\tUniversidade Federal da Bahia, Campus Universitario de Ondina\t\t", +"ALCP\tc\tAlgotheque du Laboratoire de Cryptogamie\t\t", +"ALD\ts\tAlderney Society and Museum\t\t", +"ALEX\ts\tUniversity of Alexandria, Department of Botany\t\t", +"ALF\ts\tCampus International de Baillarguet, Departement d'Elevage et de Medecine Veterinaire\t\t", +"ALGOBANK\tc\tALGOBANK\tAC", +"ALGU\ts\tUniversidade do Algarve\t\t", +"ALIRU\tc\tAustralian Legume Inoculants Research Unit\t\t", +"ALK\ts\tAlnwick Scientific and Mechanical Institution\t\t", +"ALM\ts\tMuseum National Historie Naturelle\t\t", +"ALM\ts\tArt Gallery and Museum, Central Library\t\t", +"ALMA\ts\tAlma College, Biology Department\t\t", +"ALME\ts\tEstacion Experimental de Zonas Aridas\t\t", +"ALN\ts\tAlnwick Botanical Society\t\t", +"ALNHS\ts\tNatural Heritage Section-ALDCNR\t\t", +"ALT\ts\tCurtis Museum\t\t", +"ALTA\ts\tUniversity of Alberta, Biological Sciences Department\t\t", +"ALTB\ts\tUniversity of Barnaul, Altai State University\t\t", +"ALU\ts\tAlabama Museum of Natural History\t\t", +"ALUH\ts\tAlzahra University\t\t", +"AM\tsb\tAustralian Museum\tAMS", +"AM:Arachnology\ts\tAustralian Museum, Invertebrate Collections: Arachnology", +"AM:EBU\tsb\tAustralian Museum, Evolutionary Biology Unit Tissue Collection", +"AM:Entomology\ts\tAustralian Museum, Invertebrate Collections: Entomology", +"AM:Herpetology\ts\tAustralian Museum, Vertebrate Collections: Herpetology", +"AM:Ichthyology\ts\tAustralian Museum, Vertebrate Collections: Ichthyology", +"AM:Malacology\ts\tAustralian Museum, Invertebrate Collections: Malacology", +"AM:Mammalogy\ts\tAustralian Museum, Vertebrate Collections: Mammalogy", +"AM:Marine_Invertebrates\ts\tAustralian Museum, Invertebrate Collections: Marine and other invertebrates", +"AM:Mineralogy\ts\tAustralian Museum, Earth Sciences: Mineralogy and Petrology Collection", +"AM:Ornithology\ts\tAustralian Museum, Vertebrate Collections: Ornithology", +"AM:Palaeontology\ts\tAustralian Museum, Palaeontology Collection", +"AM\ts\tAcatushun Museum at the Estancia Haberton\t\t", +"AM\ts\tAsenovgrad Paleontology Museum\t\t", +"AMAL\ts\tAnniston Museum of Natural History\t\t", +"AMAZ\ts\tUniversidad Nacional de la Amazonia Peruana\t\t", +"AMB\ts\tAssociazione Micologica Bresadola\t\t", +"AMC\tc\tDepartment of Biologics Research\t\t", +"AMCC\ts\tAmbrose Monell Cryo Collection, American Museum of Natural History\t\t", +"AMCL\ts\tMacapa, Museu Territorial de Historia Natural \"Angelo Moreira da Costa Lima\"\t\t", +"AMD\ts\tHugo de Vries-Laboratory, University of Amsterdam\t\t", +"AMDE\ts\tBrathay Field Centre for Exploration and Field Studies\t\t", +"AMES\ts\tHarvard University\t\t", +"AMG\ts\tAlbany Museum\t\t", +"AMGS\ts\tAlbany Museum\t\t", +"AMH\ts\tAgharkar Research Institute, Mycology and Plant Pathology Department\t\t", +"AMMRL\tc\tAustralian National Reference Laboratory in Medical Mycology\t\t", +"AMMS\ts\tAcademy of Military Medical Sciences\t\t", +"AMNH\tsb\tAmerican Museum of Natural History\t\t", +"AMNH:Fish\ts\tAmerican Museum of Natural History, Ichthyology Collection", +"AMNH:FM\ts\tAmerican Museum of Natural History, Fossil Mammal Collection", +"AMNH:Herp\ts\tAmerican Museum of Natural History, Herpetology collection", +"AMNH:ORN\ts\tAmerican Museum of Natural History, Ornithology Collection", +"AMNH:R\ts\tAmerican Museum of Natural History, Reptile Collection", +"AMNH\ts\tIcelandic Institute of Natural History, Akureyri Division\t\t", +"AMNZ\ts\tAuckland Institute and Museum\tAIM", +"AMO\ts\tHerbario AMO\t\t", +"AMP\tc\tAustralian Mycological Panel\t\t", +"AMP\ts\tAmpleforth College\t\t", +"AMS\ts\tAustralian Museum\tAM", +"AMSA\ts\tAlbany Museum\t\t", +"AMUZ\ts\tAligarh Muslim University\t\t", +"ANA\ts\tOrange County Department of Agriculture\t\t", +"ANACC\tc\tAustralian National Algae Culture Collection\t\t", +"ANC\ts\tUniversita di Ancona, Dipartimento di Biotecnologie Agrarie ed Ambientali\t\t", +"ANCB\ts\tMuseo Nacional de Historia Natural, La Paz\t\t", +"AND\ts\tSlezske zemske muzeum Opava, Arboretum Nopvy Dvur, Dendrology Department\t\t", +"ANDA\ts\tAndalas University\t\t", +"ANDES\ts\tLa Universidad de Los Andes\t\t", +"ANDES:A\ts\tLa Universidad de Los Andes, Amphibian Collection", +"ANDES:O\ts\tLa Universidad de Los Andes, Ornithology Collection", +"ANES\ts\tAnadolu University, Biology Department\t\t", +"ANFC\ts\tAustralian National Fish Collection\t\t", +"ANFM\ts\tAssociazione Naturalisti Forlivesi Pro Museo\t\t", +"ANG\ts\tArboretum de la Maulevrie\t\t", +"ANGU\ts\tInstituto Nacional de Tecnologia Agropecuaria\t\t", +"ANGUC\ts\tUniversite Catholiques de l'Ouest\t\t", +"ANH\ts\tAndong National University, School of Bioresource Science\t\t", +"ANHC\ts\tArkansas Natural Heritage Commission Herbarium\t\t", +"ANIC\ts\tAustralian National Insect Collection\t\t", +"ANK\ts\tAnkara Ueniversitesi, Biyoloji Boeluemue\t\t", +"ANKO\ts\tForest Research Institute, Turkey\t\t", +"ANLW\ts\tAmt Der Niederosterreichischen Landsregierung\t\t", +"ANMR\tc\tAsian Network on Microbial Researches\t\t", +"ANSM\ts\tUniversidad Autonoma Agraria Antonio Narro, Departamento de Botanica\t\t", +"ANSP\ts\tAcademy of Natural Sciences of Philadelphia\t\t", +"ANSP:Malacology\ts\tAcademy of Natural Sciences of Philadelphia, Malacology Collection", +"ANTU\ts\tChangbai Mountain National Nature Reserve Administration Bureau\t\t", +"ANU\ts\tAustralian National University\tANU,ANU", +"ANU\ts\tAnhui University, Biology Department\t\t", +"ANUB\ts\tAnhui Normal University, Biology Department\t\t", +"ANUC\ts\tAustralian National University, Chemistry Department\t\t", +"ANUG\ts\tAnhui Normal University, Geography Department\t\t", +"ANWC\ts\tAustralian National Wildlife Collection\t\t", +"AO\ts\tMuseo Regionale di Scienze Naturali della Valle d'Aosta\t\t", +"APCC\tc\tAntarctic Protistan Culture Collection (Woods Hole Oceanographic Institution)\t\t", +"APCR\ts\tArkansas Tech University, Biological Sciences Department\t\t", +"APEI\ts\tAgriculture Canada Research Station\t\t", +"APH\ts\tSociety of Apothecaries\t\t", +"APHA\tsc\tAnimal and Plant Health Agency\tVLA", +"APHI\ts\tU.S. Department of Agriculture, Animal and Plant Health Inspection Service\t\t", +"APIY\ts\tAbovian Pedagogical Institute, Botany Department\t\t", +"APM\ts\tAlgonquin Provincial Park, Algonquin Visitor Centre\t\t", +"APMJ\ts\tAomori Prefectural Museum\t\t", +"APP\ts\tParco Nazionale del Gran Sasso e Monti della Laga - Universita di Camerino, Centro Richerche Floristiche dell'Appennino\t\t", +"APSC\ts\tAustin Peay State University, Biology Department\t\t", +"AQC\ts\tAquinas College, Biology Department\t\t", +"AQP\ts\tEstudios Fitogeograficos del Peru\t\t", +"AQUI\ts\tUniversita degli Studi di L'Aquila, Dipartimento di Scienze Ambientali\t\t", +"AR\ts\tPomor State University\t\t", +"ARAGO\ts\tUniversite Pierre et Marie Curie\t\t", +"ARAN\ts\tAlto de Zorroaga s.n., Departamento de Botanica\t\t", +"ARB\ts\tSalahiddin University, Biology Department\t\t", +"ARBH\ts\tArbroath Scientific and Natural History Society\t\t", +"ARC\ts\tUniversidad Nacional del Comahue, Facultad de Ciencias Agrarias\t\t", +"ARC\ts\tAtlantic Reference Centre\t\t", +"ARC\tc\tAlgal Resources Collection\t\t", +"ARCH\ts\tArchbold Biological Station\t\t", +"ARCM\ts\tAtlantic Reference Centre\t\t", +"ARER\ts\tAssociazione Romana di Entomologia\t\t", +"ARG\ts\tArgotti Botanic Garden\t\t", +"ARIZ\ts\tUniversity of Arizona, Department of Plant Sciences\t\t", +"ARK\ts\tUniversity of Arkansas\t\t", +"ARKH\ts\tChingan State Nature Reserve\t\t", +"ARM\ts\tCounty Museum\t\t", +"ARMFN\ts\tArmagh Field Naturalists' Society\t\t", +"ARRI\ts\tAyurveda Regional Research Institute\t\t", +"ARSEF\tc\tARS Collection of Entomopathogenic Fungi\t\t", +"ARTH\ts\tArtvin Coruh University\t\t", +"ARUN\ts\tBotanical Survey of India, Arunachal Pradesh Regional Centre\t\t", +"AS\tc\tChina General Microbiological Culture Collection Center\t\t", +"AS\ts\tPaleontological Collection\t\t", +"AS\ts\tJardin Botanico\t\t", +"ASAY\ts\tAcademy of Science of Armenia\t\t", +"ASC\ts\tNorthern Arizona University, Biological Sciences Department\t\t", +"ASCC\ts\tAdams State College Collection\t\t", +"ASCU\ts\tAgricultural Scientific Collections Unit\t\t", +"ASDM\ts\tArizona-Sonora Museum\t\t", +"ASE\ts\tUniversidade Federal de Sergipe, Departamento de Biologia\t\t", +"ASH\ts\tNational Institute of Deserts Flora and Fauna\t\t", +"ASIB\tc\tAlgensammlung am Institut fur Botanik\t\t", +"ASINC\tb\tAgricultural Science Institute of North-Central Vietnam\t\t", +"ASIO\ts\tAcademia Sinica Institute of Oceanology\t\t", +"ASIZB\ts\tAcademia Sinica Institute of Zoology, Beijing\t\t", +"ASIZP\ts\tAcademia Sinica Institute of Zoology, Ichthyology Collection\tASIZP", +"ASIZT\ts\tAcademia Sinica Institute of Zoology, Taipei\t\t", +"ASM\ts\tArts and Science University\t\t", +"ASNHC\ts\tAngelo State Natural History Collection\t\t", +"ASSAM\ts\tBotanical Survey of India, Eastern Circle\t\t", +"ASSL\ts\tAcademy of Sciences\t\t", +"AST\ts\tUniversity of Aston\t\t", +"ASTC\ts\tStephen F. Austin State University, Biology Department\t\t", +"ASTN\ts\tAshton-under-Lyne Linnean Botanical Society\t\t", +"ASTU\ts\tAssiut University\t\t", +"ASU\ts\tSchool of Life Sciences, Arizona State University\t\t", +"ASUA\ts\tAin Shams University\t\t", +"ASUF\ts\tRocky Mountain Research Station, USDA Forest Service\t\t", +"ASUMC\ts\tArizona State University, Mammal Collection\t\t", +"ASUMZ\ts\tArkansas State University, Collection of Recent Mammals\t\t", +"ASUT\ts\tFrank M. Hasbrouck Insect Collection\t\t", +"ASW\ts\tSouth Valley University, Botany Department\t\t", +"ASW\tc\tCulture Collection of Algae at the University of Vienna\t\t", +"ATA\ts\tAtatuerk Ueniversitesi\t\t", +"ATCC\tcb\tAmerican Type Culture Collection\t\t", +"ATH\ts\tGoulandris Natural History Museum\t\t", +"ATHU\ts\tNational and Kapodistrian University of Athens, Biology Department\t\t", +"ATHUM\tc\tATHUM Culture Collection of Fungi\t\t", +"ATSC\tb\tAustralian Tree Seed Centre\t\t", +"ATU\tc\tDept.of Biotechnology University of Tokyo\t\t", +"AU\ts\tXiamen University, Biology Department\t\t", +"AUA\ts\tAuburn University, Biological Sciences Department\t\t", +"AUB\ts\tAndrews University\t\t", +"AUBH\ts\tAthabasca University\t\t", +"AUBL\ts\tMuseum of Natural History, Beirut\t\t", +"AUBSN\ts\tAll-Union Botanical Society\t\t", +"AUCE\ts\tEl Azhar University\t\t", +"AUEM\ts\tAuburn University Entomological Museum\t\t", +"AUG\ts\tAugustana College, Biology Department\t\t", +"AUGD\ts\tDepartment of Geology and Petroleum Geology\t\t", +"AUH\ts\tAgriculture University Herbarium\t\t", +"AUM\ts\tAuburn University Museum\t\t", +"AUMC\tc\tAssiut University Mycological Centre Culture Collection\t\t", +"AURO\ts\tAuroville Foundation\t\t", +"AUSPGRIS\tb\tAustralian Plant Genetic Resource Information Service\t\t", +"AUT\ts\tMuseum d'Histoire Naturelle\t\t", +"AUW\ts\tAcadia University, Wildlife Museum\t\t", +"AV\ts\tMuseum Requien\t\t", +"AVCH\ts\tCity of Alexandria\t\t", +"AVE\ts\tUniversidade de Aveiro, Departamento de Biologia\t\t", +"AVU\ts\tVrije Universiteit, Department of Systematic Botany\t\t", +"AWH\ts\tDr. Henri Van Heurck Museum\t\t", +"AWL\ts\tAbitibi Paper Company\t\t", +"AWQC\tc\tAustralian Water Quality Centre\t\t", +"AWRI\tc\tThe Australian Wine Research Institute\t\t", +"AYBY\ts\tBuckinghamshire County Museum Technical Centre\t\t", +"AYDN\ts\tAdnan Menderes University, Department of Biology\t\t", +"AYR\ts\tSouth Ayrshire Council\t\t", +"AZ\ts\tMuseu Carlos Machado, Natural History Department\t\t", +"AZAN\ts\tAkademia Nauk Azerbaijana-Bulgarian Academy of Science of Azerbaijan\t\t", +"AZB\ts\tHerbario Ruy Telles Palhinha - Universidade Dos Acores\t\t", +"AZU\ts\tUniversidade dos Acores, Departamento de Ciencias Agrarias\t\t", +"AZUS\ts\tCitrus College, Biological Sciences Department\t\t", +"B\ts\tBerlin Botanic Garden and Botanical Museum\tBGBM", +"BA\ts\tMuseo Argentino de Ciencias Naturales Bernardino Rivadavia\t\t", +"BAA\ts\tUniversidad de Buenos Aires, Facultad de Agronomia\t\t", +"BAAC\ts\tMusee de Beni Abbes\t\t", +"BAB\ts\tInstituto Nacional de Tecnologia Agropecuaria, Instituto de Recursos Biologicos\t\t", +"BABY\ts\tB. A. Bennett Herbarium, Yukon Government\t\t", +"BAC\ts\tBeijing Agricultural College\t\t", +"BAC\ts\tBacup Natural History Society\t\t", +"BACC\tc\tBrucella AFSSA Culture Collection\t\t", +"BACH\ts\tBotswana College of Agriculture\t\t", +"BACP\ts\tCEFYBO, Unidad Botanica\t\t", +"BAE\ts\tWillis Museum and Art Gallery\t\t", +"BAF\ts\tUniversidad de Buenos Aires, Facultad de Farmacia y Bioquimica\t\t", +"BAFC\tsc\tUniversidad de Buenos Aires, Departamento de Ciencias Biologicas\t\t", +"BAG\ts\tMinistry of Agriculture\t\t", +"BAH\ts\tEmpresa Baiana de Desenvolvimento Agricola\t\t", +"BAH\ts\tBiologische Anstalt Helgoland Marine Station\t\t", +"BAI\ts\tInstituto Forestal Nacional (IFONA), Centro Forestal Castelar\t\t", +"BAIL\ts\tConservatoire Botanique National de Bailleul\t\t", +"BAJ\ts\tInstituto Municipal de Botanica, Parque Pte. Dr. Nicolas Avellaneda\t\t", +"BAK\ts\tAcademy of Sciences of Azerbaijan\t\t", +"BAL\ts\tINTA, EEA Balcarce, Catedra de Botanica Agricola\t\t", +"BALT\ts\tTowson University, Department of Biological Sciences\t\t", +"BAMU\ts\tDr. Babasaheb Ambedkar Marathwada University\t\t", +"BAN\ts\tBanaras Hindu University, Botany Department\t\t", +"BANG\ts\tUniversite de Bangui\t\t", +"BAP\ts\tOxford Botanic Garden\t\t", +"BAR\ts\tUniversity of the West Indies, Department of Biological and Chemical Sciences\t\t", +"BARC\ts\tBeltsville Agricultural Research Center\t\t", +"BARO\ts\tMaharaja Sayajirao University of Baroda, Botany Department\t\t", +"BART\ts\tBartlett Arboretum\t\t", +"BAS\ts\tBulgarian Academy of Science\t\t", +"BAS\ts\tHerbarium, Botanisches Institut, Universitat Basel\t\t", +"BASBG\ts\tUniversitaet Basel, Basler Botanische Gesellschaft\t\t", +"BASSA\ts\tMuseo Civico, Bassano del Grappa\t\t", +"BASU\ts\tBu-Ali Sina University\t\t", +"BAT\ts\tBagshaw Museum\t\t", +"BATA\ts\tInstituto Nacional de Desarollo Forestal\t\t", +"BATH\ts\tBath Natural History Society\t\t", +"BATHG\ts\tGeology Museum\t\t", +"BATU\ts\tBatumi Botanical Garden, Botany Department\t\t", +"BAU\ts\tBeijing Agricultural University\t\t", +"BAV\ts\tSlovenskej akademie vied\t\t", +"BAY\ts\tMuseum d'Histoire Naturelle de Bayonne\t\t", +"BAYLU\ts\tBaylor University, Biology Department\t\t", +"BB\ts\tUniversidad Nacional del Sur, Departamento de Agronomia\t\t", +"BB\ts\tBuffalo Bill Museum\t\t", +"BBB\ts\tUniversidad Nacional del Sur, Departamento de Biologia, Bioquimica y Farmacia\t\t", +"BBF\ts\tConservatoire Botanique National de Midi-Pyrenees, Conservatoire botanique pyreneen\t\t", +"BBG\ts\tBirmingham Botanical Gardens\t\t", +"BBH\ts\tNational Science and Technology Development Agency\t\t", +"BBLF\tc\tInstitut fur Pflanzenschutz im Forst\t\t", +"BBLM\ts\tBoise District Bureau of Land Management\t\t", +"BBNP\ts\tBig Bend National Park\t\t", +"BBPP\tc\tBacteriology Branch, Plant Pathology and Microbiology Division, Department of Agricultural Science\t\t", +"BBS\ts\tUniversity of Suriname\t\t", +"BBSUK\ts\tNational Museum and Gallery, Department of Biodiversity and Systematic Biology\t\t", +"BC\ts\tInstitut Botanic de Barcelona\t\t", +"BCB\ts\tUniversitat Autonoma de Barcelona, Unitat de Botanica\t\t", +"BCC\ts\tUniversitat de Barcelona, Departament de Biologia Vegetal (Unitat de Botanica)\t\t", +"BCC\tc\tBIOTEC Culture Collection\t\t", +"BCCDC\tc\tBC Centre for Disease Control\t\t", +"BCCM/DCG\tc\tThe Belgian Co-ordinated Collections of Micro-organisms / DCG Diatoms Collection\tDCG", +"BCCM/IHEM\tc\tThe Belgian Co-ordinated Collections of Micro-organisms / IHEM Biomedical Fungi and Yeasts Collection\tIHEM", +"BCCM/ITM\tc\tThe Belgian Co-ordinated Collections of Micro-organisms / ITM Mycobacteria Collection\tITM", +"BCCM/LMBP\tc\tBelgian Coordinated Collections of Microorganisms / LMBP Plasmid Collection\tLMBP", +"BCCM/MUCL\tc\tThe Belgian Co-ordinated Collections of Micro-organisms / MUCL (Agro)Industrial Fungi & Yeasts Collection\tMUCL", +"BCCM/ULC\tc\tThe Belgian Co-ordinated Collections of Micro-organisms / ULC of cyanobacteria\tUCL", +"BCCN\tc\tBrucella Culture Collection\t\t", +"BCCUSP\tc\tBrazilian Cyanobacteria Collection - University of Sao Paulo\t\t", +"BCF\ts\tUniversitat de Barcelona, Laboratori de Botanica\t\t", +"BCFH\ts\tBureau of Commercial Fisheries\t\t", +"BCH\ts\tBerry College\t\t", +"BCKN\ts\tBlackburn Museum and Art Gallery\t\t", +"BCL\ts\tBates College, Biology Department\t\t", +"BCM\ts\tCampus Universitario de Tafira, Departamento de Biologia\t\t", +"BCM\ts\tBrooklyn Children's Museum\t\t", +"BCMEX\ts\tUniversidad Autonoma de Baja California, Reg. MX-HR-007-BC\t\t", +"BCMM\ts\tBeijing College of Traditional Chinese Medicine\t\t", +"BCN\ts\tUniversitat de Barcelona\t\t", +"BCNP\ts\tBryce Canyon National Park\t\t", +"BCPM\ts\tBritish Columbia Provincial Museum\t\t", +"BCRC\tc\tBioresource Collection and Research Center\tCCRC", +"BCRJ\tc\tRio de Janeiro Cell Bank (Banco de Celulas do Rio de Janeiro)\t\t", +"BCRU\ts\tUniversidad Nacional del Comahue, Departamento de Botanica\t\t", +"BCTC\ts\tBirmingham Central Technical College\t\t", +"BCU\ts\tChulalongkorn University, Botany Department\t\t", +"BCUE\ts\tDepartment of Biology, Ch'ongju University of Education\t\t", +"BCUZ\ts\tBasque Country University, Laboratory of Zoology\t\t", +"BCW\ts\tBedford College, University of London\t\t", +"BCWL\ts\tBiological Control of Weeds Laboratory-Europe\t\t", +"BDD\ts\tUniversity of Bradford, Biology Department\t\t", +"BDI\ts\tPutnam Museum of History and Natural Science, Natural History Department\t\t", +"BDIARI\tsc\tBahri Dagdas International Agricultural Research Institute\t\t", +"BDK\ts\tNorth Hertfordshire Museums Service, Natural History Department\t\t", +"BDLU\ts\tLaurentian University\t\t", +"BDMU\ts\tMcMaster University\t\t", +"BDPA\ts\tArboretum, Bolestraszyce - Zamek, Department of Physiography\t\t", +"BDUC\ts\tUniversity of Calgary\t\t", +"BDUW\ts\tUniversity of Waterloo\t\t", +"BDUZ\tc\tBiological Sciences\t\t", +"BDWC\ts\tUniversity of Windsor\t\t", +"BDWL\ts\tWilfred Laurier University\t\t", +"BDWR\ts\tBridgewater College, Biology Department\t\t", +"BEAN\ts\tBridge of Allan Museum\t\t", +"BED\ts\tBedford Public Library\t\t", +"BEDF\ts\tNew England Wild Flower Society\t\t", +"BEDPL\ts\tBedford Public Library\t\t", +"BEG\tc\tInternational Bank for the Glomeromycota\tIBG", +"BEGO\ts\tBeth Gordon Institute\t\t", +"BEI\ts\tAmerican University of Beirut, Biology Department\t\t", +"BEI\tc\tBiodefense and Emerging Infections Research Resources\t\t", +"BEL\ts\tUlster Museum, Botany Department\t\t", +"BELC\ts\tBeloit College, Biology Department\t\t", +"BELUM\ts\tUlster Museum, Belfast\t\t", +"BELZ\ts\tZapovednik Belogorje State Nature Reserve\t\t", +"BENH\ts\tBritish Entomological and Natural History Society\t\t", +"BENIN\ts\tUniversite National du Benin\t\t", +"BEO\ts\tNatural History Museum, Botany Department\t\t", +"BEOU\ts\tUniversity of Belgrade, Faculty of Biology\t\t", +"BER\ts\tOrto Botanico de Bergamo \"Lorenzo Rota\"\t\t", +"BEREA\ts\tBerea College, Biology Department\t\t", +"BERN\ts\tUniversity of Bern\t\t", +"BESA\ts\tMuseum d'Histoire naturelle de Besancon\t\t", +"BESM\ts\tBvumbwe Experiment Station\t\t", +"BEV\ts\tBorough of Beverley Art Gallery and Museum\t\t", +"BEX\ts\tBexhill Museum\t\t", +"BFBI\ts\tBiologisches Forschunsstation Burgenland\t\t", +"BFD\ts\tBedfordshire Natural History Society\t\t", +"BFDL\ts\tForest Products Laboratory\t\t", +"BFIC\ts\tMuseum National d'Histoire Naturelle\t\t", +"BFRIRS\ts\tBangladesh Fisheries Research Institute\t\t", +"BFRS\ts\tBlodgett Forest Research Station\t\t", +"BFT\ts\tQueen's University, Botany Department\t\t", +"BFUS\ts\tUniversity of Sofia, Biology Faculty\t\t", +"BFY\ts\tJohn Innes Horticultural Institution\t\t", +"BG\ts\tUniversity of Bergen, Botanical Museum\t\t", +"BGAAS\ts\tBotanical Garden of the Armenian Academy of Sciences, Flora and Vegetation Department\t\t", +"BGHan\ts\tBundesanstalf fuer Geowissenschaften und Rohstoffe\t\t", +"BGIV\tc\tBanco de Glomeromycota In Vitro (Bank of Glomeromycota In Vitro)\t\t", +"BGM\ts\tBath Geology Museum (now the Royal Literary and Scientific Institution)\t\t", +"BGR\ts\tBundesanstalt fur Geowissenschaften und Rohstoffe\t\t", +"BGS\ts\tBritish Geological Survey\t\t", +"BGSC\tc\tBacillus Genetic Stock Center\t\t", +"BGSU\ts\tBowling Green State University, Biological Sciences Department\t\t", +"BH\ts\tCornell University, Department of Plant Biology\t\t", +"BHAG\ts\tT. M. Bhagalpur University, Botany Department\t\t", +"BHAV\ts\tCentral Salt and Marine Chemicals Research Institute\t\t", +"BHCB\ts\tUniversidade Federal de Minas Gerais, Departamento de Botanica\t\t", +"BHD\ts\tWilliamson Art Gallery and Museum\t\t", +"BHDL\ts\tWirral Central Area Reference Library\t\t", +"BHDS\ts\tBirkenhead School\t\t", +"BHM\ts\tUniversity of Birmingham, Birmingham Natural Society\t\t", +"BHM\ts\tBlack Hills Museum of Natural History\t\t", +"BHMG\ts\tInstituto Agronomico\t\t", +"BHMH\ts\tUniversidade Federal de Minas Gerais, Museu de Historia Natural\t\t", +"BHO\ts\tOhio University, Environmental and Plant Biology Department\t\t", +"BHSC\ts\tBlack Hills State University, Biology Department\t\t", +"BHU\ts\tHumboldt-Universitaet zu Berlin, Institut fuer Biologie\t\t", +"BHUPM\ts\tMuseum fuer Naturkunde, Institut fuer Palaeontologie\t\t", +"BHUPP\ts\tBanaras Hindu University, Mycology and Plant Pathology Department\t\t", +"BHZB\ts\tFundacao Zoo-Botanica de Belo Horizonte\t\t", +"BI\ts\tIstituto Ortobotanico\t\t", +"BIA\ts\tBritish Institute of Archaeology\t\t", +"BIDA\ts\tBoise State University\t\t", +"BIE\ts\tInstituto di Entomologia\t\t", +"BIEL\ts\tUniversitaet Bielefeld, Abteilung Oekologie\t\t", +"BIGU\ts\tUniversidad de San Carlos de Guatemala, Departamento de Botanica\t\t", +"BIL\ts\tForest Research Institute, Natural Forest Department\t\t", +"BILAS\ts\tInstitute of Botany\t\t", +"BIM\ts\tBirmingham Natural History and Microscopical Society\t\t", +"BIM\tc\tBelarus National Academy of Sciences\t\t", +"BING\ts\tState University of New York, Biological Sciences Department\t\t", +"BIO\ts\tUniversidad del Pais Vasco/EHU, Departamento de Biologia Vegetal y Ecologia (Botanica)\t\t", +"BioCC\tc\tBioCC BioCen Culture Collection\t\t", +"BIOT\ts\tRegional Center for Tropical Biology\t\t", +"BIOUG\ts\tBiodiversity Institute of Ontario, University of Guelph\tBIO,UOG:BIO", +"BIRA\ts\tBirmingham Museums and Art Gallery, Curatorial Services\t\t", +"BIRDI\tb\tBiotechnology Research & Development Institute Vietnam\t\t", +"BIRM\ts\tUniversity of Birmingham\t\t", +"BISH\ts\tBishop Museum, Department of Natural Sciences\t\t", +"BITU\ts\tDepartment of Biology, Faculty of Science, Toyama University\t\t", +"BIUB\ts\tMongolian Academy of Sciences\t\t", +"BJ\th\tBi Jie University\t\t", +"BJA\ts\tUniversity of Burundi, Biology Department\t\t", +"BJFC\ts\tBeijing Forestry University\t\t", +"BJM\ts\tBeijing Natural History Museum\t\t", +"BJRI\tb\tGene bank at Bangladesh Jute Research Institute\t\t", +"BJTC\ts\tCapital Normal University, Biology Department\t\t", +"BK\ts\tBangkok Herbarium\t\t", +"BKF\ts\tThe Forest Herbarium\t\t", +"BKL\ts\tBrooklyn Botanic Garden\t\t", +"BKNU\ts\tKunsan National University\t\t", +"BLA\ts\tFundacao Estadual de Pesquisa Agropecuaria\t\t", +"BLAT\ts\tSt. Xavier's College, Botany Department\t\t", +"BLCU\ts\tBee Biology and Systematics Laboratory\t\t", +"BLFU\ts\tUniversity of the Free State, Department of Botany and Genetics\t\t", +"BLGA\ts\tBurgenlandisches Landesmuseum\t\t", +"BLH\ts\tCranbrook Institute of Science\t\t", +"BLIH\ts\tBiological Laboratory Imperial Household of Japan\t\t", +"BLMAR\th\tBureau of Land Management Arcata Field Office\t\t", +"BLMLK\ts\tBureau of Land Management\t\t", +"BLMPR\th\tBureau of Land Management, Prineville Field Office\t\t", +"BLT\ts\tBelfast Natural History and Philosophical Society\t\t", +"BLUZ\ts\tMuseo de Biologia\t\t", +"BLWG\tc\tBayerische Landesanstalt fur Weinbau und Gartenbau\t\t", +"BLY\ts\tHarvey Institute, Barnsley Naturalist and Scientific Society\t\t", +"BM\ts\tThe Natural History Museum, Herbarium\t\t", +"BM\ts\tBristol Museum\t\t", +"BMAM\ts\tBeijing Natural History Museum\t\t", +"BMARI\tb\tBandaranayake Memorial Ayurvedic Research Institute\t\t", +"BMB\ts\tBooth Museum of Natural History\t\t", +"BMBN\ts\tBooth Museum of Natural History\t\t", +"BMCC\tc\tBrittany Microbe Culture collection\t\t", +"BMFM-UNAM\tc\tCulture Collection of Fungal Pathogens Strains from the Basic Mycology Laboratory of the Department of Microbiology and Parasitology, Faculty of Medicine, UNAM\t\t", +"BMGB\ts\tBarbados Museum and Historical Society\t\t", +"BMH\ts\tBournemouth Natural Science Society Museum, herbarium\t\t", +"BMHP\ts\tBermuda Department of Agriculture and Fisheries\t\t", +"BMKB\ts\tBrunei Museum\tBM", +"BMM\ts\tBuergermeister Mueller, Museum\t\t", +"BMNH\ts\tNatural History Museum, London\t\t", +"BMNH:ENT\ts\tNatural History Museum, London, Entomology collection", +"BMNHC\ts\tBurpee Museum of Natural History\t\t", +"BMPS\ts\tBristol Museum and Philosophical Society\t\t", +"BMR\ts\tBureau of Mineral Resources\t\t", +"BMRP\ts\tBurpee Museum Rockford Paleontology\t\t", +"BMSA\ts\tNational Museum Bloemfontein\t\t", +"BMSC\ts\tBuffalo Museum of Science\t\t", +"BMUK\ts\tBolton Museum\t\t", +"BNA\tc\tNational Bank of Algae\t\t", +"BNA\ts\tBritish (Empire) Naturalists' Association\t\t", +"BNBE\ts\tYMCA Hostel\t\t", +"BNFF\ts\tBanff Museum\t\t", +"BNFH\th\tU.S. Forest Service, Bitterroot National Forest\t\t", +"BNH\ts\tNassau Botanical Gardens, Department of Agriculture\t\t", +"BNHD\ts\tBengal Natural History Museum\t\t", +"BNHM\ts\tBeijing Natural History Museum\t\t", +"BNHM\ts\tBombay Natural History Museum\t\t", +"BNHS\ts\tBombay Natural History Society\t\t", +"BNI\tc\tBernhard Nocht Institute for Tropical Medicine\t\t", +"BNL\ts\tBundesamt fuer Naturschutz\t\t", +"BNM\tc\tBanco Nacional Microorganismos (National Bank of Microorganisms)\t\t", +"BNP\ts\tBanff Park Museum\t\t", +"BNPL\ts\tBrighton Public Library\t\t", +"BNRH\ts\tBuffelskloof Nature Reserve\t\t", +"BNS\ts\tBristol Museum and Art Gallery\t\t", +"BNU\ts\tBeijing Normal University, Biology Department\t\t", +"BO\ts\tHerbarium Bogoriense\t\t", +"BOC\ts\tBingham Oceanographic Collection\tYPM", +"BOCH\ts\tRuhr-Universitaet Bochum, Spezielle Botanik\t\t", +"BOD\ts\tUniversity of Oxford\t\t", +"BOG\ts\tUniversidad de La Salle\t\t", +"BOGOS\tb\tBotanical Garden of Osnabruck University\t\t", +"BOIS\ts\tRocky Mountain Research Station\t\t", +"BOL\ts\tUniversity of Cape Town, Botany Department\t\t", +"BOLO\ts\tUniversita di Bologna\t\t", +"BOLV\ts\tNacional Forestal Martin Cardenas\t\t", +"BON\ts\tBolton Museum, Art Gallery and Aquarium\t\t", +"BONB\ts\tBolton Botanical Society\t\t", +"BONL\ts\tBolton Linnean Society\t\t", +"BONN\ts\tBotanisches Institut und Botanischer Garten der Universitaet Bonn\t\t", +"BOON\ts\tAppalachian State University, Biology Department\t\t", +"BOR\ts\tGuermonprez Museum\t\t", +"BORD\ts\tJardin Botanique de la Ville de Bordeaux\t\t", +"BORH\ts\tUniversiti Malaysia Sabah\t\t", +"BORN\ts\tInstitute for Tropical Biology and Conservation, Borneensis\t\t", +"BOROK\tc\tThe Collection of algae\t\t", +"BOSC\ts\tBoston State College, Biology Department\t\t", +"BOTU\ts\tUniversidade Estadual Paulista, Departamento de Botanica\t\t", +"BOUM\ts\tMuseum d'Histoire Naturelle de Bourges\t\t", +"BOZ\ts\tNaturmuseum Suedtirol/Museo Scienze Naturali Alto Adige\t\t", +"BP\ts\tHungarian Natural History Museum, Botanical Department\t\t", +"BPBM\ts\tBernice P. Bishop Museum\tBISHOP", +"BPBM:Fish\ts\tBernice P. Bishop Museum, Fish Collection", +"BPBM:IZ\ts\tBernice P. Bishop Museum, Invertebrate Zoology", +"BPI\tsc\tU.S. National Fungus Collections, Systematic Botany and Mycology Laboratory\t\t", +"BPI\ts\tBernard Price Institute for Palaeontological Research\t\t", +"BPIC\tc\tBenaki Phytopathological Institute Collection\t\t", +"BPL\ts\tMuseum of Barnstaple & North Devon\t\t", +"BPM\ts\tBeipiao Paleontological Museum\t\t", +"BPPT-ESC\tc\tBPPT Ethanol-Single Cell Protein-Fructose Syrup Technical Unit\t\t", +"BPS\ts\tCalifornia Department of Food and Agriculture\t\t", +"BPU\ts\tEoetvoes Lorand University, Department of Plant Taxonomy and Ecology\t\t", +"BR\ts\tBotanic Garden Meise\t\t", +"BR\tc\tJohanna Dobereiner Biological Resouce Center (CRB-JD)\t\t", +"BRA\ts\tSlovak National Museum, Botany Department\t\t", +"BRAD\ts\tUniversity of Bradford, Biology Department\t\t", +"BRC\ts\tBotanical Record Club\t\t", +"BRCC\tc\tUSDA-ARS Rhizobium Germplasm Resource Collection\t\t", +"BRCH\ts\tBotanical Research Center\t\t", +"BRE\ts\tUniversite\t\t", +"BREE\ts\tBraintree and Bocking Natural History Club\t\t", +"BREG\ts\tVorarlberger Naturschau\t\t", +"BREM\ts\tUebersee-Museum\t\t", +"BRFL\ts\tCity of Birmingham Reference Library\t\t", +"BRFM\tc\tBanque de Ressources Fongiques de Marseille\t\t", +"BRG\ts\tUniversity of Guyana, Biology Department\t\t", +"BRGE\ts\tLaboratoire de Genetique des Plantes Superieures\t\t", +"BRH\ts\tMinistry of Natural Resources, Local Government, and the Environment\t\t", +"BRI\ts\tBrisbane Botanic Gardens Mt Coot-tha\t\t", +"BRIP\tsc\tThe Plant Pathology Herbarium, Department of Agriculture, Fisheries and Forestry\t\t", +"BRIST\ts\tUniversity of Bristol, Botany Department\t\t", +"BRISTM\ts\tBristol Museum and Art Gallery\t\t", +"BRIT\ts\tBotanical Research Institute of Texas\t\t", +"BRIU\ts\tUniversity of Queensland, Botany Department\t\t", +"BRL\ts\tBristol City Library\t\t", +"BRLU\ts\tUniversite Libre de Bruxelles\t\t", +"BRM\ts\tAlfred-Wegener-Institut fuer Polar- und Meeresforschung\t\t", +"BRMI\ts\tBirmingham and Midland Institute\t\t", +"BRN\ts\tSexey's School\t\t", +"BRNL\ts\tMendel University of Agriculture and Forestry, Department of Forest Botany, Dendrology, and Typology\t\t", +"BRNM\ts\tMoravian Museum, Botany Department\t\t", +"BRNU\ts\tMasaryk University, Department of Botany\t\t", +"BROC\ts\tState University of New York, Biological Sciences Department\t\t", +"BRS\ts\tAgriculture and Agri-Food Canada\t\t", +"BRSL\ts\tWroclaw University, Botany Department\t\t", +"BRSMG\ts\tDepartment of Geology\t\t", +"BRSN\ts\tUniversity of Wales, Bangor Research Unit\t\t", +"BRSU\th\tBryansk State University\t\t", +"BRTN\ts\tBrighton Natural History Society\t\t", +"BRU\ts\tBrown University\t\t", +"BRUN\ts\tBrunei Forestry Centre\t\t", +"BRV\ts\tColecciones paleontologicas del Departamento de Geociencias de la Universidad Nacional de Colombia\t\t", +"BRVU\ts\tVrije Universiteit Brussel\t\t", +"BRWK\ts\tBerwick-upon-Tweed Museum\t\t", +"BRY\ts\tBrigham Young University\t\t", +"BSA\ts\tBotanical Survey of India, Central Circle\t\t", +"BSB\ts\tFreie Universitaet Berlin, Institut fuer Biologie - Systematische Botanik und Pflanzengeographie\t\t", +"BSC\ts\tCentro Oriental de Ecosistemas y Biodiversidad\t\t", +"BSCA\ts\tAnza-Borrego Desert State Park\t\t", +"BSCVC\ts\tBemidji State University, Vertebrate Collections\t\t", +"BSD\ts\tBotanical Survey of India, Northern Circle\t\t", +"BSE\ts\tMoyse's Hall Museum\t\t", +"BSHC\ts\tBotanical Survey of India, Sikkim Himalayan Circle\t\t", +"BSI\ts\tBotanical Survey of India, Western Circle, Ministry of Environment and Forests\t\t", +"BSID\th\tBotanical Survey of India\t\t", +"BSIP\ts\tMinistry of Natural Resources, Department of Forests, Environment, and Conservation\t\t", +"BSIS\ts\tBotanical Survey of India, Industrial Section\t\t", +"BSJO\ts\tBotanical Survey of India, Arid Zone Circle\t\t", +"BSKU\ts\tKochi University\t\t", +"BSL\ts\tBotanical Society of London\t\t", +"BSM\ts\tBerliner Staatisches Museum\t\t", +"BSMB\tc\tBacteriology and Soil Microbiology Branch\t\t", +"BSMP\ts\tDepartment of Agriculture, Bureau of Science\t\t", +"BSN\ts\tBoston University, Biology Department\t\t", +"BSNH\ts\tBoston Society of Natural History\t\t", +"BSNS\ts\tBuffalo Society of Natural Sciences\t\t", +"BSPG\ts\tBayerische Staatssammlung fur Palaontologie und Geologie\tBS,BSP", +"BSRA\ts\tUniversity of Basrah, Biology Department\t\t", +"BSRM\ts\tBiological Station Reference Museum at Porto Novo\t\t", +"BST\ts\tBelfast Naturalists' Field Club\t\t", +"BSTN\ts\tBoothstown Botanical Society\t\t", +"BSU\ts\tBelgorod State University, Department of Botany\t\t", +"BSUH\ts\tBall State University, Biology Department\t\t", +"BSUMC\ts\tBall State University, Mammal Collection\t\t", +"BTCC\tc\tBulgarian Type Culture Collection\t\t", +"BTCC\tc\tBiotechnology Culture Collection Institution Pusat Penelitian dan Pengembangan Bioteknologi-LIPI\t\t", +"BTH\ts\tMuseum, Bath Royal Literary and Scientific Institution\t\t", +"BTJW\ts\tBridger Teton National Forest\t\t", +"BTN\ts\tBooth Museum of Natural History\t\t", +"BTT\ts\tBurton-upon-Trent Natural History and Archaeological Society\t\t", +"BTU\ts\tTechnische Universitaet Berlin\t\t", +"BU\th\tBrock University\t\t", +"BUA\ts\tUniversity of Baghdad, Plant Protection Department\t\t", +"BUAG\ts\tUniversity of Agronomical Sciences and Veterinary Medicine, Botany and Plant Physiology Department\t\t", +"BUC\ts\tUniversitatea din Bucuresti\t\t", +"BUCA\ts\tInstitute of Biology, Romanian Academy\t\t", +"BUCF\ts\tForest Research and Management Institute\t\t", +"BUCM\ts\tInstitute of Biology, Romanian Academy\t\t", +"BUCSAV\tc\tBiologicky Ustav\t\t", +"BUE\ts\tUniversity of Baghdad, Biology Department\t\t", +"BUEN\ts\tProteccion de la Naturaleza\t\t", +"BUF\ts\tBuffalo Museum of Science\t\t", +"BUH\ts\tUniversity of Baghdad, Biology Department\t\t", +"BUHGC\ts\tBarton-on-Humber Grammar School\t\t", +"BUHR\ts\tBaysgarth Museum\t\t", +"BUL\ts\tNatural History Museum of Zimbabwe\t\t", +"BULQ\ts\tBishop's University\t\t", +"BULU\ts\tUludag University, Biology Department\t\t", +"BUNH\ts\tUniversity of Baghdad\t\t", +"BUNS\ts\tUniversity of Novi Sad, Department of Biology and Ecology\t\t", +"BUPL\ts\tBucknell University, Biology Department\t\t", +"BURD\ts\tUniversity of Burdwan, Botany Department\t\t", +"BURI\th\tBanasthali University\t\t", +"BURP\ts\tBurpee Museum of Natural History\t\t", +"BUS\ts\tUniversity of Miami, Biology Department\t\t", +"BUT\ts\tButler University\t\t", +"BUTC\ts\tBoston University\t\t", +"BVC\ts\tBuena Vista College\t\t", +"BVS\th\tTransylvania University of Brasov\t\t", +"BYBS\ts\tBungay Botanical Society\t\t", +"BYDG\ts\tTechnical-Agriculture Academy, Department of Botany and Ecology\t\t", +"BYU\ts\tMonte L. Bean Life Science Museum\t\t", +"BZ\ts\tHerbarium Bogoriense\t\t", +"BZCM\th\tBozhou Vocational and Technical College\t\t", +"BZF\ts\tForest Research and Development Center and Nature Conservation\t\t", +"BZM\ts\tMuseum fur Naturkunde, Berlin\t\t", +"BZT\ts\tBiological Institute Titograd\t\t", +"C\ts\tBotanical Museum, Natural History Museum of Denmark\t\t", +"CA\ts\tChicago Academy of Sciences\t\t", +"CABI\tc\tCABI Genetic Resource Collection\t\t", +"CACA\ts\tCarlsbad Caverns National Park\t\t", +"CACC\tc\tChina Antibiotic Culture Collection Center\t\t", +"CACS\ts\tChicago Academy of Sciences, Department of Biology\t\t", +"CAEN\ts\tJardin Botanique de la Ville de Caen\t\t", +"CAES\ts\tConnecticut Agriculture Experiment Station\t\t", +"CAF\ts\tChinese Academy of Forestry\t\t", +"CAFB\ts\tNorthern Forestry Centre, Canadian Forest Service\t\t", +"CAG\ts\tUniversita di Cagliari\t\t", +"CAH\ts\tUniversity of Zimbabwe, Biological Sciences Department\t\t", +"CAHS\ts\tCrispus Attucks High School\t\t", +"CAHUP\ts\tUniversity of the Philippines Los Banos\t\t", +"CAI\ts\tCairo University, Botany Department\t\t", +"CAIA\ts\tAin Shams University, Department of Botany\t\t", +"CAIH\ts\tDesert Research Center, Mataria, Plant Ecology\t\t", +"CAIM\ts\tAgricultural Research Center\t\t", +"CAIM\tc\tCollection of Aquatic Important Microorganisms\t\t", +"CAIRC\ts\tNational Research Centre, Plant Chemistry and Systematics Department\t\t", +"CAIRCC\tc\tCAIRCC\t\t", +"CAIRNS\ts\tc/o North Queensland Naturalists' Club\t\t", +"CAL\ts\tBotanical Survey of India\t\t", +"CALI\ts\tUniversity of Calicut, Botany Department\t\t", +"CALP\ts\tUniversity of the Philippines at Los Banos\t\t", +"CALU\tc\tCollection of Algae in Leningrad, St. Petersburg, State University\t\t", +"CALVIN\th\tCalvin College\t\t", +"CAM\ts\tCentral Australian Museum\t\t", +"CAM\ts\tSt. John's College\t\t", +"CAME\ts\tUniversita di Camerino, Dipartimento de Botanica ed Ecologia\t\t", +"CAMS\tc\tCentre for Applied Mycological Studies\t\t", +"CAMU\ts\tCameron University, Department of Biological Sciences\t\t", +"CAN\ts\tCanadian Museum of Nature, Vascular Plant Section\t\t", +"CANA\ts\tCanadian Museum of Nature, Phycology Section\t\t", +"CANB\ts\tAustralian National Herbarium, Canberra\t\t", +"CANI\ts\tCanisius College, Biology Department\t\t", +"CANL\ts\tCanadian Museum of Nature, Lichenology Section\t\t", +"CANM\ts\tCanadian Museum of Nature, Bryology Section\t\t", +"CANT\ts\tSouth China Agricultural University, Forestry Department\t\t", +"CANTY\ts\tCanterbury Museum\t\t", +"CANU\ts\tUniversity of Canterbury, Department of Plant and Microbial Sciences\t\t", +"CAPM\tc\tCollection of Animal Pathogenic Microorganisms\t\t", +"CAR\ts\tMuseo de Historia Natural La Salle, Departamento de Botanica\t\t", +"CARAN\th\tHerbarium Carautanum\t\t", +"CARD\ts\tCaribbean Agricultural Research Institute\t\t", +"CARE\ts\tCaribbean Epidemiology Centre\t\t", +"CARI\ts\tCukurova Agricultural Research Institute\t\t", +"CARL\ts\tCarleton College, Biology Department\t\t", +"CARM\ts\tCarmarthen County Museum\t\t", +"CARS\ts\tUniversity of Surinam, Center for Agricultural Research\t\t", +"CART\ts\tCarthage College, Biology Department\t\t", +"CAS\ts\tCalifornia Academy of Sciences\t\t", +"CAS-IU\ts\tCalifornia Academy of Science, Indiana University Collection\t\t", +"CAS-SU\ts\tCalifornia Academy of Sciences, Stanford University Collection\tCAS(SU)", +"CAS:ANTH\ts\tCalifornia Academy of Sciences, Anthropology Collection", +"CAS:BOT\ts\tCalifornia Academy of Sciences, Botany Collection", +"CAS:DIA\ts\tCalifornia Academy of Sciences, Diatom collection", +"CAS:DS\ts\tCalifornia Academy of Sciences, Dudley Stanford Collection", +"CAS:EGG\ts\tCalifornia Academy of Sciences, Egg & Nest Collection", +"CAS:ENT\ts\tCalifornia Academy of Sciences, Entomology collection", +"CAS:HERP\ts\tCalifornia Academy of Sciences, Herpetology collection", +"CAS:ICH\ts\tCalifornia Academy of Sciences, Ichthyology collection", +"CAS:IU\ts\tCalifornia Academy of Sciences, Indiana University fish collection", +"CAS:IZ\ts\tCalifornia Academy of Sciences, Invertebrate Zoology collection", +"CAS:MAM\ts\tCalifornia Academy of Sciences, Mammalogy Collection", +"CAS:ORN\ts\tCalifornia Academy of Sciences, Ornithology Collection", +"CAS:SU\ts\tCalifornia Academy of Sciences, Stanford University Collection of fish", +"CAS:SUA\ts\tCalifornia Academy of Sciences, Stanford University Collection of amphibians", +"CAS:SUR\ts\tCalifornia Academy of Sciences, Stanford University Collection of reptiles", +"CAS:TYPE\ts\tCalifornia Academy of Sciences, Entomology Type Collection", +"CASM\ts\tChicago Academy of Sciences, Museum of Natural History\t\t", +"CASMB\ts\tCentre of Advanced Study in Marine Biology\t\t", +"CASS\ts\tChinese Academy of Sciences, Shenyang\t\t", +"CAT\ts\tUniversita di Catania, Dipartimento di Botanica e Orto Botanico\t\t", +"CATA\th\tCatalina Island Conservancy\t\t", +"CATH\th\tCatholicate College\t\t", +"CATIE\ts\tTropical Agricultural Research and Training Center (CATIE), Plant Production Department\t\t", +"CAU\ts\tChina Agricultural University\t\t", +"CAUP\ts\tUniversidad del Cauca\t\t", +"CAUP\tc\tCollection of Algae of Charles University, Prague\t\t", +"CAUSC\ts\tUniversidade Federal de Santa Catarina Centro de Agrarias\t\t", +"CAVA\ts\tUniversity of California at Berkeley\t\t", +"CAWC\ts\tConservation Commission of the Northern Territory\tNTM", +"CAY\ts\tInstitut de Recherche pour le Developpement (IRD)\t\t", +"CAYM\ts\tNational Trust for the Cayman Islands\t\t", +"CB\tc\tThe CB Rhizobium Collection\t\t", +"CB\ts\tJihoceske Muzeum\t\t", +"CBAS\tc\tBacteria Collection of Environmemt and Health (Colecao de Bacterias do Ambiente e Saude)\t\t", +"CBC\ts\tCentre for Biodiversity Conservation\t\t", +"CBD\ts\tCollezione Ittiologica Balma-Delmastro\t\t", +"CBD\tc\tUSF Center for Biological Defense\t\t", +"CBF\ts\tColeccion Boliviana de Fauna\tCBFC", +"CBFS\ts\tUniversity of South Bohemia, Department of Botany\t\t", +"CBG\ts\tAustralian National Botanic Gardens\t\t", +"CBM\ts\tNatural History Museum and Institute\t\t", +"CBM:ZC\ts\tNatural History Museum and Institute, Zoological Collection", +"CBMAI\tc\tBrazilian Collection of Microorganisms from the Environment and Industry (Colecao Brasileira de Microrganismos de Ambiente e Industria)\t\t", +"CBNM\ts\tCedar Breaks National Monument\t\t", +"CBNSA\th\tConservatoire botanique national Sud-Atlantique\t\t", +"CBPF\th\tConservatoire Botanique Pierre Fabre\t\t", +"CBS\tsc\tWesterdijk Fungal Biodiversity Institute\t\t", +"CBSIZA\ts\tCaspian Biological Station Institute of Zoology\t\t", +"CBTCCCAS\tc\tThe Cell Bank of Type Culture Collection of Chinese Academy of Sciences\t\t", +"CBU\ts\tCape Breton University\t\t", +"CBU\ts\tChungbuk National University, School of Life Science\t\t", +"CBY\ts\tRoyal Museum and Art Gallery\t\t", +"CC\tc\tCSIRO Canberra Rhizobium Collection\t\t", +"CCA-Marburg\tc\t Culture Collection of Algae at the University of Marburg\t\t", +"CCAC\ts\tUniversidade Federal do Ceara, Centro Ciencias Agrarias\t\t", +"CCAC\tc\tCulture Collection of Algae at the University of Cologne\t\t", +"CCALA\tc\tCulture Collection of Autotrophic Organisms\t\t", +"CCAP\tc\tCulture Collection of Algae and Protozoa\t\t", +"CCARM\tc\tCulture Collection of Antimirobial Resistant Microorganisms\t\t", +"CCAU\ts\tCentral China Agricultural University\t\t", +"CCB\tc\tColecao de Culturas de Basidiomicetos\t\t", +"CCB\ts\tCentral College, Bangalore\t\t", +"CCBAS\tc\tCulture Collection of Basidiomycetes\t\t", +"CCBAU\tc\tCulture Collection, Beijing Agricultural University\t\t", +"CCC\tc\tCulture Collection of Clavicipitaceae\t\t", +"CCC\tc\tCyanobacterial Culture Collection, National Centre for Conservation and Utilisation of Blue Green Algae\t\t", +"CCCC\ts\tCarthage College\t\t", +"CCCIEB\tc\tCulture Collections of Microorgansisms of Center of Genetic Engineering and Biotechnology\t\t", +"CCCM\tc\tCanadian Center for the Culture of Microorganisms\t\t", +"CCCR\th\tFederal University of Tocantins\t\t", +"CCCryo\tc\tCulture Collection of Cryophilic Algae\t\t", +"CCCS\tc\tCulture Collection of Ciliates and their Symbionts\t\t", +"CCCZ\ts\tUniversity of Malawi\t\t", +"CCDB\ts\tCrustacean Collection of the Department of Biology\t\t", +"CCDM\tc\tCulture Collection of Department of Microbiology\t\t", +"CCDM\tc\tCulture Collection of Dairy Microorganisms Laktoflora\t\t", +"CCDMBI\tc\tCulture Collection, Department of Microbiology\t\t", +"CCEB\tc\tCulture Collection of Entomogenous Bacteria\t\t", +"CCEC\ts\tMuseum, Centre de Conservation et d'Etude des Collections\t\t", +"CCF\tc\tColleccion de Cuttivos Finlay\t\t", +"CCF\tc\tCulture Collection of Fungi\t\t", +"CCFC\tc\tCanadian Collection of Fungal Cultures\t\t", +"CCFEE\tc\tCulture Collection of Fungi From Extreme Environments\t\t", +"CCFHE\ts\tCornwall College of Further and Higher Education, Natural Sciences Department\t\t", +"CCFL\ts\tChad National Museum\t\t", +"CCFVB\tc\tFacultat de Veterinaria, Universitat Autonoma de Barcelona\t\t", +"CCG\ts\tChengdu College of Geology\tCHG", +"CCG\ts\tUniversity of Cape Coast, Botany Department\t\t", +"CCGB\tc\tCulture Collection of Bacillus and Related Genera (Instituto Oswaldo Cruz)\t\t", +"CCGVCC\tc\tChina Centre for General Viruses Culture Collection\t\t", +"CCH\th\tUniversity of Arizona South, Agricultural Extension Service\t\t", +"CCIAL\tc\tCultures Cells for Institute Adolfo Lutz\t\t", +"CCIBSO\tc\tCulture Collection IBSO\t\t", +"CCIBt\tc\tCulture Collection at the Institute of Botany, Sao Paulo\t\t", +"CCIM\tc\tCulture Collection of Industrial Microorganisms\t\t", +"CCM\tc\tCzech Collection of Microorganisms\tCCM", +"CCM-A\tc\tColeccion de Cultivos Microbianos\t\t", +"CCM\ts\tChangchun College of Traditional Chinese Medicine, Department of Chinese Materia Medica\t\t", +"CCM\ts\tCarter County Museum\t\t", +"CCMAC\tc\tCulture Collection of Macromycetes (Basidiomycotina and Ascomycotina)\t\t", +"CCMCU\tc\tCulture Collection of Microorganisms\t\t", +"CCMF\tc\tUniversity of Portsmouth\t\t", +"CCMGE\ts\tChernyshev Central Museum of Geological Explorations,Collections of the Department of Herpetology, Zoological Institute of the Russian Academy of Sciences\t\t", +"CCMH\th\tConcordia College\t\t", +"CCMI\tc\tCulture Collection of Industrial Microorganisms\t\t", +"CCML\ts\tColeccion Ictiologica del Departamento de Ciencias Marinas de la Universidad de la Laguna\t\t", +"CCMM\tc\tMoroccan Coordinated Collections of Microorganisms\t\t", +"CCMP\tc\tProvasoli-Guillard National Center for Marine Algae and Microiota\t\t", +"CCNH\ts\tCentral Michigan University, Center for Cultural and Natural History\t\t", +"CCNL\ts\tConnecticut College, Botany Department\t\t", +"CCNP\ts\tCarlsbad, Carlsbad Caverns National Park\t\t", +"CCNP\tc\tCulture Collection of Northern Poland\t\t", +"CCNU\ts\tCentral China Normal University, Biology Department\t\t", +"CCO\ts\tCarleton University, Biology Department\t\t", +"CCOS\tc\tCulture Collection of Switzerland\t\t", +"CCPF\tc\tCollection of Phytopathogenic Fungi\t\t", +"CCR\ts\tChichester District Museum\t\t", +"CCRI\tc\tCollection du Centre de Recherche en Infectiologie\t\t", +"CCRI\tscb\tThe Central Coffee Research Institute\t\t", +"CCSIIA\tc\tCulture Collection of Sichuan Industrial Institute Antibiotics\t\t", +"CCSRL\ts\tCentro Studi e Ricerche Ligabue\t\t", +"CCSU\ts\tCentral Connecticut State University, Biological Sciences Department\t\t", +"CCT\tc\tColecao de Culturas Tropical\t\t", +"CCTCC\tc\tChina Center for Type Culture Collection\t\t", +"CCTM\tc\tCentre de Collection de Type Microbien, Institut de Microbiologie, Universite de Lausanne\t\t", +"CCTR\tc\tCulture Collection Trutnov\t\t", +"CCTS\th\tUniversidade Federal de Sao Carlos\t\t", +"CCTU\tc\tCulture Collection of Tabriz University\t\t", +"CCUF\ts\tUniversidade Federal de Alagoas, Centro de Ciencias Biologicas\t\t", +"CCUG\tc\tCulture Collection, University of Goteborg, Department of Clinical Bacteriology\t\t", +"CCVC\ts\tCentenary College, Vertebrate Collection\t\t", +"CCVCC\tc\tChina Center For Virus Culture Collection\t\t", +"CCW\ts\tCasper College\t\t", +"CCY\tc\tCulture Collection Yerseke, Department of Marine Microbiology\t\t", +"CCY\tc\tCulture Collection of Yeasts, Slovak Academy of Sciences, Institute of Chemistry\t\t", +"CDA\tc\tCanadian Department of Agriculture\t\t", +"CDA\ts\tCalifornia Department of Food and Agriculture\t\t", +"CDBB\tc\tColeccion Nacional de Cepas Microbianas y Cultivos Celulares\t\t", +"CDBI\ts\tChengdu Institute of Biology\t\t", +"CDC\tc\tCenters for Disease Control and Prevention\t\t", +"CDC\ts\tChangdu Institute for Drug Control\t\t", +"CDCM\ts\tChengdu College of Traditional Chinese Medicine\t\t", +"CDFM\ts\tCardiff Museum\t\t", +"CDFN\ts\tCanadian Forest Service - Atlantic\t\t", +"CDN\ts\tWhitgift School\t\t", +"CDRI\ts\tCentral Drug Research Institute\t\t", +"CDRS\ts\tInvertebrate Collection\t\t", +"CDS\ts\tCharles Darwin Research Station, Botany Department\t\t", +"CEAM\ts\tCentro de Entomologica y Acarologia\t\t", +"CEB\ts\tTadulako University\t\t", +"CEBU\ts\tUniversity of San Carlos, Biology Department\t\t", +"CECT\tc\tColeccion Espanola de Cultivos Tipo\t\t", +"CEDD\ts\tInternational Center for Ethnomedicine and Drug Development\t\t", +"CEDiT\ts\tCentre of Excellence for Dinophyte Taxonomy\t\t", +"CEEF\ts\tEscuela Nacional de Ciencias Forestales\t\t", +"CEET\ts\tEl Colegio de la Frontera Sur, Colleccion de Insectos Asociados a Plantas Cultivadas en la Frontera Sur\t\t", +"CEL\ts\tUniversity of Illinois, Crop Sciences Department\t\t", +"CELM\ts\tColeccion Entomologica \"Luis Maria Murillo\"\t\t", +"CELMS\tc\tCollection of Environmental and Laboratory Microbial Strains\t\t", +"CEMBP\ts\tCentre of Excellence in Marine Biology\t\t", +"CEN\ts\tGenetic Resources and Biotechnology (CENARGEN), EMBRAPA\t\t", +"CENA\ts\tCentro de Energia Nuclear na Agricultura, Universidade de Sao Paulo\t\t", +"CENA\ts\tCentro Nacional de Proteccion Vegetal\t\t", +"CENACUMI\tc\tCentro Nacional de Cultivos Microbianos (National Center For Microbial Cultures)\t\t", +"CENG\ts\tCentro Experimental de Nueva Guinea\t\t", +"CEP\tc\tEntomopathogenic Fungal Culture Collection of Argentina\t\t", +"CEPEC\ts\tCEPEC, CEPLAC\t\t", +"CEPH\tb\tFoundation Jean Dausset (CEPH)\t\t", +"CEPIM\tc\tCentro per gli Enterobatteri Patogeni per l'Italia Meridionale\t\t", +"CEPM\tc\tCEPM- Centre d'Etudes sur le Polymorphisme des Micro-organismes\t\t", +"CERL/BIC\ts\tUnited States Army, Biological Inventory Collection\t\t", +"CERN\ts\tUniversity\t\t", +"CES\ts\tThe Centre for Ecological Sciences, Indian Institute of Science\t\t", +"CESJ\ts\tUniversidade Federal de Juiz de Fora, Departamento de Botanica\t\t", +"CESK\ts\tMuzeum Teainska\t\t", +"CEST\ts\tCentral Experiment Station\t\t", +"CET\ts\tCentro de Estudios Tropicales\t\t", +"CETESB\tc\tSetor de Pesquisa Tecnologica de Sistemas de Tratamento de Efluentes Domesticos\t\t", +"CEU\ts\tCollage of Eastern Utah\t\t", +"CFB\ts\tNorthern Forestry Centre, Canadian Forest Service\t\t", +"CFBH\ts\tCelio F.B. Haddad Herpetological Collection, Departamento de Zoologia, Universidade Estadual Paulista\t\t", +"CFBP\tc\tCollection Francaise des Bacteries Phytopathogenes\t\t", +"CFCC\tcb\tChina Forestry Culture Collection Center\t\t", +"CFI\ts\tGenetic Resources and Biotechnology (CENARGEN), EMBRAPA\t\t", +"CFIA\th\tCanadian Food Inspection Agency\t\t", +"CFMR\tsc\tUSDA Forest Service, Center for Forest Mycology Research\tFPL", +"CFN\ts\tClifton College, Biology Department\t\t", +"CFNL\ts\tUniversidad Autonoma de Nuevo Leon\t\t", +"CFQ\tc\tCepario de la Facultad de Quimica\t\t", +"CFRB\ts\tChinese Academy of Forestry, Forest Research Institute\t\t", +"CFS\ts\tCanadian Forest Service, Pacific Forest Research Centre\t\t", +"CFSHB\ts\tNorth Coast Regional Botanic Gardens\t\t", +"CFUA\ts\tUniversidad Austral de Chile\t\t", +"CG\tc\tEmbrapa Collection of Fungi of Invertebrates\t\t", +"CGC\tb\tCaenorhabditis Genetics Center\t\t", +"CGE\ts\tUniversity of Cambridge, Department of Plant Sciences\t\t", +"CGEC\ts\tChina Entomological Research Institute\t\t", +"CGG\ts\tCambridge University Botanic Garden\t\t", +"CGH\ts\tNational Museum of Prague\t\t", +"CGMCC\tc\tChina General Microbiological Culture Collection Center, Chinese Academy of Sciences\t\t", +"CGMS\ts\tUniversidade Federal de Mato Grosso do Sul, Departamento de Biologia\t\t", +"CGN\ts\tCentre for Genetic Resources, The Netherlands\t\t", +"CGRIS\tb\tChinese Crop Germplasm Resources Information Network\t\t", +"CGSC\tc\tE. coli Genetic Stock Center\t\t", +"CH\ts\tCirculo Herpetologico de Panama\t\t", +"CH-AG\tc\tCollection de Recherche\t\t", +"CHA\ts\tHebei Agrotechnical Teachers College\t\t", +"CHAB\ts\tFar East Forestry Research Institute\t\t", +"CHAF\ts\tChaffey College, Biology Department\t\t", +"CHAM\ts\tI.N.T.A., E.E.A. La Rioja\t\t", +"CHAP\ts\tUniversidad Autonoma Chapingo\t\t", +"CHAPA\ts\tColegio de Postgraduados, Botanica, IRENAT\t\t", +"CHARL\ts\tCharleston Museum\t\t", +"CHAS\ts\tChicago Academy of Sciences\t\t", +"CHAS\ts\tSouthern Research Station\t\t", +"CHBG\ts\tChristchurch Botanic Gardens\t\t", +"CHE\ts\tSociete Nationale des Sciences Naturelles et Mathematiques de Cherbourg\t\t", +"CHEB\ts\tRegional Museum Cheb\t\t", +"CHEL\ts\tChelsea Physic Garden\t\t", +"CHELB\ts\tCheltenham College for Boys\t\t", +"CHEP\ts\tEscuela Superior Politecnica del Chimborazo\t\t", +"CHER\ts\tYu. Fedcovich Chernivtsi State University, Botany Department\t\t", +"CHFD\ts\tChelmsford and Essex Museum\t\t", +"CHI\ts\tUniversity of Illinois, Biological Sciences Department\t\t", +"CHIA\ts\tNational Chiayi Agricultural College, Forestry Department\t\t", +"CHIC\ts\tChicago Botanic Garden, Research Department\t\t", +"CHINM\ts\tInstituto Nacional de Microbiologia\t\t", +"CHIOC\ts\tHelminthological Collection of Oswaldo Cruz Institute (Coleccion. Helmintologica del Instituto Oswaldo Cruz)\t\t", +"CHIP\ts\tInstituto de Historia Natural, Departamento de Botanica\t\t", +"CHIS\ts\tAcademy of Sciences of Moldova\t\t", +"CHISA\ts\tUniversity of Agriculture\t\t", +"CHL\ts\tCheltenham Grammar School\t\t", +"CHM\ts\tCheltenham Art Gallery and Museum\t\t", +"CHM\ts\tCharleston Museum\t\t", +"CHNCB\ts\tCentre d'Historia Natural de la Conca de Barbera\t\t", +"CHOCO\ts\tUniversidad Tecnologica del Choco\t\t", +"CHOM\ts\tOkresni muzeum Chomutov\t\t", +"CHPU\ts\tChelyabinsk State Pedagogical University, Botany Department\t\t", +"CHR\ts\tAllan Herbarium\tLCR:CHR", +"CHRB\ts\tRutgers University - Cook College\t\t", +"CHRG\ts\tGrosvenor Museum\t\t", +"CHSC\ts\tCalifornia State University, Biological Sciences Department\t\t", +"CHT\ts\tCheltenham College\t\t", +"CHUG\ts\tGaryounis University, Botany Department\t\t", +"CHULA\tc\tMicrobiology Department Faculty of Science\t\t", +"CHUNB\ts\tUniversity of Brasilia Herpetological Collection\t\t", +"CHUR\ts\tBuendner Natur-Museum\t\t", +"CI\ts\tCarnegie Institution of Washington, Plant Biology Department\t\t", +"CIAN\ts\tInstituto Nacional de Investigaciones Forestales, Agricolas y Pecuarias (INIFAP)\t\t", +"CIAN\ts\tCentro de Investigaciones Agricolas Nortoeste\t\t", +"CIAT\tb\tCentro Internacional de Agricultura Tropical (International Center for Tropical Agriculture)\t\t", +"CIAT:Bean\tb\tCentro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Bean Collection", +"CIAT:Cassava\tb\tCentro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Cassava Collection", +"CIAT:Forage\tb\tCentro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Forages Collection", +"CIAT:Rhizobium\tc\tCentro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Rhizobium Collection", +"CIB\ts\tChengdu Institute of Biology\t\t", +"CIB\ts\tCentro de Investigaciones Biologicas del Noroeste, S.C. (Mexico)\t\t", +"CIB\ts\tUniversidad Veracruzana\t\t", +"CIBC\ts\tInternational Institute of Biological Control\t\t", +"CIBIO\ts\tCentro de Investigacao em Biodiversidade e Recursos Geneticos\t\t", +"CIBM\ts\tCentro Invest. Biol. Noroeste\t\t", +"CIC\ts\tAlbertson College of Idaho, Biology Department\t\t", +"CICC\tc\tChina Center for Industrial Culture Collection\t\t", +"CICCM\tc\tCawthron Institute Culture Collection of Micro-algae\t\t", +"CICESE\ts\tCentro de Investigacion Cientifica y de Educacion Superior de Ensenada\t\t", +"CICIM\tc\tCulture and Information Centre of Industrial Microorganisms of China's Univeristies\t\t", +"CICIMAR\ts\tCentro Interdisciplinario de Ciencias Marinas\t\t", +"CICV\tc\tCentro de Investigaciones en Ciencias Veterinarias\t\t", +"CICY\ts\tCentro de Investigacion Cientifica de Yucatan, A.C. (CICY)\t\t", +"CIDA\ts\tAlbertson College, Museum of Natural History\t\t", +"CIECRO\ts\tCounty Record Office, Cambridgeshire\t\t", +"CIES\tc\tCentro de Investigacion, Experimentacion y Servicios del Champinon\t\t", +"CIFE\ts\tCentral Institute of Fisheries Education\t\t", +"CIIDIR\ts\tInstituto Politecnico Nacional\t\t", +"CIJC\ts\tMuzeului Judetean Covasna, Collection of Insects\t\t", +"CIMAP\ts\tCentral Institute of Medicinal and Aromatic Plants\t\t", +"CIMAR\ts\tUniversidad Catolica de Valparaiso, Centro de Investigaciones del Mar\t\t", +"CIMI\ts\tCentro Interdisciplinario de Investigacion para el Desarrollo Integral Regional (CIIDIR) IPN-Michoacan\t\t", +"CIMMYT\tscb\tInternational Maize and Wheat Improvement Center\t\t", +"CIMNH\ts\tAlbertson College of Idaho, Orma J. Smith Museum of Natural History\t\t", +"CIMSC\tc\tCollezione Instituto di Microbiologia\t\t", +"CINC\ts\tUniversity of Cincinnati, Biological Sciences Department\t\t", +"CIP\tc\tPasteur Institute Collection, Biological Resource Center of Pasteur Institute (CRBIP)\tCIP", +"CIP\ts\tCentro de Investigaciones Pesqueras\t\t", +"CIP\tc\tInternational Potato Center\t\t", +"CIP\tb\tCentro Internacional de las Papas\t\t", +"CIPDE\tc\tCollection of Insect Pathogens, Dept. of Entomology\t\t", +"CIPT\tc\tCollection Institut Pasteur Tuberculose\t\t", +"CIQR\ts\tEl Colegio de la Frontera Sur\t\t", +"CIR\ts\tRoyal Agricultural College\t\t", +"CIRAD\tsb\t Centre de Cooperation Internationale en Recherche Agronomique pour le Developpement\t\t", +"CIRUV\ts\tColeccion Ictiologica de Referencia de la Universidad del Valle\t\t", +"CIS\ts\tAcademia Sinica and State Planning Commission\t\t", +"CIS\ts\tCalifornia Insect Survey\t\t", +"CIS\ts\tCranbrook Institute of Science\tCISM", +"CISM\tc\tVerticillium dahliae from cotton\t\t", +"CISM\tc\tNifTAL Rhizobium Collection (Asia Center)\t\t", +"CIT\ts\tCitrus Research Institute\t\t", +"CITA\ts\tThe Citadel, Biology Department\t\t", +"CIUC\ts\tCentro Interdipartimentale dell'Universita Museo di Storia Naturale e del Territorio\t\t", +"CIZ\ts\tCentro de Investigaciones Zoologicas\t\t", +"CKE\ts\tCalke Abbey\t\t", +"CL\ts\tBabes-Bolyai University\t\t", +"CLA\ts\tUniversitatea de Stiinte Agricole si Medicina Veterinara\t\t", +"CLARK\th\tDr. Charles F. and Wilhelmina Husser Clark Herbarium\t\t", +"CLCB\ts\tLaboratorul de Ecologie\t\t", +"CLCC\ts\tAugustana University College\t\t", +"CLD\ts\tCleveland Literary and Philosophical Society\t\t", +"CLE\ts\tTullie House Museum\t\t", +"CLEMS\ts\tClemson University, Biological Sciences Department\t\t", +"CLEV\ts\tCleveland Museum of Natural History\t\t", +"CLEY\ts\tCoastal Ecology Research Station\t\t", +"CLF\ts\tInstitut des Universitaires et Musee Lecoq\t\t", +"CLI\ts\tLiterary and Philosophical Institution of Chatham\t\t", +"CLIB\tc\tCollection de Levures d'Interet Biotechnologique Collection of Yeasts of Biotechnological Interest\t\t", +"CLIOC\tc\tColecao de Leishmania do Instituto Oswaldo Cruz\tIOC:CL", +"CLM\ts\tCleveland Museum of Natural History, Botany Department\t\t", +"CLMP\ts\tDepartment of Conservation & Land Management\t\t", +"CLNP\ts\tCrater Lake National Park\t\t", +"CLOE\ts\tClitheroe Castle Museum\t\t", +"CLP\ts\tForest Products Research and Development Institute, Department of Science and Technology\t\t", +"CLQCA\tc\tColeccion de Levaduras quito catolica\t\t", +"CLR\ts\tAll Saint's Church, Colchester Borough Council\t\t", +"CLU\ts\tUniversita della Calabria\t\t", +"CM\ts\tCarnegie Museum of Natural History\tCMNH", +"CM-IEA\ts\tUniversidad Autonoma de Tamaulipas (Mexico)\t\t", +"CM-MBM-UAC\ts\tColeccion Mastozoologica de la Museo de Biodiversidad Maya, Universidad Autonoma de Campeche\tCM-MBM-UAC", +"CM-UMSNH\ts\tUniversidad de Michoacan (Mexico)\t\t", +"CM:M\ts\tCarnegie Museum of Natural History, Section of Mammals", +"CM:O\ts\tCarnegie Museum of Natural History, Section of Birds", +"CM\ts\tChongqing Museum\t\t", +"CMA\ts\tCrayford Manor House Adult Education Centre\t\t", +"CMAA\tc\tCulture Collection of Agriculture and Environmental Importance\t\t", +"CMBGCAS\tc\tCollection of Marine Biological Germplasm\t\t", +"CMBK\ts\tThe City Museum and Art Gallery, Department of Natural History\t\t", +"CMBY\ts\tCamberley Museum\t\t", +"CMC\ts\tColeccion Mastozoologica del Centro de Investigacion en Biodiversidad y Conservacion,Universidad Autonoma del Estado de Morelos\t\t", +"CMC\ts\tCanterbury Museum\t\t", +"CMC\ts\tCentral Michigan University, Department of Biology\t\t", +"CMCC\tc\tNational Center for Medical Culture Collections\t\t", +"CMCNA\ts\tMuseo de Ciencias Naturales y Antropologicas \"Prof. A. Serrano\"\t\t", +"CMDM-PUJ\tc\tColeccion de Microorganismos de la Pontificia Universidad Javeriana (Collection Microorganisms of the Pontificia Universidad Javeriana)\tCMDM-PUJ", +"CMEI\ts\tClements' Museum of Exotic Insects\t\t", +"CMFRI\ts\tSee FMRI\t\t", +"CMGP\ts\tCentral Museum of Geological Prospecting\t\t", +"CMH\ts\tCanadian Museum of History\t\t", +"CMIZASDPRK\ts\tCustody Museum\t\t", +"CMKKU\tc\tClinical Diagnostic Microbiology Srinagarind Hospital, Faculty of Medicine\t\t", +"CML\ts\tUniversidad Nacional de Tucuman, Coleccion de Mamiferos Lillo (Argentina)\t\t", +"CML\tc\tColecao Micologica de Lavras\t\t", +"CMM\ts\tBradford Art Galleries and Museums, Natural Sciences Department\t\t", +"CMM\tc\tCulture Collection of Phytopathogenic Fungi (Colecao de Culturas de Fungos Fitopatogenicos Prof. Maria Menezes)\t\t", +"CMMC\tc\tChina Marine Microbe Collection\t\t", +"CMMED\tc\tCenter for Marine Microbial Ecology & Diversity Collection\t\t", +"CMMEX\ts\tUniversidad Autonoma de Baja California\t\t", +"CMMF\th\tJardin botanique de Montreal\t\t", +"CMMI\ts\tChinese Academy of Traditional Medicine\t\t", +"CMML\ts\tColorado State University Herbarium\t\t", +"CMN\ts\tCanadian Museum of Nature\t\t", +"CMN:Annelid\ts\tCanadian Museum of Nature, Annelid Collection", +"CMN:Bird\ts\tCanadian Museum of Nature, Bird Collection", +"CMN:Crustacean\ts\tCanadian Museum of Nature, Crustacean Collection", +"CMN:Fish\ts\tCanadian Museum of Nature, Fish Collection", +"CMN:GenInvert\ts\tCanadian Museum of Nature, General Invertebrate Collextion", +"CMN:Herp\ts\tCanadian Museum of Nature, Amphibian and Reptile Collection", +"CMN:Insect\ts\tCanadian Museum of Nature, Insect Collection", +"CMN:Mammal\ts\tCanadian Museum of Nature, Mammal Collection", +"CMN:Mollusc\ts\tCanadian Museum of Nature, Mollusc Collection", +"CMN:Parasite\ts\tCanadian Museum of Nature, Parasite Collection", +"CMNAR\ts\tCanadian Museum of Nature, Amphibian and Reptile Collection\t\t", +"CMNC\ts\tCanadian Museum of Nature, Neotropical Cerambycidae Collection\t\t", +"CMNFI\ts\tCanadian Museum of Nature, Fish Collection\t\t", +"CMNH\ts\tThe Cleveland Museum of Natural History\t\t", +"CMNS\ts\tMuseum of Natural History, Shanghai\t\t", +"CMNZ\ts\tCanterbury Museum\t\t", +"CMPH\th\tColegio de Postgraduados\t\t", +"CMPR\th\tCentre for Medicinal Plants Research\t\t", +"CMS\th\tChristian Missionary Society College\t\t", +"CMSK\ts\tCity Museum, Sheffield\t\t", +"CMSU\ts\tCentral Missouri State University\t\t", +"CMU\ts\tChiang Mai University\t\t", +"CMUB\th\tChiang Mai University\t\t", +"CMUH\th\tCentral Mindanao University\t\t", +"CMUT\ts\tChiang Mai University\t\t", +"CMV\ts\tCentre Marie-Victorin\t\t", +"CMW\tc\tForestry and Agricultural Biotechnology Institute, University of Pretoria, Pretoria\t\t", +"CMY\ts\tR. G. Kar Medical College, Botany Department\t\t", +"CN\ts\tUniversite de Caen\t\t", +"CN\tc\tWellcome Collection of Bacteria, Burroughs Wellcome Research Laboratories\t\t", +"CNC\ts\tCanadian National Collection of Insects, Arachnids, and Nematodes\t\t", +"CNC:Arachnida\ts\tCanadian National Collection of Insects, Arachnids, and Nematodes, Arachnida (Mites, Ticks, Spiders)", +"CNC:Coleoptera\ts\tCanadian National Collection of Insects, Arachnids, and Nematodes, Coleoptera (Beetles)", +"CNC:Diptera\ts\tCanadian National Collection of Insects, Arachnids, and Nematodes, Diptera (Flies)", +"CNC:Hemiptera\t\tCanadian National Collection of Insects, Arachnids, and Nematodes, ", +"CNC:Hymenoptera\ts\tCanadian National Collection of Insects, Arachnids, and Nematodes, Hymenoptera (Sawflies, Parasitic Wasps, Ants, Wasps, Bees)", +"CNC:Lepidoptera\ts\tCanadian National Collection of Insects, Arachnids, and Nematodes, Lepidoptera (Butterflies, Moths)", +"CNC:Miscellaneous\ts\tCanadian National Collection of Insects, Arachnids, and Nematodes, Miscellaneous Insect Orders", +"CNC:Nematoda\ts\tCanadian National Collection of Insects, Arachnids, and Nematodes, Nematoda (Roundworms)", +"CNCI\ts\tCanadian National Collection Insects\t\t", +"CNCM\tc\tCollection Nationale de Cultures de Microorganismes\t\t", +"CNCTC\tc\tCzech National Collection of Type Cultures\t\t", +"CNE\ts\tVictoria Jubilee Museum\t\t", +"CNEN-LABPC\tc\tLaboratorio de Pocos de Caldas\t\t", +"CNF\ts\tCroatian Mycological Society\t\t", +"CNH\th\tCanakkale Onsekiz Mart University\t\t", +"CNHM\ts\tCroatian Natural History Museum, Botany Department\t\t", +"CNHM\ts\tCincinnati Museum of Natural History\t\t", +"CNHM:ORNITH\ts\tCincinnati Museum of Natural History, Ornithology collection", +"CNHP\ts\tBeijing Natural History Museum\t\t", +"CNHS\ts\tCroydon Natural History and Scientific Society\t\t", +"CNM\ts\tCheltenham Naturalists' Association\t\t", +"CNM-CM\tc\tFilamentous fungus collection of the Spanish National Center for Microbiology\t\t", +"CNM\ts\tCentro Nacional de Microbiologia\t\t", +"CNMC\ts\tColorado National Monument\t\t", +"CNMS\ts\tColombo National Museum\t\t", +"CNMT\th\tUniversidade Federal de Mato Grosso\t\t", +"CNPO\th\tEmbrapa Pecuaria Sul\t\t", +"CNPS\ts\tCentro Nacional de Pesquisas da Soja\t\t", +"CNPSo\tc\tCulture Collection of Diazotrophic and Plant Growth Promoting Bacteria of Embrapa Soja\t\t", +"CNR\th\tCrimean Natural Reserve\t\t", +"CNRO\ts\tCentre National de Recherches Oceanographiques\t\t", +"CNRS\ts\tCentre National de la Recherche Scientifique\t\t", +"CNRZ\tc\tCentre National de Recherches Zootechniques\t\t", +"CNS\ts\tAustralian Tropical Herbarium\t\t", +"CNSF\th\tCentre National de Semences Forestieres\t\t", +"CNU\ts\tCapital Normal University, College of Life Sciences\t\t", +"CNU\ts\tChungnam National University\t\t", +"CNU\ts\tChonbuk National University\t\t", +"CNUK\th\tChungnam National University\t\t", +"CNWGRGL\tb\tChinese National Waterfowl Germplasm Resources Gene Library\t\t", +"CO\ts\tMuseum National d'Histoire Naturelle, Department of Marine Biology\t\t", +"COA\ts\tHerbario, Universidad de Cordoba - Jardin Botanico de Cordoba\t\t", +"COA\ts\tCollege of the Atlantic, Museum\t\t", +"COAD\tc\tColecao Octavio de Almeida Drumond\t\t", +"COAH\ts\tHerbario Amazonico Colombiano (Instituto Amazonico de Investigaciones Cientificas SINCHI)\tCOAH", +"COCA\ts\tComision Tecnico Consultiva de Coeficientes de Agostadero (COTECOCA)\t\t", +"COCAZ\th\tCoconino National Forest Herbarium\t\t", +"COCH\ts\tUniversidad Mayor de San Simon, Departamento de Botanica\t\t", +"COCO\ts\tColorado College, Biology Department\t\t", +"CODAGEM\ts\tUniversidad Autonoma del Estado de Mexico\t\t", +"CODIMAR\tc\tCentro de Investigaciones Biologicas del Noroeste\t\t", +"COFC\ts\tUniversidad de Cordoba, Departamento de Biologia Vegetal\t\t", +"COI\ts\tUniversity of Coimbra\t\t", +"COL\ts\tUniversidad Nacional de Colombia\t\t", +"COLG\ts\tColumbus State University, Biology Department\t\t", +"COLM\ts\tColorado National Monument\t\t", +"COLO\ts\tUniversity of Colorado\t\t", +"COLOM\ts\tColorado State Museum\t\t", +"COM\ts\tColombo Museum\t\t", +"CON\ts\tBristol, Clifton and West of England Zoological Society's Gardens\t\t", +"CONC\ts\tUniversidad de Concepcion, Departamento de Botanica\t\t", +"CONN\ts\tUniversity of Connecticut, Department of Ecology and Evolutionary Biology\t\t", +"CONV\ts\tConverse College, Biology Department\t\t", +"COP\ts\tColeccion Ornitologica Phelps\t\t", +"COR\ts\tUniversidade Federal de Mato Grosso do Sul, Departamento de Ciencias do Ambiente\t\t", +"CORB\ts\tCorchester School\t\t", +"CORBIDI\ts\tCentro de Ornitologia y Biodiversidad\t\t", +"CORD\ts\tUniversidad Nacional de Cordoba\t\t", +"Coriell\tcb\tCoriell Institute for Medical Research\t\t", +"CORO\ts\tIUTAG, Departamento de Investigacion\t\t", +"CORT\ts\tState University of New York College at Cortland, Biological Sciences Department\t\t", +"CORU\ts\tUniversidad Veracruzana, Campus Cordoba\t\t", +"COV\ts\tHerbert Art Gallery and Museum\t\t", +"COVY\ts\tCoventry and District Natural History Society\t\t", +"CP\ts\tRoyal Veterinary and Agricultural University, Plant Biology Department\t\t", +"CPAC\tc\tCentro de Pesquisas Agropecuarias do Cerrado\t\t", +"CPAP\ts\tCentro de Pesquisas Agropecuarias do Tropico Umido\t\t", +"CPAP\ts\tHerbario, Centro de Pesquisas Agropecuarias do Pantanal, EMBRAPA\t\t", +"CPATU\ts\tCentro de Pesquisa Agroflorestal da Amazonia Oriental-Embrapa\t\t", +"CPB\ts\tNational Institute for the Control of Pharmaceutical and Biological Products\t\t", +"CPC\tc\tCulture collection of Pedro Crous\t\t", +"CPCC\tc\tCanadian Phycological Culture Centre\tUTCC", +"CPDC\ts\tCentro de Pesquisas do Cacau\t\t", +"CPF\ts\tKwaZulu-Natal Nature Conservation Service\t\t", +"CPH\ts\tUniversity of the Pacific, Biological Sciences Department\t\t", +"CPHS\tc\tWHO/FAO/OIE Collaborating Centre for Reference and Research on Leptospirosis, Western Pacific Region\t\t", +"CPM\ts\tChristoffel Park Museum\t\t", +"CPMM\ts\tDr. Alvaro de Castro Provincial Museum\t\t", +"CPNP\ts\tCuc Phuong National Park\t\t", +"CPPIPP\tc\tCollection of Plant Pathogens\t\t", +"CPPLIP\ts\tCentro de Pesquisas Paleontologias Llewellyn Ivor Price\t\t", +"CPRC\ts\tCaribbean Primate Research Center Museum\t\t", +"CPRR\tc\tLaboratorio de Doenca de Chagas\t\t", +"CPS\ts\tUniversity of Puget Sound, Slater Museum of Natural History\t\t", +"CPS\ts\tWyoming-Colorado Paleontological Society\t\t", +"CPSC\ts\tUniversity of Puget Sound\t\t", +"CPSU\ts\tCalifornia Polytechnic State University, San Luis Obispo\t\t", +"CPU\ts\tChina Pharmaceutical University\t\t", +"CPUN\ts\tUniversidad Nacional de Cajamarca, Departamento de Biologia\t\t", +"CPUP\ts\tCalifornia Polytechnic University\t\t", +"CPZ\tc\tCentro Panamericano de Zoonosis\t\t", +"CQBG\ts\tChongqing Botanical Garden\t\t", +"CQNM\ts\tChongqing Natural History Museum\t\t", +"CR\ts\tMuseo Nacional de Costa Rica\t\t", +"CRA-CIN\tc\tConsiglio per la Ricerca e sperimentazione in Agricoltura - Centro ricerche per le Colture Industriali ( Research Centre for Industrial Crops)\t\t", +"CRA-COLMIA\tc\tCollezione Nazionale di Microrganismi di interesse Agrario ed Industriale ed Ambientale - COL.MIA\t\t", +"CRA-OLI\tb\tCentro di Ricerca per l'Olivicoltura e l'Industria Olearia\t\t", +"CRA-PAV\tc\tCentro di Ricerca per la Patologia Vegetale\tISPaVe", +"CRAF\ts\tUniversity of Craiova, Phytopathology Department\t\t", +"CRAI\ts\tUniversity of Craiova\t\t", +"CRBF\tc\tCollection de genomes d'organismes symbiotiques\t\t", +"CRBK\ts\tCranbrook School\t\t", +"CRBO\tc\tCentre de Ressource Biologique Oenologique\tIOEB", +"CRBY\ts\tCrosby Library\t\t", +"CRC\tc\tChlamydomonas Resource Center\t\t", +"CRCA\ts\tInstituto dos Cereais\t\t", +"CRCM\ts\tWashington State University, Charles R. Conner Museum\t\t", +"CRCM:Bird\ts\tWashington State University, Charles R. Conner Museum, bird collection", +"CRCM:Mammal\ts\tWashington State University, Charles R. Conner Museum, Mammal Collection", +"CRD\ts\tInstituto Politecnico Nacional, Coleccion Cientifica de Fauna Silvestre (Mexico)\t\t", +"CRE\ts\tCosta Rica Expeditions\t\t", +"CRE\ts\tUniversity of Southern California\t\t", +"CREG\ts\tInstituto Tecnologico Agropecuario de Jalisco\t\t", +"CRGF\tc\tCollection de Recursos Geneticos Fungicos, Instituto de Ecologia y Systematica\t\t", +"CRH\ts\tCentre de Recherche en Hydrobiologie\t\t", +"CRI\ts\tUniversidade do Extremo Sul Catarinense, Bairro Universitario\t\t", +"CRIFC\ts\tCentral Research Institute for Field Crops in Turkey\t\t", +"CRK\ts\tUniversity College, Plant Science Department\t\t", +"CRL\tc\tCentro de Referencia Para Lactobacilos\t\t", +"CRLA\ts\tCrater Lake National Park, Museum and Archives Collections\t\t", +"CRMC\ts\tCollege of the Redwoods, Mendocino Coast Campus, Biological Sciences Department\t\t", +"CRMM\ts\tCentre de Recherche sur les Mammiferes Marins\t\t", +"CRO\ts\tWellington College\t\t", +"CRP\ts\tI.N.T.A., E.E.A. Bariloche\t\t", +"CRRHA\ts\tCentre Regional de Recherches en Hydrobiologie Appliquee\t\t", +"CS\tc\tCSIRO Collection of Living Micro-algae\t\t", +"CS\ts\tMusee des Dinosaures d'Esperaza (Aude)\t\t", +"CS\ts\tColorado State University, Biology Department\t\t", +"CSAT\ts\tColegio de Postgraduados, Campus Tabasco\t\t", +"CSAU\ts\tNational Agrarian University, Southern Branch \"Crimean Agrotechnological University\", Department of Botany, Plant Physiology and Genetics\t\t", +"CSB\ts\tSt. John's University/College of Saint Benedict, Biology Department\t\t", +"CSC\ts\tColegio del Sagrado Corazon\t\t", +"CSC-CLCH\tc\tCentro Substrati Cellulari, Cell Lines Collection and Hybridomas\t\t", +"CSCA\ts\tCalifornia State Collection of Arthropods\t\t", +"CSCC\tc\tCSIRO Starter Culture Collection\t\t", +"CSCCE\ts\tChadron State College, Entomology Collection\tCSCC", +"CSCCV\ts\tChadron State College, Collection of Vertebrates\t\t", +"CSCN\ts\tChadron State College\t\t", +"CSCS\ts\tCebu State College of Science and Technology, Agricultural Biology Laboratory\t\t", +"CSCS\ts\tCalifornia State University, Turlock\t\t", +"CSDS\ts\tDesert Studies Center\t\t", +"CSFI\ts\tCentral-South Forestry University\t\t", +"CSGP\ts\tServicos Geologicos de Portugal\t\t", +"CSGT\ts\tCollegio San Giuseppe\t\t", +"CSH\ts\tShanghai Chenshan Botanical Garden\t\t", +"CSIR\tc\tCouncil for Scientific and Industrial Research\t\t", +"CSIRO\ts\tCommonwealth Science & Industrial Research Organization\t\t", +"CSIRO:Ichthyology\ts\tCommonwealth Science & Industrial Research Organization, Australian National Fish Collection", +"CSJ\ts\tColegio de San Jose, Museo de Historia Natural, Medellin\t\t", +"CSLA\ts\tCalifornia State University, Department of Biological Sciences\t\t", +"CSLB\ts\tCalifornia State University at Long Beach\t\t", +"CSMA\tc\tCentro di Studio dei Microorganismi Autotrofi - CNR\t\t", +"CSPM\ts\tColegio Lasalle Palma de Mallorca\t\t", +"CSPU\ts\tCalifornia State Polytechnic University, Biological Sciences Department\t\t", +"CSPUP\ts\tCalifornia State Polytechnic University, Pomona\t\t", +"CSR\ts\tCaucasus State Nature Biosphere Reserve\t\t", +"CSTIU\ts\tFaculty of Science, University of Tokyo\t\t", +"CSU\ts\tColorado State University\tCSUC", +"CSU\ts\tUniversity of Central Oklahoma, Biology Department\t\t", +"CSUC\ts\tCalifornia State University, Chico, Vertebrate Museum\t\t", +"CSUCI\th\tCalifornia State University Channel Islands\t\t", +"CSUF\ts\tCalifornia State University, Fresno\t\t", +"CSUH\th\tChelyabinsk State University\t\t", +"CSULB\ts\tCalifornia State University, Long Beach\t\t", +"CSUN\ts\tCalifornia State University, Northridge\t\t", +"CSUNIV\th\tCharleston Southern University\t\t", +"CSUR\tc\tCollection de Souches de l'Unite des Rickettsies\t\t", +"CSUSB\th\tCalifornia State University, San Bernardino\t\t", +"CSUTC\ts\tColorado State University, Mammalogy Teaching Collection\t\t", +"CSVFC\ts\tCaradoc and Severn Valley Field Club\t\t", +"CT\ts\tUniversity of Cape Town, Botany Department\t\t", +"CTC\th\tChongqing Normal University\t\t", +"CTES\ts\tInstituto de Botanica del Nordeste\t\t", +"CTESN\ts\tUniversidad Nacional del Nordeste\t\t", +"CTM\tc\tCentre de Biotechnologie de Sfax culture collection\t\t", +"CTN\ts\tFree Library and Museum\t\t", +"CTNRC\ts\tThai National Reference Collections\t\t", +"CTR\ts\tCharles T. Ramsden historical collection\t\t", +"CTS\ts\tChongqing Teachers College\t\t", +"CTY\ts\tCanterbury Literary and Philosophical Institution\t\t", +"CU\tsb\tCornell University\t\t", +"CUAC\ts\tClemson University\t\t", +"CUBK\ts\tDepartment of Biology, Chonbuk National University\t\t", +"CUC\tc\tCepario de la Universidad de Concepcion de Chile\t\t", +"CUE\ts\tCairo University\t\t", +"CUETM\tc\tCollection Unite Ecotoxicologie Microbienne, INSERM\t\t", +"CUFH\ts\tCumhuriyet University, Biology Department\t\t", +"CUG\ts\tCollection Universite Poitiers\t\t", +"CUH\ts\tCalcutta University, Botany Department\t\t", +"CUHK\tsc\tBiology Department, Chinese University of Hong Kong\t\t", +"CUI\ts\tCentral College, Iowa\t\t", +"CUIC\ts\tCornell University, Invertebrate Collections\t\t", +"CUMV\ts\tCornell University Museum of Vertebrates\tCUVC", +"CUMV:Amph\ts\tCornell University Museum of Vertebrates, Amphibian Collection", +"CUMV:Bird\ts\tCornell University Museum of Vertebrates, Bird Collection", +"CUMV:Fish\ts\tCornell University Museum of Vertebrates, Fish Collection", +"CUMV:Mamm\ts\tCornell University Museum of Vertebrates, Mammal Collection", +"CUMV:Rept\ts\tCornell University Museum of Vertebrates, Reptile Collection", +"CUMZ\ts\tCarleton University, Museum of Zoology\t\t", +"CUMZ\ts\tCameroon University, Museum of Zoology\t\t", +"CUMZ\ts\tChulalongkorn University Museum of Natural History\tCUB", +"CUMZ:R\ts\tChulalongkorn University Museum of Natural History, Reptile Collection", +"CUMZ\ts\tCambridge University, Museum of Zoology\t\t", +"CUNRC\ts\tUniversidad Nacional de Rio Cuarto, Coleccion de Mamiferos (Argentina)\t\t", +"CUP\ts\tCornell University, Plant Pathology Herbarium\t\t", +"CUP\ts\tCatholic University of Peking\t\t", +"CUP\ts\tCharles University\t\t", +"CURLA\th\tCentro Universitario Regional del Litoral Atlantico\t\t", +"CUS\ts\tCusino Wildlife Research Station, Natural Resources Department\t\t", +"CUSC\ts\tClemson University, Vertebrate Collections\t\t", +"CUVC\ts\tUniversidad del Valle, Departamento de Biologia\t\t", +"CUW\ts\tClark University, Biology Department\t\t", +"CUWM\ts\tClark University\t\t", +"CUZ\ts\tUniversidad Nacional San Antonio Abad del Cusco\t\t", +"CV\ts\tMunicipal Museum of Chungking\t\t", +"CVCC\tc\tCenter for Veterinary Culture Collection\t\t", +"CVCC\tc\tChina Veterinary Culture Collection\t\t", +"CVCM\tc\tCentro Venezolano de Colecciones de Microorganismos\t\t", +"CVCW\ts\tClinch Valley College, University of Virginia, Biology Department\t\t", +"CVM\ts\tCity Museum, Natural History Department\t\t", +"CVRD\ts\tReserva Natural da Vale do Rio Doce\t\t", +"CVUL\ts\tUniversite Laval, Collection de Vertebres\t\t", +"CVULA\ts\tColeccion Vertebrados, Facultad de Ciencias, La Hechicera, Universidad de los Andes\t\t", +"CWB\ts\tKharkov State University\t\t", +"CWC\ts\tCentral Wyoming College\t\t", +"CWDR\ts\tCawdor Castle\t\t", +"CWU\ts\tV. N. Karasin National University\t\t", +"CY\tc\tCentre des Yersinia\t\t", +"CYN\ts\tChipstead Valley Primary School\t\t", +"CYP\ts\tMinistry of Agriculture, Natural Resources and Environment, Forestry Department\t\t", +"CZ-IICT\ts\tCentro de Zoologia, Instituto de Investigacao Cientifica Tropical\t\t", +"CZAA\ts\tCatedra de Zoologia Agricola\t\t", +"CZACC\ts\tColeccion Zoologia, Academia de Ciencias de Cuba\t\t", +"CZCEN\ts\tColeccion Zoologica de la Facultad de Ciencias Exactas y Naturales\t\t", +"CZH\th\tHanshan Normal University\t\t", +"CZIP\ts\tUniversidad de Magallanes, Instituto de la Patagonia (Chile)\t\t", +"CZL\ts\tCentro de Zoologia\t\t", +"CZRMA\ts\tColeccion Zoologica Regional (Mammalia) del Instituto de Historia Natural y Ecologia\t\t", +"CZUAA\ts\tUniversidad Autonoma de Aguascalientes (Mexico)\t\t", +"CZUG\ts\tUniversidad de Guadalajara,Centro de Estudios en Zoologia, Entomologia\t\t", +"DABUH\ts\tUniversity of Helsinki, Department of Applied Biology\t\t", +"DABZ\ts\tDepartment of Agriculture, Zimbabwe\t\t", +"DACB\ts\tBangladesh National Herbarium\t\t", +"DACL\ts\tLondon Research Centre\t\t", +"DACT\tc\tDept. Agricult. Chem. Technol.\t\t", +"DAFH\ts\tDepartment of Agriculture and Fisheries\t\t", +"DAG\th\tMountain Botanical Garden of the Dagestan Scientific Centre\t\t", +"DAKAR\ts\tUniversite Cheikh Anta Diop, Departement de Biologie Vegetale\t\t", +"DAL\ts\tDalhousie University, Biology Department\t\t", +"DANV\ts\tUmweltamt Darmstadt\t\t", +"DAO\ts\tAgriculture and Agri-Food Canada\t\t", +"DAOM\tsc\tNational Mycological Herbarium, Agriculture and Agri-Food Canada\tCCFC,DAOMC", +"DAR\tc\tPlant Pathology Herbarium\t\t", +"DARI\ts\tInsect Collection, New South Wales Department of Agriculture\t\t", +"DAS\ts\tAgriculture and Agri-Food Canada\t\t", +"DASF\ts\tDepartment of Agriculture, Stock and Fisheries\t\t", +"DAU\th\tUniversity of Daugavpils\t\t", +"DAV\ts\tUniversity of California, Plant Biology\t\t", +"DAVFP\ts\tPacific Forestry Centre, Canadian Forest Service\t\t", +"DAVH\ts\tUniversity of California, Environmental Horticulture Department\t\t", +"DAWES\th\tThe Dawes Arboretum\t\t", +"DBAI\ts\tInstituto de Ciencias Biologicas\t\t", +"DBAU\ts\tUniversidade Santa Ursula\t\t", +"DBC\ts\tUniversity College, Botany Department\t\t", +"DBCUCH\ts\tUniversidad de Chile, Departamento de Biologia Celular y Genetica\t\t", +"DBFFEUCS\ts\tDepartamento de Biologia de la Faculdad de Filosofia y Educacion de la Universidad de Chile\t\t", +"DBG\ts\tSam Mitchel Herbarium of Fungi, Denver Botanic Gardens\t\t", +"DBKKU1\tc\tDepartment of Biology, Faculty of Science\t\t", +"DBKKU2\tc\tDepartment of Biology, Faculty of Science\t\t", +"DBKKU3\tc\tDepartment of Biology, Faculty of Science\t\t", +"DBM\tc\tDepartment of Biochemistry and Microbiology\t\t", +"DBMU\tc\tBoonchird lab, Department of Biotechnology, Mahidol University\t\t", +"DBMU2\tc\tPanbangred lab, Department of Biotechnology, Mahidol University\t\t", +"DBN\ts\tNational Botanic Gardens\t\t", +"DBS\tc\tDepartment of Biological Culture Collection\t\t", +"DBSE\ts\tUniversidade Federale Sergipe\t\t", +"DBSNU\ts\tDepartment of Biology, Shaanxi Normal University\t\t", +"DBUA\tc\tZoological Collection of the Biology Department, University of the Azores\t\t", +"DBUM-IPT\tc\tDepartment of Biochemistry, Faculty of Medicine, University of Malaya\t\t", +"DBUP\tc\tAlgal Culture Collection\t\t", +"DBV\tc\tDivision of Standardisation\t\t", +"DBVPG\tc\tIndustrial Yeasts Collection\t\t", +"DBY\ts\tCity of Derby Museum and Art Gallery\t\t", +"DCBU\ts\tUniversidade Federal de Sao Carlos\t\t", +"DCCBC\tcb\tDunaliella Culture Collection at Brooklyn College\t\t", +"DCDS\ts\tDipartimento di Coltivazione e Difesa delle Specie Legnose dell'Universita, Sezione Entomologia Agraria\t\t", +"DCH\ts\tDavidson College, Biology Department\t\t", +"DCMB\ts\tUniversidade do Amazonas\t\t", +"DCMD\ts\tDerby City Museum and Art Gallery\t\t", +"DCMP\ts\tUniversidade Federal do Parana\t\t", +"DCN-UNRC\ts\tDepartamento de Ciencias Naturales, Universidad Nacional de Rio Cuarto\t\t", +"DCPC\ts\tDominicusCirillus[deceased]\t\t", +"DCR\ts\tDoncaster Museum and Art Gallery\t\t", +"DD\ts\tForest Research Institute, Indian Council of Forestry Research and Education, Systematic Botany Discipline\t\t", +"DDFF\ts\tDepartamento de Defensa Fitossanitarista\t\t", +"DDMS\th\tFundacao Universidade Federal da Grande Dourados\t\t", +"DE\ts\tDebrecen University, Botany Department\t\t", +"DE-CSIRO\tc\tCSIRO Insect Pathogen Culture Collection\t\t", +"DEBU\ts\tOntario Insect Collection, University of Guelph\tUOG:DEBU", +"DECA\ts\tAgnes Scott College, Biology Department\t\t", +"DECV\ts\tDouglas Ecological Consultants\t\t", +"DEE\ts\tMcManus Galleries, Natural History Department\t\t", +"DEES\ts\tUniversidade de Sao Paulo, Piracicaba\t\t", +"DEFS\ts\tUniversidade de Sao Paulo\t\t", +"DEI\ts\tSenckenberg Deutsches Entomologisches Institut\t\t", +"DEIB\ts\tDeutsches Entomologisches Institut\t\t", +"DEK\ts\tNorthern Illinois University, Biological Sciences Department\t\t", +"DELS\ts\tUniversity of Delaware, Plant Science Department\t\t", +"DELTA\ts\tDelta Waterfowl and Wetlands Research Station\t\t", +"DEN\ts\tDenison University, Biology Department\t\t", +"DENA\ts\tWatt Institute\t\t", +"DENF\ts\tGrand Mesa-Uncompahgre-Gunnison Natonal Forests\t\t", +"DENH\ts\tUniversity of New Hampshire\t\t", +"DERM\ts\tIntermountain Experiment Station\t\t", +"DES\tsb\tDesert Botanical Garden, Research Department\t\t", +"DEV\th\tSt. Joseph's College\t\t", +"DEVA\ts\tDeath Valley National Park\t\t", +"DEWV\ts\tDavis and Elkins College, Biology and Environmental Science Department\t\t", +"DEZA\ts\tDipartimento di Entomologia e Zoologia Agraria dell'Universita\t\t", +"DEZC\ts\tDipartimento di Entomologia e Zoologia Applicate all'Ambiente \"Carlo Vidano\"\t\t", +"DFCZ\ts\tForest Research Institute, Malawi\t\t", +"DFD\ts\tDartford Borough Museum\t\t", +"DFEC\ts\tDesert Forestry Experimental Centre\t\t", +"DFEC\ts\tDepartment of Forestry and Environmental Science, State University of New York\t\t", +"DFF\tc\tForest Pathology Culture Collection, Pacific Forest Research Centre\t\t", +"DFLC\ts\tEscola Superior de Agricultura\t\t", +"DFP\tc\tDFP Culture Collection\t\t", +"DFRU\ts\tUniversity of New Brunswick\t\t", +"DFS\ts\tDumfries and Galloway Natural History and Antiquarian Society\t\t", +"DFSM\ts\tDumfries Museum\t\t", +"DFV\ts\tDivision of Fisheres\t\t", +"DGBU\ts\tDepartment of Geology, Pusan National University\t\t", +"DGN\ts\tDarlington Museum\t\t", +"DGR\tb\tDivision of Genomic Resources, University of New Mexico\t\t", +"DGR:Bird\ts\tDivision of Genomic Resources, University of New Mexico, bird tissue collection", +"DGR:Ento\ts\tDivision of Genomic Resources, University of New Mexico, entomology tissue collection", +"DGR:Fish\ts\tDivision of Genomic Resources, University of New Mexico, fish tissue collection", +"DGR:Herp\ts\tDivision of Genomic Resources, University of New Mexico, herpetology tissue collection", +"DGR:Mamm\ts\tDivision of Genomic Resources, University of New Mexico, mammal tissue collection", +"DGS\ts\tThe Manx Museum\t\t", +"DGU\th\tDaegu University\t\t", +"DGUB\tc\tDepartment of Genetics, University of Bratislava\t\t", +"DH\ts\tHobart and William Smith Colleges, Biology Department\t\t", +"DHISUB\ts\tDepartment of Hydrobiology and Ichthyology, Sofia Univiversity\t\t", +"DHL\ts\tUniversity of Louisville, Biology Department\t\t", +"DHM\ts\tUniversity of Durham, Botany Department\t\t", +"DHMB\ts\tDepartment of Harbours and Marine\t\t", +"DHNS\ts\tDunbartonshire Natural History Society\t\t", +"DI\ts\tUniversite de Bourgogne, Laboratoire de Phytobiologie Cellulaire\t\t", +"DIA\ts\tMuseu do Dundo\t\t", +"DIAM\th\tUniversidade Federal dos Vales do Jequitinhonha e Mucuri\t\t", +"DIN\ts\tMuseum National d'Histoire Naturelle\t\t", +"DINH\ts\tDelta Institute of Natural History\t\t", +"DINO\ts\tDinosaur National Monument\t\t", +"DIS\ts\tDinamation International Society\t\t", +"DISCA\ts\tEstacion Biologica de Rancho Grande, Ministerio del Ambiente y Recursos Naturales Renovables\t\t", +"DISKO\ts\tDanish Arctic Station\t\t", +"DiSTA\ts\tPhytoplasma Collection University of Bologna\tDiSTA", +"DIX\ts\tDixie College, Natural History Museum\t\t", +"DKG\ts\tJuniper Hall Field Centre\t\t", +"DLF\ts\tStetson University, Biology Department\t\t", +"DLU\th\tDa Lat University\t\t", +"DLY\ts\tDudley and Midland Geological and Scientific Society and Field Club\t\t", +"DM\ts\tDominion Museum\t\t", +"DM\ts\tThe Dinosaur Museum\t\t", +"DMB\ts\tDurban Museum\t\t", +"DMBC\ts\tDominick Moth and Butterfly Collection\t\t", +"DMBUK\tc\tDepartment of Microbiology, Univeristy of Kelaniya\t\t", +"DMCCUS\tc\tSchool of Biological Sciences Culture Collection\t\t", +"DMCMU2\tc\tDepartment of Microbiology, Faculty of Medicine\t\t", +"DMCU\tc\tMicrobiology Department, Faculty of Science\t\t", +"DMDC\ts\tDouala Museum\t\t", +"DMFS\ts\tCrichton Royal Institution Museum\t\t", +"DMHN\th\tThe University of Newcastle\t\t", +"DMIV\tc\tDepartment of Microbiology and Immunology\t\t", +"DMKKU1\tc\tDepartment of Microbiology, Faculty of Medicine\t\t", +"DMKKU2\tc\tDepartment of Microbiology, Faculty of Medical Science\t\t", +"DMKU\tc\tDepartment of Microbiology Kasetsart University\t\t", +"DMMU1\tc\tDepartment of Microbiology, Faculty of Science\t\t", +"DMMU3\tc\tDepartment of Microbiology, Faculty of Medicine Siriraj Hospital\t\t", +"DMMZ\tc\tDepartment of Medical Microbiology, University of Zurich\t\t", +"DMNH\ts\tDelaware Museum of Natural History\t\t", +"DMNH\ts\tDayton Museum of Natural History, Biology Department\t\t", +"DMNS\ts\tDenver Museum of Nature and Science\tDMNH,DNHC", +"DMNS:Bird\ts\tDenver Museum of Nature and Science, Ornithology Collections", +"DMNS:Mamm\ts\tDenver Museum of Nature and Science, Mammology Collection", +"DMPMC\tc\tDepartment of Microbiology, University of Western Australia\t\t", +"DMSA\ts\tDurban Museum\t\t", +"DMSC\ts\tMedicinal Plants Research Institute, Department of Medical Sciences\t\t", +"DMSP\ts\tDavis Mountains State Park\t\t", +"DMSRDE\tc\tDMSRDE Culture Collection\t\t", +"DMST\tc\tCulture Collection for Medical Microorganism, Department of Medical Sciences\t\t", +"DMTH\ts\tBritannia Royal Naval College\t\t", +"DMU\ts\tMithila University, Botany Department\t\t", +"DMUIJ\tc\tDepartment of Microbiology, Jakarta Pusat\t\t", +"DMUP\tc\tMicrobiology and Biophysics Charles University\t\t", +"DMUR\tc\tDepartment of Mycology\t\t", +"DMVB\tc\tDepartment of Microbiology, Veterinary Branch of National Strain Collection\t\t", +"DNA\ts\tDepartment of Natural Resources, Environment and the Arts\t\t", +"DNAP\th\tDepartment of Primary Industry and Fisheries\t\t", +"DNATAX\tb\tDNA-TAX\t\t", +"DNHM\ts\tDalian Museum of Natural History\t\t", +"DNHM\ts\tDinosaur Natural History Museum\t\t", +"DNPM\ts\tSetor de Paleontologia do Departamento Nacional de Producao Mineral\t\t", +"DNS\ts\tDundee Naturalists' Society\t\t", +"DNZ\th\tDonetsk Botanical Garden of the National Academy of Sciences of Ukraine\t\t", +"DO\ts\tSociete d'Agriculture Sciences et Arts\t\t", +"DOA\tc\tDepartment Of Agriculture, Thailand\t\t", +"DOMO\ts\tCollegio Mellerio Rosmini\t\t", +"DOR\ts\tDorset County Museum\t\t", +"DORC\ts\tDorset County Museum\t\t", +"DORCM\ts\tDorset Royal County Museum\t\t", +"DORT\ts\tBotanischer Garten Rombergpark, Stadt Dortmund\t\t", +"DOV\ts\tDelaware State University, Department of Agriculture and Natural Resources\t\t", +"DPBA\ts\tDepartamento de Patologia Vegetal\t\t", +"DPC\tc\tDairy Products Research Center Culture Collection Teagasc\t\t", +"DPIC\ts\tBelo Horizonte, Instituto de Ciencias Biologicas\t\t", +"DPIH\ts\tDepartment of Primary Industry (formerly DAHT)\t\t", +"DPIQM\ts\tDepartment of Primary Industries\t\t", +"DPMWA\ts\tDorthy Page Museum of Wasilla\t\t", +"DPNC\ts\tDenison Pequotsepos Nature Center\t\t", +"DPPC\ts\tDepartment of Agriculture, Taiwan\t\t", +"DPU\ts\tDePauw University, Botany and Bacteriology Department\t\t", +"DPUA\tc\tDepartamento de Patologia/ICB\t\t", +"DPUP\ts\tUniversidade Federal de Maringa\t\t", +"DQTC\ts\tDaqing Teachers College, Biology Department\t\t", +"DR\ts\tTechnische Universitaet Dresden\t\t", +"DS\ts\tCalifornia Academy of Sciences, Botany Department\t\t", +"DSC\ts\tDelta State University, Biological Sciences Department\t\t", +"DSC\tc\tDicty Stock Center\t\t", +"DSEC\ts\tUniversidade Federal da Paraiba\t\t", +"DSIR\ts\tDepartment of Scientific and Industrial Research\t\t", +"DSM\tc\tDeutsche Sammlung von Mikroorganismen und Zellkulturen GmbH\tDSMZ", +"DSM\ts\tUniversity of Dar es Salaam, Botany Department\t\t", +"DSMZ\tc\tDeutsche Sammlung von Mikroorganismen und Zellkulture\t\t", +"DSP\ts\tFitzsimon's Snake Park\t\t", +"DSSC\tb\tDrosophila Species Stock Center\t\t", +"DSU\ts\tDnipropetrovsk National University, Department of Geobotany, Soil, and Ecology\t\t", +"DSY\ts\tDewsbury Museum\t\t", +"DTE\th\tCentro de Investigaciones Cientificas y Transferencia de Tecnologia a la Produccion (CICyTTP-CONICET)\t\t", +"DTIC\ts\tDepartamento Parasitologia\t\t", +"DTN\ts\tDarlington and Teesdale Naturalists' Field Club\t\t", +"DU\ts\tDuke University Vertebrate Collection\t\t", +"DUB\ts\tNational Botanic Gardens\t\t", +"DUBN\ts\tDublin Naturalists' Field Club\t\t", +"DUE\ts\tUniversity of Dundee\t\t", +"DUF\ts\tUniversity of Dicle, Biological Department, Botany\t\t", +"DUGAND\th\tUniversidad del Atlantico\t\t", +"DUH\ts\tUniversity of Delhi, Botany Department\t\t", +"DUIS\ts\tUniversitaet Duisburg, Fachbereich 6, Botanik\t\t", +"DUKE\ts\tDuke University, Biology Department\t\t", +"DUL\ts\tUniversity of Minnesota, Biology Department\t\t", +"DUM\tc\tDelhi University Mycological Herbarium\t\t", +"DUM\ts\tZooligical Museum of Science and Art Faculty\t\t", +"DUOF\th\tDuzce University\t\t", +"DUP\th\tDumlupinar University\t\t", +"DUR\ts\tSoutheastern Oklahoma State University, Biological Sciences Department\t\t", +"DUSS\ts\tUniversitaet Duesseldorf\t\t", +"DVBID\tc\tDivision Vector-Borne Infectious Diseases\t\t", +"DVCC\ts\tDiablo Valley College\t\t", +"DVCM\ts\tDiablo Valley College Museum\t\t", +"DVM\ts\tDiablo Valley College, Biology Department\t\t", +"DVNM\ts\tDeath Valley National Monument\t\t", +"DVR\ts\tDover Corporation Museum\t\t", +"DVZUT\ts\tDepartment of Vertebrate Zoology\t\t", +"DWC\ts\tWest Chester University, Biology Department\t\t", +"DWN\ts\tDarwen Library\t\t", +"DWP\th\tDisney Wilderness Preserve/The Nature Conservancy\t\t", +"DWT\tc\tWood Technology and Forest Research Division\t\t", +"DWU\ts\tDakota Wesleyan University, Biology Department\t\t", +"DZCU\ts\tCalcutta University\t\t", +"DZIB\ts\tUniversidade Estadual de Campinas\t\t", +"DZKU\ts\tDepartment of Biology, Shaanxi Normal University\t\t", +"DZMU\ts\tDepartment of Zoology, Monash University\t\t", +"DZS\ts\tDevizes Museum\t\t", +"DZSASP\ts\tDepartamento de Zoologia, Secretaria da Agricultura\t\t", +"DZUC\ts\tDepartamento de Zoologia da Universidade de Coimbra\t\t", +"DZUFRGS\ts\tDepartamento de Zoologia da Universidade Federal do Rio Grande do Sul\t\t", +"DZUH\ts\tDepartamento de Zoologia, Universidad de Havana\t\t", +"DZUL\ts\tDepartamento de Zoologia, Universidad de La Laguna\t\t", +"DZUP\ts\tUniversidade Federal do Parana, Museu de Entomologia Pe. Jesus Santiago Moure\t\t", +"DZVMLP\ts\tDepartamento Cientifico de Zoologia de Vertebrados\t\t", +"DZVU\ts\tUniversidad de Uruguay\t\t", +"E\tsb\tRoyal Botanic Garden Edinburgh\t\t", +"EA\ts\tNational Museums of Kenya\t\t", +"EAA\ts\tEstonian Agricultural University\t\t", +"EAC\ts\tUniversidade Federal do Ceara, Departamento de Biologia\t\t", +"EAFM\th\tInstituto Federal de Educacao, Ciencia e Tecnologia do Amazonas\t\t", +"EALA\th\tJardin Botanique d'Eala\t\t", +"EAN\ts\tUniversidade Federal da Paraiba, Campus III - CCA, Departamento de Fitotecnia\t\t", +"EAP\ts\tEscuela Agricola Panamericana\t\t", +"EAPZ\ts\tEscuela Agricola Panamericana\t\t", +"EAR\ts\tEarlham College, Biology Department\t\t", +"EATRO\tc\tUganda Trypanosomiasis Research Organization\t\t", +"EBA\ts\tEdinburgh Academy Field Centre\t\t", +"EBCC\ts\tUniversidad Nacional Autonoma de Mexico, Estacion de Biologia \"Chamela\"\t\t", +"EBD\ts\tEstacion Biologica de Donana\t\t", +"EBDS\ts\tEstacion Biologica de Donana\t\t", +"EBE\ts\tEastbourne Museum\t\t", +"EBF\ts\tHubei Forestry Institute\t\t", +"EBH\ts\tBotanical Society of Edinburgh\t\t", +"EBL\th\tEcosystem Research and Development Bureau\t\t", +"EBMC\ts\tUniversidad de Chile\t\t", +"EBMTV\ts\tEstacion de Biologia Marina del Instituto Tecnologico de Veracruz\t\t", +"EBNHS\ts\tEdinburgh Natural History Society\t\t", +"EBRG\ts\tMuseo de la Estacion Biologia de Rancho Grande\t\t", +"EBUAP\ts\tLaboratorio de Herpetologia, Escuela de Biologia, Benemerita Universidad Autonoma de Puebla\t\t", +"EBUM\ts\tUniversidad Michoacana de San Nicolas de Hidalgo\t\t", +"EBV\ts\tLaboratoire de Biologie Generale et de Botanique\t\t", +"ECACC\tc\tEuropean Collection of Authenticated Cell Cultures\t\t", +"ECENT\ts\tEast Central University\t\t", +"ECH\ts\tElmira College\t\t", +"ECK\th\tBuffalo State College\t\t", +"ECM\ts\tHubei College of Traditional Chinese Medicine, Department of Chinese Materia Medica\t\t", +"ECNB\ts\tEscuela Nacional Ciencias\t\t", +"ECO-SC-M\ts\tColeccion Mastozoologica de El Colegio de la Frontera Sur Unidad San Cristobal de las Casas, Chiapas\t\t", +"ECOCHM\ts\tColeccion de Mamiferos del Museo de Zoologia-ECOSUR\t\t", +"ECOL\ts\tCollection du Laborataire d'Ecologie\t\t", +"ECOMAR\ts\tECOMAR lab University of Reunion\t\t", +"ECON\ts\tHarvard University\t\t", +"ECOSCM\ts\tColeccion Mastozoologica de El Colegio de la Frontera Sur, Unidad San Cristobal\t\t", +"ECOSUR\ts\tEl Colegio de la Frontera Sur (Mexico)\t\t", +"ECSC\ts\tEast Central University, Biology Department\t\t", +"ECSFI\ts\tEast China Sea Fisheries Institute\t\t", +"ECU\th\tEdith Cowan University\t\t", +"ECUAMZ\th\tUniversidad Estatal Amazonica\t\t", +"ECUH\th\tEast Carolina University\t\t", +"ECWP\th\tEmirates Centre for Wildlife Propagation\t\t", +"EDC\ts\tHubei Institute for Drug Control\t\t", +"EDH\ts\tPlinian Society\t\t", +"EDNC\ts\tRaleigh, North Carolina Department of Agriculture\t\t", +"EDTU\th\tTrakya Universitesi\t\t", +"EEBP\ts\tEstacao Experimental de Biologia e Piscicultura de Pirassununga\t\t", +"EELM\ts\tEstacion Experimental Agricola de la Molina\t\t", +"EERU\ts\tEconomic Entomology Research Unit\t\t", +"EFC\ts\tEscola de Florestas\t\t", +"EFCC\ts\tEpping Forest Conservation Centre\t\t", +"EFH\ts\tForestry Commission\t\t", +"EFM\ts\tEpping Forest Museum, Corporation of London\t\t", +"EFWM\ts\tDepartment of Entomology\t\t", +"EGE\ts\tEge University\t\t", +"EGE-MACC\tc\tEge - Microalgae Culture Collection\t\t", +"EGH\ts\tUniversity of Edinburgh\t\t", +"EGHB\ts\tUniversity of Edinburgh\t\t", +"EGHF\ts\tUniversity of Edinburgh, Forestry and Natural Resources Department\t\t", +"EGNP\ts\tHomestead, Everglades National Park\t\t", +"EGR\ts\tEszterhazy Karoly College, Botany Department\t\t", +"EHCV\ts\tEmory and Henry College, Biology Department\t\t", +"EHH\ts\tUniversite d'Etat d'Haiti\t\t", +"EI\ts\tUniversidade Federal Rural do Rio de Janeiro\t\t", +"EIF\ts\tUniversidad de Chile, Departamento de Silvicultura\t\t", +"EIHU\ts\tEntomological Institute, Hokkaido University\t\t", +"EINS\ts\tEcuadorian Institute of Natural Sciences\t\t", +"EISC\ts\tShaanxi Agricultural University, Entomological Institute\t\t", +"EIU\ts\tEastern Illinois University, Biological Sciences Department\t\t", +"EJ\ts\t?Ein Yabrud collection catalogue entries at The Hebrew University\t\t", +"EKU\ts\tEastern Kentucky University\t\t", +"EKY\ts\tEastern Kentucky University, Biological Sciences Department\t\t", +"ELCAK\ts\tEntomological Laboratory, College of Agriculture\t\t", +"ELH\th\tBureau of Land Management, Eagle Lake Field Office\t\t", +"ELM\ts\tEast London Museum\t\t", +"ELMF\ts\tAugusta, Maine Forest Service\t\t", +"ELN\ts\tElgin Museum\t\t", +"ELRG\ts\tCentral Washington University, Biological Sciences Department\t\t", +"ELS\ts\tAldenham School, Biology Department\t\t", +"ELVE\ts\tNational Station for Plant Breeding\t\t", +"EM\ts\tUniversidade Federal de Ouro Preto\t\t", +"EMA\ts\tSichuan School of Chinese Materia Medica\t\t", +"EMAG\ts\tErnst-Moritz Arndt Collection, Museum der Stadt Greifswald\t\t", +"EMAU\ts\tErnst-Moritz-Arndt-Universitat Greifswald\t\t", +"EMBT\ts\tDepartment of Agriculture, Thailand\t\t", +"EMC\ts\tEastern Michigan University, Biology Department\t\t", +"EMCC\tc\tEgypt Microbial Culture Collection\t\t", +"EMEC\ts\tEssig Museum of Entomology\tEMUC", +"EMET\ts\tFaculty of Agriculture, Entomology Museum\t\t", +"EMMA\ts\tUniversidad Politecnica de Madrid, Unidad Docente Botanica, Departamento Silvopascicultura\t\t", +"EMNH\th\tThe Everhart Museum of Natural History, Science & Art\t\t", +"EMPARN\tc\tEmpresa de Pesquisa Agropecuaria do Rio Grande do Norte\t\t", +"EMU\ts\tEastern Michigan University, T. L. Hankinson Vertebrate Museum\t\t", +"EMUS\ts\tUtah State University\t\t", +"ENAG\ts\tUniversidad Nacional Agraria, Departamento de Ciencias Basicas\t\t", +"ENCB-IPN\tc\tColeccion de cultivos de la Escuela Nacional de Ciencias Biologicas\t\t", +"ENCB\ts\tUniversidad de Autonoma de Baja California\t\t", +"ENCB\ts\tInstituto Politecnico Nacional\t\t", +"ENG\ts\tRoyal Holloway College, University of London, Botany Department\t\t", +"ENIH\ts\tNational Institute of Health\t\t", +"ENLC\th\tEastern Nevada Landscape Coalition\t\t", +"ENMU\ts\tEastern New Mexico University, Natural History Museum\t\t", +"ENMUNHM\ts\tEastern New Mexico University, Natural History Museum\t\t", +"ENP\ts\tEverglades National Park\t\t", +"ENS\ts\tHubei College for Nationalities, Forestry Department\t\t", +"ENSJ\ts\tEscuela Normal Superior de Jalisco\t\t", +"ENT\ts\tHerbarium, Ministry of Natural Resources, Uganda\t\t", +"ENTOMOFOR\ts\tCollection of necrophagous Fauna of the Forensic Entomology Laboratory (Basque Country University)\t\t", +"EONJ\ts\tUpsala College, Biology Department\t\t", +"EOSC\ts\tEastern Oregon University, Biology Department\t\t", +"EOSCVM\ts\tEastern Oregon State College, Vertebrate Museum\t\t", +"EOSTS\ts\tOfficial Seed Testing Station, Agricultural Scientific Services, Department of Agriculture and Fisheries for Scotland\t\t", +"EPAL\ts\tEntomology Collection, Punjab Agricultural University\t\t", +"EPHR\ts\tSnow College, Biology Department\t\t", +"EPM\ts\tEpsom College Museum\t\t", +"EPN\ts\tEscuela Polytecnica Nacional\tEPNC", +"EPRL\ts\tUniversity of Puerto Rico\t\t", +"EPU\th\tCentre de Formation et de Recherche en Conservation Forestiere\t\t", +"ER\ts\tUniversitaet Erlangen-Nuernberg, Geobotanik\t\t", +"ERA\ts\tUniversidad Nacional de Entre Rios, Botanica Sistematica\t\t", +"ERAEP\tc\tRadiation Ecology Section, Biological Science Division, Office of Atomic Energy for Peace\t\t", +"ERCB\ts\tYerevan State University, Botany Department\t\t", +"ERCH\th\tErciyes University\t\t", +"ERCULE\tc\tEuropean Rumen Ciliate Culture Collection, Rowett Research Institute\t\t", +"ERE\ts\tInstitute of Botany of the National Academy of Sciences of Armenia, Department of Plant Taxonomy and Geography\t\t", +"EREM\ts\tInstitute of Botany of the National Academy of Sciences of Armenia, Mycology Department\t\t", +"ERH\ts\tBorough of Erith Museum\t\t", +"ERHM\ts\tYerevan State University, Botany Department\t\t", +"ERSAF\ts\tRegional Agency for Agriculture and Forestry Services\t\t", +"ERZ\ts\tFuerstin-Eugenie-Institut fuer Arzneipflanzenforschung\t\t", +"ESA\ts\tUniversidade de Sao Paulo, Departamento de Botanica\t\t", +"ESAL\ts\tUniversidade Federal de Lavras, Departamento de Biologia\t\t", +"ESAP\tc\tInstituto Zimotecnico-Z\t\t", +"ESEC\ts\tEntomological Society of Egypt\t\t", +"ESK\ts\tSeker Enstituesue\t\t", +"ESN\ts\tEcole des Sciences de Niamey\t\t", +"ESNHS\ts\tScottish Natural History Society\t\t", +"ESRC\ts\tNova Scotia Department Natural Resources\t\t", +"ESRN\ts\tEscola Superior de Agricultura\t\t", +"ESS\ts\tUniversitaet Essen\t\t", +"ESSE\ts\tAnadolu University\t\t", +"ESUG\ts\tUniversity of Guam\t\t", +"ESUW\ts\tUniversity of Wyoming Insect Museum and Gallery\t\t", +"ET\ts\tEast Texas State University\t\t", +"ETE\ts\tEl Colegio de la Frontera Sur, Coleccion de insectos Asociados a Plantas Cultivadas en la Frontera Sur\t\t", +"ETH\tc\tKultursammlungen der Eidgenosische Technische Hochschule\t\t", +"ETH\ts\tAddis Ababa University, Biology Department\t\t", +"ETHZ\ts\tEidgenoessische Technische Hochschule-Zentrum\t\t", +"ETL\th\tLake Forest College\t\t", +"ETN\ts\tEton College Museum\t\t", +"ETNH\th\tJarvis Christian College\t\t", +"ETON\th\tEton College Museum\t\t", +"ETST\ts\tTexas A&M University, Biology Department\t\t", +"ETSU\ts\tEast Tennessee State University, Biological Sciences Department\t\t", +"EU\ts\tHubei University, Biology Department\t\t", +"EUB\ts\tLaboratory of Biology, Faculty of Science, Ehime University\t\t", +"EUMJ\ts\tEhime University\t\t", +"EUQ\ts\tDepartment of Entomology, Queensland University\t\t", +"EUSL\tc\tEastern University\t\t", +"EVA\tc\tEuropean Virus Archive\t\t", +"EVCV\ts\tErster Vorarlberger Coleopterische Verein\t\t", +"EVE\th\tThe Evergreen State College\t\t", +"EVMU\ts\tEverhart Museum, Natural History Department\t\t", +"EWH\ts\tEwha Womans University\t\t", +"EWM\th\tElizabeth Winston Mize Herbarium\t\t", +"EWNHM\ts\tEwha Womens University, Natural History Museum\t\t", +"EX\tc\tThe Culture Collection of Extremophilic Fungi\t\t", +"EXN\ts\tExton Hall\t\t", +"EXR\ts\tUniversity of Exeter, Biological Sciences Department\t\t", +"F\ts\tField Museum of Natural History, Botany Department\tFMNH:F", +"FAA\th\tUniversidad Nacional del Centro de la Provincia de Buenos Aires\t\t", +"FABR\ts\tHarmas de J. H. Fabre\t\t", +"FACHB\tc\tFreshwater Algae Culture Collection\t\t", +"FACS\ts\tFujian Agricultural College\t\t", +"FAK\ts\tDepartment of Fisheries, Faculty of Agriculture\t\t", +"FAKOU\ts\tFaculty of Agriculture, Kochi Univerisity\t\t", +"FAKU\ts\tKyoto University\t\t", +"FAN\ts\tMuseum of Fanjingshan National Nature Reserve\t\t", +"FAR\ts\tUniversity of Tarbiat-Moaallem, Biology Department\t\t", +"FARM\ts\tLongwood University, Department of Natural Sciences\t\t", +"FAU\ts\tFlorida Atlantic University, Biological Sciences Department\t\t", +"FAUC\ts\tUniversidad de Caldas, Departamento de Recursos Naturales\t\t", +"FAUN\ts\tUniversidad de Narino\t\t", +"FAVU\ts\tUniversidade Federal do Rio Grande do Sul, Faculdade Agronomia e Veterenaria\t\t", +"FB\ts\tAlbert-Ludwigs Universitaet, Institut fuer Biologie II\t\t", +"FBA\ts\tFreshwater Biological Association\t\t", +"FBC\ts\tUniversity of Sierra Leone, Fourah Bay College, Botany Department\t\t", +"FBCS\ts\tUniversidad Autonoma de Baja California Sur, Museo de Historia Natural\t\t", +"FBGMU\tc\tFaculty of Biology Gadjah Mada University\t\t", +"FBMN\ts\tMuseum fuer Naturkunde\t\t", +"FBQ\ts\tFisheries Branch, Departement of Primary Industries\t\t", +"FBUB\ts\tUniversitat Bielefeld\t\t", +"FBWA\ts\tForstlichen Bundsversuchsanstalt\t\t", +"FC-DPV\ts\tDepartmento de Paleontologia, Facultad de Ciencias\t\t", +"FCAB\ts\tPontificia Universidade Catolica do Rio de Janeiro, Nucleo Interdisciplinar de Meio Ambiente\t\t", +"FCAP\ts\tUniversidade Federal do Para\t\t", +"FCBP\tc\tFirst Fungal Culture Bank of Pakistan\t\t", +"FCDA\ts\tFresno County Department of Agriculture\t\t", +"FCL\tc\tFungal Culture Collection of Lublin\t\t", +"FCLR\ts\tFundacion Cientifica Los Roques\t\t", +"FCM\ts\tFacultad de Ciencias Marinas\t\t", +"FCME\ts\tUniversidad Nacional Autonoma de Mexico, Ciudad Universitaria, Departamento de Biologia\t\t", +"FCMM\ts\tUniversidad Nacional Autonoma de Mexico, Facultad de Ciencias\t\t", +"FCNI\ts\tForest Commission of N.S.W.\t\t", +"FCO\ts\tUniversidad de Oviedo, Departamento de Biologia de Organismos y Sistemas\t\t", +"FCQ\ts\tUniversidad Nacional de Asuncion, Departamento de Botanica, Direccion de Investigacion\t\t", +"FCRM\ts\tFisheries College Reference Museum\t\t", +"FCT\tc\tFCT (Forestry Commission Tasmania)\t\t", +"FCTH\ts\tForestry Commission of Tasmania\t\t", +"FCU\ts\tFukien Christian University\t\t", +"FCUG\tc\tFungal Cultures University of Goteborg\t\t", +"FDA\tc\tUS Food and Drug Administration\t\t", +"FDC\tc\tForsyth Dental Center\t\t", +"FDG\ts\tGuyana Forestry Commission\t\t", +"FDLW\ts\tUniversity of Wisconsin Center, Biology Department\t\t", +"FDNR\ts\tFlorida Department of Natural Resources\t\t", +"FDUC\ts\tFairleigh Dickinson University [collection transferred to FSCA].\t\t", +"FDVC\ts\tDe La Villa, Francisco\t\t", +"FEN\th\tLycee Felix Esclangon, Region PACA\t\t", +"FER\ts\tUniversita de Ferrara, Dipartimento di Biologia - Sezione di Botanica\t\t", +"FERM\tc\tPatent and Bio-Resource Center, National Institute of Advanced Industrial Science and Technology (AIST)\t\t", +"FEZA\ts\tUniversidad Nacional Autonoma de Mexico, Carrera de Biologia\t\t", +"FFB\ts\tAtlantic Forestry Centre, Canadian Forest Service\t\t", +"FFBNM\th\tFlorissant Fossil Beds National Monument\t\t", +"FFCL\ts\tNossa Senhora do Patrocinia\t\t", +"FFR\ts\tForfar Museum and Art Gallery, Meffan Institute\t\t", +"FFS\ts\tUniversity of Stellenbosch\t\t", +"FFSUC\ts\tFaculty of Forestry Sciences\t\t", +"FG\ts\tPalaontologische Hauptsammlung der Bergakadmie\t\t", +"FGC\ts\tGrassland Research Institute, Chinese Academy of Agricultural Sciences\t\t", +"FGG\ts\tFaculty of Geology and Geophysis\t\t", +"FGGUB\ts\tFacultatea de Geologie si Geofisca\t\t", +"FGIC\ts\tFrancois Genier\t\t", +"FGSC\tc\tFungal Genetics Stock Center\t\t", +"FH\ts\tThe Farlow Herbarium, Harvard University Herbaria\t\t", +"FH\ts\tFort Hays\t\t", +"FHI\ts\tForestry Research Institute of Nigeria\t\t", +"FHK\ts\tDivisional Forest Office\t\t", +"FHKS\ts\tFort Hays State University\t\t", +"FHKSC\ts\tFort Hays State University\t\t", +"FHL\ts\tFriday Harbor Laboratories, University of Washington\t\t", +"FHO\ts\tUniversity of Oxford, Department of Plant Sciences\t\t", +"FHSM\ts\tFort Hays Sternberg Museum\t\t", +"FI\ts\tMuseo di Storia Naturale dell'Universita\t\t", +"FIAF\ts\tUniversita degli Studi di Firenze, Dipartimento di Biologia Vegetale\t\t", +"FICB\ts\tForest Research Centre\t\t", +"FIDS\ts\tGreat Lakes Forest Research Laboratory, Forest Insect and Disease Survey\t\t", +"FIEC\ts\tFreshwater Institute\t\t", +"FIJI\ts\tUniversity of the South Pacific\t\t", +"FIOC\ts\tFundacao Instituto Oswaldo Cruz\t\t", +"FIOC:ColTryp\tc\tFundacao Instituto Oswaldo Cruz, Collection of Trypanosoma from Wild and Domestic Mammals and Vectors", +"FIP\ts\tFlorida Institute of Paleontology\t\t", +"FIPF\ts\tUniversita di Firenze\t\t", +"FIPIA\ts\tInstitut Teknologi Bandung, Jurusan Biologi\t\t", +"FJFC\ts\tFujian Forestry College\t\t", +"FJSI\ts\tFujian Institute of Subtropical Botany\t\t", +"FKE\ts\tFolk Museum\t\t", +"FKEN\ts\tFolkestone Natural History Society\t\t", +"FLACC\tc\tFree-Living Amoebae Culture Collection\t\t", +"FLAS\ts\tFlorida Museum of Natural History Herbarium\t\t", +"FLC\ts\tFort Lewis College\t\t", +"FLD\ts\tFort Lewis College, Biology Department\t\t", +"FLIN\ts\tFlinders University\t\t", +"FLK\ts\tFalkirk District Council Museum\t\t", +"FLOR\ts\tUniversidade Federal de Santa Catarina, Departamento de Botanica\t\t", +"FLSP\ts\tOscar Scherer State Park\t\t", +"FM\ts\tFan Memorial Institute of Biology\t\t", +"FM\ts\tDepartment of Nature, Fujian Province Museum\t\t", +"FMB\ts\tInstituto Alexander von Humboldt\t\t", +"FMC\ts\tNorth Museum of Natural History and Science\t\t", +"FMH\ts\tGoddard College\t\t", +"FMJ\tc\tFaculty of Medicine, Juntendo University\t\t", +"FML\ts\tFundacion Miguel Lillo\t\t", +"FMM\ts\tMuzeum Beskyd\t\t", +"FMNH\ts\tField Museum of Natural History\tCMNH", +"FMNH:ARTH\ts\tField Museum of Natural History, Arthropod Collection", +"FMNH:AVES\ts\tField Museum of Natural History, Ornithology Collection", +"FMNH:HERP\ts\tField Museum of Natural History, Herpetology Collection", +"FMNH:ICHTHY\ts\tField Museum of Natural History, Ichthyology Collection", +"FMNH:INVRT\ts\tField Museum of Natural History, Invertebrate Collection", +"FMNH:MAMM\ts\tField Museum of Natural History, Mammal Collection", +"FMNH\ts\tFinnish Museum of Natural History\t\t", +"FMP\ts\tFujian Academy of Traditional Chinese Medicine and Pharmacology\t\t", +"FMPC\ts\tFairbanks Museum and Planetarium Collection\t\t", +"FMR\tc\tFacultad de Medicina\t\t", +"FMRI\ts\tCentral Marine Fisheries Marine Research Institute\t\t", +"FMSS\ts\tParque Zoological Nacional \"Finca Modelo\", Natural History Museum\t\t", +"FMUH\th\tFrancis Marion University\t\t", +"FNCC\tc\tFood and Nutrition Culture Collection\t\t", +"FNFR\ts\tFishlake National Forest\t\t", +"FNLO\ts\tFremont National Forest\t\t", +"FNM\ts\tFries Natuurmuseum\t\t", +"FNML\ts\tFries Natuurhistorisch Museum\t\t", +"FNP\ts\tFundy National Park\t\t", +"FNPS\ts\tSouth Florida Collections Management Center, Everglades National Park\t\t", +"FNU\ts\tFujian Normal University\t\t", +"FNU\ts\tNagasaki University - Fisheries\t\t", +"FOF\th\tNational University of Laos\t\t", +"FOR\ts\tForssa Museum of Natural History\t\t", +"FOSJ\ts\tFisheries and Oceans Biological Station\t\t", +"FPDB\ts\tUniversidad de Puerto Rico, Departamento de Ciencias Marinas\t\t", +"FPF\ts\tRocky Mountain Research Station, USDA Forest Service\t\t", +"FPM\ts\tFukui Prefectural Museum\t\t", +"FPRL\ts\tBuilding Research Establishment\t\t", +"FQH\ts\tFort Qu'Appelle Herbarium\t\t", +"FR\tsb\tForschungsinstitut Senckenberg\t\t", +"FRC\ts\tInstitute of Forest Genetics and Tree Breeding\t\t", +"FRC\tc\tFusarium Research Center\t\t", +"FRCL\ts\tFisheries Research Centre\t\t", +"FRCS\ts\tForest Research Centre\t\t", +"FRDC\tb\tFruit Tree Research & Development Center of ThuaThien-Hue-Vietnam\t\t", +"FRI\ts\tAustralian National Herbarium, Division of Forestry and Forest Products, CSIRO\t\t", +"FRI\tc\tFood Research Institute, Ministry of Agriculture, Forestry and Fisheries\t\t", +"FRI\tc\tFood Research Institute, Bratislava, Slovakia\t\t", +"FRIHP\ts\tFisheries Research Institute of Hunan Province\t\t", +"FRIM\ts\tForest Research Institute, Malaysia\t\t", +"FRLC\ts\tForest Insect and Disease Survey Reference Collection\t\t", +"FRLH\ts\tFoundation for Revitalisation of Local Health Traditions, Research Department\t\t", +"FRLM\ts\tFaculty of Fisheries, Mie University\t\t", +"FRM\ts\tFriends University, Fellow-Reeve Museum of History and Science\t\t", +"FRNZ\ts\tForest Research Institute, New Zealand\t\t", +"FRP\ts\tPalmengarten\t\t", +"FRR\tc\tFood Science Australia, Ryde\t\t", +"FRS\ts\tFalconer Museum\t\t", +"FRSKU\ts\tKyoto University, Fisheries Research Station\t\t", +"FRU\ts\tNational Academy of Science, Kyrgyzstan, Laboratory of Flora\t\t", +"FSAG\ts\tFaculte des Sciences Agronomiques de Gembloux\t\t", +"FSC\tc\tFredericton Stock Culture Collection\t\t", +"FSC\ts\tCalifornia State University, Biology Department\t\t", +"FSCA\ts\tFlorida State Collection of Arthropods, Florida Department of Agriculture and Consumer Services, Division of Plant Industry\t\t", +"FSCL\ts\tFlorida Southern College, Biology Department\t\t", +"FSFRL\ts\tFar Seas Fisheries Research Laboratory\t\t", +"FSIU\ts\tLaboratory of Fisheries, Department of Oceanography\t\t", +"FSL\ts\tCollections de la Faculte des Sciences de Lyon\t\t", +"FSLF\ts\tRocky Mountain Forest and Range Experiment Station\t\t", +"FSMC\ts\tFlorida State Museum\tFSM", +"FSP-USP\ts\tFaculdade de Saude Publica, Universidade de Sao Paulo\t\t", +"FSSR\ts\tForest Service, USDA, Biological and Physical Resources Unit\t\t", +"FSU\ts\tFlorida State University, Department of Biological Science\t\t", +"FSUM\ts\tFlorida State University Museum\tFSU", +"FSUMC\ts\tFrostburg State University, Mammal Collection\t\t", +"FSUNS\tc\tFaculty of Science, The University of Novi Sad\t\t", +"FT\ts\tCentro Studi Erbario Tropicale, Universita degli Studi di Firenze\t\t", +"FTCC\tc\tFood Technology Culture Collection\t\t", +"FTCMU\tc\tDepartment of Food Science and Technology, Faculty of Agriculture\t\t", +"FTG\tsb\tFairchild Tropical Botanic Garden\t\t", +"FTI\tc\tCentro de Biotecnologia e Quimica-CEBIQ\t\t", +"FTOH\th\tForestry Training Institute, Olmotonyi\t\t", +"FTS\ts\tFuzhou Teachers College, Biology Department\t\t", +"FTU\ts\tUniversity of Central Florida, Biology Department\t\t", +"FU\ts\tFudan University, Department of Biology\t\t", +"FU\ts\tKyushu University, Department of Forest and Forest Products Sciences\t\t", +"FUB\ts\tFrei Universitat\t\t", +"FUE\ts\tFukuoka University of Education\t\t", +"FUEL\ts\tUniversidade Estadual de Londrina, Departamento de Biologia Animal e Vegetal\t\t", +"FUGR\ts\tFurman University, Biology Department\t\t", +"FUH\ts\tFirat Ueniversitesi\t\t", +"FUK\th\tFukui Botanical Garden\t\t", +"FULD\ts\tVerein fuer Naturkunde in Osthessen\t\t", +"FUMH\ts\tFerdowsi University\t\t", +"FUMT\ts\tUniversity of Tokyo\t\t", +"FUNED\ts\tFundacao Ezequiel Dias, Belo Horizonte\t\t", +"FURB\th\tUniversidade Regional de Blumenau\t\t", +"FUS\ts\tFudan University, Biology Department\t\t", +"FUSC\tc\tFlinders University Smut Collection\t\t", +"FVCC\ts\tFlathead Valley Community College, Biology Department\t\t", +"FW\ts\tTexas Christian University, Biology Department\t\t", +"FWM\ts\tFort Worth Museum of Science and History, Science Department\t\t", +"FWMSH\ts\tFort Worth Museum of Science & History\t\t", +"FWRI\ts\tFlorida Fish and Wildlife Research Institute\t\t", +"FWRI:Ichthyology\ts\tFlorida Fish and Wildlife Research Institute, Ichthyology Collection", +"FWRI:Invertebrate\ts\tFlorida Fish and Wildlife Research Institute, Invertebrate Collection", +"FWRI:SEAMAP\tc\tFlorida Fish and Wildlife Research Institute, SEAMAP Ichthyoplankton Collection", +"FWVA\ts\tFairmont State University, Biology Department\t\t", +"G\ts\tConservatoire et Jardin botaniques de la Ville de Geneve\t\t", +"GA\ts\tUniversity of Georgia, Plant Biology Department\t\t", +"GAB\ts\tNational Museum, Monuments, and Art Gallery\t\t", +"GABAS\ts\tCentre d'Etude et de Conservation des Resources Vegetales\t\t", +"GAC\ts\tGuangxi Agricultural University, Forestry Department\t\t", +"GACP\ts\tGuizhou Agricultural College, Department of Plant Protection\t\t", +"GADI\th\tGrootfontein Agricultural Development Institute\t\t", +"GAES\ts\tGeorgia Agricultural Experiment Station\t\t", +"GAFS\ts\tGanzhou Forestry School\t\t", +"GAI\ts\tFolk Museum\t\t", +"GALW\ts\tNational University of Ireland, Galway, Botany Department\t\t", +"GAM\ts\tUniversity of Georgia\t\t", +"GAM\tc\tGrupo Actinomicetales Merida Facultad de Medicina\t\t", +"GAP\th\tConservatoire Botanique National Alpin\t\t", +"GAS\ts\tGeorgia Southern University, Department of Biology\t\t", +"GAT\ts\tInstitute of Plant Genetics and Crop Plant Research\t\t", +"GAUA\ts\tGuangxi University\t\t", +"GAUBA\ts\tAustralian National University, Division of Botany and Zoology\t\t", +"GAUF\ts\tGansu Agricultural University\t\t", +"GAW\ts\tEastern Botanical Society of Glasgow\t\t", +"GAZI\ts\tGazi Ueniversitesi, Biyoloji Boeluemue\t\t", +"GB\ts\tGoeteborg University, Department of Plant and Environmental Sciences\t\t", +"GBFM\ts\tUniversidad de Panama\t\t", +"GBG\tb\tGotheburg Botanical Garden\t\t", +"GBH\th\tHerbarium of Geo. B. Hinton\t\t", +"GBNM\ts\tGlacier Bay National Park and Preserve Museum\t\t", +"GBY\ts\tGrimsby Arts and Natural History\t\t", +"GC\ts\tUniversity of Ghana, Botany Department\t\t", +"GC\ts\tGoucher College\t\t", +"GCL\tc\tCentral Laboratories\t\t", +"GCM\ts\tUniversity College of Ghana\t\t", +"GCM\ts\tGovernment College, Department of Zoology\t\t", +"GCNP\ts\tGrand Canyon National Park\t\t", +"GCRL\ts\tGulf Coast Research Laboratory\t\t", +"GCTP\ts\tGlobal Colosseum\t\t", +"GCU\th\tGachon University\t\t", +"GDA\ts\tUniversidad de Granada\t\t", +"GDAC\ts\tUniversidad de Granada, Departamento de Biologia Vegetal, Botanica\t\t", +"GDB\th\tHerbarium de Gerard de Belair\t\t", +"GDGM\ts\tGuangdong Institute of Microbiology\t\t", +"GDMA\ts\tMedical University of Gdansk, Department of Biology and Pharmaceutical Botany\t\t", +"GDMCC\tc\tGuangdong Microbial Culture Collection Center\t\t", +"GDMM\ts\tGuangdong Institute of Chinese Materia Medica\t\t", +"GDMP\ts\tGuangdong Medical and Pharmaceutical College, Pharmacy Department\t\t", +"GDOR\ts\tMuseo Civico di Storia Naturale Giacomo Doria\t\t", +"GE\ts\tUniversita di Genova\t\t", +"GEIC\ts\tGuangdong Entomology Institute\t\t", +"GENT\ts\tGent University, Biology Department\t\t", +"GEO\ts\tEmory University, Biology Department\t\t", +"GES\ts\tGesneriad Research Foundation\t\t", +"GESU\ts\tState University of New York, Biology Department\t\t", +"GF\ts\tGuizhou Academy of Forestry\t\t", +"GFBI\ts\tGymnasium der Franziskaner in Bozen [= Bolzano]\t\t", +"GFC\ts\tUniversity of Great Falls, Biology Department\t\t", +"GFCC\tc\tGoa University Fungus Culture Collection and Research Unit\tGUFCC", +"GFJP\ts\tUniversidade do Estado de Minas Gerais\t\t", +"GFND\ts\tUniversity of North Dakota, Biology Department\t\t", +"GFRC\ts\tGolestan Fisheries Research Centre\t\t", +"GFS\ts\tGuizhou Forestry School\t\t", +"GFT\th\tGrumeti Fund Tanzania\t\t", +"GFW\ts\tErnst-Moritz-Arndt-Universitaet, Botanisches Institut und Botanischer Garten\t\t", +"GGB\ts\tGesneriad Gardens\t\t", +"GGM\ts\tGosudarstvennyi Geologicheskii Musei - State Geological Museum\t\t", +"GGO\ts\tUniversity of Strathclyde, Biology Department\t\t", +"GGW\ts\tBotanical Society of Glasgow\t\t", +"GH\ts\tHarvard University (The Gray Herbarium)\t\t", +"GHD\ts\tShipley Art Gallery and Saltwell Tower Museum\t\t", +"GHG\ts\tCouncil for Geosciences\t\t", +"GHPG\ts\tHarold Porter National Botanical Garden\t\t", +"GHRI\ts\tGuy Harvey Research Institute\t\t", +"GHS\ts\tGeorge Heriot's School, Biology Department\t\t", +"GI\ts\tJustus-Liebig-Universitat Giessen\t\t", +"GI-SPS\ts\tGeological Institute, Section of Palaeontology and Stratigraphy\t\t", +"GIFU\ts\tHerbarium of Gifu Pharmaceutical University\t\t", +"GINCO\th\tAgriculture and Agri-Food Canada\t\t", +"GIUV\ts\tGeological Institute, University of Vienna\t\t", +"GJO\ts\tSteiermaerkisches Landesmuseum Joanneum, Botany Department\t\t", +"GKAR\ts\tKaroo National Botanical Garden\t\t", +"GL\ts\tUniversity of Glasgow, Botany Department\t\t", +"GLA\th\tGeorge Landis Arboretum\t\t", +"GLAC\ts\tGlacier National Park, Glacier Collection\t\t", +"GLAHM\ts\tUniversity of Glasgow, Hunterian Museum\t\t", +"GLAM\ts\tArt Gallery and Museum, Natural History Department\t\t", +"GLANH\ts\tHunterian Museum\t\t", +"GLEN\ts\tRappahannock Community College\t\t", +"GLFR\ts\tGreat Lakes Forest Research Centre\t\t", +"GLG\ts\tTrinity College\t\t", +"GLLB\ts\tLaurel Bank School\t\t", +"GLM\ts\tStaatliches Museum fuer Naturkunde Goerlitz\t\t", +"GLMC\ts\tGuilin Medical College, Pharmacy Department\t\t", +"GLNP\ts\tGlacier National Park\t\t", +"GLO\ts\tNatural History Society of Glasglow\t\t", +"GLOW\ts\tLowveld National Botanical Garden\t\t", +"GLR\ts\tGloucester City Museum and Art Gallery\t\t", +"GLW\ts\tAndersonian Naturalists' Society\t\t", +"GM\ts\tMuseum of Southeastern Moravia\t\t", +"GMACC\tc\tLaboratory of Molecular Genetics and Breeding of Edible Mushrooms\t\t", +"GMAU\ts\tGeological Museum of Amsterdam University\t\t", +"GMBL\ts\tCollege of Charleston\t\t", +"GMC\ts\tGuangxi Medical College\t\t", +"GMCE\ts\tGrosvenor Museum\t\t", +"GMDRC\th\tGranite Mountains Desert Research Center\t\t", +"GMH\ts\tSammlung Jacobi des Geiseltalmuseum Halle\t\t", +"GMHH\ts\tGeological Museum of Heilongjang Province\t\t", +"GML\ts\tGorgas Memorial Laboratory\t\t", +"GML\ts\tGaylord Memorial Laboratory Museum\t\t", +"GMNGZ\ts\tGlasgow Museum and Art Galleries\t\t", +"GMNH-PV\ts\tPaleo-Vertebrate Collection\t\t", +"GMNH\ts\tMuseum d'Histoire Naturelle\t\t", +"GMNH\ts\tGeorgia Museum of Natural History\t\t", +"GMNHJ\th\tGunma Museum of Natural History\t\t", +"GMNP\ts\tGros Morne National Park\t\t", +"GMS\ts\tHopkins Marine Station, Stanford University, Biological Sciences Department\t\t", +"GMU\ts\tN. P. Ogariov Mordovia State University, Department of Botany and Plant Physiology\t\t", +"GMUF\ts\tGeorge Mason University, Department of Environmental Science and Policy 5F2\t\t", +"GMUG\ts\tUniversitat Gottingen, Geologisches-Palaatologisches Museum\t\t", +"GMUM\ts\tInstitut fuer Palaeontologie und Geologisches Museum der Universitat\t\t", +"GMUV\ts\tGeological Museum, University of Vienna\t\t", +"GNA\ts\tGannan Arboretum of Jiangxi\t\t", +"GNDUH\th\tGuru Nanak Dev University\t\t", +"GNE\tc\tGenentech\t\t", +"GNHM\ts\tGoulandris Natural History Museum\t\t", +"GNHNA\ts\tGallery of Natural History and Native Art\t\t", +"GNHS\ts\tGuildford Natural History Society\t\t", +"GNM\ts\tGothenburg Museum of Natural History (Goteborgs Naturhistoriska Museum)\t\t", +"GNU\ts\tGuangxi Normal University, Biology Department\t\t", +"GNUB\ts\tGuizhou Normal University, Biology Department\t\t", +"GNUC\ts\tGyeongsang National University, Biology Department\t\t", +"GNUG\ts\tGuizhou Normal University, Geography Department\t\t", +"GO\ts\tPhilosophical Society\t\t", +"GOD\ts\tCharterhouse School Museum\t\t", +"GOE\ts\tInstitut und Museum fuer Geologie und Palaeontologie\t\t", +"GOE\ts\tGoole Scientific Society\t\t", +"GOET\ts\tHerbarium Universitat Gottingen\t\t", +"GOFS\ts\tFree State National Botanical Garden\t\t", +"GOPU\th\tGaziosmanpasa University\t\t", +"GOW\ts\tClydebank High School\t\t", +"GP\ts\tInstituto de Geociencias, Universidade de Sao Paulo\t\t", +"GPA\ts\tGrande Prairie Regional College, Science Department\t\t", +"GPI\ts\tGeologisch-Palaeontologisches Institut\t\t", +"GPIH\ts\tGeologisch-Palaeontologiches Institut der Universitt Haemburg\t\t", +"GPIM\ts\tLehreinheit Palaeontologisches, Institut fuer Geowissenschaften\t\t", +"GPIT\ts\tInstitut und Museum fur Geologie und Palaontologie, Universitat Tubingen\t\t", +"GPM\ts\tGifu prefectural Museum\t\t", +"GPM:B\ts\tGifu prefectural Museum, Gifu prefectural Museum herbarium", +"GPM:Z\ts\tGifu prefectural Museum, Gifu prefectural Museum Zoological collection", +"GPMK\ts\tGeologisch-Palaontologisches Institut und Museum\t\t", +"GPPT\ts\tPlant Protection Institute\t\t", +"GR\ts\tUniversite J. Fourier - Grenoble I, Botanique\t\t", +"GRA\ts\tAlbany Museum\t\t", +"GRCAMC\ts\tGrand Canyon National Park Museum Collection\t\t", +"GRCH\ts\tColgate University, Biology Department\t\t", +"GREE\ts\tUniversity of Northern Colorado, Department of Biological Sciences\t\t", +"GRI\ts\tGrinnell College, Biology Department\t\t", +"GRIF\ts\tGriffith University\t\t", +"GRJC\ts\tGrand Rapids Junior College\t\t", +"GRK\ts\tMcLean Museum and Art Gallery\t\t", +"GRM\ts\tMuseum d'Histoire Naturelle de Grenoble\t\t", +"GRMP\ts\tCentral Geological Research Museum\t\t", +"GRO\ts\tState University of Groningen, Department of Plant Biology\t\t", +"GRPM\ts\tPublic Museum of Grand Rapids\t\t", +"GRS\ts\tGezira Research Station\t\t", +"GRSM\ts\tGreat Smoky Mountains National Park\t\t", +"GRSU\ts\tYanka Kupala Grodno State University, Department of Botany\t\t", +"GRSW\ts\tDesert Ecological Research Unit\t\t", +"GRTE\th\tGrand Teton National Park\t\t", +"GSAT\ts\tThe Geological Survey of Alabama\t\t", +"GSC\ts\tGeological Survey of Canada\t\t", +"GSDNM\ts\tGreat Sand Dunes National Monument\t\t", +"GSFS\ts\tGansu Forestry School\t\t", +"GSI\ts\tGeological Survey of India\t\t", +"GSM\ts\tGeologic Museum\t\t", +"GSMNP\ts\tGreat Smoky Mountains National Park\t\t", +"GSN\ts\tGeological Survey of Nambia\t\t", +"GSO\ts\tGlasgow Society of Field Naturalists'\t\t", +"GSP\ts\tGeological Survey of Portugal\t\t", +"GSU\ts\tF. Scorina Gomel State University, Department of Botany and Plant Physiology\t\t", +"GSW\ts\tGeorgia Southwestern State University, Biology Department\t\t", +"GTC\tc\tGifu Type Culture Collection\t\t", +"GTC-GIFU\tc\tGifu Type Culture Collection (GTC), Gifu University Culture Collection (GIFU)\t\t", +"GTM\ts\tGrantham Museum\t\t", +"GTNP\ts\tGrand Teton National Park\t\t", +"GTV\ts\tGregorio T. Velasquez Phycological Herbarium\t\t", +"GU\ts\tGotland University, Department of Biology\t\t", +"GU-IITG\ts\tfor Gauhati University- Indian Institute of Technology Guwahati\t\t", +"GUA\ts\tDIVEA, DEP, FEEMA, FEEMA\t\t", +"GUAD\ts\tInstitut National de la Recherche Agronomique and Parc National de Guadeloupe\t\t", +"GUADA\ts\tUniversidad Autonoma de Guadalajara\t\t", +"GUAM\ts\tUniversity of Guam, Biology Department\t\t", +"GUAT\ts\tHerbario Ulises Roja\t\t", +"GUAY\ts\tUniversidad de Guayaquil\t\t", +"GUBH\th\tGauhati University\t\t", +"GUBIOTJT\tc\tFreshwater microalgae collection and culture laboratory\t\t", +"GUCM\th\tGuangzhou University of Chinese Medicine\t\t", +"GUH\ts\tHNB Garhwal University, Botany Department\t\t", +"GUL\th\tSuleyman Demirel University\t\t", +"GUM\ts\tGlasgow University Museum (Hunter Museum)\t\t", +"GUM\ts\tMycological herbarium of University of Guilan\t\t", +"GUMACC\tc\tGotheburg University Marine Algal Culture Collection\t\t", +"GUYN\ts\tFundacion Jardin Botanico del Orinoco\t\t", +"GVF\ts\tGeorge Vanderbilt Foundation\t\t", +"GVSC\ts\tGrand Valley State University, Biology Department\t\t", +"GW\ts\tWest of Scotland College of Agriculture, Botany Department\t\t", +"GXCM\ts\tGuangxi Traditional Chinese Medicine University, Pharmacy Department\t\t", +"GXDC\ts\tGuangxi Institute for Drug Control\t\t", +"GXEM\ts\tGuangxi Institute of Ethnomedicine\t\t", +"GXF\ts\tGuangxi Institute of Forest Survey and Design\t\t", +"GXFI\ts\tGuangxi Forestry Institute\t\t", +"GXFS\ts\tGuangxi Forestry School\t\t", +"GXMG\ts\tGuangxi Medicinal Botanic Garden\t\t", +"GXMI\ts\tGuangxi Institute of Traditional Medical and Pharmaceutical Sciences\t\t", +"GXNM\ts\tGuangxi Natural History Museum, Herbarium\t\t", +"GXSP\ts\tGuangxi School of Pharmacy\t\t", +"GZAC\ts\tGuizhou Agricultural College, College of Life Science\t\t", +"GZM\ts\tGiessener Zoologisches Museum\t\t", +"GZTM\ts\tGuizhou Institute of Traditional Chinese Medicine\t\t", +"GZU\ts\tKarl-Franzens-Universitaet Graz\t\t", +"H\ts\tUniversity of Helsinki\t\t", +"H-GSP\ts\tHoward University-Geological Survey of Pakistan Project\t\t", +"HA\ts\tUniversidad del Azuay, Escuela de Biologia del Medio Ambiente\t\t", +"HABA\ts\tAcademia de Ciencias Medicas, Fisicas y Naturales de La Habana\t\t", +"HABAYC\ts\tUniversity of Mary Hardin-Baylor, Biology Department\t\t", +"HABE\ts\tInstituto de Biologia, Departamento de Ecologia\t\t", +"HAC\ts\tInstituto de Ecologia y Sistematica\t\t", +"HACC\ts\tAcademia de Ciencias Camagueey\t\t", +"HACW\ts\tDepartment of Fishery, Huazhong Agriculture Collection\t\t", +"HAF\ts\tHainan Forestry Institute\t\t", +"HAH\th\tHoyt Arboretum\t\t", +"HAI\th\tUniversity of Haifa\t\t", +"HAJB\ts\tJardin Botanico Nacional\t\t", +"HAJU\th\tHerbario Dr. Armando Jesus Urquiola\t\t", +"HAK\ts\tHokkaido University, Faculty of Fisheries\t\t", +"HAKS\ts\tHakgala Botanic Gardens\t\t", +"HAL\ts\tMartin-Luther-Universitaet\t\t", +"HALA\ts\tUniversity of Alabama, Biological Sciences Department\t\t", +"HALE\th\tHaleakala National Park\t\t", +"HALLE\ts\tZoologisches Institut der Martin-Luther Universitaet\t\t", +"HALLST\ts\tBotanische Station\t\t", +"HALN\th\tState Agency for Environmental Protection Saxony-Anhalt\t\t", +"HALX\ts\tHalifax Literary and Philosophical Society\t\t", +"HAM\ts\tRoyal Botanical Gardens\t\t", +"HAMAB\ts\tInstituto de Pesquisas Cientificas e Tecnologicas do Estado do Amapa\t\t", +"HAMBI\tc\tHAMBI Culture Collection\t\t", +"HAMU\ts\tUniversity of Newcastle upon Tyne\t\t", +"HAN\ts\tUniversitaet Hannover\t\t", +"HANC\th\tNational Aquarium of Cuba\t\t", +"HANU\ts\tHarbin Normal University, Biology Department\t\t", +"HAO\ts\tUniversidad Privada Antenor Orrego\t\t", +"HAQ\ts\tInstitut der Technische Hochschule (RWTH), Institut fuer Biologie I\t\t", +"HAS\ts\tFundacao Zoobotanica do Rio Grande do Sul\t\t", +"HAST\ts\tResearch Center for Biodiversity, Academia Sinica\t\t", +"HASU\ts\tUniversidade do Vale do Rio dos Sinos - CCS/ Centro 2\t\t", +"HAU\th\tAlzahra University\t\t", +"HAUH\ts\tHaryana Agricultural University\t\t", +"HAVI\ts\tEastern Mennonite University, Biology Department\t\t", +"HAVO\ts\tHawaii Volcanoes National Park\t\t", +"HAW\ts\tUniversity of Hawaii, Botany Department\t\t", +"HAX\ts\tBelle Vue Museum\t\t", +"HAY\ts\tCalifornia State University, Biological Sciences Department\t\t", +"HB\ts\tHerbarium Bradeanum\t\t", +"HBA\th\tNational Botanic Garden of Latvia\t\t", +"HBARC\th\tBhabha Atomic Research Centre\t\t", +"HBAU\ts\tHebei Agricultural University\t\t", +"HBAUD\ts\tHebei Agricultural University, Handan Branch, Agriculture Department\t\t", +"HBBS\ts\tMuseo Civico di Scienze Naturali\t\t", +"HBC\ts\tHenry Brockhouse Collection\t\t", +"HBDC\ts\tHebei Institute for Drug Control\t\t", +"HBFC\ts\tHebei Forestry College, Basic Courses Department\t\t", +"HBFH\ts\tHarbor Branch Oceanographic Institution, Marine Botany Department\t\t", +"HBG\ts\tInstitut fuer Allgemeine Botanik\t\t", +"HBG\tb\tHiroshima Botanical Garden\t\t", +"HBI\ts\tInstitute of Hydrobiology, Chinese Academy of Sciences, Phycology Department\t\t", +"HBIL\ts\tInstitut d'Estudis Ilerdencs\t\t", +"HBNU\ts\tHebei Normal University, Biology Department\t\t", +"HBOM\ts\tHarbor Branch Oceanographic Museum\tHBOI", +"HBR\ts\tUniversidade Federal de Santa Catarina\t\t", +"HBRA\th\tUniversidade Federal do Para, Campus Braganca\t\t", +"HBUM\ts\tCollege of Life Sciences Hebei Univesity, Baoding\t\t", +"HC\ts\tHangchow Christian College\t\t", +"HCAT\ts\tUniversity of Tabriz, Landscape Department\t\t", +"HCB\ts\tUniversidade de Santa Cruz do Sul, Departamento de Biologia\t\t", +"HCCA\ts\tHastings College\t\t", +"HCCN\th\tNational Institute of Agricultural Science and Technology\t\t", +"HCCV\ts\tHastings College, Collection of Vertebrates\t\t", +"HCDAL\th\tUniversidade Regional do Cariri\t\t", +"HCEN\ts\tUniversidad Nacional del Centro del Peru\t\t", +"HCF\th\tUniversidade Tecnologica Federal do Parana\t\t", +"HCH\ts\tLewis-Clark State College, Natural Sciences Department\t\t", +"HCHM\ts\tHope College, Biology Department\t\t", +"HCIB\ts\tCentro de Investigaciones Biologicas del Noroeste, S. C.\t\t", +"HCIO\ts\tIndian Agricultural Research Institute\t\t", +"HCMS\ts\tHampshire County Council Museums Service\t\t", +"HCMZ\ts\tHope College\t\t", +"HCNHSC\ts\tOhio Historical Society, Natural History Synoptic Collection\t\t", +"HCOA\ts\tCollege of the Atlantic, Herbarium\t\t", +"HCOM\th\tCentre d'Oceanologie de Marseille - University of Aix-Marseille II\t\t", +"HCT\ts\tTaiwan Forestry Research Institute\t\t", +"HCTR\ts\tHoogstraal Center for Tick Research\t\t", +"HDCF\th\tDepartment of Forestry Science\t\t", +"HDD\ts\tTolson Museum, Natural History Department\t\t", +"HDJF\th\tUniversidade Federal dos Vales do Jequitinhonha e Mucuri\t\t", +"HDOA\ts\tHawaii Department of Agriculture\t\t", +"HDSM\ts\tUniversity of Massachusetts Dartmouth\t\t", +"HDTC\ts\tHuddersfield Technical College\t\t", +"HEAC\ts\tHenan Agricultural University\t\t", +"HEB\ts\tHebden Bridge Literary and Scientific Society\t\t", +"HEBI\ts\tHenan Academy of Sciences\t\t", +"HECM\ts\tHenan College of Traditional Chinese Medicine\t\t", +"HEFG\ts\tl'Ecole de Faune de Garoua\t\t", +"HEH\ts\tEscuela Nacional de Ciencias Forestales, Departamento de Investigacion Forestal Aplicada\t\t", +"HEID\ts\tUniversitaet Heidelberg, Heidelberger Institut fuer Pflanzenwissenschaften\t\t", +"HEL\ts\tUniversity of Helsinki, Section of Botany\t\t", +"HEM\th\tUniversidad de Ciencias y Artes de Chiapas\t\t", +"HEMS\ts\tHaslemere Educational Museum\t\t", +"HENA\ts\tEscuela Nacional de Agricultura\t\t", +"HEND\ts\tHenderson State University, Biology Department\t\t", +"HENNU\ts\tHenan Normal University\t\t", +"HENU\ts\tHenan Normal University, Biology Department\t\t", +"HEPH\ts\tJardim Botanico de Brasilia\t\t", +"HER\tc\tFelix d'Herelle Reference Center for Bacterial Viruses (Bacteriophage)\t\t", +"HER\ts\tHermanus Botanical Society\t\t", +"HERBAM\th\tUniversidade do Estado de Mato Grosso\t\t", +"HERT\th\tFundacao Universidade Estadual do Ceara\t\t", +"HERZ\ts\tHerzen State Pedagogical University of Russia, Department of Botany\t\t", +"HERZU\ts\tUniversidad del Zulia\t\t", +"HEUS\th\tUniversidad de Sucre\t\t", +"HF\ts\tUniversidade Federal do Para\t\t", +"HFB\ts\tHainan Forestry Bureau\t\t", +"HFBG\ts\tForestry Botanical Garden of Heilongjiang\t\t", +"HFCC\tc\tFlagellate Culture Collection, University of Cologne\t\t", +"HFD\ts\tHereford Museum\t\t", +"HFLA\th\tSapienza University of Rome - Scuola di Specializzazione in Beni Naturali e Territoriali\t\t", +"HFN\th\tHerbarium Frisicum\t\t", +"HFP\tc\tHokkaido Forest Products Research Institute\t\t", +"HFR\ts\tFinnish Forest Research Institute\t\t", +"HFRI\ts\tHunan Forestry Research Institute\t\t", +"HFSL\th\tCentro de Ensino, Faculdade Sao Lucas Ltda.\t\t", +"HFU\ts\tHerbarium of Fayoum University\t\t", +"HFV\ts\tUniversidad Austral de Chile, Instituto de Produccion y Sanidad Vegetal\t\t", +"HFX\ts\tBankfield Museum and Art Gallery\t\t", +"HGAS\ts\tGuizhou Academy of Sciences, Plant Taxonomy Group\t\t", +"HGCRL\ts\tGulf Coast Research Laboratory\t\t", +"HGI\ts\tUniversitat de Girona, Unitat de Biologia Vegetal\t\t", +"HGM\ts\tHunan Geological Museum\t\t", +"HGOM\th\tUniversidad Autonoma del Estado de Hidalgo\t\t", +"HGS\ts\tPublic Museum and Art Gallery, St. John's Place\t\t", +"HGTC\ts\tHuanggang Teachers College, Biology Department\t\t", +"HGU\th\tKhakass State University\t\t", +"HH\th\tInstituto de Investigaciones de la Amazonia Peruana\t\t", +"HHBG\ts\tHangzhou Botanical Garden\t\t", +"HHC\ts\tUniversity of Helsinki, Horticulture Department\t\t", +"HHH\ts\tHartwick College\t\t", +"HHM\ts\tCollyer's School\t\t", +"HHU\ts\tHallym University\t\t", +"HHUA\ts\tUniversidad Nacional de Huanuco Hermilio Valdizan\t\t", +"HHUF\ts\tHirosaki University, Laboratory of Plant Pathology\t\t", +"HIB\ts\tWuhan Institute of Botany\t\t", +"HIBG\th\tHiroshima Botanical Garden\t\t", +"HIC\ts\tUniversity of Kentucky, Department of Entomology, Hymenoptera Institute Collection\t\t", +"HIFP\ts\tFrench Institute\t\t", +"HILL\ts\tSir Harold Hillier Gardens\t\t", +"HIMC\ts\tInner Mongolia University\t\t", +"HIN\ts\tHitchin Priory\t\t", +"HIP\ts\tUniversidad de Magallanes\t\t", +"HIPC\ts\tInstituto Superior Pedagogico Jose Marti, Departamento de Biologia\t\t", +"HIRO\ts\tHiroshima University, Biological Science Department\t\t", +"HIRU\ts\tOkayama University of Science\t\t", +"HISA\th\tUniversidade Estadual Paulista\t\t", +"HITBC\ts\tXishuangbanna Tropical Botanical Garden, Chinese Academy of Sciences\t\t", +"HIUW\ts\tHygiene-Institut der Universitaet\t\t", +"HIWNT\ts\tHampshire and Isle of Wight Naturalists' Trust Ltd.\t\t", +"HJBC\th\tJardin Botanico Culiacan\t\t", +"HJBL\ts\tEscuela Nacional de Ciencias Forestales\t\t", +"HJBS\ts\tFundacio Jardi Botanic de Soller\t\t", +"HK\ts\tAgriculture, Fisheries, and Conservation Department\t\t", +"HKAS\ts\tCryptogamic Herbarium of Kunming Institute of Botany, Chinese Academy of Sciences\t\t", +"HKBU\ts\tHong Kong Baptist University, Biology Department\t\t", +"HKFRS\ts\tHong Kong Fisheries Research Station\t\t", +"HKGL\ts\tNaturwissenschaftliche Sammlungen des Kantons Glarus\t\t", +"HKI\tc\tHans-Knoll Institute\t\t", +"HKM\th\tUniversity of Comoros\t\t", +"HKS\th\tResearch Center of Agricultural and Natural Resources Kurdistan Province\t\t", +"HKU\ts\tUniversity of Hong Kong, Ecology and Biodiversity Department\t\t", +"HKUCC\tc\tThe University of Hong Kong Culture Collection\t\t", +"HL\ts\tHoughton Lake Wildlife Research Station, Natural Resources Department\t\t", +"HL\tsb\tHortus Botanicus Leiden\t\t", +"HLA\ts\tHarold L. Lyon Arboretum\t\t", +"HLCM\ts\tHeilongjiang College of Traditional Chinese Medicine, Department of Chinese Materia Medica\t\t", +"HLD\ts\tHessisches Landesmuseum\t\t", +"HLDG\th\tLas Cruces Biological Station, Organization for Tropical Studies\t\t", +"HLL\ts\tQueen's Gardens, College of Higher Education, Natural Science Department\t\t", +"HLMA\ts\tTown Docks Museum, Hull City Corporation\t\t", +"HLMD\ts\tHessisches Landesmuseum Darmstadt\t\t", +"HLNM\ts\tHeilongjiang Provincial Museum\t\t", +"HLO\ts\tVlastivedne Muzeum v Hlohovci\t\t", +"HLSD\th\tHillsdale College\t\t", +"HLU\ts\tUniversity of Hull, Botany Department\t\t", +"HLUC\ts\tUniversita degli Studi della Basilicata, Dipartimento di Biologia Difesa e Biotecnologie Agroforestali\t\t", +"HLUL\ts\tUniversity of Hull\t\t", +"HLX\ts\tOvenden Naturalists' Society\t\t", +"HM\ts\tHumbolt Museum\t\t", +"HM\ts\tHastings Museum\t\t", +"HMAR\th\tUniversidade Federal do Ceara\t\t", +"HMAS\tsc\tInstitute of Microbiology, Academia Sinica\t\t", +"HMC\ts\tJardin Botanico de Las Tunas\t\t", +"HME\ts\tHaslemere Educational Museum\t\t", +"HMGBH\th\tGiardini Botanici Hanbury / Hanbury Botanic Gardens\t\t", +"HMH\ts\tHoebarth Museum Horn\t\t", +"HMIM\th\tJardi Botanic Marimurtra\t\t", +"HMJAU\tsc\tHerbarium of Mycology of Jilin Agricultural University\t\t", +"HMLN\ts\tDistrict Museum\t\t", +"HMM\ts\tHorsham Museum\t\t", +"HMMNH\th\tMacedonian Museum of Natural History\t\t", +"HMN\ts\tHumbolt Museum fur Naturkunde, East Berlin\t\t", +"HMNH\ts\tHayashibara Museum of Natural History\t\t", +"HMNR\th\tMordovian State Nature Reserve\t\t", +"HMNS\ts\tHouston Museum of Natural Science\t\t", +"HMNT\ts\tHancock Museum, Newcastle University\t\t", +"HMP\ts\tHornonitrianske muzeum, Department of Natural History\t\t", +"HMS\ts\tEmbrapa Gado de Corte\t\t", +"HMUG\ts\tHunterian Museum\t\t", +"HN\ts\tNational Center for Natural Sciences and Technology, Botany Department\t\t", +"HNBU\ts\tInstitut de l'Environnement et de Recherche Agricola (INERA)\t\t", +"HNCMB\tc\tHungarian National Collection of Medical Bacteria\t\t", +"HNG\th\tUniversite. Gamal Abdel Nasser de Conakry\t\t", +"HNH\ts\tDartmouth College, Biological Sciences Department\t\t", +"HNHH\ts\tHeilongjiang Natural History Museum\t\t", +"HNHM\ts\tHungarian Natural History Museum (Termeszettudomanyi Muzeum)\t\t", +"HNHM:Moll\tc\tHungarian Natural History Museum (Termeszettudomanyi Muzeum), Mollusca Collection", +"HNHM\ts\tHannam University, Department of Biology\t\t", +"HNHPS\th\tHunan Hupingshan National Nature Reserve\t\t", +"HNHR\ts\tUniversity of California, Hastings Natural History Reservation\t\t", +"HNIP\ts\tHanoi College of Pharmacy\t\t", +"HNL\th\tConseil National des Sciences\t\t", +"HNM\th\tEcole Normale Superieure de Nouakchott\t\t", +"HNMN\ts\tUniversidad Centroamericana\t\t", +"HNN\ts\tHorniman Museum of Natural History\t\t", +"HNNU\ts\tHunan Normal University, Botany Department\t\t", +"HNPGBI\th\tSeed and Plant Improvement Institute\t\t", +"HNR\ts\tHeilongjiang Academy of Sciences\t\t", +"HNT\ts\tHuntington Botanical Gardens\t\t", +"HNTS\ts\tVlastivedne muzeum\t\t", +"HNU\ts\tHunan Normal University\t\t", +"HNU\ts\tVietnam National University, Department of Botany\t\t", +"HNUB\ts\tNortheastern University, Biology Department\t\t", +"HNUE\ts\tHanoi National University of Education\t\t", +"HNUL\th\tNorthwestern University Inc.\t\t", +"HNWP\ts\tNorthwest Plateau Institute of Biology, Chinese Academy of Sciences\t\t", +"HNWU\ts\tNebraska Wesleyan University, Biology Department\t\t", +"HO\ts\tTasmanian Museum & Art Gallery\t\t", +"HOH\ts\tUniversitaet Hohenheim (210)\t\t", +"HOL\ts\tHolden Arboretum\t\t", +"HOLZ\ts\tPaleontological Collection\t\t", +"HOMP\ts\tOkresni muzeum Pribram Brezove Hory\t\t", +"HON\ts\tSichuan Grassland Research Institute\t\t", +"HOU\ts\tUniversity of Houston\t\t", +"HOXA\th\tEstacion biologica del Jardin Botanico de Missouri\t\t", +"HPAN\th\tUniversity of the State of Mato Grosso, UNEMAT\t\t", +"HPBR\th\tUniversidade Regional Integrada do Alto Uruguai e das Missoes\t\t", +"HPC\ts\tHoward Payne University, Biology Department\t\t", +"HPD\ts\tHampstead Scientific Society\t\t", +"HPDL\ts\tHampstead Public Library\t\t", +"HPH\ts\tMonroe County Department of Parks\t\t", +"HPL\th\tJardim Botanico Plantarum\t\t", +"HPM\ts\tHouston Museum of Natural Science\t\t", +"HPNP\th\tPumat National Park\t\t", +"HPP\ts\tUniversity of Helsinki, Plant Biology Department\t\t", +"HPPR\ts\tInstituto Superior Pedagogico de Pinar del Rio, Departamento de Biologia\t\t", +"HPSU\ts\tPortland State University, Biology Department\t\t", +"HPU\ts\tHigh Point University, Biology Department\t\t", +"HPU\ts\tHawaii Pacific University\t\t", +"HPUJ\ts\tPontificia Universidad Javeriana\t\t", +"HPVC\ts\tUniversidad Pedagogico Felix Varela,, Departamento de Biologia\t\t", +"HR\ts\tMuzeum Vychodnich Cech\t\t", +"HRB\ts\tIBGE\t\t", +"HRCB\ts\tUniversidade Estadual Paulista\t\t", +"HREC\th\tHopland Research & Extension Center\t\t", +"HRJ\ts\tUniversidade do Estado do Rio de Janeiro, Departamento de Biologia Animal e Vegetal\t\t", +"HRP\ts\tUniversidad Nacional de La Patagonia, Departamento Biologia General\t\t", +"HSB\ts\tUniversidad Mayor Real y Pontificia de San Francisco Xavier de Chuquisaca\t\t", +"HSBU\th\tShahid Beheshti University\t\t", +"HSC\ts\tHumboldt State University, Biological Sciences Department\t\t", +"HSCC\tc\tCulture Collection of the Research and Development Department\t\t", +"HSI\ts\tUniversity of Helsinki, Silviculture Department\t\t", +"HSIB\ts\tShanxi Institute of Biology, Botany Department\t\t", +"HSIC\ts\tMinistry of Natural Resources, Solomon Islands\t\t", +"HSM\ts\tChrist's Hospital, Biology Department\t\t", +"HSMC\th\tWhyte Thorne Botanic Garden\t\t", +"HSNU\ts\tEast China Normal University, Biology Department\t\t", +"HSP\th\tInstituto Cientifico Michael Owen Dillon\t\t", +"HSS\ts\tDevelopment, Technological and Investigacion Service, Forest Production Department\t\t", +"HSTM\th\tUniversidade Federal do Oeste do Para\t\t", +"HSU\ts\tHumboldt State University\t\t", +"HSU\ts\tHardin-Simmons University, Biology Department\t\t", +"HSUCV\ts\tHardin-Simmons University, Collection of Vertebrates\t\t", +"HSUD\th\tStation of Nature Research and Environmental Education\t\t", +"HSUE\ts\tNatural History Museum, Addis Ababa\t\t", +"HSUMZ\ts\tHenderson State University, Museum of Zoology\t\t", +"HSUVM\ts\tHumboldt State University Vertebrate Museum\t\t", +"HTC\ts\tHangzhou Normal College, Biology Department\t\t", +"HTD\ts\tCollege Natural History Society\t\t", +"HTE\ts\tQueen Ethelburga's School\t\t", +"HTGN\ts\tNorris Museum and Library\t\t", +"HTIN\ts\tUniversidad Nacional Agraria de la Selva\t\t", +"HTN\ts\tHitchin Museum\t\t", +"HTO\ts\tUniversidade Federal do Tocantins, Nucleo de Estudos Ambientais\t\t", +"HTTU\ts\tTennessee Technological University, Biology Department\t\t", +"HTU\ts\tUniversity of Taiz, Biology Department\t\t", +"HTW\th\tUniversidad Nacional de la Patagonia San Juan Bosco\t\t", +"HU\ts\tUniversity of Zhejiang\t\t", +"HUA\ts\tUniversidad de Antioquia, Centro de Investigaciones\t\t", +"HUAA\ts\tUniversidad Autonoma de Aquascalientes, Departamento de Biologia\t\t", +"HUAL\ts\tUniversidad de Almeria, Departamento de Biologia Vegetal y Ecologia\t\t", +"HUAP\ts\tHerbario, Universidad Autonoma de Puebla\tBUAP", +"HUAZ\th\tUniversidad de la Amazonia\t\t", +"HUB\ts\tHacettepe University, Botany Department\t\t", +"HUBE\ts\tGolden West College, Biology/Life Sciences Department\t\t", +"HUBO\ts\tUniversita degli Studi di Bologna\t\t", +"HUC\ts\tUniversidad de Cordoba, Departamento de Biologia\t\t", +"HUCM\ts\tHunan College of Traditional Chinese Medicine, Department of Chinese Materia Medica\t\t", +"HUCP\ts\tPontifica Universidade Catolica do Parana, Departamento de Ciencias Biologicas\t\t", +"HUCS\th\tUniversity of Caxias do Sul\t\t", +"HUDC\ts\tHoward University, Biology Department\t\t", +"HUE\ts\tHunan Education College, Biology Department\t\t", +"HUEF\ts\tHacettepe Ueniversitesi\t\t", +"HUEFS\ts\tUniversidade Estadual de Feira de Santana, Departamento de Ciencias Biologicas\t\t", +"HUEG\th\tUniversidade Estadual de Goias\t\t", +"HUEM\ts\tUniversidade Estadual de Maringa, Departamento de Biologia\t\t", +"HUESB\th\tUniversidade Estadual do Sudoeste da Bahia-Campus de Jequie\t\t", +"HUESBVC\th\tUniversidade Estadual do Sudoeste da Bahia-Vitoria da Conquista\t\t", +"HUF\ts\tHunan Forestry School\t\t", +"HUFABC\th\tUniversidade Federal do ABC\t\t", +"HUFSJ\th\tUniversidade Federal de Sao Joao del-Rei\t\t", +"HUFU\ts\tUniversidade Federal de Uberlandia, Instituto de Biologia\t\t", +"HUIC\ts\tHacettepe University Ichthyological Collection\t\t", +"HUIF\ts\tHunan Forestry Institute\t\t", +"HUJ\ts\tHebrew University of Jerusalem\t\t", +"HUJ:INV\ts\tHebrew University of Jerusalem, Invertebrate collection", +"HUKUK\tc\tCulture Collection of Animal Cells\t\t", +"HUL\ts\tFine Arts Museum\t\t", +"HULE\ts\tUniversidad Nacional Autonoma de Nicaragua, Departamento de Biologia\t\t", +"HUM\ts\tHumbolt University Zoologischen Museum\t\t", +"HUMC\th\tUniversidade de Mogi das Cruzes\t\t", +"HUMO\ts\tUniversidad Autonoma del Estado de Morelos, Centro de Educacion Ambiental e Investigacion Sierra de Huautla\t\t", +"HUMP\ts\tMuzeum v Humpolci\t\t", +"HUMZ\ts\tHokkaido University, Laboratory of Marine Zoology\t\t", +"HUNEB\th\tUniversidade do Estado da Bahia\t\t", +"HUNT\th\tHuntington University\t\t", +"HUP\th\tHazara University\t\t", +"HUPG\ts\tState University of Ponta Grossa, Departamento de Biologia\t\t", +"HUQ\ts\tUniversidad del Quindio\t\t", +"HURB\th\tUniversidade Federal do Reconcavo da Bahia\t\t", +"HURG\ts\tUniversidade do Rio Grande, Departamento de Ciencias Morfo-Biologicas\t\t", +"HUS\th\tSiauliai University\t\t", +"HUSA\ts\tUniversidad Nacional de San Agustin de Arequipa, Facultad de Ciencias Biologicas y Agropecuarias, Area de Biomedicas\t\t", +"HUSC\th\tUniversidade Santa Cecilia - UNISANTA\t\t", +"HUSEC\tc\tKonsiliarlabor fur Hamolytisch-Uramisches Syndrom\t\t", +"HUST\ts\tHunan University of Science and Technology, School of Life Sciences\t\t", +"HUT\tc\tHUT Culture Collection\t\t", +"HUT\ts\tHerbarium Truxillense, Universidad Nacional de La Libertad-Trujillo\t\t", +"HUTB\ts\tHainan University\t\t", +"HUTI\th\tUniversidad Tecnologica Indoamerica\t\t", +"HUTM\ts\tHunan Academy of Traditional Chinese Medicine and Pharmacy\t\t", +"HUTO\ts\tFundacao Universidade do Tocantins , UNITINS\t\t", +"HUTPL\ts\tUniversidad Tecnica Particular De Loja\t\t", +"HUVA\th\tUniversidade Estadual Vale do Acarau\t\t", +"HVASF\th\tUniversidade Federal do Vale do Sao Francisco\t\t", +"HVR\ts\tUniversidade de Tras-os-Montes e Alto Douro\t\t", +"HWA\ts\tSouthwest Agricultural University, Department of Biological Basic Courses\t\t", +"HWB\ts\tHarrow School, Biology Department\t\t", +"HWBA\ts\tBenedictine College, Biology Department\t\t", +"HWD\ts\tHollinwood Botanists' and Field Naturalists' Society\t\t", +"HWML\ts\tHoward W. Manter Laboratory of Parasitology\tUNSM:HWML", +"HXBH\ts\tFundacao CETEC\t\t", +"HXC\ts\tHendrix College, Biology Department\t\t", +"HY\ts\tOsmania University, Botany Department\t\t", +"HYD\ts\tHeywood and District Botanical Society\t\t", +"HYO\ts\tMuseum of Nature and Human Activities\t\t", +"Hyogo\ts\tMuseum of Nature and Human Activities\t\t", +"HZI\tc\tHelmholtz Zentrum fur Infektionsforschung (Helmholtz Centre for Infection Research)\t\t", +"HZM\ts\tMuseum of Natural History (Hrvatski Zooloski Muzej)\t\t", +"HZMZ\ts\tHrvatski Narodni Zooloski Muzej\t\t", +"HZTC\ts\tHanzhong Teachers College, Biology Department\t\t", +"HZU\ts\tZhejiang University\t\t", +"I\ts\tUniversitatea Al. I. Cuza Iasi\t\t", +"IA\ts\tUniversity of Iowa, Department of Biological Sciences\t\t", +"IAA\ts\tInstituto Antarctico Argentinao, Direccion Nacional del Antartico\t\t", +"IAAA\ts\tInstituto do Acucar e do Alcool\t\t", +"IABH\ts\tAl-Bayt University, Biology Department\t\t", +"IABHU\tscb\tInstitute for Amphibian Biology, Graduate School of Science, Hiroshima University\t\t", +"IAC\ts\tInstituto Agronomico de Campinas\t\t", +"IACC\ts\tInstituto Agronomico de Campinas\t\t", +"IACM\ts\tInstituto Agronomico\t\t", +"IADIZA-CM\ts\tInstituto Argentino de Investigaciones de las Zonas Aridas\t\t", +"IAFB\tc\tCollection of Industrial Microorganisms\t\t", +"IAGB\ts\tUniversitatea Al. I. Cuza Iasi\t\t", +"IAL\ts\tHerbario, Centro Nacional de Pesquisa de Mandioca e Fruticultura, EMBRAPA\t\t", +"IAL\tc\tSecao de Colecao de Culturas\t\t", +"IALCEL\tc\tSecao de Culturas Celulares\t\t", +"IALMIC\tc\tMicoteca do Insituto Adolfo Lutz\t\t", +"IAM\tc\tIAM Culture Collection, Center for Cellular and Molecular Research\t\t", +"IAM\ts\tNational Alliance of Shidlovskiy \"Ice Age\", Ice Age Museum\t\t", +"IAN\ts\tEmbrapa Amazonia Oriental\t\t", +"IAPG\ts\tInstitute of Animal Physiology and Genetics, Academy of Sciences of the Czech Republic\t\t", +"IARI\tsb\tIndian Agricultural Research Institute\t\t", +"IASI\ts\tUniversitatea Agronomica, Disciplina de Botanica\t\t", +"IAUGH\th\tIslamic Azad University Garmsar\t\t", +"IAUH\th\tIslamic Azad University\t\t", +"IAUM\th\tIslamic Azad University of Mashhad\t\t", +"IAUNT\th\tIslamica Azad University, North Tehran Branch\t\t", +"IAV\tsb\tInstitut Agronomique et Veterinaire Hassan II, Departement d'Ecologie Vegetale\t\t", +"IAVH\ts\tInstituto de Ivestigacion de los Recursos Biologicos Alexander von Humboldt\t\t", +"IB\ts\tUniversitat Innsbruck\t\t", +"IBA\ts\tInstituto Asturiano de Taxonomia y Ecologia Vegetal\t\t", +"IBA\tc\tCollection of Microorganisms Producing Antibiotics\t\t", +"IBAR\th\tIbaraki University\t\t", +"IBAUNC\ts\tUniversidad Nacional de Cuyo, Instituto de Biologia Animal\t\t", +"IBBS\ts\tInsitute of Biology and Soil Science, Russian Academy of Sciences\t\t", +"IBE\ts\tInstitute for Botanical Exploration\t\t", +"IBE\ts\tInstitut de Biologia Evolutiva, (CSIC-UPF)\t\t", +"IBEF\ts\tMuseum of the Izumi Board of Education\t\t", +"IBF\ts\tTiroler Landesmuseum Ferdinandeum\t\t", +"IBGE\ts\tReserva Ecologica do IBGE\t\t", +"IBH\ts\tUniversidad Nacional Autonoma de Mexico, Instituto de Biologia\t\t", +"IBI\ts\tInstituto Biologico, Laboratorio de Micologia\t\t", +"IBIR\ts\tInstitutul Agronomic\t\t", +"IBIW\ts\tI. D. Papanin Institute for Biology of Inland Waters\t\t", +"IBK\ts\tGuangxi Institute of Botany\t\t", +"IBL\ts\tIndependent Biological Laboratories\t\t", +"IBL\ts\tForest Research Institute, Poland\t\t", +"IBL\tc\tBotanical Institute, Lisbon Faculty of Sciences\t\t", +"IBL\tc\tInsect Biocontrol Laboratory (USDA-ARS, Beltsville)\t\t", +"IBLP\ts\tInstytut Badawczy Lesnictwa\t\t", +"IBMUNC\ts\tUniversidad Nacional de Cuyo, Instituto de Biologia Animal\t\t", +"IBP\ts\tInstituto de Biologia do Parana\t\t", +"IBPPM\tc\tInstitute of Biochemistry and Physiology of Plants and Microorganisms of the Russian Academy of Sciences\t\t", +"IBRC\tsc\tIranian Biological Resource Center\t\t", +"IBRP\ts\tInstituto Biologico de Ribeirao Preto\t\t", +"IBRP\ts\tInstitute for Breeding Research, Tokyo University of Agriculture\t\t", +"IBS\ts\tIrish Biogeographical Society\t\t", +"IBSBF\tc\tBiological Institute Culture Collection of Phytopathogenic Bacteria\t\t", +"IBSC\ts\tSouth China Botanical Garden\t\t", +"IBSD\ts\tDinghushan Biosphere Reserve\t\t", +"IBSP\ts\tInstituto Biologico de Sao Paulo\t\t", +"IBT\tc\tIBT Culture Collection of Fungi, Mycology Group, Technical University of Denmark\t\t", +"IBTS\ts\tInstitutul de Biologie, Tr. Savulescu\t\t", +"IBUG\ts\tUniversidad de Guadalajara\t\t", +"IBUNAM\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico\tUNAM", +"IBUNAM:CFB\tb\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion de Fotocolectas Biologicas", +"IBUNAM:CNAC\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Acaros", +"IBUNAM:CNAN\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Aracnidos", +"IBUNAM:CNAR\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Anfibios y Reptiles", +"IBUNAM:CNAV\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Aves", +"IBUNAM:CNCR\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Crustaceos", +"IBUNAM:CNHE\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Helmintos", +"IBUNAM:CNIN\ts\tColeccion Nacional de Insectos, Universidad Nacional Autonoma de Mexico\tIBUNAM:CNIN", +"IBUNAM:CNIN\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Insectos", +"IBUNAM:CNMA\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Mamiferos", +"IBUNAM:CNMO\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Moluscos", +"IBUNAM:CNPE\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Peces", +"IBUNAM:MEXU\ts\tInstituto de Biologia, Universidad Nacional Autonoma de Mexico, Herbario Nacional", +"IBUP\ts\tInstitute of Biology\t\t", +"IBUS\ts\tUniversidade Federal do Rio de Janeiro\t\t", +"IBUT\ts\tInstituto Butanta\t\t", +"IBY\ts\tBotanical Institute of Guangxi\t\t", +"ICA\ts\tInstituto Colombiano Agropecuario, Tibaitata\t\t", +"ICARDA\tsb\tInternational Center for Agricultural Research in the Dry Areas\t\t", +"ICBB\tc\tICBB Culture Collection for Microorganisms and Cell Culture\t\t", +"ICBU\ts\tBishop's University, Natural History Museum\t\t", +"ICCF\tc\tCollection of Industrial Microorganisms\t\t", +"ICEB\ts\tEurouniversity\t\t", +"ICEL\ts\tIcelandic Institute of Natural History\t\t", +"ICF\ts\tINIFAP\t\t", +"ICFC\tc\tIIB-INTECH Collection of Fungal Cultures\t\t", +"ICGC\ts\tIstituto Calasanzio\t\t", +"ICHUM\ts\tInvertebrate Collection of the Hokkaido University Museum\t\t", +"ICIS\ts\tIdaho Museum of Natural History\t\t", +"ICM\ts\tInstituto de Ciencias del Mar\tICMD", +"ICMP\tc\tInternational Collection of Microorganisms from Plants\tPDDCC ", +"ICN\ts\tUniversidade Federal do Rio Grande do Sul, Departamento de Botanica\t\t", +"ICN\ts\tInstituto de Ciencias Naturales, Museo de Historia Natural\t\t", +"ICP\ts\tIslamia College, University of Peshawar, Botany Department\t\t", +"ICPB\tc\tInternational Collection of Phytopathogenic Bacteria\t\t", +"ICPPB\ts\tInternational Collection of Plant Pathogenic Bacteria\t\t", +"ICPR\ts\tBiological Control Research Institute\t\t", +"ICRC\ts\tInsect Control and Research\t\t", +"ICRG\ts\tInstitute of Entomology\t\t", +"ICRI\ts\tZhonghan (Sun Yat-Sen) University, Research Institute of Entomology\t\t", +"ICRISAT\tb\tInternational Crops Research for the Semi-Arid Tropics\t\t", +"ICS-CC\tc\tInfection Control Services , National Health Laboratory Service 3\t\t", +"ICST\ts\tImperial College of Science, Technology & Medicine, Department of Biological Sciences\t\t", +"ICUI\ts\tUniversity of Iowa\t\t", +"ICVI\ts\tThe Volcani Center\t\t", +"ID\ts\tUniversity of Idaho, Biological Sciences Department\t\t", +"IDAC\tcb\tThe International Depositary Authority of Canada\t\t", +"IDEA\ts\tInstituto de Agronomia\t\t", +"IDF\ts\tUniversity of Idaho\t\t", +"IDS\ts\tIdaho State University, Biological Sciences Department\t\t", +"IE\tsc\tCepario de Hongos del Instituto de Ecologia\t\t", +"IEA\ts\tInstituto DI Entomologia Agraria\t\t", +"IEAB\ts\tIstituto di Entomologia Agraria dell'Universita\t\t", +"IEAM\ts\tIstituto di Entomologia dell'Universita degli Studi [= Istituto di Entomologia Agraria dell'Universita, Milan]\t\t", +"IEAP\ts\tIstituto di Entomologia Agraria dell'Universita\t\t", +"IEAPM\tc\tInstituto de Estudos do Mar \"Almirante Paulo Moreira\"\t\t", +"IEAS\ts\tInstitute of Entomology\t\t", +"IEAU\ts\tIstituto di Entomologia Agraria dell'Universita\t\t", +"IEB\ts\tInstituto de Ecologia, A.C.\t\t", +"IEBC\tc\tInternational Entomopathogenic Bacillus Centre (WHO)\t\t", +"IEBR\ts\tInstitute of Ecology and Biological Resources\t\t", +"IEC\ts\tCentre D'Etude sur les Ressources Vegetales\t\t", +"IECA\ts\tCzech Academy of Science, Institute of Entomology\t\t", +"IEEUACH\ts\tUniversidad Austral de Chile, Instituto de Ecologia y Evolucion\t\t", +"IEGG\ts\tUniversita di Bologna, Istituto di Entomologia \"Guido Grandi\"\t\t", +"IEGM\tc\tRegional Specialized Collection of Alkanotrophic Microorganisms\t\t", +"IEI\ts\tInstitut d'Estudis Ilerdencs\t\t", +"IEM\tc\tCzech National Collection of Type Cultures\t\t", +"IEME\ts\tInstitute for Evolution, Morphology, and Ecology of Animals\t\t", +"IEMM\ts\tInstituto de Ecologia\t\t", +"IENU\ts\tIstituto di Entomologia, Universita degli Studi\t\t", +"IEPA\ts\tIstituto di Entomologia Agraria dell'Universita\t\t", +"IER\th\tInstitut d'Economie Rurale\t\t", +"IEUC\ts\tIstituto di Entomologia Agraria dell'Universita Cattolica\t\t", +"IEUP\ts\tIstituto di Entomologia, Universita degli Studi\t\t", +"IEVB\ts\tInstitut de Zoologie [Institut Ed. Van Beneden]\t\t", +"IFAM\tc\tInstitut fur Allgemeine Mikrobiologie\t\t", +"IFAN\ts\tInstitut Fondamental d'Afrique Noire\t\t", +"IFBM\tc\tStreptokokken Sammlung\t\t", +"IFE\ts\tObafemi Awolowo University, Botany Department\t\t", +"IFFB\ts\tInstitut fuer Forstenentomologie und Forstschutz\t\t", +"IFG\ts\tInstitute of Forest Genetics\t\t", +"IFGD\ts\tIdaho Fish and Game\t\t", +"IFGH\ts\tIdaho Fish and Game Department\t\t", +"IFGP\ts\tPacific Southwest Research Station, USDA Forest Service\t\t", +"IFI\ts\tImperial Fisheries Institute\t\t", +"IFM\tc\tIFM Quality Services Pty Ltd\t\t", +"IFM\tc\tResearch Center for Pathogenic Fungi and Microbial Toxicoses, Chiba University\t\t", +"IFO\tc\tInstitute for Fermentation\t\t", +"IFP\ts\tInstitute of Applied Ecology, Academia Sinica\t\t", +"IFRD\ts\tResearch Institute of Resource Insects\t\t", +"IFRDCC\tc\tInternational Fungal Research and Development Culture Collection\t\t", +"IFREMER\ts\tInstitut Francais pour l'Etude de la Mer\t\t", +"IFRI\ts\tIndian Forest Research Institute\t\t", +"IFRPD\tc\tInstitute of Food Research and Product Development, Kasetsart University\t\t", +"IFSA\ts\tInstituto Florestal\t\t", +"IG\ts\tInstitute of Geology\t\t", +"IGB\tsb\tIsrael Plant Gene Bank\t\t", +"IGC\tc\tPortuguese Yeast Culture Collection\t\t", +"IGCAGS\ts\tInstitute of geology, Chinese Academy of Geological Science\t\t", +"IGCU\ts\tInstituto de Geologia, Ciudad Universitaria\t\t", +"IGESALQ\tc\tColecao Microorganismos\t\t", +"IGF\ts\tInstituto di Geologia e Paleontologia\t\t", +"IGGDC\th\tInstitute of Geology and Geophysics, Chinese Academy of Sciences\t\t", +"IGL\ts\tInstitute fuer Geowissenschaften Leoben\t\t", +"IGM\ts\tInstituto de Geologia\t\t", +"IGM\ts\tGeological Institute, Mongolian Academy of Sciences\t\t", +"IGPH\ts\tInstitut fuer Geologie und Palaeontologie der Universitat Hannover\t\t", +"IGUS\ts\tUniversitat des Saarlandes\t\t", +"IGWH\ts\tInstitut fuer Geowissenschaften aus dem Martin-Lurther- Universitat\t\t", +"IH\ts\tInstituto de Segunda Ensenanza de La Habana\t\t", +"IHASW\ts\tInstitute of Hydrobiology, Academia Sinica\t\t", +"IHB\ts\tInstitute of Hydrobiology, Chinese Academy of Sciences\t\t", +"IHCAS\ts\tMuseum of Institute of Hydrobiology, Chainese Academy of Sciences\t\t", +"IHEM\tc\tScientific Institute of Public Health, Mycology Section\tBCCM/IHEM ", +"IHUG\ts\tInstitut fuer Hygiene der Iniversitaet\t\t", +"IIBM-UNAM\tc\tIndustrial Culture Collection\t\t", +"IIBUV\ts\tInvestigaciones Biologicas de la Universidad Veracruzana (Mexico)\t\t", +"IICT\ts\tCentro de Zoologia do I.I.C.T.\t\t", +"IID\tc\tLaboratory Culture Collection\t\t", +"IIES\ts\tInstituto Investigaciones Entomologicas Salta\t\t", +"IIPB\ts\tInstituto de Ciencias del Mar\t\t", +"IITA\tb\tInternational Institute of Tropical Agriculture\t\t", +"IJ\ts\tInstitute of Jamaica\t\t", +"IJFM\tc\tInstituto Jaime Ferran de Microbiologia Consejo Superior de Investigaciones Cientificas\t\t", +"IJSM\ts\tInstitute of Jamaica, Natural History Museum\t\t", +"IK\ts\tZoological Institute, Ukrainian Academy of Sciences\t\t", +"ILCA\ts\tInternational Livestock Research Institute\t\t", +"ILF\ts\tIflracombe Museum\t\t", +"ILH\ts\tIowa Lakeside Laboratory\t\t", +"ILL\tsc\tUniversity of Illinois, Plant Biology Department\t\t", +"ILLS\ts\tIllinois Natural History Survey\t\t", +"ILMA\ts\tIstituto Leonardo Murialdo\t\t", +"ILPLA\ts\tMuseo de La Plata, Instituto de Limnologia\t\t", +"IM\ts\tInstituto de Segunda Ensenanza de Matanzas\t\t", +"IM\ts\tIndian Museum\t\t", +"IMAGE\tb\tThe I.M.A.G.E Consortium\t\t", +"IMARPE\ts\tInstituto del Mar del Peru\t\t", +"IMAS\tc\tInstitute for Marine and Antarctic Studies\t\t", +"IMAU\tc\tInner Mongolia Agricultural University, Key Laboratory of Dairy Biotechnology and Engineering\t\t", +"IMC\ts\tSichuan Academy of Traditional Chinese Medicine and Pharmacy\t\t", +"IMCC\tc\tInha Microbe Culture Collection, Inha University\t\t", +"IMCN\ts\tInstituto Vallecaucano de Investigaciones Cientificas\t\t", +"IMD\tc\tIndustrial Microbiology Dublin\t\t", +"IMD\ts\tInstitute of Medicinal Plant Development, Chinese Academy of Medical Sciences\t\t", +"IMDC\ts\tInner Mongolia Institute for Drug Control\t\t", +"IMDY\ts\tChinese Academy of Medical Sciences, Yunnan Branch\t\t", +"IMET\tc\tNational Kurturensammlung fuer Mikroorganismen\t\t", +"IMFA\ts\tInner Mongolia Academy of Forestry\t\t", +"IMI\tsc\tCABI Bioscience Genetic Resource Collection\t\t", +"IML\ts\tInstituto Miguel Lillo\t\t", +"IMLA\ts\tFundacion e Instituto Miguel Lillo\t\t", +"IMM\ts\tChinese Academy of Medical Science\t\t", +"IMM\ts\tInner Mongolian Museum\t\t", +"IMMH\tc\tCollection of Animal Viruses\t\t", +"IMMIB\tc\tCulture Collection of the Institute of Medical Microbiology and Immunology of the University of Bonn\t\t", +"IMPC\ts\tSichuan Academy of Traditional Chinese Medicine and Pharmacy\t\t", +"IMRU\tc\tWaksman Institute of Microbiology\t\t", +"IMS\ts\tInstitute of Marine Sciences\t\t", +"IMS\ts\tUniversity of North Carolina at Chapel Hill\t\t", +"IMSNU\tc\tInstitute of Microbiology, Seoul National University\t\t", +"IMSSM\ts\tInstituto Mexicano del Seguro Social\t\t", +"IMT\tc\tMicoteca do Instituto de Medicina Tropical de Sao Paulo\t\t", +"IMT\ts\tImperial Museum\t\t", +"IMTU\ts\tInstitute of Medicine, Community Medicine Department\t\t", +"IMUFRJ\tc\tInstituto de Microbiologia of Universidade Federal do Rio de Janeiro\t\t", +"IMVS\tc\tIMVS Culture Collection\t\t", +"IMYZA\tc\tInstituto de Microbiologia y Zoologia Agricola\t\t", +"INA\ts\tInstituto Nun'Alvres, Departamento de Biologia\t\t", +"INA\tc\tCulture Collection of the Institute of New Antibiotics\t\t", +"INALI\ts\tInstituto Limnologia\t\t", +"INB\ts\tInstituto Nacional de Biodiversidad, Departamento de Botanica\t\t", +"INBC\ts\tInstituto Nacional de Biodiversidad (INBio)\t\t", +"INBio\ts\tNational Biodiversity Institute, Costa Rica\t\t", +"INBP\ts\tInventorio Biologico Nacional [Museo Nacional de Historia Natural del Paraguay]\t\t", +"INC\ts\tInstituto Nacional de Cultura, Museo de Ciencias Naturales (Panama)\t\t", +"INCQS\tc\tFundacao Oswaldo Cruz-FIOCRUZ\t\t", +"IND\ts\tIndiana University, Department of Biology\t\t", +"IND-AN\ts\tAmphibian Collection\t\t", +"IND-M\ts\tLa Unidad de Investigacion \"Federico Medem\"-Inderena (Colombia)\t\t", +"INDRE\tc\tPathogen Fungi and Actinomycetes Collection\t\t", +"INEGI\ts\tInstituto Nacional de Estadistica Geografia e Informatica, Departamento de Botanica\t\t", +"INEP\th\tInstitute of the Industrial Ecology Problems of the North of Kola Science Center of the Russian Academy of Sciences.\t\t", +"INER\ts\tIstituto Nazionale di Entomologia\t\t", +"INFYB\ts\tInstituto Nacional de Farmacologia y Bromatologia, Farmacobotanica\t\t", +"INGU\th\tIngush State University\t\t", +"INH\ts\tInstitut National d'Horticulture, Departement de Sciences Biologiques\t\t", +"INH\ts\tInstituto Nacional de Higiene\t\t", +"INHM\ts\tIraq Natural History Museum\t\t", +"INHS\ts\tIllinois Natural History Survey\t\t", +"INIA\ts\tInstituto Nacional de Investigaciones Forestales y Agropecurias\t\t", +"INIA\tb\tEl Instituto de Investigaciones Agropecuarias\t\t", +"INIA\tb\tInstituto Nacional de Investigacion y Tecnologia Agraria y Alimentaria\t\t", +"INIBP\ts\tInstituto Nacional de Investigaciones Biologico Pesqueras\t\t", +"INIDA\ts\tInstituto Nacional de Investigacao e Desenvolvimento Agrario - Cape Verde\t\t", +"INIDEP\ts\tInstituto Nacional de Investigacion y Desarrollo Pesquero\t\t", +"INIF\tc\tColeccion de Microhongos\t\t", +"INIFAT\tc\tINIFAT Fungus Collection\t\t", +"INIP\ts\tInstituto Nacional de Investigacao das Pescas\t\t", +"INIR\ts\tColeccion de Termitas Mexicanas\t\t", +"INLA\ts\tINIA Subestacion Experimental Control Biologico La Cruz\t\t", +"INM\ts\tIbaraki Nature Museum\t\t", +"INMI\tc\tInstitute of Microbiology, Russian Academy of Sciences\t\t", +"INPA\ts\tInstituto Nacional de Pesquisas da Amazonia\t\t", +"INPA:CR\ts\tInstituto Nacional de Pesquisas da Amazonia, Crustacea Collection", +"INPA:H\ts\tInstituto Nacional de Pesquisas da Amazonia, Collection of Amphibians and Reptiles", +"INPA:LMM\tc\tInstituto Nacional de Pesquisas da Amazonia, Laboratorio de Micologia Medica Divisao de Microbiologia e Nutricao", +"INPC\ts\tNational Pusa Collections\t\t", +"INRA\tb\tInstitut National de la Recherche Agronomique\t\t", +"INRA:CGAB\tcb\tInstitut National de la Recherche Agronomique, Collection of Germplasms of Agaricus bisporus", +"INU\th\tInonu University\t\t", +"INV\ts\tInverness Museum and Art Gallery\t\t", +"INVA\ts\tInvergordon Academy\t\t", +"INVAM\tc\tInternational Culture Collection of (Vesicular) Arbuscular Mycorrhizal Fungi\t\t", +"INVEMAR\ts\tInstituto de Investigaciones Marinas de Punta de Betin\t\t", +"IO\ts\tInstituto Oceanografico da Universidade de Sao Paulo\t\t", +"IO\ts\tInstituto de Oceanografia da Universidade de Lisboa\t\t", +"IOAN\ts\tShirshov Institute of Oceanography\t\t", +"IOC\tc\tColecao de Culturas de Fungos do Instituto Oswaldo Cruz\t\t", +"IOCAS\ts\tInstitute of Oceanology, Chinese Academy of Scineces\t\t", +"IOEB\tc\tCentre de ressources biologiques oenologiques\tCRBO", +"IOH\ts\tAcademia de Ciencias\t\t", +"IOM\ts\tInstitute of Oceanology, Academy of Sciences\t\t", +"IOPM\ts\tIzu Oceanic Park Museum\t\t", +"IORD\ts\tTakai University, Institute of Oceanic Research and Development\t\t", +"IOS\ts\tInstitute of Oceanographic Sciences\t\t", +"IOUSP\tc\tMarine Microalgae Culture Collection\t\t", +"IOWA\ts\tUniversity of Iowa, Museum of Natural History\t\t", +"IPA\ts\tEmpresa Pernambucana de Pesquisa Agropecuaria, IPA\t\t", +"IPA:germplasm bank\tb\tEmpresa Pernambucana de Pesquisa Agropecuaria, IPA, ", +"IPAE\ts\tInstitute of Plant and Animal Ecology Ural Branch of Russian Academy of Sciences\t\t", +"IPB\ts\tInstituto Paranaense de Botanica\t\t", +"IPB\ts\tInstitut fuer Palaeontologie\t\t", +"IPBIR\tb\tIntegrated Primate Biomaterials and Information Resource\t\t", +"IPCN\ts\tInstituto Patagonico de Ciencias Naturales\t\t", +"IPE\ts\tInstituto Pirenaico de Ecologia\t\t", +"IPEE RAS\ts\tA.N. Severtzov Institute of Ecology and Evolution, Russian Academy of Sciences\t\t", +"IPEF\ts\tInstitut fuer Pflanzenschutzforschung\t\t", +"IPFUB\ts\tInstitute for Paleontology of the Freie Universitat\t\t", +"IPGR\tb\tInstitute for Plant Genetic Resources\t\t", +"IPHG\ts\tInstitut fur Palaeontologie und Historische Geologie\t\t", +"IPK\tsb\tLeibniz Institute of Plant Genetics and Crop Plant Research\t\t", +"IPKUP\ts\tPaleontologiscsky Institute\t\t", +"IPLA\tc\tInstituto de Productos Lacteos de Asturias\t\t", +"IPMB\ts\tInstitut fur Pharmazie und Molekulare Biotechnologie\t\t", +"IPMC\ts\tInstitut Paleontologic Dr. M. Crusfafont Sabadell\t\t", +"IPMGO\ts\tInstitut fur Paleontologie und Museum, Gottingen Universitat\t\t", +"IPMY\ts\tUniversidad Pedagogica Libertador, Nucleo Maracay, Departamento de Biologia\t\t", +"IPN\ts\tInstituto Politecnico Nacional\t\t", +"IPO\ts\tPlant Research International\t\t", +"IPPAS\tc\tCulture Collection of Microalgae IPPAS\tIPPRAS", +"IPRN\ts\tInstituto de Pesquisas de Recursos Naturais Renovaveis\t\t", +"IPS\ts\tIpswich Museum\t\t", +"IPSLI\ts\tIpswich Literary Institute\t\t", +"IPSM\ts\tIpswich Museum\t\t", +"IPSN\ts\tInstituto de Paleontologia de Sabadella\t\t", +"IPT\tc\tAgrupamento de Biotecnologia, Culture Collection of Microorganisms\t\t", +"IPTB\ts\tInstituto de Pesquisas Tecnologicas\t\t", +"IPUW\ts\tInstitut fuer Palaeontologie der Universitaet Wien\t\t", +"IPW\ts\tInstutut fuer Palaeontologie der Uinversitaet Wurzburg\t\t", +"IQW\th\tSenckenberg Forschungsinstitut und Naturmuseen\t\t", +"IRAG\ts\tInstitut National de la Recherche Agronomique de Antilles et Guyane\t\t", +"IRAI\th\tParque da Ciencia Newton Freire Maia\t\t", +"IRAN\tsc\tIranian Research Institute of Plant Protection, Department of Botany\t\t", +"IRAQ\ts\tIraq Natural History Museum\t\t", +"IRBR\ts\tUniversidad de Oriente, Departamento de Biologia\t\t", +"IRCW\ts\tMadison, University of Wisconsin\t\t", +"IRD\ts\tInstitut de Recherche pour le Developpement\t\t", +"IRDA\ts\tAgriculture Department\t\t", +"IREC\ts\tInstitut de Recherches Entomologique de la Caribe\t\t", +"IRGC\tb\tInternational Rice Genebank Collection\t\t", +"IRK\ts\tSiberian Institute of Plant Physiology and Biochemistry\t\t", +"IRKU\ts\tIrkutsk State University, Department of Botany and Genetics\t\t", +"IRP\ts\tIsle Royale National Park\t\t", +"IRRI\tsb\tInternational Rice Research Institute\t\t", +"IRSAC\ts\tInstitute de Recherche Scientific en Afrique Centrale\t\t", +"IRSC\ts\tInstitut de Recherches Scientifiques au Congo\t\t", +"IRSM\ts\tInstitut Recherche Scientifique de Madagascar\t\t", +"IRSN\ts\tInstitut Royal des Sciences Naturelles de Belgique\t\t", +"IRSNB\ts\tInstitut Royal des Sciences Naturelles de Belgique\t\t", +"IRVC\ts\tUniversity of California, UCI Arboretum Mail\t\t", +"IS\ts\tUniversity of Molise, Department of Science and Technology for Environment and Territory\t\t", +"ISAB\ts\tIstituto Sant'Antonio dei Padri Francescani\t\t", +"ISAR\ts\tAcademy of Science\t\t", +"ISAS\ts\tKunming Institute of Zoology\t\t", +"ISB\ts\tInstitute of Spelology \"Emile Racovita\"\t\t", +"ISBB\ts\tInstitutul de Stiinte Biologice\t\t", +"ISBC\ts\tInstitute of Soil Biology, Academy of Science of the Czech Republic\t\t", +"ISBC:CMF\tcb\tInstitute of Soil Biology, Academy of Science of the Czech Republic, Collection of Microscopic Fungi", +"ISC\tc\tInternational Salmonella Centre (W.H.O.)\t\t", +"ISC\ts\tIowa State University, Botany Department\t\t", +"ISCM\ts\tInstitut Scientifique Cheripen\t\t", +"ISE\th\tUniversidade Federal de Sergipe, Campus Professor Alberto Carvalho\t\t", +"ISEA\ts\tInstitute of Systematics and Evolution of Animals\t\t", +"ISEAK\ts\tInstytut Systematyki i Ewolucji Zwierz\t\t", +"ISEM\ts\tInstitut des Sciences de l'Evolution Montpellier \t\t\t", +"ISER\ts\tInstitutul Speologie Emil G. Racovita\t\t", +"ISH\ts\tInstitut fuer Seefischerei\t\t", +"ISI\ts\tGeological Museum, Indian Statistical Institute\t\t", +"ISIS\ts\tNaturforschende Gesellschaft Isis\t\t", +"ISKW\th\tIshikawa Museum of Natural History\t\t", +"ISL\ts\tQuaid-I-Azam University, Biological Sciences Department\t\t", +"ISM\ts\tIllinois State Museum\tISMS", +"ISMAR\th\tConsiglio Nazionale delle Ricerche, Istituto di Scienze Marine\t\t", +"ISMC\ts\tIndiana Department of Natural Resources\t\t", +"ISNHC\ts\tState Historical Society of Iowa\t\t", +"ISNP\ts\tIstituto Sperimentale per la Nutrizione delle Piante\t\t", +"ISP\tc\tInternational Cooperative Project for Description and Deposition of Type Cultures\t\t", +"ISPaVe\tc\tIstituto Sperimentale per la Patologia Vegetale\tCRA-PAV", +"ISRA\ts\tRoyal Academy\t\t", +"ISRI\tc\tIndonesian Sugar Research Institute, Pusat Penelitian Perkebunan Gula Indonesia\t\t", +"ISS\tc\tInstitute of Soil Science Collection of Bacteria\t\t", +"ISTC\ts\tUniversity of Northern Iowa, Biology Department\t\t", +"ISTE\ts\tUniversity of Istanbul, Department of Pharmaceutical Botany\t\t", +"ISTF\ts\tIstanbul University, Botany Department\t\t", +"ISTO\ts\tUniversity of Istanbul, Orman Fakueltesi\t\t", +"ISTPM\ts\tInstitut Scientifique et Technique des Peches Maritimes\t\t", +"ISU\ts\tIllinois State University, Biological Sciences Department\t\t", +"ISU\ts\tIndiana State University\t\t", +"ISUC\ts\tNormal, Illinois State University\t\t", +"ISUI\ts\tIowa State University\t\t", +"ISUVC\ts\tIndiana State University\t\t", +"ISZA\ts\tIstituto Sperimentale per la Zoologia Agraria\t\t", +"ISZP\ts\tInstitute of Systematic Zoology\t\t", +"ITAE\ts\tIstituto Tecnico Agrario Enologico\t\t", +"ITAL\tc\tBanco de Fermentos Lacticos\t\t", +"ITALSL\tc\tSecao de Leite e Derivados\t\t", +"ITALSM\tc\tSecao de Microbiologia\t\t", +"ITBCC\tc\tInstitute of Technology Bandung Culture Collection\t\t", +"ITBCZ\ts\tInstitute of Tropical Biology Collection of Zoology\t\t", +"ITBZC\ts\tInstitute of Tropical Biology, Zoology Collection\t\t", +"ITC\tb\tInternational Transit Centre\t\t", +"ITCC\tc\tIndian Type Culture Collection\t\t", +"ITCC\ts\tIstituto Tecnico Stattale \"Camillo Cavour\"\t\t", +"ITCO\ts\tIstituto Tecnico Commerciale \"Oronzio Gabriele Costa\"\t\t", +"ITCV\ts\tInstituto Tecnologico de Ciudad Victoria, Departamento de Micologia\t\t", +"ITD\tc\tColeccion de Cepas Microbianas\t\t", +"ITDI\tc\tIndustrial Technology Development Institute\t\t", +"ITEM\tc\tInstitute of Toxins and Mycotoxins from Plant Parasites\t\t", +"ITG\tc\tITG\t\t", +"ITH\tc\tW.H.O./F.A.O. Collaborating Centre for Reference and Research on Leptospirosis\t\t", +"ITHA\ts\tInstituut voor Tropische Hygiene\t\t", +"ITIC\ts\tUniversidad de El Salvador, Escuela de Biologia\t\t", +"ITLJ\ts\tNational Institute of Agro-environmental Sciences\t\t", +"ITMH\th\tMuhimbili University of Health and Allied Sciences\t\t", +"ITMM\ts\tInstituto Tecnologico de Monterrey\t\t", +"ITT\ts\tInstituto Technologico de Ciudad Victoria\t\t", +"IU\ts\tIndiana University\t\t", +"IUI\ts\tInha University, Biology Department\t\t", +"IUIC\ts\tIndiana University\t\t", +"IUK\ts\tUniversite de Kinshasa, Departement de Biologie\t\t", +"IUM\ts\tIwate University, Biology Department\t\t", +"IUP\ts\tIndiana University of Pennsylvania, Biology Department\t\t", +"IUQ\ts\tLaboratorio de Ictiologia\t\t", +"IVAU\ts\tInstituut Voor Aardwetenschappen\t\t", +"IVB\ts\tInstitute of Vertebrate Biology, Academy of Sciences of the Czech Republic\t\t", +"IVF\ts\tChinese Academy of Agricultural Sciences\t\t", +"IVGU\th\tIvanovo State University\t\t", +"IVIC\ts\tInstituto Venezolano de Investigaciones Cientificas\t\t", +"IVPP\ts\tInstitute of Vertebrate Paleontology and Paleoanthropology\tIVPP AS", +"IZ\tc\tDepartamento de Tecnologia Rural\t\t", +"IZ\ts\tInstituto de Zoologia\t\t", +"IZ\ts\tInstitute of Zoology\t\t", +"IZ\ts\tAegean Agricultural Research Institute, Department of Plant Genetic Resources\t\t", +"IZA\ts\tUniversita di l'Aguila, Instituto di Zoologia\t\t", +"IZAC\ts\tUniversidad Nacional de La Rioja-Sede Chamical\t\t", +"IZAC\ts\tAcademia de Ciencias de Cuba, Instituto de Zoologia\t\t", +"IZAS\ts\tInstitut Zoologii Akademii Nauk Ukraini - Institute of Zoology of the Academy of Sciences of Ukraine\t\t", +"IZASK\ts\tInstitue of Zoology of the Kazakh Academy of Sciences\t\t", +"IZBE\ts\tInstitute of Zoology and Botany\t\t", +"IZBT\ts\tL'Institut de Zoologie et Botanique de Tartu\t\t", +"IZCAS\ts\tInstitute of Zoology, Chinese Academy of Sciences\tZMIOZ", +"IZCR\ts\tIstituto di Zoologia\t\t", +"IZEF\ts\tEge Ueniversitesi, Farmasoetik Botanik Kuersuesue\t\t", +"IZET-UCV\ts\tInstituto de Zoologia y Ecologia Tropical\t\t", +"IZGAS\ts\tGeorgian Academy of Sciences, Insititute of Zoology\t\t", +"IZPAN\ts\tZoological Institute, Polish Academy of Sciences\t\t", +"IZPC\ts\tUniversidade do Porto\t\t", +"IZSI\ts\tIstituto di Zoologia\t\t", +"IZSSA\tc\tCollection of Experimental Zooprophylactic Institute of Sardinia (Istituto Zooprofilattico Sperimentale della Sardegna \"G.Pegreffi\", Sassari))\t\t", +"IZTA\ts\tUniversidad Nacional Autonoma de Mexico, Iztacala, Jefatura de Biologia\t\t", +"IZUA\ts\tUniversidad Austral de Chile, Instituto de Zoologia\t\t", +"IZUC\ts\tUniversidad de Concepcion, Instituto de Zoologia\t\t", +"IZUCS\ts\tUniversita DI Cagliari\t\t", +"IZUE\ts\tUniversitat -Erlangen-Nurnberg\t\t", +"IZUG\ts\tIstituto di Zoologia dell'Universita\t\t", +"IZUI\ts\tInstitut fuer Zoologie der Universitat Innsbruck\t\t", +"IZUM\ts\tIstituto di Zoologia dell'Universita\t\t", +"IZUP\ts\tIstituto di Zoologia dell'Universita\t\t", +"IZUW\ts\tInstitut fuer Zoologie der Universitat Wien\t\t", +"IZW\ts\tInstitut Zoologii\t\t", +"IZWU\ts\tPaleozology Department, Institute of Zoology, Worclaw University\t\t", +"J\ts\tUniversity of the Witwatersrand, Botany Department\t\t", +"JA\ts\tConsejeria de Medio Ambiente (Junta de Andalucia), Direccion General de Gestion del Medio Natural\t\t", +"JAC\ts\tUniversity of Jodhpur, Botany Department\t\t", +"JACA\ts\tInstituto Pirenaico de Ecologia, CSIC\t\t", +"JAEN\ts\tUniversidad de Jaen, Botanica\t\t", +"JAS\ts\tJiangxi Academy of Sciences\t\t", +"JATH\ts\tUniversity of Szeged\t\t", +"JAUM\ts\tJardin Botanico Joaquin Antonio Uribe\t\t", +"JAY\ts\tFondation Cognacq-Jay\t\t", +"JBAG\ts\tJardin Botanico Atlantico, Ayuntamiento de Gijon\t\t", +"JBB\th\tJardin Botanico Jose Celestino Mutis\t\t", +"JBC\tb\tFrancisco Javier Clavijero Botanic Garden\tXAL", +"JBCC\th\tAlaska State Museum\t\t", +"JBG\ts\tJohannesburg Botanic Garden\t\t", +"JBGP\ts\tJardin Botanico Guillermo Pineres\t\t", +"JBL\ts\tJardin Botanico Lankester, Universidad de Costa Rica\t\t", +"JBN\ts\tJardin Botanico Nacional\t\t", +"JBSD\ts\tJardin Botanico Nacional Dr. Rafael M. Moscoso\t\t", +"JBVN\ts\tJardin Botanique de la Ville de Nice, Service des Espaces Verts\t\t", +"JBVPF\tsb\tJardin botanique de la Ville de Paris\t\t", +"JBWM\ts\tJ.B. Wallis Museum of Entomology\t\t", +"JCB\ts\tSt. Joseph's College\t\t", +"JCE\ts\tJiangxi College of Education, Biology Department\t\t", +"JCM\tc\tJapan Collection of Microorganisms\t\t", +"JCRB\tc\tJapanese Collection of Research Bioresources Cell Bank\t\t", +"JCT\tc\tJames Cook Townsville\t\t", +"JE\ts\tHerbarium Haussknecht, Jena\t\t", +"JEF\ts\tIndiana University Southeast, Biology Department\t\t", +"JEL\tc\tJoyce E. Longcore Chytrid Collection at the University of Maine\t\t", +"JEL\ts\tLatvian Agricultural Academy, Plant Protection Department\t\t", +"JEPS\ts\tUniversity of California, Jepson Herbarium\t\t", +"JES\th\tUniversidad Autonoma Chapingo\t\t", +"JESW\ts\tJohn Evelyn Society's Museum\t\t", +"JEY\ts\tBoys' Grammar School, Victoria College\t\t", +"JF\ts\tJonkershoek Forestry Research Centre, Environment Affairs Department\t\t", +"JFBM\ts\tJames Ford Bell Museum of Natural History\t\t", +"JHH\ts\tNew York State Herbarium\t\t", +"JHS\th\tRegional Research Institute\t\t", +"JHWU\ts\tWittenberg University, Biology Department\t\t", +"JIC\tb\tJohn Innes Centre\t\t", +"JII\ts\tJohn Innes Institute\t\t", +"JIU\ts\tJishou University, Biology Department\t\t", +"JJF\ts\tJiujiang Forestry Institute\t\t", +"JJT\ts\tJiujiang Teachers College, Biology Department\t\t", +"JJU\ts\tJeonju University\t\t", +"JLFC\ts\tForestry College of Beihua University, Forestry Department\t\t", +"JLMP\ts\tJilin Academy of Traditional Chinese Medicine and Materia Medica\t\t", +"JM\ts\tJura Museum, Eichstatt\t\t", +"JME\th\tJura-Museum Eichstatt\t\t", +"JMM\ts\tEarlham College, Joseph Moore Museum\t\t", +"JMRC\tc\tJena Microbial Resource Collection\t\t", +"JMRC:SF\tc\tJena Microbial Resource Collection, Subcollection Fungi", +"JMSMC\ts\tJiamusi Medical College, Department of Pharmacy\t\t", +"JMUH\ts\tJames Madison University, Department of Biology\t\t", +"JN\ts\tJinggang Mountain Nature Reserve\t\t", +"JNR\ts\tJiulian Mountain Nature Reserve, Administration Department\t\t", +"JNU\ts\tJi Nan University\t\t", +"JNU\ts\tChonbuk National University, Faculty of Biological Sciences\t\t", +"JNUB\th\tJeju National University\t\t", +"JOE\ts\tUniversity of Joensuu, Biology Department\t\t", +"JOI\th\tUniversidade da Regiao de Joinville\t\t", +"JOMU\th\tJohn Muir National Historic Site\t\t", +"JONK\ts\tJonkershoek Herbarium\t\t", +"JOTR\th\tJoshua Tree National Park\t\t", +"JP\ts\tPhyletisches Museum Jena\t\t", +"JPB\ts\tUniversidade Federal da Paraiba, Cidade Universitaria, Departamento de Sistematica e Ecologia\t\t", +"JPMP\ts\tJanus Pannonius Museum\t\t", +"JPU\ts\tJanus Pannonius University, Botany Department\t\t", +"JRAU\ts\tUniversity of Johannesburg, Department of Botany and Plant Biotechnology\t\t", +"JROH\th\tJasper Ridge Biological Preserve, Stanford University\t\t", +"JRY\ts\tJersey College for Girls\t\t", +"JSHC\ts\tJay S. Haft Collection\t\t", +"JSMPE\ts\tJoint Soviet Mongolian Paleontolgical Expedition\tJRMPE", +"JSPC\ts\tShandong University, Biology Department\t\t", +"JSPC\ts\tJ. Rusek Collection\t\t", +"JSU\ts\tJacksonville State University, Biology Department\t\t", +"JSY\ts\tMuseum and Art Gallery of La Societe Jersiaise\t\t", +"JTNM\ts\tJoshua Tree National Monument\t\t", +"JTPC\ts\tColorado Entomological Museum (formerly John T. Polhemus collection)\t\t", +"JU\ts\tJinan University\t\t", +"JUA\ts\tUniversidad Nacional de Jujuy, Facultad de Ciencias Agrarias\t\t", +"JUG\ts\tJiwaji University, Botany Department\t\t", +"JUJ\ts\tHebei Agricultural University\t\t", +"JVC\ts\tJardin Botanico Canario Viera y Clavijo\t\t", +"JVR\ts\tUniversidad Nacional\t\t", +"JXAU\ts\tJiangxi Agricultural University, Forestry Department\t\t", +"JXCM\ts\tJiangxi College of Traditional Chinese Medicine, Pharmacy Department\t\t", +"JXF\ts\tJiangxi Forestry Institute\t\t", +"JXM\ts\tJiangxi Institute of Materia Medica\t\t", +"JXU\ts\tJiangxi University, Biology Department\t\t", +"JYV\ts\tUniversity of Jyvaeskylae, Natural History Department\t\t", +"K\tsb\tRoyal Botanic Gardens, Kew\t\t", +"K(M)\ts\tMycology Collection of Kew Royal Botanical Gardens\t\t", +"KA\ts\tVytautas Magnus University\t\t", +"KABA\ts\tUniversity of Kabul\t\t", +"KAC\tc\tKalmar Algae Collection\t\t", +"KACC\tc\tKorean Agricultural Culture Collection\t\t", +"KAG\ts\tKagoshima University Museum\t\t", +"KAGS\ts\tKagoshima University, Biology Department\t\t", +"KAI\ts\tHenan University, Biology Department\t\t", +"KAMA\ts\tYokohama University\t\t", +"KANA\ts\tKanazawa University\t\t", +"KAND\th\tKandalaksha State Nature Reserve\t\t", +"KANU\ts\tUniversity of Kansas\t\t", +"KAR\ts\tUniversity of Tehran, Horticulture Department\t\t", +"KARI\ts\tKenya Agricultural Research Institute\t\t", +"KARS\ts\tKawanda Agricultural Research Station\t\t", +"KAS\ts\tUniversitaet Gesamthochschule Kassel, Morphologie und Systematik der Pflanzen\t\t", +"KASH\ts\tUniversity of Kashmir\t\t", +"KASSEL\ts\tNaturkundemuseum im Ottoneum\t\t", +"KATH\ts\tDepartment of Plant Resources\t\t", +"KATO\ts\tKaradeniz Technical University, Department of Forest Botany\t\t", +"KATO:Fungi\ts\tKaradeniz Technical University, Department of Forest Botany, Fungi collection", +"KAUM\ts\tKagoshima University Museum\t\t", +"KAUM:I\ts\tKagoshima University Museum, Ichthyology Collection", +"KAW\ts\tKawanda Research Station, Department of Agriculture\t\t", +"KAZ\ts\tKazan State University\t\t", +"KB\ts\tNational Biological Resources Center, Department of Biological Sciences\t\t", +"KBAI\ts\tKuban Agricultural State University, Department of Biology and Ecology\t\t", +"KBG\tb\tKyoto Botanical Garden\t\t", +"KBHG\ts\tH. M. Berbekov Kabardian-Balkarian State University, Department of Botany\t\t", +"KBRYO\ts\tCentre College of Kentucky\t\t", +"KBSMS\ts\tKellogg Biological Station, Michigan State University\t\t", +"KBT\ts\tStewarty Museum\t\t", +"KCCM\tc\tKorean Culture Center of Microorganisms, Department of Food Engineering\t\t", +"KCFS\ts\tKing's College\t\t", +"KCK\ts\tDick Institute\t\t", +"KCLB\tc\tKorean Cell Line Bank\t\t", +"KCOM\tc\tKorean Collection for Oral Microbiology\t\t", +"KCS\ts\tUniversity of London, King's College, Botany Department\t\t", +"KCTC\tc\tKorean Collection for Type Cultures\t\t", +"KDL\ts\tKendal Museum\t\t", +"KDR\ts\tBewdley Museum\t\t", +"KE\ts\tKent State University, Biological Sciences Department\t\t", +"KEF\ts\tKunming Edible Fungi Institute\t\t", +"KEI\ts\tUniversity of Transkei, Botany Department\t\t", +"KEIB\ts\tKatedra Ekologii i Biogeografii\t\t", +"KEIU\ts\tKorea University\t\t", +"KEM\ts\tUniversity of Kemerovo, Department of Botany\t\t", +"KEMC\tc\tKorea Environmental Microorganism Center, Kyonggi University\t\t", +"KEMH\tc\tKEMH/PMH Culture collection\t\t", +"KEN\ts\tLongwood Gardens, Horticulture Department\t\t", +"KEND\ts\tKendal Natural History Society\t\t", +"KEP\ts\tForest Research Institute Malaysia\t\t", +"KESC\ts\tKeene State College, Department of Biology\t\t", +"KEVO\ts\tUniversity of Turku\t\t", +"KF\th\tKerman University of Medical Sciences\t\t", +"KFBG\th\tKadoorie Farm and Botanic Garden\t\t", +"KFCC\tc\tKorean Federation of Culture Collection\t\t", +"KFI\ts\tHongnung Arboretum, Silviculture Department\t\t", +"KFRI\ts\tKerala Forest Research Institute\t\t", +"KFRS\ts\tKanudi Fisheries Research Station\t\t", +"KFTA\ts\tSaint Petersburg State S. M. Kirov Forest Technology Academy, Botany and Dendrology Department\t\t", +"KFUH\ts\tKing Faisal University, Chemistry and Botany Department\t\t", +"KG\th\tInternational Phytochemistry Research and Production Institute\t\t", +"KGU\ts\tGeology and Mineralogy Museum\t\t", +"KGY\ts\tCliffe Castle Art Gallery and Museum\t\t", +"KH\ts\tKorea National Arboretum\t\t", +"KHA\ts\tInstitute for Water and Ecology Problems, Far East Branch, Russian Academy of Sciences, Laboratory of Plant Ecology\t\t", +"KHD\ts\tKathryn Kalmbach Herbarium of Vascular Plants, Denver Botanic Gardens\t\t", +"KHER\ts\tKherson Pedagogical University, Botany Department\t\t", +"KHF\ts\tForest Research and Education Institute, Soba\t\t", +"KHMM\ts\tKultur Historisches Museum\t\t", +"KHMS\ts\tMuzeum `umavy\t\t", +"KHOR\ts\tPamir Biological Institute\t\t", +"KHU\ts\tUniversity of Khartoum, Botany Department\t\t", +"KHUG\ts\tAussenstelle der Universitaet\t\t", +"KHUS\ts\tKyung Hee University, Biology Department\t\t", +"KIEL\ts\tChristian-Albrechts-Universitaet Kiel\t\t", +"KIFB\ts\tKorean Institute of Freshwater Biology\t\t", +"KIOM\th\tKorea Institute of Oriental Medicine\t\t", +"KIP\th\tInstitut National pour l'Etude et la Recherche Agronomique\t\t", +"KIRI\ts\tUniversity of Rhode Island, Department of Biological Sciences\t\t", +"KIS\th\tUniversite de Kisangani\t\t", +"KISA\th\tInstitut Congolais pour la Conservation de la Nature\t\t", +"KIT\tc\tLaboratorium voor Tropische Hygiene\t\t", +"KIUJ\ts\tKyusu University\t\t", +"KIZ\ts\tKunming Institute of Zoology, Chinese Academy of Sciences\t\t", +"KKFC\ts\tKasetsart University Kamphaengsaen campus Fungus Collection\t\t", +"KKM\ts\tKirkleatham Museum\t\t", +"KKU\ts\tHerbarium, Department of Biology, Khon Kaen University\t\t", +"KKUA\ts\tKhon Kaen University\t\t", +"KKUK\ts\tKon-Kuk University\t\t", +"KL\ts\tLandesmuseum fuer Kaernten\t\t", +"KLA\ts\tHerbarium, Department of Agriculture, Malaysia\t\t", +"KLE\ts\tUniversity of Keele, Biological Sciences Department\t\t", +"KLGU\ts\tKaliningrad State University, Department of Botany and Plant Ecology\t\t", +"KLH\ts\tK. E. Tsiolkovsky Kaluga State Pedagogical University, Department of Botany and Ecology\t\t", +"KLN\ts\tLynn Museum and Art Gallery\t\t", +"KLU\ts\tUniversity of Malaya\t\t", +"KM\ts\tKelowna Museum\t\t", +"KM\ts\tSprava Krkonoaskeho narodniho parku\t\t", +"KM\ts\tMuzeum Przyrodnicze Uniwersytetu Jagiellonskiego\t\t", +"KM\ts\tKotel'nich Museum\t\t", +"KMG\ts\tMcGregor Museum\t\t", +"KMK\ts\tKraevedscheskii Musei Kishineva - Museum of Regional Study\t\t", +"KMK\ts\tKaffarian Museum\t\t", +"KMKV\ts\tKarlovarske muzeum\t\t", +"KMM\tc\tCollection of Marine Microorganisms\t\t", +"KMMA\ts\tRoyal Museum for Central Africa\tRMCA", +"KMMCC\tc\tKorea Marine Microalgae Culture Center\t\t", +"KMN\ts\tAdger Museum of Natural History and Botanical Garden, Botany Department\t\t", +"KMNH\ts\tKitakyushu Museum and Institute of Natural History, Botany Department\t\t", +"KMU\ts\tKarl-Marx-Universitat Leipzeg\t\t", +"KMV\ts\tKunming Municipal Museum\t\t", +"KMVC\ts\tKrajske Muzeum Vychodnich Cech\t\t", +"KNFY\ts\tKlamath National Forest, Resources Department\t\t", +"KNH\th\tKongju National University\t\t", +"KNHM\ts\tThe Educational Science Museum [=Kuwait Natural History Museum?]\t\t", +"KNK\ts\tNorthern Kentucky University, Department of Biological Sciences\t\t", +"KNL\ts\tKinneil Museum\t\t", +"KNOX\ts\tKnox College, Department of Biology\t\t", +"KNP\ts\tSouth African National Parks, Scientific Services\t\t", +"KNU\ts\tKyungpook National University, Biology Department\t\t", +"KNUC\ts\tKangweon National University\t\t", +"KNUH\ts\tKyung-Nam University, Biology Department\t\t", +"KNWR\ts\tKenai National Wildlife Refuge\t\t", +"KNWR:Ento\ts\tKenai National Wildlife Refuge, Entomology Collection", +"KNWR:Herb\ts\tKenai National Wildlife Refuge, Herbarium", +"KNY\ts\tLiterary and Scientific Institution of Kilkenny\t\t", +"KNYA\ts\tSelcuk Ueniversitesi, Biyoloji Boeluemue\t\t", +"KO\ts\tP. J. Safarik University\t\t", +"KOCH\ts\tKochi University, Department of Natural Environmental Science\t\t", +"KOELN\ts\tUniversitaet Koeln, Arbeitsgruppe Geobotanik und Phytotaxonomie\t\t", +"KOLABIC\ts\tKorean Lichen & Allied Bioresource Center\tKoLRI", +"KONL\ts\tBodensee-Naturmuseum\t\t", +"KOPRI\tc\tKorean Polar Research Institute\t\t", +"KOPRI:KCCPM\tc\tKorean Polar Research Institute, KOPRI Culture Collection of Polar Microorganisms", +"KOR\ts\tInstitute of Dendrology\t\t", +"KOS\tc\tCollection of Salmonella Microorganisms\t\t", +"KPABG\ts\tPolar-Alpine Botanical Garden-Institute, Department of Flora and Vegetation\t\t", +"KPBG\ts\tKings Park and Botanic Garden, Botanic Gardens and Parks Authority\t\t", +"KPE\ts\tKyungpook Earth, Kyungpook National University\t\t", +"KPM\ts\tKanagawa Prefectural Museum of Natural History\t\t", +"KPM-NI\ts\tKanagawa Prefectural Museum of Natural History\t\t", +"KPMC\ts\tKalamazoo, Kalamazoo Public Museum\t\t", +"KR\ts\tStaatliches Museum fuer Naturkunde Karlsruhe\t\t", +"KRA\ts\tJagiellonian University\t\t", +"KRAM\ts\tPolish Academy of Sciences, Department of Plant Systematics\t\t", +"KRAS\ts\tKrasnoyarsk State Pedagogical University, Department of Botany\t\t", +"KRB\th\tKebun Raya Bogor\t\t", +"KRDY\ts\tKirkcaldy Museum and Art Gallery\t\t", +"KRF\ts\tV. N. Sukachev Institute of Forest and Wood\t\t", +"KRG\ts\tWestfield Museum\t\t", +"KRIB\ts\tKorea Research Institute of Bioscience and Biotechnology, Plant Diversity Research Center\t\t", +"KRMS\ts\tSternwarte Kremsmuenster, Stift\t\t", +"KRP\tsb\tKebun Raya Purwodadi (Purwodadi Botanic Gardens, Indonesia)\t\t", +"KRSF\ts\tKoronivia Research Station\t\t", +"KRSU\ts\tKrasnoyarsk State University, Department of Biogeocoenology\t\t", +"KSAN\ts\tSouth African National Parks\t\t", +"KSBS\ts\tLawrence, University of Kansas, State Biological Survey of Kansas\t\t", +"KSC\ts\tKansas State University\t\t", +"KSEM\ts\tKansas Snow Entomological Museum\t\t", +"KSHS\ts\tKochi Senior High School\t\t", +"KSK\ts\tFitz Part Museum and Art Gallery\t\t", +"KSO\ts\tTweedside Physical and Antiquarian Society Museum\t\t", +"KSP\ts\tPittsburg State University, Biology Department\t\t", +"KSPI\th\tKostanay State Pedagogical Institute\t\t", +"KSRV\ts\tKhosrov State Reserve\t\t", +"KSTC\ts\tEmporia State University\t\t", +"KSU\ts\tKing Saud University, Botany and Microbiology Department\t\t", +"KSUC\ts\tKansas State University\tKSU", +"KSUP\ts\tKing Saud University\t\t", +"KTC\ts\tPedagogical University, Botany Department\t\t", +"KTG\ts\tKettering and District Naturalists' Society and Field Club\t\t", +"KTU\ts\tUniversity of Silesia, Department of Plant Systematics\t\t", +"KTUH\ts\tKuwait University, Botany and Microbiology Department\t\t", +"KU\ts\tUniversity of Kansas Natural History Museum\tKUMNA,KUVP,UK", +"KU-MACC\tc\tKobe University Macroalgal Culture Collection\t\t", +"KU:H\ts\tUniversity of Kansas Natural History Museum, Herpetology Collection", +"KU:I\ts\tUniversity of Kansas Natural History Museum, Ichthyology collection", +"KU:IP\ts\tUniversity of Kansas Natural History Museum, Invertebrate Paleontology Collection", +"KU:IT\tsb\tUniversity of Kansas Natural History Museum, Ichthyology tissue collection", +"KU:IZ\ts\tUniversity of Kansas Natural History Museum, Invertebrate Zoology Collection", +"KU:M\ts\tUniversity of Kansas Natural History Museum, Mammology Collection", +"KU:O\ts\tUniversity of Kansas Natural History Museum, Ornithology Collection", +"KU:PB\ts\tUniversity of Kansas Natural History Museum, Paleobotany Collection", +"KU:VP\ts\tUniversity of Kansas Natural History Museum, Vertebrate Paleontology Collection", +"KU\ts\tKwangsi University\t\t", +"KUBL\ts\tYoshida College, Biological Laboratory\t\t", +"KUEC\ts\tKyushu University Entomology Collection\t\t", +"KUEL\ts\tKyushu University, Entomology Laboratory\t\t", +"KUFC\tc\tKasetsart University Fungus Collection\t\t", +"KUFF\ts\tDepartment of Forest Biology, Faculty of Forestry at Kasetsart University\t\t", +"KUFS\th\tKabul University\t\t", +"KUH\ts\tUniversity of Karachi, Botany Department\t\t", +"KUHE\ts\tKyoto University, Graduate School of Human and Environmental Studies\t\t", +"KUIC\ts\tKagoshima University\t\t", +"KUKENS\tc\tCentre for Research and Application of Culture Collections of Microorganisms\t\t", +"KUKI\ts\tKurukshetra University\t\t", +"KUM\ts\tResource Management Support Center\t\t", +"KUMA\ts\tKumamoto University, Biology Department\t\t", +"KUMF\ts\tKasetsart University Museum of Fisheries\t\t", +"KUN\ts\tKunming Institute of Botany, Chinese Academy of Sciences\t\t", +"KUNE\ts\tKunming Institute of Ecology, Academia Sinica\t\t", +"KUO\ts\tKuopio Natural History Museum\t\t", +"KURS\ts\tKursk State University, Department of Botany\t\t", +"KUS\ts\tKorea University, Biology Department\t\t", +"KUU\ts\tUniversity of Science and Technology\t\t", +"KUW\th\tKakatiya University\t\t", +"KUZ\ts\tZoological Collection of the Kyoto University\t\t", +"KUZC\ts\tKyushu University, Zoological Collection\t\t", +"KVCH\ts\tKivach Nature Reserve\t\t", +"KW\ts\tNational Academy of Sciences of Ukraine\t\t", +"KWHA\ts\tUkrainian National Academy of Sciences\t\t", +"KWHU\th\tO. V. Fomin Botanical Garden of National Taras Schevchenko University of Kiev\t\t", +"KWNU\ts\tKangwon National University, Biology Department\t\t", +"KWP\ts\tKenelm W. Philip Collection, University of Alaska Museum of the North\t\t", +"KWP:Ento\ts\tKenelm W. Philip Collection, University of Alaska Museum of the North, Lepidoptera collection", +"KY\ts\tUniversity of Kentucky\t\t", +"KYM\ts\tUniversity of Helsinki, Kymenlaakso Society of Naturalists\t\t", +"KYO\ts\tKyoto University, Botany Department\t\t", +"KYUM\ts\tKyushu University Museum\t\t", +"L\tsb\tNational Herbarium of the Netherlands (NHN)\t\t", +"LA\ts\tUniversity of California\t\t", +"LABCC\tc\tLactic acid bacteria culture collection\t\t", +"LAC\ts\tXian Institute of Lacquer\t\t", +"LACM\ts\tNatural History Museum of Los Angeles County\t\t", +"LACM:Crustacea\ts\tNatural History Museum of Los Angeles County, Crustacea Department", +"LACM:Echinoderms\ts\tNatural History Museum of Los Angeles County, Echinoderms Department", +"LACM:Entomology\ts\tNatural History Museum of Los Angeles County, Entomology Department", +"LACM:Herpetology\ts\tNatural History Museum of Los Angeles County, Section of Herpetology", +"LACM:Ichthyology\ts\tNatural History Museum of Los Angeles County, Ichthyology Department", +"LACM:Malacology\ts\tNatural History Museum of Los Angeles County, Malacology Department", +"LACM:Mammalogy\ts\tNatural History Museum of Los Angeles County, Mammalogy Department", +"LACM:Ornithology\ts\tNatural History Museum of Los Angeles County, Ornithology Department", +"LAE\ts\tPapua New Guinea Forest Research Institute\t\t", +"LAF\ts\tUniversity of Louisiana at Lafayette, Biology Department\t\t", +"LAGO\ts\tPacific Northwest Forest and Range Experiment Station\t\t", +"LAGU\ts\tAsociacion Jardin Botanico La Laguna, Urbanizacion Plan de La Laguna\t\t", +"LAH\ts\tUniversity of the Punjab, Botany Department\t\t", +"LAJC\ts\tOtero Junior College, Biology Department\t\t", +"LAM\ts\tNatural History Museum of Los Angeles County, Botanical Studies\t\t", +"LAME\ts\tLake Mead National Recreation Area\t\t", +"LAMU\ts\tLamar University, Biology Department\t\t", +"LAN\ts\tLancing College, Biology Department\t\t", +"LANC\ts\tUniversity of Lancaster, Department of Biological Sciences\t\t", +"LAPC\ts\tPierce College, Life Sciences Department\t\t", +"LAPL\ts\tLapland State Biosphere Reserve\t\t", +"LARRI\ts\tLiving Aquatic Resources Research Institute\t\t", +"LASCA\ts\tThe Los Angeles County Arboretum\t\t", +"LAT\ts\tSaint Vincent College, Biology Department\t\t", +"LATV\ts\tUniversity of Latvia, Laboratory of Botany\t\t", +"LAU\ts\tMusee et Jardins Botaniques Cantonaux\t\t", +"LAUN\ts\tLaunceston College\t\t", +"LAUS\ts\tLaunceston Museum\t\t", +"LAV\ts\tDauntsey's School\t\t", +"LAVO\ts\tLassen Volcanic National Park\t\t", +"LBC\ts\tUniversity of the Philippines at Los Banos\t\t", +"LBG\tc\tInstitute for Agricultural Bacteriology and Fermentation Biology\t\t", +"LBG\ts\tLushan Botanical Garden\t\t", +"LBIT\ts\tLaboratoire de Biologie des Insectes\t\t", +"LBL\ts\tM. Curie-Sklodowska University, Department of Biology and Earth Science\t\t", +"LBLC\ts\tM. Curie-Sklodowska University\t\t", +"LBM\tc\tLaboratorio de Biologia Molecula Depto de Biologia Celular\t\t", +"LBM\ts\tLake Biwa Museum\t\t", +"LBN\ts\tLembaga Biologi Nasional\t\t", +"LBRP\ts\tLaboratorio de Biodiversidade de Recursos Pesqueiros\t\t", +"LBUCH\ts\tLaboratorio de Biologia\t\t", +"LBV\ts\tCENAREST\t\t", +"LC\th\tLewis & Clark College\t\t", +"LCC\tc\tLabatt Culture Collection, Technology Development\t\t", +"LCC\tc\tUniversity of Warmia and Mazury in Olsztyn\t\t", +"LCDI\ts\tLuther College, Biology Department\t\t", +"LCEU\ts\tLane Community College\t\t", +"LCF\ts\tI.N.T.A.\t\t", +"LCFM\ts\tMusee d'Histoire Naturelle\t\t", +"LCG\ts\tLeamington College for Girls\t\t", +"LCH\ts\tLetchworth Museum and Art Gallery\t\t", +"LCM\ts\tUniversidad de Chile, Laboratorio de Citogenetica de Mamiferos\t\t", +"LCMI\ts\tLoyola College\t\t", +"LCN\ts\tLincoln City and County Museum\t\t", +"LCO\ts\tInternational Red Locust Control Organization for Central and Southern Africa\t\t", +"LCP\tc\tFungal Strain Collection, Laboratory of Cryptogamy\t\t", +"LCR\ts\tRatcliffe College\t\t", +"LCS\ts\tInternational Red Locust Control Service\t\t", +"LCU\ts\tCatholic University of America\t\t", +"LCVA\ts\tLakeland College, Environmental Sciences Department\t\t", +"LD\ts\tBotanical Museum, Lunds University\t\t", +"LDL\ts\tLudlow Museum\t\t", +"LDM\ts\tLatvian Natural Histotry Museum, department of Entomology\t\t", +"LDPC\ts\tL. Deharveng, Universite Paul Sabatier\t\t", +"LDS\ts\tUniversity of Leeds\t\t", +"LDSN\ts\tLeeds Naturalists' Club\t\t", +"LDSP\ts\tLeeds Philosophical and Literary Society Museum\t\t", +"LE\tc\tServico de Microbiologia e Imunologia\t\t", +"LE\ts\tV. L. Komarov Botanical Institute\t\t", +"LEA\ts\tUniversity of Lethbridge, Biological Sciences Department\t\t", +"LEB\ts\tUniversidad de Leon, Departamento de Biologia, Botanica\t\t", +"LEB\ts\tEntomological Society of Latvia\t\t", +"LEC\ts\tUniversita degli Studi di Lecce, Dipartimento di Biologia\t\t", +"LECB\ts\tSaint Petersburg State University, Botany Department\t\t", +"LEDLIE\th\tPatricia Ledlie Herbarium\t\t", +"LEF\ts\tEconomic Forestry Institute of Liaoning Province\t\t", +"LEH\th\tLehigh University\t\t", +"LEI\ts\tLeicester Literary and Philosophical Society\t\t", +"LeishCryoBank\tc\tInternational Cryobank of Leishmania\t\t", +"LEIUG\ts\tDepartment of Geology Leicester University\t\t", +"LEMA\ts\tUniversite du Maine\t\t", +"LEMQ\ts\tLyman Entomological Museum, McGill University,\tLEM", +"LEMT\ts\tEge University, Lodos Entomological Museum\t\t", +"LENUD\ts\tLenin University of Dagestan, Botany Department\t\t", +"LEP\ts\tAll-Union Institute for Plant Protection\t\t", +"LES\ts\tLeeds City Museum, Natural History Department\t\t", +"LET\ts\tLetchworth Naturalist's Society\t\t", +"LEUN\ts\tBischoefliches Gymnasium Josephinum\t\t", +"LEV\ts\tMinistry of Agriculture and Fisheries, Plant Protection Centre\t\t", +"LEYN\ts\tLeyton Reference Library\t\t", +"LFBKU\ts\tLaboratory of Fishery Biology\t\t", +"LFCC\ts\tLord Fairfax Community College, Natural Resources Department\t\t", +"LFG\ts\tCentre de Recherche de la Nature, des Forets et du Bois\t\t", +"LFM\ts\tMerseyside County Museums (formerly Liverpool Free Museum)\t\t", +"LG\ts\tUniversite de Liege, Departement de Botanique\t\t", +"LGBH\ts\tLoughborough Public Library\t\t", +"LGEMA\ts\tLaboratorio de Genetica e Evolucao Molecular de Aves, Universidade de Sao Paulo\t\t", +"LGHF\ts\tUniversite de Liege\t\t", +"LGICT\ts\tLaboratoire de Geologie de l'Institut Catholique de Toulouse\t\t", +"LGM\ts\tLeningrad School of Mines\t\t", +"LGM-USP\tc\tDepartamento de Microbiologia Lab. de Genetica de Microrganismos\t\t", +"LGO\ts\tColumbia University\t\t", +"LGPUT\ts\tLaboratory of Geology and Palaeontology\t\t", +"LGU\ts\tLeningrad State University\t\t", +"LHMS\tb\tLeslie Hill Molecular Systematics Laboratory\t\t", +"LHT\ts\tLahti City Museum\t\t", +"LI\ts\tOberoesterreichischen Landesmuseums, Botanische Abteilung\t\t", +"LI:EVAR\ts\tOberoesterreichischen Landesmuseums, Botanische Abteilung, Evertebrata Varia (Invertebrates other than Insects)", +"LI:INS\ts\tOberoesterreichischen Landesmuseums, Botanische Abteilung, Insect collection", +"LI:VERT\ts\tOberoesterreichischen Landesmuseums, Botanische Abteilung, Vertebrate collection", +"LIA\tc\tCryobank of Microorganisms\t\t", +"LIAIP\ts\tLaboratory of Ichthyology\t\t", +"LIB\ts\tUniversity of Liberia\t\t", +"LICPP\ts\tThe Crown Prince's Palace\t\t", +"LIG\ts\tSociedade de Geografia de Lisboa\t\t", +"LIH-UNAM\tc\tCulture Collection of Histoplasma capsulatum Strains from the Fungal Immunology Laboratory of the Department of Microbiology and Parasitology, Faculty of Medicine, UNAM\t\t", +"LIHUBA\ts\tUniversidad de Buenos Aires, Laboratorio de Investigaciones Herpetologicas\t\t", +"LIL\ts\tFundacion Miguel Lillo\t\t", +"LILLE\ts\tInstitut Catholique de Lille, Laboratoire de Biologie Vegetale\t\t", +"LIM\ts\tSeveroceske muzeum\t\t", +"LIMFC\ts\tLimerick Field Club\t\t", +"LIMK\ts\tLimerick Museum\t\t", +"LIMO\th\tUniversite de Limoges\t\t", +"LIN-SB\tc\tLimnological Institute, Siberian Branch, Russian Academy of Sciences\t\t", +"LINC\ts\tLincoln University, Plant Sciences Group\t\t", +"LINCO\th\tLinfield College\t\t", +"LINF\ts\tShanxi Normal University, Biology Department\t\t", +"LINHM\ts\tLong Island Natural History Museum\t\t", +"LINN\ts\tLinnean Society of London\t\t", +"LIP\ts\tUniversite de Lille, Departement de Botanique\t\t", +"LIPIMC\tc\tLembaga Ilmu Pengetahuan Indonesia, Indonesian Institute for Sciences\t\t", +"LIPP\tc\tLeptospirotheque\t\t", +"LIRP\ts\tLaboratorio de Ictiologia, Faculdade de Filosofia\t\t", +"LISC\ts\tInstituto de Investigacao Cientifica Tropical\t\t", +"LISE\ts\tEstacao Agronomica Nacional\t\t", +"LISFA\ts\tInstituto Nacional de Investigacao Agraria, Departamento Ecologia, Recursos Naturais e Ambiente\t\t", +"LISI\ts\tInstituto Superior de Agronomia\t\t", +"LISJC\ts\tJardim-Museu Agricola Tropical\t\t", +"LISM\ts\tMissao de Estudos Agronomicos do Ultramar\t\t", +"LISU\ts\tMuseu Nacional de Historia Natural\t\t", +"LISVA\ts\tMinisterio da Educacao\t\t", +"LIT\ts\tOkresni vlastivedne muzeum\t\t", +"LIUSP\ts\tLaboratorio de Ictiogenetica, Universidade de Sao Paulo\t\t", +"LIV\ts\tLiverpool Museum\t\t", +"LIVC\ts\tLiverpool Botanic Garden\t\t", +"LIVCM\ts\tLiverpool County Museum\t\t", +"LIVNFC\ts\tLiverpool Naturalists' Field Club\t\t", +"LIVU\ts\tHartley Botanical Laboratories\t\t", +"LJC\tc\tColeccion de fitopatogenos de cultivos horticolas\t\t", +"LJF\th\tSlovenian Forestry Institute\t\t", +"LJM\ts\tPrirodoslovni Muzej Slovenije\t\t", +"LJS\th\tScientific Research Centre\t\t", +"LJU\ts\tUniversity of Ljubljana, Botany Department\t\t", +"LKHD\ts\tLakehead University, Biology Department\t\t", +"LL\ts\tUniversity of Texas at Austin, Plant Resources Center\t\t", +"LLANOS\th\tUniversidad de los Llanos\t\t", +"LLC\ts\tOur Lady of the Lake University, Biology Department\t\t", +"LLN\ts\tLincolnshire Naturalists' Union\t\t", +"LLO\ts\tLloyd Library and Museum\t\t", +"LM\ts\tSeccao de Botanica e Ecologia\t\t", +"LMA\ts\tNational Institute of Agronomic Research, Botany Department\t\t", +"LMAD\ts\tLobbecke Museum und Aquazoo\t\t", +"LMC\ts\tInstituto de Investigacao Cientifica de Mozambique\t\t", +"LMCH\tc\tLaboratoire de Microbiologie\t\t", +"LMD\tc\tLaboratorium voor Microbiologie der Landbouwhogeschool\t\t", +"LMG\tc\tBelgian Coordinated Collections of Microorganisms/ LMG Bacteria Collection\tBCCM/LMG", +"LMJ\ts\tLandesmuseum Joanneum Graz\t\t", +"LMJ\ts\tCentro de Investigacao Cientifica Algodoeira, Botanical Department\t\t", +"LMKG\ts\tLandesmuseum fur Karnten\t\t", +"LMND\ts\tLandessammlungen fuer Naturkunde\t\t", +"LMNH\ts\tMuseum d'Histoire naturelle\t\t", +"LMO\th\tLandesmuseum Natur und Mensch\t\t", +"LMRZ\ts\tLivingstone Museum\t\t", +"LMS\tc\tCarolina Biological Supply Company\t\t", +"LMSZ\ts\tLatvian University, Museum of Systemic Zoology\t\t", +"LMU\ts\tEduardo Mondlane University, Department of Biological Sciences\t\t", +"LMZG\ts\tLocal Museum\t\t", +"LNAF\ts\tLiaoning Academy of Forestry\t\t", +"LNAU\th\tLuhansk National Agrarian University\t\t", +"LNCM\ts\tLiaoning College of Traditional Chinese Medicine\t\t", +"LNCN\th\tLincoln Memorial University\t\t", +"LNHS\ts\tLondon Natural History Society\t\t", +"LNK\ts\tLandessammlungen fuer Naturkunde\t\t", +"LNKD\ts\tLandessammlung fuer Naturkunde\t\t", +"LNMD\ts\tLandessammlungen fuer Naturkunde\t\t", +"LNMO\ts\tOldenburg, Landesmuseum Natur und Mensch\t\t", +"LNNU\ts\tLiaoning Normal University, Biology Department\t\t", +"LNPV\tc\t Laboratoire National de la Protection des Vegetaux\t\t", +"LO\ts\tType Collection\t\t", +"LOB\ts\tCalifornia State University, Biological Sciences Department\t\t", +"LOC\ts\tOccidental College, Biology Department\t\t", +"LOCK\tc\tCentre of Industrial Microorganisms Collection\t\t", +"LOD\ts\tLodz University, Department of Geobotany and Plant Ecology\t\t", +"LOJA\ts\tUniversidad Nacional de Loja, Departamento de Botanica y Ecologia\t\t", +"LOMA\ts\tLa Sierra University, Biology Department\t\t", +"LON\ts\tLembaga Oseanologie Nasional\t\t", +"LOU\ts\tC.I.T.A.-Xunta de Galicia\t\t", +"LP\ts\tMuseo de La Plata, Herbario\t\t", +"LP\ts\tLaboratory of Palaeontology\t\t", +"LPA\ts\tJardin Botanico Canario Viera y Clavijo\t\t", +"LPAG\ts\tUniversidad Nacional de La Plata, Area de Botanica\t\t", +"LPB\ts\tHerbario Nacional de Bolivia\t\t", +"LPC\th\tMuseo de La Plata\t\t", +"LPD\ts\tLaboratorio de Botanica de la Direccion de Agricultura\t\t", +"LPFU\ts\tLehrstuhl fur Palaontologie\t\t", +"LPL\ts\tThe University\t\t", +"LPN\ts\tLittlehampton Museum\t\t", +"LPS\ts\tUniversidad Nacional de La Plata, Instituto de Botanica Carlos Spegazzini\t\t", +"LPSC\tc\tLa Plata Spegazzini Collection\t\t", +"LPSP\ts\tLumus Pond State Park, Whale Wallow Nature Center\t\t", +"LPUB\ts\tLaboratorul de Paleontologie\t\t", +"LPUP\ts\tLaboratoire de Parasitologie\t\t", +"LPVM\ts\tLaboratoire de Paleontologie des Vertebres et de Paleontologie\t\t", +"LPVPH\ts\tLaboratoire de Paleontologie des Vertebres et de Paleontologie Humaine\t\t", +"LR\ts\tMuseum d'Histoire Naturelle\t\t", +"LRL\ts\tHistoric Society of Lancashire and Cheshire\t\t", +"LRS\ts\tAgriculture Research Center, Land Resource Sciences Section\t\t", +"LRTE\ts\tLa Retraite (Convent School)\t\t", +"LRU\ts\tUniversity of Arkansas at Little Rock, Biology Department\t\t", +"LS\ts\tColegio de La Salle\t\t", +"LS\ts\tLinnean Society of London\tLSUK", +"LSA\ts\tLytham St. Annes Public Library\t\t", +"LSAM\ts\tLouisiana State Arthropod Museum\t\t", +"LSC\ts\tLyndon State College, Natural Sciences Department\t\t", +"LSCR\ts\tOrganization for Tropical Studies, La Selva Biological Station\t\t", +"LSDC\ts\tLiangshan Institute for Drug Control\t\t", +"LSHB\tc\tBiochemistry Department\t\t", +"LSHI\ts\tUniversite Nationale du Zaire\t\t", +"LSN\ts\tLord Wandsworth College Natural History Museum\t\t", +"LSP\ts\tLake Superior Provincial Park\t\t", +"LSR\ts\tLeicestershire Museums Service\t\t", +"LSRFC\ts\tLeicestershire Flora Committee\t\t", +"LSSC\ts\tLake Superior State College\t\t", +"LSTM\tc\tDepartment of Parasitology\t\t", +"LSU\ts\tLouisiana State University, Biological Sciences Department\t\t", +"LSUHC\ts\tLa Sierra University, Herpetological Collection\t\t", +"LSUM\ts\tLouisiana State University, Biological Sciences Department\t\t", +"LSUMZ\ts\tLouisiana State University, Musuem of Zoology\tLSUMNS", +"LSUMZ:FrozenTissue\ts\tLouisiana State University, Musuem of Zoology, Frozen Tissue Collection", +"LSUMZ:Herpetology\ts\tLouisiana State University, Musuem of Zoology, Herpetology Collection", +"LSUMZ:Ichthyology\ts\tLouisiana State University, Musuem of Zoology, Ichthyology Collection", +"LSUMZ:Mammalogy\ts\tLouisiana State University, Musuem of Zoology, Mammal Collection", +"LSUMZ:Ornithology\ts\tLouisiana State University, Musuem of Zoology, Bird Collection", +"LSUS\ts\tMuseum of Life Sciences, Louisiana State University\t\t", +"LT\ts\tUniversite de Montreal\t\t", +"LTB\ts\tLa Trobe University, Botany Department\t\t", +"LTCC-IOC\tc\tLeishmania Type Culture Collection\t\t", +"LTH\ts\tMuseum of Louth Naturalists' Antiquity and Literary Society\t\t", +"LTHP\ts\tLouth Public Library\t\t", +"LTI\tc\tCryobank of Microorganisms-Destructors\t\t", +"LTM\ts\tTekovske muzeum\t\t", +"LTN\ts\tLuton Museum and Art Gallery\t\t", +"LTR\ts\tUniversity of Leicester, Biology Department\t\t", +"LTU\ts\tLouisiana Tech University\t\t", +"LU\ts\tLingnan University\t\t", +"LU\ts\tSt. Petersburg University\t\t", +"LUA\ts\tInstituto de Investigacao Agronomica\t\t", +"LUAI\ts\tex-Centro Nacional de Investigacao Cientifica (CNIC)\t\t", +"LUB\ts\tNaturhistorisches Museum zu Luebeck\t\t", +"LUBA\ts\tInstituto Superior de Ciencias da Educacao\t\t", +"LUBEE\tb\tLubee Bat Conservancy\t\t", +"LUCAS\ts\tFrancesc de Lucas i Alcover\t\t", +"LUCCA\ts\tComune di Lucca\t\t", +"LUCH\ts\tMusee du Pays de Luchon\t\t", +"LUD\ts\tLudlow Natural History Society\t\t", +"LUG\ts\tMuseo cantonale di storia naturale\t\t", +"LUGO\ts\tUniversidad de Satniago de Compostela, Departamento de Produccion Vegetal\t\t", +"LUH\ts\tUniversity of Lagos, Department of Botany\t\t", +"LUH\tc\tLeiden University Medical Center\t\t", +"LUKI\th\tInstitut National pour l'Etude et la Recherche Agronomiques\t\t", +"LUNZ\ts\tLincoln University Entomology Research Museum\t\t", +"LUQ\ts\tLaval University\t\t", +"LUS\ts\tLushan Botanical Garden\t\t", +"LUSC\th\tUniversidade do Estado de Santa Catarina\t\t", +"LUW\ts\tLandbouwuniversiteit Wageningen, Department of Entomology\t\t", +"LUX\ts\tMusee national d'histoire naturelle\t\t", +"LV\ts\tCatholic University of Leuven, Laboratory of Plant Systematics\t\t", +"LVNP\ts\tLassen Volcanic National Park\t\t", +"LVP-GSC\ts\tLaboratory of Vertebrate Paleontology\t\t", +"LW\ts\tIvan Franko National University of Lviv, Botany Department\t\t", +"LWA\ts\tAgricultural Experiment Station\t\t", +"LWD\ts\tMuseum Dzieduszyckich\t\t", +"LWG\ts\tNational Botanical Research Institute\t\t", +"LWI\th\tCentre de Recherche en Sciences Naturelles (CRSN/Lwiro)\t\t", +"LWKS\ts\tInstitute of Ecology of the Carpathians\t\t", +"LWL\ts\tLWL-Museum fuer Naturkunde\t\t", +"LWL:DNA\tb\tLWL-Museum fuer Naturkunde, LWL-DNA- und Gewebearchiv", +"LWS\ts\tMuseum of Natural History, Lviv\t\t", +"LWSM\ts\tLewes Museum, Ann of Cleves House\t\t", +"LWU\ts\tUniversity of Lucknow, Botany Department\t\t", +"LY\tsc\tUniversite Claude Bernard\t\t", +"LYAC\ts\tLaiyang Agricultural College, Department of Basic Courses\t\t", +"LYCC\tc\tLallemand Yeast Culture Collection\t\t", +"LycoCC\tc\tThe Lycoming College Culture Collection\t\t", +"LYD\ts\tMpumalanga Parks Board\t\t", +"LYJB\ts\tJardin Botanique de Lyon\t\t", +"LYN\ts\tLynchburg College, Biology Department\t\t", +"LZ\ts\tUniversitaet Leipzig\t\t", +"LZAH\ts\tLanzhou Institute of Animal Science, Chinese Academy of Agricultural Sciences\t\t", +"LZD\ts\tLanzhou Institute of Desert Research, Academia Sinica\t\t", +"LZFD\ts\tLaboratoire Zoologique\t\t", +"LZLP\ts\tUniversidade de Lisboa\t\t", +"LZU\ts\tLanzhou University\t\t", +"LZUH\ts\tLaboratoire de Zoologie, Universite de Hanoi\t\t", +"M\ts\tBotanische Staatssammlung Muenchen\t\t", +"MA\ts\tReal Jardin Botanico\t\t", +"MA:Algae\ts\tReal Jardin Botanico, Algae collection", +"MA:Fungi\ts\tReal Jardin Botanico, Fungi collection", +"MA:FunHist\ts\tReal Jardin Botanico, Historical fungi colleciton", +"MA:Hepat\ts\tReal Jardin Botanico, Liverwort collection", +"MA:Lichen\ts\tReal Jardin Botanico, Lichen collection", +"MA:Musci\ts\tReal Jardin Botanico, Bryophyte collection", +"MAA\ts\tEscuela Tecnica Superior de Ingenieros Agronomos, Departamento de Produccion Vegetal\t\t", +"MAAS\ts\tNatuurhistorisch Museum Maastricht, Botany Department\t\t", +"MAC\ts\tInstituto do Meio Ambiente\t\t", +"MAC-APU\ts\tMinisterio de Agricultura y Cria\t\t", +"MAC-PAY\ts\tMinisterio de Agricultura y Cria\t\t", +"MACA\ts\tParque da Reserva de Siac Pai van Coloane Island\t\t", +"MACB\ts\tUniversidad Complutense, Departamento de Biologia Vegetal 1\t\t", +"MACF\ts\tCalifornia State University, Biological Science Department\t\t", +"MACLPI\ts\tMinisterio de Agricultura y Cria, Seccion de Pesca Interior y Piscicultura\t\t", +"MACN\ts\tMuseo Argentino de Ciencias Naturales Bernardino Rivadavia\t\t", +"MACN-RN\ts\tMuseo Argentino de Cicencis Naturales, Coleccion Rio Negro\t\t", +"MACNCH\ts\tMuseo Argentino de Ciencias Naturales\t\t", +"MACO\ts\tMarlborough College, Biology Department\t\t", +"MAD\ts\tMadras Museum\t\t", +"MAD\ts\tForest Products Laboratory\t\t", +"MADJ\ts\tJardim Botanico da Madeira\t\t", +"MADM\ts\tMuseu Municipal do Funchal\t\t", +"MADS\ts\tMuseu de Historia Natural do Seminario do Funchal\t\t", +"MAF\ts\tUniversidad Complutense, Departamento de Biologia Vegetal II\t\t", +"MAFF\tc\tMAFF Genebank, Ministry of Agriculture Forestry and Fisheries\t\t", +"MAFF\ts\tColo-i-Suva Silvicultural Station\t\t", +"MAFI\ts\tMagyar Allami Foeldtani Intezet, Budapest - Hungarian Geological Survey\t\t", +"MAFST\ts\tInstituto Forestal de la Moncloa\t\t", +"MAG\ts\tInstitute of Biological Problems of the North\t\t", +"MAGB\ts\tNational Museum and Art Gallery, Gaberone\t\t", +"MAGD\ts\tNorthern Territory Museum of Arts and Sciences\t\t", +"MAGNT\ts\tMuseums and Art Galleries of the Northern Territory\tNTM", +"MAGNT:A\ts\tMuseums and Art Galleries of the Northern Territory, Arachnid Collection", +"MAGNT:C\ts\tMuseums and Art Galleries of the Northern Territory, Cnidarian Collection", +"MAGNT:Cr\ts\tMuseums and Art Galleries of the Northern Territory, Crustacean Collection", +"MAGNT:D\ts\tMuseums and Art Galleries of the Northern Territory, Minor Invertebrate Collection", +"MAGNT:E\ts\tMuseums and Art Galleries of the Northern Territory, Ascidian Collection", +"MAGNT:G\ts\tMuseums and Art Galleries of the Northern Territory, Bryozoan Collection", +"MAGNT:I\ts\tMuseums and Art Galleries of the Northern Territory, Insect Collection", +"MAGNT:M\ts\tMuseums and Art Galleries of the Northern Territory, Myriapod Collection", +"MAGNT:N\ts\tMuseums and Art Galleries of the Northern Territory, Pycnogonid Collection", +"MAGNT:P\ts\tMuseums and Art Galleries of the Northern Territory, Malacology Collection", +"MAGNT:Q\ts\tMuseums and Art Galleries of the Northern Territory, Echinoderm Collection", +"MAGNT:R\ts\tMuseums and Art Galleries of the Northern Territory, Herpetology Collection", +"MAGNT:S\ts\tMuseums and Art Galleries of the Northern Territory, Fish Collection", +"MAGNT:T\ts\tMuseums and Art Galleries of the Northern Territory, Bird Collection", +"MAGNT:U\ts\tMuseums and Art Galleries of the Northern Territory, Mammal Collection", +"MAGNT:W\ts\tMuseums and Art Galleries of the Northern Territory, Annelid Collection", +"MAGNT:Z\ts\tMuseums and Art Galleries of the Northern Territory, Poriferan Collection", +"MAH\ts\tDepartment of Agricultural Research\t\t", +"MAIA\ts\tInstituto Nacional de Investigaciones Agrarias, Departamento de Ecologia\t\t", +"MAIC\ts\tMediterranean Agronomic Institute of Chania, Department of Natural Products\t\t", +"MAINE\ts\tUniversity of Maine, Department of Biological Sciences\t\t", +"MAIS\ts\tInstitut d'Elevage et de Medecine Veterinaire des Pays Tropicaux, Departement de Botanique\t\t", +"MAK\ts\tTokyo Metropolitan University\t\t", +"MAKAR\ts\tInstitut Planina i More\t\t", +"MAKFUNGI\ts\tFungi Macedonici\t\t", +"MAL\ts\tBotanic Gardens of Malawi\t\t", +"MALA\ts\tMalaspina University, Biology Department\t\t", +"MALC\ts\tMuseu Municipal de la Vila d'Alcover\t\t", +"MALS\ts\tManti-LaSal National Forest\t\t", +"MAMU\ts\tUniversity of Sydney, Macleay Museum\t\t", +"MAN\ts\tUniversitas Cenderawasih\t\t", +"MANCH\ts\tUniversity of Manchester\t\t", +"MAND\ts\tAgricultural College and Research Institute\t\t", +"MANK\ts\tMinnesota State University-Mankato, Department of Biological Sciences\t\t", +"MAO\tc\tMircen Afrique Ouest\t\t", +"MAPA\ts\tMuseu Anchieta Porto Alegra\t\t", +"MAPR\ts\tUniversity of Puerto Rico, Mayagueez Campus, Biology Department\t\t", +"MAR\tc\tGrasslands Rhizobium Collection\t\t", +"MARDI\th\tMalaysian Agricultural Research and Development Institute\t\t", +"MARE\ts\tMarmara University, Department of Pharmaceutical Botany\t\t", +"MARI\th\tMari State University\t\t", +"MARK\th\tCadi Ayyad University\t\t", +"MARO\ts\tMarylhurst College\t\t", +"MARS\ts\tUniversite de Provence Centre St-Charles, case 4\t\t", +"MARSSJ\ts\tUniversite Paul Cezanne\t\t", +"MARY\ts\tUniversity of Maryland\t\t", +"MASE\ts\tMaseru Experiment Station\t\t", +"MASS\ts\tUniversity of Massachusetts, Biology Department\t\t", +"MATSU\ts\tEhime University, Forestry Department\t\t", +"MAU\ts\tMauritius Sugar Industry Research Institute\t\t", +"MAUAM\th\tUniversidad Autonoma de Madrid\t\t", +"MAY\ts\tAdygean State University, Department of Botany\t\t", +"MB\ts\tMuseum of Natural History of Humboldt-University\t\t", +"MB\ts\tPhilipps-Universitaet, Spezielle Botanik\t\t", +"MB\ts\tUniversidade de Lisboa, Museu Bocage\t\t", +"MBA\ts\tEnvironmental Protection Agency\t\t", +"MBAB\ts\tMuseo Biblioteca Archivio\t\t", +"MBAC\ts\tMuseo del Dipartimento di Biologia Animale dell'Universita\t\t", +"MBAP\ts\tMuseo del Dipartimento di Biologia Animale dell'Universita\t\t", +"MBBJ\ts\tMuseum Zoologicum Bogoriense, Entomology Collection\t\t", +"MBC\tsb\tMontgomery Botanical Center\tMBC", +"MBCG\ts\tMuseo di Scienze Naturali \"Enrico Caffi\"\t\t", +"MBCSC\ts\tMarine Biodiversity Collection of South China Sea, Chinese Academy of Sciences\t\t", +"MBCSC:Fish\ts\tMarine Biodiversity Collection of South China Sea, Chinese Academy of Sciences, Fish Collection", +"Mbg\ts\tFachberich Geowissenschaften\t\t", +"MBH\ts\tMarlborough College\t\t", +"MBIC\tc\tMarine Biotechnology Institute Culture Collection\t\t", +"MBK\ts\tKochi Prefectural Makino Botanical Garden, Botany Department\t\t", +"MBL\ts\tMuseu Nacional de Historia Natural\t\t", +"MBLUZ\ts\tMuseo de Biologia de la Universidad del Zulia\t\t", +"MBM\ts\tMuseu Botanico Municipal\t\t", +"MBM\ts\tSan Jose State University, Museum of Birds and Mammals\t\t", +"MBM\ts\tMarjorie Barrick Museum\t\t", +"MBML\ts\tMuseu de Biologia Mello Leitao\t\t", +"MBMU\tc\tInstitute of Molecular Biology and Genetics (IMBG), Mahidol University\t\t", +"MBR\ts\tMuseo Argention de Ciencias Naturales \"Bernardino Rivadavia\"\t\t", +"MBS\ts\tManchester Banksian Society\t\t", +"MBSL\ts\tRoyal Medico-Botanical Society\t\t", +"MBSN\ts\tMuseo Brembano di Scienze Naturali\t\t", +"MBUCV\ts\tMuseo de Biologia de la Universidad Central de Venezuela\tCBFC,MBUC", +"MBZH\ts\tMuseo y Biblioteca de la Zoologia\t\t", +"MC\ts\tMuseo de Cipolleti\t\t", +"MCA\ts\tMuhlenberg College, Biology Department\t\t", +"MCAS\ts\tMuseo Civico Archeologico e di Scienze Naturali \"F. Eusebio\"\t\t", +"MCBR\ts\tMuseo Civico \"Baldassarre Romano\"\t\t", +"MCC\tc\tMicrobial Culture Collection\t\t", +"MCC-UPLB\tc\tMicrobial Culture Collection\t\t", +"MCCB\ts\tMuseo Civico \"Craveri\"\t\t", +"MCCC\tc\tMarine Culture Collection of China\t\t", +"MCCI\ts\tMuseo Civico di Storia Natural de Carmognola\t\t", +"MCCM\tc\tMedical Culture Collection Marburg\t\t", +"MCCM\ts\tMadras Christian College\t\t", +"MCD\ts\tMuzeul Civilizatiei Dacice si Romane Deva\t\t", +"MCDNL\th\tMcDaniel College\t\t", +"MCES\ts\tMuseum of the Center for Entomological Studies\t\t", +"MCF\th\tSts. Cyril and Methodius University\t\t", +"MCF-PVPH\ts\tMuseo Carmen Funes\t\t", +"MCFB\ts\tMuseo de la Cienica Fundacion\t\t", +"MCFM\ts\tMuseo Civico \"Francesco Mina Palumbo\"\t\t", +"MCFS\ts\tMuseo Civico di Storia Naturale, Ferrara\t\t", +"MCG\ts\tMuseo Civico DI Storia Naturale 'Giacomo Doria'\t\t", +"McGMK\ts\tMcGregor Memorial Museum\t\t", +"MCGS\ts\tMuseo Civico \"Giuseppe Scarabelli\"\t\t", +"MCITM\tc\tBacterial Culture Collection\t\t", +"MCIZ\ts\tMuseo Cambria, Istituto di Zoologia dell'Universita\t\t", +"MCJ\ts\tMissouri Southern State College, Biology Department\t\t", +"MCLSBB\ts\tMuseo Colegio La Salle Bonanova de Barcelona\t\t", +"MCM(CMFRI)\ts\tReference Collection\t\t", +"MCM\ts\tHamilton College, McMaster University, Biology Department\t\t", +"MCM\ts\tInstitut de Paleontologie, Museum d'Histoire naturelle\t\t", +"MCM\tc\tMACS Collection of Microorganisms\t\t", +"MCM\ts\tMuseu Carlos Machado\t\t", +"MCMC\ts\tMuseo de Historia Natural de la Ciudad de Mexico\t\t", +"McMJ\ts\tMc Master University\t\t", +"MCMS\ts\tMuseo Civico di Storia Naturale, Morgegno\t\t", +"MCN\ts\tMcNeese State University, Biology Department\t\t", +"MCNA\ts\tMuseo de Ciencias naturals de Alava\t\t", +"MCNC\ts\tMuseo de Ciencias Naturales\t\t", +"MCNG\ts\tMuseo de Ciencias Naturales de la UNELLEZ en Guanare\t\t", +"MCNPV\ts\tFundacao Zoobotanica do Rio Grande do Sul\tMCN", +"MCNS\ts\tUniversidad Nacional de Salta, Facultad de Ciencias Naturales\t\t", +"MCNV\ts\tMuseo Civico di Storia Naturale, Venice\t\t", +"MCNZ\ts\tPorto Alegre, Museu de Ciencias Naturais da Fundacao Zoo-Botanica do Rio Grande do Sul\t\t", +"MCP\ts\tPontificia Universidade Catolica do Rio Grande do Sul\t\t", +"MCP\ts\tMassachusetts College of Pharmacy and Allied Health Sciences, Biological Sciences Department\t\t", +"MCPM\ts\tMilwaukee City Public Museum\t\t", +"MCPPV\ts\tMuseu de Ciencias e Tecnologia\tMCP", +"MCPUCRGS\ts\tMuseu de Ciencias da Pontificia Universidade Catolica do Rio Grande do Sul\t\t", +"MCR\ts\tManchester Literary and Philosophical Society\t\t", +"MCRA\ts\tSezione Archeologia, Storia e Scienze Naturali\t\t", +"MCRBS\ts\tManchester Botanical and Horticultural Society\t\t", +"MCSB\ts\tMuseo Civico di Scienze Naturali\t\t", +"MCSC\ts\tColorado Springs, May Natural History Museum\t\t", +"MCSF\ts\tMuseo Civico di Scienze Naturali\t\t", +"MCSG\ts\tMuseo Civico di Storia Naturale, Grosseto\t\t", +"MCSN\ts\tMuseo Civico di Storia Naturale \"Giacomo Doria\"\t\t", +"MCSN\ts\tMuseo Civico di Storia Naturale, Verona\t\t", +"MCSNC\ts\tMuseo Civico di Storia Naturale, Carmagnola\tMSNC", +"MCSNIO\ts\tMuseo Civico di Scienze Naturali di Induno Olona\t\t", +"MCST\ts\tMuseo Civico di Storia Naturale, Trieste\t\t", +"MCT\ts\tMichigan Technological University, Biological Sciences Department\t\t", +"MCTC\ts\tMichigan Technological University, Biological Sciences Department\t\t", +"MCTF\ts\tMichigan Technological University\t\t", +"MCTP\ts\tMuseu de Ciencias\t\t", +"MCVE\ts\tMuseo di Storia Naturale di Venezia\t\t", +"MCVM\ts\tMuseo Civico, Villa Mirabello\t\t", +"MCW\ts\tMilton College, Biology Department\t\t", +"MCZ\ts\tMuseum of Comparative Zoology, Harvard University\tMCZC", +"MCZ:Cryo\ts\tMuseum of Comparative Zoology, Harvard University, Cryogenic Collection", +"MCZ:Ent\ts\tMuseum of Comparative Zoology, Harvard University, Entomology Collection", +"MCZ:Herp\ts\tMuseum of Comparative Zoology, Harvard University, Herpetology Collection", +"MCZ:Ich\ts\tMuseum of Comparative Zoology, Harvard University, Ichthyology Collection", +"MCZ:IP\ts\tMuseum of Comparative Zoology, Harvard University, Invertebrate Paleontology Collection", +"MCZ:IZ\ts\tMuseum of Comparative Zoology, Harvard University, Invertebrate Zoology Collection", +"MCZ:Mala\ts\tMuseum of Comparative Zoology, Harvard University, Malacology Collection", +"MCZ:Mamm\ts\tMuseum of Comparative Zoology, Harvard University, Mammalogy Collection", +"MCZ:Orn\ts\tMuseum of Comparative Zoology, Harvard University, Ornithology Collection", +"MCZR\ts\tMuseo Civico di Zoologia\t\t", +"MD\ts\tMuseu Regional do Dundo\t\t", +"MD\ts\tMuseum Donaueschingen\t\t", +"MDC\tc\tMicrobial Depository Center (National Microbial Culture Collection of the Republic of Armenia)\t\t", +"MDE\ts\tMusee des Dinosaures in Esperaza\t\t", +"MDFW\ts\tMassachusetts Division of Fisheries and Wildlife\t\t", +"MDH\ts\tDorman Museum\t\t", +"MDH\tc\tMichigan Department of Health\t\t", +"MDI\th\tMalaysian Agricultural Research and Development Institute\t\t", +"MDKY\ts\tMorehead State University, Biological and Environmental Sciences Department\t\t", +"MDLA\ts\tMuseu do Dundo\t\t", +"MDM\ts\tMifune Dinosaur Museum\t\t", +"MDNR\ts\tManitoba Conservation\t\t", +"MDP\ts\tMuseum de Poligny\t\t", +"MDRG\ts\tMuseum voor Dierkunde, Rijksuniversiteit\t\t", +"MDTN\ts\tMiddleton Botanical Society\t\t", +"MDUG\ts\tUniversidad Guanajuato, Museo Alfredo Duges\t\t", +"MDZAU\ts\tMuseum Deptartment of Zoology\t\t", +"MECB\ts\tUniversidade Federal de Pelotas, Museu Entomologico Ceslau Biezanko\t\t", +"MECG\ts\tMedical Entomology Collection Gallery\t\t", +"MECN\ts\tMuseo Ecuadoriano de Ciencias Naturales\tDHMECN", +"MEDEL\ts\tUniversidad Nacional de Colombia - Sede de Medellin, Departamento de Biologia\t\t", +"MEFLG\ts\tMuseo Entomologico Francisco Luis Gallego\t\t", +"MEL\ts\tRoyal Botanic Gardens Victoria\t\t", +"MELG\ts\tGeology Department, University of Melbourne\t\t", +"MELIT\th\tBogdan Khmel'nysckyi State Pedagogical University of Melitopol'\t\t", +"MELU\ts\tUniversity of Melbourne\t\t", +"MEM\ts\tUniversity of Memphis, Biology Department\t\t", +"MEMO\ts\tInstituto Tecnologico y de Estudios Superiores de Monterrey, Departamento de Recursos Naturales\t\t", +"MEN\ts\tUNCuyo, Catedra de Botanica Agricola, Departamento de Ciencias Biologicas\t\t", +"MEPAN\ts\tMuseum of Evolution, Polish Academy of Sciences\t\t", +"MER\ts\tUniversidad de Los Andes\t\t", +"MERC\ts\tUniversidad de Los Andes, Centro Jardin Botanico\t\t", +"MERCA\th\tMercer Arboretum and Botanic Gardens\t\t", +"MERF\ts\tUniversidad de Los Andes\t\t", +"MERL\ts\tInstituto Argentino de Investigaciones de las Zonas Aridas (CRICYTME)\t\t", +"MESA\ts\tMesa State College, Biology Department\t\t", +"MEUC\ts\tUniversidad de Chile\t\t", +"MEX\ts\tMuseo de Historia Natural de la Ciudad de Mexico\t\t", +"MEXU\ts\tHerbario Nacional de Mexico, Universidad Nacional Autonoma de Mexico\tIBUNAM:MEXU", +"MFA\ts\tMuseo Provincial de Ciencias Naturales Florentino Ameghino, Seccion Botanica\t\t", +"MFA-ZV-M\ts\tMuseo Florentino Ameghino, Coleccion de Mastozoologia (Argentina)\t\t", +"MFAP\ts\tArchaeology and Palaeontology\t\t", +"MFB\ts\tSouthern Research Station\t\t", +"MFC\tc\tMatsushima Fungus Collection\t\t", +"MFGC\tc\tMargot Forde Germplasm Centre, AgResearch GrasslandsWar\t\t", +"MFLB\ts\tMarine Fisheries Laboratory\t\t", +"MFLU\tsc\tMae Fah Laung University Herbarium\tMFLU", +"MFLUCC\tc\tMae Fah Luang University Culture Collection\t\t", +"MfN\ts\tMuseum fur Naturkunde\t\t", +"MFNB\ts\tMuseo Friulano di Storia Naturale\t\t", +"MFP\ts\tMuseo Felipe Poey\t\t", +"MFRU\ts\tMalawi Fisheries Research Unit\t\t", +"MFS\ts\tMuseo dei Fisiocritici\t\t", +"MFSN\ts\tMuseo Friulano di Storia Naturale of Udine\t\t", +"MFU\ts\tMuseo Friulano di Storia Naturale\t\t", +"MFUM\ts\tMuseum of Ferdowsi University of Mashhad\t\t", +"MFUW\ts\tChinzombo Research Station, Chinzombo Wildlife Research Station\t\t", +"MFW\ts\tMuseum Freriks\t\t", +"MG\ts\tMuseu Paraense Emilio Goeldi, Departamento de Botanica\t\t", +"MG\ts\tMuseum of Zoology\t\t", +"MGA\ts\tInstituto Pedagogico de Varones\t\t", +"MGAB\ts\tMuzeul de Istorie Naturala \"Grigore Antipa\"\t\t", +"MGAP\ts\tMuseu Anchieta\t\t", +"MGB\ts\tMuseo de Geologia (del Seminario Diocesano) de Barcelona\t\t", +"MGC\ts\tUniversidad de Malaga, Departamento de Biologia Vegetal\t\t", +"MGDL\ts\tMuseum d'Histoire Naturalle du Grand-Duchy de Luxembourg\t\t", +"MGF\ts\tMuseum George Frey\t\t", +"MGFT\ts\tMuseum G. Frey\t\t", +"MGH\ts\tMuseum Godeffroy\t\t", +"MGHF\ts\tMuseo Geologico H. Fuenzalida\t\t", +"MGHNL\ts\tMusee Guimet d'Histoire Naturelle de Lyon\t\t", +"MGHSJ\ts\tMatuyama Girl's High School\t\t", +"MGI\ts\tGeological Institute of the Mongolian Academy of Sciences\t\t", +"MGL\ts\tMusee Geologique de Lausanne\t\t", +"MGR\ts\tUniversity of Michigan\t\t", +"MGRI\ts\tMoscow Geological Prospecting Institute\t\t", +"MGS\ts\tUpper Silesian Museum, Department of Natural History\t\t", +"MGSI\ts\tMuseum of the Geological Survey of Iran\t\t", +"MGSP\ts\tMuseum of the Geological Survey of Portugal\t\t", +"MGUG\ts\tMuseum fuer Geologie und Palaontologie der Georg-August-Universitat\t\t", +"MGUH\ts\tMuseum Geologicum Universitatis Hafniensis\t\t", +"MGUP\ts\tMuseo Geologico della Universita Pisa\t\t", +"MGUV\ts\tMuseo del Departamento de Geologia, Universidad de Valencia\t\t", +"MGUWR\ts\tInstitute of Geological Sciences, University of Wroclaw\t\t", +"MH\ts\tNaturhistorisches Museum, Basel\t\t", +"MH\ts\tTamil Nadu Agricultural University\t\t", +"MHA\ts\tMain Botanical Garden of the Russian Academy of Sciences\t\t", +"MHES\th\tMuseo de Historia Natural de El Salvador\t\t", +"MHH\tc\tInstitute of Virology\t\t", +"MHL\ts\tMildenhall and District Museum\t\t", +"MHM\ts\tMalham Tarn Field Centre\t\t", +"MHMN\ts\tMuseu Historic Municipal de Novelda\t\t", +"MHNA\ts\tMuseum d'Histoire Naturelle d'Autun\t\t", +"MHNB\ts\tMuseum d'Histoire Naturelle de Bale\t\t", +"MHNC\ts\tMusee d'Histoire Naturelle - La Chaux-de-Fonds\t\t", +"MHNC\ts\tMuseo de Historia Natural de Concepcion (Chile)\t\t", +"MHNCI\ts\tMuseu de Historia Natural Capao de Imbuia (Brazil)\t\t", +"MHNCSJ\ts\tMuseo de Historia Natural\t\t", +"MHNES\ts\tMuseo de Historia Natural de El Salvador\t\t", +"MHNG\ts\tNatural History Museum of Geneva\t\t", +"MHNG:Herp\ts\tNatural History Museum of Geneva, Herpetology collection", +"MHNG:Invertebrate\ts\tNatural History Museum of Geneva, Invertebrate collection", +"MHNH\ts\tMuseo Nacional de Historia Natural de Cuba\tMNHNCU", +"MHNI\ts\tMuseu Hist. Naturales Universidade Federal Minas Gerais\t\t", +"MHNJP\ts\tUniversidad Nacional Mayor de San Marcos\t\t", +"MHNL\ts\tMusee Guimet d'Histoire Naturelle de Lyon\t\t", +"MHNLR\ts\tMuseum d'Histoire Naturelle\tMHNR", +"MHNLS\ts\tColeccion de Mastozoologia, Museo de Historia Natural de La Salle\t\t", +"MHNM\ts\tMuseo Nacional de Historia Natural y Antropologia\t\t", +"MHNN\ts\tNeuchatel Musee d'Histoire Naturel\t\t", +"MHNN\ts\tMusee d'Histoire Naturalle\t\t", +"MHNNICE\ts\tMueusm d'Histoire Naturelle de Nice\t\t", +"MHNP\ts\tMuseum d'Histoire Naturelle Perpignan\t\t", +"MHNSM\ts\tMuseo de Historia Natural, Universidad Nacional Mayor de San Marcos\t\t", +"MHNT\ts\tMuseum d'Histoire Naturelle Toulouse\t\t", +"MHNUNC\ts\tDepartamento de Ictiologia del Museo de Historia Natural de la Universidad Nacional de Colombia\t\t", +"MHNV\ts\tMuseo de Historia Natural de Valparaiso\t\t", +"MHP\ts\tFort Hays State University, Sternberg Museum of Natural History\t\t", +"MHU\ts\tMakerere University, Botany Department\t\t", +"MHUA\ts\tMuseo de Herpetologia de la Universidad de Antioquia\t\t", +"MHV\ts\tMusee de Haute Volta\t\t", +"MHWK\ts\tMuch Wenlock Museum\t\t", +"MI\ts\tUniversita degli Studi di Milano, Dipartimento di Biologia\t\t", +"MIB\ts\tUniversity of Milano - Bicocca, Department of Biotechnology and Biosciences\t\t", +"MIB:ZPL\ts\tUniversity of Milano - Bicocca, Department of Biotechnology and Biosciences, ZooPlantLab", +"MIC\ts\tMar Ivanios College (Zoology museum)\t\t", +"MICG\th\tUniversidad de San Carlos de Guatemala\t\t", +"MICH\ts\tUniversity of Michigan\t\t", +"MICKKU\tc\tMICKKU Culture Collection\t\t", +"MID\ts\tMiddlebury College, Biology Department\t\t", +"MII\ts\tMuseum of Irish Industry\t\t", +"MIKU\ts\tMarine Biological Institute, Kyoto University\t\t", +"MIL\ts\tMilwaukee Public Museum\t\t", +"MIM\ts\tMinusinsk N. M. Martjanov Regional Museum\t\t", +"MIMB\ts\tMuseum of the Institute of Marine Biology\t\t", +"MIMM\ts\tMauritius Institute\t\t", +"MIN\ts\tUniversity of Minnesota\t\t", +"MINC\ts\tUniversidad Politecnica\t\t", +"MINI\ts\tMuzeul de Istoria Naturala\t\t", +"MIPV\ts\tUniversita degli Studi di Milano, Laboratorio di Micologia e Batteriologia Fitopathologica\t\t", +"MIRR\th\tMuseu Integrado de Roraima\t\t", +"MISR\ts\tMacaulay Land Use Research Institute\t\t", +"MISS\ts\tUniversity of Mississippi, Department of Biology\t\t", +"MISSA\ts\tMississippi State University, Department of Biological Sciences\t\t", +"MISU\th\tMinot State University\t\t", +"MIT\tc\tMassachusetts Institute of Technology\t\t", +"MIWG\ts\tMuseum of he Isle of Wight Geology\t\t", +"MIZA\ts\tMuseuo del Instituto de Zoologia Agricola\t\t", +"MIZL\ts\tMusee de l'Institut de Zoologie\t\t", +"MIZT\ts\tUniversita di Torino\t\t", +"MJ\ts\tMuzeum Vysociny\t\t", +"MJCM\ts\tMuseo de Ciencias Naturales y Antropologicas \"Prof. Juan C.Moyano\" (Argentina)\t\t", +"MJG\ts\tMuseo Jorge Gerhold\t\t", +"MJG\ts\tLandesmuseum Joanneum\t\t", +"MJG\ts\tJohannes Gutenberg-Universitat\t\t", +"MJH\ts\tMuzeul Judetean Hunedoara\t\t", +"MJMO\ts\tUniversidad Centro Occidental, Decanato de Agronomia\t\t", +"MJS\ts\tXiaolongshan Forestry Experiment Bureau\t\t", +"MJSD\ts\tMuseum-Jardin des Sciences\t\t", +"MK\ts\tNational Museum of Kenya\t\t", +"MKMEL\th\tHerbarium Melovskiorum\t\t", +"MKNDC\th\tInstitute of Biology\t\t", +"MKNH\th\tInstitute of Biology\t\t", +"ML\ts\tMusee de Lectoure\t\t", +"MLAV\ts\tMusees de Laval\t\t", +"MLGU\th\tInstitut National pour l'Etude et la Recherche Agronomiques\t\t", +"MLLD\tc\tMicrobiological Research Laboratory, Soil and Water Section, Department of Land Development\t\t", +"MLMJI\tc\tDepartment of Plant Protection, Faculty of Agricultural Production\t\t", +"MLP\ts\tMuseo de La Plata\tMLPA", +"MLRU\tc\tMicrobiology Laboratory, Department of Biology, Faculty of Science\t\t", +"MLS\ts\tMarine Laboratory Sydney\t\t", +"MLS\ts\tMuseo del Instituto de La Salle\t\t", +"MLS\ts\tLathallan Preparatory School\t\t", +"MLSU\ts\tSt. Petersburg State University, Zoology Museum\t\t", +"MLUH\ts\tMartin Luther Universitat\tMLU", +"MLY\ts\tArboretum Mlynany\t\t", +"MLZ\ts\tMoore Laboratory of Zoology, Occidental College\t\t", +"MLZ:Bird\ts\tMoore Laboratory of Zoology, Occidental College, Bird Collection", +"MLZ:Mamm\ts\tMoore Laboratory of Zoology, Occidental College, Mammal Collection", +"MM\ts\tManitoba Museum\t\t", +"MM\ts\tMuseo del Mar\t\t", +"MM\ts\tMagdeburg Museum\t\t", +"MM\ts\tUniversity of Montpellier\t\t", +"MMB\ts\tMoravske Muzeum\t\t", +"MMBC\ts\tMoravske Muzeum [Moravian Museum]\t\t", +"MMBS\ts\tMukaishima Marine Biological Station\t\t", +"MMCC\tc\tMARDI Microbial Culture Collection\t\t", +"MMChPV\ts\tMuseo Municipal El Chocon\t\t", +"MMCM\ts\tMuseum of Malawi\t\t", +"MMF\ts\tMuseu Municipal do Funchal\t\t", +"MMG\ts\tMuseo Marino de la Isla de Gorgona\t\t", +"MMH\ts\tMunicipal Museum\t\t", +"MMI\ts\tRegionalni muzeum\t\t", +"MMK\ts\tMcGregor Museum\t\t", +"MMKZ\ts\tAlexander McGregor Memorial Museum\t\t", +"MML\tc\tMedical Microbiological Laboratory\t\t", +"MMMN\ts\tManitoba Museum of Man and Nature, Botany Department\t\t", +"MMMZ\ts\tMutare Museum\t\t", +"MMNH\ts\tMongolian Museum of Natural History\t\t", +"MMNH\ts\tBell Museum of Natural History\t\t", +"MMNHS\ts\tMacedonian Museum of Natural History\t\t", +"MMNS\ts\tMississippi Museum of Natural Science\t\t", +"MMP\ts\tMuseo de Mar del Plata (Argentina)\t\t", +"MMRF\tc\tMarine Microbial Reference Facility\t\t", +"MMS\ts\tMontshire Museum of Science\t\t", +"MMTT\ts\tIran National Museum of Natural History\t\t", +"MMUE\ts\tMuseum of Manchester University\t\t", +"MMUS\ts\tMacleay Museum, University of Sydney\t\t", +"MN\ts\tMuseu Nacional, Universidade Federal do Rio de Janeiro\t\t", +"MNA\ts\tMuseum of Northern Arizona\t\t", +"MNA\ts\tThe Museo Nazionale dell'Antartide (Italian National Antarctic Museum in Genoa).\t\t", +"MNAV\ts\tMuseo Naturalistico-Archeologico\t\t", +"MNB\ts\tMuseum fuer Naturkunde der Humboldt-Universitaet\t\t", +"MNCE\ts\tMuseu de Historia Natural Capao da Embuia\t\t", +"MNCN\tsb\tMuseo Nacional de Ciencias Naturales\t\t", +"MNCN:ADN\tsb\tMuseo Nacional de Ciencias Naturales, Coleccion de Tejidos y ADN", +"MNCN:Ent\ts\tMuseo Nacional de Ciencias Naturales, Coleccion de entomologia", +"MNCN:Herpeto\ts\tMuseo Nacional de Ciencias Naturales, Coleccion de anfibios y reptiles", +"MNCN:ICTIO\ts\tMuseo Nacional de Ciencias Naturales, Coleccion de ictiologia", +"MNCN:Inverte\ts\tMuseo Nacional de Ciencias Naturales, Coleccion de invertebrados", +"MNCN:Malac\ts\tMuseo Nacional de Ciencias Naturales, Coleccion de malacologia", +"MNCN:Mam\ts\tMuseo Nacional de Ciencias Naturales, Colession de mamiferos", +"MNCN:Ornit\ts\tMuseo Nacional de Ciencias Naturales, Coleccion de aves", +"MNCR\ts\tMuseo Nacional de Costa Rica\t\t", +"MND\ts\tMuseum Natura Docet\t\t", +"MNDG\ts\tMuseo Nacional \"David J. Guzman\"\t\t", +"MNE\ts\tMaidstone Museum and Art Gallery\t\t", +"MNFD\ts\tMuseum fuer Naturkunde\t\t", +"MNG\ts\tSammlung Eisfeld des Museums der Natur Gotha\t\t", +"MNGA\ts\tMuzeul National de Istorie Natural \"Grigore Antipa\"\t\t", +"MNGC\ts\tMuseo Nacional de Historia Natural, Guatemala City\t\t", +"MNH\ts\tMuseo de Ciencias Naturales de Tenerife\t\t", +"MNHCI\ts\tMuseu de Historia Natural Capao da Imbuia\t\t", +"MNHM\ts\tNaturhistorisches Museum Mainz/Landessammlung fuer Naturkunde Rheinland-Pfalz\t\t", +"MNHM\ts\tJohn May Museum of Natural History\t\t", +"MNHN\ts\tMuseum National d'Histoire Naturelle\t\t", +"MNHN:IC\ts\tMuseum National d'Histoire Naturelle, Ichtyologie collection", +"MNHN:IE\ts\tMuseum National d'Histoire Naturelle, Echinoderm collection", +"MNHN:IK\ts\tMuseum National d'Histoire Naturelle, Cnidarians Collection", +"MNHN:IM\ts\tMuseum National d'Histoire Naturelle, Marine Invertebrate Collection", +"MNHN:IU\ts\tMuseum National d'Histoire Naturelle, Crustacean collection", +"MNHN:M\ts\tMuseum National d'Histoire Naturelle, Mammal collection", +"MNHN:P\ts\tMuseum National d'Histoire Naturelle, Paleontology Collection", +"MNHN\ts\tMuseo Nacional de Historia Natural, Departamento de Colecciones\t\t", +"MNHN\ts\tMuseo Nacional de Historia Natural de Montevideo\t\t", +"MNHNCH\ts\tMuseo Nacional de Historia Natural de Chile\tMNHN ,MNHNC", +"MNHNCU\ts\tMuseo Nacional de Historia Natural, Havana\tMNHC", +"MNHNJP\ts\tUniversidad Nacional Mayor de San Marcos\t\t", +"MNHNLES\ts\tMuseum National d'Histoire Naturelle Lesotho\t\t", +"MNHNM\ts\tMuseo Nacional de Historia Natural, Mexico City\t\t", +"MNHNP\ts\tMuseo Nacional de Historia Natural del Paraguay\t\t", +"MNHNSD\ts\tMuseo Nacional de Historia Natural, Santo Domingo\tMHND", +"MNHNUL\ts\tMuseu Nacional de Historia Natural de Universidade de Lisboa\t\t", +"MNHP\ts\tPrinceton University\t\t", +"MNHS\ts\tManchester Natural History Society\t\t", +"MNK\ts\tMuseo de Historia Natural \"Noel Kempff Mercado\"\t\t", +"MNK:A\ts\tMuseo de Historia Natural \"Noel Kempff Mercado\", Amphibian Collection", +"MNK:R\ts\tMuseo de Historia Natural \"Noel Kempff Mercado\", Reptile Collection", +"MNKNU\ts\tMuseum of Nature, V.N. Karazin Kharkiv National University\t\t", +"MNKS\ts\tMilton Keynes Development Corporation\t\t", +"MNMB\ts\tMagyar Nenzeti Museum\t\t", +"MNMS\ts\tMuseo Nacional de Ciencias Naturales\t\t", +"MNN\ts\tMusee National du Niger\t\t", +"MNNC\ts\tMuseo Nacional de Historia Natural, Santiago\t\t", +"MNNHN\ts\tMuseum National d'Historie Naturelle\t\t", +"MNNIT\tc\tMotilal Nehru National Institute of Technology\t\t", +"MNNW\ts\tMuseum fuer Naturkunde\t\t", +"MNRJ\ts\tMuseu Nacional/Universidade Federal de Rio de Janeiro\t\t", +"MNSB\ts\tMuseum of Natural Sciences\t\t", +"MNSL\ts\tMuseum of Natural Sciences\t\t", +"MNUFR\ts\tMongolian National University\t\t", +"MNVD\th\tMuseum fur Naturkunde und Vorgeschichte Dessau\t\t", +"MNVL\ts\tMuseum d'Histoire Naturelle de Ville de Lille\t\t", +"MNZ\ts\tMuseum of New Zealand Te Papa Tongarewa\t\t", +"MO\ts\tMissouri Botanical Garden\t\t", +"MOAR\ts\tMorris Arboretum, University of Pennsylvania, Botany Department\t\t", +"MOBR\th\tEstacion de Investigaciones Marinas de Margarita, Fundacion La Salle de Ciencias Naturales\t\t", +"MOC\ts\tWestern Oregon University, Biology Department\t\t", +"MOD\ts\tUniversita degli Studi di Modena e Reggio Emilia, Dipartimento de Biologia Animale\t\t", +"MODNR\ts\tDivision of State Parks, Department of Natural Resources\t\t", +"MOFUNG\ts\tMuseu Oceanogr. Fundacao Univerdidade Rio Grande\t\t", +"MOG\ts\tNational Range Agency\t\t", +"MOL\ts\tUniversidad Nacional Agraria La Molina, Departamento Academico de Biologia\t\t", +"MOLA\tc\tMicrobial Observatory of the Laboratoire Arago\t\t", +"MOM\ts\tMusee Oceanographique Monaco\t\t", +"MONA\ts\tMusee Oceanographique de Monaco\t\t", +"MONT\ts\tMontana State University\t\t", +"MONTU\ts\tUniversity of Montana\t\t", +"MONZ\ts\tMuseum of New Zealand\t\t", +"MOR\ts\tMorton Arboretum, Research Department\t\t", +"MOR\ts\tMuseum of the Rockies\t\t", +"MOS\ts\tCollege of Agriculture and Forestry\t\t", +"MOSG\ts\tMuzeul Orasului Sf. Gheorghe\t\t", +"MOSI\ts\tMuseum of Science and Industry\t\t", +"MOSM\ts\tAll-Russian Research Institute of Medicinal and Aromatic Plants\t\t", +"MOSN\ts\tMuseo Ornitologico e di Scienze Naturali\t\t", +"MOSP\ts\tMoscow State Pedagogical University, Botany Department\t\t", +"MOSS\th\tUniversidade Federal Rural do Semi-Arido\t\t", +"MOT\ts\tMote Marine Laboratory\t\t", +"MOTH\ts\tMuseum of the Hemispheres\t\t", +"MOUFPE\ts\tOceanographic Museum of the Federal University of Pernambuco\t\t", +"MOVC\ts\tCornell College, Biology Department\t\t", +"MOVI\ts\tMuseu Oceanografico do Vale do Itajai\t\t", +"MP\ts\tVychodoceske muzeum Pardubice\t\t", +"MP\ts\tMohonk Preserve, Inc.\t\t", +"MP\ts\tTransvaal Museum\t\t", +"MPA\ts\tEcole National Superieure Agronomique, Biologie et Pathologie Vegetales\t\t", +"MPC\ts\tMonterey Peninsula College, Life Science Museum\t\t", +"MPCA\ts\tMuseo Provincial \"Carlos Ameghino\"\t\t", +"MPCNyO\ts\tMuseo Provincial de Ciencias Naturales, Puerto Madryn\t\t", +"MPCRM\ts\tMuseo Paleontologico Cittadino della Rocca\t\t", +"MPE\ts\tF. R. Long Herbarium\t\t", +"MPEF-PV\ts\tMuso Paleontologico Egidio Fergulio\t\t", +"MPEG\ts\tMuseu Paraense Emilio Goeldi\t\t", +"MPEP\ts\tMusee de Paleontologie et de l'evolution\t\t", +"MPGB\ts\tMuseum of Portuguese Guinea\t\t", +"MPH\th\tShahid Behershti University\t\t", +"MPKV\tc\tBiological Nitrogen Fixation Project College of Agriculture\t\t", +"MPL\ts\tMusee de Port Louis\t\t", +"MPLN\ts\tMuseo Provinciale di Storia Naturale\t\t", +"MPM\ts\tMilwaukee Public Museum\t\t", +"MPM\ts\tMeguro Parasitological Museum\t\t", +"MPMP\ts\tNational Museum of the Philippines\t\t", +"MPN\ts\tMassey University, Ecology Group\t\t", +"MPPD\ts\tUniversity of Minnesota, Plant Pathology Department\t\t", +"MPPE\ts\tPaletnologica ed Etnologico dei Padri Francescani\t\t", +"MPR\ts\tMount Makulu Pasture Research Station\t\t", +"MPSC\ts\tMuseu de Paleontologia de Santana do Cariri\t\t", +"MPSN\ts\tMuseo Provinciale di Scienze Naturali\t\t", +"MPSP\ts\tMuseu Paulista\t\t", +"MPSU\tc\tDepartment of Microbiology, Songkla University\t\t", +"MPT\ts\tMuseuo Provincial de Teurel\t\t", +"MPU\ts\tUniversite Montpellier II\t\t", +"MPUC\ts\tPontificia Universidade Catolica do Rio Grande do Sul, Laboratorio de Botanica\t\t", +"MPUM\ts\tMuseo Paleontologia Universita degli Studi di Milano\t\t", +"MPUN\ts\tMuseo Paleontologicom\t\t", +"MPUNR\ts\tDepartamento de Geologia, Universidad de Chile\t\t", +"MPV\ts\tMuseo Paleontologico Municipal de Valencia\t\t", +"MPZ\ts\tMuseo Paleontologico de la Universidad de Zaragoza\t\t", +"MQ\ts\tGansu Institute of Desert Control\t\t", +"MQU\ts\tMacquarie University\t\t", +"MRA\ts\tMuseo Requieu\t\t", +"MRA\tc\tMalaria Research and Reference Reagent Resource Center\t\t", +"MRAC\ts\tMusee Royal de l'Afrique Centrale\t\t", +"MRC\tc\tTUBITAK Marmara Research Center Culture Collection\t\t", +"MRC\ts\tRocky Mountain Research Station\t\t", +"MRC\tc\tNational Research Institute for Nutritional Diseases\t\t", +"MRCA\ts\tMusee Royal de l'Afrique Centrale\t\t", +"MRCN\ts\tMuseu Rio-Grandense de Ciencias Naturais\t\t", +"MRD\ts\tMoorhead State University, Biology Department\t\t", +"MRF\ts\tMuseum of Histoire naturelle\t\t", +"MRGS\ts\tMuseu do Rio Grande do Sul\t\t", +"MRI\ts\tMurray Royal Institution\t\t", +"MRNP\ts\tMount Rainier National Park\t\t", +"MRSC\ts\tMount Makulu Central Research Station\t\t", +"MRSH\ts\tMatopos Research Station\t\t", +"MRSN\ts\tMuseo Regionale di Scienze Naturali\t\t", +"MRSN\tc\tMultidrug Resistant Organism Repository and Surveillance Network\t\t", +"MRSP\ts\tMuseo Regionale di Scienze Naturali, St. Pierre\t\t", +"MRST\ts\tMuseo Regionale di Storia Naturale, Terrasini\t\t", +"MS\ts\tUniversita di Messina, Dipartimento di Scienze Botaniche\t\t", +"MSA\ts\tMuseum of Science and Art\t\t", +"MSB\ts\tMuseum of Southwestern Biology\t\t", +"MSB:Bird\ts\tMuseum of Southwestern Biology, Bird Collection", +"MSB:Fishes\ts\tMuseum of Southwestern Biology, Fish Collection", +"MSB:Herp\ts\tMuseum of Southwestern Biology, Herpetology Collection", +"MSB:Mamm\ts\tMuseum of Southwestern Biology, Mammal Collection", +"MSB:Para\ts\tMuseum of Southwestern Biology, Parasitology Collection", +"MSB\ts\tMuseum Sophia\t\t", +"MSB\ts\tLudwig-Maximilians-Universitaet\t\t", +"MSC\ts\tMichigan State University, Botany and Plant Pathology Department\t\t", +"MSCL\tc\tMicrobial Strain Collection of Latvia\t\t", +"MSCMU\tc\tMicrobiology Section, Chiang Mai University (MSCMU)\t\t", +"MSCW\ts\tMississippi University for Women\t\t", +"MSDB\ts\tMuseo di Storia Naturale \"Don Bosco\"\t\t", +"MSDS\tc\tMicrobiology Section, Biological Science Division, Department of Science Services\t\t", +"MSE\ts\tAngus Museums\t\t", +"MSEM\ts\tMuseu Geologic del Seminari de Barcelona\t\t", +"MSEN\ts\tMontrose Natural History and Antiquarian Society\t\t", +"MSF\ts\tSauriermuseum Frick\t\t", +"MSGP\ts\tNusee des Services Geologiques du Portugal\t\t", +"MSI\tsc\tMarine Science Institute, University of the Philippines\t\t", +"MSI:PMS-ICBG\tc\tMarine Science Institute, University of the Philippines, Philippine Mollusk Symbiont-International Cooperative Biodiversity Group", +"MSIE\ts\tMuseum of Shanghai\t\t", +"MSINR\ts\tMuseum Sichuan Institute of Natural Resources\t\t", +"MSIR\ts\tMauritius Sugar Industry\t\t", +"MSJC\ts\tSt. Joseph's College, Natural History Museum\t\t", +"MSK\ts\tNational Academy of Sciences of Belarus, Flora and Systematic Laboratory\t\t", +"MSKH\ts\tCentral Botanical Garden\t\t", +"MSKU\ts\tBelarusian State University, Botany Department\t\t", +"MSL\ts\tRoyal Medical Society of London\t\t", +"MSLH\ts\tChinese University of Hong Kong, Marine Sciences Laboratory\tMSLKHC", +"MSLY\ts\tMossley Botanical Society\t\t", +"MSM\ts\tMarine Science Museum, Tokai Univ.\t\t", +"MSM\ts\tUniversity of Puerto Rico, Marino Puertorriqueno\t\t", +"MSNA\ts\tMuseo di Storia Naturale e Arte Archeologica\t\t", +"MSNG\ts\tMuseo Civico di Storia Naturale di Genova 'Giacomo Doria'\t\t", +"MSNM\ts\tMuseo Civico di Storia Naturale di Milano\t\t", +"MSNO\ts\tMuseum des Sciences Naturelles\t\t", +"MSNP\ts\tMuseo di Scienze Naturali\t\t", +"MSNT\ts\tMuseo Regionale di Scienze Naturali, Torino\t\t", +"MSNT:FAZC\ts\tMuseo Regionale di Scienze Naturali, Torino, Franco Andreone Zoological Collection", +"MSNT\ts\tMuseo Civico DI Storia Naturale DI Torino\t\t", +"MSNU\ts\tMuseo di Storia Naturale dell'Universita\t\t", +"MSNV\ts\tMuseo Civico di Storia Naturale di Venezia\t\t", +"MSNVR\ts\tMuseo Civico di Storia Naturale di Verona\t\t", +"MSPC\ts\tMuseo di Storia Naturale \"Pietro Calderini\"\t\t", +"MSPP\tc\tMycology Section, Plant Pathology and Microbiology Division, Department of Agricultural Science\t\t", +"MSSC\ts\tMidwestern State University\t\t", +"MSTFM\ts\tMiddle School of the Third Factory Machinery\t\t", +"MSTR\ts\tWestfaelisches Museum fuer Naturkunde\t\t", +"MSU\tc\tAcetobacter\t\t", +"MSU\ts\tMichigan State University Museum\tMSUC,MSUM", +"MSUB\ts\tMontana State University\t\t", +"MSUD\ts\tI. I. Mecynikov State University of Odessa, Department of Morphology and Systematics of Plants\t\t", +"MSUH\ts\tUniversity of Mosul, Biology Department\t\t", +"MSUMC\ts\tMurray State University\t\t", +"MSUMZ\ts\tMemphis State University\t\t", +"MSUN\ts\tWestfaelische Wilhelms-Universitaet\t\t", +"MSUT\ts\tMuseum of Natural History, Tirane\t\t", +"MSUZ\ts\tMississippi State University, Zoological Collections\t\t", +"MSV\ts\tMuseum der Stadt Villach\t\t", +"MT\ts\tUniversite de Montreal\t\t", +"MT\ts\tMus. Tinro, Vladyvostok\t\t", +"MTA\ts\tMaden Tetkik ve Arama Enstituesue\t\t", +"MTCC\tc\tMicrobial Type Culture Collection & Gene Bank\t\t", +"MTCHT\th\tMar Thoma College\t\t", +"MTD\ts\tMuseum of Zoology Senckenberg Dresden\t\t", +"MTD:T\ts\tMuseum of Zoology Senckenberg Dresden, Tissue collection", +"MTD:TD\ts\tMuseum of Zoology Senckenberg Dresden, Herpetological Tissue Collection", +"MTDO\th\tChiba University\t\t", +"MTEC\ts\tMontana State University\t\t", +"MTJB\ts\tJardin botanique de Montreal\t\t", +"MTKD\ts\tStaatliches Museum fuer Tierkunde\t\t", +"MTKKU\tc\tDepartment of Clinical Microbiology, Faculty of Medical Technology\t\t", +"MTMG\ts\tMcGill University, Macdonald Campus, Plant Science Department\t\t", +"MTN\ts\tMalton Field Naturalists' Society\t\t", +"MTQA\ts\tMuseum of Tropical Queensland\tMTQ", +"MTSN\ts\tTrento Museum of Natural Sciences\t\t", +"MTSU\ts\tMiddle Tennessee State University, Biology Department\t\t", +"MTUF\ts\tUniversity Museum, Tokyo University of Fisheries\t\t", +"MU\tc\tMugla University Collection of Microorganisms\t\t", +"MU\ts\tMiami University, Botany Department, Willard Sherman Turrell Herbarium\t\t", +"MU\ts\tMidwestern University\t\t", +"MUACC\tc\tMurdoch University Algal Culture Collection\t\t", +"MUAF\tc\tCulture collection of Mendel University of Agriculture and Forestry in Brno\t\t", +"MUB\ts\tUniversidad de Murcia, Departamento de Biologia Vegetal, Botanica\t\t", +"MUBI\t\tMuseo de Biodiversidad del Peru, Cusco\t\t", +"MUCC\tc\tMurdoch University Culture Collection\t\t", +"MUCC\tc\tMie University Culture Collection (Culture Collection, Laboratory of Plant Pathology)\t\t", +"MUCL\tc\tMycotheque de l'Universite Catholique de Louvain\tBCCM/MUCL", +"MUCPv\ts\tMuseo de la Universidad Nacional del Comahue\tMPCA", +"MUCR\ts\tMuseo de Insectos\t\t", +"MUCV\ts\tMonash University, Biological Sciences Department\t\t", +"MUDH\ts\tThe Hague, Museon\t\t", +"MUFE\ts\tUniversity of Marmara, Department of Botany\t\t", +"MUFM\ts\tManipur University Fish Museum\t\t", +"MUFS\ts\tDepartment of Animal Science, Miyazaki University\t\t", +"MUGM\ts\tMuseo de Ciencias Naturales, Coleccion \"Gustavo Orces\" (Ecuador)\t\t", +"MUGT\ts\tMuseo de Ciencias Naturales de la Universidad de Guayaquil\t\t", +"MUH\th\tMirpur University of Science & Technology\t\t", +"MUHW\ts\tMarshall University, Biological Sciences Department\t\t", +"MUJ\ts\tMuseo Javeriano de Historia Natural, Laboratoriao de Entomologia\t\t", +"MUL\tc\tDepartment of Microbiology MUL-B 250\t\t", +"MULU\ts\tMuseum Ludovicae Ulricae, Zoology Institute of the University of Uppsala\t\t", +"MUM\tc\tMicoteca da Universidade do Minho\t\t", +"MUMF\ts\tDepartment of Life Sciences\t\t", +"MUMH\ts\tMie University Mycological Herbarium\t\t", +"MUMZ\ts\tUniversity of Missouri, Museum of Zoology\t\t", +"MUNC\ts\tSt. John's, Memorial University of Newfoundland\t\t", +"MUNZ\ts\tMassey University\t\t", +"MUO\ts\tStovall Museum of Science and History\t\t", +"MUP\ts\tUniversidade do Porto, Museu do Historia Natural\t\t", +"MUR\ts\tMurray State University, Department of Biological Sciences\t\t", +"MURD\ts\tMurdoch University\t\t", +"MURU\ts\tMurdoch University\t\t", +"MUS\ts\tMuskingum College, Biology Department\t\t", +"MUSA\ts\tUniversidad Nacional de San Agustin, Museo de Historia Natural (Peru)\t\t", +"MUSK\ts\tMuskegon Community College, Life Science Department\t\t", +"MUSM\ts\tMuseo de Historia Natural de la Universidad Nacional Mayor de San Marcos en Lima\t\t", +"MUSN\ts\tMuseo Universitario di Storia Naturale e della Strumentazione Scientifica\t\t", +"MUST\th\tAl-Mustansiriya University\t\t", +"MUT\tc\tMycotheca Universitatis Taurinensis\t\t", +"MUZ\th\tKing Abdulaziz City for Science and Technology\t\t", +"MV\ts\tUniversity of Montana Museum\t\t", +"MVC\ts\tUniversity of Charleston, Natural Sciences Department\t\t", +"MVDA\ts\tMinisterio de Ganaderia y Agricultura\t\t", +"MVEN\ts\tNaturhistorisch Museum\t\t", +"MVFA\ts\tUniversidad de la Republica, Laboratorio de Botanica\t\t", +"MVFQ\ts\tUniversidad de la Republica, Catedra de Botanica Farmaceutica\t\t", +"MVHC\ts\tUniversidad de la Republica, Seccion Micologia\t\t", +"MVJB\ts\tMuseo y Jardin Botanico\t\t", +"MVM\ts\tMuseo Nacional de Historia Natural, Departamento de Botanica\t\t", +"MVMA\ts\tMuseum of Victoria\t\t", +"MVN\ts\tPublic Library\t\t", +"MVNP\ts\tMesa Verde National Park\t\t", +"MVP\ts\tMuseum of Vicotria\t\t", +"MVSC\ts\tMillersville University, Biology Department\t\t", +"MVUP\ts\tMuseo de Vertebrados de la Universidad de Panama\t\t", +"MVZ\ts\tMuseum of Vertebrate Zoology, University of California at Berkeley\t\t", +"MVZ:Bird\ts\tMuseum of Vertebrate Zoology, University of California at Berkeley, Bird Collection", +"MVZ:Egg\ts\tMuseum of Vertebrate Zoology, University of California at Berkeley, Egg Collection", +"MVZ:Herp\ts\tMuseum of Vertebrate Zoology, University of California at Berkeley, Herpetology Collection", +"MVZ:Hild\ts\tMuseum of Vertebrate Zoology, University of California at Berkeley, Milton Hildebrand collection", +"MVZ:Img\tb\tMuseum of Vertebrate Zoology, University of California at Berkeley, Image Collection", +"MVZ:Mamm\ts\tMuseum of Vertebrate Zoology, University of California at Berkeley, Mammal Collection", +"MVZ:Page\tb\tMuseum of Vertebrate Zoology, University of California at Berkeley, Notebook Page Collection", +"MW\ts\tMuseum Wasmann\t\t", +"MW\tsb\tMoscow State University Herbarium\t\t", +"MWC\ts\tMuseum of Western Colorado\t\t", +"MWCF\ts\tMary Washington College, Department of Biology\t\t", +"MWFB\ts\tUniversity of California, Davis, Museum of Wildlife and Fisheries Biology\t\t", +"MWG\ts\tMoscow State University, Department of Biogeography\t\t", +"MWI\ts\tWestern Illinois University, Biological Sciences Department\t\t", +"MWNH\ts\tMuseum Wiesbaden, Department of Natural Science\t\t", +"MWSJ\ts\tMissouri Western State College, Biology Department\t\t", +"MWSU\ts\tMidwestern State University\t\t", +"MY\ts\tUniversidad Central de Venezuela, Botanica\t\t", +"MYDC\ts\tMianyang Institute for Drug Control\t\t", +"MYF\ts\tUniversidad Central de Venezuela\t\t", +"MZ-ICACH\ts\tInstituto de Ciencias y Artes de Chiapas, Museo Zoologico (Mexico)\t\t", +"MZ\ts\tJihomoravske muzeum Znojmo\t\t", +"MZ\ts\tMuseum of the Earth, Polish Academy of Sciences\t\t", +"MZAF\ts\tMuseo Zoologico dell'Accademia dei Fisiocritici\t\t", +"MZB\ts\tMuseum Zoologicum Bogoriense\t\t", +"MZB:Amp\ts\tMuseum Zoologicum Bogoriense, Amphibian Collection", +"MZB:Ornith\ts\tMuseum Zoologicum Bogoriense, Ornithology Collection", +"MZBL\ts\tMuseo de Zoologica\t\t", +"MZBS\ts\tMuseo Zoologia\t\t", +"MZCP\ts\tUniversidade de Coimbra\t\t", +"MZCR\ts\tMuseo de Zoologia\t\t", +"MZFC\ts\tMuseo de Zoologia \"Alfonso L. Herrera\"\t\t", +"MZFN\ts\tMuseo Zoologico dell'Universita \"Federico II\"\t\t", +"MZGZ\ts\tMuseum Zoologia del Giardino Zoologico\t\t", +"MZH\ts\tZoolgical Museum, Finnish Museum of Natural History\t\t", +"MZKI\tc\tMicrobial Culture Collection of National Institute of Chemistry\t\t", +"MZL\ts\tMusee Zoologique\t\t", +"MZLS\ts\tMusee Zoologique\t\t", +"MZLU\ts\tLund University\t\t", +"MZN\ts\tMusee Zoologie\t\t", +"MZNA\ts\tUniversidad de Navarra, Museum of Zoology\t\t", +"MZNC\ts\tUniversidad Nacional de Cordoba, Museo de Zoología\t\t", +"MZP\ts\tMuzeum Ziemi Polska Akademia Nauk\t\t", +"MZPW\ts\tPolish Academy of Science, Museum of the Institute of Zoology\t\t", +"MZRF\ts\tMuseo Zangheri di Storia Naturale della Romagna\t\t", +"MZRO\ts\tMuseo Civico di Storia Naturale \"P. Zangheri\"\t\t", +"MZS\ts\tUniversite de Strasbourg, Musee de Zoologie\t\t", +"MZSF\ts\tUniversite de Strasbourg, Museum Zoologique\t\t", +"MZSP\ts\tSao Paulo, Museu de Zoologia da Universidade de Sao Paulo\t\t", +"MZTG\ts\tMuseum Zoologia\tIHN", +"MZUABCS\ts\tMuseo de Zoologia de la Universidad Automica de Baja California Sur\t\t", +"MZUB\ts\tMuseo di Zoologia\t\t", +"MZUC\ts\tMuseo de Zoologia, Universidad de Concepcion\t\t", +"MZUC\ts\tUniversita di Cagliari\t\t", +"MZUCR\ts\tUniversidad de Costa Rica, Museo de Zoologia\t\t", +"MZUEL\ts\tMuseu de Zoologia da Universidade Estadual de Londrina\tMZUEL", +"MZUESC\ts\tMuseu de Zoologia da Universidade Estadual de Santa Cruz\t\t", +"MZUF\ts\tMuseo Zoologico La Specola, Universita di Firenze\t\t", +"MZUFBA\ts\tMuseu de Zoologia, Universidade Federal da Bahia, Salvador\t\t", +"MZUN\ts\tMuseo Zoologico di Universita degli Studi\t\t", +"MZUNAP\ts\tMuseo de Zoologia de la Universidad Nacional de la Amazonia Peruana\t\t", +"MZUP\ts\tMuseo Zoologia\t\t", +"MZUP\ts\tMuseo Zoologico di Universita degli Studi\t\t", +"MZUR\ts\tMuseo di Zoologia dell'Universita di Roma \"La Sapienza\"\tMZUL", +"MZUR:BAU\ts\tMuseo di Zoologia dell'Universita di Roma \"La Sapienza\", Zoological collection of the Department of Biology and Biotechnology", +"MZUS\ts\tMusee de Zoologie de l'Universite de Strasbourg\t\t", +"MZUSP\ts\tMuseu de Zoologia da Universidade de Sao Paulo\t\t", +"MZUT\ts\tMuseo di Zoologia, Instituto di Zoologia e Anatomia Comparata Universita di Torino\t\t", +"MZUT\ts\tMuseo e Instituto DI Zoologia Sistematica dell' UniversitaDI Torino\t\t", +"MZUTH\ts\tMuseum of Zoology, University of Thessaloniki\t\t", +"MZUTI\ts\tMuseo de Zoologia, Universidad Tecnologica Indoamerica\t\t", +"MZUVN\ts\tMusee Zool. Univ. et Ville de Nancy\t\t", +"MZV\ts\tMuzeum i Instytut Zoologii\t\t", +"MZV\ts\tZoological Museum Varsovite\t\t", +"MZYU\ts\tMuseum of Zoology, Yunnan University\t\t", +"N\ts\tNanjing University, Biology Department\t\t", +"NA\ts\tUnited States National Arboretum, USDA/ARS\t\t", +"NABG\ts\tBotanical Garden\t\t", +"NAC\ts\tNagano Nature Conservation Research Institute\t\t", +"NAI\ts\tUniversity of Nairobi, Botany Department\t\t", +"NAIC\ts\tNational Agricultural Insect Collection\t\t", +"NAKU\th\tNamik Kemal University\t\t", +"NAM\ts\tFacultes Universitaires Notre-Dame de la Paix\t\t", +"NAN\ts\tNantong Teachers College, Biology Department\t\t", +"NAP\ts\tInstitute of Zoology, Academia Sinica (formerly National Academy of Peiping)\t\t", +"NAP\ts\tUniversita Degli Studi di Napoli Federico II, Dipartimento di Biologia Vegetale\t\t", +"NARA\ts\tNational Aquatic Resources Agency\t\t", +"NARI\ts\tNational Agricultural Research Institute\t\t", +"NARL\ts\tNational Agricultural Research Laboratories\t\t", +"NAS\ts\tInstitute of Botany, Jiangsu Province and Chinese Academy of Sciences\t\t", +"NASC\tb\tEuropean Arabidopsis Stock Centre\t\t", +"NASC\ts\tMassachusetts College of Liberal Arts, Biology Department\t\t", +"NAT\ts\tSeale-Hayne Agricultural College\t\t", +"NATC\ts\tNorthwestern State University, Biological Sciences Department\t\t", +"NAU\ts\tNanjing Agricultural University, Department of Plant Science\t\t", +"NAUF\ts\tNorthern Arizona University\t\t", +"NAUJ\ts\tNanjing, Nanjing Agricultural University\t\t", +"NAUVM\ts\tNorthern Arizona University, Museum of Vertebrates\t\t", +"NAVA\ts\tNavajo Natural Heritage Program, Navajo Department of Fish & Wildlife\t\t", +"NBAIM\tc\tNational Bureau of Agriculturally Important Microorganisms\t\t", +"NBFGR\ts\tNational Bureau of Fish Genetic Resources (Indian Council of Agricultural Research)\t\t", +"NBFGR:CHN\ts\tNational Bureau of Fish Genetic Resources (Indian Council of Agricultural Research), Cochin Unit", +"NBG\ts\tNational Botanical Institute\t\t", +"NBGB\tsb\tNational Botanical Garden, Belgium\t\t", +"NBIMCC\tc\tNational Bank for Industrial Microorganisms and Cell Cultures\t\t", +"NBM\ts\tNew Brunswick Museum\t\t", +"NBMB\ts\tSt. John's, New Brunswick Museum\t\t", +"NBME\ts\tNational Butterfly Museum (Saruman Museum)\t\t", +"NBNM\ts\tNational Park Service\t\t", +"NBPC\ts\tNational Birds of Prey Centre\t\t", +"NBPGR\tb\tNational Bureau of Plant Genetic Resources\t\t", +"NBRC\tc\tNITE Biological Resource Center\t\t", +"NBRP\tb\tNational Bio-Resource Project\t\t", +"NBSB\ts\tNational Biomonitoring Specimen Bank, U.S. Geological Survey\t\t", +"NBSB:Bird\ts\tNational Biomonitoring Specimen Bank, U.S. Geological Survey, bird collection", +"NBSB:Mamm\ts\tNational Biomonitoring Specimen Bank, U.S. Geological Survey, mammal tissue collection", +"NBSI\ts\tBiologische Station Neusiedler See\t\t", +"NBV\ts\tKoninklijke Nederlandse Botanische Vereniging\t\t", +"NBY\ts\tNewbury District Museum\t\t", +"NBYC\ts\tNewberry College, Department of Biology\t\t", +"NCAIM\tc\tNational Collection of Agricultural and Industrial Microorganisms\t\t", +"NCAM\tc\tNational Collection of Agricultural Microorganisms\t\t", +"NCAS\ts\tRutgers University, Biological Sciences Department\t\t", +"NCATG\ts\tNorth Carolina A & T State University, Biology Department\t\t", +"NCAW\ts\tNorth-West College of Agriculture\t\t", +"NCB\tc\tNational Culture Bank\t\t", +"NCBS\ts\tYale University, Connecticut Botanical Society\t\t", +"NCC\tc\tNantes Culture Collection\t\t", +"NCC\ts\tSonoma State University, Biology Department\t\t", +"NCCB\tc\tThe Netherlands Culture Collection of Bacteria\tNCCB", +"NCCBH\ts\tNature Conservancy Council, Balloch\t\t", +"NCCE\ts\tNature Conservancy Council, Edinburgh\t\t", +"NCCH\ts\tNature Conservancy Council\t\t", +"NCCN\ts\tNature Conservancy Council, Norwich\t\t", +"NCCP\tc\tNational Culture Collection for Pathogens\t\t", +"NCCP\tc\tNational Culture Collection of Pakistan\t\t", +"NCCPF\tc\tNational Culture Collection of Pathogenic Fungi\t\t", +"NCDC\tc\tNational Collection of Dairy Cultures\t\t", +"NCE\ts\tUniversity of Newcastle upon Tyne, School of Biological Sciences\t\t", +"NCF\ts\tDepartment of Forest Insects, Northwest College of Forestry\t\t", +"NCFB\tc\tNational Collection of Food Bacteria\t\t", +"NCH\ts\tNorwich Botanical Society\t\t", +"NCHU\ts\tNational Chung Hsing University\t\t", +"NCHU:ZOOL\ts\tNational Chung Hsing University, Department of Life Science", +"NCIM\tc\tNational Collection of Industrial Microorganisms\t\t", +"NCIMB\tc\tNational Collections of Industrial Food and Marine Bacteria (incorporating the NCFB)\tNCIB,NCMB", +"NCIP\ts\tPusat Penelitian dan Pengembangan Oseanologi\t\t", +"NCKU\ts\tNational Cheng-Kung University, Biology Department\t\t", +"NCLN\ts\tNew College\t\t", +"NCMA\ts\tRaleigh, North Carolina Department of Environmental Health and Natural Resources\t\t", +"NCMH\tc\tThe North Carolina Memorial Hostital\t\t", +"NCMK\ts\tNorwich Castle Museum\t\t", +"NCP\th\tNational Collection of Passiflora\t\t", +"NCPF\tc\tNational Collection of Pathogenic Fungi\t\t", +"NCPPB\tc\tNational Collection of Plant Pathogenic Bacteria\t\t", +"NCPV\tc\tNational Collection of Pathogenic Viruses\t\t", +"NCS\ts\tNorth Carolina State University\t\t", +"NCSC\tc\tNational Center of Streptococcus Collection, Department of Microbiology, Faculty of Medical Science\t\t", +"NCSC\ts\tNorth Carolina State University, Botany Department\t\t", +"NCSLG\th\tNorth Carolina State University\t\t", +"NCSM\ts\tNorth Carolina Museum of Natural Sciences\tNCSMNS", +"NCSU\ts\tNorth Carolina State University Collections\t\t", +"NCTC\tc\tNational Collection of Type Cultures\t\t", +"NCU\ts\tUniversity of North Carolina, North Carolina Botanical Garden\t\t", +"NCUT\ts\tNicolaus Copernicus University\t\t", +"NCWRF\tc\tNational Collection of Wood Rotting Fungi\t\t", +"NCY\ts\tConservatoire et Jardins Botaniques de Nancy\t\t", +"NCYC\tc\tNational Collection of Yeast Cultures\t\t", +"ND\ts\tUniversity of Notre Dame, Department of Biological Sciences\t\t", +"NDA\ts\tNorth Dakota State University, Animal and Range Sciences Department\t\t", +"NDAA\ts\tOrange, New South Wales Department of Agriculture\t\t", +"NDAT\ts\tDepartment of Agriculture, Tunisia\t\t", +"NDFC\ts\tNewfoundland Department of Forestry\t\t", +"NDG\ts\tUniversity of Notre Dame, Department of Biological Sciences\t\t", +"NDO\ts\tDivision of Forest Research, Forest Department\t\t", +"NDSR\ts\tNational Drosophila Species Resource Center\t\t", +"NDSU\ts\tNorth Dakota State University\t\t", +"NDTC\ts\tNingde Teachers College, Biology Department\t\t", +"NE\ts\tUniversity of New England\t\t", +"NEB\ts\tUniversity of Nebraska State Museum\t\t", +"NEBC\ts\tHarvard University\t\t", +"NEBK\th\tUniversity of Nebraska at Kearney\t\t", +"NEFI\ts\tNortheastern Forestry University, Forestry Department\t\t", +"NEM\tc\tFaculte de Medecine Necker-Enfants Malades\t\t", +"NEMO\ts\tTruman State University\t\t", +"NEMSU\ts\tTruman State University\t\t", +"NEMU\ts\tNewark Museum\t\t", +"NENU\ts\tNortheast Normal University, Biology Department\t\t", +"NEPCC\tc\tNorth East Pacific Culture Collection\t\t", +"NESH\ts\tUniversity of Nevada\t\t", +"NEU\ts\tUniversite de Neuchatel, Laboratoire de botanique evolutive\t\t", +"NEUN\th\tNear East University\t\t", +"NEW\ts\tUniversity of Newcastle\t\t", +"NEWHM\ts\tHancock Museum\t\t", +"NEZ\ts\tMuseum, Zoology Department, University of New England\t\t", +"NF\ts\tNanjing Forestry University, Forest Resources and Environment\t\t", +"NFCCI\tc\tNational Fungal Culture Collection of India\t\t", +"NFCCP\tc\tNational Fungal Culture Collection of Pakistan\t\t", +"NFLD\ts\tMemorial University of Newfoundland, Biology Department\t\t", +"NFM\ts\tNewfoundland Museum\t\t", +"NFO\ts\tNiagara Parks Botanical Gardens and School of Horticulture\t\t", +"NFRC\ts\tNorthern Forest Research Centre\t\t", +"NFRDI\tc\tNational Fisheries Research & Development Institute\t\t", +"NFRI\tc\tNorwegian Forest Research Institute\t\t", +"NFRN\ts\tCanadian Forest Service, NRCan\t\t", +"NGBB\th\tNezahat Gokyigit Botanik Bahcesi\t\t", +"NGCPR\th\tNaoroji Godrej Centre for Plant Research\t\t", +"NGI\ts\tNanjing Geographical Institute\t\t", +"NGM\ts\tBromley House Library\t\t", +"NGMC\ts\tNational Geological Museum of China\t\t", +"NGR\tc\tPlant Pathology\t\t", +"NH\ts\tSouth African National Biodiversity Institute\t\t", +"NHA\ts\tUniversity of New Hampshire, Plant Biology Department\t\t", +"NHCP\th\tNational Bureau of Plant Genetic Resources\t\t", +"NHES\ts\tConnecticut Agricultural Experiment Station, Entomology Department\t\t", +"NHG\ts\tNaturhistorische Gesellschaft e. V., Abteilung Botanik\t\t", +"NHI\th\tNatural History Institute\t\t", +"NHIC\ts\tOntario Ministry of Natural Resources\t\t", +"NHL\tc\tNational Institute of Hygienic Sciences\t\t", +"NHM\ts\tNaturhistorisches Museum, Bern\t\t", +"NHM\ts\tUniversity of Nottingham, Botany Department\t\t", +"NHMA\ts\tNatural History Museum, Denmark\t\t", +"NHMB\ts\tNaturhistorisches Museum, Basel\t\t", +"NHMB\ts\tNatural History Museum Bucharest\t\t", +"NHMBe\ts\tNaturhistorisches Museum Bern\t\t", +"NHMC\ts\tNatural History Museum of Crete, University of Crete, Department of Botany\t\t", +"NHMC\ts\tNatural History Museum, Rangoon\t\t", +"NHME\ts\tNatuurhistorisch Museum\t\t", +"NHMF\th\tNatural History Museum Fribourg\t\t", +"NHMG\ts\tNatural History Museum of Guangxi\t\t", +"NHMG\ts\tGoteborgs Naturhistoriska Museet\t\t", +"NHMK\ts\tLandesmuseum fuer Karnten\t\t", +"NHML\ts\tNatural History Museum, Tripoli\t\t", +"NHMM\ts\tNatuurhistorische Museum Maastricht\t\t", +"NHMM-LS\ts\tNaturhistorisches Museum/Landessammlung fuer Naturkunde Rheinland-Pfalz\t\t", +"NHMN\ts\tNottingham Natural History Museum (Wollaton Hall)\t\t", +"NHMR\ts\tNatural History Museum Rijeka\t\t", +"NHMR\ts\tNatural History Museum, Reykjavik\t\t", +"NHMR\ts\tNatuurhistorisch Museum\t\t", +"NHMS\th\tNatural History Museum Split\t\t", +"NHMTU\ts\tNatural History Museum, Tribhuvan University\t\t", +"NHMUK\tsb\tNatural History Museum, London\tBM,BM(NH),BMNH,NHM,NHM R,NMH", +"NHMUK\ts\tNatural History Museum, Karachi\t\t", +"NHMW\ts\tNaturhistorisches Museum, Wien\t\t", +"NHNC\ts\tLa Chaux-de-Fons\t\t", +"NHNE\ts\tNew England College, Biology Department\t\t", +"NHR\th\tInstitute of Scientific and Technological Research (IRST)\t\t", +"NHRI\ts\tIslandic Museum of Natural History\t\t", +"NHRM\ts\tNaturhistoriska Rijkmuseet\t\t", +"NHRS\ts\tSwedish Museum of Natural History, Entomology Collections\t\t", +"NHSD\ts\tNatural History Society of Dublin\t\t", +"NHST\ts\tMuseum of Natural History, Reunion\t\t", +"NHT\ts\tTropical Pesticides Research Institute\t\t", +"NHV\ts\tInstitut fuer Landwirtschaftliche Botanik\t\t", +"NI\tc\tNagao Institute\t\t", +"NI\ts\tSlovenska pol'nohospodarska Univerzita, Katedra botaniky\t\t", +"NIAB\tb\tNational Institute of Agricultural Botany\t\t", +"NIAES\tc\tNational Institute for Agro-Environmental Sciences\t\t", +"NIAH\tc\tNational Institute of Animal Health\t\t", +"NIAID\tc\tNational Institute of Allergy and Infectious Diseases\t\t", +"NIAS\tsb\tNational Institute of Agrobiological Sciences\t\t", +"NIBH\tc\tNational Institute of Bioscience and Human-Technology\t\t", +"NIBR\tscb\tNational Institute of Biological Resources\tNNIBR", +"NIBSC\tb\tNational Institute for Biological Standards and Control\t\t", +"NICC\ts\tNational Insect Collection\t\t", +"NICD\ts\tMalaria Research Center\t\t", +"NICE\ts\tMuseum d'Histoire Naturelle\t\t", +"NICH\ts\tHattori Botanical Laboratory\t\t", +"NIES\tc\tMicrobial Culture Collection\t\t", +"NIFI\ts\tNational Inland Fisheries Institute\t\t", +"NIFRS\ts\tNational Research Institute of Fisheries Science\t\t", +"NIG\ts\tNanjing Geographical Institute\t\t", +"NIGL\ts\tNanjing Institute of Geography and Limnology\t\t", +"NIGP\ts\tNaking Institute of Geology and Palaeontology\t\t", +"NIHHS\th\tNational Institute of Horticultural and Herbal Science, RDA\t\t", +"NIM\th\tMuseum d'histoire naturelle de Nimes\t\t", +"NIMM\th\tNational Institute of Medicinal Materials\t\t", +"NINF\ts\tNewfoundland Insectarium\t\t", +"NIO\ts\tNational Institute of Oceanography\t\t", +"NIOCC\tc\tNational Institute of Oceanography Culture Collection\t\t", +"NIPH\tc\tNational Institute of Public Health, Collection A. Nemec\t\t", +"NIPR\ts\tNational Institute of Polar Research, Biological Data Department\t\t", +"NIT\ts\tJardim Botanico de Niteroi\t\t", +"NIVA\tc\tCulture Collection of Algae (NIVA)\t\t", +"NIWA\ts\tNational Institute of Water and Atmospheric Research\t\t", +"NJ\ts\tNjala University College\t\t", +"NJM\ts\tOkresni vlastivedne muzeum\t\t", +"NJM\tc\tNippon Veterinary and Animal Science University\t\t", +"NJNU\ts\tNanjing Normal University, Biology Department\t\t", +"NJSM\ts\tNew Jersey State Museum\t\t", +"NKA\tc\tNationales Konsiliarlabor fur Adenoviren\t\t", +"NKMC\ts\tNational Kweiyang Medical College\t\t", +"NKME\ts\tNaturkundemuseum Erfurt\t\t", +"NKMU\ts\tNankai University Museum\t\t", +"NKU\ts\tNankai University, Biology Department\t\t", +"NKUM\ts\tNankai University\t\t", +"NLEC\ts\tNeal L. Evenhuis\t\t", +"NLH\ts\tAgricultural University of Norway, Department of Biology and Nature Conservation\t\t", +"NLHD\ts\tNiedersachsisches Landesmuseum\t\t", +"NLPS\ts\tNottingham Literary and Philosophical Society\t\t", +"NLSN\ts\tNotre Dame University, Biological Sciences Department\t\t", +"NLU\ts\tUniversity of Louisiana at Monroe, Museum of Natural History\t\t", +"NLUH\ts\tUniversity of the Philippines College Baguio\t\t", +"NM\ts\tNorthern Michigan University, Biology Department\t\t", +"NMAC\ts\tInner Mongolia Agricultural University, Department of Pratacultural Science\t\t", +"NMAG\ts\tNaturhistorisches Museum, Augsburg\t\t", +"NMB\tc\tNingbo Marine Biotechnology\t\t", +"NMB\ts\tNaturhistorishes Museum\t\t", +"NMB\ts\tNational Museum, Bloemfontein\t\t", +"NMB:P\ts\tNational Museum, Bloemfontein, The Protozoan collection of the National Museum", +"NMBA\ts\tNational Museum, Buenos Aires\t\t", +"NMBA\ts\tNaturhistorisches Museum der Benediktiner-Abtei\t\t", +"NMBA\ts\tNaturhistorisches Museum, Basel\t\t", +"NMBE\ts\tNaturhistorisches Museum der Burgergemeinde Bern\tNHM", +"NMBO\ts\tNational Museum, Bloemfontein\t\t", +"NMBT\th\tNatuurmuseum Brabant\t\t", +"NMBZ\ts\tNatural History Museum of Zimbabwe\t\t", +"NMC\ts\tNew Mexico State University, Department of Biology\t\t", +"NMC\ts\tCanadian Museum of Nature\tCMN", +"NMCC\tc\tNorth Maharashtra Microbial Culture Collection Centre\t\t", +"NMCDC\ts\tInner Mongolia Center for Endemic Disease Control and Research\t\t", +"NMCI\ts\tNoto Marine Center Ishikawa Prefecture\t\t", +"NMCI:AR\ts\tNoto Marine Center Ishikawa Prefecture, Arthropoda collection", +"NMCI:EC\ts\tNoto Marine Center Ishikawa Prefecture, Echinodermata", +"NMCI:IV\ts\tNoto Marine Center Ishikawa Prefecture, Invertebrata", +"NMCI:MO\ts\tNoto Marine Center Ishikawa Prefecture, Mollusca collection", +"NMCI:P\ts\tNoto Marine Center Ishikawa Prefecture, Pisces and Coelenterata", +"NMCI:S\ts\tNoto Marine Center Ishikawa Prefecture, Sea weed", +"NMCL\ts\tNaturkunde-Museum\t\t", +"NMCR\ts\tNew Mexico State University, Department of Animal and Range Sciences\t\t", +"NME\ts\tSammlung des Naturkundemseum Erfurt\t\t", +"NMED\ts\tNew Mexico Environment Department\t\t", +"NMEG\ts\tNaturkundesmuseum\t\t", +"NMFC\ts\tInner Mongolia Forestry College, Desert Control and Utilization Department\t\t", +"NMFSH\ts\tNational Marine Fisheries Service\t\t", +"NMG\ts\tNaturhistoriska Riksmuseet\t\t", +"NMI\ts\tNational Museum of Ireland\t\t", +"NMI\tc\tBacteria collection of National Institute of Public Health, National Medicines Institute, Poland\t\t", +"NMID\ts\tNational Museum of Ireland\t\t", +"NMK\ts\tNational Museums of Kenya\t\t", +"NMKE\ts\tNational Museum of Kenya\t\t", +"NMKL\ts\tNational Museum of Malaysia\t\t", +"NML\tc\tNational Microbiology Laboratory, Public Health Agency of Canada\tNML-HCCC", +"NMLS\ts\tNatur-Museum Luzern\t\t", +"NMLU\ts\tNatur-Museum Luzern, Botany Department\t\t", +"NMMA\ts\tNantucket Maria Mitchell Association, Natural Sciences Department\t\t", +"NMMBP\ts\tNational Museum of Marine Biology and Aquarium\tMNNB-P", +"NMMH\ts\tNorth Manchurian Museum\t\t", +"NMML\ts\tNational Marine Mammal Laboratory\t\t", +"NMMNH\ts\tNew Mexico Museum of Natural History and Science\t\t", +"NMMNH:Mamm\ts\tNew Mexico Museum of Natural History and Science, Mammal collection", +"NMN\ts\tNorthamptonshire Natural History Society\t\t", +"NMND\ts\tNational Museum of Natural History, New Delhi\t\t", +"NMNH\ts\tNational Museum of Natural History, New Delhi\t\t", +"NMNHI\ts\tNational Museum of Natural History, New Delhi\t\t", +"NMNK\ts\tNational Museum of Nepal\t\t", +"NMNL\th\tNatuurmuseum Nijmegen e.o.\t\t", +"NMNS\ts\tNational Museum of Natural Science\t\t", +"NMNW\ts\tNational Museum of Namibia\t\t", +"NMNZ\ts\tNational Museum of New Zealand\t\t", +"NMNZ:AI\ts\tNational Museum of New Zealand, Insects", +"NMNZ:AM\ts\tNational Museum of New Zealand, Amphibians", +"NMNZ:AS\ts\tNational Museum of New Zealand, Spiders", +"NMNZ:CR\ts\tNational Museum of New Zealand, Crustacea", +"NMNZ:M\ts\tNational Museum of New Zealand, Molluscs", +"NMNZ:MM\ts\tNational Museum of New Zealand, Marine Mammals", +"NMNZ:OR\ts\tNational Museum of New Zealand, Birds", +"NMNZ:P\ts\tNational Museum of New Zealand, Fish", +"NMNZ:RE\ts\tNational Museum of New Zealand, Reptiles", +"NMNZ:S\ts\tNational Museum of New Zealand, Fossil Vertebrates", +"NMNZ:TS\ts\tNational Museum of New Zealand, Tissue Collection", +"NMNZ:TSA\ts\tNational Museum of New Zealand, Tissue Collection", +"NMP\ts\tNational Museum (Prague)\t\t", +"NMP\ts\tNatal Museum\t\t", +"NMPC\ts\tNational Museum Prague\tMNHP", +"NMPC:ENT\ts\tNational Museum Prague, Entomology Collection", +"NMPG\ts\tZhejiang Institute of Traditional Chinese Medicine\t\t", +"NMPG\ts\tMuseum der Natur-Gotha\t\t", +"NMPI\ts\tDivision of Plant Industry\t\t", +"NMQR\ts\tNational Museum, Bloemfontein\t\t", +"NMR\th\tSemyung University\t\t", +"NMRC\tc\tNaval Medical Research Center\t\t", +"NMRC:RDD\tc\tNaval Medical Research Center, Rickettsial Diseases Division", +"NMS\ts\tNational Museums of Scotland\tNMSZ,NSMZ,RSM,RSME", +"NMS-G\ts\tNational Museums of Scotland - Geology & Zoology\t\t", +"NMSA\ts\tNatal Museum\t\t", +"NMSL\ts\tNational Museum of Sri Lanka\t\t", +"NMSR\ts\tNaturhistorisches Museum im Thuringer Landes museum Heidecksburg zu Rudolstadt\t\t", +"NMSU\ts\tNorthwest Missouri State University, Biology Department\t\t", +"NMSU\ts\tNew Mexico State University\t\t", +"NMTC\ts\tInner Mongolia Normal University, Biology Department\t\t", +"NMTT\ts\tNational Museum and Art Gallery, Port-of-Spain\t\t", +"NMV\ts\tMuseum Victoria\tNMM", +"NMV:A\ts\tMuseum Victoria, Ichthyology", +"NMV:AV\ts\tMuseum Victoria, Entomology - Australian Voucher Specimens", +"NMV:B\ts\tMuseum Victoria, Ornithology", +"NMV:BE\ts\tMuseum Victoria, Ornithology - Eggs", +"NMV:BUP\ts\tMuseum Victoria, Buprestidae", +"NMV:C\ts\tMuseum Victoria, Mammology", +"NMV:COL\ts\tMuseum Victoria, Coleoptera", +"NMV:D\ts\tMuseum Victoria, Herpetology", +"NMV:DIP\ts\tMuseum Victoria, Diptera", +"NMV:DTB\ts\tMuseum Victoria, Ornithology - Donald Thompson Collection", +"NMV:DTD\ts\tMuseum Victoria, Herpetology - Donald Thompson Collection", +"NMV:F\ts\tMuseum Victoria, Invertebrates Collection", +"NMV:G\tb\tMuseum Victoria, DNA Products", +"NMV:H\ts\tMuseum Victoria, Hygrobatidae", +"NMV:HEM\ts\tMuseum Victoria, Hemiptera", +"NMV:HET\ts\tMuseum Victoria, Heteroptera", +"NMV:HLW\ts\tMuseum Victoria, Ornithology - H.L. White Collection", +"NMV:HYM\ts\tMuseum Victoria, Hymenoptera", +"NMV:ISO\ts\tMuseum Victoria, Isoptera", +"NMV:J\ts\tMuseum Victoria, Crustacea", +"NMV:K\ts\tMuseum Victoria, Arachnology", +"NMV:LEP\ts\tMuseum Victoria, Lepidoptera", +"NMV:MEC\ts\tMuseum Victoria, Mecoptera", +"NMV:MEG\ts\tMuseum Victoria, Megaloptera", +"NMV:NEU\ts\tMuseum Victoria, Neuroptera", +"NMV:NOH\ts\tMuseum Victoria, Northofagus Project", +"NMV:ODO\ts\tMuseum Victoria, Odonata", +"NMV:P\ts\tMuseum Victoria, Paleontology & Paleobotany", +"NMV:T\ts\tMuseum Victoria, Entomlogy Type Collection", +"NMV:TRI\ts\tMuseum Victoria, Trichoptera", +"NMV:Z\ts\tMuseum Victoria, Tissue Collection", +"NMV\ts\tNakagawa Museum at Nakagawa-cho\t\t", +"NMW\ts\tNaturhistorisches Museum, Wien\tNHMV", +"NMW\ts\tNational Museums & Galleries of Wales, Department of Biodiversity and Systematic Biology\t\t", +"NMWC\ts\tNational Museum of Wales\t\t", +"NMWZ\ts\tNational Museum of Wales\t\t", +"NMZB\ts\tNational Museum of Zimbabwe\t\t", +"NMZL\ts\tNational Museum of Zambia\t\t", +"NNA\ts\tNanning Arboretum\t\t", +"NNHMK\ts\tNational Natural History Museum of the Ukraine\t\t", +"NNKN\ts\tNoordbrabants Natuurmuseum\t\t", +"NNM\ts\tNationaal Natuurhistroisch Museum\t\t", +"NNMN\ts\tNationaal Natuurhistorisch Museum Naturalis\t\t", +"NNSU\ts\tN. I. Lobachevsky Nizhni Novgorod State University, Department of Botany\t\t", +"NO\ts\tTulane University, Department of Ecology and Evolutionary Biology\t\t", +"NOAA\ts\tNational Oceanic and Atmospeheric Administration\t\t", +"NOAA:MarFor\ts\tNational Oceanic and Atmospeheric Administration, Marine Forensics", +"NOAS\ts\tNew Orleans Academy of Science\t\t", +"NOCC\ts\tNational Orchid Conservation Center\t\t", +"NOCS-DC\ts\tNational Oceanography Center Southampton Discovery Collections\t\t", +"NODCAR\tc\tmarwa mokhtar Abd Rabo\t\t", +"NoF\tc\tThe Fungus Culture Collection of the Northern Forestry Centre\t\t", +"NOI\ts\tNanhai Oceanographic Institute\t\t", +"NOLS\ts\tUniversity of New Orleans, Biological Sciences Department\t\t", +"NOSU\ts\tNortheastern State University, Natural Sciences and Mathematics Department\t\t", +"NOT\ts\tNottingham City Natural History Museum\t\t", +"NOTM\ts\tUniversity of Nottingham, Manuscript Department\t\t", +"NOU\ts\tInstitut de Recherche pour le Developpement, Botany and Applied Ecology Department\t\t", +"NPA\ts\tNanjing Institute of Geology and Paleontology, Academia Sinica\t\t", +"NPB\ts\tNatal Parks, Game, and Fish Preservation Board, Research Section\t\t", +"NPC\ts\tNational Pusa Collection\t\t", +"NPIB\ts\tNorthwest Plateau Institute of Biology\t\t", +"NPP\tc\tN.P.P\t\t", +"NPRI\ts\tSeoul National University\t\t", +"NPS\ts\tUnited States National Park Service\t\t", +"NPSC\ts\tNorthern Prairie Science Center\t\t", +"NPT\ts\tNewport Museum and Art Gallery\t\t", +"NPWRC\ts\tNorthern Prairie Research Center\t\t", +"NR\th\tInstitute of Forest Ecology Slovak Academy of Sciences\t\t", +"NRC\tc\tDivision of Biological Sciences, National Research Council of Canada\t\t", +"NRC\ts\tNational Research Centre\t\t", +"NRCC\ts\tNational Research Council of Canada\t\t", +"NRCS\tc\tNational Reference Center for Streptococci in Aachen\t\t", +"NRIBAS\ts\tNational Research Institute of Biology, Academia Sinica\t\t", +"NRIC\tc\tNODAI Research Institute Culture Collection\t\t", +"NRL\tc\tNeisseria Reference Laboratory\t\t", +"NRM\ts\tSwedish Museum of Natural History\t\t", +"NRN\ts\tNairn Literary Society Library, Public Library\t\t", +"NRNZ\ts\tNorthland Regional Museum\t\t", +"NRPSU\tc\tDepartment of Agro-industry, Faculty of Natural Resources\t\t", +"NRRL\tc\tAgricultural Research Service Culture Collection\t\t", +"NRRL:MOLD\tsc\tAgricultural Research Service Culture Collection, Mold collection", +"NRRL:PROK\tsc\tAgricultural Research Service Culture Collection, Prokaryotic collection", +"NRRL:YEAST\tsc\tAgricultural Research Service Culture Collection, Yeast Collection", +"NRS\ts\tNaturhistoriska Riksmuseet\t\t", +"NRWC\ts\tN. R. Whitney Collection\t\t", +"NRZM\tc\tGerman Reference Center for Meningococci\t\t", +"NS\ts\tCentral Siberian Botanical Garden\t\t", +"NSAC\ts\tNova Scotia Agricultural College, Department of Environmental Sciences\t\t", +"NSCA\ts\tNorth Scotland College of Agriculture\t\t", +"NSCNFB\tc\tNovi Sad Collection of Nitrogen Fixing Bacteria\t\t", +"NSCPM\tc\tNational State Collection of Pathogenic Microorganisms\t\t", +"NSDA\ts\tNevada Division of Agriculture\t\t", +"NSK\ts\tSiberian Central Botanical Garden, Laboratory for Plant Systematics and Floristic Genesis\t\t", +"NSM\ts\tNova Scotia Museum of Natural History\t\t", +"NSM\ts\tSun Yat-Sen Tomb and Memorial Park Commission\t\t", +"NSM\ts\tNSM-PV, National Science Museum\t\t", +"NSMC\ts\tNova Scotia Museum\t\t", +"NSMC\ts\tNevada State Museum\t\t", +"NSMHS\ts\tNevada State Museum and Historical Society\t\t", +"NSMK\ts\tNational Science Museum\t\t", +"NSMT\ts\tNational Museum of Nature and Science, Tokyo\t\t", +"NSMW\ts\tNaturwissenschftlich Sammlung, Museum Wiesbaden\t\t", +"NSNR\ts\tNova Scotia Department of Natural Resources\t\t", +"NSPM\ts\tNova Scotia Museum of Natural History\t\t", +"NSRF\ts\tNova Scotia Research Foundation\t\t", +"NSS\ts\tUniversity of Liverpool Botanic Gardens\t\t", +"NSU\ts\tNortheastern State University, Biological Collections\t\t", +"NSUL\ts\tNorthwestern State University of Louisiana\t\t", +"NSW\ts\tRoyal Botanic Gardens\t\t", +"NSWA\ts\tNew South Wales Department of Agriculture\t\t", +"NSWF\ts\tState Forests of New South Wales\t\t", +"NSWGS\ts\tGeological Survey of New South Wales\t\t", +"NSYU\ts\tNational Sun Yat-sen University\t\t", +"NT\ts\tDepartment of Natural Resources, Environment and the Arts\t\t", +"NTCCI\tc\tCulture Collection, Microbiology and Cell Biology Laboratory\t\t", +"NTDPIF\ts\tNorthern Territory Department of Primary Industry and Fisheries\t\t", +"NTLN\ts\tCounty Record Office, County Archives Department\t\t", +"NTM\ts\tMuseum and Art Gallery of the Northern Territory\t\t", +"NTM\ts\tMuseum d'Histoire Naturelle de Nantes\t\t", +"NTN\ts\tCentral Museum and Art Gallery\t\t", +"NTNU\ts\tNational Taiwan Normal University\tNTNUB", +"NTNU-VM\ts\tNorwegian University of Science and Technology, Museum of Natural History and Archaeology\t\t", +"NTOU\tsc\tInstitute of Marine Biology, National Taiwan Ocean University\t\t", +"NTS\ts\tNevada Operations Office, U.S. Department of Energy\t\t", +"NTSC\ts\tUniversity of North Texas, Biological Sciences Department\t\t", +"NTUC\ts\tNational Taiwan University\t\t", +"NTUF\ts\tNational Taiwan University, Forestry Department\t\t", +"NTUM\ts\tNational Taiwan University\t\t", +"NTUMA\ts\tNational Taiwan University\t\t", +"NU\tc\tDepartment of Microbiology, Faculty of Science\t\t", +"NU\ts\tUniversity of Natal, School of Botany and Zoology\t\t", +"NUA\tc\tDepartment of Microbiology, National University of Athens\t\t", +"NUM\ts\tNagoya University\t\t", +"NUOL\ts\tNational University of Laos\t\t", +"NUSDM\tc\tDepartment of Microbiology, National University of Singapore\t\t", +"NUSMBS\ts\tNiigata University, Sado Marine Biological Station\t\t", +"NUV\ts\tNorwich University, Biology and Life Sciences Department\t\t", +"NUVC\ts\tNortheastern University, Vertebrate Collection\t\t", +"NVDA\ts\tNevada State Department of Agriculture\t\t", +"NVMC\ts\tNevada State Museum\t\t", +"NVRL\ts\tNaturforschende Verein in Riga\t\t", +"NVRW\ts\tNaturhistorisches Verein der Preussische Rheinland und Westfalens\t\t", +"NWAU\ts\tNorth-West Agricultural University\t\t", +"NWC\ts\tUniversity of Northern Iowa, Nixon Wilson Collection\t\t", +"NWC\tb\tNational Willows Collection\t\t", +"NWFC\tsb\tNorthwest University of Agriculture Forestry Science & Technology\t\t", +"NWH\ts\tNorfolk Museums and Archaeology Service, Natural History Department\t\t", +"NWK\ts\tNewark District Council Museum\t\t", +"NWMSU\ts\tNorthwest Missouri State University\t\t", +"NWOSU\ts\tNorthwestern Oklahoma State University, Biology Department\t\t", +"NWSW\ts\tNaturwissenschaftliche Sammlungen der Stadt Winterthur\t\t", +"NWT\ts\tHarper Adams Agricultural College\t\t", +"NWTC\ts\tNorthwest Normal University\t\t", +"NWU\ts\tNorthwestern University, Botany Department\t\t", +"NWUB\ts\tNorthwest Normal University, Biology Department\t\t", +"NX\ts\tUniversidade do Estado de Mato Grosso - Campus de Nova Xavantina, Departamento de Ciencias Biologicas\t\t", +"NXAC\ts\tNingxia Agricultural College\t\t", +"NXF\ts\tNingxia Academy of Agriculture and Forestry Sciences\t\t", +"NY\ts\tNew York Botanical Garden\t\t", +"NYA\ts\tNanyue Arboretum\t\t", +"NYAS\ts\tSilvicultural Research Station\t\t", +"NYBG\ts\tNew York Botanical Garden\t\t", +"NYS\ts\tNew York State Museum\t\t", +"NYSM\ts\tNew York State Museum\t\t", +"NYZS\ts\tNew York Zoological Society\t\t", +"NZAC\ts\tNew Zealand Arthropod Collection\tLCR:NZAC", +"NZCS\ts\tUniversity, National Zoological Collection of Suriname\t\t", +"NZFRI\ts\tNew Zealand Forest Research Institute Limited\t\t", +"NZFS\tc\tForest Research Culture Collection\t\t", +"NZG\ts\tNational Zoological Gardens of South Africa\t\t", +"NZOI\ts\tNew Zealand Oceanographic Institute\t\t", +"NZRD\tc\tNew Zealand Reference Culture Collection of Microorganisms, Dairy Section\t\t", +"NZRM\tc\tNew Zealand Reference Culture Collection, Medical Section\t\t", +"NZRP\tc\tNew Zealand Reference Culture Collection and Soil Section\t\t", +"NZSI\ts\tZoological Survey of India, National Zoological Collection\t\t", +"O\ts\tBotanical Museum, Natural History Museum, Oslo\t\t", +"OAC\ts\tOAC Herbarium, Biodiversity Institute of Ontario\tUOG:OAC", +"OAKL\ts\tOakland Museum of California, Natural Sciences Department\t\t", +"OAMB\ts\tOpen Air Museum of Ethnography and Natural Sciences\t\t", +"OAX\ts\tInstituto Politecnico Nacional (CIIDIR-Oax., I.P.N.)\t\t", +"OAXM\ts\tCentro Interdisciplinario de Estudios, Coleccion Mastozoologica (Mexico)\t\t", +"OB\th\tStation Umwelt- und Natur Oberhausen\t\t", +"OBG\ts\tThe Oman Botanic Garden\t\t", +"OBI\ts\tCalifornia Polytechnic State University, Biological Sciences Department\t\t", +"OBPF\ts\tPlanting Fields Arboretum State Historic Park\t\t", +"OC\ts\tOberlin College, Biology Department\t\t", +"OCHA\ts\tOchanomizu University\t\t", +"OCLA\ts\tUniversity of Science and Arts of Oklahoma\t\t", +"OCM\tc\tOregon Collection of Methanogens\t\t", +"OCNF\ts\tOchoco National Forest\t\t", +"OCSA\ts\tVeterinary Research Institute\t\t", +"OCU\th\tOklahoma City University\t\t", +"ODAC\ts\tOregon Department of Agriculture\t\t", +"ODU\ts\tOld Dominion University, Department of Biological Sciences\t\t", +"OFC\ts\tOrielton Field Centre\t\t", +"OGDF\ts\tForest Service Region 4, USDA\t\t", +"OGL\tb\tOcean Genome Legacy\t\t", +"OGL:OGR\tb\tOcean Genome Legacy, Ocean Genome Resource", +"OGU\ts\tOdesskij Gosudarstvennij Universitet\t\t", +"OH\ts\tAgricultural Museum of Praha\t\t", +"OHBR\ts\tOntario Hydro\t\t", +"OHHI\th\tOrel State University\t\t", +"OHM\ts\tOldham Microscopical and Natural History Society\t\t", +"OHN\ts\tRegionherbariet i Oskarshamn\t\t", +"OHSC\ts\tOhio Historical Society\t\t", +"OKA\ts\tOksky State Biosphere Reserve\t\t", +"OKAY\ts\tOkayama University of Science, Department of Biosphere-Geosphere System Science\t\t", +"OKL\ts\tUniversity of Oklahoma, Botany and Microbiology Department/ Oklahoma Biological Survey\t\t", +"OKLA\ts\tOklahoma State University, Botany Department\t\t", +"OL\ts\tPalacky University, Botany Department\t\t", +"OLAN\ts\tMinisterio de Recursos Naturales\t\t", +"OLD\ts\tUniversitat Oldenburg\t\t", +"OLDM\ts\tLibraries, Art Galleries and Museums\t\t", +"OLDS\ts\tOlds College, Horticulture Department\t\t", +"OLE\ts\tOundle School, Biology Department\t\t", +"OLM\ts\tVlastivedne muzeum v Olomouci\t\t", +"OLML\ts\tOberoesterreichisches Landesmuseum\t\t", +"OLP\ts\tUniverzity Palackeho, Katedra biologie\t\t", +"OLS\th\tUniversity of Warmia and Mazury\t\t", +"OLTC\ts\tTeachers Training College, Botany Department\t\t", +"OLV\ts\tOlivet College, Biology Department\t\t", +"OLYM\th\tOlympic National Park\t\t", +"OM\ts\tOtago Museum\t\t", +"OMA\ts\tUniversity of Nebraska Omaha, Biology Department\t\t", +"OMC\ts\tCatalogues in Otago Museum\t\t", +"OMC\ts\tMills College, Biology Department\t\t", +"OMJ\ts\tOkresni muzeum a galerie\t\t", +"OMKH\ts\tOblastni muzeum Kutna Hora\t\t", +"OMNH\ts\tOsaka Museum of Natural History\t\t", +"OMNH\ts\tOklahoma Museum of Natural History\t\t", +"OMNHN\ts\tThe Sam Noble Oklahoma State Museum of Natural History\t\t", +"OMNHO\ts\tOsaka Museum of Natural History\t\t", +"OMNO\ts\tOklahoma Museum of Natural History\t\t", +"OMNZ\ts\tOtago Museum\t\t", +"OMP\ts\tPolabske muzeum v Podebradech\t\t", +"OMPB\ts\tOsservatorio per le Malattie delle Piante per la Regione Emilia-Romagna\t\t", +"OMPG\ts\tOsservatorio per le Malattie delle Piante per le Province di Genova e La Spezia\t\t", +"OMPS\ts\tOsservatorio per le Malattie delle Piante per la Sardegna\t\t", +"OMSK\th\tOmsk Pedagogical Univeristy\t\t", +"OMSKM\ts\tOmsk State Agrarian University, Department of Forestry and Plant Conservation\t\t", +"OMUB\ts\tOndokuz Mayis University, Biology Department\t\t", +"ON\ts\tOman Natural History Museum\t\t", +"ONNC\ts\tOffice de la Recherche Scientifique et Technique d'Outre-Mer\t\t", +"ONP\ts\tOlympic National Park\t\t", +"ONPC\ts\tOlympic National Park\t\t", +"OOM\ts\tKameyama Botanical Garden\t\t", +"OP\ts\tSilesian Museum\t\t", +"OPANM\ts\tOtdel Paleontologii i Biostratigrafii Akademii Nauk Moldovkoi Republiki\t\t", +"OPM\ts\tOkinawa Prefectual Museum\t\t", +"ORE\ts\tUniversity of Oregon, Biology Department\t\t", +"OREB\ts\tKarolinska Hoegre Allmaenna Laeroverket\t\t", +"ORI\ts\tOcean Research Institute\t\t", +"ORIS\ts\tInstitute of Steppe of the Ural branch of Russian Academy of Sciences\t\t", +"ORIT\ts\tUniversity of Tokyo\t\t", +"ORM\ts\tMusee des Sciences Naturelles, Departement de Botanique\t\t", +"ORS\tc\tCulture Collection of the Laboratory of Soil Microbiology, ORSTOM\t\t", +"ORSAY\tsb\tUniversite Paris-Sud - Parc Botanique de Launay\t\t", +"ORSC\ts\tOffice de la Recherche Scientifique et Technique d'Outre-Mer\t\t", +"ORST\ts\tOffice de la Recherche Scientifique et Technique d'Outre-Mer\t\t", +"ORSTOM\ts\tOffice de la Recherche scientifique et Technique Outre-mer\t\t", +"ORT\ts\tInstituto Canario de Investigaciones Agrarias (ICIA)\t\t", +"ORTN\ts\tOrton Hall\t\t", +"ORU\ts\tOral Roberts University, Biology Department\t\t", +"OS\ts\tOhio State University\t\t", +"OS\ts\tOregon State University\t\t", +"OSA\ts\tOsaka Museum of Natural History\t\t", +"OSAC\ts\tOregon State Arthropod Collection\t\t", +"OSAL\ts\tOhio State University Acarology Laboratory\t\t", +"OSB\ts\tSociety of Botanists\t\t", +"OSBU\ts\tUniversitat Osnabruck, Spezielle Botanik\t\t", +"OSC\ts\tOregon State University, Botany and Plant Pathology Department\t\t", +"OSEC\ts\tK.C Emerson Museum\t\t", +"OSH\ts\tUniversity of Wisconsin Oshkosh, Biology and Microbiology Department\t\t", +"OSI\ts\tOrdnance Survey of Ireland\t\t", +"OSM\ts\tOstravske muzeum\t\t", +"OSM\ts\tOhio State University Museum\t\t", +"OSMC\ts\tSt. Martin's College, Biology Department\t\t", +"OSN\ts\tMuseum am Schoelerberg, Natur und Umwelt\t\t", +"OSTR\th\tUniversity of Ostrava\t\t", +"OSU\ts\tOhio State University\t\t", +"OSU\ts\tOklahoma State University, Collection of Vertebrates\t\t", +"OSUC\ts\tOregon State University\t\t", +"OSUF\ts\tOregon State University, Department of Wood Science and Engineering\t\t", +"OSUFW\ts\tOregon State University, Department of Fisheries and Wildlife Mammal Collection\t\t", +"OSUMZ\ts\tOhio State University, Museum of Biological Diversity\t\t", +"OSUO\ts\tOregon State University, School of Oceanography\t\t", +"OSUS\ts\tOklahoma State University\t\t", +"OSW\th\tState University of New York at Oswego\t\t", +"OSWY\ts\tOswestry Museum\t\t", +"OTA\ts\tUniversity of Otago, Botany Department\t\t", +"OTF\ts\tCanadian Forest Service\t\t", +"OTM\ts\tOtago Museum\t\t", +"OTM\ts\tOld Trail Museum\t\t", +"OTSC\ts\tOrganization for Tropical Studies\t\t", +"OTT\ts\tUniversity of Ottawa, Biology Department\t\t", +"OU\ts\tFossil Catalgoue in the Geology Museum\t\t", +"OUA\ts\tUniversite de Ouagadougou\t\t", +"OULU\ts\tUniversity of Oulu, Biology Department\t\t", +"OUM\ts\tOxford University Museum of Natural History\tOUMNH", +"OUPR\ts\tUniversidade Federal de Ouro Preto, Campus Universitario\t\t", +"OUSM\ts\tOklahoma University Stovall Museum\t\t", +"OUT\tc\tDepartment of Biotechnology\t\t", +"OUVC\ts\tOhio University Vertebrate Collection\t\t", +"OVMB\ts\tOkresni vlastivedne muzeum\t\t", +"OWU\ts\tOhio Wesleyan University, Botany-Microbiology Department\t\t", +"OXD\ts\tWadham College\t\t", +"OXF\ts\tUniversity of Oxford, Department of Plant Sciences\t\t", +"OXM\ts\tMagdalen College Library\t\t", +"P\ts\tHerbier National de Paris\tP", +"PA\th\tUniversidade Federal do Oeste do Para\t\t", +"PAC\ts\tPennsylvania State University, Biology Department\t\t", +"PACA\ts\tInstituto Anchietano de Pesquisas/UNISINOS\t\t", +"PACMA\ts\tPennsylvania State University, Biology Department\t\t", +"PAD\ts\tUniversita degli Studi di Padova, Centro Interdipartimentale Musei Scientifici\t\t", +"PADA\ts\tPennsylvania Department of Agriculture\t\t", +"PAE\ts\tStiftung Herbarium Paul Aellen, Universitat Basel\t\t", +"PAL\ts\tUniversita degli Studi di Palermo, Dipartimento de Scienze Botaniche\t\t", +"PALEON\ts\tWyoming Dinosaur International Society\t\t", +"PAM\ts\tPennsylvania Department of Agriculture\t\t", +"PAMC\tc\tPolar and Alpine Microbial Collection\t\t", +"PAMG\ts\tEmpresa de Pesquisa Agropecuaria de Minas Gerais (EPAMIG), Departamento de Pesquisa\t\t", +"PAMP\ts\tUniversidad de Navarra, Departamento de Botanica\t\t", +"PAMUH\th\tPamukkale University\t\t", +"PAN\ts\tPanjab University, Botany Department\t\t", +"PAP\ts\tMusee de Tahiti et des Iles\t\t", +"PAR\ts\tMuseo de Ciencias Naturales y Antropologicas Prof. Antonio Serrano, Departamento de Botanica\t\t", +"PARMA\ts\tUniversita degli Studi di Parma\t\t", +"PAS\ts\tJava Sugar Experimental Station\t\t", +"PASA\ts\tPasadena City College, Life Sciences Department\t\t", +"PASG\ts\tPaleontological Section of the Georgian Academy of Sciences\t\t", +"PASM\ts\tPalomar College, Life Sciences Department\t\t", +"PASSM\ts\tPeabody Academy of Science\t\t", +"PAT\ts\tMuseum National d'Histoire Naturelle\t\t", +"PAUH\ts\tUniversity of Texas-Pan American, Biology Department\t\t", +"PAUMC\ts\tPan American University, Mammal Collection\t\t", +"PAUP\ts\tPunjab Agricultural University\t\t", +"PAV\ts\tUniversita di Pavia, Dipartimento de Ecologia del Territorio\t\t", +"PAY\ts\tPaisley Philosophical Institute\t\t", +"PBB\th\tResearch Center for the Conservation of Natural Resources University and Phu An Botanic Gardens\t\t", +"PBC\tc\tPacific Bacterial Collection\t\t", +"PBF\tc\tPerum Bio Farma\t\t", +"PBH\ts\tPeterborough City Museum\t\t", +"PBL\ts\tBotanical Survey of India, Andaman & Nicobar Circle\t\t", +"PBM\ts\tMahidol University, Department of Pharmaceutical Botany\t\t", +"PBP\ts\tPatagonia Botanical Park\t\t", +"PBS\ts\tChambers Institute, Tweeddale Museum\t\t", +"PBZT\ts\tParc Botanique et Zoologique de Tsimbazaza\t\t", +"PC\ts\tMuseum National d'Histoire Naturelle\t\t", +"PCC\tc\tPasteur Culture Collection of Cyanobacteria\t\t", +"PCE\th\tHugh Nicholson and Tony Abbott Herbarium\t\t", +"PCH\ts\tPrestwich and Pilkington Botanical Society\t\t", +"PCM\ts\tPresidency College, Botany Department\t\t", +"PCM\tc\tPolish Collection of Microorganisms\t\t", +"PCMB\tb\tThe Pacific Center for Molecular Biodiversity\tBPBM:PCMB", +"PCNZ\ts\tLincoln Plant Health Station\t\t", +"PCU\ts\tMuseum National d'Histoire Naturelle\t\t", +"PCU\tc\tDepartment of Microbiology, Faculty of Pharmaceutical Sciences\t\t", +"PD\tc\tDutch Plant Protection Service, Culture Collection of Plant Pathogenic Bacteria\t\t", +"PDA\ts\tRoyal Botanic Gardens, Department of Agriculture\t\t", +"PDBK\tb\tPlant DNA Bank in Korea\t\t", +"PDD\ts\tNew Zealand Fungal and Plant Disease Herbarium\tLCR:PDD", +"PDTFAU\ts\tPaleoantropoloji Dil ve Tarih Cografya Facueltesi\t\t", +"PE\ts\tInstitute of Botany, Chinese Academy of Sciences\t\t", +"PECA\ts\tPratt Education Center and Aquarium\t\t", +"PECS\ts\tJanus Pannonius Museum, Natural History Department\t\t", +"PEFO\ts\tPetrified Forest\t\t", +"PEI\tcb\tPaul-Ehrlich-Institut\t\t", +"PEI\ts\tAgriculture and Agri-Food Canada\t\t", +"PEL\tsc\tUniversidade Federal de Pelotas, Departamento de Botanica\t\t", +"PEL:LIPP\tc\tUniversidade Federal de Pelotas, Departamento de Botanica, Laboratory Plant-Pathogen Interaction", +"PEM\ts\tBeijing Medical University, Botany Department\t\t", +"PEM\ts\tPort Elizabeth Museum\t\t", +"PEN\ts\tPenrith Museum\t\t", +"PENN\ts\tUniversity of Pennsylvania Herbarium\t\t", +"PER\th\tCity Museum\t\t", +"PERM\ts\tUniversity of Perm, Botany Department\t\t", +"PERTH\ts\tWestern Australian Herbarium\t\t", +"PERU\ts\tUniversita di Perugia, Dipartimento di Biologia Vegetale\t\t", +"PES\ts\tUniversity of Peshawar, Natural Drug Division\t\t", +"PESA\ts\tCentro Ricerche Floristiche Marche\t\t", +"PET\ts\tNational University of Peking Teachers' College\t\t", +"PEU\ts\tUniversity of Port Elizabeth, Botany Department\t\t", +"PEUFR\ts\tUniversidade Federal Rural de Pernambuco, Departamento de Biologia\t\t", +"PEY\ts\tPeking University, Biology Department\t\t", +"PFC\ts\tPfeiffer University, Biology Department\t\t", +"PFCA\ts\tPacific Forestry Centre Arthropod Reference Collection\t\t", +"PFES\ts\tPetawawa National Forestry Institute, Canadian Forest Service\t\t", +"PFI\ts\tPercy FitzPatrick Institute of African Ornithology\t\t", +"PFRA\ts\tTree Nursery\t\t", +"PFRS\ts\tPacific Southwest Forest and Range Experiment Station\t\t", +"PFSS\ts\tPetrified Forest National Park\t\t", +"PG\th\tPlant Gateway\t\t", +"PGC\tc\tPeterhof Genetic Collection of Microalgae\t\t", +"PGFA\ts\tPyatigorsk State Pharmaceutical Academy, Botany Department\t\t", +"PGL\ts\tPreussiche Geologische Landesanstalt\t\t", +"PGM\ts\tPacific Grove Museum of Natural History\t\t", +"PGMNH\ts\tPacific Grove Museum of Natural History\t\t", +"PGR\tc\tPlant Gene Resources of Canada national and international base and active collections\t\t", +"PGRC\tb\tPlant Gene Resources of Canada\t\t", +"PGRC:CN\tb\tPlant Gene Resources of Canada, Canadian National Plant Germplasm System", +"PGSC\tc\tPseudomonas Genetic Stock Center\t\t", +"PH\ts\tAcademy of Natural Sciences, Botany Department\t\t", +"PHA\ts\tPharmaceutical Society of Great Britain\t\t", +"PHARM\th\tSouthern Cross University\t\t", +"PHBL\tc\tPhilip Harris Biological Ltd.\t\t", +"PHEL\ts\tPlant Health and Environment Laboratory\t\t", +"PHEO\th\tKaradag Natural Reserve\t\t", +"PHG\ts\tPeper Harow\t\t", +"PHH\ts\tUniversity of Science, Ho Chi Minh City Vietnam National University\t\t", +"PHIL\ts\tUniversity of the Sciences in Philadelphia, Biological Sciences Department\t\t", +"PI\ts\tInstitut und Museum fuer Geologie und Palaeontologie\t\t", +"PI\ts\tUniversita di Pisa, Dipartimento di Scienze Botaniche\t\t", +"PI\ts\tPaleontological Institute\t\t", +"PIAGR\th\tUniversity of Pisa\t\t", +"PICRC\th\tPalau International Coral Reef Center\t\t", +"PIHG\ts\tFlorida Department of Agriculture and Consumer Services\t\t", +"PIHU\ts\tPaleontological Institut of Helsingfors\t\t", +"PIKN\ts\tKoronivia Research Station\t\t", +"PIMUI\ts\tPalaeontologische Institut und Museum der Universitaet in Innsbruck\t\t", +"PIMUZ\ts\tPalaontologisches Institut und Museum der Universitat Zurich\t\t", +"PIN\ts\tPhilosophical Institution of Newport\t\t", +"PIN\ts\tPaleontological Institute, Russian Academy of Sciences\t\t", +"PINN\ts\tPinnacles National Monument\t\t", +"PIR\tc\tBulgarian Research Culture Collection\t\t", +"PISR\ts\tPechora-Ilych State Reserve, Russia\t\t", +"PIUU\ts\tPaleontological Institut, University of Uppsala\t\t", +"PKDC\ts\tDivisao de Museu de Historia Natural\t\t", +"PKM\ts\tV. G. Belinsk Pedagogical Institute of Penza\t\t", +"PL\ts\tZapadoceske muzeum\t\t", +"PLAT\th\tState University of New York, College at Plattsburgh\t\t", +"PLES\th\tPlyos State Museum\t\t", +"PLFV\ts\tPrincipality of Liechtenstein\t\t", +"PLH\ts\tPlymouth City Museum and Art Gallery\t\t", +"PLP\th\tInstitute of Himalayan Bioresource Technology\t\t", +"PLU\th\tPacific Lutheran University\t\t", +"PLY\tsc\tPlymouth Institution and Athenaeum\t\t", +"PLYMOUTH\tc\tPlymouth Culture Collection\t\t", +"PLYP\ts\tUniversity of Plymouth, Department of Biological Sciences\t\t", +"PM\ts\tPeabody Essex Museum, Natural History Department\t\t", +"PM\ts\tPratt Museum\t\t", +"PM\ts\tPutnam Museum of History and Natural Science\t\t", +"PMA\ts\tProvincial Museum of Alberta\t\t", +"PMA\ts\tUniversidad de Panama\t\t", +"PMAA\ts\tPalaeontological Collections, Provincial Museum and Achieves of Alberta\t\t", +"PMAE\ts\tRoyal Alberta Museum\t\t", +"PMAG\ts\tPerth Museum and Art Gallery\t\t", +"PMAM\ts\tBeijing Natural History Museum\t\t", +"PMAU\ts\tPeterborough Museum and Art Gallery\t\t", +"PMB\ts\tPrirodnjacki Muzej Srpske Zemije\t\t", +"PMBC\ts\tPhuket Marine Biological Centre\t\t", +"PMFP\ts\tPapeete Museum\t\t", +"PMG\ts\tHorto Florestal\t\t", +"PMG\ts\tPaisley Museum of Geological Collection\t\t", +"PMH\ts\tCity Museum and Records Office\t\t", +"PMHPS\ts\tPortsmouth Philosophical Society\t\t", +"PMHU\ts\tPalaontologisches Museum\t\t", +"PMIG\ts\tPhyletisches Museum\t\t", +"PMJ\ts\tPhyletisches Museum\t\t", +"PMK\ts\tPugachev Regional Museum\t\t", +"PMK\ts\tPodunajske muzeum\t\t", +"PMNH\ts\tPakistan Museum of Natural History\t\t", +"PMNH\ts\tPeabody Museum of Natural History\t\t", +"PMNH\ts\tPratt Museum of Natural History\t\t", +"PMQ\ts\tPublic Museum\t\t", +"PMR\ts\tPrirodoslovni muzej Rijeka\t\t", +"PMS\ts\tPrirodonamen Muzej Skopje\t\t", +"PMS\ts\tPacific Marine Station\t\t", +"PMS\ts\tPeabody Essex Museum\t\t", +"PMSD\ts\tPettigrew Museum\t\t", +"PMSL\ts\tSlovenian Museum of Natural History (Prirodosloveni Muzej Slovenije)\t\t", +"PMSP\ts\tPrefeitura do Municipio de Sao Paulo, Departamento de Parques e Areas Verdes\t\t", +"PMU\ts\tPaleontological Museum of Undory\t\t", +"PMU\ts\tPaleontological Museum of Uppsala\t\t", +"PMV\ts\tProvincial Museum\t\t", +"PNBG\ts\tUniversity of the Philippines\t\t", +"PNCM-BIOTECH\tc\tPhilippine National Collection of Microorganisms\t\t", +"PND\th\tDr. Shivaram Karantha Pilikula Nisarga Dhama\t\t", +"PNG\ts\tDivision of Primary Industry\t\t", +"PNGM\ts\tNational Museum and Art Gallery, Port Moresby\t\t", +"PNH\ts\tPhilippine National Herbarium\t\t", +"PNICMM-INP\ts\tInstituto Nacional de la Pesca (Mexico)\t\t", +"PNL\ts\tPolytechnic of North London, Food and Biological Sciences Department\t\t", +"PNM\ts\tPhilippine National Museum\t\t", +"PNPC\ts\tChickasaw National Recreational Area [formerly Platt National Park]\t\t", +"PNZ\ts\tPenlee House Museum\t\t", +"PO\ts\tUniversidade do Porto, Departamento de Botanica\t\t", +"PO\ts\tCollection of the Zoological Institute of the Russian Academy of Sciences\t\t", +"POFS\ts\tForest Service, USDA\t\t", +"POKM\ts\tPenza Regional Local History Museum\t\t", +"POKM\ts\tPerm Regional Lore Museum\t\t", +"POL-F\ts\tPollichia, Pfalzmuseum fur Naturkunde Thallichtenberg\t\t", +"POLL\ts\tPfalzmuseum fuer Naturkunde\t\t", +"POM\ts\tPomona College\t\t", +"POP\ts\tTatranske muzeum v Poprade\t\t", +"POR\ts\tUniversita degli Studi di Napoli\t\t", +"PORE\ts\tPoint Reyes National Seashore\t\t", +"PORT\ts\tBioCentro-UNELLEZ\t\t", +"PORUN\ts\tUniversita degli Studi di Napoli, Dip Ar Bo Pa Ve - Sezione Botanica\t\t", +"POZ\ts\tAdam Mickiewicz University, Department of Plant Taxonomy\t\t", +"POZG\ts\tAdam Mickiewicz University, Department of Geobotany\t\t", +"POZM\ts\tAdam Mickiewicz University, Department of Plant Ecology and Environment Protection\t\t", +"POZNB\ts\tAgricultural Academy, Botany Department\t\t", +"POZW\ts\tAdam Mickiewicz University\t\t", +"PPC\th\tPalawan State University\t\t", +"PPCC\tc\tPlant Pathology Culture Collection\t\t", +"PPCC\ts\tPlant Protection Centre Collection\t\t", +"PPCD\ts\tWest Virginia Department of Agriculture\t\t", +"PPDD\ts\tMinistry of Agriculture\t\t", +"PPFI\ts\tPakistan Forest Institute\t\t", +"PPHM\ts\tPanhandle-Plains Historical Museum\t\t", +"PPI\ts\tNational Pingtung University of Science and Technology, Department of Forestry\t\t", +"PPIHAS\tc\tPlant Protection Institute, Centre for Agricultural Research, Hungarian Academy of Sciences\tPPIHAS", +"PPIU\ts\tM. Utemisov Western Kazakhstanian State University, V. V. Ivanov Department of Botany\t\t", +"PPKMI\tc\tPlant Production Technology Department, Faculty of Agricultural Technology\t\t", +"PPKU1\tc\tDepartment of Plant Pathology, Faculty of Agriculture, Thailand\t\t", +"PPKU2\tc\tDepartment of Plant Pathology, Faculty of Agriculture, Thailand\t\t", +"PPKU3\tc\tDepartment of Plant Pathology, Faculty of Agriculture, Thailand\t\t", +"PPKU4\tc\tDepartment of Plant Pathology, Faculty of Agriculture, Thailand\t\t", +"PPKU5\tc\tDepartment of Plant Pathology, Faculty of Agriculture, Thailand\t\t", +"PPKU6\tc\tDepartment of Plant Pathology, Faculty of Agriculture, Thailand\t\t", +"PPL\ts\tAgricultural Development and Advisory Service, Harpenden Laboratory\t\t", +"PPNP\ts\tPoint Pelee National Park\t\t", +"PPPO\ts\tPusat Penelitian dan Pengembangan Oseanologi\t\t", +"PPPPB\tc\tARC-Plant Protection Research Institute, Plant Pathogenic and Plant Protecting Bacteria\t\t", +"PPRI\tc\tARC-Plant Protection Research, National Collection of Fungi: Culture Collection\t\t", +"PPRL\th\tUSDA-ARS Poisonous Plant Research Lab\t\t", +"PPRZ\ts\tPlant Protection Research Institute\t\t", +"PPSIO\ts\tP. P. Shirshov Institute of Oceanology\t\t", +"PPU\th\tPerm State Teacher Training University\t\t", +"PQFC\tb\tPhu Qui's Fruit Tree Center-Vietnam\t\t", +"PR\ts\tNational Museum in Prague, Department of Botany\t\t", +"PRA\ts\tInstitute of Botany, Academy of Sciences\t\t", +"PRB\ts\tPrague Botanical Garden\t\t", +"PRC\ts\tCharles University, Botany Department\t\t", +"PRE\ts\tNational Botanical Institute - Pretoria\t\t", +"PREM\ts\tSouth African National Collection of Fungi Herbarium\t\t", +"PRF\ts\tSouth African Forestry Research Institute, Environment Affairs Department\t\t", +"PRG\ts\tUniversidad Nacional Pedro Ruiz Gallo\t\t", +"PRH\ts\tPerthshire Society of Natural Science\t\t", +"PRI\ts\tCollege of Eastern Utah, Biology Department\t\t", +"PRICO\ts\tUniversity of Puerto Rico\t\t", +"PRL\tc\tPrairie Regional Laboratory\t\t", +"PRM\ts\tNational Museum, Mycological Department\t\t", +"PROIMI\tc\tPlanta Piloto de Procesos Industriales Microbiologicos\t\t", +"PRU\ts\tUniversity of Pretoria, Botany Department\t\t", +"PRV\ts\tPorvoo Museum of Natural History\t\t", +"PSAE\ts\tAlberta Environmental Centre\t\t", +"PSGB\ts\tUniversity of Bradford, Pharmacy Department\t\t", +"PSK\th\tPskov State University\t\t", +"PSM\ts\tUniversity of Puget Sound, James R. Slater Museum of Natural History\t\t", +"PSO\ts\tUniversidad de Narino\t\t", +"PSP\ts\tParasitic Seed Plants\t\t", +"PSS\ts\tPhilosophical Society of Southampton\t\t", +"PSS\ts\tPaleontology and Stratigraphic Section of the Geological Institute of the Mongolian Academy of Sciences\t\t", +"PSU\ts\tPrince of Songkla University, Biology Department\t\t", +"PSU\ts\tPortland State University, Vertebrate Biology Museum\t\t", +"PSU:Mamm\ts\tPortland State University, Vertebrate Biology Museum, Mammal Collection", +"PSU\ts\tPennsylvania State University\t\t", +"PSUB\ts\tUniversity of Botswana\t\t", +"PSUC\ts\tFrost Entomological Museum\t\t", +"PSUMC\ts\tPittsburg State University\t\t", +"PSY\ts\tPaisley Museum\t\t", +"PTBG\ts\tNational Tropical Botanical Garden\t\t", +"PTCC\tc\tPakistan Type Culture Collections\t\t", +"PTCCI\tc\tPersian Type Culture Collection\t\t", +"PTH\ts\tPerth Museum and Art Gallery, Herbarium\tPER", +"PTHL\ts\tLiterary and Antiquarian Society of Perth\t\t", +"PTIS\ts\tPotato Introduction Station\t\t", +"PTN\ts\tEllesmere Chambers\t\t", +"PTTC\tc\tPranakorn Teacher Training College, Department of Biology, Faculty of Science and Technology\t\t", +"PTZ\ts\tKarelian Scientific Centre, Russian Academy of Sciences\t\t", +"PU\ts\tPrinceton University\t\t", +"PU-HI\ts\tDepartment of Palaeontology, Universidad Complutense of Madrid\t\t", +"PUA\ts\tPacific Union College, Biology Department\t\t", +"PUC\ts\tBeijing University\t\t", +"PUC\ts\tNorth-West University\t\t", +"PUCMNH\ts\tPacific Union College, Museum of Natural History\t\t", +"PUCP\ts\tPunjab University\t\t", +"PUH\ts\tUniversity of the Philippines, Institute of Biology\t\t", +"PUL\ts\tPurdue University, Department of Botany and Plant Pathology\t\t", +"PUM\ts\tUniversita DI Pisa\t\t", +"PUN\ts\tPunjabi University, Botany Department\t\t", +"PUO\ts\tPortland University\t\t", +"PUP\ts\tUniversity of Peshawar, Botany Department\t\t", +"PUR\ts\tPurdue University, Department of Botany and Plant Pathology\t\t", +"PURC\ts\tPurdue University\t\t", +"PUS\ts\tPuslinch House\t\t", +"PUSC\ts\tUniversity of Southern Colorado, Life Sciences Department\t\t", +"PVB\th\tInstitute of Ecology of the Volga River Basin, Russian Academy of Science\t\t", +"PVF\tc\tPusat Veterinaria Farma\t\t", +"PVGB\tc\tPlant Virus GenBank\t\t", +"PVHR\ts\tUniversite Paris VI\t\t", +"PVL\ts\tPaleontologia de Vertebrados Lillo\t\t", +"PVNH\ts\tORSTOM\t\t", +"PVPH\ts\tPaleontolga de Vertebrados\t\t", +"PVSJ\ts\tMuseo do Ciencias Naturles\t\t", +"PW\ts\tPaleontological Collections\t\t", +"PWRC\ts\tPatuxent Wildlife Research Center\t\t", +"PWU\th\tV.G.Korolenko Poltava National Pedagogical University\t\t", +"PY\ts\tCentro de Estudios y Colecciones Biologicas para la Conservacion\t\t", +"PYCC\tc\tPortuguese Yeast Culture Collection\t\t", +"PYU\ts\tYunnan University, Laboratory of Pteridophyta\t\t", +"PZL\ts\tPenzance Library\t\t", +"PZV\ts\tPetrozavodsk State University, Department of Botany and Plant Physiology\t\t", +"Q\ts\tUniversidad Central\t\t", +"QAME\ts\tDireccion Nacional Forestal, Ministerio de Agricultura y Ganaderia\t\t", +"QAP\ts\tUniversidad Central\t\t", +"QBG\ts\tQueen Sirikit Botanic Garden\t\t", +"QC\ts\tNational Museum of Natural History, Bulawayo\t\t", +"QCA\ts\tPontificia Universidad Catolica del Ecuador, Departamento de Biologia\t\t", +"QCAZ\ts\tMuseo de Zoologia, Pontifica Universidad Catolica del Ecuador\t\t", +"QCAZ:A\ts\tMuseo de Zoologia, Pontifica Universidad Catolica del Ecuador, Amphibian Collection", +"QCAZ:R\ts\tMuseo de Zoologia, Pontifica Universidad Catolica del Ecuador, Reptile Collection", +"QCC\tc\t Qatari Culture Collection\t\t", +"QCNE\ts\tHerbario Nacional del Ecuador\t\t", +"QD\ts\tOcean University of China\t\t", +"QDC\ts\tQinghai Institute for Drug Control\t\t", +"QDPC\ts\tQueensland Department of Primary Industries\t\t", +"QDPI\ts\tQueensland Department of Primary Industries\t\t", +"QEF\ts\tUniversite Laval, Laboratoire d'ecologie forestiere\t\t", +"QF\ts\tInstitute of Forestry\t\t", +"QFA\ts\tUniversite Laval\t\t", +"QFB\ts\tLaurentian Forestry Centre, Canadian Forest Service\t\t", +"QFBE\ts\tLaurentian Forestry Centre, Canadian Forest Service\t\t", +"QFMQ\ts\tQueenstown Museum\t\t", +"QFS\ts\tUniversite Laval\t\t", +"QG\ts\tGeneral Grassland Station of Qinghai\t\t", +"QIBX\ts\tQinghai Institute of Biology\t\t", +"QIMR\ts\tQueensland Institute of Medical Research\t\t", +"QK\ts\tQueen's University, Biology Department\t\t", +"QM\ts\tQueensland Museum\t\t", +"QM\ts\tU.S. Army Natick Research and Development Center\t\t", +"QM\ts\tQueen Victoria Museum\t\t", +"QMB\ts\tQueensland Museum, Brisbane\t\t", +"QMC\ts\tQueen Mary College\t\t", +"QMEX\ts\tUniversidad Autonoma de Queretaro, Centro Universitario\t\t", +"QMOR\ts\tCollection Entomologique Ouellet-Robert\t\t", +"QMP\ts\tMusee du Quebec\t\t", +"QPAR\ts\tMinistere du Tourisme de la Chasse et de la Peche du Quebec, Laboratoire de Recherches\t\t", +"QPH\ts\tSeminaire de Quebec\t\t", +"QPIM\ts\tDepartment of Primary Industries\t\t", +"QPLS\ts\tBiblioteca Ecuatoriana Aurelio Espinosa Polit\t\t", +"QPNRA\ts\tPrograma Nacional de Regionalizacion, Ministerio de Agricultura y Ganaderia, Departamento de Ecologia\t\t", +"QRS\ts\tAustralian National Herbarium, Division of Plant Industry, CSIRO\t\t", +"QSA\ts\tInstitut de technologie agroalimentaire\t\t", +"QSMI\ts\tQueen Saovabha Memorial Institute\t\t", +"QTC\ts\tQiqihar Teachers College, Biology Department\t\t", +"QUA\ts\tQinghai University, Agriculture Department\t\t", +"QUC\ts\tUniversite Laval, Departement de biologie\t\t", +"QUE\ts\tComplexe scientifique\t\t", +"QUSF\ts\tUniversidad San Francisco de Quito, Biology Department\t\t", +"QVG\ts\tQueen Victoria Museum\t\t", +"QVM\ts\tQueen Victoria Museum\t\t", +"QVMS\ts\tQueen Victoria Memorial Museum\t\t", +"QWA\ts\tUniversity of the North, Qwa Qwa Campus\t\t", +"QYTC\ts\tQingyang Teachers College, Biology Department\t\t", +"R\ts\tUniversidade Federal do Rio de Janeiro, Departamento de Botanica\t\t", +"R\ts\tDepartamento de Geologia, Universidad de Chile\t\t", +"RAB\ts\tInstitut Scientifique, Departement de Botanique et d'Ecologie Vegetale\t\t", +"RAF\ts\tMyanmar Forest Herbarium\t\t", +"RAM\ts\tRamsey Public Library\t\t", +"RAM\ts\tRoyal Alberta Museum\t\t", +"RAME\ts\tRoyal Albert Memorial Museum\t\t", +"RAMK\ts\tRamkhamhaeng University, Biology Department\t\t", +"RAMM\ts\tRoyal Albert Memorial Museum, Leisure and Tourism Department\t\t", +"RANG\ts\tYangon University\t\t", +"RANK\th\tResearch Center of Agriculture and Natural Resources of Kermanshah province\t\t", +"RARS\ts\tRegina Research Station\t\t", +"RAS\ts\tUnion of Burma Applied Research Institute, Pharmaceutical Department\t\t", +"RAU\ts\tLaboratoire de Biologie Vegetale\t\t", +"RAW\ts\tPakistan Agricultural Research Council\t\t", +"RB\ts\tJardim Botanico do Rio de Janeiro\t\t", +"RBCM\ts\tRoyal British Columbia Museum\t\t", +"RBCM:Mamm\ts\tRoyal British Columbia Museum, Mammal Collection", +"RBE\ts\tUniversidade Federal Rural do Rio de Janeiro\t\t", +"RBF\tc\tRaiffeisen Bioforschung\t\t", +"RBINS\ts\tRoyal Belgian Institute of Natural Sciences\t\t", +"RBR\ts\tUniversidade Federal Rural do Rio de Janeiro, Departamento de Botanica\t\t", +"RBS\ts\tRoyal Botanic Society\t\t", +"RBY\ts\tEast Divisional Library\t\t", +"RCAM\ts\tRutgers University, Biology Department\t\t", +"RCAT\tc\tRegional Collection of Animal Viruses and Tissue Cultures\t\t", +"RCB\tc\tRIKEN Cell Bank\t\t", +"RCC\tc\tRoscoff Culture Collection\t\t", +"RCDM\tc\tRepublican Centre for Deposition of Microorganisms of the National Academy of Sciences and Ministry of Education and Science of Armenia\t\t", +"RCHM\ts\tRochdale Museum Service\t\t", +"RCHP\ts\tRochdale Equitable Pioneers' Memorial Museum\t\t", +"RCMC\ts\tRockford College\t\t", +"RCN\ts\tRichmond Naturalists' Field Club\t\t", +"RCR\ts\tRochester Public Museum\t\t", +"RCS\ts\tRoyal College of Surgeon's Museum\tRCSM", +"RCSL\ts\tRoyal College of Surgeons\t\t", +"RCVC\th\tUniversidad Nacional de Rio Cuarto\t\t", +"RDAF\ts\tResearch Department South East Asian Fisheries Development Centre\t\t", +"RDG\ts\tReading Museum and Archive Service\t\t", +"RDS\ts\tRoyal Dublin Society\t\t", +"RE\ts\tLiaoning Reed Science Institute\t\t", +"RED\ts\tUniversity of Redlands, Biology Department\t\t", +"REDM\ts\tReading Museum and Archive Service\t\t", +"REED\th\tReed College\t\t", +"REG\ts\tUniversitaet Regensburg, Regensburgische Botanische Gesellschaft\t\t", +"REGGIO\th\tUniversita Mediterranea di Reggio Calabria\t\t", +"RELC\ts\tINIFAP-SAGAR\t\t", +"REN\ts\tCampus Scientifique de Beaulieu, Laboratoire de Botanique\t\t", +"RENO\ts\tUniversity of Nevada, Environmental and Resource Sciences Department\t\t", +"RENZ\ts\tUniversitaet Basel, The Swiss Orchid Foundation\t\t", +"REP\ts\tDesert Experiment Station of the W.I.R.\t\t", +"RESC\ts\tShasta College\t\t", +"RET\ts\tHerbarium Amanitarum Rooseveltensis\t\t", +"REU\ts\tUniversite de la Reunion\t\t", +"RFA\ts\tUniversidade Federal do Rio de Janeiro, Departamento de Botanica\t\t", +"RFE\ts\tRadcliffe Literary and Scientific Society Museum\t\t", +"RFFP\th\tUniversidade do Estado do Rio de Janeiro\t\t", +"RFNS\ts\tRochdale Field Naturalists' Society\t\t", +"RGM\ts\tNationaal Natuurhistorisch Museum Leiden\t\t", +"RGMC\ts\tMusee Royal de l'Afrique Centrale\t\t", +"RGY\ts\tRugby School Natural History Society Museum\t\t", +"Rh-EF\ts\tMuseum of Grannat\t\t", +"RHK\th\tSt. Berchmans College\t\t", +"RHLCY\ts\tReservoir of Heilongtan\t\t", +"RHM\ts\tPublic Reference Library\t\t", +"RHMC\ts\tRed House Museum\t\t", +"RHMD\ts\tNational Institute of Science Communication\t\t", +"RHMU\tc\tDepartment of Pathology, Faculty of Medical Science, Ramathibordi Hospital\t\t", +"RHS\tc\tPlant Pathology, The Royal Horticultural Society\t\t", +"RHT\ts\tSt. Joseph's College\t\t", +"RI\ts\tRudjer Boskovic Institute\t\t", +"RIA\tc\tThe Russia Research Institute for Antibiotics Culture Collection\t\t", +"RIB\tc\tNational Research Institute of Brewing, Tax Administration Agency\t\t", +"RIBM\tc\tResearch Institute for Brewing and Malting\t\t", +"RICK\ts\tBrigham Young University - Idaho, Department of Biology\t\t", +"RICP\tc\tCrop Research Institute\t\t", +"RIFAV\tb\tResearch Institute for Fruits and Vegetables\t\t", +"RIFFL\ts\tResearch Institute of Freshwater Fisheries\t\t", +"RIFY\tc\tInstitute of Enology and Viticulture, Yamanashi University\t\t", +"RIG\ts\tUniversity of Latvia, Department of Botany and Ecology\t\t", +"RIGB\ts\tLatvian State Center of Plant Protection\t\t", +"RIGG\ts\tUniversity of Latvia\t\t", +"RIM\ts\tL'Ecole d'Agriculture\t\t", +"RIMD\tc\tResearch Institute for Microbial Diseases, Research Center for Emerging Infectious Diseases\t\t", +"RIN\ts\tResearch Institute for Nature Management, Botany Department\t\t", +"RIOC\ts\tUniversidad Nacional de Rio Cuarto\t\t", +"RIPO\tc\tPlant Virus Collection\t\t", +"RITFC\tc\tResearch Institute for Tobacco and Fibre Crops\t\t", +"RIVE\tc\tResearch Institute for Viticulture and Enology\t\t", +"RIVE\ts\tUniversity of Wisconsin, Biology Department\t\t", +"RIY\ts\tNational Agriculture and Water Research Center\t\t", +"RIZ\ts\tInstituto de Zootecnia\t\t", +"RKT\th\tRegional Research Institute (Ayurveda)\t\t", +"RLS\ts\tRoyal Latin School\t\t", +"RM\ts\tMcGill University, Redpath Museum\t\t", +"RM\tc\tRumen Microorganisms\t\t", +"RM\ts\tRaffles Museum\t\t", +"RM\ts\tUniversity of Wyoming Herbarium\t\t", +"RMA\tc\tR. M. Alden Research Lab\t\t", +"RMBL\ts\tRocky Mountain Biological Laboratory\t\t", +"RMBR\ts\tRaffles Museum of Biodiversity Research\t\t", +"RMCA\ts\tRoyal Museum for Central Africa\t\t", +"RMDRC\ts\tRocky Mountain Dinosaur Resource Center\t\t", +"RMF\tc\tRocky Mountain Herbarium, Fungi\t\t", +"RMFM\ts\tRichmond Marine Fossils Museum\t\t", +"RMNH\ts\tNaturalis Biodiversity Center\t\t", +"RMNH:ACA\ts\tNaturalis Biodiversity Center, Acari collection", +"RMNH:AVES\ts\tNaturalis Biodiversity Center, bird collection", +"RMNH:BRA\ts\tNaturalis Biodiversity Center, brachiopod collection", +"RMNH:BRY\ts\tNaturalis Biodiversity Center, bryozoan collection", +"RMNH:COEL\ts\tNaturalis Biodiversity Center, Coelomate collection", +"RMNH:CRUS\ts\tNaturalis Biodiversity Center, crustacean collection", +"RMNH:CRUS.D\ts\tNaturalis Biodiversity Center, decapod collection", +"RMNH:INS\ts\tNaturalis Biodiversity Center, Insect collection", +"RMNH:MAM\ts\tNaturalis Biodiversity Center, Mammal collection", +"RMNH:MOL\ts\tNaturalis Biodiversity Center, mollusc collection", +"RMNH:PISC\ts\tNaturalis Biodiversity Center, fish collection", +"RMNH:POR\ts\tNaturalis Biodiversity Center, poriferan collection", +"RMNHD\ts\tNaturalis Biodiversity Center\t\t", +"RMNP\ts\tRiding Mountain National Park\t\t", +"RMRC\tb\tRegional Medical Research Centre\t\t", +"RMS\ts\tUniversity of Wyoming Herbarium\t\t", +"RMSC\ts\tRocky Mountain Forest and Range Experiment Station\t\t", +"RMSCC\tc\tRoche Molecular Systems Culture Collection\t\t", +"RMTV\th\tUniversity of Rome Tor Vergata\t\t", +"RMWC\ts\tRandolph-Macon Woman's College, Biology Department\t\t", +"RNG\ts\tUniversity of Reading\t\t", +"RNMUT\ts\tRepublic Nature Museum of Uzbekistan\t\t", +"RO\ts\tUniversita degli Studi di Roma La Sapienza, Dipartimento di Biologia Vegetale\t\t", +"ROAN\ts\tVirginia Western Community College, Biology Department\t\t", +"ROCH\ts\tRochester Academy of Science\t\t", +"ROHB\ts\tCattedra di Micologia, Dipartimento di Biologia Vegetale\t\t", +"ROIG\ts\tEstacion Experimental de Plantas Medicinales Dr. Juan T. Roig\t\t", +"ROM\ts\tRoyal Ontario Museum\t\t", +"ROM:ENT\ts\tRoyal Ontario Museum, Entomology collection", +"ROM:HERP\ts\tRoyal Ontario Museum, Herpetology collection", +"ROM:ICH\ts\tRoyal Ontario Museum, Fish collection", +"ROM:IZ\ts\tRoyal Ontario Museum, Invertebrate Zoology Collection", +"ROM:MAM\ts\tRoyal Ontario Museum, Mammal Collection", +"ROM:ORN\ts\tRoyal Ontario Museum, Ornithology Collection", +"ROME\ts\tRoyal Ontario Museum, Entomology Collection\tROM:ENT", +"ROML\ts\tNational University of Lesotho, Biology Department\t\t", +"ROMO\ts\tRocky Mountain National Park\t\t", +"RON\th\tUniversidade Federal de Rondonia\t\t", +"ROO\ts\tAgricultural Research Council-Range and Forage Institute\t\t", +"ROPA\ts\tSonoma State University, Biology Department\t\t", +"ROPV\ts\tIstituto Sperimentale per la Patologia Vegetale\t\t", +"ROST\ts\tUniversitaet Rostock\t\t", +"ROV\ts\tMuseo Civico di Rovereto\t\t", +"ROZ\ts\tStredoceske muzeum\t\t", +"RPM\ts\tReading Public Museum\t\t", +"RPMH\ts\tRoemer Pelizaeus Museum Hildesheim\t\t", +"RPN\ts\tRipon Mechanics Institute\t\t", +"RPPMC\ts\tRondeau Provincial Park\t\t", +"RPPR\ts\tInternationl Institute of Tropical Forestry\t\t", +"RPSC\ts\tRio Palenque Science Center\t\t", +"RPSP\ts\tUniversidade de Sao Paulo\t\t", +"RPTN\ts\tRepton School, Biology Department\t\t", +"RRCBI\ts\tRegional Research Centre (Ay.)\t\t", +"RRIASR\tc\tFungal Pathogens of Hevea Rubber in Sri Lanka\t\t", +"RRJ\tc\tRRL , Jammu INDIA\t\t", +"RRLB\ts\tRegional Research Laboratory\t\t", +"RRLH\ts\tRegional Research Laboratory\t\t", +"RSA\ts\tRancho Santa Ana Botanic Garden\t\t", +"RSCS\tc\tMedical Culture Collection\t\t", +"RSDR\ts\tDesert Institute, Turkmenistan Academy of Sciences\t\t", +"RSKK\tc\tRefik Saydam National Type Culture Collection-RSKK\t\t", +"RSM\ts\tRoyal Saskatchewan Museum\tSMNH", +"RSM\ts\tRoyal Scottish Museum\tNMSZ,RSME", +"RSU\th\tRyazan State University\t\t", +"RSY\ts\tButeshire Natural History Society, The Museum\t\t", +"RTE\ts\tHolmesdale Natural History Club Museum\t\t", +"RTHM\ts\tMunidipal Museum and Art Gallery\t\t", +"RTMP\ts\tRoyal Tyrell Museum of Paleontology\t\t", +"RU\ts\tUniversity of Reading, Agricultural Botany Department\t\t", +"RUBL\ts\tUniversity of Rajasthan, Botany Department\t\t", +"RUDZ\ts\tRhodes University\t\t", +"RUEB\ts\tEidgenoessische Technische Hochschule ETH\t\t", +"RUH\ts\tRhodes University, Botany Department\t\t", +"RUHV\ts\tRadford University, Biology Department\t\t", +"RUIC\ts\tRutgers University\t\t", +"RUMF\ts\tUniversity Museum, University of the Ryukyus\t\t", +"RUNYON\ts\tRobert Runyon Herbarium\t\t", +"RUPP\th\tRoyal University of Phnom Penh\t\t", +"RUSI\ts\tJ.L.B. Smith Institute of Ichthyology (formerly of Rhodes University)\t\t", +"RUSU\ts\tUniversidade Santa Ursula\t\t", +"RUT\ts\tDouglass College, Rutgers University, Biological Sciences Department\t\t", +"RUTPP\ts\tCook College, Rutgers University, Plant Pathology Department\t\t", +"RUY\ts\tMid-Staffordshire Field Club\t\t", +"RV\tc\tCollection of Leptospira Strains\t\t", +"RV\ts\tMolotov State University of Rostov, Botany Department\t\t", +"RVP\ts\tMuseo Provincial de Historia Natural de La Pampa (Argentina)\t\t", +"RWBG\ts\tRostov State University\t\t", +"RWC\ts\tState University of New York, Roosevelt Wildlife Collection\t\t", +"RWDN\ts\tUniversity of Glasgow Field Station\t\t", +"RWPM\ts\tRoger Williams Park Museum of Natural History\t\t", +"RYCC\tc\tRoseworthy Yeast Culture Collection\t\t", +"RYD\ts\tSchool of Art\t\t", +"RYU\ts\tUniversity of the Ryukyus, Biology Department\t\t", +"S\ts\tSwedish Museum of Natural History, Botany Departments\t\t", +"SA\ts\tMuseum national d'Histoire Naturelle, Laboratiore de Paleontologie\t\t", +"SAAR\ts\tZentrum fuer Biodokumentation des Saarlandes\t\t", +"SAAS\ts\tSaasveld, Port Elizabeth Technikon\t\t", +"SAB\ts\tSociety of Amateur Botanists\t\t", +"SACA\ts\tSouth-west Agricultural University\t\t", +"SACC\ts\tSt. Ambrose College\t\t", +"SACL\ts\tSanta Clara University, Biology Department\t\t", +"SACON\ts\tSalim Ali Centre for Ornithology and Natural History\t\t", +"SACS\ts\tShenyang Agricultural College\t\t", +"SACT\ts\tCalifornia State University, Biological Sciences Department\t\t", +"SAF\th\tDepartment of Agricultural and Forest Sciences\t\t", +"SAFB\ts\tUniversity of Saskatchewan, Forestry Department\t\t", +"SAFU\ts\tUniversity of San Francisco\t\t", +"SAG\tc\tSammlung von Algenkulturen at Universitat Gottingen\t\t", +"SAG\tc\tColeccion de Micoligica Laboratorio Regional, Servicio Agricola y Ganadero\t\t", +"SAIAB\tsb\tSouth African Institute of Aquatic Biodiversity\t\t", +"SAIM\ts\tSouth African Institute for Medical Research\t\t", +"SAIMR\ts\tSouth African Institute for Medical Research\t\t", +"SAITP\tc\tSchool of Pharmacy and Medical Sciences, University of South Australia\t\t", +"SAK\ts\tInstitute of Marine Geology and Geophysics, Far East Branch, Island Ecological Problems Department\t\t", +"SAKH\ts\tSakhalin Botanical Garden\t\t", +"SAL\ts\tKansas Wesleyan University, Biology Department\t\t", +"SALA\ts\tUniversidad de Salamanca, Departamento de Botanica\t\t", +"SALAF\ts\tUniversidad de Salamanca\t\t", +"SALF\ts\tSalford Royal Free Museum and Library\t\t", +"SALFM\ts\tSalford Natural History Museum, Salford City Council\t\t", +"SALLE\ts\tInstituto Geobiologico La Salle\t\t", +"SAM\ts\tSouth African Museum\tSAMK", +"SAMA\tsb\tSouth Australian Museum\tSAM", +"SAMC\ts\tIziko Museum of Capetown\t\t", +"SAMF\th\tSamford University\t\t", +"SAMU\ts\tSavaria Museum, Department of Natural History\t\t", +"SAN\ts\tForest Research Centre, Forest Department\t\t", +"SANBI\ts\tSouth African National Biodiversity Institute\t\t", +"SANC\ts\tSouth African National Collection of Insects\tNCIP", +"SANT\ts\tUniversidad de Santiago de Compostela\t\t", +"SANT:Algae\ts\tUniversidad de Santiago de Compostela, algae collection", +"SANT:Bryo\ts\tUniversidad de Santiago de Compostela, bryophyte collection", +"SANT:Lich\ts\tUniversidad de Santiago de Compostela, lichen collection", +"SANU\ts\tShaanxi Normal University, Biology Department\t\t", +"SAO\ts\tSammlung Oberli\t\t", +"SAP\ts\tHerbarium of Graduate School of Science, Hokkaido University\t\t", +"SAPA\ts\tHokkaido University Museum (Fungal collection)\t\t", +"SAPCL\ts\tSt. Andrews Presbyterian College, Biology Department\t\t", +"SAPS\ts\tHokkaido University Museum (Plant collection)\t\t", +"SAPT\th\tHokkaido University Botanic Garden\t\t", +"SAR\ts\tDepartment of Forestry\t\t", +"SARA\ts\tZemaljski Muzej Bosne I. Herzegovine\t\t", +"SARAT\ts\tDepartment of Morphology and Systematic Botany\t\t", +"SARBG\th\tSaratov State University Botanical Garden\t\t", +"SARC\ts\tRoanoke College, Biology Department\t\t", +"SARI\ts\tSakarya Agricultural Research Institute\t\t", +"SAS\ts\tSammlung Arnhardt des Museums Schloss Wilhelmsburg Schmalkalden\t\t", +"SASK\ts\tUniversity of Saskatchewan, Plant Sciences Department\t\t", +"SASSA\ts\tUniversita di Sassari, Dipartimento di Scienze del Farmaco\t\t", +"SASSC\tb\tSENDAI Arabidopsis Seed Stock Center\t\t", +"SASY\ts\tInstitute for Biological Problems of Cryolithozone\t\t", +"SAT\ts\tAngelo State University, Biology Department\t\t", +"SAU\ts\tSichuan Agricultural University, Department of Basic Courses\t\t", +"SAU\ts\tSouthern Arkansas University\t\t", +"SAUF\ts\tSichuan Agricultural University, Forestry Department\t\t", +"SAUT\ts\tSichuan Agricultural University\t\t", +"SAV\ts\tInstitute of Botany, Slovak Academy of Sciences\t\t", +"SAV:F\ts\tInstitute of Botany, Slovak Academy of Sciences, Fungal Collection", +"SAWV\ts\tSalem International University, Department of Bioscience\t\t", +"SB\ts\tSaint Bernard Abbey\t\t", +"SBBG\ts\tSanta Barbara Botanic Garden\t\t", +"SBC\ts\tUniversity of California, Biological Sciences Department\t\t", +"SBCC\ts\tSanta Barbara City College, Department of Biological Sciences\t\t", +"SBCM\ts\tSan Bernardino County Museum\t\t", +"SBDE\ts\tSino-Belgian Dinosaur expedition\t\t", +"SBG\ts\tBotanical Garden of Stavropol State University, Botany Department\t\t", +"SBH\ts\tS Blair Hedges Collection\t\t", +"SBKA\ts\tStiftssammlungen des Benediktinerstiftskrems-Munster\t\t", +"SBM\ts\tSabah Museum\t\t", +"SBM\ts\tSanta Barbara Museum of Natural History\t\t", +"SBMN\ts\tSanta Barbara Museum of Natural History\t\t", +"SBMNH\ts\tSanta Barbara Museum of Natural History\t\t", +"SBNHM\ts\tSanta Barbara Natural History Museum\t\t", +"SBP\ts\tStation Biologique de Paimpont\t\t", +"SBSC\ts\tRobert A. Vines Environmental Science Center\t\t", +"SBSFU\tc\tSchool of Biological Sciences\t\t", +"SBT\ts\tBergius Foundation\t\t", +"SBU\ts\tSaint Bonaventure University, Biology Department\t\t", +"SBUG\tc\tDepartment of Biology of the University of Greifswald\t\t", +"SBY\ts\tSalisbury and South Wiltshire Museum\t\t", +"SC\ts\tSalem College, Biology Department\t\t", +"SCA\ts\tLimbe Botanical & Zoological Gardens\t\t", +"SCAC\ts\tSouth China Agricultural College\t\t", +"SCAR\ts\tWood End Museum\t\t", +"SCARB\ts\tBoys' High School\t\t", +"SCB\ts\tStation Centrale de Boukoko\t\t", +"SCCAP\tc\tScandinavian Culture Collection of Algae and Protozoa\t\t", +"SCCBC\ts\tSelkirk College, Environmental Sciences and Technologies Department\t\t", +"SCCN\th\tScott Christian College\t\t", +"SCDH\ts\tSouth Carolina Department of Health and Environmental Control\t\t", +"SCFI\ts\tSichuan Academy of Forestry\t\t", +"SCFQ\ts\tService canadien de la faune\t\t", +"SCFS\th\tUniversity of California-Berkeley, Sagehen Creek Field Station\t\t", +"SCH\ts\tMuseum zu Allerheiligen\t\t", +"SCHG\ts\tGeorge Museum\t\t", +"SCHN\ts\tSmith College, Biological Sciences Department\t\t", +"SCIEA\ts\tSouth China Institute of Endangered Animals\t\t", +"SCL\ts\tSt. Cloud State University, Department of Biological Sciences\t\t", +"SCM\ts\tSheffield City Museums\t\t", +"SCN\ts\tSociedad de Ciencias Naturales \"La Salle\"\t\t", +"SCNHM\ts\tSouthwestern College, Natural History Museum\t\t", +"SCNU\ts\tSichuan Normal University\t\t", +"SCP\th\tSociedad Cientifica del Paraguay\t\t", +"SCPS\ts\tScarborough Philosophical and Archaeological Society Museum\t\t", +"SCR\ts\tScripps Institution of Oceanography, Herbarium\t\t", +"SCS\ts\tAgriculture and Agri-Food Canada, Semiarid Prairie\t\t", +"SCSC\ts\tSaint Cloud State University\t\t", +"SCSFRI\ts\tSouth China Sea Fisheries Research Institute\t\t", +"SCSG\th\tSouth China Sea Institute of Oceanology, Academia Sinica\t\t", +"SCSIO\ts\tSouth China Sea Institute of Oceanology, Academia Sinica\tSCSG", +"SCSM\ts\tSouth Carolina State Museum\t\t", +"SCT\ts\tFriend's School\t\t", +"SCTCC\tc\tSichuan Type Culture Collection\t\t", +"SCU\ts\tShandong Christian University\t\t", +"SCUF\ts\tUniversidade Federal de Santa Catarina\t\t", +"SCUI\th\tSuez Canal University\t\t", +"SCUM\ts\tSichuan University Museum\t\t", +"SCV\tb\tState Collection of Viruses\t\t", +"SCZ\ts\tSmithsonian Tropical Research Institute\t\t", +"SD\ts\tHerbarium, San Diego Natural History Museum\t\t", +"SDAKS\ts\tSouth Dakota State University\t\t", +"SDAU\ts\tShandong Agricultural University\t\t", +"SDC\ts\tSouth Dakota State University, Department of Biology\t\t", +"SDCM\ts\tShandong College of Traditional Chinese Medicine\t\t", +"SDFI\ts\tShandong Forestry Institute\t\t", +"SDFS\ts\tShandong Forestry School\t\t", +"SDI\ts\tSouthend Institute\t\t", +"SDM\ts\tStroud and District Museum\t\t", +"SDM\ts\tSan Diego Mesa College, Botany Department\t\t", +"SDMP\ts\tShandong Institute of Traditional Chinese Medicine and Materia Medica\t\t", +"SDN\ts\tBorough of Thamesdown Museum and Art Gallery\t\t", +"SDNCU\tcb\tThe Specimen Depository of the Graduate School of Natural Sciences, Nagoya City University\t\t", +"SDNH\ts\tMalkerns Agricultural Research Station\t\t", +"SDNHM\ts\tSan Diego Natural History Museum\tSDMC,SDNH,SDSNH", +"SDNU\ts\tShandong Normal University, Biology Department\t\t", +"SDSM\ts\tSouth Dakota School of Mines and Technology\t\t", +"SDSU\ts\tSan Diego State University\t\t", +"SDSU:Arthropods\ts\tSan Diego State University, Museum of Biodiversity Terrestrial Arthropod Collection", +"SDSU:Birds\ts\tSan Diego State University, Museum of Biodiversity Birds Collection", +"SDSU:Fish\ts\tSan Diego State University, Museum of Biodiversity Fish Collection", +"SDSU:Greenhouse\tb\tSan Diego State University, Greenhouse", +"SDSU:Herbarium\ts\tSan Diego State University, Herbarium", +"SDSU:Herps\ts\tSan Diego State University, Museum of Biodiversity Amphibians & Reptiles Collection", +"SDSU:Mammals\ts\tSan Diego State University, Museum of Biodiversity Mammal Collection", +"SDSU\ts\tSeverin-McDaniel Insect Collection\t\t", +"SDU\ts\tUniversity of South Dakota, Department of Biology\t\t", +"SEAARI\ts\tSouth Eastern Anatolian Agricultural Research Institute\t\t", +"SEAC\ts\tEstacion Experimental de Agricolas de la Campara\t\t", +"SEAMEO\tc\tSeameo-Biotrop\t\t", +"SEAN\ts\tMuseo Entomologico\t\t", +"SEBR\tc\tSanofi ELF Biorecherches\t\t", +"SECM\ts\tScience Education Center\t\t", +"SEFES\ts\tSoutheastern Forest Experiment Station\t\t", +"SEFSC\ts\tSoutheast Fisheries Science Center\t\t", +"SEFSC:MMMGL\ts\tSoutheast Fisheries Science Center, Marine Mammal Molecular Genetics Laboratory", +"SEHU\ts\tHokkaido University Insect Collection\t\t", +"SEIG\ts\tSocieta Entomologica Italiana\t\t", +"SEL\ts\tMarie Selby Botanical Gardens\t\t", +"SELU\ts\tSoutheastern Louisiana University, Biological Sciences Department\t\t", +"SEMC\ts\tSnow Entomological Museum\tKU:SEMC", +"SEMIA\tc\tRhizobium Culture Collection\t\t", +"SEMK\ts\tSnow Entomological Museum\t\t", +"SEMM\ts\tStation Experimental de la Maboke\t\t", +"SEMO\ts\tSoutheast Missouri State University, Department of Biology\t\t", +"SERC\ts\tSmithsonian Environmental Research Center\t\t", +"SERG\ts\tInstitut de Recherche Agronomique de Guinee\t\t", +"SERO\ts\tSociedad para el Estudio de los Recursos Bioticos de Oaxaca\t\t", +"SERTC\ts\tSoutheastern Regional Taxonomic Center\t\t", +"SES\ts\tSoutheastern Shanxi Teachers School, Biochemistry Department\t\t", +"SETON\ts\tPhilmont Scout Ranch, Seton Memorial Library\t\t", +"SEV\ts\tUniversidad de Sevilla, Departamento de Biologia Vegetal y Ecologia\t\t", +"SEVF\ts\tUniversidad de Sevilla, Departamento de Botanica\t\t", +"SEY\ts\tSeychelles Natural History Museum\t\t", +"SF\ts\tUniversidad Nacional del Litoral\t\t", +"SFAC\ts\tStephen F. Austin State University\t\t", +"SFB\ts\tSalgues Foundation of Brignoles for Development of Biological Sciences\t\t", +"SFC\ts\tLaboratory of Fishes\t\t", +"SFD\ts\tSheffield Galleries and Museums Trust, City Museum\t\t", +"SFDK\ts\tSarawak Forestry Department\t\t", +"SFDL\ts\tSheffield Literary and Philosophical Society\t\t", +"SFDN\ts\tSheffield Naturalists' Club\t\t", +"SFI\tb\tSlovenian Forestry Institute\t\t", +"SFPA\ts\tFundacao Estadual de Pesquisa Agropecuaria\t\t", +"SFRF\ts\tForest Service, Region 5, USDA\t\t", +"SFRP\ts\tSouthern Research Station\t\t", +"SFRS\ts\tSea Fisheries Research Station\t\t", +"SFS\ts\tUniversite de Sherbrooke, Departement de biologie\t\t", +"SFSU\ts\tSan Francisco State University, Department of Biology\t\t", +"SFT\ts\tStowlangtoft Hall\t\t", +"SFU\ts\tShanghai Fisheries University\t\t", +"SFUC\ts\tSimon Fraser University\t\t", +"SFUV\ts\tSimon Fraser University, Biological Sciences Department\t\t", +"SFV\ts\tCalifornia State University, Department of Biology\t\t", +"SFVS\ts\tSan Fernando Valley State University\t\t", +"SG\ts\tShanghai Botanical Garden\t\t", +"SGBH\ts\tMuseum of Staffordshire County\t\t", +"SGE\ts\tStamford Park Museum\t\t", +"SGEL\ts\tStalybridge Library\t\t", +"SGGS\ts\tThe Museum\t\t", +"SGGW\ts\tWarsaw University of Life Sciences\t\t", +"SGMA\ts\tUniversidade Nova de Lisboa\t\t", +"SGN\th\tSouthern Institute of Ecology\t\t", +"SGO\ts\tHerbario, Museo Nacional de Historia Natural, Santiago\t\t", +"SGSC\tc\tSalmonella Genetic Stock Centre\t\t", +"SGWG\ts\tSammlung der Sektion Geologische Wissenschaften der Ernst-Moritz-Arndt University\t\t", +"SH\ts\tAcademia Sinica\t\t", +"SHB\ts\tShanghai Baptist College\t\t", +"SHC\ts\tSacred Heart College\t\t", +"SHCP\ts\tSouthern Highlands Conservation Programme\t\t", +"SHCT\ts\tShanghai Teachers College of Technology, Biology Department\t\t", +"SHD\ts\tUniversity of Sheffield, Botany Department\t\t", +"SHDC\ts\tShanghai Institute for Drug Control\t\t", +"SHG\ts\tSohag University, Botany Department\t\t", +"SHI\ts\tHerbarium, Shihezi University\t\t", +"SHIN\ts\tShinshu University\t\t", +"SHJ\ts\tSt. John's University\t\t", +"SHM\ts\tShanghai Museum of Natural History, Botanical Department\t\t", +"SHM\ts\tSiouxland Heritage Museum\t\t", +"SHMC\ts\tLuther College, Sherman A. Hoslett Museum of Natural History\t\t", +"SHMH\ts\tUniversite l'Aurore, Musee Heude\t\t", +"SHMI\ts\tShanghai Institute of Materia Medica, Chinese Academy of Sciences, Phytochemistry Department\t\t", +"SHMU\ts\tShanghai Medical University\t\t", +"SHOR\ts\tShorter College, Biology Department\t\t", +"SHSND\ts\tNorth Dakota Heritage Center\t\t", +"SHST\ts\tSam Houston State University, Department of Biological Sciences\t\t", +"SHSU\ts\tSam Houston State University, Vertebrate Natural History Collection\t\t", +"SHTC\ts\tCalifornia State University, Biology Department\t\t", +"SHTU\ts\tShanghai Teachers University, Biology Department\t\t", +"SHY\ts\tRowley's House Museum\t\t", +"SHYAN\ts\tShropshire Archaeological and Natural History Society\t\t", +"SHYB\ts\tShrewsbury School\t\t", +"SHYL\ts\tShrewsbury School\t\t", +"SHYN\ts\tShrewsbury Natural History Society\t\t", +"SHYP\ts\tShrewsbury Public Library\t\t", +"SI\ts\tInstituto de Botanica Darwinion\t\t", +"SIAC\ts\tSichuan Institute of Agriculture\t\t", +"SIAC\ts\tAccademia dei Fisiocritici Onlus\t\t", +"SIB\ts\tSibiu Natural History Museum\t\t", +"SIBAC\ts\tSouthwest Institute of Biology\t\t", +"SIBS\th\tInstitute of Biology of the Southern Seas\t\t", +"SICH\ts\tSimpson College, Biology and Environmental Sciences Department\t\t", +"SIEMEA\ts\tSevertsov Insitute for Evolutionary Morphology and Animal Ecology\t\t", +"SIENA\ts\tUniversita di Siena, Dipartimento di Scienze Ambientali \"G. Sarfatti\"\t\t", +"SIF\ts\tSenckenbergisches Institut\t\t", +"SIFS\ts\tSichuan Forestry School\t\t", +"SIGMA\ts\tStation Internationale de Geobotanique Mediterraneenne et Alpine\t\t", +"SIIS\ts\tStaten Island Institute of Arts and Sciences\t\t", +"SIM\ts\tStaten Island Institute of Arts and Sciences, Science Department\t\t", +"SIMF\ts\tTaurida National University, Botany Department\t\t", +"SIMS\ts\tSherkin Island Marine Station\t\t", +"SING\ts\tSingapore Botanic Gardens\t\t", +"SINU\ts\tNational University of Singapore, Biological Sciences Department\t\t", +"SIO\ts\tScripps Institution of Oceanography\t\t", +"SIO:BIC\ts\tScripps Institution of Oceanography, Benthic Invertebrates Collection", +"SITC\ts\tSichuan Teachers College, Biology Department\t\t", +"SIU\ts\tSouthern Illinois University, Plant Biology Department\t\t", +"SIUC\ts\tResearch Museum of Zoology, Southern Illinois University at Carbondale\t\t", +"SIUC:H\ts\tResearch Museum of Zoology, Southern Illinois University at Carbondale, Herpetology Collection", +"SIUCM\ts\tSouthern Illinois University\t\t", +"SIUE\ts\tSouthern Illinois University, Edwardsville\t\t", +"SIZK\ts\tSchmaulhausen Institute of Zoology\t\t", +"SJ\ts\tDepartamento de Recursos Naturales y Ambientales\t\t", +"SJAC\ts\tSan Joaquin County Agriculture Commissioner\t\t", +"SJC\ts\tSir John Cass College, Chemistry and Biology Department\t\t", +"SJCA\ts\tSt. John's College\t\t", +"SJCRY\ts\tSt. John's College of Ripon and York\t\t", +"SJER\ts\tUnited States Forest Service, San Joaquin Experimental Range\t\t", +"SJFM\ts\tFairbanks Museum and Planetarium\t\t", +"SJNM\ts\tSan Juan College\t\t", +"SJPC\ts\tSergei J. Paramonov personal collection -- destroyed\t\t", +"SJRP\ts\tUNESP, Campus Sao Jose Rio Preto, Departamento Zoologia e Botanica\t\t", +"SJSC\ts\tSan Jose State University, J. Gordon Edwards Museum of Entomology\t\t", +"SJSU\ts\tSan Jose State University, Biological Sciences Department\t\t", +"SJUBC\ts\tSaint John's University, Biology Collections\t\t", +"SK\ts\tKatedralskolan\t\t", +"SKK\ts\tSung Kyun Kwan University, Biological Sciences Department\t\t", +"SKM\ts\tSkokholm Field Centre\t\t", +"SKN\ts\tCraven Museum Service\t\t", +"SKR\ts\tLatvian Research Institute of Agriculture, Plant Protection Department\t\t", +"SKT\ts\tStockport Heritage Services\t\t", +"SKU\ts\tSri Krishnadevaraya University, Botany Department\t\t", +"SKUK\tc\tSimpanan Kultur Universiti Kebangsaan\t\t", +"SL\ts\tUniversity of Sierra Leone, Njala University College, Biological Sciences Department\t\t", +"SLBI\ts\tSouth London Botanical Institute\t\t", +"SLC\ts\tEast High School, Science Department\t\t", +"SLFC\ts\tSlapton Ley Field Centre\t\t", +"SlgInnsb\ts\tPaleontological Collection\t\t", +"SLJG\ts\tSteiermarkisches Landesmuseum Joanneum\t\t", +"SLL\ts\tSociete Linneenne de Lyon\t\t", +"SLO\ts\tKomenskeho University, Katedra botaniky\t\t", +"SLPM\ts\tUniversidad Autonoma de San Luis Potosi\t\t", +"SLRO\ts\tSlippery Rock University, Biology Department\t\t", +"SLSC\ts\tSt. Louis, St. Louis Science Center\t\t", +"SLSK\ts\tSt. Leonard's and St. Katherine's Schools\t\t", +"SLTC\ts\tTeachers College, Botany Department\t\t", +"SLU\ts\tLaurentian University, Biology Department\t\t", +"SLU\ts\tSoutheastern Louisiana University, Vertebrate Museum\t\t", +"SLUB\ts\tSt. Louis University Museum\t\t", +"SLUBGH\th\tShah Abdul Latif University\t\t", +"SLUM\ts\tSaint Louis University Museum Ichthylogy Collection\t\t", +"SM\ts\tChongqing Municipal Academy of Chinese Materia Medica\t\t", +"SM\ts\tSenckenberg Museum\t\t", +"SM\ts\tSchwegler Museum\t\t", +"SM\ts\tSarawak Museum\t\t", +"SM\ts\tSanford Museum Collections\t\t", +"SM\ts\tStrecker Museum, Baylor University\t\t", +"SMAG\ts\tSouthland Museum and Art Gallery\t\t", +"SMAO\ts\tSimao Forestry Bureau\t\t", +"SMB\ts\tMarianske Muzeum, Natural History Department\t\t", +"SMBB\ts\tStredoslovenske muzeum\t\t", +"SMBL\ts\tSeto Marine Biological Laboratory, Kyoto University\t\t", +"SMC\ts\tSedgwick Museum\t\t", +"SMCC\tc\tSubsurface Microbial Culture Collection\t\t", +"SMCC-W\tc\tSubsurface Microbial Culture Collection--Western Branch\t\t", +"SMCW\ts\tSaint Michael's College, Biology Department\t\t", +"SMDB\ts\tUniversidade Federal de Santa Maria, Departamento de Biologia\t\t", +"SME\ts\tStation Marine d'Endoume\t\t", +"SME\ts\tSedgwick Museum of Geology\t\t", +"SMF\ts\tForschungsinstitut und Natur-Museum Senckenberg\t\t", +"SMF\ts\tUniversidad Nacional Mayor de San Marcos\t\t", +"SMH\ts\tSaint Meinrad College of Liberal Arts, Biology Department\t\t", +"SMI\ts\tPrince Rupert Forest Region, Research Section\t\t", +"SMIP\tc\tSecao de Maricultura\t\t", +"SMJM\ts\tSabah Museum\t\t", +"SMK\ts\tSarawak Museum\tSM", +"SMKM\ts\tSelangor Museum\t\t", +"SMM\ts\tScience Museum of Minnesota\t\t", +"SMMC\ts\tSecond Military Medical College\t\t", +"SMN\ts\tSimao District National Medical and Pharmaceutical Institute\t\t", +"SMNG\ts\tSenckenberg Museum fuer Naturkunde Goerlitz\t\t", +"SMNH\ts\tSaskatchewan Museum of Natural History\t\t", +"SMNH\ts\tSteinhardt Museum of Natural History\t\t", +"SMNH\ts\tSwedish Museum of Natural History\t\t", +"SMNH\ts\tState Museum of Natural History\t\t", +"SMNH\ts\tSchmidt Museum of Natural History, Emporia State University\t\t", +"SMNK\ts\tStaatliches Museum fuer Naturkunde Karlsruhe (State Museum of Natural History)\t\t", +"SMNS\ts\tStaatliches Museum fuer Naturkund Stuttgart\t\t", +"SMOC\ts\tSlezske Muzeum Opava\t\t", +"SMP\ts\tSurinaams Museum\t\t", +"SMP\ts\tThe State Museum of Pennsylvania\t\t", +"SMPM\ts\tScience Museum of Minnesota\t\t", +"SMR\ts\tSamara State University, Department for Ecology, Botany, and Nature Protection\t\t", +"SMRG\tc\tSoil Microbiology Research Group, Division of Soil Science, Department of Agriculture\t\t", +"SMRS\ts\tStavropol Museum of Regional Studies\t\t", +"SMS\ts\tMissouri State University, Department of Biology\t\t", +"SMSM\ts\tSarawak Museum\t\t", +"SMTP\ts\tSwedish Malaise Trap Project\t\t", +"SMTWA\tc\tSchool of Medical Technology Western Australia\t\t", +"SMU\ts\tSt. Mary's University\t\t", +"SMU\ts\tSangmiung University\t\t", +"SMU\ts\tShuler Museum of Paleontology, Southern Methodist University\tSMP", +"SMVM\ts\tNational Archives and Museum\t\t", +"SMW\ts\tSchool of Medicine for Women\t\t", +"SMW\ts\tState Museum\tSMWN", +"SMWN\ts\tState Museum\tSMW", +"SMWU\ts\tSang Miung Women's University\t\t", +"SN\ts\tSouth China Normal University, Biology Department\t\t", +"SNC\ts\tSaint Norbert College\t\t", +"SNCBSH\ts\tState of North Carolina Biological Station\t\t", +"SNGM\ts\tColeccion Paleontologica\t\t", +"SNHM\ts\tSudan Natural History Museum\t\t", +"SNHS\ts\tGuildford Museum\t\t", +"SNM\ts\tSlovak National Museum\tSNMB", +"SNM\ts\tWestern New Mexico University, Department of Natural Sciences\t\t", +"SNMB\ts\tStaatliches Naturhistorisches Museum\t\t", +"SNMBR\ts\tStaatliches Naturhistorisches Museum in Braunschweig\t\t", +"SNMC\ts\tSlovenske Narodne Muzeum\t\t", +"SNMG\ts\tStaatliches Museum fuer Naturkunde\t\t", +"SNMH\th\tSree Narayana Mangalam College\t\t", +"SNMNH\ts\tSaudi Arabian National Museum of Natural History\t\t", +"SNOMNH\ts\tSam Nobel Oklahoma Museum of Natural History\t\t", +"SNP\ts\tSabah Parks, Botany Section\t\t", +"SNPH\ts\tSehlabathebe National Park\t\t", +"SNSD\ts\tSenckenberg Natural History Collections Dresden, Museum of Zoology\t\t", +"SNSD:Moll\ts\tSenckenberg Natural History Collections Dresden, Museum of Zoology, ", +"SNU\ts\tSeoul National University, School of Biological Sciences\t\t", +"SNUA\ts\tSeoul National University, The Arboretum\t\t", +"SNW\ts\tShropshire and North Wales Natural History and Antiquarian Society\t\t", +"SO\ts\tSofia University \"St. Kliment Ohridski\", Botany Department\t\t", +"SOA\ts\tAgricultural University of Plovdiv, Botany Department\t\t", +"SOB\ts\tHusite Museum Tabor\t\t", +"SOC\ts\tSouthern Oregon University, Biology Department\t\t", +"SOF\th\tSofyivka National Dendrological Park\t\t", +"SOFM\ts\tNational Museum of Natural History, Sofia\t\t", +"SOFRI\tb\tSouthern Fruit Research Institute Vietnam\t\t", +"SOGS\ts\tPal. Coll, Sokoto State Government Palaeontological Collection\t\t", +"SOIC\ts\tNatural History Museum, National Insect Collection\t\t", +"SOKO\ts\tOkresni muzeum Sokolov (Regional Muzeum), Botany Department\t\t", +"SOM\ts\tBulgarian Academy of Sciences\t\t", +"SOMF\ts\tBulgarian Academy of Sciences\t\t", +"SORO\th\tUniversidade Federal de Sao Carlos, campus Sorocaba\t\t", +"SOSCMVNH\ts\tSouthern Oregon State College, Museum of Vertebrate Natural History\t\t", +"SOSN\ts\tSilesian Medical School in Katowice, Department of Pharmaceutical Botany\t\t", +"SOSSRC\ts\tSave Our Seas Shark Research Center, Nova Southeastern University\t\t", +"SOTO\ts\tCollege of the Ozarks, Biology Department\t\t", +"SOTON\ts\tSouthampton University\t\t", +"SOUT\ts\tLong Island University\t\t", +"SP\ts\tInstituto de Botanica\t\t", +"SPA\ts\tSwedish Museum of Natural History, Section for Palaeobotany\t\t", +"SPAL\ts\tMunicipio di Reggio Emilia, Musei Civici\t\t", +"SPB\ts\tUniversidade de Sao Paulo\t\t", +"SPC\ts\tSeattle Pacific University, Biology Department, Suite 205\t\t", +"SPF\ts\tUniversidade de Sao Paulo, Departamento de Botanica\t\t", +"SPFR\ts\tUniversidade de Sao Paulo, Departamento de Biologia\t\t", +"SPH\ts\tFox Research Forest\t\t", +"SPI\ts\tStavropol Pedagogical Institute, Botany Department\t\t", +"SPL\ts\tPalynological Laboratory\t\t", +"SPLT\ts\tSouth Plains College, Science Department\t\t", +"SPM\ts\tSabah Parks\t\t", +"SPMCC\tc\tSungei Putih Microbial Culture Collection\t\t", +"SPMO\tc\tSalt Plains Microbial Observatory\t\t", +"SPMS\ts\tUniversity of South Florida\t\t", +"SPN\ts\tSouthampton University, Biology Department\t\t", +"SPNRI\ts\tSichuan Province, Natural Resources Institute\t\t", +"SPR\ts\tSpringfield Science Museum, Natural Science Department\t\t", +"SPRY\ts\tBurton Constable Foundation\t\t", +"SPSF\ts\tInstituto Florestal\t\t", +"SPSU\th\tSt. Petersburg State University\t\t", +"SPT\ts\tBotanic Gardens Museum\t\t", +"SPTS\ts\tSouthport Scientific Society\t\t", +"SPWH\ts\tMarine Biological Laboratory\t\t", +"SQB\th\tSociete quebecoise de bryologie\t\t", +"SQF\ts\tUniversidad de Chile, Laboratorio de Botanica, Escuela de Quimica y Farmacia\t\t", +"SQUH\th\tSultan Qaboos University\t\t", +"SR\ts\tSichuan Institute of Natural Resources\t\t", +"SRAICC\tc\tSRAI's culture collection\t\t", +"SRCG\ts\tBaylor University\t\t", +"SRD\ts\tPassmore Edwards Museum\t\t", +"SRF\ts\tShangrao Forestry Institute\t\t", +"SRFA\ts\tUniversidad Nacional de La Pampa\t\t", +"SRGH\ts\tBotanic Garden\t\t", +"SRI\ts\tSerengetti Research Institute\t\t", +"SRNP\ts\tInsects of the Area Conservacion Guanacaste, northwestern Costa Rica\t\t", +"SRP\ts\tBoise State University, Biology Department\t\t", +"SRR\ts\tKoninklijke Shell (Shell Research N.V.)\t\t", +"SRRC\tc\tSouthern Regional Research Center, Agricultural Research Service, United States Department of Agriculture\t\t", +"SRS\th\tUniversidade do Sul de Santa Catarina\t\t", +"SRSC\ts\tSul Ross State University, Department of Biology\t\t", +"SRSU\ts\tSul Ross State University\t\t", +"SS\ts\tUniversita di Sassari, Dipartimento di Botanica ed Ecologia Vegetale\t\t", +"SSC\ts\tSacramento State University\t\t", +"SSCMU\tc\tSoil Science and Conservation Department Faculty of Agriculture\t\t", +"SSCN\ts\tMusum of the Biological Laboratory\t\t", +"SSD\ts\tSammlung Simon des Stattlichen Museum fur Mineralogie und Geologie Dresden\t\t", +"SSF\ts\tSammlung des Senckenbrug-Museum\t\t", +"SSI\tc\tStatens Serum Institute\t\t", +"SSIC\tc\tCollaborating Centre for Reference and Research on Escherichia and Klebsiella\t\t", +"SSJC\ts\tSan Joaquin County, Agriculture Department\t\t", +"SSKKU\tc\tDepartment of Soil Science, Faculty of Agriculture\t\t", +"SSL\ts\tSammlung Langenhan an der Sektion Geophysik der Karl-Marx-Universitat Lepzig\t\t", +"SSLP\ts\tRocky Mountain Research Station\t\t", +"SSM\ts\tSavannah Science Museum\t\t", +"SSM\ts\tSpringfield Science Museum\t\t", +"SSMF\ts\tGreat Lakes Forestry Centre, Canadian Forest Service\t\t", +"SSMJI\tc\tScience Section, Department of General Education, Faculty of Agricultural Business\t\t", +"SSMM\ts\tShanxi School of Chinese Materia Medica\t\t", +"SSMS\ts\tSuriname State Museum\t\t", +"SSNR\ts\tSocieta per GL Studi Naturalistica della Romagna\t\t", +"SSOFM\ts\tSanabe Shizenkan Open Field Museum\t\t", +"SSPW\ts\tPerivale Wood Nature Reserve\t\t", +"SSU\ts\tSaratov State University\t\t", +"SSUC\ts\tPontificia Universidad Catolica de Chile, Departamento de Ecologia\t\t", +"ST\ts\tSuzhou Teachers College, Biology Department\t\t", +"STA\ts\tUniversity of St. Andrews, School of Environmental and Evolutionary Biology\t\t", +"STAL\ts\tVerulamium Museum\t\t", +"STAR\ts\tArkansas State University, Biological Sciences Department\t\t", +"STASH\ts\tSt. Beuno's College\t\t", +"STB\ts\tSt. Bartholomew's Hospital\t\t", +"STC\ts\tSichuan Teacher's College\t\t", +"STCR\ts\tUniversite de la Reunion\t\t", +"STD\ts\tPrittlewell Priory Museum\t\t", +"STDCM\ts\tSouthend Central Museum\t\t", +"STE\ts\tNational Botanical Institute\t\t", +"STE-U\tc\tCulture collection of the Department of Plant Pathology, University of Stellenbosch\t\t", +"STEU\tsc\tUniversity of Stellenbosch, Botany Department\t\t", +"STFX\ts\tSt. Francis Xavier University, Biology Department\t\t", +"STG\ts\tSt. Martin's Convent\t\t", +"STI\ts\tStirling Smith Art Gallery and Museum\t\t", +"STIU\ts\tUniversity of Stirling, Biological Sciences Department\t\t", +"STK\ts\tStoke-on-Trent Athenaeum\t\t", +"STL\ts\tInstituto Nacional de Limnologia, Departamento Macrofitas\t\t", +"STM\ts\tStettinger Museum\t\t", +"STM\tc\tLaboratoire des Symbioses Tropicales et Mediterraneennes\t\t", +"STM\ts\tStreatham Antiquarian and Natural History Society\t\t", +"STMC\ts\tSchool of Tropical Medicine\t\t", +"STNF\th\tShasta-Trinity National Forest\t\t", +"STO\ts\tThe Potteries Museum & Art Gallery\t\t", +"STP\ts\tLa Societe Guernesiaise, Priaulx Library\t\t", +"STPCM\ts\tIsland Museum, Candie Gardens\t\t", +"STPE\ts\tFlorida Marine Research Institute, Florida Department of Environmental Protection\t\t", +"STPH\th\tDireccao Geral do Ambiente, Cabinet of Environment, Ministry of Natural Resources and Environment\t\t", +"STPS\ts\tSt. Paul's School\t\t", +"STR\ts\tInstitut de Botanique\t\t", +"STRI\tsc\tSmithsonian Tropical Research Institute\t\t", +"STRI:ICBG-Panama\tc\tSmithsonian Tropical Research Institute, International Cooperative Biodiversity Groups", +"STS\ts\tStromness Museum\t\t", +"STT\ts\tSt. Thomas's Hospital Medical School Library\t\t", +"STU\ts\tStaatliches Museum fuer Naturkunde Stuttgart\t\t", +"STUM\ts\tSanto Tomas University Museum\t\t", +"SU\ts\tSuzhou University\t\t", +"SU\ts\tStanford University\t\t", +"SU\ts\tOregon State University\t\t", +"SUA\ts\tSokoine University of Agriculture, Forest Biology Department\t\t", +"SUB\ts\tUniversitat Bonn\t\t", +"SUCEA\ts\tThe University at Albany\t\t", +"SUCH\ts\tSukhumi Botanical Garden of Georgian Academy of Sciences\t\t", +"SUCN\ts\tState University of California\t\t", +"SUCO\ts\tState University of New York, College at Oneonta, Biology Department\t\t", +"SUD\ts\tStroud and District Museum\t\t", +"SUEL\ts\tNatural History Museum of Bakony Mountains\t\t", +"SUF\ts\tShimonoseki University of Fisheries\t\t", +"SUFA\th\tSulaimania University\t\t", +"SUFAF\th\tSiirt University Flora and Fauna Center\t\t", +"SUHC\ts\tSalisbury University, Department of Biology\t\t", +"SUK\ts\tShivaji University Kolhapur\t\t", +"SUM\ts\tOkresni vlastivedne muzeum v Sumperku\t\t", +"SUM\ts\tStellenbosch University\t\t", +"SUN\ts\tSunderland Museum\t\t", +"SUND\ts\tSunderland Natural History and Antiquarian Society\t\t", +"SUNIV\ts\tUniversity of Stockholm\t\t", +"SUNY\ts\tState University of New York\t\t", +"SUNYO\ts\tState University of New York at Oneonta\t\t", +"SURCO\th\tUniversidad Surcolombiana\t\t", +"SUU\th\tSouthern Utah University\t\t", +"SUVA\ts\tUniversity of the South Pacific\t\t", +"SUVM\ts\tShippensburg University, Vertebrate Museum\t\t", +"SUWS\ts\tUniversity of Wisconsin-Superior, Department of Biology and Earth Science\t\t", +"SV\ts\tAntigua Estacion Experimental Agronomica\t\t", +"SVCK\tc\tSammlung von Conjugaten Kulturen\t\t", +"SVER\ts\tInstitute of Plant and Animal Ecology, Laboratory of Plant Ecology and Geobotany\t\t", +"SVG\ts\tArkeologisk museum i Stavanger\t\t", +"SVIEC\tc\tSecao de Virus\t\t", +"SVUTY\th\tSri Venkateswara University\t\t", +"SVVC\ts\tSeminario Vescovile\t\t", +"SWA\ts\tSwansea Museum\t\t", +"SWAT\th\tUniversity of Swat Pakistan\t\t", +"SWAU\ts\tSouthwest Agricultural University, Horticulture Department\t\t", +"SWBR\ts\tSweet Briar College, Biology Department\t\t", +"SWC\ts\tSammlung des Cambridge, University of Zoology\t\t", +"SWC\ts\tSwarthmore College, Biology Department\t\t", +"SWCTU\ts\tSouthwest Teachers University, Biology Department\t\t", +"SWE\ts\tChandos House, Stowe School\t\t", +"SWF\ts\tFlorida Gulf Coast University\t\t", +"SWFC\ts\tSouthwest Forestry College\t\t", +"SWFSC\ts\tSouthwest Fisheries Science Center\t\t", +"SWGC\th\tGrenfell Campus, Memorial University of Newfoundland\t\t", +"SWIBASC\ts\tAcademia Sinica\t\t", +"SWMT\ts\tRhodes College, Biology Department\t\t", +"SWN\ts\tSaffron Walden Museum\t\t", +"SWNHS\ts\tSaffron Walden Horticultural Society\t\t", +"SWRS\ts\tSouthwestern Research Station\t\t", +"SWSL\ts\tUSDA/ARS, Southern Weed Science Research Unit\t\t", +"SWT\ts\tSouthwest Texas State University, Department of Biology\t\t", +"SWTN\ts\tSwinton and Pendlebury Botanical Society\t\t", +"SWU\th\tSungshin Women's University\t\t", +"SWU2\tc\tDepartment of Biology, Faculty of Science\t\t", +"SXAU\ts\tShanxi Agricultural University, Forestry Department\t\t", +"SXDC\ts\tShaanxi Institute for Drug Control\t\t", +"SXIM\th\tShaanxi Institute of Microbiology\t\t", +"SXMP\ts\tShaanxi Academy of Traditional Chinese Medicine and Pharmacology\t\t", +"SXU\ts\tShanxi University, Biology Department\t\t", +"SY\ts\tShenyang Municipal Academy of Landscape Gardening\t\t", +"SYAU\ts\tShenyang Agricultural University\t\t", +"SYAUF\ts\tShenyang Agricultural University, Forestry Department\t\t", +"SYD\ts\tUniversity of Sydney\t\t", +"SYKO\ts\tKomi Scientific Centre, Ural Division, Russian Academy of Sciences, Department of Geobotany and Plant Cover Restoration\t\t", +"SYKT\ts\tSyktyvkar State University, Botany Department\t\t", +"SYPC\ts\tShenyang College of Pharmacy, Pharmaceutical Botany Department\t\t", +"SYR\ts\tSyracuse University, Plant Sciences Department\t\t", +"SYRF\ts\tState University of New York\t\t", +"SYS\ts\tSun Yatsen University, Biology Department\t\t", +"SYS:Z\ts\tSun Yatsen University, Biology Department, Zoology Collection", +"SYSBM\ts\tThe Museum of Biology Sun Yat-sen University\t\t", +"SYSU\ts\tNational Sun Yat-Sen University, Department of Biological Sciences\t\t", +"SYT\ts\tStonyhurst College\t\t", +"SZ\ts\tSichuan University, Biological Department\t\t", +"SZB\ts\tHaus der Natur\t\t", +"SZCU\ts\tDepartment of Systematic Zoology\t\t", +"SZCZ\th\tUniversity of Szczecin\t\t", +"SZE\ts\tMora Ferenc Museum, Natural Science Department\t\t", +"SZE\ts\tZoology Department, Aegean University, Science Faculty\t\t", +"SZG\ts\tShenzhen Fairy Lake Botanical Garden\t\t", +"SZL\ts\tLandesherbar von Salzburg\t\t", +"SZM\ts\tSaitama Zoogeographical Museum\t\t", +"SZMC\tc\tSzeged Microbiological Collection\t\t", +"SZMN\ts\tSiberian Zoological Museum\t\t", +"SZPT\ts\tShenzhen Polytechnic\t\t", +"SZPT:ENT\ts\tShenzhen Polytechnic, Entomology Collection", +"SZU\ts\tUniversity of Salzburg, Department of Organismic Biology\t\t", +"SZUB\th\tUniversity of Szczecin\t\t", +"T\ts\tTavera, Department of Geology and Geophysics\t\t", +"TA\ts\tTimescale Adventures Research and Interpretive Center\t\t", +"TAA\ts\tEstonian Agricultural University, Institute of Agricultural and Environmental Sciences\t\t", +"TAAM\ts\tInstitute of Agricultural and Environmental Sciences of the Estonian University of Life Sciences\tTAAM", +"TAC\ts\tTarleton State University, Biological Sciences Department\t\t", +"TAD\ts\tBotanical Institute of the Tajikistan Academy of Sciences, Department of Flora and Systematics of Higher Plants\t\t", +"TAES\ts\tTexas A&M University, Department of Rangeland Ecology and Management\t\t", +"TAFIRI\ts\tTanzania Fisheries Research Institute\t\t", +"TAI\ts\tNational Taiwan University, Institute of Ecology and Evolutionary Biology\t\t", +"TAIC\ts\tTexas A&M University-Kingsville, Department of Biology\t\t", +"TAIE\th\tEndemic Species Research Institute\t\t", +"TAIF\ts\tTaiwan Forestry Research Institute\t\t", +"TAIM\ts\tTaiwan Museum\t\t", +"TAIU\ts\tTexas A&M University - Kingsville, Texas A&I Collections\t\t", +"TAK\ts\tLenin State University\t\t", +"TAL\th\tJardin botanique de Talence\t\t", +"TALE\ts\tLaboratoire Geologique\t\t", +"TALL\ts\tTallinn Botanic Garden, Department of Environmental Education\t\t", +"TAM\ts\tEstonian Museum of Natural History, Botany Department\t\t", +"TAMA\tc\tMycology & Metabolic Diversity Research Center, Tamagawa University Research Institute\t\t", +"TAMU\ts\tTexas A&M University, Biology Department\t\t", +"TAN\ts\tParc de Tsimbazaza, Departement Botanique\t\t", +"TANE\ts\tTanta University, Botany Department\t\t", +"TAR\ts\tConsiglio Nazionale delle Ricerche\t\t", +"TARI\ts\tTaiwan Agricultural Research Institute\t\t", +"TARI\ts\tResearch Institute of Forests and Rangelands, Botanical Department\t\t", +"TARI\ts\tTrakya Agricultural Research Institute\t\t", +"TASH\ts\tNational Academy of Science, Uzbekistan\t\t", +"TASM\ts\tUzbek Academy of Sciences, Laboratory of Mycology\t\t", +"TAU\ts\tAristotle University of Thessaloniki, Biology Department\t\t", +"TAU\ts\tTel-Aviv University\t\t", +"TAUF\ts\tAristotle University of Thessaloniki, Department of Forestry and Natural Environment\t\t", +"TAWES\th\tMaryland Department of Natural Resources\t\t", +"TB\ts\tTbilisi State University, Botany Department\t\t", +"TBG\tb\tTsukuba Botanical Garden\t\t", +"TBGT\ts\tTropical Botanic Garden and Research Institute\t\t", +"TBI\ts\tGeorgian Academy of Sciences\t\t", +"TBIP\ts\tResearch Institute of Plant Protection\t\t", +"TBPH\th\tIovel Kutateladze Institute of Pharmacochemistry\t\t", +"TBY\ts\tTenby Museum\t\t", +"TCB\ts\tNational Chung Hsing University, Botany Department\t\t", +"TCC/USP\tc\tTrypanosomatid Culture Collection, University of Sao Paulo\tTRYCC", +"TCD\ts\tTrinity College\t\t", +"TCDL\ts\tTrinity College Library, Manuscript Department\t\t", +"TCDU\tb\tTrinity College, Dublin University, Department of Zoology DNA repository\t\t", +"TCDU\ts\tMinistry of Animal Industry and Fisheries\t\t", +"TCF\ts\tNational Chung Hsing University, Forestry Department\t\t", +"TCFB\tc\tTasmanian Collection of Fish Bacteria\t\t", +"TCMM\tc\tThai Collection of Medical Microorganism, Department of Pathology, Faculty of Veterinary Science\t\t", +"TCNM\ts\tTimpanogos Cave National Monument\t\t", +"TCSW\ts\tTexas Women's University, Biology Department\t\t", +"TCWC\ts\tTexas Cooperative Wildlife Collection\t\t", +"TCWC:Birds\ts\tTexas Cooperative Wildlife Collection, Collection of Birds", +"TCWC:Fish\ts\tTexas Cooperative Wildlife Collection, Collection of Fishes", +"TCWC:Herp\ts\tTexas Cooperative Wildlife Collection, Collection of Amphibians and Reptiles", +"TCWC:Invrt\ts\tTexas Cooperative Wildlife Collection, Collection of Marine Invertebrate", +"TCWC:Mamm\ts\tTexas Cooperative Wildlife Collection, Mammal collection", +"TDA\ts\tDepartment of Agriculture, Tasmania\t\t", +"TDAH\ts\tTasmanian Department of Agriculture\t\t", +"TDMP\ts\tTa-Dzong Museum\t\t", +"TDN\ts\tTodmorden Botanical Society\t\t", +"TDNA\tb\tToulouse DNA databank\t\t", +"TDY\ts\tTyldesley Natural History Society\t\t", +"TEA\ts\tTea Research Institute\t\t", +"TEB\ts\tTeberda State Reserve\t\t", +"TECLA\ts\tCentro Nacional de Tecnologia Agropecuaria\t\t", +"TEF\ts\tCentre National de la Recherche Appliquee au Developement Rural, Departement des Recherches Forestieres et Piscicoles\t\t", +"TEFH\ts\tUniversidad Nacional Autonoma de Honduras, Departamento de Biologia\t\t", +"TEH\ts\tUniversity of Tehran\t\t", +"TELA\ts\tTel Aviv University, Botany Department\t\t", +"TELY\ts\tTate Library\t\t", +"TENHS\ts\tToynbee Natural History Society\t\t", +"TENN\ts\tDepartment of Ecology and Evolutionary Biology, University of Tennessee\t\t", +"TEPB\ts\tUniversidade Federal do Piaui, Departamento de Biologia\t\t", +"TER\ts\tIndiana State University, Life Science Department\t\t", +"TESC\ts\tThe Evergreen State College\t\t", +"TESRI\ts\tTaiwan Endemic Species Research Institute\t\t", +"TEU\ts\tTeikyo University, Education Department\t\t", +"TEUI\th\tU.S. Forest Service Southwest Region, Terrestrial Ecological Unit Inventory\t\t", +"TEX\ts\tUniversity of Texas at Austin, Plant Resources Center\t\t", +"TEXA\ts\tBlackland Experiment Station\t\t", +"TF\ts\tForestry and Forest Products Research Institute\t\t", +"TF\ts\tDepartment of Mineral Resources\t\t", +"TFA\ts\tForestry and Forest Products Research Institute\t\t", +"TFAV\ts\tServicio Autonomo para el Desarrollo Ambiental del Estado Amazonas\t\t", +"TFC\ts\tUniversidad de La Laguna, Departamento de Biologia Vegetal (Botanica)\t\t", +"TFC\tc\tTartu Fungal Culture Collection\t\t", +"TFD\ts\tTanzania Forestry Research Institute\t\t", +"TFDA\ts\tTasmanian Fisheries Development Authority\t\t", +"TFIC\ts\tTasmanian Forest Insect Collection\t\t", +"TFM\ts\tForestry and Forest Products Research Institute\t\t", +"TFMC\ts\tMuseo de Ciencias Naturales de Santa Cruz de Tenerife\t\t", +"TFRI\ts\tTaiwan Fisheries Research Institute\t\t", +"TGM\ts\tJanashia State Museum of Georgia\t\t", +"TGPI\ts\tTiraspolskij Gosudarstvennij Pedagogiceskij Institut\t\t", +"TGRC\tb\tC.M. Rick Tomato Genetics Resource Center\t\t", +"TGU\th\tUniversity of Montenegro\t\t", +"TH\ts\tUniversity of Tokyo\t\t", +"THBC\ts\tTechnische Hochschule\t\t", +"THIB\ts\tNicholls State University, Department of Biological Sciences\t\t", +"THIM\ts\tNational Biodiversity Centre\t\t", +"THL\ts\tGrierson Museum\t\t", +"THO\ts\tRobert Dick Museum Library\t\t", +"THRI\ts\tSequoia and Kings Canyon National Parks\t\t", +"THS\ts\tTsumura Laboratory\t\t", +"THUP\ts\tTunghai University\t\t", +"TI\ts\tHerbarium of the Department of Botany, University of Tokyo\t\t", +"TIC\ts\tCalifornia Department of Fish and Game\t\t", +"TIE\ts\tTianjin Natural History Museum, Botany Department\t\t", +"TIK\ts\tAgricultural Research Centre, Plant Pathology Department\t\t", +"TIMGP\ts\tInstitut und Museum fuer Geologie und Palaeontologie der Unversitaet\t\t", +"TIMJ\ts\tTainai Insect Museum\t\t", +"TIMM\tc\tInstitute of Medical Mycology\t\t", +"TIPR\ts\tInstitute of Pharmaceutical Research\t\t", +"TISTR\tc\tTISTR Culture Collection Bangkok MIRCEN\t\t", +"TIU\ts\tTokyo Imperial University, Science College Museum\t\t", +"TJDC\ts\tTianjin Municipal Institute for Drug Control, Department of Traditional Chinese Medicine\t\t", +"TJMP\ts\tTianjin Institute of Medical and Pharmaceutical Sciences\t\t", +"TK\ts\tTomsk State University\t\t", +"TK\ts\tColeccion de mamiferos del Centro Interdisciplinario de Investigacion para el Desarrollo Integral Regional Unidad Durango\t\t", +"TKB\ts\tUniversity of Tsukuba\t\t", +"TKNM\ts\tTwickenham Girls' School\t\t", +"TKPM\ts\tTokushima Prefectural Museum\t\t", +"TKU\ts\tTokyo Kyoiku University\t\t", +"TL\ts\tUniversite Paul Sabatier\t\t", +"TLA\ts\tEcole Nationale Superieure Agronomique\t\t", +"TLF\ts\tUniversite Paul Sabatier\t\t", +"TLHR\ts\tThueringer Landesmuseum Heidecksburg\t\t", +"TLJ\ts\tUniversite Paul-Sabatier\t\t", +"TLM\ts\tMuseum d'Histoire Naturelle de Toulouse\t\t", +"TLMF\ts\tTiroler Landesmuseum Ferdinandeum\t\t", +"TLON\ts\tMuseum d'Histoire Naturelle\t\t", +"TLP\ts\tFaculte de Medecine, Chaire de Botanique\t\t", +"TLS\ts\tTunbridge Wells Museum and Art Gallery\t\t", +"TLXM\ts\tUniversidad Autonoma de Tlaxcala\t\t", +"TM\ts\tTeylers Museum, Paleontologische\t\t", +"TM\ts\tSlovak National Museum\t\t", +"TM\ts\tTransvaal Museum\tTRM", +"TMAG\ts\tTasmanian Museum & Art Gallery\t\t", +"TMAL\ts\tTameside Metropolitan Borough Museum\t\t", +"TMBS\ts\tTatsuo Tanaka Memorial Biological Laboratory\t\t", +"TMC\ts\tTate Museum Collection\t\t", +"TMC\tc\tTrudeau Mycobacterial Culture Collection, Trudeau Institute\t\t", +"TMC\tc\tThe Mollicutes Collection\t\t", +"TMDU\ts\tTokyo Medical and Dental University\t\t", +"TMFE\ts\tElasmobranchii Collection of the Department of Fisheries, Tokai University\t\t", +"TMH\ts\tTasmanian Museum and Art Gallery\t\t", +"TMHN\ts\tTeyler Museum\t\t", +"TMI\ts\tTottori Mycological Institute\t\t", +"TMM\ts\tTexas Memorial Museum\t\t", +"TMMC\ts\tTexas Memorial Museum\t\t", +"TMNH\ts\tTianjin Museum of Natural History\t\t", +"TMP\ts\tTampere Museums\t\t", +"TMP\ts\tTransvaal Museum\t\t", +"TMRC\th\tShahid Beheshti University of Medical Sciences\t\t", +"TMS\ts\tToleco Museum of Health and Natural History\t\t", +"TMSA\ts\tTransvaal Museum\t\t", +"TMTC\ts\tTaiwan Provincial Museum\t\t", +"TNAU\ts\tTamil Nadu Agricultural University\t\t", +"TNFC\ts\tTynside Naturalists' Field Club\t\t", +"TNFS\ts\tUSDA Forest Service, Alaska Region\t\t", +"TNHC\ts\tTexas Memorial Museum, Texas Natural History Collection\t\t", +"TNHM\ts\tUniversity of Texas\t\t", +"TNM\ts\tNational Museum of Natural Science, Botany Department\t\t", +"TNP\ts\tMuseum of Tatra National Park\t\t", +"TNS\ts\tNational Science Museum, Department of Botany\t\t", +"TNSC\ts\tThierry Neef de Sainval\t\t", +"TNSC\ts\tTrailside Nature and Science Center\t\t", +"TNSM\ts\tThailand Natural History Museum\tTHNHM", +"TNU\ts\tNational Taiwan Normal University, Herbarium\t\t", +"TNZ\ts\tTianjin Nat. Hist. Mus.\t\t", +"TO\ts\tUniversita degli Studi di Torino, Dipartimento di Biologia Vegetale\t\t", +"TOD\ts\tTodmorden Free Library\t\t", +"TOFO\ts\tUniversity of Tokyo, Section of Forest Botany\t\t", +"TOGO\ts\tUniversite du Lome, Laboratoire de Botanique et Ecologie Vegetale\t\t", +"TOGR\ts\tMuseo di Storia Naturale Don Bosco\t\t", +"TOHO\ts\tToho University\t\t", +"TOKE\ts\tTokyo University of Education\t\t", +"TOLI\ts\tUniversidad del Tolima, Departamento de Biologia\t\t", +"TOM\ts\tIstituto Missioni Consolata\t\t", +"TOM\tc\tTomicus collection Canadian Forest Service\t\t", +"TON\th\tMinistry of Agriculture and Food, Forestry and Fisheries\t\t", +"TONG\ts\tTonghua Teachers College, Biology Department\t\t", +"TOR\ts\tTorquay Museum\t\t", +"TOU\th\tUniversity of Tours\t\t", +"TOYA\ts\tToyama Science Museum, Botany Department\t\t", +"TPI\ts\tThe Pirbright Institute\t\t", +"TPI:ENT\ts\tThe Pirbright Institute, Entomology collection", +"TPII\ts\tThanksgiving Point Institute\t\t", +"TPNG\ts\tDepartment of Primary Industry\t\t", +"TPV\ts\tPrairie View A & M University, Biology Department\t\t", +"TR\ts\tMuseo Tridentino di Scienze Naturali\t\t", +"TRA\ts\tAmerican Plant Life Society\t\t", +"TRD\ts\tAncient House Museum\t\t", +"TRE\ts\tTrencianske muzeum, Scientific Department\t\t", +"TRES\ts\tTresco Abbey\t\t", +"TRH\ts\tNorwegian University of Science and Technology, Department of Natural History\t\t", +"TRIN\ts\tThe National Herbarium of Trinidad and Tobago\t\t", +"TRM\ts\tVlastivedne muzeum Trutnov\t\t", +"TRN\ts\tN. Copernicus University\t\t", +"TRO\ts\tRoyal Horticultural Society of Cornwall\t\t", +"TROM\ts\tUniversity of Tromsoe, Botanical Department\t\t", +"TROY\ts\tTroy State University, Department of Biological and Environmental Sciences\t\t", +"TRPM\th\tTottori Prefectural Museum\t\t", +"TRT\ts\tRoyal Ontario Museum, Department of Natural History\t\t", +"TRTC\ts\tRoyal Ontario Museum, Center for Biodiversity and Conservation Biology\t\t", +"TRTE\ts\tErindale College, University of Toronto, Department of Biology\t\t", +"TRTS\ts\tScarborough College, University of Toronto, Botany Department\t\t", +"TRU\ts\tRoyal Cornwall Museum\t\t", +"TRV\ts\tTransvaal Museum\t\t", +"TS\ts\tNational University of Shandong, Biology Department\t\t", +"TSB\ts\tUniversita degli Studi di Trieste, Dipartimento di Biologia\t\t", +"TSC\ts\tTarleton State University, Tarleton State Collection\t\t", +"TsGM\ts\tCentral Geological Museum\t\t", +"TSH\th\tUniversity of Tsukuba\t\t", +"TSM\ts\tErbario, Museo Civico di Storia Naturale, Trieste\t\t", +"TSMHN\ts\tTeylers Strichtina Museum\t\t", +"TsNIGRI\ts\tTsentralny Nauchno-Issledovatelskii Geolgo-Razvedochni Muzei (Chernyshev's Central Museum of Geological Exploration)\t\t", +"TSSMC\ts\tTeton Science School\t\t", +"TSTN\ts\tTroston Hall\t\t", +"TSU\ts\tMiye University\t\t", +"TSY\tc\tLaboratory of Mycology, Division of Microbiology\t\t", +"TTC\ts\tTexas Tech University, Biological Sciences Department\t\t", +"TTCC\ts\tTexas Tech University\t\t", +"TTMB\ts\tTermeszettudomanyi Muzeum\t\t", +"TTN\ts\tSomerset County Museum\t\t", +"TTRS\ts\tTall Timbers Research Station, Fire Ecology Laboratory\t\t", +"TTU\ts\tTexas Tech University, Museum\t\t", +"TTY\ts\tWestonbirt School\t\t", +"TU\ts\tInstitut fur Geologie und Palaontologie, Technische Universitat Braunschweig\t\t", +"TU\ts\tUniversity of Tartu, Botanical and Mycological Museum\t\t", +"TU\ts\tTulane University, Museum of Natural History\t\t", +"TU:Birds\ts\tTulane University, Museum of Natural History, Ornithological Collection", +"TU:Fish\ts\tTulane University, Museum of Natural History, Fish Collection", +"TU:Herptiles\ts\tTulane University, Museum of Natural History, Amphibian And Reptile Collection", +"TU:Invertebrates\ts\tTulane University, Museum of Natural History, Invertebrate Collection", +"TU:Mammals\ts\tTulane University, Museum of Natural History, Mammal Collection", +"TUAT\ts\tTokyo University of Agriculture\t\t", +"TUB\ts\tEberhard-Karls-Universitaet Tuebingen, Institut fuer Biologie I\t\t", +"TUBSB\tb\tTohoku University Brassica Seed Bank\t\t", +"TUC\ts\tUniversity of Arizona, Ecology and Evolutionary Biology Department\t\t", +"TUCH\ts\tTribhuvan University, Central Department of Botany\t\t", +"TUCIM\tc\tTU Wien collection of industrial microorganisms\t\t", +"TUFC\ts\tTottori University Fungal Culture Collection\t\t", +"TUFIL\ts\tTokyo University of Fisheries, Ichthyological Laboratory\t\t", +"TUFT\ts\tTufts University, Biology Department\t\t", +"TUH\ts\tTehran University, Department of Biology\t\t", +"TULE\ts\tTokyo University of Agriculture & Technology\t\t", +"TULS\ts\tUniversity of Tulsa\t\t", +"TULV\ts\tJardin Botanico Juan Maria Cespedes\t\t", +"TUM\th\tTechnische Universitat Munchen\t\t", +"TUMH\ts\tTottori Fungus/Mushroom Resource and Research Center\t\t", +"TUN\ts\tUniversite de Tunis, Laboratoire de Biologie Vegetale\t\t", +"TUNG\ts\tTunghai University, Biology Department\t\t", +"TUP\ts\tTrent University, Biology Department\t\t", +"TUPH\ts\tInstitute of Public Health Research\t\t", +"TUR\ts\tUniversity of Turku\t\t", +"TURA\ts\tAabo Akademi University, Biology Department\t\t", +"TURP\ts\tTurpan Eremophytes Botanical Garden\t\t", +"TUS\ts\tTohoku University, Biological Institute\t\t", +"TUSG\ts\tTohoku University\t\t", +"TUT\ts\tDaejeon University, Department of Biology\t\t", +"TUTC\ts\tTunghai University\t\t", +"TUZ\ts\tTartu University Zoological Department\t\t", +"TV\ts\tCentro de Estratigrafia e Paleobiologia da Universidade Nova de Lisboa\t\t", +"TVBG\ts\tTver State University\t\t", +"TVY\ts\tTurvey Abbey\t\t", +"TWC\ts\tTexas Wesleyan College, Museum of Zoology\t\t", +"TWRA\ts\tTennessee Wildlife Resources Agency\t\t", +"TYF\ts\tShangxi Forestry Institute\t\t", +"TYM\th\tBotanic Gardens of Toyama\t\t", +"TZM\ts\tNational Science Museum\t\t", +"U\ts\tNationaal Herbarium Nederland, Utrecht University branch\t\t", +"UA\ts\tDepartment of Historical Geology and Paleontology\t\t", +"UA\ts\tUniversity of Alabama Collection\t\t", +"UA\ts\tUniversity of Arizona\t\t", +"UAAAC\ts\tUniversity of Alaska Anchorage Avian Collection\t\t", +"UAAH\ts\tHerbarium, Department of Biological Sciences, University of Alaska Anchorage\t\t", +"UAAM\ts\tThe Arthropod Museum, University of Arkansas\t\t", +"UAB\ts\tUniversidad Autonoma de Barcelona\t\t", +"UABC\ts\tUniversidad Autonoma de Baja California\t\t", +"UABCS\ts\tUniversidad Nacional Autonoma de Baja California Sur (Mexico)\t\t", +"UABD\ts\tUniversity of Alabama\t\t", +"UAC\ts\tUniversity of Calgary, Department of Biological Sciences\t\t", +"UACC\ts\tUniveridad Autonoma de Chapingo\t\t", +"UACCC\tc\tUniversity of Alabama Chytrid Culture Collection\tUA-SEC", +"UADBA\ts\tUniversity dAntananarivo, Department de Biologie Animale\t\t", +"UADY\ts\tUniversidad Autonoma de Yucatan, Departamento de Botanica\t\t", +"UAEM\ts\tUniveridad Autonoma de Morelos\t\t", +"UAEU\ts\tUnited Arab Emirates University\t\t", +"UAGC\ts\tUniversidad Autonoma de Guerrero, Area de Ciencias Naturales\t\t", +"UAIC\ts\tUniversity of Abidjan\t\t", +"UAIC\ts\tUniversity of Alabama, Ichthyological Collection\t\t", +"UAIC\ts\tUniversity of Arizona\t\t", +"UALRVC\ts\tUniversity of Arkansas at Little Rock, Vertebrate Collection\t\t", +"UAM\ts\tUniversity of Alaska, Museum of the North\tUAF", +"UAM:Bird\ts\tUniversity of Alaska, Museum of the North, Bird Collection", +"UAM:Bryo\ts\tUniversity of Alaska, Museum of the North, Bryozoan Collection", +"UAM:Crus\ts\tUniversity of Alaska, Museum of the North, Marine Arthropod Collection", +"UAM:Ento\ts\tUniversity of Alaska, Museum of the North, Insect Collection", +"UAM:ES\ts\tUniversity of Alaska, Museum of the North, Earth Science", +"UAM:Fish\ts\tUniversity of Alaska, Museum of the North, Fish Collection", +"UAM:Herb\ts\tUniversity of Alaska, Museum of the North, UAM Herbarium", +"UAM:Herp\ts\tUniversity of Alaska, Museum of the North, Amphibian and Reptile Collection", +"UAM:Mamm\ts\tUniversity of Alaska, Museum of the North, Mammal Collection", +"UAM:Moll\ts\tUniversity of Alaska, Museum of the North, Mollusc Collection", +"UAM:Paleo\ts\tUniversity of Alaska, Museum of the North, paleontology collection", +"UAM\tc\tUniversidad Autonoma De Madrid culture collection of cyanobacteria\t\t", +"UAM\ts\tUniversity of Alabama, Malacology Collection\t\t", +"UAM\ts\tUniversity of Arkansas at Monticello\t\t", +"UAM\ts\tUniversidad de los Andes, Facultad de Ciencias\t\t", +"UAMH\tscb\tUniversity of Alberta Microfungus Collection and Herbarium\t\t", +"UAMI\ts\tUniversidad Autonoma Metropolitana, Unidad Iztapalapa (Mexico)\t\t", +"UAMIZ\ts\tUniversidad Autonoma Metropolitana, Iztapalapa, Departamento de Biologia\t\t", +"UAMM\ts\tUniversidad de los Andes\t\t", +"UAMZ\ts\tUniversity of Alberta Museum of Zoology\t\t", +"UAMZC\ts\tUniversity of Arkansas, Museum Zoological Collections\t\t", +"UANL\ts\tUniversidad Autonoma de Nuevo Leon\t\t", +"UAPC\th\tUniversity of Alberta\t\t", +"UARK\ts\tUniversity of Arkansas\t\t", +"UAS\ts\tUniversidad Autonoma de Sinaloa\t\t", +"UAS-B\ts\tUniversity of Agricultural Sciences Bangalore\t\t", +"UASB\ts\tUniversity of Agricultural Sciences, Bangalore\t\t", +"UASC\ts\tMuseo de Historia Natural \"Noel Kempff Mercado\"\t\t", +"UASK\ts\tUkrainian Academy of Science\t\t", +"UASM\ts\tUniversity of Alberta, E.H. Strickland Entomological Museum\t\t", +"UAT\ts\tUniversidad Autonoma de Tamaulipas\t\t", +"UAVP\ts\tUniversity of Alberta, Laboratory for Vertebrate Paleontology\t\t", +"UAWC\tb\tUnion of Agricultural Work Committees\t\t", +"UAY\ts\tUniversidad Autonoma de Yucatan, Facultad de Medicina Veterinaria y Zootecnia\t\t", +"UAZ\ts\tUniversity of Arizona\t\t", +"UB\tsc\tUniversity of Brasilia Herbarium\t\t", +"UB\ts\tLaboratoire de Biostratigraphie\t\t", +"UBA\ts\tMongolian Academy of Sciences\t\t", +"UBC\ts\tBeaty Biodiversity Museum, University of British Columbia\t\t", +"UBC:CTC\ts\tBeaty Biodiversity Museum, University of British Columbia, Cowan Tetrapod Collection", +"UBC:Fish\ts\tBeaty Biodiversity Museum, University of British Columbia, Fish Collection", +"UBC:SEM\ts\tBeaty Biodiversity Museum, University of British Columbia, Spencer Entomological Museum", +"UBCC\tc\tUniversity of Barcelona Culture Collection\t\t", +"UBCZ\ts\tUniversity of British Columbia, Spencer Entomological Museum\t\t", +"UBDH\th\tUniversiti Brunei Darussalam\t\t", +"UBJTL\ts\tUniversidad Bogota Jorge Tadeo Lozano\t\t", +"UBL\ts\tUniversite du Benin\t\t", +"UBOCC\tc\tUniversite de Bretagne Occidentale\t\t", +"UBT\ts\tOekologisch-Botanischer Garten\t\t", +"UBU\ts\tMongolian State University, Botany Department\t\t", +"UC\tscb\tUniversity of Canberra Wildlife Tissue Collection\t\t", +"UC\ts\tUniversity of California, University Herbarium\t\t", +"UC\tc\tUpjohn Culture Collection\t\t", +"UCAC\ts\tUniversity of Central Arkansas, Department of Biology\t\t", +"UCAM\ts\tUniversidad Autonoma de Campeche\t\t", +"UCB\ts\tUniversity of California at Berkeley\t\t", +"UCBG\ts\tUniversity of Botswana, Department of Biological Sciences\t\t", +"UCBL\ts\tCentre de Paleontologie Stratigraphique et Paleoecologie\t\t", +"UCBMG\tc\tUniversity of California Berkeley Mycogarden\t\t", +"UCC\ts\tUniversity of Cincinnati\t\t", +"UCC\ts\tUniversity College Cork\t\t", +"UCCC\ts\tUniversidad de Concepcion, Museo de Zoologia\t\t", +"UCCM\tc\tUniversity of Calabar Collection of Microorganisms\t\t", +"UCD\tscb\tUniversity of California, Davis\t\t", +"UCDBA\ts\tUniversity of Chicago\t\t", +"UCDFST\tc\tPhaff Yeast Culture Collection\t\t", +"UCFC\ts\tUniversity of Central Florida\t\t", +"UCGC\ts\tUniversity of Colorado, Geological Museum\t\t", +"UCGE\tc\tUnit Cell of Genetic Engineering, Department of Biochemistry\t\t", +"UCH\th\tUniversidad Autonoma de Chiriqui\t\t", +"UCHT\ts\tUniversity of Tennessee, Chattanooga, Department of Biological and Environmental Sciences\t\t", +"UCI\ts\tUniversity of Ibadan, Botany and Microbiology Department\t\t", +"UCJ\ts\tUniversite d'Abidjan, Departemente de Botanique\t\t", +"UCL\tc\tCatholic University of Louvain\t\t", +"UCL\ts\tUniversity College London\t\t", +"UCLA\ts\tUniversity of California at Los Angeles\t\t", +"UCLAF\tc\tHMR/Romainville\t\t", +"UCLGMZ\ts\tGrant Museum of Zoology and Comparative Anatomy\t\t", +"UCLZ\ts\tUniversity College London\t\t", +"UCM\ts\tUniversidad Complutense Madrid\t\t", +"UCM\tc\tUkrainian Collection of Microorganisms, Zabolotny Institute of Microbiology and Virology\t\t", +"UCM\ts\tUniversity of Colorado Museum\t\t", +"UCM:Bird\ts\tUniversity of Colorado Museum, University of Colorado Museum Bird Collection", +"UCM:Fish\ts\tUniversity of Colorado Museum, University of Colorado Museum Fish collection", +"UCM:Herp\ts\tUniversity of Colorado Museum, University of Colorado Museum Amplibian and Reptile collection", +"UCM:Mamm\ts\tUniversity of Colorado Museum, University of Colorado Museum Mammal Collection", +"UCMC\ts\tUniversity of Colorado Museum\t\t", +"UCME\ts\tFaculdad de Biologia, Departamento de Zoologia\t\t", +"UCMM\ts\tPontificia Universidad Catolica Madre y Maestra\t\t", +"UCMP\ts\tUniversity of California Museum of Paleontology\t\t", +"UCMS\ts\tStorrs, University of Connecticut\t\t", +"UCNW\ts\tUniversity of Wales\t\t", +"UCNZ\ts\tUniversity of Canterbury\t\t", +"UCOB\ts\tUniversidad Centroccidental Lisandro Alvarado, Departamento de Ciencias Biologicas\t\t", +"UCOCV\ts\tUniversity of Central Oklahoma, Collection of Vertebrates\t\t", +"UCONN\ts\tUniversity of Connecticut\t\t", +"UCP\ts\tUniversidad del Cauca\tMHNUC ", +"UCPC\ts\tUniversidad del Cauca\t\t", +"UCR\ts\tUniversidad de Costa Rica, Museo de Zoologia\t\t", +"UCR\ts\tUniversity of California, Riverside\t\t", +"UCR:ENT\ts\tUniversity of California, Riverside, Entomology Collection", +"UCS\ts\tUniversity of Connecticut\t\t", +"UCS\ts\tUnion College, Department of Biological Sciences\t\t", +"UCSA\ts\tUniversity College of Swansea, Botany Department\t\t", +"UCSB\ts\tUniversity of California, Santa Barbara\t\t", +"UCSC\ts\tUniversity of California, Department of Environmental Studies\t\t", +"UCSW\ts\tUniversity College, Botany Department\t\t", +"UCVC\ts\tUniversidad Catolica de Valparaiso\t\t", +"UCWI\ts\tUniversity of the West Indies, Department of Life Sciences\t\t", +"UDBC\ts\tUniversidad Distrital\t\t", +"UDCC\ts\tUniversity of Delaware\t\t", +"UDEL\ts\tUniversity of Delaware\t\t", +"UDM\ts\tMuseo Friulano di Storia Naturale\t\t", +"UDO\ts\tUniversidad de Oriente\t\t", +"UDONECI\ts\tUniversidad de Oriente\t\t", +"UDSM\ts\tUniversity of Dar es Salaam\t\t", +"UDU\ts\tUdmurt State University, Department of Biology and Chemistry\t\t", +"UDW\ts\tUniversity of Durban-Westville, Botany Department\t\t", +"UEA\ts\tUniversity of East Anglia\t\t", +"UEC\ts\tUniversidade Estadual de Campinas, Departamento de Botanica\t\t", +"UEFS\ts\tLaboratorio de Ictiologia\t\t", +"UENF\ts\tUniversidade Estadual do Norte Fluminense\t\t", +"UESC\th\tUniversidade Estadual de Santa Cruz\t\t", +"UESS\ts\tUniversidad de El Salvador\t\t", +"UEVH\ts\tUniversidade de Evora, Departamento de Biologia\t\t", +"UF\tsb\tUniversity of Florida Museum of Natural History\tFLMNH", +"UF/FGS\ts\tFlorida Geological Survey\t\t", +"UF:Herpetology\ts\tUniversity of Florida Museum of Natural History, Herpetology Collection", +"UF:Ichthyology\ts\tUniversity of Florida Museum of Natural History, Fish Collection", +"UF:Invertebrate\ts\tUniversity of Florida Museum of Natural History, Invertebrate Zoology and Malacology Collection", +"UF:Mammalogy\ts\tUniversity of Florida Museum of Natural History, Mammalogy Collection", +"UF:Ornithology\ts\tUniversity of Florida Museum of Natural History, Ornithology Skins and Skeletons Collection", +"UF:Porifera\ts\tUniversity of Florida Museum of Natural History, ", +"UFA\ts\tUfa Scientific Centre, Russian Academy of Sciences\t\t", +"UFACPZ\th\tUniversidade Federal do Acre/Parque Zoobotanico\t\t", +"UFC\ts\tUniversidade Federal do Ceara, Departamento de Biologia\t\t", +"UFES\ts\tUniversidade Federal do Espirito Santo\t\t", +"UFG\ts\tUniversidade Federal de Goias, Unidade de Conservacao\t\t", +"UFH\ts\tUniversity of Fort Hare, Botany Department\t\t", +"UFHNH\ts\tUtah Field House of Natural History State Park\t\t", +"UFJF\ts\tUniversidade Federal de Juiz de Fora\t\t", +"UFMA\ts\tUniversidade Federal do Maranhao, Curso de Farmacia\t\t", +"UFMG\ts\tUniversidade Federal de Minas Gerais\t\t", +"UFMI\ts\tUniversidade Federal de Mato Grosso, Instituto de Biociencias\t\t", +"UFMT\ts\tUniversidade Federal de Mato Grosso\t\t", +"UFNH\ts\tUtah Field House Natural History [address unknown]\t\t", +"UFOP\ts\t Universidade Federal de Ouro Preto\t\t", +"UFP\ts\tUniversidade Federal de Pernambuco, Departamento de Botanica\t\t", +"UFPB\ts\tDepartamento de Sistematica e Ecologia\t\t", +"UFPEDA\tc\tUniversidade Federal de Pernambuco\t\t", +"UFRG\ts\tInstituto de Biologia\t\t", +"UFRGS\ts\tUniversidade Federale do Rio Grande do Sul\t\t", +"UFRJ\tsc\tHerbario e Colecao Fitopathologica \"Verlande Duarte Silveira\"\t\t", +"UFRJ\ts\tDepartramento de Zoologia, Universidade Federal do Rio de Janeiro\t\t", +"UFRJ:POR\ts\tDepartramento de Zoologia, Universidade Federal do Rio de Janeiro, Porifera collection", +"UFRJIM\tc\tDepartamento de Microbiologia Medica\t\t", +"UFRN\ts\tUniversidade Federal do Rio Grande do Norte\t\t", +"UFRN:Fungos\ts\tUniversidade Federal do Rio Grande do Norte, Fungal collection", +"UFRR\th\tUniversidade Federal de Roraima\t\t", +"UFS\ts\tNyabyeya Forestry College, Department of Environmental Forestry\t\t", +"UFSC\ts\tUniversidade Federal de Santa Catarina\t\t", +"UFScarCC\tc\tFreshwater Microalgae Collection Cultures\t\t", +"UFU\th\tUral Federal University\t\t", +"UFVB\ts\tVicosa, Universidade Federal de Vicosa, Museum of Entomology\t\t", +"UG\ts\tMuseo del Departamento de Estratigrafia y Paleontologia\t\t", +"UG\ts\tUniversity of Ghana\t\t", +"UGAMNH\ts\tUniversity of Georgia Museum of Natural History\t\t", +"UGCA\ts\tUniversity of Georgia\t\t", +"UGDA\ts\tGdansk University, Department of Plant Taxonomy and Nature Conservation\t\t", +"UGDZ\ts\tUniversity of Guelph, Department of Zoology\t\t", +"UGG\ts\tUniversity of Guam\t\t", +"UGGE\ts\tUniversidad de Guayaquil\t\t", +"UGGG\ts\tUniversity of Guyana\t\t", +"UGM\ts\tUniversity of Guam\t\t", +"UGMD\ts\tZoology Museum of the University of Ghent\t\t", +"UH\ts\tUniversity of Hawaii\t\t", +"UHCC\tc\tUniversity of Helsinki Cyanobacteria Culture Collection\t\t", +"UHI\ts\tUssishkin House, Botany Department\t\t", +"UHM\ts\tManoa, College of Tropical Agriculture, Department of Entomology\t\t", +"UI\ts\tUniversity of Ibadan\t\t", +"UI\ts\tBureau of Land Management\t\t", +"UICC\tc\tUniversity of Indonesia Culture Collection\t\t", +"UIDA\ts\tUniversity of Idaho, Bird and Mammal Museum\t\t", +"UIM\ts\tUniversity of Idaho\t\t", +"UIMNH\ts\tUniversity of Illinois, Museum of Natural History\t\t", +"UIS\ts\tUniversidad Industrial de Santander, Departamento de Biologia\t\t", +"UIS:H\ts\tUniversidad Industrial de Santander, Departamento de Biologia, Collecion Herpetologica", +"UISMHN\ts\tUniversidad Industrial de Santander, Museo de Historia Natural\t\t", +"UJAT\ts\tUniversidad Juarez Autonoma de Tabasco\t\t", +"UJB\tc\tUniversity of Jaffna Botany\t\t", +"UJIM\ts\tUniversity of Jordan Insect Museum\t\t", +"UK\ts\tUniversity of Kentucky\t\t", +"UKEN\ts\tUniversity of Kentucky\t\t", +"UKKP\tc\tUniversiti Kebangsaan Kultur Perubatan\t\t", +"UKKY\ts\tUniversity of Kunming\t\t", +"UKM\ts\tUniversitaetsklinikum Muenster\t\t", +"UKMB\ts\tUniversiti Kebangsaan Malaysia, Botany Department\t\t", +"UKMHC\ts\tUniversiti Kebangsaan Malaysia\t\t", +"UKMHC:HC\ts\tUniversiti Kebangsaan Malaysia, Herpetological Collection", +"UKMS\ts\tUniversiti Kebangsaan Malaysia, Kampus Sabah\t\t", +"UKMS\ts\tSudan Natural History Museum\t\t", +"UKS\ts\tUniversity of Khartoum\t\t", +"UKSPI\ts\tUst-Kamenogorsk State Pedagogical Institute, Botany Department\t\t", +"UL\ts\tUniversity of Louisville\t\t", +"ULABG\ts\tUniversidad de los Andes, Laboratorio de Biogeografia\t\t", +"ULCI\ts\tUniversidad de la Laguna\t\t", +"ULF\ts\tUniversite Laval, Departement des Sciences forestieres\t\t", +"ULKY\ts\tUniversity of Louisville\t\t", +"ULLZ\ts\tUniversity of Louisiana at Layafette Zoological Collection\tUSLZ", +"ULM\ts\tUniversitaet Ulm, Abteilung Systematische Botanik und Oekologie\t\t", +"ULMG\ts\tUniversity of Leipzig\t\t", +"ULN\ts\tUniversity of Lagos\t\t", +"ULQC\ts\tUniversity of Laval\t\t", +"ULS\ts\tUniversidad de La Serena, Departamento de Biologia\t\t", +"ULT\ts\tAl-Faateh University, Botany Department\t\t", +"ULV\ts\tUniversidad Central de Las Villas\t\t", +"UM\ts\tUniversity of Marburg\t\t", +"UM\ts\tUniversity of Memphis, Mammal Collection\t\t", +"UM\ts\tUmtali Museum\t\t", +"UMA\ts\tUniversity of Massachusetts, Museum of Zoology\t\t", +"UMAN\ts\tUniversity of Manitoba, Zoological Collection\t\t", +"UMB\ts\tUebersee-Museums\t\t", +"UMBB\ts\tUebersee-Museum, Bremen or Department of Zoology, University of Bremen\t\t", +"UMBC\ts\tUniveristy of Malawi\t\t", +"UMBS\ts\tUniversity of Michigan\t\t", +"UMD\ts\tUniversity of Minnesota, Duluth\t\t", +"UMDC\ts\tUniversity of Maryland\t\t", +"UMDE\ts\tUniversity of Maine\t\t", +"UME\ts\tUmeaa University\t\t", +"UMEC\ts\tUniversity of Massachusetts\t\t", +"UMED\ts\tUniversity of Moi\t\t", +"UMF\ts\tUniversity of Miami\t\t", +"UMF\ts\tUniversity of Maine, Farmington\t\t", +"UMF\ts\tUniversity of Michigan, Biology Department\t\t", +"UMFFTD\tc\tFood and Fermentation Technology Division, University of Mumbai\t\t", +"UMFK\ts\tUniversity of Maine at Fort Kent, Biology Department\t\t", +"UMH\ts\tUniversidad Miguel Hernandez, Departamento de Biologia Aplicada\t\t", +"UMHB\ts\tUniversity of Mary Hardin-Baylor\t\t", +"UMIC\ts\tUniversity of Mississippi\t\t", +"UMIM\ts\tUniveristy of Miami Ichthyological Museum\t\t", +"UMIP\tc\tCollection de Champignons et Actinomycetes Pathogenes\t\t", +"UMKC\ts\tUniversity of Missouri\t\t", +"UMKL\ts\tUniversity of Malaysia\t\t", +"UMKU\ts\tUganda Museum\t\t", +"UMM\th\tUniversity of Maine at Machias\t\t", +"UMML\ts\tUniversity of Miami Marine Laboratory\t\t", +"UMMP\ts\tUniversity of Michigan\t\t", +"UMMZ\ts\tUniversity of Michigan, Museum of Zoology\t\t", +"UMMZ:MC\ts\tUniversity of Michigan, Museum of Zoology, Mollusk Collection", +"UMNH\ts\tUtah Museum of Natural History\t\t", +"UMNH:Mamm\ts\tUtah Museum of Natural History, Mammal collection", +"UMO\ts\tUniversity Museum of Natural History\t\t", +"UMO\ts\tUniversity of Maine\t\t", +"UMO\ts\tDunn-Palmer Herbarium, University of Missouri, Museum Support Center\t\t", +"UMOC\ts\tUniversity of Missouri, Museum of Zoology\t\t", +"UMRC\tc\tUniversity of Minnesota Rhizobium Collection\t\t", +"UMRM\ts\tW.R. Enns Entomology Museum\t\t", +"UMS\ts\tUniversiti Malaysia Sabah\t\t", +"UMSA\ts\tInstituto de Ecologia\t\t", +"UMSNH\ts\tIchthyology Collection of the Laboratory of Aquatic Biology, Michoacan University of San Nicolas de Hidalgo\t\t", +"UMSP\ts\tUniversity of Minnesota\t\t", +"UMSS\ts\tUniversidad Mayor de San Simon, Facultad de Ciencias y Tecnologia, Centro de Biodiversidad, Zoologia,Laboratorio de Ictiologia\t\t", +"UMT\ts\tMutare Museum\t\t", +"UMUT\ts\tUniversity Museum, University of Tokyo\t\t", +"UMUTZ\ts\tDepartment of Zoology, University Museum\t\t", +"UMZ\ts\tUnivesity Museum of Zoology, Cambridge University\t\t", +"UMZC\ts\tUniversity Museum of Zoology Cambridge\t\t", +"UMZM\ts\tUniversity of Montana, Zoological Museum\t\t", +"UN\ts\tUniversity of Nebraska\t\t", +"UNA\ts\tUniversity of Alabama, Department of Biological Sciences\t\t", +"UNAB\ts\tUniversidad Nacional, Facultad de Agronomia\t\t", +"UNAC\ts\tUniversidad Nacional Agraria\t\t", +"UNAD\ts\tUniversidad Nacional Agraria\t\t", +"UNAF\ts\tUniversity of North Alabama, Department of Biology\t\t", +"UNAH\ts\tUniversidad Nacional Autonoma de Honduras\t\t", +"UNAM\ts\tUniversidad Nacional Autonoma de Mexico\tIBUNAM", +"UNAM:CNAC\ts\tUniversidad Nacional Autonoma de Mexico, Coleccion Nacional de Acaros", +"UNAM:CNAN\ts\tUniversidad Nacional Autonoma de Mexico, Coleccion Nacional de Aracnidos", +"UNAM:CNAR\ts\tUniversidad Nacional Autonoma de Mexico, Coleccion Nacional de Anfibios", +"UNAM:CNAV\ts\tUniversidad Nacional Autonoma de Mexico, Coleccion Nacional de Aves", +"UNAM:CNCR\ts\tUniversidad Nacional Autonoma de Mexico, Coleccion Nacional de Crustaceos", +"UNAM:CNHE\ts\tUniversidad Nacional Autonoma de Mexico, Coleccion Nacional de Helmintos", +"UNAM:CNIN\ts\tUniversidad Nacional Autonoma de Mexico, Coleccion Nacional de Insectos", +"UNAM:CNMA\ts\tUniversidad Nacional Autonoma de Mexico, Coleccion Nacional de Mamiferos", +"UNAM:CNMO\ts\tUniversidad Nacional Autonoma de Mexico, Coleccion Nacional de Moluscos", +"UNAM:CNPE\ts\tUniversidad Nacional Autonoma de Mexico, Coleccion Nacional de Peces", +"UNAM:CNPGG\ts\tUniversidad Nacional Autonoma de Mexico, Coleccion Nacional del Phylum Porifera Gerardo Green", +"UNAN\ts\tUniversidad Nacional Autonoma de Nicaragua\t\t", +"UNB\ts\tConnell Memorial Herbarium\t\t", +"UNC-B\ts\tUniversity of Northern Colorado\t\t", +"UNCA\th\tUniversity of North Carolina at Asheville\t\t", +"UNCB\ts\tUniversidad Nacional de Colombia, Insituto de Ciencias Naturales de la Universidad Nacional\t\t", +"UNCC\ts\tUniversidad Nacional de Caldas, Museo de Historia Natural\t\t", +"UNCC\ts\tUniversity of North Carolina, Biology Department\t\t", +"UNCG\tc\tUniversity of North Carolina at Greensboro\t\t", +"UNCM\ts\tMuseo de Entomologia \"Francisco Luis Gallego\"\t\t", +"UNCP\ts\tUniversidad Nacional de Colombia\t\t", +"UNCW\ts\tUniversity of North Carolina at Wilmington\t\t", +"UND\ts\tUniversity of North Dakota, Vertebrate Museum\t\t", +"UNDH\ts\tUniversity of Natal Durban\t\t", +"UNEFM\ts\tUniversidad Experimental Francisco de Miranda\t\t", +"UNEVR\ts\tUniversity of Nevada, Museum of Biology\t\t", +"UNEX\ts\tUniversidad de Extremadura, Departamento de Botanica\t\t", +"UNEX:FECRGA\tc\tUniversidad de Extremadura, Departamento de Botanica, Fungal Endophytes Collection of the Research Group of Agronomy", +"UNH\ts\tUniversity of New Hampshire\t\t", +"UNI\ts\tUniversity of Northern Iowa\t\t", +"UNIMAS\ts\tUniversiti Malaysia Sarawak\t\t", +"UNIN\ts\tUniversity of the North, Botany Department\t\t", +"UNIP\ts\tUniversidade Paulista, Laboratorio de Botanica\t\t", +"UNIQEM\tc\tInstitute of Microbiology, Russian Academy of Sciences\t\t", +"UNITEC\th\tUnitec Institute of Technology\t\t", +"UNL\ts\tUniversidad Autonoma de Nuevo Leon\t\t", +"UNL\ts\tCentro de Estratigrafia e Paleobiologia da Universidade Nova de Lisboa\t\t", +"UNL\ts\tUniversity of Nebraska State Museum\t\t", +"UNLO\ts\tUniversidad Nacional Experimental de los Llanos Occidental\t\t", +"UNLP\ts\tUniversidad Nacional de La Plata\t\t", +"UNLV\ts\tUniversity of Nevada, Las Vegas, Department of Biological Sciences\t\t", +"UNM\ts\tUniversity of New Mexico, Department of Biology\t\t", +"UNMC\ts\tUniversity of New Mexico\t\t", +"UNMDP\ts\tUniversidad Nacional de Mar del Plata, Mar del Plata, Argentina\t\t", +"UNN\ts\tUniversity of Nigeria, Botany Department\t\t", +"UNNEC\ts\tUniversidad Nacional del Nordeste, Facultad de Ciencias Exactas y Naturales y Agrimensura\t\t", +"UNNF\ts\tUniversite de Nancy\t\t", +"UNO\ts\tUniversity of Nebraska at Omaha\t\t", +"UNOAL\ts\tUniversity of Northern Alabama\t\t", +"UNOVC\ts\tUniversity of New Orleans\t\t", +"UNPSJB-Pv\ts\tUniversidad Nacional de la Patagonia\t\t", +"UNR\ts\tUniversidad Nacional de Rosario, Botanica y Ecologia Vegetal\t\t", +"UNR\ts\tUniversity of Nevada, Museum of Biology\t\t", +"UNS\ts\tUniversity of Science, Ho Chi Minh City, Vietnam\t\t", +"UNSA\ts\tUniversity of Natal\t\t", +"UNSL\ts\tUniversidad Nacional de San Luis\t\t", +"UNSM\ts\tUniversity of Nebraska State Museum\t\t", +"UNSW\tc\tMicrobiology Culture Collection, University of New South Wales\t\t", +"UNSW\ts\tJohn T. Waterhouse Herbarium\t\t", +"UNT\ts\tUniversidad nacional de Tucumn\t\t", +"UNWH\ts\tUniversity of North-West, Biological Sciences Department\t\t", +"UO\ts\tUniversity of Oklahoma\t\t", +"UO\ts\tUniversity of Ostrava\t\t", +"UOA/HCPF\tc\tUOA/HCPF University of Athens/Hellenic Collection of Pathogenic Fungi\t\t", +"UOG\ts\tUniversity of Guelph\t\t", +"UOG:BIO\tb\tUniversity of Guelph, Biodiversity Institute of Ontario", +"UOG:DEBU\ts\tUniversity of Guelph, Ontario Insect Collection", +"UOIC\ts\tUniversity of Oregon\t\t", +"UOJ\ts\tUniversidad del Oriente, Departamento de Agronomia\t\t", +"UOM\ts\tUniversity of Missouri\t\t", +"UOMNH\ts\tUniversity of Oregon, Museum of Natural History\t\t", +"UOMZ\ts\tUniversity of Oklahoma, Stovall Museum of Zoology\t\t", +"UOP\ts\tUniversity of Opole\t\t", +"UOPJ\ts\tOsaka Prefecture University\t\t", +"UOS\ts\tUniversity of the South, Biology Department\t\t", +"UP\ts\tUniversity of Papua and New Guinea\t\t", +"UPA\ts\tUniversity of Patras, Department of Plant Biology\t\t", +"UPCB\ts\tUniversidade Federal do Parana, Departamento de Botanica\t\t", +"UPCC\tc\tNatural Sciences Research Institute Culture Collection\t\t", +"UPCT\th\tUniversidad Politecnica De Cartagena\t\t", +"UPEI\ts\tUniversity of Prince Edward Island, Biology Department\t\t", +"UPF\ts\tUniversite de Polynesie Francaise Herbarium\t\t", +"UPIE\tb\tUnidad de Patologia Infecciosa y Epidemiologia\t\t", +"UPLB\ts\tMuseum of Natural History, University of the Philippines\t\t", +"UPM\ts\tDepartement des Siences de la Terre\t\t", +"UPM\ts\tUniversiti Pertanian Malaysia, Biology Department\t\t", +"UPM\ts\tUdory Paleontological Museum\t\t", +"UPMR\tc\tRhizobium Collection\t\t", +"UPMSI\ts\tMarine Science Institute\t\t", +"UPNA\ts\tUniversidad Publica de Navarra, Departamento de Ciencias del Medio Natural\t\t", +"UPNG\ts\tUniversity of Papua New Guinea, Division of Biological Sciences\t\t", +"UPOL\ts\tUniversity Palacky Olomouc\t\t", +"UPOS\ts\tUniversidad Pablo de Olavide, Ciencias Ambientales (Botanica)\t\t", +"UPP\ts\tUppingham School Museum\t\t", +"UPPC\ts\tUniversity of the Philippines\t\t", +"UPR\ts\tPuerto Rico Botanic Garden, University of Puerto Rico\t\t", +"UPRG\ts\tUniversidad Nacional \"Pedro Ruiz Gallo\"\t\t", +"UPRM\tc\tUniversity of Puerto Rico at Mayagueez, Rhizobium Culture Collection\t\t", +"UPRP\ts\tUniversity of Puerto Rico at Rio Piedras\t\t", +"UPRRP\ts\tUniversity of Puerto Rico, Biology Department\t\t", +"UPS\ts\tUppsala University, Museum of Evolution, Botany Section (Fytoteket)\t\t", +"UPSA\ts\tUniversity of Pretoria\t\t", +"UPSC\tc\tFungal Culture Collection at the Botanical Museum\t\t", +"UPSU\ts\tUlyanovsk State Pedagogical University, Department of Botany\t\t", +"UPSV\ts\tUppsala University, Department of Plant Ecology\t\t", +"UPTC\ts\tUniversidad Pedogogica y Tecnologica de Colombia, Escuela de Ciencias Biologicas\t\t", +"UPVB\ts\tDepartamento de Geologia, Universidad del Pais Vasco\t\t", +"UPVLP\ts\tLaboratorio de Paleontolgia of the Universdad del Pais Vasco/Euskal Herriko Unibersitatea\t\t", +"UQAM\ts\tUniversite du Quebec a Montreal, Departement des Sciences biologiques\t\t", +"UQAR\ts\tUniversite du Quebec a Rimouski, Departement de biologie\t\t", +"UQIC\ts\tUniversity of Queensland Insect Collection\t\t", +"UQTR\ts\tUniversite du Quebec a Trois-Rivieres, Departement de chimie-biologie\t\t", +"URB\ts\tRyukyu University Department of Zoology\t\t", +"URIC\ts\tUniversity of Rhode Island\t\t", +"URIMC\ts\tUniversity of Rhode Island, Mammal Collection\t\t", +"URM\tc\tUniversidade Federal de Pernambuco\t\t", +"URM\ts\tUniversity of the Ryukyus\t\t", +"URMU\ts\tMuseo Nacional de Historia Natural, Montevideo\t\t", +"URO\ts\tUniversity of the Ryukyus\t\t", +"URP\ts\tMuseo de Historia Natural, Universidad Ricardo Palma\t\t", +"URT\ts\tUniversita degli Studi di Roma Tre, Dipartimento di Biologia\t\t", +"URV\ts\tUniversity of Richmond, Biology Department\t\t", +"US\ts\tSmithsonian Institution, Department of Botany\tUSNM:US", +"US\ts\tUniversity of Stellenbosch\t\t", +"USA\ts\tUniversity of South Alabama\t\t", +"USAC\ts\tUniversity of Western Australia\t\t", +"USAC\ts\tUniversidad de San Carlos de Guatemala\t\t", +"USAM\ts\tUniversity of South Alabama, Department of Biological Sciences\t\t", +"USANHC\ts\tUniversity of South Alabama, Vertebrate Natural History Collection\t\t", +"USAS\ts\tUniversity of Regina, Biology Department\t\t", +"USB\tc\tBacterial collection of Universita degli studi della basilicata, Dipartimento di Biologia\t\t", +"USBCF\ts\tU. S. Bureau of Commercial Fisheries\t\t", +"USBS\ts\tSchool of Biological Sciences, University of Science\t\t", +"USC\ts\tUniversity of Southern California, Biological Sciences Department\t\t", +"USCC\ts\tUniversity of Southern Colorado\t\t", +"USCG\ts\tUniversidad de San Carlos de Guatemala\t\t", +"USCH\ts\tUniversity of South Carolina, Department of Biological Sciences\t\t", +"USCP\ts\tUniversity of San Carlos\t\t", +"USCS\ts\tUniversity of South Carolina, Science and Mathematics Department\t\t", +"USCWH\ts\tUnited Services College\t\t", +"USD\ts\tUniversidad Autonoma de Santo Domingo\t\t", +"USD\ts\tUniversity of South Dakota\t\t", +"USDA\tsb\tUnited States Department of Agriculture\t\t", +"USDA:CFRA\tb\tUnited States Department of Agriculture, Corvallis Fragaria Catalog", +"USDA:GRIN\tb\tUnited States Department of Agriculture, Germplasm Resources Information Network", +"USDA:NCGR\tb\tUnited States Department of Agriculture, National Clonal Germplasm Repository", +"USDA:NSGC\tsb\tUnited States Department of Agriculture, National Small Grains Collection", +"USDA:PGRU\tsb\tUnited States Department of Agriculture, Plant Genetic Resources Unit", +"USDA:USNPC\ts\tUnited States Department of Agriculture, US National Parasite Collection", +"USDAK\ts\tW. H. Over State Museum\t\t", +"USF\ts\tUniversity of South Florida, Biology Department\t\t", +"USF:CBD\tc\tUniversity of South Florida, Biology Department, Center for Biological Defense", +"USFC\ts\tU. S. Fish Commission\t\t", +"USFS\ts\tRocky Mountain Forest and Range Experiment Station\t\t", +"USGS\ts\tU.S. Geological Survey\t\t", +"USGS:ASC\ts\tU.S. Geological Survey, Alaska Science Center", +"USH\ts\tUshaw College\t\t", +"USI\ts\tUniversity of Southern Indiana\t\t", +"USJ\ts\tUniversidad de Costa Rica\t\t", +"USLH\ts\tUniversity of Louisiana Lafayette, Department of Renewable Resources\t\t", +"USM\ts\tUniversiti Sains Malaysia\t\t", +"USM:VCRU\ts\tUniversiti Sains Malaysia, Vector Control Research Unit", +"USM\ts\tUniversidad Nacional Mayor de San Marcos, Museo de Historia Natural, Herbario\t\t", +"USMMC\ts\tUniversiti Sains Malaysia Mollusc Collection\t\t", +"USMP\th\tUniversiti Sains Malaysia\t\t", +"USMS\ts\tUniversity of Southern Mississippi, Department of Biological Sciences\t\t", +"USNC\ts\tSmithsonian Institution, Paleobiology Department\t\t", +"USNM\tsb\tNational Museum of Natural History, Smithsonian Institution\tNMNH", +"USNM:Birds\ts\tNational Museum of Natural History, Smithsonian Institution, Division of Birds", +"USNM:ENT\ts\tNational Museum of Natural History, Smithsonian Institution, Entomology Collection", +"USNM:FISH\ts\tNational Museum of Natural History, Smithsonian Institution, National Fish Collection", +"USNM:Herp\ts\tNational Museum of Natural History, Smithsonian Institution, Division of Amphibians and Reptiles", +"USNM:IZ\ts\tNational Museum of Natural History, Smithsonian Institution, Department of Invertebrate Zoology", +"USNM:LAB\tb\tNational Museum of Natural History, Smithsonian Institution, Laboratories of Analytical Biology", +"USNM:MAMM\ts\tNational Museum of Natural History, Smithsonian Institution, Division of Mammals", +"USNTC\ts\tU.S. National Tick Collection\t\t", +"USON\ts\tUniversidad de Sonora, Departamento de Investigaciones Cientificas y Technologicas\t\t", +"USP\ts\tUniversidade de Sao Paulo\t\t", +"USP\ts\tUniversidad San Pablo-CEU (Departamento de Biologia Vegetal (seccion Botanica)\t\t", +"USP\ts\tUniversity of the South Pacific\t\t", +"USPIY\ts\tK. D. Ushinsky Yaroslavl State Pedagogical University, Department of Botany\t\t", +"USRC\ts\tUniversity of Regina\t\t", +"USRCB\tc\tUkrainian Scientific-Research Cell Bank.\t\t", +"USSC\ts\tU.S. Soil Conservation Service\t\t", +"USTF\ts\tTechnologische Faculteit\t\t", +"USTK\ts\tUniversity of Science and Technology, Museum of Natural History\t\t", +"USU\ts\tUnited States Department of Agriculture\t\t", +"USUUB\th\tUtah State University Uintah Basin\t\t", +"USZ\ts\tUniversidad Autonoma Gabriel Rene Moreno\t\t", +"UT\ts\tUniversity of Tennessee\t\t", +"UT\ts\tUniversity of Utah Herbarium\t\t", +"UTA\ts\tUniversity of Texas at Arlington\t\t", +"UTA:A\ts\tUniversity of Texas at Arlington, Amphibian Collection", +"UTA:R\ts\tUniversity of Texas at Arlington, Reptile collection", +"UTAI\ts\tTel Aviv University\t\t", +"UTC\ts\tUtah State University, Biology Department\t\t", +"UTCI\ts\tUniversity of Tennessee at Chattanooga Insect Collection\t\t", +"UTD\ts\tUniversity of Texas, Plant Resources Center\t\t", +"UTE\ts\tUniversity of Tartu\t\t", +"UTEP\ts\tUniversity of Texas at El Paso Biodiversity Collections\t\t", +"UTEP:Bird\ts\tUniversity of Texas at El Paso Biodiversity Collections, Ornithology Collection", +"UTEP:Ento\ts\tUniversity of Texas at El Paso Biodiversity Collections, Entomology Collection", +"UTEP:ES\ts\tUniversity of Texas at El Paso Biodiversity Collections, Earth Science fossils Collections", +"UTEP:Fish\ts\tUniversity of Texas at El Paso Biodiversity Collections, Ichthyology collection", +"UTEP:Herb\ts\tUniversity of Texas at El Paso Biodiversity Collections, Herbarium", +"UTEP:Herp\ts\tUniversity of Texas at El Paso Biodiversity Collections, Herpetology Collection", +"UTEP:INV\ts\tUniversity of Texas at El Paso Biodiversity Collections, Invertebrates - Molluscs Collections", +"UTEP:Zoo\ts\tUniversity of Texas at El Paso Biodiversity Collections, Zooplankton collections", +"UTEX\tc\tThe Culture Collection of Algae at the University of Texas Austin\t\t", +"UTG\ts\tUniversity of Tuebingen\t\t", +"UTGD\ts\tGeology Department, The University of Tasmania\t\t", +"UTHSC\tc\tUniversity of Texas Health Science Center\t\t", +"UTIM\ts\tUniversity of Tennessee Insect Museum\t\t", +"UTKI\ts\tUniversity of Teheran\t\t", +"UTLH\ts\tUniversity of Technology, Human Sciences Department\t\t", +"UTLPA\ts\tUniversity of Texas at Austin, Laboratory of Physical Anthropology\t\t", +"UTMC\ts\tUniversidad del Magdalena\t\t", +"UTMC\tc\tUniversity of Tehran Microorganisms Collection\t\t", +"UTMZ\ts\tUniversity of Tennessee, Museum of Zoology\t\t", +"UTV\ts\tUniversita degli Studi della Tuscia, Dipartimento di Agrobiologia e Agrochimica\t\t", +"UTZM\ts\tUniversity of Tsukubo\t\t", +"UU\ts\tUniversity of Uppsala\t\t", +"UU\ts\tUzhgorod State University, Botany Department\t\t", +"UU\ts\tUniversity of Utah, Department of Biology\t\t", +"UUC\tc\tJanet A. Robertson Collection of Ureaplasma urealyticum Cultures\t\t", +"UUDE\th\tBuryat State University\t\t", +"UUH\ts\tInstitute of General and Experimental Biology, Department of Floristics and Geobotany\t\t", +"UUVP\ts\tUniversity of Utah, Vertebrate Paleontology\t\t", +"UUZM\ts\tUppsala University, Zoological Museum\t\t", +"UV\ts\tUniversity of Valparaiso\t\t", +"UV\ts\tDepartamento de Biologia de la Universidad del Valle\t\t", +"UVA\ts\tGeological Institute of the University of Amsterdam\t\t", +"UVAL\ts\tUniversidad del Valle de Guatemala\t\t", +"UVC\ts\tColeccion de Anfibios y Reptiles, Universidad del Valle, Cali\t\t", +"UVCC\ts\tUniversity of Vermont\t\t", +"UVCE\ts\tColecao Entomologica, Laboratorio de Entomologia Sistematica\t\t", +"UVCO\ts\tUniversidad de Valle\t\t", +"UVG\ts\tUniversidad del Valle\t\t", +"UVGC\ts\tCollecion de Artropodos\t\t", +"UVIC\ts\tUniversity of Victoria, Biology Department\t\t", +"UVM\ts\tZadock Thompson Natural History Collection, University of Vermont\t\t", +"UVP\ts\tUtah State Vertebrate Paleontology Collection\t\t", +"UVSC\ts\tUtah Valley State College, Biology Department\t\t", +"UVST\ts\tSouthwest Texas Junior College, Biology Department\t\t", +"UVV\ts\tUniversita di Venezia, Dipartimento de Scienze Ambientali\t\t", +"UW\ts\tUniversity of Washington Fish Collection\t\t", +"UWA\ts\tUniversity of Western Australia, Botany Department\t\t", +"UWAL\th\tUniversity of West Alabama\t\t", +"UWBM\ts\tUniversity of Washington, Burke Museum\t\t", +"UWBM:Mamm\ts\tUniversity of Washington, Burke Museum, Burke Museum's mammal collection", +"UWBM:ORN\ts\tUniversity of Washington, Burke Museum, Ornithology Collection", +"UWC\ts\tUniversity of the Western Cape, Botany Department\t\t", +"UWCC\tc\tUniversity of Washington Culture Collection\t\t", +"UWCP\ts\tUniversity of Wroclaw\t\t", +"UWEC\ts\tUniversity of Wisconsin, Department of Biology\t\t", +"UWFP\ts\tUniversity of West Florida, Department of Biology\t\t", +"UWGB\ts\tUniversity of Wisconsin-Green Bay, MAC 212\t\t", +"UWI\ts\tUniversity of the West Indies (Trinidad and Tobago)\t\t", +"UWIC\ts\tUniversity of the West Indies, Trinidad and Tobago\t\t", +"UWIJ\ts\tUniversity of the West Indies, Jamaica\t\t", +"UWIZM\ts\tThe University of the West Indies Zoology Museum\t\t", +"UWJ\ts\tUniversity of Wisconsin, Biology Department\t\t", +"UWL\ts\tUniversity of Wisconsin, Biology Department\t\t", +"UWM\ts\tUniversity of Wisconsin, Biological Sciences Department\t\t", +"UWMA\ts\tUniversity of Wisconsin, Milwaukee, Department of Anthropology\t\t", +"UWMIL\ts\tUniversity of Wisconsin, Milwaukee, Department of Biological Sciences\t\t", +"UWO\tsc\tUniversity of Western Ontario\t\t", +"UWOC\ts\tUniversity of Western Ontario\t\t", +"UWP\ts\tUniversity of Wrocklaw\t\t", +"UWPG\ts\tUniversity of Winnipeg, Biology Department\t\t", +"UWSP\ts\tUniversity of Wisconsin-Stevens Point,\t\t", +"UWW\ts\tUniversity of Wisconsin - Whitewater, Biological Sciences Department\t\t", +"UWYMV\ts\tUniversity of Wyoming Museum of Vertebrates\t\t", +"UWYMV:Bird\ts\tUniversity of Wyoming Museum of Vertebrates, Bird Collection", +"UWYMV:Fish\ts\tUniversity of Wyoming Museum of Vertebrates, Fish Collection", +"UWYMV:Herp\ts\tUniversity of Wyoming Museum of Vertebrates, Herpetology Collection", +"UWYMV:Mamm\ts\tUniversity of Wyoming Museum of Vertebrates, Mammal Collection", +"UWZM\ts\tUniversity of Wisconsin, Zoological Museum\t\t", +"UYIC\ts\tInstituto de Biologia\t\t", +"UZ\ts\tHerbario de la Universidad de Zaragoza\t\t", +"UZA\ts\tUnidad de Zoologia Aplicada, Departamento de Ecologia\t\t", +"UZIU\ts\tUppsala University\t\t", +"UZL\ts\tUniversity of Zambia, Biological Sciences Department\t\t", +"UZMC\ts\tUniversidad del Zulia\t\t", +"UZMH\ts\tUniversity Museum (Zoology)\t\t", +"UZMO\ts\tZoologisk Museum\t\t", +"V\ts\tRoyal British Columbia Museum - Herbarium\t\t", +"VA\ts\tUniversity of Virginia\t\t", +"VAB\ts\tUniversitat de Valencia, Departamento de Biologia Vegetal\t\t", +"VAIC\ts\tVictorian Agricultural Insect Collection\t\t", +"VAL\tsb\tUniversitat de Valencia (Jardin Botanico de Valencia)\t\t", +"VALA\ts\tUniversidad Politecnica, Departamento de Botanica\t\t", +"VALD\ts\tUniversidad Austral de Chile, Instituto de Botanica\t\t", +"VALLE\ts\tUniversidad Nacional de Colombia, Departamento de Ciencias Basicas\t\t", +"VALPL\ts\tUniversidad de Playa Ancha, Departamento de Biologia y Quimica\t\t", +"VAN\ts\tSociete Polymathique du Morbihan\t\t", +"VANF\ts\tYuezuencue Yil University, Biology Section\t\t", +"VAS\ts\tVassar College, Biology Department\t\t", +"VBCM\ts\tUniversidad Complutense de Madrid\t\t", +"VBGI\ts\tBotanical Garden-Institute\t\t", +"VBI\ts\tInstitute of Ecology and Botany of the Hungarian Academy of Sciences, Botanical Department\t\t", +"VCRC\tc\tVolcani Center Rhizobium Collection (VCRC)\t\t", +"VCU\ts\tVirginia Commonwealth University, Biology Department\t\t", +"VDAC\ts\tVirginia Department of Agriculture and Consumer Services\t\t", +"VDAM\ts\tInstitute of Plant Science\t\t", +"VDB\ts\tVanderbilt University, Department of Biological Sciences\t\t", +"VECTOR\tsc\tState Research Center of Virology and Biotechnology\t\t", +"VEN\ts\tFundacion Instituto Botanico de Venezuela Dr. Tobias Lasser\t\t", +"VENDA\ts\tThohoyandou Botanical Gardens, Department of Agriculture, Land & Environment\t\t", +"VER\ts\tHerbario, Museo Civico di Storia Naturale, Verona\t\t", +"VETMED\ts\tUniversity of Veterinary Medicine\t\t", +"VF\ts\tUniversidad de Valencia, Departamento de Biologia Vegetal, Botanica\t\t", +"VFM\th\tForest Inventory and Planning Institute\t\t", +"VFWD\ts\tVermont Fish and Wildlife Department\t\t", +"VFWO\th\tU.S. Fish and Wildlife Service, Ventura Fish and Wildlife Office\t\t", +"VGZ\ts\tVoronezh State Biosphere Reserve, Research Department\t\t", +"VH\th\tVivekanand Arts Sardar Dalipsingh Commerce and Science College\t\t", +"VHS\tc\tVegetation Health Service ( Phytophthora cultures )\t\t", +"VI\tc\tMykotektet, National Veterinary Institute\t\t", +"VI\ts\tGotlands Fornsal\t\t", +"VIA\ts\tFONAIAP-CENIAP\t\t", +"VIAM\tc\tInstitute of Applied Microbiology, University of Agricultural Sciences\t\t", +"VIAY\ts\tVeterinarian Institute of Armenia, Botany Department\t\t", +"VIC\ts\tUniversidade Federal de Vicosa, Departamento de Biologia Vegetal\t\t", +"VICA\ts\tAgriculture Department\t\t", +"VICF\ts\tForestry Department\t\t", +"VICH\ts\tPlant Protection Department\t\t", +"VIES\th\tFederal University of Espirito Santo\t\t", +"VIL\ts\tUniversite de Paris-Sud\t\t", +"VIMS\ts\tVirginia Institute of Marine Science\t\t", +"VIST\ts\tUniversity of the Virgin Islands, Natural Resources Program\t\t", +"VIT\ts\tMuseo de Ciencias Naturales de Alava, Departamento de Botanica\t\t", +"VIZR\tc\tCollection for plant protection, All-Russian Institute of Plant Protection\t\t", +"VKM\tc\tAll-Russian Collection of Microorganisms\t\t", +"VKPM\tc\tRussian National Collection of Industrial Microorganisms\t\t", +"VLA\ts\tFar Eastern Branch, Russian Academy of Sciences, Botany Department\t\t", +"VM\ts\tOkresni vlastivedne muzeum\t\t", +"VMI\th\tVirginia Military Institute\t\t", +"VMIL\ts\tVirginia Military Institute, Biology Department\t\t", +"VMKSC\ts\tKearney State University, Vertebrate Museum\t\t", +"VMM\ts\tVanderbilt Marine Museum\t\t", +"VMNH\ts\tVirginia Museum of Natural History\t\t", +"VMSL\ts\tI.N.T.A., E.E.A. San Luis, Pastizales Naturales\t\t", +"VNC\ts\tLos Angeles Valley College, Life Sciences Department\t\t", +"VNF\th\tVietnam Forestry Herbarium\t\t", +"VNGA\ts\tVorarlberger Naturschau\t\t", +"VNIRO\ts\tInstitute of Oceanography\t\t", +"VNM\th\tInstitute of Tropical Biology\t\t", +"VNMN\ts\tVietnam National Museum of Nature\t\t", +"VOA\ts\tOstrobothnian Museum\t\t", +"VOR\ts\tVoronezh State University, Biology and Plant Ecology Department\t\t", +"VORB\th\tBotanical Garden Dr. B.M. Kozo-Polyansky, Voronezh State University\t\t", +"VORG\ts\tVoronezh State University, Faculty of Geography and Geoecology\t\t", +"VPB\tc\tVeterinary Pathology and Bacteriology Collection\t\t", +"VPCI\tc\tFungal Culture Collection\t\t", +"VPI\tsc\tVirginia Polytechnic Institute and State University\t\t", +"VPIC\ts\tVirginia Polytechnic Institute and State University\t\t", +"VPIMM\ts\tVirginia Polytechnic University, Mammal Museum\t\t", +"VPM\ts\tVolgograd Provincial Museum\t\t", +"VPRI\tc\tVictoria Department of Primary Industries, Plant Disease Herbarium\t\t", +"VRLI\tc\tDepartment of Virology\t\t", +"VSC\ts\tValdosta State University, Biology Department\t\t", +"VSC-L\ts\tLyndon State College, Mammal Collection\t\t", +"VSCA\ts\tVisayas State College of Agriculture\t\t", +"VSM\ts\tDet Kgl. Norske Videnskabers Selskab Museet\t\t", +"VSM\ts\tEastern Slovakian (Vychodoslovenske) Museum, Natural History Department\t\t", +"VSRI\ts\tN.I. Vavilov All-Russian Scientific Research Instiutte of Plant Industry\t\t", +"VSUH\ts\tVirginia State University, Life Sciences Department\t\t", +"VT\ts\tPringle Herbarium, University of Vermont\t\t", +"VTA\th\tJardin Botanique de la Villa Thuret\t\t", +"VTB\tc\tBanco de Celulas Humanas e Animais Laboratorio de Patologia Celular e Molecular\t\t", +"VTCC\tc\tVietnam Type Culture Collection, Center of Biotechnology\t\t", +"VTMH\ts\tVirginia Tech Massey Herbarium\t\t", +"VTT\tc\tVTT Biotechnology, Culture Collection\t\t", +"VU\ts\tVoronezh State University\t\t", +"VU\ts\tVrije Universiteit Amsterdam\t\t", +"VUT\tc\tSchool of Veterinary Medicine, Faculty of Agriculture\t\t", +"VUW\ts\tVictoria University\t\t", +"VUWE\ts\tVictoria University\t\t", +"VYH\tc\tFinnish Environment Institute (SYKE)\t\t", +"VYM\ts\tMuzeum Vyakovska\t\t", +"W\ts\tNaturhistorisches Museum Wien, Department of Botany\t\t", +"WA\ts\tHerbarium, Faculty of Biology, University of Warsaw\t\t", +"WAB\ts\tWabash College, Biological Sciences Department\t\t", +"WABG\ts\tUniversity of Warsaw Botanic Garden\t\t", +"WAC\tc\tDepartment of Agriculture Western Australia Plant Pathogen Collection\t\t", +"WACA\ts\tWalnut Canyon National Monument\t\t", +"WACA\ts\tWork Amber Collection\t\t", +"WACC\tc\tWestern Australian Culture Collection\t\t", +"WADA\ts\tWestern Australia Department of Agriculture\t\t", +"WAG\ts\tWageningen University\t\t", +"WAHO\ts\tInstitute of Horticultural Plant Breeding, Department of Biosystematics\t\t", +"WAI\th\tWaimea Valley\t\t", +"WAIK\ts\tUniversity of Waikato, Biological Sciences Department\t\t", +"WAITE\tc\tInsect Pathology Pathogen Collection\t\t", +"WAL\tc\tWadsworth Anaerobe Laboratory, Wadsworth Hospital Center\t\t", +"WAM\ts\tWestern Australian Museum\t\t", +"WAMP\ts\tWestern Australian Museum\t\t", +"WAN\ts\tForest Research Station\t\t", +"WANF\ts\tWasatch-Cache National Forest\t\t", +"WAPA\th\tWar in the Pacific National Historical Park\t\t", +"WAR\ts\tWarwickshire Museum, Natural History Department\t\t", +"WARC\tc\tNew Zealand Reference Culture Collection\t\t", +"WARK\ts\tWestern Illinois University, Biology Department\t\t", +"WARM\ts\tCentral Missouri State University, Biology Department\t\t", +"WARMS\ts\tWarwickshire Museum, Natural History Department\t\t", +"WARS\ts\tWildlife Advisory and Research Service\t\t", +"WASH\ts\tWashburn University, Biology Department\t\t", +"WAT\ts\tUniversity of Waterloo, Biology Department\t\t", +"WAU\ts\tWau Ecology Institute\t\t", +"WAUF\ts\tWarsaw Agricultural University, Department of Plant Pathology\t\t", +"WAVI\ts\tColby College, Biology Department\t\t", +"WB\ts\tUniversitaet Wuerzburg\t\t", +"WB\tc\tDepartment of Bacteriology, University of Wisconsin\t\t", +"WBCH\ts\tWisbech and Fenland Museum\t\t", +"WBG\ts\tWaimea Botanical Garden\t\t", +"WBM\ts\tUniversitaet Wuerzburg\t\t", +"WBR\ts\tLaboratoire de Paleontologie, Unversite de Montpellier\t\t", +"WBS\ts\tLandbouwuniversiteit\t\t", +"WCE\ts\tUniversity of London, Westfield College, Biology Department\t\t", +"WCH\ts\tGreenwich Borough Museum\t\t", +"WCL\ts\tWillesden Borough Council\t\t", +"WCP\ts\tWalla Walla College, Biological Sciences Department\t\t", +"WCR\ts\tWinchester City Museum\t\t", +"WCRP\ts\tWinchester Public Library\t\t", +"WCSBG\th\tWest China Subalpine Botanical Garden\t\t", +"WCSU\ts\tWestern Connecticut State University, Department of Biological and Environmental Sciences\t\t", +"WCU\ts\tWest China University of Medical Sciences\t\t", +"WCUH\ts\tWestern Carolina University, Department of Biology\t\t", +"WCUM\tc\tWorking Collection\t\t", +"WCUUM\ts\tWest China Union University\t\t", +"WCW\ts\tWhitman College, Department of Biology\t\t", +"WDds\tc\tRaul Lopez Sanchez\t\t", +"WDNE\ts\tBureau of Land Management, Winnemucca District\t\t", +"WECO\ts\tWesleyan University, Biology Department\t\t", +"WEIC\ts\tWau Ecology Institute\t\t", +"WELC\ts\tWellesley College, Biological Sciences Department\t\t", +"WELT\ts\tMuseum of New Zealand Te Papa Tongarewa\t\t", +"WELTU\ts\tVictoria University of Wellington\t\t", +"WERN\ts\tWerneth Park Study Centre and Natural History Museum\t\t", +"WET\ts\tWartburg College, Biology Department\t\t", +"WFBM\ts\tW.F. Barr Entomological Collection\t\t", +"WFBVA\ts\tFederal Forest Research Centre Vienna, Department of Vegetation Science\t\t", +"WFIS\ts\tWagner Free Institute of Science\t\t", +"WFU\ts\tWake Forest University, Biology Department\t\t", +"WFUVC\ts\tWake Forest University, Vertebrate Collection\t\t", +"WGC\ts\tState University of West Georgia, Biology Department\t\t", +"WGCH\th\tWilton Garden Club\t\t", +"WGD\ts\tWashington Game Department\t\t", +"WGMM\ts\tWoodspring Museum\t\t", +"WGRC\tb\tWheat Genetics Resource Center\t\t", +"WGRS\ts\tWestern Ghat Regional Station of the Zoological Survey of India at Calicut\t\t", +"WH\ts\tWuhan University\t\t", +"WHB\ts\tUniversitaet fuer Bodenkultur\t\t", +"WHIT\ts\tWhittier College, Biology Department\t\t", +"WHM\ts\tWest Highland Museum\t\t", +"WHN\ts\tWhitehaven Museum\t\t", +"WHOI\ts\tWoods Hole Oceanographic Institution\t\t", +"WHT\ts\tWildlife Heritage Trust\t\t", +"WHY\ts\tWhitby Museum\t\t", +"WHYNC\ts\tWhytby Naturalists' Club\t\t", +"WI\ts\tVilnius University, Botany and Genetics Department\t\t", +"WIAP\ts\tWistar Institute of Anatomy\t\t", +"WIB\ts\tMinistry of Environment and Parks, Resource Quality Section\t\t", +"WIBF\ts\tWest Indian Beetle Fauna Project Collection\t\t", +"WIBG\ts\tWindward Islands Banana Grower's Association\t\t", +"WICA\ts\tWind Cave National Park\t\t", +"WICH\th\tWichita State University\t\t", +"WIES\ts\tMuseum Wiesbaden\t\t", +"WII\ts\tWildlife Institute of India, Department of Habitat Ecology\t\t", +"WILLI\ts\tThe College of William and Mary, Department of Biology\t\t", +"WILLU\ts\tWillamette University\t\t", +"WIN\ts\tUniversity of Manitoba, Botany Department\t\t", +"WINC\ts\tWaite Insect & Nematode Collection\t\t", +"WIND\ts\tNational Botanical Research Institute\t\t", +"WINDM\ts\tDelta Marsh Field Station (University of Manitoba)\t\t", +"WINF\ts\tForestry and Rural Developmen Department\t\t", +"WINFM\ts\tForestry and Rural Developmen Department\t\t", +"WINO\ts\tSaint Mary's College, Biology Department\t\t", +"WINU\th\tWinthrop University\t\t", +"WIR\tsb\tN. I. Vavilov Institute of Plant Industry, Department of Introduction and Systematics\t\t", +"WIS\ts\tUniversity of Wisconsin, Botany Department\t\t", +"WIU\ts\tWestern Illinois University, Museum of Natural History\t\t", +"WIUC\ts\tWestern Illinois University\t\t", +"WJC\ts\tWilliam Jewell College, Biology Department\t\t", +"WKD\ts\tWakefield Museum\t\t", +"WKDS\ts\tWakefield Grammar School\t\t", +"WKSU\ts\tWestern Kentucky State University\t\t", +"WKU\ts\tWestern Kentucky University, Department of Biology\t\t", +"WL\ts\tWolong Nature Reserve\t\t", +"WLH\ts\tWilberforce Library\t\t", +"WLK\ts\tBritish Columbia Ministry of Forests\t\t", +"WLMH\ts\tWest Lake Musuem\t\t", +"WLU\ts\tWilfrid Laurier University, Biology Department\t\t", +"WM\ts\tGezira Research Station\t\t", +"WMGC\ts\tGordon College, Biology Department\t\t", +"WMM\ts\tWitte Memorial Museum\t\t", +"WMNH\ts\tWakayama Prefectural Museum of Natural History\t\t", +"WMS\ts\tWakes Museum\t\t", +"WMU\ts\tWestern Michigan University, Biological Sciences Department\t\t", +"WMW\ts\tVestry House Museum\t\t", +"WNC\ts\tUniversity of North Carolina Wilmington, Department of Biology and Marine Biology\t\t", +"WNHM\ts\tOklahoma Baptist University, Webster Natural History Museum\t\t", +"WNLM\ts\tNiederoesterreichisches Landesmuseum\t\t", +"WNMU\ts\tWestern New Mexico University Museum\t\t", +"WNMU:Bird\ts\tWestern New Mexico University Museum, bird collection", +"WNMU:Fish\ts\tWestern New Mexico University Museum, fish collection", +"WNMU:Mamm\ts\tWestern New Mexico University Museum, mammal collection", +"WNRE\ts\tWhiteshell Nuclear Research Establishment\t\t", +"WNS\ts\tWiesbaden Naturwissenschaftliche Sammlung der Stadt\t\t", +"WNU\ts\tNorthwest University, Biology Department\t\t", +"WOCB\ts\tUniversity of Windsor, Biological Sciences Department\t\t", +"WOCSB\tb\tWheeler Orchid Collection and Species Bank\t\t", +"WOH\ts\tSouthwestern Oklahoma State University, Biology Department\t\t", +"WOLL\ts\tUniversity of Wollongong, Department of Biological Sciences\t\t", +"WOS\ts\tCity Museum and Art Gallery\t\t", +"WOSNH\ts\tWorcestershire Natural History Society Museum\t\t", +"WPBS\tc\tWPBS Rhizobium Collection\t\t", +"WPC\tcb\tWorld Phytophthora Genetic Resource Collection\t\t", +"WPH\ts\tWaterton Lakes National Park\t\t", +"WPL\ts\tWhitechapel Museum\t\t", +"WPMM\ts\tState Museum of Pennsylvania\t\t", +"WRC\tb\tWildlife Research Center of Kyoto University\t\t", +"WRHM\ts\tInstitute of Terrestrial Ecology\t\t", +"WRL\tc\tThe Wellcome Bacterial Collection\t\t", +"WRN\ts\tWarrington Museum and Art Gallery\t\t", +"WRNFC\ts\tWarrington Field Naturalists' Club\t\t", +"WRO\ts\tUniversity of Bristol, Long Ashton Research Station\t\t", +"WRSL\ts\tWroclaw University, Botany Department\t\t", +"WS\ts\tWashington State University\t\t", +"WSBC\ts\tWichita State University\t\t", +"WSBC\tc\tResearch collection of Bacillus cereus group species\t\t", +"WSC\ts\tWestfield State College, Museum and Herbarium\t\t", +"WSCH\ts\tWestfield State College, Biology Department\t\t", +"WSCO\ts\tWeber State University, Botany Department\t\t", +"WSF\tc\tWisconsin Soil Fungi Collection\t\t", +"WSFA\ts\tWilmington College, Biology Department\t\t", +"WSL\tb\tSwiss Federal Institute for Forest, Snow and Landscape Research\t\t", +"WSLC\tc\tResearch collection of Listeria (Weihenstephan Microbial Strain Collection)\t\t", +"WSM\ts\tWeston-super-Mare Museum and Art Gallery\t\t", +"WSM\tc\tWestern Australian Soil Microbiology culture collection, Murdoch. University\t\t", +"WSNM\ts\tWhite Sands National Monument\t\t", +"WSP\ts\tWashington State University, Plant Pathology Department\t\t", +"WSRP\ts\tUniversity of Podlasie, Botany Department\t\t", +"WSU\ts\tWeber State University, Bird and Mammal Collection\t\t", +"WSU\ts\tWashington State University\t\t", +"WSUMNH\ts\tWayne State University, Museum of Natural History\t\t", +"WSY\ts\tRoyal Horticultural Society's Gardens\t\t", +"WTR\ts\tWinchester College, Biology Department\t\t", +"WTS\ts\tWest Texas A&M University, Department of Life, Earth and Environmental Sciences\t\t", +"WTSU\ts\tWest Texas A&M University, Natural History Collection\t\t", +"WTU\ts\tUniversity of Washington\t\t", +"WTU:Fungal Collection\ts\tUniversity of Washington, F", +"WTUH\ts\tUniversity of Washington Botanic Gardens, College of Forest Resources\t\t", +"WU\ts\tUniversitaet Wien\t\t", +"WU\ts\tWayland University\t\t", +"WUD\ts\tWayne State University, Biological Sciences Department\t\t", +"WUH\ts\tWuhu School of Traditional Chinese Medicine\t\t", +"WUK\ts\tNorthwestern Institute of Botany\t\t", +"WUM\ts\tUniversity of Witwatersrand\t\t", +"WUME\ts\tWillamette University\t\t", +"WUP\th\tDepartment of Pharmacognosy, Universitat Wien\t\t", +"WVA\ts\tWest Virginia University, Biology Department\t\t", +"WVBS\ts\tWest Virginia Biological Survey\t\t", +"WVDH\tc\tWest Virginia Hygienic Laboratory\t\t", +"WVIT\ts\tWest Virginia University, Biology Department\t\t", +"WVMS\ts\tMarshall University, West Virginia Mammal Survey\t\t", +"WVN\ts\tWhitehaven Scientific Association\t\t", +"WVUC\ts\tWest Virginia University\t\t", +"WVW\ts\tWest Virginia Wesleyan College, Biology Department\t\t", +"WWB\ts\tWestern Washington University, Biology Department\t\t", +"WWC\th\tWarren Wilson College\t\t", +"WWF\ts\tWelder Wildlife Foundation\t\t", +"WWM\ts\tWerner Wildlife Museum\t\t", +"WWSP\ts\tWeymouth Woods Sandhills Nature Preserve\t\t", +"WXDC\ts\tWanxian Institute of Drug Control\t\t", +"WXM\ts\tNorth East Wales Institute, Department of Natural Science\t\t", +"WYAC\ts\tUniversity of Wyoming, Range Ecology and Watershed Management Department\t\t", +"WYCO\ts\tWytheville Community College, Biology Department\t\t", +"WYE\ts\tUniversity of London, Wye College\t\t", +"XAG\ts\tXinjiang Academy of Animal Sciences\t\t", +"XAL\ts\tInstituto de Ecologia, A.C.\t\t", +"XALU\ts\tUniversidad Veracruzana\t\t", +"XBGH\ts\tXian Botanical Garden\t\t", +"XCH\ts\tSt. Xavier's College, Botany Department\t\t", +"XFCFC\ts\tXiamen Fisheries College\t\t", +"XIAS\ts\tXichang Agricultural School\t\t", +"XIN\ts\tSouthwestern Guizhou Institute of Forestry\t\t", +"XJA\ts\tXinjiang Agricultural University\t\t", +"XJBI\ts\tXinjiang Institute of Ecology and Geography\t\t", +"XJDC\ts\tXinjiang Institute for Drug Control\t\t", +"XJFA\ts\tXinjiang Academy of Forestry Sciences\t\t", +"XJNU\ts\tXinjiang Normal University, Biology Department\t\t", +"XJU\ts\tXinjiang University, Biology Department\t\t", +"XJUG\ts\tXinjiang University, Geography Department\t\t", +"XM\ts\tXinjiang Medical College, Pharmacy Department\t\t", +"XMU\ts\tXiamen University\t\t", +"XNC\ts\tDepartment of Biology, Xinxiang Normal College\t\t", +"XOLO\ts\tUniversidad Autonoma Chapingo, Departamento de Fitotecnia\t\t", +"XTNM\ts\tXinjiang Institute of Traditional Chinese and Minorities Medicine\t\t", +"XUM\ts\tHope Department of Entomology\t\t", +"XYTC\ts\tXinyang Teachers College, Biology Department\t\t", +"XZ\ts\tTibet Plateau Institute of Biology\t\t", +"XZDC\ts\tTibet Institute for Drug Control\t\t", +"XZTC\ts\tXuzhou Teachers College, Biology Department\t\t", +"Y\ts\tYale University, Samuel Jones Record Memorial Collection\t\t", +"YA\ts\tNational Herbarium of Cameroon\t\t", +"YAF\ts\tYunnan Academy of Forestry\t\t", +"YAI\ts\tArmenian Agricultural Academy, Botany Department\t\t", +"YAK\ts\tForest Survey and Design Institute\t\t", +"YALT\ts\tThe State Nikita Botanical Gardens, Flora and Vegetation\t\t", +"YAM\ts\tYamaguchi University, Plant Pathology Department\t\t", +"YAMA\th\tYamagata Prefectural Museum\t\t", +"YAR\ts\tYaroslavl State University, Department of Biology and Ecology\t\t", +"YBDC\ts\tYibin Institute for Drug Control\t\t", +"YBI\ts\tInstitut National pour l'Etude et la Recherche Agronomique, Departement de Botanique\t\t", +"YBLF\tc\tYamanouchi Pharmaceutical Co., Ltd.\t\t", +"YBU\ts\tYibin University, College of Life Science and Food Engineering\t\t", +"YCE\ts\tYunnan College of Education, Biology Department\t\t", +"YCH\ts\tYavapai College, Biology Department\t\t", +"YCM\ts\tYokosuka City Museum\t\t", +"YCP\ts\tYunnan Laboratory for Conservation of Rare, Endangered & Endemic Forest Plants, State Forestry Administration\t\t", +"YDC\ts\tYunnan Institute for Drug Control\t\t", +"Yeast Collection of Department of Microbiology, Stellenbosch University\tc\tYeast Collection of Department of Microbiology, Stellenbosch University\t\t", +"YELLO\ts\tYellowstone National Park\t\t", +"YEO\ts\tYeovil Museum\t\t", +"YF\ts\tYanbei Forestry Institute\t\t", +"YFS\ts\tYunnan Forestry School\t\t", +"YFTC\ts\tYale Fish Tissue Collection\t\t", +"YH\ts\tLutheran College\t\t", +"YHB\ts\tYukon Heritage Board , Paleontology Collections\t\t", +"YIM\tc\tYunnan Institute of Microbiology\t\t", +"YIM\ts\tYunnan Institute of Pharmacology\t\t", +"YIO\ts\tYamashina Institute for Ornithology\t\t", +"YK\ts\tBootham School\t\t", +"YKN\ts\tYorkshire Naturalists' Trust Limited\t\t", +"YL\ts\tNorthwest Sci-tech University of Agriculture and Forestry\t\t", +"YLD\ts\tYulin Institute of Desert Control Research\t\t", +"YM\tc\tStrains Collection of Yunnan Institute of Microbiology, Yunnan University, China\t\t", +"YM\ts\tYork Museum\t\t", +"YM\ts\tNational Park Service, Yosemite National Park\t\t", +"YMF\ts\tKey Laboratory of Industrial Microbiology & Fermentation Technology\t\t", +"YMUK\ts\tThe Yorkshire Museum\t\t", +"YNP\ts\tThe Yosemite Museum\t\t", +"YNU\ts\tYokohama National University\t\t", +"YNUB\ts\tYunnan Normal University, Biology Department\t\t", +"YNUGI\ts\tYokohama National University - Geological Institute\t\t", +"YNUH\ts\tYeungnam University, Biology Department\t\t", +"YOLA\ts\tMari State University, Department of Plant Biology\t\t", +"YPM\ts\tYale Peabody Museum of Natural History\t\t", +"YPM/PU\ts\tPrinceton University Collection in Yale Peabody Museum\t\t", +"YPM:ENT\ts\tYale Peabody Museum of Natural History, Entomology Collection", +"YPM:HER\ts\tYale Peabody Museum of Natural History, Herpetology Collection", +"YPM:ICH\ts\tYale Peabody Museum of Natural History, Ichthyology Collection", +"YPM:IZ\ts\tYale Peabody Museum of Natural History, Invertebrate Zoology Collection", +"YPM:MAM\ts\tYale Peabody Museum of Natural History, Mammology Collection", +"YPM:ORN\ts\tYale Peabody Museum of Natural History, Ornithology Collection", +"YPMC\ts\tYellowstone National Park\t\t", +"YRK\ts\tYorkshire Museum, Biology Department\t\t", +"YU\ts\tYunnan University\t\t", +"YU\ts\tDepartment of Earth and Environmental Sciences, Yarmouk University\t\t", +"YU\ts\tYale University, Botany Division\t\t", +"YUC\ts\tINIREB\t\t", +"YUKU\ts\tYunnan University, Biology Department\t\t", +"YUO\ts\tYoungstown State University, Biological Sciences Department\t\t", +"YUTO\ts\tYork University, Biology Department\t\t", +"YXDC\ts\tYuxi District Institute for Drug Control\t\t", +"YZU\ts\tYuzhou University\t\t", +"Z\ts\tUniversitaet Zuerich\t\t", +"ZA\ts\tUniversity of Zagreb, Botany Department\t\t", +"ZAD\ts\tMount Makulu Research Station\t\t", +"ZAGR\ts\tUniversity of Zagreb\t\t", +"ZAHO\ts\tUniversity of Zagreb, Botany Department\t\t", +"ZAR\ts\tInstitut de Paleontologie du Museum National Historie Naturelle\t\t", +"ZAU\ts\tZhejiang Agricultural University\t\t", +"ZAUC\ts\tZhejian Agricultural University\t\t", +"ZBMM\ts\tMaharaja's College, Zoology and Botany Museum\t\t", +"ZCA\ts\tZhelimu College of Animal Husbandry, Range Science Department\t\t", +"ZCM\ts\tShetland Museum\t\t", +"ZDC\ts\tZhejiang Institute for Drug Control\t\t", +"ZDEU\ts\tZoology Department, Ege University\t\t", +"ZDKU\ts\tKharkiv National University\t\t", +"ZDM\ts\tZigong dinosaur Museum\t\t", +"ZEA\ts\tUniversidad de Guadalajara, Centro Universitario de la Costa Sur, Departamento de Ecologia y Recursos Naturales\t\t", +"ZFMK\tsb\tZoologisches Forschungsmuseum Alexander Koenig\t\t", +"ZFMK:COL\ts\tZoologisches Forschungsmuseum Alexander Koenig, Coleoptera collection", +"ZFMK:FSJF\ts\tZoologisches Forschungsmuseum Alexander Koenig, fish collection of Jeorg Freyhof", +"ZFMK:ICH\ts\tZoologisches Forschungsmuseum Alexander Koenig, Ichthyological Collection", +"ZFSN\ts\tLaboratoire de Zoologie de la Faculte Des Sciences\t\t", +"ZGLC\ts\tNatural History Museum, Limassol\t\t", +"ZHAN\ts\tZhanjiang Teachers College, Biology Department\t\t", +"ZhM\ts\tZhejinag Museum\t\t", +"ZIA\ts\tNational Academy of Sciences of Armenia\t\t", +"ZIAN\ts\tZoological Institute, Academy of Sciences\t\t", +"ZICUP\ts\tZoological Institute Charles University\t\t", +"ZIHU\ts\tHiroshima University, Zoological Institute\t\t", +"ZIK\ts\tUkrainian Academy of Sciences, Zoological Institute\t\t", +"ZIKU\ts\tZoological Institute, Kochi University\t\t", +"ZIL\ts\tAcademy of Sciences, Zoological Institute\t\t", +"ZIM\tc\tZIM Culture Collection of Industrial Microorganisms\t\t", +"ZIN\ts\tZoological Institute of the Russian Academy of Sciences\tZIAS", +"ZIS\ts\tUniversitaet Saarbruecken\t\t", +"ZISB\ts\tInstitute of Zoology\t\t", +"ZISP\ts\tZoological Institute, Russian Academy of Sciences\tIN", +"ZIT\ts\tGrusinian Academy of Sciences\t\t", +"ZITIU\ts\tZoological Institute, Tokyo Imperial University\t\t", +"ZIUG\ts\tZoologisches Institut\t\t", +"ZIUL\ts\tZoologisches Institut der Universitaet\t\t", +"ZIUN\ts\tUniversita DI Napoli\t\t", +"ZIUS\ts\tZoologisches Institute der Universitat\t\t", +"ZIUS\ts\tZoologiska Institutionen\t\t", +"ZIUT\ts\tDepartment of Zoology, Faculty of Science, University of Tokyo\t\t", +"ZIUU\ts\tUppsala Universitet, Zoologiska Museum\t\t", +"ZIUW\ts\tUniversitaet Wien, Zoologisches Institut\t\t", +"ZIUZ\ts\tZagreb University\t\t", +"ZJFC\ts\tZhejiang Forestry College, Forestry Department\t\t", +"ZJFI\ts\tZhejiang Forestry Institute, Bamboo Department\t\t", +"ZJMA\ts\tZhejiang Academy of Medical Sciences\t\t", +"ZJU\tb\tZhejiang University College of Sciences\t\t", +"ZLMU\ts\tMeijo University\t\t", +"ZLSYU\ts\tZoological Laboratory\t\t", +"ZLVG\tc\tCulture collection of the Laboratory of Forest Protection at the Slovenian Forestry Institute\t\t", +"ZM\ts\tZhejiang Museum of Natural History\t\t", +"ZMA\ts\tUniversiteit van Amsterdam, Zoologisch Museum\t\t", +"ZMA:POR\ts\tUniversiteit van Amsterdam, Zoologisch Museum, Porifera collection", +"ZMAN\ts\tInstituut voor Taxonomische Zoologie, Zoologisch Museum\t\t", +"ZMAU\ts\tZoological Museum Andhra University\t\t", +"ZMB\ts\tZoologisches Museum der Humboldt-Universitaet zu Berlin\t\t", +"ZMBJ\ts\tBanding Zoological Museum\t\t", +"ZMBN\ts\tMuseum of Zoology at the University of Bergen, Invertebrate Collection\tBMBN", +"ZMC\ts\tDeptment of Biology, Zunyi Medical College\t\t", +"ZMFMIB\ts\tZoologial Museum Fan Memorial Institute of Biology\t\t", +"ZMG\ts\tZoologisches Museum der Universitat Gottingen\t\t", +"ZMG\ts\tZoologischen Museums Greifswald\t\t", +"ZMH\ts\tZoologisches Museum Hamburg\t\t", +"ZMHB\ts\tMuseum fuer Naturkunde der Humboldt-Universitat\t\t", +"ZMHU\ts\tZoologisches Museum der Humboldt Universitaet\t\t", +"ZMJU\ts\tZoological Museum, Jagiellonian University\t\t", +"ZMK\ts\tZoologisches Museum der Universitat Kiel\t\t", +"ZMK\ts\tZoological Museum, Copenhagen\t\t", +"ZMK\ts\tZoological Musem, Kristiania\t\t", +"ZMKR\ts\tKoenigsberg Zoologisches Museum\t\t", +"ZMKU\ts\tKiev Zoological Museum\t\t", +"ZMKU\ts\tZoological Museum, Kasetsart University\t\t", +"ZML\ts\tSt Petersburg State University\t\t", +"ZMLP\ts\tUniversity of Punjab\t\t", +"ZMLU\ts\tLunds Universitet, Zoologiska Institutionen\t\t", +"ZMMGU\ts\tZoological Museum\t\t", +"ZMMU\ts\tZoological Museum, Moscow Lomonosov State University\tZMM,ZMUM", +"ZMMU:Birds\ts\tZoological Museum, Moscow Lomonosov State University, Bird Collection", +"ZMMU:Fishes\ts\tZoological Museum, Moscow Lomonosov State University, Fishes Collection", +"ZMMU:Herps\ts\tZoological Museum, Moscow Lomonosov State University, Ampibia and Reptilia Collection", +"ZMMU:Insects\ts\tZoological Museum, Moscow Lomonosov State University, Insects Collection", +"ZMMU:Invertebrates\ts\tZoological Museum, Moscow Lomonosov State University, Invertebrates Collection", +"ZMMU:Mamm\ts\tZoological Museum, Moscow Lomonosov State University, Mammal Collection", +"ZMNH\ts\tZhejiang Museum of Natural History\t\t", +"ZMO\ts\tZoology Museum, Oxford University\t\t", +"ZMS\ts\tZentralmuseum Senckenberg (SENCKENBERG world of biodiversity)\t\t", +"ZMSZ\ts\tZemaljski Mujski\t\t", +"ZMT\ts\tZapadomoravske muzeum v Trebici\t\t", +"ZMT\ts\tGeorgian State Museum, Zoological Section\t\t", +"ZMTAU\ts\tZoological Museum Tel Aviv University\t\t", +"ZMU\ts\tZhejiang Medical University, Pharmacy Department\t\t", +"ZMUA\ts\tZooligal Museum, University of Amoy\t\t", +"ZMUA\ts\tZoological Museum, University of Athens\t\t", +"ZMUAS\ts\tZoological Museum Ukrainian Academy of Sciences\t\t", +"ZMUB\ts\tMuseum of Zoology at the University of Bergen, Vertebrate collections\t\t", +"ZMUB:BIRD\ts\tMuseum of Zoology at the University of Bergen, Vertebrate collections, Bird collection", +"ZMUB:HERP\ts\tMuseum of Zoology at the University of Bergen, Vertebrate collections, Herptile collection", +"ZMUB:ICHT\ts\tMuseum of Zoology at the University of Bergen, Vertebrate collections, Fish Collections", +"ZMUB:MAMM\ts\tMuseum of Zoology at the University of Bergen, Vertebrate collections, Mammal collection", +"ZMUC\tsb\tZoological Museum, University of Copenhagen\t\t", +"ZMUD\ts\tUniversity of Dhaka, Zoology Museum\t\t", +"ZMUH\ts\tZoologisches Institut und Zoologisches Museum, Universitat Hamburg\t\t", +"ZMUH\ts\tZoological Museum, University of Hanoi\t\t", +"ZMUI\ts\tZoological Museum, University of Istanbul\t\t", +"ZMUL\ts\tUniversitetets Lund, Zoologiska Museet\t\t", +"ZMUN\ts\tZoology, Natural History Museum, University of Oslo\t\t", +"ZMUO\ts\tUniversity of Oulu Zoological Museum\t\t", +"ZMUO\ts\tUniversitetets I Oslo, Zoologisk Museum\t\t", +"ZMUP\ts\tZoological Museum of the University of Patras\t\t", +"ZMUT\ts\tUniversity of Tokyo, Department of Zoology\t\t", +"ZMUU\ts\tUppsala Universitet, Zoologiska Museet\t\t", +"ZMUZ\ts\tZoologisches Museum der Universitat Zurich\t\t", +"ZNG\th\tBulent Ecevit University\t\t", +"ZNM\ts\tZhejiang Natural Museum\t\t", +"ZNP\ts\tZion National Park\t\t", +"ZNPC\ts\tSpringdale, Zion National Park\t\t", +"ZNU\ts\tZhejiang Normal University, Biology Department\t\t", +"ZOM\ts\tHerbarium, Department of Agriculture, Malawi\t\t", +"ZPAL\ts\tZoological Institute of Paleobiology, Polish Academy of Sciences\t\t", +"ZPB\ts\tInstitute of Conservation and Natural History of the Soutpansberg\t\t", +"ZRC\ts\tZoological Reference Collection, National University of Singapore\t\t", +"ZSBS\ts\tZoologische Sammlung des Bayerischen Staates\t\t", +"ZSI\ts\t Zoological Survey of India\t\t", +"ZSI-CRS\ts\tZoological Survey of India, Central Regional Station\t\t", +"ZSI-E\ts\tZoological Survey of India\t\t", +"ZSI-M\ts\tZoological Survey of India\t\t", +"ZSI-NRS\ts\tZoological Survey of India\t\t", +"ZSI-SRS\ts\tZoological Survey of India, Southern Regional Station\t\t", +"ZSI-WRS\ts\tZoological Survey of India\t\t", +"ZSIC\ts\tZoological Survey of India\t\t", +"ZSLC\ts\tZoological Society of London\t\t", +"ZSM\tsb\tZoologische Staatssammlung Munchen\tZSMH", +"ZSM/CMK\ts\tZoologische Museum Staatssammlung\t\t", +"ZSM/LIPI\ts\tZoologische Museum Staatssammlung\t\t", +"ZSM:Lep\ts\tZoologische Staatssammlung Munchen, Lepidoptera", +"ZSM:Mol\ts\tZoologische Staatssammlung Munchen, Mollusca", +"ZSMC\ts\tZoologische Staatssammlung\t\t", +"ZSP\ts\tZoological Survey of Pakistan\t\t", +"ZSP\ts\tZoological Society of Philadelphia\t\t", +"ZSS\ts\tSukkulenten-Sammlung Zuerich\t\t", +"ZT\ts\tEidgenoessische Technische Hochschule Zuerich\t\t", +"ZTNH\ts\tUniversity of Vermont, Zadock Thompson Natural History Collections\t\t", +"ZTS\ts\tInstitute of Nature Conservation, Polish Academy of Sciences, Tatra Field Station\t\t", +"ZUAB\ts\tZoologia--Universidad Autonoma de Barcelona\t\t", +"ZUAC\ts\tUniversity of Antananarivo\t\t", +"ZUEC\ts\tMuseu de Zoologia da Universidade Estadual de Campinas\t\t", +"ZUFES\ts\tUniversidad Federal do Espirito Santo\t\t", +"ZUFRJ\ts\tDepartamento de Zoolgia, Instituto de Biologia\t\t", +"ZUFSM\ts\tUniversidade Federal de Santa Maria, Laboratorio de Herpetologia\t\t", +"ZULU\ts\tUniversity of Zululand, Botany Department\t\t", +"ZUMT\ts\tDepartment of Zoology, University Museum\t\t", +"ZUTC\ts\tZoological Museum University of Tehran\t\t", +"ZV\ts\tTechnical University, Department of Phytology\t\t", +"ZVC\ts\tDepto. de Zoologia Vertebrados de la Facultad de Humanidades y Ciencias\t\t", +"ZVCB\ts\tVertebrate Collection, Facultad de Ciencias, Universidad de la Republica\t\t", +"ZVS\ts\tBundesamt fuer Naturschutz\t\t", +"ZY\th\tZunyi Normal College\t\t", +"ZYTC\ts\tZhangye Teachers College, Chemistry-Biology Department\t\t", +"ZZN\tc\tZavod za naravoslovje\t\t", +"ZZSZ\ts\tZoology Department, Faculty of Natural Sciences, University of Zagreb\t\t" }; diff --git a/c++/src/objects/seqfeat/institution_codes.txt b/c++/src/objects/seqfeat/institution_codes.txt index 39c6ba82..508a4229 100644 --- a/c++/src/objects/seqfeat/institution_codes.txt +++ b/c++/src/objects/seqfeat/institution_codes.txt @@ -1,153 +1,154 @@ -A s Arnold Arboretum, Harvard University -AA s Ministry of Science, Academy of Sciences -AAC c Arignar Anna College -AAH s Arnold Arboretum, Harvard University -AAPI s Plant Industry Laboratory -AAR s Reliquae Aaronsohnianae -AARI s Anatolian Agricultural Research Institute -AAS s British Antarctic Survey -AASU s Armstrong State University -AAU s University of Aarhus, Institute of Biological Sciences -AAU s Addis Ababa University, Department of Biology + DZSJRP s Departmento de Zoologia e Botanica, Universidade Estadual Paulista +A s Arnold Arboretum, Harvard University +AA s Ministry of Science, Academy of Sciences +AAC c Arignar Anna College +AAH s Arnold Arboretum, Harvard University +AAPI s Plant Industry Laboratory +AAR s Reliquae Aaronsohnianae +AARI s Anatolian Agricultural Research Institute +AAS s British Antarctic Survey +AASU s Armstrong State University +AAU s University of Aarhus, Institute of Biological Sciences +AAU s Addis Ababa University, Department of Biology AAU:A s Addis Ababa University, Department of Biology, Amphibian collection -AAUB s Anhui Agricultural University, Department of Basic Courses -AAUF s Anhui Agricultural University, Forest Utilization Faculty -ABB c Asian Bacterial Bank -ABD s University of Aberdeen, Plant and Soil Science Department -ABDAM s Aberdeen Art Gallery and Museum -ABDC s Aba Institute for Drug Control -ABDF s University of Aberdeen, Forestry Department -ABDH s United Arab Emirates University, Department of Biology -ABDM s Marischal College, University of Aberdeen -ABFM s The Barnes Foundation Arboretum -ABH s Universidad de Alicante, Centro Iberoamericano de la Biodiversidad (CIBIO) -ABI s Centre ORSTOM d'Adiopodoume -ABKMI c Department of Applied Biology, Faculty of science -ABL s Adviesbureau voor Bryologie en Lichenologie -ABN s Radley College -ABO s Aboyne Castle -ABRC b Arabidopsis Biological Resource Center -ABRIICC c ABRIICC Agricultural Biotechnology Research Institute of Iran Culture collection -ABRN s Centre for Ecology and Hydrology -ABS sc University of Wales, Botany Department -ABS s Archbold Biological Station -ABSH s Southern Illinois Universitiy, Department of Plant Biology -ABSL s University of Minnesota, American Bryological and Lichenological Society -ABSM s Duke University, Botany Department -ABT s Laboratoire de Biologie Vegetale et d'Ecologie Forestiere -ABTC s Australian Biological Tissue Collection, South Australian Museum -ABU s Ahmadu Bello University Herbarium -AC s Amherst College -ACA s Agricultural University of Athens -ACA-DC c Greek Coordinated Collections of Microorganisms -ACAD s Acadia University, K. C. Irving Environmental Science Centre & Harriet Irving Botanical Gardens -ACAD sb Australian Centre for Ancient DNA -ACAM c The Australian Collection of Antarctic Microorganisms, Cooperative Research Center for the Antarctic and Southern Ocean Environment -ACAP s Aquaculture Center of Aomori Prefecture -ACBC s Agriculture Canada Research Station -ACBR c Austrian Center of Biological Resources and Applied Mycology -ACBV s Agriculture Canada Research Station, The Aphids of British Columbia -ACC s Oak Hill Park Museum -ACCC c Agricultural Culture Collection of China -ACD s Alemaya University of Agriculture -ACE s Anhui College of Education, Biology Department -ACE s Arachnid Collection of Egypt -ACH c Mycology Culture Collection, Women's and Children's Hospital -ACHE s Institute of Terrestrial Ecology -ACK s Agriculture and Agri-Food Canada -ACM c Australian Collection of Microorganisms -ACM s Anhui College of Traditional Chinese Medicine, Chinese Materia Medica Department -ACNB s Agriculture Canada Research Station -ACNS s Agriculture Canada Nova Scotia -ACOI c Coimbra Collection of Algae -ACOR s Universidad Nacional de Cordoba -ACTC s Austin College -ACU s Abilene Christian University -ACUNHC s Abilene Christian University, Natural History Collection -AD s Plant Biodiversity Centre -ADA s Herbarium, Department of Agriculture, South Australia -ADMONT s Benediktinerstift Admont -ADO s Kirikkale University, Biology Department -ADR s Adrian College, Biology Department -ADRZ s Rudjer Boskovic Institute, CIM-Botany -ADSH s Arachnology Division -ADT s Antarctic Division -ADU s University of Adelaide, Botany Department -ADUG s Geology Department, University of Adelaide -ADUZ s Zoology Department, University of Adelaide -ADW s University of Adelaide -AEF s University of Ankara, Department of Pharmaceutical Botany -AEI s American Entomological Institute -AEIC s American Entomological Institute -AES s Herbarium, Agricultural and Forestry Experiment Station, University of Alaska -AESB s Agriculture Experiment Station -AFAQ s Amateur Fisheries Association of Queensland -AFES s Maritimes Forest Research Centre -AFGMC s Alaska Department of Fish and Game -AFS s University of Michigan -AFSDU s Suleyman Demirel University, Agricultural Faculty -AFTC s Alaska Frozen Tissue Collection -AGRITEC b AGRITEC, Ltd. -AGRL s Lethbridge Research Station -AGU s Astrakhan State University -AGUAT s Universidad de San Carlos -AGUCH s Facultad de Ciencias Agronomicas de la Universidad de Chile -AH s Universidad de Alcala, Departamento de Biologia Vegetal -AHBC s Dixie College -AHF s Allan Hancock Foundation, University of Southern California -AHFH s University of Southern California -AHLDA c Animal Health Division Culture Collection -AHMA s Agharkar Research Institute, Maharashtra Association for the Cultivation of Science, Botany Group -AHNU s Anhui Normal University Conservation Genetics Lab -AHS s Austin High School -AHU c AHU Culture Collection -AHUC s University of California, Agronomy and Range Science Department -AIB s Anhui Institute of Biology -AIBU s Abant Izzet Baysal Ueniversitesi, Biyoloji Boeluemue -AICH s Aichi Kyoiku University, Biology Department -AIM s Auckland Institute and Museum -AIMS s Australian Institute of Marine Science -AIS s Academie imperial des Sciences -AISIY s Armenian Institute for the Scientific Investigation of Cattle Breeding and Veterinary, Department of Meadows and Pastures -AIX s Museum d'Histoire Naturelle d'Aix-en-Provence -AJ c Central Research Laboratories -AJBC s Atkins Jardin Botanico de Cienfuegos -AJOU s Ajou University, Biological Sciences Department -AK s Auckland War Memorial Museum -AKPM s Akita Prefectural Museum -AKSU h Aksaray University -AKU c Faculty of Agriculture -AKU s University of Auckland, School of Biological Sciences -AL s Universite d'Alger -ALA s Herbarium, University of Alaska Museum of the North -ALA s University of Alabama Museum of Natural History -ALAJ s Herbarium, University of Alaska SE -ALAM s Adams State College, Biology Department -ALB s Civico Museo Archeologico e di Scienze Naturali Federico Eusebio -ALBA s Universidad de Castilla, La Mancha, Departamento de Ciencia y Tecnologia Agroforestal -ALBC s Albion College, Biology Department -ALBU s Rocky Mountain Forest and Range Experiment Station -ALCB s Universidade Federal da Bahia, Campus Universitario de Ondina -ALCP c Algotheque du Laboratoire de Cryptogamie -ALD s Alderney Society and Museum -ALEX s University of Alexandria, Department of Botany -ALF s Campus International de Baillarguet, Departement d'Elevage et de Medecine Veterinaire -ALGOBANK c ALGOBANK -ALGU s Universidade do Algarve -ALIRU c Australian Legume Inoculants Research Unit -ALK s Alnwick Scientific and Mechanical Institution -ALM s Museum National Historie Naturelle -ALM s Art Gallery and Museum, Central Library -ALMA s Alma College, Biology Department -ALME s Estacion Experimental de Zonas Aridas -ALN s Alnwick Botanical Society -ALNHS s Natural Heritage Section-ALDCNR -ALT s Curtis Museum -ALTA s University of Alberta, Biological Sciences Department -ALTB s University of Barnaul, Altai State University -ALU s Alabama Museum of Natural History -ALUH s Alzahra University -AM sb Australian Museum +AAUB s Anhui Agricultural University, Department of Basic Courses +AAUF s Anhui Agricultural University, Forest Utilization Faculty +ABB c Asian Bacterial Bank +ABD s University of Aberdeen, Plant and Soil Science Department +ABDAM s Aberdeen Art Gallery and Museum +ABDC s Aba Institute for Drug Control +ABDF s University of Aberdeen, Forestry Department +ABDH s United Arab Emirates University, Department of Biology +ABDM s Marischal College, University of Aberdeen +ABFM s The Barnes Foundation Arboretum +ABH s Universidad de Alicante, Centro Iberoamericano de la Biodiversidad (CIBIO) +ABI s Centre ORSTOM d'Adiopodoume +ABKMI c Department of Applied Biology, Faculty of science +ABL s Adviesbureau voor Bryologie en Lichenologie +ABN s Radley College +ABO s Aboyne Castle +ABRC b Arabidopsis Biological Resource Center +ABRIICC c ABRIICC Agricultural Biotechnology Research Institute of Iran Culture collection +ABRN s Centre for Ecology and Hydrology +ABS sc Aberystwyth University, Institute of Biological, Environmental and Rural Sciences +ABS s Archbold Biological Station +ABSH s Southern Illinois Universitiy, Department of Plant Biology +ABSL s University of Minnesota, American Bryological and Lichenological Society +ABSM s Duke University, Botany Department +ABT s Laboratoire de Biologie Vegetale et d'Ecologie Forestiere +ABTC s Australian Biological Tissue Collection, South Australian Museum SAMA:ABTC +ABU s Ahmadu Bello University Herbarium +AC s Amherst College +ACA s Agricultural University of Athens +ACA-DC c Greek Coordinated Collections of Microorganisms +ACAD s Acadia University, K. C. Irving Environmental Science Centre & Harriet Irving Botanical Gardens +ACAD sb Australian Centre for Ancient DNA +ACAM c The Australian Collection of Antarctic Microorganisms, Cooperative Research Center for the Antarctic and Southern Ocean Environment +ACAP s Aquaculture Center of Aomori Prefecture +ACBC s Agriculture Canada Research Station +ACBR c Austrian Center of Biological Resources and Applied Mycology +ACBV s Agriculture Canada Research Station, The Aphids of British Columbia +ACC s Oak Hill Park Museum +ACCC c Agricultural Culture Collection of China +ACD s Alemaya University of Agriculture +ACE s Anhui College of Education, Biology Department +ACE s Arachnid Collection of Egypt +ACH c National Mycology Reference Centre, SA Pathology +ACHE s Institute of Terrestrial Ecology +ACK s Agriculture and Agri-Food Canada +ACM c Australian Collection of Microorganisms +ACM s Anhui College of Traditional Chinese Medicine, Chinese Materia Medica Department +ACNB s Agriculture Canada Research Station +ACNS s Agriculture Canada Nova Scotia +ACOI c Coimbra Collection of Algae +ACOR s Universidad Nacional de Cordoba +ACTC s Austin College +ACU s Abilene Christian University +ACUNHC s Abilene Christian University, Natural History Collection +AD s Plant Biodiversity Centre +ADA s Herbarium, Department of Agriculture, South Australia +ADMONT s Benediktinerstift Admont +ADO s Kirikkale University, Biology Department +ADR s Adrian College, Biology Department +ADRZ s Rudjer Boskovic Institute, CIM-Botany +ADSH s Arachnology Division +ADT s Antarctic Division +ADU s University of Adelaide, Botany Department +ADUG s Geology Department, University of Adelaide +ADUZ s Zoology Department, University of Adelaide +ADW s University of Adelaide +AEF s University of Ankara, Department of Pharmaceutical Botany +AEI s American Entomological Institute +AEIC s American Entomological Institute +AES s Herbarium, Agricultural and Forestry Experiment Station, University of Alaska +AESB s Agriculture Experiment Station +AFAQ s Amateur Fisheries Association of Queensland +AFES s Maritimes Forest Research Centre +AFGMC s Alaska Department of Fish and Game +AFS s University of Michigan +AFSDU s Suleyman Demirel University, Agricultural Faculty +AFTC s Alaska Frozen Tissue Collection +AGRITEC b AGRITEC, Ltd. +AGRL s Lethbridge Research Station +AGU s Astrakhan State University +AGUAT s Universidad de San Carlos +AGUCH s Facultad de Ciencias Agronomicas de la Universidad de Chile +AH s Universidad de Alcala, Departamento de Biologia Vegetal +AHBC s Dixie College +AHF s Allan Hancock Foundation, University of Southern California +AHFH s University of Southern California +AHLDA c Animal Health Division Culture Collection +AHMA s Agharkar Research Institute, Maharashtra Association for the Cultivation of Science, Botany Group +AHNU s Anhui Normal University Conservation Genetics Lab +AHS s Austin High School +AHU c AHU Culture Collection +AHUC s University of California, Agronomy and Range Science Department +AIB s Anhui Institute of Biology +AIBU s Abant Izzet Baysal Ueniversitesi, Biyoloji Boeluemue +AICH s Aichi Kyoiku University, Biology Department +AIM s Auckland Institute and Museum AMNZ +AIMS s Australian Institute of Marine Science +AIS s Academie imperial des Sciences +AISIY s Armenian Institute for the Scientific Investigation of Cattle Breeding and Veterinary, Department of Meadows and Pastures +AIX s Museum d'Histoire Naturelle d'Aix-en-Provence +AJ c Central Research Laboratories +AJBC s Atkins Jardin Botanico de Cienfuegos +AJOU s Ajou University, Biological Sciences Department +AK s Auckland War Memorial Museum +AKPM s Akita Prefectural Museum +AKSU h Aksaray University +AKU c Faculty of Agriculture +AKU s University of Auckland, School of Biological Sciences +AL s Universite d'Alger +ALA s Herbarium, University of Alaska Museum of the North +ALA s University of Alabama Museum of Natural History +ALAJ s Herbarium, University of Alaska SE +ALAM s Adams State College, Biology Department +ALB s Civico Museo Archeologico e di Scienze Naturali Federico Eusebio +ALBA s Universidad de Castilla, La Mancha, Departamento de Ciencia y Tecnologia Agroforestal +ALBC s Albion College, Biology Department +ALBU s Rocky Mountain Forest and Range Experiment Station +ALCB s Universidade Federal da Bahia, Campus Universitario de Ondina +ALCP c Algotheque du Laboratoire de Cryptogamie +ALD s Alderney Society and Museum +ALEX s University of Alexandria, Department of Botany +ALF s Campus International de Baillarguet, Departement d'Elevage et de Medecine Veterinaire +ALGOBANK c ALGOBANK AC +ALGU s Universidade do Algarve +ALIRU c Australian Legume Inoculants Research Unit +ALK s Alnwick Scientific and Mechanical Institution +ALM s Museum National Historie Naturelle +ALM s Art Gallery and Museum, Central Library +ALMA s Alma College, Biology Department +ALME s Estacion Experimental de Zonas Aridas +ALN s Alnwick Botanical Society +ALNHS s Natural Heritage Section-ALDCNR +ALT s Curtis Museum +ALTA s University of Alberta, Biological Sciences Department +ALTB s University of Barnaul, Altai State University +ALU s Alabama Museum of Natural History +ALUH s Alzahra University +AM sb Australian Museum AMS AM:Arachnology s Australian Museum, Invertebrate Collections: Arachnology AM:EBU sb Australian Museum, Evolutionary Biology Unit Tissue Collection AM:Entomology s Australian Museum, Invertebrate Collections: Entomology @@ -159,624 +160,628 @@ AM:Marine_Invertebrates s Australian Museum, Invertebrate Collections: Marine an AM:Mineralogy s Australian Museum, Earth Sciences: Mineralogy and Petrology Collection AM:Ornithology s Australian Museum, Vertebrate Collections: Ornithology AM:Palaeontology s Australian Museum, Palaeontology Collection -AM s Acatushun Museum at the Estancia Haberton -AM s Asenovgrad Paleontology Museum -AMAL s Anniston Museum of Natural History -AMAZ s Universidad Nacional de la Amazonia Peruana -AMB s Associazione Micologica Bresadola -AMC c Department of Biologics Research -AMCC s Ambrose Monell Cryo Collection, American Museum of Natural History -AMCL s Macapa, Museu Territorial de Historia Natural "Angelo Moreira da Costa Lima" -AMD s Hugo de Vries-Laboratory, University of Amsterdam -AMDE s Brathay Field Centre for Exploration and Field Studies -AMES s Harvard University -AMG s Albany Museum -AMGS s Albany Museum -AMH s Agharkar Research Institute, Mycology and Plant Pathology Department -AMMRL c Australian National Reference Laboratory in Medical Mycology -AMMS s Academy of Military Medical Sciences -AMNH sb American Museum of Natural History +AM s Acatushun Museum at the Estancia Haberton +AM s Asenovgrad Paleontology Museum +AMAL s Anniston Museum of Natural History +AMAZ s Universidad Nacional de la Amazonia Peruana +AMB s Associazione Micologica Bresadola +AMC c Department of Biologics Research +AMCC s Ambrose Monell Cryo Collection, American Museum of Natural History +AMCL s Macapa, Museu Territorial de Historia Natural "Angelo Moreira da Costa Lima" +AMD s Hugo de Vries-Laboratory, University of Amsterdam +AMDE s Brathay Field Centre for Exploration and Field Studies +AMES s Harvard University +AMG s Albany Museum +AMGS s Albany Museum +AMH s Agharkar Research Institute, Mycology and Plant Pathology Department +AMMRL c Australian National Reference Laboratory in Medical Mycology +AMMS s Academy of Military Medical Sciences +AMNH sb American Museum of Natural History AMNH:Fish s American Museum of Natural History, Ichthyology Collection +AMNH:FM s American Museum of Natural History, Fossil Mammal Collection AMNH:Herp s American Museum of Natural History, Herpetology collection AMNH:ORN s American Museum of Natural History, Ornithology Collection -AMNH s Icelandic Institute of Natural History, Akureyri Division -AMNZ s Auckland Institute and Museum -AMO s Herbario AMO -AMP c Australian Mycological Panel -AMP s Ampleforth College -AMS s Australian Museum -AMSA s Albany Museum -AMUZ s Aligarh Muslim University -ANA s Orange County Department of Agriculture -ANACC c Australian National Algae Culture Collection -ANC s Universita di Ancona, Dipartimento di Biotecnologie Agrarie ed Ambientali -ANCB s Museo Nacional de Historia Natural, La Paz -AND s Slezske zemske muzeum Opava, Arboretum Nopvy Dvur, Dendrology Department -ANDA s Andalas University -ANDES s La Universidad de Los Andes +AMNH:R s American Museum of Natural History, Reptile Collection +AMNH s Icelandic Institute of Natural History, Akureyri Division +AMNZ s Auckland Institute and Museum AIM +AMO s Herbario AMO +AMP c Australian Mycological Panel +AMP s Ampleforth College +AMS s Australian Museum AM +AMSA s Albany Museum +AMUZ s Aligarh Muslim University +ANA s Orange County Department of Agriculture +ANACC c Australian National Algae Culture Collection +ANC s Universita di Ancona, Dipartimento di Biotecnologie Agrarie ed Ambientali +ANCB s Museo Nacional de Historia Natural, La Paz +AND s Slezske zemske muzeum Opava, Arboretum Nopvy Dvur, Dendrology Department +ANDA s Andalas University +ANDES s La Universidad de Los Andes ANDES:A s La Universidad de Los Andes, Amphibian Collection ANDES:O s La Universidad de Los Andes, Ornithology Collection -ANES s Anadolu University, Biology Department -ANFC s Australian National Fish Collection -ANFM s Associazione Naturalisti Forlivesi Pro Museo -ANG s Arboretum de la Maulevrie -ANGU s Instituto Nacional de Tecnologia Agropecuaria -ANGUC s Universite Catholiques de l'Ouest -ANH s Andong National University, School of Bioresource Science -ANHC s Arkansas Natural Heritage Commission -ANIC s Australian National Insect Collection -ANK s Ankara Ueniversitesi, Biyoloji Boeluemue -ANKO s Forest Research Institute, Turkey -ANLW s Amt Der Niederosterreichischen Landsregierung -ANMR c Asian Network on Microbial Researches -ANSM s Universidad Autonoma Agraria Antonio Narro, Departamento de Botanica -ANSP s Academy of Natural Sciences of Philadelphia +ANES s Anadolu University, Biology Department +ANFC s Australian National Fish Collection +ANFM s Associazione Naturalisti Forlivesi Pro Museo +ANG s Arboretum de la Maulevrie +ANGU s Instituto Nacional de Tecnologia Agropecuaria +ANGUC s Universite Catholiques de l'Ouest +ANH s Andong National University, School of Bioresource Science +ANHC s Arkansas Natural Heritage Commission Herbarium +ANIC s Australian National Insect Collection +ANK s Ankara Ueniversitesi, Biyoloji Boeluemue +ANKO s Forest Research Institute, Turkey +ANLW s Amt Der Niederosterreichischen Landsregierung +ANMR c Asian Network on Microbial Researches +ANSM s Universidad Autonoma Agraria Antonio Narro, Departamento de Botanica +ANSP s Academy of Natural Sciences of Philadelphia ANSP:Malacology s Academy of Natural Sciences of Philadelphia, Malacology Collection -ANTU s Changbai Mountain National Nature Reserve Administration Bureau -ANU s Australian National University -ANU s Anhui University, Biology Department -ANUB s Anhui Normal University, Biology Department -ANUC s Australian National University, Chemistry Department -ANUG s Anhui Normal University, Geography Department -ANWC s Australian National Wildlife Collection -AO s Museo Regionale di Scienze Naturali della Valle d'Aosta -APCC c Antarctic Protistan Culture Collection (Woods Hole Oceanographic Institution) -APCR s Arkansas Tech University, Biological Sciences Department -APEI s Agriculture Canada Research Station -APH s Society of Apothecaries -APHA sc Animal and Plant Health Agency -APHI s U.S. Department of Agriculture, Animal and Plant Health Inspection Service -APIY s Abovian Pedagogical Institute, Botany Department -APM s Algonquin Provincial Park, Algonquin Visitor Centre -APMJ s Aomori Prefectural Museum -APP s Parco Nazionale del Gran Sasso e Monti della Laga - Universita di Camerino, Centro Richerche Floristiche dell'Appennino -APSC s Austin Peay State University, Biology Department -AQC s Aquinas College, Biology Department -AQP s Estudios Fitogeograficos del Peru -AQUI s Universita degli Studi di L'Aquila, Dipartimento di Scienze Ambientali -AR s Pomor State University -ARAGO s Universite Pierre et Marie Curie -ARAN s Alto de Zorroaga s.n., Departamento de Botanica -ARB s Salahiddin University, Biology Department -ARBH s Arbroath Scientific and Natural History Society -ARC s Universidad Nacional del Comahue, Facultad de Ciencias Agrarias -ARC s Atlantic Reference Centre -ARCH s Archbold Biological Station -ARCM s Atlantic Reference Centre -ARER s Associazione Romana di Entomologia -ARG s Argotti Botanic Garden -ARIZ s University of Arizona, Department of Plant Sciences -ARK s University of Arkansas -ARKH s Chingan State Nature Reserve -ARM s County Museum -ARMFN s Armagh Field Naturalists' Society -ARRI s Ayurveda Regional Research Institute -ARSEF c ARS Collection of Entomopathogenic Fungi -ARTH s Artvin Coruh University -ARUN s Botanical Survey of India, Arunachal Pradesh Regional Centre -AS c China General Microbiological Culture Collection Center -AS s Paleontological Collection -AS s Jardin Botanico -ASAY s Academy of Science of Armenia -ASC s Northern Arizona University, Biological Sciences Department -ASCC s Adams State College Collection -ASCU s Agricultural Scientific Collections Unit -ASDM s Arizona-Sonora Museum -ASE s Universidade Federal de Sergipe, Departamento de Biologia -ASH s National Institute of Deserts Flora and Fauna -ASIB c Algensammlung am Institut fur Botanik -ASINC b Agricultural Science Institute of North-Central Vietnam -ASIO s Academia Sinica Institute of Oceanology -ASIZB s Academia Sinica Institute of Zoology, Beijing -ASIZP s Academia Sinica Institute of Zoology, Ichthyology Collection -ASIZT s Academia Sinica Institute of Zoology, Taipei -ASM s Arts and Science University -ASNHC s Angelo State Natural History Collection -ASSAM s Botanical Survey of India, Eastern Circle -ASSL s Academy of Sciences -AST s University of Aston -ASTC s Stephen F. Austin State University, Biology Department -ASTN s Ashton-under-Lyne Linnean Botanical Society -ASTU s Assiut University -ASU s School of Life Sciences, Arizona State University -ASUA s Ain Shams University -ASUF s Rocky Mountain Research Station, USDA Forest Service -ASUMC s Arizona State University, Mammal Collection -ASUMZ s Arkansas State University, Collection of Recent Mammals -ASUT s Frank M. Hasbrouck Insect Collection -ASW s South Valley University, Botany Department -ASW c Culture Collection of Algae at the University of Vienna -ATA s Atatuerk Ueniversitesi -ATCC c American Type Culture Collection -ATH s Goulandris Natural History Museum -ATHU s National and Kapodistrian University of Athens, Biology Department -ATHUM c ATHUM Culture Collection of Fungi -ATSC b Australian Tree Seed Centre -ATU c Dept.of Biotechnology University of Tokyo -AU s Xiamen University, Biology Department -AUA s Auburn University, Biological Sciences Department -AUB s Andrews University -AUBH s Athabasca University -AUBL s Museum of Natural History, Beirut -AUBSN s All-Union Botanical Society -AUCE s El Azhar University -AUEM s Auburn University Entomological Museum -AUG s Augustana College, Biology Department -AUGD s Department of Geology and Petroleum Geology -AUH s Agriculture University Herbarium -AUM s Auburn University Museum -AUMC c Assiut University Mycological Centre Culture Collection -AURO s Auroville Foundation -AUSPGRIS b Australian Plant Genetic Resource Information Service -AUT s Museum d'Histoire Naturelle -AUW s Acadia University, Wildlife Museum -AV s Museum Requien -AVCH s City of Alexandria -AVE s Universidade de Aveiro, Departamento de Biologia -AVU s Vrije Universiteit, Department of Systematic Botany -AWH s Dr. Henri Van Heurck Museum -AWL s Abitibi Paper Company -AWQC c Australian Water Quality Centre -AWRI c The Australian Wine Research Institute -AYBY s Buckinghamshire County Museum Technical Centre -AYDN s Adnan Menderes University, Department of Biology -AYR s South Ayrshire Council -AZ s Museu Carlos Machado, Natural History Department -AZAN s Akademia Nauk Azerbaijana-Bulgarian Academy of Science of Azerbaijan -AZB s Herbario Ruy Telles Palhinha - Universidade Dos Acores -AZU s Universidade dos Acores, Departamento de Ciencias Agrarias -AZUS s Citrus College, Biological Sciences Department -B s Berlin Botanic Garden and Botanical Museum -BA s Museo Argentino de Ciencias Naturales Bernardino Rivadavia -BAA s Universidad de Buenos Aires, Facultad de Agronomia -BAAC s Musee de Beni Abbes -BAB s Instituto Nacional de Tecnologia Agropecuaria, Instituto de Recursos Biologicos -BABY s B. A. Bennett Herbarium, Yukon Government -BAC s Beijing Agricultural College -BAC s Bacup Natural History Society -BACC c Brucella AFSSA Culture Collection -BACH s Botswana College of Agriculture -BACP s CEFYBO, Unidad Botanica -BAE s Willis Museum and Art Gallery -BAF s Universidad de Buenos Aires, Facultad de Farmacia y Bioquimica -BAFC sc Universidad de Buenos Aires, Departamento de Ciencias Biologicas -BAG s Ministry of Agriculture -BAH s Empresa Baiana de Desenvolvimento Agricola -BAH s Biologische Anstalt Helgoland Marine Station -BAI s Instituto Forestal Nacional (IFONA), Centro Forestal Castelar -BAIL s Conservatoire Botanique National de Bailleul -BAJ s Instituto Municipal de Botanica, Parque Pte. Dr. Nicolas Avellaneda -BAK s Academy of Sciences of Azerbaijan -BAL s INTA, EEA Balcarce, Catedra de Botanica Agricola -BALT s Towson University, Department of Biological Sciences -BAMU s Dr. Babasaheb Ambedkar Marathwada University -BAN s Banaras Hindu University, Botany Department -BANG s Universite de Bangui, -BAP s Oxford Botanic Garden -BAR s University of the West Indies, Department of Biological and Chemical Sciences -BARC s Systematic Botany and Mycology Laboratory, USDA/ARS -BARO s Maharaja Sayajirao University of Baroda, Botany Department -BART s Bartlett Arboretum -BAS s Bulgarian Academy of Science -BAS s Herbarium, Botanisches Institut, Universitat Basel -BASBG s Universitaet Basel, Basler Botanische Gesellschaft -BASSA s Museo Civico, Bassano del Grappa -BASU s Bu-Ali Sina University -BAT s Bagshaw Museum -BATA s Instituto Nacional de Desarollo Forestal -BATH s Bath Natural History Society -BATHG s Geology Museum -BATU s Batumi Botanical Garden, Botany Department -BAU s Beijing Agricultural University -BAV s Slovenskej akademie vied -BAY s Museum d'Histoire Naturelle de Bayonne -BAYLU s Baylor University, Biology Department -BB s Universidad Nacional del Sur, Departamento de Agronomia -BB s Buffalo Bill Museum -BBB s Universidad Nacional del Sur, Departamento de Biologia, Bioquimica y Farmacia -BBF s Conservatoire Botanique National de Midi-Pyrenees, Conservatoire botanique pyreneen -BBG s Birmingham Botanical Gardens -BBH s National Science and Technology Development Agency -BBLF c Institut fur Pflanzenschutz im Forst -BBLM s Boise District Bureau of Land Management -BBNP s Big Bend National Park -BBPP c Bacteriology Branch, Plant Pathology and Microbiology Division, Department of Agricultural Science -BBS s University of Suriname -BBSUK s National Museum and Gallery, Department of Biodiversity and Systematic Biology -BC s Institut Botanic de Barcelona -BCB s Universitat Autonoma de Barcelona, Unitat de Botanica -BCC s Universitat de Barcelona, Departament de Biologia Vegetal (Unitat de Botanica) -BCC c BIOTEC Culture Collection -BCCDC c BC Centre for Disease Control -BCCM/DCG c The Belgian Co-ordinated Collections of Micro-organisms / DCG Diatoms Collection -BCCM/IHEM c The Belgian Co-ordinated Collections of Micro-organisms / IHEM Biomedical Fungi and Yeasts Collection -BCCM/ITM c The Belgian Co-ordinated Collections of Micro-organisms / ITM Mycobacteria Collection -BCCM/LMBP c Belgian Coordinated Collections of Microorganisms / LMBP Plasmid Collection -BCCM/MUCL c The Belgian Co-ordinated Collections of Micro-organisms / MUCL (Agro)Industrial Fungi & Yeasts Collection -BCCM/ULC c The Belgian Co-ordinated Collections of Micro-organisms / ULC Polar cyanobacteria -BCCN c Brucella Culture Collection -BCCUSP c Brazilian Cyanobacteria Collection - University of Sao Paulo -BCF s Universitat de Barcelona, Laboratori de Botanica -BCFH s Bureau of Commercial Fisheries -BCH s Berry College -BCKN s Blackburn Museum and Art Gallery -BCL s Bates College, Biology Department -BCM s Campus Universitario de Tafira, Departamento de Biologia -BCM s Brooklyn Children's Museum -BCMEX s Universidad Autonoma de Baja California, Reg. MX-HR-007-BC -BCMM s Beijing College of Traditional Chinese Medicine -BCN s Universitat de Barcelona -BCNP s Bryce Canyon National Park -BCPM s British Columbia Provincial Museum -BCRC c Bioresource Collection and Research Center -BCRJ c Rio de Janeiro Cell Bank (Banco de Celulas do Rio de Janeiro) -BCRU s Universidad Nacional del Comahue, Departamento de Botanica -BCTC s Birmingham Central Technical College -BCU s Chulalongkorn University, Botany Department -BCUE s Department of Biology, Ch'ongju University of Education -BCUZ s Basque Country University, Laboratory of Zoology -BCW s Bedford College, University of London -BCWL s Biological Control of Weeds Laboratory-Europe -BDD s University of Bradford, Biology Department -BDI s Putnam Museum of History and Natural Science, Natural History Department -BDIARI sc Bahri Dagdas International Agricultural Research Institute -BDK s North Hertfordshire Museums Service, Natural History Department -BDLU s Laurentian University -BDMU s McMaster University -BDPA s Arboretum, Bolestraszyce - Zamek, Department of Physiography -BDUC s University of Calgary -BDUW s University of Waterloo -BDUZ c Biological Sciences -BDWC s University of Windsor -BDWL s Wilfred Laurier University -BDWR s Bridgewater College, Biology Department -BEAN s Bridge of Allan Museum -BED s Bedford Public Library -BEDF s New England Wild Flower Society -BEDPL s Bedford Public Library -BEG c International Bank for the Glomeromycota -BEGO s Beth Gordon Institute -BEI s American University of Beirut, Biology Department -BEI c Microbiology and Infectious Diseases Resources (BEI Resources) -BEL s Ulster Museum, Botany Department -BELC s Beloit College, Biology Department -BELUM s Ulster Museum, Belfast -BELZ s Zapovednik Belogorje State Nature Reserve -BENH s British Entomological and Natural History Society -BENIN s Universite National du Benin -BEO s Natural History Museum, Botany Department -BEOU s University of Belgrade, Faculty of Biology -BER s Orto Botanico de Bergamo "Lorenzo Rota" -BEREA s Berea College, Biology Department -BERN s University of Bern -BESA s Museum d'Histoire naturelle de Besancon -BESM s Bvumbwe Experiment Station -BEV s Borough of Beverley Art Gallery and Museum -BEX s Bexhill Museum -BFBI s Biologisches Forschunsstation Burgenland -BFD s Bedfordshire Natural History Society -BFDL s Forest Products Laboratory -BFIC s Museum National d'Histoire Naturelle -BFRS s Blodgett Forest Research Station -BFT s Queen's University, Botany Department -BFUS s University of Sofia, Biology Faculty -BFY s John Innes Horticultural Institution -BG s University of Bergen, Botanical Museum -BGAAS s Botanical Garden of the Armenian Academy of Sciences, Flora and Vegetation Department -BGHan s Bundesanstalf fuer Geowissenschaften und Rohstoffe -BGIV c Banco de Glomeromycota In Vitro (Bank of Glomeromycota In Vitro) -BGM s Bath Geology Museum (now the Royal Literary and Scientific Institution) -BGR s Bundesanstalt fur Geowissenschaften und Rohstoffe -BGS s British Geological Survey -BGSC c Bacillus Genetic Stock Center -BGSU s Bowling Green State University, Biological Sciences Department -BH s Cornell University, Department of Plant Biology -BHAG s T. M. Bhagalpur University, Botany Department -BHAV s Central Salt and Marine Chemicals Research Institute -BHCB s Universidade Federal de Minas Gerais, Departamento de Botanica -BHD s Williamson Art Gallery and Museum -BHDL s Wirral Central Area Reference Library -BHDS s Birkenhead School -BHM s University of Birmingham, Birmingham Natural Society -BHM s Black Hills Museum of Natural History -BHMG s Instituto Agronomico -BHMH s Universidade Federal de Minas Gerais, Museu de Historia Natural -BHO s Ohio University, Environmental and Plant Biology Department -BHSC s Black Hills State University, Biology Department -BHU s Humboldt-Universitaet zu Berlin, Institut fuer Biologie -BHUPM s Museum fuer Naturkunde, Institut fuer Palaeontologie -BHUPP s Banaras Hindu University, Mycology and Plant Pathology Department -BHZB s Fundacao Zoo-Botanica de Belo Horizonte -BI s Istituto Ortobotanico -BIA s British Institute of Archaeology -BIDA s Boise State University -BIE s Instituto di Entomologia -BIEL s Universitaet Bielefeld, Abteilung Oekologie -BIGU s Universidad de San Carlos de Guatemala, Departamento de Botanica -BIL s Forest Research Institute, Natural Forest Department -BILAS s Institute of Botany -BIM s Birmingham Natural History and Microscopical Society -BIM c Belarus National Academy of Sciences -BING s State University of New York, Biological Sciences Department -BIO s Universidad del Pais Vasco/EHU, Departamento de Biologia Vegetal y Ecologia (Botanica) -BioCC c BioCC BioCen Culture Collection -BIOT s Regional Center for Tropical Biology -BIOUG s Biodiversity Institute of Ontario, University of Guelph -BIRA s Birmingham Museums and Art Gallery, Curatorial Services -BIRDI b Biotechnology Research & Development Institute Vietnam -BIRM s University of Birmingham -BISH s Bishop Museum, Department of Natural Sciences -BITU s Department of Biology, Faculty of Science, Toyama University -BIUB s Mongolian Academy of Sciences -BJ h Bi Jie University -BJA s University of Burundi, Biology Department -BJFC s Beijing Forestry University -BJM s Beijing Natural History Museum -BJRI b Gene bank at Bangladesh Jute Research Institute -BJTC s Capital Normal University, Biology Department -BK s Bangkok Herbarium -BKF s Royal Forest Department -BKL s Brooklyn Botanic Garden -BKNU s Kunsan National University -BLA s Fundacao Estadual de Pesquisa Agropecuaria -BLAT s St. Xavier's College, Botany Department -BLCU s Bee Biology and Systematics Laboratory -BLFU s University of the Free State, Department of Botany and Genetics -BLGA s Burgenlandisches Landesmuseum -BLH s Cranbrook Institute of Science -BLIH s Biological Laboratory Imperial Household of Japan -BLMAR h Bureau of Land Management Arcata Field Office -BLMLK s Bureau of Land Management -BLMPR h Bureau of Land Management, Prineville Field Office -BLT s Belfast Natural History and Philosophical Society -BLUZ s Museo de Biologia -BLWG c Bayerische Landesanstalt fur Weinbau und Gartenbau -BLY s Harvey Institute, Barnsley Naturalist and Scientific Society -BM s The Natural History Museum, Herbarium -BM s Bristol Museum -BMAM s Beijing Natural History Museum -BMARI b Bandaranayake Memorial Ayurvedic Research Institute -BMB s Booth Museum of Natural History -BMBN s Booth Museum of Natural History -BMCC c Brittany Microbe Culture collection -BMFM-UNAM c Culture Collection of Fungal Pathogens Strains from the Basic Mycology Laboratory of the Department of Microbiology and Parasitology, Faculty of Medicine, UNAM -BMGB s Barbados Museum and Historical Society -BMH s Bournemouth Natural Science Society Museum, herbarium -BMHP s Bermuda Department of Agriculture and Fisheries -BMKB s Brunei Museum -BMM s Buergermeister Mueller, Museum -BMNH s Natural History Museum, London +ANTU s Changbai Mountain National Nature Reserve Administration Bureau +ANU s Australian National University ANU,ANU +ANU s Anhui University, Biology Department +ANUB s Anhui Normal University, Biology Department +ANUC s Australian National University, Chemistry Department +ANUG s Anhui Normal University, Geography Department +ANWC s Australian National Wildlife Collection +AO s Museo Regionale di Scienze Naturali della Valle d'Aosta +APCC c Antarctic Protistan Culture Collection (Woods Hole Oceanographic Institution) +APCR s Arkansas Tech University, Biological Sciences Department +APEI s Agriculture Canada Research Station +APH s Society of Apothecaries +APHA sc Animal and Plant Health Agency VLA +APHI s U.S. Department of Agriculture, Animal and Plant Health Inspection Service +APIY s Abovian Pedagogical Institute, Botany Department +APM s Algonquin Provincial Park, Algonquin Visitor Centre +APMJ s Aomori Prefectural Museum +APP s Parco Nazionale del Gran Sasso e Monti della Laga - Universita di Camerino, Centro Richerche Floristiche dell'Appennino +APSC s Austin Peay State University, Biology Department +AQC s Aquinas College, Biology Department +AQP s Estudios Fitogeograficos del Peru +AQUI s Universita degli Studi di L'Aquila, Dipartimento di Scienze Ambientali +AR s Pomor State University +ARAGO s Universite Pierre et Marie Curie +ARAN s Alto de Zorroaga s.n., Departamento de Botanica +ARB s Salahiddin University, Biology Department +ARBH s Arbroath Scientific and Natural History Society +ARC s Universidad Nacional del Comahue, Facultad de Ciencias Agrarias +ARC s Atlantic Reference Centre +ARC c Algal Resources Collection +ARCH s Archbold Biological Station +ARCM s Atlantic Reference Centre +ARER s Associazione Romana di Entomologia +ARG s Argotti Botanic Garden +ARIZ s University of Arizona, Department of Plant Sciences +ARK s University of Arkansas +ARKH s Chingan State Nature Reserve +ARM s County Museum +ARMFN s Armagh Field Naturalists' Society +ARRI s Ayurveda Regional Research Institute +ARSEF c ARS Collection of Entomopathogenic Fungi +ARTH s Artvin Coruh University +ARUN s Botanical Survey of India, Arunachal Pradesh Regional Centre +AS c China General Microbiological Culture Collection Center +AS s Paleontological Collection +AS s Jardin Botanico +ASAY s Academy of Science of Armenia +ASC s Northern Arizona University, Biological Sciences Department +ASCC s Adams State College Collection +ASCU s Agricultural Scientific Collections Unit +ASDM s Arizona-Sonora Museum +ASE s Universidade Federal de Sergipe, Departamento de Biologia +ASH s National Institute of Deserts Flora and Fauna +ASIB c Algensammlung am Institut fur Botanik +ASINC b Agricultural Science Institute of North-Central Vietnam +ASIO s Academia Sinica Institute of Oceanology +ASIZB s Academia Sinica Institute of Zoology, Beijing +ASIZP s Academia Sinica Institute of Zoology, Ichthyology Collection ASIZP +ASIZT s Academia Sinica Institute of Zoology, Taipei +ASM s Arts and Science University +ASNHC s Angelo State Natural History Collection +ASSAM s Botanical Survey of India, Eastern Circle +ASSL s Academy of Sciences +AST s University of Aston +ASTC s Stephen F. Austin State University, Biology Department +ASTN s Ashton-under-Lyne Linnean Botanical Society +ASTU s Assiut University +ASU s School of Life Sciences, Arizona State University +ASUA s Ain Shams University +ASUF s Rocky Mountain Research Station, USDA Forest Service +ASUMC s Arizona State University, Mammal Collection +ASUMZ s Arkansas State University, Collection of Recent Mammals +ASUT s Frank M. Hasbrouck Insect Collection +ASW s South Valley University, Botany Department +ASW c Culture Collection of Algae at the University of Vienna +ATA s Atatuerk Ueniversitesi +ATCC cb American Type Culture Collection +ATH s Goulandris Natural History Museum +ATHU s National and Kapodistrian University of Athens, Biology Department +ATHUM c ATHUM Culture Collection of Fungi +ATSC b Australian Tree Seed Centre +ATU c Dept.of Biotechnology University of Tokyo +AU s Xiamen University, Biology Department +AUA s Auburn University, Biological Sciences Department +AUB s Andrews University +AUBH s Athabasca University +AUBL s Museum of Natural History, Beirut +AUBSN s All-Union Botanical Society +AUCE s El Azhar University +AUEM s Auburn University Entomological Museum +AUG s Augustana College, Biology Department +AUGD s Department of Geology and Petroleum Geology +AUH s Agriculture University Herbarium +AUM s Auburn University Museum +AUMC c Assiut University Mycological Centre Culture Collection +AURO s Auroville Foundation +AUSPGRIS b Australian Plant Genetic Resource Information Service +AUT s Museum d'Histoire Naturelle +AUW s Acadia University, Wildlife Museum +AV s Museum Requien +AVCH s City of Alexandria +AVE s Universidade de Aveiro, Departamento de Biologia +AVU s Vrije Universiteit, Department of Systematic Botany +AWH s Dr. Henri Van Heurck Museum +AWL s Abitibi Paper Company +AWQC c Australian Water Quality Centre +AWRI c The Australian Wine Research Institute +AYBY s Buckinghamshire County Museum Technical Centre +AYDN s Adnan Menderes University, Department of Biology +AYR s South Ayrshire Council +AZ s Museu Carlos Machado, Natural History Department +AZAN s Akademia Nauk Azerbaijana-Bulgarian Academy of Science of Azerbaijan +AZB s Herbario Ruy Telles Palhinha - Universidade Dos Acores +AZU s Universidade dos Acores, Departamento de Ciencias Agrarias +AZUS s Citrus College, Biological Sciences Department +B s Berlin Botanic Garden and Botanical Museum BGBM +BA s Museo Argentino de Ciencias Naturales Bernardino Rivadavia +BAA s Universidad de Buenos Aires, Facultad de Agronomia +BAAC s Musee de Beni Abbes +BAB s Instituto Nacional de Tecnologia Agropecuaria, Instituto de Recursos Biologicos +BABY s B. A. Bennett Herbarium, Yukon Government +BAC s Beijing Agricultural College +BAC s Bacup Natural History Society +BACC c Brucella AFSSA Culture Collection +BACH s Botswana College of Agriculture +BACP s CEFYBO, Unidad Botanica +BAE s Willis Museum and Art Gallery +BAF s Universidad de Buenos Aires, Facultad de Farmacia y Bioquimica +BAFC sc Universidad de Buenos Aires, Departamento de Ciencias Biologicas +BAG s Ministry of Agriculture +BAH s Empresa Baiana de Desenvolvimento Agricola +BAH s Biologische Anstalt Helgoland Marine Station +BAI s Instituto Forestal Nacional (IFONA), Centro Forestal Castelar +BAIL s Conservatoire Botanique National de Bailleul +BAJ s Instituto Municipal de Botanica, Parque Pte. Dr. Nicolas Avellaneda +BAK s Academy of Sciences of Azerbaijan +BAL s INTA, EEA Balcarce, Catedra de Botanica Agricola +BALT s Towson University, Department of Biological Sciences +BAMU s Dr. Babasaheb Ambedkar Marathwada University +BAN s Banaras Hindu University, Botany Department +BANG s Universite de Bangui +BAP s Oxford Botanic Garden +BAR s University of the West Indies, Department of Biological and Chemical Sciences +BARC s Beltsville Agricultural Research Center +BARO s Maharaja Sayajirao University of Baroda, Botany Department +BART s Bartlett Arboretum +BAS s Bulgarian Academy of Science +BAS s Herbarium, Botanisches Institut, Universitat Basel +BASBG s Universitaet Basel, Basler Botanische Gesellschaft +BASSA s Museo Civico, Bassano del Grappa +BASU s Bu-Ali Sina University +BAT s Bagshaw Museum +BATA s Instituto Nacional de Desarollo Forestal +BATH s Bath Natural History Society +BATHG s Geology Museum +BATU s Batumi Botanical Garden, Botany Department +BAU s Beijing Agricultural University +BAV s Slovenskej akademie vied +BAY s Museum d'Histoire Naturelle de Bayonne +BAYLU s Baylor University, Biology Department +BB s Universidad Nacional del Sur, Departamento de Agronomia +BB s Buffalo Bill Museum +BBB s Universidad Nacional del Sur, Departamento de Biologia, Bioquimica y Farmacia +BBF s Conservatoire Botanique National de Midi-Pyrenees, Conservatoire botanique pyreneen +BBG s Birmingham Botanical Gardens +BBH s National Science and Technology Development Agency +BBLF c Institut fur Pflanzenschutz im Forst +BBLM s Boise District Bureau of Land Management +BBNP s Big Bend National Park +BBPP c Bacteriology Branch, Plant Pathology and Microbiology Division, Department of Agricultural Science +BBS s University of Suriname +BBSUK s National Museum and Gallery, Department of Biodiversity and Systematic Biology +BC s Institut Botanic de Barcelona +BCB s Universitat Autonoma de Barcelona, Unitat de Botanica +BCC s Universitat de Barcelona, Departament de Biologia Vegetal (Unitat de Botanica) +BCC c BIOTEC Culture Collection +BCCDC c BC Centre for Disease Control +BCCM/DCG c The Belgian Co-ordinated Collections of Micro-organisms / DCG Diatoms Collection DCG +BCCM/IHEM c The Belgian Co-ordinated Collections of Micro-organisms / IHEM Biomedical Fungi and Yeasts Collection IHEM +BCCM/ITM c The Belgian Co-ordinated Collections of Micro-organisms / ITM Mycobacteria Collection ITM +BCCM/LMBP c Belgian Coordinated Collections of Microorganisms / LMBP Plasmid Collection LMBP +BCCM/MUCL c The Belgian Co-ordinated Collections of Micro-organisms / MUCL (Agro)Industrial Fungi & Yeasts Collection MUCL +BCCM/ULC c The Belgian Co-ordinated Collections of Micro-organisms / ULC of cyanobacteria UCL +BCCN c Brucella Culture Collection +BCCUSP c Brazilian Cyanobacteria Collection - University of Sao Paulo +BCF s Universitat de Barcelona, Laboratori de Botanica +BCFH s Bureau of Commercial Fisheries +BCH s Berry College +BCKN s Blackburn Museum and Art Gallery +BCL s Bates College, Biology Department +BCM s Campus Universitario de Tafira, Departamento de Biologia +BCM s Brooklyn Children's Museum +BCMEX s Universidad Autonoma de Baja California, Reg. MX-HR-007-BC +BCMM s Beijing College of Traditional Chinese Medicine +BCN s Universitat de Barcelona +BCNP s Bryce Canyon National Park +BCPM s British Columbia Provincial Museum +BCRC c Bioresource Collection and Research Center CCRC +BCRJ c Rio de Janeiro Cell Bank (Banco de Celulas do Rio de Janeiro) +BCRU s Universidad Nacional del Comahue, Departamento de Botanica +BCTC s Birmingham Central Technical College +BCU s Chulalongkorn University, Botany Department +BCUE s Department of Biology, Ch'ongju University of Education +BCUZ s Basque Country University, Laboratory of Zoology +BCW s Bedford College, University of London +BCWL s Biological Control of Weeds Laboratory-Europe +BDD s University of Bradford, Biology Department +BDI s Putnam Museum of History and Natural Science, Natural History Department +BDIARI sc Bahri Dagdas International Agricultural Research Institute +BDK s North Hertfordshire Museums Service, Natural History Department +BDLU s Laurentian University +BDMU s McMaster University +BDPA s Arboretum, Bolestraszyce - Zamek, Department of Physiography +BDUC s University of Calgary +BDUW s University of Waterloo +BDUZ c Biological Sciences +BDWC s University of Windsor +BDWL s Wilfred Laurier University +BDWR s Bridgewater College, Biology Department +BEAN s Bridge of Allan Museum +BED s Bedford Public Library +BEDF s New England Wild Flower Society +BEDPL s Bedford Public Library +BEG c International Bank for the Glomeromycota IBG +BEGO s Beth Gordon Institute +BEI s American University of Beirut, Biology Department +BEI c Biodefense and Emerging Infections Research Resources +BEL s Ulster Museum, Botany Department +BELC s Beloit College, Biology Department +BELUM s Ulster Museum, Belfast +BELZ s Zapovednik Belogorje State Nature Reserve +BENH s British Entomological and Natural History Society +BENIN s Universite National du Benin +BEO s Natural History Museum, Botany Department +BEOU s University of Belgrade, Faculty of Biology +BER s Orto Botanico de Bergamo "Lorenzo Rota" +BEREA s Berea College, Biology Department +BERN s University of Bern +BESA s Museum d'Histoire naturelle de Besancon +BESM s Bvumbwe Experiment Station +BEV s Borough of Beverley Art Gallery and Museum +BEX s Bexhill Museum +BFBI s Biologisches Forschunsstation Burgenland +BFD s Bedfordshire Natural History Society +BFDL s Forest Products Laboratory +BFIC s Museum National d'Histoire Naturelle +BFRIRS s Bangladesh Fisheries Research Institute +BFRS s Blodgett Forest Research Station +BFT s Queen's University, Botany Department +BFUS s University of Sofia, Biology Faculty +BFY s John Innes Horticultural Institution +BG s University of Bergen, Botanical Museum +BGAAS s Botanical Garden of the Armenian Academy of Sciences, Flora and Vegetation Department +BGHan s Bundesanstalf fuer Geowissenschaften und Rohstoffe +BGIV c Banco de Glomeromycota In Vitro (Bank of Glomeromycota In Vitro) +BGM s Bath Geology Museum (now the Royal Literary and Scientific Institution) +BGR s Bundesanstalt fur Geowissenschaften und Rohstoffe +BGS s British Geological Survey +BGSC c Bacillus Genetic Stock Center +BGSU s Bowling Green State University, Biological Sciences Department +BH s Cornell University, Department of Plant Biology +BHAG s T. M. Bhagalpur University, Botany Department +BHAV s Central Salt and Marine Chemicals Research Institute +BHCB s Universidade Federal de Minas Gerais, Departamento de Botanica +BHD s Williamson Art Gallery and Museum +BHDL s Wirral Central Area Reference Library +BHDS s Birkenhead School +BHM s University of Birmingham, Birmingham Natural Society +BHM s Black Hills Museum of Natural History +BHMG s Instituto Agronomico +BHMH s Universidade Federal de Minas Gerais, Museu de Historia Natural +BHO s Ohio University, Environmental and Plant Biology Department +BHSC s Black Hills State University, Biology Department +BHU s Humboldt-Universitaet zu Berlin, Institut fuer Biologie +BHUPM s Museum fuer Naturkunde, Institut fuer Palaeontologie +BHUPP s Banaras Hindu University, Mycology and Plant Pathology Department +BHZB s Fundacao Zoo-Botanica de Belo Horizonte +BI s Istituto Ortobotanico +BIA s British Institute of Archaeology +BIDA s Boise State University +BIE s Instituto di Entomologia +BIEL s Universitaet Bielefeld, Abteilung Oekologie +BIGU s Universidad de San Carlos de Guatemala, Departamento de Botanica +BIL s Forest Research Institute, Natural Forest Department +BILAS s Institute of Botany +BIM s Birmingham Natural History and Microscopical Society +BIM c Belarus National Academy of Sciences +BING s State University of New York, Biological Sciences Department +BIO s Universidad del Pais Vasco/EHU, Departamento de Biologia Vegetal y Ecologia (Botanica) +BioCC c BioCC BioCen Culture Collection +BIOT s Regional Center for Tropical Biology +BIOUG s Biodiversity Institute of Ontario, University of Guelph BIO,UOG:BIO +BIRA s Birmingham Museums and Art Gallery, Curatorial Services +BIRDI b Biotechnology Research & Development Institute Vietnam +BIRM s University of Birmingham +BISH s Bishop Museum, Department of Natural Sciences +BITU s Department of Biology, Faculty of Science, Toyama University +BIUB s Mongolian Academy of Sciences +BJ h Bi Jie University +BJA s University of Burundi, Biology Department +BJFC s Beijing Forestry University +BJM s Beijing Natural History Museum +BJRI b Gene bank at Bangladesh Jute Research Institute +BJTC s Capital Normal University, Biology Department +BK s Bangkok Herbarium +BKF s The Forest Herbarium +BKL s Brooklyn Botanic Garden +BKNU s Kunsan National University +BLA s Fundacao Estadual de Pesquisa Agropecuaria +BLAT s St. Xavier's College, Botany Department +BLCU s Bee Biology and Systematics Laboratory +BLFU s University of the Free State, Department of Botany and Genetics +BLGA s Burgenlandisches Landesmuseum +BLH s Cranbrook Institute of Science +BLIH s Biological Laboratory Imperial Household of Japan +BLMAR h Bureau of Land Management Arcata Field Office +BLMLK s Bureau of Land Management +BLMPR h Bureau of Land Management, Prineville Field Office +BLT s Belfast Natural History and Philosophical Society +BLUZ s Museo de Biologia +BLWG c Bayerische Landesanstalt fur Weinbau und Gartenbau +BLY s Harvey Institute, Barnsley Naturalist and Scientific Society +BM s The Natural History Museum, Herbarium +BM s Bristol Museum +BMAM s Beijing Natural History Museum +BMARI b Bandaranayake Memorial Ayurvedic Research Institute +BMB s Booth Museum of Natural History +BMBN s Booth Museum of Natural History +BMCC c Brittany Microbe Culture collection +BMFM-UNAM c Culture Collection of Fungal Pathogens Strains from the Basic Mycology Laboratory of the Department of Microbiology and Parasitology, Faculty of Medicine, UNAM +BMGB s Barbados Museum and Historical Society +BMH s Bournemouth Natural Science Society Museum, herbarium +BMHP s Bermuda Department of Agriculture and Fisheries +BMKB s Brunei Museum BM +BMM s Buergermeister Mueller, Museum +BMNH s Natural History Museum, London BMNH:ENT s Natural History Museum, London, Entomology collection -BMNHC s Burpee Museum of Natural History -BMPS s Bristol Museum and Philosophical Society -BMR s Bureau of Mineral Resources -BMRP s Burpee Museum Rockford Paleontology -BMSA s National Museum Bloemfontein -BMSC s Buffalo Museum of Science -BMUK s Bolton Museum -BNA c National Bank of Algae -BNA s British (Empire) Naturalists' Association -BNBE s YMCA Hostel -BNFF s Banff Museum -BNFH h U.S. Forest Service, Bitterroot National Forest -BNH s Nassau Botanical Gardens, Department of Agriculture -BNHD s Bengal Natural History Museum -BNHM s Beijing Natural History Museum -BNHM s Bombay Natural History Museum -BNHS s Bombay Natural History Society -BNI c Bernhard Nocht Institute for Tropical Medicine -BNL s Bundesamt fuer Naturschutz -BNM c Banco Nacional Microorganismos (National Bank of Microorganisms) -BNP s Banff Park Museum -BNPL s Brighton Public Library -BNRH s Buffelskloof Nature Reserve -BNS s Bristol Museum and Art Gallery -BNU s Beijing Normal University, Biology Department -BO s Herbarium Bogoriense -BOC s Bingham Oceanographic Collection -BOCH s Ruhr-Universitaet Bochum, Spezielle Botanik -BOD s University of Oxford -BOG s Universidad de La Salle -BOGOS b Botanical Garden of Osnabruck University -BOIS s Rocky Mountain Research Station -BOL s University of Cape Town, Botany Department -BOLO s Universita di Bologna -BOLV s Nacional Forestal Martin Cardenas -BON s Bolton Museum, Art Gallery and Aquarium -BONB s Bolton Botanical Society -BONL s Bolton Linnean Society -BONN s Botanisches Institut und Botanischer Garten der Universitaet Bonn -BOON s Appalachian State University, Biology Department -BOR s Guermonprez Museum -BORD s Jardin Botanique de la Ville de Bordeaux -BORH s Universiti Malaysia Sabah -BORN s Institute for Tropical Biology and Conservation, Borneensis -BOROK c The Collection of algae -BOSC s Boston State College, Biology Department -BOTU s Universidade Estadual Paulista, Departamento de Botanica -BOUM s Museum d'Histoire Naturelle de Bourges -BOZ s Naturmuseum Suedtirol/Museo Scienze Naturali Alto Adige -BP s Hungarian Natural History Museum, Botanical Department -BPBM s Bernice P. Bishop Museum +BMNHC s Burpee Museum of Natural History +BMPS s Bristol Museum and Philosophical Society +BMR s Bureau of Mineral Resources +BMRP s Burpee Museum Rockford Paleontology +BMSA s National Museum Bloemfontein +BMSC s Buffalo Museum of Science +BMUK s Bolton Museum +BNA c National Bank of Algae +BNA s British (Empire) Naturalists' Association +BNBE s YMCA Hostel +BNFF s Banff Museum +BNFH h U.S. Forest Service, Bitterroot National Forest +BNH s Nassau Botanical Gardens, Department of Agriculture +BNHD s Bengal Natural History Museum +BNHM s Beijing Natural History Museum +BNHM s Bombay Natural History Museum +BNHS s Bombay Natural History Society +BNI c Bernhard Nocht Institute for Tropical Medicine +BNL s Bundesamt fuer Naturschutz +BNM c Banco Nacional Microorganismos (National Bank of Microorganisms) +BNP s Banff Park Museum +BNPL s Brighton Public Library +BNRH s Buffelskloof Nature Reserve +BNS s Bristol Museum and Art Gallery +BNU s Beijing Normal University, Biology Department +BO s Herbarium Bogoriense +BOC s Bingham Oceanographic Collection YPM +BOCH s Ruhr-Universitaet Bochum, Spezielle Botanik +BOD s University of Oxford +BOG s Universidad de La Salle +BOGOS b Botanical Garden of Osnabruck University +BOIS s Rocky Mountain Research Station +BOL s University of Cape Town, Botany Department +BOLO s Universita di Bologna +BOLV s Nacional Forestal Martin Cardenas +BON s Bolton Museum, Art Gallery and Aquarium +BONB s Bolton Botanical Society +BONL s Bolton Linnean Society +BONN s Botanisches Institut und Botanischer Garten der Universitaet Bonn +BOON s Appalachian State University, Biology Department +BOR s Guermonprez Museum +BORD s Jardin Botanique de la Ville de Bordeaux +BORH s Universiti Malaysia Sabah +BORN s Institute for Tropical Biology and Conservation, Borneensis +BOROK c The Collection of algae +BOSC s Boston State College, Biology Department +BOTU s Universidade Estadual Paulista, Departamento de Botanica +BOUM s Museum d'Histoire Naturelle de Bourges +BOZ s Naturmuseum Suedtirol/Museo Scienze Naturali Alto Adige +BP s Hungarian Natural History Museum, Botanical Department +BPBM s Bernice P. Bishop Museum BISHOP BPBM:Fish s Bernice P. Bishop Museum, Fish Collection BPBM:IZ s Bernice P. Bishop Museum, Invertebrate Zoology -BPI sc U.S. National Fungus Collections, Systematic Botany and Mycology Laboratory -BPI s Bernard Price Institute for Palaeontological Research -BPIC c Benaki Phytopathological Institute Collection -BPL s Museum of Barnstaple & North Devon -BPM s Beipiao Paleontological Museum -BPPT-ESC c BPPT Ethanol-Single Cell Protein-Fructose Syrup Technical Unit -BPS s California Department of Food and Agriculture -BPU s Eoetvoes Lorand University, Department of Plant Taxonomy and Ecology -BR s Botanic Garden Meise -BR c Embrapa Agrobiology Diazothrophic Microbial Culture Collection -BRA s Slovak National Museum, Botany Department -BRAD s University of Bradford, Biology Department -BRC s Botanical Record Club -BRCC c USDA-ARS Rhizobium Germplasm Resource Collection -BRCH s Botanical Research Center -BRE s Universite -BREE s Braintree and Bocking Natural History Club -BREG s Vorarlberger Naturschau -BREM s Uebersee-Museum -BRFL s City of Birmingham Reference Library -BRFM c Banque de Ressources Fongiques de Marseille -BRG s University of Guyana, Biology Department -BRGE s Laboratoire de Genetique des Plantes Superieures -BRH s Ministry of Natural Resources, Local Government, and the Environment -BRI s Brisbane Botanic Gardens Mt Coot-tha -BRIP sc The Plant Pathology Herbarium, Department of Agriculture, Fisheries and Forestry -BRIST s University of Bristol, Botany Department -BRISTM s Bristol Museum and Art Gallery -BRIT s Botanical Research Institute of Texas -BRIU s University of Queensland, Botany Department -BRL s Bristol City Library -BRLU s Universite Libre de Bruxelles -BRM s Alfred-Wegener-Institut fuer Polar- und Meeresforschung -BRMI s Birmingham and Midland Institute -BRN s Sexey's School -BRNL s Mendel University of Agriculture and Forestry, Department of Forest Botany, Dendrology, and Typology -BRNM s Moravian Museum, Botany Department -BRNU s Masaryk University, Department of Botany -BROC s State University of New York, Biological Sciences Department -BRS s Agriculture and Agri-Food Canada -BRSL s Wroclaw University, Botany Department -BRSMG s Department of Geology -BRSN s University of Wales, Bangor Research Unit -BRSU h Bryansk State University -BRTN s Brighton Natural History Society -BRU s Brown University -BRUN s Brunei Forestry Centre -BRV s Colecciones paleontologicas del Departamento de Geociencias de la Universidad Nacional de Colombia -BRVU s Vrije Universiteit Brussel -BRWK s Berwick-upon-Tweed Museum -BRY s Brigham Young University -BSA s Botanical Survey of India, Central Circle -BSB s Freie Universitaet Berlin, Institut fuer Biologie - Systematische Botanik und Pflanzengeographie -BSC s Centro Oriental de Ecosistemas y Biodiversidad -BSCA s Anza-Borrego Desert State Park -BSCVC s Bemidji State University, Vertebrate Collections -BSD s Botanical Survey of India, Northern Circle -BSE s Moyse's Hall Museum -BSHC s Botanical Survey of India, Sikkim Himalayan Circle -BSI s Botanical Survey of India, Western Circle, Ministry of Environment and Forests -BSID h Botanical Survey of India -BSIP s Ministry of Natural Resources, Department of Forests, Environment, and Conservation -BSIS s Botanical Survey of India, Industrial Section -BSJO s Botanical Survey of India, Arid Zone Circle -BSKU s Kochi University -BSL s Botanical Society of London -BSM s Berliner Staatisches Museum -BSMB c Bacteriology and Soil Microbiology Branch -BSMP s Department of Agriculture, Bureau of Science -BSN s Boston University, Biology Department -BSNH s Boston Society of Natural History -BSNS s Buffalo Society of Natural Sciences -BSPG s Bayerische Staatssammlung fuer Palaeontologie und Geologie -BSRA s University of Basrah, Biology Department -BSRM s Biological Station Reference Museum at Porto Novo -BST s Belfast Naturalists' Field Club -BSTN s Boothstown Botanical Society -BSU s Belgorod State University, Department of Botany -BSUH s Ball State University, Biology Department -BSUMC s Ball State University, Mammal Collection -BTCC c Bulgarian Type Culture Collection -BTCC c Biotechnology Culture Collection Institution Pusat Penelitian dan Pengembangan Bioteknologi-LIPI -BTH s Museum, Bath Royal Literary and Scientific Institution -BTJW s Bridger Teton National Forest -BTN s Booth Museum of Natural History -BTT s Burton-upon-Trent Natural History and Archaeological Society -BTU s Technische Universitaet Berlin -BU h Brock University -BUA s University of Baghdad, Plant Protection Department -BUAG s University of Agronomical Sciences and Veterinary Medicine, Botany and Plant Physiology Department -BUC s Universitatea din Bucuresti -BUCA s Institute of Biology, Romanian Academy -BUCF s Forest Research and Management Institute -BUCM s Institute of Biology, Romanian Academy -BUCSAV c Biologicky Ustav -BUE s University of Baghdad, Biology Department -BUEN s Proteccion de la Naturaleza -BUF s Buffalo Museum of Science -BUH s University of Baghdad, Biology Department -BUHGC s Barton-on-Humber Grammar School -BUHR s Baysgarth Museum -BUL s Natural History Museum of Zimbabwe -BULQ s Bishop's University -BULU s Uludag University, Biology Department -BUNH s University of Baghdad -BUNS s University of Novi Sad, Department of Biology and Ecology -BUPL s Bucknell University, Biology Department -BURD s University of Burdwan, Botany Department -BURI h Banasthali University -BURP s Burpee Museum of Natural History -BUS s University of Miami, Biology Department -BUT s Butler University -BUTC s Boston University -BVC s Buena Vista College -BVS h Transylvania University of Brasov -BYBS s Bungay Botanical Society -BYDG s Technical-Agriculture Academy, Department of Botany and Ecology -BYU s Monte L. Bean Life Science Museum -BZ s Herbarium Bogoriense -BZCM h Bozhou Vocational and Technical College -BZF s Forest Research and Development Center and Nature Conservation -BZM s Museum fur Naturkunde, Berlin -BZT s Biological Institute Titograd -C s Botanical Museum, Natural History Museum of Denmark -CA s Chicago Academy of Sciences -CABI c CABI Genetic Resource Collection -CACA s Carlsbad Caverns National Park -CACC c China Antibiotic Culture Collection Center -CACS s Chicago Academy of Sciences, Department of Biology -CAEN s Jardin Botanique de la Ville de Caen -CAES s Connecticut Agriculture Experiment Station -CAF s Chinese Academy of Forestry -CAFB s Northern Forestry Centre, Canadian Forest Service -CAG s Universita di Cagliari -CAH s University of Zimbabwe, Biological Sciences Department -CAHS s Crispus Attucks High School -CAHUP s University of the Philippines Los Banos -CAI s Cairo University, Botany Department -CAIA s Ain Shams University, Department of Botany -CAIH s Desert Research Center, Mataria, Plant Ecology -CAIM s Agricultural Research Center -CAIM c Collection of Aquatic Important Microorganisms -CAIRC s National Research Centre, Plant Chemistry and Systematics Department -CAIRCC c CAIRCC -CAIRNS s c/o North Queensland Naturalists' Club -CAL s Botanical Survey of India -CALI s University of Calicut, Botany Department -CALP s University of the Philippines at Los Banos -CALU c Collection of Algae in Leningrad, St. Petersburg, State University -CALVIN h Calvin College -CAM s Central Australian Museum -CAM s St. John's College -CAME s Universita di Camerino, Dipartimento de Botanica ed Ecologia -CAMS c Centre for Applied Mycological Studies -CAMU s Cameron University, Department of Biological Sciences -CAN s Canadian Museum of Nature, Vascular Plant Section -CANA s Canadian Museum of Nature, Phycology Section -CANB s Australian National Herbarium, Canberra -CANI s Canisius College, Biology Department -CANL s Canadian Museum of Nature, Lichenology Section -CANM s Canadian Museum of Nature, Bryology Section -CANT s South China Agricultural University, Forestry Department -CANTY s Canterbury Museum -CANU s University of Canterbury, Department of Plant and Microbial Sciences -CAPM c Collection of Animal Pathogenic Microorganisms -CAR s Museo de Historia Natural La Salle, Departamento de Botanica -CARAN h Herbarium Carautanum -CARD s Caribbean Agricultural Research Institute -CARE s Caribbean Epidemiology Centre -CARI s Cukurova Agricultural Research Institute -CARL s Carleton College, Biology Department -CARM s Carmarthen County Museum -CARS s University of Surinam, Center for Agricultural Research -CART s Carthage College, Biology Department -CAS s California Academy of Sciences -CAS-IU s California Academy of Science, Indiana University Collection -CAS-SU s California Academy of Sciences, Stanford University Collection +BPI sc U.S. National Fungus Collections, Systematic Botany and Mycology Laboratory +BPI s Bernard Price Institute for Palaeontological Research +BPIC c Benaki Phytopathological Institute Collection +BPL s Museum of Barnstaple & North Devon +BPM s Beipiao Paleontological Museum +BPPT-ESC c BPPT Ethanol-Single Cell Protein-Fructose Syrup Technical Unit +BPS s California Department of Food and Agriculture +BPU s Eoetvoes Lorand University, Department of Plant Taxonomy and Ecology +BR s Botanic Garden Meise +BR c Johanna Dobereiner Biological Resouce Center (CRB-JD) +BRA s Slovak National Museum, Botany Department +BRAD s University of Bradford, Biology Department +BRC s Botanical Record Club +BRCC c USDA-ARS Rhizobium Germplasm Resource Collection +BRCH s Botanical Research Center +BRE s Universite +BREE s Braintree and Bocking Natural History Club +BREG s Vorarlberger Naturschau +BREM s Uebersee-Museum +BRFL s City of Birmingham Reference Library +BRFM c Banque de Ressources Fongiques de Marseille +BRG s University of Guyana, Biology Department +BRGE s Laboratoire de Genetique des Plantes Superieures +BRH s Ministry of Natural Resources, Local Government, and the Environment +BRI s Brisbane Botanic Gardens Mt Coot-tha +BRIP sc The Plant Pathology Herbarium, Department of Agriculture, Fisheries and Forestry +BRIST s University of Bristol, Botany Department +BRISTM s Bristol Museum and Art Gallery +BRIT s Botanical Research Institute of Texas +BRIU s University of Queensland, Botany Department +BRL s Bristol City Library +BRLU s Universite Libre de Bruxelles +BRM s Alfred-Wegener-Institut fuer Polar- und Meeresforschung +BRMI s Birmingham and Midland Institute +BRN s Sexey's School +BRNL s Mendel University of Agriculture and Forestry, Department of Forest Botany, Dendrology, and Typology +BRNM s Moravian Museum, Botany Department +BRNU s Masaryk University, Department of Botany +BROC s State University of New York, Biological Sciences Department +BRS s Agriculture and Agri-Food Canada +BRSL s Wroclaw University, Botany Department +BRSMG s Department of Geology +BRSN s University of Wales, Bangor Research Unit +BRSU h Bryansk State University +BRTN s Brighton Natural History Society +BRU s Brown University +BRUN s Brunei Forestry Centre +BRV s Colecciones paleontologicas del Departamento de Geociencias de la Universidad Nacional de Colombia +BRVU s Vrije Universiteit Brussel +BRWK s Berwick-upon-Tweed Museum +BRY s Brigham Young University +BSA s Botanical Survey of India, Central Circle +BSB s Freie Universitaet Berlin, Institut fuer Biologie - Systematische Botanik und Pflanzengeographie +BSC s Centro Oriental de Ecosistemas y Biodiversidad +BSCA s Anza-Borrego Desert State Park +BSCVC s Bemidji State University, Vertebrate Collections +BSD s Botanical Survey of India, Northern Circle +BSE s Moyse's Hall Museum +BSHC s Botanical Survey of India, Sikkim Himalayan Circle +BSI s Botanical Survey of India, Western Circle, Ministry of Environment and Forests +BSID h Botanical Survey of India +BSIP s Ministry of Natural Resources, Department of Forests, Environment, and Conservation +BSIS s Botanical Survey of India, Industrial Section +BSJO s Botanical Survey of India, Arid Zone Circle +BSKU s Kochi University +BSL s Botanical Society of London +BSM s Berliner Staatisches Museum +BSMB c Bacteriology and Soil Microbiology Branch +BSMP s Department of Agriculture, Bureau of Science +BSN s Boston University, Biology Department +BSNH s Boston Society of Natural History +BSNS s Buffalo Society of Natural Sciences +BSPG s Bayerische Staatssammlung fur Palaontologie und Geologie BS,BSP +BSRA s University of Basrah, Biology Department +BSRM s Biological Station Reference Museum at Porto Novo +BST s Belfast Naturalists' Field Club +BSTN s Boothstown Botanical Society +BSU s Belgorod State University, Department of Botany +BSUH s Ball State University, Biology Department +BSUMC s Ball State University, Mammal Collection +BTCC c Bulgarian Type Culture Collection +BTCC c Biotechnology Culture Collection Institution Pusat Penelitian dan Pengembangan Bioteknologi-LIPI +BTH s Museum, Bath Royal Literary and Scientific Institution +BTJW s Bridger Teton National Forest +BTN s Booth Museum of Natural History +BTT s Burton-upon-Trent Natural History and Archaeological Society +BTU s Technische Universitaet Berlin +BU h Brock University +BUA s University of Baghdad, Plant Protection Department +BUAG s University of Agronomical Sciences and Veterinary Medicine, Botany and Plant Physiology Department +BUC s Universitatea din Bucuresti +BUCA s Institute of Biology, Romanian Academy +BUCF s Forest Research and Management Institute +BUCM s Institute of Biology, Romanian Academy +BUCSAV c Biologicky Ustav +BUE s University of Baghdad, Biology Department +BUEN s Proteccion de la Naturaleza +BUF s Buffalo Museum of Science +BUH s University of Baghdad, Biology Department +BUHGC s Barton-on-Humber Grammar School +BUHR s Baysgarth Museum +BUL s Natural History Museum of Zimbabwe +BULQ s Bishop's University +BULU s Uludag University, Biology Department +BUNH s University of Baghdad +BUNS s University of Novi Sad, Department of Biology and Ecology +BUPL s Bucknell University, Biology Department +BURD s University of Burdwan, Botany Department +BURI h Banasthali University +BURP s Burpee Museum of Natural History +BUS s University of Miami, Biology Department +BUT s Butler University +BUTC s Boston University +BVC s Buena Vista College +BVS h Transylvania University of Brasov +BYBS s Bungay Botanical Society +BYDG s Technical-Agriculture Academy, Department of Botany and Ecology +BYU s Monte L. Bean Life Science Museum +BZ s Herbarium Bogoriense +BZCM h Bozhou Vocational and Technical College +BZF s Forest Research and Development Center and Nature Conservation +BZM s Museum fur Naturkunde, Berlin +BZT s Biological Institute Titograd +C s Botanical Museum, Natural History Museum of Denmark +CA s Chicago Academy of Sciences +CABI c CABI Genetic Resource Collection +CACA s Carlsbad Caverns National Park +CACC c China Antibiotic Culture Collection Center +CACS s Chicago Academy of Sciences, Department of Biology +CAEN s Jardin Botanique de la Ville de Caen +CAES s Connecticut Agriculture Experiment Station +CAF s Chinese Academy of Forestry +CAFB s Northern Forestry Centre, Canadian Forest Service +CAG s Universita di Cagliari +CAH s University of Zimbabwe, Biological Sciences Department +CAHS s Crispus Attucks High School +CAHUP s University of the Philippines Los Banos +CAI s Cairo University, Botany Department +CAIA s Ain Shams University, Department of Botany +CAIH s Desert Research Center, Mataria, Plant Ecology +CAIM s Agricultural Research Center +CAIM c Collection of Aquatic Important Microorganisms +CAIRC s National Research Centre, Plant Chemistry and Systematics Department +CAIRCC c CAIRCC +CAIRNS s c/o North Queensland Naturalists' Club +CAL s Botanical Survey of India +CALI s University of Calicut, Botany Department +CALP s University of the Philippines at Los Banos +CALU c Collection of Algae in Leningrad, St. Petersburg, State University +CALVIN h Calvin College +CAM s Central Australian Museum +CAM s St. John's College +CAME s Universita di Camerino, Dipartimento de Botanica ed Ecologia +CAMS c Centre for Applied Mycological Studies +CAMU s Cameron University, Department of Biological Sciences +CAN s Canadian Museum of Nature, Vascular Plant Section +CANA s Canadian Museum of Nature, Phycology Section +CANB s Australian National Herbarium, Canberra +CANI s Canisius College, Biology Department +CANL s Canadian Museum of Nature, Lichenology Section +CANM s Canadian Museum of Nature, Bryology Section +CANT s South China Agricultural University, Forestry Department +CANTY s Canterbury Museum +CANU s University of Canterbury, Department of Plant and Microbial Sciences +CAPM c Collection of Animal Pathogenic Microorganisms +CAR s Museo de Historia Natural La Salle, Departamento de Botanica +CARAN h Herbarium Carautanum +CARD s Caribbean Agricultural Research Institute +CARE s Caribbean Epidemiology Centre +CARI s Cukurova Agricultural Research Institute +CARL s Carleton College, Biology Department +CARM s Carmarthen County Museum +CARS s University of Surinam, Center for Agricultural Research +CART s Carthage College, Biology Department +CAS s California Academy of Sciences +CAS-IU s California Academy of Science, Indiana University Collection +CAS-SU s California Academy of Sciences, Stanford University Collection CAS(SU) CAS:ANTH s California Academy of Sciences, Anthropology Collection CAS:BOT s California Academy of Sciences, Botany Collection CAS:DIA s California Academy of Sciences, Diatom collection @@ -793,343 +798,349 @@ CAS:SU s California Academy of Sciences, Stanford University Collection of fish CAS:SUA s California Academy of Sciences, Stanford University Collection of amphibians CAS:SUR s California Academy of Sciences, Stanford University Collection of reptiles CAS:TYPE s California Academy of Sciences, Entomology Type Collection -CASM s Chicago Academy of Sciences, Museum of Natural History -CASMB s Centre of Advanced Study in Marine Biology -CASS s Chinese Academy of Sciences, Shenyang -CAT s Universita di Catania, Dipartimento di Botanica e Orto Botanico -CATA h Catalina Island Conservancy -CATH h Catholicate College -CATIE s Tropical Agricultural Research and Training Center (CATIE), Plant Production Department -CAU s China Agricultural University -CAUP s Universidad del Cauca -CAUP c Collection of Algae of Charles University, Prague -CAUSC s Universidade Federal de Santa Catarina Centro de Agrarias -CAVA s University of California at Berkeley -CAY s Institut de Recherche pour le Developpement (IRD) -CAYM s National Trust for the Cayman Islands -CB c The CB Rhizobium Collection -CB s Jihoceske Muzeum -CBAS c Bacteria Collection of Environmemt and Health (Colecao de Bacterias do Ambiente e Saude) -CBD s Collezione Ittiologica Balma-Delmastro -CBD c USF Center for Biological Defense -CBF s Coleccion Boliviana de Fauna -CBFS s University of South Bohemia, Department of Botany -CBG s Australian National Botanic Gardens -CBM s Natural History Museum and Institute +CASM s Chicago Academy of Sciences, Museum of Natural History +CASMB s Centre of Advanced Study in Marine Biology +CASS s Chinese Academy of Sciences, Shenyang +CAT s Universita di Catania, Dipartimento di Botanica e Orto Botanico +CATA h Catalina Island Conservancy +CATH h Catholicate College +CATIE s Tropical Agricultural Research and Training Center (CATIE), Plant Production Department +CAU s China Agricultural University +CAUP s Universidad del Cauca +CAUP c Collection of Algae of Charles University, Prague +CAUSC s Universidade Federal de Santa Catarina Centro de Agrarias +CAVA s University of California at Berkeley +CAWC s Conservation Commission of the Northern Territory NTM +CAY s Institut de Recherche pour le Developpement (IRD) +CAYM s National Trust for the Cayman Islands +CB c The CB Rhizobium Collection +CB s Jihoceske Muzeum +CBAS c Bacteria Collection of Environmemt and Health (Colecao de Bacterias do Ambiente e Saude) +CBC s Centre for Biodiversity Conservation +CBD s Collezione Ittiologica Balma-Delmastro +CBD c USF Center for Biological Defense +CBF s Coleccion Boliviana de Fauna CBFC +CBFS s University of South Bohemia, Department of Botany +CBG s Australian National Botanic Gardens +CBM s Natural History Museum and Institute CBM:ZC s Natural History Museum and Institute, Zoological Collection -CBMAI c Brazilian Collection of Microorganisms from the Environment and Industry (Colecao Brasileira de Microrganismos de Ambiente e Industria) -CBNM s Cedar Breaks National Monument -CBNSA h Conservatoire botanique national Sud-Atlantique -CBPF h Conservatoire Botanique Pierre Fabre -CBS sc Centraalbureau voor Schimmelcultures, Fungal and Yeast Collection -CBSIZA s Caspian Biological Station Institute of Zoology -CBTCCCAS c The Cell Bank of Type Culture Collection of Chinese Academy of Sciences -CBU s Cape Breton University -CBU s Chungbuk National University, School of Life Science -CBY s Royal Museum and Art Gallery -CC c CSIRO Canberra Rhizobium Collection -CCA-Marburg c Culture Collection of Algae at the University of Marburg -CCAC s Universidade Federal do Ceara, Centro Ciencias Agrarias -CCAC c Culture Collection of Algae at the University of Cologne -CCALA c Culture Collection of Autotrophic Organisms -CCAP c Culture Collection of Algae and Protozoa -CCARM c Culture Collection of Antimirobial Resistant Microorganisms -CCAU s Central China Agricultural University -CCB c Colecao de Culturas de Basidiomicetos -CCB s Central College, Bangalore -CCBAS c Culture Collection of Basidiomycetes -CCBAU c Culture Collection, Beijing Agricultural University -CCC c Culture Collection of Clavicipitaceae -CCC c Cyanobacterial Culture Collection, National Centre for Conservation and Utilisation of Blue Green Algae -CCCC s Carthage College -CCCIEB c Culture Collections of Microorgansisms of Center of Genetic Engineering and Biotechnology -CCCM c Canadian Center for the Culture of Microorganisms -CCCR h Federal University of Tocantins -CCCryo c Culture Collection of Cryophilic Algae -CCCS c Culture Collection of Ciliates and their Symbionts -CCCZ s University of Malawi -CCDB s Crustacean Collection of the Department of Biology -CCDM c Culture Collection of Department of Microbiology -CCDM c Culture Collection of Dairy Microorganisms Laktoflora -CCDMBI c Culture Collection, Department of Microbiology -CCEB c Culture Collection of Entomogenous Bacteria -CCEC s Museum, Centre de Conservation et d'Etude des Collections -CCF c Colleccion de Cuttivos Finlay -CCF c Culture Collection of Fungi -CCFC c Canadian Collection of Fungal Cultures -CCFEE c Culture Collection of Fungi From Extreme Environments -CCFHE s Cornwall College of Further and Higher Education, Natural Sciences Department -CCFL s Chad National Museum -CCFVB c Facultat de Veterinaria, Universitat Autonoma de Barcelona -CCG s Chengdu College of Geology -CCG s University of Cape Coast, Botany Department -CCGB c Cole(e7)o de Culturas do G(ea)ero Bacillus e G(ea)eros Correlatos -CCGVCC c China Centre for General Viruses Culture Collection -CCH h University of Arizona South, Agricultural Extension Service -CCIAL c Cultures Cells for Institute Adolfo Lutz -CCIBSO c Culture Collection IBSO -CCIM c Culture Collection of Industrial Microorganisms -CCM c Czech Collection of Microorganisms -CCM-A c Coleccion de Cultivos Microbianos -CCM s Changchun College of Traditional Chinese Medicine, Department of Chinese Materia Medica -CCM s Carter County Museum -CCMAC c Culture Collection of Macromycetes (Basidiomycotina and Ascomycotina) -CCMCU c Culture Collection of Microorganisms -CCMF c University of Portsmouth -CCMGE s Chernyshev Central Museum of Geological Explorations,Collections of the Department of Herpetology, Zoological Institute of the Russian Academy of Sciences -CCMH h Concordia College -CCMI c Culture Collection of Industrial Microorganisms -CCML s Coleccion Ictiologica del Departamento de Ciencias Marinas de la Universidad de la Laguna -CCMM c Moroccan Coordinated Collections of Microorganisms -CCMP c Provasoli-Guillard National Center for Marine Algae and Microiota -CCNH s Central Michigan University, Center for Cultural and Natural History -CCNL s Connecticut College, Botany Department -CCNP s Carlsbad, Carlsbad Caverns National Park -CCNP c Culture Collection of Northern Poland -CCNU s Central China Normal University, Biology Department -CCO s Carleton University, Biology Department -CCOS c Culture Collection of Switzerland -CCPF c Collection of Phytopathogenic Fungi -CCR s Chichester District Museum -CCRI c Collection du Centre de Recherche en Infectiologie -CCRI scb The Central Coffee Research Institute -CCSIIA c Culture Collection of Sichuan Industrial Institute Antibiotics -CCSRL s Centro Studi e Ricerche Ligabue -CCSU s Central Connecticut State University, Biological Sciences Department -CCT c Colecao de Culturas Tropical -CCTCC c China Center for Type Culture Collection -CCTM c Centre de Collection de Type Microbien, Institut de Microbiologie, Universite de Lausanne -CCTR c Culture Collection Trutnov -CCTS h Universidade Federal de Sao Carlos -CCTU c Culture Collection of Tabriz University -CCUF s Universidade Federal de Alagoas, Centro de Ciencias Biologicas -CCUG c Culture Collection, University of Goteborg, Department of Clinical Bacteriology -CCVC s Centenary College, Vertebrate Collection -CCVCC c China Center For Virus Culture Collection -CCW s Casper College -CCY c Culture Collection Yerseke, Department of Marine Microbiology -CCY c Culture Collection of Yeasts, Slovak Academy of Sciences, Institute of Chemistry -CDA c Canadian Department of Agriculture -CDA s California Department of Food and Agriculture -CDBB c Coleccion Nacional de Cepas Microbianas y Cultivos Celulares -CDBI s Chengdu Institute of Biology -CDC c Centers for Disease Control and Prevention -CDC s Changdu Institute for Drug Control -CDCM s Chengdu College of Traditional Chinese Medicine -CDFM s Cardiff Museum -CDFN s Canadian Forest Service - Atlantic -CDN s Whitgift School -CDRI s Central Drug Research Institute -CDRS s Invertebrate Collection -CDS s Charles Darwin Research Station, Botany Department -CEAM s Centro de Entomologica y Acarologia -CEB s Tadulako University -CEBU s University of San Carlos, Biology Department -CECT c Coleccion Espanola de Cultivos Tipo -CEDD s International Center for Ethnomedicine and Drug Development -CEDiT s Centre of Excellence for Dinophyte Taxonomy -CEEF s Escuela Nacional de Ciencias Forestales -CEET s El Colegio de la Frontera Sur, Colleccion de Insectos Asociados a Plantas Cultivadas en la Frontera Sur -CEL s University of Illinois, Crop Sciences Department -CELM s Coleccion Entomologica "Luis Maria Murillo" -CELMS c Collection of Environmental and Laboratory Microbial Strains -CEMBP s Centre of Excellence in Marine Biology -CEN s Genetic Resources and Biotechnology (CENARGEN), EMBRAPA -CENA s Centro de Energia Nuclear na Agricultura, Universidade de Sao Paulo -CENA s Centro Nacional de Proteccion Vegetal -CENACUMI c Centro Nacional de Cultivos Microbianos (National Center For Microbial Cultures) -CENG s Centro Experimental de Nueva Guinea -CEP c Entomopathogenic Fungal Culture Collection of Argentina -CEPEC s CEPEC, CEPLAC -CEPH b Foundation Jean Dausset (CEPH) -CEPIM c Centro per gli Enterobatteri Patogeni per l'Italia Meridionale -CEPM c CEPM- Centre d'Etudes sur le Polymorphisme des Micro-organismes -CERL/BIC s United States Army, Biological Inventory Collection -CERN s University -CES s The Centre for Ecological Sciences, Indian Institute of Science -CESJ s Universidade Federal de Juiz de Fora, Departamento de Botanica -CESK s Muzeum Teainska -CEST s Central Experiment Station -CET s Centro de Estudios Tropicales -CETESB c Setor de Pesquisa Tecnologica de Sistemas de Tratamento de Efluentes Domesticos -CEU s Collage of Eastern Utah -CFB s Northern Forestry Centre, Canadian Forest Service -CFBH s Celio F.B. Haddad Herpetological Collection, Departamento de Zoologia, Universidade Estadual Paulista -CFBP c Collection Francaise des Bacteries Phytopathogenes -CFCC cb China Forestry Culture Collection Center -CFI s Genetic Resources and Biotechnology (CENARGEN), EMBRAPA -CFIA h Canadian Food Inspection Agency -CFMR sc Center for Forest Mycology Research -CFN s Clifton College, Biology Department -CFNL s Universidad Autonoma de Nuevo Leon -CFQ c Cepario de la Facultad de Quimica -CFRB s Chinese Academy of Forestry, Forest Research Institute -CFS s Canadian Forest Service, Pacific Forest Research Centre -CFSHB s North Coast Regional Botanic Gardens -CFUA s Universidad Austral de Chile -CG c Embrapa Collection of Fungi of Invertebrates -CGC b Caenorhabditis Genetics Center -CGE s University of Cambridge, Department of Plant Sciences -CGEC s China Entomological Research Institute -CGG s Cambridge University Botanic Garden -CGH s National Museum of Prague -CGMCC c China General Microbiological Culture Collection Center, Chinese Academy of Sciences -CGMS s Universidade Federal de Mato Grosso do Sul, Departamento de Biologia -CGN s Centre for Genetic Resources, The Netherlands -CGRIS b Chinese Crop Germplasm Resources Information Network -CGSC c E. coli Genetic Stock Center -CH s Circulo Herpetologico de Panama -CH-AG c Collection de Recherche -CHA s Hebei Agrotechnical Teachers College -CHAB s Far East Forestry Research Institute -CHAF s Chaffey College, Biology Department -CHAM s I.N.T.A., E.E.A. La Rioja -CHAP s Universidad Autonoma Chapingo -CHAPA s Colegio de Postgraduados, Botanica, IRENAT -CHARL s Charleston Museum -CHAS s Chicago Academy of Sciences -CHAS s Southern Research Station -CHBG s Christchurch Botanic Gardens -CHE s Societe Nationale des Sciences Naturelles et Mathematiques de Cherbourg -CHEB s Regional Museum Cheb -CHEL s Chelsea Physic Garden -CHELB s Cheltenham College for Boys -CHEP s Escuela Superior Politecnica del Chimborazo -CHER s Yu. Fedcovich Chernivtsi State University, Botany Department -CHFD s Chelmsford and Essex Museum -CHI s University of Illinois, Biological Sciences Department -CHIA s National Chiayi Agricultural College, Forestry Department -CHIC s Chicago Botanic Garden, Research Department -CHINM s Instituto Nacional de Microbiologia -CHIOC s Helminthological Collection of Oswaldo Cruz Institute (Coleccion. Helmintologica del Instituto Oswaldo Cruz) -CHIP s Instituto de Historia Natural, Departamento de Botanica -CHIS s Academy of Sciences of Moldova -CHISA s University of Agriculture -CHL s Cheltenham Grammar School -CHM s Cheltenham Art Gallery and Museum -CHM s Charleston Museum -CHNCB s Centre d'Historia Natural de la Conca de Barbera -CHOCO s Universidad Tecnologica del Choco -CHOM s Okresni muzeum Chomutov -CHPU s Chelyabinsk State Pedagogical University, Botany Department -CHR s Allan Herbarium -CHRB s Rutgers University - Cook College -CHRG s Grosvenor Museum -CHSC s California State University, Biological Sciences Department -CHT s Cheltenham College -CHUG s Garyounis University, Botany Department -CHULA c Microbiology Department Faculty of Science -CHUNB s University of Brasilia Herpetological Collection -CHUR s Buendner Natur-Museum -CI s Carnegie Institution of Washington, Plant Biology Department -CIAN s Instituto Nacional de Investigaciones Forestales, Agricolas y Pecuarias (INIFAP) -CIAN s Centro de Investigaciones Agricolas Nortoeste -CIAT b Centro Internacional de Agricultura Tropical (International Center for Tropical Agriculture) +CBMAI c Brazilian Collection of Microorganisms from the Environment and Industry (Colecao Brasileira de Microrganismos de Ambiente e Industria) +CBNM s Cedar Breaks National Monument +CBNSA h Conservatoire botanique national Sud-Atlantique +CBPF h Conservatoire Botanique Pierre Fabre +CBS sc Westerdijk Fungal Biodiversity Institute +CBSIZA s Caspian Biological Station Institute of Zoology +CBTCCCAS c The Cell Bank of Type Culture Collection of Chinese Academy of Sciences +CBU s Cape Breton University +CBU s Chungbuk National University, School of Life Science +CBY s Royal Museum and Art Gallery +CC c CSIRO Canberra Rhizobium Collection +CCA-Marburg c Culture Collection of Algae at the University of Marburg +CCAC s Universidade Federal do Ceara, Centro Ciencias Agrarias +CCAC c Culture Collection of Algae at the University of Cologne +CCALA c Culture Collection of Autotrophic Organisms +CCAP c Culture Collection of Algae and Protozoa +CCARM c Culture Collection of Antimirobial Resistant Microorganisms +CCAU s Central China Agricultural University +CCB c Colecao de Culturas de Basidiomicetos +CCB s Central College, Bangalore +CCBAS c Culture Collection of Basidiomycetes +CCBAU c Culture Collection, Beijing Agricultural University +CCC c Culture Collection of Clavicipitaceae +CCC c Cyanobacterial Culture Collection, National Centre for Conservation and Utilisation of Blue Green Algae +CCCC s Carthage College +CCCIEB c Culture Collections of Microorgansisms of Center of Genetic Engineering and Biotechnology +CCCM c Canadian Center for the Culture of Microorganisms +CCCR h Federal University of Tocantins +CCCryo c Culture Collection of Cryophilic Algae +CCCS c Culture Collection of Ciliates and their Symbionts +CCCZ s University of Malawi +CCDB s Crustacean Collection of the Department of Biology +CCDM c Culture Collection of Department of Microbiology +CCDM c Culture Collection of Dairy Microorganisms Laktoflora +CCDMBI c Culture Collection, Department of Microbiology +CCEB c Culture Collection of Entomogenous Bacteria +CCEC s Museum, Centre de Conservation et d'Etude des Collections +CCF c Colleccion de Cuttivos Finlay +CCF c Culture Collection of Fungi +CCFC c Canadian Collection of Fungal Cultures +CCFEE c Culture Collection of Fungi From Extreme Environments +CCFHE s Cornwall College of Further and Higher Education, Natural Sciences Department +CCFL s Chad National Museum +CCFVB c Facultat de Veterinaria, Universitat Autonoma de Barcelona +CCG s Chengdu College of Geology CHG +CCG s University of Cape Coast, Botany Department +CCGB c Culture Collection of Bacillus and Related Genera (Instituto Oswaldo Cruz) +CCGVCC c China Centre for General Viruses Culture Collection +CCH h University of Arizona South, Agricultural Extension Service +CCIAL c Cultures Cells for Institute Adolfo Lutz +CCIBSO c Culture Collection IBSO +CCIBt c Culture Collection at the Institute of Botany, Sao Paulo +CCIM c Culture Collection of Industrial Microorganisms +CCM c Czech Collection of Microorganisms CCM +CCM-A c Coleccion de Cultivos Microbianos +CCM s Changchun College of Traditional Chinese Medicine, Department of Chinese Materia Medica +CCM s Carter County Museum +CCMAC c Culture Collection of Macromycetes (Basidiomycotina and Ascomycotina) +CCMCU c Culture Collection of Microorganisms +CCMF c University of Portsmouth +CCMGE s Chernyshev Central Museum of Geological Explorations,Collections of the Department of Herpetology, Zoological Institute of the Russian Academy of Sciences +CCMH h Concordia College +CCMI c Culture Collection of Industrial Microorganisms +CCML s Coleccion Ictiologica del Departamento de Ciencias Marinas de la Universidad de la Laguna +CCMM c Moroccan Coordinated Collections of Microorganisms +CCMP c Provasoli-Guillard National Center for Marine Algae and Microiota +CCNH s Central Michigan University, Center for Cultural and Natural History +CCNL s Connecticut College, Botany Department +CCNP s Carlsbad, Carlsbad Caverns National Park +CCNP c Culture Collection of Northern Poland +CCNU s Central China Normal University, Biology Department +CCO s Carleton University, Biology Department +CCOS c Culture Collection of Switzerland +CCPF c Collection of Phytopathogenic Fungi +CCR s Chichester District Museum +CCRI c Collection du Centre de Recherche en Infectiologie +CCRI scb The Central Coffee Research Institute +CCSIIA c Culture Collection of Sichuan Industrial Institute Antibiotics +CCSRL s Centro Studi e Ricerche Ligabue +CCSU s Central Connecticut State University, Biological Sciences Department +CCT c Colecao de Culturas Tropical +CCTCC c China Center for Type Culture Collection +CCTM c Centre de Collection de Type Microbien, Institut de Microbiologie, Universite de Lausanne +CCTR c Culture Collection Trutnov +CCTS h Universidade Federal de Sao Carlos +CCTU c Culture Collection of Tabriz University +CCUF s Universidade Federal de Alagoas, Centro de Ciencias Biologicas +CCUG c Culture Collection, University of Goteborg, Department of Clinical Bacteriology +CCVC s Centenary College, Vertebrate Collection +CCVCC c China Center For Virus Culture Collection +CCW s Casper College +CCY c Culture Collection Yerseke, Department of Marine Microbiology +CCY c Culture Collection of Yeasts, Slovak Academy of Sciences, Institute of Chemistry +CDA c Canadian Department of Agriculture +CDA s California Department of Food and Agriculture +CDBB c Coleccion Nacional de Cepas Microbianas y Cultivos Celulares +CDBI s Chengdu Institute of Biology +CDC c Centers for Disease Control and Prevention +CDC s Changdu Institute for Drug Control +CDCM s Chengdu College of Traditional Chinese Medicine +CDFM s Cardiff Museum +CDFN s Canadian Forest Service - Atlantic +CDN s Whitgift School +CDRI s Central Drug Research Institute +CDRS s Invertebrate Collection +CDS s Charles Darwin Research Station, Botany Department +CEAM s Centro de Entomologica y Acarologia +CEB s Tadulako University +CEBU s University of San Carlos, Biology Department +CECT c Coleccion Espanola de Cultivos Tipo +CEDD s International Center for Ethnomedicine and Drug Development +CEDiT s Centre of Excellence for Dinophyte Taxonomy +CEEF s Escuela Nacional de Ciencias Forestales +CEET s El Colegio de la Frontera Sur, Colleccion de Insectos Asociados a Plantas Cultivadas en la Frontera Sur +CEL s University of Illinois, Crop Sciences Department +CELM s Coleccion Entomologica "Luis Maria Murillo" +CELMS c Collection of Environmental and Laboratory Microbial Strains +CEMBP s Centre of Excellence in Marine Biology +CEN s Genetic Resources and Biotechnology (CENARGEN), EMBRAPA +CENA s Centro de Energia Nuclear na Agricultura, Universidade de Sao Paulo +CENA s Centro Nacional de Proteccion Vegetal +CENACUMI c Centro Nacional de Cultivos Microbianos (National Center For Microbial Cultures) +CENG s Centro Experimental de Nueva Guinea +CEP c Entomopathogenic Fungal Culture Collection of Argentina +CEPEC s CEPEC, CEPLAC +CEPH b Foundation Jean Dausset (CEPH) +CEPIM c Centro per gli Enterobatteri Patogeni per l'Italia Meridionale +CEPM c CEPM- Centre d'Etudes sur le Polymorphisme des Micro-organismes +CERL/BIC s United States Army, Biological Inventory Collection +CERN s University +CES s The Centre for Ecological Sciences, Indian Institute of Science +CESJ s Universidade Federal de Juiz de Fora, Departamento de Botanica +CESK s Muzeum Teainska +CEST s Central Experiment Station +CET s Centro de Estudios Tropicales +CETESB c Setor de Pesquisa Tecnologica de Sistemas de Tratamento de Efluentes Domesticos +CEU s Collage of Eastern Utah +CFB s Northern Forestry Centre, Canadian Forest Service +CFBH s Celio F.B. Haddad Herpetological Collection, Departamento de Zoologia, Universidade Estadual Paulista +CFBP c Collection Francaise des Bacteries Phytopathogenes +CFCC cb China Forestry Culture Collection Center +CFI s Genetic Resources and Biotechnology (CENARGEN), EMBRAPA +CFIA h Canadian Food Inspection Agency +CFMR sc USDA Forest Service, Center for Forest Mycology Research FPL +CFN s Clifton College, Biology Department +CFNL s Universidad Autonoma de Nuevo Leon +CFQ c Cepario de la Facultad de Quimica +CFRB s Chinese Academy of Forestry, Forest Research Institute +CFS s Canadian Forest Service, Pacific Forest Research Centre +CFSHB s North Coast Regional Botanic Gardens +CFUA s Universidad Austral de Chile +CG c Embrapa Collection of Fungi of Invertebrates +CGC b Caenorhabditis Genetics Center +CGE s University of Cambridge, Department of Plant Sciences +CGEC s China Entomological Research Institute +CGG s Cambridge University Botanic Garden +CGH s National Museum of Prague +CGMCC c China General Microbiological Culture Collection Center, Chinese Academy of Sciences +CGMS s Universidade Federal de Mato Grosso do Sul, Departamento de Biologia +CGN s Centre for Genetic Resources, The Netherlands +CGRIS b Chinese Crop Germplasm Resources Information Network +CGSC c E. coli Genetic Stock Center +CH s Circulo Herpetologico de Panama +CH-AG c Collection de Recherche +CHA s Hebei Agrotechnical Teachers College +CHAB s Far East Forestry Research Institute +CHAF s Chaffey College, Biology Department +CHAM s I.N.T.A., E.E.A. La Rioja +CHAP s Universidad Autonoma Chapingo +CHAPA s Colegio de Postgraduados, Botanica, IRENAT +CHARL s Charleston Museum +CHAS s Chicago Academy of Sciences +CHAS s Southern Research Station +CHBG s Christchurch Botanic Gardens +CHE s Societe Nationale des Sciences Naturelles et Mathematiques de Cherbourg +CHEB s Regional Museum Cheb +CHEL s Chelsea Physic Garden +CHELB s Cheltenham College for Boys +CHEP s Escuela Superior Politecnica del Chimborazo +CHER s Yu. Fedcovich Chernivtsi State University, Botany Department +CHFD s Chelmsford and Essex Museum +CHI s University of Illinois, Biological Sciences Department +CHIA s National Chiayi Agricultural College, Forestry Department +CHIC s Chicago Botanic Garden, Research Department +CHINM s Instituto Nacional de Microbiologia +CHIOC s Helminthological Collection of Oswaldo Cruz Institute (Coleccion. Helmintologica del Instituto Oswaldo Cruz) +CHIP s Instituto de Historia Natural, Departamento de Botanica +CHIS s Academy of Sciences of Moldova +CHISA s University of Agriculture +CHL s Cheltenham Grammar School +CHM s Cheltenham Art Gallery and Museum +CHM s Charleston Museum +CHNCB s Centre d'Historia Natural de la Conca de Barbera +CHOCO s Universidad Tecnologica del Choco +CHOM s Okresni muzeum Chomutov +CHPU s Chelyabinsk State Pedagogical University, Botany Department +CHR s Allan Herbarium LCR:CHR +CHRB s Rutgers University - Cook College +CHRG s Grosvenor Museum +CHSC s California State University, Biological Sciences Department +CHT s Cheltenham College +CHUG s Garyounis University, Botany Department +CHULA c Microbiology Department Faculty of Science +CHUNB s University of Brasilia Herpetological Collection +CHUR s Buendner Natur-Museum +CI s Carnegie Institution of Washington, Plant Biology Department +CIAN s Instituto Nacional de Investigaciones Forestales, Agricolas y Pecuarias (INIFAP) +CIAN s Centro de Investigaciones Agricolas Nortoeste +CIAT b Centro Internacional de Agricultura Tropical (International Center for Tropical Agriculture) CIAT:Bean b Centro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Bean Collection CIAT:Cassava b Centro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Cassava Collection CIAT:Forage b Centro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Forages Collection CIAT:Rhizobium c Centro Internacional de Agricultura Tropical (International Center for Tropical Agriculture), CIAT Rhizobium Collection -CIB s Chengdu Institute of Biology -CIB s Centro de Investigaciones Biologicas del Noroeste, S.C. (Mexico) -CIB s Universidad Veracruzana -CIBC s International Institute of Biological Control -CIBIO s Centro de Investigacao em Biodiversidade e Recursos Geneticos -CIBM s Centro Invest. Biol. Noroeste -CIC s Albertson College of Idaho, Biology Department -CICC c China Center for Industrial Culture Collection -CICESE s Centro de Investigacion Cientifica y de Educacion Superior de Ensenada -CICIM c Culture and Information Centre of Industrial Microorganisms of China's Univeristies -CICIMAR s Centro Interdisciplinario de Ciencias Marinas -CICV c Centro de Investigaciones en Ciencias Veterinarias -CICY s Centro de Investigacion Cientifica de Yucatan, A.C. (CICY) -CIDA s Albertson College, Museum of Natural History -CIECRO s County Record Office, Cambridgeshire -CIES c Centro de Investigacion, Experimentacion y Servicios del Champinon -CIFE s Central Institute of Fisheries Education -CIIDIR s Instituto Politecnico Nacional -CIJC s Muzeului Judetean Covasna, Collection of Insects -CIMAP s Central Institute of Medicinal and Aromatic Plants -CIMAR s Universidad Catolica de Valparaiso, Centro de Investigaciones del Mar -CIMI s Centro Interdisciplinario de Investigacion para el Desarrollo Integral Regional (CIIDIR) IPN-Michoacan -CIMMYT scb International Maize and Wheat Improvement Center -CIMNH s Albertson College of Idaho, Orma J. Smith Museum of Natural History -CIMSC c Collezione Instituto di Microbiologia -CINC s University of Cincinnati, Biological Sciences Department -CIP c Pasteur Institute Collection, Biological Resource Center of Pasteur Institute (CRBIP) -CIP s Centro de Investigaciones Pesqueras -CIP c International Potato Center -CIP b Centro Internacional de las Papas -CIPDE c Collection of Insect Pathogens, Dept. of Entomology -CIPT c Collection Institut Pasteur Tuberculose -CIQR s El Colegio de la Frontera Sur -CIR s Royal Agricultural College -CIRAD sb Centre de Cooperation Internationale en Recherche Agronomique pour le Developpement -CIRUV s Coleccion Ictiologica de Referencia de la Universidad del Valle -CIS s Academia Sinica and State Planning Commission -CIS s California Insect Survey -CIS s Cranbrook Institute of Science -CISM c Verticillium dahliae from cotton -CISM c NifTAL Rhizobium Collection (Asia Center) -CIT s Citrus Research Institute -CITA s The Citadel, Biology Department -CIUC s Centro Interdipartimentale dell'Universita Museo di Storia Naturale e del Territorio -CIZ s Centro de Investigaciones Zoologicas -CKE s Calke Abbey -CL s Babes-Bolyai University -CLA s Universitatea de Stiinte Agricole si Medicina Veterinara -CLARK h Dr. Charles F. and Wilhelmina Husser Clark Herbarium -CLCB s Laboratorul de Ecologie -CLCC s Augustana University College -CLD s Cleveland Literary and Philosophical Society -CLE s Tullie House Museum -CLEMS s Clemson University, Biological Sciences Department -CLEV s Cleveland Museum of Natural History -CLEY s Coastal Ecology Research Station -CLF s Institut des Universitaires et Musee Lecoq -CLI s Literary and Philosophical Institution of Chatham -CLIB c Collection de Levures d'Interet Biotechnologique Collection of Yeasts of Biotechnological Interest -CLIOC c Colecao de Leishmania do Instituto Oswaldo Cruz -CLM s Cleveland Museum of Natural History, Botany Department -CLMP s Department of Conservation & Land Management -CLNP s Crater Lake National Park -CLOE s Clitheroe Castle Museum -CLP s Forest Products Research and Development Institute, Department of Science and Technology -CLQCA c Coleccion de Levaduras quito catolica -CLR s All Saint's Church, Colchester Borough Council -CLU s Universita della Calabria -CM s Carnegie Museum of Natural History -CM-IEA s Universidad Autonoma de Tamaulipas (Mexico) -CM-MBM-UAC s Coleccion Mastozoologica de la Museo de Biodiversidad Maya, Universidad Autonoma de Campeche -CM-UMSNH s Universidad de Michoacan (Mexico) +CIB s Chengdu Institute of Biology +CIB s Centro de Investigaciones Biologicas del Noroeste, S.C. (Mexico) +CIB s Universidad Veracruzana +CIBC s International Institute of Biological Control +CIBIO s Centro de Investigacao em Biodiversidade e Recursos Geneticos +CIBM s Centro Invest. Biol. Noroeste +CIC s Albertson College of Idaho, Biology Department +CICC c China Center for Industrial Culture Collection +CICCM c Cawthron Institute Culture Collection of Micro-algae +CICESE s Centro de Investigacion Cientifica y de Educacion Superior de Ensenada +CICIM c Culture and Information Centre of Industrial Microorganisms of China's Univeristies +CICIMAR s Centro Interdisciplinario de Ciencias Marinas +CICV c Centro de Investigaciones en Ciencias Veterinarias +CICY s Centro de Investigacion Cientifica de Yucatan, A.C. (CICY) +CIDA s Albertson College, Museum of Natural History +CIECRO s County Record Office, Cambridgeshire +CIES c Centro de Investigacion, Experimentacion y Servicios del Champinon +CIFE s Central Institute of Fisheries Education +CIIDIR s Instituto Politecnico Nacional +CIJC s Muzeului Judetean Covasna, Collection of Insects +CIMAP s Central Institute of Medicinal and Aromatic Plants +CIMAR s Universidad Catolica de Valparaiso, Centro de Investigaciones del Mar +CIMI s Centro Interdisciplinario de Investigacion para el Desarrollo Integral Regional (CIIDIR) IPN-Michoacan +CIMMYT scb International Maize and Wheat Improvement Center +CIMNH s Albertson College of Idaho, Orma J. Smith Museum of Natural History +CIMSC c Collezione Instituto di Microbiologia +CINC s University of Cincinnati, Biological Sciences Department +CIP c Pasteur Institute Collection, Biological Resource Center of Pasteur Institute (CRBIP) CIP +CIP s Centro de Investigaciones Pesqueras +CIP c International Potato Center +CIP b Centro Internacional de las Papas +CIPDE c Collection of Insect Pathogens, Dept. of Entomology +CIPT c Collection Institut Pasteur Tuberculose +CIQR s El Colegio de la Frontera Sur +CIR s Royal Agricultural College +CIRAD sb Centre de Cooperation Internationale en Recherche Agronomique pour le Developpement +CIRUV s Coleccion Ictiologica de Referencia de la Universidad del Valle +CIS s Academia Sinica and State Planning Commission +CIS s California Insect Survey +CIS s Cranbrook Institute of Science CISM +CISM c Verticillium dahliae from cotton +CISM c NifTAL Rhizobium Collection (Asia Center) +CIT s Citrus Research Institute +CITA s The Citadel, Biology Department +CIUC s Centro Interdipartimentale dell'Universita Museo di Storia Naturale e del Territorio +CIZ s Centro de Investigaciones Zoologicas +CKE s Calke Abbey +CL s Babes-Bolyai University +CLA s Universitatea de Stiinte Agricole si Medicina Veterinara +CLARK h Dr. Charles F. and Wilhelmina Husser Clark Herbarium +CLCB s Laboratorul de Ecologie +CLCC s Augustana University College +CLD s Cleveland Literary and Philosophical Society +CLE s Tullie House Museum +CLEMS s Clemson University, Biological Sciences Department +CLEV s Cleveland Museum of Natural History +CLEY s Coastal Ecology Research Station +CLF s Institut des Universitaires et Musee Lecoq +CLI s Literary and Philosophical Institution of Chatham +CLIB c Collection de Levures d'Interet Biotechnologique Collection of Yeasts of Biotechnological Interest +CLIOC c Colecao de Leishmania do Instituto Oswaldo Cruz IOC:CL +CLM s Cleveland Museum of Natural History, Botany Department +CLMP s Department of Conservation & Land Management +CLNP s Crater Lake National Park +CLOE s Clitheroe Castle Museum +CLP s Forest Products Research and Development Institute, Department of Science and Technology +CLQCA c Coleccion de Levaduras quito catolica +CLR s All Saint's Church, Colchester Borough Council +CLU s Universita della Calabria +CM s Carnegie Museum of Natural History CMNH +CM-IEA s Universidad Autonoma de Tamaulipas (Mexico) +CM-MBM-UAC s Coleccion Mastozoologica de la Museo de Biodiversidad Maya, Universidad Autonoma de Campeche CM-MBM-UAC +CM-UMSNH s Universidad de Michoacan (Mexico) CM:M s Carnegie Museum of Natural History, Section of Mammals CM:O s Carnegie Museum of Natural History, Section of Birds -CM s Chongqing Museum -CMA s Crayford Manor House Adult Education Centre -CMBGCAS c Collection of Marine Biological Germplasm -CMBK s The City Museum and Art Gallery, Department of Natural History -CMBY s Camberley Museum -CMC s Coleccion Mastozoologica del Centro de Investigacion en Biodiversidad y Conservacion,Universidad Autonoma del Estado de Morelos -CMC s Canterbury Museum -CMC s Central Michigan University, Department of Biology -CMCC c National Center for Medical Culture Collections -CMCNA s Museo de Ciencias Naturales y Antropologicas "Prof. A. Serrano" -CMDM-PUJ c Coleccion Microorganismos Departamento Microbiologia -CMEI s Clements' Museum of Exotic Insects -CMFRI s See FMRI -CMGP s Central Museum of Geological Prospecting -CMIZASDPRK s Custody Museum -CMKKU c Clinical Diagnostic Microbiology Srinagarind Hospital, Faculty of Medicine -CML s Universidad Nacional de Tucuman, Coleccion de Mamiferos Lillo (Argentina) -CML c Colecao Micologica de Lavras -CMM s Bradford Art Galleries and Museums, Natural Sciences Department -CMM c Culture Collection of Phytopathogenic Fungi (Colecao de Culturas de Fungos Fitopatogenicos Prof. Maria Menezes) -CMMC c China Marine Microbe Collection -CMMED c Center for Marine Microbial Ecology & Diversity Collection -CMMEX s Universidad Autonoma de Baja California -CMMF h Jardin botanique de Montreal -CMMI s Chinese Academy of Traditional Medicine -CMML s Colorado State University Herbarium -CMN s Canadian Museum of Nature +CM s Chongqing Museum +CMA s Crayford Manor House Adult Education Centre +CMAA c Culture Collection of Agriculture and Environmental Importance +CMBGCAS c Collection of Marine Biological Germplasm +CMBK s The City Museum and Art Gallery, Department of Natural History +CMBY s Camberley Museum +CMC s Coleccion Mastozoologica del Centro de Investigacion en Biodiversidad y Conservacion,Universidad Autonoma del Estado de Morelos +CMC s Canterbury Museum +CMC s Central Michigan University, Department of Biology +CMCC c National Center for Medical Culture Collections +CMCNA s Museo de Ciencias Naturales y Antropologicas "Prof. A. Serrano" +CMDM-PUJ c Coleccion de Microorganismos de la Pontificia Universidad Javeriana (Collection Microorganisms of the Pontificia Universidad Javeriana) CMDM-PUJ +CMEI s Clements' Museum of Exotic Insects +CMFRI s See FMRI +CMGP s Central Museum of Geological Prospecting +CMH s Canadian Museum of History +CMIZASDPRK s Custody Museum +CMKKU c Clinical Diagnostic Microbiology Srinagarind Hospital, Faculty of Medicine +CML s Universidad Nacional de Tucuman, Coleccion de Mamiferos Lillo (Argentina) +CML c Colecao Micologica de Lavras +CMM s Bradford Art Galleries and Museums, Natural Sciences Department +CMM c Culture Collection of Phytopathogenic Fungi (Colecao de Culturas de Fungos Fitopatogenicos Prof. Maria Menezes) +CMMC c China Marine Microbe Collection +CMMED c Center for Marine Microbial Ecology & Diversity Collection +CMMEX s Universidad Autonoma de Baja California +CMMF h Jardin botanique de Montreal +CMMI s Chinese Academy of Traditional Medicine +CMML s Colorado State University Herbarium +CMN s Canadian Museum of Nature CMN:Annelid s Canadian Museum of Nature, Annelid Collection CMN:Bird s Canadian Museum of Nature, Bird Collection CMN:Crustacean s Canadian Museum of Nature, Crustacean Collection @@ -1140,27 +1151,27 @@ CMN:Insect s Canadian Museum of Nature, Insect Collection CMN:Mammal s Canadian Museum of Nature, Mammal Collection CMN:Mollusc s Canadian Museum of Nature, Mollusc Collection CMN:Parasite s Canadian Museum of Nature, Parasite Collection -CMNAR s Canadian Museum of Nature, Amphibian and Reptile Collection -CMNC s Canadian Museum of Nature, Neotropical Cerambycidae Collection -CMNFI s Canadian Museum of Nature, Fish Collection -CMNH s The Cleveland Museum of Natural History -CMNS s Museum of Natural History, Shanghai -CMNZ s Canterbury Museum -CMPH h Colegio de Postgraduados -CMPR h Centre for Medicinal Plants Research -CMS h Christian Missionary Society College -CMSK s City Museum, Sheffield -CMSU s Central Missouri State University -CMU s Chiang Mai University -CMUB h Chiang Mai University -CMUH h Central Mindanao University -CMUT s Chiang Mai University -CMV s Centre Marie-Victorin -CMW c Forestry and Agricultural Biotechnology Institute, University of Pretoria, Pretoria -CMY s R. G. Kar Medical College, Botany Department -CN s Universite de Caen -CN c Wellcome Collection of Bacteria, Burroughs Wellcome Research Laboratories -CNC s Canadian National Collection of Insects, Arachnids, and Nematodes +CMNAR s Canadian Museum of Nature, Amphibian and Reptile Collection +CMNC s Canadian Museum of Nature, Neotropical Cerambycidae Collection +CMNFI s Canadian Museum of Nature, Fish Collection +CMNH s The Cleveland Museum of Natural History +CMNS s Museum of Natural History, Shanghai +CMNZ s Canterbury Museum +CMPH h Colegio de Postgraduados +CMPR h Centre for Medicinal Plants Research +CMS h Christian Missionary Society College +CMSK s City Museum, Sheffield +CMSU s Central Missouri State University +CMU s Chiang Mai University +CMUB h Chiang Mai University +CMUH h Central Mindanao University +CMUT s Chiang Mai University +CMV s Centre Marie-Victorin +CMW c Forestry and Agricultural Biotechnology Institute, University of Pretoria, Pretoria +CMY s R. G. Kar Medical College, Botany Department +CN s Universite de Caen +CN c Wellcome Collection of Bacteria, Burroughs Wellcome Research Laboratories +CNC s Canadian National Collection of Insects, Arachnids, and Nematodes CNC:Arachnida s Canadian National Collection of Insects, Arachnids, and Nematodes, Arachnida (Mites, Ticks, Spiders) CNC:Coleoptera s Canadian National Collection of Insects, Arachnids, and Nematodes, Coleoptera (Beetles) CNC:Diptera s Canadian National Collection of Insects, Arachnids, and Nematodes, Diptera (Flies) @@ -1169,1502 +1180,1516 @@ CNC:Hymenoptera s Canadian National Collection of Insects, Arachnids, and Nemato CNC:Lepidoptera s Canadian National Collection of Insects, Arachnids, and Nematodes, Lepidoptera (Butterflies, Moths) CNC:Miscellaneous s Canadian National Collection of Insects, Arachnids, and Nematodes, Miscellaneous Insect Orders CNC:Nematoda s Canadian National Collection of Insects, Arachnids, and Nematodes, Nematoda (Roundworms) -CNCI s Canadian National Collection Insects -CNCM c Collection Nationale de Cultures de Microorganismes -CNCTC c Czech National Collection of Type Cultures -CNE s Victoria Jubilee Museum -CNEN-LABPC c Laboratorio de Pocos de Caldas -CNF s Croatian Mycological Society -CNH h Canakkale Onsekiz Mart University -CNHM s Croatian Natural History Museum, Botany Department -CNHM s Cincinnati Museum of Natural History -CNHP s Beijing Natural History Museum -CNHS s Croydon Natural History and Scientific Society -CNM s Cheltenham Naturalists' Association -CNM-CM c Filamentous fungus collection of the Spanish National Center for Microbiology -CNM s Centro Nacional de Microbiologia -CNMC s Colorado National Monument -CNMS s Colombo National Museum -CNMT h Universidade Federal de Mato Grosso -CNPO h Embrapa Pecuaria Sul -CNPS s Centro Nacional de Pesquisas da Soja -CNPSo c Culture Collection of Diazotrophic and Plant Growth Promoting Bacteria of Embrapa Soja -CNR h Crimean Natural Reserve -CNRO s Centre National de Recherches Oceanographiques -CNRS s Centre National de la Recherche Scientifique -CNRZ c Centre National de Recherches Zootechniques -CNS s Australian Tropical Herbarium -CNSF h Centre National de Semences Forestieres -CNU s Capital Normal University, College of Life Sciences -CNU s Chungnam National University -CNU s Chonbuk National University -CNUK h Chungnam National University -CNWGRGL b Chinese National Waterfowl Germplasm Resources Gene Library -CO s Museum National d'Histoire Naturelle, Department of Marine Biology -COA s Herbario, Universidad de Cordoba - Jardin Botanico de Cordoba -COA s College of the Atlantic, Museum -COAD c Colecao Octavio de Almeida Drumond -COAH s Herbario Amazonico Colombiano (Instituto Amazonico de Investigaciones Cientificas SINCHI) -COCA s Comision Tecnico Consultiva de Coeficientes de Agostadero (COTECOCA) -COCAZ h Coconino National Forest Herbarium -COCH s Universidad Mayor de San Simon, Departamento de Botanica -COCO s Colorado College, Biology Department -CODAGEM s Universidad Autonoma del Estado de Mexico -CODIMAR c Centro de Investigaciones Biologicas del Noroeste -COFC s Universidad de Cordoba, Departamento de Biologia Vegetal -COI s University of Coimbra -COL s Universidad Nacional de Colombia -COLG s Columbus State University, Biology Department -COLM s Colorado National Monument -COLO s University of Colorado -COLOM s Colorado State Museum -COM s Colombo Museum -CON s Bristol, Clifton and West of England Zoological Society's Gardens -CONC s Universidad de Concepcion, Departamento de Botanica -CONN s University of Connecticut, Department of Ecology and Evolutionary Biology -CONV s Converse College, Biology Department -COP s Coleccion Ornitologica Phelps -COR s Universidade Federal de Mato Grosso do Sul, Departamento de Ciencias do Ambiente -CORB s Corchester School -CORBIDI s Centro de Ornitologia y Biodiversidad -CORD s Universidad Nacional de Cordoba, Facultad de Ciencias Exactas, Fisicas y Naturales -Coriell cb Coriell Institute for Medical Research -CORO s IUTAG, Departamento de Investigacion -CORT s State University of New York College at Cortland, Biological Sciences Department -CORU s Universidad Veracruzana, Campus Cordoba -COV s Herbert Art Gallery and Museum -COVY s Coventry and District Natural History Society -CP s Royal Veterinary and Agricultural University, Plant Biology Department -CPAC c Centro de Pesquisas Agropecuarias do Cerrado -CPAP s Centro de Pesquisas Agropecuarias do Tropico Umido -CPAP s Herbario, Centro de Pesquisas Agropecuarias do Pantanal, EMBRAPA -CPATU s Centro de Pesquisa Agroflorestal da Amazonia Oriental-Embrapa -CPB s National Institute for the Control of Pharmaceutical and Biological Products -CPC c Culture collection of Pedro Crous -CPCC c Canadian Phycological Culture Centre -CPDC s Centro de Pesquisas do Cacau -CPF s KwaZulu-Natal Nature Conservation Service -CPH s University of the Pacific, Biological Sciences Department -CPHS c WHO/FAO/OIE Collaborating Centre for Reference and Research on Leptospirosis, Western Pacific Region -CPM s Christoffel Park Museum -CPMM s Dr. Alvaro de Castro Provincial Museum -CPNP s Cuc Phuong National Park -CPPIPP c Collection of Plant Pathogens -CPPLIP s Centro de Pesquisas Paleontologias Llewellyn Ivor Price -CPRC s University of Puerto Rico, Caribbean Primate Research Center Museum -CPRR c Laboratorio de Doenca de Chagas -CPS s University of Puget Sound, Slater Museum of Natural History -CPS s Wyoming-Colorado Paleontological Society -CPSC s University of Puget Sound -CPSU s California Polytechnic State University, San Luis Obispo -CPU s China Pharmaceutical University -CPUN s Universidad Nacional de Cajamarca, Departamento de Biologia -CPUP s California Polytechnic University -CPZ c Centro Panamericano de Zoonosis -CQBG s Chongqing Botanical Garden -CQNM s Chongqing Natural History Museum -CR s Museo Nacional de Costa Rica -CRA-CIN c Consiglio per la Ricerca e sperimentazione in Agricoltura - Centro ricerche per le Colture Industriali ( Research Centre for Industrial Crops) -CRA-COLMIA c Collezione Nazionale di Microrganismi di interesse Agrario ed Industriale ed Ambientale - COL.MIA -CRA-OLI b Centro di Ricerca per l'Olivicoltura e l'Industria Olearia -CRA-PAV c Centro di Ricerca per la Patologia Vegetale -CRAF s University of Craiova, Phytopathology Department -CRAI s University of Craiova -CRBF c Collection de genomes d'organismes symbiotiques -CRBK s Cranbrook School -CRBY s Crosby Library -CRCA s Instituto dos Cereais -CRCM s Washington State University, Charles R. Conner Museum +CNCI s Canadian National Collection Insects +CNCM c Collection Nationale de Cultures de Microorganismes +CNCTC c Czech National Collection of Type Cultures +CNE s Victoria Jubilee Museum +CNEN-LABPC c Laboratorio de Pocos de Caldas +CNF s Croatian Mycological Society +CNH h Canakkale Onsekiz Mart University +CNHM s Croatian Natural History Museum, Botany Department +CNHM s Cincinnati Museum of Natural History +CNHM:ORNITH s Cincinnati Museum of Natural History, Ornithology collection +CNHP s Beijing Natural History Museum +CNHS s Croydon Natural History and Scientific Society +CNM s Cheltenham Naturalists' Association +CNM-CM c Filamentous fungus collection of the Spanish National Center for Microbiology +CNM s Centro Nacional de Microbiologia +CNMC s Colorado National Monument +CNMS s Colombo National Museum +CNMT h Universidade Federal de Mato Grosso +CNPO h Embrapa Pecuaria Sul +CNPS s Centro Nacional de Pesquisas da Soja +CNPSo c Culture Collection of Diazotrophic and Plant Growth Promoting Bacteria of Embrapa Soja +CNR h Crimean Natural Reserve +CNRO s Centre National de Recherches Oceanographiques +CNRS s Centre National de la Recherche Scientifique +CNRZ c Centre National de Recherches Zootechniques +CNS s Australian Tropical Herbarium +CNSF h Centre National de Semences Forestieres +CNU s Capital Normal University, College of Life Sciences +CNU s Chungnam National University +CNU s Chonbuk National University +CNUK h Chungnam National University +CNWGRGL b Chinese National Waterfowl Germplasm Resources Gene Library +CO s Museum National d'Histoire Naturelle, Department of Marine Biology +COA s Herbario, Universidad de Cordoba - Jardin Botanico de Cordoba +COA s College of the Atlantic, Museum +COAD c Colecao Octavio de Almeida Drumond +COAH s Herbario Amazonico Colombiano (Instituto Amazonico de Investigaciones Cientificas SINCHI) COAH +COCA s Comision Tecnico Consultiva de Coeficientes de Agostadero (COTECOCA) +COCAZ h Coconino National Forest Herbarium +COCH s Universidad Mayor de San Simon, Departamento de Botanica +COCO s Colorado College, Biology Department +CODAGEM s Universidad Autonoma del Estado de Mexico +CODIMAR c Centro de Investigaciones Biologicas del Noroeste +COFC s Universidad de Cordoba, Departamento de Biologia Vegetal +COI s University of Coimbra +COL s Universidad Nacional de Colombia +COLG s Columbus State University, Biology Department +COLM s Colorado National Monument +COLO s University of Colorado +COLOM s Colorado State Museum +COM s Colombo Museum +CON s Bristol, Clifton and West of England Zoological Society's Gardens +CONC s Universidad de Concepcion, Departamento de Botanica +CONN s University of Connecticut, Department of Ecology and Evolutionary Biology +CONV s Converse College, Biology Department +COP s Coleccion Ornitologica Phelps +COR s Universidade Federal de Mato Grosso do Sul, Departamento de Ciencias do Ambiente +CORB s Corchester School +CORBIDI s Centro de Ornitologia y Biodiversidad +CORD s Universidad Nacional de Cordoba +Coriell cb Coriell Institute for Medical Research +CORO s IUTAG, Departamento de Investigacion +CORT s State University of New York College at Cortland, Biological Sciences Department +CORU s Universidad Veracruzana, Campus Cordoba +COV s Herbert Art Gallery and Museum +COVY s Coventry and District Natural History Society +CP s Royal Veterinary and Agricultural University, Plant Biology Department +CPAC c Centro de Pesquisas Agropecuarias do Cerrado +CPAP s Centro de Pesquisas Agropecuarias do Tropico Umido +CPAP s Herbario, Centro de Pesquisas Agropecuarias do Pantanal, EMBRAPA +CPATU s Centro de Pesquisa Agroflorestal da Amazonia Oriental-Embrapa +CPB s National Institute for the Control of Pharmaceutical and Biological Products +CPC c Culture collection of Pedro Crous +CPCC c Canadian Phycological Culture Centre UTCC +CPDC s Centro de Pesquisas do Cacau +CPF s KwaZulu-Natal Nature Conservation Service +CPH s University of the Pacific, Biological Sciences Department +CPHS c WHO/FAO/OIE Collaborating Centre for Reference and Research on Leptospirosis, Western Pacific Region +CPM s Christoffel Park Museum +CPMM s Dr. Alvaro de Castro Provincial Museum +CPNP s Cuc Phuong National Park +CPPIPP c Collection of Plant Pathogens +CPPLIP s Centro de Pesquisas Paleontologias Llewellyn Ivor Price +CPRC s Caribbean Primate Research Center Museum +CPRR c Laboratorio de Doenca de Chagas +CPS s University of Puget Sound, Slater Museum of Natural History +CPS s Wyoming-Colorado Paleontological Society +CPSC s University of Puget Sound +CPSU s California Polytechnic State University, San Luis Obispo +CPU s China Pharmaceutical University +CPUN s Universidad Nacional de Cajamarca, Departamento de Biologia +CPUP s California Polytechnic University +CPZ c Centro Panamericano de Zoonosis +CQBG s Chongqing Botanical Garden +CQNM s Chongqing Natural History Museum +CR s Museo Nacional de Costa Rica +CRA-CIN c Consiglio per la Ricerca e sperimentazione in Agricoltura - Centro ricerche per le Colture Industriali ( Research Centre for Industrial Crops) +CRA-COLMIA c Collezione Nazionale di Microrganismi di interesse Agrario ed Industriale ed Ambientale - COL.MIA +CRA-OLI b Centro di Ricerca per l'Olivicoltura e l'Industria Olearia +CRA-PAV c Centro di Ricerca per la Patologia Vegetale ISPaVe +CRAF s University of Craiova, Phytopathology Department +CRAI s University of Craiova +CRBF c Collection de genomes d'organismes symbiotiques +CRBK s Cranbrook School +CRBO c Centre de Ressource Biologique Oenologique IOEB +CRBY s Crosby Library +CRC c Chlamydomonas Resource Center +CRCA s Instituto dos Cereais +CRCM s Washington State University, Charles R. Conner Museum CRCM:Bird s Washington State University, Charles R. Conner Museum, bird collection CRCM:Mammal s Washington State University, Charles R. Conner Museum, Mammal Collection -CRD s Instituto Politecnico Nacional, Coleccion Cientifica de Fauna Silvestre (Mexico) -CRE s Costa Rica Expeditions -CRE s University of Southern California -CREG s Instituto Tecnologico Agropecuario de Jalisco -CRGF c Collection de Recursos Geneticos Fungicos, Instituto de Ecologia y Systematica -CRH s Centre de Recherche en Hydrobiologie -CRI s Universidade do Extremo Sul Catarinense, Bairro Universitario -CRIFC s Central Research Institute for Field Crops in Turkey -CRK s University College, Plant Science Department -CRL c Centro de Referencia Para Lactobacilos -CRLA s Crater Lake National Park, Museum and Archives Collections -CRMC s College of the Redwoods, Mendocino Coast Campus, Biological Sciences Department -CRMM s Centre de Recherche sur les Mammiferes Marins -CRO s Wellington College -CRP s I.N.T.A., E.E.A. Bariloche -CRRHA s Centre Regional de Recherches en Hydrobiologie Appliquee -CS c CSIRO Collection of Living Micro-algae -CS s Musee des Dinosaures d'Esperaza (Aude) -CS s Colorado State University, Biology Department -CSAT s Colegio de Postgraduados, Campus Tabasco -CSAU s National Agrarian University, Southern Branch "Crimean Agrotechnological University", Department of Botany, Plant Physiology and Genetics -CSB s St. John's University/College of Saint Benedict, Biology Department -CSC s Colegio del Sagrado Corazon -CSC-CLCH c Centro Substrati Cellulari, Cell Lines Collection and Hybridomas -CSCA s California State Collection of Arthropods -CSCC c CSIRO Starter Culture Collection -CSCCE s Chadron State College, Entomology Collection -CSCCV s Chadron State College, Collection of Vertebrates -CSCN s Chadron State College -CSCS s Cebu State College of Science and Technology, Agricultural Biology Laboratory -CSCS s California State University, Turlock -CSDS s Desert Studies Center -CSFI s Central-South Forestry University -CSGP s Servicos Geologicos de Portugal -CSGT s Collegio San Giuseppe -CSH s Shanghai Chenshan Botanical Garden -CSIR c Council for Scientific and Industrial Research -CSIRO s Commonwealth Science & Industrial Research Organization +CRD s Instituto Politecnico Nacional, Coleccion Cientifica de Fauna Silvestre (Mexico) +CRE s Costa Rica Expeditions +CRE s University of Southern California +CREG s Instituto Tecnologico Agropecuario de Jalisco +CRGF c Collection de Recursos Geneticos Fungicos, Instituto de Ecologia y Systematica +CRH s Centre de Recherche en Hydrobiologie +CRI s Universidade do Extremo Sul Catarinense, Bairro Universitario +CRIFC s Central Research Institute for Field Crops in Turkey +CRK s University College, Plant Science Department +CRL c Centro de Referencia Para Lactobacilos +CRLA s Crater Lake National Park, Museum and Archives Collections +CRMC s College of the Redwoods, Mendocino Coast Campus, Biological Sciences Department +CRMM s Centre de Recherche sur les Mammiferes Marins +CRO s Wellington College +CRP s I.N.T.A., E.E.A. Bariloche +CRRHA s Centre Regional de Recherches en Hydrobiologie Appliquee +CS c CSIRO Collection of Living Micro-algae +CS s Musee des Dinosaures d'Esperaza (Aude) +CS s Colorado State University, Biology Department +CSAT s Colegio de Postgraduados, Campus Tabasco +CSAU s National Agrarian University, Southern Branch "Crimean Agrotechnological University", Department of Botany, Plant Physiology and Genetics +CSB s St. John's University/College of Saint Benedict, Biology Department +CSC s Colegio del Sagrado Corazon +CSC-CLCH c Centro Substrati Cellulari, Cell Lines Collection and Hybridomas +CSCA s California State Collection of Arthropods +CSCC c CSIRO Starter Culture Collection +CSCCE s Chadron State College, Entomology Collection CSCC +CSCCV s Chadron State College, Collection of Vertebrates +CSCN s Chadron State College +CSCS s Cebu State College of Science and Technology, Agricultural Biology Laboratory +CSCS s California State University, Turlock +CSDS s Desert Studies Center +CSFI s Central-South Forestry University +CSGP s Servicos Geologicos de Portugal +CSGT s Collegio San Giuseppe +CSH s Shanghai Chenshan Botanical Garden +CSIR c Council for Scientific and Industrial Research +CSIRO s Commonwealth Science & Industrial Research Organization CSIRO:Ichthyology s Commonwealth Science & Industrial Research Organization, Australian National Fish Collection -CSLA s California State University, Department of Biological Sciences -CSLB s California State University at Long Beach -CSMA c Centro di Studio dei Microorganismi Autotrofi - CNR -CSPM s Colegio Lasalle Palma de Mallorca -CSPU s California State Polytechnic University, Biological Sciences Department -CSPUP s California State Polytechnic University, Pomona -CSR s Caucasus State Nature Biosphere Reserve -CSTIU s Faculty of Science, University of Tokyo -CSU s Colorado State University -CSU s University of Central Oklahoma, Biology Department -CSUC s California State University, Chico, Vertebrate Museum -CSUCI h California State University Channel Islands -CSUF s California State University, Fresno -CSUH h Chelyabinsk State University -CSULB s California State University, Long Beach -CSUN s California State University, Northridge -CSUNIV h Charleston Southern University -CSUR c Collection de Souches de l'Unite des Rickettsies -CSUSB h California State University, San Bernardino -CSUTC s Colorado State University, Mammalogy Teaching Collection -CSVFC s Caradoc and Severn Valley Field Club -CT s University of Cape Town, Botany Department -CTC h Chongqing Normal University -CTES s Instituto de Botanica del Nordeste -CTESN s Universidad Nacional del Nordeste -CTM c Centre de Biotechnologie de Sfax culture collection -CTN s Free Library and Museum -CTNRC s Thai National Reference Collections -CTS s Chongqing Teachers College -CTY s Canterbury Literary and Philosophical Institution -CU sb Cornell University -CUAC s Clemson University -CUBK s Department of Biology, Chonbuk National University -CUC c Cepario de la Universidad de Concepcion de Chile -CUE s Cairo University -CUETM c Collection Unite Ecotoxicologie Microbienne, INSERM -CUFH s Cumhuriyet University, Biology Department -CUG s Collection Universite Poitiers -CUH s Calcutta University, Botany Department -CUHK sc Biology Department, Chinese University of Hong Kong -CUI s Central College, Iowa -CUIC s Cornell University, Invertebrate Collections -CUMV s Cornell University Museum of Vertebrates +CSJ s Colegio de San Jose, Museo de Historia Natural, Medellin +CSLA s California State University, Department of Biological Sciences +CSLB s California State University at Long Beach +CSMA c Centro di Studio dei Microorganismi Autotrofi - CNR +CSPM s Colegio Lasalle Palma de Mallorca +CSPU s California State Polytechnic University, Biological Sciences Department +CSPUP s California State Polytechnic University, Pomona +CSR s Caucasus State Nature Biosphere Reserve +CSTIU s Faculty of Science, University of Tokyo +CSU s Colorado State University CSUC +CSU s University of Central Oklahoma, Biology Department +CSUC s California State University, Chico, Vertebrate Museum +CSUCI h California State University Channel Islands +CSUF s California State University, Fresno +CSUH h Chelyabinsk State University +CSULB s California State University, Long Beach +CSUN s California State University, Northridge +CSUNIV h Charleston Southern University +CSUR c Collection de Souches de l'Unite des Rickettsies +CSUSB h California State University, San Bernardino +CSUTC s Colorado State University, Mammalogy Teaching Collection +CSVFC s Caradoc and Severn Valley Field Club +CT s University of Cape Town, Botany Department +CTC h Chongqing Normal University +CTES s Instituto de Botanica del Nordeste +CTESN s Universidad Nacional del Nordeste +CTM c Centre de Biotechnologie de Sfax culture collection +CTN s Free Library and Museum +CTNRC s Thai National Reference Collections +CTR s Charles T. Ramsden historical collection +CTS s Chongqing Teachers College +CTY s Canterbury Literary and Philosophical Institution +CU sb Cornell University +CUAC s Clemson University +CUBK s Department of Biology, Chonbuk National University +CUC c Cepario de la Universidad de Concepcion de Chile +CUE s Cairo University +CUETM c Collection Unite Ecotoxicologie Microbienne, INSERM +CUFH s Cumhuriyet University, Biology Department +CUG s Collection Universite Poitiers +CUH s Calcutta University, Botany Department +CUHK sc Biology Department, Chinese University of Hong Kong +CUI s Central College, Iowa +CUIC s Cornell University, Invertebrate Collections +CUMV s Cornell University Museum of Vertebrates CUVC CUMV:Amph s Cornell University Museum of Vertebrates, Amphibian Collection CUMV:Bird s Cornell University Museum of Vertebrates, Bird Collection CUMV:Fish s Cornell University Museum of Vertebrates, Fish Collection CUMV:Mamm s Cornell University Museum of Vertebrates, Mammal Collection CUMV:Rept s Cornell University Museum of Vertebrates, Reptile Collection -CUMZ s Carleton University, Museum of Zoology -CUMZ s Cameroon University, Museum of Zoology -CUMZ s Chulalongkorn University Museum of Natural History +CUMZ s Carleton University, Museum of Zoology +CUMZ s Cameroon University, Museum of Zoology +CUMZ s Chulalongkorn University Museum of Natural History CUB CUMZ:R s Chulalongkorn University Museum of Natural History, Reptile Collection -CUMZ s Cambridge University, Museum of Zoology -CUNRC s Universidad Nacional de Rio Cuarto, Coleccion de Mamiferos (Argentina) -CUP s Cornell University, Plant Pathology Herbarium -CUP s Catholic University of Peking -CUP s Charles University -CURLA h Centro Universitario Regional del Litoral Atlantico -CUS s Cusino Wildlife Research Station, Natural Resources Department -CUSC s Clemson University, Vertebrate Collections -CUVC s Universidad del Valle, Departamento de Biologia -CUW s Clark University, Biology Department -CUWM s Clark University -CUZ s Universidad Nacional San Antonio Abad del Cusco -CV s Municipal Museum of Chungking -CVCC c Center for Veterinary Culture Collection -CVCC c China Veterinary Culture Collection -CVCM c Centro Venezolano de Colecciones de Microorganismos -CVCW s Clinch Valley College, University of Virginia, Biology Department -CVM s City Museum, Natural History Department -CVRD s Reserva Natural da Vale do Rio Doce -CVUL s Universite Laval, Collection de Vertebres -CVULA s Coleccion Vertebrados, Facultad de Ciencias, La Hechicera, Universidad de los Andes -CWB s Kharkov State University -CWC s Central Wyoming College -CWDR s Cawdor Castle -CWU s V. N. Karasin National University -CY c Centre des Yersinia -CYN s Chipstead Valley Primary School -CYP s Ministry of Agriculture, Natural Resources and Environment, Forestry Department -CZAA s Catedra de Zoologia Agricola -CZACC s Coleccion Zoologia, Academia de Ciencias de Cuba -CZH h Hanshan Normal University -CZIP s Universidad de Magallanes, Instituto de la Patagonia (Chile) -CZL s Centro de Zoologia -CZRMA s Coleccion Zoologica Regional (Mammalia) del Instituto de Historia Natural y Ecologia -CZUAA s Universidad Autonoma de Aguascalientes (Mexico) -CZUG s Universidad de Guadalajara,Centro de Estudios en Zoologia, Entomologia -DABUH s University of Helsinki, Department of Applied Biology -DABZ s Department of Agriculture, Zimbabwe -DACB s Bangladesh National Herbarium -DACL s London Research Centre -DACT c Dept. Agricult. Chem. Technol. -DAFH s Department of Agriculture and Fisheries -DAG h Mountain Botanical Garden of the Dagestan Scientific Centre -DAKAR s Universite Cheikh Anta Diop, Departement de Biologie Vegetale -DAL s Dalhousie University, Biology Department -DANV s Umweltamt Darmstadt -DAO s Agriculture and Agri-Food Canada -DAOM sc National Mycological Herbarium, Agriculture and Agri-Food Canada -DAR c Plant Pathology Herbarium -DARI s Insect Collection, New South Wales Department of Agriculture -DAS s Agriculture and Agri-Food Canada -DASF s Department of Agriculture, Stock and Fisheries -DAU h University of Daugavpils -DAV s University of California, Plant Biology -DAVFP s Pacific Forestry Centre, Canadian Forest Service -DAVH s University of California, Environmental Horticulture Department -DAWES h The Dawes Arboretum -DBAI s Instituto de Ciencias Biologicas -DBAU s Universidade Santa Ursula -DBC s University College, Botany Department -DBCUCH s Universidad de Chile, Departamento de Biologia Celular y Genetica -DBFFEUCS s Departamento de Biologia de la Faculdad de Filosofia y Educacion de la Universidad de Chile -DBG s Denver Botanic Gardens -DBKKU1 c Department of Biology, Faculty of Science -DBKKU2 c Department of Biology, Faculty of Science -DBKKU3 c Department of Biology, Faculty of Science -DBM c Department of Biochemistry and Microbiology -DBMU c Boonchird lab, Department of Biotechnology, Mahidol University -DBMU2 c Panbangred lab, Department of Biotechnology, Mahidol University -DBN s National Botanic Gardens -DBS c Department of Biological Culture Collection -DBSE s Universidade Federale Sergipe -DBSNU s Department of Biology, Shaanxi Normal University -DBUA c Zoological Collection of the Biology Department, University of the Azores -DBUM-IPT c Department of Biochemistry, Faculty of Medicine, University of Malaya -DBUP c Algal Culture Collection -DBV c Division of Standardisation -DBVPG c Industrial Yeasts Collection -DBY s City of Derby Museum and Art Gallery -DCBU s Universidade Federal de Sao Carlos -DCCBC cb Dunaliella Culture Collection at Brooklyn College -DCDS s Dipartimento di Coltivazione e Difesa delle Specie Legnose dell'Universita, Sezione Entomologia Agraria -DCH s Davidson College, Biology Department -DCMB s Universidade do Amazonas -DCMD s Derby City Museum and Art Gallery -DCMP s Universidade Federal do Parana -DCN-UNRC s Departamento de Ciencias Naturales, Universidad Nacional de Rio Cuarto -DCPC s DominicusCirillus[deceased] -DCR s Doncaster Museum and Art Gallery -DD s Forest Research Institute, Indian Council of Forestry Research and Education, Systematic Botany Discipline -DDFF s Departamento de Defensa Fitossanitarista -DDMS h Fundacao Universidade Federal da Grande Dourados -DE s Debrecen University, Botany Department -DE-CSIRO c CSIRO Insect Pathogen Culture Collection -DEBU s Ontario Insect Collection, University of Guelph -DECA s Agnes Scott College, Biology Department -DECV s Douglas Ecological Consultants -DEE s McManus Galleries, Natural History Department -DEES s Universidade de Sao Paulo, Piracicaba -DEFS s Universidade de Sao Paulo -DEI s Senckenberg Deutsches Entomologisches Institut -DEIB s Deutsches Entomologisches Institut -DEK s Northern Illinois University, Biological Sciences Department -DELS s University of Delaware, Plant Science Department -DELTA s Delta Waterfowl and Wetlands Research Station -DEN s Denison University, Biology Department -DENA s Watt Institute -DENF s Grand Mesa-Uncompahgre-Gunnison Natonal Forests -DENH s University of New Hampshire -DERM s Intermountain Experiment Station -DES sb Desert Botanical Garden, Research Department -DEV h St. Joseph's College -DEVA s Death Valley National Park -DEWV s Davis and Elkins College, Biology and Environmental Science Department -DEZA s Dipartimento di Entomologia e Zoologia Agraria dell'Universita -DEZC s Dipartimento di Entomologia e Zoologia Applicate all'Ambiente "Carlo Vidano" -DFCZ s Forest Research Institute, Malawi -DFD s Dartford Borough Museum -DFEC s Desert Forestry Experimental Centre -DFEC s Department of Forestry and Environmental Science, State University of New York -DFF c Forest Pathology Culture Collection, Pacific Forest Research Centre -DFLC s Escola Superior de Agricultura -DFP c DFP Culture Collection -DFRU s University of New Brunswick -DFS s Dumfries and Galloway Natural History and Antiquarian Society -DFSM s Dumfries Museum -DFV s Division of Fisheres -DGBU s Department of Geology, Pusan National University -DGN s Darlington Museum -DGR b Division of Genomic Resources, University of New Mexico +CUMZ s Cambridge University, Museum of Zoology +CUNRC s Universidad Nacional de Rio Cuarto, Coleccion de Mamiferos (Argentina) +CUP s Cornell University, Plant Pathology Herbarium +CUP s Catholic University of Peking +CUP s Charles University +CURLA h Centro Universitario Regional del Litoral Atlantico +CUS s Cusino Wildlife Research Station, Natural Resources Department +CUSC s Clemson University, Vertebrate Collections +CUVC s Universidad del Valle, Departamento de Biologia +CUW s Clark University, Biology Department +CUWM s Clark University +CUZ s Universidad Nacional San Antonio Abad del Cusco +CV s Municipal Museum of Chungking +CVCC c Center for Veterinary Culture Collection +CVCC c China Veterinary Culture Collection +CVCM c Centro Venezolano de Colecciones de Microorganismos +CVCW s Clinch Valley College, University of Virginia, Biology Department +CVM s City Museum, Natural History Department +CVRD s Reserva Natural da Vale do Rio Doce +CVUL s Universite Laval, Collection de Vertebres +CVULA s Coleccion Vertebrados, Facultad de Ciencias, La Hechicera, Universidad de los Andes +CWB s Kharkov State University +CWC s Central Wyoming College +CWDR s Cawdor Castle +CWU s V. N. Karasin National University +CY c Centre des Yersinia +CYN s Chipstead Valley Primary School +CYP s Ministry of Agriculture, Natural Resources and Environment, Forestry Department +CZ-IICT s Centro de Zoologia, Instituto de Investigacao Cientifica Tropical +CZAA s Catedra de Zoologia Agricola +CZACC s Coleccion Zoologia, Academia de Ciencias de Cuba +CZCEN s Coleccion Zoologica de la Facultad de Ciencias Exactas y Naturales +CZH h Hanshan Normal University +CZIP s Universidad de Magallanes, Instituto de la Patagonia (Chile) +CZL s Centro de Zoologia +CZRMA s Coleccion Zoologica Regional (Mammalia) del Instituto de Historia Natural y Ecologia +CZUAA s Universidad Autonoma de Aguascalientes (Mexico) +CZUG s Universidad de Guadalajara,Centro de Estudios en Zoologia, Entomologia +DABUH s University of Helsinki, Department of Applied Biology +DABZ s Department of Agriculture, Zimbabwe +DACB s Bangladesh National Herbarium +DACL s London Research Centre +DACT c Dept. Agricult. Chem. Technol. +DAFH s Department of Agriculture and Fisheries +DAG h Mountain Botanical Garden of the Dagestan Scientific Centre +DAKAR s Universite Cheikh Anta Diop, Departement de Biologie Vegetale +DAL s Dalhousie University, Biology Department +DANV s Umweltamt Darmstadt +DAO s Agriculture and Agri-Food Canada +DAOM sc National Mycological Herbarium, Agriculture and Agri-Food Canada CCFC,DAOMC +DAR c Plant Pathology Herbarium +DARI s Insect Collection, New South Wales Department of Agriculture +DAS s Agriculture and Agri-Food Canada +DASF s Department of Agriculture, Stock and Fisheries +DAU h University of Daugavpils +DAV s University of California, Plant Biology +DAVFP s Pacific Forestry Centre, Canadian Forest Service +DAVH s University of California, Environmental Horticulture Department +DAWES h The Dawes Arboretum +DBAI s Instituto de Ciencias Biologicas +DBAU s Universidade Santa Ursula +DBC s University College, Botany Department +DBCUCH s Universidad de Chile, Departamento de Biologia Celular y Genetica +DBFFEUCS s Departamento de Biologia de la Faculdad de Filosofia y Educacion de la Universidad de Chile +DBG s Sam Mitchel Herbarium of Fungi, Denver Botanic Gardens +DBKKU1 c Department of Biology, Faculty of Science +DBKKU2 c Department of Biology, Faculty of Science +DBKKU3 c Department of Biology, Faculty of Science +DBM c Department of Biochemistry and Microbiology +DBMU c Boonchird lab, Department of Biotechnology, Mahidol University +DBMU2 c Panbangred lab, Department of Biotechnology, Mahidol University +DBN s National Botanic Gardens +DBS c Department of Biological Culture Collection +DBSE s Universidade Federale Sergipe +DBSNU s Department of Biology, Shaanxi Normal University +DBUA c Zoological Collection of the Biology Department, University of the Azores +DBUM-IPT c Department of Biochemistry, Faculty of Medicine, University of Malaya +DBUP c Algal Culture Collection +DBV c Division of Standardisation +DBVPG c Industrial Yeasts Collection +DBY s City of Derby Museum and Art Gallery +DCBU s Universidade Federal de Sao Carlos +DCCBC cb Dunaliella Culture Collection at Brooklyn College +DCDS s Dipartimento di Coltivazione e Difesa delle Specie Legnose dell'Universita, Sezione Entomologia Agraria +DCH s Davidson College, Biology Department +DCMB s Universidade do Amazonas +DCMD s Derby City Museum and Art Gallery +DCMP s Universidade Federal do Parana +DCN-UNRC s Departamento de Ciencias Naturales, Universidad Nacional de Rio Cuarto +DCPC s DominicusCirillus[deceased] +DCR s Doncaster Museum and Art Gallery +DD s Forest Research Institute, Indian Council of Forestry Research and Education, Systematic Botany Discipline +DDFF s Departamento de Defensa Fitossanitarista +DDMS h Fundacao Universidade Federal da Grande Dourados +DE s Debrecen University, Botany Department +DE-CSIRO c CSIRO Insect Pathogen Culture Collection +DEBU s Ontario Insect Collection, University of Guelph UOG:DEBU +DECA s Agnes Scott College, Biology Department +DECV s Douglas Ecological Consultants +DEE s McManus Galleries, Natural History Department +DEES s Universidade de Sao Paulo, Piracicaba +DEFS s Universidade de Sao Paulo +DEI s Senckenberg Deutsches Entomologisches Institut +DEIB s Deutsches Entomologisches Institut +DEK s Northern Illinois University, Biological Sciences Department +DELS s University of Delaware, Plant Science Department +DELTA s Delta Waterfowl and Wetlands Research Station +DEN s Denison University, Biology Department +DENA s Watt Institute +DENF s Grand Mesa-Uncompahgre-Gunnison Natonal Forests +DENH s University of New Hampshire +DERM s Intermountain Experiment Station +DES sb Desert Botanical Garden, Research Department +DEV h St. Joseph's College +DEVA s Death Valley National Park +DEWV s Davis and Elkins College, Biology and Environmental Science Department +DEZA s Dipartimento di Entomologia e Zoologia Agraria dell'Universita +DEZC s Dipartimento di Entomologia e Zoologia Applicate all'Ambiente "Carlo Vidano" +DFCZ s Forest Research Institute, Malawi +DFD s Dartford Borough Museum +DFEC s Desert Forestry Experimental Centre +DFEC s Department of Forestry and Environmental Science, State University of New York +DFF c Forest Pathology Culture Collection, Pacific Forest Research Centre +DFLC s Escola Superior de Agricultura +DFP c DFP Culture Collection +DFRU s University of New Brunswick +DFS s Dumfries and Galloway Natural History and Antiquarian Society +DFSM s Dumfries Museum +DFV s Division of Fisheres +DGBU s Department of Geology, Pusan National University +DGN s Darlington Museum +DGR b Division of Genomic Resources, University of New Mexico DGR:Bird s Division of Genomic Resources, University of New Mexico, bird tissue collection DGR:Ento s Division of Genomic Resources, University of New Mexico, entomology tissue collection DGR:Fish s Division of Genomic Resources, University of New Mexico, fish tissue collection DGR:Herp s Division of Genomic Resources, University of New Mexico, herpetology tissue collection DGR:Mamm s Division of Genomic Resources, University of New Mexico, mammal tissue collection -DGS s The Manx Museum -DGU h Daegu University -DGUB c Department of Genetics, University of Bratislava -DH s Hobart and William Smith Colleges, Biology Department -DHISUB s Department of Hydrobiology and Ichthyology, Sofia Univiversity -DHL s University of Louisville, Biology Department -DHM s University of Durham, Botany Department -DHMB s Department of Harbours and Marine -DHNS s Dunbartonshire Natural History Society -DI s Universite de Bourgogne, Laboratoire de Phytobiologie Cellulaire -DIA s Museu do Dundo -DIAM h Universidade Federal dos Vales do Jequitinhonha e Mucuri -DIN s Museum National d'Histoire Naturelle -DINH s Delta Institute of Natural History -DINO s Dinosaur National Monument -DIS s Dinamation International Society -DISCA s Estacion Biologica de Rancho Grande, Ministerio del Ambiente y Recursos Naturales Renovables -DISKO s Danish Arctic Station -DiSTA s Phytoplasma Collection University of Bologn -DIX s Dixie College, Natural History Museum -DKG s Juniper Hall Field Centre -DLF s Stetson University, Biology Department -DLU h Da Lat University -DLY s Dudley and Midland Geological and Scientific Society and Field Club -DM s Dominion Museum -DM s The Dinosaur Museum -DMB s Durban Museum -DMBC s Dominick Moth and Butterfly Collection -DMBUK c Department of Microbiology, Univeristy of Kelaniya -DMCCUS c School of Biological Sciences Culture Collection -DMCMU2 c Department of Microbiology, Faculty of Medicine -DMCU c Microbiology Department, Faculty of Science -DMDC s Douala Museum -DMFS s Crichton Royal Institution Museum -DMHN h The University of Newcastle -DMIV c Department of Microbiology and Immunology -DMKKU1 c Department of Microbiology, Faculty of Medicine -DMKKU2 c Department of Microbiology, Faculty of Medical Science -DMKU c Department of Microbiology Kasetsart University -DMMU1 c Department of Microbiology, Faculty of Science -DMMU3 c Department of Microbiology, Faculty of Medicine Siriraj Hospital -DMMZ c Department of Medical Microbiology, University of Zurich -DMNH s Delaware Museum of Natural History -DMNH s Dayton Museum of Natural History, Biology Department -DMNS s Denver Museum of Nature and Science +DGS s The Manx Museum +DGU h Daegu University +DGUB c Department of Genetics, University of Bratislava +DH s Hobart and William Smith Colleges, Biology Department +DHISUB s Department of Hydrobiology and Ichthyology, Sofia Univiversity +DHL s University of Louisville, Biology Department +DHM s University of Durham, Botany Department +DHMB s Department of Harbours and Marine +DHNS s Dunbartonshire Natural History Society +DI s Universite de Bourgogne, Laboratoire de Phytobiologie Cellulaire +DIA s Museu do Dundo +DIAM h Universidade Federal dos Vales do Jequitinhonha e Mucuri +DIN s Museum National d'Histoire Naturelle +DINH s Delta Institute of Natural History +DINO s Dinosaur National Monument +DIS s Dinamation International Society +DISCA s Estacion Biologica de Rancho Grande, Ministerio del Ambiente y Recursos Naturales Renovables +DISKO s Danish Arctic Station +DiSTA s Phytoplasma Collection University of Bologna DiSTA +DIX s Dixie College, Natural History Museum +DKG s Juniper Hall Field Centre +DLF s Stetson University, Biology Department +DLU h Da Lat University +DLY s Dudley and Midland Geological and Scientific Society and Field Club +DM s Dominion Museum +DM s The Dinosaur Museum +DMB s Durban Museum +DMBC s Dominick Moth and Butterfly Collection +DMBUK c Department of Microbiology, Univeristy of Kelaniya +DMCCUS c School of Biological Sciences Culture Collection +DMCMU2 c Department of Microbiology, Faculty of Medicine +DMCU c Microbiology Department, Faculty of Science +DMDC s Douala Museum +DMFS s Crichton Royal Institution Museum +DMHN h The University of Newcastle +DMIV c Department of Microbiology and Immunology +DMKKU1 c Department of Microbiology, Faculty of Medicine +DMKKU2 c Department of Microbiology, Faculty of Medical Science +DMKU c Department of Microbiology Kasetsart University +DMMU1 c Department of Microbiology, Faculty of Science +DMMU3 c Department of Microbiology, Faculty of Medicine Siriraj Hospital +DMMZ c Department of Medical Microbiology, University of Zurich +DMNH s Delaware Museum of Natural History +DMNH s Dayton Museum of Natural History, Biology Department +DMNS s Denver Museum of Nature and Science DMNH,DNHC DMNS:Bird s Denver Museum of Nature and Science, Ornithology Collections DMNS:Mamm s Denver Museum of Nature and Science, Mammology Collection -DMPMC c Department of Microbiology, University of Western Australia -DMSA s Durban Museum -DMSC s Medicinal Plants Research Institute, Department of Medical Sciences -DMSP s Davis Mountains State Park -DMSRDE c DMSRDE Culture Collection -DMST c Culture Collection for Medical Microorganism, Department of Medical Sciences -DMTH s Britannia Royal Naval College -DMU s Mithila University, Botany Department -DMUIJ c Department of Microbiology, Jakarta Pusat -DMUP c Microbiology and Biophysics Charles University -DMUR c Department of Mycology -DMVB c Department of Microbiology, Veterinary Branch of National Strain Collection -DNA s Department of Natural Resources, Environment and the Arts -DNAP h Department of Primary Industry and Fisheries -DNATAX b DNA-TAX -DNHM s Dalian Museum of Natural History -DNHM s Dinosaur Natural History Museum -DNPM s Setor de Paleontologia do Departamento Nacional de Producao Mineral -DNS s Dundee Naturalists' Society -DNZ h Donetsk Botanical Garden of the National Academy of Sciences of Ukraine -DO s Societe d'Agriculture Sciences et Arts -DOA c Department Of Agriculture, Thailand -DOMO s Collegio Mellerio Rosmini -DOR s Dorset County Museum -DORC s Dorset County Museum -DORCM s Dorset Royal County Museum -DORT s Botanischer Garten Rombergpark, Stadt Dortmund -DOV s Delaware State University, Department of Agriculture and Natural Resources -DPBA s Departamento de Patologia Vegetal -DPC c Dairy Products Research Center Culture Collection Teagasc -DPIC s Belo Horizonte, Instituto de Ciencias Biologicas -DPIH s Department of Primary Industry (formerly DAHT) -DPIQM s Department of Primary Industries -DPIWE-FHU c Fish Disease Culture Collection -DPMWA s Dorthy Page Museum of Wasilla -DPNC s Denison Pequotsepos Nature Center -DPPC s Department of Agriculture, Taiwan -DPU s DePauw University, Botany and Bacteriology Department -DPUA c Departamento de Patologia/ICB -DPUP s Universidade Federal de Maringa -DQTC s Daqing Teachers College, Biology Department -DR s Technische Universitaet Dresden -DS s California Academy of Sciences, Botany Department -DSC s Delta State University, Biological Sciences Department -DSC c Dicty Stock Center -DSEC s Universidade Federal da Paraiba -DSIR s Department of Scientific and Industrial Research -DSM c Deutsche Sammlung von Mikroorganismen und Zellkulturen GmbH -DSM s University of Dar es Salaam, Botany Department -DSMZ c Deutsche Sammlung von Mikroorganismen und Zellkulture -DSP s Fitzsimon's Snake Park -DSSC b Drosophila Species Stock Center -DSU s Dnipropetrovsk National University, Department of Geobotany, Soil, and Ecology -DSY s Dewsbury Museum -DTE h Centro de Investigaciones Cientificas y Transferencia de Tecnologia a la Produccion (CICyTTP-CONICET) -DTIC s Departamento Parasitologia -DTN s Darlington and Teesdale Naturalists' Field Club -DU s Duke University Vertebrate Collection -DUB s National Botanic Gardens -DUBN s Dublin Naturalists' Field Club -DUE s University of Dundee -DUF s University of Dicle, Biological Department, Botany -DUGAND h Universidad del Atlantico -DUH s University of Delhi, Botany Department -DUIS s Universitaet Duisburg, Fachbereich 6, Botanik -DUKE s Duke University, Biology Department -DUL s University of Minnesota, Biology Department -DUM c Delhi University Mycological Herbarium -DUM s Zooligical Museum of Science and Art Faculty -DUOF h Duzce University -DUP h Dumlupinar University -DUR s Southeastern Oklahoma State University, Biological Sciences Department -DUSS s Universitaet Duesseldorf -DVBID c Division Vector-Borne Infectious Diseases -DVCC s Diablo Valley College -DVCM s Diablo Valley College Museum -DVM s Diablo Valley College, Biology Department -DVNM s Death Valley National Monument -DVR s Dover Corporation Museum -DVZUT s Department of Vertebrate Zoology -DWC s West Chester University, Biology Department -DWN s Darwen Library -DWP h Disney Wilderness Preserve/The Nature Conservancy -DWT c Wood Technology and Forest Research Division -DWU s Dakota Wesleyan University, Biology Department -DZCU s Calcutta University -DZIB s Universidade Estadual de Campinas -DZKU s Department of Biology, Shaanxi Normal University -DZMU s Department of Zoology, Monash University -DZS s Devizes Museum -DZSASP s Departamento de Zoologia, Secretaria da Agricultura -DZUC s Departamento de Zoologia da Universidade de Coimbra -DZUFRGS s Departamento de Zoologia da Universidade Federal do Rio Grande do Sul -DZUH s Departamento de Zoologia, Universidad de Havana -DZUL s Departamento de Zoologia, Universidad de La Laguna -DZUP s Universidade Federal do Parana, Museu de Entomologia Pe. Jesus Santiago Moure -DZVMLP s Departamento Cientifico de Zoologia de Vertebrados -DZVU s Universidad de Uruguay -E sb Royal Botanic Garden Edinburgh -EA s National Museums of Kenya -EAA s Estonian Agricultural University -EAC s Universidade Federal do Ceara, Departamento de Biologia -EAFM h Instituto Federal de Educacao, Ciencia e Tecnologia do Amazonas -EALA h Jardin Botanique d'Eala -EAN s Universidade Federal da Paraiba, Campus III - CCA, Departamento de Fitotecnia -EAP s Escuela Agricola Panamericana -EAPZ s Escuela Agricola Panamericana -EAR s Earlham College, Biology Department -EATRO c Uganda Trypanosomiasis Research Organization -EBA s Edinburgh Academy Field Centre -EBCC s Universidad Nacional Autonoma de Mexico, Estacion de Biologia "Chamela" -EBD s Estacion Biologica de Donana -EBDS s Estacion Biologica de Donana -EBE s Eastbourne Museum -EBF s Hubei Forestry Institute -EBH s Botanical Society of Edinburgh -EBL h Ecosystem Research and Development Bureau -EBMC s Universidad de Chile -EBMTV s Estacion de Biologia Marina del Instituto Tecnologico de Veracruz -EBNHS s Edinburgh Natural History Society -EBRG s Museo de la Estacion Biologia de Rancho Grande -EBUAP s Laboratorio de Herpetologia, Escuela de Biologia, Benemerita Universidad Autonoma de Puebla -EBUM s Universidad Michoacana de San Nicolas de Hidalgo -EBV s Laboratoire de Biologie Generale et de Botanique -ECACC c European Collection of Authenticated Cell Cultures -ECENT s East Central University -ECH s Elmira College -ECK h Buffalo State College -ECM s Hubei College of Traditional Chinese Medicine, Department of Chinese Materia Medica -ECNB s Escuela Nacional Ciencias -ECO-SC-M s Coleccion Mastozoologica de El Colegio de la Frontera Sur Unidad San Cristobal de las Casas, Chiapas -ECOCHM s Coleccion de Mamiferos del Museo de Zoologia-ECOSUR -ECOL s Collection du Laborataire d'Ecologie -ECOMAR s ECOMAR lab University of Reunion -ECON s Harvard University -ECOSCM s Coleccion Mastozoologica de El Colegio de la Frontera Sur, Unidad San Cristobal -ECOSUR s El Colegio de la Frontera Sur (Mexico) -ECSC s East Central University, Biology Department -ECSFI s East China Sea Fisheries Institute -ECU h Edith Cowan University -ECUAMZ h Universidad Estatal Amazonica -ECUH h East Carolina University -ECWP h Emirates Centre for Wildlife Propagation -EDC s Hubei Institute for Drug Control -EDH s Plinian Society -EDNC s Raleigh, North Carolina Department of Agriculture -EDTU h Trakya Universitesi -EEBP s Estacao Experimental de Biologia e Piscicultura de Pirassununga -EELM s Estacion Experimental Agricola de la Molina -EERU s Economic Entomology Research Unit -EFC s Escola de Florestas -EFCC s Epping Forest Conservation Centre -EFH s Forestry Commission -EFM s Epping Forest Museum, Corporation of London -EFWM s Department of Entomology -EGE s Ege University -EGE-MACC c Ege - Microalgae Culture Collection -EGH s University of Edinburgh -EGHB s University of Edinburgh -EGHF s University of Edinburgh, Forestry and Natural Resources Department -EGNP s Homestead, Everglades National Park -EGR s Eszterhazy Karoly College, Botany Department -EHCV s Emory and Henry College, Biology Department -EHH s Universite d'Etat d'Haiti -EI s Universidade Federal Rural do Rio de Janeiro -EIF s Universidad de Chile, Departamento de Silvicultura -EIHU s Entomological Institute, Hokkaido University -EINS s Ecuadorian Institute of Natural Sciences -EISC s Shaanxi Agricultural University, Entomological Institute -EIU s Eastern Illinois University, Biological Sciences Department -EJ s ?Ein Yabrud collection catalogue entries at The Hebrew University -EKU s Eastern Kentucky University -EKY s Eastern Kentucky University, Biological Sciences Department -ELCAK s Entomological Laboratory, College of Agriculture -ELH h Bureau of Land Management, Eagle Lake Field Office -ELM s East London Museum -ELMF s Augusta, Maine Forest Service -ELN s Elgin Museum -ELRG s Central Washington University, Biological Sciences Department -ELS s Aldenham School, Biology Department -ELVE s National Station for Plant Breeding -EM s Universidade Federal de Ouro Preto -EMA s Sichuan School of Chinese Materia Medica -EMAG s Ernst-Moritz Arndt Collection, Museum der Stadt Greifswald -EMAU s Ernst-Moritz-Arndt-Universitat Greifswald -EMBT s Department of Agriculture, Thailand -EMC s Eastern Michigan University, Biology Department -EMCC c Egypt Microbial Culture Collection -EMEC s Essig Museum of Entomology -EMET s Faculty of Agriculture, Entomology Museum -EMMA s Universidad Politecnica de Madrid, Unidad Docente Botanica, Departamento Silvopascicultura -EMNH h The Everhart Museum of Natural History, Science & Art -EMPARN c Empresa de Pesquisa Agropecuaria do Rio Grande do Norte -EMU s Eastern Michigan University, T. L. Hankinson Vertebrate Museum -EMUS s Utah State University -ENAG s Universidad Nacional Agraria, Departamento de Ciencias Basicas -ENCB-IPN c Coleccion de cultivos de la Escuela Nacional de Ciencias Biologicas -ENCB s Universidad de Autonoma de Baja California -ENCB s Instituto Politecnico Nacional -ENG s Royal Holloway College, University of London, Botany Department -ENIH s National Institute of Health -ENLC h Eastern Nevada Landscape Coalition -ENMU s Eastern New Mexico University, Natural History Museum -ENMUNHM s Eastern New Mexico University, Natural History Museum -ENP s Everglades National Park -ENS s Hubei College for Nationalities, Forestry Department -ENSJ s Escuela Normal Superior de Jalisco -ENT s Herbarium, Ministry of Natural Resources, Uganda -ENTOMOFOR s Collection of necrophagous Fauna of the Forensic Entomology Laboratory (Basque Country University) -EONJ s Upsala College, Biology Department -EOSC s Eastern Oregon University, Biology Department -EOSCVM s Eastern Oregon State College, Vertebrate Museum -EOSTS s Official Seed Testing Station, Agricultural Scientific Services, Department of Agriculture and Fisheries for Scotland -EPAL s Entomology Collection, Punjab Agricultural University -EPHR s Snow College, Biology Department -EPM s Epsom College Museum -EPN s Escuela Polytecnica Nacional -EPRL s University of Puerto Rico -EPU h Centre de Formation et de Recherche en Conservation Forestiere -ER s Universitaet Erlangen-Nuernberg, Geobotanik -ERA s Universidad Nacional de Entre Rios, Botanica Sistematica -ERAEP c Radiation Ecology Section, Biological Science Division, Office of Atomic Energy for Peace -ERCB s Yerevan State University, Botany Department -ERCH h Erciyes University -ERCULE c European Rumen Ciliate Culture Collection, Rowett Research Institute -ERE s Institute of Botany of the National Academy of Sciences of Armenia, Department of Plant Taxonomy and Geography -EREM s Institute of Botany of the National Academy of Sciences of Armenia, Mycology Department -ERH s Borough of Erith Museum -ERHM s Yerevan State University, Botany Department -ERSAF s Regional Agency for Agriculture and Forestry Services -ERZ s Fuerstin-Eugenie-Institut fuer Arzneipflanzenforschung -ESA s Universidade de Sao Paulo, Departamento de Botanica -ESAL s Universidade Federal de Lavras, Departamento de Biologia -ESAP c Instituto Zimotecnico-Z -ESEC s Entomological Society of Egypt -ESK s Seker Enstituesue -ESN s Ecole des Sciences de Niamey -ESNHS s Scottish Natural History Society -ESRC s Nova Scotia Department Natural Resources -ESRN s Escola Superior de Agricultura -ESS s Universitaet Essen -ESSE s Anadolu University -ESUG s University of Guam -ESUW s University of Wyoming Insect Museum and Gallery -ET s East Texas State University -ETE s El Colegio de la Frontera Sur, Coleccion de insectos Asociados a Plantas Cultivadas en la Frontera Sur -ETH c Kultursammlungen der Eidgenosische Technische Hochschule -ETH s Addis Ababa University, Biology Department -ETHZ s Eidgenoessische Technische Hochschule-Zentrum -ETL h Lake Forest College -ETN s Eton College Museum -ETNH h Jarvis Christian College -ETON h Eton College Museum -ETST s Texas A&M University, Biology Department -ETSU s East Tennessee State University, Biological Sciences Department -EU s Hubei University, Biology Department -EUB s Laboratory of Biology, Faculty of Science, Ehime University -EUMJ s Ehime University -EUQ s Department of Entomology, Queensland University -EUSL c Eastern University -EVA c European Virus Archive -EVCV s Erster Vorarlberger Coleopterische Verein -EVE h The Evergreen State College -EVMU s Everhart Museum, Natural History Department -EWH s Ewha Womans University -EWM h Elizabeth Winston Mize Herbarium -EWNHM s Ewha Womens University, Natural History Museum -EX c The Culture Collection of Extremophilic Fungi -EXN s Exton Hall -EXR s University of Exeter, Biological Sciences Department -F s Field Museum of Natural History, Botany Department -FAA h Universidad Nacional del Centro de la Provincia de Buenos Aires -FABR s Harmas de J. H. Fabre -FACHB c Freshwater Algae Culture Collection -FACS s Fujian Agricultural College -FAK s Department of Fisheries, Faculty of Agriculture -FAKOU s Faculty of Agriculture, Kochi Univerisity -FAKU s Kyoto University -FAN s Museum of Fanjingshan National Nature Reserve -FAR s University of Tarbiat-Moaallem, Biology Department -FARM s Longwood University, Department of Natural Sciences -FAU s Florida Atlantic University, Biological Sciences Department -FAUC s Universidad de Caldas, Departamento de Recursos Naturales -FAUN s Universidad de Narino -FAVU s Universidade Federal do Rio Grande do Sul, Faculdade Agronomia e Veterenaria -FB s Albert-Ludwigs Universitaet, Institut fuer Biologie II -FBA s Freshwater Biological Association -FBC s University of Sierra Leone, Fourah Bay College, Botany Department -FBCS s Universidad Autonoma de Baja California Sur, Museo de Historia Natural -FBGMU c Faculty of Biology Gadjah Mada University -FBMN s Museum fuer Naturkunde -FBQ s Fisheries Branch, Departement of Primary Industries -FBUB s Universitat Bielefeld -FBWA s Forstlichen Bundsversuchsanstalt -FC-DPV s Departmento de Paleontologia, Facultad de Ciencias -FCAB s Pontificia Universidade Catolica do Rio de Janeiro, Nucleo Interdisciplinar de Meio Ambiente -FCAP s Universidade Federal do Para -FCBP c First Fungal Culture Bank of Pakistan -FCDA s Fresno County Department of Agriculture -FCL c Fungal Culture Collection of Lublin -FCLR s Fundacion Cientifica Los Roques -FCM s Facultad de Ciencias Marinas -FCME s Universidad Nacional Autonoma de Mexico, Ciudad Universitaria, Departamento de Biologia -FCMM s Universidad Nacional Autonoma de Mexico, Facultad de Ciencias -FCNI s Forest Commission of N.S.W. -FCO s Universidad de Oviedo, Departamento de Biologia de Organismos y Sistemas -FCQ s Universidad Nacional de Asuncion, Departamento de Botanica, Direccion de Investigacion -FCRM s Fisheries College Reference Museum -FCT c FCT (Forestry Commission Tasmania) -FCTH s Forestry Commission of Tasmania -FCU s Fukien Christian University -FCUG c Fungal Cultures University of Goteborg -FDA c US Food and Drug Administration -FDC c Forsyth Dental Center -FDG s Guyana Forestry Commission -FDLW s University of Wisconsin Center, Biology Department -FDNR s Florida Department of Natural Resources -FDUC s Fairleigh Dickinson University [collection transferred to FSCA]. -FDVC s De La Villa, Francisco -FEN h Lycee Felix Esclangon, Region PACA -FER s Universita de Ferrara, Dipartimento di Biologia - Sezione di Botanica -FERM c Patent and Bio-Resource Center, National Institute of Advanced Industrial Science and Technology (AIST) -FEZA s Universidad Nacional Autonoma de Mexico, Carrera de Biologia -FFB s Atlantic Forestry Centre, Canadian Forest Service -FFBNM h Florissant Fossil Beds National Monument -FFCL s Nossa Senhora do Patrocinia -FFR s Forfar Museum and Art Gallery, Meffan Institute -FFS s University of Stellenbosch -FFSUC s Faculty of Forestry Sciences -FG s Palaontologische Hauptsammlung der Bergakadmie -FGC s Grassland Research Institute, Chinese Academy of Agricultural Sciences -FGG s Faculty of Geology and Geophysis -FGGUB s Facultatea de Geologie si Geofisca -FGIC s Francois Genier -FGSC c Fungal Genetics Stock Center -FH s The Farlow Herbarium, Harvard University Herbaria -FH s Fort Hays -FHI s Forestry Research Institute of Nigeria -FHK s Divisional Forest Office -FHKS s Fort Hays State University -FHKSC s Fort Hays State University -FHL s Friday Harbor Laboratories, University of Washington -FHO s University of Oxford, Department of Plant Sciences -FHSM s Fort Hays Sternberg Museum -FI s Museo di Storia Naturale dell'Universita -FIAF s Universita degli Studi di Firenze, Dipartimento di Biologia Vegetale -FICB s Forest Research Centre -FIDS s Great Lakes Forest Research Laboratory, Forest Insect and Disease Survey -FIEC s Freshwater Institute -FIJI s University of the South Pacific -FIOC s Fundacao Instituto Oswaldo Cruz -FIP s Florida Institute of Paleontology -FIPF s Universita di Firenze -FIPIA s Institut Teknologi Bandung, Jurusan Biologi -FJFC s Fujian Forestry College -FJSI s Fujian Institute of Subtropical Botany -FKE s Folk Museum -FKEN s Folkestone Natural History Society -FLACC c Free-Living Amoebae Culture Collection -FLAS s Florida Museum of Natural History Herbarium -FLC s Fort Lewis College -FLD s Fort Lewis College, Biology Department -FLIN s Flinders University -FLK s Falkirk District Council Museum -FLOR s Universidade Federal de Santa Catarina, Departamento de Botanica -FLSP s Oscar Scherer State Park -FM s Fan Memorial Institute of Biology -FM s Department of Nature, Fujian Province Museum -FMB s Instituto Alexander von Humboldt -FMC s North Museum of Natural History and Science -FMH s Goddard College -FMJ c Faculty of Medicine, Juntendo University -FML s Fundacion Miguel Lillo -FMM s Muzeum Beskyd -FMNH s Field Museum of Natural History +DMPMC c Department of Microbiology, University of Western Australia +DMSA s Durban Museum +DMSC s Medicinal Plants Research Institute, Department of Medical Sciences +DMSP s Davis Mountains State Park +DMSRDE c DMSRDE Culture Collection +DMST c Culture Collection for Medical Microorganism, Department of Medical Sciences +DMTH s Britannia Royal Naval College +DMU s Mithila University, Botany Department +DMUIJ c Department of Microbiology, Jakarta Pusat +DMUP c Microbiology and Biophysics Charles University +DMUR c Department of Mycology +DMVB c Department of Microbiology, Veterinary Branch of National Strain Collection +DNA s Department of Natural Resources, Environment and the Arts +DNAP h Department of Primary Industry and Fisheries +DNATAX b DNA-TAX +DNHM s Dalian Museum of Natural History +DNHM s Dinosaur Natural History Museum +DNPM s Setor de Paleontologia do Departamento Nacional de Producao Mineral +DNS s Dundee Naturalists' Society +DNZ h Donetsk Botanical Garden of the National Academy of Sciences of Ukraine +DO s Societe d'Agriculture Sciences et Arts +DOA c Department Of Agriculture, Thailand +DOMO s Collegio Mellerio Rosmini +DOR s Dorset County Museum +DORC s Dorset County Museum +DORCM s Dorset Royal County Museum +DORT s Botanischer Garten Rombergpark, Stadt Dortmund +DOV s Delaware State University, Department of Agriculture and Natural Resources +DPBA s Departamento de Patologia Vegetal +DPC c Dairy Products Research Center Culture Collection Teagasc +DPIC s Belo Horizonte, Instituto de Ciencias Biologicas +DPIH s Department of Primary Industry (formerly DAHT) +DPIQM s Department of Primary Industries +DPMWA s Dorthy Page Museum of Wasilla +DPNC s Denison Pequotsepos Nature Center +DPPC s Department of Agriculture, Taiwan +DPU s DePauw University, Botany and Bacteriology Department +DPUA c Departamento de Patologia/ICB +DPUP s Universidade Federal de Maringa +DQTC s Daqing Teachers College, Biology Department +DR s Technische Universitaet Dresden +DS s California Academy of Sciences, Botany Department +DSC s Delta State University, Biological Sciences Department +DSC c Dicty Stock Center +DSEC s Universidade Federal da Paraiba +DSIR s Department of Scientific and Industrial Research +DSM c Deutsche Sammlung von Mikroorganismen und Zellkulturen GmbH DSMZ +DSM s University of Dar es Salaam, Botany Department +DSMZ c Deutsche Sammlung von Mikroorganismen und Zellkulture +DSP s Fitzsimon's Snake Park +DSSC b Drosophila Species Stock Center +DSU s Dnipropetrovsk National University, Department of Geobotany, Soil, and Ecology +DSY s Dewsbury Museum +DTE h Centro de Investigaciones Cientificas y Transferencia de Tecnologia a la Produccion (CICyTTP-CONICET) +DTIC s Departamento Parasitologia +DTN s Darlington and Teesdale Naturalists' Field Club +DU s Duke University Vertebrate Collection +DUB s National Botanic Gardens +DUBN s Dublin Naturalists' Field Club +DUE s University of Dundee +DUF s University of Dicle, Biological Department, Botany +DUGAND h Universidad del Atlantico +DUH s University of Delhi, Botany Department +DUIS s Universitaet Duisburg, Fachbereich 6, Botanik +DUKE s Duke University, Biology Department +DUL s University of Minnesota, Biology Department +DUM c Delhi University Mycological Herbarium +DUM s Zooligical Museum of Science and Art Faculty +DUOF h Duzce University +DUP h Dumlupinar University +DUR s Southeastern Oklahoma State University, Biological Sciences Department +DUSS s Universitaet Duesseldorf +DVBID c Division Vector-Borne Infectious Diseases +DVCC s Diablo Valley College +DVCM s Diablo Valley College Museum +DVM s Diablo Valley College, Biology Department +DVNM s Death Valley National Monument +DVR s Dover Corporation Museum +DVZUT s Department of Vertebrate Zoology +DWC s West Chester University, Biology Department +DWN s Darwen Library +DWP h Disney Wilderness Preserve/The Nature Conservancy +DWT c Wood Technology and Forest Research Division +DWU s Dakota Wesleyan University, Biology Department +DZCU s Calcutta University +DZIB s Universidade Estadual de Campinas +DZKU s Department of Biology, Shaanxi Normal University +DZMU s Department of Zoology, Monash University +DZS s Devizes Museum +DZSASP s Departamento de Zoologia, Secretaria da Agricultura +DZUC s Departamento de Zoologia da Universidade de Coimbra +DZUFRGS s Departamento de Zoologia da Universidade Federal do Rio Grande do Sul +DZUH s Departamento de Zoologia, Universidad de Havana +DZUL s Departamento de Zoologia, Universidad de La Laguna +DZUP s Universidade Federal do Parana, Museu de Entomologia Pe. Jesus Santiago Moure +DZVMLP s Departamento Cientifico de Zoologia de Vertebrados +DZVU s Universidad de Uruguay +E sb Royal Botanic Garden Edinburgh +EA s National Museums of Kenya +EAA s Estonian Agricultural University +EAC s Universidade Federal do Ceara, Departamento de Biologia +EAFM h Instituto Federal de Educacao, Ciencia e Tecnologia do Amazonas +EALA h Jardin Botanique d'Eala +EAN s Universidade Federal da Paraiba, Campus III - CCA, Departamento de Fitotecnia +EAP s Escuela Agricola Panamericana +EAPZ s Escuela Agricola Panamericana +EAR s Earlham College, Biology Department +EATRO c Uganda Trypanosomiasis Research Organization +EBA s Edinburgh Academy Field Centre +EBCC s Universidad Nacional Autonoma de Mexico, Estacion de Biologia "Chamela" +EBD s Estacion Biologica de Donana +EBDS s Estacion Biologica de Donana +EBE s Eastbourne Museum +EBF s Hubei Forestry Institute +EBH s Botanical Society of Edinburgh +EBL h Ecosystem Research and Development Bureau +EBMC s Universidad de Chile +EBMTV s Estacion de Biologia Marina del Instituto Tecnologico de Veracruz +EBNHS s Edinburgh Natural History Society +EBRG s Museo de la Estacion Biologia de Rancho Grande +EBUAP s Laboratorio de Herpetologia, Escuela de Biologia, Benemerita Universidad Autonoma de Puebla +EBUM s Universidad Michoacana de San Nicolas de Hidalgo +EBV s Laboratoire de Biologie Generale et de Botanique +ECACC c European Collection of Authenticated Cell Cultures +ECENT s East Central University +ECH s Elmira College +ECK h Buffalo State College +ECM s Hubei College of Traditional Chinese Medicine, Department of Chinese Materia Medica +ECNB s Escuela Nacional Ciencias +ECO-SC-M s Coleccion Mastozoologica de El Colegio de la Frontera Sur Unidad San Cristobal de las Casas, Chiapas +ECOCHM s Coleccion de Mamiferos del Museo de Zoologia-ECOSUR +ECOL s Collection du Laborataire d'Ecologie +ECOMAR s ECOMAR lab University of Reunion +ECON s Harvard University +ECOSCM s Coleccion Mastozoologica de El Colegio de la Frontera Sur, Unidad San Cristobal +ECOSUR s El Colegio de la Frontera Sur (Mexico) +ECSC s East Central University, Biology Department +ECSFI s East China Sea Fisheries Institute +ECU h Edith Cowan University +ECUAMZ h Universidad Estatal Amazonica +ECUH h East Carolina University +ECWP h Emirates Centre for Wildlife Propagation +EDC s Hubei Institute for Drug Control +EDH s Plinian Society +EDNC s Raleigh, North Carolina Department of Agriculture +EDTU h Trakya Universitesi +EEBP s Estacao Experimental de Biologia e Piscicultura de Pirassununga +EELM s Estacion Experimental Agricola de la Molina +EERU s Economic Entomology Research Unit +EFC s Escola de Florestas +EFCC s Epping Forest Conservation Centre +EFH s Forestry Commission +EFM s Epping Forest Museum, Corporation of London +EFWM s Department of Entomology +EGE s Ege University +EGE-MACC c Ege - Microalgae Culture Collection +EGH s University of Edinburgh +EGHB s University of Edinburgh +EGHF s University of Edinburgh, Forestry and Natural Resources Department +EGNP s Homestead, Everglades National Park +EGR s Eszterhazy Karoly College, Botany Department +EHCV s Emory and Henry College, Biology Department +EHH s Universite d'Etat d'Haiti +EI s Universidade Federal Rural do Rio de Janeiro +EIF s Universidad de Chile, Departamento de Silvicultura +EIHU s Entomological Institute, Hokkaido University +EINS s Ecuadorian Institute of Natural Sciences +EISC s Shaanxi Agricultural University, Entomological Institute +EIU s Eastern Illinois University, Biological Sciences Department +EJ s ?Ein Yabrud collection catalogue entries at The Hebrew University +EKU s Eastern Kentucky University +EKY s Eastern Kentucky University, Biological Sciences Department +ELCAK s Entomological Laboratory, College of Agriculture +ELH h Bureau of Land Management, Eagle Lake Field Office +ELM s East London Museum +ELMF s Augusta, Maine Forest Service +ELN s Elgin Museum +ELRG s Central Washington University, Biological Sciences Department +ELS s Aldenham School, Biology Department +ELVE s National Station for Plant Breeding +EM s Universidade Federal de Ouro Preto +EMA s Sichuan School of Chinese Materia Medica +EMAG s Ernst-Moritz Arndt Collection, Museum der Stadt Greifswald +EMAU s Ernst-Moritz-Arndt-Universitat Greifswald +EMBT s Department of Agriculture, Thailand +EMC s Eastern Michigan University, Biology Department +EMCC c Egypt Microbial Culture Collection +EMEC s Essig Museum of Entomology EMUC +EMET s Faculty of Agriculture, Entomology Museum +EMMA s Universidad Politecnica de Madrid, Unidad Docente Botanica, Departamento Silvopascicultura +EMNH h The Everhart Museum of Natural History, Science & Art +EMPARN c Empresa de Pesquisa Agropecuaria do Rio Grande do Norte +EMU s Eastern Michigan University, T. L. Hankinson Vertebrate Museum +EMUS s Utah State University +ENAG s Universidad Nacional Agraria, Departamento de Ciencias Basicas +ENCB-IPN c Coleccion de cultivos de la Escuela Nacional de Ciencias Biologicas +ENCB s Universidad de Autonoma de Baja California +ENCB s Instituto Politecnico Nacional +ENG s Royal Holloway College, University of London, Botany Department +ENIH s National Institute of Health +ENLC h Eastern Nevada Landscape Coalition +ENMU s Eastern New Mexico University, Natural History Museum +ENMUNHM s Eastern New Mexico University, Natural History Museum +ENP s Everglades National Park +ENS s Hubei College for Nationalities, Forestry Department +ENSJ s Escuela Normal Superior de Jalisco +ENT s Herbarium, Ministry of Natural Resources, Uganda +ENTOMOFOR s Collection of necrophagous Fauna of the Forensic Entomology Laboratory (Basque Country University) +EONJ s Upsala College, Biology Department +EOSC s Eastern Oregon University, Biology Department +EOSCVM s Eastern Oregon State College, Vertebrate Museum +EOSTS s Official Seed Testing Station, Agricultural Scientific Services, Department of Agriculture and Fisheries for Scotland +EPAL s Entomology Collection, Punjab Agricultural University +EPHR s Snow College, Biology Department +EPM s Epsom College Museum +EPN s Escuela Polytecnica Nacional EPNC +EPRL s University of Puerto Rico +EPU h Centre de Formation et de Recherche en Conservation Forestiere +ER s Universitaet Erlangen-Nuernberg, Geobotanik +ERA s Universidad Nacional de Entre Rios, Botanica Sistematica +ERAEP c Radiation Ecology Section, Biological Science Division, Office of Atomic Energy for Peace +ERCB s Yerevan State University, Botany Department +ERCH h Erciyes University +ERCULE c European Rumen Ciliate Culture Collection, Rowett Research Institute +ERE s Institute of Botany of the National Academy of Sciences of Armenia, Department of Plant Taxonomy and Geography +EREM s Institute of Botany of the National Academy of Sciences of Armenia, Mycology Department +ERH s Borough of Erith Museum +ERHM s Yerevan State University, Botany Department +ERSAF s Regional Agency for Agriculture and Forestry Services +ERZ s Fuerstin-Eugenie-Institut fuer Arzneipflanzenforschung +ESA s Universidade de Sao Paulo, Departamento de Botanica +ESAL s Universidade Federal de Lavras, Departamento de Biologia +ESAP c Instituto Zimotecnico-Z +ESEC s Entomological Society of Egypt +ESK s Seker Enstituesue +ESN s Ecole des Sciences de Niamey +ESNHS s Scottish Natural History Society +ESRC s Nova Scotia Department Natural Resources +ESRN s Escola Superior de Agricultura +ESS s Universitaet Essen +ESSE s Anadolu University +ESUG s University of Guam +ESUW s University of Wyoming Insect Museum and Gallery +ET s East Texas State University +ETE s El Colegio de la Frontera Sur, Coleccion de insectos Asociados a Plantas Cultivadas en la Frontera Sur +ETH c Kultursammlungen der Eidgenosische Technische Hochschule +ETH s Addis Ababa University, Biology Department +ETHZ s Eidgenoessische Technische Hochschule-Zentrum +ETL h Lake Forest College +ETN s Eton College Museum +ETNH h Jarvis Christian College +ETON h Eton College Museum +ETST s Texas A&M University, Biology Department +ETSU s East Tennessee State University, Biological Sciences Department +EU s Hubei University, Biology Department +EUB s Laboratory of Biology, Faculty of Science, Ehime University +EUMJ s Ehime University +EUQ s Department of Entomology, Queensland University +EUSL c Eastern University +EVA c European Virus Archive +EVCV s Erster Vorarlberger Coleopterische Verein +EVE h The Evergreen State College +EVMU s Everhart Museum, Natural History Department +EWH s Ewha Womans University +EWM h Elizabeth Winston Mize Herbarium +EWNHM s Ewha Womens University, Natural History Museum +EX c The Culture Collection of Extremophilic Fungi +EXN s Exton Hall +EXR s University of Exeter, Biological Sciences Department +F s Field Museum of Natural History, Botany Department FMNH:F +FAA h Universidad Nacional del Centro de la Provincia de Buenos Aires +FABR s Harmas de J. H. Fabre +FACHB c Freshwater Algae Culture Collection +FACS s Fujian Agricultural College +FAK s Department of Fisheries, Faculty of Agriculture +FAKOU s Faculty of Agriculture, Kochi Univerisity +FAKU s Kyoto University +FAN s Museum of Fanjingshan National Nature Reserve +FAR s University of Tarbiat-Moaallem, Biology Department +FARM s Longwood University, Department of Natural Sciences +FAU s Florida Atlantic University, Biological Sciences Department +FAUC s Universidad de Caldas, Departamento de Recursos Naturales +FAUN s Universidad de Narino +FAVU s Universidade Federal do Rio Grande do Sul, Faculdade Agronomia e Veterenaria +FB s Albert-Ludwigs Universitaet, Institut fuer Biologie II +FBA s Freshwater Biological Association +FBC s University of Sierra Leone, Fourah Bay College, Botany Department +FBCS s Universidad Autonoma de Baja California Sur, Museo de Historia Natural +FBGMU c Faculty of Biology Gadjah Mada University +FBMN s Museum fuer Naturkunde +FBQ s Fisheries Branch, Departement of Primary Industries +FBUB s Universitat Bielefeld +FBWA s Forstlichen Bundsversuchsanstalt +FC-DPV s Departmento de Paleontologia, Facultad de Ciencias +FCAB s Pontificia Universidade Catolica do Rio de Janeiro, Nucleo Interdisciplinar de Meio Ambiente +FCAP s Universidade Federal do Para +FCBP c First Fungal Culture Bank of Pakistan +FCDA s Fresno County Department of Agriculture +FCL c Fungal Culture Collection of Lublin +FCLR s Fundacion Cientifica Los Roques +FCM s Facultad de Ciencias Marinas +FCME s Universidad Nacional Autonoma de Mexico, Ciudad Universitaria, Departamento de Biologia +FCMM s Universidad Nacional Autonoma de Mexico, Facultad de Ciencias +FCNI s Forest Commission of N.S.W. +FCO s Universidad de Oviedo, Departamento de Biologia de Organismos y Sistemas +FCQ s Universidad Nacional de Asuncion, Departamento de Botanica, Direccion de Investigacion +FCRM s Fisheries College Reference Museum +FCT c FCT (Forestry Commission Tasmania) +FCTH s Forestry Commission of Tasmania +FCU s Fukien Christian University +FCUG c Fungal Cultures University of Goteborg +FDA c US Food and Drug Administration +FDC c Forsyth Dental Center +FDG s Guyana Forestry Commission +FDLW s University of Wisconsin Center, Biology Department +FDNR s Florida Department of Natural Resources +FDUC s Fairleigh Dickinson University [collection transferred to FSCA]. +FDVC s De La Villa, Francisco +FEN h Lycee Felix Esclangon, Region PACA +FER s Universita de Ferrara, Dipartimento di Biologia - Sezione di Botanica +FERM c Patent and Bio-Resource Center, National Institute of Advanced Industrial Science and Technology (AIST) +FEZA s Universidad Nacional Autonoma de Mexico, Carrera de Biologia +FFB s Atlantic Forestry Centre, Canadian Forest Service +FFBNM h Florissant Fossil Beds National Monument +FFCL s Nossa Senhora do Patrocinia +FFR s Forfar Museum and Art Gallery, Meffan Institute +FFS s University of Stellenbosch +FFSUC s Faculty of Forestry Sciences +FG s Palaontologische Hauptsammlung der Bergakadmie +FGC s Grassland Research Institute, Chinese Academy of Agricultural Sciences +FGG s Faculty of Geology and Geophysis +FGGUB s Facultatea de Geologie si Geofisca +FGIC s Francois Genier +FGSC c Fungal Genetics Stock Center +FH s The Farlow Herbarium, Harvard University Herbaria +FH s Fort Hays +FHI s Forestry Research Institute of Nigeria +FHK s Divisional Forest Office +FHKS s Fort Hays State University +FHKSC s Fort Hays State University +FHL s Friday Harbor Laboratories, University of Washington +FHO s University of Oxford, Department of Plant Sciences +FHSM s Fort Hays Sternberg Museum +FI s Museo di Storia Naturale dell'Universita +FIAF s Universita degli Studi di Firenze, Dipartimento di Biologia Vegetale +FICB s Forest Research Centre +FIDS s Great Lakes Forest Research Laboratory, Forest Insect and Disease Survey +FIEC s Freshwater Institute +FIJI s University of the South Pacific +FIOC s Fundacao Instituto Oswaldo Cruz +FIOC:ColTryp c Fundacao Instituto Oswaldo Cruz, Collection of Trypanosoma from Wild and Domestic Mammals and Vectors +FIP s Florida Institute of Paleontology +FIPF s Universita di Firenze +FIPIA s Institut Teknologi Bandung, Jurusan Biologi +FJFC s Fujian Forestry College +FJSI s Fujian Institute of Subtropical Botany +FKE s Folk Museum +FKEN s Folkestone Natural History Society +FLACC c Free-Living Amoebae Culture Collection +FLAS s Florida Museum of Natural History Herbarium +FLC s Fort Lewis College +FLD s Fort Lewis College, Biology Department +FLIN s Flinders University +FLK s Falkirk District Council Museum +FLOR s Universidade Federal de Santa Catarina, Departamento de Botanica +FLSP s Oscar Scherer State Park +FM s Fan Memorial Institute of Biology +FM s Department of Nature, Fujian Province Museum +FMB s Instituto Alexander von Humboldt +FMC s North Museum of Natural History and Science +FMH s Goddard College +FMJ c Faculty of Medicine, Juntendo University +FML s Fundacion Miguel Lillo +FMM s Muzeum Beskyd +FMNH s Field Museum of Natural History CMNH FMNH:ARTH s Field Museum of Natural History, Arthropod Collection FMNH:AVES s Field Museum of Natural History, Ornithology Collection FMNH:HERP s Field Museum of Natural History, Herpetology Collection FMNH:ICHTHY s Field Museum of Natural History, Ichthyology Collection FMNH:INVRT s Field Museum of Natural History, Invertebrate Collection FMNH:MAMM s Field Museum of Natural History, Mammal Collection -FMNH s Finnish Museum of Natural History -FMP s Fujian Academy of Traditional Chinese Medicine and Pharmacology -FMPC s Fairbanks Museum and Planetarium Collection -FMR c Facultad de Medicina -FMRI s Central Marine Fisheries Marine Research Institute -FMSS s Parque Zoological Nacional "Finca Modelo", Natural History Museum -FMUH h Francis Marion University -FNCC c Food and Nutrition Culture Collection -FNFR s Fishlake National Forest -FNLO s Fremont National Forest -FNM s Fries Natuurmuseum -FNML s Fries Natuurhistorisch Museum -FNP s Fundy National Park -FNPS s South Florida Collections Management Center, Everglades National Park -FNU s Fujian Normal University -FNU s Nagasaki University - Fisheries -FOF h National University of Laos -FOR s Forssa Museum of Natural History -FOSJ s Fisheries and Oceans Biological Station -FPDB s Universidad de Puerto Rico, Departamento de Ciencias Marinas -FPF s Rocky Mountain Research Station, USDA Forest Service -FPM s Fukui Prefectural Museum -FPRL s Building Research Establishment -FQH s Fort Qu'Appelle Herbarium -FR sb Forschungsinstitut Senckenberg -FRC s Institute of Forest Genetics and Tree Breeding -FRC c Fusarium Research Center -FRCL s Fisheries Research Centre -FRCS s Forest Research Centre -FRDC b Fruit Tree Research & Development Center of ThuaThien-Hue-Vietnam -FRI s Australian National Herbarium, Division of Forestry and Forest Products, CSIRO -FRI c Food Research Institute, Ministry of Agriculture, Forestry and Fisheries -FRI c Food Research Institute, Bratislava, Slovakia -FRIHP s Fisheries Research Institute of Hunan Province -FRIM s Forest Research Institute, Malaysia -FRLC s Forest Insect and Disease Survey Reference Collection -FRLH s Foundation for Revitalisation of Local Health Traditions, Research Department -FRLM s Faculty of Fisheries, Mie University -FRM s Friends University, Fellow-Reeve Museum of History and Science -FRNZ s Forest Research Institute, New Zealand -FRP s Palmengarten -FRR c Food Science Australia, Ryde -FRS s Falconer Museum -FRSKU s Kyoto University, Fisheries Research Station -FRU s National Academy of Science, Kyrgyzstan, Laboratory of Flora -FSAG s Faculte des Sciences Agronomiques de Gembloux -FSC c Fredericton Stock Culture Collection -FSC s California State University, Biology Department -FSCA s Florida State Collection of Arthropods, Florida Department of Agriculture and Consumer Services, Division of Plant Industry -FSCL s Florida Southern College, Biology Department -FSFRL s Far Seas Fisheries Research Laboratory -FSIU s Laboratory of Fisheries, Department of Oceanography -FSL s Collections de la Faculte des Sciences de Lyon -FSLF s Rocky Mountain Forest and Range Experiment Station -FSMC s Florida State Museum -FSP-USP s Faculdade de Saude Publica, Universidade de Sao Paulo -FSSR s Forest Service, USDA, Biological and Physical Resources Unit -FSU s Florida State University, Department of Biological Science -FSUM s Florida State University Museum -FSUMC s Frostburg State University, Mammal Collection -FSUNS c Faculty of Science, The University of Novi Sad -FT s Centro Studi Erbario Tropicale, Universita degli Studi di Firenze -FTCC c Food Technology Culture Collection -FTCMU c Department of Food Science and Technology, Faculty of Agriculture -FTG sb Fairchild Tropical Botanic Garden -FTI c Centro de Biotecnologia e Quimica-CEBIQ -FTOH h Forestry Training Institute, Olmotonyi -FTS s Fuzhou Teachers College, Biology Department -FTU s University of Central Florida, Biology Department -FU s Fudan University, Department of Biology -FU s Kyushu University, Department of Forest and Forest Products Sciences -FUB s Frei Universitat -FUE s Fukuoka University of Education -FUEL s Universidade Estadual de Londrina, Departamento de Biologia Animal e Vegetal -FUGR s Furman University, Biology Department -FUH s Firat Ueniversitesi -FUK h Fukui Botanical Garden -FULD s Verein fuer Naturkunde in Osthessen -FUMH s Ferdowsi University -FUMT s University of Tokyo -FURB h Universidade Regional de Blumenau -FUS s Fudan University, Biology Department -FUSC c Flinders University Smut Collection -FVCC s Flathead Valley Community College, Biology Department -FW s Texas Christian University, Biology Department -FWM s Fort Worth Museum of Science and History, Science Department -FWMSH s Fort Worth Museum of Science & History -FWRI s Florida Fish and Wildlife Research Institute +FMNH s Finnish Museum of Natural History +FMP s Fujian Academy of Traditional Chinese Medicine and Pharmacology +FMPC s Fairbanks Museum and Planetarium Collection +FMR c Facultad de Medicina +FMRI s Central Marine Fisheries Marine Research Institute +FMSS s Parque Zoological Nacional "Finca Modelo", Natural History Museum +FMUH h Francis Marion University +FNCC c Food and Nutrition Culture Collection +FNFR s Fishlake National Forest +FNLO s Fremont National Forest +FNM s Fries Natuurmuseum +FNML s Fries Natuurhistorisch Museum +FNP s Fundy National Park +FNPS s South Florida Collections Management Center, Everglades National Park +FNU s Fujian Normal University +FNU s Nagasaki University - Fisheries +FOF h National University of Laos +FOR s Forssa Museum of Natural History +FOSJ s Fisheries and Oceans Biological Station +FPDB s Universidad de Puerto Rico, Departamento de Ciencias Marinas +FPF s Rocky Mountain Research Station, USDA Forest Service +FPM s Fukui Prefectural Museum +FPRL s Building Research Establishment +FQH s Fort Qu'Appelle Herbarium +FR sb Forschungsinstitut Senckenberg +FRC s Institute of Forest Genetics and Tree Breeding +FRC c Fusarium Research Center +FRCL s Fisheries Research Centre +FRCS s Forest Research Centre +FRDC b Fruit Tree Research & Development Center of ThuaThien-Hue-Vietnam +FRI s Australian National Herbarium, Division of Forestry and Forest Products, CSIRO +FRI c Food Research Institute, Ministry of Agriculture, Forestry and Fisheries +FRI c Food Research Institute, Bratislava, Slovakia +FRIHP s Fisheries Research Institute of Hunan Province +FRIM s Forest Research Institute, Malaysia +FRLC s Forest Insect and Disease Survey Reference Collection +FRLH s Foundation for Revitalisation of Local Health Traditions, Research Department +FRLM s Faculty of Fisheries, Mie University +FRM s Friends University, Fellow-Reeve Museum of History and Science +FRNZ s Forest Research Institute, New Zealand +FRP s Palmengarten +FRR c Food Science Australia, Ryde +FRS s Falconer Museum +FRSKU s Kyoto University, Fisheries Research Station +FRU s National Academy of Science, Kyrgyzstan, Laboratory of Flora +FSAG s Faculte des Sciences Agronomiques de Gembloux +FSC c Fredericton Stock Culture Collection +FSC s California State University, Biology Department +FSCA s Florida State Collection of Arthropods, Florida Department of Agriculture and Consumer Services, Division of Plant Industry +FSCL s Florida Southern College, Biology Department +FSFRL s Far Seas Fisheries Research Laboratory +FSIU s Laboratory of Fisheries, Department of Oceanography +FSL s Collections de la Faculte des Sciences de Lyon +FSLF s Rocky Mountain Forest and Range Experiment Station +FSMC s Florida State Museum FSM +FSP-USP s Faculdade de Saude Publica, Universidade de Sao Paulo +FSSR s Forest Service, USDA, Biological and Physical Resources Unit +FSU s Florida State University, Department of Biological Science +FSUM s Florida State University Museum FSU +FSUMC s Frostburg State University, Mammal Collection +FSUNS c Faculty of Science, The University of Novi Sad +FT s Centro Studi Erbario Tropicale, Universita degli Studi di Firenze +FTCC c Food Technology Culture Collection +FTCMU c Department of Food Science and Technology, Faculty of Agriculture +FTG sb Fairchild Tropical Botanic Garden +FTI c Centro de Biotecnologia e Quimica-CEBIQ +FTOH h Forestry Training Institute, Olmotonyi +FTS s Fuzhou Teachers College, Biology Department +FTU s University of Central Florida, Biology Department +FU s Fudan University, Department of Biology +FU s Kyushu University, Department of Forest and Forest Products Sciences +FUB s Frei Universitat +FUE s Fukuoka University of Education +FUEL s Universidade Estadual de Londrina, Departamento de Biologia Animal e Vegetal +FUGR s Furman University, Biology Department +FUH s Firat Ueniversitesi +FUK h Fukui Botanical Garden +FULD s Verein fuer Naturkunde in Osthessen +FUMH s Ferdowsi University +FUMT s University of Tokyo +FUNED s Fundacao Ezequiel Dias, Belo Horizonte +FURB h Universidade Regional de Blumenau +FUS s Fudan University, Biology Department +FUSC c Flinders University Smut Collection +FVCC s Flathead Valley Community College, Biology Department +FW s Texas Christian University, Biology Department +FWM s Fort Worth Museum of Science and History, Science Department +FWMSH s Fort Worth Museum of Science & History +FWRI s Florida Fish and Wildlife Research Institute FWRI:Ichthyology s Florida Fish and Wildlife Research Institute, Ichthyology Collection FWRI:Invertebrate s Florida Fish and Wildlife Research Institute, Invertebrate Collection FWRI:SEAMAP c Florida Fish and Wildlife Research Institute, SEAMAP Ichthyoplankton Collection -FWVA s Fairmont State University, Biology Department -G s Conservatoire et Jardin botaniques de la Ville de Geneve -GA s University of Georgia, Plant Biology Department -GAB s National Museum, Monuments, and Art Gallery -GABAS s Centre d'Etude et de Conservation des Resources Vegetales -GAC s Guangxi Agricultural University, Forestry Department -GACP s Guizhou Agricultural College, Department of Plant Protection -GADI h Grootfontein Agricultural Development Institute -GAES s Georgia Agricultural Experiment Station -GAFS s Ganzhou Forestry School -GAI s Folk Museum -GALW s National University of Ireland, Galway, Botany Department -GAM s University of Georgia -GAM c Grupo Actinomicetales Merida Facultad de Medicina -GAP h Conservatoire Botanique National Alpin -GAS s Georgia Southern University, Department of Biology -GAT s Institute of Plant Genetics and Crop Plant Research -GAUA s Guangxi University -GAUBA s Australian National University, Division of Botany and Zoology -GAUF s Gansu Agricultural University -GAW s Eastern Botanical Society of Glasgow -GAZI s Gazi Ueniversitesi, Biyoloji Boeluemue -GB s Goeteborg University, Department of Plant and Environmental Sciences -GBFM s Universidad de Panama -GBG b Goteburg Botanical Garden -GBH h Herbarium of Geo. B. Hinton -GBNM s Glacier Bay National Park and Preserve Museum -GBY s Grimsby Arts and Natural History -GC s University of Ghana, Botany Department -GC s Goucher College -GCL c Central Laboratories -GCM s University College of Ghana -GCM s Government College, Department of Zoology -GCNP s Grand Canyon National Park -GCRL s Gulf Coast Research Laboratory -GCTP s Global Colosseum -GCU h Gachon University -GDA s Universidad de Granada -GDAC s Universidad de Granada, Departamento de Biologia Vegetal, Botanica -GDB h Herbarium de Gerard de Belair -GDGM s Guangdong Institute of Microbiology -GDMA s Medical University of Gdansk, Department of Biology and Pharmaceutical Botany -GDMCC c Guangdong Microbial Culture Collection Center -GDMM s Guangdong Institute of Chinese Materia Medica -GDMP s Guangdong Medical and Pharmaceutical College, Pharmacy Department -GDOR s Museo Civico di Storia Naturale Giacomo Doria -GE s Universita di Genova -GEIC s Guangdong Entomology Institute -GENT s Gent University, Biology Department -GEO s Emory University, Biology Department -GES s Gesneriad Research Foundation -GESU s State University of New York, Biology Department -GF s Guizhou Academy of Forestry -GFBI s Gymnasium der Franziskaner in Bozen [= Bolzano] -GFC s University of Great Falls, Biology Department -GFCC c Goa University Fungus Culture Collection and Research Unit -GFJP s Universidade do Estado de Minas Gerais -GFND s University of North Dakota, Biology Department -GFRC s Golestan Fisheries Research Centre -GFS s Guizhou Forestry School -GFT h Grumeti Fund Tanzania -GFW s Ernst-Moritz-Arndt-Universitaet, Botanisches Institut und Botanischer Garten -GGB s Gesneriad Gardens -GGM s Gosudarstvennyi Geologicheskii Musei - State Geological Museum -GGO s University of Strathclyde, Biology Department -GGW s Botanical Society of Glasgow -GH s Harvard University (The Gray Herbarium) -GHD s Shipley Art Gallery and Saltwell Tower Museum -GHG s Council for Geosciences -GHPG s Harold Porter National Botanical Garden -GHRI s Guy Harvey Research Institute -GHS s George Heriot's School, Biology Department -GI s Justus-Liebig-Universitat Giessen -GI-SPS s Geological Institute, Section of Palaeontology and Stratigraphy -GIFU s Herbarium of Gifu Pharmaceutical University -GINCO h Agriculture and Agri-Food Canada -GIUV s Geological Institute, University of Vienna -GJO s Steiermaerkisches Landesmuseum Joanneum, Botany Department -GKAR s Karoo National Botanical Garden -GL s University of Glasgow, Botany Department -GLA h George Landis Arboretum -GLAC s Glacier National Park, Glacier Collection -GLAHM s University of Glasgow, Hunterian Museum -GLAM s Art Gallery and Museum, Natural History Department -GLANH s Hunterian Museum -GLEN s Rappahannock Community College -GLFR s Great Lakes Forest Research Centre -GLG s Trinity College -GLLB s Laurel Bank School -GLM s Staatliches Museum fuer Naturkunde Goerlitz -GLMC s Guilin Medical College, Pharmacy Department -GLNP s Glacier National Park -GLO s Natural History Society of Glasglow -GLOW s Lowveld National Botanical Garden -GLR s Gloucester City Museum and Art Gallery -GLW s Andersonian Naturalists' Society -GM s Museum of Southeastern Moravia -GMACC c Laboratory of Molecular Genetics and Breeding of Edible Mushrooms -GMAU s Geological Museum of Amsterdam University -GMBL s College of Charleston -GMC s Guangxi Medical College -GMCE s Grosvenor Museum -GMDRC h Granite Mountains Desert Research Center -GMH s Sammlung Jacobi des Geiseltalmuseum Halle -GMHH s Geological Museum of Heilongjang Province -GML s Gorgas Memorial Laboratory -GML s Gaylord Memorial Laboratory Museum -GMNGZ s Glasgow Museum and Art Galleries -GMNH-PV s Paleo-Vertebrate Collection -GMNH s Museum d'Histoire Naturelle -GMNH s Georgia Museum of Natural History -GMNHJ h Gunma Museum of Natural History -GMNP s Gros Morne National Park -GMS s Hopkins Marine Station, Stanford University, Biological Sciences Department -GMU s N. P. Ogariov Mordovia State University, Department of Botany and Plant Physiology -GMUF s George Mason University, Department of Environmental Science and Policy 5F2 -GMUG s Universitat Gottingen, Geologisches-Palaatologisches Museum -GMUM s Institut fuer Palaeontologie und Geologisches Museum der Universitat -GMUV s Geological Museum, University of Vienna -GNA s Gannan Arboretum of Jiangxi -GNDUH h Guru Nanak Dev University -GNE c Genentech -GNHM s Goulandris Natural History Museum -GNHNA s Gallery of Natural History and Native Art -GNHS s Guildford Natural History Society -GNM s Gothenburg Museum of Natural History (Goteborgs Naturhistoriska Museum) -GNU s Guangxi Normal University, Biology Department -GNUB s Guizhou Normal University, Biology Department -GNUC s Gyeongsang National University, Biology Department -GNUG s Guizhou Normal University, Geography Department -GO s Philosophical Society -GOD s Charterhouse School Museum -GOE s Institut und Museum fuer Geologie und Palaeontologie -GOE s Goole Scientific Society -GOET s Herbarium Universitat Gottingen -GOFS s Free State National Botanical Garden -GOPU h Gaziosmanpasa University -GOW s Clydebank High School -GP s Instituto de Geociencias, Universidade de Sao Paulo -GPA s Grande Prairie Regional College, Science Department -GPI s Geologisch-Palaeontologisches Institut -GPIH s Geologisch-Palaeontologiches Institut der Universitt Haemburg -GPIM s Lehreinheit Palaeontologisches, Institut fuer Geowissenschaften -GPIT s Institut und Museum fur Geologie und Palaeontologie, Universitat Tuebingen -GPM s Gifu prefectural Museum +FWVA s Fairmont State University, Biology Department +G s Conservatoire et Jardin botaniques de la Ville de Geneve +GA s University of Georgia, Plant Biology Department +GAB s National Museum, Monuments, and Art Gallery +GABAS s Centre d'Etude et de Conservation des Resources Vegetales +GAC s Guangxi Agricultural University, Forestry Department +GACP s Guizhou Agricultural College, Department of Plant Protection +GADI h Grootfontein Agricultural Development Institute +GAES s Georgia Agricultural Experiment Station +GAFS s Ganzhou Forestry School +GAI s Folk Museum +GALW s National University of Ireland, Galway, Botany Department +GAM s University of Georgia +GAM c Grupo Actinomicetales Merida Facultad de Medicina +GAP h Conservatoire Botanique National Alpin +GAS s Georgia Southern University, Department of Biology +GAT s Institute of Plant Genetics and Crop Plant Research +GAUA s Guangxi University +GAUBA s Australian National University, Division of Botany and Zoology +GAUF s Gansu Agricultural University +GAW s Eastern Botanical Society of Glasgow +GAZI s Gazi Ueniversitesi, Biyoloji Boeluemue +GB s Goeteborg University, Department of Plant and Environmental Sciences +GBFM s Universidad de Panama +GBG b Gotheburg Botanical Garden +GBH h Herbarium of Geo. B. Hinton +GBNM s Glacier Bay National Park and Preserve Museum +GBY s Grimsby Arts and Natural History +GC s University of Ghana, Botany Department +GC s Goucher College +GCL c Central Laboratories +GCM s University College of Ghana +GCM s Government College, Department of Zoology +GCNP s Grand Canyon National Park +GCRL s Gulf Coast Research Laboratory +GCTP s Global Colosseum +GCU h Gachon University +GDA s Universidad de Granada +GDAC s Universidad de Granada, Departamento de Biologia Vegetal, Botanica +GDB h Herbarium de Gerard de Belair +GDGM s Guangdong Institute of Microbiology +GDMA s Medical University of Gdansk, Department of Biology and Pharmaceutical Botany +GDMCC c Guangdong Microbial Culture Collection Center +GDMM s Guangdong Institute of Chinese Materia Medica +GDMP s Guangdong Medical and Pharmaceutical College, Pharmacy Department +GDOR s Museo Civico di Storia Naturale Giacomo Doria +GE s Universita di Genova +GEIC s Guangdong Entomology Institute +GENT s Gent University, Biology Department +GEO s Emory University, Biology Department +GES s Gesneriad Research Foundation +GESU s State University of New York, Biology Department +GF s Guizhou Academy of Forestry +GFBI s Gymnasium der Franziskaner in Bozen [= Bolzano] +GFC s University of Great Falls, Biology Department +GFCC c Goa University Fungus Culture Collection and Research Unit GUFCC +GFJP s Universidade do Estado de Minas Gerais +GFND s University of North Dakota, Biology Department +GFRC s Golestan Fisheries Research Centre +GFS s Guizhou Forestry School +GFT h Grumeti Fund Tanzania +GFW s Ernst-Moritz-Arndt-Universitaet, Botanisches Institut und Botanischer Garten +GGB s Gesneriad Gardens +GGM s Gosudarstvennyi Geologicheskii Musei - State Geological Museum +GGO s University of Strathclyde, Biology Department +GGW s Botanical Society of Glasgow +GH s Harvard University (The Gray Herbarium) +GHD s Shipley Art Gallery and Saltwell Tower Museum +GHG s Council for Geosciences +GHPG s Harold Porter National Botanical Garden +GHRI s Guy Harvey Research Institute +GHS s George Heriot's School, Biology Department +GI s Justus-Liebig-Universitat Giessen +GI-SPS s Geological Institute, Section of Palaeontology and Stratigraphy +GIFU s Herbarium of Gifu Pharmaceutical University +GINCO h Agriculture and Agri-Food Canada +GIUV s Geological Institute, University of Vienna +GJO s Steiermaerkisches Landesmuseum Joanneum, Botany Department +GKAR s Karoo National Botanical Garden +GL s University of Glasgow, Botany Department +GLA h George Landis Arboretum +GLAC s Glacier National Park, Glacier Collection +GLAHM s University of Glasgow, Hunterian Museum +GLAM s Art Gallery and Museum, Natural History Department +GLANH s Hunterian Museum +GLEN s Rappahannock Community College +GLFR s Great Lakes Forest Research Centre +GLG s Trinity College +GLLB s Laurel Bank School +GLM s Staatliches Museum fuer Naturkunde Goerlitz +GLMC s Guilin Medical College, Pharmacy Department +GLNP s Glacier National Park +GLO s Natural History Society of Glasglow +GLOW s Lowveld National Botanical Garden +GLR s Gloucester City Museum and Art Gallery +GLW s Andersonian Naturalists' Society +GM s Museum of Southeastern Moravia +GMACC c Laboratory of Molecular Genetics and Breeding of Edible Mushrooms +GMAU s Geological Museum of Amsterdam University +GMBL s College of Charleston +GMC s Guangxi Medical College +GMCE s Grosvenor Museum +GMDRC h Granite Mountains Desert Research Center +GMH s Sammlung Jacobi des Geiseltalmuseum Halle +GMHH s Geological Museum of Heilongjang Province +GML s Gorgas Memorial Laboratory +GML s Gaylord Memorial Laboratory Museum +GMNGZ s Glasgow Museum and Art Galleries +GMNH-PV s Paleo-Vertebrate Collection +GMNH s Museum d'Histoire Naturelle +GMNH s Georgia Museum of Natural History +GMNHJ h Gunma Museum of Natural History +GMNP s Gros Morne National Park +GMS s Hopkins Marine Station, Stanford University, Biological Sciences Department +GMU s N. P. Ogariov Mordovia State University, Department of Botany and Plant Physiology +GMUF s George Mason University, Department of Environmental Science and Policy 5F2 +GMUG s Universitat Gottingen, Geologisches-Palaatologisches Museum +GMUM s Institut fuer Palaeontologie und Geologisches Museum der Universitat +GMUV s Geological Museum, University of Vienna +GNA s Gannan Arboretum of Jiangxi +GNDUH h Guru Nanak Dev University +GNE c Genentech +GNHM s Goulandris Natural History Museum +GNHNA s Gallery of Natural History and Native Art +GNHS s Guildford Natural History Society +GNM s Gothenburg Museum of Natural History (Goteborgs Naturhistoriska Museum) +GNU s Guangxi Normal University, Biology Department +GNUB s Guizhou Normal University, Biology Department +GNUC s Gyeongsang National University, Biology Department +GNUG s Guizhou Normal University, Geography Department +GO s Philosophical Society +GOD s Charterhouse School Museum +GOE s Institut und Museum fuer Geologie und Palaeontologie +GOE s Goole Scientific Society +GOET s Herbarium Universitat Gottingen +GOFS s Free State National Botanical Garden +GOPU h Gaziosmanpasa University +GOW s Clydebank High School +GP s Instituto de Geociencias, Universidade de Sao Paulo +GPA s Grande Prairie Regional College, Science Department +GPI s Geologisch-Palaeontologisches Institut +GPIH s Geologisch-Palaeontologiches Institut der Universitt Haemburg +GPIM s Lehreinheit Palaeontologisches, Institut fuer Geowissenschaften +GPIT s Institut und Museum fur Geologie und Palaontologie, Universitat Tubingen +GPM s Gifu prefectural Museum GPM:B s Gifu prefectural Museum, Gifu prefectural Museum herbarium GPM:Z s Gifu prefectural Museum, Gifu prefectural Museum Zoological collection -GPMK s Geologisch-Palaontologisches Institut und Museum -GPPT s Plant Protection Institute -GR s Universite J. Fourier - Grenoble I, Botanique -GRA s Albany Museum -GRCAMC s Grand Canyon National Park Museum Collection -GRCH s Colgate University, Biology Department -GREE s University of Northern Colorado, Department of Biological Sciences -GRI s Grinnell College, Biology Department -GRIF s Griffith University -GRJC s Grand Rapids Junior College -GRK s McLean Museum and Art Gallery -GRM s Museum d'Histoire Naturelle de Grenoble -GRMP s Central Geological Research Museum -GRO s State University of Groningen, Department of Plant Biology -GRPM s Public Museum of Grand Rapids -GRS s Gezira Research Station -GRSM s Great Smoky Mountains National Park -GRSU s Yanka Kupala Grodno State University, Department of Botany -GRSW s Desert Ecological Research Unit -GRTE h Grand Teton National Park -GSAT s The Geological Survey of Alabama -GSC s Geological Survey of Canada -GSDNM s Great Sand Dunes National Monument -GSFS s Gansu Forestry School -GSI s Geological Survey of India -GSM s Geologic Museum -GSMNP s Great Smoky Mountains National Park -GSN s Geological Survey of Nambia -GSO s Glasgow Society of Field Naturalists' -GSP s Geological Survey of Portugal -GSU s F. Scorina Gomel State University, Department of Botany and Plant Physiology -GSW s Georgia Southwestern State University, Biology Department -GTC c Gifu Type Culture Collection -GTC-GIFU c Gifu Type Culture Collection (GTC), Gifu University Culture Collection (GIFU) -GTM s Grantham Museum -GTNP s Grand Teton National Park -GTV s Gregorio T. Velasquez Phycological Herbarium -GU s Gotland University, Department of Biology -GU-IITG s for Gauhati University- Indian Institute of Technology Guwahati -GUA s DIVEA, DEP, FEEMA, FEEMA -GUAD s Institut National de la Recherche Agronomique and Parc National de Guadeloupe -GUADA s Universidad Autonoma de Guadalajara -GUAM s University of Guam, Biology Department -GUAT s Herbario Ulises Roja -GUAY s Universidad de Guayaquil -GUBH h Gauhati University -GUBIOTJT c Freshwater microalgae collection and culture laboratory -GUCM h Guangzhou University of Chinese Medicine -GUH s HNB Garhwal University, Botany Department -GUL h Suleyman Demirel University -GUM s Glasgow University Museum (Hunter Museum) -GUM s Mycological herbarium of University of Guilan -GUMACC c Gotheburg University Marine Algal Culture Collection -GUYN s Fundacion Jardin Botanico del Orinoco -GVF s George Vanderbilt Foundation -GVSC s Grand Valley State University, Biology Department -GW s West of Scotland College of Agriculture, Botany Department -GXCM s Guangxi Traditional Chinese Medicine University, Pharmacy Department -GXDC s Guangxi Institute for Drug Control -GXEM s Guangxi Institute of Ethnomedicine -GXF s Guangxi Institute of Forest Survey and Design -GXFI s Guangxi Forestry Institute -GXFS s Guangxi Forestry School -GXMG s Guangxi Medicinal Botanic Garden -GXMI s Guangxi Institute of Traditional Medical and Pharmaceutical Sciences -GXNM s Guangxi Natural History Museum, Herbarium -GXSP s Guangxi School of Pharmacy -GZAC s Guizhou Agricultural College, Forestry Department -GZM s Giessener Zoologisches Museum -GZTM s Guizhou Institute of Traditional Chinese Medicine -GZU s Karl-Franzens-Universitaet Graz -H s University of Helsinki -H-GSP s Howard University-Geological Survey of Pakistan Project -HA s Universidad del Azuay, Escuela de Biologia del Medio Ambiente -HABA s Academia de Ciencias Medicas, Fisicas y Naturales de La Habana -HABAYC s University of Mary Hardin-Baylor, Biology Department -HABE s Instituto de Biologia, Departamento de Ecologia -HAC s Instituto de Ecologia y Sistematica -HACC s Academia de Ciencias Camagueey -HACW s Department of Fishery, Huazhong Agriculture Collection -HAF s Hainan Forestry Institute -HAH h Hoyt Arboretum -HAI h University of Haifa -HAJB s Jardin Botanico Nacional -HAJU h Herbario Dr. Armando Jesus Urquiola -HAK s Hokkaido University, Faculty of Fisheries -HAKS s Hakgala Botanic Gardens -HAL s Martin-Luther-Universitaet -HALA s University of Alabama, Biological Sciences Department -HALE h Haleakala National Park -HALLE s Zoologisches Institut der Martin-Luther Universitaet -HALLST s Botanische Station -HALN h State Agency for Environmental Protection Saxony-Anhalt -HALX s Halifax Literary and Philosophical Society -HAM s Royal Botanical Gardens -HAMAB s Instituto de Pesquisas Cientificas e Tecnologicas do Estado do Amapa -HAMBI c HAMBI Culture Collection -HAMU s University of Newcastle upon Tyne -HAN s Universitaet Hannover -HANC h National Aquarium of Cuba -HANU s Harbin Normal University, Biology Department -HAO s Universidad Privada Antenor Orrego -HAQ s Institut der Technische Hochschule (RWTH), Institut fuer Biologie I -HAS s Fundacao Zoobotanica do Rio Grande do Sul -HAST s Research Center for Biodiversity, Academia Sinica -HASU s Universidade do Vale do Rio dos Sinos - CCS/ Centro 2 -HAU h Alzahra University -HAUH s Haryana Agricultural University -HAVI s Eastern Mennonite University, Biology Department -HAVO s Hawaii Volcanoes National Park -HAW s University of Hawaii, Botany Department -HAX s Belle Vue Museum -HAY s California State University, Biological Sciences Department -HB s Herbarium Bradeanum -HBA h National Botanic Garden of Latvia -HBARC h Bhabha Atomic Research Centre -HBAU s Hebei Agricultural University -HBAUD s Hebei Agricultural University, Handan Branch, Agriculture Department -HBBS s Museo Civico di Scienze Naturali -HBC s Henry Brockhouse Collection -HBDC s Hebei Institute for Drug Control -HBFC s Hebei Forestry College, Basic Courses Department -HBFH s Harbor Branch Oceanographic Institution, Marine Botany Department -HBG s Institut fuer Allgemeine Botanik -HBG b Hiroshima Botanical Garden -HBI s Institute of Hydrobiology, Chinese Academy of Sciences, Phycology Department -HBIL s Institut d'Estudis Ilerdencs -HBNU s Hebei Normal University, Biology Department -HBOM s Harbor Branch Oceanographic Museum -HBR s Universidade Federal de Santa Catarina -HBRA h Universidade Federal do Para, Campus Braganca -HBUM s College of Life Sciences Hebei Univesity, Baoding -HC s Hangchow Christian College -HCAT s University of Tabriz, Landscape Department -HCB s Universidade de Santa Cruz do Sul, Departamento de Biologia -HCCA s Hastings College -HCCN h National Institute of Agricultural Science and Technology -HCCV s Hastings College, Collection of Vertebrates -HCDAL h Universidade Regional do Cariri -HCEN s Universidad Nacional del Centro del Peru -HCF h Universidade Tecnologica Federal do Parana -HCH s Lewis-Clark State College, Natural Sciences Department -HCHM s Hope College, Biology Department -HCIB s Centro de Investigaciones Biologicas del Noroeste, S. C. -HCIO s Indian Agricultural Research Institute -HCMS s Hampshire County Council Museums Service -HCMZ s Hope College -HCNHSC s Ohio Historical Society, Natural History Synoptic Collection -HCOA s College of the Atlantic, Herbarium -HCOM h Centre d'Oceanologie de Marseille - University of Aix-Marseille II -HCT s Taiwan Forestry Research Institute -HCTR s Hoogstraal Center for Tick Research -HDCF h Department of Forestry Science -HDD s Tolson Museum, Natural History Department -HDJF h Universidade Federal dos Vales do Jequitinhonha e Mucuri -HDOA s Hawaii Department of Agriculture -HDSM s University of Massachusetts Dartmouth -HDTC s Huddersfield Technical College -HEAC s Henan Agricultural University -HEB s Hebden Bridge Literary and Scientific Society -HEBI s Henan Academy of Sciences -HECM s Henan College of Traditional Chinese Medicine -HEFG s l'Ecole de Faune de Garoua -HEH s Escuela Nacional de Ciencias Forestales, Departamento de Investigacion Forestal Aplicada -HEID s Universitaet Heidelberg, Heidelberger Institut fuer Pflanzenwissenschaften -HEL s University of Helsinki, Section of Botany -HEM h Universidad de Ciencias y Artes de Chiapas -HEMS s Haslemere Educational Museum -HENA s Escuela Nacional de Agricultura -HEND s Henderson State University, Biology Department -HENNU s Henan Normal University -HENU s Henan Normal University, Biology Department -HEPH s Jardim Botanico de Brasilia -HER c Felix d'Herelle Reference Center for Bacterial Viruses -HER s Hermanus Botanical Society -HERBAM h Universidade do Estado de Mato Grosso -HERT h Fundacao Universidade Estadual do Ceara -HERZ s Herzen State Pedagogical University of Russia, Department of Botany -HERZU s Universidad del Zulia -HEUS h Universidad de Sucre -HF s Universidade Federal do Para -HFB s Hainan Forestry Bureau -HFBG s Forestry Botanical Garden of Heilongjiang -HFCC c Flagellate Culture Collection, University of Cologne -HFD s Hereford Museum -HFLA h Sapienza University of Rome - Scuola di Specializzazione in Beni Naturali e Territoriali -HFN h Herbarium Frisicum -HFP c Hokkaido Forest Products Research Institute -HFR s Finnish Forest Research Institute -HFRI s Hunan Forestry Research Institute -HFSL h Centro de Ensino, Faculdade Sao Lucas Ltda. -HFU s Herbarium of Fayoum University -HFV s Universidad Austral de Chile, Instituto de Produccion y Sanidad Vegetal -HFX s Bankfield Museum and Art Gallery -HGAS s Guizhou Academy of Sciences, Plant Taxonomy Group -HGCRL s Gulf Coast Research Laboratory -HGI s Universitat de Girona, Unitat de Biologia Vegetal -HGM s Hunan Geological Museum -HGOM h Universidad Autonoma del Estado de Hidalgo -HGS s Public Museum and Art Gallery, St. John's Place -HGTC s Huanggang Teachers College, Biology Department -HGU h Khakass State University -HH h Instituto de Investigaciones de la Amazonia Peruana -HHBG s Hangzhou Botanical Garden -HHC s University of Helsinki, Horticulture Department -HHH s Hartwick College -HHM s Collyer's School -HHU s Hallym University -HHUA s Universidad Nacional de Huanuco Hermilio Valdizan -HHUF s Hirosaki University, Laboratory of Plant Pathology -HIB s Wuhan Institute of Botany -HIBG h Hiroshima Botanical Garden -HIC s University of Kentucky, Department of Entomology, Hymenoptera Institute Collection -HIFP s French Institute -HILL s Sir Harold Hillier Gardens -HIMC s Inner Mongolia University -HIN s Hitchin Priory -HIP s Universidad de Magallanes -HIPC s Instituto Superior Pedagogico Jose Marti, Departamento de Biologia -HIRO s Hiroshima University, Biological Science Department -HIRU s Okayama University of Science -HISA h Universidade Estadual Paulista -HITBC s Xishuangbanna Tropical Botanical Garden, Chinese Academy of Sciences -HIUW s Hygiene-Institut der Universitaet -HIWNT s Hampshire and Isle of Wight Naturalists' Trust Ltd. -HJBC h Jardin Botanico Culiacan -HJBL s Escuela Nacional de Ciencias Forestales -HJBS s Fundacio Jardi Botanic de Soller -HK s Agriculture, Fisheries, and Conservation Department -HKAS s Cryptogamic Herbarium of Kunming Institute of Botany, Chinese Academy of Sciences -HKBU s Hong Kong Baptist University, Biology Department -HKFRS s Hong Kong Fisheries Research Station -HKGL s Naturwissenschaftliche Sammlungen des Kantons Glarus -HKI c Hans-Knoll Institute -HKM h University of Comoros -HKS h Research Center of Agricultural and Natural Resources Kurdistan Province -HKU s University of Hong Kong, Ecology and Biodiversity Department -HKUCC c The University of Hong Kong Culture Collection -HL s Houghton Lake Wildlife Research Station, Natural Resources Department -HLA s Harold L. Lyon Arboretum -HLCM s Heilongjiang College of Traditional Chinese Medicine, Department of Chinese Materia Medica -HLD s Hessisches Landesmuseum -HLDG h Las Cruces Biological Station, Organization for Tropical Studies -HLL s Queen's Gardens, College of Higher Education, Natural Science Department -HLMA s Town Docks Museum, Hull City Corporation -HLMD s Hessisches Landesmuseum Darmstadt -HLNM s Heilongjiang Provincial Museum -HLO s Vlastivedne Muzeum v Hlohovci -HLSD h Hillsdale College -HLU s University of Hull, Botany Department -HLUC s Universita degli Studi della Basilicata, Dipartimento di Biologia Difesa e Biotecnologie Agroforestali -HLUL s University of Hull -HLX s Ovenden Naturalists' Society -HM s Humbolt Museum -HM s Hastings Museum -HMAR h Universidade Federal do Ceara -HMAS sc Institute of Microbiology, Academia Sinica -HMC s Jardin Botanico de Las Tunas -HME s Haslemere Educational Museum -HMGBH h Giardini Botanici Hanbury / Hanbury Botanic Gardens -HMH s Hoebarth Museum Horn -HMIM h Jardi Botanic Marimurtra -HMJAU sc Herbarium of Mycology of Jilin Agricultural University -HMLN s District Museum -HMM s Horsham Museum -HMMNH h Macedonian Museum of Natural History -HMN s Humbolt Museum fur Naturkunde, East Berlin -HMNH s Hayashibara Museum of Natural History -HMNR h Mordovian State Nature Reserve -HMNS s Houston Museum of Natural Science -HMNT s Hancock Museum, Newcastle University -HMP s Hornonitrianske muzeum, Department of Natural History -HMS s Embrapa Gado de Corte -HMUG s Hunterian Museum -HN s National Center for Natural Sciences and Technology, Botany Department -HNBU s Institut de l'Environnement et de Recherche Agricola (INERA) -HNCMB c Hungarian National Collection of Medical Bacteria -HNG h Universite. Gamal Abdel Nasser de Conakry -HNH s Dartmouth College, Biological Sciences Department -HNHH s Heilongjiang Natural History Museum -HNHM s Hungarian Natural History Museum (Termeszettudomanyi Muzeum) +GPMK s Geologisch-Palaontologisches Institut und Museum +GPPT s Plant Protection Institute +GR s Universite J. Fourier - Grenoble I, Botanique +GRA s Albany Museum +GRCAMC s Grand Canyon National Park Museum Collection +GRCH s Colgate University, Biology Department +GREE s University of Northern Colorado, Department of Biological Sciences +GRI s Grinnell College, Biology Department +GRIF s Griffith University +GRJC s Grand Rapids Junior College +GRK s McLean Museum and Art Gallery +GRM s Museum d'Histoire Naturelle de Grenoble +GRMP s Central Geological Research Museum +GRO s State University of Groningen, Department of Plant Biology +GRPM s Public Museum of Grand Rapids +GRS s Gezira Research Station +GRSM s Great Smoky Mountains National Park +GRSU s Yanka Kupala Grodno State University, Department of Botany +GRSW s Desert Ecological Research Unit +GRTE h Grand Teton National Park +GSAT s The Geological Survey of Alabama +GSC s Geological Survey of Canada +GSDNM s Great Sand Dunes National Monument +GSFS s Gansu Forestry School +GSI s Geological Survey of India +GSM s Geologic Museum +GSMNP s Great Smoky Mountains National Park +GSN s Geological Survey of Nambia +GSO s Glasgow Society of Field Naturalists' +GSP s Geological Survey of Portugal +GSU s F. Scorina Gomel State University, Department of Botany and Plant Physiology +GSW s Georgia Southwestern State University, Biology Department +GTC c Gifu Type Culture Collection +GTC-GIFU c Gifu Type Culture Collection (GTC), Gifu University Culture Collection (GIFU) +GTM s Grantham Museum +GTNP s Grand Teton National Park +GTV s Gregorio T. Velasquez Phycological Herbarium +GU s Gotland University, Department of Biology +GU-IITG s for Gauhati University- Indian Institute of Technology Guwahati +GUA s DIVEA, DEP, FEEMA, FEEMA +GUAD s Institut National de la Recherche Agronomique and Parc National de Guadeloupe +GUADA s Universidad Autonoma de Guadalajara +GUAM s University of Guam, Biology Department +GUAT s Herbario Ulises Roja +GUAY s Universidad de Guayaquil +GUBH h Gauhati University +GUBIOTJT c Freshwater microalgae collection and culture laboratory +GUCM h Guangzhou University of Chinese Medicine +GUH s HNB Garhwal University, Botany Department +GUL h Suleyman Demirel University +GUM s Glasgow University Museum (Hunter Museum) +GUM s Mycological herbarium of University of Guilan +GUMACC c Gotheburg University Marine Algal Culture Collection +GUYN s Fundacion Jardin Botanico del Orinoco +GVF s George Vanderbilt Foundation +GVSC s Grand Valley State University, Biology Department +GW s West of Scotland College of Agriculture, Botany Department +GXCM s Guangxi Traditional Chinese Medicine University, Pharmacy Department +GXDC s Guangxi Institute for Drug Control +GXEM s Guangxi Institute of Ethnomedicine +GXF s Guangxi Institute of Forest Survey and Design +GXFI s Guangxi Forestry Institute +GXFS s Guangxi Forestry School +GXMG s Guangxi Medicinal Botanic Garden +GXMI s Guangxi Institute of Traditional Medical and Pharmaceutical Sciences +GXNM s Guangxi Natural History Museum, Herbarium +GXSP s Guangxi School of Pharmacy +GZAC s Guizhou Agricultural College, College of Life Science +GZM s Giessener Zoologisches Museum +GZTM s Guizhou Institute of Traditional Chinese Medicine +GZU s Karl-Franzens-Universitaet Graz +H s University of Helsinki +H-GSP s Howard University-Geological Survey of Pakistan Project +HA s Universidad del Azuay, Escuela de Biologia del Medio Ambiente +HABA s Academia de Ciencias Medicas, Fisicas y Naturales de La Habana +HABAYC s University of Mary Hardin-Baylor, Biology Department +HABE s Instituto de Biologia, Departamento de Ecologia +HAC s Instituto de Ecologia y Sistematica +HACC s Academia de Ciencias Camagueey +HACW s Department of Fishery, Huazhong Agriculture Collection +HAF s Hainan Forestry Institute +HAH h Hoyt Arboretum +HAI h University of Haifa +HAJB s Jardin Botanico Nacional +HAJU h Herbario Dr. Armando Jesus Urquiola +HAK s Hokkaido University, Faculty of Fisheries +HAKS s Hakgala Botanic Gardens +HAL s Martin-Luther-Universitaet +HALA s University of Alabama, Biological Sciences Department +HALE h Haleakala National Park +HALLE s Zoologisches Institut der Martin-Luther Universitaet +HALLST s Botanische Station +HALN h State Agency for Environmental Protection Saxony-Anhalt +HALX s Halifax Literary and Philosophical Society +HAM s Royal Botanical Gardens +HAMAB s Instituto de Pesquisas Cientificas e Tecnologicas do Estado do Amapa +HAMBI c HAMBI Culture Collection +HAMU s University of Newcastle upon Tyne +HAN s Universitaet Hannover +HANC h National Aquarium of Cuba +HANU s Harbin Normal University, Biology Department +HAO s Universidad Privada Antenor Orrego +HAQ s Institut der Technische Hochschule (RWTH), Institut fuer Biologie I +HAS s Fundacao Zoobotanica do Rio Grande do Sul +HAST s Research Center for Biodiversity, Academia Sinica +HASU s Universidade do Vale do Rio dos Sinos - CCS/ Centro 2 +HAU h Alzahra University +HAUH s Haryana Agricultural University +HAVI s Eastern Mennonite University, Biology Department +HAVO s Hawaii Volcanoes National Park +HAW s University of Hawaii, Botany Department +HAX s Belle Vue Museum +HAY s California State University, Biological Sciences Department +HB s Herbarium Bradeanum +HBA h National Botanic Garden of Latvia +HBARC h Bhabha Atomic Research Centre +HBAU s Hebei Agricultural University +HBAUD s Hebei Agricultural University, Handan Branch, Agriculture Department +HBBS s Museo Civico di Scienze Naturali +HBC s Henry Brockhouse Collection +HBDC s Hebei Institute for Drug Control +HBFC s Hebei Forestry College, Basic Courses Department +HBFH s Harbor Branch Oceanographic Institution, Marine Botany Department +HBG s Institut fuer Allgemeine Botanik +HBG b Hiroshima Botanical Garden +HBI s Institute of Hydrobiology, Chinese Academy of Sciences, Phycology Department +HBIL s Institut d'Estudis Ilerdencs +HBNU s Hebei Normal University, Biology Department +HBOM s Harbor Branch Oceanographic Museum HBOI +HBR s Universidade Federal de Santa Catarina +HBRA h Universidade Federal do Para, Campus Braganca +HBUM s College of Life Sciences Hebei Univesity, Baoding +HC s Hangchow Christian College +HCAT s University of Tabriz, Landscape Department +HCB s Universidade de Santa Cruz do Sul, Departamento de Biologia +HCCA s Hastings College +HCCN h National Institute of Agricultural Science and Technology +HCCV s Hastings College, Collection of Vertebrates +HCDAL h Universidade Regional do Cariri +HCEN s Universidad Nacional del Centro del Peru +HCF h Universidade Tecnologica Federal do Parana +HCH s Lewis-Clark State College, Natural Sciences Department +HCHM s Hope College, Biology Department +HCIB s Centro de Investigaciones Biologicas del Noroeste, S. C. +HCIO s Indian Agricultural Research Institute +HCMS s Hampshire County Council Museums Service +HCMZ s Hope College +HCNHSC s Ohio Historical Society, Natural History Synoptic Collection +HCOA s College of the Atlantic, Herbarium +HCOM h Centre d'Oceanologie de Marseille - University of Aix-Marseille II +HCT s Taiwan Forestry Research Institute +HCTR s Hoogstraal Center for Tick Research +HDCF h Department of Forestry Science +HDD s Tolson Museum, Natural History Department +HDJF h Universidade Federal dos Vales do Jequitinhonha e Mucuri +HDOA s Hawaii Department of Agriculture +HDSM s University of Massachusetts Dartmouth +HDTC s Huddersfield Technical College +HEAC s Henan Agricultural University +HEB s Hebden Bridge Literary and Scientific Society +HEBI s Henan Academy of Sciences +HECM s Henan College of Traditional Chinese Medicine +HEFG s l'Ecole de Faune de Garoua +HEH s Escuela Nacional de Ciencias Forestales, Departamento de Investigacion Forestal Aplicada +HEID s Universitaet Heidelberg, Heidelberger Institut fuer Pflanzenwissenschaften +HEL s University of Helsinki, Section of Botany +HEM h Universidad de Ciencias y Artes de Chiapas +HEMS s Haslemere Educational Museum +HENA s Escuela Nacional de Agricultura +HEND s Henderson State University, Biology Department +HENNU s Henan Normal University +HENU s Henan Normal University, Biology Department +HEPH s Jardim Botanico de Brasilia +HER c Felix d'Herelle Reference Center for Bacterial Viruses (Bacteriophage) +HER s Hermanus Botanical Society +HERBAM h Universidade do Estado de Mato Grosso +HERT h Fundacao Universidade Estadual do Ceara +HERZ s Herzen State Pedagogical University of Russia, Department of Botany +HERZU s Universidad del Zulia +HEUS h Universidad de Sucre +HF s Universidade Federal do Para +HFB s Hainan Forestry Bureau +HFBG s Forestry Botanical Garden of Heilongjiang +HFCC c Flagellate Culture Collection, University of Cologne +HFD s Hereford Museum +HFLA h Sapienza University of Rome - Scuola di Specializzazione in Beni Naturali e Territoriali +HFN h Herbarium Frisicum +HFP c Hokkaido Forest Products Research Institute +HFR s Finnish Forest Research Institute +HFRI s Hunan Forestry Research Institute +HFSL h Centro de Ensino, Faculdade Sao Lucas Ltda. +HFU s Herbarium of Fayoum University +HFV s Universidad Austral de Chile, Instituto de Produccion y Sanidad Vegetal +HFX s Bankfield Museum and Art Gallery +HGAS s Guizhou Academy of Sciences, Plant Taxonomy Group +HGCRL s Gulf Coast Research Laboratory +HGI s Universitat de Girona, Unitat de Biologia Vegetal +HGM s Hunan Geological Museum +HGOM h Universidad Autonoma del Estado de Hidalgo +HGS s Public Museum and Art Gallery, St. John's Place +HGTC s Huanggang Teachers College, Biology Department +HGU h Khakass State University +HH h Instituto de Investigaciones de la Amazonia Peruana +HHBG s Hangzhou Botanical Garden +HHC s University of Helsinki, Horticulture Department +HHH s Hartwick College +HHM s Collyer's School +HHU s Hallym University +HHUA s Universidad Nacional de Huanuco Hermilio Valdizan +HHUF s Hirosaki University, Laboratory of Plant Pathology +HIB s Wuhan Institute of Botany +HIBG h Hiroshima Botanical Garden +HIC s University of Kentucky, Department of Entomology, Hymenoptera Institute Collection +HIFP s French Institute +HILL s Sir Harold Hillier Gardens +HIMC s Inner Mongolia University +HIN s Hitchin Priory +HIP s Universidad de Magallanes +HIPC s Instituto Superior Pedagogico Jose Marti, Departamento de Biologia +HIRO s Hiroshima University, Biological Science Department +HIRU s Okayama University of Science +HISA h Universidade Estadual Paulista +HITBC s Xishuangbanna Tropical Botanical Garden, Chinese Academy of Sciences +HIUW s Hygiene-Institut der Universitaet +HIWNT s Hampshire and Isle of Wight Naturalists' Trust Ltd. +HJBC h Jardin Botanico Culiacan +HJBL s Escuela Nacional de Ciencias Forestales +HJBS s Fundacio Jardi Botanic de Soller +HK s Agriculture, Fisheries, and Conservation Department +HKAS s Cryptogamic Herbarium of Kunming Institute of Botany, Chinese Academy of Sciences +HKBU s Hong Kong Baptist University, Biology Department +HKFRS s Hong Kong Fisheries Research Station +HKGL s Naturwissenschaftliche Sammlungen des Kantons Glarus +HKI c Hans-Knoll Institute +HKM h University of Comoros +HKS h Research Center of Agricultural and Natural Resources Kurdistan Province +HKU s University of Hong Kong, Ecology and Biodiversity Department +HKUCC c The University of Hong Kong Culture Collection +HL s Houghton Lake Wildlife Research Station, Natural Resources Department +HL sb Hortus Botanicus Leiden +HLA s Harold L. Lyon Arboretum +HLCM s Heilongjiang College of Traditional Chinese Medicine, Department of Chinese Materia Medica +HLD s Hessisches Landesmuseum +HLDG h Las Cruces Biological Station, Organization for Tropical Studies +HLL s Queen's Gardens, College of Higher Education, Natural Science Department +HLMA s Town Docks Museum, Hull City Corporation +HLMD s Hessisches Landesmuseum Darmstadt +HLNM s Heilongjiang Provincial Museum +HLO s Vlastivedne Muzeum v Hlohovci +HLSD h Hillsdale College +HLU s University of Hull, Botany Department +HLUC s Universita degli Studi della Basilicata, Dipartimento di Biologia Difesa e Biotecnologie Agroforestali +HLUL s University of Hull +HLX s Ovenden Naturalists' Society +HM s Humbolt Museum +HM s Hastings Museum +HMAR h Universidade Federal do Ceara +HMAS sc Institute of Microbiology, Academia Sinica +HMC s Jardin Botanico de Las Tunas +HME s Haslemere Educational Museum +HMGBH h Giardini Botanici Hanbury / Hanbury Botanic Gardens +HMH s Hoebarth Museum Horn +HMIM h Jardi Botanic Marimurtra +HMJAU sc Herbarium of Mycology of Jilin Agricultural University +HMLN s District Museum +HMM s Horsham Museum +HMMNH h Macedonian Museum of Natural History +HMN s Humbolt Museum fur Naturkunde, East Berlin +HMNH s Hayashibara Museum of Natural History +HMNR h Mordovian State Nature Reserve +HMNS s Houston Museum of Natural Science +HMNT s Hancock Museum, Newcastle University +HMP s Hornonitrianske muzeum, Department of Natural History +HMS s Embrapa Gado de Corte +HMUG s Hunterian Museum +HN s National Center for Natural Sciences and Technology, Botany Department +HNBU s Institut de l'Environnement et de Recherche Agricola (INERA) +HNCMB c Hungarian National Collection of Medical Bacteria +HNG h Universite. Gamal Abdel Nasser de Conakry +HNH s Dartmouth College, Biological Sciences Department +HNHH s Heilongjiang Natural History Museum +HNHM s Hungarian Natural History Museum (Termeszettudomanyi Muzeum) HNHM:Moll c Hungarian Natural History Museum (Termeszettudomanyi Muzeum), Mollusca Collection -HNHM s Hannam University, Department of Biology -HNHPS h Hunan Hupingshan National Nature Reserve -HNHR s University of California, Hastings Natural History Reservation -HNIP s Hanoi College of Pharmacy -HNL h Conseil National des Sciences -HNM h Ecole Normale Superieure de Nouakchott -HNMN s Universidad Centroamericana -HNN s Horniman Museum of Natural History -HNNU s Hunan Normal University, Botany Department -HNPGBI h Seed and Plant Improvement Institute -HNR s Heilongjiang Academy of Sciences -HNT s Huntington Botanical Gardens -HNTS s Vlastivedne muzeum -HNU s Hunan Normal University -HNU s Vietnam National University, Department of Botany -HNUB s Northeastern University, Biology Department -HNUL h Northwestern University Inc. -HNWP s Northwest Plateau Institute of Biology, Chinese Academy of Sciences -HNWU s Nebraska Wesleyan University, Biology Department -HO s Tasmanian Museum & Art Gallery -HOH s Universitaet Hohenheim (210) -HOLZ s Paleontological Collection -HOMP s Okresni muzeum Pribram Brezove Hory -HON s Sichuan Grassland Research Institute -HOU s University of Houston -HOXA h Estacion biologica del Jardin Botanico de Missouri -HPAN h University of the State of Mato Grosso, UNEMAT -HPBR h Universidade Regional Integrada do Alto Uruguai e das Missoes -HPC s Howard Payne University, Biology Department -HPD s Hampstead Scientific Society -HPDL s Hampstead Public Library -HPH s Monroe County Department of Parks -HPL h Jardim Botanico Plantarum -HPM s Houston Museum of Natural Science -HPNP h Pumat National Park -HPP s University of Helsinki, Plant Biology Department -HPPR s Instituto Superior Pedagogico de Pinar del Rio, Departamento de Biologia -HPSU s Portland State University, Biology Department -HPU s High Point University, Biology Department -HPU s Hawaii Pacific University -HPUJ s Pontificia Universidad Javeriana -HPVC s Universidad Pedagogico Felix Varela,, Departamento de Biologia -HR s Muzeum Vychodnich Cech -HRB s IBGE -HRCB s Universidade Estadual Paulista -HREC h Hopland Research & Extension Center -HRJ s Universidade do Estado do Rio de Janeiro, Departamento de Biologia Animal e Vegetal -HRP s Universidad Nacional de La Patagonia, Departamento Biologia General -HSB s Universidad Mayor Real y Pontificia de San Francisco Xavier de Chuquisaca -HSBU h Shahid Beheshti University -HSC s Humboldt State University, Biological Sciences Department -HSCC c Culture Collection of the Research and Development Department -HSI s University of Helsinki, Silviculture Department -HSIB s Shanxi Institute of Biology, Botany Department -HSIC s Ministry of Natural Resources, Solomon Islands -HSM s Christ's Hospital, Biology Department -HSMC h Whyte Thorne Botanic Garden -HSNU s East China Normal University, Biology Department -HSP h Instituto Cientifico Michael Owen Dillon -HSS s Development, Technological and Investigacion Service, Forest Production Department -HSTM h Universidade Federal do Oeste do Para -HSU s Humboldt State University -HSU s Hardin-Simmons University, Biology Department -HSUCV s Hardin-Simmons University, Collection of Vertebrates -HSUD h Station of Nature Research and Environmental Education -HSUE s Natural History Museum, Addis Ababa -HSUMZ s Henderson State University, Museum of Zoology -HSUVM s Humboldt State University Vertebrate Museum -HTC s Hangzhou Normal College, Biology Department -HTD s College Natural History Society -HTE s Queen Ethelburga's School -HTGN s Norris Museum and Library -HTIN s Universidad Nacional Agraria de la Selva -HTN s Hitchin Museum -HTO s Universidade Federal do Tocantins, Nucleo de Estudos Ambientais -HTTU s Tennessee Technological University, Biology Department -HTU s University of Taiz, Biology Department -HTW h Universidad Nacional de la Patagonia San Juan Bosco -HU s University of Zhejiang -HUA s Universidad de Antioquia, Centro de Investigaciones -HUAA s Universidad Autonoma de Aquascalientes, Departamento de Biologia -HUAL s Universidad de Almeria, Departamento de Biologia Vegetal y Ecologia -HUAP s Herbario, Universidad Autonoma de Puebla -HUAZ h Universidad de la Amazonia -HUB s Hacettepe University, Botany Department -HUBE s Golden West College, Biology/Life Sciences Department -HUBO s Universita degli Studi di Bologna -HUC s Universidad de Cordoba, Departamento de Biologia -HUCM s Hunan College of Traditional Chinese Medicine, Department of Chinese Materia Medica -HUCP s Pontifica Universidade Catolica do Parana, Departamento de Ciencias Biologicas -HUCS h University of Caxias do Sul -HUDC s Howard University, Biology Department -HUE s Hunan Education College, Biology Department -HUEF s Hacettepe Ueniversitesi -HUEFS s Universidade Estadual de Feira de Santana, Departamento de Ciencias Biologicas -HUEG h Universidade Estadual de Goias -HUEM s Universidade Estadual de Maringa, Departamento de Biologia -HUESB h Universidade Estadual do Sudoeste da Bahia-Campus de Jequie -HUESBVC h Universidade Estadual do Sudoeste da Bahia-Vitoria da Conquista -HUF s Hunan Forestry School -HUFABC h Universidade Federal do ABC -HUFSJ h Universidade Federal de Sao Joao del-Rei -HUFU s Universidade Federal de Uberlandia, Instituto de Biologia -HUIC s Hacettepe University Ichthyological Collection -HUIF s Hunan Forestry Institute -HUJ s Hebrew University of Jerusalem +HNHM s Hannam University, Department of Biology +HNHPS h Hunan Hupingshan National Nature Reserve +HNHR s University of California, Hastings Natural History Reservation +HNIP s Hanoi College of Pharmacy +HNL h Conseil National des Sciences +HNM h Ecole Normale Superieure de Nouakchott +HNMN s Universidad Centroamericana +HNN s Horniman Museum of Natural History +HNNU s Hunan Normal University, Botany Department +HNPGBI h Seed and Plant Improvement Institute +HNR s Heilongjiang Academy of Sciences +HNT s Huntington Botanical Gardens +HNTS s Vlastivedne muzeum +HNU s Hunan Normal University +HNU s Vietnam National University, Department of Botany +HNUB s Northeastern University, Biology Department +HNUE s Hanoi National University of Education +HNUL h Northwestern University Inc. +HNWP s Northwest Plateau Institute of Biology, Chinese Academy of Sciences +HNWU s Nebraska Wesleyan University, Biology Department +HO s Tasmanian Museum & Art Gallery +HOH s Universitaet Hohenheim (210) +HOL s Holden Arboretum +HOLZ s Paleontological Collection +HOMP s Okresni muzeum Pribram Brezove Hory +HON s Sichuan Grassland Research Institute +HOU s University of Houston +HOXA h Estacion biologica del Jardin Botanico de Missouri +HPAN h University of the State of Mato Grosso, UNEMAT +HPBR h Universidade Regional Integrada do Alto Uruguai e das Missoes +HPC s Howard Payne University, Biology Department +HPD s Hampstead Scientific Society +HPDL s Hampstead Public Library +HPH s Monroe County Department of Parks +HPL h Jardim Botanico Plantarum +HPM s Houston Museum of Natural Science +HPNP h Pumat National Park +HPP s University of Helsinki, Plant Biology Department +HPPR s Instituto Superior Pedagogico de Pinar del Rio, Departamento de Biologia +HPSU s Portland State University, Biology Department +HPU s High Point University, Biology Department +HPU s Hawaii Pacific University +HPUJ s Pontificia Universidad Javeriana +HPVC s Universidad Pedagogico Felix Varela,, Departamento de Biologia +HR s Muzeum Vychodnich Cech +HRB s IBGE +HRCB s Universidade Estadual Paulista +HREC h Hopland Research & Extension Center +HRJ s Universidade do Estado do Rio de Janeiro, Departamento de Biologia Animal e Vegetal +HRP s Universidad Nacional de La Patagonia, Departamento Biologia General +HSB s Universidad Mayor Real y Pontificia de San Francisco Xavier de Chuquisaca +HSBU h Shahid Beheshti University +HSC s Humboldt State University, Biological Sciences Department +HSCC c Culture Collection of the Research and Development Department +HSI s University of Helsinki, Silviculture Department +HSIB s Shanxi Institute of Biology, Botany Department +HSIC s Ministry of Natural Resources, Solomon Islands +HSM s Christ's Hospital, Biology Department +HSMC h Whyte Thorne Botanic Garden +HSNU s East China Normal University, Biology Department +HSP h Instituto Cientifico Michael Owen Dillon +HSS s Development, Technological and Investigacion Service, Forest Production Department +HSTM h Universidade Federal do Oeste do Para +HSU s Humboldt State University +HSU s Hardin-Simmons University, Biology Department +HSUCV s Hardin-Simmons University, Collection of Vertebrates +HSUD h Station of Nature Research and Environmental Education +HSUE s Natural History Museum, Addis Ababa +HSUMZ s Henderson State University, Museum of Zoology +HSUVM s Humboldt State University Vertebrate Museum +HTC s Hangzhou Normal College, Biology Department +HTD s College Natural History Society +HTE s Queen Ethelburga's School +HTGN s Norris Museum and Library +HTIN s Universidad Nacional Agraria de la Selva +HTN s Hitchin Museum +HTO s Universidade Federal do Tocantins, Nucleo de Estudos Ambientais +HTTU s Tennessee Technological University, Biology Department +HTU s University of Taiz, Biology Department +HTW h Universidad Nacional de la Patagonia San Juan Bosco +HU s University of Zhejiang +HUA s Universidad de Antioquia, Centro de Investigaciones +HUAA s Universidad Autonoma de Aquascalientes, Departamento de Biologia +HUAL s Universidad de Almeria, Departamento de Biologia Vegetal y Ecologia +HUAP s Herbario, Universidad Autonoma de Puebla BUAP +HUAZ h Universidad de la Amazonia +HUB s Hacettepe University, Botany Department +HUBE s Golden West College, Biology/Life Sciences Department +HUBO s Universita degli Studi di Bologna +HUC s Universidad de Cordoba, Departamento de Biologia +HUCM s Hunan College of Traditional Chinese Medicine, Department of Chinese Materia Medica +HUCP s Pontifica Universidade Catolica do Parana, Departamento de Ciencias Biologicas +HUCS h University of Caxias do Sul +HUDC s Howard University, Biology Department +HUE s Hunan Education College, Biology Department +HUEF s Hacettepe Ueniversitesi +HUEFS s Universidade Estadual de Feira de Santana, Departamento de Ciencias Biologicas +HUEG h Universidade Estadual de Goias +HUEM s Universidade Estadual de Maringa, Departamento de Biologia +HUESB h Universidade Estadual do Sudoeste da Bahia-Campus de Jequie +HUESBVC h Universidade Estadual do Sudoeste da Bahia-Vitoria da Conquista +HUF s Hunan Forestry School +HUFABC h Universidade Federal do ABC +HUFSJ h Universidade Federal de Sao Joao del-Rei +HUFU s Universidade Federal de Uberlandia, Instituto de Biologia +HUIC s Hacettepe University Ichthyological Collection +HUIF s Hunan Forestry Institute +HUJ s Hebrew University of Jerusalem HUJ:INV s Hebrew University of Jerusalem, Invertebrate collection -HUKUK c Culture Collection of Animal Cells -HUL s Fine Arts Museum -HULE s Universidad Nacional Autonoma de Nicaragua, Departamento de Biologia -HUM s Humbolt University Zoologischen Museum -HUMC h Universidade de Mogi das Cruzes -HUMO s Universidad Autonoma del Estado de Morelos, Centro de Educacion Ambiental e Investigacion Sierra de Huautla -HUMP s Muzeum v Humpolci -HUMZ s Hokkaido University, Laboratory of Marine Zoology -HUNEB h Universidade do Estado da Bahia -HUNT h Huntington University -HUP h Hazara University -HUPG s State University of Ponta Grossa, Departamento de Biologia -HUQ s Universidad del Quindio -HURB h Universidade Federal do Reconcavo da Bahia -HURG s Universidade do Rio Grande, Departamento de Ciencias Morfo-Biologicas -HUS h Siauliai University -HUSA s Universidad Nacional de San Agustin de Arequipa, Facultad de Ciencias Biologicas y Agropecuarias, Area de Biomedicas -HUSC h Universidade Santa Cecilia - UNISANTA -HUSEC c Konsiliarlabor fur Hamolytisch-Uramisches Syndrom -HUST s Hunan University of Science and Technology, School of Life Sciences -HUT c HUT Culture Collection -HUT s Herbarium Truxillense, Universidad Nacional de La Libertad-Trujillo -HUTB s Hainan University -HUTI h Universidad Tecnologica Indoamerica -HUTM s Hunan Academy of Traditional Chinese Medicine and Pharmacy -HUTO s Fundacao Universidade do Tocantins , UNITINS -HUTPL s Universidad Tecnica Particular De Loja -HUVA h Universidade Estadual Vale do Acarau -HVASF h Universidade Federal do Vale do Sao Francisco -HVR s Universidade de Tras-os-Montes e Alto Douro -HWA s Southwest Agricultural University, Department of Biological Basic Courses -HWB s Harrow School, Biology Department -HWBA s Benedictine College, Biology Department -HWD s Hollinwood Botanists' and Field Naturalists' Society -HWML s Howard W. Manter Laboratory of Parasitology -HXBH s Fundacao CETEC -HXC s Hendrix College, Biology Department -HY s Osmania University, Botany Department -HYD s Heywood and District Botanical Society -HYO s Museum of Nature and Human Activities -Hyogo s Museum of Nature and Human Activities -HZI c Helmholtz Zentrum fur Infektionsforschung (Helmholtz Centre for Infection Research) -HZM s Museum of Natural History (Hrvatski Zooloski Muzej) -HZMZ s Hrvatski Narodni Zooloski Muzej -HZTC s Hanzhong Teachers College, Biology Department -HZU s Zhejiang University -I s Universitatea Al. I. Cuza Iasi -IA s University of Iowa, Department of Biological Sciences -IAA s Instituto Antarctico Argentinao, Direccion Nacional del Antartico -IAAA s Instituto do Acucar e do Alcool -IABH s Al-Bayt University, Biology Department -IABHU scb Institute for Amphibian Biology, Graduate School of Science, Hiroshima University -IAC s Instituto Agronomico de Campinas -IACC s Instituto Agronomico de Campinas -IACM s Instituto Agronomico -IADIZA-CM s Instituto Argentino de Investigaciones de las Zonas Aridas -IAFB c Collection of Industrial Microorganisms -IAGB s Universitatea Al. I. Cuza Iasi -IAL s Herbario, Centro Nacional de Pesquisa de Mandioca e Fruticultura, EMBRAPA -IAL c Secao de Colecao de Culturas -IALCEL c Secao de Culturas Celulares -IALMIC c Micoteca do Insituto Adolfo Lutz -IAM c IAM Culture Collection, Center for Cellular and Molecular Research -IAN s Embrapa Amazonia Oriental -IAPG s Institute of Animal Physiology and Genetics, Academy of Sciences of the Czech Republic -IARI sb Indian Agricultural Research Institute -IASI s Universitatea Agronomica, Disciplina de Botanica -IAUGH h Islamic Azad University Garmsar -IAUH h Islamic Azad University -IAUM h Islamic Azad University of Mashhad -IAUNT h Islamica Azad University, North Tehran Branch -IAV sb Institut Agronomique et Veterinaire Hassan II, Departement d'Ecologie Vegetale -IAVH s Instituto de Ivestigacion de los Recursos Biologicos Alexander von Humboldt -IB s Universitaet Innsbruck -IBA s Instituto Asturiano de Taxonomia y Ecologia Vegetal -IBA c Collection of Microorganisms Producing Antibiotics -IBAR h Ibaraki University -IBAUNC s Universidad Nacional de Cuyo, Instituto de Biologia Animal -IBE s Institute for Botanical Exploration -IBE s Institut de Biologia Evolutiva, (CSIC-UPF) -IBEF s Museum of the Izumi Board of Education -IBF s Tiroler Landesmuseum Ferdinandeum -IBGE s Reserva Ecologica do IBGE -IBH s Universidad Nacional Autonoma de Mexico, Instituto de Biologia -IBI s Instituto Biologico, Laboratorio de Micologia -IBIR s Institutul Agronomic -IBIW s I. D. Papanin Institute for Biology of Inland Waters -IBK s Guangxi Institute of Botany -IBL s Independent Biological Laboratories -IBL c Botanical Institute, Lisbon Faculty of Sciences -IBL c Insect Biocontrol Laboratory (USDA-ARS, Beltsville) -IBLP s Instytut Badawczy Lesnictwa -IBMUNC s Universidad Nacional de Cuyo, Instituto de Biologia Animal -IBP s Instituto de Biologia do Parana -IBPPM c Institute of Biochemistry and Physiology of Plants and Microorganisms of the Russian Academy of Sciences -IBRC sc Iranian Biological Resource Center -IBRP s Instituto Biologico de Ribeirao Preto -IBRP s Institute for Breeding Research, Tokyo University of Agriculture -IBS s Irish Biogeographical Society -IBSBF c Biological Institute Culture Collection of Phytopathogenic Bacteria -IBSC s South China Botanical Garden -IBSD s Dinghushan Biosphere Reserve -IBSP s Instituto Biologico de Sao Paulo -IBT c IBT Culture Collection of Fungi, Mycology Group, Technical University of Denmark -IBTS s Institutul de Biologie, Tr. Savulescu -IBUG s Universidad de Guadalajara -IBUNAM s Instituto de Biologia, Universidad Nacional Autonoma de Mexico +HUKUK c Culture Collection of Animal Cells +HUL s Fine Arts Museum +HULE s Universidad Nacional Autonoma de Nicaragua, Departamento de Biologia +HUM s Humbolt University Zoologischen Museum +HUMC h Universidade de Mogi das Cruzes +HUMO s Universidad Autonoma del Estado de Morelos, Centro de Educacion Ambiental e Investigacion Sierra de Huautla +HUMP s Muzeum v Humpolci +HUMZ s Hokkaido University, Laboratory of Marine Zoology +HUNEB h Universidade do Estado da Bahia +HUNT h Huntington University +HUP h Hazara University +HUPG s State University of Ponta Grossa, Departamento de Biologia +HUQ s Universidad del Quindio +HURB h Universidade Federal do Reconcavo da Bahia +HURG s Universidade do Rio Grande, Departamento de Ciencias Morfo-Biologicas +HUS h Siauliai University +HUSA s Universidad Nacional de San Agustin de Arequipa, Facultad de Ciencias Biologicas y Agropecuarias, Area de Biomedicas +HUSC h Universidade Santa Cecilia - UNISANTA +HUSEC c Konsiliarlabor fur Hamolytisch-Uramisches Syndrom +HUST s Hunan University of Science and Technology, School of Life Sciences +HUT c HUT Culture Collection +HUT s Herbarium Truxillense, Universidad Nacional de La Libertad-Trujillo +HUTB s Hainan University +HUTI h Universidad Tecnologica Indoamerica +HUTM s Hunan Academy of Traditional Chinese Medicine and Pharmacy +HUTO s Fundacao Universidade do Tocantins , UNITINS +HUTPL s Universidad Tecnica Particular De Loja +HUVA h Universidade Estadual Vale do Acarau +HVASF h Universidade Federal do Vale do Sao Francisco +HVR s Universidade de Tras-os-Montes e Alto Douro +HWA s Southwest Agricultural University, Department of Biological Basic Courses +HWB s Harrow School, Biology Department +HWBA s Benedictine College, Biology Department +HWD s Hollinwood Botanists' and Field Naturalists' Society +HWML s Howard W. Manter Laboratory of Parasitology UNSM:HWML +HXBH s Fundacao CETEC +HXC s Hendrix College, Biology Department +HY s Osmania University, Botany Department +HYD s Heywood and District Botanical Society +HYO s Museum of Nature and Human Activities +Hyogo s Museum of Nature and Human Activities +HZI c Helmholtz Zentrum fur Infektionsforschung (Helmholtz Centre for Infection Research) +HZM s Museum of Natural History (Hrvatski Zooloski Muzej) +HZMZ s Hrvatski Narodni Zooloski Muzej +HZTC s Hanzhong Teachers College, Biology Department +HZU s Zhejiang University +I s Universitatea Al. I. Cuza Iasi +IA s University of Iowa, Department of Biological Sciences +IAA s Instituto Antarctico Argentinao, Direccion Nacional del Antartico +IAAA s Instituto do Acucar e do Alcool +IABH s Al-Bayt University, Biology Department +IABHU scb Institute for Amphibian Biology, Graduate School of Science, Hiroshima University +IAC s Instituto Agronomico de Campinas +IACC s Instituto Agronomico de Campinas +IACM s Instituto Agronomico +IADIZA-CM s Instituto Argentino de Investigaciones de las Zonas Aridas +IAFB c Collection of Industrial Microorganisms +IAGB s Universitatea Al. I. Cuza Iasi +IAL s Herbario, Centro Nacional de Pesquisa de Mandioca e Fruticultura, EMBRAPA +IAL c Secao de Colecao de Culturas +IALCEL c Secao de Culturas Celulares +IALMIC c Micoteca do Insituto Adolfo Lutz +IAM c IAM Culture Collection, Center for Cellular and Molecular Research +IAM s National Alliance of Shidlovskiy "Ice Age", Ice Age Museum +IAN s Embrapa Amazonia Oriental +IAPG s Institute of Animal Physiology and Genetics, Academy of Sciences of the Czech Republic +IARI sb Indian Agricultural Research Institute +IASI s Universitatea Agronomica, Disciplina de Botanica +IAUGH h Islamic Azad University Garmsar +IAUH h Islamic Azad University +IAUM h Islamic Azad University of Mashhad +IAUNT h Islamica Azad University, North Tehran Branch +IAV sb Institut Agronomique et Veterinaire Hassan II, Departement d'Ecologie Vegetale +IAVH s Instituto de Ivestigacion de los Recursos Biologicos Alexander von Humboldt +IB s Universitat Innsbruck +IBA s Instituto Asturiano de Taxonomia y Ecologia Vegetal +IBA c Collection of Microorganisms Producing Antibiotics +IBAR h Ibaraki University +IBAUNC s Universidad Nacional de Cuyo, Instituto de Biologia Animal +IBBS s Insitute of Biology and Soil Science, Russian Academy of Sciences +IBE s Institute for Botanical Exploration +IBE s Institut de Biologia Evolutiva, (CSIC-UPF) +IBEF s Museum of the Izumi Board of Education +IBF s Tiroler Landesmuseum Ferdinandeum +IBGE s Reserva Ecologica do IBGE +IBH s Universidad Nacional Autonoma de Mexico, Instituto de Biologia +IBI s Instituto Biologico, Laboratorio de Micologia +IBIR s Institutul Agronomic +IBIW s I. D. Papanin Institute for Biology of Inland Waters +IBK s Guangxi Institute of Botany +IBL s Independent Biological Laboratories +IBL s Forest Research Institute, Poland +IBL c Botanical Institute, Lisbon Faculty of Sciences +IBL c Insect Biocontrol Laboratory (USDA-ARS, Beltsville) +IBLP s Instytut Badawczy Lesnictwa +IBMUNC s Universidad Nacional de Cuyo, Instituto de Biologia Animal +IBP s Instituto de Biologia do Parana +IBPPM c Institute of Biochemistry and Physiology of Plants and Microorganisms of the Russian Academy of Sciences +IBRC sc Iranian Biological Resource Center +IBRP s Instituto Biologico de Ribeirao Preto +IBRP s Institute for Breeding Research, Tokyo University of Agriculture +IBS s Irish Biogeographical Society +IBSBF c Biological Institute Culture Collection of Phytopathogenic Bacteria +IBSC s South China Botanical Garden +IBSD s Dinghushan Biosphere Reserve +IBSP s Instituto Biologico de Sao Paulo +IBT c IBT Culture Collection of Fungi, Mycology Group, Technical University of Denmark +IBTS s Institutul de Biologie, Tr. Savulescu +IBUG s Universidad de Guadalajara +IBUNAM s Instituto de Biologia, Universidad Nacional Autonoma de Mexico UNAM IBUNAM:CFB b Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion de Fotocolectas Biologicas IBUNAM:CNAC s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Acaros IBUNAM:CNAN s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Aracnidos @@ -2672,653 +2697,660 @@ IBUNAM:CNAR s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Co IBUNAM:CNAV s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Aves IBUNAM:CNCR s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Crustaceos IBUNAM:CNHE s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Helmintos -IBUNAM:CNIN s Coleccion Nacional de Insectos, Universidad Nacional Autonoma de Mexico +IBUNAM:CNIN s Coleccion Nacional de Insectos, Universidad Nacional Autonoma de Mexico IBUNAM:CNIN IBUNAM:CNIN s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Insectos IBUNAM:CNMA s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Mamiferos IBUNAM:CNMO s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Moluscos IBUNAM:CNPE s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Peces IBUNAM:MEXU s Instituto de Biologia, Universidad Nacional Autonoma de Mexico, Herbario Nacional -IBUP s Institute of Biology -IBUS s Universidade Federal do Rio de Janeiro -IBUT s Instituto Butanta -IBY s Botanical Institute of Guangxi -ICA s Instituto Colombiano Agropecuario, Tibaitata -ICARDA sb International Center for Agricultural Research in the Dry Areas -ICBB c ICBB Culture Collection for Microorganisms and Cell Culture -ICBU s Bishop's University, Natural History Museum -ICCF c Collection of Industrial Microorganisms -ICEB s Eurouniversity -ICEL s Icelandic Institute of Natural History -ICF s INIFAP -ICFC c IIB-INTECH Collection of Fungal Cultures -ICGC s Istituto Calasanzio -ICHUM s Invertebrate Collection of the Hokkaido University Museum -ICIS s Idaho Museum of Natural History -ICM s Instituto de Ciencias del Mar -ICMP c International Collection of Micro-organisms from Plants -ICN s Universidade Federal do Rio Grande do Sul, Departamento de Botanica -ICN s Instituto de Ciencias Naturales, Museo de Historia Natural -ICP s Islamia College, University of Peshawar, Botany Department -ICPB c International Collection of Phytopathogenic Bacteria -ICPPB s International Collection of Plant Pathogenic Bacteria -ICPR s Biological Control Research Institute -ICRC s Insect Control and Research -ICRG s Institute of Entomology -ICRI s Zhonghan (Sun Yat-Sen) University, Research Institute of Entomology -ICRISAT b International Crops Research for the Semi-Arid Tropics -ICS-CC c Infection Control Services , National Health Laboratory Service 3 -ICST s Imperial College of Science, Technology & Medicine, Department of Biological Sciences -ICUI s University of Iowa -ICVI s The Volcani Center -ID s University of Idaho, Biological Sciences Department -IDAC cb The International Depositary Authority of Canada -IDEA s Instituto de Agronomia -IDF s University of Idaho -IDS s Idaho State University, Biological Sciences Department -IE sc Cepario de Hongos del Instituto de Ecologia -IEA s Instituto DI Entomologia Agraria -IEAB s Istituto di Entomologia Agraria dell'Universita -IEAM s Istituto di Entomologia dell'Universita degli Studi [= Istituto di Entomologia Agraria dell'Universita, Milan] -IEAP s Istituto di Entomologia Agraria dell'Universita -IEAPM c Instituto de Estudos do Mar "Almirante Paulo Moreira" -IEAS s Institute of Entomology -IEAU s Istituto di Entomologia Agraria dell'Universita -IEB s Instituto de Ecologia, A.C. -IEBC c International Entomopathogenic Bacillus Centre (WHO) -IEBR s Institute of Ecology and Biological Resources -IEC s Centre D'Etude sur les Ressources Vegetales -IECA s Czech Academy of Science, Institute of Entomology -IEEUACH s Universidad Austral de Chile, Instituto de Ecologia y Evolucion -IEGG s Universita di Bologna, Istituto di Entomologia "Guido Grandi" -IEGM c Regional Specialized Collection of Alkanotrophic Microorganisms -IEI s Institut d'Estudis Ilerdencs -IEM c Czech National Collection of Type Cultures -IEME s Institute for Evolution, Morphology, and Ecology of Animals -IEMM s Instituto de Ecologia -IENU s Istituto di Entomologia, Universita degli Studi -IEPA s Istituto di Entomologia Agraria dell'Universita -IER h Institut d'Economie Rurale -IEUC s Istituto di Entomologia Agraria dell'Universita Cattolica -IEUP s Istituto di Entomologia, Universita degli Studi -IEVB s Institut de Zoologie [Institut Ed. Van Beneden] -IFAM c Institut fur Allgemeine Mikrobiologie -IFAN s Institut Fondamental d'Afrique Noire -IFBM c Streptokokken Sammlung -IFE s Obafemi Awolowo University, Botany Department -IFFB s Institut fuer Forstenentomologie und Forstschutz -IFG s Institute of Forest Genetics -IFGD s Idaho Fish and Game -IFGH s Idaho Fish and Game Department -IFGP s Pacific Southwest Research Station, USDA Forest Service -IFI s Imperial Fisheries Institute -IFM c IFM Quality Services Pty Ltd -IFM c Research Center for Pathogenic Fungi and Microbial Toxicoses, Chiba University -IFO c Institute for Fermentation -IFP s Institute of Applied Ecology, Academia Sinica -IFRD h Research Institute of Resource Insects -IFRDCC c International Fungal Research and Development Culture Collection -IFREMER s Institut Francais pour l'Etude de la Mer -IFRI s Indian Forest Research Institute -IFRPD c Institute of Food Research and Product Development, Kasetsart University -IFSA s Instituto Florestal -IG s Institute of Geology -IGB sb Israel Plant Gene Bank -IGC c Portuguese Yeast Culture Collection -IGCAGS s Institute of geology, Chinese Academy of Geological Science -IGCU s Instituto de Geologia, Ciudad Universitaria -IGESALQ c Colecao Microorganismos -IGF s Instituto di Geologia e Paleontologia -IGGDC h Institute of Geology and Geophysics, Chinese Academy of Sciences -IGL s Institute fuer Geowissenschaften Leoben -IGM s Instituto de Geologia -IGM s Geological Institute, Mongolian Academy of Sciences -IGPH s Institut fuer Geologie und Palaeontologie der Universitat Hannover -IGUS s Universitat des Saarlandes -IGWH s Institut fuer Geowissenschaften aus dem Martin-Lurther- Universitat -IH s Instituto de Segunda Ensenanza de La Habana -IHASW s Institute of Hydrobiology, Academia Sinica -IHB s Institute of Hydrobiology, Chinese Academy of Sciences -IHCAS s Museum of Institute of Hydrobiology, Chainese Academy of Sciences -IHEM c Scientific Institute of Public Health, Mycology Section -IHUG s Institut fuer Hygiene der Iniversitaet -IIBM-UNAM c Industrial Culture Collection -IIBUV s Investigaciones Biologicas de la Universidad Veracruzana (Mexico) -IICT s Centro de Zoologia do I.I.C.T. -IID c Laboratory Culture Collection -IIES s Instituto Investigaciones Entomologicas Salta -IIPB s Instituto de Ciencias del Mar -IITA b International Institute of Tropical Agriculture -IJ s Institute of Jamaica -IJFM c Instituto Jaime Ferran de Microbiologia Consejo Superior de Investigaciones Cientificas -IJSM s Institute of Jamaica, Natural History Museum -IK s Zoological Institute, Ukrainian Academy of Sciences -ILCA s International Livestock Research Institute -ILF s Iflracombe Museum -ILH s Iowa Lakeside Laboratory -ILL sc University of Illinois, Plant Biology Department -ILLS s Illinois Natural History Survey -ILMA s Istituto Leonardo Murialdo -ILPLA s Museo de La Plata, Instituto de Limnologia -IM s Instituto de Segunda Ensenanza de Matanzas -IM s Indian Museum -IMAGE b The I.M.A.G.E Consortium -IMARPE s Instituto del Mar del Peru -IMAS c Institute for Marine and Antarctic Studies -IMAU c Inner Mongolia Agricultural University, Key Laboratory of Dairy Biotechnology and Engineering -IMC s Sichuan Academy of Traditional Chinese Medicine and Pharmacy -IMCC c Inha Microbe Culture Collection, Inha University -IMCN s Instituto Vallecaucano de Investigaciones Cientificas -IMD c Industrial Microbiology Dublin -IMD s Institute of Medicinal Plant Development, Chinese Academy of Medical Sciences -IMDC s Inner Mongolia Institute for Drug Control -IMDY s Chinese Academy of Medical Sciences, Yunnan Branch -IMET c National Kurturensammlung fuer Mikroorganismen -IMFA s Inner Mongolia Academy of Forestry -IMI sc CABI Bioscience Genetic Resource Collection -IML s Instituto Miguel Lillo -IMLA s Fundacion e Instituto Miguel Lillo -IMM s Chinese Academy of Medical Science -IMM s Inner Mongolian Museum -IMMH c Collection of Animal Viruses -IMMIB c Culture Collection of the Institute of Medical Microbiology and Immunology of the University of Bonn -IMPC s Sichuan Academy of Traditional Chinese Medicine and Pharmacy -IMRU c Waksman Institute of Microbiology -IMS s Institute of Marine Sciences -IMS s University of North Carolina at Chapel Hill -IMSNU c Institute of Microbiology, Seoul National University -IMSSM s Instituto Mexicano del Seguro Social -IMT c Micoteca do Instituto de Medicina Tropical de Sao Paulo -IMT s Imperial Museum -IMTU s Institute of Medicine, Community Medicine Department -IMUFRJ c Instituto de Microbiologia of Universidade Federal do Rio de Janeiro -IMVS c IMVS Culture Collection -IMYZA c Instituto de Microbiologia y Zoologia Agricola -INA s Instituto Nun'Alvres, Departamento de Biologia -INA c Culture Collection of the Institute of New Antibiotics -INALI s Instituto Limnologia -INB s Instituto Nacional de Biodiversidad, Departamento de Botanica -INBC s Instituto Nacional de Biodiversidad (INBio) -INBio s National Biodiversity Institute, Costa Rica -INBP s Inventorio Biologico Nacional [Museo Nacional de Historia Natural del Paraguay] -INC s Instituto Nacional de Cultura, Museo de Ciencias Naturales (Panama) -INCQS c Fundacao Oswaldo Cruz-FIOCRUZ -IND s Indiana University, Department of Biology -IND-AN s Amphibian Collection -IND-M s La Unidad de Investigacion "Federico Medem"-Inderena (Colombia) -INDRE c Pathogen Fungi and Actinomycetes Collection -INEGI s Instituto Nacional de Estadistica Geografia e Informatica, Departamento de Botanica -INEP h Institute of the Industrial Ecology Problems of the North of Kola Science Center of the Russian Academy of Sciences. -INER s Istituto Nazionale di Entomologia -INFYB s Instituto Nacional de Farmacologia y Bromatologia, Farmacobotanica -INGU h Ingush State University -INH s Institut National d'Horticulture, Departement de Sciences Biologiques -INHM s Iraq Natural History Museum -INHS s Illinois Natural History Survey -INIA s Instituto Nacional de Investigaciones Forestales y Agropecurias -INIA b El Instituto de Investigaciones Agropecuarias -INIA b Instituto Nacional de Investigacion y Tecnologia Agraria y Alimentaria -INIBP s Instituto Nacional de Investigaciones Biologico Pesqueras -INIDA s Instituto Nacional de Investigacao e Desenvolvimento Agrario - Cape Verde -INIDEP s Instituto Nacional de Investigacion y Desarrollo Pesquero -INIF c Coleccion de Microhongos -INIFAT c INIFAT Fungus Collection -INIP s Instituto Nacional de Investigacao das Pescas -INIR s Coleccion de Termitas Mexicanas -INLA s INIA Subestacion Experimental Control Biologico La Cruz -INM s Ibaraki Nature Museum -INMI c Institute of Microbiology, Russian Academy of Sciences -INPA s Instituto Nacional de Pesquisas da Amazonia +IBUP s Institute of Biology +IBUS s Universidade Federal do Rio de Janeiro +IBUT s Instituto Butanta +IBY s Botanical Institute of Guangxi +ICA s Instituto Colombiano Agropecuario, Tibaitata +ICARDA sb International Center for Agricultural Research in the Dry Areas +ICBB c ICBB Culture Collection for Microorganisms and Cell Culture +ICBU s Bishop's University, Natural History Museum +ICCF c Collection of Industrial Microorganisms +ICEB s Eurouniversity +ICEL s Icelandic Institute of Natural History +ICF s INIFAP +ICFC c IIB-INTECH Collection of Fungal Cultures +ICGC s Istituto Calasanzio +ICHUM s Invertebrate Collection of the Hokkaido University Museum +ICIS s Idaho Museum of Natural History +ICM s Instituto de Ciencias del Mar ICMD +ICMP c International Collection of Microorganisms from Plants PDDCC +ICN s Universidade Federal do Rio Grande do Sul, Departamento de Botanica +ICN s Instituto de Ciencias Naturales, Museo de Historia Natural +ICP s Islamia College, University of Peshawar, Botany Department +ICPB c International Collection of Phytopathogenic Bacteria +ICPPB s International Collection of Plant Pathogenic Bacteria +ICPR s Biological Control Research Institute +ICRC s Insect Control and Research +ICRG s Institute of Entomology +ICRI s Zhonghan (Sun Yat-Sen) University, Research Institute of Entomology +ICRISAT b International Crops Research for the Semi-Arid Tropics +ICS-CC c Infection Control Services , National Health Laboratory Service 3 +ICST s Imperial College of Science, Technology & Medicine, Department of Biological Sciences +ICUI s University of Iowa +ICVI s The Volcani Center +ID s University of Idaho, Biological Sciences Department +IDAC cb The International Depositary Authority of Canada +IDEA s Instituto de Agronomia +IDF s University of Idaho +IDS s Idaho State University, Biological Sciences Department +IE sc Cepario de Hongos del Instituto de Ecologia +IEA s Instituto DI Entomologia Agraria +IEAB s Istituto di Entomologia Agraria dell'Universita +IEAM s Istituto di Entomologia dell'Universita degli Studi [= Istituto di Entomologia Agraria dell'Universita, Milan] +IEAP s Istituto di Entomologia Agraria dell'Universita +IEAPM c Instituto de Estudos do Mar "Almirante Paulo Moreira" +IEAS s Institute of Entomology +IEAU s Istituto di Entomologia Agraria dell'Universita +IEB s Instituto de Ecologia, A.C. +IEBC c International Entomopathogenic Bacillus Centre (WHO) +IEBR s Institute of Ecology and Biological Resources +IEC s Centre D'Etude sur les Ressources Vegetales +IECA s Czech Academy of Science, Institute of Entomology +IEEUACH s Universidad Austral de Chile, Instituto de Ecologia y Evolucion +IEGG s Universita di Bologna, Istituto di Entomologia "Guido Grandi" +IEGM c Regional Specialized Collection of Alkanotrophic Microorganisms +IEI s Institut d'Estudis Ilerdencs +IEM c Czech National Collection of Type Cultures +IEME s Institute for Evolution, Morphology, and Ecology of Animals +IEMM s Instituto de Ecologia +IENU s Istituto di Entomologia, Universita degli Studi +IEPA s Istituto di Entomologia Agraria dell'Universita +IER h Institut d'Economie Rurale +IEUC s Istituto di Entomologia Agraria dell'Universita Cattolica +IEUP s Istituto di Entomologia, Universita degli Studi +IEVB s Institut de Zoologie [Institut Ed. Van Beneden] +IFAM c Institut fur Allgemeine Mikrobiologie +IFAN s Institut Fondamental d'Afrique Noire +IFBM c Streptokokken Sammlung +IFE s Obafemi Awolowo University, Botany Department +IFFB s Institut fuer Forstenentomologie und Forstschutz +IFG s Institute of Forest Genetics +IFGD s Idaho Fish and Game +IFGH s Idaho Fish and Game Department +IFGP s Pacific Southwest Research Station, USDA Forest Service +IFI s Imperial Fisheries Institute +IFM c IFM Quality Services Pty Ltd +IFM c Research Center for Pathogenic Fungi and Microbial Toxicoses, Chiba University +IFO c Institute for Fermentation +IFP s Institute of Applied Ecology, Academia Sinica +IFRD s Research Institute of Resource Insects +IFRDCC c International Fungal Research and Development Culture Collection +IFREMER s Institut Francais pour l'Etude de la Mer +IFRI s Indian Forest Research Institute +IFRPD c Institute of Food Research and Product Development, Kasetsart University +IFSA s Instituto Florestal +IG s Institute of Geology +IGB sb Israel Plant Gene Bank +IGC c Portuguese Yeast Culture Collection +IGCAGS s Institute of geology, Chinese Academy of Geological Science +IGCU s Instituto de Geologia, Ciudad Universitaria +IGESALQ c Colecao Microorganismos +IGF s Instituto di Geologia e Paleontologia +IGGDC h Institute of Geology and Geophysics, Chinese Academy of Sciences +IGL s Institute fuer Geowissenschaften Leoben +IGM s Instituto de Geologia +IGM s Geological Institute, Mongolian Academy of Sciences +IGPH s Institut fuer Geologie und Palaeontologie der Universitat Hannover +IGUS s Universitat des Saarlandes +IGWH s Institut fuer Geowissenschaften aus dem Martin-Lurther- Universitat +IH s Instituto de Segunda Ensenanza de La Habana +IHASW s Institute of Hydrobiology, Academia Sinica +IHB s Institute of Hydrobiology, Chinese Academy of Sciences +IHCAS s Museum of Institute of Hydrobiology, Chainese Academy of Sciences +IHEM c Scientific Institute of Public Health, Mycology Section BCCM/IHEM +IHUG s Institut fuer Hygiene der Iniversitaet +IIBM-UNAM c Industrial Culture Collection +IIBUV s Investigaciones Biologicas de la Universidad Veracruzana (Mexico) +IICT s Centro de Zoologia do I.I.C.T. +IID c Laboratory Culture Collection +IIES s Instituto Investigaciones Entomologicas Salta +IIPB s Instituto de Ciencias del Mar +IITA b International Institute of Tropical Agriculture +IJ s Institute of Jamaica +IJFM c Instituto Jaime Ferran de Microbiologia Consejo Superior de Investigaciones Cientificas +IJSM s Institute of Jamaica, Natural History Museum +IK s Zoological Institute, Ukrainian Academy of Sciences +ILCA s International Livestock Research Institute +ILF s Iflracombe Museum +ILH s Iowa Lakeside Laboratory +ILL sc University of Illinois, Plant Biology Department +ILLS s Illinois Natural History Survey +ILMA s Istituto Leonardo Murialdo +ILPLA s Museo de La Plata, Instituto de Limnologia +IM s Instituto de Segunda Ensenanza de Matanzas +IM s Indian Museum +IMAGE b The I.M.A.G.E Consortium +IMARPE s Instituto del Mar del Peru +IMAS c Institute for Marine and Antarctic Studies +IMAU c Inner Mongolia Agricultural University, Key Laboratory of Dairy Biotechnology and Engineering +IMC s Sichuan Academy of Traditional Chinese Medicine and Pharmacy +IMCC c Inha Microbe Culture Collection, Inha University +IMCN s Instituto Vallecaucano de Investigaciones Cientificas +IMD c Industrial Microbiology Dublin +IMD s Institute of Medicinal Plant Development, Chinese Academy of Medical Sciences +IMDC s Inner Mongolia Institute for Drug Control +IMDY s Chinese Academy of Medical Sciences, Yunnan Branch +IMET c National Kurturensammlung fuer Mikroorganismen +IMFA s Inner Mongolia Academy of Forestry +IMI sc CABI Bioscience Genetic Resource Collection +IML s Instituto Miguel Lillo +IMLA s Fundacion e Instituto Miguel Lillo +IMM s Chinese Academy of Medical Science +IMM s Inner Mongolian Museum +IMMH c Collection of Animal Viruses +IMMIB c Culture Collection of the Institute of Medical Microbiology and Immunology of the University of Bonn +IMPC s Sichuan Academy of Traditional Chinese Medicine and Pharmacy +IMRU c Waksman Institute of Microbiology +IMS s Institute of Marine Sciences +IMS s University of North Carolina at Chapel Hill +IMSNU c Institute of Microbiology, Seoul National University +IMSSM s Instituto Mexicano del Seguro Social +IMT c Micoteca do Instituto de Medicina Tropical de Sao Paulo +IMT s Imperial Museum +IMTU s Institute of Medicine, Community Medicine Department +IMUFRJ c Instituto de Microbiologia of Universidade Federal do Rio de Janeiro +IMVS c IMVS Culture Collection +IMYZA c Instituto de Microbiologia y Zoologia Agricola +INA s Instituto Nun'Alvres, Departamento de Biologia +INA c Culture Collection of the Institute of New Antibiotics +INALI s Instituto Limnologia +INB s Instituto Nacional de Biodiversidad, Departamento de Botanica +INBC s Instituto Nacional de Biodiversidad (INBio) +INBio s National Biodiversity Institute, Costa Rica +INBP s Inventorio Biologico Nacional [Museo Nacional de Historia Natural del Paraguay] +INC s Instituto Nacional de Cultura, Museo de Ciencias Naturales (Panama) +INCQS c Fundacao Oswaldo Cruz-FIOCRUZ +IND s Indiana University, Department of Biology +IND-AN s Amphibian Collection +IND-M s La Unidad de Investigacion "Federico Medem"-Inderena (Colombia) +INDRE c Pathogen Fungi and Actinomycetes Collection +INEGI s Instituto Nacional de Estadistica Geografia e Informatica, Departamento de Botanica +INEP h Institute of the Industrial Ecology Problems of the North of Kola Science Center of the Russian Academy of Sciences. +INER s Istituto Nazionale di Entomologia +INFYB s Instituto Nacional de Farmacologia y Bromatologia, Farmacobotanica +INGU h Ingush State University +INH s Institut National d'Horticulture, Departement de Sciences Biologiques +INH s Instituto Nacional de Higiene +INHM s Iraq Natural History Museum +INHS s Illinois Natural History Survey +INIA s Instituto Nacional de Investigaciones Forestales y Agropecurias +INIA b El Instituto de Investigaciones Agropecuarias +INIA b Instituto Nacional de Investigacion y Tecnologia Agraria y Alimentaria +INIBP s Instituto Nacional de Investigaciones Biologico Pesqueras +INIDA s Instituto Nacional de Investigacao e Desenvolvimento Agrario - Cape Verde +INIDEP s Instituto Nacional de Investigacion y Desarrollo Pesquero +INIF c Coleccion de Microhongos +INIFAT c INIFAT Fungus Collection +INIP s Instituto Nacional de Investigacao das Pescas +INIR s Coleccion de Termitas Mexicanas +INLA s INIA Subestacion Experimental Control Biologico La Cruz +INM s Ibaraki Nature Museum +INMI c Institute of Microbiology, Russian Academy of Sciences +INPA s Instituto Nacional de Pesquisas da Amazonia INPA:CR s Instituto Nacional de Pesquisas da Amazonia, Crustacea Collection INPA:H s Instituto Nacional de Pesquisas da Amazonia, Collection of Amphibians and Reptiles INPA:LMM c Instituto Nacional de Pesquisas da Amazonia, Laboratorio de Micologia Medica Divisao de Microbiologia e Nutricao -INPC s National Pusa Collections -INRA b Institut National de la Recherche Agronomique +INPC s National Pusa Collections +INRA b Institut National de la Recherche Agronomique INRA:CGAB cb Institut National de la Recherche Agronomique, Collection of Germplasms of Agaricus bisporus -Insitute of Biology and Soil Science, Russian Academy of Sciences s Insitute of Biology and Soil Science, Russian Academy of Sciences -INU h Inonu University -INV s Inverness Museum and Art Gallery -INVA s Invergordon Academy -INVAM c International Culture Collection of (Vesicular) Arbuscular Mycorrhizal Fungi -INVEMAR s Instituto de Investigaciones Marinas de Punta de Betin -IO s Instituto Oceanografico da Universidade de Sao Paulo -IO s Instituto de Oceanografia da Universidade de Lisboa -IOAN s Shirshov Institute of Oceanography -IOC c Colecao de Culturas de Fungos do Instituto Oswaldo Cruz -IOCAS s Institute of Oceanology, Chinese Academy of Scineces -IOEB c Bacterial Collection -IOH s Academia de Ciencias -IOM s Institute of Oceanology, Academy of Sciences -IOPM s Izu Oceanic Park Museum -IORD s Takai University, Institute of Oceanic Research and Development -IOS s Institute of Oceanographic Sciences -IOUSP c Marine Microalgae Culture Collection -IOWA s University of Iowa, Museum of Natural History -IPA s Empresa Pernambucana de Pesquisa Agropecuaria, IPA +INU h Inonu University +INV s Inverness Museum and Art Gallery +INVA s Invergordon Academy +INVAM c International Culture Collection of (Vesicular) Arbuscular Mycorrhizal Fungi +INVEMAR s Instituto de Investigaciones Marinas de Punta de Betin +IO s Instituto Oceanografico da Universidade de Sao Paulo +IO s Instituto de Oceanografia da Universidade de Lisboa +IOAN s Shirshov Institute of Oceanography +IOC c Colecao de Culturas de Fungos do Instituto Oswaldo Cruz +IOCAS s Institute of Oceanology, Chinese Academy of Scineces +IOEB c Centre de ressources biologiques oenologiques CRBO +IOH s Academia de Ciencias +IOM s Institute of Oceanology, Academy of Sciences +IOPM s Izu Oceanic Park Museum +IORD s Takai University, Institute of Oceanic Research and Development +IOS s Institute of Oceanographic Sciences +IOUSP c Marine Microalgae Culture Collection +IOWA s University of Iowa, Museum of Natural History +IPA s Empresa Pernambucana de Pesquisa Agropecuaria, IPA IPA:germplasm bank b Empresa Pernambucana de Pesquisa Agropecuaria, IPA, -IPAE s Institute of Plant and Animal Ecology Ural Branch of Russian Academy of Sciences -IPB s Instituto Paranaense de Botanica -IPB s Institut fuer Palaeontologie -IPBIR b Integrated Primate Biomaterials and Information Resource -IPCN s Instituto Patagonico de Ciencias Naturales -IPEE RAS s A.N. Severtzov Institute of Ecology and Evolution, Russian Academy of Sciences -IPEF s Institut fuer Pflanzenschutzforschung -IPFUB s Institute for Paleontology of the Freie Universitat -IPGR b Institute for Plant Genetic Resources -IPHG s Institut fur Palaeontologie und Historische Geologie -IPK sb Leibniz Institute of Plant Genetics and Crop Plant Research -IPKUP s Paleontologiscsky Institute -IPLA c Instituto de Productos Lacteos de Asturias -IPMB s Institut fur Pharmazie und Molekulare Biotechnologie -IPMC s Institut Paleontologic Dr. M. Crusfafont Sabadell -IPMGO s Institut fur Paleontologie und Museum, Gottingen Universitat -IPMY s Universidad Pedagogica Libertador, Nucleo Maracay, Departamento de Biologia -IPN s Instituto Politecnico Nacional -IPO s Plant Research International -IPPAS c Culture Collection of Microalgae IPPAS -IPRN s Instituto de Pesquisas de Recursos Naturais Renovaveis -IPS s Ipswich Museum -IPSLI s Ipswich Literary Institute -IPSM s Ipswich Museum -IPSN s Instituto de Paleontologia de Sabadella -IPT c Agrupamento de Biotecnologia, Culture Collection of Microorganisms -IPTB s Instituto de Pesquisas Tecnologicas -IPUW s Institut fuer Palaeontologie der Universitaet Wien -IPW s Instutut fuer Palaeontologie der Uinversitaet Wurzburg -IQW h Senckenberg Forschungsinstitut und Naturmuseen -IRAG s Institut National de la Recherche Agronomique de Antilles et Guyane -IRAI h Parque da Ciencia Newton Freire Maia -IRAN sc Iranian Research Institute of Plant Protection, Department of Botany -IRBR s Universidad de Oriente, Departamento de Biologia -IRCW s Madison, University of Wisconsin -IRD s Institut de Recherche pour le Developpement -IRDA s Agriculture Department -IREC s Institut de Recherches Entomologique de la Caribe -IRGC b International Rice Genebank Collection -IRK s Siberian Institute of Plant Physiology and Biochemistry -IRKU s Irkutsk State University, Department of Botany and Genetics -IRP s Isle Royale National Park -IRRI sb International Rice Research Institute -IRSAC s Institute de Recherche Scientific en Afrique Centrale -IRSC s Institut de Recherches Scientifiques au Congo -IRSM s Institut Recherche Scientifique de Madagascar -IRSN s Institut Royal des Sciences Naturelles de Belgique -IRSNB s Institut Royal des Sciences Naturelles de Belgique -IRVC s University of California, UCI Arboretum Mail -IS s University of Molise, Department of Science and Technology for Environment and Territory -ISAB s Istituto Sant'Antonio dei Padri Francescani -ISAR s Academy of Science -ISAS s Kunming Institute of Zoology -ISB s Institute of Spelology "Emile Racovita" -ISBB s Institutul de Stiinte Biologice -ISBC s Institute of Soil Biology, Academy of Science of the Czech Republic +IPAE s Institute of Plant and Animal Ecology Ural Branch of Russian Academy of Sciences +IPB s Instituto Paranaense de Botanica +IPB s Institut fuer Palaeontologie +IPBIR b Integrated Primate Biomaterials and Information Resource +IPCN s Instituto Patagonico de Ciencias Naturales +IPE s Instituto Pirenaico de Ecologia +IPEE RAS s A.N. Severtzov Institute of Ecology and Evolution, Russian Academy of Sciences +IPEF s Institut fuer Pflanzenschutzforschung +IPFUB s Institute for Paleontology of the Freie Universitat +IPGR b Institute for Plant Genetic Resources +IPHG s Institut fur Palaeontologie und Historische Geologie +IPK sb Leibniz Institute of Plant Genetics and Crop Plant Research +IPKUP s Paleontologiscsky Institute +IPLA c Instituto de Productos Lacteos de Asturias +IPMB s Institut fur Pharmazie und Molekulare Biotechnologie +IPMC s Institut Paleontologic Dr. M. Crusfafont Sabadell +IPMGO s Institut fur Paleontologie und Museum, Gottingen Universitat +IPMY s Universidad Pedagogica Libertador, Nucleo Maracay, Departamento de Biologia +IPN s Instituto Politecnico Nacional +IPO s Plant Research International +IPPAS c Culture Collection of Microalgae IPPAS IPPRAS +IPRN s Instituto de Pesquisas de Recursos Naturais Renovaveis +IPS s Ipswich Museum +IPSLI s Ipswich Literary Institute +IPSM s Ipswich Museum +IPSN s Instituto de Paleontologia de Sabadella +IPT c Agrupamento de Biotecnologia, Culture Collection of Microorganisms +IPTB s Instituto de Pesquisas Tecnologicas +IPUW s Institut fuer Palaeontologie der Universitaet Wien +IPW s Instutut fuer Palaeontologie der Uinversitaet Wurzburg +IQW h Senckenberg Forschungsinstitut und Naturmuseen +IRAG s Institut National de la Recherche Agronomique de Antilles et Guyane +IRAI h Parque da Ciencia Newton Freire Maia +IRAN sc Iranian Research Institute of Plant Protection, Department of Botany +IRAQ s Iraq Natural History Museum +IRBR s Universidad de Oriente, Departamento de Biologia +IRCW s Madison, University of Wisconsin +IRD s Institut de Recherche pour le Developpement +IRDA s Agriculture Department +IREC s Institut de Recherches Entomologique de la Caribe +IRGC b International Rice Genebank Collection +IRK s Siberian Institute of Plant Physiology and Biochemistry +IRKU s Irkutsk State University, Department of Botany and Genetics +IRP s Isle Royale National Park +IRRI sb International Rice Research Institute +IRSAC s Institute de Recherche Scientific en Afrique Centrale +IRSC s Institut de Recherches Scientifiques au Congo +IRSM s Institut Recherche Scientifique de Madagascar +IRSN s Institut Royal des Sciences Naturelles de Belgique +IRSNB s Institut Royal des Sciences Naturelles de Belgique +IRVC s University of California, UCI Arboretum Mail +IS s University of Molise, Department of Science and Technology for Environment and Territory +ISAB s Istituto Sant'Antonio dei Padri Francescani +ISAR s Academy of Science +ISAS s Kunming Institute of Zoology +ISB s Institute of Spelology "Emile Racovita" +ISBB s Institutul de Stiinte Biologice +ISBC s Institute of Soil Biology, Academy of Science of the Czech Republic ISBC:CMF cb Institute of Soil Biology, Academy of Science of the Czech Republic, Collection of Microscopic Fungi -ISC c International Salmonella Centre (W.H.O.) -ISC s Iowa State University, Botany Department -ISCM s Institut Scientifique Cheripen -ISE h Universidade Federal de Sergipe, Campus Professor Alberto Carvalho -ISEA s Institute of Systematics and Evolution of Animals -ISEAK s Instytut Systematyki i Ewolucji Zwierz -ISEM s Institut des Sciences de l'Evolution Montpellier -ISER s Institutul Speologie Emil G. Racovita -ISH s Institut fuer Seefischerei -ISI s Geological Museum, Indian Statistical Institute -ISIS s Naturforschende Gesellschaft Isis -ISKW h Ishikawa Museum of Natural History -ISL s Quaid-I-Azam University, Biological Sciences Department -ISM s Illinois State Museum -ISMAR h Consiglio Nazionale delle Ricerche, Istituto di Scienze Marine -ISMC s Indiana Department of Natural Resources -ISNHC s State Historical Society of Iowa -ISNP s Istituto Sperimentale per la Nutrizione delle Piante -ISP c International Cooperative Project for Description and Deposition of Type Cultures -ISPaVe c Istituto Sperimentale per la Patologia Vegetale -ISRA s Royal Academy -ISRI c Indonesian Sugar Research Institute, Pusat Penelitian Perkebunan Gula Indonesia -ISS c Institute of Soil Science Collection of Bacteria -ISTC s University of Northern Iowa, Biology Department -ISTE s University of Istanbul, Department of Pharmaceutical Botany -ISTF s Istanbul University, Botany Department -ISTO s University of Istanbul, Orman Fakueltesi -ISTPM s Institut Scientifique et Technique des Peches Maritimes -ISU s Illinois State University, Biological Sciences Department -ISU s Indiana State University -ISUC s Normal, Illinois State University -ISUI s Iowa State University -ISUVC s Indiana State University -ISZA s Istituto Sperimentale per la Zoologia Agraria -ISZP s Institute of Systematic Zoology -ITAE s Istituto Tecnico Agrario Enologico -ITAL c Banco de Fermentos Lacticos -ITALSL c Secao de Leite e Derivados -ITALSM c Secao de Microbiologia -ITBCC c Institute of Technology Bandung Culture Collection -ITBZC s Institute of Tropical Biology, Zoology Collection -ITC b International Transit Centre -ITCC c Indian Type Culture Collection -ITCC s Istituto Tecnico Stattale "Camillo Cavour" -ITCO s Istituto Tecnico Commerciale "Oronzio Gabriele Costa" -ITCV s Instituto Tecnologico de Ciudad Victoria, Departamento de Micologia -ITD c Coleccion de Cepas Microbianas -ITDI c Industrial Technology Development Institute -ITEM c Institute of Toxins and Mycotoxins from Plant Parasites -ITG c ITG -ITH c W.H.O./F.A.O. Collaborating Centre for Reference and Research on Leptospirosis -ITHA s Instituut voor Tropische Hygiene -ITIC s Universidad de El Salvador, Escuela de Biologia -ITLJ s National Institute of Agro-environmental Sciences -ITMH h Muhimbili University of Health and Allied Sciences -ITMM s Instituto Tecnologico de Monterrey -IU s Indiana University -IUI s Inha University, Biology Department -IUIC s Indiana University -IUK s Universite de Kinshasa, Departement de Biologie -IUM s Iwate University, Biology Department -IUP s Indiana University of Pennsylvania, Biology Department -IUQ s Laboratorio de Ictiologia -IVAU s Instituut Voor Aardwetenschappen -IVB s Institute of Vertebrate Biology, Academy of Sciences of the Czech Republic -IVF s Chinese Academy of Agricultural Sciences -IVGU h Ivanovo State University -IVIC s Instituto Venezolano de Investigaciones Cientificas -IVPP s Institute of Vertebrate Paleontology and Paleoanthropology -IZ c Departamento de Tecnologia Rural -IZ s Instituto de Zoologia -IZ s Institute of Zoology -IZ s Aegean Agricultural Research Institute, Department of Plant Genetic Resources -IZA s Universita di l'Aguila, Instituto di Zoologia -IZAC s Universidad Nacional de La Rioja-Sede Chamical -IZAC s Academia de Ciencias de Cuba, Instituto de Zoologia -IZAS s Institut Zoologii Akademii Nauk Ukraini - Institute of Zoology of the Academy of Sciences of Ukraine -IZASK s Institue of Zoology of the Kazakh Academy of Sciences -IZBE s Institute of Zoology and Botany -IZBT s L'Institut de Zoologie et Botanique de Tartu -IZCAS s Institute of Zoology, Chinese Academy of Sciences -IZCR s Istituto di Zoologia -IZEF s Ege Ueniversitesi, Farmasoetik Botanik Kuersuesue -IZET-UCV s Instituto de Zoologia y Ecologia Tropical -IZGAS s Georgian Academy of Sciences, Insititute of Zoology -IZPAN s Zoological Institute, Polish Academy of Sciences -IZPC s Universidade do Porto -IZSI s Istituto di Zoologia -IZSSA c Collection of Experimental Zooprophylactic Institute of Sardinia (Istituto Zooprofilattico Sperimentale della Sardegna "G.Pegreffi", Sassari)) -IZTA s Universidad Nacional Autonoma de Mexico, Iztacala, Jefatura de Biologia -IZUA s Universidad Austral de Chile, Instituto de Zoologia -IZUC s Universidad de Concepcion, Instituto de Zoologia -IZUCS s Universita DI Cagliari -IZUE s Universitat -Erlangen-Nurnberg -IZUG s Istituto di Zoologia dell'Universita -IZUI s Institut fuer Zoologie der Universitat Innsbruck -IZUM s Istituto di Zoologia dell'Universita -IZUP s Istituto di Zoologia dell'Universita -IZUW s Institut fuer Zoologie der Universitat Wien -IZW s Institut Zoologii -IZWU s Paleozology Department, Institute of Zoology, Worclaw University -J s University of the Witwatersrand, Botany Department -JA s Consejeria de Medio Ambiente (Junta de Andalucia), Direccion General de Gestion del Medio Natural -JAC s University of Jodhpur, Botany Department -JACA s Instituto Pirenaico de Ecologia, CSIC -JAEN s Universidad de Jaen, Botanica -JAS s Jiangxi Academy of Sciences -JATH s University of Szeged -JAUM s Jardin Botanico Joaquin Antonio Uribe -JAY s Fondation Cognacq-Jay -JBAG s Jardin Botanico Atlantico, Ayuntamiento de Gijon -JBB h Jardin Botanico Jose Celestino Mutis -JBC b Francisco Javier Clavijero Botanic Garden -JBCC h Alaska State Museum -JBG s Johannesburg Botanic Garden -JBGP s Jardin Botanico Guillermo Pineres -JBL s Jardin Botanico Lankester, Universidad de Costa Rica -JBN s Jardin Botanico Nacional -JBSD s Jardin Botanico Nacional Dr. Rafael M. Moscoso -JBVN s Jardin Botanique de la Ville de Nice, Service des Espaces Verts -JBVPF sb Jardin botanique de la Ville de Paris -JBWM s J.B. Wallis Museum of Entomology -JCB s St. Joseph's College -JCE s Jiangxi College of Education, Biology Department -JCM c Japan Collection of Microorganisms -JCRB c Japanese Collection of Research Bioresources Cell Bank -JCT c James Cook Townsville -JE s Herbarium Haussknecht, Jena -JEF s Indiana University Southeast, Biology Department -JEL c Joyce E. Longcore Chytrid Collection at the University of Maine -JEL s Latvian Agricultural Academy, Plant Protection Department -JEPS s University of California, Jepson Herbarium -JES h Universidad Autonoma Chapingo -JESW s John Evelyn Society's Museum -JEY s Boys' Grammar School, Victoria College -JF s Jonkershoek Forestry Research Centre, Environment Affairs Department -JFBM s James Ford Bell Museum of Natural History -JHH s New York State Herbarium -JHS h Regional Research Institute -JHWU s Wittenberg University, Biology Department -JIC b John Innes Centre -JII s John Innes Institute -JIU s Jishou University, Biology Department -JJF s Jiujiang Forestry Institute -JJT s Jiujiang Teachers College, Biology Department -JJU s Jeonju University -JLFC s Forestry College of Beihua University, Forestry Department -JLMP s Jilin Academy of Traditional Chinese Medicine and Materia Medica -JM s Jura Museum, Eichstatt -JME h Jura-Museum Eichstatt -JMM s Earlham College, Joseph Moore Museum -JMRC c Jena Microbial Resource Collection +ISC c International Salmonella Centre (W.H.O.) +ISC s Iowa State University, Botany Department +ISCM s Institut Scientifique Cheripen +ISE h Universidade Federal de Sergipe, Campus Professor Alberto Carvalho +ISEA s Institute of Systematics and Evolution of Animals +ISEAK s Instytut Systematyki i Ewolucji Zwierz +ISEM s Institut des Sciences de l'Evolution Montpellier +ISER s Institutul Speologie Emil G. Racovita +ISH s Institut fuer Seefischerei +ISI s Geological Museum, Indian Statistical Institute +ISIS s Naturforschende Gesellschaft Isis +ISKW h Ishikawa Museum of Natural History +ISL s Quaid-I-Azam University, Biological Sciences Department +ISM s Illinois State Museum ISMS +ISMAR h Consiglio Nazionale delle Ricerche, Istituto di Scienze Marine +ISMC s Indiana Department of Natural Resources +ISNHC s State Historical Society of Iowa +ISNP s Istituto Sperimentale per la Nutrizione delle Piante +ISP c International Cooperative Project for Description and Deposition of Type Cultures +ISPaVe c Istituto Sperimentale per la Patologia Vegetale CRA-PAV +ISRA s Royal Academy +ISRI c Indonesian Sugar Research Institute, Pusat Penelitian Perkebunan Gula Indonesia +ISS c Institute of Soil Science Collection of Bacteria +ISTC s University of Northern Iowa, Biology Department +ISTE s University of Istanbul, Department of Pharmaceutical Botany +ISTF s Istanbul University, Botany Department +ISTO s University of Istanbul, Orman Fakueltesi +ISTPM s Institut Scientifique et Technique des Peches Maritimes +ISU s Illinois State University, Biological Sciences Department +ISU s Indiana State University +ISUC s Normal, Illinois State University +ISUI s Iowa State University +ISUVC s Indiana State University +ISZA s Istituto Sperimentale per la Zoologia Agraria +ISZP s Institute of Systematic Zoology +ITAE s Istituto Tecnico Agrario Enologico +ITAL c Banco de Fermentos Lacticos +ITALSL c Secao de Leite e Derivados +ITALSM c Secao de Microbiologia +ITBCC c Institute of Technology Bandung Culture Collection +ITBCZ s Institute of Tropical Biology Collection of Zoology +ITBZC s Institute of Tropical Biology, Zoology Collection +ITC b International Transit Centre +ITCC c Indian Type Culture Collection +ITCC s Istituto Tecnico Stattale "Camillo Cavour" +ITCO s Istituto Tecnico Commerciale "Oronzio Gabriele Costa" +ITCV s Instituto Tecnologico de Ciudad Victoria, Departamento de Micologia +ITD c Coleccion de Cepas Microbianas +ITDI c Industrial Technology Development Institute +ITEM c Institute of Toxins and Mycotoxins from Plant Parasites +ITG c ITG +ITH c W.H.O./F.A.O. Collaborating Centre for Reference and Research on Leptospirosis +ITHA s Instituut voor Tropische Hygiene +ITIC s Universidad de El Salvador, Escuela de Biologia +ITLJ s National Institute of Agro-environmental Sciences +ITMH h Muhimbili University of Health and Allied Sciences +ITMM s Instituto Tecnologico de Monterrey +ITT s Instituto Technologico de Ciudad Victoria +IU s Indiana University +IUI s Inha University, Biology Department +IUIC s Indiana University +IUK s Universite de Kinshasa, Departement de Biologie +IUM s Iwate University, Biology Department +IUP s Indiana University of Pennsylvania, Biology Department +IUQ s Laboratorio de Ictiologia +IVAU s Instituut Voor Aardwetenschappen +IVB s Institute of Vertebrate Biology, Academy of Sciences of the Czech Republic +IVF s Chinese Academy of Agricultural Sciences +IVGU h Ivanovo State University +IVIC s Instituto Venezolano de Investigaciones Cientificas +IVPP s Institute of Vertebrate Paleontology and Paleoanthropology IVPP AS +IZ c Departamento de Tecnologia Rural +IZ s Instituto de Zoologia +IZ s Institute of Zoology +IZ s Aegean Agricultural Research Institute, Department of Plant Genetic Resources +IZA s Universita di l'Aguila, Instituto di Zoologia +IZAC s Universidad Nacional de La Rioja-Sede Chamical +IZAC s Academia de Ciencias de Cuba, Instituto de Zoologia +IZAS s Institut Zoologii Akademii Nauk Ukraini - Institute of Zoology of the Academy of Sciences of Ukraine +IZASK s Institue of Zoology of the Kazakh Academy of Sciences +IZBE s Institute of Zoology and Botany +IZBT s L'Institut de Zoologie et Botanique de Tartu +IZCAS s Institute of Zoology, Chinese Academy of Sciences ZMIOZ +IZCR s Istituto di Zoologia +IZEF s Ege Ueniversitesi, Farmasoetik Botanik Kuersuesue +IZET-UCV s Instituto de Zoologia y Ecologia Tropical +IZGAS s Georgian Academy of Sciences, Insititute of Zoology +IZPAN s Zoological Institute, Polish Academy of Sciences +IZPC s Universidade do Porto +IZSI s Istituto di Zoologia +IZSSA c Collection of Experimental Zooprophylactic Institute of Sardinia (Istituto Zooprofilattico Sperimentale della Sardegna "G.Pegreffi", Sassari)) +IZTA s Universidad Nacional Autonoma de Mexico, Iztacala, Jefatura de Biologia +IZUA s Universidad Austral de Chile, Instituto de Zoologia +IZUC s Universidad de Concepcion, Instituto de Zoologia +IZUCS s Universita DI Cagliari +IZUE s Universitat -Erlangen-Nurnberg +IZUG s Istituto di Zoologia dell'Universita +IZUI s Institut fuer Zoologie der Universitat Innsbruck +IZUM s Istituto di Zoologia dell'Universita +IZUP s Istituto di Zoologia dell'Universita +IZUW s Institut fuer Zoologie der Universitat Wien +IZW s Institut Zoologii +IZWU s Paleozology Department, Institute of Zoology, Worclaw University +J s University of the Witwatersrand, Botany Department +JA s Consejeria de Medio Ambiente (Junta de Andalucia), Direccion General de Gestion del Medio Natural +JAC s University of Jodhpur, Botany Department +JACA s Instituto Pirenaico de Ecologia, CSIC +JAEN s Universidad de Jaen, Botanica +JAS s Jiangxi Academy of Sciences +JATH s University of Szeged +JAUM s Jardin Botanico Joaquin Antonio Uribe +JAY s Fondation Cognacq-Jay +JBAG s Jardin Botanico Atlantico, Ayuntamiento de Gijon +JBB h Jardin Botanico Jose Celestino Mutis +JBC b Francisco Javier Clavijero Botanic Garden XAL +JBCC h Alaska State Museum +JBG s Johannesburg Botanic Garden +JBGP s Jardin Botanico Guillermo Pineres +JBL s Jardin Botanico Lankester, Universidad de Costa Rica +JBN s Jardin Botanico Nacional +JBSD s Jardin Botanico Nacional Dr. Rafael M. Moscoso +JBVN s Jardin Botanique de la Ville de Nice, Service des Espaces Verts +JBVPF sb Jardin botanique de la Ville de Paris +JBWM s J.B. Wallis Museum of Entomology +JCB s St. Joseph's College +JCE s Jiangxi College of Education, Biology Department +JCM c Japan Collection of Microorganisms +JCRB c Japanese Collection of Research Bioresources Cell Bank +JCT c James Cook Townsville +JE s Herbarium Haussknecht, Jena +JEF s Indiana University Southeast, Biology Department +JEL c Joyce E. Longcore Chytrid Collection at the University of Maine +JEL s Latvian Agricultural Academy, Plant Protection Department +JEPS s University of California, Jepson Herbarium +JES h Universidad Autonoma Chapingo +JESW s John Evelyn Society's Museum +JEY s Boys' Grammar School, Victoria College +JF s Jonkershoek Forestry Research Centre, Environment Affairs Department +JFBM s James Ford Bell Museum of Natural History +JHH s New York State Herbarium +JHS h Regional Research Institute +JHWU s Wittenberg University, Biology Department +JIC b John Innes Centre +JII s John Innes Institute +JIU s Jishou University, Biology Department +JJF s Jiujiang Forestry Institute +JJT s Jiujiang Teachers College, Biology Department +JJU s Jeonju University +JLFC s Forestry College of Beihua University, Forestry Department +JLMP s Jilin Academy of Traditional Chinese Medicine and Materia Medica +JM s Jura Museum, Eichstatt +JME h Jura-Museum Eichstatt +JMM s Earlham College, Joseph Moore Museum +JMRC c Jena Microbial Resource Collection JMRC:SF c Jena Microbial Resource Collection, Subcollection Fungi -JMSMC s Jiamusi Medical College, Department of Pharmacy -JMUH s James Madison University, Department of Biology -JN s Jinggang Mountain Nature Reserve -JNR s Jiulian Mountain Nature Reserve, Administration Department -JNU s Ji Nan University -JNU s Chonbuk National University, Faculty of Biological Sciences -JNUB h Jeju National University -JOE s University of Joensuu, Biology Department -JOI h Universidade da Regiao de Joinville -JOMU h John Muir National Historic Site -JONK s Jonkershoek Herbarium -JOTR h Joshua Tree National Park -JP s Phyletisches Museum Jena -JPB s Universidade Federal da Paraiba, Cidade Universitaria, Departamento de Sistematica e Ecologia -JPMP s Janus Pannonius Museum -JPU s Janus Pannonius University, Botany Department -JRAU s University of Johannesburg, Department of Botany and Plant Biotechnology -JROH h Jasper Ridge Biological Preserve, Stanford University -JRY s Jersey College for Girls -JSHC s Jay S. Haft Collection -JSMPE s Joint Soviet Mongolian Paleontolgical Expedition -JSPC s Shandong University, Biology Department -JSPC s J. Rusek Collection -JSU s Jacksonville State University, Biology Department -JSY s Museum and Art Gallery of La Societe Jersiaise -JTNM s Joshua Tree National Monument -JTPC s Colorado Entomological Museum (formerly John T. Polhemus collection) -JU s Jinan University -JUA s Universidad Nacional de Jujuy, Facultad de Ciencias Agrarias -JUG s Jiwaji University, Botany Department -JUJ s Hebei Agricultural University -JVC s Jardin Botanico Canario Viera y Clavijo -JVR s Universidad Nacional -JXAU s Jiangxi Agricultural University, Forestry Department -JXCM s Jiangxi College of Traditional Chinese Medicine, Pharmacy Department -JXF s Jiangxi Forestry Institute -JXM s Jiangxi Institute of Materia Medica -JXU s Jiangxi University, Biology Department -JYV s University of Jyvaeskylae, Natural History Department -K sb Royal Botanic Gardens, Kew -K(M) s Mycology Collection of Kew Royal Botanical Gardens -KA s Vytautas Magnus University -KABA s University of Kabul -KAC c Kalmar Algae Collection -KACC c Korean Agricultural Culture Collection -KAG s Kagoshima University Museum -KAGS s Kagoshima University, Biology Department -KAI s Henan University, Biology Department -KAMA s Yokohama University -KANA s Kanazawa University -KAND h Kandalaksha State Nature Reserve -KANU s University of Kansas -KAR s University of Tehran, Horticulture Department -KARI s Kenya Agricultural Research Institute -KARS s Kawanda Agricultural Research Station -KAS s Universitaet Gesamthochschule Kassel, Morphologie und Systematik der Pflanzen -KASH s University of Kashmir -KASSEL s Naturkundemuseum im Ottoneum -KATH s Department of Plant Resources -KATO s Karadeniz Technical University, Department of Forest Botany -KAUM s Kagoshima University Museum +JMSMC s Jiamusi Medical College, Department of Pharmacy +JMUH s James Madison University, Department of Biology +JN s Jinggang Mountain Nature Reserve +JNR s Jiulian Mountain Nature Reserve, Administration Department +JNU s Ji Nan University +JNU s Chonbuk National University, Faculty of Biological Sciences +JNUB h Jeju National University +JOE s University of Joensuu, Biology Department +JOI h Universidade da Regiao de Joinville +JOMU h John Muir National Historic Site +JONK s Jonkershoek Herbarium +JOTR h Joshua Tree National Park +JP s Phyletisches Museum Jena +JPB s Universidade Federal da Paraiba, Cidade Universitaria, Departamento de Sistematica e Ecologia +JPMP s Janus Pannonius Museum +JPU s Janus Pannonius University, Botany Department +JRAU s University of Johannesburg, Department of Botany and Plant Biotechnology +JROH h Jasper Ridge Biological Preserve, Stanford University +JRY s Jersey College for Girls +JSHC s Jay S. Haft Collection +JSMPE s Joint Soviet Mongolian Paleontolgical Expedition JRMPE +JSPC s Shandong University, Biology Department +JSPC s J. Rusek Collection +JSU s Jacksonville State University, Biology Department +JSY s Museum and Art Gallery of La Societe Jersiaise +JTNM s Joshua Tree National Monument +JTPC s Colorado Entomological Museum (formerly John T. Polhemus collection) +JU s Jinan University +JUA s Universidad Nacional de Jujuy, Facultad de Ciencias Agrarias +JUG s Jiwaji University, Botany Department +JUJ s Hebei Agricultural University +JVC s Jardin Botanico Canario Viera y Clavijo +JVR s Universidad Nacional +JXAU s Jiangxi Agricultural University, Forestry Department +JXCM s Jiangxi College of Traditional Chinese Medicine, Pharmacy Department +JXF s Jiangxi Forestry Institute +JXM s Jiangxi Institute of Materia Medica +JXU s Jiangxi University, Biology Department +JYV s University of Jyvaeskylae, Natural History Department +K sb Royal Botanic Gardens, Kew +K(M) s Mycology Collection of Kew Royal Botanical Gardens +KA s Vytautas Magnus University +KABA s University of Kabul +KAC c Kalmar Algae Collection +KACC c Korean Agricultural Culture Collection +KAG s Kagoshima University Museum +KAGS s Kagoshima University, Biology Department +KAI s Henan University, Biology Department +KAMA s Yokohama University +KANA s Kanazawa University +KAND h Kandalaksha State Nature Reserve +KANU s University of Kansas +KAR s University of Tehran, Horticulture Department +KARI s Kenya Agricultural Research Institute +KARS s Kawanda Agricultural Research Station +KAS s Universitaet Gesamthochschule Kassel, Morphologie und Systematik der Pflanzen +KASH s University of Kashmir +KASSEL s Naturkundemuseum im Ottoneum +KATH s Department of Plant Resources +KATO s Karadeniz Technical University, Department of Forest Botany +KATO:Fungi s Karadeniz Technical University, Department of Forest Botany, Fungi collection +KAUM s Kagoshima University Museum KAUM:I s Kagoshima University Museum, Ichthyology Collection -KAW s Kawanda Research Station, Department of Agriculture -KAZ s Kazan State University -KB s National Biological Resources Center, Department of Biological Sciences -KBAI s Kuban Agricultural State University, Department of Biology and Ecology -KBG b Kyoto Botanical Garden -KBHG s H. M. Berbekov Kabardian-Balkarian State University, Department of Botany -KBRYO s Centre College of Kentucky -KBSMS s Kellogg Biological Station, Michigan State University -KBT s Stewarty Museum -KCCM c Korean Culture Center of Microorganisms, Department of Food Engineering -KCFS s King's College -KCK s Dick Institute -KCLB c Korean Cell Line Bank -KCOM c Korean Collection for Oral Microbiology -KCS s University of London, King's College, Botany Department -KCTC c Korean Collection for Type Cultures -KDL s Kendal Museum -KDR s Bewdley Museum -KE s Kent State University, Biological Sciences Department -KEF s Kunming Edible Fungi Institute -KEI s University of Transkei, Botany Department -KEIU s Korea University -KEM s University of Kemerovo, Department of Botany -KEMC c Korea Environmental Microorganism Center, Kyonggi University -KEMH c KEMH/PMH Culture collection -KEN s Longwood Gardens, Horticulture Department -KEND s Kendal Natural History Society -KEP s Forest Research Institute Malaysia -KESC s Keene State College, Department of Biology -KEVO s University of Turku -KF h Kerman University of Medical Sciences -KFBG h Kadoorie Farm and Botanic Garden -KFCC c Korean Federation of Culture Collection -KFI s Hongnung Arboretum, Silviculture Department -KFRI s Kerala Forest Research Institute -KFRS s Kanudi Fisheries Research Station -KFTA s Saint Petersburg State S. M. Kirov Forest Technology Academy, Botany and Dendrology Department -KFUH s King Faisal University, Chemistry and Botany Department -KG h International Phytochemistry Research and Production Institute -KGU s Geology and Mineralogy Museum -KGY s Cliffe Castle Art Gallery and Museum -KH s Korea National Arboretum -KHA s Institute for Water and Ecology Problems, Far East Branch, Russian Academy of Sciences, Laboratory of Plant Ecology -KHD s Denver Botanic Gardens -KHER s Kherson Pedagogical University, Botany Department -KHF s Forest Research and Education Institute, Soba -KHMM s Kultur Historisches Museum -KHMS s Muzeum `umavy -KHOR s Pamir Biological Institute -KHU s University of Khartoum, Botany Department -KHUG s Aussenstelle der Universitaet -KHUS s Kyung Hee University, Biology Department -KIEL s Christian-Albrechts-Universitaet Kiel -KIFB s Korean Institute of Freshwater Biology -KIOM h Korea Institute of Oriental Medicine -KIP h Institut National pour l'Etude et la Recherche Agronomique -KIRI s University of Rhode Island, Department of Biological Sciences -KIS h Universite de Kisangani -KISA h Institut Congolais pour la Conservation de la Nature -KIT c Laboratorium voor Tropische Hygiene -KIUJ s Kyusu University -KIZ s Kunming Institute of Zoology, Chinese Academy of Sciences -KKFC s Kasetsart University Kamphaengsaen campus Fungus Collection -KKM s Kirkleatham Museum -KKU s Herbarium, Department of Biology, Khon Kaen University -KKUA s Khon Kaen University -KKUK s Kon-Kuk University -KL s Landesmuseum fuer Kaernten -KLA s Herbarium, Department of Agriculture, Malaysia -KLE s University of Keele, Biological Sciences Department -KLGU s Kaliningrad State University, Department of Botany and Plant Ecology -KLH s K. E. Tsiolkovsky Kaluga State Pedagogical University, Department of Botany and Ecology -KLN s Lynn Museum and Art Gallery -KLU s University of Malaya -KM s Kelowna Museum -KM s Sprava Krkonoaskeho narodniho parku -KM s Muzeum Przyrodnicze Uniwersytetu Jagiellonskiego -KM s Kotel'nich Museum -KMG s McGregor Museum -KMK s Kraevedscheskii Musei Kishineva - Museum of Regional Study -KMK s Kaffarian Museum -KMKV s Karlovarske muzeum -KMM c Collection of Marine Microorganisms -KMMA s Royal Museum for Central Africa -KMMCC c Korea Marine Microalgae Culture Center -KMN s Adger Museum of Natural History and Botanical Garden, Botany Department -KMNH s Kitakyushu Museum and Institute of Natural History, Botany Department -KMU s Karl-Marx-Universitat Leipzeg -KMV s Kunming Municipal Museum -KMVC s Krajske Muzeum Vychodnich Cech -KNFY s Klamath National Forest, Resources Department -KNH h Kongju National University -KNHM s The Educational Science Museum [=Kuwait Natural History Museum?] -KNK s Northern Kentucky University, Department of Biological Sciences -KNL s Kinneil Museum -KNOX s Knox College, Department of Biology -KNP s South African National Parks, Scientific Services -KNU s Kyungpook National University, Biology Department -KNUC s Kangweon National University -KNUH s Kyung-Nam University, Biology Department -KNWR s Kenai National Wildlife Refuge +KAW s Kawanda Research Station, Department of Agriculture +KAZ s Kazan State University +KB s National Biological Resources Center, Department of Biological Sciences +KBAI s Kuban Agricultural State University, Department of Biology and Ecology +KBG b Kyoto Botanical Garden +KBHG s H. M. Berbekov Kabardian-Balkarian State University, Department of Botany +KBRYO s Centre College of Kentucky +KBSMS s Kellogg Biological Station, Michigan State University +KBT s Stewarty Museum +KCCM c Korean Culture Center of Microorganisms, Department of Food Engineering +KCFS s King's College +KCK s Dick Institute +KCLB c Korean Cell Line Bank +KCOM c Korean Collection for Oral Microbiology +KCS s University of London, King's College, Botany Department +KCTC c Korean Collection for Type Cultures +KDL s Kendal Museum +KDR s Bewdley Museum +KE s Kent State University, Biological Sciences Department +KEF s Kunming Edible Fungi Institute +KEI s University of Transkei, Botany Department +KEIB s Katedra Ekologii i Biogeografii +KEIU s Korea University +KEM s University of Kemerovo, Department of Botany +KEMC c Korea Environmental Microorganism Center, Kyonggi University +KEMH c KEMH/PMH Culture collection +KEN s Longwood Gardens, Horticulture Department +KEND s Kendal Natural History Society +KEP s Forest Research Institute Malaysia +KESC s Keene State College, Department of Biology +KEVO s University of Turku +KF h Kerman University of Medical Sciences +KFBG h Kadoorie Farm and Botanic Garden +KFCC c Korean Federation of Culture Collection +KFI s Hongnung Arboretum, Silviculture Department +KFRI s Kerala Forest Research Institute +KFRS s Kanudi Fisheries Research Station +KFTA s Saint Petersburg State S. M. Kirov Forest Technology Academy, Botany and Dendrology Department +KFUH s King Faisal University, Chemistry and Botany Department +KG h International Phytochemistry Research and Production Institute +KGU s Geology and Mineralogy Museum +KGY s Cliffe Castle Art Gallery and Museum +KH s Korea National Arboretum +KHA s Institute for Water and Ecology Problems, Far East Branch, Russian Academy of Sciences, Laboratory of Plant Ecology +KHD s Kathryn Kalmbach Herbarium of Vascular Plants, Denver Botanic Gardens +KHER s Kherson Pedagogical University, Botany Department +KHF s Forest Research and Education Institute, Soba +KHMM s Kultur Historisches Museum +KHMS s Muzeum `umavy +KHOR s Pamir Biological Institute +KHU s University of Khartoum, Botany Department +KHUG s Aussenstelle der Universitaet +KHUS s Kyung Hee University, Biology Department +KIEL s Christian-Albrechts-Universitaet Kiel +KIFB s Korean Institute of Freshwater Biology +KIOM h Korea Institute of Oriental Medicine +KIP h Institut National pour l'Etude et la Recherche Agronomique +KIRI s University of Rhode Island, Department of Biological Sciences +KIS h Universite de Kisangani +KISA h Institut Congolais pour la Conservation de la Nature +KIT c Laboratorium voor Tropische Hygiene +KIUJ s Kyusu University +KIZ s Kunming Institute of Zoology, Chinese Academy of Sciences +KKFC s Kasetsart University Kamphaengsaen campus Fungus Collection +KKM s Kirkleatham Museum +KKU s Herbarium, Department of Biology, Khon Kaen University +KKUA s Khon Kaen University +KKUK s Kon-Kuk University +KL s Landesmuseum fuer Kaernten +KLA s Herbarium, Department of Agriculture, Malaysia +KLE s University of Keele, Biological Sciences Department +KLGU s Kaliningrad State University, Department of Botany and Plant Ecology +KLH s K. E. Tsiolkovsky Kaluga State Pedagogical University, Department of Botany and Ecology +KLN s Lynn Museum and Art Gallery +KLU s University of Malaya +KM s Kelowna Museum +KM s Sprava Krkonoaskeho narodniho parku +KM s Muzeum Przyrodnicze Uniwersytetu Jagiellonskiego +KM s Kotel'nich Museum +KMG s McGregor Museum +KMK s Kraevedscheskii Musei Kishineva - Museum of Regional Study +KMK s Kaffarian Museum +KMKV s Karlovarske muzeum +KMM c Collection of Marine Microorganisms +KMMA s Royal Museum for Central Africa RMCA +KMMCC c Korea Marine Microalgae Culture Center +KMN s Adger Museum of Natural History and Botanical Garden, Botany Department +KMNH s Kitakyushu Museum and Institute of Natural History, Botany Department +KMU s Karl-Marx-Universitat Leipzeg +KMV s Kunming Municipal Museum +KMVC s Krajske Muzeum Vychodnich Cech +KNFY s Klamath National Forest, Resources Department +KNH h Kongju National University +KNHM s The Educational Science Museum [=Kuwait Natural History Museum?] +KNK s Northern Kentucky University, Department of Biological Sciences +KNL s Kinneil Museum +KNOX s Knox College, Department of Biology +KNP s South African National Parks, Scientific Services +KNU s Kyungpook National University, Biology Department +KNUC s Kangweon National University +KNUH s Kyung-Nam University, Biology Department +KNWR s Kenai National Wildlife Refuge KNWR:Ento s Kenai National Wildlife Refuge, Entomology Collection KNWR:Herb s Kenai National Wildlife Refuge, Herbarium -KNY s Literary and Scientific Institution of Kilkenny -KNYA s Selcuk Ueniversitesi, Biyoloji Boeluemue -KO s P. J. Safarik University -KOCH s Kochi University, Department of Natural Environmental Science -KOELN s Universitaet Koeln, Arbeitsgruppe Geobotanik und Phytotaxonomie -KONL s Bodensee-Naturmuseum -KOPRI c Korean Polar Research Institute +KNY s Literary and Scientific Institution of Kilkenny +KNYA s Selcuk Ueniversitesi, Biyoloji Boeluemue +KO s P. J. Safarik University +KOCH s Kochi University, Department of Natural Environmental Science +KOELN s Universitaet Koeln, Arbeitsgruppe Geobotanik und Phytotaxonomie +KOLABIC s Korean Lichen & Allied Bioresource Center KoLRI +KONL s Bodensee-Naturmuseum +KOPRI c Korean Polar Research Institute KOPRI:KCCPM c Korean Polar Research Institute, KOPRI Culture Collection of Polar Microorganisms -KOR s Institute of Dendrology -KOS c Collection of Salmonella Microorganisms -KPABG s Polar-Alpine Botanical Garden-Institute, Department of Flora and Vegetation -KPBG s Kings Park and Botanic Garden, Botanic Gardens and Parks Authority -KPE s Kyungpook Earth, Kyungpook National University -KPM s Kanagawa Prefectural Museum of Natural History -KPM-NI s Kanagawa Prefectural Museum of Natural History -KPMC s Kalamazoo, Kalamazoo Public Museum -KR s Staatliches Museum fuer Naturkunde Karlsruhe -KRA s Jagiellonian University -KRAM s Polish Academy of Sciences, Department of Plant Systematics -KRAS s Krasnoyarsk State Pedagogical University, Department of Botany -KRB h Kebun Raya Bogor -KRDY s Kirkcaldy Museum and Art Gallery -KRF s V. N. Sukachev Institute of Forest and Wood -KRG s Westfield Museum -KRIB s Korea Research Institute of Bioscience and Biotechnology, Plant Diversity Research Center -KRMS s Sternwarte Kremsmuenster, Stift -KRP sb Kebun Raya Purwodadi (Purwodadi Botanic Gardens, Indonesia) -KRSF s Koronivia Research Station -KRSU s Krasnoyarsk State University, Department of Biogeocoenology -KSAN s South African National Parks -KSBS s Lawrence, University of Kansas, State Biological Survey of Kansas -KSC s Kansas State University -KSEM s Kansas Snow Entomological Museum -KSHS s Kochi Senior High School -KSK s Fitz Part Museum and Art Gallery -KSO s Tweedside Physical and Antiquarian Society Museum -KSP s Pittsburg State University, Biology Department -KSPI h Kostanay State Pedagogical Institute -KSRV s Khosrov State Reserve -KSTC s Emporia State University -KSU s King Saud University, Botany and Microbiology Department -KSUC s Kansas State University -KSUP s King Saud University -KTC s Pedagogical University, Botany Department -KTG s Kettering and District Naturalists' Society and Field Club -KTU s University of Silesia, Department of Plant Systematics -KTUH s Kuwait University, Botany and Microbiology Department -KU s University of Kansas Natural History Museum -KU-MACC c Kobe University Macroalgal Culture Collection +KOR s Institute of Dendrology +KOS c Collection of Salmonella Microorganisms +KPABG s Polar-Alpine Botanical Garden-Institute, Department of Flora and Vegetation +KPBG s Kings Park and Botanic Garden, Botanic Gardens and Parks Authority +KPE s Kyungpook Earth, Kyungpook National University +KPM s Kanagawa Prefectural Museum of Natural History +KPM-NI s Kanagawa Prefectural Museum of Natural History +KPMC s Kalamazoo, Kalamazoo Public Museum +KR s Staatliches Museum fuer Naturkunde Karlsruhe +KRA s Jagiellonian University +KRAM s Polish Academy of Sciences, Department of Plant Systematics +KRAS s Krasnoyarsk State Pedagogical University, Department of Botany +KRB h Kebun Raya Bogor +KRDY s Kirkcaldy Museum and Art Gallery +KRF s V. N. Sukachev Institute of Forest and Wood +KRG s Westfield Museum +KRIB s Korea Research Institute of Bioscience and Biotechnology, Plant Diversity Research Center +KRMS s Sternwarte Kremsmuenster, Stift +KRP sb Kebun Raya Purwodadi (Purwodadi Botanic Gardens, Indonesia) +KRSF s Koronivia Research Station +KRSU s Krasnoyarsk State University, Department of Biogeocoenology +KSAN s South African National Parks +KSBS s Lawrence, University of Kansas, State Biological Survey of Kansas +KSC s Kansas State University +KSEM s Kansas Snow Entomological Museum +KSHS s Kochi Senior High School +KSK s Fitz Part Museum and Art Gallery +KSO s Tweedside Physical and Antiquarian Society Museum +KSP s Pittsburg State University, Biology Department +KSPI h Kostanay State Pedagogical Institute +KSRV s Khosrov State Reserve +KSTC s Emporia State University +KSU s King Saud University, Botany and Microbiology Department +KSUC s Kansas State University KSU +KSUP s King Saud University +KTC s Pedagogical University, Botany Department +KTG s Kettering and District Naturalists' Society and Field Club +KTU s University of Silesia, Department of Plant Systematics +KTUH s Kuwait University, Botany and Microbiology Department +KU s University of Kansas Natural History Museum KUMNA,KUVP,UK +KU-MACC c Kobe University Macroalgal Culture Collection KU:H s University of Kansas Natural History Museum, Herpetology Collection KU:I s University of Kansas Natural History Museum, Ichthyology collection KU:IP s University of Kansas Natural History Museum, Invertebrate Paleontology Collection @@ -3328,45 +3360,46 @@ KU:M s University of Kansas Natural History Museum, Mammology Collection KU:O s University of Kansas Natural History Museum, Ornithology Collection KU:PB s University of Kansas Natural History Museum, Paleobotany Collection KU:VP s University of Kansas Natural History Museum, Vertebrate Paleontology Collection -KU s Kwangsi University -KUBL s Yoshida College, Biological Laboratory -KUEC s Kyushu University Entomology Collection -KUEL s Kyushu University, Entomology Laboratory -KUFC c Kasetsart University Fungus Collection -KUFS h Kabul University -KUH s University of Karachi, Botany Department -KUHE s Kyoto University, Graduate School of Human and Environmental Studies -KUIC s Kagoshima University -KUKENS c Centre for Research and Application of Culture Collections of Microorganisms -KUKI s Kurukshetra University -KUM s Resource Management Support Center -KUMA s Kumamoto University, Biology Department -KUMF s Kasetsart University Museum of Fisheries -KUN s Kunming Institute of Botany, Chinese Academy of Sciences -KUNE s Kunming Institute of Ecology, Academia Sinica -KUO s Kuopio Natural History Museum -KURS s Kursk State University, Department of Botany -KUS s Korea University, Biology Department -KUU s University of Science and Technology -KUW h Kakatiya University -KUZ s Zoological Collection of the Kyoto University -KUZC s Kyushu University, Zoological Collection -KVCH s Kivach Nature Reserve -KW s National Academy of Sciences of Ukraine -KWHA s Ukrainian National Academy of Sciences -KWHU h O. V. Fomin Botanical Garden of National Taras Schevchenko University of Kiev -KWNU s Kangwon National University, Biology Department -KWP s Kenelm W. Philip Collection, University of Alaska Museum of the North +KU s Kwangsi University +KUBL s Yoshida College, Biological Laboratory +KUEC s Kyushu University Entomology Collection +KUEL s Kyushu University, Entomology Laboratory +KUFC c Kasetsart University Fungus Collection +KUFF s Department of Forest Biology, Faculty of Forestry at Kasetsart University +KUFS h Kabul University +KUH s University of Karachi, Botany Department +KUHE s Kyoto University, Graduate School of Human and Environmental Studies +KUIC s Kagoshima University +KUKENS c Centre for Research and Application of Culture Collections of Microorganisms +KUKI s Kurukshetra University +KUM s Resource Management Support Center +KUMA s Kumamoto University, Biology Department +KUMF s Kasetsart University Museum of Fisheries +KUN s Kunming Institute of Botany, Chinese Academy of Sciences +KUNE s Kunming Institute of Ecology, Academia Sinica +KUO s Kuopio Natural History Museum +KURS s Kursk State University, Department of Botany +KUS s Korea University, Biology Department +KUU s University of Science and Technology +KUW h Kakatiya University +KUZ s Zoological Collection of the Kyoto University +KUZC s Kyushu University, Zoological Collection +KVCH s Kivach Nature Reserve +KW s National Academy of Sciences of Ukraine +KWHA s Ukrainian National Academy of Sciences +KWHU h O. V. Fomin Botanical Garden of National Taras Schevchenko University of Kiev +KWNU s Kangwon National University, Biology Department +KWP s Kenelm W. Philip Collection, University of Alaska Museum of the North KWP:Ento s Kenelm W. Philip Collection, University of Alaska Museum of the North, Lepidoptera collection -KY s University of Kentucky -KYM s University of Helsinki, Kymenlaakso Society of Naturalists -KYO s Kyoto University, Botany Department -KYUM s Kyushu University Museum -L sb National Herbarium of the Netherlands (NHN) -LA s University of California -LABCC c Lactic acid bacteria culture collection -LAC s Xian Institute of Lacquer -LACM s Natural History Museum of Los Angeles County +KY s University of Kentucky +KYM s University of Helsinki, Kymenlaakso Society of Naturalists +KYO s Kyoto University, Botany Department +KYUM s Kyushu University Museum +L sb National Herbarium of the Netherlands (NHN) +LA s University of California +LABCC c Lactic acid bacteria culture collection +LAC s Xian Institute of Lacquer +LACM s Natural History Museum of Los Angeles County LACM:Crustacea s Natural History Museum of Los Angeles County, Crustacea Department LACM:Echinoderms s Natural History Museum of Los Angeles County, Echinoderms Department LACM:Entomology s Natural History Museum of Los Angeles County, Entomology Department @@ -3375,337 +3408,337 @@ LACM:Ichthyology s Natural History Museum of Los Angeles County, Ichthyology Dep LACM:Malacology s Natural History Museum of Los Angeles County, Malacology Department LACM:Mammalogy s Natural History Museum of Los Angeles County, Mammalogy Department LACM:Ornithology s Natural History Museum of Los Angeles County, Ornithology Department -LAE s Papua New Guinea Forest Research Institute -LAF s University of Louisiana at Lafayette, Biology Department -LAGO s Pacific Northwest Forest and Range Experiment Station -LAGU s Asociacion Jardin Botanico La Laguna, Urbanizacion Plan de La Laguna -LAH s University of the Punjab, Botany Department -LAJC s Otero Junior College, Biology Department -LAM s Natural History Museum of Los Angeles County, Botanical Studies -LAME s Lake Mead National Recreation Area -LAMU s Lamar University, Biology Department -LAN s Lancing College, Biology Department -LANC s University of Lancaster, Department of Biological Sciences -LAPC s Pierce College, Life Sciences Department -LAPL s Lapland State Biosphere Reserve -LARRI s Living Aquatic Resources Research Institute -LASCA s The Los Angeles County Arboretum -LAT s Saint Vincent College, Biology Department -LATV s University of Latvia, Laboratory of Botany -LAU s Musee et Jardins Botaniques Cantonaux -LAUN s Launceston College -LAUS s Launceston Museum -LAV s Dauntsey's School -LAVO s Lassen Volcanic National Park -LBC s University of the Philippines at Los Banos -LBG c Institute for Agricultural Bacteriology and Fermentation Biology -LBG s Lushan Botanical Garden -LBIT s Laboratoire de Biologie des Insectes -LBL s M. Curie-Sklodowska University, Department of Biology and Earth Science -LBLC s M. Curie-Sklodowska University -LBM c Laboratorio de Biologia Molecula Depto de Biologia Celular -LBM s Lake Biwa Museum -LBN s Lembaga Biologi Nasional -LBRP s Laboratorio de Biodiversidade de Recursos Pesqueiros -LBUCH s Laboratorio de Biologia -LBV s CENAREST -LC h Lewis & Clark College -LCC c Labatt Culture Collection, Technology Development -LCC c University of Warmia and Mazury in Olsztyn -LCDI s Luther College, Biology Department -LCEU s Lane Community College -LCF s I.N.T.A. -LCFM s Musee d'Histoire Naturelle -LCG s Leamington College for Girls -LCH s Letchworth Museum and Art Gallery -LCM s Universidad de Chile, Laboratorio de Citogenetica de Mamiferos -LCMI s Loyola College -LCN s Lincoln City and County Museum -LCO s International Red Locust Control Organization for Central and Southern Africa -LCP c Fungal Strain Collection, Laboratory of Cryptogamy -LCR s Ratcliffe College -LCS s International Red Locust Control Service -LCU s Catholic University of America -LCVA s Lakeland College, Environmental Sciences Department -LD s Botanical Museum, Lunds University -LDL s Ludlow Museum -LDM s Latvian Natural Histotry Museum, department of Entomology -LDPC s L. Deharveng, Universite Paul Sabatier -LDS s University of Leeds -LDSN s Leeds Naturalists' Club -LDSP s Leeds Philosophical and Literary Society Museum -LE c Servico de Microbiologia e Imunologia -LE s V. L. Komarov Botanical Institute -LEA s University of Lethbridge, Biological Sciences Department -LEB s Universidad de Leon, Departamento de Biologia, Botanica -LEB s Entomological Society of Latvia -LEC s Universita degli Studi di Lecce, Dipartimento di Biologia -LECB s Saint Petersburg State University, Botany Department -LEDLIE h Patricia Ledlie Herbarium -LEF s Economic Forestry Institute of Liaoning Province -LEH h Lehigh University -LEI s Leicester Literary and Philosophical Society -LeishCryoBank c International Cryobank of Leishmania -LEIUG s Department of Geology Leicester University -LEMA s Universite du Maine -LEMQ s Lyman Entomological Museum, McGill University, -LEMT s Ege University, Lodos Entomological Museum -LENUD s Lenin University of Dagestan, Botany Department -LEP s All-Union Institute for Plant Protection -LES s Leeds City Museum, Natural History Department -LET s Letchworth Naturalist's Society -LEUN s Bischoefliches Gymnasium Josephinum -LEV s Ministry of Agriculture and Fisheries, Plant Protection Centre -LEYN s Leyton Reference Library -LFBKU s Laboratory of Fishery Biology -LFCC s Lord Fairfax Community College, Natural Resources Department -LFG s Centre de Recherche de la Nature, des Forets et du Bois -LFM s Merseyside County Museums (formerly Liverpool Free Museum) -LG s Universite de Liege, Departement de Botanique -LGBH s Loughborough Public Library -LGEMA s Laboratorio de Genetica e Evolucao Molecular de Aves, Universidade de Sao Paulo -LGHF s Universite de Liege -LGICT s Laboratoire de Geologie de l'Institut Catholique de Toulouse -LGM s Leningrad School of Mines -LGM-USP c Departamento de Microbiologia Lab. de Genetica de Microrganismos -LGO s Columbia University -LGPUT s Laboratory of Geology and Palaeontology -LGU s Leningrad State University -LHMS b Leslie Hill Molecular Systematics Laboratory -LHT s Lahti City Museum -LI s Oberoesterreichischen Landesmuseums, Botanische Abteilung +LAE s Papua New Guinea Forest Research Institute +LAF s University of Louisiana at Lafayette, Biology Department +LAGO s Pacific Northwest Forest and Range Experiment Station +LAGU s Asociacion Jardin Botanico La Laguna, Urbanizacion Plan de La Laguna +LAH s University of the Punjab, Botany Department +LAJC s Otero Junior College, Biology Department +LAM s Natural History Museum of Los Angeles County, Botanical Studies +LAME s Lake Mead National Recreation Area +LAMU s Lamar University, Biology Department +LAN s Lancing College, Biology Department +LANC s University of Lancaster, Department of Biological Sciences +LAPC s Pierce College, Life Sciences Department +LAPL s Lapland State Biosphere Reserve +LARRI s Living Aquatic Resources Research Institute +LASCA s The Los Angeles County Arboretum +LAT s Saint Vincent College, Biology Department +LATV s University of Latvia, Laboratory of Botany +LAU s Musee et Jardins Botaniques Cantonaux +LAUN s Launceston College +LAUS s Launceston Museum +LAV s Dauntsey's School +LAVO s Lassen Volcanic National Park +LBC s University of the Philippines at Los Banos +LBG c Institute for Agricultural Bacteriology and Fermentation Biology +LBG s Lushan Botanical Garden +LBIT s Laboratoire de Biologie des Insectes +LBL s M. Curie-Sklodowska University, Department of Biology and Earth Science +LBLC s M. Curie-Sklodowska University +LBM c Laboratorio de Biologia Molecula Depto de Biologia Celular +LBM s Lake Biwa Museum +LBN s Lembaga Biologi Nasional +LBRP s Laboratorio de Biodiversidade de Recursos Pesqueiros +LBUCH s Laboratorio de Biologia +LBV s CENAREST +LC h Lewis & Clark College +LCC c Labatt Culture Collection, Technology Development +LCC c University of Warmia and Mazury in Olsztyn +LCDI s Luther College, Biology Department +LCEU s Lane Community College +LCF s I.N.T.A. +LCFM s Musee d'Histoire Naturelle +LCG s Leamington College for Girls +LCH s Letchworth Museum and Art Gallery +LCM s Universidad de Chile, Laboratorio de Citogenetica de Mamiferos +LCMI s Loyola College +LCN s Lincoln City and County Museum +LCO s International Red Locust Control Organization for Central and Southern Africa +LCP c Fungal Strain Collection, Laboratory of Cryptogamy +LCR s Ratcliffe College +LCS s International Red Locust Control Service +LCU s Catholic University of America +LCVA s Lakeland College, Environmental Sciences Department +LD s Botanical Museum, Lunds University +LDL s Ludlow Museum +LDM s Latvian Natural Histotry Museum, department of Entomology +LDPC s L. Deharveng, Universite Paul Sabatier +LDS s University of Leeds +LDSN s Leeds Naturalists' Club +LDSP s Leeds Philosophical and Literary Society Museum +LE c Servico de Microbiologia e Imunologia +LE s V. L. Komarov Botanical Institute +LEA s University of Lethbridge, Biological Sciences Department +LEB s Universidad de Leon, Departamento de Biologia, Botanica +LEB s Entomological Society of Latvia +LEC s Universita degli Studi di Lecce, Dipartimento di Biologia +LECB s Saint Petersburg State University, Botany Department +LEDLIE h Patricia Ledlie Herbarium +LEF s Economic Forestry Institute of Liaoning Province +LEH h Lehigh University +LEI s Leicester Literary and Philosophical Society +LeishCryoBank c International Cryobank of Leishmania +LEIUG s Department of Geology Leicester University +LEMA s Universite du Maine +LEMQ s Lyman Entomological Museum, McGill University, LEM +LEMT s Ege University, Lodos Entomological Museum +LENUD s Lenin University of Dagestan, Botany Department +LEP s All-Union Institute for Plant Protection +LES s Leeds City Museum, Natural History Department +LET s Letchworth Naturalist's Society +LEUN s Bischoefliches Gymnasium Josephinum +LEV s Ministry of Agriculture and Fisheries, Plant Protection Centre +LEYN s Leyton Reference Library +LFBKU s Laboratory of Fishery Biology +LFCC s Lord Fairfax Community College, Natural Resources Department +LFG s Centre de Recherche de la Nature, des Forets et du Bois +LFM s Merseyside County Museums (formerly Liverpool Free Museum) +LG s Universite de Liege, Departement de Botanique +LGBH s Loughborough Public Library +LGEMA s Laboratorio de Genetica e Evolucao Molecular de Aves, Universidade de Sao Paulo +LGHF s Universite de Liege +LGICT s Laboratoire de Geologie de l'Institut Catholique de Toulouse +LGM s Leningrad School of Mines +LGM-USP c Departamento de Microbiologia Lab. de Genetica de Microrganismos +LGO s Columbia University +LGPUT s Laboratory of Geology and Palaeontology +LGU s Leningrad State University +LHMS b Leslie Hill Molecular Systematics Laboratory +LHT s Lahti City Museum +LI s Oberoesterreichischen Landesmuseums, Botanische Abteilung LI:EVAR s Oberoesterreichischen Landesmuseums, Botanische Abteilung, Evertebrata Varia (Invertebrates other than Insects) LI:INS s Oberoesterreichischen Landesmuseums, Botanische Abteilung, Insect collection LI:VERT s Oberoesterreichischen Landesmuseums, Botanische Abteilung, Vertebrate collection -LIA c Cryobank of Microorganisms -LIAIP s Laboratory of Ichthyology -LIB s University of Liberia -LICPP s The Crown Prince's Palace -LIG s Sociedade de Geografia de Lisboa -LIH-UNAM c Culture Collection of Histoplasma capsulatum Strains from the Fungal Immunology Laboratory of the Department of Microbiology and Parasitology, Faculty of Medicine, UNAM -LIHUBA s Universidad de Buenos Aires, Laboratorio de Investigaciones Herpetologicas -LIL s Fundacion Miguel Lillo -LILLE s Institut Catholique de Lille, Laboratoire de Biologie Vegetale -LIM s Severoceske muzeum -LIMFC s Limerick Field Club -LIMK s Limerick Museum -LIMO h Universite de Limoges -LIN-SB c Limnological Institute, Siberian Branch, Russian Academy of Sciences -LINC s Lincoln University, Plant Sciences Group -LINCO h Linfield College -LINF s Shanxi Normal University, Biology Department -LINHM s Long Island Natural History Museum -LINN s Linnean Society of London -LIP s Universite de Lille, Departement de Botanique -LIPIMC c Lembaga Ilmu Pengetahuan Indonesia, Indonesian Institute for Sciences -LIPP c Leptospirotheque -LIRP s Laboratorio de Ictiologia, Faculdade de Filosofia -LISC s Instituto de Investigacao Cientifica Tropical -LISE s Estacao Agronomica Nacional -LISFA s Instituto Nacional de Investigacao Agraria, Departamento Ecologia, Recursos Naturais e Ambiente -LISI s Instituto Superior de Agronomia -LISJC s Jardim-Museu Agricola Tropical -LISM s Missao de Estudos Agronomicos do Ultramar -LISU s Museu Nacional de Historia Natural -LISVA s Ministerio da Educacao -LIT s Okresni vlastivedne muzeum -LIUSP s Laboratorio de Ictiogenetica, Universidade de Sao Paulo -LIV s Liverpool Museum -LIVC s Liverpool Botanic Garden -LIVCM s Liverpool County Museum -LIVNFC s Liverpool Naturalists' Field Club -LIVU s Hartley Botanical Laboratories -LJC c Coleccion de fitopatogenos de cultivos horticolas -LJF h Slovenian Forestry Institute -LJM s Prirodoslovni Muzej Slovenije -LJS h Scientific Research Centre -LJU s University of Ljubljana, Botany Department -LKHD s Lakehead University, Biology Department -LL s University of Texas at Austin, Plant Resources Center -LLANOS h Universidad de los Llanos -LLC s Our Lady of the Lake University, Biology Department -LLN s Lincolnshire Naturalists' Union -LLO s Lloyd Library and Museum -LM s Seccao de Botanica e Ecologia -LMA s National Institute of Agronomic Research, Botany Department -LMAD s Lobbecke Museum und Aquazoo -LMC s Instituto de Investigacao Cientifica de Mozambique -LMCH c Laboratoire de Microbiologie -LMD c Laboratorium voor Microbiologie der Landbouwhogeschool -LMG c Belgian Coordinated Collections of Microorganisms/ LMG Bacteria Collection -LMJ s Landesmuseum Joanneum Graz -LMJ s Centro de Investigacao Cientifica Algodoeira, Botanical Department -LMKG s Landesmuseum fur Karnten -LMND s Landessammlungen fuer Naturkunde -LMNH s Museum d'Histoire naturelle -LMO h Landesmuseum Natur und Mensch -LMRZ s Livingstone Museum -LMS c Carolina Biological Supply Company -LMSZ s Latvian University, Museum of Systemic Zoology -LMU s Eduardo Mondlane University, Department of Biological Sciences -LMZG s Local Museum -LNAF s Liaoning Academy of Forestry -LNAU h Luhansk National Agrarian University -LNCM s Liaoning College of Traditional Chinese Medicine -LNCN h Lincoln Memorial University -LNHS s London Natural History Society -LNK s Landessammlungen fuer Naturkunde -LNKD s Landessammlung fuer Naturkunde -LNMD s Landessammlungen fuer Naturkunde -LNMO s Oldenburg, Landesmuseum Natur und Mensch -LNNU s Liaoning Normal University, Biology Department -LNPV c Laboratoire National de la Protection des Vegetaux -LO s Type Collection -LOB s California State University, Biological Sciences Department -LOC s Occidental College, Biology Department -LOCK c Centre of Industrial Microorganisms Collection -LOD s Lodz University, Department of Geobotany and Plant Ecology -LOJA s Universidad Nacional de Loja, Departamento de Botanica y Ecologia -LOMA s La Sierra University, Biology Department -LON s Lembaga Oseanologie Nasional -LOU s C.I.T.A.-Xunta de Galicia -LP s Museo de La Plata, Herbario -LP s Laboratory of Palaeontology -LPA s Jardin Botanico Canario Viera y Clavijo -LPAG s Universidad Nacional de La Plata, Area de Botanica -LPB s Herbario Nacional de Bolivia -LPC h Museo de La Plata -LPD s Laboratorio de Botanica de la Direccion de Agricultura -LPFU s Lehrstuhl fur Palaontologie -LPL s The University -LPN s Littlehampton Museum -LPS s Universidad Nacional de La Plata, Instituto de Botanica Carlos Spegazzini -LPSC c La Plata Spegazzini Collection -LPSP s Lumus Pond State Park, Whale Wallow Nature Center -LPUB s Laboratorul de Paleontologie -LPUP s Laboratoire de Parasitologie -LPVM s Laboratoire de Paleontologie des Vertebres et de Paleontologie -LPVPH s Laboratoire de Paleontologie des Vertebres et de Paleontologie Humaine -LR s Museum d'Histoire Naturelle -LRL s Historic Society of Lancashire and Cheshire -LRS s Agriculture Research Center, Land Resource Sciences Section -LRTE s La Retraite (Convent School) -LRU s University of Arkansas at Little Rock, Biology Department -LS s Colegio de La Salle -LS s Linnean Society of London -LSA s Lytham St. Annes Public Library -LSAM s Louisiana State Arthropod Museum -LSC s Lyndon State College, Natural Sciences Department -LSCR s Organization for Tropical Studies, La Selva Biological Station -LSDC s Liangshan Institute for Drug Control -LSHB c Biochemistry Department -LSHI s Universite Nationale du Zaire -LSN s Lord Wandsworth College Natural History Museum -LSP s Lake Superior Provincial Park -LSR s Leicestershire Museums Service -LSRFC s Leicestershire Flora Committee -LSSC s Lake Superior State College -LSTM c Department of Parasitology -LSU s Louisiana State University, Biological Sciences Department -LSUHC s La Sierra University, Herpetological Collection -LSUM s Louisiana State University, Biological Sciences Department -LSUMZ s Louisiana State University, Musuem of Zoology +LIA c Cryobank of Microorganisms +LIAIP s Laboratory of Ichthyology +LIB s University of Liberia +LICPP s The Crown Prince's Palace +LIG s Sociedade de Geografia de Lisboa +LIH-UNAM c Culture Collection of Histoplasma capsulatum Strains from the Fungal Immunology Laboratory of the Department of Microbiology and Parasitology, Faculty of Medicine, UNAM +LIHUBA s Universidad de Buenos Aires, Laboratorio de Investigaciones Herpetologicas +LIL s Fundacion Miguel Lillo +LILLE s Institut Catholique de Lille, Laboratoire de Biologie Vegetale +LIM s Severoceske muzeum +LIMFC s Limerick Field Club +LIMK s Limerick Museum +LIMO h Universite de Limoges +LIN-SB c Limnological Institute, Siberian Branch, Russian Academy of Sciences +LINC s Lincoln University, Plant Sciences Group +LINCO h Linfield College +LINF s Shanxi Normal University, Biology Department +LINHM s Long Island Natural History Museum +LINN s Linnean Society of London +LIP s Universite de Lille, Departement de Botanique +LIPIMC c Lembaga Ilmu Pengetahuan Indonesia, Indonesian Institute for Sciences +LIPP c Leptospirotheque +LIRP s Laboratorio de Ictiologia, Faculdade de Filosofia +LISC s Instituto de Investigacao Cientifica Tropical +LISE s Estacao Agronomica Nacional +LISFA s Instituto Nacional de Investigacao Agraria, Departamento Ecologia, Recursos Naturais e Ambiente +LISI s Instituto Superior de Agronomia +LISJC s Jardim-Museu Agricola Tropical +LISM s Missao de Estudos Agronomicos do Ultramar +LISU s Museu Nacional de Historia Natural +LISVA s Ministerio da Educacao +LIT s Okresni vlastivedne muzeum +LIUSP s Laboratorio de Ictiogenetica, Universidade de Sao Paulo +LIV s Liverpool Museum +LIVC s Liverpool Botanic Garden +LIVCM s Liverpool County Museum +LIVNFC s Liverpool Naturalists' Field Club +LIVU s Hartley Botanical Laboratories +LJC c Coleccion de fitopatogenos de cultivos horticolas +LJF h Slovenian Forestry Institute +LJM s Prirodoslovni Muzej Slovenije +LJS h Scientific Research Centre +LJU s University of Ljubljana, Botany Department +LKHD s Lakehead University, Biology Department +LL s University of Texas at Austin, Plant Resources Center +LLANOS h Universidad de los Llanos +LLC s Our Lady of the Lake University, Biology Department +LLN s Lincolnshire Naturalists' Union +LLO s Lloyd Library and Museum +LM s Seccao de Botanica e Ecologia +LMA s National Institute of Agronomic Research, Botany Department +LMAD s Lobbecke Museum und Aquazoo +LMC s Instituto de Investigacao Cientifica de Mozambique +LMCH c Laboratoire de Microbiologie +LMD c Laboratorium voor Microbiologie der Landbouwhogeschool +LMG c Belgian Coordinated Collections of Microorganisms/ LMG Bacteria Collection BCCM/LMG +LMJ s Landesmuseum Joanneum Graz +LMJ s Centro de Investigacao Cientifica Algodoeira, Botanical Department +LMKG s Landesmuseum fur Karnten +LMND s Landessammlungen fuer Naturkunde +LMNH s Museum d'Histoire naturelle +LMO h Landesmuseum Natur und Mensch +LMRZ s Livingstone Museum +LMS c Carolina Biological Supply Company +LMSZ s Latvian University, Museum of Systemic Zoology +LMU s Eduardo Mondlane University, Department of Biological Sciences +LMZG s Local Museum +LNAF s Liaoning Academy of Forestry +LNAU h Luhansk National Agrarian University +LNCM s Liaoning College of Traditional Chinese Medicine +LNCN h Lincoln Memorial University +LNHS s London Natural History Society +LNK s Landessammlungen fuer Naturkunde +LNKD s Landessammlung fuer Naturkunde +LNMD s Landessammlungen fuer Naturkunde +LNMO s Oldenburg, Landesmuseum Natur und Mensch +LNNU s Liaoning Normal University, Biology Department +LNPV c Laboratoire National de la Protection des Vegetaux +LO s Type Collection +LOB s California State University, Biological Sciences Department +LOC s Occidental College, Biology Department +LOCK c Centre of Industrial Microorganisms Collection +LOD s Lodz University, Department of Geobotany and Plant Ecology +LOJA s Universidad Nacional de Loja, Departamento de Botanica y Ecologia +LOMA s La Sierra University, Biology Department +LON s Lembaga Oseanologie Nasional +LOU s C.I.T.A.-Xunta de Galicia +LP s Museo de La Plata, Herbario +LP s Laboratory of Palaeontology +LPA s Jardin Botanico Canario Viera y Clavijo +LPAG s Universidad Nacional de La Plata, Area de Botanica +LPB s Herbario Nacional de Bolivia +LPC h Museo de La Plata +LPD s Laboratorio de Botanica de la Direccion de Agricultura +LPFU s Lehrstuhl fur Palaontologie +LPL s The University +LPN s Littlehampton Museum +LPS s Universidad Nacional de La Plata, Instituto de Botanica Carlos Spegazzini +LPSC c La Plata Spegazzini Collection +LPSP s Lumus Pond State Park, Whale Wallow Nature Center +LPUB s Laboratorul de Paleontologie +LPUP s Laboratoire de Parasitologie +LPVM s Laboratoire de Paleontologie des Vertebres et de Paleontologie +LPVPH s Laboratoire de Paleontologie des Vertebres et de Paleontologie Humaine +LR s Museum d'Histoire Naturelle +LRL s Historic Society of Lancashire and Cheshire +LRS s Agriculture Research Center, Land Resource Sciences Section +LRTE s La Retraite (Convent School) +LRU s University of Arkansas at Little Rock, Biology Department +LS s Colegio de La Salle +LS s Linnean Society of London LSUK +LSA s Lytham St. Annes Public Library +LSAM s Louisiana State Arthropod Museum +LSC s Lyndon State College, Natural Sciences Department +LSCR s Organization for Tropical Studies, La Selva Biological Station +LSDC s Liangshan Institute for Drug Control +LSHB c Biochemistry Department +LSHI s Universite Nationale du Zaire +LSN s Lord Wandsworth College Natural History Museum +LSP s Lake Superior Provincial Park +LSR s Leicestershire Museums Service +LSRFC s Leicestershire Flora Committee +LSSC s Lake Superior State College +LSTM c Department of Parasitology +LSU s Louisiana State University, Biological Sciences Department +LSUHC s La Sierra University, Herpetological Collection +LSUM s Louisiana State University, Biological Sciences Department +LSUMZ s Louisiana State University, Musuem of Zoology LSUMNS LSUMZ:FrozenTissue s Louisiana State University, Musuem of Zoology, Frozen Tissue Collection LSUMZ:Herpetology s Louisiana State University, Musuem of Zoology, Herpetology Collection LSUMZ:Ichthyology s Louisiana State University, Musuem of Zoology, Ichthyology Collection LSUMZ:Mammalogy s Louisiana State University, Musuem of Zoology, Mammal Collection LSUMZ:Ornithology s Louisiana State University, Musuem of Zoology, Bird Collection -LSUS s Museum of Life Sciences, Louisiana State University -LT s Universite de Montreal -LTB s La Trobe University, Botany Department -LTCC-IOC c Leishmania Type Culture Collection -LTH s Museum of Louth Naturalists' Antiquity and Literary Society -LTHP s Louth Public Library -LTI c Cryobank of Microorganisms-Destructors -LTM s Tekovske muzeum -LTN s Luton Museum and Art Gallery -LTR s University of Leicester, Biology Department -LTU s Louisiana Tech University -LU s Lingnan University -LU s St. Petersburg University -LUA s Instituto de Investigacao Agronomica -LUAI s ex-Centro Nacional de Investigacao Cientifica (CNIC) -LUB s Naturhistorisches Museum zu Luebeck -LUBA s Instituto Superior de Ciencias da Educacao -LUBEE b Lubee Bat Conservancy -LUCAS s Francesc de Lucas i Alcover -LUCCA s Comune di Lucca -LUCH s Musee du Pays de Luchon -LUD s Ludlow Natural History Society -LUG s Museo cantonale di storia naturale -LUGO s Universidad de Satniago de Compostela, Departamento de Produccion Vegetal -LUH s University of Lagos, Biological Sciences Department, Botany Unit -LUH c Leiden University Medical Center -LUKI h Institut National pour l'Etude et la Recherche Agronomiques -LUNZ s Lincoln University Entomology Research Museum -LUQ s Laval University -LUS s Lushan Botanical Garden -LUSC h Universidade do Estado de Santa Catarina -LUW s Landbouwuniversiteit Wageningen, Department of Entomology -LUX s Musee national d'histoire naturelle -LV s Catholic University of Leuven, Laboratory of Plant Systematics -LVNP s Lassen Volcanic National Park -LVP-GSC s Laboratory of Vertebrate Paleontology -LW s Ivan Franko National University of Lviv, Botany Department -LWA s Agricultural Experiment Station -LWD s Museum Dzieduszyckich -LWG s National Botanical Research Institute -LWI h Centre de Recherche en Sciences Naturelles (CRSN/Lwiro) -LWKS s Institute of Ecology of the Carpathians -LWL s LWL-Museum fuer Naturkunde +LSUS s Museum of Life Sciences, Louisiana State University +LT s Universite de Montreal +LTB s La Trobe University, Botany Department +LTCC-IOC c Leishmania Type Culture Collection +LTH s Museum of Louth Naturalists' Antiquity and Literary Society +LTHP s Louth Public Library +LTI c Cryobank of Microorganisms-Destructors +LTM s Tekovske muzeum +LTN s Luton Museum and Art Gallery +LTR s University of Leicester, Biology Department +LTU s Louisiana Tech University +LU s Lingnan University +LU s St. Petersburg University +LUA s Instituto de Investigacao Agronomica +LUAI s ex-Centro Nacional de Investigacao Cientifica (CNIC) +LUB s Naturhistorisches Museum zu Luebeck +LUBA s Instituto Superior de Ciencias da Educacao +LUBEE b Lubee Bat Conservancy +LUCAS s Francesc de Lucas i Alcover +LUCCA s Comune di Lucca +LUCH s Musee du Pays de Luchon +LUD s Ludlow Natural History Society +LUG s Museo cantonale di storia naturale +LUGO s Universidad de Satniago de Compostela, Departamento de Produccion Vegetal +LUH s University of Lagos, Department of Botany +LUH c Leiden University Medical Center +LUKI h Institut National pour l'Etude et la Recherche Agronomiques +LUNZ s Lincoln University Entomology Research Museum +LUQ s Laval University +LUS s Lushan Botanical Garden +LUSC h Universidade do Estado de Santa Catarina +LUW s Landbouwuniversiteit Wageningen, Department of Entomology +LUX s Musee national d'histoire naturelle +LV s Catholic University of Leuven, Laboratory of Plant Systematics +LVNP s Lassen Volcanic National Park +LVP-GSC s Laboratory of Vertebrate Paleontology +LW s Ivan Franko National University of Lviv, Botany Department +LWA s Agricultural Experiment Station +LWD s Museum Dzieduszyckich +LWG s National Botanical Research Institute +LWI h Centre de Recherche en Sciences Naturelles (CRSN/Lwiro) +LWKS s Institute of Ecology of the Carpathians +LWL s LWL-Museum fuer Naturkunde LWL:DNA b LWL-Museum fuer Naturkunde, LWL-DNA- und Gewebearchiv -LWS s Museum of Natural History, Lviv -LWSM s Lewes Museum, Ann of Cleves House -LWU s University of Lucknow, Botany Department -LY c Laboratoire de Mycologie associe au CNRS -LYAC s Laiyang Agricultural College, Department of Basic Courses -LYCC c Lallemand Yeast Culture Collection -LycoCC c The Lycoming College Culture Collection -LYD s Mpumalanga Parks Board -LYJB s Jardin Botanique de Lyon -LYN s Lynchburg College, Biology Department -LZ s Universitaet Leipzig -LZAH s Lanzhou Institute of Animal Science, Chinese Academy of Agricultural Sciences -LZD s Lanzhou Institute of Desert Research, Academia Sinica -LZFD s Laboratoire Zoologique -LZLP s Universidade de Lisboa -LZU s Lanzhou University -LZUH s Laboratoire de Zoologie, Universite de Hanoi -M s Botanische Staatssammlung Muenchen -MA s Real Jardin Botanico +LWS s Museum of Natural History, Lviv +LWSM s Lewes Museum, Ann of Cleves House +LWU s University of Lucknow, Botany Department +LY sc Universite Claude Bernard +LYAC s Laiyang Agricultural College, Department of Basic Courses +LYCC c Lallemand Yeast Culture Collection +LycoCC c The Lycoming College Culture Collection +LYD s Mpumalanga Parks Board +LYJB s Jardin Botanique de Lyon +LYN s Lynchburg College, Biology Department +LZ s Universitaet Leipzig +LZAH s Lanzhou Institute of Animal Science, Chinese Academy of Agricultural Sciences +LZD s Lanzhou Institute of Desert Research, Academia Sinica +LZFD s Laboratoire Zoologique +LZLP s Universidade de Lisboa +LZU s Lanzhou University +LZUH s Laboratoire de Zoologie, Universite de Hanoi +M s Botanische Staatssammlung Muenchen +MA s Real Jardin Botanico MA:Algae s Real Jardin Botanico, Algae collection MA:Fungi s Real Jardin Botanico, Fungi collection MA:FunHist s Real Jardin Botanico, Historical fungi colleciton MA:Hepat s Real Jardin Botanico, Liverwort collection MA:Lichen s Real Jardin Botanico, Lichen collection MA:Musci s Real Jardin Botanico, Bryophyte collection -MAA s Escuela Tecnica Superior de Ingenieros Agronomos, Departamento de Produccion Vegetal -MAAS s Natuurhistorisch Museum Maastricht, Botany Department -MAC s Instituto do Meio Ambiente -MAC-APU s Ministerio de Agricultura y Cria -MAC-PAY s Ministerio de Agricultura y Cria -MACA s Parque da Reserva de Siac Pai van Coloane Island -MACB s Universidad Complutense, Departamento de Biologia Vegetal 1 -MACF s California State University, Biological Science Department -MACLPI s Ministerio de Agricultura y Cria, Seccion de Pesca Interior y Piscicultura -MACN s Museo Argentino de Ciencias Naturales Bernardino Rivadavia -MACN-RN s Museo Argentino de Cicencis Naturales, Coleccion Rio Negro -MACNCH s Museo Argentino de Ciencias Naturales -MACO s Marlborough College, Biology Department -MAD s Madras Museum -MAD s Forest Products Laboratory -MADJ s Jardim Botanico da Madeira -MADM s Museu Municipal do Funchal -MADS s Museu de Historia Natural do Seminario do Funchal -MAF s Universidad Complutense, Departamento de Biologia Vegetal II -MAFF c MAFF Genebank, Ministry of Agriculture Forestry and Fisheries -MAFF s Colo-i-Suva Silvicultural Station -MAFI s Magyar Allami Foeldtani Intezet, Budapest - Hungarian Geological Survey -MAFST s Instituto Forestal de la Moncloa -MAG s Institute of Biological Problems of the North -MAGB s National Museum and Art Gallery, Gaberone -MAGD s Northern Territory Museum of Arts and Sciences -MAGNT s Museums and Art Galleries of the Northern Territory +MAA s Escuela Tecnica Superior de Ingenieros Agronomos, Departamento de Produccion Vegetal +MAAS s Natuurhistorisch Museum Maastricht, Botany Department +MAC s Instituto do Meio Ambiente +MAC-APU s Ministerio de Agricultura y Cria +MAC-PAY s Ministerio de Agricultura y Cria +MACA s Parque da Reserva de Siac Pai van Coloane Island +MACB s Universidad Complutense, Departamento de Biologia Vegetal 1 +MACF s California State University, Biological Science Department +MACLPI s Ministerio de Agricultura y Cria, Seccion de Pesca Interior y Piscicultura +MACN s Museo Argentino de Ciencias Naturales Bernardino Rivadavia +MACN-RN s Museo Argentino de Cicencis Naturales, Coleccion Rio Negro +MACNCH s Museo Argentino de Ciencias Naturales +MACO s Marlborough College, Biology Department +MAD s Madras Museum +MAD s Forest Products Laboratory +MADJ s Jardim Botanico da Madeira +MADM s Museu Municipal do Funchal +MADS s Museu de Historia Natural do Seminario do Funchal +MAF s Universidad Complutense, Departamento de Biologia Vegetal II +MAFF c MAFF Genebank, Ministry of Agriculture Forestry and Fisheries +MAFF s Colo-i-Suva Silvicultural Station +MAFI s Magyar Allami Foeldtani Intezet, Budapest - Hungarian Geological Survey +MAFST s Instituto Forestal de la Moncloa +MAG s Institute of Biological Problems of the North +MAGB s National Museum and Art Gallery, Gaberone +MAGD s Northern Territory Museum of Arts and Sciences +MAGNT s Museums and Art Galleries of the Northern Territory NTM MAGNT:A s Museums and Art Galleries of the Northern Territory, Arachnid Collection MAGNT:C s Museums and Art Galleries of the Northern Territory, Cnidarian Collection MAGNT:Cr s Museums and Art Galleries of the Northern Territory, Crustacean Collection @@ -3723,136 +3756,137 @@ MAGNT:T s Museums and Art Galleries of the Northern Territory, Bird Collect MAGNT:U s Museums and Art Galleries of the Northern Territory, Mammal Collection MAGNT:W s Museums and Art Galleries of the Northern Territory, Annelid Collection MAGNT:Z s Museums and Art Galleries of the Northern Territory, Poriferan Collection -MAH s Department of Agricultural Research -MAIA s Instituto Nacional de Investigaciones Agrarias, Departamento de Ecologia -MAIC s Mediterranean Agronomic Institute of Chania, Department of Natural Products -MAINE s University of Maine, Department of Biological Sciences -MAIS s Institut d'Elevage et de Medecine Veterinaire des Pays Tropicaux, Departement de Botanique -MAK s Tokyo Metropolitan University -MAKAR s Institut Planina i More -MAKFUNGI s Fungi Macedonici -MAL s Botanic Gardens of Malawi -MALA s Malaspina University, Biology Department -MALC s Museu Municipal de la Vila d'Alcover -MALS s Manti-LaSal National Forest -MAMU s University of Sydney, Macleay Museum -MAN s Universitas Cenderawasih -MANCH s University of Manchester -MAND s Agricultural College and Research Institute -MANK s Minnesota State University-Mankato, Department of Biological Sciences -MAO c Mircen Afrique Ouest -MAPA s Museu Anchieta Porto Alegra -MAPR s University of Puerto Rico, Mayagueez Campus, Biology Department -MAR c Grasslands Rhizobium Collection -MARDI h Malaysian Agricultural Research and Development Institute -MARE s Marmara University, Department of Pharmaceutical Botany -MARI h Mari State University -MARK h Cadi Ayyad University -MARO s Marylhurst College -MARS s Universite de Provence Centre St-Charles, case 4 -MARSSJ s Universite Paul Cezanne -MARY s University of Maryland -MASE s Maseru Experiment Station -MASS s University of Massachusetts, Biology Department -MATSU s Ehime University, Forestry Department -MAU s Mauritius Sugar Industry Research Institute -MAUAM h Universidad Autonoma de Madrid -MAY s Adygean State University, Department of Botany -MB s Museum of Natural History of Humboldt-University -MB s Philipps-Universitaet, Spezielle Botanik -MB s Universidade de Lisboa, Museu Bocage -MBA s Environmental Protection Agency -MBAB s Museo Biblioteca Archivio -MBAC s Museo del Dipartimento di Biologia Animale dell'Universita -MBAP s Museo del Dipartimento di Biologia Animale dell'Universita -MBBJ s Museum Zoologicum Bogoriense, Entomology Collection -MBC sb Montgomery Botanical Center -MBCG s Museo di Scienze Naturali "Enrico Caffi" -MBCSC s Marine Biodiversity Collection of South China Sea, Chinese Academy of Sciences +MAH s Department of Agricultural Research +MAIA s Instituto Nacional de Investigaciones Agrarias, Departamento de Ecologia +MAIC s Mediterranean Agronomic Institute of Chania, Department of Natural Products +MAINE s University of Maine, Department of Biological Sciences +MAIS s Institut d'Elevage et de Medecine Veterinaire des Pays Tropicaux, Departement de Botanique +MAK s Tokyo Metropolitan University +MAKAR s Institut Planina i More +MAKFUNGI s Fungi Macedonici +MAL s Botanic Gardens of Malawi +MALA s Malaspina University, Biology Department +MALC s Museu Municipal de la Vila d'Alcover +MALS s Manti-LaSal National Forest +MAMU s University of Sydney, Macleay Museum +MAN s Universitas Cenderawasih +MANCH s University of Manchester +MAND s Agricultural College and Research Institute +MANK s Minnesota State University-Mankato, Department of Biological Sciences +MAO c Mircen Afrique Ouest +MAPA s Museu Anchieta Porto Alegra +MAPR s University of Puerto Rico, Mayagueez Campus, Biology Department +MAR c Grasslands Rhizobium Collection +MARDI h Malaysian Agricultural Research and Development Institute +MARE s Marmara University, Department of Pharmaceutical Botany +MARI h Mari State University +MARK h Cadi Ayyad University +MARO s Marylhurst College +MARS s Universite de Provence Centre St-Charles, case 4 +MARSSJ s Universite Paul Cezanne +MARY s University of Maryland +MASE s Maseru Experiment Station +MASS s University of Massachusetts, Biology Department +MATSU s Ehime University, Forestry Department +MAU s Mauritius Sugar Industry Research Institute +MAUAM h Universidad Autonoma de Madrid +MAY s Adygean State University, Department of Botany +MB s Museum of Natural History of Humboldt-University +MB s Philipps-Universitaet, Spezielle Botanik +MB s Universidade de Lisboa, Museu Bocage +MBA s Environmental Protection Agency +MBAB s Museo Biblioteca Archivio +MBAC s Museo del Dipartimento di Biologia Animale dell'Universita +MBAP s Museo del Dipartimento di Biologia Animale dell'Universita +MBBJ s Museum Zoologicum Bogoriense, Entomology Collection +MBC sb Montgomery Botanical Center MBC +MBCG s Museo di Scienze Naturali "Enrico Caffi" +MBCSC s Marine Biodiversity Collection of South China Sea, Chinese Academy of Sciences MBCSC:Fish s Marine Biodiversity Collection of South China Sea, Chinese Academy of Sciences, Fish Collection -Mbg s Fachberich Geowissenschaften -MBH s Marlborough College -MBIC c Marine Biotechnology Institute Culture Collection -MBK s Kochi Prefectural Makino Botanical Garden, Botany Department -MBL s Museu Nacional de Historia Natural -MBM s Museu Botanico Municipal -MBM s San Jose State University, Museum of Birds and Mammals -MBM s Marjorie Barrick Museum -MBML s Museu de Biologia Mello Leitao -MBMU c Institute of Molecular Biology and Genetics (IMBG), Mahidol University -MBR s Museo Argention de Ciencias Naturales "Bernardino Rivadavia" -MBS s Manchester Banksian Society -MBSL s Royal Medico-Botanical Society -MBSN s Museo Brembano di Scienze Naturali -MBUCV s Museo de Biologia de la Universidad Central de Venezuela -MBZH s Museo y Biblioteca de la Zoologia -MC s Museo de Cipolleti -MCA s Muhlenberg College, Biology Department -MCAS s Museo Civico Archeologico e di Scienze Naturali "F. Eusebio" -MCBR s Museo Civico "Baldassarre Romano" -MCC c Microbial Culture Collection -MCC-UPLB c Microbial Culture Collection -MCCB s Museo Civico "Craveri" -MCCC c Marine Culture Collection of China -MCCI s Museo Civico di Storia Natural de Carmognola -MCCM c Medical Culture Collection Marburg -MCCM s Madras Christian College -MCD s Muzeul Civilizatiei Dacice si Romane Deva -MCDNL h McDaniel College -MCES s Museum of the Center for Entomological Studies -MCF h Sts. Cyril and Methodius University -MCF-PVPH s Museo Carmen Funes -MCFB s Museo de la Cienica Fundacion -MCFM s Museo Civico "Francesco Mina Palumbo" -MCFS s Museo Civico di Storia Naturale, Ferrara -MCG s Museo Civico DI Storia Naturale 'Giacomo Doria' -McGMK s McGregor Memorial Museum -MCGS s Museo Civico "Giuseppe Scarabelli" -MCITM c Bacterial Culture Collection -MCIZ s Museo Cambria, Istituto di Zoologia dell'Universita -MCJ s Missouri Southern State College, Biology Department -MCLSBB s Museo Colegio La Salle Bonanova de Barcelona -MCM(CMFRI) s Reference Collection -MCM s Hamilton College, McMaster University, Biology Department -MCM s Institut de Paleontologie, Museum d'Histoire naturelle -MCM c MACS Collection of Microorganisms -MCM s Museu Carlos Machado -MCMC s Museo de Historia Natural de la Ciudad de Mexico -McMJ s Mc Master University -MCMS s Museo Civico di Storia Naturale, Morgegno -MCN s McNeese State University, Biology Department -MCNA s Museo de Ciencias naturals de Alava -MCNC s Museo de Ciencias Naturales -MCNG s Museo de Ciencias Naturales de la UNELLEZ en Guanare -MCNPV s Fundacao Zoobotanica do Rio Grande do Sul -MCNS s Universidad Nacional de Salta, Facultad de Ciencias Naturales -MCNV s Museo Civico di Storia Naturale, Venice -MCNZ s Porto Alegre, Museu de Ciencias Naturais da Fundacao Zoo-Botanica do Rio Grande do Sul -MCP s Pontificia Universidade Catolica do Rio Grande do Sul -MCP s Massachusetts College of Pharmacy and Allied Health Sciences, Biological Sciences Department -MCPM s Milwaukee City Public Museum -MCPPV s Museu de Ciencias e Tecnologia -MCPUCRGS s Museu de Ciencias da Pontificia Universidade Catolica do Rio Grande do Sul -MCR s Manchester Literary and Philosophical Society -MCRA s Sezione Archeologia, Storia e Scienze Naturali -MCRBS s Manchester Botanical and Horticultural Society -MCSB s Museo Civico di Scienze Naturali -MCSC s Colorado Springs, May Natural History Museum -MCSF s Museo Civico di Scienze Naturali -MCSG s Museo Civico di Storia Naturale, Grosseto -MCSN s Museo Civico di Storia Naturale "Giacomo Doria" -MCSN s Museo Civico di Storia Naturale, Verona -MCSNC s Museo Civico di Storia Naturale, Carmagnola -MCSNIO s Museo Civico di Scienze Naturali di Induno Olona -MCST s Museo Civico di Storia Naturale, Trieste -MCT s Michigan Technological University, Biological Sciences Department -MCTC s Michigan Technological University, Biological Sciences Department -MCTF s Michigan Technological University -MCTP s Museu de Ciencias -MCVE s Museo di Storia Naturale di Venezia -MCVM s Museo Civico, Villa Mirabello -MCW s Milton College, Biology Department -MCZ s Museum of Comparative Zoology, Harvard University +Mbg s Fachberich Geowissenschaften +MBH s Marlborough College +MBIC c Marine Biotechnology Institute Culture Collection +MBK s Kochi Prefectural Makino Botanical Garden, Botany Department +MBL s Museu Nacional de Historia Natural +MBLUZ s Museo de Biologia de la Universidad del Zulia +MBM s Museu Botanico Municipal +MBM s San Jose State University, Museum of Birds and Mammals +MBM s Marjorie Barrick Museum +MBML s Museu de Biologia Mello Leitao +MBMU c Institute of Molecular Biology and Genetics (IMBG), Mahidol University +MBR s Museo Argention de Ciencias Naturales "Bernardino Rivadavia" +MBS s Manchester Banksian Society +MBSL s Royal Medico-Botanical Society +MBSN s Museo Brembano di Scienze Naturali +MBUCV s Museo de Biologia de la Universidad Central de Venezuela CBFC,MBUC +MBZH s Museo y Biblioteca de la Zoologia +MC s Museo de Cipolleti +MCA s Muhlenberg College, Biology Department +MCAS s Museo Civico Archeologico e di Scienze Naturali "F. Eusebio" +MCBR s Museo Civico "Baldassarre Romano" +MCC c Microbial Culture Collection +MCC-UPLB c Microbial Culture Collection +MCCB s Museo Civico "Craveri" +MCCC c Marine Culture Collection of China +MCCI s Museo Civico di Storia Natural de Carmognola +MCCM c Medical Culture Collection Marburg +MCCM s Madras Christian College +MCD s Muzeul Civilizatiei Dacice si Romane Deva +MCDNL h McDaniel College +MCES s Museum of the Center for Entomological Studies +MCF h Sts. Cyril and Methodius University +MCF-PVPH s Museo Carmen Funes +MCFB s Museo de la Cienica Fundacion +MCFM s Museo Civico "Francesco Mina Palumbo" +MCFS s Museo Civico di Storia Naturale, Ferrara +MCG s Museo Civico DI Storia Naturale 'Giacomo Doria' +McGMK s McGregor Memorial Museum +MCGS s Museo Civico "Giuseppe Scarabelli" +MCITM c Bacterial Culture Collection +MCIZ s Museo Cambria, Istituto di Zoologia dell'Universita +MCJ s Missouri Southern State College, Biology Department +MCLSBB s Museo Colegio La Salle Bonanova de Barcelona +MCM(CMFRI) s Reference Collection +MCM s Hamilton College, McMaster University, Biology Department +MCM s Institut de Paleontologie, Museum d'Histoire naturelle +MCM c MACS Collection of Microorganisms +MCM s Museu Carlos Machado +MCMC s Museo de Historia Natural de la Ciudad de Mexico +McMJ s Mc Master University +MCMS s Museo Civico di Storia Naturale, Morgegno +MCN s McNeese State University, Biology Department +MCNA s Museo de Ciencias naturals de Alava +MCNC s Museo de Ciencias Naturales +MCNG s Museo de Ciencias Naturales de la UNELLEZ en Guanare +MCNPV s Fundacao Zoobotanica do Rio Grande do Sul MCN +MCNS s Universidad Nacional de Salta, Facultad de Ciencias Naturales +MCNV s Museo Civico di Storia Naturale, Venice +MCNZ s Porto Alegre, Museu de Ciencias Naturais da Fundacao Zoo-Botanica do Rio Grande do Sul +MCP s Pontificia Universidade Catolica do Rio Grande do Sul +MCP s Massachusetts College of Pharmacy and Allied Health Sciences, Biological Sciences Department +MCPM s Milwaukee City Public Museum +MCPPV s Museu de Ciencias e Tecnologia MCP +MCPUCRGS s Museu de Ciencias da Pontificia Universidade Catolica do Rio Grande do Sul +MCR s Manchester Literary and Philosophical Society +MCRA s Sezione Archeologia, Storia e Scienze Naturali +MCRBS s Manchester Botanical and Horticultural Society +MCSB s Museo Civico di Scienze Naturali +MCSC s Colorado Springs, May Natural History Museum +MCSF s Museo Civico di Scienze Naturali +MCSG s Museo Civico di Storia Naturale, Grosseto +MCSN s Museo Civico di Storia Naturale "Giacomo Doria" +MCSN s Museo Civico di Storia Naturale, Verona +MCSNC s Museo Civico di Storia Naturale, Carmagnola MSNC +MCSNIO s Museo Civico di Scienze Naturali di Induno Olona +MCST s Museo Civico di Storia Naturale, Trieste +MCT s Michigan Technological University, Biological Sciences Department +MCTC s Michigan Technological University, Biological Sciences Department +MCTF s Michigan Technological University +MCTP s Museu de Ciencias +MCVE s Museo di Storia Naturale di Venezia +MCVM s Museo Civico, Villa Mirabello +MCW s Milton College, Biology Department +MCZ s Museum of Comparative Zoology, Harvard University MCZC MCZ:Cryo s Museum of Comparative Zoology, Harvard University, Cryogenic Collection MCZ:Ent s Museum of Comparative Zoology, Harvard University, Entomology Collection MCZ:Herp s Museum of Comparative Zoology, Harvard University, Herpetology Collection @@ -3862,220 +3896,222 @@ MCZ:IZ s Museum of Comparative Zoology, Harvard University, Invertebrate Zoology MCZ:Mala s Museum of Comparative Zoology, Harvard University, Malacology Collection MCZ:Mamm s Museum of Comparative Zoology, Harvard University, Mammalogy Collection MCZ:Orn s Museum of Comparative Zoology, Harvard University, Ornithology Collection -MCZR s Museo Civico di Zoologia -MD s Museu Regional do Dundo -MD s Museum Donaueschingen -MDC c Microbial Depository Center (National Microbial Culture Collection of the Republic of Armenia) -MDE s Musee des Dinosaures in Esperaza -MDFW s Massachusetts Division of Fisheries and Wildlife -MDH s Dorman Museum -MDH c Michigan Department of Health -MDI h Malaysian Agricultural Research and Development Institute -MDKY s Morehead State University, Biological and Environmental Sciences Department -MDLA s Museu do Dundo -MDM s Mifune Dinosaur Museum -MDNR s Manitoba Conservation -MDP s Museum de Poligny -MDRG s Museum voor Dierkunde, Rijksuniversiteit -MDTN s Middleton Botanical Society -MDUG s Universidad Guanajuato, Museo Alfredo Duges -MDZAU s Museum Deptartment of Zoology -MECB s Universidade Federal de Pelotas, Museu Entomologico Ceslau Biezanko -MECG s Medical Entomology Collection Gallery -MECN s Museo Ecuadoriano de Ciencias Naturales -MEDEL s Universidad Nacional de Colombia - Sede de Medellin, Departamento de Biologia -MEFLG s Museo Entomologico Francisco Luis Gallego -MEL s Royal Botanic Gardens Melbourne -MELG s Geology Department, University of Melbourne -MELIT h Bogdan Khmel'nysckyi State Pedagogical University of Melitopol' -MELU s University of Melbourne -MEM s University of Memphis, Biology Department -MEMO s Instituto Tecnologico y de Estudios Superiores de Monterrey, Departamento de Recursos Naturales -MEN s UNCuyo, Catedra de Botanica Agricola, Departamento de Ciencias Biologicas -MEPAN s Museum of Evolution, Polish Academy of Sciences -MER s Universidad de Los Andes -MERC s Universidad de Los Andes, Centro Jardin Botanico -MERCA h Mercer Arboretum and Botanic Gardens -MERF s Universidad de Los Andes -MERL s Instituto Argentino de Investigaciones de las Zonas Aridas (CRICYTME) -MESA s Mesa State College, Biology Department -MEUC s Universidad de Chile -MEX s Museo de Historia Natural de la Ciudad de Mexico -MEXU s Herbario Nacional de Mexico, Universidad Nacional Autonoma de Mexico -MFA s Museo Provincial de Ciencias Naturales Florentino Ameghino, Seccion Botanica -MFA-ZV-M s Museo Florentino Ameghino, Coleccion de Mastozoologia (Argentina) -MFAP s Archaeology and Palaeontology -MFB s Southern Research Station -MFC c Matsushima Fungus Collection -MFGC c Margot Forde Germplasm Centre, AgResearch GrasslandsWar -MFLB s Marine Fisheries Laboratory -MFLU sc Mae Fah Laung University Herbarium -MFLUCC c Mae Fah Luang University Culture Collection -MfN s Museum fur Naturkunde -MFNB s Museo Friulano di Storia Naturale -MFP s Museo Felipe Poey -MFRU s Malawi Fisheries Research Unit -MFS s Museo dei Fisiocritici -MFSN s Museo Friulano di Storia Naturale of Udine -MFU s Museo Friulano di Storia Naturale -MFUM s Museum of Ferdowsi University of Mashhad -MFUW s Chinzombo Research Station, Chinzombo Wildlife Research Station -MFW s Museum Freriks -MG s Museu Paraense Emilio Goeldi, Departamento de Botanica -MG s Museum of Zoology -MGA s Instituto Pedagogico de Varones -MGAB s Muzeul de Istorie Naturala "Grigore Antipa" -MGAP s Museu Anchieta -MGB s Museo de Geologia (del Seminario Diocesano) de Barcelona -MGC s Universidad de Malaga, Departamento de Biologia Vegetal -MGDL s Museum d'Histoire Naturalle du Grand-Duchy de Luxembourg -MGF s Museum George Frey -MGFT s Museum G. Frey -MGH s Museum Godeffroy -MGHF s Museo Geologico H. Fuenzalida -MGHNL s Musee Guimet d'Histoire Naturelle de Lyon -MGHSJ s Matuyama Girl's High School -MGI s Geological Institute of the Mongolian Academy of Sciences -MGL s Musee Geologique de Lausanne -MGR s University of Michigan -MGRI s Moscow Geological Prospecting Institute -MGS s Upper Silesian Museum, Department of Natural History -MGSI s Museum of the Geological Survey of Iran -MGSP s Museum of the Geological Survey of Portugal -MGUG s Museum fuer Geologie und Palaontologie der Georg-August-Universitat -MGUH s Museum Geologicum Universitatis Hafniensis -MGUP s Museo Geologico della Universita Pisa -MGUV s Museo del Departamento de Geologia, Universidad de Valencia -MGUWR s Institute of Geological Sciences, University of Wroclaw -MH s Naturhistorisches Museum, Basel -MH s Tamil Nadu Agricultural University -MHA s Main Botanical Garden of the Russian Academy of Sciences -MHES h Museo de Historia Natural de El Salvador -MHH c Institute of Virology -MHL s Mildenhall and District Museum -MHM s Malham Tarn Field Centre -MHMN s Museu Historic Municipal de Novelda -MHNA s Museum d'Histoire Naturelle d'Autun -MHNB s Museum d'Histoire Naturelle de Bale -MHNC s Musee d'Histoire Naturelle - La Chaux-de-Fonds -MHNC s Museo de Historia Natural de Concepcion (Chile) -MHNCI s Museu de Historia Natural Capao de Imbuia (Brazil) -MHNCSJ s Museo de Historia Natural -MHNES s Museo de Historia Natural de El Salvador -MHNG s Natural History Museum of Geneva +MCZR s Museo Civico di Zoologia +MD s Museu Regional do Dundo +MD s Museum Donaueschingen +MDC c Microbial Depository Center (National Microbial Culture Collection of the Republic of Armenia) +MDE s Musee des Dinosaures in Esperaza +MDFW s Massachusetts Division of Fisheries and Wildlife +MDH s Dorman Museum +MDH c Michigan Department of Health +MDI h Malaysian Agricultural Research and Development Institute +MDKY s Morehead State University, Biological and Environmental Sciences Department +MDLA s Museu do Dundo +MDM s Mifune Dinosaur Museum +MDNR s Manitoba Conservation +MDP s Museum de Poligny +MDRG s Museum voor Dierkunde, Rijksuniversiteit +MDTN s Middleton Botanical Society +MDUG s Universidad Guanajuato, Museo Alfredo Duges +MDZAU s Museum Deptartment of Zoology +MECB s Universidade Federal de Pelotas, Museu Entomologico Ceslau Biezanko +MECG s Medical Entomology Collection Gallery +MECN s Museo Ecuadoriano de Ciencias Naturales DHMECN +MEDEL s Universidad Nacional de Colombia - Sede de Medellin, Departamento de Biologia +MEFLG s Museo Entomologico Francisco Luis Gallego +MEL s Royal Botanic Gardens Victoria +MELG s Geology Department, University of Melbourne +MELIT h Bogdan Khmel'nysckyi State Pedagogical University of Melitopol' +MELU s University of Melbourne +MEM s University of Memphis, Biology Department +MEMO s Instituto Tecnologico y de Estudios Superiores de Monterrey, Departamento de Recursos Naturales +MEN s UNCuyo, Catedra de Botanica Agricola, Departamento de Ciencias Biologicas +MEPAN s Museum of Evolution, Polish Academy of Sciences +MER s Universidad de Los Andes +MERC s Universidad de Los Andes, Centro Jardin Botanico +MERCA h Mercer Arboretum and Botanic Gardens +MERF s Universidad de Los Andes +MERL s Instituto Argentino de Investigaciones de las Zonas Aridas (CRICYTME) +MESA s Mesa State College, Biology Department +MEUC s Universidad de Chile +MEX s Museo de Historia Natural de la Ciudad de Mexico +MEXU s Herbario Nacional de Mexico, Universidad Nacional Autonoma de Mexico IBUNAM:MEXU +MFA s Museo Provincial de Ciencias Naturales Florentino Ameghino, Seccion Botanica +MFA-ZV-M s Museo Florentino Ameghino, Coleccion de Mastozoologia (Argentina) +MFAP s Archaeology and Palaeontology +MFB s Southern Research Station +MFC c Matsushima Fungus Collection +MFGC c Margot Forde Germplasm Centre, AgResearch GrasslandsWar +MFLB s Marine Fisheries Laboratory +MFLU sc Mae Fah Laung University Herbarium MFLU +MFLUCC c Mae Fah Luang University Culture Collection +MfN s Museum fur Naturkunde +MFNB s Museo Friulano di Storia Naturale +MFP s Museo Felipe Poey +MFRU s Malawi Fisheries Research Unit +MFS s Museo dei Fisiocritici +MFSN s Museo Friulano di Storia Naturale of Udine +MFU s Museo Friulano di Storia Naturale +MFUM s Museum of Ferdowsi University of Mashhad +MFUW s Chinzombo Research Station, Chinzombo Wildlife Research Station +MFW s Museum Freriks +MG s Museu Paraense Emilio Goeldi, Departamento de Botanica +MG s Museum of Zoology +MGA s Instituto Pedagogico de Varones +MGAB s Muzeul de Istorie Naturala "Grigore Antipa" +MGAP s Museu Anchieta +MGB s Museo de Geologia (del Seminario Diocesano) de Barcelona +MGC s Universidad de Malaga, Departamento de Biologia Vegetal +MGDL s Museum d'Histoire Naturalle du Grand-Duchy de Luxembourg +MGF s Museum George Frey +MGFT s Museum G. Frey +MGH s Museum Godeffroy +MGHF s Museo Geologico H. Fuenzalida +MGHNL s Musee Guimet d'Histoire Naturelle de Lyon +MGHSJ s Matuyama Girl's High School +MGI s Geological Institute of the Mongolian Academy of Sciences +MGL s Musee Geologique de Lausanne +MGR s University of Michigan +MGRI s Moscow Geological Prospecting Institute +MGS s Upper Silesian Museum, Department of Natural History +MGSI s Museum of the Geological Survey of Iran +MGSP s Museum of the Geological Survey of Portugal +MGUG s Museum fuer Geologie und Palaontologie der Georg-August-Universitat +MGUH s Museum Geologicum Universitatis Hafniensis +MGUP s Museo Geologico della Universita Pisa +MGUV s Museo del Departamento de Geologia, Universidad de Valencia +MGUWR s Institute of Geological Sciences, University of Wroclaw +MH s Naturhistorisches Museum, Basel +MH s Tamil Nadu Agricultural University +MHA s Main Botanical Garden of the Russian Academy of Sciences +MHES h Museo de Historia Natural de El Salvador +MHH c Institute of Virology +MHL s Mildenhall and District Museum +MHM s Malham Tarn Field Centre +MHMN s Museu Historic Municipal de Novelda +MHNA s Museum d'Histoire Naturelle d'Autun +MHNB s Museum d'Histoire Naturelle de Bale +MHNC s Musee d'Histoire Naturelle - La Chaux-de-Fonds +MHNC s Museo de Historia Natural de Concepcion (Chile) +MHNCI s Museu de Historia Natural Capao de Imbuia (Brazil) +MHNCSJ s Museo de Historia Natural +MHNES s Museo de Historia Natural de El Salvador +MHNG s Natural History Museum of Geneva MHNG:Herp s Natural History Museum of Geneva, Herpetology collection MHNG:Invertebrate s Natural History Museum of Geneva, Invertebrate collection -MHNI s Museu Hist. Naturales Universidade Federal Minas Gerais -MHNJP s Universidad Nacional Mayor de San Marcos -MHNL s Musee Guimet d'Histoire Naturelle de Lyon -MHNLR s Museum d'Histoire Naturelle -MHNLS s Coleccion de Mastozoologia, Museo de Historia Natural de La Salle -MHNM s Museo Nacional de Historia Natural y Antropologia -MHNN s Neuchatel Musee d'Histoire Naturel -MHNN s Musee d'Histoire Naturalle -MHNNICE s Mueusm d'Histoire Naturelle de Nice -MHNP s Museum d'Histoire Naturelle Perpignan -MHNSM s Museo de Historia Natural, Universidad Nacional Mayor de San Marcos -MHNT s Museum d'Histoire Naturelle Toulouse -MHNUNC s Departamento de Ictiologia del Museo de Historia Natural de la Universidad Nacional de Colombia -MHNV s Museo de Historia Natural de Valparaiso -MHP s Fort Hays State University, Sternberg Museum of Natural History -MHU s Makerere University, Botany Department -MHUA s Museo de Herpetologia de la Universidad de Antioquia -MHV s Musee de Haute Volta -MHWK s Much Wenlock Museum -MI s Universita degli Studi di Milano, Dipartimento di Biologia -MIB s University of Milano - Bicocca, Department of Biotechnology and Biosciences +MHNH s Museo Nacional de Historia Natural de Cuba MNHNCU +MHNI s Museu Hist. Naturales Universidade Federal Minas Gerais +MHNJP s Universidad Nacional Mayor de San Marcos +MHNL s Musee Guimet d'Histoire Naturelle de Lyon +MHNLR s Museum d'Histoire Naturelle MHNR +MHNLS s Coleccion de Mastozoologia, Museo de Historia Natural de La Salle +MHNM s Museo Nacional de Historia Natural y Antropologia +MHNN s Neuchatel Musee d'Histoire Naturel +MHNN s Musee d'Histoire Naturalle +MHNNICE s Mueusm d'Histoire Naturelle de Nice +MHNP s Museum d'Histoire Naturelle Perpignan +MHNSM s Museo de Historia Natural, Universidad Nacional Mayor de San Marcos +MHNT s Museum d'Histoire Naturelle Toulouse +MHNUNC s Departamento de Ictiologia del Museo de Historia Natural de la Universidad Nacional de Colombia +MHNV s Museo de Historia Natural de Valparaiso +MHP s Fort Hays State University, Sternberg Museum of Natural History +MHU s Makerere University, Botany Department +MHUA s Museo de Herpetologia de la Universidad de Antioquia +MHV s Musee de Haute Volta +MHWK s Much Wenlock Museum +MI s Universita degli Studi di Milano, Dipartimento di Biologia +MIB s University of Milano - Bicocca, Department of Biotechnology and Biosciences MIB:ZPL s University of Milano - Bicocca, Department of Biotechnology and Biosciences, ZooPlantLab -MIC s Mar Ivanios College (Zoology museum) -MICG h Universidad de San Carlos de Guatemala -MICH s University of Michigan -MICKKU c MICKKU Culture Collection -MID s Middlebury College, Biology Department -MII s Museum of Irish Industry -MIKU s Marine Biological Institute, Kyoto University -MIL s Milwaukee Public Museum -MIM s Minusinsk N. M. Martjanov Regional Museum -MIMB s Museum of the Institute of Marine Biology -MIMM s Mauritius Institute -MIN s University of Minnesota -MINC s Universidad Politecnica -MINI s Muzeul de Istoria Naturala -MIPV s Universita degli Studi di Milano, Laboratorio di Micologia e Batteriologia Fitopathologica -MIRR h Museu Integrado de Roraima -MISR s Macaulay Land Use Research Institute -MISS s University of Mississippi, Department of Biology -MISSA s Mississippi State University, Department of Biological Sciences -MISU h Minot State University -MIT c Massachusetts Institute of Technology -MIWG s Museum of he Isle of Wight Geology -MIZA s Museuo del Instituto de Zoologia Agricola -MIZL s Musee de l'Institut de Zoologie -MIZT s Universita di Torino -MJ s Muzeum Vysociny -MJCM s Museo de Ciencias Naturales y Antropologicas "Prof. Juan C.Moyano" (Argentina) -MJG s Museo Jorge Gerhold -MJG s Landesmuseum Joanneum -MJG s Johannes Gutenberg-Universitaet -MJH s Muzeul Judetean Hunedoara -MJMO s Universidad Centro Occidental, Decanato de Agronomia -MJS s Xiaolongshan Forestry Experiment Bureau -MJSD s Museum-Jardin des Sciences -MK s National Museum of Kenya -MKMEL h Herbarium Melovskiorum -MKNDC h Institute of Biology -MKNH h Institute of Biology -ML s Musee de Lectoure -MLAV s Musees de Laval -MLGU h Institut National pour l'Etude et la Recherche Agronomiques -MLLD c Microbiological Research Laboratory, Soil and Water Section, Department of Land Development -MLMJI c Department of Plant Protection, Faculty of Agricultural Production -MLP s Museo de La Plata -MLRU c Microbiology Laboratory, Department of Biology, Faculty of Science -MLS s Marine Laboratory Sydney -MLS s Museo del Instituto de La Salle -MLS s Lathallan Preparatory School -MLUH s Martin Luther Universitat -MLY s Arboretum Mlynany -MLZ s Moore Laboratory of Zoology, Occidental College +MIC s Mar Ivanios College (Zoology museum) +MICG h Universidad de San Carlos de Guatemala +MICH s University of Michigan +MICKKU c MICKKU Culture Collection +MID s Middlebury College, Biology Department +MII s Museum of Irish Industry +MIKU s Marine Biological Institute, Kyoto University +MIL s Milwaukee Public Museum +MIM s Minusinsk N. M. Martjanov Regional Museum +MIMB s Museum of the Institute of Marine Biology +MIMM s Mauritius Institute +MIN s University of Minnesota +MINC s Universidad Politecnica +MINI s Muzeul de Istoria Naturala +MIPV s Universita degli Studi di Milano, Laboratorio di Micologia e Batteriologia Fitopathologica +MIRR h Museu Integrado de Roraima +MISR s Macaulay Land Use Research Institute +MISS s University of Mississippi, Department of Biology +MISSA s Mississippi State University, Department of Biological Sciences +MISU h Minot State University +MIT c Massachusetts Institute of Technology +MIWG s Museum of he Isle of Wight Geology +MIZA s Museuo del Instituto de Zoologia Agricola +MIZL s Musee de l'Institut de Zoologie +MIZT s Universita di Torino +MJ s Muzeum Vysociny +MJCM s Museo de Ciencias Naturales y Antropologicas "Prof. Juan C.Moyano" (Argentina) +MJG s Museo Jorge Gerhold +MJG s Landesmuseum Joanneum +MJG s Johannes Gutenberg-Universitat +MJH s Muzeul Judetean Hunedoara +MJMO s Universidad Centro Occidental, Decanato de Agronomia +MJS s Xiaolongshan Forestry Experiment Bureau +MJSD s Museum-Jardin des Sciences +MK s National Museum of Kenya +MKMEL h Herbarium Melovskiorum +MKNDC h Institute of Biology +MKNH h Institute of Biology +ML s Musee de Lectoure +MLAV s Musees de Laval +MLGU h Institut National pour l'Etude et la Recherche Agronomiques +MLLD c Microbiological Research Laboratory, Soil and Water Section, Department of Land Development +MLMJI c Department of Plant Protection, Faculty of Agricultural Production +MLP s Museo de La Plata MLPA +MLRU c Microbiology Laboratory, Department of Biology, Faculty of Science +MLS s Marine Laboratory Sydney +MLS s Museo del Instituto de La Salle +MLS s Lathallan Preparatory School +MLSU s St. Petersburg State University, Zoology Museum +MLUH s Martin Luther Universitat MLU +MLY s Arboretum Mlynany +MLZ s Moore Laboratory of Zoology, Occidental College MLZ:Bird s Moore Laboratory of Zoology, Occidental College, Bird Collection MLZ:Mamm s Moore Laboratory of Zoology, Occidental College, Mammal Collection -MM s Manitoba Museum -MM s Museo del Mar -MM s Magdeburg Museum -MM s University of Montpellier -MMB s Moravske Muzeum -MMBC s Moravske Muzeum [Moravian Museum] -MMBS s Mukaishima Marine Biological Station -MMCC c MARDI Microbial Culture Collection -MMChPV s Museo Municipal El Chocon -MMCM s Museum of Malawi -MMF s Museu Municipal do Funchal -MMG s Museo Marino de la Isla de Gorgona -MMH s Municipal Museum -MMI s Regionalni muzeum -MMK s McGregor Museum -MMKZ s Alexander McGregor Memorial Museum -MML c Medical Microbiological Laboratory -MMMN s Manitoba Museum of Man and Nature, Botany Department -MMMZ s Mutare Museum -MMNH s Mongolian Museum of Natural History -MMNH s Bell Museum of Natural History -MMNHS s Macedonian Museum of Natural History -MMNS s Mississippi Museum of Natural Science -MMP s Museo de Mar del Plata (Argentina) -MMRF c Marine Microbial Reference Facility -MMS s Montshire Museum of Science -MMTT s Iran National Museum of Natural History -MMUE s Museum of Manchester University -MMUS s Macleay Museum, University of Sydney -MN s Museu Nacional, Universidade Federal do Rio de Janeiro -MNA s Museum of Northern Arizona -MNA s The Museo Nazionale dell'Antartide (Italian National Antarctic Museum in Genoa). -MNAV s Museo Naturalistico-Archeologico -MNB s Museum fuer Naturkunde der Humboldt-Universitaet -MNCE s Museu de Historia Natural Capao da Embuia -MNCN sb Museo Nacional de Ciencias Naturales +MM s Manitoba Museum +MM s Museo del Mar +MM s Magdeburg Museum +MM s University of Montpellier +MMB s Moravske Muzeum +MMBC s Moravske Muzeum [Moravian Museum] +MMBS s Mukaishima Marine Biological Station +MMCC c MARDI Microbial Culture Collection +MMChPV s Museo Municipal El Chocon +MMCM s Museum of Malawi +MMF s Museu Municipal do Funchal +MMG s Museo Marino de la Isla de Gorgona +MMH s Municipal Museum +MMI s Regionalni muzeum +MMK s McGregor Museum +MMKZ s Alexander McGregor Memorial Museum +MML c Medical Microbiological Laboratory +MMMN s Manitoba Museum of Man and Nature, Botany Department +MMMZ s Mutare Museum +MMNH s Mongolian Museum of Natural History +MMNH s Bell Museum of Natural History +MMNHS s Macedonian Museum of Natural History +MMNS s Mississippi Museum of Natural Science +MMP s Museo de Mar del Plata (Argentina) +MMRF c Marine Microbial Reference Facility +MMS s Montshire Museum of Science +MMTT s Iran National Museum of Natural History +MMUE s Museum of Manchester University +MMUS s Macleay Museum, University of Sydney +MN s Museu Nacional, Universidade Federal do Rio de Janeiro +MNA s Museum of Northern Arizona +MNA s The Museo Nazionale dell'Antartide (Italian National Antarctic Museum in Genoa). +MNAV s Museo Naturalistico-Archeologico +MNB s Museum fuer Naturkunde der Humboldt-Universitaet +MNCE s Museu de Historia Natural Capao da Embuia +MNCN sb Museo Nacional de Ciencias Naturales MNCN:ADN sb Museo Nacional de Ciencias Naturales, Coleccion de Tejidos y ADN MNCN:Ent s Museo Nacional de Ciencias Naturales, Coleccion de entomologia MNCN:Herpeto s Museo Nacional de Ciencias Naturales, Coleccion de anfibios y reptiles @@ -4084,277 +4120,283 @@ MNCN:Inverte s Museo Nacional de Ciencias Naturales, Coleccion de invertebrados MNCN:Malac s Museo Nacional de Ciencias Naturales, Coleccion de malacologia MNCN:Mam s Museo Nacional de Ciencias Naturales, Colession de mamiferos MNCN:Ornit s Museo Nacional de Ciencias Naturales, Coleccion de aves -MNCR s Museo Nacional de Costa Rica -MND s Museum Natura Docet -MNDG s Museo Nacional "David J. Guzman" -MNE s Maidstone Museum and Art Gallery -MNFD s Museum fuer Naturkunde -MNG s Sammlung Eisfeld des Museums der Natur Gotha -MNGA s Muzeul National de Istorie Natural "Grigore Antipa" -MNGC s Museo Nacional de Historia Natural, Guatemala City -MNH s Musei Nacionalis Hungarici -MNHCI s Museu de Historia Natural Capao da Imbuia -MNHM s Naturhistorisches Museum Mainz/Landessammlung fuer Naturkunde Rheinland-Pfalz -MNHM s John May Museum of Natural History -MNHN s Museum National d'Histoire Naturelle +MNCR s Museo Nacional de Costa Rica +MND s Museum Natura Docet +MNDG s Museo Nacional "David J. Guzman" +MNE s Maidstone Museum and Art Gallery +MNFD s Museum fuer Naturkunde +MNG s Sammlung Eisfeld des Museums der Natur Gotha +MNGA s Muzeul National de Istorie Natural "Grigore Antipa" +MNGC s Museo Nacional de Historia Natural, Guatemala City +MNH s Museo de Ciencias Naturales de Tenerife +MNHCI s Museu de Historia Natural Capao da Imbuia +MNHM s Naturhistorisches Museum Mainz/Landessammlung fuer Naturkunde Rheinland-Pfalz +MNHM s John May Museum of Natural History +MNHN s Museum National d'Histoire Naturelle MNHN:IC s Museum National d'Histoire Naturelle, Ichtyologie collection +MNHN:IE s Museum National d'Histoire Naturelle, Echinoderm collection +MNHN:IK s Museum National d'Histoire Naturelle, Cnidarians Collection MNHN:IM s Museum National d'Histoire Naturelle, Marine Invertebrate Collection MNHN:IU s Museum National d'Histoire Naturelle, Crustacean collection MNHN:M s Museum National d'Histoire Naturelle, Mammal collection MNHN:P s Museum National d'Histoire Naturelle, Paleontology Collection -MNHN s Museo Nacional de Historia Natural, Departamento de Colecciones -MNHN s Museo Nacional de Historia Natural de Montevideo -MNHNCH s Museo Nacional de Historia Natural de Chile -MNHNCU s Museo Nacional de Historia Natural, Havana -MNHNJP s Universidad Nacional Mayor de San Marcos -MNHNLES s Museum National d'Histoire Naturelle Lesotho -MNHNM s Museo Nacional de Historia Natural, Mexico City -MNHNP s Museo Nacional de Historia Natural del Paraguay -MNHNSD s Museo Nacional de Historia Natural, Santo Domingo -MNHNUL s Museu Nacional de Historia Natural de Universidade de Lisboa -MNHP s Princeton University -MNHS s Manchester Natural History Society -MNK s Museo de Historia Natural "Noel Kempff Mercado" +MNHN s Museo Nacional de Historia Natural, Departamento de Colecciones +MNHN s Museo Nacional de Historia Natural de Montevideo +MNHNCH s Museo Nacional de Historia Natural de Chile MNHN ,MNHNC +MNHNCU s Museo Nacional de Historia Natural, Havana MNHC +MNHNJP s Universidad Nacional Mayor de San Marcos +MNHNLES s Museum National d'Histoire Naturelle Lesotho +MNHNM s Museo Nacional de Historia Natural, Mexico City +MNHNP s Museo Nacional de Historia Natural del Paraguay +MNHNSD s Museo Nacional de Historia Natural, Santo Domingo MHND +MNHNUL s Museu Nacional de Historia Natural de Universidade de Lisboa +MNHP s Princeton University +MNHS s Manchester Natural History Society +MNK s Museo de Historia Natural "Noel Kempff Mercado" MNK:A s Museo de Historia Natural "Noel Kempff Mercado", Amphibian Collection MNK:R s Museo de Historia Natural "Noel Kempff Mercado", Reptile Collection -MNKS s Milton Keynes Development Corporation -MNMB s Magyar Nenzeti Museum -MNMS s Museo Nacional de Ciencias Naturales -MNN s Musee National du Niger -MNNC s Museo Nacional de Historia Natural, Santiago -MNNHN s Museum National d'Historie Naturelle -MNNW s Museum fuer Naturkunde -MNRJ s Museu Nacional/Universidade Federal de Rio de Janeiro -MNSB s Museum of Natural Sciences -MNSL s Museum of Natural Sciences -MNUFR s Mongolian National University -MNVD h Museum fur Naturkunde und Vorgeschichte Dessau -MNVL s Museum d'Histoire Naturelle de Ville de Lille -MNZ s Museum of New Zealand Te Papa Tongarewa -MO s Missouri Botanical Garden -MOAR s Morris Arboretum, University of Pennsylvania, Botany Department -MOBR h Estacion de Investigaciones Marinas de Margarita, Fundacion La Salle de Ciencias Naturales -MOC s Western Oregon University, Biology Department -MOD s Universita degli Studi di Modena e Reggio Emilia, Dipartimento de Biologia Animale -MODNR s Division of State Parks, Department of Natural Resources -MOFUNG s Museu Oceanogr. Fundacao Univerdidade Rio Grande -MOG s National Range Agency -MOL s Universidad Nacional Agraria La Molina, Departamento Academico de Biologia -MOLA c Microbial Observatory of the Laboratoire Arago -MOM s Musee Oceanographique Monaco -MONA s Musee Oceanographique de Monaco -MONT s Montana State University -MONTU s University of Montana -MONZ s Museum of New Zealand -MOR s Morton Arboretum, Research Department -MOR s Museum of the Rockies -MOS s College of Agriculture and Forestry -MOSG s Muzeul Orasului Sf. Gheorghe -MOSI s Museum of Science and Industry -MOSM s All-Russian Research Institute of Medicinal and Aromatic Plants -MOSN s Museo Ornitologico e di Scienze Naturali -MOSP s Moscow State Pedagogical University, Botany Department -MOSS h Universidade Federal Rural do Semi-Arido -MOT s Mote Marine Laboratory -MOTH s Museum of the Hemispheres -MOUFPE s Oceanographic Museum of the Federal University of Pernambuco -MOVC s Cornell College, Biology Department -MOVI s Museu Oceanografico do Vale do Itajai -MP s Vychodoceske muzeum Pardubice -MP s Mohonk Preserve, Inc. -MP s Transvaal Museum -MPA s Ecole National Superieure Agronomique, Biologie et Pathologie Vegetales -MPC s Monterey Peninsula College, Life Science Museum -MPCA s Museo Provincial "Carlos Ameghino" -MPCNyO s Museo Provincial de Ciencias Naturales, Puerto Madryn -MPCRM s Museo Paleontologico Cittadino della Rocca -MPE s F. R. Long Herbarium -MPEF-PV s Muso Paleontologico Egidio Fergulio -MPEG s Museu Paraense Emilio Goeldi -MPEP s Musee de Paleontologie et de l'evolution -MPGB s Museum of Portuguese Guinea -MPH h Shahid Behershti University -MPKV c Biological Nitrogen Fixation Project College of Agriculture -MPL s Musee de Port Louis -MPLN s Museo Provinciale di Storia Naturale -MPM s Milwaukee Public Museum -MPM s Meguro Parasitological Museum -MPMP s National Museum of the Philippines -MPN s Massey University, Ecology Group -MPPD s University of Minnesota, Plant Pathology Department -MPPE s Paletnologica ed Etnologico dei Padri Francescani -MPR s Mount Makulu Pasture Research Station -MPSC s Museu de Paleontologia de Santana do Cariri -MPSN s Museo Provinciale di Scienze Naturali -MPSP s Museu Paulista -MPSU c Department of Microbiology, Songkla University -MPT s Museuo Provincial de Teurel -MPU s Universite Montpellier II -MPUC s Pontificia Universidade Catolica do Rio Grande do Sul, Laboratorio de Botanica -MPUM s Museo Paleontologia Universita degli Studi di Milano -MPUN s Museo Paleontologicom -MPUNR s Departamento de Geologia, Universidad de Chile -MPV s Museo Paleontologico Municipal de Valencia -MPZ s Museo Paleontologico de la Universidad de Zaragoza -MQ s Gansu Institute of Desert Control -MQU s Macquarie University -MRA s Museo Requieu -MRA c Malaria Research and Reference Reagent Resource Center -MRAC s Musee Royal de l'Afrique Centrale -MRC c TUBITAK Marmara Research Center Culture Collection -MRC s Rocky Mountain Research Station -MRC c National Research Institute for Nutritional Diseases -MRCA s Musee Royal de l'Afrique Centrale -MRCN s Museu Rio-Grandense de Ciencias Naturais -MRD s Moorhead State University, Biology Department -MRF s Museum of Histoire naturelle -MRGS s Museu do Rio Grande do Sul -MRI s Murray Royal Institution -MRNP s Mount Rainier National Park -MRSC s Mount Makulu Central Research Station -MRSH s Matopos Research Station -MRSN s Museo Regionale di Scienze Naturali -MRSN c Multidrug Resistant Organism Repository and Surveillance Network -MRSP s Museo Regionale di Scienze Naturali, St. Pierre -MRST s Museo Regionale di Storia Naturale, Terrasini -MS s Universita di Messina, Dipartimento di Scienze Botaniche -MSA s Museum of Science and Art -MSB s Museum of Southwestern Biology +MNKNU s Museum of Nature, V.N. Karazin Kharkiv National University +MNKS s Milton Keynes Development Corporation +MNMB s Magyar Nenzeti Museum +MNMS s Museo Nacional de Ciencias Naturales +MNN s Musee National du Niger +MNNC s Museo Nacional de Historia Natural, Santiago +MNNHN s Museum National d'Historie Naturelle +MNNIT c Motilal Nehru National Institute of Technology +MNNW s Museum fuer Naturkunde +MNRJ s Museu Nacional/Universidade Federal de Rio de Janeiro +MNSB s Museum of Natural Sciences +MNSL s Museum of Natural Sciences +MNUFR s Mongolian National University +MNVD h Museum fur Naturkunde und Vorgeschichte Dessau +MNVL s Museum d'Histoire Naturelle de Ville de Lille +MNZ s Museum of New Zealand Te Papa Tongarewa +MO s Missouri Botanical Garden +MOAR s Morris Arboretum, University of Pennsylvania, Botany Department +MOBR h Estacion de Investigaciones Marinas de Margarita, Fundacion La Salle de Ciencias Naturales +MOC s Western Oregon University, Biology Department +MOD s Universita degli Studi di Modena e Reggio Emilia, Dipartimento de Biologia Animale +MODNR s Division of State Parks, Department of Natural Resources +MOFUNG s Museu Oceanogr. Fundacao Univerdidade Rio Grande +MOG s National Range Agency +MOL s Universidad Nacional Agraria La Molina, Departamento Academico de Biologia +MOLA c Microbial Observatory of the Laboratoire Arago +MOM s Musee Oceanographique Monaco +MONA s Musee Oceanographique de Monaco +MONT s Montana State University +MONTU s University of Montana +MONZ s Museum of New Zealand +MOR s Morton Arboretum, Research Department +MOR s Museum of the Rockies +MOS s College of Agriculture and Forestry +MOSG s Muzeul Orasului Sf. Gheorghe +MOSI s Museum of Science and Industry +MOSM s All-Russian Research Institute of Medicinal and Aromatic Plants +MOSN s Museo Ornitologico e di Scienze Naturali +MOSP s Moscow State Pedagogical University, Botany Department +MOSS h Universidade Federal Rural do Semi-Arido +MOT s Mote Marine Laboratory +MOTH s Museum of the Hemispheres +MOUFPE s Oceanographic Museum of the Federal University of Pernambuco +MOVC s Cornell College, Biology Department +MOVI s Museu Oceanografico do Vale do Itajai +MP s Vychodoceske muzeum Pardubice +MP s Mohonk Preserve, Inc. +MP s Transvaal Museum +MPA s Ecole National Superieure Agronomique, Biologie et Pathologie Vegetales +MPC s Monterey Peninsula College, Life Science Museum +MPCA s Museo Provincial "Carlos Ameghino" +MPCNyO s Museo Provincial de Ciencias Naturales, Puerto Madryn +MPCRM s Museo Paleontologico Cittadino della Rocca +MPE s F. R. Long Herbarium +MPEF-PV s Muso Paleontologico Egidio Fergulio +MPEG s Museu Paraense Emilio Goeldi +MPEP s Musee de Paleontologie et de l'evolution +MPGB s Museum of Portuguese Guinea +MPH h Shahid Behershti University +MPKV c Biological Nitrogen Fixation Project College of Agriculture +MPL s Musee de Port Louis +MPLN s Museo Provinciale di Storia Naturale +MPM s Milwaukee Public Museum +MPM s Meguro Parasitological Museum +MPMP s National Museum of the Philippines +MPN s Massey University, Ecology Group +MPPD s University of Minnesota, Plant Pathology Department +MPPE s Paletnologica ed Etnologico dei Padri Francescani +MPR s Mount Makulu Pasture Research Station +MPSC s Museu de Paleontologia de Santana do Cariri +MPSN s Museo Provinciale di Scienze Naturali +MPSP s Museu Paulista +MPSU c Department of Microbiology, Songkla University +MPT s Museuo Provincial de Teurel +MPU s Universite Montpellier II +MPUC s Pontificia Universidade Catolica do Rio Grande do Sul, Laboratorio de Botanica +MPUM s Museo Paleontologia Universita degli Studi di Milano +MPUN s Museo Paleontologicom +MPUNR s Departamento de Geologia, Universidad de Chile +MPV s Museo Paleontologico Municipal de Valencia +MPZ s Museo Paleontologico de la Universidad de Zaragoza +MQ s Gansu Institute of Desert Control +MQU s Macquarie University +MRA s Museo Requieu +MRA c Malaria Research and Reference Reagent Resource Center +MRAC s Musee Royal de l'Afrique Centrale +MRC c TUBITAK Marmara Research Center Culture Collection +MRC s Rocky Mountain Research Station +MRC c National Research Institute for Nutritional Diseases +MRCA s Musee Royal de l'Afrique Centrale +MRCN s Museu Rio-Grandense de Ciencias Naturais +MRD s Moorhead State University, Biology Department +MRF s Museum of Histoire naturelle +MRGS s Museu do Rio Grande do Sul +MRI s Murray Royal Institution +MRNP s Mount Rainier National Park +MRSC s Mount Makulu Central Research Station +MRSH s Matopos Research Station +MRSN s Museo Regionale di Scienze Naturali +MRSN c Multidrug Resistant Organism Repository and Surveillance Network +MRSP s Museo Regionale di Scienze Naturali, St. Pierre +MRST s Museo Regionale di Storia Naturale, Terrasini +MS s Universita di Messina, Dipartimento di Scienze Botaniche +MSA s Museum of Science and Art +MSB s Museum of Southwestern Biology MSB:Bird s Museum of Southwestern Biology, Bird Collection MSB:Fishes s Museum of Southwestern Biology, Fish Collection MSB:Herp s Museum of Southwestern Biology, Herpetology Collection MSB:Mamm s Museum of Southwestern Biology, Mammal Collection MSB:Para s Museum of Southwestern Biology, Parasitology Collection -MSB s Museum Sophia -MSB s Ludwig-Maximilians-Universitaet -MSC s Michigan State University, Botany and Plant Pathology Department -MSCL c Microbial Strain Collection of Latvia -MSCMU c Microbiology Section, Chiang Mai University (MSCMU) -MSCW s Mississippi University for Women -MSDB s Museo di Storia Naturale "Don Bosco" -MSDS c Microbiology Section, Biological Science Division, Department of Science Services -MSE s Angus Museums -MSEM s Museu Geologic del Seminari de Barcelona -MSEN s Montrose Natural History and Antiquarian Society -MSF s Sauriermuseum Frick -MSGP s Nusee des Services Geologiques du Portugal -MSI h Marine Science Institute, University of the Philippines -MSIE s Museum of Shanghai -MSINR s Museum Sichuan Institute of Natural Resources -MSIR s Mauritius Sugar Industry -MSJC s St. Joseph's College, Natural History Museum -MSK s National Academy of Sciences of Belarus, Flora and Systematic Laboratory -MSKH s Central Botanical Garden -MSKU s Belarusian State University, Botany Department -MSL s Royal Medical Society of London -MSLH s Chinese University of Hong Kong, Marine Sciences Laboratory -MSLY s Mossley Botanical Society -MSM s Marine Science Museum, Tokai Univ. -MSM s University of Puerto Rico, Marino Puertorriqueno -MSNA s Museo di Storia Naturale e Arte Archeologica -MSNG s Museo Civico di Storia Naturale di Genova 'Giacomo Doria' -MSNM s Museo Civico di Storia Naturale di Milano -MSNO s Museum des Sciences Naturelles -MSNP s Museo di Scienze Naturali -MSNT s Museo Regionale di Scienze Naturali, Torino +MSB s Museum Sophia +MSB s Ludwig-Maximilians-Universitaet +MSC s Michigan State University, Botany and Plant Pathology Department +MSCL c Microbial Strain Collection of Latvia +MSCMU c Microbiology Section, Chiang Mai University (MSCMU) +MSCW s Mississippi University for Women +MSDB s Museo di Storia Naturale "Don Bosco" +MSDS c Microbiology Section, Biological Science Division, Department of Science Services +MSE s Angus Museums +MSEM s Museu Geologic del Seminari de Barcelona +MSEN s Montrose Natural History and Antiquarian Society +MSF s Sauriermuseum Frick +MSGP s Nusee des Services Geologiques du Portugal +MSI sc Marine Science Institute, University of the Philippines +MSI:PMS-ICBG c Marine Science Institute, University of the Philippines, Philippine Mollusk Symbiont-International Cooperative Biodiversity Group +MSIE s Museum of Shanghai +MSINR s Museum Sichuan Institute of Natural Resources +MSIR s Mauritius Sugar Industry +MSJC s St. Joseph's College, Natural History Museum +MSK s National Academy of Sciences of Belarus, Flora and Systematic Laboratory +MSKH s Central Botanical Garden +MSKU s Belarusian State University, Botany Department +MSL s Royal Medical Society of London +MSLH s Chinese University of Hong Kong, Marine Sciences Laboratory MSLKHC +MSLY s Mossley Botanical Society +MSM s Marine Science Museum, Tokai Univ. +MSM s University of Puerto Rico, Marino Puertorriqueno +MSNA s Museo di Storia Naturale e Arte Archeologica +MSNG s Museo Civico di Storia Naturale di Genova 'Giacomo Doria' +MSNM s Museo Civico di Storia Naturale di Milano +MSNO s Museum des Sciences Naturelles +MSNP s Museo di Scienze Naturali +MSNT s Museo Regionale di Scienze Naturali, Torino MSNT:FAZC s Museo Regionale di Scienze Naturali, Torino, Franco Andreone Zoological Collection -MSNT s Museo Civico DI Storia Naturale DI Torino -MSNU s Museo di Storia Naturale dell'Universita -MSNV s Museo Civico di Storia Naturale di Venezia -MSNVR s Museo Civico di Storia Naturale di Verona -MSPC s Museo di Storia Naturale "Pietro Calderini" -MSPP c Mycology Section, Plant Pathology and Microbiology Division, Department of Agricultural Science -MSSC s Midwestern State University -MSTFM s Middle School of the Third Factory Machinery -MSTR s Westfaelisches Museum fuer Naturkunde -MSU c Acetobacter -MSU s Michigan State University Museum -MSUB s Montana State University -MSUD s I. I. Mecynikov State University of Odessa, Department of Morphology and Systematics of Plants -MSUH s University of Mosul, Biology Department -MSUMC s Murray State University -MSUMZ s Memphis State University -MSUN s Westfaelische Wilhelms-Universitaet -MSUT s Museum of Natural History, Tirane -MSUZ s Mississippi State University, Zoological Collections -MSV s Museum der Stadt Villach -MT s Universite de Montreal -MT s Mus. Tinro, Vladyvostok -MTA s Maden Tetkik ve Arama Enstituesue -MTCC c Microbial Type Culture Collection & Gene Bank -MTCHT h Mar Thoma College -MTD s Museum of Zoology Senckenberg Dresden +MSNT s Museo Civico DI Storia Naturale DI Torino +MSNU s Museo di Storia Naturale dell'Universita +MSNV s Museo Civico di Storia Naturale di Venezia +MSNVR s Museo Civico di Storia Naturale di Verona +MSPC s Museo di Storia Naturale "Pietro Calderini" +MSPP c Mycology Section, Plant Pathology and Microbiology Division, Department of Agricultural Science +MSSC s Midwestern State University +MSTFM s Middle School of the Third Factory Machinery +MSTR s Westfaelisches Museum fuer Naturkunde +MSU c Acetobacter +MSU s Michigan State University Museum MSUC,MSUM +MSUB s Montana State University +MSUD s I. I. Mecynikov State University of Odessa, Department of Morphology and Systematics of Plants +MSUH s University of Mosul, Biology Department +MSUMC s Murray State University +MSUMZ s Memphis State University +MSUN s Westfaelische Wilhelms-Universitaet +MSUT s Museum of Natural History, Tirane +MSUZ s Mississippi State University, Zoological Collections +MSV s Museum der Stadt Villach +MT s Universite de Montreal +MT s Mus. Tinro, Vladyvostok +MTA s Maden Tetkik ve Arama Enstituesue +MTCC c Microbial Type Culture Collection & Gene Bank +MTCHT h Mar Thoma College +MTD s Museum of Zoology Senckenberg Dresden MTD:T s Museum of Zoology Senckenberg Dresden, Tissue collection MTD:TD s Museum of Zoology Senckenberg Dresden, Herpetological Tissue Collection -MTDO h Chiba University -MTEC s Montana State University -MTJB s Jardin botanique de Montreal -MTKD s Staatliches Museum fuer Tierkunde -MTKKU c Department of Clinical Microbiology, Faculty of Medical Technology -MTMG s McGill University, Macdonald Campus, Plant Science Department -MTN s Malton Field Naturalists' Society -MTQA s Museum of Tropical Queensland -MTSN s Trento Museum of Natural Sciences -MTSU s Middle Tennessee State University, Biology Department -MTUF s University Museum, Tokyo University of Fisheries -MU c Mugla University Collection of Microorganisms -MU s Miami University, Botany Department, Willard Sherman Turrell Herbarium -MU s Midwestern University -MUACC c Murdoch University Algal Culture Collection -MUAF c Culture collection of Mendel University of Agriculture and Forestry in Brno -MUB s Universidad de Murcia, Departamento de Biologia Vegetal, Botanica -MUCC c Murdoch University Culture Collection -MUCC c Mie University Culture Collection (Culture Collection, Laboratory of Plant Pathology) -MUCL c Mycotheque de l'Universite Catholique de Louvain -MUCPv s Museo de la Universidad Nacional del Comahue -MUCR s Museo de Insectos -MUCV s Monash University, Biological Sciences Department -MUDH s The Hague, Museon -MUFE s University of Marmara, Department of Botany -MUFM s Manipur University Fish Museum -MUFS s Department of Animal Science, Miyazaki University -MUGM s Museo de Ciencias Naturales, Coleccion "Gustavo Orces" (Ecuador) -MUGT s Museo de Ciencias Naturales de la Universidad de Guayaquil -MUH h Mirpur University of Science & Technology -MUHW s Marshall University, Biological Sciences Department -MUJ s Museo Javeriano de Historia Natural, Laboratoriao de Entomologia -MUL c Department of Microbiology MUL-B 250 -MULU s Museum Ludovicae Ulricae, Zoology Institute of the University of Uppsala -MUM c Micoteca da Universidade do Minho -MUMF s Department of Life Sciences -MUMH s Mie University Mycological Herbarium -MUMZ s University of Missouri, Museum of Zoology -MUNC s St. John's, Memorial University of Newfoundland -MUNZ s Massey University -MUO s Stovall Museum of Science and History -MUP s Universidade do Porto, Museu do Historia Natural -MUR s Murray State University, Department of Biological Sciences -MURD s Murdoch University -MURU s Murdoch University -MUS s Muskingum College, Biology Department -MUSA s Universidad Nacional de San Agustin, Museo de Historia Natural (Peru) -MUSK s Muskegon Community College, Life Science Department -MUSM s Museo de Historia Natural de la Universidad Nacional Mayor de San Marcos en Lima -MUSN s Museo Universitario di Storia Naturale e della Strumentazione Scientifica -MUST h Al-Mustansiriya University -MUT c Mycotheca Universitatis Taurinensis -MUZ h King Abdulaziz City for Science and Technology -MV s University of Montana Museum -MVC s University of Charleston, Natural Sciences Department -MVDA s Ministerio de Ganaderia y Agricultura -MVEN s Naturhistorisch Museum -MVFA s Universidad de la Republica, Laboratorio de Botanica -MVFQ s Universidad de la Republica, Catedra de Botanica Farmaceutica -MVHC s Universidad de la Republica, Seccion Micologia -MVJB s Museo y Jardin Botanico -MVM s Museo Nacional de Historia Natural, Departamento de Botanica -MVMA s Museum of Victoria -MVN s Public Library -MVNP s Mesa Verde National Park -MVP s Museum of Vicotria -MVSC s Millersville University, Biology Department -MVUP s Museo de Vertebrados de la Universidad de Panama -MVZ s Museum of Vertebrate Zoology, University of California at Berkeley +MTDO h Chiba University +MTEC s Montana State University +MTJB s Jardin botanique de Montreal +MTKD s Staatliches Museum fuer Tierkunde +MTKKU c Department of Clinical Microbiology, Faculty of Medical Technology +MTMG s McGill University, Macdonald Campus, Plant Science Department +MTN s Malton Field Naturalists' Society +MTQA s Museum of Tropical Queensland MTQ +MTSN s Trento Museum of Natural Sciences +MTSU s Middle Tennessee State University, Biology Department +MTUF s University Museum, Tokyo University of Fisheries +MU c Mugla University Collection of Microorganisms +MU s Miami University, Botany Department, Willard Sherman Turrell Herbarium +MU s Midwestern University +MUACC c Murdoch University Algal Culture Collection +MUAF c Culture collection of Mendel University of Agriculture and Forestry in Brno +MUB s Universidad de Murcia, Departamento de Biologia Vegetal, Botanica +MUBI Museo de Biodiversidad del Peru, Cusco +MUCC c Murdoch University Culture Collection +MUCC c Mie University Culture Collection (Culture Collection, Laboratory of Plant Pathology) +MUCL c Mycotheque de l'Universite Catholique de Louvain BCCM/MUCL +MUCPv s Museo de la Universidad Nacional del Comahue MPCA +MUCR s Museo de Insectos +MUCV s Monash University, Biological Sciences Department +MUDH s The Hague, Museon +MUFE s University of Marmara, Department of Botany +MUFM s Manipur University Fish Museum +MUFS s Department of Animal Science, Miyazaki University +MUGM s Museo de Ciencias Naturales, Coleccion "Gustavo Orces" (Ecuador) +MUGT s Museo de Ciencias Naturales de la Universidad de Guayaquil +MUH h Mirpur University of Science & Technology +MUHW s Marshall University, Biological Sciences Department +MUJ s Museo Javeriano de Historia Natural, Laboratoriao de Entomologia +MUL c Department of Microbiology MUL-B 250 +MULU s Museum Ludovicae Ulricae, Zoology Institute of the University of Uppsala +MUM c Micoteca da Universidade do Minho +MUMF s Department of Life Sciences +MUMH s Mie University Mycological Herbarium +MUMZ s University of Missouri, Museum of Zoology +MUNC s St. John's, Memorial University of Newfoundland +MUNZ s Massey University +MUO s Stovall Museum of Science and History +MUP s Universidade do Porto, Museu do Historia Natural +MUR s Murray State University, Department of Biological Sciences +MURD s Murdoch University +MURU s Murdoch University +MUS s Muskingum College, Biology Department +MUSA s Universidad Nacional de San Agustin, Museo de Historia Natural (Peru) +MUSK s Muskegon Community College, Life Science Department +MUSM s Museo de Historia Natural de la Universidad Nacional Mayor de San Marcos en Lima +MUSN s Museo Universitario di Storia Naturale e della Strumentazione Scientifica +MUST h Al-Mustansiriya University +MUT c Mycotheca Universitatis Taurinensis +MUZ h King Abdulaziz City for Science and Technology +MV s University of Montana Museum +MVC s University of Charleston, Natural Sciences Department +MVDA s Ministerio de Ganaderia y Agricultura +MVEN s Naturhistorisch Museum +MVFA s Universidad de la Republica, Laboratorio de Botanica +MVFQ s Universidad de la Republica, Catedra de Botanica Farmaceutica +MVHC s Universidad de la Republica, Seccion Micologia +MVJB s Museo y Jardin Botanico +MVM s Museo Nacional de Historia Natural, Departamento de Botanica +MVMA s Museum of Victoria +MVN s Public Library +MVNP s Mesa Verde National Park +MVP s Museum of Vicotria +MVSC s Millersville University, Biology Department +MVUP s Museo de Vertebrados de la Universidad de Panama +MVZ s Museum of Vertebrate Zoology, University of California at Berkeley MVZ:Bird s Museum of Vertebrate Zoology, University of California at Berkeley, Bird Collection MVZ:Egg s Museum of Vertebrate Zoology, University of California at Berkeley, Egg Collection MVZ:Herp s Museum of Vertebrate Zoology, University of California at Berkeley, Herpetology Collection @@ -4362,355 +4404,359 @@ MVZ:Hild s Museum of Vertebrate Zoology, University of California at Berkeley, M MVZ:Img b Museum of Vertebrate Zoology, University of California at Berkeley, Image Collection MVZ:Mamm s Museum of Vertebrate Zoology, University of California at Berkeley, Mammal Collection MVZ:Page b Museum of Vertebrate Zoology, University of California at Berkeley, Notebook Page Collection -MW s Museum Wasmann -MW sb Moscow State University Herbarium -MWC s Museum of Western Colorado -MWCF s Mary Washington College, Department of Biology -MWFB s University of California, Davis, Museum of Wildlife and Fisheries Biology -MWG s Moscow State University, Department of Biogeography -MWI s Western Illinois University, Biological Sciences Department -MWNH s Museum Wiesbaden, Department of Natural Science -MWSJ s Missouri Western State College, Biology Department -MWSU s Midwestern State University -MY s Universidad Central de Venezuela, Botanica -MYDC s Mianyang Institute for Drug Control -MYF s Universidad Central de Venezuela -MZ-ICACH s Instituto de Ciencias y Artes de Chiapas, Museo Zoologico (Mexico) -MZ s Jihomoravske muzeum Znojmo -MZ s Museum of the Earth, Polish Academy of Sciences -MZAF s Museo Zoologico dell'Accademia dei Fisiocritici -MZB s Museum Zoologicum Bogoriense +MW s Museum Wasmann +MW sb Moscow State University Herbarium +MWC s Museum of Western Colorado +MWCF s Mary Washington College, Department of Biology +MWFB s University of California, Davis, Museum of Wildlife and Fisheries Biology +MWG s Moscow State University, Department of Biogeography +MWI s Western Illinois University, Biological Sciences Department +MWNH s Museum Wiesbaden, Department of Natural Science +MWSJ s Missouri Western State College, Biology Department +MWSU s Midwestern State University +MY s Universidad Central de Venezuela, Botanica +MYDC s Mianyang Institute for Drug Control +MYF s Universidad Central de Venezuela +MZ-ICACH s Instituto de Ciencias y Artes de Chiapas, Museo Zoologico (Mexico) +MZ s Jihomoravske muzeum Znojmo +MZ s Museum of the Earth, Polish Academy of Sciences +MZAF s Museo Zoologico dell'Accademia dei Fisiocritici +MZB s Museum Zoologicum Bogoriense MZB:Amp s Museum Zoologicum Bogoriense, Amphibian Collection MZB:Ornith s Museum Zoologicum Bogoriense, Ornithology Collection -MZBL s Museo de Zoologica -MZBS s Museo Zoologia -MZCP s Universidade de Coimbra -MZCR s Museo de Zoologia -MZFC s Museo de Zoologia "Alfonso L. Herrera" -MZFN s Museo Zoologico dell'Universita "Federico II" -MZGZ s Museum Zoologia del Giardino Zoologico -MZH s Zoolgical Museum, Finnish Museum of Natural History -MZKI c Microbial Culture Collection of National Institute of Chemistry -MZL s Musee Zoologique -MZLS s Musee Zoologique -MZLU s Lund University -MZN s Musee Zoologie -MZNA s Universidad de Navarra, Museum of Zoology -MZNC s Universidad Nacional de Cordoba, Museo de Zoología -MZP s Muzeum Ziemi Polska Akademia Nauk -MZPW s Polish Academy of Science, Museum of the Institute of Zoology -MZRF s Museo Zangheri di Storia Naturale della Romagna -MZRO s Museo Civico di Storia Naturale "P. Zangheri" -MZS s Universite de Strasbourg, Musee de Zoologie -MZSF s Universite de Strasbourg, Museum Zoologique -MZSP s Sao Paulo, Museu de Zoologia da Universidade de Sao Paulo -MZTG s Museum Zoologia -MZUABCS s Museo de Zoologia de la Universidad Automica de Baja California Sur -MZUB s Museo di Zoologia -MZUC s Museo de Zoologia, Universidad de Concepcion -MZUC s Universita di Cagliari -MZUCR s Universidad de Costa Rica, Museo de Zoologia -MZUEL s Museu de Zoologia da Universidade Estadual de Londrina -MZUESC s Museu de Zoologia da Universidade Estadual de Santa Cruz -MZUF s Museo Zoologico La Specola, Universita di Firenze -MZUN s Museo Zoologico di Universita degli Studi -MZUNAP s Museo de Zoologia de la Universidad Nacional de la Amazonia Peruana -MZUP s Museo Zoologia -MZUP s Museo Zoologico di Universita degli Studi -MZUR s Museo di Zoologia dell'Universita di Roma "La Sapienza" +MZBL s Museo de Zoologica +MZBS s Museo Zoologia +MZCP s Universidade de Coimbra +MZCR s Museo de Zoologia +MZFC s Museo de Zoologia "Alfonso L. Herrera" +MZFN s Museo Zoologico dell'Universita "Federico II" +MZGZ s Museum Zoologia del Giardino Zoologico +MZH s Zoolgical Museum, Finnish Museum of Natural History +MZKI c Microbial Culture Collection of National Institute of Chemistry +MZL s Musee Zoologique +MZLS s Musee Zoologique +MZLU s Lund University +MZN s Musee Zoologie +MZNA s Universidad de Navarra, Museum of Zoology +MZNC s Universidad Nacional de Cordoba, Museo de Zoología +MZP s Muzeum Ziemi Polska Akademia Nauk +MZPW s Polish Academy of Science, Museum of the Institute of Zoology +MZRF s Museo Zangheri di Storia Naturale della Romagna +MZRO s Museo Civico di Storia Naturale "P. Zangheri" +MZS s Universite de Strasbourg, Musee de Zoologie +MZSF s Universite de Strasbourg, Museum Zoologique +MZSP s Sao Paulo, Museu de Zoologia da Universidade de Sao Paulo +MZTG s Museum Zoologia IHN +MZUABCS s Museo de Zoologia de la Universidad Automica de Baja California Sur +MZUB s Museo di Zoologia +MZUC s Museo de Zoologia, Universidad de Concepcion +MZUC s Universita di Cagliari +MZUCR s Universidad de Costa Rica, Museo de Zoologia +MZUEL s Museu de Zoologia da Universidade Estadual de Londrina MZUEL +MZUESC s Museu de Zoologia da Universidade Estadual de Santa Cruz +MZUF s Museo Zoologico La Specola, Universita di Firenze +MZUFBA s Museu de Zoologia, Universidade Federal da Bahia, Salvador +MZUN s Museo Zoologico di Universita degli Studi +MZUNAP s Museo de Zoologia de la Universidad Nacional de la Amazonia Peruana +MZUP s Museo Zoologia +MZUP s Museo Zoologico di Universita degli Studi +MZUR s Museo di Zoologia dell'Universita di Roma "La Sapienza" MZUL MZUR:BAU s Museo di Zoologia dell'Universita di Roma "La Sapienza", Zoological collection of the Department of Biology and Biotechnology -MZUS s Musee de Zoologie de l'Universite de Strasbourg -MZUSP s Museu de Zoologia da Universidade de Sao Paulo -MZUT s Museo di Zoologia, Instituto di Zoologia e Anatomia Comparata Universita di Torino -MZUT s Museo e Instituto DI Zoologia Sistematica dell' UniversitaDI Torino -MZUTH s Museum of Zoology, University of Thessaloniki -MZUVN s Musee Zool. Univ. et Ville de Nancy -MZV s Muzeum i Instytut Zoologii -MZV s Zoological Museum Varsovite -MZYU s Museum of Zoology, Yunnan University -N s Nanjing University, Biology Department -NA s United States National Arboretum, USDA/ARS -NABG s Botanical Garden -NAC s Nagano Nature Conservation Research Institute -NAI s University of Nairobi, Botany Department -NAIC s National Agricultural Insect Collection -NAKU h Namik Kemal University -NAM s Facultes Universitaires Notre-Dame de la Paix -NAN s Nantong Teachers College, Biology Department -NAP s Institute of Zoology, Academia Sinica (formerly National Academy of Peiping) -NAP s Universita Degli Studi di Napoli Federico II, Dipartimento di Biologia Vegetale -NARA s National Aquatic Resources Agency -NARI s National Agricultural Research Institute -NARL s National Agricultural Research Laboratories -NAS s Institute of Botany, Jiangsu Province and Chinese Academy of Sciences -NASC b European Arabidopsis Stock Centre -NASC s Massachusetts College of Liberal Arts, Biology Department -NAT s Seale-Hayne Agricultural College -NATC s Northwestern State University, Biological Sciences Department -NAU s Nanjing Agricultural University, Department of Plant Science -NAUF s Northern Arizona University -NAUJ s Nanjing, Nanjing Agricultural University -NAUVM s Northern Arizona University, Museum of Vertebrates -NAVA s Navajo Natural Heritage Program, Navajo Department of Fish & Wildlife -NBAIM c National Bureau of Agriculturally Important Microorganisms -NBFGR s National Bureau of Fish Genetic Resources (Indian Council of Agricultural Research) +MZUS s Musee de Zoologie de l'Universite de Strasbourg +MZUSP s Museu de Zoologia da Universidade de Sao Paulo +MZUT s Museo di Zoologia, Instituto di Zoologia e Anatomia Comparata Universita di Torino +MZUT s Museo e Instituto DI Zoologia Sistematica dell' UniversitaDI Torino +MZUTH s Museum of Zoology, University of Thessaloniki +MZUTI s Museo de Zoologia, Universidad Tecnologica Indoamerica +MZUVN s Musee Zool. Univ. et Ville de Nancy +MZV s Muzeum i Instytut Zoologii +MZV s Zoological Museum Varsovite +MZYU s Museum of Zoology, Yunnan University +N s Nanjing University, Biology Department +NA s United States National Arboretum, USDA/ARS +NABG s Botanical Garden +NAC s Nagano Nature Conservation Research Institute +NAI s University of Nairobi, Botany Department +NAIC s National Agricultural Insect Collection +NAKU h Namik Kemal University +NAM s Facultes Universitaires Notre-Dame de la Paix +NAN s Nantong Teachers College, Biology Department +NAP s Institute of Zoology, Academia Sinica (formerly National Academy of Peiping) +NAP s Universita Degli Studi di Napoli Federico II, Dipartimento di Biologia Vegetale +NARA s National Aquatic Resources Agency +NARI s National Agricultural Research Institute +NARL s National Agricultural Research Laboratories +NAS s Institute of Botany, Jiangsu Province and Chinese Academy of Sciences +NASC b European Arabidopsis Stock Centre +NASC s Massachusetts College of Liberal Arts, Biology Department +NAT s Seale-Hayne Agricultural College +NATC s Northwestern State University, Biological Sciences Department +NAU s Nanjing Agricultural University, Department of Plant Science +NAUF s Northern Arizona University +NAUJ s Nanjing, Nanjing Agricultural University +NAUVM s Northern Arizona University, Museum of Vertebrates +NAVA s Navajo Natural Heritage Program, Navajo Department of Fish & Wildlife +NBAIM c National Bureau of Agriculturally Important Microorganisms +NBFGR s National Bureau of Fish Genetic Resources (Indian Council of Agricultural Research) NBFGR:CHN s National Bureau of Fish Genetic Resources (Indian Council of Agricultural Research), Cochin Unit -NBG s National Botanical Institute -NBGB sb National Botanical Garden, Belgium -NBIMCC c National Bank for Industrial Microorganisms and Cell Cultures -NBM s New Brunswick Museum -NBMB s St. John's, New Brunswick Museum -NBME s National Butterfly Museum (Saruman Museum) -NBNM s National Park Service -NBPC s National Birds of Prey Centre -NBPGR b National Bureau of Plant Genetic Resources -NBRC c NITE Biological Resource Center -NBRP b National Bio-Resource Project -NBSB s National Biomonitoring Specimen Bank, U.S. Geological Survey +NBG s National Botanical Institute +NBGB sb National Botanical Garden, Belgium +NBIMCC c National Bank for Industrial Microorganisms and Cell Cultures +NBM s New Brunswick Museum +NBMB s St. John's, New Brunswick Museum +NBME s National Butterfly Museum (Saruman Museum) +NBNM s National Park Service +NBPC s National Birds of Prey Centre +NBPGR b National Bureau of Plant Genetic Resources +NBRC c NITE Biological Resource Center +NBRP b National Bio-Resource Project +NBSB s National Biomonitoring Specimen Bank, U.S. Geological Survey NBSB:Bird s National Biomonitoring Specimen Bank, U.S. Geological Survey, bird collection NBSB:Mamm s National Biomonitoring Specimen Bank, U.S. Geological Survey, mammal tissue collection -NBSI s Biologische Station Neusiedler See -NBV s Koninklijke Nederlandse Botanische Vereniging -NBY s Newbury District Museum -NBYC s Newberry College, Department of Biology -NCAIM c National Collection of Agricultural and Industrial Microorganisms -NCAM c National Collection of Agricultural Microorganisms -NCAS s Rutgers University, Biological Sciences Department -NCATG s North Carolina A & T State University, Biology Department -NCAW s North-West College of Agriculture -NCB c National Culture Bank -NCBS s Yale University, Connecticut Botanical Society -NCC c Nantes Culture Collection -NCC s Sonoma State University, Biology Department -NCCB c The Netherlands Culture Collection of Bacteria -NCCBH s Nature Conservancy Council, Balloch -NCCE s Nature Conservancy Council, Edinburgh -NCCH s Nature Conservancy Council -NCCN s Nature Conservancy Council, Norwich -NCCP c National Culture Collection for Pathogens -NCCP c National Culture Collection of Pakistan -NCCPF c National Culture Collection of Pathogenic Fungi -NCDC c National Collection of Dairy Cultures -NCE s University of Newcastle upon Tyne, School of Biological Sciences -NCFB c National Collection of Food Bacteria -NCH s Norwich Botanical Society -NCHU s National Chung Hsing University +NBSI s Biologische Station Neusiedler See +NBV s Koninklijke Nederlandse Botanische Vereniging +NBY s Newbury District Museum +NBYC s Newberry College, Department of Biology +NCAIM c National Collection of Agricultural and Industrial Microorganisms +NCAM c National Collection of Agricultural Microorganisms +NCAS s Rutgers University, Biological Sciences Department +NCATG s North Carolina A & T State University, Biology Department +NCAW s North-West College of Agriculture +NCB c National Culture Bank +NCBS s Yale University, Connecticut Botanical Society +NCC c Nantes Culture Collection +NCC s Sonoma State University, Biology Department +NCCB c The Netherlands Culture Collection of Bacteria NCCB +NCCBH s Nature Conservancy Council, Balloch +NCCE s Nature Conservancy Council, Edinburgh +NCCH s Nature Conservancy Council +NCCN s Nature Conservancy Council, Norwich +NCCP c National Culture Collection for Pathogens +NCCP c National Culture Collection of Pakistan +NCCPF c National Culture Collection of Pathogenic Fungi +NCDC c National Collection of Dairy Cultures +NCE s University of Newcastle upon Tyne, School of Biological Sciences +NCF s Department of Forest Insects, Northwest College of Forestry +NCFB c National Collection of Food Bacteria +NCH s Norwich Botanical Society +NCHU s National Chung Hsing University NCHU:ZOOL s National Chung Hsing University, Department of Life Science -NCIM c National Collection of Industrial Microorganisms -NCIMB c National Collections of Industrial Food and Marine Bacteria (incorporating the NCFB) -NCIP s Pusat Penelitian dan Pengembangan Oseanologi -NCKU s National Cheng-Kung University, Biology Department -NCLN s New College -NCMA s Raleigh, North Carolina Department of Environmental Health and Natural Resources -NCMH c The North Carolina Memorial Hostital -NCMK s Norwich Castle Museum -NCP h National Collection of Passiflora -NCPF c National Collection of Pathogenic Fungi -NCPPB c National Collection of Plant Pathogenic Bacteria -NCPV c National Collection of Pathogenic Viruses -NCS s North Carolina State University -NCSC c National Center of Streptococcus Collection, Department of Microbiology, Faculty of Medical Science -NCSC s North Carolina State University, Botany Department -NCSLG h North Carolina State University -NCSM s North Carolina Museum of Natural Sciences -NCSU s North Carolina State University Collections -NCTC c National Collection of Type Cultures -NCU s University of North Carolina, North Carolina Botanical Garden -NCUT s Nicolaus Copernicus University -NCWRF c National Collection of Wood Rotting Fungi -NCY s Conservatoire et Jardins Botaniques de Nancy -NCYC c National Collection of Yeast Cultures -ND s University of Notre Dame, Department of Biological Sciences -NDA s North Dakota State University, Animal and Range Sciences Department -NDAA s Orange, New South Wales Department of Agriculture -NDAT s Department of Agriculture, Tunisia -NDFC s Newfoundland Department of Forestry -NDG s University of Notre Dame, Department of Biological Sciences -NDO s Division of Forest Research, Forest Department -NDSR s National Drosophila Species Resource Center -NDSU s North Dakota State University -NDTC s Ningde Teachers College, Biology Department -NE s University of New England -NEB s University of Nebraska State Museum -NEBC s Harvard University -NEBK h University of Nebraska at Kearney -NEFI s Northeastern Forestry University, Forestry Department -NEM c Faculte de Medecine Necker-Enfants Malades -NEMO s Truman State University -NEMSU s Truman State University -NEMU s Newark Museum -NENU s Northeast Normal University, Biology Department -NEPCC c North East Pacific Culture Collection -NESH s University of Nevada -NEU s Universite de Neuchatel, Laboratoire de botanique evolutive -NEUN h Near East University -NEW s University of Newcastle -NEWHM s Hancock Museum -NEZ s Museum, Zoology Department, University of New England -NF s Nanjing Forestry University, Forest Resources and Environment -NFCCI c National Fungal Culture Collection of India -NFCCP c National Fungal Culture Collection of Pakistan -NFLD s Memorial University of Newfoundland, Biology Department -NFM s Newfoundland Museum -NFO s Niagara Parks Botanical Gardens and School of Horticulture -NFRC s Northern Forest Research Centre -NFRDI c National Fisheries Research & Development Institute -NFRI c Norwegian Forest Research Institute -NFRN s Canadian Forest Service, NRCan -NGBB h Nezahat Gokyigit Botanik Bahcesi -NGCPR h Naoroji Godrej Centre for Plant Research -NGI s Nanjing Geographical Institute -NGM s Bromley House Library -NGMC s National Geological Museum of China -NGR c Plant Pathology -NH s South African National Biodiversity Institute -NHA s University of New Hampshire, Plant Biology Department -NHCP h National Bureau of Plant Genetic Resources -NHES s Connecticut Agricultural Experiment Station, Entomology Department -NHG s Naturhistorische Gesellschaft e. V., Abteilung Botanik -NHI h Natural History Institute -NHIC s Ontario Ministry of Natural Resources -NHL c National Institute of Hygienic Sciences -NHM s Naturhistorisches Museum, Bern -NHM s University of Nottingham, Botany Department -NHMA s Natural History Museum, Denmark -NHMB s Naturhistorisches Museum, Basel -NHMB s Natural History Museum Bucharest -NHMBe s Naturhistorisches Museum Bern -NHMC s Natural History Museum of Crete, University of Crete, Department of Botany -NHMC s Natural History Museum, Rangoon -NHME s Natuurhistorisch Museum -NHMF h Natural History Museum Fribourg -NHMG s Natural History Museum of Guangxi -NHMG s Goteborgs Naturhistoriska Museet -NHMK s Landesmuseum fuer Karnten -NHML s Natural History Museum, Tripoli -NHMM s Natuurhistorische Museum Maastricht -NHMM-LS s Naturhistorisches Museum/Landessammlung fuer Naturkunde Rheinland-Pfalz -NHMN s Nottingham Natural History Museum (Wollaton Hall) -NHMR s Natural History Museum Rijeka -NHMR s Natural History Museum, Reykjavik -NHMR s Natuurhistorisch Museum -NHMS h Natural History Museum Split -NHMTU s Natural History Museum, Tribhuvan University -NHMUK sb Natural History Museum, London -NHMUK s Natural History Museum, Karachi -NHMW s Naturhistorisches Museum, Wien -NHNC s La Chaux-de-Fons -NHNE s New England College, Biology Department -NHR h Institute of Scientific and Technological Research (IRST) -NHRI s Islandic Museum of Natural History -NHRM s Naturhistoriska Rijkmuseet -NHRS s Swedish Museum of Natural History, Entomology Collections -NHSD s Natural History Society of Dublin -NHST s Museum of Natural History, Reunion -NHT s Tropical Pesticides Research Institute -NHV s Institut fuer Landwirtschaftliche Botanik -NI c Nagao Institute -NI s Slovenska pol'nohospodarska Univerzita, Katedra botaniky -NIAB b National Institute of Agricultural Botany -NIAES c National Institute for Agro-Environmental Sciences -NIAH c National Institute of Animal Health -NIAID c National Institute of Allergy and Infectious Diseases -NIAS sb National Institute of Agrobiological Sciences -NIBH c National Institute of Bioscience and Human-Technology -NIBR scb National Institute of Biological Resources -NIBSC b National Institute for Biological Standards and Control -NICC s National Insect Collection -NICD s Malaria Research Center -NICE s Museum d'Histoire Naturelle -NICH s Hattori Botanical Laboratory -NIES c Microbial Culture Collection -NIFI s National Inland Fisheries Institute -NIFRS s National Research Institute of Fisheries Science -NIG s Nanjing Geographical Institute -NIGL s Nanjing Institute of Geography and Limnology -NIGP s Naking Institute of Geology and Palaeontology -NIHHS h National Institute of Horticultural and Herbal Science, RDA -NIM h Museum d'histoire naturelle de Nimes -NIMM h National Institute of Medicinal Materials -NINF s Newfoundland Insectarium -NIO s National Institute of Oceanography -NIOCC c National Institute of Oceanography Culture Collection -NIPH c National Institute of Public Health, Collection A. Nemec -NIPR s National Institute of Polar Research, Biological Data Department -NIT s Jardim Botanico de Niteroi -NIVA c Culture Collection of Algae (NIVA) -NIWA s National Institute of Water and Atmospheric Research -NJ s Njala University College -NJM s Okresni vlastivedne muzeum -NJM c Nippon Veterinary and Animal Science University -NJNU s Nanjing Normal University, Biology Department -NJSM s New Jersey State Museum -NKA c Nationales Konsiliarlabor fur Adenoviren -NKMC s National Kweiyang Medical College -NKME s Naturkundemuseum Erfurt -NKMU s Nankai University Museum -NKU s Nankai University, Biology Department -NKUM s Nankai University -NLEC s Neal L. Evenhuis -NLH s Agricultural University of Norway, Department of Biology and Nature Conservation -NLHD s Niedersachsisches Landesmuseum -NLPS s Nottingham Literary and Philosophical Society -NLSN s Notre Dame University, Biological Sciences Department -NLU s University of Louisiana at Monroe, Museum of Natural History -NLUH s University of the Philippines College Baguio -NM s Northern Michigan University, Biology Department -NMAC s Inner Mongolia Agricultural University, Department of Pratacultural Science -NMAG s Naturhistorisches Museum, Augsburg -NMB s Naturhistorishes Museum -NMB s National Museum, Bloemfontein +NCIM c National Collection of Industrial Microorganisms +NCIMB c National Collections of Industrial Food and Marine Bacteria (incorporating the NCFB) NCIB,NCMB +NCIP s Pusat Penelitian dan Pengembangan Oseanologi +NCKU s National Cheng-Kung University, Biology Department +NCLN s New College +NCMA s Raleigh, North Carolina Department of Environmental Health and Natural Resources +NCMH c The North Carolina Memorial Hostital +NCMK s Norwich Castle Museum +NCP h National Collection of Passiflora +NCPF c National Collection of Pathogenic Fungi +NCPPB c National Collection of Plant Pathogenic Bacteria +NCPV c National Collection of Pathogenic Viruses +NCS s North Carolina State University +NCSC c National Center of Streptococcus Collection, Department of Microbiology, Faculty of Medical Science +NCSC s North Carolina State University, Botany Department +NCSLG h North Carolina State University +NCSM s North Carolina Museum of Natural Sciences NCSMNS +NCSU s North Carolina State University Collections +NCTC c National Collection of Type Cultures +NCU s University of North Carolina, North Carolina Botanical Garden +NCUT s Nicolaus Copernicus University +NCWRF c National Collection of Wood Rotting Fungi +NCY s Conservatoire et Jardins Botaniques de Nancy +NCYC c National Collection of Yeast Cultures +ND s University of Notre Dame, Department of Biological Sciences +NDA s North Dakota State University, Animal and Range Sciences Department +NDAA s Orange, New South Wales Department of Agriculture +NDAT s Department of Agriculture, Tunisia +NDFC s Newfoundland Department of Forestry +NDG s University of Notre Dame, Department of Biological Sciences +NDO s Division of Forest Research, Forest Department +NDSR s National Drosophila Species Resource Center +NDSU s North Dakota State University +NDTC s Ningde Teachers College, Biology Department +NE s University of New England +NEB s University of Nebraska State Museum +NEBC s Harvard University +NEBK h University of Nebraska at Kearney +NEFI s Northeastern Forestry University, Forestry Department +NEM c Faculte de Medecine Necker-Enfants Malades +NEMO s Truman State University +NEMSU s Truman State University +NEMU s Newark Museum +NENU s Northeast Normal University, Biology Department +NEPCC c North East Pacific Culture Collection +NESH s University of Nevada +NEU s Universite de Neuchatel, Laboratoire de botanique evolutive +NEUN h Near East University +NEW s University of Newcastle +NEWHM s Hancock Museum +NEZ s Museum, Zoology Department, University of New England +NF s Nanjing Forestry University, Forest Resources and Environment +NFCCI c National Fungal Culture Collection of India +NFCCP c National Fungal Culture Collection of Pakistan +NFLD s Memorial University of Newfoundland, Biology Department +NFM s Newfoundland Museum +NFO s Niagara Parks Botanical Gardens and School of Horticulture +NFRC s Northern Forest Research Centre +NFRDI c National Fisheries Research & Development Institute +NFRI c Norwegian Forest Research Institute +NFRN s Canadian Forest Service, NRCan +NGBB h Nezahat Gokyigit Botanik Bahcesi +NGCPR h Naoroji Godrej Centre for Plant Research +NGI s Nanjing Geographical Institute +NGM s Bromley House Library +NGMC s National Geological Museum of China +NGR c Plant Pathology +NH s South African National Biodiversity Institute +NHA s University of New Hampshire, Plant Biology Department +NHCP h National Bureau of Plant Genetic Resources +NHES s Connecticut Agricultural Experiment Station, Entomology Department +NHG s Naturhistorische Gesellschaft e. V., Abteilung Botanik +NHI h Natural History Institute +NHIC s Ontario Ministry of Natural Resources +NHL c National Institute of Hygienic Sciences +NHM s Naturhistorisches Museum, Bern +NHM s University of Nottingham, Botany Department +NHMA s Natural History Museum, Denmark +NHMB s Naturhistorisches Museum, Basel +NHMB s Natural History Museum Bucharest +NHMBe s Naturhistorisches Museum Bern +NHMC s Natural History Museum of Crete, University of Crete, Department of Botany +NHMC s Natural History Museum, Rangoon +NHME s Natuurhistorisch Museum +NHMF h Natural History Museum Fribourg +NHMG s Natural History Museum of Guangxi +NHMG s Goteborgs Naturhistoriska Museet +NHMK s Landesmuseum fuer Karnten +NHML s Natural History Museum, Tripoli +NHMM s Natuurhistorische Museum Maastricht +NHMM-LS s Naturhistorisches Museum/Landessammlung fuer Naturkunde Rheinland-Pfalz +NHMN s Nottingham Natural History Museum (Wollaton Hall) +NHMR s Natural History Museum Rijeka +NHMR s Natural History Museum, Reykjavik +NHMR s Natuurhistorisch Museum +NHMS h Natural History Museum Split +NHMTU s Natural History Museum, Tribhuvan University +NHMUK sb Natural History Museum, London BM,BM(NH),BMNH,NHM,NHM R,NMH +NHMUK s Natural History Museum, Karachi +NHMW s Naturhistorisches Museum, Wien +NHNC s La Chaux-de-Fons +NHNE s New England College, Biology Department +NHR h Institute of Scientific and Technological Research (IRST) +NHRI s Islandic Museum of Natural History +NHRM s Naturhistoriska Rijkmuseet +NHRS s Swedish Museum of Natural History, Entomology Collections +NHSD s Natural History Society of Dublin +NHST s Museum of Natural History, Reunion +NHT s Tropical Pesticides Research Institute +NHV s Institut fuer Landwirtschaftliche Botanik +NI c Nagao Institute +NI s Slovenska pol'nohospodarska Univerzita, Katedra botaniky +NIAB b National Institute of Agricultural Botany +NIAES c National Institute for Agro-Environmental Sciences +NIAH c National Institute of Animal Health +NIAID c National Institute of Allergy and Infectious Diseases +NIAS sb National Institute of Agrobiological Sciences +NIBH c National Institute of Bioscience and Human-Technology +NIBR scb National Institute of Biological Resources NNIBR +NIBSC b National Institute for Biological Standards and Control +NICC s National Insect Collection +NICD s Malaria Research Center +NICE s Museum d'Histoire Naturelle +NICH s Hattori Botanical Laboratory +NIES c Microbial Culture Collection +NIFI s National Inland Fisheries Institute +NIFRS s National Research Institute of Fisheries Science +NIG s Nanjing Geographical Institute +NIGL s Nanjing Institute of Geography and Limnology +NIGP s Naking Institute of Geology and Palaeontology +NIHHS h National Institute of Horticultural and Herbal Science, RDA +NIM h Museum d'histoire naturelle de Nimes +NIMM h National Institute of Medicinal Materials +NINF s Newfoundland Insectarium +NIO s National Institute of Oceanography +NIOCC c National Institute of Oceanography Culture Collection +NIPH c National Institute of Public Health, Collection A. Nemec +NIPR s National Institute of Polar Research, Biological Data Department +NIT s Jardim Botanico de Niteroi +NIVA c Culture Collection of Algae (NIVA) +NIWA s National Institute of Water and Atmospheric Research +NJ s Njala University College +NJM s Okresni vlastivedne muzeum +NJM c Nippon Veterinary and Animal Science University +NJNU s Nanjing Normal University, Biology Department +NJSM s New Jersey State Museum +NKA c Nationales Konsiliarlabor fur Adenoviren +NKMC s National Kweiyang Medical College +NKME s Naturkundemuseum Erfurt +NKMU s Nankai University Museum +NKU s Nankai University, Biology Department +NKUM s Nankai University +NLEC s Neal L. Evenhuis +NLH s Agricultural University of Norway, Department of Biology and Nature Conservation +NLHD s Niedersachsisches Landesmuseum +NLPS s Nottingham Literary and Philosophical Society +NLSN s Notre Dame University, Biological Sciences Department +NLU s University of Louisiana at Monroe, Museum of Natural History +NLUH s University of the Philippines College Baguio +NM s Northern Michigan University, Biology Department +NMAC s Inner Mongolia Agricultural University, Department of Pratacultural Science +NMAG s Naturhistorisches Museum, Augsburg +NMB c Ningbo Marine Biotechnology +NMB s Naturhistorishes Museum +NMB s National Museum, Bloemfontein NMB:P s National Museum, Bloemfontein, The Protozoan collection of the National Museum -NMBA s National Museum, Buenos Aires -NMBA s Naturhistorisches Museum der Benediktiner-Abtei -NMBA s Naturhistorisches Museum, Basel -NMBE s Naturhistorisches Museum der Burgergemeinde Bern -NMBO s National Museum, Bloemfontein -NMBT h Natuurmuseum Brabant -NMBZ s Natural History Museum of Zimbabwe -NMC s New Mexico State University, Department of Biology -NMC s Canadian Museum of Nature -NMCC c North Maharashtra Microbial Culture Collection Centre -NMCDC s Inner Mongolia Center for Endemic Disease Control and Research -NMCI s Noto Marine Center Ishikawa Prefecture +NMBA s National Museum, Buenos Aires +NMBA s Naturhistorisches Museum der Benediktiner-Abtei +NMBA s Naturhistorisches Museum, Basel +NMBE s Naturhistorisches Museum der Burgergemeinde Bern NHM +NMBO s National Museum, Bloemfontein +NMBT h Natuurmuseum Brabant +NMBZ s Natural History Museum of Zimbabwe +NMC s New Mexico State University, Department of Biology +NMC s Canadian Museum of Nature CMN +NMCC c North Maharashtra Microbial Culture Collection Centre +NMCDC s Inner Mongolia Center for Endemic Disease Control and Research +NMCI s Noto Marine Center Ishikawa Prefecture NMCI:AR s Noto Marine Center Ishikawa Prefecture, Arthropoda collection NMCI:EC s Noto Marine Center Ishikawa Prefecture, Echinodermata NMCI:IV s Noto Marine Center Ishikawa Prefecture, Invertebrata NMCI:MO s Noto Marine Center Ishikawa Prefecture, Mollusca collection NMCI:P s Noto Marine Center Ishikawa Prefecture, Pisces and Coelenterata NMCI:S s Noto Marine Center Ishikawa Prefecture, Sea weed -NMCL s Naturkunde-Museum -NMCR s New Mexico State University, Department of Animal and Range Sciences -NME s Sammlung des Naturkundemseum Erfurt -NMED s New Mexico Environment Department -NMEG s Naturkundesmuseum -NMFC s Inner Mongolia Forestry College, Desert Control and Utilization Department -NMFSH s National Marine Fisheries Service -NMG s Naturhistoriska Riksmuseet -NMI s National Museum of Ireland -NMI c Bacteria collection of National Institute of Public Health, National Medicines Institute, Poland -NMID s National Museum of Ireland -NMK s National Museums of Kenya -NMKE s National Museum of Kenya -NMKL s National Museum of Malaysia -NML c National Microbiology Laboratory, Public Health Agency of Canada -NMLS s Natur-Museum Luzern -NMLU s Natur-Museum Luzern, Botany Department -NMMA s Nantucket Maria Mitchell Association, Natural Sciences Department -NMMBP s National Museum of Marine Biology and Aquarium -NMMH s North Manchurian Museum -NMML s National Marine Mammal Laboratory -NMMNH s New Mexico Museum of Natural History and Science +NMCL s Naturkunde-Museum +NMCR s New Mexico State University, Department of Animal and Range Sciences +NME s Sammlung des Naturkundemseum Erfurt +NMED s New Mexico Environment Department +NMEG s Naturkundesmuseum +NMFC s Inner Mongolia Forestry College, Desert Control and Utilization Department +NMFSH s National Marine Fisheries Service +NMG s Naturhistoriska Riksmuseet +NMI s National Museum of Ireland +NMI c Bacteria collection of National Institute of Public Health, National Medicines Institute, Poland +NMID s National Museum of Ireland +NMK s National Museums of Kenya +NMKE s National Museum of Kenya +NMKL s National Museum of Malaysia +NML c National Microbiology Laboratory, Public Health Agency of Canada NML-HCCC +NMLS s Natur-Museum Luzern +NMLU s Natur-Museum Luzern, Botany Department +NMMA s Nantucket Maria Mitchell Association, Natural Sciences Department +NMMBP s National Museum of Marine Biology and Aquarium MNNB-P +NMMH s North Manchurian Museum +NMML s National Marine Mammal Laboratory +NMMNH s New Mexico Museum of Natural History and Science NMMNH:Mamm s New Mexico Museum of Natural History and Science, Mammal collection -NMN s Northamptonshire Natural History Society -NMND s National Museum of Natural History, New Delhi -NMNH s National Museum of Natural History, New Delhi -NMNHI s National Museum of Natural History, New Delhi -NMNK s National Museum of Nepal -NMNL h Natuurmuseum Nijmegen e.o. -NMNS s National Museum of Natural Science -NMNW s National Museum of Namibia -NMNZ s National Museum of New Zealand +NMN s Northamptonshire Natural History Society +NMND s National Museum of Natural History, New Delhi +NMNH s National Museum of Natural History, New Delhi +NMNHI s National Museum of Natural History, New Delhi +NMNK s National Museum of Nepal +NMNL h Natuurmuseum Nijmegen e.o. +NMNS s National Museum of Natural Science +NMNW s National Museum of Namibia +NMNZ s National Museum of New Zealand NMNZ:AI s National Museum of New Zealand, Insects NMNZ:AM s National Museum of New Zealand, Amphibians NMNZ:AS s National Museum of New Zealand, Spiders @@ -4723,27 +4769,27 @@ NMNZ:RE s National Museum of New Zealand, Reptiles NMNZ:S s National Museum of New Zealand, Fossil Vertebrates NMNZ:TS s National Museum of New Zealand, Tissue Collection NMNZ:TSA s National Museum of New Zealand, Tissue Collection -NMP s National Museum (Prague) -NMP s Natal Museum -NMPC s National Museum Prague +NMP s National Museum (Prague) +NMP s Natal Museum +NMPC s National Museum Prague MNHP NMPC:ENT s National Museum Prague, Entomology Collection -NMPG s Zhejiang Institute of Traditional Chinese Medicine -NMPG s Museum der Natur-Gotha -NMPI s Division of Plant Industry -NMQR s National Museum, Bloemfontein -NMR h Semyung University -NMRC c Naval Medical Research Center +NMPG s Zhejiang Institute of Traditional Chinese Medicine +NMPG s Museum der Natur-Gotha +NMPI s Division of Plant Industry +NMQR s National Museum, Bloemfontein +NMR h Semyung University +NMRC c Naval Medical Research Center NMRC:RDD c Naval Medical Research Center, Rickettsial Diseases Division -NMS s National Museums of Scotland -NMS-G s National Museums of Scotland - Geology & Zoology -NMSA s Natal Museum -NMSL s National Museum of Sri Lanka -NMSR s Naturhistorisches Museum im Thueringer Landes museum Heidecksburg zu Rudolstadt -NMSU s Northwest Missouri State University, Biology Department -NMSU s New Mexico State University -NMTC s Inner Mongolia Normal University, Biology Department -NMTT s National Museum and Art Gallery, Port-of-Spain -NMV s Museum Victoria +NMS s National Museums of Scotland NMSZ,NSMZ,RSM,RSME +NMS-G s National Museums of Scotland - Geology & Zoology +NMSA s Natal Museum +NMSL s National Museum of Sri Lanka +NMSR s Naturhistorisches Museum im Thuringer Landes museum Heidecksburg zu Rudolstadt +NMSU s Northwest Missouri State University, Biology Department +NMSU s New Mexico State University +NMTC s Inner Mongolia Normal University, Biology Department +NMTT s National Museum and Art Gallery, Port-of-Spain +NMV s Museum Victoria NMM NMV:A s Museum Victoria, Ichthyology NMV:AV s Museum Victoria, Entomology - Australian Voucher Specimens NMV:B s Museum Victoria, Ornithology @@ -4775,733 +4821,738 @@ NMV:P s Museum Victoria, Paleontology & Paleobotany NMV:T s Museum Victoria, Entomlogy Type Collection NMV:TRI s Museum Victoria, Trichoptera NMV:Z s Museum Victoria, Tissue Collection -NMV s Nakagawa Museum at Nakagawa-cho -NMW s Naturhistorisches Museum, Wien -NMW s National Museums & Galleries of Wales, Department of Biodiversity and Systematic Biology -NMWC s National Museum of Wales -NMWZ s National Museum of Wales -NMZB s National Museum of Zimbabwe -NMZL s National Museum of Zambia -NNA s Nanning Arboretum -NNHMK s National Natural History Museum of the Ukraine -NNKN s Noordbrabants Natuurmuseum -NNM s Nationaal Natuurhistroisch Museum -NNMN s Nationaal Natuurhistorisch Museum Naturalis -NNSU s N. I. Lobachevsky Nizhni Novgorod State University, Department of Botany -NO s Tulane University, Department of Ecology and Evolutionary Biology -NOAA s National Oceanic and Atmospeheric Administration +NMV s Nakagawa Museum at Nakagawa-cho +NMW s Naturhistorisches Museum, Wien NHMV +NMW s National Museums & Galleries of Wales, Department of Biodiversity and Systematic Biology +NMWC s National Museum of Wales +NMWZ s National Museum of Wales +NMZB s National Museum of Zimbabwe +NMZL s National Museum of Zambia +NNA s Nanning Arboretum +NNHMK s National Natural History Museum of the Ukraine +NNKN s Noordbrabants Natuurmuseum +NNM s Nationaal Natuurhistroisch Museum +NNMN s Nationaal Natuurhistorisch Museum Naturalis +NNSU s N. I. Lobachevsky Nizhni Novgorod State University, Department of Botany +NO s Tulane University, Department of Ecology and Evolutionary Biology +NOAA s National Oceanic and Atmospeheric Administration NOAA:MarFor s National Oceanic and Atmospeheric Administration, Marine Forensics -NOAS s New Orleans Academy of Science -NOCC s National Orchid Conservation Center -NODCAR c marwa mokhtar Abd Rabo -NoF c The Fungus Culture Collection of the Northern Forestry Centre -NOI s Nanhai Oceanographic Institute -NOLS s University of New Orleans, Biological Sciences Department -NOSU s Northeastern State University, Natural Sciences and Mathematics Department -NOT s Nottingham City Natural History Museum -NOTM s University of Nottingham, Manuscript Department -NOU s Institut de Recherche pour le Developpement, Botany and Applied Ecology Department -NPA s Nanjing Institute of Geology and Paleontology, Academia Sinica -NPB s Natal Parks, Game, and Fish Preservation Board, Research Section -NPC s National Pusa Collection -NPIB s Northwest Plateau Institute of Biology -NPP c N.P.P -NPRI s Seoul National University -NPS s United States National Park Service -NPSC s Northern Prairie Science Center -NPT s Newport Museum and Art Gallery -NPWRC s Northern Prairie Research Center -NR h Institute of Forest Ecology Slovak Academy of Sciences -NRC c Division of Biological Sciences, National Research Council of Canada -NRC s National Research Centre -NRCC s National Research Council of Canada -NRCS c National Reference Center for Streptococci in Aachen -NRIBAS s National Research Institute of Biology, Academia Sinica -NRIC c NODAI Research Institute Culture Collection -NRL c Neisseria Reference Laboratory -NRM s Swedish Museum of Natural History -NRN s Nairn Literary Society Library, Public Library -NRNZ s Northland Regional Museum -NRPSU c Department of Agro-industry, Faculty of Natural Resources -NRRL c Agricultural Research Service Culture Collection -NRRL:MOLD sc Agricultural Research Service Culture Collection, -NRRL:PROK sc Agricultural Research Service Culture Collection, -NRRL:YEAST sc Agricultural Research Service Culture Collection, -NRS s Naturhistoriska Riksmuseet -NRWC s N. R. Whitney Collection -NRZM c German Reference Center for Meningococci -NS s Central Siberian Botanical Garden -NSAC s Nova Scotia Agricultural College, Department of Environmental Sciences -NSCA s North Scotland College of Agriculture -NSCNFB c Novi Sad Collection of Nitrogen Fixing Bacteria -NSCPM c National State Collection of Pathogenic Microorganisms -NSDA s Nevada Division of Agriculture -NSK s Siberian Central Botanical Garden, Laboratory for Plant Systematics and Floristic Genesis -NSM s Nova Scotia Museum of Natural History -NSM s Sun Yat-Sen Tomb and Memorial Park Commission -NSM s NSM-PV, National Science Museum -NSMC s Nova Scotia Museum -NSMC s Nevada State Museum -NSMHS s Nevada State Museum and Historical Society -NSMK s National Science Museum -NSMT s National Museum of Nature and Science, Tokyo -NSMW s Naturwissenschftlich Sammlung, Museum Wiesbaden -NSNR s Nova Scotia Department of Natural Resources -NSPM s Nova Scotia Museum of Natural History -NSRF s Nova Scotia Research Foundation -NSS s University of Liverpool Botanic Gardens -NSU s Northeastern State University, Biological Collections -NSUL s Northwestern State University of Louisiana -NSW s Royal Botanic Gardens -NSWA s New South Wales Department of Agriculture -NSWF s State Forests of New South Wales -NSWGS s Geological Survey of New South Wales -NSYU s National Sun Yat-sen University -NT s Department of Natural Resources, Environment and the Arts -NTCCI c Culture Collection, Microbiology and Cell Biology Laboratory -NTDPIF s Northern Territory Department of Primary Industry and Fisheries -NTLN s County Record Office, County Archives Department -NTM s Museum and Art Gallery of the Northern Territory -NTM s Museum d'Histoire Naturelle de Nantes -NTN s Central Museum and Art Gallery -NTNU s National Taiwan Normal University -NTNU-VM s Norwegian University of Science and Technology, Museum of Natural History and Archaeology -NTOU sc Institute of Marine Biology, National Taiwan Ocean University -NTS s Nevada Operations Office, U.S. Department of Energy -NTSC s University of North Texas, Biological Sciences Department -NTUC s National Taiwan University -NTUF s National Taiwan University, Forestry Department -NTUM s National Taiwan University -NTUMA s National Taiwan University -NU c Department of Microbiology, Faculty of Science -NU s University of Natal, School of Botany and Zoology -NUA c Department of Microbiology, National University of Athens -NUM s Nagoya University -NUOL s National University of Laos -NUSDM c Department of Microbiology, National University of Singapore -NUSMBS s Niigata University, Sado Marine Biological Station -NUV s Norwich University, Biology and Life Sciences Department -NUVC s Northeastern University, Vertebrate Collection -NVDA s Nevada State Department of Agriculture -NVMC s Nevada State Museum -NVRL s Naturforschende Verein in Riga -NVRW s Naturhistorisches Verein der Preussische Rheinland und Westfalens -NWAU s North-West Agricultural University -NWC s University of Northern Iowa, Nixon Wilson Collection -NWC b National Willows Collection -NWFC sb Northwest University of Agriculture Forestry Science & Technology -NWH s Norfolk Museums and Archaeology Service, Natural History Department -NWK s Newark District Council Museum -NWMSU s Northwest Missouri State University -NWOSU s Northwestern Oklahoma State University, Biology Department -NWSW s Naturwissenschaftliche Sammlungen der Stadt Winterthur -NWT s Harper Adams Agricultural College -NWTC s Northwest Normal University -NWU s Northwestern University, Botany Department -NWUB s Northwest Normal University, Biology Department -NX s Universidade do Estado de Mato Grosso - Campus de Nova Xavantina, Departamento de Ciencias Biologicas -NXAC s Ningxia Agricultural College -NXF s Ningxia Academy of Agriculture and Forestry Sciences -NY s New York Botanical Garden -NYA s Nanyue Arboretum -NYAS s Silvicultural Research Station -NYBG s New York Botanical Garden -NYS s New York State Museum -NYSM s New York State Museum -NYZS s New York Zoological Society -NZAC s New Zealand Arthropod Collection -NZCS s University, National Zoological Collection of Suriname -NZFRI s New Zealand Forest Research Institute Limited -NZFS c Forest Research Culture Collection -NZG s National Zoological Gardens of South Africa -NZOI s New Zealand Oceanographic Institute -NZRD c New Zealand Reference Culture Collection of Microorganisms, Dairy Section -NZRM c New Zealand Reference Culture Collection, Medical Section -NZRP c New Zealand Reference Culture Collection and Soil Section -NZSI s Zoological Survey of India, National Zoological Collection -O s Botanical Museum, Natural History Museum, Oslo -OAC s OAC Herbarium, Biodiversity Institute of Ontario -OAKL s Oakland Museum of California, Natural Sciences Department -OAMB s Open Air Museum of Ethnography and Natural Sciences -OAX s Instituto Politecnico Nacional (CIIDIR-Oax., I.P.N.) -OAXM s Centro Interdisciplinario de Estudios, Coleccion Mastozoologica (Mexico) -OB h Station Umwelt- und Natur Oberhausen -OBG s The Oman Botanic Garden -OBI s California Polytechnic State University, Biological Sciences Department -OBPF s Planting Fields Arboretum State Historic Park -OC s Oberlin College, Biology Department -OCHA s Ochanomizu University -OCLA s University of Science and Arts of Oklahoma -OCM c Oregon Collection of Methanogens -OCNF s Ochoco National Forest -OCSA s Veterinary Research Institute -OCU h Oklahoma City University -ODAC s Oregon Department of Agriculture -ODU s Old Dominion University, Department of Biological Sciences -OFC s Orielton Field Centre -OGDF s Forest Service Region 4, USDA -OGL b Ocean Genome Legacy +NOAS s New Orleans Academy of Science +NOCC s National Orchid Conservation Center +NOCS-DC s National Oceanography Center Southampton Discovery Collections +NODCAR c marwa mokhtar Abd Rabo +NoF c The Fungus Culture Collection of the Northern Forestry Centre +NOI s Nanhai Oceanographic Institute +NOLS s University of New Orleans, Biological Sciences Department +NOSU s Northeastern State University, Natural Sciences and Mathematics Department +NOT s Nottingham City Natural History Museum +NOTM s University of Nottingham, Manuscript Department +NOU s Institut de Recherche pour le Developpement, Botany and Applied Ecology Department +NPA s Nanjing Institute of Geology and Paleontology, Academia Sinica +NPB s Natal Parks, Game, and Fish Preservation Board, Research Section +NPC s National Pusa Collection +NPIB s Northwest Plateau Institute of Biology +NPP c N.P.P +NPRI s Seoul National University +NPS s United States National Park Service +NPSC s Northern Prairie Science Center +NPT s Newport Museum and Art Gallery +NPWRC s Northern Prairie Research Center +NR h Institute of Forest Ecology Slovak Academy of Sciences +NRC c Division of Biological Sciences, National Research Council of Canada +NRC s National Research Centre +NRCC s National Research Council of Canada +NRCS c National Reference Center for Streptococci in Aachen +NRIBAS s National Research Institute of Biology, Academia Sinica +NRIC c NODAI Research Institute Culture Collection +NRL c Neisseria Reference Laboratory +NRM s Swedish Museum of Natural History +NRN s Nairn Literary Society Library, Public Library +NRNZ s Northland Regional Museum +NRPSU c Department of Agro-industry, Faculty of Natural Resources +NRRL c Agricultural Research Service Culture Collection +NRRL:MOLD sc Agricultural Research Service Culture Collection, Mold collection +NRRL:PROK sc Agricultural Research Service Culture Collection, Prokaryotic collection +NRRL:YEAST sc Agricultural Research Service Culture Collection, Yeast Collection +NRS s Naturhistoriska Riksmuseet +NRWC s N. R. Whitney Collection +NRZM c German Reference Center for Meningococci +NS s Central Siberian Botanical Garden +NSAC s Nova Scotia Agricultural College, Department of Environmental Sciences +NSCA s North Scotland College of Agriculture +NSCNFB c Novi Sad Collection of Nitrogen Fixing Bacteria +NSCPM c National State Collection of Pathogenic Microorganisms +NSDA s Nevada Division of Agriculture +NSK s Siberian Central Botanical Garden, Laboratory for Plant Systematics and Floristic Genesis +NSM s Nova Scotia Museum of Natural History +NSM s Sun Yat-Sen Tomb and Memorial Park Commission +NSM s NSM-PV, National Science Museum +NSMC s Nova Scotia Museum +NSMC s Nevada State Museum +NSMHS s Nevada State Museum and Historical Society +NSMK s National Science Museum +NSMT s National Museum of Nature and Science, Tokyo +NSMW s Naturwissenschftlich Sammlung, Museum Wiesbaden +NSNR s Nova Scotia Department of Natural Resources +NSPM s Nova Scotia Museum of Natural History +NSRF s Nova Scotia Research Foundation +NSS s University of Liverpool Botanic Gardens +NSU s Northeastern State University, Biological Collections +NSUL s Northwestern State University of Louisiana +NSW s Royal Botanic Gardens +NSWA s New South Wales Department of Agriculture +NSWF s State Forests of New South Wales +NSWGS s Geological Survey of New South Wales +NSYU s National Sun Yat-sen University +NT s Department of Natural Resources, Environment and the Arts +NTCCI c Culture Collection, Microbiology and Cell Biology Laboratory +NTDPIF s Northern Territory Department of Primary Industry and Fisheries +NTLN s County Record Office, County Archives Department +NTM s Museum and Art Gallery of the Northern Territory +NTM s Museum d'Histoire Naturelle de Nantes +NTN s Central Museum and Art Gallery +NTNU s National Taiwan Normal University NTNUB +NTNU-VM s Norwegian University of Science and Technology, Museum of Natural History and Archaeology +NTOU sc Institute of Marine Biology, National Taiwan Ocean University +NTS s Nevada Operations Office, U.S. Department of Energy +NTSC s University of North Texas, Biological Sciences Department +NTUC s National Taiwan University +NTUF s National Taiwan University, Forestry Department +NTUM s National Taiwan University +NTUMA s National Taiwan University +NU c Department of Microbiology, Faculty of Science +NU s University of Natal, School of Botany and Zoology +NUA c Department of Microbiology, National University of Athens +NUM s Nagoya University +NUOL s National University of Laos +NUSDM c Department of Microbiology, National University of Singapore +NUSMBS s Niigata University, Sado Marine Biological Station +NUV s Norwich University, Biology and Life Sciences Department +NUVC s Northeastern University, Vertebrate Collection +NVDA s Nevada State Department of Agriculture +NVMC s Nevada State Museum +NVRL s Naturforschende Verein in Riga +NVRW s Naturhistorisches Verein der Preussische Rheinland und Westfalens +NWAU s North-West Agricultural University +NWC s University of Northern Iowa, Nixon Wilson Collection +NWC b National Willows Collection +NWFC sb Northwest University of Agriculture Forestry Science & Technology +NWH s Norfolk Museums and Archaeology Service, Natural History Department +NWK s Newark District Council Museum +NWMSU s Northwest Missouri State University +NWOSU s Northwestern Oklahoma State University, Biology Department +NWSW s Naturwissenschaftliche Sammlungen der Stadt Winterthur +NWT s Harper Adams Agricultural College +NWTC s Northwest Normal University +NWU s Northwestern University, Botany Department +NWUB s Northwest Normal University, Biology Department +NX s Universidade do Estado de Mato Grosso - Campus de Nova Xavantina, Departamento de Ciencias Biologicas +NXAC s Ningxia Agricultural College +NXF s Ningxia Academy of Agriculture and Forestry Sciences +NY s New York Botanical Garden +NYA s Nanyue Arboretum +NYAS s Silvicultural Research Station +NYBG s New York Botanical Garden +NYS s New York State Museum +NYSM s New York State Museum +NYZS s New York Zoological Society +NZAC s New Zealand Arthropod Collection LCR:NZAC +NZCS s University, National Zoological Collection of Suriname +NZFRI s New Zealand Forest Research Institute Limited +NZFS c Forest Research Culture Collection +NZG s National Zoological Gardens of South Africa +NZOI s New Zealand Oceanographic Institute +NZRD c New Zealand Reference Culture Collection of Microorganisms, Dairy Section +NZRM c New Zealand Reference Culture Collection, Medical Section +NZRP c New Zealand Reference Culture Collection and Soil Section +NZSI s Zoological Survey of India, National Zoological Collection +O s Botanical Museum, Natural History Museum, Oslo +OAC s OAC Herbarium, Biodiversity Institute of Ontario UOG:OAC +OAKL s Oakland Museum of California, Natural Sciences Department +OAMB s Open Air Museum of Ethnography and Natural Sciences +OAX s Instituto Politecnico Nacional (CIIDIR-Oax., I.P.N.) +OAXM s Centro Interdisciplinario de Estudios, Coleccion Mastozoologica (Mexico) +OB h Station Umwelt- und Natur Oberhausen +OBG s The Oman Botanic Garden +OBI s California Polytechnic State University, Biological Sciences Department +OBPF s Planting Fields Arboretum State Historic Park +OC s Oberlin College, Biology Department +OCHA s Ochanomizu University +OCLA s University of Science and Arts of Oklahoma +OCM c Oregon Collection of Methanogens +OCNF s Ochoco National Forest +OCSA s Veterinary Research Institute +OCU h Oklahoma City University +ODAC s Oregon Department of Agriculture +ODU s Old Dominion University, Department of Biological Sciences +OFC s Orielton Field Centre +OGDF s Forest Service Region 4, USDA +OGL b Ocean Genome Legacy OGL:OGR b Ocean Genome Legacy, Ocean Genome Resource -OGU s Odesskij Gosudarstvennij Universitet -OH s Agricultural Museum of Praha -OHBR s Ontario Hydro -OHHI h Orel State University -OHM s Oldham Microscopical and Natural History Society -OHN s Regionherbariet i Oskarshamn -OHSC s Ohio Historical Society -OKA s Oksky State Biosphere Reserve -OKAY s Okayama University of Science, Department of Biosphere-Geosphere System Science -OKL s University of Oklahoma, Botany and Microbiology Department/ Oklahoma Biological Survey -OKLA s Oklahoma State University, Botany Department -OL s Palacky University, Botany Department -OLAN s Ministerio de Recursos Naturales -OLD s Universitat Oldenburg -OLDM s Libraries, Art Galleries and Museums -OLDS s Olds College, Horticulture Department -OLE s Oundle School, Biology Department -OLM s Vlastivedne muzeum v Olomouci -OLML s Oberoesterreichisches Landesmuseum -OLP s Univerzity Palackeho, Katedra biologie -OLS h University of Warmia and Mazury -OLTC s Teachers Training College, Botany Department -OLV s Olivet College, Biology Department -OLYM h Olympic National Park -OM s Otago Museum -OMA s University of Nebraska Omaha, Biology Department -OMC s Catalogues in Otago Museum -OMC s Mills College, Biology Department -OMJ s Okresni muzeum a galerie -OMKH s Oblastni muzeum Kutna Hora -OMNH s Osaka Museum of Natural History -OMNH s Oklahoma Museum of Natural History -OMNHN s The Sam Noble Oklahoma State Museum of Natural History -OMNHO s Osaka Museum of Natural History -OMNO s Oklahoma Museum of Natural History -OMNZ s Otago Museum -OMP s Polabske muzeum v Podebradech -OMPB s Osservatorio per le Malattie delle Piante per la Regione Emilia-Romagna -OMPG s Osservatorio per le Malattie delle Piante per le Province di Genova e La Spezia -OMPS s Osservatorio per le Malattie delle Piante per la Sardegna -OMSK h Omsk Pedagogical Univeristy -OMSKM s Omsk State Agrarian University, Department of Forestry and Plant Conservation -OMUB s Ondokuz Mayis University, Biology Department -ON s Oman Natural History Museum -ONNC s Office de la Recherche Scientifique et Technique d'Outre-Mer -ONP s Olympic National Park -ONPC s Olympic National Park -OOM s Kameyama Botanical Garden -OP s Silesian Museum -OPANM s Otdel Paleontologii i Biostratigrafii Akademii Nauk Moldovkoi Republiki -OPM s Okinawa Prefectual Museum -ORE s University of Oregon, Biology Department -OREB s Karolinska Hoegre Allmaenna Laeroverket -ORI s Ocean Research Institute -ORIS s Institute of Steppe of the Ural branch of Russian Academy of Sciences -ORIT s University of Tokyo -ORM s Musee des Sciences Naturelles, Departement de Botanique -ORS c Culture Collection of the Laboratory of Soil Microbiology, ORSTOM -ORSAY sb Universite Paris-Sud - Parc Botanique de Launay -ORSC s Office de la Recherche Scientifique et Technique d'Outre-Mer -ORST s Office de la Recherche Scientifique et Technique d'Outre-Mer -ORSTOM s Office de la Recherche scientifique et Technique Outre-mer -ORT s Instituto Canario de Investigaciones Agrarias (ICIA) -ORTN s Orton Hall -ORU s Oral Roberts University, Biology Department -OS s Ohio State University -OS s Oregon State University -OSA s Osaka Museum of Natural History -OSAC s Oregon State Arthropod Collection -OSAL s Ohio State University Acarology Laboratory -OSB s Society of Botanists -OSBU s Universitat Osnabruck, Spezielle Botanik -OSC s Oregon State University, Botany and Plant Pathology Department -OSEC s K.C Emerson Museum -OSH s University of Wisconsin Oshkosh, Biology and Microbiology Department -OSI s Ordnance Survey of Ireland -OSM s Ostravske muzeum -OSM s Ohio State University Museum -OSMC s St. Martin's College, Biology Department -OSN s Museum am Schoelerberg, Natur und Umwelt -OSTR h University of Ostrava -OSU s Ohio State University -OSU s Oklahoma State University, Collection of Vertebrates -OSUC s Oregon State University -OSUF s Oregon State University, Department of Wood Science and Engineering -OSUFW s Oregon State University, Department of Fisheries and Wildlife Mammal Collection -OSUMZ s Ohio State University, Museum of Biological Diversity -OSUO s Oregon State University, School of Oceanography -OSUS s Oklahoma State University -OSW h State University of New York at Oswego -OSWY s Oswestry Museum -OTA s University of Otago, Botany Department -OTF s Canadian Forest Service -OTM s Otago Museum -OTM s Old Trail Museum -OTSC s Organization for Tropical Studies -OTT s University of Ottawa, Biology Department -OU s Fossil Catalgoue in the Geology Museum -OUA s Universite de Ouagadougou -OULU s University of Oulu, Biology Department -OUM s Oxford University Museum of Natural History -OUPR s Universidade Federal de Ouro Preto, Campus Universitario -OUSM s Oklahoma University Stovall Museum -OUT c Department of Biotechnology -OUVC s Ohio University Vertebrate Collection -OVMB s Okresni vlastivedne muzeum -OWU s Ohio Wesleyan University, Botany-Microbiology Department -OXD s Wadham College -OXF s University of Oxford, Department of Plant Sciences -OXM s Magdalen College Library -P s Herbier National de Paris -PA h Universidade Federal do Oeste do Para -PAC s Pennsylvania State University, Biology Department -PACA s Instituto Anchietano de Pesquisas/UNISINOS -PACMA s Pennsylvania State University, Biology Department -PAD s Universita degli Studi di Padova, Centro Interdipartimentale Musei Scientifici -PADA s Pennsylvania Department of Agriculture -PAE s Stiftung Herbarium Paul Aellen, Universitat Basel -PAL s Universita degli Studi di Palermo, Dipartimento de Scienze Botaniche -PALEON s Wyoming Dinosaur International Society -PAM s Pennsylvania Department of Agriculture -PAMC c Polar and Alpine Microbial Collection -PAMG s Empresa de Pesquisa Agropecuaria de Minas Gerais (EPAMIG), Departamento de Pesquisa -PAMP s Universidad de Navarra, Departamento de Botanica -PAMUH h Pamukkale University -PAN s Panjab University, Botany Department -PAP s Musee de Tahiti et des Iles -PAR s Museo de Ciencias Naturales y Antropologicas Prof. Antonio Serrano, Departamento de Botanica -PARMA s Universita degli Studi di Parma -PAS s Java Sugar Experimental Station -PASA s Pasadena City College, Life Sciences Department -PASG s Paleontological Section of the Georgian Academy of Sciences -PASM s Palomar College, Life Sciences Department -PASSM s Peabody Academy of Science -PAT s Museum National d'Histoire Naturelle -PAUH s University of Texas-Pan American, Biology Department -PAUMC s Pan American University, Mammal Collection -PAUP s Punjab Agricultural University -PAV s Universita di Pavia, Dipartimento de Ecologia del Territorio -PAY s Paisley Philosophical Institute -PBB h Research Center for the Conservation of Natural Resources University and Phu An Botanic Gardens -PBC c Pacific Bacterial Collection -PBF c Perum Bio Farma -PBH s Peterborough City Museum -PBL s Botanical Survey of India, Andaman & Nicobar Circle -PBM s Mahidol University, Department of Pharmaceutical Botany -PBP s Patagonia Botanical Park -PBS s Chambers Institute, Tweeddale Museum -PBZT s Parc Botanique et Zoologique de Tsimbazaza -PC s Museum National d'Histoire Naturelle -PCC c Pasteur Culture Collection of Cyanobacteria -PCE h Hugh Nicholson and Tony Abbott Herbarium -PCH s Prestwich and Pilkington Botanical Society -PCM s Presidency College, Botany Department -PCM c Polish Collection of Microorganisms -PCMB b The Pacific Center for Molecular Biodiversity -PCNZ s Lincoln Plant Health Station -PCU s Museum National d'Histoire Naturelle -PCU c Department of Microbiology, Faculty of Pharmaceutical Sciences -PD c Dutch Plant Protection Service, Culture Collection of Plant Pathogenic Bacteria -PDA s Royal Botanic Gardens, Department of Agriculture -PDBK b Plant DNA Bank in Korea -PDD s New Zealand Fungal and Plant Disease Herbarium -PDTFAU s Paleoantropoloji Dil ve Tarih Cografya Facueltesi -PE s Institute of Botany, Chinese Academy of Sciences -PECA s Pratt Education Center and Aquarium -PECS s Janus Pannonius Museum, Natural History Department -PEFO s Petrified Forest -PEI cb Paul-Ehrlich-Institut -PEI s Agriculture and Agri-Food Canada -PEL sc Universidade Federal de Pelotas, Departamento de Botanica +OGU s Odesskij Gosudarstvennij Universitet +OH s Agricultural Museum of Praha +OHBR s Ontario Hydro +OHHI h Orel State University +OHM s Oldham Microscopical and Natural History Society +OHN s Regionherbariet i Oskarshamn +OHSC s Ohio Historical Society +OKA s Oksky State Biosphere Reserve +OKAY s Okayama University of Science, Department of Biosphere-Geosphere System Science +OKL s University of Oklahoma, Botany and Microbiology Department/ Oklahoma Biological Survey +OKLA s Oklahoma State University, Botany Department +OL s Palacky University, Botany Department +OLAN s Ministerio de Recursos Naturales +OLD s Universitat Oldenburg +OLDM s Libraries, Art Galleries and Museums +OLDS s Olds College, Horticulture Department +OLE s Oundle School, Biology Department +OLM s Vlastivedne muzeum v Olomouci +OLML s Oberoesterreichisches Landesmuseum +OLP s Univerzity Palackeho, Katedra biologie +OLS h University of Warmia and Mazury +OLTC s Teachers Training College, Botany Department +OLV s Olivet College, Biology Department +OLYM h Olympic National Park +OM s Otago Museum +OMA s University of Nebraska Omaha, Biology Department +OMC s Catalogues in Otago Museum +OMC s Mills College, Biology Department +OMJ s Okresni muzeum a galerie +OMKH s Oblastni muzeum Kutna Hora +OMNH s Osaka Museum of Natural History +OMNH s Oklahoma Museum of Natural History +OMNHN s The Sam Noble Oklahoma State Museum of Natural History +OMNHO s Osaka Museum of Natural History +OMNO s Oklahoma Museum of Natural History +OMNZ s Otago Museum +OMP s Polabske muzeum v Podebradech +OMPB s Osservatorio per le Malattie delle Piante per la Regione Emilia-Romagna +OMPG s Osservatorio per le Malattie delle Piante per le Province di Genova e La Spezia +OMPS s Osservatorio per le Malattie delle Piante per la Sardegna +OMSK h Omsk Pedagogical Univeristy +OMSKM s Omsk State Agrarian University, Department of Forestry and Plant Conservation +OMUB s Ondokuz Mayis University, Biology Department +ON s Oman Natural History Museum +ONNC s Office de la Recherche Scientifique et Technique d'Outre-Mer +ONP s Olympic National Park +ONPC s Olympic National Park +OOM s Kameyama Botanical Garden +OP s Silesian Museum +OPANM s Otdel Paleontologii i Biostratigrafii Akademii Nauk Moldovkoi Republiki +OPM s Okinawa Prefectual Museum +ORE s University of Oregon, Biology Department +OREB s Karolinska Hoegre Allmaenna Laeroverket +ORI s Ocean Research Institute +ORIS s Institute of Steppe of the Ural branch of Russian Academy of Sciences +ORIT s University of Tokyo +ORM s Musee des Sciences Naturelles, Departement de Botanique +ORS c Culture Collection of the Laboratory of Soil Microbiology, ORSTOM +ORSAY sb Universite Paris-Sud - Parc Botanique de Launay +ORSC s Office de la Recherche Scientifique et Technique d'Outre-Mer +ORST s Office de la Recherche Scientifique et Technique d'Outre-Mer +ORSTOM s Office de la Recherche scientifique et Technique Outre-mer +ORT s Instituto Canario de Investigaciones Agrarias (ICIA) +ORTN s Orton Hall +ORU s Oral Roberts University, Biology Department +OS s Ohio State University +OS s Oregon State University +OSA s Osaka Museum of Natural History +OSAC s Oregon State Arthropod Collection +OSAL s Ohio State University Acarology Laboratory +OSB s Society of Botanists +OSBU s Universitat Osnabruck, Spezielle Botanik +OSC s Oregon State University, Botany and Plant Pathology Department +OSEC s K.C Emerson Museum +OSH s University of Wisconsin Oshkosh, Biology and Microbiology Department +OSI s Ordnance Survey of Ireland +OSM s Ostravske muzeum +OSM s Ohio State University Museum +OSMC s St. Martin's College, Biology Department +OSN s Museum am Schoelerberg, Natur und Umwelt +OSTR h University of Ostrava +OSU s Ohio State University +OSU s Oklahoma State University, Collection of Vertebrates +OSUC s Oregon State University +OSUF s Oregon State University, Department of Wood Science and Engineering +OSUFW s Oregon State University, Department of Fisheries and Wildlife Mammal Collection +OSUMZ s Ohio State University, Museum of Biological Diversity +OSUO s Oregon State University, School of Oceanography +OSUS s Oklahoma State University +OSW h State University of New York at Oswego +OSWY s Oswestry Museum +OTA s University of Otago, Botany Department +OTF s Canadian Forest Service +OTM s Otago Museum +OTM s Old Trail Museum +OTSC s Organization for Tropical Studies +OTT s University of Ottawa, Biology Department +OU s Fossil Catalgoue in the Geology Museum +OUA s Universite de Ouagadougou +OULU s University of Oulu, Biology Department +OUM s Oxford University Museum of Natural History OUMNH +OUPR s Universidade Federal de Ouro Preto, Campus Universitario +OUSM s Oklahoma University Stovall Museum +OUT c Department of Biotechnology +OUVC s Ohio University Vertebrate Collection +OVMB s Okresni vlastivedne muzeum +OWU s Ohio Wesleyan University, Botany-Microbiology Department +OXD s Wadham College +OXF s University of Oxford, Department of Plant Sciences +OXM s Magdalen College Library +P s Herbier National de Paris P +PA h Universidade Federal do Oeste do Para +PAC s Pennsylvania State University, Biology Department +PACA s Instituto Anchietano de Pesquisas/UNISINOS +PACMA s Pennsylvania State University, Biology Department +PAD s Universita degli Studi di Padova, Centro Interdipartimentale Musei Scientifici +PADA s Pennsylvania Department of Agriculture +PAE s Stiftung Herbarium Paul Aellen, Universitat Basel +PAL s Universita degli Studi di Palermo, Dipartimento de Scienze Botaniche +PALEON s Wyoming Dinosaur International Society +PAM s Pennsylvania Department of Agriculture +PAMC c Polar and Alpine Microbial Collection +PAMG s Empresa de Pesquisa Agropecuaria de Minas Gerais (EPAMIG), Departamento de Pesquisa +PAMP s Universidad de Navarra, Departamento de Botanica +PAMUH h Pamukkale University +PAN s Panjab University, Botany Department +PAP s Musee de Tahiti et des Iles +PAR s Museo de Ciencias Naturales y Antropologicas Prof. Antonio Serrano, Departamento de Botanica +PARMA s Universita degli Studi di Parma +PAS s Java Sugar Experimental Station +PASA s Pasadena City College, Life Sciences Department +PASG s Paleontological Section of the Georgian Academy of Sciences +PASM s Palomar College, Life Sciences Department +PASSM s Peabody Academy of Science +PAT s Museum National d'Histoire Naturelle +PAUH s University of Texas-Pan American, Biology Department +PAUMC s Pan American University, Mammal Collection +PAUP s Punjab Agricultural University +PAV s Universita di Pavia, Dipartimento de Ecologia del Territorio +PAY s Paisley Philosophical Institute +PBB h Research Center for the Conservation of Natural Resources University and Phu An Botanic Gardens +PBC c Pacific Bacterial Collection +PBF c Perum Bio Farma +PBH s Peterborough City Museum +PBL s Botanical Survey of India, Andaman & Nicobar Circle +PBM s Mahidol University, Department of Pharmaceutical Botany +PBP s Patagonia Botanical Park +PBS s Chambers Institute, Tweeddale Museum +PBZT s Parc Botanique et Zoologique de Tsimbazaza +PC s Museum National d'Histoire Naturelle +PCC c Pasteur Culture Collection of Cyanobacteria +PCE h Hugh Nicholson and Tony Abbott Herbarium +PCH s Prestwich and Pilkington Botanical Society +PCM s Presidency College, Botany Department +PCM c Polish Collection of Microorganisms +PCMB b The Pacific Center for Molecular Biodiversity BPBM:PCMB +PCNZ s Lincoln Plant Health Station +PCU s Museum National d'Histoire Naturelle +PCU c Department of Microbiology, Faculty of Pharmaceutical Sciences +PD c Dutch Plant Protection Service, Culture Collection of Plant Pathogenic Bacteria +PDA s Royal Botanic Gardens, Department of Agriculture +PDBK b Plant DNA Bank in Korea +PDD s New Zealand Fungal and Plant Disease Herbarium LCR:PDD +PDTFAU s Paleoantropoloji Dil ve Tarih Cografya Facueltesi +PE s Institute of Botany, Chinese Academy of Sciences +PECA s Pratt Education Center and Aquarium +PECS s Janus Pannonius Museum, Natural History Department +PEFO s Petrified Forest +PEI cb Paul-Ehrlich-Institut +PEI s Agriculture and Agri-Food Canada +PEL sc Universidade Federal de Pelotas, Departamento de Botanica PEL:LIPP c Universidade Federal de Pelotas, Departamento de Botanica, Laboratory Plant-Pathogen Interaction -PEM s Beijing Medical University, Botany Department -PEM s Port Elizabeth Museum -PEN s Penrith Museum -PENN s University of Pennsylvania Herbarium -PER h City Museum -PERM s University of Perm, Botany Department -PERTH s Western Australian Herbarium -PERU s Universita di Perugia, Dipartimento di Biologia Vegetale -PES s University of Peshawar, Natural Drug Division -PESA s Centro Ricerche Floristiche Marche -PET s National University of Peking Teachers' College -PEU s University of Port Elizabeth, Botany Department -PEUFR s Universidade Federal Rural de Pernambuco, Departamento de Biologia -PEY s Peking University, Biology Department -PFC s Pfeiffer University, Biology Department -PFCA s Pacific Forestry Centre Arthropod Reference Collection -PFES s Petawawa National Forestry Institute, Canadian Forest Service -PFI s Percy FitzPatrick Institute of African Ornithology -PFRA s Tree Nursery -PFRS s Pacific Southwest Forest and Range Experiment Station -PFSS s Petrified Forest National Park -PG h Plant Gateway -PGC c Peterhof Genetic Collection of Microalgae -PGFA s Pyatigorsk State Pharmaceutical Academy, Botany Department -PGL s Preussiche Geologische Landesanstalt -PGM s Pacific Grove Museum of Natural History -PGMNH s Pacific Grove Museum of Natural History -PGR c Plant Gene Resources of Canada national and international base and active collections -PGRC b Plant Gene Resources of Canada +PEM s Beijing Medical University, Botany Department +PEM s Port Elizabeth Museum +PEN s Penrith Museum +PENN s University of Pennsylvania Herbarium +PER h City Museum +PERM s University of Perm, Botany Department +PERTH s Western Australian Herbarium +PERU s Universita di Perugia, Dipartimento di Biologia Vegetale +PES s University of Peshawar, Natural Drug Division +PESA s Centro Ricerche Floristiche Marche +PET s National University of Peking Teachers' College +PEU s University of Port Elizabeth, Botany Department +PEUFR s Universidade Federal Rural de Pernambuco, Departamento de Biologia +PEY s Peking University, Biology Department +PFC s Pfeiffer University, Biology Department +PFCA s Pacific Forestry Centre Arthropod Reference Collection +PFES s Petawawa National Forestry Institute, Canadian Forest Service +PFI s Percy FitzPatrick Institute of African Ornithology +PFRA s Tree Nursery +PFRS s Pacific Southwest Forest and Range Experiment Station +PFSS s Petrified Forest National Park +PG h Plant Gateway +PGC c Peterhof Genetic Collection of Microalgae +PGFA s Pyatigorsk State Pharmaceutical Academy, Botany Department +PGL s Preussiche Geologische Landesanstalt +PGM s Pacific Grove Museum of Natural History +PGMNH s Pacific Grove Museum of Natural History +PGR c Plant Gene Resources of Canada national and international base and active collections +PGRC b Plant Gene Resources of Canada PGRC:CN b Plant Gene Resources of Canada, Canadian National Plant Germplasm System -PGSC c Pseudomonas Genetic Stock Center -PH s Academy of Natural Sciences, Botany Department -PHA s Pharmaceutical Society of Great Britain -PHARM h Southern Cross University -PHBL c Philip Harris Biological Ltd. -PHEL s Plant Health and Environment Laboratory -PHEO h Karadag Natural Reserve -PHG s Peper Harow -PHH h University of Science,Ho Chi Minh City Vietnam National University -PHIL s University of the Sciences in Philadelphia, Biological Sciences Department -PI s Institut und Museum fuer Geologie und Palaeontologie -PI s Universita di Pisa, Dipartimento di Scienze Botaniche -PI s Paleontological Institute -PIAGR h University of Pisa -PICRC h Palau International Coral Reef Center -PIHG s Florida Department of Agriculture and Consumer Services -PIHU s Paleontological Institut of Helsingfors -PIKN s Koronivia Research Station -PIMUI s Palaeontologische Institut und Museum der Universitaet in Innsbruck -PIMUZ s Palaontologisches Institut und Museum der Universitat Zurich -PIN s Philosophical Institution of Newport -PIN s Paleontological Institute, Russian Academy of Sciences -PINN s Pinnacles National Monument -PIR c Bulgarian Research Culture Collection -PISR s Pechora-Ilych State Reserve, Russia -PIUU s Paleontological Institut, University of Uppsala -PKDC s Divisao de Museu de Historia Natural -PKM s V. G. Belinsk Pedagogical Institute of Penza -PL s Zapadoceske muzeum -PLAT h State University of New York, College at Plattsburgh -PLES h Plyos State Museum -PLFV s Principality of Liechtenstein -PLH s Plymouth City Museum and Art Gallery -PLP h Institute of Himalayan Bioresource Technology -PLU h Pacific Lutheran University -PLY sc Plymouth Institution and Athenaeum -PLYMOUTH c Plymouth Culture Collection -PLYP s University of Plymouth, Department of Biological Sciences -PM s Peabody Essex Museum, Natural History Department -PM s Pratt Museum -PM s Putnam Museum of History and Natural Science -PMA s Provincial Museum of Alberta -PMA s Universidad de Panama -PMAA s Palaeontological Collections, Provincial Museum and Achieves of Alberta -PMAE s Royal Alberta Museum -PMAG s Perth Museum and Art Gallery -PMAM s Beijing Natural History Museum -PMAU s Peterborough Museum and Art Gallery -PMB s Prirodnjacki Muzej Srpske Zemije -PMBC s Phuket Marine Biological Centre -PMFP s Papeete Museum -PMG s Horto Florestal -PMG s Paisley Museum of Geological Collection -PMH s City Museum and Records Office -PMHPS s Portsmouth Philosophical Society -PMHU s Palaontologisches Museum -PMIG s Phyletisches Museum -PMJ s Phyletisches Museum -PMK s Pugachev Regional Museum -PMK s Podunajske muzeum -PMNH s Pakistan Museum of Natural History -PMNH s Peabody Museum of Natural History -PMNH s Pratt Museum of Natural History -PMQ s Public Museum -PMR s Prirodoslovni muzej Rijeka -PMS s Prirodonamen Muzej Skopje -PMS s Pacific Marine Station -PMS s Peabody Essex Museum -PMSD s Pettigrew Museum -PMSL s Slovenian Museum of Natural History (Prirodosloveni Muzej Slovenije) -PMSP s Prefeitura do Municipio de Sao Paulo, Departamento de Parques e Areas Verdes -PMU s Paleontological Museum of Undory -PMU s Paleontological Museum of Uppsala -PMV s Provincial Museum -PNBG s University of the Philippines -PNCM-BIOTECH c Philippine National Collection of Microorganisms -PND h Dr. Shivaram Karantha Pilikula Nisarga Dhama -PNG s Division of Primary Industry -PNGM s National Museum and Art Gallery, Port Moresby -PNH s Philippine National Herbarium -PNICMM-INP s Instituto Nacional de la Pesca (Mexico) -PNL s Polytechnic of North London, Food and Biological Sciences Department -PNM s Philippine National Museum -PNPC s Chickasaw National Recreational Area [formerly Platt National Park] -PNZ s Penlee House Museum -PO s Universidade do Porto, Departamento de Botanica -PO s Collection of the Zoological Institute of the Russian Academy of Sciences -POFS s Forest Service, USDA -POKM s Penza Regional Local History Museum -POKM s Perm Regional Lore Museum -POL-F s Pollichia, Pfalzmuseum fur Naturkunde Thallichtenberg -POLL s Pfalzmuseum fuer Naturkunde -POM s Pomona College -POP s Tatranske muzeum v Poprade -POR s Universita degli Studi di Napoli -PORE s Point Reyes National Seashore -PORT s BioCentro-UNELLEZ -PORUN s Universita degli Studi di Napoli, Dip Ar Bo Pa Ve - Sezione Botanica -POZ s Adam Mickiewicz University, Department of Plant Taxonomy -POZG s Adam Mickiewicz University, Department of Geobotany -POZM s Adam Mickiewicz University, Department of Plant Ecology and Environment Protection -POZNB s Agricultural Academy, Botany Department -POZW s Adam Mickiewicz University -PPC h Palawan State University -PPCC c Plant Pathology Culture Collection -PPCC s Plant Protection Centre Collection -PPCD s West Virginia Department of Agriculture -PPDD s Ministry of Agriculture -PPFI s Pakistan Forest Institute -PPHM s Panhandle-Plains Historical Museum -PPI s National Pingtung University of Science and Technology, Department of Forestry -PPIHAS c Mycology Collection -PPIU s M. Utemisov Western Kazakhstanian State University, V. V. Ivanov Department of Botany -PPKMI c Plant Production Technology Department, Faculty of Agricultural Technology -PPKU1 c Department of Plant Pathology, Faculty of Agriculture, Thailand -PPKU2 c Department of Plant Pathology, Faculty of Agriculture, Thailand -PPKU3 c Department of Plant Pathology, Faculty of Agriculture, Thailand -PPKU4 c Department of Plant Pathology, Faculty of Agriculture, Thailand -PPKU5 c Department of Plant Pathology, Faculty of Agriculture, Thailand -PPKU6 c Department of Plant Pathology, Faculty of Agriculture, Thailand -PPL s Agricultural Development and Advisory Service, Harpenden Laboratory -PPNP s Point Pelee National Park -PPPO s Pusat Penelitian dan Pengembangan Oseanologi -PPPPB c ARC-Plant Protection Research Institute, Plant Pathogenic and Plant Protecting Bacteria -PPRI c ARC-Plant Protection Research Institute, National Collection of Fungi: Culture Collection -PPRL h USDA-ARS Poisonous Plant Research Lab -PPRZ s Plant Protection Research Institute -PPSIO s P. P. Shirshov Institute of Oceanology -PPU h Perm State Teacher Training University -PQFC b Phu Qui's Fruit Tree Center-Vietnam -PR s National Museum in Prague, Department of Botany -PRA s Institute of Botany, Academy of Sciences -PRB s Prague Botanical Garden -PRC s Charles University, Botany Department -PRE s National Botanical Institute - Pretoria -PREM s Plant Protection Research Institute, Biosystematics Division, Mycology Unit -PRF s South African Forestry Research Institute, Environment Affairs Department -PRG s Universidad Nacional Pedro Ruiz Gallo -PRH s Perthshire Society of Natural Science -PRI s College of Eastern Utah, Biology Department -PRICO s University of Puerto Rico -PRL c Prairie Regional Laboratory -PRM s National Museum, Mycological Department -PROIMI c Planta Piloto de Procesos Industriales Microbiologicos -PRU s University of Pretoria, Botany Department -PRV s Porvoo Museum of Natural History -PSAE s Alberta Environmental Centre -PSGB s University of Bradford, Pharmacy Department -PSK h Pskov State University -PSM s University of Puget Sound, James R. Slater Museum of Natural History -PSO s Universidad de Narino -PSP s Parasitic Seed Plants -PSS s Philosophical Society of Southampton -PSS s Paleontology and Stratigraphic Section of the Geological Institute of the Mongolian Academy of Sciences -PSU s Prince of Songkla University, Biology Department -PSU s Portland State University, Vertebrate Biology Museum +PGSC c Pseudomonas Genetic Stock Center +PH s Academy of Natural Sciences, Botany Department +PHA s Pharmaceutical Society of Great Britain +PHARM h Southern Cross University +PHBL c Philip Harris Biological Ltd. +PHEL s Plant Health and Environment Laboratory +PHEO h Karadag Natural Reserve +PHG s Peper Harow +PHH s University of Science, Ho Chi Minh City Vietnam National University +PHIL s University of the Sciences in Philadelphia, Biological Sciences Department +PI s Institut und Museum fuer Geologie und Palaeontologie +PI s Universita di Pisa, Dipartimento di Scienze Botaniche +PI s Paleontological Institute +PIAGR h University of Pisa +PICRC h Palau International Coral Reef Center +PIHG s Florida Department of Agriculture and Consumer Services +PIHU s Paleontological Institut of Helsingfors +PIKN s Koronivia Research Station +PIMUI s Palaeontologische Institut und Museum der Universitaet in Innsbruck +PIMUZ s Palaontologisches Institut und Museum der Universitat Zurich +PIN s Philosophical Institution of Newport +PIN s Paleontological Institute, Russian Academy of Sciences +PINN s Pinnacles National Monument +PIR c Bulgarian Research Culture Collection +PISR s Pechora-Ilych State Reserve, Russia +PIUU s Paleontological Institut, University of Uppsala +PKDC s Divisao de Museu de Historia Natural +PKM s V. G. Belinsk Pedagogical Institute of Penza +PL s Zapadoceske muzeum +PLAT h State University of New York, College at Plattsburgh +PLES h Plyos State Museum +PLFV s Principality of Liechtenstein +PLH s Plymouth City Museum and Art Gallery +PLP h Institute of Himalayan Bioresource Technology +PLU h Pacific Lutheran University +PLY sc Plymouth Institution and Athenaeum +PLYMOUTH c Plymouth Culture Collection +PLYP s University of Plymouth, Department of Biological Sciences +PM s Peabody Essex Museum, Natural History Department +PM s Pratt Museum +PM s Putnam Museum of History and Natural Science +PMA s Provincial Museum of Alberta +PMA s Universidad de Panama +PMAA s Palaeontological Collections, Provincial Museum and Achieves of Alberta +PMAE s Royal Alberta Museum +PMAG s Perth Museum and Art Gallery +PMAM s Beijing Natural History Museum +PMAU s Peterborough Museum and Art Gallery +PMB s Prirodnjacki Muzej Srpske Zemije +PMBC s Phuket Marine Biological Centre +PMFP s Papeete Museum +PMG s Horto Florestal +PMG s Paisley Museum of Geological Collection +PMH s City Museum and Records Office +PMHPS s Portsmouth Philosophical Society +PMHU s Palaontologisches Museum +PMIG s Phyletisches Museum +PMJ s Phyletisches Museum +PMK s Pugachev Regional Museum +PMK s Podunajske muzeum +PMNH s Pakistan Museum of Natural History +PMNH s Peabody Museum of Natural History +PMNH s Pratt Museum of Natural History +PMQ s Public Museum +PMR s Prirodoslovni muzej Rijeka +PMS s Prirodonamen Muzej Skopje +PMS s Pacific Marine Station +PMS s Peabody Essex Museum +PMSD s Pettigrew Museum +PMSL s Slovenian Museum of Natural History (Prirodosloveni Muzej Slovenije) +PMSP s Prefeitura do Municipio de Sao Paulo, Departamento de Parques e Areas Verdes +PMU s Paleontological Museum of Undory +PMU s Paleontological Museum of Uppsala +PMV s Provincial Museum +PNBG s University of the Philippines +PNCM-BIOTECH c Philippine National Collection of Microorganisms +PND h Dr. Shivaram Karantha Pilikula Nisarga Dhama +PNG s Division of Primary Industry +PNGM s National Museum and Art Gallery, Port Moresby +PNH s Philippine National Herbarium +PNICMM-INP s Instituto Nacional de la Pesca (Mexico) +PNL s Polytechnic of North London, Food and Biological Sciences Department +PNM s Philippine National Museum +PNPC s Chickasaw National Recreational Area [formerly Platt National Park] +PNZ s Penlee House Museum +PO s Universidade do Porto, Departamento de Botanica +PO s Collection of the Zoological Institute of the Russian Academy of Sciences +POFS s Forest Service, USDA +POKM s Penza Regional Local History Museum +POKM s Perm Regional Lore Museum +POL-F s Pollichia, Pfalzmuseum fur Naturkunde Thallichtenberg +POLL s Pfalzmuseum fuer Naturkunde +POM s Pomona College +POP s Tatranske muzeum v Poprade +POR s Universita degli Studi di Napoli +PORE s Point Reyes National Seashore +PORT s BioCentro-UNELLEZ +PORUN s Universita degli Studi di Napoli, Dip Ar Bo Pa Ve - Sezione Botanica +POZ s Adam Mickiewicz University, Department of Plant Taxonomy +POZG s Adam Mickiewicz University, Department of Geobotany +POZM s Adam Mickiewicz University, Department of Plant Ecology and Environment Protection +POZNB s Agricultural Academy, Botany Department +POZW s Adam Mickiewicz University +PPC h Palawan State University +PPCC c Plant Pathology Culture Collection +PPCC s Plant Protection Centre Collection +PPCD s West Virginia Department of Agriculture +PPDD s Ministry of Agriculture +PPFI s Pakistan Forest Institute +PPHM s Panhandle-Plains Historical Museum +PPI s National Pingtung University of Science and Technology, Department of Forestry +PPIHAS c Plant Protection Institute, Centre for Agricultural Research, Hungarian Academy of Sciences PPIHAS +PPIU s M. Utemisov Western Kazakhstanian State University, V. V. Ivanov Department of Botany +PPKMI c Plant Production Technology Department, Faculty of Agricultural Technology +PPKU1 c Department of Plant Pathology, Faculty of Agriculture, Thailand +PPKU2 c Department of Plant Pathology, Faculty of Agriculture, Thailand +PPKU3 c Department of Plant Pathology, Faculty of Agriculture, Thailand +PPKU4 c Department of Plant Pathology, Faculty of Agriculture, Thailand +PPKU5 c Department of Plant Pathology, Faculty of Agriculture, Thailand +PPKU6 c Department of Plant Pathology, Faculty of Agriculture, Thailand +PPL s Agricultural Development and Advisory Service, Harpenden Laboratory +PPNP s Point Pelee National Park +PPPO s Pusat Penelitian dan Pengembangan Oseanologi +PPPPB c ARC-Plant Protection Research Institute, Plant Pathogenic and Plant Protecting Bacteria +PPRI c ARC-Plant Protection Research, National Collection of Fungi: Culture Collection +PPRL h USDA-ARS Poisonous Plant Research Lab +PPRZ s Plant Protection Research Institute +PPSIO s P. P. Shirshov Institute of Oceanology +PPU h Perm State Teacher Training University +PQFC b Phu Qui's Fruit Tree Center-Vietnam +PR s National Museum in Prague, Department of Botany +PRA s Institute of Botany, Academy of Sciences +PRB s Prague Botanical Garden +PRC s Charles University, Botany Department +PRE s National Botanical Institute - Pretoria +PREM s South African National Collection of Fungi Herbarium +PRF s South African Forestry Research Institute, Environment Affairs Department +PRG s Universidad Nacional Pedro Ruiz Gallo +PRH s Perthshire Society of Natural Science +PRI s College of Eastern Utah, Biology Department +PRICO s University of Puerto Rico +PRL c Prairie Regional Laboratory +PRM s National Museum, Mycological Department +PROIMI c Planta Piloto de Procesos Industriales Microbiologicos +PRU s University of Pretoria, Botany Department +PRV s Porvoo Museum of Natural History +PSAE s Alberta Environmental Centre +PSGB s University of Bradford, Pharmacy Department +PSK h Pskov State University +PSM s University of Puget Sound, James R. Slater Museum of Natural History +PSO s Universidad de Narino +PSP s Parasitic Seed Plants +PSS s Philosophical Society of Southampton +PSS s Paleontology and Stratigraphic Section of the Geological Institute of the Mongolian Academy of Sciences +PSU s Prince of Songkla University, Biology Department +PSU s Portland State University, Vertebrate Biology Museum PSU:Mamm s Portland State University, Vertebrate Biology Museum, Mammal Collection -PSU s Pennsylvania State University -PSUB s University of Botswana -PSUC s Frost Entomological Museum -PSUMC s Pittsburg State University -PSY s Paisley Museum -PTBG s National Tropical Botanical Garden -PTCC c Pakistan Type Culture Collections -PTCCI c Persian Type Culture Collection -PTH s Perth Museum and Art Gallery, Herbarium -PTHL s Literary and Antiquarian Society of Perth -PTIS s Potato Introduction Station -PTN s Ellesmere Chambers -PTTC c Pranakorn Teacher Training College, Department of Biology, Faculty of Science and Technology -PTZ s Karelian Scientific Centre, Russian Academy of Sciences -PU s Princeton University -PU-HI s Department of Palaeontology, Universidad Complutense of Madrid -PUA s Pacific Union College, Biology Department -PUC s Beijing University -PUC s North-West University -PUCMNH s Pacific Union College, Museum of Natural History -PUCP s Punjab University -PUH s University of the Philippines, Institute of Biology -PUL s Purdue University, Department of Botany and Plant Pathology -PUM s Universita DI Pisa -PUN s Punjabi University, Botany Department -PUO s Portland University -PUP s University of Peshawar, Botany Department -PUR s Purdue University, Department of Botany and Plant Pathology -PURC s Purdue University -PUS s Puslinch House -PUSC s University of Southern Colorado, Life Sciences Department -PVB h Institute of Ecology of the Volga River Basin, Russian Academy of Science -PVF c Pusat Veterinaria Farma -PVGB c Plant Virus GenBank -PVHR s Universite Paris VI -PVL s Paleontologia de Vertebrados Lillo -PVNH s ORSTOM -PVPH s Paleontolga de Vertebrados -PVSJ s Museo do Ciencias Naturles -PW s Paleontological Collections -PWRC s Patuxent Wildlife Research Center -PWU h V.G.Korolenko Poltava National Pedagogical University -PY s Centro de Estudios y Colecciones Biologicas para la Conservacion -PYCC c Portuguese Yeast Culture Collection -PYU s Yunnan University, Laboratory of Pteridophyta -PZL s Penzance Library -PZV s Petrozavodsk State University, Department of Botany and Plant Physiology -Q s Universidad Central -QAME s Direccion Nacional Forestal, Ministerio de Agricultura y Ganaderia -QAP s Universidad Central -QBG s Queen Sirikit Botanic Garden -QC s National Museum of Natural History, Bulawayo -QCA s Pontificia Universidad Catolica del Ecuador, Departamento de Biologia -QCAZ s Museo de Zoologia, Pontifica Universidad Catolica del Ecuador +PSU s Pennsylvania State University +PSUB s University of Botswana +PSUC s Frost Entomological Museum +PSUMC s Pittsburg State University +PSY s Paisley Museum +PTBG s National Tropical Botanical Garden +PTCC c Pakistan Type Culture Collections +PTCCI c Persian Type Culture Collection +PTH s Perth Museum and Art Gallery, Herbarium PER +PTHL s Literary and Antiquarian Society of Perth +PTIS s Potato Introduction Station +PTN s Ellesmere Chambers +PTTC c Pranakorn Teacher Training College, Department of Biology, Faculty of Science and Technology +PTZ s Karelian Scientific Centre, Russian Academy of Sciences +PU s Princeton University +PU-HI s Department of Palaeontology, Universidad Complutense of Madrid +PUA s Pacific Union College, Biology Department +PUC s Beijing University +PUC s North-West University +PUCMNH s Pacific Union College, Museum of Natural History +PUCP s Punjab University +PUH s University of the Philippines, Institute of Biology +PUL s Purdue University, Department of Botany and Plant Pathology +PUM s Universita DI Pisa +PUN s Punjabi University, Botany Department +PUO s Portland University +PUP s University of Peshawar, Botany Department +PUR s Purdue University, Department of Botany and Plant Pathology +PURC s Purdue University +PUS s Puslinch House +PUSC s University of Southern Colorado, Life Sciences Department +PVB h Institute of Ecology of the Volga River Basin, Russian Academy of Science +PVF c Pusat Veterinaria Farma +PVGB c Plant Virus GenBank +PVHR s Universite Paris VI +PVL s Paleontologia de Vertebrados Lillo +PVNH s ORSTOM +PVPH s Paleontolga de Vertebrados +PVSJ s Museo do Ciencias Naturles +PW s Paleontological Collections +PWRC s Patuxent Wildlife Research Center +PWU h V.G.Korolenko Poltava National Pedagogical University +PY s Centro de Estudios y Colecciones Biologicas para la Conservacion +PYCC c Portuguese Yeast Culture Collection +PYU s Yunnan University, Laboratory of Pteridophyta +PZL s Penzance Library +PZV s Petrozavodsk State University, Department of Botany and Plant Physiology +Q s Universidad Central +QAME s Direccion Nacional Forestal, Ministerio de Agricultura y Ganaderia +QAP s Universidad Central +QBG s Queen Sirikit Botanic Garden +QC s National Museum of Natural History, Bulawayo +QCA s Pontificia Universidad Catolica del Ecuador, Departamento de Biologia +QCAZ s Museo de Zoologia, Pontifica Universidad Catolica del Ecuador QCAZ:A s Museo de Zoologia, Pontifica Universidad Catolica del Ecuador, Amphibian Collection QCAZ:R s Museo de Zoologia, Pontifica Universidad Catolica del Ecuador, Reptile Collection -QCNE s Herbario Nacional del Ecuador -QD s Ocean University of China -QDC s Qinghai Institute for Drug Control -QDPC s Queensland Department of Primary Industries -QDPI s Queensland Department of Primary Industries -QEF s Universite Laval, Laboratoire d'ecologie forestiere -QF s Institute of Forestry -QFA s Universite Laval -QFB s Laurentian Forestry Centre, Canadian Forest Service -QFBE s Laurentian Forestry Centre, Canadian Forest Service -QFMQ s Queenstown Museum -QFS s Universite Laval -QG s General Grassland Station of Qinghai -QIBX s Qinghai Institute of Biology -QIMR s Queensland Institute of Medical Research -QK s Queen's University, Biology Department -QM s Queensland Museum -QM s U.S. Army Natick Research and Development Center -QM s Queen Victoria Museum -QMB s Queensland Museum, Brisbane -QMC s Queen Mary College -QMEX s Universidad Autonoma de Queretaro, Centro Universitario -QMOR s Collection Entomologique Ouellet-Robert -QMP s Musee du Quebec -QPAR s Ministere du Tourisme de la Chasse et de la Peche du Quebec, Laboratoire de Recherches -QPH s Seminaire de Quebec -QPIM s Department of Primary Industries -QPLS s Biblioteca Ecuatoriana Aurelio Espinosa Polit -QPNRA s Programa Nacional de Regionalizacion, Ministerio de Agricultura y Ganaderia, Departamento de Ecologia -QRS s Australian National Herbarium, Division of Plant Industry, CSIRO -QSA s Institut de technologie agroalimentaire -QTC s Qiqihar Teachers College, Biology Department -QUA s Qinghai University, Agriculture Department -QUC s Universite Laval, Departement de biologie -QUE s Complexe scientifique -QUSF s Universidad San Francisco de Quito, Biology Department -QVG s Queen Victoria Museum -QVM s Queen Victoria Museum -QVMS s Queen Victoria Memorial Museum -QWA s University of the North, Qwa Qwa Campus -QYTC s Qingyang Teachers College, Biology Department -R s Universidade Federal do Rio de Janeiro, Departamento de Botanica -R s Departamento de Geologia, Universidad de Chile -RAB s Institut Scientifique, Departement de Botanique et d'Ecologie Vegetale -RAF s Myanmar Forest Herbarium -RAM s Ramsey Public Library -RAME s Royal Albert Memorial Museum -RAMK s Ramkhamhaeng University, Biology Department -RAMM s Royal Albert Memorial Museum, Leisure and Tourism Department -RANG s Yangon University -RANK h Research Center of Agriculture and Natural Resources of Kermanshah province -RARS s Regina Research Station -RAS s Union of Burma Applied Research Institute, Pharmaceutical Department -RAU s Laboratoire de Biologie Vegetale -RAW s Pakistan Agricultural Research Council -RB s Jardim Botanico do Rio de Janeiro -RBCM s Royal British Columbia Museum +QCC c Qatari Culture Collection +QCNE s Herbario Nacional del Ecuador +QD s Ocean University of China +QDC s Qinghai Institute for Drug Control +QDPC s Queensland Department of Primary Industries +QDPI s Queensland Department of Primary Industries +QEF s Universite Laval, Laboratoire d'ecologie forestiere +QF s Institute of Forestry +QFA s Universite Laval +QFB s Laurentian Forestry Centre, Canadian Forest Service +QFBE s Laurentian Forestry Centre, Canadian Forest Service +QFMQ s Queenstown Museum +QFS s Universite Laval +QG s General Grassland Station of Qinghai +QIBX s Qinghai Institute of Biology +QIMR s Queensland Institute of Medical Research +QK s Queen's University, Biology Department +QM s Queensland Museum +QM s U.S. Army Natick Research and Development Center +QM s Queen Victoria Museum +QMB s Queensland Museum, Brisbane +QMC s Queen Mary College +QMEX s Universidad Autonoma de Queretaro, Centro Universitario +QMOR s Collection Entomologique Ouellet-Robert +QMP s Musee du Quebec +QPAR s Ministere du Tourisme de la Chasse et de la Peche du Quebec, Laboratoire de Recherches +QPH s Seminaire de Quebec +QPIM s Department of Primary Industries +QPLS s Biblioteca Ecuatoriana Aurelio Espinosa Polit +QPNRA s Programa Nacional de Regionalizacion, Ministerio de Agricultura y Ganaderia, Departamento de Ecologia +QRS s Australian National Herbarium, Division of Plant Industry, CSIRO +QSA s Institut de technologie agroalimentaire +QSMI s Queen Saovabha Memorial Institute +QTC s Qiqihar Teachers College, Biology Department +QUA s Qinghai University, Agriculture Department +QUC s Universite Laval, Departement de biologie +QUE s Complexe scientifique +QUSF s Universidad San Francisco de Quito, Biology Department +QVG s Queen Victoria Museum +QVM s Queen Victoria Museum +QVMS s Queen Victoria Memorial Museum +QWA s University of the North, Qwa Qwa Campus +QYTC s Qingyang Teachers College, Biology Department +R s Universidade Federal do Rio de Janeiro, Departamento de Botanica +R s Departamento de Geologia, Universidad de Chile +RAB s Institut Scientifique, Departement de Botanique et d'Ecologie Vegetale +RAF s Myanmar Forest Herbarium +RAM s Ramsey Public Library +RAM s Royal Alberta Museum +RAME s Royal Albert Memorial Museum +RAMK s Ramkhamhaeng University, Biology Department +RAMM s Royal Albert Memorial Museum, Leisure and Tourism Department +RANG s Yangon University +RANK h Research Center of Agriculture and Natural Resources of Kermanshah province +RARS s Regina Research Station +RAS s Union of Burma Applied Research Institute, Pharmaceutical Department +RAU s Laboratoire de Biologie Vegetale +RAW s Pakistan Agricultural Research Council +RB s Jardim Botanico do Rio de Janeiro +RBCM s Royal British Columbia Museum RBCM:Mamm s Royal British Columbia Museum, Mammal Collection -RBE s Universidade Federal Rural do Rio de Janeiro -RBF c Raiffeisen Bioforschung -RBINS s Royal Belgian Institute of Natural Sciences -RBR s Universidade Federal Rural do Rio de Janeiro, Departamento de Botanica -RBS s Royal Botanic Society -RBY s East Divisional Library -RCAM s Rutgers University, Biology Department -RCAT c Regional Collection of Animal Viruses and Tissue Cultures -RCB c RIKEN Cell Bank -RCC c Roscoff Culture Collection -RCDM c Republican Centre for Deposition of Microorganisms of the National Academy of Sciences and Ministry of Education and Science of Armenia -RCHM s Rochdale Museum Service -RCHP s Rochdale Equitable Pioneers' Memorial Museum -RCMC s Rockford College -RCN s Richmond Naturalists' Field Club -RCR s Rochester Public Museum -RCS s Royal College of Surgeons -RCSL s Royal College of Surgeons -RCVC h Universidad Nacional de Rio Cuarto -RDAF s Research Department South East Asian Fisheries Development Centre -RDG s Reading Museum and Archive Service -RDS s Royal Dublin Society -RE s Liaoning Reed Science Institute -RED s University of Redlands, Biology Department -REDM s Reading Museum and Archive Service -REED h Reed College -REG s Universitaet Regensburg, Regensburgische Botanische Gesellschaft -REGGIO h Universita Mediterranea di Reggio Calabria -RELC s INIFAP-SAGAR -REN s Campus Scientifique de Beaulieu, Laboratoire de Botanique -RENO s University of Nevada, Environmental and Resource Sciences Department -RENZ s Universitaet Basel, The Swiss Orchid Foundation -REP s Desert Experiment Station of the W.I.R. -RESC s Shasta College -REU s Universite de la Reunion -RFA s Universidade Federal do Rio de Janeiro, Departamento de Botanica -RFE s Radcliffe Literary and Scientific Society Museum -RFFP h Universidade do Estado do Rio de Janeiro -RFNS s Rochdale Field Naturalists' Society -RGM s Nationaal Natuurhistorisch Museum Leiden -RGMC s Musee Royal de l'Afrique Centrale -RGY s Rugby School Natural History Society Museum -Rh-EF s Museum of Grannat -RHK h St. Berchmans College -RHLCY s Reservoir of Heilongtan -RHM s Public Reference Library -RHMC s Red House Museum -RHMD s National Institute of Science Communication -RHMU c Department of Pathology, Faculty of Medical Science, Ramathibordi Hospital -RHS c Plant Pathology, The Royal Horticultural Society -RHT s St. Joseph's College -RI s Rudjer Boskovic Institute -RIA c The Russia Research Institute for Antibiotics Culture Collection -RIB c National Research Institute of Brewing, Tax Administration Agency -RIBM c Research Institute for Brewing and Malting -RICK s Brigham Young University - Idaho, Department of Biology -RICP c Crop Research Institute -RIFAV b Research Institute for Fruits and Vegetables -RIFFL s Research Institute of Freshwater Fisheries -RIFY c Institute of Enology and Viticulture, Yamanashi University -RIG s University of Latvia, Department of Botany and Ecology -RIGB s Latvian State Center of Plant Protection -RIGG s University of Latvia -RIM s L'Ecole d'Agriculture -RIMD c Research Institute for Microbial Diseases, Research Center for Emerging Infectious Diseases -RIN s Research Institute for Nature Management, Botany Department -RIOC s Universidad Nacional de Rio Cuarto -RIPO c Plant Virus Collection -RITFC c Research Institute for Tobacco and Fibre Crops -RIVE c Research Institute for Viticulture and Enology -RIVE s University of Wisconsin, Biology Department -RIY s National Agriculture and Water Research Center -RIZ s Instituto de Zootecnia -RKT h Regional Research Institute (Ayurveda) -RLS s Royal Latin School -RM s McGill University, Redpath Museum -RM c Rumen Microorganisms -RM s Raffles Museum -RM s University of Wyoming Herbarium -RMA c R. M. Alden Research Lab -RMBL s Rocky Mountain Biological Laboratory -RMBR s Raffles Museum of Biodiversity Research -RMCA s Royal Museum for Central Africa -RMDRC s Rocky Mountain Dinosaur Resource Center -RMF c Rocky Mountain Herbarium, Fungi -RMFM s Richmond Marine Fossils Museum -RMNH s Naturalis Biodiversity Center +RBE s Universidade Federal Rural do Rio de Janeiro +RBF c Raiffeisen Bioforschung +RBINS s Royal Belgian Institute of Natural Sciences +RBR s Universidade Federal Rural do Rio de Janeiro, Departamento de Botanica +RBS s Royal Botanic Society +RBY s East Divisional Library +RCAM s Rutgers University, Biology Department +RCAT c Regional Collection of Animal Viruses and Tissue Cultures +RCB c RIKEN Cell Bank +RCC c Roscoff Culture Collection +RCDM c Republican Centre for Deposition of Microorganisms of the National Academy of Sciences and Ministry of Education and Science of Armenia +RCHM s Rochdale Museum Service +RCHP s Rochdale Equitable Pioneers' Memorial Museum +RCMC s Rockford College +RCN s Richmond Naturalists' Field Club +RCR s Rochester Public Museum +RCS s Royal College of Surgeon's Museum RCSM +RCSL s Royal College of Surgeons +RCVC h Universidad Nacional de Rio Cuarto +RDAF s Research Department South East Asian Fisheries Development Centre +RDG s Reading Museum and Archive Service +RDS s Royal Dublin Society +RE s Liaoning Reed Science Institute +RED s University of Redlands, Biology Department +REDM s Reading Museum and Archive Service +REED h Reed College +REG s Universitaet Regensburg, Regensburgische Botanische Gesellschaft +REGGIO h Universita Mediterranea di Reggio Calabria +RELC s INIFAP-SAGAR +REN s Campus Scientifique de Beaulieu, Laboratoire de Botanique +RENO s University of Nevada, Environmental and Resource Sciences Department +RENZ s Universitaet Basel, The Swiss Orchid Foundation +REP s Desert Experiment Station of the W.I.R. +RESC s Shasta College +RET s Herbarium Amanitarum Rooseveltensis +REU s Universite de la Reunion +RFA s Universidade Federal do Rio de Janeiro, Departamento de Botanica +RFE s Radcliffe Literary and Scientific Society Museum +RFFP h Universidade do Estado do Rio de Janeiro +RFNS s Rochdale Field Naturalists' Society +RGM s Nationaal Natuurhistorisch Museum Leiden +RGMC s Musee Royal de l'Afrique Centrale +RGY s Rugby School Natural History Society Museum +Rh-EF s Museum of Grannat +RHK h St. Berchmans College +RHLCY s Reservoir of Heilongtan +RHM s Public Reference Library +RHMC s Red House Museum +RHMD s National Institute of Science Communication +RHMU c Department of Pathology, Faculty of Medical Science, Ramathibordi Hospital +RHS c Plant Pathology, The Royal Horticultural Society +RHT s St. Joseph's College +RI s Rudjer Boskovic Institute +RIA c The Russia Research Institute for Antibiotics Culture Collection +RIB c National Research Institute of Brewing, Tax Administration Agency +RIBM c Research Institute for Brewing and Malting +RICK s Brigham Young University - Idaho, Department of Biology +RICP c Crop Research Institute +RIFAV b Research Institute for Fruits and Vegetables +RIFFL s Research Institute of Freshwater Fisheries +RIFY c Institute of Enology and Viticulture, Yamanashi University +RIG s University of Latvia, Department of Botany and Ecology +RIGB s Latvian State Center of Plant Protection +RIGG s University of Latvia +RIM s L'Ecole d'Agriculture +RIMD c Research Institute for Microbial Diseases, Research Center for Emerging Infectious Diseases +RIN s Research Institute for Nature Management, Botany Department +RIOC s Universidad Nacional de Rio Cuarto +RIPO c Plant Virus Collection +RITFC c Research Institute for Tobacco and Fibre Crops +RIVE c Research Institute for Viticulture and Enology +RIVE s University of Wisconsin, Biology Department +RIY s National Agriculture and Water Research Center +RIZ s Instituto de Zootecnia +RKT h Regional Research Institute (Ayurveda) +RLS s Royal Latin School +RM s McGill University, Redpath Museum +RM c Rumen Microorganisms +RM s Raffles Museum +RM s University of Wyoming Herbarium +RMA c R. M. Alden Research Lab +RMBL s Rocky Mountain Biological Laboratory +RMBR s Raffles Museum of Biodiversity Research +RMCA s Royal Museum for Central Africa +RMDRC s Rocky Mountain Dinosaur Resource Center +RMF c Rocky Mountain Herbarium, Fungi +RMFM s Richmond Marine Fossils Museum +RMNH s Naturalis Biodiversity Center RMNH:ACA s Naturalis Biodiversity Center, Acari collection RMNH:AVES s Naturalis Biodiversity Center, bird collection RMNH:BRA s Naturalis Biodiversity Center, brachiopod collection @@ -5514,229 +5565,231 @@ RMNH:MAM s Naturalis Biodiversity Center, Mammal collection RMNH:MOL s Naturalis Biodiversity Center, mollusc collection RMNH:PISC s Naturalis Biodiversity Center, fish collection RMNH:POR s Naturalis Biodiversity Center, poriferan collection -RMNHD s Naturalis Biodiversity Center -RMNP s Riding Mountain National Park -RMRC b Regional Medical Research Centre -RMS s University of Wyoming Herbarium -RMSC s Rocky Mountain Forest and Range Experiment Station -RMSCC c Roche Molecular Systems Culture Collection -RMTV h University of Rome Tor Vergata -RMWC s Randolph-Macon Woman's College, Biology Department -RNG s University of Reading -RNMUT s Republic Nature Museum of Uzbekistan -RO s Universita degli Studi di Roma La Sapienza, Dipartimento di Biologia Vegetale -ROAN s Virginia Western Community College, Biology Department -ROCH s Rochester Academy of Science -ROHB s Cattedra di Micologia, Dipartimento di Biologia Vegetale -ROIG s Estacion Experimental de Plantas Medicinales Dr. Juan T. Roig -ROM s Royal Ontario Museum +RMNHD s Naturalis Biodiversity Center +RMNP s Riding Mountain National Park +RMRC b Regional Medical Research Centre +RMS s University of Wyoming Herbarium +RMSC s Rocky Mountain Forest and Range Experiment Station +RMSCC c Roche Molecular Systems Culture Collection +RMTV h University of Rome Tor Vergata +RMWC s Randolph-Macon Woman's College, Biology Department +RNG s University of Reading +RNMUT s Republic Nature Museum of Uzbekistan +RO s Universita degli Studi di Roma La Sapienza, Dipartimento di Biologia Vegetale +ROAN s Virginia Western Community College, Biology Department +ROCH s Rochester Academy of Science +ROHB s Cattedra di Micologia, Dipartimento di Biologia Vegetale +ROIG s Estacion Experimental de Plantas Medicinales Dr. Juan T. Roig +ROM s Royal Ontario Museum ROM:ENT s Royal Ontario Museum, Entomology collection ROM:HERP s Royal Ontario Museum, Herpetology collection ROM:ICH s Royal Ontario Museum, Fish collection ROM:IZ s Royal Ontario Museum, Invertebrate Zoology Collection ROM:MAM s Royal Ontario Museum, Mammal Collection ROM:ORN s Royal Ontario Museum, Ornithology Collection -ROME s Royal Ontario Museum, Entomology Collection -ROML s National University of Lesotho, Biology Department -ROMO s Rocky Mountain National Park -RON h Universidade Federal de Rondonia -ROO s Agricultural Research Council-Range and Forage Institute -ROPA s Sonoma State University, Biology Department -ROPV s Istituto Sperimentale per la Patologia Vegetale -ROST s Universitaet Rostock -ROV s Museo Civico di Rovereto -ROZ s Stredoceske muzeum -RPM s Reading Public Museum -RPMH s Roemer Pelizaeus Museum Hildesheim -RPN s Ripon Mechanics Institute -RPPMC s Rondeau Provincial Park -RPPR s Internationl Institute of Tropical Forestry -RPSC s Rio Palenque Science Center -RPSP s Universidade de Sao Paulo -RPTN s Repton School, Biology Department -RRCBI s Regional Research Centre (Ay.) -RRIASR c Fungal Pathogens of Hevea Rubber in Sri Lanka -RRJ c RRL , Jammu INDIA -RRLB s Regional Research Laboratory -RRLH s Regional Research Laboratory -RSA s Rancho Santa Ana Botanic Garden -RSCS c Medical Culture Collection -RSDR s Desert Institute, Turkmenistan Academy of Sciences -RSKK c Refik Saydam National Type Culture Collection-RSKK -RSM s Royal Saskatchewan Museum -RSM s Royal Scottish Museum -RSU h Ryazan State University -RSY s Buteshire Natural History Society, The Museum -RTE s Holmesdale Natural History Club Museum -RTHM s Munidipal Museum and Art Gallery -RTMP s Royal Tyrell Museum of Paleontology -RU s University of Reading, Agricultural Botany Department -RUBL s University of Rajasthan, Botany Department -RUDZ s Rhodes University -RUEB s Eidgenoessische Technische Hochschule ETH -RUH s Rhodes University, Botany Department -RUHV s Radford University, Biology Department -RUIC s Rutgers University -RUMF s University Museum, University of the Ryukyus -RUNYON s Robert Runyon Herbarium -RUPP h Royal University of Phnom Penh -RUSI s J.L.B. Smith Institute of Ichthyology (formerly of Rhodes University) -RUSU s Universidade Santa Ursula -RUT s Douglass College, Rutgers University, Biological Sciences Department -RUTPP s Cook College, Rutgers University, Plant Pathology Department -RUY s Mid-Staffordshire Field Club -RV c Collection of Leptospira Strains -RV s Molotov State University of Rostov, Botany Department -RVP s Museo Provincial de Historia Natural de La Pampa (Argentina) -RWBG s Rostov State University -RWC s State University of New York, Roosevelt Wildlife Collection -RWDN s University of Glasgow Field Station -RWPM s Roger Williams Park Museum of Natural History -RYCC c Roseworthy Yeast Culture Collection -RYD s School of Art -RYU s University of the Ryukyus, Biology Department -S s Swedish Museum of Natural History, Botany Departments -SA s Museum national d'Histoire Naturelle, Laboratiore de Paleontologie -SAAR s Zentrum fuer Biodokumentation des Saarlandes -SAAS s Saasveld, Port Elizabeth Technikon -SAB s Society of Amateur Botanists -SACA s South-west Agricultural University -SACC s St. Ambrose College -SACL s Santa Clara University, Biology Department -SACON s Salim Ali Centre for Ornithology and Natural History -SACS s Shenyang Agricultural College -SACT s California State University, Biological Sciences Department -SAF h Department of Agricultural and Forest Sciences -SAFB s University of Saskatchewan, Forestry Department -SAFU s University of San Francisco -SAG c Sammlung von Algenkulturen at Universitat Gottingen -SAG c Coleccion de Micoligica Laboratorio Regional, Servicio Agricola y Ganadero -SAIAB sb South African Institute of Aquatic Biodiversity -SAIM s South African Institute for Medical Research -SAIMR s South African Institute for Medical Research -SAITP c School of Pharmacy and Medical Sciences, University of South Australia -SAK s Institute of Marine Geology and Geophysics, Far East Branch, Island Ecological Problems Department -SAKH s Sakhalin Botanical Garden -SAL s Kansas Wesleyan University, Biology Department -SALA s Universidad de Salamanca, Departamento de Botanica -SALAF s Universidad de Salamanca -SALF s Salford Royal Free Museum and Library -SALFM s Salford Natural History Museum, Salford City Council -SALLE s Instituto Geobiologico La Salle -SAM s South African Museum -SAMA sb South Australian Museum -SAMC s Iziko Museum of Capetown -SAMF h Samford University -SAMU s Savaria Museum, Department of Natural History -SAN s Forest Research Centre, Forest Department -SANBI s South African National Biodiversity Institute -SANC s South African National Collection of Insects -SANT s Universidad de Santiago de Compostela +ROME s Royal Ontario Museum, Entomology Collection ROM:ENT +ROML s National University of Lesotho, Biology Department +ROMO s Rocky Mountain National Park +RON h Universidade Federal de Rondonia +ROO s Agricultural Research Council-Range and Forage Institute +ROPA s Sonoma State University, Biology Department +ROPV s Istituto Sperimentale per la Patologia Vegetale +ROST s Universitaet Rostock +ROV s Museo Civico di Rovereto +ROZ s Stredoceske muzeum +RPM s Reading Public Museum +RPMH s Roemer Pelizaeus Museum Hildesheim +RPN s Ripon Mechanics Institute +RPPMC s Rondeau Provincial Park +RPPR s Internationl Institute of Tropical Forestry +RPSC s Rio Palenque Science Center +RPSP s Universidade de Sao Paulo +RPTN s Repton School, Biology Department +RRCBI s Regional Research Centre (Ay.) +RRIASR c Fungal Pathogens of Hevea Rubber in Sri Lanka +RRJ c RRL , Jammu INDIA +RRLB s Regional Research Laboratory +RRLH s Regional Research Laboratory +RSA s Rancho Santa Ana Botanic Garden +RSCS c Medical Culture Collection +RSDR s Desert Institute, Turkmenistan Academy of Sciences +RSKK c Refik Saydam National Type Culture Collection-RSKK +RSM s Royal Saskatchewan Museum SMNH +RSM s Royal Scottish Museum NMSZ,RSME +RSU h Ryazan State University +RSY s Buteshire Natural History Society, The Museum +RTE s Holmesdale Natural History Club Museum +RTHM s Munidipal Museum and Art Gallery +RTMP s Royal Tyrell Museum of Paleontology +RU s University of Reading, Agricultural Botany Department +RUBL s University of Rajasthan, Botany Department +RUDZ s Rhodes University +RUEB s Eidgenoessische Technische Hochschule ETH +RUH s Rhodes University, Botany Department +RUHV s Radford University, Biology Department +RUIC s Rutgers University +RUMF s University Museum, University of the Ryukyus +RUNYON s Robert Runyon Herbarium +RUPP h Royal University of Phnom Penh +RUSI s J.L.B. Smith Institute of Ichthyology (formerly of Rhodes University) +RUSU s Universidade Santa Ursula +RUT s Douglass College, Rutgers University, Biological Sciences Department +RUTPP s Cook College, Rutgers University, Plant Pathology Department +RUY s Mid-Staffordshire Field Club +RV c Collection of Leptospira Strains +RV s Molotov State University of Rostov, Botany Department +RVP s Museo Provincial de Historia Natural de La Pampa (Argentina) +RWBG s Rostov State University +RWC s State University of New York, Roosevelt Wildlife Collection +RWDN s University of Glasgow Field Station +RWPM s Roger Williams Park Museum of Natural History +RYCC c Roseworthy Yeast Culture Collection +RYD s School of Art +RYU s University of the Ryukyus, Biology Department +S s Swedish Museum of Natural History, Botany Departments +SA s Museum national d'Histoire Naturelle, Laboratiore de Paleontologie +SAAR s Zentrum fuer Biodokumentation des Saarlandes +SAAS s Saasveld, Port Elizabeth Technikon +SAB s Society of Amateur Botanists +SACA s South-west Agricultural University +SACC s St. Ambrose College +SACL s Santa Clara University, Biology Department +SACON s Salim Ali Centre for Ornithology and Natural History +SACS s Shenyang Agricultural College +SACT s California State University, Biological Sciences Department +SAF h Department of Agricultural and Forest Sciences +SAFB s University of Saskatchewan, Forestry Department +SAFU s University of San Francisco +SAG c Sammlung von Algenkulturen at Universitat Gottingen +SAG c Coleccion de Micoligica Laboratorio Regional, Servicio Agricola y Ganadero +SAIAB sb South African Institute of Aquatic Biodiversity +SAIM s South African Institute for Medical Research +SAIMR s South African Institute for Medical Research +SAITP c School of Pharmacy and Medical Sciences, University of South Australia +SAK s Institute of Marine Geology and Geophysics, Far East Branch, Island Ecological Problems Department +SAKH s Sakhalin Botanical Garden +SAL s Kansas Wesleyan University, Biology Department +SALA s Universidad de Salamanca, Departamento de Botanica +SALAF s Universidad de Salamanca +SALF s Salford Royal Free Museum and Library +SALFM s Salford Natural History Museum, Salford City Council +SALLE s Instituto Geobiologico La Salle +SAM s South African Museum SAMK +SAMA sb South Australian Museum SAM +SAMC s Iziko Museum of Capetown +SAMF h Samford University +SAMU s Savaria Museum, Department of Natural History +SAN s Forest Research Centre, Forest Department +SANBI s South African National Biodiversity Institute +SANC s South African National Collection of Insects NCIP +SANT s Universidad de Santiago de Compostela SANT:Algae s Universidad de Santiago de Compostela, algae collection SANT:Bryo s Universidad de Santiago de Compostela, bryophyte collection SANT:Lich s Universidad de Santiago de Compostela, lichen collection -SANU s Shaanxi Normal University, Biology Department -SAO s Sammlung Oberli -SAP s Herbarium of Graduate School of Science, Hokkaido University -SAPA s Hokkaido University Museum (Fungal collection) -SAPCL s St. Andrews Presbyterian College, Biology Department -SAPS s Hokkaido University Museum (Plant collection) -SAPT h Hokkaido University Botanic Garden -SAR s Department of Forestry -SARA s Zemaljski Muzej Bosne I. Herzegovine -SARAT s Department of Morphology and Systematic Botany -SARBG h Saratov State University Botanical Garden -SARC s Roanoke College, Biology Department -SARI s Sakarya Agricultural Research Institute -SAS s Sammlung Arnhardt des Museums Schloss Wilhelmsburg Schmalkalden -SASK s University of Saskatchewan, Plant Sciences Department -SASSA s Universita di Sassari, Dipartimento di Scienze del Farmaco -SASSC b SENDAI Arabidopsis Seed Stock Center -SASY s Institute for Biological Problems of Cryolithozone -SAT s Angelo State University, Biology Department -SAU s Sichuan Agricultural University, Department of Basic Courses -SAU s Southern Arkansas University -SAUF s Sichuan Agricultural University, Forestry Department -SAUT s Sichuan Agricultural University -SAV s Institute of Botany, Slovak Academy of Sciences -SAWV s Salem International University, Department of Bioscience -SB s Saint Bernard Abbey -SBBG s Santa Barbara Botanic Garden -SBC s University of California, Biological Sciences Department -SBCC s Santa Barbara City College, Department of Biological Sciences -SBCM s San Bernardino County Museum -SBDE s Sino-Belgian Dinosaur expedition -SBG s Botanical Garden of Stavropol State University, Botany Department -SBH s S Blair Hedges Collection -SBKA s Stiftssammlungen des Benediktinerstiftskrems-Munster -SBM s Sabah Museum -SBM s Santa Barbara Museum of Natural History -SBMN s Santa Barbara Museum of Natural History -SBMNH s Santa Barbara Museum of Natural History -SBNHM s Santa Barbara Natural History Museum -SBP s Station Biologique de Paimpont -SBSC s Robert A. Vines Environmental Science Center -SBSFU c School of Biological Sciences -SBT s Bergius Foundation -SBU s Saint Bonaventure University, Biology Department -SBUG c Department of Biology of the University of Greifswald -SBY s Salisbury and South Wiltshire Museum -SC s Salem College, Biology Department -SCA s Limbe Botanical & Zoological Gardens -SCAC s South China Agricultural College -SCAR s Wood End Museum -SCARB s Boys' High School -SCB s Station Centrale de Boukoko -SCCAP c Scandinavian Culture Collection of Algae and Protozoa -SCCBC s Selkirk College, Environmental Sciences and Technologies Department -SCCN h Scott Christian College -SCDH s South Carolina Department of Health and Environmental Control -SCFI s Sichuan Academy of Forestry -SCFQ s Service canadien de la faune -SCFS h University of California-Berkeley, Sagehen Creek Field Station -SCH s Museum zu Allerheiligen -SCHG s George Museum -SCHN s Smith College, Biological Sciences Department -SCIEA s South China Institute of Endangered Animals -SCL s St. Cloud State University, Department of Biological Sciences -SCM s Sheffield City Museums -SCN s Sociedad de Ciencias Naturales "La Salle" -SCNHM s Southwestern College, Natural History Museum -SCNU s Sichuan Normal University, Biology Department -SCP h Sociedad Cientifica del Paraguay -SCPS s Scarborough Philosophical and Archaeological Society Museum -SCR s Scripps Institution of Oceanography, Herbarium -SCS s Agriculture and Agri-Food Canada, Semiarid Prairie -SCSC s Saint Cloud State University -SCSFRI s South China Sea Fisheries Research Institute -SCSG h South China Sea Institute of Oceanology, Academia Sinica -SCSIO s South China Sea Institute of Oceanology, Academia Sinica -SCSM s South Carolina State Museum -SCT s Friend's School -SCTCC c Sichuan Type Culture Collection -SCU s Shandong Christian University -SCUF s Universidade Federal de Santa Catarina -SCUI h Suez Canal University -SCV b State Collection of Viruses -SCZ s Smithsonian Tropical Research Institute -SD s Herbarium, San Diego Natural History Museum -SDAKS s South Dakota State University -SDAU s Shandong Agricultural University -SDC s South Dakota State University, Department of Biology -SDCM s Shandong College of Traditional Chinese Medicine -SDFI s Shandong Forestry Institute -SDFS s Shandong Forestry School -SDI s Southend Institute -SDM s Stroud and District Museum -SDM s San Diego Mesa College, Botany Department -SDMP s Shandong Institute of Traditional Chinese Medicine and Materia Medica -SDN s Borough of Thamesdown Museum and Art Gallery -SDNCU cb The Specimen Depository of the Graduate School of Natural Sciences, Nagoya City University -SDNH s Malkerns Agricultural Research Station -SDNHM s San Diego Natural History Museum -SDNU s Shandong Normal University, Biology Department -SDSM s South Dakota School of Mines and Technology -SDSU s San Diego State University +SANU s Shaanxi Normal University, Biology Department +SAO s Sammlung Oberli +SAP s Herbarium of Graduate School of Science, Hokkaido University +SAPA s Hokkaido University Museum (Fungal collection) +SAPCL s St. Andrews Presbyterian College, Biology Department +SAPS s Hokkaido University Museum (Plant collection) +SAPT h Hokkaido University Botanic Garden +SAR s Department of Forestry +SARA s Zemaljski Muzej Bosne I. Herzegovine +SARAT s Department of Morphology and Systematic Botany +SARBG h Saratov State University Botanical Garden +SARC s Roanoke College, Biology Department +SARI s Sakarya Agricultural Research Institute +SAS s Sammlung Arnhardt des Museums Schloss Wilhelmsburg Schmalkalden +SASK s University of Saskatchewan, Plant Sciences Department +SASSA s Universita di Sassari, Dipartimento di Scienze del Farmaco +SASSC b SENDAI Arabidopsis Seed Stock Center +SASY s Institute for Biological Problems of Cryolithozone +SAT s Angelo State University, Biology Department +SAU s Sichuan Agricultural University, Department of Basic Courses +SAU s Southern Arkansas University +SAUF s Sichuan Agricultural University, Forestry Department +SAUT s Sichuan Agricultural University +SAV s Institute of Botany, Slovak Academy of Sciences +SAV:F s Institute of Botany, Slovak Academy of Sciences, Fungal Collection +SAWV s Salem International University, Department of Bioscience +SB s Saint Bernard Abbey +SBBG s Santa Barbara Botanic Garden +SBC s University of California, Biological Sciences Department +SBCC s Santa Barbara City College, Department of Biological Sciences +SBCM s San Bernardino County Museum +SBDE s Sino-Belgian Dinosaur expedition +SBG s Botanical Garden of Stavropol State University, Botany Department +SBH s S Blair Hedges Collection +SBKA s Stiftssammlungen des Benediktinerstiftskrems-Munster +SBM s Sabah Museum +SBM s Santa Barbara Museum of Natural History +SBMN s Santa Barbara Museum of Natural History +SBMNH s Santa Barbara Museum of Natural History +SBNHM s Santa Barbara Natural History Museum +SBP s Station Biologique de Paimpont +SBSC s Robert A. Vines Environmental Science Center +SBSFU c School of Biological Sciences +SBT s Bergius Foundation +SBU s Saint Bonaventure University, Biology Department +SBUG c Department of Biology of the University of Greifswald +SBY s Salisbury and South Wiltshire Museum +SC s Salem College, Biology Department +SCA s Limbe Botanical & Zoological Gardens +SCAC s South China Agricultural College +SCAR s Wood End Museum +SCARB s Boys' High School +SCB s Station Centrale de Boukoko +SCCAP c Scandinavian Culture Collection of Algae and Protozoa +SCCBC s Selkirk College, Environmental Sciences and Technologies Department +SCCN h Scott Christian College +SCDH s South Carolina Department of Health and Environmental Control +SCFI s Sichuan Academy of Forestry +SCFQ s Service canadien de la faune +SCFS h University of California-Berkeley, Sagehen Creek Field Station +SCH s Museum zu Allerheiligen +SCHG s George Museum +SCHN s Smith College, Biological Sciences Department +SCIEA s South China Institute of Endangered Animals +SCL s St. Cloud State University, Department of Biological Sciences +SCM s Sheffield City Museums +SCN s Sociedad de Ciencias Naturales "La Salle" +SCNHM s Southwestern College, Natural History Museum +SCNU s Sichuan Normal University +SCP h Sociedad Cientifica del Paraguay +SCPS s Scarborough Philosophical and Archaeological Society Museum +SCR s Scripps Institution of Oceanography, Herbarium +SCS s Agriculture and Agri-Food Canada, Semiarid Prairie +SCSC s Saint Cloud State University +SCSFRI s South China Sea Fisheries Research Institute +SCSG h South China Sea Institute of Oceanology, Academia Sinica +SCSIO s South China Sea Institute of Oceanology, Academia Sinica SCSG +SCSM s South Carolina State Museum +SCT s Friend's School +SCTCC c Sichuan Type Culture Collection +SCU s Shandong Christian University +SCUF s Universidade Federal de Santa Catarina +SCUI h Suez Canal University +SCUM s Sichuan University Museum +SCV b State Collection of Viruses +SCZ s Smithsonian Tropical Research Institute +SD s Herbarium, San Diego Natural History Museum +SDAKS s South Dakota State University +SDAU s Shandong Agricultural University +SDC s South Dakota State University, Department of Biology +SDCM s Shandong College of Traditional Chinese Medicine +SDFI s Shandong Forestry Institute +SDFS s Shandong Forestry School +SDI s Southend Institute +SDM s Stroud and District Museum +SDM s San Diego Mesa College, Botany Department +SDMP s Shandong Institute of Traditional Chinese Medicine and Materia Medica +SDN s Borough of Thamesdown Museum and Art Gallery +SDNCU cb The Specimen Depository of the Graduate School of Natural Sciences, Nagoya City University +SDNH s Malkerns Agricultural Research Station +SDNHM s San Diego Natural History Museum SDMC,SDNH,SDSNH +SDNU s Shandong Normal University, Biology Department +SDSM s South Dakota School of Mines and Technology +SDSU s San Diego State University SDSU:Arthropods s San Diego State University, Museum of Biodiversity Terrestrial Arthropod Collection SDSU:Birds s San Diego State University, Museum of Biodiversity Birds Collection SDSU:Fish s San Diego State University, Museum of Biodiversity Fish Collection @@ -5744,749 +5797,748 @@ SDSU:Greenhouse b San Diego State University, Greenhouse SDSU:Herbarium s San Diego State University, Herbarium SDSU:Herps s San Diego State University, Museum of Biodiversity Amphibians & Reptiles Collection SDSU:Mammals s San Diego State University, Museum of Biodiversity Mammal Collection -SDSU s Severin-McDaniel Insect Collection -SDU s University of South Dakota, Department of Biology -SEAARI s South Eastern Anatolian Agricultural Research Institute -SEAC s Estacion Experimental de Agricolas de la Campara -SEAMEO c Seameo-Biotrop -SEAN s Museo Entomologico -SEBR c Sanofi ELF Biorecherches -SECM s Science Education Center -SEFES s Southeastern Forest Experiment Station -SEFSC s Southeast Fisheries Science Center +SDSU s Severin-McDaniel Insect Collection +SDU s University of South Dakota, Department of Biology +SEAARI s South Eastern Anatolian Agricultural Research Institute +SEAC s Estacion Experimental de Agricolas de la Campara +SEAMEO c Seameo-Biotrop +SEAN s Museo Entomologico +SEBR c Sanofi ELF Biorecherches +SECM s Science Education Center +SEFES s Southeastern Forest Experiment Station +SEFSC s Southeast Fisheries Science Center SEFSC:MMMGL s Southeast Fisheries Science Center, Marine Mammal Molecular Genetics Laboratory -SEHU s Hokkaido University Insect Collection -SEIG s Societa Entomologica Italiana -SEL s Marie Selby Botanical Gardens -SELU s Southeastern Louisiana University, Biological Sciences Department -SEMC s Snow Entomological Museum -SEMIA c Colecao de Culturas de Rhizobium da Fepagro -SEMK s Snow Entomological Museum -SEMM s Station Experimental de la Maboke -SEMO s Southeast Missouri State University, Department of Biology -SERC s Smithsonian Environmental Research Center -SERG s Institut de Recherche Agronomique de Guinee -SERO s Sociedad para el Estudio de los Recursos Bioticos de Oaxaca -SERTC s Southeastern Regional Taxonomic Center -SES s Southeastern Shanxi Teachers School, Biochemistry Department -SETON s Philmont Scout Ranch, Seton Memorial Library -SEV s Universidad de Sevilla, Departamento de Biologia Vegetal y Ecologia -SEVF s Universidad de Sevilla, Departamento de Botanica -SEY s Seychelles Natural History Museum -SF s Universidad Nacional del Litoral -SFAC s Stephen F. Austin State University -SFB s Salgues Foundation of Brignoles for Development of Biological Sciences -SFC s Laboratory of Fishes -SFD s Sheffield Galleries and Museums Trust, City Museum -SFDK s Sarawak Forestry Department -SFDL s Sheffield Literary and Philosophical Society -SFDN s Sheffield Naturalists' Club -SFI b Slovenian Forestry Institute -SFPA s Fundacao Estadual de Pesquisa Agropecuaria -SFRF s Forest Service, Region 5, USDA -SFRP s Southern Research Station -SFRS s Sea Fisheries Research Station -SFS s Universite de Sherbrooke, Departement de biologie -SFSU s San Francisco State University, Department of Biology -SFT s Stowlangtoft Hall -SFU s Shanghai Fisheries University -SFUC s Simon Fraser University -SFUV s Simon Fraser University, Biological Sciences Department -SFV s California State University, Department of Biology -SFVS s San Fernando Valley State University -SG s Shanghai Botanical Garden -SGBH s Museum of Staffordshire County -SGE s Stamford Park Museum -SGEL s Stalybridge Library -SGGS s The Museum -SGGW s Warsaw University of Life Sciences -SGMA s Universidade Nova de Lisboa -SGN h Southern Institute of Ecology -SGO s Herbario, Museo Nacional de Historia Natural, Santiago -SGSC c Salmonella Genetic Stock Centre -SGWG s Sammlung der Sektion Geologische Wissenschaften der Ernst-Moritz-Arndt University -SH s Academia Sinica -SHB s Shanghai Baptist College -SHC s Sacred Heart College -SHCP s Southern Highlands Conservation Programme -SHCT s Shanghai Teachers College of Technology, Biology Department -SHD s University of Sheffield, Botany Department -SHDC s Shanghai Institute for Drug Control -SHG s Sohag University, Botany Department -SHI s Herbarium, Shihezi University -SHIN s Shinshu University -SHJ s St. John's University -SHM s Shanghai Museum of Natural History, Botanical Department -SHM s Siouxland Heritage Museum -SHMC s Luther College, Sherman A. Hoslett Museum of Natural History -SHMH s Universite l'Aurore, Musee Heude -SHMI s Shanghai Institute of Materia Medica, Chinese Academy of Sciences, Phytochemistry Department -SHMU s Shanghai Medical University -SHOR s Shorter College, Biology Department -SHSND s North Dakota Heritage Center -SHST s Sam Houston State University, Department of Biological Sciences -SHSU s Sam Houston State University, Vertebrate Natural History Collection -SHTC s California State University, Biology Department -SHTU s Shanghai Teachers University, Biology Department -SHY s Rowley's House Museum -SHYAN s Shropshire Archaeological and Natural History Society -SHYB s Shrewsbury School -SHYL s Shrewsbury School -SHYN s Shrewsbury Natural History Society -SHYP s Shrewsbury Public Library -SI s Instituto de Botanica Darwinion -SIAC s Sichuan Institute of Agriculture -SIAC s Accademia dei Fisiocritici Onlus -SIB s Sibiu Natural History Museum -SIBAC s Southwest Institute of Biology -SIBS h Institute of Biology of the Southern Seas -SICH s Simpson College, Biology and Environmental Sciences Department -SIEMEA s Severtsov Insitute for Evolutionary Morphology and Animal Ecology -SIENA s Universita di Siena, Dipartimento di Scienze Ambientali "G. Sarfatti" -SIF s Senckenbergisches Institut -SIFS s Sichuan Forestry School -SIGMA s Station Internationale de Geobotanique Mediterraneenne et Alpine -SIIS s Staten Island Institute of Arts and Sciences -SIM s Staten Island Institute of Arts and Sciences, Science Department -SIMF s Taurida National University, Botany Department -SIMS s Sherkin Island Marine Station -SING s Singapore Botanic Gardens -SINU s National University of Singapore, Biological Sciences Department -SIO s Scripps Institution of Oceanography +SEHU s Hokkaido University Insect Collection +SEIG s Societa Entomologica Italiana +SEL s Marie Selby Botanical Gardens +SELU s Southeastern Louisiana University, Biological Sciences Department +SEMC s Snow Entomological Museum KU:SEMC +SEMIA c Rhizobium Culture Collection +SEMK s Snow Entomological Museum +SEMM s Station Experimental de la Maboke +SEMO s Southeast Missouri State University, Department of Biology +SERC s Smithsonian Environmental Research Center +SERG s Institut de Recherche Agronomique de Guinee +SERO s Sociedad para el Estudio de los Recursos Bioticos de Oaxaca +SERTC s Southeastern Regional Taxonomic Center +SES s Southeastern Shanxi Teachers School, Biochemistry Department +SETON s Philmont Scout Ranch, Seton Memorial Library +SEV s Universidad de Sevilla, Departamento de Biologia Vegetal y Ecologia +SEVF s Universidad de Sevilla, Departamento de Botanica +SEY s Seychelles Natural History Museum +SF s Universidad Nacional del Litoral +SFAC s Stephen F. Austin State University +SFB s Salgues Foundation of Brignoles for Development of Biological Sciences +SFC s Laboratory of Fishes +SFD s Sheffield Galleries and Museums Trust, City Museum +SFDK s Sarawak Forestry Department +SFDL s Sheffield Literary and Philosophical Society +SFDN s Sheffield Naturalists' Club +SFI b Slovenian Forestry Institute +SFPA s Fundacao Estadual de Pesquisa Agropecuaria +SFRF s Forest Service, Region 5, USDA +SFRP s Southern Research Station +SFRS s Sea Fisheries Research Station +SFS s Universite de Sherbrooke, Departement de biologie +SFSU s San Francisco State University, Department of Biology +SFT s Stowlangtoft Hall +SFU s Shanghai Fisheries University +SFUC s Simon Fraser University +SFUV s Simon Fraser University, Biological Sciences Department +SFV s California State University, Department of Biology +SFVS s San Fernando Valley State University +SG s Shanghai Botanical Garden +SGBH s Museum of Staffordshire County +SGE s Stamford Park Museum +SGEL s Stalybridge Library +SGGS s The Museum +SGGW s Warsaw University of Life Sciences +SGMA s Universidade Nova de Lisboa +SGN h Southern Institute of Ecology +SGO s Herbario, Museo Nacional de Historia Natural, Santiago +SGSC c Salmonella Genetic Stock Centre +SGWG s Sammlung der Sektion Geologische Wissenschaften der Ernst-Moritz-Arndt University +SH s Academia Sinica +SHB s Shanghai Baptist College +SHC s Sacred Heart College +SHCP s Southern Highlands Conservation Programme +SHCT s Shanghai Teachers College of Technology, Biology Department +SHD s University of Sheffield, Botany Department +SHDC s Shanghai Institute for Drug Control +SHG s Sohag University, Botany Department +SHI s Herbarium, Shihezi University +SHIN s Shinshu University +SHJ s St. John's University +SHM s Shanghai Museum of Natural History, Botanical Department +SHM s Siouxland Heritage Museum +SHMC s Luther College, Sherman A. Hoslett Museum of Natural History +SHMH s Universite l'Aurore, Musee Heude +SHMI s Shanghai Institute of Materia Medica, Chinese Academy of Sciences, Phytochemistry Department +SHMU s Shanghai Medical University +SHOR s Shorter College, Biology Department +SHSND s North Dakota Heritage Center +SHST s Sam Houston State University, Department of Biological Sciences +SHSU s Sam Houston State University, Vertebrate Natural History Collection +SHTC s California State University, Biology Department +SHTU s Shanghai Teachers University, Biology Department +SHY s Rowley's House Museum +SHYAN s Shropshire Archaeological and Natural History Society +SHYB s Shrewsbury School +SHYL s Shrewsbury School +SHYN s Shrewsbury Natural History Society +SHYP s Shrewsbury Public Library +SI s Instituto de Botanica Darwinion +SIAC s Sichuan Institute of Agriculture +SIAC s Accademia dei Fisiocritici Onlus +SIB s Sibiu Natural History Museum +SIBAC s Southwest Institute of Biology +SIBS h Institute of Biology of the Southern Seas +SICH s Simpson College, Biology and Environmental Sciences Department +SIEMEA s Severtsov Insitute for Evolutionary Morphology and Animal Ecology +SIENA s Universita di Siena, Dipartimento di Scienze Ambientali "G. Sarfatti" +SIF s Senckenbergisches Institut +SIFS s Sichuan Forestry School +SIGMA s Station Internationale de Geobotanique Mediterraneenne et Alpine +SIIS s Staten Island Institute of Arts and Sciences +SIM s Staten Island Institute of Arts and Sciences, Science Department +SIMF s Taurida National University, Botany Department +SIMS s Sherkin Island Marine Station +SING s Singapore Botanic Gardens +SINU s National University of Singapore, Biological Sciences Department +SIO s Scripps Institution of Oceanography SIO:BIC s Scripps Institution of Oceanography, Benthic Invertebrates Collection -SITC s Sichuan Teachers College, Biology Department -SIU s Southern Illinois University, Plant Biology Department -SIUC s Research Museum of Zoology, Southern Illinois University at Carbondale +SITC s Sichuan Teachers College, Biology Department +SIU s Southern Illinois University, Plant Biology Department +SIUC s Research Museum of Zoology, Southern Illinois University at Carbondale SIUC:H s Research Museum of Zoology, Southern Illinois University at Carbondale, Herpetology Collection -SIUCM s Southern Illinois University -SIUE s Southern Illinois University, Edwardsville -SIZK s Schmaulhausen Institute of Zoology -SJ s Departamento de Recursos Naturales y Ambientales -SJAC s San Joaquin County Agriculture Commissioner -SJC s Sir John Cass College, Chemistry and Biology Department -SJCA s St. John's College -SJCRY s St. John's College of Ripon and York -SJER s United States Forest Service, San Joaquin Experimental Range -SJFM s Fairbanks Museum and Planetarium -SJNM s San Juan College -SJPC s Sergei J. Paramonov personal collection -- destroyed -SJRP s UNESP, Campus Sao Jose Rio Preto, Departamento Zoologia e Botanica -SJSC s San Jose State University, J. Gordon Edwards Museum of Entomology -SJSU s San Jose State University, Biological Sciences Department -SJUBC s Saint John's University, Biology Collections -SK s Katedralskolan -SKK s Sung Kyun Kwan University, Biological Sciences Department -SKM s Skokholm Field Centre -SKN s Craven Museum Service -SKR s Latvian Research Institute of Agriculture, Plant Protection Department -SKT s Stockport Heritage Services -SKU s Sri Krishnadevaraya University, Botany Department -SKUK c Simpanan Kultur Universiti Kebangsaan -SL s University of Sierra Leone, Njala University College, Biological Sciences Department -SLBI s South London Botanical Institute -SLC s East High School, Science Department -SLFC s Slapton Ley Field Centre -SlgInnsb s Paleontological Collection -SLJG s Steiermarkisches Landesmuseum Joanneum -SLL s Societe Linneenne de Lyon -SLO s Komenskeho University, Katedra botaniky -SLPM s Universidad Autonoma de San Luis Potosi -SLRO s Slippery Rock University, Biology Department -SLSC s St. Louis, St. Louis Science Center -SLSK s St. Leonard's and St. Katherine's Schools -SLTC s Teachers College, Botany Department -SLU s Laurentian University, Biology Department -SLU s Southeastern Louisiana University, Vertebrate Museum -SLUB s St. Louis University Museum -SLUBGH h Shah Abdul Latif University -SLUM s Saint Louis University Museum Ichthylogy Collection -SM s Chongqing Municipal Academy of Chinese Materia Medica -SM s Senckenberg Museum -SM s Schwegler Museum -SM s Sarawak Museum -SM s Sanford Museum Collections -SM s Strecker Museum, Baylor University -SMAG s Southland Museum and Art Gallery -SMAO s Simao Forestry Bureau -SMB s Marianske Muzeum, Natural History Department -SMBB s Stredoslovenske muzeum -SMBL s Seto Marine Biological Laboratory, Kyoto University -SMC s Sedgwick Museum -SMCC c Subsurface Microbial Culture Collection -SMCC-W c Subsurface Microbial Culture Collection--Western Branch -SMCW s Saint Michael's College, Biology Department -SMDB s Universidade Federal de Santa Maria, Departamento de Biologia -SME s Station Marine d'Endoume -SME s Sedgwick Museum of Geology -SMF s Forschungsinstitut und Natur-Museum Senckenberg -SMF s Universidad Nacional Mayor de San Marcos -SMH s Saint Meinrad College of Liberal Arts, Biology Department -SMI s Prince Rupert Forest Region, Research Section -SMIP c Secao de Maricultura -SMJM s Sabah Museum -SMK s Sarawak Museum -SMKM s Selangor Museum -SMM s Science Museum of Minnesota -SMMC s Second Military Medical College -SMN s Simao District National Medical and Pharmaceutical Institute -SMNG s Senckenberg Museum fuer Naturkunde Goerlitz -SMNH s Saskatchewan Museum of Natural History -SMNH s Steinhardt Museum of Natural History -SMNH s Swedish Museum of Natural History -SMNH s State Museum of Natural History -SMNH s Schmidt Museum of Natural History, Emporia State University -SMNK s Staatliches Museum fuer Naturkunde Karlsruhe (State Museum of Natural History) -SMNS s Staatliches Museum fuer Naturkund Stuttgart -SMOC s Slezske Muzeum Opava -SMP s Surinaams Museum -SMP s The State Museum of Pennsylvania -SMPM s Science Museum of Minnesota -SMR s Samara State University, Department for Ecology, Botany, and Nature Protection -SMRG c Soil Microbiology Research Group, Division of Soil Science, Department of Agriculture -SMRS s Stavropol Museum of Regional Studies -SMS s Missouri State University, Department of Biology -SMSM s Sarawak Museum -SMTP s Swedish Malaise Trap Project -SMTWA c School of Medical Technology Western Australia -SMU s St. Mary's University -SMU s Sangmiung University -SMU s Shuler Museum of Paleontology, Southern Methodist University -SMVM s National Archives and Museum -SMW s School of Medicine for Women -SMW s State Museum -SMWN s State Museum -SMWU s Sang Miung Women's University -SN s South China Normal University, Biology Department -SNC s Saint Norbert College -SNCBSH s State of North Carolina Biological Station -SNGM s Coleccion Paleontologica -SNHM s Sudan Natural History Museum -SNHS s Guildford Museum -SNM s Slovak National Museum -SNM s Western New Mexico University, Department of Natural Sciences -SNMB s Staatliches Naturhistorisches Museum -SNMBR s Staatliches Naturhistorisches Museum in Braunschweig -SNMC s Slovenske Narodne Muzeum -SNMG s Staatliches Museum fuer Naturkunde -SNMH h Sree Narayana Mangalam College -SNMNH s Saudi Arabian National Museum of Natural History -SNOMNH s Sam Nobel Oklahoma Museum of Natural History -SNP s Sabah Parks, Botany Section -SNPH s Sehlabathebe National Park -SNSD s Senckenberg Natural History Collections Dresden, Museum of Zoology +SIUCM s Southern Illinois University +SIUE s Southern Illinois University, Edwardsville +SIZK s Schmaulhausen Institute of Zoology +SJ s Departamento de Recursos Naturales y Ambientales +SJAC s San Joaquin County Agriculture Commissioner +SJC s Sir John Cass College, Chemistry and Biology Department +SJCA s St. John's College +SJCRY s St. John's College of Ripon and York +SJER s United States Forest Service, San Joaquin Experimental Range +SJFM s Fairbanks Museum and Planetarium +SJNM s San Juan College +SJPC s Sergei J. Paramonov personal collection -- destroyed +SJRP s UNESP, Campus Sao Jose Rio Preto, Departamento Zoologia e Botanica +SJSC s San Jose State University, J. Gordon Edwards Museum of Entomology +SJSU s San Jose State University, Biological Sciences Department +SJUBC s Saint John's University, Biology Collections +SK s Katedralskolan +SKK s Sung Kyun Kwan University, Biological Sciences Department +SKM s Skokholm Field Centre +SKN s Craven Museum Service +SKR s Latvian Research Institute of Agriculture, Plant Protection Department +SKT s Stockport Heritage Services +SKU s Sri Krishnadevaraya University, Botany Department +SKUK c Simpanan Kultur Universiti Kebangsaan +SL s University of Sierra Leone, Njala University College, Biological Sciences Department +SLBI s South London Botanical Institute +SLC s East High School, Science Department +SLFC s Slapton Ley Field Centre +SlgInnsb s Paleontological Collection +SLJG s Steiermarkisches Landesmuseum Joanneum +SLL s Societe Linneenne de Lyon +SLO s Komenskeho University, Katedra botaniky +SLPM s Universidad Autonoma de San Luis Potosi +SLRO s Slippery Rock University, Biology Department +SLSC s St. Louis, St. Louis Science Center +SLSK s St. Leonard's and St. Katherine's Schools +SLTC s Teachers College, Botany Department +SLU s Laurentian University, Biology Department +SLU s Southeastern Louisiana University, Vertebrate Museum +SLUB s St. Louis University Museum +SLUBGH h Shah Abdul Latif University +SLUM s Saint Louis University Museum Ichthylogy Collection +SM s Chongqing Municipal Academy of Chinese Materia Medica +SM s Senckenberg Museum +SM s Schwegler Museum +SM s Sarawak Museum +SM s Sanford Museum Collections +SM s Strecker Museum, Baylor University +SMAG s Southland Museum and Art Gallery +SMAO s Simao Forestry Bureau +SMB s Marianske Muzeum, Natural History Department +SMBB s Stredoslovenske muzeum +SMBL s Seto Marine Biological Laboratory, Kyoto University +SMC s Sedgwick Museum +SMCC c Subsurface Microbial Culture Collection +SMCC-W c Subsurface Microbial Culture Collection--Western Branch +SMCW s Saint Michael's College, Biology Department +SMDB s Universidade Federal de Santa Maria, Departamento de Biologia +SME s Station Marine d'Endoume +SME s Sedgwick Museum of Geology +SMF s Forschungsinstitut und Natur-Museum Senckenberg +SMF s Universidad Nacional Mayor de San Marcos +SMH s Saint Meinrad College of Liberal Arts, Biology Department +SMI s Prince Rupert Forest Region, Research Section +SMIP c Secao de Maricultura +SMJM s Sabah Museum +SMK s Sarawak Museum SM +SMKM s Selangor Museum +SMM s Science Museum of Minnesota +SMMC s Second Military Medical College +SMN s Simao District National Medical and Pharmaceutical Institute +SMNG s Senckenberg Museum fuer Naturkunde Goerlitz +SMNH s Saskatchewan Museum of Natural History +SMNH s Steinhardt Museum of Natural History +SMNH s Swedish Museum of Natural History +SMNH s State Museum of Natural History +SMNH s Schmidt Museum of Natural History, Emporia State University +SMNK s Staatliches Museum fuer Naturkunde Karlsruhe (State Museum of Natural History) +SMNS s Staatliches Museum fuer Naturkund Stuttgart +SMOC s Slezske Muzeum Opava +SMP s Surinaams Museum +SMP s The State Museum of Pennsylvania +SMPM s Science Museum of Minnesota +SMR s Samara State University, Department for Ecology, Botany, and Nature Protection +SMRG c Soil Microbiology Research Group, Division of Soil Science, Department of Agriculture +SMRS s Stavropol Museum of Regional Studies +SMS s Missouri State University, Department of Biology +SMSM s Sarawak Museum +SMTP s Swedish Malaise Trap Project +SMTWA c School of Medical Technology Western Australia +SMU s St. Mary's University +SMU s Sangmiung University +SMU s Shuler Museum of Paleontology, Southern Methodist University SMP +SMVM s National Archives and Museum +SMW s School of Medicine for Women +SMW s State Museum SMWN +SMWN s State Museum SMW +SMWU s Sang Miung Women's University +SN s South China Normal University, Biology Department +SNC s Saint Norbert College +SNCBSH s State of North Carolina Biological Station +SNGM s Coleccion Paleontologica +SNHM s Sudan Natural History Museum +SNHS s Guildford Museum +SNM s Slovak National Museum SNMB +SNM s Western New Mexico University, Department of Natural Sciences +SNMB s Staatliches Naturhistorisches Museum +SNMBR s Staatliches Naturhistorisches Museum in Braunschweig +SNMC s Slovenske Narodne Muzeum +SNMG s Staatliches Museum fuer Naturkunde +SNMH h Sree Narayana Mangalam College +SNMNH s Saudi Arabian National Museum of Natural History +SNOMNH s Sam Nobel Oklahoma Museum of Natural History +SNP s Sabah Parks, Botany Section +SNPH s Sehlabathebe National Park +SNSD s Senckenberg Natural History Collections Dresden, Museum of Zoology SNSD:Moll s Senckenberg Natural History Collections Dresden, Museum of Zoology, -SNU s Seoul National University, School of Biological Sciences -SNUA s Seoul National University, The Arboretum -SNW s Shropshire and North Wales Natural History and Antiquarian Society -SO s Sofia University "St. Kliment Ohridski", Botany Department -SOA s Agricultural University of Plovdiv, Botany Department -SOB s Husite Museum Tabor -SOC s Southern Oregon University, Biology Department -SOF h Sofyivka National Dendrological Park -SOFM s National Museum of Natural History, Sofia -SOFRI b Southern Fruit Research Institute Vietnam -SOGS s Pal. Coll, Sokoto State Government Palaeontological Collection -SOIC s Natural History Museum, National Insect Collection -SOKO s Okresni muzeum Sokolov (Regional Muzeum), Botany Department -SOM s Bulgarian Academy of Sciences -SOMF s Bulgarian Academy of Sciences -SORO h Universidade Federal de Sao Carlos, campus Sorocaba -SOSCMVNH s Southern Oregon State College, Museum of Vertebrate Natural History -SOSN s Silesian Medical School in Katowice, Department of Pharmaceutical Botany -SOSSRC s Save Our Seas Shark Research Center, Nova Southeastern University -SOTO s College of the Ozarks, Biology Department -SOTON s Southampton University -SOUT s Long Island University -SP s Instituto de Botanica -SPA s Swedish Museum of Natural History, Section for Palaeobotany -SPAL s Municipio di Reggio Emilia, Musei Civici -SPB s Universidade de Sao Paulo -SPC s Seattle Pacific University, Biology Department, Suite 205 -SPF s Universidade de Sao Paulo, Departamento de Botanica -SPFR s Universidade de Sao Paulo, Departamento de Biologia -SPH s Fox Research Forest -SPI s Stavropol Pedagogical Institute, Botany Department -SPL s Palynological Laboratory -SPLT s South Plains College, Science Department -SPM s Sabah Parks -SPMCC c Sungei Putih Microbial Culture Collection -SPMO c Salt Plains Microbial Observatory -SPMS s University of South Florida -SPN s Southampton University, Biology Department -SPNRI s Sichuan Province, Natural Resources Institute -SPR s Springfield Science Museum, Natural Science Department -SPRY s Burton Constable Foundation -SPSF s Instituto Florestal -SPSU h St. Petersburg State University -SPT s Botanic Gardens Museum -SPTS s Southport Scientific Society -SPWH s Marine Biological Laboratory -SQB h Societe quebecoise de bryologie -SQF s Universidad de Chile, Laboratorio de Botanica, Escuela de Quimica y Farmacia -SQUH h Sultan Qaboos University -SR s Sichuan Institute of Natural Resources -SRAICC c SRAI's culture collection -SRCG s Baylor University -SRD s Passmore Edwards Museum -SRF s Shangrao Forestry Institute -SRFA s Universidad Nacional de La Pampa -SRGH s Botanic Garden -SRI s Serengetti Research Institute -SRNP s Insects of the Area Conservacion Guanacaste, northwestern Costa Rica -SRP s Boise State University, Biology Department -SRR s Koninklijke Shell (Shell Research N.V.) -SRRC c Southern Regional Research Center, Agricultural Research Service, United States Department of Agriculture -SRS h Universidade do Sul de Santa Catarina -SRSC s Sul Ross State University, Department of Biology -SRSU s Sul Ross State University -SS s Universita di Sassari, Dipartimento di Botanica ed Ecologia Vegetale -SSC s Sacramento State University -SSCMU c Soil Science and Conservation Department Faculty of Agriculture -SSCN s Musum of the Biological Laboratory -SSD s Sammlung Simon des Stattlichen Museum fur Mineralogie und Geologie Dresden -SSF s Sammlung des Senckenbrug-Museum -SSI c Statens Serum Institute -SSIC c Collaborating Centre for Reference and Research on Escherichia and Klebsiella -SSJC s San Joaquin County, Agriculture Department -SSKKU c Department of Soil Science, Faculty of Agriculture -SSL s Sammlung Langenhan an der Sektion Geophysik der Karl-Marx-Universitat Lepzig -SSLP s Rocky Mountain Research Station -SSM s Savannah Science Museum -SSM s Springfield Science Museum -SSMF s Great Lakes Forestry Centre, Canadian Forest Service -SSMJI c Science Section, Department of General Education, Faculty of Agricultural Business -SSMM s Shanxi School of Chinese Materia Medica -SSMS s Suriname State Museum -SSNR s Societa per GL Studi Naturalistica della Romagna -SSOFM s Sanabe Shizenkan Open Field Museum -SSPW s Perivale Wood Nature Reserve -SSU s Saratov State University -SSUC s Pontificia Universidad Catolica de Chile, Departamento de Ecologia -ST s Suzhou Teachers College, Biology Department -STA s University of St. Andrews, School of Environmental and Evolutionary Biology -STAL s Verulamium Museum -STAR s Arkansas State University, Biological Sciences Department -STASH s St. Beuno's College -STB s St. Bartholomew's Hospital -STC s Sichuan Teacher's College -STCR s Universite de la Reunion -STD s Prittlewell Priory Museum -STDCM s Southend Central Museum -STE s National Botanical Institute -STE-U c Culture collection of the Department of Plant Pathology, University of Stellenbosch -STEU sc University of Stellenbosch, Botany Department -STFX s St. Francis Xavier University, Biology Department -STG s St. Martin's Convent -STI s Stirling Smith Art Gallery and Museum -STIU s University of Stirling, Biological Sciences Department -STK s Stoke-on-Trent Athenaeum -STL s Instituto Nacional de Limnologia, Departamento Macrofitas -STM s Stettinger Museum -STM c Laboratoire des Symbioses Tropicales et Mediterraneennes -STM s Streatham Antiquarian and Natural History Society -STMC s School of Tropical Medicine -STNF h Shasta-Trinity National Forest -STO s The Potteries Museum & Art Gallery -STP s La Societe Guernesiaise, Priaulx Library -STPCM s Island Museum, Candie Gardens -STPE s Florida Marine Research Institute, Florida Department of Environmental Protection -STPH h Direccao Geral do Ambiente, Cabinet of Environment, Ministry of Natural Resources and Environment -STPS s St. Paul's School -STR s Institut de Botanique -STRI sc Smithsonian Tropical Research Institute +SNU s Seoul National University, School of Biological Sciences +SNUA s Seoul National University, The Arboretum +SNW s Shropshire and North Wales Natural History and Antiquarian Society +SO s Sofia University "St. Kliment Ohridski", Botany Department +SOA s Agricultural University of Plovdiv, Botany Department +SOB s Husite Museum Tabor +SOC s Southern Oregon University, Biology Department +SOF h Sofyivka National Dendrological Park +SOFM s National Museum of Natural History, Sofia +SOFRI b Southern Fruit Research Institute Vietnam +SOGS s Pal. Coll, Sokoto State Government Palaeontological Collection +SOIC s Natural History Museum, National Insect Collection +SOKO s Okresni muzeum Sokolov (Regional Muzeum), Botany Department +SOM s Bulgarian Academy of Sciences +SOMF s Bulgarian Academy of Sciences +SORO h Universidade Federal de Sao Carlos, campus Sorocaba +SOSCMVNH s Southern Oregon State College, Museum of Vertebrate Natural History +SOSN s Silesian Medical School in Katowice, Department of Pharmaceutical Botany +SOSSRC s Save Our Seas Shark Research Center, Nova Southeastern University +SOTO s College of the Ozarks, Biology Department +SOTON s Southampton University +SOUT s Long Island University +SP s Instituto de Botanica +SPA s Swedish Museum of Natural History, Section for Palaeobotany +SPAL s Municipio di Reggio Emilia, Musei Civici +SPB s Universidade de Sao Paulo +SPC s Seattle Pacific University, Biology Department, Suite 205 +SPF s Universidade de Sao Paulo, Departamento de Botanica +SPFR s Universidade de Sao Paulo, Departamento de Biologia +SPH s Fox Research Forest +SPI s Stavropol Pedagogical Institute, Botany Department +SPL s Palynological Laboratory +SPLT s South Plains College, Science Department +SPM s Sabah Parks +SPMCC c Sungei Putih Microbial Culture Collection +SPMO c Salt Plains Microbial Observatory +SPMS s University of South Florida +SPN s Southampton University, Biology Department +SPNRI s Sichuan Province, Natural Resources Institute +SPR s Springfield Science Museum, Natural Science Department +SPRY s Burton Constable Foundation +SPSF s Instituto Florestal +SPSU h St. Petersburg State University +SPT s Botanic Gardens Museum +SPTS s Southport Scientific Society +SPWH s Marine Biological Laboratory +SQB h Societe quebecoise de bryologie +SQF s Universidad de Chile, Laboratorio de Botanica, Escuela de Quimica y Farmacia +SQUH h Sultan Qaboos University +SR s Sichuan Institute of Natural Resources +SRAICC c SRAI's culture collection +SRCG s Baylor University +SRD s Passmore Edwards Museum +SRF s Shangrao Forestry Institute +SRFA s Universidad Nacional de La Pampa +SRGH s Botanic Garden +SRI s Serengetti Research Institute +SRNP s Insects of the Area Conservacion Guanacaste, northwestern Costa Rica +SRP s Boise State University, Biology Department +SRR s Koninklijke Shell (Shell Research N.V.) +SRRC c Southern Regional Research Center, Agricultural Research Service, United States Department of Agriculture +SRS h Universidade do Sul de Santa Catarina +SRSC s Sul Ross State University, Department of Biology +SRSU s Sul Ross State University +SS s Universita di Sassari, Dipartimento di Botanica ed Ecologia Vegetale +SSC s Sacramento State University +SSCMU c Soil Science and Conservation Department Faculty of Agriculture +SSCN s Musum of the Biological Laboratory +SSD s Sammlung Simon des Stattlichen Museum fur Mineralogie und Geologie Dresden +SSF s Sammlung des Senckenbrug-Museum +SSI c Statens Serum Institute +SSIC c Collaborating Centre for Reference and Research on Escherichia and Klebsiella +SSJC s San Joaquin County, Agriculture Department +SSKKU c Department of Soil Science, Faculty of Agriculture +SSL s Sammlung Langenhan an der Sektion Geophysik der Karl-Marx-Universitat Lepzig +SSLP s Rocky Mountain Research Station +SSM s Savannah Science Museum +SSM s Springfield Science Museum +SSMF s Great Lakes Forestry Centre, Canadian Forest Service +SSMJI c Science Section, Department of General Education, Faculty of Agricultural Business +SSMM s Shanxi School of Chinese Materia Medica +SSMS s Suriname State Museum +SSNR s Societa per GL Studi Naturalistica della Romagna +SSOFM s Sanabe Shizenkan Open Field Museum +SSPW s Perivale Wood Nature Reserve +SSU s Saratov State University +SSUC s Pontificia Universidad Catolica de Chile, Departamento de Ecologia +ST s Suzhou Teachers College, Biology Department +STA s University of St. Andrews, School of Environmental and Evolutionary Biology +STAL s Verulamium Museum +STAR s Arkansas State University, Biological Sciences Department +STASH s St. Beuno's College +STB s St. Bartholomew's Hospital +STC s Sichuan Teacher's College +STCR s Universite de la Reunion +STD s Prittlewell Priory Museum +STDCM s Southend Central Museum +STE s National Botanical Institute +STE-U c Culture collection of the Department of Plant Pathology, University of Stellenbosch +STEU sc University of Stellenbosch, Botany Department +STFX s St. Francis Xavier University, Biology Department +STG s St. Martin's Convent +STI s Stirling Smith Art Gallery and Museum +STIU s University of Stirling, Biological Sciences Department +STK s Stoke-on-Trent Athenaeum +STL s Instituto Nacional de Limnologia, Departamento Macrofitas +STM s Stettinger Museum +STM c Laboratoire des Symbioses Tropicales et Mediterraneennes +STM s Streatham Antiquarian and Natural History Society +STMC s School of Tropical Medicine +STNF h Shasta-Trinity National Forest +STO s The Potteries Museum & Art Gallery +STP s La Societe Guernesiaise, Priaulx Library +STPCM s Island Museum, Candie Gardens +STPE s Florida Marine Research Institute, Florida Department of Environmental Protection +STPH h Direccao Geral do Ambiente, Cabinet of Environment, Ministry of Natural Resources and Environment +STPS s St. Paul's School +STR s Institut de Botanique +STRI sc Smithsonian Tropical Research Institute STRI:ICBG-Panama c Smithsonian Tropical Research Institute, International Cooperative Biodiversity Groups -STS s Stromness Museum -STT s St. Thomas's Hospital Medical School Library -STU s Staatliches Museum fuer Naturkunde Stuttgart -STUM s Santo Tomas University Museum -SU s Suzhou University -SU s Stanford University -SU s Oregon State University -SUA s Sokoine University of Agriculture, Forest Biology Department -SUB s Universitat Bonn -SUCEA s The University at Albany -SUCH s Sukhumi Botanical Garden of Georgian Academy of Sciences -SUCN s State University of California -SUCO s State University of New York, College at Oneonta, Biology Department -SUD s Stroud and District Museum -SUEL s Natural History Museum of Bakony Mountains -SUF s Shimonoseki University of Fisheries -SUFA h Sulaimania University -SUFAF h Siirt University Flora and Fauna Center -SUHC s Salisbury University, Department of Biology -SUK s Shivaji University Kolhapur -SUM s Okresni vlastivedne muzeum v Sumperku -SUM s Stellenbosch University -SUN s Sunderland Museum -SUND s Sunderland Natural History and Antiquarian Society -SUNIV s University of Stockholm -SUNY s State University of New York -SUNYO s State University of New York at Oneonta -SURCO h Universidad Surcolombiana -SUU h Southern Utah University -SUVA s University of the South Pacific -SUVM s Shippensburg University, Vertebrate Museum -SUWS s University of Wisconsin-Superior, Department of Biology and Earth Science -SV s Antigua Estacion Experimental Agronomica -SVCK c Sammlung von Conjugaten Kulturen -SVER s Institute of Plant and Animal Ecology, Laboratory of Plant Ecology and Geobotany -SVG s Arkeologisk museum i Stavanger -SVIEC c Secao de Virus -SVUTY h Sri Venkateswara University -SVVC s Seminario Vescovile -SWA s Swansea Museum -SWAT h University of Swat Pakistan -SWAU s Southwest Agricultural University, Horticulture Department -SWBR s Sweet Briar College, Biology Department -SWC s Sammlung des Cambridge, University of Zoology -SWC s Swarthmore College, Biology Department -SWCTU s Southwest Teachers University, Biology Department -SWE s Chandos House, Stowe School -SWF s Florida Gulf Coast University -SWFC s Southwest Forestry College -SWFSC s Southwest Fisheries Science Center -SWGC h Grenfell Campus, Memorial University of Newfoundland -SWIBASC s Academia Sinica -SWMT s Rhodes College, Biology Department -SWN s Saffron Walden Museum -SWNHS s Saffron Walden Horticultural Society -SWRS s Southwestern Research Station -SWSL s USDA/ARS, Southern Weed Science Research Unit -SWT s Southwest Texas State University, Department of Biology -SWTN s Swinton and Pendlebury Botanical Society -SWU h Sungshin Women's University -SWU2 c Department of Biology, Faculty of Science -SXAU s Shanxi Agricultural University, Forestry Department -SXDC s Shaanxi Institute for Drug Control -SXIM h Shaanxi Institute of Microbiology -SXMP s Shaanxi Academy of Traditional Chinese Medicine and Pharmacology -SXU s Shanxi University, Biology Department -SY s Shenyang Municipal Academy of Landscape Gardening -SYAU s Shenyang Agricultural University -SYAUF s Shenyang Agricultural University, Forestry Department -SYD s University of Sydney -SYKO s Komi Scientific Centre, Ural Division, Russian Academy of Sciences, Department of Geobotany and Plant Cover Restoration -SYKT s Syktyvkar State University, Botany Department -SYPC s Shenyang College of Pharmacy, Pharmaceutical Botany Department -SYR s Syracuse University, Plant Sciences Department -SYRF s State University of New York -SYS s Sun Yatsen University, Biology Department +STS s Stromness Museum +STT s St. Thomas's Hospital Medical School Library +STU s Staatliches Museum fuer Naturkunde Stuttgart +STUM s Santo Tomas University Museum +SU s Suzhou University +SU s Stanford University +SU s Oregon State University +SUA s Sokoine University of Agriculture, Forest Biology Department +SUB s Universitat Bonn +SUCEA s The University at Albany +SUCH s Sukhumi Botanical Garden of Georgian Academy of Sciences +SUCN s State University of California +SUCO s State University of New York, College at Oneonta, Biology Department +SUD s Stroud and District Museum +SUEL s Natural History Museum of Bakony Mountains +SUF s Shimonoseki University of Fisheries +SUFA h Sulaimania University +SUFAF h Siirt University Flora and Fauna Center +SUHC s Salisbury University, Department of Biology +SUK s Shivaji University Kolhapur +SUM s Okresni vlastivedne muzeum v Sumperku +SUM s Stellenbosch University +SUN s Sunderland Museum +SUND s Sunderland Natural History and Antiquarian Society +SUNIV s University of Stockholm +SUNY s State University of New York +SUNYO s State University of New York at Oneonta +SURCO h Universidad Surcolombiana +SUU h Southern Utah University +SUVA s University of the South Pacific +SUVM s Shippensburg University, Vertebrate Museum +SUWS s University of Wisconsin-Superior, Department of Biology and Earth Science +SV s Antigua Estacion Experimental Agronomica +SVCK c Sammlung von Conjugaten Kulturen +SVER s Institute of Plant and Animal Ecology, Laboratory of Plant Ecology and Geobotany +SVG s Arkeologisk museum i Stavanger +SVIEC c Secao de Virus +SVUTY h Sri Venkateswara University +SVVC s Seminario Vescovile +SWA s Swansea Museum +SWAT h University of Swat Pakistan +SWAU s Southwest Agricultural University, Horticulture Department +SWBR s Sweet Briar College, Biology Department +SWC s Sammlung des Cambridge, University of Zoology +SWC s Swarthmore College, Biology Department +SWCTU s Southwest Teachers University, Biology Department +SWE s Chandos House, Stowe School +SWF s Florida Gulf Coast University +SWFC s Southwest Forestry College +SWFSC s Southwest Fisheries Science Center +SWGC h Grenfell Campus, Memorial University of Newfoundland +SWIBASC s Academia Sinica +SWMT s Rhodes College, Biology Department +SWN s Saffron Walden Museum +SWNHS s Saffron Walden Horticultural Society +SWRS s Southwestern Research Station +SWSL s USDA/ARS, Southern Weed Science Research Unit +SWT s Southwest Texas State University, Department of Biology +SWTN s Swinton and Pendlebury Botanical Society +SWU h Sungshin Women's University +SWU2 c Department of Biology, Faculty of Science +SXAU s Shanxi Agricultural University, Forestry Department +SXDC s Shaanxi Institute for Drug Control +SXIM h Shaanxi Institute of Microbiology +SXMP s Shaanxi Academy of Traditional Chinese Medicine and Pharmacology +SXU s Shanxi University, Biology Department +SY s Shenyang Municipal Academy of Landscape Gardening +SYAU s Shenyang Agricultural University +SYAUF s Shenyang Agricultural University, Forestry Department +SYD s University of Sydney +SYKO s Komi Scientific Centre, Ural Division, Russian Academy of Sciences, Department of Geobotany and Plant Cover Restoration +SYKT s Syktyvkar State University, Botany Department +SYPC s Shenyang College of Pharmacy, Pharmaceutical Botany Department +SYR s Syracuse University, Plant Sciences Department +SYRF s State University of New York +SYS s Sun Yatsen University, Biology Department SYS:Z s Sun Yatsen University, Biology Department, Zoology Collection -SYSBM s The Museum of Biology Sun Yat-sen University -SYSU s National Sun Yat-Sen University, Department of Biological Sciences -SYT s Stonyhurst College -SZ s Sichuan University, Biological Department -SZB s Haus der Natur -SZCU s Department of Systematic Zoology -SZCZ h University of Szczecin -SZE s Mora Ferenc Museum, Natural Science Department -SZE s Zoology Department, Aegean University, Science Faculty -SZG s Shenzhen Fairy Lake Botanical Garden -SZL s Landesherbar von Salzburg -SZM s Saitama Zoogeographical Museum -SZMC c Szeged Microbiological Collection -SZMN s Siberian Zoological Museum -SZPT s Shenzhen Polytechnic +SYSBM s The Museum of Biology Sun Yat-sen University +SYSU s National Sun Yat-Sen University, Department of Biological Sciences +SYT s Stonyhurst College +SZ s Sichuan University, Biological Department +SZB s Haus der Natur +SZCU s Department of Systematic Zoology +SZCZ h University of Szczecin +SZE s Mora Ferenc Museum, Natural Science Department +SZE s Zoology Department, Aegean University, Science Faculty +SZG s Shenzhen Fairy Lake Botanical Garden +SZL s Landesherbar von Salzburg +SZM s Saitama Zoogeographical Museum +SZMC c Szeged Microbiological Collection +SZMN s Siberian Zoological Museum +SZPT s Shenzhen Polytechnic SZPT:ENT s Shenzhen Polytechnic, Entomology Collection -SZU s University of Salzburg, Department of Organismic Biology -SZUB h University of Szczecin -T s Tavera, Department of Geology and Geophysics -TA s Timescale Adventures Research and Interpretive Center -TAA s Estonian Agricultural University, Institute of Agricultural and Environmental Sciences -TAAM s Institute of Agricultural and Environmental Sciences of the Estonian University of Life Sciences -TAC s Tarleton State University, Biological Sciences Department -TAD s Botanical Institute of the Tajikistan Academy of Sciences, Department of Flora and Systematics of Higher Plants -TAES s Texas A&M University, Department of Rangeland Ecology and Management -TAFIRI s Tanzania Fisheries Research Institute -TAI s National Taiwan University, Institute of Ecology and Evolutionary Biology -TAIC s Texas A&M University-Kingsville, Department of Biology -TAIE h Endemic Species Research Institute -TAIF s Taiwan Forestry Research Institute -TAIM s Taiwan Museum -TAIU s Texas A&M University - Kingsville, Texas A&I Collections -TAK s Lenin State University -TAL h Jardin botanique de Talence -TALE s Laboratoire Geologique -TALL s Tallinn Botanic Garden, Department of Environmental Education -TAM s Estonian Museum of Natural History, Botany Department -TAMA c Mycology & Metabolic Diversity Research Center, Tamagawa University Research Institute -TAMU s Texas A&M University, Biology Department -TAN s Parc de Tsimbazaza, Departement Botanique -TANE s Tanta University, Botany Department -TAR s Consiglio Nazionale delle Ricerche -TARI s Taiwan Agricultural Research Institute -TARI s Research Institute of Forests and Rangelands, Botanical Department -TARI s Trakya Agricultural Research Institute -TASH s National Academy of Science, Uzbekistan -TASM s Uzbek Academy of Sciences, Laboratory of Mycology -TAU s Aristotle University of Thessaloniki, Biology Department -TAU s Tel-Aviv University -TAUF s Aristotle University of Thessaloniki, Department of Forestry and Natural Environment -TAWES h Maryland Department of Natural Resources -TB s Tbilisi State University, Botany Department -TBG b Tsukuba Botanical Garden -TBGT s Tropical Botanic Garden and Research Institute -TBI s Georgian Academy of Sciences -TBIP s Research Institute of Plant Protection -TBPH h Iovel Kutateladze Institute of Pharmacochemistry -TBY s Tenby Museum -TCB s National Chung Hsing University, Botany Department -TCC/USP c Trypanosomatid Culture Collection, University of Sao Paulo -TCD s Trinity College -TCDL s Trinity College Library, Manuscript Department -TCDU b Trinity College, Dublin University, Department of Zoology DNA repository -TCDU s Ministry of Animal Industry and Fisheries -TCF s National Chung Hsing University, Forestry Department -TCFB c Tasmanian Collection of Fish Bacteria -TCMM c Thai Collection of Medical Microorganism, Department of Pathology, Faculty of Veterinary Science -TCNM s Timpanogos Cave National Monument -TCSW s Texas Women's University, Biology Department -TCWC s Texas Cooperative Wildlife Collection +SZU s University of Salzburg, Department of Organismic Biology +SZUB h University of Szczecin +T s Tavera, Department of Geology and Geophysics +TA s Timescale Adventures Research and Interpretive Center +TAA s Estonian Agricultural University, Institute of Agricultural and Environmental Sciences +TAAM s Institute of Agricultural and Environmental Sciences of the Estonian University of Life Sciences TAAM +TAC s Tarleton State University, Biological Sciences Department +TAD s Botanical Institute of the Tajikistan Academy of Sciences, Department of Flora and Systematics of Higher Plants +TAES s Texas A&M University, Department of Rangeland Ecology and Management +TAFIRI s Tanzania Fisheries Research Institute +TAI s National Taiwan University, Institute of Ecology and Evolutionary Biology +TAIC s Texas A&M University-Kingsville, Department of Biology +TAIE h Endemic Species Research Institute +TAIF s Taiwan Forestry Research Institute +TAIM s Taiwan Museum +TAIU s Texas A&M University - Kingsville, Texas A&I Collections +TAK s Lenin State University +TAL h Jardin botanique de Talence +TALE s Laboratoire Geologique +TALL s Tallinn Botanic Garden, Department of Environmental Education +TAM s Estonian Museum of Natural History, Botany Department +TAMA c Mycology & Metabolic Diversity Research Center, Tamagawa University Research Institute +TAMU s Texas A&M University, Biology Department +TAN s Parc de Tsimbazaza, Departement Botanique +TANE s Tanta University, Botany Department +TAR s Consiglio Nazionale delle Ricerche +TARI s Taiwan Agricultural Research Institute +TARI s Research Institute of Forests and Rangelands, Botanical Department +TARI s Trakya Agricultural Research Institute +TASH s National Academy of Science, Uzbekistan +TASM s Uzbek Academy of Sciences, Laboratory of Mycology +TAU s Aristotle University of Thessaloniki, Biology Department +TAU s Tel-Aviv University +TAUF s Aristotle University of Thessaloniki, Department of Forestry and Natural Environment +TAWES h Maryland Department of Natural Resources +TB s Tbilisi State University, Botany Department +TBG b Tsukuba Botanical Garden +TBGT s Tropical Botanic Garden and Research Institute +TBI s Georgian Academy of Sciences +TBIP s Research Institute of Plant Protection +TBPH h Iovel Kutateladze Institute of Pharmacochemistry +TBY s Tenby Museum +TCB s National Chung Hsing University, Botany Department +TCC/USP c Trypanosomatid Culture Collection, University of Sao Paulo TRYCC +TCD s Trinity College +TCDL s Trinity College Library, Manuscript Department +TCDU b Trinity College, Dublin University, Department of Zoology DNA repository +TCDU s Ministry of Animal Industry and Fisheries +TCF s National Chung Hsing University, Forestry Department +TCFB c Tasmanian Collection of Fish Bacteria +TCMM c Thai Collection of Medical Microorganism, Department of Pathology, Faculty of Veterinary Science +TCNM s Timpanogos Cave National Monument +TCSW s Texas Women's University, Biology Department +TCWC s Texas Cooperative Wildlife Collection TCWC:Birds s Texas Cooperative Wildlife Collection, Collection of Birds TCWC:Fish s Texas Cooperative Wildlife Collection, Collection of Fishes TCWC:Herp s Texas Cooperative Wildlife Collection, Collection of Amphibians and Reptiles TCWC:Invrt s Texas Cooperative Wildlife Collection, Collection of Marine Invertebrate TCWC:Mamm s Texas Cooperative Wildlife Collection, Mammal collection -TDA s Department of Agriculture, Tasmania -TDAH s Tasmanian Department of Agriculture -TDMP s Ta-Dzong Museum -TDN s Todmorden Botanical Society -TDNA b Toulouse DNA databank -TDY s Tyldesley Natural History Society -TEA s Tea Research Institute -TEB s Teberda State Reserve -TECLA s Centro Nacional de Tecnologia Agropecuaria -TEF s Centre National de la Recherche Appliquee au Developement Rural, Departement des Recherches Forestieres et Piscicoles -TEFH s Universidad Nacional Autonoma de Honduras, Departamento de Biologia -TEH s University of Tehran -TELA s Tel Aviv University, Botany Department -TELY s Tate Library -TENHS s Toynbee Natural History Society -TENN s Department of Ecology and Evolutionary Biology, University of Tennessee -TEPB s Universidade Federal do Piaui, Departamento de Biologia -TER s Indiana State University, Life Science Department -TESC s The Evergreen State College -TESRI s Taiwan Endemic Species Research Institute -TEU s Teikyo University, Education Department -TEUI h U.S. Forest Service Southwest Region, Terrestrial Ecological Unit Inventory -TEX s University of Texas at Austin, Plant Resources Center -TEXA s Blackland Experiment Station -TF s Forestry and Forest Products Research Institute -TF s Department of Mineral Resources -TFA s Forestry and Forest Products Research Institute -TFAV s Servicio Autonomo para el Desarrollo Ambiental del Estado Amazonas -TFC s Universidad de La Laguna, Departamento de Biologia Vegetal (Botanica) -TFC c Tartu Fungal Culture Collection -TFD s Tanzania Forestry Research Institute -TFDA s Tasmanian Fisheries Development Authority -TFIC s Tasmanian Forest Insect Collection -TFM s Forestry and Forest Products Research Institute -TFMC s Museo de Ciencias Naturales de Santa Cruz de Tenerife -TFRI s Taiwan Fisheries Research Institute -TGM s Janashia State Museum of Georgia -TGPI s Tiraspolskij Gosudarstvennij Pedagogiceskij Institut -TGRC b C.M. Rick Tomato Genetics Resource Center -TGU h University of Montenegro -TH s University of Tokyo -THBC s Technische Hochschule -THIB s Nicholls State University, Department of Biological Sciences -THIM s National Biodiversity Centre -THL s Grierson Museum -THO s Robert Dick Museum Library -THRI s Sequoia and Kings Canyon National Parks -THS s Tsumura Laboratory -THUP s Tunghai University -TI s Herbarium of the Department of Botany, University of Tokyo -TIC s California Department of Fish and Game -TIE s Tianjin Natural History Museum, Botany Department -TIK s Agricultural Research Centre, Plant Pathology Department -TIMGP s Institut und Museum fuer Geologie und Palaeontologie der Unversitaet -TIMJ s Tainai Insect Museum -TIMM c Institute of Medical Mycology -TIPR s Institute of Pharmaceutical Research -TISTR c TISTR Culture Collection Bangkok MIRCEN -TIU s Tokyo Imperial University, Science College Museum -TJDC s Tianjin Municipal Institute for Drug Control, Department of Traditional Chinese Medicine -TJMP s Tianjin Institute of Medical and Pharmaceutical Sciences -TK s Tomsk State University -TK s Coleccion de mamiferos del Centro Interdisciplinario de Investigacion para el Desarrollo Integral Regional Unidad Durango -TKB s University of Tsukuba -TKNM s Twickenham Girls' School -TKPM s Tokushima Prefectural Museum -TKU s Tokyo Kyoiku University -TL s Universite Paul Sabatier -TLA s Ecole Nationale Superieure Agronomique -TLF s Universite Paul Sabatier -TLHR s Thueringer Landesmuseum Heidecksburg -TLJ s Universite Paul-Sabatier -TLM s Museum d'Histoire Naturelle de Toulouse -TLMF s Tiroler Landesmuseum Ferdinandeum -TLON s Museum d'Histoire Naturelle -TLP s Faculte de Medecine, Chaire de Botanique -TLS s Tunbridge Wells Museum and Art Gallery -TLXM s Universidad Autonoma de Tlaxcala -TM s Teylers Museum, Paleontologische -TM s Slovak National Museum -TM s Transvaal Museum -TMAG s Tasmanian Museum & Art Gallery -TMAL s Tameside Metropolitan Borough Museum -TMBS s Tatsuo Tanaka Memorial Biological Laboratory -TMC s Tate Museum Collection -TMC c Trudeau Mycobacterial Culture Collection, Trudeau Institute -TMC c The Mollicutes Collection -TMDU s Tokyo Medical and Dental University -TMFE s Elasmobranchii Collection of the Department of Fisheries, Tokai University -TMH s Tasmanian Museum and Art Gallery -TMHN s Teyler Museum -TMI s Tottori Mycological Institute -TMM s Texas Memorial Museum -TMMC s Texas Memorial Museum -TMNH s Tianjin Museum of Natural History -TMP s Tampere Museums -TMP s Transvaal Museum -TMRC h Shahid Beheshti University of Medical Sciences -TMS s Toleco Museum of Health and Natural History -TMSA s Transvaal Museum -TMTC s Taiwan Provincial Museum -TNAU s Tamil Nadu Agricultural University -TNFC s Tynside Naturalists' Field Club -TNFS s USDA Forest Service, Alaska Region -TNHC s Texas Memorial Museum, Texas Natural History Collection -TNHM s University of Texas -TNM s National Museum of Natural Science, Botany Department -TNP s Museum of Tatra National Park -TNS s National Science Museum, Department of Botany -TNSC s Thierry Neef de Sainval -TNSC s Trailside Nature and Science Center -TNSM s Thailand Natural History Museum -TNU s National Taiwan Normal University, Herbarium -TNZ s Tianjin Nat. Hist. Mus. -TO s Universita degli Studi di Torino, Dipartimento di Biologia Vegetale -TOD s Todmorden Free Library -TOFO s University of Tokyo, Section of Forest Botany -TOGO s Universite du Lome, Laboratoire de Botanique et Ecologie Vegetale -TOGR s Museo di Storia Naturale Don Bosco -TOHO s Toho University -TOKE s Tokyo University of Education -TOLI s Universidad del Tolima, Departamento de Biologia -TOM s Istituto Missioni Consolata -TOM c Tomicus collection Canadian Forest Service -TON h Ministry of Agriculture and Food, Forestry and Fisheries -TONG s Tonghua Teachers College, Biology Department -TOR s Torquay Museum -TOU h University of Tours -TOYA s Toyama Science Museum, Botany Department -TPI s The Pirbright Institute +TDA s Department of Agriculture, Tasmania +TDAH s Tasmanian Department of Agriculture +TDMP s Ta-Dzong Museum +TDN s Todmorden Botanical Society +TDNA b Toulouse DNA databank +TDY s Tyldesley Natural History Society +TEA s Tea Research Institute +TEB s Teberda State Reserve +TECLA s Centro Nacional de Tecnologia Agropecuaria +TEF s Centre National de la Recherche Appliquee au Developement Rural, Departement des Recherches Forestieres et Piscicoles +TEFH s Universidad Nacional Autonoma de Honduras, Departamento de Biologia +TEH s University of Tehran +TELA s Tel Aviv University, Botany Department +TELY s Tate Library +TENHS s Toynbee Natural History Society +TENN s Department of Ecology and Evolutionary Biology, University of Tennessee +TEPB s Universidade Federal do Piaui, Departamento de Biologia +TER s Indiana State University, Life Science Department +TESC s The Evergreen State College +TESRI s Taiwan Endemic Species Research Institute +TEU s Teikyo University, Education Department +TEUI h U.S. Forest Service Southwest Region, Terrestrial Ecological Unit Inventory +TEX s University of Texas at Austin, Plant Resources Center +TEXA s Blackland Experiment Station +TF s Forestry and Forest Products Research Institute +TF s Department of Mineral Resources +TFA s Forestry and Forest Products Research Institute +TFAV s Servicio Autonomo para el Desarrollo Ambiental del Estado Amazonas +TFC s Universidad de La Laguna, Departamento de Biologia Vegetal (Botanica) +TFC c Tartu Fungal Culture Collection +TFD s Tanzania Forestry Research Institute +TFDA s Tasmanian Fisheries Development Authority +TFIC s Tasmanian Forest Insect Collection +TFM s Forestry and Forest Products Research Institute +TFMC s Museo de Ciencias Naturales de Santa Cruz de Tenerife +TFRI s Taiwan Fisheries Research Institute +TGM s Janashia State Museum of Georgia +TGPI s Tiraspolskij Gosudarstvennij Pedagogiceskij Institut +TGRC b C.M. Rick Tomato Genetics Resource Center +TGU h University of Montenegro +TH s University of Tokyo +THBC s Technische Hochschule +THIB s Nicholls State University, Department of Biological Sciences +THIM s National Biodiversity Centre +THL s Grierson Museum +THO s Robert Dick Museum Library +THRI s Sequoia and Kings Canyon National Parks +THS s Tsumura Laboratory +THUP s Tunghai University +TI s Herbarium of the Department of Botany, University of Tokyo +TIC s California Department of Fish and Game +TIE s Tianjin Natural History Museum, Botany Department +TIK s Agricultural Research Centre, Plant Pathology Department +TIMGP s Institut und Museum fuer Geologie und Palaeontologie der Unversitaet +TIMJ s Tainai Insect Museum +TIMM c Institute of Medical Mycology +TIPR s Institute of Pharmaceutical Research +TISTR c TISTR Culture Collection Bangkok MIRCEN +TIU s Tokyo Imperial University, Science College Museum +TJDC s Tianjin Municipal Institute for Drug Control, Department of Traditional Chinese Medicine +TJMP s Tianjin Institute of Medical and Pharmaceutical Sciences +TK s Tomsk State University +TK s Coleccion de mamiferos del Centro Interdisciplinario de Investigacion para el Desarrollo Integral Regional Unidad Durango +TKB s University of Tsukuba +TKNM s Twickenham Girls' School +TKPM s Tokushima Prefectural Museum +TKU s Tokyo Kyoiku University +TL s Universite Paul Sabatier +TLA s Ecole Nationale Superieure Agronomique +TLF s Universite Paul Sabatier +TLHR s Thueringer Landesmuseum Heidecksburg +TLJ s Universite Paul-Sabatier +TLM s Museum d'Histoire Naturelle de Toulouse +TLMF s Tiroler Landesmuseum Ferdinandeum +TLON s Museum d'Histoire Naturelle +TLP s Faculte de Medecine, Chaire de Botanique +TLS s Tunbridge Wells Museum and Art Gallery +TLXM s Universidad Autonoma de Tlaxcala +TM s Teylers Museum, Paleontologische +TM s Slovak National Museum +TM s Transvaal Museum TRM +TMAG s Tasmanian Museum & Art Gallery +TMAL s Tameside Metropolitan Borough Museum +TMBS s Tatsuo Tanaka Memorial Biological Laboratory +TMC s Tate Museum Collection +TMC c Trudeau Mycobacterial Culture Collection, Trudeau Institute +TMC c The Mollicutes Collection +TMDU s Tokyo Medical and Dental University +TMFE s Elasmobranchii Collection of the Department of Fisheries, Tokai University +TMH s Tasmanian Museum and Art Gallery +TMHN s Teyler Museum +TMI s Tottori Mycological Institute +TMM s Texas Memorial Museum +TMMC s Texas Memorial Museum +TMNH s Tianjin Museum of Natural History +TMP s Tampere Museums +TMP s Transvaal Museum +TMRC h Shahid Beheshti University of Medical Sciences +TMS s Toleco Museum of Health and Natural History +TMSA s Transvaal Museum +TMTC s Taiwan Provincial Museum +TNAU s Tamil Nadu Agricultural University +TNFC s Tynside Naturalists' Field Club +TNFS s USDA Forest Service, Alaska Region +TNHC s Texas Memorial Museum, Texas Natural History Collection +TNHM s University of Texas +TNM s National Museum of Natural Science, Botany Department +TNP s Museum of Tatra National Park +TNS s National Science Museum, Department of Botany +TNSC s Thierry Neef de Sainval +TNSC s Trailside Nature and Science Center +TNSM s Thailand Natural History Museum THNHM +TNU s National Taiwan Normal University, Herbarium +TNZ s Tianjin Nat. Hist. Mus. +TO s Universita degli Studi di Torino, Dipartimento di Biologia Vegetale +TOD s Todmorden Free Library +TOFO s University of Tokyo, Section of Forest Botany +TOGO s Universite du Lome, Laboratoire de Botanique et Ecologie Vegetale +TOGR s Museo di Storia Naturale Don Bosco +TOHO s Toho University +TOKE s Tokyo University of Education +TOLI s Universidad del Tolima, Departamento de Biologia +TOM s Istituto Missioni Consolata +TOM c Tomicus collection Canadian Forest Service +TON h Ministry of Agriculture and Food, Forestry and Fisheries +TONG s Tonghua Teachers College, Biology Department +TOR s Torquay Museum +TOU h University of Tours +TOYA s Toyama Science Museum, Botany Department +TPI s The Pirbright Institute TPI:ENT s The Pirbright Institute, Entomology collection -TPII s Thanksgiving Point Institute -TPNG s Department of Primary Industry -TPV s Prairie View A & M University, Biology Department -TR s Museo Tridentino di Scienze Naturali -TRA s American Plant Life Society -TRD s Ancient House Museum -TRE s Trencianske muzeum, Scientific Department -TRES s Tresco Abbey -TRH s Norwegian University of Science and Technology, Department of Natural History -TRIN s The National Herbarium of Trinidad and Tobago -TRM s Vlastivedne muzeum Trutnov -TRN s N. Copernicus University -TRO s Royal Horticultural Society of Cornwall -TROM s University of Tromsoe, Botanical Department -TROY s Troy State University, Department of Biological and Environmental Sciences -TRPM h Tottori Prefectural Museum -TRT s Royal Ontario Museum, Department of Natural History -TRTC s Royal Ontario Museum, Center for Biodiversity and Conservation Biology -TRTE s Erindale College, University of Toronto, Department of Biology -TRTS s Scarborough College, University of Toronto, Botany Department -TRU s Royal Cornwall Museum -TRV s Transvaal Museum -TS s National University of Shandong, Biology Department -TSB s Universita degli Studi di Trieste, Dipartimento di Biologia -TSC s Tarleton State University, Tarleton State Collection -TsGM s Central Geological Museum -TSH h University of Tsukuba -TSM s Erbario, Museo Civico di Storia Naturale, Trieste -TSMHN s Teylers Strichtina Museum -TsNIGRI s Tsentralny Nauchno-Issledovatelskii Geolgo-Razvedochni Muzei (Chernyshev's Central Museum of Geological Exploration) -TSSMC s Teton Science School -TSTN s Troston Hall -TSU s Miye University -TSY c Laboratory of Mycology, Division of Microbiology -TTC s Texas Tech University, Biological Sciences Department -TTCC s Texas Tech University -TTMB s Termeszettudomanyi Muzeum -TTN s Somerset County Museum -TTRS s Tall Timbers Research Station, Fire Ecology Laboratory -TTU s Texas Tech University, Museum -TTY s Westonbirt School -TU s Institut fur Geologie und Palaontologie, Technische Universitat Braunschweig -TU s University of Tartu, Botanical and Mycological Museum -TU s Tulane University, Museum of Natural History +TPII s Thanksgiving Point Institute +TPNG s Department of Primary Industry +TPV s Prairie View A & M University, Biology Department +TR s Museo Tridentino di Scienze Naturali +TRA s American Plant Life Society +TRD s Ancient House Museum +TRE s Trencianske muzeum, Scientific Department +TRES s Tresco Abbey +TRH s Norwegian University of Science and Technology, Department of Natural History +TRIN s The National Herbarium of Trinidad and Tobago +TRM s Vlastivedne muzeum Trutnov +TRN s N. Copernicus University +TRO s Royal Horticultural Society of Cornwall +TROM s University of Tromsoe, Botanical Department +TROY s Troy State University, Department of Biological and Environmental Sciences +TRPM h Tottori Prefectural Museum +TRT s Royal Ontario Museum, Department of Natural History +TRTC s Royal Ontario Museum, Center for Biodiversity and Conservation Biology +TRTE s Erindale College, University of Toronto, Department of Biology +TRTS s Scarborough College, University of Toronto, Botany Department +TRU s Royal Cornwall Museum +TRV s Transvaal Museum +TS s National University of Shandong, Biology Department +TSB s Universita degli Studi di Trieste, Dipartimento di Biologia +TSC s Tarleton State University, Tarleton State Collection +TsGM s Central Geological Museum +TSH h University of Tsukuba +TSM s Erbario, Museo Civico di Storia Naturale, Trieste +TSMHN s Teylers Strichtina Museum +TsNIGRI s Tsentralny Nauchno-Issledovatelskii Geolgo-Razvedochni Muzei (Chernyshev's Central Museum of Geological Exploration) +TSSMC s Teton Science School +TSTN s Troston Hall +TSU s Miye University +TSY c Laboratory of Mycology, Division of Microbiology +TTC s Texas Tech University, Biological Sciences Department +TTCC s Texas Tech University +TTMB s Termeszettudomanyi Muzeum +TTN s Somerset County Museum +TTRS s Tall Timbers Research Station, Fire Ecology Laboratory +TTU s Texas Tech University, Museum +TTY s Westonbirt School +TU s Institut fur Geologie und Palaontologie, Technische Universitat Braunschweig +TU s University of Tartu, Botanical and Mycological Museum +TU s Tulane University, Museum of Natural History TU:Birds s Tulane University, Museum of Natural History, Ornithological Collection TU:Fish s Tulane University, Museum of Natural History, Fish Collection TU:Herptiles s Tulane University, Museum of Natural History, Amphibian And Reptile Collection TU:Invertebrates s Tulane University, Museum of Natural History, Invertebrate Collection TU:Mammals s Tulane University, Museum of Natural History, Mammal Collection -TUAT s Tokyo University of Agriculture -TUB s Eberhard-Karls-Universitaet Tuebingen, Institut fuer Biologie I -TUBSB b Tohoku University Brassica Seed Bank -TUC s University of Arizona, Ecology and Evolutionary Biology Department -TUCH s Tribhuvan University, Central Department of Botany -TUCIM c TU Wien collection of industrial microorganisms -TUCIM: c TU Wien collection of industrial microorganisms, -TUFC s Tottori University Fungal Culture Collection -TUFIL s Tokyo University of Fisheries, Ichthyological Laboratory -TUFT s Tufts University, Biology Department -TUH s Tehran University, Department of Biology -TULE s Tokyo University of Agriculture & Technology -TULS s University of Tulsa -TULV s Jardin Botanico Juan Maria Cespedes -TUM h Technische Universitat Munchen -TUMH s Tottori Fungus/Mushroom Resource and Research Center -TUN s Universite de Tunis, Laboratoire de Biologie Vegetale -TUNG s Tunghai University, Biology Department -TUP s Trent University, Biology Department -TUPH s Institute of Public Health Research -TUR s University of Turku -TURA s Aabo Akademi University, Biology Department -TURP s Turpan Eremophytes Botanical Garden -TUS s Tohoku University, Biological Institute -TUSG s Tohoku University -TUT s Daejeon University, Department of Biology -TUTC s Tunghai University -TUZ s Tartu University Zoological Department -TV s Centro de Estratigrafia e Paleobiologia da Universidade Nova de Lisboa -TVBG s Tver State University -TVY s Turvey Abbey -TWC s Texas Wesleyan College, Museum of Zoology -TWRA s Tennessee Wildlife Resources Agency -TYF s Shangxi Forestry Institute -TYM h Botanic Gardens of Toyama -TZM s National Science Museum -U s Nationaal Herbarium Nederland, Utrecht University branch -UA s Department of Historical Geology and Paleontology -UA s University of Alabama Collection -UA s University of Arizona -UAAAC s University of Alaska Anchorage Avian Collection -UAAH s Herbarium, Department of Biological Sciences, University of Alaska Anchorage -UAAM s The Arthropod Museum, University of Arkansas -UAB s Universidad Autonoma de Barcelona -UABC s Universidad Autonoma de Baja California -UABCS s Universidad Nacional Autonoma de Baja California Sur (Mexico) -UABD s University of Alabama -UAC s University of Calgary, Department of Biological Sciences -UACC s Univeridad Autonoma de Chapingo -UACCC c University of Alabama Chytrid Culture Collection -UADBA s University dAntananarivo, Department de Biologie Animale -UADY s Universidad Autonoma de Yucatan, Departamento de Botanica -UAEM s Univeridad Autonoma de Morelos -UAEU s United Arab Emirates University -UAGC s Universidad Autonoma de Guerrero, Area de Ciencias Naturales -UAIC s University of Abidjan -UAIC s University of Alabama, Ichthyological Collection -UAIC s University of Arizona -UALRVC s University of Arkansas at Little Rock, Vertebrate Collection -UAM s University of Alaska, Museum of the North +TUAT s Tokyo University of Agriculture +TUB s Eberhard-Karls-Universitaet Tuebingen, Institut fuer Biologie I +TUBSB b Tohoku University Brassica Seed Bank +TUC s University of Arizona, Ecology and Evolutionary Biology Department +TUCH s Tribhuvan University, Central Department of Botany +TUCIM c TU Wien collection of industrial microorganisms +TUFC s Tottori University Fungal Culture Collection +TUFIL s Tokyo University of Fisheries, Ichthyological Laboratory +TUFT s Tufts University, Biology Department +TUH s Tehran University, Department of Biology +TULE s Tokyo University of Agriculture & Technology +TULS s University of Tulsa +TULV s Jardin Botanico Juan Maria Cespedes +TUM h Technische Universitat Munchen +TUMH s Tottori Fungus/Mushroom Resource and Research Center +TUN s Universite de Tunis, Laboratoire de Biologie Vegetale +TUNG s Tunghai University, Biology Department +TUP s Trent University, Biology Department +TUPH s Institute of Public Health Research +TUR s University of Turku +TURA s Aabo Akademi University, Biology Department +TURP s Turpan Eremophytes Botanical Garden +TUS s Tohoku University, Biological Institute +TUSG s Tohoku University +TUT s Daejeon University, Department of Biology +TUTC s Tunghai University +TUZ s Tartu University Zoological Department +TV s Centro de Estratigrafia e Paleobiologia da Universidade Nova de Lisboa +TVBG s Tver State University +TVY s Turvey Abbey +TWC s Texas Wesleyan College, Museum of Zoology +TWRA s Tennessee Wildlife Resources Agency +TYF s Shangxi Forestry Institute +TYM h Botanic Gardens of Toyama +TZM s National Science Museum +U s Nationaal Herbarium Nederland, Utrecht University branch +UA s Department of Historical Geology and Paleontology +UA s University of Alabama Collection +UA s University of Arizona +UAAAC s University of Alaska Anchorage Avian Collection +UAAH s Herbarium, Department of Biological Sciences, University of Alaska Anchorage +UAAM s The Arthropod Museum, University of Arkansas +UAB s Universidad Autonoma de Barcelona +UABC s Universidad Autonoma de Baja California +UABCS s Universidad Nacional Autonoma de Baja California Sur (Mexico) +UABD s University of Alabama +UAC s University of Calgary, Department of Biological Sciences +UACC s Univeridad Autonoma de Chapingo +UACCC c University of Alabama Chytrid Culture Collection UA-SEC +UADBA s University dAntananarivo, Department de Biologie Animale +UADY s Universidad Autonoma de Yucatan, Departamento de Botanica +UAEM s Univeridad Autonoma de Morelos +UAEU s United Arab Emirates University +UAGC s Universidad Autonoma de Guerrero, Area de Ciencias Naturales +UAIC s University of Abidjan +UAIC s University of Alabama, Ichthyological Collection +UAIC s University of Arizona +UALRVC s University of Arkansas at Little Rock, Vertebrate Collection +UAM s University of Alaska, Museum of the North UAF UAM:Bird s University of Alaska, Museum of the North, Bird Collection UAM:Bryo s University of Alaska, Museum of the North, Bryozoan Collection UAM:Crus s University of Alaska, Museum of the North, Marine Arthropod Collection @@ -6498,266 +6550,271 @@ UAM:Herp s University of Alaska, Museum of the North, Amphibian and Reptile Coll UAM:Mamm s University of Alaska, Museum of the North, Mammal Collection UAM:Moll s University of Alaska, Museum of the North, Mollusc Collection UAM:Paleo s University of Alaska, Museum of the North, paleontology collection -UAM c Universidad Autonoma De Madrid culture collection of cyanobacteria -UAM s University of Alabama, Malacology Collection -UAM s University of Arkansas at Monticello -UAM s Universidad de los Andes, Facultad de Ciencias -UAMH scb University of Alberta Microfungus Collection and Herbarium -UAMI s Universidad Autonoma Metropolitana, Unidad Iztapalapa (Mexico) -UAMIZ s Universidad Autonoma Metropolitana, Iztapalapa, Departamento de Biologia -UAMM s Universidad de los Andes -UAMZ s University of Alberta Museum of Zoology -UAMZC s University of Arkansas, Museum Zoological Collections -UANL s Universidad Autonoma de Nuevo Leon -UAPC h University of Alberta -UARK s University of Arkansas -UAS s Universidad Autonoma de Sinaloa -UAS-B s University of Agricultural Sciences Bangalore -UASB s University of Agricultural Sciences, Bangalore -UASC s Museo de Historia Natural "Noel Kempff Mercado" -UASK s Ukrainian Academy of Science -UASM s University of Alberta, E.H. Strickland Entomological Museum -UAT s Universidad Autonoma de Tamaulipas -UAVP s University of Alberta, Laboratory for Vertebrate Paleontology -UAWC b Union of Agricultural Work Committees -UAY s Universidad Autonoma de Yucatan, Facultad de Medicina Veterinaria y Zootecnia -UAZ s University of Arizona -UB sc University of Brasilia Herbarium -UB s Laboratoire de Biostratigraphie -UBA s Mongolian Academy of Sciences -UBC s Beaty Biodiversity Museum, University of British Columbia +UAM c Universidad Autonoma De Madrid culture collection of cyanobacteria +UAM s University of Alabama, Malacology Collection +UAM s University of Arkansas at Monticello +UAM s Universidad de los Andes, Facultad de Ciencias +UAMH scb University of Alberta Microfungus Collection and Herbarium +UAMI s Universidad Autonoma Metropolitana, Unidad Iztapalapa (Mexico) +UAMIZ s Universidad Autonoma Metropolitana, Iztapalapa, Departamento de Biologia +UAMM s Universidad de los Andes +UAMZ s University of Alberta Museum of Zoology +UAMZC s University of Arkansas, Museum Zoological Collections +UANL s Universidad Autonoma de Nuevo Leon +UAPC h University of Alberta +UARK s University of Arkansas +UAS s Universidad Autonoma de Sinaloa +UAS-B s University of Agricultural Sciences Bangalore +UASB s University of Agricultural Sciences, Bangalore +UASC s Museo de Historia Natural "Noel Kempff Mercado" +UASK s Ukrainian Academy of Science +UASM s University of Alberta, E.H. Strickland Entomological Museum +UAT s Universidad Autonoma de Tamaulipas +UAVP s University of Alberta, Laboratory for Vertebrate Paleontology +UAWC b Union of Agricultural Work Committees +UAY s Universidad Autonoma de Yucatan, Facultad de Medicina Veterinaria y Zootecnia +UAZ s University of Arizona +UB sc University of Brasilia Herbarium +UB s Laboratoire de Biostratigraphie +UBA s Mongolian Academy of Sciences +UBC s Beaty Biodiversity Museum, University of British Columbia UBC:CTC s Beaty Biodiversity Museum, University of British Columbia, Cowan Tetrapod Collection UBC:Fish s Beaty Biodiversity Museum, University of British Columbia, Fish Collection -UBCC c University of Barcelona Culture Collection -UBCZ s University of British Columbia, Spencer Entomological Museum -UBDH h Universiti Brunei Darussalam -UBJTL s Universidad Bogota Jorge Tadeo Lozano -UBL s Universite du Benin -UBOCC c Universite de Bretagne Occidentale -UBT s Oekologisch-Botanischer Garten -UBU s Mongolian State University, Botany Department -UC scb University of Canberra Wildlife Tissue Collection -UC s University of California, University Herbarium -UC c Upjohn Culture Collection -UCAC s University of Central Arkansas, Department of Biology -UCAM s Universidad Autonoma de Campeche -UCB s University of California at Berkeley -UCBG s University of Botswana, Department of Biological Sciences -UCBL s Centre de Paleontologie Stratigraphique et Paleoecologie -UCBMG c University of California Berkeley Mycogarden -UCC s University of Cincinnati -UCC s University College Cork -UCCC s Universidad de Concepcion, Museo de Zoologia -UCCM c University of Calabar Collection of Microorganisms -UCD scb University of California, Davis -UCDBA s University of Chicago -UCFC s University of Central Florida -UCGC s University of Colorado, Geological Museum -UCGE c Unit Cell of Genetic Engineering, Department of Biochemistry -UCH h Universidad Autonoma de Chiriqui -UCHT s University of Tennessee, Chattanooga, Department of Biological and Environmental Sciences -UCI s University of Ibadan, Botany and Microbiology Department -UCJ s Universite d'Abidjan, Departemente de Botanique -UCL c Catholic University of Louvain -UCL s University College London -UCLA s University of California at Los Angeles -UCLAF c HMR/Romainville -UCLGMZ s Grant Museum of Zoology and Comparative Anatomy -UCLZ s University College London -UCM s Universidad Complutense Madrid -UCM c Ukrainian Collection of Microorganisms, Zabolotny Institute of Microbiology and Virology -UCM s University of Colorado Museum +UBC:SEM s Beaty Biodiversity Museum, University of British Columbia, Spencer Entomological Museum +UBCC c University of Barcelona Culture Collection +UBCZ s University of British Columbia, Spencer Entomological Museum +UBDH h Universiti Brunei Darussalam +UBJTL s Universidad Bogota Jorge Tadeo Lozano +UBL s Universite du Benin +UBOCC c Universite de Bretagne Occidentale +UBT s Oekologisch-Botanischer Garten +UBU s Mongolian State University, Botany Department +UC scb University of Canberra Wildlife Tissue Collection +UC s University of California, University Herbarium +UC c Upjohn Culture Collection +UCAC s University of Central Arkansas, Department of Biology +UCAM s Universidad Autonoma de Campeche +UCB s University of California at Berkeley +UCBG s University of Botswana, Department of Biological Sciences +UCBL s Centre de Paleontologie Stratigraphique et Paleoecologie +UCBMG c University of California Berkeley Mycogarden +UCC s University of Cincinnati +UCC s University College Cork +UCCC s Universidad de Concepcion, Museo de Zoologia +UCCM c University of Calabar Collection of Microorganisms +UCD scb University of California, Davis +UCDBA s University of Chicago +UCDFST c Phaff Yeast Culture Collection +UCFC s University of Central Florida +UCGC s University of Colorado, Geological Museum +UCGE c Unit Cell of Genetic Engineering, Department of Biochemistry +UCH h Universidad Autonoma de Chiriqui +UCHT s University of Tennessee, Chattanooga, Department of Biological and Environmental Sciences +UCI s University of Ibadan, Botany and Microbiology Department +UCJ s Universite d'Abidjan, Departemente de Botanique +UCL c Catholic University of Louvain +UCL s University College London +UCLA s University of California at Los Angeles +UCLAF c HMR/Romainville +UCLGMZ s Grant Museum of Zoology and Comparative Anatomy +UCLZ s University College London +UCM s Universidad Complutense Madrid +UCM c Ukrainian Collection of Microorganisms, Zabolotny Institute of Microbiology and Virology +UCM s University of Colorado Museum UCM:Bird s University of Colorado Museum, University of Colorado Museum Bird Collection UCM:Fish s University of Colorado Museum, University of Colorado Museum Fish collection UCM:Herp s University of Colorado Museum, University of Colorado Museum Amplibian and Reptile collection UCM:Mamm s University of Colorado Museum, University of Colorado Museum Mammal Collection -UCMC s University of Colorado Museum -UCME s Faculdad de Biologia, Departamento de Zoologia -UCMM s Pontificia Universidad Catolica Madre y Maestra -UCMP s University of California Museum of Paleontology -UCMS s Storrs, University of Connecticut -UCNW s University of Wales -UCNZ s University of Canterbury -UCOB s Universidad Centroccidental Lisandro Alvarado, Departamento de Ciencias Biologicas -UCOCV s University of Central Oklahoma, Collection of Vertebrates -UCONN s University of Connecticut -UCP s Universidad del Cauca -UCPC s Universidad del Cauca -UCR s Universidad de Costa Rica, Museo de Zoologia -UCR s University of California, Riverside +UCMC s University of Colorado Museum +UCME s Faculdad de Biologia, Departamento de Zoologia +UCMM s Pontificia Universidad Catolica Madre y Maestra +UCMP s University of California Museum of Paleontology +UCMS s Storrs, University of Connecticut +UCNW s University of Wales +UCNZ s University of Canterbury +UCOB s Universidad Centroccidental Lisandro Alvarado, Departamento de Ciencias Biologicas +UCOCV s University of Central Oklahoma, Collection of Vertebrates +UCONN s University of Connecticut +UCP s Universidad del Cauca MHNUC +UCPC s Universidad del Cauca +UCR s Universidad de Costa Rica, Museo de Zoologia +UCR s University of California, Riverside UCR:ENT s University of California, Riverside, Entomology Collection -UCS s University of Connecticut -UCS s Union College, Department of Biological Sciences -UCSA s University College of Swansea, Botany Department -UCSB s University of California, Santa Barbara -UCSC s University of California, Department of Environmental Studies -UCSW s University College, Botany Department -UCVC s Universidad Catolica de Valparaiso -UCWI s University of the West Indies, Department of Life Sciences -UDBC s Universidad Distrital -UDCC s University of Delaware -UDEL s University of Delaware -UDM s Museo Friulano di Storia Naturale -UDO s Universidad de Oriente -UDONECI s Universidad de Oriente -UDSM s University of Dar es Salaam -UDU s Udmurt State University, Department of Biology and Chemistry -UDW s University of Durban-Westville, Botany Department -UEA s University of East Anglia -UEC s Universidade Estadual de Campinas, Departamento de Botanica -UEFS s Laboratorio de Ictiologia -UENF s Universidade Estadual do Norte Fluminense -UESC h Universidade Estadual de Santa Cruz -UESS s Universidad de El Salvador -UEVH s Universidade de Evora, Departamento de Biologia -UF sb University of Florida Museum of Natural History -UF/FGS s Florida Geological Survey +UCS s University of Connecticut +UCS s Union College, Department of Biological Sciences +UCSA s University College of Swansea, Botany Department +UCSB s University of California, Santa Barbara +UCSC s University of California, Department of Environmental Studies +UCSW s University College, Botany Department +UCVC s Universidad Catolica de Valparaiso +UCWI s University of the West Indies, Department of Life Sciences +UDBC s Universidad Distrital +UDCC s University of Delaware +UDEL s University of Delaware +UDM s Museo Friulano di Storia Naturale +UDO s Universidad de Oriente +UDONECI s Universidad de Oriente +UDSM s University of Dar es Salaam +UDU s Udmurt State University, Department of Biology and Chemistry +UDW s University of Durban-Westville, Botany Department +UEA s University of East Anglia +UEC s Universidade Estadual de Campinas, Departamento de Botanica +UEFS s Laboratorio de Ictiologia +UENF s Universidade Estadual do Norte Fluminense +UESC h Universidade Estadual de Santa Cruz +UESS s Universidad de El Salvador +UEVH s Universidade de Evora, Departamento de Biologia +UF sb University of Florida Museum of Natural History FLMNH +UF/FGS s Florida Geological Survey UF:Herpetology s University of Florida Museum of Natural History, Herpetology Collection UF:Ichthyology s University of Florida Museum of Natural History, Fish Collection UF:Invertebrate s University of Florida Museum of Natural History, Invertebrate Zoology and Malacology Collection UF:Mammalogy s University of Florida Museum of Natural History, Mammalogy Collection UF:Ornithology s University of Florida Museum of Natural History, Ornithology Skins and Skeletons Collection UF:Porifera s University of Florida Museum of Natural History, -UFA s Ufa Scientific Centre, Russian Academy of Sciences -UFACPZ h Universidade Federal do Acre/Parque Zoobotanico -UFC s Universidade Federal do Ceara, Departamento de Biologia -UFES s Universidade Federal do Espirito Santo -UFG s Universidade Federal de Goias, Unidade de Conservacao -UFH s University of Fort Hare, Botany Department -UFHNH s Utah Field House of Natural History State Park -UFJF s Universidade Federal de Juiz de Fora -UFMA s Universidade Federal do Maranhao, Curso de Farmacia -UFMG s Universidade Federal de Minas Gerais -UFMI s Universidade Federal de Mato Grosso, Instituto de Biociencias -UFMT s Universidade Federal de Mato Grosso -UFNH s Utah Field House Natural History [address unknown] -UFOP s Universidade Federal de Ouro Preto -UFP s Universidade Federal de Pernambuco, Departamento de Botanica -UFPB s Departamento de Sistematica e Ecologia -UFPEDA c Universidade Federal de Pernambuco -UFRG s Instituto de Biologia -UFRGS s Universidade Federale do Rio Grande do Sul -UFRJ sc Herbario e Colecao Fitopathologica "Verlande Duarte Silveira" -UFRJ s Departramento de Zoologia, Universidade Federal do Rio de Janeiro -UFRJIM c Departamento de Microbiologia Medica -UFRN s Universidade Federal do Rio Grande do Norte -UFRR h Universidade Federal de Roraima -UFS s Nyabyeya Forestry College, Department of Environmental Forestry -UFSC s Universidade Federal de Santa Catarina -UFScarCC c Freshwater Microalgae Collection Cultures -UFU h Ural Federal University -UFVB s Vicosa, Universidade Federal de Vicosa, Museum of Entomology -UG s Museo del Departamento de Estratigrafia y Paleontologia -UG s University of Ghana -UGAMNH s University of Georgia Museum of Natural History -UGCA s University of Georgia -UGDA s Gdansk University, Department of Plant Taxonomy and Nature Conservation -UGDZ s University of Guelph, Department of Zoology -UGG s University of Guam -UGGE s Universidad de Guayaquil -UGGG s University of Guyana -UGM s University of Guam -UGMD s Zoology Museum of the University of Ghent -UH s University of Hawaii -UHCC c University of Helsinki Cyanobacteria Culture Collection -UHI s Ussishkin House, Botany Department -UHM s Manoa, College of Tropical Agriculture, Department of Entomology -UI s University of Ibadan -UI s Bureau of Land Management -UICC c University of Indonesia Culture Collection -UIDA s University of Idaho, Bird and Mammal Museum -UIM s University of Idaho -UIMNH s University of Illinois, Museum of Natural History -UIS s Universidad Industrial de Santander, Departamento de Biologia +UFA s Ufa Scientific Centre, Russian Academy of Sciences +UFACPZ h Universidade Federal do Acre/Parque Zoobotanico +UFC s Universidade Federal do Ceara, Departamento de Biologia +UFES s Universidade Federal do Espirito Santo +UFG s Universidade Federal de Goias, Unidade de Conservacao +UFH s University of Fort Hare, Botany Department +UFHNH s Utah Field House of Natural History State Park +UFJF s Universidade Federal de Juiz de Fora +UFMA s Universidade Federal do Maranhao, Curso de Farmacia +UFMG s Universidade Federal de Minas Gerais +UFMI s Universidade Federal de Mato Grosso, Instituto de Biociencias +UFMT s Universidade Federal de Mato Grosso +UFNH s Utah Field House Natural History [address unknown] +UFOP s Universidade Federal de Ouro Preto +UFP s Universidade Federal de Pernambuco, Departamento de Botanica +UFPB s Departamento de Sistematica e Ecologia +UFPEDA c Universidade Federal de Pernambuco +UFRG s Instituto de Biologia +UFRGS s Universidade Federale do Rio Grande do Sul +UFRJ sc Herbario e Colecao Fitopathologica "Verlande Duarte Silveira" +UFRJ s Departramento de Zoologia, Universidade Federal do Rio de Janeiro +UFRJ:POR s Departramento de Zoologia, Universidade Federal do Rio de Janeiro, Porifera collection +UFRJIM c Departamento de Microbiologia Medica +UFRN s Universidade Federal do Rio Grande do Norte +UFRN:Fungos s Universidade Federal do Rio Grande do Norte, Fungal collection +UFRR h Universidade Federal de Roraima +UFS s Nyabyeya Forestry College, Department of Environmental Forestry +UFSC s Universidade Federal de Santa Catarina +UFScarCC c Freshwater Microalgae Collection Cultures +UFU h Ural Federal University +UFVB s Vicosa, Universidade Federal de Vicosa, Museum of Entomology +UG s Museo del Departamento de Estratigrafia y Paleontologia +UG s University of Ghana +UGAMNH s University of Georgia Museum of Natural History +UGCA s University of Georgia +UGDA s Gdansk University, Department of Plant Taxonomy and Nature Conservation +UGDZ s University of Guelph, Department of Zoology +UGG s University of Guam +UGGE s Universidad de Guayaquil +UGGG s University of Guyana +UGM s University of Guam +UGMD s Zoology Museum of the University of Ghent +UH s University of Hawaii +UHCC c University of Helsinki Cyanobacteria Culture Collection +UHI s Ussishkin House, Botany Department +UHM s Manoa, College of Tropical Agriculture, Department of Entomology +UI s University of Ibadan +UI s Bureau of Land Management +UICC c University of Indonesia Culture Collection +UIDA s University of Idaho, Bird and Mammal Museum +UIM s University of Idaho +UIMNH s University of Illinois, Museum of Natural History +UIS s Universidad Industrial de Santander, Departamento de Biologia UIS:H s Universidad Industrial de Santander, Departamento de Biologia, Collecion Herpetologica -UISMHN s Universidad Industrial de Santander, Museo de Historia Natural -UJAT s Universidad Juarez Autonoma de Tabasco -UJB c University of Jaffna Botany -UJIM s University of Jordan Insect Museum -UK s University of Kentucky -UKEN s University of Kentucky -UKKP c Universiti Kebangsaan Kultur Perubatan -UKKY s University of Kunming -UKM s Universitaetsklinikum Muenster -UKMB s Universiti Kebangsaan Malaysia, Botany Department -UKMHC s Universiti Kebangsaan Malaysia +UISMHN s Universidad Industrial de Santander, Museo de Historia Natural +UJAT s Universidad Juarez Autonoma de Tabasco +UJB c University of Jaffna Botany +UJIM s University of Jordan Insect Museum +UK s University of Kentucky +UKEN s University of Kentucky +UKKP c Universiti Kebangsaan Kultur Perubatan +UKKY s University of Kunming +UKM s Universitaetsklinikum Muenster +UKMB s Universiti Kebangsaan Malaysia, Botany Department +UKMHC s Universiti Kebangsaan Malaysia UKMHC:HC s Universiti Kebangsaan Malaysia, Herpetological Collection -UKMS s Universiti Kebangsaan Malaysia, Kampus Sabah -UKMS s Sudan Natural History Museum -UKS s University of Khartoum -UKSPI s Ust-Kamenogorsk State Pedagogical Institute, Botany Department -UL s University of Louisville -ULABG s Universidad de los Andes, Laboratorio de Biogeografia -ULCI s Universidad de la Laguna -ULF s Universite Laval, Departement des Sciences forestieres -ULKY s University of Louisville -ULLZ s University of Louisiana at Layafette Zoological Collection -ULM s Universitaet Ulm, Abteilung Systematische Botanik und Oekologie -ULMG s University of Leipzig -ULN s University of Lagos -ULQC s University of Laval -ULS s Universidad de La Serena, Departamento de Biologia -ULT s Al-Faateh University, Botany Department -ULV s Universidad Central de Las Villas -UM s University of Marburg -UM s University of Memphis, Mammal Collection -UM s Umtali Museum -UMA s University of Massachusetts, Museum of Zoology -UMAN s University of Manitoba, Zoological Collection -UMB s Uebersee-Museums -UMBB s Uebersee-Museum, Bremen or Department of Zoology, University of Bremen -UMBC s Univeristy of Malawi -UMBS s University of Michigan -UMD s University of Minnesota, Duluth -UMDC s University of Maryland -UMDE s University of Maine -UME s Umeaa University -UMEC s University of Massachusetts -UMED s University of Moi -UMF s University of Miami -UMF s University of Maine, Farmington -UMF s University of Michigan, Biology Department -UMFFTD c Food and Fermentation Technology Division, University of Mumbai -UMFK s University of Maine at Fort Kent, Biology Department -UMH s Universidad Miguel Hernandez, Departamento de Biologia Aplicada -UMHB s University of Mary Hardin-Baylor -UMIC s University of Mississippi -UMIM s Univeristy of Miami Ichthyological Museum -UMIP c Collection de Champignons et Actinomycetes Pathogenes -UMKC s University of Missouri -UMKL s University of Malaysia -UMKU s Uganda Museum -UMM h University of Maine at Machias -UMML s University of Miami Marine Laboratory -UMMP s University of Michigan -UMMZ s University of Michigan, Museum of Zoology +UKMS s Universiti Kebangsaan Malaysia, Kampus Sabah +UKMS s Sudan Natural History Museum +UKS s University of Khartoum +UKSPI s Ust-Kamenogorsk State Pedagogical Institute, Botany Department +UL s University of Louisville +ULABG s Universidad de los Andes, Laboratorio de Biogeografia +ULCI s Universidad de la Laguna +ULF s Universite Laval, Departement des Sciences forestieres +ULKY s University of Louisville +ULLZ s University of Louisiana at Layafette Zoological Collection USLZ +ULM s Universitaet Ulm, Abteilung Systematische Botanik und Oekologie +ULMG s University of Leipzig +ULN s University of Lagos +ULQC s University of Laval +ULS s Universidad de La Serena, Departamento de Biologia +ULT s Al-Faateh University, Botany Department +ULV s Universidad Central de Las Villas +UM s University of Marburg +UM s University of Memphis, Mammal Collection +UM s Umtali Museum +UMA s University of Massachusetts, Museum of Zoology +UMAN s University of Manitoba, Zoological Collection +UMB s Uebersee-Museums +UMBB s Uebersee-Museum, Bremen or Department of Zoology, University of Bremen +UMBC s Univeristy of Malawi +UMBS s University of Michigan +UMD s University of Minnesota, Duluth +UMDC s University of Maryland +UMDE s University of Maine +UME s Umeaa University +UMEC s University of Massachusetts +UMED s University of Moi +UMF s University of Miami +UMF s University of Maine, Farmington +UMF s University of Michigan, Biology Department +UMFFTD c Food and Fermentation Technology Division, University of Mumbai +UMFK s University of Maine at Fort Kent, Biology Department +UMH s Universidad Miguel Hernandez, Departamento de Biologia Aplicada +UMHB s University of Mary Hardin-Baylor +UMIC s University of Mississippi +UMIM s Univeristy of Miami Ichthyological Museum +UMIP c Collection de Champignons et Actinomycetes Pathogenes +UMKC s University of Missouri +UMKL s University of Malaysia +UMKU s Uganda Museum +UMM h University of Maine at Machias +UMML s University of Miami Marine Laboratory +UMMP s University of Michigan +UMMZ s University of Michigan, Museum of Zoology UMMZ:MC s University of Michigan, Museum of Zoology, Mollusk Collection -UMNH s Utah Museum of Natural History +UMNH s Utah Museum of Natural History UMNH:Mamm s Utah Museum of Natural History, Mammal collection -UMO s University Museum of Natural History -UMO s University of Maine -UMO s Dunn-Palmer Herbarium, University of Missouri, Museum Support Center -UMOC s University of Missouri, Museum of Zoology -UMRC c University of Minnesota Rhizobium Collection -UMRM s W.R. Enns Entomology Museum -UMS s Universiti Malaysia Sabah -UMSA s Instituto de Ecologia -UMSP s University of Minnesota -UMSS s Universidad Mayor de San Simon, Facultad de Ciencias y Tecnologia, Centro de Biodiversidad, Zoologia,Laboratorio de Ictiologia -UMT s Mutare Museum -UMUT s University Museum, University of Tokyo -UMUTZ s Department of Zoology, University Museum -UMZ s Univesity Museum of Zoology, Cambridge University -UMZC s University Museum of Zoology Cambridge -UMZM s University of Montana, Zoological Museum -UN s University of Nebraska -UNA s University of Alabama, Department of Biological Sciences -UNAB s Universidad Nacional, Facultad de Agronomia -UNAC s Universidad Nacional Agraria -UNAD s Universidad Nacional Agraria -UNAF s University of North Alabama, Department of Biology -UNAH s Universidad Nacional Autonoma de Honduras -UNAM s Universidad Nacional Autonoma de Mexico +UMO s University Museum of Natural History +UMO s University of Maine +UMO s Dunn-Palmer Herbarium, University of Missouri, Museum Support Center +UMOC s University of Missouri, Museum of Zoology +UMRC c University of Minnesota Rhizobium Collection +UMRM s W.R. Enns Entomology Museum +UMS s Universiti Malaysia Sabah +UMSA s Instituto de Ecologia +UMSNH s Ichthyology Collection of the Laboratory of Aquatic Biology, Michoacan University of San Nicolas de Hidalgo +UMSP s University of Minnesota +UMSS s Universidad Mayor de San Simon, Facultad de Ciencias y Tecnologia, Centro de Biodiversidad, Zoologia,Laboratorio de Ictiologia +UMT s Mutare Museum +UMUT s University Museum, University of Tokyo +UMUTZ s Department of Zoology, University Museum +UMZ s Univesity Museum of Zoology, Cambridge University +UMZC s University Museum of Zoology Cambridge +UMZM s University of Montana, Zoological Museum +UN s University of Nebraska +UNA s University of Alabama, Department of Biological Sciences +UNAB s Universidad Nacional, Facultad de Agronomia +UNAC s Universidad Nacional Agraria +UNAD s Universidad Nacional Agraria +UNAF s University of North Alabama, Department of Biology +UNAH s Universidad Nacional Autonoma de Honduras +UNAM s Universidad Nacional Autonoma de Mexico IBUNAM UNAM:CNAC s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Acaros UNAM:CNAN s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Aracnidos UNAM:CNAR s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Anfibios @@ -6769,162 +6826,163 @@ UNAM:CNMA s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Mamif UNAM:CNMO s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Moluscos UNAM:CNPE s Universidad Nacional Autonoma de Mexico, Coleccion Nacional de Peces UNAM:CNPGG s Universidad Nacional Autonoma de Mexico, Coleccion Nacional del Phylum Porifera Gerardo Green -UNAN s Universidad Nacional Autonoma de Nicaragua -UNB s Connell Memorial Herbarium -UNC-B s University of Northern Colorado -UNCA h University of North Carolina at Asheville -UNCB s Universidad Nacional de Colombia, Insituto de Ciencias Naturales de la Universidad Nacional -UNCC s Universidad Nacional de Caldas, Museo de Historia Natural -UNCC s University of North Carolina, Biology Department -UNCG c University of North Carolina at Greensboro -UNCM s Museo de Entomologia "Francisco Luis Gallego" -UNCP s Universidad Nacional de Colombia -UNCW s University of North Carolina at Wilmington -UND s University of North Dakota, Vertebrate Museum -UNDH s University of Natal Durban -UNEFM s Universidad Experimental Francisco de Miranda -UNEVR s University of Nevada, Museum of Biology -UNEX s Universidad de Extremadura, Departamento de Botanica +UNAN s Universidad Nacional Autonoma de Nicaragua +UNB s Connell Memorial Herbarium +UNC-B s University of Northern Colorado +UNCA h University of North Carolina at Asheville +UNCB s Universidad Nacional de Colombia, Insituto de Ciencias Naturales de la Universidad Nacional +UNCC s Universidad Nacional de Caldas, Museo de Historia Natural +UNCC s University of North Carolina, Biology Department +UNCG c University of North Carolina at Greensboro +UNCM s Museo de Entomologia "Francisco Luis Gallego" +UNCP s Universidad Nacional de Colombia +UNCW s University of North Carolina at Wilmington +UND s University of North Dakota, Vertebrate Museum +UNDH s University of Natal Durban +UNEFM s Universidad Experimental Francisco de Miranda +UNEVR s University of Nevada, Museum of Biology +UNEX s Universidad de Extremadura, Departamento de Botanica UNEX:FECRGA c Universidad de Extremadura, Departamento de Botanica, Fungal Endophytes Collection of the Research Group of Agronomy -UNH s University of New Hampshire -UNI s University of Northern Iowa -UNIMAS s Universiti Malaysia Sarawak -UNIN s University of the North, Botany Department -UNIP s Universidade Paulista, Laboratorio de Botanica -UNIQEM c Institute of Microbiology, Russian Academy of Sciences -UNITEC h Unitec Institute of Technology -UNL s Universidad Autonoma de Nuevo Leon -UNL s Centro de Estratigrafia e Paleobiologia da Universidade Nova de Lisboa -UNL s University of Nebraska State Museum -UNLO s Universidad Nacional Experimental de los Llanos Occidental -UNLP s Universidad Nacional de La Plata -UNLV s University of Nevada, Las Vegas, Department of Biological Sciences -UNM s University of New Mexico, Department of Biology -UNMC s University of New Mexico -UNMDP s Universidad Nacional de Mar del Plata, Mar del Plata, Argentina -UNN s University of Nigeria, Botany Department -UNNF s Universite de Nancy -UNO s University of Nebraska at Omaha -UNOAL s University of Northern Alabama -UNOVC s University of New Orleans -UNPSJB-Pv s Universidad Nacional de la Patagonia -UNR s Universidad Nacional de Rosario, Botanica y Ecologia Vegetal -UNR s University of Nevada, Museum of Biology -UNS s University of Science, Ho Chi Minh City, Vietnam -UNSA s University of Natal -UNSL s Universidad Nacional de San Luis -UNSM s University of Nebraska State Museum -UNSW c Microbiology Culture Collection, University of New South Wales -UNSW s John T. Waterhouse Herbarium -UNT s Universidad nacional de Tucumn -UNWH s University of North-West, Biological Sciences Department -UO s University of Oklahoma -UO s University of Ostrava -UOA/HCPF c UOA/HCPF University of Athens/Hellenic Collection of Pathogenic Fungi -UOG s University of Guelph +UNH s University of New Hampshire +UNI s University of Northern Iowa +UNIMAS s Universiti Malaysia Sarawak +UNIN s University of the North, Botany Department +UNIP s Universidade Paulista, Laboratorio de Botanica +UNIQEM c Institute of Microbiology, Russian Academy of Sciences +UNITEC h Unitec Institute of Technology +UNL s Universidad Autonoma de Nuevo Leon +UNL s Centro de Estratigrafia e Paleobiologia da Universidade Nova de Lisboa +UNL s University of Nebraska State Museum +UNLO s Universidad Nacional Experimental de los Llanos Occidental +UNLP s Universidad Nacional de La Plata +UNLV s University of Nevada, Las Vegas, Department of Biological Sciences +UNM s University of New Mexico, Department of Biology +UNMC s University of New Mexico +UNMDP s Universidad Nacional de Mar del Plata, Mar del Plata, Argentina +UNN s University of Nigeria, Botany Department +UNNEC s Universidad Nacional del Nordeste, Facultad de Ciencias Exactas y Naturales y Agrimensura +UNNF s Universite de Nancy +UNO s University of Nebraska at Omaha +UNOAL s University of Northern Alabama +UNOVC s University of New Orleans +UNPSJB-Pv s Universidad Nacional de la Patagonia +UNR s Universidad Nacional de Rosario, Botanica y Ecologia Vegetal +UNR s University of Nevada, Museum of Biology +UNS s University of Science, Ho Chi Minh City, Vietnam +UNSA s University of Natal +UNSL s Universidad Nacional de San Luis +UNSM s University of Nebraska State Museum +UNSW c Microbiology Culture Collection, University of New South Wales +UNSW s John T. Waterhouse Herbarium +UNT s Universidad nacional de Tucumn +UNWH s University of North-West, Biological Sciences Department +UO s University of Oklahoma +UO s University of Ostrava +UOA/HCPF c UOA/HCPF University of Athens/Hellenic Collection of Pathogenic Fungi +UOG s University of Guelph UOG:BIO b University of Guelph, Biodiversity Institute of Ontario UOG:DEBU s University of Guelph, Ontario Insect Collection -UOIC s University of Oregon -UOJ s Universidad del Oriente, Departamento de Agronomia -UOM s University of Missouri -UOMNH s University of Oregon, Museum of Natural History -UOMZ s University of Oklahoma, Stovall Museum of Zoology -UOP s University of Opole -UOPJ s Osaka Prefecture University -UOS s University of the South, Biology Department -UP s University of Papua and New Guinea -UPA s University of Patras, Department of Plant Biology -UPCB s Universidade Federal do Parana, Departamento de Botanica -UPCC c Natural Sciences Research Institute Culture Collection -UPCT h Universidad Politecnica De Cartagena -UPEI s University of Prince Edward Island, Biology Department -UPF s Universite de Polynesie Francaise Herbarium -UPIE b Unidad de Patologia Infecciosa y Epidemiologia -UPLB s Museum of Natural History, University of the Philippines -UPM s Departement des Siences de la Terre -UPM s Universiti Pertanian Malaysia, Biology Department -UPM s Udory Paleontological Museum -UPMR c Rhizobium Collection -UPMSI s Marine Science Institute -UPNA s Universidad Publica de Navarra, Departamento de Ciencias del Medio Natural -UPNG s University of Papua New Guinea, Division of Biological Sciences -UPOL s University Palacky Olomouc -UPOS s Universidad Pablo de Olavide, Ciencias Ambientales (Botanica) -UPP s Uppingham School Museum -UPPC s University of the Philippines -UPR s Puerto Rico Botanic Garden, University of Puerto Rico -UPRG s Universidad Nacional "Pedro Ruiz Gallo" -UPRM c University of Puerto Rico at Mayagueez, Rhizobium Culture Collection -UPRP s University of Puerto Rico at Rio Piedras -UPRRP s University of Puerto Rico, Biology Department -UPS s Uppsala University, Museum of Evolution, Botany Section (Fytoteket) -UPSA s University of Pretoria -UPSC c Fungal Culture Collection at the Botanical Museum -UPSU s Ulyanovsk State Pedagogical University, Department of Botany -UPSV s Uppsala University, Department of Plant Ecology -UPTC s Universidad Pedogogica y Tecnologica de Colombia, Escuela de Ciencias Biologicas -UPVB s Departamento de Geologia, Universidad del Pais Vasco -UPVLP s Laboratorio de Paleontolgia of the Universdad del Pais Vasco/Euskal Herriko Unibersitatea -UQAM s Universite du Quebec a Montreal, Departement des Sciences biologiques -UQAR s Universite du Quebec a Rimouski, Departement de biologie -UQIC s University of Queensland Insect Collection -UQTR s Universite du Quebec a Trois-Rivieres, Departement de chimie-biologie -URB s Ryukyu University Department of Zoology -URIC s University of Rhode Island -URIMC s University of Rhode Island, Mammal Collection -URM c Universidade Federal de Pernambuco -URM s University of the Ryukyus -URMU s Museo Nacional de Historia Natural, Montevideo -URO s University of the Ryukyus -URP s Museo de Historia Natural, Universidad Ricardo Palma -URT s Universita degli Studi di Roma Tre, Dipartimento di Biologia -URV s University of Richmond, Biology Department -US s Smithsonian Institution, Department of Botany -US s University of Stellenbosch -USA s University of South Alabama -USAC s University of Western Australia -USAC s Universidad de San Carlos de Guatemala -USAM s University of South Alabama, Department of Biological Sciences -USANHC s University of South Alabama, Vertebrate Natural History Collection -USAS s University of Regina, Biology Department -USB c Bacterial collection of Universita degli studi della basilicata, Dipartimento di Biologia -USBCF s U. S. Bureau of Commercial Fisheries -USBS s School of Biological Sciences, University of Science -USC s University of Southern California, Biological Sciences Department -USCC s University of Southern Colorado -USCG s Universidad de San Carlos de Guatemala -USCH s University of South Carolina, Department of Biological Sciences -USCP s University of San Carlos -USCS s University of South Carolina, Science and Mathematics Department -USCWH s United Services College -USD s Universidad Autonoma de Santo Domingo -USD s University of South Dakota -USDA sb United States Department of Agriculture +UOIC s University of Oregon +UOJ s Universidad del Oriente, Departamento de Agronomia +UOM s University of Missouri +UOMNH s University of Oregon, Museum of Natural History +UOMZ s University of Oklahoma, Stovall Museum of Zoology +UOP s University of Opole +UOPJ s Osaka Prefecture University +UOS s University of the South, Biology Department +UP s University of Papua and New Guinea +UPA s University of Patras, Department of Plant Biology +UPCB s Universidade Federal do Parana, Departamento de Botanica +UPCC c Natural Sciences Research Institute Culture Collection +UPCT h Universidad Politecnica De Cartagena +UPEI s University of Prince Edward Island, Biology Department +UPF s Universite de Polynesie Francaise Herbarium +UPIE b Unidad de Patologia Infecciosa y Epidemiologia +UPLB s Museum of Natural History, University of the Philippines +UPM s Departement des Siences de la Terre +UPM s Universiti Pertanian Malaysia, Biology Department +UPM s Udory Paleontological Museum +UPMR c Rhizobium Collection +UPMSI s Marine Science Institute +UPNA s Universidad Publica de Navarra, Departamento de Ciencias del Medio Natural +UPNG s University of Papua New Guinea, Division of Biological Sciences +UPOL s University Palacky Olomouc +UPOS s Universidad Pablo de Olavide, Ciencias Ambientales (Botanica) +UPP s Uppingham School Museum +UPPC s University of the Philippines +UPR s Puerto Rico Botanic Garden, University of Puerto Rico +UPRG s Universidad Nacional "Pedro Ruiz Gallo" +UPRM c University of Puerto Rico at Mayagueez, Rhizobium Culture Collection +UPRP s University of Puerto Rico at Rio Piedras +UPRRP s University of Puerto Rico, Biology Department +UPS s Uppsala University, Museum of Evolution, Botany Section (Fytoteket) +UPSA s University of Pretoria +UPSC c Fungal Culture Collection at the Botanical Museum +UPSU s Ulyanovsk State Pedagogical University, Department of Botany +UPSV s Uppsala University, Department of Plant Ecology +UPTC s Universidad Pedogogica y Tecnologica de Colombia, Escuela de Ciencias Biologicas +UPVB s Departamento de Geologia, Universidad del Pais Vasco +UPVLP s Laboratorio de Paleontolgia of the Universdad del Pais Vasco/Euskal Herriko Unibersitatea +UQAM s Universite du Quebec a Montreal, Departement des Sciences biologiques +UQAR s Universite du Quebec a Rimouski, Departement de biologie +UQIC s University of Queensland Insect Collection +UQTR s Universite du Quebec a Trois-Rivieres, Departement de chimie-biologie +URB s Ryukyu University Department of Zoology +URIC s University of Rhode Island +URIMC s University of Rhode Island, Mammal Collection +URM c Universidade Federal de Pernambuco +URM s University of the Ryukyus +URMU s Museo Nacional de Historia Natural, Montevideo +URO s University of the Ryukyus +URP s Museo de Historia Natural, Universidad Ricardo Palma +URT s Universita degli Studi di Roma Tre, Dipartimento di Biologia +URV s University of Richmond, Biology Department +US s Smithsonian Institution, Department of Botany USNM:US +US s University of Stellenbosch +USA s University of South Alabama +USAC s University of Western Australia +USAC s Universidad de San Carlos de Guatemala +USAM s University of South Alabama, Department of Biological Sciences +USANHC s University of South Alabama, Vertebrate Natural History Collection +USAS s University of Regina, Biology Department +USB c Bacterial collection of Universita degli studi della basilicata, Dipartimento di Biologia +USBCF s U. S. Bureau of Commercial Fisheries +USBS s School of Biological Sciences, University of Science +USC s University of Southern California, Biological Sciences Department +USCC s University of Southern Colorado +USCG s Universidad de San Carlos de Guatemala +USCH s University of South Carolina, Department of Biological Sciences +USCP s University of San Carlos +USCS s University of South Carolina, Science and Mathematics Department +USCWH s United Services College +USD s Universidad Autonoma de Santo Domingo +USD s University of South Dakota +USDA sb United States Department of Agriculture USDA:CFRA b United States Department of Agriculture, Corvallis Fragaria Catalog USDA:GRIN b United States Department of Agriculture, Germplasm Resources Information Network USDA:NCGR b United States Department of Agriculture, National Clonal Germplasm Repository USDA:NSGC sb United States Department of Agriculture, National Small Grains Collection USDA:PGRU sb United States Department of Agriculture, Plant Genetic Resources Unit USDA:USNPC s United States Department of Agriculture, US National Parasite Collection -USDAK s W. H. Over State Museum -USF s University of South Florida, Biology Department +USDAK s W. H. Over State Museum +USF s University of South Florida, Biology Department USF:CBD c University of South Florida, Biology Department, Center for Biological Defense -USFC s U. S. Fish Commission -USFS s Rocky Mountain Forest and Range Experiment Station -USGS s U.S. Geological Survey +USFC s U. S. Fish Commission +USFS s Rocky Mountain Forest and Range Experiment Station +USGS s U.S. Geological Survey USGS:ASC s U.S. Geological Survey, Alaska Science Center -USH s Ushaw College -USI s University of Southern Indiana -USJ s Universidad de Costa Rica -USLH s University of Louisiana Lafayette, Department of Renewable Resources -USM s Universiti Sains Malaysia +USH s Ushaw College +USI s University of Southern Indiana +USJ s Universidad de Costa Rica +USLH s University of Louisiana Lafayette, Department of Renewable Resources +USM s Universiti Sains Malaysia USM:VCRU s Universiti Sains Malaysia, Vector Control Research Unit -USM s Universidad Nacional Mayor de San Marcos, Museo de Historia Natural, Herbario -USMMC s Universiti Sains Malaysia Mollusc Collection -USMP h Universiti Sains Malaysia -USMS s University of Southern Mississippi, Department of Biological Sciences -USNC s Smithsonian Institution, Paleobiology Department -USNM sb National Museum of Natural History, Smithsonian Institution +USM s Universidad Nacional Mayor de San Marcos, Museo de Historia Natural, Herbario +USMMC s Universiti Sains Malaysia Mollusc Collection +USMP h Universiti Sains Malaysia +USMS s University of Southern Mississippi, Department of Biological Sciences +USNC s Smithsonian Institution, Paleobiology Department +USNM sb National Museum of Natural History, Smithsonian Institution NMNH USNM:Birds s National Museum of Natural History, Smithsonian Institution, Division of Birds USNM:ENT s National Museum of Natural History, Smithsonian Institution, Entomology Collection USNM:FISH s National Museum of Natural History, Smithsonian Institution, National Fish Collection @@ -6932,644 +6990,660 @@ USNM:Herp s National Museum of Natural History, Smithsonian Institution, Divisio USNM:IZ s National Museum of Natural History, Smithsonian Institution, Department of Invertebrate Zoology USNM:LAB b National Museum of Natural History, Smithsonian Institution, Laboratories of Analytical Biology USNM:MAMM s National Museum of Natural History, Smithsonian Institution, Division of Mammals -USNTC s U.S. National Tick Collection -USON s Universidad de Sonora, Departamento de Investigaciones Cientificas y Technologicas -USP s Universidade de Sao Paulo -USP s Universidad San Pablo-CEU (Departamento de Biologia Vegetal (seccion Botanica) -USP s University of the South Pacific -USPIY s K. D. Ushinsky Yaroslavl State Pedagogical University, Department of Botany -USRC s University of Regina -USRCB c Ukrainian Scientific-Research Cell Bank. -USSC s U.S. Soil Conservation Service -USTF s Technologische Faculteit -USTK s University of Science and Technology, Museum of Natural History -USU s United States Department of Agriculture -USUUB h Utah State University Uintah Basin -USZ s Universidad Autonoma Gabriel Rene Moreno -UT s University of Tennessee -UT s University of Utah Herbarium -UTA s University of Texas at Arlington +USNTC s U.S. National Tick Collection +USON s Universidad de Sonora, Departamento de Investigaciones Cientificas y Technologicas +USP s Universidade de Sao Paulo +USP s Universidad San Pablo-CEU (Departamento de Biologia Vegetal (seccion Botanica) +USP s University of the South Pacific +USPIY s K. D. Ushinsky Yaroslavl State Pedagogical University, Department of Botany +USRC s University of Regina +USRCB c Ukrainian Scientific-Research Cell Bank. +USSC s U.S. Soil Conservation Service +USTF s Technologische Faculteit +USTK s University of Science and Technology, Museum of Natural History +USU s United States Department of Agriculture +USUUB h Utah State University Uintah Basin +USZ s Universidad Autonoma Gabriel Rene Moreno +UT s University of Tennessee +UT s University of Utah Herbarium +UTA s University of Texas at Arlington UTA:A s University of Texas at Arlington, Amphibian Collection UTA:R s University of Texas at Arlington, Reptile collection -UTAI s Tel Aviv University -UTC s Utah State University, Biology Department -UTCI s University of Tennessee at Chattanooga Insect Collection -UTD s University of Texas, Plant Resources Center -UTE s University of Tartu -UTEP s University of Texas at El Paso, Centennial Museum -UTEP:Herp s University of Texas at El Paso, Centennial Museum, Herpetology Collection -UTEX c The Culture Collection of Algae at the University of Texas Austin -UTG s University of Tuebingen -UTGD s Geology Department, The University of Tasmania -UTHSC c University of Texas Health Science Center -UTIM s University of Tennessee Insect Museum -UTKI s University of Teheran -UTLH s University of Technology, Human Sciences Department -UTLPA s University of Texas at Austin, Laboratory of Physical Anthropology -UTMC s Universidad del Magdalena -UTMZ s University of Tennessee, Museum of Zoology -UTV s Universita degli Studi della Tuscia, Dipartimento di Agrobiologia e Agrochimica -UTZM s University of Tsukubo -UU s University of Uppsala -UU s Uzhgorod State University, Botany Department -UU s University of Utah, Department of Biology -UUC c Janet A. Robertson Collection of Ureaplasma urealyticum Cultures -UUDE h Buryat State University -UUH s Institute of General and Experimental Biology, Department of Floristics and Geobotany -UUVP s University of Utah, Vertebrate Paleontology -UUZM s Uppsala University, Zoological Museum -UV s University of Valparaiso -UV s Departamento de Biologia de la Universidad del Valle -UVA s Geological Institute of the University of Amsterdam -UVAL s Universidad del Valle de Guatemala -UVC s Coleccion de Anfibios y Reptiles, Universidad del Valle, Cali -UVCC s University of Vermont -UVCE s Colecao Entomologica, Laboratorio de Entomologia Sistematica -UVCO s Universidad de Valle -UVG s Universidad del Valle -UVGC s Collecion de Artropodos -UVIC s University of Victoria, Biology Department -UVM s Zadock Thompson Natural History Collection, University of Vermont -UVP s Utah State Vertebrate Paleontology Collection -UVSC s Utah Valley State College, Biology Department -UVST s Southwest Texas Junior College, Biology Department -UVV s Universita di Venezia, Dipartimento de Scienze Ambientali -UW s University of Washington Fish Collection -UWA s University of Western Australia, Botany Department -UWAL h University of West Alabama -UWBM s University of Washington, Burke Museum +UTAI s Tel Aviv University +UTC s Utah State University, Biology Department +UTCI s University of Tennessee at Chattanooga Insect Collection +UTD s University of Texas, Plant Resources Center +UTE s University of Tartu +UTEP s University of Texas at El Paso Biodiversity Collections +UTEP:Bird s University of Texas at El Paso Biodiversity Collections, Ornithology Collection +UTEP:Ento s University of Texas at El Paso Biodiversity Collections, Entomology Collection +UTEP:ES s University of Texas at El Paso Biodiversity Collections, Earth Science fossils Collections +UTEP:Fish s University of Texas at El Paso Biodiversity Collections, Ichthyology collection +UTEP:Herb s University of Texas at El Paso Biodiversity Collections, Herbarium +UTEP:Herp s University of Texas at El Paso Biodiversity Collections, Herpetology Collection +UTEP:INV s University of Texas at El Paso Biodiversity Collections, Invertebrates - Molluscs Collections +UTEP:Zoo s University of Texas at El Paso Biodiversity Collections, Zooplankton collections +UTEX c The Culture Collection of Algae at the University of Texas Austin +UTG s University of Tuebingen +UTGD s Geology Department, The University of Tasmania +UTHSC c University of Texas Health Science Center +UTIM s University of Tennessee Insect Museum +UTKI s University of Teheran +UTLH s University of Technology, Human Sciences Department +UTLPA s University of Texas at Austin, Laboratory of Physical Anthropology +UTMC s Universidad del Magdalena +UTMC c University of Tehran Microorganisms Collection +UTMZ s University of Tennessee, Museum of Zoology +UTV s Universita degli Studi della Tuscia, Dipartimento di Agrobiologia e Agrochimica +UTZM s University of Tsukubo +UU s University of Uppsala +UU s Uzhgorod State University, Botany Department +UU s University of Utah, Department of Biology +UUC c Janet A. Robertson Collection of Ureaplasma urealyticum Cultures +UUDE h Buryat State University +UUH s Institute of General and Experimental Biology, Department of Floristics and Geobotany +UUVP s University of Utah, Vertebrate Paleontology +UUZM s Uppsala University, Zoological Museum +UV s University of Valparaiso +UV s Departamento de Biologia de la Universidad del Valle +UVA s Geological Institute of the University of Amsterdam +UVAL s Universidad del Valle de Guatemala +UVC s Coleccion de Anfibios y Reptiles, Universidad del Valle, Cali +UVCC s University of Vermont +UVCE s Colecao Entomologica, Laboratorio de Entomologia Sistematica +UVCO s Universidad de Valle +UVG s Universidad del Valle +UVGC s Collecion de Artropodos +UVIC s University of Victoria, Biology Department +UVM s Zadock Thompson Natural History Collection, University of Vermont +UVP s Utah State Vertebrate Paleontology Collection +UVSC s Utah Valley State College, Biology Department +UVST s Southwest Texas Junior College, Biology Department +UVV s Universita di Venezia, Dipartimento de Scienze Ambientali +UW s University of Washington Fish Collection +UWA s University of Western Australia, Botany Department +UWAL h University of West Alabama +UWBM s University of Washington, Burke Museum UWBM:Mamm s University of Washington, Burke Museum, Burke Museum's mammal collection UWBM:ORN s University of Washington, Burke Museum, Ornithology Collection -UWC s University of the Western Cape, Botany Department -UWCC c University of Washington Culture Collection -UWCP s University of Wroclaw -UWEC s University of Wisconsin, Department of Biology -UWFP s University of West Florida, Department of Biology -UWGB s University of Wisconsin-Green Bay, MAC 212 -UWI s University of the West Indies (Trinidad and Tobago) -UWIC s University of the West Indies, Trinidad and Tobago -UWIJ s University of the West Indies, Jamaica -UWIZM s The University of the West Indies Zoology Museum -UWJ s University of Wisconsin, Biology Department -UWL s University of Wisconsin, Biology Department -UWM s University of Wisconsin, Biological Sciences Department -UWMA s University of Wisconsin, Milwaukee, Department of Anthropology -UWMIL s University of Wisconsin, Milwaukee, Department of Biological Sciences -UWO c University of Western Ontario -UWOC s University of Western Ontario -UWP s University of Wrocklaw -UWPG s University of Winnipeg, Biology Department -UWSP s University of Wisconsin-Stevens Point, -UWW s University of Wisconsin - Whitewater, Biological Sciences Department -UWYMV s University of Wyoming Museum of Vertebrates +UWC s University of the Western Cape, Botany Department +UWCC c University of Washington Culture Collection +UWCP s University of Wroclaw +UWEC s University of Wisconsin, Department of Biology +UWFP s University of West Florida, Department of Biology +UWGB s University of Wisconsin-Green Bay, MAC 212 +UWI s University of the West Indies (Trinidad and Tobago) +UWIC s University of the West Indies, Trinidad and Tobago +UWIJ s University of the West Indies, Jamaica +UWIZM s The University of the West Indies Zoology Museum +UWJ s University of Wisconsin, Biology Department +UWL s University of Wisconsin, Biology Department +UWM s University of Wisconsin, Biological Sciences Department +UWMA s University of Wisconsin, Milwaukee, Department of Anthropology +UWMIL s University of Wisconsin, Milwaukee, Department of Biological Sciences +UWO sc University of Western Ontario +UWOC s University of Western Ontario +UWP s University of Wrocklaw +UWPG s University of Winnipeg, Biology Department +UWSP s University of Wisconsin-Stevens Point, +UWW s University of Wisconsin - Whitewater, Biological Sciences Department +UWYMV s University of Wyoming Museum of Vertebrates UWYMV:Bird s University of Wyoming Museum of Vertebrates, Bird Collection UWYMV:Fish s University of Wyoming Museum of Vertebrates, Fish Collection UWYMV:Herp s University of Wyoming Museum of Vertebrates, Herpetology Collection UWYMV:Mamm s University of Wyoming Museum of Vertebrates, Mammal Collection -UWZM s University of Wisconsin, Zoological Museum -UYIC s Instituto de Biologia -UZ s Herbario de la Universidad de Zaragoza -UZA s Unidad de Zoologia Aplicada, Departamento de Ecologia -UZIU s Uppsala University -UZL s University of Zambia, Biological Sciences Department -UZMC s Universidad del Zulia -UZMH s University Museum (Zoology) -UZMO s Zoologisk Museum -V s Royal British Columbia Museum - Herbarium -VA s University of Virginia -VAB s Universitat de Valencia, Departamento de Biologia Vegetal -VAIC s Victorian Agricultural Insect Collection -VAL sb Universitat de Valencia (Jardin Botanico de Valencia) -VALA s Universidad Politecnica, Departamento de Botanica -VALD s Universidad Austral de Chile, Instituto de Botanica -VALLE s Universidad Nacional de Colombia, Departamento de Ciencias Basicas -VALPL s Universidad de Playa Ancha, Departamento de Biologia y Quimica -VAN s Societe Polymathique du Morbihan -VANF s Yuezuencue Yil University, Biology Section -VAS s Vassar College, Biology Department -VBCM s Universidad Complutense de Madrid -VBGI s Botanical Garden-Institute -VBI s Institute of Ecology and Botany of the Hungarian Academy of Sciences, Botanical Department -VCRC c Volcani Center Rhizobium Collection (VCRC) -VCU s Virginia Commonwealth University, Biology Department -VDAC s Virginia Department of Agriculture and Consumer Services -VDAM s Institute of Plant Science -VDB s Vanderbilt University, Department of Biological Sciences -VECTOR sc State Research Center of Virology and Biotechnology -VEN s Fundacion Instituto Botanico de Venezuela Dr. Tobias Lasser -VENDA s Thohoyandou Botanical Gardens, Department of Agriculture, Land & Environment -VER s Herbario, Museo Civico di Storia Naturale, Verona -VETMED s University of Veterinary Medicine -VF s Universidad de Valencia, Departamento de Biologia Vegetal, Botanica -VFM h Forest Inventory and Planning Institute -VFWD s Vermont Fish and Wildlife Department -VFWO h U.S. Fish and Wildlife Service, Ventura Fish and Wildlife Office -VGZ s Voronezh State Biosphere Reserve, Research Department -VH h Vivekanand Arts Sardar Dalipsingh Commerce and Science College -VHS c Vegetation Health Service ( Phytophthora cultures ) -VI c Mykotektet, National Veterinary Institute -VI s Gotlands Fornsal -VIA s FONAIAP-CENIAP -VIAM c Institute of Applied Microbiology, University of Agricultural Sciences -VIAY s Veterinarian Institute of Armenia, Botany Department -VIC s Universidade Federal de Vicosa, Departamento de Biologia Vegetal -VICA s Agriculture Department -VICF s Forestry Department -VICH s Plant Protection Department -VIES h Federal University of Espirito Santo -VIL s Universite de Paris-Sud -VIMS s Virginia Institute of Marine Science -VIST s University of the Virgin Islands, Natural Resources Program -VIT s Museo de Ciencias Naturales de Alava, Departamento de Botanica -VIZR c Collection for plant protection, All-Russian Institute of Plant Protection -VKM c All-Russian Collection of Microorganisms -VKPM c Russian National Collection of Industrial Microorganisms -VLA s Far Eastern Branch, Russian Academy of Sciences, Botany Department -VM s Okresni vlastivedne muzeum -VMI h Virginia Military Institute -VMIL s Virginia Military Institute, Biology Department -VMKSC s Kearney State University, Vertebrate Museum -VMM s Vanderbilt Marine Museum -VMNH s Virginia Museum of Natural History -VMSL s I.N.T.A., E.E.A. San Luis, Pastizales Naturales -VNC s Los Angeles Valley College, Life Sciences Department -VNF h Vietnam Forestry Herbarium -VNGA s Vorarlberger Naturschau -VNIRO s Institute of Oceanography -VNM h Institute of Tropical Biology -VNMN s Vietnam National Museum of Nature -VOA s Ostrobothnian Museum -VOR s Voronezh State University, Biology and Plant Ecology Department -VORB h Botanical Garden Dr. B.M. Kozo-Polyansky, Voronezh State University -VORG s Voronezh State University, Faculty of Geography and Geoecology -VPB c Veterinary Pathology and Bacteriology Collection -VPCI c Fungal Culture Collection -VPI sc Virginia Polytechnic Institute and State University -VPIC s Virginia Polytechnic Institute and State University -VPIMM s Virginia Polytechnic University, Mammal Museum -VPM s Volgograd Provincial Museum -VPRI c Victoria Department of Primary Industries, Plant Disease Herbarium -VRLI c Department of Virology -VSC s Valdosta State University, Biology Department -VSC-L s Lyndon State College, Mammal Collection -VSCA s Visayas State College of Agriculture -VSM s Det Kgl. Norske Videnskabers Selskab Museet -VSM s Eastern Slovakian (Vychodoslovenske) Museum, Natural History Department -VSRI s N.I. Vavilov All-Russian Scientific Research Instiutte of Plant Industry -VSUH s Virginia State University, Life Sciences Department -VT s Pringle Herbarium, University of Vermont -VTA h Jardin Botanique de la Villa Thuret -VTB c Banco de Celulas Humanas e Animais Laboratorio de Patologia Celular e Molecular -VTCC c Vietnam Type Culture Collection, Center of Biotechnology -VTT c VTT Biotechnology, Culture Collection -VU s Voronezh State University -VUT c School of Veterinary Medicine, Faculty of Agriculture -VUW s Victoria University -VUWE s Victoria University -VYH c Finnish Environment Institute (SYKE) -VYM s Muzeum Vyakovska -W s Naturhistorisches Museum Wien, Department of Botany -WA s Herbarium, Faculty of Biology, University of Warsaw -WAB s Wabash College, Biological Sciences Department -WABG h University of Warsaw Botanic Garden -WAC c Department of Agriculture Western Australia Plant Pathogen Collection -WACA s Walnut Canyon National Monument -WACA s Work Amber Collection -WACC c Western Australian Culture Collection -WADA s Western Australia Department of Agriculture -WAG s Wageningen University -WAHO s Institute of Horticultural Plant Breeding, Department of Biosystematics -WAI h Waimea Valley -WAIK s University of Waikato, Biological Sciences Department -WAITE c Insect Pathology Pathogen Collection -WAL c Wadsworth Anaerobe Laboratory, Wadsworth Hospital Center -WAM s Western Australian Museum -WAMP s Western Australian Museum -WAN s Forest Research Station -WANF s Wasatch-Cache National Forest -WAPA h War in the Pacific National Historical Park -WAR s Warwickshire Museum, Natural History Department -WARC c New Zealand Reference Culture Collection -WARK s Western Illinois University, Biology Department -WARM s Central Missouri State University, Biology Department -WARMS s Warwickshire Museum, Natural History Department -WARS s Wildlife Advisory and Research Service -WASH s Washburn University, Biology Department -WAT s University of Waterloo, Biology Department -WAU s Wau Ecology Institute -WAUF s Warsaw Agricultural University, Department of Plant Pathology -WAVI s Colby College, Biology Department -WB s Universitaet Wuerzburg -WB c Department of Bacteriology, University of Wisconsin -WBCH s Wisbech and Fenland Museum -WBG s Waimea Botanical Garden -WBM s Universitaet Wuerzburg -WBR s Laboratoire de Paleontologie, Unversite de Montpellier -WBS s Landbouwuniversiteit -WCE s University of London, Westfield College, Biology Department -WCH s Greenwich Borough Museum -WCL s Willesden Borough Council -WCP s Walla Walla College, Biological Sciences Department -WCR s Winchester City Museum -WCRP s Winchester Public Library -WCSBG h West China Subalpine Botanical Garden -WCSU s Western Connecticut State University, Department of Biological and Environmental Sciences -WCU s West China University of Medical Sciences -WCUH s Western Carolina University, Department of Biology -WCUM c Working Collection -WCUUM s West China Union University -WCW s Whitman College, Department of Biology -WDds c Raul Lopez Sanchez -WDNE s Bureau of Land Management, Winnemucca District -WECO s Wesleyan University, Biology Department -WEIC s Wau Ecology Institute -WELC s Wellesley College, Biological Sciences Department -WELT s Museum of New Zealand Te Papa Tongarewa -WELTU s Victoria University of Wellington -WERN s Werneth Park Study Centre and Natural History Museum -WET s Wartburg College, Biology Department -WFBM s W.F. Barr Entomological Collection -WFBVA s Federal Forest Research Centre Vienna, Department of Vegetation Science -WFIS s Wagner Free Institute of Science -WFU s Wake Forest University, Biology Department -WFUVC s Wake Forest University, Vertebrate Collection -WGC s State University of West Georgia, Biology Department -WGCH h Wilton Garden Club -WGD s Washington Game Department -WGMM s Woodspring Museum -WGRC b Wheat Genetics Resource Center -WGRS s Western Ghat Regional Station of the Zoological Survey of India at Calicut -WH s Wuhan University -WHB s Universitaet fuer Bodenkultur -WHIT s Whittier College, Biology Department -WHM s West Highland Museum -WHN s Whitehaven Museum -WHOI s Woods Hole Oceanographic Institution -WHY s Whitby Museum -WHYNC s Whytby Naturalists' Club -WI s Vilnius University, Botany and Genetics Department -WIAP s Wistar Institute of Anatomy -WIB s Ministry of Environment and Parks, Resource Quality Section -WIBF s West Indian Beetle Fauna Project Collection -WIBG s Windward Islands Banana Grower's Association -WICA s Wind Cave National Park -WICH h Wichita State University -WIES s Museum Wiesbaden -WII s Wildlife Institute of India, Department of Habitat Ecology -WILLI s The College of William and Mary, Department of Biology -WILLU s Willamette University -WIN s University of Manitoba, Botany Department -WINC s Waite Insect & Nematode Collection -WIND s National Botanical Research Institute -WINDM s Delta Marsh Field Station (University of Manitoba) -WINF s Forestry and Rural Developmen Department -WINFM s Forestry and Rural Developmen Department -WINO s Saint Mary's College, Biology Department -WINU h Winthrop University -WIR sb N. I. Vavilov Institute of Plant Industry, Department of Introduction and Systematics -WIS s University of Wisconsin, Botany Department -WIU s Western Illinois University, Museum of Natural History -WIUC s Western Illinois University -WJC s William Jewell College, Biology Department -WKD s Wakefield Museum -WKDS s Wakefield Grammar School -WKSU s Western Kentucky State University -WKU s Western Kentucky University, Department of Biology -WL s Wolong Nature Reserve -WLH s Wilberforce Library -WLK s British Columbia Ministry of Forests -WLMH s West Lake Musuem -WLU s Wilfrid Laurier University, Biology Department -WM s Gezira Research Station -WMGC s Gordon College, Biology Department -WMM s Witte Memorial Museum -WMNH s Wakayama Prefectural Museum of Natural History -WMS s Wakes Museum -WMU s Western Michigan University, Biological Sciences Department -WMW s Vestry House Museum -WNC s University of North Carolina Wilmington, Department of Biology and Marine Biology -WNHM s Oklahoma Baptist University, Webster Natural History Museum -WNLM s Niederoesterreichisches Landesmuseum -WNMU s Western New Mexico University Museum +UWZM s University of Wisconsin, Zoological Museum +UYIC s Instituto de Biologia +UZ s Herbario de la Universidad de Zaragoza +UZA s Unidad de Zoologia Aplicada, Departamento de Ecologia +UZIU s Uppsala University +UZL s University of Zambia, Biological Sciences Department +UZMC s Universidad del Zulia +UZMH s University Museum (Zoology) +UZMO s Zoologisk Museum +V s Royal British Columbia Museum - Herbarium +VA s University of Virginia +VAB s Universitat de Valencia, Departamento de Biologia Vegetal +VAIC s Victorian Agricultural Insect Collection +VAL sb Universitat de Valencia (Jardin Botanico de Valencia) +VALA s Universidad Politecnica, Departamento de Botanica +VALD s Universidad Austral de Chile, Instituto de Botanica +VALLE s Universidad Nacional de Colombia, Departamento de Ciencias Basicas +VALPL s Universidad de Playa Ancha, Departamento de Biologia y Quimica +VAN s Societe Polymathique du Morbihan +VANF s Yuezuencue Yil University, Biology Section +VAS s Vassar College, Biology Department +VBCM s Universidad Complutense de Madrid +VBGI s Botanical Garden-Institute +VBI s Institute of Ecology and Botany of the Hungarian Academy of Sciences, Botanical Department +VCRC c Volcani Center Rhizobium Collection (VCRC) +VCU s Virginia Commonwealth University, Biology Department +VDAC s Virginia Department of Agriculture and Consumer Services +VDAM s Institute of Plant Science +VDB s Vanderbilt University, Department of Biological Sciences +VECTOR sc State Research Center of Virology and Biotechnology +VEN s Fundacion Instituto Botanico de Venezuela Dr. Tobias Lasser +VENDA s Thohoyandou Botanical Gardens, Department of Agriculture, Land & Environment +VER s Herbario, Museo Civico di Storia Naturale, Verona +VETMED s University of Veterinary Medicine +VF s Universidad de Valencia, Departamento de Biologia Vegetal, Botanica +VFM h Forest Inventory and Planning Institute +VFWD s Vermont Fish and Wildlife Department +VFWO h U.S. Fish and Wildlife Service, Ventura Fish and Wildlife Office +VGZ s Voronezh State Biosphere Reserve, Research Department +VH h Vivekanand Arts Sardar Dalipsingh Commerce and Science College +VHS c Vegetation Health Service ( Phytophthora cultures ) +VI c Mykotektet, National Veterinary Institute +VI s Gotlands Fornsal +VIA s FONAIAP-CENIAP +VIAM c Institute of Applied Microbiology, University of Agricultural Sciences +VIAY s Veterinarian Institute of Armenia, Botany Department +VIC s Universidade Federal de Vicosa, Departamento de Biologia Vegetal +VICA s Agriculture Department +VICF s Forestry Department +VICH s Plant Protection Department +VIES h Federal University of Espirito Santo +VIL s Universite de Paris-Sud +VIMS s Virginia Institute of Marine Science +VIST s University of the Virgin Islands, Natural Resources Program +VIT s Museo de Ciencias Naturales de Alava, Departamento de Botanica +VIZR c Collection for plant protection, All-Russian Institute of Plant Protection +VKM c All-Russian Collection of Microorganisms +VKPM c Russian National Collection of Industrial Microorganisms +VLA s Far Eastern Branch, Russian Academy of Sciences, Botany Department +VM s Okresni vlastivedne muzeum +VMI h Virginia Military Institute +VMIL s Virginia Military Institute, Biology Department +VMKSC s Kearney State University, Vertebrate Museum +VMM s Vanderbilt Marine Museum +VMNH s Virginia Museum of Natural History +VMSL s I.N.T.A., E.E.A. San Luis, Pastizales Naturales +VNC s Los Angeles Valley College, Life Sciences Department +VNF h Vietnam Forestry Herbarium +VNGA s Vorarlberger Naturschau +VNIRO s Institute of Oceanography +VNM h Institute of Tropical Biology +VNMN s Vietnam National Museum of Nature +VOA s Ostrobothnian Museum +VOR s Voronezh State University, Biology and Plant Ecology Department +VORB h Botanical Garden Dr. B.M. Kozo-Polyansky, Voronezh State University +VORG s Voronezh State University, Faculty of Geography and Geoecology +VPB c Veterinary Pathology and Bacteriology Collection +VPCI c Fungal Culture Collection +VPI sc Virginia Polytechnic Institute and State University +VPIC s Virginia Polytechnic Institute and State University +VPIMM s Virginia Polytechnic University, Mammal Museum +VPM s Volgograd Provincial Museum +VPRI c Victoria Department of Primary Industries, Plant Disease Herbarium +VRLI c Department of Virology +VSC s Valdosta State University, Biology Department +VSC-L s Lyndon State College, Mammal Collection +VSCA s Visayas State College of Agriculture +VSM s Det Kgl. Norske Videnskabers Selskab Museet +VSM s Eastern Slovakian (Vychodoslovenske) Museum, Natural History Department +VSRI s N.I. Vavilov All-Russian Scientific Research Instiutte of Plant Industry +VSUH s Virginia State University, Life Sciences Department +VT s Pringle Herbarium, University of Vermont +VTA h Jardin Botanique de la Villa Thuret +VTB c Banco de Celulas Humanas e Animais Laboratorio de Patologia Celular e Molecular +VTCC c Vietnam Type Culture Collection, Center of Biotechnology +VTMH s Virginia Tech Massey Herbarium +VTT c VTT Biotechnology, Culture Collection +VU s Voronezh State University +VU s Vrije Universiteit Amsterdam +VUT c School of Veterinary Medicine, Faculty of Agriculture +VUW s Victoria University +VUWE s Victoria University +VYH c Finnish Environment Institute (SYKE) +VYM s Muzeum Vyakovska +W s Naturhistorisches Museum Wien, Department of Botany +WA s Herbarium, Faculty of Biology, University of Warsaw +WAB s Wabash College, Biological Sciences Department +WABG s University of Warsaw Botanic Garden +WAC c Department of Agriculture Western Australia Plant Pathogen Collection +WACA s Walnut Canyon National Monument +WACA s Work Amber Collection +WACC c Western Australian Culture Collection +WADA s Western Australia Department of Agriculture +WAG s Wageningen University +WAHO s Institute of Horticultural Plant Breeding, Department of Biosystematics +WAI h Waimea Valley +WAIK s University of Waikato, Biological Sciences Department +WAITE c Insect Pathology Pathogen Collection +WAL c Wadsworth Anaerobe Laboratory, Wadsworth Hospital Center +WAM s Western Australian Museum +WAMP s Western Australian Museum +WAN s Forest Research Station +WANF s Wasatch-Cache National Forest +WAPA h War in the Pacific National Historical Park +WAR s Warwickshire Museum, Natural History Department +WARC c New Zealand Reference Culture Collection +WARK s Western Illinois University, Biology Department +WARM s Central Missouri State University, Biology Department +WARMS s Warwickshire Museum, Natural History Department +WARS s Wildlife Advisory and Research Service +WASH s Washburn University, Biology Department +WAT s University of Waterloo, Biology Department +WAU s Wau Ecology Institute +WAUF s Warsaw Agricultural University, Department of Plant Pathology +WAVI s Colby College, Biology Department +WB s Universitaet Wuerzburg +WB c Department of Bacteriology, University of Wisconsin +WBCH s Wisbech and Fenland Museum +WBG s Waimea Botanical Garden +WBM s Universitaet Wuerzburg +WBR s Laboratoire de Paleontologie, Unversite de Montpellier +WBS s Landbouwuniversiteit +WCE s University of London, Westfield College, Biology Department +WCH s Greenwich Borough Museum +WCL s Willesden Borough Council +WCP s Walla Walla College, Biological Sciences Department +WCR s Winchester City Museum +WCRP s Winchester Public Library +WCSBG h West China Subalpine Botanical Garden +WCSU s Western Connecticut State University, Department of Biological and Environmental Sciences +WCU s West China University of Medical Sciences +WCUH s Western Carolina University, Department of Biology +WCUM c Working Collection +WCUUM s West China Union University +WCW s Whitman College, Department of Biology +WDds c Raul Lopez Sanchez +WDNE s Bureau of Land Management, Winnemucca District +WECO s Wesleyan University, Biology Department +WEIC s Wau Ecology Institute +WELC s Wellesley College, Biological Sciences Department +WELT s Museum of New Zealand Te Papa Tongarewa +WELTU s Victoria University of Wellington +WERN s Werneth Park Study Centre and Natural History Museum +WET s Wartburg College, Biology Department +WFBM s W.F. Barr Entomological Collection +WFBVA s Federal Forest Research Centre Vienna, Department of Vegetation Science +WFIS s Wagner Free Institute of Science +WFU s Wake Forest University, Biology Department +WFUVC s Wake Forest University, Vertebrate Collection +WGC s State University of West Georgia, Biology Department +WGCH h Wilton Garden Club +WGD s Washington Game Department +WGMM s Woodspring Museum +WGRC b Wheat Genetics Resource Center +WGRS s Western Ghat Regional Station of the Zoological Survey of India at Calicut +WH s Wuhan University +WHB s Universitaet fuer Bodenkultur +WHIT s Whittier College, Biology Department +WHM s West Highland Museum +WHN s Whitehaven Museum +WHOI s Woods Hole Oceanographic Institution +WHT s Wildlife Heritage Trust +WHY s Whitby Museum +WHYNC s Whytby Naturalists' Club +WI s Vilnius University, Botany and Genetics Department +WIAP s Wistar Institute of Anatomy +WIB s Ministry of Environment and Parks, Resource Quality Section +WIBF s West Indian Beetle Fauna Project Collection +WIBG s Windward Islands Banana Grower's Association +WICA s Wind Cave National Park +WICH h Wichita State University +WIES s Museum Wiesbaden +WII s Wildlife Institute of India, Department of Habitat Ecology +WILLI s The College of William and Mary, Department of Biology +WILLU s Willamette University +WIN s University of Manitoba, Botany Department +WINC s Waite Insect & Nematode Collection +WIND s National Botanical Research Institute +WINDM s Delta Marsh Field Station (University of Manitoba) +WINF s Forestry and Rural Developmen Department +WINFM s Forestry and Rural Developmen Department +WINO s Saint Mary's College, Biology Department +WINU h Winthrop University +WIR sb N. I. Vavilov Institute of Plant Industry, Department of Introduction and Systematics +WIS s University of Wisconsin, Botany Department +WIU s Western Illinois University, Museum of Natural History +WIUC s Western Illinois University +WJC s William Jewell College, Biology Department +WKD s Wakefield Museum +WKDS s Wakefield Grammar School +WKSU s Western Kentucky State University +WKU s Western Kentucky University, Department of Biology +WL s Wolong Nature Reserve +WLH s Wilberforce Library +WLK s British Columbia Ministry of Forests +WLMH s West Lake Musuem +WLU s Wilfrid Laurier University, Biology Department +WM s Gezira Research Station +WMGC s Gordon College, Biology Department +WMM s Witte Memorial Museum +WMNH s Wakayama Prefectural Museum of Natural History +WMS s Wakes Museum +WMU s Western Michigan University, Biological Sciences Department +WMW s Vestry House Museum +WNC s University of North Carolina Wilmington, Department of Biology and Marine Biology +WNHM s Oklahoma Baptist University, Webster Natural History Museum +WNLM s Niederoesterreichisches Landesmuseum +WNMU s Western New Mexico University Museum WNMU:Bird s Western New Mexico University Museum, bird collection WNMU:Fish s Western New Mexico University Museum, fish collection WNMU:Mamm s Western New Mexico University Museum, mammal collection -WNRE s Whiteshell Nuclear Research Establishment -WNS s Wiesbaden Naturwissenschaftliche Sammlung der Stadt -WNU s Northwest University, Biology Department -WOCB s University of Windsor, Biological Sciences Department -WOCSB b Wheeler Orchid Collection and Species Bank -WOH s Southwestern Oklahoma State University, Biology Department -WOLL s University of Wollongong, Department of Biological Sciences -WOS s City Museum and Art Gallery -WOSNH s Worcestershire Natural History Society Museum -WPBS c WPBS Rhizobium Collection -WPC cb World Phytophthora Genetic Resource Collection -WPH s Waterton Lakes National Park -WPL s Whitechapel Museum -WPMM s State Museum of Pennsylvania -WRC b Wildlife Research Center of Kyoto University -WRHM s Institute of Terrestrial Ecology -WRL c The Wellcome Bacterial Collection -WRN s Warrington Museum and Art Gallery -WRNFC s Warrington Field Naturalists' Club -WRO s University of Bristol, Long Ashton Research Station -WRSL s Wroclaw University, Botany Department -WS s Washington State University -WSBC s Wichita State University -WSBC c Research collection of Bacillus cereus group species -WSC s Westfield State College, Museum and Herbarium -WSCH s Westfield State College, Biology Department -WSCO s Weber State University, Botany Department -WSF c Wisconsin Soil Fungi Collection -WSFA s Wilmington College, Biology Department -WSL b Swiss Federal Institute for Forest, Snow and Landscape Research -WSLC c Research collection of Listeria (Weihenstephan Microbial Strain Collection) -WSM s Weston-super-Mare Museum and Art Gallery -WSM c Western Australian Soil Microbiology culture collection, Murdoch. University -WSNM s White Sands National Monument -WSP s Washington State University, Plant Pathology Department -WSRP s University of Podlasie, Botany Department -WSU s Weber State University, Bird and Mammal Collection -WSU s Washington State University -WSUMNH s Wayne State University, Museum of Natural History -WSY s Royal Horticultural Society's Gardens -WTR s Winchester College, Biology Department -WTS s West Texas A&M University, Department of Life, Earth and Environmental Sciences -WTSU s West Texas A&M University, Natural History Collection -WTU s University of Washington -WTUH s University of Washington Botanic Gardens, College of Forest Resources -WU s Universitaet Wien -WU s Wayland University -WUD s Wayne State University, Biological Sciences Department -WUH s Wuhu School of Traditional Chinese Medicine -WUK s Northwestern Institute of Botany -WUM s University of Witwatersrand -WUME s Willamette University -WUP h Department of Pharmacognosy, Universitat Wien -WVA s West Virginia University, Biology Department -WVBS s West Virginia Biological Survey -WVDH c West Virginia Hygienic Laboratory -WVIT s West Virginia University, Biology Department -WVMS s Marshall University, West Virginia Mammal Survey -WVN s Whitehaven Scientific Association -WVUC s West Virginia University -WVW s West Virginia Wesleyan College, Biology Department -WWB s Western Washington University, Biology Department -WWC h Warren Wilson College -WWF s Welder Wildlife Foundation -WWM s Werner Wildlife Museum -WWSP s Weymouth Woods Sandhills Nature Preserve -WXDC s Wanxian Institute of Drug Control -WXM s North East Wales Institute, Department of Natural Science -WYAC s University of Wyoming, Range Ecology and Watershed Management Department -WYCO s Wytheville Community College, Biology Department -WYE s University of London, Wye College -XAG s Xinjiang Academy of Animal Sciences -XAL s Instituto de Ecologia, A.C. -XALU s Universidad Veracruzana -XBGH s Xian Botanical Garden -XCH s St. Xavier's College, Botany Department -XFCFC s Xiamen Fisheries College -XIAS s Xichang Agricultural School -XIN s Southwestern Guizhou Institute of Forestry -XJA s Xinjiang Agricultural University -XJBI s Xinjiang Institute of Ecology and Geography -XJDC s Xinjiang Institute for Drug Control -XJFA s Xinjiang Academy of Forestry Sciences -XJNU s Xinjiang Normal University, Biology Department -XJU s Xinjiang University, Biology Department -XJUG s Xinjiang University, Geography Department -XM s Xinjiang Medical College, Pharmacy Department -XMU s Xiamen University -XNC s Department of Biology, Xinxiang Normal College -XOLO s Universidad Autonoma Chapingo, Departamento de Fitotecnia -XTNM s Xinjiang Institute of Traditional Chinese and Minorities Medicine -XUM s Hope Department of Entomology -XYTC s Xinyang Teachers College, Biology Department -XZ s Tibet Plateau Institute of Biology -XZDC s Tibet Institute for Drug Control -XZTC s Xuzhou Teachers College, Biology Department -Y s Yale University, Samuel Jones Record Memorial Collection -YA s National Herbarium of Cameroon -YAF s Yunnan Academy of Forestry -YAI s Armenian Agricultural Academy, Botany Department -YAK s Forest Survey and Design Institute -YALT s The State Nikita Botanical Gardens, Flora and Vegetation -YAM s Yamaguchi University, Plant Pathology Department -YAMA h Yamagata Prefectural Museum -YAR s Yaroslavl State University, Department of Biology and Ecology -YBDC s Yibin Institute for Drug Control -YBI s Institut National pour l'Etude et la Recherche Agronomique, Departement de Botanique -YBLF c Yamanouchi Pharmaceutical Co., Ltd. -YCE s Yunnan College of Education, Biology Department -YCH s Yavapai College, Biology Department -YCM s Yokosuka City Museum -YCP s Yunnan Laboratory for Conservation of Rare, Endangered & Endemic Forest Plants, State Forestry Administration -YDC s Yunnan Institute for Drug Control -YELLO s Yellowstone National Park -YEO s Yeovil Museum -YF s Yanbei Forestry Institute -YFS s Yunnan Forestry School -YFTC s Yale Fish Tissue Collection -YH s Lutheran College -YHB s Yukon Heritage Board , Paleontology Collections -YIM c Yunnan Institute of Microbiology -YIM s Yunnan Institute of Pharmacology -YIO s Yamashina Institute for Ornithology -YK s Bootham School -YKN s Yorkshire Naturalists' Trust Limited -YL s Northwest Sci-tech University of Agriculture and Forestry -YLD s Yulin Institute of Desert Control Research -YM c Strains Collection of Yunnan Institute of Microbiology, Yunnan University, China -YM s York Museum -YM s National Park Service, Yosemite National Park -YMF s Key Laboratory of Industrial Microbiology & Fermentation Technology -YMUK s The Yorkshire Museum -YNP s The Yosemite Museum -YNU s Yokohama National University -YNUB s Yunnan Normal University, Biology Department -YNUGI s Yokohama National University - Geological Institute -YNUH s Yeungnam University, Biology Department -YOLA s Mari State University, Department of Plant Biology -YPM s Yale Peabody Museum of Natural History -YPM/PU s Princeton University Collection in Yale Peabody Museum +WNRE s Whiteshell Nuclear Research Establishment +WNS s Wiesbaden Naturwissenschaftliche Sammlung der Stadt +WNU s Northwest University, Biology Department +WOCB s University of Windsor, Biological Sciences Department +WOCSB b Wheeler Orchid Collection and Species Bank +WOH s Southwestern Oklahoma State University, Biology Department +WOLL s University of Wollongong, Department of Biological Sciences +WOS s City Museum and Art Gallery +WOSNH s Worcestershire Natural History Society Museum +WPBS c WPBS Rhizobium Collection +WPC cb World Phytophthora Genetic Resource Collection +WPH s Waterton Lakes National Park +WPL s Whitechapel Museum +WPMM s State Museum of Pennsylvania +WRC b Wildlife Research Center of Kyoto University +WRHM s Institute of Terrestrial Ecology +WRL c The Wellcome Bacterial Collection +WRN s Warrington Museum and Art Gallery +WRNFC s Warrington Field Naturalists' Club +WRO s University of Bristol, Long Ashton Research Station +WRSL s Wroclaw University, Botany Department +WS s Washington State University +WSBC s Wichita State University +WSBC c Research collection of Bacillus cereus group species +WSC s Westfield State College, Museum and Herbarium +WSCH s Westfield State College, Biology Department +WSCO s Weber State University, Botany Department +WSF c Wisconsin Soil Fungi Collection +WSFA s Wilmington College, Biology Department +WSL b Swiss Federal Institute for Forest, Snow and Landscape Research +WSLC c Research collection of Listeria (Weihenstephan Microbial Strain Collection) +WSM s Weston-super-Mare Museum and Art Gallery +WSM c Western Australian Soil Microbiology culture collection, Murdoch. University +WSNM s White Sands National Monument +WSP s Washington State University, Plant Pathology Department +WSRP s University of Podlasie, Botany Department +WSU s Weber State University, Bird and Mammal Collection +WSU s Washington State University +WSUMNH s Wayne State University, Museum of Natural History +WSY s Royal Horticultural Society's Gardens +WTR s Winchester College, Biology Department +WTS s West Texas A&M University, Department of Life, Earth and Environmental Sciences +WTSU s West Texas A&M University, Natural History Collection +WTU s University of Washington +WTU:Fungal Collection s University of Washington, F +WTUH s University of Washington Botanic Gardens, College of Forest Resources +WU s Universitaet Wien +WU s Wayland University +WUD s Wayne State University, Biological Sciences Department +WUH s Wuhu School of Traditional Chinese Medicine +WUK s Northwestern Institute of Botany +WUM s University of Witwatersrand +WUME s Willamette University +WUP h Department of Pharmacognosy, Universitat Wien +WVA s West Virginia University, Biology Department +WVBS s West Virginia Biological Survey +WVDH c West Virginia Hygienic Laboratory +WVIT s West Virginia University, Biology Department +WVMS s Marshall University, West Virginia Mammal Survey +WVN s Whitehaven Scientific Association +WVUC s West Virginia University +WVW s West Virginia Wesleyan College, Biology Department +WWB s Western Washington University, Biology Department +WWC h Warren Wilson College +WWF s Welder Wildlife Foundation +WWM s Werner Wildlife Museum +WWSP s Weymouth Woods Sandhills Nature Preserve +WXDC s Wanxian Institute of Drug Control +WXM s North East Wales Institute, Department of Natural Science +WYAC s University of Wyoming, Range Ecology and Watershed Management Department +WYCO s Wytheville Community College, Biology Department +WYE s University of London, Wye College +XAG s Xinjiang Academy of Animal Sciences +XAL s Instituto de Ecologia, A.C. +XALU s Universidad Veracruzana +XBGH s Xian Botanical Garden +XCH s St. Xavier's College, Botany Department +XFCFC s Xiamen Fisheries College +XIAS s Xichang Agricultural School +XIN s Southwestern Guizhou Institute of Forestry +XJA s Xinjiang Agricultural University +XJBI s Xinjiang Institute of Ecology and Geography +XJDC s Xinjiang Institute for Drug Control +XJFA s Xinjiang Academy of Forestry Sciences +XJNU s Xinjiang Normal University, Biology Department +XJU s Xinjiang University, Biology Department +XJUG s Xinjiang University, Geography Department +XM s Xinjiang Medical College, Pharmacy Department +XMU s Xiamen University +XNC s Department of Biology, Xinxiang Normal College +XOLO s Universidad Autonoma Chapingo, Departamento de Fitotecnia +XTNM s Xinjiang Institute of Traditional Chinese and Minorities Medicine +XUM s Hope Department of Entomology +XYTC s Xinyang Teachers College, Biology Department +XZ s Tibet Plateau Institute of Biology +XZDC s Tibet Institute for Drug Control +XZTC s Xuzhou Teachers College, Biology Department +Y s Yale University, Samuel Jones Record Memorial Collection +YA s National Herbarium of Cameroon +YAF s Yunnan Academy of Forestry +YAI s Armenian Agricultural Academy, Botany Department +YAK s Forest Survey and Design Institute +YALT s The State Nikita Botanical Gardens, Flora and Vegetation +YAM s Yamaguchi University, Plant Pathology Department +YAMA h Yamagata Prefectural Museum +YAR s Yaroslavl State University, Department of Biology and Ecology +YBDC s Yibin Institute for Drug Control +YBI s Institut National pour l'Etude et la Recherche Agronomique, Departement de Botanique +YBLF c Yamanouchi Pharmaceutical Co., Ltd. +YBU s Yibin University, College of Life Science and Food Engineering +YCE s Yunnan College of Education, Biology Department +YCH s Yavapai College, Biology Department +YCM s Yokosuka City Museum +YCP s Yunnan Laboratory for Conservation of Rare, Endangered & Endemic Forest Plants, State Forestry Administration +YDC s Yunnan Institute for Drug Control +Yeast Collection of Department of Microbiology, Stellenbosch University c Yeast Collection of Department of Microbiology, Stellenbosch University +YELLO s Yellowstone National Park +YEO s Yeovil Museum +YF s Yanbei Forestry Institute +YFS s Yunnan Forestry School +YFTC s Yale Fish Tissue Collection +YH s Lutheran College +YHB s Yukon Heritage Board , Paleontology Collections +YIM c Yunnan Institute of Microbiology +YIM s Yunnan Institute of Pharmacology +YIO s Yamashina Institute for Ornithology +YK s Bootham School +YKN s Yorkshire Naturalists' Trust Limited +YL s Northwest Sci-tech University of Agriculture and Forestry +YLD s Yulin Institute of Desert Control Research +YM c Strains Collection of Yunnan Institute of Microbiology, Yunnan University, China +YM s York Museum +YM s National Park Service, Yosemite National Park +YMF s Key Laboratory of Industrial Microbiology & Fermentation Technology +YMUK s The Yorkshire Museum +YNP s The Yosemite Museum +YNU s Yokohama National University +YNUB s Yunnan Normal University, Biology Department +YNUGI s Yokohama National University - Geological Institute +YNUH s Yeungnam University, Biology Department +YOLA s Mari State University, Department of Plant Biology +YPM s Yale Peabody Museum of Natural History +YPM/PU s Princeton University Collection in Yale Peabody Museum YPM:ENT s Yale Peabody Museum of Natural History, Entomology Collection YPM:HER s Yale Peabody Museum of Natural History, Herpetology Collection YPM:ICH s Yale Peabody Museum of Natural History, Ichthyology Collection YPM:IZ s Yale Peabody Museum of Natural History, Invertebrate Zoology Collection YPM:MAM s Yale Peabody Museum of Natural History, Mammology Collection YPM:ORN s Yale Peabody Museum of Natural History, Ornithology Collection -YPMC s Yellowstone National Park -YRK s Yorkshire Museum, Biology Department -YU s Yunnan University -YU s Department of Earth and Environmental Sciences, Yarmouk University -YU s Yale University, Botany Division -YUC s INIREB -YUKU s Yunnan University, Biology Department -YUO s Youngstown State University, Biological Sciences Department -YUTO s York University, Biology Department -YXDC s Yuxi District Institute for Drug Control -YZU s Yuzhou University -Z s Universitaet Zuerich -ZA s University of Zagreb, Botany Department -ZAD s Mount Makulu Research Station -ZAGR s University of Zagreb -ZAHO s University of Zagreb, Botany Department -ZAR s Institut de Paleontologie du Museum National d'Historie Naturelle -ZAU s Zhejiang Agricultural University -ZAUC s Zhejian Agricultural University -ZBMM s Maharaja's College, Zoology and Botany Museum -ZCA s Zhelimu College of Animal Husbandry, Range Science Department -ZCM s Shetland Museum -ZDC s Zhejiang Institute for Drug Control -ZDEU s Zoology Department, Ege University -ZDKU s Kharkiv National University -ZDM s Zigong dinosaur Museum -ZEA s Universidad de Guadalajara, Centro Universitario de la Costa Sur, Departamento de Ecologia y Recursos Naturales -ZFMK sb Zoologisches Forschungsmuseum Alexander Koenig +YPMC s Yellowstone National Park +YRK s Yorkshire Museum, Biology Department +YU s Yunnan University +YU s Department of Earth and Environmental Sciences, Yarmouk University +YU s Yale University, Botany Division +YUC s INIREB +YUKU s Yunnan University, Biology Department +YUO s Youngstown State University, Biological Sciences Department +YUTO s York University, Biology Department +YXDC s Yuxi District Institute for Drug Control +YZU s Yuzhou University +Z s Universitaet Zuerich +ZA s University of Zagreb, Botany Department +ZAD s Mount Makulu Research Station +ZAGR s University of Zagreb +ZAHO s University of Zagreb, Botany Department +ZAR s Institut de Paleontologie du Museum National Historie Naturelle +ZAU s Zhejiang Agricultural University +ZAUC s Zhejian Agricultural University +ZBMM s Maharaja's College, Zoology and Botany Museum +ZCA s Zhelimu College of Animal Husbandry, Range Science Department +ZCM s Shetland Museum +ZDC s Zhejiang Institute for Drug Control +ZDEU s Zoology Department, Ege University +ZDKU s Kharkiv National University +ZDM s Zigong dinosaur Museum +ZEA s Universidad de Guadalajara, Centro Universitario de la Costa Sur, Departamento de Ecologia y Recursos Naturales +ZFMK sb Zoologisches Forschungsmuseum Alexander Koenig ZFMK:COL s Zoologisches Forschungsmuseum Alexander Koenig, Coleoptera collection ZFMK:FSJF s Zoologisches Forschungsmuseum Alexander Koenig, fish collection of Jeorg Freyhof ZFMK:ICH s Zoologisches Forschungsmuseum Alexander Koenig, Ichthyological Collection -ZFSN s Laboratoire de Zoologie de la Faculte Des Sciences -ZGLC s Natural History Museum, Limassol -ZHAN s Zhanjiang Teachers College, Biology Department -ZhM s Zhejinag Museum -ZIA s National Academy of Sciences of Armenia -ZIAN s Zoological Institute, Academy of Sciences -ZICUP s Zoological Institute Charles University -ZIHU s Hiroshima University, Zoological Institute -ZIK s Ukrainian Academy of Sciences, Zoological Institute -ZIKU s Zoological Institute, Kochi University -ZIL s Academy of Sciences, Zoological Institute -ZIM c ZIM Culture Collection of Industrial Microorganisms -ZIN s Zoological Institute of the Russian Academy of Sciences -ZIS s Universitaet Saarbruecken -ZISB s Institute of Zoology -ZISP s Zoological Institute, Russian Academy of Sciences -ZIT s Grusinian Academy of Sciences -ZITIU s Zoological Institute, Tokyo Imperial University -ZIUG s Zoologisches Institut -ZIUL s Zoologisches Institut der Universitaet -ZIUN s Universita DI Napoli -ZIUS s Zoologisches Institute der Universitat -ZIUS s Zoologiska Institutionen -ZIUT s Department of Zoology, Faculty of Science, University of Tokyo -ZIUU s Uppsala Universitet, Zoologiska Museum -ZIUW s Universitaet Wien, Zoologisches Institut -ZIUZ s Zagreb University -ZJFC s Zhejiang Forestry College, Forestry Department -ZJFI s Zhejiang Forestry Institute, Bamboo Department -ZJMA s Zhejiang Academy of Medical Sciences -ZJU b Zhejiang University College of Sciences -ZLMU s Meijo University -ZLSYU s Zoological Laboratory -ZLVG c Culture collection of the Laboratory of Forest Protection at the Slovenian Forestry Institute -ZM s Zhejiang Museum of Natural History -ZMA s Universiteit van Amsterdam, Zoologisch Museum -ZMAN s Instituut voor Taxonomische Zoologie, Zoologisch Museum -ZMAU s Zoological Museum Andhra University -ZMB s Zoologisches Museum der Humboldt-Universitaet zu Berlin -ZMBJ s Banding Zoological Museum -ZMBN s Museum of Zoology at the University of Bergen, Invertebrate Collection -ZMC s Deptment of Biology, Zunyi Medical College -ZMFMIB s Zoologial Museum Fan Memorial Institute of Biology -ZMG s Zoologisches Museum der Universitat Gottingen -ZMG s Zoologischen Museums Greifswald -ZMH s Zoologisches Museum Hamburg -ZMHB s Museum fuer Naturkunde der Humboldt-Universitat -ZMHU s Zoologisches Museum der Humboldt Universitaet -ZMJU s Zoological Museum, Jagiellonian University -ZMK s Zoologisches Museum der Universitat Kiel -ZMK s Zoological Museum, Copenhagen -ZMK s Zoological Musem, Kristiania -ZMKR s Koenigsberg Zoologisches Museum -ZMKU s Kiev Zoological Museum -ZMKU s Zoological Museum, Kasetsart University -ZML s St Petersburg State University -ZMLP s University of Punjab -ZMLU s Lunds Universitet, Zoologiska Institutionen -ZMMGU s Zoological Museum -ZMMU s Zoological Museum, Moscow Lomonosov State University +ZFSN s Laboratoire de Zoologie de la Faculte Des Sciences +ZGLC s Natural History Museum, Limassol +ZHAN s Zhanjiang Teachers College, Biology Department +ZhM s Zhejinag Museum +ZIA s National Academy of Sciences of Armenia +ZIAN s Zoological Institute, Academy of Sciences +ZICUP s Zoological Institute Charles University +ZIHU s Hiroshima University, Zoological Institute +ZIK s Ukrainian Academy of Sciences, Zoological Institute +ZIKU s Zoological Institute, Kochi University +ZIL s Academy of Sciences, Zoological Institute +ZIM c ZIM Culture Collection of Industrial Microorganisms +ZIN s Zoological Institute of the Russian Academy of Sciences ZIAS +ZIS s Universitaet Saarbruecken +ZISB s Institute of Zoology +ZISP s Zoological Institute, Russian Academy of Sciences IN +ZIT s Grusinian Academy of Sciences +ZITIU s Zoological Institute, Tokyo Imperial University +ZIUG s Zoologisches Institut +ZIUL s Zoologisches Institut der Universitaet +ZIUN s Universita DI Napoli +ZIUS s Zoologisches Institute der Universitat +ZIUS s Zoologiska Institutionen +ZIUT s Department of Zoology, Faculty of Science, University of Tokyo +ZIUU s Uppsala Universitet, Zoologiska Museum +ZIUW s Universitaet Wien, Zoologisches Institut +ZIUZ s Zagreb University +ZJFC s Zhejiang Forestry College, Forestry Department +ZJFI s Zhejiang Forestry Institute, Bamboo Department +ZJMA s Zhejiang Academy of Medical Sciences +ZJU b Zhejiang University College of Sciences +ZLMU s Meijo University +ZLSYU s Zoological Laboratory +ZLVG c Culture collection of the Laboratory of Forest Protection at the Slovenian Forestry Institute +ZM s Zhejiang Museum of Natural History +ZMA s Universiteit van Amsterdam, Zoologisch Museum +ZMA:POR s Universiteit van Amsterdam, Zoologisch Museum, Porifera collection +ZMAN s Instituut voor Taxonomische Zoologie, Zoologisch Museum +ZMAU s Zoological Museum Andhra University +ZMB s Zoologisches Museum der Humboldt-Universitaet zu Berlin +ZMBJ s Banding Zoological Museum +ZMBN s Museum of Zoology at the University of Bergen, Invertebrate Collection BMBN +ZMC s Deptment of Biology, Zunyi Medical College +ZMFMIB s Zoologial Museum Fan Memorial Institute of Biology +ZMG s Zoologisches Museum der Universitat Gottingen +ZMG s Zoologischen Museums Greifswald +ZMH s Zoologisches Museum Hamburg +ZMHB s Museum fuer Naturkunde der Humboldt-Universitat +ZMHU s Zoologisches Museum der Humboldt Universitaet +ZMJU s Zoological Museum, Jagiellonian University +ZMK s Zoologisches Museum der Universitat Kiel +ZMK s Zoological Museum, Copenhagen +ZMK s Zoological Musem, Kristiania +ZMKR s Koenigsberg Zoologisches Museum +ZMKU s Kiev Zoological Museum +ZMKU s Zoological Museum, Kasetsart University +ZML s St Petersburg State University +ZMLP s University of Punjab +ZMLU s Lunds Universitet, Zoologiska Institutionen +ZMMGU s Zoological Museum +ZMMU s Zoological Museum, Moscow Lomonosov State University ZMM,ZMUM ZMMU:Birds s Zoological Museum, Moscow Lomonosov State University, Bird Collection ZMMU:Fishes s Zoological Museum, Moscow Lomonosov State University, Fishes Collection ZMMU:Herps s Zoological Museum, Moscow Lomonosov State University, Ampibia and Reptilia Collection ZMMU:Insects s Zoological Museum, Moscow Lomonosov State University, Insects Collection ZMMU:Invertebrates s Zoological Museum, Moscow Lomonosov State University, Invertebrates Collection ZMMU:Mamm s Zoological Museum, Moscow Lomonosov State University, Mammal Collection -ZMNH s Zhejiang Museum of Natural History -ZMO s Zoology Museum, Oxford University -ZMS s Zentralmuseum Senckenberg (SENCKENBERG world of biodiversity) -ZMSZ s Zemaljski Mujski -ZMT s Zapadomoravske muzeum v Trebici -ZMT s Georgian State Museum, Zoological Section -ZMTAU s Zoological Museum Tel Aviv University -ZMU s Zhejiang Medical University, Pharmacy Department -ZMUA s Zooligal Museum, University of Amoy -ZMUA s Zoological Museum, University of Athens -ZMUAS s Zoological Museum Ukrainian Academy of Sciences -ZMUB s Museum of Zoology at the University of Bergen, Vertebrate collections +ZMNH s Zhejiang Museum of Natural History +ZMO s Zoology Museum, Oxford University +ZMS s Zentralmuseum Senckenberg (SENCKENBERG world of biodiversity) +ZMSZ s Zemaljski Mujski +ZMT s Zapadomoravske muzeum v Trebici +ZMT s Georgian State Museum, Zoological Section +ZMTAU s Zoological Museum Tel Aviv University +ZMU s Zhejiang Medical University, Pharmacy Department +ZMUA s Zooligal Museum, University of Amoy +ZMUA s Zoological Museum, University of Athens +ZMUAS s Zoological Museum Ukrainian Academy of Sciences +ZMUB s Museum of Zoology at the University of Bergen, Vertebrate collections ZMUB:BIRD s Museum of Zoology at the University of Bergen, Vertebrate collections, Bird collection ZMUB:HERP s Museum of Zoology at the University of Bergen, Vertebrate collections, Herptile collection ZMUB:ICHT s Museum of Zoology at the University of Bergen, Vertebrate collections, Fish Collections ZMUB:MAMM s Museum of Zoology at the University of Bergen, Vertebrate collections, Mammal collection -ZMUC sb Zoological Museum, University of Copenhagen -ZMUD s University of Dhaka, Zoology Museum -ZMUH s Zoologisches Institut und Zoologisches Museum, Universitat Hamburg -ZMUH s Zoological Museum, University of Hanoi -ZMUI s Zoological Museum, University of Istanbul -ZMUL s Universitetets Lund, Zoologiska Museet -ZMUN s Zoology, Natural History Museum, University of Oslo -ZMUO s University of Oulu Zoological Museum -ZMUO s Universitetets I Oslo, Zoologisk Museum -ZMUP s Zoological Museum of the University of Patras -ZMUT s University of Tokyo, Department of Zoology -ZMUU s Uppsala Universitet, Zoologiska Museet -ZMUZ s Zoologisches Museum der Universitaet Zuerich -ZNG h Bulent Ecevit University -ZNM s Zhejiang Natural Museum -ZNP s Zion National Park -ZNPC s Springdale, Zion National Park -ZNU s Zhejiang Normal University, Biology Department -ZOM s Herbarium, Department of Agriculture, Malawi -ZPAL s Zoological Institute of Paleobiology, Polish Academy of Sciences -ZPB s Institute of Conservation and Natural History of the Soutpansberg -ZRC s Zoological Reference Collection, National University of Singapore -ZSBS s Zoologische Sammlung des Bayerischen Staates -ZSI-CRS s Zoological Survey of India, Central Regional Station -ZSI-E s Zoological Survey of India -ZSI-M s Zoological Survey of India -ZSI-NRS s Zoological Survey of India -ZSI-SRS s Zoological Survey of India, Southern Regional Station -ZSI-WRS s Zoological Survey of India -ZSIC s Zoological Survey of India -ZSLC s Zoological Society of London -ZSM sb Zoologisches Staatssammlung Munchen -ZSM/CMK s Zoologische Museum Staatssammlung -ZSM/LIPI s Zoologische Museum Staatssammlung -ZSM:Lep s Zoologisches Staatssammlung Munchen, Lepidoptera -ZSM:Mol s Zoologisches Staatssammlung Munchen, Mollusca -ZSMC s Zoologische Staatssammlung -ZSP s Zoological Survey of Pakistan -ZSP s Zoological Society of Philadelphia -ZSS s Sukkulenten-Sammlung Zuerich -ZT s Eidgenoessische Technische Hochschule Zuerich -ZTNH s University of Vermont, Zadock Thompson Natural History Collections -ZTS s Institute of Nature Conservation, Polish Academy of Sciences, Tatra Field Station -ZUAB s Zoologia--Universidad Autonoma de Barcelona -ZUAC s University of Antananarivo -ZUEC s Museu de Zoologia da Universidade Estadual de Campinas -ZUFES s Universidad Federal do Espirito Santo -ZUFRJ s Departamento de Zoolgia, Instituto de Biologia -ZUFSM s Universidade Federal de Santa Maria, Laboratorio de Herpetologia -ZULU s University of Zululand, Botany Department -ZUMT s Department of Zoology, University Museum -ZUTC s Zoological Museum University of Tehran -ZV s Technical University, Department of Phytology -ZVC s Depto. de Zoologia Vertebrados de la Facultad de Humanidades y Ciencias -ZVCB s Vertebrate Collection, Facultad de Ciencias, Universidad de la Republica -ZVS s Bundesamt fuer Naturschutz -ZY h Zunyi Normal College -ZYTC s Zhangye Teachers College, Chemistry-Biology Department -ZZN c Zavod za naravoslovje -ZZSZ s Zoology Department, Faculty of Natural Sciences, University of Zagreb +ZMUC sb Zoological Museum, University of Copenhagen +ZMUD s University of Dhaka, Zoology Museum +ZMUH s Zoologisches Institut und Zoologisches Museum, Universitat Hamburg +ZMUH s Zoological Museum, University of Hanoi +ZMUI s Zoological Museum, University of Istanbul +ZMUL s Universitetets Lund, Zoologiska Museet +ZMUN s Zoology, Natural History Museum, University of Oslo +ZMUO s University of Oulu Zoological Museum +ZMUO s Universitetets I Oslo, Zoologisk Museum +ZMUP s Zoological Museum of the University of Patras +ZMUT s University of Tokyo, Department of Zoology +ZMUU s Uppsala Universitet, Zoologiska Museet +ZMUZ s Zoologisches Museum der Universitat Zurich +ZNG h Bulent Ecevit University +ZNM s Zhejiang Natural Museum +ZNP s Zion National Park +ZNPC s Springdale, Zion National Park +ZNU s Zhejiang Normal University, Biology Department +ZOM s Herbarium, Department of Agriculture, Malawi +ZPAL s Zoological Institute of Paleobiology, Polish Academy of Sciences +ZPB s Institute of Conservation and Natural History of the Soutpansberg +ZRC s Zoological Reference Collection, National University of Singapore +ZSBS s Zoologische Sammlung des Bayerischen Staates +ZSI s Zoological Survey of India +ZSI-CRS s Zoological Survey of India, Central Regional Station +ZSI-E s Zoological Survey of India +ZSI-M s Zoological Survey of India +ZSI-NRS s Zoological Survey of India +ZSI-SRS s Zoological Survey of India, Southern Regional Station +ZSI-WRS s Zoological Survey of India +ZSIC s Zoological Survey of India +ZSLC s Zoological Society of London +ZSM sb Zoologische Staatssammlung Munchen ZSMH +ZSM/CMK s Zoologische Museum Staatssammlung +ZSM/LIPI s Zoologische Museum Staatssammlung +ZSM:Lep s Zoologische Staatssammlung Munchen, Lepidoptera +ZSM:Mol s Zoologische Staatssammlung Munchen, Mollusca +ZSMC s Zoologische Staatssammlung +ZSP s Zoological Survey of Pakistan +ZSP s Zoological Society of Philadelphia +ZSS s Sukkulenten-Sammlung Zuerich +ZT s Eidgenoessische Technische Hochschule Zuerich +ZTNH s University of Vermont, Zadock Thompson Natural History Collections +ZTS s Institute of Nature Conservation, Polish Academy of Sciences, Tatra Field Station +ZUAB s Zoologia--Universidad Autonoma de Barcelona +ZUAC s University of Antananarivo +ZUEC s Museu de Zoologia da Universidade Estadual de Campinas +ZUFES s Universidad Federal do Espirito Santo +ZUFRJ s Departamento de Zoolgia, Instituto de Biologia +ZUFSM s Universidade Federal de Santa Maria, Laboratorio de Herpetologia +ZULU s University of Zululand, Botany Department +ZUMT s Department of Zoology, University Museum +ZUTC s Zoological Museum University of Tehran +ZV s Technical University, Department of Phytology +ZVC s Depto. de Zoologia Vertebrados de la Facultad de Humanidades y Ciencias +ZVCB s Vertebrate Collection, Facultad de Ciencias, Universidad de la Republica +ZVS s Bundesamt fuer Naturschutz +ZY h Zunyi Normal College +ZYTC s Zhangye Teachers College, Chemistry-Biology Department +ZZN c Zavod za naravoslovje +ZZSZ s Zoology Department, Faculty of Natural Sciences, University of Zagreb diff --git a/c++/src/objects/seqfeat/isolation_sources.inc b/c++/src/objects/seqfeat/isolation_sources.inc new file mode 100644 index 00000000..e97a5965 --- /dev/null +++ b/c++/src/objects/seqfeat/isolation_sources.inc @@ -0,0 +1,367 @@ +/* $Id: isolation_sources.inc 529164 2017-03-01 18:39:34Z bollin $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: NCBI developers + * + * File Description: + * Built-in copy of isolation_sources.txt. + * + */ + +static const char* const k_isolation_sources[] = { + "abdomen\tabdomen", + "abdominal fluid\tabdominal fluid", + "acne\tacne", + "activated sludge\tactivated sludge", + "adductor muscle\tadductor muscle", + "agricultural soil\tagricultural soil", + "air\tair", + "amniotic fluid\tamniotic fluid", + "Animal\tanimal", + "Animal-Cattle-Beef Cow\tanimal-cattle-beef cow", + "Animal-Cattle-Dairy Cow\tanimal-cattle-dairy cow", + "Animal-Cattle-Heifer\tanimal-cattle-heifer", + "Animal-Cattle-Steer\tanimal-cattle-steer", + "Animal-Chicken-Young Chicken\tanimal-chicken-young chicken", + "Animal-Swine-Market Swine\tanimal-swine-market swine", + "Animal-Swine-Sow\tanimal-swine-sow", + "antenna\tantenna", + "aquaculture water\taquaculture water", + "aquifer sediment\taquifer sediment", + "aspirate\taspirate", + "Beef\tbeef", + "bile\tbile", + "biofilm\tbiofilm", + "bitumen\tbitumen", + "BLOOD\tblood", + "blood cells\tblood cells", + "blood sample\tblood sample", + "Bodily fluid\tbodily fluid", + "body fluid\tbody fluid", + "bone\tbone", + "bone marrow\tbone marrow", + "Bovine (feces)\tbovine feces", + "bovine feces\tbovine feces", + "bovine milk\tbovine milk", + "Brain\tbrain", + "brain abscess\tbrain abscess", + "brain biopsy\tbrain biopsy", + "brain tissue\tbrain tissue", + "branch\tbranch", + "bronchial mucosa\tbronchial mucosa", + "bronchoalveolar lavage\tbronchoalveolar lavage", + "buccal epithelial cells\tbuccal epithelial cells", + "buccal mucosa\tbuccal mucosa", + "buccal swab\tbuccal swab", + "buffy coat\tbuffy coat", + "bursa\tbursa", + "cabbage leaves\tcabbage leaves", + "callus\tcallus", + "catfish\tcatfish", + "cave sediment\tcave sediment", + "cave sediments\tcave sediments", + "cerebellum\tcerebellum", + "cerebrospinal fluid\tcerebrospinal fluid", + "cervix\tcervix", + "Channel catfish\tChannel catfish", + "cheese\tcheese", + "Chicken\tchicken", + "Chicken Breast\tchicken breast", + "Chicken Carcass\tchicken carcass", + "Clinical\tclinical", + "clinical isolate\tclinical isolate", + "clinical isolates\tclinical isolate", + "clinical sample\tclinical sample", + "clinical samples\tclinical sample", + "cloaca\tcloaca", + "cloacal swab\tcloacal swab", + "Comminuted Beef\tcomminuted beef", + "Comminuted Chicken\tcomminuted chicken", + "compost\tcompost", + "compost soil\tcompost soil", + "coral reef\tcoral reef", + "corn rhizosphere\tcorn rhizosphere", + "cornea\tcornea", + "cotton rhizosphere\tcotton rhizosphere", + "creek water\tcreek water", + "crown\tcrown", + "CSF\tCSF", + "Cucumbers\tcucumbers", + "culture\tculture", + "curd sample\tcurd sample", + "dairy cow rumen\tdairy cow rumen", + "dairy farm soil\tdairy farm soil", + "distillery\tdistillery", + "drinking water\tdrinking water", + "ear\tear", + "egg\tegg", + "embryogenic callus\tembryogenic callus", + "Environmental\tenvironmental", + "environmental sample\tenvironmental sample", + "Environmental Swab\tenvironmental swab", + "Environmental Swabs\tenvironmental swab", + "Environmental: non-food-contact surface\tenvironmental: non-food-contact surface", + "epithelium\tepithelium", + "esophageal mucosa\tesophageal mucosa", + "estuarine water\testuarine water", + "estuarine waters\testuarine waters", + "Excreted bodily substance\texcreted bodily substance", + "eye\teye", + "Faeces\tfeces", + "farm environment\tfarm environment", + "farm soil\tfarm soil", + "fecal\tfeces", + "fecal sample\tfecal sample", + "fecal samples\tfecal sample", + "Feces\tfeces", + "fermented food\tfermented food", + "fermented soybeans\tfermented soybeans", + "fetal brain\tfetal brain", + "field soil\tfield soil", + "fin\tfin", + "fin wound\tfin wound", + "fish eggs\tfish eggs", + "fish intestine\tfish intestine", + "flooded rice soil\tflooded rice soil", + "flower\tflower", + "Food\tfood", + "food product\tfood product", + "food sample\tfood sample", + "food samples\tfood sample", + "forest\tforest", + "forest soil\tforest soil", + "freshwater\tfreshwater", + "freshwater stream\tfreshwater stream", + "fruit\tfruit", + "fruit body\tfruit body", + "fruitbody\tfruitbody", + "fruiting body\tfruiting body", + "gastric mucosa\tgastric mucosa", + "gastrointestinal tract\tgastrointestinal tract", + "genital cells\tgenital cells", + "genitals\tgenitals", + "gill\tgill", + "gills\tgills", + "goat milk\tgoat milk", + "Ground Chicken\tground chicken", + "Ground Turkey\tground turkey", + "groundwater\tgroundwater", + "head\thead", + "head kidney\thead kidney", + "heart\theart", + "heart blood\theart blood", + "hemocyte\themocyte", + "hepatic bile duct\thepatic bile duct", + "hepatic biliary duct\thepatic biliary duct", + "hepatocyte\thepatocyte", + "hepatopancreas\thepatopancreas", + "horse\thorse", + "Hospital\thospital", + "hot marine salterns\thot marine salterns", + "hot spring\thot spring", + "hot springs\thot springs", + "Human\thuman", + "human plasma\thuman plasma", + "human skin\thuman skin", + "infected leaf\tinfected leaf", + "inflorescence\tinflorescence", + "intestinal mucosa\tintestinal mucosa", + "intestine\tintestine", + "intestines\tintestines", + "kidney\tkidney", + "kimchi\tkimchi", + "lake\tlake", + "lake isolate\tlake isolate", + "lake mud\tlake mud", + "lake sediment\tlake sediment", + "lake soil\tlake soil", + "lake water\tlake water", + "leaf\tleaf", + "leaves\tleaves", + "lentil\tlentil", + "liver\tliver", + "liver abscess\tliver abscess", + "lung\tlung", + "lymph node\tlymph node", + "lymphocyte\tlymphocyte", + "maize\tmaize", + "mammary gland\tmammary gland", + "mangrove sediment\tmangrove sediment", + "mangrove sediments\tmangrove sediments", + "mangrove soil\tmangrove soil", + "manure\tmanure", + "marine environment\tmarine environment", + "marine sediment\tmarine sediment", + "marine sediments\tmarine sediments", + "marine water\tmarine water", + "mature leaf\tmature leaf", + "meat\tmeat", + "midgut\tmidgut", + "Milk\tmilk", + "Missing\tmissing", + "mitral valve\tmitral valve", + "mouth wound\tmouth wound", + "mucosa\tmucosa", + "mucus\tmucus", + "muscle\tmuscle", + "muscle tissue\tmuscle tissue", + "mycelium\tmycelium", + "Nares\tnares", + "nasal\tnasal", + "nasal mucosa\tnasal mucosa", + "nasal sample\tnasal sample", + "nasal samples\tnasal sample", + "nasal swab\tnasal swab", + "nasopharyngeal aspirate\tnasopharyngeal aspirate", + "nasopharyngeal swab\tnasopharyngeal swab", + "nasopharynx\tnasopharynx", + "nest\tnest", + "neuroblast\tneuroblast", + "nodule\tnodule", + "nodules\tnodules", + "nose swab\tnose swab", + "Not Applicable\tnot applicable", + "Not known\tunknown", + "olfactory mucosa\tolfactory mucosa", + "oral fluid\toral fluid", + "oral lexion\toral lexion", + "oral mucosa\toral mucosa", + "Other\tmissing", + "ovary\tovary", + "oviduct\toviduct", + "paddy soil\tpaddy soil", + "papaya\tpapaya", + "parietal cortex\tparietal cortex", + "patient\tpatient", + "patient with urinary tract infection\tpatient with urinary tract infection", + "pericardial\tpericardial", + "pharnyx\tpharnyx", + "placenta\tplacenta", + "plasma\tplasma", + "pleopod\tpleopod", + "pleopods\tpleopods", + "pleura\tpleura", + "pod\tpod", + "pond sediment\tpond sediment", + "pond water\tpond water", + "porcine Pleural Cavity\tporcine pleural cavity", + "poultry farm soil\tpoultry farm soil", + "product-eggs-raw-whole\tproduct-eggs-raw-whole", + "Product-Raw-Intact-Beef\tproduct-raw-intact-beef", + "purulent fluid\tpurulent fluid", + "Raw Intact Chicken\traw intact chicken", + "Respiratory\trespiratory", + "Respiratory system\trespiratory system", + "respiratory tract\trespiratory tract", + "Retail Deli\tretail deli", + "Retail Meat\tretail meat", + "rhizosphere\trhizosphere", + "rhizosphere soil\trhizosphere soil", + "rice rhizosphere\trice rhizosphere", + "rice soil\trice soil", + "river sand\triver sand", + "river sediment\triver sediment", + "river sediments\triver sediments", + "river water\triver water", + "root\troot", + "root nodule\troot nodule", + "root nodules\troot nodules", + "root tip\troot tip", + "root tips\troot tips", + "roots\troots", + "rumen\trumen", + "saline lake\tsaline lake", + "saliva\tsaliva", + "salivary gland\tsalivary gland", + "saltern soil\tsaltern soil", + "seafood\tseafood", + "seawater\tseawater", + "sediment\tsediment", + "sediments\tsediments", + "seedling\tseedling", + "seedling roots\tseedling roots", + "sera\tsera", + "serum\tserum", + "sesame seeds\tsesame seeds", + "sewage sludge\tsewage sludge", + "shrimp pond\tshrimp pond", + "skeletal muscle\tskeletal muscle", + "skin\tskin", + "skin lesion\tskin lesion", + "sludge\tsludge", + "soda lake\tsoda lake", + "Soil\tsoil", + "soil rhizosphere\tsoil rhizosphere", + "soil sample\tsoil sample", + "solar saltern\tsolar saltern", + "solar salterns\tsolar salterns", + "spindle leaf\tspindle leaf", + "spleen\tspleen", + "Sputum\tsputum", + "stem\tstem", + "stem base\tstem base", + "stems\tstems", + "stomach\tstomach", + "Stool\tstool", + "stool sample\tstool", + "stool samples\tstool", + "Stool/Fecal\tstool", + "strawberry\tstrawberry", + "sulphur spring\tsulphur spring", + "surface water\tsurface water", + "swab\tswab", + "swamp soil\tswamp soil", + "tail\ttail", + "tannery waste\ttannery waste", + "tannery waste effluent\ttannery waste effluent", + "tentacle\ttentacle", + "testes\ttestes", + "testis\ttestis", + "textile wastewater\ttextile wastewater", + "throat\tthroat", + "throat swab\tthroat swab", + "throat wash\tthroat wash", + "thymus\tthymus", + "tissue biopsy\ttissue biopsy", + "trachea\ttrachea", + "tracheal aspirate\ttracheal aspirate", + "tracheal swab\ttracheal swab", + "turfgrass\tturfgrass", + "twig\ttwig", + "underground water\tunderground water", + "Unknown\tunknown", + "urethra\turethra", + "Urine\turine", + "uterine mucosa\tuterine mucosa", + "vegetable\tvegetable", + "vegetables\tvegetables", + "wastewater\twastewater", + "Water\twater", + "white clover\twhite clover", + "whole blood\twhole blood", + "whole cell/tissue lysate\twhole cell/tissue lysate", + "WOUND\twound", + "yogurt\tyogurt" +}; diff --git a/c++/src/objects/seqfeat/isolation_sources.txt b/c++/src/objects/seqfeat/isolation_sources.txt new file mode 100644 index 00000000..1af08124 --- /dev/null +++ b/c++/src/objects/seqfeat/isolation_sources.txt @@ -0,0 +1,333 @@ +abdomen abdomen +abdominal fluid abdominal fluid +acne acne +activated sludge activated sludge +adductor muscle adductor muscle +agricultural soil agricultural soil +air air +amniotic fluid amniotic fluid +Animal animal +Animal-Cattle-Beef Cow animal-cattle-beef cow +Animal-Cattle-Dairy Cow animal-cattle-dairy cow +Animal-Cattle-Heifer animal-cattle-heifer +Animal-Cattle-Steer animal-cattle-steer +Animal-Chicken-Young Chicken animal-chicken-young chicken +Animal-Swine-Market Swine animal-swine-market swine +Animal-Swine-Sow animal-swine-sow +antenna antenna +aquaculture water aquaculture water +aquifer sediment aquifer sediment +aspirate aspirate +Beef beef +bile bile +biofilm biofilm +bitumen bitumen +BLOOD blood +blood cells blood cells +blood sample blood sample +Bodily fluid bodily fluid +body fluid body fluid +bone bone +bone marrow bone marrow +Bovine (feces) bovine feces +bovine feces bovine feces +bovine milk bovine milk +Brain brain +brain abscess brain abscess +brain biopsy brain biopsy +brain tissue brain tissue +branch branch +bronchial mucosa bronchial mucosa +bronchoalveolar lavage bronchoalveolar lavage +buccal epithelial cells buccal epithelial cells +buccal mucosa buccal mucosa +buccal swab buccal swab +buffy coat buffy coat +bursa bursa +cabbage leaves cabbage leaves +callus callus +catfish catfish +cave sediment cave sediment +cave sediments cave sediments +cerebellum cerebellum +cerebrospinal fluid cerebrospinal fluid +cervix cervix +Channel catfish Channel catfish +cheese cheese +Chicken chicken +Chicken Breast chicken breast +Chicken Carcass chicken carcass +Clinical clinical +clinical isolate clinical isolate +clinical isolates clinical isolate +clinical sample clinical sample +clinical samples clinical sample +cloaca cloaca +cloacal swab cloacal swab +Comminuted Beef comminuted beef +Comminuted Chicken comminuted chicken +compost compost +compost soil compost soil +coral reef coral reef +corn rhizosphere corn rhizosphere +cornea cornea +cotton rhizosphere cotton rhizosphere +creek water creek water +crown crown +CSF CSF +Cucumbers cucumbers +culture culture +curd sample curd sample +dairy cow rumen dairy cow rumen +dairy farm soil dairy farm soil +distillery distillery +drinking water drinking water +ear ear +egg egg +embryogenic callus embryogenic callus +Environmental environmental +environmental sample environmental sample +Environmental Swab environmental swab +Environmental Swabs environmental swab +Environmental: non-food-contact surface environmental: non-food-contact surface +epithelium epithelium +esophageal mucosa esophageal mucosa +estuarine water estuarine water +estuarine waters estuarine waters +Excreted bodily substance excreted bodily substance +eye eye +Faeces feces +farm environment farm environment +farm soil farm soil +fecal feces +fecal sample fecal sample +fecal samples fecal sample +Feces feces +fermented food fermented food +fermented soybeans fermented soybeans +fetal brain fetal brain +field soil field soil +fin fin +fin wound fin wound +fish eggs fish eggs +fish intestine fish intestine +flooded rice soil flooded rice soil +flower flower +Food food +food product food product +food sample food sample +food samples food sample +forest forest +forest soil forest soil +freshwater freshwater +freshwater stream freshwater stream +fruit fruit +fruit body fruit body +fruitbody fruitbody +fruiting body fruiting body +gastric mucosa gastric mucosa +gastrointestinal tract gastrointestinal tract +genital cells genital cells +genitals genitals +gill gill +gills gills +goat milk goat milk +Ground Chicken ground chicken +Ground Turkey ground turkey +groundwater groundwater +head head +head kidney head kidney +heart heart +heart blood heart blood +hemocyte hemocyte +hepatic bile duct hepatic bile duct +hepatic biliary duct hepatic biliary duct +hepatocyte hepatocyte +hepatopancreas hepatopancreas +horse horse +Hospital hospital +hot marine salterns hot marine salterns +hot spring hot spring +hot springs hot springs +Human human +human plasma human plasma +human skin human skin +infected leaf infected leaf +inflorescence inflorescence +intestinal mucosa intestinal mucosa +intestine intestine +intestines intestines +kidney kidney +kimchi kimchi +lake lake +lake isolate lake isolate +lake mud lake mud +lake sediment lake sediment +lake soil lake soil +lake water lake water +leaf leaf +leaves leaves +lentil lentil +liver liver +liver abscess liver abscess +lung lung +lymph node lymph node +lymphocyte lymphocyte +maize maize +mammary gland mammary gland +mangrove sediment mangrove sediment +mangrove sediments mangrove sediments +mangrove soil mangrove soil +manure manure +marine environment marine environment +marine sediment marine sediment +marine sediments marine sediments +marine water marine water +mature leaf mature leaf +meat meat +midgut midgut +Milk milk +Missing missing +mitral valve mitral valve +mouth wound mouth wound +mucosa mucosa +mucus mucus +muscle muscle +muscle tissue muscle tissue +mycelium mycelium +Nares nares +nasal nasal +nasal mucosa nasal mucosa +nasal sample nasal sample +nasal samples nasal sample +nasal swab nasal swab +nasopharyngeal aspirate nasopharyngeal aspirate +nasopharyngeal swab nasopharyngeal swab +nasopharynx nasopharynx +nest nest +neuroblast neuroblast +nodule nodule +nodules nodules +nose swab nose swab +Not Applicable not applicable +Not known unknown +olfactory mucosa olfactory mucosa +oral fluid oral fluid +oral lexion oral lexion +oral mucosa oral mucosa +Other missing +ovary ovary +oviduct oviduct +paddy soil paddy soil +papaya papaya +parietal cortex parietal cortex +patient patient +patient with urinary tract infection patient with urinary tract infection +pericardial pericardial +pharnyx pharnyx +placenta placenta +plasma plasma +pleopod pleopod +pleopods pleopods +pleura pleura +pod pod +pond sediment pond sediment +pond water pond water +porcine Pleural Cavity porcine pleural cavity +poultry farm soil poultry farm soil +product-eggs-raw-whole product-eggs-raw-whole +Product-Raw-Intact-Beef product-raw-intact-beef +purulent fluid purulent fluid +Raw Intact Chicken raw intact chicken +Respiratory respiratory +Respiratory system respiratory system +respiratory tract respiratory tract +Retail Deli retail deli +Retail Meat retail meat +rhizosphere rhizosphere +rhizosphere soil rhizosphere soil +rice rhizosphere rice rhizosphere +rice soil rice soil +river sand river sand +river sediment river sediment +river sediments river sediments +river water river water +root root +root nodule root nodule +root nodules root nodules +root tip root tip +root tips root tips +roots roots +rumen rumen +saline lake saline lake +saliva saliva +salivary gland salivary gland +saltern soil saltern soil +seafood seafood +seawater seawater +sediment sediment +sediments sediments +seedling seedling +seedling roots seedling roots +sera sera +serum serum +sesame seeds sesame seeds +sewage sludge sewage sludge +shrimp pond shrimp pond +skeletal muscle skeletal muscle +skin skin +skin lesion skin lesion +sludge sludge +soda lake soda lake +Soil soil +soil rhizosphere soil rhizosphere +soil sample soil sample +solar saltern solar saltern +solar salterns solar salterns +spindle leaf spindle leaf +spleen spleen +Sputum sputum +stem stem +stem base stem base +stems stems +stomach stomach +Stool stool +stool sample stool +stool samples stool +Stool/Fecal stool +strawberry strawberry +sulphur spring sulphur spring +surface water surface water +swab swab +swamp soil swamp soil +tail tail +tannery waste tannery waste +tannery waste effluent tannery waste effluent +tentacle tentacle +testes testes +testis testis +textile wastewater textile wastewater +throat throat +throat swab throat swab +throat wash throat wash +thymus thymus +tissue biopsy tissue biopsy +trachea trachea +tracheal aspirate tracheal aspirate +tracheal swab tracheal swab +turfgrass turfgrass +twig twig +underground water underground water +Unknown unknown +urethra urethra +Urine urine +uterine mucosa uterine mucosa +vegetable vegetable +vegetables vegetables +wastewater wastewater +Water water +white clover white clover +whole blood whole blood +whole cell/tissue lysate whole cell/tissue lysate +WOUND wound +yogurt yogurt diff --git a/c++/src/objects/seqfeat/lat_lon_country.inc b/c++/src/objects/seqfeat/lat_lon_country.inc index 106600b8..d0e15549 100644 --- a/c++/src/objects/seqfeat/lat_lon_country.inc +++ b/c++/src/objects/seqfeat/lat_lon_country.inc @@ -1,4 +1,4 @@ -/* $Id: lat_lon_country.inc 513850 2016-09-15 17:37:05Z ivanov $ +/* $Id: lat_lon_country.inc 513722 2016-09-14 18:41:05Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seqfeat/prepare_taxtable.sh b/c++/src/objects/seqfeat/prepare_taxtable.sh new file mode 100644 index 00000000..fcbe44d3 --- /dev/null +++ b/c++/src/objects/seqfeat/prepare_taxtable.sh @@ -0,0 +1,25 @@ +#! /bin/sh +cut -f 3 top900_orgn_nucl.txt > taxids.txt +cat taxids.txt | +epost -db taxonomy | +efetch -format xml | +xtract -format | +sed \ + -e 's/Bacteria<\/Division>/BCT<\/Division>/g' \ + -e 's/Environmental samples<\/Division>/ENV<\/Division>/g' \ + -e 's/Invertebrates<\/Division>/INV<\/Division>/g' \ + -e 's/Mammals<\/Division>/MAM<\/Division>/g' \ + -e 's/Phages<\/Division>/PHG<\/Division>/g' \ + -e 's/Plants and Fungi<\/Division>/PLN<\/Division>/g' \ + -e 's/Primates<\/Division>/PRI<\/Division>/g' \ + -e 's/Rodents<\/Division>/ROD<\/Division>/g' \ + -e 's/Synthetic and Chimeric<\/Division>/SYN<\/Division>/g' \ + -e 's/Unassigned<\/Division>/UNA<\/Division>/g' \ + -e 's/Vertebrates<\/Division>/VRT<\/Division>/g' \ + -e 's/Viruses<\/Division>/VRL<\/Division>/g' \ +> taxa.xml +cat taxa.xml | +xtract -pattern Taxon -COMM "(-)" -COMM GenbankCommonName -PGCODE "(-)" \ + -block Property -if PropName -equals pgcode -PGCODE PropValueInt \ + -block Taxon -element ScientificName "&COMM" GCId MGCId "&PGCODE" TaxId Division Lineage > tax_table.txt +cat tax_table.txt | sort -f > sorted_taxlist.txt diff --git a/c++/src/objects/seqfeat/seqfeat.asn b/c++/src/objects/seqfeat/seqfeat.asn index b12e0403..28041676 100644 --- a/c++/src/objects/seqfeat/seqfeat.asn +++ b/c++/src/objects/seqfeat/seqfeat.asn @@ -1,4 +1,4 @@ ---$Revision: 509630 $ +--$Revision: 547741 $ --********************************************************************** -- -- NCBI Sequence Feature elements @@ -1121,6 +1121,7 @@ OrgMod ::= SEQUENCE { bio-material (36) , metagenome-source (37) , type-material (38) , + nomenclature (39) , -- code of nomenclature in subname (B,P,V,Z or combination) old-lineage (253) , old-name (254) , other (255) } , -- ASN5: old-name (254) will be added to next spec diff --git a/c++/src/objects/seqloc/Seq_id.cpp b/c++/src/objects/seqloc/Seq_id.cpp index d700d330..5a80af50 100644 --- a/c++/src/objects/seqloc/Seq_id.cpp +++ b/c++/src/objects/seqloc/Seq_id.cpp @@ -1,4 +1,4 @@ -/* $Id: Seq_id.cpp 516491 2016-10-13 17:39:08Z ivanov $ +/* $Id: Seq_id.cpp 542765 2017-08-02 14:41:08Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -442,7 +443,7 @@ CSeq_id::E_SIC CSeq_id::Compare(const CSeq_id& sid2) const } -TIntId CSeq_id::CompareOrdered(const CSeq_id& sid2) const +int CSeq_id::CompareOrdered(const CSeq_id& sid2) const { int ret = Which() - sid2.Which(); if ( ret != 0 ) { @@ -467,7 +468,12 @@ TIntId CSeq_id::CompareOrdered(const CSeq_id& sid2) const case e_General: return GetGeneral().Compare(sid2.GetGeneral()); case e_Gi: - return GetGi() - sid2.GetGi(); + if ( GetGi() < sid2.GetGi() ) { + return -1; + } + else { + return GetGi() > sid2.GetGi(); + } case e_Pdb: return GetPdb().Compare(sid2.GetPdb()); default: @@ -601,6 +607,7 @@ static const TAccInfoMapEntry sc_AccInfoArray[] = { { "ddbj_other_nuc", CSeq_id::eAcc_ddbj_other_nuc }, { "ddbj_patent", CSeq_id::eAcc_ddbj_patent }, { "ddbj_prot", CSeq_id::eAcc_ddbj_prot }, + { "ddbj_targeted_nuc", CSeq_id::eAcc_ddbj_targeted_nuc }, { "ddbj_tpa_chromosome", CSeq_id::eAcc_ddbj_tpa_chromosome }, { "ddbj_tpa_con", CSeq_id::eAcc_ddbj_tpa_con }, { "ddbj_tpa_nuc", CSeq_id::eAcc_ddbj_tpa_nuc }, @@ -620,6 +627,7 @@ static const TAccInfoMapEntry sc_AccInfoArray[] = { { "embl_dirsub", CSeq_id::eAcc_embl_dirsub }, { "embl_est", CSeq_id::eAcc_embl_est }, { "embl_genome", CSeq_id::eAcc_embl_genome }, + { "embl_gss", CSeq_id::eAcc_embl_gss }, { "embl_htgs", CSeq_id::eAcc_embl_htgs }, { "embl_mga", CSeq_id::eAcc_embl_mga }, { "embl_other_nuc", CSeq_id::eAcc_embl_other_nuc }, @@ -639,6 +647,7 @@ static const TAccInfoMapEntry sc_AccInfoArray[] = { { "embl_wgsm_prot", CSeq_id::eAcc_embl_wgsm_prot }, { "gb_backbone", CSeq_id::eAcc_gb_backbone }, { "gb_cdna", CSeq_id::eAcc_gb_cdna }, + { "gb_chromosome", CSeq_id::eAcc_gb_chromosome }, { "gb_con", CSeq_id::eAcc_gb_con }, { "gb_ddbj", CSeq_id::eAcc_gb_ddbj }, { "gb_dirsub", CSeq_id::eAcc_gb_dirsub }, @@ -662,6 +671,7 @@ static const TAccInfoMapEntry sc_AccInfoArray[] = { { "gb_tpa_con", CSeq_id::eAcc_gb_tpa_con }, { "gb_tpa_nuc", CSeq_id::eAcc_gb_tpa_nuc }, { "gb_tpa_prot", CSeq_id::eAcc_gb_tpa_prot }, + { "gb_tpa_segset", CSeq_id::eAcc_gb_tpa_segset }, { "gb_tpa_wgs_nuc", CSeq_id::eAcc_gb_tpa_wgs_nuc }, { "gb_tpa_wgs_prot", CSeq_id::eAcc_gb_tpa_wgs_prot }, { "gb_tpa_wgsm_nuc", CSeq_id::eAcc_gb_tpa_wgsm_nuc }, @@ -746,6 +756,20 @@ struct SAccGuide : public CObject }; typedef map TMainMap; + struct SHints { + SHints() + : prev_type(CSeq_id::eAcc_unknown), prev_submap(NULL) + {} + + TAccInfo FindAccInfo(CTempString name); + SSubMap& FindSubMap(TMainMap& rules, TFormatCode fmt); + + TAccInfo prev_type; + CTempString prev_type_name; + TMainMap::value_type* prev_submap; + TSpecialMap::iterator prev_special; + }; + SAccGuide(void); SAccGuide(const string& filename) : count(0) @@ -754,7 +778,7 @@ struct SAccGuide : public CObject : count(0) { x_Load(lr); } - void AddRule(const CTempString& rule); + void AddRule(const CTempString& rule, SHints& hints); TAccInfo Find(TFormatCode fmt, const CTempString& acc_or_pfx, string* key_used = NULL); static TFormatCode s_Key(unsigned short letters, unsigned short digits) @@ -770,7 +794,43 @@ private: void x_InitGeneral(void); }; -void SAccGuide::AddRule(const CTempString& rule) +static const SAccGuide::TAccInfo kUnrecognized + = static_cast(-1); + +inline +SAccGuide::TAccInfo SAccGuide::SHints::FindAccInfo(CTempString name) +{ + if (name == prev_type_name) { + return prev_type; + } else { + TAccInfoMap::const_iterator it = sc_AccInfoMap.find(name); + if (it == sc_AccInfoMap.end()) { + return kUnrecognized; + } else { + prev_type_name = it->first; + return prev_type = it->second; + } + } +} + +inline +SAccGuide::SSubMap& SAccGuide::SHints::FindSubMap(SAccGuide::TMainMap& rules, + SAccGuide::TFormatCode fmt) +{ + if (prev_submap != NULL && prev_submap->first == fmt) { + return prev_submap->second; + } else { + SAccGuide::TMainMap::iterator it = rules.lower_bound(fmt); + if (it == rules.end() || it->first != fmt) { + it = rules.insert(it, make_pair(fmt, SAccGuide::SSubMap())); + } + prev_submap = &*it; + prev_special = it->second.specials.end(); + return it->second; + } +} + +void SAccGuide::AddRule(const CTempString& rule, SHints& hints) { CTempString tmp1, tmp2; vector tokens; @@ -803,17 +863,23 @@ void SAccGuide::AddRule(const CTempString& rule) TFormatCode fmt = s_Key(NStr::StringToUInt(tmp1, NStr::fConvErr_NoThrow), NStr::StringToUInt(tmp2, NStr::fConvErr_NoThrow)); - TAccInfoMap::const_iterator it = sc_AccInfoMap.find(tokens[2]); - if (it == sc_AccInfoMap.end()) { + TAccInfo value = hints.FindAccInfo(tokens[2]); + if (value == kUnrecognized) { string key_used; TAccInfo old = Find(fmt, tokens[1], &key_used); if (old != CSeq_id::eAcc_unknown) { + string old_name; + if (old == hints.prev_type) { + old_name = hints.prev_type_name; + } else { + old_name = "0x" + NStr::UIntToString(old, 16); + } if ( !key_used.empty() ) { key_used = " (per " + key_used + ')'; } ERR_POST_X(8, Warning << "SAccGuide::AddRule: " << count << ": ignoring refinement of " << tokens[1] - << " from 0x" << hex << old << key_used + << " from " << old_name << key_used << " to unrecognized accession type " << tokens[2]); } else { ERR_POST_X(3, "SAccGuide::AddRule: " << count @@ -821,21 +887,21 @@ void SAccGuide::AddRule(const CTempString& rule) << " for " << tokens[1]); } } else { - TAccInfo value = it->second; + SSubMap& submap = hints.FindSubMap(rules, fmt); if (tokens.size() == 4) { value = TAccInfo(value | CSeq_id::fAcc_specials); } if (tokens[1].find_first_of("?*") == NPOS) { - rules[fmt].prefixes[tokens[1]] = value; + submap.prefixes[tokens[1]] = value; } else { // Account for possible refinements of fallback definitions - NON_CONST_ITERATE (TPairs, wit, rules[fmt].wildcards) { + NON_CONST_ITERATE (TPairs, wit, submap.wildcards) { if (wit->first == tokens[1]) { wit->second = value; return; } } - rules[fmt].wildcards.push_back(TPair(tokens[1], value)); + submap.wildcards.push_back(TPair(tokens[1], value)); } } } else if (tokens.size() == 3 && NStr::EqualNocase(tokens[0], "special")) { @@ -843,52 +909,77 @@ void SAccGuide::AddRule(const CTempString& rule) pos2 = tokens[1].find('-', pos); TFormatCode fmt = s_Key(pos, ((pos2 == NPOS) ? tokens[1].size() : pos2) - pos); - TAccInfoMap::const_iterator it = sc_AccInfoMap.find(tokens[2]); - if (it == sc_AccInfoMap.end()) { + TAccInfo value = hints.FindAccInfo(tokens[2]); + if (value == kUnrecognized) { string key_used; TAccInfo old = Find(fmt, tokens[1], &key_used); if (old) { + string old_name; + if (old == hints.prev_type) { + old_name = hints.prev_type_name; + } else { + old_name = "0x" + NStr::UIntToString(old, 16); + } if ( !key_used.empty() ) { key_used = " (per " + key_used + ')'; } ERR_POST_X(4, Warning << "SAccGuide::AddRule: " << count << ": unrecognized accession type " << tokens[2] << " for special case " << tokens[1] - << "; falling back to " << old << key_used); + << "; falling back to " << old_name << key_used); } else { ERR_POST_X(9, Warning << "SAccGuide::AddRule: " << count << ": unrecognized accession type " << tokens[2] << " for stray(!) special case " << tokens[1]); } } else { - TAccInfo value = it->second; + SSubMap& submap = hints.FindSubMap(rules, fmt); + if (pos2 == NPOS) { + tmp1 = tmp2 = tokens[1]; + } else { + tmp1.assign(tokens[1], 0, pos2); + tmp2.assign(tokens[1], pos2 + 1, NPOS); + } + hints.prev_special + = submap.specials.insert(hints.prev_special, + make_pair(tmp2, TPair(tmp1, value))); + // Account for possible refinement. + hints.prev_special->second.second = value; + /* if (pos2 == NPOS) { - rules[fmt].specials[tokens[1]] = TPair(tokens[1], value); + submap.specials[tokens[1]] = TPair(tokens[1], value); } else { // _VERIFY(NStr::SplitInTwo(tokens[1], "-", tmp1, tmp2)); tmp1.assign(tokens[1], 0, pos2); tmp2.assign(tokens[1], pos2 + 1, NPOS); - rules[fmt].specials[tmp2] = TPair(tmp1, value); + submap.specials[tmp2] = TPair(tmp1, value); } + */ } } else if (tokens.size() == 3 && NStr::EqualNocase(tokens[0], "gnl")) { string key(tokens[1]); NStr::ToUpper(key); - TAccInfoMap::const_iterator it = sc_AccInfoMap.find(tokens[2]); - if (it == sc_AccInfoMap.end()) { + TAccInfo value = hints.FindAccInfo(tokens[2]); + if (value == kUnrecognized) { TPrefixes::const_iterator it2 = general.find(key); if (it2 == general.end()) { ERR_POST_X(3, "SAccGuide::AddRule: " << count << ": unrecognized accession type " << tokens[2] << " for " << key); } else { + string old_name; + if (it2->second == hints.prev_type) { + old_name = hints.prev_type_name; + } else { + old_name = "0x" + NStr::UIntToString(it2->second, 16); + } ERR_POST_X(8, Warning << "SAccGuide::AddRule: " << count - << ": ignoring refinement of " << key - << " from 0x" << hex << it2->second - << " to unrecognized accession type " << tokens[2]); + << ": ignoring refinement of " << key << " from " + << old_name << " to unrecognized accession type " + << tokens[2]); } } else { - general[key] = it->second; + general[key] = value; } } else { ERR_POST_X(5, Warning << "SAccGuide::AddRule: " << count @@ -943,44 +1034,14 @@ SAccGuide::TAccInfo SAccGuide::Find(TFormatCode fmt, } -static bool s_IsFileOld(const string& file) -{ - static const char vcs_id_start[] = "# $Id: accguide.inc "; - if ( !NStr::StartsWith(kBuiltInGuide[0], vcs_id_start) ) { - return false; - } - const char* rev_start = kBuiltInGuide[0] + sizeof(vcs_id_start); - const char* date_start = strchr(rev_start, ' '); - if (date_start != NULL) { - ++date_start; - } else { - return false; - } - const char* time_start = strchr(date_start + 1, ' '); - if (time_start != NULL) { - ++time_start; - } else { - return false; - } - const char* time_end = strchr(time_start + 1, ' '); - if (time_end == NULL) { - return false; - } - string builtin_timestamp_str(date_start, time_end - date_start); - CTime builtin_timestamp(builtin_timestamp_str, "Y-M-D h:m:sZ"); - CTime file_timestamp; - CFile(file).GetTime(&file_timestamp); - return file_timestamp < builtin_timestamp; -} - - SAccGuide::SAccGuide(void) : count(0) { bool file_is_old = false; {{ string file = g_FindDataFile("accguide.txt"); - if ( !file.empty() && !(file_is_old = s_IsFileOld(file))) { + if ( !file.empty() && + !(file_is_old = g_IsDataFileOld(file, kBuiltInGuide[0])) ) { try { x_Load(file); } STD_CATCH_ALL_X(1, "SAccGuide::SAccGuide") @@ -996,8 +1057,9 @@ SAccGuide::SAccGuide(void) } static const unsigned int kNumBuiltInRules = sizeof(kBuiltInGuide) / sizeof(*kBuiltInGuide); + SHints hints; for (unsigned int i = 0; i < kNumBuiltInRules; ++i) { - AddRule(kBuiltInGuide[i]); + AddRule(kBuiltInGuide[i], hints); } } x_InitGeneral(); @@ -1026,8 +1088,9 @@ void SAccGuide::x_Load(const string& filename) void SAccGuide::x_Load(ILineReader& in) { + SHints hints; do { - AddRule(*++in); + AddRule(*++in, hints); } while ( !in.AtEOF() ); } @@ -2244,7 +2307,8 @@ int CSeq_id::BaseTextScore(void) const { switch (Which()) { case e_not_set: return 83; - case e_Giim: case e_Gi: return 20; + case e_Giim: return 20; + case e_Gi: return PreferAccessionOverGi() ? kMaxScore + 1 : 20; case e_General: case e_Gibbsq: case e_Gibbmt: return 15; case e_Local: case e_Patent: return 10; case e_Gpipe: case e_Named_annot_track: return 9; @@ -2264,7 +2328,7 @@ int CSeq_id::BaseBestRankScore(void) const case e_Gpipe: return 68; case e_Patent: return 67; case e_Other: return 65; - case e_Gi: return 51; + case e_Gi: return PreferAccessionOverGi() ? kMaxScore + 1 : 51; default: return 60; } } @@ -2277,7 +2341,7 @@ int CSeq_id::BaseFastaNAScore(void) const case e_not_set: case e_Giim: case e_Pir: case e_Swissprot: case e_Prf: return 255; case e_Local: return 230; - case e_Gi: return 120; + case e_Gi: return PreferAccessionOverGi() ? kMaxScore + 1 : 120; case e_General: { const string& db = GetGeneral().GetDb(); @@ -2286,11 +2350,15 @@ int CSeq_id::BaseFastaNAScore(void) const db.compare("NCBIFILE") == 0 ) return 240; else - return 50; - } - case e_Patent: return 40; - case e_Gibbsq: case e_Gibbmt: case e_Pdb: return 30; - case e_Other: return 15; + return 100; + } + case e_Patent: return 90; + case e_Pdb: return 80; +// see SQD-4175 ticket for priorities + case e_Gibbsq: return 72; + case e_Gibbmt: return 71; + case e_Genbank: return 70; + case e_Other: return 15; default: /* [third party] GB/EMBL/DDBJ */ return 20; } } @@ -2301,7 +2369,7 @@ int CSeq_id::BaseFastaAAScore(void) const switch (Which()) { case e_not_set: case e_Giim: return 255; case e_Local: return 230; - case e_Gi: return 120; + case e_Gi: return PreferAccessionOverGi() ? kMaxScore + 1 : 120; case e_General: { const string& db = GetGeneral().GetDb(); @@ -2315,7 +2383,10 @@ int CSeq_id::BaseFastaAAScore(void) const case e_Patent: return 80; case e_Prf: return 70; case e_Pdb: return 50; - case e_Gibbsq: case e_Gibbmt: return 40; +// see SQD-4175 ticket for priorities + case e_Gibbsq: return 42; + case e_Gibbmt: return 41; + case e_Genbank: return 40; case e_Pir: return 30; case e_Swissprot: return 20; case e_Other: return 15; @@ -2504,6 +2575,29 @@ void CSeq_id::GetMatchingIds(TSeqIdHandles& matches) const } +NCBI_PARAM_DECL(bool, SeqId, PreferAccessionOverGi); +NCBI_PARAM_DEF_EX(bool, SeqId, PreferAccessionOverGi, false, eParam_NoThread, + SEQ_ID_PREFER_ACCESSION_OVER_GI); +typedef NCBI_PARAM_TYPE(SeqId, PreferAccessionOverGi) TPreferAccessionOverGi; + +NCBI_PARAM_DECL(bool, SeqId, AvoidGi); +NCBI_PARAM_DEF_EX(bool, SeqId, AvoidGi, false, eParam_NoThread, + SEQ_ID_AVOID_GI); +typedef NCBI_PARAM_TYPE(SeqId, AvoidGi) TAvoidGi; + + +bool CSeq_id::PreferAccessionOverGi(void) +{ + return TPreferAccessionOverGi::GetDefault() || AvoidGi(); +} + + +bool CSeq_id::AvoidGi(void) +{ + return TAvoidGi::GetDefault(); +} + + SSeqIdRange::SSeqIdRange(const CTempString& s, TFlags flags) : start(0), stop(0), digits(0), acc_info(CSeq_id::eAcc_unknown) { diff --git a/c++/src/objects/seqloc/Seq_loc.cpp b/c++/src/objects/seqloc/Seq_loc.cpp index 15f06b20..4657e73e 100644 --- a/c++/src/objects/seqloc/Seq_loc.cpp +++ b/c++/src/objects/seqloc/Seq_loc.cpp @@ -1,4 +1,4 @@ -/* $Id: Seq_loc.cpp 514371 2016-09-21 15:22:54Z ivanov $ +/* $Id: Seq_loc.cpp 545905 2017-09-12 14:23:04Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -51,6 +51,7 @@ #include #include #include +#include #include @@ -4075,6 +4076,8 @@ private: CRef x_SetFuzz(TFuzz& fuzz, const CInt_fuzz* copy_from) { + TFuzz copy_from_cref; + if (copy_from == fuzz) copy_from_cref.Reset(copy_from); // Since TFuzz is a const-ref, setting fuzz requires creating // a new object CRef new_fuzz(new CInt_fuzz); @@ -4161,11 +4164,7 @@ private: case CInt_fuzz::e_Alt: { // Use union - CRef new_fuzz = x_SetFuzz(fuzz, NULL); - new_fuzz->SetAlt().insert( - new_fuzz->SetAlt().end(), - fz.GetAlt().begin(), - fz.GetAlt().end()); + CRef new_fuzz = x_SetFuzz(fuzz, fuzz); new_fuzz->SetAlt().insert( new_fuzz->SetAlt().end(), ofz.GetAlt().begin(), @@ -4219,11 +4218,50 @@ private: }; -typedef CRangeWithFuzz TRangeWithFuzz; -typedef vector TRanges; -typedef map TIdToRangeMap; -typedef CRangeCollection TRangeColl; -typedef map TIdToRangeColl; +class CSeq_id_Handle_Wrapper +{ +public: + CSeq_id_Handle_Wrapper(void) {} + + CSeq_id_Handle_Wrapper(const CSeq_id_Handle& idh, const CSeq_id& id) + : m_Handle(idh) + { + if (id.IsLocal() && id.GetLocal().IsStr()) { + m_Id.Reset(&id); + } + } + + CConstRef GetSeqId(void) const { return m_Id ? m_Id : m_Handle.GetSeqId(); } + + const CSeq_id_Handle& GetHandle(void) const { return m_Handle; } + + bool operator== (const CSeq_id_Handle_Wrapper& handle) const + { + return m_Handle == handle.m_Handle; + } + + bool operator!= (const CSeq_id_Handle_Wrapper& handle) const + { + return m_Handle != handle.m_Handle; + } + bool operator< (const CSeq_id_Handle_Wrapper& handle) const + { + return m_Handle < handle.m_Handle; + } + + DECLARE_OPERATOR_BOOL(m_Handle); + +private: + CSeq_id_Handle m_Handle; + CConstRef m_Id; +}; + + +typedef CRangeWithFuzz TRangeWithFuzz; +typedef vector TRanges; +typedef map TIdToRangeMap; +typedef CRangeCollection TRangeColl; +typedef map TIdToRangeColl; class CRange_Less @@ -4337,7 +4375,7 @@ bool x_MergeRanges(TRangeWithFuzz& rg1, ENa_strand str1, static void x_PushRange(CSeq_loc& dst, - const CSeq_id_Handle& idh, + const CSeq_id_Handle_Wrapper& idh, const TRangeWithFuzz& rg, ENa_strand strand) { @@ -4445,10 +4483,10 @@ void x_SingleRange(CSeq_loc& dst, { // Create a single range TRangeWithFuzz total_rg(TRangeWithFuzz::GetEmpty()); - CSeq_id_Handle first_id; + CSeq_id_Handle_Wrapper first_id; ENa_strand first_strand = eNa_strand_unknown; for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) { - CSeq_id_Handle next_id = syn_mapper.GetBestSynonym(it.GetSeq_id()); + CSeq_id_Handle_Wrapper next_id(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id()); if ( !next_id ) { // Ignore NULLs continue; @@ -4546,12 +4584,12 @@ void x_MergeNoSort(CSeq_loc& dst, ISynonymMapper& syn_mapper) { _ASSERT((flags & CSeq_loc::fSort) == 0); - CSeq_id_Handle last_id; + CSeq_id_Handle_Wrapper last_id; TRangeWithFuzz last_rg(TRangeWithFuzz::GetEmpty()); ENa_strand last_strand = eNa_strand_unknown; bool have_range = false; for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) { - CSeq_id_Handle idh = syn_mapper.GetBestSynonym(it.GetSeq_id()); + CSeq_id_Handle_Wrapper idh(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id()); // ID and strand must match TRangeWithFuzz it_rg(it); if ( have_range && last_id == idh ) { @@ -4608,7 +4646,7 @@ void x_MergeAndSort(CSeq_loc& dst, // Split location by by id/strand/range for (CSeq_loc_CI it(src, CSeq_loc_CI::eEmpty_Allow); it; ++it) { - CSeq_id_Handle idh = syn_mapper.GetBestSynonym(it.GetSeq_id()); + CSeq_id_Handle_Wrapper idh(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id()); if ( IsReverse(it.GetStrand()) ) { id_map_minus[idh].push_back(TRangeWithFuzz(it)); } @@ -4642,10 +4680,10 @@ void x_SingleRange(CSeq_loc& dst, ILengthGetter& len_getter) { TRangeWithFuzz total_rg(TRangeWithFuzz::GetEmpty()); - CSeq_id_Handle first_id; + CSeq_id_Handle_Wrapper first_id; ENa_strand first_strand = eNa_strand_unknown; for (CSeq_loc_CI it(minuend, CSeq_loc_CI::eEmpty_Allow); it; ++it) { - CSeq_id_Handle next_id = syn_mapper.GetBestSynonym(it.GetSeq_id()); + CSeq_id_Handle_Wrapper next_id(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id()); if ( !next_id ) { // Ignore NULLs continue; @@ -4742,12 +4780,12 @@ void x_SubNoSort(CSeq_loc& dst, CSeq_loc::TOpFlags flags) { _ASSERT((flags & CSeq_loc::fSort) == 0); - CSeq_id_Handle last_id; + CSeq_id_Handle_Wrapper last_id; TRangeWithFuzz last_rg(TRangeWithFuzz::GetEmpty()); ENa_strand last_strand = eNa_strand_unknown; bool have_range = false; for (CSeq_loc_CI it(minuend, CSeq_loc_CI::eEmpty_Allow); it; ++it) { - CSeq_id_Handle idh = syn_mapper.GetBestSynonym(it.GetSeq_id()); + CSeq_id_Handle_Wrapper idh(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id()); bool rev = IsReverse(it.GetStrand()); TRangeWithFuzz it_range = TRangeWithFuzz(it); if ( it_range.IsWhole() ) { @@ -4877,7 +4915,7 @@ void x_SubAndSort(CSeq_loc& dst, eNa_strand_minus : eNa_strand_unknown; for (CSeq_loc_CI it(minuend, CSeq_loc_CI::eEmpty_Allow); it; ++it) { - CSeq_id_Handle idh = syn_mapper.GetBestSynonym(it.GetSeq_id()); + CSeq_id_Handle_Wrapper idh(syn_mapper.GetBestSynonym(it.GetSeq_id()), it.GetSeq_id()); TRangeWithFuzz it_range = TRangeWithFuzz(it); if ( it_range.IsWhole() ) { it_range.SetOpen(0, len_getter.GetLength(it.GetSeq_id())); @@ -5055,7 +5093,7 @@ CRef CSeq_loc::Subtract(const CSeq_loc& other, if ( it.IsEmpty() ) { continue; } - CSeq_id_Handle idh = syn_mapper->GetBestSynonym(it.GetSeq_id()); + CSeq_id_Handle_Wrapper idh(syn_mapper->GetBestSynonym(it.GetSeq_id()), it.GetSeq_id()); TRangeColl& rmap = IsReverse(it.GetStrand()) ? rg_coll_minus[idh] : rg_coll_plus[idh]; rmap += TRangeWithFuzz(it); diff --git a/c++/src/objects/seqloc/accguide.inc b/c++/src/objects/seqloc/accguide.inc index a5e81092..e9e63f5e 100644 --- a/c++/src/objects/seqloc/accguide.inc +++ b/c++/src/objects/seqloc/accguide.inc @@ -1,4 +1,4 @@ -/* $Id: accguide.inc 519343 2016-11-15 13:41:14Z ucko $ +/* $Id: accguide.inc 548063 2017-10-10 13:00:13Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,7 +31,7 @@ */ static const char* const kBuiltInGuide[] = { - "# $Id: accguide.inc 519343 2016-11-15 13:41:14Z ucko $", + "# $Id: accguide.inc 548063 2017-10-10 13:00:13Z ucko $", "version 1 # of file format", "", "# 8-character protein accessions", @@ -48,14 +48,14 @@ static const char* const kBuiltInGuide[] = { "3+5 I?? ddbj_tpa_wgs_prot", "3+5 J?? gb_tsa_prot", "3+5 K?? gb_wgs_prot", - "3+5 L?? ddbj_tsa_prot", + "3+5 L?? ddbj_prot # mixed TSA and TLS", "3+5 M?? gb_wgs_prot", "3+5 N?? gb_wgs_prot", "3+5 O?? gb_wgs_prot", "3+5 P?? gb_wgs_prot", "3+5 Q?? gb_prot", "3+5 R?? gb_prot", - "3+5 S?? embl_prot", + "3+5 S?? embl_prot *", "3+5 ??? unreserved_prot", "", "# Genome pipeline accessions", @@ -122,12 +122,12 @@ static const char* const kBuiltInGuide[] = { "4+8 L??? gb_wgs_nuc", "4+9 L??? gb_wgs_nuc", "4+10 L??? gb_wgs_nuc", - "4+8 M??? gb_wgs_nuc", - "4+9 M??? gb_wgs_nuc", - "4+10 M??? gb_wgs_nuc", - "4+8 N??? gb_wgs_nuc", - "4+9 N??? gb_wgs_nuc", - "4+10 N??? gb_wgs_nuc", + "4+8 M??? gb_wgs_nuc # gb_tsa_nuc?", + "4+9 M??? gb_wgs_nuc # gb_tsa_nuc?", + "4+10 M??? gb_wgs_nuc # gb_tsa_nuc?", + "4+8 N??? gb_wgs_nuc # gb_tsa_nuc?", + "4+9 N??? gb_wgs_nuc # gb_tsa_nuc?", + "4+10 N??? gb_wgs_nuc # gb_tsa_nuc?", "4+8 O??? embl_wgs_nuc", "4+9 O??? embl_wgs_nuc", "4+10 O??? embl_wgs_nuc", @@ -143,6 +143,12 @@ static const char* const kBuiltInGuide[] = { "4+8 S??? gb_wgs_nuc # specifically, USPTO pre-grant patent data", "4+9 S??? gb_wgs_nuc # specifically, USPTO pre-grant patent data", "4+10 S??? gb_wgs_nuc # specifically, USPTO pre-grant patent data", + "4+8 T??? ddbj_wgs_nuc # fallback to placate older clients", + "4+9 T??? ddbj_wgs_nuc # fallback to placate older clients", + "4+10 T??? ddbj_wgs_nuc # fallback to placate older clients", + "4+8 T??? ddbj_targeted_nuc", + "4+9 T??? ddbj_targeted_nuc", + "4+10 T??? ddbj_targeted_nuc", "", "# Mass sequence Genome for Annotation", "5+7 A???? ddbj_other_nuc", @@ -197,46 +203,46 @@ static const char* const kBuiltInGuide[] = { "# 6-character accessions (mixed, but generally nucleotide)", "1+5 A embl_patent", "1+5 B gb_gss", - "1+5 C ddbj_est", - "1+5 D ddbj_dirsub", + "1+5 C ddbj_est *", + "1+5 D ddbj_dirsub *", "1+5 E ddbj_patent", - "1+5 F embl_est", + "1+5 F embl_est *", "1+5 G gb_sts", "1+5 H gb_est", "1+5 I gb_patent", "1+5 J gsdb_dirsub", "1+5 K gsdb_dirsub", - "1+5 L gsdb_dirsub", - "1+5 M gsdb_dirsub", + "1+5 L gsdb_dirsub *", + "1+5 M gsdb_dirsub *", "1+5 N unreserved_nuc *", "1+5 O swissprot", "1+5 P swissprot", "1+5 Q swissprot", "1+5 R gb_est", "1+5 S gb_backbone", - "1+5 T gb_est", - "1+5 U gb_dirsub", + "1+5 T gb_est *", + "1+5 U gb_dirsub *", "1+5 V embl_dirsub", "1+5 W gb_est", - "1+5 X embl_dirsub", - "1+5 Y embl_dirsub", - "1+5 Z embl_dirsub", + "1+5 X embl_dirsub *", + "1+5 Y embl_dirsub *", + "1+5 Z embl_dirsub *", "1+5 ? unreserved_nuc", "", "# 8-character nucleotide accessions", "2+6 AA gb_est", - "2+6 AB ddbj_dirsub", + "2+6 AB ddbj_dirsub *", "2+6 AC gb_htgs", "2+6 AD gb_gsdb", "2+6 AE gb_genome", - "2+6 AF gb_dirsub", - "2+6 AG ddbj_genome", + "2+6 AF gb_dirsub *", + "2+6 AG ddbj_gss *", "2+6 AH gb_segset", "2+6 AI gb_est", - "2+6 AJ embl_dirsub", + "2+6 AJ embl_dirsub *", "2+6 AK ddbj_mrna", - "2+6 AL embl_other_nuc # nominally for genome projects, but unrestricted", - "2+6 AM embl_dirsub", + "2+6 AL embl_dirsub *", + "2+6 AM embl_dirsub *", "2+6 AN embl_con", "2+6 AO unreserved_nuc", "2+6 AP ddbj_genome", @@ -244,11 +250,11 @@ static const char* const kBuiltInGuide[] = { "2+6 AR gb_patent", "2+6 AS gb_other_nuc", "2+6 AT ddbj_est", - "2+6 AU ddbj_est", + "2+6 AU ddbj_est *", "2+6 AV ddbj_est", "2+6 AW gb_est", - "2+6 AX embl_patent", - "2+6 AY gb_dirsub", + "2+6 AX embl_patent *", + "2+6 AY gb_dirsub *", "2+6 AZ gb_gss", "2+6 BA ddbj_con", "2+6 BB ddbj_est", @@ -261,7 +267,8 @@ static const char* const kBuiltInGuide[] = { "2+6 BI gb_est", "2+6 BJ ddbj_est", "2+6 BK gb_tpa_nuc", - "2+6 BL gb_tpa_nuc", + "2+6 BL gb_tpa_nuc # Fallback to placate older clients", + "2+6 BL gb_tpa_segset # Formally CON but not necessarily genomic", "2+6 BM gb_est", "2+6 BN embl_tpa_nuc", "2+6 BO unreserved_nuc", @@ -273,7 +280,7 @@ static const char* const kBuiltInGuide[] = { "2+6 BU gb_est", "2+6 BV gb_sts", "2+6 BW ddbj_est", - "2+6 BX embl_other_nuc", + "2+6 BX embl_dirsub *", "2+6 BY ddbj_est", "2+6 BZ gb_gss", "2+6 CA gb_est", @@ -288,15 +295,16 @@ static const char* const kBuiltInGuide[] = { "2+6 CJ ddbj_est", "2+6 CK gb_est", "2+6 CL gb_gss", - "2+6 CM gb_con", + "2+6 CM gb_con # Fallback to placate older clients", + "2+6 CM gb_chromosome", "2+6 CN gb_est", "2+6 CO gb_est", - "2+6 CP gb_genome", + "2+6 CP gb_genome *", "2+6 CQ embl_patent", - "2+6 CR embl_other_nuc", + "2+6 CR embl_dirsub *", "2+6 CS embl_patent", - "2+6 CT embl_other_nuc", - "2+6 CU embl_other_nuc", + "2+6 CT embl_dirsub *", + "2+6 CU embl_dirsub *", "2+6 CV gb_est", "2+6 CW gb_gss", "2+6 CX gb_est", @@ -306,7 +314,7 @@ static const char* const kBuiltInGuide[] = { "2+6 DB ddbj_est", "2+6 DC ddbj_est", "2+6 DD ddbj_patent", - "2+6 DE ddbj_gss", + "2+6 DE ddbj_gss *", "2+6 DF ddbj_con", "2+6 DG ddbj_con", "2+6 DH ddbj_gss", @@ -317,10 +325,10 @@ static const char* const kBuiltInGuide[] = { "2+6 DM ddbj_patent", "2+6 DN gb_est", "2+6 DO unreserved_nuc", - "2+6 DP gb_htgs", - "2+6 DQ gb_dirsub", + "2+6 DP gb_htgs # HTG scaffolds; look like gb_con, but built on htgs parts", + "2+6 DQ gb_dirsub *", "2+6 DR gb_est", - "2+6 DS gb_con", + "2+6 DS gb_con *", "2+6 DT gb_est", "2+6 DU gb_gss", "2+6 DV gb_est", @@ -333,7 +341,7 @@ static const char* const kBuiltInGuide[] = { "2+6 EC gb_est", "2+6 ED gb_gss", "2+6 EE gb_est", - "2+6 EF gb_dirsub", + "2+6 EF gb_dirsub *", "2+6 EG gb_est", "2+6 EH gb_est", "2+6 EI gb_gss", @@ -348,7 +356,7 @@ static const char* const kBuiltInGuide[] = { "2+6 ER gb_gss", "2+6 ES gb_est", "2+6 ET gb_gss", - "2+6 EU gb_dirsub", + "2+6 EU gb_dirsub *", "2+6 EV gb_est", "2+6 EW gb_est", "2+6 EX gb_est", @@ -363,15 +371,15 @@ static const char* const kBuiltInGuide[] = { "2+6 FG gb_est", "2+6 FH gb_gss", "2+6 FI gb_gss", - "2+6 FJ gb_dirsub", + "2+6 FJ gb_dirsub *", "2+6 FK gb_est", "2+6 FL gb_est", - "2+6 FM embl_dirsub", - "2+6 FN embl_dirsub", - "2+6 FO embl_dirsub", - "2+6 FP embl_other_nuc", - "2+6 FQ embl_other_nuc", - "2+6 FR embl_other_nuc", + "2+6 FM embl_dirsub *", + "2+6 FN embl_dirsub *", + "2+6 FO embl_dirsub *", + "2+6 FP embl_dirsub *", + "2+6 FQ embl_dirsub *", + "2+6 FR embl_dirsub *", "2+6 FS ddbj_est", "2+6 FT ddbj_gss", "2+6 FU ddbj_patent", @@ -396,11 +404,11 @@ static const char* const kBuiltInGuide[] = { "2+6 GN embl_patent", "2+6 GO gb_est", "2+6 GP gb_patent", - "2+6 GQ gb_dirsub", + "2+6 GQ gb_dirsub *", "2+6 GR gb_est", "2+6 GS gb_gss", "2+6 GT gb_est", - "2+6 GU gb_dirsub", + "2+6 GU gb_dirsub *", "2+6 GV gb_patent", "2+6 GW gb_est", "2+6 GX gb_patent", @@ -410,27 +418,27 @@ static const char* const kBuiltInGuide[] = { "2+6 HB embl_patent", "2+6 HC embl_patent", "2+6 HD embl_patent", - "2+6 HE embl_dirsub", - "2+6 HF embl_dirsub", - "2+6 HG embl_dirsub", + "2+6 HE embl_dirsub *", + "2+6 HF embl_dirsub *", + "2+6 HG embl_dirsub *", "2+6 HH embl_patent", "2+6 HI embl_patent", "2+6 HJ gb_patent", "2+6 HK gb_patent", "2+6 HL gb_patent", - "2+6 HM gb_dirsub", + "2+6 HM gb_dirsub *", "2+6 HN gb_gss", "2+6 HO gb_est", "2+6 HP gb_tsa_nuc", - "2+6 HQ gb_dirsub", + "2+6 HQ gb_dirsub *", "2+6 HR gb_gss", "2+6 HS gb_est", "2+6 HT ddbj_tpa_nuc # fallback to placate older clients", "2+6 HT ddbj_tpa_con", "2+6 HU ddbj_tpa_nuc # fallback to placate older clients", "2+6 HU ddbj_tpa_chromosome", - "2+6 HV gb_patent", - "2+6 HW gb_patent", + "2+6 HV ddbj_patent", + "2+6 HW ddbj_patent", "2+6 HX ddbj_est", "2+6 HY ddbj_est", "2+6 HZ ddbj_patent", @@ -447,7 +455,7 @@ static const char* const kBuiltInGuide[] = { "2+6 JK gb_est", "2+6 JL gb_tsa_nuc", "2+6 JM gb_gss", - "2+6 JN gb_dirsub", + "2+6 JN gb_dirsub *", "2+6 JO gb_tsa_nuc", "2+6 JP gb_tsa_nuc", "2+6 JQ gb_dirsub", @@ -465,14 +473,14 @@ static const char* const kBuiltInGuide[] = { "2+6 KC gb_dirsub", "2+6 KD gb_con", "2+6 KE gb_con", - "2+6 KF gb_dirsub", + "2+6 KF gb_dirsub *", "2+6 KG gb_gss", "2+6 KH gb_patent", "2+6 KI gb_con", - "2+6 KJ gb_dirsub", + "2+6 KJ gb_dirsub *", "2+6 KK gb_con", "2+6 KL gb_con", - "2+6 KM gb_dirsub", + "2+6 KM gb_dirsub *", "2+6 KN gb_con", "2+6 KO gb_gss", "2+6 KP gb_dirsub", @@ -482,9 +490,10 @@ static const char* const kBuiltInGuide[] = { "2+6 KT gb_dirsub", "2+6 KU gb_dirsub", "2+6 KV gb_con", + "2+6 KW gb_other_nuc", "2+6 KX gb_dirsub", "2+6 KY gb_dirsub", - "2+6 K? gb_other_nuc", + "2+6 KZ gb_con", "2+6 LA ddbj_tsa_nuc", "2+6 LB ddbj_gss", "2+6 LC ddbj_dirsub", @@ -495,26 +504,41 @@ static const char* const kBuiltInGuide[] = { "2+6 LH ddbj_tsa_nuc", "2+6 LI ddbj_tsa_nuc", "2+6 LJ ddbj_tsa_nuc", - "2+6 LK embl_other_nuc", - "2+6 LL embl_other_nuc", - "2+6 LM embl_other_nuc", - "2+6 LN embl_other_nuc", - "2+6 LO embl_other_nuc", - "2+6 LP embl_other_nuc", - "2+6 LQ embl_other_nuc", - "2+6 LR embl_other_nuc", - "2+6 LS embl_other_nuc", - "2+6 LT embl_other_nuc", + "2+6 LK embl_dirsub *", + "2+6 LL embl_dirsub", + "2+6 LM embl_dirsub *", + "2+6 LN embl_dirsub *", + "2+6 LO embl_dirsub *", + "2+6 LP embl_patent", + "2+6 LQ embl_patent", + "2+6 LR embl_dirsub # embl_patent?", + "2+6 LS embl_dirsub # embl_patent?", + "2+6 LT embl_dirsub *", "2+6 LU ddbj_est", "2+6 LV ddbj_patent", + "2+6 LW ddbj_other_nuc", "2+6 LX ddbj_patent", - "2+6 LY ddbj_other_nuc", - "2+6 LZ ddbj_other_nuc", + "2+6 LY ddbj_patent", + "2+6 LZ ddbj_patent", "2+6 MA ddbj_other_nuc", "2+6 MB ddbj_other_nuc", "2+6 MC ddbj_other_nuc", "2+6 MD ddbj_other_nuc", "2+6 ME ddbj_other_nuc", + "2+6 MF gb_dirsub", + "2+6 MG gb_dirsub", + "2+6 MH gb_other_nuc", + "2+6 MI gb_other_nuc", + "2+6 MJ gb_other_nuc", + "2+6 MK gb_other_nuc", + "2+6 ML gb_other_nuc", + "2+6 MM gb_other_nuc", + "2+6 MN gb_other_nuc", + "2+6 MO gb_other_nuc", + "2+6 MP embl_patent", + "2+6 MQ embl_patent", + "2+6 MR embl_patent", + "2+6 MS embl_patent", "2+6 ?? unreserved_nuc", "", "# Specially handled type-general Dbtag names; commented out for now in", @@ -527,67 +551,2161 @@ static const char* const kBuiltInGuide[] = { "#gnl TRACE_CHGR general_nuc", "", "# SPECIAL CASES", + "# Mostly in the same order as baseline assignments, but embl_tpa_prot", + "# specials are at the very end because there are so many of them. To", + "# keep to a rough limit of 100 lines per prefix, resort to *_other_nuc", + "# for some heavily mixed ranges.", + "", + "# Some GenBank \"TPA\" 8-character protein accessions are really native.", + "special DAA00001 gb_prot", + "special DAA02110-DAA02116 gb_prot", + "special DAA34794-DAA34795 gb_prot", + "", + "# Nominally ddbj_est.", + "special C21595-C21827 ddbj_dirsub", + "special C22715-C22762 ddbj_dirsub", + "special C22783-C22911 ddbj_dirsub", + "special C24689-C24767 ddbj_dirsub", + "special C75685-C75936 ddbj_dirsub", + "special C95573-C95642 ddbj_dirsub", + "special C99933-C99976 ddbj_dirsub", + "", + "# Nominally ddbj_dirsub. Split out EST ranges, and give the benefit", + "# of the doubt to sequences that look like ddbj_con, ddbj_genome,", + "# ddbj_mrna, or ddbj_other_nuc.", + "special D00922 ddbj_est", + "special D11487-D12469 ddbj_est", + "special D15075-D17289 ddbj_other_nuc # 62 EST ranges", + "special D17812-D21053 ddbj_est", + "special D21355-D26768 ddbj_other_nuc # 118 EST ranges", + "special D26771-D28109 ddbj_est", + "special D28170-D28183 ddbj_est", + "special D28185-D28196 ddbj_est", + "special D28198 ddbj_est", + "special D28200 ddbj_est", + "special D28203 ddbj_est", + "special D28205-D28206 ddbj_est", + "special D28208-D28215 ddbj_est", + "special D28217-D28224 ddbj_est", + "special D28227 ddbj_est", + "special D28229 ddbj_est", + "special D28232 ddbj_est", + "special D28234 ddbj_est", + "special D28281-D28288 ddbj_est", + "special D28290-D28310 ddbj_est", + "special D28312-D28318 ddbj_est", + "special D28320-D28326 ddbj_est", + "special D28603-D28744 ddbj_est", + "special D29018-D29624 ddbj_est", + "special D29993-D30029 ddbj_est", + "special D30816-D31599 ddbj_est", + "special D32304-D32958 ddbj_est", + "special D32960-D33769 ddbj_est", + "special D33771-D34214 ddbj_est", + "special D34216-D34410 ddbj_est", + "special D34412-D34589 ddbj_est", + "special D34640-D35674 ddbj_est", + "special D35676-D36684 ddbj_est", + "special D36686-D42011 ddbj_other_nuc # 101 EST ranges", + "special D42187-D43617 ddbj_est", + "special D44612-D49352 ddbj_other_nuc # 70 EST ranges", + "special D50936-D60141 ddbj_other_nuc # 1208 EST ranges", + "special D60143-D61376 ddbj_est", + "special D61420-D61685 ddbj_est", + "special D61708-D62388 ddbj_est", + "special D62390-D63133 ddbj_est", + "special D63171-D63317 ddbj_est", + "special D63319-D63324 ddbj_est", + "special D63330 ddbj_est", + "special D63746-D63758 ddbj_est", + "special D64179-D65034 ddbj_est", + "special D65036-D65241 ddbj_est", + "special D65243-D65978 ddbj_est", + "special D65980-D66873 ddbj_est", + "special D67099-D68048 ddbj_est", + "special D68050-D68323 ddbj_est", + "special D68325-D68600 ddbj_est", + "special D68602-D69603 ddbj_est", + "special D69605-D70813 ddbj_est", + "special D70900-D76413 ddbj_other_nuc # 45 EST ranges", + "special D76447-D77996 ddbj_est", + "special D78209-D89649 ddbj_other_nuc # 91 EST ranges", + "", + "special F38006 embl_dirsub # Nominally embl_est.", + "", + "# Nominally gsdb_dirsub. Split out EST, GSS, and STS ranges, and", + "# give the benefit of the doubt to sequences that look like gb_cdna,", + "# gb_con, gb_genome, gsdb_dirsub, or gb_other_nuc.", + "special L00738-L00844 gb_sts", + "special L00846-L00850 gb_sts", + "special L00852-L00891 gb_sts", + "special L00893-L00916 gb_sts", + "special L00994-L01014 gb_sts", + "special L01996-L02021 gb_sts", + "special L02080-L02091 gb_sts", + "special L04198-L04215 gb_sts", + "special L07331-L07332 gb_sts", + "special L07863 gb_sts", + "special L08881-L15794 gb_other_nuc # 6 EST ranges and 23 STS ranges", + "special L17188-L17290 gb_sts", + "special L18193-L18255 gb_sts", + "special L18857-L18858 gb_est", + "special L19032-L19041 gb_est", + "special L19143-L19155 gb_est", + "special L19160 gb_est", + "special L19202-L19214 gb_est", + "special L20451-L20461 gb_est", + "special L23479-L23493 gb_sts", + "special L23992 gb_sts", + "special L23997 gb_sts", + "special L24693 gb_sts", + "special L24826 gb_sts", + "special L25137 gb_sts", + "special L25173-L25249 gb_est", + "special L25344-L25345 gb_est", + "special L25347 gb_est", + "special L25417-L25420 gb_est", + "special L25449-L25525 gb_est", + "special L25888 gb_sts", + "special L26606-L26848 gb_est", + "special L27444 gb_est", + "special L28178-L28418 gb_sts", + "special L28420-L28422 gb_sts", + "special L30148 gb_est", + "special L31430-L31437 gb_sts", + "special L31440-L31489 gb_sts", + "special L31968-L32015 gb_est", + "special L32028-L32065 gb_est", + "special L33494-L33675 gb_est", + "special L34798-L34802 gb_sts", + "special L34957-L35007 gb_est", + "special L35580-L35581 gb_sts", + "special L35773-L35843 gb_est", + "special L36534 gb_sts", + "special L37208-L37288 gb_sts", + "special L37453-L37515 gb_est", + "special L37607-L37659 gb_est", + "special L37974-L38013 gb_est", + "special L38026-L38243 gb_est", + "special L38525-L38543 gb_est", + "special L38741 gb_est", + "special L38750-L38760 gb_est", + "special L38763 gb_est", + "special L38774 gb_est", + "special L38787 gb_est", + "special L39872-L39873 gb_sts", + "special L40034 gb_sts", + "special L40040-L40041 gb_sts", + "special L40351-L40352 gb_sts", + "special L40420-L40424 gb_est", + "special L41967 gb_sts", + "special L43576-L43577 gb_est", + "special L43579-L43580 gb_est", + "special L44279-L44576 gb_est", + "special L46401-L46582 gb_est", + "special L46914-L47098 gb_est", + "special L47214-L47215 gb_sts", + "special L47542 gb_sts", + "special L47554-L47568 gb_sts", + "special L47842-L47965 gb_est", + "special L48016 gb_sts", + "special L48736-L48796 gb_gss", + "special L48818-L48873 gb_est", + "special L49057-L49120 gb_est", + "special L76101-L76131 gb_est", + "special L76151 gb_sts", + "special L77669-L77670 gb_sts", + "special L77674-L77683 gb_sts", + "special L77685-L77686 gb_sts", + "special L77689 gb_sts", + "special L77878-L77883 gb_sts", + "special L77993 gb_sts", + "special L81201-L81260 gb_est", + "", + "# Nominally gsdb_dirsub. Split out EST and STS ranges, and give the", + "# benefit of the doubt to sequences that look like gb_cdna, gb_con,", + "# gb_genome, gsdb_dirsub, or gb_other_nuc.", + "special M23606-M23610 gb_sts", + "special M61953-M62300 gb_est", + "special M75734-M75848 gb_est", + "special M75850-M75852 gb_est", + "special M75854-M75855 gb_est", + "special M75857 gb_est", + "special M75859-M75863 gb_est", + "special M75868-M75869 gb_est", + "special M75872 gb_est", + "special M75874 gb_est", + "special M75876-M75881 gb_est", + "special M75885 gb_est", + "special M75890 gb_est", + "special M75892-M75902 gb_est", + "special M75904-M75905 gb_est", + "special M75912 gb_est", + "special M75915 gb_est", + "special M75917-M75943 gb_est", + "special M75945-M75946 gb_est", + "special M75951 gb_est", + "special M75955 gb_est", + "special M75964-M75965 gb_est", + "special M75988 gb_est", + "special M76111-M76122 gb_est", + "special M77851-M79278 gb_est", + "special M79465-M80184 gb_est", + "special M80369-M80376 gb_sts", + "special M83631-M83639 gb_sts", + "special M84924-M84934 gb_sts", + "special M84943 gb_sts", + "special M85308-M86179 gb_est", + "special M88774-M89469 gb_est", + "special M91216-M91222 gb_est", + "special M91387-M91403 gb_est", + "special M91480-M91511 gb_est", + "special M92283-M92284 gb_est", + "special M92935 gb_est", + "special M94585-M94622 gb_sts", + "special M94635-M94643 gb_sts", + "special M94655-M94662 gb_sts", + "special M95212-M95280 gb_sts", + "special M95301-M95323 gb_sts", + "special M96605-M96621 gb_est", + "special M98979-M98996 gb_sts", "", "# Early N accessions were assigned haphazardly, and sometimes ambiguously.", - "# (These are all secondary accessions nowadays, though.)", - "special N00001-N00002 gb_embl", - "special N00003-N00004 gb_ddbj", - "special N00005 gb_embl_ddbj", - "special N00006-N00007 gb_ddbj", - "special N00008 gb_other_nuc", - "special N00009 gb_embl_ddbj", - "special N00010 gb_ddbj", - "special N00011 gb_embl", - "special N00012 gb_embl_ddbj", - "special N00013 gb_other_nuc", - "special N00014-N00017 gb_ddbj", - "special N00018-N00019 gb_other_nuc", - "special N00020 gb_embl_ddbj", - "special N00021 gb_ddbj", - "special N00022 gb_embl_ddbj", - "special N00023-N00024 gb_ddbj", - "special N00025 gb_embl_ddbj", - "special N00026 gb_ddbj", - "special N00027 gb_other_nuc", - "special N00028 ddbj_other_nuc", - "special N00029-N00034 gb_ddbj", - "special N00035 ddbj_other_nuc", - "special N00036 gb_ddbj", - "special N00037 ddbj_other_nuc", - "special N00038-N00040 gb_ddbj", - "special N00041 gb_other_nuc", - "special N00042-N00045 gb_ddbj", - "special N00046 gb_other_nuc", - "special N00047 gb_ddbj", - "special N00048 gb_other_nuc", - "special N00049-N00051 gb_ddbj", - "special N00052 gb_other_nuc", - "special N00053 ddbj_other_nuc", - "special N00054 gb_other_nuc", - "special N00055-N00056 gb_ddbj", - "special N00057 gb_embl", - "special N00058 gb_embl_ddbj", - "special N00059 gb_ddbj", - "special N00060 embl_other_nuc", - "special N00061-N00063 ddbj_other_nuc", - "special N00064 embl_other_nuc", - "special N00065-N00069 ddbj_other_nuc", - "special N00070 embl_ddbj", - "special N00078-N00079 ddbj_other_nuc", - "special N00083 ddbj_other_nuc", - "special N00088 ddbj_other_nuc", - "special N00090-N00094 ddbj_other_nuc", - "special N18624 gb_other_nuc", - "special N20000-N99999 gb_est", + "# (These are all secondary accessions nowadays, though.) \"*\" denotes what,", + "# if anything, N????? (and usually also N?????.1) immediately resolves to.", + "# Some unambiguous accessions don't resolve, and some ambiguous ones do.", + "special N00001 gb_embl # (L29187+L00109+L00110 / AH005313.2) / X04516.1", + "special N00002 gb_embl_ddbj # M31027.1 / X04469.1 = D00002", + "special N00003 gb_ddbj # L29169.1 / D00003.1", + "special N00004 gb_ddbj # *L29170.1 / D00004.1", + "special N00005 gb_embl_ddbj # L29171.1 / V01385.1 / D00005.1", + "special N00006 gb_ddbj # (M31028.1 / AH002572.2) / D00006.1", + "special N00007 gb_ddbj # (M31029.1 / AH002572.2) / D00007.1", + "special N00008 gb_other_nuc # *L29172.1", + "special N00009 gb_embl_ddbj # M13655.1 / *X00532.1 / D00009.1 (= M13655.1)", + "special N00010 gb_embl_ddbj # *L29174.1 / X04067.1 = D00010.1", + "special N00011 gb_embl # *L29175.1 = V00749.1", + "special N00012 gb_embl_ddbj # L29176.1 = V00751.1 / D00012.1", + "special N00013 gb_other_nuc # L29177.1 / AH002712.2", + "special N00014 gb_ddbj # (L29178.1 / AH005322.2) / D00014.1", + "special N00015 gb_ddbj # (L29187.1 / AH005313.2) / D00015.1", + "special N00016 gb_ddbj # (L29188.1 / AH005313.2) / D00016.1", + "special N00017 gb_ddbj # *L29190.1 / (M14043 =) D00017.1", + "special N00018 gb_other_nuc # *L29191.1 / AH002172.2; only unversioned", + "special N00019 gb_other_nuc # *L29197.1", + "special N00020 gb_embl_ddbj # (L29198.1 / AH002320.2) / X03632.1 = D00020.1", + "special N00021 gb_ddbj # (L29199.1 / AH002320.2) / D00021.1", + "special N00022 gb_embl_ddbj # L29390.1 / V01168.1 / D00022.1", + "special N00023 gb_ddbj # (L29391.1 / AH000963.2) / D00023.1", + "special N00024 gb_ddbj # *L29392.1 / (M13071.1 =) D00024.1", + "special N00025 gb_embl_ddbj # L29393.1 / X00626.1 / D00025.1", + "special N00026 gb_ddbj # L29394.1 (= *X00442.1) / D00026.1", + "special N00027 gb_other_nuc # *L29395.1", + "special N00028 ddbj_other_nuc # D00028.1", + "special N00029 gb_ddbj # *L29397.1 / D00029.1", + "special N00030 gb_ddbj # M10126.1 / D00030.1", + "special N00031 gb_ddbj # (*L29400.1 / AH002739.2) / D00031.1; unvers.", + "special N00032 gb_ddbj # (L?????.1 / AH??????.2) / D00032.1", + "special N00033 gb_ddbj # (L29401.1 / AH002776.2) / D00033.1", + "special N00034 gb_ddbj # (L29424.1 / AH001823.2) / D00034.1", + "special N00035 ddbj_other_nuc # D00035.1", + "special N00036 gb_ddbj # M31030.1 / D00036.1", + "special N00037 ddbj_other_nuc # D00037.1", + "special N00038 gb_ddbj # M31031.1 / D00038.1", + "special N00039 gb_ddbj # *L29427.1 / D00039.1", + "special N00040 gb_ddbj # L29428.1 / D00040.1", + "special N00041 gb_other_nuc # L29429.1 / *M13756.1 (= D00041)", + "special N00042 gb_ddbj # (L29430.1 / AH002209.2) / (M13752 =) D00042.1", + "special N00043 gb_ddbj # (L29431.1 / AH005585.2) / (M13753 =) D00043.1", + "special N00044 gb_ddbj # L29432.1 / D00044.1", + "special N00045 gb_other_nuc # (*L29433.1/AH002727.2); once also DDBJ?", + "special N00046 gb_other_nuc # *L29434.1", + "special N00047 gb_ddbj # (*L29435.1 / AH002481.2) / D00047.1", + "special N00048 gb_other_nuc # *L29436.1", + "special N00049 gb_ddbj # M31032.1 / D00049.1", + "special N00050 gb_ddbj # (L29399.1 / AH002739.2) / D00050.1", + "special N00051 gb_ddbj # (L?????.1 / AH??????.2) / D00051.1", + "special N00052 gb_other_nuc # L29472.1 / *M14909.1 (= D00052.1)", + "special N00053 ddbj_other_nuc # D00053.1", + "special N00054 gb_other_nuc # M31033.1", + "special N00055 gb_ddbj # (L?????.1 / AH??????.2) / D00055.1", + "special N00056 gb_ddbj # L39908.1 / D00056.1", + "special N00057 gb_embl # M31034.1 / X05532.1", + "special N00058 gb_embl_ddbj # M31035.1 (= X05163.1) / (X05537.1 =) D00058.1", + "special N00059 gb_ddbj # M22232.1 / (X05538.1 =) D00059.1", + "special N00060 embl_other_nuc # X05541.1 (= D00060.1)", + "special N00061 ddbj_other_nuc # (X05531.1 =) D00061.1", + "special N00062 ddbj_other_nuc # (X05530.1 =) D00062.1", + "special N00063 ddbj_other_nuc # (X05529.1 =) D00063.1", + "special N00064 embl_other_nuc # X05528.1 (= D00064.1 = D10030.1)", + "special N00065 ddbj_other_nuc # (X05527.1 =) D00065.1 = D10031.1", + "special N00066 ddbj_other_nuc # D00066.1", + "special N00067 ddbj_other_nuc # (M20207.1 =) D00067.1", + "special N00068 ddbj_other_nuc # D00068.1", + "special N00069 ddbj_other_nuc # D00069.1", + "special N00070 embl_ddbj # X04036.1 = D00070.1", + "special N00078 ddbj_other_nuc # D00078.1", + "special N00079 ddbj_other_nuc # D00079.1", + "special N00083 ddbj_other_nuc # D00083.1", + "special N00088 ddbj_other_nuc # (M16550.1 =) D00088.1 = D10032.1", + "special N00090 ddbj_other_nuc # (X05597.1 =) D00090.1", + "special N00091 ddbj_other_nuc # (M15807.1 =) D00091.1", + "special N00092 ddbj_other_nuc # D00092.1", + "special N00093 ddbj_other_nuc # (M34437.1 = X04797.1 =) D00093.1", + "special N00094 ddbj_other_nuc # (X05040.1 =) D00094.1", + "special N18624 gb_other_nuc # *L29496.1 / M23263.1", + "special N20001-N97317 gb_est", + "special N97318-N97531 gb_gss", + "special N97532-N99999 gb_est", "", - "# Some GenBank \"TPA\" 8-character protein accessions are really native.", - "special DAA00974-DAA00975 gb_prot", - "special DAA01471 gb_prot", - "special DAA01543 gb_prot", - "special DAA06450-DAA06453 gb_prot", - "special DAA06495 gb_prot", - "special DAA06633-DAA06636 gb_prot", - "special DAA12517-DAA33856 gb_prot", + "# Nominally gb_est.", + "special T02634-T02808 gb_gss", + "special T09496-T09993 gb_gss", + "", + "# Nominally gb_dirsub.", + "special U01537-U01551 gb_est", + "special U01921 gb_est", + "special U13686 gb_est", + "special U14111-U14114 gb_est", + "special U14171 gb_est", + "special U15041-U15047 gb_est", + "special U15988 gb_est", + "special U17154 gb_est", + "special U17513-U17564 gb_est", + "special U17582-U17584 gb_est", + "special U17905-U17909 gb_est", + "special U17976-U17977 gb_est", + "special U17999-U18008 gb_est", + "special U18010-U18017 gb_est", + "special U19036 gb_est", + "special U19135-U19141 gb_est", + "special U19502-U19510 gb_gss", + "special U19512-U19515 gb_est", + "special U19678-U19693 gb_est", + "special U19732 gb_est", + "special U19772 gb_est", + "special U19823 gb_est", + "special U21073-U21081 gb_est", + "special U21083-U21085 gb_est", + "special U21457-U21470 gb_est", + "special U21493-U21545 gb_gss", + "special U23049-U26690 gb_other_nuc # 21 EST ranges and 1 GSS range", + "special U27989-U31698 gb_other_nuc # 18 EST ranges and 1 GSS range", + "special U33921 gb_est", + "special U34233-U34244 gb_est", + "special U34396-U34400 gb_est", + "special U35429 gb_est", + "special U36594-U36596 gb_est", + "special U37151-U37164 gb_est", + "special U37229 gb_est", + "special U37231-U37234 gb_est", + "special U37588 gb_gss", + "special U37913-U37935 gb_est", + "special U37937-U38174 gb_est", + "special U39396 gb_est", + "special U39407-U39408 gb_est", + "special U39588-U39607 gb_est", + "special U40055 gb_est", + "special U40140-U40143 gb_est", + "special U40153 gb_est", + "special U40589 gb_est", + "special U40629 gb_est", + "special U41133-U41161 gb_est", + "special U41297 gb_est", + "special U42490-U42491 gb_est", + "special U42570-U42579 gb_est", + "special U42751 gb_est", + "special U43146 gb_est", + "special U44093-U44102 gb_est", + "special U44135-U44377 gb_est", + "special U44981-U44990 gb_est", + "special U46160-U53560 gb_other_nuc # 30 EST ranges and 5 GSS ranges", + "special U54592-U54607 gb_est", + "special U54706-U54733 gb_est", + "special U54735-U54739 gb_est", + "special U54779 gb_est", + "special U55034 gb_est", + "special U55777 gb_est", + "special U55962-U55991 gb_est", + "special U56653-U56660 gb_est", + "special U57844 gb_est", + "special U58051-U58082 gb_est", + "special U58979 gb_est", + "special U59417 gb_est", + "special U59419 gb_est", + "special U59755-U59756 gb_est", + "special U60299-U60311 gb_est", + "special U60606-U60638 gb_gss", + "special U60799 gb_est", + "special U61299-U61300 gb_gss", + "special U61522-U61525 gb_gss", + "special U62909 gb_est", + "special U63519 gb_est", + "special U63522-U63528 gb_est", + "special U64597 gb_est", + "special U64679 gb_est", + "special U64965-U64966 gb_est", + "special U65082 gb_est", + "special U65383-U65389 gb_est", + "special U65438-U65439 gb_est", + "special U65740 gb_est", + "special U65903-U65905 gb_gss", + "special U65917 gb_est", + "special U66210-U66213 gb_gss", + "special U66215 gb_gss", + "special U66423 gb_est", + "special U66576-U66577 gb_est", + "special U66693-U66697 gb_est", + "special U66718 gb_est", + "special U67850-U70383 gb_other_nuc # 13 EST ranges and 5 GSS ranges", + "special U72041-U95639 gb_other_nuc # 103 EST ranges, 35 GSS ranges, and 1 STS range", + "special U97486 gb_gss", + "special U97488 gb_gss", + "special U97490 gb_gss", + "special U97493 gb_gss", + "", + "# Nominally embl_dirsub. Give the benefit of the doubt to sequences", + "# that look like embl_con, embl_genome, or embl_other_nuc, but split", + "# out EST ranges.", + "special X61801-X61899 embl_est", + "special X62402 embl_est", + "special X65268-X65275 embl_est", + "special X65374-X65393 embl_est", + "special X71637-X71641 embl_est", + "special X71643-X71652 embl_est", + "special X73542-X73548 embl_est", + "special X73704-X73804 embl_est", + "special X76318 embl_est", + "special X76487 embl_est", + "special X78018-X78028 embl_est", + "special X82204 embl_est", + "special X83032-X83034 embl_est", + "special X83304-X83366 embl_est", + "special X84313 embl_est", + "special X84711-X84721 embl_est", + "special X85546-X85725 embl_est", + "special X86144-X86146 embl_est", + "special X86218-X86220 embl_est", + "special X87300-X87305 embl_est", + "special X89987-X89996 embl_est", + "special X90532-X90545 embl_est", + "special X91308-X91335 embl_est", + "special X91672-X91734 embl_est", + "special X92440 embl_est", + "special X92790-X92803 embl_est", + "special X93012-X93014 embl_est", + "special X93079 embl_est", + "special X93227-X93300 embl_est", + "special X93413-X93460 embl_est", + "special X93811-X93867 embl_est", + "special X93915-X93919 embl_est", + "special X93988-X93989 embl_est", + "special X94486-X94532 embl_est", + "special X95581 embl_est", + "special X95686 embl_est", + "special X96619-X96625 embl_est", + "special X97503-X97519 embl_est", + "special X97896-X97897 embl_est", + "special X98134-X98140 embl_est", + "special X98198-X98204 embl_est", + "special X98425-X98428 embl_est", + "special X98548-X98554 embl_est", + "special X99272 embl_est", + "", + "# Nominally embl_dirsub. Give the benefit of the doubt to sequences", + "# that look like embl_genome or embl_other_nuc, but split out EST", + "# ranges.", + "special Y07823 embl_est", + "special Y08464-Y08483 embl_est", + "special Y08705-Y08714 embl_est", + "special Y09139 embl_est", + "special Y09316-Y09320 embl_est", + "special Y09359-Y09364 embl_est", + "special Y09375-Y09377 embl_est", + "special Y09459-Y09464 embl_est", + "special Y09519-Y09523 embl_est", + "special Y09543-Y09545 embl_est", + "special Y09726-Y09732 embl_est", + "special Y09875 embl_est", + "special Y09981-Y09986 embl_est", + "special Y10008-Y10010 embl_est", + "special Y10037-Y10042 embl_est", + "special Y10056-Y10060 embl_est", + "special Y10217-Y10220 embl_est", + "special Y10671-Y10672 embl_est", + "special Y11191 embl_est", + "special Y11308 embl_est", + "special Y11615 embl_est", + "special Y14396-Y14402 embl_est", + "special Y16130-Y16131 embl_est", + "special Y16971-Y16974 embl_est", + "special Y18366 embl_est", + "", + "# Nominally embl_dirsub. Give the benefit of the doubt to sequences", + "# that look like embl_genome or embl_other_nuc, but split out EST", + "# ranges.", + "special Z12653-Z23155 embl_other_nuc # 69 EST ranges", + "special Z24464-Z24546 embl_est", + "special Z24760-Z24766 embl_est", + "special Z24769-Z25279 embl_est", + "special Z25283-Z25392 embl_est", + "special Z25400-Z25417 embl_est", + "special Z25486-Z25508 embl_est", + "special Z25510-Z25518 embl_est", + "special Z25546-Z25586 embl_est", + "special Z25588-Z25733 embl_est", + "special Z25776-Z25794 embl_est", + "special Z25799-Z25801 embl_est", + "special Z25805-Z25808 embl_est", + "special Z25825-Z25826 embl_est", + "special Z25832-Z25850 embl_est", + "special Z25889-Z26039 embl_est", + "special Z26045-Z26132 embl_est", + "special Z26184-Z26235 embl_est", + "special Z26237-Z26238 embl_est", + "special Z26243-Z26244 embl_est", + "special Z26323-Z26330 embl_est", + "special Z26342-Z26480 embl_est", + "special Z26495-Z26517 embl_est", + "special Z26525-Z26579 embl_est", + "special Z26658-Z26752 embl_est", + "special Z26754-Z26764 embl_est", + "special Z26772-Z26823 embl_est", + "special Z26868-Z26874 embl_est", + "special Z26952-Z26966 embl_est", + "special Z26971-Z27066 embl_est", + "special Z27095-Z27104 embl_est", + "special Z27240 embl_est", + "special Z27249-Z27303 embl_est", + "special Z28355-Z38124 embl_other_nuc # 84 EST ranges", + "special Z38136-Z46221 embl_est", + "special Z46243-Z46248 embl_est", + "special Z46291-Z46298 embl_est", + "special Z46428-Z46430 embl_est", + "special Z46510-Z46520 embl_est", + "special Z46526-Z46594 embl_est", + "special Z46677-Z46718 embl_est", + "special Z46813-Z46822 embl_est", + "special Z46830-Z46832 embl_est", + "special Z46974-Z46980 embl_est", + "special Z47057-Z47065 embl_est", + "special Z47278-Z47348 embl_est", + "special Z47350-Z47351 embl_est", + "special Z47382-Z47408 embl_est", + "special Z47575-Z47720 embl_est", + "special Z47801-Z47802 embl_est", + "special Z47985 embl_est", + "special Z48368-Z48427 embl_est", + "special Z48445-Z48448 embl_est", + "special Z48453-Z48467 embl_est", + "special Z48545-Z48560 embl_est", + "special Z48608-Z48611 embl_est", + "special Z48637 embl_est", + "special Z49229-Z49232 embl_est", + "special Z49744-Z49745 embl_est", + "special Z54295-Z54305 embl_est", + "special Z54309-Z54311 embl_est", + "special Z69578-Z69584 embl_est", + "special Z69945-Z69972 embl_est", + "special Z69974-Z69975 embl_est", + "special Z69983-Z69984 embl_est", + "special Z71789-Z71924 embl_est", + "special Z72392-Z72421 embl_est", + "special Z74621-Z74661 embl_est", + "special Z78280-Z78408 embl_est", + "special Z81149-Z81290 embl_est", + "special Z82016-Z82017 embl_est", + "special Z82913-Z82935 embl_est", + "special Z83019-Z83066 embl_est", + "special Z83980-Z84196 embl_est", + "special Z92674-Z92705 embl_est", + "special Z93025-Z93038 embl_est", + "special Z93725-Z93763 embl_est", + "special Z94848-Z94863 embl_est", + "special Z97038-Z97047 embl_est", + "special Z97731-Z97830 embl_est", + "special Z97862-Z97872 embl_est", + "special Z98057-Z98138 embl_est", + "special Z98443-Z98527 embl_est", + "special Z98764-Z98819 embl_est", + "special Z98821-Z98845 embl_est", + "special Z99067-Z99089 embl_est", + "special Z99348-Z99435 embl_est", + "", + "# Nominally ddbj_dirsub.", + "special AB001540-AB128048 ddbj_other_nuc # 197 EST ranges", + "special AB158145 ddbj_est", + "special AB158279-AB158287 ddbj_est", + "special AB158432 ddbj_est", + "special AB159214-AB159217 ddbj_est", + "special AB159736-AB159739 ddbj_est", + "special AB163429 ddbj_est", + "special AB163431 ddbj_est", + "special AB166724 ddbj_est", + "special AB178168-AB308274 ddbj_other_nuc # 80 EST ranges", + "special AB327169 ddbj_est", + "special AB331173-AB331192 ddbj_est", + "special AB331734-AB331746 ddbj_est", + "special AB331927-AB331949 ddbj_est", + "special AB334239 ddbj_est", + "special AB353143 ddbj_est", + "special AB354879 ddbj_est", + "special AB361047-AB361052 ddbj_est", + "special AB361241-AB361244 ddbj_est", + "special AB361292-AB361358 ddbj_est", + "special AB364678-AB364679 ddbj_est", + "special AB371430-AB371572 ddbj_est", + "special AB372866-AB372875 ddbj_est", + "special AB373997-AB374042 ddbj_est", + "special AB374263-AB374265 ddbj_est", + "special AB375019-AB375060 ddbj_est", + "special AB433981 ddbj_est", + "special AB434937-AB434950 ddbj_est", + "special AB437321-AB437344 ddbj_est", + "special AB446243-AB446391 ddbj_est", + "special AB447894-AB447981 ddbj_est", + "special AB448953-AB449020 ddbj_est", + "special AB450689-AB450761 ddbj_est", + "special AB458260-AB458300 ddbj_est", + "special AB458688-AB458789 ddbj_est", + "special AB461364-AB461372 ddbj_est", + "special AB471888-AB471891 ddbj_est", + "special AB474609-AB474619 ddbj_est", + "special AB474621-AB474714 ddbj_est", + "special AB474716-AB474721 ddbj_est", + "special AB474726-AB474739 ddbj_est", + "special AB474741-AB474748 ddbj_est", + "special AB480784-AB480824 ddbj_est", + "special AB485714-AB485715 ddbj_est", + "special AB485764-AB485770 ddbj_est", + "special AB485960-AB485992 ddbj_est", + "special AB492065-AB492083 ddbj_est", + "special AB505865-AB505873 ddbj_est", + "special AB509259 ddbj_est", + "special AB516772-AB516956 ddbj_est", + "special AB517053-AB517143 ddbj_est", + "special AB517145 ddbj_est", + "special AB529438-AB529445 ddbj_est", + "special AB535102-AB535104 ddbj_est", + "special AB537328-AB537329 ddbj_est", + "special AB542429-AB542450 ddbj_est", + "special AB552736-AB552841 ddbj_est", + "special AB553313-AB553315 ddbj_est", + "special AB568279-AB568290 ddbj_est", + "special AB571597-AB571602 ddbj_est", + "special AB572918-AB572921 ddbj_est", + "special AB573693-AB573709 ddbj_est", + "special AB575970-AB575978 ddbj_est", + "special AB576812-AB576850 ddbj_est", + "special AB585974-AB585996 ddbj_est", + "special AB594978-AB595127 ddbj_est", + "special AB602400-AB602424 ddbj_est", + "special AB613266 ddbj_est", + "special AB617526 ddbj_est", + "special AB626803 ddbj_est", + "special AB640724 ddbj_est", + "special AB646299-AB646300 ddbj_est", + "special AB646321-AB646345 ddbj_est", + "special AB668572-AB668577 ddbj_est", + "special AB669437-AB669464 ddbj_est", + "special AB709967-AB710073 ddbj_est", + "special AB734662-AB734675 ddbj_est", + "special AB738045-AB738062 ddbj_est", + "special AB742236-AB742251 ddbj_est", + "special AB757677-AB757705 ddbj_est", + "special AB811436 ddbj_est", + "special AB823195-AB823214 ddbj_est", + "special AB827265-AB827267 ddbj_est", + "special AB862603-AB862877 ddbj_est", + "special AB863290-AB863461 ddbj_est", + "special AB899003-AB899014 ddbj_est", + "special AB922020-AB922116 ddbj_est", + "", + "# Nominally gb_dirsub.", + "special AF000235-AF373213 gb_other_nuc # 585 EST ranges and 303 GSS ranges", + "special AF384864-AF384865 gb_gss", + "special AF387113-AF387121 gb_gss", + "special AF390017 gb_est", + "special AF390858 gb_est", + "special AF391795 gb_est", + "special AF391801-AF391804 gb_est", + "special AF391806-AF391807 gb_est", + "special AF396672 gb_gss", + "special AF396868 gb_est", + "special AF397194 gb_gss", + "special AF400792-AF400848 gb_gss", + "special AF401241-AF401271 gb_gss", + "special AF405213-AF405230 gb_est", + "special AF408415-AF408416 gb_est", + "special AF411092-AF411099 gb_est", + "special AF416103-AF416138 gb_gss", + "special AF420231 gb_est", + "special AF425300 gb_est", + "special AF435833-AF435837 gb_gss", + "special AF436075 gb_est", + "special AF439734 gb_est", + "special AF439736 gb_est", + "special AF439961-AF439972 gb_est", + "special AF440734 gb_gss", + "special AF441178-AF441182 gb_est", + "special AF441184-AF441187 gb_est", + "special AF441725 gb_gss", + "special AF441760-AF441769 gb_gss", + "special AF447921 gb_gss", + "special AF448511-AF448512 gb_est", + "special AF449707-AF449712 gb_gss", + "special AF451165-AF451181 gb_est", + "special AF451183-AF451189 gb_est", + "special AF453446 gb_est", + "special AF454762 gb_est", + "special AF455790-AF455802 gb_gss", + "special AF456411 gb_est", + "special AF461771 gb_est", + "special AF465471-AF465474 gb_gss", + "special AF468668-AF468672 gb_est", + "special AF469688-AF469692 gb_est", + "special AF472511 gb_gss", + "special AF486818-AF486819 gb_est", + "special AF487314-AF487325 gb_est", + "special AF487327-AF487329 gb_est", + "special AF492012-AF492014 gb_gss", + "special AF492272 gb_gss", + "special AF492356 gb_est", + "special AF494494-AF494495 gb_gss", + "special AF503187-AF503189 gb_est", + "special AF503588 gb_est", + "special AF506703-AF506706 gb_est", + "special AF507053 gb_est", + "special AF507058 gb_est", + "special AF507060 gb_est", + "special AF509571 gb_gss", + "special AF510188-AF510190 gb_est", + "special AF515664-AF515665 gb_gss", + "special AF516758-AF516766 gb_est", + "special AF520437-AF520439 gb_est", + "special AF520964 gb_est", + "special AF521604 gb_gss", + "special AF521978-AF522027 gb_est", + "special AF524047-AF524260 gb_gss", + "special AF524262-AF524826 gb_gss", + "special AF525702 gb_est", + "special AF525774-AF525775 gb_gss", + "special AF527684-AF527733 gb_est", + "special AF529172 gb_gss", + "special AF533598-AF533600 gb_est", + "special AF534530-AF534533 gb_gss", + "special AF537199-AF537202 gb_gss", + "special AF538926-AF538927 gb_est", + "special AF542503 gb_gss", + "", + "special AG266800-AG266855 ddbj_dirsub # Nominally ddbj_gss.", + "", + "# Nominally embl_dirsub. Give the benefit of the doubt to sequences", + "# that look like embl_genome or embl_other_nuc, but split out EST and", + "# GSS ranges.", + "special AJ003249-AJ013072 embl_other_nuc # 29 EST ranges", + "special AJ131530-AJ131531 embl_est", + "special AJ131534 embl_est", + "special AJ131640 embl_est", + "special AJ131743 embl_est", + "special AJ132447-AJ132453 embl_est", + "special AJ132743-AJ132744 embl_est", + "special AJ132746-AJ132747 embl_est", + "special AJ132768 embl_est", + "special AJ132770 embl_est", + "special AJ133279-AJ133310 embl_est", + "special AJ133423 embl_est", + "special AJ133627-AJ133630 embl_est", + "special AJ133823-AJ133832 embl_est", + "special AJ133887-AJ133891 embl_est", + "special AJ223808-AJ252067 embl_other_nuc # 37 EST ranges", + "special AJ269829-AJ320073 embl_other_nuc # 106 EST ranges", + "special AJ344568-AJ344620 embl_est", + "special AJ345961-AJ346853 embl_est", + "special AJ347704-AJ347708 embl_est", + "special AJ348845-AJ348907 embl_est", + "special AJ388667-AJ441054 embl_other_nuc # 46 EST ranges", + "special AJ441341-AJ456950 embl_est", + "special AJ457094-AJ457095 embl_est", + "special AJ457215-AJ457787 embl_est", + "special AJ457797-AJ457801 embl_est", + "special AJ457995-AJ458180 embl_est", + "special AJ459102-AJ459105 embl_est", + "special AJ460001-AJ486853 embl_est", + "special AJ487042-AJ519345 embl_other_nuc # 41 EST ranges", + "special AJ532915-AJ583526 embl_other_nuc # 46 EST ranges", + "special AJ601557-AJ646868 embl_other_nuc # 55 EST ranges", + "special AJ646897-AJ697608 embl_est", + "special AJ697763-AJ697764 embl_est", + "special AJ698954 embl_est", + "special AJ699509-AJ703791 embl_est", + "special AJ704820 embl_est", + "special AJ704866-AJ704927 embl_est", + "special AJ705105-AJ715323 embl_est", + "special AJ716425-AJ717291 embl_est", + "special AJ719195-AJ719266 embl_est", + "special AJ721139-AJ744704 embl_est", + "special AJ745200-AJ745660 embl_est", + "special AJ746228-AJ746232 embl_est", + "special AJ746346 embl_est", + "special AJ746581-AJ747913 embl_est", + "special AJ749659-AJ749668 embl_est", + "special AJ750001-AJ767053 embl_est", + "special AJ767069-AJ780913 embl_est", + "special AJ781008-AJ781024 embl_est", + "special AJ783757 embl_est", + "special AJ784436-AJ784774 embl_est", + "special AJ785005-AJ785280 embl_est", + "special AJ785296-AJ785566 embl_est", + "special AJ785755 embl_est", + "special AJ786842-AJ809161 embl_est", + "special AJ810177-AJ810178 embl_est", + "special AJ812737-AJ821279 embl_est", + "special AJ821281-AJ821793 embl_est", + "special AJ821924-AJ829440 embl_est", + "special AJ831476-AJ831483 embl_est", + "special AJ831580-AJ831586 embl_est", + "special AJ831846-AJ832104 embl_est", + "special AJ833020-AJ833569 embl_est", + "special AJ843898-AJ920257 embl_other_nuc # 63 EST ranges and 2 GSS ranges", + "special AJ920420-AJ936931 embl_est", + "special AJ937840-AJ937842 embl_est", + "special AJ937844-AJ937846 embl_est", + "special AJ937848-AJ937851 embl_est", + "special AJ937853-AJ937854 embl_est", + "special AJ937856 embl_est", + "special AJ938183-AJ964871 embl_est", + "special AJ966338 embl_est", + "special AJ966532-AJ966570 embl_est", + "special AJ967011-AJ967015 embl_est", + "special AJ968963-AJ968985 embl_est", + "special AJ970155-AJ970160 embl_est", + "special AJ972495-AJ972503 embl_est", + "special AJ973481-AJ973591 embl_est", + "", + "# Nominally embl_dirsub. Give the benefit of the doubt to sequences", + "# that look like embl_con, embl_genome, or embl_other_nuc, but split", + "# out EST and GSS ranges.", + "special AL022607-AL022715 embl_est", + "special AL022730-AL023086 embl_est", + "special AL023993-AL024449 embl_est", + "special AL024459-AL024460 embl_est", + "special AL033283-AL033374 embl_est", + "special AL034585-AL042364 embl_other_nuc # 182 EST ranges", + "special AL042366-AL043422 embl_est", + "special AL043424-AL049170 embl_other_nuc # 72 EST ranges", + "special AL079357-AL079851 embl_est", + "special AL079853-AL079877 embl_est", + "special AL079879-AL080030 embl_est", + "special AL080032-AL080055 embl_est", + "special AL110302-AL110468 embl_est", + "special AL117695-AL118492 embl_est", + "special AL118560-AL121566 embl_est", + "special AL132634 embl_est", + "special AL132645-AL132647 embl_est", + "special AL132695-AL132706 embl_est", + "special AL132781-AL132790 embl_est", + "special AL132802-AL132817 embl_est", + "special AL132829-AL132837 embl_est", + "special AL132910-AL132942 embl_est", + "special AL133667-AL135743 embl_est", + "special AL137939-AL138463 embl_est", + "special AL138519 embl_est", + "special AL157506-AL157686 embl_est", + "special AL160494-AL161251 embl_other_nuc # Fallback to placate older clients", + "special AL160494-AL161251 embl_gss", + "special AL162087-AL162101 embl_est", + "special AL163072-AL163135 embl_est", + "special AL163154 embl_est", + "special AL163196 embl_est", + "special AL163331-AL163480 embl_est", + "special AL163493-AL163504 embl_est", + "special AL163513-AL163522 embl_est", + "special AL163614-AL163635 embl_est", + "special AL163643 embl_est", + "special AL163692-AL163701 embl_est", + "special AL163712-AL163759 embl_est", + "special AL163761-AL163762 embl_est", + "special AL163773-AL163784 embl_est", + "special AL163892-AL163901 embl_est", + "special AL352973-AL352975 embl_est", + "special AL352994-AL353006 embl_est", + "special AL353958-AL353985 embl_est", + "special AL354617-AL354621 embl_est", + "special AL355193-AL355214 embl_est", + "special AL355755-AL355764 embl_est", + "special AL355890-AL355912 embl_est", + "special AL355914-AL355915 embl_est", + "special AL355917-AL355918 embl_est", + "special AL360374-AL365136 embl_est", + "special AL365523-AL389869 embl_est", + "special AL391923-AL391974 embl_est", + "special AL392063-AL392067 embl_est", + "special AL441606-AL441620 embl_est", + "special AL441622-AL441623 embl_est", + "special AL449467-AL449917 embl_est", + "special AL450491-AL450982 embl_est", + "special AL499630-AL500520 embl_est", + "special AL500542-AL512267 embl_est", + "special AL513551-AL540319 embl_other_nuc # 490 EST ranges", + "special AL540321-AL541353 embl_est", + "special AL541355-AL583950 embl_other_nuc # 393 EST ranges", + "special AL583964-AL589147 embl_est", + "special AL589204-AL589622 embl_est", + "special AL593862-AL596018 embl_other_nuc # 251 EST ranges", + "special AL596479-AL603622 embl_est", + "special AL627462-AL663681 embl_other_nuc # 3583 EST ranges", + "special AL663683-AL666314 embl_est", + "special AL666316-AL666416 embl_est", + "special AL666418-AL666705 embl_est", + "special AL666707-AL666821 embl_est", + "special AL666823-AL667261 embl_est", + "special AL667264-AL667371 embl_est", + "special AL667373-AL668474 embl_est", + "special AL668476-AL668875 embl_est", + "special AL668877-AL669016 embl_est", + "special AL669018-AL669138 embl_est", + "special AL669140-AL669810 embl_est", + "special AL669812 embl_est", + "special AL669890 embl_est", + "special AL669994-AL669997 embl_est", + "special AL671927-AL683797 embl_other_nuc # 1244 EST ranges", + "special AL691524-AL713628 embl_est", + "special AL713805-AL713837 embl_est", + "special AL714032-AL731499 embl_est", + "special AL731899-AL732289 embl_est", + "special AL732297-AL732307 embl_est", + "special AL749534-AL749539 embl_est", + "special AL749541-AL750301 embl_est", + "special AL750303-AL751363 embl_est", + "special AL773605-AL805894 embl_other_nuc # 3341 EST ranges", + "special AL808211-AL823461 embl_est", + "special AL824717-AL831324 embl_est", + "special AL834580-AL837504 embl_est", + "special AL837529-AL840622 embl_est", + "special AL840645-AL840932 embl_est", + "special AL841430-AL844138 embl_est", + "special AL844226-AL844479 embl_est", + "special AL845558-AL901606 embl_other_nuc # 5767 EST ranges", + "special AL901610-AL928536 embl_est", + "special AL929474-AL929490 embl_est", + "special AL929609-AL935024 embl_est", + "special AL935073-AL935113 embl_est", + "special AL954873-AL973407 embl_other_nuc # 638 EST ranges", + "", + "# Nominally embl_dirsub.", + "special AM003907-AM039430 embl_est", + "special AM041272-AM041897 embl_est", + "special AM041899-AM041928 embl_est", + "special AM042018-AM042538 embl_est", + "special AM042715-AM048613 embl_est", + "special AM049439-AM049915 embl_est", + "special AM051087-AM051089 embl_est", + "special AM051366-AM055585 embl_est", + "special AM056504-AM062638 embl_est", + "special AM062766-AM063038 embl_est", + "special AM063043-AM071350 embl_est", + "special AM071401-AM071405 embl_est", + "special AM071408 embl_est", + "special AM071410-AM071411 embl_est", + "special AM071520-AM072286 embl_est", + "special AM072430-AM072444 embl_est", + "special AM075249-AM075607 embl_est", + "special AM083343-AM083946 embl_est", + "special AM085154-AM085297 embl_est", + "special AM088777-AM109845 embl_est", + "special AM110258-AM110692 embl_est", + "special AM111128-AM111305 embl_est", + "special AM111350-AM111351 embl_est", + "special AM111376-AM113422 embl_est", + "special AM113870 embl_est", + "special AM115672-AM115694 embl_est", + "special AM117760-AM117779 embl_est", + "special AM137442-AM156757 embl_est", + "special AM157797-AM158083 embl_est", + "special AM159647-AM160600 embl_est", + "special AM161052-AM161090 embl_est", + "special AM161647-AM162203 embl_est", + "special AM165128-AM167516 embl_est", + "special AM168256-AM168269 embl_est", + "special AM168526-AM176418 embl_est", + "special AM177644-AM179408 embl_est", + "special AM180191-AM180250 embl_est", + "special AM184308-AM228715 embl_est", + "special AM229723-AM230448 embl_est", + "special AM231596-AM231607 embl_est", + "special AM231751-AM231752 embl_est", + "special AM232089-AM232226 embl_est", + "special AM233524 embl_est", + "special AM233688-AM233739 embl_est", + "special AM237575-AM237581 embl_est", + "special AM237631-AM237802 embl_est", + "special AM237808-AM237828 embl_est", + "special AM259062-AM259066 embl_est", + "special AM260753-AM260790 embl_est", + "special AM261635-AM261651 embl_est", + "special AM261893-AM261919 embl_est", + "special AM263561-AM265360 embl_est", + "special AM265378-AM265389 embl_est", + "special AM265633-AM265637 embl_est", + "special AM267321-AM267478 embl_est", + "special AM268883-AM268894 embl_est", + "special AM279675 embl_est", + "special AM283547-AM284142 embl_est", + "special AM285455-AM285649 embl_est", + "special AM286691 embl_est", + "special AM287291-AM291980 embl_est", + "special AM292305 embl_est", + "special AM292925-AM292926 embl_est", + "special AM293570-AM293588 embl_est", + "special AM293624 embl_est", + "special AM295342-AM295345 embl_est", + "special AM296550-AM384871 embl_est", + "special AM384993-AM422606 embl_other_nuc # 21 EST ranges", + "special AM493773-AM493867 embl_est", + "special AM495471-AM495722 embl_est", + "special AM496020-AM496068 embl_est", + "special AM496070-AM497466 embl_est", + "special AM498769-AM500636 embl_est", + "special AM500638 embl_est", + "special AM502267-AM502286 embl_est", + "special AM503942-AM503952 embl_est", + "special AM504150-AM600638 embl_est", + "special AM695771-AM696203 embl_est", + "special AM696311-AM696688 embl_est", + "special AM713476-AM743079 embl_est", + "special AM743198-AM748699 embl_other_nuc # 23 EST ranges", + "special AM750062-AM765799 embl_est", + "special AM766003-AM773228 embl_est", + "special AM774151 embl_est", + "special AM779939-AM849033 embl_est", + "special AM849823-AM850054 embl_est", + "special AM851127-AM882506 embl_est", + "special AM894321-AM950290 embl_other_nuc # 183 EST ranges", + "special AM950553-AM980446 embl_est", + "special AM981402-AM982512 embl_est", + "special AM982822-AM983454 embl_est", + "special AM983577-AM988621 embl_est", + "special AM991118-AM991127 embl_est", + "special AM992040-AM992047 embl_est", + "special AM992256-AM992457 embl_est", + "", + "# Nominally ddbj_est.", + "special AU024804-AU029241 ddbj_dirsub", + "special AU036596-AU036726 ddbj_gss", + "special AU046301-AU050022 ddbj_dirsub", + "special AU050808-AU050815 ddbj_dirsub", + "special AU062283-AU062350 ddbj_dirsub", + "special AU066497-AU066498 ddbj_dirsub", + "special AU066500 ddbj_dirsub", + "special AU066504 ddbj_dirsub", + "special AU066506 ddbj_dirsub", + "special AU066511-AU066512 ddbj_dirsub", + "special AU066514-AU066515 ddbj_dirsub", + "special AU066521-AU066524 ddbj_dirsub", + "special AU066527-AU066529 ddbj_dirsub", + "special AU066535 ddbj_dirsub", + "special AU066540-AU066542 ddbj_dirsub", + "special AU066544 ddbj_dirsub", + "special AU066546 ddbj_dirsub", + "special AU066548-AU066553 ddbj_dirsub", + "special AU066555 ddbj_dirsub", + "special AU066557-AU066558 ddbj_dirsub", + "special AU078429-AU078598 ddbj_dirsub", + "special AU090535 ddbj_dirsub", + "special AU279339 ddbj_dirsub", + "special AU279378 ddbj_dirsub", + "", + "special AX114121 embl_dirsub # Nominally embl_patent.", + "", + "# Nominally gb_dirsub.", + "special AY007260 gb_est", + "special AY026952-AY027433 gb_gss", + "special AY030235-AY030236 gb_est", + "special AY032615-AY032616 gb_est", + "special AY032902 gb_est", + "special AY032979 gb_est", + "special AY033289 gb_est", + "special AY038985-AY038987 gb_gss", + "special AY039709-AY039712 gb_gss", + "special AY042532 gb_est", + "special AY048753 gb_est", + "special AY055854 gb_gss", + "special AY063513 gb_est", + "special AY079522-AY080585 gb_gss", + "special AY093804-AY093817 gb_est", + "special AY096240 gb_est", + "special AY120880 gb_est", + "special AY123938 gb_gss", + "special AY125856-AY125890 gb_est", + "special AY127080-AY127557 gb_gss", + "special AY139011-AY139023 gb_est", + "special AY156078-AY156082 gb_gss", + "special AY160080-AY160082 gb_gss", + "special AY160682 gb_est", + "special AY166588 gb_est", + "special AY166650-AY166651 gb_gss", + "special AY168429-AY168439 gb_est", + "special AY174766-AY174778 gb_gss", + "special AY189691-AY189692 gb_est", + "special AY189695 gb_est", + "special AY196929-AY196933 gb_est", + "special AY198434-AY201593 gb_gss", + "special AY201595-AY201640 gb_gss", + "special AY201642-AY201691 gb_gss", + "special AY201693-AY203610 gb_gss", + "special AY243511 gb_est", + "special AY244458 gb_gss", + "special AY245441 gb_est", + "special AY265801-AY265804 gb_gss", + "special AY270178-AY270181 gb_gss", + "special AY282782-AY282785 gb_gss", + "special AY311391 gb_est", + "special AY321461-AY321462 gb_est", + "special AY325801-AY325802 gb_est", + "special AY326073 gb_est", + "special AY345126 gb_est", + "special AY347477 gb_est", + "special AY352272-AY352273 gb_gss", + "special AY356158-AY356311 gb_est", + "special AY357293-AY357295 gb_est", + "special AY366892-AY366899 gb_gss", + "special AY377860-AY377864 gb_est", + "special AY391730-AY391744 gb_gss", + "special AY395905 gb_est", + "special AY449735-AY449746 gb_est", + "special AY457064-AY457065 gb_est", + "special AY460108-AY460111 gb_est", + "special AY465830-AY465832 gb_est", + "special AY489065-AY489066 gb_gss", + "special AY491396-AY491398 gb_gss", + "special AY494600-AY494604 gb_est", + "special AY517518 gb_est", + "special AY518259-AY518264 gb_est", + "special AY547439-AY547457 gb_est", + "special AY553914 gb_est", + "special AY560545-AY560546 gb_est", + "special AY560548-AY560550 gb_est", + "special AY577286-AY577287 gb_est", + "special AY580990-AY580994 gb_gss", + "special AY583837 gb_gss", + "special AY589693-AY589694 gb_est", + "special AY589700-AY589701 gb_est", + "special AY589704 gb_est", + "special AY589708-AY589710 gb_est", + "special AY648006-AY648007 gb_gss", + "special AY651316 gb_est", + "special AY665687 gb_gss", + "special AY678444-AY678449 gb_est", + "special AY679774-AY679778 gb_est", + "special AY685649-AY685661 gb_gss", + "special AY686735-AY686747 gb_est", + "special AY688838-AY688840 gb_est", + "special AY714068-AY714071 gb_est", + "special AY736327 gb_est", + "special AY740678 gb_est", + "special AY750901-AY750904 gb_est", + "special AY758600-AY760022 gb_gss", + "special AY760098-AY760631 gb_gss", + "special AY760640-AY761013 gb_gss", + "special AY788904 gb_est", + "special AY796341 gb_est", + "special AY803125-AY803165 gb_est", + "special AY822675-AY822677 gb_gss", + "special AY831429 gb_est", + "special AY831657-AY831667 gb_gss", + "special AY838273-AY838277 gb_gss", + "special AY857201 gb_gss", + "special AY866420-AY866424 gb_gss", + "special AY870328 gb_gss", + "special AY872191-AY872255 gb_gss", + "special AY872390-AY873704 gb_gss", + "special AY879586-AY879591 gb_est", + "special AY885220-AY885221 gb_est", + "special AY898612 gb_gss", + "special AY922984-AY922988 gb_est", + "special AY928802-AY928805 gb_est", + "special AY952968-AY952970 gb_est", + "special AY966462-AY966485 gb_est", + "special AY987852 gb_est", + "special AY993980-AY993984 gb_gss", + "special AY994354-AY994356 gb_est", + "", + "# Nominally embl_dirsub.", + "special BX000562-BX000687 embl_est", + "special BX000710-BX000759 embl_est", + "special BX000976-BX000979 embl_est", + "special BX072585-BX088684 embl_other_nuc # 403 EST ranges", + "special BX088730-BX119313 embl_est", + "special BX119401-BX119900 embl_est", + "special BX248593 embl_est", + "special BX248783-BX248982 embl_est", + "special BX248986-BX249708 embl_est", + "special BX249763-BX251408 embl_est", + "special BX251414-BX255275 embl_est", + "special BX255279-BX255804 embl_est", + "special BX255991-BX279521 embl_other_nuc # 815 EST ranges", + "special BX279530-BX283066 embl_est", + "special BX283068-BX284108 embl_est", + "special BX294120-BX294121 embl_est", + "special BX294198-BX294232 embl_est", + "special BX295243-BX295348 embl_est", + "special BX295350-BX295358 embl_est", + "special BX295360-BX295378 embl_est", + "special BX295380-BX295516 embl_est", + "special BX295518 embl_est", + "special BX296570-BX318042 embl_other_nuc # 309 EST ranges", + "special BX318044-BX318558 embl_est", + "special BX318560-BX321855 embl_other_nuc # 42 EST ranges", + "special BX323813-BX465182 embl_other_nuc # 5821 EST ranges", + "special BX466087-BX466922 embl_est", + "special BX467129-BX469883 embl_est", + "special BX470269-BX510298 embl_est", + "special BX511045-BX511047 embl_est", + "special BX511314-BX511323 embl_est", + "special BX511333-BX526833 embl_est", + "special BX526835-BX530014 embl_est", + "special BX540327-BX540980 embl_other_nuc # 79 EST ranges", + "special BX548257-BX569683 embl_est", + "special BX601649-BX629297 embl_est", + "special BX629361-BX640397 embl_est", + "special BX641173-BX647061 embl_est", + "special BX663509 embl_est", + "special BX664722-BX677662 embl_other_nuc # 573 EST ranges", + "special BX677677-BX678768 embl_est", + "special BX678777-BX679656 embl_est", + "special BX679676-BX681414 embl_est", + "special BX681419-BX682226 embl_est", + "special BX682240-BX682527 embl_est", + "special BX682559-BX682952 embl_est", + "special BX682956-BX769172 embl_est", + "special BX769177-BX784021 embl_est", + "special BX784033 embl_est", + "special BX784044-BX784278 embl_est", + "special BX784281-BX784385 embl_est", + "special BX834112-BX841509 embl_est", + "special BX842705-BX861002 embl_other_nuc # 596 EST ranges", + "special BX861004-BX861521 embl_est", + "special BX861523-BX861681 embl_est", + "special BX861683-BX862186 embl_est", + "special BX862188-BX867356 embl_other_nuc # 51 EST ranges", + "special BX867358-BX867914 embl_est", + "special BX867916-BX872506 embl_other_nuc # 66 EST ranges", + "special BX872508-BX873028 embl_est", + "special BX873030-BX879623 embl_other_nuc # 76 EST ranges", + "special BX879625-BX880165 embl_est", + "special BX880167-BX889492 embl_other_nuc # 119 EST ranges", + "special BX889494-BX890135 embl_est", + "special BX890137-BX890188 embl_est", + "special BX890190-BX890198 embl_est", + "special BX890200-BX890202 embl_est", + "special BX890204-BX890224 embl_est", + "special BX890226-BX890232 embl_est", + "special BX890234-BX890308 embl_est", + "special BX890310-BX890394 embl_est", + "special BX890396-BX890483 embl_est", + "special BX890485-BX890537 embl_est", + "special BX897754-BX899178 embl_est", + "special BX899182-BX901874 embl_est", + "special BX908815-BX927274 embl_other_nuc # 343 EST ranges", + "special BX927416-BX928738 embl_est", + "special BX928759-BX929267 embl_est", + "special BX950875-BX957214 embl_est", + "special BX957366-BX957367 embl_est", + "", + "# Nominally gb_genome.", + "special CP000925 gb_dirsub", + "special CP002027 gb_dirsub", + "special CP006698 gb_dirsub", + "special CP010455-CP010456 gb_dirsub", + "special CP013186 gb_dirsub", + "special CP014940 gb_dirsub", + "special CP014992 gb_dirsub", + "special CP016816 gb_dirsub", + "", + "# Nominally embl_dirsub. Give the benefit of the doubt to sequences", + "# that look like embl_genome, but split out EST ranges.", + "special CR278161-CR293495 embl_est", + "special CR354614-CR394505 embl_other_nuc # 315 EST ranges", + "special CR407721-CR450243 embl_est", + "special CR450855-CR457481 embl_other_nuc # 307 EST ranges", + "special CR457485-CR477643 embl_est", + "special CR502047 embl_est", + "special CR513801-CR559927 embl_other_nuc # 134 EST ranges", + "special CR559947-CR589873 embl_est", + "special CR627501-CR628310 embl_est", + "special CR628421-CR631118 embl_est", + "special CR735161-CR749142 embl_est", + "special CR749881-CR751205 embl_est", + "special CR751241-CR751527 embl_est", + "special CR751621-CR752637 embl_est", + "special CR752662-CR752728 embl_est", + "special CR752730-CR752981 embl_est", + "special CR752983-CR753092 embl_est", + "special CR753094-CR753178 embl_est", + "special CR753180-CR753308 embl_est", + "special CR753310-CR753327 embl_est", + "special CR753329-CR753416 embl_est", + "special CR753418-CR753420 embl_est", + "special CR753422-CR753508 embl_est", + "special CR753510-CR753608 embl_est", + "special CR753610-CR753633 embl_est", + "special CR753635-CR753650 embl_est", + "special CR753652-CR753793 embl_est", + "special CR753795-CR753802 embl_est", + "special CR753804-CR753811 embl_est", + "special CR753907-CR759280 embl_est", + "special CR759282-CR759423 embl_est", + "special CR759425-CR759701 embl_est", + "special CR759703-CR759731 embl_est", + "special CR762499-CR764089 embl_est", + "special CR764098-CR767811 embl_est", + "special CR767822-CR769762 embl_est", + "special CR770518-CR774176 embl_est", + "special CR774201-CR775849 embl_est", + "special CR786583-CR788225 embl_est", + "special CR788341-CR790347 embl_est", + "special CR790390-CR792412 embl_est", + "special CR848861-CR857055 embl_other_nuc # 70 EST ranges", + "special CR926157 embl_est", + "special CR926498-CR926878 embl_est", + "special CR926880-CR926886 embl_est", + "special CR926888-CR926910 embl_est", + "special CR926912-CR927049 embl_est", + "special CR927051-CR927214 embl_est", + "special CR927216-CR927367 embl_est", + "special CR927369-CR927455 embl_est", + "special CR927457-CR927478 embl_est", + "special CR927480-CR927552 embl_est", + "special CR927554-CR931631 embl_est", + "special CR938765-CR940296 embl_est", + "special CR942245-CR942270 embl_est", + "special CR942275 embl_est", + "special CR942825-CR944659 embl_est", + "special CR974421 embl_est", + "special CR974599-CR999998 embl_est", + "", + "# Nominally embl_dirsub.", + "special CT000001-CT005229 embl_est", + "special CT009777-CT010161 embl_est", + "special CT010409-CT010425 embl_est", + "special CT025916-CT025917 embl_est", + "special CT485799-CT485989 embl_est", + "special CT563249-CT571240 embl_est", + "special CT571279-CT572707 embl_est", + "special CT574594-CT583622 embl_est", + "special CT583731-CT737118 embl_est", + "special CT737258 embl_est", + "special CT737431-CT762374 embl_other_nuc # 1381 EST ranges", + "special CT762376-CT762504 embl_est", + "special CT762507-CT766183 embl_other_nuc # 153 EST ranges", + "special CT766185-CT766353 embl_est", + "special CT766355-CT773818 embl_other_nuc # 322 EST ranges", + "special CT773820-CT773949 embl_est", + "special CT773951-CT774143 embl_est", + "special CT774146-CT774910 embl_other_nuc # 37 EST ranges", + "special CT774912-CT775059 embl_est", + "special CT775061-CT777270 embl_other_nuc # 84 EST ranges", + "special CT777272-CT777416 embl_est", + "special CT777418-CT780755 embl_other_nuc # 137 EST ranges", + "special CT780757-CT780877 embl_est", + "special CT780879-CT781911 embl_other_nuc # 39 EST ranges", + "special CT781913-CT782070 embl_est", + "special CT782072-CT782090 embl_est", + "special CT782092-CT782100 embl_est", + "special CT782102-CT782110 embl_est", + "special CT782112-CT782124 embl_est", + "special CT782126-CT782150 embl_est", + "special CT782152-CT782183 embl_est", + "special CT782185-CT782187 embl_est", + "special CT782189-CT782321 embl_est", + "special CT782323-CT786110 embl_other_nuc # 147 EST ranges", + "special CT786112-CT786237 embl_est", + "special CT786239-CT792224 embl_other_nuc # 219 EST ranges", + "special CT792226-CT792352 embl_est", + "special CT792354-CT793395 embl_other_nuc # 36 EST ranges", + "special CT793397-CT793519 embl_est", + "special CT793521-CT794722 embl_other_nuc # 48 EST ranges", + "special CT794724-CT794853 embl_est", + "special CT794855-CT823556 embl_other_nuc # 2036 EST ranges", + "special CT842009-CT842118 embl_est", + "special CT842120-CT842121 embl_est", + "special CT842123-CT842130 embl_est", + "special CT842132-CT842147 embl_est", + "special CT842149-CT842158 embl_est", + "special CT842160-CT842178 embl_est", + "special CT842180-CT842181 embl_est", + "special CT842183-CT842516 embl_est", + "special CT842518-CT842528 embl_est", + "special CT842530-CT842531 embl_est", + "special CT842533-CT842540 embl_est", + "special CT842542-CT863709 embl_est", + "special CT863715-CT863733 embl_est", + "special CT868744-CT928681 embl_est", + "special CT928683-CT938375 embl_est", + "special CT938377-CT940347 embl_other_nuc # 367 EST ranges", + "special CT943670-CT950687 embl_est", + "special CT962514-CT963069 embl_est", + "special CT963097-CT963104 embl_est", + "special CT971504-CT971571 embl_est", + "special CT978604 embl_est", + "special CT978606-CT978646 embl_est", + "special CT978648-CT978649 embl_est", + "special CT978651-CT978652 embl_est", + "special CT978654 embl_est", + "special CT978656-CT978677 embl_est", + "special CT978679 embl_est", + "special CT978681 embl_est", + "special CT978683 embl_est", + "special CT978685-CT978926 embl_est", + "special CT978928-CT978956 embl_est", + "special CT978958-CT989251 embl_est", + "special CT989258-CT990465 embl_est", + "special CT990474-CT990486 embl_est", + "special CT990490-CT990531 embl_est", + "", + "# Nominally embl_dirsub.", + "special CU062670-CU062842 embl_est", + "special CU062844-CU062846 embl_est", + "special CU062848-CU074269 embl_est", + "special CU074339-CU074382 embl_est", + "special CU074423-CU075311 embl_est", + "special CU075931-CU076039 embl_est", + "special CU234182-CU234194 embl_est", + "special CU302207 embl_est", + "special CU302209-CU302216 embl_est", + "special CU302324 embl_est", + "special CU306818-CU310069 embl_est", + "special CU310076-CU311182 embl_est", + "special CU367886-CU368379 embl_est", + "special CU368381-CU368441 embl_est", + "special CU368443-CU368521 embl_est", + "special CU368523-CU368526 embl_est", + "special CU368528-CU368600 embl_est", + "special CU368602-CU368745 embl_est", + "special CU368747-CU368750 embl_est", + "special CU368752-CU369046 embl_est", + "special CU369048-CU369187 embl_est", + "special CU369189-CU369553 embl_est", + "special CU369555-CU369565 embl_est", + "special CU369567-CU372896 embl_est", + "special CU372931-CU392058 embl_est", + "special CU394257-CU405559 embl_est", + "special CU415883-CU424422 embl_est", + "special CU424474 embl_est", + "special CU424496-CU442700 embl_est", + "special CU442764-CU457374 embl_est", + "special CU457503-CU487206 embl_other_nuc # 81 EST ranges and 1 GSS range", + "special CU487231-CU498825 embl_est", + "special CU498835-CU499386 embl_other_nuc # 43 EST ranges", + "special CU499388-CU524144 embl_est", + "special CU524146-CU524185 embl_est", + "special CU524187-CU524607 embl_est", + "special CU524609-CU524647 embl_est", + "special CU524649-CU525008 embl_est", + "special CU525010-CU525305 embl_est", + "special CU525307-CU525317 embl_est", + "special CU525319-CU525433 embl_est", + "special CU525435-CU525727 embl_est", + "special CU525729-CU525806 embl_est", + "special CU525808-CU525920 embl_est", + "special CU525922-CU530337 embl_est", + "special CU530421-CU538870 embl_est", + "special CU539140-CU550647 embl_est", + "special CU550735-CU565320 embl_est", + "special CU565322-CU596014 embl_other_nuc # 231 EST ranges", + "special CU596016-CU606845 embl_est", + "special CU607105-CU611033 embl_est", + "special CU611062-CU618304 embl_est", + "special CU618343-CU627974 embl_est", + "special CU628007-CU633156 embl_est", + "special CU637754-CU638663 embl_est", + "special CU639489-CU640365 embl_est", + "special CU640490-CU640880 embl_est", + "special CU651679-CU660012 embl_other_nuc # 41 EST ranges", + "special CU660014-CU672219 embl_est", + "special CU681473-CU681818 embl_est", + "special CU682012-CU682338 embl_est", + "special CU682367-CU682456 embl_est", + "special CU682458-CU682575 embl_est", + "special CU682577-CU682600 embl_est", + "special CU682602-CU682603 embl_est", + "special CU682605-CU682621 embl_est", + "special CU682623-CU682639 embl_est", + "special CU682641-CU682661 embl_est", + "special CU682663-CU682763 embl_est", + "special CU682765-CU682766 embl_est", + "special CU682768-CU682776 embl_est", + "special CU682778-CU682779 embl_est", + "special CU682781-CU682810 embl_est", + "special CU682812-CU683823 embl_est", + "special CU683828-CU683864 embl_est", + "special CU684056-CU686587 embl_est", + "special CU693503-CU694195 embl_est", + "special CU695349-CU740080 embl_est", + "special CU862081-CU896531 embl_est", + "special CU896700-CU905499 embl_est", + "special CU905513-CU914123 embl_est", + "special CU983906-CU984539 embl_est", + "special CU986307-CU993795 embl_est", + "special CU993823-CU999999 embl_est", + "", + "# Nominally ddbj_gss.", + "special DE990447-DE990894 ddbj_dirsub", + "special DE997363-DE998419 ddbj_dirsub", + "", + "# Nominally gb_dirsub.", + "special DQ000203-DQ000205 gb_est", + "special DQ003271-DQ003274 gb_est", + "special DQ005448-DQ005452 gb_est", + "special DQ006915-DQ006921 gb_est", + "special DQ008074-DQ008087 gb_est", + "special DQ009493 gb_est", + "special DQ010056 gb_est", + "special DQ023561-DQ023596 gb_est", + "special DQ054537 gb_est", + "special DQ056320-DQ056336 gb_est", + "special DQ062432 gb_est", + "special DQ068265-DQ068267 gb_est", + "special DQ071657-DQ071667 gb_est", + "special DQ072281-DQ072378 gb_gss", + "special DQ073526-DQ073530 gb_gss", + "special DQ079655-DQ079657 gb_est", + "special DQ082731 gb_est", + "special DQ090495-DQ090499 gb_est", + "special DQ092578-DQ092599 gb_gss", + "special DQ093275-DQ093284 gb_gss", + "special DQ103519-DQ103523 gb_gss", + "special DQ114785 gb_gss", + "special DQ115593-DQ115640 gb_gss", + "special DQ118389-DQ118393 gb_est", + "special DQ119294 gb_est", + "special DQ124861-DQ124867 gb_gss", + "special DQ131496 gb_gss", + "special DQ137423-DQ137425 gb_gss", + "special DQ138061-DQ138069 gb_est", + "special DQ156350-DQ156363 gb_gss", + "special DQ159946-DQ159947 gb_est", + "special DQ160233-DQ160240 gb_gss", + "special DQ172857-DQ172899 gb_est", + "special DQ176001-DQ176002 gb_gss", + "special DQ178992-DQ178994 gb_gss", + "special DQ190447-DQ190449 gb_est", + "special DQ205195-DQ205199 gb_est", + "special DQ207956 gb_est", + "special DQ211055-DQ211083 gb_est", + "special DQ211697 gb_est", + "special DQ217772 gb_est", + "special DQ219385-DQ219392 gb_gss", + "special DQ225105-DQ225107 gb_est", + "special DQ238007-DQ238010 gb_est", + "special DQ256365-DQ256368 gb_est", + "special DQ286755-DQ286759 gb_est", + "special DQ296475-DQ296480 gb_est", + "special DQ301872-DQ301876 gb_est", + "special DQ306698-DQ306705 gb_est", + "special DQ323032-DQ323035 gb_gss", + "special DQ329527-DQ329529 gb_gss", + "special DQ334866 gb_gss", + "special DQ341431-DQ341441 gb_est", + "special DQ349205-DQ349206 gb_est", + "special DQ351716-DQ351721 gb_gss", + "special DQ351838-DQ351840 gb_est", + "special DQ354361 gb_est", + "special DQ394888-DQ394890 gb_est", + "special DQ399337-DQ399338 gb_gss", + "special DQ530238 gb_gss", + "special DQ641039 gb_gss", + "special DQ672588 gb_est", + "special DQ821447-DQ821472 gb_est", + "special DQ822605-DQ822689 gb_est", + "special DQ858157-DQ858164 gb_est", + "special DQ866805 gb_gss", + "special DQ873299-DQ873317 gb_est", + "special DQ883824-DQ884159 gb_est", + "special DQ886384-DQ886389 gb_est", + "special DQ988883-DQ988928 gb_gss", + "special DQ999011-DQ999023 gb_est", + "", + "# Nominally gb_con.", + "special DS483562 gb_dirsub", + "special DS483659 gb_dirsub", + "special DS483744-DS484493 gb_other_nuc # 159 dirsub ranges", + "special DS484496-DS484515 gb_dirsub", + "special DS484518-DS484535 gb_dirsub", + "special DS484538-DS484550 gb_dirsub", + "special DS484552-DS484553 gb_dirsub", + "special DS484555-DS484574 gb_dirsub", + "special DS484576-DS484611 gb_dirsub", + "special DS484614-DS484623 gb_dirsub", + "special DS484625-DS484626 gb_dirsub", + "special DS484628-DS484633 gb_dirsub", + "special DS484635-DS484637 gb_dirsub", + "special DS484639 gb_dirsub", + "special DS484641-DS484654 gb_dirsub", + "special DS484656-DS484675 gb_dirsub", + "special DS484677-DS484686 gb_dirsub", + "special DS484688-DS484703 gb_dirsub", + "special DS484706-DS484707 gb_dirsub", + "special DS484709-DS484710 gb_dirsub", + "special DS484712-DS484716 gb_dirsub", + "special DS484718-DS484742 gb_dirsub", + "special DS484745-DS485146 gb_other_nuc # 80 dirsub ranges", + "special DS485148-DS485167 gb_dirsub", + "special DS485169 gb_dirsub", + "special DS485172-DS485174 gb_dirsub", + "special DS485176-DS485178 gb_dirsub", + "special DS485181-DS485182 gb_dirsub", + "special DS485184 gb_dirsub", + "special DS485186 gb_dirsub", + "special DS485189-DS485190 gb_dirsub", + "special DS485192 gb_dirsub", + "special DS485194-DS485195 gb_dirsub", + "special DS485198-DS485201 gb_dirsub", + "special DS485203-DS485205 gb_dirsub", + "special DS485208-DS485209 gb_dirsub", + "special DS485211 gb_dirsub", + "special DS485215-DS485216 gb_dirsub", + "special DS485218-DS485221 gb_dirsub", + "special DS485223-DS485230 gb_dirsub", + "special DS485233 gb_dirsub", + "special DS485235-DS485236 gb_dirsub", + "special DS485238-DS485240 gb_dirsub", + "special DS485242-DS485243 gb_dirsub", + "special DS485245-DS485247 gb_dirsub", + "special DS485249-DS485268 gb_dirsub", + "special DS485270-DS485271 gb_dirsub", + "special DS485273 gb_dirsub", + "special DS485275 gb_dirsub", + "special DS485277-DS485278 gb_dirsub", + "special DS485280-DS485281 gb_dirsub", + "special DS485283-DS485285 gb_dirsub", + "special DS485287-DS485288 gb_dirsub", + "special DS485290-DS485292 gb_dirsub", + "special DS485294 gb_dirsub", + "special DS485296-DS485306 gb_dirsub", + "special DS485309-DS485311 gb_dirsub", + "special DS485313-DS485316 gb_dirsub", + "special DS485318-DS485320 gb_dirsub", + "special DS485322-DS485326 gb_dirsub", + "special DS485328-DS485331 gb_dirsub", + "special DS485333-DS485343 gb_dirsub", + "special DS485345 gb_dirsub", + "special DS485349 gb_dirsub", + "special DS485351 gb_dirsub", + "special DS485353-DS485354 gb_dirsub", + "special DS485356-DS485365 gb_dirsub", + "special DS485368 gb_dirsub", + "special DS485370-DS485371 gb_dirsub", + "special DS485374-DS485376 gb_dirsub", + "special DS485378-DS485379 gb_dirsub", + "special DS485381-DS485390 gb_dirsub", + "special DS485392-DS485393 gb_dirsub", + "special DS485395 gb_dirsub", + "special DS485397-DS485401 gb_dirsub", + "special DS485403 gb_dirsub", + "special DS485407 gb_dirsub", + "special DS485409-DS485411 gb_dirsub", + "special DS485415-DS485416 gb_dirsub", + "special DS485418-DS485430 gb_dirsub", + "special DS485433-DS485434 gb_dirsub", + "special DS485436-DS485443 gb_dirsub", + "special DS485448 gb_dirsub", + "special DS485450-DS485454 gb_dirsub", + "special DS485456-DS485457 gb_dirsub", + "special DS485459-DS485462 gb_dirsub", + "special DS485464-DS485473 gb_dirsub", + "special DS485475-DS485478 gb_dirsub", + "special DS485481-DS485483 gb_dirsub", + "special DS485488 gb_dirsub", + "special DS485490-DS485492 gb_dirsub", + "special DS485494-DS485498 gb_dirsub", + "special DS485500-DS485501 gb_dirsub", + "special DS485503-DS485506 gb_dirsub", + "special DS485509 gb_dirsub", + "special DS485512 gb_dirsub", + "special DS485514-DS485515 gb_dirsub", + "special DS485517-DS485518 gb_dirsub", + "special DS485520-DS485523 gb_dirsub", + "special DS485525-DS485545 gb_dirsub", + "special DS485547-DS486008 gb_other_nuc # 95 dirsub ranges", + "", + "# Nominally gb_dirsub.", + "special EF053039-EF053049 gb_gss", + "special EF063001 gb_est", + "special EF095769 gb_gss", + "special EF165098 gb_gss", + "special EF182756-EF182758 gb_gss", + "special EF189906-EF189916 gb_est", + "special EF204530-EF204533 gb_gss", + "special EF208191 gb_gss", + "special EF210438-EF210453 gb_gss", + "special EF377525-EF377537 gb_est", + "special EF422869 gb_est", + "special EF473211-EF473215 gb_est", + "special EF494771-EF494773 gb_est", + "special EF552376 gb_est", + "special EF578434-EF578635 gb_gss", + "special EF592824-EF592944 gb_gss", + "", + "# Nominally gb_dirsub.", + "special EU152056-EU152079 gb_est", + "special EU239816 gb_est", + "special EU306364-EU306386 gb_gss", + "special EU364506-EU364507 gb_est", + "special EU368044 gb_est", + "special EU369669 gb_est", + "special EU420034 gb_est", + "special EU597223-EU597228 gb_est", + "", + "# Nominally gb_dirsub.", + "special FJ710154-FJ710155 gb_est", + "special FJ842632-FJ842642 gb_est", + "", + "# Nominally embl_dirsub.", + "special FM000001-FM160408 embl_est", + "special FM164769 embl_est", + "special FM164940 embl_est", + "special FM165392 embl_est", + "special FM165707-FM172746 embl_est", + "special FM178562-FM178778 embl_est", + "special FM180579-FM196445 embl_est", + "special FM205236-FM205493 embl_est", + "special FM205777-FM205831 embl_est", + "special FM207878-FM207900 embl_est", + "special FM208280-FM208711 embl_est", + "special FM208851 embl_est", + "special FM208900 embl_est", + "special FM212937 embl_est", + "special FM215048-FM242054 embl_est", + "special FM246886-FM251871 embl_est", + "special FM253361 embl_est", + "special FM253366-FM253368 embl_est", + "special FM253372 embl_est", + "special FM253378 embl_est", + "special FM864313-FM864344 embl_est", + "special FM864347-FM865295 embl_est", + "special FM868295-FM872275 embl_est", + "special FM879143-FM881767 embl_est", + "special FM882258-FM883162 embl_est", + "special FM885959-FM886821 embl_est", + "special FM887038-FM896881 embl_est", + "special FM897212-FM897213 embl_est", + "special FM897377-FM945301 embl_est", + "special FM945441-FM945999 embl_est", + "special FM946183-FM954971 embl_est", + "special FM957013-FM957079 embl_est", + "special FM958532-FM985957 embl_est", + "special FM992847-FM992850 embl_est", + "special FM999776-FM999787 embl_est", + "", + "# Nominally embl_dirsub. Give the benefit of the doubt to sequences", + "# that look like embl_genome, but split out EST ranges.", + "special FN000001-FN177896 embl_est", + "special FN179489-FN182188 embl_est", + "special FN182288-FN185725 embl_est", + "special FN186135-FN190445 embl_est", + "special FN190447-FN252183 embl_est", + "special FN252460-FN252789 embl_est", + "special FN263376-FN292969 embl_est", + "special FN377870-FN386264 embl_est", + "special FN393571-FN393732 embl_est", + "special FN393830-FN393849 embl_est", + "special FN424437-FN428571 embl_est", + "special FN430839-FN431219 embl_est", + "special FN431234-FN431660 embl_est", + "special FN432032-FN432041 embl_est", + "special FN432154-FN432328 embl_est", + "special FN432729-FN432775 embl_est", + "special FN433834-FN433837 embl_est", + "special FN435336-FN435350 embl_est", + "special FN539079-FN543092 embl_est", + "special FN551261-FN551733 embl_est", + "special FN552552-FN552591 embl_est", + "special FN552699-FN552705 embl_est", + "special FN555710-FN555987 embl_est", + "special FN557216-FN557223 embl_est", + "special FN561898-FN561924 embl_est", + "special FN562175-FN562396 embl_est", + "special FN564151-FN564158 embl_est", + "special FN565576-FN566839 embl_est", + "special FN588437-FN594512 embl_est", + "special FN600697 embl_est", + "special FN601407-FN610843 embl_est", + "special FN611035-FN640462 embl_est", + "special FN640581-FN641653 embl_est", + "special FN641925-FN643079 embl_est", + "special FN646764-FN647626 embl_est", + "special FN651825-FN651826 embl_est", + "special FN652903-FN652904 embl_est", + "special FN661971-FN662351 embl_est", + "special FN664012-FN665290 embl_est", + "special FN669777-FN673545 embl_est", + "special FN679295-FN686775 embl_est", + "special FN691927 embl_est", + "special FN692044-FN706436 embl_est", + "special FN706565-FN773062 embl_est", + "special FN773104-FN773170 embl_est", + "special FN796618-FN796723 embl_est", + "special FN796987-FN806772 embl_est", + "special FN806826-FN806848 embl_est", + "special FN811794-FN811851 embl_est", + "special FN811944-FN812314 embl_est", + "special FN813225-FN813226 embl_est", + "special FN813467-FN813469 embl_est", + "special FN814310-FN820203 embl_est", + "special FN822244-FN822743 embl_est", + "special FN823242-FN823254 embl_est", + "special FN868597 embl_est", + "special FN868902-FN868929 embl_est", + "special FN869177-FN869376 embl_est", + "special FN870962-FN907899 embl_est", + "special FN908254-FN908302 embl_est", + "special FN985040 embl_est", + "special FN985644-FN993914 embl_est", + "special FN997680-FN998838 embl_est", + "special FN999023-FN999906 embl_est", + "", + "# Nominally embl_dirsub.", + "special FO000003-FO076577 embl_est", + "special FO082887-FO117570 embl_est", + "special FO117633-FO181358 embl_est", + "special FO181544-FO203352 embl_est", + "special FO203528-FO393391 embl_est", + "special FO680693-FO681285 embl_est", + "special FO704924-FO722023 embl_est", + "special FO981374-FO999999 embl_est", + "", + "# Nominally embl_dirsub.", + "special FP000001-FP003579 embl_est", + "special FP003602-FP009753 embl_est", + "special FP009755-FP009758 embl_est", + "special FP009760-FP009761 embl_est", + "special FP009763-FP009764 embl_est", + "special FP009766-FP012228 embl_est", + "special FP024615-FP057328 embl_est", + "special FP057330-FP057370 embl_est", + "special FP057373-FP057454 embl_other_nuc # 33 EST ranges", + "special FP057456-FP057462 embl_est", + "special FP057465-FP057560 embl_other_nuc # 43 EST ranges", + "special FP057562-FP057566 embl_est", + "special FP057568-FP057656 embl_other_nuc # 39 EST ranges", + "special FP057664-FP057702 embl_other_nuc # 16 EST ranges", + "special FP057704-FP057709 embl_est", + "special FP057711-FP058036 embl_other_nuc # 141 EST ranges", + "special FP058042-FP058155 embl_other_nuc # 45 EST ranges", + "special FP058162-FP058163 embl_est", + "special FP058165 embl_est", + "special FP058167 embl_est", + "special FP058169 embl_est", + "special FP058171-FP058172 embl_est", + "special FP058174 embl_est", + "special FP058176-FP058177 embl_est", + "special FP058180 embl_est", + "special FP058183-FP058190 embl_est", + "special FP058192-FP058271 embl_other_nuc # 33 EST ranges", + "special FP058282 embl_est", + "special FP058284 embl_est", + "special FP058286 embl_est", + "special FP058293-FP058514 embl_other_nuc # 95 EST ranges", + "special FP058526-FP058527 embl_est", + "special FP058529 embl_est", + "special FP058531-FP058532 embl_est", + "special FP058534 embl_est", + "special FP058537 embl_est", + "special FP058539 embl_est", + "special FP058542-FP058543 embl_est", + "special FP058545 embl_est", + "special FP058547-FP058553 embl_est", + "special FP058556-FP058658 embl_other_nuc # 44 EST ranges", + "special FP058673-FP058706 embl_other_nuc # 15 EST ranges", + "special FP058708-FP058713 embl_est", + "special FP058715-FP059322 embl_other_nuc # 248 EST ranges", + "special FP059328 embl_est", + "special FP059330-FP059332 embl_est", + "special FP059334 embl_est", + "special FP059337 embl_est", + "special FP059339 embl_est", + "special FP059341 embl_est", + "special FP059343 embl_est", + "special FP059345 embl_est", + "special FP059348-FP059352 embl_est", + "special FP059354-FP059385 embl_other_nuc # 14 EST ranges", + "special FP059387-FP059393 embl_est", + "special FP059395-FP059833 embl_other_nuc # 187 EST ranges", + "special FP059841-FP059887 embl_other_nuc # 22 EST ranges", + "special FP059895-FP060210 embl_other_nuc # 136 EST ranges", + "special FP060212-FP060217 embl_est", + "special FP060219-FP060469 embl_other_nuc # 104 EST ranges", + "special FP060477-FP061762 embl_other_nuc # 552 EST ranges", + "special FP061764-FP061769 embl_est", + "special FP061771-FP062313 embl_other_nuc # 234 EST ranges", + "special FP062315-FP062321 embl_est", + "special FP062324-FP062896 embl_other_nuc # 246 EST ranges", + "special FP062906-FP062999 embl_other_nuc # 39 EST ranges", + "special FP063008-FP063034 embl_other_nuc # 11 EST ranges", + "special FP063036-FP063040 embl_est", + "special FP063043-FP063447 embl_other_nuc # 166 EST ranges", + "special FP063449-FP063453 embl_est", + "special FP063455-FP063802 embl_other_nuc # 154 EST ranges", + "special FP063804-FP063812 embl_est", + "special FP063814-FP063898 embl_other_nuc # 35 EST ranges", + "special FP063900-FP063904 embl_est", + "special FP063906-FP064076 embl_other_nuc # 74 EST ranges", + "special FP064082-FP064562 embl_other_nuc # 208 EST ranges", + "special FP064569-FP065157 embl_other_nuc # 251 EST ranges", + "special FP065159-FP067333 embl_est", + "special FP067453-FP074848 embl_est", + "special FP089705-FP089949 embl_est", + "special FP090914-FP091223 embl_est", + "special FP101920-FP101950 embl_est", + "special FP104570-FP236120 embl_est", + "special FP236870-FP243270 embl_est", + "special FP245546-FP312611 embl_est", + "special FP318637-FP325096 embl_est", + "special FP331359-FP339571 embl_est", + "special FP339630-FP340170 embl_est", + "special FP340462-FP340488 embl_est", + "special FP350355-FP360034 embl_est", + "special FP360036-FP458874 embl_est", + "special FP458876-FP475875 embl_est", + "special FP489021-FP539727 embl_est", + "special FP539730-FP565142 embl_est", + "special FP565937-FP578983 embl_est", + "special FP579010-FP583343 embl_est", + "special FP583356-FP628470 embl_est", + "special FP628472-FP671119 embl_est", + "special FP671140-FP680548 embl_est", + "special FP680607-FP690338 embl_est", + "special FP690350-FP700052 embl_est", + "special FP700189-FP710243 embl_est", + "special FP710258-FP791398 embl_est", + "special FP791400-FP884219 embl_est", + "special FP884235-FP885524 embl_est", + "special FP885545-FP885822 embl_est", + "special FP885927-FP893245 embl_est", + "special FP893247-FP924936 embl_est", + "special FP927985-FP928978 embl_est", + "special FP928990-FP928995 embl_est", + "special FP929145-FP999998 embl_est", + "", + "# Nominally embl_dirsub.", + "special FQ000001 embl_est", + "special FQ000005-FQ014216 embl_est", + "special FQ014236-FQ032656 embl_est", + "special FQ032836-FQ073829 embl_est", + "special FQ073967-FQ116746 embl_est", + "special FQ116748-FQ209379 embl_est", + "special FQ235350-FQ242479 embl_est", + "special FQ312199-FQ323093 embl_est", + "special FQ323164-FQ361146 embl_est", + "special FQ361149-FQ377486 embl_est", + "special FQ377488-FQ377516 embl_est", + "special FQ398062-FQ439981 embl_est", + "special FQ439983-FQ440019 embl_est", + "special FQ440021-FQ440022 embl_est", + "special FQ440024 embl_est", + "special FQ440026 embl_est", + "special FQ440028 embl_est", + "special FQ440030-FQ440032 embl_est", + "special FQ440034-FQ456868 embl_est", + "special FQ456875-FQ482045 embl_est", + "special FQ482048-FQ482071 embl_est", + "special FQ660554-FQ670147 embl_est", + "special FQ790408-FQ828345 embl_est", + "special FQ828348-FQ857191 embl_est", + "special FQ859091-FQ859175 embl_est", + "special FQ859187-FQ865452 embl_est", + "special FQ865457-FQ908260 embl_est", + "special FQ908267-FQ958209 embl_est", + "special FQ958213-FQ976554 embl_est", + "special FQ976923-FQ999999 embl_est", + "", + "# Nominally embl_dirsub. Give the benefit of the doubt to sequences", + "# that look like embl_con or embl_genome, but split out EST and TPA(!)", + "# ranges.", + "special FR595163-FR647444 embl_est", + "special FR660151-FR666602 embl_est", + "special FR668536 embl_est", + "special FR669245-FR669246 embl_est", + "special FR686584 embl_est", + "special FR686963-FR686965 embl_est", + "special FR688150-FR689535 embl_est", + "special FR691564 embl_est", + "special FR697056-FR714330 embl_est", + "special FR719326-FR719692 embl_est", + "special FR726163-FR726165 embl_est", + "special FR728240-FR728241 embl_est", + "special FR729927-FR731105 embl_est", + "special FR734011-FR734074 embl_tpa_nuc", + "special FR734407-FR744448 embl_est", + "special FR746042-FR746044 embl_est", + "special FR746111-FR747822 embl_est", + "special FR748230-FR749648 embl_est", + "special FR749997 embl_tpa_nuc", + "special FR753167-FR754317 embl_est", + "special FR754554-FR771822 embl_est", + "special FR773977 embl_est", + "special FR775966 embl_est", + "special FR819721-FR819744 embl_est", + "special FR821738-FR821754 embl_tpa_nuc", + "special FR822741 embl_tpa_nuc", + "special FR828827-FR831799 embl_est", + "special FR836483-FR837532 embl_est", + "special FR837542-FR837592 embl_est", + "special FR839767-FR845655 embl_est", + "special FR846456-FR846460 embl_est", + "special FR846537-FR846887 embl_est", + "special FR847124-FR847145 embl_est", + "special FR847228-FR847840 embl_est", + "special FR847888-FR847943 embl_est", + "special FR848368-FR848371 embl_est", + "special FR850135-FR850157 embl_est", + "special FR851958 embl_est", + "special FR852768 embl_est", + "special FR852894-FR852904 embl_est", + "special FR854398-FR856581 embl_est", + "special FR863689-FR864978 embl_est", + "special FR869720-FR869795 embl_est", + "special FR872817 embl_tpa_nuc", + "special FR873995-FR874005 embl_est", + "special FR877768-FR877777 embl_tpa_nuc", + "special FR877779-FR878008 embl_est", + "special FR878032-FR878040 embl_est", + "", + "special GQ162211-GQ162212 gb_est # Nominally gb_dirsub.", + "", + "# Nominally gb_dirsub.", + "special GU357827-GU357840 gb_est", + "special GU385812 gb_est", + "", + "# Nominally embl_dirsub.", + "special HE575663-HE575667 embl_est", + "special HE578177-HE578180 embl_est", + "special HE578289-HE578716 embl_est", + "special HE580226-HE580228 embl_est", + "special HE580237-HE580238 embl_tpa_nuc", + "special HE583424-HE583588 embl_tpa_nuc", + "special HE600073-HE600122 embl_est", + "special HE602495-HE602530 embl_est", + "special HE612182 embl_est", + "special HE613800 embl_tpa_nuc", + "special HE617969-HE646283 embl_est", + "special HE681861-HE681882 embl_est", + "special HE775617-HE792769 embl_est", + "special HE795538-HE795641 embl_est", + "special HE799315-HE799645 embl_est", + "special HE802076-HE802106 embl_est", + "special HE804769-HE804772 embl_tpa_nuc", + "special HE858615-HE859937 embl_est", + "special HE862417-HE862958 embl_est", + "special HE957083-HE961812 embl_est", + "special HE962539 embl_est", + "special HE963851-HE964756 embl_tpa_nuc", + "special HE967761 embl_tpa_nuc", + "special HE967924-HE967957 embl_est", + "special HE981808-HE983324 embl_est", + "special HE985332-HE993548 embl_est", + "", + "# Nominally embl_dirsub. Give the benefit of the doubt to sequences", + "# that look like embl_genome, but split out EST, TPA(!), and WGS ranges.", + "special HF546137-HF546200 embl_est", + "special HF546978 embl_est", + "special HF564658-HF564815 embl_tpa_nuc", + "special HF566097-HF566123 embl_est", + "special HF567775-HF567843 embl_est", + "special HF913790-HF920632 embl_wgs_nuc", + "special HF933207-HF933230 embl_tpa_nuc", + "special HF952730-HF952771 embl_est", + "special HF953988-HF954002 embl_est", + "", + "# Nominally embl_dirsub. Give the benefit of the doubt to sequences", + "# that look like embl_genome, but split out EST and TPA(!) ranges.", + "special HG000495-HG000664 embl_est", + "special HG001312-HG001319 embl_est", + "special HG313979-HG314002 embl_tpa_nuc", + "special HG314154-HG314951 embl_est", + "special HG322958-HG323812 embl_tpa_nuc", + "special HG326529-HG326598 embl_est", + "special HG328835-HG329089 embl_tpa_nuc", + "special HG421036-HG421067 embl_est", + "special HG424982-HG425075 embl_est", + "special HG425120-HG425123 embl_tpa_nuc", + "special HG426065-HG426183 embl_tpa_nuc", + "special HG491497-HG512884 embl_tpa_nuc", + "special HG516089-HG518058 embl_est", + "special HG518794-HG528968 embl_tpa_nuc", + "special HG531973-HG532008 embl_tpa_nuc", + "special HG780872-HG792014 embl_tpa_nuc", + "special HG792878-HG792996 embl_est", + "special HG798530-HG798533 embl_est", + "special HG931734-HG931849 embl_tpa_nuc", + "special HG964498-HG964527 embl_est", + "special HG965112-HG965128 embl_est", + "special HG970048-HG970064 embl_est", + "special HG975377-HG975438 embl_tpa_nuc", + "special HG977712-HG983278 embl_tpa_nuc", + "special HG983548-HG986399 embl_tpa_nuc", + "", + "special HM042681 gb_est # Nominally gb_dirsub.", + "", + "# Nominally gb_dirsub.", + "special HQ385980-HQ385998 gb_est", + "special HQ436350 gb_est", + "special HQ596498-HQ596504 gb_est", + "special HQ603829-HQ603854 gb_est", + "special HQ616895-HQ616912 gb_est", + "special HQ634394-HQ634477 gb_est", + "", + "special JN376805-JN377341 gb_est # Nominally gb_dirsub.", + "", + "special KF487514 gb_est # Nominally gb_dirsub.", + "", + "special KJ472321-KJ472336 gb_est # Nominally gb_dirsub.", + "", + "special KM673248-KM673271 gb_est # Nominally gb_dirsub.", + "", + "# Nominally embl_dirsub.", + "special LK000001-LK020668 embl_tpa_nuc", + "special LK937705-LK939125 embl_tpa_nuc", + "special LK985528-LK995307 embl_est", + "", + "# Nominally embl_dirsub.", + "special LM378690-LM383429 embl_tpa_nuc", + "special LM608092-LM611902 embl_tpa_nuc", + "special LM644135-LM644234 embl_tpa_nuc", + "special LM994684-LM994695 embl_est", + "", + "# Nominally embl_dirsub. Give the benefit of the doubt to sequences", + "# that look like embl_con, but split out EST and TPA(!) ranges.", + "special LN607841-LN608991 embl_tpa_nuc", + "special LN624403-LN624404 embl_est", + "special LN651082-LN651092 embl_est", + "special LN651553-LN678462 embl_est", + "special LN680257-LN680271 embl_est", + "special LN714474-LN714514 embl_tpa_nuc", + "special LN794245-LN794246 embl_tpa_nuc", + "special LN809256-LN809883 embl_tpa_nuc", + "special LN846618-LN846619 embl_tpa_nuc", + "special LN847449-LN848230 embl_tpa_nuc", + "special LN849001 embl_tpa_nuc", + "special LN871971-LN872940 embl_tpa_nuc", + "special LN874312-LN874522 embl_tpa_nuc", + "special LN879549-LN879837 embl_est", + "special LN898187-LN898198 embl_tpa_nuc", + "special LN901194-LN901210 embl_tpa_nuc", + "special LN901386-LN901412 embl_est", + "", + "# Nominally embl_dirsub.", + "special LT159851-LT159865 embl_est", + "special LT548096-LT548244 embl_tpa_nuc", + "special LT556286-LT558089 embl_est", + "special LT571433-LT571435 embl_tpa_nuc", + "special LT605004 embl_tpa_nuc", + "special LT631550-LT631670 embl_tpa_nuc", + "## Err on the side of caution on as yet unassigned IDs, and hope that", + "## there's not *too* much more backfilling.", + "#special LT828649-LT999999 unreserved_nuc", "", "# Some \"EMBL\" 8-character protein accessions are really third party", "# annotations.", @@ -9737,7 +11855,10 @@ static const char* const kBuiltInGuide[] = { "special SAI82298-SAI82303 embl_tpa_prot", "special SAQ69746-SAQ69766 embl_tpa_prot", "special SAQ71209 embl_tpa_prot", + "special SCC99881-SCC99885 embl_tpa_prot", + "special SFW93197-SFW93317 embl_tpa_prot", + "special SNU76807-SNU78093 embl_tpa_prot", "## Err on the side of caution on as yet unassigned IDs, and hope that", "## there's not *too* much more backfilling.", - "#special SEW57495-SZZ99999 unreserved_prot" + "#special SNZ31834-SZZ99999 unreserved_prot" }; diff --git a/c++/src/objects/seqloc/accguide.txt b/c++/src/objects/seqloc/accguide.txt index 996d3155..10b4b813 100644 --- a/c++/src/objects/seqloc/accguide.txt +++ b/c++/src/objects/seqloc/accguide.txt @@ -1,4 +1,4 @@ -# $Id: accguide.txt 519343 2016-11-15 13:41:14Z ucko $ +# $Id: accguide.txt 548063 2017-10-10 13:00:13Z ucko $ version 1 # of file format # 8-character protein accessions @@ -15,14 +15,14 @@ version 1 # of file format 3+5 I?? ddbj_tpa_wgs_prot 3+5 J?? gb_tsa_prot 3+5 K?? gb_wgs_prot -3+5 L?? ddbj_tsa_prot +3+5 L?? ddbj_prot # mixed TSA and TLS 3+5 M?? gb_wgs_prot 3+5 N?? gb_wgs_prot 3+5 O?? gb_wgs_prot 3+5 P?? gb_wgs_prot 3+5 Q?? gb_prot 3+5 R?? gb_prot -3+5 S?? embl_prot +3+5 S?? embl_prot * 3+5 ??? unreserved_prot # Genome pipeline accessions @@ -89,12 +89,12 @@ version 1 # of file format 4+8 L??? gb_wgs_nuc 4+9 L??? gb_wgs_nuc 4+10 L??? gb_wgs_nuc -4+8 M??? gb_wgs_nuc -4+9 M??? gb_wgs_nuc -4+10 M??? gb_wgs_nuc -4+8 N??? gb_wgs_nuc -4+9 N??? gb_wgs_nuc -4+10 N??? gb_wgs_nuc +4+8 M??? gb_wgs_nuc # gb_tsa_nuc? +4+9 M??? gb_wgs_nuc # gb_tsa_nuc? +4+10 M??? gb_wgs_nuc # gb_tsa_nuc? +4+8 N??? gb_wgs_nuc # gb_tsa_nuc? +4+9 N??? gb_wgs_nuc # gb_tsa_nuc? +4+10 N??? gb_wgs_nuc # gb_tsa_nuc? 4+8 O??? embl_wgs_nuc 4+9 O??? embl_wgs_nuc 4+10 O??? embl_wgs_nuc @@ -110,6 +110,12 @@ version 1 # of file format 4+8 S??? gb_wgs_nuc # specifically, USPTO pre-grant patent data 4+9 S??? gb_wgs_nuc # specifically, USPTO pre-grant patent data 4+10 S??? gb_wgs_nuc # specifically, USPTO pre-grant patent data +4+8 T??? ddbj_wgs_nuc # fallback to placate older clients +4+9 T??? ddbj_wgs_nuc # fallback to placate older clients +4+10 T??? ddbj_wgs_nuc # fallback to placate older clients +4+8 T??? ddbj_targeted_nuc +4+9 T??? ddbj_targeted_nuc +4+10 T??? ddbj_targeted_nuc # Mass sequence Genome for Annotation 5+7 A???? ddbj_other_nuc @@ -164,46 +170,46 @@ version 1 # of file format # 6-character accessions (mixed, but generally nucleotide) 1+5 A embl_patent 1+5 B gb_gss -1+5 C ddbj_est -1+5 D ddbj_dirsub +1+5 C ddbj_est * +1+5 D ddbj_dirsub * 1+5 E ddbj_patent -1+5 F embl_est +1+5 F embl_est * 1+5 G gb_sts 1+5 H gb_est 1+5 I gb_patent 1+5 J gsdb_dirsub 1+5 K gsdb_dirsub -1+5 L gsdb_dirsub -1+5 M gsdb_dirsub +1+5 L gsdb_dirsub * +1+5 M gsdb_dirsub * 1+5 N unreserved_nuc * 1+5 O swissprot 1+5 P swissprot 1+5 Q swissprot 1+5 R gb_est 1+5 S gb_backbone -1+5 T gb_est -1+5 U gb_dirsub +1+5 T gb_est * +1+5 U gb_dirsub * 1+5 V embl_dirsub 1+5 W gb_est -1+5 X embl_dirsub -1+5 Y embl_dirsub -1+5 Z embl_dirsub +1+5 X embl_dirsub * +1+5 Y embl_dirsub * +1+5 Z embl_dirsub * 1+5 ? unreserved_nuc # 8-character nucleotide accessions 2+6 AA gb_est -2+6 AB ddbj_dirsub +2+6 AB ddbj_dirsub * 2+6 AC gb_htgs 2+6 AD gb_gsdb 2+6 AE gb_genome -2+6 AF gb_dirsub -2+6 AG ddbj_genome +2+6 AF gb_dirsub * +2+6 AG ddbj_gss * 2+6 AH gb_segset 2+6 AI gb_est -2+6 AJ embl_dirsub +2+6 AJ embl_dirsub * 2+6 AK ddbj_mrna -2+6 AL embl_other_nuc # nominally for genome projects, but unrestricted -2+6 AM embl_dirsub +2+6 AL embl_dirsub * +2+6 AM embl_dirsub * 2+6 AN embl_con 2+6 AO unreserved_nuc 2+6 AP ddbj_genome @@ -211,11 +217,11 @@ version 1 # of file format 2+6 AR gb_patent 2+6 AS gb_other_nuc 2+6 AT ddbj_est -2+6 AU ddbj_est +2+6 AU ddbj_est * 2+6 AV ddbj_est 2+6 AW gb_est -2+6 AX embl_patent -2+6 AY gb_dirsub +2+6 AX embl_patent * +2+6 AY gb_dirsub * 2+6 AZ gb_gss 2+6 BA ddbj_con 2+6 BB ddbj_est @@ -228,7 +234,8 @@ version 1 # of file format 2+6 BI gb_est 2+6 BJ ddbj_est 2+6 BK gb_tpa_nuc -2+6 BL gb_tpa_nuc +2+6 BL gb_tpa_nuc # Fallback to placate older clients +2+6 BL gb_tpa_segset # Formally CON but not necessarily genomic 2+6 BM gb_est 2+6 BN embl_tpa_nuc 2+6 BO unreserved_nuc @@ -240,7 +247,7 @@ version 1 # of file format 2+6 BU gb_est 2+6 BV gb_sts 2+6 BW ddbj_est -2+6 BX embl_other_nuc +2+6 BX embl_dirsub * 2+6 BY ddbj_est 2+6 BZ gb_gss 2+6 CA gb_est @@ -255,15 +262,16 @@ version 1 # of file format 2+6 CJ ddbj_est 2+6 CK gb_est 2+6 CL gb_gss -2+6 CM gb_con +2+6 CM gb_con # Fallback to placate older clients +2+6 CM gb_chromosome 2+6 CN gb_est 2+6 CO gb_est -2+6 CP gb_genome +2+6 CP gb_genome * 2+6 CQ embl_patent -2+6 CR embl_other_nuc +2+6 CR embl_dirsub * 2+6 CS embl_patent -2+6 CT embl_other_nuc -2+6 CU embl_other_nuc +2+6 CT embl_dirsub * +2+6 CU embl_dirsub * 2+6 CV gb_est 2+6 CW gb_gss 2+6 CX gb_est @@ -273,7 +281,7 @@ version 1 # of file format 2+6 DB ddbj_est 2+6 DC ddbj_est 2+6 DD ddbj_patent -2+6 DE ddbj_gss +2+6 DE ddbj_gss * 2+6 DF ddbj_con 2+6 DG ddbj_con 2+6 DH ddbj_gss @@ -284,10 +292,10 @@ version 1 # of file format 2+6 DM ddbj_patent 2+6 DN gb_est 2+6 DO unreserved_nuc -2+6 DP gb_htgs -2+6 DQ gb_dirsub +2+6 DP gb_htgs # HTG scaffolds; look like gb_con, but built on htgs parts +2+6 DQ gb_dirsub * 2+6 DR gb_est -2+6 DS gb_con +2+6 DS gb_con * 2+6 DT gb_est 2+6 DU gb_gss 2+6 DV gb_est @@ -300,7 +308,7 @@ version 1 # of file format 2+6 EC gb_est 2+6 ED gb_gss 2+6 EE gb_est -2+6 EF gb_dirsub +2+6 EF gb_dirsub * 2+6 EG gb_est 2+6 EH gb_est 2+6 EI gb_gss @@ -315,7 +323,7 @@ version 1 # of file format 2+6 ER gb_gss 2+6 ES gb_est 2+6 ET gb_gss -2+6 EU gb_dirsub +2+6 EU gb_dirsub * 2+6 EV gb_est 2+6 EW gb_est 2+6 EX gb_est @@ -330,15 +338,15 @@ version 1 # of file format 2+6 FG gb_est 2+6 FH gb_gss 2+6 FI gb_gss -2+6 FJ gb_dirsub +2+6 FJ gb_dirsub * 2+6 FK gb_est 2+6 FL gb_est -2+6 FM embl_dirsub -2+6 FN embl_dirsub -2+6 FO embl_dirsub -2+6 FP embl_other_nuc -2+6 FQ embl_other_nuc -2+6 FR embl_other_nuc +2+6 FM embl_dirsub * +2+6 FN embl_dirsub * +2+6 FO embl_dirsub * +2+6 FP embl_dirsub * +2+6 FQ embl_dirsub * +2+6 FR embl_dirsub * 2+6 FS ddbj_est 2+6 FT ddbj_gss 2+6 FU ddbj_patent @@ -363,11 +371,11 @@ version 1 # of file format 2+6 GN embl_patent 2+6 GO gb_est 2+6 GP gb_patent -2+6 GQ gb_dirsub +2+6 GQ gb_dirsub * 2+6 GR gb_est 2+6 GS gb_gss 2+6 GT gb_est -2+6 GU gb_dirsub +2+6 GU gb_dirsub * 2+6 GV gb_patent 2+6 GW gb_est 2+6 GX gb_patent @@ -377,27 +385,27 @@ version 1 # of file format 2+6 HB embl_patent 2+6 HC embl_patent 2+6 HD embl_patent -2+6 HE embl_dirsub -2+6 HF embl_dirsub -2+6 HG embl_dirsub +2+6 HE embl_dirsub * +2+6 HF embl_dirsub * +2+6 HG embl_dirsub * 2+6 HH embl_patent 2+6 HI embl_patent 2+6 HJ gb_patent 2+6 HK gb_patent 2+6 HL gb_patent -2+6 HM gb_dirsub +2+6 HM gb_dirsub * 2+6 HN gb_gss 2+6 HO gb_est 2+6 HP gb_tsa_nuc -2+6 HQ gb_dirsub +2+6 HQ gb_dirsub * 2+6 HR gb_gss 2+6 HS gb_est 2+6 HT ddbj_tpa_nuc # fallback to placate older clients 2+6 HT ddbj_tpa_con 2+6 HU ddbj_tpa_nuc # fallback to placate older clients 2+6 HU ddbj_tpa_chromosome -2+6 HV gb_patent -2+6 HW gb_patent +2+6 HV ddbj_patent +2+6 HW ddbj_patent 2+6 HX ddbj_est 2+6 HY ddbj_est 2+6 HZ ddbj_patent @@ -414,7 +422,7 @@ version 1 # of file format 2+6 JK gb_est 2+6 JL gb_tsa_nuc 2+6 JM gb_gss -2+6 JN gb_dirsub +2+6 JN gb_dirsub * 2+6 JO gb_tsa_nuc 2+6 JP gb_tsa_nuc 2+6 JQ gb_dirsub @@ -432,14 +440,14 @@ version 1 # of file format 2+6 KC gb_dirsub 2+6 KD gb_con 2+6 KE gb_con -2+6 KF gb_dirsub +2+6 KF gb_dirsub * 2+6 KG gb_gss 2+6 KH gb_patent 2+6 KI gb_con -2+6 KJ gb_dirsub +2+6 KJ gb_dirsub * 2+6 KK gb_con 2+6 KL gb_con -2+6 KM gb_dirsub +2+6 KM gb_dirsub * 2+6 KN gb_con 2+6 KO gb_gss 2+6 KP gb_dirsub @@ -449,9 +457,10 @@ version 1 # of file format 2+6 KT gb_dirsub 2+6 KU gb_dirsub 2+6 KV gb_con +2+6 KW gb_other_nuc 2+6 KX gb_dirsub 2+6 KY gb_dirsub -2+6 K? gb_other_nuc +2+6 KZ gb_con 2+6 LA ddbj_tsa_nuc 2+6 LB ddbj_gss 2+6 LC ddbj_dirsub @@ -462,26 +471,41 @@ version 1 # of file format 2+6 LH ddbj_tsa_nuc 2+6 LI ddbj_tsa_nuc 2+6 LJ ddbj_tsa_nuc -2+6 LK embl_other_nuc -2+6 LL embl_other_nuc -2+6 LM embl_other_nuc -2+6 LN embl_other_nuc -2+6 LO embl_other_nuc -2+6 LP embl_other_nuc -2+6 LQ embl_other_nuc -2+6 LR embl_other_nuc -2+6 LS embl_other_nuc -2+6 LT embl_other_nuc +2+6 LK embl_dirsub * +2+6 LL embl_dirsub +2+6 LM embl_dirsub * +2+6 LN embl_dirsub * +2+6 LO embl_dirsub * +2+6 LP embl_patent +2+6 LQ embl_patent +2+6 LR embl_dirsub # embl_patent? +2+6 LS embl_dirsub # embl_patent? +2+6 LT embl_dirsub * 2+6 LU ddbj_est 2+6 LV ddbj_patent +2+6 LW ddbj_other_nuc 2+6 LX ddbj_patent -2+6 LY ddbj_other_nuc -2+6 LZ ddbj_other_nuc +2+6 LY ddbj_patent +2+6 LZ ddbj_patent 2+6 MA ddbj_other_nuc 2+6 MB ddbj_other_nuc 2+6 MC ddbj_other_nuc 2+6 MD ddbj_other_nuc 2+6 ME ddbj_other_nuc +2+6 MF gb_dirsub +2+6 MG gb_dirsub +2+6 MH gb_other_nuc +2+6 MI gb_other_nuc +2+6 MJ gb_other_nuc +2+6 MK gb_other_nuc +2+6 ML gb_other_nuc +2+6 MM gb_other_nuc +2+6 MN gb_other_nuc +2+6 MO gb_other_nuc +2+6 MP embl_patent +2+6 MQ embl_patent +2+6 MR embl_patent +2+6 MS embl_patent 2+6 ?? unreserved_nuc # Specially handled type-general Dbtag names; commented out for now in @@ -494,67 +518,2161 @@ version 1 # of file format #gnl TRACE_CHGR general_nuc # SPECIAL CASES +# Mostly in the same order as baseline assignments, but embl_tpa_prot +# specials are at the very end because there are so many of them. To +# keep to a rough limit of 100 lines per prefix, resort to *_other_nuc +# for some heavily mixed ranges. + +# Some GenBank "TPA" 8-character protein accessions are really native. +special DAA00001 gb_prot +special DAA02110-DAA02116 gb_prot +special DAA34794-DAA34795 gb_prot + +# Nominally ddbj_est. +special C21595-C21827 ddbj_dirsub +special C22715-C22762 ddbj_dirsub +special C22783-C22911 ddbj_dirsub +special C24689-C24767 ddbj_dirsub +special C75685-C75936 ddbj_dirsub +special C95573-C95642 ddbj_dirsub +special C99933-C99976 ddbj_dirsub + +# Nominally ddbj_dirsub. Split out EST ranges, and give the benefit +# of the doubt to sequences that look like ddbj_con, ddbj_genome, +# ddbj_mrna, or ddbj_other_nuc. +special D00922 ddbj_est +special D11487-D12469 ddbj_est +special D15075-D17289 ddbj_other_nuc # 62 EST ranges +special D17812-D21053 ddbj_est +special D21355-D26768 ddbj_other_nuc # 118 EST ranges +special D26771-D28109 ddbj_est +special D28170-D28183 ddbj_est +special D28185-D28196 ddbj_est +special D28198 ddbj_est +special D28200 ddbj_est +special D28203 ddbj_est +special D28205-D28206 ddbj_est +special D28208-D28215 ddbj_est +special D28217-D28224 ddbj_est +special D28227 ddbj_est +special D28229 ddbj_est +special D28232 ddbj_est +special D28234 ddbj_est +special D28281-D28288 ddbj_est +special D28290-D28310 ddbj_est +special D28312-D28318 ddbj_est +special D28320-D28326 ddbj_est +special D28603-D28744 ddbj_est +special D29018-D29624 ddbj_est +special D29993-D30029 ddbj_est +special D30816-D31599 ddbj_est +special D32304-D32958 ddbj_est +special D32960-D33769 ddbj_est +special D33771-D34214 ddbj_est +special D34216-D34410 ddbj_est +special D34412-D34589 ddbj_est +special D34640-D35674 ddbj_est +special D35676-D36684 ddbj_est +special D36686-D42011 ddbj_other_nuc # 101 EST ranges +special D42187-D43617 ddbj_est +special D44612-D49352 ddbj_other_nuc # 70 EST ranges +special D50936-D60141 ddbj_other_nuc # 1208 EST ranges +special D60143-D61376 ddbj_est +special D61420-D61685 ddbj_est +special D61708-D62388 ddbj_est +special D62390-D63133 ddbj_est +special D63171-D63317 ddbj_est +special D63319-D63324 ddbj_est +special D63330 ddbj_est +special D63746-D63758 ddbj_est +special D64179-D65034 ddbj_est +special D65036-D65241 ddbj_est +special D65243-D65978 ddbj_est +special D65980-D66873 ddbj_est +special D67099-D68048 ddbj_est +special D68050-D68323 ddbj_est +special D68325-D68600 ddbj_est +special D68602-D69603 ddbj_est +special D69605-D70813 ddbj_est +special D70900-D76413 ddbj_other_nuc # 45 EST ranges +special D76447-D77996 ddbj_est +special D78209-D89649 ddbj_other_nuc # 91 EST ranges + +special F38006 embl_dirsub # Nominally embl_est. + +# Nominally gsdb_dirsub. Split out EST, GSS, and STS ranges, and +# give the benefit of the doubt to sequences that look like gb_cdna, +# gb_con, gb_genome, gsdb_dirsub, or gb_other_nuc. +special L00738-L00844 gb_sts +special L00846-L00850 gb_sts +special L00852-L00891 gb_sts +special L00893-L00916 gb_sts +special L00994-L01014 gb_sts +special L01996-L02021 gb_sts +special L02080-L02091 gb_sts +special L04198-L04215 gb_sts +special L07331-L07332 gb_sts +special L07863 gb_sts +special L08881-L15794 gb_other_nuc # 6 EST ranges and 23 STS ranges +special L17188-L17290 gb_sts +special L18193-L18255 gb_sts +special L18857-L18858 gb_est +special L19032-L19041 gb_est +special L19143-L19155 gb_est +special L19160 gb_est +special L19202-L19214 gb_est +special L20451-L20461 gb_est +special L23479-L23493 gb_sts +special L23992 gb_sts +special L23997 gb_sts +special L24693 gb_sts +special L24826 gb_sts +special L25137 gb_sts +special L25173-L25249 gb_est +special L25344-L25345 gb_est +special L25347 gb_est +special L25417-L25420 gb_est +special L25449-L25525 gb_est +special L25888 gb_sts +special L26606-L26848 gb_est +special L27444 gb_est +special L28178-L28418 gb_sts +special L28420-L28422 gb_sts +special L30148 gb_est +special L31430-L31437 gb_sts +special L31440-L31489 gb_sts +special L31968-L32015 gb_est +special L32028-L32065 gb_est +special L33494-L33675 gb_est +special L34798-L34802 gb_sts +special L34957-L35007 gb_est +special L35580-L35581 gb_sts +special L35773-L35843 gb_est +special L36534 gb_sts +special L37208-L37288 gb_sts +special L37453-L37515 gb_est +special L37607-L37659 gb_est +special L37974-L38013 gb_est +special L38026-L38243 gb_est +special L38525-L38543 gb_est +special L38741 gb_est +special L38750-L38760 gb_est +special L38763 gb_est +special L38774 gb_est +special L38787 gb_est +special L39872-L39873 gb_sts +special L40034 gb_sts +special L40040-L40041 gb_sts +special L40351-L40352 gb_sts +special L40420-L40424 gb_est +special L41967 gb_sts +special L43576-L43577 gb_est +special L43579-L43580 gb_est +special L44279-L44576 gb_est +special L46401-L46582 gb_est +special L46914-L47098 gb_est +special L47214-L47215 gb_sts +special L47542 gb_sts +special L47554-L47568 gb_sts +special L47842-L47965 gb_est +special L48016 gb_sts +special L48736-L48796 gb_gss +special L48818-L48873 gb_est +special L49057-L49120 gb_est +special L76101-L76131 gb_est +special L76151 gb_sts +special L77669-L77670 gb_sts +special L77674-L77683 gb_sts +special L77685-L77686 gb_sts +special L77689 gb_sts +special L77878-L77883 gb_sts +special L77993 gb_sts +special L81201-L81260 gb_est + +# Nominally gsdb_dirsub. Split out EST and STS ranges, and give the +# benefit of the doubt to sequences that look like gb_cdna, gb_con, +# gb_genome, gsdb_dirsub, or gb_other_nuc. +special M23606-M23610 gb_sts +special M61953-M62300 gb_est +special M75734-M75848 gb_est +special M75850-M75852 gb_est +special M75854-M75855 gb_est +special M75857 gb_est +special M75859-M75863 gb_est +special M75868-M75869 gb_est +special M75872 gb_est +special M75874 gb_est +special M75876-M75881 gb_est +special M75885 gb_est +special M75890 gb_est +special M75892-M75902 gb_est +special M75904-M75905 gb_est +special M75912 gb_est +special M75915 gb_est +special M75917-M75943 gb_est +special M75945-M75946 gb_est +special M75951 gb_est +special M75955 gb_est +special M75964-M75965 gb_est +special M75988 gb_est +special M76111-M76122 gb_est +special M77851-M79278 gb_est +special M79465-M80184 gb_est +special M80369-M80376 gb_sts +special M83631-M83639 gb_sts +special M84924-M84934 gb_sts +special M84943 gb_sts +special M85308-M86179 gb_est +special M88774-M89469 gb_est +special M91216-M91222 gb_est +special M91387-M91403 gb_est +special M91480-M91511 gb_est +special M92283-M92284 gb_est +special M92935 gb_est +special M94585-M94622 gb_sts +special M94635-M94643 gb_sts +special M94655-M94662 gb_sts +special M95212-M95280 gb_sts +special M95301-M95323 gb_sts +special M96605-M96621 gb_est +special M98979-M98996 gb_sts # Early N accessions were assigned haphazardly, and sometimes ambiguously. -# (These are all secondary accessions nowadays, though.) -special N00001-N00002 gb_embl -special N00003-N00004 gb_ddbj -special N00005 gb_embl_ddbj -special N00006-N00007 gb_ddbj -special N00008 gb_other_nuc -special N00009 gb_embl_ddbj -special N00010 gb_ddbj -special N00011 gb_embl -special N00012 gb_embl_ddbj -special N00013 gb_other_nuc -special N00014-N00017 gb_ddbj -special N00018-N00019 gb_other_nuc -special N00020 gb_embl_ddbj -special N00021 gb_ddbj -special N00022 gb_embl_ddbj -special N00023-N00024 gb_ddbj -special N00025 gb_embl_ddbj -special N00026 gb_ddbj -special N00027 gb_other_nuc -special N00028 ddbj_other_nuc -special N00029-N00034 gb_ddbj -special N00035 ddbj_other_nuc -special N00036 gb_ddbj -special N00037 ddbj_other_nuc -special N00038-N00040 gb_ddbj -special N00041 gb_other_nuc -special N00042-N00045 gb_ddbj -special N00046 gb_other_nuc -special N00047 gb_ddbj -special N00048 gb_other_nuc -special N00049-N00051 gb_ddbj -special N00052 gb_other_nuc -special N00053 ddbj_other_nuc -special N00054 gb_other_nuc -special N00055-N00056 gb_ddbj -special N00057 gb_embl -special N00058 gb_embl_ddbj -special N00059 gb_ddbj -special N00060 embl_other_nuc -special N00061-N00063 ddbj_other_nuc -special N00064 embl_other_nuc -special N00065-N00069 ddbj_other_nuc -special N00070 embl_ddbj -special N00078-N00079 ddbj_other_nuc -special N00083 ddbj_other_nuc -special N00088 ddbj_other_nuc -special N00090-N00094 ddbj_other_nuc -special N18624 gb_other_nuc -special N20000-N99999 gb_est +# (These are all secondary accessions nowadays, though.) "*" denotes what, +# if anything, N????? (and usually also N?????.1) immediately resolves to. +# Some unambiguous accessions don't resolve, and some ambiguous ones do. +special N00001 gb_embl # (L29187+L00109+L00110 / AH005313.2) / X04516.1 +special N00002 gb_embl_ddbj # M31027.1 / X04469.1 = D00002 +special N00003 gb_ddbj # L29169.1 / D00003.1 +special N00004 gb_ddbj # *L29170.1 / D00004.1 +special N00005 gb_embl_ddbj # L29171.1 / V01385.1 / D00005.1 +special N00006 gb_ddbj # (M31028.1 / AH002572.2) / D00006.1 +special N00007 gb_ddbj # (M31029.1 / AH002572.2) / D00007.1 +special N00008 gb_other_nuc # *L29172.1 +special N00009 gb_embl_ddbj # M13655.1 / *X00532.1 / D00009.1 (= M13655.1) +special N00010 gb_embl_ddbj # *L29174.1 / X04067.1 = D00010.1 +special N00011 gb_embl # *L29175.1 = V00749.1 +special N00012 gb_embl_ddbj # L29176.1 = V00751.1 / D00012.1 +special N00013 gb_other_nuc # L29177.1 / AH002712.2 +special N00014 gb_ddbj # (L29178.1 / AH005322.2) / D00014.1 +special N00015 gb_ddbj # (L29187.1 / AH005313.2) / D00015.1 +special N00016 gb_ddbj # (L29188.1 / AH005313.2) / D00016.1 +special N00017 gb_ddbj # *L29190.1 / (M14043 =) D00017.1 +special N00018 gb_other_nuc # *L29191.1 / AH002172.2; only unversioned +special N00019 gb_other_nuc # *L29197.1 +special N00020 gb_embl_ddbj # (L29198.1 / AH002320.2) / X03632.1 = D00020.1 +special N00021 gb_ddbj # (L29199.1 / AH002320.2) / D00021.1 +special N00022 gb_embl_ddbj # L29390.1 / V01168.1 / D00022.1 +special N00023 gb_ddbj # (L29391.1 / AH000963.2) / D00023.1 +special N00024 gb_ddbj # *L29392.1 / (M13071.1 =) D00024.1 +special N00025 gb_embl_ddbj # L29393.1 / X00626.1 / D00025.1 +special N00026 gb_ddbj # L29394.1 (= *X00442.1) / D00026.1 +special N00027 gb_other_nuc # *L29395.1 +special N00028 ddbj_other_nuc # D00028.1 +special N00029 gb_ddbj # *L29397.1 / D00029.1 +special N00030 gb_ddbj # M10126.1 / D00030.1 +special N00031 gb_ddbj # (*L29400.1 / AH002739.2) / D00031.1; unvers. +special N00032 gb_ddbj # (L?????.1 / AH??????.2) / D00032.1 +special N00033 gb_ddbj # (L29401.1 / AH002776.2) / D00033.1 +special N00034 gb_ddbj # (L29424.1 / AH001823.2) / D00034.1 +special N00035 ddbj_other_nuc # D00035.1 +special N00036 gb_ddbj # M31030.1 / D00036.1 +special N00037 ddbj_other_nuc # D00037.1 +special N00038 gb_ddbj # M31031.1 / D00038.1 +special N00039 gb_ddbj # *L29427.1 / D00039.1 +special N00040 gb_ddbj # L29428.1 / D00040.1 +special N00041 gb_other_nuc # L29429.1 / *M13756.1 (= D00041) +special N00042 gb_ddbj # (L29430.1 / AH002209.2) / (M13752 =) D00042.1 +special N00043 gb_ddbj # (L29431.1 / AH005585.2) / (M13753 =) D00043.1 +special N00044 gb_ddbj # L29432.1 / D00044.1 +special N00045 gb_other_nuc # (*L29433.1/AH002727.2); once also DDBJ? +special N00046 gb_other_nuc # *L29434.1 +special N00047 gb_ddbj # (*L29435.1 / AH002481.2) / D00047.1 +special N00048 gb_other_nuc # *L29436.1 +special N00049 gb_ddbj # M31032.1 / D00049.1 +special N00050 gb_ddbj # (L29399.1 / AH002739.2) / D00050.1 +special N00051 gb_ddbj # (L?????.1 / AH??????.2) / D00051.1 +special N00052 gb_other_nuc # L29472.1 / *M14909.1 (= D00052.1) +special N00053 ddbj_other_nuc # D00053.1 +special N00054 gb_other_nuc # M31033.1 +special N00055 gb_ddbj # (L?????.1 / AH??????.2) / D00055.1 +special N00056 gb_ddbj # L39908.1 / D00056.1 +special N00057 gb_embl # M31034.1 / X05532.1 +special N00058 gb_embl_ddbj # M31035.1 (= X05163.1) / (X05537.1 =) D00058.1 +special N00059 gb_ddbj # M22232.1 / (X05538.1 =) D00059.1 +special N00060 embl_other_nuc # X05541.1 (= D00060.1) +special N00061 ddbj_other_nuc # (X05531.1 =) D00061.1 +special N00062 ddbj_other_nuc # (X05530.1 =) D00062.1 +special N00063 ddbj_other_nuc # (X05529.1 =) D00063.1 +special N00064 embl_other_nuc # X05528.1 (= D00064.1 = D10030.1) +special N00065 ddbj_other_nuc # (X05527.1 =) D00065.1 = D10031.1 +special N00066 ddbj_other_nuc # D00066.1 +special N00067 ddbj_other_nuc # (M20207.1 =) D00067.1 +special N00068 ddbj_other_nuc # D00068.1 +special N00069 ddbj_other_nuc # D00069.1 +special N00070 embl_ddbj # X04036.1 = D00070.1 +special N00078 ddbj_other_nuc # D00078.1 +special N00079 ddbj_other_nuc # D00079.1 +special N00083 ddbj_other_nuc # D00083.1 +special N00088 ddbj_other_nuc # (M16550.1 =) D00088.1 = D10032.1 +special N00090 ddbj_other_nuc # (X05597.1 =) D00090.1 +special N00091 ddbj_other_nuc # (M15807.1 =) D00091.1 +special N00092 ddbj_other_nuc # D00092.1 +special N00093 ddbj_other_nuc # (M34437.1 = X04797.1 =) D00093.1 +special N00094 ddbj_other_nuc # (X05040.1 =) D00094.1 +special N18624 gb_other_nuc # *L29496.1 / M23263.1 +special N20001-N97317 gb_est +special N97318-N97531 gb_gss +special N97532-N99999 gb_est -# Some GenBank "TPA" 8-character protein accessions are really native. -special DAA00974-DAA00975 gb_prot -special DAA01471 gb_prot -special DAA01543 gb_prot -special DAA06450-DAA06453 gb_prot -special DAA06495 gb_prot -special DAA06633-DAA06636 gb_prot -special DAA12517-DAA33856 gb_prot +# Nominally gb_est. +special T02634-T02808 gb_gss +special T09496-T09993 gb_gss + +# Nominally gb_dirsub. +special U01537-U01551 gb_est +special U01921 gb_est +special U13686 gb_est +special U14111-U14114 gb_est +special U14171 gb_est +special U15041-U15047 gb_est +special U15988 gb_est +special U17154 gb_est +special U17513-U17564 gb_est +special U17582-U17584 gb_est +special U17905-U17909 gb_est +special U17976-U17977 gb_est +special U17999-U18008 gb_est +special U18010-U18017 gb_est +special U19036 gb_est +special U19135-U19141 gb_est +special U19502-U19510 gb_gss +special U19512-U19515 gb_est +special U19678-U19693 gb_est +special U19732 gb_est +special U19772 gb_est +special U19823 gb_est +special U21073-U21081 gb_est +special U21083-U21085 gb_est +special U21457-U21470 gb_est +special U21493-U21545 gb_gss +special U23049-U26690 gb_other_nuc # 21 EST ranges and 1 GSS range +special U27989-U31698 gb_other_nuc # 18 EST ranges and 1 GSS range +special U33921 gb_est +special U34233-U34244 gb_est +special U34396-U34400 gb_est +special U35429 gb_est +special U36594-U36596 gb_est +special U37151-U37164 gb_est +special U37229 gb_est +special U37231-U37234 gb_est +special U37588 gb_gss +special U37913-U37935 gb_est +special U37937-U38174 gb_est +special U39396 gb_est +special U39407-U39408 gb_est +special U39588-U39607 gb_est +special U40055 gb_est +special U40140-U40143 gb_est +special U40153 gb_est +special U40589 gb_est +special U40629 gb_est +special U41133-U41161 gb_est +special U41297 gb_est +special U42490-U42491 gb_est +special U42570-U42579 gb_est +special U42751 gb_est +special U43146 gb_est +special U44093-U44102 gb_est +special U44135-U44377 gb_est +special U44981-U44990 gb_est +special U46160-U53560 gb_other_nuc # 30 EST ranges and 5 GSS ranges +special U54592-U54607 gb_est +special U54706-U54733 gb_est +special U54735-U54739 gb_est +special U54779 gb_est +special U55034 gb_est +special U55777 gb_est +special U55962-U55991 gb_est +special U56653-U56660 gb_est +special U57844 gb_est +special U58051-U58082 gb_est +special U58979 gb_est +special U59417 gb_est +special U59419 gb_est +special U59755-U59756 gb_est +special U60299-U60311 gb_est +special U60606-U60638 gb_gss +special U60799 gb_est +special U61299-U61300 gb_gss +special U61522-U61525 gb_gss +special U62909 gb_est +special U63519 gb_est +special U63522-U63528 gb_est +special U64597 gb_est +special U64679 gb_est +special U64965-U64966 gb_est +special U65082 gb_est +special U65383-U65389 gb_est +special U65438-U65439 gb_est +special U65740 gb_est +special U65903-U65905 gb_gss +special U65917 gb_est +special U66210-U66213 gb_gss +special U66215 gb_gss +special U66423 gb_est +special U66576-U66577 gb_est +special U66693-U66697 gb_est +special U66718 gb_est +special U67850-U70383 gb_other_nuc # 13 EST ranges and 5 GSS ranges +special U72041-U95639 gb_other_nuc # 103 EST ranges, 35 GSS ranges, and 1 STS range +special U97486 gb_gss +special U97488 gb_gss +special U97490 gb_gss +special U97493 gb_gss + +# Nominally embl_dirsub. Give the benefit of the doubt to sequences +# that look like embl_con, embl_genome, or embl_other_nuc, but split +# out EST ranges. +special X61801-X61899 embl_est +special X62402 embl_est +special X65268-X65275 embl_est +special X65374-X65393 embl_est +special X71637-X71641 embl_est +special X71643-X71652 embl_est +special X73542-X73548 embl_est +special X73704-X73804 embl_est +special X76318 embl_est +special X76487 embl_est +special X78018-X78028 embl_est +special X82204 embl_est +special X83032-X83034 embl_est +special X83304-X83366 embl_est +special X84313 embl_est +special X84711-X84721 embl_est +special X85546-X85725 embl_est +special X86144-X86146 embl_est +special X86218-X86220 embl_est +special X87300-X87305 embl_est +special X89987-X89996 embl_est +special X90532-X90545 embl_est +special X91308-X91335 embl_est +special X91672-X91734 embl_est +special X92440 embl_est +special X92790-X92803 embl_est +special X93012-X93014 embl_est +special X93079 embl_est +special X93227-X93300 embl_est +special X93413-X93460 embl_est +special X93811-X93867 embl_est +special X93915-X93919 embl_est +special X93988-X93989 embl_est +special X94486-X94532 embl_est +special X95581 embl_est +special X95686 embl_est +special X96619-X96625 embl_est +special X97503-X97519 embl_est +special X97896-X97897 embl_est +special X98134-X98140 embl_est +special X98198-X98204 embl_est +special X98425-X98428 embl_est +special X98548-X98554 embl_est +special X99272 embl_est + +# Nominally embl_dirsub. Give the benefit of the doubt to sequences +# that look like embl_genome or embl_other_nuc, but split out EST +# ranges. +special Y07823 embl_est +special Y08464-Y08483 embl_est +special Y08705-Y08714 embl_est +special Y09139 embl_est +special Y09316-Y09320 embl_est +special Y09359-Y09364 embl_est +special Y09375-Y09377 embl_est +special Y09459-Y09464 embl_est +special Y09519-Y09523 embl_est +special Y09543-Y09545 embl_est +special Y09726-Y09732 embl_est +special Y09875 embl_est +special Y09981-Y09986 embl_est +special Y10008-Y10010 embl_est +special Y10037-Y10042 embl_est +special Y10056-Y10060 embl_est +special Y10217-Y10220 embl_est +special Y10671-Y10672 embl_est +special Y11191 embl_est +special Y11308 embl_est +special Y11615 embl_est +special Y14396-Y14402 embl_est +special Y16130-Y16131 embl_est +special Y16971-Y16974 embl_est +special Y18366 embl_est + +# Nominally embl_dirsub. Give the benefit of the doubt to sequences +# that look like embl_genome or embl_other_nuc, but split out EST +# ranges. +special Z12653-Z23155 embl_other_nuc # 69 EST ranges +special Z24464-Z24546 embl_est +special Z24760-Z24766 embl_est +special Z24769-Z25279 embl_est +special Z25283-Z25392 embl_est +special Z25400-Z25417 embl_est +special Z25486-Z25508 embl_est +special Z25510-Z25518 embl_est +special Z25546-Z25586 embl_est +special Z25588-Z25733 embl_est +special Z25776-Z25794 embl_est +special Z25799-Z25801 embl_est +special Z25805-Z25808 embl_est +special Z25825-Z25826 embl_est +special Z25832-Z25850 embl_est +special Z25889-Z26039 embl_est +special Z26045-Z26132 embl_est +special Z26184-Z26235 embl_est +special Z26237-Z26238 embl_est +special Z26243-Z26244 embl_est +special Z26323-Z26330 embl_est +special Z26342-Z26480 embl_est +special Z26495-Z26517 embl_est +special Z26525-Z26579 embl_est +special Z26658-Z26752 embl_est +special Z26754-Z26764 embl_est +special Z26772-Z26823 embl_est +special Z26868-Z26874 embl_est +special Z26952-Z26966 embl_est +special Z26971-Z27066 embl_est +special Z27095-Z27104 embl_est +special Z27240 embl_est +special Z27249-Z27303 embl_est +special Z28355-Z38124 embl_other_nuc # 84 EST ranges +special Z38136-Z46221 embl_est +special Z46243-Z46248 embl_est +special Z46291-Z46298 embl_est +special Z46428-Z46430 embl_est +special Z46510-Z46520 embl_est +special Z46526-Z46594 embl_est +special Z46677-Z46718 embl_est +special Z46813-Z46822 embl_est +special Z46830-Z46832 embl_est +special Z46974-Z46980 embl_est +special Z47057-Z47065 embl_est +special Z47278-Z47348 embl_est +special Z47350-Z47351 embl_est +special Z47382-Z47408 embl_est +special Z47575-Z47720 embl_est +special Z47801-Z47802 embl_est +special Z47985 embl_est +special Z48368-Z48427 embl_est +special Z48445-Z48448 embl_est +special Z48453-Z48467 embl_est +special Z48545-Z48560 embl_est +special Z48608-Z48611 embl_est +special Z48637 embl_est +special Z49229-Z49232 embl_est +special Z49744-Z49745 embl_est +special Z54295-Z54305 embl_est +special Z54309-Z54311 embl_est +special Z69578-Z69584 embl_est +special Z69945-Z69972 embl_est +special Z69974-Z69975 embl_est +special Z69983-Z69984 embl_est +special Z71789-Z71924 embl_est +special Z72392-Z72421 embl_est +special Z74621-Z74661 embl_est +special Z78280-Z78408 embl_est +special Z81149-Z81290 embl_est +special Z82016-Z82017 embl_est +special Z82913-Z82935 embl_est +special Z83019-Z83066 embl_est +special Z83980-Z84196 embl_est +special Z92674-Z92705 embl_est +special Z93025-Z93038 embl_est +special Z93725-Z93763 embl_est +special Z94848-Z94863 embl_est +special Z97038-Z97047 embl_est +special Z97731-Z97830 embl_est +special Z97862-Z97872 embl_est +special Z98057-Z98138 embl_est +special Z98443-Z98527 embl_est +special Z98764-Z98819 embl_est +special Z98821-Z98845 embl_est +special Z99067-Z99089 embl_est +special Z99348-Z99435 embl_est + +# Nominally ddbj_dirsub. +special AB001540-AB128048 ddbj_other_nuc # 197 EST ranges +special AB158145 ddbj_est +special AB158279-AB158287 ddbj_est +special AB158432 ddbj_est +special AB159214-AB159217 ddbj_est +special AB159736-AB159739 ddbj_est +special AB163429 ddbj_est +special AB163431 ddbj_est +special AB166724 ddbj_est +special AB178168-AB308274 ddbj_other_nuc # 80 EST ranges +special AB327169 ddbj_est +special AB331173-AB331192 ddbj_est +special AB331734-AB331746 ddbj_est +special AB331927-AB331949 ddbj_est +special AB334239 ddbj_est +special AB353143 ddbj_est +special AB354879 ddbj_est +special AB361047-AB361052 ddbj_est +special AB361241-AB361244 ddbj_est +special AB361292-AB361358 ddbj_est +special AB364678-AB364679 ddbj_est +special AB371430-AB371572 ddbj_est +special AB372866-AB372875 ddbj_est +special AB373997-AB374042 ddbj_est +special AB374263-AB374265 ddbj_est +special AB375019-AB375060 ddbj_est +special AB433981 ddbj_est +special AB434937-AB434950 ddbj_est +special AB437321-AB437344 ddbj_est +special AB446243-AB446391 ddbj_est +special AB447894-AB447981 ddbj_est +special AB448953-AB449020 ddbj_est +special AB450689-AB450761 ddbj_est +special AB458260-AB458300 ddbj_est +special AB458688-AB458789 ddbj_est +special AB461364-AB461372 ddbj_est +special AB471888-AB471891 ddbj_est +special AB474609-AB474619 ddbj_est +special AB474621-AB474714 ddbj_est +special AB474716-AB474721 ddbj_est +special AB474726-AB474739 ddbj_est +special AB474741-AB474748 ddbj_est +special AB480784-AB480824 ddbj_est +special AB485714-AB485715 ddbj_est +special AB485764-AB485770 ddbj_est +special AB485960-AB485992 ddbj_est +special AB492065-AB492083 ddbj_est +special AB505865-AB505873 ddbj_est +special AB509259 ddbj_est +special AB516772-AB516956 ddbj_est +special AB517053-AB517143 ddbj_est +special AB517145 ddbj_est +special AB529438-AB529445 ddbj_est +special AB535102-AB535104 ddbj_est +special AB537328-AB537329 ddbj_est +special AB542429-AB542450 ddbj_est +special AB552736-AB552841 ddbj_est +special AB553313-AB553315 ddbj_est +special AB568279-AB568290 ddbj_est +special AB571597-AB571602 ddbj_est +special AB572918-AB572921 ddbj_est +special AB573693-AB573709 ddbj_est +special AB575970-AB575978 ddbj_est +special AB576812-AB576850 ddbj_est +special AB585974-AB585996 ddbj_est +special AB594978-AB595127 ddbj_est +special AB602400-AB602424 ddbj_est +special AB613266 ddbj_est +special AB617526 ddbj_est +special AB626803 ddbj_est +special AB640724 ddbj_est +special AB646299-AB646300 ddbj_est +special AB646321-AB646345 ddbj_est +special AB668572-AB668577 ddbj_est +special AB669437-AB669464 ddbj_est +special AB709967-AB710073 ddbj_est +special AB734662-AB734675 ddbj_est +special AB738045-AB738062 ddbj_est +special AB742236-AB742251 ddbj_est +special AB757677-AB757705 ddbj_est +special AB811436 ddbj_est +special AB823195-AB823214 ddbj_est +special AB827265-AB827267 ddbj_est +special AB862603-AB862877 ddbj_est +special AB863290-AB863461 ddbj_est +special AB899003-AB899014 ddbj_est +special AB922020-AB922116 ddbj_est + +# Nominally gb_dirsub. +special AF000235-AF373213 gb_other_nuc # 585 EST ranges and 303 GSS ranges +special AF384864-AF384865 gb_gss +special AF387113-AF387121 gb_gss +special AF390017 gb_est +special AF390858 gb_est +special AF391795 gb_est +special AF391801-AF391804 gb_est +special AF391806-AF391807 gb_est +special AF396672 gb_gss +special AF396868 gb_est +special AF397194 gb_gss +special AF400792-AF400848 gb_gss +special AF401241-AF401271 gb_gss +special AF405213-AF405230 gb_est +special AF408415-AF408416 gb_est +special AF411092-AF411099 gb_est +special AF416103-AF416138 gb_gss +special AF420231 gb_est +special AF425300 gb_est +special AF435833-AF435837 gb_gss +special AF436075 gb_est +special AF439734 gb_est +special AF439736 gb_est +special AF439961-AF439972 gb_est +special AF440734 gb_gss +special AF441178-AF441182 gb_est +special AF441184-AF441187 gb_est +special AF441725 gb_gss +special AF441760-AF441769 gb_gss +special AF447921 gb_gss +special AF448511-AF448512 gb_est +special AF449707-AF449712 gb_gss +special AF451165-AF451181 gb_est +special AF451183-AF451189 gb_est +special AF453446 gb_est +special AF454762 gb_est +special AF455790-AF455802 gb_gss +special AF456411 gb_est +special AF461771 gb_est +special AF465471-AF465474 gb_gss +special AF468668-AF468672 gb_est +special AF469688-AF469692 gb_est +special AF472511 gb_gss +special AF486818-AF486819 gb_est +special AF487314-AF487325 gb_est +special AF487327-AF487329 gb_est +special AF492012-AF492014 gb_gss +special AF492272 gb_gss +special AF492356 gb_est +special AF494494-AF494495 gb_gss +special AF503187-AF503189 gb_est +special AF503588 gb_est +special AF506703-AF506706 gb_est +special AF507053 gb_est +special AF507058 gb_est +special AF507060 gb_est +special AF509571 gb_gss +special AF510188-AF510190 gb_est +special AF515664-AF515665 gb_gss +special AF516758-AF516766 gb_est +special AF520437-AF520439 gb_est +special AF520964 gb_est +special AF521604 gb_gss +special AF521978-AF522027 gb_est +special AF524047-AF524260 gb_gss +special AF524262-AF524826 gb_gss +special AF525702 gb_est +special AF525774-AF525775 gb_gss +special AF527684-AF527733 gb_est +special AF529172 gb_gss +special AF533598-AF533600 gb_est +special AF534530-AF534533 gb_gss +special AF537199-AF537202 gb_gss +special AF538926-AF538927 gb_est +special AF542503 gb_gss + +special AG266800-AG266855 ddbj_dirsub # Nominally ddbj_gss. + +# Nominally embl_dirsub. Give the benefit of the doubt to sequences +# that look like embl_genome or embl_other_nuc, but split out EST and +# GSS ranges. +special AJ003249-AJ013072 embl_other_nuc # 29 EST ranges +special AJ131530-AJ131531 embl_est +special AJ131534 embl_est +special AJ131640 embl_est +special AJ131743 embl_est +special AJ132447-AJ132453 embl_est +special AJ132743-AJ132744 embl_est +special AJ132746-AJ132747 embl_est +special AJ132768 embl_est +special AJ132770 embl_est +special AJ133279-AJ133310 embl_est +special AJ133423 embl_est +special AJ133627-AJ133630 embl_est +special AJ133823-AJ133832 embl_est +special AJ133887-AJ133891 embl_est +special AJ223808-AJ252067 embl_other_nuc # 37 EST ranges +special AJ269829-AJ320073 embl_other_nuc # 106 EST ranges +special AJ344568-AJ344620 embl_est +special AJ345961-AJ346853 embl_est +special AJ347704-AJ347708 embl_est +special AJ348845-AJ348907 embl_est +special AJ388667-AJ441054 embl_other_nuc # 46 EST ranges +special AJ441341-AJ456950 embl_est +special AJ457094-AJ457095 embl_est +special AJ457215-AJ457787 embl_est +special AJ457797-AJ457801 embl_est +special AJ457995-AJ458180 embl_est +special AJ459102-AJ459105 embl_est +special AJ460001-AJ486853 embl_est +special AJ487042-AJ519345 embl_other_nuc # 41 EST ranges +special AJ532915-AJ583526 embl_other_nuc # 46 EST ranges +special AJ601557-AJ646868 embl_other_nuc # 55 EST ranges +special AJ646897-AJ697608 embl_est +special AJ697763-AJ697764 embl_est +special AJ698954 embl_est +special AJ699509-AJ703791 embl_est +special AJ704820 embl_est +special AJ704866-AJ704927 embl_est +special AJ705105-AJ715323 embl_est +special AJ716425-AJ717291 embl_est +special AJ719195-AJ719266 embl_est +special AJ721139-AJ744704 embl_est +special AJ745200-AJ745660 embl_est +special AJ746228-AJ746232 embl_est +special AJ746346 embl_est +special AJ746581-AJ747913 embl_est +special AJ749659-AJ749668 embl_est +special AJ750001-AJ767053 embl_est +special AJ767069-AJ780913 embl_est +special AJ781008-AJ781024 embl_est +special AJ783757 embl_est +special AJ784436-AJ784774 embl_est +special AJ785005-AJ785280 embl_est +special AJ785296-AJ785566 embl_est +special AJ785755 embl_est +special AJ786842-AJ809161 embl_est +special AJ810177-AJ810178 embl_est +special AJ812737-AJ821279 embl_est +special AJ821281-AJ821793 embl_est +special AJ821924-AJ829440 embl_est +special AJ831476-AJ831483 embl_est +special AJ831580-AJ831586 embl_est +special AJ831846-AJ832104 embl_est +special AJ833020-AJ833569 embl_est +special AJ843898-AJ920257 embl_other_nuc # 63 EST ranges and 2 GSS ranges +special AJ920420-AJ936931 embl_est +special AJ937840-AJ937842 embl_est +special AJ937844-AJ937846 embl_est +special AJ937848-AJ937851 embl_est +special AJ937853-AJ937854 embl_est +special AJ937856 embl_est +special AJ938183-AJ964871 embl_est +special AJ966338 embl_est +special AJ966532-AJ966570 embl_est +special AJ967011-AJ967015 embl_est +special AJ968963-AJ968985 embl_est +special AJ970155-AJ970160 embl_est +special AJ972495-AJ972503 embl_est +special AJ973481-AJ973591 embl_est + +# Nominally embl_dirsub. Give the benefit of the doubt to sequences +# that look like embl_con, embl_genome, or embl_other_nuc, but split +# out EST and GSS ranges. +special AL022607-AL022715 embl_est +special AL022730-AL023086 embl_est +special AL023993-AL024449 embl_est +special AL024459-AL024460 embl_est +special AL033283-AL033374 embl_est +special AL034585-AL042364 embl_other_nuc # 182 EST ranges +special AL042366-AL043422 embl_est +special AL043424-AL049170 embl_other_nuc # 72 EST ranges +special AL079357-AL079851 embl_est +special AL079853-AL079877 embl_est +special AL079879-AL080030 embl_est +special AL080032-AL080055 embl_est +special AL110302-AL110468 embl_est +special AL117695-AL118492 embl_est +special AL118560-AL121566 embl_est +special AL132634 embl_est +special AL132645-AL132647 embl_est +special AL132695-AL132706 embl_est +special AL132781-AL132790 embl_est +special AL132802-AL132817 embl_est +special AL132829-AL132837 embl_est +special AL132910-AL132942 embl_est +special AL133667-AL135743 embl_est +special AL137939-AL138463 embl_est +special AL138519 embl_est +special AL157506-AL157686 embl_est +special AL160494-AL161251 embl_other_nuc # Fallback to placate older clients +special AL160494-AL161251 embl_gss +special AL162087-AL162101 embl_est +special AL163072-AL163135 embl_est +special AL163154 embl_est +special AL163196 embl_est +special AL163331-AL163480 embl_est +special AL163493-AL163504 embl_est +special AL163513-AL163522 embl_est +special AL163614-AL163635 embl_est +special AL163643 embl_est +special AL163692-AL163701 embl_est +special AL163712-AL163759 embl_est +special AL163761-AL163762 embl_est +special AL163773-AL163784 embl_est +special AL163892-AL163901 embl_est +special AL352973-AL352975 embl_est +special AL352994-AL353006 embl_est +special AL353958-AL353985 embl_est +special AL354617-AL354621 embl_est +special AL355193-AL355214 embl_est +special AL355755-AL355764 embl_est +special AL355890-AL355912 embl_est +special AL355914-AL355915 embl_est +special AL355917-AL355918 embl_est +special AL360374-AL365136 embl_est +special AL365523-AL389869 embl_est +special AL391923-AL391974 embl_est +special AL392063-AL392067 embl_est +special AL441606-AL441620 embl_est +special AL441622-AL441623 embl_est +special AL449467-AL449917 embl_est +special AL450491-AL450982 embl_est +special AL499630-AL500520 embl_est +special AL500542-AL512267 embl_est +special AL513551-AL540319 embl_other_nuc # 490 EST ranges +special AL540321-AL541353 embl_est +special AL541355-AL583950 embl_other_nuc # 393 EST ranges +special AL583964-AL589147 embl_est +special AL589204-AL589622 embl_est +special AL593862-AL596018 embl_other_nuc # 251 EST ranges +special AL596479-AL603622 embl_est +special AL627462-AL663681 embl_other_nuc # 3583 EST ranges +special AL663683-AL666314 embl_est +special AL666316-AL666416 embl_est +special AL666418-AL666705 embl_est +special AL666707-AL666821 embl_est +special AL666823-AL667261 embl_est +special AL667264-AL667371 embl_est +special AL667373-AL668474 embl_est +special AL668476-AL668875 embl_est +special AL668877-AL669016 embl_est +special AL669018-AL669138 embl_est +special AL669140-AL669810 embl_est +special AL669812 embl_est +special AL669890 embl_est +special AL669994-AL669997 embl_est +special AL671927-AL683797 embl_other_nuc # 1244 EST ranges +special AL691524-AL713628 embl_est +special AL713805-AL713837 embl_est +special AL714032-AL731499 embl_est +special AL731899-AL732289 embl_est +special AL732297-AL732307 embl_est +special AL749534-AL749539 embl_est +special AL749541-AL750301 embl_est +special AL750303-AL751363 embl_est +special AL773605-AL805894 embl_other_nuc # 3341 EST ranges +special AL808211-AL823461 embl_est +special AL824717-AL831324 embl_est +special AL834580-AL837504 embl_est +special AL837529-AL840622 embl_est +special AL840645-AL840932 embl_est +special AL841430-AL844138 embl_est +special AL844226-AL844479 embl_est +special AL845558-AL901606 embl_other_nuc # 5767 EST ranges +special AL901610-AL928536 embl_est +special AL929474-AL929490 embl_est +special AL929609-AL935024 embl_est +special AL935073-AL935113 embl_est +special AL954873-AL973407 embl_other_nuc # 638 EST ranges + +# Nominally embl_dirsub. +special AM003907-AM039430 embl_est +special AM041272-AM041897 embl_est +special AM041899-AM041928 embl_est +special AM042018-AM042538 embl_est +special AM042715-AM048613 embl_est +special AM049439-AM049915 embl_est +special AM051087-AM051089 embl_est +special AM051366-AM055585 embl_est +special AM056504-AM062638 embl_est +special AM062766-AM063038 embl_est +special AM063043-AM071350 embl_est +special AM071401-AM071405 embl_est +special AM071408 embl_est +special AM071410-AM071411 embl_est +special AM071520-AM072286 embl_est +special AM072430-AM072444 embl_est +special AM075249-AM075607 embl_est +special AM083343-AM083946 embl_est +special AM085154-AM085297 embl_est +special AM088777-AM109845 embl_est +special AM110258-AM110692 embl_est +special AM111128-AM111305 embl_est +special AM111350-AM111351 embl_est +special AM111376-AM113422 embl_est +special AM113870 embl_est +special AM115672-AM115694 embl_est +special AM117760-AM117779 embl_est +special AM137442-AM156757 embl_est +special AM157797-AM158083 embl_est +special AM159647-AM160600 embl_est +special AM161052-AM161090 embl_est +special AM161647-AM162203 embl_est +special AM165128-AM167516 embl_est +special AM168256-AM168269 embl_est +special AM168526-AM176418 embl_est +special AM177644-AM179408 embl_est +special AM180191-AM180250 embl_est +special AM184308-AM228715 embl_est +special AM229723-AM230448 embl_est +special AM231596-AM231607 embl_est +special AM231751-AM231752 embl_est +special AM232089-AM232226 embl_est +special AM233524 embl_est +special AM233688-AM233739 embl_est +special AM237575-AM237581 embl_est +special AM237631-AM237802 embl_est +special AM237808-AM237828 embl_est +special AM259062-AM259066 embl_est +special AM260753-AM260790 embl_est +special AM261635-AM261651 embl_est +special AM261893-AM261919 embl_est +special AM263561-AM265360 embl_est +special AM265378-AM265389 embl_est +special AM265633-AM265637 embl_est +special AM267321-AM267478 embl_est +special AM268883-AM268894 embl_est +special AM279675 embl_est +special AM283547-AM284142 embl_est +special AM285455-AM285649 embl_est +special AM286691 embl_est +special AM287291-AM291980 embl_est +special AM292305 embl_est +special AM292925-AM292926 embl_est +special AM293570-AM293588 embl_est +special AM293624 embl_est +special AM295342-AM295345 embl_est +special AM296550-AM384871 embl_est +special AM384993-AM422606 embl_other_nuc # 21 EST ranges +special AM493773-AM493867 embl_est +special AM495471-AM495722 embl_est +special AM496020-AM496068 embl_est +special AM496070-AM497466 embl_est +special AM498769-AM500636 embl_est +special AM500638 embl_est +special AM502267-AM502286 embl_est +special AM503942-AM503952 embl_est +special AM504150-AM600638 embl_est +special AM695771-AM696203 embl_est +special AM696311-AM696688 embl_est +special AM713476-AM743079 embl_est +special AM743198-AM748699 embl_other_nuc # 23 EST ranges +special AM750062-AM765799 embl_est +special AM766003-AM773228 embl_est +special AM774151 embl_est +special AM779939-AM849033 embl_est +special AM849823-AM850054 embl_est +special AM851127-AM882506 embl_est +special AM894321-AM950290 embl_other_nuc # 183 EST ranges +special AM950553-AM980446 embl_est +special AM981402-AM982512 embl_est +special AM982822-AM983454 embl_est +special AM983577-AM988621 embl_est +special AM991118-AM991127 embl_est +special AM992040-AM992047 embl_est +special AM992256-AM992457 embl_est + +# Nominally ddbj_est. +special AU024804-AU029241 ddbj_dirsub +special AU036596-AU036726 ddbj_gss +special AU046301-AU050022 ddbj_dirsub +special AU050808-AU050815 ddbj_dirsub +special AU062283-AU062350 ddbj_dirsub +special AU066497-AU066498 ddbj_dirsub +special AU066500 ddbj_dirsub +special AU066504 ddbj_dirsub +special AU066506 ddbj_dirsub +special AU066511-AU066512 ddbj_dirsub +special AU066514-AU066515 ddbj_dirsub +special AU066521-AU066524 ddbj_dirsub +special AU066527-AU066529 ddbj_dirsub +special AU066535 ddbj_dirsub +special AU066540-AU066542 ddbj_dirsub +special AU066544 ddbj_dirsub +special AU066546 ddbj_dirsub +special AU066548-AU066553 ddbj_dirsub +special AU066555 ddbj_dirsub +special AU066557-AU066558 ddbj_dirsub +special AU078429-AU078598 ddbj_dirsub +special AU090535 ddbj_dirsub +special AU279339 ddbj_dirsub +special AU279378 ddbj_dirsub + +special AX114121 embl_dirsub # Nominally embl_patent. + +# Nominally gb_dirsub. +special AY007260 gb_est +special AY026952-AY027433 gb_gss +special AY030235-AY030236 gb_est +special AY032615-AY032616 gb_est +special AY032902 gb_est +special AY032979 gb_est +special AY033289 gb_est +special AY038985-AY038987 gb_gss +special AY039709-AY039712 gb_gss +special AY042532 gb_est +special AY048753 gb_est +special AY055854 gb_gss +special AY063513 gb_est +special AY079522-AY080585 gb_gss +special AY093804-AY093817 gb_est +special AY096240 gb_est +special AY120880 gb_est +special AY123938 gb_gss +special AY125856-AY125890 gb_est +special AY127080-AY127557 gb_gss +special AY139011-AY139023 gb_est +special AY156078-AY156082 gb_gss +special AY160080-AY160082 gb_gss +special AY160682 gb_est +special AY166588 gb_est +special AY166650-AY166651 gb_gss +special AY168429-AY168439 gb_est +special AY174766-AY174778 gb_gss +special AY189691-AY189692 gb_est +special AY189695 gb_est +special AY196929-AY196933 gb_est +special AY198434-AY201593 gb_gss +special AY201595-AY201640 gb_gss +special AY201642-AY201691 gb_gss +special AY201693-AY203610 gb_gss +special AY243511 gb_est +special AY244458 gb_gss +special AY245441 gb_est +special AY265801-AY265804 gb_gss +special AY270178-AY270181 gb_gss +special AY282782-AY282785 gb_gss +special AY311391 gb_est +special AY321461-AY321462 gb_est +special AY325801-AY325802 gb_est +special AY326073 gb_est +special AY345126 gb_est +special AY347477 gb_est +special AY352272-AY352273 gb_gss +special AY356158-AY356311 gb_est +special AY357293-AY357295 gb_est +special AY366892-AY366899 gb_gss +special AY377860-AY377864 gb_est +special AY391730-AY391744 gb_gss +special AY395905 gb_est +special AY449735-AY449746 gb_est +special AY457064-AY457065 gb_est +special AY460108-AY460111 gb_est +special AY465830-AY465832 gb_est +special AY489065-AY489066 gb_gss +special AY491396-AY491398 gb_gss +special AY494600-AY494604 gb_est +special AY517518 gb_est +special AY518259-AY518264 gb_est +special AY547439-AY547457 gb_est +special AY553914 gb_est +special AY560545-AY560546 gb_est +special AY560548-AY560550 gb_est +special AY577286-AY577287 gb_est +special AY580990-AY580994 gb_gss +special AY583837 gb_gss +special AY589693-AY589694 gb_est +special AY589700-AY589701 gb_est +special AY589704 gb_est +special AY589708-AY589710 gb_est +special AY648006-AY648007 gb_gss +special AY651316 gb_est +special AY665687 gb_gss +special AY678444-AY678449 gb_est +special AY679774-AY679778 gb_est +special AY685649-AY685661 gb_gss +special AY686735-AY686747 gb_est +special AY688838-AY688840 gb_est +special AY714068-AY714071 gb_est +special AY736327 gb_est +special AY740678 gb_est +special AY750901-AY750904 gb_est +special AY758600-AY760022 gb_gss +special AY760098-AY760631 gb_gss +special AY760640-AY761013 gb_gss +special AY788904 gb_est +special AY796341 gb_est +special AY803125-AY803165 gb_est +special AY822675-AY822677 gb_gss +special AY831429 gb_est +special AY831657-AY831667 gb_gss +special AY838273-AY838277 gb_gss +special AY857201 gb_gss +special AY866420-AY866424 gb_gss +special AY870328 gb_gss +special AY872191-AY872255 gb_gss +special AY872390-AY873704 gb_gss +special AY879586-AY879591 gb_est +special AY885220-AY885221 gb_est +special AY898612 gb_gss +special AY922984-AY922988 gb_est +special AY928802-AY928805 gb_est +special AY952968-AY952970 gb_est +special AY966462-AY966485 gb_est +special AY987852 gb_est +special AY993980-AY993984 gb_gss +special AY994354-AY994356 gb_est + +# Nominally embl_dirsub. +special BX000562-BX000687 embl_est +special BX000710-BX000759 embl_est +special BX000976-BX000979 embl_est +special BX072585-BX088684 embl_other_nuc # 403 EST ranges +special BX088730-BX119313 embl_est +special BX119401-BX119900 embl_est +special BX248593 embl_est +special BX248783-BX248982 embl_est +special BX248986-BX249708 embl_est +special BX249763-BX251408 embl_est +special BX251414-BX255275 embl_est +special BX255279-BX255804 embl_est +special BX255991-BX279521 embl_other_nuc # 815 EST ranges +special BX279530-BX283066 embl_est +special BX283068-BX284108 embl_est +special BX294120-BX294121 embl_est +special BX294198-BX294232 embl_est +special BX295243-BX295348 embl_est +special BX295350-BX295358 embl_est +special BX295360-BX295378 embl_est +special BX295380-BX295516 embl_est +special BX295518 embl_est +special BX296570-BX318042 embl_other_nuc # 309 EST ranges +special BX318044-BX318558 embl_est +special BX318560-BX321855 embl_other_nuc # 42 EST ranges +special BX323813-BX465182 embl_other_nuc # 5821 EST ranges +special BX466087-BX466922 embl_est +special BX467129-BX469883 embl_est +special BX470269-BX510298 embl_est +special BX511045-BX511047 embl_est +special BX511314-BX511323 embl_est +special BX511333-BX526833 embl_est +special BX526835-BX530014 embl_est +special BX540327-BX540980 embl_other_nuc # 79 EST ranges +special BX548257-BX569683 embl_est +special BX601649-BX629297 embl_est +special BX629361-BX640397 embl_est +special BX641173-BX647061 embl_est +special BX663509 embl_est +special BX664722-BX677662 embl_other_nuc # 573 EST ranges +special BX677677-BX678768 embl_est +special BX678777-BX679656 embl_est +special BX679676-BX681414 embl_est +special BX681419-BX682226 embl_est +special BX682240-BX682527 embl_est +special BX682559-BX682952 embl_est +special BX682956-BX769172 embl_est +special BX769177-BX784021 embl_est +special BX784033 embl_est +special BX784044-BX784278 embl_est +special BX784281-BX784385 embl_est +special BX834112-BX841509 embl_est +special BX842705-BX861002 embl_other_nuc # 596 EST ranges +special BX861004-BX861521 embl_est +special BX861523-BX861681 embl_est +special BX861683-BX862186 embl_est +special BX862188-BX867356 embl_other_nuc # 51 EST ranges +special BX867358-BX867914 embl_est +special BX867916-BX872506 embl_other_nuc # 66 EST ranges +special BX872508-BX873028 embl_est +special BX873030-BX879623 embl_other_nuc # 76 EST ranges +special BX879625-BX880165 embl_est +special BX880167-BX889492 embl_other_nuc # 119 EST ranges +special BX889494-BX890135 embl_est +special BX890137-BX890188 embl_est +special BX890190-BX890198 embl_est +special BX890200-BX890202 embl_est +special BX890204-BX890224 embl_est +special BX890226-BX890232 embl_est +special BX890234-BX890308 embl_est +special BX890310-BX890394 embl_est +special BX890396-BX890483 embl_est +special BX890485-BX890537 embl_est +special BX897754-BX899178 embl_est +special BX899182-BX901874 embl_est +special BX908815-BX927274 embl_other_nuc # 343 EST ranges +special BX927416-BX928738 embl_est +special BX928759-BX929267 embl_est +special BX950875-BX957214 embl_est +special BX957366-BX957367 embl_est + +# Nominally gb_genome. +special CP000925 gb_dirsub +special CP002027 gb_dirsub +special CP006698 gb_dirsub +special CP010455-CP010456 gb_dirsub +special CP013186 gb_dirsub +special CP014940 gb_dirsub +special CP014992 gb_dirsub +special CP016816 gb_dirsub + +# Nominally embl_dirsub. Give the benefit of the doubt to sequences +# that look like embl_genome, but split out EST ranges. +special CR278161-CR293495 embl_est +special CR354614-CR394505 embl_other_nuc # 315 EST ranges +special CR407721-CR450243 embl_est +special CR450855-CR457481 embl_other_nuc # 307 EST ranges +special CR457485-CR477643 embl_est +special CR502047 embl_est +special CR513801-CR559927 embl_other_nuc # 134 EST ranges +special CR559947-CR589873 embl_est +special CR627501-CR628310 embl_est +special CR628421-CR631118 embl_est +special CR735161-CR749142 embl_est +special CR749881-CR751205 embl_est +special CR751241-CR751527 embl_est +special CR751621-CR752637 embl_est +special CR752662-CR752728 embl_est +special CR752730-CR752981 embl_est +special CR752983-CR753092 embl_est +special CR753094-CR753178 embl_est +special CR753180-CR753308 embl_est +special CR753310-CR753327 embl_est +special CR753329-CR753416 embl_est +special CR753418-CR753420 embl_est +special CR753422-CR753508 embl_est +special CR753510-CR753608 embl_est +special CR753610-CR753633 embl_est +special CR753635-CR753650 embl_est +special CR753652-CR753793 embl_est +special CR753795-CR753802 embl_est +special CR753804-CR753811 embl_est +special CR753907-CR759280 embl_est +special CR759282-CR759423 embl_est +special CR759425-CR759701 embl_est +special CR759703-CR759731 embl_est +special CR762499-CR764089 embl_est +special CR764098-CR767811 embl_est +special CR767822-CR769762 embl_est +special CR770518-CR774176 embl_est +special CR774201-CR775849 embl_est +special CR786583-CR788225 embl_est +special CR788341-CR790347 embl_est +special CR790390-CR792412 embl_est +special CR848861-CR857055 embl_other_nuc # 70 EST ranges +special CR926157 embl_est +special CR926498-CR926878 embl_est +special CR926880-CR926886 embl_est +special CR926888-CR926910 embl_est +special CR926912-CR927049 embl_est +special CR927051-CR927214 embl_est +special CR927216-CR927367 embl_est +special CR927369-CR927455 embl_est +special CR927457-CR927478 embl_est +special CR927480-CR927552 embl_est +special CR927554-CR931631 embl_est +special CR938765-CR940296 embl_est +special CR942245-CR942270 embl_est +special CR942275 embl_est +special CR942825-CR944659 embl_est +special CR974421 embl_est +special CR974599-CR999998 embl_est + +# Nominally embl_dirsub. +special CT000001-CT005229 embl_est +special CT009777-CT010161 embl_est +special CT010409-CT010425 embl_est +special CT025916-CT025917 embl_est +special CT485799-CT485989 embl_est +special CT563249-CT571240 embl_est +special CT571279-CT572707 embl_est +special CT574594-CT583622 embl_est +special CT583731-CT737118 embl_est +special CT737258 embl_est +special CT737431-CT762374 embl_other_nuc # 1381 EST ranges +special CT762376-CT762504 embl_est +special CT762507-CT766183 embl_other_nuc # 153 EST ranges +special CT766185-CT766353 embl_est +special CT766355-CT773818 embl_other_nuc # 322 EST ranges +special CT773820-CT773949 embl_est +special CT773951-CT774143 embl_est +special CT774146-CT774910 embl_other_nuc # 37 EST ranges +special CT774912-CT775059 embl_est +special CT775061-CT777270 embl_other_nuc # 84 EST ranges +special CT777272-CT777416 embl_est +special CT777418-CT780755 embl_other_nuc # 137 EST ranges +special CT780757-CT780877 embl_est +special CT780879-CT781911 embl_other_nuc # 39 EST ranges +special CT781913-CT782070 embl_est +special CT782072-CT782090 embl_est +special CT782092-CT782100 embl_est +special CT782102-CT782110 embl_est +special CT782112-CT782124 embl_est +special CT782126-CT782150 embl_est +special CT782152-CT782183 embl_est +special CT782185-CT782187 embl_est +special CT782189-CT782321 embl_est +special CT782323-CT786110 embl_other_nuc # 147 EST ranges +special CT786112-CT786237 embl_est +special CT786239-CT792224 embl_other_nuc # 219 EST ranges +special CT792226-CT792352 embl_est +special CT792354-CT793395 embl_other_nuc # 36 EST ranges +special CT793397-CT793519 embl_est +special CT793521-CT794722 embl_other_nuc # 48 EST ranges +special CT794724-CT794853 embl_est +special CT794855-CT823556 embl_other_nuc # 2036 EST ranges +special CT842009-CT842118 embl_est +special CT842120-CT842121 embl_est +special CT842123-CT842130 embl_est +special CT842132-CT842147 embl_est +special CT842149-CT842158 embl_est +special CT842160-CT842178 embl_est +special CT842180-CT842181 embl_est +special CT842183-CT842516 embl_est +special CT842518-CT842528 embl_est +special CT842530-CT842531 embl_est +special CT842533-CT842540 embl_est +special CT842542-CT863709 embl_est +special CT863715-CT863733 embl_est +special CT868744-CT928681 embl_est +special CT928683-CT938375 embl_est +special CT938377-CT940347 embl_other_nuc # 367 EST ranges +special CT943670-CT950687 embl_est +special CT962514-CT963069 embl_est +special CT963097-CT963104 embl_est +special CT971504-CT971571 embl_est +special CT978604 embl_est +special CT978606-CT978646 embl_est +special CT978648-CT978649 embl_est +special CT978651-CT978652 embl_est +special CT978654 embl_est +special CT978656-CT978677 embl_est +special CT978679 embl_est +special CT978681 embl_est +special CT978683 embl_est +special CT978685-CT978926 embl_est +special CT978928-CT978956 embl_est +special CT978958-CT989251 embl_est +special CT989258-CT990465 embl_est +special CT990474-CT990486 embl_est +special CT990490-CT990531 embl_est + +# Nominally embl_dirsub. +special CU062670-CU062842 embl_est +special CU062844-CU062846 embl_est +special CU062848-CU074269 embl_est +special CU074339-CU074382 embl_est +special CU074423-CU075311 embl_est +special CU075931-CU076039 embl_est +special CU234182-CU234194 embl_est +special CU302207 embl_est +special CU302209-CU302216 embl_est +special CU302324 embl_est +special CU306818-CU310069 embl_est +special CU310076-CU311182 embl_est +special CU367886-CU368379 embl_est +special CU368381-CU368441 embl_est +special CU368443-CU368521 embl_est +special CU368523-CU368526 embl_est +special CU368528-CU368600 embl_est +special CU368602-CU368745 embl_est +special CU368747-CU368750 embl_est +special CU368752-CU369046 embl_est +special CU369048-CU369187 embl_est +special CU369189-CU369553 embl_est +special CU369555-CU369565 embl_est +special CU369567-CU372896 embl_est +special CU372931-CU392058 embl_est +special CU394257-CU405559 embl_est +special CU415883-CU424422 embl_est +special CU424474 embl_est +special CU424496-CU442700 embl_est +special CU442764-CU457374 embl_est +special CU457503-CU487206 embl_other_nuc # 81 EST ranges and 1 GSS range +special CU487231-CU498825 embl_est +special CU498835-CU499386 embl_other_nuc # 43 EST ranges +special CU499388-CU524144 embl_est +special CU524146-CU524185 embl_est +special CU524187-CU524607 embl_est +special CU524609-CU524647 embl_est +special CU524649-CU525008 embl_est +special CU525010-CU525305 embl_est +special CU525307-CU525317 embl_est +special CU525319-CU525433 embl_est +special CU525435-CU525727 embl_est +special CU525729-CU525806 embl_est +special CU525808-CU525920 embl_est +special CU525922-CU530337 embl_est +special CU530421-CU538870 embl_est +special CU539140-CU550647 embl_est +special CU550735-CU565320 embl_est +special CU565322-CU596014 embl_other_nuc # 231 EST ranges +special CU596016-CU606845 embl_est +special CU607105-CU611033 embl_est +special CU611062-CU618304 embl_est +special CU618343-CU627974 embl_est +special CU628007-CU633156 embl_est +special CU637754-CU638663 embl_est +special CU639489-CU640365 embl_est +special CU640490-CU640880 embl_est +special CU651679-CU660012 embl_other_nuc # 41 EST ranges +special CU660014-CU672219 embl_est +special CU681473-CU681818 embl_est +special CU682012-CU682338 embl_est +special CU682367-CU682456 embl_est +special CU682458-CU682575 embl_est +special CU682577-CU682600 embl_est +special CU682602-CU682603 embl_est +special CU682605-CU682621 embl_est +special CU682623-CU682639 embl_est +special CU682641-CU682661 embl_est +special CU682663-CU682763 embl_est +special CU682765-CU682766 embl_est +special CU682768-CU682776 embl_est +special CU682778-CU682779 embl_est +special CU682781-CU682810 embl_est +special CU682812-CU683823 embl_est +special CU683828-CU683864 embl_est +special CU684056-CU686587 embl_est +special CU693503-CU694195 embl_est +special CU695349-CU740080 embl_est +special CU862081-CU896531 embl_est +special CU896700-CU905499 embl_est +special CU905513-CU914123 embl_est +special CU983906-CU984539 embl_est +special CU986307-CU993795 embl_est +special CU993823-CU999999 embl_est + +# Nominally ddbj_gss. +special DE990447-DE990894 ddbj_dirsub +special DE997363-DE998419 ddbj_dirsub + +# Nominally gb_dirsub. +special DQ000203-DQ000205 gb_est +special DQ003271-DQ003274 gb_est +special DQ005448-DQ005452 gb_est +special DQ006915-DQ006921 gb_est +special DQ008074-DQ008087 gb_est +special DQ009493 gb_est +special DQ010056 gb_est +special DQ023561-DQ023596 gb_est +special DQ054537 gb_est +special DQ056320-DQ056336 gb_est +special DQ062432 gb_est +special DQ068265-DQ068267 gb_est +special DQ071657-DQ071667 gb_est +special DQ072281-DQ072378 gb_gss +special DQ073526-DQ073530 gb_gss +special DQ079655-DQ079657 gb_est +special DQ082731 gb_est +special DQ090495-DQ090499 gb_est +special DQ092578-DQ092599 gb_gss +special DQ093275-DQ093284 gb_gss +special DQ103519-DQ103523 gb_gss +special DQ114785 gb_gss +special DQ115593-DQ115640 gb_gss +special DQ118389-DQ118393 gb_est +special DQ119294 gb_est +special DQ124861-DQ124867 gb_gss +special DQ131496 gb_gss +special DQ137423-DQ137425 gb_gss +special DQ138061-DQ138069 gb_est +special DQ156350-DQ156363 gb_gss +special DQ159946-DQ159947 gb_est +special DQ160233-DQ160240 gb_gss +special DQ172857-DQ172899 gb_est +special DQ176001-DQ176002 gb_gss +special DQ178992-DQ178994 gb_gss +special DQ190447-DQ190449 gb_est +special DQ205195-DQ205199 gb_est +special DQ207956 gb_est +special DQ211055-DQ211083 gb_est +special DQ211697 gb_est +special DQ217772 gb_est +special DQ219385-DQ219392 gb_gss +special DQ225105-DQ225107 gb_est +special DQ238007-DQ238010 gb_est +special DQ256365-DQ256368 gb_est +special DQ286755-DQ286759 gb_est +special DQ296475-DQ296480 gb_est +special DQ301872-DQ301876 gb_est +special DQ306698-DQ306705 gb_est +special DQ323032-DQ323035 gb_gss +special DQ329527-DQ329529 gb_gss +special DQ334866 gb_gss +special DQ341431-DQ341441 gb_est +special DQ349205-DQ349206 gb_est +special DQ351716-DQ351721 gb_gss +special DQ351838-DQ351840 gb_est +special DQ354361 gb_est +special DQ394888-DQ394890 gb_est +special DQ399337-DQ399338 gb_gss +special DQ530238 gb_gss +special DQ641039 gb_gss +special DQ672588 gb_est +special DQ821447-DQ821472 gb_est +special DQ822605-DQ822689 gb_est +special DQ858157-DQ858164 gb_est +special DQ866805 gb_gss +special DQ873299-DQ873317 gb_est +special DQ883824-DQ884159 gb_est +special DQ886384-DQ886389 gb_est +special DQ988883-DQ988928 gb_gss +special DQ999011-DQ999023 gb_est + +# Nominally gb_con. +special DS483562 gb_dirsub +special DS483659 gb_dirsub +special DS483744-DS484493 gb_other_nuc # 159 dirsub ranges +special DS484496-DS484515 gb_dirsub +special DS484518-DS484535 gb_dirsub +special DS484538-DS484550 gb_dirsub +special DS484552-DS484553 gb_dirsub +special DS484555-DS484574 gb_dirsub +special DS484576-DS484611 gb_dirsub +special DS484614-DS484623 gb_dirsub +special DS484625-DS484626 gb_dirsub +special DS484628-DS484633 gb_dirsub +special DS484635-DS484637 gb_dirsub +special DS484639 gb_dirsub +special DS484641-DS484654 gb_dirsub +special DS484656-DS484675 gb_dirsub +special DS484677-DS484686 gb_dirsub +special DS484688-DS484703 gb_dirsub +special DS484706-DS484707 gb_dirsub +special DS484709-DS484710 gb_dirsub +special DS484712-DS484716 gb_dirsub +special DS484718-DS484742 gb_dirsub +special DS484745-DS485146 gb_other_nuc # 80 dirsub ranges +special DS485148-DS485167 gb_dirsub +special DS485169 gb_dirsub +special DS485172-DS485174 gb_dirsub +special DS485176-DS485178 gb_dirsub +special DS485181-DS485182 gb_dirsub +special DS485184 gb_dirsub +special DS485186 gb_dirsub +special DS485189-DS485190 gb_dirsub +special DS485192 gb_dirsub +special DS485194-DS485195 gb_dirsub +special DS485198-DS485201 gb_dirsub +special DS485203-DS485205 gb_dirsub +special DS485208-DS485209 gb_dirsub +special DS485211 gb_dirsub +special DS485215-DS485216 gb_dirsub +special DS485218-DS485221 gb_dirsub +special DS485223-DS485230 gb_dirsub +special DS485233 gb_dirsub +special DS485235-DS485236 gb_dirsub +special DS485238-DS485240 gb_dirsub +special DS485242-DS485243 gb_dirsub +special DS485245-DS485247 gb_dirsub +special DS485249-DS485268 gb_dirsub +special DS485270-DS485271 gb_dirsub +special DS485273 gb_dirsub +special DS485275 gb_dirsub +special DS485277-DS485278 gb_dirsub +special DS485280-DS485281 gb_dirsub +special DS485283-DS485285 gb_dirsub +special DS485287-DS485288 gb_dirsub +special DS485290-DS485292 gb_dirsub +special DS485294 gb_dirsub +special DS485296-DS485306 gb_dirsub +special DS485309-DS485311 gb_dirsub +special DS485313-DS485316 gb_dirsub +special DS485318-DS485320 gb_dirsub +special DS485322-DS485326 gb_dirsub +special DS485328-DS485331 gb_dirsub +special DS485333-DS485343 gb_dirsub +special DS485345 gb_dirsub +special DS485349 gb_dirsub +special DS485351 gb_dirsub +special DS485353-DS485354 gb_dirsub +special DS485356-DS485365 gb_dirsub +special DS485368 gb_dirsub +special DS485370-DS485371 gb_dirsub +special DS485374-DS485376 gb_dirsub +special DS485378-DS485379 gb_dirsub +special DS485381-DS485390 gb_dirsub +special DS485392-DS485393 gb_dirsub +special DS485395 gb_dirsub +special DS485397-DS485401 gb_dirsub +special DS485403 gb_dirsub +special DS485407 gb_dirsub +special DS485409-DS485411 gb_dirsub +special DS485415-DS485416 gb_dirsub +special DS485418-DS485430 gb_dirsub +special DS485433-DS485434 gb_dirsub +special DS485436-DS485443 gb_dirsub +special DS485448 gb_dirsub +special DS485450-DS485454 gb_dirsub +special DS485456-DS485457 gb_dirsub +special DS485459-DS485462 gb_dirsub +special DS485464-DS485473 gb_dirsub +special DS485475-DS485478 gb_dirsub +special DS485481-DS485483 gb_dirsub +special DS485488 gb_dirsub +special DS485490-DS485492 gb_dirsub +special DS485494-DS485498 gb_dirsub +special DS485500-DS485501 gb_dirsub +special DS485503-DS485506 gb_dirsub +special DS485509 gb_dirsub +special DS485512 gb_dirsub +special DS485514-DS485515 gb_dirsub +special DS485517-DS485518 gb_dirsub +special DS485520-DS485523 gb_dirsub +special DS485525-DS485545 gb_dirsub +special DS485547-DS486008 gb_other_nuc # 95 dirsub ranges + +# Nominally gb_dirsub. +special EF053039-EF053049 gb_gss +special EF063001 gb_est +special EF095769 gb_gss +special EF165098 gb_gss +special EF182756-EF182758 gb_gss +special EF189906-EF189916 gb_est +special EF204530-EF204533 gb_gss +special EF208191 gb_gss +special EF210438-EF210453 gb_gss +special EF377525-EF377537 gb_est +special EF422869 gb_est +special EF473211-EF473215 gb_est +special EF494771-EF494773 gb_est +special EF552376 gb_est +special EF578434-EF578635 gb_gss +special EF592824-EF592944 gb_gss + +# Nominally gb_dirsub. +special EU152056-EU152079 gb_est +special EU239816 gb_est +special EU306364-EU306386 gb_gss +special EU364506-EU364507 gb_est +special EU368044 gb_est +special EU369669 gb_est +special EU420034 gb_est +special EU597223-EU597228 gb_est + +# Nominally gb_dirsub. +special FJ710154-FJ710155 gb_est +special FJ842632-FJ842642 gb_est + +# Nominally embl_dirsub. +special FM000001-FM160408 embl_est +special FM164769 embl_est +special FM164940 embl_est +special FM165392 embl_est +special FM165707-FM172746 embl_est +special FM178562-FM178778 embl_est +special FM180579-FM196445 embl_est +special FM205236-FM205493 embl_est +special FM205777-FM205831 embl_est +special FM207878-FM207900 embl_est +special FM208280-FM208711 embl_est +special FM208851 embl_est +special FM208900 embl_est +special FM212937 embl_est +special FM215048-FM242054 embl_est +special FM246886-FM251871 embl_est +special FM253361 embl_est +special FM253366-FM253368 embl_est +special FM253372 embl_est +special FM253378 embl_est +special FM864313-FM864344 embl_est +special FM864347-FM865295 embl_est +special FM868295-FM872275 embl_est +special FM879143-FM881767 embl_est +special FM882258-FM883162 embl_est +special FM885959-FM886821 embl_est +special FM887038-FM896881 embl_est +special FM897212-FM897213 embl_est +special FM897377-FM945301 embl_est +special FM945441-FM945999 embl_est +special FM946183-FM954971 embl_est +special FM957013-FM957079 embl_est +special FM958532-FM985957 embl_est +special FM992847-FM992850 embl_est +special FM999776-FM999787 embl_est + +# Nominally embl_dirsub. Give the benefit of the doubt to sequences +# that look like embl_genome, but split out EST ranges. +special FN000001-FN177896 embl_est +special FN179489-FN182188 embl_est +special FN182288-FN185725 embl_est +special FN186135-FN190445 embl_est +special FN190447-FN252183 embl_est +special FN252460-FN252789 embl_est +special FN263376-FN292969 embl_est +special FN377870-FN386264 embl_est +special FN393571-FN393732 embl_est +special FN393830-FN393849 embl_est +special FN424437-FN428571 embl_est +special FN430839-FN431219 embl_est +special FN431234-FN431660 embl_est +special FN432032-FN432041 embl_est +special FN432154-FN432328 embl_est +special FN432729-FN432775 embl_est +special FN433834-FN433837 embl_est +special FN435336-FN435350 embl_est +special FN539079-FN543092 embl_est +special FN551261-FN551733 embl_est +special FN552552-FN552591 embl_est +special FN552699-FN552705 embl_est +special FN555710-FN555987 embl_est +special FN557216-FN557223 embl_est +special FN561898-FN561924 embl_est +special FN562175-FN562396 embl_est +special FN564151-FN564158 embl_est +special FN565576-FN566839 embl_est +special FN588437-FN594512 embl_est +special FN600697 embl_est +special FN601407-FN610843 embl_est +special FN611035-FN640462 embl_est +special FN640581-FN641653 embl_est +special FN641925-FN643079 embl_est +special FN646764-FN647626 embl_est +special FN651825-FN651826 embl_est +special FN652903-FN652904 embl_est +special FN661971-FN662351 embl_est +special FN664012-FN665290 embl_est +special FN669777-FN673545 embl_est +special FN679295-FN686775 embl_est +special FN691927 embl_est +special FN692044-FN706436 embl_est +special FN706565-FN773062 embl_est +special FN773104-FN773170 embl_est +special FN796618-FN796723 embl_est +special FN796987-FN806772 embl_est +special FN806826-FN806848 embl_est +special FN811794-FN811851 embl_est +special FN811944-FN812314 embl_est +special FN813225-FN813226 embl_est +special FN813467-FN813469 embl_est +special FN814310-FN820203 embl_est +special FN822244-FN822743 embl_est +special FN823242-FN823254 embl_est +special FN868597 embl_est +special FN868902-FN868929 embl_est +special FN869177-FN869376 embl_est +special FN870962-FN907899 embl_est +special FN908254-FN908302 embl_est +special FN985040 embl_est +special FN985644-FN993914 embl_est +special FN997680-FN998838 embl_est +special FN999023-FN999906 embl_est + +# Nominally embl_dirsub. +special FO000003-FO076577 embl_est +special FO082887-FO117570 embl_est +special FO117633-FO181358 embl_est +special FO181544-FO203352 embl_est +special FO203528-FO393391 embl_est +special FO680693-FO681285 embl_est +special FO704924-FO722023 embl_est +special FO981374-FO999999 embl_est + +# Nominally embl_dirsub. +special FP000001-FP003579 embl_est +special FP003602-FP009753 embl_est +special FP009755-FP009758 embl_est +special FP009760-FP009761 embl_est +special FP009763-FP009764 embl_est +special FP009766-FP012228 embl_est +special FP024615-FP057328 embl_est +special FP057330-FP057370 embl_est +special FP057373-FP057454 embl_other_nuc # 33 EST ranges +special FP057456-FP057462 embl_est +special FP057465-FP057560 embl_other_nuc # 43 EST ranges +special FP057562-FP057566 embl_est +special FP057568-FP057656 embl_other_nuc # 39 EST ranges +special FP057664-FP057702 embl_other_nuc # 16 EST ranges +special FP057704-FP057709 embl_est +special FP057711-FP058036 embl_other_nuc # 141 EST ranges +special FP058042-FP058155 embl_other_nuc # 45 EST ranges +special FP058162-FP058163 embl_est +special FP058165 embl_est +special FP058167 embl_est +special FP058169 embl_est +special FP058171-FP058172 embl_est +special FP058174 embl_est +special FP058176-FP058177 embl_est +special FP058180 embl_est +special FP058183-FP058190 embl_est +special FP058192-FP058271 embl_other_nuc # 33 EST ranges +special FP058282 embl_est +special FP058284 embl_est +special FP058286 embl_est +special FP058293-FP058514 embl_other_nuc # 95 EST ranges +special FP058526-FP058527 embl_est +special FP058529 embl_est +special FP058531-FP058532 embl_est +special FP058534 embl_est +special FP058537 embl_est +special FP058539 embl_est +special FP058542-FP058543 embl_est +special FP058545 embl_est +special FP058547-FP058553 embl_est +special FP058556-FP058658 embl_other_nuc # 44 EST ranges +special FP058673-FP058706 embl_other_nuc # 15 EST ranges +special FP058708-FP058713 embl_est +special FP058715-FP059322 embl_other_nuc # 248 EST ranges +special FP059328 embl_est +special FP059330-FP059332 embl_est +special FP059334 embl_est +special FP059337 embl_est +special FP059339 embl_est +special FP059341 embl_est +special FP059343 embl_est +special FP059345 embl_est +special FP059348-FP059352 embl_est +special FP059354-FP059385 embl_other_nuc # 14 EST ranges +special FP059387-FP059393 embl_est +special FP059395-FP059833 embl_other_nuc # 187 EST ranges +special FP059841-FP059887 embl_other_nuc # 22 EST ranges +special FP059895-FP060210 embl_other_nuc # 136 EST ranges +special FP060212-FP060217 embl_est +special FP060219-FP060469 embl_other_nuc # 104 EST ranges +special FP060477-FP061762 embl_other_nuc # 552 EST ranges +special FP061764-FP061769 embl_est +special FP061771-FP062313 embl_other_nuc # 234 EST ranges +special FP062315-FP062321 embl_est +special FP062324-FP062896 embl_other_nuc # 246 EST ranges +special FP062906-FP062999 embl_other_nuc # 39 EST ranges +special FP063008-FP063034 embl_other_nuc # 11 EST ranges +special FP063036-FP063040 embl_est +special FP063043-FP063447 embl_other_nuc # 166 EST ranges +special FP063449-FP063453 embl_est +special FP063455-FP063802 embl_other_nuc # 154 EST ranges +special FP063804-FP063812 embl_est +special FP063814-FP063898 embl_other_nuc # 35 EST ranges +special FP063900-FP063904 embl_est +special FP063906-FP064076 embl_other_nuc # 74 EST ranges +special FP064082-FP064562 embl_other_nuc # 208 EST ranges +special FP064569-FP065157 embl_other_nuc # 251 EST ranges +special FP065159-FP067333 embl_est +special FP067453-FP074848 embl_est +special FP089705-FP089949 embl_est +special FP090914-FP091223 embl_est +special FP101920-FP101950 embl_est +special FP104570-FP236120 embl_est +special FP236870-FP243270 embl_est +special FP245546-FP312611 embl_est +special FP318637-FP325096 embl_est +special FP331359-FP339571 embl_est +special FP339630-FP340170 embl_est +special FP340462-FP340488 embl_est +special FP350355-FP360034 embl_est +special FP360036-FP458874 embl_est +special FP458876-FP475875 embl_est +special FP489021-FP539727 embl_est +special FP539730-FP565142 embl_est +special FP565937-FP578983 embl_est +special FP579010-FP583343 embl_est +special FP583356-FP628470 embl_est +special FP628472-FP671119 embl_est +special FP671140-FP680548 embl_est +special FP680607-FP690338 embl_est +special FP690350-FP700052 embl_est +special FP700189-FP710243 embl_est +special FP710258-FP791398 embl_est +special FP791400-FP884219 embl_est +special FP884235-FP885524 embl_est +special FP885545-FP885822 embl_est +special FP885927-FP893245 embl_est +special FP893247-FP924936 embl_est +special FP927985-FP928978 embl_est +special FP928990-FP928995 embl_est +special FP929145-FP999998 embl_est + +# Nominally embl_dirsub. +special FQ000001 embl_est +special FQ000005-FQ014216 embl_est +special FQ014236-FQ032656 embl_est +special FQ032836-FQ073829 embl_est +special FQ073967-FQ116746 embl_est +special FQ116748-FQ209379 embl_est +special FQ235350-FQ242479 embl_est +special FQ312199-FQ323093 embl_est +special FQ323164-FQ361146 embl_est +special FQ361149-FQ377486 embl_est +special FQ377488-FQ377516 embl_est +special FQ398062-FQ439981 embl_est +special FQ439983-FQ440019 embl_est +special FQ440021-FQ440022 embl_est +special FQ440024 embl_est +special FQ440026 embl_est +special FQ440028 embl_est +special FQ440030-FQ440032 embl_est +special FQ440034-FQ456868 embl_est +special FQ456875-FQ482045 embl_est +special FQ482048-FQ482071 embl_est +special FQ660554-FQ670147 embl_est +special FQ790408-FQ828345 embl_est +special FQ828348-FQ857191 embl_est +special FQ859091-FQ859175 embl_est +special FQ859187-FQ865452 embl_est +special FQ865457-FQ908260 embl_est +special FQ908267-FQ958209 embl_est +special FQ958213-FQ976554 embl_est +special FQ976923-FQ999999 embl_est + +# Nominally embl_dirsub. Give the benefit of the doubt to sequences +# that look like embl_con or embl_genome, but split out EST and TPA(!) +# ranges. +special FR595163-FR647444 embl_est +special FR660151-FR666602 embl_est +special FR668536 embl_est +special FR669245-FR669246 embl_est +special FR686584 embl_est +special FR686963-FR686965 embl_est +special FR688150-FR689535 embl_est +special FR691564 embl_est +special FR697056-FR714330 embl_est +special FR719326-FR719692 embl_est +special FR726163-FR726165 embl_est +special FR728240-FR728241 embl_est +special FR729927-FR731105 embl_est +special FR734011-FR734074 embl_tpa_nuc +special FR734407-FR744448 embl_est +special FR746042-FR746044 embl_est +special FR746111-FR747822 embl_est +special FR748230-FR749648 embl_est +special FR749997 embl_tpa_nuc +special FR753167-FR754317 embl_est +special FR754554-FR771822 embl_est +special FR773977 embl_est +special FR775966 embl_est +special FR819721-FR819744 embl_est +special FR821738-FR821754 embl_tpa_nuc +special FR822741 embl_tpa_nuc +special FR828827-FR831799 embl_est +special FR836483-FR837532 embl_est +special FR837542-FR837592 embl_est +special FR839767-FR845655 embl_est +special FR846456-FR846460 embl_est +special FR846537-FR846887 embl_est +special FR847124-FR847145 embl_est +special FR847228-FR847840 embl_est +special FR847888-FR847943 embl_est +special FR848368-FR848371 embl_est +special FR850135-FR850157 embl_est +special FR851958 embl_est +special FR852768 embl_est +special FR852894-FR852904 embl_est +special FR854398-FR856581 embl_est +special FR863689-FR864978 embl_est +special FR869720-FR869795 embl_est +special FR872817 embl_tpa_nuc +special FR873995-FR874005 embl_est +special FR877768-FR877777 embl_tpa_nuc +special FR877779-FR878008 embl_est +special FR878032-FR878040 embl_est + +special GQ162211-GQ162212 gb_est # Nominally gb_dirsub. + +# Nominally gb_dirsub. +special GU357827-GU357840 gb_est +special GU385812 gb_est + +# Nominally embl_dirsub. +special HE575663-HE575667 embl_est +special HE578177-HE578180 embl_est +special HE578289-HE578716 embl_est +special HE580226-HE580228 embl_est +special HE580237-HE580238 embl_tpa_nuc +special HE583424-HE583588 embl_tpa_nuc +special HE600073-HE600122 embl_est +special HE602495-HE602530 embl_est +special HE612182 embl_est +special HE613800 embl_tpa_nuc +special HE617969-HE646283 embl_est +special HE681861-HE681882 embl_est +special HE775617-HE792769 embl_est +special HE795538-HE795641 embl_est +special HE799315-HE799645 embl_est +special HE802076-HE802106 embl_est +special HE804769-HE804772 embl_tpa_nuc +special HE858615-HE859937 embl_est +special HE862417-HE862958 embl_est +special HE957083-HE961812 embl_est +special HE962539 embl_est +special HE963851-HE964756 embl_tpa_nuc +special HE967761 embl_tpa_nuc +special HE967924-HE967957 embl_est +special HE981808-HE983324 embl_est +special HE985332-HE993548 embl_est + +# Nominally embl_dirsub. Give the benefit of the doubt to sequences +# that look like embl_genome, but split out EST, TPA(!), and WGS ranges. +special HF546137-HF546200 embl_est +special HF546978 embl_est +special HF564658-HF564815 embl_tpa_nuc +special HF566097-HF566123 embl_est +special HF567775-HF567843 embl_est +special HF913790-HF920632 embl_wgs_nuc +special HF933207-HF933230 embl_tpa_nuc +special HF952730-HF952771 embl_est +special HF953988-HF954002 embl_est + +# Nominally embl_dirsub. Give the benefit of the doubt to sequences +# that look like embl_genome, but split out EST and TPA(!) ranges. +special HG000495-HG000664 embl_est +special HG001312-HG001319 embl_est +special HG313979-HG314002 embl_tpa_nuc +special HG314154-HG314951 embl_est +special HG322958-HG323812 embl_tpa_nuc +special HG326529-HG326598 embl_est +special HG328835-HG329089 embl_tpa_nuc +special HG421036-HG421067 embl_est +special HG424982-HG425075 embl_est +special HG425120-HG425123 embl_tpa_nuc +special HG426065-HG426183 embl_tpa_nuc +special HG491497-HG512884 embl_tpa_nuc +special HG516089-HG518058 embl_est +special HG518794-HG528968 embl_tpa_nuc +special HG531973-HG532008 embl_tpa_nuc +special HG780872-HG792014 embl_tpa_nuc +special HG792878-HG792996 embl_est +special HG798530-HG798533 embl_est +special HG931734-HG931849 embl_tpa_nuc +special HG964498-HG964527 embl_est +special HG965112-HG965128 embl_est +special HG970048-HG970064 embl_est +special HG975377-HG975438 embl_tpa_nuc +special HG977712-HG983278 embl_tpa_nuc +special HG983548-HG986399 embl_tpa_nuc + +special HM042681 gb_est # Nominally gb_dirsub. + +# Nominally gb_dirsub. +special HQ385980-HQ385998 gb_est +special HQ436350 gb_est +special HQ596498-HQ596504 gb_est +special HQ603829-HQ603854 gb_est +special HQ616895-HQ616912 gb_est +special HQ634394-HQ634477 gb_est + +special JN376805-JN377341 gb_est # Nominally gb_dirsub. + +special KF487514 gb_est # Nominally gb_dirsub. + +special KJ472321-KJ472336 gb_est # Nominally gb_dirsub. + +special KM673248-KM673271 gb_est # Nominally gb_dirsub. + +# Nominally embl_dirsub. +special LK000001-LK020668 embl_tpa_nuc +special LK937705-LK939125 embl_tpa_nuc +special LK985528-LK995307 embl_est + +# Nominally embl_dirsub. +special LM378690-LM383429 embl_tpa_nuc +special LM608092-LM611902 embl_tpa_nuc +special LM644135-LM644234 embl_tpa_nuc +special LM994684-LM994695 embl_est + +# Nominally embl_dirsub. Give the benefit of the doubt to sequences +# that look like embl_con, but split out EST and TPA(!) ranges. +special LN607841-LN608991 embl_tpa_nuc +special LN624403-LN624404 embl_est +special LN651082-LN651092 embl_est +special LN651553-LN678462 embl_est +special LN680257-LN680271 embl_est +special LN714474-LN714514 embl_tpa_nuc +special LN794245-LN794246 embl_tpa_nuc +special LN809256-LN809883 embl_tpa_nuc +special LN846618-LN846619 embl_tpa_nuc +special LN847449-LN848230 embl_tpa_nuc +special LN849001 embl_tpa_nuc +special LN871971-LN872940 embl_tpa_nuc +special LN874312-LN874522 embl_tpa_nuc +special LN879549-LN879837 embl_est +special LN898187-LN898198 embl_tpa_nuc +special LN901194-LN901210 embl_tpa_nuc +special LN901386-LN901412 embl_est + +# Nominally embl_dirsub. +special LT159851-LT159865 embl_est +special LT548096-LT548244 embl_tpa_nuc +special LT556286-LT558089 embl_est +special LT571433-LT571435 embl_tpa_nuc +special LT605004 embl_tpa_nuc +special LT631550-LT631670 embl_tpa_nuc +## Err on the side of caution on as yet unassigned IDs, and hope that +## there's not *too* much more backfilling. +#special LT828649-LT999999 unreserved_nuc # Some "EMBL" 8-character protein accessions are really third party # annotations. @@ -9704,6 +11822,9 @@ special SAI82294-SAI82296 embl_tpa_prot special SAI82298-SAI82303 embl_tpa_prot special SAQ69746-SAQ69766 embl_tpa_prot special SAQ71209 embl_tpa_prot +special SCC99881-SCC99885 embl_tpa_prot +special SFW93197-SFW93317 embl_tpa_prot +special SNU76807-SNU78093 embl_tpa_prot ## Err on the side of caution on as yet unassigned IDs, and hope that ## there's not *too* much more backfilling. -#special SEW57495-SZZ99999 unreserved_prot +#special SNZ31834-SZZ99999 unreserved_prot diff --git a/c++/src/objects/seqset/Bioseq_set.cpp b/c++/src/objects/seqset/Bioseq_set.cpp index d683eff3..742a683d 100644 --- a/c++/src/objects/seqset/Bioseq_set.cpp +++ b/c++/src/objects/seqset/Bioseq_set.cpp @@ -1,4 +1,4 @@ -/* $Id: Bioseq_set.cpp 519216 2016-11-14 16:06:08Z ivanov $ +/* $Id: Bioseq_set.cpp 518925 2016-11-09 14:19:55Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objects/seqset/CMakeLists.seqset.asn.txt b/c++/src/objects/seqset/CMakeLists.seqset.asn.txt new file mode 100644 index 00000000..0c0dc4af --- /dev/null +++ b/c++/src/objects/seqset/CMakeLists.seqset.asn.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/seqset/Makefile.seqset.lib +# + +set(MODULE seqset) +set(MODULE_IMPORT objects/general/general objects/ /biblio objects/medline/medline objects/seq/seq) +set(MODULE_PATH objects/seqset) + +set(MODULE_EXT "asn") +add_library(seqset ${MODULE}__ ${MODULE}___ gb_release_file) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(seqset + seq +) diff --git a/c++/src/objects/seqset/CMakeLists.txt b/c++/src/objects/seqset/CMakeLists.txt new file mode 100644 index 00000000..ea6a6ac1 --- /dev/null +++ b/c++/src/objects/seqset/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.seqset.asn.txt) + +# Recurse subdirectories +add_subdirectory(test ) diff --git a/c++/src/objects/seqset/Makefile.seqset.lib b/c++/src/objects/seqset/Makefile.seqset.lib index a5526312..7b44c907 100644 --- a/c++/src/objects/seqset/Makefile.seqset.lib +++ b/c++/src/objects/seqset/Makefile.seqset.lib @@ -1,6 +1,7 @@ LIB = seqset SRC = seqset__ seqset___ gb_release_file +DLL_LIB = $(SEQ_LIBS) USES_LIBRARIES = \ $(SEQ_LIBS) pub diff --git a/c++/src/objects/seqset/Seq_entry.cpp b/c++/src/objects/seqset/Seq_entry.cpp index 214eb225..65582fe0 100644 --- a/c++/src/objects/seqset/Seq_entry.cpp +++ b/c++/src/objects/seqset/Seq_entry.cpp @@ -1,4 +1,4 @@ -/* $Id: Seq_entry.cpp 434371 2014-05-07 13:05:31Z vasilche $ +/* $Id: Seq_entry.cpp 541340 2017-07-17 15:57:52Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -302,7 +302,9 @@ typedef pair TIdInsert; inline bool sx_CanReassign(CSeq_id::E_Choice type) { - return type == CSeq_id::e_Local || type == CSeq_id::e_General; + return type == CSeq_id::e_Local || type == CSeq_id::e_General || + type == CSeq_id::e_Ddbj || type == CSeq_id::e_Genbank || + type == CSeq_id::e_Embl || type == CSeq_id::e_Other; } @@ -320,6 +322,17 @@ CSeq_id_Handle sx_MakeUniqueId(const CSeq_id_Handle& idh, TIdMap& id_map) switch ( new_id->Which() ) { case CSeq_id::e_Local: obj_id = &new_id->SetLocal(); break; case CSeq_id::e_General: obj_id = &new_id->SetGeneral().SetTag(); break; + case CSeq_id::e_Ddbj: + case CSeq_id::e_Genbank: + case CSeq_id::e_Embl: + case CSeq_id::e_Other: + { + string lcl = new_id->AsFastaString(); + NStr::ReplaceInPlace(lcl, "|", "_"); + new_id->SetLocal().SetStr(lcl); + obj_id = &new_id->SetLocal(); + break; + } default: NCBI_THROW(CException, eUnknown, "CSeq_entry::ReassignConflictingIds: " @@ -517,7 +530,8 @@ void sx_ProcessId(const TIdMap& id_map, return; } CSeq_id_Handle idh = CSeq_id_Handle::GetHandle(id); - if ( !id_map.find(TIdKey(idh, null))->second ) { + auto id_it = id_map.find(TIdKey(idh, null)); + if ( id_it == id_map.end() || !id_it->second ) { // no mapping is necessary return; } diff --git a/c++/src/objects/seqsplit/CMakeLists.seqsplit.asn.txt b/c++/src/objects/seqsplit/CMakeLists.seqsplit.asn.txt new file mode 100644 index 00000000..aa798d2c --- /dev/null +++ b/c++/src/objects/seqsplit/CMakeLists.seqsplit.asn.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/seqsplit/Makefile.seqsplit.lib +# + +set(MODULE seqsplit) +set(MODULE_IMPORT objects/seqloc/seqloc objects/seqset/seqset objects/seq/seq objects/seqalign/seqalign objects/seqfeat/seqfeat) +set(MODULE_PATH objects/id2) + +set(MODULE_EXT "asn") +add_library(seqsplit ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(seqsplit + seqset +) diff --git a/c++/src/objects/seqsplit/CMakeLists.txt b/c++/src/objects/seqsplit/CMakeLists.txt new file mode 100644 index 00000000..c96fb9c2 --- /dev/null +++ b/c++/src/objects/seqsplit/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.seqsplit.asn.txt) + diff --git a/c++/src/objects/seqtest/CMakeLists.seqtest.asn.txt b/c++/src/objects/seqtest/CMakeLists.seqtest.asn.txt new file mode 100644 index 00000000..f35e71cd --- /dev/null +++ b/c++/src/objects/seqtest/CMakeLists.seqtest.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/seqtest/Makefile.seqtest.lib +# + +set(MODULE seqtest) +set(MODULE_IMPORT objects/general/general objects/seqloc/seqloc objects/seqalign/seqalign objects/seqfeat/seqfeat objects/seq/seq) +set(MODULE_PATH objects/seqtest) + +set(MODULE_EXT "asn") +add_library(seqtest ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(seqtest + seq +) \ No newline at end of file diff --git a/c++/src/objects/seqtest/CMakeLists.txt b/c++/src/objects/seqtest/CMakeLists.txt new file mode 100644 index 00000000..a0d89a8b --- /dev/null +++ b/c++/src/objects/seqtest/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.seqtest.asn.txt) + diff --git a/c++/src/objects/submit/CMakeLists.submit.asn.txt b/c++/src/objects/submit/CMakeLists.submit.asn.txt new file mode 100644 index 00000000..08498f3c --- /dev/null +++ b/c++/src/objects/submit/CMakeLists.submit.asn.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/submit/Makefile.submit.lib +# + +set(MODULE submit) +set(MODULE_IMPORT objects/general/general objects/biblio/biblio objects/seq/seq objects/seqset/seqset objects/seqloc/seqloc) +set(MODULE_PATH objects/submit) + +set(MODULE_EXT "asn") +add_library(submit ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(submit + seqset +) diff --git a/c++/src/objects/submit/CMakeLists.txt b/c++/src/objects/submit/CMakeLists.txt new file mode 100644 index 00000000..78375420 --- /dev/null +++ b/c++/src/objects/submit/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.submit.asn.txt) + diff --git a/c++/src/objects/taxon1/CMakeLists.taxon1.asn.txt b/c++/src/objects/taxon1/CMakeLists.taxon1.asn.txt new file mode 100644 index 00000000..1c403ced --- /dev/null +++ b/c++/src/objects/taxon1/CMakeLists.taxon1.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/taxon1/Makefile.taxon1.lib +# + +set(MODULE taxon1) +set(MODULE_IMPORT objects/seqfeat/seqfeat) +set(MODULE_PATH objects/taxon1) + +set(MODULE_EXT "asn") +add_library(taxon1 ${MODULE}__ ${MODULE}___ taxon1 cache utils ctreecont) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(taxon1 + seq xconnect +) \ No newline at end of file diff --git a/c++/src/objects/taxon1/CMakeLists.txt b/c++/src/objects/taxon1/CMakeLists.txt new file mode 100644 index 00000000..38a4c41e --- /dev/null +++ b/c++/src/objects/taxon1/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.taxon1.asn.txt) + diff --git a/c++/src/objects/taxon1/cache.cpp b/c++/src/objects/taxon1/cache.cpp index 0c9592dc..7805de2b 100644 --- a/c++/src/objects/taxon1/cache.cpp +++ b/c++/src/objects/taxon1/cache.cpp @@ -1,4 +1,4 @@ -/* $Id: cache.cpp 488663 2016-01-04 18:15:48Z domrach $ +/* $Id: cache.cpp 532449 2017-04-05 14:12:46Z domrach $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -94,8 +94,8 @@ COrgRefCache::Init( unsigned nCapacity ) if( nCapacity != 0 ) { m_nCacheCapacity = nCapacity; } - InitRanks(); - InitDivisions(); +// InitRanks(); +// InitDivisions(); return true; } @@ -166,8 +166,8 @@ COrgRefCache::LookupAndAdd( TTaxId tax_id, CTaxon1Node** ppData ) *ppData = pNode; return true; } else { // Internal: wrong respond type - m_host.SetLastError( "Unable to get node lineage:\ - Response type is not Taxalineage" ); + m_host.SetLastError( "Unable to get node lineage: " + "Response type is not Taxalineage" ); return false; } } @@ -176,28 +176,6 @@ COrgRefCache::LookupAndAdd( TTaxId tax_id, CTaxon1Node** ppData ) return false; } -bool -COrgRefCache::LookupAndInsert( TTaxId tax_id, CTaxon1_data** ppData ) -{ - CTaxon1Node* pNode = ( NULL ); - *ppData = NULL; - - if( LookupAndAdd( tax_id, &pNode ) && pNode ) { - SCacheEntry* pEntry = ( pNode->GetEntry() ); - if( !pEntry ) { - if( !Insert1( *pNode ) ) - return false; - pEntry = pNode->GetEntry(); - } else { - m_lCache.remove( pEntry ); - m_lCache.push_front( pEntry ); - } - *ppData = pEntry->GetData1(); - return true; - } - return false; -} - bool COrgRefCache::LookupAndInsert( TTaxId tax_id, CTaxon2_data** ppData ) { @@ -214,30 +192,12 @@ COrgRefCache::LookupAndInsert( TTaxId tax_id, CTaxon2_data** ppData ) m_lCache.remove( pEntry ); m_lCache.push_front( pEntry ); } - *ppData = pEntry->GetData2(); + *ppData = pEntry->GetData(); return true; } return false; } -bool -COrgRefCache::Lookup( TTaxId tax_id, CTaxon1_data** ppData ) -{ - if( (unsigned)tax_id < m_nMaxTaxId ) { - CTaxon1Node* pNode = ( m_ppEntries[tax_id] ); - SCacheEntry* pEntry; - if( pNode && (pEntry=pNode->GetEntry()) ) { - // Move in the list - m_lCache.remove( pEntry ); - m_lCache.push_front( pEntry ); - *ppData = pEntry->GetData1(); - return true; - } - } - *ppData = NULL; - return false; -} - bool COrgRefCache::Lookup( TTaxId tax_id, CTaxon2_data** ppData ) { @@ -248,7 +208,7 @@ COrgRefCache::Lookup( TTaxId tax_id, CTaxon2_data** ppData ) // Move in the list m_lCache.remove( pEntry ); m_lCache.push_front( pEntry ); - *ppData = pEntry->GetData2(); + *ppData = pEntry->GetData(); return true; } } @@ -257,690 +217,50 @@ COrgRefCache::Lookup( TTaxId tax_id, CTaxon2_data** ppData ) } bool -s_BuildLineage( string& str, CTaxon1Node* pNode, size_t sz, int sp_rank ) -{ - if( !pNode->IsRoot() ) { -// if( pNode->GetRank() > sp_rank-1 ) { -// s_BuildLineage( str, pNode->GetParent(), 0, sp_rank ); -// return false; -// } else { - if( pNode->IsGenBankHidden() ) { - return s_BuildLineage( str, pNode->GetParent(), sz, sp_rank ); - } - bool bCont; - bCont=s_BuildLineage( str, pNode->GetParent(), - sz+pNode->GetName().size()+2, sp_rank ); - if( bCont ) { - str.append( pNode->GetName() ); - if( sz != 0 ) { - str.append( "; " ); - } - } - return bCont; -// } - } else { - str.reserve( sz ); - } - return true; -} - -string::size_type -s_AfterPrefix( const string& str1, const string& prefix ) -{ - string::size_type pos(0), result(string::npos); - if( NStr::StartsWith( str1, prefix ) ) { - pos += prefix.size(); - if( pos < str1.size() ) { - result = str1.find_first_not_of( " \t\n\r", pos ); - if( result == pos ) { // fail in word-for-word comparison - result = string::npos; - } - } - } - return result; -} - -static const char s_achSubsp[] = "subsp."; -static const char s_achSsp[] = "ssp."; -static const char s_achF_Sp[] = "f. sp."; -static const char s_achFSp[] = "f.sp."; -static const char s_achStr[] = "str."; -static const char s_achSubstr[] = "substr."; -static const char s_achVar[] = "var."; -static const char s_achSv[] = "sv."; -static const char s_achCv[] = "cv."; -static const char s_achPv[] = "pv."; -static const char s_achBv[] = "bv."; -static const char s_achF[] = "f."; -static const char s_achFo[] = "fo."; -static const char s_achGrp[] = "grp."; - -struct SSubtypeAbbr { - const char* m_pchAbbr; - size_t m_nAbbrLen; - COrgMod::ESubtype m_eSubtype; -}; - - -static SSubtypeAbbr s_aSubtypes[] = { - { s_achSubsp, sizeof(s_achSubsp)-1, COrgMod::eSubtype_sub_species }, - { s_achSsp, sizeof(s_achSsp)-1, COrgMod::eSubtype_sub_species }, - { s_achF_Sp, sizeof(s_achF_Sp)-1, COrgMod::eSubtype_forma_specialis }, - { s_achFSp, sizeof(s_achFSp)-1, COrgMod::eSubtype_forma_specialis }, - { s_achStr, sizeof(s_achStr)-1, COrgMod::eSubtype_strain }, - { s_achSubstr,sizeof(s_achSubstr)-1,COrgMod::eSubtype_substrain }, - { s_achVar, sizeof(s_achVar)-1, COrgMod::eSubtype_variety }, - { s_achSv, sizeof(s_achSv)-1, COrgMod::eSubtype_serovar }, - { s_achCv, sizeof(s_achCv)-1, COrgMod::eSubtype_cultivar }, - { s_achPv, sizeof(s_achPv)-1, COrgMod::eSubtype_pathovar }, - { s_achBv, sizeof(s_achBv)-1, COrgMod::eSubtype_biovar }, - { s_achF, sizeof(s_achF)-1, COrgMod::eSubtype_forma }, - { s_achFo, sizeof(s_achFo)-1, COrgMod::eSubtype_forma }, - { s_achGrp, sizeof(s_achGrp)-1, COrgMod::eSubtype_group }, - { NULL, 0, COrgMod::eSubtype_other } -}; - -static int -s_NofTokens( const string& s ) -{ - int nof = 0; - char first, last, c; - int bracket_level, token; - - if( !s.empty() ) { - string::size_type pos = 0; - while( pos < s.size() ) { - bracket_level= 0; - token = 0; - - do { // Skip heading white space - first= s[pos++]; - } while( (isspace((unsigned char) first) || iscntrl((unsigned char) first)) && - pos < s.size() ); - - switch( first ) { - case '"': last= '"'; break; - case '(': last= ')'; break; - case '{': last= '}'; break; - case '[': last= ']'; break; - default: last= 0; break; - } - - for(; pos < s.size(); ++pos) { - c = s[pos]; - if( !isalnum((unsigned char) c) ) { - if( last != 0 ) { - if( first == c ) { - ++bracket_level; - } - if( last == c && (!bracket_level--) ) { - ++pos; - break; - } - } else { - if( c == '.' || isspace((unsigned char) c) || iscntrl((unsigned char) c) ) { - ++pos; - break; - } - } - } else { - token = 1; - } - } - nof += token; - } - } - return nof; -} - -COrgMod::ESubtype -COrgRefCache::GetSubtypeFromName( string& sName ) -{ - static const char* s_sSubspCf = " subsp. cf."; - static const char* s_sSubspAff = " subsp. aff."; - static const char* s_sCf = " cf."; - static const char* s_sAff = " aff."; - - string::size_type pos; - if( sName.find('.') == string::npos ) { - return COrgMod::eSubtype_other; - } - /* ignore subsp. cf. and subsp. aff. */ - if( NStr::FindNoCase( sName, s_sSubspCf ) != string::npos ) { - return COrgMod::eSubtype_other; - } - if( NStr::FindNoCase( sName, s_sSubspAff ) != string::npos ) { - return COrgMod::eSubtype_other; - } - /* ignore cf. and aff. */ - if( NStr::FindNoCase( sName, s_sCf ) != string::npos ) { - return COrgMod::eSubtype_other; - } - if( NStr::FindNoCase( sName, s_sAff ) != string::npos ) { - return COrgMod::eSubtype_other; - } - - /* check for subsp */ - SSubtypeAbbr* pSubtypeAbbr = &s_aSubtypes[0]; - while( pSubtypeAbbr->m_eSubtype != COrgMod::eSubtype_other ) { - if( (pos=NStr::FindNoCase( sName, - string(pSubtypeAbbr->m_pchAbbr, - pSubtypeAbbr->m_nAbbrLen) )) != NPOS ) { - if( pos == 0 || sName[pos-1] == ' ' || sName[pos-1] == '\t' ) { - sName.erase( pos, pSubtypeAbbr->m_nAbbrLen ); - sName = NStr::TruncateSpaces( sName, NStr::eTrunc_Begin ); - if( pSubtypeAbbr->m_eSubtype == COrgMod::eSubtype_sub_species - && s_NofTokens( sName ) != 1 ) { - break; // Return other - } - return pSubtypeAbbr->m_eSubtype; - } - } - ++pSubtypeAbbr; - } - return COrgMod::eSubtype_other; -} - -bool -COrgRefCache::BuildOrgModifier( CTaxon1Node* pNode, - COrgName& on, - CTaxon1Node* pParent ) -{ - CTaxon1Node* pTmp; - CRef pMod( new COrgMod ); - - if( !pParent && !pNode->IsRoot() ) { - pTmp = pNode->GetParent(); - while( !pTmp->IsRoot() ) { - int prank = pTmp->GetRank(); - if((prank == GetSubspeciesRank()) || - (prank == GetSpeciesRank()) || - (prank == GetGenusRank())) { - pParent = pTmp; - break; - } - pTmp = pTmp->GetParent(); - } - } - string::size_type pos = 0; - if( pParent ) { // Get rid of parent prefix - pos = s_AfterPrefix( pNode->GetName(), - pParent->GetName() ); - if( pos == string::npos ) { - return false; - } - } - pMod->SetSubname().assign( pNode->GetName(), pos, - pNode->GetName().size()-pos ); - - pMod->SetSubtype( GetSubtypeFromName( pMod->SetSubname() ) ); - - if( pMod->GetSubtype() == COrgMod_Base::eSubtype_sub_species && - (pNode->GetRank() != GetSubspeciesRank() || - s_NofTokens( pMod->GetSubname() ) != 1) ) { - pMod->SetSubtype( COrgMod_Base::eSubtype_other ); - } - if( pMod->GetSubtype() == COrgMod_Base::eSubtype_variety && - (pNode->GetRank() != GetVarietyRank() || - s_NofTokens( pMod->GetSubname() ) != 1) ) { - pMod->SetSubtype( COrgMod_Base::eSubtype_other ); - } - if( pMod->GetSubtype() == COrgMod_Base::eSubtype_forma && - (pNode->GetRank() != GetFormaRank() || - s_NofTokens( pMod->GetSubname() ) != 1) ) { - pMod->SetSubtype( COrgMod_Base::eSubtype_other ); - } - - if( pMod->GetSubtype() == COrgMod_Base::eSubtype_other ) { - int rank = pNode->GetRank(); - if( rank == GetSubspeciesRank() && - s_NofTokens( pNode->GetName() ) == 3 ) { - pMod->SetSubtype( COrgMod_Base::eSubtype_sub_species ); - } else { // Do not insert invalid modifier - return false; - } - } - // Store it into list - on.SetMod().push_back( pMod ); - - return true; -} - -bool -COrgRefCache::SetBinomialName( CTaxon1Node& node, COrgName& on ) -{ - CTaxon1Node* pSpec = ( NULL ); - CTaxon1Node* pSubspec = ( NULL ); - CTaxon1Node* pGenus = ( NULL ); - CTaxon1Node* pSubgen = ( NULL ); - CTaxon1Node* pNode = ( &node ); - string::size_type pos(0); - do { - int rank( pNode->GetRank() ); - if( rank == GetSubspeciesRank()) - pSubspec = pNode; - else if( rank == GetSpeciesRank()) - pSpec = pNode; - else if( rank == GetSubgenusRank()) - pSubgen = pNode; - else if(rank == GetGenusRank()) { - pGenus = pNode; - break; - } - pNode = pNode->GetParent(); - } while( pNode && !pNode->IsRoot() ); - pNode = &node; - - if( !pGenus ) { - if( !pSubgen ) - return false; - else - pGenus = pSubgen; - } - CBinomialOrgName& bon = ( on.SetName().SetBinomial() ); - - bon.SetGenus( pGenus->GetName() ); - - if( pSpec ) { // we have a species in lineage - pos = s_AfterPrefix( pSpec->GetName(), pGenus->GetName() ); - if( pos != string::npos ) { - bon.SetSpecies().assign( pSpec->GetName(), - pos, pSpec->GetName().size() - pos ); - } else { - bon.SetSpecies().assign( pSpec->GetName() ); - } - if( pSubspec ) { // we also have a subspecies in lineage - pos = s_AfterPrefix( pSubspec->GetName(), pSpec->GetName() ); - if( pos != string::npos ) { - bon.SetSubspecies().assign( pSubspec->GetName(), - pos, - pSubspec->GetName().size() - pos ); - } else { - bon.SetSubspecies().assign( pSubspec->GetName() ); - } - } - if( pNode != pSpec ) { - BuildOrgModifier( pNode, on ); - } - return true; - } - // no species in lineage - if( pSubspec ) { // we have no species but we have subspecies - pos = s_AfterPrefix( pSubspec->GetName(), pGenus->GetName() ); - if( pos != string::npos ) { - bon.SetSubspecies().assign( pSubspec->GetName(), - pos, - pSubspec->GetName().size() - pos ); - } else { - bon.SetSubspecies().assign( pSubspec->GetName() ); - } - BuildOrgModifier( pNode, on, - pNode==pSubspec ? pGenus : pSubspec ); - return true; - } - - // we have no species, no subspecies - // but we are under species level (varietas or forma) - BuildOrgModifier( pNode, on, pGenus ); - return true; -} - -bool -COrgRefCache::SetPartialName( CTaxon1Node& node, COrgName& on ) -{ - CTaxElement* pTaxElem = ( new CTaxElement ); - int rank_id= node.GetRank(); - - CPartialOrgName& pon = ( on.SetName().SetPartial() ); - pon.Set().push_back(CRef(pTaxElem)); - - if( rank_id == GetFamilyRank()) { - pTaxElem->SetFixed_level( CTaxElement_Base::eFixed_level_family ); - } - else if(rank_id == GetOrderRank()) { - pTaxElem->SetFixed_level( CTaxElement_Base::eFixed_level_order ); - } - else if(rank_id == GetClassRank()) { - pTaxElem->SetFixed_level( CTaxElement_Base::eFixed_level_class ); - } - else { - pTaxElem->SetFixed_level( CTaxElement_Base::eFixed_level_other ); - pTaxElem->SetLevel( GetRankName( rank_id ) ); - } - pTaxElem->SetName( node.GetName() ); - return true; -} - -bool -COrgRefCache::BuildOrgRef( CTaxon1Node& node, COrg_ref& org, bool& is_species ) +COrgRefCache::Insert2( CTaxon1Node& node ) { - // Init ranks here - if( !InitRanks() || !InitNameClasses() || !InitDivisions() ) - return false; - CTaxon1_req req; CTaxon1_resp resp; - req.SetGetorgnames( node.GetTaxId() ); + req.SetLookup().SetTaxId( node.GetTaxId() ); + // Set version db tag + COrgrefProp::SetOrgrefProp( req.SetLookup(), "version", 2 ); + if( m_host.m_bWithSynonyms ) { + COrgrefProp::SetOrgrefProp( req.SetLookup(), "syn", m_host.m_bWithSynonyms ); + } if( m_host.SendRequest( req, resp ) ) { - if( resp.IsGetorgnames() ) { + if( resp.IsLookup() ) { // Correct response, return object - list< CRef< CTaxon1_name > >& - lLin = ( resp.SetGetorgnames() ); - // Save taxname - org.SetTaxname().swap( lLin.front()->SetOname() ); - lLin.pop_front(); - - list< CRef< CTaxon1_name > >::iterator i; - // Find preferred common name - int pref_cls = GetPreferredCommonNameClass(); - for( i = lLin.begin(); i != lLin.end(); ++i ) { - if( (*i)->CanGetCde() && (*i)->GetCde() == pref_cls ) { - org.SetCommon().swap( (*i)->SetOname() ); - lLin.erase( i ); - break; - } - } - int syn_cls(GetSynonymNameClass()); - int comm_cls(GetCommonNameClass()); - for( i = lLin.begin(); i != lLin.end(); ++i ) { - if( (*i)->CanGetCde() ) { - int cls = (*i)->GetCde(); - if( cls == syn_cls || cls == comm_cls ) { - org.SetSyn().push_back( (*i)->GetOname() ); - } - } - } - // Set taxid as db tag - org.SetTaxId( node.GetTaxId() ); - - COrgName& on = ( org.SetOrgname() ); - - // Create name - bool bOrgnameRetreived = false; - CRef pProp( new CTaxon1_info() ); - pProp->SetIval1( node.GetTaxId() ); - pProp->SetIval2( -1 ); // Get string property by name - pProp->SetSval( "orgname" ); - CTaxon1_req req1; - CTaxon1_resp resp1; + struct SCacheEntry* pEntry = ( new SCacheEntry ); + pEntry->m_pTax2 = new CTaxon2_data(); + pEntry->m_pTreeNode = &node; - req1.SetGetorgprop( *pProp ); - try { - if( m_host.SendRequest( req1, resp1 ) ) { - if( resp1.IsGetorgprop() ) { - if( resp1.GetGetorgprop().size() > 0 ) { - CRef pInfo - = resp1.GetGetorgprop().front(); - if( pInfo->IsSetSval() && !pInfo->GetSval().empty() ) { - try { - CObjectIStreamAsn is( pInfo->GetSval().c_str(), - pInfo->GetSval().size(), eFNP_Allow ); - is >> on; - bOrgnameRetreived = true; - } catch( exception& e ) { - if( e.what() ) { - _TRACE( "Exception while parsing orgname property: " << e.what() ); - } - } - } - } - } - } - } catch( exception& /*e*/ ) { - } - // Fill some other orgname fields - short div_id( node.GetDivision() ); - if( GetDivisionCode( div_id ) ) { - on.SetDiv( GetDivisionCode( div_id ) ); - } - on.SetGcode( node.GetGC() ); - if( node.GetMGC() > 0 ) { - on.SetMgcode( node.GetMGC() ); - } - // Build lineage - CTaxon1Node* pNode; - if( !node.IsRoot() ) { - pNode = node.GetParent(); - on.SetLineage(kEmptyStr); - s_BuildLineage( on.SetLineage(), pNode, 0, - GetSpeciesRank() ); - if( on.GetLineage().empty() ) { - on.ResetLineage(); - } - } - // Set rank - int rank_id( node.GetRank() ); - - is_species = (rank_id >= GetSpeciesRank()); - // correct level by lineage if node has no rank - if( rank_id < 0 && !node.IsRoot() ) { - pNode = node.GetParent(); - while( !pNode->IsRoot() ) { - int rank( pNode->GetRank() ); - if(rank >= 0) { - is_species= (rank >= GetSpeciesRank()); - break; - } - pNode = pNode->GetParent(); - } - } - - if( !bOrgnameRetreived ) { // build orgname myself - if(is_species) { - /* we are on species level or below */ - - /* check for viruses */ - if( div_id == GetVirusesDivision() - || div_id == GetPhagesDivision() ) { - /* this is a virus */ - /* virus */ - if( rank_id == GetSpeciesRank() ) { - /* we are on species level */ - on.SetName().SetVirus( node.GetName() ); - } else { - /* we are below species */ - /* first try to find species or min rank which - below species but above us */ - pNode = 0; - CTaxon1Node* pTmp = ( node.GetParent() ); - - while( pTmp && !pTmp->IsRoot() ) { - int rank(pTmp->GetRank()); - if( rank >= GetSpeciesRank() ) { - pNode = pTmp; - if( rank == GetSpeciesRank() ) - break; - } else if( rank >= 0 ) - break; - pTmp = pTmp->GetParent(); - } - if( !pNode ) {// we have species or something above us - pNode = &node; - } - on.SetName().SetVirus( pNode->GetName() ); - // Add modifier to orgname - BuildOrgModifier( &node, on ); - } // non species rank - } else if( !SetBinomialName( node, on ) ) { - // name is not binomial: set partial - SetPartialName( node, on ); - } - } else { // above species - SetPartialName( node, on ); - } - } - // Add some genbank names as organism modifiers - if( org.IsSetOrgname() ) { // OrgName is not empty - for( i = lLin.begin(); i != lLin.end(); ++i ) { - if( (*i)->CanGetCde() ) { - int cde = (*i)->GetCde(); - COrgMod::ESubtype stype = (COrgMod::ESubtype)0; - if( cde == GetGBAcronymNameClass() ) { - stype = COrgMod::eSubtype_gb_acronym; - } else if( cde == GetGBSynonymNameClass() ) { - stype = COrgMod::eSubtype_gb_synonym; - } else if( cde == GetGBAnamorphNameClass() ) { - stype = COrgMod::eSubtype_gb_anamorph; - } - if( stype ) { - CRef pMod( new COrgMod ); - pMod->SetSubname().swap( (*i)->SetOname() ); - pMod->SetSubtype( stype ); - on.SetMod().push_back( pMod ); - } - } - } - } - - } else { - m_host.SetLastError - ("Unable to get orgref: Response is not Getorgnames"); - return false; - } - } else - return false; - - CRef pProp( new CTaxon1_info() ); - pProp->SetIval1( node.GetTaxId() ); - pProp->SetIval2( -2 ); // Get int property by name - pProp->SetSval( "pgcode" ); - - req.SetGetorgprop( *pProp ); - try { - if( m_host.SendRequest( req, resp ) ) { - if( resp.IsGetorgprop() ) { - if( resp.GetGetorgprop().size() > 0 ) { - CRef pInfo - = resp.GetGetorgprop().front(); - org.SetOrgname().SetPgcode( pInfo->GetIval2() ); - } + SerialAssign< COrg_ref >( pEntry->m_pTax2->SetOrg(), resp.GetLookup().GetOrg() ); + m_host.x_ConvertOrgrefProps( *pEntry->m_pTax2 ); + + // Remove last element from list + if( m_lCache.size() >= m_nCacheCapacity ) { + CTaxon1Node* pNode = m_lCache.back()->m_pTreeNode; + pNode->m_cacheEntry = NULL; + delete m_lCache.back(); + m_lCache.pop_back(); } - } - } catch( exception& /*e*/ ) { - } - return true; -} - -bool -COrgRefCache::Insert1( CTaxon1Node& node ) -{ - bool is_species( false ); - struct SCacheEntry* pEntry = ( new SCacheEntry ); - pEntry->m_pTax1 = new CTaxon1_data; - pEntry->m_pTax2 = NULL; - pEntry->m_pTreeNode = &node; - - COrg_ref& org = ( pEntry->m_pTax1->SetOrg() ); - - if( !BuildOrgRef( node, org, is_species ) ) { - delete pEntry; - return false; - } - // Set division code - if( GetDivisionCode(node.GetDivision()) ) { - pEntry->m_pTax1->SetDiv() - .assign( GetDivisionCode(node.GetDivision()) ); - } - // Set species level - pEntry->m_pTax1->SetIs_species_level( is_species ); - // Remove last element from list - if( m_lCache.size() >= m_nCacheCapacity ) { - CTaxon1Node* pNode = ( m_lCache.back()->m_pTreeNode ); - pNode->m_cacheEntry = NULL; - delete m_lCache.back(); - m_lCache.pop_back(); - } - node.m_cacheEntry = pEntry; - m_lCache.push_front( pEntry ); + node.m_cacheEntry = pEntry; + m_lCache.push_front( pEntry ); - return true; -} + return true; -bool -COrgRefCache::Insert2( CTaxon1Node& node ) -{ - bool is_species( false ); - struct SCacheEntry* pEntry = ( new SCacheEntry ); - pEntry->m_pTax1 = NULL; - pEntry->m_pTax2 = new CTaxon2_data; - pEntry->m_pTreeNode = &node; - - pEntry->m_pTax2->SetIs_uncultured( node.IsUncultured() ); - - COrg_ref& org = pEntry->m_pTax2->SetOrg(); - - if( !BuildOrgRef( node, org, is_species ) ) { - delete pEntry; - return false; - } - // Set blast names - CTaxon1Node* pNode = ( &node ); - while( !pNode->IsRoot() ) { - if( !pNode->GetBlastName().empty() ) { - pEntry->m_pTax2->SetBlast_name() - .push_back( pNode->GetBlastName() ); - } - pNode = pNode->GetParent(); - } - // Set species level - pEntry->m_pTax2->SetIs_species_level( is_species ); - // Remove last element from list - if( m_lCache.size() >= m_nCacheCapacity ) { - pNode = m_lCache.back()->m_pTreeNode; - pNode->m_cacheEntry = NULL; - delete m_lCache.back(); - m_lCache.pop_back(); - } - - node.m_cacheEntry = pEntry; - m_lCache.push_front( pEntry ); - - return true; -} - -CTaxon1_data* -COrgRefCache::SCacheEntry::GetData1() -{ - if( ! m_pTax1 ) { - m_pTax1 = new CTaxon1_data; - if( m_pTax2->IsSetOrg() ) { - m_pTax1->SetOrg( m_pTax2->SetOrg() ); - } - if( m_pTax2->GetOrg().GetOrgname().CanGetDiv() ) { - m_pTax1->SetDiv( m_pTax2->GetOrg().GetOrgname().GetDiv() ); - } else { - m_pTax1->SetDiv( kEmptyStr ); + } else { // Internal: wrong respond type + m_host.SetLastError( "Response type is not Lookup" ); } - m_pTax1->SetIs_species_level(m_pTax2->GetIs_species_level()); } - return m_pTax1; -} -CTaxon2_data* -COrgRefCache::SCacheEntry::GetData2() -{ - if( ! m_pTax2 ) { - m_pTax2 = new CTaxon2_data; - if( m_pTax1->IsSetOrg() ) { - m_pTax2->SetOrg( m_pTax1->SetOrg() ); - } - CTaxon1Node* pNode = ( m_pTreeNode ); - while( !pNode->IsRoot() ) { - if( !pNode->GetBlastName().empty() ) { - m_pTax2->SetBlast_name().push_back( pNode->GetBlastName() ); - } - pNode = pNode->GetParent(); - } - m_pTax2->SetIs_uncultured( m_pTreeNode->IsUncultured() ); - m_pTax2->SetIs_species_level(m_pTax1->GetIs_species_level()); - } - return m_pTax2; + return false; } -int +TTaxRank COrgRefCache::FindRankByName( const char* pchName ) { if( InitRanks() ) @@ -999,31 +319,11 @@ COrgRefCache::InitRanks() m_host.SetLastError( "Superkingdom rank was not found" ); return false; } - m_nFamilyRank = FindRankByName( "family" ); - if( m_nFamilyRank < -10 ) { - m_host.SetLastError( "Family rank was not found" ); - return false; - } - m_nOrderRank = FindRankByName( "order" ); - if( m_nOrderRank < -10 ) { - m_host.SetLastError( "Order rank was not found" ); - return false; - } - m_nClassRank = FindRankByName( "class" ); - if( m_nClassRank < -10 ) { - m_host.SetLastError( "Class rank was not found" ); - return false; - } m_nGenusRank = FindRankByName( "genus" ); if( m_nGenusRank < -10 ) { m_host.SetLastError( "Genus rank was not found" ); return false; } - m_nSubgenusRank = FindRankByName( "subgenus" ); - if( m_nSubgenusRank < -10 ) { - m_host.SetLastError( "Subgenus rank was not found" ); - return false; - } m_nSpeciesRank = FindRankByName( "species" ); if( m_nSpeciesRank < -10 ) { m_host.SetLastError( "Species rank was not found" ); @@ -1034,16 +334,6 @@ COrgRefCache::InitRanks() m_host.SetLastError( "Subspecies rank was not found" ); return false; } - m_nFormaRank = FindRankByName( "forma" ); - if( m_nFormaRank < -10 ) { - m_host.SetLastError( "Forma rank was not found" ); - return false; - } - m_nVarietyRank = FindRankByName( "varietas" ); - if( m_nVarietyRank < -10 ) { - m_host.SetLastError( "Variety rank was not found" ); - return false; - } } return true; } @@ -1059,7 +349,7 @@ COrgRefCache::GetNameClassName( short nc ) return NULL; } -short +TTaxNameClass COrgRefCache::FindNameClassByName( const char* pchName ) { if( !InitNameClasses() ) return -1; @@ -1109,32 +399,11 @@ COrgRefCache::InitNameClasses() m_host.SetLastError( "Common name class was not found" ); return false; } - m_ncSynonym = FindNameClassByName( "synonym" ); - if( m_ncSynonym < 0 ) { - m_host.SetLastError( "Synonym name class was not found" ); - return false; - } - - m_ncGBAcronym= FindNameClassByName("genbank acronym"); - if( m_ncGBAcronym < 0 ) { - m_host.SetLastError( "Genbank acrony name class was not found" ); - return false; - } - m_ncGBSynonym= FindNameClassByName("genbank synonym"); - if( m_ncGBSynonym < 0 ) { - m_host.SetLastError( "Genbank synonym name class was not found" ); - return false; - } - m_ncGBAnamorph= FindNameClassByName("genbank anamorph"); - if( m_ncGBAnamorph < 0 ) { - m_host.SetLastError( "Genbank anamorph name class was not found" ); - return false; - } } return true; } -short +TTaxDivision COrgRefCache::FindDivisionByCode( const char* pchCode ) { if( !InitDivisions() ) return -1; @@ -1204,21 +473,12 @@ COrgRefCache::InitDivisions() return false; } } - - if( (m_divViruses = FindDivisionByCode( "VRL" )) < 0 ) { - m_host.SetLastError( "Viruses division was not found" ); - return false; - } - if( (m_divPhages = FindDivisionByCode( "PHG" )) < 0 ) { - m_host.SetLastError( "Phages division was not found" ); - return false; - } } return true; } void -COrgRefCache::SetIndexEntry( TTaxId id, CTaxon1Node* pNode ) +COrgRefCache::SetIndexEntry( int id, CTaxon1Node* pNode ) { m_ppEntries[id] = pNode; } diff --git a/c++/src/objects/taxon1/cache.hpp b/c++/src/objects/taxon1/cache.hpp index 9fbe85a6..4bfbd5f3 100644 --- a/c++/src/objects/taxon1/cache.hpp +++ b/c++/src/objects/taxon1/cache.hpp @@ -1,7 +1,7 @@ #ifndef NCBI_TAXON1_CACHE_HPP #define NCBI_TAXON1_CACHE_HPP -/* $Id: cache.hpp 488663 2016-01-04 18:15:48Z domrach $ +/* $Id: cache.hpp 526973 2017-02-08 15:57:04Z domrach $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -57,60 +57,41 @@ public: bool Lookup( TTaxId tax_id, CTaxon1Node** ppNode ); bool LookupAndAdd( TTaxId tax_id, CTaxon1Node** ppData ); - bool LookupAndInsert( TTaxId tax_id, CTaxon1_data** ppData ); bool LookupAndInsert( TTaxId tax_id, CTaxon2_data** ppData ); - bool Lookup( TTaxId tax_id, CTaxon1_data** ppData ); bool Lookup( TTaxId tax_id, CTaxon2_data** ppData ); - bool Insert1( CTaxon1Node& node ); bool Insert2( CTaxon1Node& node ); // Rank stuff const char* GetRankName( int rank ); - int GetSuperkingdomRank() const { return m_nSuperkingdomRank; } - int GetFamilyRank() const { return m_nFamilyRank; } - int GetOrderRank() const { return m_nOrderRank; } - int GetClassRank() const { return m_nClassRank; } - int GetGenusRank() const { return m_nGenusRank; } - int GetSubgenusRank() const { return m_nSubgenusRank; } - int GetSpeciesRank() const { return m_nSpeciesRank; } - int GetSubspeciesRank() const { return m_nSubspeciesRank; } - int GetFormaRank() const { return m_nFormaRank; } - int GetVarietyRank() const { return m_nVarietyRank; } + TTaxRank GetSuperkingdomRank() const { return m_nSuperkingdomRank; } + TTaxRank GetGenusRank() const { return m_nGenusRank; } + TTaxRank GetSpeciesRank() const { return m_nSpeciesRank; } + TTaxRank GetSubspeciesRank() const { return m_nSubspeciesRank; } const char* GetNameClassName( short nc ); - short GetPreferredCommonNameClass() const { return m_ncPrefCommon; } - short GetCommonNameClass() const { return m_ncCommon; } - short GetSynonymNameClass() const { return m_ncSynonym; } - short GetGBAcronymNameClass() const { return m_ncGBAcronym; } - short GetGBSynonymNameClass() const { return m_ncGBSynonym; } - short GetGBAnamorphNameClass() const { return m_ncGBAnamorph; } - - const char* GetDivisionName( short div_id ); - const char* GetDivisionCode( short div_id ); - short GetVirusesDivision() const { return m_divViruses; } - short GetPhagesDivision() const { return m_divPhages; } + TTaxNameClass GetPreferredCommonNameClass() const { return m_ncPrefCommon; } + TTaxNameClass GetCommonNameClass() const { return m_ncCommon; } + + const char* GetDivisionName( TTaxDivision div_id ); + const char* GetDivisionCode( TTaxDivision div_id ); CTreeCont& GetTree() { return m_tPartTree; } const CTreeCont& GetTree() const { return m_tPartTree; } void SetIndexEntry( TTaxId id, CTaxon1Node* pNode ); - COrgMod::ESubtype GetSubtypeFromName( string& sName ); - private: friend class CTaxon1Node; friend class CTaxon1; struct SCacheEntry { friend class CTaxon1Node; - CRef< CTaxon1_data > m_pTax1; CRef< CTaxon2_data > m_pTax2; CTaxon1Node* m_pTreeNode; - CTaxon1_data* GetData1(); - CTaxon2_data* GetData2(); + CTaxon2_data* GetData() { return m_pTax2.GetPointer(); } }; CTaxon1& m_host; @@ -122,63 +103,44 @@ private: unsigned m_nCacheCapacity; // Max number of elements in cache list m_lCache; // LRU list - bool BuildOrgRef( CTaxon1Node& node, COrg_ref& org, - bool& is_species ); - bool BuildOrgModifier( CTaxon1Node* pNode, - COrgName& on, - CTaxon1Node* pParent = NULL ); - bool SetBinomialName( CTaxon1Node& node, COrgName& on ); - bool SetPartialName( CTaxon1Node& node, COrgName& on ); // Rank stuff - int m_nSuperkingdomRank; - int m_nFamilyRank; - int m_nOrderRank; - int m_nClassRank; - int m_nGenusRank; - int m_nSubgenusRank; - int m_nSpeciesRank; - int m_nSubspeciesRank; - int m_nFormaRank; - int m_nVarietyRank; - - typedef map TRankMap; + TTaxRank m_nSuperkingdomRank; + TTaxRank m_nGenusRank; + TTaxRank m_nSpeciesRank; + TTaxRank m_nSubspeciesRank; + + typedef map TRankMap; typedef TRankMap::const_iterator TRankMapCI; typedef TRankMap::iterator TRankMapI; TRankMap m_rankStorage; - bool InitRanks(); - int FindRankByName( const char* pchName ); + bool InitRanks(); + TTaxRank FindRankByName( const char* pchName ); // Name classes stuff - short m_ncPrefCommon; // now called "genbank common name" - short m_ncCommon; - short m_ncSynonym; - short m_ncGBAcronym; - short m_ncGBSynonym; - short m_ncGBAnamorph; - - typedef map TNameClassMap; + TTaxNameClass m_ncPrefCommon; // now called "genbank common name" + TTaxNameClass m_ncCommon; + + typedef map TNameClassMap; typedef TNameClassMap::const_iterator TNameClassMapCI; typedef TNameClassMap::iterator TNameClassMapI; TNameClassMap m_ncStorage; - bool InitNameClasses(); - short FindNameClassByName( const char* pchName ); + bool InitNameClasses(); + TTaxNameClass FindNameClassByName( const char* pchName ); // Division stuff - short m_divViruses; - short m_divPhages; struct SDivision { string m_sCode; string m_sName; }; - typedef map TDivisionMap; + typedef map TDivisionMap; typedef TDivisionMap::const_iterator TDivisionMapCI; typedef TDivisionMap::iterator TDivisionMapI; TDivisionMap m_divStorage; - bool InitDivisions(); - short FindDivisionByCode( const char* pchCode ); + bool InitDivisions(); + TTaxDivision FindDivisionByCode( const char* pchCode ); // forbidden COrgRefCache(const COrgRefCache&); @@ -196,31 +158,31 @@ public: virtual ~CTaxon1Node() {} virtual TTaxId GetTaxId() const { return m_ref->GetTaxid(); } - virtual const string& GetName() const { return m_ref->GetOname(); } - virtual const string& GetBlastName() const + virtual const string& GetName() const { return m_ref->GetOname(); } + virtual const string& GetBlastName() const { return m_ref->CanGetUname() ? m_ref->GetUname() : kEmptyStr; } - virtual short GetRank() const; - virtual short GetDivision() const; - virtual short GetGC() const; - virtual short GetMGC() const; + virtual TTaxRank GetRank() const; + virtual TTaxDivision GetDivision() const; + virtual TTaxGeneticCode GetGC() const; + virtual TTaxGeneticCode GetMGC() const; - virtual bool IsUncultured() const; - virtual bool IsGenBankHidden() const; + virtual bool IsUncultured() const; + virtual bool IsGenBankHidden() const; - virtual bool IsRoot() const + virtual bool IsRoot() const { return CTreeContNodeBase::IsRoot(); } COrgRefCache::SCacheEntry* GetEntry() { return m_cacheEntry; } - bool IsJoinTerminal() const + bool IsJoinTerminal() const { return m_flags&mJoinTerm ? true : false; } - void SetJoinTerminal() { m_flags |= mJoinTerm; } - bool IsSubtreeLoaded() const + void SetJoinTerminal() { m_flags |= mJoinTerm; } + bool IsSubtreeLoaded() const { return m_flags&mSubtreeLoaded ? true : false; } - void SetSubtreeLoaded( bool b ) + void SetSubtreeLoaded( bool b ) { if( b ) m_flags |= mSubtreeLoaded; else m_flags &= ~mSubtreeLoaded; } - CTaxon1Node* GetParent() + CTaxon1Node* GetParent() { return static_cast(Parent()); } private: friend class COrgRefCache; @@ -352,6 +314,26 @@ protected: virtual bool IsVisible( const CTreeContNodeBase* p ) const; }; +// Orgref "properties" +class COrgrefProp { +public: + static bool HasOrgrefProp( const ncbi::objects::COrg_ref& org, const std::string& prop_name ); + static const std::string& GetOrgrefProp( const ncbi::objects::COrg_ref& org, const std::string& prop_name ); + // returns default value false if not found + static bool GetOrgrefPropBool( const ncbi::objects::COrg_ref& org, const std::string& prop_name ); + // returns default value 0 if not found + static int GetOrgrefPropInt( const ncbi::objects::COrg_ref& org, const std::string& prop_name ); + + static void SetOrgrefProp( ncbi::objects::COrg_ref& org, const std::string& prop_name, + const std::string& prop_val ); + static void SetOrgrefProp( ncbi::objects::COrg_ref& org, const std::string& prop_name, + int prop_val ); + static void SetOrgrefProp( ncbi::objects::COrg_ref& org, const std::string& prop_name, + bool prop_val ); + + static void RemoveOrgrefProp( ncbi::objects::COrg_ref& org, const std::string& prop_name ); +}; + END_objects_SCOPE END_NCBI_SCOPE diff --git a/c++/src/objects/taxon1/taxon1.asn b/c++/src/objects/taxon1/taxon1.asn index 9fbf77bc..e3e7bca6 100644 --- a/c++/src/objects/taxon1/taxon1.asn +++ b/c++/src/objects/taxon1/taxon1.asn @@ -1,4 +1,4 @@ ---$Revision: 96973 $ +--$Revision: 548390 $ --********************************************************************** -- -- NCBI Taxonomy Server @@ -39,7 +39,8 @@ Taxon1-req ::= CHOICE { getproptypes NULL, -- get property types getorgprop Taxon1-info, -- get properties for organism searchname Taxon1-info, -- fancy search (token set, wild card) - dumpnames4class INTEGER} -- all names of certain name class + dumpnames4class INTEGER, -- all names of certain name class + getdomain VisibleString} -- get domain description and values Taxon1-resp ::= CHOICE { error Taxon1-error, -- sent on any error @@ -67,7 +68,8 @@ Taxon1-resp ::= CHOICE { getproptypes SET OF Taxon1-info, getorgprop SET OF Taxon1-info, searchname SET OF Taxon1-name, - dumpnames4class SET OF Taxon1-name} + dumpnames4class SET OF Taxon1-name, + getdomain SEQUENCE OF Taxon1-info} -- [0]:id,nof_fields,name, [1..nof_fields]:field_no,val_type,field_name, [:nof_fields]:val_id,int_val or str_len(-1 for null),str_val Taxon1-info ::= SEQUENCE { ival1 INTEGER, diff --git a/c++/src/objects/taxon1/taxon1.cpp b/c++/src/objects/taxon1/taxon1.cpp index e4cea546..69f4eb6b 100644 --- a/c++/src/objects/taxon1/taxon1.cpp +++ b/c++/src/objects/taxon1/taxon1.cpp @@ -1,4 +1,4 @@ -/* $Id: taxon1.cpp 504314 2016-06-14 14:34:17Z domrach $ +/* $Id: taxon1.cpp 539336 2017-06-21 13:20:52Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -89,24 +88,29 @@ CTaxon1::Reset() m_plCache = NULL; } +//--------------------------------------------- +// Taxon1 server init +// Returns: TRUE - OK +// FALSE - Can't open connection to taxonomy service +/// +// default: 10 sec timeout, 5 reconnect attempts, +// cache for 1000 org-refs +static const STimeout def_timeout = { 10, 0 }; bool CTaxon1::Init(void) { - static const STimeout def_timeout = { 120, 0 }; - return CTaxon1::Init(&def_timeout); + return CTaxon1::Init(&def_timeout, def_reconnect_attempts, def_cache_capacity); } bool CTaxon1::Init(unsigned cache_capacity) { - static const STimeout def_timeout = { 120, 0 }; - return CTaxon1::Init(&def_timeout, 5, cache_capacity); + return CTaxon1::Init(&def_timeout, def_reconnect_attempts, cache_capacity); } bool -CTaxon1::Init(const STimeout* timeout, unsigned reconnect_attempts, - unsigned cache_capacity) +CTaxon1::Init(const STimeout* timeout, unsigned reconnect_attempts, unsigned cache_capacity) { SetLastError(NULL); if( TAXON1_IS_INITED ) { // Already inited @@ -128,12 +132,13 @@ CTaxon1::Init(const STimeout* timeout, unsigned reconnect_attempts, } m_nReconnectAttempts = reconnect_attempts; - m_pchService = "TaxService"; + m_pchService = "TaxService4"; const char* tmp; if( ( (tmp=getenv("NI_TAXONOMY_SERVICE_NAME")) != NULL ) || ( (tmp=getenv("NI_SERVICE_NAME_TAXONOMY")) != NULL ) ) { m_pchService = tmp; } + auto_ptr pServer; auto_ptr pOut; auto_ptr pIn; pNi = ConnNetInfo_Create( m_pchService ); @@ -144,8 +149,7 @@ CTaxon1::Init(const STimeout* timeout, unsigned reconnect_attempts, pNi->max_try = reconnect_attempts + 1; ConnNetInfo_SetTimeout( pNi, timeout ); - auto_ptr - pServer( new CConn_ServiceStream(m_pchService, fSERV_Any, + pServer.reset( new CConn_ServiceStream(m_pchService, fSERV_Any, pNi, 0, m_timeout) ); ConnNetInfo_Destroy( pNi ); pNi = NULL; @@ -157,8 +161,8 @@ CTaxon1::Init(const STimeout* timeout, unsigned reconnect_attempts, #endif pOut.reset( CObjectOStream::Open(m_eDataFormat, *pServer) ); pIn.reset( CObjectIStream::Open(m_eDataFormat, *pServer) ); - pOut->FixNonPrint(eFNP_Allow); - pIn->FixNonPrint(eFNP_Allow); + pOut->FixNonPrint(eFNP_Allow); + pIn->FixNonPrint(eFNP_Allow); req.SetInit(); @@ -176,7 +180,7 @@ CTaxon1::Init(const STimeout* timeout, unsigned reconnect_attempts, delete m_plCache; m_plCache = NULL; } else { // Set error - SetLastError( "ERROR: Response type is not Init" ); + SetLastError( "INTERNAL: TaxService response type is not Init" ); } } } catch( exception& e ) { @@ -207,13 +211,21 @@ CTaxon1::Fini(void) if( SendRequest( req, resp, false ) ) { if( !resp.IsFini() ) { - SetLastError( "Response type is not Fini" ); + SetLastError( "INTERNAL: TaxService response type is not Fini" ); } } } Reset(); } +//--------------------------------------------- +// Get organism data (including org-ref) by tax_id +// Returns: pointer to Taxon2Data if organism exists +// NULL - if tax_id wrong +// +// NOTE: +// Caller gets own copy of Taxon2Data structure. +/// CRef< CTaxon2_data > CTaxon1::GetById(TTaxId tax_id) { @@ -239,512 +251,179 @@ CTaxon1::GetById(TTaxId tax_id) return CRef(NULL); } -class PFindMod { -public: - void SetModToMatch( const CRef< COrgMod >& mod ) { - CanonizeName( mod->GetSubname(), m_sName ); - m_nType = mod->GetSubtype(); - } - - bool operator()( const CRef< COrgMod >& mod ) const { - if( m_nType == mod->GetSubtype() ) { - string sCanoName; - CanonizeName( mod->GetSubname(), sCanoName ); - return ( sCanoName == m_sName ); - } - return false; - } - - void CanonizeName( const string& in, string& out ) const { - bool bSpace = true; - char prevc = '\0'; - for( size_t i = 0; i < in.size(); ++i ) { - if( bSpace ) { - if( !isspace((unsigned char) in[i]) ) { - bSpace = false; - if( prevc ) - out += tolower((unsigned char) prevc); - prevc = in[i]; - } - } else { - if( prevc ) - out += tolower((unsigned char) prevc); - if( isspace((unsigned char) in[i]) ) { - prevc = ' '; - bSpace = true; - } else { - prevc = in[i]; - } - } - } - if( prevc && prevc != ' ' ) - out += tolower((unsigned char) prevc); - } - -private: - string m_sName; - int m_nType; -}; - -class PFindConflict { -public: - void SetTypeToMatch( int type ) { - m_nType = type; - switch( type ) { - case COrgMod::eSubtype_strain: - case COrgMod::eSubtype_variety: - //case COrgMod::eSubtype_sub_species: - m_bSubSpecType = true; - break; - default: - m_bSubSpecType = false; - break; - } - } - - bool operator()( const CRef< COrgMod >& mod ) const { - // mod is the destination modifier - if( m_nType == COrgMod::eSubtype_other ) { - return true; - } - if( m_nType == mod->GetSubtype() ) { - return true; - } -#if 0 - switch( mod->GetSubtype() ) { - case COrgMod::eSubtype_strain: - case COrgMod::eSubtype_substrain: - case COrgMod::eSubtype_type: - case COrgMod::eSubtype_subtype: - case COrgMod::eSubtype_variety: - case COrgMod::eSubtype_serotype: - case COrgMod::eSubtype_serogroup: - case COrgMod::eSubtype_serovar: - case COrgMod::eSubtype_cultivar: - case COrgMod::eSubtype_pathovar: - case COrgMod::eSubtype_chemovar: - case COrgMod::eSubtype_biovar: - case COrgMod::eSubtype_biotype: - case COrgMod::eSubtype_group: - case COrgMod::eSubtype_subgroup: - case COrgMod::eSubtype_isolate: - // case COrgMod::eSubtype_sub_species: - return m_bSubSpecType; - - default: - break; - } -#endif - return false; - } - -private: - int m_nType; - bool m_bSubSpecType; -}; - -class PFindModByType { -public: - PFindModByType( int type ) : m_nType( type ) {} - - bool operator()( const CRef< COrgMod >& mod ) const { - return ( m_nType == mod->GetSubtype() ); - } -private: - int m_nType; -}; - -class PRemoveSynAnamorph { -public: - PRemoveSynAnamorph( const string& sTaxname ) : m_sName( sTaxname ) {} - - bool operator()( const CRef< COrgMod >& mod ) const { - switch( mod->GetSubtype() ) { - case COrgMod::eSubtype_synonym: - case COrgMod::eSubtype_anamorph: - return (NStr::CompareNocase( m_sName, mod->GetSubname() ) == 0); - default: - break; - } - return false; - } - -private: - const string& m_sName; -}; - -void -CTaxon1::OrgRefAdjust( COrg_ref& inp_orgRef, const COrg_ref& db_orgRef, - TTaxId tax_id ) +static bool +s_GetBoolValue( const CObject_id& val ) { - inp_orgRef.ResetCommon(); - inp_orgRef.ResetSyn(); - - // fill-up inp_orgRef based on db_orgRef - inp_orgRef.SetTaxname( db_orgRef.GetTaxname() ); - if( db_orgRef.IsSetCommon() ) { - inp_orgRef.SetCommon( db_orgRef.GetCommon() ); - } - // Set tax id - inp_orgRef.SetTaxId( tax_id ); - // copy the synonym list - if( m_bWithSynonyms && db_orgRef.IsSetSyn() ) { - inp_orgRef.SetSyn() = db_orgRef.GetSyn(); + switch( val.Which() ) { + case CObject_id::e_Id: + return val.GetId() != 0; + case CObject_id::e_Str: + try { + return NStr::StringToBool( val.GetStr().c_str() ); + } catch(...) { return false; } + default: + return false; } +} - // copy orgname - COrgName& on = inp_orgRef.SetOrgname(); - - // Copy the orgname - on.SetName().Assign( db_orgRef.GetOrgname().GetName() ); - - bool bHasMod = on.IsSetMod(); - const COrgName::TMod& lSrcMod = db_orgRef.GetOrgname().GetMod(); - COrgName::TMod& lDstMod = on.SetMod(); - - if( bHasMod ) { // Merge modifiers - // Find and remove gb_xxx modifiers - // tc2proc.c: CleanOrgName - // Service stuff - CTaxon1_req req; - CTaxon1_resp resp; - CRef pModInfo( new CTaxon1_info() ); - - PushDiagPostPrefix( "Taxon1::OrgRefAdjust" ); - for( COrgName::TMod::iterator i = lDstMod.begin(); - i != lDstMod.end(); ) { - switch( (*i)->GetSubtype() ) { - case COrgMod::eSubtype_gb_acronym: - case COrgMod::eSubtype_gb_anamorph: - case COrgMod::eSubtype_gb_synonym: - i = lDstMod.erase( i ); - break; - default: // Check the modifier validity - if( (*i)->CanGetSubname() && (*i)->CanGetSubtype() && - !(*i)->GetSubname().empty() && (*i)->GetSubtype() != 0 ) { - pModInfo->SetIval1( tax_id ); - pModInfo->SetIval2( (*i)->GetSubtype() ); - pModInfo->SetSval( (*i)->GetSubname() ); - - req.SetGetorgmod( *pModInfo ); - try { - if( SendRequest( req, resp ) ) { - if( !resp.IsGetorgmod() ) { // error - ERR_POST_X( 1, "Response type is not Getorgmod" ); - } else { - if( resp.GetGetorgmod().size() > 0 ) { - CRef pInfo - = resp.GetGetorgmod().front(); - if( pInfo->GetIval1() == tax_id ) { - if( pInfo->GetIval2() == 0 ) { - // Modifier is wrong (probably, hidden) - i = lDstMod.erase( i ); - continue; - } else { - (*i)->SetSubname( pInfo->GetSval() ); - (*i)->SetSubtype( COrgMod::TSubtype( pInfo->GetIval2() ) ); - } - } else if( pInfo->GetIval1() != 0 ) { - // Another redirection occurred - // leave modifier but issue warning - NCBI_NS_NCBI::CNcbiDiag(eDiag_Warning) - << NCBI_NS_NCBI::ErrCode(NCBI_ERRCODE_X, 19) - << "OrgMod type=" - << COrgMod::GetTypeInfo_enum_ESubtype() - ->FindName( (*i)->GetSubtype(), true ) - << " name='" << (*i)->GetSubname() - << "' causing illegal redirection" - << NCBI_NS_NCBI::Endm; - } - } - } - } else if( resp.IsError() - && resp.GetError().GetLevel() - != CTaxon1_error::eLevel_none ) { - string sErr; - resp.GetError().GetErrorText( sErr ); - ERR_POST_X( 2, sErr ); +CTaxon1::TOrgRefStatus +CTaxon1::x_ConvertOrgrefProps( CTaxon2_data& data ) +{ + TOrgRefStatus result = 0; + COrg_ref& org = data.SetOrg(); + // Copy dbtags from org to inp_orgRef + for( COrg_ref::TDb::iterator i = org.SetDb().begin(); i != org.SetDb().end(); ) { + if( (*i)->GetDb() != "taxon" ) { + if( NStr::StartsWith( (*i)->GetDb(), "taxlookup" ) ) { + // convert taxlookup to status or refresh flags + if( NStr::EndsWith( (*i)->GetDb(), "-changed" ) ) { // refresh flag + if( NStr::Equal( (*i)->GetDb(), "taxlookup?taxid-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongTaxId; + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?taxname-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongTaxname; + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?common-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongCommonName; + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?orgname-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongOrgname; + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?division-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongDivision; + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?lineage-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongLineage; + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?gc-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongGC; + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?mgc-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongMGC; + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?orgmod-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongOrgmod; + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?pgc-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongPGC; + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?orgrefmod-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongOrgrefMod; + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?orgnameattr-changed" ) && + (*i)->IsSetTag() && s_GetBoolValue((*i)->GetTag()) ) { + result |= eStatus_WrongOrgnameAttr; + } + } else { // status flag + if( NStr::Equal( (*i)->GetDb(), "taxlookup?is_species_level" ) && + (*i)->IsSetTag() ) { + data.SetIs_species_level( s_GetBoolValue((*i)->GetTag()) ); + } else if( NStr::Equal( (*i)->GetDb(), "taxlookup?is_uncultured" ) && + (*i)->IsSetTag() ) { + data.SetIs_uncultured( s_GetBoolValue((*i)->GetTag()) ); + } else if( NStr::EqualNocase( (*i)->GetDb(), "taxlookup$blast_lineage" ) && + (*i)->IsSetTag() && (*i)->GetTag().IsStr() ) { + list< string > lBlastNames; + NStr::Split( (*i)->GetTag().GetStr(), ";", lBlastNames, NStr::fSplit_Tokenize ); + NON_CONST_ITERATE( list< string >, i, lBlastNames ) { + NStr::TruncateSpacesInPlace( *i ); } - } catch( exception& e ) { - ERR_POST_X( 3, e.what() ); - } - - } - - ++i; - break; - } - } - - PopDiagPostPrefix(); - - PFindConflict predConflict; - - for( COrgName::TMod::const_iterator i = lSrcMod.begin(); - i != lSrcMod.end(); - ++i ) { - predConflict.SetTypeToMatch( (*i)->GetSubtype() ); - if( (*i)->GetSubtype() != COrgMod::eSubtype_other ) { - if( find_if( lDstMod.begin(), lDstMod.end(), predConflict ) - == lDstMod.end() ) { - CRef pMod( new COrgMod() ); - pMod->Assign( *(*i) ); - lDstMod.push_back( pMod ); - } - } - } - } else { // Copy modifiers - - CRef pMod; - for( COrgName::TMod::const_iterator i = lSrcMod.begin(); - i != lSrcMod.end(); - ++i ) { - switch( (*i)->GetSubtype() ) { - //case COrgMod::eSubtype_gb_acronym: - //case COrgMod::eSubtype_gb_anamorph: - //case COrgMod::eSubtype_gb_synonym: - default: - pMod.Reset( new COrgMod() ); - pMod->Assign( *(*i) ); - lDstMod.push_back( pMod ); - case COrgMod::eSubtype_other: - break; - } - } - // Remove 'other' modifiers - //PFindModByType fmbt( COrgMod::eSubtype_other ); - //remove_if( lDstMod.begin(), lDstMod.end(), fmbt ); - } - // Remove 'synonym' or 'anamorph' it if coincides with taxname - PRemoveSynAnamorph rsa( inp_orgRef.GetTaxname() ); - remove_if( lDstMod.begin(), lDstMod.end(), rsa ); - - // Remove duplicated modifiers - for( COrgName::TMod::iterator i = lDstMod.begin(); - i != lDstMod.end(); - ++i ) { - COrgName::TMod::iterator ii = i; - for( COrgName::TMod::iterator j = ++ii; - j != lDstMod.end(); ) { - if( (*i)->GetSubtype() == (*j)->GetSubtype() && - NStr::EqualNocase( (*i)->GetSubname(), (*j)->GetSubname() ) ) { - j = lDstMod.erase( j ); + lBlastNames.reverse(); + data.SetBlast_name().insert( data.SetBlast_name().end(), + lBlastNames.begin(), lBlastNames.end() ); + } else { + string sPropName = (*i)->GetDb().substr( strlen( "taxlookup?" ) ); + switch( (*i)->GetTag().Which() ) { + case CObject_id::e_Str: data.SetProperty( sPropName, (*i)->GetTag().GetStr() ); break; + case CObject_id::e_Id: data.SetProperty( sPropName, (*i)->GetTag().GetId() ); break; + default: break; // unknown type + } + } + } + i = org.SetDb().erase(i); } else { - ++j; + ++i; } + } else { + ++i; } } - - // Reset destination modifiers if empty - if( lDstMod.size() == 0 ) { - on.ResetMod(); + + // Set flags to default values if corresponding property is not found + if( !data.IsSetIs_uncultured() ) { + data.SetIs_uncultured( false ); } - // Copy lineage - if( db_orgRef.GetOrgname().IsSetLineage() ) { - on.SetLineage() = db_orgRef.GetOrgname().GetLineage(); - } else { - on.ResetLineage(); - } - if( db_orgRef.GetOrgname().IsSetGcode() ) { - on.SetGcode( db_orgRef.GetOrgname().GetGcode() ); - } else { - on.ResetGcode(); - } - if( db_orgRef.GetOrgname().IsSetMgcode() ) { - on.SetMgcode( db_orgRef.GetOrgname().GetMgcode() ); - } else { - on.ResetMgcode(); - } - if( db_orgRef.GetOrgname().IsSetDiv() ) { - on.SetDiv( db_orgRef.GetOrgname().GetDiv() ); - } else { - on.ResetDiv(); - } - if( db_orgRef.GetOrgname().IsSetPgcode() ) { - on.SetPgcode( db_orgRef.GetOrgname().GetPgcode() ); - } else { - on.ResetPgcode(); + if( !data.IsSetIs_species_level() ) { + data.SetIs_species_level( false ); } + return result; } -bool -CTaxon1::LookupByOrgRef(const COrg_ref& inp_orgRef, TTaxId* pTaxid, - COrgName::TMod& hitMods ) +//---------------------------------------------- +// Get organism data by OrgRef +// Returns: pointer to Taxon2Data if organism exists +// NULL - if no such organism in taxonomy database +// +// NOTE: +// 1. These functions uses the following data from inp_orgRef to find +// organism in taxonomy database. It uses taxname first. If no organism +// was found (or multiple nodes found) then it tries to find organism +// using common name. If nothing found, then it tries to find organism +// using synonyms. Lookup never uses tax_id to find organism. +// 2. LookupMerge function modifies given OrgRef to correspond to the +// found one and returns constant pointer to the Taxon2Data structure +// stored internally. +/// +CRef< CTaxon2_data > +CTaxon1::Lookup(const COrg_ref& inp_orgRef, string* psLog) { + SetLastError(NULL); + if( !TAXON1_IS_INITED ) { + if( !Init() ) { + return CRef(NULL); + } + } + // Check if this taxon is in cache + CRef pData( 0 ); + SetLastError(NULL); CTaxon1_req req; CTaxon1_resp resp; SerialAssign< COrg_ref >( req.SetLookup(), inp_orgRef ); + // Set version db tag + COrgrefProp::SetOrgrefProp( req.SetLookup(), "version", 2 ); + if( m_bWithSynonyms ) { + COrgrefProp::SetOrgrefProp( req.SetLookup(), "syn", m_bWithSynonyms ); + } + if( psLog ) { + COrgrefProp::SetOrgrefProp( req.SetLookup(), "log", true ); + } if( SendRequest( req, resp ) ) { if( resp.IsLookup() ) { // Correct response, return object - COrg_ref& result = resp.SetLookup().SetOrg(); - *pTaxid = result.GetTaxId(); - if( result.IsSetOrgname() && - result.GetOrgname().IsSetMod() ) { - hitMods.swap( result.SetOrgname().SetMod() ); + pData.Reset( new CTaxon2_data() ); + + SerialAssign< COrg_ref >( pData->SetOrg(), resp.GetLookup().GetOrg() ); + x_ConvertOrgrefProps( *pData ); + if( psLog ) { + pData->GetProperty( "log", *psLog ); } - // for( COrgName::TMod::const_iterator ci = - // result.GetOrgname().GetMod().begin(); - // ci != result.GetOrgname().GetMod().end(); - // ++ci ) { - // if( (*ci)->GetSubtype() == COrgMod::eSubtype_old_name ) { - // hitMod->Assign( *ci ); - // bHitFound = true; - // break; - // } - // } - // } - // if( bHitFound ) { - // hitMod.Reset( NULL ); - // } - return true; } else { // Internal: wrong respond type - SetLastError( "Response type is not Lookup" ); + SetLastError( "INTERNAL: TaxService response type is not Lookup" ); } } - return false; -} - -void -CTaxon1::PopulateReplaced( COrg_ref& org, COrgName::TMod& lMods ) -{ - if( org.IsSetOrgname() ) { - CRef< COrgMod > pOldNameMod; - COrgName& on = org.SetOrgname(); - for( COrgName::TMod::iterator i = lMods.begin(); - i != lMods.end(); - ++i ) { - if( (*i)->GetSubtype() == COrgMod::eSubtype_old_name ) { - pOldNameMod = *i; - continue; - } - if( on.IsSetMod() ) { - PFindModByType fmbt( (*i)->GetSubtype() ); - if( find_if( on.GetMod().begin(), on.GetMod().end(), fmbt ) - != on.GetMod().end() ) { - /* modifier already present in target orgref */ - continue; - } - } - /* adding this modifier */ - on.SetMod().push_back( *i ); - } - if( pOldNameMod ) { - if( on.IsSetMod() ) { - PFindModByType fmbt( COrgMod::eSubtype_old_name ); - COrgName::TMod::iterator i = - find_if( on.SetMod().begin(), on.SetMod().end(), fmbt ); - if( i != on.SetMod().end() ) { - // There is old-name in the target already - if( !(*i)->IsSetAttrib() && pOldNameMod->IsSetAttrib() && - NStr::CompareNocase(pOldNameMod->GetSubname(), - (*i)->GetSubname() ) == 0 ) { - (*i)->SetAttrib( pOldNameMod->GetAttrib() ); - } - return; - } - } - /* we probably don't need to populate search name */ - if( org.IsSetTaxname() && - NStr::CompareNocase( org.GetTaxname(), - pOldNameMod->GetSubname() ) == 0 ) { - if( pOldNameMod->IsSetAttrib() ) { - const string& sAttrib = pOldNameMod->GetAttrib(); - if( !sAttrib.empty() && sAttrib[0] == '(' ) { - try { - CRef< COrgMod > srchMod( new COrgMod ); - string::size_type pos = sAttrib.find("="); - if( pos == string::npos ) { - return; - } - if( on.IsSetMod() ) { - const COrgName::TMod& mods = on.GetMod(); - srchMod->SetSubname() - .assign( sAttrib.c_str()+pos+1 ); - srchMod->SetSubtype - ( COrgMod::TSubtype - (NStr::StringToInt - (sAttrib.substr(1, pos-1), - NStr::fAllowTrailingSymbols) ) ); - PFindMod mf; - mf.SetModToMatch( srchMod ); - if( find_if( mods.begin(), mods.end(), - mf ) != mods.end() ) { - return; - } - } - } catch(...) { return; } - } else - return; - } else - return; - } - // Add old-name to modifiers - on.SetMod().push_back( pOldNameMod ); - } - } -} - -CRef< CTaxon2_data > -CTaxon1::Lookup(const COrg_ref& inp_orgRef ) -{ - SetLastError(NULL); - if( !TAXON1_IS_INITED ) { - if( !Init() ) { - return CRef(NULL); - } - } - // Check if this taxon is in cache - CTaxon2_data* pData = 0; - COrgName::TMod hitMod; - TTaxId tax_id = 0; - - if( LookupByOrgRef( inp_orgRef, &tax_id, hitMod ) - && tax_id > 0 - && m_plCache->LookupAndInsert( tax_id, &pData ) && pData ) { - - CTaxon2_data* pNewData = new CTaxon2_data(); - - COrg_ref* pOrf = new COrg_ref; - pOrf->Assign( inp_orgRef ); - if( pOrf->IsSetOrgname() && pOrf->GetOrgname().IsSetMod() ) { - // Clean up modifiers - pOrf->SetOrgname().ResetMod(); - } - pNewData->SetOrg( *pOrf ); - - const COrg_ref& db_orgRef = pData->GetOrg(); - - OrgRefAdjust( pNewData->SetOrg(), db_orgRef, tax_id ); - // Copy all other fields - if( pData->IsSetBlast_name() ) { - pNewData->SetBlast_name() = pData->GetBlast_name(); - } - if( pData->IsSetIs_uncultured() ) { - pNewData->SetIs_uncultured( pData->GetIs_uncultured() ); - } - if( pData->IsSetIs_species_level() ) { - pNewData->SetIs_species_level( pData->GetIs_species_level() ); - } - // Insert the hitMod if necessary - if( hitMod.size() > 0 ) { - PopulateReplaced( pNewData->SetOrg(), hitMod ); - } - return CRef(pNewData); - } - return CRef(NULL); + return pData; } CConstRef< CTaxon2_data > -CTaxon1::LookupMerge(COrg_ref& inp_orgRef ) +CTaxon1::LookupMerge(COrg_ref& inp_orgRef, string* psLog) { - CTaxon2_data* pData = 0; + //CTaxon2_data* pData = 0; SetLastError(NULL); if( !TAXON1_IS_INITED ) { @@ -752,24 +431,52 @@ CTaxon1::LookupMerge(COrg_ref& inp_orgRef ) return CConstRef(NULL); } } - COrgName::TMod hitMod; - TTaxId tax_id = 0; //GetTaxIdByOrgRef( inp_orgRef ); - - if( LookupByOrgRef( inp_orgRef, &tax_id, hitMod ) - && tax_id > 0 - && m_plCache->LookupAndInsert( tax_id, &pData ) && pData ) { + // Check if this taxon is in cache + CRef pData( 0 ); - const COrg_ref& db_orgRef = pData->GetOrg(); + SetLastError(NULL); - OrgRefAdjust( inp_orgRef, db_orgRef, tax_id ); + CTaxon1_req req; + CTaxon1_resp resp; - if( hitMod.size() > 0 ) { - PopulateReplaced( inp_orgRef, hitMod ); + SerialAssign< COrg_ref >( req.SetLookup(), inp_orgRef ); + // Set version db tag + COrgrefProp::SetOrgrefProp( req.SetLookup(), "version", 2 ); + COrgrefProp::SetOrgrefProp( req.SetLookup(), "merge", true ); + COrgrefProp::SetOrgrefProp( req.SetLookup(), "syn", m_bWithSynonyms ); + if( psLog ) { + COrgrefProp::SetOrgrefProp( req.SetLookup(), "log", true ); + } + if( SendRequest( req, resp ) ) { + if( resp.IsLookup() ) { + // Correct response, return object + pData.Reset( new CTaxon2_data() ); + + SerialAssign< COrg_ref >( pData->SetOrg(), resp.GetLookup().GetOrg() ); + x_ConvertOrgrefProps( *pData ); + if( psLog ) { + pData->GetProperty( "log", *psLog ); + } + SerialAssign< COrg_ref >( inp_orgRef, pData->GetOrg() ); + + } else { // Internal: wrong respond type + SetLastError( "INTERNAL: TaxService response type is not Lookup" ); } } + return CConstRef(pData); } +//----------------------------------------------- +// Get tax_id by OrgRef +// Returns: tax_id - if organism found +// 0 - no organism found +// -1 - error during processing occured +// -tax_id - if multiple nodes found +// (where tax_id > 1 is id of one of the nodes) +// NOTE: +// This function uses the same information from inp_orgRef as Lookup +/// TTaxId CTaxon1::GetTaxIdByOrgRef(const COrg_ref& inp_orgRef) { @@ -790,25 +497,45 @@ CTaxon1::GetTaxIdByOrgRef(const COrg_ref& inp_orgRef) // Correct response, return object return resp.GetGetidbyorg(); } else { // Internal: wrong respond type - SetLastError( "Response type is not Getidbyorg" ); + SetLastError( "INTERNAL: TaxService response type is not Getidbyorg" ); } } return 0; } +//---------------------------------------------- +// Get tax_id by organism name +// Returns: tax_id - if organism found +// 0 - no organism found +// -1 - error during processing occured +// -tax_id - if multiple nodes found +// (where tax_id > 1 is id of one of the nodes) +/// TTaxId CTaxon1::GetTaxIdByName(const string& orgname) { SetLastError(NULL); if( orgname.empty() ) return 0; - COrg_ref orgRef; - - orgRef.SetTaxname().assign( orgname ); + list< CRef< CTaxon1_name > > lNames; + TTaxId retc = SearchTaxIdByName(orgname, eSearch_Exact, &lNames); + switch( retc ) { + case -2: retc = -1; break; + case -1: retc = -lNames.front()->GetTaxid(); break; // Multiple nodes found, get first taxid + default: break; + } - return GetTaxIdByOrgRef(orgRef); + return retc; } +//---------------------------------------------- +// Get tax_id by organism "unique" name +// Returns: tax_id - if organism found +// 0 - no organism found +// -1 - error during processing occured +// -tax_id - if multiple nodes found +// (where tax_id > 1 is id of one of the nodes) +/// TTaxId CTaxon1::FindTaxIdByName(const string& orgname) { @@ -825,7 +552,7 @@ CTaxon1::FindTaxIdByName(const string& orgname) if(id < 1) { - int idu = 0; + TTaxId idu = 0; CTaxon1_req req; CTaxon1_resp resp; @@ -837,7 +564,7 @@ CTaxon1::FindTaxIdByName(const string& orgname) // Correct response, return object idu = resp.GetGetunique(); } else { // Internal: wrong respond type - SetLastError( "Response type is not Getunique" ); + SetLastError( "INTERNAL: TaxService response type is not Getunique" ); } } @@ -891,7 +618,7 @@ CTaxon1::SearchTaxIdByName(const string& orgname, ESearch mode, if( SendRequest( req, resp ) ) { if( resp.IsSearchname() ) { // Correct response, return object - int retc = 0; + TTaxId retc = 0; const CTaxon1_resp::TSearchname& lNm = resp.GetSearchname(); if( lNm.size() == 0 ) { retc = 0; @@ -906,13 +633,20 @@ CTaxon1::SearchTaxIdByName(const string& orgname, ESearch mode, } return retc; } else { // Internal: wrong respond type - SetLastError( "Response type is not Searchname" ); - return 0; + SetLastError( "INTERNAL: TaxService response type is not Searchname" ); + return -2; } + } else if( GetLastError().find("Nothing found") != string::npos ) { + return 0; } - return 0; + return -2; } +//---------------------------------------------- +// Get ALL tax_id by organism name +// Returns: number of organisms found (negative value on error), +// id list appended with found tax ids +/// int CTaxon1::GetAllTaxIdByName(const string& orgname, TTaxIdList& lIds) { @@ -942,7 +676,7 @@ CTaxon1::GetAllTaxIdByName(const string& orgname, TTaxIdList& lIds) i != lNm.end(); ++i, ++count ) lIds.push_back( (*i)->GetTaxid() ); } else { // Internal: wrong respond type - SetLastError( "Response type is not Findname" ); + SetLastError( "INTERNAL: TaxService response type is not Findname" ); return 0; } } @@ -976,16 +710,17 @@ CTaxon1::GetOrgRef(TTaxId tax_id, if( m_plCache->LookupAndInsert( tax_id, &pData ) && pData ) { is_species = pData->GetIs_species_level(); is_uncultured = pData->GetIs_uncultured(); - if( pData->GetBlast_name().size() > 0 ) { + if( pData->IsSetBlast_name() && pData->GetBlast_name().size() > 0 ) { blast_name.assign( pData->GetBlast_name().front() ); } if( is_specified ) { - bool specified = false; - if( GetNodeProperty( tax_id, "specified_inh", specified ) ) { - *is_specified = specified; - } else { - return null; - } + *is_specified = pData->GetOrg().GetOrgname().IsFormalName(); +// bool specified = false; +// if( GetNodeProperty( tax_id, "specified_inh", specified ) ) { +// *is_specified = specified; +// } else { +// return null; +// } } return CConstRef(&pData->GetOrg()); } @@ -1054,39 +789,38 @@ CTaxon1::GetSpecies(TTaxId id_tax, ESpeciesMode mode) } if( m_plCache->LookupAndAdd( id_tax, &pNode ) && pNode && m_plCache->InitRanks() ) { - if( mode == eSpeciesMode_RankOnly ) { - int species_rank(m_plCache->GetSpeciesRank()); - while( !pNode->IsRoot() ) { - int rank( pNode->GetRank() ); - if( rank == species_rank ) - return pNode->GetTaxId(); - if( (rank >= 0) && (rank < species_rank)) - return 0; - pNode = pNode->GetParent(); - } - return 0; - } else { // Based on flag - CTaxon1Node* pResult = NULL; - CTaxon2_data* pData = NULL; - while( !pNode->IsRoot() ) { - if( m_plCache->LookupAndInsert( pNode->GetTaxId(), &pData ) ) { - if( !pData ) - return -1; - if( !(pData->IsSetIs_species_level() && - pData->GetIs_species_level()) ) { - if( pResult ) { - return pResult->GetTaxId(); - } else { - return 0; - } - } - pResult = pNode; - pNode = pNode->GetParent(); - } else { // Node in the lineage not found - return -1; - } - } - } + if( mode == eSpeciesMode_RankOnly ) { + TTaxRank species_rank(m_plCache->GetSpeciesRank()); + while( !pNode->IsRoot() ) { + TTaxRank rank( pNode->GetRank() ); + if( rank == species_rank ) + return pNode->GetTaxId(); + if( (rank > 0) && (rank < species_rank)) + return 0; + pNode = pNode->GetParent(); + } + return 0; + } else { // Based on flag + CTaxon1Node* pResult = NULL; + CTaxon2_data* pData = NULL; + while( !pNode->IsRoot() ) { + if( m_plCache->LookupAndInsert( pNode->GetTaxId(), &pData ) ) { + if( !pData ) + return -1; + if( !(pData->IsSetIs_species_level() && pData->GetIs_species_level()) ) { + if( pResult ) { + return pResult->GetTaxId(); + } else { + return 0; + } + } + pResult = pNode; + pNode = pNode->GetParent(); + } else { // Node in the lineage not found + return -1; + } + } + } } return -1; } @@ -1109,16 +843,16 @@ CTaxon1::GetGenus(TTaxId id_tax) } if( m_plCache->LookupAndAdd( id_tax, &pNode ) && pNode && m_plCache->InitRanks() ) { - int genus_rank(m_plCache->GetGenusRank()); + TTaxRank genus_rank(m_plCache->GetGenusRank()); while( !pNode->IsRoot() ) { - int rank( pNode->GetRank() ); + TTaxRank rank( pNode->GetRank() ); if( rank == genus_rank ) return pNode->GetTaxId(); - if( (rank >= 0) && (rank < genus_rank)) - break; + if( (rank > 0) && (rank < genus_rank)) + return 0; pNode = pNode->GetParent(); } - return 0; + return 0; } return -1; } @@ -1141,15 +875,17 @@ CTaxon1::GetSuperkingdom(TTaxId id_tax) } if( m_plCache->LookupAndAdd( id_tax, &pNode ) && pNode && m_plCache->InitRanks() ) { - int sk_rank(m_plCache->GetSuperkingdomRank()); + TTaxRank sk_rank(m_plCache->GetSuperkingdomRank()); while( !pNode->IsRoot() ) { - int rank( pNode->GetRank() ); + TTaxRank rank( pNode->GetRank() ); if( rank == sk_rank ) return pNode->GetTaxId(); + if( (rank > 0) && (rank < sk_rank)) + return 0; pNode = pNode->GetParent(); } - return 0; - } + return 0; + } return -1; } @@ -1190,50 +926,51 @@ CTaxon1::GetSuperkingdom(TTaxId id_tax) // // Returns: tax_id of properly ranked accessor or // 0 - no such rank in the lineage -// -1 - invalid rank name -// -2 - any other error (use GetLastError for details) +// -1 - tax id is not found +// -2 - invalid rank name +// -3 - any other error (use GetLastError for details) /// TTaxId CTaxon1::GetAncestorByRank(TTaxId id_tax, const char* rank_name) { SetLastError(NULL); if( !TAXON1_IS_INITED ) { - if( !Init() ) { - return -2; - } + if( !Init() ) { + return -3; + } } if( rank_name ) { - short rank( m_plCache->FindRankByName( rank_name ) ); - if( rank != -1000 ) { - return GetAncestorByRank(id_tax, rank); - } + TTaxRank rank( m_plCache->FindRankByName( rank_name ) ); + if( rank != -1000 ) { + return GetAncestorByRank(id_tax, rank); + } } SetLastError( "rank not found" ); ERR_POST_X( 2, GetLastError() ); - return -1; + return -2; } TTaxId -CTaxon1::GetAncestorByRank(TTaxId id_tax, short rank_id) +CTaxon1::GetAncestorByRank(TTaxId id_tax, TTaxRank rank_id) { CTaxon1Node* pNode = 0; SetLastError(NULL); if( !TAXON1_IS_INITED ) { - if( !Init() ) { - return -1; - } + if( !Init() ) { + return -3; + } } if( m_plCache->LookupAndAdd( id_tax, &pNode ) && pNode ) { while( !pNode->IsRoot() ) { - int rank( pNode->GetRank() ); + TTaxRank rank( pNode->GetRank() ); if( rank == rank_id ) return pNode->GetTaxId(); if( (rank >= 0) && (rank < rank_id)) return 0; pNode = pNode->GetParent(); } - return 0; + return 0; } return -1; } @@ -1243,7 +980,7 @@ CTaxon1::GetAncestorByRank(TTaxId id_tax, short rank_id) // Returns: number of children, id list appended with found tax ids // -1 - in case of error /// -int +TTaxId CTaxon1::GetChildren(TTaxId id_tax, TTaxIdList& children_ids) { int count(0); @@ -1279,7 +1016,7 @@ CTaxon1::GetChildren(TTaxId id_tax, TTaxIdList& children_ids) pIt->AddChild( pNewNode ); } } else { // Internal: wrong respond type - SetLastError( "Response type is not Taxachildren" ); + SetLastError( "INTERNAL: TaxService response type is not Taxachildren" ); return 0; } } @@ -1288,7 +1025,7 @@ CTaxon1::GetChildren(TTaxId id_tax, TTaxIdList& children_ids) } bool -CTaxon1::GetGCName(short gc_id, string& gc_name_out ) +CTaxon1::GetGCName(TTaxGeneticCode gc_id, string& gc_name_out ) { SetLastError(NULL); if( !TAXON1_IS_INITED ) { @@ -1314,7 +1051,7 @@ CTaxon1::GetGCName(short gc_id, string& gc_name_out ) (*i)->GetSval()) ); } } else { // Internal: wrong respond type - SetLastError( "Response type is not Getgcs" ); + SetLastError( "INTERNAL: TaxService response type is not Getgcs" ); return false; } } @@ -1333,7 +1070,7 @@ CTaxon1::GetGCName(short gc_id, string& gc_name_out ) // Get taxonomic rank name by rank id /// bool -CTaxon1::GetRankName(short rank_id, string& rank_name_out ) +CTaxon1::GetRankName(TTaxRank rank_id, string& rank_name_out ) { SetLastError( NULL ); if( !TAXON1_IS_INITED ) { @@ -1355,7 +1092,7 @@ CTaxon1::GetRankName(short rank_id, string& rank_name_out ) // Get taxonomic division name by division id /// bool -CTaxon1::GetDivisionName(short div_id, string& div_name_out, string* div_code_out ) +CTaxon1::GetDivisionName(TTaxDivision div_id, string& div_name_out, string* div_code_out ) { SetLastError( NULL ); if( !TAXON1_IS_INITED ) { @@ -1381,7 +1118,7 @@ CTaxon1::GetDivisionName(short div_id, string& div_name_out, string* div_code_ou // Get taxonomic name class (scientific name, common name, etc.) by id /// bool -CTaxon1::GetNameClass(short nameclass_id, string& name_class_out ) +CTaxon1::GetNameClass(TTaxNameClass nameclass_id, string& name_class_out ) { SetLastError( NULL ); if( !TAXON1_IS_INITED ) { @@ -1403,7 +1140,7 @@ CTaxon1::GetNameClass(short nameclass_id, string& name_class_out ) // Get name class id by name class name // Returns: value < 0 - Incorrect class name /// -short +TTaxNameClass CTaxon1::GetNameClassId( const string& class_name ) { SetLastError( NULL ); @@ -1483,7 +1220,7 @@ CTaxon1::GetAllNames(TTaxId tax_id, TNameList& lNames, bool unique) (*i)->GetOname() ); } } else { // Internal: wrong respond type - SetLastError( "Response type is not Getorgnames" ); + SetLastError( "INTERNAL: TaxService response type is not Getorgnames" ); return 0; } } @@ -1523,7 +1260,7 @@ CTaxon1::GetAllNamesEx(TTaxId tax_id, list< CRef< CTaxon1_name > >& lNames) lNames.push_back( *i ); } } else { // Internal: wrong respond type - SetLastError( "Response type is not Getorgnames" ); + SetLastError( "INTERNAL: TaxService response type is not Getorgnames" ); return false; } } @@ -1532,7 +1269,7 @@ CTaxon1::GetAllNamesEx(TTaxId tax_id, list< CRef< CTaxon1_name > >& lNames) } bool -CTaxon1::DumpNames( short name_class, list< CRef< CTaxon1_name > >& lOut ) +CTaxon1::DumpNames( TTaxNameClass name_class, list< CRef< CTaxon1_name > >& lOut ) { SetLastError(NULL); if( !TAXON1_IS_INITED ) { @@ -1550,7 +1287,7 @@ CTaxon1::DumpNames( short name_class, list< CRef< CTaxon1_name > >& lOut ) // Correct response, return object lOut.swap( resp.SetDumpnames4class() ); } else { // Internal: wrong respond type - SetLastError( "Response type is not Dumpnames4class" ); + SetLastError( "INTERNAL: TaxService response type is not Dumpnames4class" ); return false; } } @@ -1558,16 +1295,6 @@ CTaxon1::DumpNames( short name_class, list< CRef< CTaxon1_name > >& lOut ) return true; } -/*--------------------------------------------- - * Find organism name in the string (for PDB mostly) - * Returns: nimber of tax_ids found - * NOTE: - * 1. orgname is substring of search_str which matches organism name - * (return parameter). - * 2. Ids consists of tax_ids. Caller is responsible to free this memory - */ - // int getTaxId4Str(const char* search_str, char** orgname, intPtr *Ids_out); - bool CTaxon1::IsAlive(void) { @@ -1606,7 +1333,7 @@ CTaxon1::GetTaxId4GI(TGi gi, TTaxId& tax_id_out ) tax_id_out = resp.GetId4gi(); return true; } else { // Internal: wrong respond type - SetLastError( "Response type is not Id4gi" ); + SetLastError( "INTERNAL: TaxService response type is not Id4gi" ); } } return false; @@ -1709,6 +1436,7 @@ CTaxon1::SendRequest( CTaxon1_req& req, CTaxon1_resp& resp, bool bShouldReconnec pIn.reset( CObjectIStream::Open(m_eDataFormat, *pServer) ); pOut->FixNonPrint(eFNP_Allow); pIn->FixNonPrint(eFNP_Allow); + m_pServer = pServer.release(); m_pIn = pIn.release(); m_pOut = pOut.release(); @@ -1773,7 +1501,7 @@ CTaxon1::GetPopsetJoin( const TTaxIdList& ids_in, TTaxIdList& ids_out ) for( TTaxIdList::const_iterator ci = ids_in.begin(); ci != ids_in.end(); ++ci ) { - map< TTaxId, CTaxon1Node* >::iterator nmi = nodeMap.find( *ci ); + map< int, CTaxon1Node* >::iterator nmi = nodeMap.find( *ci ); if( nmi == nodeMap.end() ) { if( m_plCache->LookupAndAdd( *ci, &pNode ) ) { if( !tPartTree.GetRoot() ) { @@ -1781,7 +1509,7 @@ CTaxon1::GetPopsetJoin( const TTaxIdList& ids_in, TTaxIdList& ids_out ) ( *static_cast (m_plCache->GetTree().GetRoot()) ); tPartTree.SetRoot( pNewParent ); - nodeMap.insert( map< TTaxId,CTaxon1Node* >::value_type + nodeMap.insert( map< int,CTaxon1Node* >::value_type (pNewParent->GetTaxId(), pNewParent) ); } if( pNode ) { @@ -1807,7 +1535,7 @@ CTaxon1::GetPopsetJoin( const TTaxIdList& ids_in, TTaxIdList& ids_out ) i != vLin.rend(); ++i ) { pNode = *i; - nodeMap.insert( map< TTaxId,CTaxon1Node* >::value_type + nodeMap.insert( map< int,CTaxon1Node* >::value_type ( pNode->GetTaxId(), pNode ) ); pIt->AddChild( pNode ); pIt->GoNode( pNode ); @@ -1913,7 +1641,7 @@ CTaxon1::LoadSubtreeEx( TTaxId tax_id, int levels, const ITaxon1Node** ppNode ) } return true; } else { // Internal: wrong respond type - SetLastError( "Response type is not Taxachildren" ); + SetLastError( "INTERNAL: TaxService response type is not Taxachildren" ); return false; } } @@ -2000,6 +1728,7 @@ CTaxon1::GetNodeProperty( TTaxId tax_id, const string& prop_name, if( SendRequest( req, resp ) ) { if( !resp.IsGetorgprop() ) { // error ERR_POST_X( 4, "Response type is not Getorgprop" ); + SetLastError( "INTERNAL: TaxService response type is not Getorgprop" ); } else { if( resp.GetGetorgprop().size() > 0 ) { CRef pInfo @@ -2052,6 +1781,7 @@ CTaxon1::GetNodeProperty( TTaxId tax_id, const string& prop_name, if( SendRequest( req, resp ) ) { if( !resp.IsGetorgprop() ) { // error ERR_POST_X( 8, "Response type is not Getorgprop" ); + SetLastError( "INTERNAL: TaxService response type is not Getorgprop" ); } else { if( resp.GetGetorgprop().size() > 0 ) { CRef pInfo @@ -2104,6 +1834,7 @@ CTaxon1::GetNodeProperty( TTaxId tax_id, const string& prop_name, if( SendRequest( req, resp ) ) { if( !resp.IsGetorgprop() ) { // error ERR_POST_X( 12, "Response type is not Getorgprop" ); + SetLastError( "INTERNAL: TaxService response type is not Getorgprop" ); } else { if( resp.GetGetorgprop().size() > 0 ) { CRef pInfo @@ -2291,146 +2022,46 @@ ITreeIterator::TraverseAncestors(I4Each& cb) return stat; } +//----------------------------------------------- +// Checks whether OrgRef is current +// Returns: false on any error, stat_out filled with status flags +// (see above) +/// bool CTaxon1::CheckOrgRef( const COrg_ref& orgRef, TOrgRefStatus& stat_out ) { CDiagAutoPrefix( "Taxon1::CheckOrgRef" ); SetLastError(NULL); - TTaxId tax_id; - - tax_id = GetTaxIdByOrgRef( orgRef ); + if( !TAXON1_IS_INITED ) { + if( !Init() ) { + return false; + } + } stat_out = eStatus_Ok; - if( tax_id == 0 ) { - SetLastError( "No organism found for specified org_ref" ); - ERR_POST_X( 16, GetLastError() ); - return false; - } else if( tax_id < 0 ) { - SetLastError( "Multiple organisms found for specified org_ref" ); - ERR_POST_X( 17, GetLastError() ); - return false; - } else { - CRef< CTaxon2_data > pData( GetById( tax_id ) ); - if( pData ) { - // Compare orgrefs - const COrg_ref& goodOr = pData->GetOrg(); + CTaxon1_req req; + CTaxon1_resp resp; - if( !orgRef.IsSetOrgname() ) { - stat_out |= eStatus_NoOrgname; - } else { - const COrgName& goodOn = goodOr.GetOrgname(); - const COrgName& inpOn = orgRef.GetOrgname(); + SerialAssign< COrg_ref >( req.SetLookup(), orgRef ); + // Set version db tag + COrgrefProp::SetOrgrefProp( req.SetLookup(), "version", 2 ); + COrgrefProp::SetOrgrefProp( req.SetLookup(), "merge", true ); - if( !inpOn.IsSetGcode() || !goodOn.IsSetGcode() || - inpOn.GetGcode() != goodOn.GetGcode() ) { - stat_out |= eStatus_WrongGC; - } - if( !inpOn.IsSetMgcode() ) { // mgc not set in input - if( goodOn.IsSetMgcode() && - goodOn.GetMgcode() != 0 ) { - stat_out |= eStatus_WrongMGC; - } - } else { // mgc set - if( !goodOn.IsSetMgcode() ) { - if( inpOn.GetMgcode() != 0 ) { // not unassigned - stat_out |= eStatus_WrongMGC; - } - } else if( inpOn.GetMgcode() != goodOn.GetMgcode() ) { - stat_out |= eStatus_WrongMGC; - } - } - if( !inpOn.IsSetPgcode() ) { // pgc not set in input - if( goodOn.IsSetPgcode() && - goodOn.GetPgcode() != 0 ) { - stat_out |= eStatus_WrongPGC; - } - } else { // pgc set - if( !goodOn.IsSetPgcode() ) { - if( inpOn.GetPgcode() != 0 ) { // not unassigned - stat_out |= eStatus_WrongPGC; - } - } else if( inpOn.GetPgcode() != goodOn.GetPgcode() ) { - stat_out |= eStatus_WrongPGC; - } - } - if( !inpOn.IsSetLineage() || !goodOn.IsSetLineage() || - inpOn.GetLineage().compare( goodOn.GetLineage() ) != 0 ) { - stat_out |= eStatus_WrongLineage; - } - if( !inpOn.IsSetName() || !goodOn.IsSetName() || - inpOn.GetName().Which() != goodOn.GetName().Which() ) { - stat_out |= eStatus_WrongOrgname; - } - if( !inpOn.IsSetDiv() ) { - if( goodOn.IsSetDiv() && - goodOn.GetDiv().compare( "UNA" ) != 0 ) { - stat_out |= eStatus_WrongDivision; - } - } else { - if( !goodOn.IsSetDiv() ) { - if( inpOn.GetDiv().compare( "UNA" ) != 0 ) { - stat_out |= eStatus_WrongDivision; - } - } else if( inpOn.GetDiv().compare( goodOn.GetDiv() ) - != 0 ) { - stat_out |= eStatus_WrongDivision; - } - } - if( goodOn.IsSetMod() ) { - if( inpOn.IsSetMod() ) { - const COrgName::TMod& inpMods = inpOn.GetMod(); - const COrgName::TMod& goodMods = goodOn.GetMod(); - for( COrgName::TMod::const_iterator gi = - goodMods.begin(); - gi != goodMods.end(); - ++gi ) { - bool bFound = false; - for( COrgName::TMod::const_iterator ii = - inpMods.begin(); - ii != inpMods.end(); - ++ii ) { - if( (*gi)->GetSubtype() == (*ii)->GetSubtype() - && ((*gi)->GetSubname() == - (*ii)->GetSubname()) ) { - bFound = true; - break; - } - } - if( !bFound ) { - stat_out |= eStatus_WrongOrgmod; - break; - } - } - } else { - stat_out |= eStatus_WrongOrgmod; - } - } - } - // Check taxname - if( orgRef.IsSetTaxname() ) { - if( !goodOr.IsSetTaxname() || - orgRef.GetTaxname().compare( goodOr.GetTaxname() ) != 0 ) { - stat_out |= eStatus_WrongTaxname; - } - } else if( goodOr.IsSetTaxname() ) { - stat_out |= eStatus_WrongTaxname; - } - // Check common name - if( orgRef.IsSetCommon() ) { - if( !goodOr.IsSetCommon() || - orgRef.GetCommon().compare( goodOr.GetCommon() ) != 0 ) { - stat_out |= eStatus_WrongCommonName; - } - } else if( goodOr.IsSetCommon() ) { - stat_out |= eStatus_WrongCommonName; - } - } else { // Internal error: Cannot find orgref by tax_id - SetLastError( "No organisms found for tax id" ); - ERR_POST_X( 18, GetLastError() ); - return false; + if( SendRequest( req, resp ) ) { + if( resp.IsLookup() ) { + // Correct response, return object + CRef pData( new CTaxon2_data() ); + + SerialAssign< COrg_ref >( pData->SetOrg(), resp.GetLookup().GetOrg() ); + stat_out = x_ConvertOrgrefProps( *pData ); + + return true; + } else { // Internal: wrong respond type + SetLastError( "INTERNAL: TaxService response type is not Lookup" ); } } - return true; + + return false; } //--------------------------------------------------- @@ -2493,7 +2124,7 @@ CTaxon1::GetTypeMaterial( TTaxId tax_id, TNameList& type_material_list_out ) pNode = pNode->GetParent(); } // Filter out excessive name classes, leave type material only - short tm_cde = GetNameClassId( "type material" ); + TTaxNameClass tm_cde = GetNameClassId( "type material" ); if ( tm_cde < 0 ) { SetLastError( "Name class for type material not found" ); ERR_POST_X( 19, GetLastError() ); @@ -2553,7 +2184,7 @@ CTaxon1::GetDisplayCommonName( TTaxId tax_id, string& disp_name_out ) if( m_plCache->LookupAndAdd( tax_id, &pNode ) && pNode && m_plCache->InitNameClasses() ) { tax_id = pNode->GetTaxId(); // get rid of secondary taxid - short cn = m_plCache->GetPreferredCommonNameClass(); + TTaxNameClass cn = m_plCache->GetPreferredCommonNameClass(); list< CRef< CTaxon1_name > > lNames; if( GetAllNamesEx(tax_id, lNames) ) { // 1) @@ -2628,5 +2259,32 @@ CTaxon1::GetDisplayCommonName( TTaxId tax_id, string& disp_name_out ) return true; } +//-------------------------------------------------- +// Get scientific name for taxonomy id +// Returns: false if some error occurred (name_out not changed) +// true if Ok +// name_out contains scientific name of this node +/// +bool +CTaxon1::GetScientificName(TTaxId tax_id, string& name_out) +{ + CTaxon1Node* pNode = 0; + SetLastError(NULL); + if( !TAXON1_IS_INITED ) { + if( !Init() ) { + return false; + } + } + if( m_plCache->LookupAndAdd( tax_id, &pNode ) && pNode ) { + if( !pNode->GetName().empty() ) { + name_out.assign( pNode->GetName() ); + return true; + } else { + SetLastError( "ERROR: No scientific name at the node" ); + } + } + return false; +} + END_objects_SCOPE END_NCBI_SCOPE diff --git a/c++/src/objects/taxon1/taxon1.def b/c++/src/objects/taxon1/taxon1.def index ec06b29f..321cfe29 100644 --- a/c++/src/objects/taxon1/taxon1.def +++ b/c++/src/objects/taxon1/taxon1.def @@ -5,9 +5,6 @@ _export = NCBI_TAXON1_EXPORT id4gi._type = ncbi::TGi id4gi._storage_type = ncbi::TIntId -[Taxon1-name] -taxid._type = ncbi::TTaxId - [Taxon1-info] ival1._type = ncbi::TEntrezId ival1._storage_type = ncbi::TIntId diff --git a/c++/src/objects/taxon1/utils.cpp b/c++/src/objects/taxon1/utils.cpp index 43ac8f6a..8fdcdf50 100644 --- a/c++/src/objects/taxon1/utils.cpp +++ b/c++/src/objects/taxon1/utils.cpp @@ -1,4 +1,4 @@ -/* $Id: utils.cpp 103491 2007-05-04 17:18:18Z kazimird $ +/* $Id: utils.cpp 526973 2017-02-08 15:57:04Z domrach $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,6 +37,8 @@ #include "ctreecont.hpp" #include "cache.hpp" +using namespace std; + BEGIN_NCBI_SCOPE BEGIN_objects_SCOPE @@ -55,25 +57,25 @@ BEGIN_objects_SCOPE #define TXC_GBHIDE 0x40000000 #define TXC_STHIDE 0x80000000 -short +TTaxRank CTaxon1Node::GetRank() const { return ((m_ref->GetCde())&0xff)-1; } -short +TTaxDivision CTaxon1Node::GetDivision() const { return (m_ref->GetCde()>>8)&0x3f; } -short +TTaxGeneticCode CTaxon1Node::GetGC() const { return (m_ref->GetCde()>>(8+6))&0x3f; } -short +TTaxGeneticCode CTaxon1Node::GetMGC() const { return (m_ref->GetCde()>>(8+6+6))&0x3f; @@ -91,6 +93,143 @@ CTaxon1Node::IsGenBankHidden() const return m_ref->GetCde() & TXC_GBHIDE ? true : false; } +class PPredDbTagByName { + const string& m_name; +public: + PPredDbTagByName(const string& sName) : m_name(sName) {} + bool operator()( const COrg_ref::TDb::value_type& vt ) const { + return m_name.size()+10 == vt->GetDb().size() && + NStr::StartsWith( vt->GetDb(), "taxlookup" ) && + NStr::EndsWith( vt->GetDb(), m_name ); + } +}; + + +void +COrgrefProp::SetOrgrefProp( COrg_ref& org, const string& prop_name, const string& prop_val ) +{ + string sProp = "taxlookup$"+prop_name; + CRef< CDbtag > pDb( new CDbtag ); + pDb->SetDb( sProp ); + pDb->SetTag().SetStr( prop_val ); + // Find the prop_name first + if( org.IsSetDb() ) { + PPredDbTagByName ppdb( prop_name ); + COrg_ref::TDb::iterator i = find_if( org.SetDb().begin(), org.SetDb().end(), ppdb ); + if( i != org.SetDb().end() ) { + *i = pDb; + return; + } + } + org.SetDb().push_back( pDb ); +} + +void +COrgrefProp::SetOrgrefProp( COrg_ref& org, const string& prop_name, int prop_val ) +{ + string sProp = "taxlookup%"+prop_name; + CRef< CDbtag > pDb( new CDbtag ); + pDb->SetDb( sProp ); + pDb->SetTag().SetId( prop_val ); + // Find the prop_name first + if( org.IsSetDb() ) { + PPredDbTagByName ppdb( prop_name ); + COrg_ref::TDb::iterator i = find_if( org.SetDb().begin(), org.SetDb().end(), ppdb ); + if( i != org.SetDb().end() ) { + *i = pDb; + return; + } + } + org.SetDb().push_back( pDb ); +} + +void +COrgrefProp::SetOrgrefProp( COrg_ref& org, const string& prop_name, bool prop_val ) +{ + string sProp = "taxlookup?"+prop_name; + CRef< CDbtag > pDb( new CDbtag ); + pDb->SetDb( sProp ); + pDb->SetTag().SetId( prop_val ? 1 : 0 ); + // Find the prop_name first + if( org.IsSetDb() ) { + PPredDbTagByName ppdb( prop_name ); + COrg_ref::TDb::iterator i = find_if( org.SetDb().begin(), org.SetDb().end(), ppdb ); + if( i != org.SetDb().end() ) { + *i = pDb; + return; + } + } + org.SetDb().push_back( pDb ); +} + +bool +COrgrefProp::HasOrgrefProp( const COrg_ref& org, const string& prop_name ) +{ + if( org.IsSetDb() ) { + PPredDbTagByName ppdb( prop_name ); + COrg_ref::TDb::const_iterator i = find_if( org.GetDb().begin(), org.GetDb().end(), ppdb ); + return i != org.GetDb().end(); + } + return false; +} + +const string& +COrgrefProp::GetOrgrefProp( const COrg_ref& org, const string& prop_name ) +{ + if( org.IsSetDb() ) { + PPredDbTagByName ppdb( prop_name ); + COrg_ref::TDb::const_iterator i = find_if( org.GetDb().begin(), org.GetDb().end(), ppdb ); + if( i != org.GetDb().end() && (*i)->IsSetTag() && (*i)->GetTag().IsStr() ) { + return (*i)->GetTag().GetStr(); + } + } + return CNcbiEmptyString::Get(); +} + +// returns default value false if not found +bool +COrgrefProp::GetOrgrefPropBool( const COrg_ref& org, const string& prop_name ) +{ + if( org.IsSetDb() ) { + PPredDbTagByName ppdb( prop_name ); + COrg_ref::TDb::const_iterator i = find_if( org.GetDb().begin(), org.GetDb().end(), ppdb ); + if( i != org.GetDb().end() && (*i)->IsSetTag() && (*i)->GetTag().IsId() ) { + return (*i)->GetTag().GetId() != 0; + } + } + return false; +} + +// returns default value 0 if not found +int +COrgrefProp::GetOrgrefPropInt( const COrg_ref& org, const string& prop_name ) +{ + if( org.IsSetDb() ) { + PPredDbTagByName ppdb( prop_name ); + COrg_ref::TDb::const_iterator i = find_if( org.GetDb().begin(), org.GetDb().end(), ppdb ); + if( i != org.GetDb().end() && (*i)->IsSetTag() && (*i)->GetTag().IsId() ) { + return (*i)->GetTag().GetId(); + } + } + return 0; +} + +void +COrgrefProp::RemoveOrgrefProp( COrg_ref& org, const string& prop_name ) +{ + // Find the prop_name first + if( org.IsSetDb() ) { + for( COrg_ref::TDb::iterator i = org.SetDb().begin(); i != org.SetDb().end(); ) { + if( prop_name.size()+10 == (*i)->GetDb().size() && + NStr::StartsWith( (*i)->GetDb(), "taxlookup" ) && + NStr::EndsWith( (*i)->GetDb(), prop_name ) ) { + i = org.SetDb().erase(i); + } else { + ++i; + } + } + } +} END_objects_SCOPE END_NCBI_SCOPE diff --git a/c++/src/objects/taxon3/CMakeLists.taxon3.asn.txt b/c++/src/objects/taxon3/CMakeLists.taxon3.asn.txt new file mode 100644 index 00000000..0a657287 --- /dev/null +++ b/c++/src/objects/taxon3/CMakeLists.taxon3.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/taxon3/Makefile.taxon3.lib +# + +set(MODULE taxon3) +set(MODULE_IMPORT objects/seqfeat/seqfeat) +set(MODULE_PATH objects/taxon3) + +set(MODULE_EXT "asn") +add_library(taxon3 ${MODULE}__ ${MODULE}___ taxon3) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(taxon3 + seq xconnect +) diff --git a/c++/src/objects/taxon3/CMakeLists.txt b/c++/src/objects/taxon3/CMakeLists.txt new file mode 100644 index 00000000..26d818bd --- /dev/null +++ b/c++/src/objects/taxon3/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.taxon3.asn.txt) + diff --git a/c++/src/objects/taxon3/Makefile.taxon3.lib b/c++/src/objects/taxon3/Makefile.taxon3.lib index 90a35ed2..b74fc28a 100644 --- a/c++/src/objects/taxon3/Makefile.taxon3.lib +++ b/c++/src/objects/taxon3/Makefile.taxon3.lib @@ -1,7 +1,8 @@ -# $Id: Makefile.taxon3.lib 473759 2015-07-22 14:02:22Z holmesbr $ +# $Id: Makefile.taxon3.lib 542758 2017-08-02 14:34:21Z ivanov $ LIB = taxon3 -SRC = taxon3__ taxon3___ taxon3 cached_taxon3 +SRC = taxon3__ taxon3___ taxon3 +# cached_taxon3 DLL_LIB = xconnect diff --git a/c++/src/objects/taxon3/T3Data.cpp b/c++/src/objects/taxon3/T3Data.cpp index bc1e52c3..44b90d3d 100644 --- a/c++/src/objects/taxon3/T3Data.cpp +++ b/c++/src/objects/taxon3/T3Data.cpp @@ -1,4 +1,4 @@ -/* $Id: T3Data.cpp 431074 2014-04-01 15:57:25Z bollin $ +/* $Id: T3Data.cpp 542758 2017-08-02 14:34:21Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -23,10 +23,10 @@ * * =========================================================================== * - * Author: ....... + * Author: NCBI Staff * * File Description: - * ....... + * Convenience and optimization functions for CT3Data * * Remark: * This code was originally generated by application DATATOOL @@ -108,6 +108,24 @@ bool CT3Data::HasPlastids (void) const return rval; } +#define NO_FLAG(a,f) (( a & f ) == 0) + +void CT3Data::FilterOutDataParts( ITaxon3::fT3reply_parts to_remain ) +{ + if( NO_FLAG( to_remain, ITaxon3::eT3reply_org ) ) { + ResetOrg(); + SetOrg(); // empty org since it is mandatory + } + if( NO_FLAG( to_remain, ITaxon3::eT3reply_blast_lin ) ) { + ResetBlast_name_lineage(); + } + if( NO_FLAG( to_remain, ITaxon3::eT3reply_status ) ) { + ResetStatus(); + } + if( NO_FLAG( to_remain, ITaxon3::eT3reply_refresh ) ) { + ResetRefresh(); + } +} END_objects_SCOPE // namespace ncbi::objects:: diff --git a/c++/src/objects/taxon3/taxon3.cpp b/c++/src/objects/taxon3/taxon3.cpp index 565f10d8..32419b7e 100644 --- a/c++/src/objects/taxon3/taxon3.cpp +++ b/c++/src/objects/taxon3/taxon3.cpp @@ -1,4 +1,4 @@ -/* $Id: taxon3.cpp 475514 2015-08-10 15:53:39Z bollin $ +/* $Id: taxon3.cpp 542758 2017-08-02 14:34:21Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -65,7 +66,7 @@ CTaxon3::~CTaxon3() void CTaxon3::Init(void) { - static const STimeout def_timeout = { 120, 0 }; + static const STimeout def_timeout = { 20, 0 }; CTaxon3::Init(&def_timeout); } @@ -83,14 +84,23 @@ CTaxon3::Init(const STimeout* timeout, unsigned reconnect_attempts) } m_nReconnectAttempts = reconnect_attempts; - m_pchService = "TaxService3"; + + CNcbiEnvironment env; + bool bFound = false; + + m_sService = env.Get("NI_SERVICE_NAME_TAXON3", &bFound); + if( !bFound ) { + m_sService = env.Get("NI_TAXON3_SERVICE_NAME", &bFound); + if( !bFound ) { + m_sService = "TaxService3"; + } + } #ifdef USE_TEXT_ASN - m_eDataFormat = eSerial_AsnText; + m_eDataFormat = eSerial_AsnText; #else - m_eDataFormat = eSerial_AsnBinary; + m_eDataFormat = eSerial_AsnBinary; #endif - } @@ -106,9 +116,8 @@ CTaxon3::SendRequest(const CTaxon3_request& request) auto_ptr pOut; auto_ptr pIn; auto_ptr - pServer( new CConn_ServiceStream(m_pchService, fSERV_Any, - 0, 0, m_timeout) ); - + pServer( new CConn_ServiceStream(m_sService, fSERV_Any, + 0, 0, m_timeout) ); pOut.reset( CObjectOStream::Open(m_eDataFormat, *pServer) ); pIn.reset( CObjectIStream::Open(m_eDataFormat, *pServer) ); @@ -158,20 +167,69 @@ CTaxon3::SetLastError( const char* pchErr ) } -CRef CTaxon3::SendOrgRefList(const vector >& list) +CRef CTaxon3::SendOrgRefList(const vector >& list, + COrg_ref::fOrgref_parts result_parts, + fT3reply_parts t3reply_parts) +{ + CTaxon3_request request; + if( result_parts != COrg_ref::eOrgref_default || + t3reply_parts != eT3reply_default ) { + CRef rq(new CT3Request); + rq->SetJoin().Set().push_back( -result_parts ); + rq->SetJoin().Set().push_back( -t3reply_parts ); // set return parts + request.SetRequest().push_back(rq); + } + ITERATE (vector >, it, list) { + CRef rq(new CT3Request); + CRef org(new COrg_ref); + org->Assign(**it); + rq->SetOrg(*org); + request.SetRequest().push_back(rq); + } + return SendRequest (request); +} + +CRef< CTaxon3_reply > +CTaxon3::SendNameList(const vector& list, + COrg_ref::fOrgref_parts result_parts, + fT3reply_parts t3reply_parts) { - // Open connection to Taxonomy service CTaxon3_request request; - ITERATE (vector >, it, list) { + if( result_parts != COrg_ref::eOrgref_default || + t3reply_parts != eT3reply_default ) { + CRef rq(new CT3Request); + rq->SetJoin().Set().push_back( -result_parts ); + rq->SetJoin().Set().push_back( -t3reply_parts ); // set return parts + request.SetRequest().push_back(rq); + } + ITERATE (vector, it, list) { CRef rq(new CT3Request); - CRef org(new COrg_ref); - org->Assign(**it); - rq->SetOrg(*org); - request.SetRequest().push_back(rq); - } - return SendRequest (request); + rq->SetName(*it); + request.SetRequest().push_back(rq); + } + return SendRequest (request); } +CRef< CTaxon3_reply > +CTaxon3::SendTaxidList(const vector& list, + COrg_ref::fOrgref_parts result_parts, + fT3reply_parts t3reply_parts) +{ + CTaxon3_request request; + if( result_parts != COrg_ref::eOrgref_default || + t3reply_parts != eT3reply_default ) { + CRef rq(new CT3Request); + rq->SetJoin().Set().push_back( -result_parts ); + rq->SetJoin().Set().push_back( -t3reply_parts ); // set return parts + request.SetRequest().push_back(rq); + } + ITERATE (vector, it, list) { + CRef rq(new CT3Request); + rq->SetTaxid(*it); + request.SetRequest().push_back(rq); + } + return SendRequest (request); +} END_objects_SCOPE diff --git a/c++/src/objects/tinyseq/CMakeLists.tinyseq.asn.txt b/c++/src/objects/tinyseq/CMakeLists.tinyseq.asn.txt new file mode 100644 index 00000000..1dbfe3c5 --- /dev/null +++ b/c++/src/objects/tinyseq/CMakeLists.tinyseq.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/tinyseq/Makefile.tinyseq.lib +# + +set(MODULE tinyseq) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/tinyseq) + +set(MODULE_EXT "asn") +add_library(tinyseq ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(tinyseq + xser +) \ No newline at end of file diff --git a/c++/src/objects/tinyseq/CMakeLists.txt b/c++/src/objects/tinyseq/CMakeLists.txt new file mode 100644 index 00000000..98afadca --- /dev/null +++ b/c++/src/objects/tinyseq/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.tinyseq.asn.txt) + diff --git a/c++/src/objects/trackmgr/CMakeLists.trackmgr.asn.txt b/c++/src/objects/trackmgr/CMakeLists.trackmgr.asn.txt new file mode 100644 index 00000000..624556e3 --- /dev/null +++ b/c++/src/objects/trackmgr/CMakeLists.trackmgr.asn.txt @@ -0,0 +1,21 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/trackmgr/Makefile.trackmgr.lib +# + +set(MODULE trackmgr) +set(MODULE_IMPORT objects/seqloc/seqloc objects/general/general) +set(MODULE_PATH objects/trackmgr) + +set(MODULE_EXT "asn") +add_library(trackmgr ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(trackmgr + seq +) \ No newline at end of file diff --git a/c++/src/objects/trackmgr/CMakeLists.trackmgrcli.lib.txt b/c++/src/objects/trackmgr/CMakeLists.trackmgrcli.lib.txt new file mode 100644 index 00000000..c601480f --- /dev/null +++ b/c++/src/objects/trackmgr/CMakeLists.trackmgrcli.lib.txt @@ -0,0 +1,10 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/trackmgr/Makefile.trackmgrcli.lib +# +add_library(trackmgrcli + trackmgr_client trackmgr_client_ +) + +target_link_libraries(trackmgrcli + trackmgr xconnect +) diff --git a/c++/src/objects/trackmgr/CMakeLists.trackmgrgridcli.lib.txt b/c++/src/objects/trackmgr/CMakeLists.trackmgrgridcli.lib.txt new file mode 100644 index 00000000..d89583af --- /dev/null +++ b/c++/src/objects/trackmgr/CMakeLists.trackmgrgridcli.lib.txt @@ -0,0 +1,12 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/trackmgr/Makefile.trackmgrgridcli.lib +# +add_library(trackmgrgridcli + tms_exception blast_client displaytrack_client createusertrack_client + removeusertrack_client item_resolver_client switch_context_client + track_attrvalue_client +) + +target_link_libraries(trackmgrgridcli + trackmgr xcompress xconnserv +) diff --git a/c++/src/objects/trackmgr/CMakeLists.txt b/c++/src/objects/trackmgr/CMakeLists.txt new file mode 100644 index 00000000..c0faec95 --- /dev/null +++ b/c++/src/objects/trackmgr/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.trackmgrcli.lib.txt) +include(CMakeLists.trackmgrgridcli.lib.txt) +include(CMakeLists.trackmgr.asn.txt) + diff --git a/c++/src/objects/trackmgr/trackmgr.asn b/c++/src/objects/trackmgr/trackmgr.asn index e9c7640e..23a34cac 100644 --- a/c++/src/objects/trackmgr/trackmgr.asn +++ b/c++/src/objects/trackmgr/trackmgr.asn @@ -1,4 +1,4 @@ ---- $Id: trackmgr.asn 498762 2016-04-19 15:46:52Z clausen $ +--- $Id: trackmgr.asn 525201 2017-01-19 21:58:31Z meric $ --- --- Definitions for the TrackManager service --- @@ -55,7 +55,11 @@ TMgr-GenomeContext ::= CHOICE { assembly TMgr-AssemblySpec, sequence Seq-id, refseqgene NULL, - all NULL + all NULL, + assembly-and-sequence SEQUENCE { + assembly TMgr-AssemblySpec, + sequence Seq-id + } } TMgr-ClientInfo ::= SEQUENCE { @@ -79,8 +83,9 @@ TMgr-DisplayTrackRequest ::= SEQUENCE { authorization TMgr-TrackACL-Authorization OPTIONAL, flags SEQUENCE { include-stats BOOLEAN DEFAULT FALSE, - include-default-tracks BOOLEAN OPTIONAL, - include-track-items BOOLEAN DEFAULT FALSE + include-default-tracks BOOLEAN DEFAULT FALSE, + include-track-items BOOLEAN DEFAULT FALSE, + expanded-rid-details BOOLEAN DEFAULT FALSE } OPTIONAL } @@ -93,6 +98,16 @@ TMgr-DisplayTrackReply ::= SEQUENCE { TMgr-DTrackId ::= Dbtag +TMgr-SeqTrackIdRequest ::= SEQUENCE { + seq-accession VisibleString +} + +TMgr-SeqTrackIdReply ::= SEQUENCE { + status TMgr-Status, + messages SET OF TMgr-Message OPTIONAL, + dtrack-id TMgr-DTrackId OPTIONAL +} + TMgr-SwitchTrackContextRequest ::= SEQUENCE { client TMgr-ClientInfo, new-genome-context TMgr-GenomeContext, @@ -229,7 +244,10 @@ TMgr-BlastQuerySeq ::= SEQUENCE { TMgr-BlastRIDDetail ::= SEQUENCE { rid VisibleString, title VisibleString OPTIONAL, - query-sequences SEQUENCE OF TMgr-BlastQuerySeq OPTIONAL + query-sequences SEQUENCE OF TMgr-BlastQuerySeq OPTIONAL, + created INTEGER OPTIONAL, -- seconds since unix epoch, 00:00:00 UTC on 1 January 1970 + database VisibleString OPTIONAL, + program VisibleString OPTIONAL } TMgr-BlastRIDReply ::= SEQUENCE { diff --git a/c++/src/objects/trackmgr/trackmgr.def b/c++/src/objects/trackmgr/trackmgr.def index 6daccd48..92e33591 100644 --- a/c++/src/objects/trackmgr/trackmgr.def +++ b/c++/src/objects/trackmgr/trackmgr.def @@ -17,3 +17,6 @@ min._type = TSeqPos max._type = TSeqPos mean._type = TSeqPos +[TMgr-BlastRIDDetail] +created._type = time_t + diff --git a/c++/src/objects/trackmgr/trackmgr_client.cpp b/c++/src/objects/trackmgr/trackmgr_client.cpp index e7dc238c..8860ebd6 100644 --- a/c++/src/objects/trackmgr/trackmgr_client.cpp +++ b/c++/src/objects/trackmgr/trackmgr_client.cpp @@ -1,4 +1,4 @@ -/* $Id: trackmgr_client.cpp 450827 2014-10-30 18:38:02Z grichenk $ +/* $Id: trackmgr_client.cpp 542061 2017-07-25 17:14:08Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -126,6 +126,66 @@ CTrackMgrClient::s_Ask(const CTMgr_DisplayTrackRequest& request) : CRef(); } +bool CTrackMgrClient::ParseAlignId (const string& external_id, + TAlignIDs& parsed_ids) +{ + using TStrIDs = vector; + + string delim[3] = {";", ":", ","}; + + TStrIDs vec1; + NStr::Split(external_id, delim[0], vec1, 0, NULL); + for (auto tok1 : vec1) + { + parsed_ids.push_back(SAlignIds()); + + int batch_id = + NStr::StringToNumeric(tok1, NStr::fConvErr_NoThrow, 10); + if (batch_id != 0) { + parsed_ids.back().batch_id = batch_id; + continue; + } + + TStrIDs vec2; + NStr::Split(tok1, delim[1], vec2, 0, NULL); + int i = -1; + for (auto tok2 : vec2) + { + ++i; + if (i % 2 == 0) + { + int id = NStr::StringToNumeric(tok2, + NStr::fConvErr_NoThrow, + 10); + if (id != 0) { + parsed_ids.back().batch_id = id; + continue; + } + else if (i % 2 == 0) { + return false; + } + } + + TStrIDs vec3; + NStr::Split(tok2, delim[2], vec3, 0, NULL); + for (auto tok3 : vec3) + { + int align_id = NStr::StringToNumeric + (tok3, NStr::fConvErr_NoThrow, 10); + if (align_id != 0) + { + parsed_ids.back().align_ids.push_back(align_id); + } + else + { + return false; + } + } + } + + } + return true; +} END_objects_SCOPE END_NCBI_SCOPE diff --git a/c++/src/objects/valerr/CMakeLists.txt b/c++/src/objects/valerr/CMakeLists.txt new file mode 100644 index 00000000..69277517 --- /dev/null +++ b/c++/src/objects/valerr/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.valerr.asn.txt) + diff --git a/c++/src/objects/valerr/CMakeLists.valerr.asn.txt b/c++/src/objects/valerr/CMakeLists.valerr.asn.txt new file mode 100644 index 00000000..ffdbb361 --- /dev/null +++ b/c++/src/objects/valerr/CMakeLists.valerr.asn.txt @@ -0,0 +1,24 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/valerr/Makefile.valerr.lib +# + +set(MODULE valerr) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/valerr) + +set(MODULE_EXT "asn") +add_library(valerr ${MODULE}__ ${MODULE}___) +add_dependencies(valerr + seqset +) + + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(valerr + xser +) \ No newline at end of file diff --git a/c++/src/objects/valerr/ValidErrItem.cpp b/c++/src/objects/valerr/ValidErrItem.cpp index 2fce2fa1..c11cc016 100644 --- a/c++/src/objects/valerr/ValidErrItem.cpp +++ b/c++/src/objects/valerr/ValidErrItem.cpp @@ -1,4 +1,4 @@ -/* $Id: ValidErrItem.cpp 519224 2016-11-14 16:08:42Z ivanov $ +/* $Id: ValidErrItem.cpp 547746 2017-10-03 17:56:09Z fukanchi $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -315,7 +315,12 @@ static const TErrTypStrs sc_ErrStrs[] = { { eErr_SEQ_INST_AllNs, { "AllNs", "Sequence has only Ns." } }, - + { eErr_SEQ_INST_FarLocationExcludesFeatures, + { "FarLocationExcludesFeatures", + "Scaffold points to sequence that has features outside the location." } }, + { eErr_SEQ_INST_ProteinShouldNotHaveGaps, + { "ProteinShouldNotHaveGaps", + "Protein sequences should not have gaps" } }, /* SEQ_DESCR */ @@ -675,6 +680,9 @@ static const TErrTypStrs sc_ErrStrs[] = { { eErr_SEQ_DESCR_TitleNotAppropriateForSet, { "TitleNotAppropriateForSet", "Only population study, phylogenetic study, ecological sample study, and mutation sets should have title descriptors." } }, + { eErr_SEQ_DESCR_StrainContainsTaxInfo, + { "StrainContainsTaxInfo", + "Strain contains taxonomic name information" } }, /* SEQ_GENERIC */ @@ -782,7 +790,13 @@ static const TErrTypStrs sc_ErrStrs[] = { "Barcode test passes." } }, { eErr_GENERIC_InvalidAsn, { "InvalidAsn", - "Invalid ASN.1" } }, +"Invalid ASN.1" } }, + { eErr_GENERIC_ServiceError, + { "ServiceError", +"Service failure prevented complete validation" } }, + { eErr_GENERIC_DuplicateIDs, + { "DuplicateIDs", +"Colliding sequence identifiers prevented loading into the object manager." } }, /* SEQ_PKG */ @@ -1673,6 +1687,15 @@ same id type" } }, { eErr_SEQ_FEAT_BadLocation, { "BadLocation", "There is a problem with this feature location." } }, + { eErr_SEQ_FEAT_GenCodeInvalid, + { "GenCodeInvalid", +"A coding region contains invalid genetic code." } }, + { eErr_SEQ_FEAT_TranslExceptIsPartial, + { "TranslExceptIsPartial", +"A translation exception location should not be partial." } }, + { eErr_SEQ_FEAT_GeneIdMismatch, + { "GeneIdMismatch", +"GeneID for parent and child features should match." } }, /* SEQ_ALIGN */ @@ -1939,6 +1962,38 @@ CValidErrItem::CValidErrItem } +void CValidErrItem::SetFeatureObjDescFromFields() +{ + // Add feature part of label + string desc = "FEATURE: "; + if (IsSetObj_content()) { + desc += GetObj_content(); + } + + // Add feature ID part of label (if present) + if (IsSetFeatureId()) { + desc += " <" + GetFeatureId() + "> "; + } + + // Add feature location part of label + if (IsSetLocation()) { + desc += " [" + GetLocation() + "]"; + } + + // Append label for bioseq of feature location + if (IsSetBioseq()) { + desc += GetBioseq(); + } + + // Append label for product of feature + if (IsSetProduct_loc()) { + desc += " -> " + GetProduct_loc(); + } + + SetObjDesc(desc); +} + + // destructor CValidErrItem::~CValidErrItem(void) { @@ -1951,7 +2006,7 @@ const string CValidErrItem::GetErrCode(void) const } -unsigned int CValidErrItem::GetErrCount(void) +size_t CValidErrItem::GetErrCount(void) { return sc_ErrStrsMap.size(); } @@ -2032,6 +2087,12 @@ bool CValidErrItem::IsSetObject(void) const } +void CValidErrItem::SetObject(const CSerialObject& obj) +{ + m_Object.Reset(&obj); +} + + const string CValidErrItem::ConvertSeverity(EDiagSev sev) { static const char* str_sev[] = { diff --git a/c++/src/objects/valerr/ValidError.cpp b/c++/src/objects/valerr/ValidError.cpp index 596b97d7..7eda15c6 100644 --- a/c++/src/objects/valerr/ValidError.cpp +++ b/c++/src/objects/valerr/ValidError.cpp @@ -1,4 +1,4 @@ -/* $Id: ValidError.cpp 513779 2016-09-15 11:23:57Z ivanov $ +/* $Id: ValidError.cpp 538704 2017-06-13 16:56:44Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -63,12 +63,16 @@ void CValidError::AddValidErrItem const CSerialObject& obj, const string& acc, const int ver, + const string& location, const int seq_offset) { if (ShouldSuppress(ec)) { return; } CRef item(new CValidErrItem(sev, ec, msg, desc, obj, acc, ver, seq_offset)); + if (!NStr::IsBlank(location)) { + item->SetLocation(location); + } SetErrs().push_back(item); m_Stats[item->GetSeverity()]++; } @@ -83,12 +87,16 @@ void CValidError::AddValidErrItem const string& acc, const int ver, const string& feature_id, + const string& location, const int seq_offset) { if (ShouldSuppress(ec)) { return; } CRef item(new CValidErrItem(sev, ec, msg, desc, obj, acc, ver, feature_id, seq_offset)); + if (!NStr::IsBlank(location)) { + item->SetLocation(location); + } SetErrs().push_back(item); m_Stats[item->GetSeverity()]++; } @@ -131,6 +139,24 @@ void CValidError::AddValidErrItem(EDiagSev sev, unsigned int ec, const string& m } +void CValidError::AddValidErrItem(CRef item) +{ + if (!item || !item->IsSetErrIndex()) { + return; + } + if (ShouldSuppress(item->GetErrIndex())) { + return; + } + if (!item->IsSetSev()) { + item->SetSev(eDiag_Info); + } + item->SetErrorName(CValidErrItem::ConvertErrCode(item->GetErrIndex())); + item->SetErrorGroup(CValidErrItem::ConvertErrGroup(item->GetErrIndex())); + SetErrs().push_back(item); + m_Stats[item->GetSeverity()]++; +} + + void CValidError::SuppressError(unsigned int ec) { m_SuppressionList.push_back(ec); diff --git a/c++/src/objects/valerr/valerr.asn b/c++/src/objects/valerr/valerr.asn index f97d9623..b311eca1 100644 --- a/c++/src/objects/valerr/valerr.asn +++ b/c++/src/objects/valerr/valerr.asn @@ -1,4 +1,4 @@ ---$Revision: 340608 $ +--$Revision: 538704 $ --********************************************************************** -- -- NCBI Validator Errors @@ -42,7 +42,12 @@ ValidErrItem ::= SEQUENCE { errorName VisibleString OPTIONAL, errorGroup VisibleString OPTIONAL, accnver VisibleString OPTIONAL, - version INTEGER OPTIONAL + version INTEGER OPTIONAL, + location VisibleString OPTIONAL, + product-loc VisibleString OPTIONAL, + bioseq VisibleString OPTIONAL, + locus-tag VisibleString OPTIONAL, + obj-content VisibleString OPTIONAL } diff --git a/c++/src/objects/valid/CMakeLists.txt b/c++/src/objects/valid/CMakeLists.txt new file mode 100644 index 00000000..135400c4 --- /dev/null +++ b/c++/src/objects/valid/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.valid.asn.txt) + diff --git a/c++/src/objects/valid/CMakeLists.valid.asn.txt b/c++/src/objects/valid/CMakeLists.valid.asn.txt new file mode 100644 index 00000000..a29f35f0 --- /dev/null +++ b/c++/src/objects/valid/CMakeLists.valid.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/valid/Makefile.valid.lib +# + +set(MODULE valid) +set(MODULE_IMPORT ) +set(MODULE_PATH ) + +set(MODULE_EXT "asn") +add_library(valid ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + general-lib xregexp +) + +target_link_libraries(valid + general-lib xregexp +) \ No newline at end of file diff --git a/c++/src/objects/valid/Comment_rule.cpp b/c++/src/objects/valid/Comment_rule.cpp index 685b3231..6301bd37 100644 --- a/c++/src/objects/valid/Comment_rule.cpp +++ b/c++/src/objects/valid/Comment_rule.cpp @@ -1,4 +1,4 @@ -/* $Id: Comment_rule.cpp 491404 2016-02-04 17:37:54Z bollin $ +/* $Id: Comment_rule.cpp 540400 2017-07-06 15:47:41Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -287,8 +287,6 @@ CComment_rule::TErrorList CComment_rule::IsValid(const CUser_object& user) const { TErrorList errors; - CField_rule::TSeverity sev; - CField_set::Tdata::const_iterator field_rule = GetFields().Get().begin(); CUser_object::TData::const_iterator field = user.GetData().begin(); while (field_rule != GetFields().Get().end() diff --git a/c++/src/objects/valid/Comment_set.cpp b/c++/src/objects/valid/Comment_set.cpp index 97865647..96bb3fca 100644 --- a/c++/src/objects/valid/Comment_set.cpp +++ b/c++/src/objects/valid/Comment_set.cpp @@ -1,4 +1,4 @@ -/* $Id: Comment_set.cpp 498903 2016-04-20 15:50:10Z ivanov $ +/* $Id: Comment_set.cpp 527196 2017-02-10 13:36:16Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -108,8 +108,10 @@ static void s_InitializeStructuredCommentRules(void) in.reset(CObjectIStream::Open(file, eSerial_AsnText)); string header = in->ReadFileHeader(); in->Read(ObjectInfo(*s_CommentRules), CObjectIStream::eNoFileHeader); + LOG_POST("Reading from " + file + " for structured comment rules."); } if (!s_CommentRules->IsSet()) { + LOG_POST("Falling back on built-in data for structured comment rules"); size_t num_lines = sizeof (s_Defaultvalidrules) / sizeof (char *); string all_rules = ""; for (size_t i = 0; i < num_lines; i++) { diff --git a/c++/src/objects/valid/validrules.inc b/c++/src/objects/valid/validrules.inc index 06aa1fcc..86979512 100644 --- a/c++/src/objects/valid/validrules.inc +++ b/c++/src/objects/valid/validrules.inc @@ -1,4 +1,4 @@ -/* $Id: validrules.inc 520820 2016-12-01 18:51:57Z ivanov $ +/* $Id: validrules.inc 535585 2017-05-10 12:44:17Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -520,7 +520,7 @@ static const char* const s_Defaultvalidrules[] = { " fields {", " {", " field-name \"investigation_type\" ,", - " match-expression \"^\\(mimarks-survey\\|mimarks-culture\\)$\" ,", + " match-expression \"^\\(mimarks-survey\\|mimarks-culture\\|mimarks-specimen\\)$\" ,", " required TRUE ,", " severity info } ,", " {", @@ -741,7 +741,7 @@ static const char* const s_Defaultvalidrules[] = { " fields {", " {", " field-name \"investigation_type\" ,", - " match-expression \"^\\(mimarks-survey\\|mimarks-culture\\)$\" ,", + " match-expression \"^\\(mimarks-survey\\|mimarks-culture\\|mimarks-specimen\\)$\" ,", " required TRUE ,", " severity info } ,", " {", @@ -1086,6 +1086,52 @@ static const char* const s_Defaultvalidrules[] = { " } ,", " require-order TRUE ,", " allow-unlisted FALSE ", + " },", + " {", + " prefix \"##HumanSTR-START##\" ,", + " fields {", + " {", + " field-name \"STR locus name\" ,", + " required TRUE } ,", + " {", + " field-name \"STR locus alt. name\" ,", + " required FALSE } ,", + " {", + " field-name \"Length-based allele\" ,", + " required TRUE } ,", + " {", + " field-name \"Bracketed repeat\" ,", + " required TRUE } ,", + " {", + " field-name \"Sequencing technology\" ,", + " required FALSE } ,", + " {", + " field-name \"Coverage\" ,", + " required FALSE } ,", + " {", + " field-name \"Length-based tech.\" ,", + " required FALSE } ,", + " {", + " field-name \"Assembly\" ,", + " required FALSE } ,", + " {", + " field-name \"Chromosome\" ,", + " required FALSE } ,", + " {", + " field-name \"RefSeq Accession\" ,", + " required FALSE } ,", + " {", + " field-name \"Chrom. Location\" ,", + " required FALSE } ,", + " {", + " field-name \"Repeat Location\" ,", + " required FALSE } ,", + " {", + " field-name \"Cytogenetic Location\" ,", + " required FALSE }", + " } ,", + " require-order TRUE ,", + " allow-unlisted FALSE", " }", "}", "" diff --git a/c++/src/objects/valid/validrules.prt b/c++/src/objects/valid/validrules.prt index 84445083..045003f5 100644 --- a/c++/src/objects/valid/validrules.prt +++ b/c++/src/objects/valid/validrules.prt @@ -487,7 +487,7 @@ nelle\)$" , fields { { field-name "investigation_type" , - match-expression "^\(mimarks-survey\|mimarks-culture\)$" , + match-expression "^\(mimarks-survey\|mimarks-culture\|mimarks-specimen\)$" , required TRUE , severity info } , { @@ -708,7 +708,7 @@ nelle\)$" , fields { { field-name "investigation_type" , - match-expression "^\(mimarks-survey\|mimarks-culture\)$" , + match-expression "^\(mimarks-survey\|mimarks-culture\|mimarks-specimen\)$" , required TRUE , severity info } , { @@ -1053,6 +1053,52 @@ AR\|APR\|MAY\|JUN\|JUL\|AUG\|SEP\|OCT\|NOV\|DEC\)-\(19\|20\)\(0\|1\|2\|3\|4\|5 } , require-order TRUE , allow-unlisted FALSE + }, + { + prefix "##HumanSTR-START##" , + fields { + { + field-name "STR locus name" , + required TRUE } , + { + field-name "STR locus alt. name" , + required FALSE } , + { + field-name "Length-based allele" , + required TRUE } , + { + field-name "Bracketed repeat" , + required TRUE } , + { + field-name "Sequencing technology" , + required FALSE } , + { + field-name "Coverage" , + required FALSE } , + { + field-name "Length-based tech." , + required FALSE } , + { + field-name "Assembly" , + required FALSE } , + { + field-name "Chromosome" , + required FALSE } , + { + field-name "RefSeq Accession" , + required FALSE } , + { + field-name "Chrom. Location" , + required FALSE } , + { + field-name "Repeat Location" , + required FALSE } , + { + field-name "Cytogenetic Location" , + required FALSE } + } , + require-order TRUE , + allow-unlisted FALSE } } diff --git a/c++/src/objects/variation/CMakeLists.txt b/c++/src/objects/variation/CMakeLists.txt new file mode 100644 index 00000000..aca71acc --- /dev/null +++ b/c++/src/objects/variation/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.variation.asn.txt) + diff --git a/c++/src/objects/variation/CMakeLists.variation.asn.txt b/c++/src/objects/variation/CMakeLists.variation.asn.txt new file mode 100644 index 00000000..84f49567 --- /dev/null +++ b/c++/src/objects/variation/CMakeLists.variation.asn.txt @@ -0,0 +1,20 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objects/variation/Makefile.variation.lib +# + +set(MODULE variation) +set(MODULE_IMPORT objects/seqfeat/seqfeat objects/general/general objects/seqloc/seqloc objects/pub/pub objects/seq/seq) +set(MODULE_PATH objects/variation) + +set(MODULE_EXT "asn") +add_library(variation ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") + +target_link_libraries(${MODULE} + seq +) + +target_link_libraries(variation + seq +) \ No newline at end of file diff --git a/c++/src/objects/varrep/CMakeLists.txt b/c++/src/objects/varrep/CMakeLists.txt new file mode 100644 index 00000000..34c033b5 --- /dev/null +++ b/c++/src/objects/varrep/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.varrep.asn.txt) + diff --git a/c++/src/objects/varrep/CMakeLists.varrep.asn.txt b/c++/src/objects/varrep/CMakeLists.varrep.asn.txt new file mode 100644 index 00000000..586763ef --- /dev/null +++ b/c++/src/objects/varrep/CMakeLists.varrep.asn.txt @@ -0,0 +1,21 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/gpipe-trunk.clean/src/objects/varrep/Makefile.varrep.lib +# + +set(MODULE varrep) +set(MODULE_IMPORT ) +set(MODULE_PATH objects/varrep) + +set(MODULE_EXT "asn") +add_library(varrep ${MODULE}__ ${MODULE}___) + +RunDatatool("${MODULE}" "${MODULE_IMPORT}") +SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}__.cpp ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE}___.cpp PROPERTIES GENERATED 1) + +target_link_libraries(${MODULE} + xser +) + +target_link_libraries(varrep + xser +) \ No newline at end of file diff --git a/c++/src/objects/varrep/varrep.asn b/c++/src/objects/varrep/varrep.asn index 43f3e408..3b2637e6 100644 --- a/c++/src/objects/varrep/varrep.asn +++ b/c++/src/objects/varrep/varrep.asn @@ -63,6 +63,7 @@ SimpleVariant ::= SEQUENCE { na-identity NaIdentity, na-sub NaSub, prot-sub ProteinSub, + prot-silent AaLocation, del Deletion, dup Duplication, inv Inversion, diff --git a/c++/src/objmgr/CMakeLists.objmgr.lib.txt b/c++/src/objmgr/CMakeLists.objmgr.lib.txt new file mode 100644 index 00000000..ec230ffa --- /dev/null +++ b/c++/src/objmgr/CMakeLists.objmgr.lib.txt @@ -0,0 +1,27 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objmgr/Makefile.objmgr.lib +# +add_library(xobjmgr + seq_table_setters seq_table_info seq_annot_info table_field + seq_map_switch snp_annot_info annot_types_ci seq_loc_cvt annot_selector + seq_descr_ci feat_ci graph_ci annot_object annot_object_index annot_ci + tse_info tse_info_object seq_entry_info bioseq_base_info bioseq_set_info + bioseq_info data_source priority prefetch_impl prefetch_manager + prefetch_manager_impl prefetch_actions scope heap_scope scope_impl + scope_info tse_handle seq_map seq_map_ci seq_entry_ci seq_annot_ci + seq_table_ci seq_entry_handle bioseq_set_handle bioseq_handle + seq_annot_handle align_ci data_loader handle_range objmgr_exception + handle_range_map object_manager seq_vector seq_vector_ci seqdesc_ci + tse_split_info tse_chunk_info bioseq_ci annot_type_index seq_loc_mapper + seq_align_mapper annot_collector data_loader_factory mapped_feat + seq_feat_handle seq_graph_handle seq_align_handle tse_assigner + scope_transaction scope_transaction_impl edit_commands_impl + bioseq_edit_commands seq_entry_edit_commands bioseq_set_edit_commands + edit_saver unsupp_editsaver edits_db_engine edits_db_saver annot_finder + gc_assembly_parser split_parser seq_id_sort +) + +target_link_libraries(xobjmgr + genome_collection seqedit seqsplit +) + diff --git a/c++/src/objmgr/CMakeLists.txt b/c++/src/objmgr/CMakeLists.txt new file mode 100644 index 00000000..5f2720e6 --- /dev/null +++ b/c++/src/objmgr/CMakeLists.txt @@ -0,0 +1,11 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.objmgr.lib.txt) + +# Recurse subdirectories +add_subdirectory(test ) +add_subdirectory(util) +add_subdirectory(split) diff --git a/c++/src/objmgr/align_ci.cpp b/c++/src/objmgr/align_ci.cpp index 822cd680..bc7416a0 100644 --- a/c++/src/objmgr/align_ci.cpp +++ b/c++/src/objmgr/align_ci.cpp @@ -1,4 +1,4 @@ -/* $Id: align_ci.cpp 439368 2014-06-27 17:33:59Z vasilche $ +/* $Id: align_ci.cpp 536422 2017-05-18 14:44:05Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -128,6 +128,26 @@ CAlign_CI::CAlign_CI(const CSeq_annot_Handle& annot, } +CAlign_CI::CAlign_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot) + : CAnnotTypes_CI(CSeq_annot::C_Data::e_Align, + loc, + annot) +{ +} + + +CAlign_CI::CAlign_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot, + const SAnnotSelector& sel) + : CAnnotTypes_CI(CSeq_annot::C_Data::e_Align, + loc, + annot, + &sel) +{ +} + + CAlign_CI::CAlign_CI(const CSeq_entry_Handle& entry) : CAnnotTypes_CI(CSeq_annot::C_Data::e_Align, entry) { diff --git a/c++/src/objmgr/annot_collector.cpp b/c++/src/objmgr/annot_collector.cpp index 0dcc6228..cf4041bc 100644 --- a/c++/src/objmgr/annot_collector.cpp +++ b/c++/src/objmgr/annot_collector.cpp @@ -1,4 +1,4 @@ -/* $Id: annot_collector.cpp 519943 2016-11-21 15:34:20Z ivanov $ +/* $Id: annot_collector.cpp 538963 2017-06-15 17:46:51Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1568,6 +1568,8 @@ public: CAnnot_Collector::CAnnot_Collector(CScope& scope) : m_Selector(0), m_Scope(scope), + m_LoadBytes(0), + m_LoadSeconds(0), m_FromOtherTSE(false) { } @@ -1856,11 +1858,17 @@ void CAnnot_Collector::x_Initialize(const SAnnotSelector& selector, bool CAnnot_Collector::x_CheckAdaptive(const CBioseq_Handle& bh) const { int adaptive_flags = GetSelector().GetAdaptiveDepthFlags(); - if ( !(adaptive_flags & SAnnotSelector::fAdaptive_ByPolicy) && - (adaptive_flags & (SAnnotSelector::fAdaptive_ByTriggers | - SAnnotSelector::fAdaptive_BySubtypes)) ) { + if ( !(adaptive_flags & (SAnnotSelector::fAdaptive_ByTriggers | + SAnnotSelector::fAdaptive_BySubtypes)) ) { + // no heuristics return false; } + if ( !(adaptive_flags & SAnnotSelector::fAdaptive_ByPolicy) ) { + // heuristics only + return true; + } + // both policy and heuristics are active + // use heuristics only if there is no policy information on sequence return bh && bh.GetFeatureFetchPolicy() == bh.eFeatureFetchPolicy_default; } @@ -1868,11 +1876,17 @@ bool CAnnot_Collector::x_CheckAdaptive(const CBioseq_Handle& bh) const bool CAnnot_Collector::x_CheckAdaptive(const CSeq_id_Handle& id) const { int adaptive_flags = GetSelector().GetAdaptiveDepthFlags(); - if ( !(adaptive_flags & SAnnotSelector::fAdaptive_ByPolicy) && - (adaptive_flags & (SAnnotSelector::fAdaptive_ByTriggers | - SAnnotSelector::fAdaptive_BySubtypes)) ) { + if ( !(adaptive_flags & (SAnnotSelector::fAdaptive_ByTriggers | + SAnnotSelector::fAdaptive_BySubtypes)) ) { + // no heuristics return false; } + if ( !(adaptive_flags & SAnnotSelector::fAdaptive_ByPolicy) ) { + // heuristics only + return true; + } + // both policy and heuristics are active + // use heuristics only if there is no policy information on sequence CBioseq_Handle bh = x_GetBioseqHandle(id); return bh && bh.GetFeatureFetchPolicy() == bh.eFeatureFetchPolicy_default; } @@ -2764,6 +2778,9 @@ void CAnnot_Collector::x_SearchObjects(const CTSE_Handle& tseh, return; } } + if ( m_Selector->m_CollectCostOfLoading ) { + return; + } static const size_t kAnnotTypeIndex_SNP = CAnnotType_Index::GetSubtypeIndex(CSeqFeatData::eSubtype_variation); @@ -2926,6 +2943,15 @@ void CAnnot_Collector::x_SearchRange(const CTSE_Handle& tseh, // Skip chunk stub continue; } + if ( chunk.NotLoaded() && + m_Selector->m_CollectCostOfLoading && + chunk.GetChunkId() != CTSE_Chunk_Info::kDelayedMain_ChunkId ) { + // accumulate cost of chunks to be loaded + auto cost = chunk.GetLoadCost(); + m_LoadBytes += cost.first; + m_LoadSeconds += cost.second; + continue; + } if ( !restart ) { restart = true; // New annot objects are to be loaded, @@ -2944,6 +2970,9 @@ void CAnnot_Collector::x_SearchRange(const CTSE_Handle& tseh, _ASSERT(!enough); continue; } + if ( m_Selector->m_CollectCostOfLoading ) { + continue; + } if ( annot_info.IsLocs() ) { const CSeq_loc& ref_loc = annot_info.GetLocs(); @@ -3078,6 +3107,10 @@ void CAnnot_Collector::x_SearchRange(const CTSE_Handle& tseh, } } } + if ( enough ) { + _ASSERT(!restart); + break; + } continue; } @@ -3507,15 +3540,14 @@ bool CAnnot_Collector::x_SearchMapped(const CSeqMap_CI& seg, "search time limit exceeded, no annotations found"); } if ( m_SearchSegments != numeric_limits::max() && - x_MaxSearchSegmentsLimitIsReached() || - --m_SearchSegments == 0 ) { + (x_MaxSearchSegmentsLimitIsReached() || --m_SearchSegments == 0) ) { if ( m_SearchSegmentsAction == SAnnotSelector::eMaxSearchSegmentsThrow ) { NCBI_THROW(CAnnotSearchLimitException, eSegmentsLimitExceded, "CAnnot_Collector: " "search segments limit exceeded, no annotations found"); } if ( m_SearchSegmentsAction == SAnnotSelector::eMaxSearchSegmentsLog ) { - ERR_POST_X(2, "CAnnot_Collector: " + ERR_POST_X(2, Warning << "CAnnot_Collector: " "search segments limit exceeded, no annotations found"); } // stop searching @@ -3587,5 +3619,17 @@ CAnnot_Collector::x_GetAnnotNames(void) const } +Uint8 CAnnot_Collector::x_GetCostOfLoadingInBytes(void) const +{ + return m_LoadBytes; +} + + +double CAnnot_Collector::x_GetCostOfLoadingInSeconds(void) const +{ + return m_LoadSeconds; +} + + END_SCOPE(objects) END_NCBI_SCOPE diff --git a/c++/src/objmgr/annot_object_index.cpp b/c++/src/objmgr/annot_object_index.cpp index c6c25d6a..47a10b38 100644 --- a/c++/src/objmgr/annot_object_index.cpp +++ b/c++/src/objmgr/annot_object_index.cpp @@ -1,4 +1,4 @@ -/* $Id: annot_object_index.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: annot_object_index.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/annot_selector.cpp b/c++/src/objmgr/annot_selector.cpp index aea70d55..ab81ba93 100644 --- a/c++/src/objmgr/annot_selector.cpp +++ b/c++/src/objmgr/annot_selector.cpp @@ -1,4 +1,4 @@ -/* $Id: annot_selector.cpp 519943 2016-11-21 15:34:20Z ivanov $ +/* $Id: annot_selector.cpp 538306 2017-06-09 12:27:28Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -77,6 +77,7 @@ SAnnotSelector::SAnnotSelector(TAnnotType annot, m_CollectSeq_annots(false), m_CollectTypes(false), m_CollectNames(false), + m_CollectCostOfLoading(false), m_IgnoreStrand(false), m_FilterMask(0), m_FilterBits(0) @@ -108,6 +109,7 @@ SAnnotSelector::SAnnotSelector(TFeatType feat, m_CollectSeq_annots(false), m_CollectTypes(false), m_CollectNames(false), + m_CollectCostOfLoading(false), m_IgnoreStrand(false), m_FilterMask(0), m_FilterBits(0) @@ -135,6 +137,7 @@ SAnnotSelector::SAnnotSelector(TFeatSubtype feat_subtype) m_CollectSeq_annots(false), m_CollectTypes(false), m_CollectNames(false), + m_CollectCostOfLoading(false), m_IgnoreStrand(false), m_FilterMask(0), m_FilterBits(0) @@ -179,6 +182,7 @@ SAnnotSelector& SAnnotSelector::operator=(const SAnnotSelector& sel) m_CollectSeq_annots = sel.m_CollectSeq_annots; m_CollectTypes = sel.m_CollectTypes; m_CollectNames = sel.m_CollectNames; + m_CollectCostOfLoading = sel.m_CollectCostOfLoading; m_IgnoreStrand = sel.m_IgnoreStrand; m_FilterMask = sel.m_FilterMask; m_FilterBits = sel.m_FilterBits; diff --git a/c++/src/objmgr/annot_types_ci.cpp b/c++/src/objmgr/annot_types_ci.cpp index 118b262c..7456afbd 100644 --- a/c++/src/objmgr/annot_types_ci.cpp +++ b/c++/src/objmgr/annot_types_ci.cpp @@ -1,4 +1,4 @@ -/* $Id: annot_types_ci.cpp 519943 2016-11-21 15:34:20Z ivanov $ +/* $Id: annot_types_ci.cpp 536422 2017-05-18 14:44:05Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -187,6 +187,19 @@ CAnnotTypes_CI::CAnnotTypes_CI(TAnnotType type, } +CAnnotTypes_CI::CAnnotTypes_CI(TAnnotType type, + const CSeq_loc& loc, + const CSeq_annot_Handle& annot, + const SAnnotSelector* params) + : m_DataCollector(new CAnnot_Collector(annot.GetScope())) +{ + SAnnotSelector sel = params ? *params : SAnnotSelector(); + sel.ForceAnnotType(type) + .SetLimitSeqAnnot(annot); + x_Init(annot.GetScope(), loc, sel); +} + + CAnnotTypes_CI::CAnnotTypes_CI(TAnnotType type, const CSeq_entry_Handle& entry, const SAnnotSelector* params) diff --git a/c++/src/objmgr/bioseq_base_info.cpp b/c++/src/objmgr/bioseq_base_info.cpp index feb62a2e..af46c666 100644 --- a/c++/src/objmgr/bioseq_base_info.cpp +++ b/c++/src/objmgr/bioseq_base_info.cpp @@ -1,4 +1,4 @@ -/* $Id: bioseq_base_info.cpp 512047 2016-08-26 14:21:48Z ivanov $ +/* $Id: bioseq_base_info.cpp 511088 2016-08-18 15:44:06Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/bioseq_info.cpp b/c++/src/objmgr/bioseq_info.cpp index 71678007..5e0af0aa 100644 --- a/c++/src/objmgr/bioseq_info.cpp +++ b/c++/src/objmgr/bioseq_info.cpp @@ -1,4 +1,4 @@ -/* $Id: bioseq_info.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: bioseq_info.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/bioseq_set_info.cpp b/c++/src/objmgr/bioseq_set_info.cpp index 75ebb006..420485cf 100644 --- a/c++/src/objmgr/bioseq_set_info.cpp +++ b/c++/src/objmgr/bioseq_set_info.cpp @@ -1,4 +1,4 @@ -/* $Id: bioseq_set_info.cpp 507368 2016-07-18 21:33:41Z vasilche $ +/* $Id: bioseq_set_info.cpp 521281 2016-12-07 16:40:59Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -454,6 +454,44 @@ CConstRef CBioseq_set_Info::GetFirstEntry(void) const } +void CBioseq_set_Info::x_SetChunkBioseqs(const list< CRef >& bioseqs, int chunk_id) +{ + CBioseq_set::TSeq_set& obj_seq_set = m_Object->SetSeq_set(); + CBioseq_set::TSeq_set::iterator insert_iter = obj_seq_set.end(); + size_t seq_index = m_Seq_set.size(); + TChunkSeqSets::iterator chunk_iter = m_ChunkSeqSets.end(); + while ( chunk_iter != m_ChunkSeqSets.begin() ) { + --chunk_iter; + if ( chunk_iter->first > chunk_id ) { + seq_index -= chunk_iter->second.count; + insert_iter = chunk_iter->second.first_iter; + // verify consistency between obj_seq_set (in CBioseq_set) and m_Seq_set (in CBioseq_set_Info) + _ASSERT(seq_index < m_Seq_set.size()); + _ASSERT(m_Seq_set[seq_index]->GetSeq_entryCore() == *chunk_iter->second.first_iter); + continue; + } + // this chunk is before new one + ++chunk_iter; + break; + } + size_t insert_count = bioseqs.size(); + SChunkSeqSet& seq_set = m_ChunkSeqSets[chunk_id]; + m_Seq_set.insert(m_Seq_set.begin()+seq_index, insert_count, TSeq_set::value_type()); + for ( auto& i : bioseqs ) { + CRef entry(new CSeq_entry); + entry->SetSeq(i.GetNCObject()); + CRef info(new CSeq_entry_Info(*entry)); + CBioseq_set::TSeq_set::iterator added_iter = obj_seq_set.insert(insert_iter, entry); + if ( seq_set.count++ == 0 ) { + seq_set.first_iter = added_iter; + } + _ASSERT(!m_Seq_set[seq_index]); + m_Seq_set[seq_index++] = info; + x_AttachEntry(info); + } +} + + void CBioseq_set_Info::x_AttachEntry(CRef entry) { _ASSERT(!entry->HasParent_Info()); diff --git a/c++/src/objmgr/data_loader.cpp b/c++/src/objmgr/data_loader.cpp index 36eea408..ba64dba2 100644 --- a/c++/src/objmgr/data_loader.cpp +++ b/c++/src/objmgr/data_loader.cpp @@ -1,4 +1,4 @@ -/* $Id: data_loader.cpp 498345 2016-04-15 14:39:08Z vasilche $ +/* $Id: data_loader.cpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -843,6 +843,24 @@ CObjectManager::TPriority CDataLoader::GetDefaultPriority(void) const } +Uint4 CDataLoader::EstimateLoadBytes(const CTSE_Chunk_Info& /*chunk*/) const +{ + return 32000; // assume 32KB chunk size +} + + +double CDataLoader::EstimateLoadSeconds(const CTSE_Chunk_Info& /*chunk*/, Uint4 bytes) const +{ + return bytes*1e-7+0.001; // assume 10MB/s transfer speed and 1ms overhead +} + + +unsigned CDataLoader::GetDefaultBlobCacheSizeLimit(void) const +{ + return kMax_UInt; +} + + ///////////////////////////////////////////////////////////////////////////// // CBlobId diff --git a/c++/src/objmgr/data_source.cpp b/c++/src/objmgr/data_source.cpp index 02c33145..2358b115 100644 --- a/c++/src/objmgr/data_source.cpp +++ b/c++/src/objmgr/data_source.cpp @@ -1,4 +1,4 @@ -/* $Id: data_source.cpp 498345 2016-04-15 14:39:08Z vasilche $ +/* $Id: data_source.cpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -87,9 +87,23 @@ NCBI_DEFINE_ERR_SUBCODE_X(3); BEGIN_SCOPE(objects) +class CSeq_entry; + +NCBI_PARAM_DECL(unsigned, OBJMGR, BLOB_CACHE); +NCBI_PARAM_DEF_EX(unsigned, OBJMGR, BLOB_CACHE, 10, + eParam_NoThread, OBJMGR_BLOB_CACHE); + +unsigned CDataSource::GetDefaultBlobCacheSizeLimit(void) +{ + static CSafeStatic sx_Value; + return sx_Value->Get(); +} + + CDataSource::CDataSource(void) : m_DefaultPriority(CObjectManager::kPriority_Entry), - m_Blob_Cache_Size(0) + m_Blob_Cache_Size(0), + m_Blob_Cache_Size_Limit(GetDefaultBlobCacheSizeLimit()) { } @@ -97,7 +111,9 @@ CDataSource::CDataSource(void) CDataSource::CDataSource(CDataLoader& loader) : m_Loader(&loader), m_DefaultPriority(loader.GetDefaultPriority()), - m_Blob_Cache_Size(0) + m_Blob_Cache_Size(0), + m_Blob_Cache_Size_Limit(min(GetDefaultBlobCacheSizeLimit(), + loader.GetDefaultBlobCacheSizeLimit())) { m_Loader->SetTargetDataSource(*this); } @@ -106,7 +122,8 @@ CDataSource::CDataSource(CDataLoader& loader) CDataSource::CDataSource(const CObject& shared_object, const CSeq_entry& entry) : m_SharedObject(&shared_object), m_DefaultPriority(CObjectManager::kPriority_Entry), - m_Blob_Cache_Size(0) + m_Blob_Cache_Size(0), + m_Blob_Cache_Size_Limit(GetDefaultBlobCacheSizeLimit()) { CTSE_Lock tse_lock = AddTSE(const_cast(entry)); m_StaticBlobs.PutLock(tse_lock); @@ -298,8 +315,7 @@ bool CDataSource::DropTSE(CTSE_Info& info) _TRACE("DropTSE: DS="< sx_Value; - return sx_Value->Get(); -} - - void CDataSource::x_ReleaseLastTSELock(CRef tse) { if ( !m_Loader ) { @@ -1782,7 +1787,7 @@ void CDataSource::x_ReleaseLastTSELock(CRef tse) find(m_Blob_Cache.begin(), m_Blob_Cache.end(), tse)); _ASSERT(m_Blob_Cache_Size == m_Blob_Cache.size()); - unsigned cache_size = s_GetCacheSize(); + unsigned cache_size = m_Blob_Cache_Size_Limit; while ( m_Blob_Cache_Size > cache_size ) { CRef del_tse = m_Blob_Cache.front(); m_Blob_Cache.pop_front(); diff --git a/c++/src/objmgr/edits_db_saver.cpp b/c++/src/objmgr/edits_db_saver.cpp index 242f68af..44ee8a6c 100644 --- a/c++/src/objmgr/edits_db_saver.cpp +++ b/c++/src/objmgr/edits_db_saver.cpp @@ -1,4 +1,4 @@ -/* $Id: edits_db_saver.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: edits_db_saver.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/feat_ci.cpp b/c++/src/objmgr/feat_ci.cpp index 839c7be2..742fba67 100644 --- a/c++/src/objmgr/feat_ci.cpp +++ b/c++/src/objmgr/feat_ci.cpp @@ -1,4 +1,4 @@ -/* $Id: feat_ci.cpp 331631 2011-08-18 13:26:53Z kornbluh $ +/* $Id: feat_ci.cpp 536422 2017-05-18 14:44:05Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -182,6 +182,28 @@ CFeat_CI::CFeat_CI(const CSeq_annot_Handle& annot, } +CFeat_CI::CFeat_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot) + : CAnnotTypes_CI(CSeq_annot::C_Data::e_Ftable, + loc, + annot) +{ + Update(); +} + + +CFeat_CI::CFeat_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot, + const SAnnotSelector& sel) + : CAnnotTypes_CI(CSeq_annot::C_Data::e_Ftable, + loc, + annot, + &sel) +{ + Update(); +} + + CFeat_CI::CFeat_CI(const CSeq_entry_Handle& entry) : CAnnotTypes_CI(CSeq_annot::C_Data::e_Ftable, entry) diff --git a/c++/src/objmgr/gc_assembly_parser.cpp b/c++/src/objmgr/gc_assembly_parser.cpp index 01fa7ae0..412350a4 100644 --- a/c++/src/objmgr/gc_assembly_parser.cpp +++ b/c++/src/objmgr/gc_assembly_parser.cpp @@ -1,4 +1,4 @@ -/* $Id: gc_assembly_parser.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: gc_assembly_parser.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/graph_ci.cpp b/c++/src/objmgr/graph_ci.cpp index 03a7f86e..4ac6392d 100644 --- a/c++/src/objmgr/graph_ci.cpp +++ b/c++/src/objmgr/graph_ci.cpp @@ -1,4 +1,4 @@ -/* $Id: graph_ci.cpp 439336 2014-06-27 16:08:17Z vasilche $ +/* $Id: graph_ci.cpp 536422 2017-05-18 14:44:05Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -308,6 +308,28 @@ CGraph_CI::CGraph_CI(const CSeq_annot_Handle& annot, } +CGraph_CI::CGraph_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot) + : CAnnotTypes_CI(CSeq_annot::C_Data::e_Graph, + loc, + annot) +{ + x_Update(); +} + + +CGraph_CI::CGraph_CI(const CSeq_loc& loc, + const CSeq_annot_Handle& annot, + const SAnnotSelector& sel) + : CAnnotTypes_CI(CSeq_annot::C_Data::e_Graph, + loc, + annot, + &sel) +{ + x_Update(); +} + + CGraph_CI::CGraph_CI(const CSeq_entry_Handle& entry) : CAnnotTypes_CI(CSeq_annot::C_Data::e_Graph, entry) { diff --git a/c++/src/objmgr/mapped_feat.cpp b/c++/src/objmgr/mapped_feat.cpp index c729784e..f895f8e4 100644 --- a/c++/src/objmgr/mapped_feat.cpp +++ b/c++/src/objmgr/mapped_feat.cpp @@ -1,4 +1,4 @@ -/* $Id: mapped_feat.cpp 499886 2016-04-28 19:54:10Z vasilche $ +/* $Id: mapped_feat.cpp 526107 2017-01-31 17:17:26Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -157,12 +157,18 @@ const CSeq_feat& CMappedFeat::GetMappedFeature(void) const bool CMappedFeat::IsSetPartial(void) const { + if ( !m_MappingInfoPtr->IsMapped() ) { + return CSeq_feat_Handle::IsSetPartial(); + } return m_MappingInfoPtr->IsPartial(); } bool CMappedFeat::GetPartial(void) const { + if ( !m_MappingInfoPtr->IsMapped() ) { + return CSeq_feat_Handle::GetPartial(); + } return m_MappingInfoPtr->IsPartial(); } diff --git a/c++/src/objmgr/objmgr_exception.cpp b/c++/src/objmgr/objmgr_exception.cpp index 2a532095..24698bff 100644 --- a/c++/src/objmgr/objmgr_exception.cpp +++ b/c++/src/objmgr/objmgr_exception.cpp @@ -1,4 +1,4 @@ -/* $Id: objmgr_exception.cpp 493168 2016-02-24 19:28:38Z vasilche $ +/* $Id: objmgr_exception.cpp 541890 2017-07-24 13:05:52Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -139,6 +139,7 @@ const char* CObjmgrUtilException::GetErrCodeString(void) const case eUnknownLength: return "eUnknownLength"; case eBadResidue: return "eBadResidue"; case eBadFeature: return "eBadFeature"; + case eBadAlignment: return "eBadAlignment"; default: return CException::GetErrCodeString(); } } diff --git a/c++/src/objmgr/prefetch_actions.cpp b/c++/src/objmgr/prefetch_actions.cpp index bdaebfb1..16c08d18 100644 --- a/c++/src/objmgr/prefetch_actions.cpp +++ b/c++/src/objmgr/prefetch_actions.cpp @@ -1,4 +1,4 @@ -/* $Id: prefetch_actions.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: prefetch_actions.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/scope_impl.cpp b/c++/src/objmgr/scope_impl.cpp index 1ddfe397..71074280 100644 --- a/c++/src/objmgr/scope_impl.cpp +++ b/c++/src/objmgr/scope_impl.cpp @@ -1,4 +1,4 @@ -/* $Id: scope_impl.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: scope_impl.cpp 546021 2017-09-13 11:14:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -104,7 +104,11 @@ static bool sx_KeepExternalAnnotsForEdit(void) CScope_Impl::CScope_Impl(CObjectManager& objmgr) - : m_HeapScope(0), m_ObjMgr(0), m_Transaction(NULL) + : m_HeapScope(0), + m_ObjMgr(0), + m_Transaction(NULL), + m_BioseqChangeCounter(0), + m_AnnotChangeCounter(0) { TConfWriteLockGuard guard(m_ConfLock); x_AttachToOM(objmgr); @@ -958,8 +962,7 @@ void CScope_Impl::x_ClearCacheOnNewData(const TIds& seq_ids, CBioseq_ScopeInfo& binfo = *it2->second.m_Bioseq_Info; if ( !binfo.HasBioseq() ) { // try to resolve again - binfo.m_SynCache.Reset(); // break circular link - it2->second.m_Bioseq_Info.Reset(); + binfo.m_UnresolvedTimestamp = m_BioseqChangeCounter-1; } conflict_id = &*it1; } @@ -976,8 +979,7 @@ void CScope_Impl::x_ClearCacheOnNewData(const TIds& seq_ids, CBioseq_ScopeInfo& binfo = *it2->second.m_Bioseq_Info; if ( !binfo.HasBioseq() ) { // try to resolve again - binfo.m_SynCache.Reset(); // break circular link - it2->second.m_Bioseq_Info.Reset(); + binfo.m_UnresolvedTimestamp = m_BioseqChangeCounter-1; } conflict_id = &*it1; } @@ -990,12 +992,11 @@ void CScope_Impl::x_ClearCacheOnNewData(const TIds& seq_ids, TIds::const_iterator it1 = lower_bound(seq_ids.begin(), seq_ids.end(), it2->first); - if ( it1 != seq_ids.end() ) { + if ( it1 != seq_ids.end() && *it1 == it2->first ) { CBioseq_ScopeInfo& binfo = *it2->second.m_Bioseq_Info; if ( !binfo.HasBioseq() ) { // try to resolve again - binfo.m_SynCache.Reset(); // break circular link - it2->second.m_Bioseq_Info.Reset(); + binfo.m_UnresolvedTimestamp = m_BioseqChangeCounter-1; } conflict_id = &*it1; } @@ -1030,8 +1031,8 @@ void CScope_Impl::x_ClearCacheOnEdit(const CTSE_ScopeInfo& replaced_tse) binfo.m_BioseqAnnotRef_Info.Reset(); } else { - binfo.m_SynCache.Reset(); // break circular link - it->second.m_Bioseq_Info.Reset(); // try to resolve again + // try to resolve again + binfo.m_UnresolvedTimestamp = m_BioseqChangeCounter-1; } } it->second.m_AllAnnotRef_Info.Reset(); @@ -1042,6 +1043,9 @@ void CScope_Impl::x_ClearCacheOnEdit(const CTSE_ScopeInfo& replaced_tse) void CScope_Impl::x_ClearAnnotCache(void) { + ++m_AnnotChangeCounter; + return; + // Clear annot cache NON_CONST_ITERATE ( TSeq_idMap, it, m_Seq_idMap ) { if ( it->second.m_Bioseq_Info ) { @@ -1062,27 +1066,15 @@ void CScope_Impl::x_ClearCacheOnNewAnnot(const CTSE_Info& /*new_tse*/) void CScope_Impl::x_ClearCacheOnNewDS(void) { - if ( 1 ) return; + //if ( 1 ) return; // Clear unresolved bioseq handles // Clear annot cache if ( !m_Seq_idMap.empty() ) { x_ReportNewDataConflict(); } - for ( TSeq_idMap::iterator it = m_Seq_idMap.begin(); - it != m_Seq_idMap.end(); ) { - if ( it->second.m_Bioseq_Info ) { - CBioseq_ScopeInfo& binfo = *it->second.m_Bioseq_Info; - if ( binfo.HasBioseq() ) { - binfo.m_BioseqAnnotRef_Info.Reset(); - } - else { - binfo.m_SynCache.Reset(); // break circular link - it->second.m_Bioseq_Info.Reset(); // try to resolve again - } - } - it->second.m_AllAnnotRef_Info.Reset(); - ++it; - } + ++m_BioseqChangeCounter; + ++m_AnnotChangeCounter; + return; } @@ -1712,17 +1704,17 @@ CScope_Impl::x_InitBioseq_Info(TSeq_idMapValue& info, int get_flag, SSeqMatch_Scope& match) { - if (get_flag != CScope::eGetBioseq_Resolved) { + if ( get_flag != CScope::eGetBioseq_Resolved ) { // Resolve only if the flag allows - CInitGuard init(info.second.m_Bioseq_Info, m_MutexPool); - if ( init ) { + CInitGuard init(info.second.m_Bioseq_Info, m_MutexPool, CInitGuard::force); + if ( init || info.second.m_Bioseq_Info->NeedsReResolve(m_BioseqChangeCounter) ) { x_ResolveSeq_id(info, get_flag, match); } } - if ( get_flag == CScope::eGetBioseq_All ) { - _ASSERT(info.second.m_Bioseq_Info); - _ASSERT(!info.second.m_Bioseq_Info->HasBioseq() || - &info.second.m_Bioseq_Info->x_GetScopeImpl() == this); + else if ( info.second.m_Bioseq_Info && + info.second.m_Bioseq_Info->NeedsReResolve(m_BioseqChangeCounter) ) { + // outdated + return null; } return info.second.m_Bioseq_Info; } @@ -1733,9 +1725,8 @@ bool CScope_Impl::x_InitBioseq_Info(TSeq_idMapValue& info, { _ASSERT(&bioseq_info.x_GetScopeImpl() == this); {{ - CInitGuard init(info.second.m_Bioseq_Info, m_MutexPool); - if ( init ) { - _ASSERT(!info.second.m_Bioseq_Info); + CInitGuard init(info.second.m_Bioseq_Info, m_MutexPool, CInitGuard::force); + if ( init || info.second.m_Bioseq_Info->NeedsReResolve(m_BioseqChangeCounter) ) { info.second.m_Bioseq_Info.Reset(&bioseq_info); return true; } @@ -2080,12 +2071,15 @@ SSeqMatch_Scope CScope_Impl::x_FindBioseqInfo(const CPriorityTree& tree, SSeqMatch_Scope new_ret = x_FindBioseqInfo(mit->second, idh, get_flag); if ( new_ret ) { _ASSERT(&new_ret.m_TSE_Lock->GetScopeImpl() == this); - if ( ret && ret.m_Bioseq != new_ret.m_Bioseq ) { + if ( ret && ret.m_Bioseq != new_ret.m_Bioseq && + ret.m_TSE_Lock->CanBeEdited() == new_ret.m_TSE_Lock->CanBeEdited() ) { ret.m_BlobState = CBioseq_Handle::fState_conflict; ret.m_Bioseq.Reset(); return ret; } - ret = new_ret; + if ( !ret || new_ret.m_TSE_Lock->CanBeEdited() ) { + ret = new_ret; + } } else if (new_ret.m_BlobState != 0) { // Remember first blob state @@ -2142,20 +2136,29 @@ void CScope_Impl::x_ResolveSeq_id(TSeq_idMapValue& id_info, match = x_FindBioseqInfo(m_setDataSrc, id_info.first, get_flag); if ( !match ) { // Map unresoved ids only if loading was requested - _ASSERT(!id_info.second.m_Bioseq_Info); if (get_flag == CScope::eGetBioseq_All) { - id_info.second.m_Bioseq_Info.Reset - (new CBioseq_ScopeInfo(match.m_BlobState | - CBioseq_Handle::fState_no_data)); + CRef bioseq; + if ( !id_info.second.m_Bioseq_Info ) { + // first time + bioseq = new CBioseq_ScopeInfo(match.m_BlobState, m_BioseqChangeCounter); + id_info.second.m_Bioseq_Info = bioseq; + } + else { + // update unresolved state + bioseq = id_info.second.m_Bioseq_Info; + bioseq->SetUnresolved(match.m_BlobState, m_BioseqChangeCounter); + } + _ASSERT(!bioseq->HasBioseq()); } } else { CTSE_ScopeInfo& tse_info = *match.m_TSE_Lock; _ASSERT(&tse_info.GetScopeImpl() == this); + // resolved CRef bioseq = tse_info.GetBioseqInfo(match); - _ASSERT(!id_info.second.m_Bioseq_Info); _ASSERT(&bioseq->x_GetScopeImpl() == this); id_info.second.m_Bioseq_Info = bioseq; + _ASSERT(bioseq->HasBioseq()); } } @@ -2235,38 +2238,54 @@ void CScope_Impl::x_GetTSESetWithAnnots(TTSE_LockMatchSet& lock, return; } - CInitGuard init(binfo.m_BioseqAnnotRef_Info, m_MutexPool); - if ( init ) { - CRef match - (new CBioseq_ScopeInfo::TTSE_MatchSetObject); - x_GetTSESetWithAnnots(lock, &match->GetData(), binfo); - binfo.m_BioseqAnnotRef_Info = match; - } - else { - x_LockMatchSet(lock, *binfo.m_BioseqAnnotRef_Info); -#ifdef EXCLUDE_EDITED_BIOSEQ_ANNOT_SET - if ( binfo.x_GetTSE_ScopeInfo().CanBeEdited() ) { - x_GetTSESetWithBioseqAnnots(lock, binfo, 0); + {{ + CInitGuard init(binfo.m_BioseqAnnotRef_Info, m_MutexPool, CInitGuard::force); + if ( init || binfo.m_BioseqAnnotRef_Info->m_SearchTimestamp != m_AnnotChangeCounter ) { + CRef cache = binfo.m_BioseqAnnotRef_Info; + if ( !cache ) { + cache = new CBioseq_ScopeInfo::SAnnotSetCache; + } + else { + cache->match.clear(); + } + x_GetTSESetWithAnnots(lock, &cache->match, binfo); + cache->m_SearchTimestamp = m_AnnotChangeCounter; + binfo.m_BioseqAnnotRef_Info = cache; return; } -#endif + }} + // use cached set + x_LockMatchSet(lock, binfo.m_BioseqAnnotRef_Info->match); +#ifdef EXCLUDE_EDITED_BIOSEQ_ANNOT_SET + if ( binfo.x_GetTSE_ScopeInfo().CanBeEdited() ) { + x_GetTSESetWithBioseqAnnots(lock, binfo, 0); + return; } +#endif } void CScope_Impl::x_GetTSESetWithAnnots(TTSE_LockMatchSet& lock, TSeq_idMapValue& info) { - CInitGuard init(info.second.m_AllAnnotRef_Info, m_MutexPool); - if ( init ) { - CRef match - (new CBioseq_ScopeInfo::TTSE_MatchSetObject); - x_GetTSESetWithAnnots(lock, &match->GetData(), info); - info.second.m_AllAnnotRef_Info = match; - } - else { - x_LockMatchSet(lock, *info.second.m_AllAnnotRef_Info); - } + {{ + CInitGuard init(info.second.m_AllAnnotRef_Info, m_MutexPool, CInitGuard::force); + if ( init || info.second.m_AllAnnotRef_Info->m_SearchTimestamp != m_AnnotChangeCounter ) { + CRef cache = info.second.m_AllAnnotRef_Info; + if ( !cache ) { + cache = new CBioseq_ScopeInfo::SAnnotSetCache; + } + else { + cache->match.clear(); + } + x_GetTSESetWithAnnots(lock, &cache->match, info); + cache->m_SearchTimestamp = m_AnnotChangeCounter; + info.second.m_AllAnnotRef_Info = cache; + return; + } + }} + // use cached set + x_LockMatchSet(lock, info.second.m_AllAnnotRef_Info->match); } @@ -3122,12 +3141,14 @@ void CScope_Impl::x_GetBioseqHandlesSorted(const TIds& ids, } else { TSeq_idMapValue& id_info = x_GetSeq_id_Info(ids[i]); - CInitGuard init(id_info.second.m_Bioseq_Info, m_MutexPool); - if ( init ) { - _ASSERT(!id_info.second.m_Bioseq_Info); - id_info.second.m_Bioseq_Info.Reset(new CBioseq_ScopeInfo( - CBioseq_Handle::fState_no_data | - CBioseq_Handle::fState_not_found)); + CInitGuard init(id_info.second.m_Bioseq_Info, m_MutexPool, CInitGuard::force); + if ( init || id_info.second.m_Bioseq_Info->NeedsReResolve(m_BioseqChangeCounter) ) { + if ( !id_info.second.m_Bioseq_Info ) { + id_info.second.m_Bioseq_Info.Reset(new CBioseq_ScopeInfo(CBioseq_Handle::fState_not_found, m_BioseqChangeCounter)); + } + else { + id_info.second.m_Bioseq_Info->SetUnresolved(CBioseq_Handle::fState_not_found, m_BioseqChangeCounter); + } } CRef info = id_info.second.m_Bioseq_Info; ret[i].m_Handle_Seq_id = ids[i]; diff --git a/c++/src/objmgr/scope_info.cpp b/c++/src/objmgr/scope_info.cpp index eaac7517..dce25871 100644 --- a/c++/src/objmgr/scope_info.cpp +++ b/c++/src/objmgr/scope_info.cpp @@ -1,4 +1,4 @@ -/* $Id: scope_info.cpp 514917 2016-09-27 11:52:34Z ivanov $ +/* $Id: scope_info.cpp 545052 2017-08-31 13:54:34Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -968,6 +968,10 @@ void CTSE_ScopeInfo::ReleaseUsedTSEs(void) it->second->m_UsedByTSE = 0; } m_UsedTSE_Set.swap(used); + if ( m_UsedByTSE ) { + m_UsedByTSE->m_UsedTSE_Set.erase(ConstRef(this)); + m_UsedByTSE = 0; + } } @@ -1761,16 +1765,17 @@ SSeqMatch_Scope CTSE_ScopeInfo::Resolve(const CSeq_id_Handle& id) # define BIOSEQ_TRACE(x) #endif - -CBioseq_ScopeInfo::CBioseq_ScopeInfo(TBlobStateFlags flags) - : m_BlobState(flags) +CBioseq_ScopeInfo::CBioseq_ScopeInfo(TBlobStateFlags flags, int timestamp) + : m_BlobState(flags | CBioseq_Handle::fState_no_data), + m_UnresolvedTimestamp(timestamp) { BIOSEQ_TRACE("CBioseq_ScopeInfo: "<GetData().IsFtable() ) { NON_CONST_ITERATE ( SAnnotObjectsIndex::TObjectInfos, oit, m_ObjectIndex.GetInfos() ) { x_UnmapFeatIds(*oit); } diff --git a/c++/src/objmgr/seq_entry_info.cpp b/c++/src/objmgr/seq_entry_info.cpp index 03cfb669..480c8b63 100644 --- a/c++/src/objmgr/seq_entry_info.cpp +++ b/c++/src/objmgr/seq_entry_info.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_entry_info.cpp 518178 2016-11-01 11:46:07Z ivanov $ +/* $Id: seq_entry_info.cpp 517902 2016-10-28 16:56:25Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/seq_loc_mapper.cpp b/c++/src/objmgr/seq_loc_mapper.cpp index f705cc9b..17fdc524 100644 --- a/c++/src/objmgr/seq_loc_mapper.cpp +++ b/c++/src/objmgr/seq_loc_mapper.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_loc_mapper.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: seq_loc_mapper.cpp 543872 2017-08-15 12:17:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -212,6 +212,30 @@ CSeq_loc_Mapper::CSeq_loc_Mapper(const CSeq_align& map_align, } +CSeq_loc_Mapper::CSeq_loc_Mapper(const CSeq_id& from_id, + const CSeq_id& to_id, + const CSeq_align& map_align, + CScope* scope, + CSeq_loc_Mapper_Options options) + : CSeq_loc_Mapper_Base(options.SetMapperSequenceInfo(new CScope_Mapper_Sequence_Info(scope))), + m_Scope(scope) +{ + x_InitializeAlign(map_align, to_id, &from_id); +} + + +CSeq_loc_Mapper::CSeq_loc_Mapper(size_t from_row, + size_t to_row, + const CSeq_align& map_align, + CScope* scope, + CSeq_loc_Mapper_Options options) + : CSeq_loc_Mapper_Base(options.SetMapperSequenceInfo(new CScope_Mapper_Sequence_Info(scope))), + m_Scope(scope) +{ + x_InitializeAlign(map_align, to_row, from_row); +} + + CSeq_loc_Mapper::CSeq_loc_Mapper(CBioseq_Handle target_seq, ESeqMapDirection direction, CSeq_loc_Mapper_Options options) diff --git a/c++/src/objmgr/seq_map.cpp b/c++/src/objmgr/seq_map.cpp index d8087378..f62a71c6 100644 --- a/c++/src/objmgr/seq_map.cpp +++ b/c++/src/objmgr/seq_map.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_map.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: seq_map.cpp 541892 2017-07-24 13:06:17Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1513,9 +1513,7 @@ bool CSeqMap::x_DoUpdateSeq_inst(CSeq_inst& inst) if ( iter == delta.end() ) { iter = delta.insert(iter, CDelta_ext::Tdata::value_type()); } - if ( !*iter ) { - iter->Reset(new CDelta_seq); - } + iter->Reset(new CDelta_seq); CDelta_seq& dseq = **iter; ++iter; if ( seg.m_SegType == eSeqData ) { diff --git a/c++/src/objmgr/seq_map_ci.cpp b/c++/src/objmgr/seq_map_ci.cpp index 2e18d799..40efcd98 100644 --- a/c++/src/objmgr/seq_map_ci.cpp +++ b/c++/src/objmgr/seq_map_ci.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_map_ci.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: seq_map_ci.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/seq_map_switch.cpp b/c++/src/objmgr/seq_map_switch.cpp index c31f3f40..c0bc5c79 100644 --- a/c++/src/objmgr/seq_map_switch.cpp +++ b/c++/src/objmgr/seq_map_switch.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_map_switch.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: seq_map_switch.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/seq_table_info.cpp b/c++/src/objmgr/seq_table_info.cpp index 72b80834..3c7587c4 100644 --- a/c++/src/objmgr/seq_table_info.cpp +++ b/c++/src/objmgr/seq_table_info.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_table_info.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: seq_table_info.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/seq_table_setters.cpp b/c++/src/objmgr/seq_table_setters.cpp index 9a711784..009a80b8 100644 --- a/c++/src/objmgr/seq_table_setters.cpp +++ b/c++/src/objmgr/seq_table_setters.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_table_setters.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: seq_table_setters.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/seq_vector.cpp b/c++/src/objmgr/seq_vector.cpp index ad571718..35dceae5 100644 --- a/c++/src/objmgr/seq_vector.cpp +++ b/c++/src/objmgr/seq_vector.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_vector.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: seq_vector.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/snp_annot_info.cpp b/c++/src/objmgr/snp_annot_info.cpp index 6337349b..30cf8146 100644 --- a/c++/src/objmgr/snp_annot_info.cpp +++ b/c++/src/objmgr/snp_annot_info.cpp @@ -1,4 +1,4 @@ -/* $Id: snp_annot_info.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: snp_annot_info.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information diff --git a/c++/src/objmgr/split/CMakeLists.id2_split.lib.txt b/c++/src/objmgr/split/CMakeLists.id2_split.lib.txt new file mode 100644 index 00000000..0d645d58 --- /dev/null +++ b/c++/src/objmgr/split/CMakeLists.id2_split.lib.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objmgr/split/Makefile.id2_split.lib +# +add_library(id2_split + blob_splitter blob_splitter_params split_blob blob_splitter_impl + blob_splitter_parser blob_splitter_maker id_range object_splitinfo + asn_sizer annot_piece chunk_info size split_exceptions +) +include_directories(SYSTEM ${CMPRS_INCLUDE}) + +add_dependencies(id2_split + seqsplit +) +target_link_libraries(id2_split + xcompress xobjmgr +) + diff --git a/c++/src/objmgr/split/CMakeLists.txt b/c++/src/objmgr/split/CMakeLists.txt new file mode 100644 index 00000000..8b7b016f --- /dev/null +++ b/c++/src/objmgr/split/CMakeLists.txt @@ -0,0 +1,8 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.id2_split.lib.txt) + +# Recurse subdirectories diff --git a/c++/src/objmgr/split/annot_piece.cpp b/c++/src/objmgr/split/annot_piece.cpp index 05329470..f1f194c3 100644 --- a/c++/src/objmgr/split/annot_piece.cpp +++ b/c++/src/objmgr/split/annot_piece.cpp @@ -1,4 +1,4 @@ -/* $Id: annot_piece.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: annot_piece.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/split/blob_splitter_impl.cpp b/c++/src/objmgr/split/blob_splitter_impl.cpp index 634eccc9..15e8d6f2 100644 --- a/c++/src/objmgr/split/blob_splitter_impl.cpp +++ b/c++/src/objmgr/split/blob_splitter_impl.cpp @@ -1,4 +1,4 @@ -/* $Id: blob_splitter_impl.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: blob_splitter_impl.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/split/blob_splitter_maker.cpp b/c++/src/objmgr/split/blob_splitter_maker.cpp index 8e3851be..2d771d0e 100644 --- a/c++/src/objmgr/split/blob_splitter_maker.cpp +++ b/c++/src/objmgr/split/blob_splitter_maker.cpp @@ -1,4 +1,4 @@ -/* $Id: blob_splitter_maker.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: blob_splitter_maker.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/split/blob_splitter_parser.cpp b/c++/src/objmgr/split/blob_splitter_parser.cpp index 08b37d41..cf4844dc 100644 --- a/c++/src/objmgr/split/blob_splitter_parser.cpp +++ b/c++/src/objmgr/split/blob_splitter_parser.cpp @@ -1,4 +1,4 @@ -/* $Id: blob_splitter_parser.cpp 444533 2014-08-25 18:35:34Z vasilche $ +/* $Id: blob_splitter_parser.cpp 522077 2016-12-14 20:32:22Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -368,7 +368,7 @@ void CBlobSplitterImpl::CopySkeleton(CBioseq_set& dst, const CBioseq_set& src) bool need_split_bioseq = false; if ( m_Params.m_SplitWholeBioseqs ) { - ITERATE ( CBioseq_set::TSeq_set, it, src.GetSeq_set() ) { + REVERSE_ITERATE ( CBioseq_set::TSeq_set, it, src.GetSeq_set() ) { const CSeq_entry& entry = **it; if ( entry.Which() == CSeq_entry::e_Seq ) { const CBioseq& bioseq = entry.GetSeq(); @@ -377,6 +377,8 @@ void CBlobSplitterImpl::CopySkeleton(CBioseq_set& dst, const CBioseq_set& src) break; } } + // cannot split bioseqs before unsplit entry (seq or set) + break; } } @@ -391,7 +393,7 @@ void CBlobSplitterImpl::CopySkeleton(CBioseq_set& dst, const CBioseq_set& src) info = &m_Entries[place_id]; if ( info->m_PlaceId.IsBioseq_set() ) { ERR_POST_X(5, "Several Bioseq-sets with the same id: " << - place_id.GetBioseq_setId()); + place_id.GetBioseq_setId()); info = 0; } else { @@ -429,19 +431,35 @@ void CBlobSplitterImpl::CopySkeleton(CBioseq_set& dst, const CBioseq_set& src) } dst.SetSeq_set(); - ITERATE ( CBioseq_set::TSeq_set, it, src.GetSeq_set() ) { + {{ + auto& seq_set = src.GetSeq_set(); + auto begin = seq_set.begin(); + auto end = seq_set.end(); if ( need_split_bioseq ) { - const CSeq_entry& entry = **it; - if ( entry.Which() == CSeq_entry::e_Seq ) { - const CBioseq& seq = entry.GetSeq(); - if ( SplitBioseq(*info, seq) ) { - continue; + // extract split bioseqs starting from end + // remember start of split bioseqs + size_t old_size = info->m_Bioseqs.size(); + while ( begin != end ) { + auto it = prev(end); + const CSeq_entry& entry = **it; + if ( entry.Which() == CSeq_entry::e_Seq ) { + const CBioseq& seq = entry.GetSeq(); + if ( SplitBioseq(*info, seq) ) { + end = it; + continue; + } } + break; } + // reverse split entries as they were added in backward order + reverse(info->m_Bioseqs.begin()+old_size, info->m_Bioseqs.end()); } - dst.SetSeq_set().push_back(Ref(new CSeq_entry)); - CopySkeleton(*dst.SetSeq_set().back(), **it); - } + // add remaining entries to skeleton + while ( begin != end ) { + dst.SetSeq_set().push_back(Ref(new CSeq_entry)); + CopySkeleton(*dst.SetSeq_set().back(), **begin++); + } + }} if ( src.IsSetClass() && src.GetClass() == CBioseq_set::eClass_segset && diff --git a/c++/src/objmgr/split/id_range.cpp b/c++/src/objmgr/split/id_range.cpp index 0501b80b..ad257703 100644 --- a/c++/src/objmgr/split/id_range.cpp +++ b/c++/src/objmgr/split/id_range.cpp @@ -1,4 +1,4 @@ -/* $Id: id_range.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: id_range.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/split/object_splitinfo.cpp b/c++/src/objmgr/split/object_splitinfo.cpp index d1811f78..f52ab9a4 100644 --- a/c++/src/objmgr/split/object_splitinfo.cpp +++ b/c++/src/objmgr/split/object_splitinfo.cpp @@ -1,4 +1,4 @@ -/* $Id: object_splitinfo.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: object_splitinfo.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/split/size.cpp b/c++/src/objmgr/split/size.cpp index 2d9913a4..f439f263 100644 --- a/c++/src/objmgr/split/size.cpp +++ b/c++/src/objmgr/split/size.cpp @@ -1,4 +1,4 @@ -/* $Id: size.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: size.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/split_parser.cpp b/c++/src/objmgr/split_parser.cpp index e4d80594..7db5a3b2 100644 --- a/c++/src/objmgr/split_parser.cpp +++ b/c++/src/objmgr/split_parser.cpp @@ -1,4 +1,4 @@ -/* $Id: split_parser.cpp 518178 2016-11-01 11:46:07Z ivanov $ +/* $Id: split_parser.cpp 521281 2016-12-07 16:40:59Z vasilche $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information @@ -511,9 +511,8 @@ void CSplitParser::Load(CTSE_Chunk_Info& chunk, chunk.x_LoadSequence(place, piece.GetStart(), piece.GetData()); } - ITERATE ( CID2S_Chunk_Data::TBioseqs, it, data.GetBioseqs() ) { - const CBioseq& bioseq = **it; - chunk.x_LoadBioseq(place, bioseq); + if ( !data.GetBioseqs().empty() ) { + chunk.x_LoadBioseqs(place, data.GetBioseqs()); } } } diff --git a/c++/src/objmgr/tse_assigner.cpp b/c++/src/objmgr/tse_assigner.cpp index 88bcd9e7..797a2655 100644 --- a/c++/src/objmgr/tse_assigner.cpp +++ b/c++/src/objmgr/tse_assigner.cpp @@ -1,4 +1,4 @@ -/* $Id: tse_assigner.cpp 504373 2016-06-14 18:05:35Z vasilche $ +/* $Id: tse_assigner.cpp 521281 2016-12-07 16:40:59Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -205,7 +205,8 @@ void CTSE_Default_Assigner::LoadAnnot(CTSE_Info& tse, void CTSE_Default_Assigner::LoadBioseq(CTSE_Info& tse, const TPlace& place, - CRef entry) + CRef entry, + int chunk_id) { CRef entry_info; {{ @@ -217,7 +218,7 @@ void CTSE_Default_Assigner::LoadBioseq(CTSE_Info& tse, tse.x_SetObject(*entry_info, 0); //??? } else { - entry_info = x_GetBioseq_set(tse, place).AddEntry(*entry); + entry_info = x_GetBioseq_set(tse, place).AddEntry(*entry, chunk_id); } }} if ( !entry_info->x_GetBaseInfo().GetAnnot().empty() ) { @@ -228,6 +229,26 @@ void CTSE_Default_Assigner::LoadBioseq(CTSE_Info& tse, } } +void CTSE_Default_Assigner::LoadChunkBioseqs(CTSE_Info& tse, + const TPlace& place, + const list< CRef >& bioseqs, + int chunk_id) +{ + CDataSource::TMainLock::TWriteLockGuard guard(eEmptyGuard); + if ( tse.HasDataSource() ) + guard.Guard(tse.GetDataSource().GetMainLock()); + if ( place == TPlace(CSeq_id_Handle(), kTSE_Place_id) ) { + _ASSERT(bioseqs.size() == 1); + CRef entry(new CSeq_entry); + entry->SetSeq(bioseqs.front().GetNCObject()); + CRef entry_info(new CSeq_entry_Info(*entry)); + tse.x_SetObject(*entry_info, 0); //??? + } + else { + x_GetBioseq_set(tse, place).x_SetChunkBioseqs(bioseqs, chunk_id); + } +} + void CTSE_Default_Assigner::LoadSequence(CTSE_Info& tse, const TPlace& place, TSeqPos pos, diff --git a/c++/src/objmgr/tse_chunk_info.cpp b/c++/src/objmgr/tse_chunk_info.cpp index 48fce872..345b5ab4 100644 --- a/c++/src/objmgr/tse_chunk_info.cpp +++ b/c++/src/objmgr/tse_chunk_info.cpp @@ -1,4 +1,4 @@ -/* $Id: tse_chunk_info.cpp 465027 2015-04-16 13:18:40Z vasilche $ +/* $Id: tse_chunk_info.cpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -56,6 +56,8 @@ NCBI_DEFINE_ERR_SUBCODE_X(11); BEGIN_SCOPE(objects) +class CTSE_Chunk_Info; + ///////////////////////////////////////////////////////////////////////////// // CTSE_Chunk_Info ///////////////////////////////////////////////////////////////////////////// @@ -64,6 +66,8 @@ BEGIN_SCOPE(objects) CTSE_Chunk_Info::CTSE_Chunk_Info(TChunkId id) : m_SplitInfo(0), m_ChunkId(id), + m_LoadBytes(0), + m_LoadSeconds(0), m_AnnotIndexEnabled(false), m_ExplicitFeatIds(false) { @@ -734,9 +738,18 @@ void CTSE_Chunk_Info::x_LoadAnnot(const TPlace& place, void CTSE_Chunk_Info::x_LoadBioseq(const TPlace& place, const CBioseq& bioseq) +{ + list< CRef > bioseqs; + bioseqs.push_back(Ref(const_cast(&bioseq))); + x_LoadBioseqs(place, bioseqs); +} + + +void CTSE_Chunk_Info::x_LoadBioseqs(const TPlace& place, + const list< CRef >& bioseqs) { _ASSERT(x_Attached()); - m_SplitInfo->x_LoadBioseq(place, bioseq); + m_SplitInfo->x_LoadBioseqs(place, bioseqs, GetChunkId()); } @@ -764,5 +777,37 @@ void CTSE_Chunk_Info::x_LoadSeq_entry(CSeq_entry& entry, } +void CTSE_Chunk_Info::x_AddUsedMemory(size_t size) +{ + _ASSERT(x_Attached()); + m_SplitInfo->x_AddUsedMemory(size); +} + + +void CTSE_Chunk_Info::x_SetLoadBytes(Uint4 bytes) +{ + m_LoadBytes = bytes; +} + + +void CTSE_Chunk_Info::x_SetLoadSeconds(double seconds) +{ + m_LoadSeconds = float(seconds); +} + + +pair CTSE_Chunk_Info::GetLoadCost() const +{ + pair ret(GetLoadBytes(), GetLoadSeconds()); + if ( !ret.first ) { + ret.first = m_SplitInfo->GetDataLoader().EstimateLoadBytes(*this); + } + if ( !ret.second ) { + ret.second = m_SplitInfo->GetDataLoader().EstimateLoadSeconds(*this, ret.first); + } + return ret; +} + + END_SCOPE(objects) END_NCBI_SCOPE diff --git a/c++/src/objmgr/tse_handle.cpp b/c++/src/objmgr/tse_handle.cpp index 26588796..bb48cefb 100644 --- a/c++/src/objmgr/tse_handle.cpp +++ b/c++/src/objmgr/tse_handle.cpp @@ -1,4 +1,4 @@ -/* $Id: tse_handle.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: tse_handle.cpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -136,6 +136,12 @@ bool CTSE_Handle::IsValid(void) const } +size_t CTSE_Handle::GetUsedMemory(void) const +{ + return x_GetTSE_Info().GetUsedMemory(); +} + + bool CTSE_Handle::OrderedBefore(const CTSE_Handle& tse) const { if ( *this == tse ) { diff --git a/c++/src/objmgr/tse_info.cpp b/c++/src/objmgr/tse_info.cpp index c66d0580..6c8b8a91 100644 --- a/c++/src/objmgr/tse_info.cpp +++ b/c++/src/objmgr/tse_info.cpp @@ -1,4 +1,4 @@ -/* $Id: tse_info.cpp 518178 2016-11-01 11:46:07Z ivanov $ +/* $Id: tse_info.cpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -337,6 +337,12 @@ void CTSE_Info::SetUsedMemory(size_t size) } +void CTSE_Info::AddUsedMemory(size_t size) +{ + m_UsedMemory += size; +} + + void CTSE_Info::SetSeq_entry(CSeq_entry& entry, CTSE_SetObjectInfo* set_info) { if ( m_Which != CSeq_entry::e_not_set ) { @@ -1078,10 +1084,10 @@ SIdAnnotObjs& CTSE_Info::x_SetIdObjects(TAnnotObjs& objs, const CSeq_id_Handle& id) { // repeat for more generic types of selector - TAnnotObjs::iterator it = objs.lower_bound(id); - if ( it == objs.end() || it->first != id ) { + TAnnotObjs::iterator it = objs.find(id); + if ( it == objs.end() ) { // new id - it = objs.insert(it, TAnnotObjs::value_type(id, SIdAnnotObjs())); + it = objs.insert(TAnnotObjs::value_type(id, SIdAnnotObjs())).first; x_IndexAnnotTSE(name, id); } _ASSERT(it != objs.end() && it->first == id); @@ -1099,8 +1105,8 @@ SIdAnnotObjs& CTSE_Info::x_SetIdObjects(const CAnnotName& name, const SIdAnnotObjs* CTSE_Info::x_GetIdObjects(const TAnnotObjs& objs, const CSeq_id_Handle& idh) const { - TAnnotObjs::const_iterator it = objs.lower_bound(idh); - if ( it == objs.end() || it->first != idh ) { + TAnnotObjs::const_iterator it = objs.find(idh); + if ( it == objs.end() ) { return 0; } return &it->second; diff --git a/c++/src/objmgr/tse_split_info.cpp b/c++/src/objmgr/tse_split_info.cpp index a0c7d3da..5c42d279 100644 --- a/c++/src/objmgr/tse_split_info.cpp +++ b/c++/src/objmgr/tse_split_info.cpp @@ -1,4 +1,4 @@ -/* $Id: tse_split_info.cpp 518178 2016-11-01 11:46:07Z ivanov $ +/* $Id: tse_split_info.cpp 545441 2017-09-06 17:53:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -179,17 +179,19 @@ CDataLoader& CTSE_Split_Info::GetDataLoader(void) const bool CTSE_Split_Info::x_HasDelayedMainChunk(void) const { TChunks::const_iterator iter = m_Chunks.end(), begin = m_Chunks.begin(); - return iter != begin && (--iter)->first == kMax_Int; + return iter != begin && (--iter)->first == CTSE_Chunk_Info::kDelayedMain_ChunkId; } bool CTSE_Split_Info::x_NeedsDelayedMainChunk(void) const { TChunks::const_iterator iter = m_Chunks.end(), begin = m_Chunks.begin(); - if ( iter == begin || (--iter)->first != kMax_Int ) { + if ( iter == begin || (--iter)->first != CTSE_Chunk_Info::kDelayedMain_ChunkId ) { + // no delayed main chunk return false; } - return iter == begin || ((--iter)->first == kMax_Int-1 && iter == begin); + // no other chunks except maybe WGS master chunk + return iter == begin || ((--iter)->first == CTSE_Chunk_Info::kMasterWGS_ChunkId && iter == begin); } @@ -207,7 +209,7 @@ void CTSE_Split_Info::AddChunk(CTSE_Chunk_Info& chunk_info) { CMutexGuard guard(m_SeqIdToChunksMutex); _ASSERT(m_Chunks.find(chunk_info.GetChunkId()) == m_Chunks.end()); - _ASSERT(m_Chunks.empty() || chunk_info.GetChunkId() != kMax_Int); + _ASSERT(m_Chunks.empty() || chunk_info.GetChunkId() != chunk_info.kDelayedMain_ChunkId); bool need_update = x_HasDelayedMainChunk(); m_Chunks[chunk_info.GetChunkId()].Reset(&chunk_info); chunk_info.x_SplitAttach(*this); @@ -524,22 +526,12 @@ void CTSE_Split_Info::x_LoadAnnot(const TPlace& place, } } -void CTSE_Split_Info::x_LoadBioseq(const TPlace& place, const CBioseq& bioseq) +void CTSE_Split_Info::x_LoadBioseqs(const TPlace& place, const list< CRef >& bioseqs, int chunk_id) { - CRef add; NON_CONST_ITERATE ( TTSE_Set, it, m_TSE_Set ) { CTSE_Info& tse = *it->first; ITSE_Assigner& listener = *it->second; - if ( !add ) { - add = new CSeq_entry; - add->SetSeq(const_cast(bioseq)); - } - else { - CRef tmp(add); - add.Reset(new CSeq_entry); - add->Assign(*tmp); - } - listener.LoadBioseq(tse, place, add); + listener.LoadChunkBioseqs(tse, place, bioseqs, chunk_id); } } @@ -586,6 +578,15 @@ void CTSE_Split_Info::x_LoadSeq_entry(CSeq_entry& entry, } +void CTSE_Split_Info::x_AddUsedMemory(size_t size) +{ + NON_CONST_ITERATE ( TTSE_Set, it, m_TSE_Set ) { + CTSE_Info& tse = *it->first; + tse.AddUsedMemory(size); + } +} + + void CTSE_Split_Info::x_SetBioseqUpdater(CRef updater) { NON_CONST_ITERATE ( TTSE_Set, it, m_TSE_Set ) { diff --git a/c++/src/objmgr/unsupp_editsaver.cpp b/c++/src/objmgr/unsupp_editsaver.cpp index f3ab9fc0..cc75edc0 100644 --- a/c++/src/objmgr/unsupp_editsaver.cpp +++ b/c++/src/objmgr/unsupp_editsaver.cpp @@ -1,4 +1,4 @@ -/* $Id: unsupp_editsaver.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: unsupp_editsaver.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/util/CMakeLists.txt b/c++/src/objmgr/util/CMakeLists.txt new file mode 100644 index 00000000..6dad94a7 --- /dev/null +++ b/c++/src/objmgr/util/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.util.lib.txt) + +# Recurse subdirectories +add_subdirectory(unit_test ) diff --git a/c++/src/objmgr/util/CMakeLists.util.lib.txt b/c++/src/objmgr/util/CMakeLists.util.lib.txt new file mode 100644 index 00000000..3508faf4 --- /dev/null +++ b/c++/src/objmgr/util/CMakeLists.util.lib.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objmgr/util/Makefile.util.lib +# +add_library(xobjutil + weight sequence feature indexer seqtitle create_defline obj_sniff seq_loc_util seq_align_util seq_trimmer bioseqgaps_ci + objutil feature_edit + autodef autodef_feature_clause_base autodef_source_desc autodef_available_modifier + autodef_mod_combo autodef_source_group autodef_feature_clause autodef_options +) +add_dependencies(xobjutil + submit +) + +target_link_libraries(xobjutil + submit xobjmgr +) + diff --git a/c++/src/objmgr/util/Makefile.util.lib b/c++/src/objmgr/util/Makefile.util.lib index bc691eb6..3387d795 100644 --- a/c++/src/objmgr/util/Makefile.util.lib +++ b/c++/src/objmgr/util/Makefile.util.lib @@ -1,15 +1,18 @@ -# $Id: Makefile.util.lib 501626 2016-05-17 17:32:10Z kornbluh $ +# $Id: Makefile.util.lib 536105 2017-05-15 20:05:08Z kans $ # Build library "xobjutil" ############################### ASN_DEP = submit -SRC = weight sequence feature seqtitle create_defline obj_sniff seq_loc_util seq_align_util seq_trimmer bioseqgaps_ci \ - objutil +SRC = weight sequence feature indexer seqtitle create_defline obj_sniff seq_loc_util seq_align_util seq_trimmer bioseqgaps_ci \ + objutil feature_edit \ + autodef autodef_feature_clause_base autodef_source_desc autodef_available_modifier \ + autodef_mod_combo autodef_source_group autodef_feature_clause autodef_options + LIB = xobjutil -DLL_LIB = $(SOBJMGR_LIBS) +DLL_LIB = submit $(SOBJMGR_LIBS) WATCHERS = ucko vasilche diff --git a/c++/src/objtools/edit/autodef.cpp b/c++/src/objmgr/util/autodef.cpp similarity index 90% rename from c++/src/objtools/edit/autodef.cpp rename to c++/src/objmgr/util/autodef.cpp index e95008ba..eaf60039 100644 --- a/c++/src/objtools/edit/autodef.cpp +++ b/c++/src/objmgr/util/autodef.cpp @@ -1,4 +1,4 @@ -/* $Id: autodef.cpp 511804 2016-08-24 17:35:08Z ivanov $ +/* $Id: autodef.cpp 536624 2017-05-22 10:30:37Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,7 +31,7 @@ */ #include -#include +#include #include #include #include @@ -44,14 +44,10 @@ #include #include #include +#include #include #include -#include -#include -#include -#include -#include -#include +#include #include @@ -654,6 +650,15 @@ string CAutoDef::x_GetFeatureClauses(CBioseq_Handle bh) return custom; } + CSeqdesc_CI d(bh, CSeqdesc::e_User); + while (d) { + if (x_IsHumanSTR(d->GetUser())) { + return x_GetHumanSTRFeatureClauses(bh, d->GetUser()); + } + ++d; + } + + CAutoDefFeatureClause_Base main_clause; CAutoDefFeatureClause *new_clause; CRange range; @@ -892,11 +897,7 @@ static unsigned int s_GetProductFlagFromCDSProductNames (CBioseq_Handle bh) bh.GetScope()); if (prot) { feature::GetLabel(*prot, &label, feature::fFGL_Content); - if (NStr::Find(label, "macronuclear") != NCBI_NS_STD::string::npos) { - product_flag = CBioSource::eGenome_macronuclear; - } else if (NStr::Find(label, "nucleomorph") != NCBI_NS_STD::string::npos) { - product_flag = CBioSource::eGenome_nucleomorph; - } else if (NStr::Find(label, "mitochondrion") != NCBI_NS_STD::string::npos + if (NStr::Find(label, "mitochondrion") != NCBI_NS_STD::string::npos || NStr::Find(label, "mitochondrial") != NCBI_NS_STD::string::npos) { product_flag = CBioSource::eGenome_mitochondrion; } else if (NStr::Find(label, "apicoplast") != NCBI_NS_STD::string::npos) { @@ -916,8 +917,6 @@ static unsigned int s_GetProductFlagFromCDSProductNames (CBioseq_Handle bh) product_flag = CBioSource::eGenome_cyanelle; } else if (NStr::Find(label, "leucoplast") != NCBI_NS_STD::string::npos) { product_flag = CBioSource::eGenome_leucoplast; - } else if (NStr::Find(label, "hydrogenosome") != NCBI_NS_STD::string::npos) { - product_flag = CBioSource::eGenome_hydrogenosome; } } } @@ -1189,8 +1188,7 @@ string CAutoDef::GetOneDefLine(CBioseq_Handle bh) if (bh.CanGetInst() && bh.GetInst().CanGetMol() && bh.GetInst().GetMol() == CSeq_inst::eMol_aa) { return sequence::CDeflineGenerator() .GenerateDefline(bh, - sequence::CDeflineGenerator::fIgnoreExisting | - sequence::CDeflineGenerator::fAllProteinNames); + sequence::CDeflineGenerator::fIgnoreExisting); } string org_desc = "Unknown organism"; unsigned int genome_val = CBioSource::eGenome_unknown; @@ -1221,80 +1219,6 @@ string CAutoDef::GetOneDefLine(CBioseq_Handle bh) } -string CAutoDef::GetDocsumOrgDescription(CSeq_entry_Handle se) -{ - string joined_org = "Mixed organisms"; - - CRef rq(new CT3Request()); - CBioseq_CI bi (se, CSeq_inst::eMol_na); - while (bi) { - CSeqdesc_CI desc_ci(*bi, CSeqdesc::e_Source); - if (desc_ci && desc_ci->GetSource().IsSetOrg()) { - int taxid = desc_ci->GetSource().GetOrg().GetTaxId(); - if (taxid > 0) { - rq->SetJoin().Set().push_back(taxid); - } - } - ++bi; - } - if (rq->IsJoin() && rq->GetJoin().Get().size() > 0) { - CTaxon3_request request; - request.SetRequest().push_back(rq); - CTaxon3 taxon3; - taxon3.Init(); - CRef reply = taxon3.SendRequest(request); - if (reply) { - CTaxon3_reply::TReply::const_iterator reply_it = reply->GetReply().begin(); - while (reply_it != reply->GetReply().end()) { - if ((*reply_it)->IsData() - && (*reply_it)->GetData().GetOrg().IsSetTaxname()) { - joined_org = (*reply_it)->GetData().GetOrg().GetTaxname(); - break; - } - ++reply_it; - } - } - } - - return joined_org; -} - - -string CAutoDef::GetDocsumDefLine(CSeq_entry_Handle se) -{ - string org_desc = GetDocsumOrgDescription(se); - - string feature_clauses = ""; - CBioseq_CI bi(se, CSeq_inst::eMol_na); - if (bi) { - unsigned int genome_val = CBioSource::eGenome_unknown; - CSeqdesc_CI di(*bi, CSeqdesc::e_Source); - if (di && di->GetSource().IsSetGenome()) { - genome_val = di->GetSource().GetGenome(); - } - feature_clauses = GetOneFeatureClauseList(*bi, genome_val); - } - - return org_desc + feature_clauses; -} - - -bool CAutoDef::NeedsDocsumDefline(const CBioseq_set& set) -{ - bool rval = false; - if (set.IsSetClass()) { - CBioseq_set::EClass set_class = set.GetClass(); - if (set_class == CBioseq_set::eClass_pop_set - || set_class == CBioseq_set::eClass_phy_set - || set_class == CBioseq_set::eClass_eco_set - || set_class == CBioseq_set::eClass_mut_set) { - rval = true; - } - } - return rval; -} - - void CAutoDef::GetAvailableModifiers(CAutoDef::TAvailableModifierSet &mod_set) { mod_set.clear(); @@ -1313,7 +1237,8 @@ void CAutoDef::SetOptionsObject(const CUser_object& user) } -CConstRef GetOptionsForSet(CBioseq_set_Handle set) +//starting here, remove when separating autodef from taxonomy options +CConstRef s_GetOptionsForSet(CBioseq_set_Handle set) { CConstRef options(NULL); CBioseq_CI b(set, CSeq_inst::eMol_na); @@ -1330,7 +1255,30 @@ CConstRef GetOptionsForSet(CBioseq_set_Handle set) } -bool CAutoDef::RegenerateDefLines(CSeq_entry_Handle se) +string CAutoDef::RegenerateDefLine(CBioseq_Handle bh) +{ + string defline = kEmptyStr; + if (bh.IsAa()) { + return kEmptyStr; + } + CSeqdesc_CI desc(bh, CSeqdesc::e_User); + while (desc && desc->GetUser().GetObjectType() != CUser_object::eObjectType_AutodefOptions) { + ++desc; + } + if (desc) { + CAutoDef autodef; + autodef.SetOptionsObject(desc->GetUser()); + CAutoDefModifierCombo mod_combo; + CAutoDefOptions options; + options.InitFromUserObject(desc->GetUser()); + mod_combo.SetOptions(options); + defline = autodef.GetOneDefLine(&mod_combo, bh); + } + return defline; +} + + +bool CAutoDef::RegenerateSequenceDefLines(CSeq_entry_Handle se) { bool any = false; CBioseq_CI b_iter(se); @@ -1343,13 +1291,7 @@ bool CAutoDef::RegenerateDefLines(CSeq_entry_Handle se) ++desc; } if (desc) { - CAutoDef autodef; - autodef.SetOptionsObject(desc->GetUser()); - CAutoDefModifierCombo mod_combo; - CAutoDefOptions options; - options.InitFromUserObject(desc->GetUser()); - mod_combo.SetOptions(options); - string defline = autodef.GetOneDefLine(&mod_combo, *b_iter); + string defline = RegenerateDefLine(*b_iter); bool found_existing = false; CBioseq_EditHandle beh(*b_iter); @@ -1368,44 +1310,80 @@ bool CAutoDef::RegenerateDefLines(CSeq_entry_Handle se) new_desc->SetTitle(defline); beh.SetDescr().Set().push_back(new_desc); any = true; - } + } } } + return any; +} + - // update the title of the set - for (CSeq_entry_CI si(se, CSeq_entry_CI::fRecursive | CSeq_entry_CI::fIncludeGivenEntry, CSeq_entry::e_Set); si; ++si) { - if (si->IsSet() && CAutoDef::NeedsDocsumDefline(*(si->GetSet().GetCompleteBioseq_set()))) { - CAutoDef autodef; - CConstRef options = GetOptionsForSet(si->GetSet()); - if (options) { - autodef.SetOptionsObject(*options); +bool CAutoDef::x_IsHumanSTR(const CUser_object& obj) +{ + if (obj.GetObjectType() != CUser_object::eObjectType_StructuredComment) { + return false; + } + if (!obj.IsSetData()) { + return false; + } + ITERATE(CUser_object::TData, f, obj.GetData()) { + if ((*f)->IsSetLabel() && (*f)->GetLabel().IsStr() && + NStr::EqualNocase((*f)->GetLabel().GetStr(), "StructuredCommentPrefix") && + (*f)->IsSetData() && (*f)->GetData().IsStr()) { + if (NStr::EqualNocase((*f)->GetData().GetStr(), "##HumanSTR-START##")) { + return true; + } else { + return false; } - autodef.AddSources(se); - string defline = autodef.GetDocsumDefLine(*si); + } + } + return false; +} - bool found_existing = false; - CBioseq_set_EditHandle bsseh(si->GetSet()); - NON_CONST_ITERATE(CBioseq_set_EditHandle::TDescr::Tdata, it, bsseh.SetDescr().Set()) { - if ((*it)->IsTitle()) { - if (!NStr::Equal((*it)->GetTitle(), defline)) { - (*it)->SetTitle(defline); - any = true; - } - found_existing = true; - break; + +string CAutoDef::x_GetHumanSTRFeatureClauses(CBioseq_Handle bh, const CUser_object& comment) +{ + string locus_name = kEmptyStr; + string allele = kEmptyStr; + string repeat = kEmptyStr; + + if (comment.IsSetData()) { + ITERATE(CUser_object::TData, it, comment.GetData()) { + if ((*it)->IsSetData() && (*it)->GetData().IsStr() && + (*it)->IsSetLabel() && (*it)->GetLabel().IsStr()) { + const string& label = (*it)->GetLabel().GetStr(); + if (NStr::EqualNocase(label, "STR locus name")) { + locus_name = (*it)->GetData().GetStr(); + } else if (NStr::EqualNocase(label, "Length-based allele")) { + allele = (*it)->GetData().GetStr(); + } else if (NStr::EqualNocase(label, "Bracketed repeat")) { + repeat = (*it)->GetData().GetStr(); } } - if (!found_existing) { - CRef new_desc(new CSeqdesc()); - new_desc->SetTitle(defline); - bsseh.SetDescr().Set().push_back(new_desc); - any = true; - } } } - return any; + + string clause = "microsatellite " + locus_name + " " + allele + " " + repeat; + CFeat_CI f(bh, CSeqFeatData::eSubtype_variation); + while (f) { + if (f->IsSetDbxref()) { + ITERATE(CSeq_feat::TDbxref, db, f->GetDbxref()) { + if ((*db)->IsSetDb() && NStr::Equal((*db)->GetDb(), "dbSNP") && + (*db)->IsSetTag()) { + if ((*db)->GetTag().IsStr()) { + clause += " " + (*db)->GetTag().GetStr(); + } else if ((*db)->GetTag().IsId()) { + clause += " " + NStr::NumericToString((*db)->GetTag().GetId()); + } + } + } + } + ++f; + } + clause += " sequence"; + return clause; } + END_SCOPE(objects) END_NCBI_SCOPE diff --git a/c++/src/objtools/edit/autodef_available_modifier.cpp b/c++/src/objmgr/util/autodef_available_modifier.cpp similarity index 99% rename from c++/src/objtools/edit/autodef_available_modifier.cpp rename to c++/src/objmgr/util/autodef_available_modifier.cpp index b2261d78..a4663c8b 100644 --- a/c++/src/objtools/edit/autodef_available_modifier.cpp +++ b/c++/src/objmgr/util/autodef_available_modifier.cpp @@ -1,4 +1,4 @@ -/* $Id: autodef_available_modifier.cpp 514107 2016-09-19 16:06:20Z ivanov $ +/* $Id: autodef_available_modifier.cpp 530196 2017-03-13 12:59:43Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,7 +31,7 @@ */ #include -#include +#include #include #include #include diff --git a/c++/src/objtools/edit/autodef_feature_clause.cpp b/c++/src/objmgr/util/autodef_feature_clause.cpp similarity index 98% rename from c++/src/objtools/edit/autodef_feature_clause.cpp rename to c++/src/objmgr/util/autodef_feature_clause.cpp index b74de873..d4af5cd4 100644 --- a/c++/src/objtools/edit/autodef_feature_clause.cpp +++ b/c++/src/objmgr/util/autodef_feature_clause.cpp @@ -1,4 +1,4 @@ -/* $Id: autodef_feature_clause.cpp 519214 2016-11-14 16:05:29Z ivanov $ +/* $Id: autodef_feature_clause.cpp 544439 2017-08-23 11:27:20Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,7 +31,7 @@ */ #include -#include +#include #include #include #include @@ -653,7 +653,7 @@ bool CAutoDefFeatureClause::x_GetProductName(string &product_name) product_name = comment; return true; } - } else if (m_MainFeat.GetData().GetSubtype() == CSeqFeatData::eSubtype_tmRNA) { + } else if (subtype == CSeqFeatData::eSubtype_tmRNA) { product_name = "tmRNA"; return true; } else if (m_MainFeat.GetData().Which() == CSeqFeatData::e_Rna) { @@ -662,9 +662,9 @@ bool CAutoDefFeatureClause::x_GetProductName(string &product_name) product_name = m_MainFeat.GetComment(); } return true; - } else if (m_MainFeat.GetData().GetSubtype() == CSeqFeatData::eSubtype_regulatory) { + } else if (subtype == CSeqFeatData::eSubtype_regulatory) { return true; - } else if (m_MainFeat.GetData().GetSubtype() == CSeqFeatData::eSubtype_misc_recomb) { + } else if (subtype == CSeqFeatData::eSubtype_misc_recomb) { if (m_MainFeat.IsSetQual()) { ITERATE(CSeq_feat::TQual, q, m_MainFeat.GetQual()) { if ((*q)->IsSetQual() && NStr::Equal((*q)->GetQual(), "recombination_class") && @@ -676,6 +676,8 @@ bool CAutoDefFeatureClause::x_GetProductName(string &product_name) } s_UseCommentBeforeSemicolon(m_MainFeat, product_name); return true; + } else if (subtype == CSeqFeatData::eSubtype_exon || subtype == CSeqFeatData::eSubtype_intron) { + return x_GetExonDescription(product_name); } else { string label; @@ -691,11 +693,6 @@ bool CAutoDefFeatureClause::x_GetProductName(string &product_name) if (NStr::IsBlank(label)) { feature::GetLabel(m_MainFeat, &label, feature::fFGL_Content); - if ((subtype == CSeqFeatData::eSubtype_exon && NStr::Equal(label, "exon")) - || (subtype == CSeqFeatData::eSubtype_intron && NStr::Equal(label, "[intron]")) - || (subtype != CSeqFeatData::eSubtype_exon && subtype != CSeqFeatData::eSubtype_intron)) { - label = ""; - } } if ((subtype == CSeqFeatData::eSubtype_cdregion && !NStr::Equal(label, "CDS")) || (subtype == CSeqFeatData::eSubtype_mRNA && !NStr::Equal(label, "mRNA")) @@ -736,20 +733,8 @@ bool CAutoDefFeatureClause::x_GetExonDescription(string &description) } } } - - string label; - feature::GetLabel(m_MainFeat, &label, feature::fFGL_Content); - - if ((subtype == CSeqFeatData::eSubtype_exon && - (NStr::Equal(label, "exon") || NStr::Equal(label, "[exon]"))) - || (subtype == CSeqFeatData::eSubtype_intron && NStr::Equal(label, "[intron]")) - || (subtype != CSeqFeatData::eSubtype_exon && subtype != CSeqFeatData::eSubtype_intron)) { - description = ""; - return false; - } else { - description = label; - return true; - } + description = kEmptyStr; + return false; } @@ -1326,6 +1311,13 @@ bool CAutoDefFeatureClause::OkToGroupUnderByLocation(CAutoDefFeatureClause_Base if (parent_clause == NULL) { return false; } + + if (m_HasGene && parent_clause->GetMainFeatureSubtype() == CSeqFeatData::eSubtype_gene) { + // genes must match to be parents + if (!NStr::Equal(m_GeneName, parent_clause->GetGeneName())) { + return false; + } + } if (m_Biomol == CMolInfo::eBiomol_mRNA) { return true; @@ -1817,7 +1809,10 @@ CAutoDefIntergenicSpacerClause::CAutoDefIntergenicSpacerClause(CBioseq_Handle bh : CAutoDefFeatureClause(bh, main_feat, mapped_loc) { - string comment = m_MainFeat.GetComment(); + string comment = kEmptyStr; + if (m_MainFeat.IsSetComment()) { + comment = m_MainFeat.GetComment(); + } /* truncate at first semicolon */ string::size_type pos = NStr::Find(comment, ";"); diff --git a/c++/src/objtools/edit/autodef_feature_clause_base.cpp b/c++/src/objmgr/util/autodef_feature_clause_base.cpp similarity index 99% rename from c++/src/objtools/edit/autodef_feature_clause_base.cpp rename to c++/src/objmgr/util/autodef_feature_clause_base.cpp index c7e4b136..a006ad87 100644 --- a/c++/src/objtools/edit/autodef_feature_clause_base.cpp +++ b/c++/src/objmgr/util/autodef_feature_clause_base.cpp @@ -1,4 +1,4 @@ -/* $Id: autodef_feature_clause_base.cpp 519214 2016-11-14 16:05:29Z ivanov $ +/* $Id: autodef_feature_clause_base.cpp 542567 2017-08-01 14:03:30Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,7 +31,7 @@ */ #include -#include +#include #include #include #include @@ -2016,8 +2016,6 @@ vector CAutoDefFeatureClause_Base::GetFeatureClausePhrases(string commen CAutoDefFeatureClause_Base * CAutoDefFeatureClause_Base::ClauseFromPhrase(const string& phrase, CBioseq_Handle bh, const CSeq_feat& cf, const CSeq_loc& mapped_loc, bool first, bool last) { - CAutoDefFeatureClause_Base *clause = NULL; - if (NStr::Equal(phrase, "control region") || NStr::Equal(phrase, "D-loop")) { // create a clause of the appropriate type diff --git a/c++/src/objtools/edit/autodef_mod_combo.cpp b/c++/src/objmgr/util/autodef_mod_combo.cpp similarity index 95% rename from c++/src/objtools/edit/autodef_mod_combo.cpp rename to c++/src/objmgr/util/autodef_mod_combo.cpp index ed3d8472..7a62d578 100644 --- a/c++/src/objtools/edit/autodef_mod_combo.cpp +++ b/c++/src/objmgr/util/autodef_mod_combo.cpp @@ -1,4 +1,4 @@ -/* $Id: autodef_mod_combo.cpp 514107 2016-09-19 16:06:20Z ivanov $ +/* $Id: autodef_mod_combo.cpp 544096 2017-08-17 17:21:55Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -43,7 +43,7 @@ #include -#include +#include BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) @@ -267,6 +267,8 @@ string CAutoDefModifierCombo::x_GetSubSourceLabel (CSubSource::ESubtype st) label = "plasmid"; } else if (st == CSubSource::eSubtype_country) { label = "from"; + } else if (st == CSubSource::eSubtype_segment) { + label = "segment"; } else if (m_UseModifierLabels) { label = CAutoDefAvailableModifier::GetSubSourceLabel (st); } @@ -349,7 +351,7 @@ bool CAutoDefModifierCombo::x_AddSubsourceString (string &source_description, co return false; } ITERATE (CBioSource::TSubtype, subSrcI, bsrc.GetSubtype()) { - if ((*subSrcI)->GetSubtype() == st) { + if ((*subSrcI)->IsSetSubtype() && (*subSrcI)->GetSubtype() == st) { source_description += x_GetSubSourceLabel (st); string val = (*subSrcI)->GetName(); @@ -420,8 +422,12 @@ bool CAutoDefModifierCombo::x_AddOrgModString (string &source_description, const bool used = false; string val; + if (!bsrc.IsSetOrg() || !bsrc.GetOrg().IsSetOrgname() || !bsrc.GetOrg().GetOrgname().IsSetMod()) { + return false; + } + ITERATE (COrgName::TMod, modI, bsrc.GetOrg().GetOrgname().GetMod()) { - if ((*modI)->GetSubtype() == st) { + if ((*modI)->IsSetSubtype() && (*modI)->GetSubtype() == st) { string val = (*modI)->GetSubname(); // truncate value at first semicolon @@ -478,6 +484,7 @@ void CAutoDefModifierCombo::x_AddHIVModifiers(TExtraOrgMods& extra_orgmods, TExt string isolate_text = ""; bool src_has_clone = false; bool src_has_isolate = false; + bool src_has_strain = false; if (!bsrc.IsSetOrg() || !bsrc.GetOrg().IsSetTaxname()) { return; @@ -495,23 +502,33 @@ void CAutoDefModifierCombo::x_AddHIVModifiers(TExtraOrgMods& extra_orgmods, TExt src_has_clone = x_BioSourceHasSubSrc(bsrc, CSubSource::eSubtype_clone); src_has_isolate = x_BioSourceHasOrgMod(bsrc, COrgMod::eSubtype_isolate); + src_has_strain = x_BioSourceHasOrgMod(bsrc, COrgMod::eSubtype_strain); - if ((HasSubSource (CSubSource::eSubtype_clone) && src_has_clone) - || (HasOrgMod (COrgMod::eSubtype_isolate) && src_has_isolate)) { + if ((HasSubSource (CSubSource::eSubtype_clone) && src_has_clone) || + (HasOrgMod (COrgMod::eSubtype_isolate) && src_has_isolate) || + (HasOrgMod (COrgMod::eSubtype_strain) && src_has_strain)) { // no additional changes - isolate and clone rule taken care of } else { + bool use_isolate = false; if ( ! HasOrgMod (COrgMod::eSubtype_isolate) && src_has_isolate && (m_HIVCloneIsolateRule == CAutoDefOptions::ePreferIsolate || m_HIVCloneIsolateRule == CAutoDefOptions::eWantBoth || !src_has_clone)) { if (extra_orgmods.find(COrgMod::eSubtype_isolate) == extra_orgmods.end()) { extra_orgmods.insert(TExtraOrgMod(COrgMod::eSubtype_isolate, true)); + use_isolate = true; + } + } + if (!HasOrgMod(COrgMod::eSubtype_strain) && src_has_strain && + !use_isolate) { + if (extra_orgmods.find(COrgMod::eSubtype_strain) == extra_orgmods.end()) { + extra_orgmods.insert(TExtraOrgMod(COrgMod::eSubtype_strain, true)); } } if (! HasSubSource(CSubSource::eSubtype_clone) && src_has_clone && (m_HIVCloneIsolateRule == CAutoDefOptions::ePreferClone || m_HIVCloneIsolateRule == CAutoDefOptions::eWantBoth - || !src_has_isolate)) { + || (!src_has_isolate && !src_has_strain))) { if (extra_subsrcs.find(CSubSource::eSubtype_clone) == extra_subsrcs.end()) { extra_subsrcs.insert(TExtraSubSrc(CSubSource::eSubtype_clone, true)); } @@ -544,6 +561,11 @@ void CAutoDefModifierCombo::x_AddRequiredSubSourceModifiers(TExtraOrgMods& extra if (extra_subsrcs.find(CSubSource::eSubtype_endogenous_virus_name) == extra_subsrcs.end()) { extra_subsrcs.insert(TExtraSubSrc(CSubSource::eSubtype_endogenous_virus_name, true)); } + + if (extra_subsrcs.find(CSubSource::eSubtype_segment) == extra_subsrcs.end() && + bsrc.IsSetOrg() && bsrc.GetOrg().IsSetTaxname() && NStr::StartsWith(bsrc.GetOrg().GetTaxname(), "Influenza ")) { + extra_subsrcs.insert(TExtraSubSrc(CSubSource::eSubtype_segment, true)); + } } @@ -777,7 +799,7 @@ bool CAutoDefModifierCombo::x_AddMinicircle(string& source_description, const st { bool any_change = false; vector tokens; - NStr::Tokenize(note_text, ";", tokens); + NStr::Split(note_text, ";", tokens, NStr::fSplit_Tokenize); ITERATE(vector, t, tokens) { if (NStr::Find(*t, "maxicircle") != string::npos || NStr::Find(*t, "minicircle") != string::npos) { diff --git a/c++/src/objtools/edit/autodef_options.cpp b/c++/src/objmgr/util/autodef_options.cpp similarity index 99% rename from c++/src/objtools/edit/autodef_options.cpp rename to c++/src/objmgr/util/autodef_options.cpp index 6fcdc5f5..7020c8de 100644 --- a/c++/src/objtools/edit/autodef_options.cpp +++ b/c++/src/objmgr/util/autodef_options.cpp @@ -1,4 +1,4 @@ -/* $Id: autodef_options.cpp 510717 2016-08-15 17:12:40Z ivanov $ +/* $Id: autodef_options.cpp 530196 2017-03-13 12:59:43Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,7 +31,7 @@ */ #include -#include +#include #include #include diff --git a/c++/src/objtools/edit/autodef_source_desc.cpp b/c++/src/objmgr/util/autodef_source_desc.cpp similarity index 98% rename from c++/src/objtools/edit/autodef_source_desc.cpp rename to c++/src/objmgr/util/autodef_source_desc.cpp index b8937176..657bcb4f 100644 --- a/c++/src/objtools/edit/autodef_source_desc.cpp +++ b/c++/src/objmgr/util/autodef_source_desc.cpp @@ -1,4 +1,4 @@ -/* $Id: autodef_source_desc.cpp 432403 2014-04-14 11:58:47Z bollin $ +/* $Id: autodef_source_desc.cpp 530196 2017-03-13 12:59:43Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,7 +31,7 @@ */ #include -#include +#include #include #include #include diff --git a/c++/src/objtools/edit/autodef_source_group.cpp b/c++/src/objmgr/util/autodef_source_group.cpp similarity index 93% rename from c++/src/objtools/edit/autodef_source_group.cpp rename to c++/src/objmgr/util/autodef_source_group.cpp index beba3977..0fa2ab0b 100644 --- a/c++/src/objtools/edit/autodef_source_group.cpp +++ b/c++/src/objmgr/util/autodef_source_group.cpp @@ -1,4 +1,4 @@ -/* $Id: autodef_source_group.cpp 387372 2013-01-29 14:57:41Z bollin $ +/* $Id: autodef_source_group.cpp 530329 2017-03-14 11:07:17Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,7 +31,6 @@ */ #include -//#include #include #include #include @@ -44,7 +43,7 @@ #include -#include +#include BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) @@ -188,26 +187,27 @@ CAutoDefSourceDescription::TModifierVector CAutoDefSourceGroup::GetModifiersPres return mods; } +//isOrgMod, subtype +typedef pair TModPair; +typedef map TModMap; CAutoDefSourceDescription::TModifierVector CAutoDefSourceGroup::GetModifiersPresentForAny() { CAutoDefSourceDescription::TModifierVector mods; CAutoDefSourceDescription::TModifierVector::iterator mod_it_other; - bool found_mod; + TModMap present_any; mods.clear(); ITERATE (TSourceDescriptionVector, it, m_SourceList) { ITERATE (CAutoDefSourceDescription::TModifierVector, mod_it, (*it)->GetModifiers()) { - found_mod = false; - mod_it_other = mods.begin(); - while (mod_it_other != mods.end() && !found_mod) { - if (mod_it->Compare (*mod_it_other) == 0) { - found_mod = true; + // don't include notes. both CSubSource::eSubtype_other and COrgMod::eSubtype_other + // are notes and have the same numerical value (255) + if (mod_it->GetSubtype() != (int)CSubSource::eSubtype_other) { + TModPair x(mod_it->IsOrgMod(), mod_it->GetSubtype()); + if (present_any.find(x) == present_any.end()) { + present_any[x] = true; + mods.push_back(*mod_it); } - mod_it_other++; - } - if (!found_mod) { - mods.push_back (*mod_it); } } } diff --git a/c++/src/objmgr/util/create_defline.cpp b/c++/src/objmgr/util/create_defline.cpp index 64523473..f8e8eef4 100644 --- a/c++/src/objmgr/util/create_defline.cpp +++ b/c++/src/objmgr/util/create_defline.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,66 @@ USING_SCOPE(objects); USING_SCOPE(sequence); USING_SCOPE(feature); +#define NCBI_USE_ERRCODE_X ObjMgr_SeqUtil + +enum EHidePart { eHideNone, eHideType, eHideValue }; +class CDefLineJoiner +{ +public: + CDefLineJoiner(bool show_mods = false) + : m_ShowMods(show_mods) + { + } + void Add(const CTempString &name, const CTempString &value, EHidePart hide = eHideNone) + { + if (m_ShowMods) + { + if (name.empty() || value.empty()) { + return; + } + // The case of no quotes is much more common, so optimize for that + if (value.find_first_of("\"=") != string::npos) { + // rarer case: bad characters in value name, so + // we need surrounding double-quotes and we need to change + // double-quotes to single-quotes. + m_Joiner.Add(" [").Add(name).Add("=\""); + ReplaceAndAdd(value, "\"", "'"); + m_Joiner.Add("\"]"); + } else { + m_Joiner.Add(" [").Add(name).Add("=").Add(value).Add("]"); + } + } + else + { + if (eHideNone == hide && !name.empty()) { + m_Joiner.Add(" ").Add(name); + } + if (!value.empty()) { + m_Joiner.Add(" ").Add(value); + } + } + } + void Join(std::string* result) const + { + m_Joiner.Join(result); + } +private: + void ReplaceAndAdd(const CTempString &value, + const CTempString &replace_what, const CTempString &replace_with) + { + // commented out: CTempString is immutable + //string fixed = NStr::Replace(value, "\"", "'"); + CTempString::size_type p1 = 0, p2 = value.length(); + for (; (p2 = value.find(replace_what, p1)) != string::npos; + p1 = p2 + 1, p2 = value.length()) { + m_Joiner.Add(value.substr(p1, p2 - p1)).Add(replace_with); + } + m_Joiner.Add(value.substr(p1, p2 - p1)); + } + bool m_ShowMods; + CTextJoiner<64, CTempString> m_Joiner; +}; + // constructor CDeflineGenerator::CDeflineGenerator (void) { @@ -153,7 +214,7 @@ for (SELECTED_SEQFEAT_ON_BIOSEQ_HANDLE_ITERATOR(Itr, Var, Sel); Itr; ++Itr) #define comma_space twochars(',',' ') #define semicolon_space twochars(';',' ') -void x_CleanAndCompress(string& dest, const CTempString& instr) +void x_CleanAndCompress(string& dest, const CTempString& instr, bool isProt) { size_t left = instr.size(); // this is the input stream @@ -243,6 +304,11 @@ void x_CleanAndCompress(string& dest, const CTempString& instr) } dest.resize(out - dest.c_str()); + + if (isProt) { + NStr::ReplaceInPlace (dest, ". [", " ["); + NStr::ReplaceInPlace (dest, ", [", " ["); + } } static const char* x_OrganelleName ( @@ -390,6 +456,7 @@ void CDeflineGenerator::x_SetFlags ( m_MainTitle.clear(); m_GeneralStr.clear(); + m_GeneralId = 0; m_PatentCountry.clear(); m_PatentNumber.clear(); @@ -516,6 +583,8 @@ void CDeflineGenerator::x_SetFlags ( const CObject_id& oid = gen_id.GetTag(); if (oid.IsStr()) { m_GeneralStr = oid.GetStr(); + } else if (oid.IsId()) { + m_GeneralId = oid.GetId(); } } } @@ -801,7 +870,7 @@ void CDeflineGenerator::x_SetFlags ( FOR_EACH_STRING_IN_LIST (kw_itr, *keywords) { const string& clause = *kw_itr; list kywds; - NStr::Split( clause, ";", kywds ); + NStr::Split( clause, ";", kywds, NStr::fSplit_Tokenize ); FOR_EACH_STRING_IN_LIST ( k_itr, kywds ) { const string& str = *k_itr; if (NStr::EqualNocase (str, "UNORDERED")) { @@ -1007,7 +1076,7 @@ void CDeflineGenerator::x_SetBioSrc ( } ++feat_it; } - } catch ( const exception& e ) { + } catch ( const exception& ) { // ERR_POST(Error << "Unable to iterate source features while constructing default definition line"); } } @@ -1083,65 +1152,49 @@ static bool x_EndsWithStrain ( void CDeflineGenerator::x_SetTitleFromBioSrc (void) { - string clnbuf; - vector clnvec; - CTextJoiner<12, CTempString> joiner; + CDefLineJoiner joiner; - joiner.Add(m_Taxname); + joiner.Add("organism", m_Taxname, eHideType); if (! m_Strain.empty()) { CTempString add(m_Strain, 0, m_Strain.find(';')); if (! x_EndsWithStrain (m_Taxname, add)) { - joiner.Add(" strain ").Add(add); + joiner.Add("strain", add); } } if (! m_Breed.empty()) { - joiner.Add(" breed ").Add(m_Breed.substr (0, m_Breed.find(';'))); + joiner.Add("breed", m_Breed.substr (0, m_Breed.find(';'))); } if (! m_Cultivar.empty()) { - joiner.Add(" cultivar ").Add(m_Cultivar.substr (0, m_Cultivar.find(';'))); + joiner.Add("cultivar", m_Cultivar.substr (0, m_Cultivar.find(';'))); } if (! m_Isolate.empty()) { // x_EndsWithStrain just checks for supplied pattern, using here for isolate if (! x_EndsWithStrain (m_Taxname, m_Isolate)) { - joiner.Add(" isolate ").Add(m_Isolate); + joiner.Add("isolate", m_Isolate); } } + if (! m_Chromosome.empty()) { - joiner.Add(" chromosome ").Add(m_Chromosome); - } + joiner.Add("location", "chromosome", eHideType); + joiner.Add("chromosome", m_Chromosome, eHideType); + } else if ( !m_Plasmid.empty()) { + joiner.Add("location", m_Organelle, eHideType); //"plasmid" + joiner.Add("plasmid-name", m_Plasmid, eHideType); + } else if (! m_Organelle.empty()) { + joiner.Add("location", m_Organelle, eHideType); + } + + string clnbuf; + vector clnvec; if (m_has_clone) { x_DescribeClones (clnvec, clnbuf); ITERATE (vector, it, clnvec) { - joiner.Add(*it); + joiner.Add("clone", *it, eHideType); } } if (! m_Map.empty()) { - joiner.Add(" map ").Add(m_Map); - } - - if (! m_Organelle.empty()) { - if (NStr::FindNoCase(m_Organelle, "chromosome") != NPOS) { - /* - if (m_Chromosome.empty()) { - joiner.Add(" ").Add(m_Organelle); - } - */ - } else if (NStr::FindNoCase(m_Organelle, "plasmid") != NPOS) { - if (m_Plasmid.empty() && m_Chromosome.empty()) { - joiner.Add(" ").Add(m_Organelle); - } - } else { - joiner.Add(" ").Add(m_Organelle); - } - } - - if (! m_Plasmid.empty()) { - if (NStr::FindNoCase(m_Organelle, "plasmid") != NPOS) { - joiner.Add(" plasmid ").Add(m_Plasmid); - } else { - joiner.Add(" ").Add(m_Plasmid); - } + joiner.Add("map", m_Map); } joiner.Join(&m_MainTitle); @@ -1158,48 +1211,27 @@ void CDeflineGenerator::x_SetTitleFromNC (void) // require taxname to be set if (m_Taxname.empty()) return; - const char * seq_tag, * gen_tag, * pls_pfx = " "; - - CTextJoiner<6, CTempString> joiner; - - - switch (m_MICompleteness) { - case NCBI_COMPLETENESS(partial): - case NCBI_COMPLETENESS(no_left): - case NCBI_COMPLETENESS(no_right): - case NCBI_COMPLETENESS(no_ends): - seq_tag = ", partial sequence"; - gen_tag = ", genome"; - break; - default: - seq_tag = ", complete sequence"; - gen_tag = ", complete genome"; - break; - } + CDefLineJoiner joiner; - joiner.Add(m_Taxname); + joiner.Add("organism", m_Taxname, eHideType); + bool add_gen_tag = false; if (NStr::FindNoCase (m_Taxname, "plasmid") != NPOS) { - joiner.Add(seq_tag); - } else if (m_IsPlasmid) { + // + } else if (m_IsPlasmid || ! m_Plasmid.empty()) { if (m_Plasmid.empty()) { - joiner.Add(" unnamed plasmid").Add(seq_tag); + joiner.Add("", "unnamed plasmid", eHideType); } else { + if ( !m_IsPlasmid) { // do we need this? + joiner.Add("location", m_Organelle, eHideType); + } if (NStr::FindNoCase(m_Plasmid, "plasmid") == NPOS && NStr::FindNoCase(m_Plasmid, "element") == NPOS) { - pls_pfx = " plasmid "; + joiner.Add("plasmid", m_Plasmid); + } else { + joiner.Add("", m_Plasmid, eHideType); } - joiner.Add(pls_pfx).Add(m_Plasmid).Add(seq_tag); - } - } else if (! m_Plasmid.empty() ) { - if (! m_Organelle.empty()) { - joiner.Add(" ").Add(m_Organelle); - } - if (NStr::FindNoCase(m_Plasmid, "plasmid") == NPOS && - NStr::FindNoCase(m_Plasmid, "element") == NPOS) { - pls_pfx = " plasmid "; } - joiner.Add(pls_pfx).Add(m_Plasmid).Add(seq_tag); } else if ( ! m_Organelle.empty() ) { if ( m_Chromosome.empty() ) { switch (m_Genome) { @@ -1208,29 +1240,35 @@ void CDeflineGenerator::x_SetTitleFromNC (void) case NCBI_GENOME(kinetoplast): case NCBI_GENOME(plastid): case NCBI_GENOME(apicoplast): - joiner.Add(" ").Add(m_Organelle); + joiner.Add("location", m_Organelle, eHideType); break; } - joiner.Add(gen_tag); - } else if (m_IsChromosome) { - joiner.Add(" chromosome ").Add(m_Chromosome).Add(seq_tag); + add_gen_tag = true; } else { - joiner.Add(" ").Add(m_Organelle).Add(" chromosome ").Add(m_Chromosome) - .Add(seq_tag); + if (! m_IsChromosome) { + joiner.Add("location", m_Organelle, eHideType); + } + joiner.Add("chromosome", m_Chromosome); } } else if (! m_Segment.empty()) { if (m_Segment.find ("DNA") == NPOS && m_Segment.find ("RNA") == NPOS && m_Segment.find ("segment") == NPOS && m_Segment.find ("Segment") == NPOS) { - joiner.Add(" segment ").Add(m_Segment).Add(seq_tag); + joiner.Add("segment", m_Segment); } else { - joiner.Add(" ").Add(m_Segment).Add(seq_tag); + joiner.Add("", m_Segment, eHideType); } } else if (! m_Chromosome.empty()) { - joiner.Add(" chromosome ").Add(m_Chromosome).Add(seq_tag); + joiner.Add("chromosome", m_Chromosome); + } else { + add_gen_tag = true; + } + + if (add_gen_tag) { + joiner.Add("completeness", (x_IsComplete() ? ", complete genome" : ", genome"), eHideType); } else { - joiner.Add(gen_tag); + joiner.Add("completeness", (x_IsComplete() ? ", complete sequence" : ", partial sequence"), eHideType); } joiner.Join(&m_MainTitle); @@ -1402,45 +1440,45 @@ void CDeflineGenerator::x_SetTitleFromPDB (void) void CDeflineGenerator::x_SetTitleFromGPipe (void) { - string clnbuf; - vector clnvec; - CTextJoiner<12, CTempString> joiner; - - joiner.Add(m_Taxname); + CDefLineJoiner joiner; - const char * pls_pfx = " "; + joiner.Add("organism", m_Taxname, eHideType); if ( ! m_Organelle.empty() && NStr::FindNoCase (m_Organelle, "plasmid") != NPOS) { - joiner.Add(m_Organelle); + joiner.Add("location", m_Organelle, eHideType); } if (! m_Strain.empty()) { CTempString add(m_Strain, 0, m_Strain.find(';')); if (! x_EndsWithStrain (m_Taxname, add)) { - joiner.Add(" strain ").Add(add); + joiner.Add("strain", add); } } if (! m_Chromosome.empty()) { - joiner.Add(" chromosome ").Add(m_Chromosome); + joiner.Add("chromosome", m_Chromosome); } if (m_has_clone) { + string clnbuf; + vector clnvec; x_DescribeClones (clnvec, clnbuf); ITERATE (vector, it, clnvec) { - joiner.Add(*it); + joiner.Add("clone", *it, eHideType); } } if (! m_Map.empty()) { - joiner.Add(" map ").Add(m_Map); + joiner.Add("map", m_Map); } if (! m_Plasmid.empty()) { if (NStr::FindNoCase(m_Plasmid, "plasmid") == NPOS && NStr::FindNoCase(m_Plasmid, "element") == NPOS) { - pls_pfx = " plasmid "; + joiner.Add("plasmid", m_Plasmid); + } else { + joiner.Add("", m_Plasmid); } - joiner.Add(pls_pfx).Add(m_Plasmid); } - if (m_MICompleteness == NCBI_COMPLETENESS(complete)) { - joiner.Add(", complete sequence"); + + if (x_IsComplete()) { + joiner.Add("completeness", ", complete sequence", eHideType); } joiner.Join(&m_MainTitle); @@ -1588,16 +1626,13 @@ static CConstRef x_GetSourceFeatViaCDS ( if (cds_loc) { CRef cleaned_location( new CSeq_loc ); cleaned_location->Assign( *cds_loc ); - if (cleaned_location->IsSetStrand() && IsReverse(cleaned_location->GetStrand())) { + CConstRef src_feat + = GetBestOverlappingFeat (*cleaned_location, CSeqFeatData::eSubtype_biosrc, eOverlap_SubsetRev, scope); + if (! src_feat && cleaned_location->IsSetStrand() && IsReverse(cleaned_location->GetStrand())) { CRef rev_loc(SeqLocRevCmpl(*cleaned_location, &scope)); cleaned_location->Assign(*rev_loc); + src_feat = GetBestOverlappingFeat (*cleaned_location, CSeqFeatData::eSubtype_biosrc, eOverlap_SubsetRev, scope); } - /* - CConstRef src_feat - = GetOverlappingSource (*cleaned_location, scope); - */ - CConstRef src_feat - = GetBestOverlappingFeat (*cleaned_location, CSeqFeatData::eSubtype_biosrc, eOverlap_SubsetRev, scope); if (src_feat) { const CSeq_feat& feat = *src_feat; if (feat.IsSetData()) { @@ -1642,58 +1677,30 @@ bool CDeflineGenerator::x_CDShasLowQualityException ( return false; } -/* static const char* s_proteinOrganellePrefix [] = { - "", - "", - "chloroplast", - "chromoplast", - "kinetoplast", - "mitochondrion", - "plastid", - "macronuclear", - "extrachromosomal", - "plasmid", - "", - "", - "cyanelle", - "proviral", - "virus", - "nucleomorph", - "apicoplast", - "leucoplast", - "protoplast", - "endogenous virus", - "hydrogenosome", - "chromosome", - "chromatophore" -}; -*/ - -static const char* s_proteinOrganellePrefix [] = { - "", - "", - "chloroplast", - "chromoplast", - "kinetoplast", - "mitochondrion", - "plastid", - "macronuclear", - "", - "plasmid", - "", - "", - "cyanelle", - "", - "", - "nucleomorph", - "apicoplast", - "leucoplast", - "protoplast", - "endogenous virus", - "hydrogenosome", - "", - "chromatophore" + "", // "", + "", // "", + "chloroplast", // "chloroplast", + "chromoplast", // "chromoplast", + "kinetoplast", // "kinetoplast", + "mitochondrion", // "mitochondrion", + "plastid", // "plastid", + "macronuclear", // "macronuclear", + "", // "extrachromosomal", + "plasmid", // "plasmid", + "", // "", + "", // "", + "cyanelle", // "cyanelle", + "", // "proviral", + "", // "virus", + "nucleomorph", // "nucleomorph", + "apicoplast", // "apicoplast", + "leucoplast", // "leucoplast", + "protoplast", // "protoplast", + "endogenous virus", // "endogenous virus", + "hydrogenosome", // "hydrogenosome", + "", // "chromosome", + "chromatophore" // "chromatophore" }; static string s_RemoveBracketedOrgFromEnd (string str, string taxname) @@ -1713,12 +1720,210 @@ static string s_RemoveBracketedOrgFromEnd (string str, string taxname) if (suffix.length() != taxlen + 1) return str; if (NStr::StartsWith(suffix, taxname)) { str.erase (cp); - x_CleanAndCompress(final, str); + x_CleanAndCompress(final, str, true); } return final; } +void CDeflineGenerator::x_SetTitleFromProteinIdx ( + const CBioseq_Handle& bsh +) + +{ + CConstRef cds_feat; + CConstRef prot; + CConstRef prot_feat; + CConstRef gene; + CConstRef src; + CTempString locus_tag; + + CRef bsx = m_Idx->GetBioseqIndex (bsh); + if (! bsx) { + return; + } + + CRef prtx = bsx->GetBestProteinFeature(); + + CRef sfxp = bsx->GetFeatureForProduct(); + + if (prtx) { + const CMappedFeat mf = prtx->GetMappedFeat(); + const CProt_ref& prp = mf.GetData().GetProt(); + + const char* prefix = ""; + FOR_EACH_NAME_ON_PROT (prp_itr, prp) { + const string& str = *prp_itr; + string trimmed = s_RemoveBracketedOrgFromEnd (str, m_Taxname); + m_MainTitle += prefix; + m_MainTitle += trimmed; + if (! m_AllProtNames) { + break; + } + prefix = "; "; + } + + if (! m_MainTitle.empty()) { + // strip trailing periods, commas, and spaces + SIZE_TYPE pos = m_MainTitle.find_last_not_of (".,;~ "); + if (pos != NPOS) { + m_MainTitle.erase (pos + 1); + } + + int offset = 0; + int delta = 0; + string comma = ""; + string isoform = ""; + if (NStr::StartsWith (m_MainTitle, "hypothetical protein")) { + offset = 20; + } else if (NStr::StartsWith (m_MainTitle, "uncharacterized protein")) { + offset = 23; + } + if (offset > 0 && offset < m_MainTitle.length()) { + if (m_MainTitle [offset] == ',' && m_MainTitle [offset + 1] == ' ') { + comma = ", isoform "; + delta = 2; + } + if (m_MainTitle [offset] == ' ') { + comma = " isoform "; + delta = 1; + } + if (NStr::StartsWith (m_MainTitle.substr (offset + delta), "isoform ")) { + isoform = m_MainTitle.substr (offset + delta + 8); + // !!! check for single alphanumeric string + m_MainTitle.erase (offset); + } + } + if ((NStr::EqualNocase (m_MainTitle, "hypothetical protein") || + NStr::EqualNocase (m_MainTitle, "uncharacterized protein")) + /* && !m_LocalAnnotsOnly */ ) { + if (sfxp) { + CRef fsx = sfxp->GetBestGene(); + if (fsx) { + const CGene_ref& grp = fsx->GetMappedFeat().GetData().GetGene(); + if (grp.IsSetLocus_tag()) { + locus_tag = grp.GetLocus_tag(); + } + } + } + if (! locus_tag.empty()) { + m_MainTitle += " " + string(locus_tag) + string(comma) + string(isoform); + } + } + } + if (m_MainTitle.empty() && !m_LocalAnnotsOnly) { + if (prp.IsSetDesc()) { + m_MainTitle = prp.GetDesc(); + } + } + if (m_MainTitle.empty() && !m_LocalAnnotsOnly) { + FOR_EACH_ACTIVITY_ON_PROT (act_itr, prp) { + const string& str = *act_itr; + m_MainTitle = str; + break; + } + } + } + + if (m_MainTitle.empty() && !m_LocalAnnotsOnly) { + if (sfxp) { + CRef fsx = sfxp->GetBestGene(); + if (fsx) { + const CGene_ref& grp = fsx->GetMappedFeat().GetData().GetGene(); + if (grp.IsSetLocus()) { + m_MainTitle = grp.GetLocus(); + } + if (m_MainTitle.empty()) { + FOR_EACH_SYNONYM_ON_GENE (syn_itr, grp) { + const string& str = *syn_itr; + m_MainTitle = str; + break; + } + } + if (m_MainTitle.empty()) { + if (grp.IsSetDesc()) { + m_MainTitle = grp.GetDesc(); + } + } + } + } + if (! m_MainTitle.empty()) { + m_MainTitle += " gene product"; + } + } + + if (m_MainTitle.empty() && !m_LocalAnnotsOnly) { + m_MainTitle = "unnamed protein product"; + if (sfxp) { + CRef fsx = sfxp->GetBestGene(); + if (fsx) { + const CGene_ref& grp = fsx->GetMappedFeat().GetData().GetGene(); + if (grp.IsSetLocus_tag()) { + locus_tag = grp.GetLocus_tag(); + } + } + } + if (! locus_tag.empty()) { + m_MainTitle += " " + string(locus_tag); + } + } + + if (sfxp) { + const CMappedFeat mf = sfxp->GetMappedFeat(); + const CSeq_feat& cds = mf.GetOriginalFeature(); + if (x_CDShasLowQualityException (cds)) { + const string& low_qual = "LOW QUALITY PROTEIN: "; + if (NStr::FindNoCase (m_MainTitle, low_qual, 0) == NPOS) { + string tmp = m_MainTitle; + m_MainTitle = low_qual + tmp; + } + } + } + + // strip trailing periods, commas, and spaces + SIZE_TYPE pos = m_MainTitle.find_last_not_of (".,;~ "); + if (pos != NPOS) { + m_MainTitle.erase (pos + 1); + } + + if (! x_IsComplete() /* && m_MainTitle.find(", partial") == NPOS */) { + m_MainTitle += ", partial"; + } + + if (m_OmitTaxonomicName) return; + + CTempString taxname = m_Taxname; + + if (m_Genome >= NCBI_GENOME(chloroplast) && m_Genome <= NCBI_GENOME(chromatophore)) { + const char * organelle = s_proteinOrganellePrefix [m_Genome]; + if ( organelle[0] != '\0' && ! taxname.empty() + /* && NStr::Find (taxname, organelle) == NPOS */) { + m_MainTitle += " ("; + m_MainTitle += organelle; + m_MainTitle += ")"; + } + } + + // check for special taxname, go to overlapping source feature + if ((taxname.empty() || + (!NStr::EqualNocase (taxname, "synthetic construct") && + !NStr::EqualNocase (taxname, "artificial sequence") && + taxname.find ("vector") == NPOS && + taxname.find ("Vector") == NPOS)) && + !m_LocalAnnotsOnly) { + src = x_GetSourceFeatViaCDS (bsh); + if (src.NotEmpty() && src->IsSetTaxname()) { + taxname = src->GetTaxname(); + } + } + + if (m_IsCrossKingdom && ! m_FirstSuperKingdom.empty() && ! m_SecondSuperKingdom.empty()) { + m_MainTitle += " [" + string(m_FirstSuperKingdom) + "][" + string(m_SecondSuperKingdom) + "]"; + } else if (! taxname.empty() /* && m_MainTitle.find(taxname) == NPOS */) { + m_MainTitle += " [" + string(taxname) + "]"; + } +} + void CDeflineGenerator::x_SetTitleFromProtein ( const CBioseq_Handle& bsh ) @@ -1730,7 +1935,6 @@ void CDeflineGenerator::x_SetTitleFromProtein ( CConstRef gene; CConstRef src; CTempString locus_tag; - bool partial = false; // gets longest protein on Bioseq, parts set, or seg set, even if not // full-length @@ -1741,17 +1945,6 @@ void CDeflineGenerator::x_SetTitleFromProtein ( prot = &prot_feat->GetData().GetProt(); } - switch (m_MICompleteness) { - case NCBI_COMPLETENESS(partial): - case NCBI_COMPLETENESS(no_left): - case NCBI_COMPLETENESS(no_right): - case NCBI_COMPLETENESS(no_ends): - partial = true; - break; - default: - break; - } - const CMappedFeat& mapped_cds = GetMappedCDSForProduct (bsh); if (prot) { @@ -1801,7 +1994,7 @@ void CDeflineGenerator::x_SetTitleFromProtein ( } if ((NStr::EqualNocase (m_MainTitle, "hypothetical protein") || NStr::EqualNocase (m_MainTitle, "uncharacterized protein")) - && !m_LocalAnnotsOnly ) { + /* && !m_LocalAnnotsOnly */ ) { gene = x_GetGeneRefViaCDS (mapped_cds); if (gene) { const CGene_ref& grp = *gene; @@ -1884,7 +2077,7 @@ void CDeflineGenerator::x_SetTitleFromProtein ( m_MainTitle.erase (pos + 1); } - if (partial /* && m_MainTitle.find(", partial") == NPOS */) { + if (! x_IsComplete() /* && m_MainTitle.find(", partial") == NPOS */) { m_MainTitle += ", partial"; } @@ -1998,44 +2191,43 @@ void CDeflineGenerator::x_SetTitleFromSegSeq ( { const char * completeness = "complete"; bool cds_found = false; - string locus, product, clnbuf; - vector clnvec; - CTextJoiner<13, CTempString> joiner; + string locus, product; + CDefLineJoiner joiner; if (m_Taxname.empty()) { m_Taxname = "Unknown"; } + joiner.Add("organism", m_Taxname, eHideType); if ( !m_LocalAnnotsOnly ) { cds_found = x_GetSegSeqInfoViaCDS(locus, product, completeness, bsh); } - - joiner.Add(m_Taxname); - if ( !cds_found) { if (! m_Strain.empty() && ! x_EndsWithStrain (m_Taxname, m_Strain) ) { - joiner.Add(" strain ").Add(m_Strain); + joiner.Add("strain", m_Strain); } else if (! m_Clone.empty() /* && m_Clone.find(" clone ") != NPOS */) { + string clnbuf; + vector clnvec; x_DescribeClones (clnvec, clnbuf); ITERATE (vector, it, clnvec) { - joiner.Add(*it); + joiner.Add("clone", *it, eHideType); } } else if (! m_Isolate.empty() ) { - joiner.Add(" isolate ").Add(m_Isolate); + joiner.Add("isolate", m_Isolate); } } if (! product.empty()) { - joiner.Add(" ").Add(product); + joiner.Add("product", product, eHideType); } + joiner.Join(&m_MainTitle); if (! locus.empty()) { - joiner.Add(" (").Add(locus).Add(")"); + m_MainTitle += " (" + locus + ")"; } if ((! product.empty()) || (! locus.empty())) { - joiner.Add(" gene, ").Add(completeness).Add(" cds"); + m_MainTitle += " gene, " + string(completeness) + " cds"; } - joiner.Join(&m_MainTitle); NStr::TruncateSpacesInPlace(m_MainTitle); } @@ -2043,51 +2235,57 @@ void CDeflineGenerator::x_SetTitleFromSegSeq ( void CDeflineGenerator::x_SetTitleFromWGS (void) { - string clnbuf; - vector clnvec; - CTextJoiner<14, CTempString> joiner; + CDefLineJoiner joiner; - joiner.Add(m_Taxname); + joiner.Add("organism", m_Taxname, eHideType); if (! m_Strain.empty()) { if (! x_EndsWithStrain (m_Taxname, m_Strain)) { - joiner.Add(" strain "); - joiner.Add(m_Strain.substr (0, m_Strain.find(';'))); + joiner.Add("strain", m_Strain.substr (0, m_Strain.find(';'))); } } else if (! m_Breed.empty()) { - joiner.Add(" breed ").Add(m_Breed.substr (0, m_Breed.find(';'))); + joiner.Add("breed", m_Breed.substr (0, m_Breed.find(';'))); } else if (! m_Cultivar.empty()) { - joiner.Add(" cultivar "); - joiner.Add(m_Cultivar.substr (0, m_Cultivar.find(';'))); + joiner.Add("cultivar", m_Cultivar.substr (0, m_Cultivar.find(';'))); } if (! m_Isolate.empty()) { // x_EndsWithStrain just checks for supplied pattern, using here for isolate if (! x_EndsWithStrain (m_Taxname, m_Isolate)) { - joiner.Add(" isolate ").Add(m_Isolate); + joiner.Add("isolate", m_Isolate); } } if (! m_Chromosome.empty()) { - joiner.Add(" chromosome ").Add(m_Chromosome); + joiner.Add("chromosome", m_Chromosome); } if (! m_Clone.empty()) { + string clnbuf; + vector clnvec; x_DescribeClones (clnvec, clnbuf); ITERATE (vector, it, clnvec) { - joiner.Add(*it); + joiner.Add("clone", *it, eHideType); } } if (! m_Map.empty()) { - joiner.Add(" map ").Add(m_Map); + joiner.Add("map", m_Map); } if (! m_Plasmid.empty()) { if (m_IsWGS) { - joiner.Add(" plasmid ").Add(m_Plasmid); + joiner.Add("plasmid", m_Plasmid); } } if (m_Genome == NCBI_GENOME(plasmid) && m_Topology == NCBI_SEQTOPOLOGY(circular)) { } else if (m_Genome == NCBI_GENOME(chromosome)) { - } else if (! m_GeneralStr.empty() && m_GeneralStr != m_Chromosome - && (! m_IsWGS || m_GeneralStr != m_Plasmid)) { - joiner.Add(" ").Add(m_GeneralStr); + } else if (! m_GeneralStr.empty()) { + if (m_GeneralStr != m_Chromosome && (! m_IsWGS || m_GeneralStr != m_Plasmid)) { + joiner.Add("", m_GeneralStr, eHideType); + } + } else if (m_GeneralId > 0) { + string tmp = NStr::NumericToString (m_GeneralId); + if (! tmp.empty()) { + if (tmp != m_Chromosome && (! m_IsWGS || tmp != m_Plasmid)) { + joiner.Add("", tmp, eHideType); + } + } } joiner.Join(&m_MainTitle); @@ -2098,37 +2296,34 @@ void CDeflineGenerator::x_SetTitleFromWGS (void) void CDeflineGenerator::x_SetTitleFromMap (void) { - string clnbuf; - vector clnvec; - CTextJoiner<14, CTempString> joiner; + CDefLineJoiner joiner; - joiner.Add(m_Taxname); + joiner.Add("organism", m_Taxname, eHideType); if (! m_Strain.empty()) { if (! x_EndsWithStrain (m_Taxname, m_Strain)) { - joiner.Add(" strain "); - joiner.Add(m_Strain.substr (0, m_Strain.find(';'))); + joiner.Add("strain", m_Strain.substr (0, m_Strain.find(';'))); } } if (! m_Chromosome.empty()) { - joiner.Add(" chromosome ").Add(m_Chromosome); + joiner.Add("chromosome", m_Chromosome); } else if (m_IsChromosome) { - joiner.Add(" chromosome"); + joiner.Add("location", "chromosome", eHideType); } if (! m_Plasmid.empty()) { - joiner.Add(" plasmid ").Add(m_Plasmid); + joiner.Add("plasmid", m_Plasmid); } else if (m_IsPlasmid) { - joiner.Add(" plasmid"); + joiner.Add("location", "plasmid", eHideType); } if (! m_Isolate.empty()) { - joiner.Add(" isolate ").Add(m_Isolate); + joiner.Add("isolate", m_Isolate); } + joiner.Join(&m_MainTitle); if (! m_rEnzyme.empty()) { - joiner.Add(", ").Add(m_rEnzyme).Add(" whole genome map"); + m_MainTitle += ", " + m_rEnzyme + " whole genome map"; } - joiner.Join(&m_MainTitle); NStr::TruncateSpacesInPlace(m_MainTitle); } @@ -2414,7 +2609,6 @@ void CDeflineGenerator::x_AdjustProteinTitleSuffix ( CBioSource::TGenome genome; size_t pos, tpos = NPOS, opos = NPOS; int len1, len2; - bool partial = false; CConstRef src; if (m_Source.Empty()) return; @@ -2441,17 +2635,6 @@ void CDeflineGenerator::x_AdjustProteinTitleSuffix ( } } - switch (m_MICompleteness) { - case NCBI_COMPLETENESS(partial): - case NCBI_COMPLETENESS(no_left): - case NCBI_COMPLETENESS(no_right): - case NCBI_COMPLETENESS(no_ends): - partial = true; - break; - default: - break; - } - s_TrimMainTitle (m_MainTitle); len1 = m_MainTitle.length(); @@ -2519,7 +2702,7 @@ void CDeflineGenerator::x_AdjustProteinTitleSuffix ( // then reconstruct partial (organelle) [taxname] suffix - if (partial) { + if ( !x_IsComplete()) { m_MainTitle += ", partial"; } @@ -2557,6 +2740,21 @@ void CDeflineGenerator::x_AdjustProteinTitleSuffix ( } } +bool CDeflineGenerator::x_IsComplete() const +{ + switch (m_MICompleteness) { + case NCBI_COMPLETENESS(complete): + return true; + case NCBI_COMPLETENESS(partial): + case NCBI_COMPLETENESS(no_left): + case NCBI_COMPLETENESS(no_right): + case NCBI_COMPLETENESS(no_ends): + return false; + } + return true; +} + + static const char* s_tpaPrefixList [] = { "TPA:", "TPA_exp:", @@ -2566,6 +2764,127 @@ static const char* s_tpaPrefixList [] = { "TSA:", "UNVERIFIED:" }; +string CDeflineGenerator::x_GetModifiers(const CBioseq_Handle & bsh) +{ + CDefLineJoiner joiner(true); + + x_SetBioSrc (bsh); + + joiner.Add("location", m_Organelle); + if (m_IsChromosome || !m_Chromosome.empty()) { + joiner.Add("chromosome", m_Chromosome); + } + if (m_IsPlasmid || !m_Plasmid.empty()) { + joiner.Add("plasmid-name", m_Plasmid); + } + if (m_MICompleteness == NCBI_COMPLETENESS(complete)) { + joiner.Add("completeness", CTempString("complete")); + } + + // print [topology=...], if necessary + if (bsh.CanGetInst_Topology()) { + CSeq_inst::ETopology topology = bsh.GetInst_Topology(); + if (topology == CSeq_inst::eTopology_circular) { + joiner.Add("topology", CTempString("circular")); + } + } + + // bsh modifiers retrieved from Biosource.Org-ref + // [organism=...], etc. + + bool strain_seen = false; + string gcode; // should be in the same scope as joiner.Join() because joiner stores CTempString + + try { + const COrg_ref & org = sequence::GetOrg_ref(bsh); + if (org.IsSetTaxname()) { + joiner.Add("organism", org.GetTaxname()); + } + if (org.IsSetOrgname()) { + const COrg_ref::TOrgname & orgname = org.GetOrgname(); + if (orgname.IsSetMod()) { + ITERATE(COrgName::TMod, mod_iter, orgname.GetMod()) { + const COrgMod & mod = **mod_iter; + if (mod.IsSetSubtype()) { + switch (mod.GetSubtype()) { + case COrgMod::eSubtype_strain: + if (mod.IsSetSubname()) { + if (strain_seen) { + ERR_POST_X(9, Warning << __FUNCTION__ << ": " + << "key 'strain' would appear multiple times, but only using the first."); + } + else { + strain_seen = true; + joiner.Add("strain", mod.GetSubname()); + } + } + break; + default: + // ignore; do nothing + break; + } + } + } + } + if (orgname.IsSetGcode()) { + gcode = std::to_string(orgname.GetGcode()); + joiner.Add("gcode", gcode); + } + } + } + catch (CException &) { + // ignore exception; it probably just means there's no org-ref + } + + typedef SStaticPair TTechMapEntry; + static const TTechMapEntry sc_TechArray[] = { + // note that the text values do *NOT* precisely correspond with + // the names in the ASN.1 schema files + { CMolInfo::eTech_unknown, "?" }, + { CMolInfo::eTech_standard, "standard" }, + { CMolInfo::eTech_est, "EST" }, + { CMolInfo::eTech_sts, "STS" }, + { CMolInfo::eTech_survey, "survey" }, + { CMolInfo::eTech_genemap, "genetic map" }, + { CMolInfo::eTech_physmap, "physical map" }, + { CMolInfo::eTech_derived, "derived" }, + { CMolInfo::eTech_concept_trans, "concept-trans" }, + { CMolInfo::eTech_seq_pept, "seq-pept" }, + { CMolInfo::eTech_both, "both" }, + { CMolInfo::eTech_seq_pept_overlap, "seq-pept-overlap" }, + { CMolInfo::eTech_seq_pept_homol, "seq-pept-homol" }, + { CMolInfo::eTech_concept_trans_a, "concept-trans-a" }, + { CMolInfo::eTech_htgs_1, "htgs 1" }, + { CMolInfo::eTech_htgs_2, "htgs 2" }, + { CMolInfo::eTech_htgs_3, "htgs 3" }, + { CMolInfo::eTech_fli_cdna, "fli cDNA" }, + { CMolInfo::eTech_htgs_0, "htgs 0" }, + { CMolInfo::eTech_htc, "htc" }, + { CMolInfo::eTech_wgs, "wgs" }, + { CMolInfo::eTech_barcode, "barcode" }, + { CMolInfo::eTech_composite_wgs_htgs, "composite-wgs-htgs" }, + { CMolInfo::eTech_tsa, "tsa" } + }; + typedef CStaticPairArrayMap TTechMap; + DEFINE_STATIC_ARRAY_MAP(TTechMap, sc_TechMap, sc_TechArray); + + // print some key-value pairs + const CMolInfo * pMolInfo = sequence::GetMolInfo(bsh); + if (pMolInfo != NULL) { + const CMolInfo & molinfo = *pMolInfo; + if (molinfo.IsSetTech()) { + TTechMap::const_iterator find_iter = sc_TechMap.find(molinfo.GetTech()); + if (find_iter != sc_TechMap.end()) { + joiner.Add("tech", CTempString(find_iter->second)); + } + } + } + string modifiers; + joiner.Join(&modifiers); + m_MainTitle = (m_MainTitle.empty()) ? modifiers : modifiers + " " + m_MainTitle; + return m_MainTitle; +} + // main method string CDeflineGenerator::GenerateDefline ( @@ -2584,6 +2903,10 @@ string CDeflineGenerator::GenerateDefline ( // set flags from record components x_SetFlags (bsh, flags); + if (flags & fShowModifiers) { + return x_GetModifiers(bsh); + } + if (! m_Reconstruct) { // x_SetFlags set m_MainTitle from a suitable descriptor, if any; // now strip trailing periods, commas, semicolons, and spaces. @@ -2621,6 +2944,8 @@ string CDeflineGenerator::GenerateDefline ( x_SetTitleFromNM (bsh); } else if (m_IsNR) { x_SetTitleFromNR (bsh); + } else if (m_IsAA && m_Idx) { + x_SetTitleFromProteinIdx (bsh); } else if (m_IsAA) { x_SetTitleFromProtein (bsh); } else if (m_IsSeg && (! m_IsEST_STS_GSS)) { @@ -2630,17 +2955,17 @@ string CDeflineGenerator::GenerateDefline ( } else if (m_IsMap) { x_SetTitleFromMap (); } - } - if (m_MainTitle.empty() && m_GpipeMode) { - x_SetTitleFromGPipe (); - } + if (m_MainTitle.empty() && m_GpipeMode) { + x_SetTitleFromGPipe(); + } - if (m_MainTitle.empty()) { - // default title using source fields - x_SetTitleFromBioSrc (); - if (m_MICompleteness == NCBI_COMPLETENESS(complete) && ! m_MainTitle.empty()) { - appendComplete = true; + if (m_MainTitle.empty()) { + // default title using source fields + x_SetTitleFromBioSrc(); + if (m_MICompleteness == NCBI_COMPLETENESS(complete) && !m_MainTitle.empty()) { + appendComplete = true; + } } } @@ -2681,7 +3006,7 @@ string CDeflineGenerator::GenerateDefline ( // produce final result string penult = prefix + decoded + suffix; - x_CleanAndCompress (final, penult); + x_CleanAndCompress (final, penult, m_IsAA); if (! m_IsPDB && ! m_IsPatent && ! m_IsAA && ! m_IsSeg) { if (!final.empty() && islower ((unsigned char) final[0]) && capitalize) { @@ -2689,9 +3014,51 @@ string CDeflineGenerator::GenerateDefline ( } } + m_Feat_Tree.Reset (NULL); + m_Idx.Reset (NULL); + return final; } +string CDeflineGenerator::GenerateDefline ( + const CBioseq_Handle& bsh, + CSeqEntryIndex& idx, + TUserFlags flags +) + +{ + m_Idx = &idx; + + return GenerateDefline(bsh, flags); +} + +string CDeflineGenerator::GenerateDefline ( + const CBioseq& bioseq, + CScope& scope, + CSeqEntryIndex& idx, + TUserFlags flags +) + +{ + m_Idx = &idx; + + return GenerateDefline(bioseq, scope, flags); +} + +string CDeflineGenerator::GenerateDefline ( + const CBioseq_Handle& bsh, + feature::CFeatTree& ftree, + TUserFlags flags +) + +{ + m_ConstructedFeatTree = true; + m_InitializedFeatTree = true; + m_Feat_Tree = &ftree; + + return GenerateDefline(bsh, flags); +} + string CDeflineGenerator::GenerateDefline ( const CBioseq& bioseq, CScope& scope, @@ -2705,6 +3072,21 @@ string CDeflineGenerator::GenerateDefline ( return GenerateDefline(bsh, flags); } +string CDeflineGenerator::GenerateDefline ( + const CBioseq& bioseq, + CScope& scope, + feature::CFeatTree& ftree, + TUserFlags flags +) + +{ + m_ConstructedFeatTree = true; + m_InitializedFeatTree = true; + m_Feat_Tree = &ftree; + + return GenerateDefline(bioseq, scope, flags); +} + CDeflineGenerator::CLowQualityTextFsm::CLowQualityTextFsm(void) { AddWord ("heterogeneous population sequenced", 1); AddWord ("low-quality sequence region", 2); diff --git a/c++/src/objmgr/util/feature.cpp b/c++/src/objmgr/util/feature.cpp index 6719334c..c8744fec 100644 --- a/c++/src/objmgr/util/feature.cpp +++ b/c++/src/objmgr/util/feature.cpp @@ -1,4 +1,4 @@ -/* $Id: feature.cpp 517781 2016-10-27 16:29:06Z ivanov $ +/* $Id: feature.cpp 547367 2017-09-28 14:46:32Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1590,6 +1590,8 @@ CMappedFeat GetParentFeature(const CMappedFeat& feat) namespace { + typedef map TCanonicalIdsMap; + struct SBestInfo { typedef CFeatTree::CFeatInfo CFeatInfo; SBestInfo(void) @@ -1630,8 +1632,28 @@ namespace { // results SBestInfo* m_Best; - - SFeatRangeInfo(CFeatInfo& info, SBestInfo* best, + + void x_CanonizeId(TCanonicalIdsMap& ids_map) + { + if ( m_Id ) { + auto iter = ids_map.find(m_Id); + if ( iter != ids_map.end() ) { + m_Id = iter->second; + } + else { + CSeq_id_Handle new_id = sequence::GetId(m_Id, + m_Info->m_Feat.GetScope(), + eGetId_Seq_id_BestRank); + if ( !new_id ) { + new_id = m_Id; + } + ids_map[m_Id] = new_id; + m_Id = new_id; + } + } + } + SFeatRangeInfo(TCanonicalIdsMap& ids_map, + CFeatInfo& info, SBestInfo* best, bool by_product = false) : m_Info(&info), m_Best(best) @@ -1648,14 +1670,19 @@ namespace { m_Range = info.m_Feat.GetLocationTotalRange(); } } + // id may be non-canonical + x_CanonizeId(ids_map); } - SFeatRangeInfo(CFeatInfo& info, SBestInfo* best, + SFeatRangeInfo(TCanonicalIdsMap& ids_map, + CFeatInfo& info, SBestInfo* best, CHandleRangeMap::const_iterator it) : m_Id(it->first), m_Range(it->second.GetOverlappingRange()), m_Info(&info), m_Best(best) { + // id may be non-canonical + x_CanonizeId(ids_map); } }; struct PLessByStart { @@ -1678,7 +1705,8 @@ namespace { } }; - void s_AddRanges(vector& rr, + void s_AddRanges(TCanonicalIdsMap& ids_map, + vector& rr, CFeatTree::CFeatInfo& info, SBestInfo* best, const CSeq_loc& loc) @@ -1687,7 +1715,7 @@ namespace { CHandleRangeMap hrmap; hrmap.AddLocation(loc); ITERATE ( CHandleRangeMap, it, hrmap ) { - SFeatRangeInfo range_info(info, best, it); + SFeatRangeInfo range_info(ids_map, info, best, it); rr.push_back(range_info); } } @@ -1717,7 +1745,8 @@ namespace { { } - TRangeArray& GetIndex(const TInfoArray& feats) { + TRangeArray& GetIndex(TCanonicalIdsMap& ids_map, + const TInfoArray& feats) { if ( m_IndexedParents == feats.size() ) { return m_Index; } @@ -1728,12 +1757,13 @@ namespace { (m_ByProduct && !feat_info.m_Feat.IsSetProduct()) ) { continue; } - SFeatRangeInfo range_info(feat_info, 0, m_ByProduct); + SFeatRangeInfo range_info(ids_map, feat_info, 0, m_ByProduct); if ( range_info.m_Id ) { m_Index.push_back(range_info); } else { - s_AddRanges(m_Index, feat_info, 0, + s_AddRanges(ids_map, + m_Index, feat_info, 0, m_ByProduct? feat_info.m_Feat.GetProduct(): feat_info.m_Feat.GetLocation()); @@ -1767,7 +1797,7 @@ public: if ( !index ) { index = new CFeatTreeParentTypeIndex(type, by_product); } - return index->GetIndex(feats); + return index->GetIndex(m_CanonicalIds, feats); } TRangeArray& GetIndex(const STypeLink& link, const TInfoArray& feats) { @@ -1775,7 +1805,10 @@ public: } private: + friend class CFeatTree; + TIndex m_Index; + TCanonicalIdsMap m_CanonicalIds; }; @@ -2085,7 +2118,8 @@ static void s_CollectBestOverlaps(CFeatTree::TFeatArray& features, TBestArray& bests, const STypeLink& link, TRangeArray& pp, - CFeatTree* tree) + CFeatTree* tree, + TCanonicalIdsMap& ids_map) { _ASSERT(!features.empty()); _ASSERT(!pp.empty()); @@ -2106,12 +2140,12 @@ static void s_CollectBestOverlaps(CFeatTree::TFeatArray& features, for ( size_t i = 0; i < cnt; ++i ) { CFeatTree::CFeatInfo& feat_info = *features[i]; SBestInfo* best = &bests[i]; - SFeatRangeInfo range_info(feat_info, best); + SFeatRangeInfo range_info(ids_map, feat_info, best); if ( range_info.m_Id ) { cc.push_back(range_info); } else { - s_AddRanges(cc, feat_info, best, feat_info.m_Feat.GetLocation()); + s_AddRanges(ids_map, cc, feat_info, best, feat_info.m_Feat.GetLocation()); } } sort(cc.begin(), cc.end(), PLessByStart()); @@ -2311,7 +2345,7 @@ void CFeatTree::x_AssignParentsByOverlap(TFeatArray& features, continue; } TBestArray bests1; - s_CollectBestOverlaps(features, bests1, link, parents, this); + s_CollectBestOverlaps(features, bests1, link, parents, this, m_Index->m_CanonicalIds); if ( bests.empty() ) { swap(bests, bests1); } @@ -2330,7 +2364,7 @@ void CFeatTree::x_AssignParentsByOverlap(TFeatArray& features, if ( parents.empty() ) { return; } - s_CollectBestOverlaps(features, bests, link, parents, this); + s_CollectBestOverlaps(features, bests, link, parents, this, m_Index->m_CanonicalIds); } size_t cnt = features.size(); _ASSERT(bests.size() == cnt); @@ -2369,7 +2403,7 @@ void CFeatTree::x_AssignGenesByOverlap(TFeatArray& features) return; } TBestArray bests; - s_CollectBestOverlaps(features, bests, STypeLink(), genes, this); + s_CollectBestOverlaps(features, bests, STypeLink(), genes, this, m_Index->m_CanonicalIds); size_t cnt = features.size(); _ASSERT(bests.size() == cnt); @@ -3552,14 +3586,16 @@ bool AdjustProteinMolInfoToMatchCDS(CMolInfo& molinfo, const CSeq_feat& cds) else if (partial3) { completeness = CMolInfo::eCompleteness_no_right; } + else { + completeness = CMolInfo::eCompleteness_complete; + } if (!molinfo.IsSetCompleteness() || molinfo.GetCompleteness() != completeness) { if (completeness == CMolInfo::eCompleteness_complete) - molinfo.SetDefaultCompleteness(); + molinfo.SetDefaultCompleteness(); else - molinfo.SetCompleteness(completeness); - + molinfo.SetCompleteness(completeness); rval = true; } return rval; @@ -3640,24 +3676,24 @@ bool RetranslateCDS(const CSeq_feat& cds, CScope& scope) CRef new_inst(new CSeq_inst()); new_inst->Assign(new_protein->GetInst()); peh.SetInst(*new_inst); - } - // If protein feature exists, update location - CFeat_CI f(prot_bsh, SAnnotSelector(CSeqFeatData::eSubtype_prot)); - if (f) { - // This is necessary, to make sure that we are in "editing mode" - const CSeq_annot_Handle& annot_handle = f->GetAnnot(); - CSeq_entry_EditHandle eh = annot_handle.GetParentEntry().GetEditHandle(); - CSeq_feat_EditHandle feh(*f); - CRef new_feat(new CSeq_feat()); - new_feat->Assign(*(f->GetSeq_feat())); - if (new_feat->CanGetLocation() && - new_feat->GetLocation().IsInt() && - new_feat->GetLocation().GetInt().CanGetTo()) - { - new_feat->SetLocation().SetInt().SetTo( - new_protein->GetLength() - 1); - feh.Replace(*new_feat); + // If protein feature exists, update location + CFeat_CI f(prot_bsh, SAnnotSelector(CSeqFeatData::eSubtype_prot)); + if (f) { + // This is necessary, to make sure that we are in "editing mode" + const CSeq_annot_Handle& annot_handle = f->GetAnnot(); + CSeq_entry_EditHandle eh = annot_handle.GetParentEntry().GetEditHandle(); + CSeq_feat_EditHandle feh(*f); + CRef new_feat(new CSeq_feat()); + new_feat->Assign(*(f->GetSeq_feat())); + if (new_feat->CanGetLocation() && + new_feat->GetLocation().IsInt() && + new_feat->GetLocation().GetInt().CanGetTo()) + { + new_feat->SetLocation().SetInt().SetTo( + new_protein->GetLength() - 1); + feh.Replace(*new_feat); + } } } @@ -3780,7 +3816,7 @@ bool sGetFeatureGeneBiotypeWrapper( //for debugging specific genes: // size_t start = mf.GetLocation().GetInt().GetStart(objects::eExtreme_Positional); - // if (XXXX == start) { + // if (start == 23365505-1) { // cerr << ""; // } @@ -3797,15 +3833,17 @@ bool sGetFeatureGeneBiotypeWrapper( // except-text="rearrangement required for product" qualifier then // gene_biotype qualifier is "protein_coding". // - for (MFSit it = vecCds.begin(); it != vecCds.end(); it++) { - if (it->IsSetPseudo() && it->GetPseudo()) { - continue; - } - if (it->IsSetExcept_text() && (it->GetExcept_text() == strRearrange)) { - continue; + if (!mf.IsSetPseudo() || !mf.GetPseudo()) { + for (MFSit it = vecCds.begin(); it != vecCds.end(); it++) { + if (it->IsSetPseudo() && it->GetPseudo()) { + continue; + } + if (it->IsSetExcept_text() && (it->GetExcept_text() == strRearrange)) { + continue; + } + biotype = "protein_coding"; + return true; } - biotype = "protein_coding"; - return true; } vector vecOthers; @@ -3840,9 +3878,10 @@ bool sGetFeatureGeneBiotypeWrapper( CSeqFeatData::ESubtype singleSubtype = SUBTYPE(bad); CMappedFeat nonPseudo; + bool geneIsPseudo = mf.IsSetPseudo() && mf.GetPseudo(); for (MFSit it = vecOthers.begin(); it != vecOthers.end(); it++) { CSeqFeatData::ESubtype currentSubtype = it->GetFeatSubtype(); - if (!it->IsSetPseudo() || !it->GetPseudo()) { + if (!geneIsPseudo && (!it->IsSetPseudo() || !it->GetPseudo())) { nonPseudo = *it; } if (singleSubtype == SUBTYPE(bad)) { diff --git a/c++/src/objmgr/util/feature_edit.cpp b/c++/src/objmgr/util/feature_edit.cpp new file mode 100644 index 00000000..96197165 --- /dev/null +++ b/c++/src/objmgr/util/feature_edit.cpp @@ -0,0 +1,400 @@ + +/* $Id: feature_edit.cpp 546431 2017-09-18 17:09:40Z ivanov $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Justin Foley, NCBI +* +* File Description: +* Feature trimming code +*/ +#include +#include +#include +#include + +#include +#include +#include +#include + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) +BEGIN_SCOPE(sequence) + + +struct SOutsideRange +{ + SOutsideRange(const CRange& range) : m_Range(range) {} + + bool operator()(const CRef& code_break) { + CRange cb_range = code_break->GetLoc().GetTotalRange(); + return cb_range.IntersectionWith(m_Range).Empty(); + } + CRange m_Range; +}; + + +CRef CFeatTrim::Apply(const CCode_break& code_break, + const CRange& range) +{ + CRef trimmed_cb; + + if (code_break.GetLoc().GetTotalRange().IntersectionWith(range).NotEmpty()) + { + trimmed_cb = Ref(new CCode_break()); + trimmed_cb->Assign(code_break); + const auto strand = code_break.GetLoc().GetStrand(); + // Trim the 3' end - RW-301 + if (strand != eNa_strand_minus) { + const TSeqPos to = range.GetTo(); + const TSeqPos cb_to = code_break.GetLoc().GetTotalRange().GetTo(); + if (cb_to > to) { + x_TrimCodeBreak(0, to, *trimmed_cb); + } + + } + else { // strand == eNa_strand_minus + const TSeqPos from = range.GetFrom(); + const TSeqPos cb_from = code_break.GetLoc().GetTotalRange().GetFrom(); + if (cb_from < from) { + x_TrimCodeBreak(from, kMax_UInt, *trimmed_cb); + } + } + } + return trimmed_cb; +} + + +CRef CFeatTrim::Apply(const CTrna_ext& trna_ext, + const CRange& range) +{ + CRef trimmed_ext; + if (trna_ext.GetAnticodon().GetTotalRange().IntersectionWith(range).NotEmpty()) + { + trimmed_ext->Assign(trna_ext); + x_TrimTrnaExt(range.GetFrom(), range.GetTo(), *trimmed_ext); + } + return trimmed_ext; +} + + +CRef CFeatTrim::Apply(const CSeq_loc& loc, + const CRange& range) +{ + const bool set_partial = true; + const TSeqPos from = range.GetFrom(); + const TSeqPos to = range.GetTo(); + + CRef trimmed_loc(new CSeq_loc()); + trimmed_loc->Assign(loc); + + x_TrimLocation(from, to, set_partial, trimmed_loc); + + return trimmed_loc; +} + + +CRef CFeatTrim::Apply(const CSeq_feat& feat, + const CRange& range) +{ + CRef loc = Ref(new CSeq_loc()); + loc->Assign(feat.GetLocation()); + + const TSeqPos from = range.GetFrom(); + const TSeqPos to = range.GetTo(); + + const bool set_partial = true; + + x_TrimLocation(from, to, set_partial, loc); + if (loc->IsNull()) { + return Ref(new CSeq_feat()); + } + + // Create a new seq-feat with the trimmed location + CRef new_sf(new CSeq_feat()); + new_sf->Assign(feat); + new_sf->SetLocation(*loc); + if (!loc->IsNull() && + (loc->IsPartialStart(eExtreme_Biological) || + loc->IsPartialStop(eExtreme_Biological))) { + new_sf->SetPartial(true); + } + + + // If Cdregion need to consider changes in frameshift + if (new_sf->GetData().IsCdregion()) { + const TSeqPos offset = x_GetStartOffset(feat, from, to); + x_UpdateFrame(offset, new_sf->SetData().SetCdregion()); + + if (new_sf->SetData().SetCdregion().IsSetCode_break()) { + // iterate over code breaks and remove if they fall outside the range + list>& code_breaks = new_sf->SetData().SetCdregion().SetCode_break(); + //code_breaks.remove_if(SOutsideRange(from,to)); + code_breaks.remove_if(SOutsideRange(range)); + if (code_breaks.empty()) { + new_sf->SetData().SetCdregion().ResetCode_break(); + } + else { + const auto strand = loc->GetStrand(); + // Trim the 3' end - RW-301 + if (strand != eNa_strand_minus) { + for (auto code_break : code_breaks) { + const TSeqPos cb_to = code_break->GetLoc().GetTotalRange().GetTo(); + if (cb_to > to) { + x_TrimCodeBreak(0, to, *code_break); + } + } + } + else { // strand == eNa_strand_minus + for (auto code_break : code_breaks) { + const TSeqPos cb_from = code_break->GetLoc().GetTotalRange().GetFrom(); + if (cb_from < from) { + x_TrimCodeBreak(from, kMax_UInt, *code_break); + } + } + } + } + } + } + else + if (new_sf->GetData().GetSubtype() == CSeqFeatData::eSubtype_tRNA) { + auto& rna = new_sf->SetData().SetRna(); + if (rna.IsSetExt() && rna.GetExt().IsTRNA()) { + x_TrimTrnaExt(from, to, rna.SetExt().SetTRNA()); + } + } + return new_sf; +} + + +void CFeatTrim::x_TrimCodeBreak(const TSeqPos from, const TSeqPos to, + CCode_break& code_break) +{ + const bool not_partial = false; + CRef cb_loc(new CSeq_loc()); + cb_loc->Assign(code_break.GetLoc()); + x_TrimLocation(from, to, not_partial, cb_loc); + code_break.ResetLoc(); + code_break.SetLoc(*cb_loc); +} + + +void CFeatTrim::x_TrimLocation(const TSeqPos from, const TSeqPos to, + const bool set_partial, + CRef& loc) +{ + if (loc.IsNull()) { + return; + } + + bool partial_start = false; + bool partial_stop = false; + const auto strand = loc->GetStrand(); + + + for(CSeq_loc_CI loc_it(*loc); loc_it; ++loc_it) { + + const auto& current_range = loc_it.GetRange(); + const auto current_from = current_range.GetFrom(); + const auto current_to = current_range.GetTo(); + + CRef current_seqid = Ref(new CSeq_id()); + current_seqid->Assign(loc_it.GetSeq_id()); + + // May be able to do this more succinctly and efficiently using CSeq_loc::Intersect + if ((current_to < from) || + (current_from > to)) { + CRef trim(new CSeq_loc(*current_seqid, + current_from, + current_to, + strand)); + + loc = loc->Subtract(*trim, 0, NULL, NULL); + if (current_to < from) { + partial_start = true; + } + if (current_from > to) { + partial_stop = true; + } + continue; + } + + if (current_from < from) { + CRef trim(new CSeq_loc(*current_seqid, + current_from, + from-1, + strand)); + + loc = loc->Subtract(*trim, 0, NULL, NULL); + partial_start = true; + } + + if (current_to > to) { + CRef trim(new CSeq_loc(*current_seqid, + to+1, + current_to, + strand)); + + loc = loc->Subtract(*trim, 0, NULL, NULL); + partial_stop = true; + } + } + + if (loc->IsNull() || !set_partial) { + return; + } + + + if (strand == eNa_strand_minus) { + swap(partial_start, partial_stop); + } + + + if (partial_start) { + loc->SetPartialStart(true, eExtreme_Biological); + } + + if (partial_stop) { + loc->SetPartialStop(true, eExtreme_Biological); + } +} + + +TSeqPos CFeatTrim::x_GetStartOffset(const CSeq_feat& feat, + TSeqPos from, TSeqPos to) +{ + TSeqPos offset = 0; + const auto strand = feat.GetLocation().GetStrand(); + CRange feat_range = feat.GetLocation().GetTotalRange(); + + if (strand != eNa_strand_minus) { + TSeqPos feat_from = feat_range.GetFrom(); + if (feat_from < from) { + offset = from - feat_from; + } + } + else { // eNa_strand_minus + TSeqPos feat_to = feat_range.GetTo(); + if (feat_to > to) { + offset = feat_to - to; + } + } + return offset; +} + + +TSeqPos CFeatTrim::x_GetFrame(const CCdregion& cds) +{ + switch(cds.GetFrame()) { + case CCdregion::eFrame_not_set: + case CCdregion::eFrame_one: + return 0; + case CCdregion::eFrame_two: + return 1; + case CCdregion::eFrame_three: + return 2; + default: + return 0; + + } + return 0; +} + + +CCdregion::EFrame CFeatTrim::GetCdsFrame(const CSeq_feat& cds_feature, const CRange& range) +{ + const TSeqPos offset = x_GetStartOffset(cds_feature, range.GetFrom(), range.GetTo()); + + return x_GetNewFrame(offset, cds_feature.GetData().GetCdregion()); +} + + +CCdregion::EFrame CFeatTrim::x_GetNewFrame(const TSeqPos offset, const CCdregion& cdregion) +{ + + const TSeqPos frame_change = offset%3; + if (!frame_change) { + return cdregion.GetFrame(); + } + + const TSeqPos old_frame = x_GetFrame(cdregion); + const TSeqPos new_frame = (old_frame + frame_change)%3; + if (new_frame == 1) { + return CCdregion::eFrame_two; + } + if (new_frame == 2) { + return CCdregion::eFrame_three; + } + return CCdregion::eFrame_one; +} + + +void CFeatTrim::x_UpdateFrame(const TSeqPos offset, CCdregion& cdregion) +{ + const TSeqPos frame_change = offset%3; + if (!frame_change) { + return; + } + + cdregion.ResetFrame(); + cdregion.SetFrame(x_GetNewFrame(offset, cdregion)); +} + + +void CFeatTrim::x_TrimTrnaExt(const TSeqPos from, const TSeqPos to, CTrna_ext& ext) +{ + if (!ext.IsSetAnticodon()) { + return; + } + + CRange ac_range = ext.GetAnticodon().GetTotalRange(); + + const TSeqPos ac_from = ac_range.GetFrom(); + const TSeqPos ac_to = ac_range.GetTo(); + + if (from <= ac_from && to >= ac_to) { + return; + } + + if (from > ac_to || to < ac_from) { + ext.ResetAnticodon(); + return; + } + + const bool set_partial=true; + // else there is some overlap + CRef loc(new CSeq_loc()); + loc->Assign(ext.GetAnticodon()); + x_TrimLocation(from, to, set_partial, loc); + ext.ResetAnticodon(); + ext.SetAnticodon(*loc); + + return; +} + + +END_SCOPE(sequence) +END_SCOPE(objects) +END_NCBI_SCOPE diff --git a/c++/src/objmgr/util/indexer.cpp b/c++/src/objmgr/util/indexer.cpp new file mode 100644 index 00000000..6bba43b3 --- /dev/null +++ b/c++/src/objmgr/util/indexer.cpp @@ -0,0 +1,1941 @@ +/* +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Jonathan Kans +* +*/ + +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) + + +// CSeqEntryIndex + +// Constructors take top-level sequence object, create a CRef, and call its initializer +CSeqEntryIndex::CSeqEntryIndex (CSeq_entry_Handle& topseh, EPolicy policy, TFlags flags, int depth) + +{ + m_Idx.Reset(new CSeqMasterIndex); + m_Idx->x_Initialize(topseh, policy, flags, depth); +} + +CSeqEntryIndex::CSeqEntryIndex (CSeq_entry& topsep, EPolicy policy, TFlags flags, int depth) + +{ + m_Idx.Reset(new CSeqMasterIndex); + m_Idx->x_Initialize(topsep, policy, flags, depth); +} + +CSeqEntryIndex::CSeqEntryIndex (CBioseq_set& seqset, EPolicy policy, TFlags flags, int depth) + +{ + m_Idx.Reset(new CSeqMasterIndex); + m_Idx->x_Initialize(seqset, policy, flags, depth); +} + +CSeqEntryIndex::CSeqEntryIndex (CBioseq& bioseq, EPolicy policy, TFlags flags, int depth) + +{ + m_Idx.Reset(new CSeqMasterIndex); + m_Idx->x_Initialize(bioseq, policy, flags, depth); +} + +CSeqEntryIndex::CSeqEntryIndex (CSeq_submit& submit, EPolicy policy, TFlags flags, int depth) + +{ + m_Idx.Reset(new CSeqMasterIndex); + m_Idx->x_Initialize(submit, policy, flags, depth); +} + +CSeqEntryIndex::CSeqEntryIndex (CSeq_entry& topsep, CSubmit_block &sblock, EPolicy policy, TFlags flags, int depth) + +{ + m_Idx.Reset(new CSeqMasterIndex); + m_Idx->x_Initialize(topsep, sblock, policy, flags, depth); +} + +CSeqEntryIndex::CSeqEntryIndex (CSeq_entry& topsep, CSeq_descr &descr, EPolicy policy, TFlags flags, int depth) + +{ + m_Idx.Reset(new CSeqMasterIndex); + m_Idx->x_Initialize(topsep, descr, policy, flags, depth); +} + +// Get first Bioseq index +CRef CSeqEntryIndex::GetBioseqIndex (void) + +{ + return m_Idx->GetBioseqIndex(); +} + +// Get Nth Bioseq index +CRef CSeqEntryIndex::GetBioseqIndex (int n) + +{ + return m_Idx->GetBioseqIndex(n); +} + +// Get Bioseq index by accession +CRef CSeqEntryIndex::GetBioseqIndex (const string& accn) + +{ + return m_Idx->GetBioseqIndex(accn); +} + +// Get Bioseq index by handle (via best Seq-id string) +CRef CSeqEntryIndex::GetBioseqIndex (CBioseq_Handle bsh) + +{ + return m_Idx->GetBioseqIndex(bsh); +} + +// // Get Bioseq index by feature +CRef CSeqEntryIndex::GetBioseqIndex (const CMappedFeat& mf) + +{ + return m_Idx->GetBioseqIndex(mf); +} + +// Get Bioseq index by sublocation +CRef CSeqEntryIndex::GetBioseqIndex (const CSeq_loc& loc) + +{ + return m_Idx->GetBioseqIndex(loc); +} + +// Get Bioseq index by subrange +CRef CSeqEntryIndex::GetBioseqIndex (const string& accn, int from, int to, bool rev_comp) + +{ + return m_Idx->GetBioseqIndex(accn, from, to, rev_comp); +} + +CRef CSeqEntryIndex::GetBioseqIndex (int from, int to, bool rev_comp) + +{ + return m_Idx->GetBioseqIndex("", from, to, rev_comp); +} + +const vector>& CSeqEntryIndex::GetBioseqIndices(void) + +{ + return m_Idx->GetBioseqIndices(); +} + +const vector>& CSeqEntryIndex::GetSeqsetIndices(void) + +{ + return m_Idx->GetSeqsetIndices(); +} + +bool CSeqEntryIndex::IsFetchFailure(void) + +{ + return m_Idx->IsFetchFailure(); +} + + +// CSeqMasterIndex + +// Initializers take top-level sequence object, create Seq-entry wrapper if necessary +void CSeqMasterIndex::x_Initialize (CSeq_entry_Handle& topseh, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth) +{ + m_Policy = policy; + m_Flags = flags; + m_Depth = depth; + + m_Tseh = topseh.GetTopLevelEntry(); + CConstRef tcsep = m_Tseh.GetCompleteSeq_entry(); + CSeq_entry& topsep = const_cast(*tcsep); + topsep.Parentize(); + m_Tsep.Reset(&topsep); + + try { + // Code copied from x_Init, then modified to reuse existing scope from CSeq_entry_Handle + m_Scope.Reset( &m_Tseh.GetScope() ); + if ( !m_Scope ) { + /* raise hell */; + } + + m_Counter.Set(0); + + // Populate vector of CBioseqIndex objects representing local Bioseqs in blob + CRef noparent; + x_InitSeqs( *m_Tsep, noparent ); + } + catch (CException& e) { + LOG_POST(Error << "Error in CSeqMasterIndex::x_Init: " << e.what()); + } +} + +void CSeqMasterIndex::x_Initialize (CSeq_entry& topsep, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth) +{ + m_Policy = policy; + m_Flags = flags; + m_Depth = depth; + + topsep.Parentize(); + m_Tsep.Reset(&topsep); + + x_Init(); +} + +void CSeqMasterIndex::x_Initialize (CBioseq_set& seqset, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth) +{ + m_Policy = policy; + m_Flags = flags; + m_Depth = depth; + + CSeq_entry* parent = seqset.GetParentEntry(); + if (parent) { + parent->Parentize(); + m_Tsep.Reset(parent); + } else { + CRef sep(new CSeq_entry); + sep->SetSet(seqset); + sep->Parentize(); + m_Tsep.Reset(sep); + } + + x_Init(); +} + +void CSeqMasterIndex::x_Initialize (CBioseq& bioseq, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth) +{ + m_Policy = policy; + m_Flags = flags; + m_Depth = depth; + + CSeq_entry* parent = bioseq.GetParentEntry(); + if (parent) { + parent->Parentize(); + m_Tsep.Reset(parent); + } else { + CRef sep(new CSeq_entry); + sep->SetSeq(bioseq); + sep->Parentize(); + m_Tsep.Reset(sep); + } + + x_Init(); +} + +void CSeqMasterIndex::x_Initialize (CSeq_submit& submit, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth) +{ + m_Policy = policy; + m_Flags = flags; + m_Depth = depth; + + _ASSERT(submit.CanGetData()); + _ASSERT(submit.CanGetSub()); + _ASSERT(submit.GetData().IsEntrys()); + _ASSERT(!submit.GetData().GetEntrys().empty()); + + CRef sep = submit.GetData().GetEntrys().front(); + sep->Parentize(); + m_Tsep.Reset(sep); + m_SbtBlk.Reset(&submit.GetSub()); + + x_Init(); +} + +void CSeqMasterIndex::x_Initialize (CSeq_entry& topsep, CSubmit_block &sblock, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth) +{ + m_Policy = policy; + m_Flags = flags; + m_Depth = depth; + + topsep.Parentize(); + m_Tsep.Reset(&topsep); + m_SbtBlk.Reset(&sblock); + + x_Init(); +} + +void CSeqMasterIndex::x_Initialize (CSeq_entry& topsep, CSeq_descr &descr, CSeqEntryIndex::EPolicy policy, CSeqEntryIndex::TFlags flags, int depth) +{ + m_Policy = policy; + m_Flags = flags; + m_Depth = depth; + + topsep.Parentize(); + m_Tsep.Reset(&topsep); + m_TopDescr.Reset(&descr); + + x_Init(); +} + +// At end of program, poll all Bioseqs to check for far fetch failure flag +bool CSeqMasterIndex::IsFetchFailure (void) + +{ + for (auto& bsx : m_BsxList) { + if (bsx->IsFetchFailure()) { + return true; + } + } + return false; +} + +// FindBestIdChoice modified from feature_item.cpp +static int s_IdxSeqIdHandle(const CSeq_id_Handle& idh) +{ + CConstRef id = idh.GetSeqId(); + CRef id_non_const + (const_cast(id.GetPointer())); + return CSeq_id::Score(id_non_const); +} + +static CSeq_id_Handle s_IdxFindBestIdChoice(const CBioseq_Handle::TId& ids) +{ + CBestChoiceTracker< CSeq_id_Handle, int (*)(const CSeq_id_Handle&) > + tracker(s_IdxSeqIdHandle); + + ITERATE( CBioseq_Handle::TId, it, ids ) { + switch( (*it).Which() ) { + case CSeq_id::e_Genbank: + case CSeq_id::e_Embl: + case CSeq_id::e_Ddbj: + case CSeq_id::e_Gi: + case CSeq_id::e_Other: + case CSeq_id::e_General: + case CSeq_id::e_Tpg: + case CSeq_id::e_Tpe: + case CSeq_id::e_Tpd: + case CSeq_id::e_Gpipe: + tracker(*it); + break; + default: + break; + } + } + return tracker.GetBestChoice(); +} + +static string s_IdxGetBestIdString(CBioseq_Handle bsh) + +{ + if (bsh) { + const CBioseq_Handle::TId& ids = bsh.GetId(); + if (! ids.empty()) { + CSeq_id_Handle best = s_IdxFindBestIdChoice(ids); + if (best) { + return best.AsString(); + } + } + } + + return ""; +} + +// Recursively explores from top-level Seq-entry to make flattened vector of CBioseqIndex objects +void CSeqMasterIndex::x_InitSeqs (const CSeq_entry& sep, CRef prnt) + +{ + if (sep.IsSeq()) { + // Is Bioseq + const CBioseq& bsp = sep.GetSeq(); + CBioseq_Handle bsh = m_Scope->GetBioseqHandle(bsp); + if (bsh) { + // create CBioseqIndex object for current Bioseq + CRef bsx(new CBioseqIndex(bsh, bsp, bsh, prnt, m_Tseh, m_Scope, *this, m_Policy, m_Flags, m_Depth, false)); + + // record CBioseqIndex in vector for IterateBioseqs or GetBioseqIndex + m_BsxList.push_back(bsx); + + // map from accession string to CBioseqIndex object + const string& accn = bsx->GetAccession(); + m_AccnIndexMap[accn] = bsx; + + // map from handle to best Seq-id string to CBioseqIndex object + string bestid = s_IdxGetBestIdString(bsh); + m_BestIdIndexMap[bestid] = bsx; + } + } else if (sep.IsSet()) { + // Is Bioseq-set + const CBioseq_set& bssp = sep.GetSet(); + CBioseq_set_Handle ssh = m_Scope->GetBioseq_setHandle(bssp); + if (ssh) { + // create CSeqsetIndex object for current Bioseq-set + CRef ssx(new CSeqsetIndex(ssh, bssp, prnt)); + + // record CSeqsetIndex in vector + m_SsxList.push_back(ssx); + + if (bssp.CanGetSeq_set()) { + // recursively explore current Bioseq-set + for (const CRef& tmp : bssp.GetSeq_set()) { + x_InitSeqs(*tmp, ssx); + } + } + } + } +} + +// Common initialization function creates local default CScope +void CSeqMasterIndex::x_Init (void) + +{ + try { + m_Objmgr = CObjectManager::GetInstance(); + if ( !m_Objmgr ) { + /* raise hell */; + } + + m_Scope.Reset( new CScope( *m_Objmgr ) ); + if ( !m_Scope ) { + /* raise hell */; + } + + m_Counter.Set(0); + + m_Scope->AddDefaults(); + + m_Tseh = m_Scope->AddTopLevelSeqEntry( *m_Tsep ); + + // Populate vector of CBioseqIndex objects representing local Bioseqs in blob + CRef noparent; + x_InitSeqs( *m_Tsep, noparent ); + } + catch (CException& e) { + LOG_POST(Error << "Error in CSeqMasterIndex::x_Init: " << e.what()); + } +} + +// Support for temporary delta sequence referring to subrange of original sequence +CRef CSeqMasterIndex::x_MakeUniqueId(void) +{ + CRef id(new CSeq_id()); + bool good = false; + while (!good) { + id->SetLocal().SetStr("tmp_delta_subset_" + NStr::NumericToString(m_Counter.Add(1))); + CBioseq_Handle bsh = m_Scope->GetBioseqHandle(*id); + if (! bsh) { + good = true; + } + } + return id; +} + +CRef CSeqMasterIndex::x_DeltaIndex(const CSeq_loc& loc) + +{ + try { + // create delta sequence referring to location or range, using temporary local Seq-id + CBioseq_Handle bsh = m_Scope->GetBioseqHandle(loc); + CRef delta(new CBioseq()); + delta->SetId().push_back(x_MakeUniqueId()); + delta->SetInst().Assign(bsh.GetInst()); + delta->SetInst().ResetSeq_data(); + delta->SetInst().ResetExt(); + delta->SetInst().SetRepr(CSeq_inst::eRepr_delta); + CRef element(new CDelta_seq()); + element->SetLoc().Assign(loc); + delta->SetInst().SetExt().SetDelta().Set().push_back(element); + delta->SetInst().SetLength(sequence::GetLength(loc, m_Scope)); + + // add to scope + CBioseq_Handle deltaBsh = m_Scope->AddBioseq(*delta); + + if (deltaBsh) { + // create CBioseqIndex object for delta Bioseq + CRef noparent; + + CRef bsx(new CBioseqIndex(deltaBsh, *delta, bsh, noparent, m_Tseh, m_Scope, *this, m_Policy, m_Flags, m_Depth, true)); + + return bsx; + } + } + catch (CException& e) { + LOG_POST(Error << "Error in CSeqMasterIndex::x_DeltaIndex: " << e.what()); + } + return CRef (); +} + +CConstRef CSeqMasterIndex::x_SubRangeLoc(const string& accn, int from, int to, bool rev_comp) + +{ + TAccnIndexMap::iterator it = m_AccnIndexMap.find(accn); + if (it != m_AccnIndexMap.end()) { + CRef bsx = it->second; + for (const CRef& id : bsx->GetBioseq().GetId()) { + switch (id->Which()) { + case CSeq_id::e_Other: + case CSeq_id::e_Genbank: + case CSeq_id::e_Embl: + case CSeq_id::e_Ddbj: + case CSeq_id::e_Tpg: + case CSeq_id::e_Tpe: + case CSeq_id::e_Tpd: + { + CSeq_loc::TStrand strand = eNa_strand_unknown; + if (rev_comp) { + strand = eNa_strand_minus; + } + CSeq_id& nc_id = const_cast(*id); + // create location from range + CConstRef loc(new CSeq_loc(nc_id, from, to, strand)); + if (loc) { + return loc; + } + } + break; + default: + break; + } + } + } + return CConstRef (); +} + +// Get first Bioseq index +CRef CSeqMasterIndex::GetBioseqIndex (void) + +{ + for (auto& bsx : m_BsxList) { + return bsx; + } + return CRef (); +} + +// Get Nth Bioseq index +CRef CSeqMasterIndex::GetBioseqIndex (int n) + +{ + for (auto& bsx : m_BsxList) { + n--; + if (n > 0) continue; + return bsx; + } + return CRef (); +} + +// Get Bioseq index by accession +CRef CSeqMasterIndex::GetBioseqIndex (const string& accn) + +{ + TAccnIndexMap::iterator it = m_AccnIndexMap.find(accn); + if (it != m_AccnIndexMap.end()) { + CRef bsx = it->second; + return bsx; + } + return CRef (); +} + +// Get Bioseq index by handle (via best Seq-id string) +CRef CSeqMasterIndex::GetBioseqIndex (CBioseq_Handle bsh) + +{ + string bestid = s_IdxGetBestIdString(bsh); + TBestIdIndexMap::iterator it = m_BestIdIndexMap.find(bestid); + if (it != m_BestIdIndexMap.end()) { + CRef bsx = it->second; + return bsx; + } + return CRef (); +} + +// // Get Bioseq index by feature +CRef CSeqMasterIndex::GetBioseqIndex (const CMappedFeat& mf) + +{ + CSeq_id_Handle idh = mf.GetLocationId(); + CBioseq_Handle bsh = m_Scope->GetBioseqHandle(idh); + return GetBioseqIndex(bsh); +} + +// Get Bioseq index by sublocation +CRef CSeqMasterIndex::GetBioseqIndex (const CSeq_loc& loc) + +{ + CRef bsx = x_DeltaIndex(loc); + + if (bsx) { + return bsx; + } + return CRef (); +} + +// Get Bioseq index by subrange +CRef CSeqMasterIndex::GetBioseqIndex (const string& accn, int from, int to, bool rev_comp) + +{ + string accession = accn; + if (accession.empty()) { + CRef bsx = GetBioseqIndex(); + if (bsx) { + accession = bsx->GetAccession(); + } + } + + if (! accession.empty()) { + CConstRef loc = x_SubRangeLoc(accession, from, to, rev_comp); + + if (loc) { + return GetBioseqIndex(*loc); + } + } + return CRef (); +} + +CRef CSeqMasterIndex::GetBioseqIndex (int from, int to, bool rev_comp) + +{ + return GetBioseqIndex("", from, to, rev_comp); +} + +// Allow access to internal vectors for application to use in iterators +const vector>& CSeqMasterIndex::GetBioseqIndices(void) + +{ + return m_BsxList; +} + +const vector>& CSeqMasterIndex::GetSeqsetIndices(void) + +{ + return m_SsxList; +} + + +// CSeqsetIndex + +// Constructor +CSeqsetIndex::CSeqsetIndex (CBioseq_set_Handle ssh, + const CBioseq_set& bssp, + CRef prnt) + : m_Ssh(ssh), + m_Bssp(bssp), + m_Prnt(prnt) +{ + m_Class = CBioseq_set::eClass_not_set; + + if (ssh.IsSetClass()) { + m_Class = ssh.GetClass(); + } +} + + +// CBioseqIndex + +// Constructor +CBioseqIndex::CBioseqIndex (CBioseq_Handle bsh, + const CBioseq& bsp, + CBioseq_Handle obsh, + CRef prnt, + CSeq_entry_Handle tseh, + CRef scope, + CSeqMasterIndex& idx, + CSeqEntryIndex::EPolicy policy, + CSeqEntryIndex::TFlags flags, + int depth, + bool surrogate) + : m_Bsh(bsh), + m_Bsp(bsp), + m_OrigBsh(obsh), + m_Prnt(prnt), + m_Tseh(tseh), + m_Scope(scope), + m_Idx(&idx), + m_Policy(policy), + m_Flags(flags), + m_Depth(depth), + m_Surrogate(surrogate) +{ + m_FetchFailure = false; + + m_GapsInitialized = false; + m_DescsInitialized = false; + m_FeatsInitialized = false; + + m_HasSourceFeats = false; + + m_Accession.clear(); + + for (CSeq_id_Handle sid : obsh.GetId()) { + switch (sid.Which()) { + case CSeq_id::e_Other: + case CSeq_id::e_Genbank: + case CSeq_id::e_Embl: + case CSeq_id::e_Ddbj: + case CSeq_id::e_Tpg: + case CSeq_id::e_Tpe: + case CSeq_id::e_Tpd: + { + CConstRef id = sid.GetSeqId(); + const CTextseq_id& tsid = *id->GetTextseq_Id (); + if (tsid.IsSetAccession()) { + m_Accession = tsid.GetAccession (); + } + } + break; + default: + break; + } + } + + m_IsNA = m_Bsh.IsNa(); + m_IsAA = m_Bsh.IsAa(); + m_Topology = CSeq_inst::eTopology_not_set; + m_Length = 0; + + m_IsDelta = false; + m_IsVirtual = false; + m_IsMap = false; + + if (m_Bsh.IsSetInst()) { + if (m_Bsh.IsSetInst_Topology()) { + m_Topology = m_Bsh.GetInst_Topology(); + } + + if (m_Bsh.IsSetInst_Length()) { + m_Length = m_Bsh.GetInst_Length(); + } else { + m_Length = m_Bsh.GetBioseqLength(); + } + + if (m_Bsh.IsSetInst_Repr()) { + CBioseq_Handle::TInst_Repr repr = m_Bsh.GetInst_Repr(); + m_IsDelta = (repr == CSeq_inst::eRepr_delta); + m_IsVirtual = (repr == CSeq_inst::eRepr_virtual); + m_IsMap = (repr == CSeq_inst::eRepr_map); + } + } + + m_Title.clear(); + m_MolInfo.Reset(); + m_BioSource.Reset(); + m_Taxname.clear(); + + m_Biomol = CMolInfo::eBiomol_unknown; + m_Tech = CMolInfo::eTech_unknown; + m_Completeness = CMolInfo::eCompleteness_unknown; + + m_ForceOnlyNearFeats = false; +} + +// Destructor +CBioseqIndex::~CBioseqIndex (void) + +{ + if (m_Surrogate) { + try { + m_Scope->RemoveBioseq(m_Bsh); + } catch (CException&) { + // presumably still in use; let it be + } + } +} + +// Gap collection (delayed until needed) +void CBioseqIndex::x_InitGaps (void) + +{ + try { + if (m_GapsInitialized) { + return; + } + + m_GapsInitialized = true; + + if (! m_IsDelta) { + return; + } + + SSeqMapSelector sel; + + sel.SetFlags(CSeqMap::fFindGap) + .SetResolveCount(1); + + // explore gaps, pass original target BioseqHandle if using Bioseq sublocation + for (CSeqMap_CI gap_it(m_OrigBsh, sel); gap_it; ++gap_it) { + + TSeqPos start = gap_it.GetPosition(); + TSeqPos end = gap_it.GetEndPosition() - 1; + TSeqPos length = gap_it.GetLength(); + + // attempt to find CSeq_gap info + const CSeq_gap * pGap = NULL; + if( gap_it.IsSetData() && gap_it.GetData().IsGap() ) { + pGap = &gap_it.GetData().GetGap(); + } else { + CConstRef pSeqLiteral = gap_it.GetRefGapLiteral(); + if( pSeqLiteral && pSeqLiteral->IsSetSeq_data() ) { + const CSeq_data & seq_data = pSeqLiteral->GetSeq_data(); + if( seq_data.IsGap() ) { + pGap = &seq_data.GetGap(); + } + } + } + + CFastaOstream::SGapModText gap_mod_text; + if( pGap ) { + CFastaOstream::GetGapModText(*pGap, gap_mod_text); + } + string type = gap_mod_text.gap_type; + vector& evidence = gap_mod_text.gap_linkage_evidences; + + bool isUnknownLength = gap_it.IsUnknownLength(); + + // feature name depends on what quals we use + bool isAssemblyGap = ( ! type.empty() || ! evidence.empty() ); + + CRef sgx(new CGapIndex(start, end, length, type, evidence, isUnknownLength, isAssemblyGap, *this)); + m_GapList.push_back(sgx); + } + } + catch (CException& e) { + LOG_POST(Error << "Error in CBioseqIndex::x_InitGaps: " << e.what()); + } +} + +// Descriptor collection (delayed until needed) +void CBioseqIndex::x_InitDescs (void) + +{ + try { + if (m_DescsInitialized) { + return; + } + + m_DescsInitialized = true; + + // explore descriptors, pass original target BioseqHandle if using Bioseq sublocation + for (CSeqdesc_CI desc_it(m_OrigBsh); desc_it; ++desc_it) { + const CSeqdesc& sd = *desc_it; + CRef sdx(new CDescriptorIndex(sd, *this)); + m_SdxList.push_back(sdx); + + switch (sd.Which()) { + case CSeqdesc::e_Source: + { + if (! m_BioSource) { + const CBioSource& biosrc = sd.GetSource(); + m_BioSource.Reset (&biosrc); + if (biosrc.IsSetOrgname()) { + const COrg_ref& org = biosrc.GetOrg(); + if (org.CanGetTaxname()) { + m_Taxname = org.GetTaxname(); + } + } + } + break; + } + case CSeqdesc::e_Molinfo: + { + if (! m_MolInfo) { + const CMolInfo& molinf = sd.GetMolinfo(); + m_MolInfo.Reset (&molinf); + m_Biomol = molinf.GetBiomol(); + m_Tech = molinf.GetTech(); + m_Completeness = molinf.GetCompleteness(); + } + break; + } + case CSeqdesc::e_Title: + { + if (m_Title.empty()) { + m_Title = sd.GetTitle(); + } + break; + } + case CSeqdesc::e_User: + { + const CUser_object& usr = sd.GetUser(); + if (usr.IsSetType()) { + const CObject_id& oi = usr.GetType(); + if (oi.IsStr()) { + const string& type = oi.GetStr(); + if (NStr::EqualNocase(type, "FeatureFetchPolicy")) { + FOR_EACH_USERFIELD_ON_USEROBJECT (uitr, usr) { + const CUser_field& fld = **uitr; + if (fld.IsSetLabel() && fld.GetLabel().IsStr()) { + const string &label_str = GET_FIELD(fld.GetLabel(), Str); + if (! NStr::EqualNocase(label_str, "Policy")) continue; + if (fld.IsSetData() && fld.GetData().IsStr()) { + const string& str = fld.GetData().GetStr(); + if (NStr::EqualNocase(str, "OnlyNearFeatures")) { + m_ForceOnlyNearFeats = true; + } + } + } + } + } + } + } + break; + } + default: + break; + } + } + } + catch (CException& e) { + LOG_POST(Error << "Error in CBioseqIndex::x_InitDescs: " << e.what()); + } +} + +// Feature collection (delayed until needed) +void CBioseqIndex::x_InitFeats (void) + +{ + try { + if (m_FeatsInitialized) { + return; + } + + if (! m_DescsInitialized) { + // initialize descriptors first to get m_ForceOnlyNearFeats flag + x_InitDescs(); + } + + m_FeatsInitialized = true; + + SAnnotSelector sel; + + if (m_Policy != CSeqEntryIndex::fExternal) { + // unless explicitly desired, exclude external annots + sel.ExcludeNamedAnnots("CDD") + .ExcludeNamedAnnots("SNP") + .ExcludeNamedAnnots("STS"); + } + + if (m_Policy == CSeqEntryIndex::fExhaustive) { + + sel.SetResolveAll(); + // experimental flag forces collection of features from all levels + sel.SetResolveDepth(kMax_Int); + // also ignores RefSeq/INSD barrier, far fetch policy user object + + } else if (m_Policy == CSeqEntryIndex::fExternal) { + + // same as fAdaptive, except also allows external annots + sel.SetResolveAll(); + sel.SetAdaptiveDepth(true); + + } else if (m_Policy == CSeqEntryIndex::fInternal || m_ForceOnlyNearFeats) { + + // do not fetch features from underlying sequence component records + if (m_Surrogate) { + // delta with sublocation needs to map features from original Bioseq + sel.SetResolveAll(); + sel.SetResolveDepth(1); + sel.SetExcludeExternal(); + } else { + // otherwise limit collection to local records in top-level Seq-entry + sel.SetResolveDepth(0); + sel.SetExcludeExternal(); + } + + } else if (m_Depth > -1) { + + sel.SetResolveAll(); + // explicit depth setting overrides adaptive depth (probably only needed for debugging) + sel.SetResolveDepth(m_Depth); + + } else if (m_Policy == CSeqEntryIndex::fAdaptive) { + + sel.SetResolveAll(); + // normal situation uses adaptive depth for feature collection, + // includes barrier between RefSeq and INSD accession types + sel.SetAdaptiveDepth(true); + } + + // bit flags exclude specific features + if ((m_Flags & CSeqEntryIndex::fHideImpFeats) != 0) { + sel.ExcludeFeatType(CSeqFeatData::e_Imp); + } + if ((m_Flags & CSeqEntryIndex::fHideSNPFeats) != 0) { + sel.ExcludeFeatType(CSeqFeatData::e_Variation); + sel.ExcludeFeatSubtype(CSeqFeatData::eSubtype_variation); + } + if ((m_Flags & CSeqEntryIndex::fHideSTSFeats) != 0) { + sel.ExcludeFeatSubtype(CSeqFeatData::eSubtype_STS); + } + if ((m_Flags & CSeqEntryIndex::fHideExonFeats) != 0) { + sel.ExcludeFeatSubtype(CSeqFeatData::eSubtype_exon); + } + if ((m_Flags & CSeqEntryIndex::fHideIntronFeats) != 0) { + sel.ExcludeFeatSubtype(CSeqFeatData::eSubtype_intron); + } + if ((m_Flags & CSeqEntryIndex::fHideMiscFeats) != 0) { + sel.ExcludeFeatSubtype(CSeqFeatData::eSubtype_misc_feature); + } + + // additional common settings + sel.ExcludeFeatSubtype(CSeqFeatData::eSubtype_non_std_residue) + .ExcludeFeatSubtype(CSeqFeatData::eSubtype_rsite) + .ExcludeFeatSubtype(CSeqFeatData::eSubtype_seq); + + sel.SetFeatComparator(new feature::CFeatComparatorByLabel); + + // request exception to capture fetch failure + sel.SetFailUnresolved(); + + // limit feature collection to immediate Bioseq-set parent + CRef prnt = GetParent(); + if (prnt) { + CBioseq_set_Handle bssh = prnt->GetSeqsetHandle(); + if (bssh) { + CSeq_entry_Handle pseh = bssh.GetParentEntry(); + if (pseh) { + sel.SetLimitSeqEntry(pseh); + } + } + } + + // variables for setting m_BestProteinFeature + TSeqPos longest = 0; + CProt_ref::EProcessed bestprocessed = CProt_ref::eProcessed_not_set; + CProt_ref::EProcessed processed; + + // next gap + CGapIndex* sgx = NULL; + if (m_GapList.size() > 0) { + sgx = m_GapList[0]; + } + + // iterate features on Bioseq + for (CFeat_CI feat_it(m_Bsh, sel); feat_it; ++feat_it) { + const CMappedFeat mf = *feat_it; + CSeq_feat_Handle hdl = mf.GetSeq_feat_Handle(); + + CRef sfx(new CFeatureIndex(hdl, mf, *this)); + m_SfxList.push_back(sfx); + + m_FeatTree.AddFeature(mf); + + // CFeatureIndex from CMappedFeat for use with GetBestGene + m_FeatIndexMap[mf] = sfx; + + // set specific flags for various feature types + CSeqFeatData::E_Choice type = sfx->GetType(); + + if (type == CSeqFeatData::e_Biosrc) { + m_HasSourceFeats = true; + continue; + } + + if (type == CSeqFeatData::e_Prot && IsAA()) { + if (! mf.IsSetData ()) continue; + const CSeqFeatData& sfdata = mf.GetData(); + const CProt_ref& prp = sfdata.GetProt(); + processed = CProt_ref::eProcessed_not_set; + if (prp.IsSetProcessed()) { + processed = prp.GetProcessed(); + } + const CSeq_loc& loc = mf.GetLocation (); + TSeqPos prot_length = sequence::GetLength(loc, m_Scope); + if (prot_length > longest) { + m_BestProteinFeature = sfx; + longest = prot_length; + bestprocessed = processed; + } else if (prot_length == longest) { + // unprocessed 0 > preprotein 1 > mat peptide 2 + if (processed < bestprocessed) { + m_BestProteinFeature = sfx; + longest = prot_length; + bestprocessed = processed; + } + } + continue; + } + + if (type == CSeqFeatData::e_Cdregion && IsNA()) { + } else if (type == CSeqFeatData::e_Rna && IsAA()) { + } else if (type == CSeqFeatData::e_Prot && IsNA()) { + } else { + continue; + } + + // index feature for product (CDS -> protein, mRNA -> cDNA, or Prot -> peptide) + CSeq_id_Handle idh = mf.GetProductId(); + if (idh) { + CBioseq_Handle pbsh = m_Scope->GetBioseqHandle(idh); + if (pbsh) { + CWeakRef idx = GetSeqMasterIndex(); + auto idxl = idx.Lock(); + if (idxl) { + CRef bsxp = idxl->GetBioseqIndex(pbsh); + if (bsxp) { + bsxp->m_FeatureForProduct = sfx; + } + } + } + } + } + } + catch (CException& e) { + m_FetchFailure = true; + LOG_POST(Error << "Error in CBioseqIndex::x_InitFeats: " << e.what()); + } +} + +// GetFeatureForProduct allows hypothetical protein defline generator to obtain gene locus tag +CRef CBioseqIndex::GetFeatureForProduct (void) + +{ + if (! m_FeatureForProduct) { + if (m_Bsh) { + CFeat_CI fi(m_Bsh, + SAnnotSelector(CSeqFeatData::e_Cdregion) + .SetByProduct().SetLimitTSE(m_Bsh.GetTSE_Handle())); + if (! fi) { + fi = CFeat_CI(m_Bsh, + SAnnotSelector(CSeqFeatData::e_Rna) + .SetByProduct().SetLimitTSE(m_Bsh.GetTSE_Handle())); + } + if (! fi) { + fi = CFeat_CI(m_Bsh, + SAnnotSelector(CSeqFeatData::e_Prot) + .SetByProduct().SetLimitTSE(m_Bsh.GetTSE_Handle())); + } + if (fi) { + CMappedFeat mf = *fi; + CSeq_id_Handle idh = mf.GetLocationId(); + CBioseq_Handle nbsh = m_Scope->GetBioseqHandle(idh); + if (nbsh) { + CWeakRef idx = GetSeqMasterIndex(); + auto idxl = idx.Lock(); + if (idxl) { + CRef bsxn = idxl->GetBioseqIndex(nbsh); + if (bsxn) { + if (! bsxn->m_FeatsInitialized) { + bsxn->x_InitFeats(); + } + } + } + } + } + } + } + + return m_FeatureForProduct; +} + +// Get Bioseq index containing feature with product pointing to this Bioseq +CWeakRef CBioseqIndex::GetBioseqForProduct (void) + +{ + CRef sfxp = GetFeatureForProduct(); + if (sfxp) { + return sfxp->GetBioseqIndex(); + } + + return CWeakRef (); +} + +// GetBestProteinFeature indexes longest protein feature on protein Bioseq +CRef CBioseqIndex::GetBestProteinFeature (void) + +{ + if (! m_FeatsInitialized) { + x_InitFeats(); + } + + return m_BestProteinFeature; +} + +// HasSourceFeats reports whether Bioseq has BioSource features +bool CBioseqIndex::HasSourceFeats (void) + +{ + if (! m_FeatsInitialized) { + x_InitFeats(); + } + + return m_HasSourceFeats; +} + +// Common descriptor field getters +const string& CBioseqIndex::GetTitle (void) + +{ + if (! m_DescsInitialized) { + x_InitDescs(); + } + + return m_Title; +} + +CConstRef CBioseqIndex::GetMolInfo (void) + +{ + if (! m_DescsInitialized) { + x_InitDescs(); + } + + return m_MolInfo; +} + +CMolInfo::TBiomol CBioseqIndex::GetBiomol (void) + +{ + if (! m_DescsInitialized) { + x_InitDescs(); + } + + return m_Biomol; +} + +CMolInfo::TTech CBioseqIndex::GetTech (void) + +{ + if (! m_DescsInitialized) { + x_InitDescs(); + } + + return m_Tech; +} + +CMolInfo::TCompleteness CBioseqIndex::GetCompleteness (void) + +{ + if (! m_DescsInitialized) { + x_InitDescs(); + } + + return m_Completeness; +} + +CConstRef CBioseqIndex::GetBioSource (void) + +{ + if (! m_DescsInitialized) { + x_InitDescs(); + } + + return m_BioSource; +} + +const string& CBioseqIndex::GetTaxname (void) + +{ + if (! m_DescsInitialized) { + x_InitDescs(); + } + + return m_Taxname; +} + +CRef CBioseqIndex::GetFeatIndex (const CMappedFeat& mf) + +{ + CRef sfx; + + TFeatIndexMap::iterator it = m_FeatIndexMap.find(mf); + if (it != m_FeatIndexMap.end()) { + sfx = it->second; + } + + return sfx; +} + +void CBioseqIndex::GetSequence (int from, int to, string& buffer) + +{ + try { + if (! m_SeqVec) { + m_SeqVec = new CSeqVector(m_Bsh); + if (m_SeqVec) { + m_SeqVec->SetCoding(CBioseq_Handle::eCoding_Iupac); + } + } + + if (m_SeqVec) { + CSeqVector& vec = *m_SeqVec; + if (from < 0) { + from = 0; + } + if (to < 0 || to >= (int) vec.size()) { + to = vec.size(); + } + if (vec.CanGetRange(from, to)) { + vec.GetSeqData(from, to, buffer); + } else { + m_FetchFailure = true; + } + } + } + catch (CException& e) { + LOG_POST(Error << "Error in CBioseqIndex::GetSequence: " << e.what()); + } +} + +string CBioseqIndex::GetSequence (int from, int to) + +{ + string buffer; + + GetSequence(from, to, buffer); + + return buffer; +} + +void CBioseqIndex::GetSequence (string& buffer) + +{ + GetSequence(0, -1, buffer); +} + +string CBioseqIndex::GetSequence (void) + +{ + string buffer; + + GetSequence(0, -1, buffer); + + return buffer; +} + +const vector>& CBioseqIndex::GetGapIndices(void) + +{ + if (! m_GapsInitialized) { + x_InitGaps(); + } + + return m_GapList; +} + +const vector>& CBioseqIndex::GetDescriptorIndices(void) + +{ + if (! m_DescsInitialized) { + x_InitDescs(); + } + + return m_SdxList; +} + +const vector>& CBioseqIndex::GetFeatureIndices(void) + +{ + if (! m_FeatsInitialized) { + x_InitFeats(); + } + + return m_SfxList; +} + + +// CGapIndex + +// Constructor +CGapIndex::CGapIndex (TSeqPos start, + TSeqPos end, + TSeqPos length, + const string& type, + const vector& evidence, + bool isUnknownLength, + bool isAssemblyGap, + CBioseqIndex& bsx) + : m_Start(start), + m_End(end), + m_Length(length), + m_GapType(type), + m_GapEvidence(evidence), + m_IsUnknownLength(isUnknownLength), + m_IsAssemblyGap(isAssemblyGap), + m_Bsx(&bsx) +{ +} + + +// CDescriptorIndex + +// Constructor +CDescriptorIndex::CDescriptorIndex (const CSeqdesc& sd, + CBioseqIndex& bsx) + : m_Sd(sd), + m_Bsx(&bsx) +{ + m_Type = m_Sd.Which(); +} + + +// CFeatureIndex + +// Constructor +CFeatureIndex::CFeatureIndex (CSeq_feat_Handle sfh, + const CMappedFeat mf, + CBioseqIndex& bsx) + : m_Sfh(sfh), + m_Mf(mf), + m_Bsx(&bsx) +{ + const CSeqFeatData& data = m_Mf.GetData(); + m_Type = data.Which(); + m_Subtype = data.GetSubtype(); + const CSeq_feat& mpd = m_Mf.GetMappedFeature(); + CConstRef fl(&mpd.GetLocation()); + m_Fl = fl; + m_Start = fl->GetStart(eExtreme_Positional); + m_End = fl->GetStop(eExtreme_Positional); +} + +// Find CFeatureIndex object for best gene using internal CFeatTree +CRef CFeatureIndex::GetBestGene (void) + +{ + try { + CMappedFeat best; + CWeakRef bsx = GetBioseqIndex(); + auto bsxl = bsx.Lock(); + if (bsxl) { + best = feature::GetBestGeneForFeat(m_Mf, &bsxl->GetFeatTree(), 0, + feature::CFeatTree::eBestGene_AllowOverlapped); + if (best) { + return bsxl->GetFeatIndex(best); + } + } + } catch (CException& e) { + LOG_POST(Error << "Error in CFeatureIndex::GetBestGene: " << e.what()); + } + return CRef (); +} + +void CFeatureIndex::SetFetchFailure (bool fails) + +{ + CWeakRef bsx = GetBioseqIndex(); + auto bsxl = bsx.Lock(); + if (bsxl) { + bsxl->SetFetchFailure(fails); + } +} + +void CFeatureIndex::GetSequence (int from, int to, string& buffer) + +{ + try { + if (! m_SeqVec) { + CWeakRef bsx = GetBioseqIndex(); + auto bsxl = bsx.Lock(); + if (bsxl) { + CConstRef lc = GetMappedLocation(); + if (lc) { + m_SeqVec = new CSeqVector(*lc, *bsxl->GetScope()); + if (m_SeqVec) { + m_SeqVec->SetCoding(CBioseq_Handle::eCoding_Iupac); + } + } + } + } + + if (m_SeqVec) { + CSeqVector& vec = *m_SeqVec; + if (from < 0) { + from = 0; + } + if (to < 0 || to >= (int) vec.size()) { + to = vec.size(); + } + if (vec.CanGetRange(from, to)) { + vec.GetSeqData(from, to, buffer); + } else { + SetFetchFailure(true); + } + } + } + catch (CException& e) { + SetFetchFailure(true); + LOG_POST(Error << "Error in CFeatureIndex::GetSequence: " << e.what()); + } +} + +string CFeatureIndex::GetSequence (int from, int to) + +{ + string buffer; + + GetSequence(from, to, buffer); + + return buffer; +} + +void CFeatureIndex::GetSequence (string& buffer) + +{ + GetSequence(0, -1, buffer); +} + +string CFeatureIndex::GetSequence (void) + +{ + string buffer; + + GetSequence(0, -1, buffer); + + return buffer; +} + + +// CWordPairIndexer + +// superscript and subscript code points not handled by UTF8ToAsciiString +typedef SStaticPair TExtraTranslationPair; +typedef CStaticPairArrayMap TExtraTranslations; +static const TExtraTranslationPair kExtraTranslations[] = { + { 0x00B2, '2' }, + { 0x00B3, '3' }, + { 0x00B9, '1' }, + { 0x2070, '0' }, + { 0x2071, '1' }, + { 0x2074, '4' }, + { 0x2075, '5' }, + { 0x2076, '6' }, + { 0x2077, '7' }, + { 0x2078, '8' }, + { 0x2079, '9' }, + { 0x207A, '+' }, + { 0x207B, '-' }, + { 0x207C, '=' }, + { 0x207D, '(' }, + { 0x207E, ')' }, + { 0x207F, 'n' }, + { 0x2080, '0' }, + { 0x2081, '1' }, + { 0x2082, '2' }, + { 0x2083, '3' }, + { 0x2084, '4' }, + { 0x2085, '5' }, + { 0x2086, '6' }, + { 0x2087, '7' }, + { 0x2088, '8' }, + { 0x2089, '9' }, + { 0x208A, '+' }, + { 0x208B, '-' }, + { 0x208C, '=' }, + { 0x208D, '(' }, + { 0x208E, ')' } +}; +DEFINE_STATIC_ARRAY_MAP(TExtraTranslations, sc_ExtraTranslations, + kExtraTranslations); + +string CWordPairIndexer::ConvertUTF8ToAscii( const string& str ) + +{ + const char* src = str.c_str(); + string dst; + while (*src) { + if (static_cast(*src) < 128) { // no translation needed + dst += *src++; + } else { + utf8::TUnicode character; + size_t n = utf8::UTF8ToUnicode(src, &character); + src += n; + TExtraTranslations::const_iterator it + = sc_ExtraTranslations.find(character); + if (it != sc_ExtraTranslations.end()) { + dst += it->second; + } else { + const utf8::SUnicodeTranslation* translation = + utf8::UnicodeToAscii(character); + if (translation != NULL && translation->Type != utf8::eSkip) { + _ASSERT(translation->Type == utf8::eString); + if (translation->Subst != NULL) { + dst += translation->Subst; + } + } + } + } + } + return dst; +} + +static const char* const idxStopWords[] = { + "+", + "-", + "a", + "about", + "again", + "all", + "almost", + "also", + "although", + "always", + "among", + "an", + "and", + "another", + "any", + "are", + "as", + "at", + "be", + "because", + "been", + "before", + "being", + "between", + "both", + "but", + "by", + "can", + "could", + "did", + "do", + "does", + "done", + "due", + "during", + "each", + "either", + "enough", + "especially", + "etc", + "for", + "found", + "from", + "further", + "had", + "has", + "have", + "having", + "here", + "how", + "however", + "i", + "if", + "in", + "into", + "is", + "it", + "its", + "itself", + "just", + "kg", + "km", + "made", + "mainly", + "make", + "may", + "mg", + "might", + "ml", + "mm", + "most", + "mostly", + "must", + "nearly", + "neither", + "no", + "nor", + "obtained", + "of", + "often", + "on", + "our", + "overall", + "perhaps", + "pmid", + "quite", + "rather", + "really", + "regarding", + "seem", + "seen", + "several", + "should", + "show", + "showed", + "shown", + "shows", + "significantly", + "since", + "so", + "some", + "such", + "than", + "that", + "the", + "their", + "theirs", + "them", + "then", + "there", + "therefore", + "these", + "they", + "this", + "those", + "through", + "thus", + "to", + "upon", + "use", + "used", + "using", + "various", + "very", + "was", + "we", + "were", + "what", + "when", + "which", + "while", + "with", + "within", + "without", + "would", +}; +typedef CStaticArraySet TStopWords; +DEFINE_STATIC_ARRAY_MAP(TStopWords, sc_StopWords, idxStopWords); + +bool CWordPairIndexer::IsStopWord(const string& str) + +{ + TStopWords::const_iterator iter = sc_StopWords.find(str.c_str()); + return (iter != sc_StopWords.end()); +} + +string CWordPairIndexer::TrimPunctuation (const string& str) + +{ + string dst = str; + + int max = dst.length(); + + for (; max > 0; max--) { + char ch = dst[0]; + if (ch != '.' && ch != ',' && ch != ':' && ch != ';') { + break; + } + // trim leading period, comma, colon, and semicolon + dst.erase(0, 1); + } + + for (; max > 0; max--) { + char ch = dst[max-1]; + if (ch != '.' && ch != ',' && ch != ':' && ch != ';') { + break; + } + // // trim trailing period, comma, colon, and semicolon + dst.erase(max-1, 1); + } + + if (max > 1) { + if (dst[0] == '(' && dst[max-1] == ')') { + // trim flanking parentheses + dst.erase(max-1, 1); + dst.erase(0, 1); + max -= 2; + } + } + + if (max > 0) { + if (dst[0] == '(' && NStr::Find (dst, ")") == NPOS) { + // trim isolated left parentheses + dst.erase(0, 1); + max--; + } + } + + if (max > 1) { + if (dst[max-1] == ')' && NStr::Find (dst, "(") == NPOS) { + // trim isolated right parentheses + dst.erase(max-1, 1); + // max--; + } + } + + return dst; +} + +static const char* const mixedTags[] = { + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "", + "<i>", + "</i>", + "<i/>", + "<b>", + "</b>", + "<b/>", + "<u>", + "</u>", + "<u/>", + "<sub>", + "</sub>", + "<sub/>", + "<sup>", + "</sup>", + "<sup/>", + "&lt;i&gt;", + "&lt;/i&gt;", + "&lt;i/&gt;", + "&lt;b&gt;", + "&lt;/b&gt;", + "&lt;b/&gt;", + "&lt;u&gt;", + "&lt;/u&gt;", + "&lt;u/&gt;", + "&lt;sub&gt;", + "&lt;/sub&gt;", + "&lt;sub/&gt;", + "&lt;sup&gt;", + "&lt;/sup&gt;", + "&lt;sup/&gt;", +}; + +static int SkipMixedContent ( const char* ptr ) + +{ + for (int i = 0; i < sizeof (mixedTags); i++) { + const char* tag = mixedTags[i]; + const char* tmp = ptr; + int len = 0; + while (*tag && *tmp && *tag == *tmp) { + tag++; + tmp++; + len++; + } + if (! *tag) { + return len; + } + } + return 0; +} + +string CWordPairIndexer::TrimMixedContent ( const string& str ) + +{ + const char* src = str.c_str(); + string dst; + while (*src) { + if (*src == '<' || *src == '&') { + int skip = SkipMixedContent (src); + if (skip > 0) { + src += skip; + } else { + dst += *src++; + } + } else { + dst += *src++; + } + } + return dst; +} + +string CWordPairIndexer::x_AddToWordPairIndex (string item, string prev) + +{ + if (IsStopWord(item)) { + return ""; + } + // append item + m_Norm.push_back(item); + if (! prev.empty()) { + // append prev+" "+item + string pair = prev + " " + item; + m_Pair.push_back(pair); + } + return item; +} + +void CWordPairIndexer::PopulateWordPairIndex (string str) + +{ + m_Norm.clear(); + m_Pair.clear(); + + str = ConvertUTF8ToAscii(str); + NStr::ToLower(str); + + if (NStr::Find(str, "<") != NPOS || NStr::Find(str, "&") != NPOS) { + str = TrimMixedContent(str); + } + + // split terms at spaces + list terms; + NStr::Split( str, " ", terms, NStr::fSplit_Tokenize ); + string prev = ""; + ITERATE( list, it, terms ) { + string curr = NStr::TruncateSpaces( *it ); + // allow parentheses in chemical formula + curr = TrimPunctuation(curr); + prev = x_AddToWordPairIndex (curr, prev); + } + + // convert non-alphanumeric punctuation to space + for (int i = 0; i < str.length(); i++) { + char ch = str[i]; + if (ch >= 'A' && ch <= 'Z') { + } else if (ch >= 'a' && ch <= 'z') { + } else if (ch >= '0' && ch <= '9') { + } else { + str[i] = ' '; + } + } + // now splitting at all punctuation + list words; + NStr::Split( str, " ", words, NStr::fSplit_Tokenize ); + prev = ""; + ITERATE( list, it, words ) { + string curr = NStr::TruncateSpaces( *it ); + prev = x_AddToWordPairIndex (curr, prev); + } + + std::sort(m_Norm.begin(), m_Norm.end()); + auto nit = std::unique(m_Norm.begin(), m_Norm.end()); + m_Norm.erase(nit, m_Norm.end()); + + std::sort(m_Pair.begin(), m_Pair.end()); + auto pit = std::unique(m_Pair.begin(), m_Pair.end()); + m_Pair.erase(pit, m_Pair.end()); +} + + +END_SCOPE(objects) +END_NCBI_SCOPE diff --git a/c++/src/objmgr/util/obj_sniff.cpp b/c++/src/objmgr/util/obj_sniff.cpp index 4cd0d19c..ac8aa2c6 100644 --- a/c++/src/objmgr/util/obj_sniff.cpp +++ b/c++/src/objmgr/util/obj_sniff.cpp @@ -1,4 +1,4 @@ -/* $Id: obj_sniff.cpp 518489 2016-11-03 16:06:30Z ivanov $ +/* $Id: obj_sniff.cpp 518419 2016-11-02 19:37:47Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/util/objutil.cpp b/c++/src/objmgr/util/objutil.cpp index dff15ec0..b07f05ed 100644 --- a/c++/src/objmgr/util/objutil.cpp +++ b/c++/src/objmgr/util/objutil.cpp @@ -1,4 +1,4 @@ -/* $Id: objutil.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: objutil.cpp 544492 2017-08-23 17:44:32Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -265,8 +265,9 @@ void StripSpaces(string& str) while (it != end) { *new_str++ = *it; if ( (*it == ' ') || (*it == '\t') || (*it == '(') ) { - for (++it; *it == ' ' || *it == '\t'; ++it) continue; - if (*it == ')' || *it == ',') { + for (++it; it != end && (*it == ' ' || *it == '\t'); ++it) + continue; + if (it != end && (*it == ')' || *it == ',')) { if( *(new_str - 1) != '(' ) { // this if protects against the case "(...bunch of spaces and tabs...)". Otherwise, the first '(' is erased --new_str; } @@ -1615,37 +1616,37 @@ EResolveOrder GetResolveOrder(CScope& scope, // ============================================================================ // Link locations: // ============================================================================ -const string strLinkBaseNuc( - "https://www.ncbi.nlm.nih.gov/nuccore/" ); -const string strLinkBaseProt( - "https://www.ncbi.nlm.nih.gov/protein/" ); - -const string strLinkBaseEntrezViewer( - "https://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?val=" ); // https forwarded to http - -const string strLinkBaseTaxonomy( - "https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?" ); -const string strLinkBaseTransTable( - "https://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi?mode=c#SG" ); -const string strLinkBasePubmed( - "https://www.ncbi.nlm.nih.gov/pubmed/" ); -const string strLinkBaseExpasy( - "http://www.expasy.org/enzyme/" ); // not government site -const string strLinkBaseNucSearch( - "https://www.ncbi.nlm.nih.gov/sites/entrez?db=Nucleotide&cmd=Search&term=" ); -const string strLinkBaseGenomePrj( - "https://www.ncbi.nlm.nih.gov/bioproject/" ); -const string strLinkBaseLatLon( - "https://www.ncbi.nlm.nih.gov/projects/Sequin/latlonview.html" ); -const string strLinkBaseGeneOntology ( - "http://amigo.geneontology.org/cgi-bin/amigo/go.cgi?view=details&depth=1&query=GO:" ); // not government site -const string strLinkBaseGeneOntologyRef ( - "http://www.geneontology.org/cgi-bin/references.cgi#GO_REF:" ); // not government site -const string strLinkBaseUSPTO( - "http://patft.uspto.gov/netacgi/nph-Parser?patentnumber=" ); - -const string strDocLink( - "https://www.ncbi.nlm.nih.gov/genome/annotation_euk/process/" ); +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseNuc = + "https://www.ncbi.nlm.nih.gov/nuccore/"; +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseProt = + "https://www.ncbi.nlm.nih.gov/protein/"; + +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseEntrezViewer = + "https://www.ncbi.nlm.nih.gov/entrez/viewer.fcgi?val="; // https forwarded to http + +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseTaxonomy = + "https://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?"; +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseTransTable = + "https://www.ncbi.nlm.nih.gov/Taxonomy/Utils/wprintgc.cgi?mode=c#SG"; +NCBI_XOBJEDIT_EXPORT const char* strLinkBasePubmed = + "https://www.ncbi.nlm.nih.gov/pubmed/"; +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseExpasy = + "http://www.expasy.org/enzyme/"; // not government site +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseNucSearch = + "https://www.ncbi.nlm.nih.gov/sites/entrez?db=Nucleotide&cmd=Search&term="; +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseGenomePrj = + "https://www.ncbi.nlm.nih.gov/bioproject/"; +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseLatLon = + "https://www.ncbi.nlm.nih.gov/projects/Sequin/latlonview.html"; +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseGeneOntology = + "http://amigo.geneontology.org/cgi-bin/amigo/go.cgi?view=details&depth=1&query=GO:"; // not government site +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseGeneOntologyRef = + "http://www.geneontology.org/cgi-bin/references.cgi#GO_REF:"; // not government site +NCBI_XOBJEDIT_EXPORT const char* strLinkBaseUSPTO = + "http://patft.uspto.gov/netacgi/nph-Parser?patentnumber="; + +NCBI_XOBJEDIT_EXPORT const char* strDocLink = + "https://www.ncbi.nlm.nih.gov/genome/annotation_euk/process/"; namespace { // make sure we're not "double-sanitizing" diff --git a/c++/src/objmgr/util/seq_align_util.cpp b/c++/src/objmgr/util/seq_align_util.cpp index a9209836..a2ee0f9a 100644 --- a/c++/src/objmgr/util/seq_align_util.cpp +++ b/c++/src/objmgr/util/seq_align_util.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_align_util.cpp 140455 2008-09-17 19:14:07Z grichenk $ +/* $Id: seq_align_util.cpp 544228 2017-08-21 11:28:23Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,9 +32,16 @@ #include #include #include -#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include BEGIN_NCBI_SCOPE @@ -72,6 +79,213 @@ CRef RemapAlignToLoc(const CSeq_align& align, } +class CProductStringBuilder +{ +public: + CProductStringBuilder(const CSeq_align& align, CScope& scope); + const string& GetProductString(void); + +private: + bool x_AddExon(const CSpliced_exon& ex); + bool x_AddExonPart(const CSpliced_exon_chunk& ch, TSeqPos& gen_offset); + void x_Match(TSeqPos gen_from, TSeqPos gen_to_open); + bool x_Mismatch(TSeqPos mismatch_len); + + const CSeq_align& m_Align; + CScope& m_Scope; + string m_MismatchedBases; + bool m_GenRev = false; + bool m_ProdRev = false; + CSeqVector m_GenVector; + string m_ExonData; + string m_Result; + TSeqPos m_ProdPos = 0; + size_t m_MismatchPos = 0; +}; + + +CProductStringBuilder::CProductStringBuilder(const CSeq_align& align, CScope& scope) + : m_Align(align), m_Scope(scope) +{ +} + + +const string& CProductStringBuilder::GetProductString(void) +{ + m_Result.clear(); + // Only spliced-segs are supported. + if (!m_Align.GetSegs().IsSpliced()) { + NCBI_THROW(CObjmgrUtilException, eBadAlignment, + "Only splised-seg alignments are supported"); + } + + const CSpliced_seg& spliced_seg = m_Align.GetSegs().GetSpliced(); + // Only genomic alignments support MismatchedBases. + if (spliced_seg.GetProduct_type() != CSpliced_seg::eProduct_type_transcript) { + // ERROR: Non-transcript alignment. + NCBI_THROW(CObjmgrUtilException, eBadAlignment, + "Only transcript spliced-segs are supported"); + } + + const CSeq_id& gen_id = m_Align.GetSeq_id(1); + + CBioseq_Handle gen_handle = m_Scope.GetBioseqHandle(gen_id); + if ( !gen_handle ) { + NCBI_THROW(CObjmgrUtilException, eBadAlignment, + "Failed to fetch genomic sequence data"); + } + + m_GenVector = CSeqVector(gen_handle, CBioseq_Handle::eCoding_Iupac); + + if ( spliced_seg.IsSetProduct_length() ) { + m_Result.reserve(spliced_seg.GetProduct_length()); + } + m_GenRev = IsReverse(m_Align.GetSeqStrand(1)); + m_ProdRev = IsReverse(m_Align.GetSeqStrand(0)); + + // NOTE: Even if ext is not set or does not contain MismatchedBases entry it may + // still be possible to generate product sequence if the alignment is a perfect + // match (no indels, mismatches or unaligned ranges on product). + + if ( m_Align.IsSetExt() ) { + // Find MismatchedBases entry in ext. If several entries are present, use + // the first one. + ITERATE(CSeq_align::TExt, ext_it, m_Align.GetExt()) { + const CUser_object& obj = **ext_it; + if (obj.GetType().IsStr() && obj.GetType().GetStr() == "MismatchedBases") { + ITERATE(CUser_object::TData, data_it, obj.GetData()) { + const CUser_field& field = **data_it; + if (field.GetLabel().IsStr() && field.GetLabel().GetStr() == "Bases" && + field.GetData().IsStr()) { + m_MismatchedBases = field.GetData().GetStr(); + break; + } + } + if ( !m_MismatchedBases.empty() ) break; + } + } + } + + if ((m_GenRev != m_ProdRev) && !m_MismatchedBases.empty()) { + CSeqManip::ReverseComplement(m_MismatchedBases, CSeqUtil::e_Iupacna, 0, (TSeqPos)m_MismatchedBases.size()); + } + + const CSpliced_seg::TExons& exons = spliced_seg.GetExons(); + + if ( m_ProdRev ) { + REVERSE_ITERATE(CSpliced_seg::TExons, ex_it, exons) { + if ( !x_AddExon(**ex_it) ) return kEmptyStr; + } + } + else { + ITERATE(CSpliced_seg::TExons, ex_it, exons) { + if ( !x_AddExon(**ex_it) ) return kEmptyStr; + } + } + if (m_MismatchPos < m_MismatchedBases.size()) { + x_Mismatch(TSeqPos(m_MismatchedBases.size() - m_MismatchPos)); + } + + return m_Result; +} + + +bool CProductStringBuilder::x_AddExon(const CSpliced_exon& ex) +{ + TSeqPos gen_from = ex.GetGenomic_start(); + TSeqPos gen_to = ex.GetGenomic_end() + 1; // open range + _ASSERT(ex.GetProduct_start().IsNucpos()); + _ASSERT(ex.GetProduct_end().IsNucpos()); + + // The whole exon must be reverse-complemented. + m_GenVector.GetSeqData(gen_from, gen_to, m_ExonData); + if (m_GenRev != m_ProdRev) { + CSeqManip::ReverseComplement(m_ExonData, CSeqUtil::e_Iupacna, 0, gen_to - gen_from); + } + + TSeqPos prod_from = ex.GetProduct_start().GetNucpos(); + if (prod_from > m_ProdPos) { + if ( !x_Mismatch(prod_from - m_ProdPos) ) return false; + } + _ASSERT(prod_from == m_ProdPos); + + if ( ex.IsSetParts() ) { + // Iterate parts + TSeqPos gen_offset = 0; + if (m_ProdRev) { + REVERSE_ITERATE(CSpliced_exon::TParts, part_it, ex.GetParts()) { + if ( !x_AddExonPart(**part_it, gen_offset) ) return false; + } + } + else { + ITERATE(CSpliced_exon::TParts, part_it, ex.GetParts()) { + if ( !x_AddExonPart(**part_it, gen_offset) ) return false; + } + } + } + else { + // Use whole exon + x_Match(0, gen_to - gen_from); + } + _ASSERT(m_ProdPos == ex.GetProduct_end().GetNucpos() + 1); + return true; +} + + +bool CProductStringBuilder::x_AddExonPart(const CSpliced_exon_chunk& ch, TSeqPos& gen_offset) +{ + switch ( ch.Which() ) { + case CSpliced_exon_chunk::e_Match: + x_Match(gen_offset, gen_offset + ch.GetMatch()); + gen_offset += ch.GetMatch(); + break; + case CSpliced_exon_chunk::e_Mismatch: + if ( !x_Mismatch(ch.GetMismatch()) ) return false; + gen_offset += ch.GetMismatch(); + break; + case CSpliced_exon_chunk::e_Product_ins: + x_Mismatch(ch.GetProduct_ins()); + break; + case CSpliced_exon_chunk::e_Genomic_ins: + gen_offset += ch.GetGenomic_ins(); + break; + case CSpliced_exon_chunk::e_Diag: + // ERROR: It's not clear if diag is a match or a mismatch. + default: + // ERROR: Unexpected chunk type. + NCBI_THROW(CObjmgrUtilException, eBadAlignment, + "Unsupported chunk type"); + } + return true; +} + + +inline +void CProductStringBuilder::x_Match(TSeqPos gen_from, TSeqPos gen_to_open) +{ + m_Result.append(m_ExonData.substr(gen_from, gen_to_open - gen_from)); + m_ProdPos += gen_to_open - gen_from; +} + + +inline +bool CProductStringBuilder::x_Mismatch(TSeqPos mismatch_len) +{ + if (m_MismatchedBases.size() < mismatch_len) return false; + m_Result.append(m_MismatchedBases.substr(m_MismatchPos, mismatch_len)); + m_MismatchPos += mismatch_len; + m_ProdPos += mismatch_len; + return true; +} + + +string GetProductString(const CSeq_align& align, CScope& scope) +{ + CProductStringBuilder builder(align, scope); + return builder.GetProductString(); +} + + END_SCOPE(sequence) END_SCOPE(objects) END_NCBI_SCOPE diff --git a/c++/src/objmgr/util/seq_loc_util.cpp b/c++/src/objmgr/util/seq_loc_util.cpp index 63effb7e..a05d84e0 100644 --- a/c++/src/objmgr/util/seq_loc_util.cpp +++ b/c++/src/objmgr/util/seq_loc_util.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_loc_util.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: seq_loc_util.cpp 531968 2017-03-30 17:34:38Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -2008,10 +2008,18 @@ CSeq_id_Handle CDefaultSynonymMapper::GetBestSynonym(const CSeq_id& id) return id_syn->second; } CSeq_id_Handle best; - int best_rank = kMax_Int; + int best_rank = CSeq_id::kMaxScore; CConstRef syn_set = m_Scope->GetSynonyms(idh); +#ifdef _DEBUG + TGi gi = ZERO_GI; +#endif ITERATE(CSynonymsSet, syn_it, *syn_set) { CSeq_id_Handle synh = syn_set->GetSeq_id_Handle(syn_it); +#ifdef _DEBUG + if (synh.IsGi()) { + gi = synh.GetGi(); + } +#endif int rank = synh.GetSeqId()->BestRankScore(); if (rank < best_rank) { best = synh; @@ -2026,6 +2034,13 @@ CSeq_id_Handle CDefaultSynonymMapper::GetBestSynonym(const CSeq_id& id) ITERATE(CSynonymsSet, syn_it, *syn_set) { m_SynMap[syn_set->GetSeq_id_Handle(syn_it)] = best; } +#ifdef _DEBUG + const CTextseq_id* txt_id = best.GetSeqId()->GetTextseq_Id(); + if (txt_id && !txt_id->IsSetVersion() && gi != ZERO_GI) { + ERR_POST("Using version-less accession " << txt_id->GetAccession() + << " instead of GI " << gi); + } +#endif return best; } diff --git a/c++/src/objmgr/util/seq_trimmer.cpp b/c++/src/objmgr/util/seq_trimmer.cpp index 2f8196f7..200afabb 100644 --- a/c++/src/objmgr/util/seq_trimmer.cpp +++ b/c++/src/objmgr/util/seq_trimmer.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_trimmer.cpp 433382 2014-04-24 17:15:18Z gotvyans $ +/* $Id: seq_trimmer.cpp 540892 2017-07-12 11:35:04Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -210,7 +210,8 @@ CSequenceAmbigTrimmer::CSequenceAmbigTrimmer( } CSequenceAmbigTrimmer::EResult -CSequenceAmbigTrimmer::DoTrim( CBioseq_Handle &bioseq_handle) +CSequenceAmbigTrimmer::DoTrim( CBioseq_Handle &bioseq_handle, + CRangeCollection *trimmed_ranges ) { _ASSERT( bioseq_handle ); @@ -231,6 +232,10 @@ CSequenceAmbigTrimmer::DoTrim( CBioseq_Handle &bioseq_handle) } if( leftmost_good_base > rightmost_good_base ) { // trimming leaves nothing left + if( trimmed_ranges ) { + *trimmed_ranges += TSeqRange(0, bioseq_len - 1); + _ASSERT(bioseq_len == trimmed_ranges->GetCoveredLength()); + } return x_TrimToNothing( bioseq_handle ); } @@ -242,6 +247,10 @@ CSequenceAmbigTrimmer::DoTrim( CBioseq_Handle &bioseq_handle) } if( leftmost_good_base > rightmost_good_base ) { // trimming leaves nothing left + if( trimmed_ranges ) { + *trimmed_ranges += TSeqRange(0, bioseq_len - 1); + _ASSERT(bioseq_len == trimmed_ranges->GetCoveredLength()); + } return x_TrimToNothing( bioseq_handle ); } @@ -252,10 +261,21 @@ CSequenceAmbigTrimmer::DoTrim( CBioseq_Handle &bioseq_handle) return eResult_NoTrimNeeded; } - // do the actually slicing of the bioseq + // do the actual slicing of the bioseq x_SliceBioseq( leftmost_good_base, rightmost_good_base, bioseq_handle ); + if ( trimmed_ranges ) { + if( leftmost_good_base > 0 ) { + *trimmed_ranges += TSeqRange(0, leftmost_good_base - 1); + } + if( rightmost_good_base < bioseq_len - 1 ) { + *trimmed_ranges += TSeqRange(rightmost_good_base + 1, + bioseq_len - 1); + } + _ASSERT( bioseq_handle.GetBioseqLength() == + bioseq_len - trimmed_ranges->GetCoveredLength()); + } return eResult_SuccessfullyTrimmed; } diff --git a/c++/src/objmgr/util/seqtitle.cpp b/c++/src/objmgr/util/seqtitle.cpp index 4dc00fce..dec36291 100644 --- a/c++/src/objmgr/util/seqtitle.cpp +++ b/c++/src/objmgr/util/seqtitle.cpp @@ -1,4 +1,4 @@ -/* $Id: seqtitle.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: seqtitle.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objmgr/util/sequence.cpp b/c++/src/objmgr/util/sequence.cpp index edf30280..aa82b4cb 100644 --- a/c++/src/objmgr/util/sequence.cpp +++ b/c++/src/objmgr/util/sequence.cpp @@ -1,4 +1,4 @@ -/* $Id: sequence.cpp 520790 2016-12-01 16:46:36Z ivanov $ +/* $Id: sequence.cpp 548848 2017-10-18 15:50:51Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -101,38 +101,6 @@ BEGIN_SCOPE(objects) BEGIN_SCOPE(sequence) -static string s_GetFastaTitle(const CBioseq& bs, - CDeflineGenerator::TUserFlags flags) -{ - string title; - bool has_molinfo = false; - - const CSeq_descr::Tdata& descr = bs.GetDescr().Get(); - for ( CSeq_descr::Tdata::const_iterator it = descr.begin(); it != descr.end(); ++it ) { - const CSeqdesc* sd = *it; - if ( sd->Which() == CSeqdesc::e_Title ) { - if ( title == "" ) { - title = sd->GetTitle(); - } - } - if ( sd->Which() == CSeqdesc::e_Molinfo ) { - has_molinfo = true; - } - } - - if ( !title.empty() && ! has_molinfo ) { - while (NStr::EndsWith(title, ".") || NStr::EndsWith(title, " ")) { - title.erase(title.end() - 1); - } - return title; - } - else { - CScope scope(*CObjectManager::GetInstance()); - CDeflineGenerator gen; - return gen.GenerateDefline(bs, scope, flags); - } -} - const CBioSource* GetBioSource(const CBioseq& bioseq) { ITERATE(CBioseq::TDescr::Tdata, it, bioseq.GetDescr().Get()) @@ -388,13 +356,13 @@ CSeq_id_Handle x_GetId(const CScope::TIds& ids, EGetIdType type) switch ( (type & eGetId_TypeMask) ) { case eGetId_ForceGi: - {{ + if ( !CSeq_id::AvoidGi() ) { ITERATE (CScope::TIds, iter, ids) { if (iter->IsGi()) { return *iter; } } - }} + } if ((type & eGetId_ThrowOnError) != 0) { NCBI_THROW(CSeqIdFromHandleException, eRequestedIdNotFound, "sequence::GetId(): gi seq-id not found in the list"); @@ -499,7 +467,8 @@ CSeq_id_Handle GetId(const CSeq_id_Handle& idh, CScope& scope, /// note that in the C Toolkit, the /// canonical ID appears to be gnl|TRACE|. /// - Short Read Archive: gnl|SRA|... - if (idh.IsGi()) return idh; + if (!CSeq_id::PreferAccessionOverGi() && + idh.IsGi()) return idh; if (idh.Which() == CSeq_id::e_General) { CConstRef id = idh.GetSeqId(); _ASSERT(id && id->IsGeneral()); @@ -557,6 +526,8 @@ CSeq_id_Handle GetId(const CBioseq_Handle& handle, TGi GetGiForAccession(const string& acc, CScope& scope, EGetIdType flags) { + if ( CSeq_id::AvoidGi() ) return ZERO_GI; + // Clear throw-on-error flag EGetIdType get_id_flags = (flags & eGetId_VerifyId) | eGetId_ForceGi; try { @@ -585,6 +556,8 @@ TGi GetGiForAccession(const string& acc, CScope& scope, EGetIdType flags) TGi GetGiForId(const objects::CSeq_id& id, CScope& scope, EGetIdType flags) { + if ( CSeq_id::AvoidGi() ) return ZERO_GI; + // Clear throw-on-error flag EGetIdType get_id_flags = (flags & eGetId_VerifyId) | eGetId_ForceGi; CSeq_id_Handle idh = GetId(id, scope, get_id_flags); @@ -1096,8 +1069,14 @@ void GetOverlappingFeatures(const CSeq_loc& loc, continue; } - TFeatScore sc(cur_diff, - ConstRef(&feat_it->GetMappedFeature())); + // quick fix for CFeat_CI returning wrong additional features + if (overlap_type == eOverlap_Contained) { + ECompare cmp = Compare(feat_it->GetLocation(), loc, &scope, fCompareOverlapping); + if (cmp != eContains && cmp != eSame) { + continue; + } + } + TFeatScore sc(cur_diff, ConstRef(&feat_it->GetMappedFeature())); feats.push_back(sc); } catch (CObjmgrUtilException&) { @@ -1180,14 +1159,19 @@ CConstRef GetmRNAforCDS(const CSeq_feat& cds, CScope& scope) CBioseq_Handle bsh; try { bsh = scope.GetBioseqHandle(cds.GetLocation()); - } catch (CException& ex) { + } catch (CException& ) { // multi-accession location, can't do this check return CConstRef(NULL); } + if (!bsh) + { + return CConstRef(NULL); + } + CTSE_Handle tse = bsh.GetTSE_Handle(); ITERATE(CSeq_feat::TXref, it, cds.GetXref()) { - if ((*it)->IsSetId() && (*it)->GetId().IsLocal() && (*it)->GetId().GetLocal().IsId()) { - CSeq_feat_Handle mrna_h = tse.GetFeatureWithId(CSeqFeatData::eSubtype_mRNA, (*it)->GetId().GetLocal().GetId()); + if ((*it)->IsSetId() && (*it)->GetId().IsLocal()) { + CSeq_feat_Handle mrna_h = tse.GetFeatureWithId(CSeqFeatData::eSubtype_mRNA, (*it)->GetId().GetLocal()); if (mrna_h) { mrna = mrna_h.GetSeq_feat(); } @@ -1361,20 +1345,48 @@ bool IsPseudo(const CSeq_feat& feat, CScope& scope) return false; } - CConstRef GetLocalGeneByLocus(const string& locus, bool use_tag, CBioseq_Handle bsh) { CTSE_Handle tse = bsh.GetTSE_Handle(); const CBioseq& b = *(bsh.GetCompleteBioseq()); CTSE_Handle::TSeq_feat_Handles potentials = tse.GetGenesWithLocus(locus, use_tag); + //if (potentials.size() == 1) { // it may return wrong gene! + // return potentials.front().GetSeq_feat(); + //} ITERATE(CTSE_Handle::TSeq_feat_Handles, p, potentials) { - ITERATE(CBioseq::TId, id, b.GetId()) { - CSeq_id::E_SIC cmp = p->GetLocationId().GetSeqId()->Compare(**id); - if (cmp == CSeq_id::e_YES) { - return p->GetSeq_feat(); - } else if (cmp == CSeq_id::e_NO) { - break; + try { + CSeq_id_Handle id_h = p->GetLocationId(); + if (id_h) { + CConstRef p_id = id_h.GetSeqId(); + if (p_id) { + ITERATE(CBioseq::TId, id, b.GetId()) { + CSeq_id::E_SIC cmp = p_id->Compare(**id); + if (cmp == CSeq_id::e_YES) { + return p->GetSeq_feat(); + } else if (cmp == CSeq_id::e_NO) { + break; + } + } + } + } + } catch (CException&) { + CSeq_loc_CI li(p->GetLocation()); + while (li) { + try { + const CSeq_id& this_id = li.GetSeq_id(); + ITERATE(CBioseq::TId, id, b.GetId()) { + CSeq_id::E_SIC cmp = this_id.Compare(**id); + if (cmp == CSeq_id::e_YES) { + return p->GetSeq_feat(); + } else if (cmp == CSeq_id::e_NO) { + break; + } + } + } catch (CException& ) { + // no Seq-id for this sublocation, keep trying + } + ++li; } } } @@ -2208,7 +2220,7 @@ void GetCdssForGene(const CSeq_feat& gene_feat, CScope& scope, CConstRef feat = sequence::GetBestOverlappingFeat(gene_feat.GetLocation(), CSeqFeatData::eSubtype_cdregion, - sequence::eOverlap_CheckIntervals, + sequence::eOverlap_Subset, scope, opts, plugin ); if (feat) { cds_feats.push_back(feat); @@ -2677,31 +2689,83 @@ static bool s_ShouldUseOriginalID (const CBioseq& seq) return true; } -void CFastaOstream::x_WriteAsFasta(const CBioseq& bioseq) +void CFastaOstream::x_GetBestId(CConstRef& gi_id, CConstRef& best_id, bool& hide_prefix, const CBioseq& bioseq) { bool is_na = bioseq.GetInst().GetMol() != CSeq_inst::eMol_aa; - CConstRef best_id = FindBestChoice(bioseq.GetId(), - is_na ? CSeq_id::FastaNARank - : CSeq_id::FastaAARank); + best_id = FindBestChoice(bioseq.GetId(), is_na ? CSeq_id::FastaNARank : CSeq_id::FastaAARank); + + ITERATE(CBioseq::TId, id, bioseq.GetId()) { + if ((*id)->IsGi()) { + gi_id = *id; + break; + } + } + + // see SQD-4144, only Accession.Version should be shown, without prefixes and suffixes + if (best_id.NotEmpty() && + (m_Flags & fEnableGI) == 0 && + (m_Flags & fHideGenBankPrefix) != 0) + { + switch (best_id->Which()) + { + case CSeq_id::e_Genbank: + case CSeq_id::e_Embl: + case CSeq_id::e_Other: + case CSeq_id::e_Ddbj: + case CSeq_id::e_Tpg: + case CSeq_id::e_Tpe: + case CSeq_id::e_Tpd: + hide_prefix = true; + break; + default: + break; + } + } +} + +void CFastaOstream::x_WriteAsFasta(const CBioseq& bioseq) +{ + CConstRef best_id; + CConstRef gi_id; + bool hide_prefix = false; + + // override this method and provide application specific 'best id' policy + x_GetBestId(gi_id, best_id, hide_prefix, bioseq); - // RW-139, no GI in FASTA output if (best_id.NotEmpty()) { - if ((m_Flags & fEnableGI) && !best_id->IsGi()) + // RW-139, no GI in FASTA output + if (gi_id.NotEmpty() && (m_Flags & fEnableGI) && !best_id->IsGi()) { // FastA format // Here we have something like: // gi|###|SOME_ACCESSION|title - ITERATE(CBioseq::TId, id, bioseq.GetId()) { - if ((*id)->IsGi()) { - (*id)->WriteAsFasta(m_Out); - m_Out << '|'; - break; + gi_id->WriteAsFasta(m_Out); + m_Out << '|'; + } + + const CTextseq_id* text_id = 0; + if (hide_prefix) + { + text_id = best_id->GetTextseq_Id(); + } + + if (text_id != 0) + { + if (text_id->IsSetAccession()) + { + m_Out << text_id->GetAccession(); + if (text_id->IsSetVersion()) + { + m_Out << "." << text_id->GetVersion(); } } } - best_id->WriteAsFasta(m_Out); + else + { + best_id->WriteAsFasta(m_Out); + } } } @@ -2753,104 +2817,6 @@ void CFastaOstream::x_WriteSeqIds(const CBioseq& bioseq, } } -void CFastaOstream::x_WriteModifiers ( const CBioseq_Handle & handle ) -{ - // print [topology=...], if necessary - if( handle.CanGetInst_Topology() ) { - CSeq_inst::ETopology topology = handle.GetInst_Topology(); - if( topology == CSeq_inst::eTopology_circular ) { - m_Out << " [topology=circular]"; - } - } - - // handle modifiers retrieved from Biosource.Org-ref - // [organism=...], etc. - - bool organism_seen = false; - bool strain_seen = false; - bool gcode_seen = false; - - try { - const COrg_ref & org = sequence::GetOrg_ref(handle); - if( org.IsSetTaxname() ) { - x_PrintStringModIfNotDup( &organism_seen, "organism", org.GetTaxname() ); - } - if( org.IsSetOrgname() ) { - const COrg_ref::TOrgname & orgname = org.GetOrgname(); - if( orgname.IsSetMod() ) { - ITERATE( COrgName::TMod, mod_iter, orgname.GetMod() ) { - const COrgMod & mod = **mod_iter; - if( mod.IsSetSubtype() ) { - switch( mod.GetSubtype() ) { - case COrgMod::eSubtype_strain: - if( mod.IsSetSubname() ) { - x_PrintStringModIfNotDup( &strain_seen, "strain", mod.GetSubname() ); - } - break; - default: - // ignore; do nothing - break; - } - } - } - } - if( orgname.IsSetGcode() ) { - x_PrintIntModIfNotDup( &gcode_seen, "gcode", orgname.GetGcode() ); - } - } - } catch( CException & ) { - // ignore exception; it probably just means there's no org-ref - } - - typedef SStaticPair TTechMapEntry; - static const TTechMapEntry sc_TechArray[] = { - // note that the text values do *NOT* precisely correspond with - // the names in the ASN.1 schema files - { CMolInfo::eTech_unknown, "?" }, - { CMolInfo::eTech_standard, "standard" }, - { CMolInfo::eTech_est, "EST" }, - { CMolInfo::eTech_sts, "STS" }, - { CMolInfo::eTech_survey, "survey" }, - { CMolInfo::eTech_genemap, "genetic map" }, - { CMolInfo::eTech_physmap, "physical map" }, - { CMolInfo::eTech_derived, "derived" }, - { CMolInfo::eTech_concept_trans, "concept-trans" }, - { CMolInfo::eTech_seq_pept, "seq-pept" }, - { CMolInfo::eTech_both, "both" }, - { CMolInfo::eTech_seq_pept_overlap, "seq-pept-overlap" }, - { CMolInfo::eTech_seq_pept_homol, "seq-pept-homol" }, - { CMolInfo::eTech_concept_trans_a, "concept-trans-a" }, - { CMolInfo::eTech_htgs_1, "htgs 1" }, - { CMolInfo::eTech_htgs_2, "htgs 2" }, - { CMolInfo::eTech_htgs_3, "htgs 3" }, - { CMolInfo::eTech_fli_cdna, "fli cDNA" }, - { CMolInfo::eTech_htgs_0, "htgs 0" }, - { CMolInfo::eTech_htc, "htc" }, - { CMolInfo::eTech_wgs, "wgs" }, - { CMolInfo::eTech_barcode, "barcode" }, - { CMolInfo::eTech_composite_wgs_htgs, "composite-wgs-htgs" }, - { CMolInfo::eTech_tsa, "tsa" } - }; - typedef CStaticPairArrayMap TTechMap; - DEFINE_STATIC_ARRAY_MAP(TTechMap, sc_TechMap, sc_TechArray); - - // print some key-value pairs - bool tech_seen = false; - const CMolInfo * pMolInfo = sequence::GetMolInfo(handle); - if( pMolInfo != NULL ) { - const CMolInfo & molinfo = *pMolInfo; - if( molinfo.IsSetTech() ) { - TTechMap::const_iterator find_iter = sc_TechMap.find(molinfo.GetTech()); - if( find_iter != sc_TechMap.end() ) { - x_PrintStringModIfNotDup( &tech_seen, "tech", - find_iter->second ); - } - } - } - - m_Out << '\n'; -} - inline sequence::CDeflineGenerator::TUserFlags CFastaOstream::x_GetTitleFlags(void) const @@ -2859,116 +2825,48 @@ CFastaOstream::x_GetTitleFlags(void) const if ((m_Flags & fNoExpensiveOps) != 0) { title_flags |= sequence::CDeflineGenerator::fNoExpensiveOps; } + if ((m_Flags & fShowModifiers) != 0) { + title_flags |= sequence::CDeflineGenerator::fShowModifiers; + } return title_flags; } -void CFastaOstream::x_WriteSeqTitle(const CBioseq& bioseq, - CScope* scope, +void CFastaOstream::x_WriteSeqTitle(const CBioseq_Handle & bioseq_handle, const string& custom_title) { - string safe_title; - if ( !custom_title.empty() ) { - safe_title = custom_title; - } else if (scope) { - safe_title = m_Gen->GenerateDefline(bioseq, *scope, x_GetTitleFlags()); - } else { - safe_title = sequence::s_GetFastaTitle(bioseq, x_GetTitleFlags()); - } - - if ( !(m_Flags & fKeepGTSigns) ) { - NON_CONST_ITERATE (string, it, safe_title) { - switch (*it) { - case '>': *it = '_'; break; - default: break; - } - } - } + string safe_title = (!custom_title.empty()) ? custom_title + : m_Gen->GenerateDefline(bioseq_handle, x_GetTitleFlags()); if ( !safe_title.empty() ) { - m_Out << ' ' << safe_title; + if ( !(m_Flags & fKeepGTSigns) ) { + NStr::ReplaceInPlace(safe_title, ">", "_"); + } + if (safe_title[0] != ' ') { + m_Out << ' '; + } + m_Out << safe_title; } m_Out << '\n'; } -void CFastaOstream::x_PrintStringModIfNotDup( - bool *seen, const CTempString & key, const CTempString & value ) -{ - _ASSERT( NULL != seen ); - _ASSERT( ! key.empty() ); - if( *seen ) { - ERR_POST_X(9, Warning << "CFastaOstream::x_PrintStringModIfNotDup: " - << "key " << key << " would appear multiple times, but only using the first." ); - return; - } - - if( value.empty() ) { - return; - } - - m_Out << " [" << key << '='; - // The case of no quotes is much more common, so optimize for that - if( value.find_first_of("\"=") == string::npos ) { - // normal case: no weird characters in value name - m_Out << value ; - } else { - // rarer case: bad characters in value name, so - // we need surrounding double-quotes and we need to change - // double-quotes to single-quotes. - m_Out << '"' << NStr::Replace( value, "\"", "'") << '"'; - } - m_Out << ']'; - *seen = true; -} - -void CFastaOstream::x_PrintIntModIfNotDup( - bool *seen, const CTempString & key, const int value ) -{ - CNcbiOstrstream strm; - strm << value; - x_PrintStringModIfNotDup( seen, key, - (string)CNcbiOstrstreamToString(strm) ); -} - - void CFastaOstream::WriteTitle(const CBioseq& bioseq, const CSeq_loc* location, - bool no_scope, + bool no_scope, // not used const string& custom_title) { - if ( no_scope && ! location ) { - x_WriteSeqIds(bioseq, NULL); - if( (m_Flags & fShowModifiers) != 0 ) { - CScope scope(*CObjectManager::GetInstance()); - CBioseq_Handle bioseq_handle = scope.AddBioseq(bioseq); - x_WriteModifiers(bioseq_handle); - } else { - x_WriteSeqTitle(bioseq, NULL, custom_title); - } - } - else { - CScope scope(*CObjectManager::GetInstance()); - WriteTitle(scope.AddBioseq(bioseq), location, custom_title); - } + x_WriteSeqIds(bioseq, location); + CScope scope(*CObjectManager::GetInstance()); + CBioseq_Handle bioseq_handle = scope.AddBioseq(bioseq); + x_WriteSeqTitle(bioseq_handle, custom_title); } - -void CFastaOstream::WriteTitle(const CBioseq_Handle& handle, +void CFastaOstream::WriteTitle(const CBioseq_Handle& bioseq_handle, const CSeq_loc* location, const string& custom_title) { - x_WriteSeqIds(*handle.GetBioseqCore(), location); - if( (m_Flags & fShowModifiers) != 0 ) { - x_WriteModifiers(handle); - } else { - string safe_title = - (custom_title.empty() - ? m_Gen->GenerateDefline(handle, x_GetTitleFlags()) - : custom_title); - if ((m_Flags & fKeepGTSigns) == 0) { - NStr::ReplaceInPlace(safe_title, ">", "_"); - } - m_Out << ' ' << safe_title << '\n'; - } + const CBioseq& bioseq = *bioseq_handle.GetBioseqCore(); + x_WriteSeqIds(bioseq, location); + x_WriteSeqTitle(bioseq_handle, custom_title); } @@ -3321,13 +3219,14 @@ void CFastaOstream::Write(const CSeq_entry& entry, const CSeq_loc* location, void CFastaOstream::Write(const CBioseq& seq, const CSeq_loc* location, bool no_scope, const string& custom_title ) { + CScope scope(*CObjectManager::GetInstance()); + CBioseq_Handle bioseq_handle = scope.AddBioseq(seq); if (location || !no_scope) { - CScope scope(*CObjectManager::GetInstance()); - Write(scope.AddBioseq(seq), location, custom_title); + Write(bioseq_handle, location, custom_title); } else { /// write our title x_WriteSeqIds(seq, NULL); - x_WriteSeqTitle(seq, NULL, custom_title); + x_WriteSeqTitle(bioseq_handle, custom_title); /// write the sequence TMSMap masking_state; @@ -3456,7 +3355,7 @@ CFastaOstream::GetGapModText( need_evidence = is_linkage; break; case CSeq_gap::eType_short_arm: - gap_type = "short_arm"; + gap_type = "short arm"; break; case CSeq_gap::eType_heterochromatin: gap_type = "heterochromatin"; @@ -3577,74 +3476,78 @@ void x_Translate(const Container& seq, (code ? CGen_code_table::GetTransTable(*code) : CGen_code_table::GetTransTable(1)); - // main loop through bases - typename Container::const_iterator start = seq.begin(); - {{ - for (int i = 0; i < frame; ++i) { - ++start; - } - }} - - size_t i; - size_t k; + char aa = '\0'; int state = 0; int start_state = 0; - size_t length = usable_size / 3; - bool check_start = (is_5prime_complete && frame == 0); - bool first_time = true; - char aa = '\0'; + try { + // main loop through bases + typename Container::const_iterator start = seq.begin(); + {{ + for (int i = 0; i < frame; ++i) { + ++start; + } + }} - for (i = 0; i < length; ++i) { + size_t i; + size_t k; + size_t length = usable_size / 3; + bool check_start = (is_5prime_complete && frame == 0); + bool first_time = true; - // loop through one codon at a time - for (k = 0; k < 3; ++k, ++start) { - state = tbl.NextCodonState(state, *start); - } + for (i = 0; i < length; ++i) { - if (first_time) { - start_state = state; - } + // loop through one codon at a time + for (k = 0; k < 3; ++k, ++start) { + state = tbl.NextCodonState(state, *start); + } - // save translated amino acid - if (first_time && check_start) { - aa = tbl.GetStartResidue(state); - prot.append(1, aa); - } else { - aa = tbl.GetCodonResidue(state); - prot.append(1, aa); - } + if (first_time) { + start_state = state; + } - first_time = false; - } + // save translated amino acid + if (first_time && check_start) { + aa = tbl.GetStartResidue(state); + prot.append(1, aa); + } else { + aa = tbl.GetCodonResidue(state); + prot.append(1, aa); + } - if (mod) { - for (k = 0; k < mod; ++k, ++start) { - state = tbl.NextCodonState(state, *start); + first_time = false; } - for ( ; k < 3; ++k) { - state = tbl.NextCodonState(state, 'N'); - } + if (mod) { + for (k = 0; k < mod; ++k, ++start) { + state = tbl.NextCodonState(state, *start); + } - if (first_time) { - start_state = state; - } + for (; k < 3; ++k) { + state = tbl.NextCodonState(state, 'N'); + } + + if (first_time) { + start_state = state; + } - // save translated amino acid - char c = tbl.GetCodonResidue(state); - if (first_time && check_start) { - aa = tbl.GetStartResidue(state); - prot.append(1, aa); - } else if (c != 'X') { - // if padding was needed, trim ambiguous last residue - aa = tbl.GetCodonResidue(state); - prot.append(1, aa); + // save translated amino acid + char c = tbl.GetCodonResidue(state); + if (first_time && check_start) { + aa = tbl.GetStartResidue(state); + prot.append(1, aa); + } else if (c != 'X') { + // if padding was needed, trim ambiguous last residue + aa = tbl.GetCodonResidue(state); + prot.append(1, aa); + } } + } catch (CSeqVectorException& ex) { + // ran out of sequence } if ( aa != '*' && include_stop && (! mod) && prot.size() > 0 ) { // check for stop codon that normally encodes an amino acid - aa = tbl.GetStartResidue(state); + aa = tbl.GetStopResidue(state); if (aa == '*') { prot[prot.size()-1] = aa; } @@ -3799,97 +3702,100 @@ CRef CSeqTranslator::TranslateToProtein(const CSeq_feat& cds, (code ? CGen_code_table::GetTransTable(*code) : CGen_code_table::GetTransTable(1)); - // main loop through bases - CSeqVector::const_iterator start = seq.begin(); - for (int i = 0; i < frame; ++i) { - ++start; - } + try { + // main loop through bases + CSeqVector::const_iterator start = seq.begin(); + for (int i = 0; i < frame; ++i) { + ++start; + } + + TSeqPos i; + TSeqPos k; + int state = 0; + TSeqPos length = usable_size / 3; + bool check_start = (is_5prime_complete && frame == 0); + bool first_time = true; + + for (i = 0; i < length; ++i) { + bool is_gap = true; + bool unknown_length = false; + TSeqPos pos = (i * 3) + frame; + + if (start.HasZeroGapBefore()) { + AddGapToDeltaSeq(prot, true, 0); + } - TSeqPos i; - TSeqPos k; - int state = 0; - TSeqPos length = usable_size / 3; - bool check_start = (is_5prime_complete && frame == 0); - bool first_time = true; - - for (i = 0; i < length; ++i) { - bool is_gap = true; - bool unknown_length = false; - TSeqPos pos = (i * 3) + frame; - - if (start.HasZeroGapBefore()) { - AddGapToDeltaSeq(prot, true, 0); - } - - // loop through one codon at a time - for (k = 0; k < 3; ++k, ++start) { - state = tbl.NextCodonState(state, *start); - if (seq.IsInGap(pos + k)) { - if (is_gap && !unknown_length) { - CSeqMap_CI map_iter(map, &scope, SSeqMapSelector(), pos + k); - if (map_iter.GetType() == CSeqMap::eSeqGap - && map_iter.IsUnknownLength()) { - unknown_length = true; + // loop through one codon at a time + for (k = 0; k < 3; ++k, ++start) { + state = tbl.NextCodonState(state, *start); + if (seq.IsInGap(pos + k)) { + if (is_gap && !unknown_length) { + CSeqMap_CI map_iter(map, &scope, SSeqMapSelector(), pos + k); + if (map_iter.GetType() == CSeqMap::eSeqGap + && map_iter.IsUnknownLength()) { + unknown_length = true; + } } + } else { + is_gap = false; } - } else { - is_gap = false; } - } - if (is_gap) { - AddGapToDeltaSeq(prot, unknown_length, 1); - } else { - // save translated amino acid - if (first_time && check_start) { - AddAAToDeltaSeq(prot, tbl.GetStartResidue(state)); + if (is_gap) { + AddGapToDeltaSeq(prot, unknown_length, 1); } else { - AddAAToDeltaSeq(prot, tbl.GetCodonResidue(state)); - } - - } + // save translated amino acid + if (first_time && check_start) { + AddAAToDeltaSeq(prot, tbl.GetStartResidue(state)); + } else { + AddAAToDeltaSeq(prot, tbl.GetCodonResidue(state)); + } - first_time = false; - } + } - if (mod) { - bool is_gap = true; - bool unknown_length = false; - TSeqPos pos = (length * 3) + frame; - for (k = 0; k < mod; ++k, ++start) { - state = tbl.NextCodonState(state, *start); - if (seq.IsInGap(pos + k)) { - if (is_gap && !unknown_length) { - CSeqMap_CI map_iter(map, &scope, SSeqMapSelector(), pos + k); - if (map_iter.GetType() == CSeqMap::eSeqGap) { - if (map_iter.IsUnknownLength()) { - unknown_length = true; + first_time = false; + } + + if (mod) { + bool is_gap = true; + bool unknown_length = false; + TSeqPos pos = (length * 3) + frame; + for (k = 0; k < mod; ++k, ++start) { + state = tbl.NextCodonState(state, *start); + if (seq.IsInGap(pos + k)) { + if (is_gap && !unknown_length) { + CSeqMap_CI map_iter(map, &scope, SSeqMapSelector(), pos + k); + if (map_iter.GetType() == CSeqMap::eSeqGap) { + if (map_iter.IsUnknownLength()) { + unknown_length = true; + } } } + } else { + is_gap = false; } - } else { - is_gap = false; } - } - CRef last = prot->SetInst().SetExt().SetDelta().Set().back(); - if (is_gap) { - AddGapToDeltaSeq(prot, unknown_length, 1); - } else { - for (; k < 3; ++k) { - state = tbl.NextCodonState(state, 'N'); - } + if (is_gap) { + AddGapToDeltaSeq(prot, unknown_length, 1); + } else { + for (; k < 3; ++k) { + state = tbl.NextCodonState(state, 'N'); + } - // save translated amino acid - char c = tbl.GetCodonResidue(state); - if (c != 'X') { - if (first_time && check_start) { - AddAAToDeltaSeq(prot, tbl.GetStartResidue(state)); - } else { - AddAAToDeltaSeq(prot, tbl.GetCodonResidue(state)); + // save translated amino acid + char c = tbl.GetCodonResidue(state); + if (c != 'X') { + if (first_time && check_start) { + AddAAToDeltaSeq(prot, tbl.GetStartResidue(state)); + } else { + AddAAToDeltaSeq(prot, tbl.GetCodonResidue(state)); + } } } } + } catch (CSeqVectorException& ex) { + // ran out of sequence } TSeqPos prot_len = 0; @@ -3940,8 +3846,13 @@ CRef CSeqTranslator::TranslateToProtein(const CSeq_feat& cds, } // remove stop codon from end - CRef end = prot->SetInst().SetExt().SetDelta().Set().back(); - if (end->IsLiteral() && end->GetLiteral().IsSetSeq_data()) { + CRef end; + if (!prot->SetInst().SetExt().SetDelta().Set().empty()) + { + end = prot->SetInst().SetExt().SetDelta().Set().back(); + } + + if (end && end->IsLiteral() && end->GetLiteral().IsSetSeq_data()) { if (end->GetLiteral().GetSeq_data().IsIupacaa()) { string& last_seg = end->SetLiteral().SetSeq_data().SetIupacaa().Set(); if (NStr::EndsWith(last_seg, "*")) { @@ -4163,8 +4074,19 @@ void CSeqTranslator::Translate(const CSeq_feat& feat, } -CCdregion::EFrame CSeqTranslator::FindBestFrame(const CSeq_feat& cds, CScope& scope) +typedef struct { + bool has_final_stop; + bool has_internal_stop; + bool has_start_m; + size_t len; + size_t frame_offset; +} SFrameInfo; + +typedef map TFrameInfoMap; + +CCdregion::EFrame CSeqTranslator::FindBestFrame(const CSeq_feat& cds, CScope& scope, bool& ambiguous) { + ambiguous = false; if (!cds.IsSetLocation() || !cds.IsSetData() || !cds.GetData().IsCdregion()) { return CCdregion::eFrame_not_set; } @@ -4177,27 +4099,100 @@ CCdregion::EFrame CSeqTranslator::FindBestFrame(const CSeq_feat& cds, CScope& sc CRef tmp_cds(new CSeq_feat()); tmp_cds->Assign(cds); - vector frames; - frames.push_back(CCdregion::eFrame_one); - frames.push_back(CCdregion::eFrame_two); - frames.push_back(CCdregion::eFrame_three); - size_t best = 0; - CCdregion::EFrame best_frame = orig_frame; - ITERATE(vector, it, frames) { - tmp_cds->SetData().SetCdregion().SetFrame(*it); + TFrameInfoMap frame_map; + frame_map[CCdregion::eFrame_one] = { false, false, false, NPOS, 0 }; + frame_map[CCdregion::eFrame_two] = { false, false, false, NPOS, 1 }; + frame_map[CCdregion::eFrame_three] = { false, false, false, NPOS, 2 }; + + bool is_3complete = !tmp_cds->GetLocation().IsPartialStop(eExtreme_Biological); + bool is_5complete = !tmp_cds->GetLocation().IsPartialStart(eExtreme_Biological); + + size_t leftover = sequence::GetLength(tmp_cds->GetLocation(), &scope) % 3; + + for (auto it = frame_map.begin(); it != frame_map.end(); it++) { + tmp_cds->SetData().SetCdregion().SetFrame(it->first); string prot; CSeqTranslator::Translate(*tmp_cds, scope, prot, true, false, NULL); size_t pos = NStr::Find(prot, "*"); - if (pos == string::npos) { - pos = prot.length(); + it->second.len = prot.length(); + + if ((pos == prot.length() - 1) && (leftover == it->second.frame_offset)) { + it->second.has_final_stop = true; + } else if (pos != NPOS) { + it->second.has_internal_stop = true; + } + + if (NStr::StartsWith(prot, "M") && it->second.frame_offset == 0) { + it->second.has_start_m = true; } - if (pos > best || (pos == best && *it == orig_frame)) { - best = pos; - best_frame = *it; - } } - - return best_frame; + + // if the original frame has no internal stop codons and has a final + // stop codon, keep the original frame + if (frame_map[orig_frame].has_final_stop) { + return orig_frame; + } + + if (is_3complete && !is_5complete) { + // find a frame that has a stop codon + for (auto it = frame_map.begin(); it != frame_map.end(); it++) { + if (it->second.has_final_stop) { + return it->first; + } + } + } + + if (is_5complete && !is_3complete) { + // find a frame that has a start codon (could only be first frame) + if (frame_map[CCdregion::eFrame_one].has_start_m && !frame_map[CCdregion::eFrame_one].has_internal_stop) { + return CCdregion::eFrame_one; + } + } + + if (is_3complete) { + // find a frame that has a stop codon + for (auto it = frame_map.begin(); it != frame_map.end(); it++) { + if (it->second.has_final_stop) { + return it->first; + } + } + } + + if (is_5complete) { + // find a frame that has a start codon (could only be first frame) + if (frame_map[CCdregion::eFrame_one].has_start_m && !frame_map[CCdregion::eFrame_one].has_internal_stop) { + return CCdregion::eFrame_one; + } + } + + // otherwise, just looking for no internal stop codon + if (!frame_map[orig_frame].has_internal_stop) { + return orig_frame; + } + + CCdregion::EFrame best_frame = CCdregion::eFrame_not_set; + for (auto it = frame_map.begin(); it != frame_map.end(); it++) { + if (!it->second.has_internal_stop) { + if (best_frame == CCdregion::eFrame_not_set) { + best_frame = it->first; + } else { + ambiguous = true; + } + } + } + if (best_frame != CCdregion::eFrame_not_set) { + return best_frame; + } else { + return orig_frame; + } +} + + +CCdregion::EFrame CSeqTranslator::FindBestFrame(const CSeq_feat& cds, CScope& scope) +{ + bool ambiguous = false; + + return FindBestFrame(cds, scope, ambiguous); } diff --git a/c++/src/objmgr/util/weight.cpp b/c++/src/objmgr/util/weight.cpp index 5289947d..900cc4fb 100644 --- a/c++/src/objmgr/util/weight.cpp +++ b/c++/src/objmgr/util/weight.cpp @@ -1,4 +1,4 @@ -/* $Id: weight.cpp 514368 2016-09-21 15:22:14Z ivanov $ +/* $Id: weight.cpp 513580 2016-09-13 11:58:16Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/CMakeLists.txt b/c++/src/objtools/CMakeLists.txt new file mode 100644 index 00000000..728500a6 --- /dev/null +++ b/c++/src/objtools/CMakeLists.txt @@ -0,0 +1,30 @@ +############################################################################## +# +# + +# Include projects from this directory + +# Recurse subdirectories +add_subdirectory(unit_test_util ) +add_subdirectory(readers) +add_subdirectory(blast) +add_subdirectory(lds2) +add_subdirectory(data_loaders) +add_subdirectory(simple) +add_subdirectory(alnmgr) +add_subdirectory(cddalignview) +add_subdirectory(test ) +add_subdirectory(manip) +add_subdirectory(cleanup) +add_subdirectory(format) +add_subdirectory(edit) +add_subdirectory(validator) +add_subdirectory(asniotest) +add_subdirectory(align) +add_subdirectory(seqmasks_io) +add_subdirectory(eutils) +add_subdirectory(align_format) +add_subdirectory(snputil) +add_subdirectory(uudutil) +add_subdirectory(variation) +add_subdirectory(writers) diff --git a/c++/src/objtools/align_format/CMakeLists.align_format.lib.txt b/c++/src/objtools/align_format/CMakeLists.align_format.lib.txt new file mode 100644 index 00000000..82e7b4df --- /dev/null +++ b/c++/src/objtools/align_format/CMakeLists.align_format.lib.txt @@ -0,0 +1,12 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/align_format/Makefile.align_format.lib +# +add_library(align_format + format_flags align_format_util showdefline showalign tabular + vectorscreen seqalignfilter taxFormat aln_printer +) +target_link_libraries(align_format + blast_services gene_info ncbi_xloader_genbank + seqdb taxon1 xalnmgr + xcgi xhtml xobjread +) diff --git a/c++/src/objtools/align_format/CMakeLists.txt b/c++/src/objtools/align_format/CMakeLists.txt new file mode 100644 index 00000000..5595c1a8 --- /dev/null +++ b/c++/src/objtools/align_format/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.align_format.lib.txt) + +# Recurse subdirectories +add_subdirectory(unit_test ) diff --git a/c++/src/objtools/align_format/align_format_util.cpp b/c++/src/objtools/align_format/align_format_util.cpp index 558f7784..2b785274 100644 --- a/c++/src/objtools/align_format/align_format_util.cpp +++ b/c++/src/objtools/align_format/align_format_util.cpp @@ -1,4 +1,4 @@ -/* $Id: align_format_util.cpp 520428 2016-11-28 18:25:18Z ivanov $ +/* $Id: align_format_util.cpp 548514 2017-10-16 11:11:33Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -87,7 +87,8 @@ CRef kScope; const char k_PSymbol[ePMatrixSize+1] = "ARNDCQEGHILKMFPSTWYVBZX"; -CNcbiRegistry *CAlignFormatUtil::m_Reg = NULL; +unique_ptr CAlignFormatUtil::m_Reg; +string CAlignFormatUtil::m_Protocol = ""; bool CAlignFormatUtil::m_geturl_debug_flag = false; auto_ptr CAlignFormatUtil::m_GeneInfoReader; ///Get blast score information @@ -667,6 +668,20 @@ void CAlignFormatUtil::GetAlnScores(const CSeq_align& aln, num_ident, use_this_gi, comp_adj_method); } +void CAlignFormatUtil::GetAlnScores(const CSeq_align& aln, + int& score, + double& bits, + double& evalue, + int& sum_n, + int& num_ident, + list& use_this_seq) +{ + int comp_adj_method = 0; // dummy variable + + CAlignFormatUtil::GetAlnScores(aln, score, bits, evalue, sum_n, + num_ident, use_this_seq, comp_adj_method); +} + void CAlignFormatUtil::GetAlnScores(const CSeq_align& aln, int& score, @@ -703,7 +718,65 @@ void CAlignFormatUtil::GetAlnScores(const CSeq_align& aln, score, bits, evalue, sum_n, num_ident, use_this_gi, comp_adj_method); } } - if(use_this_gi.size() == 0) GetUseThisSequence(aln,use_this_gi); + if(use_this_gi.size() == 0) { + GetUseThisSequence(aln,use_this_gi); + } +} + +//converts gi list to the list of gi:XXXXXXXX strings +static list s_NumGiToStringGiList(list use_this_gi)//for backward compatability +{ + const string k_GiPrefix = "gi:"; + list use_this_seq; + ITERATE(list, iter_gi, use_this_gi){ + string strSeq = k_GiPrefix + NStr::NumericToString(*iter_gi); + use_this_seq.push_back(strSeq); + } + return use_this_seq; +} + +void CAlignFormatUtil::GetAlnScores(const CSeq_align& aln, + int& score, + double& bits, + double& evalue, + int& sum_n, + int& num_ident, + list& use_this_seq, + int& comp_adj_method) +{ + bool hasScore = false; + score = -1; + bits = -1; + evalue = -1; + sum_n = -1; + num_ident = -1; + comp_adj_method = 0; + + list use_this_gi; + //look for scores at seqalign level first + hasScore = s_GetBlastScore(aln.GetScore(), score, bits, evalue, + sum_n, num_ident, use_this_gi, comp_adj_method); + + //look at the seg level + if(!hasScore){ + const CSeq_align::TSegs& seg = aln.GetSegs(); + if(seg.Which() == CSeq_align::C_Segs::e_Std){ + s_GetBlastScore(seg.GetStd().front()->GetScores(), + score, bits, evalue, sum_n, num_ident, use_this_gi, comp_adj_method); + } else if (seg.Which() == CSeq_align::C_Segs::e_Dendiag){ + s_GetBlastScore(seg.GetDendiag().front()->GetScores(), + score, bits, evalue, sum_n, num_ident, use_this_gi, comp_adj_method); + } else if (seg.Which() == CSeq_align::C_Segs::e_Denseg){ + s_GetBlastScore(seg.GetDenseg().GetScores(), + score, bits, evalue, sum_n, num_ident, use_this_gi, comp_adj_method); + } + } + if(use_this_gi.size() == 0) { + GetUseThisSequence(aln,use_this_seq); + } + else { + use_this_seq = s_NumGiToStringGiList(use_this_gi);//for backward compatability + } } string CAlignFormatUtil::GetGnlID(const CDbtag& dtg) @@ -718,7 +791,7 @@ string CAlignFormatUtil::GetGnlID(const CDbtag& dtg) return retval; } -string CAlignFormatUtil::GetLabel(CConstRef id) +string CAlignFormatUtil::GetLabel(CConstRef id,bool with_version) { string retval = ""; if (id->Which() == CSeq_id::e_General){ @@ -726,7 +799,7 @@ string CAlignFormatUtil::GetLabel(CConstRef id) retval = CAlignFormatUtil::GetGnlID(dtg); } if (retval == "") - retval = id->GetSeqIdString(); + retval = id->GetSeqIdString(with_version); return retval; } @@ -820,7 +893,7 @@ void CAlignFormatUtil::PruneSeqalign(const CSeq_align_set& source_aln, { CConstRef previous_id, subid; bool is_first_aln = true; - unsigned int num_align = 0; + unsigned int num_align = 0; ITERATE(CSeq_align_set::Tdata, iter, source_aln.Get()){ if ((*iter)->GetSegs().IsDisc()) { @@ -838,11 +911,38 @@ void CAlignFormatUtil::PruneSeqalign(const CSeq_align_set& source_aln, is_first_aln = false; previous_id = subid; } - new_aln.Set().push_back(*iter); + new_aln.Set().push_back(*iter); } } +unsigned int CAlignFormatUtil::GetSubjectsNumber(const CSeq_align_set& source_aln, + unsigned int number) +{ + CConstRef previous_id, subid; + bool is_first_aln = true; + unsigned int num_align = 0; + ITERATE(CSeq_align_set::Tdata, iter, source_aln.Get()){ + + if ((*iter)->GetSegs().IsDisc()) { + ++num_align; + } else { + subid = &((*iter)->GetSeq_id(1)); + if(is_first_aln || (!is_first_aln && !subid->Match(*previous_id))){ + ++num_align; + } + + if(num_align >= number) { + break; + } + + is_first_aln = false; + previous_id = subid; + } + } + return num_align; +} + void CAlignFormatUtil::PruneSeqalignAll(const CSeq_align_set& source_aln, CSeq_align_set& new_aln, @@ -1981,6 +2081,7 @@ static string s_MapLinkoutGenParam(string &url_link_tmpl, url_link = CAlignFormatUtil::MapTemplate(url_link,"lnk_displ",lnk_displ); url_link = CAlignFormatUtil::MapTemplate(url_link,"lnk_tl_info",lnk_tl_info); url_link = CAlignFormatUtil::MapTemplate(url_link,"label",label); + url_link = CAlignFormatUtil::MapProtocol(url_link); return url_link; } static string s_MapDisabledLink(string lnk_displ) @@ -2028,6 +2129,7 @@ static list s_GetLinkoutUrl(int linkout, if(textLink) { url_link = CAlignFormatUtil::MapTemplate(kUnigeneDispl,"lnk",url_link); } + url_link = CAlignFormatUtil::MapProtocol(url_link); linkout_list.push_back(url_link); } if ((linkout & eStructure) && cdd_rid != "" && cdd_rid != "0"){ @@ -2062,6 +2164,7 @@ static list s_GetLinkoutUrl(int linkout, if(textLink) { url_link = CAlignFormatUtil::MapTemplate(kStructureDispl,"lnk",url_link); } + url_link = CAlignFormatUtil::MapProtocol(url_link); linkout_list.push_back(url_link); } if (linkout & eGeo){ @@ -2078,6 +2181,7 @@ static list s_GetLinkoutUrl(int linkout, if(textLink) { url_link = CAlignFormatUtil::MapTemplate(kGeoDispl,"lnk",url_link); } + url_link = CAlignFormatUtil::MapProtocol(url_link); linkout_list.push_back(url_link); } if(linkout & eGene){ @@ -2102,7 +2206,8 @@ static list s_GetLinkoutUrl(int linkout, } if(textLink) { url_link = CAlignFormatUtil::MapTemplate(kGeneDispl,"lnk",url_link); - } + } + url_link = CAlignFormatUtil::MapProtocol(url_link); linkout_list.push_back(url_link); } @@ -2135,6 +2240,7 @@ static list s_GetLinkoutUrl(int linkout, if(textLink) { url_link = CAlignFormatUtil::MapTemplate(kMapviwerDispl,"lnk",url_link); } + url_link = CAlignFormatUtil::MapProtocol(url_link); linkout_list.push_back(url_link); } } @@ -2151,6 +2257,7 @@ static list s_GetLinkoutUrl(int linkout, if(textLink) { url_link = CAlignFormatUtil::MapTemplate(kMapviwerDispl,"lnk",url_link); } + url_link = CAlignFormatUtil::MapProtocol(url_link); linkout_list.push_back(url_link); } //View Bioassays involving s_GetLinkoutUrl(int linkout, if(textLink) { url_link = CAlignFormatUtil::MapTemplate(kBioAssayDispl,"lnk",url_link); } + url_link = CAlignFormatUtil::MapProtocol(url_link); linkout_list.push_back(url_link); } else if (linkout & eBioAssay && !is_na) { @@ -2187,6 +2295,7 @@ static list s_GetLinkoutUrl(int linkout, if(textLink) { url_link = CAlignFormatUtil::MapTemplate(kBioAssayDispl,"lnk",url_link); } + url_link = CAlignFormatUtil::MapProtocol(url_link); linkout_list.push_back(url_link); } if(linkout & eReprMicrobialGenomes){ @@ -2203,6 +2312,7 @@ static list s_GetLinkoutUrl(int linkout, if(textLink) { url_link = CAlignFormatUtil::MapTemplate(kReprMicrobialGenomesDispl,"lnk",url_link); } + url_link = CAlignFormatUtil::MapProtocol(url_link); linkout_list.push_back(url_link); } return linkout_list; @@ -2289,19 +2399,12 @@ static void s_AddLinkoutInfo(map > &linkout_map,int } - - void -CAlignFormatUtil::GetBdlLinkoutInfo(const list< CRef< CBlast_def_line > > &bdl, +CAlignFormatUtil::GetBdlLinkoutInfo(CBioseq::TId& cur_id, map > &linkout_map, ILinkoutDB* linkoutdb, const string& mv_build_name) { - - - for(list< CRef< CBlast_def_line > >::const_iterator iter = bdl.begin(); - iter != bdl.end(); iter++){ - CBioseq::TId& cur_id = (CBioseq::TId &)(*iter)->GetSeqid(); TGi gi = FindGi(cur_id); CRef seqID = FindBestChoice(cur_id, CSeq_id::WorstRank); @@ -2332,9 +2435,28 @@ CAlignFormatUtil::GetBdlLinkoutInfo(const list< CRef< CBlast_def_line > > &bdl, } if(linkout & eReprMicrobialGenomes){ s_AddLinkoutInfo(linkout_map,eReprMicrobialGenomes,cur_id); - } + } +} + +void +CAlignFormatUtil::GetBdlLinkoutInfo(const list< CRef< CBlast_def_line > > &bdl, + map > &linkout_map, + ILinkoutDB* linkoutdb, + const string& mv_build_name) +{ + + + for(list< CRef< CBlast_def_line > >::const_iterator iter = bdl.begin(); + iter != bdl.end(); iter++){ + CBioseq::TId& cur_id = (CBioseq::TId &)(*iter)->GetSeqid(); + + GetBdlLinkoutInfo(cur_id, + linkout_map, + linkoutdb, + mv_build_name); } } + static string s_GetTaxName(int taxid) { string taxName; @@ -2351,7 +2473,7 @@ static string s_GetTaxName(int taxid) return taxName; } -void s_AddOtherRelatedInfoLinks(const list< CRef< CBlast_def_line > > &bdl, +void s_AddOtherRelatedInfoLinks(CBioseq::TId& cur_id, const string& rid, bool is_na, bool for_alignment, @@ -2360,48 +2482,42 @@ void s_AddOtherRelatedInfoLinks(const list< CRef< CBlast_def_line > > &bdl, { //Identical Proteins - if(!is_na && bdl.size() > 1) { - list< CRef< CBlast_def_line > >::const_iterator iter = bdl.begin(); - CBioseq::TId& cur_id = (CBioseq::TId &)(*iter)->GetSeqid(); - TGi gi = FindGi(cur_id); - if (gi > ZERO_GI) { - CRef wid = FindBestChoice(cur_id, CSeq_id::WorstRank); - string label; - wid->GetLabel(&label, CSeq_id::eContent); - string url_link = kIdenticalProteinsUrl; - string lnk_displ = "Identical Proteins"; - url_link = s_MapLinkoutGenParam(url_link,rid,NStr::NumericToString(gi),for_alignment, cur_align,label,lnk_displ); - url_link = CAlignFormatUtil::MapTemplate(kIdenticalProteinsDispl,"lnk",url_link); - url_link = CAlignFormatUtil::MapTemplate(url_link,"label",label); - linkout_list.push_back(url_link); - } + TGi gi = FindGi(cur_id); + if (gi > ZERO_GI) { + CRef wid = FindBestChoice(cur_id, CSeq_id::WorstRank); + string label; + wid->GetLabel(&label, CSeq_id::eContent); + string url_link = kIdenticalProteinsUrl; + string lnk_displ = "Identical Proteins"; + url_link = s_MapLinkoutGenParam(url_link,rid,NStr::NumericToString(gi),for_alignment, cur_align,label,lnk_displ); + url_link = CAlignFormatUtil::MapTemplate(kIdenticalProteinsDispl,"lnk",url_link); + url_link = CAlignFormatUtil::MapTemplate(url_link,"label",label); + linkout_list.push_back(url_link); } } -list CAlignFormatUtil::GetFullLinkoutUrl(const list< CRef< CBlast_def_line > > &bdl, - const string& rid, - const string& cdd_rid, - const string& entrez_term, - bool is_na, - bool structure_linkout_as_group, - bool for_alignment, - int cur_align, - string& linkoutOrder, - int taxid, - string &database, - int query_number, - string &user_url, - string &preComputedResID, - ILinkoutDB* linkoutdb, - const string& mv_build_name) +static list s_GetFullLinkoutUrl(CBioseq::TId& cur_id, + const string& rid, + const string& cdd_rid, + const string& entrez_term, + bool is_na, + bool structure_linkout_as_group, + bool for_alignment, + int cur_align, + string& linkoutOrder, + int taxid, + string &database, + int query_number, + string &user_url, + string &preComputedResID, + //ILinkoutDB* linkoutdb, + //const string& mv_build_name, + map > &linkout_map, + bool getIdentProteins) { - list linkout_list; - map > linkout_map; - map >::iterator it; + list linkout_list; - GetBdlLinkoutInfo(bdl,linkout_map, linkoutdb, mv_build_name); - vector linkLetters; NStr::Split(linkoutOrder,",",linkLetters); //linkoutOrder = "G,U,M,E,S,B,R" for(size_t i = 0; i < linkLetters.size(); i++) { @@ -2439,9 +2555,7 @@ list CAlignFormatUtil::GetFullLinkoutUrl(const list< CRef< CBlast_def_li } string gnl; - if(!disableLink && linkout == eGenomicSeq) { - list< CRef< CBlast_def_line > >::const_iterator iter = bdl.begin(); - CBioseq::TId& cur_id = (CBioseq::TId &)(*iter)->GetSeqid(); + if(!disableLink && linkout == eGenomicSeq) { gnl = s_GetBestIDForURL(cur_id); } @@ -2472,10 +2586,103 @@ list CAlignFormatUtil::GetFullLinkoutUrl(const list< CRef< CBlast_def_li linkout_list.push_back(*iter); } } - s_AddOtherRelatedInfoLinks(bdl,rid,is_na,for_alignment,cur_align,linkout_list); + if(getIdentProteins) { + s_AddOtherRelatedInfoLinks(cur_id,rid,is_na,for_alignment,cur_align,linkout_list); + } return linkout_list; } + + +list CAlignFormatUtil::GetFullLinkoutUrl(const list< CRef< CBlast_def_line > > &bdl, + const string& rid, + const string& cdd_rid, + const string& entrez_term, + bool is_na, + bool structure_linkout_as_group, + bool for_alignment, + int cur_align, + string& linkoutOrder, + int taxid, + string &database, + int query_number, + string &user_url, + string &preComputedResID, + ILinkoutDB* linkoutdb, + const string& mv_build_name) + +{ + list linkout_list; + map > linkout_map; + if(bdl.size() > 0) { + GetBdlLinkoutInfo(bdl,linkout_map, linkoutdb, mv_build_name); + list< CRef< CBlast_def_line > >::const_iterator iter = bdl.begin(); + CBioseq::TId& cur_id = (CBioseq::TId &)(*iter)->GetSeqid(); + linkout_list = s_GetFullLinkoutUrl(cur_id, + rid, + cdd_rid, + entrez_term, + is_na, + structure_linkout_as_group, + for_alignment, + cur_align, + linkoutOrder, + taxid, + database, + query_number, + user_url, + preComputedResID, + linkout_map, + !is_na && bdl.size() > 1); + } + return linkout_list; +} + +list CAlignFormatUtil::GetFullLinkoutUrl(CBioseq::TId& cur_id, + const string& rid, + const string& cdd_rid, + const string& entrez_term, + bool is_na, + bool structure_linkout_as_group, + bool for_alignment, + int cur_align, + string& linkoutOrder, + int taxid, + string &database, + int query_number, + string &user_url, + string &preComputedResID, + ILinkoutDB* linkoutdb, + const string& mv_build_name, + bool getIdentProteins) + +{ + list linkout_list; + + map > linkout_map; + GetBdlLinkoutInfo(cur_id,linkout_map, linkoutdb, mv_build_name); + + linkout_list = s_GetFullLinkoutUrl(cur_id, + rid, + cdd_rid, + entrez_term, + is_na, + structure_linkout_as_group, + for_alignment, + cur_align, + linkoutOrder, + taxid, + database, + query_number, + user_url, + preComputedResID, + linkout_map, + getIdentProteins); + + return linkout_list; +} + + static bool FromRangeAscendingSort(CRange const& info1, CRange const& info2) { @@ -2833,6 +3040,42 @@ CRef CAlignFormatUtil::ExtractQuerySeqAlign(CRef return new_aln; } + +void CAlignFormatUtil::InitConfig() +{ + string l_cfg_file_name; + bool l_dbg = CAlignFormatUtil::m_geturl_debug_flag; + if( getenv("GETURL_DEBUG") ) CAlignFormatUtil::m_geturl_debug_flag = l_dbg = true; + if( !m_Reg ) { + bool cfgExists = true; + string l_ncbi_env; + string l_fmtcfg_env; + if( NULL != getenv("NCBI") ) l_ncbi_env = getenv("NCBI"); + if( NULL != getenv("FMTCFG") ) l_fmtcfg_env = getenv("FMTCFG"); + // config file name: value of FMTCFG or default ( .ncbirc ) + if( l_fmtcfg_env.empty() ) + l_cfg_file_name = ".ncbirc"; + else + l_cfg_file_name = l_fmtcfg_env; + // checkinf existance of configuration file + CFile l_fchecker( l_cfg_file_name ); + cfgExists = l_fchecker.Exists(); + if( (!cfgExists) && (!l_ncbi_env.empty()) ) { + if( l_ncbi_env.rfind("/") != (l_ncbi_env.length() -1 )) + l_ncbi_env.append("/"); + l_cfg_file_name = l_ncbi_env + l_cfg_file_name; + CFile l_fchecker2( l_cfg_file_name ); + cfgExists = l_fchecker2.Exists(); + } + if(cfgExists) { + CNcbiIfstream l_ConfigFile(l_cfg_file_name.c_str() ); + m_Reg.reset(new CNcbiRegistry(l_ConfigFile)); + if( l_dbg ) fprintf(stderr,"REGISTRY: %s\n",l_cfg_file_name.c_str()); + } + } + return; +} + // // get given url from registry file or return corresponding kNAME // value as default to preserve compatibility. @@ -2854,32 +3097,9 @@ string CAlignFormatUtil::GetURLFromRegistry( const string url_name, int index){ string l_fmt_suffix = "_FORMAT"; string l_host_port_suffix = "_HOST_PORT"; string l_subst_pattern; - string l_cfg_file_name; - bool l_dbg = CAlignFormatUtil::m_geturl_debug_flag; - if( getenv("GETURL_DEBUG") ) CAlignFormatUtil::m_geturl_debug_flag = l_dbg = true; - + if( !m_Reg ) { - string l_ncbi_env; - string l_fmtcfg_env; - if( NULL != getenv("NCBI") ) l_ncbi_env = getenv("NCBI"); - if( NULL != getenv("FMTCFG") ) l_fmtcfg_env = getenv("FMTCFG"); - // config file name: value of FMTCFG or default ( .ncbirc ) - if( l_fmtcfg_env.empty() ) - l_cfg_file_name = ".ncbirc"; - else - l_cfg_file_name = l_fmtcfg_env; - // checkinf existance of configuration file - CFile l_fchecker( l_cfg_file_name ); - if( (!l_fchecker.Exists()) && (!l_ncbi_env.empty()) ) { - if( l_ncbi_env.rfind("/") != (l_ncbi_env.length() -1 )) - l_ncbi_env.append("/"); - l_cfg_file_name = l_ncbi_env + l_cfg_file_name; - CFile l_fchecker2( l_cfg_file_name ); - if( !l_fchecker2.Exists() ) return GetURLDefault(url_name,index); // can't find .ncbrc file - } - CNcbiIfstream l_ConfigFile(l_cfg_file_name.c_str() ); - m_Reg = new CNcbiRegistry(l_ConfigFile); - if( l_dbg ) fprintf(stderr,"REGISTRY: %s\n",l_cfg_file_name.c_str()); + InitConfig(); } if( !m_Reg ) return GetURLDefault(url_name,index); // can't read .ncbrc file string l_base_dir = m_Reg->Get(l_secion_name, "INCLUDE_BASE_DIR"); @@ -2944,18 +3164,15 @@ string CAlignFormatUtil::GetURLDefault( const string url_name, int index) { TTagUrlMap::const_iterator url_it; if( index >= 0 ) search_name += "_" + NStr::IntToString( index); // actual name for index value is NAME_{index} - if( (url_it = sm_TagUrlMap.find( search_name ) ) != sm_TagUrlMap.end()) return url_it->second; + if( (url_it = sm_TagUrlMap.find( search_name ) ) != sm_TagUrlMap.end()) { + string url_link = CAlignFormatUtil::MapProtocol(url_it->second); + return url_link; + } string error_msg = "CAlignFormatUtil::GetURLDefault:no_defualt_for"+url_name; if( index != -1 ) error_msg += "_index_"+ NStr::IntToString( index ); return error_msg; } -// -// Release memory allocated for the NCBIRegistry object -// -void CAlignFormatUtil::ReleaseURLRegistry(void){ - if( m_Reg) { delete m_Reg; m_Reg = NULL;} -} void CAlignFormatUtil::GetAsciiProteinMatrix(const char* matrix_name, @@ -3052,6 +3269,8 @@ string CAlignFormatUtil::AddSpaces(string paramVal, unsigned int maxParamValLeng return paramVal; } + + string CAlignFormatUtil::GetProtocol() { CNcbiIfstream config_file(".ncbirc"); @@ -3065,6 +3284,23 @@ string CAlignFormatUtil::GetProtocol() return httpProt; } +/* +if(no config file) protocol = "https:" +if(no "BLASTFMTUTIL","PROTOCOL" entry in config file) protocol = "https:" +if(there is entry in config) protocol = entry which could be blank = "" +*/ +string CAlignFormatUtil::MapProtocol(string url_link) +{ + if(m_Protocol.empty()){ + if(!m_Reg) { + InitConfig(); + } + m_Protocol = (m_Reg && m_Reg->HasEntry("BLASTFMTUTIL","PROTOCOL")) ? m_Protocol = m_Reg->Get("BLASTFMTUTIL","PROTOCOL") : "https:"; + } + url_link = CAlignFormatUtil::MapTemplate(url_link,"protocol",m_Protocol); + return url_link; +} + static string s_MapCommonUrlParams(string urlTemplate, CAlignFormatUtil::SSeqURLInfo *seqUrlInfo) { string db,logstr_moltype; @@ -3081,6 +3317,7 @@ static string s_MapCommonUrlParams(string urlTemplate, CAlignFormatUtil::SSeqURL url_link = CAlignFormatUtil::MapTemplate(url_link,"log",logstr_moltype + logstr_location); url_link = CAlignFormatUtil::MapTemplate(url_link,"blast_rank",seqUrlInfo->blast_rank); url_link = CAlignFormatUtil::MapTemplate(url_link,"rid",seqUrlInfo->rid); + url_link = CAlignFormatUtil::MapProtocol(url_link); return url_link; } @@ -3178,18 +3415,11 @@ string CAlignFormatUtil::GetIDUrlGen(SSeqURLInfo *seqUrlInfo,const CBioseq::TId* string l_EntrezUrl = CAlignFormatUtil::GetURLFromRegistry(entrezTag); url_link = s_MapCommonUrlParams(l_EntrezUrl, seqUrlInfo); - if(!seqUrlInfo->useTemplates) { - string httpProt = kDefaultProtocol; - if(m_Reg && !m_Reg->Empty()) { - if(m_Reg->HasEntry("BLASTFMTUTIL","PROTOCOL")) { - httpProt = m_Reg->Get("BLASTFMTUTIL","PROTOCOL"); - } - } + if(!seqUrlInfo->useTemplates) { url_link = CAlignFormatUtil::MapTemplate(url_link,"acc",seqUrlInfo->accession); temp_class_info = (!seqUrlInfo->defline.empty())? CAlignFormatUtil::MapTemplate(temp_class_info,"defline",NStr::JavaScriptEncode(seqUrlInfo->defline)):temp_class_info; url_link = CAlignFormatUtil::MapTemplate(url_link,"cssInf",(seqUrlInfo->addCssInfo) ? temp_class_info.c_str() : ""); - url_link = CAlignFormatUtil::MapTemplate(url_link,"target",seqUrlInfo->new_win ? "TARGET=\"EntrezView\"" : ""); - url_link = CAlignFormatUtil::MapTemplate(url_link,"protocol",httpProt); + url_link = CAlignFormatUtil::MapTemplate(url_link,"target",seqUrlInfo->new_win ? "TARGET=\"EntrezView\"" : ""); } } else {//seqid general, dbtag specified @@ -3213,7 +3443,10 @@ string CAlignFormatUtil::GetIDUrlGen(SSeqURLInfo *seqUrlInfo,const CBioseq::TId* string url_holder = CAlignFormatUtil::GetURLFromRegistry("LOCAL_ID"); - string user_url = (seqUrlInfo->addCssInfo) ? m_Reg->Get("LOCAL_ID","TOOL_URL_ALIGN") : m_Reg->Get("LOCAL_ID","TOOL_URL"); + string user_url; + if (m_Reg) { + user_url = (seqUrlInfo->addCssInfo) ? m_Reg->Get("LOCAL_ID","TOOL_URL_ALIGN") : m_Reg->Get("LOCAL_ID","TOOL_URL"); + } string id_string; wid->GetLabel(&id_string, CSeq_id::eContent); url_link = CAlignFormatUtil::MapTemplate(user_url,"seq_id", NStr::URLEncode(id_string)); @@ -3225,6 +3458,7 @@ string CAlignFormatUtil::GetIDUrlGen(SSeqURLInfo *seqUrlInfo,const CBioseq::TId* url_link = CAlignFormatUtil::MapTemplate(url_link,"target",seqUrlInfo->new_win ? "TARGET=\"EntrezView\"" : ""); } } + url_link = CAlignFormatUtil::MapProtocol(url_link); seqUrlInfo->seqUrl = url_link; return url_link; } @@ -3334,6 +3568,7 @@ string CAlignFormatUtil::GetFullIDLink(SSeqURLInfo *seqUrlInfo,const CBioseq::TI static string s_MapCustomLink(string linkUrl,string reportType,string accession, string linkText, string linktrg, string linkTitle = kCustomLinkTitle,string linkCls = "") { string link = CAlignFormatUtil::MapTemplate(kCustomLinkTemplate,"custom_url",linkUrl); + link = CAlignFormatUtil::MapProtocol(link); link = CAlignFormatUtil::MapTemplate(link,"custom_title",linkTitle); link = CAlignFormatUtil::MapTemplate(link,"custom_report_type",reportType); link = CAlignFormatUtil::MapTemplate(link,"seqid",accession); @@ -3805,6 +4040,32 @@ void CAlignFormatUtil::GetUseThisSequence(const CSeq_align& aln,list& use_t } } + +/*use_this_seq will contain gi:nnnnnn or seqid:ssssss string list*/ +void CAlignFormatUtil::GetUseThisSequence(const CSeq_align& aln,list& use_this_seq) + +{ + if(!aln.CanGetExt() || aln.GetExt().size() == 0) return; + const CUser_object &user = *(aln.GetExt().front()); + + if (user.IsSetType() && user.GetType().IsStr() && user.GetType().GetStr() == "use_this_seqid" && user.IsSetData()) { + const CUser_object::TData& fields = user.GetData(); + for (CUser_object::TData::const_iterator fit = fields.begin(); fit != fields.end(); ++fit) { + const CUser_field& field = **fit; + + if (field.IsSetLabel() && field.GetLabel().IsStr() && field.GetLabel().GetStr() == "SEQIDS" && + field.IsSetData() && field.GetData().IsStrs()) { + const CUser_field::C_Data::TStrs& strs = field.GetData().GetStrs(); + ITERATE(CUser_field::TData::TStrs, acc_iter, strs) { + use_this_seq.push_back(*acc_iter); + } + } + } + } +} + + + CAlignFormatUtil::SSeqAlignSetCalcParams* CAlignFormatUtil::GetSeqAlignSetCalcParamsFromASN(const CSeq_align_set& alnSet) { @@ -3819,6 +4080,7 @@ CAlignFormatUtil::GetSeqAlignSetCalcParamsFromASN(const CSeq_align_set& alnSet) int rawScore = -1; int sum_n = -1; list use_this_gi; + list use_this_seq; const CSeq_align& aln = *(alnSet.Get().front()); @@ -3838,8 +4100,12 @@ CAlignFormatUtil::GetSeqAlignSetCalcParamsFromASN(const CSeq_align_set& alnSet) } } - - if(use_this_gi.size() == 0) GetUseThisSequence(aln,use_this_gi); + if(use_this_gi.size() == 0) { + GetUseThisSequence(aln,use_this_seq); + } + else { + use_this_seq = s_NumGiToStringGiList(use_this_gi);//for backward compatability + } auto_ptr seqSetInfo(new SSeqAlignSetCalcParams); @@ -3853,7 +4119,8 @@ CAlignFormatUtil::GetSeqAlignSetCalcParamsFromASN(const CSeq_align_set& alnSet) seqSetInfo->sum_n = sum_n == -1 ? 1:sum_n ; seqSetInfo->id = &(aln.GetSeq_id(1)); - seqSetInfo->use_this_gi = use_this_gi; + seqSetInfo->use_this_gi = StringGiToNumGiList(use_this_seq);//for backward compatability + seqSetInfo->use_this_seq = use_this_seq; seqSetInfo->raw_score = rawScore;//not used seqSetInfo->subjRange = CRange(0,0); @@ -3928,6 +4195,137 @@ CRef CAlignFormatUtil::GetDisplayIds(const CBioseq_Handle& handle, } + +//removes "gi:" or "seqid:" prefix from gi:nnnnnnn or seqid:nnnnn +static string s_UseThisSeqToTextSeqID(string use_this_seqid, bool &isGi) +{ + const string k_GiPrefix = "gi:"; + const string k_SeqIDPrefix = "seqid:"; + isGi = false; + string textSeqid; + if(NStr::StartsWith(use_this_seqid,k_GiPrefix)) { + textSeqid = NStr::Replace(use_this_seqid,k_GiPrefix,""); + isGi = true; + } + else if(NStr::StartsWith(use_this_seqid,k_SeqIDPrefix)) { + textSeqid = NStr::Replace(use_this_seqid,k_SeqIDPrefix,""); + } + else {//assume no prefix - gi + if(NStr::StringToInt8(use_this_seqid,NStr::fConvErr_NoThrow)) { + isGi = true; + } + } + return textSeqid; +} + + + +//assume that we have EITHER gi: OR seqid: in the list +bool CAlignFormatUtil::IsGiList(list &use_this_seq) +{ + bool isGi = false; + ITERATE(list, iter_seq, use_this_seq){ + s_UseThisSeqToTextSeqID( *iter_seq, isGi); + break; + } + return isGi; +} + +list CAlignFormatUtil::StringGiToNumGiList(list &use_this_seq) +{ + list use_this_gi; + ITERATE(list, iter_seq, use_this_seq){ + bool isGi = false; + string strGI = s_UseThisSeqToTextSeqID( *iter_seq, isGi); + if(isGi) use_this_gi.push_back(NStr::StringToInt8(strGI)); + } + return use_this_gi; +} + + + +bool CAlignFormatUtil::MatchSeqInSeqList(TGi cur_gi, CRef &seqID, list &use_this_seq,bool *isGiList) +{ + bool found = false; + bool isGi = false; + + string curSeqID = CAlignFormatUtil::GetLabel(seqID,true); //uses GetSeqIdString(true) + ITERATE(list, iter_seq, use_this_seq){ + isGi = false; + string useThisSeq = s_UseThisSeqToTextSeqID(*iter_seq, isGi); + if((isGi && cur_gi == NStr::StringToInt8((useThisSeq))) || (!isGi && curSeqID == useThisSeq)){ + found = true; + break; + } + } + if(isGiList) *isGiList = isGi; + return found; +} + + + +CRef CAlignFormatUtil::GetDisplayIds(const CBioseq_Handle& handle, + const CSeq_id& aln_id, + list& use_this_seq, + TGi *gi, + int *taxid, + string *textSeqID) + +{ + const CRef bdlRef = CSeqDB::ExtractBlastDefline(handle); + const list< CRef< CBlast_def_line > > &bdl = (bdlRef.Empty()) ? list< CRef< CBlast_def_line > >() : bdlRef->Get(); + + const CBioseq::TId* ids = &handle.GetBioseqCore()->GetId(); + CRef wid; + + if(gi) *gi = ZERO_GI; + if(taxid) *taxid = 0; + if(bdl.empty()){ + wid = FindBestChoice(*ids, CSeq_id::WorstRank); + if(gi) *gi = FindGi(*ids); + if(textSeqID) *textSeqID = GetLabel(wid,true);//uses GetSeqIdString(true) + } else { + bool found = false; + for(list< CRef< CBlast_def_line > >::const_iterator iter = bdl.begin(); + iter != bdl.end(); iter++){ + const CBioseq::TId* cur_id = &((*iter)->GetSeqid()); + TGi cur_gi = FindGi(*cur_id); + wid = FindBestChoice(*cur_id, CSeq_id::WorstRank); + string curSeqID = GetLabel(wid,true);//uses GetSeqIdString(true) + if (taxid && (*iter)->IsSetTaxid() && (*iter)->CanGetTaxid()){ + *taxid = (*iter)->GetTaxid(); + } + if (!use_this_seq.empty()) { + ITERATE(list, iter_seq, use_this_seq){ + bool isGi = false; + string useThisSeq = s_UseThisSeqToTextSeqID( *iter_seq, isGi); + if((isGi && cur_gi == NStr::StringToInt8((useThisSeq))) || (!isGi && curSeqID == useThisSeq)){ + found = true; + break; + } + } + } else { + ITERATE(CBioseq::TId, iter_id, *cur_id) { + if ((*iter_id)->Match(aln_id) + || (aln_id.IsGeneral() && aln_id.GetGeneral().CanGetDb() && + (*iter_id)->IsGeneral() && (*iter_id)->GetGeneral().CanGetDb() && + aln_id.GetGeneral().GetDb() == (*iter_id)->GetGeneral().GetDb())) { + found = true; + } + } + } + if(found){ + if(gi) *gi = cur_gi; + if(textSeqID) *textSeqID = curSeqID; + break; + } + } + } + + return wid; +} + + TGi CAlignFormatUtil::GetDisplayIds(const list< CRef< CBlast_def_line > > &bdl, const CSeq_id& aln_id, list& use_this_gi) diff --git a/c++/src/objtools/align_format/format_flags.cpp b/c++/src/objtools/align_format/format_flags.cpp index c09fd002..e27892a5 100644 --- a/c++/src/objtools/align_format/format_flags.cpp +++ b/c++/src/objtools/align_format/format_flags.cpp @@ -1,4 +1,4 @@ -/* $Id: format_flags.cpp 518046 2016-10-31 14:58:35Z ivanov $ +/* $Id: format_flags.cpp 516923 2016-10-19 14:23:23Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/align_format/showalign.cpp b/c++/src/objtools/align_format/showalign.cpp index fd678c56..04d0c479 100644 --- a/c++/src/objtools/align_format/showalign.cpp +++ b/c++/src/objtools/align_format/showalign.cpp @@ -1,4 +1,4 @@ -/* $Id: showalign.cpp 519417 2016-11-15 18:30:33Z ivanov $ +/* $Id: showalign.cpp 529708 2017-03-07 13:03:38Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -241,7 +241,7 @@ CDisplaySeqalign::~CDisplaySeqalign() if(m_DynamicFeature){ delete m_DynamicFeature; } - } + } } //8.Display Identities,positives,frames etc @@ -443,64 +443,6 @@ static int s_GetStdsegMasterFrame(const CStd_seg& ss, CScope& scope) return frame; } -///return the get sequence table for html display -///@param form_name: form name -///@parm db_is_na: is the db of nucleotide type? -///@query_number: the query number -///@return: the from string -/// -static string s_GetSeqForm(char* form_name, bool db_is_na, int query_number, - int db_type, const string& dbName,const char *rid, const char *queryID,bool showTreeButtons) -{ - string temp_buf = NcbiEmptyString; - AutoPtr > buf(new char[dbName.size() + 4096]); - if(form_name){ - string localClientButtons = ""; - if(showTreeButtons) { - string l_GetTreeViewForm = CAlignFormatUtil::GetURLFromRegistry( "TREEVIEW_FRM"); - localClientButtons = "" + l_GetTreeViewForm + ""; - } - string l_GetSeqSubmitForm = CAlignFormatUtil::GetURLFromRegistry( "GETSEQ_SUB_FRM", db_type); - string l_GetSeqSelectForm = CAlignFormatUtil::GetURLFromRegistry( "GETSEQ_SEL_FRM"); - - string template_str = "" + - localClientButtons + - "
    " + - l_GetSeqSubmitForm + //k_GetSeqSubmitForm[db_type] + - "" + - l_GetSeqSelectForm + //k_GetSeqSelectForm + - "
    "; - - if(showTreeButtons) { - sprintf(buf.get(), template_str.c_str(), form_name, query_number, - db_is_na?1:0, query_number, form_name, query_number, db_type, - query_number,query_number, - rid,queryID,form_name,query_number,rid,query_number,form_name,query_number); - - } - else { - sprintf(buf.get(), template_str.c_str(), form_name, query_number, - db_is_na?1:0, query_number, form_name, query_number, db_type, - query_number,query_number); - } - - } - temp_buf = buf.get(); - return temp_buf; -} - -///Gets Query Seq ID from Seq Align -///@param actual_aln_list: align set for one query -///@return: string query ID -static string s_GetQueryIDFromSeqAlign(const CSeq_align_set& actual_aln_list) -{ - CRef first_aln = actual_aln_list.Get().front(); - const CSeq_id& query_SeqID = first_aln->GetSeq_id(0); - string queryID; - query_SeqID.GetLabel(&queryID); - return queryID; -} - ///return concatenated exon sequence ///@param feat: the feature containing this cds @@ -1912,23 +1854,9 @@ void CDisplaySeqalign::DisplaySeqalign(CNcbiOstream& out) //inits m_FeatObj,m_featScope,m_CanRetrieveSeq,m_ConfigFile,m_Reg,m_LinkoutOrder,m_DynamicFeature x_InitAlignParams(actual_aln_list); - - bool newDesign = false; - string oldBlastFormat = m_Ctx ? m_Ctx->GetRequestValue("OLD_BLAST").GetValue() : kEmptyStr; - if(!oldBlastFormat.empty() && m_AlignOption & eHtml) { - oldBlastFormat = NStr::ToLower(oldBlastFormat); - newDesign = (oldBlastFormat == "on" || oldBlastFormat == "true" || oldBlastFormat == "yes") ? false : true; - } - if(m_Ctx && (m_AlignOption & eHtml) && !newDesign){ - out<<""; - } + //get sequence - if(m_AlignOption&eSequenceRetrieval && m_AlignOption&eHtml && m_CanRetrieveSeq){ - if(!newDesign) - out<\n"; } //begin to display @@ -1971,7 +1899,7 @@ void CDisplaySeqalign::DisplaySeqalign(CNcbiOstream& out) alnvecInfo->evalue, alnvecInfo->sum_n, num_ident, - alnvecInfo->use_this_gi, + alnvecInfo->use_this_seqid, alnvecInfo->comp_adj_method); alnvecInfo->alnvec = avRef; @@ -2119,13 +2047,7 @@ void CDisplaySeqalign::DisplaySeqalign(CNcbiOstream& out) } } if(m_AlignOption&eSequenceRetrieval && m_AlignOption&eHtml && m_CanRetrieveSeq){ - out<<"\n"; - if(!newDesign) - out<\n"; } } @@ -2171,26 +2093,26 @@ void CDisplaySeqalign::x_FillIdentityInfo(const string& sequence_standard, CDisplaySeqalign::SAlnDispParams *CDisplaySeqalign::x_FillAlnDispParams(const CRef< CBlast_def_line > &bdl, - const CBioseq_Handle& bsp_handle, - list& use_this_gi, + const CBioseq_Handle& bsp_handle, + list &use_this_seqid, TGi firstGi) { SAlnDispParams *alnDispParams = NULL; + bool isNa = bsp_handle.GetBioseqCore()->IsNa(); int seqLength = (int)bsp_handle.GetBioseqLength(); const list > ids = bdl->GetSeqid(); - TGi gi = CAlignFormatUtil::GetGiForSeqIdList(ids); - TGi gi_in_use_this_gi = ZERO_GI; + TGi gi = CAlignFormatUtil::GetGiForSeqIdList(ids); + + CRef wid = FindBestChoice(ids, CSeq_id::WorstRank); + TGi gi_in_use_this_gi = ZERO_GI; + bool isGiList = false; + bool match = CAlignFormatUtil::MatchSeqInSeqList(gi, wid, use_this_seqid,&isGiList); + if(match && isGiList) gi_in_use_this_gi = gi; - ITERATE(list, iter_gi, use_this_gi){ - if(gi == *iter_gi){ - gi_in_use_this_gi = *iter_gi; - break; - } - } - if(use_this_gi.empty() || gi_in_use_this_gi > ZERO_GI) { + if(use_this_seqid.empty() || match) { firstGi = (firstGi == ZERO_GI) ? gi_in_use_this_gi : firstGi; alnDispParams = new SAlnDispParams(); alnDispParams->gi = gi; @@ -2277,7 +2199,7 @@ CDisplaySeqalign::x_PrintDefLine(const CBioseq_Handle& bsp_handle,SAlnInfo* aln_ value_set = true; } #endif /* CTOOLKIT_COMPATIBLE */ - + if(bsp_handle){ const CRef wid = FindBestChoice(bsp_handle.GetBioseqCore()->GetId(), @@ -2314,7 +2236,7 @@ CDisplaySeqalign::x_PrintDefLine(const CBioseq_Handle& bsp_handle,SAlnInfo* aln_ } if(m_AlignOption&eShowGi && alnDispParams->gi > ZERO_GI && - !alnDispParams->seqID->IsGi()){ + !alnDispParams->seqID->IsGi()){ out<<"gi|"<gi<<"|"; } if(!((alnDispParams->seqID->AsFastaString().find("gnl|BL_ORD_ID") != string::npos) || @@ -2353,12 +2275,12 @@ CDisplaySeqalign::x_PrintDefLine(const CBioseq_Handle& bsp_handle,SAlnInfo* aln_ //print each defline bool bMultipleDeflines = false; int numBdl = 0; - int maxNumBdl = (aln_vec_info->use_this_gi.empty()) ? bdl.size() : aln_vec_info->use_this_gi.size(); + int maxNumBdl = (aln_vec_info->use_this_seqid.empty()) ? bdl.size() : aln_vec_info->use_this_seqid.size(); for(list< CRef< CBlast_def_line > >::const_iterator iter = bdl.begin(); iter != bdl.end(); iter++){ SAlnDispParams *alnDispParams = x_FillAlnDispParams(*iter, bsp_handle, - aln_vec_info->use_this_gi, + aln_vec_info->use_this_seqid, firstGi); @@ -3749,7 +3671,7 @@ CDisplaySeqalign::x_InitDefLinesHeader(const CBioseq_Handle& bsp_handle,SAlnInfo string deflines; string firstDefline; CNcbiEnvironment env; - list& use_this_gi = aln_vec_info->use_this_gi; + list& use_this_seqid = aln_vec_info->use_this_seqid; if(bsp_handle){ const CRef bdlRef = CSeqDB::ExtractBlastDefline(bsp_handle); const list< CRef< CBlast_def_line > > &bdl = (bdlRef.Empty()) ? list< CRef< CBlast_def_line > >() : bdlRef->Get(); @@ -3766,8 +3688,8 @@ CDisplaySeqalign::x_InitDefLinesHeader(const CBioseq_Handle& bsp_handle,SAlnInfo alnDispParams = x_FillAlnDispParams(bsp_handle); string alnDefLine = x_MapDefLine(alnDispParams,isFirst,false,false,seqLength); m_CurrAlnID_Lbl = (alnDispParams->gi != ZERO_GI) ? - NStr::NumericToString(alnDispParams->gi) : alnDispParams->label; - if (m_UseLongSeqIds) { + NStr::NumericToString(alnDispParams->gi) : alnDispParams->label; + if (m_UseLongSeqIds || alnDispParams->seqID->IsLocal()) { m_CurrAlnAccession = alnDispParams->seqID->AsFastaString(); } else { @@ -3785,15 +3707,15 @@ CDisplaySeqalign::x_InitDefLinesHeader(const CBioseq_Handle& bsp_handle,SAlnInfo int numBdl = 0; for(list< CRef< CBlast_def_line > >::const_iterator iter = bdl.begin(); iter != bdl.end(); iter++){ - alnDispParams = x_FillAlnDispParams(*iter,bsp_handle,use_this_gi,firstGi); + alnDispParams = x_FillAlnDispParams(*iter,bsp_handle,use_this_seqid,firstGi); if(alnDispParams) { numBdl++; bool hideDefline = (numBdl > 1)? true : false; string alnDefLine = x_MapDefLine(alnDispParams,isFirst,m_AlignOption&eLinkout,hideDefline,seqLength); if(isFirst){ const CSeq_id& aln_id = m_AV->GetSeqId(1); - TGi alnGi; - CRef dispId = CAlignFormatUtil::GetDisplayIds(bsp_handle,aln_id,use_this_gi,alnGi); + TGi alnGi; + CRef dispId = CAlignFormatUtil::GetDisplayIds(bsp_handle,aln_id,use_this_seqid,&alnGi); m_CurrAlnID_Lbl = (alnGi == ZERO_GI) ? CAlignFormatUtil::GetLabel(dispId) : NStr::NumericToString(alnGi); if(alnGi == ZERO_GI) { dispId->GetLabel(&m_CurrAlnID_DbLbl, CSeq_id::eContent); @@ -4773,7 +4695,7 @@ void CDisplaySeqalign::DisplayPairwiseSeqalign(CNcbiOstream& out,unordered_set < alnvecInfo->evalue, alnvecInfo->sum_n, num_ident, - alnvecInfo->use_this_gi, + alnvecInfo->use_this_seqid, alnvecInfo->comp_adj_method); alnvecInfo->alnvec = avRef; diff --git a/c++/src/objtools/align_format/showdefline.cpp b/c++/src/objtools/align_format/showdefline.cpp index fad406c3..ad2b6f69 100644 --- a/c++/src/objtools/align_format/showdefline.cpp +++ b/c++/src/objtools/align_format/showdefline.cpp @@ -1,4 +1,4 @@ -/* $Id: showdefline.cpp 517104 2016-10-20 17:33:21Z ivanov $ +/* $Id: showdefline.cpp 529376 2017-03-03 16:10:21Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -280,9 +280,61 @@ static void s_LimitDescrLength(string &descr) } +void CShowBlastDefline::x_InitLinkOutInfo(SDeflineInfo* sdl, + CBioseq::TId& cur_id, + int blast_rank, + bool getIdentProteins) +{ + string linkout_list; + TGi cur_gi = FindGi(cur_id); + sdl->linkout = m_LinkoutDB ? m_LinkoutDB->GetLinkout(cur_gi,m_MapViewerBuildName) : 0; + if(m_LinkoutOrder.empty()) { + m_ConfigFile.reset(new CNcbiIfstream(".ncbirc")); + m_Reg.reset(new CNcbiRegistry(*m_ConfigFile)); + if(!m_BlastType.empty()) m_LinkoutOrder = m_Reg->Get(m_BlastType,"LINKOUT_ORDER"); + m_LinkoutOrder = (!m_LinkoutOrder.empty()) ? m_LinkoutOrder : kLinkoutOrderStr; + } + if (m_DeflineTemplates == NULL || !m_DeflineTemplates->advancedView) { + if(m_Option & eRealtedInfoLinks){ + string user_url = m_Reg.get() ? m_Reg->Get(m_BlastType, "TOOL_URL") : kEmptyStr; + sdl->linkout_list = CAlignFormatUtil::GetFullLinkoutUrl(cur_id, + m_Rid, + m_CddRid, + m_EntrezTerm, + m_IsDbNa, + false, + true, + blast_rank, + m_LinkoutOrder, + sdl->taxid, + m_Database, + m_QueryNumber, + user_url, + m_PreComputedResID, + m_LinkoutDB, + m_MapViewerBuildName, + getIdentProteins); + } + else { + sdl->linkout_list = CAlignFormatUtil::GetLinkoutUrl(sdl->linkout, + cur_id, + m_Rid, + m_CddRid, + m_EntrezTerm, + m_IsDbNa, + ZERO_GI, + true, + false, + blast_rank, + m_PreComputedResID); + } + } +} + + void CShowBlastDefline::x_FillDeflineAndId(const CBioseq_Handle& handle, const CSeq_id& aln_id, - list& use_this_gi, + list &use_this_seqid, SDeflineInfo* sdl, int blast_rank) { @@ -325,49 +377,27 @@ void CShowBlastDefline::x_FillDeflineAndId(const CBioseq_Handle& handle, } } //get id (sdl->id, sdl-gi) - sdl->id = CAlignFormatUtil::GetDisplayIds(handle,aln_id,use_this_gi,sdl->gi,sdl->taxid); + sdl->id = CAlignFormatUtil::GetDisplayIds(handle,aln_id,use_this_seqid,&sdl->gi,&sdl->taxid,&sdl->textSeqID); sdl->alnIDFasta = aln_id.AsFastaString(); - //get linkout + //get linkout**** if((m_Option & eLinkout)){ bool linkout_not_found = true; + bool getIdentProteins = !m_IsDbNa && bdl.size() > 1; for(list< CRef< CBlast_def_line > >::const_iterator iter = bdl.begin(); iter != bdl.end(); iter++){ - const CBioseq::TId& cur_id = (*iter)->GetSeqid(); + CBioseq::TId& cur_id = (CBioseq::TId &)(*iter)->GetSeqid(); TGi cur_gi = FindGi(cur_id); - if(use_this_gi.empty()){ - if(sdl->gi == cur_gi){ - sdl->linkout = m_LinkoutDB - ? m_LinkoutDB->GetLinkout(cur_gi,m_MapViewerBuildName) - : 0; - if (m_DeflineTemplates == NULL || !m_DeflineTemplates->advancedView) - sdl->linkout_list = - CAlignFormatUtil::GetLinkoutUrl(sdl->linkout, - cur_id, m_Rid, - m_CddRid, - m_EntrezTerm, - handle.GetBioseqCore()->IsNa(), - ZERO_GI, true, false, - blast_rank,m_PreComputedResID); - + if(use_this_seqid.empty()){ + if(sdl->gi == cur_gi){ + x_InitLinkOutInfo(sdl,cur_id,blast_rank,getIdentProteins); break; } - } else { + } else if (CAlignFormatUtil::IsGiList(use_this_seqid)) { + list use_this_gi = CAlignFormatUtil::StringGiToNumGiList(use_this_seqid); ITERATE(list, iter_gi, use_this_gi){ - if(cur_gi == *iter_gi){ - sdl->linkout = m_LinkoutDB - ? - m_LinkoutDB->GetLinkout(cur_gi,m_MapViewerBuildName) - : 0; - if (m_DeflineTemplates == NULL || !m_DeflineTemplates->advancedView) - sdl->linkout_list = - CAlignFormatUtil::GetLinkoutUrl(sdl->linkout, - cur_id, m_Rid, - m_CddRid, - m_EntrezTerm, - handle.GetBioseqCore()->IsNa(), - ZERO_GI, true, false, - blast_rank,m_PreComputedResID); + if(cur_gi == *iter_gi){ + x_InitLinkOutInfo(sdl,cur_id,blast_rank,getIdentProteins); linkout_not_found = false; break; } @@ -424,14 +454,9 @@ void CShowBlastDefline::x_FillDeflineAndId(const CBioseq_Handle& handle, iter != bdl.end(); iter++){ const CBioseq::TId& cur_id = (*iter)->GetSeqid(); TGi cur_gi = FindGi(cur_id); - TGi gi_in_use_this_gi = ZERO_GI; - ITERATE(list, iter_gi, use_this_gi){ - if(cur_gi == *iter_gi){ - gi_in_use_this_gi = *iter_gi; - break; - } - } - if(use_this_gi.empty() || gi_in_use_this_gi > ZERO_GI) { + wid = FindBestChoice(cur_id, CSeq_id::WorstRank); + bool match = CAlignFormatUtil::MatchSeqInSeqList(cur_gi, wid, use_this_seqid); + if(use_this_seqid.empty() || match) { if((*iter)->IsSetTitle()){ bool id_used_already = false; @@ -694,7 +719,7 @@ void CShowBlastDefline::x_DisplayDefline(CNcbiOstream & out) bool first_new =true; ITERATE(vector, iter, m_ScoreList){ - SDeflineInfo* sdl = x_GetDeflineInfo((*iter)->id, (*iter)->use_this_gi, (*iter)->blast_rank); + SDeflineInfo* sdl = x_GetDeflineInfo((*iter)->id, (*iter)->use_this_seqid, (*iter)->blast_rank); size_t line_length = 0; string line_component; if ((m_Option & eHtml) && (sdl->gi > ZERO_GI)){ @@ -731,7 +756,7 @@ void CShowBlastDefline::x_DisplayDefline(CNcbiOstream & out) if((m_Option & eHtml) && (sdl->id_url != NcbiEmptyString)) { out << sdl->id_url; } - if((m_Option & eShowGi) && !sdl->id->IsGi()){ + if(m_Option & eShowGi){ if(sdl->gi > ZERO_GI){ line_component = "gi|" + NStr::NumericToString(sdl->gi) + "|"; out << line_component; @@ -742,10 +767,7 @@ void CShowBlastDefline::x_DisplayDefline(CNcbiOstream & out) if(!(sdl->id->AsFastaString().find("gnl|BL_ORD_ID") != string::npos || sdl->id->AsFastaString().find("lcl|Subject_") != string::npos)){ string idStr; - if (use_long_seqids || - // use long sequence ids if more than one id is printed - ((m_Option & eShowGi) && sdl->gi > ZERO_GI)) { - + if (use_long_seqids || ((m_Option & eShowGi) && !sdl->id->IsGi())) { idStr = sdl->id->AsFastaString(); } else { @@ -1077,7 +1099,7 @@ void CShowBlastDefline::x_DisplayDeflineTableBody(CNcbiOstream & out) query_buf); } ITERATE(vector, iter, m_ScoreList){ - SDeflineInfo* sdl = x_GetDeflineInfo((*iter)->id, (*iter)->use_this_gi, (*iter)->blast_rank); + SDeflineInfo* sdl = x_GetDeflineInfo((*iter)->id, (*iter)->use_this_seqid, (*iter)->blast_rank); size_t line_length = 0; string line_component; cur_database_type = (sdl->linkout & eGenomicSeq); @@ -1309,13 +1331,12 @@ CShowBlastDefline::x_GetScoreInfo(const CSeq_align& aln, int blast_rank) double bits = 0; double evalue = 0; int sum_n = 0; - int num_ident = 0; - list use_this_gi; - - use_this_gi.clear(); + int num_ident = 0; + list use_this_seq; + use_this_seq.clear(); CAlignFormatUtil::GetAlnScores(aln, score, bits, evalue, sum_n, - num_ident, use_this_gi); + num_ident, use_this_seq); CAlignFormatUtil::GetScoreString(evalue, bits, 0, score, evalue_buf, bit_score_buf, total_bit_score_buf, @@ -1325,7 +1346,7 @@ CShowBlastDefline::x_GetScoreInfo(const CSeq_align& aln, int blast_rank) score_info->sum_n = sum_n == -1 ? 1:sum_n ; score_info->id = &(aln.GetSeq_id(1)); - score_info->use_this_gi = use_this_gi; + score_info->use_this_seqid = use_this_seq; score_info->bit_string = bit_score_buf; score_info->raw_score_string = raw_score_buf; @@ -1365,8 +1386,7 @@ CShowBlastDefline::x_GetScoreInfoForTable(const CSeq_align_set& aln, int blast_r score_info->hspNum = seqSetInfo->hspNum; score_info->totalLen = seqSetInfo->totalLen; - - score_info->use_this_gi = seqSetInfo->use_this_gi; + score_info->use_this_seqid = seqSetInfo->use_this_seq; score_info->sum_n = seqSetInfo->sum_n == -1 ? 1:seqSetInfo->sum_n ; score_info->raw_score_string = raw_score_buf;//check if used @@ -1388,8 +1408,8 @@ CShowBlastDefline::GetDeflineInfo(vector< CConstRef > &seqIds) { vector sdlVec; for(size_t i = 0; i < seqIds.size(); i++) { - list use_this_gi; - CShowBlastDefline::SDeflineInfo* sdl = x_GetDeflineInfo(seqIds[i], use_this_gi, i + 1 ); + list use_this_seq; + CShowBlastDefline::SDeflineInfo* sdl = x_GetDeflineInfo(seqIds[i], use_this_seq, i + 1 ); sdlVec.push_back(sdl); } return sdlVec; @@ -1398,7 +1418,7 @@ CShowBlastDefline::GetDeflineInfo(vector< CConstRef > &seqIds) CShowBlastDefline::SDeflineInfo* -CShowBlastDefline::x_GetDeflineInfo(CConstRef id, list& use_this_gi, int blast_rank) +CShowBlastDefline::x_GetDeflineInfo(CConstRef id, list &use_this_seqid, int blast_rank) { SDeflineInfo* sdl = NULL; sdl = new SDeflineInfo; @@ -1406,7 +1426,7 @@ CShowBlastDefline::x_GetDeflineInfo(CConstRef id, list& use_this_g sdl->defline = "Unknown"; try{ const CBioseq_Handle& handle = m_ScopeRef->GetBioseqHandle(*id); - x_FillDeflineAndId(handle, *id, use_this_gi, sdl, blast_rank); + x_FillDeflineAndId(handle, *id, use_this_seqid, sdl, blast_rank); } catch (const CException&){ sdl->defline = "Unknown"; sdl->is_new = false; @@ -1447,7 +1467,7 @@ void CShowBlastDefline::x_DisplayDeflineTableTemplate(CNcbiOstream & out) string rowType = "odd"; string subHeaderID; ITERATE(vector, iter, m_ScoreList){ - SDeflineInfo* sdl = x_GetDeflineInfo((*iter)->id, (*iter)->use_this_gi, (*iter)->blast_rank); + SDeflineInfo* sdl = x_GetDeflineInfo((*iter)->id, (*iter)->use_this_seqid, (*iter)->blast_rank); cur_database_type = (sdl->linkout & eGenomicSeq); string subHeader; bool formatHeaderSort = !is_first && (prev_database_type != cur_database_type); diff --git a/c++/src/objtools/align_format/tabular.cpp b/c++/src/objtools/align_format/tabular.cpp index 5bdb42c7..243f9952 100644 --- a/c++/src/objtools/align_format/tabular.cpp +++ b/c++/src/objtools/align_format/tabular.cpp @@ -1,4 +1,4 @@ -/* $Id: tabular.cpp 518048 2016-10-31 14:59:16Z ivanov $ +/* $Id: tabular.cpp 532684 2017-04-07 16:01:51Z jianye $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1706,7 +1706,7 @@ void CIgBlastTabularInfo::PrintMasterAlign(const string &header) const m_ChainType == "VB") m_Ostream << "Top D gene match, "; m_Ostream << "Top J gene match, Chain type, stop codon, "; m_Ostream << "V-J frame, Productive, Strand). "; - m_Ostream <<"Multiple equivalent top matches having the same score and percent identity, if present, are separated by a comma." << endl; + m_Ostream <<"Multiple equivalent top matches, if present, are separated by a comma." << endl; m_Ostream << m_VGene.sid << m_FieldDelimiter; if (m_ChainType == "VH"|| m_ChainType == "VD" || m_ChainType == "VB") m_Ostream << m_DGene.sid << m_FieldDelimiter; @@ -1764,7 +1764,7 @@ void CIgBlastTabularInfo::PrintHtmlSummary() const << "of a V gene and has been converted to the plus strand. " << "The sequence positions refer to the converted sequence.\n\n"; } - m_Ostream << "
    V-(D)-J rearrangement summary for query sequence (multiple equivalent top matches having the same score \nand percent identity, if present, are separated by a comma):\n"; + m_Ostream << "
    V-(D)-J rearrangement summary for query sequence (multiple equivalent top matches, if present, are separated by a comma):\n"; m_Ostream << "\n"; m_Ostream << ""; if (m_ChainType == "VH" || m_ChainType == "VD" || @@ -1970,8 +1970,10 @@ void CIgBlastTabularInfo::x_PrintIgGenes(bool isHtml, const string& header) cons m_Ostream << "
    Top V gene match
    \n"; m_Ostream << ""; m_Ostream << ""; + m_Ostream << ""; + m_Ostream << ""; } else { - m_Ostream << header << "Sub-region sequence details (nucleotide sequence, translation)" << endl; + m_Ostream << header << "Sub-region sequence details (nucleotide sequence, translation, start, end)" << endl; } if (isHtml) { m_Ostream << "\n
    Nucleotide sequenceTranslationStartEnd
    CDR3"; @@ -1982,10 +1984,20 @@ void CIgBlastTabularInfo::x_PrintIgGenes(bool isHtml, const string& header) cons if (isHtml) { m_Ostream << ""; } - m_Ostream << m_Cdr3SeqTrans; + m_Ostream << m_Cdr3SeqTrans << m_FieldDelimiter; + if (isHtml) { + m_Ostream << ""; + } + m_Ostream << m_Cdr3Start + 1 << m_FieldDelimiter; + if (isHtml) { + m_Ostream << ""; + } + m_Ostream << m_Cdr3End + 1 << m_FieldDelimiter; + if (isHtml) { m_Ostream << "
    "; } + m_Ostream << endl << endl; } diff --git a/c++/src/objtools/align_format/taxFormat.cpp b/c++/src/objtools/align_format/taxFormat.cpp index 4e9e6830..47ffc3c4 100644 --- a/c++/src/objtools/align_format/taxFormat.cpp +++ b/c++/src/objtools/align_format/taxFormat.cpp @@ -1,4 +1,4 @@ -/* $Id: taxFormat.cpp 504856 2016-06-20 15:36:19Z zaretska $ +/* $Id: taxFormat.cpp 528166 2017-02-21 15:46:12Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -646,7 +646,15 @@ void CTaxFormat::x_InitBlastNameTaxInfo(STaxInfo &taxInfo) if(m_TaxClient && m_TaxClient->IsAlive()) { m_TaxClient->GetBlastName(taxInfo.taxid,taxInfo.blastName); - taxInfo.blNameTaxid = m_TaxClient->SearchTaxIdByName(taxInfo.blastName,CTaxon1::eSearch_Exact); + list< CRef< CTaxon1_name > > nameList; + taxInfo.blNameTaxid = m_TaxClient->SearchTaxIdByName(taxInfo.blastName,CTaxon1::eSearch_Exact,&nameList); + if(taxInfo.blNameTaxid == -1) //more than one name in the list + ITERATE(list < CRef< CTaxon1_name > >, iter, nameList) { + ncbi::TIntId blastNameCde = m_TaxClient->GetNameClassId("blast name"); + if((*iter)->CanGetTaxid() && (*iter)->IsSetCde() && (*iter)->GetCde() == blastNameCde) { + taxInfo.blNameTaxid = (*iter)->GetTaxid(); + } + } } } @@ -811,22 +819,17 @@ CTaxFormat::SSeqInfo *CTaxFormat::x_FillTaxDispParams(const CRef< CBlast_def_lin const CBioseq_Handle& bsp_handle, double bits, double evalue, - list& use_this_gi) + list& use_this_seqid) { SSeqInfo *seqInfo = NULL; const list > ids = bdl->GetSeqid(); - TGi gi = CAlignFormatUtil::GetGiForSeqIdList(ids); - TGi gi_in_use_this_gi = ZERO_GI; - - ITERATE(list, iter_gi, use_this_gi){ - if(gi == *iter_gi){ - gi_in_use_this_gi = *iter_gi; - break; - } - } - if(use_this_gi.empty() || gi_in_use_this_gi > ZERO_GI) { + TGi gi = CAlignFormatUtil::GetGiForSeqIdList(ids); + CRef wid = FindBestChoice(ids, CSeq_id::WorstRank); + bool match = CAlignFormatUtil::MatchSeqInSeqList(gi, wid, use_this_seqid); + + if(use_this_seqid.empty() || match) { seqInfo = new SSeqInfo(); seqInfo->gi = gi; @@ -860,7 +863,7 @@ void CTaxFormat::x_InitTaxInfoMap(void) { int score, sum_n, num_ident; double bits, evalue; - list use_this_gi; + list use_this_seqid; m_BlastResTaxInfo = new SBlastResTaxInfo; CConstRef previousId,subid; @@ -871,7 +874,7 @@ void CTaxFormat::x_InitTaxInfoMap(void) if(!previousId.Empty() && subid->Match(*previousId)) continue; CAlignFormatUtil::GetAlnScores(**iter, score, bits, evalue, - sum_n, num_ident, use_this_gi); + sum_n, num_ident, use_this_seqid); try { const CBioseq_Handle& handle = m_Scope.GetBioseqHandle(*subid); if( !handle ) continue; @@ -883,10 +886,10 @@ void CTaxFormat::x_InitTaxInfoMap(void) TGi dispGI = ZERO_GI; for(list< CRef< CBlast_def_line > >::const_iterator iter = bdl.begin(); iter != bdl.end(); iter++){ - SSeqInfo *seqInfo = x_FillTaxDispParams(*iter,handle,bits,evalue,use_this_gi); + SSeqInfo *seqInfo = x_FillTaxDispParams(*iter,handle,bits,evalue,use_this_seqid); if(seqInfo) { if(dispGI == ZERO_GI){ - dispGI = CAlignFormatUtil::GetDisplayIds(bdl,*seqInfo->seqID,use_this_gi); + CAlignFormatUtil::GetDisplayIds(handle,*seqInfo->seqID,use_this_seqid,&dispGI); } seqInfo->displGi = dispGI; x_InitBlastDBTaxInfo(seqInfo); diff --git a/c++/src/objtools/align_format/unit_test/CMakeLists.align_format_unit_test.app.txt b/c++/src/objtools/align_format/unit_test/CMakeLists.align_format_unit_test.app.txt new file mode 100644 index 00000000..5db23913 --- /dev/null +++ b/c++/src/objtools/align_format/unit_test/CMakeLists.align_format_unit_test.app.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/align_format/unit_test/Makefile.align_format_unit_test.app +# +add_executable(align_format_unit_test-app + showdefline_unit_test showalign_unit_test blast_test_util + vectorscreen_unit_test tabularinof_unit_test aln_printer_unit_test +) + +set_target_properties(align_format_unit_test-app PROPERTIES OUTPUT_NAME align_format_unit_test) + + + +target_link_libraries(align_format_unit_test-app + align_format ncbi_xloader_blastdb_rmt test_boost +) + diff --git a/c++/src/objtools/align_format/unit_test/CMakeLists.txt b/c++/src/objtools/align_format/unit_test/CMakeLists.txt new file mode 100644 index 00000000..a60109e5 --- /dev/null +++ b/c++/src/objtools/align_format/unit_test/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +include_directories(SYSTEM ${BOOST_INCLUDE}) + +# Include projects from this directory +include(CMakeLists.align_format_unit_test.app.txt) + diff --git a/c++/src/objtools/align_format/unit_test/aln_printer_unit_test.cpp b/c++/src/objtools/align_format/unit_test/aln_printer_unit_test.cpp index be79491b..ff84ddad 100644 --- a/c++/src/objtools/align_format/unit_test/aln_printer_unit_test.cpp +++ b/c++/src/objtools/align_format/unit_test/aln_printer_unit_test.cpp @@ -1,4 +1,4 @@ -/* $Id: aln_printer_unit_test.cpp 482778 2015-10-26 18:45:59Z boratyng $ +/* $Id: aln_printer_unit_test.cpp 545961 2017-09-12 17:22:13Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -65,6 +65,9 @@ public: CRef m_Scope; string kNuclSeqs; string kProtSeqs; + // input file names + string kProtein_seqalign; + string kNucleotide_seqalign; void x_InitScope(void) { @@ -99,15 +102,23 @@ public: } } + void x_Init(bool isNuc) + { + string seqInputData = (isNuc) ? kNuclSeqs : kProtSeqs; + bool parse_id = (isNuc) ? false : true; + + + x_LoadSequences(seqInputData, parse_id); + } CAlnPrinterFixture(void) { kNuclSeqs = "data/nucleotide.fa"; kProtSeqs = "data/protein.fa"; - + kNucleotide_seqalign = "data/multialign_nucleotide.asn"; + kProtein_seqalign = "data/multialign.asn"; + x_InitScope(); - x_LoadSequences(kNuclSeqs, false); - x_LoadSequences(kProtSeqs, true); } @@ -119,10 +130,13 @@ public: // Print alignment for a given Seq-align string PrintAlignment(CMultiAlnPrinter::EFormat format, - const string& seqalign_file, + bool isNuc, CMultiAlnPrinter::EAlignType type = CMultiAlnPrinter::eNotSet) { + x_Init(isNuc); + string seqalign_file = (isNuc) ? kNucleotide_seqalign : kProtein_seqalign; + CSeq_align seqalign; CNcbiIfstream istr(seqalign_file.c_str()); istr >> MSerial_AsnText >> seqalign; @@ -134,7 +148,7 @@ public: CNcbiOstrstream output_stream; printer.Print(output_stream); string output = CNcbiOstrstreamToString(output_stream); - + m_Scope->GetObjectManager().RevokeAllDataLoaders(); return output; } @@ -143,15 +157,15 @@ public: BOOST_FIXTURE_TEST_SUITE(aln_printer, CAlnPrinterFixture) // input file names -const string protein_seqalign = "data/multialign.asn"; -const string nucleotide_seqalign = "data/multialign_nucleotide.asn"; +//const string protein_seqalign = "data/multialign.asn"; +//const string nucleotide_seqalign = "data/multialign_nucleotide.asn"; BOOST_AUTO_TEST_CASE(TestFastaPlusGaps) { // Test protein string output = PrintAlignment(CMultiAlnPrinter::eFastaPlusGaps, - protein_seqalign); + false); BOOST_REQUIRE(output.find(">gi|129295|sp|P01013.1|OVALX_CHICK RecName: " "Full=Ovalbumin-related protein X; AltName: " @@ -165,7 +179,7 @@ BOOST_AUTO_TEST_CASE(TestFastaPlusGaps) // Test nucleotide output = PrintAlignment(CMultiAlnPrinter::eFastaPlusGaps, - nucleotide_seqalign); + true); BOOST_REQUIRE(output.find(">lcl|1 gi|405832|gb|U00001.1|HSCDC27 Human " "homologue of S. pombe nuc2+ and A. nidulans " @@ -184,7 +198,7 @@ BOOST_AUTO_TEST_CASE(TestClustalW) { // Test protein string output = PrintAlignment(CMultiAlnPrinter::eClustal, - protein_seqalign); + false); BOOST_REQUIRE(output.find("gi|189500654 M----------------" "------------------------RII-IYNR---------------" @@ -199,7 +213,7 @@ BOOST_AUTO_TEST_CASE(TestClustalW) // Test nucleotide output = PrintAlignment(CMultiAlnPrinter::eClustal, - nucleotide_seqalign); + true); BOOST_REQUIRE(output.find("lcl|2 ------CCGCTACAGG" "GGGGGCCTGAGGCACTGCAGAAAGTGGGCCTGAGCCTCGAGGATGA" @@ -219,7 +233,7 @@ BOOST_AUTO_TEST_CASE(TestPhylipSequential) { // Test protein string output = PrintAlignment(CMultiAlnPrinter::ePhylipSequential, - protein_seqalign); + false); BOOST_REQUIRE(output.find(" 100 749") != NPOS); @@ -234,7 +248,7 @@ BOOST_AUTO_TEST_CASE(TestPhylipSequential) // Test nucleotide output = PrintAlignment(CMultiAlnPrinter::ePhylipSequential, - nucleotide_seqalign); + true); BOOST_REQUIRE(output.find(" 10 2634") != NPOS); @@ -251,7 +265,7 @@ BOOST_AUTO_TEST_CASE(TestPhylipInterleaved) { // Test protein string output = PrintAlignment(CMultiAlnPrinter::ePhylipInterleaved, - protein_seqalign); + false); BOOST_REQUIRE(output.find(" 100 749") != NPOS); @@ -268,7 +282,7 @@ BOOST_AUTO_TEST_CASE(TestPhylipInterleaved) // Test nucleotide output = PrintAlignment(CMultiAlnPrinter::ePhylipInterleaved, - nucleotide_seqalign); + true); BOOST_REQUIRE(output.find(" 10 2634") != NPOS); @@ -285,7 +299,7 @@ BOOST_AUTO_TEST_CASE(TestNexus) { // Test protein string output = PrintAlignment(CMultiAlnPrinter::eNexus, - protein_seqalign, + false, CMultiAlnPrinter::eProtein); BOOST_REQUIRE(output.find("#NEXUS") != NPOS); @@ -317,7 +331,7 @@ BOOST_AUTO_TEST_CASE(TestNexus) // Test nucleotide output = PrintAlignment(CMultiAlnPrinter::eNexus, - nucleotide_seqalign, + true, CMultiAlnPrinter::eNucleotide); BOOST_REQUIRE(output.find("#NEXUS") != NPOS); @@ -347,7 +361,7 @@ BOOST_AUTO_TEST_CASE(TestRejectNexusWithNoAlignType) // verify that formatting nexus alignment with m_AlignType == eNotSet // throws the exception BOOST_REQUIRE_THROW(PrintAlignment(CMultiAlnPrinter::eNexus, - protein_seqalign, + false, CMultiAlnPrinter::eNotSet), CException); } diff --git a/c++/src/objtools/align_format/unit_test/showalign_unit_test.cpp b/c++/src/objtools/align_format/unit_test/showalign_unit_test.cpp index 91e81154..77b4275b 100644 --- a/c++/src/objtools/align_format/unit_test/showalign_unit_test.cpp +++ b/c++/src/objtools/align_format/unit_test/showalign_unit_test.cpp @@ -1,4 +1,4 @@ -/* $Id: showalign_unit_test.cpp 520429 2016-11-28 18:25:40Z ivanov $ +/* $Id: showalign_unit_test.cpp 545961 2017-09-12 17:22:13Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -72,6 +72,7 @@ BOOST_AUTO_TEST_CASE(TestPerformance) CDisplaySeqalign ds(*fileSeqAlignSet, *scope); CNcbiOfstream dumpster("/dev/null"); // we don't care about the output ds.DisplaySeqalign(dumpster); + scope->GetObjectManager().RevokeAllDataLoaders(); } #ifdef _DEBUG const int kPerformanceTimeout = 120; @@ -111,6 +112,7 @@ BOOST_AUTO_TEST_CASE(TestTGIConversion) BOOST_REQUIRE(output.find("gi|212900") != NPOS); BOOST_REQUIRE(output.find("gi|385145537") != NPOS); BOOST_REQUIRE(output.find("gi|385145539") != NPOS); + scope->GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(TestTGIConversionExt) @@ -146,6 +148,7 @@ BOOST_AUTO_TEST_CASE(TestTGIConversionExt) BOOST_REQUIRE(output.find("gi|385145539") != NPOS); BOOST_REQUIRE(output.find("gi|129296") != NPOS); BOOST_REQUIRE(output.find("gi|71897377") != NPOS); + scope->GetObjectManager().RevokeAllDataLoaders(); } bool TestSimpleAlignment(CBlastOM::ELocation location, bool long_seqids) @@ -192,9 +195,9 @@ bool TestSimpleAlignment(CBlastOM::ELocation location, bool long_seqids) BOOST_REQUIRE(output.find("Length=11852") != NPOS); BOOST_REQUIRE(output.find("Query 5636 GTAGG-CAGGATAAGGCGTTCACGCCGCATCCGGCA 5670") != NPOS); BOOST_REQUIRE(output.find(" Score = 54.7 bits (29), Expect = 2e-0") - != NPOS); + != NPOS); }} - tmp_data_loader.RevokeBlastDbDataLoader(); + tmp_data_loader.RevokeBlastDbDataLoader(); return true; } diff --git a/c++/src/objtools/align_format/unit_test/showdefline_unit_test.cpp b/c++/src/objtools/align_format/unit_test/showdefline_unit_test.cpp index db7a0850..a70749f9 100644 --- a/c++/src/objtools/align_format/unit_test/showdefline_unit_test.cpp +++ b/c++/src/objtools/align_format/unit_test/showdefline_unit_test.cpp @@ -1,4 +1,4 @@ -/* $Id: showdefline_unit_test.cpp 507726 2016-07-21 14:42:04Z grichenk $ +/* $Id: showdefline_unit_test.cpp 545961 2017-09-12 17:22:13Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -102,13 +102,14 @@ struct CShowBlastDeflineTest : public CShowBlastDefline { auto_ptr si(sbd.x_GetScoreInfo(**iter, 1)); auto_ptr - dl(sbd.x_GetDeflineInfo(si->id, si->use_this_gi, 1)); + dl(sbd.x_GetDeflineInfo(si->id, si->use_this_seqid, 1)); CShowBlastDeflineTest::TestData(dl.get(), si.get(), i); i++; if (i > 1) { break; } - } + } + scope->GetObjectManager().RevokeAllDataLoaders(); } static void TestData(CShowBlastDefline::SDeflineInfo* dl, diff --git a/c++/src/objtools/align_format/unit_test/tabularinof_unit_test.cpp b/c++/src/objtools/align_format/unit_test/tabularinof_unit_test.cpp index 4d101b96..541390e4 100644 --- a/c++/src/objtools/align_format/unit_test/tabularinof_unit_test.cpp +++ b/c++/src/objtools/align_format/unit_test/tabularinof_unit_test.cpp @@ -1,4 +1,4 @@ -/* $Id: tabularinof_unit_test.cpp 516292 2016-10-12 14:27:10Z ivanov $ +/* $Id: tabularinof_unit_test.cpp 545961 2017-09-12 17:22:13Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -99,6 +99,7 @@ BOOST_AUTO_TEST_CASE(StandardOutput) { BOOST_REQUIRE(output.find("AE000111.1 AE000111.1 100.000 10596 0 0 1 10596") != NPOS); BOOST_REQUIRE(output.find("AE000111.1 AE000188.1 97.059 34 1 0 5567 5600 1088") != NPOS); BOOST_REQUIRE(output.find("# BLAST processed 1 queries") != NPOS); + scope->GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(QuerySubjectScoreOutput) { @@ -132,6 +133,7 @@ BOOST_AUTO_TEST_CASE(QuerySubjectScoreOutput) { // but some windows binaires print the bit score as 1.957e+004. Hence, we drop the exponent. BOOST_REQUIRE(output.find("gi|1786181|gb|AE000111.1|AE000111 gi|1786181|gb|AE000111.1|AE000111 19568") != NPOS); BOOST_REQUIRE(output.find("gi|1786181|gb|AE000111.1|AE000111 gi|1788899|gb|AE000341.1|AE000341 91.6") != NPOS); + scope->GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(QueryAccSubjectAccIdentScoreOutput) { @@ -166,6 +168,7 @@ BOOST_AUTO_TEST_CASE(QueryAccSubjectAccIdentScoreOutput) { BOOST_REQUIRE(output.find("AE000111 AE000111 100.000 19568") != NPOS); BOOST_REQUIRE(output.find("AE000111 AE000310 94.595 56.5") != NPOS); BOOST_REQUIRE(output.find("AE000111 AE000509 80.508 76.8") != NPOS); + scope->GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(QueryAccSubjectAccIdentBTOPOutput) { @@ -199,6 +202,7 @@ BOOST_AUTO_TEST_CASE(QueryAccSubjectAccIdentBTOPOutput) { BOOST_REQUIRE(output.find("AE000111 AE000447 57 89.412 15T-TA2TA2-T6AG8CT1GT4CA10AC28") != NPOS); BOOST_REQUIRE(output.find("AE000111 AE000116 48 98.039 12GA38") != NPOS); BOOST_REQUIRE(output.find("AE000111 AE000183 36 82.022 14G-TATGAG2-A3-G4-C1A-4-AGA3C-6CATATC7C-1-C28") != NPOS); + scope->GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(TaxonomyOutput) { @@ -264,6 +268,7 @@ BOOST_AUTO_TEST_CASE(TaxonomyOutput) { } } } + scope->GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_CASE(SubjectTitlesOutput) { @@ -342,6 +347,7 @@ BOOST_AUTO_TEST_CASE(SubjectTitlesOutput) { BOOST_REQUIRE_MESSAGE(results[i].find(ref[i]) != NPOS, msg); } } + scope->GetObjectManager().RevokeAllDataLoaders(); } // SB-1177 @@ -377,6 +383,7 @@ BOOST_AUTO_TEST_CASE(ExtractCorrectSeqIdWhenThereIsSourceObjectInDescription) { string output = CNcbiOstrstreamToString(output_stream); BOOST_REQUIRE(NStr::StartsWith(output, "Query_1")); BOOST_REQUIRE(output.find("Macaca") == NPOS); + scope->GetObjectManager().RevokeAllDataLoaders(); } BOOST_AUTO_TEST_SUITE_END() diff --git a/c++/src/objtools/alnmgr/CMakeLists.alnmgr.lib.txt b/c++/src/objtools/alnmgr/CMakeLists.alnmgr.lib.txt new file mode 100644 index 00000000..77c9db54 --- /dev/null +++ b/c++/src/objtools/alnmgr/CMakeLists.alnmgr.lib.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/alnmgr/Makefile.alnmgr.lib +# +add_library(xalnmgr + aln_builders aln_converters aln_generators aln_seqid aln_serial alndiag + alnmap alnmapprint alnmatch alnmerger alnmix alnpos_ci alnsegments + alnseq alnvec alnvec_iterator alnvecprint pairwise_aln sparse_aln + sparse_ci alntext score_builder_base +) +add_dependencies(xalnmgr + seqset +) + +target_link_libraries(xalnmgr + tables xobjutil +) diff --git a/c++/src/objtools/alnmgr/CMakeLists.txt b/c++/src/objtools/alnmgr/CMakeLists.txt new file mode 100644 index 00000000..123f8ce8 --- /dev/null +++ b/c++/src/objtools/alnmgr/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.alnmgr.lib.txt) + +# Recurse subdirectories +add_subdirectory(demo ) +add_subdirectory(unit_test ) diff --git a/c++/src/objtools/alnmgr/Makefile.alnmgr.lib b/c++/src/objtools/alnmgr/Makefile.alnmgr.lib index 15b8d33f..9a8b4c82 100644 --- a/c++/src/objtools/alnmgr/Makefile.alnmgr.lib +++ b/c++/src/objtools/alnmgr/Makefile.alnmgr.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.alnmgr.lib 502200 2016-05-23 14:42:40Z vakatov $ +# $Id: Makefile.alnmgr.lib 536880 2017-05-24 13:40:16Z ucko $ # Build library "xalnmgr" ################################# @@ -10,7 +10,7 @@ SRC = aln_builders aln_converters aln_generators aln_seqid aln_serial \ alnsegments alnseq alnvec alnvec_iterator alnvecprint \ pairwise_aln sparse_aln sparse_ci alntext score_builder_base -DLL_LIB = tables +DLL_LIB = xobjutil tables WATCHERS = grichenk diff --git a/c++/src/objtools/alnmgr/aln_converters.cpp b/c++/src/objtools/alnmgr/aln_converters.cpp index 6c3d6bdd..1bf018a0 100644 --- a/c++/src/objtools/alnmgr/aln_converters.cpp +++ b/c++/src/objtools/alnmgr/aln_converters.cpp @@ -1,4 +1,4 @@ -/* $Id: aln_converters.cpp 415574 2013-10-18 13:21:57Z chetvern $ +/* $Id: aln_converters.cpp 531968 2017-03-30 17:34:38Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -892,7 +892,15 @@ CSeq_id_Handle s_GetBestSynonym(const CSeq_id_Handle& idh, mapper.CollectSynonyms(idh, syn_set); CSeq_id_Handle best_id = idh; int best_score = idh.GetSeqId()->BestRankScore(); +#ifdef _DEBUG + TGi gi = best_id.IsGi() ? best_id.GetGi() : ZERO_GI; +#endif ITERATE(CSeq_loc_Mapper_Base::TSynonyms, it, syn_set) { +#ifdef _DEBUG + if (it->IsGi()) { + gi = it->GetGi(); + } +#endif int score = it->GetSeqId()->BestRankScore(); if (score < best_score) { best_id = *it; @@ -902,6 +910,13 @@ CSeq_id_Handle s_GetBestSynonym(const CSeq_id_Handle& idh, ITERATE(CSeq_loc_Mapper_Base::TSynonyms, it, syn_set) { syn_map[*it] = best_id; } +#ifdef _DEBUG + const CTextseq_id* txt_id = best_id.GetSeqId()->GetTextseq_Id(); + if (txt_id && !txt_id->IsSetVersion() && gi != ZERO_GI) { + ERR_POST("Using version-less accession " << txt_id->GetAccession() + << " instead of GI " << gi); + } +#endif return best_id; } diff --git a/c++/src/objtools/alnmgr/alnmix.cpp b/c++/src/objtools/alnmgr/alnmix.cpp index 16ecf622..728ff9c8 100644 --- a/c++/src/objtools/alnmgr/alnmix.cpp +++ b/c++/src/objtools/alnmgr/alnmix.cpp @@ -1,4 +1,4 @@ -/* $Id: alnmix.cpp 346733 2011-12-09 16:01:27Z ivanov $ +/* $Id: alnmix.cpp 531968 2017-03-30 17:34:38Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -245,10 +245,28 @@ CAlnMix::ChooseSeqId(CSeq_id& id1, const CSeq_id& id2) CRef id1cref(&id1); CRef id2cref(&(const_cast(id2))); if (CSeq_id::BestRank(id1cref) > CSeq_id::BestRank(id2cref)) { +#ifdef _DEBUG + if (id1.IsGi()) { + const CTextseq_id* txt_id = id2.GetTextseq_Id(); + if (txt_id && !txt_id->IsSetVersion()) { + ERR_POST("Using version-less accession " << txt_id->GetAccession() + << " instead of GI " << id1.GetGi()); + } + } +#endif id1.Reset(); SerialAssign(id1, id2); } -} +#ifdef _DEBUG + else if (id2.IsGi()) { + const CTextseq_id* txt_id = id1.GetTextseq_Id(); + if (txt_id && !txt_id->IsSetVersion()) { + ERR_POST("Using version-less accession " << txt_id->GetAccession() + << " instead of GI " << id2.GetGi()); + } + } +#endif +} void diff --git a/c++/src/objtools/alnmgr/alnvec.cpp b/c++/src/objtools/alnmgr/alnvec.cpp index 53e60994..74c48eb5 100644 --- a/c++/src/objtools/alnmgr/alnvec.cpp +++ b/c++/src/objtools/alnmgr/alnvec.cpp @@ -1,4 +1,4 @@ -/* $Id: alnvec.cpp 520514 2016-11-29 16:11:43Z ivanov $ +/* $Id: alnvec.cpp 520399 2016-11-28 16:26:10Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/alnmgr/sparse_aln.cpp b/c++/src/objtools/alnmgr/sparse_aln.cpp index 9b924596..d82fd77a 100644 --- a/c++/src/objtools/alnmgr/sparse_aln.cpp +++ b/c++/src/objtools/alnmgr/sparse_aln.cpp @@ -1,4 +1,4 @@ -/* $Id: sparse_aln.cpp 520514 2016-11-29 16:11:43Z ivanov $ +/* $Id: sparse_aln.cpp 520399 2016-11-28 16:26:10Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -699,7 +699,7 @@ string& CSparseAln::GetAlnSeqString(TNumrow row, ++it; is_first_seg = false; } - if ( translate ) { + if (translate && aln_range.GetLength() >= trim_from + trim_to) { buffer.resize((aln_range.GetLength() - trim_from - trim_to) / 3); } return buffer; diff --git a/c++/src/objtools/alnmgr/sparse_ci.cpp b/c++/src/objtools/alnmgr/sparse_ci.cpp index 849a5c98..7db85751 100644 --- a/c++/src/objtools/alnmgr/sparse_ci.cpp +++ b/c++/src/objtools/alnmgr/sparse_ci.cpp @@ -1,4 +1,4 @@ -/* $Id: sparse_ci.cpp 490380 2016-01-25 16:11:22Z grichenk $ +/* $Id: sparse_ci.cpp 536319 2017-05-17 15:53:12Z grichenk $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -164,7 +164,7 @@ void CSparse_CI::x_InitSegment(void) right_offset = m_RowIt.GetFirstRange().GetToOpen() - to; if (m_NextAnchorRg.GetToOpen() < to) { from = max(m_NextAnchorRg.GetToOpen(), m_NextRowRg.GetFrom()); - left_offset = m_NextRowRg.GetFrom() - from; + left_offset = from - m_NextRowRg.GetFrom(); } else if (m_NextRowRg.GetToOpen() < to) { from = max(m_NextRowRg.GetToOpen(), m_NextAnchorRg.GetFrom()); diff --git a/c++/src/objtools/blast/CMakeLists.txt b/c++/src/objtools/blast/CMakeLists.txt new file mode 100644 index 00000000..268d808e --- /dev/null +++ b/c++/src/objtools/blast/CMakeLists.txt @@ -0,0 +1,13 @@ +############################################################################## +# +# + +# Include projects from this directory + +# Recurse subdirectories +add_subdirectory(seqdb_reader) +add_subdirectory(seqdb_writer) +add_subdirectory(gene_info_reader) +add_subdirectory(gene_info_writer) +add_subdirectory(services) +add_subdirectory(blastdb_format) diff --git a/c++/src/objtools/blast/blastdb_format/CMakeLists.blastdb_format.lib.txt b/c++/src/objtools/blast/blastdb_format/CMakeLists.blastdb_format.lib.txt new file mode 100644 index 00000000..af7b52e1 --- /dev/null +++ b/c++/src/objtools/blast/blastdb_format/CMakeLists.blastdb_format.lib.txt @@ -0,0 +1,14 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/blast/blastdb_format/Makefile.blastdb_format.lib +# +add_library(blastdb_format + seq_writer blastdb_dataextract blastdb_formatter seq_formatter +) +add_dependencies(blastdb_format + blastdb seqset +) + +target_link_libraries(blastdb_format + seqdb xobjutil +) + diff --git a/c++/src/objtools/blast/blastdb_format/CMakeLists.txt b/c++/src/objtools/blast/blastdb_format/CMakeLists.txt new file mode 100644 index 00000000..111e7ce4 --- /dev/null +++ b/c++/src/objtools/blast/blastdb_format/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.blastdb_format.lib.txt) + +# Recurse subdirectories +add_subdirectory(unit_test ) diff --git a/c++/src/objtools/blast/blastdb_format/Makefile.blastdb_format.lib b/c++/src/objtools/blast/blastdb_format/Makefile.blastdb_format.lib index 9cfbe045..e7a0f395 100644 --- a/c++/src/objtools/blast/blastdb_format/Makefile.blastdb_format.lib +++ b/c++/src/objtools/blast/blastdb_format/Makefile.blastdb_format.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.blastdb_format.lib 516388 2016-10-13 12:25:09Z ivanov $ +# $Id: Makefile.blastdb_format.lib 514414 2016-09-21 17:13:37Z fongah2 $ WATCHERS = camacho diff --git a/c++/src/objtools/blast/blastdb_format/blastdb_dataextract.cpp b/c++/src/objtools/blast/blastdb_format/blastdb_dataextract.cpp index 29b1802d..580bf3a2 100644 --- a/c++/src/objtools/blast/blastdb_format/blastdb_dataextract.cpp +++ b/c++/src/objtools/blast/blastdb_format/blastdb_dataextract.cpp @@ -1,4 +1,4 @@ -/* $Id: blastdb_dataextract.cpp 521160 2016-12-06 15:25:33Z ivanov $ +/* $Id: blastdb_dataextract.cpp 545431 2017-09-06 17:03:49Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -647,7 +648,7 @@ s_ConfigureDeflineTitle(const string& title, bool use_ctrl_a) try { CSeq_id::ParseIDs(seqids, kPossibleId, CSeq_id::fParse_PartialOK); - } catch (const CException& e) {} + } catch (const CException&) {} if (!seqids.empty()) { retval += kSeparator; @@ -797,6 +798,22 @@ void CBlastDBExtractor::SetConfig(TSeqRange range, objects::ENa_strand strand, m_FiltAlgoId = filt_algo_id; } +static bool s_MatchPDBId(const CSeq_id & target_id, const CSeq_id & defline_id) +{ + if(defline_id.IsPdb()) { + if(target_id.GetPdb().IsSetChain()) { + if(defline_id.GetPdb().IsSetChain()) { + return ((target_id.GetPdb().GetChain() == defline_id.GetPdb().GetChain()) && + PNocase().Equals(target_id.GetPdb().GetMol(), defline_id.GetPdb().GetMol())); + } + } + else { + return PNocase().Equals(target_id.GetPdb().GetMol(), defline_id.GetPdb().GetMol()); + } + } + return false; +} + void CBlastDeflineUtil::ExtractDataFromBlastDeflineSet(const CBlast_def_line_set & dl_set, vector & results, BlastDeflineFields fields, @@ -806,10 +823,11 @@ void CBlastDeflineUtil::ExtractDataFromBlastDeflineSet(const CBlast_def_line_set CSeq_id target_seq_id (target_id, CSeq_id::fParse_PartialOK | CSeq_id::fParse_Default); Int8 num_id = NStr::StringToNumeric(target_id, NStr::fConvErr_NoThrow); bool can_be_gi = errno ? false: true; + bool isPDBId = target_seq_id.IsPdb(); ITERATE(CBlast_def_line_set::Tdata, itr, dl_set.Get()) { ITERATE(CBlast_def_line::TSeqid, id, (*itr)->GetSeqid()) { - - if ((*id)->Match(target_seq_id) || (can_be_gi && (*id)->IsGi() && ((*id)->GetGi() == num_id))) { + if ((*id)->Match(target_seq_id) || (can_be_gi && (*id)->IsGi() && ((*id)->GetGi() == num_id)) + || (isPDBId && s_MatchPDBId(target_seq_id, **id))) { CBlastDeflineUtil::ExtractDataFromBlastDefline( **itr, results, fields, use_long_id); return; } diff --git a/c++/src/objtools/blast/blastdb_format/seq_formatter.cpp b/c++/src/objtools/blast/blastdb_format/seq_formatter.cpp index 69201f3e..ddaa7ad0 100644 --- a/c++/src/objtools/blast/blastdb_format/seq_formatter.cpp +++ b/c++/src/objtools/blast/blastdb_format/seq_formatter.cpp @@ -399,7 +399,6 @@ int CBlastDB_FastaFormatter::Write(CSeqDB::TOID oid, const CBlastDB_FormatterCon int status = -1; CRef bioseq = m_BlastDb.GetBioseq(oid); if(target_id != kEmptyStr) { - CSeq_id seq_id(target_id, CSeq_id::fParse_PartialOK | CSeq_id::fParse_Default); Int8 num_id = NStr::StringToNumeric(target_id, NStr::fConvErr_NoThrow); if(errno) { CSeq_id seq_id(target_id, CSeq_id::fParse_PartialOK | CSeq_id::fParse_Default); diff --git a/c++/src/objtools/blast/blastdb_format/seq_writer.cpp b/c++/src/objtools/blast/blastdb_format/seq_writer.cpp index cb452a6e..1736ea99 100644 --- a/c++/src/objtools/blast/blastdb_format/seq_writer.cpp +++ b/c++/src/objtools/blast/blastdb_format/seq_writer.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_writer.cpp 520557 2016-11-29 19:16:57Z ivanov $ +/* $Id: seq_writer.cpp 520176 2016-11-23 15:19:35Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/blast/blastdb_format/unit_test/CMakeLists.blastdb_format_unit_test.app.txt b/c++/src/objtools/blast/blastdb_format/unit_test/CMakeLists.blastdb_format_unit_test.app.txt new file mode 100644 index 00000000..ebd82a2b --- /dev/null +++ b/c++/src/objtools/blast/blastdb_format/unit_test/CMakeLists.blastdb_format_unit_test.app.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/blast/blastdb_format/unit_test/Makefile.blastdb_format_unit_test.app +# +add_executable(blastdb_format_unit_test-app + seq_writer_unit_test +) + +set_target_properties(blastdb_format_unit_test-app PROPERTIES OUTPUT_NAME blastdb_format_unit_test) + + + +target_link_libraries(blastdb_format_unit_test-app + blastdb_format test_boost +) + diff --git a/c++/src/objtools/blast/blastdb_format/unit_test/CMakeLists.txt b/c++/src/objtools/blast/blastdb_format/unit_test/CMakeLists.txt new file mode 100644 index 00000000..6b3c9d16 --- /dev/null +++ b/c++/src/objtools/blast/blastdb_format/unit_test/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +include_directories(SYSTEM ${BOOST_INCLUDE}) + +# Include projects from this directory +include(CMakeLists.blastdb_format_unit_test.app.txt) + diff --git a/c++/src/objtools/blast/blastdb_format/unit_test/Makefile.blastdb_format_unit_test.app b/c++/src/objtools/blast/blastdb_format/unit_test/Makefile.blastdb_format_unit_test.app index 52e373de..272404e8 100644 --- a/c++/src/objtools/blast/blastdb_format/unit_test/Makefile.blastdb_format_unit_test.app +++ b/c++/src/objtools/blast/blastdb_format/unit_test/Makefile.blastdb_format_unit_test.app @@ -1,4 +1,4 @@ -# $Id: Makefile.blastdb_format_unit_test.app 516391 2016-10-13 12:25:53Z ivanov $ +# $Id: Makefile.blastdb_format_unit_test.app 514540 2016-09-22 14:52:09Z fongah2 $ APP = blastdb_format_unit_test SRC = seq_writer_unit_test seq_formatter_unit_test diff --git a/c++/src/objtools/blast/blastdb_format/unit_test/seq_formatter_unit_test.cpp b/c++/src/objtools/blast/blastdb_format/unit_test/seq_formatter_unit_test.cpp index 1d1fdf8a..cb5a09f8 100644 --- a/c++/src/objtools/blast/blastdb_format/unit_test/seq_formatter_unit_test.cpp +++ b/c++/src/objtools/blast/blastdb_format/unit_test/seq_formatter_unit_test.cpp @@ -99,7 +99,7 @@ BOOST_AUTO_TEST_CASE(TestRequestGiOidLength) ofstream out(fname.c_str()); CBlastDB_SeqFormatter f(format_spec, db, out); int id = -1; - db.GiToOid(kGi, id); + db.GiToOid(GI_CONST(kGi), id); CBlastDB_FormatterConfig config; f.Write(id, config); out.close(); @@ -143,7 +143,7 @@ BOOST_AUTO_TEST_CASE(TestRequestSeqId) ofstream out(fname.c_str()); CBlastDB_SeqFormatter f(format_spec, db, out); int oid = -1; - db.GiToOid(kGi, oid); + db.GiToOid(GI_CONST(kGi), oid); CBlastDB_FormatterConfig config; f.Write(oid, config); out.close(); @@ -189,7 +189,7 @@ BOOST_AUTO_TEST_CASE(TestRequestSeqIdLong) ofstream out(fname.c_str()); CBlastDB_SeqFormatter f(format_spec, db, out); int oid = -1; - db.GiToOid(kGi, oid); + db.GiToOid(GI_CONST(kGi), oid); CBlastDB_FormatterConfig config; f.Write(oid, config); out.close(); @@ -224,7 +224,7 @@ BOOST_AUTO_TEST_CASE(TestRequestAccessionPIGTaxidTitle) ofstream out(fname.c_str()); CBlastDB_SeqFormatter f(format_spec, db, out); int oid = -1; - db.GiToOid(kGi, oid); + db.GiToOid(GI_CONST(kGi), oid); CBlastDB_FormatterConfig config; f.Write(oid, config); out.close(); @@ -284,7 +284,7 @@ BOOST_AUTO_TEST_CASE(TestRequestSequenceDataLength) ofstream out(fname.c_str()); CBlastDB_SeqFormatter f(format_spec, db, out); int oid = -1; - db.GiToOid(kGi, oid); + db.GiToOid(GI_CONST(kGi), oid); CBlastDB_FormatterConfig config; f.Write(oid, config); out.close(); @@ -320,7 +320,7 @@ BOOST_AUTO_TEST_CASE(TestMaskedFasta) //config.m_FiltAlgoIds.push_back(40); CBlastDB_FastaFormatter f(db, out, config.m_SeqRange.GetLength()); int oid = -1; - db.GiToOid(kGi, oid); + db.GiToOid(GI_CONST(kGi), oid); f.Write(oid, config); out.close(); @@ -363,7 +363,7 @@ BOOST_AUTO_TEST_CASE(TestMaskedSequenceData) //config.m_FiltAlgoIds.push_back(40); CBlastDB_SeqFormatter f(format_spec, db, out); int oid = -1; - db.GiToOid(kGi, oid); + db.GiToOid(GI_CONST(kGi), oid); f.Write(oid, config); out.close(); diff --git a/c++/src/objtools/blast/blastdb_format/unit_test/seq_writer_unit_test.cpp b/c++/src/objtools/blast/blastdb_format/unit_test/seq_writer_unit_test.cpp index bb433867..ff1ee68c 100644 --- a/c++/src/objtools/blast/blastdb_format/unit_test/seq_writer_unit_test.cpp +++ b/c++/src/objtools/blast/blastdb_format/unit_test/seq_writer_unit_test.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_writer_unit_test.cpp 509852 2016-08-09 16:58:45Z ivanov $ +/* $Id: seq_writer_unit_test.cpp 509457 2016-08-05 16:24:09Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/blast/gene_info_reader/CMakeLists.gene_info.lib.txt b/c++/src/objtools/blast/gene_info_reader/CMakeLists.gene_info.lib.txt new file mode 100644 index 00000000..d1c97955 --- /dev/null +++ b/c++/src/objtools/blast/gene_info_reader/CMakeLists.gene_info.lib.txt @@ -0,0 +1,10 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/blast/gene_info_reader/Makefile.gene_info.lib +# +add_library(gene_info + gene_info gene_info_reader file_utils +) + +target_link_libraries(gene_info + xncbi +) diff --git a/c++/src/objtools/blast/gene_info_reader/CMakeLists.txt b/c++/src/objtools/blast/gene_info_reader/CMakeLists.txt new file mode 100644 index 00000000..954a7a47 --- /dev/null +++ b/c++/src/objtools/blast/gene_info_reader/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.gene_info.lib.txt) + +# Recurse subdirectories +add_subdirectory(demo ) +add_subdirectory(unit_test ) diff --git a/c++/src/objtools/blast/gene_info_reader/demo/CMakeLists.gene_info_reader.app.txt b/c++/src/objtools/blast/gene_info_reader/demo/CMakeLists.gene_info_reader.app.txt new file mode 100644 index 00000000..5456f31c --- /dev/null +++ b/c++/src/objtools/blast/gene_info_reader/demo/CMakeLists.gene_info_reader.app.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/blast/gene_info_reader/demo/Makefile.gene_info_reader.app +# +add_executable(gene_info_reader-app + gene_info_reader_app +) + +set_target_properties(gene_info_reader-app PROPERTIES OUTPUT_NAME gene_info_reader) + +target_link_libraries(gene_info_reader-app + gene_info +) + +add_dependencies(gene_info_reader-app + seq +) + diff --git a/c++/src/objtools/blast/gene_info_reader/demo/CMakeLists.txt b/c++/src/objtools/blast/gene_info_reader/demo/CMakeLists.txt new file mode 100644 index 00000000..6ea64ebe --- /dev/null +++ b/c++/src/objtools/blast/gene_info_reader/demo/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.gene_info_reader.app.txt) + diff --git a/c++/src/objtools/blast/gene_info_reader/file_utils.cpp b/c++/src/objtools/blast/gene_info_reader/file_utils.cpp index ae838fd0..06d0676f 100644 --- a/c++/src/objtools/blast/gene_info_reader/file_utils.cpp +++ b/c++/src/objtools/blast/gene_info_reader/file_utils.cpp @@ -1,4 +1,4 @@ -/* $Id: file_utils.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: file_utils.cpp 523368 2017-01-03 13:12:11Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -158,7 +158,7 @@ void CGeneFileUtils::ReadGeneInfo(CNcbiIfstream& in, } vector strItems; - NStr::Tokenize(strBuf, "\t", strItems); + NStr::SplitByPattern(strBuf, "\t", strItems); if (strItems.size() != k_nGeneAllDataNumItems) { diff --git a/c++/src/objtools/blast/gene_info_reader/gene_info.cpp b/c++/src/objtools/blast/gene_info_reader/gene_info.cpp index d6a54060..b1106411 100644 --- a/c++/src/objtools/blast/gene_info_reader/gene_info.cpp +++ b/c++/src/objtools/blast/gene_info_reader/gene_info.cpp @@ -1,4 +1,4 @@ -/* $Id: gene_info.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: gene_info.cpp 523368 2017-01-03 13:12:11Z madden $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -174,7 +174,7 @@ void CGeneInfo::ToString(string& strGeneInfo, // words and append them one by one. vector strDescrWords; - NStr::Tokenize(GetDescription(), " ", strDescrWords); + NStr::SplitByPattern(GetDescription(), " ", strDescrWords); for (size_t iWord = 0; iWord < strDescrWords.size(); iWord++) { string strCurWord = strDescrWords[iWord]; diff --git a/c++/src/objtools/blast/gene_info_reader/unit_test/CMakeLists.gene_info_unit_test.app.txt b/c++/src/objtools/blast/gene_info_reader/unit_test/CMakeLists.gene_info_unit_test.app.txt new file mode 100644 index 00000000..c26c245e --- /dev/null +++ b/c++/src/objtools/blast/gene_info_reader/unit_test/CMakeLists.gene_info_unit_test.app.txt @@ -0,0 +1,19 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/blast/gene_info_reader/unit_test/Makefile.gene_info_unit_test.app +# + +if (UNIX AND NOT APPLE) + + add_executable(gene_info_unit_test-app + gene_info_test + ) + + set_target_properties(gene_info_unit_test-app PROPERTIES OUTPUT_NAME gene_info_unit_test) + + + + target_link_libraries(gene_info_unit_test-app + gene_info test_boost +) + +endif () diff --git a/c++/src/objtools/blast/gene_info_reader/unit_test/CMakeLists.txt b/c++/src/objtools/blast/gene_info_reader/unit_test/CMakeLists.txt new file mode 100644 index 00000000..68a47599 --- /dev/null +++ b/c++/src/objtools/blast/gene_info_reader/unit_test/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +include_directories(SYSTEM ${BOOST_INCLUDE}) + +# Include projects from this directory +include(CMakeLists.gene_info_unit_test.app.txt) + diff --git a/c++/src/objtools/blast/gene_info_reader/unit_test/gene_info_test.cpp b/c++/src/objtools/blast/gene_info_reader/unit_test/gene_info_test.cpp index e7116452..5476f9b4 100644 --- a/c++/src/objtools/blast/gene_info_reader/unit_test/gene_info_test.cpp +++ b/c++/src/objtools/blast/gene_info_reader/unit_test/gene_info_test.cpp @@ -1,4 +1,4 @@ -/* $Id: gene_info_test.cpp 192788 2010-05-27 13:59:43Z camacho $ +/* $Id: gene_info_test.cpp 529268 2017-03-02 16:27:53Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -456,28 +456,28 @@ BOOST_AUTO_TEST_CASE(s_TestGeneInfo) BOOST_AUTO_TEST_CASE(s_IncorrectPathTest) { - CGeneInfoFileReader *pReader1 = 0, *pReader2 = 0; + unique_ptr pReader1, pReader2; CNcbiEnvironment env; string strDirPath = env.Get(GENE_INFO_PATH_ENV_VARIABLE); env.Set(GENE_INFO_PATH_ENV_VARIABLE, "./"); - BOOST_REQUIRE_THROW(pReader1 = new CGeneInfoFileReader(true), + BOOST_REQUIRE_THROW(pReader1.reset(new CGeneInfoFileReader(true)), CGeneInfoException); - BOOST_REQUIRE_THROW(pReader1 = new CGeneInfoFileReader(false), + BOOST_REQUIRE_THROW(pReader1.reset(new CGeneInfoFileReader(false)), CGeneInfoException); env.Set(GENE_INFO_PATH_ENV_VARIABLE, "invalid_path"); - BOOST_REQUIRE_THROW(pReader1 = new CGeneInfoFileReader(true), + BOOST_REQUIRE_THROW(pReader1.reset(new CGeneInfoFileReader(true)), CGeneInfoException); - BOOST_REQUIRE_THROW(pReader1 = new CGeneInfoFileReader(false), + BOOST_REQUIRE_THROW(pReader1.reset(new CGeneInfoFileReader(false)), CGeneInfoException); - env.Set(GENE_INFO_PATH_ENV_VARIABLE, strDirPath); - BOOST_REQUIRE_NO_THROW(pReader1 = new CGeneInfoFileReader(true)); - BOOST_REQUIRE_NO_THROW(pReader2 = new CGeneInfoFileReader(false)); - delete pReader1; - delete pReader2; + if (strDirPath != kEmptyStr) { + env.Set(GENE_INFO_PATH_ENV_VARIABLE, strDirPath); + BOOST_REQUIRE_NO_THROW(pReader1.reset(new CGeneInfoFileReader(true))); + BOOST_REQUIRE_NO_THROW(pReader2.reset(new CGeneInfoFileReader(false))); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/c++/src/objtools/blast/seqdb_reader/CMakeLists.seqdb.lib.txt b/c++/src/objtools/blast/seqdb_reader/CMakeLists.seqdb.lib.txt new file mode 100644 index 00000000..d1cf7ed2 --- /dev/null +++ b/c++/src/objtools/blast/seqdb_reader/CMakeLists.seqdb.lib.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/blast/seqdb_reader/Makefile.seqdb.lib +# +add_library(seqdb + seqdb seqdbbitset seqdbfilter seqdbatlas seqdbalias seqdbcommon + seqdbfile seqdbimpl seqdbvol seqdbvolset seqdboidlist seqdbisam + seqdbtax seqdbgilistset seqdbexpert seqdbblob seqdbcol seqdbgimask seqdbobj +) +add_dependencies(seqdb + blastdb +) + +target_link_libraries(seqdb + blastdb xobjmgr +) + diff --git a/c++/src/objtools/blast/seqdb_reader/CMakeLists.txt b/c++/src/objtools/blast/seqdb_reader/CMakeLists.txt new file mode 100644 index 00000000..ab254c6c --- /dev/null +++ b/c++/src/objtools/blast/seqdb_reader/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.seqdb.lib.txt) + +# Recurse subdirectories +add_subdirectory(demo ) +add_subdirectory(test ) diff --git a/c++/src/objtools/blast/seqdb_reader/Makefile.in b/c++/src/objtools/blast/seqdb_reader/Makefile.in index 068b561a..1ef515fc 100644 --- a/c++/src/objtools/blast/seqdb_reader/Makefile.in +++ b/c++/src/objtools/blast/seqdb_reader/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in 340120 2011-10-05 16:10:29Z camacho $ +# $Id: Makefile.in 535575 2017-05-10 10:14:35Z camacho $ # Meta-makefile("SEQDB" project) ################################# diff --git a/c++/src/objtools/blast/seqdb_reader/Makefile.seqdb.lib b/c++/src/objtools/blast/seqdb_reader/Makefile.seqdb.lib index c46a572a..e5a5a856 100644 --- a/c++/src/objtools/blast/seqdb_reader/Makefile.seqdb.lib +++ b/c++/src/objtools/blast/seqdb_reader/Makefile.seqdb.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.seqdb.lib 468761 2015-05-27 20:14:39Z ucko $ +# $Id: Makefile.seqdb.lib 535575 2017-05-10 10:14:35Z camacho $ ASN_DEP = blastdb @@ -30,7 +30,7 @@ CPPFLAGS = -DNCBI_MODULE=BLASTDB $(ORIG_CPPFLAGS) CXXFLAGS = $(FAST_CXXFLAGS) LDFLAGS = $(FAST_LDFLAGS) -WATCHERS = camacho fongah2 +WATCHERS = camacho fongah2 rackerst USES_LIBRARIES = \ diff --git a/c++/src/objtools/blast/seqdb_reader/demo/CMakeLists.seqdb_demo.app.txt b/c++/src/objtools/blast/seqdb_reader/demo/CMakeLists.seqdb_demo.app.txt new file mode 100644 index 00000000..b6525bef --- /dev/null +++ b/c++/src/objtools/blast/seqdb_reader/demo/CMakeLists.seqdb_demo.app.txt @@ -0,0 +1,9 @@ +add_executable(seqdb_demo-app + seqdb_demo +) + +set_target_properties(seqdb_demo-app PROPERTIES OUTPUT_NAME seqdb_demo) + +target_link_libraries(seqdb_demo-app + seqdb +) diff --git a/c++/src/objtools/blast/seqdb_reader/demo/CMakeLists.txt b/c++/src/objtools/blast/seqdb_reader/demo/CMakeLists.txt new file mode 100644 index 00000000..456b47f8 --- /dev/null +++ b/c++/src/objtools/blast/seqdb_reader/demo/CMakeLists.txt @@ -0,0 +1,6 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.seqdb_demo.app.txt) diff --git a/c++/src/objtools/blast/seqdb_reader/demo/seqdb_demo.cpp b/c++/src/objtools/blast/seqdb_reader/demo/seqdb_demo.cpp index 9bd7cba2..e9f7686c 100644 --- a/c++/src/objtools/blast/seqdb_reader/demo/seqdb_demo.cpp +++ b/c++/src/objtools/blast/seqdb_reader/demo/seqdb_demo.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdb_demo.cpp 468781 2015-05-28 12:51:59Z vasilche $ +/* $Id: seqdb_demo.cpp 532309 2017-04-03 20:04:51Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,9 +33,15 @@ #include #include #include +#include +#include +#include BEGIN_NCBI_SCOPE +DEFINE_STATIC_MUTEX(s_mutex); + + /// Demo case base class. class ISeqDBDemoCase : public CObject { public: @@ -43,14 +49,15 @@ public: virtual ~ISeqDBDemoCase() { } - + /// Show description for this test case. virtual void DisplayHelp() = 0; - + /// Run this test case. virtual void Run() = 0; }; + /// Demo for GetSequence() methods. class CSeqDBDemo_GetSequence : public ISeqDBDemoCase { public: @@ -58,39 +65,39 @@ public: virtual ~CSeqDBDemo_GetSequence() { } - + /// Show description for this test case. virtual void DisplayHelp() { cout << " GetSequence() provides a basic interface to fetch\n" << " a sequence from a SeqDB object given an OID.\n"; } - + /// Run this test case. virtual void Run() { CSeqDB nr("nr", CSeqDB::eProtein); - + TGi gi = GI_CONST(129295); int oid(0); - + if (nr.GiToOid(gi, oid)) { const char * buffer(0); unsigned length = nr.GetSequence(oid, & buffer); - + int alanine = 1; // encoding for the amino acid alanine unsigned count_a = 0; - + for(unsigned i = 0; i 1000) ? 1000 : oid_count; - + cout << " Number of swissprot sequences in (from iteration): " << oid_count << endl; - + cout << " Number of sequences in swissprot (from index file): " << sp.GetNumSeqs() << endl; - + cout << " Combined length of the first " << measured << " sequences: " << length_1000 << endl; } }; -/// Demo for chunk iteration methods. + +/// Demo for chunk iteration methods (single-threaded). class CSeqDBDemo_ChunkIteration : public ISeqDBDemoCase { public: /// Destructor virtual ~CSeqDBDemo_ChunkIteration() { } - + /// Show description for this test case. virtual void DisplayHelp() { @@ -165,35 +174,35 @@ public: << " in a vector. The number of OIDs desired is indicated\n" << " by setting the size of the vector on input.\n"; } - + /// Run this test case. virtual void Run() { CSeqDB sp("swissprot", CSeqDB::eProtein); - + // Summary data to collect - + int oid_count = 0; int length_1000 = 0; - + // This many OIDs will be fetched at once. - + int at_a_time = 1000; - + vector oids; - + // These will be set to a range if SeqDB chooses to return one. - + int begin(0), end(0); - + // In a real multithreaded application, each thread might have // code like the loop inside the "iteration shell" markers, // all using a reference to the same SeqDB object and the same // local_state variable (if needed). The locking inside SeqDB // will prevent simultaneous access - each thread will get // seperate slices of the OID range. - - + + // This (local_state) variable is only needed if more than one // iteration will be done. The GetNextOIDChunk() call would // work the same way (in this example) with the last parameter @@ -205,15 +214,15 @@ public: // would need to share one variable. If only three parameters // are specified to the GetNextOIDChunk() method, the method // uses a variable which is a field of the SeqDB object. - + int local_state = 0; - + // --- Start of iteration "shell" --- - + bool done = false; - + while(! done) { - + // The GetNextOIDChunk() uses the third argument to // determine how many OIDs the user needs, even if the // begin/end variables are used to return the range. In @@ -222,7 +231,7 @@ public: // outputs. local_state keeps track of the position in // the iteration - the only user adjustment of it should // be to reset it to 0 at the beginning of each iteration. - + switch(sp.GetNextOIDChunk(begin, end, at_a_time, oids, & local_state)) { case CSeqDB::eOidList: for(int index = 0; index < (int)oids.size(); index++) { @@ -230,7 +239,7 @@ public: } done = oids.empty(); break; - + case CSeqDB::eOidRange: for(int oid = begin; oid < end; oid++) { x_UseOID(sp, oid, oid_count, length_1000); @@ -239,11 +248,11 @@ public: break; } } - + // --- End of iteration "shell" --- - + unsigned measured = (oid_count > 1000) ? 1000 : oid_count; - + cout << " Sequences in swissprot (counted during iteration): " << oid_count << endl; cout << " Sequences in swissprot (from database index file): " @@ -251,13 +260,15 @@ public: cout << " Combined length of the first " << measured << " sequences: " << length_1000 << endl; } - + private: /// Use this OID as part of the set. - void x_UseOID(CSeqDB & sp, - int oid, - int & oid_count, - int & length_1000) + void x_UseOID( + CSeqDB& sp, + int oid, + int& oid_count, + int& length_1000 + ) { if (oid_count++ < 1000) { length_1000 += sp.GetSeqLength(oid); @@ -265,6 +276,425 @@ private: } }; + +class CSeqDBDemo_Thread : public CThread +{ +public: + CSeqDBDemo_Thread( + int index, + int at_a_time, + int max_length + ); + + virtual void* Main(void); + virtual void OnExit(void); + const int GetIndex(void) const; + + static void Init(CSeqDB& db, bool oid_shuffle, bool use_ambigs) + { + sm_sp = &db; + sm_is_protein = (db.GetSequenceType() == CSeqDB::eProtein); + sm_oid_shuffle = oid_shuffle; + sm_use_ambigs = use_ambigs; + } + + bool IsRunning(void) const + { + return m_Running; + } + +private: + static CSeqDB* sm_sp; + static bool sm_is_protein; + static bool sm_oid_shuffle; + static bool sm_use_ambigs; + static int sm_oid_state; + + const int m_Index; + const int m_AtATime; + const int m_MaxLength; + bool m_Running; + char* m_Temp; + // int* m_HeapVar; + + /// Use this OID as part of the set. + long x_UseOID( + int letter, + int oid + ) + { + static const int kNuclCode = kSeqDBNuclNcbiNA8; + + static const int kLoops = 1; + + static char* mask = NULL; + static char* lets = NULL; + + if (mask == NULL) { + mask = new char[4]; + lets = new char[4]; + for (int i = 0; i < 4; ++i) { + mask[i] = static_cast(0x03 << (i << 1)); + lets[i] = static_cast((letter & 0x03) << (i << 1)); + } + } + + long count = 0; + + const char* buffer = NULL; + if (!sm_is_protein && sm_use_ambigs) { + + int length = sm_sp->GetAmbigSeq(oid, &buffer, kNuclCode); + if (length > 0) { + + // Artificially inflate the amount of "work" being performed + // on each oid. + + for (int loop = 0; loop < kLoops; ++loop) { + count = 0L; + const char* p = buffer; + for (int i = 0; i < length; ++i) { + if (*p++ == letter) { + ++count; + } + } + } + + } + sm_sp->RetAmbigSeq(&buffer); + + } else { + + int length = sm_sp->GetSequence(oid, &buffer); + if (length > 0) { + + // Artificially inflate the amount of "work" being performed + // on each oid. + + for (int loop = 0; loop < kLoops; ++loop) { + count = 0L; + const char* p = buffer; + if (sm_is_protein) { + for (int i = 0; i < length; ++i) { + if (*p++ == letter) { + ++count; + } + } + } else { + int nbytes = (length + 3) / 4; + for (int i = 0; i < nbytes; ++i) { + char c = *p++; + for (int j = 0; j < 4; ++j) { + if ((c & mask[j]) == lets[j]) { + ++count; + } + } + } + } + } + + } + sm_sp->RetSequence(&buffer); + + } + + return count; + } +}; + +CSeqDB* CSeqDBDemo_Thread::sm_sp = NULL; +bool CSeqDBDemo_Thread::sm_is_protein = false; +bool CSeqDBDemo_Thread::sm_oid_shuffle = false; +bool CSeqDBDemo_Thread::sm_use_ambigs = false; +int CSeqDBDemo_Thread::sm_oid_state = 0; + +CSeqDBDemo_Thread::CSeqDBDemo_Thread( + int index, + int at_a_time, + int max_length +) : m_Index(index), m_AtATime(at_a_time), m_MaxLength(max_length), + m_Running(true), m_Temp(NULL) +{ +} + +void* CSeqDBDemo_Thread::Main(void) +{ + long* retval = new long; + + // m_HeapVar = new int; + // *m_HeapVar = 12345; + + // Summary data to collect + long count = 0; + + // This will be set to a collection of oids + // if SeqDB chooses to return one. + vector oids; + + // These will be set to a range if SeqDB chooses to return one. + int oid_begin(0), oid_end(0); + + bool done = false; + while (!done) { + + // The GetNextOIDChunk() uses the third argument to + // determine how many OIDs the user needs, even if the + // begin/end variables are used to return the range. In + // other words, at_a_time is an INPUT to this call, and + // begin, end, and the size and contents of oids, are all + // outputs. local_state keeps track of the position in + // the iteration - the only user adjustment of it should + // be to reset it to 0 at the beginning of each iteration. + + const int letter = 1; + + if (sm_use_ambigs) { + if ( + sm_sp->GetNextOIDChunk( + oid_begin, + oid_end, + m_AtATime, + oids, + &sm_oid_state + ) == CSeqDB::eOidRange + ) { + oids.clear(); + for (int oid = oid_begin; oid < oid_end; ++oid) { + oids.push_back(oid); + } + } + } else { + if ( + sm_sp->GetNextOIDChunk( + oid_begin, + oid_end, + m_AtATime, + oids, + &sm_oid_state + ) == CSeqDB::eOidRange + ) { + oids.clear(); + for (int oid = oid_begin; oid < oid_end; ++oid) { + oids.push_back(oid); + } + } + } + + if (sm_oid_shuffle) { + random_shuffle(oids.begin(), oids.end()); + } + ITERATE(vector, oid, oids) { + count += x_UseOID(letter, *oid); + } + done = oids.empty(); + + } + + std::ostringstream oss; + oss << "Thread " << m_Index << " says: " + << count << " occurrences of A" << endl; + + s_mutex.Lock(); + cout << oss.str() << flush; + s_mutex.Unlock(); + + *retval = count; + return retval; +} + +void CSeqDBDemo_Thread::OnExit(void) +{ + // Delete here anything declared on the heap in Main, + // except for the return value. All such items should + // have their pointers as data members of this class. + + // delete m_HeapVar; + + if (m_Temp != NULL) { + delete [] m_Temp; + } + + m_Running = false; +} + +const int CSeqDBDemo_Thread::GetIndex(void) const +{ + return m_Index; +} + + +/// Demo for chunk iteration methods (multi-threaded). +class CSeqDBDemo_Threaded : public ISeqDBDemoCase { +private: + + static string sm_DbName; + static int sm_NumThreads; + static int sm_OidBatchSize; + static bool sm_ListVols; + static bool sm_NoMmap; + static bool sm_OidShuffle; + static bool sm_UseAmbigs; + +public: + + /// Destructor + virtual ~CSeqDBDemo_Threaded() + { + } + + static void SetDbName(const string& dbname) + { + sm_DbName = dbname; + } + + static void SetNumThreads(const int nthreads) + { + sm_NumThreads = nthreads; + } + + static void SetListVols(void) + { + sm_ListVols = true; + } + + static void SetNoMmap(void) + { + sm_NoMmap = true; + } + + static void SetOidShuffle(void) + { + sm_OidShuffle = true; + } + + static void SetUseAmbigs(void) + { + sm_UseAmbigs = true; + } + + static void SetOidBatchSize(const int num) + { + sm_OidBatchSize = num; + } + + /// Show description for this test case. + virtual void DisplayHelp() + { + cout << " GetNextOIDChunk() provides versatile iteration meant\n" + << " for multithreaded applications. Each thread fetches\n" + << " a set of OIDs to work with, only returning for more\n" + << " when done with that set. SeqDB guarantees that all\n" + << " OIDs will be assigned, and no OID will be returned\n" + << " more than once.\n\n" + << " The data will be returned in one of two forms, either\n" + << " as a pair of numbers representing a range of OIDs, or\n" + << " in a vector. The number of OIDs desired is indicated\n" + << " by setting the size of the vector on input.\n"; + } + + /// Run this test case. + virtual void Run() + { + // Open and configure access to the database. + CSeqDB sp(sm_DbName, CSeqDB::eUnknown, 0, 0, !sm_NoMmap, NULL); + sp.SetNumberOfThreads(sm_NumThreads, true); + if (sp.GetSequenceType() == CSeqDB::eProtein) { + cout << "Sequence type is PROTEIN" << endl; + } else { + cout << "Sequence type is NUCLEOTIDE" << endl; + } + + // Set the database for the thread class. + CSeqDBDemo_Thread::Init(sp, sm_OidShuffle, sm_UseAmbigs); + + if (sm_ListVols) { + // Show the base names of all volumes. + vector paths; + bool recursive = true; + sp.FindVolumePaths(paths, recursive); + cout << "Volume paths:" << endl; + ITERATE(vector, path, paths) { + cout << "\t" << *path << endl; + } + } + + // Get the length of the largest sequence in the database. + int max_length = sp.GetMaxLength(); + + // The locking inside SeqDB will prevent simultaneous access - + // each thread will get separate slices of the OID range. + // + // The (local_state) variable is only needed if more than one + // iteration will be done. The GetNextOIDChunk() call would + // work the same way (in this example) with the last parameter + // omitted, because we only iterate over the database once. + // + // Multiple, simultaneous, independent, iterations (ie. each + // getting every OID), would need more than one "local_state" + // variable. Iterations pulling OIDs from the same collection + // would need to share one variable. If only three parameters + // are specified to the GetNextOIDChunk() method, the method + // uses a variable which is a field of the SeqDB object. + + vector threads; + + for (int index = 1; index <= sm_NumThreads; ++index) { + CSeqDBDemo_Thread* thread( + new CSeqDBDemo_Thread( + index, + sm_OidBatchSize, + max_length + ) + ); + threads.push_back(thread); + } + + NON_CONST_ITERATE(vector, thread, threads) { + (*thread)->Run(); + } + + long sumval = 0; + vector::iterator thr; + while (!threads.empty()) { + bool found = false; + NON_CONST_ITERATE( + vector, + thread, + threads + ) { + CSeqDBDemo_Thread* th = *thread; + if (!th->IsRunning()) { + thr = thread; + found = true; + break; + } + } + if (found) { + long* retval; + (*thr)->Join(reinterpret_cast(&retval)); + s_mutex.Lock(); + cout << "Thread " << (*thr)->GetIndex() << " returned " + << *retval << endl; + s_mutex.Unlock(); + threads.erase(thr); + sumval += *retval; + } else { + SleepMilliSec(100); + } + } + cout << "Threads combined returned " << sumval << endl; + } +}; + +string CSeqDBDemo_Threaded::sm_DbName ("swissprot"); +int CSeqDBDemo_Threaded::sm_NumThreads (4); +int CSeqDBDemo_Threaded::sm_OidBatchSize (100); +bool CSeqDBDemo_Threaded::sm_ListVols (false); +bool CSeqDBDemo_Threaded::sm_NoMmap (false); +bool CSeqDBDemo_Threaded::sm_OidShuffle (false); +bool CSeqDBDemo_Threaded::sm_UseAmbigs (false); + + /// Demo for fetching a bioseq from a seqid methods. class CSeqDBDemo_SeqidToBioseq : public ISeqDBDemoCase { public: @@ -272,7 +702,7 @@ public: virtual ~CSeqDBDemo_SeqidToBioseq() { } - + /// Show description for this test case. virtual void DisplayHelp() { @@ -281,17 +711,17 @@ public: << " method returns the first matching CBioseq found in\n" << " the database.\n"; } - + /// Run this test case. virtual void Run() { CSeqDB sp("swissprot", CSeqDB::eProtein); - + string str("gi|129295"); - + CSeq_id seqid(str); CRef bs = sp.SeqidToBioseq(seqid); - + if (! bs.Empty()) { if (bs->CanGetInst()) { if (bs->GetInst().CanGetLength()) { @@ -311,37 +741,83 @@ public: } }; + /// Run one or more test cases. extern "C" int main(int argc, char ** argv) { - // Build a set of command line options - + // Build a set of available test options + typedef map< string, CRef > TDemoSet; TDemoSet demo_set; - + demo_set["-get-sequence"].Reset(new CSeqDBDemo_GetSequence); demo_set["-iteration-simple"].Reset(new CSeqDBDemo_SimpleIteration); demo_set["-iteration-chunk"].Reset(new CSeqDBDemo_ChunkIteration); + demo_set["-iteration-threaded"].Reset(new CSeqDBDemo_Threaded); demo_set["-seqid-to-bioseq"].Reset(new CSeqDBDemo_SeqidToBioseq); - - // Parse and attempt to run everything the user throws at us - + + // Additional options recognized: + // These are used only by "-iteration-threaded" test. + // -db + // -list_vols + // -no_mmap + // -num_threads + // -oid_batch + // -shuffle_oids + // -use_ambigs (only applies to nucleotide searches) + + // Create a list for the tests which will be queued. + list< CRef > demo_list; + + // Parse and attempt to run everything the user throws at us. + bool display_help = false; - + cout << endl; if (argc > 1) { - for(int arg = 1; arg < argc; arg++) { - TDemoSet::iterator it = demo_set.find(string(argv[arg])); - - if (it == demo_set.end()) { - cout << "** Sorry, option [" << argv[arg] - << "] was not found. **\n" << endl; - display_help = true; + for (int arg = 1; arg < argc; arg++) { + char* args = argv[arg]; + if (string(args) == "-db") { + if (++arg == argc) { + cout << "** No database name specified. **\n" << endl; + return -1; + } else { + CSeqDBDemo_Threaded::SetDbName(string(argv[arg])); + } + } else if (string(args) == "-num_threads") { + if (++arg == argc) { + cout << "** Number of threads not given. **\n" << endl; + return -1; + } else { + CSeqDBDemo_Threaded::SetNumThreads(atoi(argv[arg])); + } + } else if (string(args) == "-oid_batch") { + if (++arg == argc) { + cout << "** Number of oids not given. **\n" << endl; + return -1; + } else { + CSeqDBDemo_Threaded::SetOidBatchSize(atoi(argv[arg])); + } + } else if (string(args) == "-list_vols") { + CSeqDBDemo_Threaded::SetListVols(); + } else if (string(args) == "-no_mmap") { + CSeqDBDemo_Threaded::SetNoMmap(); + } else if (string(args) == "-shuffle_oids") { + CSeqDBDemo_Threaded::SetOidShuffle(); + } else if (string(args) == "-use_ambigs") { + CSeqDBDemo_Threaded::SetUseAmbigs(); } else { - cout << "Running test [" << argv[arg] << "]:" << endl; - it->second->Run(); - cout << endl; + TDemoSet::iterator it = demo_set.find(string(args)); + if (it == demo_set.end()) { + cout << "** Sorry, option [" << argv[arg] + << "] was not found. **\n" << endl; + display_help = true; + } else { + cout << "Queueing test [" << argv[arg] << "]:" << endl; + demo_list.push_back(it->second); + cout << endl; + } } } } else { @@ -349,23 +825,30 @@ int main(int argc, char ** argv) << " stepped through in a debugger, or as a minimal test app.\n" << " It demonstrates use of the CSeqDB library API to perform\n" << " simple and/or common blast database operations.\n"; - + display_help = true; } - - + // If there was a problem, display usage messages - + if (display_help) { cout << "\nAvailable options:\n\n"; - + NON_CONST_ITERATE(TDemoSet, demo, demo_set) { cout << demo->first << ":\n"; demo->second->DisplayHelp(); cout << endl; } + + return -1; } - + + // Run the queued demos. + + NON_CONST_ITERATE(list >, it, demo_list) { + (*it)->Run(); + } + return 0; } diff --git a/c++/src/objtools/blast/seqdb_reader/seqdb.cpp b/c++/src/objtools/blast/seqdb_reader/seqdb.cpp index 665601f4..51e4b652 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdb.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdb.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdb.cpp 516402 2016-10-13 12:28:06Z ivanov $ +/* $Id: seqdb.cpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -171,7 +171,7 @@ CSeqDB::CSeqDB(const string & dbname, true, gi_list); - m_Impl->Verify(); + ////m_Impl->Verify(); } CSeqDB::CSeqDB(const string & dbname, @@ -192,7 +192,7 @@ CSeqDB::CSeqDB(const string & dbname, NULL, nlist); - m_Impl->Verify(); + ////m_Impl->Verify(); } // This could become the primary constructor for SeqDB, and those @@ -238,7 +238,7 @@ CSeqDB::CSeqDB(const string & dbname, ESeqType seqtype, CSeqDBIdSet ids) neg.GetPointerOrNull(), ids); - m_Impl->Verify(); + ////m_Impl->Verify(); } CSeqDB::CSeqDB(const vector & dbs, @@ -261,7 +261,7 @@ CSeqDB::CSeqDB(const vector & dbs, true, gi_list); - m_Impl->Verify(); + ////m_Impl->Verify(); } CSeqDB::CSeqDB(const string & dbname, @@ -284,7 +284,7 @@ CSeqDB::CSeqDB(const string & dbname, use_mmap, gi_list); - m_Impl->Verify(); + ////m_Impl->Verify(); } CSeqDB::CSeqDB(const vector & dbs, @@ -310,60 +310,38 @@ CSeqDB::CSeqDB(const vector & dbs, use_mmap, gi_list); - m_Impl->Verify(); + ////m_Impl->Verify(); } CSeqDB::CSeqDB() { m_Impl = new CSeqDBImpl; - m_Impl->Verify(); -} - -void CSeqDB::SetMmapStrategy( - EMmapFileTypes filetype, - EMmapStrategies strategy -) -{ - // If this construct looks odd, it's a Perl-ish technique, - // chaining the ternary ?: operator. - // Read it as - // thing = (if this) then that - // else (if this) then that - // else that - EMemoryAdvise st = - (strategy == eMmap_Sequential) ? eMADV_Sequential - : (strategy == eMmap_WillNeed) ? eMADV_WillNeed - : eMADV_Normal; - if (filetype == eMmap_IndexFile) { - CRegionMap::SetMmapStrategy_Index(st); - } else if (filetype == eMmap_SequenceFile) { - CRegionMap::SetMmapStrategy_Sequence(st); - } + ////m_Impl->Verify(); } int CSeqDB::GetSeqLength(int oid) const { - m_Impl->Verify(); + ////m_Impl->Verify(); int length = m_Impl->GetSeqLength(oid); - m_Impl->Verify(); + ////m_Impl->Verify(); return length; } int CSeqDB::GetSeqLengthApprox(int oid) const { - m_Impl->Verify(); + ////m_Impl->Verify(); int length = m_Impl->GetSeqLengthApprox(oid); - m_Impl->Verify(); + ////m_Impl->Verify(); return length; } CRef CSeqDB::GetHdr(int oid) const { - m_Impl->Verify(); + ////m_Impl->Verify(); CRef rv = m_Impl->GetHdr(oid); - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } @@ -386,7 +364,7 @@ void CSeqDB::GetTaxIDs(int oid, map & gi_to_taxid, bool persist) const { - m_Impl->Verify(); + ////m_Impl->Verify(); typedef map TmpMap; TmpMap gi_to_taxid_tmp; m_Impl->GetTaxIDs(oid, gi_to_taxid_tmp, persist); @@ -396,16 +374,16 @@ void CSeqDB::GetTaxIDs(int oid, ITERATE ( TmpMap, it, gi_to_taxid_tmp ) { gi_to_taxid[it->first] = it->second; } - m_Impl->Verify(); + ////m_Impl->Verify(); } void CSeqDB::GetTaxIDs(int oid, vector & taxids, bool persist) const { - m_Impl->Verify(); + ////m_Impl->Verify(); m_Impl->GetTaxIDs(oid, taxids, persist); - m_Impl->Verify(); + ////m_Impl->Verify(); } void CSeqDB::GetLeafTaxIDs( @@ -414,7 +392,7 @@ void CSeqDB::GetLeafTaxIDs( bool persist ) const { - m_Impl->Verify(); + ////m_Impl->Verify(); typedef map > TmpMap; TmpMap gi_to_taxid_set_tmp; m_Impl->GetLeafTaxIDs(oid, gi_to_taxid_set_tmp, persist); @@ -424,7 +402,7 @@ void CSeqDB::GetLeafTaxIDs( ITERATE ( TmpMap, it, gi_to_taxid_set_tmp ) { gi_to_taxid_set[it->first] = it->second; } - m_Impl->Verify(); + //m_Impl->Verify(); } void CSeqDB::GetLeafTaxIDs( @@ -433,17 +411,17 @@ void CSeqDB::GetLeafTaxIDs( bool persist ) const { - m_Impl->Verify(); + //m_Impl->Verify(); m_Impl->GetLeafTaxIDs(oid, taxids, persist); - m_Impl->Verify(); + //m_Impl->Verify(); } CRef CSeqDB::GetBioseq(int oid, TGi target_gi, const CSeq_id * target_id) const { - m_Impl->Verify(); + //m_Impl->Verify(); CRef rv = m_Impl->GetBioseq(oid, target_gi, target_id, true); - m_Impl->Verify(); + //m_Impl->Verify(); return rv; } @@ -451,25 +429,25 @@ CSeqDB::GetBioseq(int oid, TGi target_gi, const CSeq_id * target_id) const CRef CSeqDB::GetBioseqNoData(int oid, TGi target_gi, const CSeq_id * target_id) const { - m_Impl->Verify(); + //m_Impl->Verify(); CRef rv = m_Impl->GetBioseq(oid, target_gi, target_id, false); - m_Impl->Verify(); + //m_Impl->Verify(); return rv; } void CSeqDB::RetSequence(const char ** buffer) const { - m_Impl->Verify(); + //m_Impl->Verify(); m_Impl->RetSequence(buffer); - m_Impl->Verify(); + //m_Impl->Verify(); } int CSeqDB::GetSequence(int oid, const char ** buffer) const { - m_Impl->Verify(); + //m_Impl->Verify(); int rv = m_Impl->GetSequence(oid, buffer); - m_Impl->Verify(); + //m_Impl->Verify(); return rv; } @@ -478,31 +456,31 @@ CRef CSeqDB::GetSeqData(int oid, TSeqPos begin, TSeqPos end) const { - m_Impl->Verify(); + //m_Impl->Verify(); CRef rv = m_Impl->GetSeqData(oid, begin, end); - m_Impl->Verify(); + //m_Impl->Verify(); return rv; } int CSeqDB::GetAmbigSeq(int oid, const char ** buffer, int nucl_code) const { - m_Impl->Verify(); + //m_Impl->Verify(); int rv = m_Impl->GetAmbigSeq(oid, (char **)buffer, nucl_code, 0, (ESeqDBAllocType) 0); - m_Impl->Verify(); + //m_Impl->Verify(); return rv; } void CSeqDB::RetAmbigSeq(const char ** buffer) const { - m_Impl->Verify(); + //m_Impl->Verify(); m_Impl->RetAmbigSeq(buffer); - m_Impl->Verify(); + //m_Impl->Verify(); } int CSeqDB::GetAmbigSeq(int oid, @@ -511,7 +489,7 @@ int CSeqDB::GetAmbigSeq(int oid, int begin_offset, int end_offset) const { - m_Impl->Verify(); + //m_Impl->Verify(); SSeqDBSlice region(begin_offset, end_offset); @@ -521,7 +499,7 @@ int CSeqDB::GetAmbigSeq(int oid, & region, (ESeqDBAllocType) 0); - m_Impl->Verify(); + //m_Impl->Verify(); return rv; } @@ -532,7 +510,7 @@ int CSeqDB::GetAmbigSeqAlloc(int oid, ESeqDBAllocType strategy, TSequenceRanges *masks) const { - m_Impl->Verify(); + //m_Impl->Verify(); if ((strategy != eMalloc) && (strategy != eNew)) { NCBI_THROW(CSeqDBException, @@ -542,7 +520,7 @@ int CSeqDB::GetAmbigSeqAlloc(int oid, int rv = m_Impl->GetAmbigSeq(oid, buffer, nucl_code, 0, strategy, masks); - m_Impl->Verify(); + //m_Impl->Verify(); return rv; } @@ -634,7 +612,7 @@ int CSeqDB::GetMinLength() const CSeqDB::~CSeqDB() { - m_Impl->Verify(); + ////m_Impl->Verify(); if (m_Impl) delete m_Impl; @@ -647,9 +625,9 @@ CSeqDBIter CSeqDB::Begin() const bool CSeqDB::CheckOrFindOID(int & oid) const { - m_Impl->Verify(); + ////m_Impl->Verify(); bool rv = m_Impl->CheckOrFindOID(oid); - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } @@ -662,12 +640,12 @@ CSeqDB::GetNextOIDChunk(int & begin, vector & lst, int * state) { - m_Impl->Verify(); + ////m_Impl->Verify(); CSeqDB::EOidListType rv = m_Impl->GetNextOIDChunk(begin, end, size, lst, state); - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } @@ -684,11 +662,11 @@ const string & CSeqDB::GetDBNameList() const list< CRef > CSeqDB::GetSeqIDs(int oid) const { - m_Impl->Verify(); + ////m_Impl->Verify(); list< CRef > rv = m_Impl->GetSeqIDs(oid); - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } @@ -700,63 +678,63 @@ TGi CSeqDB::GetSeqGI(int oid) const bool CSeqDB::PigToOid(int pig, int & oid) const { - m_Impl->Verify(); + ////m_Impl->Verify(); bool rv = m_Impl->PigToOid(pig, oid); - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } bool CSeqDB::OidToPig(int oid, int & pig) const { - m_Impl->Verify(); + ////m_Impl->Verify(); bool rv = m_Impl->OidToPig(oid, pig); - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } bool CSeqDB::TiToOid(Int8 ti, int & oid) const { - m_Impl->Verify(); + ////m_Impl->Verify(); bool rv = m_Impl->TiToOid(ti, oid); - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } bool CSeqDB::GiToOid(TGi gi, int & oid) const { - m_Impl->Verify(); + ////m_Impl->Verify(); bool rv = m_Impl->GiToOid(gi, oid); - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } bool CSeqDB::GiToOidwFilterCheck(TGi gi, int & oid) const { - m_Impl->Verify(); + ////m_Impl->Verify(); bool rv = m_Impl->GiToOidwFilterCheck(gi, oid); - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } bool CSeqDB::OidToGi(int oid, TGi & gi) const { - m_Impl->Verify(); + ////m_Impl->Verify(); TGi gi_tmp; bool rv = m_Impl->OidToGi(oid, gi_tmp); gi = gi_tmp; - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } bool CSeqDB::PigToGi(int pig, TGi & gi) const { - m_Impl->Verify(); + ////m_Impl->Verify(); bool rv = false; int oid(0); @@ -766,14 +744,14 @@ bool CSeqDB::PigToGi(int pig, TGi & gi) const rv = m_Impl->OidToGi(oid, gi_tmp); gi = gi_tmp; } - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } bool CSeqDB::GiToPig(TGi gi, int & pig) const { - m_Impl->Verify(); + ////m_Impl->Verify(); bool rv = false; int oid(0); @@ -782,14 +760,14 @@ bool CSeqDB::GiToPig(TGi gi, int & pig) const rv = m_Impl->OidToPig(oid, pig); } - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } void CSeqDB::AccessionToOids(const string & acc, vector & oids) const { - m_Impl->Verify(); + ////m_Impl->Verify(); m_Impl->AccessionToOids(acc, oids); // If we have a numeric ID and the search failed, try to look it @@ -813,19 +791,19 @@ void CSeqDB::AccessionToOids(const string & acc, vector & oids) const } } - m_Impl->Verify(); + ////m_Impl->Verify(); } void CSeqDB::SeqidToOids(const CSeq_id & seqid, vector & oids) const { - m_Impl->Verify(); + ////m_Impl->Verify(); m_Impl->SeqidToOids(seqid, oids, true); - m_Impl->Verify(); + ////m_Impl->Verify(); } bool CSeqDB::SeqidToOid(const CSeq_id & seqid, int & oid) const { - m_Impl->Verify(); + ////m_Impl->Verify(); bool rv = false; oid = -1; @@ -838,21 +816,16 @@ bool CSeqDB::SeqidToOid(const CSeq_id & seqid, int & oid) const oid = oids[0]; } - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } -void CSeqDB::SetMemoryBound(Uint8 membound, Uint8 slice_size) -{ - m_Impl->SetMemoryBound(membound); -} - int CSeqDB::GetOidAtOffset(int first_seq, Uint8 residue) const { - m_Impl->Verify(); + ////m_Impl->Verify(); int rv = m_Impl->GetOidAtOffset(first_seq, residue); - m_Impl->Verify(); + ////m_Impl->Verify(); return rv; } @@ -914,7 +887,7 @@ CSeqDBIter & CSeqDBIter::operator++() CRef CSeqDB::GiToBioseq(TGi gi) const { - m_Impl->Verify(); + ////m_Impl->Verify(); CRef bs; int oid(0); @@ -923,7 +896,7 @@ CSeqDB::GiToBioseq(TGi gi) const bs = m_Impl->GetBioseq(oid, gi, NULL, true); } - m_Impl->Verify(); + ////m_Impl->Verify(); return bs; } @@ -931,7 +904,7 @@ CSeqDB::GiToBioseq(TGi gi) const CRef CSeqDB::PigToBioseq(int pig) const { - m_Impl->Verify(); + ////m_Impl->Verify(); int oid(0); CRef bs; @@ -940,7 +913,7 @@ CSeqDB::PigToBioseq(int pig) const bs = m_Impl->GetBioseq(oid, ZERO_GI, NULL, true); } - m_Impl->Verify(); + ////m_Impl->Verify(); return bs; } @@ -948,7 +921,7 @@ CSeqDB::PigToBioseq(int pig) const CRef CSeqDB::SeqidToBioseq(const CSeq_id & seqid) const { - m_Impl->Verify(); + ////m_Impl->Verify(); vector oids; CRef bs; @@ -959,7 +932,7 @@ CSeqDB::SeqidToBioseq(const CSeq_id & seqid) const bs = m_Impl->GetBioseq(oids[0], ZERO_GI, &seqid, true); } - m_Impl->Verify(); + ////m_Impl->Verify(); return bs; } @@ -989,15 +962,15 @@ CSeqDB::FindVolumePaths(const string & dbname, void CSeqDB::FindVolumePaths(vector & paths, bool recursive) const { - m_Impl->Verify(); + ////m_Impl->Verify(); m_Impl->FindVolumePaths(paths, recursive); - m_Impl->Verify(); + ////m_Impl->Verify(); } void CSeqDB::GetGis(int oid, vector & gis, bool append) const { - m_Impl->Verify(); + ////m_Impl->Verify(); // This could be done a little faster at a lower level, but not // necessarily by too much. If this operation is important to @@ -1015,7 +988,7 @@ CSeqDB::GetGis(int oid, vector & gis, bool append) const } } - m_Impl->Verify(); + ////m_Impl->Verify(); } void CSeqDB::SetIterationRange(int oid_begin, int oid_end) @@ -1025,9 +998,9 @@ void CSeqDB::SetIterationRange(int oid_begin, int oid_end) void CSeqDB::GetAliasFileValues(TAliasFileValues & afv) { - m_Impl->Verify(); + ////m_Impl->Verify(); m_Impl->GetAliasFileValues(afv); - m_Impl->Verify(); + ////m_Impl->Verify(); } void CSeqDB::GetTaxInfo(int taxid, SSeqDBTaxInfo & info) @@ -1040,9 +1013,9 @@ void CSeqDB::GetTotals(ESummaryType sumtype, Uint8 * total_length, bool use_approx) const { - m_Impl->Verify(); + ////m_Impl->Verify(); m_Impl->GetTotals(sumtype, oid_count, total_length, use_approx); - m_Impl->Verify(); + ////m_Impl->Verify(); } const CSeqDBGiList * CSeqDB::GetGiList() const @@ -1055,11 +1028,6 @@ CSeqDBIdSet CSeqDB::GetIdSet() const return m_Impl->GetIdSet(); } -void CSeqDB::SetDefaultMemoryBound(Uint8 bytes) -{ - CSeqDBImpl::SetDefaultMemoryBound(bytes); -} - void CSeqDB::GetSequenceAsString(int oid, string & output, TSeqRange range /* = TSeqRange() */) const @@ -1225,24 +1193,19 @@ void CSeqDB::GetMaskData(int oid, #endif -void CSeqDB::GarbageCollect(void) -{ - m_Impl->GarbageCollect(); -} - void CSeqDB::SetOffsetRanges(int oid, const CSeqDB::TRangeList & offset_ranges, bool append_ranges, bool cache_data) { - m_Impl->Verify(); + ////m_Impl->Verify(); m_Impl->SetOffsetRanges(oid, offset_ranges, append_ranges, cache_data); - m_Impl->Verify(); + ////m_Impl->Verify(); } void CSeqDB::RemoveOffsetRanges(int oid) @@ -1258,7 +1221,7 @@ void CSeqDB::FlushOffsetRangeCache() void CSeqDB::SetNumberOfThreads(int num_threads, bool force_mt) { - m_Impl->Verify(); + ////m_Impl->Verify(); m_Impl->SetNumberOfThreads(num_threads, force_mt); } @@ -1399,13 +1362,6 @@ FindBlastDBs(const string& path, const string& dbtype, bool recurse, return dbfinder.m_DBs; } -Int8 CSeqDB::GetSliceSize() const -{ - m_Impl->Verify(); - - return m_Impl->GetSliceSize(); -} - Int8 CSeqDB::GetDiskUsage() const { vector paths; @@ -1483,96 +1439,11 @@ bool DeleteBlastDb(const string& dbpath, CSeqDB::ESeqType seq_type) const char* CSeqDB::kBlastDbDateFormat = "b d, Y H:m P"; -set -CWgsDbTrimmer::x_ExtractOriginalWgsDbs() -{ - vector orig_wgs_dbs; - NStr::Split(m_OrigWgsList, " ", orig_wgs_dbs, NStr::fSplit_NoMergeDelims); - set retval; - copy(orig_wgs_dbs.begin(), orig_wgs_dbs.end(), inserter(retval, - retval.begin())); - return retval; -} - -CWgsDbTrimmer::CWgsDbTrimmer(const string& wgs_db_list) - : m_OrigWgsList(wgs_db_list) -{ - CMutexGuard guard(CNcbiApplication::GetInstanceMutex()); - CNcbiApplication* app = CNcbiApplication::Instance(); - if (app) { - m_Path = app->GetEnvironment().Get("WGS_GILIST_DIR"); - } -} - -CWgsDbTrimmer::TGiLists -CWgsDbTrimmer::x_ReadGiListsForDbs() +void CSeqDB::DebugDump(CDebugDumpContext ddc, unsigned int depth) const { - TGiLists retval; - if (m_Path.empty()) { - return retval; - } - - set orig_wgs_dbs = x_ExtractOriginalWgsDbs(); - if ( !orig_wgs_dbs.empty() ) { - const string kExtn = ".gil"; - ITERATE(set, wgs_db_name, orig_wgs_dbs) { - CNcbiOstrstream oss; - oss << m_Path << "/" << CDirEntry(*wgs_db_name).GetName() << kExtn; - string fname = CNcbiOstrstreamToString(oss); - vector gis; - try { - bool in_order = false; - SeqDB_ReadGiList(fname, gis, &in_order); - if ( !in_order ) { - sort(gis.begin(), gis.end()); - } - } catch (...) {} // if there's no GI list, save it - vector& dst = retval[*wgs_db_name]; - dst.clear(); - ITERATE ( vector, it, gis ) { - dst.push_back(*it); - } - _TRACE("Read " << gis.size() << " from " << fname); - } - } - return retval; -} - -string CWgsDbTrimmer::GetDbList() -{ - TGiLists wgs_gi_lists = x_ReadGiListsForDbs(); - if (wgs_gi_lists.empty()) { - // no GI lists were found in WGS_GILIST_DIR, we can't do anything - return m_OrigWgsList; - } - set trimmed_wgs_dbs; - ITERATE(set, gi, m_Gis) { - if (wgs_gi_lists.empty()) { - break; - } - NON_CONST_ITERATE(TGiLists, gis4wgs_db, wgs_gi_lists) { - const string& wgs_db_name = gis4wgs_db->first; - const vector& wgs_gis = gis4wgs_db->second; - if (find(wgs_gis.begin(), wgs_gis.end(), *gi) != wgs_gis.end()) { - trimmed_wgs_dbs.insert(wgs_db_name); - wgs_gi_lists.erase(wgs_db_name); - break; - } - } - } - ITERATE(TGiLists, gis4wgs_db, wgs_gi_lists) { - const string& wgs_db_name = gis4wgs_db->first; - const vector& wgs_gis = gis4wgs_db->second; - if (wgs_gis.empty()) { - trimmed_wgs_dbs.insert(wgs_db_name); - } - } - - CNcbiOstrstream oss; - ITERATE(set, wgs_db, trimmed_wgs_dbs) { - oss << *wgs_db << " "; - } - return NStr::TruncateSpaces(CNcbiOstrstreamToString(oss)); + ddc.SetFrame("CSeqDB"); + CObject::DebugDump(ddc, depth); + ddc.Log("m_Impl", m_Impl, depth); } END_NCBI_SCOPE diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbalias.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbalias.cpp index c982d91c..3803db9d 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbalias.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbalias.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbalias.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: seqdbalias.cpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -108,7 +108,7 @@ CSeqDBAliasNode::CSeqDBAliasNode(CSeqDBAtlas & atlas, m_ExpandLinks(expand_links) { CSeqDBLockHold locked(atlas); - m_Atlas.Verify(locked); + m_Values["DBLIST"] = dbname_list; @@ -125,7 +125,7 @@ CSeqDBAliasNode::CSeqDBAliasNode(CSeqDBAtlas & atlas, x_ExpandAliases(CSeqDB_BasePath("-"), prot_nucl, recurse, locked); - m_Atlas.Unlock(locked); + _ASSERT(recurse.Size() == 0); @@ -550,12 +550,13 @@ void CSeqDBAliasSets::x_ReadAliasSetFile(const CSeqDB_Path & aset_path, { string key("ALIAS_FILE"); - CSeqDBMemLease lease(m_Atlas); + CSeqDBFileMemMap lease(m_Atlas,aset_path.GetPathS()); - CSeqDBAtlas::TIndx length(0); - m_Atlas.GetFile(lease, aset_path, length, locked); + CSeqDBAtlas::TIndx length(0); + m_Atlas.GetFileSizeL(aset_path.GetPathS(), length); - const char * bp = lease.GetPtr(0); + const char * bp = lease.GetFileDataPtr(0); + const char * ep = bp + (size_t) length; vector offsets; @@ -589,9 +590,7 @@ void CSeqDBAliasSets::x_ReadAliasSetFile(const CSeqDB_Path & aset_path, group[value].assign(offsets[i+1], offsets[i+2]); } - } - - m_Atlas.RetRegion(lease); + } } @@ -610,7 +609,7 @@ bool CSeqDBAliasSets::ReadAliasFile(const CSeqDB_Path & dbpath, // Check whether we already have this combined alias file. if (m_Groups.find(aset_path.GetPathS()) == m_Groups.end()) { - if (! m_Atlas.DoesFileExist(aset_path, locked)) { + if (! m_Atlas.DoesFileExist(aset_path)) { return false; } @@ -650,7 +649,7 @@ bool CSeqDBAliasSets::ReadAliasFile(const CSeqDB_Path & dbpath, } -void CSeqDBAliasNode::x_ReadAliasFile(CSeqDBMemLease & lease, +void CSeqDBAliasNode::x_ReadAliasFile(CSeqDBFileMemMap & lease, const CSeqDB_Path & path, const char ** bp, const char ** ep, @@ -662,9 +661,9 @@ void CSeqDBAliasNode::x_ReadAliasFile(CSeqDBMemLease & lease, if (! has_group_file) { CSeqDBAtlas::TIndx length(0); - m_Atlas.GetFile(lease, path, length, locked); - *bp = lease.GetPtr(0); + m_Atlas.GetFileSizeL(path.GetPathS(), length); + *bp = lease.GetFileDataPtr(0); *ep = (*bp) + length; } } @@ -673,9 +672,8 @@ void CSeqDBAliasNode::x_ReadAliasFile(CSeqDBMemLease & lease, void CSeqDBAliasNode::x_ReadValues(const CSeqDB_Path & path, CSeqDBLockHold & locked) { - m_Atlas.Lock(locked); - - CSeqDBMemLease lease(m_Atlas); + + CSeqDBFileMemMap lease(m_Atlas,path.GetPathS()); const char * bp(0); const char * ep(0); @@ -708,9 +706,7 @@ void CSeqDBAliasNode::x_ReadValues(const CSeqDB_Path & path, } p = eolp + 1; - } - - m_Atlas.RetRegion(lease); + } } @@ -820,7 +816,7 @@ void CSeqDBAliasNode::x_ExpandAliases(const CSeqDB_BasePath & this_name, // of the individual ones, build a subnode. if ( m_AliasSets.FindAliasPath(new_db_path, 0, locked) || - m_Atlas.DoesFileExist(new_db_path, locked) ) { + m_Atlas.DoesFileExist(new_db_path) ) { x_AppendSubNode(base, prot_nucl, recurse, locked); continue; @@ -838,7 +834,7 @@ void CSeqDBAliasNode::x_ExpandAliases(const CSeqDB_BasePath & this_name, CSeqDB_BasePath local_base((CSeqDB_DirName(CDir::GetCwd())), CSeqDB_BaseName(m_DBList[i].FindBaseName())); CSeqDB_Path new_local_vol_path(local_base, prot_nucl, 'i', 'n' ); - if (m_Atlas.DoesFileExist(new_local_vol_path, locked)) { + if (m_Atlas.DoesFileExist(new_local_vol_path)) { bp = CSeqDB_BasePath(new_local_vol_path.FindBasePath()); found = true; } @@ -846,7 +842,7 @@ void CSeqDBAliasNode::x_ExpandAliases(const CSeqDB_BasePath & this_name, if (!found) { CSeqDB_Path new_vol_path( base, prot_nucl, 'i', 'n' ); - if (m_Atlas.DoesFileExist(new_vol_path, locked)) { + if (m_Atlas.DoesFileExist(new_vol_path)) { bp = CSeqDB_BasePath(new_db_path.FindBasePath() ); found = true; } @@ -891,9 +887,9 @@ void CSeqDBAliasNode::x_ExpandAliases(const CSeqDB_BasePath & this_name, CSeqDB_Path new_alias( result, prot_nucl, 'a', 'l' ); CSeqDB_Path new_volume( result, prot_nucl, 'i', 'n' ); - if (m_Atlas.DoesFileExist(new_alias, locked)) { + if (m_Atlas.DoesFileExist(new_alias)) { x_AppendSubNode( result, prot_nucl, recurse, locked ); - } else if (m_Atlas.DoesFileExist(new_volume, locked)) { + } else if (m_Atlas.DoesFileExist(new_volume)) { string normal_name; if (m_ExpandLinks) { // normalize this_name @@ -1838,6 +1834,34 @@ CRef CSeqDBAliasFile::GetFilterTree() return m_TopTree; } +void +CSeqDBAliasFile::DebugDump(CDebugDumpContext ddc, unsigned int depth) const +{ + ddc.SetFrame("CSeqDBAliasFile"); + CObject::DebugDump(ddc, depth); + for (SIZE_TYPE i = 0; i < m_VolumeNames.size(); i++) { + ddc.Log("m_VolumeNames[" + NStr::SizetToString(i) + "]", + m_VolumeNames[i]); + } + for (SIZE_TYPE i = 0; i < m_AliasNames.size(); i++) { + ddc.Log("m_AliasNames[" + NStr::SizetToString(i) + "]", + m_AliasNames[i]); + } + ddc.Log("m_IsProtein", m_IsProtein); + ddc.Log("m_MinLength", m_MinLength); + ddc.Log("m_NumSeqs", m_NumSeqs); + ddc.Log("m_NumSeqsStats", m_NumSeqsStats); + ddc.Log("m_NumOIDs", m_NumOIDs); + ddc.Log("m_TotalLength", m_TotalLength); + ddc.Log("m_TotalLengthStats", m_TotalLengthStats); + ddc.Log("m_VolumeLength", m_VolumeLength); + ddc.Log("m_MembBit", m_MembBit); + ddc.Log("m_HasTitle", m_HasTitle); + ddc.Log("m_Title", m_Title); + ddc.Log("m_NeedTotalsScan", m_NeedTotalsScan); + ddc.Log("m_HasFilters", m_HasFilters); +} + void CSeqDBAliasNode::ComputeMasks(bool & has_filters) { if (! m_NodeMasks.empty()) { diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbalias.hpp b/c++/src/objtools/blast/seqdb_reader/seqdbalias.hpp index b0fb2326..2b5a8b33 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbalias.hpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbalias.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBALIAS_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBALIAS_HPP -/* $Id: seqdbalias.hpp 398155 2013-05-03 11:37:45Z camacho $ +/* $Id: seqdbalias.hpp 530464 2017-03-15 14:36:01Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -882,7 +882,7 @@ private: /// /// Fetches the lines belonging to an alias file, either directly /// or via a combined alias file. - void x_ReadAliasFile(CSeqDBMemLease & lease, + void x_ReadAliasFile(CSeqDBFileMemMap & lease, const CSeqDB_Path & fname, const char ** bp, const char ** ep, @@ -973,7 +973,7 @@ private: /// functionality to classes like CSeqDBImpl (and others) that do not /// need to understand alias walkers, nodes, and tree traversal. -class CSeqDBAliasFile : CObject { +class CSeqDBAliasFile : public CObject { /// Import type to allow shorter name. typedef TSeqDBAliasFileValues TAliasFileValues; @@ -1246,6 +1246,10 @@ public: m_Node->GetMaskList(mask_list); } + /// Dump debug information for this object + /// @sa CDebugDumpable + void DebugDump(CDebugDumpContext ddc, unsigned int depth) const; + private: /// Compute filtering options for all volumes. /// diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbatlas.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbatlas.cpp index d6bc86a3..bef4cd3b 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbatlas.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbatlas.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbatlas.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: seqdbatlas.cpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -184,35 +184,30 @@ TOut SeqDB_CheckLength(TIn value) } CSeqDBAtlas::CSeqDBAtlas(bool use_mmap) - : m_UseMmap (use_mmap), - m_CurAlloc (0), + :m_CurAlloc (0), m_LastFID (0), - m_OpenRegionsTrigger(CSeqDBMapStrategy::eOpenRegionsWindow), - m_MaxFileSize (0), - m_Strategy (*this), + m_MaxFileSize (0), m_SearchPath (GenerateSearchPath()) { - for(int i = 0; i < eNumRecent; i++) { - m_Recent[i] = 0; - } - Verify(true); + m_Alloc = false; + m_OpenedFilesCount = 0; + m_MaxOpenedFilesCount = 0; } CSeqDBAtlas::~CSeqDBAtlas() { - Verify(true); - x_GarbageCollect(0); - - // Clear mapped file regions - - if ((! m_Regions.empty()) || (m_CurAlloc != 0)) { - if (! m_Regions.empty()) { - ShowLayout(true, 0); - } - - _ASSERT(m_Regions.empty()); - _ASSERT(m_CurAlloc == 0); + //int openedFilesCount = GetOpenedFilseCount(); + //cerr << "********Before Cleaning: openedFilesCount=" << openedFilesCount << endl; + for (map::iterator it=m_FileMemMap.begin(); it!=m_FileMemMap.end(); ++it) { + string filename = it->first; + it->second->Unmap(); + //ChangeOpenedFilseCount(eFileCounterDecrement); + //cerr << "********Cleaning:Unmap CMemoryFile:" << filename << endl; + delete it->second; } + //openedFilesCount = GetOpenedFilseCount(); + //cerr << "********After Cleaning: openedFilesCount=" << openedFilesCount << " maxOpenedFilesCount="<< m_MaxOpenedFilesCount << endl; + // For now, and maybe permanently, enforce balance. @@ -230,91 +225,16 @@ CSeqDBAtlas::~CSeqDBAtlas() bool CSeqDBAtlas::DoesFileExist(const string & fname, CSeqDBLockHold & locked) { - Verify(locked); TIndx length(0); return GetFileSize(fname, length, locked); } -const char * CSeqDBAtlas::GetFile(const string & fname, - TIndx & length, - CSeqDBLockHold & locked) -{ - Verify(locked); - if (! GetFileSize(fname, length, locked)) { - s_SeqDB_FileNotFound(fname); - } - - // If allocating more than 256MB in a file, do a full sweep first. - // This technique may help prevent unnecessary fragmentation. - // How? Well, it's kind of a fudge, really: before allocating - // anything really big, we want to clean memory as much as - // possible. - // - // Essentially, big objects can fail due to fragmentation, even if - // we are well below the memory bound. So if there is a big spot - // where this new allocation may fit, we want to remove any small - // objects from it first. When I mention fragmentation here, I - // mean "you have 1.3 GB of address space left, but no piece - // bigger than .75 GB". Memory mapping is sensitive to this - // because it needs huge contiguous chunks of sizes that are not - // aligned. - // - // It should be mentioned that this will not (greatly) affect - // users who are using the round-to-chunk-size allocator. - - if (TIndx(length) > m_Strategy.GetGCTriggerSize()) { - Lock(locked); - x_GarbageCollect(0); - } - - return GetRegion(fname, 0, length, locked); -} - -void CSeqDBAtlas::GetFile(CSeqDBMemLease & lease, - const string & fname, - TIndx & length, - CSeqDBLockHold & locked) -{ - if (! GetFileSize(fname, length, locked)) { - s_SeqDB_FileNotFound(fname); - } - - // If allocating more than 256MB in a file, do a full sweep first. - // This technique may help prevent unnecessary fragmentation. - // How? Well, it's kind of a fudge, really: before allocating - // anythin humongous, we want to clean memory as much as possible. - // - // Essentially, big objects can fail due to fragmentation, even if - // we are well below the memory bound. So if there is a big spot - // where this new allocation may fit, we want to remove any small - // objects from it first. When I mention fragmentation here, I - // mean "you have 1.3 GB of address space left, but no piece - // bigger than .75 GB". Memory mapping is sensitive to this - // because it needs huge contiguous chunks of sizes that are not - // aligned. - // - // It should be mentioned that this will not (greatly) affect - // users who are using the round-to-chunk-size allocator. - // - // Also, for systems with (e.g.) 64 bit address spaces, this - // could/should be relaxed, to require less mapping. - - if (length > m_Strategy.GetGCTriggerSize()) { - GarbageCollect(locked); - } - - Lock(locked); - Verify(true); - - GetRegion(lease, fname, 0, length); -} - bool CSeqDBAtlas::GetFileSize(const string & fname, TIndx & length, CSeqDBLockHold & locked) { Lock(locked); - Verify(true); + return GetFileSizeL(fname, length); } @@ -322,7 +242,7 @@ bool CSeqDBAtlas::GetFileSize(const string & fname, bool CSeqDBAtlas::GetFileSizeL(const string & fname, TIndx & length) { - Verify(true); + // Fields: file-exists, file-length pair data; @@ -346,371 +266,12 @@ bool CSeqDBAtlas::GetFileSizeL(const string & fname, } else { data = (*i).second; } - Verify(true); + length = data.second; return data.first; } -void CSeqDBAtlas::GarbageCollect(CSeqDBLockHold & locked) -{ - Lock(locked); - x_GarbageCollect(0); -} - -void CSeqDBAtlas::x_GarbageCollect(Uint8 reduce_to) -{ - Verify(true); - if (Uint8(m_CurAlloc) <= reduce_to) { - return; - } - - x_FlushAll(); - - x_ClearRecent(); - - int max_distinct_clock = 10; - - int num_gcs = 1; - - if (reduce_to > 0) { - TIndx in_use = m_CurAlloc; - - for(unsigned i = 0; i < m_Regions.size(); i++) { - CRegionMap * mr = m_Regions[i]; - - if (! mr->InUse()) { - mr->BumpClock(); - in_use -= mr->Length(); - } - - num_gcs = ((num_gcs > mr->GetClock()) - ? num_gcs - : mr->GetClock()); // max - } - - num_gcs = 1 + ((num_gcs < max_distinct_clock) - ? num_gcs - : max_distinct_clock); //min - } - - Verify(true); - while(num_gcs >= 0) { - num_gcs --; - - size_t i = 0; - - while(i < m_Regions.size()) { - CRegionMap * mr = m_Regions[i]; - - if (mr->InUse() || mr->GetClock() < num_gcs) { - i++; - continue; - } - - size_t last = m_Regions.size() - 1; - - if (i != last) { - m_Regions[i] = m_Regions[last]; - } - - m_Regions.pop_back(); - - m_CurAlloc -= mr->Length(); - - m_NameOffsetLookup.erase(mr); - m_AddressLookup.erase(mr->Data()); - - delete mr; - - if (Uint8(m_CurAlloc) < reduce_to) { - return; - } - } - } - Verify(true); -} - - -// Algorithm: -// -// In file mode, get exactly what we need. Otherwise, if the request -// fits entirely into one slice, use large slice rounding (get large -// pieces). If it is on a large slice boundary, use small slice -// rounding (get small pieces). - - -// Rationale: -// -// We would like to map all data using the same slice size, and in -// practice, 99% of the objects *will* fall entirely within the large -// slice boundaries. But for cases where they do not, we have several -// strategies. -// -// The simplest is to round both boundaries out to large slices, -// making a double-wide slice. The problem with this is that in a -// straight-through traversal, every large slice will be mapped twice, -// because each overlap case will cause a mapping of one already -// mapped large slice (the most recent one) and one not-yet mapped -// slice (the one after it). -// -// Instead, I am using two strategies to avoid this phenomena. The -// first is the use of one large slice size and one small slice size. -// Boundary cases (including any object not fitting in one slice) will -// be rounded out to the smaller slice size. This solves the problem -// of the boundary case: the small allocations will only cause a -// minimal "duplication" of the mapped area. -// -// The memory layout pattern due to the previous technique will -// alternate between short and long slices, with each short slice -// echoing the end and beginning of the slices before and after it, -// respectively. The short slices represent redundant mapping. To -// prevent the proliferation of short slices, there is a second -// technique to preferentially remove "irregular" sequences. -// -// Each mapping also gets a "penalty" value: the value is added to the -// "clock" value when considering mappings for garbage collection. -// The fragmentation is least when all the sequences are the same -// size. The penalty value is 0 for mappings of size "slice", 1 for -// mappings of size "small slice" or "small slice * 2", and 2 for -// mappings that do not correspond to any slice size, i.e. the "tail" -// portion of a file, or whole mappings of short files. (KMB) - -void CRegionMap::x_Roundup(TIndx & begin, - TIndx & end, - int & penalty, - TIndx file_size, - bool use_mmap, - CSeqDBAtlas * atlas) -{ - // These should be made available to some kind of interface to - // allow memory-usage tuning. - - const TIndx block_size = 1024 * 512; - TIndx large_slice = (size_t)atlas->GetSliceSize(); - TIndx overhang = (size_t)atlas->GetOverhang(); - TIndx small_slice = (size_t)large_slice / 16; - - if (small_slice < block_size) { - small_slice = block_size; - } - - if (large_slice < small_slice) { - large_slice = small_slice * 16; - } - - _ASSERT(begin < end); - SEQDB_FILE_ASSERT(end <= file_size); - - penalty = 0; - - TIndx align = 1; - - if (use_mmap) { - TIndx page_b = begin / large_slice; - TIndx page_e = end / large_slice; - - if (page_b == page_e) { - align = large_slice; - penalty = 0; - } else { - if ((end-begin) < (small_slice * 2)) { - penalty = 1; - } else { - penalty = 2; - } - - align = small_slice; - } - } else { - // File mode, align to block. (This only helps if there are - // other sequences completely included in the same blocks that - // interest us.) - - penalty = 2; - align = block_size; - - // Also, do not use overhang logic, because the overhang size - // is tuned for the memory mapping case. - - overhang = 0; - } - - if (align > 1) { - // Integer math can do the rounding. - - TIndx new_begin = (begin / align) * align; - TIndx new_end = ((end + align - 1) / align) * align + overhang; - - // If there is less than a third of a slice left, grab it all. - if ((new_end + (align/3)) > file_size) { - new_end = file_size; - penalty = 2; - } - - _ASSERT(new_begin <= begin); - _ASSERT(new_end >= end ); - - begin = new_begin; - end = new_end; - } - - // Should be true on all architectures now, due to the CMemoryFile - // map/segment work. - - bool have_range_mmap = true; - - if (! have_range_mmap) { - begin = 0; - end = file_size; - - // This code biases larger items to last longer, ie to garbage - // collect irregular or short items first. This is basically - // an "intuitive" decision on my part, intended to improve - // memory layout (i.e. to decrease the occurrence of internal - // memory fragmentation), which in most cases can be seen as - // fragmentation of large areas by small elements. [Note that - // the effectiveness of this technique on reducing internal - // fragmentation has not been measured.] - - // In theory, no memory management strategy that provides - // different sized blocks can guarantee a reasonable upper - // bound on memory exhaustion from internal fragmentation. - // (An exception would be systems with memory compaction, - // which is normally considered infeasible for languages like - // C.) Also, These concerns probably have little significance - // on a 64 bit memory architecture, since the access patterns - // that cause internal fragmentation involve alternating maps - // and unmaps, and a 64 bit system will normally not need to - // unmap files. - - penalty = ((file_size > (large_slice+overhang)) - ? 0 - : 1); - } -} - -const char * CSeqDBAtlas::x_FindRegion(int fid, - TIndx & begin, - TIndx & end, - const char ** start, - CRegionMap ** region) -{ - Verify(true); - - // Try recent matches first. - - for(int i = 0; iMatchAndUse(fid, begin, end, start); - - if (retval) { - // Moves region to top - if (region) { - *region = m_Recent[i]; - } - - if (i) { - x_AddRecent(m_Recent[i]); - } - - _ASSERT(*start); - return retval; - } - } - - if (m_NameOffsetLookup.empty()) { - return 0; - } - - // Start key - will be used to find the least element that is NOT - // good enough. We want the elements before this to have - - CRegionMap key(0, fid, begin, end); - - TNameOffsetTable::iterator iter - = m_NameOffsetLookup.upper_bound(& key); - - while(iter != m_NameOffsetLookup.begin()) { - --iter; - - if ((*iter)->Fid() != fid) - return 0; - - CRegionMap * rmap = *iter; - - // Should be guaranteed by the ordering we are using. - _ASSERT(rmap->Begin() <= begin); - - if (rmap->End() >= end) { - const char * retval = rmap->MatchAndUse(fid, begin, end, start); - _ASSERT(retval); - _ASSERT(*start); - - if (region) { - *region = rmap; - } - - x_AddRecent(rmap); - return retval; - } - } - Verify(true); - - return 0; -} - -// Assumes locked. - -void CSeqDBAtlas::PossiblyGarbageCollect(Uint8 space_needed, bool returning) -{ - Verify(true); - - if ((int) m_Regions.size() >= m_OpenRegionsTrigger) { - // If we are collecting because of the number of open regions, - // we use zero as the size. This kind of flush is probably - // due to extensive alias node forests, and it is better to - // clear cut than try to take only old-growth. Alias files - // are only read once, so caching would only help if there is - // overlap between subtrees. - - // The mechanism uses three numbers. MAX is a constant - // expressing the most regions you ever want to have open. - // WINDOW is a constant expressing the number of regions you - // want to be able to open without a garbage collection being - // triggered. TRIGGER is the number of regions creations that - // will trigger the next full garbage collection. - - // 1. In the constructor, TRIGGER is set to WINDOW. - // - // 2. If the number of regions exceeds TRIGGER, a full - // collection is done. - // - // 3. After each full collection, TRIGGER is set to the lesser - // of the number of surviving regions plus WINDOW, or MAX. - - x_GarbageCollect(0); - - int window = CSeqDBMapStrategy::eOpenRegionsWindow; - int maxopen = CSeqDBMapStrategy::eMaxOpenRegions; - - m_OpenRegionsTrigger = min(int(m_Regions.size() + window), maxopen); - } else { - // Use Int8 to avoid "unsigned rollunder" - - Int8 bound = m_Strategy.GetMemoryBound(returning); - Int8 capacity_left = bound - m_CurAlloc; - - if (Int8(space_needed) > capacity_left) { - x_GarbageCollect(bound - space_needed); - } - } - - Verify(true); -} - /// Simple idiom for RIIA with malloc + free. struct CSeqDBAutoFree { /// Constructor. @@ -738,297 +299,21 @@ private: const char * m_Array; }; -const char * -CSeqDBAtlas::x_GetRegion(const string & fname, - TIndx & begin, - TIndx & end, - const char ** start, - CRegionMap ** rmap) -{ - _ASSERT(fname.size()); - - Verify(true); - - const char * dummy = 0; - - if (start == 0) { - start = & dummy; - } - - _ASSERT(end > begin); - - const string * strp = 0; - - int fid = x_LookupFile(fname, & strp); - - const char * retval = 0; - - if ((retval = x_FindRegion(fid, begin, end, start, rmap))) { - _ASSERT(*start); - return retval; - } - - // Need to add the range, so GC first. - - PossiblyGarbageCollect(end - begin, false); - - CRegionMap * nregion = 0; - - try { - nregion = new CRegionMap(strp, fid, begin, end); - - // new() should have thrown, but some old implementations are - // said to be non-compliant in this regard: - - if (! nregion) { - throw std::bad_alloc(); - } - - auto_ptr newmap(nregion); - - if (rmap) - *rmap = nregion; - - if (m_UseMmap) { - for(int fails = 0; fails < 2; fails++) { - CSeqDBAutoFree shim; - - bool worked = true; - - try { - // On Linux, allocate 10 MB of (non-initialized!) - // memory. The goal is to cause memory shortages - // to happen in SeqDB rather than in client code, - // so that SeqDB can adjust its parameters to free - // up memory. This reduces errors and improves - // performance on Linux, but not on other O/Ses; - // See also comments in SeqDBMapStrategy. - - const char * a = 0; - - if (CSeqDBMapStrategy::e_ProbeMemory) { - a = (const char*) malloc(10 << 20); - - if (! a) { - worked = false; - } - - shim.Set(a); - } - } - catch(...) { - // allocation failure; reduce - worked = false; - } - - if (worked) { - if (newmap->MapMmap(this)) { - retval = newmap->Data(begin, end); - newmap->AddRef(); - - if (retval == 0) { - worked = false; - } - } else { - worked = false; - } - } - - if (worked) { - break; - } - - // If there was a map (or new[]) failure, tell the - // strategy module and wipe out half of the allocated - // memory bound. - - m_Strategy.MentionMapFailure(m_CurAlloc); - x_GarbageCollect(m_CurAlloc/2); - } - } - - // mmap() sometimes fails for no discernable reason.. if it - // does, try reading the file. - - if (retval == 0 && newmap->MapFile(this)) { - retval = newmap->Data(begin, end); - newmap->AddRef(); - } - - m_NameOffsetLookup.insert(nregion); - - newmap->GetBoundaries(start, begin, end); - - if (retval == 0) { - s_SeqDB_FileNotFound(fname); - } - - m_AddressLookup[nregion->Data()] = nregion; - - m_CurAlloc += (end-begin); - - CRegionMap * nmp = newmap.release(); - - _ASSERT(nmp); - - m_Regions.push_back(nmp); - } - catch(std::bad_alloc) { - if (m_NameOffsetLookup.find(nregion) != m_NameOffsetLookup.end()) { - m_NameOffsetLookup.erase(nregion); - } - - SeqDB_ThrowException(CSeqDBException::eMemErr, - "CSeqDBAtlas::x_GetRegion: allocation failed."); - } - - // Collect down to 'retbound' amount. - PossiblyGarbageCollect(0, true); - - Verify(true); - - return retval; -} - -const char * CSeqDBAtlas::GetRegion(const string & fname, - TIndx begin, - TIndx end, - CSeqDBLockHold & locked) -{ - Lock(locked); - Verify(true); - - return x_GetRegion(fname, begin, end, 0, 0); -} - -// Assumes lock is held. -void CSeqDBAtlas::GetRegion(CSeqDBMemLease & lease, - const string & fname, - TIndx begin, - TIndx end) -{ - Verify(true); - RetRegion(lease); - - const char * start(0); - CRegionMap * rmap(0); - - const char * result = x_GetRegion(fname, begin, end, & start, & rmap); - - if (result) { -#ifdef _DEBUG - if (! (start)) { - cout << "fname [" << fname << "] begin " << begin << " end " << end - << " start " << size_t(start) << " result " << size_t(result) - << " rmap " << static_cast(rmap) << endl; - } -#endif - _ASSERT(start); - - lease.x_SetRegion(begin, end, start, rmap); - } - Verify(true); -} - -// Assumes lock is held -/// Releases a hold on a partial mapping of the file. -void CSeqDBAtlas::RetRegion(CSeqDBMemLease & ml) -{ - Verify(true); - if (ml.m_Data) { -#ifdef _DEBUG - const char * datap = ml.m_Data; - if (! ml.m_RMap) { - cout << "m_RMap is null" << endl; - } - if (! ml.m_RMap->InRange(datap)) { - cout << "datap not in range; datap = " << ((size_t)(datap)) << endl; - cout << "datap not in range; m.data = " << ((size_t)(ml.m_RMap->Data())) << endl; - cout << "datap not in range; begin = " << ((size_t)(ml.m_RMap->Data() + ml.m_RMap->Begin())) << endl; - cout << "datap not in range; begin = " << ((size_t)(ml.m_RMap->Data() + ml.m_RMap->End())) << endl; - } -#endif - _ASSERT(ml.m_RMap); - _ASSERT(ml.m_RMap->InRange(datap)); - - ml.m_RMap->RetRef(); - - ml.m_Data = 0; - ml.m_Begin = 0; - ml.m_End = 0; - } - Verify(true); -} -/// Releases a hold on a partial mapping of the file. -void CSeqDBAtlas::x_RetRegionNonRecent(const char * datap) +/// Releases allocated memory +void CSeqDBAtlas::x_RetRegion(const char * datap) { - Verify(true); - CSeqDBAtlas::TAddressTable::iterator iter = m_AddressLookup.upper_bound(datap); - - if (iter != m_AddressLookup.begin()) { - --iter; - - CRegionMap * rmap = (*iter).second; - - if (rmap->InRange(datap)) { - x_AddRecent(rmap); - rmap->RetRef(); - return; - } - } - + bool worked = x_Free(datap); _ASSERT(worked); if (! worked) { cerr << "Address leak in CSeqDBAtlas::RetRegion" << endl; } - Verify(true); -} -void CSeqDBAtlas::ShowLayout(bool locked, TIndx index) -{ - // This odd looking construction is for debugging existing - // binaries with the help of a debugger. By setting the static - // value (in the debugger) the user can override the default - // behavior (whichever is compiled in). - - static int enabled = 0; - -#ifdef _DEBUG -#ifdef VERBOSE - if (enabled == 0) { - enabled = 1; - } -#endif -#endif - - if (enabled == 1) { - if (! locked) { - m_Lock.Lock(); - } - - // MSVC cannot use Uint8 here... as in "ostream << [Uint8]". - - cerr << "\n\nShowing layout (index " << NStr::UInt8ToString((Uint8)index) - << "), current alloc = " << m_CurAlloc << endl; - - for(unsigned i = 0; i < m_Regions.size(); i++) { - m_Regions[i]->Show(); - } - - cerr << "\n\n" << endl; - - if (! locked) { - m_Lock.Unlock(); - } - } } -// This does not attempt to garbage collect, but it will influence -// garbage collection if it is used enough. char * CSeqDBAtlas::Alloc(size_t length, CSeqDBLockHold & locked, bool clear) { @@ -1069,7 +354,8 @@ char * CSeqDBAtlas::Alloc(size_t length, CSeqDBLockHold & locked, bool clear) m_Pool[newcp] = length; m_CurAlloc += length; - + m_Alloc = true; + //cerr << "allocated " << m_CurAlloc << " memory" << endl; return newcp; } @@ -1091,6 +377,7 @@ void CSeqDBAtlas::Free(const char * freeme, CSeqDBLockHold & locked) bool CSeqDBAtlas::x_Free(const char * freeme) { + if(!m_Alloc) return true; TPoolIter i = m_Pool.find((const char*) freeme); if (i == m_Pool.end()) { @@ -1100,8 +387,9 @@ bool CSeqDBAtlas::x_Free(const char * freeme) size_t sz = (*i).second; _ASSERT(m_CurAlloc >= (TIndx)sz); - m_CurAlloc -= sz; - + m_CurAlloc -= sz; + //cerr << "deallocated " << sz << " memory m_CurAlloc=" << m_CurAlloc << endl; + if(m_CurAlloc == 0) m_Alloc = false; char * cp = (char*) freeme; delete[] cp; m_Pool.erase(i); @@ -1109,313 +397,7 @@ bool CSeqDBAtlas::x_Free(const char * freeme) return true; } -// Assumes lock is held. - -void CRegionMap::Show() -{ - CHECK_MARKER(); - // This odd looking construction is for debugging existing - // binaries with the help of a debugger. By setting the static - // value (in the debugger) the user can override the default - // behavior (whichever is compiled in). - - static int enabled = 0; - -#ifdef _DEBUG -#ifdef VERBOSE - if (enabled == 0) { - enabled = 1; - } -#endif -#endif - - if (enabled == 1) { - cout << " [" << static_cast(m_Data) << "]-[" - << static_cast(m_Data + m_End - m_Begin) << "]: " - << *m_Fname << ", ref=" << m_Ref << " size=" << (m_End - m_Begin) << endl; - } -} - -EMemoryAdvise CRegionMap::sm_MmapStrategy_Index = eMADV_Normal; - -EMemoryAdvise CRegionMap::sm_MmapStrategy_Sequence = eMADV_Normal; - -CRegionMap::CRegionMap(const string * fname, int fid, TIndx begin, TIndx end) - : m_Data (0), - m_MemFile (0), - m_Fname (fname), - m_Begin (begin), - m_End (end), - m_Fid (fid), - m_Ref (0), - m_Clock (0), - m_Penalty (0) -{ - INIT_CLASS_MARK(); - CHECK_MARKER(); -} - -CRegionMap::~CRegionMap() -{ - CHECK_MARKER(); - - if (m_MemFile) { - delete m_MemFile; - m_MemFile = 0; - m_Data = 0; - } - if (m_Data) { - delete[] ((char*) m_Data); - m_Data = 0; - } - BREAK_MARKER(); -} - -bool CRegionMap::MapMmap(CSeqDBAtlas * atlas) -{ - CHECK_MARKER(); - bool rv = false; - - TIndx flength(0); - bool file_exists = atlas->GetFileSizeL(*m_Fname, flength); - - if (file_exists) { - string expt; - - try { - m_MemFile = new CMemoryFileMap(*m_Fname, - CMemoryFileMap::eMMP_Read, - CMemoryFileMap::eMMS_Private); - - // new() should have thrown, but some old implementations are - // said to be non-compliant in this regard: - - if (! m_MemFile) { - throw std::bad_alloc(); - } - - if ((m_Begin != 0) || (m_End != flength)) { - x_Roundup(m_Begin, m_End, m_Penalty, flength, true, atlas); - atlas->PossiblyGarbageCollect(m_End - m_Begin, false); - } - - m_Data = (const char*) m_MemFile->Map(m_Begin, m_End - m_Begin); - - string last2 = m_Fname->substr(m_Fname->length() - 2); - EMemoryAdvise strategy = eMADV_Normal; - if (last2 == "in") { - strategy = sm_MmapStrategy_Index; - } else if (last2 == "sq") { - strategy = sm_MmapStrategy_Sequence; - } - - // If "normal" is set, don't call MemoryAdvise at all. We cannot - // guarantee that a call to MemoryAdvise with eMADV_Normal gives - // identical behavior to not calling MemoryAdvise in the first - // place, even if eMADV_Normal is the default. - if (strategy != eMADV_Normal) { - MemoryAdvise( - (void*) m_Data, - (unsigned long) (m_End - m_Begin), - strategy - ); - } - - } - catch(std::bad_alloc&) { - expt = "\nstd::bad_alloc."; - } - catch(CException & e) { - // Make sure the string is not empty. - expt = string("\n") + e.ReportAll(); - } - catch(...) { - throw; - } - - if (expt.length()) { - // For now, if I can't memory map the file, I'll revert to - // the old way: malloc a chunk of core and copy the data - // into it. - - if (expt.find(": Cannot allocate memory") == expt.npos) { - expt = string("CSeqDBAtlas::MapMmap: While mapping file [") + (*m_Fname) + "] with " + - NStr::UInt8ToString(atlas->GetCurrentAllocationTotal()) + - " bytes allocated, caught exception:" + expt; - - SeqDB_ThrowException(CSeqDBException::eFileErr, expt); - } - } - - if (m_Data) { - rv = true; - } else { - delete m_MemFile; - m_MemFile = 0; - } - } - - return rv; -} - -bool CRegionMap::MapFile(CSeqDBAtlas * atlas) -{ - CHECK_MARKER(); - - // Okay, rethink: - - // 1. Unlike mmap, the file state disappears, the only state here - // will be the data itself. The stream is not kept because we - // only need to read the data into a buffer, then the stream goes - // away. - - // Steps: - - // 1. round up slice. - // 2. open file, seek, and read. - // a. if read fails, delete section, return failure, and quit. - // a. if read works, return true. - - // Find file and get length - - CFile file(*m_Fname); - CNcbiIfstream istr(m_Fname->c_str(), IOS_BASE::binary | IOS_BASE::in); - - if ((! file.Exists()) || istr.fail()) { - return false; - } - - // Round up slice size -- this should be a win for sequences if - // they are read sequentially, and are smaller than one block - // (16,000 base pairs). This is a safe bet. We are trading - // memory bandwidth for disk bandwidth. A more intelligent - // algorithm might heuristically determine whether such an - // optimization is working, or even switch back and forth and - // measure performance. - - // For now, this code has to be rock solid, so I am avoiding - // anything like cleverness. The assumptions are: - - // (1) That reading whole blocks (and therefore avoiding multiple - // IOs per block) saves more time than is lost in read(2) when - // copying the (potentially) unused parts of the block. - // - // (2) That it is better for memory performance to store - // whole-blocks in memory than to store 'trimmed' sequences. - - // If you think this is not true, consider the case of the index - // file, where we would be storing regions consisting of only 4 or - // 8 bytes. - - x_Roundup(m_Begin, - m_End, - m_Penalty, - SeqDB_CheckLength(file.GetLength()), - false, - atlas); - - atlas->PossiblyGarbageCollect(m_End - m_Begin, false); - - istr.seekg(m_Begin); - - Uint8 rdsize8 = m_End - m_Begin; - _ASSERT((TIndx(rdsize8) & TIndx(-1)) == TIndx(rdsize8)); - - TIndx rdsize = (TIndx) rdsize8; - - char * newbuf = 0; - - bool throw_afe = false; - - try { - newbuf = new char[rdsize]; - - // new() should have thrown, but some old implementations are - // said to be non-compliant in this regard: - - if (! newbuf) { - CHECK_MARKER(); - throw std::bad_alloc(); - } - } - catch(std::bad_alloc) { - throw_afe = true; - } - - if (throw_afe) { - CHECK_MARKER(); - - string msg("CSeqDBAtlas::MapFile: allocation failed for "); - msg += NStr::UInt8ToString(rdsize); - msg += " bytes."; - - NCBI_THROW(CSeqDBException, eMemErr, msg); - } - - TIndx amt_read = 0; - - while((amt_read < rdsize) && istr) { - istr.read(newbuf + amt_read, rdsize - amt_read); - - size_t count = istr.gcount(); - if (! count) { - delete[] newbuf; - return false; - } - - amt_read += count; - } - - m_Data = newbuf; - - return (amt_read == rdsize); -} - -const char * CRegionMap::Data(TIndx begin, TIndx end) -{ - CHECK_MARKER(); - _ASSERT(m_Data != 0); - _ASSERT(begin >= m_Begin); - - // Avoid solaris warning. - if (! (end <= m_End)) { - _ASSERT(end <= m_End); - } - - return m_Data + begin - m_Begin; -} - -int CSeqDBAtlas::x_LookupFile(const string & fname, - const string ** map_fname_ptr) -{ - Verify(true); - map::iterator i = m_FileIDs.find(fname); - - if (i == m_FileIDs.end()) { - m_FileIDs[fname] = ++ m_LastFID; - - i = m_FileIDs.find(fname); - } - - // Get address of string in string->fid table. - - *map_fname_ptr = & (*i).first; - Verify(true); - - return (*i).second; -} - -void CSeqDBAtlas::SetMemoryBound(Uint8 mb) -{ - CSeqDBLockHold locked(*this); - Lock(locked); - - Verify(true); - - m_Strategy.SetMemoryBound(mb); - Verify(true); -} void CSeqDBAtlas::RegisterExternal(CSeqDBMemReg & memreg, size_t bytes, @@ -1423,10 +405,8 @@ void CSeqDBAtlas::RegisterExternal(CSeqDBMemReg & memreg, { if (bytes > 0) { Lock(locked); - PossiblyGarbageCollect(bytes, false); - - _ASSERT(memreg.m_Bytes == 0); - m_CurAlloc += memreg.m_Bytes = bytes; + _ASSERT(memreg.m_Bytes == 0); + memreg.m_Bytes = bytes; } } @@ -1434,254 +414,18 @@ void CSeqDBAtlas::UnregisterExternal(CSeqDBMemReg & memreg) { size_t bytes = memreg.m_Bytes; - if (bytes > 0) { - _ASSERT((size_t)m_CurAlloc >= bytes); - m_CurAlloc -= bytes; + if (bytes > 0) { memreg.m_Bytes = 0; } } -// 16 GB should be enough - -const Int8 CSeqDBMapStrategy::e_MaxMemory64 = Int8(16) << 30; - -Int8 CSeqDBMapStrategy::m_GlobalMaxBound = 0; - -bool CSeqDBMapStrategy::m_AdjustedBound = false; - -/// Constructor -CSeqDBMapStrategy::CSeqDBMapStrategy(CSeqDBAtlas & atlas) - : m_Atlas (atlas), - m_MaxBound (0), - m_RetBound (0), - m_SliceSize (0), - m_Overhang (0), - m_Order (0.95, .901), - m_InOrder (true), - m_MapFailed (false), - m_LastOID (0), - m_BlockSize (4096) -{ - m_BlockSize = GetVirtualMemoryPageSize(); - - if (m_GlobalMaxBound == 0) { - SetDefaultMemoryBound(0); - _ASSERT(m_GlobalMaxBound != 0); - } - m_MaxBound = m_GlobalMaxBound; - x_SetBounds(m_MaxBound); -} - -void CSeqDBMapStrategy::MentionOid(int oid, int num_oids) -{ - // Still working on the same oid, ignore. - if (m_LastOID == oid) { - return; - } - - // The OID is compared to the previous OID. Sequential access is - // defined as having increasing OIDs about 90% of the time. - // However, if the OID is only slightly before the previous OID, - // it is ignored. This is to allow sequential semantics for - // multithreaded apps that divide work into chunks of OIDs. - // - // "Slightly" before is defined as the greater of 10 OIDs or - // 10% of the database. This 'window' of the database can - // only move backward when the ordering test fails, so walking - // backward through the entire database will not be considered - // sequential. - - // In the blast libraries, work is divided into 1% of the database - // or 1 OID. So 10% allows 5 threads and the assumption that some - // chunks will take as much as twice as long to run as others. - - int pct = 10; - int window = max(num_oids/100*pct, pct); - int low_bound = max(m_LastOID - window, 0); - - if (oid > m_LastOID) { - // Register sequential access. - x_OidOrder(true); - m_LastOID = oid; - } else if (oid < low_bound) { - // Register non-sequential access. - x_OidOrder(false); - m_LastOID = oid; - } -} - -void CSeqDBMapStrategy::x_OidOrder(bool in_order) -{ - m_Order.AddData(in_order ? 1.0 : 0); - - // Moving average with thermostat-like hysteresis. - bool new_order = m_Order.GetAverage() > (m_InOrder ? .8 : .9); - - if (new_order != m_InOrder) { - // Rebuild the bounds with the new ordering constraint. - m_InOrder = new_order; - x_SetBounds(m_MaxBound); - } -} - -void CSeqDBMapStrategy::MentionMapFailure(Uint8 current) -{ - // The first map failure only modifies the slice size; after that - // we reduce the amount of allocation permitted. - - if (m_MapFailed) { - m_MaxBound = (m_MaxBound * 4) / 5; - x_SetBounds(min((Int8) current, m_MaxBound)); - } else { - m_MapFailed = true; - x_SetBounds(m_MaxBound); - } -} - -Uint8 CSeqDBMapStrategy::x_Pick(Uint8 low, Uint8 high, Uint8 guess) -{ - // max and guess is usually computed; min is usually a - // constant, so if there is a conflict, use min. - - if (low > high) { - high = low; - } - - int bs = int(m_BlockSize); - - if (guess < low) { - guess = (low + bs - 1); - } - - if (guess > high) { - guess = high; - } - - guess -= (guess % bs); - - _ASSERT((guess % bs) == 0); - _ASSERT((guess >= low) && (guess <= high)); - - return guess; -} - -/// Set all parameters. -void CSeqDBMapStrategy::x_SetBounds(Uint8 bound) -{ - Uint8 max_bound(0); - Uint8 max_slice(0); - - if (sizeof(int*) == 8) { - max_bound = e_MaxMemory64; - max_slice = e_MaxSlice64; - } else { - max_bound = e_MaxMemory32; - max_slice = e_MaxSlice32; - } - - int overhang_ratio = 32; - int slice_ratio = 10; - - // If a mapping request has never failed, use large slice for - // efficiency. Otherwise, if the client follows a mostly linear - // access pattern, use middle sized slices, and if not, use small - // slices. - - const int no_limits = 4; - const int linear_oids = 10; - const int random_oids = 80; - - if (! m_MapFailed) { - slice_ratio = no_limits; - } else if (m_InOrder) { - slice_ratio = linear_oids; - } else { - slice_ratio = random_oids; - } - - m_MaxBound = x_Pick(e_MinMemory, - min(max_bound, bound), - bound); - - m_SliceSize = x_Pick(e_MinSlice, - max_slice, - m_MaxBound / slice_ratio); - - m_RetBound = x_Pick(e_MinMemory, - m_MaxBound-((m_SliceSize*3)/2), - (m_MaxBound*8)/10); - - m_Overhang = x_Pick(e_MinOverhang, - e_MaxOverhang, - m_SliceSize / overhang_ratio); - - m_AdjustedBound = false; -} - -void CSeqDBAtlas::SetDefaultMemoryBound(Uint8 bytes) -{ - CSeqDBMapStrategy::SetDefaultMemoryBound(bytes); -} - -void CSeqDBMapStrategy::SetDefaultMemoryBound(Uint8 bytes) -{ - Uint8 app_space = CSeqDBMapStrategy::e_AppSpace; - - if (bytes == 0) { - if (sizeof(int*) == 4) { - bytes = e_MaxMemory32; - } else { - bytes = e_MaxMemory64; - } - -#if defined(NCBI_OS_UNIX) - rlimit vspace; - rusage ruse; - - int rc = 0; - int rc2 = 0; - -#ifdef RLIMIT_AS - rc = getrlimit(RLIMIT_AS, & vspace); -#elif defined(RLIMIT_RSS) - rc = getrlimit(RLIMIT_RSS, & vspace); -#else - vspace.rlim_cur = RLIM_INFINITY; -#endif - rc2 = getrusage(RUSAGE_SELF, & ruse); - - if (rc || rc2) { - _ASSERT(rc == 0); - _ASSERT(rc2 == 0); - } - Uint8 max_mem = vspace.rlim_cur; - Uint8 max_mem75 = (max_mem/4)*3; - if (max_mem < (app_space*2)) { - app_space = max_mem/2; - } else { - max_mem -= app_space; - if (max_mem > max_mem75) { - max_mem = max_mem75; - } - } - if (max_mem < bytes) { - bytes = max_mem; - } -#endif - } - - m_GlobalMaxBound = bytes; - m_AdjustedBound = true; -} - -CSeqDBAtlasHolder::CSeqDBAtlasHolder(bool use_mmap, - CSeqDBFlushCB * flush, +CSeqDBAtlasHolder::CSeqDBAtlasHolder(bool use_mmap, CSeqDBLockHold * lockedp) - : m_FlushCB(0) + { {{ CFastMutexGuard guard(m_Lock); @@ -1691,29 +435,13 @@ CSeqDBAtlasHolder::CSeqDBAtlasHolder(bool use_mmap, } m_Count ++; }} - - if (lockedp == NULL) { - CSeqDBLockHold locked2(*m_Atlas); - - if (flush) - m_Atlas->AddRegionFlusher(flush, & m_FlushCB, locked2); - } - else { - if (flush) - m_Atlas->AddRegionFlusher(flush, & m_FlushCB, *lockedp); - } - } DEFINE_CLASS_STATIC_FAST_MUTEX(CSeqDBAtlasHolder::m_Lock); CSeqDBAtlasHolder::~CSeqDBAtlasHolder() { - if (m_FlushCB) { - CSeqDBLockHold locked(*m_Atlas); - m_Atlas->RemoveRegionFlusher(m_FlushCB, locked); - } - + CFastMutexGuard guard(m_Lock); m_Count --; @@ -1732,51 +460,14 @@ CSeqDBLockHold::~CSeqDBLockHold() { CHECK_MARKER(); - if (m_Holds.size()) { - m_Atlas.Lock(*this); - for(size_t i = 0; i < m_Holds.size(); i++) { - m_Holds[i]->RetRef(); - } - m_Holds.clear(); - } - m_Atlas.Unlock(*this); BREAK_MARKER(); } -/// Get a hold a region of memory. -void CSeqDBLockHold::HoldRegion(CSeqDBMemLease & lease) -{ - m_Atlas.Lock(*this); - - CRegionMap * rmap = lease.GetRegionMap(); - - _ASSERT(rmap); - - for(size_t i = 0; i < m_Holds.size(); i++) { - if (m_Holds[i] == rmap) - return; - } - - if (m_Holds.empty()) { - m_Holds.reserve(4); - } - - m_Holds.push_back(rmap); - rmap->AddRef(); -} - int CSeqDBAtlasHolder::m_Count = 0; CSeqDBAtlas * CSeqDBAtlasHolder::m_Atlas = NULL; -void CSeqDBMapStrategy::x_CheckAdjusted() -{ - if (m_GlobalMaxBound && m_AdjustedBound) { - x_SetBounds(m_GlobalMaxBound); - } -} - CSeqDB_AtlasRegionHolder:: CSeqDB_AtlasRegionHolder(CSeqDBAtlas & atlas, const char * ptr) : m_Atlas(atlas), m_Ptr(ptr) @@ -1789,7 +480,7 @@ CSeqDB_AtlasRegionHolder::~CSeqDB_AtlasRegionHolder() CSeqDBLockHold locked(m_Atlas); m_Atlas.Lock(locked); - m_Atlas.RetRegion(m_Ptr); + //m_Atlas.RetRegion(m_Ptr); m_Ptr = NULL; } } diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbbitset.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbbitset.cpp index 6b6c8ad4..1c2eba48 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbbitset.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbbitset.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbbitset.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: seqdbbitset.cpp 515860 2016-10-06 12:29:07Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -422,5 +422,15 @@ void CSeqDB_BitSet::Normalize() } } +void CSeqDB_BitSet::DebugDump(CDebugDumpContext ddc, unsigned int depth) const +{ + ddc.SetFrame("CSeqDB_BitSet"); + CObject::DebugDump(ddc, depth); + ddc.Log("m_Special", m_Special); + ddc.Log("m_Start", m_Start); + ddc.Log("m_End", m_End); + ddc.Log("m_Bits.size", m_Bits.size()); +} + END_NCBI_SCOPE diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbbitset.hpp b/c++/src/objtools/blast/seqdb_reader/seqdbbitset.hpp index 74a20fd6..06ad1df4 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbbitset.hpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbbitset.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBBITSET_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBBITSET_HPP -/* $Id: seqdbbitset.hpp 398155 2013-05-03 11:37:45Z camacho $ +/* $Id: seqdbbitset.hpp 515860 2016-10-06 12:29:07Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -269,6 +269,11 @@ private: /// Representation of bit data. vector m_Bits; + +public: + /// Allows to dump a snapshot of the object + /// @todo this doesn't do anything for locality eRemote + void DebugDump(CDebugDumpContext ddc, unsigned int depth) const; }; END_NCBI_SCOPE diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbcol.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbcol.cpp index 56a56153..f8fe1dd1 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbcol.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbcol.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbcol.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: seqdbcol.cpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -29,7 +29,7 @@ /// @file seqdbcol.cpp /// This is the implementation file for the CSeqDBColumnReader, -/// CSeqDBColumn, CSeqDBColumnFlush, and CSeqDB_ColumnEntry classes, +/// CSeqDBColumn, and CSeqDB_ColumnEntry classes, /// which support read operations on BlastDb format database columns. #include #include @@ -103,11 +103,11 @@ CSeqDBColumn::CSeqDBColumn(const string & basename, const string & index_extn, const string & data_extn, CSeqDBLockHold * lockedp) - : m_AtlasHolder (true, & m_FlushCB, lockedp), + : m_AtlasHolder (true, lockedp), m_Atlas (m_AtlasHolder.Get()), - m_IndexFile (m_Atlas), + m_IndexFile (m_Atlas), + m_DataFile (m_Atlas), m_IndexLease (m_Atlas), - m_DataFile (m_Atlas), m_DataLease (m_Atlas), m_NumOIDs (0), m_DataLength (0), @@ -126,8 +126,8 @@ CSeqDBColumn::CSeqDBColumn(const string & basename, CSeqDB_Path fn1(basename + "." + index_extn); CSeqDB_Path fn2(basename + "." + data_extn); - bool found1 = m_IndexFile.Open(fn1, *lockedp); - bool found2 = m_DataFile.Open(fn2, *lockedp); + bool found1 = m_IndexFile.Open(fn1); + bool found2 = m_DataFile.Open(fn2); if (! (found1 && found2)) { NCBI_THROW(CSeqDBException, eFileErr, @@ -141,8 +141,7 @@ CSeqDBColumn::CSeqDBColumn(const string & basename, m_Atlas.Unlock(*lockedp); throw; } - - m_FlushCB.SetColumn(this); + } CSeqDBColumn::~CSeqDBColumn() @@ -150,7 +149,6 @@ CSeqDBColumn::~CSeqDBColumn() CSeqDBLockHold locked(m_Atlas); m_Atlas.Lock(locked); - m_FlushCB.SetColumn(NULL); Flush(); } @@ -192,16 +190,15 @@ void CSeqDBColumn::x_GetFileRange(TIndx begin, _ASSERT(index || (select_file == e_Data)); CSeqDBRawFile & file = index ? m_IndexFile : m_DataFile; - CSeqDBMemLease & lease = index ? m_IndexLease : m_DataLease; + CSeqDBFileMemMap & lease = index ? m_IndexLease : m_DataLease; - const char * ptr = file.GetRegion(lease, begin, end, locked); + const char * ptr = file.GetFileDataPtr(lease, begin, end); CTempString data(ptr, end-begin); if (lifetime) { CRef hold(new CSeqDB_AtlasRegionHolder(m_Atlas, ptr)); - blob.ReferTo(data, hold); - lease.IncrementRefCnt(); + blob.ReferTo(data, hold); } else { blob.ReferTo(data); } @@ -356,15 +353,6 @@ void CSeqDBColumn::GetBlob(int oid, } -// CSeqDBColumnFlush - -void CSeqDBColumnFlush::operator()() -{ - if (m_Column) { - m_Column->Flush(); - } -} - const map & CSeqDBColumn::GetMetaData() { return m_MetaData; diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbcommon.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbcommon.cpp index a9f2f45e..71821e99 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbcommon.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbcommon.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbcommon.cpp 519978 2016-11-21 18:10:37Z ivanov $ +/* $Id: seqdbcommon.cpp 535605 2017-05-10 15:41:23Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -353,7 +353,7 @@ static string s_SeqDB_TryPaths(const string & blast_paths, // indices (see comments in CSeqDBAliasSets::FindAliasPath). vector roads; - NStr::Tokenize(blast_paths, s_GetPathSplitter(), roads, NStr::eMergeDelims); + NStr::Split(blast_paths, s_GetPathSplitter(), roads, NStr::fSplit_Tokenize); string result; string attempt; @@ -780,6 +780,21 @@ CSeqDBGiList::GetTiList(vector& tis) const } +void +CSeqDBGiList::GetSiList(vector& sis) const +{ + sis.clear(); + sis.reserve(GetNumSis()); + + ITERATE(vector, itr, m_SisOids) { + sis.push_back(itr->si); + } +} + + + + + void SeqDB_ReadBinaryGiList(const string & fname, vector & gis) { CMemoryFile mfile(SeqDB_MakeOSPath(fname)); @@ -1383,8 +1398,7 @@ void SeqDB_ReadSiList(const string & fname, vector & sis, bool CSeqDBNegativeList::FindGi(TGi gi) { - InsureOrder(); - + InsureOrder(); int b(0), e((int)m_Gis.size()); while(b < e) { @@ -1433,27 +1447,72 @@ bool CSeqDBNegativeList::FindId(const CSeq_id & id) } +bool CSeqDBNegativeList::FindSi(string si) +{ + InsureOrder(); + int b(0), e((int)m_Sis.size()); + + while(b < e) { + int m = (b + e)/2; + string m_si = m_Sis[m]; + + if (m_si < si) { + b = m + 1; + } else if (m_si > si) { + e = m; + } else { + return true; + } + } + + return false; +} + + bool CSeqDBNegativeList::FindId(const CSeq_id & id, bool & match_type) { - if (id.IsGi()) { - match_type = true; - return FindGi(id.GetGi()); + if (id.IsGi()) { + match_type = (GetNumGis() > 0) ? true : false; + if(match_type) { + return(FindGi(id.GetGi())); + } } else if (id.IsGeneral() && id.GetGeneral().GetDb() == "ti") { - match_type = true; - const CObject_id & obj = id.GetGeneral().GetTag(); + match_type = (GetNumTis() > 0) ? true : false; + + if(match_type) { + const CObject_id & obj = id.GetGeneral().GetTag(); - Int8 ti = (obj.IsId() + Int8 ti = (obj.IsId() ? obj.GetId() : NStr::StringToInt8(obj.GetStr())); - return FindTi(ti); + return FindTi(ti); + } } else { - match_type = false; - return false; + match_type = (GetNumSis() > 0) ? true : false; + + Int8 num_id; + string str_id; + bool simpler; + + SeqDB_SimplifySeqid(*(const_cast(&id)), 0, num_id, str_id, simpler); + + if(match_type) { + if (FindSi(str_id)) { + return true; + } + + // We may have to strip the version to find it... + size_t pos = str_id.find("."); + if (pos != str_id.npos) { + string nover(str_id, 0, pos); + return FindSi(nover); + } + } } + return false; } - bool CSeqDBGiList::FindId(const CSeq_id & id) { if (id.IsGi()) { @@ -1722,12 +1781,25 @@ CSeqDBIdSet::CSeqDBIdSet(const vector & ids, EIdType t, bool positive) } #endif +CSeqDBIdSet::CSeqDBIdSet(const vector & ids, EIdType t, bool positive) + : m_Positive(positive), m_IdType(t), m_Ids(new CSeqDBIdSet_Vector(ids)) +{ + x_SortAndUnique(m_Ids->SetSeqIDs()); +} + void CSeqDBIdSet::x_SortAndUnique(vector & ids) { sort(ids.begin(), ids.end()); ids.erase(unique(ids.begin(), ids.end()), ids.end()); } + +void CSeqDBIdSet::x_SortAndUnique(vector & ids) +{ + sort(ids.begin(), ids.end()); + ids.erase(unique(ids.begin(), ids.end()), ids.end()); +} + void CSeqDBIdSet::Negate() { m_Positive = ! m_Positive; @@ -2021,7 +2093,7 @@ CRef CSeqDBIdSet::GetNegativeList() ITERATE(vector, iter, m_Ids->Set()) { ids->AddTi(*iter); } - } else { + } else if (m_IdType == eGi) { ids->ReserveGis(m_Ids->Size()); ITERATE(vector, iter, m_Ids->Set()) { @@ -2029,6 +2101,13 @@ CRef CSeqDBIdSet::GetNegativeList() ids->AddGi(GI_FROM(Int8, *iter)); } } + else { + ids->ReserveSis(m_Ids->Size()); + + ITERATE(vector, iter, m_Ids->SetSeqIDs()) { + ids->AddSi(*iter); + } + } return ids; } diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbexpert.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbexpert.cpp index f2258ae3..03bc34ce 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbexpert.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbexpert.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbexpert.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: seqdbexpert.cpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -66,57 +66,57 @@ void CSeqDBExpert::GetRawSeqAndAmbig(int oid, int * seq_length, int * ambig_length) const { - m_Impl->Verify(); + m_Impl->GetRawSeqAndAmbig(oid, buf, seq_length, ambig_length); - m_Impl->Verify(); + } void CSeqDBExpert::GetGiBounds(TGi * low_id, TGi * high_id, int * count) { - m_Impl->Verify(); + m_Impl->GetGiBounds(low_id, high_id, count); - m_Impl->Verify(); + } void CSeqDBExpert::GetPigBounds(int * low_id, int * high_id, int * count) { - m_Impl->Verify(); + m_Impl->GetPigBounds(low_id, high_id, count); - m_Impl->Verify(); + } void CSeqDBExpert::GetStringBounds(string * low_id, string * high_id, int * count) { - m_Impl->Verify(); + m_Impl->GetStringBounds(low_id, high_id, count); - m_Impl->Verify(); + } void CSeqDBExpert::Verify() { - m_Impl->Verify(); + } unsigned CSeqDBExpert::GetSequenceHash(int oid) { - m_Impl->Verify(); + unsigned h = m_Impl->GetSequenceHash(oid); - m_Impl->Verify(); + return h; } void CSeqDBExpert::HashToOids(unsigned hash, vector & oids) { - m_Impl->Verify(); + m_Impl->HashToOids(hash, oids); - m_Impl->Verify(); + } END_NCBI_SCOPE diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbfile.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbfile.cpp index d55559e1..750915b8 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbfile.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbfile.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbfile.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: seqdbfile.cpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -68,71 +68,48 @@ BEGIN_NCBI_SCOPE typedef CSeqDBAtlas::TIndx TIndx; -TIndx CSeqDBRawFile::ReadSwapped(CSeqDBMemLease & lease, +TIndx CSeqDBRawFile::ReadSwapped(CSeqDBFileMemMap & lease, TIndx offset, - Uint4 * value, - CSeqDBLockHold & locked) const + Uint4 * value) const + { - m_Atlas.Lock(locked); - - if (! lease.Contains(offset, offset + sizeof(*value))) { - m_Atlas.GetRegion(lease, m_FileName, offset, offset + sizeof(*value)); - } - - *value = SeqDB_GetStdOrd((Uint4 *) lease.GetPtr(offset)); + *value = SeqDB_GetStdOrd((Uint4 *) lease.GetFileDataPtr(m_FileName,offset)); return offset + sizeof(*value); } -TIndx CSeqDBRawFile::ReadSwapped(CSeqDBMemLease & lease, +TIndx CSeqDBRawFile::ReadSwapped(CSeqDBFileMemMap & lease, TIndx offset, - Uint8 * value, - CSeqDBLockHold & locked) const + Uint8 * value) const + { - m_Atlas.Lock(locked); - - if (! lease.Contains(offset, offset + sizeof(*value))) { - m_Atlas.GetRegion(lease, m_FileName, offset, offset + sizeof(*value)); - } - - *value = SeqDB_GetBroken((Int8 *) lease.GetPtr(offset)); + *value = SeqDB_GetBroken((Int8 *) lease.GetFileDataPtr(m_FileName,offset)); return offset + sizeof(*value); } -TIndx CSeqDBRawFile::ReadSwapped(CSeqDBMemLease & lease, +TIndx CSeqDBRawFile::ReadSwapped(CSeqDBFileMemMap & lease, TIndx offset, - string * value, - CSeqDBLockHold & locked) const + string * value) const { Uint4 len = 0; - m_Atlas.Lock(locked); - - if (! lease.Contains(offset, offset + sizeof(len))) { - m_Atlas.GetRegion(lease, m_FileName, offset, offset + sizeof(len)); - } - - len = SeqDB_GetStdOrd((Int4 *) lease.GetPtr(offset)); + len = SeqDB_GetStdOrd((Int4 *) lease.GetFileDataPtr(m_FileName,offset)); offset += sizeof(len); - if (! lease.Contains(offset, offset + len)) { - m_Atlas.GetRegion(lease, m_FileName, offset, offset + sizeof(len)); - } - - value->assign(lease.GetPtr(offset), (int) len); + value->assign(lease.GetFileDataPtr(offset), (int) len); return offset + len; } CSeqDBExtFile::CSeqDBExtFile(CSeqDBAtlas & atlas, const string & dbfilename, - char prot_nucl, - CSeqDBLockHold & locked) - : m_Atlas (atlas), - m_Lease (atlas), + char prot_nucl) + + : m_Atlas (atlas), m_FileName(dbfilename), + m_Lease (atlas), m_File (atlas) { if ((prot_nucl != 'p') && (prot_nucl != 'n')) { @@ -143,27 +120,29 @@ CSeqDBExtFile::CSeqDBExtFile(CSeqDBAtlas & atlas, x_SetFileType(prot_nucl); - if (! m_File.Open(CSeqDB_Path(m_FileName), locked)) { - m_Atlas.Unlock(locked); + if (! m_File.Open(CSeqDB_Path(m_FileName))) { + //m_Atlas.Unlock(locked); string msg = string("Error: File (") + m_FileName + ") not found."; NCBI_THROW(CSeqDBException, eFileErr, msg); - } + } + + m_Lease.Init(m_FileName); } CSeqDBIdxFile::CSeqDBIdxFile(CSeqDBAtlas & atlas, const string & dbname, - char prot_nucl, - CSeqDBLockHold & locked) - : CSeqDBExtFile(atlas, dbname + ".-in", prot_nucl, locked), + char prot_nucl) + + : CSeqDBExtFile(atlas, dbname + ".-in", prot_nucl), + m_HdrLease (atlas), + m_SeqLease (atlas), + m_AmbLease (atlas), m_NumOIDs (0), m_VolLen (0), m_MaxLen (0), - m_MinLen (0), - m_HdrLease (atlas), - m_SeqLease (atlas), - m_AmbLease (atlas), + m_MinLen (0), m_OffHdr (0), m_EndHdr (0), m_OffSeq (0), @@ -171,7 +150,7 @@ CSeqDBIdxFile::CSeqDBIdxFile(CSeqDBAtlas & atlas, m_OffAmb (0), m_EndAmb (0) { - Verify(); + //Verify(); // Input validation @@ -189,12 +168,12 @@ CSeqDBIdxFile::CSeqDBIdxFile(CSeqDBAtlas & atlas, TIndx offset = 0; + Uint4 f_format_version = 0; Uint4 f_db_seqtype = 0; - CSeqDBMemLease lease (m_Atlas); - - offset = x_ReadSwapped(lease, offset, & f_format_version, locked); + + offset = x_ReadSwapped(m_Lease, offset, & f_format_version); TIndx off1(0), off2(0), off3(0), offend(0); @@ -204,13 +183,23 @@ CSeqDBIdxFile::CSeqDBIdxFile(CSeqDBAtlas & atlas, eFileErr, "Error: Not a valid version 4 database."); } + + offset = x_ReadSwapped(m_Lease, offset, & f_db_seqtype); + + + offset = x_ReadSwapped(m_Lease, offset, & m_Title); + - offset = x_ReadSwapped(lease, offset, & f_db_seqtype, locked); - offset = x_ReadSwapped(lease, offset, & m_Title, locked); - offset = x_ReadSwapped(lease, offset, & m_Date, locked); - offset = x_ReadSwapped(lease, offset, & m_NumOIDs, locked); - offset = x_ReadSwapped(lease, offset, & m_VolLen, locked); - offset = x_ReadSwapped(lease, offset, & m_MaxLen, locked); + offset = x_ReadSwapped(m_Lease, offset, & m_Date); + + + offset = x_ReadSwapped(m_Lease, offset, & m_NumOIDs); + + + offset = x_ReadSwapped(m_Lease, offset, & m_VolLen); + + + offset = x_ReadSwapped(m_Lease, offset, & m_MaxLen); TIndx region_bytes = 4 * (m_NumOIDs + 1); @@ -219,13 +208,11 @@ CSeqDBIdxFile::CSeqDBIdxFile(CSeqDBAtlas & atlas, off3 = off2 + region_bytes; offend = off3 + region_bytes; } - catch(...) { - m_Atlas.RetRegion(lease); + catch(...) { throw; } - m_Atlas.RetRegion(lease); - + char db_seqtype = ((f_db_seqtype == 1) ? 'p' : 'n'); if (db_seqtype != x_GetSeqType()) { diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbfilter.hpp b/c++/src/objtools/blast/seqdb_reader/seqdbfilter.hpp index 2abf5ec5..bbbd0ec5 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbfilter.hpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbfilter.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBFILTER_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBFILTER_HPP -/* $Id: seqdbfilter.hpp 398155 2013-05-03 11:37:45Z camacho $ +/* $Id: seqdbfilter.hpp 515860 2016-10-06 12:29:07Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -158,6 +158,17 @@ public: return m_MemBit; } + void DebugDump(CDebugDumpContext ddc, unsigned int depth) const + { + ddc.SetFrame("CSeqDB_AliasMask"); + CObject::DebugDump(ddc, depth); + ddc.Log("m_MaskType", m_MaskType); + ddc.Log("m_Path", m_Path.GetPathS()); + ddc.Log("m_Begin", m_Begin); + ddc.Log("m_End", m_End); + ddc.Log("m_MemBit", m_MemBit); + } + private: /// Type of filtering to apply. EMaskType m_MaskType; diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbgilistset.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbgilistset.cpp index 6845a03c..897fa6bb 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbgilistset.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbgilistset.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbgilistset.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: seqdbgilistset.cpp 530464 2017-03-15 14:36:01Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -91,10 +91,11 @@ public: { CSeqDBAtlas::TIndx file_size(0); - CSeqDBMemLease memlease(atlas); - atlas.GetFile(memlease, fname.GetPathS(), file_size, locked); - - const char * fbeginp = memlease.GetPtr(0); + CSeqDBFileMemMap memlease(atlas,fname.GetPathS()); + atlas.GetFileSizeL(fname.GetPathS(), file_size); + + const char * fbeginp = memlease.GetFileDataPtr(0); + const char * fendp = fbeginp + (int)file_size; try { @@ -120,7 +121,7 @@ public: throw; } - memlease.Clear(); + //memlease.Clear(); int vector_size = (int(m_GisOids.size() * sizeof(m_GisOids[0])) + @@ -210,7 +211,7 @@ CSeqDBGiListSet::GetNodeIdList(const CSeqDB_Path & filename, // allow GI list vectors to share the memory bound with memory // mapped file ranges. - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); // Seperate indices are used for TIs and GIs. (Attempting to use // the same file for both should also produce an error when the diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbgimask.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbgimask.cpp index c3b36786..ea54bb36 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbgimask.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbgimask.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbgimask.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: seqdbgimask.cpp 530764 2017-03-17 14:01:30Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -45,19 +45,20 @@ CSeqDBGiMask::CSeqDBGiMask(CSeqDBAtlas & atlas, const vector & mask_name) : m_Atlas (atlas), m_MaskNames (mask_name), + m_IndexLease (atlas), + m_OffsetLease (atlas), m_AlgoId (-1), - m_IndexFile (m_Atlas), - m_IndexLease (m_Atlas), - m_OffsetFile (m_Atlas), - m_OffsetLease (m_Atlas) + m_IndexFile (m_Atlas), + m_OffsetFile (m_Atlas) + { } const string & CSeqDBGiMask::GetDesc(int algo_id, CSeqDBLockHold & locked) { - m_Atlas.Lock(locked); - x_Open(algo_id, locked); + //m_Atlas.Lock(locked); + x_Open(algo_id); return m_Desc; } @@ -67,9 +68,9 @@ CSeqDBGiMask::GetMaskData(int algo_id, CSeqDB::TSequenceRanges &ranges, CSeqDBLockHold &locked) { - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); - x_Open(algo_id, locked); + x_Open(algo_id); int page, vol, off; @@ -87,7 +88,7 @@ CSeqDBGiMask::GetMaskData(int algo_id, TIndx begin = page * m_PageSize * (m_GiSize + m_OffsetSize); TIndx end = begin + pagesize * (m_GiSize + m_OffsetSize); const Int4 * offset = (const Int4 *) - m_OffsetFile.GetRegion(m_OffsetLease, begin, end, locked); + m_OffsetFile.GetFileDataPtr(m_OffsetLease, begin, end); if (!s_BinarySearch(offset, pagesize, GI_TO(int, gi), page)) return; @@ -100,19 +101,19 @@ CSeqDBGiMask::GetMaskData(int algo_id, // Retrieving the mask data const Int4 * datap = (const Int4 *) - m_DataFile[vol]->GetRegion(*m_DataLease[vol], off, off+4, locked); + m_DataFile[vol]->GetFileDataPtr(*m_DataLease[vol], off, off+4); Int4 n = *datap; // Remapping the mask data datap = (const Int4 *) - m_DataFile[vol]->GetRegion(*m_DataLease[vol], off+4, off + 8*n + 4, locked); + m_DataFile[vol]->GetFileDataPtr(*m_DataLease[vol], off+4, off + 8*n + 4); ranges.append(datap, n); return; } -void CSeqDBGiMask::x_Open(Int4 algo_id, - CSeqDBLockHold & locked) +void CSeqDBGiMask::x_Open(Int4 algo_id) + { if (algo_id == m_AlgoId) { return; @@ -131,28 +132,31 @@ void CSeqDBGiMask::x_Open(Int4 algo_id, ext_i[2] = ext_o[2] = ext_d[2] = 'n'; } - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); try { CSeqDB_Path fn_i(SeqDB_ResolveDbPath(m_MaskNames[algo_id] + ext_i)); CSeqDB_Path fn_o(SeqDB_ResolveDbPath(m_MaskNames[algo_id] + ext_o)); - bool found_i = m_IndexFile.Open(fn_i, locked); - bool found_o = m_OffsetFile.Open(fn_o, locked); + bool found_i = m_IndexFile.Open(fn_i); + bool found_o = m_OffsetFile.Open(fn_o); if (! (found_i && found_o)) { NCBI_THROW(CSeqDBException, eFileErr, "Could not open gi-mask index files."); } + m_IndexLease.Init(fn_i.GetPathS()); + m_OffsetLease.Init(fn_o.GetPathS()); m_AlgoId = algo_id; - x_ReadFields(locked); + x_ReadFields(); if (m_NumVols == 1) { m_DataFile.push_back(new CSeqDBRawFile(m_Atlas)); - m_DataLease.push_back(new CSeqDBMemLease(m_Atlas)); + m_DataLease.push_back(new CSeqDBFileMemMap(m_Atlas)); CSeqDB_Path fn(SeqDB_ResolveDbPath(m_MaskNames[algo_id] + ext_d)); - bool found = m_DataFile[0]->Open(fn, locked); + bool found = m_DataFile[0]->Open(fn); + m_DataLease[0]->Init(fn.GetPathS()); if (! found) { NCBI_THROW(CSeqDBException, eFileErr, "Could not open gi-mask data file."); @@ -160,11 +164,12 @@ void CSeqDBGiMask::x_Open(Int4 algo_id, } else { for (int vol=0; volOpen(fn, locked); + bool found = m_DataFile[vol]->Open(fn); + m_DataLease[vol]->Init(fn.GetPathS()); if (! found) { NCBI_THROW(CSeqDBException, eFileErr, "Could not open gi-mask data files."); @@ -175,7 +180,7 @@ void CSeqDBGiMask::x_Open(Int4 algo_id, } catch(...) { m_AlgoId = -1; - m_Atlas.Unlock(locked); + //m_Atlas.Unlock(locked); throw; } } @@ -183,25 +188,25 @@ void CSeqDBGiMask::x_Open(Int4 algo_id, void CSeqDBGiMask::s_GetFileRange(TIndx begin, TIndx end, CSeqDBRawFile & file, - CSeqDBMemLease & lease, - CBlastDbBlob & blob, - CSeqDBLockHold & locked) + CSeqDBFileMemMap & lease, + CBlastDbBlob & blob) + { - const char * ptr = file.GetRegion(lease, begin, end, locked); + const char * ptr = file.GetFileDataPtr(lease, begin, end); CTempString data(ptr, end-begin); blob.ReferTo(data); } -void CSeqDBGiMask::x_ReadFields(CSeqDBLockHold & locked) +void CSeqDBGiMask::x_ReadFields(void)// { const int kFixedFieldBytes = 32; - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); // First, get the 32 bytes of fields that we know exist. CBlastDbBlob header; - s_GetFileRange(0, kFixedFieldBytes, m_IndexFile, m_IndexLease, header, locked); + s_GetFileRange(0, kFixedFieldBytes, m_IndexFile, m_IndexLease, header); int fmt_version = header.ReadInt4(); @@ -228,7 +233,7 @@ void CSeqDBGiMask::x_ReadFields(CSeqDBLockHold & locked) // to reference the whole thing. (The memory lease should already // hold the data, so this will just adjust a few integer fields.) - s_GetFileRange(0, m_IndexStart, m_IndexFile, m_IndexLease, header, locked); + s_GetFileRange(0, m_IndexStart, m_IndexFile, m_IndexLease, header); // Get string type header fields. @@ -242,7 +247,7 @@ void CSeqDBGiMask::x_ReadFields(CSeqDBLockHold & locked) TIndx begin = m_IndexStart; TIndx end = begin + m_NumIndex * (m_GiSize + m_OffsetSize); m_GiIndex = (const Int4 *) - m_IndexFile.GetRegion(m_IndexLease, begin, end, locked); + m_IndexFile.GetFileDataPtr(m_IndexLease, begin, end); } // TODO: if gi becomes 8-bytes long, this may better be implemented as diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbgimask.hpp b/c++/src/objtools/blast/seqdb_reader/seqdbgimask.hpp index 98f5eb6f..afc729c9 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbgimask.hpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbgimask.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBGIMASK_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBGIMASK_HPP -/* $Id: seqdbgimask.hpp 481389 2015-10-09 14:40:20Z rackerst $ +/* $Id: seqdbgimask.hpp 530764 2017-03-17 14:01:30Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -159,11 +159,11 @@ private: /// Open file for a chosen algo_id /// @param algo_id The chosen algo_id [in] /// @param locked The lock holder object for this thread. [in] - void x_Open(Int4 algo_id, CSeqDBLockHold & locked); + void x_Open(Int4 algo_id); /// Open files and read field data from the atlas. /// @param locked The lock holder object for this thread. [in] - void x_ReadFields(CSeqDBLockHold & locked); + void x_ReadFields(void); /// Verify the algorithm exists. If not, raise an exception void x_VerifyAlgorithmId(int algo_id) const { @@ -190,9 +190,9 @@ private: static void s_GetFileRange(TIndx begin, TIndx end, CSeqDBRawFile & file, - CSeqDBMemLease & lease, - CBlastDbBlob & blob, - CSeqDBLockHold & locked); + CSeqDBFileMemMap & lease, + CBlastDbBlob & blob); + /// Binary search for value associated with a key /// @@ -212,21 +212,21 @@ private: /// The set of gi masks found in alias description const vector m_MaskNames; + /// Index file lease. + CSeqDBFileMemMap m_IndexLease; + + /// Offset file lease. + CSeqDBFileMemMap m_OffsetLease; + /// The current used mask id Int4 m_AlgoId; /// Index file. CSeqDBRawFile m_IndexFile; - /// Index file lease. - CSeqDBMemLease m_IndexLease; - /// Offset file. CSeqDBRawFile m_OffsetFile; - /// Offset file lease. - CSeqDBMemLease m_OffsetLease; - /// Number of data volumes Int4 m_NumVols; @@ -234,7 +234,7 @@ private: vector m_DataFile; /// Data file lease. - vector m_DataLease; + vector m_DataLease; /// GI size Int4 m_GiSize; diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbimpl.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbimpl.cpp index 5b17e02b..8d97dac9 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbimpl.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbimpl.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbimpl.cpp 516293 2016-10-12 14:27:34Z ivanov $ +/* $Id: seqdbimpl.cpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -48,7 +48,7 @@ CSeqDBImpl::CSeqDBImpl(const string & db_name_list, CSeqDBGiList * gi_list, CSeqDBNegativeList * neg_list, CSeqDBIdSet idset) - : m_AtlasHolder (use_mmap, & m_FlushCB, NULL), + : m_AtlasHolder (use_mmap, NULL), m_Atlas (m_AtlasHolder.Get()), m_DBNames (db_name_list), m_Aliases (m_Atlas, db_name_list, prot_nucl), @@ -98,20 +98,7 @@ CSeqDBImpl::CSeqDBImpl(const string & db_name_list, SetIterationRange(0, m_NumOIDs); - try { - m_Atlas.Verify(false); - m_TaxInfo = new CSeqDBTaxInfo(m_Atlas); - m_Atlas.Verify(false); - } - catch(CSeqDBException &) { - } - - // Don't setup the flush callback until the implementation data - // structures are fully populated (otherwise flushing may try to - // flush unconstructed memory leases). - - m_FlushCB.SetImpl(this); - + // If the alias files seem to provide correct data for the totals, // use it; otherwise scan the OID list and use approximate lengths // to compute the totals. Presence of a user GI list implies that @@ -134,7 +121,7 @@ CSeqDBImpl::CSeqDBImpl(const string & db_name_list, x_ScanTotals(true, & m_NumSeqs, & m_TotalLength, & m_MaxLength, & m_MinLength, locked); - m_Atlas.Verify(locked); + } else { m_NumSeqs = x_GetNumSeqs(); m_TotalLength = x_GetTotalLength(); @@ -153,7 +140,6 @@ CSeqDBImpl::CSeqDBImpl(const string & db_name_list, m_UserGiList.Reset(); m_NegativeList.Reset(); m_VolSet.UnLease(); - m_FlushCB.SetImpl(0); throw e; } @@ -163,7 +149,7 @@ CSeqDBImpl::CSeqDBImpl(const string & db_name_list, } CSeqDBImpl::CSeqDBImpl() - : m_AtlasHolder (false, & m_FlushCB, NULL), + : m_AtlasHolder (false, NULL), m_Atlas (m_AtlasHolder.Get()), m_Aliases (m_Atlas, "", '-'), m_RestrictBegin (0), @@ -183,18 +169,6 @@ CSeqDBImpl::CSeqDBImpl() { INIT_CLASS_MARK(); - try { - m_TaxInfo = new CSeqDBTaxInfo(m_Atlas); - } - catch(CSeqDBException &) { - } - - // Don't setup the flush callback until the implementation data - // structures are fully populated (otherwise flushing may try to - // flush unconstructed memory leases). - - m_FlushCB.SetImpl(this); - CHECK_MARKER(); } @@ -228,11 +202,7 @@ CSeqDBImpl::~CSeqDBImpl() CSeqDBLockHold locked(m_Atlas); m_Atlas.Lock(locked); - // Prevent GC from flushing volumes after they are torn down. - - m_FlushCB.SetImpl(0); - - m_TaxInfo.Reset(); + m_VolSet.UnLease(); @@ -420,7 +390,7 @@ int CSeqDBImpl::GetSeqLength(int oid) const { CHECK_MARKER(); CSeqDBLockHold locked(m_Atlas); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); return x_GetSeqLength(oid, locked); } @@ -448,7 +418,7 @@ int CSeqDBImpl::GetSeqLengthApprox(int oid) const { CHECK_MARKER(); CSeqDBLockHold locked(m_Atlas); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); int vol_oid = 0; @@ -471,7 +441,7 @@ void CSeqDBImpl::GetTaxIDs(int oid, { CSeqDBLockHold locked(m_Atlas); m_Atlas.Lock(locked); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); if (! persist) { gi_to_taxid.clear(); @@ -506,7 +476,7 @@ void CSeqDBImpl::GetTaxIDs(int oid, bool persist) { CSeqDBLockHold locked(m_Atlas); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); if (! persist) { taxids.clear(); @@ -534,7 +504,7 @@ void CSeqDBImpl::GetLeafTaxIDs( { CSeqDBLockHold locked(m_Atlas); m_Atlas.Lock(locked); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); if (! persist) { gi_to_taxid_set.clear(); @@ -571,7 +541,7 @@ void CSeqDBImpl::GetLeafTaxIDs( { CSeqDBLockHold locked(m_Atlas); m_Atlas.Lock(locked); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); if (! persist) { taxids.clear(); @@ -613,7 +583,7 @@ CSeqDBImpl::GetBioseq(int oid, TGi target_gi, const CSeq_id * target_seq_id, boo CSeqDBLockHold locked(m_Atlas); m_Atlas.Lock(locked); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); int vol_oid = 0; @@ -625,7 +595,6 @@ CSeqDBImpl::GetBioseq(int oid, TGi target_gi, const CSeq_id * target_seq_id, boo return vol->GetBioseq(vol_oid, target_gi, target_seq_id, - m_TaxInfo, seqdata, locked); } @@ -648,9 +617,9 @@ void CSeqDBImpl::RetSequence(const char ** buffer) const // This returns a reference to part of a memory mapped region. - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); - m_Atlas.RetRegion(*buffer); + //m_Atlas.RetRegion(*buffer); *buffer = 0; } @@ -661,7 +630,7 @@ void CSeqDBImpl::RetAmbigSeq(const char ** buffer) const CSeqDBLockHold locked(m_Atlas); m_Atlas.Lock(locked); - m_Atlas.RetRegion(*buffer); + m_Atlas.RetRegion(*buffer);//Keep this *buffer = 0; } @@ -676,11 +645,11 @@ void CSeqDBImpl::x_RetSeqBuffer(SSeqResBuffer * buffer, buffer->checked_out = 0; m_Atlas.Lock(locked); - +/* for(Uint4 index = 0; index < buffer->results.size(); ++index) { m_Atlas.RetRegion(buffer->results[index].address); } - +*/ buffer->results.clear(); } @@ -733,7 +702,7 @@ void CSeqDBImpl::x_FillSeqBuffer(SSeqResBuffer *buffer, res.length = vol->GetSequence(vol_oid++, &seq, locked); } while (res.length >= 0 && tot_length >= res.length && vol_oid < m_RestrictEnd); - if (res.length >= 0) m_Atlas.RetRegion(seq); + //if (res.length >= 0) m_Atlas.RetRegion(seq); return; } @@ -754,7 +723,7 @@ int CSeqDBImpl::GetSequence(int oid, const char ** buffer) const int vol_oid = 0; m_Atlas.Lock(locked); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); if (const CSeqDBVol * vol = m_VolSet.FindVol(oid, vol_oid)) { return vol->GetSequence(vol_oid, buffer, locked); @@ -772,7 +741,7 @@ CRef CSeqDBImpl::GetSeqData(int oid, int vol_oid = 0; m_Atlas.Lock(locked); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); if (const CSeqDBVol * vol = m_VolSet.FindVol(oid, vol_oid)) { return vol->GetSeqData(vol_oid, begin, end, locked); @@ -792,7 +761,7 @@ int CSeqDBImpl::GetAmbigSeq(int oid, CSeqDBLockHold locked(m_Atlas); m_Atlas.Lock(locked); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); int vol_oid = 0; if (const CSeqDBVol * vol = m_VolSet.FindVol(oid, vol_oid)) { @@ -815,14 +784,14 @@ list< CRef > CSeqDBImpl::GetSeqIDs(int oid) CSeqDBLockHold locked(m_Atlas); m_Atlas.Lock(locked); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); if (! m_OidListSetup) { x_GetOidList(locked); } if (const CSeqDBVol * vol = m_VolSet.FindVol(oid, vol_oid)) { - return vol->GetSeqIDs(vol_oid, locked); + return vol->GetSeqIDs(vol_oid); } NCBI_THROW(CSeqDBException, eArgErr, CSeqDB::kOidNotFound); @@ -869,7 +838,7 @@ Uint8 CSeqDBImpl::GetExactTotalLength() CSeqDBLockHold locked(m_Atlas); x_ScanTotals(false, &m_NumSeqs, &m_ExactTotalLength, &m_MaxLength, &m_MinLength, locked); - m_Atlas.Verify(locked); + } else { m_ExactTotalLength = m_TotalLength; @@ -919,7 +888,7 @@ TGi CSeqDBImpl::x_GetSeqGI(int oid, CSeqDBLockHold & locked) if (gi>=ZERO_GI) return gi; // Fall back to parsing deflines list< CRef > ids = - vol->GetSeqIDs(vol_oid, locked); + vol->GetSeqIDs(vol_oid); ITERATE(list< CRef >, id, ids) { if ((**id).IsGi()) { return (**id).GetGi(); @@ -1066,7 +1035,7 @@ CSeqDBImpl::x_GetHdr(int oid, CSeqDBLockHold & locked) { CHECK_MARKER(); m_Atlas.Lock(locked); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); if (! m_OidListSetup) { x_GetOidList(locked); @@ -1118,13 +1087,6 @@ string CSeqDBImpl::x_FixString(const string & s) const return s; } -void CSeqDBImplFlush::operator()() -{ - if (m_Impl) { - m_Impl->FlushSeqMemory(); - } -} - // Assumes atlas is locked void CSeqDBImpl::FlushSeqMemory() @@ -1410,7 +1372,7 @@ CSeqDBImpl::FindVolumePaths(const string & dbname, bool recursive, bool expand_links) { - CSeqDBAtlasHolder AH(true, NULL, NULL); + CSeqDBAtlasHolder AH(true, NULL); CSeqDBAtlas & atlas(AH.Get()); // This constructor handles its own locking. @@ -1495,12 +1457,7 @@ void CSeqDBImpl::x_ScanTotals(bool approx, void CSeqDBImpl::GetTaxInfo(int taxid, SSeqDBTaxInfo & info) { - CSeqDBAtlasHolder AH(true, NULL, NULL); - CSeqDBAtlas &atlas(AH.Get()); - CSeqDBLockHold locked(atlas); - - CSeqDBTaxInfo taxinfo(atlas); - if (! taxinfo.GetTaxNames(taxid, info, locked)) { + if (! CSeqDBTaxInfo::GetTaxNames(taxid, info)) { CNcbiOstrstream oss; oss << "Taxid " << taxid << " not found"; string msg = CNcbiOstrstreamToString(oss); @@ -1557,7 +1514,7 @@ void CSeqDBImpl::GetRawSeqAndAmbig(int oid, CSeqDBLockHold locked(m_Atlas); m_Atlas.Lock(locked); - m_Atlas.MentionOid(oid, m_NumOIDs, locked); + //m_Atlas.MentionOid(oid, m_NumOIDs, locked); int vol_oid = 0; @@ -1754,11 +1711,6 @@ void CSeqDBImpl::FlushOffsetRangeCache() } -void CSeqDBImpl::SetDefaultMemoryBound(Uint8 bytes) -{ - CSeqDBAtlas::SetDefaultMemoryBound(bytes); -} - unsigned CSeqDBImpl::GetSequenceHash(int oid) { char * datap(0); @@ -1834,6 +1786,7 @@ CSeqDBIdSet CSeqDBImpl::GetIdSet() } else if (! m_NegativeList.Empty()) { const vector & ngis = m_NegativeList->GetGiList(); const vector & ntis = m_NegativeList->GetTiList(); + const vector & stis = m_NegativeList->GetSiList(); if (! ngis.empty()) { CSeqDBIdSet new_ids(ngis, CSeqDBIdSet::eGi, false); @@ -1841,6 +1794,9 @@ CSeqDBIdSet CSeqDBImpl::GetIdSet() } else if (! ntis.empty()) { CSeqDBIdSet new_ids(ntis, CSeqDBIdSet::eTi, false); m_IdSet = new_ids; + } else if (!stis.empty()) { + CSeqDBIdSet new_ids(stis, CSeqDBIdSet::eSi, false); + m_IdSet = new_ids; } } } @@ -2047,7 +2003,7 @@ static const string* s_CheckUniqueValues(const map & m) ITERATE(TStringMap, iter, m) { string v = iter->second; vector items; - NStr::Tokenize(v, ":", items); + NStr::Split(v, ":", items, NStr::fSplit_NoMergeDelims); if (items.size() == 4) { v = items[2]; @@ -2081,7 +2037,7 @@ void CSeqDB_IdRemapper::AddMapping(int vol_id, int id, const string & desc) { string real_desc = desc; vector items; - NStr::Tokenize(desc, ":", items); + NStr::Split(desc, ":", items, NStr::fSplit_NoMergeDelims); if (items.size() == 4) { real_desc = items[2]; } @@ -2257,8 +2213,7 @@ void s_GetDetails(const string & desc, _ASSERT(enum_type_vals); vector items; - NStr::Tokenize(desc, ":", items); - + NStr::Split(desc, ":", items, NStr::fSplit_NoMergeDelims); if (items.size() == 2) { EBlast_filter_program @@ -2452,13 +2407,6 @@ void CSeqDBImpl::GetMaskData(int oid, } #endif -void CSeqDBImpl::GarbageCollect(void) -{ - CHECK_MARKER(); - CSeqDBLockHold locked(m_Atlas); - m_Atlas.GarbageCollect(locked); -} - void CSeqDBImpl::SetNumberOfThreads(int num_threads, bool force_mt) { CSeqDBLockHold locked(m_Atlas); @@ -2479,7 +2427,7 @@ void CSeqDBImpl::SetNumberOfThreads(int num_threads, bool force_mt) for(int vol_idx = 0; vol_idx < m_VolSet.GetNumVols(); vol_idx++) { m_VolSet.GetVol(vol_idx)->OpenSeqFile(locked); } - m_Atlas.SetSliceSize(); + //m_Atlas.SetSliceSize(); } else if (num_threads < m_NumThreads) { @@ -2494,7 +2442,6 @@ void CSeqDBImpl::SetNumberOfThreads(int num_threads, bool force_mt) m_CacheID.clear(); m_NextCacheID = 0; m_NumThreads = num_threads; - } int CSeqDBImpl::x_GetCacheID(CSeqDBLockHold &locked) const @@ -2527,5 +2474,34 @@ void CSeqDBImpl::SetVolsMemBit(int mbit) } } +void CSeqDBImpl::DebugDump(CDebugDumpContext ddc, unsigned int depth) const +{ + ddc.SetFrame("CSeqDBImpl"); + CObject::DebugDump(ddc, depth); + ddc.Log("m_DBNames", m_DBNames); + ddc.Log("m_Aliases", &m_Aliases, depth); + ddc.Log("m_OIDList", m_OIDList, depth); + ddc.Log("m_RestrictBegin", m_RestrictBegin); + ddc.Log("m_RestrictEnd", m_RestrictEnd); + ddc.Log("m_NextChunkOID", m_NextChunkOID); + ddc.Log("m_NumSeqs", m_NumSeqs); + ddc.Log("m_NumSeqsStats", m_NumSeqsStats); + ddc.Log("m_NumOIDs", m_NumOIDs); + ddc.Log("m_TotalLength", m_TotalLength); + ddc.Log("m_ExactTotalLength", m_ExactTotalLength); + ddc.Log("m_TotalLengthStats", m_TotalLengthStats); + ddc.Log("m_VolumeLength", m_VolumeLength); + ddc.Log("m_MaxLength", m_MaxLength); + ddc.Log("m_MinLength", m_MinLength); + ddc.Log("m_SeqType", string(1, m_SeqType)); + ddc.Log("m_OidListSetup", m_OidListSetup); + ddc.Log("m_NeedTotalsScan", m_NeedTotalsScan); + ddc.Log("m_Date", m_Date); + ddc.Log("m_UseGiMask", m_UseGiMask); + ddc.Log("m_GiMask", m_GiMask); + ddc.Log("m_NumThreads", m_NumThreads); + ddc.Log("m_NextCacheID", m_NextCacheID); +} + END_NCBI_SCOPE diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbimpl.hpp b/c++/src/objtools/blast/seqdb_reader/seqdbimpl.hpp index af38eeb6..595d9da8 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbimpl.hpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbimpl.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBIMPL_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBIMPL_HPP -/* $Id: seqdbimpl.hpp 491223 2016-02-03 15:19:38Z rackerst $ +/* $Id: seqdbimpl.hpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -35,7 +35,6 @@ /// The top level of the private implementation layer for SeqDB. /// /// Defines classes: -/// CSeqDBImplFlush /// CSeqDBImpl /// /// Implemented for: UNIX, MS-Windows @@ -51,55 +50,6 @@ BEGIN_NCBI_SCOPE using namespace ncbi::objects; -/// CSeqDBImplFlush class -/// -/// This functor like object provides a call back mechanism to return -/// memory holds to the atlas, from lease objects in the other objects -/// under CSeqDBImpl. Without this class, CSeqDBAtlas and CSeqDBImpl -/// would be codependant, which is somewhat bad style, and creates -/// annoying cyclical dependencies among the include files. - -class CSeqDBImplFlush : public CSeqDBFlushCB { -public: - /// Constructor - CSeqDBImplFlush() - : m_Impl(0) - { - } - - /// Destructor - virtual ~CSeqDBImplFlush() - { - } - - /// Specify the implementation layer object. - /// - /// This method sets the SeqDB implementation layer object - /// pointer. Until this pointer is set, this object will ignore - /// attempts to flush unused data. This pointer should not bet - /// set until object construction is complete enough to permit the - /// memory lease flushing to happen safely. - /// - /// @param impl - /// A pointer to the implementation layer object. - virtual void SetImpl(class CSeqDBImpl * impl) - { - m_Impl = impl; - } - - /// Flush any held memory leases. - /// - /// At the beginning of garbage collection, this method is called - /// to tell the implementation layer to release any held memory - /// leases. If the SetImpl() method has not been called, this - /// method will do nothing. - virtual void operator()(); - -private: - /// A pointer to the SeqDB implementation layer. - CSeqDBImpl * m_Impl; -}; - /// Map user algorithm IDs to volume algorithm IDs. /// @@ -184,7 +134,7 @@ private: /// is seperated from that class so that various implementation /// details of CSeqDB are kept from the public interface. -class CSeqDBImpl { +class CSeqDBImpl : public CObject { /// Import type to allow shorter name. typedef TSeqDBAliasFileValues TAliasFileValues; @@ -634,22 +584,7 @@ public: /// @return A pointer to the attached ID set, or NULL. CSeqDBIdSet GetIdSet(); - /// Set upper limit on memory and mapping slice size. - /// - /// This sets an approximate upper limit on memory used by CSeqDB - /// for file mappings and large arrays. This will not be exactly - /// enforced; the library will prefer to exceed the bound rather - /// than return an error. Setting this to a very low value will - /// cause bad performance. If this is not set, SeqDB picks a - /// large value and lowers it if an allocation fails. - /// - /// @param membound Maximum memory to use for file mappings. - void SetMemoryBound(Uint8 membound) - { - CHECK_MARKER(); - m_Atlas.SetMemoryBound(membound); - } - + /// Flush unnecessarily held memory /// /// This is used by the atlas garbage collection callback - when @@ -767,11 +702,6 @@ public: /// The alias file values will be returned here. void GetAliasFileValues(TAliasFileValues & afv); - /// Verify consistency of the memory management (atlas) layer. - void Verify() - { - m_Atlas.Verify(false); - } /// Get taxonomy information /// @@ -932,18 +862,6 @@ public: /// Flush all offset ranges cached void FlushOffsetRangeCache(); - /// Set global default memory bound for SeqDB. - /// - /// The memory bound for individual SeqDB objects can be adjusted - /// with SetMemoryBound(), but this cannot be called until after - /// the object is constructed. Until that time, the value used is - /// set from a global default. This method allows that global - /// default value to be changed. Any SeqDB object constructed - /// after this method is called will use this value as the initial - /// memory bound. If zero is specified, an appropriate default - /// will be selected based on system information. - static void SetDefaultMemoryBound(Uint8 bytes); - /// Get the sequence hash for a given OID. /// /// The sequence data is fetched and the sequence hash is @@ -1099,7 +1017,7 @@ public: #endif /// Invoke the garbage collector to free up memory - void GarbageCollect(void); + //void GarbageCollect(void); /// Set number of threads /// @@ -1122,14 +1040,13 @@ public: /// internal mmap. [in] void SetNumberOfThreads(int num_threads, bool force_mt = false); - /// Retrieve the slice size used in internal mmap - Int8 GetSliceSize() const{ - return m_Atlas.GetSliceSize(); - } - /// Set the membership bit of all volumes void SetVolsMemBit(int mbit); + /// Dump debug information for this object + /// @sa CDebugDumpable + void DebugDump(CDebugDumpContext ddc, unsigned int depth) const; + private: CLASS_MARKER_FIELD("IMPL") @@ -1317,10 +1234,7 @@ private: /// The mapped local cache ID int x_GetCacheID(CSeqDBLockHold &locked) const; - /// This callback functor allows the atlas code flush any cached - /// region holds prior to garbage collection. - CSeqDBImplFlush m_FlushCB; - + /// Memory management layer guard (RIIA) object. CSeqDBAtlasHolder m_AtlasHolder; @@ -1339,9 +1253,6 @@ private: /// The list of included OIDs (construction is deferred). mutable CRef m_OIDList; - /// Taxonomic information. - CRef m_TaxInfo; - /// Starting OID as provided to the constructor. int m_RestrictBegin; @@ -1466,7 +1377,6 @@ private: /// Return sequence to buffer void x_RetSeqBuffer(SSeqResBuffer * buffer, CSeqDBLockHold & locked) const; - }; END_NCBI_SCOPE diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbisam.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbisam.cpp index bc17903c..af6c3738 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbisam.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbisam.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbisam.cpp 500834 2016-05-09 15:12:58Z rackerst $ +/* $Id: seqdbisam.cpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -26,7 +26,7 @@ * Author: Kevin Bealer * */ - +//IRENA: ALL locking removed from this file CSeqDBLockHold & stays in some functions but is not used /// @file seqdbisam.cpp /// Implementation for the CSeqDBIsam class, which manages an ISAM /// index of some particular kind of identifiers. @@ -56,25 +56,24 @@ USING_SCOPE(objects); CSeqDBIsam::EErrorCode -CSeqDBIsam::x_InitSearch(CSeqDBLockHold & locked) +CSeqDBIsam::x_InitSearch(void) { if(m_Initialized == true) return eNoError; TIndx info_needed = 10 * sizeof(Int4); - m_Atlas.Lock(locked); - + //m_Atlas.Lock(locked); + bool found_index_file = - m_Atlas.GetFileSize(m_IndexFname, m_IndexFileLength, locked); - + m_Atlas.GetFileSizeL(m_IndexFname, m_IndexFileLength); + if ((! found_index_file) || (m_IndexFileLength < info_needed)) { return eWrongFile; } - m_Atlas.GetRegion(m_IndexLease, m_IndexFname, 0, info_needed); - - Int4 * FileInfo = (Int4*) m_IndexLease.GetPtr(0); + + Int4 * FileInfo = (Int4*)m_IndexLease.GetFileDataPtr(m_IndexFname,0); // Check for consistence of files and parameters @@ -105,8 +104,8 @@ CSeqDBIsam::x_InitSearch(CSeqDBLockHold & locked) TIndx disk_file_length(0); bool found_data_file = - m_Atlas.GetFileSize(m_DataFname, disk_file_length, locked); - + m_Atlas.GetFileSizeL(m_DataFname, disk_file_length); + if ((! found_data_file) || (m_DataFileLength != disk_file_length)) { return eWrongFile; } @@ -144,13 +143,14 @@ CSeqDBIsam::x_SearchIndexNumeric(Int8 Number, int * Data, Uint4 * Index, Int4 & SampleNum, - bool & done, - CSeqDBLockHold & locked) + bool & done) + { - m_Atlas.Lock(locked); - + //m_Atlas.Lock(locked); + + x_InitLease();//Map files if needed if(m_Initialized == false) { - EErrorCode error = x_InitSearch(locked); + EErrorCode error = x_InitSearch(); if(error != eNoError) { done = true; @@ -158,7 +158,7 @@ CSeqDBIsam::x_SearchIndexNumeric(Int8 Number, } } - if (x_OutOfBounds(Number, locked)) { + if (x_OutOfBounds(Number)) { done = true; return eNotFound; } @@ -174,22 +174,13 @@ CSeqDBIsam::x_SearchIndexNumeric(Int8 Number, SampleNum = ((Uint4)(Stop + Start)) >> 1; TIndx offset_begin = m_KeySampleOffset + (m_TermSize * SampleNum); - TIndx offset_end = offset_begin + m_TermSize; - - m_Atlas.Lock(locked); - - if (! m_IndexLease.Contains(offset_begin, offset_end)) { - m_Atlas.GetRegion(m_IndexLease, - m_IndexFname, - offset_begin, - offset_end); - } - + //TIndx offset_end = offset_begin + m_TermSize; + const void* keydatap(0); Int8 Key(0); - keydatap = m_IndexLease.GetPtr(offset_begin); + keydatap = m_IndexLease.GetFileDataPtr(m_IndexFname,offset_begin); Key = x_GetNumericKey (keydatap); // If this is an exact match, return the master term number. @@ -236,13 +227,14 @@ void CSeqDBIsam::x_SearchNegativeMulti(int vol_start, int vol_end, CSeqDBNegativeList & ids, - bool use_tis, - CSeqDBLockHold & locked) + bool use_tis) + { - m_Atlas.Lock(locked); - + //m_Atlas.Lock(locked); + + x_InitLease();//Map files if needed if(m_Initialized == false) { - EErrorCode error = x_InitSearch(locked); + EErrorCode error = x_InitSearch(); if(error != eNoError) { // Most ordinary errors (missing IDs for example) are @@ -255,7 +247,8 @@ CSeqDBIsam::x_SearchNegativeMulti(int vol_start, } } - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); + // We can use Parabolic Binary Search for the negative GI list but // not for the ISAM file data, because in the negative ID list @@ -282,8 +275,7 @@ CSeqDBIsam::x_SearchNegativeMulti(int vol_start, x_MapDataPage(sample_index, start, num_elements, - & data_page, - locked); + & data_page); for(int i = 0; i < num_elements; i++) { Int8 isam_key(0); @@ -328,13 +320,133 @@ CSeqDBIsam::x_SearchNegativeMulti(int vol_start, } } +//In case if acc2 does not have version and acc1 has version +//check if it is the same accession +static bool s_IsSameAccession(string acc1, string acc2) +{ + bool sameAccession = false; + if(NStr::Find(acc2,".") == NPOS) { // no version in acc2 + if(NStr::Find(acc1,".") != NPOS && NStr::Find(acc1, acc2) != NPOS) { + string accession, version; + NStr::SplitInTwo(acc1,".", accession, version); + if(acc2 == accession) { + sameAccession = true; + } + } + } + return sameAccession; +} + +//In case if keys[currIndex] does not have version and keys[currIndex + 1] has version +//check if it is the same accession +static bool s_IsSameAccession(vector keys, int num_keys, int currIndex) +{ + bool sameAccession = false; + if(currIndex < num_keys - 1) { + sameAccession = s_IsSameAccession(keys[currIndex + 1], keys[currIndex]); + } + return sameAccession; +} + +void +CSeqDBIsam::x_SearchNegativeMultiSeq(int vol_start, + int vol_end, + CSeqDBNegativeList & ids) + +{ + int gilist_size = ids.ListSize(); + if (! gilist_size) return; + + x_InitLease();//Map files if needed + if(m_Initialized == false) { + EErrorCode error = x_InitSearch(); + + if(error != eNoError) { + // Most ordinary errors (missing GIs for example) are + // ignored for "multi" mode searches. But if a GI list is + // specified, and cannot be interpreted, it is an error. + + NCBI_THROW(CSeqDBException, + eArgErr, + "Error: Unable to use ISAM index in batch mode."); + } + } + + + vector sample_keys; + vector page_offs; + vector keys; + vector vals; + + sample_keys.reserve(m_NumSamples); + page_offs.reserve(m_NumSamples + 1); + keys.reserve(m_PageSize); + vals.reserve(m_PageSize); + + + x_LoadIndex(m_IndexLease, sample_keys, page_offs); + + int gilist_index = 0; + int sample_index = 0; + + while(sample_index < m_NumSamples) { + + // Now we should be ready to search a data block. + keys.clear(); + vals.clear(); + + int num_keys = m_PageSize; + if (sample_index + 1 == m_NumSamples) { + num_keys = m_NumTerms - sample_index * m_PageSize; + } + + x_LoadData(m_DataLease, keys, vals, num_keys, page_offs[sample_index]); + + for(int i = 0; i < num_keys; i++) { + // 2. Look for it in the negative id list. + + bool found = false; + if (gilist_index < gilist_size) { + found = x_FindInNegativeList(ids, + gilist_index, + keys[i]); + + } + if (vals[i] < vol_end) { + if (found) { + // OID is found, but may not be included yet. + ids.AddVisibleOid(vals[i] + vol_start); + //If next accession is the same as current, but with version + if(s_IsSameAccession(keys, num_keys, i)) { + i++; //skip next check - sequence already excluded + } + } else { + // OID is included for iteration. + //Only include next accession if it is not the same as current (but with version) + //because it may be in exclude list. The check will be done in the next step + if(!s_IsSameAccession(keys, num_keys, i)) { + ids.AddIncludedOid(vals[i] + vol_start); + } + } + } + + } + // Move to next data page. Note that for a negative ID list + // processing, we don't actually fetch any samples, because + // every ID->OID line needs to be examined anyway. + + sample_index ++; + + } +} + CSeqDBIsam::EErrorCode CSeqDBIsam::x_SearchDataNumeric(Int8 Number, int * Data, Uint4 * Index, - Int4 SampleNum, - CSeqDBLockHold & locked) + Int4 SampleNum) + { // Load the appropriate page of numbers into memory. _ASSERT(m_Type != eNumericNoData); @@ -349,18 +461,10 @@ CSeqDBIsam::x_SearchDataNumeric(Int8 Number, const void * KeyDataPageStart = NULL; TIndx offset_begin = Start * m_TermSize; - TIndx offset_end = offset_begin + m_TermSize * NumElements; - - m_Atlas.Lock(locked); - - if (! m_DataLease.Contains(offset_begin, offset_end)) { - m_Atlas.GetRegion(m_DataLease, - m_DataFname, - offset_begin, - offset_end); - } - - KeyDataPageStart = m_DataLease.GetPtr(offset_begin); + //TIndx offset_end = offset_begin + m_TermSize * NumElements; + + KeyDataPageStart = m_DataLease.GetFileDataPtr(m_DataFname,offset_begin); + KeyDataPage = (char *)KeyDataPageStart - Start * m_TermSize; @@ -417,34 +521,34 @@ CSeqDBIsam::x_SearchDataNumeric(Int8 Number, CSeqDBIsam::EErrorCode CSeqDBIsam::x_NumericSearch(Int8 Number, int * Data, - Uint4 * Index, - CSeqDBLockHold & locked) + Uint4 * Index) + { bool done (false); Int4 SampleNum (0); EErrorCode error = - x_SearchIndexNumeric(Number, Data, Index, SampleNum, done, locked); + x_SearchIndexNumeric(Number, Data, Index, SampleNum, done); if (! done) { - error = x_SearchDataNumeric(Number, Data, Index, SampleNum, locked); + error = x_SearchDataNumeric(Number, Data, Index, SampleNum); } return error; } int CSeqDBIsam::x_DiffCharLease(const string & term_in, - CSeqDBMemLease & lease, + CSeqDBFileMemMap & lease, const string & file_name, TIndx file_length, Uint4 at_least, TIndx KeyOffset, - bool ignore_case, - CSeqDBLockHold & locked) + bool ignore_case) + { int result(-1); - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); // Add one to term_end to insure we don't consider "AA" and "AAB" // as equal. @@ -461,15 +565,8 @@ int CSeqDBIsam::x_DiffCharLease(const string & term_in, result = int(file_length - offset_begin); } } - - if (! lease.Contains(offset_begin, map_end)) { - m_Atlas.GetRegion( lease, - file_name, - offset_begin, - term_end ); - } - - const char * file_data = lease.GetPtr(offset_begin); + + const char * file_data = (const char *)lease.GetFileDataPtr(file_name,offset_begin); Int4 dc_result = x_DiffChar(term_in, @@ -616,8 +713,8 @@ void CSeqDBIsam::x_ExtractAllData(const string & term_in, TIndx sample_index, vector & indices_out, vector & keys_out, - vector & data_out, - CSeqDBLockHold & locked) + vector & data_out) + { // The object at sample_index is known to match; we will iterate // over the surrounding values to see if they match as well. No @@ -651,7 +748,7 @@ void CSeqDBIsam::x_ExtractAllData(const string & term_in, end_off = sample_index + post_amt; } - x_LoadPage(beg_off, end_off, & beginp, & endp, locked); + x_LoadPage(beg_off, end_off, & beginp, & endp); if (! done_b) { Int4 diff_begin = x_DiffChar(term_in, @@ -748,23 +845,14 @@ void CSeqDBIsam::x_ExtractData(const char * key_start, CSeqDBIsam::TIndx CSeqDBIsam::x_GetIndexKeyOffset(TIndx sample_offset, - Uint4 sample_num, - CSeqDBLockHold & locked) + Uint4 sample_num) + { TIndx offset_begin = sample_offset + (sample_num * sizeof(Uint4)); - TIndx offset_end = offset_begin + sizeof(Uint4); - - m_Atlas.Lock(locked); - - if (! m_IndexLease.Contains(offset_begin, offset_end)) { - m_Atlas.GetRegion(m_IndexLease, - m_IndexFname, - offset_begin, - offset_end); - } - - Int4 * key_offset_addr = (Int4 *) m_IndexLease.GetPtr(offset_begin); + //TIndx offset_end = offset_begin + sizeof(Uint4); + + Int4 * key_offset_addr = (Int4 *)m_IndexLease.GetFileDataPtr(offset_begin); return SeqDB_GetStdOrd(key_offset_addr); } @@ -772,22 +860,14 @@ void CSeqDBIsam::x_GetIndexString(TIndx key_offset, int length, string & str, - bool trim_to_null, - CSeqDBLockHold & locked) + bool trim_to_null) + { - TIndx offset_end = key_offset + length; - - m_Atlas.Lock(locked); - - if (! m_IndexLease.Contains(key_offset, offset_end)) { - m_Atlas.GetRegion(m_IndexLease, - m_IndexFname, - key_offset, - offset_end); - } - - const char * key_offset_addr = - (const char *) m_IndexLease.GetPtr(key_offset); + //TIndx offset_end = key_offset + length; + + const char * key_offset_addr = + (const char *)m_IndexLease.GetFileDataPtr(key_offset); + if (trim_to_null) { for(int i = 0; i SampleNum1); TIndx begin_offset = m_KeySampleOffset + SampleNum1 * sizeof(Uint4); - TIndx end_offset = m_KeySampleOffset + (SampleNum2 + 1) * sizeof(Uint4); - - m_Atlas.Lock(locked); - - if (! m_IndexLease.Contains(begin_offset, end_offset)) { - m_Atlas.GetRegion(m_IndexLease, m_IndexFname, begin_offset, end_offset); - } - - Uint4 * key_offsets((Uint4*) m_IndexLease.GetPtr(begin_offset)); + //TIndx end_offset = m_KeySampleOffset + (SampleNum2 + 1) * sizeof(Uint4); + + Uint4 * key_offsets((Uint4*)m_IndexLease.GetFileDataPtr(begin_offset)); + Uint4 key_off1 = SeqDB_GetStdOrd(& key_offsets[0]); Uint4 key_off2 = SeqDB_GetStdOrd(& key_offsets[SampleNum2 - SampleNum1]); - - if (! m_DataLease.Contains(key_off1, key_off2)) { - m_Atlas.GetRegion(m_DataLease, m_DataFname, key_off1, key_off2); - } - - *beginp = (const char *) m_DataLease.GetPtr(key_off1); - *endp = (const char *) m_DataLease.GetPtr(key_off2); + + *beginp = (const char *) m_DataLease.GetFileDataPtr(m_DataFname,key_off1); + *endp = (const char *) m_DataLease.GetFileDataPtr(key_off2); } @@ -896,8 +958,8 @@ CSeqDBIsam::EErrorCode CSeqDBIsam::x_StringSearch(const string & term_in, vector & terms_out, vector & values_out, - vector & indices_out, - CSeqDBLockHold & locked) + vector & indices_out) + { // These are always false; They may relate to the prior find_one / // expand_to_many method of getting multiple OIDs. @@ -907,15 +969,16 @@ CSeqDBIsam::x_StringSearch(const string & term_in, size_t preexisting_data_count = values_out.size(); + x_InitLease();//Map files if needed if (m_Initialized == false) { - EErrorCode error = x_InitSearch(locked); + EErrorCode error = x_InitSearch(); if(error != eNoError) { return error; } } - if (x_OutOfBounds(term_in, locked)) { + if (x_OutOfBounds(term_in)) { return eNotFound; } @@ -945,11 +1008,11 @@ CSeqDBIsam::x_StringSearch(const string & term_in, TIndx KeyOffset(0); - int diff = x_DiffSample(term_in, SampleNum, KeyOffset, locked); + int diff = x_DiffSample(term_in, SampleNum, KeyOffset); // If this is an exact match, return the master term number. - - const char * KeyData = m_IndexLease.GetPtr(KeyOffset); + + const char * KeyData = (const char *)m_IndexLease.GetFileDataPtr(KeyOffset); TIndx BytesToEnd = m_IndexFileLength - KeyOffset; Uint4 max_lines_2 = m_MaxLineSize * 2; @@ -963,8 +1026,8 @@ CSeqDBIsam::x_StringSearch(const string & term_in, SampleNum, indices_out, terms_out, - values_out, - locked); + values_out); + return eNoError; } @@ -979,11 +1042,11 @@ CSeqDBIsam::x_StringSearch(const string & term_in, while(SampleNum > 0) { TIndx key_offset = x_GetIndexKeyOffset(SampleOffset, - SampleNum, - locked); + SampleNum); + string prefix; - x_GetIndexString(key_offset, Length, prefix, false, locked); + x_GetIndexString(key_offset, Length, prefix, false); if (ignore_case) { if (NStr::CompareNocase(prefix, term_in) != 0) { @@ -1002,11 +1065,11 @@ CSeqDBIsam::x_StringSearch(const string & term_in, TIndx key_offset = x_GetIndexKeyOffset(SampleOffset, - SampleNum + 1, - locked); + SampleNum + 1); + string prefix; - x_GetIndexString(key_offset, max_lines_2, short_term, true, locked); + x_GetIndexString(key_offset, max_lines_2, short_term, true); break; } else { @@ -1015,7 +1078,7 @@ CSeqDBIsam::x_StringSearch(const string & term_in, if (follow_match) { found_short = SampleNum; - x_GetIndexString(KeyOffset, max_lines_2, short_term, true, locked); + x_GetIndexString(KeyOffset, max_lines_2, short_term, true); } } @@ -1042,7 +1105,7 @@ CSeqDBIsam::x_StringSearch(const string & term_in, const char * beginp(0); const char * endp(0); - x_LoadPage(SampleNum, SampleNum + 1, & beginp, & endp, locked); + x_LoadPage(SampleNum, SampleNum + 1, & beginp, & endp); // Search the page for the term. @@ -1122,7 +1185,8 @@ CSeqDBIsam::CSeqDBIsam(CSeqDBAtlas & atlas, msg += m_IndexFname + "/" + m_DataFname + ")"; NCBI_THROW(CSeqDBException, eFileErr, msg); } - + m_IndexLease.Init(m_IndexFname); + m_DataLease.Init(m_DataFname); if(m_Type == eNumeric) { m_PageSize = DEFAULT_NISAM_SIZE; } else { @@ -1170,23 +1234,19 @@ bool CSeqDBIsam::IndexExists(const string & dbname, CSeqDBIsam::~CSeqDBIsam() { - UnLease(); + UnLease(); } - +//Remove this void CSeqDBIsam::UnLease() { - if (! m_IndexLease.Empty()) { - m_Atlas.RetRegion(m_IndexLease); - } - if (! m_DataLease.Empty()) { - m_Atlas.RetRegion(m_DataLease); - } + m_IndexLease.Clear(); + m_DataLease.Clear(); } -bool CSeqDBIsam::x_IdentToOid(Int8 ident, TOid & oid, CSeqDBLockHold & locked) +bool CSeqDBIsam::x_IdentToOid(Int8 ident, TOid & oid) { EErrorCode err = - x_NumericSearch(ident, & oid, 0, locked); + x_NumericSearch(ident, & oid, 0); if (err == eNoError) { return true; @@ -1200,18 +1260,19 @@ bool CSeqDBIsam::x_IdentToOid(Int8 ident, TOid & oid, CSeqDBLockHold & locked) void CSeqDBIsam::StringToOids(const string & acc, vector & oids, bool adjusted, - bool & version_check, - CSeqDBLockHold & locked) + bool & version_check) + { bool strip_version = version_check; version_check = false; _ASSERT(m_IdentType == eStringId); - m_Atlas.Lock(locked); - + //m_Atlas.Lock(locked); + + x_InitLease();//Map files if needed if(m_Initialized == false) { - if (eNoError != x_InitSearch(locked)) { + if (eNoError != x_InitSearch()) { return; } } @@ -1231,8 +1292,7 @@ void CSeqDBIsam::StringToOids(const string & acc, if ((err = x_StringSearch(accession, keys_out, data_out, - indices_out, - locked)) < 0) { + indices_out)) < 0) { return; } @@ -1244,8 +1304,8 @@ void CSeqDBIsam::StringToOids(const string & acc, (err = x_StringSearch(locus_str, keys_out, data_out, - indices_out, - locked)) < 0) { + indices_out)) < 0) { + return; } @@ -1258,8 +1318,8 @@ void CSeqDBIsam::StringToOids(const string & acc, (err = x_StringSearch(acc, keys_out, data_out, - indices_out, - locked)) < 0) { + indices_out)) < 0) { + return; } @@ -1292,8 +1352,8 @@ void CSeqDBIsam::StringToOids(const string & acc, err = x_StringSearch(nover, keys_out, data_out, - indices_out, - locked); + indices_out); + if (data_out.size()) { version_check = true; @@ -1327,8 +1387,8 @@ void CSeqDBIsam::StringToOids(const string & acc, ((err = x_StringSearch(id, keys_out, data_out, - indices_out, - locked)) < 0)) { + indices_out)) < 0)) { + return; } } @@ -1346,8 +1406,8 @@ void CSeqDBIsam::StringToOids(const string & acc, bool CSeqDBIsam::x_SparseStringToOids(const string &, vector &, - bool, - CSeqDBLockHold &) + bool) + { cerr << " this should be derived from readdb_acc2fastaEx().." << endl; _TROUBLE; @@ -1356,23 +1416,24 @@ bool CSeqDBIsam::x_SparseStringToOids(const string &, void CSeqDBIsam::IdsToOids(int vol_start, int vol_end, - CSeqDBGiList & ids, - CSeqDBLockHold & locked) + CSeqDBGiList & ids) + + { // The vol_start parameter is needed because translations in the // GI list should refer to global OIDs, not per-volume OIDs. switch (m_IdentType) { case eGiId: - x_TranslateGiList(vol_start, ids, locked); + x_TranslateGiList(vol_start, ids); break; case eTiId: - x_TranslateGiList(vol_start, ids, locked); + x_TranslateGiList(vol_start, ids); break; case eStringId: - x_TranslateGiList(vol_start, ids, locked); + x_TranslateGiList(vol_start, ids); break; default: @@ -1384,40 +1445,51 @@ void CSeqDBIsam::IdsToOids(int vol_start, void CSeqDBIsam::IdsToOids(int vol_start, int vol_end, - CSeqDBNegativeList & ids, - CSeqDBLockHold & locked) + CSeqDBNegativeList & ids) + + { // The vol_start parameter is needed because translations in the // GI list should refer to global OIDs, not per-volume OIDs. - _ASSERT(m_IdentType == eGiId || m_IdentType == eTiId); + _ASSERT(m_IdentType == eGiId || m_IdentType == eTiId || m_IdentType == eStringId); - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); + ids.InsureOrder(); if ((m_IdentType == eGiId) && ids.GetNumGis()) { x_SearchNegativeMulti(vol_start, vol_end, ids, - false, - locked); + false); + } if ((m_IdentType == eTiId) && ids.GetNumTis()) { x_SearchNegativeMulti(vol_start, vol_end, ids, - true, - locked); + true); + + } + + if(m_IdentType == eStringId && ids.GetNumSis()) { + x_SearchNegativeMultiSeq(vol_start, + vol_end, + ids); + //true, + } } -void CSeqDBIsam::x_FindIndexBounds(CSeqDBLockHold & locked) +void CSeqDBIsam::x_FindIndexBounds() { Int4 Start (0); Int4 Stop (m_NumSamples - 1); - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); + if (m_Type == eNumeric) { // @@ -1430,8 +1502,8 @@ void CSeqDBIsam::x_FindIndexBounds(CSeqDBLockHold & locked) x_MapDataPage(Start, start, num_elements, - & data_page, - locked); + & data_page); + _ASSERT(num_elements); @@ -1454,8 +1526,8 @@ void CSeqDBIsam::x_FindIndexBounds(CSeqDBLockHold & locked) x_MapDataPage(Stop, start, num_elements, - & data_page, - locked); + & data_page); + _ASSERT(num_elements); @@ -1477,7 +1549,7 @@ void CSeqDBIsam::x_FindIndexBounds(CSeqDBLockHold & locked) // // Load the first page - x_LoadPage(Start, Start + 1, & beginp, & endp, locked); + x_LoadPage(Start, Start + 1, & beginp, & endp); // Get first term @@ -1496,7 +1568,7 @@ void CSeqDBIsam::x_FindIndexBounds(CSeqDBLockHold & locked) // // Load the last page - x_LoadPage(Stop, Stop + 1, & beginp, & endp, locked); + x_LoadPage(Stop, Stop + 1, & beginp, & endp); // Advance to last item @@ -1535,10 +1607,10 @@ void CSeqDBIsam::x_FindIndexBounds(CSeqDBLockHold & locked) } } -bool CSeqDBIsam::x_OutOfBounds(Int8 key, CSeqDBLockHold & locked) +bool CSeqDBIsam::x_OutOfBounds(Int8 key) { if (! m_FirstKey.IsSet()) { - x_FindIndexBounds(locked); + x_FindIndexBounds(); } if (! (m_FirstKey.IsSet() && m_LastKey.IsSet())) { @@ -1558,10 +1630,10 @@ bool CSeqDBIsam::x_OutOfBounds(Int8 key, CSeqDBLockHold & locked) return false; } -bool CSeqDBIsam::x_OutOfBounds(string key, CSeqDBLockHold & locked) +bool CSeqDBIsam::x_OutOfBounds(string key) { if (! m_FirstKey.IsSet()) { - x_FindIndexBounds(locked); + x_FindIndexBounds(); } if (! (m_FirstKey.IsSet() && m_LastKey.IsSet())) { @@ -1585,13 +1657,15 @@ bool CSeqDBIsam::x_OutOfBounds(string key, CSeqDBLockHold & locked) void CSeqDBIsam::GetIdBounds(Int8 & low_id, Int8 & high_id, - int & count, - CSeqDBLockHold & locked) + int & count) + + { - m_Atlas.Lock(locked); - + //m_Atlas.Lock(locked); + + x_InitLease();//Map files if needed if(m_Initialized == false) { - EErrorCode error = x_InitSearch(locked); + EErrorCode error = x_InitSearch(); if(error != eNoError) { count = 0; @@ -1600,7 +1674,7 @@ void CSeqDBIsam::GetIdBounds(Int8 & low_id, } if (! (m_FirstKey.IsSet() && m_LastKey.IsSet())) { - x_FindIndexBounds(locked); + x_FindIndexBounds(); } low_id = m_FirstKey.GetNumeric(); @@ -1610,13 +1684,15 @@ void CSeqDBIsam::GetIdBounds(Int8 & low_id, void CSeqDBIsam::GetIdBounds(string & low_id, string & high_id, - int & count, - CSeqDBLockHold & locked) + int & count) + + { - m_Atlas.Lock(locked); - + //m_Atlas.Lock(locked); + + x_InitLease();//Map files if needed if(m_Initialized == false) { - EErrorCode error = x_InitSearch(locked); + EErrorCode error = x_InitSearch(); if(error != eNoError) { count = 0; @@ -1625,7 +1701,7 @@ void CSeqDBIsam::GetIdBounds(string & low_id, } if (! (m_FirstKey.IsSet() && m_LastKey.IsSet())) { - x_FindIndexBounds(locked); + x_FindIndexBounds(); } low_id = m_FirstKey.GetString(); @@ -1634,15 +1710,17 @@ void CSeqDBIsam::GetIdBounds(string & low_id, } void CSeqDBIsam::HashToOids(unsigned hash, - vector & oids, - CSeqDBLockHold & locked) + vector & oids) + + { _ASSERT(m_IdentType == eHashId); - m_Atlas.Lock(locked); - + //m_Atlas.Lock(locked); + + x_InitLease();//Map files if needed if(m_Initialized == false) { - if (eNoError != x_InitSearch(locked)) { + if (eNoError != x_InitSearch()) { return; } } @@ -1660,8 +1738,8 @@ void CSeqDBIsam::HashToOids(unsigned hash, if ((err = x_StringSearch(key, keys_out, data_out, - indices_out, - locked)) < 0) { + indices_out)) < 0) { + return; } diff --git a/c++/src/objtools/blast/seqdb_reader/seqdboidlist.cpp b/c++/src/objtools/blast/seqdb_reader/seqdboidlist.cpp index e4ba7238..b5fe7fe9 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdboidlist.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdboidlist.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdboidlist.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: seqdboidlist.cpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -46,8 +46,8 @@ CSeqDBOIDList::CSeqDBOIDList(CSeqDBAtlas & atlas, CRef & gi_list, CRef & neg_list, CSeqDBLockHold & locked) - : m_Atlas (atlas), - m_Lease (atlas), + : m_Atlas (atlas), + m_Lease (atlas), m_NumOIDs (0) { _ASSERT(gi_list.NotEmpty() || neg_list.NotEmpty() || filters.HasFilter()); @@ -97,9 +97,9 @@ void CSeqDBOIDList::x_Setup(const CSeqDBVolSet & volset, } if (gi_list.NotEmpty()) { - x_ApplyUserGiList(*gi_list, locked); + x_ApplyUserGiList(*gi_list); } else if (neg_list.NotEmpty()) { - x_ApplyNegativeList(*neg_list, locked); + x_ApplyNegativeList(*neg_list); } while(m_NumOIDs && (! x_IsSet(m_NumOIDs - 1))) { @@ -213,7 +213,7 @@ CSeqDBOIDList::x_ComputeFilters(const CSeqDB_FilterTree & filters, switch(mask.GetType()) { case CSeqDB_AliasMask::eOidList: - f = x_GetOidMask(mask.GetPath(), vol_start, vol_end, locked); + f = x_GetOidMask(mask.GetPath(), vol_start, vol_end); break; case CSeqDB_AliasMask::eSiList: @@ -255,10 +255,10 @@ CSeqDBOIDList::x_ComputeFilters(const CSeqDB_FilterTree & filters, return volume_map; } -void CSeqDBOIDList::x_ApplyUserGiList(CSeqDBGiList & gis, - CSeqDBLockHold & locked) +void CSeqDBOIDList::x_ApplyUserGiList(CSeqDBGiList & gis) + { - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); if (gis.Empty()) { x_ClearBitRange(0, m_NumOIDs); @@ -304,10 +304,10 @@ void CSeqDBOIDList::x_ApplyUserGiList(CSeqDBGiList & gis, m_AllBits->IntersectWith(*gilist_oids, true); } -void CSeqDBOIDList::x_ApplyNegativeList(CSeqDBNegativeList & nlist, - CSeqDBLockHold & locked) +void CSeqDBOIDList::x_ApplyNegativeList(CSeqDBNegativeList & nlist) + { - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); // Intersect the user GI list with the OID bit map. @@ -399,25 +399,24 @@ void CSeqDBOIDList::x_ClearBitRange(int oid_start, CRef CSeqDBOIDList::x_GetOidMask(const CSeqDB_Path & fn, int vol_start, - int vol_end, - CSeqDBLockHold & locked) + int vol_end) + { - m_Atlas.Lock(locked); - + // Open file and get pointers TCUC* bitmap = 0; TCUC* bitend = 0; CSeqDBRawFile volmask(m_Atlas); - CSeqDBMemLease lease(m_Atlas); + CSeqDBFileMemMap lease(m_Atlas); Uint4 num_oids = 0; { - volmask.Open(fn, locked); - - volmask.ReadSwapped(lease, 0, & num_oids, locked); + volmask.Open(fn); + lease.Init(fn.GetPathS()); + volmask.ReadSwapped(lease, 0, & num_oids); // This is the index of the last oid, not the count of oids... num_oids++; @@ -426,13 +425,15 @@ CSeqDBOIDList::x_GetOidMask(const CSeqDB_Path & fn, // Cast forces signed/unsigned conversion. - volmask.GetRegion(lease, sizeof(Int4), file_length, locked); - bitmap = (TCUC*) lease.GetPtr(sizeof(Int4)); + volmask.GetFileDataPtr(lease, sizeof(Int4), file_length); + + bitmap = (TCUC*) lease.GetFileDataPtr(sizeof(Int4)); + bitend = bitmap + (((num_oids + 31) / 32) * 4); } CRef bitset(new CSeqDB_BitSet(vol_start, vol_end, bitmap, bitend)); - m_Atlas.RetRegion(lease); + // Disable any enabled bits occuring after the volume end point // [this should not normally occur.] @@ -444,5 +445,14 @@ CSeqDBOIDList::x_GetOidMask(const CSeqDB_Path & fn, return bitset; } +void +CSeqDBOIDList::DebugDump(CDebugDumpContext ddc, unsigned int depth) const +{ + ddc.SetFrame("CSeqDBOIDList"); + CObject::DebugDump(ddc, depth); + ddc.Log("m_NumOIDs", m_NumOIDs); + ddc.Log("m_AllBits", m_AllBits, depth); +} + END_NCBI_SCOPE diff --git a/c++/src/objtools/blast/seqdb_reader/seqdboidlist.hpp b/c++/src/objtools/blast/seqdb_reader/seqdboidlist.hpp index 0a207a72..ac4d17d9 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdboidlist.hpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdboidlist.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBOIDLIST_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBOIDLIST_HPP -/* $Id: seqdboidlist.hpp 311249 2011-07-11 14:12:16Z camacho $ +/* $Id: seqdboidlist.hpp 530464 2017-03-15 14:36:01Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -138,6 +138,10 @@ public: { m_Lease.Clear(); } + + /// Dump debug information for this object + /// @sa CDebugDumpable + void DebugDump(CDebugDumpContext ddc, unsigned int depth) const; private: /// Shorthand type to clarify code that iterates over memory. @@ -225,8 +229,8 @@ private: CRef x_GetOidMask(const CSeqDB_Path & fn, int vol_start, - int vol_end, - CSeqDBLockHold & locked); + int vol_end); + /// Load an ID (GI or TI) list file into a bitset object. /// @@ -249,8 +253,8 @@ private: /// The user gi list to apply to the volumes. /// @param locked /// The lock holder object for this thread. - void x_ApplyUserGiList(CSeqDBGiList & gis, - CSeqDBLockHold & locked); + void x_ApplyUserGiList(CSeqDBGiList & gis); + /// Apply a negative user GI list to a volume. /// @@ -265,14 +269,14 @@ private: /// The negative user gi list to apply to the volumes. /// @param locked /// The lock holder object for this thread. - void x_ApplyNegativeList(CSeqDBNegativeList & neg, - CSeqDBLockHold & locked); + void x_ApplyNegativeList(CSeqDBNegativeList & neg); + /// The memory management layer object. CSeqDBAtlas & m_Atlas; /// A memory lease which holds the mask file (if only one is used). - CSeqDBMemLease m_Lease; + CSeqDBFileMemMap m_Lease; /// The total number of OIDs represented in the bit set. int m_NumOIDs; diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbtax.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbtax.cpp index 7e523313..ada5e6c1 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbtax.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbtax.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbtax.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: seqdbtax.cpp 530943 2017-03-20 12:53:37Z fongah2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -39,25 +39,99 @@ BEGIN_NCBI_SCOPE -CSeqDBTaxInfo::CSeqDBTaxInfo(CSeqDBAtlas & atlas) - : m_Atlas (atlas), - m_Lease (atlas), - m_AllTaxidCount(0), - m_TaxData (0), - m_Initialized (false), - m_MissingDB (false) -{ -} -void CSeqDBTaxInfo::x_Init(CSeqDBLockHold & locked) +/// CSeqDBTaxId class +/// +/// This is a memory overlay class. Do not change the size or layout +/// of this class unless corresponding changes happen to the taxonomy +/// database file format. This class's constructor and destructor are +/// not called; instead, a pointer to mapped memory is cast to a +/// pointer to this type, and the access methods are used to examine +/// the fields. + +class CSeqDBTaxId { +public: + /// Constructor + /// + /// This class is a read-only memory overlay and is not expected + /// to ever be constructed. + CSeqDBTaxId() + { + _ASSERT(0); + } + + /// Return the taxonomic identifier field (in host order) + Int4 GetTaxId()const + { + return SeqDB_GetStdOrd(& m_Taxid); + } + + /// Return the offset field (in host order) + Int4 GetOffset() const + { + return SeqDB_GetStdOrd(& m_Offset); + } + +private: + /// This structure should not be copy constructed + CSeqDBTaxId(const CSeqDBTaxId &); + + /// The taxonomic identifier + Uint4 m_Taxid; + + /// The offset of the start of the taxonomy data. + Uint4 m_Offset; +}; + + + +class CTaxDBFileInfo { - m_Atlas.Lock(locked); +public: + CTaxDBFileInfo(); + ~CTaxDBFileInfo(); + + const char* GetDataPtr() {return m_DataPtr;} + const CSeqDBTaxId* GetIndexPtr() {return m_IndexPtr;} + bool IsMissingTaxInfo() {return m_MissingDB;} + const Int4 GetTaxidCount() { return m_AllTaxidCount;} + size_t GetDataFileSize() { return m_DataFileSize;} + +private: + /// The filename of the taxonomic db index file + string m_IndexFN; + + /// The filename of the taxnomoic db data file + string m_DataFN; + + /// Total number of taxids in the database + Int4 m_AllTaxidCount; + + /// Memory map of the index file + auto_ptr m_IndexFileMap; + auto_ptr m_DataFileMap; + CSeqDBTaxId* m_IndexPtr; + char * m_DataPtr; + + size_t m_DataFileSize; + - if (m_Initialized) return; + /// Indicator if tax db files are missing + bool m_MissingDB; +}; + + + +CTaxDBFileInfo::CTaxDBFileInfo() + : m_AllTaxidCount(0), + m_IndexPtr(NULL), + m_DataPtr(NULL), + m_DataFileSize(0), + m_MissingDB(false) +{ // It is reasonable for this database to not exist. - m_IndexFN = - SeqDB_FindBlastDBPath("taxdb.bti", '-', 0, true, m_Atlas, locked); + m_IndexFN = SeqDB_ResolveDbPath("taxdb.bti"); if (m_IndexFN.size()) { m_DataFN = m_IndexFN; @@ -69,10 +143,7 @@ void CSeqDBTaxInfo::x_Init(CSeqDBLockHold & locked) CFile(m_IndexFN).Exists() && CFile(m_DataFN).Exists())) { m_MissingDB = true; - m_Atlas.Unlock(locked); - NCBI_THROW(CSeqDBException, - eFileErr, - "Error: Tax database file not found."); + return; } // Size for header data plus one taxid object. @@ -85,28 +156,25 @@ void CSeqDBTaxInfo::x_Init(CSeqDBLockHold & locked) if (idx_file_len < (data_start + sizeof(CSeqDBTaxId))) { m_MissingDB = true; - m_Atlas.Unlock(locked); - NCBI_THROW(CSeqDBException, - eFileErr, - "Error: Tax database file not found."); + return; } - CSeqDBMemLease lease(m_Atlas); + m_IndexFileMap.reset(new CMemoryFile(m_IndexFN)); + m_IndexFileMap->Map(); + // Last check-up of the database validity - m_Atlas.GetRegion(lease, m_IndexFN, 0, data_start); - Uint4 * magic_num_ptr = (Uint4 *) lease.GetPtr(0); + Uint4 * magic_num_ptr = (Uint4 *)m_IndexFileMap->GetPtr(); const unsigned TAX_DB_MAGIC_NUMBER = 0x8739; if (TAX_DB_MAGIC_NUMBER != SeqDB_GetStdOrd(magic_num_ptr ++)) { m_MissingDB = true; - m_Atlas.Unlock(locked); - NCBI_THROW(CSeqDBException, - eFileErr, - "Error: Tax database file has wrong magic number."); + m_IndexFileMap.reset(); + ERR_POST("Error: Tax database file has wrong magic number."); + return; } m_AllTaxidCount = SeqDB_GetStdOrd(magic_num_ptr ++); @@ -118,56 +186,50 @@ void CSeqDBTaxInfo::x_Init(CSeqDBLockHold & locked) if (taxid_array_size != m_AllTaxidCount) { m_MissingDB = true; - ERR_POST_X(1, "SeqDB: Taxid metadata indicates (" << m_AllTaxidCount + m_IndexFileMap.reset(); + ERR_POST("SeqDB: Taxid metadata indicates (" << m_AllTaxidCount << ") entries but file has room for (" << taxid_array_size << ")."); if (taxid_array_size < m_AllTaxidCount) { m_AllTaxidCount = taxid_array_size; } + return; } - m_TaxData = (CSeqDBTaxId*) - m_Atlas.GetRegion(m_IndexFN, data_start, idx_file_len, locked); + m_DataFileMap.reset(new CMemoryFile(m_DataFN)); + + m_DataPtr = (char *) (m_DataFileMap->GetPtr()); + m_DataFileSize = m_DataFileMap->GetSize(); + m_IndexPtr = (CSeqDBTaxId*) magic_num_ptr; - m_Atlas.RetRegion(lease); - m_Initialized = true; } -CSeqDBTaxInfo::~CSeqDBTaxInfo() +CTaxDBFileInfo::~CTaxDBFileInfo() { - if (! m_Initialized) return; - if (! m_Lease.Empty()) { - m_Atlas.RetRegion(m_Lease); - } - if (m_TaxData != 0) { - m_Atlas.RetRegion((const char*) m_TaxData); - m_TaxData = 0; + if (!m_MissingDB) { + m_IndexFileMap->Unmap(); + m_IndexFileMap.reset(); + m_DataFileMap->Unmap(); + m_DataFileMap.reset(); } } + bool CSeqDBTaxInfo::GetTaxNames(Int4 tax_id, - SSeqDBTaxInfo & info, - CSeqDBLockHold & locked) + SSeqDBTaxInfo & info ) { - if (m_MissingDB) return false; - - if (! m_Initialized) { - try { - x_Init(locked); - } catch (CSeqDBException &) { - m_MissingDB = true; - } - } - - if (m_MissingDB) return false; + static CTaxDBFileInfo t; + if (t.IsMissingTaxInfo()) return false; Int4 low_index = 0; - Int4 high_index = m_AllTaxidCount - 1; - - Int4 low_taxid = m_TaxData[low_index ].GetTaxId(); - Int4 high_taxid = m_TaxData[high_index].GetTaxId(); + Int4 high_index = t.GetTaxidCount() - 1; + const char * Data = t.GetDataPtr(); + const CSeqDBTaxId* Index = t.GetIndexPtr(); + Int4 low_taxid = Index[low_index ].GetTaxId(); + Int4 high_taxid = Index[high_index].GetTaxId(); + if((tax_id < low_taxid) || (tax_id > high_taxid)) return false; @@ -175,7 +237,7 @@ bool CSeqDBTaxInfo::GetTaxNames(Int4 tax_id, Int4 old_index = new_index; while(1) { - Int4 curr_taxid = m_TaxData[new_index].GetTaxId(); + Int4 curr_taxid = Index[new_index].GetTaxId(); if (tax_id < curr_taxid) { high_index = new_index; @@ -195,42 +257,26 @@ bool CSeqDBTaxInfo::GetTaxNames(Int4 tax_id, old_index = new_index; } - if (tax_id == m_TaxData[new_index].GetTaxId()) { + if (tax_id == Index[new_index].GetTaxId()) { info.taxid = tax_id; - m_Atlas.Lock(locked); - - Uint4 begin_data(m_TaxData[new_index].GetOffset()); + Uint4 begin_data(Index[new_index].GetOffset()); Uint4 end_data(0); if (new_index == high_index) { // Last index is special... - CSeqDBAtlas::TIndx fsize(0); - - if (! m_Atlas.GetFileSizeL(m_DataFN, fsize)) { - // Should not happen. - NCBI_THROW(CSeqDBException, - eFileErr, - "Error: Cannot get tax database file length."); - } - - end_data = Uint4(fsize); + end_data = Uint4(t.GetDataFileSize()); if (end_data < begin_data) { // Should not happen. - NCBI_THROW(CSeqDBException, - eFileErr, - "Error: Offset error at end of taxdb file."); + ERR_POST( "Error: Offset error at end of taxdb file."); + return false; } } else { - end_data = (m_TaxData[new_index+1].GetOffset()); - } - - if (! m_Lease.Contains(begin_data, end_data)) { - m_Atlas.GetRegion(m_Lease, m_DataFN, begin_data, end_data); + end_data = (Index[new_index+1].GetOffset()); } - const char * start_ptr = m_Lease.GetPtr(begin_data); + const char * start_ptr = &Data[begin_data]; CSeqDB_Substring buffer(start_ptr, start_ptr + (end_data - begin_data)); CSeqDB_Substring sci, com, blast, king; diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbvol.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbvol.cpp index 376072be..b3420898 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbvol.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbvol.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbvol.cpp 516395 2016-10-13 12:26:34Z ivanov $ +/* $Id: seqdbvol.cpp 533967 2017-04-21 15:04:16Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -54,10 +54,9 @@ TGi CSeqDBGiIndex::GetSeqGI(TOid oid, const char* data(0); if (m_NumOIDs == 0) { - TIndx length; - m_Atlas.Lock(locked); - m_Atlas.GetFile(m_Lease, m_Fname, length, locked); - data = m_Lease.GetPtr(0); + + data = m_Lease.GetFileDataPtr(0); + // TODO we may want to check the version number and file type m_Size = (Int4) SeqDB_GetStdOrd((Int4 *) (data+8)); m_NumOIDs = (Int4) SeqDB_GetStdOrd((Int4 *) (data+12)); @@ -65,8 +64,8 @@ TGi CSeqDBGiIndex::GetSeqGI(TOid oid, if (oid >= m_NumOIDs || oid < 0) return INVALID_GI; - TIndx offset = oid * m_Size + 32; - data = m_Lease.GetPtr(offset); + TIndx offset = oid * m_Size + 32; + data = m_Lease.GetFileDataPtr(offset); return GI_FROM(Int4, SeqDB_GetStdOrd((Int4 *) data)); } @@ -102,7 +101,7 @@ CSeqDBVol::CSeqDBVol(CSeqDBAtlas & atlas, m_NegativeList.Reset(neg_list); } - m_Idx.Reset(new CSeqDBIdxFile(atlas, name, prot_nucl, locked)); + m_Idx.Reset(new CSeqDBIdxFile(atlas, name, prot_nucl)); m_VolEnd = m_VolStart + m_Idx->GetNumOIDs(); @@ -112,30 +111,30 @@ CSeqDBVol::CSeqDBVol(CSeqDBAtlas & atlas, void CSeqDBVol::OpenSeqFile(CSeqDBLockHold & locked) const{ - if (!m_SeqFileOpened) x_OpenSeqFile(locked); + if (!m_SeqFileOpened) x_OpenSeqFile(); } void -CSeqDBVol::x_OpenSeqFile(CSeqDBLockHold & locked) const { - m_Atlas.Lock(locked); +CSeqDBVol::x_OpenSeqFile(void) const { + //m_Atlas.Lock(locked); if (!m_SeqFileOpened && m_Idx->GetNumOIDs() != 0) { - m_Seq.Reset(new CSeqDBSeqFile(m_Atlas, m_VolName, (m_IsAA?'p':'n'), locked)); + m_Seq.Reset(new CSeqDBSeqFile(m_Atlas, m_VolName, (m_IsAA?'p':'n'))); } m_SeqFileOpened = true; } void -CSeqDBVol::x_OpenHdrFile(CSeqDBLockHold & locked) const { - m_Atlas.Lock(locked); +CSeqDBVol::x_OpenHdrFile(void) const { + //m_Atlas.Lock(locked); if (!m_HdrFileOpened && m_Idx->GetNumOIDs() != 0) { - m_Hdr.Reset(new CSeqDBHdrFile(m_Atlas, m_VolName, (m_IsAA?'p':'n'), locked)); + m_Hdr.Reset(new CSeqDBHdrFile(m_Atlas, m_VolName, (m_IsAA?'p':'n'))); } m_HdrFileOpened = true; } void -CSeqDBVol::x_OpenPigFile(CSeqDBLockHold & locked) const{ - m_Atlas.Lock(locked); +CSeqDBVol::x_OpenPigFile(void) const{ + //m_Atlas.Lock(locked); if (!m_PigFileOpened && CSeqDBIsam::IndexExists(m_VolName, (m_IsAA?'p':'n'), 'p') && m_Idx->GetNumOIDs() != 0) { @@ -150,8 +149,8 @@ CSeqDBVol::x_OpenPigFile(CSeqDBLockHold & locked) const{ } void -CSeqDBVol::x_OpenGiFile(CSeqDBLockHold & locked) const{ - m_Atlas.Lock(locked); +CSeqDBVol::x_OpenGiFile(void) const{ + //m_Atlas.Lock(locked); if (!m_GiFileOpened && CSeqDBIsam::IndexExists(m_VolName, (m_IsAA?'p':'n'), 'n') && m_Idx->GetNumOIDs() != 0) { @@ -166,8 +165,8 @@ CSeqDBVol::x_OpenGiFile(CSeqDBLockHold & locked) const{ } void -CSeqDBVol::x_OpenStrFile(CSeqDBLockHold & locked) const{ - m_Atlas.Lock(locked); +CSeqDBVol::x_OpenStrFile(void) const{ + //m_Atlas.Lock(locked); if (!m_StrFileOpened && CSeqDBIsam::IndexExists(m_VolName, (m_IsAA?'p':'n'), 's') && m_Idx->GetNumOIDs() != 0) { @@ -182,8 +181,8 @@ CSeqDBVol::x_OpenStrFile(CSeqDBLockHold & locked) const{ } void -CSeqDBVol::x_OpenTiFile(CSeqDBLockHold & locked) const{ - m_Atlas.Lock(locked); +CSeqDBVol::x_OpenTiFile(void) const{ + //m_Atlas.Lock(locked); if (!m_TiFileOpened && CSeqDBIsam::IndexExists(m_VolName, (m_IsAA?'p':'n'), 't') && m_Idx->GetNumOIDs() != 0) { @@ -198,8 +197,8 @@ CSeqDBVol::x_OpenTiFile(CSeqDBLockHold & locked) const{ } void -CSeqDBVol::x_OpenHashFile(CSeqDBLockHold & locked) const{ - m_Atlas.Lock(locked); +CSeqDBVol::x_OpenHashFile(void) const{ + //m_Atlas.Lock(locked); if (!m_HashFileOpened && CSeqDBIsam::IndexExists(m_VolName, (m_IsAA?'p':'n'), 'h') && m_Idx->GetNumOIDs() != 0) { @@ -214,8 +213,8 @@ CSeqDBVol::x_OpenHashFile(CSeqDBLockHold & locked) const{ } void -CSeqDBVol::x_OpenOidFile(CSeqDBLockHold & locked) const{ - m_Atlas.Lock(locked); +CSeqDBVol::x_OpenOidFile(void) const{ + //m_Atlas.Lock(locked); if (!m_OidFileOpened && CSeqDBGiIndex::IndexExists(m_VolName, (m_IsAA?'p':'n')) && m_Idx->GetNumOIDs() != 0) { @@ -242,7 +241,7 @@ int CSeqDBVol::GetSeqLengthProt(int oid, CSeqDBLockHold & locked) const TIndx start_offset = 0; TIndx end_offset = 0; - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); m_Idx->GetSeqStartEnd(oid, start_offset, end_offset); _ASSERT('p' == m_Idx->GetSeqType()); @@ -258,8 +257,8 @@ int CSeqDBVol::GetSeqLengthExact(int oid, CSeqDBLockHold & locked) const TIndx start_offset = 0; TIndx end_offset = 0; - m_Atlas.Lock(locked); - if (!m_SeqFileOpened) x_OpenSeqFile(locked); + //m_Atlas.Lock(locked); + if (!m_SeqFileOpened) x_OpenSeqFile(); m_Idx->GetSeqStartEnd(oid, start_offset, end_offset); _ASSERT(m_Idx->GetSeqType() == 'n'); @@ -270,8 +269,7 @@ int CSeqDBVol::GetSeqLengthExact(int oid, CSeqDBLockHold & locked) const // the last byte store the number of nucleotides in the // last byte (0 to 3). - char amb_char = 0; - + char amb_char = 0; m_Seq->ReadBytes(& amb_char, end_offset - 1, end_offset); int remainder = amb_char & 3; @@ -283,7 +281,7 @@ int CSeqDBVol::GetSeqLengthApprox(int oid, CSeqDBLockHold & locked) const TIndx start_offset = 0; TIndx end_offset = 0; - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); m_Idx->GetSeqStartEnd(oid, start_offset, end_offset); _ASSERT(m_Idx->GetSeqType() == 'n'); @@ -997,8 +995,8 @@ s_SeqDB_SeqIdIn(const list< CRef< CSeq_id > > & seqids, const CSeq_id & target) CRef CSeqDBVol::x_GetTaxDefline(int oid, TGi preferred_gi, - const CSeq_id * preferred_seqid, - CSeqDBLockHold & locked) + const CSeq_id * preferred_seqid) + { // Commented out, not used at this time. // typedef list< CRef > TBDLL; @@ -1008,7 +1006,7 @@ CSeqDBVol::x_GetTaxDefline(int oid, // 1. read a defline set w/ gethdr, filtering by membership bit. CRef BDLS = - x_GetFilteredHeader(oid, NULL, locked); + x_GetFilteredHeader(oid, NULL); // 2. if there is a preferred gi, bump it to the top. @@ -1042,9 +1040,9 @@ CSeqDBVol::x_GetTaxDefline(int oid, list< CRef > CSeqDBVol::x_GetTaxonomy(int oid, TGi preferred_gi, - const CSeq_id * preferred_seqid, - CRef tax_info, - CSeqDBLockHold & locked) + const CSeq_id * preferred_seqid) + + { const bool provide_new_taxonomy_info = true; const bool use_taxinfo_cache = true; @@ -1054,7 +1052,7 @@ CSeqDBVol::x_GetTaxonomy(int oid, list< CRef > taxonomy; CRef bdls = - x_GetTaxDefline(oid, preferred_gi, preferred_seqid, locked); + x_GetTaxDefline(oid, preferred_gi, preferred_seqid); if (bdls.Empty()) { return taxonomy; @@ -1068,7 +1066,7 @@ CSeqDBVol::x_GetTaxonomy(int oid, // Lock for sake of tax cache - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); for(TBDLLConstIter iter = dl.begin(); iter != dl.end(); iter ++) { int taxid = 0; @@ -1087,16 +1085,11 @@ CSeqDBVol::x_GetTaxonomy(int oid, } SSeqDBTaxInfo tnames(taxid); - - if (tax_info.Empty()) { - continue; - } - bool found_taxid_in_taxonomy_blastdb = true; if ((! have_org_desc) && provide_new_taxonomy_info) { try { - found_taxid_in_taxonomy_blastdb = tax_info->GetTaxNames(taxid, tnames, locked); + found_taxid_in_taxonomy_blastdb = CSeqDBTaxInfo::GetTaxNames(taxid, tnames); } catch (CSeqDBException &) { found_taxid_in_taxonomy_blastdb = false; } @@ -1215,13 +1208,12 @@ CSeqDB::ExtractBlastDefline(const CBioseq & bioseq) { return s_ExtractBlastDefline(bioseq); } CRef -CSeqDBVol::x_GetAsnDefline(int oid, - CSeqDBLockHold & locked) const +CSeqDBVol::x_GetAsnDefline(int oid) const { CRef asndef; vector hdr_data; - x_GetFilteredBinaryHeader(oid, hdr_data, locked); + x_GetFilteredBinaryHeader(oid, hdr_data); if (! hdr_data.empty()) { CRef uobj(new CUser_object); @@ -1255,7 +1247,6 @@ CRef CSeqDBVol::GetBioseq(int oid, TGi target_gi, const CSeq_id * target_seq_id, - CRef tax_info, bool seqdata, CSeqDBLockHold & locked) { @@ -1265,13 +1256,13 @@ CSeqDBVol::GetBioseq(int oid, CRef defline; list< CRef< CSeq_id > > seqids; - if (!m_SeqFileOpened) x_OpenSeqFile(locked); + if (!m_SeqFileOpened) x_OpenSeqFile(); // Get the defline set; but do not modify the object returned by // GetFilteredHeader, since that object lives in the cache. CRef orig_deflines = - x_GetFilteredHeader(oid, NULL, locked); + x_GetFilteredHeader(oid, NULL); CRef defline_set; @@ -1329,7 +1320,7 @@ CSeqDBVol::GetBioseq(int oid, if (seqdata) { const char * seq_buffer = 0; - int length = x_GetSequence(oid, & seq_buffer, false, locked, false); + int length = x_GetSequence(oid, & seq_buffer, false, false); if (length < 1) { return null_result; @@ -1353,7 +1344,7 @@ CSeqDBVol::GetBioseq(int oid, // nucl vector ambchars; - x_GetAmbChar(oid, ambchars, locked); + x_GetAmbChar(oid, ambchars); if (ambchars.empty()) { // keep as 2 bit @@ -1402,7 +1393,7 @@ CSeqDBVol::GetBioseq(int oid, CRef desc1(new CSeqdesc); desc1->SetTitle().swap(description); - CRef desc2( x_GetAsnDefline(oid, locked) ); + CRef desc2( x_GetAsnDefline(oid) ); CSeq_descr & seq_desc_set = bioseq->SetDescr(); seq_desc_set.Set().push_back(desc1); @@ -1413,7 +1404,7 @@ CSeqDBVol::GetBioseq(int oid, } list< CRef > tax = - x_GetTaxonomy(oid, target_gi, target_seq_id, tax_info, locked); + x_GetTaxonomy(oid, target_gi, target_seq_id); ITERATE(list< CRef >, iter, tax) { bioseq->SetDescr().Set().push_back(*iter); @@ -1508,8 +1499,7 @@ int CSeqDBVol::x_GetAmbigSeq(int oid, const char * tmp(0); int base_length = x_GetSequence(oid, &tmp, - false, - locked, + false, false); if (region && region->end > base_length ) @@ -1538,7 +1528,7 @@ int CSeqDBVol::x_GetAmbigSeq(int oid, // Get ambiguity characters. vector ambchars; - x_GetAmbChar(oid, ambchars, locked); + x_GetAmbChar(oid, ambchars); // Determine if we want to filter by offset ranges. This // is only done if: @@ -1664,8 +1654,7 @@ void SeqDB_UnpackAmbiguities(const CTempString & sequence, int CSeqDBVol::x_GetSequence(int oid, const char ** buffer, - bool keep, - CSeqDBLockHold & locked, + bool keep, bool can_release, bool in_lease) const { @@ -1674,8 +1663,8 @@ int CSeqDBVol::x_GetSequence(int oid, int length = -1; - m_Atlas.Lock(locked); - if (!m_SeqFileOpened) x_OpenSeqFile(locked); + //m_Atlas.Lock(locked); + if (!m_SeqFileOpened) x_OpenSeqFile(); if (oid >= m_Idx->GetNumOIDs()) return -1; @@ -1693,14 +1682,8 @@ int CSeqDBVol::x_GetSequence(int oid, // Although we subtracted one above to get the correct length, // we expand the range here by one byte in both directions. // The normal consumer of this data relies on them, and can - // walk off memory if a sequence ends on a slice boundary. - - *buffer = m_Seq->GetRegion(start_offset-1, - end_offset+1, - keep, - false, - locked, - in_lease) + 1; + // walk off memory if a sequence ends on a slice boundary. + *buffer = m_Seq->GetFileDataPtr(start_offset-1) + 1; if (! (*buffer - 1)) return -1; } else if ('n' == seqtype) { @@ -1714,14 +1697,8 @@ int CSeqDBVol::x_GetSequence(int oid, // this. If keep is true, we don't need hold because keep // will already have preserved the region. - bool hold = ! (keep || can_release); - - *buffer = m_Seq->GetRegion(start_offset, - end_offset, - keep, - hold, - locked, - in_lease); + + *buffer = m_Seq->GetFileDataPtr(start_offset); if (! (*buffer)) return -1; @@ -1748,13 +1725,12 @@ int CSeqDBVol::x_GetSequence(int oid, return length; } -list< CRef > CSeqDBVol::GetSeqIDs(int oid, - CSeqDBLockHold & locked) const +list< CRef > CSeqDBVol::GetSeqIDs(int oid) const { list< CRef< CSeq_id > > seqids; CRef defline_set = - x_GetFilteredHeader(oid, NULL, locked); + x_GetFilteredHeader(oid, NULL); if ((! defline_set.Empty()) && defline_set->CanGet()) { ITERATE(list< CRef >, defline, defline_set->Get()) { @@ -1774,7 +1750,7 @@ list< CRef > CSeqDBVol::GetSeqIDs(int oid, TGi CSeqDBVol::GetSeqGI(int oid, CSeqDBLockHold & locked) const { - if (!m_OidFileOpened) x_OpenOidFile(locked); + if (!m_OidFileOpened) x_OpenOidFile(); if (!m_GiIndex.Empty()) { return m_GiIndex->GetSeqGI(oid, locked); } @@ -1790,18 +1766,17 @@ CRef CSeqDBVol::GetFilteredHeader(int oid, CSeqDBLockHold & locked) const { - return x_GetFilteredHeader(oid, NULL, locked); + return x_GetFilteredHeader(oid, NULL); } CRef CSeqDBVol::x_GetFilteredHeader(int oid, - bool * changed, - CSeqDBLockHold & locked) const + bool * changed) const { typedef list< CRef > TBDLL; typedef TBDLL::iterator TBDLLIter; - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); TDeflineCacheItem & cached = m_DeflineCache.Lookup(oid); @@ -1816,7 +1791,7 @@ CSeqDBVol::x_GetFilteredHeader(int oid, bool asn_changed = false; CRef BDLS = - x_GetHdrAsn1(oid, true, & asn_changed, locked); + x_GetHdrAsn1(oid, true, & asn_changed); bool id_filter = x_HaveIdFilter(); @@ -1889,12 +1864,11 @@ CSeqDBVol::x_GetFilteredHeader(int oid, CRef CSeqDBVol::x_GetHdrAsn1(int oid, bool adjust_oids, - bool * changed, - CSeqDBLockHold & locked) const + bool * changed) const { CRef bdls; - CTempString raw_data = x_GetHdrAsn1Binary(oid, locked); + CTempString raw_data = x_GetHdrAsn1Binary(oid); if (! raw_data.size()) { return bdls; @@ -1936,26 +1910,24 @@ CSeqDBVol::x_GetHdrAsn1(int oid, } CTempString -CSeqDBVol::x_GetHdrAsn1Binary(int oid, CSeqDBLockHold & locked) const +CSeqDBVol::x_GetHdrAsn1Binary(int oid) const { TIndx hdr_start = 0; TIndx hdr_end = 0; - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); - if (!m_HdrFileOpened) x_OpenHdrFile(locked); + if (!m_HdrFileOpened) x_OpenHdrFile(); - m_Idx->GetHdrStartEnd(oid, hdr_start, hdr_end); - - const char * asn_region = m_Hdr->GetRegion(hdr_start, hdr_end, locked); + m_Idx->GetHdrStartEnd(oid, hdr_start, hdr_end); + const char * asn_region = m_Hdr->GetFileDataPtr(hdr_start); return CTempString(asn_region, hdr_end - hdr_start); } void CSeqDBVol::x_GetFilteredBinaryHeader(int oid, - vector & hdr_data, - CSeqDBLockHold & locked) const + vector & hdr_data ) const { // This method's client is GetBioseq() and related methods. That // code needs filtered ASN.1 headers; eliminating the fetching of @@ -1968,7 +1940,7 @@ CSeqDBVol::x_GetFilteredBinaryHeader(int oid, bool changed = false; CRef dls = - x_GetFilteredHeader(oid, & changed, locked); + x_GetFilteredHeader(oid, & changed); if (changed) { CNcbiOstrstream asndata; @@ -1980,19 +1952,18 @@ CSeqDBVol::x_GetFilteredBinaryHeader(int oid, string s = CNcbiOstrstreamToString(asndata); hdr_data.assign(s.data(), s.data() + s.size()); } else { - CTempString raw = x_GetHdrAsn1Binary(oid, locked); + CTempString raw = x_GetHdrAsn1Binary(oid); hdr_data.assign(raw.data(), raw.data() + raw.size()); } } void CSeqDBVol::x_GetAmbChar(int oid, - vector & ambchars, - CSeqDBLockHold & locked) const + vector & ambchars) const { TIndx start_offset = 0; TIndx end_offset = 0; - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); bool ok = m_Idx->GetAmbStartEnd(oid, start_offset, end_offset); @@ -2007,14 +1978,9 @@ void CSeqDBVol::x_GetAmbChar(int oid, int total = length / 4; // 'hold' should be false here because we only need the data - // for the duration of this function. - + // for the duration of this function. Int4 * buffer = - (Int4*) m_Seq->GetRegion(start_offset, - start_offset + (total * 4), - false, - false, - locked); + (Int4*) m_Seq->GetFileDataPtr(start_offset); // This is probably unnecessary total &= 0x7FFFFFFF; @@ -2056,19 +2022,19 @@ int CSeqDBVol::GetMinLength() const bool CSeqDBVol::PigToOid(int pig, int & oid, CSeqDBLockHold & locked) const { - if (!m_PigFileOpened) x_OpenPigFile(locked); + if (!m_PigFileOpened) x_OpenPigFile(); if (m_IsamPig.Empty()) { return false; } - return m_IsamPig->PigToOid(pig, oid, locked); + return m_IsamPig->PigToOid(pig, oid); } bool CSeqDBVol::GetPig(int oid, int & pig, CSeqDBLockHold & locked) const { pig = -1; - CRef BDLS = x_GetHdrAsn1(oid, false, NULL, locked); + CRef BDLS = x_GetHdrAsn1(oid, false, NULL); if (BDLS.Empty() || (! BDLS->IsSet())) { return false; @@ -2104,7 +2070,7 @@ bool CSeqDBVol::TiToOid(Int8 ti, // this point (in the call stack) uses int; code above this level, // up to the user level, uses Int8. - if (!m_TiFileOpened) x_OpenTiFile(locked); + if (!m_TiFileOpened) x_OpenTiFile(); if (m_IsamTi.Empty()) { // If the "nti/ntd" files become ubiquitous, this could be // removed. For now, I will look up trace IDs in the string @@ -2123,26 +2089,26 @@ bool CSeqDBVol::TiToOid(Int8 ti, return ! oids.empty(); } - return m_IsamTi->IdToOid(ti, oid, locked); + return m_IsamTi->IdToOid(ti, oid); } bool CSeqDBVol::GiToOid(TGi gi, int & oid, CSeqDBLockHold & locked) const { - if (!m_GiFileOpened) x_OpenGiFile(locked); + if (!m_GiFileOpened) x_OpenGiFile(); if (m_IsamGi.Empty()) { return false; } - return m_IsamGi->IdToOid(GI_TO(Int8, gi), oid, locked); + return m_IsamGi->IdToOid(GI_TO(Int8, gi), oid); } void CSeqDBVol::IdsToOids(CSeqDBGiList & ids, CSeqDBLockHold & locked) const { if (ids.GetNumGis()) { - if (!m_GiFileOpened) x_OpenGiFile(locked); + if (!m_GiFileOpened) x_OpenGiFile(); if (m_IsamGi.NotEmpty()) { - m_IsamGi->IdsToOids(m_VolStart, m_VolEnd, ids, locked); + m_IsamGi->IdsToOids(m_VolStart, m_VolEnd, ids); } else { NCBI_THROW(CSeqDBException, eArgErr, @@ -2151,9 +2117,9 @@ void CSeqDBVol::IdsToOids(CSeqDBGiList & ids, } if (ids.GetNumTis()) { - if (!m_TiFileOpened) x_OpenTiFile(locked); + if (!m_TiFileOpened) x_OpenTiFile(); if (m_IsamTi.NotEmpty()) { - m_IsamTi->IdsToOids(m_VolStart, m_VolEnd, ids, locked); + m_IsamTi->IdsToOids(m_VolStart, m_VolEnd, ids); } else { NCBI_THROW(CSeqDBException, eArgErr, @@ -2162,15 +2128,16 @@ void CSeqDBVol::IdsToOids(CSeqDBGiList & ids, } if (ids.GetNumSis()) { - if (!m_StrFileOpened) x_OpenStrFile(locked); + if (!m_StrFileOpened) x_OpenStrFile(); if (m_IsamStr.NotEmpty()) { - m_IsamStr->IdsToOids(m_VolStart, m_VolEnd, ids, locked); + m_IsamStr->IdsToOids(m_VolStart, m_VolEnd, ids); } else { NCBI_THROW(CSeqDBException, eArgErr, "SI list specified but no ISAM file found for SI in " + m_VolName); } } + x_UnLeaseIsam(); } void CSeqDBVol::IdsToOids(CSeqDBNegativeList & ids, @@ -2179,9 +2146,9 @@ void CSeqDBVol::IdsToOids(CSeqDBNegativeList & ids, // Numeric translation is done in batch mode. if (ids.GetNumGis()) { - if (!m_GiFileOpened) x_OpenGiFile(locked); + if (!m_GiFileOpened) x_OpenGiFile(); if (m_IsamGi.NotEmpty()) { - m_IsamGi->IdsToOids(m_VolStart, m_VolEnd, ids, locked); + m_IsamGi->IdsToOids(m_VolStart, m_VolEnd, ids); } else { NCBI_THROW(CSeqDBException, eArgErr, @@ -2190,15 +2157,27 @@ void CSeqDBVol::IdsToOids(CSeqDBNegativeList & ids, } if (ids.GetNumTis()) { - if (!m_TiFileOpened) x_OpenTiFile(locked); + if (!m_TiFileOpened) x_OpenTiFile(); if (m_IsamTi.NotEmpty()) { - m_IsamTi->IdsToOids(m_VolStart, m_VolEnd, ids, locked); + m_IsamTi->IdsToOids(m_VolStart, m_VolEnd, ids); } else { NCBI_THROW(CSeqDBException, eArgErr, "TI list specified but no ISAM file found for TI in " + m_VolName); } } + + if (ids.GetNumSis()) { + if (!m_StrFileOpened) x_OpenStrFile(); + if (m_IsamStr.NotEmpty()) { + m_IsamStr->IdsToOids(m_VolStart, m_VolEnd, ids); + } else { + NCBI_THROW(CSeqDBException, + eArgErr, + "SI list specified but no ISAM file found for SI in " + m_VolName); + } + } + x_UnLeaseIsam(); } bool CSeqDBVol::GetGi(int oid, @@ -2207,13 +2186,13 @@ bool CSeqDBVol::GetGi(int oid, { gi = INVALID_GI; - if (!m_GiFileOpened) x_OpenGiFile(locked); + if (!m_GiFileOpened) x_OpenGiFile(); if (m_IsamGi.Empty()) { return false; } CRef BDLS = - x_GetFilteredHeader(oid, NULL, locked); + x_GetFilteredHeader(oid, NULL); if (BDLS.Empty() || (! BDLS->IsSet())) { return false; @@ -2250,8 +2229,7 @@ void CSeqDBVol::x_StringToOids(const string & acc, Int8 ident, const string & str_id, bool simpler, - vector & oids, - CSeqDBLockHold & locked) const + vector & oids) const { bool vcheck (false); bool fits_in_four = (ident == -1) || ! (ident >> 32); @@ -2259,21 +2237,21 @@ void CSeqDBVol::x_StringToOids(const string & acc, switch(id_type) { case eStringId: - if (!m_StrFileOpened) x_OpenStrFile(locked); + if (!m_StrFileOpened) x_OpenStrFile(); if (! m_IsamStr.Empty()) { // Not simplified vcheck = true; - m_IsamStr->StringToOids(str_id, oids, simpler, vcheck, locked); + m_IsamStr->StringToOids(str_id, oids, simpler, vcheck); } break; case ePigId: // Converted to PIG type. - if (!m_PigFileOpened) x_OpenPigFile(locked); + if (!m_PigFileOpened) x_OpenPigFile(); if (! m_IsamPig.Empty()) { int oid(-1); - if (m_IsamPig->PigToOid((int) ident, oid, locked)) { + if (m_IsamPig->PigToOid((int) ident, oid)) { oids.push_back(oid); } } @@ -2281,11 +2259,11 @@ void CSeqDBVol::x_StringToOids(const string & acc, case eGiId: // Converted to GI type. - if (!m_GiFileOpened) x_OpenGiFile(locked); + if (!m_GiFileOpened) x_OpenGiFile(); if (! m_IsamGi.Empty()) { int oid(-1); - if (m_IsamGi->IdToOid(ident, oid, locked)) { + if (m_IsamGi->IdToOid(ident, oid)) { oids.push_back(oid); } } @@ -2293,12 +2271,12 @@ void CSeqDBVol::x_StringToOids(const string & acc, case eTiId: // Converted to TI type. - if (!m_TiFileOpened) x_OpenTiFile(locked); - if (!m_StrFileOpened) x_OpenStrFile(locked); + if (!m_TiFileOpened) x_OpenTiFile(); + if (!m_StrFileOpened) x_OpenStrFile(); if (! m_IsamTi.Empty()) { int oid(-1); - if (m_IsamTi->IdToOid(ident, oid, locked)) { + if (m_IsamTi->IdToOid(ident, oid)) { oids.push_back(oid); } } else if (m_IsamStr) { @@ -2309,7 +2287,7 @@ void CSeqDBVol::x_StringToOids(const string & acc, // 2. Specify "adjusted" as true, because lookup of // "gb|.." and similar tricks are not needed for TIs. - m_IsamStr->StringToOids(acc, oids, true, vcheck, locked); + m_IsamStr->StringToOids(acc, oids, true, vcheck); } break; @@ -2332,13 +2310,13 @@ void CSeqDBVol::x_StringToOids(const string & acc, } if (vcheck) { - x_CheckVersions(acc, oids, locked); + x_CheckVersions(acc, oids); } + x_UnLeaseIsam(); } void CSeqDBVol::x_CheckVersions(const string & acc, - vector & oids, - CSeqDBLockHold & locked) const + vector & oids) const { // If we resolved a string id by stripping the version off of the // string, we need to check (for each OID) if the real ID had a @@ -2367,7 +2345,7 @@ void CSeqDBVol::x_CheckVersions(const string & acc, NON_CONST_ITERATE(vector, iter, oids) { list< CRef > ids = - GetSeqIDs(*iter, locked); + GetSeqIDs(*iter); bool found = false; @@ -2403,7 +2381,7 @@ void CSeqDBVol::AccessionToOids(const string & acc, ESeqDBIdType id_type = SeqDB_SimplifyAccession(acc, ident, str_id, simpler); - x_StringToOids(acc, id_type, ident, str_id, simpler, oids, locked); + x_StringToOids(acc, id_type, ident, str_id, simpler, oids); } @@ -2417,8 +2395,30 @@ void CSeqDBVol::SeqidToOids(CSeq_id & seqid, ESeqDBIdType id_type = SeqDB_SimplifySeqid(seqid, 0, ident, str_id, simpler); - x_StringToOids(seqid.AsFastaString(), id_type, ident, str_id, simpler, oids, locked); + x_StringToOids(seqid.AsFastaString(), id_type, ident, str_id, simpler, oids); + +} +void CSeqDBVol::x_UnLeaseIsam(void) const +{ + if(m_Atlas.GetOpenedFilseCount() > CSeqDBAtlas::e_MaxFileDescritors) { + if (m_IsamPig.NotEmpty()) { + m_PigFileOpened = false; + m_IsamPig->UnLease(); + } + if (m_IsamGi.NotEmpty()) { + m_GiFileOpened = false; + m_IsamGi->UnLease(); + } + if (m_IsamStr.NotEmpty()) { + m_StrFileOpened = false; + m_IsamStr->UnLease(); + } + if (m_IsamTi.NotEmpty()) { + m_TiFileOpened = false; + m_IsamTi->UnLease(); + } + } } void CSeqDBVol::UnLease() @@ -2473,7 +2473,7 @@ int CSeqDBVol::GetOidAtOffset(int first_seq, // Input range is from 0 .. total_length // Require range from 0 .. byte_length - Uint8 end_of_bytes = x_GetSeqResidueOffset(vol_cnt, locked); + Uint8 end_of_bytes = x_GetSeqResidueOffset(vol_cnt); double dresidue = (double(residue) * end_of_bytes) / vol_len; @@ -2499,7 +2499,7 @@ int CSeqDBVol::GetOidAtOffset(int first_seq, int oid_mid = (oid_beg + oid_end)/2; while(oid_beg < oid_end) { - Uint8 offset = x_GetSeqResidueOffset(oid_mid, locked); + Uint8 offset = x_GetSeqResidueOffset(oid_mid); if ('p' == m_Idx->GetSeqType()) { offset -= oid_mid; @@ -2517,9 +2517,9 @@ int CSeqDBVol::GetOidAtOffset(int first_seq, return oid_mid; } -Uint8 CSeqDBVol::x_GetSeqResidueOffset(int oid, CSeqDBLockHold & locked) const +Uint8 CSeqDBVol::x_GetSeqResidueOffset(int oid) const { - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); TIndx start_offset = 0; m_Idx->GetSeqStart(oid, start_offset); @@ -2534,9 +2534,9 @@ CSeqDBVol::GetSeqData(int oid, { // This design was part of the BlastDbDataLoader code. - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); - if (!m_SeqFileOpened) x_OpenSeqFile(locked); + if (!m_SeqFileOpened) x_OpenSeqFile(); CRef seq_data(new CSeq_data); @@ -2544,7 +2544,7 @@ CSeqDBVol::GetSeqData(int oid, const char * buffer(0); TSeqPos length(0); - length = x_GetSequence(oid, & buffer, false, locked, false); + length = x_GetSequence(oid, & buffer, false, false); if ((begin >= end) || (end > length)) { NCBI_THROW(CSeqDBException, @@ -2622,8 +2622,8 @@ CSeqDBVol::GetRawSeqAndAmbig(int oid, TIndx map_begin = 0; TIndx map_end = 0; - m_Atlas.Lock(locked); - if (!m_SeqFileOpened) x_OpenSeqFile(locked); + //m_Atlas.Lock(locked); + if (!m_SeqFileOpened) x_OpenSeqFile(); m_Idx->GetSeqStartEnd(oid, start_S, end_S); bool amb_ok = true; @@ -2661,8 +2661,8 @@ CSeqDBVol::GetRawSeqAndAmbig(int oid, *seq_length = s_len; } - if (buffer) { - *buffer = m_Seq->GetRegion(map_begin, map_end, true, false, locked); + if (buffer) { + *buffer = m_Seq->GetFileDataPtr(map_begin); *buffer += (start_S - map_begin); } @@ -2695,8 +2695,8 @@ void CSeqDBVol::GetGiBounds(TGi & low_id, int & count, CSeqDBLockHold & locked) const { - m_Atlas.Lock(locked); - if (!m_GiFileOpened) x_OpenGiFile(locked); + //m_Atlas.Lock(locked); + if (!m_GiFileOpened) x_OpenGiFile(); low_id = ZERO_GI; high_id = ZERO_GI; count = 0; @@ -2704,7 +2704,7 @@ void CSeqDBVol::GetGiBounds(TGi & low_id, if (m_IsamGi.NotEmpty()) { Int8 L(0), H(0); - m_IsamGi->GetIdBounds(L, H, count, locked); + m_IsamGi->GetIdBounds(L, H, count); low_id = GI_FROM(Int8, L); high_id = GI_FROM(Int8, H); @@ -2719,14 +2719,14 @@ void CSeqDBVol::GetPigBounds(int & low_id, int & count, CSeqDBLockHold & locked) const { - m_Atlas.Lock(locked); - if (!m_PigFileOpened) x_OpenPigFile(locked); + //m_Atlas.Lock(locked); + if (!m_PigFileOpened) x_OpenPigFile(); low_id = high_id = count = 0; if (m_IsamPig.NotEmpty()) { Int8 L(0), H(0); - m_IsamPig->GetIdBounds(L, H, count, locked); + m_IsamPig->GetIdBounds(L, H, count); low_id = (int) L; high_id = (int) H; @@ -2741,14 +2741,14 @@ void CSeqDBVol::GetStringBounds(string & low_id, int & count, CSeqDBLockHold & locked) const { - m_Atlas.Lock(locked); - if (!m_StrFileOpened) x_OpenStrFile(locked); + //m_Atlas.Lock(locked); + if (!m_StrFileOpened) x_OpenStrFile(); count = 0; low_id.erase(); high_id.erase(); if (m_IsamStr.NotEmpty()) { - m_IsamStr->GetIdBounds(low_id, high_id, count, locked); + m_IsamStr->GetIdBounds(low_id, high_id, count); } } @@ -2758,7 +2758,7 @@ void CSeqDBVol::SetOffsetRanges(int oid, bool cache_data, CSeqDBLockHold & locked) const { - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); if (offset_ranges.empty() && (! cache_data) && (! append_ranges)) { // Specifying no-cache plus an empty offset range list, means @@ -2807,7 +2807,7 @@ void CSeqDBVol::SetOffsetRanges(int oid, void CSeqDBVol::FlushOffsetRangeCache(CSeqDBLockHold& locked) { - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); m_RangeCache.clear(); } @@ -2868,14 +2868,14 @@ void CSeqDBVol::HashToOids(unsigned hash, // feature generally does not know if the sequence will be found), // the lack of hash indexing is reported by throwing an exception. - if (!m_HashFileOpened) x_OpenHashFile(locked); + if (!m_HashFileOpened) x_OpenHashFile(); if (m_IsamHash.Empty()) { NCBI_THROW(CSeqDBException, eArgErr, "Hash lookup requested but no hash ISAM file found."); } - m_IsamHash->HashToOids(hash, oids, locked); + m_IsamHash->HashToOids(hash, oids); } #if ((!defined(NCBI_COMPILER_WORKSHOP) || (NCBI_COMPILER_VERSION > 550)) && \ @@ -2886,7 +2886,7 @@ void CSeqDBVol::GetColumnBlob(int col_id, bool keep, CSeqDBLockHold & locked) { - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); if (! m_HaveColumns) { x_OpenAllColumns(locked); @@ -2903,7 +2903,7 @@ const map & CSeqDBVol::GetColumnMetaData(int col_id, CSeqDBLockHold & locked) { - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); if (! m_HaveColumns) { x_OpenAllColumns(locked); @@ -2919,7 +2919,7 @@ CSeqDBVol::GetColumnMetaData(int col_id, void CSeqDBVol::ListColumns(set & titles, CSeqDBLockHold & locked) { - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); if (! m_HaveColumns) { x_OpenAllColumns(locked); @@ -2932,7 +2932,7 @@ void CSeqDBVol::ListColumns(set & titles, void CSeqDBVol::x_OpenAllColumns(CSeqDBLockHold & locked) { - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); if (m_HaveColumns) { return; @@ -3002,7 +3002,7 @@ void CSeqDBVol::x_OpenAllColumns(CSeqDBLockHold & locked) int CSeqDBVol::GetColumnId(const string & title, CSeqDBLockHold & locked) { - m_Atlas.Lock(locked); + //m_Atlas.Lock(locked); if (! m_HaveColumns) { x_OpenAllColumns(locked); diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbvolset.cpp b/c++/src/objtools/blast/seqdb_reader/seqdbvolset.cpp index 359b85e7..1ae3ddc8 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbvolset.cpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbvolset.cpp @@ -1,4 +1,4 @@ -/* $Id: seqdbvolset.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: seqdbvolset.cpp 536658 2017-05-22 15:48:20Z zaretska $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -42,7 +42,7 @@ CSeqDBVolSet::CSeqDBVolSet(CSeqDBAtlas & atlas, : m_RecentVol(0) { CSeqDBLockHold locked(atlas); - atlas.Verify(locked); + try { for(int i = 0; i < (int) vol_names.size(); i++) { @@ -74,9 +74,7 @@ CSeqDBVolSet::CSeqDBVolSet(CSeqDBAtlas & atlas, throw; } catch(...) { - // The volume destructor will assume the lock is not held. - atlas.Unlock(locked); - + // For other exceptions, we'll provide a message. for(int i = 0; i < (int) m_VolList.size(); i++) { diff --git a/c++/src/objtools/blast/seqdb_reader/seqdbvolset.hpp b/c++/src/objtools/blast/seqdb_reader/seqdbvolset.hpp index c1fe7585..a9e354e8 100644 --- a/c++/src/objtools/blast/seqdb_reader/seqdbvolset.hpp +++ b/c++/src/objtools/blast/seqdb_reader/seqdbvolset.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_READERS_SEQDB__SEQDBVOLSET_HPP #define OBJTOOLS_READERS_SEQDB__SEQDBVOLSET_HPP -/* $Id: seqdbvolset.hpp 398155 2013-05-03 11:37:45Z camacho $ +/* $Id: seqdbvolset.hpp 539178 2017-06-19 17:07:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -73,8 +73,7 @@ public: CSeqDBVolEntry(CSeqDBVol * new_vol) : m_Vol (new_vol), m_OIDStart (0), - m_OIDEnd (0), - m_AllOIDs (false) + m_OIDEnd (0) { } @@ -144,9 +143,6 @@ private: /// The end of the OID range. int m_OIDEnd; - - /// True if all OIDs are included. - bool m_AllOIDs; }; diff --git a/c++/src/objtools/blast/seqdb_reader/test/CMakeLists.seqdb_perf.app.txt b/c++/src/objtools/blast/seqdb_reader/test/CMakeLists.seqdb_perf.app.txt new file mode 100644 index 00000000..cbe64a37 --- /dev/null +++ b/c++/src/objtools/blast/seqdb_reader/test/CMakeLists.seqdb_perf.app.txt @@ -0,0 +1,9 @@ +add_executable(seqdb_perf-app + seqdb_perf +) + +set_target_properties(seqdb_perf-app PROPERTIES OUTPUT_NAME seqdb_perf) + +target_link_libraries(seqdb_perf-app + seqdb +) diff --git a/c++/src/objtools/blast/seqdb_reader/test/CMakeLists.txt b/c++/src/objtools/blast/seqdb_reader/test/CMakeLists.txt new file mode 100644 index 00000000..9abb7afd --- /dev/null +++ b/c++/src/objtools/blast/seqdb_reader/test/CMakeLists.txt @@ -0,0 +1,6 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.seqdb_perf.app.txt) diff --git a/c++/src/objtools/blast/seqdb_writer/CMakeLists.txt b/c++/src/objtools/blast/seqdb_writer/CMakeLists.txt new file mode 100644 index 00000000..da248ab2 --- /dev/null +++ b/c++/src/objtools/blast/seqdb_writer/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.writedb.lib.txt) + +# Recurse subdirectories +add_subdirectory(unit_test ) diff --git a/c++/src/objtools/blast/seqdb_writer/CMakeLists.writedb.lib.txt b/c++/src/objtools/blast/seqdb_writer/CMakeLists.writedb.lib.txt new file mode 100644 index 00000000..0302423f --- /dev/null +++ b/c++/src/objtools/blast/seqdb_writer/CMakeLists.writedb.lib.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/blast/seqdb_writer/Makefile.writedb.lib +# +add_library(writedb + writedb writedb_impl writedb_volume writedb_files writedb_isam + writedb_gimask writedb_convert writedb_general writedb_column + mask_info_registry taxid_set build_db multisource_util criteria +) +add_dependencies(writedb + blastdb seqset +) + +target_link_libraries(writedb + seqdb xobjread +) diff --git a/c++/src/objtools/blast/seqdb_writer/Makefile.in b/c++/src/objtools/blast/seqdb_writer/Makefile.in index 1389578f..4a171961 100644 --- a/c++/src/objtools/blast/seqdb_writer/Makefile.in +++ b/c++/src/objtools/blast/seqdb_writer/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in 88982 2006-08-31 15:53:40Z bealer $ +# $Id: Makefile.in 535575 2017-05-10 10:14:35Z camacho $ # Meta-makefile("WRITEDB" project) ################################# diff --git a/c++/src/objtools/blast/seqdb_writer/Makefile.writedb.lib b/c++/src/objtools/blast/seqdb_writer/Makefile.writedb.lib index b153d68a..de3d2287 100644 --- a/c++/src/objtools/blast/seqdb_writer/Makefile.writedb.lib +++ b/c++/src/objtools/blast/seqdb_writer/Makefile.writedb.lib @@ -1,11 +1,14 @@ -# $Id: Makefile.writedb.lib 427429 2014-02-20 13:41:40Z gouriano $ +# $Id: Makefile.writedb.lib 535575 2017-05-10 10:14:35Z camacho $ ASN_DEP = blastdb seqset -SRC = writedb writedb_impl writedb_volume writedb_files writedb_isam writedb_gimask\ +SRC = writedb writedb_impl writedb_volume writedb_files writedb_isam \ + writedb_gimask\ writedb_convert writedb_general writedb_column mask_info_registry \ taxid_set build_db multisource_util criteria +DLL_LIB = blastdb $(SOBJMGR_LIBS) + LIB = writedb CFLAGS = $(FAST_CFLAGS) diff --git a/c++/src/objtools/blast/seqdb_writer/build-alias-index b/c++/src/objtools/blast/seqdb_writer/build-alias-index index 29210857..49b28239 100755 --- a/c++/src/objtools/blast/seqdb_writer/build-alias-index +++ b/c++/src/objtools/blast/seqdb_writer/build-alias-index @@ -3,7 +3,7 @@ # subdirectory # Author: Kevin Bealer # Original date: 10/21/2005 -# $URL: https://svn.ncbi.nlm.nih.gov/repos/toolkit/release/blast/2.6.0/c++/src/objtools/blast/seqdb_writer/build-alias-index $ +# $URL: https://svn.ncbi.nlm.nih.gov/repos/toolkit/release/blast/2.7.1/c++/src/objtools/blast/seqdb_writer/build-alias-index $ INDEX_NAME=index.alx OUTNAME=index.alx.new diff --git a/c++/src/objtools/blast/seqdb_writer/build_db.cpp b/c++/src/objtools/blast/seqdb_writer/build_db.cpp index b2fe68c7..0d39a027 100644 --- a/c++/src/objtools/blast/seqdb_writer/build_db.cpp +++ b/c++/src/objtools/blast/seqdb_writer/build_db.cpp @@ -1,4 +1,4 @@ -/* $Id: build_db.cpp 518102 2016-10-31 17:37:45Z ivanov $ +/* $Id: build_db.cpp 535592 2017-05-10 13:38:07Z rackerst $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -978,9 +978,7 @@ bool CBuildDatabase::AddSequences(IRawSequenceSource & src) } } } - if (!mask_data.empty()) { - m_OutputDb->SetMaskData(mask_data, gis); - } + m_OutputDb->SetMaskData(mask_data, gis); #endif rv = true; @@ -1121,6 +1119,7 @@ CBuildDatabase::CBuildDatabase(const string & dbname, title, ix, m_ParseIDs, + long_seqids, use_gi_mask)); // Standard 1 GB limit diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/CMakeLists.txt b/c++/src/objtools/blast/seqdb_writer/unit_test/CMakeLists.txt new file mode 100644 index 00000000..5b254161 --- /dev/null +++ b/c++/src/objtools/blast/seqdb_writer/unit_test/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +include_directories(SYSTEM ${BOOST_INCLUDE}) + +# Include projects from this directory +include(CMakeLists.writedb_unit_test.app.txt) + diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/CMakeLists.writedb_unit_test.app.txt b/c++/src/objtools/blast/seqdb_writer/unit_test/CMakeLists.writedb_unit_test.app.txt new file mode 100644 index 00000000..cc93dc2d --- /dev/null +++ b/c++/src/objtools/blast/seqdb_writer/unit_test/CMakeLists.writedb_unit_test.app.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/blast/seqdb_writer/unit_test/Makefile.writedb_unit_test.app +# +add_executable(writedb_unit_test-app + writedb_unit_test criteria_unit_test +) + +set_target_properties(writedb_unit_test-app PROPERTIES OUTPUT_NAME writedb_unit_test) + + + +target_link_libraries(writedb_unit_test-app + test_boost writedb +) + diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/Makefile.writedb_unit_test.app b/c++/src/objtools/blast/seqdb_writer/unit_test/Makefile.writedb_unit_test.app index 38aff80a..9392a6ae 100644 --- a/c++/src/objtools/blast/seqdb_writer/unit_test/Makefile.writedb_unit_test.app +++ b/c++/src/objtools/blast/seqdb_writer/unit_test/Makefile.writedb_unit_test.app @@ -1,4 +1,4 @@ -# $Id: Makefile.writedb_unit_test.app 507920 2016-07-22 15:11:05Z boratyng $ +# $Id: Makefile.writedb_unit_test.app 535575 2017-05-10 10:14:35Z camacho $ APP = writedb_unit_test SRC = writedb_unit_test criteria_unit_test @@ -16,4 +16,4 @@ CHECK_REQUIRES = in-house-resources CHECK_CMD = writedb_unit_test CHECK_COPY = writedb_unit_test.ini data -WATCHERS = madden camacho fongah2 boratyng +WATCHERS = madden camacho fongah2 boratyng rackerst diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nhr b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nhr new file mode 100644 index 0000000000000000000000000000000000000000..f1a8a1a565cce6befa2461ec1f24fd6d96e769f6 GIT binary patch literal 8179 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 Y{S*7AFft`@-0--5^F9oUl|rxiKaSWh4FCWD literal 0 HcmV?d00001 diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nin b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nin new file mode 100644 index 0000000000000000000000000000000000000000..031da2a618e75fddd7d5e6a30eafa3b14c2f7499 GIT binary patch literal 716 zcmc)H&r8#B9LMqJ(phs`eOudNHRmUZQY_jJ*O$ebjisZcS(hN94r2>ExS}nhQ+e{} zH7XAt>rzm7Oca9-A%Yi?PCFQgkRWIgqA%J01fefH_ zE0>DqS!JYVYUOIpl!}@P50;B2ZeK9*Xv{Vyb|sNCw{JB+($H789nGiEo94}HaD-(V z4khI)wB%(`RreUr#fXBPLHe2fP8}vt%Ms4pynJIQRbFc%Kk`suPLWj*PPIRP znSd^hXEmO?BXiJw33{$W?+#p?g{TW+>OZk0e;}zdy1Wav_D-o@N;$56gv=!LuR``S ln)pk3xt-mqMD(;wsc@vjdv<@mP+v#<@bB{tHDc6pAjVgjyVB5q(3ZlVdd zFj?7-mM}%x4+c=jDRe4la42rwVHnNIeRYR9c#paGgjVH_SuhWqF&|s80Nb%pc~=I} zfyTWm9L5^uE562J)n?7b66KFBVuk9S>B36YGikzV)%$ghwRnqls&9Mm-~D(Vx?Dz0 z>v=GC)@y-q5MBD{mht}veKfLzP5O98KQ`)<-`iNEPp=#OrFes7`fTz9x)aV$j6T5& LQ0CC4ADjLF%tu&x literal 0 HcmV?d00001 diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nni b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nni new file mode 100644 index 0000000000000000000000000000000000000000..d48e1724dad3eec6d8c9d9c16b0c7fb7e1448ed5 GIT binary patch literal 52 kcmZQzU|?hb1I7zL$_j{qe5epa0!T7x0|~?bKmZZ~07z;DX#fBK literal 0 HcmV?d00001 diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nog b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nog new file mode 100644 index 0000000000000000000000000000000000000000..b28ca97ba931d3ed7751b48a00e81f4132e48870 GIT binary patch literal 240 zcmZQzU|?i`02Ux+0%gM~md&en1MyzQlGC+}%Cr0#o^GoL;zl5D2I5vAZfDe5P{F9M zq=rGV@&ypT0^&D7{0@jeFf99T48*2DY|f~E<_ZvB1L7x)`j>cs*aV2pfY^dL=SvTx zvGh4cb5RlI{HAk2e1V~q>ovnfzDJBM+o~8{3!E4(#W*q=)rA0YD5F~rJCF`%)JO?s t^zNAn#M7BPDpHu-ZZt9{wQDn{IruUcb7XUtw7M`bFlhs^4g;H^2LQoENV)(3 literal 0 HcmV?d00001 diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nsd b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nsd new file mode 100644 index 00000000..c487b7db --- /dev/null +++ b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nsd @@ -0,0 +1,117 @@ +ab02164535 +ab021645.135 +ab02714419 +ab027144.119 +ab02729220 +ab027292.120 +ab03328321 +ab033283.121 +ab04165531 +ab041655.131 +ab04199916 +ab041999.116 +ab04200017 +ab042000.117 +ab04200118 +ab042001.118 +ab0495714 +ab049571.14 +ab0495725 +ab049572.15 +ab0495736 +ab049573.16 +ab0495747 +ab049574.17 +ab0495758 +ab049575.18 +ab05116428 +ab051164.128 +ab0702289 +ab070228.19 +ab07035522 +ab070355.122 +ab07060510 +ab070605.110 +ab07084923 +ab070849.123 +ab07085024 +ab070850.124 +ab07097625 +ab070976.125 +ab0710223 +ab071022.13 +ab07243940 +ab072439.140 +ab07261436 +ab072614.136 +ab07261537 +ab072615.137 +ab07261639 +ab072616.139 +ab07292027 +ab072920.127 +ab07594638 +ab075946.138 +ab07639842 +ab076398.142 +ab07704233 +ab077042.133 +ab08618034 +ab086180.134 +ab08643241 +ab086432.141 +af01739332 +af017393.132 +ay1427092 +ay142709.12 +ay85605426 +ay856054.126 +ay86230729 +ay862307.129 +ay86230830 +ay862308.130 +bc06184144 +bc061841.144 +bc06207343 +bc062073.143 +bc08811948 +bc088119.148 +bc08842445 +bc088424.145 +bc08885446 +bc088854.146 +bc08906647 +bc089066.147 +d8875811 +d88758.111 +d8875912 +d88759.112 +d8876013 +d88760.113 +d8876114 +d88761.114 +d8876215 +d88762.115 +dq2736780 +dq273678.10 +dq2736791 +dq273679.11 +hscdc2751 +nm_01930332 +nm_019303.132 +nm_03134235 +nm_031342.135 +nm_05709748 +nm_057097.248 +nm_13362040 +nm_133620.140 +nm_14567842 +nm_145678.142 +nm_14567941 +nm_145679.141 +u0000151 +u00001.151 +x6521549 +x65215.149 +x6521650 +x65216.150 diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nsi b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nsi new file mode 100644 index 0000000000000000000000000000000000000000..238e308939c8ef8a55fa7e538efb17a08e80656a GIT binary patch literal 83 zcmZQzU|?imU|?ckU_B0`OCf9q2L=WKAQKrd8$s3B07X53I5;uMz{t?d#FWX{lp(Rw N(8S2xz>>*`0RZOL2onGR literal 0 HcmV?d00001 diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nsq b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_nucl.nsq new file mode 100644 index 0000000000000000000000000000000000000000..e39b45bd14ee31836ae7bdbaf4d1410ff28a69eb GIT binary patch literal 20028 zcmeFYX;hP0n>HE(6k&z{Vp#$qfCP|11({SJK#>HQ0vJJ(l#~R#)7!;f$O*!$n}TJSW2l>cb9sk= z{EpBmC5Vern4r{xMEYeQ5CqNWn7Rf79Rb|Fh+wkKb79}kGGKQy3X)A{xC|=<6voL8 zW4v-?dU6ZYx;BvAT#yZf zeFkze=rCip-R7yWaoCThb$XLGVQjY9W-LvT;huUOmX(6ZR&$#K>HNyeAOE(qjbxV1 z{Jp=!t?GhX9_<5$rLUxR65F2ofg(MGeg`!L{auzN&eoT%2Jj|I#jFG?@JN2jl+7tiHK&3`#*3aS#azT=tgCfu^=;3ds zDe~x{dTzE(fXjnnJUWr8X zrGhVRO7-cxRV>}%TSRhjxfYK+3|clBiEKO(MDMrvZRiC_~3LyWG z1||Qo-|`FfQHZAf*S4J3Hh~T_kO8zm165`HxLSmr9@^gSN92rNDZ=|fmiXBP%k8XT zNhKf$FoQdkZy_=XcfwVPeJ6|3%|g>-hzl}guZiEV=YTq#w$^?U(>EUYOCHt{ zpJoH7t80s7$U{zKw4BZKm7lXRs{Sp|>4DYUv6#IGeJl4P{?{*_J7a^!osPstmJVsC zGgN+yO%~K(B~Vr0C0J8btFc$fm~&0UNc=ehcBym&a%&34$eKC*o-@w8JpvA^tYuVX zgvI##ni>>UDII@-obuyF{APF=d9%v=65r7+!<)7-8JgEv$o0YuG6MuUf~4^7*YOmq(cI4zq)Ss+SI?;xh%TNU!xc=? z%gwvf{wAL=sSBL8dxnpoD5I32l`WgH>y>ObnUFnI1)mC2F*B~1F zDysZH?6WUkv!LQ2!G{$U-70I9Akok!ZUNKf-pzA9Op7C*(>Z9Ksn`G$Mrou)Bh->( zj#>3S0Zdb?MC7rNT}SK%^(NCH#f2=p33WkXv=I<+D~&4nKau_4EV7seT~W;tdTk<$ z?^Jf-EQ=M7E(*1iQz}gbcyS$Dr#OO$zYwNehuj=Wx;Jeq>NmQ_wsV5A1H_g9XI@cc z%603r1SFcvhu*UY;o0h^9>bOE{;F!3XPj~RDfacA$nyO275Mr)8OKT~S8~w^YIwDA z{Lckbna`R<$>G&AYPl68%S6OYSqx^BX*KZ#-%b+wCYL7%qPY~=6kVmpuX1|reBk@0 z^Q5V0zEE;Wyc1{4wF^ZnVB9SR#T69q+cTD9!nkfqUWSdI7HEXjOV$-V72RY}eFHT` z4P@Q3@2}?)56=@C8zgPNv41LEgH9-dGuA3|e(S5{;I~h|Rwd_uffpDT84f+>R1{sh zfuj*9K6D=0OV98(teA_QHVi72H6vK*pGKRdY?^KeDG%ztY91zu_-rM8IyEXk@Y9`| zdh5{Q<{}y;l%4$VZThbwD=LHcSH9jHa)$TN5x!zDdsW6l2coArA-VX z8Vo;8VNf1G2aVZ0`%|6Ih~mOIQnKfg2GG71_NgrL;Cr%_Ww=%R{&`|G-N<)~xjL>o zSQP(l&@*zWWQ3%45p7H}{TMSbiME;=rC(A9=J_(st6@;}Pc`>y4bo=N7L`bt^=Pg5 z@FeQ;1MBO-(A(34FPmR1?) zaGQ3F$N%M-IiQV6vChcCb4O*S{w4l%*b8?oGmg{kOWqI8oQ0N}ibro^W3_fx757=7 zm}2Iw!k-K3(Yg_oT;Ch!Y#)ln%`Zgr+p(;G+Tw)%Sc}NCnQkwn>D;kO^5Cvemff0& zt$eJe+!|giEZ&5kXy)N5unOk8M1{%X9Y3&?T~Qg*78c0(fpJ;U%meqx@duN6OleA0 z2j?V-!e|aaC`Zi}VYtOJT4&2k5|dxLN`5wfu-nBfe$s2okG;r_M9vwwII{<*d`lvC zc@4{3`$vbWH=mI%ri(Kf8YoK%_i)?K{N%*VB6Ew+L0xLWlqfvz4V{gBv5&mmHv?8H zoK`xDZ6$Iu{0p#0()rU+l*w-tQ7w7N*LT8)F+Y_TT6OkTMeSlfb@=VY*xKHzz^k9J z%QJxpYxq$yHofrC+L8<{on9{DgmKW;nQf!u*o?_qnW_v`VCU-@mss{-^s#?>cmuC8 z9?31hA|S!tMl$@|OZPbAy%K{V!jLoWNoAdfXYm0pQ<8>zmBgm=A9QbXOouU-ziOFE z>NCSAl!DfL@ah;B(=ef|*z2Hhn~-=Wp6|-0Sw&w>K6ZLFWO-tB2z{Y?%6n8$DJUe2 zo|%cp)ZDv8ZL2;Hj&_QTm6W2`XT1_yea|s;IA^N({e^|l;yw8As*AVmGXVAzY$o?t zjJUCdffn_zV@{mOm^cQ>6fHMUB3@M@D343ycRXH;Df(1HWin#IPRsE3ez|(#wKall z$!~SctFl>(HIbZc?L+>a;A;^d7G5~SHR2lXDLGzjWu11EI!?lhM--Yf&_@0({?Qmd`b;UPN zbPcmkS0fMdLP?R;xlQIc;15opyp4TzQPeF^T1_Y!+=x zWw)qmC#(LFFl#7FCC`}JO^&gw4-<}3F?l;^=VDZ@jLQ9~xSDUP<9rjY9b_M@q?++< zbC*PU`&(3Q(QOZXE3cV28r52jOayg_hWyGA)|dj_eOH%9nHF{-gf(MnK?aQ0DrGl| z`V0&+z-DbM-#{Kan%&YJFn?uVb9D=x=lbb3afs&%sZu>qde!*YOX)zfe_hdgTrxTt zQEj(PEv>f9ZfUY?whnGKQ0UsqZlt`nGdlMEX6fJ_W=K3F+1rKKoY=T~u9Nhn5`!Ix z8liM^pKbyP-AtQm11c0qQIj;fZzZM2VgGvNl3v|!8!{t7e>>_gO31(sG4!=P+X1AJ z4)-`>6Wpeo=vS~vr^fxggnRjLhc-yvUN9^+&p-LtG8j>{H$`VEae>~gA8134N&sr% z1~|ZRAFV<;W1Xer1_diyhP+Bw@HH6a>4Zh23tWcR44-k6#vOd;4|`2T!9CFzM75PA z2_|f=p6?};2u&7+g-`cSgB`*OL&u(FSA6TU7+G=&C`JWfLVbP*zxbhqzF*sSYfrsW zaJb!bJBMGvMVF9ZOH-F~iEV-kRu@oDz(&d&qrk{N1}!%BS?l-d)GyeR48W>N>|Z`- zsrK#D)T!$CW@UZQY0}vYCp661DY)M%9vb#yOvXuyxc5%sGL6Z|n^D(y1ise|F%+C( z!PvZ8ENp{s)$x19*vPXL+*6R%5Q-}nnw6wkKDX#;a26`O~*0R?%n$hV1r)Yc~%dp7}nMpyo^q!$14 zQX;uqF^T|$R;wCj7O`s+W$XaQmds3U%WDY_OwYeow#F%YC~qm?n(9@NSIU$pT-Tv{ zVXzTr)vsYX~|*A!1vGGR(}bW)j!Vrm1) zAE%?kVJJ9S)A#jzjbOTSI<99G>{}C9= zf6YwU|IN&$f5Xhb2BYxbW9Hw2QTrEW9{htDe7+8lanjN5Uzh>?f5DK7PTmQrI8z*% zYo(S_amrNA?2n0ym7FXNe_zorKQrcO$V5OZUYKilA#eS0)$A>0cr=1Z_cKkzHMNIwyJ=q{tfs4Y35s;ahQIsZ*F}(q~@E64?${CYa2u1 zG#adj*pA_h4IioPNFq;&m_Gz4o9<-{CHYXt55nl&Ubbpq0AIJTVy%oN^!jE;Q4RG= zcQ-}a3;jJ#WCLReJK#!!QstUFQBmB|Ncgu@@e0rG`Wu>y75isMt!aamGIGjNxtBha$?^-+3i$ z%un~2F6`I{*V~a%iR{W^={@9YHf1Q5+iU@-7wdq^8tJWF8K!?F3&U8uzLn#WRwWOD5>rkoX z*{ftQ;o;k-->h8$>Q(4(LYlGf!DI{&#}6CyjGx0YeyDs{tZ6H*!$P!6kEj$eohIVK=j1eHdb-dLj0iYrMLrg+?m)B~NHP zz#LK2gaTDK87tPsjBvmsC0Do?q6A&~BBZN5eV?1LftZ*UYGdy5BgqI zDh&5e{_9FL_g=1~vPNQ^Y~aADwyvzs-a3{PnN;cE_lx@hkOskC0{~Db6$f^R6@wkL zjy@UgIutVQc}Wx0|4?UGCp1nu3Z_B#4+1oXDJdx>$x%u-5?_N=;t;fUx}`>M4_2`! z1keWuJ17~5y#dd+C!XYZkP=Ma#zDOII;eI^H}U~`;3JN1KyA7K#6@4%WWVl8(71+o zl48;UA0@2@>7}m^$sUlDhY$5%_ZUrin&<|*>1)g><>>-8FRLf5-`9>x9+-wQJU4~c z_Q4G$L7;_>j+7>>i%Qa*OM%XQ<#y#g+0MTsCYG>f?Eu9%r5tJEE|kC}Nw5tAEx$aZ zSF+i2XyJgK#}(q@mH&6d1-xt5LBDzF?6+-)7@3`Y+Y9J6ahSYy)MxjNL)(vgc6(@h zc5GE7dAu;Q{kr-}eb&KaZ*T`>oD)1+&17#Jo1({T>IQu4u(Wqc>o4*68xatj>awDLXn?Urhll>$MpK<=^k)%~Z>9i2S(=5%_S^@jp<${d9r{keR1XO2ck;9eW$S7AvC zZ!_JD4Bg+Rt_=V?OEq1m9QPXpCzCiY)C<)Z?k>(R5waWY`}<$j212dXYbxnaK;|i# zZaJuK*bilHj4Ep=M6797nNI{=zHCcLVOn?JXavuvT|wlGz$uFRO&6-QH@95{I*A8H zN!Qf3S`nRG3udp6y z_Twjt`s`OUmjLzIj{2u&8pG0eKP`DM{t8yCPk{BLCdw5TwSs2bIwu}4D$Q9RJ=Aez z;lTdRjSfRfn_Ft%rGhReZy0Q7AH^5cV=`OhIM-p_Kd-;tQ|7U;_{Bp=eTP~0UJiJx zk8#QwAz+5CFk1%WLPJ8{%CTX@8%x)&R$4z$#j(uib>yxv$ajP8pgjU=>tCGPZnbxv zc#QQRX}P@+cSJc*foSU|WEGuR$DowA_B3R-Jzpu|FZ`9+=1C33he^zeY7a~Q`xzyM zus!fX$+re{JOBWgg+O3XC=nijD4*r?XQ>1H0djY6Gr;fPfcC zQyO30*BpR!koFD5jXb3RMMdrQLq>}33uY@WEgp{Uok9nKgSM)t^ECv`3*h4URL#<3 z{o25Uj(w02YNlXUkj`{$NQg*penRe?QpEOX6pT z#c8TIuC?m&5HD^h-g}$lF@|{6t)_Rv+uKR&MK^xm80zh^Xi0du$C#mbWFlkFkF|dx zV(c0uR;k4`ktIa3JmQof;!HSiu)yi>sSHWXnaOH0H>U7&@tv5nMYkuK|7ecHMii27 zpZT3O{xS0Ev5)VOcSsz3vI7l3_sH3xiOB~bJjawjxLBFm>))a$3YQKaXQ1Jk!Of0K z*{IyB`cK{|dnO0N%!6%dmMd{%#*IGMBDw*2E1=)v_eWZK5;e2pRaYAQZb##j#3DD= zj%JBs)Xy%GBseGo6`AGa^GpUZ*@9$g=}@&m-D5@uDtn@ zVdD?z$MK!bIZZp+hgI$c!;Er(^k&6FI*r%7w#wCmKH|%n;^$Lv_+9`Vq%gU${Kfk4 z{I!H)8bk3i-)k^=%56qOYB-hJdnH>T!TcAKN z5)2>T++QUrJ@j`^R#0~KAtHxwrRbcLvy`l1{^q5~VieMQn&K@FF&9W02sEb?G}pd` zzfiGJhSapZOHkNiqb|josT!2rNY6yj9akq-T$ClCB-%qIW+=i93MrbeU`Xr>{^Vp= zD<%BC*>?$OS`OnNZvk`z$K?p9TW&0|wgOCn_6Ez^|HTRML&GB1SkdgIXpI z5+N8S2>_kSm2L%CHUn6KQsg>qcv?fabP}E>W+5s{yP@r?RtX66I>uFJ3K^<@4oZh{ znd(DgpZt`SXN7k6mN{WRA)OvP?byO0L4eKn=x=hivF`4d;WF%T zV_FE;jidZC422*32$ojx)zN9f6t0(E&x5TSmT*LR*`?1=cNY|^skS0`8om?BI2j0L zojkGe>v;iXNkzsf#&`%~WWtHlt0zzS#)l;??>fGm+9#xtqLHv^H&|k}3-6nFd`Iy( ztCY*kf)e{Dt6ajicOD;1X!ZCDW*sDZIpIZ~6*OaVd}??H`zO>Y?P5#t(K9ks=+qq- zNHJ-#f}(xW76!hgF}Bi?Y0`mcqT!KKE?4Cb<`S5e%p)t6sDjK<^#I#=2)*}j7ng(_ z;UDEh_H|BnlNh#r9D3wo2uY>N?l-^XOuuFU&n_PqxpyjcY~8;%arI#Sb=6h@$$$j$ z;xN_2C5c_`V2xEfW?%HcdTD2`vO?&^EgM?ZAvDs!Bwz{#w|s8v+aG!rBp(b5n>G@p z*`q^VEa(O*DIgQdRb6r)rOE50D_M3b+$ak4?Xo3*B@~QGz!X&LZL@u?1CZCVz~enm zF7)!IVn2>qLlc|-=HnqwJI}?zY$D5bZx=JS4-KCZoJrxX| zw8Ks}N}OaC=Yn@GaptZ$t~yy*)c3u}mIXErFGst=oqhFxBQli7q;_`+>b|Ce9ea&a z;xfKon^G*lLCHYpv#hub;8>aA`Fq{pDwz;0i+u~rH?lz(6h@1m}6Qo{;|4yu!bB7y|2>+5}n{2_91JDs4WK zemZ^a!qV__I~`N>tKZ89o>N22QQ}8?U}#h*8|3@kWK}lhnRl@UPgWh#(lK>$p)CHG zsO*Ph=V{n@8jY}Ag9{22ckeM6%19vKPnrRN^M(X@ViR$^?(n+1Cbi;u`tsEQoZrY_ zBjmw%f|=1F;=ow*_`12QNJ)+3`5xeAt@{{eHL4=XfIJ|rbl^xql!58rJ#dr(>9Z34 z@H|3)zZH0G=H*y%>FT}|A6*;2 zP~I2lu}=nOvhVn1cOv|nO=1uocfwFjC(q>>RM*Uuqh&#be?08%yHWbZ`4)BZC zO{!3XB(DUVPl-Utzw@ZSk(R1~Y#4^32JA$7-m-44X*7Tv*C)!e9L zlci#-t=g6W8EfuhNksvFsyxp+208X?=Tc)MI*xK$&=N7XB`PPb7hYVLP;1_lqz6?O zvE7O+FANxDjwP1IB4wWqMgzkN#>laqaYU2Tj&hp3IA*!eD0d`sD#E~tKo1Z^P`3T! z%aLlZJ51*?Hs~p{!2%mEL+olsX-&D637LZLxsnz6Jz6B9$objkP)R>`C?uqdX;YCK zf{J-n>ey5k#^y!;w*rnvvH zHVstBW6sI!WU?)p?6HI_8|5g?rZmrqGVdnvXBIOPHuSpr(VF;h|J_k`P>z^G#jVRG zm~I*CHq>VYQ>-}=D&Zz_@Gd(P>#Fxax1@NRSlnYVzolN+Gf0EVOENXGPdpp(S7%T? zmdNl~GC@J}xl6GD1v_SL`cZBATIRW;CZ|{{<_*a3xopq`U$0hc7dRaO1&xg0aaXwc zQY$sQi(vetJ=-vp2eV{lh*|!^@^da+*Ex6wB#VOK=15rv0+ufnse|S+ExEdOLCC3H zs5PkDo>qd(72Xt|f2+_a!x_@;h^U5XuiowQ&EF$XBp{x z`XR1lhSlo&8`f6!FFzX22t7u!j63J1=`#OoDLxW2{3}M6b+#xn^<`Pb*kHdUD`s{m zJ2QO4Mm6oTB5F8{xr@yU3ahpL#Fs=O6n|9fGqo0TO;GW$aS=m%RHfJkcTT`{{EMqgPADSXL6o91Pd|6{FA5n6B_@xZoR1@qt_($4XhH|l~! z%y1le=J{I8=bW)=&WFX8q3jLan8>*#!|^#~c1e6eb^I$Ii*erIj5k@T%@%`v<}_W( z7*1fXm0&>ZIGZrUZmBw2upL-^KKw@sMZ1WsG-4sbju!s<#hm+vFh$i$2;DPv8PAUG+X>KS_ADe%T{Khbh& zoYGk>hHe7VKw%TwXv;v(>zBTdj}MQ~HQ3i|I-9*~g9iL1C~W%)*m;bU_6;KQRra+g~}V zuy@;A@sJ|mOTzca{i^}AkA4=pYW$wRX0%F-!No+39Lu{I4rCM3ZvGlmakE8m`~8K; zFh14v-W%Ur{T3PV@#lH5J8s>&)xfArsIs|7PICJIN0gm#3y%KYRju^A|4i{_Jv@dV1PQ)@D$=OnV_gB?#yK_w?ljg`iBu z7&0Lxee*yB&AonEZEguVAgB}B28P(-b5->NHB>beR~BC^?|rQQvd15+WxwdQ*shnZ zZPq?In_9EqV_x}^tbOWGiQ-nuHR_k-hqp0fMV27R@CEid!#EAGk4QKChj(tq}~&bKI@Ibwsi7 zYu)9>gU*T>9vq>Ihp|hU|K&0K?D)4g>p58-V;h(LQftc8va(qTlHb1~RMGi5g;zlsfEDVct1BcnK?3GRgR@l14ia>hJ6G{ZWVG+ zP#Rnm?;XW4WFx=D!%f(Re!i+-;puMmEq%3Jl0vJNoQD2$?-XQeR%3h}Yo@(Fk4fkX zOy=^{3tfV{!&M5P{hGZX55lM=6`d~4RPo!8d-di%=v+yTexL#abqas z?D=@5#nsUPTKONFIWE5@R}||nhHUhXs|a#jSmBae*`0c{ekPWx;P)4}4U}AVB?VvG@;HmWpMu!_1TbOve>EcP_K0b!UTl^mw)GGbN9|Q5& z!;AE;U_1CR848q>(^6a7ddD?{&D=31nEnF(vDRs)9kOKV`armgVWIEuL9x1qOVu<| z7rY!X=Xe&cbRw_Y=%jaV8Wz^7Ny^_8Pitz@K+y1_fr9Or%G2pB6h;B%=fI5lqg{RR zhXu(?zvV|rxj0xr+W0X-u{9-kE10+GFY7+_jr3>=T}d7-97ESEQDr>A%7u}>Ry;-_ zk~jU+ACERLL(VTwjRhttULOZmYJ`pL%QMBvZ%tt~Db#hx&CBgwU;g@kHUfnOfa3W- zew1M2Bcz2`eV?hUH%EAqu@Je?$@Q1z1jfHX!9oeH+%nmS~?b>^pvcARqhU!}uKh!d%oq;Jx09<+K3(ywS#A%l%Phu`V8n zD%!nbUh}SiCF5f7{C)DYF~imGjvv%?VuFIHVPD1}QPrsMlTN+mq^pKYK3GQq`vyz) z6pcKD_R_zEw3vM1S39#*&HXW~(!7cD+3;#bf)9g(><bQsPFt#1)>;iSivs| zAkWx*5Y-Y}sFb0Arz*uNRCeqiL3vg((1~|ih;7VZVnqeA!i4AaNz5uymW%q$AI~kt zSR9!iajTIu_2QDN;=;#p6~RH}A--U|F&o3PAe;X5lEzx9D;@}uZ+lTFN6E5BlvEGTJ3wZ_j@F}=Lb-1wv8NZ?GL$R#;M{b&h+wa&1s4eM3* z7hI-Q2XR>pW#a%Irpf*R?7`AMBD_~bAr~X+qbFx^7HRIs1AO1LJM9E}^6|v|T)~rmbq}SMtDc^+=a5p^EhdZlZo;Busdbeb3v5VJf`zc*km>~mPzP?MjRi`jiwEM?0uyJ|v^ z9S+S_opFTlSdaj<#GK@v*`QrHxZvXlhiWP|S+!NT!QsxlFXV88(VO`fOD4!O)1$r| zTDYo(7He9~kmt1I`tvPzTIhY;x3+3bDjQOK&VNpqjB2odp=V%IKZP7>=x5AWK7@Ht zASUGa2hU%NDvp185LOJX49m?eBi;PN0yik9#YM?!Ay&j{)Q4#HE#9(-_i=zk??+mH zFP2>kHwlN{DMXq-5m%F}_Hcn!X!3YOUw>L($m?T?RpCQTSnI7YeqnzVX7EG~Inv=1 z5r;KKibnfVT0(h|yae)WMG>3AV%IluAKPNBi^BWE2Yr|oRXA+e41SDN#Koc5Im{*N zaPL7;qi^`3x$tXMD5kWUY2T7CMy0vet+i|?Y&VFPZvdWNQ`51f6cxyKSClNIl!j(5 ze~rg`I!UuReC)K5b-%QceQCjIKu%uwpQ!fl>8vBlDTK;S+N)Pk+9+?E#jczw3F$6~mPk#N0R2G3dl?PxrXFtBSZOOXQmMWKf(zaPyU#^PU)8uWv?h zYu7EM6{XzXG+<^av(K+yZ*=z#f2}DdN{3don*j?3CQl!{C45#iC-oJlHqBdI5vJk@ zkFv2sf@-{rHI74?NXG;)2FSh1Ua^)e#)9~X1IJw_ElW&K{X|SfLbF@v5AKd8t)R2R zxI`BbQ^*9C{@NVOcgzno-s9Kuy?0i0EC6XKEnC~; zPj^9?`hfcs<*&8O+}}l+{tf*HPR~<^wCuhYF=VpmKC!-T7QowK>~ma*l{GX2mdwS8 z=^P)}DMTRx_ed-4QnCjoih5IlvXP_kU$AWGSd&;6KSSK}Y3?Fy8|8OVFG&r*p zQ~5(u+ko#WTjQ%c@4DIK2EA8y)(>2IZAENJaP04*gq~blnJBNzru;S;H$=1i2qxq2 zktX@Ap{>*qHf=f%fxknoLWLAt-@{#}G$SeO`R@k$Iii;MJ1%nSV!tpyd3i_C8EW%- zVulT3c{0h;h(=RoE9+YGB^a*LLTDOr}x9 zs(I0sqLKj0O{{EiZYwy@mSM1z7g;P~3x@IvVhhU00?9)G@((n!F@^9W?WP&~{F*6b zJ}%anuM)Q`55CfsNBQCWgFs_;=iQ6%KoV-jHBNa=bd`mx#BTYo#zLuHrXEf730E@~ z7dgOo8XM!U*^q@aec?$f-S5|%lAR{`hH@IEzRJl4dBqr=dH-xoDit%0J|47|Ax*^= zQ-%t{U)id~>rNpi%X^FEaY$fT2CA44M@Yzorw#6@Ia*05_rc1_*##)Vqq@nz^L&YX z<0(`hZ4zG*Z^P#rL6fZudhN&cDe|^>Z7x?tb9&8yTCc>Dx_a2uRW3}qwVuR+9U0@oeOqbZkuH01v1X= zc1fSl&`~d4fudFY+5|4JWd-|%BL9*FN3_}C;B=ItryCsci>8upLSVzHe+EpDwesx1 zxh=XH=Gai@u~&+BGoW@O$ZU}P&ziCvk~b3Y0w}hwaB){Oez~b2$ZGH2NDO^^7!nXX z-z;1ja$kR@<-PgE)5c{gk(93~+~o+G>ylT9_WoYS}5{I?dMjC~L| z!)d>}d@NQ|@U`72v>Py)q+tV5`XL9r6sm%pD5nV-pcHPqxkV*J3!%8Pb*Tj5tOS24 zpnAcl25re!U};(ya-K%Hn`d*w*gw8lDY@6=L6prkCu)cJvT~>E)S81gR&Jsc<)t{d z80B4`^u<1r+?%V>$yCY$jkfiN{j^{%dHO6J2inWD0zs4xYbDzqr5YkaRh}+)`fU1e z9!kCh^n6ip_54eUM2$9l>3vKwSHc%Oj2S#aOy#5Mf*qB#I)S$8MQlP58=<6%^kMl6 z22QKj^Mq_aJ7vVu){~C~fOIt_HcKVx>0LZPzb$+xfiZx(Ce#2IbpdbX0JPfd_NjI1 zGqgQ3mF=zt^gd6=PVXK#nvR}K3WtOvr`Q+3$CVnyPKh`ZQ8=Ux2vK2~n_L{~&utq~ zYMs4?5T>-hS;)xMS9u9xXlEz1fgy?jPs;_^1n||~Y+%RZ$IC#FAr~OWF@CwZYN(F1 z2ItB=MuWJU)mW$zz1sWb>lm8o({hBeF5 zlZLM;j;cXk$a|N}8dF|2xfLpFCb;-9T(_$B?b`$(oHPVLMQ*&iEZ9~-#QIoON7ib8 zb-SZo2W;GKr???cEz32OX>OSeTR(LPc~#QTchv~F&yos4Q4isI5>sV|EIUgk#yx|+ zK-=w~CP|B9V+r54n^8(^_=AfKHW zw9%fpxc&TXNssyAVAm-Rwg=6~)Usl|s$%fpz(9eWe z3t^P-c+`Vc`2belw(Dzi{IpN~v|V_bYwXRLxgge6Xa$QgsFpftp>)1vMa8TDtT~t& zu9ZPUIu{}*xD>;NqpktWD-tx4*56oBUBsk`uMO&aaH4Al!_H80pX~|GIz1Pn>6a(7 zn$mU^@ppcXNPV6~KxJg))r!F|4%eYzBplOQgDZ)f)(s3jQ8#^0WYh zN`b-2f5OUX6>&&cS*8c}=TOgX)et)!o*FbL+OyepZ&Yf=_nYEnJuei15WR9hK|Lr1 z(PX9ec-#*BOSOZ50Z94+02qxf<@rzX zYti|}#I-_no|SqOu0Zu-F2X{|s7pQ~8^V^6=3Yo8oIQ}c^#I(KJp^{^8~y z#(sXVOA9cu$I9ZDGEcC5LW3fUD@oCCkr=Iy)rKfI;cC|oTR3u=TYy_02f|hnoIA&+ z5%V9v7*?A5_9^$7-PH@tn27)(tX`tbZ}bNp{9HORz(V%}9@(1fn!wezr1-1K%9rO| zRwilVVe|2@EL6pQvvjd|4%gI9d{xBX3jC;7e4fbLeXI~HoXR%D0o#-0q|&Wau08M` zQ}yJ0q%(Oxs!(|=9_lzV&2+E5MLC^@j;2`0REc^S+dqFGdXYtV-e|zGC=T@LL$!Wk zEn1Sg^W=4l!iebzg2nIYeVCgnYQOFjH^7dal6M#M#;DDoYznqIWq+mWTy^NK2U`?S zb^waE>a$%`3RE>#b9s_&C{ODfDm3RB2*)Kx{Y!Xwm*Yi_3R_K$n{iV1^4ug{8IWxy zItLvWviimO&K~O?Q;I>edVtHPQOwv|1Z>{X%*9(uYc^mf#IT`N}#Dry-hom>pS4gM_l z3-j?;A^6}PuKA01dqGA4OE!?iTo7P%b=|y5>#6MNTCh7{3+lZOhEl5ioY16vS-zzmw z-U+?_Vs4s_JzTd}v^~-zmsz$fNH?&G2!JA8Bz# z??-K$J5n@RX^dzD3uVPj9|^7~U$)!A(eIg>G56x6`4fn-R~BlQ00?7 znR6$%_Kvi?!fleDTO|wQk*c?=kJ&o*MIST>(DKV=hjJ@i?(1JErQ=>Oa|5>ee8Ftl zjR8EbJTb$Jp8aD`>BZGG zcb6IoXqHW_f*2sck;J%5qm)mQDJ$-6V%gmm`fvI+2V_=mS;K>B==1i#j zSENJr@URCu;6om5Z`~JNdtSLe2h#Zt8vb(QsDC7`0DxjWi-Pt0 z-gI0-mdt2Dvh=5tNjpDW#m24a)Skg`QI}>i#I>MrC#CvyR9Y*=l-X&+9Z2#@6-qUv6Fe&T052T1%%Wi9aB=>(XknGrfe!XQ zXw2YBLT~%-q2S7Yq4#&j?K|g`3A@?(pY(?o?OZ!cfiO1*g(J6e3H!~vRcR-!T;2AY z_4|V|rdS|Sa<>v_->qDf5_@1t$7o>Os=Xfh=NSL+U(pVJvfZ9F6%{o(~Zs!uS}m{&PL-$&fiEE(4JuD5@W6Z@yfZO85RLz^Bm9};0g44MAT zD4jMfu`LuF#xbb_ARs0^!o$|u%AqR#S9FvYl#F$h6tIfdGTzTmTXOX~T83veehZ_4 zj^TbZ+{7B^gu~RR$4h-!;ahb4@^iTE_*bdEU8`yTOS}TXPG(PqTW*E~;PuefIYW^F z3!Q!oV#YO1y%h!11A%gCcH6{O$6bc&>bh$ChK=kkP;p=md}YN$e#!nR(Rl;vxc$Td za78=lz}v-vwta6s&>o(LPRR_x_U@Vv8}pakF0~!mGU`hjUht?p;5q-c=CI<@miES> zm*9sz`1S*B53eCQ%u^3!0o&gxdI#AT+5r|9^ft0QHZ=C>)h%qlbbkVvnw*&IIi#_m zKGZ#sa|Ae_*hadqp{cjVtvmY9vH$>+8Fpg}@rQ$_S8PckJp*2dOt_`Yz*C+tyJ)AO z5VSSuaaiafS~%3xcR=9B89ll^vJE(p=bW0}vZBFH)}K33hxVOc3H4d%k;lV%Dsk{v z2l5u`p6b_>esO+GMQ}jK?=9&+L6RQ1c#eyg&Ha_!=ix~R)g$vywD>7XY%pTkW{0)U z6(+Jn4DyuSo!F$#G|So{E0b*m+fJV{Ep;Y&Yu#n5yUyhh0AASJqQlRkTK!)EQ3kI0 z{N)%)AiM+wK|x9N_yP|Jz3mT=&==AJAU=XGA^HP6k4in! zAd(~L9Te}q$s!^i1bauX#RF50QTcnj_yh$6&;p%$z5rksb#z^MM}gr{{Y^qpVeiQY}_&V=nhp3{x~A5d@kf>Jo69pF(5!ckL1I--*=z! z-?xzB2Y-J66!Y>ia{q!rz&oR{&h#!5(>jEs%ijR-01NRkd&eI?d{7fT!QAe`0Pz11 z^bQB{{4fKa1OuQLMum2i_IYQPS!Dq2#H!`=t5WBbdP@z09Z4Y) z4GSZR>!CE_Ee`0yyT}NIAf3`DA%&SEk>sSNU6TF*3!YHE2!ONepn>Egx|qt1F4wL+ z`%g5}?(4gE!-52g1A<-}N;ltPAKZL_=I^#g)$hOm|J4JJKfBBEF)vG(AP(jJ|I;xY zitZPclt&WET7q5He^i=HELx;yP2I)3Q%C?b#h(6pY_L|hZ0^Z`V_0e`Cx zBh?4!Ur>Ssapl1PG`K+|skwarj2x^V^ze%x`w1LaRi4knIqQNaPIu1oF`_%s{mb9J z?9ulCOFzR%3>EyKzw;n_g#!K0`9LoN5I8>6!v57#%LC9bxkBt63gv$Y06WVb-X&y{ zeiGN$x(<6Q5`EKNJFnl@B4Z-BT?0g3&O$QF`61+TUg<|J}tq~&H6Nib1(fuFvKTc1gS_7mN9ZS9WdLY#*I-r-Xr=HyE zwn&ReMji`?$s`xvg8`RHe*xZ~g*_aU>NOmTVR>GU6s))6@{q3A`+UIzNXPU3 z2og#D=qbWF!UO>54uUU2KmB^M!ib2B%*@P0L`=-??(XjH?(XjH@BM%O`uP;Z)4GiE zeb5r1093_t00005@c;l8@Bjd4@c;m9@BjdS@BjdagVmf$s+WpKk^<^pCD@~ex#XZ$ z)Tf-zkdeSq&U{#oYyEae8Gkt-u^k|SU%&C`1@Amr(txDQ2{R$zfT0rm97T}i3|@Xf zJMQ@1Bq!v8s1P^J>!R<&2_OkhIM2Lzzpgze=kedu@2F19`3Okbeo!dV4)H)DUoXJd z_1?Ev_%!pl46Xo_jd)NK@I4cM5(n}@?d3t=kpx1;!%V+7M1+@!OWzs+6-p5ggTP4m zKOo;w^a~w+3`q6T?eji8C$Rk&jC)jifhZqSJlq7YKrj>lde|?|D4|Iwe6>6kLjS1$ zl=1;oEqWuPT>L;BM+`;Ru=ws%QD~KY01JENAlgtKfdby&bV#}bC5WsYL*J1B5HEVv zKtjY3bgcN5M?6i{P#GLuf(y}ye;l|;)ImasGC%{s4h!`c0M!8?0RSuk!vcy79Rc_c2`U;mn;D1Q5ISJq(&vc6N3O*q7BKRpfBXQh8AL%#H0z2n_OWx23d=e9* z06mn7Ub~)3f$!4ZL8udq`40o%QX+FuzBL2JeC5n{JgGRpx540p=s=Un`~86DG>b!A zg!2wgv#-hyKRiN006iu7AUQu!0%zki70@qB{C|{BqRY@uM}PxJf}iNca1bRv)8kYi zS96d*M2U32&)5zCGYfhALI>c3;1E9bK!aCr$KMQ~EAa>~D?nsjmE(i=ey2J=BU}n4 z3>1$7DG!V$^LklBd*f2Y~4iXD@wcVI>`3EeJT=p65jIM<(<*= ztA`_z=i!GZFYmo2E6bvoOmmUQ)0cPd*b(u+o`N5HKXBb=r&f@v83wX7Rco~^8*ON9 z1*r{1Hz!d`vD><0_)<;F-qh;4>N1 z%uMDKC$2b-rRqvstD;ABQ$;o1tZO!E*;ZR4e7micwHH1g5}eK?lM;hq0QSLyNF`68olO46&ZEqTSEqC5(0N4Gn1!_ckZl&#Y1MMhWp#k%!gW58=9EzHqoX9 zk*#a-y4TL2Uz?_8AjjRPDNWtzpgd}7%?${U=!b&GiLJV}16{s9N4D#Au{*B4ac?B@ zY&ReuESA?fju#TCbcP?UV|P$3Zc0-k_2JP^{NuYJ+XX2hu(&==2{z-Ta^(+%MB}K7 zBTOmKsNnJIWNxAy?4hG-+ykK zwk%~Rqr=PnskweF$GzeP{OiMgYH4flyhBCJwfvJ{s9%ThL3RF2gRSG61ssaD%oOb0f2ocPp=+xIezwEz>ye1=c44AT?x z3iL3|babx{7LVc;z7GjqQ*XnNwUbjLaOr0rdmcGUdo_egni zMo6V7kkl`v1No)7B&sXTrb16B^*^g20qHc1MTVisPAbfi&-X|L76W>CjKnP0fsp{_ z^|4=o$F@T(B=*Y__~<%h0rc7`E8oXPkpO4Ibxs2Zt@W!j!1p`;^^r*AY8T(% zS~@2$t*z(g7jldE9eZysb3DgGdw2@SPFvg5wToJHcv5>R?(sb`)c$Dn^pyYt$g-SF zL%EE2?mhlSbGW_~^!ezurNusnM!S*x^}D6u`AKZOKhvX(M{ePeFO?7t}_8uK!v%C5{l`~7IL z6Ek4=00^MC!fP*mVkSk+OCV<6yDMlhGkHwRBw3L2$4iyj5h=6#F_=ov^cI+$EGJ;p zkC!t35fIgw=$_7BNk4h~K8wJUj%EPA?lu86wKTJ;nQa7E8Fsjaj^||yw!}+%RRQQs z1oS317f;=~KJSC>3q`=Y7?Xc*74~k}LPm*F( zwMM6k*AcJ8pw-H=az$WE&>d@6zeLI{a$;JbOvu3G!9BqOMiiFiK|opBgqW+{9_<1f zMeYT+`;c;1>0D`fT`tOHIDzoi0)b13kZRY7D8IPl3xj&Ourt9d!Wq!p;!dDkHvygF zDE#g$?%85Im(P_)yh&hr6F=fjImM_M?j`KBVH(N!9CXBEN}GKfeFMXrSx&=e)WF|* z)3Uq6T6PCIv0JsOmhHf=ysIPr-!H?f_DS%={BYG)duq)ZN*z2|wtM_68R3tS5k5P= zzO+_YUg
    Ns)uru{FZfiLYBOrrz*e046TX6MHsP^-bNu0awf_>aFjXOorBuF~W?a zHt@MrLkBEv89D;WcM2`Wd9Pr+9}07PGLZFB=7WwJ(csT9w#G}m}HdO|!@0o&-X zuq+VrVh3-1^i2Z)|j zX=_b%Q3r}+#@zhmHmb3>r}RkJJxMqOAHE3tEhO6l@PQ8(On_3Li;2$}JgCSJqz6Tw z=ZF}^t^#}t1{17_a8AmgL?Iss?gVqYayExZb{DW~Q)5+Uo1D3y)CY2glUNXS7Oq{O zRUVFojgF%`!Qf)>$yOywkTro*a;c<9<0QR_$vH+RKVBkCOg})1gSCa1SPq#^`KLZD zV1Ik-!dUj6`7Egb*qdg;eT4+KjBI@aZoM?27xr;-f0!@v0E@=brxY8|M-(WH!}I_D zOP7i11EelEI2_MVAggd5rs3fc%#9YTcNZ0yAN`&(iB!7-kyFQY(>_u)oTdqiYMz@U z*rL}hDFeW9oXAW}1IP&~1A9YY>98ZC11H<#=(Df1i_{0ZK%|roTc(Vu%f$2{QWq~% zSXx&@5TS}HMHw~c1R=pA;l6k&?v<4W1H0Ym7+!y^K{`3wBwCgW1Z^;$+bZ88RmGE; zi71)&I}X|L$5WyFWLSk{ibi?))35BSa5#SiE`J%YzvJ^JEi{D2Q>h5#dXU_ZOnj25 zo@$abZqA%`NRe_Pm0`jF1(Di$m&fkBmC!zn6C*+Cyna*``#nFG2-+L6YN%4gP@p_! zb(eogdItiM5?CrKKU*lqf!eB)t8ziN;B0-YCR6_Xpc=GGAYPL>z$X`ngAf9M-Tb#u z2g3l2*2H~}YdziypendoZtB^|9BR5YzQ+xFt!)|Lcn7#4fCeyy;HqtK9y^8;VmEO= zgG2~b2cV+vAf#>{Czs-vI)>|E#S6MQJ~AvrV-L%xosavD+E7ddU%G)Q+jI?pNw!-@ zS`BZIWXqUDvaQN+g5@m$!19fkDy2UUD4D?P_{a|-WbH{oOo;RvYgM4z#xCKF7_{Cpg4 zb9fyebL3XQ-@qqC-k0Adrq7dp!vj3YvJ1`EY#?c27s9KDsl}7=G7RXt(NV`ucI+Uy zpB>6}vHzJ8s)LTTF`|S^=!zNK=o`M05shf)$zPBX@quBQ0`0smH-CN7SV)73)87cG z0TYqwV8gfiIXX~{RlU`)9Ec5|l^|`i z0q00w)*B#P$Vi>KgH#8P3?}YTorSXu&AXBVBco3R#WyS$C?B{!)#VZ(XD3nj9#Max z8?OtMe@AMGhd0yt?Wk2jgezQQ46x|FGfxlbli^t?_)m*a%+{q&JP&-7X879-5Snl= zM^}J8ayRfj)Zl-DJd2%jb`y8#OSuwUMr9(`?+w$#VV0oZqL%<#_ddH9yRGvUG@ssO zmx;;}zdkP)@-Xi)r=61)rCBJqt&Ham+8O6^Sc$W?M@scm+PgS5NV?bwV5!dC)$})@#tg_5KP??9l8r4&Jd5RP=QA<)YZMF22w5dHkF=M#IxM0j?!^~WJ z9~W-8vAHm_h8u62v0-NJ%*%Xcw(~jvv-3ay-|zeV{thq+NRT=EVngw0e_t@ZXDA-T zqhs-4G&T|s`up6>X^Qp*;i}>wTv}EY1mQ?&dC=D426VQL{ad|F9{>N;ZOOHA9})}X zuzZ805qW0IFeHcMxM!xqlw?R5mgg`nkkgQwC_VBBrr&_Hi;$isewY3jGH%0+Lb(i? zS72tA#AO1quEVTy$R1RAx_Bn%DTIpU0_5sB*V?(h%WIQckbep0E|F960}5V1&@T3x z*9(P>@)Z_%u1Fn4YFs!U7G=vhSZs|Y4`AslSauYOQ(<|gsBc9Hl&G)7JWA{29h40~ zSnpwdl`n+~y;R(Vl}+*mDi1s{Xdd94_nbT*p zG5d@=X7LMVpO8QLw?@bwA+?2m>;1dF?U%n_U-m0{uaB*IXx76^b;s13Cnv?)W$F&U zR%?ek*Q?Q7D)n4#@0wPKcs9~4PsBM!-axH7Yn@G9rKqRwC#-6R)rX+|CN!8|gIXIm zh?#Hn|7bSfO$T7}LufI>)=~KYZ4wf0h6M literal 0 HcmV?d00001 diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.pnd b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.pnd new file mode 100644 index 0000000000000000000000000000000000000000..7f1609f5d7880c870f11e3ca042a248ad774ab94 GIT binary patch literal 912 zcmXZbNl4UT7{~Ev#!=_5j^ox$_IDjkXEe9mms#9%Uot4{QjvjBQA3aw)uB#ObSN(d z5os1>mr4&oP*w*8DItjJ;y|=9gjuO|sP8LX-VZ-`d7p>(d0#QCSw$p63~Mpyz*sE7 zcq|p8`z3aW(PPIh3Gt4hLrfECSSexOBd}34uOI913U-L*OF=hgq8CfhgRNMN{n#e9 z;RbX`;?QTz#;+KPK{Vhu%)zDgtas*Pr|6w+SSNay3Eimr@S=_$EXHa)f))4$w~5|e zip_W(Yw-~_;Ct-G57;Pr&nc|I8`y()u|@RW8mz*zScccohf`QD`n0OINs=zuFhtS^ z-(k39oL2p(OJ+&{dnLPL1>?kZ@hWCY&d*yICHaGKXp@5T>KrQ`#TY4^%0;sjrM6?V zl-#?7cD#(5l&`+RJgJyBjK>;C8Z_3WOV#?7+t&rVE{ z{maXkfWI(N21X8It_)0`L8Bacb{~_)pWKU)*oR?qtTq>*XyFbN|uLQW2kqAnwY zK8%&Ixn@ko7BtDtzv`Vhu?#I(fk|?E<~8Qa+)_Dik$KNUj5q9>IETf?phew(LCE8p zN-Q+B#HORe^v1t{Mfe-Hh88|oeYB&h(~4?;lX-Dv0xjmn)l_tv1N{du&m1_s2Q_W? zQx_I#p9WTOhjl2R{zaed$J;09z!{}|^uahL;vGz|2N$w1$`N^D5z8G5D{9UgoYBEF R%yS)&m{-~3x2gKu{{f`KrcM9= literal 0 HcmV?d00001 diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.pni b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.pni new file mode 100644 index 0000000000000000000000000000000000000000..0a97c9f0df5dfcdd8b476cfcda3204199e80e08c GIT binary patch literal 52 kcmZQzU|?hb1Lg@pstAaIe5epa0?7Tz4`eF;2Lg}~08%{$F#rGn literal 0 HcmV?d00001 diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.pog b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.pog new file mode 100644 index 0000000000000000000000000000000000000000..cacc72b1180ed251a7d46117f524c96dd4bf0f01 GIT binary patch literal 376 zcmZQzU|?i`02Uw>24y2Ci&Gj5l9g{6($>~9$n=UaEII87jwDG117v+{BE@f+5)?+a%3|$-;yI01l}Qod5s; literal 0 HcmV?d00001 diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.psq b/c++/src/objtools/blast/seqdb_writer/unit_test/data/writedb_prot.psq new file mode 100644 index 0000000000000000000000000000000000000000..02c4cdb4355147174362afce1bb50c6955d7dd70 GIT binary patch literal 29605 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 literal 0 HcmV?d00001 diff --git a/c++/src/objtools/blast/seqdb_writer/unit_test/writedb_unit_test.cpp b/c++/src/objtools/blast/seqdb_writer/unit_test/writedb_unit_test.cpp index b1b0ebdd..3ca76f3b 100644 --- a/c++/src/objtools/blast/seqdb_writer/unit_test/writedb_unit_test.cpp +++ b/c++/src/objtools/blast/seqdb_writer/unit_test/writedb_unit_test.cpp @@ -1,4 +1,4 @@ -/* $Id: writedb_unit_test.cpp 518254 2016-11-01 17:36:44Z ivanov $ +/* $Id: writedb_unit_test.cpp 535575 2017-05-10 10:14:35Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -220,6 +220,9 @@ s_DupIdsBioseq(CWriteDB & w, int oid = -1; bool found = s.SeqidToOid(*seqid, oid); +if(!found) { + cerr << seqid->GetSeqIdString() << endl; +} BOOST_REQUIRE(found); @@ -633,7 +636,7 @@ static void s_NuclBioseqDupSwitch(int cutpoint) BOOST_REQUIRE_CUTPOINT(0); - const string srcname("nt"); + const string srcname("data/writedb_nucl"); const string dstname("w-nucl-bs"); const string title("bioseq nucleotide dup"); @@ -1084,14 +1087,14 @@ BOOST_AUTO_TEST_CASE(ProtBioseqDup) s_DupSequencesTest(ids, true, false, - "nr", + "data/writedb_prot", "w-prot-bs", "bioseq protein dup"); s_DupSequencesTest(ids, true, true, - "nr", + "data/writedb_prot", "w-prot-raw", "raw protein dup"); } @@ -1210,20 +1213,20 @@ BOOST_AUTO_TEST_CASE(SetPig) vector files; { - CSeqDB nr("nr", CSeqDB::eProtein); + CSeqDB wdb("data/writedb_prot", CSeqDB::eProtein); CWriteDB db(nm, CWriteDB::eProtein, "title", CWriteDB::eFullIndex); - db.AddSequence(*nr.GiToBioseq(129295)); + db.AddSequence(*wdb.GiToBioseq(129295)); db.SetPig(101); - db.AddSequence(*nr.GiToBioseq(129296)); + db.AddSequence(*wdb.GiToBioseq(129296)); db.SetPig(102); - db.AddSequence(*nr.GiToBioseq(129297)); + db.AddSequence(*wdb.GiToBioseq(129297)); db.SetPig(103); db.Close(); @@ -1263,7 +1266,7 @@ BOOST_AUTO_TEST_CASE(SetPig) BOOST_AUTO_TEST_CASE(MultiVolume) { - CSeqDB nr("nr", CSeqDB::eProtein); + CSeqDB wdb("data/writedb_prot", CSeqDB::eProtein); CWriteDB db("multivol", CWriteDB::eProtein, @@ -1278,10 +1281,10 @@ BOOST_AUTO_TEST_CASE(MultiVolume) for(int i = 0; gis[i]; i++) { int oid(0); - nr.GiToOid(gis[i], oid); + wdb.GiToOid(gis[i], oid); - db.AddSequence(*nr.GetBioseq(oid)); - letter_count += nr.GetSeqLength(oid); + db.AddSequence(*wdb.GetBioseq(oid)); + letter_count += wdb.GetSeqLength(oid); } db.Close(); @@ -1328,7 +1331,7 @@ BOOST_AUTO_TEST_CASE(UsPatId) "patent id test", CWriteDB::eFullIndex)); - CSeqDB seqdb("nr", CSeqDB::eProtein); + CSeqDB seqdb("data/writedb_prot", CSeqDB::eProtein); CRef bs = seqdb.GiToBioseq(129297); @@ -1395,7 +1398,7 @@ BOOST_AUTO_TEST_CASE(IsamSorting) s_DupSequencesTest(ids, true, false, - "nr", + "data/writedb_prot", "w-isam-sort-bs", "test of string ISAM sortedness"); } @@ -1424,7 +1427,7 @@ BOOST_AUTO_TEST_CASE(DuplicateId) BOOST_REQUIRE_THROW(s_DupSequencesTest(ids, true, false, - "nr", + "data/writedb_prot", "w-isam-sort-bs", "test of string ISAM sortedness"), CWriteDBException); @@ -1433,8 +1436,8 @@ BOOST_AUTO_TEST_CASE(DuplicateId) BOOST_AUTO_TEST_CASE(HashToOid) { - CSeqDBExpert nr("nr", CSeqDB::eProtein); - CSeqDBExpert nt("nt", CSeqDB::eNucleotide); + CSeqDBExpert wdb_p("data/writedb_prot", CSeqDB::eProtein); + CSeqDBExpert wdb_n("data/writedb_nucl", CSeqDB::eNucleotide); TGi prot_gis[] = { 129295, 129296, 129297, 0 }; TGi nucl_gis[] = { 555, 556, 405832, 0 }; @@ -1458,8 +1461,8 @@ BOOST_AUTO_TEST_CASE(HashToOid) "test of hash ISAMs (N)", itype)); - s_DupIdsBioseq(*prot, nr, prot_ids, 99); - s_DupIdsBioseq(*nucl, nt, nucl_ids, 99); + s_DupIdsBioseq(*prot, wdb_p, prot_ids, 99); + s_DupIdsBioseq(*nucl, wdb_n, nucl_ids, 99); prot->Close(); nucl->Close(); @@ -1765,7 +1768,7 @@ BOOST_AUTO_TEST_CASE(UserDefinedColumns) string vname("user-column-db"); string title("comedy"); - CSeqDB R("nr", CSeqDB::eProtein); + CSeqDB R("data/writedb_prot", CSeqDB::eProtein); CWriteDB W(vname, CWriteDB::eProtein, "User defined column"); @@ -1923,9 +1926,9 @@ BOOST_AUTO_TEST_CASE(RegisterTooManyVariantsOfOther) BOOST_AUTO_TEST_CASE(MaskDataColumn) { - CSeqDB R("nr", CSeqDB::eProtein); + CSeqDB R("data/writedb_prot", CSeqDB::eProtein); CWriteDB W("mask-data-db", CWriteDB::eProtein, "Mask data test"); - const int kNumSeqs = 10; + const int kNumSeqs = 3; vector oids; int next_oid = 0; @@ -2056,7 +2059,7 @@ BOOST_AUTO_TEST_CASE(TooManyAlgoId) BOOST_AUTO_TEST_CASE(UndefinedAlgoID) { - CSeqDB R("nr", CSeqDB::eProtein); + CSeqDB R("data/writedb_prot", CSeqDB::eProtein); CWriteDB W("mask-data-db", CWriteDB::eProtein, "Mask data test"); W.RegisterMaskAlgorithm(eBlast_filter_program_seg); @@ -2094,7 +2097,7 @@ BOOST_AUTO_TEST_CASE(UndefinedAlgoID) BOOST_AUTO_TEST_CASE(MaskDataBoundsError) { - CSeqDB R("nr", CSeqDB::eProtein); + CSeqDB R("data/writedb_prot", CSeqDB::eProtein); CWriteDB W("mask-data-db", CWriteDB::eProtein, "Mask data test"); W.RegisterMaskAlgorithm(eBlast_filter_program_seg); @@ -2218,7 +2221,7 @@ BOOST_AUTO_TEST_CASE(AliasFileGeneration) CDiagRestorer diag_restorer; SetDiagPostLevel(eDiag_Fatal); CTmpFile tmp_aliasfile, tmp_gifile; - const string kDbName("nr"); + const string kDbName("data/writedb_prot"); const string kTitle("My alias file"); string kAliasFileName(tmp_aliasfile.GetFileName()); string kGiFileName(tmp_gifile.GetFileName()); @@ -2258,7 +2261,7 @@ BOOST_AUTO_TEST_CASE(AliasFileGeneration_SeqIdList) CDiagRestorer diag_restorer; SetDiagPostLevel(eDiag_Fatal); CTmpFile tmp_aliasfile, tmp_gifile; - const string kDbName("nr"); + const string kDbName("data/writedb_prot"); const string kTitle("My alias file"); string kAliasFileName(tmp_aliasfile.GetFileName()); string kGiFileName(tmp_gifile.GetFileName()); @@ -2505,7 +2508,7 @@ BOOST_AUTO_TEST_CASE(CBuildDatabase_WriteToInvalidPathWindows) BOOST_REQUIRE_THROW( bd.Reset(new CBuildDatabase(kOutput, "foo", true, CWriteDB::eDefault, false, &log)), - CMultisourceException); + CFileException); BOOST_REQUIRE(bd.Empty()); /* temporarily disabled. CFile f1(kOutput + ".pal"), f2(kOutput + ".pin"); @@ -2617,15 +2620,13 @@ BOOST_AUTO_TEST_CASE(CBuildDatabase_TestDirectoryCreation) bd.Reset(new CBuildDatabase(kOutput, "foo", true, CWriteDB::eNoIndex, false, &log)); //CWriteDB::eDefault, false, &cerr)); - //CRef tid(new CTaxIdSet(9301)); - CRef tid(new CTaxIdSet(9606)); + CRef tid(new CTaxIdSet(9301)); bd->SetTaxids(*tid); bd->StartBuild(); - bd->SetSourceDb("swissprot"); + bd->SetSourceDb("data/writedb_prot"); //bd->SetVerbosity(true); bd->SetUseRemote(true); - //vector ids(1, "129295"); - vector ids(1, "30172867"); + vector ids(1, "129295"); bd->AddIds(ids); bd->EndBuild(); CFile f1(kOutput + ".pin"); @@ -2648,14 +2649,14 @@ BOOST_AUTO_TEST_CASE(CBuildDatabase_TestBasicDatabaseCreation) bd.Reset(new CBuildDatabase(kOutput, "foo", true, CWriteDB::eNoIndex, false, &log)); //CWriteDB::eDefault, false, &cerr)); - //CRef tid(new CTaxIdSet(9301)); - CRef tid(new CTaxIdSet(9606)); + CRef tid(new CTaxIdSet(9301)); + //CRef tid(new CTaxIdSet(9606)); bd->SetTaxids(*tid); bd->StartBuild(); - bd->SetSourceDb("swissprot"); + bd->SetSourceDb("data/writedb_prot"); //bd->SetVerbosity(true); bd->SetUseRemote(true); - vector ids(1, "30172867"); + vector ids(1, "129295"); bd->AddIds(ids); bd->EndBuild(); CFile f1(kOutput + ".pin"); @@ -2686,7 +2687,7 @@ BOOST_AUTO_TEST_CASE(CBuildDatabase_TestQuickDatabaseCreation) false, // use_gi_mask &log )); - bd->SetSourceDb("swissprot"); + bd->SetSourceDb("data/writedb_prot"); // These two IDs are NOT in the FASTA file. vector ids; @@ -2725,7 +2726,7 @@ BOOST_AUTO_TEST_CASE(CBuildDatabase_TestQuickDatabaseCreation_NoIds) false, // use_gi_mask &log )); - bd->SetSourceDb("swissprot"); + bd->SetSourceDb("data/writedb_prot"); // Not adding any IDs. vector ids; // empty @@ -2889,7 +2890,7 @@ BOOST_AUTO_TEST_CASE(CSeqDBIsam_32bit_GI) new CSeq_id(CSeq_id::e_Gi, GI_TO(TIntId, gi)) ); int oid; - rdb->IdToOid(GI_TO(long, seqid->GetGi()), oid, lock); + rdb->IdToOid(GI_TO(long, seqid->GetGi()), oid); BOOST_REQUIRE(oid == rand()); } catch (...) { BOOST_FAIL("CSeq_id constructor threw exception"); @@ -3269,6 +3270,7 @@ BOOST_AUTO_TEST_CASE(ReadLongIDNucleotide) BOOST_REQUIRE_EQUAL(index, (int)fasta_ids.size()); } + BOOST_AUTO_TEST_SUITE_END() #endif /* SKIP_DOXYGEN_PROCESSING */ diff --git a/c++/src/objtools/blast/seqdb_writer/writedb.cpp b/c++/src/objtools/blast/seqdb_writer/writedb.cpp index c13618ff..0a263728 100644 --- a/c++/src/objtools/blast/seqdb_writer/writedb.cpp +++ b/c++/src/objtools/blast/seqdb_writer/writedb.cpp @@ -1,4 +1,4 @@ -/* $Id: writedb.cpp 513849 2016-09-15 17:36:45Z ivanov $ +/* $Id: writedb.cpp 513693 2016-09-14 15:53:17Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/blast/seqdb_writer/writedb_files.cpp b/c++/src/objtools/blast/seqdb_writer/writedb_files.cpp index c39fe809..b2d5411f 100644 --- a/c++/src/objtools/blast/seqdb_writer/writedb_files.cpp +++ b/c++/src/objtools/blast/seqdb_writer/writedb_files.cpp @@ -1,4 +1,4 @@ -/* $Id: writedb_files.cpp 500404 2016-05-04 14:59:01Z camacho $ +/* $Id: writedb_files.cpp 539178 2017-06-19 17:07:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -112,12 +112,16 @@ CWriteDB_File::CWriteDB_File(const string & basename, // deducting one for the sign bit. static const int MAX_OFFSET_BITS = (sizeof m_Offset * 8) - 1; // Define maximum allowed max_file_size. +#ifdef _DEBUG static const Uint8 MAX_FILE_SIZE = (1L << MAX_OFFSET_BITS) - 1L; +#endif if (m_MaxFileSize == 0) { m_MaxFileSize = x_DefaultByteLimit(); } else { +#ifdef _DEBUG _ASSERT(max_file_size <= MAX_FILE_SIZE); +#endif } m_Nul.resize(1); @@ -144,10 +148,14 @@ int CWriteDB_File::Write(const CTempString & data) // deducting one for the sign bit. static const int MAX_OFFSET_BITS = (sizeof m_Offset * 8) - 1; // Define maximum allowed max_file_size. +#ifdef _DEBUG static const Uint8 MAX_OFFSET = (1L << MAX_OFFSET_BITS) - 1L; +#endif _ASSERT(m_Created); +#ifdef _DEBUG _ASSERT(((Uint8) m_Offset + data.length()) <= MAX_OFFSET); +#endif m_RealFile.write(data.data(), data.length()); m_Offset += data.length(); @@ -324,8 +332,12 @@ CWriteDB_SequenceFile::CWriteDB_SequenceFile(const string & dbname, max_file_size, true), m_Letters (0), +#ifdef _DEBUG m_BaseLimit(max_letters), m_Protein (protein) +#else + m_BaseLimit(max_letters) +#endif { // Only protein sequences need the inter-sequence NUL bytes. // The first null written here is for nucleotide sequences. diff --git a/c++/src/objtools/blast/seqdb_writer/writedb_impl.cpp b/c++/src/objtools/blast/seqdb_writer/writedb_impl.cpp index e561b0a8..32546901 100644 --- a/c++/src/objtools/blast/seqdb_writer/writedb_impl.cpp +++ b/c++/src/objtools/blast/seqdb_writer/writedb_impl.cpp @@ -1,4 +1,4 @@ -/* $Id: writedb_impl.cpp 518254 2016-11-01 17:36:44Z ivanov $ +/* $Id: writedb_impl.cpp 535592 2017-05-10 13:38:07Z rackerst $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1234,15 +1234,6 @@ void CWriteDB_Impl::SetMaskData(const CMaskedRangesVector & ranges, } - // We may be passed an empty list of ranges, or we might be passed - // several ranges whose lists of offsets are themself empty. No - // matter what is passed in, we should not emit empty lists and we - // should not emit any bytes at all if there are no elements. - - if (offset_pairs_count == 0) { - return; - } - // Gi-based masks if (m_UseGiMask) { ITERATE(CMaskedRangesVector, r1, ranges) { diff --git a/c++/src/objtools/blast/seqdb_writer/writedb_impl.hpp b/c++/src/objtools/blast/seqdb_writer/writedb_impl.hpp index 18d8cec3..fa5ae285 100644 --- a/c++/src/objtools/blast/seqdb_writer/writedb_impl.hpp +++ b/c++/src/objtools/blast/seqdb_writer/writedb_impl.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_WRITERS_WRITEDB__WRITEDB_IMPL_HPP #define OBJTOOLS_WRITERS_WRITEDB__WRITEDB_IMPL_HPP -/* $Id: writedb_impl.hpp 513849 2016-09-15 17:36:45Z ivanov $ +/* $Id: writedb_impl.hpp 513693 2016-09-14 15:53:17Z boratyng $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/blast/seqdb_writer/writedb_volume.hpp b/c++/src/objtools/blast/seqdb_writer/writedb_volume.hpp index 17e30dba..a4116212 100644 --- a/c++/src/objtools/blast/seqdb_writer/writedb_volume.hpp +++ b/c++/src/objtools/blast/seqdb_writer/writedb_volume.hpp @@ -1,7 +1,7 @@ #ifndef OBJTOOLS_WRITERS_WRITEDB__WRITEDB_VOLUME_HPP #define OBJTOOLS_WRITERS_WRITEDB__WRITEDB_VOLUME_HPP -/* $Id: writedb_volume.hpp 481389 2015-10-09 14:40:20Z rackerst $ +/* $Id: writedb_volume.hpp 539178 2017-06-19 17:07:37Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -247,7 +247,6 @@ private: string m_Date; ///< Construct time (same for all volumes). int m_Index; ///< Index of this volume (1 based). EIndexType m_Indices; ///< Indices are sparse, full, or disabled. - Uint8 m_MaxFileSize; ///< Maximum size for any component file. // Status. diff --git a/c++/src/objtools/blast/services/CMakeLists.blast_services.lib.txt b/c++/src/objtools/blast/services/CMakeLists.blast_services.lib.txt new file mode 100644 index 00000000..548a0d29 --- /dev/null +++ b/c++/src/objtools/blast/services/CMakeLists.blast_services.lib.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/blast/services/Makefile.blast_services.lib +# +add_library(blast_services + blast_services +) +add_dependencies(blast_services + xnetblast +) + +target_link_libraries(blast_services + xnetblastcli +) diff --git a/c++/src/objtools/blast/services/CMakeLists.txt b/c++/src/objtools/blast/services/CMakeLists.txt new file mode 100644 index 00000000..07674289 --- /dev/null +++ b/c++/src/objtools/blast/services/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.blast_services.lib.txt) + +# Recurse subdirectories +add_subdirectory(unit_test ) diff --git a/c++/src/objtools/blast/services/unit_test/CMakeLists.blast_services_unit_test.app.txt b/c++/src/objtools/blast/services/unit_test/CMakeLists.blast_services_unit_test.app.txt new file mode 100644 index 00000000..ee0ac8eb --- /dev/null +++ b/c++/src/objtools/blast/services/unit_test/CMakeLists.blast_services_unit_test.app.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/blast/services/unit_test/Makefile.blast_services_unit_test.app +# +add_executable(blast_services_unit_test-app + blast_services_test +) + +set_target_properties(blast_services_unit_test-app PROPERTIES OUTPUT_NAME blast_services_unit_test) + + + +target_link_libraries(blast_services_unit_test-app + blast_services test_boost +) + diff --git a/c++/src/objtools/blast/services/unit_test/CMakeLists.txt b/c++/src/objtools/blast/services/unit_test/CMakeLists.txt new file mode 100644 index 00000000..9f8333e8 --- /dev/null +++ b/c++/src/objtools/blast/services/unit_test/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +include_directories(SYSTEM ${BOOST_INCLUDE}) + +# Include projects from this directory +include(CMakeLists.blast_services_unit_test.app.txt) + diff --git a/c++/src/objtools/blast/services/unit_test/blast_services_test.cpp b/c++/src/objtools/blast/services/unit_test/blast_services_test.cpp index 47a2ce87..6a59cdd1 100644 --- a/c++/src/objtools/blast/services/unit_test/blast_services_test.cpp +++ b/c++/src/objtools/blast/services/unit_test/blast_services_test.cpp @@ -1,4 +1,4 @@ -/* $Id: blast_services_test.cpp 439117 2014-06-25 18:13:50Z camacho $ +/* $Id: blast_services_test.cpp 524212 2017-01-10 17:27:50Z camacho $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE(GetInformationAboutInvalidBlastDatabaseRemotely) BOOST_AUTO_TEST_CASE(MultipleDatabaseValidityCheck) { CBlastServices remote_svc; - bool found = remote_svc.IsValidBlastDb("nt wgs", false); + bool found = remote_svc.IsValidBlastDb("nt pdbnt", false); BOOST_REQUIRE(found == true); } diff --git a/c++/src/objtools/cleanup/CMakeLists.cleanup.lib.txt b/c++/src/objtools/cleanup/CMakeLists.cleanup.lib.txt new file mode 100644 index 00000000..7142a9f1 --- /dev/null +++ b/c++/src/objtools/cleanup/CMakeLists.cleanup.lib.txt @@ -0,0 +1,14 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/cleanup/Makefile.cleanup.lib +# +add_library(xcleanup + autogenerated_cleanup autogenerated_extended_cleanup cleanup + cleanup_utils newcleanupp +) +add_dependencies(xcleanup + submit valid valerr +) + +target_link_libraries(xcleanup + taxon3 valid xobjutil +) diff --git a/c++/src/objtools/cleanup/CMakeLists.txt b/c++/src/objtools/cleanup/CMakeLists.txt new file mode 100644 index 00000000..a21d5c64 --- /dev/null +++ b/c++/src/objtools/cleanup/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.cleanup.lib.txt) + +# Recurse subdirectories +add_subdirectory(test ) diff --git a/c++/src/objtools/cleanup/Makefile.cleanup.lib b/c++/src/objtools/cleanup/Makefile.cleanup.lib index 7a04a5f2..866712cb 100644 --- a/c++/src/objtools/cleanup/Makefile.cleanup.lib +++ b/c++/src/objtools/cleanup/Makefile.cleanup.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.cleanup.lib 515770 2016-10-05 17:31:33Z ivanov $ +# $Id: Makefile.cleanup.lib 531965 2017-03-30 17:12:21Z bollin $ # Build library "xcleanup" ############################### diff --git a/c++/src/objtools/cleanup/autogenerated_cleanup.cpp b/c++/src/objtools/cleanup/autogenerated_cleanup.cpp index 31b83a58..9e25aec0 100644 --- a/c++/src/objtools/cleanup/autogenerated_cleanup.cpp +++ b/c++/src/objtools/cleanup/autogenerated_cleanup.cpp @@ -1,4 +1,4 @@ -/* $Id: autogenerated_cleanup.cpp 518682 2016-11-07 15:44:00Z ivanov $ +/* $Id: autogenerated_cleanup.cpp 533717 2017-04-19 13:06:11Z dobronad $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -3404,6 +3404,7 @@ void CAutogeneratedCleanup::BasicCleanupBioseq( CBioseq & arg0 ) m_LastArg_BasicCleanupBioseq = &arg0; m_NewCleanup.ProtSeqBC( arg0 ); + m_NewCleanup.x_RemoveSingleStrand( arg0 ); if( arg0.IsSetAnnot() ) { x_BasicCleanupBioseq_annot( arg0.SetAnnot() ); } diff --git a/c++/src/objtools/cleanup/autogenerated_cleanup.hpp b/c++/src/objtools/cleanup/autogenerated_cleanup.hpp index 8e615752..2ade0db4 100644 --- a/c++/src/objtools/cleanup/autogenerated_cleanup.hpp +++ b/c++/src/objtools/cleanup/autogenerated_cleanup.hpp @@ -1,7 +1,7 @@ #ifndef AUTOGENERATEDCLEANUP__HPP #define AUTOGENERATEDCLEANUP__HPP -/* $Id: autogenerated_cleanup.hpp 518682 2016-11-07 15:44:00Z ivanov $ +/* $Id: autogenerated_cleanup.hpp 518473 2016-11-03 14:39:39Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/cleanup/autogenerated_cleanup.txt b/c++/src/objtools/cleanup/autogenerated_cleanup.txt index 045ba4d8..6b91d604 100644 --- a/c++/src/objtools/cleanup/autogenerated_cleanup.txt +++ b/c++/src/objtools/cleanup/autogenerated_cleanup.txt @@ -328,6 +328,11 @@ use m_NewCleanup.x_ClearEmptyDescr { POST Bioseq } +#remove single-strandedness from non-viral nucleotide sequences +use m_NewCleanup.x_RemoveSingleStrand { + Bioseq +} + # Call LeavingEntry as late as possible, so keep this as close # as possible to end of file. # (Its partner function is EnteringEntry. See above.) diff --git a/c++/src/objtools/cleanup/autogenerated_extended_cleanup.cpp b/c++/src/objtools/cleanup/autogenerated_extended_cleanup.cpp index adca8554..c4c47d8b 100644 --- a/c++/src/objtools/cleanup/autogenerated_extended_cleanup.cpp +++ b/c++/src/objtools/cleanup/autogenerated_extended_cleanup.cpp @@ -1,4 +1,4 @@ -/* $Id: autogenerated_extended_cleanup.cpp 520823 2016-12-01 18:52:54Z ivanov $ +/* $Id: autogenerated_extended_cleanup.cpp 520267 2016-11-25 15:29:28Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/cleanup/cleanup.cpp b/c++/src/objtools/cleanup/cleanup.cpp index 579f5ac9..9f83e161 100644 --- a/c++/src/objtools/cleanup/cleanup.cpp +++ b/c++/src/objtools/cleanup/cleanup.cpp @@ -1,4 +1,4 @@ -/* $Id: cleanup.cpp 520817 2016-12-01 18:50:34Z ivanov $ +/* $Id: cleanup.cpp 545969 2017-09-12 17:23:55Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -436,6 +436,7 @@ const char* const CCleanupChange::sm_ChangeDesc[eNumberofChangeTypes + 1] = { "Clean Org-ref", "Trim Internal Semicolons", "Add SeqFeatXref", + "Convert Unstructured Org-ref Modifier", // set when any other change is made. "Change Other", @@ -801,7 +802,8 @@ bool CCleanup::RepairXrefs(const CSeq_feat& src, CSeq_feat_Handle& dst, const CT // only create reciprocal xrefs if permitted return false; } - // don't create xref if already have xref to feature of same type as src + // don't create xref if already have xref or if dst not gene and already has + // xref to feature of same type as src bool has_xref = false; if (dst.IsSetXref()) { ITERATE(CSeq_feat::TXref, xit, dst.GetXref()) { @@ -810,7 +812,7 @@ bool CCleanup::RepairXrefs(const CSeq_feat& src, CSeq_feat_Handle& dst, const CT // already have xref has_xref = true; break; - } else { + } else if (!dst.GetData().IsGene()) { const CTSE_Handle::TFeatureId& feat_id = (*xit)->GetId().GetLocal(); CTSE_Handle::TSeq_feat_Handles far_feats = tse.GetFeaturesWithId(CSeqFeatData::e_not_set, feat_id); ITERATE(CTSE_Handle::TSeq_feat_Handles, fit, far_feats) { @@ -1059,6 +1061,10 @@ bool CCleanup::ExtendToStopCodon(CSeq_feat& f, CBioseq_Handle bsh, size_t limit) } size_t stop = loc.GetStop(eExtreme_Biological); + if (stop < 1 || stop > bsh.GetBioseqLength() - 1) { + // no room to extend + return false; + } // figure out if we have a partial codon at the end size_t orig_len = sequence::GetLength(loc, &(bsh.GetScope())); size_t len = orig_len; @@ -1214,6 +1220,29 @@ bool IsTransSpliced(const CSeq_feat& feat) } +bool s_IsLocationEndAtOtherLocationInternalEndpoint(const CSeq_loc& loc, const CSeq_loc& other_loc) +{ + size_t loc_end = loc.GetStop(eExtreme_Biological); + CSeq_loc_CI other_int(other_loc); + while (other_int) { + if (other_int.IsSetStrand() && + other_int.GetStrand() == eNa_strand_minus) { + if (loc.IsSetStrand() && loc.GetStrand() == eNa_strand_minus && + loc_end == other_int.GetRange().GetFrom()) { + return true; + } + } else { + if ((!loc.IsSetStrand() || loc.GetStrand() != eNa_strand_minus) && + loc_end == other_int.GetRange().GetTo()) { + return true; + } + } + ++other_int; + } + return false; +} + + bool CCleanup::ExtendToStopIfShortAndNotPartial(CSeq_feat& f, CBioseq_Handle bsh, bool check_for_stop) { if (!f.GetData().IsCdregion()) { @@ -1226,6 +1255,14 @@ bool CCleanup::ExtendToStopIfShortAndNotPartial(CSeq_feat& f, CBioseq_Handle bsh if (f.GetLocation().IsPartialStop(eExtreme_Biological)) { return false; } + CConstRef mrna = sequence::GetmRNAforCDS(f, bsh.GetScope()); + if (mrna) { + if (mrna->GetLocation().GetStop(eExtreme_Biological) == f.GetLocation().GetStop(eExtreme_Biological)) { + //ok + } else if (s_IsLocationEndAtOtherLocationInternalEndpoint(f.GetLocation(), mrna->GetLocation())) { + return false; + } + } if (check_for_stop) { string translation; @@ -1248,6 +1285,18 @@ bool CCleanup::ExtendToStopIfShortAndNotPartial(CSeq_feat& f, CBioseq_Handle bsh } +bool CCleanup::LocationMayBeExtendedToMatch(const CSeq_loc& orig, const CSeq_loc& improved) +{ + if ((orig.GetStrand() == eNa_strand_minus && + orig.GetStop(eExtreme_Biological) > improved.GetStop(eExtreme_Biological)) || + (orig.GetStrand() != eNa_strand_minus && + orig.GetStop(eExtreme_Biological) < improved.GetStop(eExtreme_Biological))) { + return true; + } + + return false; +} + void CCleanup::SetProteinName(CProt_ref& prot_ref, const string& protein_name, bool append) { if (append && prot_ref.IsSetName() && @@ -1814,7 +1863,7 @@ bool CCleanup::TaxonomyLookup(CSeq_entry_Handle seh) any_changes = true; CSeqdesc* desc = const_cast(*desc_it); desc->SetSource().SetOrg().Assign((*reply_it)->GetData().GetOrg()); - desc->SetSource().SetOrg().ResetSyn(); + desc->SetSource().SetOrg().CleanForGenBank(); } ++reply_it; ++desc_it; @@ -1855,6 +1904,10 @@ CRef AddProtein(const CSeq_feat& cds, CScope& scope) } CRef new_product = CSeqTranslator::TranslateToProtein(cds, scope); + if (new_product.Empty()) { + return CRef(NULL); + } + CRef molinfo(new CSeqdesc()); molinfo->SetMolinfo().SetBiomol(CMolInfo::eBiomol_peptide); molinfo->SetMolinfo().SetTech(CMolInfo::eTech_concept_trans_a); @@ -1987,11 +2040,9 @@ bool CCleanup::SetGeneticCodes(CBioseq_Handle bsh) static SIZE_TYPE s_TitleEndsInOrganism( const string & sTitle, const string & sOrganism, - SIZE_TYPE * out_piOrganellePos) + SIZE_TYPE& OrganellePos) { - if (out_piOrganellePos) { - *out_piOrganellePos = NPOS; - } + OrganellePos = NPOS; SIZE_TYPE answer = NPOS; @@ -2003,15 +2054,15 @@ static SIZE_TYPE s_TitleEndsInOrganism( answer = NPOS; } } else { - answer = NStr::FindNoCase(sTitle, sPattern, 0, NPOS, NStr::eLast); + answer = NStr::Find(sTitle, sPattern, NStr::eNocase, NStr::eReverseSearch); if (answer < 1 || answer == NPOS) { // pattern not found answer = NPOS; } } - // find organelle prefix - if (out_piOrganellePos) { + if (answer != NPOS) { + // find organelle prefix for (unsigned int genome = CBioSource::eGenome_chloroplast; genome <= CBioSource::eGenome_chromatophore; genome++) { @@ -2023,20 +2074,125 @@ static SIZE_TYPE s_TitleEndsInOrganism( genome != CBioSource::eGenome_chromosome) { string organelle = " (" + CBioSource::GetOrganelleByGenome(genome) + ")"; - SIZE_TYPE possible_organelle_start_pos = NStr::Find(sTitle, organelle); + SIZE_TYPE possible_organelle_start_pos = NStr::Find(sTitle, organelle, NStr::eNocase, NStr::eReverseSearch); if (possible_organelle_start_pos != NPOS && NStr::EndsWith(CTempString(sTitle, 0, answer), organelle)) { - *out_piOrganellePos = possible_organelle_start_pos; + OrganellePos = possible_organelle_start_pos; break; } } } } - return answer; } + +static SIZE_TYPE s_TitleEndsInOrganism( + const string & sTitle, + const COrgName::TName& orgname, + SIZE_TYPE &organelle_pos) +{ + SIZE_TYPE suffixPos = NPOS; // will point to " [${organism name}]" at end + organelle_pos = NPOS; + + if (orgname.IsBinomial() && + orgname.GetBinomial().IsSetGenus() && + !NStr::IsBlank(orgname.GetBinomial().GetGenus()) && + orgname.GetBinomial().IsSetSpecies() && + !NStr::IsBlank(orgname.GetBinomial().GetSpecies())) { + string binomial = orgname.GetBinomial().GetGenus() + " " + orgname.GetBinomial().GetSpecies(); + suffixPos = s_TitleEndsInOrganism(sTitle, binomial, organelle_pos); + } + return suffixPos; +} + + +bool IsCrossKingdom(const COrg_ref& org, string& first_kingdom, string& second_kingdom) +{ + bool is_cross_kingdom = false; + first_kingdom = kEmptyStr; + second_kingdom = kEmptyStr; + if (org.IsSetOrgname() && org.GetOrgname().IsSetName() && + org.GetOrgname().GetName().IsPartial() && + org.GetOrgname().GetName().GetPartial().IsSet()) { + ITERATE(CPartialOrgName::Tdata, it, org.GetOrgname().GetName().GetPartial().Get()) { + const CTaxElement& te = **it; + if (te.IsSetFixed_level() && te.GetFixed_level() == 0 && + te.IsSetLevel() && + NStr::EqualNocase(te.GetLevel(), "superkingdom") && + te.IsSetName() && !NStr::IsBlank(te.GetName())) { + if (first_kingdom.empty()) { + first_kingdom = te.GetName(); + } else if (!NStr::EqualNocase(first_kingdom, te.GetName())) { + is_cross_kingdom = true; + second_kingdom = te.GetName(); + break; + } + } + } + } + return is_cross_kingdom; +} + + +bool IsCrossKingdom(const COrg_ref& org) +{ + string first_kingdom, second_kingdom; + return IsCrossKingdom(org, first_kingdom, second_kingdom); +} + + +static SIZE_TYPE s_TitleEndsInOrganism( + const string & sTitle, + const COrg_ref& org, + SIZE_TYPE &organelle_pos) +{ + SIZE_TYPE suffixPos = NPOS; // will point to " [${organism name}]" at end + organelle_pos = NPOS; + + // first, check to see if protein title matches old-name + if (org.IsSetOrgMod()) { + ITERATE(COrgName::TMod, it, org.GetOrgname().GetMod()) { + if ((*it)->IsSetSubtype() && (*it)->IsSetSubname() && + (*it)->GetSubtype() == COrgMod::eSubtype_old_name && + !NStr::IsBlank((*it)->GetSubname())) { + suffixPos = s_TitleEndsInOrganism(sTitle, (*it)->GetSubname(), organelle_pos); + if (suffixPos != NPOS) { + return suffixPos; + } + } + } + } + + // next, check to see if protein title matches taxname + if (org.IsSetTaxname() && !NStr::IsBlank(org.GetTaxname())) { + suffixPos = s_TitleEndsInOrganism(sTitle, org.GetTaxname(), organelle_pos); + if (suffixPos != NPOS) { + return suffixPos; + } + } + + // try binomial if preset + if (org.IsSetOrgname() && org.GetOrgname().IsSetName() && + org.GetOrgname().GetName().IsBinomial()) { + suffixPos = s_TitleEndsInOrganism(sTitle, org.GetOrgname().GetName(), organelle_pos); + if (suffixPos != NPOS) { + return suffixPos; + } + } + + // cross-kingdom? + if (IsCrossKingdom(org)) { + SIZE_TYPE sep = NStr::Find(sTitle, "]["); + if (sep != string::npos) { + suffixPos = s_TitleEndsInOrganism(sTitle.substr(0, sep + 1), org.GetTaxname(), organelle_pos); + } + } + return suffixPos; +} + + static void s_RemoveOrgFromEndOfProtein(CBioseq& seq, string taxname) { @@ -2057,7 +2213,7 @@ static void s_RemoveOrgFromEndOfProtein(CBioseq& seq, string taxname) int len = str.length(); if (len < 5) continue; if (str[len - 1] != ']') continue; - SIZE_TYPE cp = NStr::Find(str, "[", 0, NPOS, NStr::eLast); + SIZE_TYPE cp = NStr::Find(str, "[", NStr::eCase, NStr::eReverseSearch); if (cp == NPOS) continue; string suffix = str.substr(cp + 1); if (NStr::StartsWith(suffix, "NAD")) continue; @@ -2075,16 +2231,13 @@ static void s_RemoveOrgFromEndOfProtein(CBioseq& seq, string taxname) bool CCleanup::AddPartialToProteinTitle(CBioseq &bioseq) { // Bail if not protein - if (!FIELD_CHAIN_OF_2_IS_SET(bioseq, Inst, Mol) || - bioseq.GetInst().GetMol() != NCBI_SEQMOL(aa)) - { + if (!bioseq.IsSetInst() || !bioseq.GetInst().IsSetMol() || !bioseq.GetInst().IsAa()) { return false; } // Bail if record is swissprot FOR_EACH_SEQID_ON_BIOSEQ(seqid_itr, bioseq) { - const CSeq_id& seqid = **seqid_itr; - if (FIELD_IS(seqid, Swissprot)) { + if ((*seqid_itr)->IsSwissprot()) { return false; } } @@ -2092,40 +2245,44 @@ bool CCleanup::AddPartialToProteinTitle(CBioseq &bioseq) // gather some info from the Seqdesc's on the bioseq, into // the following variables bool bPartial = false; - string sTaxname; - string sOldName; - string *psTitle = NULL; string organelle = kEmptyStr; - // iterate for title - EDIT_EACH_SEQDESC_ON_BIOSEQ(descr_iter, bioseq) { - CSeqdesc &descr = **descr_iter; - if (descr.IsTitle()) { - psTitle = &GET_MUTABLE(descr, Title); + CConstRef molinfo_desc(NULL); + CConstRef src_desc(NULL); + FOR_EACH_SEQDESC_ON_BIOSEQ(descr_iter, bioseq) { + if (!molinfo_desc && (*descr_iter)->IsMolinfo()) { + molinfo_desc = *descr_iter; } - } - - // iterate Seqdescs from bottom to top - // accumulate seqdescs into here - typedef vector< CConstRef > TSeqdescVec; - TSeqdescVec vecSeqdesc; - { - FOR_EACH_SEQDESC_ON_BIOSEQ(descr_iter, bioseq) { - vecSeqdesc.push_back(CConstRef(&**descr_iter)); + if (!src_desc && (*descr_iter)->IsSource()) { + src_desc = *descr_iter; + } + if (molinfo_desc && src_desc) { + break; } + } + if (!molinfo_desc || !src_desc) { // climb up to get parent Seqdescs CConstRef bioseq_set(bioseq.GetParentSet()); for (; bioseq_set; bioseq_set = bioseq_set->GetParentSet()) { FOR_EACH_SEQDESC_ON_SEQSET(descr_iter, *bioseq_set) { - vecSeqdesc.push_back(CConstRef(&**descr_iter)); + if (!molinfo_desc && (*descr_iter)->IsMolinfo()) { + molinfo_desc = *descr_iter; + } + if (!src_desc && (*descr_iter)->IsSource()) { + src_desc = *descr_iter; + } + if (molinfo_desc && src_desc) { + break; + } + } + if (molinfo_desc && src_desc) { + break; } } } - ITERATE(TSeqdescVec, descr_iter, vecSeqdesc) { - const CSeqdesc &descr = **descr_iter; - if (descr.IsMolinfo() && FIELD_IS_SET(descr.GetMolinfo(), Completeness)) { - switch (GET_FIELD(descr.GetMolinfo(), Completeness)) { + if (molinfo_desc && molinfo_desc->GetMolinfo().IsSetCompleteness()) { + switch (molinfo_desc->GetMolinfo().GetCompleteness()) { case NCBI_COMPLETENESS(partial): case NCBI_COMPLETENESS(no_left): case NCBI_COMPLETENESS(no_right): @@ -2134,60 +2291,51 @@ bool CCleanup::AddPartialToProteinTitle(CBioseq &bioseq) break; default: break; - } - // stop at first molinfo - break; } } - ITERATE(TSeqdescVec, descr_iter, vecSeqdesc) { - const CSeqdesc &descr = **descr_iter; - if (descr.IsSource()) { - const TBIOSOURCE_GENOME genome = (descr.GetSource().CanGetGenome() ? - descr.GetSource().GetGenome() : - CBioSource::eGenome_unknown); - if (genome >= CBioSource::eGenome_chloroplast && - genome <= CBioSource::eGenome_chromatophore && - genome != CBioSource::eGenome_extrachrom && - genome != CBioSource::eGenome_transposon && - genome != CBioSource::eGenome_insertion_seq && - genome != CBioSource::eGenome_proviral && - genome != CBioSource::eGenome_virion && - genome != CBioSource::eGenome_chromosome) - { - organelle = CBioSource::GetOrganelleByGenome(genome); - } + CConstRef org(NULL); + if (src_desc) { + const TBIOSOURCE_GENOME genome = (src_desc->GetSource().IsSetGenome() ? + src_desc->GetSource().GetGenome() : CBioSource::eGenome_unknown); + if (genome >= CBioSource::eGenome_chloroplast && + genome <= CBioSource::eGenome_chromatophore && + genome != CBioSource::eGenome_extrachrom && + genome != CBioSource::eGenome_transposon && + genome != CBioSource::eGenome_insertion_seq && + genome != CBioSource::eGenome_proviral && + genome != CBioSource::eGenome_virion && + genome != CBioSource::eGenome_chromosome) + { + organelle = CBioSource::GetOrganelleByGenome(genome); + } - if (FIELD_IS_SET(descr.GetSource(), Org)) { - const COrg_ref & org = GET_FIELD(descr.GetSource(), Org); - if (!RAW_FIELD_IS_EMPTY_OR_UNSET(org, Taxname)) { - sTaxname = GET_FIELD(org, Taxname); - } - if (NStr::StartsWith(sTaxname, organelle, NStr::eNocase)) { - organelle = kEmptyStr; - } - FOR_EACH_ORGMOD_ON_ORGREF(mod_iter, org) { - const COrgMod & orgmod = **mod_iter; - if (FIELD_EQUALS(orgmod, Subtype, NCBI_ORGMOD(old_name))) { - sOldName = GET_FIELD(orgmod, Subname); - } - } - } - // stop at first source - break; + if (src_desc->GetSource().IsSetOrg()) { + org.Reset(&(src_desc->GetSource().GetOrg())); } } - s_RemoveOrgFromEndOfProtein(bioseq, sTaxname); - - // bail if no title - if ((NULL == psTitle) || psTitle->empty()) { + if (!org) { return false; } + if (org->IsSetTaxname() && !NStr::IsBlank(org->GetTaxname())) { + s_RemoveOrgFromEndOfProtein(bioseq, org->GetTaxname()); + } - // put title into a reference, - // just because it's more convenient than a pointer - string & sTitle = *psTitle; + // find the title to edit + if (!bioseq.IsSetDescr()) { + return false; + } + CRef title_desc(NULL); + NON_CONST_ITERATE(CBioseq::TDescr::Tdata, d, bioseq.SetDescr().Set()) { + if ((*d)->IsTitle()) { + title_desc = *d; + } + } + if (!title_desc) { + return false; + } + string & sTitle = title_desc->SetTitle(); // remember original so we can see if we changed it const string sOriginalTitle = sTitle; @@ -2199,26 +2347,7 @@ bool CCleanup::AddPartialToProteinTitle(CBioseq &bioseq) // find oldname or taxname in brackets at end of protein title SIZE_TYPE penult = NPOS; - SIZE_TYPE suffixPos = NPOS; // will point to " [${organism name}]" at end - if (!sOldName.empty() && !sTaxname.empty()) { - suffixPos = s_TitleEndsInOrganism(sTitle, sOldName, &penult); - } - if (suffixPos == NPOS && !sTaxname.empty()) { - suffixPos = s_TitleEndsInOrganism(sTitle, sTaxname, &penult); - if (suffixPos != NPOS) { - if (NStr::IsBlank(organelle) && penult != NPOS) { - } else if (!NStr::IsBlank(organelle) && penult == NPOS) { - } else if (penult != NPOS && sTitle.substr(penult) == organelle) { - } else { - // bail if no need to change partial text or [organism name] - if (bPartial && partialPos != NPOS) { - return false; - } else if (!bPartial && partialPos == NPOS){ - return false; - } - } - } - } + SIZE_TYPE suffixPos = s_TitleEndsInOrganism(sTitle, *org, penult); // will point to " [${organism name}]" at end // do not change unless [genus species] was at the end if (suffixPos == NPOS) { return false; @@ -2247,8 +2376,15 @@ bool CCleanup::AddPartialToProteinTitle(CBioseq &bioseq) if (!NStr::IsBlank(organelle)) { sTitle += " (" + string(organelle) + ")"; } - if (!sTaxname.empty()) { - sTitle += " [" + sTaxname + "]"; + string first_kingdom, second_kingdom; + if (IsCrossKingdom(*org, first_kingdom, second_kingdom)) { + sTitle += " [" + first_kingdom + "][" + second_kingdom + "]"; + } else { + sTitle += " ["; + if (org->IsSetTaxname()) { + sTitle += org->GetTaxname(); + } + sTitle += "]"; } if (sTitle != sOriginalTitle) { @@ -2292,6 +2428,38 @@ bool CCleanup::RemovePseudoProduct(CSeq_feat& cds, CScope& scope) } +bool CCleanup::ExpandGeneToIncludeChildren(CSeq_feat& gene, CTSE_Handle& tse) +{ + if (!gene.IsSetXref() || !gene.IsSetLocation() || !gene.GetLocation().IsInt()) { + return false; + } + bool any_change = false; + TSeqPos gene_start = gene.GetLocation().GetStart(eExtreme_Positional); + TSeqPos gene_stop = gene.GetLocation().GetStop(eExtreme_Positional); + ITERATE(CSeq_feat::TXref, xit, gene.GetXref()) { + if ((*xit)->IsSetId() && (*xit)->GetId().IsLocal()) { + const CTSE_Handle::TFeatureId& feat_id = (*xit)->GetId().GetLocal(); + CTSE_Handle::TSeq_feat_Handles far_feats = tse.GetFeaturesWithId(CSeqFeatData::eSubtype_any, feat_id); + ITERATE(CTSE_Handle::TSeq_feat_Handles, f, far_feats) { + TSeqPos f_start = f->GetLocation().GetStart(eExtreme_Positional); + TSeqPos f_stop = f->GetLocation().GetStop(eExtreme_Positional); + if (f_start < gene_start) { + gene.SetLocation().SetInt().SetFrom(f_start); + gene_start = f_start; + any_change = true; + } + if (f_stop > gene_stop) { + gene.SetLocation().SetInt().SetTo(f_stop); + gene_stop = f_stop; + any_change = true; + } + } + } + } + return any_change; +} + + bool CCleanup::WGSCleanup(CSeq_entry_Handle entry) { bool any_changes = false; @@ -2332,7 +2500,7 @@ bool CCleanup::WGSCleanup(CSeq_entry_Handle entry) //prefer ncbieaa if (new_cds->IsSetProduct()) { CBioseq_Handle p = entry.GetScope().GetBioseqHandle(new_cds->GetProduct()); - if (p.GetInst().IsSetSeq_data() && p.GetInst().GetSeq_data().IsIupacaa()) { + if (p && p.IsSetInst() && p.GetInst().IsSetSeq_data() && p.GetInst().GetSeq_data().IsIupacaa()) { CBioseq_EditHandle peh(p); string current = p.GetInst().GetSeq_data().GetIupacaa().Get(); CRef new_inst(new CSeq_inst()); @@ -2386,12 +2554,16 @@ bool CCleanup::WGSCleanup(CSeq_entry_Handle entry) } + CTSE_Handle tse = entry.GetTSE_Handle(); + for (CFeat_CI gene_it(entry, SAnnotSelector(CSeqFeatData::e_Gene)); gene_it; ++gene_it) { bool change_this_gene; CRef new_gene(new CSeq_feat()); new_gene->Assign(*(gene_it->GetSeq_feat())); - change_this_gene = SetGenePartialByLongestContainedFeature(*new_gene, entry.GetScope()); + change_this_gene = ExpandGeneToIncludeChildren(*new_gene, tse); + + change_this_gene |= SetGenePartialByLongestContainedFeature(*new_gene, entry.GetScope()); if (change_this_gene) { CSeq_feat_EditHandle gene_h(*gene_it); @@ -2413,6 +2585,104 @@ bool CCleanup::WGSCleanup(CSeq_entry_Handle entry) return any_changes; } + +bool CCleanup::x_HasShortIntron(const CSeq_loc& loc, size_t min_len) +{ + CSeq_loc_CI li(loc); + while (li && li.IsEmpty()) { + ++li; + } + if (!li) { + return false; + } + while (li) { + TSeqPos prev_end; + ENa_strand prev_strand; + if (li.IsSetStrand() && li.GetStrand() == eNa_strand_minus) { + prev_end = li.GetRange().GetFrom(); + prev_strand = eNa_strand_minus; + } else { + prev_end = li.GetRange().GetTo(); + prev_strand = eNa_strand_plus; + } + ++li; + while (li && li.IsEmpty()) { + ++li; + } + if (li) { + TSeqPos this_start; + ENa_strand this_strand; + if (li.IsSetStrand() && li.GetStrand() == eNa_strand_minus) { + this_start = li.GetRange().GetTo(); + this_strand = eNa_strand_minus; + } else { + this_start = li.GetRange().GetFrom(); + this_strand = eNa_strand_plus; + } + if (this_strand == prev_strand) { + if (abs((long int)this_start - (long int)prev_end) < min_len) { + return true; + } + } + } + } + return false; +} + + +const string kLowQualitySequence = "low-quality sequence region"; + +bool CCleanup::x_AddLowQualityException(CSeq_feat& feat) +{ + bool any_change = false; + if (!feat.IsSetExcept()) { + any_change = true; + feat.SetExcept(true); + } + if (!feat.IsSetExcept_text() || NStr::IsBlank(feat.GetExcept_text())) { + feat.SetExcept_text(kLowQualitySequence); + any_change = true; + } else if (NStr::Find(feat.GetExcept_text(), kLowQualitySequence) == string::npos) { + feat.SetExcept_text(feat.GetExcept_text() + "; " + kLowQualitySequence); + any_change = true; + } + return any_change; +} + + +bool CCleanup::x_AddLowQualityException(CSeq_entry_Handle entry, CSeqFeatData::ESubtype subtype) +{ + bool any_changes = false; + + SAnnotSelector sel(subtype); + for (CFeat_CI cds_it(entry, sel); cds_it; ++cds_it) { + bool change_this_cds = false; + CRef new_cds(new CSeq_feat()); + new_cds->Assign(*(cds_it->GetSeq_feat())); + if (!sequence::IsPseudo(*(cds_it->GetSeq_feat()), entry.GetScope()) && + x_HasShortIntron(cds_it->GetLocation())) { + change_this_cds = x_AddLowQualityException(*new_cds); + } + + if (change_this_cds) { + CSeq_feat_EditHandle cds_h(*cds_it); + + cds_h.Replace(*new_cds); + any_changes = true; + } + } + return any_changes; +} + + +bool CCleanup::AddLowQualityException(CSeq_entry_Handle entry) +{ + bool any_changes = x_AddLowQualityException(entry, CSeqFeatData::eSubtype_cdregion); + any_changes |= x_AddLowQualityException(entry, CSeqFeatData::eSubtype_mRNA); + return any_changes; +} + + // maps the type of seqdesc to the order it should be in // (lowest to highest) typedef SStaticPair TSeqdescOrderElem; @@ -2990,8 +3260,18 @@ bool CCleanup::RescueSiteRefPubs(CSeq_entry_Handle seh) } } if (is_site_ref) { + CSeq_feat_EditHandle feh(*p); + CSeq_annot_Handle annot = feh.GetAnnot(); + feh.Remove(); + + // remove old annot if now empty + if (CNewCleanup_imp::ShouldRemoveAnnot(*(annot.GetCompleteSeq_annot()))) { + CSeq_annot_EditHandle annot_edit(annot); + annot_edit.Remove(); + } + } any_change = true; } @@ -3707,19 +3987,20 @@ CRef CCleanup::GetProteinLocationFromNucleotideLocation(const CSeq_loc new_loc = tmp; } - if (!cds.GetLocation().IsPartialStart(eExtreme_Biological)) { + // fix partials if protein feature starts or ends at beginning or end of protein sequence + if (!cds.GetLocation().IsPartialStart(eExtreme_Biological) && + new_loc->GetStart(eExtreme_Biological) == 0) { if (new_loc->IsPartialStart(eExtreme_Biological)) { new_loc->SetPartialStart(false, eExtreme_Biological); } } - if (!cds.GetLocation().IsPartialStop(eExtreme_Biological)) { + if (!cds.GetLocation().IsPartialStop(eExtreme_Biological) && + new_loc->GetStop(eExtreme_Biological) == prot.GetBioseqLength() - 1) { if (new_loc->IsPartialStop(eExtreme_Biological)) { new_loc->SetPartialStop(false, eExtreme_Biological); } } - - return new_loc; } @@ -3800,5 +4081,458 @@ bool CCleanup::ConvertDeltaSeqToRaw(CSeq_entry_Handle seh, CSeq_inst::EMol filte return any_change; } + +bool CCleanup::ParseCodeBreak(const CSeq_feat& feat, CCdregion& cds, const string& str, CScope& scope) +{ + if (str.empty() || !feat.IsSetLocation()) { + return false; + } + + const CSeq_id* feat_loc_seq_id = feat.GetLocation().GetId(); + if (!feat_loc_seq_id) { + return false; + } + + string::size_type aa_pos = NStr::Find(str, "aa:"); + string::size_type len = 0; + string::size_type loc_pos, end_pos; + char protein_letter = 'X'; + CRef break_loc; + + if (aa_pos == string::npos) { + aa_pos = NStr::Find(str, ","); + if (aa_pos != string::npos) { + aa_pos = NStr::Find(str, ":", aa_pos); + } + if (aa_pos != string::npos) { + aa_pos++; + } + } else { + aa_pos += 3; + } + + if (aa_pos != string::npos) { + while (aa_pos < str.length() && isspace(str[aa_pos])) { + aa_pos++; + } + while (aa_pos + len < str.length() && isalpha(str[aa_pos + len])) { + len++; + } + if (len != 0) { + protein_letter = ValidAminoAcid(str.substr(aa_pos, len)); + } + } + + loc_pos = NStr::Find(str, "(pos:"); + if (loc_pos == string::npos) { + return false; + } + loc_pos += 5; + while (loc_pos < str.length() && isspace(str[loc_pos])) { + loc_pos++; + } + + end_pos = NStr::Find(str, ",aa:", loc_pos); + if (end_pos == NPOS) { + end_pos = NStr::Find(str, ",", loc_pos); + if (end_pos == NPOS) { + end_pos = str.length(); + } + } + + string pos = NStr::TruncateSpaces(str.substr(loc_pos, end_pos - loc_pos)); + + // handle multi-interval positions by adding a join() around them + if (pos.find_first_of(",") != string::npos) { + pos = "join(" + pos + ")"; + } + + break_loc = ReadLocFromText(pos, feat_loc_seq_id, &scope); + if (FIELD_IS_SET(feat.GetLocation(), Strand) && GET_FIELD(feat.GetLocation(), Strand) == eNa_strand_minus) { + break_loc->SetStrand(GET_FIELD(feat.GetLocation(), Strand)); + } else { + RESET_FIELD(*break_loc, Strand); + } + + if (break_loc == NULL + || (break_loc->IsInt() + && sequence::Compare(*break_loc, feat.GetLocation(), &scope, sequence::fCompareOverlapping) != sequence::eContained) + || (break_loc->IsInt() && sequence::GetLength(*break_loc, &scope) > 3)) { + return false; + } + + // need to build code break object and add it to coding region + CRef newCodeBreak(new CCode_break()); + CCode_break::TAa& aa = newCodeBreak->SetAa(); + aa.SetNcbieaa(protein_letter); + newCodeBreak->SetLoc(*break_loc); + + CCdregion::TCode_break& orig_list = cds.SetCode_break(); + orig_list.push_back(newCodeBreak); + + return true; +} + + +bool CCleanup::ParseCodeBreaks(CSeq_feat& feat, CScope& scope) +{ + if (!feat.IsSetData() || !feat.GetData().IsCdregion() || + !feat.IsSetQual() || !feat.IsSetLocation()) { + return false; + } + + bool any_removed = false; + CSeq_feat::TQual::iterator it = feat.SetQual().begin(); + while (it != feat.SetQual().end()) { + if ((*it)->IsSetQual() && + NStr::EqualNocase((*it)->GetQual(), "transl_except") && + (*it)->IsSetVal() && + ParseCodeBreak(feat, feat.SetData().SetCdregion(), (*it)->GetVal(), scope)) { + it = feat.SetQual().erase(it); + any_removed = true; + } else { + ++it; + } + } + if (feat.GetQual().size() == 0) { + feat.ResetQual(); + } + return any_removed; +} + + +// From SQD-4297 +// Influenza is a multi-segmented virus. We would like to create +// small-genome sets when all segments of a particular viral strain +// are submitted together. This is made more difficult due to fact +// that submitters often have large submissions with multiple strains +// at one time. +// This function will segregate sequences with the same taxname +// plus additional qualifiers into small-genome sets, if there are enough +// sequences for that type of Influenza *AND* all CDS and gene features +// on the sequences are complete. +// * Influenza A virus: 8 or more nucleotide sequences with same strain and serotype +// * Influenza B virus: 8 or more nucleotide sequences with same strain +// * Influenza C virus: 7 or more nucleotide sequences with same strain +// * Influenza D virus: 7 or more records with same strain +// Note that as long as we are making strain-specific organism names, +// the taxname must only start with the Influenza designation, not match it. +// Can only make a set if at least one instance of each segment value is represented. +class CInfluenzaSet : public CObject { +public: + CInfluenzaSet(const string& key); + ~CInfluenzaSet() {} + + static string GetKey(const COrg_ref& org); + bool OkToMakeSet() const; + void MakeSet(); + + typedef enum { + eNotInfluenza = 0, + eInfluenzaA, + eInfluenzaB, + eInfluenzaC, + eInfluenzaD + } EInfluenzaType; + + static EInfluenzaType GetInfluenzaType(const string& taxname); + + void AddBioseq(CBioseq_Handle bsh); + +protected: + typedef vector TMembers; + TMembers m_Members; + const string m_Key; + EInfluenzaType m_FluType; + size_t m_Required; +}; + + +CInfluenzaSet::CInfluenzaSet(const string& key) : m_Key(key) +{ + m_FluType = GetInfluenzaType(key); + m_Required = 7; + if (m_FluType == eInfluenzaA || m_FluType == eInfluenzaB) { + m_Required = 8; + } +} + + +CInfluenzaSet::EInfluenzaType CInfluenzaSet::GetInfluenzaType(const string& taxname) +{ + if (NStr::StartsWith(taxname, "Influenza A virus", NStr::eNocase)) { + return eInfluenzaA; + } else if (NStr::StartsWith(taxname, "Influenza B virus", NStr::eNocase)) { + return eInfluenzaB; + } else if (NStr::StartsWith(taxname, "Influenza C virus", NStr::eNocase)) { + return eInfluenzaC; + } else if (NStr::StartsWith(taxname, "Influenza D virus", NStr::eNocase)) { + return eInfluenzaD; + } else { + return eNotInfluenza; + } +} + + +string CInfluenzaSet::GetKey(const COrg_ref& org) +{ + if (!org.IsSetTaxname() || !org.IsSetOrgname() || !org.GetOrgname().IsSetMod()) { + return kEmptyStr; + } + EInfluenzaType flu_type = GetInfluenzaType(org.GetTaxname()); + if (flu_type == eNotInfluenza) { + return kEmptyStr; + } + + CTempString strain = kEmptyStr; + CTempString serotype = kEmptyStr; + + ITERATE(COrgName::TMod, it, org.GetOrgname().GetMod()) { + if ((*it)->IsSetSubtype() && (*it)->IsSetSubname()) { + if ((*it)->GetSubtype() == COrgMod::eSubtype_strain) { + strain = (*it)->GetSubname(); + } else if ((*it)->GetSubtype() == COrgMod::eSubtype_serotype && + flu_type == eInfluenzaA) { + serotype = (*it)->GetSubname(); + } + } + } + if(NStr::IsBlank(strain)) { + return kEmptyStr; + } + if (flu_type == eInfluenzaA) { + if (NStr::IsBlank(serotype)) { + return kEmptyStr; + } else { + return org.GetTaxname() + ":" + strain + ":" + serotype; + } + } else { + return org.GetTaxname() + ":" + strain; + } +} + + +void CInfluenzaSet::AddBioseq(CBioseq_Handle bsh) +{ + m_Members.push_back(bsh); +} + + +bool CInfluenzaSet::OkToMakeSet() const +{ + if (m_Members.size() < m_Required) { + return false; + } + + bool ok = true; + bool* seg_found = new bool[m_Required]; + for (size_t i = 0; i < m_Required; i++) { + seg_found[i] = false; + } + + ITERATE(TMembers, it, m_Members) { + // check to make sure one of each segment is represented + CSeqdesc_CI src(*it, CSeqdesc::e_Source); + if (src->GetSource().IsSetSubtype()) { + bool found_seg = false; + ITERATE(CBioSource::TSubtype, s, src->GetSource().GetSubtype()) { + if ((*s)->IsSetSubtype() && (*s)->IsSetName() && + (*s)->GetSubtype() == CSubSource::eSubtype_segment) { + try { + size_t seg = NStr::StringToSizet((*s)->GetName()); + if (seg < 1 || seg > m_Required) { + ok = false; + break; + } + seg_found[seg - 1] = true; + found_seg = true; + } catch (CException& ex) { + ok = false; + break; + } + } + } + if (!found_seg) { + ok = false; + } + } else { + ok = false; + } + if (!ok) { + break; + } + + // make sure all coding regions and genes are complete + SAnnotSelector sel; + sel.IncludeFeatType(CSeqFeatData::e_Cdregion); + sel.IncludeFeatType(CSeqFeatData::e_Gene); + CFeat_CI f(*it, sel); + while (f) { + if (f->GetLocation().IsPartialStart(eExtreme_Biological) || + f->GetLocation().IsPartialStop(eExtreme_Biological)) { + ok = false; + break; + } + ++f; + } + if (!ok) break; + } + + if (ok) { + for (size_t i = 0; i < m_Required; i++) { + if (!seg_found[i]) { + ok = false; + break; + } + } + } + delete[] seg_found; + + return ok; +} + + +void CInfluenzaSet::MakeSet() +{ + if (m_Members.size() == 0) { + return; + } + CBioseq_set_Handle parent = m_Members[0].GetParentBioseq_set(); + if (!parent) { + return; + } + if (parent.IsSetClass() && parent.GetClass() == CBioseq_set::eClass_nuc_prot) { + parent = parent.GetParentBioseq_set(); + } + if (!parent) { + return; + } + CSeq_entry_Handle peh = parent.GetParentEntry(); + CSeq_entry_EditHandle peeh(peh); + CBioseq_set_EditHandle parent_edit(parent); + CRef ns(new CSeq_entry()); + ns->SetSet().SetClass(CBioseq_set::eClass_small_genome_set); + CSeq_entry_EditHandle new_set = parent_edit.AttachEntry(*ns, -1); + ITERATE(TMembers, it, m_Members) { + CBioseq_set_Handle np = it->GetParentBioseq_set(); + if (np && np.IsSetClass() && np.GetClass() == CBioseq_set::eClass_nuc_prot) { + CSeq_entry_Handle nps = np.GetParentEntry(); + CSeq_entry_EditHandle npse(nps); + npse.Remove(); + new_set.AttachEntry(npse); + } else { + CSeq_entry_Handle s = it->GetParentEntry(); + CSeq_entry_EditHandle se(s); + se.Remove(); + new_set.AttachEntry(se); + } + } +} + + +typedef map > TInfluenzaSetMap; + +size_t CCleanup::MakeSmallGenomeSet(CSeq_entry_Handle entry) +{ + TInfluenzaSetMap flu_map; + + CBioseq_CI bi(entry, CSeq_inst::eMol_na); + while (bi) { + CSeqdesc_CI src(*bi, CSeqdesc::e_Source); + if (src && src->GetSource().IsSetOrg()) { + string key = CInfluenzaSet::GetKey(src->GetSource().GetOrg()); + if (!NStr::IsBlank(key)) { + // add to set + TInfluenzaSetMap::iterator it = flu_map.find(key); + if (it == flu_map.end()) { + CRef new_set(new CInfluenzaSet(key)); + new_set->AddBioseq(*bi); + flu_map[key] = new_set; + } else { + it->second->AddBioseq(*bi); + } + } + } + ++bi; + } + // now create sets + size_t added = 0; + NON_CONST_ITERATE(TInfluenzaSetMap, it, flu_map) { + if (it->second->OkToMakeSet()) { + it->second->MakeSet(); + added++; + } + } + + return added; +} + + +void AddIRDMiscFeature(CBioseq_Handle bh, const CDbtag& tag) +{ + CSeq_annot_Handle ftable; + + CSeq_annot_CI annot_ci(bh); + for (; annot_ci; ++annot_ci) { + if ((*annot_ci).IsFtable()) { + ftable = *annot_ci; + break; + } + } + + if (!ftable) { + CBioseq_EditHandle beh = bh.GetEditHandle(); + CRef new_annot(new CSeq_annot()); + ftable = beh.AttachAnnot(*new_annot); + } + + CSeq_annot_EditHandle aeh(ftable); + + CRef f(new CSeq_feat()); + f->SetData().SetImp().SetKey("misc_feature"); + f->SetLocation().SetInt().SetFrom(0); + f->SetLocation().SetInt().SetTo(bh.GetBioseqLength() - 1); + f->SetLocation().SetInt().SetId().Assign(*(bh.GetSeqId())); + CRef xref(new CDbtag()); + xref->Assign(tag); + f->SetDbxref().push_back(xref); + CRef suppress(new CSeqFeatXref()); + suppress->SetData().SetGene(); + f->SetXref().push_back(suppress); + aeh.AddFeat(*f); +} + + +bool CCleanup::MakeIRDFeatsFromSourceXrefs(CSeq_entry_Handle entry) +{ + bool any = false; + CBioseq_CI bi(entry, CSeq_inst::eMol_na); + while (bi) { + CSeqdesc_CI src(*bi, CSeqdesc::e_Source); + while (src) { + if (src->GetSource().IsSetOrg() && src->GetSource().GetOrg().IsSetDb()) { + CRef org(const_cast(&(src->GetSource().GetOrg()))); + COrg_ref::TDb::iterator db = org->SetDb().begin(); + while (db != org->SetDb().end()) { + if ((*db)->IsSetDb() && NStr::Equal((*db)->GetDb(), "IRD")) { + AddIRDMiscFeature(*bi, **db); + db = org->SetDb().erase(db); + any = true; + } else { + ++db; + } + } + if (org->GetDb().size() == 0) { + org->ResetDb(); + } + } + ++src; + } + ++bi; + } + return any; +} + + END_SCOPE(objects) END_NCBI_SCOPE diff --git a/c++/src/objtools/cleanup/cleanup_utils.cpp b/c++/src/objtools/cleanup/cleanup_utils.cpp index ea0f23c0..19d3619e 100644 --- a/c++/src/objtools/cleanup/cleanup_utils.cpp +++ b/c++/src/objtools/cleanup/cleanup_utils.cpp @@ -1,4 +1,4 @@ -/* $Id: cleanup_utils.cpp 518092 2016-10-31 17:33:59Z ivanov $ +/* $Id: cleanup_utils.cpp 535438 2017-05-08 19:09:23Z kachalos $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -125,7 +125,7 @@ void s_SplitMLAuthorName(string name, string& last, string& initials, string& su } vector parts; - NStr::Split( name, " ", parts, NStr::eMergeDelims ); + NStr::Split( name, " ", parts, NStr::fSplit_Tokenize ); if ( parts.empty() ) { return; } diff --git a/c++/src/objtools/cleanup/newcleanupp.cpp b/c++/src/objtools/cleanup/newcleanupp.cpp index 065bb296..5ec3d5ae 100644 --- a/c++/src/objtools/cleanup/newcleanupp.cpp +++ b/c++/src/objtools/cleanup/newcleanupp.cpp @@ -252,7 +252,7 @@ void CNewCleanup_imp::BasicCleanupSeqAnnot ( x_PostProcessing(); } -void CNewCleanup_imp::BasicCleanupBioseq ( +void CNewCleanup_imp::BasicCleanupBioseq( CBioseq& bs ) @@ -1099,7 +1099,7 @@ void CNewCleanup_imp::GBblockBC ( CGB_block::TKeywords::iterator it = gbk.SetKeywords().begin(); while (it != gbk.SetKeywords().end()) { vector tokens; - NStr::Split(*it, ";", tokens); + NStr::Split(*it, ";", tokens, NStr::fSplit_Tokenize); if (tokens.size() > 1) { it = gbk.SetKeywords().erase(it); gbk.SetKeywords().insert(it, tokens.begin(), tokens.end()); @@ -1857,6 +1857,7 @@ void CNewCleanup_imp::x_ConvertOrgref_modToSubSource( CBioSource& biosrc ) ADD_SUBSOURCE_TO_BIOSOURCE (biosrc, sbs); ERASE_MOD_ON_ORGREF (it, org); ChangeMade (CCleanupChange::eChangeSubsource); + ChangeMade(CCleanupChange::eConvertUnstructuredOrgrefModifier); } if( MOD_ON_ORGREF_IS_EMPTY(org) ) { @@ -1903,6 +1904,7 @@ void CNewCleanup_imp::x_ConvertOrgref_modToOrgMod(COrg_ref& org) ADD_ORGMOD_TO_ORGREF(org, omd); ERASE_MOD_ON_ORGREF(it, org); ChangeMade(CCleanupChange::eChangeOrgmod); + ChangeMade(CCleanupChange::eConvertUnstructuredOrgrefModifier); } if (RAW_FIELD_IS_EMPTY(org, Mod)) { RESET_FIELD(org, Mod); @@ -1944,9 +1946,7 @@ void CNewCleanup_imp::OrgrefModBC (string& str) } } -void CNewCleanup_imp::OrgrefBC ( - COrg_ref& org -) +void CNewCleanup_imp::OrgrefBC (COrg_ref& org) { CLEAN_STRING_MEMBER (org, Taxname); @@ -2224,11 +2224,13 @@ void CNewCleanup_imp::DbtagBC ( } if (NStr::EqualNocase(db, "Swiss-Prot") - || NStr::EqualNocase (db, "SWISSPROT")) { + || NStr::EqualNocase (db, "SWISSPROT") + || NStr::EqualNocase (db, "UniProt/Swiss-Prot")) { db = "UniProtKB/Swiss-Prot"; ChangeMade(CCleanupChange::eChangeDbxrefs); } else if (NStr::EqualNocase(db, "SPTREMBL") || - NStr::EqualNocase(db, "TrEMBL") ) { + NStr::EqualNocase(db, "TrEMBL") || + NStr::EqualNocase(db, "UniProt/TrEMBL") ) { db = "UniProtKB/TrEMBL"; ChangeMade(CCleanupChange::eChangeDbxrefs); } else if (NStr::EqualNocase(db, "SUBTILIS")) { @@ -3032,7 +3034,7 @@ void CNewCleanup_imp::PubSetBC( CPub_set &pub_set ) TCitSet cit_set; ITERATE (CPub_set::TPub, cit_it, pub_set.GetPub()) { string label; - (*cit_it)->GetLabel(&label, CPub::eContent, false); + (*cit_it)->GetLabel(&label, CPub::eContent, CPub::fLabel_Unique, CPub::eLabel_V1 ); // the following line may fail due to dups // (that's okay; it lets us automatically remove dups) cit_set.insert( TCit(label, *cit_it) ); @@ -3061,22 +3063,14 @@ void CNewCleanup_imp::ImpFeatBC( CSeq_feat& feat ) CLEAN_STRING_MEMBER_JUNK(imf, Key); CLEAN_STRING_MEMBER(imf, Loc); CLEAN_STRING_MEMBER(imf, Descr); + + if (imf.IsSetKey() && CSeqFeatData::FixImportKey(imf.SetKey())) { + ChangeMade(CCleanupChange::eChangeKeywords); + } if ( FIELD_IS_SET(imf, Key) ) { const CImp_feat::TKey& key = GET_FIELD(imf, Key); - if (key == "allele" || key == "mutation") { - SET_FIELD(imf, Key, "variation"); - ChangeMade(CCleanupChange::eChangeKeywords); - } else if ( key == "Import" || key == "virion" ) { - SET_FIELD(imf, Key, "misc_feature"); - ChangeMade(CCleanupChange::eChangeKeywords); - } else if ( key == "repeat_unit" ) { - SET_FIELD(imf, Key, "repeat_region"); - ChangeMade(CCleanupChange::eChangeKeywords); - } else if ( key == "misc_bind" ) { - SET_FIELD(imf, Key, "misc_binding"); - ChangeMade(CCleanupChange::eChangeKeywords); - } else if ( key == "satellite" && ! m_IsEmblOrDdbj ) { + if ( key == "satellite" && ! m_IsEmblOrDdbj ) { SET_FIELD(imf, Key, "repeat_region"); ChangeMade(CCleanupChange::eChangeKeywords); @@ -3579,7 +3573,21 @@ void CNewCleanup_imp::GBQualBC ( if (CGb_qual::CleanupReplace(gbq.SetVal())) { ChangeMade(CCleanupChange::eChangeQualifiers); } - } + } else if (NStr::EqualNocase(gbq.GetQual(), "repeat_type")) { + if (CGb_qual::FixRptTypeValue(gbq.SetVal())) { + ChangeMade(CCleanupChange::eChangeQualifiers); + } + } else if (NStr::EqualNocase(gbq.GetQual(), "regulatory_class")) { + if (CSeqFeatData::FixRegulatoryClassValue(gbq.SetVal())) { + ChangeMade(CCleanupChange::eChangeQualifiers); + } + } else if (NStr::EqualNocase(gbq.GetQual(), "pseudogene")) { + if (CGb_qual::FixPseudogeneValue(gbq.SetVal())) { + ChangeMade(CCleanupChange::eChangeQualifiers); + } + } + + x_ChangeTransposonToMobileElement(gbq); x_ChangeInsertionSeqToMobileElement(gbq); @@ -3587,6 +3595,11 @@ void CNewCleanup_imp::GBQualBC ( SET_FIELD( gbq, Qual, "mobile_element_type" ); ChangeMade(CCleanupChange::eChangeQualifiers); } + if (NStr::EqualNocase(gbq.GetQual(), "mobile_element_type") && + gbq.IsSetVal() && + CGb_qual::FixMobileElementValue(gbq.SetVal())) { + ChangeMade(CCleanupChange::eChangeQualifiers); + } } static @@ -3937,6 +3950,12 @@ CNewCleanup_imp::EAction CNewCleanup_imp::GBQualSeqFeatBC(CGb_qual& gb_qual, CSe ChangeMade(CCleanupChange::eCleanQualifiers); } } + else if (NStr::EqualNocase(qual, "recombination_class")) { + if (CGb_qual::FixRecombinationClassValue(val)) { + ChangeMade(CCleanupChange::eCleanQualifiers); + } + } + if( NStr::EqualNocase( qual, "mobile_element_type" ) ) { // trim spaces around first colon but only if there are no colons @@ -4188,7 +4207,7 @@ void s_ExpandThisQual( // vector< string > newValues; string valueList = val.substr(1, val.length() - 2); - NStr::Split(valueList, ",", newValues); + NStr::Split(valueList, ",", newValues, NStr::fSplit_Tokenize); qual.SetVal( newValues[0] ); @@ -4294,7 +4313,8 @@ CNewCleanup_imp::x_SeqFeatCDSGBQualBC(CSeq_feat& feat, CCdregion& cds, const CGb // transl_except qual -> Cdregion.code_break if (NStr::EqualNocase(qual, "transl_except")) { - return x_ParseCodeBreak(feat, cds, val); + // could not be parsed earlier + return eAction_Nothing; } // codon_start qual -> Cdregion.frame @@ -4443,7 +4463,8 @@ static const TTrnaKey trna_key_to_subtype [] = { { "Asp or Asn", 'B' }, { "Asparagine", 'N' }, { "Aspartate", 'D' }, - { "Aspartic Acid", 'D' }, + { "Aspartic", 'D' }, + { "Aspartic Acid", 'D' }, { "Asx", 'B' }, { "Cys", 'C' }, { "Cysteine", 'C' }, @@ -4452,6 +4473,7 @@ static const TTrnaKey trna_key_to_subtype [] = { { "Glu", 'E' }, { "Glu or Gln", 'Z' }, { "Glutamate", 'E' }, + { "Glutamic", 'E' }, { "Glutamic Acid", 'E' }, { "Glutamine", 'Q' }, { "Glx", 'Z' }, @@ -4749,9 +4771,6 @@ CNewCleanup_imp::x_HandleTrnaProductGBQual(CSeq_feat& feat, CRNA_ref& rna, const const bool is_iMet = (NStr::Find(name, "iMet") != NPOS); CRNA_ref_Base::C_Ext::TTRNA &trp = rna.SetExt().SetTRNA(); trp.SetAa().SetNcbieaa(aa); - if (justTrnaText) { - copy(codon.begin(), codon.end(), back_inserter(trp.SetCodon())); - } if (aa == 'M') { if (is_fMet) { x_AddToComment(feat, "fMet"); @@ -4773,20 +4792,21 @@ CNewCleanup_imp::x_HandleTrnaProductGBQual(CSeq_feat& feat, CRNA_ref& rna, const CRNA_ref_Base::C_Ext::TTRNA& trna = rna.SetExt().SetTRNA(); trna.SetAa().SetNcbieaa(aa); - if (justTrnaText) { - copy(codon.begin(), codon.end(), back_inserter(trna.SetCodon())); - } - else { + if (!justTrnaText || !NStr::IsBlank(codon)) { x_AddToComment(feat, product); } if (aa == 'M') { if (NStr::Find(product, "fMet") != NPOS && (!feat.IsSetComment() || NStr::Find(feat.GetComment(), "fMet") == NPOS)) { - x_AddToComment(feat, "fMet"); + // x_AddToComment(feat, "fMet"); + ChangeMade(CCleanupChange::eChangeRNAref); + return eAction_Nothing; } else if (NStr::Find(product, "iMet") != NPOS && (!feat.IsSetComment() || NStr::Find(feat.GetComment(), "iMet") == NPOS)) { - x_AddToComment(feat, "iMet"); + // x_AddToComment(feat, "iMet"); + ChangeMade(CCleanupChange::eChangeRNAref); + return eAction_Nothing; } } @@ -4804,8 +4824,8 @@ CNewCleanup_imp::x_HandleTrnaProductGBQual(CSeq_feat& feat, CRNA_ref& rna, const if (trp.GetAa().GetNcbieaa() == s_ParseSeqFeatTRnaString(product, NULL, ignored, false) && NStr::IsBlank(ignored)) { } else { + // don't remove product qual because it conflicts with existing aa value return eAction_Nothing; -// x_AddToComment(feat, product); } if (NStr::CompareNocase (product, "tRNA-fMet") == 0 || NStr::CompareNocase (product, "iRNA-fMet") == 0) { return eAction_Nothing; @@ -4814,6 +4834,23 @@ CNewCleanup_imp::x_HandleTrnaProductGBQual(CSeq_feat& feat, CRNA_ref& rna, const return eAction_Nothing; } return eAction_Erase; + } else if (!trp.IsSetAa()) { + string ignored = kEmptyStr; + bool justTrnaText = false; + char aa = s_ParseSeqFeatTRnaString(product, &justTrnaText, ignored, false); + if (aa != '\0') { + trp.SetAa().SetNcbieaa(aa); + if (!justTrnaText || !NStr::IsBlank(ignored)) { + x_AddToComment(feat, product); + } + if (NStr::CompareNocase(product, "tRNA-fMet") == 0 || + NStr::CompareNocase(product, "iRNA-fMet") == 0 || + NStr::CompareNocase(product, "tRNA-iMet") == 0 || + NStr::CompareNocase(product, "iRNA-iMet") == 0) { + return eAction_Nothing; + } + return eAction_Erase; + } } } @@ -5028,22 +5065,21 @@ CNewCleanup_imp::x_SeqFeatRnaGBQualBC(CSeq_feat& feat, CRNA_ref& rna, CGb_qual& trna->GetAnticodon(), m_Scope, sequence::fCompareOverlapping) != sequence::eSame) { ok_to_apply = false; } - } - else { + } else { apply_anticodon = true; } } } if (ok_to_apply) { - if (apply_aa ) { + if (apply_aa) { rna.SetExt().SetTRNA().SetAa().SetIupacaa(trna->GetAa().GetNcbieaa()); - ChangeMade (CCleanupChange::eChange_tRna); + ChangeMade(CCleanupChange::eChange_tRna); } if (apply_anticodon) { CRef anticodon(new CSeq_loc()); - anticodon->Add (trna->GetAnticodon()); + anticodon->Add(trna->GetAnticodon()); rna.SetExt().SetTRNA().SetAnticodon(*anticodon); - ChangeMade (CCleanupChange::eChangeAnticodon); + ChangeMade(CCleanupChange::eChangeAnticodon); } return eAction_Erase; } @@ -5053,125 +5089,32 @@ CNewCleanup_imp::x_SeqFeatRnaGBQualBC(CSeq_feat& feat, CRNA_ref& rna, CGb_qual& } -CNewCleanup_imp::EAction CNewCleanup_imp::x_ParseCodeBreak(const CSeq_feat& feat, CCdregion& cds, const string& str) -{ - if( str.empty() || ! feat.IsSetLocation() ) { - return eAction_Nothing; - } - - const CSeq_id* feat_loc_seq_id = feat.GetLocation().GetId(); - if( ! feat_loc_seq_id ) { - return eAction_Nothing; - } - - string::size_type aa_pos = NStr::Find(str, "aa:"); - string::size_type len = 0; - string::size_type loc_pos, end_pos; - char protein_letter = 'X'; - CRef break_loc; - - if (aa_pos == string::npos) { - aa_pos = NStr::Find (str, ","); - if (aa_pos != string::npos) { - aa_pos = NStr::Find (str, ":", aa_pos); - } - if (aa_pos != string::npos) { - aa_pos ++; - } - } else { - aa_pos += 3; - } - - if (aa_pos != string::npos) { - while (aa_pos < str.length() && isspace (str[aa_pos])) { - aa_pos++; - } - while (aa_pos + len < str.length() && isalpha (str[aa_pos + len])) { - len++; - } - if (len != 0) { - protein_letter = ValidAminoAcid(str.substr(aa_pos, len)); - } - } - - loc_pos = NStr::Find (str, "(pos:"); - if (loc_pos == string::npos) { - return eAction_Nothing; - } - loc_pos += 5; - while (loc_pos < str.length() && isspace (str[loc_pos])) { - loc_pos++; - } - - end_pos = NStr::Find (str, ",aa:", loc_pos); - if( end_pos == NPOS ) { - end_pos = NStr::Find (str, ",", loc_pos); - if (end_pos == NPOS) { - end_pos = str.length(); - } - } - - string pos = NStr::TruncateSpaces(str.substr(loc_pos, end_pos - loc_pos)); - - // handle multi-interval positions by adding a join() around them - if( pos.find_first_of(",") != string::npos ) { - pos = "join(" + pos + ")"; - } - - break_loc = ReadLocFromText (pos, feat_loc_seq_id, m_Scope); - if( FIELD_IS_SET(feat.GetLocation(), Strand) && GET_FIELD(feat.GetLocation(), Strand) == eNa_strand_minus ) { - break_loc->SetStrand( GET_FIELD( feat.GetLocation(), Strand) ); - } else { - RESET_FIELD( *break_loc, Strand ); - } - - if (break_loc == NULL - || (break_loc->IsInt() - && sequence::Compare (*break_loc, feat.GetLocation(), m_Scope, sequence::fCompareOverlapping) != sequence::eContained ) - || (break_loc->IsInt() && sequence::GetLength(*break_loc, m_Scope) != 3)) { - return eAction_Nothing; - } - - // need to build code break object and add it to coding region - CRef newCodeBreak(new CCode_break()); - CCode_break::TAa& aa = newCodeBreak->SetAa(); - aa.SetNcbieaa(protein_letter); - newCodeBreak->SetLoc (*break_loc); - - CCdregion::TCode_break& orig_list = cds.SetCode_break(); - orig_list.push_back(newCodeBreak); - - ChangeMade(CCleanupChange::eChangeCodeBreak); - - return eAction_Erase; -} - -CNewCleanup_imp::EAction -CNewCleanup_imp::x_ProtGBQualBC(CProt_ref& prot, const CGb_qual& gb_qual, EGBQualOpt opt ) +CNewCleanup_imp::EAction +CNewCleanup_imp::x_ProtGBQualBC(CProt_ref& prot, const CGb_qual& gb_qual, EGBQualOpt opt) { const string& qual = gb_qual.GetQual(); - const string& val = gb_qual.GetVal(); + const string& val = gb_qual.GetVal(); - if (NStr::EqualNocase(qual, "product") || NStr::EqualNocase(qual, "standard_name")) { - if ( opt == eGBQualOpt_CDSMode || !prot.IsSetName() || NStr::IsBlank(prot.GetName().front())) { + if (NStr::EqualNocase(qual, "product") || NStr::EqualNocase(qual, "standard_name")) { + if (opt == eGBQualOpt_CDSMode || !prot.IsSetName() || NStr::IsBlank(prot.GetName().front())) { CCleanup::SetProteinName(prot, val, false); ChangeMade(CCleanupChange::eChangeQualifiers); } else { return eAction_Nothing; } } else if (NStr::EqualNocase(qual, "function")) { - ADD_STRING_TO_LIST( prot.SetActivity(), val ); + ADD_STRING_TO_LIST(prot.SetActivity(), val); ChangeMade(CCleanupChange::eChangeQualifiers); } else if (NStr::EqualNocase(qual, "EC_number")) { - ADD_STRING_TO_LIST( prot.SetEc(), val ); + ADD_STRING_TO_LIST(prot.SetEc(), val); ChangeMade(CCleanupChange::eChangeQualifiers); } // labels to leave alone - static const char * const ignored_quals[] = - { "label", "allele", "experiment", "inference", "UniProtKB_evidence", - "dbxref", "replace", "rpt_unit_seq", "rpt_unit_range"}; - static set ignored_quals_raw; + static const char * const ignored_quals[] = + { "label", "allele", "experiment", "inference", "UniProtKB_evidence", + "dbxref", "replace", "rpt_unit_seq", "rpt_unit_range" }; + static set ignored_quals_raw; // the mutex is just there in the unlikely event that two separate // threads both try to initialized ignored_quals_raw. It's NOT @@ -5179,13 +5122,13 @@ CNewCleanup_imp::x_ProtGBQualBC(CProt_ref& prot, const CGb_qual& gb_qual, EGBQua static CMutex ignored_quals_raw_initialization_mutex; { CMutexGuard guard(ignored_quals_raw_initialization_mutex); - if( ignored_quals_raw.empty() ) { - copy( ignored_quals, ignored_quals + sizeof(ignored_quals)/sizeof(ignored_quals[0]), - inserter(ignored_quals_raw, ignored_quals_raw.begin()) ); + if (ignored_quals_raw.empty()) { + copy(ignored_quals, ignored_quals + sizeof(ignored_quals) / sizeof(ignored_quals[0]), + inserter(ignored_quals_raw, ignored_quals_raw.begin())); } } - if( ignored_quals_raw.find(qual) != ignored_quals_raw.end() ) { + if (ignored_quals_raw.find(qual) != ignored_quals_raw.end()) { return eAction_Nothing; } @@ -5201,6 +5144,15 @@ void CNewCleanup_imp::BioSourceEC(CBioSource& biosrc) x_CleanupOldName(biosrc.SetOrg()); x_CleanupOrgModNoteEC(biosrc.SetOrg()); } + if (biosrc.IsSetSubtype()) { + x_CleanupSubTypeEC(biosrc.SetSubtype()); + } +} + + +void CNewCleanup_imp::x_CleanupSubTypeEC(CBioSource::TSubtype& subtypes) +{ + // no longer reducing precision per SQD-4332 } @@ -5823,7 +5775,7 @@ void CNewCleanup_imp::x_SplitDbtag( CDbtag &dbt, vector< CRef< CDbtag > > & out_ // split by colon and generate new tags vector tags; - NStr::Split(dbt.GetTag().GetStr(), ":", tags); + NStr::Split(dbt.GetTag().GetStr(), ":", tags, NStr::fSplit_Tokenize); _ASSERT( tags.size() >= 2 ); // treat the CDbtag argument as the first of the new CDbtags @@ -5890,8 +5842,6 @@ char s_ConvertTrnaAaToLetter( const CTrna_ext::C_Aa &trna_aa, CSeqUtil::ECoding void CNewCleanup_imp::x_SeqFeatTRNABC( CSeq_feat& feat, CTrna_ext & tRNA ) { - const string &comment = ( FIELD_IS_SET(feat, Comment) ? GET_FIELD(feat, Comment) : kEmptyStr ); - if( tRNA.IsSetAa() && tRNA.GetAa().IsIupacaa() ) { const int old_value = tRNA.GetAa().GetIupacaa(); tRNA.SetAa().SetNcbieaa( old_value ); @@ -5926,7 +5876,7 @@ void s_ParsePCRComponent(vector &out_list, const string *component) component_copy = component_copy.substr( 1, component_copy.length() - 2 ); } - NStr::Split(component_copy, string(","), out_list); + NStr::Split(component_copy, string(","), out_list, NStr::fSplit_Tokenize); EDIT_EACH_STRING_IN_VECTOR( str_iter, out_list ) { NStr::TruncateSpacesInPlace( *str_iter ); } @@ -6040,7 +5990,7 @@ void s_ParsePCRSet( const CBioSource &biosrc, list &out_pcr_set ) static void s_ParsePCRColonString( vector &out_list, const string &str ) { - NStr::Split(str, ":", out_list); + NStr::Split(str, ":", out_list, NStr::fSplit_Tokenize); EDIT_EACH_STRING_IN_VECTOR(str_iter, out_list ) { NStr::TruncateSpacesInPlace( *str_iter ); if( str_iter->empty() ) { @@ -6392,6 +6342,82 @@ void CNewCleanup_imp::x_CleanupOrgModAndSubSourceOther( COrgName &orgname, CBioS } } + +// As requested in SQD-4021: +// * if strain begins with "serovar " move remaining text to a serovar +// qualifier, unless a serovar qualifier is already present, in which case add +// to note +// * if strain begins with "subsp. " move remaining text to a subspecies +// qualifier, unless a subspecies qualifier is already present, in which case +// add to note +void CNewCleanup_imp::x_MovedNamedValuesInStrain(COrgName& orgname) +{ + if (!orgname.IsSetMod()) { + return; + } + COrgName::TMod::iterator m = orgname.SetMod().begin(); + while (m != orgname.SetMod().end()) { + if ((*m)->IsSetSubtype() && (*m)->IsSetSubname()) { + bool do_erase = false; + switch ((*m)->GetSubtype()) { + case COrgMod::eSubtype_serovar: + if (NStr::StartsWith((*m)->GetSubname(), "subsp. ")) { + string val = (*m)->GetSubname().substr(7); + x_MovedNamedValuesInStrain(orgname, COrgMod::eSubtype_sub_species, val); + do_erase = true; + } + break; + case COrgMod::eSubtype_strain: + if (NStr::StartsWith((*m)->GetSubname(), "subsp. ")) { + string val = (*m)->GetSubname().substr(7); + x_MovedNamedValuesInStrain(orgname, COrgMod::eSubtype_sub_species, val); + do_erase = true; + } else if (NStr::StartsWith((*m)->GetSubname(), "serovar ")) { + string val = (*m)->GetSubname().substr(8); + x_MovedNamedValuesInStrain(orgname, COrgMod::eSubtype_serovar, val); + do_erase = true; + } + break; + default: + break; + } + if (do_erase) { + m = orgname.SetMod().erase(m); + ChangeMade(CCleanupChange::eRemoveOrgmod); + } else { + ++m; + } + } + } +} + + +void CNewCleanup_imp::x_MovedNamedValuesInStrain(COrgName& orgname, COrgMod::ESubtype stype, const string& value) +{ + bool add_val = true; + bool add_note = false; + ITERATE(COrgName::TMod, m, orgname.GetMod()) { + if ((*m)->IsSetSubtype() && (*m)->GetSubtype() == stype) { + if ((*m)->IsSetSubname() && NStr::Equal((*m)->GetSubname(), value)) { + // already there, can just remove it + add_note = false; + add_val = false; + break; + } else { + add_note = true; + } + } + } + if (add_val) { + orgname.SetMod().push_back(CRef(new COrgMod(stype, value))); + ChangeMade(CCleanupChange::eAddOrgMod); + } else if (add_note) { + orgname.SetMod().push_back(CRef(new COrgMod(COrgMod::eSubtype_other, value))); + ChangeMade(CCleanupChange::eAddOrgMod); + } +} + + void CNewCleanup_imp::x_OrgnameModBC( COrgName &orgname, const string &org_ref_common ) { @@ -6446,6 +6472,8 @@ CNewCleanup_imp::x_OrgnameModBC( COrgName &orgname, const string &org_ref_common } } + x_MovedNamedValuesInStrain(orgname); + COrgMod *omp_anamorph = NULL; COrgMod *omp_gb_anamorph = NULL; COrgMod *omp_other = NULL; @@ -6837,14 +6865,50 @@ bool s_BarcodeCompare( return idx1 < idx2; } + +void CNewCleanup_imp::x_RemoveEmptyFields(CUser_object& user_object) +{ + if (user_object.GetObjectType() != CUser_object::eObjectType_StructuredComment) { + return; + } + if (!user_object.IsSetData()) { + return; + } + + CUser_object::TData::iterator it = user_object.SetData().begin(); + while (it != user_object.SetData().end()) { + bool is_blank = false; + if ((*it)->IsSetData()) { + if ((*it)->GetData().IsStr()) { + const string& val = (*it)->GetData().GetStr(); + if (NStr::IsBlank(val)) { + is_blank = true; + } + } else if ((*it)->GetData().Which() == CUser_field::TData::e_not_set) { + is_blank = true; + } + } else { + is_blank = true; + } + + if (is_blank) { + it = user_object.SetData().erase(it); + ChangeMade(CCleanupChange::eCleanUserObjectOrField); + } else { + ++it; + } + } +} + + void CNewCleanup_imp::x_CleanStructuredComment( CUser_object &user_object ) { - if( ! FIELD_IS_SET_AND_IS(user_object, Type, Str) || - user_object.GetType().GetStr() != "StructuredComment" ) - { + if (user_object.GetObjectType() != CUser_object::eObjectType_StructuredComment) { return; } + x_RemoveEmptyFields(user_object); + bool genome_assembly_data = false; bool ibol_data = false; @@ -6995,6 +7059,9 @@ void CNewCleanup_imp::x_FixUpEllipsis( string &str ) void CNewCleanup_imp::x_RemoveFlankingQuotes( string &val ) { + if (val.empty()) { + return; + } // holds the first and last pos that we will keep // (have to use "ints" since might be negative) int first_pos = 0; @@ -7134,7 +7201,7 @@ void CNewCleanup_imp::Except_textBC ( } vector exceptions; - NStr::Split(except_text, ",", exceptions); + NStr::Split(except_text, ",", exceptions, NStr::fSplit_Tokenize); EDIT_EACH_STRING_IN_VECTOR (it, exceptions) { string& text = *it; @@ -7240,6 +7307,9 @@ bool SortGBQuals(CSeq_feat& sf) void CNewCleanup_imp::x_CleanSeqFeatQuals(CSeq_feat& sf) { + if (!sf.IsSetQual()) { + return; + } // clean before uniquing EDIT_EACH_GBQUAL_ON_SEQFEAT(gbq_it, sf) { CGb_qual& gbq = **gbq_it; @@ -7257,6 +7327,13 @@ void CNewCleanup_imp::x_CleanSeqFeatQuals(CSeq_feat& sf) } // move quals to other parts of the feature as appropriate + if (CCleanup::ParseCodeBreaks(sf, *m_Scope)) { + ChangeMade(CCleanupChange::eChangeCodeBreak); + ChangeMade(CCleanupChange::eRemoveQualifier); + } + if (!sf.IsSetQual()) { + return; + } EDIT_EACH_GBQUAL_ON_SEQFEAT(gbq_it, sf) { CGb_qual& gbq = **gbq_it; if (GBQualSeqFeatBC(gbq, sf) == eAction_Erase) @@ -7432,7 +7509,7 @@ bool s_SplitGeneSyn( const string &syn, vector &gene_syns_to_add) // split by comma vector pieces_split_by_comma; - NStr::Split(syn, ",", pieces_split_by_comma); + NStr::Split(syn, ",", pieces_split_by_comma, NStr::fSplit_Tokenize); // now split each of those pieces by "; " vector pieces_split_by_semicolon; @@ -7459,6 +7536,20 @@ void CNewCleanup_imp::GenerefBC ( ) { + if (gr.IsSetLocus()) { + // split locus at '|', copy values after first to synonyms + // VR-746 + vector tokens; + NStr::Split(gr.GetLocus(), "|", tokens); + if (tokens.size() > 1) { + for (size_t i = 1; i < tokens.size(); i++) { + gr.SetSyn().push_back(tokens[i]); + } + gr.SetLocus(tokens[0]); + ChangeMade(CCleanupChange::eChangeGeneRef); + } + } + // split gene synonyms that have a comma or "; " vector gene_syns_to_add; EDIT_EACH_SYNONYM_ON_GENEREF (syn_itr, gr) { @@ -8093,19 +8184,19 @@ static bool s_IsNcrnaName ( static bool s_StartsWithNcrnaName( const string& name, - const string **out_ncrna_name = NULL ) + string &out_ncrna_name) { - TNcrna::const_iterator suffix_finder = s_FindInSetAsPrefix( name, sc_NcrnafNames ); - if( suffix_finder == sc_NcrnafNames.end() ) { - if( NULL != out_ncrna_name ) { - *out_ncrna_name = NULL; - } - return false; - } else { - if( NULL != out_ncrna_name ) { - *out_ncrna_name = &*suffix_finder; - } + string tmp_name = name; + size_t pos = NStr::Find(name, " "); + if (pos != NPOS) { + tmp_name = name.substr(0, pos); + } + if (!NStr::EqualNocase(tmp_name, "other") && CRNA_gen::IsLegalClass(tmp_name)) { + out_ncrna_name = tmp_name; + CRNA_gen::FixncRNAClassValue(out_ncrna_name); return true; + } else { + return false; } } @@ -8180,6 +8271,89 @@ CNewCleanup_imp::x_RRNANameBC( string &name ) } } +void CNewCleanup_imp::RnarefGenBC(CRNA_ref& rr) +{ + bool changed = false; + + CRNA_ref::C_Ext& ext = GET_MUTABLE(rr, Ext); + CRNA_gen& gen = GET_MUTABLE(ext, Gen); + + if (FIELD_IS_SET(gen, Class)) { + const string& str = GET_FIELD(gen, Class); + if (NStr::IsBlank(str)) { + RESET_FIELD(gen, Class); + ChangeMade(CCleanupChange::eChangeRNAref); + } + else { + string& class_val = GET_MUTABLE(gen, Class); + if (CRNA_gen::FixncRNAClassValue(class_val)) { + ChangeMade(CCleanupChange::eChangeRNAref); + } + } + } + if (FIELD_IS_SET(gen, Product)) { + const string& str = GET_FIELD(gen, Product); + if (NStr::IsBlank(str)) { + RESET_FIELD(gen, Product); + ChangeMade(CCleanupChange::eChangeRNAref); + } + } + if (FIELD_IS_SET(gen, Quals)) { + CRNA_qual_set& qset = GET_MUTABLE(gen, Quals); + EDIT_EACH_QUAL_ON_RNAQSET(qitr, qset) { + CRNA_qual& qual = **qitr; + CLEAN_STRING_MEMBER(qual, Qual); + CLEAN_STRING_MEMBER(qual, Val); + if (!FIELD_IS_SET(qual, Qual) || !FIELD_IS_SET(qual, Val)) { + ERASE_QUAL_ON_RNAQSET(qitr, qset); + ChangeMade(CCleanupChange::eChangeRNAref); + } + } + + if (QUAL_ON_RNAQSET_IS_EMPTY(qset)) { + RESET_FIELD(gen, Quals); + ChangeMade(CCleanupChange::eChangeRNAref); + } + } + + if (FIELD_EQUALS(rr, Type, NCBI_RNAREF(miscRNA)) && + FIELD_IS_SET(gen, Product) && + !FIELD_IS_SET(gen, Class)) { + string & product = GET_MUTABLE(gen, Product); + string ncrna_name = kEmptyStr; + if (s_StartsWithNcrnaName(product, ncrna_name)) { + if (product.length() > (ncrna_name.length() + 1) && + product[ncrna_name.length()] == ' ') { + SET_FIELD(gen, Class, ncrna_name); + SET_FIELD(gen, Product, product.substr(ncrna_name.length() + 1)); + TRUNCATE_SPACES(gen, Class); + TRUNCATE_SPACES(gen, Product); + SET_FIELD(rr, Type, NCBI_RNAREF(ncRNA)); + ChangeMade(CCleanupChange::eChangeRNAref); + } + } + } + + if ((FIELD_EQUALS(rr, Type, NCBI_RNAREF(mRNA)) || + FIELD_EQUALS(rr, Type, NCBI_RNAREF(rRNA))) && + STRING_FIELD_NOT_EMPTY(gen, Product) && + RAW_FIELD_IS_EMPTY_OR_UNSET(gen, Class) && + !FIELD_IS_SET(gen, Quals)) { + // convert RNA-Gen to name. + // Careful: this invalidates the "gen" variable. + const string product = GET_FIELD(gen, Product); + SET_FIELD(ext, Name, product); + return; + } + + if (!FIELD_IS_SET(gen, Class) && + !FIELD_IS_SET(gen, Product) && + !FIELD_IS_SET(gen, Quals)) { + RESET_FIELD(rr, Ext); + ChangeMade(CCleanupChange::eChangeRNAref); + } +} + void CNewCleanup_imp::RnarefBC ( CRNA_ref& rr ) @@ -8268,81 +8442,7 @@ void CNewCleanup_imp::RnarefBC ( break; case NCBI_RNAEXT(Gen): { - CRNA_gen& gen = GET_MUTABLE (ext, Gen); - if (FIELD_IS_SET (gen, Class)) { - const string& str = GET_FIELD (gen, Class); - if (NStr::IsBlank (str)) { - RESET_FIELD (gen, Class); - ChangeMade(CCleanupChange::eChangeRNAref); - } - } - if (FIELD_IS_SET (gen, Product)) { - const string& str = GET_FIELD (gen, Product); - if (NStr::IsBlank (str)) { - RESET_FIELD (gen, Product); - ChangeMade(CCleanupChange::eChangeRNAref); - } - } - if (FIELD_IS_SET (gen, Quals)) { - CRNA_qual_set& qset = GET_MUTABLE (gen, Quals); - EDIT_EACH_QUAL_ON_RNAQSET (qitr, qset) { - CRNA_qual& qual = **qitr; - CLEAN_STRING_MEMBER (qual, Qual); - CLEAN_STRING_MEMBER (qual, Val); - if( ! FIELD_IS_SET(qual, Qual) || ! FIELD_IS_SET(qual, Val) ) { - ERASE_QUAL_ON_RNAQSET( qitr, qset ); - ChangeMade(CCleanupChange::eChangeRNAref); - } - } - - if( QUAL_ON_RNAQSET_IS_EMPTY(qset) ) { - RESET_FIELD(gen, Quals); - ChangeMade(CCleanupChange::eChangeRNAref); - } - } - - if ( FIELD_EQUALS(rr, Type, NCBI_RNAREF(miscRNA)) && - FIELD_IS_SET (gen, Product) && - ! FIELD_IS_SET (gen, Class) ) - { - string & product = GET_MUTABLE(gen, Product); - const string *ncrna_name = NULL; - if( s_StartsWithNcrnaName(product, &ncrna_name) ) { - _ASSERT( NULL != ncrna_name ); - if( product.length() > (ncrna_name->length() + 1) && - product[ncrna_name->length()] == ' ' ) - { - SET_FIELD( gen, Class, *ncrna_name ); - SET_FIELD( gen, Product, product.substr(ncrna_name->length() + 1) ); - TRUNCATE_SPACES( gen, Class ); - TRUNCATE_SPACES( gen, Product ); - SET_FIELD( rr, Type, NCBI_RNAREF(ncRNA) ); - ChangeMade(CCleanupChange::eChangeRNAref); - } - // no need to erase ncrna_name because it points to - // global memory. - } - } - - if( ( FIELD_EQUALS(rr, Type, NCBI_RNAREF(mRNA)) || - FIELD_EQUALS(rr, Type, NCBI_RNAREF(rRNA)) ) && - STRING_FIELD_NOT_EMPTY(gen, Product) && - RAW_FIELD_IS_EMPTY_OR_UNSET(gen, Class) && - ! FIELD_IS_SET(gen, Quals) ) - { - // convert RNA-Gen to name. - // Careful: this invalidates the "gen" variable. - const string product = GET_FIELD(gen, Product); - SET_FIELD( ext, Name, product ); - break; - } - - if (! FIELD_IS_SET (gen, Class) && - ! FIELD_IS_SET (gen, Product) && - ! FIELD_IS_SET (gen, Quals)) { - RESET_FIELD (rr, Ext); - ChangeMade(CCleanupChange::eChangeRNAref); - } + RnarefGenBC(rr); } break; default: @@ -8920,9 +9020,6 @@ void CNewCleanup_imp::RnaFeatBC ( if( aa != '\0' ) { CRef tRNA( new CTrna_ext ); tRNA->SetAa().SetNcbieaa( aa ); - if (justTrnaText) { - copy( codon.begin(), codon.end(), back_inserter(tRNA->SetCodon()) ); - } rna.SetExt().SetTRNA( *tRNA ); ChangeMade(CCleanupChange::eChange_tRna); if (justTrnaText) { @@ -9033,7 +9130,8 @@ void CNewCleanup_imp::RnaFeatBC ( CAminoAcidCharToSymbol::const_iterator aa_end = sm_TrnaInverseKeys.upper_bound(aa); for( ; aa_iter != aa_end ; ++aa_iter ) { const string &a_name = aa_iter->second; - if( comment == a_name && ( aa != 'M' || ! NStr::EqualNocase(a_name, "fMet") || ! NStr::EqualNocase(a_name, "iMet") ) ) { + if (comment != a_name) continue; + if ( aa != 'M' || (! NStr::EqualNocase(a_name, "fMet") && ! NStr::EqualNocase(a_name, "iMet") ) ) { RESET_FIELD(seq_feat, Comment); ChangeMade(CCleanupChange::eChangeComment); break; @@ -9786,6 +9884,45 @@ void CNewCleanup_imp::x_ClearEmptyDescr( CBioseq& bioseq ) } } +static bool IsBadSeqInstStrand(const CSeq_inst& inst, const CBioSource* bio_src) +{ + bool ret = false; + if (inst.IsSetStrand() && inst.GetStrand() == CSeq_inst::eStrand_ss && + inst.IsSetMol() && inst.GetMol() == CSeq_inst::eMol_dna) { + if (bio_src && bio_src->IsSetLineage()) { + ret = true; + if (NStr::FindNoCase(bio_src->GetLineage(), "virus", 0) != NPOS) { + ret = false; + } else if (bio_src->IsSetDivision() && NStr::EqualNocase(bio_src->GetDivision(), "SYN")) { + ret = false; + } + } + } + + return ret; +} + +void CNewCleanup_imp::x_RemoveSingleStrand(CBioseq& bioseq) +{ + // do not remove single-strandedness for patent sequences + bool is_patent = false; + for (auto id = bioseq.GetId().begin(); id != bioseq.GetId().end(); id++) { + if ((*id)->IsPatent()) { + is_patent = true; + break; + } + } + if (is_patent) { + return; + } + + CBioseq_Handle bsh = m_Scope->GetBioseqHandle(bioseq); + + if (bioseq.IsSetInst() && IsBadSeqInstStrand(bioseq.GetInst(), sequence::GetBioSource(bsh))) { + bioseq.SetInst().ResetStrand(); + ChangeMade(CCleanupChange::eChangeBioseqInst); + } +} void CNewCleanup_imp::x_NotePubdescOrAnnotPubs( const CPub_equiv &pub_equiv ) @@ -11363,7 +11500,7 @@ bool s_IsGenomeAnnotationStart(const CUser_object& user) NStr::Equal(prefix.GetData().GetStr(), "##Genome-Annotation-Data-START##")) { return true; } - } catch (CException& e) { + } catch (CException&) { } } @@ -11633,11 +11770,59 @@ void CNewCleanup_imp::x_RemoveOldFeatures(CBioseq & bioseq) } +//SQD-2043 change pop sets to phy sets if taxnames differ +void CNewCleanup_imp::x_ChangePopToPhy(CBioseq_set& bioseq_set) +{ + if (!bioseq_set.IsSetClass() || bioseq_set.GetClass() != CBioseq_set::eClass_pop_set) { + return; + } + bool all_same = true; + CTypeConstIterator seqit(ConstBegin(bioseq_set)); + string first_taxname = ""; + bool is_first = true; + for (; seqit; ++seqit) { + string taxname = ""; + CBioseq_Handle bsh = m_Scope->GetBioseqHandle(*seqit); + // Will get the first biosource either from the descriptor + // or feature. + CSeqdesc_CI d(bsh, CSeqdesc::e_Source); + if (d) { + if (d->GetSource().IsSetOrg() && d->GetSource().GetOrg().IsSetTaxname()) { + taxname = d->GetSource().GetOrg().GetTaxname(); + } + } else { + CFeat_CI f(bsh, CSeqFeatData::e_Biosrc); + if (f && f->GetData().GetBiosrc().IsSetOrg() && f->GetData().GetBiosrc().GetOrg().IsSetTaxname()) { + taxname = f->GetData().GetBiosrc().GetOrg().GetTaxname(); + } + } + + if (is_first) { + first_taxname = taxname; + is_first = false; + continue; + } + + // Make sure all the taxnames in the set are the same. + if (NStr::CompareNocase(first_taxname, taxname) != 0) { + all_same = false; + break; + } + } + if (!all_same) { + bioseq_set.SetClass(CBioseq_set::eClass_phy_set); + ChangeMade(CCleanupChange::eChangeBioseqSetClass); + } +} + void CNewCleanup_imp::x_BioseqSetEC( CBioseq_set & bioseq_set ) { // put general Bioseq-set cleanup here: // ... + // NOTE: Need to do this first, because cleanup rules may be different for pop and phy + x_ChangePopToPhy(bioseq_set); + // special logic for various bioseq_set types: switch( GET_FIELD_OR_DEFAULT( bioseq_set, Class, NCBI_BIOSEQSETCLASS(not_set)) ) @@ -12454,19 +12639,6 @@ void CNewCleanup_imp::ProtRefEC(CProt_ref& pr) } -bool s_LocationShouldBeExtendedToMatch(const CSeq_loc& orig, const CSeq_loc& improved) -{ - if ((orig.GetStrand() == eNa_strand_minus && - orig.GetStop(eExtreme_Biological) > improved.GetStop(eExtreme_Biological)) || - (orig.GetStrand() != eNa_strand_minus && - orig.GetStop(eExtreme_Biological) < improved.GetStop(eExtreme_Biological))) { - return true; - } else { - return false; - } -} - - void CNewCleanup_imp::CdRegionEC(CSeq_feat& sf) { if (!sf.IsSetData() || !sf.GetData().IsCdregion()) { @@ -12503,19 +12675,21 @@ void CNewCleanup_imp::CdRegionEC(CSeq_feat& sf) } } } - } catch (CException& ex) { + } catch (CException&) { // unable to get bioseq handle when loc is on multiple sequences } } - CConstRef mrna = sequence::GetmRNAforCDS(sf, *m_Scope); - CConstRef gene = sequence::GetGeneForFeature(sf, *m_Scope); - if (!m_IsEmblOrDdbj) { try { + CRef cds_cpy(new CSeq_feat()); + cds_cpy->Assign(sf); CBioseq_Handle bsh = m_Scope->GetBioseqHandle(sf.GetLocation()); if (bsh && CCleanup::ExtendToStopIfShortAndNotPartial(sf, bsh)) { - if (gene && s_LocationShouldBeExtendedToMatch(gene->GetLocation(), sf.GetLocation())) { + CConstRef mrna = sequence::GetmRNAforCDS(*cds_cpy, *m_Scope); + CConstRef gene = sequence::GetGeneForFeature(*cds_cpy, *m_Scope); + + if (gene && CCleanup::LocationMayBeExtendedToMatch(gene->GetLocation(), sf.GetLocation())) { CRef new_gene(new CSeq_feat()); new_gene->Assign(*gene); if (CCleanup::ExtendStopPosition(*new_gene, &sf)) { @@ -12523,7 +12697,7 @@ void CNewCleanup_imp::CdRegionEC(CSeq_feat& sf) efh.Replace(*new_gene); } } - if (mrna && s_LocationShouldBeExtendedToMatch(mrna->GetLocation(), sf.GetLocation())) { + if (mrna && CCleanup::LocationMayBeExtendedToMatch(mrna->GetLocation(), sf.GetLocation())) { CRef new_mrna(new CSeq_feat()); new_mrna->Assign(*mrna); if (CCleanup::ExtendStopPosition(*new_mrna, &sf)) { @@ -12533,7 +12707,7 @@ void CNewCleanup_imp::CdRegionEC(CSeq_feat& sf) } ChangeMade(CCleanupChange::eChangeFeatureLocation); } - } catch (CException& ex) { + } catch (CException& ) { // unable to get bioseq handle when loc is on multiple sequences } } diff --git a/c++/src/objtools/cleanup/newcleanupp.hpp b/c++/src/objtools/cleanup/newcleanupp.hpp index 344be6b4..45a37065 100644 --- a/c++/src/objtools/cleanup/newcleanupp.hpp +++ b/c++/src/objtools/cleanup/newcleanupp.hpp @@ -36,6 +36,7 @@ #include +#include #include #include #include @@ -90,7 +91,6 @@ class CName_std; class CBioSource; class COrg_ref; class COrgName; -class COrgMod; class CSubSource; class CMolInfo; class CCdregion; @@ -248,6 +248,8 @@ private: void BiosourceBC (CBioSource& bsc); void OrgrefModBC (string& str); void OrgrefBC (COrg_ref& org); + void x_MovedNamedValuesInStrain(COrgName& orgname); + void x_MovedNamedValuesInStrain(COrgName& orgname, COrgMod::ESubtype stype, const string& prefix); void OrgnameBC (COrgName& onm, COrg_ref &org_ref); void OrgmodBC (COrgMod& omd); @@ -292,6 +294,7 @@ private: void ProtActivityBC ( std::string & str ); void ProtrefBC (CProt_ref& pr); void RnarefBC (CRNA_ref& rr); + void RnarefGenBC(CRNA_ref& rr); void GeneFeatBC (CGene_ref& gr, CSeq_feat& sf); void ProtFeatfBC (CProt_ref& pr, CSeq_feat& sf); @@ -338,6 +341,7 @@ private: void x_RemoveOrphanedProteins(CBioseq_set& set); void x_SingleSeqSetToSeq(CBioseq_set& set); void x_MergeDupBioSources(CSeq_descr & seq_descr); + void x_CleanupSubTypeEC(CBioSource::TSubtype& subtypes); // void XxxxxxBC (Cxxxxx& xxx); @@ -401,7 +405,6 @@ private: EAction x_HandleTrnaProductGBQual(CSeq_feat& feat, CRNA_ref& rna, const string& product); EAction x_HandleStandardNameRnaGBQual(CSeq_feat& feat, CRNA_ref& rna, const string& standard_name); EAction x_SeqFeatRnaGBQualBC(CSeq_feat& feat, CRNA_ref& rna, CGb_qual& gb_qual); - EAction x_ParseCodeBreak(const CSeq_feat& feat, CCdregion& cds, const string& str); EAction x_ProtGBQualBC(CProt_ref& prot, const CGb_qual& gb_qual, EGBQualOpt opt ); void x_AddEnvSamplOrMetagenomic(CBioSource& biosrc); void x_CleanupOldName(COrg_ref& org); @@ -458,6 +461,7 @@ private: void x_CleanupAndRepairInference( string &inference ); void x_CleanStructuredComment( CUser_object &user_object ); + void x_RemoveEmptyFields(CUser_object& user_object); void x_MendSatelliteQualifier( string &val ); @@ -520,6 +524,9 @@ private: void x_ClearEmptyDescr( CBioseq_set& bioseq_set ); void x_ClearEmptyDescr( CBioseq& bioseq ); + // removes single-strandedness from non-viral nucleotide sequences + void x_RemoveSingleStrand( CBioseq& bioseq ); + // functions that prepare for post-processing while traversing void x_NotePubdescOrAnnotPubs( const CPub_equiv &pub_equiv ); void x_NotePubdescOrAnnotPubs_RecursionHelper( @@ -583,6 +590,7 @@ private: void x_RemoveOldFeatures(CBioseq & bioseq); void x_BioseqSetEC( CBioseq_set & bioseq_set ); + void x_ChangePopToPhy(CBioseq_set& bioseq_set); void x_CollapseSet(CBioseq_set& set); void x_RemovePopPhyBioSource(CBioseq_set& set); void x_RemovePopPhyBioSource(CBioseq_set& set, const COrg_ref& org); diff --git a/c++/src/objtools/data_loaders/CMakeLists.txt b/c++/src/objtools/data_loaders/CMakeLists.txt new file mode 100644 index 00000000..509825df --- /dev/null +++ b/c++/src/objtools/data_loaders/CMakeLists.txt @@ -0,0 +1,13 @@ +############################################################################## +# +# + +# Include projects from this directory + +# Recurse subdirectories +add_subdirectory(genbank) +add_subdirectory(lds2) +add_subdirectory(asn_cache) +add_subdirectory(blastdb) +add_subdirectory(patcher) +add_subdirectory(cdd) diff --git a/c++/src/objtools/data_loaders/Makefile.in b/c++/src/objtools/data_loaders/Makefile.in index 9e7505b8..65c9df2d 100644 --- a/c++/src/objtools/data_loaders/Makefile.in +++ b/c++/src/objtools/data_loaders/Makefile.in @@ -1,6 +1,6 @@ -# $Id: Makefile.in 501731 2016-05-18 15:58:33Z gouriano $ +# $Id: Makefile.in 534723 2017-05-01 18:22:26Z grichenk $ -SUB_PROJ = genbank lds2 blastdb patcher asn_cache +SUB_PROJ = genbank lds2 blastdb patcher asn_cache cdd srcdir = @srcdir@ include @builddir@/Makefile.meta diff --git a/c++/src/objtools/data_loaders/blastdb/CMakeLists.ncbi_xloader_blastdb.lib.txt b/c++/src/objtools/data_loaders/blastdb/CMakeLists.ncbi_xloader_blastdb.lib.txt new file mode 100644 index 00000000..ef4b11df --- /dev/null +++ b/c++/src/objtools/data_loaders/blastdb/CMakeLists.ncbi_xloader_blastdb.lib.txt @@ -0,0 +1,14 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/data_loaders/blastdb/Makefile.ncbi_xloader_blastdb.lib +# +add_library(ncbi_xloader_blastdb + bdbloader cached_sequence local_blastdb_adapter +) +add_dependencies(ncbi_xloader_blastdb + blastdb seqset +) + +target_link_libraries(ncbi_xloader_blastdb + seqdb +) + diff --git a/c++/src/objtools/data_loaders/blastdb/CMakeLists.ncbi_xloader_blastdb_rmt.lib.txt b/c++/src/objtools/data_loaders/blastdb/CMakeLists.ncbi_xloader_blastdb_rmt.lib.txt new file mode 100644 index 00000000..99cbf3e5 --- /dev/null +++ b/c++/src/objtools/data_loaders/blastdb/CMakeLists.ncbi_xloader_blastdb_rmt.lib.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/data_loaders/blastdb/Makefile.ncbi_xloader_blastdb_rmt.lib +# +add_library(ncbi_xloader_blastdb_rmt + bdbloader_rmt remote_blastdb_adapter +) +add_dependencies(ncbi_xloader_blastdb_rmt + blastdb xnetblast +) + +target_link_libraries(ncbi_xloader_blastdb_rmt + blast_services ncbi_xloader_blastdb +) diff --git a/c++/src/objtools/data_loaders/blastdb/CMakeLists.txt b/c++/src/objtools/data_loaders/blastdb/CMakeLists.txt new file mode 100644 index 00000000..a3bb3865 --- /dev/null +++ b/c++/src/objtools/data_loaders/blastdb/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.ncbi_xloader_blastdb.lib.txt) +include(CMakeLists.ncbi_xloader_blastdb_rmt.lib.txt) + +# Recurse subdirectories +add_subdirectory(unit_test ) diff --git a/c++/src/objtools/data_loaders/genbank/CMakeLists.ncbi_xloader_genbank.lib.txt b/c++/src/objtools/data_loaders/genbank/CMakeLists.ncbi_xloader_genbank.lib.txt new file mode 100644 index 00000000..5d1d519e --- /dev/null +++ b/c++/src/objtools/data_loaders/genbank/CMakeLists.ncbi_xloader_genbank.lib.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/data_loaders/genbank/Makefile.ncbi_xloader_genbank.lib +# +add_library(ncbi_xloader_genbank + gbloader gbload_util +) +add_dependencies(ncbi_xloader_genbank + seqsplit +) + +target_link_libraries(ncbi_xloader_genbank + ncbi_xreader_cache ncbi_xreader_id1 ncbi_xreader_id2 +) diff --git a/c++/src/objtools/data_loaders/genbank/CMakeLists.ncbi_xreader.lib.txt b/c++/src/objtools/data_loaders/genbank/CMakeLists.ncbi_xreader.lib.txt new file mode 100644 index 00000000..66caa529 --- /dev/null +++ b/c++/src/objtools/data_loaders/genbank/CMakeLists.ncbi_xreader.lib.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/data_loaders/genbank/Makefile.ncbi_xreader.lib +# +add_library(ncbi_xreader + dispatcher reader writer processors + reader_snp seqref blob_id request_result + reader_id1_base reader_id2_base reader_service incr_time info_cache +) +add_dependencies(ncbi_xreader + id1 id2 seqsplit seqset +) + +target_link_libraries(ncbi_xreader + id1 id2 xcompress + xconnect xobjmgr +) diff --git a/c++/src/objtools/data_loaders/genbank/CMakeLists.txt b/c++/src/objtools/data_loaders/genbank/CMakeLists.txt new file mode 100644 index 00000000..dbd15c0b --- /dev/null +++ b/c++/src/objtools/data_loaders/genbank/CMakeLists.txt @@ -0,0 +1,16 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.ncbi_xreader.lib.txt) +include(CMakeLists.ncbi_xloader_genbank.lib.txt) + +# Recurse subdirectories +add_subdirectory(cache) +add_subdirectory(pubseq) +add_subdirectory(id2) +add_subdirectory(id1) +add_subdirectory(pubseq2) +add_subdirectory(gicache) +add_subdirectory(test ) diff --git a/c++/src/objtools/data_loaders/genbank/cache/CMakeLists.ncbi_xreader_cache.lib.txt b/c++/src/objtools/data_loaders/genbank/cache/CMakeLists.ncbi_xreader_cache.lib.txt new file mode 100644 index 00000000..1701f2a6 --- /dev/null +++ b/c++/src/objtools/data_loaders/genbank/cache/CMakeLists.ncbi_xreader_cache.lib.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/data_loaders/genbank/cache/Makefile.ncbi_xreader_cache.lib +# +add_library(ncbi_xreader_cache + reader_cache writer_cache +) +include_directories(SYSTEM ${CMPRS_INCLUDE}) + +target_link_libraries(ncbi_xreader_cache + ncbi_xreader +) +add_dependencies(ncbi_xreader_cache + seqsplit +) + diff --git a/c++/src/objtools/data_loaders/genbank/cache/CMakeLists.txt b/c++/src/objtools/data_loaders/genbank/cache/CMakeLists.txt new file mode 100644 index 00000000..7406dd25 --- /dev/null +++ b/c++/src/objtools/data_loaders/genbank/cache/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.ncbi_xreader_cache.lib.txt) + diff --git a/c++/src/objtools/data_loaders/genbank/gbloader.cpp b/c++/src/objtools/data_loaders/genbank/gbloader.cpp index 0400d271..829e6948 100644 --- a/c++/src/objtools/data_loaders/genbank/gbloader.cpp +++ b/c++/src/objtools/data_loaders/genbank/gbloader.cpp @@ -1,4 +1,4 @@ -/* $Id: gbloader.cpp 499679 2016-04-27 16:42:09Z vasilche $ +/* $Id: gbloader.cpp 534193 2017-04-25 14:00:21Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -86,6 +86,16 @@ NCBI_PARAM_DEF_EX(string, GENBANK, LOADER_METHOD, kEmptyStr, eParam_NoThread, GENBANK_LOADER_METHOD); typedef NCBI_PARAM_TYPE(GENBANK, LOADER_METHOD) TGenbankLoaderMethod; +NCBI_PARAM_DECL(string, GENBANK, READER_NAME); +NCBI_PARAM_DEF_EX(string, GENBANK, READER_NAME, kEmptyStr, + eParam_NoThread, GENBANK_READER_NAME); +typedef NCBI_PARAM_TYPE(GENBANK, READER_NAME) TGenbankReaderName; + +NCBI_PARAM_DECL(string, GENBANK, WRITER_NAME); +NCBI_PARAM_DEF_EX(string, GENBANK, WRITER_NAME, kEmptyStr, + eParam_NoThread, GENBANK_WRITER_NAME); +typedef NCBI_PARAM_TYPE(GENBANK, WRITER_NAME) TGenbankWriterName; + #if defined(HAVE_PUBSEQ_OS) static const char* const DEFAULT_DRV_ORDER = "ID2:PUBSEQOS:ID1"; #else @@ -93,6 +103,7 @@ static const char* const DEFAULT_DRV_ORDER = "ID2:ID1"; #endif #define GBLOADER_NAME "GBLOADER" +#define GBLOADER_HUP_NAME "GBLOADER-HUP" #define DEFAULT_ID_GC_SIZE 10000 #define DEFAULT_ID_EXPIRATION_TIMEOUT 2*3600 // 2 hours @@ -137,7 +148,8 @@ CGBLoaderParams::CGBLoaderParams(void) : m_ReaderName(), m_ReaderPtr(0), m_ParamTree(0), - m_Preopen(ePreopenByConfig) + m_Preopen(ePreopenByConfig), + m_HasHUPIncluded(false) { } @@ -146,7 +158,8 @@ CGBLoaderParams::CGBLoaderParams(const string& reader_name) : m_ReaderName(reader_name), m_ReaderPtr(0), m_ParamTree(0), - m_Preopen(ePreopenByConfig) + m_Preopen(ePreopenByConfig), + m_HasHUPIncluded(false) { } @@ -155,7 +168,8 @@ CGBLoaderParams::CGBLoaderParams(CReader* reader_ptr) : m_ReaderName(), m_ReaderPtr(reader_ptr), m_ParamTree(0), - m_Preopen(ePreopenByConfig) + m_Preopen(ePreopenByConfig), + m_HasHUPIncluded(false) { } @@ -164,7 +178,8 @@ CGBLoaderParams::CGBLoaderParams(const TParamTree* param_tree) : m_ReaderName(), m_ReaderPtr(0), m_ParamTree(param_tree), - m_Preopen(ePreopenByConfig) + m_Preopen(ePreopenByConfig), + m_HasHUPIncluded(false) { } @@ -173,7 +188,8 @@ CGBLoaderParams::CGBLoaderParams(EPreopenConnection preopen) : m_ReaderName(), m_ReaderPtr(0), m_ParamTree(0), - m_Preopen(preopen) + m_Preopen(preopen), + m_HasHUPIncluded(false) { } @@ -187,7 +203,8 @@ CGBLoaderParams::CGBLoaderParams(const CGBLoaderParams& params) : m_ReaderName(params.m_ReaderName), m_ReaderPtr(params.m_ReaderPtr), m_ParamTree(params.m_ParamTree), - m_Preopen(params.m_Preopen) + m_Preopen(params.m_Preopen), + m_HasHUPIncluded(params.m_HasHUPIncluded) { } @@ -199,6 +216,7 @@ CGBLoaderParams& CGBLoaderParams::operator=(const CGBLoaderParams& params) m_ReaderPtr = params.m_ReaderPtr; m_ParamTree = params.m_ParamTree; m_Preopen = params.m_Preopen; + m_HasHUPIncluded = params.m_HasHUPIncluded; } return *this; } @@ -260,6 +278,48 @@ string CGBDataLoader::GetLoaderNameFromArgs(const string& /*reader_name*/) } +CGBDataLoader::TRegisterLoaderInfo CGBDataLoader::RegisterInObjectManager( + CObjectManager& om, + EIncludeHUP /*include_hup*/, + CObjectManager::EIsDefault is_default, + CObjectManager::TPriority priority) +{ + CGBLoaderParams params("PUBSEQOS2:PUBSEQOS"); + params.SetHUPIncluded(); + TGBMaker maker(params); + CDataLoader::RegisterInObjectManager(om, maker, is_default, priority); + return maker.GetRegisterInfo(); +} + + +string CGBDataLoader::GetLoaderNameFromArgs(EIncludeHUP /*include_hup*/) +{ + return GBLOADER_HUP_NAME; +} + + +CGBDataLoader::TRegisterLoaderInfo CGBDataLoader::RegisterInObjectManager( + CObjectManager& om, + const string& reader_name, + EIncludeHUP /*include_hup*/, + CObjectManager::EIsDefault is_default, + CObjectManager::TPriority priority) +{ + CGBLoaderParams params(reader_name); + params.SetHUPIncluded(); + TGBMaker maker(params); + CDataLoader::RegisterInObjectManager(om, maker, is_default, priority); + return maker.GetRegisterInfo(); +} + + +string CGBDataLoader::GetLoaderNameFromArgs(const string& /*reader_name*/, + EIncludeHUP /*include_hup*/) +{ + return GBLOADER_HUP_NAME; +} + + CGBDataLoader::TRegisterLoaderInfo CGBDataLoader::RegisterInObjectManager( CObjectManager& om, const TParamTree& param_tree, @@ -291,15 +351,16 @@ CGBDataLoader::TRegisterLoaderInfo CGBDataLoader::RegisterInObjectManager( } -string CGBDataLoader::GetLoaderNameFromArgs(const CGBLoaderParams& /*params*/) +string CGBDataLoader::GetLoaderNameFromArgs(const CGBLoaderParams& params) { - return GBLOADER_NAME; + return params.HasHUPIncluded()? GBLOADER_HUP_NAME: GBLOADER_NAME; } CGBDataLoader::CGBDataLoader(const string& loader_name, const CGBLoaderParams& params) - : CDataLoader(loader_name) + : CDataLoader(loader_name), + m_HasHUPIncluded(params.HasHUPIncluded()) { GBLOG_POST_X(1, "CGBDataLoader"); x_CreateDriver(params); @@ -313,6 +374,17 @@ CGBDataLoader::~CGBDataLoader(void) } +CObjectManager::TPriority CGBDataLoader::GetDefaultPriority(void) const +{ + CObjectManager::TPriority priority = CDataLoader::GetDefaultPriority(); + if ( HasHUPIncluded() ) { + // HUP data loader has lower priority by default + priority += 1; + } + return priority; +} + + namespace { typedef CGBDataLoader::TParamTree TParams; @@ -580,51 +652,47 @@ void CGBDataLoader::x_CreateDriver(const CGBLoaderParams& params) } } else { - if ( x_CreateReaders(GetReaderName(gb_params), gb_params, preopen) ) { - x_CreateWriters(GetWriterName(gb_params), gb_params); + pair rw_name = GetReaderWriterName(gb_params); + if ( x_CreateReaders(rw_name.first, gb_params, preopen) ) { + x_CreateWriters(rw_name.second, gb_params); } } } -string CGBDataLoader::GetReaderName(const TParamTree* params) const +pair +CGBDataLoader::GetReaderWriterName(const TParamTree* params) const { - string str; - if ( str.empty() ) { - str = GetParam(params, NCBI_GBLOADER_PARAM_READER_NAME); - } - if ( str.empty() ) { - str = GetParam(params, NCBI_GBLOADER_PARAM_LOADER_METHOD); - } - if ( str.empty() ) { - // try config first - str = TGenbankLoaderMethod::GetDefault(); + pair ret; + ret.first = GetParam(params, NCBI_GBLOADER_PARAM_READER_NAME); + if ( ret.first.empty() ) { + ret.first = TGenbankReaderName::GetDefault(); } - if ( str.empty() ) { - // fall back default reader list - str = DEFAULT_DRV_ORDER; + ret.second = GetParam(params, NCBI_GBLOADER_PARAM_WRITER_NAME); + if ( ret.first.empty() ) { + ret.first = TGenbankWriterName::GetDefault(); } - NStr::ToLower(str); - return str; -} - - -string CGBDataLoader::GetWriterName(const TParamTree* params) const -{ - string str = GetParam(params, NCBI_GBLOADER_PARAM_WRITER_NAME); - if ( str.empty() ) { - // try config first - string env_reader = GetParam(params, NCBI_GBLOADER_PARAM_LOADER_METHOD); - if ( env_reader.empty() ) { - env_reader = TGenbankLoaderMethod::GetDefault(); + if ( ret.first.empty() || ret.second.empty() ) { + string method = GetParam(params, NCBI_GBLOADER_PARAM_LOADER_METHOD); + if ( method.empty() ) { + // try config first + method = TGenbankLoaderMethod::GetDefault(); + } + if ( method.empty() ) { + // fall back default reader list + method = DEFAULT_DRV_ORDER; + } + NStr::ToLower(method); + if ( ret.first.empty() ) { + ret.first = method; } - NStr::ToLower(env_reader); - if ( NStr::StartsWith(env_reader, "cache;") ) { - str = "cache"; + if ( ret.second.empty() && NStr::StartsWith(method, "cache;") ) { + ret.second = "cache"; } } - NStr::ToLower(str); - return str; + NStr::ToLower(ret.first); + NStr::ToLower(ret.second); + return ret; } @@ -638,6 +706,9 @@ bool CGBDataLoader::x_CreateReaders(const string& str, for ( size_t i = 0; i < str_list.size(); ++i ) { CRef reader(x_CreateReader(str_list[i], params)); if( reader ) { + if ( HasHUPIncluded() ) { + reader->SetIncludeHUP(); + } if ( preopen != CGBLoaderParams::ePreopenNever ) { reader->OpenInitialConnection(preopen == CGBLoaderParams::ePreopenAlways); } @@ -659,6 +730,10 @@ void CGBDataLoader::x_CreateWriters(const string& str, vector str_list; NStr::Split(str, ";", str_list); for ( size_t i = 0; i < str_list.size(); ++i ) { + if ( HasHUPIncluded() ) { + NCBI_THROW(CObjMgrException, eRegisterError, + "HUP GBLoader cannot have cache"); + } CRef writer(x_CreateWriter(str_list[i], params)); if( writer ) { m_Dispatcher->InsertWriter(i, writer); diff --git a/c++/src/objtools/data_loaders/genbank/gicache/CMakeLists.ncbi_xreader_gicache.lib.txt b/c++/src/objtools/data_loaders/genbank/gicache/CMakeLists.ncbi_xreader_gicache.lib.txt new file mode 100644 index 00000000..d7ae96b5 --- /dev/null +++ b/c++/src/objtools/data_loaders/genbank/gicache/CMakeLists.ncbi_xreader_gicache.lib.txt @@ -0,0 +1,12 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/data_loaders/genbank/gicache/Makefile.ncbi_xreader_gicache.lib +# +add_library(ncbi_xreader_gicache + reader_gicache gicache +) + +include_directories(${LMDB_INCLUDE} ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(ncbi_xreader_gicache + ncbi_xreader ${LMDB_LIBS} +) diff --git a/c++/src/objtools/data_loaders/genbank/gicache/CMakeLists.txt b/c++/src/objtools/data_loaders/genbank/gicache/CMakeLists.txt new file mode 100644 index 00000000..26291924 --- /dev/null +++ b/c++/src/objtools/data_loaders/genbank/gicache/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.ncbi_xreader_gicache.lib.txt) + diff --git a/c++/src/objtools/data_loaders/genbank/gicache/Makefile.in b/c++/src/objtools/data_loaders/genbank/gicache/Makefile.in index acda1292..dfc38b50 100644 --- a/c++/src/objtools/data_loaders/genbank/gicache/Makefile.in +++ b/c++/src/objtools/data_loaders/genbank/gicache/Makefile.in @@ -1,4 +1,4 @@ -# $Id: Makefile.in 514589 2016-09-22 17:28:21Z ivanov $ +# $Id: Makefile.in 511920 2016-08-25 17:29:10Z ucko $ LIB_PROJ = ncbi_xreader_gicache diff --git a/c++/src/objtools/data_loaders/genbank/gicache/Makefile.ncbi_xreader_gicache.lib b/c++/src/objtools/data_loaders/genbank/gicache/Makefile.ncbi_xreader_gicache.lib index 7ad030ef..f339c381 100644 --- a/c++/src/objtools/data_loaders/genbank/gicache/Makefile.ncbi_xreader_gicache.lib +++ b/c++/src/objtools/data_loaders/genbank/gicache/Makefile.ncbi_xreader_gicache.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.ncbi_xreader_gicache.lib 514596 2016-09-22 17:29:50Z ivanov $ +# $Id: Makefile.ncbi_xreader_gicache.lib 540088 2017-06-30 17:33:34Z ivanov $ REQUIRES = unix @@ -12,7 +12,7 @@ LIB_OR_DLL = both CPPFLAGS = $(LMDB_INCLUDE) -I$(srcdir) $(ORIG_CPPFLAGS) # Dependencies for shared library -DLL_LIB = ncbi_xreader$(DLL) +DLL_LIB = ncbi_xreader$(DLL) $(LMDB_LIB) LIBS = $(LMDB_LIBS) WATCHERS = vasilche diff --git a/c++/src/objtools/data_loaders/genbank/gicache/gicache.c b/c++/src/objtools/data_loaders/genbank/gicache/gicache.c index 5c939422..f2ccbd7d 100644 --- a/c++/src/objtools/data_loaders/genbank/gicache/gicache.c +++ b/c++/src/objtools/data_loaders/genbank/gicache/gicache.c @@ -1,5 +1,5 @@ /***************************************************************************** -* $Id: gicache.c 514594 2016-09-22 17:29:29Z ivanov $ +* $Id: gicache.c 518770 2016-11-07 19:47:02Z syncbot $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -40,6 +40,7 @@ #include #include #include +#include #include #include "gicache.h" @@ -72,7 +73,49 @@ typedef struct { static SGiDataIndex *gi_cache = NULL; -static void (*LogFunc)(char*) = NULL; +static void (*__LogFunc)(char*) = NULL; +static void (*__LogFuncEx)(int severity, char* msg) = NULL; + +static void LOG(int severity, char* fmt, ...) +#ifdef __GNUC__ +__attribute__ ((format (printf, 2, 3))) +#endif +; + +#define SEV_NONE 0 +#define SEV_INFO 1 +#define SEV_WARNING 2 +#define SEV_ERROR 3 +#define SEV_REJECT 4 +#define SEV_FATAL 5 + +static void LOG(int severity, char* fmt, ...) +{ + if (__LogFuncEx || __LogFunc) { + char msg[2048]; + va_list args; + va_start(args, fmt); + int n = vsnprintf(msg, sizeof(msg), fmt, args); + if (n >= sizeof(msg) - 1) + n = sizeof(msg) - 1; + msg[n] = '\0'; + va_end(args); + if (__LogFuncEx) + __LogFuncEx(severity, msg); + if (__LogFunc) + __LogFunc(msg); + } +} + +static int x_mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **txn) { + int rv; + rv = mdb_txn_begin(env, parent, flags, txn); + if (rv == MDB_READERS_FULL) { + mdb_reader_check(env, NULL); + rv = mdb_txn_begin(env, parent, flags, txn); + } + return rv; +} int x_Commit(SGiDataIndex* data_index) { int rv = 0; @@ -82,10 +125,7 @@ int x_Commit(SGiDataIndex* data_index) { data_index->m_txn = NULL; data_index->m_txn_rowcount = 0; if (rc) { - char logmsg[256]; - snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to commit transaction: %s\n", mdb_strerror(rc)); - if (LogFunc) - LogFunc(logmsg); + LOG(SEV_ERROR, "GI_CACHE: failed to commit transaction: %s\n", mdb_strerror(rc)); rv = -1; } } @@ -118,6 +158,13 @@ static void GiDataIndex_Free(SGiDataIndex* data_index) { } } +static int +xFindFile(SGiDataIndex* data_index, struct stat* fstat) { + int rv; + rv = stat(data_index->m_FileName, fstat); + return rv; +} + /* Constructor */ static SGiDataIndex* GiDataIndex_New(const char* prefix, Uint1 readonly, Uint1 enablesync) { @@ -125,12 +172,25 @@ GiDataIndex_New(const char* prefix, Uint1 readonly, Uint1 enablesync) { char logmsg[256]; SGiDataIndex* data_index; struct stat fstat; + int fstat_err; MDB_txn *txn = 0; - int strc; int64_t mapsize; data_index = (SGiDataIndex*) malloc(sizeof(SGiDataIndex)); memset(data_index, 0, sizeof(SGiDataIndex)); + data_index->m_ReadOnlyMode = readonly; + assert(strlen(prefix) < PATH_MAX); + snprintf(data_index->m_FileName, sizeof(data_index->m_FileName), "%s.db", prefix); + fstat_err = xFindFile(data_index, &fstat); + if (fstat_err != 0 || fstat.st_size == 0) { + /* file does not exist */ + enablesync = 0; + if (readonly) { + rc = errno; + snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to access file (%s): %s\n", data_index->m_FileName, strerror(rc)); + goto ERROR; + } + } rc = mdb_env_create(&data_index->m_env); if (rc) { @@ -150,20 +210,8 @@ GiDataIndex_New(const char* prefix, Uint1 readonly, Uint1 enablesync) { goto ERROR; } - data_index->m_ReadOnlyMode = readonly; - assert(strlen(prefix) < PATH_MAX); - snprintf(data_index->m_FileName, sizeof(data_index->m_FileName), "%s.db", prefix); - - strc = stat(data_index->m_FileName, &fstat); - - if (readonly && (strc != 0 || fstat.st_size == 0)) { - rc = errno; - snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to access file (%s): %s\n", data_index->m_FileName, strerror(rc)); - goto ERROR; - } - mapsize = MAP_SIZE_INIT; - if (strc == 0 && fstat.st_size + MAP_SIZE_DELTA > mapsize) + if (fstat_err == 0 && fstat.st_size + MAP_SIZE_DELTA > mapsize) mapsize = fstat.st_size + MAP_SIZE_DELTA; rc = mdb_env_set_mapsize(data_index->m_env, mapsize); @@ -172,13 +220,13 @@ GiDataIndex_New(const char* prefix, Uint1 readonly, Uint1 enablesync) { goto ERROR; } - rc = mdb_env_open(data_index->m_env, data_index->m_FileName, MDB_NOSUBDIR | (readonly ? MDB_RDONLY : 0) | (enablesync ? MDB_MAPASYNC : (MDB_NOSYNC | MDB_NOMETASYNC)), 0644); + rc = mdb_env_open(data_index->m_env, data_index->m_FileName, MDB_NOSUBDIR | (readonly ? MDB_RDONLY : 0) | (enablesync ? 0 : (MDB_NOSYNC | MDB_NOMETASYNC)), 0644); if (rc) { snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to open LMDB db (%s): %s\n", data_index->m_FileName, mdb_strerror(rc)); goto ERROR; } - rc = mdb_txn_begin(data_index->m_env, NULL, readonly ? MDB_RDONLY : 0, &txn); + rc = x_mdb_txn_begin(data_index->m_env, NULL, readonly ? MDB_RDONLY : 0, &txn); if (rc) { snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to start transaction: %s\n", mdb_strerror(rc)); goto ERROR; @@ -201,7 +249,12 @@ GiDataIndex_New(const char* prefix, Uint1 readonly, Uint1 enablesync) { snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to commit transaction: %s\n", mdb_strerror(rc)); goto ERROR; } - + + rc = mdb_reader_check(data_index->m_env, NULL); + if (rc) { + snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to check readers: %s\n", mdb_strerror(rc)); + goto ERROR; + } return data_index; @@ -212,8 +265,7 @@ ERROR: } GiDataIndex_Free(data_index); data_index = NULL; - if (LogFunc) - LogFunc(logmsg); + LOG(SEV_ERROR, logmsg); return NULL; } @@ -226,9 +278,7 @@ static int x_DataToGiData(int64_t gi, MDB_val *data, char *acc_buf, int acc_buf_ char* pacc = (char*)data->mv_data + gi_len_bytes + 2; if (acclen >= MAX_ACCESSION_LENGTH) { - snprintf(logmsg, sizeof(logmsg), "GI_CACHE: accession length (%d) exceeded limit (%d) for gi: %" PRId64 "\n", acclen, MAX_ACCESSION_LENGTH, gi); - if (LogFunc) - LogFunc(logmsg); + LOG(SEV_ERROR, "GI_CACHE: accession length (%d) exceeded limit (%d) for gi: %" PRId64 "\n", acclen, MAX_ACCESSION_LENGTH, gi); return 1; } @@ -245,9 +295,7 @@ static int x_DataToGiData(int64_t gi, MDB_val *data, char *acc_buf, int acc_buf_ } if (acc_buf) { if (acc_buf_len <= acclen) { - snprintf(logmsg, sizeof(logmsg), "GI_CACHE: accession length buffer length (%d) is too small, actual accession length is %d for gi: %" PRId64 "\n", acc_buf_len, acclen, gi); - if (LogFunc) - LogFunc(logmsg); + LOG(SEV_ERROR, "GI_CACHE: accession length buffer length (%d) is too small, actual accession length is %d for gi: %" PRId64 "\n", acc_buf_len, acclen, gi); return 1; } memcpy(acc_buf, pacc, acclen); @@ -275,7 +323,7 @@ static int x_GetGiData(SGiDataIndex* data_index, int64_t gi, char *acc_buf, int goto ERROR; } - rc = mdb_txn_begin(data_index->m_env, NULL, MDB_RDONLY, &txn); + rc = x_mdb_txn_begin(data_index->m_env, NULL, MDB_RDONLY, &txn); if (rc) { snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to start transaction: %s\n", mdb_strerror(rc)); goto ERROR; @@ -285,8 +333,10 @@ static int x_GetGiData(SGiDataIndex* data_index, int64_t gi, char *acc_buf, int key.mv_size = sizeof(gi64); key.mv_data = &gi64; rc = mdb_get(txn, data_index->m_gi_dbi, &key, &data); - if (rc == MDB_NOTFOUND) // silent error + if (rc == MDB_NOTFOUND) { // silent error + LOG(SEV_INFO, "cache-miss for gi=%" PRId64, gi); goto ERROR; + } if (rc) { snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to get data for gi=%" PRId64 ": %s\n", gi, mdb_strerror(rc)); goto ERROR; @@ -309,8 +359,8 @@ ERROR: mdb_txn_abort(txn); txn = NULL; } - if (LogFunc && logmsg[0]) { - LogFunc(logmsg); + if (logmsg[0]) { + LOG(SEV_ERROR, logmsg); } return 0; } @@ -324,7 +374,7 @@ static int64_t x_GetMaxGi(SGiDataIndex* data_index) { MDB_val data = {0}; int64_t gi64 = 0; - rc = mdb_txn_begin(data_index->m_env, NULL, MDB_RDONLY, &txn); + rc = x_mdb_txn_begin(data_index->m_env, NULL, MDB_RDONLY, &txn); if (rc) { snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to start transaction: %s\n", mdb_strerror(rc)); goto ERROR; @@ -371,9 +421,7 @@ ERROR: mdb_txn_abort(txn); txn = NULL; } - if (LogFunc) { - LogFunc(logmsg); - } + LOG(SEV_ERROR, logmsg); return -1; } @@ -415,7 +463,7 @@ static int x_PutData(SGiDataIndex* data_index, int64_t gi, int64_t gi_len, const } if (!data_index->m_txn) { - rc = mdb_txn_begin(data_index->m_env, NULL, 0, &data_index->m_txn); + rc = x_mdb_txn_begin(data_index->m_env, NULL, 0, &data_index->m_txn); if (rc) { data_index->m_txn = NULL; snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to start transaction: %s\n", mdb_strerror(rc)); @@ -473,8 +521,8 @@ ERROR: mdb_txn_abort(data_index->m_txn); data_index->m_txn = NULL; } - if (LogFunc && logmsg[0]) { - LogFunc(logmsg); + if (logmsg[0]) { + LOG(SEV_ERROR, logmsg); } return 0; } @@ -515,22 +563,26 @@ int GICache_ReadData(const char *prefix) { return rc; } -int GICache_GetAccession(int64_t gi, char* acc, int buf_len) { +/* Retrieves accession.version and gi length by gi. */ +int GICache_GetAccessionLen(int64_t gi, char* acc, int buf_len, int64_t* gi_len) { int retval = 0; int rv; if (acc && buf_len > 0) acc[0] = NULLB; if (!gi_cache) { - if (LogFunc) - LogFunc("GICache_GetAccession: GI Cache is not initialized, call GICache_ReadData() first"); + LOG(SEV_ERROR, "GICache_GetAccession: GI Cache is not initialized, call GICache_ReadData() first"); return 0; } - rv = x_GetGiData(gi_cache, gi, acc, buf_len, NULL); + rv = x_GetGiData(gi_cache, gi, acc, buf_len, gi_len); if (rv) retval = 1; return retval; } +int GICache_GetAccession(int64_t gi, char* acc, int buf_len) { + return GICache_GetAccessionLen(gi, acc, buf_len, NULL); +} + int64_t GICache_GetLength(int64_t gi) { int rv; int64_t gi_len = 0; @@ -586,10 +638,14 @@ int GICache_LoadEnd() { } void GICache_SetLog(void (*logfunc)(char*)) { - LogFunc = logfunc; + __LogFunc = logfunc; +} + +void GICache_SetLogEx(void (*logfunc)(int severity, char* msg)) { + __LogFuncEx = logfunc; } -void GICache_Dump(const char* cache_prefix, const char* filename) { +void GICache_Dump(const char* cache_prefix, const char* filename, volatile int * quitting) { FILE* f; char logmsg[256]; int needopen; @@ -611,7 +667,7 @@ void GICache_Dump(const char* cache_prefix, const char* filename) { } setvbuf(f, NULL, _IOFBF, 128 * 1024); - rc = mdb_txn_begin(gi_cache->m_env, NULL, MDB_RDONLY, &txn); + rc = x_mdb_txn_begin(gi_cache->m_env, NULL, MDB_RDONLY, &txn); if (rc) { snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to start transaction: %s\n", mdb_strerror(rc)); goto ERROR; @@ -632,9 +688,7 @@ void GICache_Dump(const char* cache_prefix, const char* filename) { int64_t gi64 = 0; if (!key.mv_data || key.mv_size != sizeof(gi64)) { - snprintf(logmsg, sizeof(logmsg), "GI_CACHE: last record contains no valid gi\n"); - if (LogFunc) - LogFunc(logmsg); + LOG(SEV_ERROR, "GI_CACHE: last record contains no valid gi\n"); continue; } gi64 = *(int64_t*)key.mv_data; @@ -643,6 +697,8 @@ void GICache_Dump(const char* cache_prefix, const char* filename) { snprintf(line, sizeof(line), "%" PRId64 " %s %" PRId64 "\n", gi64, acc_buf, gi_len); fputs(line, f); } + if (quitting && *quitting) + break; } mdb_cursor_close(cur); @@ -674,9 +730,7 @@ ERROR: mdb_txn_abort(txn); txn = NULL; } - if (LogFunc) { - LogFunc(logmsg); - } + LOG(SEV_ERROR, logmsg); if (needopen) { GICache_ReadEnd(); } @@ -700,7 +754,7 @@ int GICache_DropDb() { snprintf(logmsg, sizeof(logmsg), "GICache_DropDb: failed to drop DB, database has an active transaction"); goto ERROR; } - rc = mdb_txn_begin(gi_cache->m_env, NULL, 0, &gi_cache->m_txn); + rc = x_mdb_txn_begin(gi_cache->m_env, NULL, 0, &gi_cache->m_txn); if (rc) { snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to start transaction: %s\n", mdb_strerror(rc)); goto ERROR; @@ -725,9 +779,7 @@ int GICache_DropDb() { return 0; ERROR: - if (LogFunc) { - LogFunc(logmsg); - } + LOG(SEV_ERROR, logmsg); if (gi_cache && gi_cache->m_txn && transtarted) { mdb_txn_abort(gi_cache->m_txn); gi_cache->m_txn = NULL; @@ -752,12 +804,8 @@ static int x_PutMeta(const char* Name, const char* Value) { if (rc == MDB_NOTFOUND) rc = 0; } - if (rc) { - char logmsg[256]; - snprintf(logmsg, sizeof(logmsg), "GICache_UpdateMeta: failed to update META: %s\n", mdb_strerror(rc)); - if (LogFunc) - LogFunc(logmsg); - } + if (rc) + LOG(SEV_ERROR, "GICache_UpdateMeta: failed to update META: %s\n", mdb_strerror(rc)); return rc; } @@ -780,7 +828,7 @@ int GICache_SetMeta(const char* Name, const char* Value) { snprintf(logmsg, sizeof(logmsg), "GICache_SetMeta: failed to update META, database has an active transaction"); goto ERROR; } - rc = mdb_txn_begin(gi_cache->m_env, NULL, 0, &gi_cache->m_txn); + rc = x_mdb_txn_begin(gi_cache->m_env, NULL, 0, &gi_cache->m_txn); if (rc) { snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to start transaction: %s\n", mdb_strerror(rc)); goto ERROR; @@ -797,8 +845,8 @@ int GICache_SetMeta(const char* Name, const char* Value) { return 0; ERROR: - if (LogFunc && logmsg[0]) { - LogFunc(logmsg); + if (logmsg[0]) { + LOG(SEV_ERROR, logmsg); } if (gi_cache && gi_cache->m_txn && transtarted) { mdb_txn_abort(gi_cache->m_txn); @@ -827,8 +875,8 @@ int GICache_UpdateMeta(int is_incremental, const char* DB, time_t starttime) { goto ERROR; return 0; ERROR: - if (LogFunc && logmsg[0]) { - LogFunc(logmsg); + if (logmsg[0]) { + LOG(SEV_ERROR, logmsg); } return 1; } @@ -846,7 +894,7 @@ int GICache_GetMeta(const char* Name, char* Value, size_t ValueSz) { snprintf(logmsg, sizeof(logmsg), "GICache_GetMeta: failed to read META, database is not open"); goto ERROR; } - rc = mdb_txn_begin(gi_cache->m_env, NULL, MDB_RDONLY, &txn); + rc = x_mdb_txn_begin(gi_cache->m_env, NULL, MDB_RDONLY, &txn); if (rc) { snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to start transaction: %s\n", mdb_strerror(rc)); goto ERROR; @@ -873,8 +921,8 @@ int GICache_GetMeta(const char* Name, char* Value, size_t ValueSz) { return 0; ERROR: - if (LogFunc && logmsg[0]) { - LogFunc(logmsg); + if (logmsg[0]) { + LOG(SEV_ERROR, logmsg); } if (gi_cache && txn) { mdb_txn_abort(txn); @@ -900,7 +948,7 @@ int GICache_GetAccFreqTab(FreqTab* tab, const FreqTab* tablen) { goto ERROR; } - rc = mdb_txn_begin(gi_cache->m_env, NULL, MDB_RDONLY, &txn); + rc = x_mdb_txn_begin(gi_cache->m_env, NULL, MDB_RDONLY, &txn); if (rc) { snprintf(logmsg, sizeof(logmsg), "GI_CACHE: failed to start transaction: %s\n", mdb_strerror(rc)); goto ERROR; @@ -921,9 +969,7 @@ int GICache_GetAccFreqTab(FreqTab* tab, const FreqTab* tablen) { int64_t gi64 = 0; if (!key.mv_data || key.mv_size != sizeof(gi64)) { - snprintf(logmsg, sizeof(logmsg), "GI_CACHE: record contains no valid gi\n"); - if (LogFunc) - LogFunc(logmsg); + LOG(SEV_ERROR, "GI_CACHE: record contains no valid gi\n"); continue; } gi64 = *(int64_t*)key.mv_data; @@ -977,8 +1023,8 @@ ERROR: mdb_txn_abort(txn); txn = NULL; } - if (LogFunc && logmsg[0]) { - LogFunc(logmsg); + if (logmsg[0]) { + LOG(SEV_ERROR, logmsg); } return -1; diff --git a/c++/src/objtools/data_loaders/genbank/gicache/gicache.h b/c++/src/objtools/data_loaders/genbank/gicache/gicache.h index b00660f1..823b3d9a 100644 --- a/c++/src/objtools/data_loaders/genbank/gicache/gicache.h +++ b/c++/src/objtools/data_loaders/genbank/gicache/gicache.h @@ -23,6 +23,12 @@ typedef struct { int64_t Count[256]; } FreqTab; +#ifdef __GNUC__ +#define DEPRECATED __attribute__ ((deprecated)); +#else +#define DEPRECATED +#endif + /* Initializes the cache. If cache_prefix argument is not provided, default name * is used. If local cache is not available, use default path and prefix. * Return value: 0 on success, 1 on failure. @@ -35,6 +41,8 @@ int GICache_ReadData(const char *cache_prefix); * is 0, otherwise return code is 1. */ int GICache_GetAccession(int64_t gi, char* acc, int buf_len); +/* Retrieves accession.version and gi length by gi. */ +int GICache_GetAccessionLen(int64_t gi, char* acc, int buf_len, int64_t* gi_len); /* Retrieves gi length */ int64_t GICache_GetLength(int64_t gi); /* Returns maximal gi available in cache */ @@ -58,10 +66,12 @@ int GICache_SetMeta(const char* Name, const char* Value); int GICache_UpdateMeta(int is_incremental, const char* DB, time_t starttime); /* Retrieve meta info */ int GICache_GetMeta(const char* Name, char* Value, size_t ValueSz); -/* Install logger CB */ -void GICache_SetLog(void (*logfunc)(char*)); +/* Install logger CB *DEPRECATED* */ +void GICache_SetLog(void (*logfunc)(char*)) DEPRECATED; +/* Install logger CB, severity is actually of ErrSev enum type */ +void GICache_SetLogEx(void (*logfunc)(int severity, char* msg)); /* Dumps out content of the cache. Result is a text file with 3 columns: gi, accession, length */ -void GICache_Dump(const char* cache_prefix, const char* filename); +void GICache_Dump(const char* cache_prefix, const char* filename, volatile int * quitting); int GICache_GetAccFreqTab(FreqTab* tab, const FreqTab* tablen); #ifdef __cplusplus } diff --git a/c++/src/objtools/data_loaders/genbank/gicache/reader_gicache.cpp b/c++/src/objtools/data_loaders/genbank/gicache/reader_gicache.cpp index 1c485cc9..b2cd6f6b 100644 --- a/c++/src/objtools/data_loaders/genbank/gicache/reader_gicache.cpp +++ b/c++/src/objtools/data_loaders/genbank/gicache/reader_gicache.cpp @@ -1,4 +1,4 @@ -/* $Id: reader_gicache.cpp 514597 2016-09-22 17:30:12Z ivanov $ +/* $Id: reader_gicache.cpp 512980 2016-09-06 16:00:18Z vasilche $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information diff --git a/c++/src/objtools/data_loaders/genbank/id1/CMakeLists.ncbi_xreader_id1.lib.txt b/c++/src/objtools/data_loaders/genbank/id1/CMakeLists.ncbi_xreader_id1.lib.txt new file mode 100644 index 00000000..948160ed --- /dev/null +++ b/c++/src/objtools/data_loaders/genbank/id1/CMakeLists.ncbi_xreader_id1.lib.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/data_loaders/genbank/id1/Makefile.ncbi_xreader_id1.lib +# +add_library(ncbi_xreader_id1 + reader_id1 +) +include_directories(SYSTEM ${CMPRS_INCLUDE}) + +target_link_libraries(ncbi_xreader_id1 + ncbi_xreader +) +add_dependencies(ncbi_xreader_id1 + id1 id2 +) + diff --git a/c++/src/objtools/data_loaders/genbank/id1/CMakeLists.txt b/c++/src/objtools/data_loaders/genbank/id1/CMakeLists.txt new file mode 100644 index 00000000..f2797769 --- /dev/null +++ b/c++/src/objtools/data_loaders/genbank/id1/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.ncbi_xreader_id1.lib.txt) + diff --git a/c++/src/objtools/data_loaders/genbank/id1/Makefile.ncbi_xreader_id1.lib b/c++/src/objtools/data_loaders/genbank/id1/Makefile.ncbi_xreader_id1.lib index 7959ffb1..abce7716 100644 --- a/c++/src/objtools/data_loaders/genbank/id1/Makefile.ncbi_xreader_id1.lib +++ b/c++/src/objtools/data_loaders/genbank/id1/Makefile.ncbi_xreader_id1.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.ncbi_xreader_id1.lib 427429 2014-02-20 13:41:40Z gouriano $ +# $Id: Makefile.ncbi_xreader_id1.lib 521293 2016-12-07 17:11:15Z ucko $ SRC = reader_id1 @@ -10,7 +10,7 @@ ASN_DEP = id1 id2 LIB_OR_DLL = both # Dependencies for shared library -DLL_LIB = xconnect ncbi_xreader$(DLL) +DLL_LIB = ncbi_xreader$(DLL) $(GENBANK_READER_LDEP) CPPFLAGS = $(ORIG_CPPFLAGS) $(CMPRS_INCLUDE) diff --git a/c++/src/objtools/data_loaders/genbank/id2/CMakeLists.ncbi_xreader_id2.lib.txt b/c++/src/objtools/data_loaders/genbank/id2/CMakeLists.ncbi_xreader_id2.lib.txt new file mode 100644 index 00000000..98f1c73f --- /dev/null +++ b/c++/src/objtools/data_loaders/genbank/id2/CMakeLists.ncbi_xreader_id2.lib.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/data_loaders/genbank/id2/Makefile.ncbi_xreader_id2.lib +# +add_library(ncbi_xreader_id2 + reader_id2 +) +include_directories(SYSTEM ${Z_INCLUDE}) + +add_dependencies(ncbi_xreader_id2 + id2 +) + +target_link_libraries(ncbi_xreader_id2 + ncbi_xreader +) diff --git a/c++/src/objtools/data_loaders/genbank/id2/CMakeLists.txt b/c++/src/objtools/data_loaders/genbank/id2/CMakeLists.txt new file mode 100644 index 00000000..b1c24442 --- /dev/null +++ b/c++/src/objtools/data_loaders/genbank/id2/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.ncbi_xreader_id2.lib.txt) + diff --git a/c++/src/objtools/data_loaders/genbank/processors.cpp b/c++/src/objtools/data_loaders/genbank/processors.cpp index 9f460524..8e5ac52a 100644 --- a/c++/src/objtools/data_loaders/genbank/processors.cpp +++ b/c++/src/objtools/data_loaders/genbank/processors.cpp @@ -1,4 +1,4 @@ -/* $Id: processors.cpp 507982 2016-07-22 19:52:48Z vasilche $ +/* $Id: processors.cpp 522272 2016-12-16 17:07:55Z vasilche $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information @@ -887,12 +887,14 @@ void CProcessor::LoadWGSMaster(CDataLoader* loader, CSeq_id_Handle id = chunk_info.m_MasterId; int mask = chunk_info.m_DescrMask; CRef descr = s_GetWGSMasterDescr(loader, id, mask); - if ( kAddMasterDescrToTSE ) { - chunk->x_LoadDescr(CTSE_Chunk_Info::TPlace(), *descr); - } - else { - CRef upd(new CWGSBioseqUpdaterDescr(id, descr)); - const_cast(chunk->GetSplitInfo()).x_SetBioseqUpdater(upd); + if ( descr ) { + if ( kAddMasterDescrToTSE ) { + chunk->x_LoadDescr(CTSE_Chunk_Info::TPlace(), *descr); + } + else { + CRef upd(new CWGSBioseqUpdaterDescr(id, descr)); + const_cast(chunk->GetSplitInfo()).x_SetBioseqUpdater(upd); + } } chunk->SetLoaded(); } diff --git a/c++/src/objtools/data_loaders/genbank/reader.cpp b/c++/src/objtools/data_loaders/genbank/reader.cpp index afdf9aae..8bb12a14 100644 --- a/c++/src/objtools/data_loaders/genbank/reader.cpp +++ b/c++/src/objtools/data_loaders/genbank/reader.cpp @@ -1,4 +1,4 @@ -/* $Id: reader.cpp 493171 2016-02-24 19:31:13Z vasilche $ +/* $Id: reader.cpp 534193 2017-04-25 14:00:21Z vasilche $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information @@ -72,7 +72,8 @@ CReader::CDebugPrinter::CDebugPrinter(const char* name) CReader::CDebugPrinter::~CDebugPrinter() { - LOG_POST_X(9, Info << SetPostFlags(eDPF_DateTime|eDPF_TID) << rdbuf()); + LOG_POST_X(9, Info << SetPostFlags(eDPF_DateTime|eDPF_TID) << + CNcbiOstrstreamToString(*this)); } @@ -577,7 +578,7 @@ bool CReader::LoadSequenceHash(CReaderRequestResult& result, hash.sequence_found = ids.GetSeq_ids().IsFound(); // no hash information by default } - result.SetLoadedHash(seq_id, TSequenceHash()); + result.SetLoadedHash(seq_id, hash); } return true; } @@ -1304,6 +1305,13 @@ void CReader::ResetCache(void) } +void CReader::SetIncludeHUP(bool include_hup) +{ + NCBI_THROW(CObjMgrException, eRegisterError, + "HUP is supported only by pubseqos or pubseqos2 readers"); +} + + CReaderCacheManager::CReaderCacheManager(void) { } diff --git a/c++/src/objtools/data_loaders/genbank/reader_id1_base.cpp b/c++/src/objtools/data_loaders/genbank/reader_id1_base.cpp index 92b49a51..653e6a8e 100644 --- a/c++/src/objtools/data_loaders/genbank/reader_id1_base.cpp +++ b/c++/src/objtools/data_loaders/genbank/reader_id1_base.cpp @@ -1,4 +1,4 @@ -/* $Id: reader_id1_base.cpp 493171 2016-02-24 19:31:13Z vasilche $ +/* $Id: reader_id1_base.cpp 536514 2017-05-19 14:04:58Z vasilche $ * =========================================================================== * PUBLIC DOMAIN NOTICE * National Center for Biotechnology Information @@ -33,12 +33,15 @@ #include #include #include +#include #include #include #include #include +#define NCBI_USE_ERRCODE_X Objtools_Reader_Id1 + BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) @@ -118,6 +121,13 @@ bool CId1ReaderBase::LoadChunk(CReaderRequestResult& result, } GetBlob(result, blob_id, chunk_id); + if ( !blob.IsLoadedChunk() ) { + CLoadLockSetter setter(blob); + if ( !setter.IsLoaded() ) { + ERR_POST_X(1, "ExtAnnot chunk is not loaded: "<, it, proc_list ) { const string& proc_name = *it; - CRef proc; + SProcessorInfo info; try { - proc = CPluginManagerGetter::Get()-> + info.processor = CPluginManagerGetter::Get()-> CreateInstance(proc_name); } catch ( CException& exc ) { ERR_POST_X(15, "CId2ReaderBase: " "cannot load ID2 processor "<CreateContext(); // send init request CID2_Request req; req.SetRequest().SetInit(); x_SetContextData(req); CID2_Request_Packet packet; packet.Set().push_back(Ref(&req)); - proc->ProcessSomeRequests(packet); - m_Processors.push_back(proc); + CID2Processor::TReplies replies; + info.processor->ProcessPacket(info.context, packet, replies); + m_Processors.push_back(info); } } } @@ -1583,99 +1588,26 @@ struct SId2PacketInfo struct SId2PacketReplies { - typedef vector< CRef > TRequestReplies; + typedef CID2Processor::TReplies TRequestReplies; vector replies; }; -class CId2ReaderProcessorResolver : public CID2ProcessorResolver +struct SId2ProcessorStage { -public: - CId2ReaderProcessorResolver(CId2ReaderBase& reader, - CReaderRequestResult& result) - : m_Reader(reader), - m_RequestResult(result) - { - } - - virtual TIds GetIds(const CSeq_id& id) - { - TIds ret; - CSeq_id_Handle idh = CSeq_id_Handle::GetHandle(id); - CLoadLockSeqIds lock(m_RequestResult, idh); - if ( !lock.IsLoaded() ) { - CReaderRequestResultRecursion recurse(m_RequestResult, true); - m_Reader.m_Dispatcher->LoadSeq_idSeq_ids(m_RequestResult, idh); - } - CFixedSeq_ids ids = lock.GetSeq_ids(); - ITERATE ( CFixedSeq_ids, it, ids ) { - ret.push_back(it->GetSeqId()); - } - return ret; - } - - /* - CRef MakeReply(const CID2_Request& req) - { - CRef reply(new CID2_Reply); - if ( req.IsSetSerial_number() ) { - reply->SetSerial_number(req.GetSerial_number()); - } - return reply; - } - - void ProcessGetBlobIds(TReplies& replies, - const CID2_Request& req) - { - auto reply = MakeReply(req); - - CRef error(new CID2_Error); - error->SetSeverity(CID2_Error::eSeverity_unsupported_command); - reply->SetError().push_back(error); - reply->SetReply().SetEmpty(); - - replies.push_back(reply); - replies.back()->SetEnd_of_reply(); - } - - void ProcessOther(TReplies& replies, - const CID2_Request& req) - { - auto reply = MakeReply(req); - - CRef error(new CID2_Error); - error->SetSeverity(CID2_Error::eSeverity_unsupported_command); - reply->SetError().push_back(error); - reply->SetReply().SetEmpty(); - - replies.push_back(reply); - replies.back()->SetEnd_of_reply(); - } + CRef packet_context; + CID2Processor::TReplies replies; // in backward order to use pop_back() +}; - void ProcessRequest(TReplies& replies, - const CID2_Request& req) - { - switch ( req.GetRequest().Which() ) { - case CID2_Request::TRequest::e_Get_blob_id: - ProcessGetBlobIds(replies, req); - break; - default: - ProcessOther(replies, req); - break; - } - } - */ - virtual void ProcessPacket(TReplies& replies, - CID2_Request_Packet& packet) - { - SId2PacketReplies replies2; - m_Reader.x_GetPacketReplies(m_RequestResult, replies2, packet); - } +struct SId2ProcessingState +{ + vector stages; + unique_ptr conn; -private: - CId2ReaderBase& m_Reader; - CReaderRequestResult& m_RequestResult; + CReader::TConn GetConn() const { + return conn? *conn: 0; + } }; @@ -1695,6 +1627,10 @@ void CId2ReaderBase::x_SetContextData(CID2_Request& request) // enable VDB-based WGS sequences param->SetValue().push_back("vdb-wgs"); } + if ( NCBI_PARAM_TYPE(GENBANK, VDB_SNP)::GetDefault() ) { + // enable VDB-based SNP sequences + param->SetValue().push_back("vdb-snp"); + } request.SetParams().Set().push_back(param); } } @@ -1715,11 +1651,12 @@ void CId2ReaderBase::x_SetContextData(CID2_Request& request) void CId2ReaderBase::x_DumpPacket(TConn conn, - const CID2_Request_Packet& packet) + const CID2_Request_Packet& packet, + const char* msg) { if ( GetDebugLevel() >= eTraceConn ) { CDebugPrinter s(conn, "CId2Reader"); - s << "Sending"; + s << msg; if ( GetDebugLevel() >= eTraceASN ) { s << ": " << MSerial_AsnText << packet; } @@ -1732,12 +1669,12 @@ void CId2ReaderBase::x_DumpPacket(TConn conn, void CId2ReaderBase::x_DumpReply(TConn conn, - const char* source, - CID2_Reply& reply) + CID2_Reply& reply, + const char* msg) { if ( GetDebugLevel() >= eTraceConn ) { CDebugPrinter s(0, "CId2Reader"); - s << "Received" << source; + s << msg; if ( GetDebugLevel() >= eTraceASN ) { if ( GetDebugLevel() >= eTraceBlobData ) { s << ": " << MSerial_AsnText << reply; @@ -1821,7 +1758,112 @@ CRef CId2ReaderBase::x_ReceiveFromConnection(TConn conn) "reply deserialization failed: "+ x_ConnDescription(conn)); } - x_DumpReply(conn, "", *reply); + x_DumpReply(conn, *reply); + CProcessor::OffsetAllGisToOM(*reply); + return reply; +} + + +void CId2ReaderBase::x_SendID2Packet(CReaderRequestResult& result, + SId2ProcessingState& state, + CID2_Request_Packet& packet) +{ + CProcessor::OffsetAllGisFromOM(packet); + x_DumpPacket(0, packet, "Processing"); + size_t proc_count = m_Processors.size(); + state.stages.reserve(proc_count); + for ( size_t i = 0; i < proc_count; ++i ) { + if ( packet.Get().empty() ) { + return; + } + state.stages.resize(i+1); + SProcessorInfo& info = m_Processors[i]; + SId2ProcessorStage& stage = state.stages[i]; + stage.packet_context = info.processor->ProcessPacket(info.context, packet, stage.replies); + if ( GetDebugLevel() >= eTraceConn && + !stage.replies.empty() ) { + x_DumpPacket(0, packet, "Filtered"); + for ( auto& it : stage.replies ) { + x_DumpReply(0, *it, "Got from processor"); + } + } + reverse(stage.replies.begin(), stage.replies.end()); + } + if ( packet.Get().empty() ) { + return; + } + state.conn.reset(new CConn(result, this)); + TConn conn = state.GetConn(); + try { + if ( GetDebugLevel() >= eTraceConn ) { + CDebugPrinter s(conn, "CId2Reader"); + s << "Sending ID2-Request-Packet..."; + } + x_SendPacket(conn, packet); + if ( GetDebugLevel() >= eTraceConn ) { + CDebugPrinter s(conn, "CId2Reader"); + s << "Sent ID2-Request-Packet."; + } + } + catch ( CException& exc ) { + NCBI_RETHROW(exc, CLoaderException, eConnectionFailed, + "failed to send request: "+ + x_ConnDescription(conn)); + } +} + + +CRef CId2ReaderBase::x_ReceiveID2ReplyStage(SId2ProcessingState& state, size_t pos) +{ + if ( pos < state.stages.size() ) { + SId2ProcessorStage& stage = state.stages[pos]; + SProcessorInfo& info = m_Processors[pos]; + while ( stage.replies.empty() ) { + CRef reply = x_ReceiveID2ReplyStage(state, pos+1); + info.processor->ProcessReply(info.context, stage.packet_context, *reply, stage.replies); + if ( GetDebugLevel() >= eTraceConn && + (stage.replies.size() != 1 || stage.replies[0] != reply) ) { + x_DumpReply(0, *reply, "Filtered by processor"); + for ( auto& it : stage.replies ) { + x_DumpReply(0, *it, "New from processor"); + } + } + reverse(stage.replies.begin(), stage.replies.end()); + } + CRef reply = stage.replies.back(); + stage.replies.pop_back(); + return reply; + } + else { + _ASSERT(state.conn); + TConn conn = state.GetConn(); + for (;;) { + if ( GetDebugLevel() >= eTraceConn ) { + CDebugPrinter s(conn, "CId2Reader"); + s << "Receiving ID2-Reply..."; + } + CRef reply(new CID2_Reply); + try { + x_ReceiveReply(conn, *reply); + } + catch ( CException& exc ) { + NCBI_RETHROW(exc, CLoaderException, eConnectionFailed, + "reply deserialization failed: "+ + x_ConnDescription(conn)); + } + x_DumpReply(conn, *reply); + if ( reply->IsSetDiscard() ) { + continue; + } + return reply; + } + } +} + + +CRef CId2ReaderBase::x_ReceiveID2Reply(SId2ProcessingState& state) +{ + CRef reply = x_ReceiveID2ReplyStage(state, 0); CProcessor::OffsetAllGisToOM(*reply); return reply; } @@ -1920,59 +1962,6 @@ bool CId2ReaderBase::x_DoneReply(SId2PacketInfo& info, } -void CId2ReaderBase::x_GetPacketReplies(CReaderRequestResult& result, - SId2PacketReplies& replies, - CID2_Request_Packet& packet) -{ - SId2PacketInfo packet_info; - x_AssignSerialNumbers(packet_info, packet); - replies.replies.resize(packet_info.request_count); - - CConn conn(result, this); - CRef reply; - try { - // send request - x_SendToConnection(conn, packet); - - // process replies - while ( packet_info.remaining_count ) { - reply = x_ReceiveFromConnection(conn); - int num = x_GetReplyIndex(result, &conn, packet_info, *reply); - if ( num >= 0 ) { - replies.replies[num].push_back(reply); - if ( x_DoneReply(packet_info, num, *reply) ) { - // do nothing - } - } - reply = null; - } - if ( conn.IsAllocated() ) { - x_EndOfPacket(conn); - } - } - catch ( exception& /*rethrown*/ ) { - if ( GetDebugLevel() >= eTraceError ) { - CDebugPrinter s(conn, "CId2Reader"); - s << "Error processing request: " << MSerial_AsnText << packet; - if ( reply && - (reply->IsSetSerial_number() || - reply->IsSetParams() || - reply->IsSetError() || - reply->IsSetEnd_of_reply() || - reply->IsSetReply()) ) { - try { - s << "Last reply: " << MSerial_AsnText << *reply; - } - catch ( exception& /*ignored*/ ) { - } - } - } - throw; - } - conn.Release(); -} - - void CId2ReaderBase::x_ProcessPacket(CReaderRequestResult& result, CID2_Request_Packet& packet, const SAnnotSelector* sel) @@ -1981,50 +1970,17 @@ void CId2ReaderBase::x_ProcessPacket(CReaderRequestResult& result, x_AssignSerialNumbers(packet_info, packet); vector loaded_sets(packet_info.request_count); - - NON_CONST_ITERATE ( TProcessors, it, m_Processors ) { - if ( result.IsInProcessor() ) { - break; - } - CId2ReaderProcessorResolver resolver(*this, result); - CID2Processor::TReplies replies = - (*it)->ProcessSomeRequests(packet, &resolver); - ITERATE ( CID2Processor::TReplies, it, replies ) { - CRef reply = *it; - x_DumpReply(0, " from processor", *reply); - int num = x_GetReplyIndex(result, 0, packet_info, *reply); - if ( num >= 0 ) { - try { - x_ProcessReply(result, loaded_sets[num], *reply); - } - catch ( CException& exc ) { - NCBI_RETHROW(exc, CLoaderException, eOtherError, - "CId2ReaderBase: failed to process reply"); - } - if ( x_DoneReply(packet_info, num, *reply) ) { - x_UpdateLoadedSet(result, loaded_sets[num], sel); - } - } - } - if ( size_t(packet_info.remaining_count) != packet.Get().size() ) { - NCBI_THROW(CLoaderException, eOtherError, - "CId2ReaderBase: processor discrepancy"); - } - if ( packet_info.remaining_count == 0 ) { - return; - } - } - CConn conn(result, this); + SId2ProcessingState state; CRef reply; try { // send request - x_SendToConnection(conn, packet); + x_SendID2Packet(result, state, packet); // process replies while ( packet_info.remaining_count > 0 ) { - reply = x_ReceiveFromConnection(conn); - int num = x_GetReplyIndex(result, &conn, packet_info, *reply); + reply = x_ReceiveID2Reply(state); + int num = x_GetReplyIndex(result, state.conn.get(), packet_info, *reply); if ( num >= 0 ) { try { x_ProcessReply(result, loaded_sets[num], *reply); @@ -2032,7 +1988,7 @@ void CId2ReaderBase::x_ProcessPacket(CReaderRequestResult& result, catch ( CException& exc ) { NCBI_RETHROW(exc, CLoaderException, eOtherError, "CId2ReaderBase: failed to process reply: "+ - x_ConnDescription(conn)); + x_ConnDescription(state.GetConn())); } if ( x_DoneReply(packet_info, num, *reply) ) { x_UpdateLoadedSet(result, loaded_sets[num], sel); @@ -2040,13 +1996,13 @@ void CId2ReaderBase::x_ProcessPacket(CReaderRequestResult& result, } reply.Reset(); } - if ( conn.IsAllocated() ) { - x_EndOfPacket(conn); + if ( state.conn ) { + x_EndOfPacket(*state.conn); } } catch ( exception& /*rethrown*/ ) { if ( GetDebugLevel() >= eTraceError ) { - CDebugPrinter s(conn, "CId2Reader"); + CDebugPrinter s(state.GetConn(), "CId2Reader"); s << "Error processing request: " << MSerial_AsnText << packet; if ( reply && (reply->IsSetSerial_number() || @@ -2063,7 +2019,9 @@ void CId2ReaderBase::x_ProcessPacket(CReaderRequestResult& result, } throw; } - conn.Release(); + if ( state.conn ) { + state.conn->Release(); + } } @@ -2118,6 +2076,11 @@ void CId2ReaderBase::x_UpdateLoadedSet(CReaderRequestResult& result, annot_info.IsSetGraph() && ainfos.size() == 1 && !ExtractZoomLevel(annot_info.GetName(), 0, 0) ) { // graphs are suppozed to be zoom tracks + if ( GetDebugLevel() >= eTraceASN ) { + CDebugPrinter s(0, "CId2Reader"); + s << "Adding zoom tracks for " + << MSerial_AsnText << annot_info; + } for ( int zoom = 10; zoom < 1000000; zoom *= 10 ) { CRef zoom_info; zoom_info = SerialClone(annot_info); diff --git a/c++/src/objtools/edit/CMakeLists.edit.lib.txt b/c++/src/objtools/edit/CMakeLists.edit.lib.txt new file mode 100644 index 00000000..20fac4b6 --- /dev/null +++ b/c++/src/objtools/edit/CMakeLists.edit.lib.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/edit/Makefile.edit.lib +# +add_library(xobjedit + gene_utils seq_entry_edit promote autodef_with_tax + field_handler apply_object string_constraint seqid_guesser dblink_field + struc_comm_field text_desc_field gb_block_field + link_cds_mrna cds_fix capitalization_string loc_edit mail_report + feattable_edit gaps_edit source_edit rna_edit + remote_updater parse_text_options publication_edit +) + +target_link_libraries(xobjedit + xformat xobjread +) + diff --git a/c++/src/objtools/edit/CMakeLists.txt b/c++/src/objtools/edit/CMakeLists.txt new file mode 100644 index 00000000..b61f25df --- /dev/null +++ b/c++/src/objtools/edit/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.edit.lib.txt) + +# Recurse subdirectories +add_subdirectory(demo ) +add_subdirectory(unit_test ) diff --git a/c++/src/objtools/edit/Makefile.edit.lib b/c++/src/objtools/edit/Makefile.edit.lib index e5f67526..3f816656 100644 --- a/c++/src/objtools/edit/Makefile.edit.lib +++ b/c++/src/objtools/edit/Makefile.edit.lib @@ -1,24 +1,22 @@ -# $Id: Makefile.edit.lib 501626 2016-05-17 17:32:10Z kornbluh $ +# $Id: Makefile.edit.lib 531965 2017-03-30 17:12:21Z bollin $ # Build library "xobjedit" ############################### -SRC = gene_utils seq_entry_edit promote autodef_available_modifier autodef \ - autodef_feature_clause_base autodef_feature_clause autodef_mod_combo \ - autodef_source_desc autodef_source_group autodef_options \ +SRC = gene_utils seq_entry_edit promote autodef_with_tax \ field_handler apply_object string_constraint seqid_guesser dblink_field \ struc_comm_field text_desc_field gb_block_field \ link_cds_mrna cds_fix capitalization_string loc_edit mail_report \ feattable_edit gaps_edit source_edit rna_edit \ - remote_updater parse_text_options publication_edit + remote_updater parse_text_options publication_edit gap_trim LIB = xobjedit DLL_LIB = $(XFORMAT_LIBS) xregexp $(PCRE_LIB) $(SOBJMGR_LIBS) -ASN_DEP = seqset valid macro +ASN_DEP = seqset valid -WATCHERS = bollin gotvyans +WATCHERS = bollin gotvyans foleyjp USES_LIBRARIES = \ diff --git a/c++/src/objtools/edit/Makefile.in b/c++/src/objtools/edit/Makefile.in index 58ce753c..3180dcdd 100644 --- a/c++/src/objtools/edit/Makefile.in +++ b/c++/src/objtools/edit/Makefile.in @@ -1,10 +1,10 @@ -# $Id: Makefile.in 387372 2013-01-29 14:57:41Z bollin $ +# $Id: Makefile.in 529052 2017-02-28 18:43:36Z ucko $ # Meta-makefile (object utilities) ################################## LIB_PROJ = edit -SUB_PROJ = demo unit_test +SUB_PROJ = protein_match demo unit_test srcdir = @srcdir@ include @builddir@/Makefile.meta diff --git a/c++/src/objtools/edit/autodef_with_tax.cpp b/c++/src/objtools/edit/autodef_with_tax.cpp new file mode 100644 index 00000000..708fa34d --- /dev/null +++ b/c++/src/objtools/edit/autodef_with_tax.cpp @@ -0,0 +1,169 @@ +/* $Id: autodef_with_tax.cpp 530245 2017-03-13 15:52:22Z bollin $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Colleen Bollin +* +* File Description: +* Extends CAutoDef to create docsum titles (which require a call to taxonomy) +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) + + +CConstRef GetOptionsForSet(CBioseq_set_Handle set) +{ + CConstRef options(NULL); + CBioseq_CI b(set, CSeq_inst::eMol_na); + while (b && !options) { + CSeqdesc_CI desc(*b, CSeqdesc::e_User); + while (desc && desc->GetUser().GetObjectType() != CUser_object::eObjectType_AutodefOptions) { + ++desc; + } + if (desc) { + options.Reset(&(desc->GetUser())); + } + } + return options; +} + +bool CAutoDefWithTaxonomy::RegeneratePopsetTitles(CSeq_entry_Handle se) +{ + bool any = false; + // update the title of the set + for (CSeq_entry_CI si(se, CSeq_entry_CI::fRecursive | CSeq_entry_CI::fIncludeGivenEntry, CSeq_entry::e_Set); si; ++si) { + if (si->IsSet() && si->GetSet().GetCompleteBioseq_set()->NeedsDocsumTitle()) { + CAutoDefWithTaxonomy autodef; + CConstRef options = GetOptionsForSet(si->GetSet()); + if (options) { + autodef.SetOptionsObject(*options); + } + autodef.AddSources(se); + string defline = autodef.GetDocsumDefLine(*si); + + bool found_existing = false; + CBioseq_set_EditHandle bsseh(si->GetSet()); + NON_CONST_ITERATE(CBioseq_set_EditHandle::TDescr::Tdata, it, bsseh.SetDescr().Set()) { + if ((*it)->IsTitle()) { + if (!NStr::Equal((*it)->GetTitle(), defline)) { + (*it)->SetTitle(defline); + any = true; + } + found_existing = true; + break; + } + } + if (!found_existing) { + CRef new_desc(new CSeqdesc()); + new_desc->SetTitle(defline); + bsseh.SetDescr().Set().push_back(new_desc); + any = true; + } + } + } + return any; +} + + +bool CAutoDefWithTaxonomy::RegenerateDefLines(CSeq_entry_Handle se) +{ + bool any = RegenerateSequenceDefLines(se); + + any |= RegeneratePopsetTitles(se); + return any; +} + + +string CAutoDefWithTaxonomy::GetDocsumOrgDescription(CSeq_entry_Handle se) +{ + string joined_org = "Mixed organisms"; + + CRef rq(new CT3Request()); + CBioseq_CI bi(se, CSeq_inst::eMol_na); + while (bi) { + CSeqdesc_CI desc_ci(*bi, CSeqdesc::e_Source); + if (desc_ci && desc_ci->GetSource().IsSetOrg()) { + int taxid = desc_ci->GetSource().GetOrg().GetTaxId(); + if (taxid > 0) { + rq->SetJoin().Set().push_back(taxid); + } + } + ++bi; + } + if (rq->IsJoin() && rq->GetJoin().Get().size() > 0) { + CTaxon3_request request; + request.SetRequest().push_back(rq); + CTaxon3 taxon3; + taxon3.Init(); + CRef reply = taxon3.SendRequest(request); + if (reply) { + CTaxon3_reply::TReply::const_iterator reply_it = reply->GetReply().begin(); + while (reply_it != reply->GetReply().end()) { + if ((*reply_it)->IsData() + && (*reply_it)->GetData().GetOrg().IsSetTaxname()) { + joined_org = (*reply_it)->GetData().GetOrg().GetTaxname(); + break; + } + ++reply_it; + } + } + } + + return joined_org; +} + + +string CAutoDefWithTaxonomy::GetDocsumDefLine(CSeq_entry_Handle se) +{ + string org_desc = GetDocsumOrgDescription(se); + + string feature_clauses = ""; + CBioseq_CI bi(se, CSeq_inst::eMol_na); + if (bi) { + unsigned int genome_val = CBioSource::eGenome_unknown; + CSeqdesc_CI di(*bi, CSeqdesc::e_Source); + if (di && di->GetSource().IsSetGenome()) { + genome_val = di->GetSource().GetGenome(); + } + feature_clauses = GetOneFeatureClauseList(*bi, genome_val); + } + + return org_desc + feature_clauses; +} + + +END_SCOPE(objects) +END_NCBI_SCOPE diff --git a/c++/src/objtools/edit/capitalization_string.cpp b/c++/src/objtools/edit/capitalization_string.cpp index 78e42f57..57579a26 100644 --- a/c++/src/objtools/edit/capitalization_string.cpp +++ b/c++/src/objtools/edit/capitalization_string.cpp @@ -1,4 +1,4 @@ -/* $Id: capitalization_string.cpp 490174 2016-01-21 20:09:56Z asztalos $ +/* $Id: capitalization_string.cpp 536438 2017-05-18 16:14:52Z asztalos $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -652,7 +652,7 @@ void FixCapitalizationInString (objects::CSeq_entry_Handle seh, string& str, ECa { NStr::ToLower(str); vector words; - NStr::Tokenize(str, " \t\r\n", words); + NStr::Split(str, " \t\r\n", words, NStr::fSplit_NoMergeDelims); for (vector::iterator word = words.begin(); word != words.end(); ++word) { if (!word->empty() && isalpha(word->at(0))) { word->at(0) = toupper(word->at(0)); @@ -701,15 +701,38 @@ void FixAbbreviationsInElement(string& result, bool fix_end_of_sentence) } +static bool s_ReplaceInPlaceWholeWordNoCase(string& str, const string& search, const string& replace) +{ + bool modified = false; + + size_t pos = NStr::FindNoCase(str, search); + while (pos != string::npos) { + size_t right_end = pos + search.length(); + if ((pos == 0 || !isalpha(str.c_str()[pos - 1])) + && (right_end == str.length() || !isalpha(str.c_str()[right_end]))) { + string this_replace = replace; + str = str.substr(0, pos) + this_replace + str.substr(right_end); + right_end = pos + this_replace.length(); + modified = true; + } + pos = NStr::FindNoCase(str, search, right_end); + } + + return modified; +} + void FixOrgNames(objects::CSeq_entry_Handle seh, string& result) { vector taxnames; - FindOrgNames(seh,taxnames); - for(vector::const_iterator name=taxnames.begin(); name!=taxnames.end(); ++name) { - CRegexpUtil replacer( result ); - //int num_replacements = - replacer.Replace( "\\b"+*name+"\\b", *name, CRegexp::fCompile_ignore_case, CRegexp::fMatch_default, 0); - replacer.GetResult().swap( result ); + FindOrgNames(seh, taxnames); + for (vector::const_iterator name = taxnames.begin(); name != taxnames.end(); ++name) { + bool modified = s_ReplaceInPlaceWholeWordNoCase(result, *name, *name); + if (!modified && (NStr::Find(*name, "]") != NPOS || NStr::Find(*name, "[") != NPOS)) { + string temp_taxname(*name); + NStr::ReplaceInPlace(temp_taxname, "]", ""); + NStr::ReplaceInPlace(temp_taxname, "[", ""); + modified = s_ReplaceInPlaceWholeWordNoCase(result, temp_taxname, temp_taxname); + } } } diff --git a/c++/src/objtools/edit/cds_fix.cpp b/c++/src/objtools/edit/cds_fix.cpp index 9a0dec05..516b1b58 100644 --- a/c++/src/objtools/edit/cds_fix.cpp +++ b/c++/src/objtools/edit/cds_fix.cpp @@ -1,4 +1,4 @@ -/* $Id: cds_fix.cpp 501569 2016-05-17 12:33:15Z filippov $ +/* $Id: cds_fix.cpp 547098 2017-09-26 12:05:24Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -639,14 +639,32 @@ void s_AdjustForUTR_SingleSide(CSeq_loc& mrna_loc, const CSeq_loc &utr_loc, cons void s_AdjustForUTR(const CSeq_feat& utr, int cd_start, int cd_stop, CSeq_loc& mrna_loc, bool& found5, bool& found3, CScope& scope) { - if ( utr.GetData().GetSubtype() == CSeqFeatData::eSubtype_5UTR ) - { + if (utr.GetData().GetSubtype() == CSeqFeatData::eSubtype_5UTR && mrna_loc.GetStrand() == utr.GetLocation().GetStrand()) { + if (utr.GetLocation().GetStrand() == eNa_strand_minus) { + if (utr.GetLocation().GetStart(eExtreme_Positional) != cd_stop + 1) { + return; + } + } + else { + if (utr.GetLocation().GetStop(eExtreme_Positional) != cd_start - 1) { + return; + } + } found5 = true; s_AdjustForUTR_SingleSide(mrna_loc, utr.GetLocation(), *mrna_loc.GetId()); mrna_loc.SetPartialStart( utr.GetLocation().IsPartialStart(eExtreme_Positional), eExtreme_Positional ); } - else if ( utr.GetData().GetSubtype() == CSeqFeatData::eSubtype_3UTR ) - { + else if (utr.GetData().GetSubtype() == CSeqFeatData::eSubtype_3UTR && mrna_loc.GetStrand() == utr.GetLocation().GetStrand()) { + if (utr.GetLocation().GetStrand() == eNa_strand_minus) { + if (utr.GetLocation().GetStop(eExtreme_Positional) != cd_start - 1) { + return; + } + } + else { + if (utr.GetLocation().GetStart(eExtreme_Positional) != cd_stop + 1) { + return; + } + } found3 = true; CRef new_loc(new CSeq_loc); new_loc->Assign(utr.GetLocation()); @@ -707,6 +725,7 @@ CRef MakemRNAforCDS(const CSeq_feat& cds, CScope& scope) bool found5 = false; int cd_start = cd_loc.GetStart(eExtreme_Positional); int cd_stop = cd_loc.GetStop(eExtreme_Positional); + //cd_loc.GetStrand(); if (bsh) { for (CFeat_CI utr(bsh, CSeqFeatData::e_Imp); utr; ++utr) diff --git a/c++/src/objtools/edit/feattable_edit.cpp b/c++/src/objtools/edit/feattable_edit.cpp index 36d9979f..1af9e412 100644 --- a/c++/src/objtools/edit/feattable_edit.cpp +++ b/c++/src/objtools/edit/feattable_edit.cpp @@ -1,4 +1,4 @@ -/* $Id: feattable_edit.cpp 520505 2016-11-29 16:02:37Z ivanov $ +/* $Id: feattable_edit.cpp 546402 2017-09-18 15:03:27Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -48,6 +48,8 @@ #include #include +#include + BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) BEGIN_SCOPE(edit) @@ -103,11 +105,12 @@ CFeatTableEdit::CFeatTableEdit( CSeq_annot& annot, const string& locusTagPrefix, unsigned int locusTagNumber, + unsigned int startingFeatId, ILineErrorListener* pMessageListener) : // ------------------------------------------------------------------------- mAnnot(annot), mpMessageListener(pMessageListener), - mNextFeatId(1), + mNextFeatId(startingFeatId), mLocusTagNumber(locusTagNumber), mLocusTagPrefix(locusTagPrefix) { @@ -319,17 +322,11 @@ void CFeatTableEdit::EliminateBadQualifiers() != specialQuals.end()) { continue; } - if (qualKey == "transcript_id") { - if (!NStr::StartsWith((*qual)->GetVal(), "gnl|")) { - badQuals.push_back(qualKey); - } - continue; - } - if (qualKey == "protein_id") { - if (!NStr::StartsWith((*qual)->GetVal(), "gnl|")) { - badQuals.push_back(qualKey); + if (subtype == CSeqFeatData::eSubtype_cdregion || + subtype == CSeqFeatData::eSubtype_mRNA) { + if (qualKey == "protein_id" || qualKey == "transcript_id") { + continue; } - continue; } CSeqFeatData::EQualifier qualType = CSeqFeatData::GetQualifierType(qualKey); if (CSeqFeatData::IsLegalQualifier(subtype, qualType)) { @@ -349,14 +346,37 @@ void CFeatTableEdit::EliminateBadQualifiers() void CFeatTableEdit::GenerateProteinAndTranscriptIds() // ---------------------------------------------------------------------------- { - SAnnotSelector sel; - //sel.IncludeFeatSubtype(CSeqFeatData::eSubtype_mRNA); - sel.IncludeFeatType(CSeqFeatData::e_Rna); - sel.IncludeFeatSubtype(CSeqFeatData::eSubtype_cdregion); - for (CFeat_CI it(mHandle, sel); it; ++it){ + SAnnotSelector sel1; + sel1.IncludeFeatSubtype(CSeqFeatData::eSubtype_mRNA); + sel1.IncludeFeatSubtype(CSeqFeatData::eSubtype_cdregion); + for (CFeat_CI it(mHandle, sel1); it; ++it) { CMappedFeat mf = *it; - xFeatureAddProteinId(mf); - xFeatureAddTranscriptId(mf); + switch(mf.GetFeatSubtype()) { + default: + break; + case CSeqFeatData::eSubtype_mRNA: + xFeatureAddTranscriptIdMrna(mf); + break; + case CSeqFeatData::eSubtype_cdregion: + xFeatureAddProteinIdCds(mf); + break; + } + } + SAnnotSelector sel2; + for (CFeat_CI it(mHandle, sel2); it; ++it) { + CMappedFeat mf = *it; + switch(mf.GetFeatSubtype()) { + default: + xFeatureAddProteinIdDefault(mf); + xFeatureAddTranscriptIdDefault(mf); + break; + case CSeqFeatData::eSubtype_mRNA: + xFeatureAddProteinIdMrna(mf); + break; + case CSeqFeatData::eSubtype_cdregion: + xFeatureAddTranscriptIdCds(mf); + break; + } } } @@ -447,83 +467,233 @@ CFeatTableEdit::xCreateMissingParentGene( return true; } +// ---------------------------------------------------------------------------- +void CFeatTableEdit::xFeatureAddProteinIdMrna( + CMappedFeat mf) +// ---------------------------------------------------------------------------- +{ + //rw-451 rules for mRNA: + // no mRNA survives with an orig_protein_id + // almost all mRNA features should have protein_ids + // if one exists already then police it + // if none exists then if possible inherit it from the decendent CDS + + auto orig_tid = mf.GetNamedQual("orig_protein_id"); + if (!orig_tid.empty()) { + xFeatureRemoveQualifier(mf, "orig_protein_id"); + } + auto pid = mf.GetNamedQual("protein_id"); + if (NStr::StartsWith(pid, "gb|") || NStr::StartsWith(pid, "gnl|")) { + // already what we want + return; + } + if (pid.empty()) { + // we need to upinherit the protein_id from the CDS: + CMappedFeat child = feature::GetBestCdsForMrna(mf, &mTree); + if (!child) { + // only permitted case of an mRNA without a protein_id + return; + } + auto pid = child.GetNamedQual("protein_id"); + xFeatureAddQualifier(mf, "protein_id", pid); + return; + } + + // otherwise, we need to police the existing transcript_id: + pid = xGenerateTranscriptOrProteinId(mf, pid); + if (!pid.empty()) { + xFeatureSetQualifier(mf, "protein_id", pid); + } +} // ---------------------------------------------------------------------------- -void CFeatTableEdit::xFeatureAddProteinId( +void CFeatTableEdit::xFeatureAddProteinIdCds( CMappedFeat mf) // ---------------------------------------------------------------------------- { - //mss-375: - // make sure we got a protein_id qualifier: - // if we already got one from the GFF then keep it - // otherwise if the parent/child got one then use that - // otherwise generate one based on the gene locustag + //rw-451 rules for CDS: + // no CDS survives with an orig_protein_id + // all CDS features should have transcript_ids + // if one exists already then police it + // if it doen't have one then generate one following a strict set of rules + + auto orig_pid = mf.GetNamedQual("orig_protein_id"); + if (!orig_pid.empty()) { + xFeatureRemoveQualifier(mf, "orig_protein_id"); + } - string protein_id = mf.GetNamedQual("protein_id"); - if (!protein_id.empty()) { + auto pid = mf.GetNamedQual("protein_id"); + if (NStr::StartsWith(pid, "gb|") || NStr::StartsWith(pid, "gnl|")) { + // already what we want return; } - CMappedFeat associateFeat; - switch (mf.GetFeatSubtype()) { - default: - break; - case CSeqFeatData::eSubtype_mRNA: - associateFeat = feature::GetBestCdsForMrna(mf, &mTree); - break; - case CSeqFeatData::eSubtype_cdregion: - associateFeat = feature::GetBestMrnaForCds(mf, &mTree); - break; + if (pid.empty()) { + pid = mf.GetNamedQual("ID"); + if (pid.empty()) { + pid = xGetIdStr(mf); + } } - if (associateFeat) { - protein_id = associateFeat.GetNamedQual("protein_id"); + pid = xGenerateTranscriptOrProteinId(mf, pid); + if (!pid.empty()) { + xFeatureSetQualifier(mf, "protein_id", pid); } - if (protein_id.empty()) { - protein_id = xNextProteinId(mf); +} + +// ---------------------------------------------------------------------------- +void CFeatTableEdit::xFeatureAddProteinIdDefault( + CMappedFeat mf) +// ---------------------------------------------------------------------------- +{ + //rw-451 rules for non CDS, non mRNA: + // we won't touch orig_protein_id + // we don't generate any protein_ids + // if it comes with a protein_id then we add it to the "gnl|locus_tag|" + // namespace if necessary. + + auto pid = mf.GetNamedQual("protein_id"); + if (pid.empty()) { + return; } - if (!protein_id.empty()) { - xFeatureAddQualifier(mf, "protein_id", protein_id); + if (NStr::StartsWith(pid, "gb|") || NStr::StartsWith(pid, "gnl|")) { + // already what we want + return; + } + pid = xGenerateTranscriptOrProteinId(mf, pid); + if (!pid.empty()) { + xFeatureSetQualifier(mf, "protein_id", pid); } } + // ---------------------------------------------------------------------------- -void CFeatTableEdit::xFeatureAddTranscriptId( +void CFeatTableEdit::xFeatureAddTranscriptIdMrna( CMappedFeat mf) // ---------------------------------------------------------------------------- { - //mss-375: - // make sure we got a transcript_id qualifier: - // if we already got one from the GFF then keep it - // otherwise if the parent/child got one then use that - // otherwise generate one based on the gene locustag + //rw-451 rules for mRNA: + // no mRNA survives with an orig_transcript_id + // every mRNA must have a transcript_id. + // if it already got one then police it. + // if it doen't have one then generate one following a strict set of rules + + auto orig_tid = mf.GetNamedQual("orig_transcript_id"); + if (!orig_tid.empty()) { + xFeatureRemoveQualifier(mf, "orig_transcript_id"); + } - string transcript_id = mf.GetNamedQual("transcript_id"); - if (!transcript_id.empty()) { + auto tid = mf.GetNamedQual("transcript_id"); + if (NStr::StartsWith(tid, "gb|") || NStr::StartsWith(tid, "gnl|")) { + // already what we want return; } - CMappedFeat associateFeat; - switch (mf.GetFeatSubtype()) { - default: - break; - case CSeqFeatData::eSubtype_mRNA: - associateFeat = feature::GetBestCdsForMrna(mf, &mTree); - break; - case CSeqFeatData::eSubtype_cdregion: - associateFeat = feature::GetBestMrnaForCds(mf, &mTree); - break; + if (tid.empty()) { + tid = mf.GetNamedQual("ID"); + if (tid.empty()) { + tid = xGetIdStr(mf); + } + } + tid = xGenerateTranscriptOrProteinId(mf, tid); + if (!tid.empty()) { + xFeatureSetQualifier(mf, "transcript_id", tid); + } +} + + +// ---------------------------------------------------------------------------- +void CFeatTableEdit::xFeatureAddTranscriptIdCds( + CMappedFeat mf) + // ---------------------------------------------------------------------------- +{ + //rw-451 rules for CDS: + // no CDS survives with an orig_transcript_id + // almost all CDS features should have transcript_ids + // if one exists already then police it + // if none exists then if possible inherit it from the parent mRNA + + auto orig_tid = mf.GetNamedQual("orig_transcript_id"); + if (!orig_tid.empty()) { + xFeatureRemoveQualifier(mf, "orig_transcript_id"); + } + + auto tid = mf.GetNamedQual("transcript_id"); + if (tid.empty()) { + // we need to down inherit the transcript_id from the mRNA: + CMappedFeat parent = feature::GetBestMrnaForCds(mf, &mTree); + if (!parent) { + // only permitted case of a CDS without a transcript_id + return; + } + auto tid = parent.GetNamedQual("transcript_id"); + xFeatureAddQualifier(mf, "transcript_id", tid); + return; + } + + // otherwise, we need to police the existing transcript_id: + if (NStr::StartsWith(tid, "gb|") || NStr::StartsWith(tid, "gnl|")) { + // already what we want + return; + } + tid = xGenerateTranscriptOrProteinId(mf, tid); + if (!tid.empty()) { + xFeatureSetQualifier(mf, "transcript_id", tid); + } +} + + +// ---------------------------------------------------------------------------- +void CFeatTableEdit::xFeatureAddTranscriptIdDefault( + CMappedFeat mf) +// ---------------------------------------------------------------------------- +{ + //rw-451 rules for non CDS, non mRNA: + // we won't touch orig_transcript_id + // we don't generate any transcript_ids + // if it comes with a transcript_id then we add it to the "gnl|locus_tag|" + // namespace if necessary. + + auto tid = mf.GetNamedQual("transcript_id"); + if (tid.empty()) { + return; } - if (associateFeat) { - transcript_id = associateFeat.GetNamedQual("transcript_id"); + if (NStr::StartsWith(tid, "gb|") || NStr::StartsWith(tid, "gnl|")) { + // already what we want + return; } - if (transcript_id.empty()) { - transcript_id = xNextTranscriptId(mf); + tid = xGenerateTranscriptOrProteinId(mf, tid); + if (!tid.empty()) { + xFeatureSetQualifier(mf, "transcript_id", tid); } - if (!transcript_id.empty()) { - xFeatureAddQualifier(mf, "transcript_id", transcript_id); +} + + +// ---------------------------------------------------------------------------- +string CFeatTableEdit::xGenerateTranscriptOrProteinId( + CMappedFeat mf, + const string& rawId) +// ---------------------------------------------------------------------------- +{ + if (string::npos != rawId.find("|")) { + xPutError( + ILineError::eProblem_InvalidQualifier, + "Feature " + xGetIdStr(mf) + + " does not have a usable transcript_ or protein_id."); + return ""; + } + + auto locusTagPrefix = xGetCurrentLocusTagPrefix(mf); + if (locusTagPrefix.empty()) { + xPutError( + ILineError::eProblem_InvalidQualifier, + "Cannot generate transcript_/protein_id for feature " + xGetIdStr(mf) + + " without a locus tag."); + return ""; } + return string("gnl|") + locusTagPrefix + "|" + rawId; } + // ---------------------------------------------------------------------------- void CFeatTableEdit::GenerateLocusIds() // ---------------------------------------------------------------------------- @@ -612,7 +782,6 @@ void CFeatTableEdit::xGenerateLocusIdsUseExisting() for (CFeat_CI it(mHandle, sel); it; ++it) { //mss-362: every feature that needs them must come with a complete set // of locus_tag, protein_id, and transcript_id. - // we will generate orig_protein_id and orig_transcript_id as needed. CMappedFeat mf = *it; CSeqFeatData::ESubtype subtype = mf.GetFeatSubtype(); @@ -777,6 +946,43 @@ void CFeatTableEdit::xFeatureAddQualifier( feh.Replace(*pEditedFeat); } + +// ---------------------------------------------------------------------------- +void CFeatTableEdit::xFeatureRemoveQualifier( + CMappedFeat mf, + const string& qualKey) +// ---------------------------------------------------------------------------- +{ + const CSeq_feat& origFeat = mf.GetOriginalFeature(); + CRef pEditedFeat(new CSeq_feat); + pEditedFeat->Assign(origFeat); + pEditedFeat->RemoveQualifier(qualKey); + CSeq_feat_EditHandle feh(mpScope->GetObjectHandle(origFeat)); + feh.Replace(*pEditedFeat); +} + +// ---------------------------------------------------------------------------- +void CFeatTableEdit::xFeatureSetQualifier( + CMappedFeat mf, + const string& qualKey, + const string& qualVal) +// ---------------------------------------------------------------------------- +{ + const CSeq_feat& origFeat = mf.GetOriginalFeature(); + CRef pEditedFeat(new CSeq_feat); + pEditedFeat->Assign(origFeat); + auto existing = pEditedFeat->GetNamedQual(qualKey); + if (!existing.empty()) { + pEditedFeat->RemoveQualifier(qualKey); + } + CRef pQual(new CGb_qual); + pQual->SetQual(qualKey); + pQual->SetVal(qualVal); + pEditedFeat->SetQual().push_back(pQual); + CSeq_feat_EditHandle feh(mpScope->GetObjectHandle(origFeat)); + feh.Replace(*pEditedFeat); +} + // ---------------------------------------------------------------------------- string CFeatTableEdit::xNextFeatId() // ---------------------------------------------------------------------------- @@ -899,6 +1105,23 @@ CRef CFeatTableEdit::xMakeGeneForFeature( return pGene; } +// ---------------------------------------------------------------------------- +void +CFeatTableEdit::xPutError( + ILineError::EProblem problem, + const string& message) +// ---------------------------------------------------------------------------- +{ + AutoPtr pErr( + CObjReaderLineException::Create( + eDiag_Error, + 0, + message, + problem)); + pErr->SetLineNumber(0); + mpMessageListener->PutError(*pErr); +} + // ---------------------------------------------------------------------------- void CFeatTableEdit::xPutErrorMissingLocustag( @@ -980,6 +1203,55 @@ CMappedFeat mf) mpMessageListener->PutError(*pErr); } +// ---------------------------------------------------------------------------- +string +CFeatTableEdit::xGetIdStr( + CMappedFeat mf) +// ---------------------------------------------------------------------------- +{ + stringstream strstr; + auto& id = mf.GetId(); + switch (id.Which()) { + default: + return "\"UNKNOWN ID\""; + case CFeat_id::e_Local: + id.GetLocal().AsString(strstr); + return strstr.str(); + } +} + +// ---------------------------------------------------------------------------- +string +CFeatTableEdit::xGetCurrentLocusTagPrefix( + CMappedFeat mf) +// ---------------------------------------------------------------------------- +{ + if (!mLocusTagPrefix.empty()) { + return mLocusTagPrefix; + } + CMappedFeat geneFeature = mf; + if (geneFeature.GetFeatSubtype() != CSeqFeatData::eSubtype_gene) { + geneFeature = feature::GetBestGeneForFeat(mf, &mTree); + } + if (!geneFeature) { + return ""; + } + const auto& geneRef = geneFeature.GetData().GetGene(); + if (geneRef.IsSetLocus_tag()) { + const auto& locusTag = geneFeature.GetData().GetGene().GetLocus_tag(); + string prefix, suffix; + NStr::SplitInTwo(locusTag, "_", prefix, suffix); + return prefix; + } + auto locusTagFromQualifier = geneFeature.GetNamedQual("locus_tag"); + if (!locusTagFromQualifier.empty()) { + string prefix, suffix; + NStr::SplitInTwo(locusTagFromQualifier, "_", prefix, suffix); + return prefix; + } + return ""; +} + END_SCOPE(edit) END_SCOPE(objects) END_NCBI_SCOPE diff --git a/c++/src/objtools/edit/gap_trim.cpp b/c++/src/objtools/edit/gap_trim.cpp new file mode 100644 index 00000000..d55145f1 --- /dev/null +++ b/c++/src/objtools/edit/gap_trim.cpp @@ -0,0 +1,801 @@ +/* $Id: gap_trim.cpp 540672 2017-07-10 15:05:36Z ivanov $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Colleen Bollin + * + * File Description: + * For adjusting features for gaps + * + * =========================================================================== + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) +BEGIN_SCOPE(edit) + +CFeatGapInfo::CFeatGapInfo(CSeq_feat_Handle sf) +{ + m_Feature = sf; + CollectGaps(sf.GetLocation(), sf.GetScope()); +} + + +void CFeatGapInfo::CollectGaps(const CSeq_loc& feat_loc, CScope& scope) +{ + m_Gaps.clear(); + m_Unknown = false; + m_Known = false; + m_Ns = false; + + m_Start = feat_loc.GetStart(objects::eExtreme_Positional); + m_Stop = feat_loc.GetStop(objects::eExtreme_Positional); + CRef total_loc = sequence::Seq_loc_Merge(feat_loc, CSeq_loc::fMerge_SingleRange, &scope); + if (total_loc->IsSetStrand()) total_loc->ResetStrand(); + CConstRef seq_map = CSeqMap::GetSeqMapForSeq_loc(*total_loc, &scope); + + // use CSeqVector for finding Ns + CSeqVector vec(*seq_map, scope, CBioseq_Handle::eCoding_Iupac); + + CSeqMap_CI seq_map_ci = seq_map->ResolvedRangeIterator(&scope, + 0, + m_Stop - m_Start + 1, + feat_loc.GetStrand(), + size_t(-1), + objects::CSeqMap::fFindGap | objects::CSeqMap::fFindData); + + for (; seq_map_ci; ++seq_map_ci) + { + + if (seq_map_ci.GetType() == objects::CSeqMap::eSeqGap) + { + TSeqPos gap_start = m_Start + seq_map_ci.GetPosition(); + TSeqPos gap_stop = gap_start + seq_map_ci.GetLength() - 1; + bool is_unknown = seq_map_ci.IsUnknownLength(); + if (is_unknown) { + m_Unknown = true; + } else { + m_Known = true; + } + m_Gaps.push_back(TGapInterval(is_unknown ? eGapIntervalType_unknown : eGapIntervalType_known, pair(gap_start, gap_stop))); + } else { + // look for Ns + TSeqPos map_start = seq_map_ci.GetPosition(); + TSeqPos map_stop = map_start + seq_map_ci.GetLength() - 1; + bool in_ns = false; + TSeqPos gap_start; + for (TSeqPos i = map_start; i <= map_stop; ++i) { + char letter = vec[i]; + if (letter == 'N') { + if (!in_ns) { + // start new gap + gap_start = m_Start + i; + in_ns = true; + } + } else if (in_ns) { + // end previous gap + TSeqPos gap_stop = m_Start + i - 1; + m_Gaps.push_back(TGapInterval(eGapIntervalType_n, pair(gap_start, gap_stop))); + m_Ns = true; + in_ns = false; + } + } + if (in_ns) { + TSeqPos gap_stop = m_Start + map_stop; + m_Gaps.push_back(TGapInterval(eGapIntervalType_n, pair(gap_start, gap_stop))); + m_Ns = true; + } + } + } +} + + +bool CFeatGapInfo::x_UsableInterval(const TGapInterval& interval, bool unknown_length, bool known_length, bool ns) +{ + if (interval.first == eGapIntervalType_unknown && !unknown_length) { + return false; + } else if (interval.first == eGapIntervalType_known && !known_length) { + return false; + } else if (interval.first == eGapIntervalType_n && !ns) { + return false; + } else { + return true; + } +} + + +void CFeatGapInfo::CalculateRelevantIntervals(bool unknown_length, bool known_length, bool ns) +{ + m_InsideGaps.clear(); + m_LeftGaps.clear(); + m_RightGaps.clear(); + + if (!m_Gaps.empty()) { + // find left offset + size_t skip_left = 0; + TGapIntervalList::iterator it = m_Gaps.begin(); + while (it != m_Gaps.end()) { + if (!x_UsableInterval(*it, unknown_length, known_length, ns)) { + break; + } + + if (m_LeftGaps.empty()) { + if (it->second.first <= m_Start && it->second.second >= m_Start) { + m_LeftGaps.push_back(it->second); + skip_left++; + } else { + break; + } + } else if (it->second.first <= m_LeftGaps.front().second + 1 && it->second.second >= m_LeftGaps.front().second) { + m_LeftGaps.front().second = it->second.second; + skip_left++; + } else { + break; + } + ++it; + } + TGapIntervalList::reverse_iterator rit = m_Gaps.rbegin(); + size_t skip_right = 0; + while (rit != m_Gaps.rend()) { + if (!x_UsableInterval(*rit, unknown_length, known_length, ns)) { + break; + } + if (m_RightGaps.empty()) { + if (rit->second.first <= m_Stop && rit->second.second >= m_Stop) { + m_RightGaps.push_back(rit->second); + skip_right++; + } else { + break; + } + } else if (rit->second.first <= m_RightGaps.front().first - 1 && rit->second.second >= m_RightGaps.front().second) { + m_RightGaps.front().first = rit->second.first; + skip_right++; + } else { + break; + } + ++rit; + } + for (size_t offset = skip_left; offset < m_Gaps.size() - skip_right; offset++) { + if (x_UsableInterval(m_Gaps[offset], unknown_length, known_length, ns)) { + m_InsideGaps.push_back(m_Gaps[offset].second); + } + } + } +} + + +bool CFeatGapInfo::Trimmable() const +{ + if (ShouldRemove()) { + return false; + } else if (!m_LeftGaps.empty() || !m_RightGaps.empty()) { + return true; + } else { + return false; + } +} + + +bool CFeatGapInfo::Splittable() const +{ + if (!m_InsideGaps.empty()) { + return true; + } else { + return false; + } +} + + +bool CFeatGapInfo::ShouldRemove() const +{ + if (!m_LeftGaps.empty() && m_LeftGaps.front().second >= m_Stop) { + return true; + } else { + return false; + } +} + + +void CFeatGapInfo::Trim(CSeq_loc& loc, bool make_partial, CScope& scope) +{ + for (vector >::reverse_iterator b = m_LeftGaps.rbegin(); b != m_LeftGaps.rend(); ++b) + { + size_t start = b->first; + size_t stop = b->second; + CRef loc2(new CSeq_loc()); + int options = edit::eSplitLocOption_split_in_exon; + if (make_partial) + options |= edit::eSplitLocOption_make_partial; + edit::SplitLocationForGap(loc, *loc2, start, stop, loc.GetId(), options); + if (loc2->Which() != CSeq_loc::e_not_set) + { + loc.Assign(*loc2); + } + } + for (vector >::reverse_iterator b = m_RightGaps.rbegin(); b != m_RightGaps.rend(); ++b) + { + size_t start = b->first; + size_t stop = b->second; + CRef loc2(new CSeq_loc()); + int options = edit::eSplitLocOption_split_in_exon; + if (make_partial) + options |= edit::eSplitLocOption_make_partial; + edit::SplitLocationForGap(loc, *loc2, start, stop, loc.GetId(), options); + } +} + + +CFeatGapInfo::TLocList CFeatGapInfo::Split(const CSeq_loc& orig, bool in_intron, bool make_partial) +{ + TLocList locs; + CRef left_loc(new CSeq_loc()); + left_loc->Assign(orig); + for (vector >::reverse_iterator b = m_InsideGaps.rbegin(); b != m_InsideGaps.rend(); ++b) + { + size_t start = b->first; + size_t stop = b->second; + CRef loc2(new CSeq_loc()); + int options = edit::eSplitLocOption_make_partial | edit::eSplitLocOption_split_in_exon; + if (in_intron) + options |= edit::eSplitLocOption_split_in_intron; + edit::SplitLocationForGap(*left_loc, *loc2, start, stop, orig.GetId(), options); + if (loc2->GetId()) + { + if (make_partial) + { + loc2->SetPartialStart(true, objects::eExtreme_Positional); + left_loc->SetPartialStop(true, objects::eExtreme_Positional); + } + locs.push_back(loc2); + } + } + if (locs.size() > 0) { + locs.push_back(left_loc); + reverse(locs.begin(), locs.end()); + } + return locs; +} + + +void CFeatGapInfo::x_AdjustOrigLabel(CSeq_feat& feat, size_t& id_offset, string& id_label, const string& qual) +{ + if (!feat.IsSetQual()) { + return; + } + NON_CONST_ITERATE(CSeq_feat::TQual, it, feat.SetQual()) { + if ((*it)->IsSetQual() && (*it)->IsSetVal() && + !NStr::IsBlank((*it)->GetVal()) && + NStr::EqualNocase((*it)->GetQual(), qual) && + (id_label.empty() || NStr::Equal((*it)->GetVal(), id_label) || NStr::Equal((*it)->GetVal(), id_label + "_1"))) { + if (id_label.empty()) { + id_label = (*it)->GetVal(); + } + (*it)->SetVal(id_label + "_" + NStr::NumericToString(id_offset)); + id_offset++; + } + } +} + + +CRef CFeatGapInfo::x_AdjustProtId(const CDbtag& orig_gen, size_t& id_offset) +{ + string id_base; + if (!orig_gen.IsSetTag()) { + id_base = kEmptyStr; + } else if (orig_gen.GetTag().IsId()) + { + id_base = NStr::NumericToString(orig_gen.GetTag().GetId()); + } else { + id_base = orig_gen.GetTag().GetStr(); + } + + CRef new_id(new CSeq_id()); + new_id->SetGeneral().Assign(orig_gen); + new_id->SetGeneral().SetTag().SetStr(id_base + "_" + NStr::NumericToString(id_offset)); + return new_id; +} + + +CRef CFeatGapInfo::x_AdjustProtId(const CSeq_id& orig, size_t& id_offset) +{ + if (orig.IsGeneral()) { + return x_AdjustProtId(orig.GetGeneral(), id_offset); + } else { + string id_base; + orig.GetLabel(&id_base, NULL, CSeq_id::eContent); + CRef new_id(new CSeq_id()); + new_id->SetLocal().SetStr(id_base + "_" + NStr::NumericToString(id_offset)); + return new_id; + } +} + + +CRef CFeatGapInfo::AdjustProteinSeq(const CBioseq& seq, const CSeq_feat& feat, const CSeq_feat& orig_cds, CScope& scope) +{ + if (!feat.IsSetProduct() || !feat.GetProduct().IsWhole() || !seq.IsAa()) { + return CRef(NULL); + } + + TSeqPos orig_len = seq.GetInst().GetLength(); + + string prot; + CSeqTranslator::Translate(feat, scope, prot); + if (prot.empty()) { + return CRef(NULL); + } + + CRef prot_seq(new CBioseq); + prot_seq->Assign(seq); + prot_seq->SetInst().ResetExt(); + prot_seq->SetInst().SetRepr(objects::CSeq_inst::eRepr_raw); + prot_seq->SetInst().SetSeq_data().SetIupacaa().Set(prot); + prot_seq->SetInst().SetLength(TSeqPos(prot.length())); + prot_seq->SetInst().SetMol(objects::CSeq_inst::eMol_aa); + // fix sequence ID + const CSeq_id& feat_prod = feat.GetProduct().GetWhole(); + if (!feat_prod.Equals(orig_cds.GetProduct().GetWhole())) { + NON_CONST_ITERATE(CBioseq::TId, id, prot_seq->SetId()) { + if ((*id)->Which() == feat_prod.Which()) { + bool do_replace = false; + if ((*id)->IsGeneral()) { + if ((*id)->GetGeneral().IsSetDb()) { + if (feat_prod.GetGeneral().IsSetDb() && + NStr::Equal(feat_prod.GetGeneral().GetDb(), (*id)->GetGeneral().GetDb())) { + do_replace = true; + } + } else if (!feat_prod.GetGeneral().IsSetDb()) { + do_replace = true; + } + } else { + do_replace = true; + } + if (do_replace) { + (*id)->Assign(feat.GetProduct().GetWhole()); + } + } + } + } + // fix molinfo + if (prot_seq->IsSetDescr()) { + NON_CONST_ITERATE(CBioseq::TDescr::Tdata, mi, prot_seq->SetDescr().Set()) { + if ((*mi)->IsMolinfo()) { + feature::AdjustProteinMolInfoToMatchCDS((*mi)->SetMolinfo(), feat); + } + } + } + + // also fix protein feature locations + if (prot_seq->IsSetAnnot()) { + + CRef nuc2prot_mapper( + new CSeq_loc_Mapper(orig_cds, CSeq_loc_Mapper::eLocationToProduct, &scope)); + CRef prot_shadow = nuc2prot_mapper->Map(feat.GetLocation()); + TSeqPos start = prot_shadow->GetStart(eExtreme_Positional); + TSeqPos stop = prot_shadow->GetStop(eExtreme_Positional); + NON_CONST_ITERATE(CBioseq::TAnnot, ait, prot_seq->SetAnnot()) { + if ((*ait)->IsFtable()) { + CSeq_annot::TData::TFtable::iterator fit = (*ait)->SetData().SetFtable().begin(); + while (fit != (*ait)->SetData().SetFtable().end()) { + CRef new_prot_loc(new CSeq_loc()); + new_prot_loc->Assign((*fit)->GetLocation()); + bool complete_cut = false; + bool adjusted = false; + TSeqPos removed = 0; + if (start > 0) { + SeqLocAdjustForTrim(*new_prot_loc, 0, start - 1, orig_cds.GetProduct().GetId(), complete_cut, removed, adjusted); + } + if (!complete_cut && stop < orig_len - 1) { + SeqLocAdjustForTrim(*new_prot_loc, stop + 1, orig_len - 1, orig_cds.GetProduct().GetId(), complete_cut, removed, adjusted); + } + if (complete_cut) { + // out of range, drop this one + fit = (*ait)->SetData().SetFtable().erase(fit); + } else { + new_prot_loc->SetId(feat_prod); + AdjustProteinFeaturePartialsToMatchCDS(**fit, feat); + if (!feat_prod.Equals(orig_cds.GetProduct().GetWhole())) { + // fix sequence ID + (*fit)->SetLocation().Assign(*new_prot_loc); + } + } + ++fit; + } + } + } + } + + return prot_seq; +} + + +void CFeatGapInfo::x_AdjustCodebreaks(CSeq_feat& feat) +{ + if (!feat.IsSetData() || !feat.GetData().IsCdregion() || + !feat.GetData().GetCdregion().IsSetCode_break()) { + return; + } + CCdregion& cdr = feat.SetData().SetCdregion(); + CCdregion::TCode_break::iterator cit = cdr.SetCode_break().begin(); + while (cit != cdr.SetCode_break().end()) { + bool do_remove = false; + if ((*cit)->IsSetLoc()) { + CRef new_loc = feat.GetLocation().Intersect((*cit)->GetLoc(), 0, NULL); + if (new_loc && !new_loc->IsEmpty() && !new_loc->IsNull()) { + (*cit)->SetLoc().Assign(*new_loc); + } else { + do_remove = true; + } + } + if (do_remove) { + cit = cdr.SetCode_break().erase(cit); + } else { + ++cit; + } + } + if (cdr.GetCode_break().empty()) { + cdr.ResetCode_break(); + } +} + + +void CFeatGapInfo::x_AdjustAnticodons(CSeq_feat& feat) +{ + if (!feat.IsSetData() || !feat.GetData().IsRna() || + !feat.GetData().GetRna().IsSetExt() || + !feat.GetData().GetRna().GetExt().IsTRNA()) { + return; + } + CTrna_ext& trna = feat.SetData().SetRna().SetExt().SetTRNA(); + if (!trna.IsSetAnticodon()) { + return; + } + CRef new_loc = feat.GetLocation().Intersect(trna.GetAnticodon(), 0, NULL); + if (new_loc && !new_loc->IsEmpty() && !new_loc->IsNull()) { + trna.SetAnticodon().Assign(*new_loc); + } else { + trna.ResetAnticodon(); + } +} + + +void s_FixPartial(CSeq_feat& feat) +{ + if (feat.GetLocation().IsPartialStart(eExtreme_Biological) || + feat.GetLocation().IsPartialStop(eExtreme_Biological)) { + feat.SetPartial(true); + } +} + + +// returns a list of features to replace the original +// if list is empty, feature should be removed +// list should only contain one element if split is not specified +// coding regions should be retranslated after split +vector > CFeatGapInfo::AdjustForRelevantGapIntervals(bool make_partial, bool trim, bool split, bool in_intron) +{ + CRef new_feat(new CSeq_feat); + new_feat->Assign(*m_Feature.GetOriginalSeq_feat()); + vector > rval; + + if (!trim && !split) { + rval.push_back(new_feat); + return rval; + } else if (ShouldRemove()) { + return rval; + } + + if (trim && Trimmable()) { + Trim(new_feat->SetLocation(), make_partial, m_Feature.GetScope()); + new_feat->SetPartial(new_feat->GetLocation().IsPartialStart(objects::eExtreme_Positional) || new_feat->GetLocation().IsPartialStop(objects::eExtreme_Positional)); + if (new_feat->GetData().IsCdregion()) { + // adjust frame + TSeqPos frame_adjust = sequence::LocationOffset(m_Feature.GetLocation(), new_feat->GetLocation(), + sequence::eOffset_FromStart, &(m_Feature.GetScope())); + x_AdjustFrame(new_feat->SetData().SetCdregion(), frame_adjust); + } + } + + if (split) { + const string cds_gap_comment = "coding region disrupted by sequencing gap"; + + vector > locs = Split(new_feat->GetLocation(), in_intron, make_partial); + if (locs.size() > 0) { + // set comment + if (!new_feat->IsSetComment()) + { + new_feat->SetComment(cds_gap_comment); + } else if (new_feat->IsSetComment() && new_feat->GetComment().find(cds_gap_comment) == string::npos) + { + string comment = new_feat->GetComment(); + comment = comment + "; " + cds_gap_comment; + new_feat->SetComment(comment); + } + + // adjust transcript id if splitting + size_t transcript_id_offset = 1; + string transcript_id_label = kEmptyStr; + size_t protein_id_offset = 1; + string protein_id_label = kEmptyStr; + size_t protein_seqid_offset = 1; + + ITERATE(vector >, lit, locs) { + CRef split_feat(new CSeq_feat()); + // copy from original + split_feat->Assign(*new_feat); + // with new location + split_feat->SetLocation().Assign(**lit); + split_feat->SetPartial(split_feat->GetLocation().IsPartialStart(eExtreme_Positional) || new_feat->GetLocation().IsPartialStop(eExtreme_Positional)); + //adjust transcript id + x_AdjustOrigLabel(*split_feat, transcript_id_offset, transcript_id_label, "orig_transcript_id"); + x_AdjustOrigLabel(*split_feat, protein_id_offset, protein_id_label, "orig_protein_id"); + if (split_feat->GetData().IsCdregion()) { + // adjust frame + TSeqPos frame_adjust = sequence::LocationOffset(new_feat->GetLocation(), split_feat->GetLocation(), + sequence::eOffset_FromStart, &(m_Feature.GetScope())); + x_AdjustFrame(split_feat->SetData().SetCdregion(), frame_adjust); + // adjust product ID + if (split_feat->IsSetProduct() && split_feat->GetProduct().IsWhole()) { + CRef new_id = x_AdjustProtId(split_feat->GetProduct().GetWhole(), protein_seqid_offset); + protein_seqid_offset++; + CBioseq_Handle bsh = m_Feature.GetScope().GetBioseqHandle(*new_id); + while (bsh) { + new_id = x_AdjustProtId(split_feat->GetProduct().GetWhole(), protein_seqid_offset); + protein_seqid_offset++; + bsh = m_Feature.GetScope().GetBioseqHandle(*new_id); + } + split_feat->SetProduct().SetWhole().Assign(*new_id); + } + } + rval.push_back(split_feat); + } + + } else { + rval.push_back(new_feat); + } + } else { + rval.push_back(new_feat); + } + NON_CONST_ITERATE(vector >, it, rval) { + x_AdjustCodebreaks(**it); + x_AdjustAnticodons(**it); + s_FixPartial(**it); + } + return rval; +} + + +void CFeatGapInfo::x_AdjustFrame(CCdregion& cdregion, TSeqPos frame_adjust) +{ + frame_adjust = frame_adjust % 3; + if (frame_adjust == 0) { + return; + } + + CCdregion::TFrame orig_frame = cdregion.SetFrame(); + if (orig_frame == CCdregion::eFrame_not_set) { + orig_frame = CCdregion::eFrame_one; + } + + if (frame_adjust == 1) { + if (orig_frame == CCdregion::eFrame_one) { + cdregion.SetFrame(CCdregion::eFrame_three); // + } else if (orig_frame == CCdregion::eFrame_two) { + cdregion.SetFrame(CCdregion::eFrame_one); // + } else if (orig_frame == CCdregion::eFrame_three) { + cdregion.SetFrame(CCdregion::eFrame_two); + } + } else if (frame_adjust == 2) { + if (orig_frame == CCdregion::eFrame_one) { + cdregion.SetFrame(CCdregion::eFrame_two); + } else if (orig_frame == CCdregion::eFrame_two) { + cdregion.SetFrame(CCdregion::eFrame_three); + } else if (orig_frame == CCdregion::eFrame_three) { + cdregion.SetFrame(CCdregion::eFrame_one); // + } + } +} + + +TGappedFeatList ListGappedFeatures(CFeat_CI& feat_it, CScope& scope) +{ + TGappedFeatList gapped_feats; + while (feat_it) { + if (!feat_it->GetData().IsProt()) { + CRef fgap(new CFeatGapInfo(*feat_it)); + if (fgap->HasKnown() || fgap->HasUnknown() || fgap->HasNs()) { + gapped_feats.push_back(fgap); + } + } + ++feat_it; + } + return gapped_feats; +} + + +void ProcessForTrimAndSplitUpdates(CSeq_feat_Handle cds, vector > updates) +{ + CBioseq_Handle orig_prot_handle = cds.GetScope().GetBioseqHandle(cds.GetProduct()); + CConstRef orig_prot = orig_prot_handle.GetCompleteBioseq(); + CBioseq_set_Handle nph = orig_prot_handle.GetParentBioseq_set(); + CBioseq_set_EditHandle npeh(nph); + // need to remove original first if not changing sequence IDs + CBioseq_EditHandle beh(orig_prot_handle); + beh.Remove(); + ITERATE(vector >, it, updates) { + CRef new_prot = CFeatGapInfo::AdjustProteinSeq(*orig_prot, **it, *(cds.GetSeq_feat()), cds.GetScope()); + if (new_prot) { + npeh.AttachBioseq(*new_prot); + } + } + + CSeq_annot_Handle sah = cds.GetAnnot(); + CSeq_annot_EditHandle saeh = sah.GetEditHandle(); + CSeq_feat_EditHandle feh(cds); + if (updates.size() == 0) { + feh.Remove(); + } else { + feh.Replace(*(updates[0])); + for (size_t i = 1; i < updates.size(); i++) { + saeh.AddFeat(*(updates[i])); + } + } +} + + + +// for fixing feature IDs and feature ID xrefs +void FixFeatureIdsForUpdates(CSeq_feat& feat, CObject_id::TId& next_id) +{ + if (feat.IsSetId() && feat.GetId().IsLocal() && + feat.GetId().GetLocal().IsId()) { + feat.SetId().SetLocal().SetId(next_id); + ++next_id; + } + +} + + +void FixFeatureIdsForUpdates(vector > updates, CObject_id::TId& next_id) +{ + for (size_t i = 1; i < updates.size(); i++) { + FixFeatureIdsForUpdates(*(updates[i]), next_id); + } +} + + +bool s_IsRelated(const CSeq_feat& f1, CObject_id::TId search) +{ + if (!f1.IsSetXref()) { + return false; + } + ITERATE(CSeq_feat::TXref, xit, f1.GetXref()) { + if ((*xit)->IsSetId() && (*xit)->GetId().IsLocal() && + (*xit)->GetId().GetLocal().IsId() && + (*xit)->GetId().GetLocal().GetId() == search) { + return true; + } + } + return false; +} + + +bool s_IsRelated(const CSeq_feat& f1, const CSeq_feat& f2) +{ + if (f1.IsSetId() && f1.GetId().IsLocal() && f1.GetId().GetLocal().IsId() && + s_IsRelated(f2, f1.GetId().GetLocal().GetId())) { + return true; + } else if (f2.IsSetId() && f2.GetId().IsLocal() && f2.GetId().GetLocal().IsId() && + s_IsRelated(f1, f2.GetId().GetLocal().GetId())) { + return true; + } else { + return false; + } +} + + +bool CFeatGapInfo::IsRelatedByCrossRef(const CFeatGapInfo& other) const +{ + return s_IsRelated(*(GetFeature().GetSeq_feat()), *(other.GetFeature().GetSeq_feat())); +} + + + +void s_ReplaceFeatureIdXref(CSeq_feat& f, CObject_id::TId orig_id, CObject_id::TId new_id) +{ + if (orig_id > 0 && new_id > 0 && f.IsSetXref()) { + NON_CONST_ITERATE(CSeq_feat::TXref, xit, f.SetXref()) { + if ((*xit)->IsSetId() && (*xit)->GetId().IsLocal() && + (*xit)->GetId().GetLocal().IsId() && + (*xit)->GetId().GetLocal().GetId() == orig_id) { + (*xit)->SetId().SetLocal().SetId(new_id); + } + } + } +} + + +void FixFeatureIdsForUpdatePair(vector >& updates1, vector >& updates2) +{ + if (updates1.size() != updates2.size()) { + // can't fix if lists are different lengths + return; + } + if (updates1.size() < 2) { + // nothing to fix if there's only one object + } + vector >::iterator u1 = updates1.begin(); + vector >::iterator u2 = updates2.begin(); + + CObject_id::TId orig_id_1 = 0; + if ((*u1)->IsSetId() && (*u1)->GetId().IsLocal() && (*u1)->GetId().GetLocal().IsId()) { + orig_id_1 = (*u1)->GetId().GetLocal().GetId(); + } + CObject_id::TId orig_id_2 = 0; + if ((*u2)->IsSetId() && (*u2)->GetId().IsLocal() && (*u2)->GetId().GetLocal().IsId()) { + orig_id_2 = (*u2)->GetId().GetLocal().GetId(); + } + u1++; + u2++; + + while (u1 != updates1.end() && u2 != updates2.end()) { + CObject_id::TId new_id_1 = 0; + if ((*u1)->IsSetId() && (*u1)->GetId().IsLocal() && (*u1)->GetId().GetLocal().IsId()) { + new_id_1 = (*u1)->GetId().GetLocal().GetId(); + } + CObject_id::TId new_id_2 = 0; + if ((*u2)->IsSetId() && (*u2)->GetId().IsLocal() && (*u2)->GetId().GetLocal().IsId()) { + new_id_2 = (*u2)->GetId().GetLocal().GetId(); + } + s_ReplaceFeatureIdXref(**u1, orig_id_2, new_id_2); + s_ReplaceFeatureIdXref(**u2, orig_id_1, new_id_1); + ++u1; + ++u2; + } +} + + +END_SCOPE(edit) +END_SCOPE(objects) +END_NCBI_SCOPE diff --git a/c++/src/objtools/edit/gaps_edit.cpp b/c++/src/objtools/edit/gaps_edit.cpp index 9bda11d8..912ee71c 100644 --- a/c++/src/objtools/edit/gaps_edit.cpp +++ b/c++/src/objtools/edit/gaps_edit.cpp @@ -1,4 +1,4 @@ -/* $Id: gaps_edit.cpp 515961 2016-10-06 18:15:52Z ivanov $ +/* $Id: gaps_edit.cpp 521260 2016-12-07 14:11:06Z gotvyans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -228,7 +228,7 @@ CGapsEditor::CreateGap(CBioseq& bioseq, TSeqPos gap_start, TSeqPos gap_length) CRef seq = MakeGap(bioseq.SetInst(), gap_start, gap_length); if (seq.NotEmpty()) { - CDelta_seq::TLiteral& lit = seq->SetLiteral(); + seq->SetLiteral(); x_SetGapParameters(*seq); } return seq; @@ -395,8 +395,10 @@ void CGapsEditor::AppendGap(CBioseq& bioseq) CDelta_seq::TLiteral& lit = delta_seq->SetLiteral(); lit.SetLength(0); x_SetGapParameters(*delta_seq); - lit.SetLength(100); + const TSeqPos len = 100; + lit.SetLength(len); bioseq.SetInst().SetExt().SetDelta().Set().push_back(delta_seq); + bioseq.SetInst().SetLength() += len; } void CGapsEditor::AddBioseqAsLiteral(CBioseq& parent, CBioseq& bioseq) diff --git a/c++/src/objtools/edit/loc_edit.cpp b/c++/src/objtools/edit/loc_edit.cpp index 769adedf..0d90e97a 100644 --- a/c++/src/objtools/edit/loc_edit.cpp +++ b/c++/src/objtools/edit/loc_edit.cpp @@ -1,4 +1,4 @@ -/* $Id: loc_edit.cpp 496298 2016-03-25 13:38:39Z gotvyans $ +/* $Id: loc_edit.cpp 538916 2017-06-15 15:31:20Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -339,6 +340,9 @@ bool CLocationEditPolicy::Interpret5Policy case ePartialPolicy_eClearForGoodEnd: if (orig_feat.GetLocation().IsPartialStart(eExtreme_Biological) && orig_feat.GetData().IsCdregion() + && (!orig_feat.GetData().GetCdregion().IsSetFrame() || + orig_feat.GetData().GetCdregion().GetFrame() == CCdregion::eFrame_not_set || + orig_feat.GetData().GetCdregion().GetFrame() == CCdregion::eFrame_one) && bsh) { string transl_prot; try { @@ -2014,6 +2018,219 @@ void FeatureAdjustForInsert(CSeq_feat& feat, } +bool s_PPntComparePlus(const TSeqPos& p1, const TSeqPos& p2) +{ + return (p1 < p2); +} + + +bool s_PPntCompareMinus(const TSeqPos& p1, const TSeqPos& p2) +{ + return (p1 > p2); +} + + +bool CorrectIntervalOrder(CPacked_seqpnt& ppnt) +{ + bool rval = false; + if (!ppnt.IsSetPoints()) { + // nothing to do + } else if (!ppnt.IsSetStrand() || ppnt.GetStrand() == eNa_strand_plus || ppnt.GetStrand() == eNa_strand_unknown) { + if (!seq_mac_is_sorted(ppnt.GetPoints().begin(), ppnt.GetPoints().end(), s_PPntComparePlus)) { + stable_sort(ppnt.SetPoints().begin(), ppnt.SetPoints().end(), s_PPntComparePlus); + rval = true; + } + } else if (ppnt.IsSetStrand() && ppnt.GetStrand() == eNa_strand_minus) { + if (!seq_mac_is_sorted(ppnt.GetPoints().begin(), ppnt.GetPoints().end(), s_PPntCompareMinus)) { + stable_sort(ppnt.SetPoints().begin(), ppnt.SetPoints().end(), s_PPntCompareMinus); + rval = true; + } + } + return rval; +} + + +bool s_StrandsConsistent(const CSeq_interval& a, const CSeq_interval& b) +{ + if (a.IsSetStrand() && a.GetStrand() == eNa_strand_minus) { + if (!b.IsSetStrand() || b.GetStrand() != eNa_strand_minus) { + return false; + } else { + return true; + } + } else if (b.IsSetStrand() && b.GetStrand() == eNa_strand_minus) { + return false; + } else { + return true; + } +} + + +bool CorrectIntervalOrder(CPacked_seqint& pint) +{ + if (pint.Get().size() < 2) { + return false; + } + bool any_change = false; + + bool this_change = true; + while (this_change) { + this_change = false; + + // can only swap elements if they have the same strand and Seq-id + CPacked_seqint::Tdata::iterator a = pint.Set().begin(); + CPacked_seqint::Tdata::iterator b = a; + b++; + while (b != pint.Set().end()) { + if ((*a)->IsSetId() && (*b)->IsSetId() && + (*a)->GetId().Equals((*b)->GetId()) && + (*a)->IsSetFrom() && (*a)->IsSetTo() && (*a)->GetFrom() < (*a)->GetTo() && + (*b)->IsSetFrom() && (*b)->IsSetTo() && (*b)->GetFrom() < (*b)->GetTo() && + s_StrandsConsistent(**a, **b)) { + if ((*a)->IsSetStrand() && (*a)->GetStrand() == eNa_strand_minus) { + if ((*b)->GetTo() > (*a)->GetFrom()) { + CRef swp(a->GetPointer()); + a->Reset(b->GetPointer()); + b->Reset(swp.GetPointer()); + this_change = true; + any_change = true; + } + } else { + if ((*b)->GetTo() < (*a)->GetFrom()) { + CRef swp(a->GetPointer()); + a->Reset(b->GetPointer()); + b->Reset(swp.GetPointer()); + this_change = true; + any_change = true; + } + } + } + ++a; + ++b; + } + } + return any_change; +} + + +bool OneIdOneStrand(const CSeq_loc& loc, const CSeq_id** id, ENa_strand& strand) +{ + try { + CSeq_loc_CI li(loc); + *id = &(li.GetSeq_id()); + strand = li.IsSetStrand() ? li.GetStrand() : eNa_strand_plus; + if (strand == eNa_strand_unknown) { + strand = eNa_strand_plus; + } + if (strand != eNa_strand_plus && strand != eNa_strand_minus) { + return false; + } + ++li; + while (li) { + if (!li.GetSeq_id().Equals(**id)) { + return false; + } + ENa_strand this_strand = li.IsSetStrand() ? li.GetStrand() : eNa_strand_plus; + if (this_strand == eNa_strand_unknown) { + this_strand = eNa_strand_plus; + } + if (this_strand != strand) { + return false; + } + ++li; + } + return true; + } catch (CException& ex) { + return false; + } +} + + +bool CorrectIntervalOrder(CSeq_loc::TMix::Tdata& mix) +{ + bool any_change = false; + NON_CONST_ITERATE(CSeq_loc::TMix::Tdata, it, mix) { + any_change |= CorrectIntervalOrder(**it); + } + if (mix.size() < 2) { + return any_change; + } + bool this_change = true; + while (this_change) { + this_change = false; + + // can only swap elements if they have the same strand and Seq-id + CSeq_loc::TMix::Tdata::iterator a = mix.begin(); + CSeq_loc::TMix::Tdata::iterator b = a; + b++; + while (b != mix.end()) { + try { + const CSeq_id* a_id; + const CSeq_id* b_id; + ENa_strand a_strand; + ENa_strand b_strand; + if (OneIdOneStrand(**a, &a_id, a_strand) && + OneIdOneStrand(**b, &b_id, b_strand) && + a_id->Equals(*b_id) && + a_strand == b_strand) { + if (a_strand == eNa_strand_plus) { + if ((*a)->GetStart(eExtreme_Biological) > (*b)->GetStop(eExtreme_Biological)) { + CRef swp(a->GetPointer()); + a->Reset(b->GetPointer()); + b->Reset(swp.GetPointer()); + this_change = true; + any_change = true; + } + } else if (a_strand == eNa_strand_minus) { + if ((*a)->GetStart(eExtreme_Biological) < (*b)->GetStop(eExtreme_Biological)) { + CRef swp(a->GetPointer()); + a->Reset(b->GetPointer()); + b->Reset(swp.GetPointer()); + this_change = true; + any_change = true; + } + } + } + } catch (CException& ex) { + // not just one id + } + ++a; + ++b; + } + } + return any_change; +} + + +bool CorrectIntervalOrder(CSeq_loc& loc) +{ + bool any_change = false; + switch (loc.Which()) { + case CSeq_loc::e_Bond: + case CSeq_loc::e_Empty: + case CSeq_loc::e_Equiv: + case CSeq_loc::e_Feat: + case CSeq_loc::e_Int: + case CSeq_loc::e_not_set: + case CSeq_loc::e_Null: + case CSeq_loc::e_Pnt: + case CSeq_loc::e_Whole: + // nothing to do + break; + case CSeq_loc::e_Mix: + any_change = CorrectIntervalOrder(loc.SetMix().Set()); + break; + case CSeq_loc::e_Packed_int: + any_change = CorrectIntervalOrder(loc.SetPacked_int()); + break; + case CSeq_loc::e_Packed_pnt: + any_change = CorrectIntervalOrder(loc.SetPacked_pnt()); + break; + } + return any_change; +} + + END_SCOPE(edit) END_SCOPE(objects) END_NCBI_SCOPE diff --git a/c++/src/objtools/edit/mail_report.cpp b/c++/src/objtools/edit/mail_report.cpp index af920c6a..b4b0659d 100644 --- a/c++/src/objtools/edit/mail_report.cpp +++ b/c++/src/objtools/edit/mail_report.cpp @@ -1,4 +1,4 @@ -/* $Id: mail_report.cpp 519250 2016-11-14 18:26:30Z ivanov $ +/* $Id: mail_report.cpp 519061 2016-11-10 20:00:41Z filippov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/edit/remote_updater.cpp b/c++/src/objtools/edit/remote_updater.cpp index 8bb0214d..d4b61d76 100644 --- a/c++/src/objtools/edit/remote_updater.cpp +++ b/c++/src/objtools/edit/remote_updater.cpp @@ -1,4 +1,4 @@ -/* $Id: remote_updater.cpp 493987 2016-03-02 20:43:23Z gotvyans $ +/* $Id: remote_updater.cpp 539753 2017-06-27 14:26:39Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -454,6 +454,7 @@ void CRemoteUpdater::UpdateOrgFromTaxon(objects::ILineErrorListener* logger, obj if ((*reply_it)->IsData() && (*reply_it)->SetData().IsSetOrg()) { (*reply_it)->SetData().SetOrg().ResetSyn(); + (*reply_it)->SetData().SetOrg().SetOrgname().SetFormalNameFlag(false); xUpdate(it->second.owner, (*reply_it)->SetData().SetOrg()); } diff --git a/c++/src/objtools/edit/rna_edit.cpp b/c++/src/objtools/edit/rna_edit.cpp index ec9eb4f3..c885a248 100755 --- a/c++/src/objtools/edit/rna_edit.cpp +++ b/c++/src/objtools/edit/rna_edit.cpp @@ -1,4 +1,4 @@ -/* $Id: rna_edit.cpp 513682 2016-09-14 14:50:59Z ivanov $ +/* $Id: rna_edit.cpp 513597 2016-09-13 15:00:33Z filippov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/edit/seq_entry_edit.cpp b/c++/src/objtools/edit/seq_entry_edit.cpp index 2f100f58..c80cdcfe 100644 --- a/c++/src/objtools/edit/seq_entry_edit.cpp +++ b/c++/src/objtools/edit/seq_entry_edit.cpp @@ -1,4 +1,4 @@ -/* $Id: seq_entry_edit.cpp 519211 2016-11-14 16:04:20Z ivanov $ +/* $Id: seq_entry_edit.cpp 541341 2017-07-17 15:57:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -30,6 +30,7 @@ */ #include #include +#include #include #include #include @@ -60,7 +61,7 @@ #include #include -#include +#include #include #include @@ -1501,6 +1502,94 @@ void BioseqSetDescriptorPropagateDown( } +CSeq_id::E_Choice TypeFromLabel(const string& label) +{ + if (NStr::EqualNocase(label, "LocalId")) { + return CSeq_id::e_Local; + } else if (NStr::EqualNocase(label, "DDBJ")) { + return CSeq_id::e_Ddbj; + } else if (NStr::EqualNocase(label, "EMBL")) { + return CSeq_id::e_Embl; + } else if (NStr::EqualNocase(label, "GenBank")) { + return CSeq_id::e_Genbank; + } else if (NStr::EqualNocase(label, "RefSeq")) { + return CSeq_id::e_Other; + } else if (NStr::EqualNocase(label, "General")) { + return CSeq_id::e_General; + } else { + return CSeq_id::e_not_set; + } +} + + +string LabelFromType(CSeq_id::E_Choice choice) +{ + switch (choice) { + case CSeq_id::e_Local: + return "LocalId"; + break; + case CSeq_id::e_Ddbj: + return "DDBJ"; + break; + case CSeq_id::e_Embl: + return "EMBL"; + break; + case CSeq_id::e_Genbank: + return "GenBank"; + break; + case CSeq_id::e_Other: + return "RefSeq"; + break; + case CSeq_id::e_General: + return "General"; + break; + default: + return kEmptyStr; + break; + } +} + + +string MakeOriginalLabelForId(const CSeq_id& id) +{ + string val = kEmptyStr; + switch (id.Which()) { + case CSeq_id::e_Local: + if (id.GetLocal().IsStr()) { + val = id.GetLocal().GetStr(); + } else if (id.GetLocal().IsId()) { + val = NStr::NumericToString(id.GetLocal().GetId()); + } + break; + case CSeq_id::e_Ddbj: + case CSeq_id::e_Embl: + case CSeq_id::e_Genbank: + case CSeq_id::e_Other: + case CSeq_id::e_General: + val = id.AsFastaString(); + break; + default: + break; + } + return val; +} + + +CRef MakeOriginalIdField(const CSeq_id& id) +{ + CRef field(NULL); + + string label = LabelFromType(id.Which()); + string val = MakeOriginalLabelForId(id); + if (!NStr::IsBlank(label) && !NStr::IsBlank(val)) { + field = new CUser_field(); + field->SetLabel().SetStr(label); + field->SetData().SetStr(val); + } + return field; +} + + void AddLocalIdUserObjects(CSeq_entry& entry) { if (entry.IsSeq()) { @@ -1519,19 +1608,9 @@ void AddLocalIdUserObjects(CSeq_entry& entry) CRef obj(new CUser_object()); obj->SetObjectType(CUser_object::eObjectType_OriginalId); ITERATE(CBioseq::TId, id, entry.GetSeq().GetId()) { - if ((*id)->IsLocal()) { - string val = ""; - if ((*id)->GetLocal().IsStr()) { - val = (*id)->GetLocal().GetStr(); - } else if ((*id)->GetLocal().IsId()) { - val = NStr::NumericToString((*id)->GetLocal().GetId()); - } - if (!NStr::IsBlank(val)) { - CRef field(new CUser_field()); - field->SetLabel().SetStr("LocalId"); - field->SetData().SetStr(val); - obj->SetData().push_back(field); - } + CRef field = MakeOriginalIdField(**id); + if (field) { + obj->SetData().push_back(field); } } if (obj->IsSetData()) { @@ -1548,34 +1627,62 @@ void AddLocalIdUserObjects(CSeq_entry& entry) } +bool IsMatchingIdMissing(const CUser_field& field, const CBioseq::TId& ids) +{ + if (!field.IsSetLabel() || !field.GetLabel().IsStr() || + NStr::IsBlank(field.GetLabel().GetStr()) || + !field.IsSetData() || !field.GetData().IsStr() || + NStr::IsBlank(field.GetData().GetStr())) { + return false; + } + bool found = false; + bool any_type = false; + bool found_mismatch = false; + + CSeq_id::E_Choice choice = TypeFromLabel(field.GetLabel().GetStr()); + if (choice == CSeq_id::e_not_set) { + return false; + } + + ITERATE(CBioseq::TId, id_it, ids) { + string expected = MakeOriginalLabelForId(**id_it); + if ((*id_it)->Which() == choice) { + any_type = true; + if (NStr::Equal(field.GetData().GetStr(), expected)) { + found = true; + break; + } + } else if ((*id_it)->Which() == CSeq_id::e_Local) { + if (choice == CSeq_id::e_Ddbj && NStr::StartsWith(expected, "dbj_")) { + found_mismatch = true; + } + if (choice == CSeq_id::e_Embl && NStr::StartsWith(expected, "emb_")) { + found_mismatch = true; + } + if (choice == CSeq_id::e_Genbank && NStr::StartsWith(expected, "gb_")) { + found_mismatch = true; + } + if (choice == CSeq_id::e_Other && NStr::StartsWith(expected, "ref_")) { + found_mismatch = true; + } + } + } + if (!found && (any_type || found_mismatch)) { + return true; + } else { + return false; + } +} + + bool HasRepairedIDs(const CUser_object& user, const CBioseq::TId& ids) { bool rval = false; if (user.IsSetData()) { ITERATE(CUser_object::TData, it, user.GetData()) { - if ((*it)->IsSetLabel() && (*it)->GetLabel().IsStr() - && NStr::EqualNocase((*it)->GetLabel().GetStr(), "LocalId") - && (*it)->IsSetData() - && (*it)->GetData().IsStr()) { - string orig_id = (*it)->GetData().GetStr(); - bool found = false; - bool any_local = false; - ITERATE(CBioseq::TId, id_it, ids) { - if ((*id_it)->IsLocal()) { - any_local = true; - if ((*id_it)->GetLocal().IsStr() - && NStr::EqualNocase((*id_it)->GetLocal().GetStr(), orig_id)) { - found = true; - } else if ((*id_it)->GetLocal().IsId() - && NStr::EqualNocase(NStr::NumericToString((*id_it)->GetLocal().GetId()), orig_id)) { - found = true; - } - } - } - if (any_local && !found) { - rval = true; - break; - } + if (IsMatchingIdMissing(**it, ids)) { + rval = true; + break; } } } @@ -2231,8 +2338,8 @@ static void s_AdjustInternalCutLocations(TCuts& cuts, } -/// 1) Merge abutting and overlapping cuts. -/// 2) Adjust any internal cuts to terminal cuts according to option. +/// 1) Adjust any internal cuts to terminal cuts according to option. +/// 2) Merge abutting and overlapping cuts. /// 3) Sort the cuts from greatest to least so that sequence /// data and annotation will be deleted from greatest loc to smallest loc. /// That way we don't have to adjust coordinate values after @@ -2242,22 +2349,35 @@ void GetSortedCuts(CBioseq_Handle bsh, TCuts& sorted_cuts, EInternalTrimType internal_cut_conversion) { - sorted_cuts = cuts; + if (internal_cut_conversion == eDoNotTrimInternal) { + // Remove internal cuts + for (TCuts::size_type ii = 0; ii < cuts.size(); ++ii) { + const TRange& cut = cuts[ii]; + TSeqPos from = cut.GetFrom(); + TSeqPos to = cut.GetTo(); + + if (from == 0 || to == bsh.GetBioseqLength()-1) { + sorted_cuts.push_back(cut); + } + } + } + else { + sorted_cuts = cuts; + } /*************************************************************************** - * Merge abutting and overlapping cuts * Adjust internal cuts to terminal cuts + * Merge abutting and overlapping cuts ***************************************************************************/ CRangeCmp asc(CRangeCmp::eAscending); sort(sorted_cuts.begin(), sorted_cuts.end(), asc); - // Merge abutting and overlapping cuts - s_MergeCuts(sorted_cuts); - // Adjust internal cuts to terminal cuts s_AdjustInternalCutLocations(sorted_cuts, bsh.GetBioseqLength(), internal_cut_conversion); + // Merge abutting and overlapping cuts + s_MergeCuts(sorted_cuts); /*************************************************************************** * Sort the cuts in descending order @@ -2281,29 +2401,89 @@ void TrimSeqData(CBioseq_Handle bsh, return; } - // There should be sequence data - if ( !(bsh.CanGetInst() && bsh.GetInst().IsSetSeq_data()) ) { - return; + // Add the complete bioseq to scope + CRef bseq(new CBioseq); + bseq->Assign(*bsh.GetCompleteBioseq()); + CScope& scope = bsh.GetTopLevelEntry().GetScope(); + CBioseq_Handle complete_bsh = scope.AddBioseq(*bseq); + + // Determine the "good" range sequence coordinates + TSeqPos left_pos = 0; + TSeqPos right_pos = inst->GetLength() - 1; + for (const auto& cut : sorted_cuts) { + if (cut.GetTo() == right_pos) { + right_pos = cut.GetFrom() - 1; } - // Copy residues to buffer - CSeqVector vec(bsh, CBioseq_Handle::eCoding_Iupac); - string seq_string; - vec.GetSeqData(0, vec.size(), seq_string); + if (cut.GetFrom() == left_pos) { + left_pos = cut.GetTo() + 1; + } + } - // Delete residues per cut - for (TCuts::size_type ii = 0; ii < sorted_cuts.size(); ++ii) { - const TRange& cut = sorted_cuts[ii]; - TSeqPos start = cut.GetFrom(); - TSeqPos length = cut.GetTo() - start + 1; - seq_string.erase(start, length); - } + // Create a new Delta-ext + CAutoInitRef pDeltaExt; + CSeqMap_CI seqmap_ci = complete_bsh.GetSeqMap().ResolvedRangeIterator(&complete_bsh.GetScope(), + left_pos, + 1 + (right_pos - left_pos)); + for (; seqmap_ci; ++seqmap_ci) { + switch (seqmap_ci.GetType()) { + case CSeqMap::eSeqGap: + { + // Sequence gaps + const TSeqPos uGapLength = seqmap_ci.GetLength(); + const bool bIsLengthKnown = !seqmap_ci.IsUnknownLength(); + CConstRef pOriginalGapSeqLiteral = + seqmap_ci.GetRefGapLiteral(); + CAutoInitRef pDeltaSeq; + CAutoInitRef pNewGapLiteral; + if (pOriginalGapSeqLiteral) { + pNewGapLiteral->Assign(*pOriginalGapSeqLiteral); + } + if (!bIsLengthKnown) { + pNewGapLiteral->SetFuzz().SetLim(CInt_fuzz::eLim_unk); + } + pNewGapLiteral->SetLength(uGapLength); + pDeltaSeq->SetLiteral(*pNewGapLiteral); + pDeltaExt->Set().push_back(ncbi::Ref(&*pDeltaSeq)); + } + break; + case CSeqMap::eSeqData: + { + // Sequence data + string new_data; + CSeqVector seqvec(complete_bsh, CBioseq_Handle::eCoding_Iupac); + seqvec.GetSeqData(seqmap_ci.GetPosition(), seqmap_ci.GetEndPosition(), + new_data); + CRef pSeqData(new CSeq_data()); + pSeqData->SetIupacna(*new CIUPACna(new_data)); + CSeqportUtil::Pack(pSeqData); + CAutoInitRef pDeltaSeq; + pDeltaSeq->SetLiteral().SetLength(seqmap_ci.GetLength()); + pDeltaSeq->SetLiteral().SetSeq_data(*pSeqData); + pDeltaExt->Set().push_back(ncbi::Ref(&*pDeltaSeq)); + } + break; + } + } + + scope.RemoveBioseq(complete_bsh); - // Update sequence length and sequence data - inst->SetLength(seq_string.size()); - inst->SetSeq_data().SetIupacna(*new CIUPACna(seq_string)); - CSeqportUtil::Pack(&inst->SetSeq_data()); + // Update sequence repr, length and data + inst->ResetExt(); + inst->ResetSeq_data(); + inst->SetLength(1 + (right_pos - left_pos)); + if (pDeltaExt->Set().size() == 1) { + // Repr raw + inst->SetRepr(CSeq_inst::eRepr_raw); + CRef pDeltaSeq = *pDeltaExt->Set().begin(); + CSeq_data& seq_data = pDeltaSeq->SetLiteral().SetSeq_data(); + inst->SetSeq_data(seq_data); + } + else { + // Repr delta + inst->SetExt().SetDelta(*pDeltaExt); } +} static void s_GetTrimCoordinates(CBioseq_Handle bsh, @@ -2973,7 +3153,10 @@ CRef SetNewProteinSequence(CScope& new_scope, if (new_inst->IsSetSeq_data()) { // Generate new protein sequence data and length new_protein_bioseq = CSeqTranslator::TranslateToProtein(*cds, new_scope); - if (new_protein_bioseq->GetInst().GetSeq_data().IsIupacaa()) + if (!new_protein_bioseq) { + // too short to translate + } + else if (new_protein_bioseq->GetInst().GetSeq_data().IsIupacaa()) { new_inst->SetSeq_data().SetIupacaa().Set( new_protein_bioseq->GetInst().GetSeq_data().GetIupacaa().Get()); @@ -3308,9 +3491,9 @@ string GetTargetedLocusNameConsensus(const string& tls1, const string& tls2) } vector tokens1; - NStr::Tokenize(tls1, " ", tokens1); + NStr::Split(tls1, " ", tokens1, NStr::fSplit_Tokenize); vector tokens2; - NStr::Tokenize(tls2, " ", tokens2); + NStr::Split(tls2, " ", tokens2, NStr::fSplit_Tokenize); size_t t1_pos = 0; size_t t1_match_start = string::npos; diff --git a/c++/src/objtools/edit/seqid_guesser.cpp b/c++/src/objtools/edit/seqid_guesser.cpp index a74a3fc6..41159fde 100644 --- a/c++/src/objtools/edit/seqid_guesser.cpp +++ b/c++/src/objtools/edit/seqid_guesser.cpp @@ -1,4 +1,4 @@ -/* $Id: seqid_guesser.cpp 482267 2015-10-21 19:28:06Z filippov $ +/* $Id: seqid_guesser.cpp 546695 2017-09-20 17:25:08Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -58,12 +58,19 @@ CSeqIdGuesser::CSeqIdGuesser(CSeq_entry_Handle entry) : m_SeqEntry(entry) } } ITERATE(CBioseq::TId, id, bi->GetCompleteBioseq()->GetId()) { - string label = ""; + string label; (*id)->GetLabel(&label); x_AddIdString(label, *id); - label = ""; + + label.clear(); + int version; + (*id)->GetLabel(&label, &version, CSeq_id::eContent); + x_AddIdString(label, *id); + + label.clear(); (*id)->GetLabel(&label, CSeq_id::eContent); x_AddIdString(label, *id); + if ((*id)->IsGenbank()) { size_t pos = NStr::Find(label, "."); if (pos != string::npos) { @@ -96,7 +103,7 @@ CSeqIdGuesser::CSeqIdGuesser(CSeq_entry_Handle entry) : m_SeqEntry(entry) // File ID are usually a filename plus a slash plus the original local ID // add the filename as its own identifier, but only add the local ID if it hasn't // already been encountered - size_t pos = NStr::Find(tag_str, "/", 0, string::npos, NStr::eLast); + size_t pos = NStr::Find(tag_str, "/", NStr::eNocase, NStr::eReverseSearch); if (pos != string::npos) { string file = tag_str.substr(0, pos); x_AddIdString(file, *id); @@ -175,7 +182,7 @@ vector CSeqIdGuesser::GetIdStrings(CBioseq_Handle bsh) // File ID are usually a filename plus a slash plus the original local ID // add the filename as its own identifier, but only add the local ID if it hasn't // already been encountered - size_t pos = NStr::Find(tag_str, "/", 0, string::npos, NStr::eLast); + size_t pos = NStr::Find(tag_str, "/", NStr::eNocase, NStr::eReverseSearch); if (pos != string::npos) { string file = tag_str.substr(0, pos); id_str.push_back(file); diff --git a/c++/src/objtools/edit/source_edit.cpp b/c++/src/objtools/edit/source_edit.cpp index 0cb9148a..ebf27fad 100644 --- a/c++/src/objtools/edit/source_edit.cpp +++ b/c++/src/objtools/edit/source_edit.cpp @@ -1,4 +1,4 @@ -/* $Id: source_edit.cpp 453178 2014-12-01 18:15:03Z bollin $ +/* $Id: source_edit.cpp 540409 2017-07-06 15:49:20Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -51,6 +51,7 @@ BEGIN_SCOPE(edit) bool CleanupForTaxnameChange( objects::CBioSource& src ) { bool rval = RemoveOldName(src); + rval |= RemoveMod(src, COrgMod::eSubtype_type_material); rval |= RemoveTaxId(src); if (src.IsSetOrg() && src.GetOrg().IsSetCommon()) { src.SetOrg().ResetCommon(); @@ -64,13 +65,18 @@ bool CleanupForTaxnameChange( objects::CBioSource& src ) } bool RemoveOldName( objects::CBioSource& src ) +{ + return RemoveMod(src, COrgMod::eSubtype_old_name); +} + +bool RemoveMod( objects::CBioSource& src, objects::COrgMod::ESubtype subtype ) { bool erased = false; if (src.IsSetOrg() && src.GetOrg().IsSetOrgname() && src.GetOrg().GetOrgname().IsSetMod()) { COrgName::TMod::iterator it = src.SetOrg().SetOrgname().SetMod().begin(); while (it != src.SetOrg().SetOrgname().SetMod().end()) { - if ((*it)->GetSubtype() && (*it)->GetSubtype() == COrgMod::eSubtype_old_name) { + if ((*it)->GetSubtype() && (*it)->GetSubtype() == subtype) { it = src.SetOrg().SetOrgname().SetMod().erase(it); erased = true; } else { @@ -105,6 +111,54 @@ bool RemoveTaxId( objects::CBioSource& src ) } +bool s_ProcessReply(const CT3Reply& reply, CRef org) +{ + if (reply.IsData()) { + org->Assign(reply.GetData().GetOrg()); + return true; + } else if (reply.IsError() && reply.GetError().IsSetMessage()) { + ERR_POST(reply.GetError().GetMessage()); + return false; + } else { + ERR_POST("Taxonomy service failure"); + return false; + } +} + + +void AddMissingCommonOrgMods(const COrg_ref& o1, const COrg_ref& o2, COrg_ref& common) +{ + if (!o1.IsSetOrgMod() || !o2.IsSetOrgMod()) { + return; + } + ITERATE(COrgName::TMod, it1, o1.GetOrgname().GetMod()) { + bool found_in_both = false; + ITERATE(COrgName::TMod, it2, o2.GetOrgname().GetMod()) { + if ((*it1)->Equals(**it2)) { + found_in_both = true; + break; + } + } + if (found_in_both) { + bool already_in_common = false; + if (common.IsSetOrgMod()) { + ITERATE(COrgName::TMod, it3, common.GetOrgname().GetMod()) { + if ((*it3)->Equals(**it1)) { + already_in_common = true; + break; + } + } + } + if (!already_in_common) { + CRef add(new COrgMod()); + add->Assign(**it1); + common.SetOrgname().SetMod().push_back(add); + } + } + } +} + + CRef MakeCommonBioSource(const objects::CBioSource& src1, const objects::CBioSource& src2) { CRef common(NULL); @@ -112,35 +166,73 @@ CRef MakeCommonBioSource(const objects::CBioSource& src1, const obje if (!src1.IsSetOrg() || !src2.IsSetOrg()) { return common; } - int taxid1 = src1.GetOrg().GetTaxId(); - int taxid2 = src2.GetOrg().GetTaxId(); - if (taxid1 == 0 || taxid2 == 0) { + + CTaxon3 taxon3; + taxon3.Init(); + + // do lookup before attempting to merge + vector > rq_list; + CRef o1(new COrg_ref()); + o1->Assign(src1.GetOrg()); + rq_list.push_back(o1); + CRef o2(new COrg_ref()); + o2->Assign(src2.GetOrg()); + rq_list.push_back(o2); + CRef reply = taxon3.SendOrgRefList(rq_list); + if (!reply || reply->GetReply().size() != 2) { + ERR_POST("Taxonomy service failure"); + return CRef(NULL); + } + if (!s_ProcessReply(*(reply->GetReply().front()), o1) || + !s_ProcessReply(*(reply->GetReply().back()), o2)) { + return common; + } + + int taxid1 = o1->GetTaxId(); + int taxid2 = o2->GetTaxId(); + if (taxid1 == 0) { + ERR_POST("No taxonomy ID for " + o1->GetTaxname()); + return common; + } else if (taxid2 == 0) { + ERR_POST("No taxonomy ID for " + o2->GetTaxname()); return common; } else if (taxid1 == taxid2) { - common = src1.MakeCommon(src2); + CRef tmp1(new CBioSource()); + tmp1->Assign(src1); + tmp1->SetOrg().Assign(*o1); + CRef tmp2(new CBioSource()); + tmp2->Assign(src2); + tmp2->SetOrg().Assign(*o2); + common = tmp1->MakeCommon(*tmp2); } else { CRef rq(new CT3Request()); rq->SetJoin().Set().push_back(taxid1); rq->SetJoin().Set().push_back(taxid2); + string err_nums = "(" + NStr::NumericToString(taxid1) + "," + NStr::NumericToString(taxid2) + ")"; CTaxon3_request request; request.SetRequest().push_back(rq); - CTaxon3 taxon3; - taxon3.Init(); CRef reply = taxon3.SendRequest(request); - if (reply) { - CTaxon3_reply::TReply::const_iterator reply_it = reply->GetReply().begin(); - while (reply_it != reply->GetReply().end()) { - if ((*reply_it)->IsData() - && (*reply_it)->GetData().GetOrg().IsSetTaxname()) { + if (!reply || reply->GetReply().size() != 1) { + ERR_POST("Taxonomy service failure" + err_nums); + return CRef(NULL); + } + const CT3Reply& join_reply = *(reply->GetReply().front()); + if (join_reply.IsData()) { + if (join_reply.GetData().IsSetOrg()) { + if (join_reply.GetData().GetOrg().IsSetTaxname()) { bool is_species_level = false, force_consult = false, has_nucleomorphs = false; - (*reply_it)->GetData().GetTaxFlags (is_species_level, force_consult, has_nucleomorphs); + join_reply.GetData().GetTaxFlags(is_species_level, force_consult, has_nucleomorphs); if (is_species_level) { - common.Reset(new CBioSource()); - common->SetOrg().Assign((*reply_it)->GetData().GetOrg()); + common = src1.MakeCommonExceptOrg(src2); + common->SetOrg().Assign(join_reply.GetData().GetOrg()); + } else { + ERR_POST("Taxonomy join reply is not species level" + err_nums); } - break; + } else { + ERR_POST("Taxonomy join reply Org-ref does not contain taxname" + err_nums); } - ++reply_it; + } else { + ERR_POST("Taxonomy join reply does not contain Org-ref" + err_nums); } } } diff --git a/c++/src/objtools/edit/string_constraint.cpp b/c++/src/objtools/edit/string_constraint.cpp index c77a2604..d3b6519c 100644 --- a/c++/src/objtools/edit/string_constraint.cpp +++ b/c++/src/objtools/edit/string_constraint.cpp @@ -1,4 +1,4 @@ -/* $Id: string_constraint.cpp 518211 2016-11-01 15:04:31Z ivanov $ +/* $Id: string_constraint.cpp 518013 2016-10-31 12:22:48Z filippov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/format/CMakeLists.txt b/c++/src/objtools/format/CMakeLists.txt new file mode 100644 index 00000000..40bf5b5b --- /dev/null +++ b/c++/src/objtools/format/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xformat.lib.txt) + diff --git a/c++/src/objtools/format/CMakeLists.xformat.lib.txt b/c++/src/objtools/format/CMakeLists.xformat.lib.txt new file mode 100644 index 00000000..1e7fbe5a --- /dev/null +++ b/c++/src/objtools/format/CMakeLists.xformat.lib.txt @@ -0,0 +1,25 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/format/Makefile.xformat.lib +# +add_library(xformat + accession_item basecount_item comment_item contig_item date_item + dbsource_item defline_item feature_item genome_item ctrl_items + keywords_item locus_item primary_item reference_item segment_item + sequence_item source_item version_item wgs_item tsa_item flat_seqloc qualifiers + context gather_items embl_gather genbank_gather + flat_file_generator item_formatter embl_formatter genbank_formatter + format_item_ostream item_ostream ostream_text_ostream + origin_item ftable_gather ftable_formatter + gbseq_formatter flat_file_config alignment_item + gap_item genome_project_item sam_formatter cigar_formatter + gather_iter html_anchor_item inst_info_map gene_finder flat_qual_slots +) +add_dependencies(xformat + submit gbseq +) + +target_link_libraries(xformat + gbseq mlacli xalnmgr + xcleanup +) + diff --git a/c++/src/objtools/format/accession_item.cpp b/c++/src/objtools/format/accession_item.cpp index afbe719e..2a80bcd2 100644 --- a/c++/src/objtools/format/accession_item.cpp +++ b/c++/src/objtools/format/accession_item.cpp @@ -1,4 +1,4 @@ -/* $Id: accession_item.cpp 472056 2015-07-06 19:29:12Z gotvyans $ +/* $Id: accession_item.cpp 533931 2017-04-20 21:18:56Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -82,37 +82,34 @@ void CAccessionItem::x_GatherInfo(CBioseqContext& ctx) const CSeq_id& id = *ctx.GetPrimaryId(); + if (!ctx.GetLocation().IsWhole()) { + // specific region is set + m_Region.Reset(&ctx.GetLocation()); + m_IsSetRegion = true; + } + + bool okay = true; // if no accession, do not show local or general in ACCESSION if ((id.IsGeneral() || id.IsLocal()) && (ctx.Config().IsModeEntrez() || ctx.Config().IsModeGBench())) { - return; + okay = false; } - m_Accession = id.GetSeqIdString(); - - if ( ctx.IsWGS() && ctx.GetLocation().IsWhole() && ctx.GetTech() == CMolInfo::eTech_wgs ) { - size_t acclen = m_Accession.length(); - m_WGSAccession = m_Accession; - if (acclen >= 12) { - size_t stem_len = (acclen >= 15) ? 7 : 6, tail_len = acclen - stem_len; - if (m_Accession.find_first_not_of("0", stem_len) != NPOS) { - m_WGSAccession.replace(stem_len, tail_len, tail_len, '0'); - } else { - m_WGSAccession.erase(); + + if (okay) { + m_Accession = id.GetSeqIdString(); + + if ( ctx.IsWGS() && ctx.GetLocation().IsWhole() && ctx.GetTech() == CMolInfo::eTech_wgs ) { + size_t acclen = m_Accession.length(); + m_WGSAccession = m_Accession; + if (acclen >= 12) { + size_t stem_len = (acclen >= 15) ? 7 : 6, tail_len = acclen - stem_len; + if (m_Accession.find_first_not_of("0", stem_len) != NPOS) { + m_WGSAccession.replace(stem_len, tail_len, tail_len, '0'); + } else { + m_WGSAccession.erase(); + } } } - /* - if (acclen == 12 && ! NStr::EndsWith(m_WGSAccession, "000000")) { - m_WGSAccession.replace(6, acclen - 6, acclen - 6, '0'); - } else if (acclen == 13 && ! NStr::EndsWith(m_WGSAccession, "0000000")) { - m_WGSAccession.replace(6, acclen - 7, acclen - 7, '0'); - } else if (acclen == 14 && ! NStr::EndsWith(m_WGSAccession, "00000000")) { - m_WGSAccession.replace(6, acclen - 8, acclen - 8, '0'); - } else if (acclen == 15 && ! NStr::EndsWith(m_WGSAccession, "00000000")) { - m_WGSAccession.replace(6, acclen - 8, acclen - 8, '0'); - } else { - m_WGSAccession.erase(); - } - */ } // extra accessions not done if we're taking a slice @@ -149,19 +146,17 @@ void CAccessionItem::x_GatherInfo(CBioseqContext& ctx) } } - /// add GPipe accessions as extra - ITERATE (CBioseq::TId, it, ctx.GetHandle().GetBioseqCore()->GetId()) { - if ((*it)->IsGpipe()) { - m_ExtraAccessions.push_back((*it)->GetGpipe().GetAccession()); + /// add GPipe accessions as extra if no RefSeq accession + if (okay && ! id.IsOther() && ! id.IsGpipe()) { + ITERATE (CBioseq::TId, it, ctx.GetHandle().GetBioseqCore()->GetId()) { + if ((*it)->IsGpipe()) { + m_ExtraAccessions.push_back((*it)->GetGpipe().GetAccession()); + } } } sort(m_ExtraAccessions.begin(), m_ExtraAccessions.end()); - } else { - // specific region is set - m_Region.Reset(&ctx.GetLocation()); - m_IsSetRegion = true; } } diff --git a/c++/src/objtools/format/comment_item.cpp b/c++/src/objtools/format/comment_item.cpp index 5b076397..8e726153 100644 --- a/c++/src/objtools/format/comment_item.cpp +++ b/c++/src/objtools/format/comment_item.cpp @@ -1,4 +1,4 @@ -/* $Id: comment_item.cpp 506085 2016-07-01 14:25:26Z gotvyans $ +/* $Id: comment_item.cpp 528985 2017-02-28 01:19:12Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -2010,7 +2010,7 @@ string s_CreateHistCommentString (const string& prefix, const string& suffix, const CSeq_hist_rec& hist, - const CBioseqContext& ctx) + CBioseqContext& ctx) { //if (!hist.CanGetDate() || !hist.CanGetIds()) { // return "???"; @@ -2042,12 +2042,22 @@ string s_CreateHistCommentString if ( count != 0 ) { text << ","; } + string accn = GetAccessionForGi(gis[count], ctx.GetScope(), sequence::eWithAccessionVersion, sequence::eGetId_Best); + text << " "; + if (NStr::Find(accn, ".") != NPOS) { + NcbiId(text, accn, ctx.Config().DoHTML()); + } else { + text << "gi:"; + NcbiId(text, gis[count], ctx.Config().DoHTML()); + } + /* was text << " gi:"; #ifdef NEW_HTML_FMT ctx.Config().GetHTMLFormatter().FormatGeneralId(text, NStr::NumericToString(gis[count])); #else NcbiId(text, gis[count], ctx.Config().DoHTML()); #endif + */ } text << '.' << '\n'; diff --git a/c++/src/objtools/format/context.cpp b/c++/src/objtools/format/context.cpp index ea1dfa7e..04034daf 100644 --- a/c++/src/objtools/format/context.cpp +++ b/c++/src/objtools/format/context.cpp @@ -1,4 +1,4 @@ -/* $Id: context.cpp 515538 2016-10-03 16:03:11Z ivanov $ +/* $Id: context.cpp 530533 2017-03-15 17:22:48Z gotvyans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -122,6 +122,7 @@ CBioseqContext::CBioseqContext m_IsCrossKingdom(false), m_fUnverified(fUnverified_None), m_ShowAnnotCommentAsCOMMENT(false), + m_ShowAnnotCommentAsCOMMENT_checked(false), m_FFCtx(ffctx), m_Master(mctx), m_TLSeqEntryCtx(tlsec) @@ -182,6 +183,7 @@ CBioseqContext::CBioseqContext m_IsCrossKingdom(false), m_fUnverified(fUnverified_None), m_ShowAnnotCommentAsCOMMENT(false), + m_ShowAnnotCommentAsCOMMENT_checked(false), m_FFCtx(ffctx), m_Master(mctx), m_TLSeqEntryCtx(tlsec) @@ -246,7 +248,8 @@ void CBioseqContext::x_Init(const CBioseq_Handle& seq, const CSeq_loc* user_loc) x_SetDataFromUserObjects(); - x_SetDataFromAnnot(); + m_ShowAnnotCommentAsCOMMENT = false; + m_ShowAnnotCommentAsCOMMENT_checked = false; m_HasOperon = x_HasOperon(); @@ -326,8 +329,7 @@ void CBioseqContext::x_SetHasMultiIntervalGenes(void) { m_HasMultiIntervalGenes = false; - SAnnotSelector sel; - sel.SetFeatType( CSeqFeatData::e_Gene ); + SAnnotSelector sel(CSeqFeatData::e_Gene); CFeat_CI gene_ci( m_Handle, sel ); for( ; gene_ci ; ++gene_ci ) { @@ -606,15 +608,26 @@ void CBioseqContext::x_SetDataFromUserObjects(void) } } -void CBioseqContext::x_SetDataFromAnnot(void) +bool CBioseqContext::ShowAnnotCommentAsCOMMENT() const { - if( GetRepr() == CSeq_inst::eRepr_map ) { + if (!m_ShowAnnotCommentAsCOMMENT_checked) + { + x_CheckForShowComments(); + } + return m_ShowAnnotCommentAsCOMMENT; +} + +void CBioseqContext::x_CheckForShowComments() const +{ + m_ShowAnnotCommentAsCOMMENT_checked = true; + + if (GetRepr() == CSeq_inst::eRepr_map) { // TODO: is this right? Maybe handle it differently once // CAnnot_CI is able to handle CSeq_inst::eRepr_map. return; } - CAnnot_CI annot_ci(m_Handle); + CAnnot_CI annot_ci(m_Handle, SAnnotSelector(CSeq_annot::TData::e_Ftable)); for( ; annot_ci; ++annot_ci ) { if( ! annot_ci->Seq_annot_IsSetDesc() ) { continue; @@ -1173,6 +1186,7 @@ CTopLevelSeqEntryContext::CTopLevelSeqEntryContext( const CSeq_entry_Handle &ent case CSeq_id_Base::e_Tpg: // Genbank allows merging only if it's the old-style 1 + 5 accessions if( NULL != seqId->GetTextseq_Id() && + seqId->GetTextseq_Id()->IsSetAccession() && seqId->GetTextseq_Id()->GetAccession().length() == 6 ) { m_CanSourcePubsBeFused = true; } diff --git a/c++/src/objtools/format/dbsource_item.cpp b/c++/src/objtools/format/dbsource_item.cpp index f908a191..7e8cac10 100644 --- a/c++/src/objtools/format/dbsource_item.cpp +++ b/c++/src/objtools/format/dbsource_item.cpp @@ -1,4 +1,4 @@ -/* $Id: dbsource_item.cpp 506085 2016-07-01 14:25:26Z gotvyans $ +/* $Id: dbsource_item.cpp 545754 2017-09-11 11:57:08Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -541,7 +541,9 @@ void CDBSourceItem::x_AddPDBBlock(CBioseqContext& ctx) string CDBSourceItem::x_FormatDBSourceID(const CSeq_id_Handle& idh) { +#ifndef NEW_HTML_FMT const bool is_html = ( GetContext()->Config().DoHTML() ); +#endif CConstRef id; if (idh) { @@ -588,7 +590,7 @@ string CDBSourceItem::x_FormatDBSourceID(const CSeq_id_Handle& idh) if (tsid == NULL) { return kEmptyStr; } - string s, sep, comma; + string s, sep, comma, ht; switch (choice) { case CSeq_id::e_Embl: s = "embl "; comma = ","; break; case CSeq_id::e_Other: s = "REFSEQ: "; break; @@ -610,8 +612,8 @@ string CDBSourceItem::x_FormatDBSourceID(const CSeq_id_Handle& idh) acc += '.' + NStr::IntToString(tsid->GetVersion()); } #ifdef NEW_HTML_FMT - s += comma + sep + "accession "; - GetContext()->Config().GetHTMLFormatter().FormatNucId(s, *idh.GetSeqId(), GetContext()->GetScope().GetGi(idh), acc); + GetContext()->Config().GetHTMLFormatter().FormatNucId(ht, *idh.GetSeqId(), GetContext()->GetScope().GetGi(idh), acc); + s += comma + sep + "accession " + ht; #else if (is_html) { const TIntId gi = GetContext()->GetScope().GetGi(idh); diff --git a/c++/src/objtools/format/feature_item.cpp b/c++/src/objtools/format/feature_item.cpp index 2d9b93a8..d1850b7f 100644 --- a/c++/src/objtools/format/feature_item.cpp +++ b/c++/src/objtools/format/feature_item.cpp @@ -1,4 +1,4 @@ -/* $Id: feature_item.cpp 514605 2016-09-22 18:44:07Z ivanov $ +/* $Id: feature_item.cpp 542867 2017-08-03 17:11:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -871,7 +871,7 @@ static void s_SplitCommaSeparatedStringInParens( vector &output_vec, con amount_to_chop_off_end = 1; } - NStr::Tokenize( string_to_split.substr( 1, string_to_split.length() - amount_to_chop_off_end - 1), ",", output_vec ); + NStr::Split( string_to_split.substr( 1, string_to_split.length() - amount_to_chop_off_end - 1), ",", output_vec, 0 ); } static const char* const sc_ValidPseudoGene[] = { @@ -968,6 +968,13 @@ CFeatureItemBase::CFeatureItemBase { if (m_Feat) { x_SetObject(m_Feat.GetOriginalFeature()); + + CSeq_feat_Handle feat = m_Feat.GetSeq_feat_Handle(); + const CSeq_annot_Handle& ah = feat.GetAnnot(); + CSeq_entry_Handle seh = ah.GetParentEntry(); + if (! seh) { + x_SetExternal(); + } } } @@ -998,7 +1005,7 @@ string CFeatureItem::GetKey(void) const subtype == CSeqFeatData::eSubtype_mat_peptide_aa || subtype == CSeqFeatData::eSubtype_sig_peptide_aa || subtype == CSeqFeatData::eSubtype_transit_peptide_aa || - subtype == CSeqFeatData::eSubtype_propeptide ) { + subtype == CSeqFeatData::eSubtype_propeptide_aa ) { return "Precursor"; } } @@ -1390,7 +1397,7 @@ void CFeatureItem::x_AddQualExceptions( const bool bIsRelaxed = ( ! cfg.DropIllegalQuals() ); list exceptions; - NStr::Split( raw_exception, ",", exceptions ); + NStr::Split( raw_exception, ",", exceptions, NStr::fSplit_Tokenize ); list output_exceptions; list output_notes; @@ -1599,9 +1606,7 @@ void CFeatureItem::x_AddQuals( x_AddFTableQuals( ctx ); return; } - - m_Feat_Tree->AddGenesForFeat (m_Feat); - + m_Feat_Tree->AddGenesForFeat(m_Feat); // // Collect/Compute data that will be shared between several qualifier @@ -1661,19 +1666,38 @@ void CFeatureItem::x_AddQuals( if (feat_gene_xref && ! suppressed && ! CGeneFinder::ResolveGeneXref(feat_gene_xref, ctx.GetTopLevelEntry())) { gene_ref = feat_gene_xref; - } else if (! feat_gene_xref || ! suppressed) { - CMappedFeat mapped_gene = GetBestGeneForFeat (m_Feat, m_Feat_Tree); - if (mapped_gene && subtype != CSeqFeatData::eSubtype_primer_bind) { - gene_feat = &mapped_gene.GetOriginalFeature(); - gene_ref = &gene_feat->GetData().GetGene(); - } else { - // e.g., check sig_peptide for gene overlapping parent CDS - CSeq_feat_Handle parent_feat_handle; - if( parentFeatureItem ) { - parent_feat_handle = parentFeatureItem->GetFeat(); + } else if ((! feat_gene_xref || ! suppressed) && + subtype != CSeqFeatData::eSubtype_primer_bind) { + + bool is_mapped = false; + try { + CMappedFeat mapped_gene = ctx.GetFeatTree().GetBestGene(m_Feat); + if (mapped_gene) { + gene_feat = mapped_gene.GetOriginalSeq_feat(); + gene_ref = &gene_feat->GetData().GetGene(); + is_mapped = true; } - CGeneFinder::GetAssociatedGeneInfo( m_Feat, ctx, m_Loc, m_GeneRef, gene_ref, - gene_feat, parent_feat_handle ); + } catch (CException&) {} + if (! is_mapped) { + try { + CMappedFeat mapped_gene = m_Feat_Tree->GetBestGene(m_Feat); + if (mapped_gene) { + gene_feat = mapped_gene.GetOriginalSeq_feat(); + gene_ref = &gene_feat->GetData().GetGene(); + is_mapped = true; + } + } catch (CException&) {} + } + if (! is_mapped) { + try { + // e.g., check sig_peptide for gene overlapping parent CDS + CSeq_feat_Handle parent_feat_handle; + if( parentFeatureItem ) { + parent_feat_handle = parentFeatureItem->GetFeat(); + CGeneFinder::GetAssociatedGeneInfo( m_Feat, ctx, m_Loc, m_GeneRef, gene_ref, + gene_feat, parent_feat_handle ); + } + } catch (CException&) {} } } } @@ -1733,7 +1757,6 @@ void CFeatureItem::x_AddQuals( x_AddQualsGene( gene_ref, gene_feat, gene_ref ? false : gene_feat.NotEmpty() ); x_AddQualPseudo( ctx, type, subtype, pseudo ); - x_AddQualSeqfeatNote(ctx); x_AddQualsGb( ctx ); // dynamic mapping of old features to regulatory with regulatory_class qualifier @@ -1741,6 +1764,8 @@ void CFeatureItem::x_AddQuals( x_AddQualsRegulatoryClass ( ctx, subtype ); } + x_AddQualSeqfeatNote(ctx); + // cleanup (drop illegal quals, duplicate information etc.) x_CleanQuals( gene_ref ); } @@ -1849,7 +1874,11 @@ void CFeatureItem::x_AddQualsRna( CRef acc_id(new CSeq_id(acc)); x_AddQual(slot, new CFlatSeqIdQVal(*acc_id)); } - x_AddQual(eFQ_db_xref, new CFlatSeqIdQVal(*sip, true)); + /* + if (! cfg.HideGI()) { + x_AddQual(eFQ_db_xref, new CFlatSeqIdQVal(*sip, true)); + } + */ } } } @@ -1864,7 +1893,7 @@ void CFeatureItem::x_AddQualsRna( switch ( rna_type ) { case CRNA_ref::eType_tRNA: { - if ( !pseudo && cfg.ShowTranscript() ) { + if ( !pseudo && ( cfg.ShowTranscript() || cfg.IsFormatGBSeq() ) ) { CSeqVector vec(feat.GetLocation(), scope); vec.SetCoding(CBioseq_Handle::eCoding_Iupac); string transcription; @@ -1937,7 +1966,7 @@ void CFeatureItem::x_AddQualsRna( } case CRNA_ref::eType_mRNA: { - if ( !pseudo && cfg.ShowTranscript() ) { + if ( !pseudo && ( cfg.ShowTranscript() || cfg.IsFormatGBSeq() ) ) { CSeqVector vec(feat.GetLocation(), scope); vec.SetCoding(CBioseq_Handle::eCoding_Iupac); string transcription; @@ -3169,11 +3198,9 @@ void CFeatureItem::x_AddQualsProt( } } if ( pref.IsSetActivity() && !pref.GetActivity().empty() ) { - if ( ctx.IsNuc() || processed != CProt_ref::eProcessed_mature ) { - ITERATE (CProt_ref::TActivity, it, pref.GetActivity()) { - if (!NStr::IsBlank(*it)) { - x_AddQual(eFQ_prot_activity, new CFlatStringQVal(*it)); - } + ITERATE (CProt_ref::TActivity, it, pref.GetActivity()) { + if (!NStr::IsBlank(*it)) { + x_AddQual(eFQ_prot_activity, new CFlatStringQVal(*it)); } } } @@ -3202,7 +3229,7 @@ void CFeatureItem::x_AddQualsProt( } else { // protein feature on subpeptide bioseq x_AddQual(eFQ_derived_from, new CFlatSeqLocQVal(m_Feat.GetLocation())); } - if ( !pseudo && ctx.Config().ShowPeptides() ) { + if ( !pseudo && ( ctx.Config().ShowPeptides() || ctx.Config().IsFormatGBSeq() ) ) { if ( processed == CProt_ref::eProcessed_mature || processed == CProt_ref::eProcessed_signal_peptide || processed == CProt_ref::eProcessed_transit_peptide || @@ -3228,6 +3255,7 @@ void CFeatureItem::x_AddQualsProt( { double wt = 0; bool has_mat_peptide = false; + bool has_propeptide = false; bool has_signal_peptide = false; CConstRef loc(&m_Feat.GetLocation()); @@ -3262,6 +3290,10 @@ void CFeatureItem::x_AddQualsProt( has_mat_peptide = true; break; + case CProt_ref::eProcessed_propeptide: + has_propeptide = true; + break; + default: break; } @@ -3302,7 +3334,7 @@ void CFeatureItem::x_AddQualsProt( break; } - if ( (!has_mat_peptide || !has_signal_peptide) || (proteinIsAtLeastMature) || (!is_pept_whole_loc) ) { + if ( (!has_mat_peptide || !has_signal_peptide || !has_propeptide) || (proteinIsAtLeastMature) || (!is_pept_whole_loc) ) { try { const TGetProteinWeight flags = 0; wt = GetProteinWeight(m_Feat.GetOriginalFeature(), @@ -3352,7 +3384,7 @@ static void s_ParseParentQual(const CGb_qual& gbqual, list& vals) if (val.length() > 1 && NStr::StartsWith(val, '(') && NStr::EndsWith(val, ')') && val.find(',') != NPOS) { - NStr::Split(val, "(,)", vals); + NStr::Split(val, "(,)", vals, NStr::fSplit_Tokenize); } else { vals.push_back(val); } @@ -3742,6 +3774,10 @@ void CFeatureItem::x_ImportQuals( x_AddRegulatoryClassQual(val, check_qual_syntax); break; + case eFQ_recombination_class: + x_AddRecombinationClassQual(val, check_qual_syntax); + break; + default: x_AddQual(slot, new CFlatStringQVal(val)); break; @@ -3784,7 +3820,7 @@ void CFeatureItem::x_AddRptUnitQual( if (NStr::StartsWith(rpt_unit, '(') && NStr::EndsWith(rpt_unit, ')') && NStr::Find(rpt_unit, "(", 1) == NPOS) { string tmp = rpt_unit.substr(1, rpt_unit.length() - 2); - NStr::Tokenize(tmp, ",", units); + NStr::Split(tmp, ",", units, 0); } else { units.push_back(rpt_unit); } @@ -3834,9 +3870,47 @@ static bool s_IsValidRegulatoryClass(const string& type) return false; } +static bool s_IsValidRecombinationClass(const string& type) +{ + vector valid_types = CSeqFeatData::GetRecombinationClassList(); + + FOR_EACH_STRING_IN_VECTOR (itr, valid_types) { + string str = *itr; + if (NStr::Equal (str, type)) return true; + } + + return false; +} + +// ---------------------------------------------------------------------------- +void CFeatureItem::x_AddRecombinationClassQual( + const string& recombination_class, + bool check_qual_syntax +) +// ---------------------------------------------------------------------------- +{ + if (recombination_class.empty()) { + return; + } + + string recomb_class = recombination_class; + + if (NStr::StartsWith(recomb_class, "other:")) { + NStr::TrimPrefixInPlace(recomb_class, "other:"); + NStr::TruncateSpacesInPlace(recomb_class); + } + if ( s_IsValidRecombinationClass( recomb_class ) ) { + x_AddQual( eFQ_recombination_class, new CFlatStringQVal(recomb_class)); + } else { + x_AddQual( eFQ_recombination_class, new CFlatStringQVal("other")); + x_AddQual( eFQ_seqfeat_note, new CFlatStringQVal(recomb_class)); + } +} + + // ---------------------------------------------------------------------------- void CFeatureItem::x_AddRegulatoryClassQual( - const string& regulatory_class, + const string& regulatory_class, bool check_qual_syntax ) // ---------------------------------------------------------------------------- @@ -3844,22 +3918,21 @@ void CFeatureItem::x_AddRegulatoryClassQual( if (regulatory_class.empty()) { return; } - - if ( ! check_qual_syntax || s_IsValidRegulatoryClass( regulatory_class ) ) { - x_AddQual( eFQ_regulatory_class, new CFlatStringQVal(regulatory_class)); + + string reg_class = regulatory_class; + + if (NStr::StartsWith(reg_class, "other:")) { + NStr::TrimPrefixInPlace(reg_class, "other:"); + NStr::TruncateSpacesInPlace(reg_class); + } + if ( s_IsValidRegulatoryClass( reg_class ) ) { + x_AddQual( eFQ_regulatory_class, new CFlatStringQVal(reg_class)); + } else if (NStr::CompareNocase(reg_class, "other") == 0 && + m_Feat.IsSetComment() && !m_Feat.GetComment().empty()) { + x_AddQual( eFQ_regulatory_class, new CFlatStringQVal("other")); } else { x_AddQual( eFQ_regulatory_class, new CFlatStringQVal("other")); - string tmp = regulatory_class; - /* - if (NStr::StartsWith(tmp, "other:")) { - NStr::TrimPrefixInPlace(tmp, "other:"); - NStr::TruncateSpacesInPlace(tmp); - } - */ - if (NStr::StartsWith(tmp, "other")) { - return; - } - x_AddQual( eFQ_seqfeat_note, new CFlatStringQVal(tmp)); + x_AddQual( eFQ_seqfeat_note, new CFlatStringQVal(reg_class)); } } @@ -4730,8 +4803,14 @@ void CFeatureItem::x_AddFTableQuals( x_AddFTableQual("pseudo"); } const CGene_ref* grp = m_Feat.GetGeneXref(); - if ( grp != 0 && grp->IsSuppressed() ) { - x_AddFTableQual("gene", "-"); + if ( grp != 0 ) { + string gene_label; + if (grp->IsSuppressed()) { + gene_label = "-"; + } else { + grp->GetLabel(&gene_label); + } + x_AddFTableQual("gene", gene_label); } if ( m_Feat.IsSetComment() && !m_Feat.GetComment().empty() ) { x_AddFTableQual("note", m_Feat.GetComment()); @@ -4908,29 +4987,115 @@ void CFeatureItem::x_AddFTableRnaQuals( feature::fFGL_Content, &ctx.GetScope()); x_AddFTableQual("product", label); } + else if ( ext.IsGen() ) { + const CRNA_gen& gen = ext.GetGen(); + if ( gen.IsSetClass() ) { + if ( gen.IsLegalClass()) { + x_AddFTableQual("ncRNA_class", gen.GetClass()); + } + else { + x_AddFTableQual("ncRNA_class", "other"); + x_AddFTableQual("note", gen.GetClass()); + } + } + + if ( gen.IsSetProduct() ) { + x_AddFTableQual("product", gen.GetProduct()); + } + } } - if ( feat.IsSetProduct() ) { + if ( feat.IsSetProduct() && !cfg.HideProteinID()) { CBioseq_Handle prod = ctx.GetScope().GetBioseqHandle(m_Feat.GetProductId()); if ( prod ) { - CConstRef id = GetId(prod, eGetId_Best).GetSeqId(); - string id_str; - if ( id->IsGenbank() || id->IsEmbl() || id->IsDdbj() || - id->IsTpg() || id->IsTpd() || id->IsTpe() || - id->IsOther() || - (id->IsLocal() && !ctx.Config().SuppressLocalId()) ) { - id_str = id->GetSeqIdString(true); - } else if ( id->IsGeneral() ) { - id_str = id->AsFastaString(); - } - if (! cfg.HideProteinID()) { + string id_str = x_SeqIdWriteForTable(*(prod.GetBioseqCore()), ctx.Config().SuppressLocalId(), !ctx.Config().HideGI()); + if (!NStr::IsBlank(id_str)) { x_AddFTableQual("transcript_id", id_str); } } } } + +// originally SeqIdWriteForTable in the C Toolkit +// specific Seq-ids are included in the value, in a specific order +string CFeatureItem::x_SeqIdWriteForTable(const CBioseq& seq, bool suppress_local, bool giOK) + +{ + if (!seq.IsSetId()) { + return kEmptyStr; + } + const CSeq_id* accn = NULL; + const CSeq_id* local = NULL; + const CSeq_id* patent = NULL; + const CSeq_id* pdb = NULL; + const CSeq_id* general = NULL; + const CSeq_id* gi = NULL; + + ITERATE(CBioseq::TId, it, seq.GetId()) { + switch ((*it)->Which()) { + case CSeq_id::e_Local: + local = it->GetPointer(); + break; + case CSeq_id::e_Genbank: + case CSeq_id::e_Embl: + case CSeq_id::e_Pir: + case CSeq_id::e_Swissprot: + case CSeq_id::e_Ddbj: + case CSeq_id::e_Prf: + case CSeq_id::e_Tpg: + case CSeq_id::e_Tpe: + case CSeq_id::e_Tpd: + case CSeq_id::e_Other: + case CSeq_id::e_Gpipe: + accn = it->GetPointer(); + break; + case CSeq_id::e_Patent: + patent = it->GetPointer(); + break; + case CSeq_id::e_General: + if (!(*it)->GetGeneral().IsSkippable()) { + general = it->GetPointer(); + } + break; + case CSeq_id::e_Pdb: + pdb = it->GetPointer(); + break; + case CSeq_id::e_Gi: + gi = it->GetPointer(); + break; + default: + break; + } + } + + + string label = kEmptyStr; + + if (accn != NULL) { + label = accn->AsFastaString(); + } + + if (general != NULL) { + if (!label.empty()) { + label += "|"; + } + label += general->AsFastaString(); + } + + if (local != NULL && (!suppress_local) && label.empty()) { + label = local->AsFastaString(); + } + + if (gi != NULL && giOK && label.empty()) { + label = gi->AsFastaString(); + } + + return label; +} + + // ---------------------------------------------------------------------------- void CFeatureItem::x_AddFTableCdregionQuals( const CMappedFeat& feat, @@ -4942,6 +5107,12 @@ void CFeatureItem::x_AddFTableCdregionQuals( if ( feat.IsSetProduct() ) { prod = ctx.GetScope().GetBioseqHandle(feat.GetProductId()); } + + const CProt_ref* prot_xref = feat.GetProtXref(); + if (prot_xref) { + x_AddFTableProtQuals(*prot_xref); + } + else if ( prod ) { CMappedFeat prot_ref = s_GetBestProtFeature(prod); if ( prot_ref ) { @@ -4971,30 +5142,17 @@ void CFeatureItem::x_AddFTableCdregionQuals( } x_AddFTableQual("transl_except", "(pos:" + pos + ",aa:" + aa + ")"); } - CConstRef id; - string id_str; - if ( prod ) { - id = GetId(prod, eGetId_Best).GetSeqId(); - } else if ( feat.IsSetProduct() ) { - try { - id.Reset(&GetId(feat.GetProduct(), &ctx.GetScope())); - if ( id->IsGi() ) { - // get "normal" id - } - } catch (CObjmgrUtilException&) { - id.Reset(); - } - } - if ( id ) { - if ( id->IsGenbank() || id->IsEmbl() || id->IsDdbj() || - id->IsTpg() || id->IsTpd() || id->IsTpe() || - id->IsOther() || - (id->IsLocal() && !ctx.Config().SuppressLocalId()) ) { - id_str = id->GetSeqIdString(true); - } else if ( id->IsGi() || id->IsGeneral() ) { - id_str = id->AsFastaString(); - } - if (! cfg.HideProteinID() && !NStr::IsBlank(id_str)) { + + if (cdr.IsSetCode()) { + int gcode = cdr.GetCode().GetId(); + if (gcode > 1 && gcode != 255) { + x_AddFTableQual("transl_table", NStr::NumericToString(gcode)); + } + } + + if (prod && !cfg.HideProteinID()) { + string id_str = x_SeqIdWriteForTable(*(prod.GetBioseqCore()), ctx.Config().SuppressLocalId(), !ctx.Config().HideGI()); + if (!NStr::IsBlank(id_str)) { x_AddFTableQual("protein_id", id_str); } } @@ -5008,28 +5166,36 @@ void CFeatureItem::x_AddFTableProtQuals( if ( !prot.GetData().IsProt() ) { return; } - const CProt_ref& pref = prot.GetData().GetProt(); - ITERATE (CProt_ref::TName, it, pref.GetName()) { + x_AddFTableProtQuals(prot.GetData().GetProt()); + + if ( prot.IsSetComment() && !prot.GetComment().empty() ) { + x_AddFTableQual("prot_note", prot.GetComment()); + } +} + +// ---------------------------------------------------------------------------- +void CFeatureItem::x_AddFTableProtQuals( + const CProt_ref& prot_ref) +// ---------------------------------------------------------------------------- +{ + ITERATE (CProt_ref::TName, it, prot_ref.GetName()) { if ( !it->empty() ) { x_AddFTableQual("product", *it); } } - if ( pref.IsSetDesc() && !pref.GetDesc().empty() ) { - x_AddFTableQual("prot_desc", pref.GetDesc()); + if ( prot_ref.IsSetDesc() && !prot_ref.GetDesc().empty() ) { + x_AddFTableQual("prot_desc", prot_ref.GetDesc()); } - ITERATE (CProt_ref::TActivity, it, pref.GetActivity()) { + ITERATE (CProt_ref::TActivity, it, prot_ref.GetActivity()) { if ( !it->empty() ) { x_AddFTableQual("function", *it); } } - ITERATE (CProt_ref::TEc, it, pref.GetEc()) { + ITERATE (CProt_ref::TEc, it, prot_ref.GetEc()) { if ( !it->empty() ) { x_AddFTableQual("EC_number", *it); } } - if ( prot.IsSetComment() && !prot.GetComment().empty() ) { - x_AddFTableQual("prot_note", prot.GetComment()); - } } // ---------------------------------------------------------------------------- @@ -5294,7 +5460,7 @@ static string s_GetSpecimenVoucherText( string id; { string coll; - if( ! COrgMod::ParseStructuredVoucher(strRawName, inst, coll, id) ) { + if( ! COrgMod::ParseStructuredVoucher(strRawName, inst, coll, id) || NStr::IsBlank(inst)) { return strRawName; } if( ! coll.empty() ) { @@ -5391,12 +5557,19 @@ void CSourceFeatureItem::x_AddQuals(const COrg_ref& org, CBioseqContext& ctx) co case eSQ_none: break; default: - if( COrgMod::HoldsInstitutionCode(mod.GetSubtype()) ) { - CRef new_mod( new COrgMod(mod.GetSubtype(), - ( sSubname.empty() ? kEmptyStr : s_GetSpecimenVoucherText(ctx, sSubname) ) )); - x_AddQual(slot, new CFlatOrgModQVal(*new_mod)); - } else { - x_AddQual(slot, new CFlatOrgModQVal(**it)); + { + const COrgMod::TSubtype stype = mod.GetSubtype(); + if( COrgMod::HoldsInstitutionCode(stype) ) { + CRef new_mod( new COrgMod(stype, + ( sSubname.empty() ? kEmptyStr : s_GetSpecimenVoucherText(ctx, sSubname) ) )); + x_AddQual(slot, new CFlatOrgModQVal(*new_mod)); + } else if (stype == COrgMod::eSubtype_type_material && (! COrgMod::IsINSDCValidTypeMaterial(sSubname))) { + CRef new_mod( new COrgMod(COrgMod::eSubtype_other, + ( sSubname.empty() ? kEmptyStr : "type_material: " + sSubname ) )); + x_AddQual(eSQ_orgmod_note, new CFlatOrgModQVal(*new_mod)); + } else { + x_AddQual(slot, new CFlatOrgModQVal(**it)); + } } break; } @@ -5875,132 +6048,6 @@ void CSourceFeatureItem::SetLoc(const CSeq_loc& loc) } -// ---------------------------------------------------------------------------- -void CFeatureItemGff::x_AddQualsRna( - const CMappedFeat& feat, - CBioseqContext& ctx, - bool pseudo ) -// ---------------------------------------------------------------------------- -{ - CSeqFeatData::ESubtype subtype = m_Feat.GetData().GetSubtype(); - const CRNA_ref& rna = feat.GetData().GetRna(); - const CFlatFileConfig& cfg = ctx.Config(); - CScope& scope = ctx.GetScope(); - - CRNA_ref::TType rna_type = rna.IsSetType() ? - rna.GetType() : CRNA_ref::eType_unknown; - switch ( rna_type ) { - case CRNA_ref::eType_tRNA: - { - if ( !pseudo && cfg.ShowTranscript() ) { - CSeqVector vec(feat.GetLocation(), scope); - vec.SetCoding(CBioseq_Handle::eCoding_Iupac); - string transcription; - vec.GetSeqData(0, vec.size(), transcription); - x_AddQual(eFQ_transcription, new CFlatStringQVal(transcription)); - } - if (rna.IsSetExt()) { - const CRNA_ref::C_Ext& ext = rna.GetExt(); - switch (ext.Which()) { - case CRNA_ref::C_Ext::e_Name: - { - // amino acid could not be parsed into structured form - if (!cfg.DropIllegalQuals()) { - x_AddQual(eFQ_product, - new CFlatStringQVal(ext.GetName())); - } else { - x_AddQual(eFQ_product, - new CFlatStringQVal("tRNA-OTHER")); - } - break; - } - case CRNA_ref::C_Ext::e_TRNA: - { - const CTrna_ext& trna = ext.GetTRNA(); - int aa = 0; - if ( trna.IsSetAa() && trna.GetAa().IsNcbieaa() ) { - aa = trna.GetAa().GetNcbieaa(); - } else { - // !!! - return; - } -/* if (aa == 'U') { - if ( ctx.Config().SelenocysteineToNote() ) { - x_AddQual(eFQ_selenocysteine_note, - new CFlatStringQVal("selenocysteine")); - } else { - x_AddQual(eFQ_selenocysteine, new CFlatBoolQVal(true)); - } - } -*/ if ( cfg.IupacaaOnly() ) { - aa = s_ToIupacaa(aa); - } - const string& aa_str = s_AaName(aa); - if ( !aa_str.empty() ) { - x_AddQual(eFQ_product, new CFlatStringQVal(aa_str)); - if ( trna.IsSetAnticodon() && !aa_str.empty() ) { - x_AddQual(eFQ_anticodon, - new CFlatAnticodonQVal(trna.GetAnticodon(), - aa_str.substr(5, NPOS))); - } - } - if ( trna.IsSetCodon() ) { - const string& comment = - m_Feat.IsSetComment() ? m_Feat.GetComment() : kEmptyStr; - x_AddQual(eFQ_trna_codons, new CFlatTrnaCodonsQVal(trna, comment)); - } - break; - } - default: - break; - } // end of internal switch - } - break; - } - case CRNA_ref::eType_mRNA: - { - if ( !pseudo && cfg.ShowTranscript() ) { - CSeqVector vec(feat.GetLocation(), scope); - vec.SetCoding(CBioseq_Handle::eCoding_Iupac); - string transcription; - vec.GetSeqData(0, vec.size(), transcription); - x_AddQual(eFQ_transcription, new CFlatStringQVal(transcription)); - } - // intentional fall through - } - default: - switch ( subtype ) { - - case CSeqFeatData::eSubtype_ncRNA: - case CSeqFeatData::eSubtype_tmRNA: - break; - case CSeqFeatData::eSubtype_misc_RNA: - case CSeqFeatData::eSubtype_otherRNA: - if ( rna.IsSetExt() && rna.GetExt().IsName() ) { - string strName = rna.GetExt().GetName(); - if ( strName != "misc_RNA" ) { - x_AddQual( eFQ_product, new CFlatStringQVal( strName ) ); - } - } - break; - default: - if ( rna.IsSetExt() && rna.GetExt().IsName() ) { - x_AddQual( eFQ_product, new CFlatStringQVal( rna.GetExt().GetName() ) ); - } - break; - } - } // end of switch - - try { - if (feat.IsSetProduct()) { - CConstRef sip(feat.GetProduct().GetId()); - if (sip && sip->IsGi() ) { - x_AddQual(eFQ_db_xref, new CFlatSeqIdQVal(*sip, true)); - } - } - } catch (CObjmgrUtilException&) {} -} - // ---------------------------------------------------------------------------- bool CFeatureItem::x_GetGbValue( const string& key, diff --git a/c++/src/objtools/format/flat_file_config.cpp b/c++/src/objtools/format/flat_file_config.cpp index e39cda66..5fea0628 100644 --- a/c++/src/objtools/format/flat_file_config.cpp +++ b/c++/src/objtools/format/flat_file_config.cpp @@ -1,4 +1,4 @@ -/* $Id: flat_file_config.cpp 507550 2016-07-19 22:30:02Z kans $ +/* $Id: flat_file_config.cpp 544802 2017-08-28 14:35:41Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -308,20 +308,45 @@ CFlatFileConfig::CFlatFileConfig( CGenbankBlockCallback* pGenbankBlockCallback, const ICanceled * pCanceledCallback, bool basicCleanup, TCustom custom ) : - m_Format(format), m_Mode(mode), m_Style(style), m_View(view), - m_Flags(flags), m_RefSeqConventions(false), m_GffOptions(gff_options), + m_Format(format), m_Mode(mode), m_Style(style), + m_Flags(flags), m_View(view), + m_RefSeqConventions(false), m_GffOptions(gff_options), m_fGenbankBlocks(genbank_blocks), m_GenbankBlockCallback(pGenbankBlockCallback), m_pCanceledCallback(pCanceledCallback), m_BasicCleanup(basicCleanup), m_Custom(custom) { - // GFF/GFF3 and FTable always require master style - if (m_Format == eFormat_GFF || m_Format == eFormat_GFF3 || - m_Format == eFormat_FTable) { + // FTable always requires master style + if (m_Format == eFormat_FTable) { m_Style = eStyle_Master; } + m_html_formatter.Reset(new CHTMLEmptyFormatter); } + +CFlatFileConfig::CFlatFileConfig( + TFormat format, + TMode mode, + TStyle style, + TFlags flags, + TView view) : + m_Format(format), m_Mode(mode), m_Style(style), m_Flags(flags), m_View(view) +{ + m_RefSeqConventions = false; + SetGenbankBlocks(fGenbankBlocks_All); + SetGenbankBlockCallback(NULL); + SetCanceledCallback(NULL); + BasicCleanup(false); + SetCustom(0); + + // FTable always requires master style + if (m_Format == eFormat_FTable) { + m_Style = eStyle_Master; + } + m_html_formatter.Reset(new CHTMLEmptyFormatter); +} + + // -- destructor CFlatFileConfig::~CFlatFileConfig(void) { @@ -560,7 +585,8 @@ void CFlatFileConfig::AddArgumentDescriptions(CArgDescriptions& args) arg_desc->AddDefaultKey("custom", "Custom", "Custom flat file output bits. The value is the bitwise OR (logical addition) of:\n" " 1 - hide protein_id and transcript_id\n" - " 2 - hide GI number", + " 2 - hide GI number\n" + " 4 - allow long locus lines", CArgDescriptions::eInteger, "0"); @@ -838,7 +864,7 @@ CFlatFileConfig::TGenbankBlocks x_GetGenbankBlocks(const CArgs& args) // turn the blocks into one mask CFlatFileConfig::TGenbankBlocks fBlocksGiven = 0; vector vecOfBlockNames; - NStr::Tokenize(blocks_arg, ",", vecOfBlockNames); + NStr::Split(blocks_arg, ",", vecOfBlockNames, NStr::fSplit_NoMergeDelims); ITERATE(vector, name_iter, vecOfBlockNames) { // Note that StringToGenbankBlock throws an // exception if it gets an illegal value. @@ -859,7 +885,6 @@ void CFlatFileConfig::FromArguments(const CArgs& args) CFlatFileConfig::EStyle style = x_GetStyle(args); CFlatFileConfig::EFlags flags = x_GetFlags(args); CFlatFileConfig::EView view = x_GetView(args); - CFlatFileConfig::EGffOptions gff_options = CFlatFileConfig::fGffGTFCompat; CFlatFileConfig::TGenbankBlocks genbank_blocks = x_GetGenbankBlocks(args); CFlatFileConfig::ECustom custom = x_GetCustom(args); @@ -868,7 +893,6 @@ void CFlatFileConfig::FromArguments(const CArgs& args) SetStyle(style); SetFlags(flags); SetView(view); - m_GffOptions = gff_options; m_fGenbankBlocks = genbank_blocks; m_BasicCleanup = args["cleanup"]; SetCustom(custom); diff --git a/c++/src/objtools/format/flat_file_generator.cpp b/c++/src/objtools/format/flat_file_generator.cpp index c758d2cd..e581e742 100644 --- a/c++/src/objtools/format/flat_file_generator.cpp +++ b/c++/src/objtools/format/flat_file_generator.cpp @@ -1,4 +1,4 @@ -/* $Id: flat_file_generator.cpp 511755 2016-08-24 13:57:06Z ivanov $ +/* $Id: flat_file_generator.cpp 532240 2017-04-03 15:25:21Z foleyjp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -84,11 +84,12 @@ CFlatFileGenerator::CFlatFileGenerator CFlatFileConfig::TFlags flags, CFlatFileConfig::TView view, CFlatFileConfig::TCustom custom) : - m_Ctx(new CFlatFileContext(CFlatFileConfig(format, mode, style, flags, view, custom))) + m_Ctx(new CFlatFileContext(CFlatFileConfig(format, mode, style, flags, view))) { if ( !m_Ctx ) { NCBI_THROW(CFlatException, eInternal, "Unable to initialize context"); } + m_Ctx->SetConfig().SetCustom(custom); } @@ -111,6 +112,72 @@ void CFlatFileGenerator::SetFeatTree(feature::CFeatTree* tree) m_Ctx->SetFeatTree(tree); } + + + /* + template + void VisitAllBioseqs(objects::CSeq_entry& entry, _Pred m) + { + if (entry.IsSeq()) + { + m(entry.SetSeq()); + } + else + if (entry.IsSet()) + { + NON_CONST_ITERATE(CSeq_entry::TSet::TSeq_set, it_se, entry.SetSet().SetSeq_set()) + { + VisitAllBioseqs(**it_se, m); + } + } + } + // also const visitor + template + void VisitAllBioseqs(const objects::CSeq_entry& entry, _Pred m) + { + if (entry.IsSeq()) + { + m(entry.GetSeq()); + } + else + if (entry.IsSet()) + { + ITERATE(CSeq_entry::TSet::TSeq_set, it_se, entry.GetSet().GetSeq_set()) + { + VisitAllBioseqs(**it_se, m); + } + } + } + + template + void VisitAllSeqSets(objects::CSeq_entry& entry, _Pred m) + { + if (entry.IsSet()) + { + m(entry.SetSet()); + NON_CONST_ITERATE(CSeq_entry::TSet::TSeq_set, it_se, entry.SetSet().SetSeq_set()) + { + VisitAllSeqSets(**it_se, m); + } + } + } + */ + // also const visitor + template + void VisitAllSeqSets(const objects::CSeq_entry& entry, _Pred m) + { + if (entry.IsSet()) + { + m(entry.GetSet()); + ITERATE(CSeq_entry::TSet::TSeq_set, it_se, entry.GetSet().GetSeq_set()) + { + VisitAllSeqSets(**it_se, m); + } + } + } + + + // Generate a flat-file report for a Seq-entry // (the other CFlatFileGenerator::Generate functions ultimately // call this) @@ -156,6 +223,7 @@ void CFlatFileGenerator::Generate m_Ctx->SetSGS(false); CConstRef topent = entry.GetTopLevelEntry().GetCompleteSeq_entry(); if (topent && topent->IsSet()) { + /* const CBioseq_set& topset = topent->GetSet(); VISIT_ALL_SEQSETS_WITHIN_SEQSET (itr, topset) { const CBioseq_set& bss = *itr; @@ -163,6 +231,11 @@ void CFlatFileGenerator::Generate m_Ctx->SetSGS(true); } } + */ + VisitAllSeqSets(*topent, [this](const CBioseq_set& bss){ + if (bss.GetClass() == CBioseq_set::eClass_small_genome_set) { + m_Ctx->SetSGS(true); + }}); } CRef pItemOS( & item_os ); diff --git a/c++/src/objtools/format/flat_qual_slots.cpp b/c++/src/objtools/format/flat_qual_slots.cpp index b5087dea..9a95ffa3 100644 --- a/c++/src/objtools/format/flat_qual_slots.cpp +++ b/c++/src/objtools/format/flat_qual_slots.cpp @@ -1,4 +1,4 @@ -/* $Id: flat_qual_slots.cpp 514605 2016-09-22 18:44:07Z ivanov $ +/* $Id: flat_qual_slots.cpp 514265 2016-09-20 19:15:12Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/format/flat_seqloc.cpp b/c++/src/objtools/format/flat_seqloc.cpp index e2904087..3638cf13 100644 --- a/c++/src/objtools/format/flat_seqloc.cpp +++ b/c++/src/objtools/format/flat_seqloc.cpp @@ -1,4 +1,4 @@ -/* $Id: flat_seqloc.cpp 499994 2016-04-29 18:39:01Z kans $ +/* $Id: flat_seqloc.cpp 533244 2017-04-13 20:40:43Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -148,7 +148,8 @@ static CConstRef s_FlattenLoc (const CSeq_loc &loc) CFlatSeqLoc::CFlatSeqLoc (const CSeq_loc& loc, CBioseqContext& ctx, - TType type) + TType type, + bool show_all_accns) { // load the map that caches conversion to accession, because // it's *much* faster when done in bulk vs. one at a time. @@ -173,8 +174,10 @@ CFlatSeqLoc::CFlatSeqLoc } // don't translate ones that are synonyms of this bioseq - if( ctx.GetHandle().IsSynonym( loc_ci.GetSeq_id() ) ) { - continue; + if (! show_all_accns) { + if( ctx.GetHandle().IsSynonym( loc_ci.GetSeq_id() ) ) { + continue; + } } handles_set.insert( handle ); @@ -204,9 +207,9 @@ CFlatSeqLoc::CFlatSeqLoc CNcbiOstrstream oss; if (s_NeedsFlattening (loc)) { CConstRef flat = s_FlattenLoc (loc); - x_Add(*flat, oss, ctx, type, true); + x_Add(*flat, oss, ctx, type, true, show_all_accns); } else { - x_Add(loc, oss, ctx, type, true); + x_Add(loc, oss, ctx, type, true, show_all_accns); } ((string)CNcbiOstrstreamToString(oss)).swap( m_String ); } @@ -217,7 +220,8 @@ bool CFlatSeqLoc::x_Add CNcbiOstrstream& oss, CBioseqContext& ctx, TType type, - bool show_comp) + bool show_comp, + bool show_all_accns) { CScope& scope = ctx.GetScope(); const CBioseq_Handle& seq = ctx.GetHandle(); @@ -232,7 +236,7 @@ bool CFlatSeqLoc::x_Add if ( show_comp && GetStrand(loc, &scope) == eNa_strand_minus ) { CRef rev_loc(SeqLocRevCmpl(loc, &scope)); oss << "complement("; - x_Add(*rev_loc, oss, ctx, type, false); + x_Add(*rev_loc, oss, ctx, type, false, show_all_accns); oss << ')'; return true; } @@ -284,7 +288,7 @@ bool CFlatSeqLoc::x_Add }} case CSeq_loc::e_Whole: {{ - x_AddID(loc.GetWhole(), oss, ctx, type); + x_AddID(loc.GetWhole(), oss, ctx, type, show_all_accns); TSeqPos len = sequence::GetLength(loc, &scope); oss << "1"; if (len > 1) { @@ -294,7 +298,7 @@ bool CFlatSeqLoc::x_Add }} case CSeq_loc::e_Int: {{ - return x_Add(loc.GetInt(), oss, ctx, type, show_comp); + return x_Add(loc.GetInt(), oss, ctx, type, show_comp, show_all_accns); }} case CSeq_loc::e_Packed_int: {{ @@ -304,7 +308,7 @@ bool CFlatSeqLoc::x_Add const char* delim = ""; ITERATE (CPacked_seqint::Tdata, it, loc.GetPacked_int().Get()) { oss << delim; - if (!x_Add(**it, oss, ctx, type, show_comp)) { + if (!x_Add(**it, oss, ctx, type, show_comp, show_all_accns)) { delim = ""; } else { delim = ","; @@ -315,13 +319,13 @@ bool CFlatSeqLoc::x_Add }} case CSeq_loc::e_Pnt: {{ - return x_Add(loc.GetPnt(), oss, ctx, type, show_comp); + return x_Add(loc.GetPnt(), oss, ctx, type, show_comp, show_all_accns); }} case CSeq_loc::e_Packed_pnt: {{ const CPacked_seqpnt& ppnt = loc.GetPacked_pnt(); ENa_strand strand = ppnt.IsSetStrand() ? ppnt.GetStrand() : eNa_strand_unknown; - x_AddID(ppnt.GetId(), oss, ctx, type); + x_AddID(ppnt.GetId(), oss, ctx, type, show_all_accns); if (strand == eNa_strand_minus && show_comp) { oss << "complement("; } @@ -330,7 +334,7 @@ bool CFlatSeqLoc::x_Add ITERATE (CPacked_seqpnt::TPoints, it, ppnt.GetPoints()) { oss << delim; const CInt_fuzz* fuzz = ppnt.CanGetFuzz() ? &ppnt.GetFuzz() : 0; - if (!x_Add(*it, fuzz, oss, ( ctx.Config().DoHTML() ? eHTML_Yes : eHTML_None ) )) { + if (!x_Add(*it, fuzz, oss, ( ctx.Config().DoHTML() ? eHTML_Yes : eHTML_None ), eForce_None, eSource_Other, show_all_accns )) { delim = ""; } else { delim = ","; @@ -385,7 +389,7 @@ bool CFlatSeqLoc::x_Add delim = ""; } else { // add the actual location - if (!x_Add(this_loc, oss, ctx, type, show_comp)) { + if (!x_Add(this_loc, oss, ctx, type, show_comp, show_all_accns)) { delim = ""; } else { delim = ","; @@ -414,7 +418,7 @@ bool CFlatSeqLoc::x_Add oss << "one-of("; ITERATE (CSeq_loc_equiv::Tdata, it, loc.GetEquiv().Get()) { oss << delim; - if (!x_Add(**it, oss, ctx, type, show_comp)) { + if (!x_Add(**it, oss, ctx, type, show_comp, show_all_accns)) { delim = ""; } else { delim = ","; @@ -430,10 +434,10 @@ bool CFlatSeqLoc::x_Add return false; } oss << "bond("; - x_Add(bond.GetA(), oss, ctx, type, show_comp); + x_Add(bond.GetA(), oss, ctx, type, show_comp, show_all_accns); if ( bond.CanGetB() ) { oss << ","; - x_Add(bond.GetB(), oss, ctx, type, show_comp); + x_Add(bond.GetB(), oss, ctx, type, show_comp, show_all_accns); } oss << ")"; break; @@ -450,12 +454,41 @@ bool CFlatSeqLoc::x_Add } +bool CFlatSeqLoc::x_FuzzToDisplayed(const CSeq_interval& si) const +{ + if (!si.IsSetFuzz_to()) { + return false; + } + + const CInt_fuzz& to_fuzz = si.GetFuzz_to(); +/* Range fuzziness is not displayed + if (to_fuzz.IsRange()) { + return true; + } +*/ + if (to_fuzz.IsLim()) { + switch( to_fuzz.GetLim() ) { + case CInt_fuzz::eLim_tr: + case CInt_fuzz::eLim_gt: + case CInt_fuzz::eLim_tl: + case CInt_fuzz::eLim_lt: + return true; + default: + break; + } + } + return false; +} + + + bool CFlatSeqLoc::x_Add (const CSeq_interval& si, CNcbiOstrstream& oss, CBioseqContext& ctx, TType type, - bool show_comp) + bool show_comp, + bool show_all_accns) { bool do_html = ctx.Config().DoHTML(); @@ -470,15 +503,15 @@ bool CFlatSeqLoc::x_Add if (comp) { oss << "complement("; } - x_AddID(si.GetId(), oss, ctx, type); + x_AddID(si.GetId(), oss, ctx, type, show_all_accns); // get the fuzz we need, but certain kinds of fuzz do not belong in an interval const CSeq_interval::TFuzz_from *from_fuzz = (si.IsSetFuzz_from() ? &si.GetFuzz_from() : 0); x_Add(from, from_fuzz, oss, ( do_html ? eHTML_Yes : eHTML_None )); + if ( (type == eType_assembly) || - ( to > 0 && - (from != to || si.IsSetFuzz_from() || si.IsSetFuzz_to()) ) ) + ((from != to || x_FuzzToDisplayed(si)) ) ) { oss << ".."; @@ -499,7 +532,8 @@ bool CFlatSeqLoc::x_Add CNcbiOstrstream& oss, CBioseqContext& ctx, TType type, - bool show_comp) + bool show_comp, + bool show_all_accns) { if ( !pnt.CanGetPoint() ) { return false; @@ -510,7 +544,7 @@ bool CFlatSeqLoc::x_Add pnt.IsSetStrand() && IsReverse(pnt.GetStrand()) && show_comp; TSeqPos pos = pnt.GetPoint(); - x_AddID(pnt.GetId(), oss, ctx, type); + x_AddID(pnt.GetId(), oss, ctx, type, show_all_accns); if( is_comp ) { oss << "complement("; } @@ -532,7 +566,8 @@ bool CFlatSeqLoc::x_Add CNcbiOstrstream& oss, EHTML html, EForce force, - ESource source) + ESource source, + bool show_all_accns) { // need to convert to 1-based coordinates pnt += 1; @@ -626,15 +661,18 @@ void CFlatSeqLoc::x_AddID (const CSeq_id& id, CNcbiOstrstream& oss, CBioseqContext& ctx, - TType type) + TType type, + bool show_all_accns) { const bool do_html = ( ctx.Config().DoHTML() && type == eType_assembly); - if (ctx.GetHandle().IsSynonym(id)) { - if ( type == eType_assembly ) { - oss << ctx.GetAccession() << ':'; + if (! show_all_accns) { + if (ctx.GetHandle().IsSynonym(id)) { + if ( type == eType_assembly ) { + oss << ctx.GetAccession() << ':'; + } + return; } - return; } CConstRef idp; diff --git a/c++/src/objtools/format/ftable_formatter.cpp b/c++/src/objtools/format/ftable_formatter.cpp index 71a264d5..fb0ccc7e 100644 --- a/c++/src/objtools/format/ftable_formatter.cpp +++ b/c++/src/objtools/format/ftable_formatter.cpp @@ -1,4 +1,4 @@ -/* $Id: ftable_formatter.cpp 282934 2011-05-17 16:08:46Z kornbluh $ +/* $Id: ftable_formatter.cpp 537539 2017-06-01 14:54:26Z foleyjp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -116,8 +116,11 @@ void CFtableFormatter::x_FormatLocation bool need_key = true; for (CSeq_loc_CI it(loc); it; ++it) { const CSeq_loc& curr = it.GetEmbeddingSeq_loc(); + CConstRef curr_it = it.GetRangeAsSeq_loc(); + bool is_between = s_IsBetween(curr); - + + const bool minus_strand = it.GetStrand() == eNa_strand_minus; CSeq_loc_CI::TRange range = it.GetRange(); TSeqPos start, stop; if ( range.IsWhole() ) { @@ -132,20 +135,20 @@ void CFtableFormatter::x_FormatLocation } string left, right; - if ( curr.IsPartialStart(eExtreme_Biological) ) { - left = '<'; + if ( curr_it->IsPartialStart(eExtreme_Positional) ) { + left = minus_strand ? '>' : '<'; } left += NStr::IntToString(start); if ( is_between ) { left += '^'; } - if ( curr.IsPartialStop(eExtreme_Biological) ) { - right = '>'; + if ( curr_it->IsPartialStop(eExtreme_Positional) ) { + right = minus_strand ? '<' : '>'; } right += NStr::IntToString(stop); string line; - if ( it.GetStrand() == eNa_strand_minus ) { + if ( minus_strand ) { line = right + '\t' + left; } else { line = left + '\t' + right; diff --git a/c++/src/objtools/format/gather_items.cpp b/c++/src/objtools/format/gather_items.cpp index 755d2293..97a4a8ad 100644 --- a/c++/src/objtools/format/gather_items.cpp +++ b/c++/src/objtools/format/gather_items.cpp @@ -1,4 +1,4 @@ -/* $Id: gather_items.cpp 520380 2016-11-28 14:03:14Z ivanov $ +/* $Id: gather_items.cpp 547740 2017-10-03 17:54:39Z fukanchi $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -105,6 +105,7 @@ #include #include #include +#include #include #include @@ -484,6 +485,7 @@ bool s_FilterPubdesc(const CPubdesc& pubdesc, CBioseqContext& ctx) return false; } +/* static bool s_IsDuplicatePmid(const CPubdesc& pubdesc, set& included_pmids) { @@ -500,6 +502,7 @@ static bool s_IsDuplicatePmid(const CPubdesc& pubdesc, } return is_duplicate; } +*/ void CFlatGatherer::x_GatherReferences(const CSeq_loc& loc, TReferences& refs) const @@ -511,7 +514,7 @@ void CFlatGatherer::x_GatherReferences(const CSeq_loc& loc, TReferences& refs) c return; } - set included_pmids; + // set included_pmids; // gather references from descriptors (top-level first) // (Since CSeqdesc_CI doesn't currently support bottom-to-top iteration, @@ -521,9 +524,11 @@ void CFlatGatherer::x_GatherReferences(const CSeq_loc& loc, TReferences& refs) c if ( s_FilterPubdesc(pubdesc, *m_Current) ) { continue; } + /* if (s_IsDuplicatePmid(pubdesc, included_pmids)) { continue; } + */ refs.push_back(CBioseqContext::TRef(new CReferenceItem(*it, *m_Current))); } for (CSeqdesc_CI it(seq, CSeqdesc::e_Pub); it; ++it) { @@ -535,9 +540,11 @@ void CFlatGatherer::x_GatherReferences(const CSeq_loc& loc, TReferences& refs) c if ( s_FilterPubdesc(pubdesc, *m_Current) ) { continue; } + /* if (s_IsDuplicatePmid(pubdesc, included_pmids)) { continue; } + */ refs.push_back(CBioseqContext::TRef(new CReferenceItem(*it, *m_Current))); } @@ -558,9 +565,11 @@ void CFlatGatherer::x_GatherReferences(const CSeq_loc& loc, TReferences& refs) c if ( s_FilterPubdesc(pubdesc, *m_Current) ) { continue; } + /* if (s_IsDuplicatePmid(pubdesc, included_pmids)) { continue; } + */ CRef desc(new CSeqdesc); desc->SetPub(const_cast((*it)->GetPub())); refs.push_back(CBioseqContext::TRef @@ -599,9 +608,11 @@ void CFlatGatherer::x_GatherReferences(const CSeq_loc& loc, TReferences& refs) c if ( s_FilterPubdesc(pubdesc, *m_Current) ) { continue; } + /* if (s_IsDuplicatePmid(pubdesc, included_pmids)) { continue; } + */ refs.push_back(CBioseqContext::TRef(new CReferenceItem(*dit, *m_Current))); } @@ -1321,7 +1332,8 @@ static int s_StrucCommOrder(const string&str) { return 1000; } -static bool s_SeqDescCompare(const CRef& desc1, const CRef& desc2) +static bool s_SeqDescCompare(const CConstRef& desc1, + const CConstRef& desc2) { CSeqdesc::E_Choice chs1, chs2; @@ -1366,18 +1378,17 @@ static bool s_SeqDescCompare(const CRef& desc1, const CRef& void CFlatGatherer::x_StructuredComments(CBioseqContext& ctx) const { - vector> vdesc; + vector > vdesc; for (CSeqdesc_CI it(ctx.GetHandle(), CSeqdesc::e_User); it; ++it) { const CSeqdesc & desc = *it; if (desc.IsUser()) { - CRef dsc(new CSeqdesc); - dsc->Assign(desc); + CConstRef dsc(&desc); vdesc.push_back(dsc); } } stable_sort( vdesc.begin(), vdesc.end(), s_SeqDescCompare ); for (size_t ii = 0; ii < vdesc.size(); ii++) { - CRef& dsc = vdesc[ii]; + CConstRef& dsc = vdesc[ii]; const CSeqdesc & desc = *dsc; if (m_FirstGenAnnotSCAD && desc.IsUser()) { const CUser_object& usr = desc.GetUser(); @@ -1697,7 +1708,7 @@ void CFlatGatherer::x_CollectSourceFeatures for ( CFeat_CI fi(bh, range, as); fi; ++fi ) { TSeqPos start = fi->GetLocation().GetTotalRange().GetFrom(); TSeqPos stop = fi->GetLocation().GetTotalRange().GetTo(); - if ( start <= range.GetFrom() && stop >= range.GetTo() ) { + if ( start >= range.GetFrom() && stop <= range.GetTo() ) { CRef sf(new CSourceFeatureItem(*fi, ctx, m_Feat_Tree)); srcs.push_back(sf); } @@ -1705,6 +1716,43 @@ void CFlatGatherer::x_CollectSourceFeatures } +static CConstRef x_GetSourceFeatFromCDS ( + const CBioseq_Handle& bsh +) + +{ + CConstRef cds_feat; + CConstRef cds_loc; + CConstRef src_ref; + + CScope& scope = bsh.GetScope(); + + cds_feat = sequence::GetCDSForProduct (bsh); + + if (cds_feat) { + cds_loc = &cds_feat->GetLocation(); + if (cds_loc) { + CRef cleaned_location( new CSeq_loc ); + cleaned_location->Assign( *cds_loc ); + CConstRef src_feat + = sequence::GetBestOverlappingFeat (*cleaned_location, CSeqFeatData::eSubtype_biosrc, sequence::eOverlap_SubsetRev, scope); + if (! src_feat && cleaned_location->IsSetStrand() && IsReverse(cleaned_location->GetStrand())) { + CRef rev_loc(sequence::SeqLocRevCmpl(*cleaned_location, &scope)); + cleaned_location->Assign(*rev_loc); + src_feat = sequence::GetBestOverlappingFeat (*cleaned_location, CSeqFeatData::eSubtype_biosrc, sequence::eOverlap_SubsetRev, scope); + } + if (src_feat) { + const CSeq_feat& feat = *src_feat; + if (feat.IsSetData()) { + return src_feat; + } + } + } + } + + return CConstRef (); +} + void CFlatGatherer::x_CollectBioSourcesOnBioseq (const CBioseq_Handle& bh, const TRange& range, @@ -1713,11 +1761,20 @@ void CFlatGatherer::x_CollectBioSourcesOnBioseq { const CFlatFileConfig& cfg = ctx.Config(); + // if protein, get sources applicable to DNA location of CDS if ( ctx.IsProt() ) { // collect biosources features on bioseq if ( !ctx.DoContigStyle() || cfg.ShowContigSources() ) { - x_CollectSourceFeatures(bh, range, ctx, srcs); - if (! srcs.empty()) return; + CConstRef src_feat = x_GetSourceFeatFromCDS (bh); + if (src_feat.NotEmpty()) { + // CMappedFeat mapped_feat(bh.GetScope().GetSeq_featHandle(*src_feat)); + const CSeq_feat& feat = *src_feat; + const CSeqFeatData& data = feat.GetData(); + const CBioSource& src = data.GetBiosrc(); + CRef sf(new CSourceFeatureItem(src, range, ctx, m_Feat_Tree)); + srcs.push_back(sf); + return; + } } } @@ -1741,40 +1798,10 @@ void CFlatGatherer::x_CollectBioSources(TSourceFeatSet& srcs) const CScope* scope = &ctx.GetScope(); const CFlatFileConfig& cfg = ctx.Config(); - // if protein, get sources applicable to DNA location of CDS - if ( ctx.IsProt() ) { - const CSeq_feat* cds = GetCDSForProduct(ctx.GetHandle()); - if ( cds != 0 ) { - const CSeq_loc& cds_loc = cds->GetLocation(); - CRef cleaned_location( new CSeq_loc ); - cleaned_location->Assign( cds_loc ); - if (cleaned_location->IsSetStrand() && IsReverse(cleaned_location->GetStrand())) { - CRef rev_loc(SeqLocRevCmpl(*cleaned_location, scope)); - cleaned_location->Assign(*rev_loc); - } - CBioseq_Handle bioseq_h; - ITERATE( CSeq_loc, cds_loc_ci, *cleaned_location ) { - bioseq_h = scope->GetBioseqHandle(cds_loc_ci.GetSeq_id()); - if( bioseq_h ) { - break; - } - } - if( bioseq_h ) { - x_CollectBioSourcesOnBioseq( - bioseq_h, - cleaned_location->GetTotalRange(), - ctx, - srcs); - } - } - } - - if ( srcs.empty() ) { - x_CollectBioSourcesOnBioseq(ctx.GetHandle(), - ctx.GetLocation().GetTotalRange(), - ctx, - srcs); - } + x_CollectBioSourcesOnBioseq(ctx.GetHandle(), + ctx.GetLocation().GetTotalRange(), + ctx, + srcs); // if no source found create one (only if not FTable format or Dump mode) if ( srcs.empty() && /* ! cfg.IsFormatFTable() && */ ! cfg.IsModeDump() ) { @@ -2640,7 +2667,27 @@ bool s_CoincidingGapFeatures( return false; } -void CFlatGatherer::x_GatherFeaturesOnLocation + +static CMappedFeat s_GetMappedFeat(CRef& feat, CScope& scope) +{ + CRef temp_annot = Ref(new CSeq_annot()); + temp_annot->SetData().SetFtable().push_back(feat); + scope.AddSeq_annot(*temp_annot); + CSeq_feat_Handle sfh = scope.GetSeq_featHandle(*feat); + return CMappedFeat(sfh); +} + + +static CMappedFeat s_GetTrimmedMappedFeat(const CSeq_feat& feat, + const CRange& range, + CScope& scope) +{ + CRef trimmed_feat = sequence::CFeatTrim::Apply(feat, range); + return s_GetMappedFeat(trimmed_feat, scope); +} + + +void CFlatGatherer::x_GatherFeaturesOnWholeLocation (const CSeq_loc& loc, SAnnotSelector& sel, CBioseqContext& ctx) const @@ -2653,26 +2700,6 @@ void CFlatGatherer::x_GatherFeaturesOnLocation // logic to handle offsets that occur when user sets // the -from and -to command-line parameters CRef slice_mapper; // NULL (unset) if no slicing - if( ! ctx.GetLocation().IsWhole() ) { - // build slice_mapper for mapping locations - - CSeq_id seq_id; - seq_id.Assign( *ctx.GetHandle().GetSeqId() ); - - const TSeqPos new_len = sequence::GetLength( ctx.GetLocation(), &scope ); - - CSeq_loc old_loc; - old_loc.SetInt().SetId( seq_id ); - old_loc.SetInt().SetFrom( 0 ); - old_loc.SetInt().SetTo( new_len - 1 ); - - slice_mapper.Reset( new CSeq_loc_Mapper( loc, old_loc ) ); - slice_mapper->SetFuzzOption( CSeq_loc_Mapper::fFuzzOption_RemoveLimTlOrTr ); - slice_mapper->TruncateNonmappingRanges(); - - // skip gaps when we take slices - gap_it = CSeqMap_CI(); - } // Gaps of length zero are only shown for SwissProt Genpept records const bool showGapsOfSizeZero = ( ctx.IsProt() && ctx.GetPrimaryId()->Which() == CSeq_id_Base::e_Swissprot ); @@ -2705,12 +2732,6 @@ void CFlatGatherer::x_GatherFeaturesOnLocation /// we may need to assert proper product resolution /// - if( slice_mapper && (feat.GetFeatSubtype() == CSeqFeatData::eSubtype_gap) && ! feat.IsPlainFeat() ) { - // skip gaps when we take slices (i.e. "-from" and "-to" command-line args), - // unless they're a plain feature. - // (compare NW_001468136 (100 to 200000) and AC185591 (100 to 100000) ) - continue; - } if (it->GetData().IsRna() && it->IsSetProduct()) { vector children = @@ -2745,12 +2766,6 @@ void CFlatGatherer::x_GatherFeaturesOnLocation CConstRef feat_loc(&it->GetLocation()); - // Map the feat_loc if we're using a slice (the "-from" and "-to" command-line options) - if( slice_mapper ) - { - feat_loc.Reset( slice_mapper->Map( *feat_loc ) ); - } - feat_loc = s_NormalizeNullsBetween( feat_loc ); // make sure location ends on the current bioseq @@ -2758,7 +2773,7 @@ void CFlatGatherer::x_GatherFeaturesOnLocation // may need to map sig_peptide on a different segment if (feat.GetData().IsCdregion()) { if (!ctx.Config().IsFormatFTable()) { - x_GetFeatsOnCdsProduct(original_feat, *feat_loc, ctx, slice_mapper); + x_GetFeatsOnCdsProduct(original_feat, ctx, slice_mapper); } } continue; @@ -2789,7 +2804,6 @@ void CFlatGatherer::x_GatherFeaturesOnLocation } } - // format feature item.Reset( x_NewFeatureItem(*it, ctx, feat_loc, m_Feat_Tree) ); out << item; @@ -2808,7 +2822,7 @@ void CFlatGatherer::x_GatherFeaturesOnLocation {{ // map features from protein if (!ctx.Config().IsFormatFTable()) { - x_GetFeatsOnCdsProduct(original_feat, *feat_loc, ctx, + x_GetFeatsOnCdsProduct(original_feat, ctx, slice_mapper, CConstRef(static_cast(item.GetNonNullPointer())) ); } @@ -2852,6 +2866,276 @@ void CFlatGatherer::x_GatherFeaturesOnLocation } } +//#define USE_DELTA + +#ifdef USE_DELTA +DEFINE_STATIC_MUTEX(sx_UniqueIdMutex); +static size_t s_UniqueIdOffset = 0; +CRef s_MakeUniqueId(CScope& scope) +{ + CMutexGuard guard(sx_UniqueIdMutex); + + CRef id(new CSeq_id()); + bool good = false; + while (!good) { +// id->SetOther().SetAccession("X" + NStr::NumericToString(s_UniqueIdOffset)); + id->SetLocal().SetStr("tmp_delta" + NStr::NumericToString(s_UniqueIdOffset)); + CBioseq_Handle bsh = scope.GetBioseqHandle(*id); + if (bsh) { + s_UniqueIdOffset++; + } else { + good = true; + } + } + return id; +} + + +static CRef s_MakeTemporaryDelta(const CSeq_loc& loc, CScope& scope) +{ + CBioseq_Handle bsh = scope.GetBioseqHandle(loc); + CRef seq(new CBioseq()); + seq->SetId().push_back(s_MakeUniqueId(scope)); + seq->SetInst().Assign(bsh.GetInst()); + seq->SetInst().ResetSeq_data(); + seq->SetInst().ResetExt(); + seq->SetInst().SetRepr(CSeq_inst::eRepr_delta); + CRef element(new CDelta_seq()); + element->SetLoc().Assign(loc); + seq->SetInst().SetExt().SetDelta().Set().push_back(element); + seq->SetInst().SetLength(sequence::GetLength(*loc.GetId(), &scope)); + return seq; +} + + +static CRef s_FixId(const CSeq_loc& loc, const CSeq_id& orig, const CSeq_id& temporary) +{ + bool any_change = false; + CRef new_loc(new CSeq_loc()); + new_loc->Assign(loc); + CSeq_loc_I it(*new_loc); + for (; it; ++it) { + const CSeq_id& id = it.GetSeq_id(); + if (id.Equals(temporary)) { + it.SetSeq_id(orig); + any_change = true; + } + } + if (any_change) { + new_loc->Assign(*it.MakeSeq_loc()); + } + return new_loc; +} +#endif // USE_DELTA + + +CRef s_MakeSliceMapper(const CSeq_loc& loc, CBioseqContext& ctx) +{ + CSeq_id seq_id; + seq_id.Assign( *ctx.GetHandle().GetSeqId() ); + + const TSeqPos new_len = sequence::GetLength( ctx.GetLocation(), &(ctx.GetScope())); + + CSeq_loc old_loc; + old_loc.SetInt().SetId( seq_id ); + old_loc.SetInt().SetFrom( 0 ); + old_loc.SetInt().SetTo( new_len - 1 ); + + CRef slice_mapper( new CSeq_loc_Mapper( loc, old_loc ) ); + slice_mapper->SetFuzzOption( CSeq_loc_Mapper::fFuzzOption_RemoveLimTlOrTr ); + slice_mapper->TruncateNonmappingRanges(); + return slice_mapper; +} + + +void CFlatGatherer::x_GatherFeaturesOnRange +(const CSeq_loc& loc, + SAnnotSelector& sel, + CBioseqContext& ctx) const +{ + CScope& scope = ctx.GetScope(); + CFlatItemOStream& out = *m_ItemOS; + + // logic to handle offsets that occur when user sets + // the -from and -to command-line parameters + // build slice_mapper for mapping locations + CRef slice_mapper = s_MakeSliceMapper(loc, ctx); + + CSeq_feat_Handle prev_feat; + CConstRef item; +#ifdef USE_DELTA + SAnnotSelector sel_cpy = sel; + sel_cpy.SetResolveAll(); + sel_cpy.SetResolveDepth(kMax_Int); + sel_cpy.SetAdaptiveDepth(true); + CRef delta = s_MakeTemporaryDelta(loc, scope); + CBioseq_Handle delta_bsh = scope.AddBioseq(*delta); + CFeat_CI it(delta_bsh, sel_cpy); +#else + SAnnotSelector sel_cpy = sel; + sel_cpy.SetIgnoreStrand(); + if (loc.IsSetStrand() && loc.GetStrand() == eNa_strand_minus) { + sel_cpy.SetSortOrder(SAnnotSelector::eSortOrder_Reverse); + } + CFeat_CI it(scope, loc, sel_cpy); +#endif + ctx.GetFeatTree().AddFeatures(it); + for ( ; it; ++it) { + try { + CSeq_feat_Handle feat = it->GetSeq_feat_Handle(); + const CSeq_feat& original_feat = it->GetOriginalFeature(); + + /// we need to cleanse CDD features + + s_CleanCDDFeature(original_feat); + + /// + /// HACK HACK HACK + /// + + /// + /// HACK HACK HACK + /// we may need to assert proper product resolution + /// + + if( (feat.GetFeatSubtype() == CSeqFeatData::eSubtype_gap) && ! feat.IsPlainFeat() ) { + // skip gaps when we take slices (i.e. "-from" and "-to" command-line args), + // unless they're a plain feature. + // (compare NW_001468136 (100 to 200000) and AC185591 (100 to 100000) ) + continue; + } + + if (it->GetData().IsRna() && it->IsSetProduct()) { + vector children = + ctx.GetFeatTree().GetChildren(*it); + if (children.size() == 1 && + children.front().IsSetProduct()) { + + /// resolve sequences + CSeq_id_Handle rna = + sequence::GetIdHandle(it->GetProduct(), &scope); + CSeq_id_Handle prot = + sequence::GetIdHandle(children.front().GetProduct(), + &scope); + + CBioseq_Handle rna_bsh; + CBioseq_Handle prot_bsh; + GetResolveOrder(scope, + rna, prot, + rna_bsh, prot_bsh); + } + } + + /// + /// HACK HACK HACK + /// + + // supress dupliacte features + if (prev_feat && s_IsDuplicateFeatures(prev_feat, feat)) { + continue; + } + prev_feat = feat; + + CConstRef feat_loc(&it->GetLocation()); + +#ifdef USE_DELTA + CMappedFeat mapped_feat = *it; + feat_loc = s_FixId(*feat_loc, *(ctx.GetBioseqIds().front()), *(delta->GetId().front())); +#else + // Map the feat_loc if we're using a slice (the "-from" and "-to" command-line options) + CRange range = loc.GetTotalRange(); + const CSeq_feat& ft = it->GetMappedFeature(); + CMappedFeat mapped_feat = s_GetTrimmedMappedFeat(ft, range, scope); + feat_loc.Reset( slice_mapper->Map( mapped_feat.GetLocation() ) ); +#endif + feat_loc = s_NormalizeNullsBetween( feat_loc ); + + // make sure location ends on the current bioseq + if ( !s_SeqLocEndsOnBioseq(*feat_loc, ctx, eEndsOnBioseqOpt_LastPartOfSeqLoc, feat.GetData().Which() ) ) { + // may need to map sig_peptide on a different segment + if (feat.GetData().IsCdregion()) { + if (!ctx.Config().IsFormatFTable()) { + x_GetFeatsOnCdsProduct(original_feat, ctx, slice_mapper); + } + } + continue; + } + + item.Reset( x_NewFeatureItem(mapped_feat, ctx, feat_loc, m_Feat_Tree) ); + out << item; + + // Add more features depending on user preferences + + switch (feat.GetFeatSubtype()) { + case CSeqFeatData::eSubtype_mRNA: + {{ + // optionally map CDS from cDNA onto genomic + if (s_CopyCDSFromCDNA(ctx) && feat.IsSetProduct()) { + x_CopyCDSFromCDNA(original_feat, ctx); + } + break; + }} + case CSeqFeatData::eSubtype_cdregion: + {{ + // map features from protein + if (!ctx.Config().IsFormatFTable()) { + x_GetFeatsOnCdsProduct(original_feat, ctx, + slice_mapper, + CConstRef(static_cast(item.GetNonNullPointer())) ); + } + break; + }} + default: + break; + } + } catch (CException& e) { + // special case: Job cancellation exceptions make us stop + // generating features. + if( NStr::EqualNocase(e.what(), "job cancelled") || + NStr::EqualNocase(e.what(), "job canceled") ) + { + LOG_POST_X(2, Error << "Job canceled while processing feature " + << s_GetFeatDesc(it->GetSeq_feat_Handle()) + << " [" << e << "]; flatfile may be truncated"); +#ifdef USE_DELTA + scope.RemoveBioseq(delta_bsh); +#endif + return; + } + + // for cases where a halt is requested, just rethrow the exception + if( e.GetErrCodeString() == string("eHaltRequested") ) { +#ifdef USE_DELTA + scope.RemoveBioseq(delta_bsh); +#endif + throw e; + } + + // post to log, go on to next feature + LOG_POST_X(2, Error << "Error processing feature " + << s_GetFeatDesc(it->GetSeq_feat_Handle()) + << " [" << e << "]"); + } + } // end of for loop + +#ifdef USE_DELTA + scope.RemoveBioseq(delta_bsh); +#endif +} + + +void CFlatGatherer::x_GatherFeaturesOnLocation +(const CSeq_loc& loc, + SAnnotSelector& sel, + CBioseqContext& ctx) const +{ + if( ctx.GetLocation().IsWhole() ) { + x_GatherFeaturesOnWholeLocation(loc, sel, ctx); + } else { + x_GatherFeaturesOnRange(loc, sel, ctx); + } +} + void CFlatGatherer::x_CopyCDSFromCDNA (const CSeq_feat& feat, @@ -3065,7 +3349,7 @@ SAnnotSelector s_GetCdsProductSel(CBioseqContext& ctx) .IncludeFeatSubtype(CSeqFeatData::eSubtype_sig_peptide_aa) .IncludeFeatSubtype(CSeqFeatData::eSubtype_transit_peptide_aa) .IncludeFeatSubtype(CSeqFeatData::eSubtype_preprotein) - .IncludeFeatSubtype(CSeqFeatData::eSubtype_propeptide); + .IncludeFeatSubtype(CSeqFeatData::eSubtype_propeptide_aa); return sel; } @@ -3155,7 +3439,6 @@ void s_FixIntervalProtToCds( // ============================================================================ void CFlatGatherer::x_GetFeatsOnCdsProduct( const CSeq_feat& feat, - const CSeq_loc& mapped_loc, CBioseqContext& ctx, CRef slice_mapper, CConstRef cdsFeatureItem ) const @@ -3176,6 +3459,7 @@ void CFlatGatherer::x_GetFeatsOnCdsProduct( if (!prot_id) { return; } + CBioseq_Handle prot; @@ -3201,7 +3485,7 @@ void CFlatGatherer::x_GetFeatsOnCdsProduct( CSeqFeatData::ESubtype subtype = curr.GetFeatSubtype(); if ( cfg.HideCDDFeatures() && - subtype == CSeqFeatData::eSubtype_region && + (subtype == CSeqFeatData::eSubtype_region || subtype == CSeqFeatData::eSubtype_site) && s_IsCDD(curr) ) { // passing this test prevents mapping of COG CDD region features continue; @@ -3224,12 +3508,6 @@ void CFlatGatherer::x_GetFeatsOnCdsProduct( // map prot location to nuc location CRef loc(prot_to_cds.Map(curr_loc)); - if ( curr.IsSetData() ) { - const CSeqFeatData& currData = curr.GetData(); - if ( currData.Which() == CSeqFeatData::e_Prot ) { - // s_FixIntervalProtToCds( feat, curr_loc, loc ); // This line appears to be unnecessary, but I'm leaving it in in case further testing reveals I'm wrong. - } - } if (loc) { if (loc->IsMix() || loc->IsPacked_int()) { // merge might turn interval into point, so we give it 2 fuzzes to prevent that @@ -3247,19 +3525,28 @@ void CFlatGatherer::x_GetFeatsOnCdsProduct( continue; } + CConstRef item; // for command-line args "-from" and "-to" + CMappedFeat mapped_feat = *it; if( slice_mapper && loc ) { - loc = slice_mapper->Map( *loc ); - if( loc->IsNull() ) { + CRange range = ctx.GetLocation().GetTotalRange(); + CRef mapped_loc = slice_mapper->Map(*CFeatTrim::Apply(*loc, range)); + if( mapped_loc->IsNull() ) { continue; } + CRef feat(new CSeq_feat()); + feat->Assign(mapped_feat.GetMappedFeature()); + feat->ResetLocation(); + feat->SetLocation(*loc); + mapped_feat = s_GetTrimmedMappedFeat(*feat, range, scope); + loc = mapped_loc; } - CConstRef item - ( x_NewFeatureItem(*it, ctx, - s_NormalizeNullsBetween(loc), m_Feat_Tree, - CFeatureItem::eMapped_from_prot, - cdsFeatureItem ) ); + item = ConstRef( x_NewFeatureItem(*it, ctx, + s_NormalizeNullsBetween(loc), m_Feat_Tree, + CFeatureItem::eMapped_from_prot, + cdsFeatureItem ) ); + *m_ItemOS << item; prev = curr; diff --git a/c++/src/objtools/format/gbseq_formatter.cpp b/c++/src/objtools/format/gbseq_formatter.cpp index f3eb1a99..07803cc6 100644 --- a/c++/src/objtools/format/gbseq_formatter.cpp +++ b/c++/src/objtools/format/gbseq_formatter.cpp @@ -1,4 +1,4 @@ -/* $Id: gbseq_formatter.cpp 472056 2015-07-06 19:29:12Z gotvyans $ +/* $Id: gbseq_formatter.cpp 515707 2016-10-05 12:32:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -79,7 +79,7 @@ BEGIN_SCOPE(objects) static void s_GBSeqStringCleanup(string& str, bool location = false) { list l; - NStr::Split(str, " \n\r\t\b", l); + NStr::Split(str, " \n\r\t\b", l, NStr::fSplit_Tokenize); str = NStr::Join(l, " "); if ( location ) { str = NStr::Replace(str, ", ", ","); @@ -355,7 +355,7 @@ void CGBSeqFormatter::FormatGenomeProject list ids; NStr::SplitInTwo( line, ":", first, second ); first = NStr::TruncateSpaces(first); - NStr::Split(second, ",", ids); + NStr::Split(second, ",", ids, NStr::fSplit_Tokenize); FOR_EACH_STRING_IN_LIST (s_itr, ids) { string id = *s_itr; id = NStr::TruncateSpaces(id); @@ -682,7 +682,7 @@ void CGBSeqFormatter::x_StrOStreamToTextOStream(IFlatTextOStream& text_os) // flush ObjectOutputStream to underlying strstream m_Out->Flush(); // read text from strstream - NStr::Split((string)CNcbiOstrstreamToString(m_StrStream), "\n", l); + NStr::Split((string)CNcbiOstrstreamToString(m_StrStream), "\n", l, NStr::fSplit_Tokenize); // add text to TextOStream text_os.AddParagraph(l); // reset strstream diff --git a/c++/src/objtools/format/genbank_formatter.cpp b/c++/src/objtools/format/genbank_formatter.cpp index d8cc59e8..be3a0fa0 100644 --- a/c++/src/objtools/format/genbank_formatter.cpp +++ b/c++/src/objtools/format/genbank_formatter.cpp @@ -1,4 +1,4 @@ -/* $Id: genbank_formatter.cpp 510812 2016-08-16 14:54:30Z ivanov $ +/* $Id: genbank_formatter.cpp 545053 2017-08-31 13:54:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -75,6 +76,7 @@ #include +#define NCBI_USE_ERRCODE_X Objtools_Fmt_Genbank BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) @@ -108,11 +110,27 @@ namespace { m_orig_text_os(orig_text_os), m_ctx(ctx), m_item(item) - { + { + m_Flushed = false; } - ~CWrapperForFlatTextOStream(void) + ~CWrapperForFlatTextOStream() { + if ( !m_Flushed ) { + try { + Flush(); + ERR_POST_X(1, Warning << "Flatfile output left unflushed in " + << CStackTrace()); + } catch (CFlatException& ) { + ERR_POST_X(2, "Missed flatfile output halt request in " + << CStackTrace()); + } + } + } + + void Flush(void) + { + m_Flushed = true; CFlatFileConfig::CGenbankBlockCallback::EAction eAction = m_block_callback->notify(m_block_text_str, *m_ctx, m_item); switch(eAction) { @@ -164,6 +182,8 @@ namespace { // build the block text here string m_block_text_str; + + bool m_Flushed; }; template @@ -294,6 +314,8 @@ void CGenbankFormatter::EndSection 0, IFlatTextOStream::eAddNewline_No ); } + text_os.Flush(); + // New record, so reset m_FeatureKeyToLocMap.clear(); m_bHavePrintedSourceFeatureJavascript = false; @@ -360,17 +382,28 @@ void CGenbankFormatter::FormatLocus string mol = s_GenbankMol[locus.GetBiomol()]; + const CFlatFileConfig& cfg = GetContext().GetConfig(); + locus_line.setf(IOS_BASE::left, IOS_BASE::adjustfield); - locus_line << setw(16) << locus.GetName(); + + string locusname; + if (cfg.LongLocusNames()) { + locusname = locus.GetFullName(); + } else { + locusname = locus.GetName(); + } + int locuslength = locusname.length(); + locus_line << setw(16) << locusname; // long LOCUS names may impinge on the length (e.g. gi 1449456) // I would consider this behavior conceptually incorrect; we should either fix the data // or truncate the locus names to 16 chars. This is done here as a temporary measure // to make the asn2gb and asn2flat diffs match. // Note: currently this still cannot handle very long LOCUS names (e.g. in gi 1449821) - int spaceForLength = min( 12, (int)(12 - (locus.GetName().length() - 16)) ); + int spaceForLength = min( 12, (int)(12 - (locuslength - 16)) ); locus_line.setf(IOS_BASE::right, IOS_BASE::adjustfield); locus_line - << setw(spaceForLength) << locus.GetLength() + << ' ' + << setw(spaceForLength-1) << locus.GetLength() << ' ' << units << ' ' @@ -397,6 +430,8 @@ void CGenbankFormatter::FormatLocus } text_os.AddParagraph(l, locus.GetObject()); + + text_os.Flush(); } @@ -419,6 +454,8 @@ void CGenbankFormatter::FormatDefline Wrap(l, "DEFINITION", defline_text); text_os.AddParagraph(l, defline.GetObject()); + + text_os.Flush(); } @@ -435,7 +472,8 @@ void CGenbankFormatter::FormatAccession string acc_line = x_FormatAccession(acc, ' '); if( acc.GetContext()->Config().DoHTML() && ! acc.GetContext()->GetLocation().IsWhole() ) { - acc_line = "" + acc_line + ""; + acc_line = "" + acc_line + ""; } if ( acc.IsSetRegion() ) { acc_line += " REGION: "; @@ -451,6 +489,8 @@ void CGenbankFormatter::FormatAccession Wrap(l, "ACCESSION", acc_line); } text_os.AddParagraph(l, acc.GetObject()); + + text_os.Flush(); } @@ -486,6 +526,8 @@ void CGenbankFormatter::FormatVersion } text_os.AddParagraph(l, version.GetObject()); + + text_os.Flush(); } @@ -544,6 +586,8 @@ void CGenbankFormatter::FormatGenomeProject( if( ! l.empty() ) { text_os.AddParagraph(l, gp.GetObject()); } + + text_os.Flush(); } /////////////////////////////////////////////////////////////////////////// @@ -578,6 +622,8 @@ void CGenbankFormatter::FormatKeywords TryToSanitizeHtmlList(l); } text_os.AddParagraph(l, keys.GetObject()); + + text_os.Flush(); } @@ -599,6 +645,8 @@ void CGenbankFormatter::FormatSegment Wrap(l, "SEGMENT", CNcbiOstrstreamToString(segment_line)); text_os.AddParagraph(l, seg.GetObject()); + + text_os.Flush(); } @@ -619,6 +667,8 @@ void CGenbankFormatter::FormatSource x_FormatSourceLine(l, source); x_FormatOrganismLine(l, source); text_os.AddParagraph(l, source.GetObject()); + + text_os.Flush(); } @@ -776,6 +826,8 @@ void CGenbankFormatter::FormatReference } text_os.AddParagraph(l, ref.GetObject()); + + text_os.Flush(); } @@ -1317,6 +1369,8 @@ void CGenbankFormatter::FormatComment // s_FixLineBrokenWeblinks( l ); // } text_os.AddParagraph(l, comment.GetObject()); + + text_os.Flush(); } @@ -1338,6 +1392,8 @@ void CGenbankFormatter::FormatFeatHeader Wrap(l, "FEATURES", "Location/Qualifiers", eFeatHead); text_os.AddParagraph(l, NULL); + + text_os.Flush(); } // ============================================================================ @@ -1435,8 +1491,10 @@ bool s_GetLinkFeatureKey( strLink += NStr::IntToString(iTo); } else if (strRawKey != "Precursor") { - // TODO: this fails on URLs that require "?itemID=" (e.g. almost any, such as U54469) - strLink += "?itemid=TBD"; + strLink += "?itemid="; + string tbd = CFlatSeqLoc(item.GetFeat().GetLocation(), *item.GetContext(), + CFlatSeqLoc::eType_assembly, true).GetString(); + strLink += tbd; } strLink += "\">"; @@ -1455,10 +1513,15 @@ public: { Append(CTempString(s)); } - virtual void Append(const CTempString& s) - { - m_text_os.AddLine(NStr::TruncateSpaces_Unsafe(s, NStr::eTrunc_End)); - } + virtual void Append(const CTempString& s) + { + CTempString t = NStr::TruncateSpaces_Unsafe(s, NStr::eTrunc_End); + if (t.find_first_not_of(" ") == NPOS && s.size() == 22) { + t = s; + t.erase(21); + } + m_text_os.AddLine(t); + } }; void CGenbankFormatter::x_SmartWrapQuals(const CFeatureItemBase& feat, const CFlatFeature& ff, IFlatTextOStream& text_os) @@ -1590,8 +1653,8 @@ void CGenbankFormatter::FormatFeature if (f.GetContext()->IsProt()) { } else if (f.GetContext()->IsRefSeq()) { } else if (f.GetContext()->Config().IsModeEntrez() || f.GetContext()->Config().IsModeRelease()) { - fkey = "misc_feature"; - } + // fkey = "misc_feature"; + } } // write and in HTML mode if (bHtml && f.GetContext()->Config().IsModeEntrez() && f.GetContext()->Config().ShowSeqSpans()) { @@ -1630,6 +1693,8 @@ void CGenbankFormatter::FormatFeature // close the , without an endline text_os->AddLine("", 0, IFlatTextOStream::eAddNewline_No ); } + + text_os->Flush(); } @@ -1659,6 +1724,8 @@ void CGenbankFormatter::FormatBasecount } Wrap(l, "BASE COUNT", CNcbiOstrstreamToString(bc_line)); text_os.AddParagraph(l, bc.GetObject()); + + text_os.Flush(); } @@ -1953,6 +2020,8 @@ void CGenbankFormatter::FormatSequence } } } + + text_os.Flush(); } @@ -1988,6 +2057,8 @@ void CGenbankFormatter::FormatDBSource text_os.AddParagraph(l, dbs.GetObject()); } } + + text_os.Flush(); } @@ -2073,6 +2144,8 @@ void CGenbankFormatter::FormatWGS Wrap( l, tag, wgs_line, ePara, bHtml ); text_os.AddParagraph(l, wgs.GetObject()); + + text_os.Flush(); } /////////////////////////////////////////////////////////////////////////// @@ -2120,6 +2193,8 @@ void CGenbankFormatter::FormatTSA text_os.AddParagraph(l, tsa.GetObject()); + text_os.Flush(); + return; } @@ -2154,6 +2229,8 @@ void CGenbankFormatter::FormatTSA Wrap(l, "TSA", id_range, ePara, bHtml); text_os.AddParagraph(l, tsa.GetObject()); + + text_os.Flush(); } @@ -2178,6 +2255,8 @@ void CGenbankFormatter::FormatPrimary Wrap(l, "PRIMARY", primary_str); text_os.AddParagraph(l, primary.GetObject()); + + text_os.Flush(); } @@ -2219,6 +2298,8 @@ void CGenbankFormatter::FormatContig Wrap(l, "CONTIG", assembly); text_os.AddParagraph(l, contig.GetObject()); + + text_os.Flush(); } @@ -2253,6 +2334,8 @@ void CGenbankFormatter::FormatOrigin Wrap( l, "ORIGIN", strOrigin ); } text_os.AddParagraph( l, origin.GetObject() ); + + text_os.Flush(); } @@ -2329,6 +2412,8 @@ void CGenbankFormatter::FormatGap(const CGapItem& gap, IFlatTextOStream& orig_te text_os.AddParagraph(l, gap.GetObject()); + text_os.Flush(); + // gaps don't use the span stuff, but I'm leaving this code here // (but commented out) in case that changes in the future. diff --git a/c++/src/objtools/format/genbank_gather.cpp b/c++/src/objtools/format/genbank_gather.cpp index 44894951..a8696f29 100644 --- a/c++/src/objtools/format/genbank_gather.cpp +++ b/c++/src/objtools/format/genbank_gather.cpp @@ -1,4 +1,4 @@ -/* $Id: genbank_gather.cpp 500338 2016-05-03 23:56:29Z kans $ +/* $Id: genbank_gather.cpp 531965 2017-03-30 17:12:21Z bollin $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -204,7 +204,7 @@ void CGenbankGatherer::x_DoSingleSection(CBioseqContext& ctx) const if ( cfg.ShowContigFeatures() ) { GATHER_VIA_FUNC(FeatAndGap, x_GatherFeatures); } - else if ( cfg.IsModeEntrez() ) { + else if ( cfg.IsModeEntrez() && m_Current->GetLocation().IsWhole()) { size_t size = sequence::GetLength( m_Current->GetLocation(), &m_Current->GetScope() ); if ( size <= cfg.SMARTFEATLIMIT ) { GATHER_VIA_FUNC(FeatAndGap, x_GatherFeatures); diff --git a/c++/src/objtools/format/gene_finder.cpp b/c++/src/objtools/format/gene_finder.cpp index ce40026a..4eeadbe2 100644 --- a/c++/src/objtools/format/gene_finder.cpp +++ b/c++/src/objtools/format/gene_finder.cpp @@ -1,4 +1,4 @@ -/* $Id: gene_finder.cpp 510811 2016-08-16 14:54:08Z ivanov $ +/* $Id: gene_finder.cpp 522410 2016-12-19 17:39:06Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -325,7 +325,7 @@ void CGeneFinder::GetAssociatedGeneInfo( case CSeqFeatData::eSubtype_sig_peptide_aa: case CSeqFeatData::eSubtype_transit_peptide_aa: case CSeqFeatData::eSubtype_preprotein: - case CSeqFeatData::eSubtype_propeptide: + case CSeqFeatData::eSubtype_propeptide_aa: also_look_at_parent_CDS = true; break; default: diff --git a/c++/src/objtools/format/gff3_formatter.cpp b/c++/src/objtools/format/gff3_formatter.cpp deleted file mode 100644 index 2575ef2e..00000000 --- a/c++/src/objtools/format/gff3_formatter.cpp +++ /dev/null @@ -1,949 +0,0 @@ -/* $Id: gff3_formatter.cpp 435421 2014-05-15 19:29:47Z ucko $ -* =========================================================================== -* -* PUBLIC DOMAIN NOTICE -* National Center for Biotechnology Information -* -* This software/database is a "United States Government Work" under the -* terms of the United States Copyright Act. It was written as part of -* the author's official duties as a United States Government employee and -* thus cannot be copyrighted. This software/database is freely available -* to the public for use. The National Library of Medicine and the U.S. -* Government have not placed any restriction on its use or reproduction. -* -* Although all reasonable efforts have been taken to ensure the accuracy -* and reliability of the software and data, the NLM and the U.S. -* Government do not and cannot warrant the performance or results that -* may be obtained by using this software or data. The NLM and the U.S. -* Government disclaim all warranties, express or implied, including -* warranties of performance, merchantability or fitness for any particular -* purpose. -* -* Please cite the author in any work or product based on this material. -* -* =========================================================================== -* -* Author: Aaron Ucko -* -* File Description: -* Flat formatter for Generic Feature Format version 3. -* (See http://song.sourceforge.net/gff3-jan04.shtml .) -* -* =========================================================================== -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define NCBI_USE_ERRCODE_X Objtools_Fmt_GFF - -//#define GFF3_USE_CIGAR_FORMATTER 1 - - -BEGIN_NCBI_SCOPE -BEGIN_SCOPE(objects) -USING_SCOPE(sequence); - - -static const string& s_GetMatchType( - const CSeq_id& ref_id, const CSeq_id& tgt_id, - bool flybase) -{ - static const string kMatch = "match"; // generic match - static const string kEST = "EST_match"; - static const string kcDNA = "cDNA_match"; - static const string kProt = "protein_match"; - static const string kTransNuc = "translated_nucleotide_match"; - static const string kNucToProt = "nucleotide_to_protein_match"; - - CSeq_id::EAccessionInfo ref_info = ref_id.IdentifyAccession(); - CSeq_id::EAccessionInfo tgt_info = tgt_id.IdentifyAccession(); - if (flybase) { - if ((ref_info & CSeq_id::fAcc_prot) || (tgt_info & CSeq_id::fAcc_prot)) { - return kNucToProt; // NOT a valid SOFA term!!! - } else if (((ref_info & CSeq_id::eAcc_division_mask) == CSeq_id::eAcc_est) || - ((tgt_info & CSeq_id::eAcc_division_mask) == CSeq_id::eAcc_est)) { - return kEST; - } - // HACK HACK HACK - // we should provide a check for cDNA and retuen kMatch as the default. - return kcDNA; - } - // Rules according to GFF3 specifications using a more strict - // interpretation. If we can't reliably tell the kind of match, - // then don't add possibly incorrect levels of detail. - // Note how none of these categorizations currently in SOFA - // state anything about the reference side of the alignment! - if ( tgt_info & CSeq_id::fAcc_prot ) { - return kProt; // "A match against a protein sequence." - } - if ( (tgt_info & CSeq_id::eAcc_division_mask) == CSeq_id::eAcc_est) { - return kEST; // "A match against an EST sequence." - } - if ( ref_info & CSeq_id::fAcc_prot && ! (tgt_info & CSeq_id::fAcc_prot) ) { - return kTransNuc; // "A match against a translated sequence." - } - // Should check for more refined categorization. - return kMatch; -} - - -class CGFF3_CIGAR_Formatter : public CCIGAR_Formatter -{ -public: - CGFF3_CIGAR_Formatter(CGFF3_Formatter& gff3, - const CAlignmentItem& aln, - IFlatTextOStream& text_os); - -protected: - virtual void EndRows(void); - virtual void EndSubAlignment(void); - virtual void StartRow(void); - virtual void AddRow(const string& cigar); - virtual void EndRow(void); - virtual void AddSegment(CNcbiOstream& cigar, - char seg_type, - TSeqPos seg_len); - -private: - const CAlignmentItem& m_Alignment; - IFlatTextOStream& m_Out; - CGFF3_Formatter& m_GFF3_Fmt; - auto_ptr m_Attrs; - list m_Lines; -}; - - -CGFF3_CIGAR_Formatter::CGFF3_CIGAR_Formatter(CGFF3_Formatter& gff3, - const CAlignmentItem& aln, - IFlatTextOStream& text_os) - : CCIGAR_Formatter(aln.GetAlign(), - &aln.GetContext()->GetScope()), - m_Alignment(aln), - m_Out(text_os), - m_GFF3_Fmt(gff3), - m_Attrs(new CNcbiOstrstream) -{ -} - - -void CGFF3_CIGAR_Formatter::EndSubAlignment(void) -{ -} - - -void CGFF3_CIGAR_Formatter::StartRow(void) -{ - const CFlatFileConfig& config = m_Alignment.GetContext()->Config(); - - // We can't use x_FormatAttr because we seem to need a mix - // of literal pluses, which we otherwise avoid due to ambiguity, - // as well as two kinds of escapes for spaces, one with pluses, - // and one with %09. Really. Read the GFF3 specs. :-/ - if ( config.GffGenerateIdTags() ) { - *m_Attrs << "ID=" << m_GFF3_Fmt.m_CurrentId << ";"; - } - *m_Attrs << "Target="; - // GFF3 specs require %09 escape for spaces in the Target, - // not + or any other! - CGFF3_Formatter::x_AppendEncoded(*m_Attrs, - GetTargetId().GetSeqIdString(true), "%09"); - // We are allowed spaces here, so we'll make use of them. - // It's more pleasing to the eye. - *m_Attrs << ' ' << (GetTargetRange().GetFrom() + 1) << ' ' - << (GetTargetRange().GetTo() + 1); - - /// - /// HACK HACK HACK - /// optional strand on the end - if (GetTargetSign() == 1) { - // By prior versions of GFF3 specs (current is 1.14), - // + had special meaning (as a space), wheras - didn't. - // That made + ambiguous. However, even if interpreted as - // a space, the strand default to positive, so it's not - // a problem. - // - // DETAILS: - // In older versions of the specs, they discussed URL encoding, - // specifically mentionned + as space. In subsequent versions, - // + was explicitly listed amongst the allowable characters - // for the Seqid column. I believe the issue arised from - // confusion between URL encoding (which only does % escaping) - // vs application/x-www-form-urlencoded which is similar, - // but adds things like + to represent spaces. - *m_Attrs << " +"; - } else { - // A minus is unambiguous. So, the only question is, - // do we escape the space? Hmmm... "+-" looks strange (and - // likely wrong, given discussion above about confusion with - // URL Encoding in GFF3 specs), and things like "%09%2D" - // are totally ugly. - *m_Attrs << " -"; - } -} - - -void CGFF3_CIGAR_Formatter::AddRow(const string& cigar) -{ - if ( !IsTrivial() || GetLastType() != 'M' ) { - *m_Attrs << ";Gap=" << cigar; - } -} - - -void CGFF3_CIGAR_Formatter::EndRow(void) -{ - CBioseqContext& ctx = *m_Alignment.GetContext(); - // XXX - should supply appropriate score, if any - CSeq_loc loc(*ctx.GetPrimaryId(), - GetRefRange().GetFrom(), GetRefRange().GetTo(), - (GetRefSign() == 1 ? eNa_strand_plus - : eNa_strand_minus)); - - // HACK HACK HACK - // add score attributes - const CSeq_align& seq_align = GetSeq_align(); - if (IsFirstSubalign() && seq_align.IsSetScore()) { - ITERATE (CDense_seg::TScores, score_it, seq_align.GetScore()) { - const CScore& score = **score_it; - if (score.IsSetId() && score.GetId().IsStr() && score.IsSetValue()) { - *m_Attrs << ';'; - // Not one of the special cases of escaping, so space ok. - CGFF3_Formatter::x_AppendEncoded( - *m_Attrs, score.GetId().GetStr(), " "); - *m_Attrs << '='; - if (score.GetValue().IsInt()) { - *m_Attrs << score.GetValue().GetInt(); - } else { - *m_Attrs << score.GetValue().GetReal(); - } - } - } - } - - // HACK HACK HACK - // add score attributes - const CDense_seg& ds = GetDense_seg(); - if (ds.IsSetScores()) { - ITERATE (CDense_seg::TScores, score_it, ds.GetScores()) { - const CScore& score = **score_it; - if (score.IsSetId() && score.GetId().IsStr() && score.IsSetValue()) { - *m_Attrs << ';'; - // Not one of the special cases of escaping, so space ok. - CGFF3_Formatter::x_AppendEncoded( - *m_Attrs, score.GetId().GetStr(), " "); - *m_Attrs << '='; - if (score.GetValue().IsInt()) { - *m_Attrs << score.GetValue().GetInt(); - } else { - *m_Attrs << score.GetValue().GetReal(); - } - } - } - } - - string attr_string = CNcbiOstrstreamToString(*m_Attrs); - m_Attrs.reset(new CNcbiOstrstream); - - // Phase has a different interpretation in GFF3 for Flybase. - // Seriously. Adjust the phase for display, as appropriate. - // Note that the API expects frame, which is not the same as - // the phase, and it also wants that frame to be 0-based, with - // values 0, 1, 2, or -1 for undefined, which is not the same - // as the frame in ASN.1. Confused? Convert as appropriate. - string source = m_GFF3_Fmt.x_GetSourceName(ctx); - const CFlatFileConfig& config = ctx.Config(); - int frame = GetFrame(); - m_GFF3_Fmt.x_AddFeature(m_Lines, loc, source, - s_GetMatchType(GetRefId(), GetTargetId(), config.GffForFlybase()), - "." /*score*/, - config.GffForFlybase() ? - /* frame vs phase inverted for flybase! */ - (frame > 0 ? 3 - frame : frame) - /* frame for everybody else... undefined! */ - : -1, - attr_string, false /*gtf*/, ctx); -} - - -void CGFF3_CIGAR_Formatter::EndRows(void) -{ - m_Out.AddParagraph(m_Lines, &GetDense_seg()); - m_Lines.clear(); -} - - -void CGFF3_CIGAR_Formatter::AddSegment(CNcbiOstream& cigar, - char seg_type, - TSeqPos seg_len) -{ - // In GFF3 type and length are swapped and '+' is used between segments - if ( cigar.tellp() > 0) { - cigar << '+'; - } - cigar << seg_type << seg_len; -} - - -void CGFF3_Formatter::Start(IFlatTextOStream& text_os) -{ - list l; - // The GFF version is rquired to be 3, with no minor revisions. - // This is unfortunate, since there are multiple revisions of the - // specifications (up to GFF3 specs version 1.14 as of 6/5/2009), - // and some of them hav minor differences of significance, - // such as refinement of allowable character code vs escape. - // - // Also, there are at least 3 flavours of GFF3, discounting multiple - // versions of each: - // - "Official specifications" by the Sequence Ontology group (SO), - // see http://www.sequenceontology.org/gff3.shtml - // - GFF3 as modified by the Interoperability Working Group (IOWG), - // see http://www.pathogenportal.org/gff3-usage-conventions.html - // - GFF3 as modified for exchange with Flybase. This alters - // such critical information as how phase is represented. - // - l.push_back("##gff-version 3"); - - // Add unofficial "metadata". According to GFF3 specifications (v1.15), - // lines preceeded by ## are metadata or directives. However, according - // to the de-facto standard of BioPerl's implementation, there are - // only directives, no metadata, with the directives using a controlled - // vocabulary, and it is an error to use an unsupported directive. - // - // Thus, we are forced to use comment lines instead (# followed by - // any character other than #). To distinguish true comments from - // metadata we wish to emit, we are free to adopt our own conventions. - // That is, comments do not have any enforced structure according to - // GFF3 specifications. Arbitrarily, we adopt #! to indicate such - // metadata-as-comments. - // - // Also, not that a comment may NOT be empty, according to BioPerl. - // (Regexp used is /^#[^#]/ which requires 2 characters.) - // - // @see _handle_directive and next_feature in - // svn://code.open-bio.org/bioperl/bioperl-live/trunk/Bio/FeatureIO/gff.pm - - l.push_back("#!gff-spec-version 1.14"); // A comment, not a directive. - if ( GetContext().GetConfig().GffForFlybase() ) { - l.push_back("#!gff-variant flybase"); // A comment, not a directive. - l.push_back("# This variant of GFF3 interprets ambiguities in the"); - l.push_back("# GFF3 specifications in accordance with the views of Flybase."); - l.push_back("# This impacts the feature tag set, and meaning of the phase."); - } - // All comments, not a directives. - l.push_back("#!source-version NCBI C++ formatter 0.2"); -// l.push_back("#!date " + CurrentTime().AsString("Y-M-D")); - text_os.AddParagraph(l); -} - -void CGFF3_Formatter::EndSection(const CEndSectionItem&, - IFlatTextOStream& text_os) -{ - list l; - l.push_back("###"); - text_os.AddParagraph(l); -} - - -void CGFF3_Formatter::FormatAlignment(const CAlignmentItem& aln, - IFlatTextOStream& text_os) -{ -#ifdef GFF3_USE_CIGAR_FORMATTER - CGFF3_CIGAR_Formatter cigar(*this, aln, text_os); - cigar.FormatByReferenceId(*aln.GetContext()->GetPrimaryId()); -#else - x_FormatAlignment(aln, text_os, aln.GetAlign(), true, false); - if ( aln.GetContext()->Config().GffGenerateIdTags() ) { - ++m_CurrentId; - } -#endif -} - -void CGFF3_Formatter::x_FormatAlignment(const CAlignmentItem& aln, - IFlatTextOStream& text_os, - const CSeq_align& sa, - bool first, - bool width_inverted) -{ - //const CFlatFileConfig& config = aln.GetContext()->Config(); - - switch (sa.GetSegs().Which()) { - case CSeq_align::TSegs::e_Denseg: - x_FormatDenseg(aln, text_os, sa.GetSegs().GetDenseg(), - first, width_inverted); - break; - - case CSeq_align::TSegs::e_Spliced: - { - CRef sa2; - try { - sa2 = sa.GetSegs().GetSpliced().AsDiscSeg(); - if (sa.IsSetScore()) { - sa2->SetScore().insert(sa2->SetScore().end(), - sa.GetScore().begin(), - sa.GetScore().end()); - } - } STD_CATCH_ALL_X(4, "CGFF3_Formatter::x_FormatAlignment") - if (sa2) { - // HACK HACK HACK WORKAROUND - // Conversion from Spliced to Disc inverts meaning of width!!! - x_FormatAlignment(aln, text_os, *sa2, first, true); - } - break; - } - - case CSeq_align::TSegs::e_Std: - { - CRef sa2; - try { - sa2 = sa.CreateDensegFromStdseg(); - } STD_CATCH_ALL_X(4, "CGFF3_Formatter::x_FormatAlignment") - if (sa2.NotEmpty() && sa2->GetSegs().IsDenseg()) { - x_FormatDenseg(aln, text_os, sa2->GetSegs().GetDenseg(), - first, width_inverted); - } - break; - } - - case CSeq_align::TSegs::e_Disc: - { - ITERATE (CSeq_align_set::Tdata, it, sa.GetSegs().GetDisc().Get()) { - x_FormatAlignment(aln, text_os, **it, - first, width_inverted); - first = false; - } - break; - } - - default: // dendiag or packed; unsupported - NCBI_THROW(CFlatException, eNotSupported, - "Conversion of alignments of type dendiag and packed " - "not supported in current GFF3 CIGAR output"); - } -} - - -static CConstRef s_GetTargetId(const CSeq_id& id, CScope& scope) -{ - try { - return sequence::GetId(id, scope, sequence::eGetId_ForceAcc).GetSeqId(); - } - catch (CException&) { - } - return CConstRef(&id); -} - - -void CGFF3_Formatter::x_FormatDenseg(const CAlignmentItem& aln, - IFlatTextOStream& text_os, - const CDense_seg& ds, - bool first, - bool width_inverted) -{ - // cerr << "DENSEG:\n" << MSerial_AsnText << ds << endl; - - // Frame, as a value of 0, 1, 2, or -1 for undefined. - // This is NOT the same frame as the frame in ASN.1! - int frame(-1); - - // HACK HACK HACK WORKAROUND - // I do believe there is lack of agreement on what - // the "widths" of a dense-seg mean -- as multiplier, or as divisor. - // - // In CSpliced_seg::s_ExonToDenseg, the widths act as divisors, - // i.e. width 3 means every 3 units (na) in the alignment - // correspond to 1 unit (aa) on the sequence. - // - // In CAlnMix as witnessed by e.g. x_ExtendDSWithWidths, - // or even CDense_seg::Validate, the widths are a multiplier, - // i.e. width 3 means every 1 unit (aa) in the alignment - // corresponds to an alignment of 3 units (na) on the sequence. - // - // These definitions are incompatible. - // The problem with the latter definition as a multiplier, - // is that the smallest unit of alignment (in a protein-to-nucleotide) - // is 1 aa = 3 bp... no opportunity for a frameshift. :-( - // - // To compensate (or rather, avoid double-compentating), avoid use - // of widths, and copy to a temporary alignment, storing the old widths - // for lookup, but reset them in the temporary alignment. - - CRef ds_filled = ds.FillUnaligned(); //keep ds_for_alnmix - // alive through scope! - const CDense_seg* ds_for_alnmix = ds_filled.GetNCPointerOrNull(); - if ( 0 == ds_for_alnmix ) { - ds_for_alnmix = &ds; - } - CDense_seg ds_no_widths; - if (width_inverted) { - ds_no_widths.Assign(*ds_for_alnmix); - ds_no_widths.ResetWidths(); - ds_for_alnmix = &ds_no_widths; - } - - typedef CAlnMap::TNumrow TNumrow; - typedef CAlnMap::TNumchunk TNumchunk; - typedef CAlnMap::TSignedRange TRange; - - CBioseqContext* ctx = aln.GetContext(); - list l; - string source = x_GetSourceName(*ctx); - CAlnMap alnmap(*ds_for_alnmix); - TNumrow ref_row = -1; - CScope& scope = ctx->GetScope(); - const CFlatFileConfig& config = ctx->Config(); - - const CSeq_id& ref_id = *ctx->GetPrimaryId(); - for (TNumrow row = 0; row < alnmap.GetNumRows(); ++row) { - if (sequence::IsSameBioseq(alnmap.GetSeqId(row), ref_id, &scope)) { - ref_row = row; - break; - } - } - if (ref_row < 0) { - ERR_POST_X(3, "CGFF3_Formatter::FormatAlignment: " - "no row with a matching ID found!"); - return; - } - - TSeqPos ref_width = - (static_cast(ref_row) < ds.GetWidths().size()) ? - ds.GetWidths()[ref_row] : 1; - - TSeqPos ref_start(0); - int ref_sign = alnmap.StrandSign(ref_row); - for (TNumrow tgt_row = 0; tgt_row < alnmap.GetNumRows(); ++tgt_row) { - if (tgt_row == ref_row) { - continue; - } - CNcbiOstrstream cigar; - TSeqPos tgt_width = - (static_cast(tgt_row) < ds.GetWidths().size()) ? - ds.GetWidths()[tgt_row] : 1; - int tgt_sign = alnmap.StrandSign(tgt_row); - TRange ref_range, tgt_range; - bool trivial = true; - - if (! width_inverted && (ref_width != 1 || tgt_width != 1)) { - // Supporting widths ONLY in the unamiguous case when we - // know they are WRONG and put there incorrectly from conversion - // from Spliced-seg. If we didn't get widths that way, we don't - // know what they mean, so punt if not all widths are 1. - NCBI_THROW(CFlatException, eNotSupported, - "Widths in alignments do not have clear semantics, " - "and thus are not supported in current GFF3 CIGAR output"); - } - - // HACK HACK HACK - // Is the following correct??? - // - // Expecting all coordinates to be normalized relative to - // some reference width, which might be the - // Least Common Multiple of length in nucleotide bases of - // the coordinate system used for each row, e.g. using - // LCM of 3 if either row is protein. The Least Common Multiple - // would allow accurately representing frameshifts in either - // sequence. - // - // What does width for an alignment really mean, biologically? - // It can't have arbitrary meaning, because CIGAR has fixed - // semantics that M/I/D/F/R are in 3-bp units (i.e. one aa) for - // proteins and 1-bp units for cDNA. - // - // Thus, in practice, I think we are expecting widths to be - // one of (1, 1) for nuc-nuc, (1, 3) for nuc-prot, - // (3, 1) for prot-nuc, and (3, 3) for prot-prot. - TSeqPos width = max(ref_width, tgt_width); - - for (TNumchunk i0 = 0; i0 < alnmap.GetNumSegs(); ++i0) { - TRange ref_piece = alnmap.GetRange(ref_row, i0); - TRange tgt_piece = alnmap.GetRange(tgt_row, i0); - CAlnMap::TSegTypeFlags ref_flags = alnmap.GetSegType(ref_row, i0); - CAlnMap::TSegTypeFlags tgt_flags = alnmap.GetSegType(tgt_row, i0); - - //The type and count are guaranteed set by one of the if/else cases below. - char type = 'X'; // Guaranteed set. Pacify compiler. - TSeqPos count = 0; // Guaranteed set. Pacify compiler. - TSignedSeqPos frameshift = 0; - - // cerr << "TARGET PIECE " << tgt_piece.GetFrom() - // << " to " << tgt_piece.GetTo() << endl; - // cerr << "REF PIECE " << ref_piece.GetFrom() << " to " << ref_piece.GetTo() - // << " + " << ref_start << "\n" << endl; - - if ( (tgt_flags & CAlnMap::fSeq) && - ! (ref_flags & CAlnMap::fSeq)) { - // See MakeGapString() in: - // /panfs/pan1.be-md.ncbi.nlm.nih.gov/gpipe/ThirdParty/ProSplignForFlyBase/production/prosplign2gff3 - // - // elif starts[2 * i] == -1: - // # gap in prot - // if (starts[2 * (i - 1)] + lens[i - 1]) % 3 and i != 0: - // raise 'non-initial prot gap does not start on aa boundary' - // if seg_len / 3: - // l.append('I%d' % (seg_len / 3)) - // if seg_len % 3: - // l.append('R%d' % (seg_len % 3)) - // - // TODO: Handle non-initial protein gap that does not start - // on an aa boundary. - // - type = 'I'; - if (i0 == 0 && config.GffForFlybase() && tgt_width == 3) { - // See comments about frame and phase, below. - frame = (tgt_piece.GetFrom() ) % tgt_width; - } - count = tgt_piece.GetLength() / width; - frameshift = -(TSignedSeqPos)(tgt_piece.GetLength() % width); - tgt_piece.SetFrom(tgt_piece.GetFrom() / tgt_width); - tgt_piece.SetTo (tgt_piece.GetTo() / tgt_width); - tgt_range += tgt_piece; - - } else if (! (tgt_flags & CAlnMap::fSeq) && - (ref_flags & CAlnMap::fSeq)) { - - // See MakeGapString() in: - // /panfs/pan1.be-md.ncbi.nlm.nih.gov/gpipe/ThirdParty/ProSplignForFlyBase/production/prosplign2gff3 - // - // else: - // # gap in nuc - // if starts[2 * i] % 3: - // raise 'nuc gap does not start on aa boundary' - // if seg_len / 3: - // l.append('D%d' % (seg_len / 3)) - // if seg_len % 3: - // l.append('F%d' % (seg_len % 3)) - // - // TODO: Handle gap that does not start on an aa boundary. - // - type = 'D'; - if (i0 == 0 && config.GffForFlybase() && ref_width == 3) { - // See comments about frame and phase, below. - frame = (ref_piece.GetFrom() ) % ref_width; - } - count = ref_piece.GetLength() / width; - frameshift = +(ref_piece.GetLength() % width); - // Adjusting for start position, converting to natural cordinates - // (aa for protein locations, which would imply divide by 3). - ref_piece.SetFrom((ref_piece.GetFrom() + ref_start) / ref_width); - ref_piece.SetTo ((ref_piece.GetTo() + ref_start) / ref_width); - ref_range += ref_piece; - } else if ( (tgt_flags & CAlnMap::fSeq) && - (ref_flags & CAlnMap::fSeq)) { - // Hanlde case when sequences aligned. - // The remaining case is when both don't align at all, - // which shouldn't happen in a pairwise alignment. If we - // happen to have a multiple alignment, the remaining case - // would be one that aligns unrelated sequences, thus has - // no affect on the current GFF3 output. - - // See MakeGapString() in: - // /panfs/pan1.be-md.ncbi.nlm.nih.gov/gpipe/ThirdParty/ProSplignForFlyBase/production/prosplign2gff3 - // - // if starts[2 * i] != -1 and starts[2 * i + 1] != -1: - // # non-gap - // - // # for internal segs, length is easy - // if numseg != 1 and i != numseg - 1: - // # One end should be a codon boundary - // # Check this - // if starts[2 * i] % 3 != 0 and (starts[2 * i] + seg_len) % 3 != 0: - // raise 'a bad thing happened; i = %d' % i - // length = (seg_len + 2) / 3 - // else: - // # single segment or last segment - // length = (starts[2 * i] % 3 + seg_len + 2) / 3 - // l.append('M%d' % length) - // - // TODO: Resolve why the following implementation is different - // from the above historic implementation. The difference - // will be in rounding down vs up on single or last - // segment. - // - type = 'M'; - if (ref_piece.GetLength() != tgt_piece.GetLength()) { - // There's a frameshift.. somewhere. Is this valid? Bail. - NCBI_THROW(CFlatException, eNotSupported, - "Frameshift(s) in Spliced-exon-chunk's diag " - "not supported in current GFF3 CIGAR output"); - } - if (i0 == 0 && config.GffForFlybase()) { - // Semantics of the phase aren't defined in GFF3 for - // feature types other than a CDS, and this is an alignment. - // - // Since phase is not required for alignment features, don't - // emit one, unless we have been requested with the special - // Flybase variant of GFF3 -- they did ask for phase. - // - // Also, phase can only be interpreted if we have an alignment - // in terms of protein aa, and a width of 3 for one or - // the other. - // - // For an alignment, the meaning of phase is ambiguous, - // particularly in dealing with a protein-protein - // alignment (if ever it allowed alignment to parts of - // a codon), and when the seqid is the protein, rather - // than the target. - // - // A protein won't be "reverse complemented" thus, - // can assume that it's plus-strand and look at start - // position. - // - // The computation below is actually for the frame. - // The phase is not the same, and will be derived from - // the frame. - if (ref_width == 3) { - frame = (ref_piece.GetFrom() + ref_start) % ref_width; - } else if (tgt_width == 3) { - frame = (tgt_piece.GetFrom() ) % tgt_width; - } - } - // Adjusting for start position, converting to natural cordinates - // (aa for protein locations, which would imply divide by 3). - count = ref_piece.GetLength() / width; - ref_piece.SetFrom((ref_piece.GetFrom() + ref_start) / ref_width); - ref_piece.SetTo ((ref_piece.GetTo() + ref_start) / ref_width); - ref_range += ref_piece; - tgt_piece.SetFrom(tgt_piece.GetFrom() / tgt_width); - tgt_piece.SetTo (tgt_piece.GetTo() / tgt_width); - tgt_range += tgt_piece; - } - if (count) { - if ( !IsOssEmpty(cigar) ) { - trivial = false; - cigar << '+'; - } - cigar << type << count; - } - if (frameshift) { - trivial = false; - cigar << (frameshift < 0 ? 'F' : 'R') << abs(frameshift) << '+'; - } - } - // We can't use x_FormatAttr because we seem to need a mix - // of literal pluses, which we otherwise avoid due to ambiguity, - // as well as two kinds of escapes for spaces, one with pluses, - // and one with %09. Really. Read the GFF3 specs. :-/ - CNcbiOstrstream attrs; - CConstRef tgt_id = - s_GetTargetId(alnmap.GetSeqId(tgt_row), scope); - if ( config.GffGenerateIdTags() ) { - attrs << "ID=" << m_CurrentId << ";"; - } - attrs << "Target="; - // GFF3 specs require %09 escape for spaces in the Target, - // not + or any other! - x_AppendEncoded(attrs, tgt_id->GetSeqIdString(true), "%09"); - // We are allowed spaces here, so we'll make use of them. - // It's more pleasing to the eye. - attrs << ' ' << (tgt_range.GetFrom() + 1) << ' ' - << (tgt_range.GetTo() + 1); - - /// - /// HACK HACK HACK - /// optional strand on the end - if (tgt_sign == 1) { - // By prior versions of GFF3 specs (current is 1.14), - // + had special meaning (as a space), wheras - didn't. - // That made + ambiguous. However, even if interpreted as - // a space, the strand default to positive, so it's not - // a problem. - // - // DETAILS: - // In older versions of the specs, they discussed URL encoding, - // specifically mentionned + as space. In subsequent versions, - // + was explicitly listed amongst the allowable characters - // for the Seqid column. I believe the issue arised from - // confusion between URL encoding (which only does % escaping) - // vs application/x-www-form-urlencoded which is similar, - // but adds things like + to represent spaces. - attrs << " +"; - } else { - // A minus is unambiguous. So, the only question is, - // do we escape the space? Hmmm... "+-" looks strange (and - // likely wrong, given discussion above about confusion with - // URL Encoding in GFF3 specs), and things like "%09%2D" - // are totally ugly. - attrs << " -"; - } - - if ( !trivial ) { - string cigar_string = CNcbiOstrstreamToString(cigar); - attrs << ";Gap=" << cigar_string; - } - // XXX - should supply appropriate score, if any - CSeq_loc loc(*ctx->GetPrimaryId(), - ref_range.GetFrom(), ref_range.GetTo(), - (ref_sign == 1 ? eNa_strand_plus - : eNa_strand_minus)); - - // HACK HACK HACK - // add score attributes - if (first && aln.GetAlign().IsSetScore()) { - ITERATE (CDense_seg::TScores, score_it, aln.GetAlign().GetScore()) { - const CScore& score = **score_it; - if (score.IsSetId() && score.GetId().IsStr() && score.IsSetValue()) { - attrs << ';'; - // Not one of the special cases of escaping, so space ok. - x_AppendEncoded(attrs, score.GetId().GetStr(), " "); - attrs << '='; - if (score.GetValue().IsInt()) { - attrs << score.GetValue().GetInt(); - } else { - attrs << score.GetValue().GetReal(); - } - } - } - } - - // HACK HACK HACK - // add score attributes - string score_text("."); - if (ds.IsSetScores()) { - ITERATE (CDense_seg::TScores, score_it, ds.GetScores()) { - const CScore& score = **score_it; - if (score.IsSetId() && score.GetId().IsStr() && score.IsSetValue()) { - if (score.GetId().GetStr() == "score") { - // The generic 'score' score, if present, - // goes to the 6th column. - if (score.GetValue().IsInt()) { - score_text = NStr::IntToString(score.GetValue().GetInt()); - } else { - score_text = NStr::DoubleToString(score.GetValue().GetReal()); - } - } else { - attrs << ';'; - // Not one of the special cases of escaping, so space ok. - x_AppendEncoded(attrs, score.GetId().GetStr(), " "); - attrs << '='; - if (score.GetValue().IsInt()) { - attrs << score.GetValue().GetInt(); - } else { - attrs << score.GetValue().GetReal(); - } - } - } - } - } - - string attr_string = CNcbiOstrstreamToString(attrs); - - // Phase has a different interpretation in GFF3 for Flybase. - // Seriously. Adjust the phase for display, as appropriate. - // Note that the API expects frame, which is not the same as - // the phase, and it also wants that frame to be 0-based, with - // values 0, 1, 2, or -1 for undefined, which is not the same - // as the frame in ASN.1. Confused? Convert as appropriate. - x_AddFeature(l, loc, source, - s_GetMatchType(ref_id, *tgt_id, config.GffForFlybase()), - score_text, - config.GffForFlybase() ? - /* frame vs phase inverted for flybase! */ - (frame > 0 ? 3 - frame : frame) - /* frame for everybody else... undefined! */ - : -1, - attr_string, false /*gtf*/, *ctx); - } - text_os.AddParagraph(l, &ds); -} - - -string CGFF3_Formatter::x_FormatAttr(const string& name, const string& value) - const -{ - CNcbiOstrstream oss; - oss << name << '='; - // Not one of the special cases of escaping, so space ok. - x_AppendEncoded(oss, value, " "); - return CNcbiOstrstreamToString(oss); -} - - -void CGFF3_Formatter::x_AddGeneID(list& attr_list, - const string& gene_id, - const string& transcript_id) const -{ - if (transcript_id.empty()) { - attr_list.push_front(x_FormatAttr("ID", gene_id)); - } else { - attr_list.push_front(x_FormatAttr("Parent", gene_id)); - attr_list.push_front(x_FormatAttr("ID", transcript_id)); - } -} - - -CNcbiOstream& CGFF3_Formatter::x_AppendEncoded(CNcbiOstream& os, - const string& s, - const char* space) -{ - // Encode space as %20 rather than +, whose status is ambiguous. - // Officially, [a-zA-Z0-9.:^*$@!+_?-|] are okay, but we punt [*+?] - // to be extra safe. - static const char s_Table[256][4] = { - "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", - "%08", "%09", "%0A", "%0B", "%0C", "%0D", "%0E", "%0F", - "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", - "%18", "%19", "%1A", "%1B", "%1C", "%1D", "%1E", "%1F", - "%20", "!", "%22", "%23", "$", "%25", "%26", "%27", - "%28", "%29", "%2A", "%2B", "%2C", "-", ".", "%2F", - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", ":", "%3B", "%3C", "%3D", "%3E", "%3F", - "@", "A", "B", "C", "D", "E", "F", "G", - "H", "I", "J", "K", "L", "M", "N", "O", - "P", "Q", "R", "S", "T", "U", "V", "W", - "X", "Y", "Z", "%5B", "%5C", "%5D", "^", "_", - "%60", "a", "b", "c", "d", "e", "f", "g", - "h", "i", "j", "k", "l", "m", "n", "o", - "p", "q", "r", "s", "t", "u", "v", "w", - "x", "y", "z", "%7B", "%7C", "%7D", "%7E", "%7F", - "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87", - "%88", "%89", "%8A", "%8B", "%8C", "%8D", "%8E", "%8F", - "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97", - "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F", - "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7", - "%A8", "%A9", "%AA", "%AB", "%AC", "%AD", "%AE", "%AF", - "%B0", "%B1", "%B2", "%B3", "%B4", "%B5", "%B6", "%B7", - "%B8", "%B9", "%BA", "%BB", "%BC", "%BD", "%BE", "%BF", - "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7", - "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF", - "%D0", "%D1", "%D2", "%D3", "%D4", "%D5", "%D6", "%D7", - "%D8", "%D9", "%DA", "%DB", "%DC", "%DD", "%DE", "%DF", - "%E0", "%E1", "%E2", "%E3", "%E4", "%E5", "%E6", "%E7", - "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF", - "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7", - "%F8", "%F9", "%FA", "%FB", "|", "%FD", "%FE", "%FF" - }; - for (SIZE_TYPE i = 0; i < s.size(); ++i) { - if (s[i] == ' ') { - os << space; - } else { - os << s_Table[static_cast(s[i])]; - } - } - return os; -} - - -END_SCOPE(objects) -END_NCBI_SCOPE diff --git a/c++/src/objtools/format/gff_formatter.cpp b/c++/src/objtools/format/gff_formatter.cpp deleted file mode 100644 index c43f47a8..00000000 --- a/c++/src/objtools/format/gff_formatter.cpp +++ /dev/null @@ -1,591 +0,0 @@ -/* $Id: gff_formatter.cpp 346734 2011-12-09 16:04:28Z ivanov $ -* =========================================================================== -* -* PUBLIC DOMAIN NOTICE -* National Center for Biotechnology Information -* -* This software/database is a "United States Government Work" under the -* terms of the United States Copyright Act. It was written as part of -* the author's official duties as a United States Government employee and -* thus cannot be copyrighted. This software/database is freely available -* to the public for use. The National Library of Medicine and the U.S. -* Government have not placed any restriction on its use or reproduction. -* -* Although all reasonable efforts have been taken to ensure the accuracy -* and reliability of the software and data, the NLM and the U.S. -* Government do not and cannot warrant the performance or results that -* may be obtained by using this software or data. The NLM and the U.S. -* Government disclaim all warranties, express or implied, including -* warranties of performance, merchantability or fitness for any particular -* purpose. -* -* Please cite the author in any work or product based on this material. -* -* =========================================================================== -* -* Author: Aaron Ucko, NCBI -* Mati Shomrat -* -* File Description: -* -* -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define NCBI_USE_ERRCODE_X Objtools_Fmt_GFF - - -BEGIN_NCBI_SCOPE -BEGIN_SCOPE(objects) - - -CGFFFormatter::CGFFFormatter(void) -{ -} - - -void CGFFFormatter::Start(IFlatTextOStream& text_os) -{ - list l; - l.push_back("##gff-version 2"); - l.push_back("##source-version NCBI C++ formatter 0.3"); - text_os.AddParagraph(l); -} - - -void CGFFFormatter::StartSection(const CStartSectionItem& ssec, IFlatTextOStream& text_os) -{ - list l; - CBioseqContext& bctx = *ssec.GetContext(); - - switch (bctx.GetMol()) { - case CSeq_inst::eMol_dna: m_SeqType = "DNA"; break; - case CSeq_inst::eMol_rna: m_SeqType = "RNA"; break; - case CSeq_inst::eMol_aa: m_SeqType = "Protein"; break; - default: m_SeqType.erase(); break; - } - if ( !m_SeqType.empty() ) { - l.push_back("##Type " + m_SeqType + ' ' - + bctx.GetAccession()); - } - text_os.AddParagraph(l); -} - - -void CGFFFormatter::EndSection(const CEndSectionItem&, - IFlatTextOStream& text_os) -{ - if ( !m_EndSequence.empty() ) { - list l; - l.push_back(m_EndSequence); - text_os.AddParagraph(l); - } -} - - -void CGFFFormatter::FormatLocus -(const CLocusItem& locus, - IFlatTextOStream& text_os) -{ - m_Strandedness = locus.GetStrand(); -} - - -void CGFFFormatter::FormatDate -(const CDateItem& date, - IFlatTextOStream& text_os) -{ - m_Date.erase(); - - const CDate* d = date.GetUpdateDate(); - if ( d != 0 ) { - d->GetDate(&m_Date, "%4Y-%{%2M%|??%}-%{%2D%|??%}"); - } -} - - - -/////////////////////////////////////////////////////////////////////////// -// -// FEATURES - - -void CGFFFormatter::FormatFeature -(const CFeatureItemBase& f, - IFlatTextOStream& text_os) -{ - CMappedFeat seqfeat = f.GetFeat(); - string key(f.GetKey()), oldkey; - bool gtf = false; - CBioseqContext& ctx = *f.GetContext(); - const CFlatFileConfig& cfg = ctx.Config(); - CScope* scope = &ctx.GetScope(); - - // CSeq_loc tentative_stop; - - if (( cfg.GffGTFCompat() ) && !ctx.IsProt() - && (key == "CDS" || key == "exon")) { - gtf = true; - } else if (( cfg.GffGTFCompat() ) - && ctx.GetMol() == CSeq_inst::eMol_dna - && seqfeat.GetData().IsRna()) { - oldkey = key; - key = "exon"; - gtf = true; - } else if ( cfg.GffGTFOnly() ) { - return; - } - - CConstRef feat = f.Format(); - list l; - list attr_list; - - if ( !oldkey.empty() ) { - attr_list.push_back(x_FormatAttr("gbkey", oldkey)); - } - - ITERATE (CFlatFeature::TQuals, it, feat->GetQuals()) { - string name = (*it)->GetName(); - if (name == "codon_start" || name == "translation" - || name == "transcription") { - continue; // suppressed to reduce verbosity - } else if (name == "number" && key == "exon") { - name = "exon_number"; - } else if (( cfg.GffGTFCompat() ) && !ctx.IsProt() - && name == "gene") { - string gene_id = x_GetGeneID(*feat, (*it)->GetValue(), ctx); - string transcript_id; - if (key != "gene") { - transcript_id = x_GetTranscriptID(*feat, gene_id, ctx); - } - x_AddGeneID(attr_list, gene_id, transcript_id); - continue; - } else if (name == "transcript_id") { - name = "insd_transcript_id"; - } - attr_list.push_back(x_FormatAttr(name, (*it)->GetValue())); - } - string attrs(NStr::Join(attr_list, x_GetAttrSep())); - - string source = x_GetSourceName(ctx); - - int frame = -1; - if (seqfeat.GetData().IsCdregion() && !ctx.IsProt() ) { - const CCdregion& cds = seqfeat.GetData().GetCdregion(); - frame = max(cds.GetFrame() - 1, 0); - } - - CConstRef feat_loc(&f.GetLoc()); - CRef tentative_stop; - if (gtf && seqfeat.GetData().IsCdregion()) { - const CCdregion& cds = seqfeat.GetData().GetCdregion(); - if ( !f.GetLoc().IsPartialStop(eExtreme_Biological) && seqfeat.IsSetProduct() ) { - TSeqPos loc_len = sequence::GetLength(f.GetLoc(), scope); - TSeqPos prod_len = sequence::GetLength(seqfeat.GetProduct(), - scope); - if (loc_len >= frame + 3 * prod_len + 3) { - SRelLoc::TRange range; - range.SetFrom(frame + 3 * prod_len); - range.SetTo (frame + 3 * prod_len + 2); - // needs to be partial for TranslateCdregion to DTRT - range.SetFuzz_from().SetLim(CInt_fuzz::eLim_lt); - SRelLoc::TRanges ranges; - ranges.push_back(CRef(&range)); - tentative_stop = SRelLoc(f.GetLoc(), ranges).Resolve(scope); - } - if (tentative_stop.NotEmpty() && !tentative_stop->IsNull()) { - string s; - CCdregion_translate::TranslateCdregion - (s, ctx.GetHandle(), *tentative_stop, cds); - if (s != "*") { - tentative_stop.Reset(); - } else { - // valid stop, we may be able to trim the CDS - if (loc_len > frame + 3 * prod_len + 3) { - // truncation error - string msg("truncation error: "); - feature::GetLabel(seqfeat.GetOriginalFeature(), &msg, - feature::fFGL_Both); - msg += "; protein: "; - seqfeat.GetProduct().GetLabel(&msg); - - if (seqfeat.IsSetExcept() && - seqfeat.GetExcept()) { - msg = "warning: " + msg + - " (translation exception"; - if (seqfeat.IsSetExcept_text()) { - msg += ' ' + seqfeat.GetExcept_text(); - } - msg += ")"; - } else { - msg = "error: " + msg; - } - LOG_POST_X(1, Error << msg); - } else { - SRelLoc::TRange range; - range.SetFrom(0); - range.SetTo(frame + 3 * prod_len - 1); - SRelLoc::TRanges ranges; - ranges.push_back(CRef(&range)); - feat_loc = SRelLoc(f.GetLoc(), ranges).Resolve(scope); - } - } - } else { - tentative_stop.Reset(); - } - } - } - - x_AddFeature(l, *feat_loc, source, key, "." /*score*/, frame, attrs, - gtf, ctx, tentative_stop.NotEmpty()); - - if (gtf && seqfeat.GetData().IsCdregion()) { - const CCdregion& cds = seqfeat.GetData().GetCdregion(); - if ( !f.GetLoc().IsPartialStart(eExtreme_Biological) ) { - CRef tentative_start; - {{ - CRef range(new SRelLoc::TRange); - SRelLoc::TRanges ranges; - range->SetFrom(frame); - range->SetTo(frame + 2); - ranges.push_back(range); - tentative_start = SRelLoc(f.GetLoc(), ranges).Resolve(scope); - }} - - string s; - {{ - CSeqVector vect(*tentative_start, ctx.GetHandle().GetScope()); - vect.GetSeqData(0, 3, s); - }} - const CTrans_table* tt; - if (cds.IsSetCode()) { - tt = &CGen_code_table::GetTransTable(cds.GetCode()); - } else { - tt = &CGen_code_table::GetTransTable(1); - } - if (s.size() == 3 - && tt->IsAnyStart(tt->SetCodonState(s[0], s[1], s[2]))) { - x_AddFeature(l, *tentative_start, source, "start_codon", - "." /* score */, 0, attrs, gtf, ctx); - } - } - if ( tentative_stop ) { - x_AddFeature(l, *tentative_stop, source, "stop_codon", - "." /* score */, 0, attrs, gtf, ctx); - } - } - - text_os.AddParagraph(l, &seqfeat.GetOriginalFeature()); -} - - -string CGFFFormatter::x_FormatAttr(const string& name, const string& value) - const -{ - string value1; - NStr::Replace(value, " \b", kEmptyStr, value1); - string value2(NStr::PrintableString(value1)); - // some parsers may be dumb, so quote further - value1.erase(); - ITERATE (string, c, value2) { - switch (*c) { - // Spaces allowed in the attribute column, if value is quoted, - // which this function is already doing. Thus, avoid ugly \x20. - // @see GTF specs v 1, 2, 2.1, 2.2 - // @see GFF version 1 and version 2 - // case ' ': value1 += "\\x20"; break; - case '\"': value1 += "x22"; break; // already backslashed - case '#': value1 += "\\x23"; break; - default: value1 += *c; - } - } - return name + " \"" + value1 + "\";"; -} - - -void CGFFFormatter::x_AddGeneID(list& attr_list, const string& gene_id, - const string& transcript_id) const -{ - if ( !transcript_id.empty() ) { - attr_list.push_front(x_FormatAttr("transcript_id", transcript_id)); - } - attr_list.push_front(x_FormatAttr("gene_id", gene_id)); -} - - -/////////////////////////////////////////////////////////////////////////// -// -// BASE COUNT - -// used as a trigger for the sequence header - -void CGFFFormatter::FormatBasecount -(const CBaseCountItem& bc, - IFlatTextOStream& text_os) -{ - CBioseqContext& ctx = *bc.GetContext(); - const CFlatFileConfig& cfg = ctx.Config(); - - if ( ! ( cfg.GffShowSeq() ) ) - return; - - list l; - l.push_back("##" + m_SeqType + ' ' + ctx.GetAccession()); - text_os.AddParagraph(l); - m_EndSequence = "##end-" + m_SeqType; -} - - -/////////////////////////////////////////////////////////////////////////// -// -// SEQUENCE - -void CGFFFormatter::FormatSequence -(const CSequenceItem& seq, - IFlatTextOStream& text_os) -{ - CBioseqContext& ctx = *seq.GetContext(); - const CFlatFileConfig& cfg = ctx.Config(); - - if ( ! ( cfg.GffShowSeq() ) ) - return; - - list l; - CSeqVector v = seq.GetSequence(); - v.SetCoding(CBioseq_Handle::eCoding_Iupac); - - CSeqVector_CI vi(v); - string s; - while (vi) { - s.erase(); - vi.GetSeqData(s, 70); - l.push_back("##" + s); - } - text_os.AddParagraph(l, ctx.GetHandle().GetCompleteBioseq()); -} - - - -// Private - -string CGFFFormatter::x_GetGeneID(const CFlatFeature& feat, - const string& gene, - CBioseqContext& ctx) const -{ - //const CSeq_feat& seqfeat = feat.GetFeat(); - CMappedFeat seqfeat = feat.GetFeat(); - - string main_acc = ctx.GetAccession(); - if (ctx.IsPart()) { - const CSeq_id& id = *(ctx.GetMaster().GetHandle().GetSeqId()); - CSeq_id_Handle idh = ctx.GetPreferredSynonym(id); - main_acc = idh.GetSeqId()->GetSeqIdString(true); - } - - string gene_id = main_acc + ':' + gene; - if (seqfeat.GetData().IsGene()) { - return gene_id; - } - - /** - CConstRef gene_feat = - sequence::GetBestOverlappingFeat(seqfeat, CSeqFeatData::e_Gene, - sequence::eOverlap_Interval, - ctx.GetScope()); - **/ - CMappedFeat gene_feat = - ctx.GetFeatTree().GetParent(seqfeat, CSeqFeatData::e_Gene); - if (gene_feat) { - gene_id = main_acc + ':'; - feature::GetLabel(gene_feat.GetOriginalFeature(), &gene_id, - feature::fFGL_Content); - } else { - string msg; - feature::GetLabel(seqfeat.GetOriginalFeature(), &msg, - feature::fFGL_Both); - LOG_POST_X(2, Info << "info: no best overlapping feature for " << msg); - } - - return gene_id; -} - - - -string CGFFFormatter::x_GetTranscriptID -(const CFlatFeature& feat, - const string& gene_id, - CBioseqContext& ctx) const -{ - //const CSeq_feat& seqfeat = feat.GetFeat(); - CMappedFeat seqfeat = feat.GetFeat(); - - // if our feature already is an mRNA, we need look no further - CMappedFeat rna_feat; - switch (seqfeat.GetData().Which()) { - case CSeqFeatData::e_Rna: - rna_feat = seqfeat; - break; - - case CSeqFeatData::e_Cdregion: - if (seqfeat.GetData().GetSubtype() == CSeqFeatData::eSubtype_cdregion) { - //rna_feat = sequence::GetBestMrnaForCds(seqfeat, ctx.GetScope()); - rna_feat = feature::GetBestMrnaForCds(seqfeat, &ctx.GetFeatTree()); - } - break; - - default: - break; - } - - // - // check if the mRNA feature we found has a product - // - if (rna_feat && rna_feat.IsSetProduct()) { - try { - const CSeq_id& id = sequence::GetId(rna_feat.GetProduct(), 0); - CSeq_id_Handle idh = ctx.GetPreferredSynonym(id); - string transcript_id = idh.GetSeqId()->GetSeqIdString(true); - return transcript_id; - } - catch (...) { - } - } - - // - // nothing found, so fake it - // - - // failed to get transcript id, so we fake a globally unique one based - // on the gene id - m_Transcripts[gene_id].push_back(seqfeat); - - string transcript_id = gene_id; - transcript_id += ":unknown_transcript_"; - transcript_id += NStr::NumericToString(m_Transcripts[gene_id].size()); - return transcript_id; -} - - -string CGFFFormatter::x_GetSourceName(CBioseqContext& ctx) const -{ - // XXX - get from annot name (not presently available from IFF)? - switch ( ctx.GetPrimaryId()->Which() ) { - case CSeq_id::e_Local: return "Local"; - case CSeq_id::e_Gibbsq: case CSeq_id::e_Gibbmt: - case CSeq_id::e_Giim: case CSeq_id::e_Gi: return "GenInfo"; - case CSeq_id::e_Genbank: return "Genbank"; - case CSeq_id::e_Swissprot: return "SwissProt"; - case CSeq_id::e_Patent: return "Patent"; - case CSeq_id::e_Other: return "RefSeq"; - case CSeq_id::e_General: - return ctx.GetPrimaryId()->GetGeneral().GetDb(); - default: - { - string source - (CSeq_id::SelectionName(ctx.GetPrimaryId()->Which())); - return NStr::ToUpper(source); - } - } -} - - -void CGFFFormatter::x_AddFeature -(list& l, - const CSeq_loc& loc, - const string& source, - const string& key, - const string& score, - int frame, - const string& attrs, - bool gtf, - CBioseqContext& ctx, - bool tentative_stop) const -{ - int num_exons = 0; - for (CSeq_loc_CI it(loc); it; ++it) { - ++num_exons; - } - int exon_number = 1; - for (CSeq_loc_CI it(loc); it; ++it) { - TSeqPos from = it.GetRange().GetFrom(), to = it.GetRange().GetTo(); - char strand = '+'; - - if (IsReverse(it.GetStrand())) { - strand = '-'; - } else if (it.GetRange().IsWhole()) { - strand = '.'; // N/A - } - - if (it.GetRange().IsWhole()) { - to = sequence::GetLength(it.GetSeq_id(), &ctx.GetScope()) - 1; - } - - string extra_attrs; - if (gtf && attrs.find("exon_number") == NPOS) { - CSeq_loc loc2; - CSeq_interval& si = loc2.SetInt(); - si.SetFrom(from); - si.SetTo(to); - si.SetStrand(it.GetStrand()); - si.SetId(const_cast(it.GetSeq_id())); - - CConstRef exon = sequence::GetBestOverlappingFeat - (loc2, CSeqFeatData::eSubtype_exon, - sequence::eOverlap_Contains, ctx.GetScope()); - if (exon.NotEmpty() && exon->IsSetQual()) { - const CSeq_feat_Base::TQual & qual = exon->GetQual(); // must store reference since ITERATE macro evaluates 3rd arg multiple times - ITERATE( CSeq_feat::TQual, q, qual ) { - if ( !NStr::CompareNocase((*q)->GetQual(), "number") ) { - int n = NStr::StringToNumeric((*q)->GetVal()); - if (n >= exon_number) { - exon_number = n; - break; - } - } - } - } - extra_attrs = x_GetAttrSep() - + x_FormatAttr("exon_number", NStr::IntToString(exon_number)); - ++exon_number; - } - - if ( sequence::IsSameBioseq(it.GetSeq_id(), *ctx.GetPrimaryId(), - &ctx.GetScope()) ) { - // conditionalize printing, but update state regardless - l.push_back(ctx.GetAccession() + '\t' - + source + '\t' - + key + '\t' - + NStr::UIntToString(from + 1) + '\t' - + NStr::UIntToString(to + 1) + '\t' - + score + '\t' - + strand + '\t' - + (frame >= 0 && frame < 3 ? "021"[frame] : '.') + "\t" - + attrs + extra_attrs); - } - if (frame >= 0) { - frame = (frame + to - from + 1) % 3; - } - } -} - - -END_SCOPE(objects) -END_NCBI_SCOPE diff --git a/c++/src/objtools/format/gff_gather.cpp b/c++/src/objtools/format/gff_gather.cpp deleted file mode 100644 index 4cac7c95..00000000 --- a/c++/src/objtools/format/gff_gather.cpp +++ /dev/null @@ -1,104 +0,0 @@ -/* $Id: gff_gather.cpp 477043 2015-08-25 20:27:27Z kans $ -* =========================================================================== -* -* PUBLIC DOMAIN NOTICE -* National Center for Biotechnology Information -* -* This software/database is a "United States Government Work" under the -* terms of the United States Copyright Act. It was written as part of -* the author's official duties as a United States Government employee and -* thus cannot be copyrighted. This software/database is freely available -* to the public for use. The National Library of Medicine and the U.S. -* Government have not placed any restriction on its use or reproduction. -* -* Although all reasonable efforts have been taken to ensure the accuracy -* and reliability of the software and data, the NLM and the U.S. -* Government do not and cannot warrant the performance or results that -* may be obtained by using this software or data. The NLM and the U.S. -* Government disclaim all warranties, express or implied, including -* warranties of performance, merchantability or fitness for any particular -* purpose. -* -* Please cite the author in any work or product based on this material. -* -* =========================================================================== -* -* Author: Aaron Ucko, Mati Shomrat -* -* File Description: -* -* -* =========================================================================== -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -BEGIN_NCBI_SCOPE -BEGIN_SCOPE(objects) - -// ============================================================================ -CGFFGatherer::CGFFGatherer() -// ============================================================================ -{ -} - -// ============================================================================ -void CGFFGatherer::Gather( - CFlatFileContext& ctx, - CFlatItemOStream& os ) const -// ============================================================================ -{ - const CSeq_entry_Handle& seh = ctx.GetEntry(); - - m_ItemOS.Reset(&os); - m_Context.Reset(&ctx); - - CConstRef item; - item.Reset( new CStartItem(seh) ); - os << item; - x_GatherSeqEntry(ctx); - item.Reset( new CEndItem() ); - os << item; -} - -// ============================================================================ -void CGFFGatherer::x_DoSingleSection( - CBioseqContext& ctx ) const -// ============================================================================ -{ - CConstRef item; - - item.Reset( new CStartSectionItem(ctx) ); - ItemOS() << item; - - item.Reset( new CDateItem(ctx) ); - ItemOS() << item; // for UpdateDate - - item.Reset( new CLocusItem(ctx) ); - ItemOS() << item; // for strand - - if ( !ctx.Config().HideSourceFeatures() ) { - x_GatherSourceFeatures(); - } - x_GatherFeatures(); - if ( ctx.Config().IsFormatGFF3() ) { - x_GatherAlignments(); - } - item.Reset( new CBaseCountItem(ctx) ); - ItemOS() << item; - - item.Reset( new CEndSectionItem(ctx) ); - ItemOS() << item; -} - -END_SCOPE(objects) -END_NCBI_SCOPE diff --git a/c++/src/objtools/format/inst_info_map.cpp b/c++/src/objtools/format/inst_info_map.cpp index 9f471555..069c5d04 100644 --- a/c++/src/objtools/format/inst_info_map.cpp +++ b/c++/src/objtools/format/inst_info_map.cpp @@ -1,4 +1,4 @@ -/* $Id: inst_info_map.cpp 506763 2016-07-11 19:47:22Z kans $ +/* $Id: inst_info_map.cpp 523046 2016-12-27 20:19:50Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -57,7 +57,8 @@ CInstInfoMap::GetInstitutionVoucherInfo( static const string s_ccug_base("http://www.ccug.se/default.cfm?page=search_record.cfm&db=mc&s_tests=1&ccugno="); static const string s_cfmr_base("http://www.fpl.fs.fed.us/search/mycologysearch_action.php?sorting_rule=1u&phrasesAndKeywords02="); static const string s_cori_base("http://ccr.coriell.org/Sections/Search/Search.aspx?q="); - static const string s_dsmz_base("http://www.dsmz.de/catalogues/details/culture/DSM-"); + static const string s_dsm_base("https://www.dsmz.de/catalogues/details/culture/DSM-"); + static const string s_dsmz_base("https://www.dsmz.de/catalogues/details/culture/PV-"); static const string s_frr_base("http://www.foodscience.csiro.au/cgi-bin/rilax/search.pl?stpos=0&stype=AND&query="); static const string s_fsu_base("http://www.prz.uni-jena.de/data.php?fsu="); static const string s_jcm_base("http://www.jcm.riken.jp/cgi-bin/jcm/jcm_number?JCM="); @@ -130,7 +131,8 @@ CInstInfoMap::GetInstitutionVoucherInfo( { "DGR:Mamm", TVoucherInfoRef(new SVoucherInfo(&s_uam_base, true, 0, NULL, &s_colon_pfx, NULL, "Division of Genomic Resources, University of New Mexico, mammal tissue collection") ) }, { "DMNS:Bird", TVoucherInfoRef(new SVoucherInfo(&s_uam_base, true, 0, NULL, &s_colon_pfx, NULL, "Denver Museum of Nature and Science, Ornithology Collections") ) }, { "DMNS:Mamm", TVoucherInfoRef(new SVoucherInfo(&s_uam_base, true, 0, NULL, &s_colon_pfx, NULL, "Denver Museum of Nature and Science, Mammology Collection") ) }, - { "DSM", TVoucherInfoRef(new SVoucherInfo(&s_dsmz_base, false, 0, NULL, NULL, NULL, "Deutsche Sammlung von Mikroorganismen und Zellkulturen GmbH") ) }, + { "DSM", TVoucherInfoRef(new SVoucherInfo(&s_dsm_base, false, 0, NULL, NULL, NULL, "Deutsche Sammlung von Mikroorganismen und Zellkulturen GmbH") ) }, + { "DSMZ", TVoucherInfoRef(new SVoucherInfo(&s_dsmz_base, false, 0, NULL, NULL, NULL, "Deutsche Sammlung von Mikroorganismen und Zellkulturen GmbH") ) }, { "FRR", TVoucherInfoRef(new SVoucherInfo(&s_frr_base, false, 0, NULL, NULL, NULL, "Food Science Australia, Ryde") ) }, { "FSU", TVoucherInfoRef(new SVoucherInfo(&s_fsu_base, false, 0, NULL, NULL, NULL, "Jena Microbial Resource Collection") ) }, { "ICMP", TVoucherInfoRef(new SVoucherInfo(&s_lcr_base, true, 0, NULL, &s_uscr_pfx, NULL, "International Collection of Microorganisms from Plants") ) }, @@ -167,7 +169,7 @@ CInstInfoMap::GetInstitutionVoucherInfo( { "MVZ:Mamm", TVoucherInfoRef(new SVoucherInfo(&s_uam_base, true, 0, NULL, &s_colon_pfx, NULL, "Museum of Vertebrate Zoology, University of California at Berkeley, Mammal Collection") ) }, { "MVZ:Page", TVoucherInfoRef(new SVoucherInfo(&s_uam_base, true, 0, NULL, &s_colon_pfx, NULL, "Museum of Vertebrate Zoology, University of California at Berkeley, Notebook Page Collection") ) }, { "MVZObs:Herp", TVoucherInfoRef(new SVoucherInfo(&s_uam_base, true, 0, NULL, &s_colon_pfx, NULL, "Museum of Vertebrate Zoology, University of California at Berkeley, Herpetology Collection") ) }, - { "NBRC", TVoucherInfoRef(new SVoucherInfo(&s_nbrc_base, false, 0, NULL, NULL, NULL, "NITE Biological Resource Center") ) }, + { "NBRC", TVoucherInfoRef(new SVoucherInfo(&s_nbrc_base, false, 8, &yp0, NULL, NULL, "NITE Biological Resource Center") ) }, { "NBSB:Bird", TVoucherInfoRef(new SVoucherInfo(&s_uam_base, true, 0, NULL, &s_colon_pfx, NULL, "National Biomonitoring Specimen Bank, U.S. Geological Survey, bird collection") ) }, { "NCIMB", TVoucherInfoRef(new SVoucherInfo(&s_ncimb_base, false, 0, NULL, NULL, NULL, "National Collections of Industrial Food and Marine Bacteria (incorporating the NCFB)") ) }, { "NCTC", TVoucherInfoRef(new SVoucherInfo(&s_nctc_base, false, 0, NULL, NULL, NULL, "National Collection of Type Cultures") ) }, diff --git a/c++/src/objtools/format/item_formatter.cpp b/c++/src/objtools/format/item_formatter.cpp index 3e9b1f0b..7a9a4247 100644 --- a/c++/src/objtools/format/item_formatter.cpp +++ b/c++/src/objtools/format/item_formatter.cpp @@ -1,4 +1,4 @@ -/* $Id: item_formatter.cpp 506085 2016-07-01 14:25:26Z gotvyans $ +/* $Id: item_formatter.cpp 527373 2017-02-13 18:27:39Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1412,6 +1412,9 @@ static void s_FormatJournal s_FixPages(pages); } } + if (NStr::IsBlank(pages)) { + pages = ref.GetPII(); + } if (!NStr::IsBlank(volume) || !NStr::IsBlank(pages)) { jour << s_DoSup(issue, part_sup, part_supi); diff --git a/c++/src/objtools/format/keywords_item.cpp b/c++/src/objtools/format/keywords_item.cpp index deb689ec..47d8473e 100644 --- a/c++/src/objtools/format/keywords_item.cpp +++ b/c++/src/objtools/format/keywords_item.cpp @@ -1,4 +1,4 @@ -/* $Id: keywords_item.cpp 493033 2016-02-23 18:51:30Z kans $ +/* $Id: keywords_item.cpp 515707 2016-10-05 12:32:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -375,7 +375,7 @@ static bool x_OkayToAddKeyword(const string& keyword, vector keywords) void CKeywordsItem::x_AddKeyword(const string& keyword) { list kywds; - NStr::Split( keyword, ";", kywds ); + NStr::Split( keyword, ";", kywds, NStr::fSplit_Tokenize ); FOR_EACH_STRING_IN_LIST ( k_itr, kywds ) { const string& kw = *k_itr; if (x_OkayToAddKeyword (kw, m_Keywords)) { diff --git a/c++/src/objtools/format/locus_item.cpp b/c++/src/objtools/format/locus_item.cpp index 6a316017..0d906d19 100644 --- a/c++/src/objtools/format/locus_item.cpp +++ b/c++/src/objtools/format/locus_item.cpp @@ -1,4 +1,4 @@ -/* $Id: locus_item.cpp 515537 2016-10-03 16:02:52Z ivanov $ +/* $Id: locus_item.cpp 522282 2016-12-16 18:36:56Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/objtools/format/primary_item.cpp b/c++/src/objtools/format/primary_item.cpp index f01ac8ee..46d4e431 100644 --- a/c++/src/objtools/format/primary_item.cpp +++ b/c++/src/objtools/format/primary_item.cpp @@ -1,4 +1,4 @@ -/* $Id: primary_item.cpp 472056 2015-07-06 19:29:12Z gotvyans $ +/* $Id: primary_item.cpp 523934 2017-01-06 20:30:58Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -273,13 +273,14 @@ void CPrimaryItem::x_GetStrForPrimary(CBioseqContext& ctx) continue; } } + string tid = other_id->GetSeqIdString(true); if (other_id->IsGeneral()) { const CDbtag& dbt = other_id->GetGeneral(); if (dbt.IsSetDb() && NStr::EqualNocase(dbt.GetDb(), "TI")) { - s += "TI"; - } + NStr::ReplaceInPlace (tid, "ti:", "TI"); + } } - s += other_id->GetSeqIdString(true); + s += tid; s.resize(39, ' '); s += NStr::IntToString(align.GetSeqStart(1) + 1) + '-' + NStr::IntToString(align.GetSeqStop(1) + 1); diff --git a/c++/src/objtools/format/qualifiers.cpp b/c++/src/objtools/format/qualifiers.cpp index a65aef47..eae3a71f 100644 --- a/c++/src/objtools/format/qualifiers.cpp +++ b/c++/src/objtools/format/qualifiers.cpp @@ -1,4 +1,4 @@ -/* $Id: qualifiers.cpp 509627 2016-08-08 14:27:18Z ivanov $ +/* $Id: qualifiers.cpp 544492 2017-08-23 17:44:32Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -147,7 +147,8 @@ static string s_GetGOText( if (go_id != NULL) { go_text = string( "GO:" ); if( is_html ) { - go_text += ""; + go_text += ""; } go_text += *go_id; if( is_html ) { @@ -162,7 +163,8 @@ static string s_GetGOText( go_text += string( " - " ); } if( is_html && go_id != NULL ) { - go_text += ""; + go_text += ""; } // NO, we NO LONGER have the dash here even if there's no go_id (RETAIN compatibility with CHANGE in C) go_text += *text_string; @@ -178,7 +180,8 @@ static string s_GetGOText( go_text += " [PMID "; if( is_html && go_id != NULL ) { - go_text += ""; + go_text += ""; } go_text += pmid_str; if( is_html && go_id != NULL ) { @@ -189,7 +192,8 @@ static string s_GetGOText( if ( go_ref != 0 ) { go_text += " [GO Ref "; if( is_html ) { - go_text += ""; + go_text += ""; } go_text += *go_ref; if( is_html ) { @@ -590,7 +594,7 @@ void CFlatGeneSynonymsQVal::Format // std::sort(sub.begin(), sub.end(), PNocase()); stable_sort(sub.begin(), sub.end(), CLessThanNoCaseViaUpper() ); - if (ctx.IsRefSeq()) { + if (ctx.IsRefSeq() && !ctx.Config().IsModeDump()) { x_AddFQ( q, qual, NStr::Join(sub, "; "), m_Style, 0, CFormatQual::eTrim_WhitespaceOnly ); } else { ITERATE (vector, it, sub) { @@ -978,7 +982,8 @@ void CFlatPubSetQVal::Format(TFlatQuals& q, const CTempString& name, if( (*ref_iter)->GetPMID() > 0 && bHtml ) { // create a link const int pmid = (*ref_iter)->GetPMID(); - value = "[" + + value = "[" + NStr::IntToString((*ref_iter)->GetSerial()) + "]"; } else { @@ -1048,6 +1053,7 @@ void CFlatSeqIdQVal::Format(TFlatQuals& q, const CTempString& name, if ( m_Value->IsGi() ) { if ( m_GiPrefix ) { id_str = "GI:"; + if (ctx.Config().HideGI() && name == "db_xref") return; } m_Value->GetLabel(&id_str, CSeq_id::eContent); } else { @@ -1149,12 +1155,20 @@ void s_HtmlizeLatLon( string &subname ) { // now we can form the HTML CNcbiOstrstream result; + /* result << "" << subname << ""; + */ + result << "" + << subname << ""; subname = CNcbiOstrstreamToString(result); } diff --git a/c++/src/objtools/format/reference_item.cpp b/c++/src/objtools/format/reference_item.cpp index 2b5e63b9..8d5b08ac 100644 --- a/c++/src/objtools/format/reference_item.cpp +++ b/c++/src/objtools/format/reference_item.cpp @@ -1,4 +1,4 @@ -/* $Id: reference_item.cpp 472056 2015-07-06 19:29:12Z gotvyans $ +/* $Id: reference_item.cpp 529217 2017-03-01 22:06:32Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include #include @@ -171,7 +173,7 @@ CReferenceItem::CReferenceItem(const CSeqdesc& desc, CBioseqContext& ctx) : { _ASSERT(desc.IsPub()); - x_SetObject(desc.GetPub()); + x_SetObject(desc); m_Pubdesc.Reset(&(desc.GetPub())); if (ctx.GetMapper() != NULL) { @@ -912,6 +914,47 @@ void CReferenceItem::x_Init(const CMedline_entry& mle, CBioseqContext& ctx) } +static bool PiiOk(const string& str) +{ + if (NStr::IsBlank(str)) return false; + + int max = str.length(); + int i = 0; + + char ch = str[i]; + + if (ch != 'e' && ch != 'E') return false; + if (ch == 'e' || ch == 'E') { + i++; + ch = str[i]; + } + if (i >= max || ch < '0' || ch > '9') return false; + while (i < max && ch >= '0' && ch <= '9') { + i++; + ch = str[i]; + } + if (i >= max) return true; + + if (ch == 'e' || ch == 'E') return false; + if (ch == '-') { + i++; + ch = str[i]; + } + if (ch == 'e' || ch == 'E') { + i++; + ch = str[i]; + } + if (i >= max || ch < '0' || ch > '9') return false; + while (i < max && ch >= '0' && ch <= '9') { + i++; + ch = str[i]; + } + + if (i >= max) return true; + + return false; +} + void CReferenceItem::x_Init(const CCit_art& art, CBioseqContext& ctx) { // Title @@ -924,10 +967,33 @@ void CReferenceItem::x_Init(const CCit_art& art, CBioseqContext& ctx) x_AddAuthors(art.GetAuthors()); } + bool not_in_press = false; + bool is_epublish = false; + switch (art.GetFrom().Which()) { case CCit_art::C_From::e_Journal: - m_PubType = ePub_jour; - x_Init(art.GetFrom().GetJournal(), ctx); + { + m_PubType = ePub_jour; + const CCit_jour& jour = art.GetFrom().GetJournal(); + x_Init(jour, ctx); + if (jour.IsSetImp()) { + const CImprint& imp = jour.GetImp(); + if (imp.IsSetPrepub()) { + CImprint::TPrepub prepub = imp.GetPrepub(); + if (prepub != CImprint::ePrepub_in_press) { + not_in_press = true; + } + } else { + not_in_press = true; + } + if (imp.IsSetPubstatus()) { + CImprint::TPubstatus pubstatus = imp.GetPubstatus(); + if (pubstatus == 3) { + is_epublish = true; + } + } + } + } break; case CCit_art::C_From::e_Proc: m_PubType = ePub_book_art; @@ -954,6 +1020,25 @@ void CReferenceItem::x_Init(const CCit_art& art, CBioseqContext& ctx) m_MUID = (*it)->GetMedline(); } break; + case CArticleId_Base::e_Other: + { + const CDbtag& dbt = (*it)->GetOther(); + if (dbt.CanGetDb()) { + const string& db = dbt.GetDb(); + if (NStr::EqualNocase(db, "ELocationID pii")) { + if (dbt.IsSetTag ()) { + const CObject_id& oid = dbt.GetTag(); + if (oid.IsStr() && not_in_press && is_epublish) { + const string& pii = oid.GetStr(); + if (PiiOk (pii)) { + m_ELocationPII = pii; + } + } + } + } + } + } + break; default: break; } @@ -1297,7 +1382,8 @@ void CReferenceItem::ChangeMedlineAuthorsToISO( CRef pub ) { NStr::TruncateSpacesInPlace(author_name); vector tokens; - NStr::Tokenize(author_name, " ", tokens, NStr::eMergeDelims); + NStr::Split(author_name, " ", tokens, + NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); // get suffix if it exists, and remove it from the list if( tokens.size() >= 3 && diff --git a/c++/src/objtools/format/source_item.cpp b/c++/src/objtools/format/source_item.cpp index ddcbc30c..d588b9ed 100644 --- a/c++/src/objtools/format/source_item.cpp +++ b/c++/src/objtools/format/source_item.cpp @@ -1,4 +1,4 @@ -/* $Id: source_item.cpp 472056 2015-07-06 19:29:12Z gotvyans $ +/* $Id: source_item.cpp 530087 2017-03-10 18:26:41Z kans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -102,8 +102,60 @@ const string CSourceItem::scm_Unclassified = "Unclassified."; const list CSourceItem::scm_EmptyList; +static CConstRef x_GetSourceFeatFromCDS ( + const CBioseq_Handle& bsh +) + +{ + CConstRef cds_feat; + CConstRef cds_loc; + CConstRef src_ref; + + CScope& scope = bsh.GetScope(); + + cds_feat = sequence::GetCDSForProduct (bsh); + + if (cds_feat) { + cds_loc = &cds_feat->GetLocation(); + if (cds_loc) { + CRef cleaned_location( new CSeq_loc ); + cleaned_location->Assign( *cds_loc ); + CConstRef src_feat + = sequence::GetBestOverlappingFeat (*cleaned_location, CSeqFeatData::eSubtype_biosrc, sequence::eOverlap_SubsetRev, scope); + if (! src_feat && cleaned_location->IsSetStrand() && IsReverse(cleaned_location->GetStrand())) { + CRef rev_loc(sequence::SeqLocRevCmpl(*cleaned_location, &scope)); + cleaned_location->Assign(*rev_loc); + src_feat = sequence::GetBestOverlappingFeat (*cleaned_location, CSeqFeatData::eSubtype_biosrc, sequence::eOverlap_SubsetRev, scope); + } + if (src_feat) { + const CSeq_feat& feat = *src_feat; + if (feat.IsSetData()) { + return src_feat; + } + } + } + } + + return CConstRef (); +} + void CSourceItem::x_GatherInfo(CBioseqContext& ctx) { + CConstRef cds_feat; + CConstRef cds_loc; + CConstRef src_ref; + CConstRef src_feat; + + if (ctx.IsProt()) { + const CBioseq_Handle& bsh = ctx.GetHandle(); + src_feat = x_GetSourceFeatFromCDS (bsh); + if (src_feat.NotEmpty()) { + const CSeq_feat& feat = *src_feat; + x_SetSource(feat.GetData().GetBiosrc(), feat); + return; + } + } + // For DDBJ format first try a GB-Block descriptor (old style) if ( ctx.Config().IsFormatDDBJ() ) { CSeqdesc_CI gb_it(ctx.GetHandle(), CSeqdesc::e_Genbank); @@ -133,6 +185,22 @@ void CSourceItem::x_GatherInfo(CBioseqContext& ctx) void CSourceItem::x_GatherInfo(CBioseqContext& ctx, const CBioSource& bsrc, const CSerialObject& obj) { + CConstRef cds_feat; + CConstRef cds_loc; + CConstRef src_ref; + + CConstRef src_feat; + + if (ctx.IsProt()) { + const CBioseq_Handle& bsh = ctx.GetHandle(); + src_feat = x_GetSourceFeatFromCDS (bsh); + if (src_feat.NotEmpty()) { + const CSeq_feat& feat = *src_feat; + x_SetSource(feat.GetData().GetBiosrc(), feat); + return; + } + } + // For DDBJ format first try a GB-Block descriptor (old style) if ( ctx.Config().IsFormatDDBJ() ) { CSeqdesc_CI gb_it(ctx.GetHandle(), CSeqdesc::e_Genbank); diff --git a/c++/src/objtools/readers/CMakeLists.txt b/c++/src/objtools/readers/CMakeLists.txt new file mode 100644 index 00000000..f8f5e5ff --- /dev/null +++ b/c++/src/objtools/readers/CMakeLists.txt @@ -0,0 +1,12 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xobjread.lib.txt) +include(CMakeLists.xobjreadex.lib.txt) + +# Recurse subdirectories +add_subdirectory(app) +add_subdirectory(test ) +add_subdirectory(unit_test ) diff --git a/c++/src/objtools/readers/CMakeLists.xobjread.lib.txt b/c++/src/objtools/readers/CMakeLists.xobjread.lib.txt new file mode 100644 index 00000000..68a2de24 --- /dev/null +++ b/c++/src/objtools/readers/CMakeLists.xobjread.lib.txt @@ -0,0 +1,25 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/readers/Makefile.xobjread.lib +# +add_library(xobjread + read_util format_guess_ex + acc_pattern agp_read agp_seq_entry agp_util agp_validate_reader aln_reader bed_reader cigar fasta + fasta_aln_builder fasta_reader_utils getfeature gff_reader track_data reader_data + microarray_reader phrap reader_base readfeat rm_reader + wiggle_reader gff3_sofa gff3_reader gtf_reader + gff2_data gff2_reader + gvf_reader + vcf_reader + best_feat_finder source_mod_parser fasta_exception agp_converter + ucscregion_reader struct_cmt_reader + message_listener line_error +) +include_directories(SYSTEM ${BOOST_INCLUDE}) + +target_link_libraries(xobjread + creaders submit +) +add_dependencies(xobjread + seqset +) + diff --git a/c++/src/objtools/readers/CMakeLists.xobjreadex.lib.txt b/c++/src/objtools/readers/CMakeLists.xobjreadex.lib.txt new file mode 100644 index 00000000..39ebf0a5 --- /dev/null +++ b/c++/src/objtools/readers/CMakeLists.xobjreadex.lib.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/readers/Makefile.xobjreadex.lib +# +add_library(xobjreadex + glimmer_reader idmapper idmapper_builtin idmapper_config + idmapper_database idmapper_gcassembly idmapper_scope + source_mod_parser_wrapper +) +target_link_libraries(xobjreadex + xobjread xobjutil +) +add_dependencies(xobjreadex + seqset +) + diff --git a/c++/src/objtools/readers/Makefile.xobjread.lib b/c++/src/objtools/readers/Makefile.xobjread.lib index d6d96b2d..4ecc5958 100644 --- a/c++/src/objtools/readers/Makefile.xobjread.lib +++ b/c++/src/objtools/readers/Makefile.xobjread.lib @@ -1,6 +1,6 @@ -# $Id: Makefile.xobjread.lib 515962 2016-10-06 18:16:16Z ivanov $ +# $Id: Makefile.xobjread.lib 525947 2017-01-30 16:58:18Z foleyjp $ -WATCHERS = jcherry sapojnik bollin ludwigf ucko gotvyans +WATCHERS = jcherry sapojnik bollin ludwigf ucko gotvyans foleyjp ASN_DEP = submit @@ -10,7 +10,7 @@ CPPFLAGS = $(ORIG_CPPFLAGS) $(BOOST_INCLUDE) LIB = xobjread SRC = read_util format_guess_ex \ acc_pattern agp_read agp_seq_entry agp_util agp_validate_reader aln_reader bed_reader cigar fasta \ - fasta_aln_builder getfeature gff_reader track_data reader_data \ + fasta_aln_builder fasta_reader_utils getfeature gff_reader track_data reader_data \ microarray_reader phrap reader_base readfeat rm_reader \ wiggle_reader gff3_sofa gff3_reader gtf_reader \ gff2_data gff2_reader \ diff --git a/c++/src/objtools/readers/Makefile.xobjreadex.lib b/c++/src/objtools/readers/Makefile.xobjreadex.lib index 7c3f5867..caa8065f 100644 --- a/c++/src/objtools/readers/Makefile.xobjreadex.lib +++ b/c++/src/objtools/readers/Makefile.xobjreadex.lib @@ -1,4 +1,4 @@ -# $Id: Makefile.xobjreadex.lib 501626 2016-05-17 17:32:10Z kornbluh $ +# $Id: Makefile.xobjreadex.lib 536919 2017-05-24 15:51:10Z ucko $ WATCHERS = dicuccio ludwigf gotvyans @@ -9,7 +9,7 @@ SRC = glimmer_reader idmapper idmapper_builtin idmapper_config \ idmapper_database idmapper_gcassembly idmapper_scope \ source_mod_parser_wrapper -DLL_LIB = xobjread +DLL_LIB = xobjread xobjutil USES_LIBRARIES = \ diff --git a/c++/src/objtools/readers/agp_converter.cpp b/c++/src/objtools/readers/agp_converter.cpp index 4e3c5c93..97e8d678 100644 --- a/c++/src/objtools/readers/agp_converter.cpp +++ b/c++/src/objtools/readers/agp_converter.cpp @@ -1,4 +1,4 @@ -/* $Id: agp_converter.cpp 439674 2014-07-02 16:25:04Z vakatov $ +/* $Id: agp_converter.cpp 515707 2016-10-05 12:32:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -140,7 +140,7 @@ CAgpConverter::LoadChromosomeMap(CNcbiIstream & chromosomes_istr ) continue; } list split_line; - NStr::Split(line, " \t", split_line); + NStr::Split(line, " \t", split_line, NStr::fSplit_Tokenize); if (split_line.size() != 2) { m_pErrorHandler->HandleError( eError_ChromosomeFileBadFormat, diff --git a/c++/src/objtools/readers/agp_read.cpp b/c++/src/objtools/readers/agp_read.cpp index f90e1dba..a04cabee 100644 --- a/c++/src/objtools/readers/agp_read.cpp +++ b/c++/src/objtools/readers/agp_read.cpp @@ -1,4 +1,4 @@ -/* $Id: agp_read.cpp 372820 2012-08-22 17:50:43Z kornbluh $ +/* $Id: agp_read.cpp 543178 2017-08-08 11:22:20Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -120,7 +120,7 @@ void AgpRead(CNcbiIstream& is, // split into fields, as delimited by tabs fields.clear(); - NStr::Tokenize(line, "\t", fields); + NStr::Split(line, "\t", fields, NStr::fSplit_NoMergeDelims); // eliminate any empty fields at the end of the line int index; @@ -226,7 +226,7 @@ void AgpRead(CNcbiIstream& is, type = CSeq_gap::eType_contig; } else if (type_string == "centromere") { type = CSeq_gap::eType_centromere; - } else if (type_string == "short_arm") { + } else if (type_string == "short arm" || type_string == "short_arm") { type = CSeq_gap::eType_short_arm; } else if (type_string == "heterochromatin") { type = CSeq_gap::eType_heterochromatin; diff --git a/c++/src/objtools/readers/agp_util.cpp b/c++/src/objtools/readers/agp_util.cpp index 6cc4ea74..ae4841d7 100644 --- a/c++/src/objtools/readers/agp_util.cpp +++ b/c++/src/objtools/readers/agp_util.cpp @@ -1,4 +1,4 @@ -/* $Id: agp_util.cpp 496699 2016-03-30 14:46:49Z sapojnik $ +/* $Id: agp_util.cpp 544557 2017-08-24 11:54:27Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1193,6 +1193,7 @@ void CAgpErrEx::PrintAllMessages(CNcbiOstream& out) "#Error with -sub, warning if no -sub option:\n" "#\tcomponent name(s)/object name(s) in FASTA not found in AGP\n" "#\tscaffold(s) not found in Chromosome from scaffold AGP\n" + "#\tno gap lines\n" ; } @@ -1245,6 +1246,10 @@ void ReplaceUnprintableCharacters(string& text) if(p1==NPOS) break; SIZE_TYPE p2 = text.find(';', p1+2); if(p2!=NPOS) { + // allow tabs + if( text.substr(p1, p2-p1)==" ") { + p1=p2; continue; + } text = text.substr(0,p1) + "?" + text.substr(p2+1); } else { diff --git a/c++/src/objtools/readers/agp_validate_reader.cpp b/c++/src/objtools/readers/agp_validate_reader.cpp index e0a9c3ae..3328f9eb 100644 --- a/c++/src/objtools/readers/agp_validate_reader.cpp +++ b/c++/src/objtools/readers/agp_validate_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: agp_validate_reader.cpp 465301 2015-04-20 16:41:10Z sapojnik $ +/* $Id: agp_validate_reader.cpp 529752 2017-03-07 17:57:23Z sapojnik $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -369,13 +369,17 @@ void CAgpValidateReader::OnGapOrComponent() if(m_this_row->component_type == 'W') m_AgpErr->Msg(CAgpErr::W_CompIsNotWgsTypeIs); } else if( div != CSeq_id::eAcc_other // no further classification + && div != CSeq_id::eAcc_dirsub // direct submission of anything, e.g. FO081906.4 (see GCOL-6194) ) { - if( string("ADF").find(m_this_row->component_type)!=NPOS ) m_AgpErr->Msg(CAgpErr::W_CompIsNotHtgTypeIs, m_this_row->GetComponentId()); + if( string("ADF").find(m_this_row->component_type)!=NPOS ) + m_AgpErr->Msg(CAgpErr::W_CompIsNotHtgTypeIs, m_this_row->GetComponentId()); } } else { - if( string("ADF").find(m_this_row->component_type)!=NPOS ) m_AgpErr->Msg(CAgpErr::W_CompIsNotHtgTypeIs, m_this_row->GetComponentId()); - else if(m_this_row->component_type!='W') m_AgpErr->Msg( CAgpErr::W_CompIsLocalTypeNotW, m_this_row->GetComponentId() ); + if( string("ADF").find(m_this_row->component_type)!=NPOS ) + m_AgpErr->Msg(CAgpErr::W_CompIsNotHtgTypeIs, m_this_row->GetComponentId()); + else if(m_this_row->component_type!='W') + m_AgpErr->Msg( CAgpErr::W_CompIsLocalTypeNotW, m_this_row->GetComponentId() ); } if( m_comp2len->size() ) { @@ -460,6 +464,7 @@ void CAgpValidateReader::OnGapOrComponent() // m_this_row = current gap or component (check with m_this_row->IsGap()) } +// this function can use m_prev_row - but not m_this_row void CAgpValidateReader::OnScaffoldEnd() { NCBI_ASSERT(m_componentsInLastScaffold>0 || m_gapsInLastScaffold>0, @@ -470,10 +475,10 @@ void CAgpValidateReader::OnScaffoldEnd() m_SingleCompScaffolds++; if(m_gapsInLastScaffold) m_SingleCompScaffolds_withGaps++; - if(m_unplaced && m_prev_orientation) { + if((m_unplaced || NStr::StartsWith(m_prev_row->GetObject(), "un", NStr::eNocase) ) && m_prev_orientation) { if(m_prev_orientation!='+') m_AgpErr->Msg( CAgpErrEx::W_UnSingleOriNotPlus , CAgpErr::fAtPrevLine ); - TMapStrInt::iterator it = m_comp2len->find( m_this_row->GetComponentId() ); + TMapStrInt::iterator it = m_comp2len->find( m_prev_row->GetComponentId() ); if( it!=m_comp2len->end() ) { int len = it->second; if(m_prev_component_beg!=1 || m_prev_component_endCountTotals(CAgpErrEx::G_Last); int w_count=m_AgpErr->CountTotals(CAgpErrEx::W_Last); + if(m_GapCount==0) { + if(m_AgpErr->m_strict) e_count++; else w_count++; + } + if(not_in_agp_msg.size()) { if(m_AgpErr->m_strict) e_count++; else w_count++; } @@ -905,6 +914,9 @@ void CAgpValidateReader::x_PrintTotals(CNcbiOstream& out, bool use_xml) // witho if(not_in_agp_msg.size() && !use_xml) { out << " - - " << not_in_agp_msg << "\n"; } + if(m_GapCount==0 && !use_xml) { + out << " - - no gap lines\n"; + } xprint.line(); //// Prepare component/gap types and counts for later printing diff --git a/c++/src/objtools/readers/aln_reader.cpp b/c++/src/objtools/readers/aln_reader.cpp index 4e6e9115..9ff63a21 100644 --- a/c++/src/objtools/readers/aln_reader.cpp +++ b/c++/src/objtools/readers/aln_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: aln_reader.cpp 511112 2016-08-18 18:12:19Z ivanov $ +/* $Id: aln_reader.cpp 540464 2017-07-06 17:51:02Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -47,7 +47,7 @@ #include #include #include - +#include #define NCBI_USE_ERRCODE_X Objtools_Rd_Align @@ -162,6 +162,73 @@ CAlnReader::~CAlnReader() } +int CAlnReader::x_GetGCD(const int a, const int b) const +{ + if (a == 0) { + return b; + } + + if (b == 0) { + return a; + } + + + if (a > b) { + const int r = a%b; + return x_GetGCD(b,r); + } + // b > a + const int r = b%a; + return x_GetGCD(a, r); +} + + +void s_GetSequenceLengthInfo(const TAlignmentFilePtr afp, + size_t& min_len, + size_t& max_len, + int& max_index) +{ + + if (afp->num_sequences == 0) { + return; + } + + max_len = strlen(afp->sequences[0]); + min_len = max_len; + max_index = 0; + + for (auto i=0; inum_sequences; ++i) { + size_t curr_len = strlen(afp->sequences[i]); + if (curr_len > max_len) { + max_len = curr_len; + max_index = i; + } + else + if (curr_len < min_len){ + min_len = curr_len; + } + } +} + + +bool CAlnReader::x_IsReplicatedSequence(const char* seq_data, + const int length, + const int repeat_interval) const +{ + if (length%repeat_interval != 0) { + return false; + } + + const int num_repeats = length/repeat_interval; + for (int i=1; isequences[0]); - for (int i = 1; i < afp->num_sequences; i++) { - if (strlen (afp->sequences[i]) != first_len) { - AlignmentFileFree (afp); + if (1 == afp->num_sequences) { + NCBI_THROW2(CObjReaderParseException, eFormat, + "Error reading alignment: Need more than one sequence", 0); + } + + + // Check sequence lengths + size_t max_len, min_len; + int max_index; + s_GetSequenceLengthInfo(afp, + min_len, + max_len, + max_index); + + if (min_len == 0) { + NCBI_THROW2(CObjReaderParseException, eFormat, + "Error reading alignment: Missing sequence data", 0); + } + + + + if (max_len != min_len) { + // Check for replicated intervals in the longest sequence + const int repeat_interval = x_GetGCD(max_len, min_len); + const bool is_repeated = + x_IsReplicatedSequence(afp->sequences[max_index], max_len, repeat_interval); + AlignmentFileFree(afp); + + if (is_repeated) { + NCBI_THROW2(CObjReaderParseException, eFormat, + "Error reading alignment: Possible sequence replication", 0); + } + else { NCBI_THROW2(CObjReaderParseException, eFormat, "Error reading alignment: Not all sequences have same length", 0); } } + // if we're trying to guess whether this is an alignment file, // and no tell-tale alignment format lines were found, @@ -281,7 +377,148 @@ void CAlnReader::SetPhylip(EAlphabet alpha) } -CRef CAlnReader::GetSeqAlign() +void CAlnReader::x_CalculateMiddleSections() +{ + m_MiddleSections.clear(); + + + for (TNumrow row_i = 0; row_i < m_Dim; row_i++) { + TSeqPos begin_len = strspn(m_Seqs[row_i].c_str(), m_BeginningGap.c_str()); + TSeqPos end_len = 0; + if (begin_len < m_Seqs[row_i].length()) { + string::iterator s = m_Seqs[row_i].end(); + while (s != m_Seqs[row_i].begin()) { + --s; + if (strchr(m_EndGap.c_str(), *s) != NULL) { + end_len++; + } else { + break; + } + } + } + m_MiddleSections.push_back(TAlignMiddleInterval(begin_len, m_Seqs[row_i].length() - end_len - 1)); + } +} + + +bool CAlnReader::x_IsGap(TNumrow row, TSeqPos pos, const string& residue) +{ + if (m_MiddleSections.size() == 0) { + x_CalculateMiddleSections(); + } + if (row > m_MiddleSections.size()) { + return false; + } + if (pos < m_MiddleSections[row].first) { + if (NStr::Find(m_BeginningGap, residue) == string::npos) { + return false; + } else { + return true; + } + } else if (pos > m_MiddleSections[row].second) { + if (NStr::Find(m_EndGap, residue) == string::npos) { + return false; + } else { + return true; + } + } else { + if (NStr::Find(m_MiddleGap, residue) == string::npos) { + return false; + } else { + return true; + } + } +} + +/* +CRef CAlnReader::GetFastaId(const string& fasta_defline, + const TSeqPos& defline_number, + TFastaFlags fasta_flags) +{ + TSeqPos range_start = 0, range_end = 0; + bool has_range = false; + SDeflineParseInfo parse_info; + parse_info.fBaseFlags = 0; + parse_info.fFastaFlags = fasta_flags; + parse_info.maxIdLength = kMax_UI4; + parse_info.lineNumber = defline_number; + + TIgnoredProblems ignored_errors; + TSeqTitles seq_titles; + list> ids; + try { + ParseDefline(fasta_defline, + parse_info, + ignored_errors, + ids, + has_range, + range_start, + range_end, + seq_titles, + 0); + } + catch (const exception&) {} + + CRef result; + const bool unique_id = (fasta_flags & objects::CFastaReader::fUniqueIDs); + + + if (ids.empty()) { + result = GenerateID(fasta_defline, unique_id); + } + else { + result = FindBestChoice(ids, CSeq_id::BestRank); + } + + if (has_range) { + string seq_id_text = "lcl|" + result->GetSeqIdString(true); + seq_id_text += ":" + NStr::NumericToString(range_start+1) + "_" + NStr::NumericToString(range_end+1); + result = Ref(new CSeq_id(seq_id_text)); + } + + if (unique_id) { + x_CacheIdHandle(CSeq_id_Handle::GetHandle(*result)); + } + + return result; +} +*/ + + +CRef CAlnReader::GenerateID(const string& fasta_defline, + const TSeqPos& defline_number, + TFastaFlags fasta_flags) +{ + string id_string = m_Ids[defline_number]; + + CBioseq::TId xid; + if (CSeq_id::ParseFastaIds(xid, id_string, true) > 0) { + return xid.front(); + } + return Ref(new CSeq_id(CSeq_id::e_Local, id_string)); +} + + +void CAlnReader::x_AssignDensegIds(const TFastaFlags fasta_flags, + CDense_seg& denseg) +{ + CDense_seg::TIds& ids = denseg.SetIds(); + ids.resize(m_Dim); + + for (auto i=0; i CAlnReader::GetSeqAlign(const TFastaFlags fasta_flags) { if (m_Aln) { return m_Aln; @@ -292,7 +529,6 @@ CRef CAlnReader::GetSeqAlign() } typedef CDense_seg::TNumseg TNumseg; - typedef CDense_seg::TDim TNumrow; m_Aln = new CSeq_align(); m_Aln->SetType(CSeq_align::eType_not_set); @@ -301,12 +537,11 @@ CRef CAlnReader::GetSeqAlign() CDense_seg& ds = m_Aln->SetSegs().SetDenseg(); ds.SetDim(m_Dim); - CDense_seg::TIds& ids = ds.SetIds(); CDense_seg::TStarts& starts = ds.SetStarts(); //CDense_seg::TStrands& strands = ds.SetStrands(); CDense_seg::TLens& lens = ds.SetLens(); - ids.resize(m_Dim); + x_AssignDensegIds(fasta_flags, ds); // get the length of the alignment TSeqPos aln_stop = m_Seqs[0].size(); @@ -316,14 +551,6 @@ CRef CAlnReader::GetSeqAlign() } } - for (TNumrow row_i = 0; row_i < m_Dim; row_i++) { - CBioseq::TId xid; - if (CSeq_id::ParseFastaIds(xid, m_Ids[row_i], true) > 0) { - ids[row_i] = xid.front(); - } else { - ids[row_i] = new CSeq_id(CSeq_id::e_Local, m_Ids[row_i]); - } - } m_SeqVec.resize(m_Dim); for (TNumrow row_i = 0; row_i < m_Dim; row_i++) { @@ -348,9 +575,7 @@ CRef CAlnReader::GetSeqAlign() } else { string residue = m_Seqs[row_i].substr(aln_pos, 1); NStr::ToUpper(residue); - if (NStr::Find(m_MiddleGap, residue) == string::npos && - NStr::Find(m_EndGap, residue) == string::npos && - NStr::Find(m_BeginningGap, residue) == string::npos) { + if (!x_IsGap(row_i, aln_pos, residue)) { if (is_gap[row_i]) { is_gap[row_i] = false; @@ -414,7 +639,7 @@ CRef CAlnReader::GetSeqAlign() } -CRef CAlnReader::GetSeqEntry() +CRef CAlnReader::GetSeqEntry(const TFastaFlags fasta_flags) { if (m_Entry) { return m_Entry; @@ -424,8 +649,13 @@ CRef CAlnReader::GetSeqEntry() "Seq_entry is not available until after Read()", 0); } m_Entry = new CSeq_entry(); + + CRef seq_align = GetSeqAlign(fasta_flags); + const CDense_seg& denseg = seq_align->GetSegs().GetDenseg(); + _ASSERT(denseg.GetIds().size() == m_Dim); + CRef seq_annot (new CSeq_annot); - seq_annot->SetData().SetAlign().push_back(GetSeqAlign()); + seq_annot->SetData().SetAlign().push_back(seq_align); m_Entry->SetSet().SetClass(CBioseq_set::eClass_pop_set); m_Entry->SetSet().SetAnnot().push_back(seq_annot); @@ -441,12 +671,14 @@ CRef CAlnReader::GetSeqEntry() // seq-id(s) CBioseq::TId& ids = seq_entry->SetSeq().SetId(); + ids.push_back(denseg.GetIds()[row_i]); +/* CSeq_id::ParseFastaIds(ids, m_Ids[row_i], true); if (ids.empty()) { ids.push_back(CRef(new CSeq_id(CSeq_id::e_Local, m_Ids[row_i]))); } - +*/ // mol CSeq_inst::EMol mol = CSeq_inst::eMol_not_set; CSeq_id::EAccessionInfo ai = ids.front()->IdentifyAccession(); @@ -492,4 +724,27 @@ CRef CAlnReader::GetSeqEntry() return m_Entry; } + +void CAlnReader::ParseDefline(const string& defline, + const SDeflineParseInfo& info, + const TIgnoredProblems& ignoredErrors, + list>& ids, + bool& hasRange, + TSeqPos& rangeStart, + TSeqPos& rangeEnd, + TSeqTitles& seqTitles, + ILineErrorListener* pMessageListener) +{ + CFastaDeflineReader::ParseDefline( + defline, + info, + ignoredErrors, + ids, + hasRange, + rangeStart, + rangeEnd, + seqTitles, + pMessageListener); +} + END_NCBI_SCOPE diff --git a/c++/src/objtools/readers/bed_reader.cpp b/c++/src/objtools/readers/bed_reader.cpp index 2b5aa19d..eafcc435 100644 --- a/c++/src/objtools/readers/bed_reader.cpp +++ b/c++/src/objtools/readers/bed_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: bed_reader.cpp 518716 2016-11-07 18:15:34Z ivanov $ +/* $Id: bed_reader.cpp 538707 2017-06-13 16:57:06Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -148,6 +148,9 @@ CBedReader::ReadSeqAnnot( annot->SetDesc(*desc); m_CurrentFeatureCount = 0; + + xParseTrackLine("track", pEC); + string line; while (xGetLine(lr, line)) { @@ -273,7 +276,7 @@ CBedReader::xParseFeature( // parse vector fields; - NStr::Split( record_copy, " \t", fields, NStr::eMergeDelims ); + NStr::Split(record_copy, " \t", fields, NStr::fSplit_MergeDelimiters); try { xCleanColumnValues(fields); } @@ -575,12 +578,14 @@ void CBedReader::x_SetFeatureDisplayData( if ( !m_usescore ) { display_data->AddField( "score", - NStr::StringToInt(fields[4], NStr::fConvErr_NoThrow) ); + NStr::StringToInt(fields[4], + NStr::fConvErr_NoThrow|NStr::fAllowTrailingSymbols) ); } else { display_data->AddField( "greylevel", - NStr::StringToInt(fields[4], NStr::fConvErr_NoThrow) ); + NStr::StringToInt(fields[4], + NStr::fConvErr_NoThrow|NStr::fAllowTrailingSymbols) ); } } if ( m_columncount >= 7 ) { @@ -970,7 +975,7 @@ void CBedReader::xSetFeatureLocationRna( CRef pInterval(new CSeq_interval); pInterval->SetId(*pId); pInterval->SetFrom(blockStarts[i]); - pInterval->SetTo(blockStarts[i] + blockSizes[i]); + pInterval->SetTo(blockStarts[i] + blockSizes[i] -1); pInterval->SetStrand(strand); if (negative) blocks.insert(blocks.begin(), pInterval); @@ -1500,7 +1505,7 @@ CBedReader::xReadBedRecordRaw( NStr::TruncateSpacesInPlace(linecopy); // parse - NStr::Split( linecopy, " \t", columns, NStr::eMergeDelims ); + NStr::Split(linecopy, " \t", columns, NStr::fSplit_MergeDelimiters); try { xCleanColumnValues(columns); } @@ -1556,9 +1561,10 @@ CBedReader::xReadBedRecordRaw( } int score(-1); - if (m_columncount >= 7 && columns[6] != ".") { + if (m_columncount >= 5 && columns[4] != ".") { try { - score = NStr::StringToInt(columns[6]); + score = NStr::StringToInt(columns[4], + NStr::fConvErr_NoThrow|NStr::fAllowTrailingSymbols); } catch(std::exception&) { AutoPtr pErr( diff --git a/c++/src/objtools/readers/fasta.cpp b/c++/src/objtools/readers/fasta.cpp index baa852ea..51c5fb21 100644 --- a/c++/src/objtools/readers/fasta.cpp +++ b/c++/src/objtools/readers/fasta.cpp @@ -1,4 +1,4 @@ -/* $Id: fasta.cpp 520111 2016-11-22 19:00:06Z ivanov $ +/* $Id: fasta.cpp 541541 2017-07-19 13:48:44Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -80,9 +80,13 @@ #include #include +#include #include +// The "49518053" is just a random number to minimize the chance of the +// variable name conflicting with another variable name and has no +// particular meaning #define FASTA_LINE_EXPT(_eSeverity, _uLineNum, _MessageStrmOps, _eErrCode, _eProblem, _sFeature, _sQualName, _sQualValue) \ do { \ stringstream err_strm_49518053; \ @@ -90,6 +94,9 @@ PostWarning(pMessageListener, (_eSeverity), (_uLineNum), (err_strm_49518053.str()), (_eErrCode), (_eProblem), (_sFeature), (_sQualName), (_sQualValue)); \ } while(0) +// The "49518053" is just a random number to minimize the chance of the +// variable name conflicting with another variable name and has no +// particular meaning #define FASTA_PROGRESS(_MessageStrmOps) \ do { \ stringstream err_strm_49518053; \ @@ -172,68 +179,38 @@ inline bool s_ASCII_IsAlpha(unsigned char c) return s_ASCII_IsUpper(c) || s_ASCII_IsLower(c); } -inline unsigned char s_ASCII_ToUpper(unsigned char c) +// The arg *must* be a lowercase letter or this won't work +inline unsigned char s_ASCII_MustBeLowerToUpper(unsigned char c) { - return s_ASCII_IsLower(c) ? c + 'A' - 'a' : c; + return c + ('A' - 'a'); } inline bool s_ASCII_IsAmbigNuc(unsigned char c) { - switch( s_ASCII_ToUpper(c) ) { - case 'U': - case 'R': - case 'Y': - case 'S': - case 'W': - case 'K': - case 'M': - case 'B': - case 'D': - case 'H': - case 'V': - case 'N': + switch(c) { + case 'U': case 'u': + case 'R': case 'r': + case 'Y': case 'y': + case 'S': case 's': + case 'W': case 'w': + case 'K': case 'k': + case 'M': case 'm': + case 'B': case 'b': + case 'D': case 'd': + case 'H': case 'h': + case 'V': case 'v': + case 'N': case 'n': return true; default: return false; } } -inline bool s_ASCII_IsUnAmbigNuc(unsigned char c) +inline static bool s_ASCII_IsUnAmbigNuc(unsigned char c) { switch( c ) { - case 'A': - case 'C': - case 'G': - case 'T': - case 'a': - case 'c': - case 'g': - case 't': - return true; - default: - return false; - } -} - -inline bool s_ASCII_IsValidNuc(unsigned char c) -{ - switch( s_ASCII_ToUpper(c) ) { - case 'A': - case 'C': - case 'G': - case 'T': - case 'U': - case 'R': - case 'Y': - case 'S': - case 'W': - case 'K': - case 'M': - case 'B': - case 'D': - case 'H': - case 'V': - case 'N': + case 'A': case 'C': case 'G': case 'T': + case 'a': case 'c': case 'g': case 't': return true; default: return false; @@ -247,6 +224,7 @@ CFastaReader::CFastaReader(ILineReader& reader, TFlags flags) m_MaxIDLength(kMax_UI4) { m_Flags.push(flags); + m_IDHandler = Ref(new CFastaIdHandler()); } CFastaReader::CFastaReader(CNcbiIstream& in, TFlags flags) @@ -256,6 +234,7 @@ CFastaReader::CFastaReader(CNcbiIstream& in, TFlags flags) m_MaxIDLength(kMax_UI4) { m_Flags.push(flags); + m_IDHandler = Ref(new CFastaIdHandler()); } CFastaReader::CFastaReader(const string& path, TFlags flags) @@ -265,6 +244,7 @@ CFastaReader::CFastaReader(const string& path, TFlags flags) m_MaxIDLength(kMax_UI4) { m_Flags.push(flags); + m_IDHandler = Ref(new CFastaIdHandler()); } CFastaReader::CFastaReader(CReaderBase::TReaderFlags fBaseFlags, TFlags flags) @@ -274,6 +254,7 @@ CFastaReader::CFastaReader(CReaderBase::TReaderFlags fBaseFlags, TFlags flags) m_MaxIDLength(kMax_UI4) { m_Flags.push(flags); + m_IDHandler = Ref(new CFastaIdHandler()); } CFastaReader::~CFastaReader(void) @@ -286,15 +267,6 @@ void CFastaReader::SetMinGaps(TSeqPos gapNmin, TSeqPos gap_Unknown_length) m_gapNmin = gapNmin; m_gap_Unknown_length = gap_Unknown_length; } -inline -void CFastaReader::CloseGap(bool atStartOfLine, ILineErrorListener * pMessageListener) -{ - if (m_CurrentGapLength > 0) { - x_CloseGap(m_CurrentGapLength, atStartOfLine, pMessageListener); - m_CurrentGapLength = 0; - } -} - CRef CFastaReader::ReadObject (ILineReader &lr, ILineErrorListener *pMessageListener) { @@ -467,7 +439,7 @@ CRef CFastaReader::x_ReadSegSet(ILineErrorListener * pMessageListene CBioseq& master_seq = master->SetSeq(); CSeq_inst& inst = master_seq.SetInst(); // XXX - work out less generic ID? - CRef id(SetIDGenerator().GenerateID(true)); + CRef id(m_IDHandler->SetGenerator().GenerateID(true)); if (m_CurrentMask) { m_CurrentMask->SetId(*id); } @@ -531,11 +503,11 @@ CRef CFastaReader::SaveMask(void) void CFastaReader::SetIDGenerator(CSeqIdGenerator& gen) { - m_IDGenerator.Reset(&gen); + m_IDHandler->SetGenerator(gen); } -// This method does not use CRef to access range -// information for reasons of efficiency - RW-26 +// For reasons of efficiency, this method does not use +// CRef to access range information - RW-26 void CFastaReader::ParseDefLine(const TStr& defLine, const SDefLineParseInfo& info, const TIgnoredProblems& ignoredErrors, @@ -544,130 +516,63 @@ void CFastaReader::ParseDefLine(const TStr& defLine, TSeqPos& rangeStart, TSeqPos& rangeEnd, TSeqTitles& seqTitles, - ILineErrorListener * pMessageListener) -{ - size_t start = 1, pos, len = defLine.length(), title_start; - size_t range_len = 0; - const TFlags& fFastaFlags = info.fFastaFlags; - const size_t& lineNumber = info.lineNumber; - - // ignore spaces between '>' and the sequence ID - for( ; start < len; ++start ) { - if( ! isspace(defLine[start]) ) { - break; - } + ILineErrorListener* pMessageListener) +{ + CFastaDeflineReader::ParseDefline( + defLine, + info, + ignoredErrors, + ids, + hasRange, + rangeStart, + rangeEnd, + seqTitles, + pMessageListener); +} + + +CRef CFastaReader::xCreateAlignment(CRef old_id, + CRef new_id, + TSeqPos range_start, + TSeqPos range_end) +{ + CRef align(new CSeq_align()); + align->SetType(CSeq_align::eType_partial); // ? + align->SetDim(2); + CDense_seg& denseg = align->SetSegs().SetDenseg(); + denseg.SetNumseg(1); + denseg.SetDim(2); // redundant, but required by validator + denseg.SetIds().push_back(new_id); + denseg.SetIds().push_back(old_id); + denseg.SetStarts().push_back(0); + denseg.SetStarts().push_back(range_start); + if (range_start > range_end) { // negative strand + denseg.SetLens().push_back(range_start + 1 - range_end); + denseg.SetStrands().push_back(eNa_strand_plus); + denseg.SetStrands().push_back(eNa_strand_minus); + } else { + denseg.SetLens().push_back(range_end + 1 - range_start); } - do { - bool has_id = true; - if ((fFastaFlags & fNoParseID)) { - title_start = start; - } else { - // This loop finds the end of the sequence ID - for ( pos = start; pos < len; ++pos) { - unsigned char c = defLine[pos]; - - if (c <= ' ' ) { // assumes ASCII - break; - } else if( c == '[' ) { - - // see if this is part of a FASTA mod, which - // implies a pattern like "[key=value]". We only check - // that it looks *roughly* like a FASTA mod and only before the '=' - // - // It might be worth it to put the body of this "if" into its own function, - // for clarity if nothing else. - - const size_t left_bracket_pos = pos; - ++pos; - - // arbitrary, but shouldn't be too much bigger than the largest possible mod key for efficiency - const static size_t kMaxCharsToLookAt = 30; - // we give up much sooner than the length of the string, if the string is long. - // also note that we give up *before* the end so even if pos - // reaches bracket_give_up_pos, we can still say defLine[pos] without worrying - // about array-out-of-bounds issues. - const size_t bracket_give_up_pos = min(len - 1, kMaxCharsToLookAt); - // keep track of the first space we find, because that becomes the end of the seqid - // if this turns out not to be a FASTA mod. - size_t first_space_pos = kMax_UI4; - - // find the end of the key - for( ; pos < bracket_give_up_pos ; ++pos ) { - const unsigned char c = defLine[pos]; - if( c == '=' ) { - break; - } else if( c <= ' ' ) { - first_space_pos = min(first_space_pos, pos); - // keep going - } else if( isalnum(c) || c == '-' || c == '_' ) { - // this is fine; keep going - } else { - // bad character, so this is NOT a FASTA mod - break; - } - } + return align; +} - if( defLine[pos] == '=' ) { - // this seems to be a FASTA mod, so consider the left square bracket - // to be the end of the seqid - pos = left_bracket_pos; - break; - } else { - // if we stopped on anything but an equal sign, this is NOT a - // FASTA mod. - if( first_space_pos < len ) { - // If we've found a space at any point, we consider that the end of the seq-id - pos = first_space_pos; - break; - } - // it's not a FASTA mod and we didn't find any spaces, so just - // keep going as normal, continuing from where we let off at "pos" - } - } - } +bool CFastaReader::xSetSeqMol(const list>& ids, CSeq_inst_Base::EMol& mol) { - range_len = ParseRange(TStr(defLine.data() + start, pos - start), - rangeStart, rangeEnd, pMessageListener); - has_id = ParseIDs(TStr(defLine.data() + start, pos - start - range_len), - info, - ignoredErrors, - ids, - pMessageListener); - if (has_id && (fFastaFlags & fAllSeqIds) && defLine[pos] == '\1') { - start = pos + 1; - continue; - } - title_start = pos; - // trim leading whitespace from title (is this appropriate?) - while (title_start < len - && isspace((unsigned char) defLine[title_start])) { - ++title_start; - } - } - for (pos = title_start + 1; pos < len; ++pos) { - if ((unsigned char) defLine[pos] < ' ') { - break; - } - } - if ( !has_id ) { - // no IDs after all, so take the whole line as a title - // (done now rather than earlier to avoid rescanning) - title_start = start; - } - if (title_start < min(pos, len)) { - // we parse the titles after we know what molecule this is - seqTitles.push_back( - SLineTextAndLoc( - defLine.substr(title_start, pos - title_start), lineNumber)); + for (auto pId : ids) { + const CSeq_id::EAccessionInfo acc_info = pId->IdentifyAccession(); + if (acc_info & CSeq_id::fAcc_nuc) { + mol = CSeq_inst::eMol_na; + return true; } - start = pos + 1; - } while ( (fFastaFlags & fAllSeqIds) && start < len && defLine[start - 1] == '\1' - && !range_len); - - hasRange = (range_len>0); + if (acc_info & CSeq_id::fAcc_prot) { + mol = CSeq_inst::eMol_aa; + return true; + } + } + return false; } @@ -681,70 +586,40 @@ void CFastaReader::ParseDefLine(const TStr& s, ILineErrorListener * pMessageList parseInfo.maxIdLength = m_MaxIDLength; parseInfo.lineNumber = LineNumber(); - ParseDefLine(s, + CBioseq::TId defline_ids; + + CFastaDeflineReader::ParseDefline(s, parseInfo, m_ignorable, - SetIDs(), + defline_ids, has_range, range_start, range_end, m_CurrentSeqTitles, pMessageListener); - if (GetIDs().empty()) { - // No [usable] IDs + + if (defline_ids.empty()) { if (TestFlag(fRequireID)) { + // No [usable] IDs FASTA_ERROR(LineNumber(), - "CFastaReader: Defline lacks a proper ID around line " << LineNumber(), - CObjReaderParseException::eNoIDs ); + "CFastaReader: Defline lacks a proper ID around line " << LineNumber(), + CObjReaderParseException::eNoIDs ); } - GenerateID(); - } else if ( !TestFlag(fForceType) ) { - // Does any ID imply a specific type? - ITERATE (CBioseq::TId, it, GetIDs()) { - CSeq_id::EAccessionInfo acc_info = (*it)->IdentifyAccession(); - if (acc_info & CSeq_id::fAcc_nuc) { - _ASSERT ( !(acc_info & CSeq_id::fAcc_prot) ); - m_CurrentSeq->SetInst().SetMol(CSeq_inst::eMol_na); - break; - } else if (acc_info & CSeq_id::fAcc_prot) { - m_CurrentSeq->SetInst().SetMol(CSeq_inst::eMol_aa); - break; - } - // XXX - verify that other IDs aren't contradictory? + } + else if (!TestFlag(fForceType)) { + CSeq_inst::EMol mol; + if (xSetSeqMol(defline_ids, mol)) { + m_CurrentSeq->SetInst().SetMol(mol); } } - m_BestID = FindBestChoice(GetIDs(), CSeq_id::BestRank); + PostProcessIDs(defline_ids, s, has_range, range_start, range_end); - if (has_range) { - // generate a new ID, and record its relation to the given one(s). - SetIDs().clear(); - GenerateID(); - CRef sa(new CSeq_align); - sa->SetType(CSeq_align::eType_partial); // ? - sa->SetDim(2); - CDense_seg& ds = sa->SetSegs().SetDenseg(); - ds.SetNumseg(1); - ds.SetDim(2); // redundant, but required by validator - ds.SetIds().push_back(GetIDs().front()); - ds.SetIds().push_back(m_BestID); - ds.SetStarts().push_back(0); - ds.SetStarts().push_back(range_start); - if (range_start > range_end) { // negative strand - ds.SetLens().push_back(range_start + 1 - range_end); - ds.SetStrands().push_back(eNa_strand_plus); - ds.SetStrands().push_back(eNa_strand_minus); - } else { - ds.SetLens().push_back(range_end + 1 - range_start); - } - m_CurrentSeq->SetInst().SetHist().SetAssembly().push_back(sa); - _ASSERT(m_BestID->IsLocal() || !GetIDs().front()->IsLocal() - || m_CurrentSeq->GetNonLocalId() == &*m_BestID); - m_BestID = GetIDs().front(); + m_BestID = FindBestChoice(GetIDs(), CSeq_id::BestRank); + if(has_range) { m_ExpectedEnd = range_end - range_start; } - FASTA_PROGRESS("Processing Seq-id: " << ( m_BestID ? m_BestID->AsFastaString() : string("UNKNOWN") ) ); @@ -759,7 +634,7 @@ void CFastaReader::ParseDefLine(const TStr& s, ILineErrorListener * pMessageList if (TestFlag(fUniqueIDs)) { ITERATE (CBioseq::TId, it, GetIDs()) { CSeq_id_Handle h = CSeq_id_Handle::GetHandle(**it); - if ( !m_IDTracker.insert(h).second ) { + if ( !m_IDHandler->CacheIdHandle(h) ) { FASTA_ERROR(LineNumber(), "CFastaReader: Seq-id " << h.AsString() << " is a duplicate around line " << LineNumber(), @@ -770,240 +645,71 @@ void CFastaReader::ParseDefLine(const TStr& s, ILineErrorListener * pMessageList } -bool CFastaReader::ParseIDs( - const TStr& s, - const SDefLineParseInfo& info, - const TIgnoredProblems& ignoredErrors, - list>& ids, - ILineErrorListener * pMessageListener) +void CFastaReader::PostProcessIDs( + const CBioseq::TId& defline_ids, + const string& defline, + const bool has_range, + const TSeqPos range_start, + const TSeqPos range_end) { - // if user wants all ids to be purely local, no problem - if( info.fBaseFlags & CReaderBase::fAllIdsAsLocal ) - { - ids.push_back(Ref(new CSeq_id(CSeq_id::e_Local, s))); - return true; - } - - size_t count = 0; - // be generous overall, and give raw local IDs the benefit of the - // doubt for now - CSeq_id::TParseFlags flags - = CSeq_id::fParse_PartialOK | CSeq_id::fParse_AnyLocal; - if ( info.fFastaFlags & fParseRawID ) { - flags |= CSeq_id::fParse_RawText; + if (defline_ids.empty()) { + GenerateID(); + } + else { + SetIDs() = defline_ids; } - const bool ignoreError - = (find(ignoredErrors.cbegin(), ignoredErrors.cend(), ILineError::eProblem_GeneralParsingError) - != ignoredErrors.cend()); - - try { - if (s.find(',') != TStr::npos && s.find('|') == TStr::npos) - { - string temp = NStr::Replace(s, ",", "_"); - count = CSeq_id::ParseIDs(ids, temp, flags); - - const string errMessage = - "CFastaReader: Near line " + NStr::NumericToString(info.lineNumber) - + ", the sequence contains 'comma' symbol and replaced with 'underscore' " - + "symbol. Please find and correct the sequence id."; - - if (!ignoreError) { - PostWarning(pMessageListener, - info.lineNumber, - errMessage, - CObjReaderParseException::eFormat); + if (has_range) { + auto old_id = FindBestChoice(GetIDs(), CSeq_id::BestRank); + // generate a new ID, and record its relation to the given one(s). + SetIDs().clear(); + GenerateID(); - } - } - else - { - count = CSeq_id::ParseIDs(ids, s, flags); - } - } catch (CSeqIdException&) { - // swap(ids, old_ids); - } + CRef align = xCreateAlignment(old_id, + GetIDs().front(), range_start, range_end); - // numerics become local, if requested - if( info.fBaseFlags & CReaderBase::fNumericIdsAsLocal ) { - NON_CONST_ITERATE(CBioseq::TId, id_it, ids) { - CSeq_id & id = **id_it; - if( id.IsGi() ) { - const TGi gi = id.GetGi(); - id.SetLocal().SetStr( NStr::NumericToString(gi) ); - } - } + m_CurrentSeq->SetInst().SetHist().SetAssembly().push_back(align); } - // recheck raw local IDs - if (count == 1 && ids.back()->IsLocal()) - { - string temp; - ids.back()->GetLabel(&temp, 0, CSeq_id::eContent); - if (!IsValidLocalID(temp, info.fFastaFlags)) - { - ids.clear(); - return false; - } - } - // check if ID was too long, use only - if( count == 1) - { - CTempString check; - size_t last = s.rfind('|'); - check = (last == CTempString::npos) ? s : s.substr(last + 1); - if (check.length() > info.maxIdLength) { - - // before throwing an ID-too-long error, check if what we - // think is a "sequence ID" is actually sequence data - if (ExcessiveSeqDataInTitle(s, info.fFastaFlags)) { - return false; - } - - const string errMessage = - "CFastaReader: Near line " + NStr::NumericToString(info.lineNumber) - + ", the sequence ID is too long. Its length is " + NStr::NumericToString(s.length()) - + " but the max length allowed is "+ NStr::NumericToString(info.maxIdLength) - + ". Please find and correct all sequence IDs that are too long."; +} - if (!ignoreError) { - PostError(pMessageListener, - info.lineNumber, - errMessage, - CObjReaderParseException::eIDTooLong); - } - } - } - return count > 0; +bool CFastaReader::ParseIDs( + const TStr& s, + const SDefLineParseInfo& info, + const TIgnoredProblems& ignoredErrors, + list>& ids, + ILineErrorListener * pMessageListener) +{ + return CFastaDeflineReader::ParseIDs(s, info, ignoredErrors, ids, pMessageListener); } bool CFastaReader::ParseIDs( const TStr& s, ILineErrorListener * pMessageListener) { - // if user wants all ids to be purely local, no problem - if( m_iFlags & CReaderBase::fAllIdsAsLocal ) - { - return new CSeq_id(CSeq_id::e_Local, s); - } - CBioseq::TId& ids = SetIDs(); - // CBioseq::TId old_ids = ids; - size_t count = 0; - // be generous overall, and give raw local IDs the benefit of the - // doubt for now - CSeq_id::TParseFlags flags - = CSeq_id::fParse_PartialOK | CSeq_id::fParse_AnyLocal; - if (TestFlag(fParseRawID)) { - flags |= CSeq_id::fParse_RawText; - } - try { - if (s.find(',') != TStr::npos && s.find('|') == TStr::npos) - { - string temp = NStr::Replace(s, ",", "_"); - count = CSeq_id::ParseIDs(ids, temp, flags); - FASTA_WARNING(LineNumber(), - "CFastaReader: Near line " << LineNumber() - << ", the sequence contains 'comma' symbol and replaced with 'underscore' " - << "symbol. Please find and correct the sequence id.", - ILineError::eProblem_GeneralParsingError, ""); - } - else - { - count = CSeq_id::ParseIDs(ids, s, flags); - } - } catch (CSeqIdException&) { - // swap(ids, old_ids); - } + SDefLineParseInfo info; + info.fBaseFlags = m_iFlags; + info.fFastaFlags = GetFlags(); + info.maxIdLength = m_MaxIDLength; + info.lineNumber = LineNumber(); - // numerics become local, if requested - if( m_iFlags & CReaderBase::fNumericIdsAsLocal ) { - NON_CONST_ITERATE(CBioseq::TId, id_it, ids) { - CSeq_id & id = **id_it; - if( id.IsGi() ) { - const TGi gi = id.GetGi(); - id.SetLocal().SetStr( NStr::NumericToString(gi) ); - } - } - } - // recheck raw local IDs - if (count == 1 && ids.back()->IsLocal()) - { - string temp; - ids.back()->GetLabel(&temp, 0, CSeq_id::eContent); - if (!IsValidLocalID(temp)) - { - //&& !NStr::StartsWith(s, "lcl|", NStr::eNocase) - ids.clear(); - return false; - } - } - // check if ID was too long, use only - if( count == 1) - { - CTempString check; - size_t last = s.rfind('|'); - check = (last == CTempString::npos) ? s : s.substr(last + 1); - if (check.length() > m_MaxIDLength ) { - - // before throwing an ID-too-long error, check if what we - // think is a "sequence ID" is actually sequence data - CMessageListenerLenient dummy_err_container; // so we can ignore them - if( CreateWarningsForSeqDataInTitle(s, LineNumber(), &dummy_err_container) ) { - // it's actually seq data - return false; - } - - FASTA_ERROR(LineNumber(), - "CFastaReader: Near line " << LineNumber() - << ", the sequence ID is too long. Its length is " << s.length() - << " but the max length allowed is " << m_MaxIDLength - << ". Please find and correct all sequence IDs that are too long.", - CObjReaderParseException::eIDTooLong); - } - } - return count > 0; + return CFastaDeflineReader::ParseIDs(s, info, m_ignorable, SetIDs(), pMessageListener); } + size_t CFastaReader::ParseRange( const TStr& s, TSeqPos& start, TSeqPos& end, - ILineErrorListener * pMessageListener) + ILineErrorListener* pMessageListener) { - bool on_start = false; - bool negative = false; - TSeqPos mult = 1; - size_t pos; - start = end = 0; - for (pos = s.length() - 1; pos > 0; --pos) { - unsigned char c = s[pos]; - if (c >= '0' && c <= '9') { - if (on_start) { - start += (c - '0') * mult; - } else { - end += (c - '0') * mult; - } - mult *= 10; - } else if (c == '-' && !on_start && mult > 1) { - on_start = true; - mult = 1; - } else if (c == ':' && on_start && mult > 1) { - break; - } else if (c == 'c' && pos > 0 && s[--pos] == ':' - && on_start && mult > 1) { - negative = true; - break; - } else { - return 0; // syntax error - } - } - if ((negative ? (end > start) : (start > end)) || s[pos] != ':') { - return 0; - } - --start; - --end; - return s.length() - pos; + return CFastaDeflineReader::ParseRange( + s, + start, + end, + pMessageListener); } + void CFastaReader::ParseTitle( const SLineTextAndLoc & lineInfo, ILineErrorListener * pMessageListener) { @@ -1026,11 +732,13 @@ void CFastaReader::ParseTitle( x_ApplyAllMods(*m_CurrentSeq, lineInfo.m_iLineNum, pMessageListener); } + bool CFastaReader::IsValidLocalID(const TStr& s) const { return IsValidLocalID(s, GetFlags()); } + bool CFastaReader::IsValidLocalID(const TStr& idString, const TFlags fFastaFlags) { @@ -1043,18 +751,11 @@ bool CFastaReader::IsValidLocalID(const TStr& idString, void CFastaReader::GenerateID(void) { - if (TestFlag(fUniqueIDs)) { // be extra careful - CRef id; - TIDTracker::const_iterator idt_end = m_IDTracker.end(); - do { - id = m_IDGenerator->GenerateID(true); - } while (m_IDTracker.find(CSeq_id_Handle::GetHandle(*id)) != idt_end); - SetIDs().push_back(id); - } else { - SetIDs().push_back(m_IDGenerator->GenerateID(true)); - } + CRef id = m_IDHandler->GenerateID(TestFlag(fUniqueIDs)); + SetIDs().push_back(id); } + void CFastaReader::CheckDataLine( const TStr& s, ILineErrorListener * pMessageListener) { @@ -1064,13 +765,18 @@ void CFastaReader::CheckDataLine( return; } const bool bIgnoreHyphens = TestFlag(fHyphensIgnoreAndWarn); - size_t good = 0, bad = 0, len = s.length(); + size_t good = 0, bad = 0; + // in case the data has huge sequences all on the first line we do need + // a cutoff and "70" seems reasonable since it's the default width of + // CFastaOstream (as of 2017-03-09) + size_t len_to_check = min(s.length(), + static_cast(70)); const bool bIsNuc = ( ( TestFlag(fAssumeNuc) && TestFlag(fForceType) ) || ( m_CurrentSeq && m_CurrentSeq->IsSetInst() && m_CurrentSeq->GetInst().IsSetMol() && m_CurrentSeq->IsNa() ) ); size_t ambig_nuc = 0; - for (size_t pos = 0; pos < len; ++pos) { + for (size_t pos = 0; pos < len_to_check; ++pos) { unsigned char c = s[pos]; if (s_ASCII_IsAlpha(c) || c == '*') { ++good; @@ -1091,7 +797,9 @@ void CFastaReader::CheckDataLine( ++bad; } } - if (bad >= good / 3 && (len > 3 || good == 0 || bad > good)) { + if (bad >= good / 3 && + (len_to_check > 3 || good == 0 || bad > good)) + { FASTA_ERROR( LineNumber(), "CFastaReader: Near line " << LineNumber() << ", there's a line that doesn't look like plausible data, " @@ -1101,9 +809,9 @@ void CFastaReader::CheckDataLine( // warn if more than a certain percentage is ambiguous nucleotides const static size_t kWarnPercentAmbiguous = 40; // e.g. "40" means "40%" const size_t percent_ambig = (good == 0)?100:((ambig_nuc * 100) / good); - if( len > 3 && percent_ambig > kWarnPercentAmbiguous ) { + if( len_to_check > 3 && percent_ambig > kWarnPercentAmbiguous ) { FASTA_WARNING(LineNumber(), - "FASTA-Reader: First data line in seq is about " + "FASTA-Reader: Start of first data line in seq is about " << percent_ambig << "% ambiguous nucleotides (shouldn't be over " << kWarnPercentAmbiguous << "%)", ILineError::eProblem_TooManyAmbiguousResidues, @@ -1111,6 +819,7 @@ void CFastaReader::CheckDataLine( } } + void CFastaReader::ParseDataLine( const TStr& s, ILineErrorListener * pMessageListener) { @@ -1121,33 +830,40 @@ void CFastaReader::ParseDataLine( CheckDataLine(s, pMessageListener); - size_t len = min(s.length(), s.find(';')); // ignore ;-delimited comments - if (m_SeqData.capacity() < m_SeqData.size() + len) { + // most lines won't have a comment (';') so optimize for that case as + // much as possible + + const size_t s_len = s.length(); // avoid checking over and over + + if (m_SeqData.capacity() < m_SeqData.size() + s_len) { // ensure exponential capacity growth to avoid quadratic runtime - m_SeqData.reserve(2 * max(m_SeqData.capacity(), len)); + m_SeqData.reserve(2 * max(m_SeqData.capacity(), s_len)); } + if ((GetFlags() & (fSkipCheck | fParseGaps | fValidate)) == fSkipCheck - && m_CurrentMask.Empty()) { - m_SeqData.append(s.data(), len); - m_CurrentPos += len; + && m_CurrentMask.Empty()) + { + // copy until comment char or end of line + size_t pos = 0; + char c = '\0'; + for( ; pos < s_len && (c = s[pos]) != ';'; ++pos) { + m_SeqData.push_back(c); + } + m_CurrentPos += pos; return; } // we're stricter with nucs, so try to determine if we should // assume this is a nuc - bool bIsNuc = false; - if( ! TestFlag(fForceType) && - FIELD_CHAIN_OF_2_IS_SET(*m_CurrentSeq, Inst, Mol) ) - { - if( m_CurrentSeq->IsNa() ) { - bIsNuc = true; - } - } else { - bIsNuc = TestFlag(fAssumeNuc); - } - - m_SeqData.resize(m_CurrentPos + len); + const bool bIsNuc = ( + (! TestFlag(fForceType) && + FIELD_CHAIN_OF_2_IS_SET(*m_CurrentSeq, Inst, Mol)) + ? m_CurrentSeq->IsNa() + : TestFlag(fAssumeNuc) + ); + m_SeqData.resize(m_CurrentPos + s_len); + // these will stay as -1 and empty unless there's an error int bad_pos_line_num = -1; vector bad_pos_vec; @@ -1160,43 +876,158 @@ void CFastaReader::ParseDataLine( bool bIgnorableHyphenSeen = false; - const char chLetterGap_lc = ( bIsNuc ? 'N' : 'X'); - const char chLetterGap_uc = ( bIsNuc ? 'n' : 'x'); - for (size_t pos = 0; pos < len; ++pos) { - unsigned char c = s[pos]; - if ( ( (c == '-') && bHyphensAreGaps) || - ( (c == chLetterGap_lc || c == chLetterGap_uc) && bAllowLetterGaps) ) - { + // indicates how the char should be treated + enum ECharType { + eCharType_NormalNonGap, + eCharType_MaskedNonGap, + eCharType_Gap, + eCharType_JustIgnore, + eCharType_HyphenToIgnoreAndWarn, + eCharType_Comment, + eCharType_Bad, + }; + + for (size_t pos = 0; pos < s_len; ++pos) { + const unsigned char c = s[pos]; + + // figure out what exactly should be done with the char + ECharType char_type = eCharType_Bad; + switch(c) { + // try to keep cases with consecutive letters on the same line + // and try to have all cases with the same result in alphabetical + // order. This will to make it easier to + // tell if a letter was skipped or entered mult times + + // some cases just set char_type but others can be implemented right + // in the first switch followed by a continue. Try to minimize the + // latter because they can make this switch very long + + case 'A': case 'B': case 'C': case 'D': + case 'G': case 'H': + case 'K': + case 'M': + case 'R': case 'S': case 'T': case 'U': case 'V': case 'W': + case 'Y': + CloseGap(pos == 0); + m_SeqData[m_CurrentPos] = c; + CloseMask(); + ++m_CurrentPos; + continue; + case 'a': case 'b': case 'c': case 'd': + case 'g': case 'h': + case 'k': + case 'm': + case 'r': case 's': case 't': case 'u': case 'v': case 'w': + case 'y': + char_type = eCharType_MaskedNonGap; + break; + + case 'E': case 'F': + case 'I': case 'J': + case 'L': + case 'O': case 'P': case 'Q': + case 'Z': + case '*': + if( bIsNuc ) { + char_type = eCharType_Bad; + } else { + CloseGap(pos == 0); + m_SeqData[m_CurrentPos] = c; + CloseMask(); + ++m_CurrentPos; + continue; + } + break; + case 'e': case 'f': + case 'i': case 'j': + case 'l': + case 'o': case 'p': case 'q': + case 'z': + char_type = (bIsNuc ? eCharType_Bad : eCharType_MaskedNonGap ); + break; + + case 'N': + char_type = ( bIsNuc && bAllowLetterGaps ? + eCharType_Gap : eCharType_NormalNonGap ); + break; + case 'n': + char_type = ( bIsNuc && bAllowLetterGaps ? + eCharType_Gap : eCharType_MaskedNonGap ); + break; + + case 'X': + char_type = ( bIsNuc ? eCharType_Bad : + bAllowLetterGaps ? eCharType_Gap : + eCharType_NormalNonGap); + break; + case 'x': + char_type = ( bIsNuc ? eCharType_Bad : + bAllowLetterGaps ? eCharType_Gap : + eCharType_MaskedNonGap); + break; + + case '-': + char_type = ( + bHyphensAreGaps ? eCharType_Gap : + bHyphensIgnoreAndWarn ? eCharType_HyphenToIgnoreAndWarn : + eCharType_NormalNonGap ); + break; + case ';': + char_type = eCharType_Comment; + break; + + case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': + continue; + + default: + char_type = eCharType_Bad; + break; + } + + switch(char_type) { + case eCharType_NormalNonGap: + CloseGap(pos == 0); + m_SeqData[m_CurrentPos] = c; + CloseMask(); + ++m_CurrentPos; + break; + case eCharType_MaskedNonGap: + CloseGap(pos == 0); + m_SeqData[m_CurrentPos] = s_ASCII_MustBeLowerToUpper(c); + OpenMask(); + ++m_CurrentPos; + break; + case eCharType_Gap: { CloseMask(); // open a gap + size_t pos2 = pos + 1; - while (pos2 < len && s[pos2] == c) { + while( pos2 < s_len && s[pos2] == c ) { ++pos2; } + _ASSERT(pos2 <= s_len); m_CurrentGapLength += pos2 - pos; m_CurrentGapChar = toupper(c); - pos = pos2 - 1; - } else if( c == '-' && bHyphensIgnoreAndWarn ) { + pos = pos2 - 1; // `- 1` compensates for the `++pos` in the `for` + break; + } + case eCharType_JustIgnore: + break; + case eCharType_HyphenToIgnoreAndWarn: bIgnorableHyphenSeen = true; - } else if ( - s_ASCII_IsValidNuc(c) || - ( ! bIsNuc && ( s_ASCII_IsAlpha(c) || c == '*' ) ) || - c == '-' ) - { - CloseGap(pos == 0); - if (s_ASCII_IsLower(c)) { - m_SeqData[m_CurrentPos] = s_ASCII_ToUpper(c); - OpenMask(); - } else { - m_SeqData[m_CurrentPos] = c; - CloseMask(); - } - ++m_CurrentPos; - } else if ( !isspace(c) ) { + break; + case eCharType_Comment: + // artificially advance pos to the end to break the pos loop + pos = s_len; + break; + case eCharType_Bad: if( bad_pos_line_num < 0 ) { bad_pos_line_num = LineNumber(); } bad_pos_vec.push_back(pos); + break; + default: + _TROUBLE; } } @@ -1405,6 +1236,20 @@ bool CFastaReader::ParseGapLine( SGap::TNullableGapType pGapType; CSeq_gap::ELinkEvid eLinkEvid = CSeq_gap::eLinkEvid_UnspecifiedOnly; set setOfLinkageEvidence; + + if (m_gap_type && modKeyValueMultiMap.empty()) // fall back to default values coming from caller + { + pGapType = m_gap_type; + setOfLinkageEvidence = m_gap_linkage_evidence; + for (const auto& rec : CSeq_gap::GetNameToGapTypeInfoMap()) + { + if (rec.second.m_eType == *pGapType) + { + eLinkEvid = rec.second.m_eLinkEvid; + } + } + } + ITERATE(TModKeyValueMultiMap, modKeyValue_it, modKeyValueMultiMap) { const TStr & sKey = modKeyValue_it->first; const TStr & sValue = modKeyValue_it->second; @@ -1437,8 +1282,8 @@ bool CFastaReader::ParseGapLine( // could be semi-colon separated vector arrLinkageEvidences; - NStr::Tokenize(sValue, ";", arrLinkageEvidences, - NStr::eMergeDelims); + NStr::Split(sValue, ";", arrLinkageEvidences, + NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); ITERATE(vector, link_evid_it, arrLinkageEvidences) { CTempString sLinkEvid = *link_evid_it; @@ -1809,20 +1654,17 @@ CFastaReader::CreateWarningsForSeqDataInTitle( TSeqPos iLineNum, ILineErrorListener * pMessageListener) const { - bool bFoundProblem = false; // check for nuc or aa sequences at the end of the title const static size_t kWarnNumNucCharsAtEnd = 20; const static size_t kWarnAminoAcidCharsAtEnd = 50; - if (TestFlag(fAssumeProt)) - { - } - else - if( sLineText.length() > kWarnNumNucCharsAtEnd ) { + const size_t length = sLineText.length(); + SIZE_TYPE pos_to_check = length-1; + + if((length > kWarnNumNucCharsAtEnd) && !TestFlag(fAssumeProt)) { // find last non-nuc character, within the last kWarnNumNucCharsAtEnd characters - SIZE_TYPE pos_to_check = (sLineText.length() - 1); const SIZE_TYPE last_pos_to_check_for_nuc = (sLineText.length() - kWarnNumNucCharsAtEnd); for( ; pos_to_check >= last_pos_to_check_for_nuc; --pos_to_check ) { if( ! s_ASCII_IsUnAmbigNuc(sLineText[pos_to_check]) ) { @@ -1838,38 +1680,40 @@ CFastaReader::CreateWarningsForSeqDataInTitle( ILineError::eProblem_UnexpectedNucResidues, "defline" ); - bFoundProblem = true; - } else if( sLineText.length() > kWarnAminoAcidCharsAtEnd ) { - // check for aa's at the end of the title - // for efficiency, continue where the nuc search left off, since - // we know that nucs can be amino acids, also - const SIZE_TYPE last_pos_to_check_for_amino_acid = - ( sLineText.length() - kWarnAminoAcidCharsAtEnd ); - for( ; pos_to_check >= last_pos_to_check_for_amino_acid; --pos_to_check ) { - // can't just use "isalpha" in case it includes characters - // with diacritics (an accent, tilde, umlaut, etc.) - const char ch = sLineText[pos_to_check]; - if( ( ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ) { - // potential amino acid, so keep going - } else { - // non-amino-acid found - break; - } + return true; // found problem + } + } + + if((length > kWarnAminoAcidCharsAtEnd) && !TestFlag(fAssumeNuc)) { + // check for aa's at the end of the title + // for efficiency, continue where the nuc search left off, since + // we know that nucs can be amino acids, also + const SIZE_TYPE last_pos_to_check_for_amino_acid = + ( sLineText.length() - kWarnAminoAcidCharsAtEnd ); + for( ; pos_to_check >= last_pos_to_check_for_amino_acid; --pos_to_check ) { + // can't just use "isalpha" in case it includes characters + // with diacritics (an accent, tilde, umlaut, etc.) + const char ch = sLineText[pos_to_check]; + if( ( ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ) { + // potential amino acid, so keep going + } else { + // non-amino-acid found + break; } + } - if( pos_to_check < last_pos_to_check_for_amino_acid ) { - FASTA_WARNING(iLineNum, - "FASTA-Reader: Title ends with at least " << kWarnAminoAcidCharsAtEnd - << " valid amino acid characters. Was the sequence " - << "accidentally put in the title line?", - ILineError::eProblem_UnexpectedAminoAcids, - "defline"); - bFoundProblem = true; - } + if( pos_to_check < last_pos_to_check_for_amino_acid ) { + FASTA_WARNING(iLineNum, + "FASTA-Reader: Title ends with at least " << kWarnAminoAcidCharsAtEnd + << " valid amino acid characters. Was the sequence " + << "accidentally put in the title line?", + ILineError::eProblem_UnexpectedAminoAcids, + "defline"); + return true; // found problem } } - return bFoundProblem; + return false; } CRef CFastaReader::ReadAlignedSet( @@ -2039,53 +1883,25 @@ void CFastaReader::x_AddMultiwayAlignment(CSeq_annot& annot, const TIds& ids) } -CRef CSeqIdGenerator::GenerateID(bool advance) -{ - CRef seq_id(new CSeq_id); - int n = advance ? m_Counter.Add(1) - 1 : m_Counter.Get(); - if (m_Prefix.empty() && m_Suffix.empty()) { - seq_id->SetLocal().SetId(n); - } else { - string& id = seq_id->SetLocal().SetStr(); - id.reserve(128); - id += m_Prefix; - id += NStr::IntToString(n); - id += m_Suffix; - } - return seq_id; -} - -CRef CSeqIdGenerator::GenerateID(void) const -{ - return const_cast(this)->GenerateID(false); -} - - -class CCounterManager -{ -public: - CCounterManager(CSeqIdGenerator& generator, int* counter) - : m_Generator(generator), m_Counter(counter) - { if (counter) { generator.SetCounter(*counter); } } - ~CCounterManager() - { if (m_Counter) { *m_Counter = m_Generator.GetCounter(); } } - -private: - CSeqIdGenerator& m_Generator; - int* m_Counter; -}; - CRef ReadFasta(CNcbiIstream& in, TReadFastaFlags flags, int* counter, vector >* lcv, ILineErrorListener * pMessageListener) { CRef lr(ILineReader::New(in)); CFastaReader reader(*lr, flags); - CCounterManager counter_manager(reader.SetIDGenerator(), counter); + if (counter) { + reader.SetIDGenerator().SetCounter(*counter); + } + if (lcv) { reader.SaveMasks(reinterpret_cast(lcv)); } - return reader.ReadSet(kMax_Int, pMessageListener); + CRef seq_entry = reader.ReadSet(kMax_Int, pMessageListener); + + if (counter) { + *counter = reader.GetIDGenerator().GetCounter(); + } + return seq_entry; } @@ -2268,7 +2084,7 @@ void CFastaReader::x_ApplyAllMods( copy( unused_mods.begin(), unused_mods.end(), inserter(m_UnusedMods, m_UnusedMods.begin() ) ); } else { - // user did not request fAddMods, so we warn that we found + // user did not request fAddMods, so we warn if we found // mods anyway smp.ParseTitle( title, @@ -2356,69 +2172,21 @@ void CFastaReader::SetGapLinkageEvidences(CSeq_gap::EType type, const set& } -void CFastaReader::PostWarning(ILineErrorListener* pMessageListener, - const size_t lineNumber, - const string& errMessage, - const CObjReaderParseException::EErrCode errCode) -{ - unique_ptr pLineExpt( - CObjReaderLineException::Create( - eDiag_Warning, - lineNumber, - errMessage, - ILineError::eProblem_GeneralParsingError, - "", "", "", "", - errCode)); - - - if (!pMessageListener) { - LOG_POST_X(1, Warning << pLineExpt->Message()); - return; - } - - if (!pMessageListener->PutError(*pLineExpt)) { - throw CObjReaderParseException(DIAG_COMPILE_INFO, 0, errCode, errMessage, lineNumber, eDiag_Warning); - } -} - - -void CFastaReader::PostError(ILineErrorListener* pMessageListener, - const size_t lineNumber, - const string& errMessage, - const CObjReaderParseException::EErrCode errCode) -{ - - unique_ptr pLineExpt( - CObjReaderLineException::Create( - eDiag_Error, - lineNumber, - errMessage, - ILineError::eProblem_GeneralParsingError, - "", "", "", "", - errCode)); - - if (!pMessageListener || !pMessageListener->PutError(*pLineExpt)) { - throw CObjReaderParseException(DIAG_COMPILE_INFO, 0, errCode, errMessage, lineNumber, eDiag_Error); - } -} - - - void CFastaReader::PostWarning( ILineErrorListener * pMessageListener, EDiagSev _eSeverity, size_t _uLineNum, CTempString _MessageStrmOps, CObjReaderParseException::EErrCode _eErrCode, ILineError::EProblem _eProblem, CTempString _sFeature, CTempString _sQualName, CTempString _sQualValue) const { if (find(m_ignorable.begin(), m_ignorable.end(), _eProblem) != m_ignorable.end()) + // this is a problem that should be ignored return; - - string sSeqId_49518053 = ( m_BestID ? m_BestID->AsFastaString() : kEmptyStr); + string sSeqId = ( m_BestID ? m_BestID->AsFastaString() : kEmptyStr); AutoPtr pLineExpt( CObjReaderLineException::Create( (_eSeverity), _uLineNum, _MessageStrmOps, (_eProblem), - sSeqId_49518053, (_sFeature), + sSeqId, (_sFeature), (_sQualName), (_sQualValue), _eErrCode) ); if ( ! pMessageListener && (_eSeverity) <= eDiag_Warning ) { diff --git a/c++/src/objtools/readers/fasta_reader_utils.cpp b/c++/src/objtools/readers/fasta_reader_utils.cpp new file mode 100644 index 00000000..2bb6db06 --- /dev/null +++ b/c++/src/objtools/readers/fasta_reader_utils.cpp @@ -0,0 +1,710 @@ +/* $Id: fasta_reader_utils.cpp 543881 2017-08-15 13:56:46Z ivanov $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Authors: Justin Foley +* +* File Description: +* Reader for FASTA-format definition lines. Based on code +* originally contained in CFastaReader. +* +* =========================================================================== +*/ + +#include +#include +#include +#include +#include +#include + +#define NCBI_USE_ERRCODE_X Objtools_Rd_Fasta // Will need to change this + +BEGIN_NCBI_SCOPE +BEGIN_SCOPE(objects) + +// For reasons of efficiency, this method does not use CRef to access range +// information - RW-26 +void CFastaDeflineReader::ParseDefline(const string& defline, + const SDeflineParseInfo& info, + const TIgnoredProblems& ignoredErrors, + list>& ids, + bool& hasRange, + TSeqPos& rangeStart, + TSeqPos& rangeEnd, + TSeqTitles& seqTitles, + ILineErrorListener* pMessageListener) +{ + size_t range_len = 0; + const TFastaFlags& fFastaFlags = info.fFastaFlags; + const TSeqPos& lineNumber = info.lineNumber; + hasRange = false; + + const size_t len = defline.length(); + if (len <= 1 || + NStr::IsBlank(defline.substr(1))) { + return; + } + + if (defline.front() != '>') { + NCBI_THROW2(CObjReaderParseException, eFormat, + "Invalid defline. First character is not '>'", 0); + } + + + // ignore spaces between '>' and the sequence ID + size_t start; + for(start = 1 ; start < len; ++start ) { + if( ! isspace(defline[start]) ) { + break; + } + } + + string id_string; + size_t pos; + size_t title_start = NPOS; + if ((fFastaFlags & CFastaReader::fNoParseID)) { + title_start = start; + } + else + { + // This loop finds the end of the sequence ID + for ( pos = start; pos < len; ++pos) { + unsigned char c = defline[pos]; + + if (c <= ' ' ) { // assumes ASCII + break; + } else if( c == '[' ) { + + // see if this is part of a FASTA mod, which + // implies a pattern like "[key=value]". We only check + // that it looks *roughly* like a FASTA mod and only before the '=' + // + // It might be worth it to put the body of this "if" into its own function, + // for clarity if nothing else. + + const size_t left_bracket_pos = pos; + ++pos; + + // arbitrary, but shouldn't be too much bigger than the largest possible mod key for efficiency + const static size_t kMaxCharsToLookAt = 30; + // we give up much sooner than the length of the string, if the string is long. + // also note that we give up *before* the end so even if pos + // reaches bracket_give_up_pos, we can still say defline[pos] without worrying + // about array-out-of-bounds issues. + const size_t bracket_give_up_pos = min(len - 1, kMaxCharsToLookAt); + // keep track of the first space we find, because that becomes the end of the seqid + // if this turns out not to be a FASTA mod. + size_t first_space_pos = kMax_UI4; + + // find the end of the key + for( ; pos < bracket_give_up_pos ; ++pos ) { + const unsigned char c = defline[pos]; + if( c == '=' ) { + break; + } else if( c <= ' ' ) { + first_space_pos = min(first_space_pos, pos); + // keep going + } else if( isalnum(c) || c == '-' || c == '_' ) { + // this is fine; keep going + } else { + // bad character, so this is NOT a FASTA mod + break; + } + } + + if( defline[pos] == '=' ) { + // this seems to be a FASTA mod, so consider the left square bracket + // to be the end of the seqid + pos = left_bracket_pos; + break; + } else { + // if we stopped on anything but an equal sign, this is NOT a + // FASTA mod. + if( first_space_pos < len ) { + // If we've found a space at any point, we consider that the end of the seq-id + pos = first_space_pos; + break; + } + + // it's not a FASTA mod and we didn't find any spaces, so just + // keep going as normal, continuing from where we let off at "pos" + } + } + } + + range_len = ParseRange(defline.substr(start, pos - start), + rangeStart, rangeEnd, pMessageListener); + + id_string = defline.substr(start, pos - start - range_len); + if (NStr::IsBlank(id_string)) { + NCBI_THROW2(CObjReaderParseException, eFormat, + "Unable to locate sequence id in definition line", 0); + } + + title_start = pos; + x_ProcessIDs(id_string, + info, + ids, + pMessageListener); + + hasRange = (range_len>0); + } + + + // trim leading whitespace from title (is this appropriate?) + while (title_start < len + && isspace((unsigned char) defline[title_start])) { + ++title_start; + } + + if (title_start < len) { + for (pos = title_start + 1; pos < len; ++pos) { + if ((unsigned char) defline[pos] < ' ') { + break; + } + } + // Parse the title elsewhere - after the molecule has been deduced + seqTitles.push_back( + SLineTextAndLoc( + defline.substr(title_start, pos - title_start), lineNumber)); + } +} + + +TSeqPos CFastaDeflineReader::ParseRange( + const string& s, + TSeqPos& start, + TSeqPos& end, + ILineErrorListener * pMessageListener) +{ + + if (s.empty()) { + return 0; + } + + bool on_start = false; + bool negative = false; + TSeqPos mult = 1; + size_t pos; + start = end = 0; + for (pos = s.length() - 1; pos > 0; --pos) { + unsigned char c = s[pos]; + if (c >= '0' && c <= '9') { + if (on_start) { + start += (c - '0') * mult; + } else { + end += (c - '0') * mult; + } + mult *= 10; + } else if (c == '-' && !on_start && mult > 1) { + on_start = true; + mult = 1; + } else if (c == ':' && on_start && mult > 1) { + break; + } else if (c == 'c' && pos > 0 && s[--pos] == ':' + && on_start && mult > 1) { + negative = true; + break; + } else { + return 0; // syntax error + } + } + if ((negative ? (end > start) : (start > end)) || s[pos] != ':') { + return 0; + } + --start; + --end; + return s.length() - pos; +} + + +void CFastaDeflineReader::x_ProcessIDs( + const string& id_string, + const SDeflineParseInfo& info, + list>& ids, + ILineErrorListener* pMessageListener) +{ + + + x_CheckForExcessiveSeqDataInID( + id_string, + info, + pMessageListener); + + + if (info.fBaseFlags & CReaderBase::fAllIdsAsLocal) + { + if (!x_IsValidLocalID(id_string, info.fFastaFlags)) { + NCBI_THROW2(CObjReaderParseException, eFormat, + "'" + id_string + "' is not a valid local ID", 0); + } + ids.push_back(Ref(new CSeq_id(CSeq_id::e_Local, id_string))); + return; + } + + CSeq_id::TParseFlags flags = + CSeq_id::fParse_PartialOK | + CSeq_id::fParse_AnyLocal; + + if (info.fFastaFlags & CFastaReader::fParseRawID) { + flags |= CSeq_id::fParse_RawText; + } + + string local_id_string = id_string; + if (id_string.find(',') != NPOS && + id_string.find('|') == NPOS) { + + const string err_message = + "CFastaReader: Near line " + NStr::NumericToString(info.lineNumber) + + ", the sequence id string contains 'comma' symbol, which has been replaced with 'underscore' " + + "symbol. Please correct the sequence id string."; + + x_PostWarning(pMessageListener, + info.lineNumber, + err_message, + CObjReaderParseException::eFormat); + + local_id_string = NStr::Replace(id_string, ",", "_"); + } + + CSeq_id::ParseIDs(ids, local_id_string, flags); + ids.remove_if([](CRef id_ref){ return NStr::IsBlank(id_ref->GetSeqIdString()); }); + if (ids.empty()) { + NCBI_THROW2(CObjReaderParseException, eNoIDs, + "Could not construct seq-id from '" + id_string + "'", + 0); + } + // Convert anything that looks like a GI to a local id + if ( info.fBaseFlags & CReaderBase::fNumericIdsAsLocal ) { + x_ConvertNumericToLocal(ids); + } + + + for (const auto& id : ids) { + if (id->IsLocal() && + !x_IsValidLocalID(*id, info.fFastaFlags)) { + NCBI_THROW2(CObjReaderParseException, eInvalidID, + "'" + id->GetLocal().GetStr() + "' is not a valid local ID", 0); + } + } + + if (x_ExceedsMaxLength(id_string, info.maxIdLength)) { + const string err_message = + "CFastaReader: Near line " + NStr::NumericToString(info.lineNumber) + + ", the sequence ID is too long. Its length is " + NStr::NumericToString(id_string.length()) + + " but the max length allowed is "+ NStr::NumericToString(info.maxIdLength) + + ". Please find and correct all sequence IDs that are too long."; + + x_PostError(pMessageListener, + info.lineNumber, + err_message, + CObjReaderParseException::eIDTooLong); + } +} + + +bool CFastaDeflineReader::ParseIDs( + const string& s, + const SDeflineParseInfo& info, + const TIgnoredProblems& ignoredErrors, + list>& ids, + ILineErrorListener* pMessageListener) +{ + if (s.empty()) { + return false; + } + + // if user wants all ids to be purely local, no problem + if( info.fBaseFlags & CReaderBase::fAllIdsAsLocal ) + { + ids.push_back(Ref(new CSeq_id(CSeq_id::e_Local, s))); + return true; + } + + TSeqPos num_ids = 0; + // be generous overall, and give raw local IDs the benefit of the + // doubt for now + CSeq_id::TParseFlags flags + = CSeq_id::fParse_PartialOK | CSeq_id::fParse_AnyLocal; + if ( info.fFastaFlags & CFastaReader::fParseRawID ) { + flags |= CSeq_id::fParse_RawText; + } + + const bool ignoreError + = (find(ignoredErrors.cbegin(), ignoredErrors.cend(), ILineError::eProblem_GeneralParsingError) + != ignoredErrors.cend()); + + try { + if (s.find(',') != NPOS && s.find('|') == NPOS) + { + string temp = NStr::Replace(s, ",", "_"); + num_ids = CSeq_id::ParseIDs(ids, temp, flags); + + const string errMessage = + "CFastaReader: Near line " + NStr::NumericToString(info.lineNumber) + + ", the sequence contains 'comma' symbol and replaced with 'underscore' " + + "symbol. Please find and correct the sequence id."; + + if (!ignoreError) { + x_PostWarning(pMessageListener, + info.lineNumber, + errMessage, + CObjReaderParseException::eFormat); + + } + } + else + { + num_ids = CSeq_id::ParseIDs(ids, s, flags); + } + } catch (CSeqIdException&) { + // swap(ids, old_ids); + } + + + + if ( info.fBaseFlags & CReaderBase::fNumericIdsAsLocal ) { + x_ConvertNumericToLocal(ids); + } + + if (num_ids == 1) { + if (ids.front()->IsLocal()) + { + if (!x_IsValidLocalID(*ids.front(), info.fFastaFlags)) { + ids.clear(); + return false; + } + } + if ( x_ExceedsMaxLength(s, info.maxIdLength) ) { + const string errMessage = + "CFastaReader: Near line " + NStr::NumericToString(info.lineNumber) + + ", the sequence ID is too long. Its length is " + NStr::NumericToString(s.length()) + + " but the max length allowed is "+ NStr::NumericToString(info.maxIdLength) + + ". Please find and correct all sequence IDs that are too long."; + + + if (!ignoreError) { + x_PostError(pMessageListener, + info.lineNumber, + errMessage, + CObjReaderParseException::eIDTooLong); + } + + if (x_ExcessiveSeqDataInTitle(s, info.fFastaFlags)) { + return false; + } + } + } + + return true; +} + + +bool CFastaDeflineReader::x_IsValidLocalID(const CSeq_id& id, TFastaFlags fasta_flags) +{ + string id_label; + id.GetLabel(&id_label, 0, CSeq_id::eContent); + return x_IsValidLocalID(id_label, fasta_flags); +} + + +bool CFastaDeflineReader::x_IsValidLocalID(const string& id_string, + const TFastaFlags fasta_flags) +{ + if ( fasta_flags & CFastaReader::fQuickIDCheck) { // check only the first character + return CSeq_id::IsValidLocalID(id_string.substr(0,1)); + } + return CSeq_id::IsValidLocalID(id_string); +} + + +void CFastaDeflineReader::x_ConvertNumericToLocal( + list>& ids) +{ + for (auto id : ids) { + if (id->IsGi()) { + const TGi gi = id->GetGi(); + id->SetLocal().SetStr(NStr::NumericToString(gi)); + } + } +} + + +void CFastaDeflineReader::x_PostWarning(ILineErrorListener* pMessageListener, + const TSeqPos lineNumber, + const string& errMessage, + const CObjReaderParseException::EErrCode errCode) +{ + x_PostWarning(pMessageListener, + lineNumber, + errMessage, + ILineError::eProblem_GeneralParsingError, + errCode); +} + + +void CFastaDeflineReader::x_PostWarning(ILineErrorListener* pMessageListener, + const TSeqPos lineNumber, + const string& errMessage, + const CObjReaderLineException::EProblem problem, + const CObjReaderParseException::EErrCode errCode) +{ + unique_ptr pLineExpt( + CObjReaderLineException::Create( + eDiag_Warning, + lineNumber, + errMessage, + problem, + "", "", "", "", + errCode)); + + if (!pMessageListener) { + LOG_POST_X(1, Warning << pLineExpt->Message()); + return; + } + + if (!pMessageListener->PutError(*pLineExpt)) { + throw CObjReaderParseException(DIAG_COMPILE_INFO, 0, errCode, errMessage, lineNumber, eDiag_Warning); + } +} + + +void CFastaDeflineReader::x_PostError(ILineErrorListener* pMessageListener, + const TSeqPos lineNumber, + const string& errMessage, + const CObjReaderParseException::EErrCode errCode) +{ + + unique_ptr pLineExpt( + CObjReaderLineException::Create( + eDiag_Error, + lineNumber, + errMessage, + ILineError::eProblem_GeneralParsingError, + "", "", "", "", + errCode)); + + if (!pMessageListener || !pMessageListener->PutError(*pLineExpt)) { + throw CObjReaderParseException(DIAG_COMPILE_INFO, 0, errCode, errMessage, lineNumber, eDiag_Error); + } +} + + +bool +CFastaDeflineReader::x_ExceedsMaxLength(const string& title, + const TSeqPos max_length) +{ + auto last = title.rfind('|'); + string substring = (last == NPOS) ? title : title.substr(last+1); + + return (substring.length() > max_length); +} + + +static bool s_ASCII_IsUnAmbigNuc(unsigned char c) +{ + switch( c ) { + case 'A': + case 'C': + case 'G': + case 'T': + case 'a': + case 'c': + case 'g': + case 't': + return true; + default: + return false; + } +} + +void +CFastaDeflineReader::x_CheckForExcessiveSeqDataInID( + const string& id_string, + const SDeflineParseInfo& info, + ILineErrorListener* pMessageListener) +{ + const TSeqPos kWarnNumNucCharsAtEnd = 20; + const TSeqPos kWarnNumAminoAcidCharsAtEnd = 50; + + + const bool assume_prot = (info.fFastaFlags & CFastaReader::fAssumeProt); + + if (!assume_prot && id_string.length() > kWarnNumNucCharsAtEnd) { + TSeqPos numNucChars = 0; + for (auto rit=id_string.crbegin(); rit!=id_string.crend(); ++rit) { + if (!s_ASCII_IsUnAmbigNuc(*rit) && (*rit != 'N')) { + break; + } + ++numNucChars; + } + if (numNucChars > kWarnNumNucCharsAtEnd) { + const string err_message = + "Fasta Reader: sequence id ends with " + + NStr::NumericToString(numNucChars) + + " valid nucleotide characters. " + + " Was the sequence accidentally placed in the definition line?"; + + x_PostWarning(pMessageListener, + info.lineNumber, + err_message, + ILineError::eProblem_UnexpectedNucResidues, + CObjReaderParseException::eFormat); + + return; + } + } + + const bool assume_nuc = (info.fFastaFlags & CFastaReader::fAssumeNuc); + // Check for Aa sequence + if (!assume_nuc && id_string.length() > kWarnNumAminoAcidCharsAtEnd) { + TSeqPos numAaChars = 0; + for (auto rit=id_string.crbegin(); rit!=id_string.crend(); ++rit) { + const auto ch = *rit; + if ( !(ch >= 'A' && ch <= 'Z') && + !(ch >= 'a' && ch <= 'z') ) { + break; + } + ++numAaChars; + } + if (numAaChars > kWarnNumAminoAcidCharsAtEnd) { + const string err_message = + "Fasta Reader: sequence id ends with " + + NStr::NumericToString(numAaChars) + + " valid amino-acid characters. " + + " Was the sequence accidentally placed in the definition line?"; + + x_PostWarning(pMessageListener, + info.lineNumber, + err_message, + ILineError::eProblem_UnexpectedAminoAcids, + CObjReaderParseException::eFormat); + } + } +} + + + +bool +CFastaDeflineReader::x_ExcessiveSeqDataInTitle(const string& title, + TFastaFlags fasta_flags) +{ + if (fasta_flags & CFastaReader::fAssumeProt) { + return false; + } + + // Check for nuc or aa sequence at the end of the title + const TSeqPos kWarnNumNucCharsAtEnd = 20; + const TSeqPos kWarnNumAminoAcidCharsAtEnd = 50; + + // Check for nuc sequence + if (title.length() > kWarnNumNucCharsAtEnd) { + TSeqPos numNucChars = 0; + for (auto rit=title.crbegin(); rit!=title.crend(); ++rit) { + if (!s_ASCII_IsUnAmbigNuc(*rit) && (*rit != 'N')) { + break; + } + ++numNucChars; + } + if (numNucChars > kWarnNumNucCharsAtEnd) { + return true; + } + } + + // Check for Aa sequence + if (title.length() > kWarnNumAminoAcidCharsAtEnd) { + TSeqPos numAaChars = 0; + for (auto rit=title.crbegin(); rit!=title.crend(); ++rit) { + const auto ch = *rit; + if ( !(ch >= 'A' && ch <= 'Z') && + !(ch >= 'a' && ch <= 'z') ) { + break; + } + ++numAaChars; + } + if (numAaChars > kWarnNumAminoAcidCharsAtEnd) { + return true; + } + } + return false; +} + + +CRef CFastaIdHandler::GenerateID(bool unique_id) +{ + return GenerateID("", unique_id); +} + + + +CRef CFastaIdHandler::GenerateID(const string& defline, const bool unique_id) +{ + const bool advance = true; + while (unique_id) { + auto p_Id = mp_IdGenerator->GenerateID(defline, advance); + auto idh = CSeq_id_Handle::GetHandle(*p_Id); + if (x_IsUniqueIdHandle(idh)) { + return p_Id; + } + } + // !unique_id + return mp_IdGenerator->GenerateID(defline, advance); +} + + +CRef CSeqIdGenerator::GenerateID(const bool advance) +{ + return GenerateID("", advance); +} + + +CRef CSeqIdGenerator::GenerateID(const string& defline, const bool advance) +{ + CRef seq_id(new CSeq_id); + int n = advance ? m_Counter.Add(1) - 1 : m_Counter.Get(); + if (m_Prefix.empty() && m_Suffix.empty()) { + seq_id->SetLocal().SetId(n); + } else { + string& id = seq_id->SetLocal().SetStr(); + id.reserve(128); + id += m_Prefix; + id += NStr::IntToString(n); + id += m_Suffix; + } + return seq_id; +} + + +CRef CSeqIdGenerator::GenerateID(void) const +{ + return const_cast(this)->GenerateID(false); +} + + + +END_SCOPE(objects) +END_NCBI_SCOPE + + diff --git a/c++/src/objtools/readers/format_guess_ex.cpp b/c++/src/objtools/readers/format_guess_ex.cpp index a68bfa54..a89d72b4 100644 --- a/c++/src/objtools/readers/format_guess_ex.cpp +++ b/c++/src/objtools/readers/format_guess_ex.cpp @@ -1,4 +1,4 @@ -/* $Id: format_guess_ex.cpp 478995 2015-09-15 16:48:20Z gotvyans $ +/* $Id: format_guess_ex.cpp 538713 2017-06-13 16:58:09Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -357,12 +357,12 @@ bool CFormatGuessEx::x_TryGtf() int GtfCount = 0; - CGtfReader Reader(CGtfReader::fNewCode); + CGtfReader Reader(0); CStreamLineReader LineReader(m_LocalBuffer); CGtfReader::TAnnots LocalAnnots; try { - Reader.ReadSeqAnnotsNew(LocalAnnots, LineReader); + Reader.ReadSeqAnnots(LocalAnnots, LineReader); } catch(CException&) { } catch(...) { } @@ -383,12 +383,12 @@ bool CFormatGuessEx::x_TryGff3() int Gff3Count = 0; - CGff3Reader Reader(CGff3Reader::fNewCode); + CGff3Reader Reader(0); CStreamLineReader LineReader(m_LocalBuffer); CGff3Reader::TAnnots LocalAnnots; try { - Reader.ReadSeqAnnotsNew(LocalAnnots, LineReader); + Reader.ReadSeqAnnots(LocalAnnots, LineReader); } catch(CException&) { } catch(...) { } @@ -409,12 +409,12 @@ bool CFormatGuessEx::x_TryGff2() int Gff2Count = 0; - CGff2Reader Reader(CGff2Reader::fNewCode); + CGff2Reader Reader(0); CStreamLineReader LineReader(m_LocalBuffer); CGff2Reader::TAnnots LocalAnnots; try { - Reader.ReadSeqAnnotsNew(LocalAnnots, LineReader); + Reader.ReadSeqAnnots(LocalAnnots, LineReader); } catch(CException&) { } catch(...) { } diff --git a/c++/src/objtools/readers/gff2_data.cpp b/c++/src/objtools/readers/gff2_data.cpp index 027b47c6..e56e8223 100644 --- a/c++/src/objtools/readers/gff2_data.cpp +++ b/c++/src/objtools/readers/gff2_data.cpp @@ -1,4 +1,4 @@ -/* $Id: gff2_data.cpp 516436 2016-10-13 15:25:49Z ivanov $ +/* $Id: gff2_data.cpp 546403 2017-09-18 15:03:56Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -56,9 +57,9 @@ #include #include -#include #include #include +#include BEGIN_NCBI_SCOPE @@ -122,10 +123,7 @@ CRef s_StringToCodeBreak( return pCodeBreak; } - if (strand == eNa_strand_minus) { - int temp = from; from = to; to = temp; - } - int aacode = 85; //for now + int aacode = 'U'; //for now pCodeBreak.Reset(new CCode_break); pCodeBreak->SetLoc().SetInt().SetId(id); @@ -218,7 +216,7 @@ void CGff2Record::TokenizeGFF(vector& columns, const CTempStringE columns.reserve(9); size_t index; // first try to split just using tabs - NStr::Tokenize(in_line, "\t", columns, NStr::fSplit_MergeDelims); + NStr::Split(in_line, "\t", columns, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); if (columns.size() == 9) return; columns.clear(); @@ -380,19 +378,24 @@ bool CGff2Record::GetAttribute( // ---------------------------------------------------------------------------- CRef CGff2Record::GetSeqId( - int flags ) const + int flags, + SeqIdResolver seqidresolve ) const // ---------------------------------------------------------------------------- { - return CReadUtil::AsSeqId(Id(), flags); + if (!seqidresolve) { + seqidresolve = CReadUtil::AsSeqId; + } + return seqidresolve(Id(), flags, true); } // ---------------------------------------------------------------------------- CRef CGff2Record::GetSeqLoc( - int flags ) const + int flags, + SeqIdResolver seqidresolve ) const // ---------------------------------------------------------------------------- { CRef pLocation(new CSeq_loc); - pLocation->SetInt().SetId(*GetSeqId(flags)); + pLocation->SetInt().SetId(*GetSeqId(flags, seqidresolve)); pLocation->SetInt().SetFrom(SeqStart()); pLocation->SetInt().SetTo(SeqStop()); if (IsSetStrand()) { @@ -470,7 +473,11 @@ bool x_GetNextAttribute(CTempString& input, CTempString& key, CTempString& value bool inQuotes = false; size_t i = 0; - for (; i < input.length(); i++) + while (input[i] == ';') { + ++i; + } + input = input.substr(i); + for (i=0; i < input.length(); i++) { if (inQuotes) { if (input[i] == '\"') { @@ -573,11 +580,12 @@ bool CGff2Record::x_SplitGffAttributes( // ---------------------------------------------------------------------------- bool CGff2Record::InitializeFeature( int flags, - CRef pFeature ) const + CRef pFeature, + SeqIdResolver seqidresolve ) const // ---------------------------------------------------------------------------- { return ( - x_InitFeatureLocation(flags, pFeature) && + x_InitFeatureLocation(flags, pFeature, seqidresolve) && xInitFeatureData(flags, pFeature) && x_MigrateId(pFeature) && x_MigrateStartStopStrand(pFeature) && @@ -590,7 +598,8 @@ bool CGff2Record::InitializeFeature( // ---------------------------------------------------------------------------- bool CGff2Record::UpdateFeature( int flags, - CRef pFeature ) const + CRef pFeature, + SeqIdResolver seqidresolve ) const // ---------------------------------------------------------------------------- { // mss-582: @@ -601,7 +610,7 @@ bool CGff2Record::UpdateFeature( return true; } const CSeq_loc& target = pFeature->GetLocation(); - CRef pAddLoc = GetSeqLoc(flags); + CRef pAddLoc = GetSeqLoc(flags, seqidresolve); if (target.IsInt() && target.GetInt().GetFrom() <= SeqStart() && target.GetInt().GetTo() >= SeqStop() ) { @@ -612,7 +621,7 @@ bool CGff2Record::UpdateFeature( else { // indicates the feature location is already under construction pFeature->SetLocation(*pFeature->SetLocation().Add( - *pAddLoc, CSeq_loc::fSortAndMerge_All, 0)); + *pAddLoc, CSeq_loc::fSort | CSeq_loc::fMerge_Abutting, 0)); if (pFeature->GetLocation().IsInt()) { CRef pOld(new CSeq_loc); pOld->Assign(pFeature->GetLocation()); @@ -628,12 +637,13 @@ bool CGff2Record::UpdateFeature( // ---------------------------------------------------------------------------- bool CGff2Record::xUpdateFeatureData( int flags, - CRef pFeature) const + CRef pFeature, + SeqIdResolver seqidresolve) const // ---------------------------------------------------------------------------- { const CSeq_loc& target = pFeature->GetLocation(); CSeqFeatData::ESubtype subtype = pFeature->GetData().GetSubtype(); - CRef pAddLoc = GetSeqLoc(flags); + CRef pAddLoc = GetSeqLoc(flags, seqidresolve); switch(subtype) { default: { @@ -674,9 +684,6 @@ bool CGff2Record::x_MigrateId( // ---------------------------------------------------------------------------- { unsigned int featId = NextId(); -// if (!GetAttribute("ID", featIdStr)) { -// featIdStr = NextId(); -// } CRef pFeatId(new CFeat_id); pFeatId->SetLocal().SetId(featId); pFeature->SetId(*pFeatId); @@ -734,7 +741,7 @@ bool CGff2Record::x_MigrateAttributes( it = attrs_left.find("Dbxref"); if (it != attrs_left.end()) { vector dbxrefs; - NStr::Split(it->second, ",", dbxrefs, NStr::eMergeDelims); + NStr::Split(it->second, ",", dbxrefs, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); for (vector::iterator it1 = dbxrefs.begin(); it1 != dbxrefs.end(); ++it1 ) { string dbtag = xNormalizedAttributeValue(*it1); @@ -874,7 +881,7 @@ bool CGff2Record::x_MigrateAttributes( if (it != attrs_left.end()) { if (pFeature->GetData().IsGene()) { vector synonyms; - NStr::Split(it->second, ",", synonyms, NStr::eMergeDelims); + NStr::Split(it->second, ",", synonyms, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); for (vector::iterator it1 = synonyms.begin(); it1 != synonyms.end(); ++it1 ) { string synonym = xNormalizedAttributeValue(*it1); @@ -933,58 +940,17 @@ bool CGff2Record::x_MigrateAttributes( attrs_left.erase(it); } -// it = attrs_left.find("product"); -// if (it != attrs_left.end()) { -// if (!pFeature->IsSetProduct()) { -// CRef pId = CReadUtil::AsSeqId(it->second, flags); -// CRef pLoc( new CSeq_loc(CSeq_loc::e_Whole)); -// pLoc->SetId(*pId); -// pFeature->SetProduct(*pLoc); -// } -// xMigrateAttributeDefault( -// attrs_left, "product", pFeature, "product", flags); -// } - -// xMigrateAttributeDefault( -// attrs_left, "Product", pFeature, "product", flags); - -// it = attrs_left.find("protein_id"); -// if (it != attrs_left.end()) { -// string protId = it->second; -// CRef pId = CReadUtil::AsSeqId(protId, flags); -// CRef pLoc( new CSeq_loc(CSeq_loc::e_Whole)); -// pLoc->SetId(*pId); -// pFeature->SetProduct(*pLoc); - -// this->xMigrateAttributeDefault( -// attrs_left, "protein_id", pFeature, "protein_id", flags); -// } - it = attrs_left.find("pseudo"); if (it != attrs_left.end()) { pFeature->SetPseudo(true); attrs_left.erase(it); } -// it = attrs_left.find("transcript_id"); -// if (it != attrs_left.end()) { -// string transcriptId = it->second; -// if (!pFeature->IsSetProduct()) { -// CRef pId = CReadUtil::AsSeqId(transcriptId, flags); -// CRef pLoc( new CSeq_loc(CSeq_loc::e_Whole)); -// pLoc->SetId(*pId); -// pFeature->SetProduct(*pLoc); -// } - // mss-362: turn transcript_id attributes into transcript_id quailifiers. -// xMigrateAttributeSingle( -// attrs_left, "transcript_id", pFeature, "transcript_id", flags); -// } - it = attrs_left.find("transl_except"); if (it != attrs_left.end()) { if (pFeature->GetData().IsCdregion()) { vector codebreaks; - NStr::Split(it->second, ",", codebreaks, NStr::eMergeDelims); + NStr::Split(it->second, ",", codebreaks, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); for (vector::iterator it1 = codebreaks.begin(); it1 != codebreaks.end(); ++it1 ) { string breakData = xNormalizedAttributeValue(*it1); @@ -1224,10 +1190,11 @@ bool CGff2Record::x_MigrateAttributesSubSource( // ---------------------------------------------------------------------------- bool CGff2Record::x_InitFeatureLocation( int flags, - CRef pFeature ) const + CRef pFeature, + SeqIdResolver seqidresolve ) const // ---------------------------------------------------------------------------- { - pFeature->SetLocation(*GetSeqLoc(flags)); + pFeature->SetLocation(*GetSeqLoc(flags, seqidresolve)); return true; } @@ -1245,217 +1212,32 @@ bool CGff2Record::xInitFeatureData( } } - //special cases: - if (xInitFeatureDataBond(flags, pFeature)) { - return true; - } - if (xInitFeatureDataNcrna(flags, pFeature)) { - return true; - } - if (xInitFeatureDataSpecialImp(flags, pFeature)) { - return true; - } - - //regular case: - // use 1<->1 SOFA map. - CFeatListItem itemtype = SofaTypes().MapSofaTermToFeatListItem(Type()); - switch( itemtype.GetType() ) { - default: { - return true; - } - case CSeqFeatData::e_Gene: { - pFeature->SetData().SetGene(); - return true; - } - - case CSeqFeatData::e_Cdregion: { - //oh my --- phases again --- - CCdregion::EFrame frame = Phase(); - if (frame == CCdregion::eFrame_not_set) { - frame = CCdregion::eFrame_one; - } - pFeature->SetData().SetCdregion(); - pFeature->SetData().SetCdregion().SetFrame(frame); - return true; - } - - case CSeqFeatData::e_Rna: { - CRNA_ref& rnaref = pFeature->SetData().SetRna(); - switch( itemtype.GetSubtype() ) { - default: - rnaref.SetType(CRNA_ref::eType_unknown); - return true; - case CSeqFeatData::eSubtype_tmRNA: - rnaref.SetType(CRNA_ref::eType_tmRNA); - return true; - case CSeqFeatData::eSubtype_mRNA: - rnaref.SetType(CRNA_ref::eType_mRNA); - return true; - case CSeqFeatData::eSubtype_ncRNA: - rnaref.SetType(CRNA_ref::eType_ncRNA); - return true; - case CSeqFeatData::eSubtype_otherRNA: - rnaref.SetType(CRNA_ref::eType_other); - return true; - case CSeqFeatData::eSubtype_rRNA: - rnaref.SetType(CRNA_ref::eType_rRNA); - return true; - case CSeqFeatData::eSubtype_scRNA: - rnaref.SetType(CRNA_ref::eType_scRNA); - return true; - case CSeqFeatData::eSubtype_tRNA: - rnaref.SetType(CRNA_ref::eType_tRNA); - return true; + if (Type() == "ncRNA") { + string qual_type; + if(GetAttribute("ncrna_class", qual_type)) { + if (qual_type == "other") { + qual_type = "ncRNA"; } - return true; - } - case CSeqFeatData::e_Imp: { - CSeqFeatData::TImp& imp = pFeature->SetData().SetImp(); - CSeqFeatData::ESubtype subType = - static_cast(itemtype.GetSubtype()); - if (subType == CSeqFeatData::eSubtype_bad) { - if (Type() == ".") { - imp.SetKey("misc_feature"); - return true; - } - imp.SetKey(Type()); + if (CSoMap::SoTypeToFeature(qual_type, *pFeature)) { return true; } - const string& key = CSeqFeatData::SubtypeValueToName( - static_cast(itemtype.GetSubtype())); - imp.SetKey(key); - return true; - } - case CSeqFeatData::e_Variation: { - CSeqFeatData::TVariation& variation = pFeature->SetData().SetVariation(); - variation.SetData().SetUnknown(); - //CSeqFeatData::TImp& imp = pFeature->SetData().SetImp(); - //CSeqFeatData::ESubtype subType = - // static_cast(itemtype.GetSubtype()); - //if (subType == CSeqFeatData::eSubtype_bad) { - // if (Type() == ".") { - // imp.SetKey("misc_feature"); - // return true; - // } - // imp.SetKey(Type()); - // return true; - //} - //const string& key = CSeqFeatData::SubtypeValueToName( - // static_cast(itemtype.GetSubtype())); - //imp.SetKey(key); - return true; } } -} -// ---------------------------------------------------------------------------- -bool CGff2Record::xInitFeatureDataBond( - int flags, - CRef pFeature) const -// ---------------------------------------------------------------------------- -{ - string ftype = Type(); - if (ftype == "cross_link") { - pFeature->SetData().SetBond(CSeqFeatData::eBond_xlink); - return true; - } - if (ftype == "disulfide_bond") { - pFeature->SetData().SetBond(CSeqFeatData::eBond_disulfide); - return true; + if (!CSoMap::SoTypeToFeature(Type(), *pFeature)) { + return false; } - return false; -} -// ---------------------------------------------------------------------------- -bool CGff2Record::xInitFeatureDataNcrna( - int flags, - CRef pFeature) const -// ---------------------------------------------------------------------------- -{ - typedef SStaticPair NCRNA_ENTRY; - static const NCRNA_ENTRY ncRnaMap_[] = { - { "antisense_RNA", "antisense_RNA" }, - { "autocatalytically_spliced_intron", "autocatalytically_spliced_intron" }, - { "guide_RNA", "guide_RNA" }, - { "hammerhead_ribozyme", "hammerhead_ribozyme" }, - { "lnc_RNA", "lncRNA" }, - { "miRNA", "miRNA" }, - { "ncRNA", "other" }, - { "piRNA", "piRNA" }, - { "rasiRNA", "rasiRNA" }, - { "ribozyme", "ribozyme" }, - { "RNase_MRP_RNA", "RNase_MRP_RNA" }, - { "RNase_P_RNA", "RNase_P_RNA" }, - { "scRNA", "scRNA" }, - { "siRNA", "siRNA" }, - { "snoRNA", "snoRNA" }, - { "snRNA", "snRNA" }, - { "SRP_RNA", "SRP_RNA" }, - { "telomerase_RNA", "telomerase_RNA" }, - { "vault_RNA", "vault_RNA" }, - { "Y_RNA", "Y_RNA" } - }; - typedef CStaticArrayMap NCRNA_MAP; - DEFINE_STATIC_ARRAY_MAP_WITH_COPY(NCRNA_MAP, ncRnaMap, ncRnaMap_); - - string ftype = Type(); - if (ftype == "ncRNA") { - pFeature->SetData().SetRna().SetType(CRNA_ref::eType_ncRNA); - string ncrna_class; - if (GetAttribute("ncrna_class", ncrna_class)) { - pFeature->SetData().SetRna().SetExt().SetGen().SetClass(ncrna_class); - } - else { - pFeature->SetData().SetRna().SetExt().SetGen().SetClass("other"); + CSeqFeatData::ESubtype subtype = pFeature->GetData().GetSubtype(); + if (subtype == CSeqFeatData::eSubtype_cdregion) { + CCdregion::EFrame frame = Phase(); + if (frame == CCdregion::eFrame_not_set) { + frame = CCdregion::eFrame_one; } + pFeature->SetData().SetCdregion().SetFrame(frame); return true; } - NCRNA_MAP::const_iterator cit = ncRnaMap.find(ftype); - if (cit != ncRnaMap.end()) { - pFeature->SetData().SetRna().SetType(CRNA_ref::eType_ncRNA); - pFeature->SetData().SetRna().SetExt().SetGen().SetClass(cit->second); - return true; - } - return false; -} - -// ---------------------------------------------------------------------------- -bool CGff2Record::xInitFeatureDataSpecialImp( - int flags, - CRef pFeature) const -// ---------------------------------------------------------------------------- -{ - typedef SStaticPair REGULATORY_ENTRY; - static const REGULATORY_ENTRY regulatoryMap_[] = { - { "attenuator", "attenuator" }, - { "boundary_element", "insulator" }, - { "CAAT_signal", "CAAT_signal" }, - { "enhancer", "enhancer" }, - { "GC_rich_promoter_region", "GC_signal" }, - { "insulator", "enhancer_blocking_element" }, - { "locus_control_region", "locus_control_region" }, - { "minus_10_signal", "minus_10_signal" }, - { "minus_35_signal", "minus_35_signal" }, - { "polyA_signal_sequence", "polyA_signal_sequence" }, - { "promoter", "promoter" }, - { "regulatory_region", "other" }, - { "riboswitch", "riboswitch" }, - { "Shine_Dalgarno_sequence", "ribosome_binding_site" }, - { "silencer", "silencer" }, - { "TATA_box", "TATA_box" }, - { "terminator", "terminator" }, - }; - typedef CStaticArrayMap REGULATORY_MAP; - DEFINE_STATIC_ARRAY_MAP_WITH_COPY(REGULATORY_MAP, regulatoryMap, regulatoryMap_); - - string ftype = Type(); - REGULATORY_MAP::const_iterator cit = regulatoryMap.find(ftype); - if (cit != regulatoryMap.end()) { - pFeature->SetData().SetImp().SetKey("regulatory"); - pFeature->AddQualifier("regulatory_class", cit->second); - return true; - } - return false; + return true; } END_objects_SCOPE diff --git a/c++/src/objtools/readers/gff2_reader.cpp b/c++/src/objtools/readers/gff2_reader.cpp index 808007d4..2810e847 100644 --- a/c++/src/objtools/readers/gff2_reader.cpp +++ b/c++/src/objtools/readers/gff2_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: gff2_reader.cpp 520682 2016-11-30 18:52:13Z ivanov $ +/* $Id: gff2_reader.cpp 542725 2017-08-02 11:32:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -91,7 +91,6 @@ #include #include #include -#include #include #include #include @@ -99,6 +98,8 @@ #include #include #include +#include + #include @@ -132,9 +133,10 @@ const string* CGff2Reader::s_GetAnnotId( CGff2Reader::CGff2Reader( int iFlags, const string& name, - const string& title): + const string& title, + SeqIdResolver seqidresolve): // ---------------------------------------------------------------------------- - CReaderBase(iFlags, name, title), + CReaderBase(iFlags, name, title, seqidresolve), m_pErrors(0), mCurrentFeatureCount(0), mParsingAlignment(false) @@ -147,40 +149,6 @@ CGff2Reader::~CGff2Reader() { } -// --------------------------------------------------------------------------- -void -CGff2Reader::ReadSeqAnnots( - TAnnotList& annots, - CNcbiIstream& istr, - ILineErrorListener* pMessageListener ) -// --------------------------------------------------------------------------- -{ - xReadInit(); - CStreamLineReader lr( istr ); - ReadSeqAnnots( annots, lr, pMessageListener ); -} - -// --------------------------------------------------------------------------- -void -CGff2Reader::ReadSeqAnnots( - TAnnotList& annots, - ILineReader& lr, - ILineErrorListener* pMessageListener ) -// ---------------------------------------------------------------------------- -{ - xProgressInit(lr); - - if ( m_iFlags & fNewCode ) { - ReadSeqAnnotsNew(annots, lr, pMessageListener); - } - else { - CRef< CSeq_entry > entry = ReadSeqEntry(lr, pMessageListener); - CTypeIterator annot_iter( *entry ); - for (; annot_iter; ++annot_iter) { - annots.push_back(CRef(annot_iter.operator->())); - } - } -} // ---------------------------------------------------------------------------- CRef @@ -213,7 +181,8 @@ CGff2Reader::ReadSeqAnnot( return pAnnot; } xReportProgress(pEC); - if ( xParseStructuredComment(line) ) { + if ( xParseStructuredComment(line) + && !NStr::StartsWith(line, "##sequence-region") ) { continue; } if (xIsTrackLine(line)) { @@ -221,9 +190,20 @@ CGff2Reader::ReadSeqAnnot( xParseTrackLine(line, pEC); continue; } - xUngetLine(lr); + m_PendingLine = line; break; } + if (xIsTrackTerminator(line)) { + if (!mCurrentFeatureCount) { + xParseTrackLine("track", pEC); + continue; + } + //if (line == "###") { + // m_PendingLine = "track"; + //} + break; + } + if (xParseBrowserLine(line, pAnnot, pEC)) { continue; } @@ -233,9 +213,11 @@ CGff2Reader::ReadSeqAnnot( break; } - if ( CGff2Reader::IsAlignmentData(line) && - x_ParseAlignmentGff(line, id_list, alignments)) { - continue; + if ( CGff2Reader::IsAlignmentData(line)) { + if ((m_iFlags && fGenbankMode) || + x_ParseAlignmentGff(line, id_list, alignments)) { + continue; + } } if (xParseFeature(line, pAnnot, pEC)) { @@ -248,79 +230,36 @@ CGff2Reader::ReadSeqAnnot( return CRef(); } + if (!alignments.empty()) { x_ProcessAlignmentsGff(id_list, alignments, pAnnot); } - xPostProcessAnnot(pAnnot, pEC); return pAnnot; } + +// --------------------------------------------------------------------------- +void +CGff2Reader::ReadSeqAnnots( + TAnnots& annots, + CNcbiIstream& istr, + ILineErrorListener* pMessageListener ) +// --------------------------------------------------------------------------- +{ + CStreamLineReader lr( istr ); + ReadSeqAnnots( annots, lr, pMessageListener ); +} + // --------------------------------------------------------------------------- void -CGff2Reader::ReadSeqAnnotsNew( +CGff2Reader::ReadSeqAnnots( TAnnots& annots, ILineReader& lr, ILineErrorListener* pEC ) // ---------------------------------------------------------------------------- { xProgressInit(lr); - - if (m_iFlags&fGenbankMode) { - CRef pAnnot; - pAnnot.Reset(new CSeq_annot); - - map>> alignments; - list id_list; - - string line; - while (xGetLine(lr, line)) { - if (IsCanceled()) { - AutoPtr pErr( - CObjReaderLineException::Create( - eDiag_Info, - 0, - "Reader stopped by user.", - ILineError::eProblem_ProgressInfo)); - ProcessError(*pErr, pEC); - annots.clear(); - return; - } - xReportProgress(pEC); - - try { - if (xParseStructuredComment(line)) { - continue; - } - if (x_ParseBrowserLineGff(line, m_CurrentBrowserInfo)) { - continue; - } - if ( x_ParseTrackLineGff(line, m_CurrentTrackInfo)) { - continue; - } - - if ( CGff2Reader::IsAlignmentData(line) && - x_ParseAlignmentGff(line, id_list, alignments) ) { - continue; - } - - if ( ! x_ParseDataGff(line, annots, pEC) ) { - continue; - } - } - catch( CObjReaderLineException& err ) { - err.SetLineNumber( m_uLineNumber ); - ProcessError(err, pEC); - } - } - - if (!alignments.empty()) { - x_ProcessAlignmentsGff(id_list, alignments, pAnnot); - } - return; - } - - //main line code: CRef pAnnot = ReadSeqAnnot(lr, pEC); while (pAnnot) { annots.push_back(pAnnot); @@ -329,6 +268,7 @@ CGff2Reader::ReadSeqAnnotsNew( return; } + // ---------------------------------------------------------------------------- CRef< CSeq_entry > CGff2Reader::ReadSeqEntry( @@ -339,7 +279,8 @@ CGff2Reader::ReadSeqEntry( xProgressInit(lr); TAnnots annots; - ReadSeqAnnotsNew( annots, lr, pMessageListener ); + //ReadSeqAnnotsNew( annots, lr, pMessageListener ); + ReadSeqAnnots( annots, lr, pMessageListener ); CRef pSeqEntry(new CSeq_entry()); pSeqEntry->SetSet(); @@ -378,10 +319,12 @@ void CGff2Reader::xPostProcessAnnot( ILineErrorListener *pEC) // ---------------------------------------------------------------------------- { - xAddConversionInfo(pAnnot, pEC); - xAssignTrackData(pAnnot); xAssignAnnotId(pAnnot); - xGenerateParentChildXrefs(pAnnot); + if (!(m_iFlags && fGenbankMode)) { + //xAssignTrackData(pAnnot); + xAddConversionInfo(pAnnot, pEC); + xGenerateParentChildXrefs(pAnnot); + } } // ---------------------------------------------------------------------------- @@ -440,27 +383,13 @@ bool CGff2Reader::xParseStructuredComment( const string& strLine) // ---------------------------------------------------------------------------- { - if ( ! NStr::StartsWith( strLine, "##" ) ) { + if (NStr::StartsWith(strLine, "###")) { return false; } - return true; -} - -// ---------------------------------------------------------------------------- -bool CGff2Reader::x_ParseDataGff( - const string& strLine, - TAnnots& annots, - ILineErrorListener* pEC) -// ---------------------------------------------------------------------------- -{ - if (CGff2Reader::IsAlignmentData(strLine)) { - if (m_iFlags&fGenbankMode) { - return true; - } - //return x_ParseAlignmentGff(strLine, annots); - return true; + if (!NStr::StartsWith( strLine, "##")) { + return false; } - return x_ParseFeatureGff(strLine, annots, pEC); + return true; } // ---------------------------------------------------------------------------- @@ -488,17 +417,10 @@ CGff2Reader::xParseFeature( } //make sure we are interested: - string ftype = pRecord->Type(); - if (xIsIgnoredFeatureType(ftype)) { - string message = string("GFF3 feature type \"") + ftype + - string("\" not supported- ignored."); - AutoPtr pErr( - CObjReaderLineException::Create( - eDiag_Warning, - 0, - message, - ILineError::eProblem_FeatureNameNotAllowed)); - ProcessError(*pErr, pEC); + if (xIsIgnoredFeatureType(pRecord->Type())) { + return true; + } + if (xIsIgnoredFeatureId(pRecord->Id())) { return true; } @@ -515,7 +437,7 @@ CGff2Reader::xParseFeature( // ---------------------------------------------------------------------------- void CGff2Reader::x_GetAlignmentScores(const CSeq_align& alignment, - TScoreValueMap& score_values) + TScoreValueMap& score_values) const // ---------------------------------------------------------------------------- { // Start with empty scores @@ -565,7 +487,7 @@ bool s_CompareValues(const CScore::TValue& score_val1, // ---------------------------------------------------------------------------- void CGff2Reader::x_FindMatchingScores(const TScoreValueMap& scores_1, const TScoreValueMap& scores_2, - set& matching_scores) + set& matching_scores) const // ---------------------------------------------------------------------------- { matching_scores.clear(); @@ -621,6 +543,7 @@ bool CGff2Reader::x_ParseAlignmentGff( // ---------------------------------------------------------------------------- { unique_ptr pRecord(x_CreateRecord()); + if ( !pRecord->AssignFromGff(strLine) ) { return false; } @@ -647,6 +570,55 @@ bool CGff2Reader::x_ParseAlignmentGff( } + +// ---------------------------------------------------------------------------- +void CGff2Reader::x_InitializeScoreSums(const TScoreValueMap score_values, + map& summed_scores) const +// ---------------------------------------------------------------------------- +{ + const list score_names {"num_ident", "num_mismatch"}; + + for (const string& score_name : score_names) { + if (score_values.find(score_name) != score_values.end()) { + summed_scores[score_name] = score_values.at(score_name)->GetInt(); + } + } +} + + +// ---------------------------------------------------------------------------- +void CGff2Reader::x_ProcessAlignmentScores(const CSeq_align& alignment, + map& summed_scores, + TScoreValueMap& common_scores) const +// ---------------------------------------------------------------------------- +{ + const list summed_score_names {"num_ident", "num_mismatch"}; + + TScoreValueMap new_scores; + x_GetAlignmentScores(alignment, new_scores); + + for (const string& score_name : summed_score_names) { + if (new_scores.find(score_name) == new_scores.end()) { + summed_scores.erase(score_name); + } else if (summed_scores.find(score_name) != summed_scores.end()) { + summed_scores[score_name] += new_scores[score_name]->GetInt(); + new_scores.erase(score_name); + } + } + + set matching_score_names; + x_FindMatchingScores(common_scores, + new_scores, + matching_score_names); + + common_scores.clear(); + for (string score_name : matching_score_names) { + common_scores[score_name] = Ref(new CScore::TValue()); + common_scores[score_name]->Assign(*new_scores[score_name]); + } +} + + // ---------------------------------------------------------------------------- bool CGff2Reader::x_MergeAlignments( const list>& alignment_list, @@ -662,7 +634,7 @@ bool CGff2Reader::x_MergeAlignments( return true; } - map summed_scores; + map summed_scores; const list summed_score_names {"num_ident", "num_mismatch"}; // Factor out identical scores @@ -670,62 +642,81 @@ bool CGff2Reader::x_MergeAlignments( TScoreValueMap score_values; x_GetAlignmentScores(**align_it, score_values); - - for (const string& score_name : summed_score_names) { - if (score_values.find(score_name) != score_values.end()) { - summed_scores[score_name] = score_values[score_name]->GetInt(); - } - } + x_InitializeScoreSums(score_values, + summed_scores); ++align_it; while (align_it != alignment_list.end() && !score_values.empty()) { - TScoreValueMap new_score_values; - x_GetAlignmentScores(**align_it, new_score_values); - - for (const string& score_name : summed_score_names) { - if (new_score_values.find(score_name) == new_score_values.end()) { - summed_scores.erase(score_name); - } else if (summed_scores.find(score_name) != summed_scores.end()) { - summed_scores[score_name] += new_score_values[score_name]->GetInt(); - new_score_values.erase(score_name); - } + + x_ProcessAlignmentScores(**align_it, summed_scores, score_values); + ++align_it; + } + // At this point, the score_values map should contain the scores that + // do not change over the rows + + const auto first_alignment = alignment_list.front(); + if (first_alignment->IsSetSegs() && + first_alignment->GetSegs().IsSpliced()) { + + processed->SetType(CSeq_align::eType_global); + + if (first_alignment->IsSetDim()) { + processed->SetDim(first_alignment->GetDim()); } - set matching_scores; - x_FindMatchingScores(score_values, - new_score_values, - matching_scores); + for (auto& kv : summed_scores) { + auto score = Ref(new CScore()); + score->SetId().SetStr(kv.first); + score->SetValue().SetInt(kv.second); + processed->SetScore().push_back(score); + } - score_values.clear(); - for (string score_name : matching_scores) { - score_values[score_name] = Ref(new CScore::TValue()); - score_values[score_name]->Assign(*new_score_values[score_name]); + for (auto& kv : score_values) { + auto score = Ref(new CScore()); + score->SetId().SetStr(kv.first); + score->SetValue().Assign(*(kv.second)); + processed->SetScore().push_back(score); } + + CRef spliced = Ref(new CSpliced_seg()); + spliced->Assign(first_alignment->GetSegs().GetSpliced()); + processed->SetSegs().SetSpliced(*spliced); + + auto align_it = alignment_list.cbegin(); ++align_it; + + while(align_it != alignment_list.end()) { + const auto& spliced_seg = (*align_it)->GetSegs().GetSpliced(); + if (spliced_seg.IsSetExons()) { + for (auto exon : spliced_seg.GetExons()) { + processed->SetSegs().SetSpliced().SetExons().push_back(exon); + } + } + ++align_it; + } + return true; } - // At this point, the score_values map should contain the scores that - // do not change over the rows processed->SetType(CSeq_align::eType_disc); for (auto& kv : summed_scores) { - CRef score = Ref(new CScore()); + auto score = Ref(new CScore()); score->SetId().SetStr(kv.first); score->SetValue().SetInt(kv.second); processed->SetScore().push_back(score); } for (auto& kv : score_values) { - CRef score = Ref(new CScore()); + auto score = Ref(new CScore()); score->SetId().SetStr(kv.first); score->SetValue().Assign(*(kv.second)); processed->SetScore().push_back(score); } for (auto current : alignment_list) { - CRef new_align = Ref(new CSeq_align()); + auto new_align = Ref(new CSeq_align()); new_align->Assign(*current); new_align->ResetScore(); @@ -794,10 +785,6 @@ bool CGff2Reader::x_ParseFeatureGff( ILineErrorListener* pEC) // ---------------------------------------------------------------------------- { - // - // Parse the record and determine which ID the given feature will pertain - // to: - // auto_ptr pRecord(x_CreateRecord()); try { if (!pRecord->AssignFromGff(strLine)) { @@ -810,55 +797,18 @@ bool CGff2Reader::x_ParseFeatureGff( } string ftype = pRecord->Type(); if (xIsIgnoredFeatureType(ftype)) { - string message = string("GFF3 feature type \"") + ftype + - string("\" not supported- ignored."); - AutoPtr pErr( - CObjReaderLineException::Create( - eDiag_Warning, - 0, - message, - ILineError::eProblem_FeatureNameNotAllowed)); - ProcessError(*pErr, pEC); return true; } - // - // Search annots for a pre-existing annot pertaining to the same ID: - // - TAnnotIt it = annots.begin(); - for ( /*NOOP*/; it != annots.end(); ++it ) { - if (!(**it).IsFtable()) continue; - const string* strAnnotId = s_GetAnnotId(**it); - if (strAnnotId == 0) { - return false; - } - if ( pRecord->Id() == *strAnnotId ) { - break; - } - } - - // - // If a preexisting annot was found, update it with the new feature - // information: - // - if ( it != annots.end() ) { - if ( ! x_UpdateAnnotFeature( *pRecord, *it, pEC ) ) { - return false; - } - } - - // - // Otherwise, create a new annot pertaining to the new ID and initialize it - // with the given feature information: - // - else { + if (annots.empty()) { CRef< CSeq_annot > pAnnot( new CSeq_annot ); if ( ! x_InitAnnot( *pRecord, pAnnot, pEC ) ) { return false; } - annots.insert(annots.begin(), pAnnot ); + annots.push_back(pAnnot); + return true; } - return true; + return x_UpdateAnnotFeature(*pRecord, annots.back(), pEC); }; @@ -928,7 +878,7 @@ bool CGff2Reader::x_ParseBrowserLineGff( return false; } vector< string > columns; - NStr::Split( strRawInput, " \t", columns, NStr::eMergeDelims ); + NStr::Split( strRawInput, " \t", columns, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate ); if ( columns.size() <= 1 || 1 != ( columns.size() % 2 ) ) { // don't know how to unwrap this @@ -968,7 +918,7 @@ bool CGff2Reader::x_ParseTrackLineGff( } } vector< string > columns; - NStr::Split( strCookedInput, " \t", columns, NStr::eMergeDelims ); + NStr::Split( strCookedInput, " \t", columns, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate ); if ( columns.size() <= 1 ) { pAnnotDesc.Reset(); @@ -1005,9 +955,9 @@ bool CGff2Reader::x_InitAnnot( ILineErrorListener* pEC ) // ---------------------------------------------------------------------------- { - CRef< CAnnot_id > pAnnotId( new CAnnot_id ); - pAnnotId->SetLocal().SetStr( gff.Id() ); - pAnnot->SetId().push_back( pAnnotId ); + //CRef< CAnnot_id > pAnnotId( new CAnnot_id ); + //pAnnotId->SetLocal().SetStr( gff.Id() ); + //pAnnot->SetId().push_back( pAnnotId ); //pAnnot->SetData().SetFtable(); // if available, add current browser information @@ -1044,33 +994,7 @@ bool CGff2Reader::x_UpdateAnnotFeature( ILineErrorListener* pEC) // ---------------------------------------------------------------------------- { - CRef< CSeq_feat > pFeature( new CSeq_feat ); - - if ( ! x_FeatureSetId( gff, pFeature ) ) { - return false; - } - if ( ! x_FeatureSetLocation( gff, pFeature ) ) { - return false; - } - if ( ! x_FeatureSetData( gff, pFeature ) ) { - return false; - } - if ( ! x_FeatureSetGffInfo( gff, pFeature ) ) { - return false; - } - if ( ! x_FeatureSetQualifiers( gff, pFeature ) ) { - return false; - } - if (!xAddFeatureToAnnot( pFeature, pAnnot )) { - return false; - } - string strId; - if (gff.GetAttribute("ID", strId) ) { - if (m_MapIdToFeature.find(strId) == m_MapIdToFeature.end()) { - m_MapIdToFeature[strId] = pFeature; - } - } - return true; + return false; } @@ -1212,89 +1136,272 @@ bool CGff2Reader::xGetTargetParts(const CGff2Record& gff, vector& target return true; } + // ---------------------------------------------------------------------------- -bool CGff2Reader::xSetDensegStarts(const vector& gapParts, - const bool oppositeStrands, - const size_t targetStart, - const CGff2Record& gff, - CSeq_align::C_Segs::TDenseg& denseg) +bool CGff2Reader::xGetStartsOnMinusStrand(TSeqPos offset, + const vector& gapParts, + const bool isTarget, + vector& starts) const // ---------------------------------------------------------------------------- { - - size_t targetOffset = targetStart; + starts.clear(); const size_t gapCount = gapParts.size(); - // Gap attribute is always given with respect to the target - // strand. - // The reference start values depend on the relative strandedness. - // The target start values do not. - if (oppositeStrands) { - size_t identOffset = gff.SeqStop(); - for (size_t i=0; i& gapParts, + const bool isTarget, + vector& starts) const +// ---------------------------------------------------------------------------- +{ + starts.clear(); + const auto gapCount = gapParts.size(); + + for (auto i=0; i& gapParts, + const ENa_strand identStrand, + const ENa_strand targetStrand, + const TSeqPos targetStart, + const TSeqPos targetEnd, + const CGff2Record& gff, + CSeq_align::C_Segs::TDenseg& denseg) +// ---------------------------------------------------------------------------- +{ + const size_t gapCount = gapParts.size(); + + const bool isTarget = true; + vector targetStarts; + if (targetStrand == eNa_strand_minus) { + if( !xGetStartsOnMinusStrand(targetEnd, + gapParts, + isTarget, + targetStarts)) { + return false; + } + } + else { + if (!xGetStartsOnPlusStrand(targetStart, + gapParts, + isTarget, + targetStarts)) { + return false; + } + } + + vector identStarts; + const bool isIdent = !isTarget; + + if (identStrand == eNa_strand_minus) { + + if ( !xGetStartsOnMinusStrand(gff.SeqStop(), + gapParts, + isIdent, + identStarts)) { + return false; + } + } + else { + if ( !xGetStartsOnPlusStrand(gff.SeqStart(), + gapParts, + isIdent, + identStarts)) { + return false; + } + } + for (auto i=0; i pAlign) // ---------------------------------------------------------------------------- { + const string& type = gff.Type(); + + if (type == "cDNA_match" || + type == "EST_match" || + type == "translated_nucleotide_match") { + return xAlignmentSetSpliced_seg(gff, pAlign); + } + + return xAlignmentSetDenseg(gff, pAlign); +} + + +// ---------------------------------------------------------------------------- +bool CGff2Reader::xAlignmentSetSpliced_seg( + const CGff2Record& gff, + CRef pAlign) +// ---------------------------------------------------------------------------- +{ + vector targetParts; + if (!xGetTargetParts(gff, targetParts)) { + return false; + } + + CSeq_align::TSegs& segs = pAlign->SetSegs(); + + auto& spliced_seg = segs.SetSpliced(); + + const string& type = gff.Type(); + if (type == "translated_nucleotide_match") { + spliced_seg.SetProduct_type(CSpliced_seg::eProduct_type_protein); + } + else { + spliced_seg.SetProduct_type(CSpliced_seg::eProduct_type_transcript); + } + CRef product_id = mSeqIdResolve(targetParts[0], 0, true); + spliced_seg.SetProduct_id(*product_id); + + CRef genomic_id = mSeqIdResolve(gff.Id(), 0, true); + spliced_seg.SetGenomic_id(*genomic_id); + + if (targetParts[3] == "+") { + spliced_seg.SetProduct_strand(eNa_strand_plus); + } + else + if (targetParts[3] == "-") { + spliced_seg.SetProduct_strand(eNa_strand_minus); + } + + if (gff.IsSetStrand()) { + ENa_strand ident_strand = gff.Strand(); + spliced_seg.SetGenomic_strand(ident_strand); + } + + CRef exon(new CSpliced_exon()); + exon->SetProduct_start().SetNucpos(NStr::StringToInt(targetParts[1])-1); + exon->SetProduct_end().SetNucpos(NStr::StringToInt(targetParts[2])-1); + + const auto genomic_start = gff.SeqStart(); + const auto genomic_end = gff.SeqStop(); + exon->SetGenomic_start(genomic_start); + exon->SetGenomic_end(genomic_end); + + string gapInfo; + vector gapParts; + if (gff.GetAttribute("Gap", gapInfo)) { + NStr::Split(gapInfo, " ", gapParts); + } + else { + gapParts.push_back(string("M") + NStr::NumericToString(gff.SeqStop()-gff.SeqStart()+1)); + } + + const auto gapCount = gapParts.size(); + + for (auto i=0; i chunk(new CSpliced_exon_chunk()); + char changeType = gapParts[i][0]; + int changeSize = NStr::StringToInt(gapParts[i].substr(1)); + switch (changeType) { + default: + return false; + + case 'M': + chunk->SetMatch(changeSize); + break; + + case 'I': + chunk->SetProduct_ins(changeSize); + break; + + case 'D': + chunk->SetGenomic_ins(changeSize); + break; + } + exon->SetParts().push_back(chunk); + } + + spliced_seg.SetExons().push_back(exon); + + return true; +} + + +// ---------------------------------------------------------------------------- +bool CGff2Reader::xAlignmentSetDenseg( + const CGff2Record& gff, + CRef pAlign) +// ---------------------------------------------------------------------------- +{ vector targetParts; if (!xGetTargetParts(gff, targetParts)) { return false; @@ -1320,8 +1427,6 @@ bool CGff2Reader::xAlignmentSetSegment( gapParts.push_back(string("M") + NStr::NumericToString(gff.SeqStop()-gff.SeqStart()+1)); } - bool oppositeStrands = (targetStrand != identStrand); - int gapCount = gapParts.size(); //meta @@ -1332,15 +1437,18 @@ bool CGff2Reader::xAlignmentSetSegment( //ids denseg.SetIds().push_back( - CReadUtil::AsSeqId(targetParts[0])); + mSeqIdResolve(targetParts[0], 0, true)); denseg.SetIds().push_back( - CReadUtil::AsSeqId(gff.Id())); + mSeqIdResolve(gff.Id(), 0, true)); - size_t targetOffset = NStr::StringToInt(targetParts[1])-1; + const TSeqPos targetStart = NStr::StringToInt(targetParts[1])-1; + const TSeqPos targetEnd = NStr::StringToInt(targetParts[2])-1; if (!xSetDensegStarts(gapParts, - oppositeStrands, - targetOffset, + identStrand, + targetStrand, + targetStart, + targetEnd, gff, denseg)) { return false; @@ -1358,6 +1466,9 @@ bool CGff2Reader::xAlignmentSetSegment( return true; } + + + // ---------------------------------------------------------------------------- bool CGff2Reader::xAlignmentSetScore( const CGff2Record& gff, @@ -1428,26 +1539,13 @@ bool CGff2Reader::xAlignmentSetScore( return true; } -// ---------------------------------------------------------------------------- -bool CGff2Reader::x_FeatureSetId( - const CGff2Record& record, - CRef< CSeq_feat > pFeature ) -// ---------------------------------------------------------------------------- -{ - string strId; - if ( record.GetAttribute( "ID", strId ) ) { - pFeature->SetId().SetLocal().SetStr( strId ); - } - return true; -} - // ---------------------------------------------------------------------------- bool CGff2Reader::x_FeatureSetLocation( const CGff2Record& record, CRef< CSeq_feat > pFeature ) // ---------------------------------------------------------------------------- { - CRef< CSeq_id > pId = CReadUtil::AsSeqId(record.Id(), m_iFlags); + CRef< CSeq_id > pId = mSeqIdResolve(record.Id(), m_iFlags, true); CRef< CSeq_loc > pLocation( new CSeq_loc ); pLocation->SetInt().SetId( *pId ); pLocation->SetInt().SetFrom( record.SeqStart() ); @@ -1562,132 +1660,6 @@ bool CGff2Reader::xFeatureSetQualifier( return true; } -// ---------------------------------------------------------------------------- -bool CGff2Reader::x_FeatureSetGffInfo( - const CGff2Record& record, - CRef< CSeq_feat > pFeature ) -// ---------------------------------------------------------------------------- -{ - CRef< CUser_object > pGffInfo( new CUser_object ); - pGffInfo->SetType().SetStr( "gff-info" ); - pGffInfo->AddField( "gff-attributes", record.AttributesLiteral() ); - pGffInfo->AddField( "gff-start", NStr::NumericToString( record.SeqStart() ) ); - pGffInfo->AddField( "gff-stop", NStr::NumericToString( record.SeqStop() ) ); - pGffInfo->AddField( "gff-cooked", string( "false" ) ); - - pFeature->SetExts().push_back( pGffInfo ); - return true; -} - -// ---------------------------------------------------------------------------- -bool CGff2Reader::x_FeatureSetData( - const CGff2Record& record, - CRef< CSeq_feat > pFeature) -// ---------------------------------------------------------------------------- -{ - // - // Do something with the phase information --- but only for CDS features! - // - - CSeqFeatData::ESubtype iGenbankType = SofaTypes().MapSofaTermToGenbankType( - record.Type()); - - switch(iGenbankType) { - default: - return x_FeatureSetDataMiscFeature(record, pFeature); - - case CSeqFeatData::eSubtype_cdregion: - return x_FeatureSetDataCDS(record, pFeature); - case CSeqFeatData::eSubtype_exon: - return x_FeatureSetDataExon(record, pFeature); - case CSeqFeatData::eSubtype_gene: - return x_FeatureSetDataGene(record, pFeature); - case CSeqFeatData::eSubtype_mRNA: - case CSeqFeatData::eSubtype_rRNA: - case CSeqFeatData::eSubtype_ncRNA: - case CSeqFeatData::eSubtype_preRNA: - case CSeqFeatData::eSubtype_scRNA: - case CSeqFeatData::eSubtype_snRNA: - case CSeqFeatData::eSubtype_snoRNA: - case CSeqFeatData::eSubtype_tRNA: - case CSeqFeatData::eSubtype_tmRNA: - return x_FeatureSetDataRna(record, pFeature, iGenbankType); - } - return true; -} - -// ---------------------------------------------------------------------------- -bool CGff2Reader::x_FeatureSetDataGene( - const CGff2Record& record, - CRef< CSeq_feat > pFeature ) -// ---------------------------------------------------------------------------- -{ - pFeature->SetData().SetGene(); - return true; -} - -// ---------------------------------------------------------------------------- -bool CGff2Reader::x_FeatureSetDataRna( - const CGff2Record& record, - CRef< CSeq_feat > pFeature, - CSeqFeatData::ESubtype subType) -// ---------------------------------------------------------------------------- -{ - CRNA_ref& rnaRef = pFeature->SetData().SetRna(); - switch (subType){ - default: - rnaRef.SetType(CRNA_ref::eType_miscRNA); - break; - case CSeqFeatData::eSubtype_mRNA: - rnaRef.SetType(CRNA_ref::eType_mRNA); - break; - case CSeqFeatData::eSubtype_rRNA: - rnaRef.SetType(CRNA_ref::eType_rRNA); - break; - } - return true; -} - -// ---------------------------------------------------------------------------- -bool CGff2Reader::x_FeatureSetDataCDS( - const CGff2Record& record, - CRef< CSeq_feat > pFeature ) -// ---------------------------------------------------------------------------- -{ - pFeature->SetData().SetCdregion(); - return true; -} - -// ---------------------------------------------------------------------------- -bool CGff2Reader::x_FeatureSetDataExon( - const CGff2Record& record, - CRef< CSeq_feat > pFeature ) -// ---------------------------------------------------------------------------- -{ - CSeqFeatData& data = pFeature->SetData(); - data.SetImp().SetKey( "exon" ); - - return true; -} - -// ---------------------------------------------------------------------------- -bool CGff2Reader::x_FeatureSetDataMiscFeature( - const CGff2Record& record, - CRef< CSeq_feat > pFeature ) -// ---------------------------------------------------------------------------- -{ - CSeqFeatData& data = pFeature->SetData(); - data.SetImp().SetKey( "misc_feature" ); - if ( record.IsSetPhase() ) { - CRef< CGb_qual > pQual( new CGb_qual ); - pQual->SetQual( "gff_phase" ); - pQual->SetVal( NStr::UIntToString( record.Phase() ) ); - pFeature->SetQual().push_back( pQual ); - } - - return true; -} - // ---------------------------------------------------------------------------- bool CGff2Reader::x_GetFeatureById( const string & strId, @@ -2000,13 +1972,20 @@ void CGff2Reader::xSetAncestorXrefs( } // ============================================================================ -bool CGff2Reader::xReadInit() +void CGff2Reader::xSetXrefFromTo( + CSeq_feat& from, + CSeq_feat& to) // ============================================================================ { - if (!CReaderBase::xReadInit()) { - return false; + + //xref descendent->ancestor + if (!sFeatureHasXref(from, to.GetId())) { + CRef pToId(new CFeat_id); + pToId->Assign(to.GetId()); + CRef pToXref(new CSeqFeatXref); + pToXref->SetId(*pToId); + from.SetXref().push_back(pToXref); } - return true; } // ============================================================================ @@ -2034,5 +2013,13 @@ bool CGff2Reader::xIsIgnoredFeatureType( return false; } +// ============================================================================ +bool CGff2Reader::xIsIgnoredFeatureId( + const string& type) +// ============================================================================ +{ + return false; +} + END_objects_SCOPE END_NCBI_SCOPE diff --git a/c++/src/objtools/readers/gff3_reader.cpp b/c++/src/objtools/readers/gff3_reader.cpp index fcdb4dc2..dddb112c 100644 --- a/c++/src/objtools/readers/gff3_reader.cpp +++ b/c++/src/objtools/readers/gff3_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: gff3_reader.cpp 520685 2016-11-30 18:53:22Z ivanov $ +/* $Id: gff3_reader.cpp 546403 2017-09-18 15:03:56Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -61,6 +61,7 @@ #include #include #include +#include #include #include @@ -85,7 +86,6 @@ #include #include #include -#include #include #include #include @@ -147,6 +147,14 @@ bool CGff3ReadRecord::AssignFromGff( m_Attributes["pseudo"] = "true"; return true; } + if (m_strType == "transcript") { + m_strType = "misc_RNA"; + return true; + } + if (m_strType == "start_codon" || m_strType == "stop_codon") { + m_strType = "CDS"; + return true; + } return true; } @@ -194,9 +202,10 @@ string CGff3ReadRecord::x_NormalizedAttributeKey( CGff3Reader::CGff3Reader( unsigned int uFlags, const string& name, - const string& title ): + const string& title, + SeqIdResolver resolver ): // ---------------------------------------------------------------------------- - CGff2Reader( uFlags, name, title ) + CGff2Reader( uFlags, name, title, resolver ) { CGff2Record::ResetId(); } @@ -261,12 +270,13 @@ bool CGff3Reader::xVerifyExonLocation( ILineErrorListener* pEC) // ---------------------------------------------------------------------------- { + //return true; map >::const_iterator cit = mMrnaLocs.find(mrnaId); if (cit == mMrnaLocs.end()) { return false; } const CSeq_interval& containingInt = cit->second.GetObject(); - const CRef pContainedLoc = exon.GetSeqLoc(m_iFlags); + const CRef pContainedLoc = exon.GetSeqLoc(m_iFlags, mSeqIdResolve); const CSeq_interval& containedInt = pContainedLoc->GetInt(); if (containedInt.GetFrom() < containingInt.GetFrom()) { return false; @@ -287,6 +297,9 @@ bool CGff3Reader::xUpdateAnnotExon( { list parents; if (record.GetAttribute("Parent", parents)) { + if (!parents.empty() && parents.front() == "ENST00000367927") { + cerr << ""; + } for (list::const_iterator it = parents.begin(); it != parents.end(); ++it) { const string& parentId = *it; @@ -296,8 +309,11 @@ bool CGff3Reader::xUpdateAnnotExon( return false; } CRef pParent; - if (!xGetParentFeature(*pFeature, pParent) || - !pParent->GetData().IsGene()) { + if (!xGetParentFeature(*pFeature, pParent)) { + //Note: The below does not quite cut it as there are types of RNA that come + // as Imps. + //if (!xGetParentFeature(*pFeature, pParent) || + // (!pParent->GetData().IsGene() && !pParent->GetData().IsRna())) { AutoPtr pErr( CObjReaderLineException::Create( eDiag_Error, @@ -372,11 +388,14 @@ bool CGff3Reader::xUpdateAnnotCds( for (list::const_iterator it = parents.begin(); it != parents.end(); ++it) { string parentId = *it; - + bool parentIsGene = false; //update parent location: IdToFeatureMap::iterator featIt = m_MapIdToFeature.find(parentId); if (featIt != m_MapIdToFeature.end()) { CRef pParent = featIt->second; + if (pParent->GetData().IsGene()) { + parentIsGene = true; + } if (!record.UpdateFeature(m_iFlags, pParent)) { return false; } @@ -390,7 +409,7 @@ bool CGff3Reader::xUpdateAnnotCds( //generate applicable CDS ID: string siblingId("cds"); - if (!record.GetAttribute("ID", siblingId) || IsInGenbankMode()) { + if (!record.GetAttribute("ID", siblingId) || !parentIsGene) { siblingId = string("cds:") + parentId; } impliedCdsFeats[siblingId] = parentId; @@ -415,11 +434,14 @@ bool CGff3Reader::xUpdateAnnotCds( // If there is, use record to update feature under construction. // If there isn't, use record to initialize a brand new feature. // - for (map::iterator featIt = impliedCdsFeats.begin(); - featIt != impliedCdsFeats.end(); ++featIt) { - string cdsId = featIt->first; - string parentId = featIt->second; - IdToFeatureMap::iterator idIt = m_MapIdToFeature.find(cdsId); + for (auto featIt = impliedCdsFeats.begin(); featIt != impliedCdsFeats.end(); ++featIt) { + auto cdsId = featIt->first; + auto parentId = featIt->second; + auto idIt = m_MapIdToFeature.find(cdsId); + if (idIt == m_MapIdToFeature.end()) { + auto altId = string("cds:") + parentId; + idIt = m_MapIdToFeature.find(altId); + } if (idIt != m_MapIdToFeature.end()) { //found feature with ID in question: update record.UpdateFeature(m_iFlags, idIt->second); @@ -553,7 +575,7 @@ bool CGff3Reader::xUpdateAnnotGeneric( CRef pCodeBreak(new CCode_break); CSeq_interval& cbLoc = pCodeBreak->SetLoc().SetInt(); - CRef< CSeq_id > pId = CReadUtil::AsSeqId(record.Id(), m_iFlags); + CRef< CSeq_id > pId = mSeqIdResolve(record.Id(), m_iFlags, true); cbLoc.SetId(*pId); cbLoc.SetFrom(record.SeqStart()); cbLoc.SetTo(record.SeqStop()); @@ -578,7 +600,8 @@ bool CGff3Reader::xUpdateAnnotGeneric( if ( record.GetAttribute("ID", strId)) { m_MapIdToFeature[strId] = pFeature; } - if (pFeature->GetData().IsRna()) { + auto st = pFeature->GetData().GetSubtype(); + if (pFeature->GetData().IsRna() || pFeature->GetData().GetSubtype() == CSeqFeatData::eSubtype_misc_RNA) { CRef rnaLoc(new CSeq_interval); rnaLoc->Assign(pFeature->GetLocation().GetInt()); mMrnaLocs[strId] = rnaLoc; @@ -705,11 +728,7 @@ bool CGff3Reader::xIsIgnoredFeatureType( { typedef CStaticArraySet STRINGARRAY; - string ftype(featureType); - NStr::ToLower(ftype); - if (SofaTypes().IsStringSofaAlias(ftype)) { - ftype = SofaTypes().MapSofaAliasToSofaTerm(ftype); - } + string ftype(CSoMap::ResolveSoAlias(featureType)); static const char* const ignoredTypesAlways_[] = { "protein" @@ -793,11 +812,6 @@ bool CGff3Reader::xIsIgnoredFeatureType( return true; } - CSeqFeatData::ESubtype iGenbankType = SofaTypes().MapSofaTermToGenbankType(ftype); - if (iGenbankType == CSeqFeatData::eSubtype_bad) { - return true; - } - /*anything else?*/ return false; } diff --git a/c++/src/objtools/readers/gff3_sofa.cpp b/c++/src/objtools/readers/gff3_sofa.cpp index e130ef32..d700a4ac 100644 --- a/c++/src/objtools/readers/gff3_sofa.cpp +++ b/c++/src/objtools/readers/gff3_sofa.cpp @@ -1,4 +1,4 @@ -/* $Id: gff3_sofa.cpp 520685 2016-11-30 18:53:22Z ivanov $ +/* $Id: gff3_sofa.cpp 520640 2016-11-30 14:07:40Z ludwigf $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -77,7 +77,56 @@ CGff3SofaTypes::CGff3SofaTypes() lookup["signal_peptide"] = GT(e_Imp, eSubtype_sig_peptide); TAliasToTerm& aliases = *m_Aliases; + aliases["-10_signal"] = "minus_10_signal"; + aliases["-35_signal"] = "minus_35_signal"; + aliases["3'UTR"] = "three_prime_UTR"; + aliases["3'clip"] = "three_prime_clip"; + aliases["5'UTR"] = "five_prime_UTR"; + aliases["5'clip"] = "five_prime_clip"; + aliases["C_region"] = "C_gene_segment"; + aliases["D-loop"] = "D_loop"; + aliases["D_segment"] = "D_gene_segment"; + aliases["GC_signal"] = "GC_rich_promoter_region"; + aliases["J_segment"] = "J_gene_segment"; + aliases["LTR"] = "long_terminal_repeat"; + aliases["RBS"] = "ribosome_entry_site"; + aliases["TATA_signal"] = "TATA_box"; + aliases["V_segment"] = "V_gene_segment"; + aliases["assembly_gap"] = "gap"; + aliases["Comment"] = "remark"; + aliases["conflict"] = "sequence_conflict"; + aliases["mat_peptide_nt"] = "mature_protein_region"; + aliases["mat_peptide"] = "mature_peptide"; + aliases["misc_binding"] = "binding_site"; + aliases["misc_difference"] = "sequence_difference"; + aliases["misc_feature"] = "sequence_feature"; + aliases["misc_recomb"] = "recombination_feature"; + aliases["misc_signal"] = "regulatory_region"; + aliases["misc_structure"] = "sequence_secondary_structure"; + aliases["mobile_element"] = "mobile_genetic_element"; + aliases["modified_base"] = "modified_DNA_base"; + aliases["misc_RNA"] = "transcript"; + aliases["polyA_signal"] = "polyA_signal_sequence"; + aliases["pre_RNA"] = "primary_transcript"; + aliases["precursor_RNA"] = "primary_transcript"; + aliases["proprotein"] = "immature_peptide_region"; + aliases["prim_transcript"] = "primary_transcript"; + aliases["primer_bind"] = "primer_binding_site"; + aliases["Protein"] = "polypeptide"; + aliases["protein_bind"] = "protein_binding_site"; + aliases["SecStr"] = "sequence_secondary_structure"; + aliases["rep_origin"] = "origin_of_replication"; + aliases["Rsite"] = "restriction_enzyme_cut_site"; aliases["satellite"] = "satellite_DNA"; + aliases["sig_peptide_nt"] = "signal_peptide"; + aliases["sig_peptide"] = "signal_peptide"; + aliases["Site"] = "site"; + aliases["Site-ref"] = "site"; + aliases["transit_peptide_nt"] = "transit_peptide"; + aliases["unsure"] = "sequence_uncertainty"; + aliases["variation"] = "sequence_alteration"; + aliases["VariationRef"] = "sequence_alteration"; + aliases["virion"] = "viral_sequence"; }; // -------------------------------------------------------------------------- diff --git a/c++/src/objtools/readers/gff_reader.cpp b/c++/src/objtools/readers/gff_reader.cpp index c8813518..d2e8c0e8 100644 --- a/c++/src/objtools/readers/gff_reader.cpp +++ b/c++/src/objtools/readers/gff_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: gff_reader.cpp 491626 2016-02-08 14:58:45Z ludwigf $ +/* $Id: gff_reader.cpp 536287 2017-05-17 13:05:21Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -405,7 +405,7 @@ bool CGFFReader::x_ParseStructuredComment(const TStr& line) return false; } TStrVec v; - NStr::Tokenize(line, "# \t", v, NStr::eMergeDelims); + NStr::Split(line, "# \t", v, NStr::fSplit_Tokenize); if (v.empty()) { return true; } @@ -476,10 +476,10 @@ CGFFReader::x_ParseFeatureInterval(const TStr& line) TStrVec v; bool misdelimited = false; - NStr::Tokenize(line, "\t", v, NStr::eNoMergeDelims); + NStr::Split(line, "\t", v, NStr::fSplit_NoMergeDelims); if (v.size() < 8) { v.clear(); - NStr::Tokenize(line, " \t", v, NStr::eMergeDelims); + NStr::Split(line, " \t", v, NStr::fSplit_Tokenize); if (v.size() < 8) { x_Error("Skipping line due to insufficient fields", x_GetLineNumber()); @@ -718,7 +718,7 @@ CRef CGFFReader::x_ParseAlignRecord(const SRecord& record) SRecord::TAttrs::const_iterator tgit = record.FindAttribute("Target"); vector target; if (tgit != record.attrs.end()) { - NStr::Split((*tgit)[1], " +-", target, NStr::eMergeDelims); + NStr::Split((*tgit)[1], " +-", target, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); } if (target.size() != 3) { x_Warn("Bad Target attribute", record.line_no); @@ -927,7 +927,7 @@ void CGFFReader::x_ParseV3Attributes(SRecord& record, const TStrVec& v, SIZE_TYPE& i) { vector v2, attr; - NStr::Tokenize(v[i], ";", v2, NStr::eMergeDelims); + NStr::Split(v[i], ";", v2, NStr::fSplit_Tokenize); ITERATE (vector, it, v2) { attr.clear(); string key, values; @@ -935,7 +935,7 @@ void CGFFReader::x_ParseV3Attributes(SRecord& record, const TStrVec& v, vector vals; attr.resize(2); s_URLDecode(key, attr[0]); - NStr::Tokenize(values, ",", vals); + NStr::Split(values, ",", vals, NStr::fSplit_NoMergeDelims); ITERATE (vector, it2, vals) { string value( *it2 ); if ( NStr::MatchesMask(value, "\"*\"") ) { diff --git a/c++/src/objtools/readers/glimmer_reader.cpp b/c++/src/objtools/readers/glimmer_reader.cpp index e573c9a2..a8e7835d 100644 --- a/c++/src/objtools/readers/glimmer_reader.cpp +++ b/c++/src/objtools/readers/glimmer_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: glimmer_reader.cpp 389354 2013-02-15 00:27:40Z dicuccio $ +/* $Id: glimmer_reader.cpp 515707 2016-10-05 12:32:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -110,7 +110,7 @@ CRef CGlimmerReader::Read(CNcbiIstream& istr, CScope& scope, } } else { list toks; - NStr::Split(line, " \t", toks); + NStr::Split(line, " \t", toks, NStr::fSplit_Tokenize); if (toks.size() != 5) { CNcbiOstrstream ostr; ostr << "CGlimmerReader::ReadAnnot(): line " diff --git a/c++/src/objtools/readers/gtf_reader.cpp b/c++/src/objtools/readers/gtf_reader.cpp index 35879590..d134f777 100644 --- a/c++/src/objtools/readers/gtf_reader.cpp +++ b/c++/src/objtools/readers/gtf_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: gtf_reader.cpp 515629 2016-10-04 17:46:33Z ivanov $ +/* $Id: gtf_reader.cpp 545908 2017-09-12 14:24:34Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -181,6 +181,7 @@ string s_FeatureKey( const CGff2Record& gff ) // ---------------------------------------------------------------------------- { + static unsigned int tidCounter(1); string strGeneId = s_GeneKey( gff ); if ( gff.Type() == "gene" ) { return strGeneId; @@ -188,20 +189,20 @@ string s_FeatureKey( string strTranscriptId; if ( ! gff.GetAttribute( "transcript_id", strTranscriptId ) ) { - cerr << "Unexpected: GTF feature without a transcript_id." << endl; - strTranscriptId = "transcript_id"; + strTranscriptId = "t"+NStr::IntToString(tidCounter++); } - return strGeneId + "|" + strTranscriptId; + return strGeneId + "_" + strTranscriptId; } // ---------------------------------------------------------------------------- CGtfReader::CGtfReader( unsigned int uFlags, const string& strAnnotName, - const string& strAnnotTitle ): + const string& strAnnotTitle, + SeqIdResolver resolver ): // ---------------------------------------------------------------------------- - CGff2Reader( uFlags, strAnnotName, strAnnotTitle ) + CGff2Reader( uFlags, strAnnotName, strAnnotTitle, resolver ) { } @@ -235,6 +236,10 @@ CGtfReader::ReadSeqAnnots( return; } xReportProgress(pEC); + if ( xParseStructuredComment(line) ) { + continue; + } + try { if (xIsTrackTerminator(line)) { continue; @@ -242,9 +247,23 @@ CGtfReader::ReadSeqAnnots( if (x_ParseBrowserLineGff(line, m_CurrentBrowserInfo)) { continue; } - if (xParseTrackLine(line, pEC)) { + if (xIsTrackLine(line)) { + if (!annots.empty()) { + xPostProcessAnnot(annots.back(), pEC); + } + xParseTrackLine(line, pEC); + CRef< CSeq_annot > pAnnot( new CSeq_annot ); + annots.push_back(pAnnot); continue; } + if (xNeedsNewSeqAnnot(line)) { + if (!annots.empty()) { + xPostProcessAnnot(annots.back(), pEC); + } + CRef< CSeq_annot > pAnnot( new CSeq_annot ); + annots.push_back(pAnnot); + continue; + } if (x_ParseFeatureGff(line, annots, pEC)) { continue; } @@ -253,6 +272,26 @@ CGtfReader::ReadSeqAnnots( err.SetLineNumber(m_uLineNumber); } } + if (!annots.empty()) { + xPostProcessAnnot(annots.back(), pEC); + } +} + +// --------------------------------------------------------------------------- +bool +CGtfReader::xNeedsNewSeqAnnot( + const string& line) +// --------------------------------------------------------------------------- +{ + vector columns; + NStr::Split(line, "\t ", columns, NStr::eMergeDelims); + string seqId = columns[0]; + if (m_CurrentSeqId == seqId) { + return false; + } + m_CurrentSeqId = seqId; + m_PendingLine = line; + return true; } // --------------------------------------------------------------------------- @@ -274,80 +313,45 @@ bool CGtfReader::x_UpdateAnnotFeature( ILineErrorListener* pEC) // ---------------------------------------------------------------------------- { - CRef< CSeq_feat > pFeature( new CSeq_feat ); + string strType = gff.Type(); + + using TYPEHANDLER = bool (CGtfReader::*)(const CGff2Record&, CRef< CSeq_annot >); + using HANDLERMAP = map; + + HANDLERMAP typeHandlers = { + {"CDS", &CGtfReader::x_UpdateAnnotCds}, + {"start_codon", &CGtfReader::x_UpdateAnnotCds}, + {"stop_codon", &CGtfReader::x_UpdateAnnotCds}, + {"5UTR", &CGtfReader::x_UpdateAnnotTranscript}, + {"3UTR", &CGtfReader::x_UpdateAnnotTranscript}, + {"exon", &CGtfReader::x_UpdateAnnotTranscript}, + {"initial", &CGtfReader::x_UpdateAnnotTranscript}, + {"internal", &CGtfReader::x_UpdateAnnotTranscript}, + {"terminal", &CGtfReader::x_UpdateAnnotTranscript}, + {"single", &CGtfReader::x_UpdateAnnotTranscript}, + }; // // Handle officially recognized GTF types: // - string strType = gff.Type(); - if ( strType == "CDS" ) { - // - // Observations: - // Location does not include the stop codon hence must be fixed up once - // the stop codon is seen. - // - return x_UpdateAnnotCds( gff, pAnnot ); + HANDLERMAP::iterator it = typeHandlers.find(strType); + if (it != typeHandlers.end()) { + TYPEHANDLER handler = it->second; + return (this->*handler)(gff, pAnnot); } - if ( strType == "start_codon" ) { - // - // Observation: - // Comes in up to three pieces (depending on splicing). - // Location _is_ included in CDS. - // - return x_UpdateAnnotStartCodon( gff, pAnnot ); - } - if ( strType == "stop_codon" ) { - // - // Observation: - // Comes in up to three pieces (depending on splicing). - // Location not included in CDS hence must be used to fix up location of - // the coding region. - // - return x_UpdateAnnotStopCodon( gff, pAnnot ); - } - if ( strType == "5UTR" ) { - return x_UpdateAnnot5utr( gff, pAnnot ); - } - if ( strType == "3UTR" ) { - return x_UpdateAnnot3utr( gff, pAnnot ); - } - if ( strType == "inter" ) { - return x_UpdateAnnotInter( gff, pAnnot ); - } - if ( strType == "inter_CNS" ) { - return x_UpdateAnnotInterCns( gff, pAnnot ); - } - if ( strType == "intron_CNS" ) { - return x_UpdateAnnotIntronCns( gff, pAnnot ); - } - if ( strType == "exon" || - strType == "initial" || - strType == "internal" || - strType == "terminal" || - strType == "single") { - return x_UpdateAnnotExon( gff, pAnnot ); - } - + // // Every other type is not officially sanctioned GTF, and per spec we are // supposed to ignore it. In the spirit of being lenient on input we may // try to salvage some of it anyway. // if ( strType == "gene" ) { - // - // Not an official GTF feature type but seen frequently. Hence we give - // it some recognition. - // - if ( ! x_CreateParentGene( gff, pAnnot ) ) { - return false; - } + return x_CreateParentGene(gff, pAnnot); } if (strType == "mRNA") { - if ( ! x_CreateParentMrna(gff, pAnnot) ) { - return false; - } + return x_CreateParentMrna(gff, pAnnot); } - return x_UpdateAnnotMiscFeature( gff, pAnnot ); + return true; } // ---------------------------------------------------------------------------- @@ -356,44 +360,49 @@ bool CGtfReader::x_UpdateAnnotCds( CRef< CSeq_annot > pAnnot ) // ---------------------------------------------------------------------------- { + bool needXref = false; + + // + // From the spec, the stop codon has _not_ been accounted for in any of the + // coding regions. Hence, we will treat (pieces of) the stop codon just + // like (pieces of) CDS. + // // // If there is no gene feature to go with this CDS then make one. Otherwise, // make sure the existing gene feature includes the location of the CDS. // - CRef< CSeq_feat > pGene; - if ( ! x_FindParentGene( gff, pGene ) ) { - if ( ! x_CreateParentGene( gff, pAnnot ) ) { + CRef pGene; + if (!x_FindParentGene(gff, pGene)) { + if (!x_CreateParentGene(gff, pAnnot) || !x_FindParentGene(gff, pGene)) { return false; } + needXref = true; } else { - if ( ! x_MergeParentGene( gff, pGene ) ) { + if (!x_MergeParentGene(gff, pGene)) { return false; } } - + // // If there is no CDS feature with this gene_id|transcript_id then make one. // Otherwise, fix up the location of the existing one. // - CRef< CSeq_feat > pCds; - if ( ! x_FindParentCds( gff, pCds ) ) { + CRef pCds; + if (!x_FindParentCds(gff, pCds)) { // // Create a brand new CDS feature: // - if ( ! x_CreateParentCds( gff, pAnnot ) ) { + if (!x_CreateParentCds(gff, pAnnot) || !x_FindParentCds(gff, pCds)) { return false; } - x_FindParentCds( gff, pCds ); + needXref = true; } else { // // Update an already existing CDS features: // - if ( ! x_MergeFeatureLocationMultiInterval( gff, pCds ) ) { - return false; - } - if (!x_FeatureTrimQualifiers(gff, pCds)) { + if (!x_MergeFeatureLocationMultiInterval(gff, pCds)) { return false; } } @@ -421,135 +430,7 @@ bool CGtfReader::x_UpdateAnnotCds( } // ---------------------------------------------------------------------------- -bool CGtfReader::x_UpdateAnnotStartCodon( - const CGff2Record& gff, - CRef< CSeq_annot > pAnnot ) -// ---------------------------------------------------------------------------- -{ - // If this belongs to a partial feature then that feature has been given a - // 5' fuzz. Now that we see an actual start codon it is time to remove that - // fuzz. - // - CRef< CSeq_feat > pCds; - if ( ! x_FindParentCds( gff, pCds ) ) { - if ( ! x_CreateParentCds( gff, pAnnot ) || ! x_FindParentCds( gff, pCds ) ) { - return false; - } - } - if ( ! pCds->IsSetPartial() || ! pCds->GetPartial() ) { - return true; - } - CSeq_loc& loc = pCds->SetLocation(); - if ( loc.IsPartialStart( eExtreme_Positional ) ) { - loc.SetPartialStart( false, eExtreme_Positional ); - } - return true; -} - -// ---------------------------------------------------------------------------- -bool CGtfReader::x_UpdateAnnotStopCodon( - const CGff2Record& gff, - CRef< CSeq_annot > pAnnot ) -// ---------------------------------------------------------------------------- -{ - // - // From the spec, the stop codon has _not_ been accounted for in any of the - // coding regions. Hence, we will treat (pieces of) the stop codon just - // like (pieces of) CDS. - // - // - // If there is no gene feature to go with this CDS then make one. Otherwise, - // make sure the existing gene feature includes the location of the CDS. - // - CRef pGene; - if (!x_FindParentGene(gff, pGene)) { - if (!x_CreateParentGene(gff, pAnnot)) { - return false; - } - } - else { - if (!x_MergeParentGene(gff, pGene)) { - return false; - } - } - - // - // If there is no CDS feature with this gene_id|transcript_id then make one. - // Otherwise, fix up the location of the existing one. - // - CRef pCds; - if (!x_FindParentCds(gff, pCds)) { - // - // Create a brand new CDS feature: - // - if (!x_CreateParentCds(gff, pAnnot)) { - return false; - } - x_FindParentCds(gff, pCds); - } - else { - // - // Update an already existing CDS features: - // - if (!x_MergeFeatureLocationMultiInterval(gff, pCds)) { - return false; - } - } - return true; -} - -// ---------------------------------------------------------------------------- -bool CGtfReader::x_UpdateAnnot5utr( - const CGff2Record& gff, - CRef< CSeq_annot > pAnnot ) -// ---------------------------------------------------------------------------- -{ - // - // If there is no gene feature to go with this CDS then make one. Otherwise, - // make sure the existing gene feature includes the location of the CDS. - // - CRef< CSeq_feat > pGene; - if ( ! x_FindParentGene( gff, pGene ) ) { - if ( ! x_CreateParentGene( gff, pAnnot ) ) { - return false; - } - } - else { - if ( ! x_MergeParentGene( gff, pGene ) ) { - return false; - } - } - - // - // If there is no mRNA feature with this gene_id|transcript_id then make one. - // Otherwise, fix up the location of the existing one. - // - CRef< CSeq_feat > pMrna; - if ( ! x_FindParentMrna( gff, pMrna ) ) { - // - // Create a brand new CDS feature: - // - if ( ! x_CreateParentMrna( gff, pAnnot ) ) { - return false; - } - } - else { - // - // Update an already existing CDS features: - // - if ( ! x_MergeFeatureLocationMultiInterval( gff, pMrna ) ) { - return false; - } - //if (!x_FeatureTrimQualifiers(gff, pMrna)) { - // return false; - //} - } - - return true; -} - -// ---------------------------------------------------------------------------- -bool CGtfReader::x_UpdateAnnot3utr( +bool CGtfReader::x_UpdateAnnotTranscript( const CGff2Record& gff, CRef< CSeq_annot > pAnnot ) // ---------------------------------------------------------------------------- @@ -568,83 +449,6 @@ bool CGtfReader::x_UpdateAnnot3utr( if ( ! x_MergeParentGene( gff, pGene ) ) { return false; } - } - - // - // If there is no mRNA feature with this gene_id|transcript_id then make one. - // Otherwise, fix up the location of the existing one. - // - CRef< CSeq_feat > pMrna; - if ( ! x_FindParentMrna( gff, pMrna ) ) { - // - // Create a brand new CDS feature: - // - if ( ! x_CreateParentMrna( gff, pAnnot ) ) { - return false; - } - } - else { - // - // Update an already existing CDS features: - // - if ( ! x_MergeFeatureLocationMultiInterval( gff, pMrna ) ) { - return false; - } - //if (!x_FeatureTrimQualifiers(gff, pMrna)) { - // return false; - //} - } - - return true; -} - -// ---------------------------------------------------------------------------- -bool CGtfReader::x_UpdateAnnotInter( - const CGff2Record& gff, - CRef< CSeq_annot > pAnnot ) -// ---------------------------------------------------------------------------- -{ - return true; -} - -// ---------------------------------------------------------------------------- -bool CGtfReader::x_UpdateAnnotInterCns( - const CGff2Record& gff, - CRef< CSeq_annot > pAnnot ) -// ---------------------------------------------------------------------------- -{ - return true; -} - -// ---------------------------------------------------------------------------- -bool CGtfReader::x_UpdateAnnotIntronCns( - const CGff2Record& gff, - CRef< CSeq_annot > pAnnot ) -// ---------------------------------------------------------------------------- -{ - return true; -} - -// ---------------------------------------------------------------------------- -bool CGtfReader::x_UpdateAnnotExon( - const CGff2Record& gff, - CRef< CSeq_annot > pAnnot ) -// ---------------------------------------------------------------------------- -{ - // - // If there is no gene feature to go with this CDS then make one. Otherwise, - // make sure the existing gene feature includes the location of the CDS. - // - CRef< CSeq_feat > pGene; - if ( ! x_FindParentGene( gff, pGene ) ) { - if ( ! x_CreateParentGene( gff, pAnnot ) ) { - return false; - } - } - else { - if (!x_MergeParentGene(gff, pGene)) { - return false; - } if (!x_FeatureTrimQualifiers(gff, pGene)) { return false; } @@ -667,7 +471,7 @@ bool CGtfReader::x_UpdateAnnotExon( // // Update an already existing CDS features: // - if (!x_MergeFeatureLocationMultiInterval(gff, pMrna)) { + if ( ! x_MergeFeatureLocationMultiInterval( gff, pMrna ) ) { return false; } if (!x_FeatureTrimQualifiers(gff, pMrna)) { @@ -678,15 +482,6 @@ bool CGtfReader::x_UpdateAnnotExon( return true; } -// ---------------------------------------------------------------------------- -bool CGtfReader::x_UpdateAnnotMiscFeature( - const CGff2Record& gff, - CRef< CSeq_annot > pAnnot ) -// ---------------------------------------------------------------------------- -{ - return true; -} - // ---------------------------------------------------------------------------- bool CGtfReader::x_CreateFeatureId( const CGff2Record& record, @@ -700,7 +495,7 @@ bool CGtfReader::x_CreateFeatureId( if (strFeatureId.empty()) { strFeatureId = "id"; } - strFeatureId += "|"; + strFeatureId += "_"; strFeatureId += NStr::IntToString(seqNum++); pFeature->SetId().SetLocal().SetStr( strFeatureId ); return true; @@ -712,8 +507,8 @@ bool CGtfReader::x_CreateFeatureLocation( CRef< CSeq_feat > pFeature ) // ---------------------------------------------------------------------------- { - CRef pId = CReadUtil::AsSeqId( - record.Id(), m_iFlags & fAllIdsAsLocal); + CRef pId = mSeqIdResolve( + record.Id(), m_iFlags & fAllIdsAsLocal, true); CSeq_interval& location = pFeature->SetLocation().SetInt(); location.SetId( *pId ); @@ -769,6 +564,30 @@ bool CGtfReader::x_CreateMrnaXrefs( return true; } + CRef< CSeqFeatXref > pXrefToChild( new CSeqFeatXref ); + pXrefToChild->SetId( pFeature->SetId() ); + pParent->SetXref().push_back( pXrefToChild ); + + if (m_iFlags & CGtfReader::fGenerateChildXrefs) { + CRef< CSeqFeatXref > pXrefToParent( new CSeqFeatXref ); + pXrefToParent->SetId( pParent->SetId() ); + pFeature->SetXref().push_back( pXrefToParent ); + } + + return true; +} + +// ---------------------------------------------------------------------------- +bool CGtfReader::x_CreateCdsXrefs( + const CGff2Record& record, + CRef< CSeq_feat > pFeature ) +// ---------------------------------------------------------------------------- +{ + CRef< CSeq_feat > pParent; + if ( ! x_FindParentCds( record, pParent ) ) { + return true; + } + CRef< CSeqFeatXref > pXrefToParent( new CSeqFeatXref ); pXrefToParent->SetId( pParent->SetId() ); pFeature->SetXref().push_back( pXrefToParent ); @@ -807,8 +626,8 @@ bool CGtfReader::x_MergeFeatureLocationMultiInterval( CRef< CSeq_feat > pFeature ) // ---------------------------------------------------------------------------- { - CRef pId = CReadUtil::AsSeqId( - record.Id(), m_iFlags & fAllIdsAsLocal); + CRef pId = mSeqIdResolve( + record.Id(), m_iFlags & fAllIdsAsLocal, true); CRef< CSeq_loc > pLocation( new CSeq_loc ); pLocation->SetInt().SetId( *pId ); @@ -870,6 +689,9 @@ bool CGtfReader::xFeatureSetQualifiersGene( CRef< CSeq_feat > pFeature ) // ---------------------------------------------------------------------------- { + list ignoredAttrs = { + "locus_tag", "transcript_id" + }; // // Create GB qualifiers for the record attributes: // @@ -877,8 +699,68 @@ bool CGtfReader::xFeatureSetQualifiersGene( const CGff2Record::TAttributes& attrs = record.Attributes(); CGff2Record::TAttrCit it = attrs.begin(); for (/*NOOP*/; it != attrs.end(); ++it) { - // gtf genes don't get transcript_id - if (it->first == "transcript_id") { + auto cit = std::find(ignoredAttrs.begin(), ignoredAttrs.end(), it->first); + if (cit != ignoredAttrs.end()) { + continue; + } + // special case some well-known attributes + if (x_ProcessQualifierSpecialCase(it, pFeature)) { + continue; + } + + // turn everything else into a qualifier + pQual.Reset(new CGb_qual); + pQual->SetQual(it->first); + pQual->SetVal(it->second); + pFeature->SetQual().push_back(pQual); + } + return true; +} + +// ---------------------------------------------------------------------------- +bool CGtfReader::xFeatureSetQualifiersRna( + const CGff2Record& record, + CRef< CSeq_feat > pFeature ) +// ---------------------------------------------------------------------------- +{ + list ignoredAttrs = { + "locus_tag" + }; + + const CGff2Record::TAttributes& attrs = record.Attributes(); + CGff2Record::TAttrCit it = attrs.begin(); + for (/*NOOP*/; it != attrs.end(); ++it) { + auto cit = std::find(ignoredAttrs.begin(), ignoredAttrs.end(), it->first); + if (cit != ignoredAttrs.end()) { + continue; + } + // special case some well-known attributes + if (x_ProcessQualifierSpecialCase(it, pFeature)) { + continue; + } + + // turn everything else into a qualifier + pFeature->AddQualifier(it->first, it->second); + } + return true; +} + +// ---------------------------------------------------------------------------- +bool CGtfReader::xFeatureSetQualifiersCds( + const CGff2Record& record, + CRef< CSeq_feat > pFeature ) +// ---------------------------------------------------------------------------- +{ + list ignoredAttrs = { + "locus_tag" + }; + + CRef< CGb_qual > pQual(0); + const CGff2Record::TAttributes& attrs = record.Attributes(); + CGff2Record::TAttrCit it = attrs.begin(); + for (/*NOOP*/; it != attrs.end(); ++it) { + auto cit = std::find(ignoredAttrs.begin(), ignoredAttrs.end(), it->first); + if (cit != ignoredAttrs.end()) { continue; } // special case some well-known attributes @@ -931,7 +813,7 @@ bool CGtfReader::x_CreateParentCds( if ( ! x_CreateMrnaXrefs( gff, pFeature ) ) { return false; } - if ( ! x_FeatureSetQualifiers( gff, pFeature ) ) { + if ( ! xFeatureSetQualifiersCds( gff, pFeature ) ) { return false; } @@ -963,7 +845,10 @@ bool CGtfReader::x_CreateParentMrna( if ( ! x_CreateGeneXrefs( gff, pFeature ) ) { return false; } - if ( ! x_FeatureSetQualifiers( gff, pFeature ) ) { + if ( ! x_CreateCdsXrefs( gff, pFeature ) ) { + return false; + } + if ( ! xFeatureSetQualifiersRna( gff, pFeature ) ) { return false; } @@ -1020,16 +905,15 @@ bool CGtfReader::x_FeatureSetDataGene( CRef< CSeq_feat > pFeature ) // ---------------------------------------------------------------------------- { - if ( ! CGff2Reader::x_FeatureSetDataGene( record, pFeature ) ) { - return false; - } - CGene_ref& gene = pFeature->SetData().SetGene(); string strValue; - if ( record.GetAttribute( "gene_synonym", strValue ) ) { + if (record.GetAttribute( "gene_synonym", strValue)) { gene.SetSyn().push_back( strValue ); } + if (record.GetAttribute("locus_tag", strValue)) { + gene.SetLocus_tag(strValue); + } // mss-399: do -not- use gene_id for /gene_syn or /gene: //if ( record.GetAttribute( "gene_id", strValue ) ) { // gene.SetSyn().push_front( strValue ); @@ -1043,8 +927,7 @@ bool CGtfReader::x_FeatureSetDataMRNA( CRef pFeature) // ---------------------------------------------------------------------------- { - if ( ! CGff2Reader::x_FeatureSetDataRna( - record, pFeature, CSeqFeatData::eSubtype_mRNA)) { + if ( !x_FeatureSetDataRna( record, pFeature, CSeqFeatData::eSubtype_mRNA)) { return false; } @@ -1059,19 +942,37 @@ bool CGtfReader::x_FeatureSetDataMRNA( } // ---------------------------------------------------------------------------- -bool CGtfReader::x_FeatureSetDataCDS( +bool CGtfReader::x_FeatureSetDataRna( const CGff2Record& record, - CRef< CSeq_feat > pFeature ) + CRef< CSeq_feat > pFeature, + CSeqFeatData::ESubtype subType) // ---------------------------------------------------------------------------- { - if ( ! CGff2Reader::x_FeatureSetDataCDS( record, pFeature ) ) { - return false; + CRNA_ref& rnaRef = pFeature->SetData().SetRna(); + switch (subType){ + default: + rnaRef.SetType(CRNA_ref::eType_miscRNA); + break; + case CSeqFeatData::eSubtype_mRNA: + rnaRef.SetType(CRNA_ref::eType_mRNA); + break; + case CSeqFeatData::eSubtype_rRNA: + rnaRef.SetType(CRNA_ref::eType_rRNA); + break; } + return true; +} +// ---------------------------------------------------------------------------- +bool CGtfReader::x_FeatureSetDataCDS( + const CGff2Record& record, + CRef< CSeq_feat > pFeature ) +// ---------------------------------------------------------------------------- +{ CCdregion& cdr = pFeature->SetData().SetCdregion(); string strValue; if ( record.GetAttribute( "protein_id", strValue ) ) { - CRef pId = CReadUtil::AsSeqId(strValue,m_iFlags); + CRef pId = mSeqIdResolve(strValue,m_iFlags, true); if (pId->IsGenbank()) { pFeature->SetProduct().SetWhole(*pId); } diff --git a/c++/src/objtools/readers/gvf_reader.cpp b/c++/src/objtools/readers/gvf_reader.cpp index e08048e9..a9791725 100644 --- a/c++/src/objtools/readers/gvf_reader.cpp +++ b/c++/src/objtools/readers/gvf_reader.cpp @@ -1,4 +1,4 @@ - /* $Id: gvf_reader.cpp 515629 2016-10-04 17:46:33Z ivanov $ + /* $Id: gvf_reader.cpp 542725 2017-08-02 11:32:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -92,10 +92,8 @@ #include #include #include -#include #include #include -#include #include #include @@ -376,7 +374,7 @@ bool CGvfReader::x_SetLocationInterval( CRef pLocation) // ---------------------------------------------------------------------------- { - CRef< CSeq_id > pId = CReadUtil::AsSeqId(record.Id(), m_iFlags); + CRef< CSeq_id > pId = mSeqIdResolve(record.Id(), m_iFlags, true); pLocation->SetInt().SetId(*pId); pLocation->SetInt().SetFrom(record.SeqStart()); @@ -484,7 +482,7 @@ bool CGvfReader::x_SetLocationPoint( CRef pLocation) // ---------------------------------------------------------------------------- { - CRef< CSeq_id > pId = CReadUtil::AsSeqId(record.Id(), m_iFlags); + CRef< CSeq_id > pId = mSeqIdResolve(record.Id(), m_iFlags, true); pLocation->SetPnt().SetId(*pId); if (record.Type() == "insertion") { //for insertions, GVF uses insert-after logic while NCBI uses insert-before @@ -566,7 +564,7 @@ bool CGvfReader::xFeatureSetLocationInterval( CRef< CSeq_feat > pFeature ) // ---------------------------------------------------------------------------- { - CRef< CSeq_id > pId = CReadUtil::AsSeqId(record.Id(), m_iFlags); + CRef< CSeq_id > pId = mSeqIdResolve(record.Id(), m_iFlags, true); CRef< CSeq_loc > pLocation( new CSeq_loc ); pLocation->SetInt().SetId(*pId); pLocation->SetInt().SetFrom(record.SeqStart()); @@ -673,7 +671,7 @@ bool CGvfReader::xFeatureSetLocationPoint( CRef< CSeq_feat > pFeature ) // ---------------------------------------------------------------------------- { - CRef< CSeq_id > pId = CReadUtil::AsSeqId(record.Id(), m_iFlags); + CRef< CSeq_id > pId = mSeqIdResolve(record.Id(), m_iFlags, true); CRef< CSeq_loc > pLocation( new CSeq_loc ); pLocation->SetPnt().SetId(*pId); if (record.Type() == "insertion") { diff --git a/c++/src/objtools/readers/idmapper_config.cpp b/c++/src/objtools/readers/idmapper_config.cpp index 945fb938..a0bb7cf9 100644 --- a/c++/src/objtools/readers/idmapper_config.cpp +++ b/c++/src/objtools/readers/idmapper_config.cpp @@ -1,4 +1,4 @@ -/* $Id: idmapper_config.cpp 501592 2016-05-17 15:27:30Z grichenk $ +/* $Id: idmapper_config.cpp 536284 2017-05-17 12:39:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -205,7 +205,7 @@ CIdMapperConfig::AddMapEntry( // ============================================================================ { vector columns; - NStr::Split(strLine, " \t", columns, NStr::fSplit_MergeDelims); + NStr::Split(strLine, " \t", columns, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); //sanity check: two or three columns. If three columns, the last better be //integer diff --git a/c++/src/objtools/readers/microarray_reader.cpp b/c++/src/objtools/readers/microarray_reader.cpp index 5c9e8c2f..376cb3fb 100644 --- a/c++/src/objtools/readers/microarray_reader.cpp +++ b/c++/src/objtools/readers/microarray_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: microarray_reader.cpp 515629 2016-10-04 17:46:33Z ivanov $ +/* $Id: microarray_reader.cpp 536287 2017-05-17 13:05:21Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -160,7 +160,7 @@ CMicroArrayReader::ReadSeqAnnot( // parse vector fields; - NStr::Split( record_copy, " \t", fields, NStr::eMergeDelims ); + NStr::Split(record_copy, " \t", fields, NStr::fSplit_MergeDelimiters); try { xCleanColumnValues(fields); } diff --git a/c++/src/objtools/readers/read_util.cpp b/c++/src/objtools/readers/read_util.cpp index e409ee1f..d5f993b7 100644 --- a/c++/src/objtools/readers/read_util.cpp +++ b/c++/src/objtools/readers/read_util.cpp @@ -1,4 +1,4 @@ -/* $Id: read_util.cpp 494824 2016-03-10 19:12:03Z ludwigf $ +/* $Id: read_util.cpp 542725 2017-08-02 11:32:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -71,10 +71,10 @@ void CReadUtil::Tokenize( } } if (temp.empty()) { - NStr::Split(str, delim, parts, NStr::eMergeDelims); + NStr::Split(str, delim, parts, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); return; } - NStr::Split(temp, delim, parts, NStr::eMergeDelims); + NStr::Split(temp, delim, parts, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); for (size_t j=0; j < parts.size(); ++j) { for (size_t i=0; i < parts[j].size(); ++i) { if (parts[j][i] == joiner) { @@ -84,7 +84,6 @@ void CReadUtil::Tokenize( } } - // ----------------------------------------------------------------- CRef CReadUtil::AsSeqId( const string& givenId, @@ -132,6 +131,7 @@ CRef CReadUtil::AsSeqId( return CRef(new CSeq_id(CSeq_id::e_Local, rawId)); } + // ---------------------------------------------------------------------------- bool CReadUtil::GetTrackName( const CSeq_annot& annot, diff --git a/c++/src/objtools/readers/reader_base.cpp b/c++/src/objtools/readers/reader_base.cpp index a23916c9..ea4cf18d 100644 --- a/c++/src/objtools/readers/reader_base.cpp +++ b/c++/src/objtools/readers/reader_base.cpp @@ -1,4 +1,4 @@ -/* $Id: reader_base.cpp 515630 2016-10-04 17:46:56Z ivanov $ +/* $Id: reader_base.cpp 542725 2017-08-02 11:32:01Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -148,7 +148,8 @@ CReaderBase::GetReader( CReaderBase::CReaderBase( TReaderFlags flags, const string& annotName, - const string& annotTitle) : + const string& annotTitle, + SeqIdResolver seqidresolver) : // ---------------------------------------------------------------------------- m_uLineNumber(0), m_uProgressReportInterval(0), @@ -157,7 +158,8 @@ CReaderBase::CReaderBase( m_AnnotName(annotName), m_AnnotTitle(annotTitle), m_pReader(0), - m_pCanceler(0) + m_pCanceler(0), + mSeqIdResolve(seqidresolver) { m_pTrackDefaults = new CTrackData; } @@ -222,10 +224,10 @@ CReaderBase::ReadSeqAnnots( ILineErrorListener* pMessageListener ) // ---------------------------------------------------------------------------- { + xReadInit(); xProgressInit(lr); CRef annot = ReadSeqAnnot(lr, pMessageListener); while (annot) { - //xAssignTrackData(annot); annots.push_back(annot); annot = ReadSeqAnnot(lr, pMessageListener); } @@ -408,7 +410,7 @@ bool CReaderBase::xParseBrowserLine( CAnnot_descr& desc = annot->SetDesc(); vector fields; - NStr::Split( strLine, " \t", fields, NStr::eMergeDelims ); + NStr::Split(strLine, " \t", fields, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); for ( vector::iterator it = fields.begin(); it != fields.end(); ++it ) { if ( *it == "position" ) { ++it; @@ -647,7 +649,11 @@ bool CReaderBase::xIsTrackTerminator( const CTempString& strLine) // ---------------------------------------------------------------------------- { - return (NStr::TruncateSpaces(strLine) == "###"); + auto line = NStr::TruncateSpaces(strLine); + if (NStr::StartsWith(line, "##sequence-region")) { + return true; + } + return (line == "###"); } // ---------------------------------------------------------------------------- @@ -664,6 +670,11 @@ bool CReaderBase::xGetLine( string& line) // ---------------------------------------------------------------------------- { + if (!m_PendingLine.empty()) { + line = m_PendingLine; + m_PendingLine.clear(); + return true; + } CTempString temp; while (!lr.AtEOF()) { temp = *++lr; diff --git a/c++/src/objtools/readers/readfeat.cpp b/c++/src/objtools/readers/readfeat.cpp index cbd4f2fa..335ac296 100644 --- a/c++/src/objtools/readers/readfeat.cpp +++ b/c++/src/objtools/readers/readfeat.cpp @@ -96,22 +96,16 @@ #define NCBI_USE_ERRCODE_X Objtools_Rd_Feature -#define FTBL_PROGRESS(listener, _sSeqid, _uLineNum) \ - do { \ - const Uint8 uLineNum = (_uLineNum); \ - CNcbiOstrstream err_strm; \ - err_strm << "Seq-id " << (_sSeqid) << ", line " << uLineNum; \ - listener->PutProgress(CNcbiOstrstreamToString(err_strm)); \ - } while(false) - BEGIN_NCBI_SCOPE BEGIN_objects_SCOPE // namespace ncbi::objects:: + + namespace { static const char * const kCdsFeatName = "CDS"; // priorities, inherited from C toolkit - static Uint1 std_order[CSeq_id::e_MaxChoice] = { + static Uchar std_order[CSeq_id::e_MaxChoice] = { 83, /* 0 = not set */ 80, /* 1 = local Object-id */ 70, /* 2 = gibbsq */ @@ -143,10 +137,10 @@ CRef GetBestId(const CBioseq::TId& ids) CRef id; if (!ids.empty()) { - Uint1 best_weight = UINT_MAX; + Uchar best_weight = UCHAR_MAX; ITERATE(CBioseq::TId, it, ids) { - Uint1 new_weight = std_order[(*it)->Which()]; + Uchar new_weight = std_order[(*it)->Which()]; if (new_weight < best_weight) { id = *it; @@ -158,8 +152,30 @@ CRef GetBestId(const CBioseq::TId& ids) return id; } + +map> s_IUPACmap +{ + {'A', list({'A'})}, + {'G', list({'G'})}, + {'C', list({'C'})}, + {'T', list({'T'})}, + {'U', list({'U'})}, + {'M', list({'A', 'C'})}, + {'R', list({'A', 'G'})}, + {'W', list({'A', 'T'})}, + {'S', list({'C', 'G'})}, + {'Y', list({'C', 'T'})}, + {'K', list({'G', 'T'})}, + {'V', list({'A', 'C', 'G'})}, + {'H', list({'A', 'C', 'T'})}, + {'D', list({'A', 'G', 'T'})}, + {'B', list({'C', 'G', 'T'})}, + {'N', list({'A', 'C', 'G', 'T'})} +}; + } + class /* NCBI_XOBJREAD_EXPORT */ CFeature_table_reader_imp { public: @@ -306,13 +322,16 @@ public: string & out_seqid, string & out_annotname ); + static void PutProgress(const string& seq_id, + const unsigned int line_number, + ILineErrorListener* pListener); private: // Prohibit copy constructor and assignment operator CFeature_table_reader_imp(const CFeature_table_reader_imp& value); CFeature_table_reader_imp& operator=(const CFeature_table_reader_imp& value); - void x_InitId(const string& seq_id); + void x_InitId(const string& seq_id, const CFeature_table_reader::TFlags flags); // returns true if parsed (otherwise, out_offset is left unchanged) bool x_TryToParseOffset(const CTempString & sLine, Int4 & out_offset ); @@ -347,12 +366,21 @@ private: bool x_AddQualifierToBioSrc (CSeqFeatData& sfdata, COrgMod::ESubtype mtype, const string& val); + bool x_AddNoteToFeature(CRef sfp, const string& note); + + bool x_AddNoteToFeature(CRef sfp, + const string& feat_name, + const string& qual, + const string& val); + bool x_AddGBQualToFeature (CRef sfp, const string& qual, const string& val); bool x_AddGeneOntologyToFeature (CRef sfp, const CTempString& qual, const CTempString& val); + bool x_AddCodons(const string& val, CTrna_ext& trna_ext) const; + typedef CConstRef TFeatConstRef; struct SFeatAndLineNum { SFeatAndLineNum( @@ -410,6 +438,7 @@ private: const std::string & strFeatureName = kEmptyStr, const std::string & strQualifierName = kEmptyStr, const std::string & strQualifierValue = kEmptyStr, + const std::string & strErrorMessage = kEmptyStr, const ILineError::TVecOfLines & vecOfOtherLines = ILineError::TVecOfLines() ); @@ -420,6 +449,7 @@ private: const std::string & strFeatureName = kEmptyStr, const std::string & strQualifierName = kEmptyStr, const std::string & strQualifierValue = kEmptyStr, + const std::string & strErrorMessage = kEmptyStr, const ILineError::TVecOfLines & vecOfOtherLines = ILineError::TVecOfLines()); @@ -432,10 +462,10 @@ private: bool m_need_check_strand; string m_real_seqid; - unsigned int m_line_num; CRef m_seq_id; - ILineErrorListener* m_pMessageListener; ILineReader* m_reader; + unsigned int m_line_num; + ILineErrorListener* m_pMessageListener; }; typedef SStaticPair TQualKey; @@ -808,6 +838,8 @@ bool CFeature_table_reader_imp::x_TryToParseOffset( // "=" not found return false; } + + // check key NStr::TruncateSpacesInPlace(sKey); @@ -832,9 +864,9 @@ bool CFeature_table_reader_imp::x_TryToParseOffset( // is it a number? try { Int4 new_offset = NStr::StringToInt(sValue); - if( new_offset < 0 ) { - return false; - } + // if( new_offset < 0 ) { + // return false; + // } out_offset = new_offset; return true; } catch ( CStringException & ) { @@ -869,6 +901,7 @@ bool CFeature_table_reader_imp::x_ParseFeatureTableLine ( string start, stop, feat, qual, val, stnd; vector tkns; + if (line.empty ()) return false; /* offset and other instructions encoded in brackets */ @@ -901,6 +934,7 @@ bool CFeature_table_reader_imp::x_ParseFeatureTableLine ( stnd = NStr::TruncateSpaces(tkns[5]); } + bool has_start = false; if (! start.empty ()) { if (start [0] == '<') { partial5 = true; @@ -913,8 +947,10 @@ bool CFeature_table_reader_imp::x_ParseFeatureTableLine ( } startv = x_StringToLongNoThrow(start, feat, qual, ILineError::eProblem_BadFeatureInterval); + has_start = true; } + bool has_stop = false; if (! stop.empty ()) { if (stop [0] == '>') { partial3 = true; @@ -922,8 +958,9 @@ bool CFeature_table_reader_imp::x_ParseFeatureTableLine ( } stopv = x_StringToLongNoThrow (stop, feat, qual, ILineError::eProblem_BadFeatureInterval); + has_stop = true; } - + if ( startv <= 0 || stopv <= 0 ) { startv = -1; stopv = -1; @@ -942,8 +979,24 @@ bool CFeature_table_reader_imp::x_ParseFeatureTableLine ( } } - *startP = ( startv < 0 ? -1 : startv + offset ); - *stopP = ( stopv < 0 ? -1 : stopv + offset ); + if (startv >= 0) { + startv += offset; + } + if (stopv >= 0) { + stopv += offset; + } + + if ((has_start && startv < 0) || (has_stop && stopv < 0)) { + x_ProcessMsg( + ILineError::eProblem_FeatureBadStartAndOrStop, + eDiag_Error, + feat); + } + + *startP = ( startv < 0 ? -1 : startv); + *stopP = ( stopv < 0 ? -1 : stopv); + + *partial5P = partial5; *partial3P = partial3; *ispointP = ispoint; @@ -1184,12 +1237,22 @@ bool CFeature_table_reader_imp::x_AddQualifierToCdregion ( // set genetic code directly, or add qualifier and let cleanup convert? try { int num = NStr::StringToLong(val); + CGen_code_table::GetTransTable(num); // throws if bad num CRef code(new CGenetic_code::C_E()); code->SetId(num); crp.SetCode().Set().push_back(code); return true; - } catch( ... ) { + } catch( CStringException ) { + // if val is not a number, add qualifier directly and + // let cleanup convert? return x_AddGBQualToFeature(sfp, "transl_table", val); + } catch( ... ) { + // invalid genome code table so don't even try to make + // the transl_table qual + x_ProcessMsg( + ILineError::eProblem_QualifierBadValue, eDiag_Error, + kCdsFeatName, "transl_table", val); + return true; } break; @@ -1267,6 +1330,7 @@ s_LocationJoinToOrder( const CSeq_loc & loc ) } } + int CFeature_table_reader_imp::x_ParseTrnaString ( const string& val ) @@ -1277,10 +1341,11 @@ int CFeature_table_reader_imp::x_ParseTrnaString ( if (NStr::StartsWith(value, "tRNA-")) { value.assign(value, strlen("tRNA-"), CTempString::npos); } - CTempString::size_type pos = value.find('('); - if (pos != CTempString::npos) - { + + CTempString::size_type pos = value.find_first_of("-,;:()=\'_~"); + if (pos != CTempString::npos) { value.erase(pos); + NStr::TruncateSpacesInPlace(value); } TTrnaMap::const_iterator t_iter = sm_TrnaKeys.find(string(value).c_str()); @@ -1301,9 +1366,19 @@ CFeature_table_reader_imp::x_ParseTrnaExtString(CTrna_ext & ext_trna, const stri string::size_type pos_end = x_MatchingParenPos( str, 0 ); if (pos_end != string::npos) { string pos_str = str.substr (5, pos_end - 5); - string::size_type aa_start = NStr::FindNoCase (pos_str, "aa:"); + string::size_type aa_start = NStr::FindNoCase(pos_str, "aa:"); if (aa_start != string::npos) { - string abbrev = pos_str.substr (aa_start + 3); + auto seq_start = NStr::FindNoCase(pos_str, ",seq:"); + if (seq_start != string::npos && + seq_start < aa_start+3) { + return false; + } + + size_t aa_length = (seq_start == NPOS) ? + pos_str.size() - (aa_start+3) : + seq_start - (aa_start+3); + + string abbrev = pos_str.substr (aa_start + 3, aa_length); TTrnaMap::const_iterator t_iter = sm_TrnaKeys.find (abbrev.c_str ()); if (t_iter == sm_TrnaKeys.end ()) { // unable to parse @@ -1491,7 +1566,7 @@ bool CFeature_table_reader_imp::x_AddQualifierToRna ( if (rrp.IsSetExt() && rrp.GetExt().Which() == CRNA_ref::C_Ext::e_Name) return false; - sfp->SetComment(val); + // sfp->SetComment(val); int aaval = x_ParseTrnaString(val); if (aaval > 0) { CRNA_ref::TExt& tex = rrp.SetExt (); @@ -1521,10 +1596,14 @@ bool CFeature_table_reader_imp::x_AddQualifierToRna ( break; case eQual_codon_recognized: { - CRNA_ref::TExt& tex = rrp.SetExt (); - CRNA_ref::C_Ext::TTRNA & ext_trna = tex.SetTRNA(); - ext_trna.SetAa().SetNcbieaa(); - ext_trna.SetCodon().push_back( CGen_code_table::CodonToIndex(val) ); + //const auto codon_index = CGen_code_table::CodonToIndex(val); + //if (codon_index >= 0) { + CRNA_ref::TExt& tex = rrp.SetExt (); + CRNA_ref::C_Ext::TTRNA & ext_trna = tex.SetTRNA(); + if (!x_AddCodons(val, ext_trna)) { + return false; + } + //} return true; } break; @@ -1539,6 +1618,40 @@ bool CFeature_table_reader_imp::x_AddQualifierToRna ( } +bool CFeature_table_reader_imp::x_AddCodons( + const string& val, + CTrna_ext& trna_ext + ) const +{ + if (val.size() != 3) { + return false; + } + + set codons; + try { + for (char char1 : s_IUPACmap.at(val[0])) { + for (char char2 : s_IUPACmap.at(val[1])) { + for (char char3 : s_IUPACmap.at(val[2])) { + const auto codon_index = CGen_code_table::CodonToIndex(char1, char2, char3); + codons.insert(codon_index); + } + } + } + + if (!codons.empty()) { + trna_ext.SetAa().SetNcbieaa(); + for (const auto codon_index : codons) { + trna_ext.SetCodon().push_back(codon_index); + } + } + return true; + } + catch(...) {} + + return false; +} + + bool CFeature_table_reader_imp::x_AddQualifierToImp ( CRef sfp, CSeqFeatData& sfdata, @@ -1557,26 +1670,31 @@ bool CFeature_table_reader_imp::x_AddQualifierToImp ( if( (subtype == CSeqFeatData::eSubtype_regulatory) || CSeqFeatData::IsRegulatory(subtype) ) { - switch (qtype) - { - case eQual_regulatory_class: - { + if (qtype == eQual_regulatory_class) { + if (val != "other") { // RW-374 "other" is a special case + + const vector& allowed_values = + CSeqFeatData::GetRegulatoryClassList(); + if (find(allowed_values.cbegin(), allowed_values.cend(), val) + == allowed_values.cend()) { + return false; + } + +/* const CSeqFeatData::ESubtype regulatory_class_subtype = CSeqFeatData::GetRegulatoryClass(val); if( regulatory_class_subtype == CSeqFeatData::eSubtype_bad ) { // msg will be sent in caller x_AddQualifierToFeature return false; - } else { - // okay - // (Note that at this time we don't validate - // if the regulatory_class actually matches the - // subtype) - x_AddGBQualToFeature(sfp, qual, val); - return true; - } + } + */ } - default: - break; + // okay + // (Note that at this time we don't validate + // if the regulatory_class actually matches the + // subtype) + x_AddGBQualToFeature(sfp, qual, val); + return true; } } @@ -1942,6 +2060,18 @@ void CFeature_table_reader_imp::x_CreateGenesFromCDSs( // this CDS xrefs. It should be somewhat uncommon for there // to be more than one matching gene. set matchingGenes; + + const string locus = + pGeneXrefOnCDS->IsSetLocus() ? + pGeneXrefOnCDS->GetLocus() : + ""; + + const string locus_tag = + pGeneXrefOnCDS->IsSetLocus_tag() ? + pGeneXrefOnCDS->GetLocus_tag() : + ""; + + {{ // all the code in this scope is all just for setting up matchingGenes @@ -1949,25 +2079,39 @@ void CFeature_table_reader_imp::x_CreateGenesFromCDSs( typedef pair TStrToGeneEqualRange; set locusGeneMatches; // add the locus matches (if any) to genesAlreadyCreated - if( ! RAW_FIELD_IS_EMPTY_OR_UNSET(*pGeneXrefOnCDS, Locus) ) { + if( !NStr::IsBlank(locus) ) { TStrToGeneEqualRange locus_equal_range = - locusToGeneAndLineMap.equal_range(pGeneXrefOnCDS->GetLocus()); + locusToGeneAndLineMap.equal_range(locus); for( TStrToGeneCI locus_gene_ci = locus_equal_range.first; locus_gene_ci != locus_equal_range.second; ++locus_gene_ci ) { + if (!NStr::IsBlank(locus_tag)) { + auto gene_feat = locus_gene_ci->second.m_pFeat; + if (gene_feat->GetData().GetGene().IsSetLocus_tag() && + gene_feat->GetData().GetGene().GetLocus_tag() != locus_tag) { + continue; + } + } locusGeneMatches.insert(locus_gene_ci->second); } } // remove any that don't also match the locus-tag (if any) set locusTagGeneMatches; - if( ! RAW_FIELD_IS_EMPTY_OR_UNSET(*pGeneXrefOnCDS, Locus_tag) ) { + if( !NStr::IsBlank(locus_tag) ) { TStrToGeneEqualRange locus_tag_equal_range = - locusTagToGeneAndLineMap.equal_range(pGeneXrefOnCDS->GetLocus_tag()); + locusTagToGeneAndLineMap.equal_range(locus_tag); for( TStrToGeneCI locus_tag_gene_ci = locus_tag_equal_range.first; locus_tag_gene_ci != locus_tag_equal_range.second; ++locus_tag_gene_ci ) { + if (!NStr::IsBlank(locus)) { + auto gene_feat = locus_tag_gene_ci->second.m_pFeat; + if (gene_feat->GetData().GetGene().IsSetLocus() && + gene_feat->GetData().GetGene().GetLocus() != locus) { + continue; + } + } locusTagGeneMatches.insert(locus_tag_gene_ci->second); } } @@ -1994,16 +2138,6 @@ void CFeature_table_reader_imp::x_CreateGenesFromCDSs( const CSeq_loc & gene_loc = gene_feat_and_line_ci->m_pFeat->GetLocation(); const TSeqPos gene_line_num = gene_feat_and_line_ci->m_uLineNum; - // check if we're attempting to create a gene we've already created - if( (flags & CFeature_table_reader::fCreateGenesFromCDSs) != 0 && - gene_line_num < 1 ) - { - x_ProcessMsg( - cds_line_num, - ILineError::eProblem_CreatedGeneFromMultipleFeats, eDiag_Error, - kCdsFeatName ); - } - if ((flags & CFeature_table_reader::fCDSsMustBeInTheirGenes) != 0) { // CDS's loc minus gene's loc should be an empty location @@ -2022,7 +2156,7 @@ void CFeature_table_reader_imp::x_CreateGenesFromCDSs( cds_line_num, ILineError::eProblem_FeatMustBeInXrefdGene, eDiag_Error, kCdsFeatName, - kEmptyStr, kEmptyStr, + kEmptyStr, kEmptyStr, kEmptyStr, gene_lines ); } } @@ -2087,6 +2221,46 @@ static string s_FixQualCapitalization (const string& qual) } +bool CFeature_table_reader_imp::x_AddNoteToFeature( + CRef sfp, + const string& note) +{ + if (sfp.IsNull()) { + return false; + } + + if (NStr::IsBlank(note)) { // Nothing to do + return true; + } + + string comment = (sfp->CanGetComment()) ? + sfp->GetComment() + "; " + note : + note; + sfp->SetComment(comment); + return true; +} + + +bool CFeature_table_reader_imp::x_AddNoteToFeature( + CRef sfp, + const string& feat_name, + const string& qual, + const string& val) { + + if (!x_AddNoteToFeature(sfp, val)) { + return false; + } + // Else convert qualifier to note and issue warning + if (qual != "note") { + string error_message = + qual + " is not a valid qualifier for this feature. Converting to note."; + x_ProcessMsg( + ILineError::eProblem_InvalidQualifier, eDiag_Warning, + feat_name, qual, kEmptyStr, error_message); + } + return true; +} + bool CFeature_table_reader_imp::x_AddQualifierToFeature ( CRef sfp, const string &feat_name, @@ -2115,7 +2289,6 @@ bool CFeature_table_reader_imp::x_AddQualifierToFeature ( if (o_iter != sm_OrgRefKeys.end ()) { EOrgRef rtype = o_iter->second; if (x_AddQualifierToBioSrc (sfdata, feat_name, rtype, val)) return true; - } else { TSubSrcMap::const_iterator s_iter = sm_SubSrcKeys.find (qual.c_str ()); @@ -2131,274 +2304,285 @@ bool CFeature_table_reader_imp::x_AddQualifierToFeature ( COrgMod::ESubtype mtype = m_iter->second; if (x_AddQualifierToBioSrc (sfdata, mtype, val)) return true; - } } } + return false; + } - } else { - string lqual = s_FixQualCapitalization(qual); - TQualMap::const_iterator q_iter = sm_QualKeys.find (lqual.c_str ()); - if (q_iter != sm_QualKeys.end ()) { - EQual qtype = q_iter->second; - switch (typ) { - case CSeqFeatData::e_Gene: - if (x_AddQualifierToGene (sfdata, qtype, val)) return true; - break; - case CSeqFeatData::e_Cdregion: - if (x_AddQualifierToCdregion (sfp, sfdata, qtype, val)) return true; - break; - case CSeqFeatData::e_Rna: - if (x_AddQualifierToRna (sfp, qtype, val)) return true; - break; - case CSeqFeatData::e_Imp: - if (x_AddQualifierToImp (sfp, sfdata, qtype, qual, val)) return true; - break; - case CSeqFeatData::e_Region: - if (qtype == eQual_region_name) { - sfdata.SetRegion (val); - return true; - } - break; - case CSeqFeatData::e_Bond: - if (qtype == eQual_bond_type) { - CSeqFeatData::EBond btyp = CSeqFeatData::eBond_other; - if (CSeqFeatData::GetBondList()->IsBondName(val.c_str(), btyp)) { - sfdata.SetBond (btyp); - return true; - } - } - break; - case CSeqFeatData::e_Site: - if (qtype == eQual_site_type) { - CSeqFeatData::ESite styp = CSeqFeatData::eSite_other; - if (CSeqFeatData::GetSiteList()->IsSiteName( val.c_str(), styp)) { - sfdata.SetSite (styp); - return true; - } - } - break; - case CSeqFeatData::e_Pub: - if( qtype == eQual_PubMed ) { - CRef new_pub( new CPub ); - new_pub->SetPmid( CPubMedId( x_StringToLongNoThrow(val, feat_name, qual) ) ); - sfdata.SetPub().SetPub().Set().push_back( new_pub ); + + // else type != CSeqFeatData::e_Biosrc + string lqual = s_FixQualCapitalization(qual); + TQualMap::const_iterator q_iter = sm_QualKeys.find (lqual.c_str ()); + if (q_iter != sm_QualKeys.end ()) { + EQual qtype = q_iter->second; + switch (typ) { + case CSeqFeatData::e_Gene: + if (x_AddQualifierToGene (sfdata, qtype, val)) return true; + break; + case CSeqFeatData::e_Cdregion: + if (x_AddQualifierToCdregion (sfp, sfdata, qtype, val)) return true; + break; + case CSeqFeatData::e_Rna: + if (x_AddQualifierToRna (sfp, qtype, val)) return true; + break; + case CSeqFeatData::e_Imp: + if (x_AddQualifierToImp (sfp, sfdata, qtype, qual, val)) return true; + break; + case CSeqFeatData::e_Region: + if (qtype == eQual_region_name) { + sfdata.SetRegion (val); + return true; + } + break; + case CSeqFeatData::e_Bond: + if (qtype == eQual_bond_type) { + CSeqFeatData::EBond btyp = CSeqFeatData::eBond_other; + if (CSeqFeatData::GetBondList()->IsBondName(val.c_str(), btyp)) { + sfdata.SetBond (btyp); return true; } - break; - case CSeqFeatData::e_Prot: - switch( qtype ) { - case eQual_product: - sfdata.SetProt().SetName().push_back( val ); - return true; - case eQual_function: - sfdata.SetProt().SetActivity().push_back( val ); - return true; - case eQual_EC_number: - sfdata.SetProt().SetEc().push_back( val ); + } + break; + case CSeqFeatData::e_Site: + if (qtype == eQual_site_type) { + CSeqFeatData::ESite styp = CSeqFeatData::eSite_other; + if (CSeqFeatData::GetSiteList()->IsSiteName( val.c_str(), styp)) { + sfdata.SetSite (styp); return true; - default: - break; } - break; - default: - break; - } - switch (qtype) { - case eQual_pseudo: - sfp->SetPseudo (true); - return true; - case eQual_partial: - sfp->SetPartial (true); - return true; - case eQual_exception: - sfp->SetExcept (true); - sfp->SetExcept_text (val); - return true; - case eQual_ribosomal_slippage: - sfp->SetExcept (true); - sfp->SetExcept_text (qual); + } + break; + case CSeqFeatData::e_Pub: + if( qtype == eQual_PubMed ) { + CRef new_pub( new CPub ); + new_pub->SetPmid( CPubMedId( x_StringToLongNoThrow(val, feat_name, qual) ) ); + sfdata.SetPub().SetPub().Set().push_back( new_pub ); return true; - case eQual_trans_splicing: - sfp->SetExcept (true); - sfp->SetExcept_text (qual); + } + break; + case CSeqFeatData::e_Prot: + switch( qtype ) { + case eQual_product: + sfdata.SetProt().SetName().push_back( val ); return true; - case eQual_evidence: - if (val == "experimental") { - sfp->SetExp_ev (CSeq_feat::eExp_ev_experimental); - } else if (val == "not_experimental" || val == "non_experimental" || - val == "not-experimental" || val == "non-experimental") { - sfp->SetExp_ev (CSeq_feat::eExp_ev_not_experimental); - } + case eQual_function: + sfdata.SetProt().SetActivity().push_back( val ); return true; - case eQual_note: - { - if (sfp->CanGetComment ()) { - const CSeq_feat::TComment& comment = sfp->GetComment (); - CSeq_feat::TComment revised = comment + "; " + val; - sfp->SetComment (revised); - } else { - sfp->SetComment (val); - } - return true; - } - case eQual_inference: - { - string prefix, remainder; - CInferencePrefixList::GetPrefixAndRemainder(val, prefix, remainder); - if (!NStr::IsBlank(prefix)) { - x_AddGBQualToFeature(sfp, qual, val); - } - else { - x_ProcessMsg( - ILineError::eProblem_QualifierBadValue, eDiag_Error, - feat_name, qual, val); - } - return true; - } - case eQual_replace: - { - string val_copy = val; - NStr::ToLower( val_copy ); - x_AddGBQualToFeature (sfp, qual, val_copy ); - return true; - } - case eQual_allele: - case eQual_bound_moiety: - case eQual_clone: - case eQual_compare: - case eQual_cons_splice: - case eQual_direction: case eQual_EC_number: - case eQual_estimated_length: - case eQual_experiment: - case eQual_frequency: - case eQual_function: - case eQual_gap_type: - case eQual_insertion_seq: - case eQual_label: - case eQual_linkage_evidence: - case eQual_map: - case eQual_ncRNA_class: - case eQual_number: - case eQual_old_locus_tag: - case eQual_operon: - case eQual_organism: - case eQual_PCR_conditions: - case eQual_phenotype: - case eQual_product: - case eQual_pseudogene: - case eQual_satellite: - case eQual_rpt_family: - case eQual_rpt_type: - case eQual_rpt_unit: - case eQual_rpt_unit_range: - case eQual_rpt_unit_seq: - case eQual_standard_name: - case eQual_tag_peptide: - case eQual_transcript_id: - case eQual_transposon: - case eQual_usedin: - case eQual_cyt_map: - case eQual_gen_map: - case eQual_rad_map: - case eQual_mobile_element_type: + sfdata.SetProt().SetEc().push_back( val ); + return true; + default: + break; + } + break; + default: + break; + } - { - x_AddGBQualToFeature (sfp, qual, val); - return true; + switch (qtype) { + case eQual_pseudo: + sfp->SetPseudo (true); + return true; + case eQual_partial: + sfp->SetPartial (true); + return true; + case eQual_exception: + sfp->SetExcept (true); + sfp->SetExcept_text (val); + return true; + case eQual_ribosomal_slippage: + sfp->SetExcept (true); + sfp->SetExcept_text (qual); + return true; + case eQual_trans_splicing: + sfp->SetExcept (true); + sfp->SetExcept_text (qual); + return true; + case eQual_evidence: + if (val == "experimental") { + sfp->SetExp_ev (CSeq_feat::eExp_ev_experimental); + } else if (val == "not_experimental" || val == "non_experimental" || + val == "not-experimental" || val == "non-experimental") { + sfp->SetExp_ev (CSeq_feat::eExp_ev_not_experimental); + } + return true; + case eQual_note: + return x_AddNoteToFeature(sfp, val); + case eQual_inference: + { + string prefix, remainder; + CInferencePrefixList::GetPrefixAndRemainder(val, prefix, remainder); + if (!NStr::IsBlank(prefix)) { + x_AddGBQualToFeature(sfp, qual, val); } - case eQual_gene: - { + else { + x_ProcessMsg( + ILineError::eProblem_QualifierBadValue, eDiag_Error, + feat_name, qual, val); + } + return true; + } + case eQual_replace: + { + string val_copy = val; + NStr::ToLower( val_copy ); + x_AddGBQualToFeature (sfp, qual, val_copy ); + return true; + } + case eQual_allele: + case eQual_bound_moiety: + case eQual_clone: + case eQual_compare: + case eQual_cons_splice: + case eQual_direction: + case eQual_EC_number: + case eQual_estimated_length: + case eQual_experiment: + case eQual_frequency: + case eQual_function: + case eQual_gap_type: + case eQual_insertion_seq: + case eQual_label: + case eQual_linkage_evidence: + case eQual_map: + case eQual_ncRNA_class: + case eQual_number: + case eQual_old_locus_tag: + case eQual_operon: + case eQual_organism: + case eQual_PCR_conditions: + case eQual_phenotype: + case eQual_product: + case eQual_pseudogene: + case eQual_satellite: + case eQual_rpt_family: + case eQual_rpt_type: + case eQual_rpt_unit: + case eQual_rpt_unit_range: + case eQual_rpt_unit_seq: + case eQual_standard_name: + case eQual_tag_peptide: + case eQual_transcript_id: + case eQual_transposon: + case eQual_usedin: + case eQual_cyt_map: + case eQual_gen_map: + case eQual_rad_map: + case eQual_mobile_element_type: + { + x_AddGBQualToFeature (sfp, qual, val); + return true; + } + case eQual_gene: + { + if (CSeqFeatData::CanHaveGene(sfdata.GetSubtype())) { CGene_ref& grp = sfp->SetGeneXref (); if (val == "-") { - grp.SetLocus (""); + grp.SetLocus (""); } else { grp.SetLocus (val); } return true; } - case eQual_gene_desc: - { + // else: + return x_AddNoteToFeature(sfp, feat_name, qual, val); + } + case eQual_gene_desc: + { + if (CSeqFeatData::CanHaveGene(sfdata.GetSubtype())) { CGene_ref& grp = sfp->SetGeneXref (); grp.SetDesc (val); return true; } - case eQual_gene_syn: - { + // else: + return x_AddNoteToFeature(sfp, feat_name, qual, val); + } + case eQual_gene_syn: + { + if (CSeqFeatData::CanHaveGene(sfdata.GetSubtype())) { CGene_ref& grp = sfp->SetGeneXref (); CGene_ref::TSyn& syn = grp.SetSyn (); syn.push_back (val); return true; } - case eQual_locus_tag: - { + // else: + return x_AddNoteToFeature(sfp, feat_name, qual, val); + } + case eQual_locus_tag: + { + if (CSeqFeatData::CanHaveGene(sfdata.GetSubtype())) { CGene_ref& grp = sfp->SetGeneXref (); grp.SetLocus_tag (val); return true; - } - case eQual_db_xref: - { - CTempString db, tag; - if (NStr::SplitInTwo (val, ":", db, tag)) { - CSeq_feat::TDbxref& dblist = sfp->SetDbxref (); - CRef dbt (new CDbtag); - dbt->SetDb (db); - CRef oid (new CObject_id); - static const char* digits = "0123456789"; - if (tag.find_first_not_of(digits) == string::npos) - oid->SetId(NStr::StringToLong(tag)); - else - oid->SetStr(tag); - dbt->SetTag (*oid); - dblist.push_back (dbt); - return true; - } - return true; - } - case eQual_nomenclature: - { - /* !!! need to implement !!! */ + } + // else: + return x_AddNoteToFeature(sfp, feat_name, qual, val); + } + case eQual_db_xref: + { + CTempString db, tag; + if (NStr::SplitInTwo (val, ":", db, tag)) { + CSeq_feat::TDbxref& dblist = sfp->SetDbxref (); + CRef dbt (new CDbtag); + dbt->SetDb (db); + CRef oid (new CObject_id); + static const char* digits = "0123456789"; + if (tag.find_first_not_of(digits) == string::npos) + oid->SetId(NStr::StringToLong(tag)); + else + oid->SetStr(tag); + dbt->SetTag (*oid); + dblist.push_back (dbt); return true; } - case eQual_go_component: - case eQual_go_function: - case eQual_go_process: - if (typ == CSeqFeatData::e_Gene || typ == CSeqFeatData::e_Cdregion || typ == CSeqFeatData::e_Rna) { - return x_AddGeneOntologyToFeature(sfp, qual, val); - } - return false; - case eQual_protein_id: - // see SQD-1535 and SQD-3496 - if (typ == CSeqFeatData::e_Cdregion || - (typ == CSeqFeatData::e_Rna && - sfdata.GetRna().GetType() == CRNA_ref::eType_mRNA)) - try { - CBioseq::TId ids; - CSeq_id::ParseIDs(ids, val, - CSeq_id::fParse_ValidLocal - | CSeq_id::fParse_PartialOK); - if ((flags & CFeature_table_reader::fLeaveProteinIds) || (ids.size()>1)) - { - x_AddGBQualToFeature (sfp, qual, val); // need to store all ids - } - CRef best = GetBestId(ids); - if (!best.Empty()) - sfp->SetProduct().SetWhole(*best); - return true; - } catch( CSeqIdException & ) { - return false; + return true; + } + case eQual_nomenclature: + { + /* !!! need to implement !!! */ + return true; + } + case eQual_go_component: + case eQual_go_function: + case eQual_go_process: + if (typ == CSeqFeatData::e_Gene || typ == CSeqFeatData::e_Cdregion || typ == CSeqFeatData::e_Rna) { + return x_AddGeneOntologyToFeature(sfp, qual, val); + } + return false; + case eQual_protein_id: + // see SQD-1535 and SQD-3496 + if (typ == CSeqFeatData::e_Cdregion || + (typ == CSeqFeatData::e_Rna && + sfdata.GetRna().GetType() == CRNA_ref::eType_mRNA)) + try { + CBioseq::TId ids; + CSeq_id::ParseIDs(ids, val, + CSeq_id::fParse_ValidLocal + | CSeq_id::fParse_PartialOK); + if (ids.size()>0) { + if (typ == CSeqFeatData::e_Cdregion) { + CRef best = GetBestId(ids); + if (!best.Empty()) + sfp->SetProduct().SetWhole(*best); + } + // else { + x_AddGBQualToFeature (sfp, qual, val); // Temporary hack for GB-7030 + // } // This logic should be moved into cleanup or objtools/edit } - case eQual_regulatory_class: - // This should've been handled up in x_AddQualifierToImp - // so it's always a bad value to be here - x_ProcessMsg( - ILineError::eProblem_QualifierBadValue, eDiag_Error, - feat_name, qual, val ); return true; - default: - break; - } + } catch( CSeqIdException & ) { + return false; + } + case eQual_regulatory_class: + // This should've been handled up in x_AddQualifierToImp + // so it's always a bad value to be here + x_ProcessMsg( + ILineError::eProblem_QualifierBadValue, eDiag_Error, + feat_name, qual, val ); + return true; + default: + break; } } return false; @@ -2469,6 +2653,7 @@ bool CFeature_table_reader_imp::x_AddIntervalToFeature( ) { + const Int4 orig_start = start; CSeq_interval::TStrand strand = eNa_strand_plus; if (start > stop) { @@ -2489,7 +2674,12 @@ bool CFeature_table_reader_imp::x_AddIntervalToFeature( else x_GetPointStrand(*sfp, strand); - CRef pPoint( new CSeq_point(*m_seq_id, start, strand) ); + // note usage of orig_start instead of start + // because we want the first part of the point + // specified in the file, not the smallest because SetRightOf + // works differently for plus vs. minus strand + CRef pPoint( + new CSeq_point(*m_seq_id, orig_start, strand) ); if( ispoint ) { // between two bases pPoint->SetRightOf (true); @@ -2646,6 +2836,9 @@ bool CFeature_table_reader_imp::x_SetupSeqFeat ( case CSeqFeatData::eSubtype_transit_peptide_aa: prot_ref.SetProcessed(CProt_ref::eProcessed_transit_peptide); break; + case CSeqFeatData::eSubtype_propeptide_aa: + prot_ref.SetProcessed(CProt_ref::eProcessed_propeptide); + break; } } @@ -2693,13 +2886,20 @@ bool CFeature_table_reader_imp::x_SetupSeqFeat ( void CFeature_table_reader_imp::x_ProcessMsg( ILineError::EProblem eProblem, EDiagSev eSeverity, - const std::string & strFeatureName, - const std::string & strQualifierName, - const std::string & strQualifierValue, + const string& strFeatureName, + const string& strQualifierName, + const string& strQualifierValue, + const string& strErrorMessage, const ILineError::TVecOfLines & vecOfOtherLines) { x_ProcessMsg(m_reader ? m_reader->GetLineNumber() : m_line_num, - eProblem, eSeverity, strFeatureName, strQualifierName, strQualifierValue, vecOfOtherLines); + eProblem, + eSeverity, + strFeatureName, + strQualifierName, + strQualifierValue, + strErrorMessage, + vecOfOtherLines); } @@ -2707,21 +2907,24 @@ void CFeature_table_reader_imp::x_ProcessMsg( int line_num, ILineError::EProblem eProblem, EDiagSev eSeverity, - const std::string & strFeatureName, - const std::string & strQualifierName, - const std::string & strQualifierValue, + const string & strFeatureName, + const string & strQualifierName, + const string & strQualifierValue, + const string& strErrorMessage, const ILineError::TVecOfLines & vecOfOtherLines ) { + + if (!m_pMessageListener) { + return; + } + AutoPtr pErr ( CObjReaderLineException::Create( - eSeverity, line_num, "", eProblem, m_real_seqid, strFeatureName, + eSeverity, line_num, strErrorMessage, eProblem, m_real_seqid, strFeatureName, strQualifierName, strQualifierValue)); ITERATE( ILineError::TVecOfLines, line_it, vecOfOtherLines ) { pErr->AddOtherLine(*line_it); } - if (m_pMessageListener == 0) { - pErr->Throw(); - } if (!m_pMessageListener->PutError(*pErr)) { pErr->Throw(); @@ -2729,6 +2932,20 @@ void CFeature_table_reader_imp::x_ProcessMsg( } +void CFeature_table_reader_imp::PutProgress( + const string& seq_id, + const unsigned int line_number, + ILineErrorListener* pListener) +{ + if (!pListener) { + return; + } + + string msg = "Seq-id " + seq_id + ", line " + NStr::IntToString(line_number); + pListener->PutProgress(msg); +} + + // helper for CFeature_table_reader_imp::ReadSequinFeatureTable, // just so we don't forget a step when we reset the feature // @@ -2773,26 +2990,29 @@ void CFeature_table_reader_imp::x_UpdatePointStrand(CSeq_feat& feat, CSeq_interv void CFeature_table_reader_imp::x_FinishFeature(CRef& feat) { - if (feat.Empty()) + if ( ! feat || feat.Empty()) return; if (feat->IsSetLocation()) { - // demote single interval seqlocmix to seqlocint + if (feat->GetLocation().IsMix()) { switch (feat->GetLocation().GetMix().Get().size()) { case 0: + // turn empty seqlocmix into a null seq-loc feat->SetLocation().SetNull(); break; case 1: { + // demote 1-part seqlocmixes to seq-loc with just that part CRef keep_loc = *feat->SetLocation().SetMix().Set().begin(); feat->SetLocation(*keep_loc); } break; default: + // mixes with 2 or more parts can be left alone break; } } @@ -2817,7 +3037,7 @@ CRef CFeature_table_reader_imp::ReadSequinFeatureTable ( ( (flags & CFeature_table_reader::fIgnoreWebComments) != 0 ); // if sequence ID is a list, use just one sequence ID string - x_InitId(seqid); + x_InitId(seqid, flags); // Use this to efficiently find the best CDS for a prot feature // (only add CDS's for it to work right) @@ -2860,7 +3080,7 @@ CRef CFeature_table_reader_imp::ReadSequinFeatureTable ( if( m_reader->GetLineNumber() % 10000 == 0 && m_reader->GetLineNumber() > 0 ) { - FTBL_PROGRESS(m_pMessageListener, m_real_seqid, m_reader->GetLineNumber()); + PutProgress(m_real_seqid, m_reader->GetLineNumber(), m_pMessageListener); } // skip empty lines. @@ -2969,14 +3189,14 @@ CRef CFeature_table_reader_imp::ReadSequinFeatureTable ( } } - } else if ((! qual.empty ()) && (! val.empty ())) { - + } else if ((!qual.empty())) { + + if (!val.empty()) { // process qual - val qualifier line // there should no more ranges for this feature // (although there still can be ranges for quals, of course) curr_feat_intervals_done = true; - if ( !sfp ) { if ((flags & CFeature_table_reader::fReportBadKey) != 0) { x_ProcessMsg( @@ -2999,7 +3219,7 @@ CRef CFeature_table_reader_imp::ReadSequinFeatureTable ( } } - } else if ((! qual.empty ()) && (val.empty ())) { + } else { // val.empty() // there should no more ranges for this feature // (although there still can be ranges for quals, of course) @@ -3007,19 +3227,20 @@ CRef CFeature_table_reader_imp::ReadSequinFeatureTable ( // check for the few qualifiers that do not need a value if ( !sfp ) { - if ((flags & CFeature_table_reader::fReportBadKey) != 0) { - x_ProcessMsg( - ILineError::eProblem_QualifierWithoutFeature, eDiag_Warning, - kEmptyStr, qual ); - } - } else { - TSingleSet::const_iterator s_iter = sc_SingleKeys.find (qual.c_str ()); - if (s_iter != sc_SingleKeys.end ()) { - - x_AddQualifierToFeature (sfp, curr_feat_name, qual, val, flags); + if ((flags & CFeature_table_reader::fReportBadKey) != 0) { + x_ProcessMsg( + ILineError::eProblem_QualifierWithoutFeature, eDiag_Warning, + kEmptyStr, qual ); + } + } else { + TSingleSet::const_iterator s_iter = sc_SingleKeys.find (qual.c_str ()); + if (s_iter != sc_SingleKeys.end ()) { + x_AddQualifierToFeature (sfp, curr_feat_name, qual, val, flags); + } } - } - } else if (! feat.empty ()) { + } + } + else if (!feat.empty()) { // unrecognized location @@ -3036,6 +3257,10 @@ CRef CFeature_table_reader_imp::ReadSequinFeatureTable ( } } + // make sure last feature is finished + x_FinishFeature(sfp); + x_ResetFeat( sfp, curr_feat_intervals_done ); + if ((flags & CFeature_table_reader::fCreateGenesFromCDSs) != 0 || (flags & CFeature_table_reader::fCDSsMustBeInTheirGenes) != 0 ) { @@ -3077,11 +3302,12 @@ CRef CFeature_table_reader_imp::CreateSeqFeat ( return sfp; } -void CFeature_table_reader_imp::x_InitId(const string& seq_id) +void CFeature_table_reader_imp::x_InitId(const string& seq_id, const CFeature_table_reader::TFlags flags) { if (!NStr::IsBlank(seq_id)) { CBioseq::TId ids; - CSeq_id::ParseIDs(ids, seq_id); + CSeq_id::ParseIDs(ids, seq_id, + (flags && CFeature_table_reader::fAllIdsAsLocal) ? CSeq_id::fParse_AnyLocal:CSeq_id::fParse_Default); m_real_seqid.clear(); ids.front()->GetLabel(&m_real_seqid, CSeq_id::eFasta); m_seq_id = ids.front(); @@ -3097,7 +3323,7 @@ void CFeature_table_reader_imp::AddFeatQual ( const string &seq_id1 ) { - x_InitId(seq_id1); + x_InitId(seq_id1, flags); if ((! qual.empty ()) && (! val.empty ())) { @@ -3164,8 +3390,7 @@ bool CFeature_table_reader_imp::ParseInitialFeatureLine ( NStr::TruncateSpacesInPlace(line, NStr::eTrunc_Begin); string seqid; string annotname; - NStr::SplitInTwo(line, " ", seqid, annotname, - NStr::fSplit_MergeDelims ); + NStr::SplitInTwo(line, " ", seqid, annotname, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); // swap is faster than assignment out_seqid.swap(seqid); @@ -3257,7 +3482,7 @@ CRef CFeature_table_reader::ReadSequinFeatureTable ( CTempString line = *++reader; if( ParseInitialFeatureLine(line, seqid, annotname) ) { - FTBL_PROGRESS(pMessageListener, seqid, reader.GetLineNumber()); + CFeature_table_reader_imp::PutProgress(seqid, reader.GetLineNumber(), pMessageListener); } } diff --git a/c++/src/objtools/readers/rm_reader.cpp b/c++/src/objtools/readers/rm_reader.cpp index 6537374f..68c4d5b0 100644 --- a/c++/src/objtools/readers/rm_reader.cpp +++ b/c++/src/objtools/readers/rm_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: rm_reader.cpp 472138 2015-07-07 16:07:55Z grichenk $ +/* $Id: rm_reader.cpp 515707 2016-10-05 12:32:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -890,7 +890,7 @@ bool CRepeatMaskerReader::ParseRecord(const string& record, SRepeatRegion& mask_ string line = NStr::TruncateSpaces( record ); list< string > values; - if ( NStr::Split( line, " \t", values ).size() < MIN_VALUE_COUNT ) { + if ( NStr::Split( line, " \t", values, NStr::fSplit_Tokenize ).size() < MIN_VALUE_COUNT ) { return false; } diff --git a/c++/src/objtools/readers/source_mod_parser.cpp b/c++/src/objtools/readers/source_mod_parser.cpp index 90e2d55d..7eef18d7 100644 --- a/c++/src/objtools/readers/source_mod_parser.cpp +++ b/c++/src/objtools/readers/source_mod_parser.cpp @@ -1,4 +1,4 @@ -/* $Id: source_mod_parser.cpp 520374 2016-11-28 13:29:07Z ivanov $ +/* $Id: source_mod_parser.cpp 542051 2017-07-25 16:55:29Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -70,6 +70,214 @@ BEGIN_NCBI_SCOPE BEGIN_SCOPE(objects) +namespace +{ + class equal_subtype + { + public: + equal_subtype(CSubSource::TSubtype st) : m_st(st){}; + bool operator()(const CRef& st) const + { + return st->IsSetSubtype() && (st->GetSubtype() == m_st); + } + private: + CSubSource::TSubtype m_st; + }; + +#ifdef STATIC_SMOD +# error "STATIC_SMOD already defined" +#endif + +// The macro makes sure that the var's name matches its key. +// Due to kKeyCanonicalizationTable, it's okay to use '_' for '-' +// because it will match both. +#define STATIC_SMOD(key_str) \ + CSafeStatic s_Mod_##key_str([]() { \ + return new CSourceModParser::SMod(#key_str); }, nullptr); + + // For CBioseq + STATIC_SMOD(topology); + STATIC_SMOD(top); + STATIC_SMOD(molecule); + STATIC_SMOD(mol); + STATIC_SMOD(moltype); + STATIC_SMOD(mol_type); + STATIC_SMOD(strand); + STATIC_SMOD(comment); + + // For CBioSource + STATIC_SMOD(organism); + STATIC_SMOD(org); + STATIC_SMOD(taxname); + STATIC_SMOD(taxid); + STATIC_SMOD(location); + STATIC_SMOD(origin); + STATIC_SMOD(sub_clone); + STATIC_SMOD(lat_long); + STATIC_SMOD(latitude_longitude); + STATIC_SMOD(fwd_primer_seq); + STATIC_SMOD(rev_primer_seq); + STATIC_SMOD(fwd_primer_name); + STATIC_SMOD(rev_primer_name); + STATIC_SMOD(dbxref); + STATIC_SMOD(db_xref); + STATIC_SMOD(division); + STATIC_SMOD(div); + STATIC_SMOD(lineage); + STATIC_SMOD(gcode); + STATIC_SMOD(mgcode); + STATIC_SMOD(pgcode); + STATIC_SMOD(note); + STATIC_SMOD(notes); + STATIC_SMOD(focus); + + // For CMolInfo + STATIC_SMOD(tech); + STATIC_SMOD(completeness); + STATIC_SMOD(completedness); + + // For CGene_ref + STATIC_SMOD(gene); + STATIC_SMOD(allele); + STATIC_SMOD(gene_syn); + STATIC_SMOD(gene_synonym); + STATIC_SMOD(locus_tag); + + // For CProt_ref + STATIC_SMOD(protein); + STATIC_SMOD(prot); + STATIC_SMOD(prot_desc); + STATIC_SMOD(protein_desc); + STATIC_SMOD(EC_number); + STATIC_SMOD(activity); + STATIC_SMOD(function); + + // For CGB_block + STATIC_SMOD(secondary_accession); + STATIC_SMOD(secondary_accessions); + STATIC_SMOD(keyword); + STATIC_SMOD(keywords); + + // For TPA Mods (CUser_object) + STATIC_SMOD(primary); + STATIC_SMOD(primary_accessions); + + // For Genome Project DB Mods (CUser_object) + STATIC_SMOD(project); + STATIC_SMOD(projects); + + // For Pub Mods (CSeq_descr) + STATIC_SMOD(PubMed); + STATIC_SMOD(PMID); + + +#undef STATIC_SMOD + + typedef set TSModNameSet; + + // Loads up a map of SMod to subtype + template, + typename TEnumNameToValMap = map> + TSModEnumMap * s_InitSmodToEnumMap( + const CEnumeratedTypeValues* etv, + // names to skip + const TSModNameSet & skip_enum_names, + // extra values to add that aren't in the enum + const TEnumNameToValMap & extra_enum_names_to_vals ) + { + unique_ptr smod_enum_map(new TSModEnumMap); + + ITERATE (CEnumeratedTypeValues::TValues, it, etv->GetValues()) { + const string & enum_name = it->first; + const TEnum enum_val = static_cast(it->second); + if( skip_enum_names.find(enum_name.c_str()) != + skip_enum_names.end() ) + { + // skip this tag + continue; + } + auto emplace_result = + smod_enum_map->emplace( + CSourceModParser::SMod(enum_name), enum_val); + // emplace must succeed + if( ! emplace_result.second) { + NCBI_USER_THROW_FMT( + "s_InitSmodToEnumMap " << enum_name); + } + } + + for(auto extra_smod_to_enum : extra_enum_names_to_vals) { + auto emplace_result = + smod_enum_map->emplace( + CSourceModParser::SMod(extra_smod_to_enum.first), + extra_smod_to_enum.second); + // emplace must succeed + if( ! emplace_result.second) { + NCBI_USER_THROW_FMT( + "s_InitSmodToEnumMap " << extra_smod_to_enum.first); + } + } + + return smod_enum_map.release(); + } + + typedef map TSModOrgSubtypeMap; + + TSModOrgSubtypeMap * s_InitSModOrgSubtypeMap(void) + { + const TSModNameSet kDeprecatedOrgSubtypes{ + "dosage", "old-lineage", "old-name"}; + const map extra_smod_to_enum_names { + { "subspecies", COrgMod::eSubtype_sub_species }, + { "host", COrgMod::eSubtype_nat_host }, + { "specific-host", COrgMod::eSubtype_nat_host }, + }; + + return s_InitSmodToEnumMap( + COrgMod::GetTypeInfo_enum_ESubtype(), + kDeprecatedOrgSubtypes, + extra_smod_to_enum_names + ); + } + + // The subtype SMods are loaded from the names of the enum + // and they map to ESubtype enum values so we can't just use STATIC_SMOD + CSafeStatic kSModOrgSubtypeMap(s_InitSModOrgSubtypeMap, + nullptr); + + typedef map TSModSubSrcSubtype; + + TSModSubSrcSubtype * s_InitSModSubSrcSubtypeMap(void) + { + // some are skipped because they're handled specially and some are + // skipped because they're deprecated + TSModNameSet skip_enum_names { + // skip because handled specially elsewhere + "fwd_primer_seq", "rev_primer_seq", + "fwd_primer_name", "rev_primer_name", + // skip because deprecated + "transposon_name", + "plastid_name", + "insertion_seq_name", + }; + const map extra_smod_to_enum_names { + { "sub-clone", CSubSource::eSubtype_subclone }, + { "lat-long", CSubSource::eSubtype_lat_lon }, + { "latitude-longitude", CSubSource::eSubtype_lat_lon }, + }; + return s_InitSmodToEnumMap( + CSubSource::GetTypeInfo_enum_ESubtype(), + skip_enum_names, + extra_smod_to_enum_names ); + } + + CSafeStatic kSModSubSrcSubtypeMap( + s_InitSModSubSrcSubtypeMap, nullptr); +}; + +CSafeStatic CSourceModParser::kEmptyMod; // ASCII letters to lowercase, space and underscore to hyphen. const unsigned char CSourceModParser::kKeyCanonicalizationTable[257] = @@ -232,7 +440,7 @@ string CSourceModParser::ParseTitle(const CTempString& title, } mod.pos = lb_pos; mod.used = false; - m_Mods.insert(mod); + m_Mods.emplace(mod); CTempString text = NStr::TruncateSpaces_Unsafe (title.substr(pos, lb_pos - pos)); if ( !stripped_title.empty() && !text.empty() ) { @@ -370,12 +578,7 @@ void CSourceModParser::ApplyAllMods(CBioseq& seq, CTempString organism, CConstRe }} {{ - CSeq_descr pubs; - ApplyPubMods(pubs); - if ( !pubs.Get().empty() ) { - CSeq_descr::Tdata& sds = seq.SetDescr().Set(); - sds.splice(sds.end(), pubs.Set()); - } + ApplyPubMods(seq); }} }; @@ -427,7 +630,7 @@ void CSourceModParser::ApplyMods(CBioseq& seq) const SMod* mod = NULL; // top[ology] - if ((mod = FindMod("topology", "top")) != NULL) { + if ((mod = FindMod(s_Mod_topology.Get(), s_Mod_top.Get())) != NULL) { if (NStr::EqualNocase(mod->value, "linear")) { seq.SetInst().SetTopology(CSeq_inst::eTopology_linear); } else if (NStr::EqualNocase(mod->value, "circular")) { @@ -444,7 +647,7 @@ void CSourceModParser::ApplyMods(CBioseq& seq) bool bMolSetViaMolMod = false; // mol[ecule] - if ((mod = FindMod("molecule", "mol")) != NULL) { + if ((mod = FindMod(s_Mod_molecule.Get(), s_Mod_mol.Get())) != NULL) { if (NStr::EqualNocase(mod->value, "dna")) { seq.SetInst().SetMol( CSeq_inst::eMol_dna ); bMolSetViaMolMod = true; @@ -460,7 +663,7 @@ void CSourceModParser::ApplyMods(CBioseq& seq) // mol[-]type if( ! bMolSetViaMolMod ) { - if ((mod = FindMod("moltype", "mol-type")) != NULL) { + if ((mod = FindMod(s_Mod_moltype.Get(), s_Mod_mol_type.Get())) != NULL) { TBiomolMap::const_iterator it = sc_BiomolMap.find(mod->value.c_str()); if (it == sc_BiomolMap.end()) { x_HandleBadModValue(*mod); @@ -473,7 +676,7 @@ void CSourceModParser::ApplyMods(CBioseq& seq) } // strand - if ((mod = FindMod("strand")) != NULL) { + if ((mod = FindMod(s_Mod_strand.Get())) != NULL) { if (NStr::EqualNocase(mod->value, "single")) { seq.SetInst().SetStrand( CSeq_inst::eStrand_ss ); } else if (NStr::EqualNocase(mod->value, "double")) { @@ -486,7 +689,7 @@ void CSourceModParser::ApplyMods(CBioseq& seq) } // comment - if ((mod = FindMod("comment")) != NULL) { + if ((mod = FindMod(s_Mod_comment.Get())) != NULL) { CRef desc(new CSeqdesc); desc->SetComment( mod->value ); seq.SetDescr().Set().push_back(desc); @@ -502,11 +705,11 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& bsrc, // org[anism] if (organism.empty()) { - if ((mod = FindMod("organism", "org")) != NULL) { + if ((mod = FindMod(s_Mod_organism.Get(), s_Mod_org.Get())) != NULL) { organism = mod->value; } else - if ((mod = FindMod("taxname")) != NULL) { + if ((mod = FindMod(s_Mod_taxname.Get())) != NULL) { organism = mod->value; } } @@ -526,7 +729,7 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& bsrc, } // location - if ((mod = FindMod("location")) != NULL) { + if ((mod = FindMod(s_Mod_location.Get())) != NULL) { if (NStr::EqualNocase(mod->value, "mitochondrial")) { bsrc->SetGenome(CBioSource::eGenome_mitochondrion); } else if (NStr::EqualNocase(mod->value, "provirus")) { @@ -546,7 +749,7 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& bsrc, } // origin - if ((mod = FindMod("origin")) != NULL) { + if ((mod = FindMod(s_Mod_origin.Get())) != NULL) { try { // also check for special cases that don't match the enum name if( NStr::EqualNocase(mod->value, "natural mutant") ) { @@ -562,90 +765,49 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& bsrc, } } - struct SSubtypeAlias { - const char *name; - int value; - }; - // handle orgmods - {{ - // create lookup set for finding discouraged tags - static const char * kDeprecatedSubtypes_arr[] = { - "dosage", "old-lineage", "old-name" - }; - const int kDeprecatedSubtypes_arr_len = sizeof(kDeprecatedSubtypes_arr) / sizeof(kDeprecatedSubtypes_arr[0]); - const set kDeprecatedSubtypes( - kDeprecatedSubtypes_arr, kDeprecatedSubtypes_arr + kDeprecatedSubtypes_arr_len); - - const CEnumeratedTypeValues* etv = COrgMod::GetTypeInfo_enum_ESubtype(); - ITERATE (CEnumeratedTypeValues::TValues, it, etv->GetValues()) { - if( kDeprecatedSubtypes.find(it->first.c_str()) != kDeprecatedSubtypes.end() ) { - // skip this bad tag - } else if ((mod = FindMod(it->first)) != NULL) { - CRef org_mod(new COrgMod); - org_mod->SetSubtype(it->second); - org_mod->SetSubname(mod->value); - bsrc->SetOrg().SetOrgname().SetMod().push_back(org_mod); - reset_taxid = true; - } + for(const auto & smod_orgsubtype : kSModOrgSubtypeMap.Get()) { + const SMod & smod = smod_orgsubtype.first; + const COrgMod::ESubtype e_subtype = smod_orgsubtype.second; + if ((mod = FindMod(smod)) != NULL) { + CRef org_mod(new COrgMod); + org_mod->SetSubtype(e_subtype); + org_mod->SetSubname(mod->value); + bsrc->SetOrg().SetOrgname().SetMod().push_back(org_mod); + reset_taxid = true; } - }} + } - // handle orgmod aliases - {{ - static const SSubtypeAlias kOrgmodAliases[] = { - { "subspecies", COrgMod::eSubtype_sub_species }, - { "host", COrgMod::eSubtype_nat_host }, - { "specific-host", COrgMod::eSubtype_nat_host }, - { NULL, 0 } - }; - for (const SSubtypeAlias* it = &kOrgmodAliases[0]; - it->name != NULL; ++it) { - if ((mod = FindMod(it->name)) != NULL) { - CRef org_mod(new COrgMod); - org_mod->SetSubtype(it->value); - org_mod->SetSubname(mod->value); - bsrc->SetOrg().SetOrgname().SetMod().push_back(org_mod); - reset_taxid = true; + // handle subsources + for( const auto & smod_subsrcsubtype : kSModSubSrcSubtypeMap.Get() ) { + const SMod & smod = smod_subsrcsubtype.first; + const CSubSource::ESubtype e_subtype = smod_subsrcsubtype.second; + if ((mod = FindMod(smod)) != NULL) { + auto& subtype = bsrc->SetSubtype(); + CRef subsource(new CSubSource); + subsource->SetSubtype(e_subtype); + + if( CSubSource::NeedsNoText(e_subtype) ) { + subsource->SetName(kEmptyStr); + } else { + subsource->SetName(mod->value); } - } - }} - // handle subsources - {{ - const CEnumeratedTypeValues* etv - = CSubSource::GetTypeInfo_enum_ESubtype(); - ITERATE (CEnumeratedTypeValues::TValues, it, etv->GetValues()) { - // certain tags have to be handled differently - switch( it->second ) { - case CSubSource::eSubtype_fwd_primer_seq: - case CSubSource::eSubtype_rev_primer_seq: - case CSubSource::eSubtype_fwd_primer_name: - case CSubSource::eSubtype_rev_primer_name: - // skip; we'll handle these below - break; - case CSubSource::eSubtype_transposon_name: - case CSubSource::eSubtype_plastid_name: - case CSubSource::eSubtype_insertion_seq_name: - // skip these deprecated tags - break; - default: - if ((mod = FindMod(it->first)) != NULL) { - CRef subsource(new CSubSource); - subsource->SetSubtype(it->second); - - if( CSubSource::NeedsNoText(it->second) ) { - subsource->SetName(kEmptyStr); - } else { - subsource->SetName(mod->value); - } - - bsrc->SetSubtype().push_back(subsource); - } - break; + if (!CSubSource::IsMultipleValuesAllowed(e_subtype)) + { + // since only one of this e_subtype is allowed, we erase any + // that are already in the subtype list. + // (Unfortunately, we cannot just use bsrc->RemoveSubSource + // because it will ResetSubtype if subtype ends up empty) + subtype.erase( + remove_if(subtype.begin(), subtype.end(), + equal_subtype(e_subtype)), + subtype.end()); } + + subtype.push_back(subsource); } - }} + } // handle PCR Primers {{ @@ -657,57 +819,41 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& bsrc, bool used_fwd = false; bool used_rev = false; - if ((mod = FindMod("fwd-primer-name")) != NULL) { + if ((mod = FindMod(s_Mod_fwd_primer_name.Get())) != NULL) { fwd_primer->SetName().Set( mod->value ); used_fwd = true; } - if ((mod = FindMod("fwd-primer-seq")) != NULL) { + if ((mod = FindMod(s_Mod_fwd_primer_seq.Get())) != NULL) { fwd_primer->SetSeq().Set( mod->value ); NStr::ToLower( fwd_primer->SetSeq().Set() ); used_fwd = true; } - if ((mod = FindMod("rev-primer-name")) != NULL) { + if ((mod = FindMod(s_Mod_rev_primer_name.Get())) != NULL) { rev_primer->SetName().Set( mod->value ); used_rev = true; } - if ((mod = FindMod("rev-primer-seq")) != NULL) { + if ((mod = FindMod(s_Mod_rev_primer_seq.Get())) != NULL) { rev_primer->SetSeq().Set( mod->value ); NStr::ToLower( rev_primer->SetSeq().Set() ); used_rev = true; } if( used_fwd ) { - pcr_reaction->SetForward().Set().push_back( CRef(&*fwd_primer) ); + pcr_reaction->SetForward().Set().push_back( + CRef(&*fwd_primer) ); } if( used_rev ) { - pcr_reaction->SetReverse().Set().push_back( CRef(&*rev_primer) ); + pcr_reaction->SetReverse().Set().push_back( + CRef(&*rev_primer) ); } if( used_fwd || used_rev ) { - bsrc->SetPcr_primers().Set().push_back( CRef(&*pcr_reaction) ); - } - }} - - // handle subsource aliases - {{ - static const SSubtypeAlias kSubsourceAliases[] = { - { "sub-clone", CSubSource::eSubtype_subclone }, - { "lat-long", CSubSource::eSubtype_lat_lon }, - { "latitude-longitude", CSubSource::eSubtype_lat_lon }, - { NULL, 0 } - }; - for (const SSubtypeAlias* it = &kSubsourceAliases[0]; - it->name != NULL; ++it) { - if ((mod = FindMod(it->name)) != NULL) { - CRef subsource(new CSubSource); - subsource->SetSubtype(it->value); - subsource->SetName(mod->value); - bsrc->SetSubtype().push_back(subsource); - } + bsrc->SetPcr_primers().Set().push_back( + CRef(&*pcr_reaction) ); } }} // db_xref - TModsRange db_xref_mods_range = FindAllMods( "db_xref" ); + TModsRange db_xref_mods_range = FindAllMods( s_Mod_db_xref.Get(), s_Mod_dbxref.Get() ); for( TModsCI db_xref_iter = db_xref_mods_range.first; db_xref_iter != db_xref_mods_range.second; ++db_xref_iter ) { @@ -733,34 +879,34 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& bsrc, } // div[ision] - if ((mod = FindMod("division", "div")) != NULL) { + if ((mod = FindMod(s_Mod_division.Get(), s_Mod_div.Get())) != NULL) { bsrc->SetOrg().SetOrgname().SetDiv( mod->value ); } // lineage - if ((mod = FindMod("lineage")) != NULL) { + if ((mod = FindMod(s_Mod_lineage.Get())) != NULL) { bsrc->SetOrg().SetOrgname().SetLineage( mod->value ); } // gcode - if ((mod = FindMod("gcode")) != NULL) { + if ((mod = FindMod(s_Mod_gcode.Get())) != NULL) { bsrc->SetOrg().SetOrgname().SetGcode( NStr::StringToInt(mod->value, NStr::fConvErr_NoThrow) ); } // mgcode - if ((mod = FindMod("mgcode")) != NULL) { + if ((mod = FindMod(s_Mod_mgcode.Get())) != NULL) { bsrc->SetOrg().SetOrgname().SetMgcode( NStr::StringToInt(mod->value, NStr::fConvErr_NoThrow) ); } // pgcode - if ((mod = FindMod("pgcode")) != NULL) { + if ((mod = FindMod(s_Mod_pgcode.Get())) != NULL) { bsrc->SetOrg().SetOrgname().SetPgcode( NStr::StringToInt(mod->value, NStr::fConvErr_NoThrow) ); } // note[s] TModsRange mods[2]; - mods[0] = FindAllMods("note"); - mods[1] = FindAllMods("notes"); + mods[0] = FindAllMods(s_Mod_note.Get()); + mods[1] = FindAllMods(s_Mod_notes.Get()); for (size_t i = 0; i < 2; i++) { for (TModsCI it = mods[i].first; it != mods[i].second; it++) @@ -773,14 +919,20 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& bsrc, } // focus - if ((mod = FindMod("focus")) != NULL) { + if ((mod = FindMod(s_Mod_focus.Get())) != NULL) { if( NStr::EqualNocase( mod->value, "TRUE" ) ) { bsrc->SetIs_focus(); } } - if (reset_taxid && bsrc->IsSetOrgname() && bsrc->GetOrg().GetTaxId() != 0) + + if ((mod = FindMod(s_Mod_taxid.Get())) != NULL) { + bsrc->SetOrg().SetTaxId( NStr::StringToInt(mod->value, NStr::fConvErr_NoThrow) ); + } + else + if (reset_taxid && bsrc->IsSetOrgname() && bsrc->GetOrg().GetTaxId() != 0) { bsrc->SetOrg().SetTaxId(0); + } } typedef SStaticPair TTechMapEntry; @@ -834,7 +986,7 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& mi) const SMod* mod = NULL; // mol[-]type - if ((mod = FindMod("moltype", "mol-type")) != NULL) { + if ((mod = FindMod(s_Mod_moltype.Get(), s_Mod_mol_type.Get())) != NULL) { TBiomolMap::const_iterator it = sc_BiomolMap.find(mod->value.c_str()); if (it == sc_BiomolMap.end()) { // construct the possible bad values by hand @@ -846,7 +998,7 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& mi) } // tech - if ((mod = FindMod("tech")) != NULL) { + if ((mod = FindMod(s_Mod_tech.Get())) != NULL) { TTechMap::const_iterator it = sc_TechMap.find(mod->value.c_str()); if (it == sc_TechMap.end()) { x_HandleBadModValue(*mod); @@ -856,7 +1008,7 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& mi) } // complete[d]ness - if ((mod = FindMod("completeness", "completedness")) != NULL) { + if ((mod = FindMod(s_Mod_completeness.Get(), s_Mod_completedness.Get())) != NULL) { TTechMap::const_iterator it = sc_CompletenessMap.find(mod->value.c_str()); if (it == sc_CompletenessMap.end()) { x_HandleBadModValue(*mod); @@ -871,22 +1023,22 @@ void CSourceModParser::x_ApplyMods(CAutoInitRef& gene) const SMod* mod = NULL; // gene - if ((mod = FindMod("gene")) != NULL) { + if ((mod = FindMod(s_Mod_gene.Get())) != NULL) { gene->SetLocus(mod->value); } // allele - if ((mod = FindMod("allele")) != NULL) { + if ((mod = FindMod(s_Mod_allele.Get())) != NULL) { gene->SetAllele( mod->value ); } // gene_syn[onym] - if ((mod = FindMod("gene_syn", "gene_synonym")) != NULL) { + if ((mod = FindMod(s_Mod_gene_syn.Get(), s_Mod_gene_synonym.Get())) != NULL) { gene->SetSyn().push_back( mod->value ); } // locus_tag - if ((mod = FindMod("locus_tag")) != NULL) { + if ((mod = FindMod(s_Mod_locus_tag.Get())) != NULL) { gene->SetLocus_tag( mod->value ); } } @@ -897,22 +1049,22 @@ void CSourceModParser::x_ApplyMods(CAutoInitRef& prot) const SMod* mod = NULL; // prot[ein] - if ((mod = FindMod("protein", "prot")) != NULL) { + if ((mod = FindMod(s_Mod_protein.Get(), s_Mod_prot.Get())) != NULL) { prot->SetName().push_back(mod->value); } // prot[ein]_desc - if ((mod = FindMod("prot_desc", "protein_desc")) != NULL) { + if ((mod = FindMod(s_Mod_prot_desc.Get(), s_Mod_protein_desc.Get())) != NULL) { prot->SetDesc( mod->value ); } // EC_number - if ((mod = FindMod("EC_number")) != NULL) { + if ((mod = FindMod(s_Mod_EC_number.Get())) != NULL) { prot->SetEc().push_back( mod->value ); } // activity/function - if ((mod = FindMod("activity", "function")) != NULL) { + if ((mod = FindMod(s_Mod_activity.Get(), s_Mod_function.Get())) != NULL) { prot->SetActivity().push_back( mod->value ); } } @@ -923,7 +1075,8 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& gbb) const SMod* mod = NULL; // secondary-accession[s] - if ((mod = FindMod("secondary-accession", "secondary-accessions")) != NULL) + if ((mod = FindMod(s_Mod_secondary_accession.Get(), + s_Mod_secondary_accessions.Get())) != NULL) { list ranges; NStr::Split(mod->value, ",", ranges, NStr::fSplit_MergeDelimiters); @@ -941,7 +1094,7 @@ void CSourceModParser::x_ApplyMods(CAutoInitDesc& gbb) } // keyword[s] - if ((mod = FindMod("keyword", "keywords")) != NULL) { + if ((mod = FindMod(s_Mod_keyword.Get(), s_Mod_keywords.Get())) != NULL) { list keywordList; NStr::Split(mod->value, ",;", keywordList, NStr::fSplit_MergeDelimiters); // trim every string and push it into the real keyword list @@ -958,7 +1111,8 @@ void CSourceModParser::x_ApplyMods(CAutoInitRef& hist) const SMod* mod = NULL; // secondary-accession[s] - if ((mod = FindMod("secondary-accession", "secondary-accessions")) != NULL) + if ((mod = FindMod(s_Mod_secondary_accession.Get(), + s_Mod_secondary_accessions.Get())) != NULL) { list ranges; NStr::Split(mod->value, ",", ranges, NStr::fSplit_MergeDelimiters); @@ -1036,7 +1190,7 @@ void CSourceModParser::x_ApplyTPAMods(CAutoInitRef& tpa) const SMod* mod = NULL; // primary[-accessions] - if ((mod = FindMod("primary", "primary-accessions")) != NULL) { + if ((mod = FindMod(s_Mod_primary.Get(), s_Mod_primary_accessions.Get())) != NULL) { CUser_object::TData data; list accns; NStr::Split(mod->value, ",", accns, NStr::fSplit_MergeDelimiters); @@ -1062,7 +1216,7 @@ CSourceModParser::x_ApplyGenomeProjectsDBMods(CAutoInitRef& gpdb) const SMod* mod = NULL; // project[s] - if ((mod = FindMod("project", "projects")) != NULL) { + if ((mod = FindMod(s_Mod_project.Get(), s_Mod_projects.Get())) != NULL) { CUser_object::TData data; list ids; NStr::Split(mod->value, ",;", ids, NStr::fSplit_MergeDelimiters); @@ -1091,25 +1245,25 @@ CSourceModParser::x_ApplyGenomeProjectsDBMods(CAutoInitRef& gpdb) static -void s_ApplyPubMods(CSeq_descr& sd, CSourceModParser::TModsRange range) +void s_ApplyPubMods(CBioseq& bioseq, const CSourceModParser::TModsRange& range) { for (CSourceModParser::TModsCI it = range.first; it != range.second; ++it) { - int pmid = NStr::StringToInt(it->value, NStr::fConvErr_NoThrow); - CRef desc(new CSeqdesc); + TIntId pmid = NStr::StringToNumeric(it->value, NStr::fConvErr_NoThrow); CRef pub(new CPub); pub->SetPmid().Set(pmid); - desc->SetPub().SetPub().Set().push_back(pub); - sd.Set().push_back(desc); + CRef pubdesc(new CSeqdesc); + pubdesc->SetPub().SetPub().Set().push_back(pub); + bioseq.SetDescr().Set().push_back(pubdesc); } } -void CSourceModParser::ApplyPubMods(CSeq_descr& sd) +void CSourceModParser::ApplyPubMods(CBioseq& seq) { // find PubMed IDs - s_ApplyPubMods(sd, FindAllMods("PubMed")); - s_ApplyPubMods(sd, FindAllMods("PMID")); + s_ApplyPubMods(seq, FindAllMods(s_Mod_PubMed.Get())); + s_ApplyPubMods(seq, FindAllMods(s_Mod_PMID.Get())); } CSourceModParser::CBadModError::CBadModError( @@ -1136,6 +1290,8 @@ string CSourceModParser::CBadModError::x_CalculateErrorString( CSourceModParser::TMods CSourceModParser::GetMods(TWhichMods which) const { if (which == fAllMods) { + // if caller gave this they probably should prefer calling GetAllMods + // to avoid the struct copy. return m_Mods; } else { TMods ret; @@ -1150,28 +1306,30 @@ CSourceModParser::TMods CSourceModParser::GetMods(TWhichMods which) const } } - -const CSourceModParser::SMod* CSourceModParser::FindMod(const CTempString& key, - CTempString alt_key ) +const CSourceModParser::SMod* CSourceModParser::FindMod( + const SMod & smod, const SMod & alt_smod) { // check against m_pModFilter, if any if( m_pModFilter ) { - if( ! (*m_pModFilter)(key) || ! (*m_pModFilter)(alt_key) ) { + if( ! (*m_pModFilter)(smod.key) || ! (*m_pModFilter)(alt_smod.key) ) { return NULL; } } - SMod mod; - for (int tries = 0; tries < 2; ++tries) { - mod.key = ( tries == 0 ? key : alt_key ); - mod.pos = 0; - if ( !mod.key.empty() ) { - TModsCI it = m_Mods.lower_bound(mod); - if (it != m_Mods.end() && CompareKeys(it->key, mod.key) == 0) { - const_cast(*it).used = true; - return &*it; - } + const SMod & mod = ( tries == 0 ? smod : alt_smod ); + if( mod.key.empty() ) { + continue; + } + + TModsCI it = m_Mods.lower_bound(mod); + if (it != m_Mods.end() && EqualKeys(it->key, mod.key)) { + // set iterators are const since changing an object could affect + // its order in the set. However, in this case we know that + // changing the `used` field won't affect the order so we know + // that a const_cast to change it is safe to do. + const_cast(*it).used = true; + return &*it; } } @@ -1182,15 +1340,26 @@ const CSourceModParser::SMod* CSourceModParser::FindMod(const CTempString& key, CSourceModParser::TModsRange CSourceModParser::FindAllMods(const CTempString& key) { - SMod mod; - mod.key = key; - mod.pos = 0; + SMod smod(key); + return FindAllMods(smod); +} +CSourceModParser::TModsRange +CSourceModParser::FindAllMods(const SMod & smod, const SMod & alt_smod) +{ TModsRange r; - r.first = m_Mods.lower_bound(mod); + r.first = m_Mods.lower_bound(smod); + if (r.first == m_Mods.end() || !EqualKeys(r.first->key, smod.key)) { + r.first = m_Mods.lower_bound(alt_smod); + } for (r.second = r.first; - r.second != m_Mods.end() && CompareKeys(r.second->key, key) == 0; - ++r.second) { + r.second != m_Mods.end() && (EqualKeys(r.second->key, smod.key) || EqualKeys(r.second->key, alt_smod.key)); + ++r.second) + { + // set iterators are const since changing an object could affect + // its order in the set. However, in this case we know that + // changing the `used` field won't affect the order so we know + // that a const_cast to change it is safe to do. const_cast(*r.second).used = true; } return r; @@ -1362,14 +1531,17 @@ void CSourceModParser::SetAllUnused() { NON_CONST_ITERATE(TMods, it, m_Mods) { + // set iterators are const since changing an object could affect + // its order in the set. However, in this case we know that + // changing the `used` field won't affect the order so we know + // that a const_cast to change it is safe to do. const_cast(*it).used = false; } } void CSourceModParser::AddMods(const CTempString& name, const CTempString& value) { - SMod newmod; - newmod.key = name; + SMod newmod(name); newmod.value = value; newmod.used = false; diff --git a/c++/src/objtools/readers/struct_cmt_reader.cpp b/c++/src/objtools/readers/struct_cmt_reader.cpp index 86e37944..6137fce6 100644 --- a/c++/src/objtools/readers/struct_cmt_reader.cpp +++ b/c++/src/objtools/readers/struct_cmt_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: struct_cmt_reader.cpp 515962 2016-10-06 18:16:16Z ivanov $ +/* $Id: struct_cmt_reader.cpp 528801 2017-02-27 12:16:41Z gotvyans $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -33,15 +33,17 @@ #include -#include - #include #include +#include + #include #include -#include +#include #include +#include + #include /* This header must go last */ @@ -56,20 +58,26 @@ CStructuredCommentsReader::~CStructuredCommentsReader() { } -CUser_object* CStructuredCommentsReader::FindStructuredComment(CSeq_descr& descr) +const string& CStructuredCommentsReader::CStructComment::GetPrefix(const objects::CSeqdesc& desc) { - NON_CONST_ITERATE(CSeq_descr::Tdata, it, descr.Set()) + if (!desc.IsUser()) + return kEmptyStr; + + auto& user = desc.GetUser(); + if (user.IsSetType() && user.GetType().IsStr() && NStr::Equal(user.GetType().GetStr(), "StructuredComment")) { - if ((**it).IsUser()) + if (user.IsSetData() && user.GetData().size() > 0) { - if ((**it).GetUser().GetType().GetStr().compare("StructuredComment") == 0) - return &((**it).SetUser()); + const auto& fdata = *user.GetData().front(); + if (fdata.IsSetLabel() && fdata.GetLabel().IsStr() && NStr::Equal(fdata.GetLabel().GetStr(), "StructuredCommentPrefix")) + return fdata.GetData().GetStr(); } } - return 0; + + return kEmptyStr; } -objects::CUser_object* CStructuredCommentsReader::_AddStructuredComment(objects::CUser_object* user_obj, TStructComment& cmt, const CTempString& name, const CTempString& value) +objects::CUser_object* CStructuredCommentsReader::_AddStructuredComment(objects::CUser_object* user_obj, CStructComment& cmt, const CTempString& name, const CTempString& value) { if (name.compare("StructuredCommentPrefix") == 0) user_obj = 0; // reset user obj so to create a new one @@ -95,7 +103,7 @@ objects::CUser_object* CStructuredCommentsReader::_AddStructuredComment(objects: return user_obj; } -void CStructuredCommentsReader::_BuildStructuredComment(TStructComment& cmt, const vector& cols, const vector& values) +void CStructuredCommentsReader::_BuildStructuredComment(CStructComment& cmt, const vector& cols, const vector& values) { cmt.m_descs.reserve(values.size() - 1); objects::CUser_object* user = 0; diff --git a/c++/src/objtools/readers/track_data.cpp b/c++/src/objtools/readers/track_data.cpp index 59f2e679..0ae7aab6 100644 --- a/c++/src/objtools/readers/track_data.cpp +++ b/c++/src/objtools/readers/track_data.cpp @@ -1,4 +1,4 @@ -/* $Id: track_data.cpp 515629 2016-10-04 17:46:33Z ivanov $ +/* $Id: track_data.cpp 538707 2017-06-13 16:57:06Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -114,9 +114,6 @@ CTrackData::WriteToAnnot( CSeq_annot& annot) // ----------------------------------------------------------------------------- { - if (!ContainsData()) { - return false; - } CAnnot_descr& desc = annot.SetDesc(); CRef pTrackdata(new CUser_object()); pTrackdata->SetType().SetStr("Track Data"); @@ -127,17 +124,17 @@ CTrackData::WriteToAnnot( if (!Name().empty()) { annot.SetNameDesc(Name()); } + pTrackdata->SetData(); + map::const_iterator cit = Values().begin(); while ( cit != Values().end() ) { pTrackdata->AddField( cit->first, cit->second ); ++cit; } - if ( pTrackdata->CanGetData() && ! pTrackdata->GetData().empty() ) { - CRef user(new CAnnotdesc()); - user->SetUser(*pTrackdata); - desc.Set().push_back(user); - } - return true; + CRef user(new CAnnotdesc()); + user->SetUser(*pTrackdata); + desc.Set().push_back(user); + return true; } END_SCOPE(objects) diff --git a/c++/src/objtools/readers/ucscregion_reader.cpp b/c++/src/objtools/readers/ucscregion_reader.cpp index 5726bba9..152886ff 100644 --- a/c++/src/objtools/readers/ucscregion_reader.cpp +++ b/c++/src/objtools/readers/ucscregion_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: ucscregion_reader.cpp 472138 2015-07-07 16:07:55Z grichenk $ +/* $Id: ucscregion_reader.cpp 535710 2017-05-11 11:59:45Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -88,8 +88,6 @@ #include #include -#include - #include @@ -127,10 +125,10 @@ CRef CUCSCRegionReader::xParseFeatureUCSCFormat(const string string SubLine = Line.substr(IdSubI ); //cerr << IdStr << endl; //cerr << SubLine << endl; - NStr::Tokenize(NStr::TruncateSpaces(SubLine), Delims, Tokens, NStr::eMergeDelims); + NStr::Split(NStr::TruncateSpaces(SubLine), Delims, Tokens, NStr::fSplit_Tokenize); Tokens.insert(Tokens.begin(), IdStr); } else { - NStr::Tokenize(NStr::TruncateSpaces(Line), Delims, Tokens, NStr::eMergeDelims); + NStr::Split(NStr::TruncateSpaces(Line), Delims, Tokens, NStr::fSplit_Tokenize); } }} @@ -181,7 +179,7 @@ CRef CUCSCRegionReader::xParseFeatureUCSCFormat(const string // ---------------------------------------------------------------------------- void CUCSCRegionReader::xSmartFieldSplit(vector& fields, CTempString line) { - NStr::Tokenize(line, " \t.-:", fields, NStr::eMergeDelims); + NStr::Split(line, " \t.-:", fields, NStr::fSplit_Tokenize); if (line[line.length()-1] == '-') fields.push_back("-"); while (fields.size() > 3) @@ -195,6 +193,8 @@ void CUCSCRegionReader::xSmartFieldSplit(vector& fields, CTempString lin fields[0] += line[len]; fields[0] += fields[1]; fields.erase(fields.begin()+1); + } else { + break; } } } diff --git a/c++/src/objtools/readers/vcf_reader.cpp b/c++/src/objtools/readers/vcf_reader.cpp index 2cb5655f..ca931b88 100644 --- a/c++/src/objtools/readers/vcf_reader.cpp +++ b/c++/src/objtools/readers/vcf_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: vcf_reader.cpp 503929 2016-06-09 14:30:25Z foleyjp $ +/* $Id: vcf_reader.cpp 539451 2017-06-22 14:57:32Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -498,7 +498,7 @@ CVcfReader::xProcessHeaderLine( // After that come the various headers for the genotype information, and these // need to be preserved: // - NStr::Split(line, " \t", m_GenotypeHeaders, NStr::eMergeDelims); + NStr::Split(line, " \t", m_GenotypeHeaders, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); vector::iterator pos_format = find( m_GenotypeHeaders.begin(), m_GenotypeHeaders.end(), "FORMAT"); if ( pos_format == m_GenotypeHeaders.end() ) { @@ -835,7 +835,7 @@ CVcfReader::xParseData( // ---------------------------------------------------------------------------- { vector columns; - NStr::Split( line, "\t", columns, NStr::eMergeDelims ); + NStr::Split(line, "\t", columns, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); if ( columns.size() < 8 ) { return false; } @@ -857,7 +857,7 @@ CVcfReader::xParseData( vector infos; if ( columns[7] != "." ) { - NStr::Split( columns[7], ";", infos, NStr::eMergeDelims ); + NStr::Split( columns[7], ";", infos, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate ); for ( vector::iterator it = infos.begin(); it != infos.end(); ++it ) { @@ -868,11 +868,11 @@ CVcfReader::xParseData( } } if ( columns.size() > 8 ) { - NStr::Split( columns[8], ":", data.m_FormatKeys, NStr::eMergeDelims ); + NStr::Split( columns[8], ":", data.m_FormatKeys, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate ); for ( size_t u=9; u < columns.size(); ++u ) { vector values; - NStr::Split( columns[u], ":", values, NStr::eMergeDelims ); + NStr::Split( columns[u], ":", values, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate ); data.m_GenotypeData[ m_GenotypeHeaders[u-9] ] = values; } } @@ -1230,6 +1230,32 @@ CVcfReader::xProcessFormat( return true; } + +// ---------------------------------------------------------------------------- +bool CVcfReader::xAssigndbSNPTag( + const vector& ids, + CRef pDbtag) const +// ---------------------------------------------------------------------------- +{ + for (const string& id : ids) { + if (NStr::StartsWith(id, "rs") || + NStr::StartsWith(id, "ss") ) + { + try { + const int idval = NStr::StringToInt(id.substr(2)); + pDbtag->SetDb("dbSNP"); + pDbtag->SetTag().SetId(idval); + } + catch (...) { + continue; + } + return true; + } + } + return false; +} + + // ---------------------------------------------------------------------------- bool CVcfReader::xAssignVariationIds( @@ -1243,6 +1269,23 @@ CVcfReader::xAssignVariationIds( CVariation_ref& variation = pFeature->SetData().SetVariation(); // CVariation_ref::TVariant_prop& var_prop = variation.SetVariant_prop(); // var_prop.SetVersion( 5 ); + + auto it = data.m_Info.find("SOURCE"); + + if (data.m_Info.end() != it) { + vector sources = it->second; + if (sources.size() > 0 && + NStr::Equal(sources.front(), "dbsnp")) + { + CRef pDbtag = Ref(new CDbtag()); + if (xAssigndbSNPTag(data.m_Ids, pDbtag)) { + variation.SetId(pDbtag.GetNCObject()); + return true; + } + } + } + + if ( data.m_Info.find( "DB" ) != data.m_Info.end() ) { string id = data.m_Ids[0]; NStr::ToLower(id); @@ -1275,6 +1318,7 @@ CVcfReader::xAssignVariationIds( return true; } + // ---------------------------------------------------------------------------- bool CVcfReader::xAssignVariantProps( @@ -1361,6 +1405,8 @@ CVcfReader::xAssignVariantProps( infos.erase(it); } + xAssignVariantSource(data, pFeat, pEC); + //superbyte F2 it = infos.find("R5"); if (infos.end() != it) { @@ -1542,6 +1588,42 @@ CVcfReader::xAssignVariantProps( return true; } + +// ---------------------------------------------------------------------------- +void CVcfReader::xAssignVariantSource(CVcfData& data, + CRef pFeat, + ILineErrorListener* pEC) +// ---------------------------------------------------------------------------- +{ + CVcfData::INFOS& infos = data.m_Info; + auto it = infos.find("SOURCE"); + if (infos.end() != it) { + vector sources = it->second; + if (sources.size() > 0 && + NStr::Equal(sources.front(),"dbsnp")) + { + bool valid_id=false; + CRef pDbtag(new CDbtag()); + if (xAssigndbSNPTag(data.m_Ids, pDbtag)) { + pFeat->SetDbxref().push_back(pDbtag); + valid_id = true; + } + + if (!valid_id) { + AutoPtr pErr( + CObjReaderLineException::Create( + eDiag_Warning, + 0, + "CVcfReader::xAssignVariantProps: No valid dbSNP identifier", + ILineError::eProblem_GeneralParsingError) ); + ProcessWarning(*pErr, pEC); + } + infos.erase(it); + } + } +} + + // ---------------------------------------------------------------------------- bool CVcfReader::xIsCommentLine( const CTempString& strLine) diff --git a/c++/src/objtools/readers/wiggle_reader.cpp b/c++/src/objtools/readers/wiggle_reader.cpp index a5944661..9e174c0a 100644 --- a/c++/src/objtools/readers/wiggle_reader.cpp +++ b/c++/src/objtools/readers/wiggle_reader.cpp @@ -1,4 +1,4 @@ -/* $Id: wiggle_reader.cpp 503674 2016-06-07 13:47:01Z ludwigf $ +/* $Id: wiggle_reader.cpp 545119 2017-08-31 16:42:10Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -250,6 +250,8 @@ CWiggleReader::xReadSeqAnnotTable( return CRef(); } xResetChromValues(); + //set track defaults in case mandatory track line is missing + xParseTrackLine("track type=wiggle_0", pMessageListener); bool haveData = false; while (xGetLine(lr, m_CurLine)) { diff --git a/c++/src/objtools/seqmasks_io/CMakeLists.seqmasks_io.lib.txt b/c++/src/objtools/seqmasks_io/CMakeLists.seqmasks_io.lib.txt new file mode 100644 index 00000000..65334caf --- /dev/null +++ b/c++/src/objtools/seqmasks_io/CMakeLists.seqmasks_io.lib.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/seqmasks_io/Makefile.seqmasks_io.lib +# +add_library(seqmasks_io + mask_cmdline_args mask_bdb_reader mask_fasta_reader mask_writer + mask_writer_fasta mask_writer_int mask_writer_tab mask_writer_seqloc + mask_writer_blastdb_maskinfo +) +add_dependencies(seqmasks_io + seqset +) + +target_link_libraries(seqmasks_io + seqdb xobjread xobjutil +) diff --git a/c++/src/objtools/seqmasks_io/CMakeLists.txt b/c++/src/objtools/seqmasks_io/CMakeLists.txt new file mode 100644 index 00000000..a90cb4c6 --- /dev/null +++ b/c++/src/objtools/seqmasks_io/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.seqmasks_io.lib.txt) + +# Recurse subdirectories +add_subdirectory(unit_test ) diff --git a/c++/src/objtools/simple/CMakeLists.txt b/c++/src/objtools/simple/CMakeLists.txt new file mode 100644 index 00000000..6ae6987c --- /dev/null +++ b/c++/src/objtools/simple/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xobjsimple.lib.txt) + diff --git a/c++/src/objtools/simple/CMakeLists.xobjsimple.lib.txt b/c++/src/objtools/simple/CMakeLists.xobjsimple.lib.txt new file mode 100644 index 00000000..1672da1a --- /dev/null +++ b/c++/src/objtools/simple/CMakeLists.xobjsimple.lib.txt @@ -0,0 +1,14 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/objtools/simple/Makefile.xobjsimple.lib +# +add_library(xobjsimple + simple_om +) +add_dependencies(xobjsimple + seqset +) + +target_link_libraries(xobjsimple + ncbi_xloader_genbank +) + diff --git a/c++/src/serial/CMakeLists.cserial.lib.txt b/c++/src/serial/CMakeLists.cserial.lib.txt new file mode 100644 index 00000000..d99db968 --- /dev/null +++ b/c++/src/serial/CMakeLists.cserial.lib.txt @@ -0,0 +1,15 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/serial/Makefile.cserial.lib +# + +include_directories(SYSTEM ${NCBI_C_INCLUDE}) +link_directories(${NCBI_C_LIBPATH}) + +add_library(xcser + asntypes serialasn +) + +target_link_libraries(xcser + ${NCBI_C_ncbi} xser +) + diff --git a/c++/src/serial/CMakeLists.serial.lib.txt b/c++/src/serial/CMakeLists.serial.lib.txt new file mode 100644 index 00000000..53e58492 --- /dev/null +++ b/c++/src/serial/CMakeLists.serial.lib.txt @@ -0,0 +1,17 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/serial/Makefile.serial.lib +# +add_library(xser + hookdata hookdatakey typeinfo objectinfo objectiter objectio typeref + typemap stdtypes enumerated ptrinfo autoptrinfo continfo stltypes + memberid memberlist item classinfob member classinfo variant choice + choiceptr aliasinfo objistr objostr objcopy iterator serial delaybuf + pack_string exception objhook objlist objstack + ${serial_ws50_rtti_kludge} objostrasn objistrasn objostrasnb objistrasnb + objostrxml objistrxml objostrjson objistrjson serializable serialobject + pathhook rpcbase +) + +target_link_libraries(xser + xutil +) diff --git a/c++/src/serial/CMakeLists.txt b/c++/src/serial/CMakeLists.txt new file mode 100644 index 00000000..d405486d --- /dev/null +++ b/c++/src/serial/CMakeLists.txt @@ -0,0 +1,12 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.serial.lib.txt) +include(CMakeLists.cserial.lib.txt) + +# Recurse subdirectories +add_subdirectory(datatool) +add_subdirectory(test ) +add_subdirectory(soap) diff --git a/c++/src/serial/classinfo.cpp b/c++/src/serial/classinfo.cpp index 00260e64..0b60ed26 100644 --- a/c++/src/serial/classinfo.cpp +++ b/c++/src/serial/classinfo.cpp @@ -1,4 +1,4 @@ -/* $Id: classinfo.cpp 497217 2016-04-05 11:37:33Z ivanov $ +/* $Id: classinfo.cpp 532474 2017-04-05 15:51:46Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -344,10 +344,14 @@ void CClassTypeInfo::WriteImplicitMember(CObjectOStream& out, return; } if (memberInfo->Nillable()) { - out.WriteClassMemberSpecialCase( CMemberId(classType->GetName()), - memberInfo->GetTypeInfo(), memberInfo->GetItemPtr(objectPtr), - CObjectOStream::eWriteAsNil); - return; + if (out.GetDataFormat() != eSerial_AsnText && out.GetDataFormat() != eSerial_AsnBinary) { + out.WriteClassMemberSpecialCase( CMemberId(classType->GetName()), + memberInfo->GetTypeInfo(), memberInfo->GetItemPtr(objectPtr), + CObjectOStream::eWriteAsNil); + return; + } else { + goto do_write; + } } if (memberInfo->NonEmpty() || memberInfo->GetTypeInfo()->GetTypeFamily() != eTypeFamilyContainer) { @@ -360,6 +364,7 @@ void CClassTypeInfo::WriteImplicitMember(CObjectOStream& out, } } } +do_write: out.WriteNamedType(classType, memberInfo->GetTypeInfo(), memberInfo->GetItemPtr(objectPtr)); diff --git a/c++/src/serial/datatool/CMakeLists.datatool.app.txt b/c++/src/serial/datatool/CMakeLists.datatool.app.txt new file mode 100644 index 00000000..0ce3ed17 --- /dev/null +++ b/c++/src/serial/datatool/CMakeLists.datatool.app.txt @@ -0,0 +1,22 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/serial/datatool/Makefile.datatool.app +# +add_executable(datatool-app + datatool + type namespace statictype enumtype reftype unitype blocktype choicetype + typestr ptrstr stdstr classstr enumstr stlstr choicestr choiceptrstr + value mcontainer module moduleset generate filecode code + fileutil alexer aparser parser lexer exceptions comments srcutil + dtdaux dtdlexer dtdparser rpcgen aliasstr xsdlexer xsdparser + wsdllexer wsdlparser wsdlstr jsdlexer jsdparser + traversal_pattern_match_callback + traversal_code_generator traversal_merger + traversal_node traversal_spec_file_parser +) + +set_target_properties(datatool-app PROPERTIES OUTPUT_NAME datatool) + +target_link_libraries(datatool-app + xser +) + diff --git a/c++/src/serial/datatool/CMakeLists.txt b/c++/src/serial/datatool/CMakeLists.txt new file mode 100644 index 00000000..9e232419 --- /dev/null +++ b/c++/src/serial/datatool/CMakeLists.txt @@ -0,0 +1,8 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.datatool.app.txt) + +# Recurse subdirectories diff --git a/c++/src/serial/datatool/Makefile.datatool.app b/c++/src/serial/datatool/Makefile.datatool.app index 63bcc4ee..96f63afd 100644 --- a/c++/src/serial/datatool/Makefile.datatool.app +++ b/c++/src/serial/datatool/Makefile.datatool.app @@ -1,5 +1,5 @@ ################################# -# $Id: Makefile.datatool.app 341370 2011-10-19 14:23:17Z kornbluh $ +# $Id: Makefile.datatool.app 532212 2017-04-03 13:24:13Z gouriano $ # Author: Eugene Vasilchenko (vasilche@ncbi.nlm.nih.gov) ################################# @@ -13,7 +13,7 @@ SRC = datatool \ value mcontainer module moduleset generate filecode code \ fileutil alexer aparser parser lexer exceptions comments srcutil \ dtdaux dtdlexer dtdparser rpcgen aliasstr xsdlexer xsdparser \ - wsdllexer wsdlparser wsdlstr \ + wsdllexer wsdlparser wsdlstr jsdlexer jsdparser \ traversal_pattern_match_callback \ traversal_code_generator traversal_merger \ traversal_node traversal_spec_file_parser diff --git a/c++/src/serial/datatool/aliasstr.cpp b/c++/src/serial/datatool/aliasstr.cpp index 6e326dc9..8e515773 100644 --- a/c++/src/serial/datatool/aliasstr.cpp +++ b/c++/src/serial/datatool/aliasstr.cpp @@ -1,4 +1,4 @@ -/* $Id: aliasstr.cpp 507796 2016-07-21 17:25:37Z gouriano $ +/* $Id: aliasstr.cpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -326,6 +326,7 @@ void CAliasTypeStrings::GenerateCode(CClassContext& ctx) const "\n"; } methods << " info->CodeVersion(" << DATATOOL_VERSION << ");\n"; + methods << " info->DataSpec(" << CDataType::GetSourceDataSpecString() << ");\n"; methods << "}\n" "END_ALIAS_INFO\n" diff --git a/c++/src/serial/datatool/choiceptrstr.cpp b/c++/src/serial/datatool/choiceptrstr.cpp index 06308e58..c4f1ad14 100644 --- a/c++/src/serial/datatool/choiceptrstr.cpp +++ b/c++/src/serial/datatool/choiceptrstr.cpp @@ -1,4 +1,4 @@ -/* $Id: choiceptrstr.cpp 507796 2016-07-21 17:25:37Z gouriano $ +/* $Id: choiceptrstr.cpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -38,6 +38,7 @@ #include "code.hpp" #include "namespace.hpp" #include "srcutil.hpp" +#include "type.hpp" BEGIN_NCBI_SCOPE @@ -163,6 +164,7 @@ void CChoicePtrTypeStrings::GenerateClassCode(CClassCode& code, } } code.Methods() << " info->CodeVersion(" << DATATOOL_VERSION << ");\n"; + code.Methods() << " info->DataSpec(" << CDataType::GetSourceDataSpecString() << ");\n"; code.Methods() << "}\n" "END_CLASS_INFO\n" diff --git a/c++/src/serial/datatool/choicestr.cpp b/c++/src/serial/datatool/choicestr.cpp index 5970b57f..3251940b 100644 --- a/c++/src/serial/datatool/choicestr.cpp +++ b/c++/src/serial/datatool/choicestr.cpp @@ -1,4 +1,4 @@ -/* $Id: choicestr.cpp 507796 2016-07-21 17:25:37Z gouriano $ +/* $Id: choicestr.cpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1605,6 +1605,7 @@ void CChoiceTypeStrings::GenerateClassCode(CClassCode& code, } } methods << " info->CodeVersion(" << DATATOOL_VERSION << ");\n"; + methods << " info->DataSpec(" << CDataType::GetSourceDataSpecString() << ");\n"; methods << "}\n" "END_CHOICE_INFO\n" diff --git a/c++/src/serial/datatool/classstr.cpp b/c++/src/serial/datatool/classstr.cpp index 3d8d8b92..a9073c77 100644 --- a/c++/src/serial/datatool/classstr.cpp +++ b/c++/src/serial/datatool/classstr.cpp @@ -1,4 +1,4 @@ -/* $Id: classstr.cpp 507796 2016-07-21 17:25:37Z gouriano $ +/* $Id: classstr.cpp 534119 2017-04-24 17:07:34Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -96,7 +96,11 @@ bool CClassTypeStrings::x_IsNullWithAttlist(TMembers::const_iterator i) const bool CClassTypeStrings::x_IsAnyContentType(TMembers::const_iterator i) const { - return (dynamic_cast(i->type.get()) != 0); + if (x_IsUniSeq(i)) { + const CUniSequenceDataType* seq = dynamic_cast(i->dataType); + return dynamic_cast(seq->GetElementType()) != nullptr; + } + return (dynamic_cast(i->type.get()) != 0); } bool CClassTypeStrings::x_IsUniSeq(TMembers::const_iterator i) const @@ -1469,6 +1473,7 @@ void CClassTypeStrings::GenerateClassCode(CClassCode& code, } } methods << " info->CodeVersion(" << DATATOOL_VERSION << ");\n"; + methods << " info->DataSpec(" << CDataType::GetSourceDataSpecString() << ");\n"; methods << "}\n" "END_CLASS_INFO\n" diff --git a/c++/src/serial/datatool/datatool.cpp b/c++/src/serial/datatool/datatool.cpp index 74d69db4..92c8c04d 100644 --- a/c++/src/serial/datatool/datatool.cpp +++ b/c++/src/serial/datatool/datatool.cpp @@ -1,4 +1,4 @@ -/* $Id: datatool.cpp 507796 2016-07-21 17:25:37Z gouriano $ +/* $Id: datatool.cpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -50,6 +50,8 @@ #include "xsdparser.hpp" #include "wsdllexer.hpp" #include "wsdlparser.hpp" +#include "jsdlexer.hpp" +#include "jsdparser.hpp" #include "moduleset.hpp" #include "module.hpp" #include "type.hpp" @@ -297,9 +299,7 @@ bool CDataTool::ProcessModules(void) } if ( const CArgValue& fx = args["fx"] ) { - if (srctype == SourceFile::eDTD || - srctype == SourceFile::eXSD || - srctype == SourceFile::eWSDL) { + if (srctype != SourceFile::eASN) { CDataType::SetEnforcedStdXml(true); } if ( fx.AsString() == "m" ) { @@ -316,9 +316,7 @@ bool CDataTool::ProcessModules(void) } if ( const CArgValue& ax = args["fxs"] ) { - if (srctype == SourceFile::eDTD || - srctype == SourceFile::eXSD || - srctype == SourceFile::eWSDL) { + if (srctype != SourceFile::eASN) { CDataType::SetEnforcedStdXml(true); } if ( ax.AsString() == "m" ) { @@ -776,6 +774,7 @@ SourceFile::EType CDataTool::LoadDefinitions( lexer.AllowIDsEndingWithMinus(generator.GetOpt("lax_syntax")); ASNParser parser(lexer); fileSet.AddFile(parser.Modules(name)); + CDataType::SetSourceDataSpec(EDataSpec::eASN); } break; case SourceFile::eDTD: @@ -783,16 +782,16 @@ SourceFile::EType CDataTool::LoadDefinitions( DTDLexer lexer(fName,name); DTDParser parser(lexer); fileSet.AddFile(parser.Modules(name)); - CDataType::SetXmlSourceSpec(true); + CDataType::SetSourceDataSpec(EDataSpec::eDTD); } break; case SourceFile::eXSD: { name = fName.GetFileName(); - XSDLexer lexer(fName,name); + XSDLexer lexer(fName,name); XSDParser parser(lexer); fileSet.AddFile(parser.Modules(name)); - CDataType::SetXmlSourceSpec(true); + CDataType::SetSourceDataSpec(EDataSpec::eXSD); } break; case SourceFile::eWSDL: @@ -801,7 +800,16 @@ SourceFile::EType CDataTool::LoadDefinitions( WSDLLexer lexer(fName,name); WSDLParser parser(lexer); fileSet.AddFile(parser.Modules(name)); - CDataType::SetXmlSourceSpec(true); + CDataType::SetSourceDataSpec(EDataSpec::eXSD); + } + break; + case SourceFile::eJSON: + { + name = fName.GetFileName(); + JSDLexer lexer(fName,name); + JSDParser parser(lexer); + fileSet.AddFile(parser.Modules(name)); + CDataType::SetSourceDataSpec(EDataSpec::eJSON); } break; } diff --git a/c++/src/serial/datatool/datatool.hpp b/c++/src/serial/datatool/datatool.hpp index ccfaeaf3..4483eb6a 100644 --- a/c++/src/serial/datatool/datatool.hpp +++ b/c++/src/serial/datatool/datatool.hpp @@ -1,7 +1,7 @@ #ifndef DATATOOL__HPP #define DATATOOL__HPP -/* $Id: datatool.hpp 507796 2016-07-21 17:25:37Z gouriano $ +/* $Id: datatool.hpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -41,7 +41,7 @@ BEGIN_NCBI_SCOPE #define DATATOOL_VERSION_MAJOR 2 -#define DATATOOL_VERSION_MINOR 16 +#define DATATOOL_VERSION_MINOR 17 #define DATATOOL_VERSION_PATCH 0 const size_t DATATOOL_VERSION = DATATOOL_VERSION_MAJOR*10000 + DATATOOL_VERSION_MINOR*100 + DATATOOL_VERSION_PATCH; diff --git a/c++/src/serial/datatool/datatool.sh b/c++/src/serial/datatool/datatool.sh index 54b9389b..bae66a6f 100755 --- a/c++/src/serial/datatool/datatool.sh +++ b/c++/src/serial/datatool/datatool.sh @@ -1,12 +1,8 @@ #! /bin/sh -# $Id: datatool.sh 385192 2013-01-07 15:56:02Z gouriano $ +# $Id: datatool.sh 535120 2017-05-05 13:00:49Z gouriano $ # -if test "$OSTYPE" = "cygwin"; then - bases="./testdata //snowman/toolkit_test_data/objects/datatool" -else - bases="./testdata /net/snowman/vol/projects/toolkit_test_data/objects/datatool" -fi +bases="./testdata ${NCBI_TEST_DATA}/objects/datatool" if test -z "$CHECK_EXEC"; then tool="./datatool" else diff --git a/c++/src/serial/datatool/datatool_xml.sh b/c++/src/serial/datatool/datatool_xml.sh index ed94dabc..b7b767f4 100755 --- a/c++/src/serial/datatool/datatool_xml.sh +++ b/c++/src/serial/datatool/datatool_xml.sh @@ -1,12 +1,8 @@ #! /bin/sh -# $Id: datatool_xml.sh 385283 2013-01-08 17:50:10Z gouriano $ +# $Id: datatool_xml.sh 535120 2017-05-05 13:00:49Z gouriano $ # -if test "$OSTYPE" = "cygwin"; then - bases="./testdata //snowman/toolkit_test_data/objects/datatool" -else - bases="./testdata /net/snowman/vol/projects/toolkit_test_data/objects/datatool" -fi +bases="./testdata ${NCBI_TEST_DATA}/objects/datatool" if test -z "$CHECK_EXEC"; then tool="./datatool" else diff --git a/c++/src/serial/datatool/dtdaux.cpp b/c++/src/serial/datatool/dtdaux.cpp index fa524ac7..38901f73 100644 --- a/c++/src/serial/datatool/dtdaux.cpp +++ b/c++/src/serial/datatool/dtdaux.cpp @@ -1,4 +1,4 @@ -/* $Id: dtdaux.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: dtdaux.cpp 534447 2017-04-27 14:18:47Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -292,6 +292,11 @@ DTDElement::DTDElement(void) } DTDElement::DTDElement(const DTDElement& other) +{ + *this = other; +} + +DTDElement& DTDElement::operator=(const DTDElement& other) { m_SourceLine = other.m_SourceLine; m_Name = other.m_Name; @@ -310,6 +315,7 @@ DTDElement::DTDElement(const DTDElement& other) m_Nillable = other.m_Nillable; m_Comments = other.m_Comments; m_AttribComments = other.m_AttribComments; + return *this; } DTDElement::~DTDElement(void) @@ -381,6 +387,14 @@ const string& DTDElement::GetTypeName( void) const } +void DTDElement::SetDefaultRefsOccurence(EOccurrence occ) +{ + for (const string& ref : m_Refs) { + if (m_RefOcc.find(ref) == m_RefOcc.end()) { + m_RefOcc[ref] = occ; + } + } +} void DTDElement::SetOccurrence( const string& ref_name, EOccurrence occ) { m_RefOcc[ref_name] = occ; @@ -408,10 +422,12 @@ void DTDElement::AddContent( const string& ref_name) m_Refs.push_back( ref_name); } -void DTDElement::RemoveContent( const string& ref_name) +bool DTDElement::RemoveContent( const string& ref_name) { string t(ref_name); + size_t prev = m_Refs.size(); m_Refs.remove(t); + return prev != m_Refs.size(); } void DTDElement::RemoveContent( void) diff --git a/c++/src/serial/datatool/dtdaux.hpp b/c++/src/serial/datatool/dtdaux.hpp index f0a0a181..06c96574 100644 --- a/c++/src/serial/datatool/dtdaux.hpp +++ b/c++/src/serial/datatool/dtdaux.hpp @@ -1,7 +1,7 @@ #ifndef DTDAUX_HPP #define DTDAUX_HPP -/* $Id: dtdaux.hpp 406003 2013-07-10 13:17:43Z gouriano $ +/* $Id: dtdaux.hpp 534447 2017-04-27 14:18:47Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -213,6 +213,7 @@ class DTDElement public: DTDElement(void); DTDElement(const DTDElement& other); + DTDElement& operator=(const DTDElement& other); virtual ~DTDElement(void); enum EType { @@ -226,6 +227,10 @@ public: eChoice, // (a|b|c) eSet, // (a,b,c) + eAlias, + eEnum, + eIntEnum, + eBoolean, eInteger, eBigInt, @@ -266,6 +271,7 @@ public: void SetTypeName( const string& name); const string& GetTypeName( void) const; + void SetDefaultRefsOccurence(EOccurrence occ); void SetOccurrence( const string& ref_name, EOccurrence occ); EOccurrence GetOccurrence(const string& ref_name) const; @@ -274,7 +280,7 @@ public: // i.e. element contains other elements void AddContent( const string& ref_name); - void RemoveContent( const string& ref_name); + bool RemoveContent( const string& ref_name); void RemoveContent( void); const list& GetContent(void) const; diff --git a/c++/src/serial/datatool/dtdparser.cpp b/c++/src/serial/datatool/dtdparser.cpp index 859f5d05..64a1aeee 100644 --- a/c++/src/serial/datatool/dtdparser.cpp +++ b/c++/src/serial/datatool/dtdparser.cpp @@ -1,4 +1,4 @@ -/* $Id: dtdparser.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: dtdparser.cpp 534303 2017-04-26 13:43:42Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -562,7 +562,7 @@ string DTDParser::CreateEmbeddedName(const DTDElement& node, int depth) const if (!refname.empty()) { string::size_type name = refname.find(':'); name = (name != string::npos && (name+1) < refname.size()) ? (name+1) : 0; - new_var += (char)toupper((unsigned char) refname[name]);; + new_var += (char)toupper((unsigned char) refname[name]); // try to avoid very long names if (new_var.size() > 8) { break; @@ -892,7 +892,8 @@ void DTDParser::GenerateDataTree(CDataTypeModule& module, const string& name_spa for (i = m_MapElement.begin(); i != m_MapElement.end(); ++i) { DTDElement::EType type = i->second.GetType(); - if (i->second.GetName().empty() && + if (m_SrcType != eJson && + i->second.GetName().empty() && i->first != s_SpecialName && type != DTDElement::eAny) { ParseError(i->first.c_str(),"definition"); @@ -961,8 +962,11 @@ CDataType* DTDParser::x_Type( DTDElement::EOccurrence ref_occ = refNode.GetOccurrence(); DTDElement::EOccurrence new_occ = (fromInside || ref_occ == DTDElement::eOne) ? occ : ref_occ; + if (m_SrcType == eJson) { + new_occ = ref_occ; + } type = x_Type(refNode, new_occ, fromInside); - if (node.IsEmbedded()) { + if (node.IsEmbedded() && m_SrcType != eJson) { DTDElement& emb = const_cast(node); emb.SetName(refNode.GetName()); } @@ -1040,6 +1044,28 @@ CDataType* DTDParser::x_Type( } } break; + case DTDElement::eAlias: + { + string base(node.GetTypeName()); + map::const_iterator b; + for (b = m_MapElement.find(base); + b != m_MapElement.end(); b = m_MapElement.find(base)) { + if (b->second.GetType() != DTDElement::eAlias) { + base = b->second.GetName(); + break; + } + base = b->second.GetTypeName(); + } + type = new CReferenceDataType(base); + type->SetIsAlias(true); + } + break; + case DTDElement::eEnum: + type = EnumeratedBlock(node, new CEnumDataType()); + break; + case DTDElement::eIntEnum: + type = EnumeratedBlock(node, new CIntEnumDataType()); + break; case DTDElement::eString: type = new CStringDataType(); break; @@ -1491,6 +1517,21 @@ CDataType* DTDParser::EnumeratedBlock(const DTDAttribute& att, return enumType; } +CDataType* DTDParser::EnumeratedBlock(const DTDElement& node, + CEnumDataType* enumType) +{ + int v=1; + const list& enums = node.GetContent(); + list::const_iterator i; + for (i = enums.begin(); i != enums.end(); ++i, ++v) { + if (enumType->IsInteger()) { + v = NStr::StringToInt(*i); + } + enumType->AddValue( *i, v).SetSourceLine( node.GetSourceLine()); + } + return enumType; +} + void DTDParser::SetCommentsIfEmpty(CComments* comments) { if (comments->Empty()) { @@ -1592,6 +1633,10 @@ void DTDParser::PrintDocumentNode(const string& name, const DTDElement& node) case DTDElement::eChoice: cout << "choice"; break; case DTDElement::eSet: cout << "set"; break; + case DTDElement::eAlias: cout << "Alias"; break; + case DTDElement::eEnum: cout << "Enum"; break; + case DTDElement::eIntEnum: cout << "IntEnum"; break; + case DTDElement::eBoolean: cout << "boolean"; break; case DTDElement::eInteger: cout << "integer"; break; case DTDElement::eBigInt: cout << "BigInt"; break; diff --git a/c++/src/serial/datatool/dtdparser.hpp b/c++/src/serial/datatool/dtdparser.hpp index eea87e74..8a21196e 100644 --- a/c++/src/serial/datatool/dtdparser.hpp +++ b/c++/src/serial/datatool/dtdparser.hpp @@ -1,7 +1,7 @@ #ifndef DTDPARSER_HPP #define DTDPARSER_HPP -/* $Id: dtdparser.hpp 406003 2013-07-10 13:17:43Z gouriano $ +/* $Id: dtdparser.hpp 533028 2017-04-12 16:15:32Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -69,7 +69,8 @@ public: enum ESrcType { eDTD, eSchema, - eWsdl + eWsdl, + eJson }; AutoPtr Modules(const string& fileName); @@ -133,6 +134,8 @@ protected: CDataValue* x_AttribValue(const DTDAttribute& att, const string& value); CDataType* EnumeratedBlock(const DTDAttribute& att, CEnumDataType* enumType); + CDataType* EnumeratedBlock(const DTDElement& node, + CEnumDataType* enumType); void SetCommentsIfEmpty(CComments* comments); #if defined(NCBI_DTDPARSER_TRACE) diff --git a/c++/src/serial/datatool/enumtype.cpp b/c++/src/serial/datatool/enumtype.cpp index 673a1053..289f60eb 100644 --- a/c++/src/serial/datatool/enumtype.cpp +++ b/c++/src/serial/datatool/enumtype.cpp @@ -1,4 +1,4 @@ -/* $Id: enumtype.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: enumtype.cpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/exceptions.hpp b/c++/src/serial/datatool/exceptions.hpp index f46ce399..bb05c635 100644 --- a/c++/src/serial/datatool/exceptions.hpp +++ b/c++/src/serial/datatool/exceptions.hpp @@ -1,7 +1,7 @@ #ifndef DATATOOL_EXCEPTIONS_HPP #define DATATOOL_EXCEPTIONS_HPP -/* $Id: exceptions.hpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: exceptions.hpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/filecode.cpp b/c++/src/serial/datatool/filecode.cpp index 585911ef..5bad639b 100644 --- a/c++/src/serial/datatool/filecode.cpp +++ b/c++/src/serial/datatool/filecode.cpp @@ -1,4 +1,4 @@ -/* $Id: filecode.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: filecode.cpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/fileutil.cpp b/c++/src/serial/datatool/fileutil.cpp index 6739fd19..7c2c5ddc 100644 --- a/c++/src/serial/datatool/fileutil.cpp +++ b/c++/src/serial/datatool/fileutil.cpp @@ -1,4 +1,4 @@ -/* $Id: fileutil.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: fileutil.cpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -94,6 +94,10 @@ SourceFile::EType SourceFile::GetType(void) const return eXSD; } else if (NStr::CompareNocase(ext,".wsdl") == 0) { return eWSDL; + } else if (NStr::CompareNocase(ext,".json") == 0) { + return eJSON; + } else if (NStr::CompareNocase(ext,".jsd") == 0) { + return eJSON; } return eUnknown; } diff --git a/c++/src/serial/datatool/fileutil.hpp b/c++/src/serial/datatool/fileutil.hpp index 2710e2f1..a2b32be2 100644 --- a/c++/src/serial/datatool/fileutil.hpp +++ b/c++/src/serial/datatool/fileutil.hpp @@ -1,7 +1,7 @@ #ifndef FILEUTIL_HPP #define FILEUTIL_HPP -/* $Id: fileutil.hpp 365689 2012-06-07 13:52:21Z gouriano $ +/* $Id: fileutil.hpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -58,7 +58,8 @@ public: eASN, // ASN file eDTD, // DTD file eXSD, // XSD file - eWSDL // WSDL file + eWSDL, // WSDL file + eJSON // JSON schema file }; EType GetType(void) const; string GetFileName(void) const diff --git a/c++/src/serial/datatool/jsdlexer.cpp b/c++/src/serial/datatool/jsdlexer.cpp new file mode 100644 index 00000000..5d759626 --- /dev/null +++ b/c++/src/serial/datatool/jsdlexer.cpp @@ -0,0 +1,176 @@ +/* $Id: jsdlexer.cpp 532212 2017-04-03 13:24:13Z gouriano $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Andrei Gourianov +* +* File Description: +* JSON Schema lexer +* +* =========================================================================== +*/ + +#include +#include "jsdlexer.hpp" +#include "tokens.hpp" + +BEGIN_NCBI_SCOPE + + +JSDLexer::JSDLexer(CNcbiIstream& in, const string& name) + : DTDLexer(in,name) +{ +} + +JSDLexer::~JSDLexer(void) +{ +} + + +void JSDLexer::SkipWhitespace(void) +{ + char c; + for (;;) { + c = Char(); + switch (c) { + case ' ': + case '\t': + case '\r': + SkipChar(); + break; + case '\n': + SkipChar(); + NextLine(); + break; + default: + return; + } + } +} + +void JSDLexer::LookupComments(void) +{ + SkipWhitespace(); +} + +TToken JSDLexer::LookupToken(void) +{ + TToken tok = T_SYMBOL; + if (m_CharsToSkip != 0) { + SkipChars(m_CharsToSkip); + m_CharsToSkip = 0; + SkipWhitespace(); + } + SkipWhitespace(); + char c = Char(); + switch (c) { + case '{': + tok = K_BEGIN_OBJECT; + break; + case '}': + tok = K_END_OBJECT; + break; + case '[': + tok = K_BEGIN_ARRAY; + break; + case ']': + tok = K_END_ARRAY; + break; + case ':': + tok = K_KEY; + break; + case '\"': + LookupString(); + return T_STRING; + case '-': + case '+': + if ( isdigit((unsigned char)Char(1)) ) { + StartToken(); + AddChar(); + return LookupNumber(); + } + return T_SYMBOL; + default: + if ( isdigit((unsigned char)c) ) { + StartToken(); + AddChar(); + return LookupNumber(); + } else if ( isalpha ((unsigned char)c)) { + StartToken(); + AddChar(); + LookupIdentifier(); + return LookupKeyword(); + } + return T_SYMBOL; + } + StartToken(); + AddChar(); + return tok; +} + +TToken JSDLexer::LookupNumber(void) +{ + while ( isdigit((unsigned char)Char()) ) { + AddChar(); + } + char c = Char(); + if (c == '.' || c == 'e' || c == 'E' || c == '-' || c == '+') { + AddChar(); + LookupNumber(); + return T_DOUBLE; + } + return T_NUMBER; +} + +void JSDLexer::LookupIdentifier(void) +{ + for (;;) { + char c = Char(); + if ( isalpha((unsigned char)c) ) { + AddChar(); + } else { + return; + } + } +} + +#define CHECK(keyword, t, length) \ + if ( memcmp(token, keyword, length) == 0 ) return t + +TToken JSDLexer::LookupKeyword(void) +{ + const char* token = CurrentTokenStart(); + switch ( CurrentTokenLength() ) { + case 4: + CHECK("true", K_TRUE, 4); + CHECK("null", K_NULL, 4); + break; + case 5: + CHECK("false", K_FALSE, 5); + break; + } + return T_TYPE_REFERENCE; +} + +END_NCBI_SCOPE diff --git a/c++/src/serial/datatool/jsdlexer.hpp b/c++/src/serial/datatool/jsdlexer.hpp new file mode 100644 index 00000000..43e19a5e --- /dev/null +++ b/c++/src/serial/datatool/jsdlexer.hpp @@ -0,0 +1,59 @@ +#ifndef JSDLEXER_HPP +#define JSDLEXER_HPP + +/* $Id: jsdlexer.hpp 532212 2017-04-03 13:24:13Z gouriano $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Andrei Gourianov +* +* File Description: +* JSON Schema lexer +* +* =========================================================================== +*/ + +#include "dtdlexer.hpp" +#include + +BEGIN_NCBI_SCOPE + +class JSDLexer : public DTDLexer +{ +public: + JSDLexer(CNcbiIstream& in, const string& name); + virtual ~JSDLexer(void); + +protected: + void SkipWhitespace(void); + virtual void LookupComments(void); + virtual TToken LookupToken(void); + TToken LookupNumber(void); + void LookupIdentifier(void); + TToken LookupKeyword(void); +}; + +END_NCBI_SCOPE + +#endif // JSDLEXER_HPP diff --git a/c++/src/serial/datatool/jsdparser.cpp b/c++/src/serial/datatool/jsdparser.cpp new file mode 100644 index 00000000..4671887e --- /dev/null +++ b/c++/src/serial/datatool/jsdparser.cpp @@ -0,0 +1,506 @@ +/* $Id: jsdparser.cpp 534655 2017-05-01 13:02:07Z gouriano $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Andrei Gourianov +* +* File Description: +* JSON Schema parser +* +* =========================================================================== +*/ + +#include +#include "exceptions.hpp" +#include "jsdparser.hpp" +#include "tokens.hpp" +#include "module.hpp" +#include + + +#define NCBI_USE_ERRCODE_X Serial_Parsers + +BEGIN_NCBI_SCOPE + +///////////////////////////////////////////////////////////////////////////// +// JSDParser + +JSDParser::JSDParser(JSDLexer& lexer) + : DTDParser(lexer) +{ + m_SrcType = eJson; +} + +JSDParser::~JSDParser(void) +{ +} + +void JSDParser::BeginDocumentTree(void) +{ +// Reset(); +} + +void JSDParser::BuildDocumentTree(CDataTypeModule& module) +{ + string value; + TToken tok; + m_URI.clear(); + m_URI.push_back("#"); + for (;;) { + tok = GetNextToken(); + switch (tok) { + case K_BEGIN_OBJECT: + ParseRoot(); + break; + case T_EOF: + return; + default: + break; + } + } +} + +void JSDParser::ParseRoot(void) +{ + string node_id(m_URI.front()); + DTDElement& node = m_MapElement[node_id]; + node.SetName("JsonValue"); + ParseNode(node); +} + +void JSDParser::ParseObjectContent(DTDElement* owner) +{ + TToken tok; + for (tok = GetNextToken(); tok != K_END_OBJECT; tok = GetNextToken()) { + if (tok == K_KEY) { + ParseMemberDefinition(owner); + } + } +} + +void JSDParser::ParseMemberDefinition(DTDElement* owner) +{ + string key = Value(); + m_URI.push_back(key); + string node_id = NStr::Join(m_URI,"/"); + DTDElement& item = m_MapElement[node_id]; + item.SetName(key); + item.SetNamed(); + if (owner) { + item.SetEmbedded(); + } + TToken tok = GetNextToken(); + if (tok == K_BEGIN_OBJECT) { + ParseNode(item); + } + if (owner) { + AddElementContent(*owner,node_id); + } + m_URI.pop_back(); +} + +void JSDParser::ParseArrayContent(DTDElement& node) +{ + string node_id = NStr::Join(m_URI,"/"); + DTDElement& item = m_MapElement[node_id]; + item.SetOccurrence(DTDElement::eZeroOrMore); + ParseNode(item); + item.SetEmbedded(); + AddElementContent(node,node_id); +} + +void JSDParser::ParseNode(DTDElement& node) +{ + string key; + TToken tok; + bool is_object = false; + bool has_additional_prop = false;//true; + node.SetSourceLine( Lexer().CurrentLine()); + for (tok = GetNextToken(); tok != K_END_OBJECT; tok = GetNextToken()) { + if (tok == K_KEY) { + key = Value(); + tok = GetNextToken(); + if (tok == K_VALUE) { + if (key == "$schema") { + } else if (key == "title") { + if (!node.IsNamed()) { + node.SetName(Value()); + } + } else if (key == "type") { + if (Value() == "string") { + node.SetType(DTDElement::eString); + } else if (Value() == "integer") { + node.SetType(DTDElement::eInteger); + } else if (Value() == "number") { + node.SetType(DTDElement::eDouble); + } else if (Value() == "boolean") { + node.SetType(DTDElement::eBoolean); + } else if (Value() == "null") { + node.SetType(DTDElement::eEmpty); + } else if (Value() == "object") { + node.SetType(DTDElement::eSequence); + } else if (Value() == "array") { + node.SetType(DTDElement::eSequence); + } + } else if (key == "default") { + node.SetDefault(Value()); + AdjustMinOccurence(node, 0); + } else if (key == "description") { + node.Comments().Add(Value()); + } else if (key == "$ref") { + node.SetTypeName(Value()); + node.SetType(DTDElement::eAlias); + } else { + ERR_POST_X(8, Warning << GetLocation() << "Unsupported property: " << key); + } + } else if (tok == T_NUMBER) { + if (key == "minItems") { + AdjustMinOccurence(node, NStr::StringToInt(Value())); + } else { + ERR_POST_X(8, Warning << GetLocation() << "Unsupported property: " << key); + } + } else if (tok == K_BEGIN_OBJECT) { + if (key == "properties") { + is_object = true; + ParseObjectContent(&node); + node.SetDefaultRefsOccurence(DTDElement::eZeroOrOne); + } else if (key == "items") { + m_URI.push_back(key); + ParseArrayContent(node); + m_URI.pop_back(); + } else if (key == "definitions") { + m_URI.push_back(key); + ParseObjectContent(nullptr); + m_URI.pop_back(); + } else if (key == "dependencies") { + ParseDependencies(node); + } else { + ERR_POST_X(8, Warning << GetLocation() << "Unsupported property: " << key); + SkipUnknown(K_END_OBJECT); + } + } else if (tok == K_BEGIN_ARRAY) { + if (key == "required") { + ParseRequired(node); + } else if (key == "enum") { + ParseEnumeration(node); + } else if (key == "oneOf") { + ParseOneOf(node); + } else if (key == "anyOf") { + ParseAnyOf(node); + } else if (key == "allOf") { + ParseAllOf(node); + } else if (key == "type") { + ParseError("type arrays not supported", "string"); + } else if (key == "items") { + ParseError("tuple validation not supported", "{"); + } else { + ERR_POST_X(8, Warning << GetLocation() << "Unsupported property: " << key); + SkipUnknown(K_END_ARRAY); + } +#if 0 + } else if (tok == K_TRUE || tok == K_FALSE) { + if (key == "additionalProperties") { + has_additional_prop = tok == K_TRUE; + } else { + ERR_POST_X(8, Warning << GetLocation() << "Unsupported property: " << key); + } +#endif + } else { + ERR_POST_X(8, Warning << GetLocation() << "Unsupported property: " << key); + } + } + } + if (is_object && has_additional_prop) { + string item_id = NStr::Join(m_URI,"/") + "*"; + DTDElement& item = m_MapElement[item_id]; + item.SetType(DTDElement::eAny); + item.SetOccurrence(DTDElement::eZeroOrMore); + item.SetEmbedded(); + item.SetName(CreateEmbeddedName(item,0)); + AddElementContent(node, item_id); + } +} + +void JSDParser::AdjustMinOccurence(DTDElement& node, int occ) +{ + DTDElement::EOccurrence occNow = node.GetOccurrence(); + DTDElement::EOccurrence occNew = occNow; + if (occ == 0) { + if (occNow == DTDElement::eOne) { + occNew = DTDElement::eZeroOrOne; + } else if (occNow == DTDElement::eOneOrMore) { + occNew = DTDElement::eZeroOrMore; + } + } else { + if (occ != 1) { + ERR_POST_X(8, Warning << GetLocation() << "Unsupported property minItems= " << occ); + } + if (occNow == DTDElement::eZeroOrOne) { + occNew = DTDElement::eOne; + } else if (occNow == DTDElement::eZeroOrMore) { + occNew = DTDElement::eOneOrMore; + } + } + node.SetOccurrence(occNew); +} + +void JSDParser::ParseRequired(DTDElement& node) +{ + TToken tok; + for (tok = GetNextToken(); tok != K_END_ARRAY; tok = GetNextToken()) { + if (tok == K_VALUE) { + m_URI.push_back(Value()); + string node_id = NStr::Join(m_URI,"/"); + m_URI.pop_back(); + if (m_MapElement[node_id].GetDefault().empty()) { + node.SetOccurrence(node_id, DTDElement::eOne); + } + } + } +} + +void JSDParser::ParseDependencies(DTDElement& node) +{ + string key, node_id; + TToken tok; + int i=0; + for (tok = GetNextToken(); tok != K_END_OBJECT; tok = GetNextToken()) { + if (tok == K_KEY) { + key = Value(); + m_URI.push_back(Value()); + node_id = NStr::Join(m_URI,"/"); + m_URI.pop_back(); + if (node.RemoveContent(node_id)) { + DTDElement::EOccurrence occ = node.GetOccurrence(node_id); + string seq_id = NStr::Join(m_URI,"/") + "/" + NStr::NumericToString(i++); + DTDElement& seq = m_MapElement[seq_id]; + seq.SetType(DTDElement::eSequence); + seq.SetName(seq_id); + seq.SetEmbedded(); + seq.SetOccurrence(occ); + seq.SetOccurrence(node_id, occ); + AddElementContent(seq, node_id); + AddElementContent(node, seq_id); + tok = GetNextToken(); + if (tok == K_BEGIN_OBJECT) { + ParseNode(seq); + } else { + for (tok = GetNextToken(); tok != K_END_ARRAY; tok = GetNextToken()) { + if (tok == K_VALUE) { + key = Value(); + m_URI.push_back(Value()); + node_id = NStr::Join(m_URI,"/"); + m_URI.pop_back(); + node.RemoveContent(node_id); + DTDElement::EOccurrence occ = node.GetOccurrence(node_id); + seq.SetOccurrence(node_id, occ); + AddElementContent(seq, node_id); + } + } + } + } else { + tok = GetNextToken(); + if (tok == K_BEGIN_OBJECT) { + SkipUnknown(K_END_OBJECT); + } else if (tok == K_BEGIN_ARRAY) { + SkipUnknown(K_END_ARRAY); + } else { + ParseError("Invalid schema", "{ or ["); + } + } + } else if (tok != T_SYMBOL) { + ParseError("Invalid schema", "element name"); + } + } + FixEmbeddedNames(node); +} + +void JSDParser::ParseEnumeration(DTDElement& node) +{ + bool isknown = true; + if (node.GetType() == DTDElement::eInteger) { + node.ResetType(DTDElement::eUnknown); + node.SetType(DTDElement::eIntEnum); + } else if (node.GetType() == DTDElement::eString) { + node.ResetType(DTDElement::eUnknown); + node.SetType(DTDElement::eEnum); + } else if (node.GetType() == DTDElement::eUnknown) { + isknown = false; + } else { + ParseError("enum restriction not supported", "string or integer type"); + } + bool isint = node.GetType() == DTDElement::eIntEnum; + TToken tok; + for (tok = GetNextToken(); tok != K_END_ARRAY; tok = GetNextToken()) { + if (tok != T_SYMBOL) { + if (!isknown) { + isknown = true; + if (tok == T_NUMBER) { + node.SetType(DTDElement::eIntEnum); + isint = true; + } else if (tok == K_VALUE) { + node.SetType(DTDElement::eEnum); + isint = false; + } + } + if ((isint && tok == T_NUMBER) || (!isint && tok == K_VALUE)) { + node.AddContent(Value()); + } else { + ParseError("enum restriction not supported", isint? "integer" : "string"); + } + } + } +} + +void JSDParser::ParseOneOf(DTDElement& node) +{ + string node_id_base = NStr::Join(m_URI,"/"); + DTDElement::EType type = node.GetType(); + vector contents; + TToken tok; + for (tok = GetNextToken(); tok != K_END_ARRAY; tok = GetNextToken()) { + if (tok == K_BEGIN_OBJECT) { + contents.push_back(DTDElement()); + DTDElement& item = contents.back(); + item.SetType(type); + item.SetEmbedded(); + ParseNode(item); + } + } + // now merge + bool hasnil = false; + DTDElement::EType nexttype = DTDElement::eUnknown; + for(const DTDElement& c : contents) { + const DTDElement& e = (c.GetType() == DTDElement::eAlias) ? m_MapElement[c.GetTypeName()] : c; + if (e.GetType() == DTDElement::eEmpty && !e.IsNamed()) { + hasnil = true; + } + if (e.GetType() != DTDElement::eEmpty && type == DTDElement::eUnknown) { + if (nexttype == DTDElement::eUnknown) { + nexttype = e.GetType(); + } else { + nexttype = DTDElement::eChoice; + } + } + } + if (nexttype == DTDElement::eUnknown) { + nexttype = DTDElement::eChoice; + } + if (type == DTDElement::eUnknown) { + node.SetType(nexttype); + } else if (type == DTDElement::eSequence) { + node.ResetType(DTDElement::eUnknown); + node.SetType(nexttype); + } + type = node.GetType(); + if (type == DTDElement::eSequence || type == DTDElement::eChoice) { + int i = 0; + for(DTDElement& c : contents) { + string item_id = node_id_base + "/" + NStr::NumericToString(i++); + if (c.GetType() == DTDElement::eAlias) { + item_id = c.GetTypeName(); + } else { + if (!c.IsNamed()) { + c.SetName(item_id); + } + m_MapElement[item_id] = c; + } + AddElementContent(node,item_id); + } + FixEmbeddedNames(node); + } + node.SetNillable(hasnil); +} + +void JSDParser::ParseAnyOf(DTDElement& node) +{ + ParseOneOf(node); +// node.SetOccurrence(DTDElement::eZeroOrMore); +} + +void JSDParser::ParseAllOf(DTDElement& node) +{ + string node_id_base = NStr::Join(m_URI,"/"); + DTDElement::EType type = node.GetType(); + vector contents; + TToken tok; + for (tok = GetNextToken(); tok != K_END_ARRAY; tok = GetNextToken()) { + if (tok == K_BEGIN_OBJECT) { + contents.push_back(DTDElement()); + DTDElement& item = contents.back(); + item.SetType(type); + item.SetEmbedded(); + ParseNode(item); + } + } + for(const DTDElement& c : contents) { + const DTDElement& e = (c.GetType() == DTDElement::eAlias) ? m_MapElement[c.GetTypeName()] : c; + node.SetType(e.GetType()); + string item_id; + if (c.GetType() != DTDElement::eAlias && e.IsNamed()) { + item_id = e.GetName(); + AddElementContent(node,item_id); + } else { + for(const string& ref : e.GetContent()) { + item_id = ref; + AddElementContent(node,item_id); + } + } + } +} +void JSDParser::SkipUnknown(TToken tokend) +{ + TToken tok; + for (tok = GetNextToken(); tok != tokend; tok = GetNextToken()) { + if (tok == K_BEGIN_ARRAY) { + SkipUnknown(K_END_ARRAY); + } else if (tok == K_BEGIN_OBJECT) { + SkipUnknown(K_END_OBJECT); + } + } +} + +const string& JSDParser::Value(void) +{ + return m_StringValue; +} + +TToken JSDParser::GetNextToken(void) +{ + TToken tok = Next(); + if (tok == T_STRING) { + m_StringValue = NextToken().GetText(); + Consume(); + tok = Next(); + if (tok != K_KEY) { + return K_VALUE; + } + } else { + m_StringValue = NextToken().GetText(); + } + Consume(); + return tok; +} + +END_NCBI_SCOPE diff --git a/c++/src/serial/datatool/jsdparser.hpp b/c++/src/serial/datatool/jsdparser.hpp new file mode 100644 index 00000000..1f32d81f --- /dev/null +++ b/c++/src/serial/datatool/jsdparser.hpp @@ -0,0 +1,82 @@ +#ifndef JSDPARSER_HPP +#define JSDPARSER_HPP + +/* $Id: jsdparser.hpp 534447 2017-04-27 14:18:47Z gouriano $ +* =========================================================================== +* +* PUBLIC DOMAIN NOTICE +* National Center for Biotechnology Information +* +* This software/database is a "United States Government Work" under the +* terms of the United States Copyright Act. It was written as part of +* the author's official duties as a United States Government employee and +* thus cannot be copyrighted. This software/database is freely available +* to the public for use. The National Library of Medicine and the U.S. +* Government have not placed any restriction on its use or reproduction. +* +* Although all reasonable efforts have been taken to ensure the accuracy +* and reliability of the software and data, the NLM and the U.S. +* Government do not and cannot warrant the performance or results that +* may be obtained by using this software or data. The NLM and the U.S. +* Government disclaim all warranties, express or implied, including +* warranties of performance, merchantability or fitness for any particular +* purpose. +* +* Please cite the author in any work or product based on this material. +* +* =========================================================================== +* +* Author: Andrei Gourianov +* +* File Description: +* JSON Schema parser +* +* =========================================================================== +*/ + +#include +#include "dtdparser.hpp" +#include "jsdlexer.hpp" + +BEGIN_NCBI_SCOPE + + +///////////////////////////////////////////////////////////////////////////// +// JSDParser + +class JSDParser : public DTDParser +{ +public: + JSDParser( JSDLexer& lexer); + virtual ~JSDParser(void); + +protected: + virtual void BeginDocumentTree(void); + virtual void BuildDocumentTree(CDataTypeModule& module); + + void ParseRoot(void); + void ParseObjectContent(DTDElement* owner); + void ParseMemberDefinition(DTDElement* owner); + void ParseArrayContent(DTDElement& node); + void ParseNode(DTDElement& node); + void AdjustMinOccurence(DTDElement& node, int occ); + void ParseRequired(DTDElement& node); + void ParseDependencies(DTDElement& node); + void ParseEnumeration(DTDElement& node); + void ParseOneOf(DTDElement& node); + void ParseAnyOf(DTDElement& node); + void ParseAllOf(DTDElement& node); + + void SkipUnknown(TToken tokend); + + const string& Value(void); + + TToken GetNextToken(void); + + string m_StringValue; + list m_URI; +}; + +END_NCBI_SCOPE + +#endif // JSDPARSER_HPP diff --git a/c++/src/serial/datatool/module.cpp b/c++/src/serial/datatool/module.cpp index fb1a9945..8607c3b1 100644 --- a/c++/src/serial/datatool/module.cpp +++ b/c++/src/serial/datatool/module.cpp @@ -1,4 +1,4 @@ -/* $Id: module.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: module.cpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/srcutil.cpp b/c++/src/serial/datatool/srcutil.cpp index 32617133..a1ce4073 100644 --- a/c++/src/serial/datatool/srcutil.cpp +++ b/c++/src/serial/datatool/srcutil.cpp @@ -1,4 +1,4 @@ -/* $Id: srcutil.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: srcutil.cpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/statictype.cpp b/c++/src/serial/datatool/statictype.cpp index 460d92bb..3ee0dc38 100644 --- a/c++/src/serial/datatool/statictype.cpp +++ b/c++/src/serial/datatool/statictype.cpp @@ -1,4 +1,4 @@ -/* $Id: statictype.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: statictype.cpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -92,7 +92,7 @@ void CStaticDataType::PrintXMLSchema(CNcbiOstream& out, if (!use.empty()) { out << " use=\"" << use << "\""; } else { - if (GetXmlSourceSpec()) { + if (!IsASNDataSpec()) { if (optional) { out << " minOccurs=\"0\""; } @@ -265,7 +265,7 @@ const char* CBoolDataType::GetXMLContents(void) const string CBoolDataType::GetSchemaTypeString(void) const { - if (GetXmlSourceSpec()) { + if (!IsASNDataSpec()) { return "xs:boolean"; } if (GetParentType() && diff --git a/c++/src/serial/datatool/tokens.hpp b/c++/src/serial/datatool/tokens.hpp index 5c270020..e764a932 100644 --- a/c++/src/serial/datatool/tokens.hpp +++ b/c++/src/serial/datatool/tokens.hpp @@ -1,7 +1,7 @@ #ifndef ASNTOKENS_HPP #define ASNTOKENS_HPP -/* $Id: tokens.hpp 412225 2013-09-05 15:31:52Z gouriano $ +/* $Id: tokens.hpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -154,7 +154,14 @@ enum TToken { K_PORT = 410, K_ADDRESS = 411, K_BODY = 412, - K_HEADER = 413 + K_HEADER = 413, + + K_BEGIN_OBJECT = 501, + K_END_OBJECT = 502, + K_BEGIN_ARRAY = 503, + K_END_ARRAY = 504, + K_KEY = 505, + K_VALUE = 506 }; END_NCBI_SCOPE diff --git a/c++/src/serial/datatool/traversal_code_generator.cpp b/c++/src/serial/datatool/traversal_code_generator.cpp index a98dc8be..a89190c4 100644 --- a/c++/src/serial/datatool/traversal_code_generator.cpp +++ b/c++/src/serial/datatool/traversal_code_generator.cpp @@ -1,4 +1,4 @@ -/* $Id: traversal_code_generator.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: traversal_code_generator.cpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/traversal_node.cpp b/c++/src/serial/datatool/traversal_node.cpp index 687137c9..8402a42a 100644 --- a/c++/src/serial/datatool/traversal_node.cpp +++ b/c++/src/serial/datatool/traversal_node.cpp @@ -1,4 +1,4 @@ -/* $Id: traversal_node.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: traversal_node.cpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/traversal_pattern_match_callback.cpp b/c++/src/serial/datatool/traversal_pattern_match_callback.cpp index be93bb9a..e01fd170 100644 --- a/c++/src/serial/datatool/traversal_pattern_match_callback.cpp +++ b/c++/src/serial/datatool/traversal_pattern_match_callback.cpp @@ -1,4 +1,4 @@ -/* $Id: traversal_pattern_match_callback.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: traversal_pattern_match_callback.cpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/traversal_spec_file_parser.cpp b/c++/src/serial/datatool/traversal_spec_file_parser.cpp index 08fe0650..c2db72a9 100644 --- a/c++/src/serial/datatool/traversal_spec_file_parser.cpp +++ b/c++/src/serial/datatool/traversal_spec_file_parser.cpp @@ -1,4 +1,4 @@ -/* $Id: traversal_spec_file_parser.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: traversal_spec_file_parser.cpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/type.cpp b/c++/src/serial/datatool/type.cpp index f14fef20..60a936d7 100644 --- a/c++/src/serial/datatool/type.cpp +++ b/c++/src/serial/datatool/type.cpp @@ -1,4 +1,4 @@ -/* $Id: type.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: type.cpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -58,7 +58,7 @@ BEGIN_NCBI_SCOPE bool CDataType::sm_EnableDTDEntities = false; bool CDataType::sm_EnforcedStdXml = false; -bool CDataType::sm_XmlSourceSpec = false; +EDataSpec CDataType::sm_SourceDataSpec = EDataSpec::eUnknown; set CDataType::sm_SavedNames; map CDataType::sm_ClassToMember; @@ -771,7 +771,7 @@ AutoPtr CDataType::GenerateCode(void) const if (uniseq) { nonempty = uniseq->IsNonEmpty(); } - noprefix = GetXmlSourceSpec(); + noprefix = !IsASNDataSpec(); code->AddMember(dType, GetTag(), nonempty, noprefix); SetParentClassTo(*code); return AutoPtr(code.release()); @@ -924,6 +924,18 @@ const char* CDataType::GetDEFKeyword(void) const return "-"; } +string CDataType::GetSourceDataSpecString(void) +{ + switch (sm_SourceDataSpec) { + case EDataSpec::eASN: return "ncbi::EDataSpec::eASN"; + case EDataSpec::eDTD: return "ncbi::EDataSpec::eDTD"; + case EDataSpec::eXSD: return "ncbi::EDataSpec::eXSD"; + case EDataSpec::eJSON: return "ncbi::EDataSpec::eJSON"; + default: break; + } + return "ncbi::EDataSpec::eUnknown"; +} + string CDataType::GetFullName(void) const { string name; diff --git a/c++/src/serial/datatool/type.hpp b/c++/src/serial/datatool/type.hpp index 02bd4177..1844b319 100644 --- a/c++/src/serial/datatool/type.hpp +++ b/c++/src/serial/datatool/type.hpp @@ -1,7 +1,7 @@ #ifndef TYPE_HPP #define TYPE_HPP -/* $Id: type.hpp 428029 2014-02-26 19:29:54Z gouriano $ +/* $Id: type.hpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -284,11 +284,15 @@ public: static bool GetEnforcedStdXml(void) { return sm_EnforcedStdXml; } - static void SetXmlSourceSpec(bool set = true) { - sm_XmlSourceSpec = set; + static void SetSourceDataSpec(EDataSpec spec) { + sm_SourceDataSpec = spec; } - static bool GetXmlSourceSpec(void) { - return sm_XmlSourceSpec; + static EDataSpec GetSourceDataSpec(void) { + return sm_SourceDataSpec; + } + static string GetSourceDataSpecString(void); + static bool IsASNDataSpec(void) { + return sm_SourceDataSpec == EDataSpec::eASN; } virtual const char* GetDEFKeyword(void) const; @@ -364,7 +368,7 @@ private: CDataType& operator=(const CDataType&); static bool sm_EnableDTDEntities; static bool sm_EnforcedStdXml; - static bool sm_XmlSourceSpec; + static EDataSpec sm_SourceDataSpec; static set sm_SavedNames; static map sm_ClassToMember; }; diff --git a/c++/src/serial/datatool/typestr.cpp b/c++/src/serial/datatool/typestr.cpp index ccaab2d7..21189391 100644 --- a/c++/src/serial/datatool/typestr.cpp +++ b/c++/src/serial/datatool/typestr.cpp @@ -1,4 +1,4 @@ -/* $Id: typestr.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: typestr.cpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/unitype.cpp b/c++/src/serial/datatool/unitype.cpp index 7bc6270d..1337d411 100644 --- a/c++/src/serial/datatool/unitype.cpp +++ b/c++/src/serial/datatool/unitype.cpp @@ -1,4 +1,4 @@ -/* $Id: unitype.cpp 485707 2015-11-25 13:58:19Z gouriano $ +/* $Id: unitype.cpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -261,7 +261,7 @@ void CUniSequenceDataType::PrintXMLSchema(CNcbiOstream& out, if (GetDataMember()->Optional()) { tmp += " minOccurs=\"0\""; } - if (GetXmlSourceSpec()) { + if (!IsASNDataSpec()) { tmp += " maxOccurs=\"unbounded\""; } if (isNillable) { @@ -271,7 +271,7 @@ void CUniSequenceDataType::PrintXMLSchema(CNcbiOstream& out, opentag.push_back(tmp + ">"); closetag.push_front(""); - if (typeContainer && !GetXmlSourceSpec() && !GetEnforcedStdXml()) { + if (typeContainer && IsASNDataSpec() && !GetEnforcedStdXml()) { asn_container = true; opentag.push_back(""); closetag.push_front(""); @@ -289,7 +289,7 @@ void CUniSequenceDataType::PrintXMLSchema(CNcbiOstream& out, if (!isNillable) { tmp = "(&value); if ( !block ) { - if (CDataType::GetXmlSourceSpec()) { + if (!CDataType::IsASNDataSpec()) { return m_ElementType->CheckValue(value); } value.Warning("block of values expected", 18); @@ -446,7 +446,7 @@ bool CUniSequenceDataType::CheckValue(const CDataValue& value) const TObjectPtr CUniSequenceDataType::CreateDefault(const CDataValue& value) const { - if (CDataType::GetXmlSourceSpec()) { + if (!CDataType::IsASNDataSpec()) { return m_ElementType->CreateDefault(value); } NCBI_THROW(CDatatoolException,eNotImplemented, @@ -455,7 +455,7 @@ TObjectPtr CUniSequenceDataType::CreateDefault(const CDataValue& value) const string CUniSequenceDataType::GetDefaultString(const CDataValue& value) const { - if (CDataType::GetXmlSourceSpec()) { + if (!CDataType::IsASNDataSpec()) { return m_ElementType->GetDefaultString(value); } return CParent::GetDefaultString(value); diff --git a/c++/src/serial/datatool/wsdlparser.cpp b/c++/src/serial/datatool/wsdlparser.cpp index f92603c9..ab4b995c 100644 --- a/c++/src/serial/datatool/wsdlparser.cpp +++ b/c++/src/serial/datatool/wsdlparser.cpp @@ -1,4 +1,4 @@ -/* $Id: wsdlparser.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: wsdlparser.cpp 534782 2017-05-02 14:08:37Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -546,7 +546,7 @@ void WSDLParser::ParsePart(DTDElement& node) { TToken tok = GetRawAttributeSet(); if (GetAttribute("element")) { - string name( m_Value + m_PrefixToNamespace[m_ValuePrefix]); + string name( m_Value + NStr::Replace(m_PrefixToNamespace[m_ValuePrefix], ":", "/")); AddElementContent(node,name); } else { bool ok = false; diff --git a/c++/src/serial/datatool/wsdlstr.cpp b/c++/src/serial/datatool/wsdlstr.cpp index ec15ef0b..c038884a 100644 --- a/c++/src/serial/datatool/wsdlstr.cpp +++ b/c++/src/serial/datatool/wsdlstr.cpp @@ -1,4 +1,4 @@ -/* $Id: wsdlstr.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: wsdlstr.cpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/xsdlexer.cpp b/c++/src/serial/datatool/xsdlexer.cpp index ae6a7c1e..33295d42 100644 --- a/c++/src/serial/datatool/xsdlexer.cpp +++ b/c++/src/serial/datatool/xsdlexer.cpp @@ -1,4 +1,4 @@ -/* $Id: xsdlexer.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: xsdlexer.cpp 512472 2016-08-31 12:38:54Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/serial/datatool/xsdparser.cpp b/c++/src/serial/datatool/xsdparser.cpp index 12121fc7..040e340d 100644 --- a/c++/src/serial/datatool/xsdparser.cpp +++ b/c++/src/serial/datatool/xsdparser.cpp @@ -1,4 +1,4 @@ -/* $Id: xsdparser.cpp 514363 2016-09-21 15:20:35Z ivanov $ +/* $Id: xsdparser.cpp 532218 2017-04-03 14:21:54Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -590,13 +590,13 @@ string XSDParser::ParseElementContent(DTDElement* owner, int emb) ref=true; name_space = m_ResolveTypes ? m_TargetNamespace : m_PrefixToNamespace[m_ValuePrefix]; - name = m_Value + name_space; + name = m_Value + NStr::Replace(name_space, ":", "/"); } } if (GetAttribute("name")) { ref=false; name_space = m_TargetNamespace; - name = m_Value + name_space; + name = m_Value + NStr::Replace(name_space, ":", "/");; if (owner) { name = CreateTmpEmbeddedName(owner->GetName(), emb); m_MapElement[name].SetEmbedded(); diff --git a/c++/src/serial/member.cpp b/c++/src/serial/member.cpp index 2bb405fd..b2a41b6a 100644 --- a/c++/src/serial/member.cpp +++ b/c++/src/serial/member.cpp @@ -1,4 +1,4 @@ -/* $Id: member.cpp 507795 2016-07-21 17:24:14Z gouriano $ +/* $Id: member.cpp 532692 2017-04-07 17:09:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -755,6 +755,9 @@ void CMemberInfoFunctions::ReadWithSetFlagMember(CObjectIStream& in, if ( memberInfo->UpdateSetFlagNo(classPtr) ) { memberInfo->GetTypeInfo()->SetDefault( memberInfo->GetItemPtr(classPtr)); + if (memberInfo->GetDefault()) { + memberInfo->GetTypeInfo()->Assign(memberInfo->GetItemPtr(classPtr),memberInfo->GetDefault()); + } } } else { NCBI_RETHROW(e, CSerialException, eFormatError, @@ -839,6 +842,9 @@ void CMemberInfoFunctions::ReadWithDefaultMemberX(CObjectIStream& in, if ( memberInfo->UpdateSetFlagNo(classPtr) ) { memberInfo->GetTypeInfo()->SetDefault( memberInfo->GetItemPtr(classPtr)); + if (memberInfo->GetDefault()) { + memberInfo->GetTypeInfo()->Assign(memberInfo->GetItemPtr(classPtr),memberInfo->GetDefault()); + } } } else { NCBI_RETHROW(e, CSerialException, eFormatError, @@ -925,6 +931,9 @@ CMemberInfoFunctions::ReadMissingWithSetFlagMember(CObjectIStream& /*in*/, _ASSERT(memberInfo->HaveSetFlag()); if ( memberInfo->UpdateSetFlagNo(classPtr) ) { memberInfo->GetTypeInfo()->SetDefault(memberInfo->GetItemPtr(classPtr)); + if (memberInfo->GetDefault()) { + memberInfo->GetTypeInfo()->Assign(memberInfo->GetItemPtr(classPtr),memberInfo->GetDefault()); + } } } @@ -1196,9 +1205,6 @@ void CMemberInfoFunctions::ReadHookedMember(CObjectIStream& stream, TMemberIndex index = memberInfo->GetIndex(); CObjectInfo::CMemberIterator member(object, index); _ASSERT(member.Valid()); - if (memberInfo->HaveSetFlag()) { - memberInfo->UpdateSetFlagYes(classPtr); - } hook->ReadClassMember(stream, member); } else diff --git a/c++/src/serial/objectio.cpp b/c++/src/serial/objectio.cpp index 686448fa..f50a0fa7 100644 --- a/c++/src/serial/objectio.cpp +++ b/c++/src/serial/objectio.cpp @@ -1,4 +1,4 @@ -/* $Id: objectio.cpp 500790 2016-05-09 11:30:33Z ivanov $ +/* $Id: objectio.cpp 529139 2017-03-01 17:43:15Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -218,7 +218,7 @@ void CIStreamClassMemberIterator::NextClassMember(void) void CIStreamClassMemberIterator::ReadClassMember(const CObjectInfo& member) { CheckState(); - GetStream().ReadSeparateObject(member); + GetMemberInfo()->ReadMember(GetStream(), member.GetObjectPtr()); } void CIStreamClassMemberIterator::SkipClassMember(const CObjectTypeInfo& member) @@ -295,13 +295,16 @@ CIStreamContainerIterator::CIStreamContainerIterator(CObjectIStream& in, const CItemInfo* itemInfo = classType->GetItems().GetItemInfo(classType->GetItems().FirstIndex()); _ASSERT(itemInfo->GetTypeInfo()->GetTypeFamily() == eTypeFamilyContainer); + m_Container = itemInfo; containerTypeInfo = CTypeConverter::SafeCast(itemInfo->GetTypeInfo()); in.PushFrame(CObjectStackFrame::eFrameNamed, m_ContainerType.GetTypeInfo()); in.BeginNamedType(m_ContainerType.GetTypeInfo()); } else { + m_Container = nullptr; containerTypeInfo = GetContainerType().GetContainerTypeInfo(); } + m_ContainerTypeInfo = containerTypeInfo; in.PushFrame(CObjectStackFrame::eFrameArray, containerTypeInfo); in.BeginContainer(containerTypeInfo); @@ -387,6 +390,15 @@ void CIStreamContainerIterator::BeginElementData(const CObjectTypeInfo& ) BeginElementData(); } +CObjectInfo CIStreamContainerIterator::ReadElement(TObjectPtr container) +{ + BeginElementData(GetElementType()); + TObjectPtr cont = m_Container ? m_Container->GetItemPtr(container) : container; + TObjectPtr elem = m_ContainerTypeInfo->AddElement(cont, GetStream()); + NextElement(); + return CObjectInfo(elem, m_ElementTypeInfo); +} + void CIStreamContainerIterator::ReadElement(const CObjectInfo& element) { BeginElementData(element); diff --git a/c++/src/serial/objistr.cpp b/c++/src/serial/objistr.cpp index 37102d27..da1d75f6 100644 --- a/c++/src/serial/objistr.cpp +++ b/c++/src/serial/objistr.cpp @@ -1,4 +1,4 @@ -/* $Id: objistr.cpp 500790 2016-05-09 11:30:33Z ivanov $ +/* $Id: objistr.cpp 528362 2017-02-22 17:18:08Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -569,12 +569,7 @@ bool CObjectIStream::EndOfData(void) if (GetFailFlags() & failure || m_Input.EndOfData()) { return true; } - try { - m_Input.PeekChar(); - } catch (...) { - return true; - } - return false; + return !m_Input.HasMore(); } void CObjectIStream::HandleEOF(CEofException& expt) @@ -1079,8 +1074,7 @@ void CObjectIStream::ReadClassMember(const CObjectInfo::CMemberIterator& member) { const CMemberInfo* memberInfo = member.GetMemberInfo(); TObjectPtr classPtr = member.GetClassObject().GetObjectPtr(); - ReadObject(memberInfo->GetMemberPtr(classPtr), - memberInfo->GetTypeInfo()); + memberInfo->DefaultReadMember(*this, classPtr); } void CObjectIStream::ReadChoiceVariant(const CObjectInfoCV& object) diff --git a/c++/src/serial/objistrasn.cpp b/c++/src/serial/objistrasn.cpp index 69b2402f..2c2a2722 100644 --- a/c++/src/serial/objistrasn.cpp +++ b/c++/src/serial/objistrasn.cpp @@ -1,4 +1,4 @@ -/* $Id: objistrasn.cpp 501579 2016-05-17 14:01:10Z gouriano $ +/* $Id: objistrasn.cpp 534119 2017-04-24 17:07:34Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -522,6 +522,7 @@ void CObjectIStreamAsn::ReadAnyContent(string& value) void CObjectIStreamAsn::ReadAnyContentObject(CAnyContentObject& obj) { + obj.SetName(ReadMemberId(SkipWhiteSpace())); string value; ReadAnyContent(value); obj.SetValue(CUtf8::AsUTF8(value,eEncoding_UTF8)); diff --git a/c++/src/serial/objistrasnb.cpp b/c++/src/serial/objistrasnb.cpp index 0727895e..2099fc6a 100644 --- a/c++/src/serial/objistrasnb.cpp +++ b/c++/src/serial/objistrasnb.cpp @@ -1,4 +1,4 @@ -/* $Id: objistrasnb.cpp 507795 2016-07-21 17:24:14Z gouriano $ +/* $Id: objistrasnb.cpp 512957 2016-09-06 14:50:26Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1079,7 +1079,7 @@ CObjectIStreamAsnBinary::BeginClassMember(const CClassTypeInfo* classType) m_SkipNextTag = false; return index; } - bool need_eoc = GetTagConstructed(first_tag_byte) != ePrimitive; + bool need_eoc = IsTagConstructed(first_tag_byte); if (need_eoc) { ExpectIndefiniteLength(); } @@ -1133,7 +1133,7 @@ CObjectIStreamAsnBinary::BeginClassMember(const CClassTypeInfo* classType, m_SkipNextTag = false; return index; } - bool need_eoc = GetTagConstructed(first_tag_byte) != ePrimitive; + bool need_eoc = IsTagConstructed(first_tag_byte); if (need_eoc) { ExpectIndefiniteLength(); } @@ -1316,7 +1316,7 @@ CObjectIStreamAsnBinary::BeginChoiceVariant(const CChoiceTypeInfo* choiceType) m_SkipNextTag = false; return index; } - bool need_eoc = GetTagConstructed(first_tag_byte) != ePrimitive; + bool need_eoc = IsTagConstructed(first_tag_byte); if (need_eoc) { ExpectIndefiniteLength(); } @@ -1502,6 +1502,7 @@ void CObjectIStreamAsnBinary::ReadAnyContentObject(CAnyContentObject& ) void CObjectIStreamAsnBinary::SkipAnyContent(void) { +#if 0 TByte byte = PeekAnyTagFirstByte(); if ( GetTagConstructed(byte) && PeekIndefiniteLength() ) { ExpectIndefiniteLength(); @@ -1537,6 +1538,29 @@ void CObjectIStreamAsnBinary::SkipAnyContent(void) } } } +#else + int depth = 0; + do { + if ( depth != 0 && !HaveMoreElements() ) { + ExpectEndOfContent(); + --depth; + } + else { + TByte byte = PeekAnyTagFirstByte(); + if ( IsTagConstructed(byte) && PeekIndefiniteLength() ) { + ExpectIndefiniteLength(); + ++depth; + } + else { + size_t length = ReadLength(); + if (length) { + SkipBytes(length); + } + EndOfTag(); + } + } + } while (depth != 0); +#endif } set @@ -1624,7 +1648,7 @@ void CObjectIStreamAsnBinary::GetTagPattern(vector& pattern, size_t max_len pattern.push_back((int)(byte & CAsnBinaryDefs::eTagValueMask)); } - if ( GetTagConstructed(byte) && PeekIndefiniteLength() ) { + if ( IsTagConstructed(byte) && PeekIndefiniteLength() ) { ExpectIndefiniteLength(); } else { @@ -1663,7 +1687,7 @@ void CObjectIStreamAsnBinary::GetTagPattern(vector& pattern, size_t max_len } else { memtag = byte; } - if ( GetTagConstructed(byte) && PeekIndefiniteLength() ) { + if ( IsTagConstructed(byte) && PeekIndefiniteLength() ) { ExpectIndefiniteLength(); ++depth; } @@ -2004,7 +2028,7 @@ bool CObjectIStreamAsnBinary::SkipRealValue(void) PeekTagByte(1) == eZeroLengthByte ) return false; TByte byte = PeekAnyTagFirstByte(); - if ( GetTagConstructed(byte) ) { + if ( IsTagConstructed(byte) ) { // constructed ExpectIndefiniteLength(); while ( SkipRealValue() ) diff --git a/c++/src/serial/objistrjson.cpp b/c++/src/serial/objistrjson.cpp index 213abcd0..6ace3d00 100644 --- a/c++/src/serial/objistrjson.cpp +++ b/c++/src/serial/objistrjson.cpp @@ -1,4 +1,4 @@ -/* $Id: objistrjson.cpp 501456 2016-05-16 15:12:46Z ivanov $ +/* $Id: objistrjson.cpp 534119 2017-04-24 17:07:34Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -53,9 +53,10 @@ CObjectIStreamJson::CObjectIStreamJson(void) m_ExpectValue(false), m_GotNameless(false), m_Closing(0), - m_StringEncoding( eEncoding_Unknown ), + m_StringEncoding( eEncoding_UTF8 ), m_BinaryFormat(eDefault) { + m_Utf8Pos = m_Utf8Buf.begin(); } CObjectIStreamJson::CObjectIStreamJson(CNcbiIstream& in, EOwnership deleteIn) @@ -65,9 +66,10 @@ CObjectIStreamJson::CObjectIStreamJson(CNcbiIstream& in, EOwnership deleteIn) m_ExpectValue(false), m_GotNameless(false), m_Closing(0), - m_StringEncoding( eEncoding_Unknown ), + m_StringEncoding( eEncoding_UTF8 ), m_BinaryFormat(eDefault) { + m_Utf8Pos = m_Utf8Buf.begin(); Open(in, deleteIn); } @@ -83,6 +85,8 @@ void CObjectIStreamJson::ResetState(void) } m_LastTag.clear(); m_RejectedTag.clear(); + m_Utf8Buf.clear(); + m_Utf8Pos = m_Utf8Buf.begin(); } string CObjectIStreamJson::GetPosition(void) const @@ -196,6 +200,11 @@ void CObjectIStreamJson::UnexpectedMember(const CTempString& id, ThrowError(fFormatError, message); } +template inline +Type CObjectIStreamJson::x_UseMemberDefault(void) +{ + return GetMemberDefault() ? CTypeConverter::Get(GetMemberDefault()) : Type(); +} int CObjectIStreamJson::ReadEscapedChar(bool* encoded /*=0*/) { @@ -230,19 +239,48 @@ int CObjectIStreamJson::ReadEscapedChar(bool* encoded /*=0*/) return c & 0xFF; } -char CObjectIStreamJson::ReadEncodedChar( - EStringType type /*= eStringTypeVisible*/, bool* encoded /*=0*/) +char CObjectIStreamJson::ReadEncodedChar(EStringType type, bool& encoded) { EEncoding enc_out( type == eStringTypeUTF8 ? eEncoding_UTF8 : m_StringEncoding); EEncoding enc_in(eEncoding_UTF8); - if (enc_in != enc_out && enc_out != eEncoding_Unknown) { - int c = ReadEscapedChar(encoded); - TUnicodeSymbol chU = ReadUtf8Char((char)c); - Uint1 ch = CUtf8::SymbolToChar(chU, enc_out); - return ch & 0xFF; + if (enc_out == eEncoding_UTF8 && + !m_Utf8Buf.empty() && m_Utf8Pos != m_Utf8Buf.end()) { + if (++m_Utf8Pos != m_Utf8Buf.end()) { + return *m_Utf8Pos & 0xFF; + } else { + m_Utf8Buf.clear(); + } + } + int c = ReadEscapedChar(&encoded); + if (enc_out != eEncoding_Unknown) { + if (encoded) { + TUnicodeSymbol chU = c; + if (enc_out == eEncoding_UTF8) { + m_Utf8Buf = CUtf8::AsUTF8( &chU, 1); + m_Utf8Pos = m_Utf8Buf.begin(); + return *m_Utf8Pos & 0xFF; + } else { + return CUtf8::SymbolToChar( chU, enc_out); + } + } + if (enc_in != enc_out) { + if (enc_out != eEncoding_UTF8) { + TUnicodeSymbol chU = enc_in == eEncoding_UTF8 ? + ReadUtf8Char((char)c) : CUtf8::CharToSymbol((char)c, enc_in); + Uint1 ch = CUtf8::SymbolToChar( chU, enc_out); + return ch & 0xFF; + } + if ((c & 0x80) == 0) { + return c; + } + char ch = (char)c; + m_Utf8Buf = CUtf8::AsUTF8( CTempString(&ch,1), enc_in); + m_Utf8Pos = m_Utf8Buf.begin(); + return *m_Utf8Pos & 0xFF; + } } - return (char)ReadEscapedChar(encoded); + return (char)c; } TUnicodeSymbol CObjectIStreamJson::ReadUtf8Char(char c) @@ -264,8 +302,8 @@ string CObjectIStreamJson::x_ReadString(EStringType type) Expect('\"',true); string str; for (;;) { - bool encoded; - char c = ReadEncodedChar(type, &encoded); + bool encoded = false; + char c = ReadEncodedChar(type, encoded); if (!encoded) { if (c == '\r' || c == '\n') { ThrowError(fFormatError, "end of line: expected '\"'"); @@ -283,13 +321,12 @@ string CObjectIStreamJson::x_ReadString(EStringType type) return str; } -string CObjectIStreamJson::x_ReadData(EStringType type /*= eStringTypeVisible*/) +void CObjectIStreamJson::x_ReadData(string& str, EStringType type /*= eStringTypeVisible*/) { SkipWhiteSpace(); - string str; for (;;) { - bool encoded; - char c = ReadEncodedChar(type, &encoded); + bool encoded = false; + char c = ReadEncodedChar(type, encoded); if (!encoded && strchr(",]} \r\n", c)) { m_Input.UngetChar(c); break; @@ -301,16 +338,20 @@ string CObjectIStreamJson::x_ReadData(EStringType type /*= eStringTypeVisible*/) } } str.reserve(str.size()); - return str; } -string CObjectIStreamJson::x_ReadDataAndCheck(EStringType type) +bool CObjectIStreamJson::x_ReadDataAndCheck(string& str, EStringType type) { - string d(x_ReadData(type)); - if (d == "null") { - NCBI_THROW(CSerialException,eNullValue, kEmptyStr); + x_ReadData(str, type); + if (str == "null") { + if ((ExpectSpecialCase() & CObjectIStream::eReadAsNil)!=0) { + SetSpecialCaseUsed(CObjectIStream::eReadAsNil); + return false; + } else { + NCBI_THROW(CSerialException,eNullValue, kEmptyStr); + } } - return d; + return true; } void CObjectIStreamJson::x_SkipData(void) @@ -318,8 +359,8 @@ void CObjectIStreamJson::x_SkipData(void) m_ExpectValue = false; char to = GetChar(true); for (;;) { - bool encoded; - char c = ReadEncodedChar(eStringTypeUTF8, &encoded); + bool encoded = false; + char c = ReadEncodedChar(eStringTypeUTF8, encoded); if (!encoded) { if (to == '\"') { if (c == to) { @@ -399,6 +440,18 @@ bool CObjectIStreamJson::NextElement(void) string CObjectIStreamJson::ReadFileHeader(void) { + { + char c = m_Input.PeekChar(); + if ((unsigned char)c == 0xEF) { + if ((unsigned char)m_Input.PeekChar(1) == 0xBB && + (unsigned char)m_Input.PeekChar(2) == 0xBF) { + m_Input.SkipChars(3); + } + } + } + if (TopFrame().GetTypeInfo()->GetDataSpec() == EDataSpec::eJSON) { + return kEmptyStr; + } m_FileHeader = true; StartBlock('{'); string str( ReadKey()); @@ -427,7 +480,8 @@ void CObjectIStreamJson::EndOfRead(void) bool CObjectIStreamJson::ReadBool(void) { - return NStr::StringToBool( x_ReadDataAndCheck()); + string str; + return x_ReadDataAndCheck(str) ? NStr::StringToBool(str) : x_UseMemberDefault(); } void CObjectIStreamJson::SkipBool(void) @@ -437,7 +491,8 @@ void CObjectIStreamJson::SkipBool(void) char CObjectIStreamJson::ReadChar(void) { - return x_ReadDataAndCheck().at(0); + string str; + return x_ReadDataAndCheck(str) ? str.at(0) : x_UseMemberDefault(); } void CObjectIStreamJson::SkipChar(void) @@ -447,12 +502,14 @@ void CObjectIStreamJson::SkipChar(void) Int8 CObjectIStreamJson::ReadInt8(void) { - return NStr::StringToInt8( x_ReadDataAndCheck()); + string str; + return x_ReadDataAndCheck(str) ? NStr::StringToInt8(str) : x_UseMemberDefault(); } Uint8 CObjectIStreamJson::ReadUint8(void) { - return NStr::StringToUInt8( x_ReadDataAndCheck()); + string str; + return x_ReadDataAndCheck(str) ? NStr::StringToUInt8(str) : x_UseMemberDefault(); } void CObjectIStreamJson::SkipSNumber(void) @@ -468,7 +525,8 @@ void CObjectIStreamJson::SkipUNumber(void) double CObjectIStreamJson::ReadDouble(void) { char* endptr; - return NStr::StringToDoublePosix( x_ReadDataAndCheck().c_str(), &endptr, NStr::fDecimalPosixFinite); + string str; + return x_ReadDataAndCheck(str) ? NStr::StringToDoublePosix( str.c_str(), &endptr, NStr::fDecimalPosixFinite) : x_UseMemberDefault(); } void CObjectIStreamJson::SkipFNumber(void) @@ -486,6 +544,10 @@ void CObjectIStreamJson::ReadString(string& s, m_Input.PeekChar(3) == 'l') { m_ExpectValue = false; m_Input.SkipChars(4); + if ((ExpectSpecialCase() & CObjectIStream::eReadAsNil)!=0) { + SetSpecialCaseUsed(CObjectIStream::eReadAsNil); + return; + } NCBI_THROW(CSerialException,eNullValue, kEmptyStr); } } @@ -500,7 +562,8 @@ void CObjectIStreamJson::SkipString(EStringType /*type*/) void CObjectIStreamJson::ReadNull(void) { if (m_ExpectValue) { - x_ReadData(); + string str; + x_ReadData(str); } } @@ -521,6 +584,8 @@ void CObjectIStreamJson::ReadAnyContentObject(CAnyContentObject& obj) m_RejectedTag.erase(); } else if (!StackIsEmpty() && TopFrame().HasMemberId()) { obj.SetName( TopFrame().GetMemberId().GetName()); + } else { + obj.SetName( ReadKey()); } if (PeekChar(true) == '{') { @@ -543,7 +608,7 @@ void CObjectIStreamJson::ReadAnyContentObject(CAnyContentObject& obj) if (PeekChar(true) == '\"') { value = ReadValue(eStringTypeUTF8); } else { - value = x_ReadData(); + x_ReadData(value); } obj.SetValue(CUtf8::AsUTF8(value,eEncoding_UTF8)); } @@ -668,13 +733,24 @@ void CObjectIStreamJson::SkipClassSequential(const CClassTypeInfo* classType) #endif // container -void CObjectIStreamJson::BeginContainer(const CContainerTypeInfo* /*containerType*/) +void CObjectIStreamJson::BeginContainer(const CContainerTypeInfo* containerType) { + CObjectTypeInfo type(GetRealTypeInfo(containerType->GetElementType())); + if (type.GetTypeFamily() == eTypeFamilyPrimitive && type.GetPrimitiveValueType() == ePrimitiveValueAny) { + TopFrame().SetNotag(); + m_BlockStart = true; + m_ExpectValue = false; + return; + } StartBlock('['); } void CObjectIStreamJson::EndContainer(void) { + if (TopFrame().GetNotag()) { + TopFrame().SetNotag(false); + return; + } EndBlock(']'); } @@ -781,6 +857,12 @@ TMemberIndex CObjectIStreamJson::BeginClassMember(const CClassTypeInfo* classTyp bool deep = false; TMemberIndex ind = FindDeep(classType->GetMembers(), tagName, deep); + if (ind == kInvalidMember) { + if (classType->GetMembers().GetItemInfo(last)->GetId().HasAnyContent()) { + UndoClassMember(); + return last; + } + } /* skipping unknown members is not present here this method has to do with random order of members, for example in XML attribute list @@ -1113,7 +1195,8 @@ CObjectIStream::EPointerType CObjectIStreamJson::ReadPointerType(void) { char c = PeekChar(true); if (c == 'n') { - string s = x_ReadData(); + string s; + x_ReadData(s); if (s != "null") { ThrowError(fFormatError, "null expected"); } diff --git a/c++/src/serial/objistrxml.cpp b/c++/src/serial/objistrxml.cpp index 7a8273fb..c0ea6475 100644 --- a/c++/src/serial/objistrxml.cpp +++ b/c++/src/serial/objistrxml.cpp @@ -1,4 +1,4 @@ -/* $Id: objistrxml.cpp 501456 2016-05-16 15:12:46Z ivanov $ +/* $Id: objistrxml.cpp 534803 2017-05-02 16:42:54Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -59,7 +59,7 @@ CObjectIStreamXml::CObjectIStreamXml(void) m_TagState(eTagOutside), m_Attlist(false), m_StdXml(false), m_Doctype_found(false), m_IsNil(false), m_Encoding( eEncoding_Unknown ), - m_StringEncoding( eEncoding_Unknown ), + m_StringEncoding( eEncoding_UTF8 ), m_SkipNextTag(false) { m_Utf8Pos = m_Utf8Buf.begin(); @@ -70,7 +70,7 @@ CObjectIStreamXml::CObjectIStreamXml(CNcbiIstream& in, EOwnership deleteIn) m_TagState(eTagOutside), m_Attlist(false), m_StdXml(false), m_Doctype_found(false), m_IsNil(false), m_Encoding( eEncoding_Unknown ), - m_StringEncoding( eEncoding_Unknown ), + m_StringEncoding( eEncoding_UTF8 ), m_SkipNextTag(false) { m_Utf8Pos = m_Utf8Buf.begin(); @@ -758,7 +758,7 @@ int CObjectIStreamXml::ReadEscapedChar(char endingChar, bool* encoded) "invalid symbol in char reference"); } while ( p < end ); } - return v & 0xFF; + return v; } else { CTempString e(p, offset); @@ -799,12 +799,12 @@ inline int CObjectIStreamXml::x_VerifyChar(int x) { ReplaceVisibleChar((char)x, x_FixCharsMethod(), this, kEmptyStr) : x; } inline -int CObjectIStreamXml::ReadEncodedChar(char endingChar, EStringType type, bool* encoded) +int CObjectIStreamXml::ReadEncodedChar(char endingChar, EStringType type, bool& encoded) { return x_VerifyChar(x_ReadEncodedChar(endingChar,type,encoded)); } -int CObjectIStreamXml::x_ReadEncodedChar(char endingChar, EStringType type, bool* encoded) +int CObjectIStreamXml::x_ReadEncodedChar(char endingChar, EStringType type, bool& encoded) { EEncoding enc_out( type == eStringTypeUTF8 ? eEncoding_UTF8 : m_StringEncoding); EEncoding enc_in(m_Encoding == eEncoding_Unknown ? eEncoding_UTF8 : m_Encoding); @@ -814,29 +814,41 @@ int CObjectIStreamXml::x_ReadEncodedChar(char endingChar, EStringType type, bool if (++m_Utf8Pos != m_Utf8Buf.end()) { return *m_Utf8Pos & 0xFF; } else { - m_Utf8Buf.erase(); + m_Utf8Buf.clear(); } } - if (enc_in != enc_out && enc_out != eEncoding_Unknown) { - int c = ReadEscapedChar(endingChar, encoded); - if (c < 0) { - return c; - } - if (enc_out != eEncoding_UTF8) { - TUnicodeSymbol chU = enc_in == eEncoding_UTF8 ? - ReadUtf8Char((char)c) : CUtf8::CharToSymbol((char)c, enc_in); - Uint1 ch = CUtf8::SymbolToChar( chU, enc_out); - return ch & 0xFF; + int c = ReadEscapedChar(endingChar, &encoded); + if (c < 0) { + return c; + } + if (enc_out != eEncoding_Unknown) { + if (encoded) { + TUnicodeSymbol chU = c; + if (enc_out == eEncoding_UTF8) { + m_Utf8Buf = CUtf8::AsUTF8( &chU, 1); + m_Utf8Pos = m_Utf8Buf.begin(); + return *m_Utf8Pos & 0xFF; + } else { + return CUtf8::SymbolToChar( chU, enc_out); + } } - if ((c & 0x80) == 0) { - return c; + if (enc_in != enc_out) { + if (enc_out != eEncoding_UTF8) { + TUnicodeSymbol chU = enc_in == eEncoding_UTF8 ? + ReadUtf8Char((char)c) : CUtf8::CharToSymbol((char)c, enc_in); + Uint1 ch = CUtf8::SymbolToChar( chU, enc_out); + return ch & 0xFF; + } + if ((c & 0x80) == 0) { + return c; + } + char ch = (char)c; + m_Utf8Buf = CUtf8::AsUTF8( CTempString(&ch,1), enc_in); + m_Utf8Pos = m_Utf8Buf.begin(); + return *m_Utf8Pos & 0xFF; } - char ch = (char)c; - m_Utf8Buf = CUtf8::AsUTF8( CTempString(&ch,1), enc_in); - m_Utf8Pos = m_Utf8Buf.begin(); - return *m_Utf8Pos & 0xFF; } - return ReadEscapedChar(endingChar, encoded); + return c; } TUnicodeSymbol CObjectIStreamXml::ReadUtf8Char(char c) @@ -868,8 +880,9 @@ void CObjectIStreamXml::ReadAttributeValue(string& value, bool skipClosing) if ( startChar != '\'' && startChar != '\"' ) ThrowError(fFormatError, "attribute value must start with ' or \""); m_Input.SkipChar(); + bool encoded = false; for ( ;; ) { - int c = ReadEncodedChar(startChar,eStringTypeUTF8); + int c = ReadEncodedChar(startChar,eStringTypeUTF8,encoded); if ( c < 0 ) break; value += char(c); @@ -924,7 +937,7 @@ bool CObjectIStreamXml::ReadBool(void) } } if (!haveattr) { - ReadTagData(sValue); + ReadWord(sValue); } NStr::TruncateSpacesInPlace(sValue); @@ -998,7 +1011,7 @@ double CObjectIStreamXml::ReadDouble(void) return x_UseMemberDefault(); } string s; - ReadTagData(s); + ReadWord(s); char* endptr; double result = NStr::StringToDoublePosix(s.c_str(), &endptr, NStr::fDecimalPosixFinite); while (IsWhiteSpace(*endptr)) { @@ -1212,7 +1225,15 @@ void CObjectIStreamXml::ReadString(string& str, EStringType type) if (EndOpeningTagSelfClosed()) { return; } +#if 0 + if (TopFrame().GetNotag()) { + ReadWord(str, type); + } else { + ReadTagData(str, type); + } +#else ReadTagData(str, type); +#endif } char* CObjectIStreamXml::ReadCString(void) @@ -1269,7 +1290,7 @@ void CObjectIStreamXml::ReadTagData(string& str, EStringType type) bool CR = false; try { for ( ;; ) { - int c = ReadEncodedChar(m_Attlist ? '\"' : '<', type, &encoded); + int c = ReadEncodedChar(m_Attlist ? '\"' : '<', type, encoded); if ( c < 0 ) { if (m_Attlist || !ReadCDSection(str)) { break; @@ -1301,15 +1322,44 @@ void CObjectIStreamXml::ReadTagData(string& str, EStringType type) str.reserve(str.size()); } +void CObjectIStreamXml::ReadWord(string& str, EStringType type) +{ + BeginData(); + bool encoded = false; + SkipWS(); + try { + for ( ;; ) { + int c = ReadEncodedChar(m_Attlist ? '\"' : '<', type, encoded); + if ( c < 0 || IsWhiteSpace((char)c)) { + break; + } + str += (char)c; + } + } catch (CEofException&) { + } + str.reserve(str.size()); +} + TEnumValueType CObjectIStreamXml::ReadEnum(const CEnumeratedTypeValues& values) { + TEnumValueType value; + bool valueonly = GetRecentTypeInfo() && GetRecentTypeInfo()->GetDataSpec() == EDataSpec::eJSON; + if (valueonly) { + if (values.IsInteger()) { + value = ReadInt4(); + } else { + string str; + ReadString(str); + value = values.FindValue( str); + } + return value; + } const string& enumName = values.GetName(); if ( !m_SkipNextTag && !enumName.empty() ) { // global enum OpenTag(enumName); _ASSERT(InsideOpeningTag()); } - TEnumValueType value; if ( InsideOpeningTag() ) { // try to read attribute 'value' if ( IsEndOfTagChar( SkipWS()) ) { @@ -1702,8 +1752,8 @@ bool CObjectIStreamXml::HasMoreElements(TTypeInfo elementType) } else { tagName = ReadName(BeginOpeningTag()); UndoClassMember(); - bool res = (tagName == m_LastPrimitive || - tagName == type->GetName() || + bool res = (m_LastPrimitive.empty() || + tagName == m_LastPrimitive || tagName == type->GetName() || CObjectTypeInfo(type).GetPrimitiveValueType() == ePrimitiveValueAny); if (!res) { m_LastPrimitive.erase(); @@ -1964,42 +2014,6 @@ void CObjectIStreamXml::CheckStdXml(const CClassTypeInfoBase* classType) m_StdXml = classType->GetItems().GetItemInfo(first)->GetId().HaveNoPrefix(); } -TTypeInfo CObjectIStreamXml::GetRealTypeInfo(TTypeInfo typeInfo) -{ - if (typeInfo->GetTypeFamily() == eTypeFamilyPointer) { - const CPointerTypeInfo* ptr = - dynamic_cast(typeInfo); - if (ptr) { - typeInfo = ptr->GetPointedType(); - } - } - return typeInfo; -} - -ETypeFamily CObjectIStreamXml::GetRealTypeFamily(TTypeInfo typeInfo) -{ - return GetRealTypeInfo( typeInfo )->GetTypeFamily(); -} - -TTypeInfo CObjectIStreamXml::GetContainerElementTypeInfo(TTypeInfo typeInfo) -{ - typeInfo = GetRealTypeInfo( typeInfo ); - _ASSERT(typeInfo->GetTypeFamily() == eTypeFamilyContainer); - const CContainerTypeInfo* ptr = - dynamic_cast(typeInfo); - return GetRealTypeInfo(ptr->GetElementType()); -} - -ETypeFamily CObjectIStreamXml::GetContainerElementTypeFamily(TTypeInfo typeInfo) -{ - typeInfo = GetRealTypeInfo( typeInfo ); - _ASSERT(typeInfo->GetTypeFamily() == eTypeFamilyContainer); - const CContainerTypeInfo* ptr = - dynamic_cast(typeInfo); - return GetRealTypeFamily(ptr->GetElementType()); -} - - void CObjectIStreamXml::BeginClass(const CClassTypeInfo* classInfo) { if (m_SkipNextTag) { diff --git a/c++/src/serial/objostrasn.cpp b/c++/src/serial/objostrasn.cpp index 24338163..77c7a0ac 100644 --- a/c++/src/serial/objostrasn.cpp +++ b/c++/src/serial/objostrasn.cpp @@ -1,4 +1,4 @@ -/* $Id: objostrasn.cpp 501450 2016-05-16 14:53:19Z gouriano $ +/* $Id: objostrasn.cpp 534119 2017-04-24 17:07:34Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -279,11 +279,17 @@ void CObjectOStreamAsn::WriteNull(void) m_Output.PutString("NULL"); } -void CObjectOStreamAsn::WriteAnyContentObject(const CAnyContentObject& ) +void CObjectOStreamAsn::WriteAnyContentObject(const CAnyContentObject& obj) { +#if 0 ThrowError(fNotImplemented, "CObjectOStreamAsn::WriteAnyContentObject: " "unable to write AnyContent object in ASN"); +#else + m_Output.PutString(obj.GetName()); + m_Output.PutChar(' '); + m_Output.PutString(obj.GetValue()); +#endif } void CObjectOStreamAsn::CopyAnyContentObject(CObjectIStream& ) diff --git a/c++/src/serial/objostrasnb.cpp b/c++/src/serial/objostrasnb.cpp index 3b02f238..246f0706 100644 --- a/c++/src/serial/objostrasnb.cpp +++ b/c++/src/serial/objostrasnb.cpp @@ -1,4 +1,4 @@ -/* $Id: objostrasnb.cpp 507795 2016-07-21 17:24:14Z gouriano $ +/* $Id: objostrasnb.cpp 525716 2017-01-26 20:47:16Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -146,7 +146,7 @@ void CObjectOStreamAsnBinary::SetTagLength(size_t length) (m_CurrentTagLimit != 0 && limit > m_CurrentTagLimit) ) ThrowError(fIllegalCall, "tag will overflow enclosing tag"); m_CurrentTagLimit = limit; - if ( GetTagConstructed(m_CurrentTagCode) ) // constructed + if ( IsTagConstructed(m_CurrentTagCode) ) // constructed m_CurrentTagState = eTagStart; else m_CurrentTagState = eData; @@ -180,7 +180,7 @@ void CObjectOStreamAsnBinary::WriteByte(Uint1 byte) EndTag(); } else if ( byte == 0x80 ) { - if ( !GetTagConstructed(m_CurrentTagCode) ) { + if ( !IsTagConstructed(m_CurrentTagCode) ) { ThrowError(fIllegalCall, "cannot use indefinite form for primitive tag"); } @@ -566,10 +566,26 @@ void CObjectOStreamAsnBinary::WriteNumberValue(Int8 data) // three bytes length = 3; } - else if ( data >= Int8(-0x7fffffffL-1) && data <= Int8(0x7fffffffL) ) { + else if ( data >= NCBI_CONST_INT8(-0x80000000) && + data <= NCBI_CONST_INT8( 0x7fffffff) ) { // four bytes length = 4; } + else if ( data >= NCBI_CONST_INT8(-0x8000000000) && + data <= NCBI_CONST_INT8( 0x7fffffffff) ) { + // four bytes + length = 5; + } + else if ( data >= NCBI_CONST_INT8(-0x800000000000) && + data <= NCBI_CONST_INT8( 0x7fffffffffff) ) { + // four bytes + length = 6; + } + else if ( data >= NCBI_CONST_INT8(-0x80000000000000) && + data <= NCBI_CONST_INT8( 0x7fffffffffffff) ) { + // four bytes + length = 7; + } else { // full length signed length = sizeof(data); @@ -632,6 +648,18 @@ void CObjectOStreamAsnBinary::WriteNumberValue(Uint8 data) // four bytes length = 4; } + else if ( data <= NCBI_CONST_UINT8(0x7fffffffff) ) { + length = 5; + } + else if ( data <= NCBI_CONST_UINT8(0x7fffffffffff) ) { + length = 6; + } + else if ( data <= NCBI_CONST_UINT8(0x7fffffffffffff) ) { + length = 7; + } + else if ( data <= NCBI_CONST_UINT8(0x7fffffffffffffff) ) { + length = 8; + } else { // check for high bit to avoid storing unsigned data as negative if ( (data & (Uint8(1) << (sizeof(data) * 8 - 1))) != 0 ) { diff --git a/c++/src/serial/objostrjson.cpp b/c++/src/serial/objostrjson.cpp index 0e9b2fe0..89d5a1fa 100644 --- a/c++/src/serial/objostrjson.cpp +++ b/c++/src/serial/objostrjson.cpp @@ -1,4 +1,4 @@ -/* $Id: objostrjson.cpp 501456 2016-05-16 15:12:46Z ivanov $ +/* $Id: objostrjson.cpp 534119 2017-04-24 17:07:34Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -67,9 +67,10 @@ CObjectOStream* CObjectOStream::OpenObjectOStreamJson(CNcbiOstream& out, CObjectOStreamJson::CObjectOStreamJson(CNcbiOstream& out, bool deleteOut) : CObjectOStream(eSerial_Json, out, deleteOut ? eTakeOwnership : eNoOwnership), + m_FileHeader(false), m_BlockStart(false), m_ExpectValue(false), - m_StringEncoding(eEncoding_Unknown), + m_StringEncoding(eEncoding_UTF8), m_BinaryFormat(eDefault), m_WrapAt(0) { @@ -79,9 +80,10 @@ CObjectOStreamJson::CObjectOStreamJson(CNcbiOstream& out, bool deleteOut) CObjectOStreamJson::CObjectOStreamJson(CNcbiOstream& out, EOwnership deleteOut) : CObjectOStream(eSerial_Json, out, deleteOut), + m_FileHeader(false), m_BlockStart(false), m_ExpectValue(false), - m_StringEncoding(eEncoding_Unknown), + m_StringEncoding(eEncoding_UTF8), m_BinaryFormat(eDefault), m_WrapAt(0) { @@ -135,16 +137,25 @@ void CObjectOStreamJson::WriteFileHeader(TTypeInfo type) if (!m_JsonpPrefix.empty() || !m_JsonpSuffix.empty()) { m_Output.PutString(m_JsonpPrefix); } - StartBlock(); - if (!type->GetName().empty()) { - m_Output.PutEol(); - WriteKey(type->GetName()); + if (type->GetDataSpec() != EDataSpec::eJSON) { + m_FileHeader = true; + StartBlock(); + if (!type->GetName().empty()) { + m_Output.PutEol(); + WriteKey(type->GetName()); + } } } void CObjectOStreamJson::EndOfWrite(void) { - EndBlock(); + if (m_FileHeader) { + EndBlock(); + m_FileHeader = false; + } else { + m_BlockStart = false; + m_ExpectValue = false; + } if (!m_JsonpPrefix.empty() || !m_JsonpSuffix.empty()) { m_Output.PutString(m_JsonpSuffix); } @@ -244,8 +255,11 @@ void CObjectOStreamJson::CopyStringStore(CObjectIStream& in) void CObjectOStreamJson::WriteNullPointer(void) { + CObjectStackFrame::EFrameType ftype = TopFrame().GetFrameType(); if (m_ExpectValue || - TopFrame().GetFrameType() == CObjectStackFrame::eFrameArrayElement) { + ftype == CObjectStackFrame::eFrameArrayElement || + ftype == CObjectStackFrame::eFrameClassMember || + ftype == CObjectStackFrame::eFrameChoiceVariant) { WriteKeywordValue("null"); } } @@ -291,7 +305,6 @@ void CObjectOStreamJson::WriteAnyContentObject(const CAnyContentObject& obj) ThrowError(fInvalidData, "AnyContent object must have name"); } } - NextElement(); WriteKey(obj_name); const vector& attlist = obj.GetAttributes(); if (attlist.empty()) { @@ -402,6 +415,16 @@ bool CObjectOStreamJson::WriteClassMember(const CMemberId& memberId, return CObjectOStream::WriteClassMember(memberId,buffer); } +void CObjectOStreamJson::WriteClassMemberSpecialCase( + const CMemberId& memberId, TTypeInfo memberType, + TConstObjectPtr memberPtr, ESpecialCaseWrite how) +{ + if (how == eWriteAsNil) { + BeginClassMember(memberId); + WriteKeywordValue("null"); + EndClassMember(); + } +} void CObjectOStreamJson::BeginNamedType(TTypeInfo namedTypeInfo) { @@ -414,13 +437,24 @@ void CObjectOStreamJson::EndNamedType(void) } -void CObjectOStreamJson::BeginContainer(const CContainerTypeInfo* /*containerType*/) +void CObjectOStreamJson::BeginContainer(const CContainerTypeInfo* containerType) { + CObjectTypeInfo type(GetRealTypeInfo(containerType->GetElementType())); + if (type.GetTypeFamily() == eTypeFamilyPrimitive && type.GetPrimitiveValueType() == ePrimitiveValueAny) { + TopFrame().SetNotag(); + m_BlockStart = true; + m_ExpectValue = false; + return; + } BeginArray(); } void CObjectOStreamJson::EndContainer(void) { + if (TopFrame().GetNotag()) { + TopFrame().SetNotag(false); + return; + } EndArray(); } @@ -453,9 +487,24 @@ void CObjectOStreamJson::EndClass(void) void CObjectOStreamJson::BeginClassMember(const CMemberId& id) { + if (m_ExpectValue) { + return; + } if (id.HasNotag() || id.IsAttlist()) { - m_SkippedMemberId = id.GetName(); TopFrame().SetNotag(); + if (id.HasAnyContent()) { +#if 1 + if ( m_BlockStart ) { + m_BlockStart = false; + } else { + m_Output.PutChar(','); + } +#else + NextElement(); +#endif + } else { + m_SkippedMemberId = id.GetName(); + } return; } if (id.HasAnyContent()) { @@ -774,7 +823,7 @@ void CObjectOStreamJson::NextElement(void) m_Output.PutChar(','); } m_Output.PutEol(); - m_ExpectValue = false; + m_ExpectValue = true; } void CObjectOStreamJson::BeginArray(void) diff --git a/c++/src/serial/objostrxml.cpp b/c++/src/serial/objostrxml.cpp index 3d82102a..903e8c32 100644 --- a/c++/src/serial/objostrxml.cpp +++ b/c++/src/serial/objostrxml.cpp @@ -1,4 +1,4 @@ -/* $Id: objostrxml.cpp 507946 2016-07-22 16:50:31Z gouriano $ +/* $Id: objostrxml.cpp 534119 2017-04-24 17:07:34Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -77,7 +77,7 @@ CObjectOStreamXml::CObjectOStreamXml(CNcbiOstream& out, bool deleteOut) m_UsePublicId( true), m_Attlist( false), m_StdXml( false), m_EnforcedStdXml( false), m_RealFmt( eRealScientificFormat ), - m_Encoding( eEncoding_Unknown ), m_StringEncoding( eEncoding_Unknown ), + m_Encoding( eEncoding_Unknown ), m_StringEncoding( eEncoding_UTF8 ), m_UseXmlDecl(true), m_UseSchemaRef( false ), m_UseSchemaLoc( true ), m_UseDTDRef( true ), m_DefaultSchemaNamespace( sm_DefaultSchemaNamespace ), @@ -93,7 +93,7 @@ CObjectOStreamXml::CObjectOStreamXml(CNcbiOstream& out, EOwnership deleteOut) m_UsePublicId( true), m_Attlist( false), m_StdXml( false), m_EnforcedStdXml( false), m_RealFmt( eRealScientificFormat ), - m_Encoding( eEncoding_Unknown ), m_StringEncoding( eEncoding_Unknown ), + m_Encoding( eEncoding_Unknown ), m_StringEncoding( eEncoding_UTF8 ), m_UseXmlDecl(true), m_UseSchemaRef( false ), m_UseSchemaLoc( true ), m_UseDTDRef( true ), m_DefaultSchemaNamespace( sm_DefaultSchemaNamespace ), @@ -416,26 +416,35 @@ void CObjectOStreamXml::WriteEnum(const CEnumeratedTypeValues& values, { bool skipname = valueName.empty() || (m_WriteNamedIntegersByValue && values.IsInteger()); + bool valueonly = GetRecentTypeInfo() && GetRecentTypeInfo()->GetDataSpec() == EDataSpec::eJSON; if ( !m_SkipNextTag && !values.GetName().empty() ) { // global enum - OpenTagStart(); - m_Output.PutString(values.GetName()); - if ( !skipname ) { - m_Output.PutString(" value=\""); - m_Output.PutString(valueName); - m_Output.PutChar('\"'); - } - if ( values.IsInteger() ) { - OpenTagEnd(); - m_Output.PutInt4(value); - CloseTagStart(); + if (valueonly) { + if ( values.IsInteger() ) { + m_Output.PutInt4(value); + } else { + m_Output.PutString(valueName); + } + } else { + OpenTagStart(); m_Output.PutString(values.GetName()); - CloseTagEnd(); - } - else { - _ASSERT(!valueName.empty()); - SelfCloseTagEnd(); - m_LastTagAction = eTagClose; + if ( !skipname ) { + m_Output.PutString(" value=\""); + m_Output.PutString(valueName); + m_Output.PutChar('\"'); + } + if ( values.IsInteger() ) { + OpenTagEnd(); + m_Output.PutInt4(value); + CloseTagStart(); + m_Output.PutString(values.GetName()); + CloseTagEnd(); + } + else { + _ASSERT(!valueName.empty()); + SelfCloseTagEnd(); + m_LastTagAction = eTagClose; + } } } else { @@ -1354,47 +1363,6 @@ void CObjectOStreamXml::CheckStdXml(const CClassTypeInfoBase* classType) m_StdXml = classType->GetItems().GetItemInfo(first)->GetId().HaveNoPrefix(); } -TTypeInfo CObjectOStreamXml::GetRealTypeInfo(TTypeInfo typeInfo) -{ - if (typeInfo->GetTypeFamily() == eTypeFamilyPointer) { - const CPointerTypeInfo* ptr = - dynamic_cast(typeInfo); - if (ptr) { - typeInfo = ptr->GetPointedType(); - } - } - return typeInfo; -} - -ETypeFamily CObjectOStreamXml::GetRealTypeFamily(TTypeInfo typeInfo) -{ - return GetRealTypeInfo( typeInfo )->GetTypeFamily(); -} - -TTypeInfo CObjectOStreamXml::GetContainerElementTypeInfo(TTypeInfo typeInfo) -{ - typeInfo = GetRealTypeInfo( typeInfo ); - _ASSERT(typeInfo->GetTypeFamily() == eTypeFamilyContainer); - const CContainerTypeInfo* ptr = - dynamic_cast(typeInfo); - return GetRealTypeInfo(ptr->GetElementType()); -} - -ETypeFamily CObjectOStreamXml::GetContainerElementTypeFamily(TTypeInfo typeInfo) -{ - if (typeInfo->GetTypeFamily() == eTypeFamilyPointer) { - const CPointerTypeInfo* ptr = - dynamic_cast(typeInfo); - if (ptr) { - typeInfo = ptr->GetPointedType(); - } - } - _ASSERT(typeInfo->GetTypeFamily() == eTypeFamilyContainer); - const CContainerTypeInfo* ptr = - dynamic_cast(typeInfo); - return GetRealTypeFamily(ptr->GetElementType()); -} - void CObjectOStreamXml::BeginClass(const CClassTypeInfo* classInfo) { if (m_SkipNextTag) { diff --git a/c++/src/serial/objstack.cpp b/c++/src/serial/objstack.cpp index d888ee5d..6adca629 100644 --- a/c++/src/serial/objstack.cpp +++ b/c++/src/serial/objstack.cpp @@ -1,4 +1,4 @@ -/* $Id: objstack.cpp 501450 2016-05-16 14:53:19Z gouriano $ +/* $Id: objstack.cpp 534119 2017-04-24 17:07:34Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,6 +32,8 @@ #include #include #include +#include +#include BEGIN_NCBI_SCOPE @@ -249,14 +251,15 @@ void CObjectStack::x_PopStackPath(void) } } -const string& CObjectStack::GetStackPath(void) +const string& CObjectStack::GetStackPath(void) const { if (GetStackDepth()) { // _ASSERT(FetchFrameFromBottom(0).m_FrameType == TFrame::eFrameNamed); // _ASSERT(FetchFrameFromBottom(0).m_TypeInfo); // m_MemberPath = FetchFrameFromBottom(0).GetTypeInfo()->GetName(); // there is no "root" symbol - m_MemberPath = FetchFrameFromBottom(0).HasTypeInfo() ? + string path; + path = FetchFrameFromBottom(0).HasTypeInfo() ? FetchFrameFromBottom(0).m_TypeInfo->GetName() : "?"; for ( size_t i = 1; i < GetStackDepth(); ++i ) { const TFrame& frame = FetchFrameFromBottom(i); @@ -266,16 +269,17 @@ const string& CObjectStack::GetStackPath(void) continue; } // member separator symbol is '.' - m_MemberPath += '.'; + path += '.'; const string& member = mem_id.GetName(); if (!member.empty()) { - m_MemberPath += member; + path += member; } else { - m_MemberPath += NStr::IntToString(mem_id.GetTag()); + path += NStr::IntToString(mem_id.GetTag()); } } } - m_PathValid = true; + const_cast(this)->m_PathValid = true; + const_cast(this)->m_MemberPath = path; } return m_MemberPath; } @@ -292,6 +296,41 @@ void CObjectStack::PopErrorFrame(void) PopFrame(); } +TTypeInfo CObjectStack::GetRealTypeInfo(TTypeInfo typeInfo) +{ + if (typeInfo->GetTypeFamily() == eTypeFamilyPointer) { + const CPointerTypeInfo* ptr = + dynamic_cast(typeInfo); + if (ptr) { + typeInfo = ptr->GetPointedType(); + } + } + return typeInfo; +} + +ETypeFamily CObjectStack::GetRealTypeFamily(TTypeInfo typeInfo) +{ + return GetRealTypeInfo( typeInfo )->GetTypeFamily(); +} + +TTypeInfo CObjectStack::GetContainerElementTypeInfo(TTypeInfo typeInfo) +{ + typeInfo = GetRealTypeInfo( typeInfo ); + _ASSERT(typeInfo->GetTypeFamily() == eTypeFamilyContainer); + const CContainerTypeInfo* ptr = + dynamic_cast(typeInfo); + return GetRealTypeInfo(ptr->GetElementType()); +} + +ETypeFamily CObjectStack::GetContainerElementTypeFamily(TTypeInfo typeInfo) +{ + typeInfo = GetRealTypeInfo( typeInfo ); + _ASSERT(typeInfo->GetTypeFamily() == eTypeFamilyContainer); + const CContainerTypeInfo* ptr = + dynamic_cast(typeInfo); + return GetRealTypeFamily(ptr->GetElementType()); +} + const char* CObjectStackFrame::GetFrameTypeName(void) const { const char* s; diff --git a/c++/src/serial/rpcbase.cpp b/c++/src/serial/rpcbase.cpp index 9c157d53..2cd70c66 100644 --- a/c++/src/serial/rpcbase.cpp +++ b/c++/src/serial/rpcbase.cpp @@ -1,4 +1,4 @@ -/* $Id: rpcbase.cpp 501456 2016-05-16 15:12:46Z ivanov $ +/* $Id: rpcbase.cpp 541584 2017-07-19 16:03:23Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,26 +37,6 @@ BEGIN_NCBI_SCOPE -// HTTP headers controlling retries. - -// Stop retries if set, value describes the reason. -const char* kRetryStop = "X-NCBI-Retry-Stop"; -// Override retries delay. Use min of the header and m_RetryDelay. -const char* kRetryDelay = "X-NCBI-Retry-Delay"; -// Add args to the request when sending next retry. -const char* kRetryArgs = "X-NCBI-Retry-Args"; -// Use the specified URL for the next retry. -const char* kRetryURL = "X-NCBI-Retry-URL"; -// Use different content when sending retry. The values are described below. -const char* kRetryContent = "X-NCBI-Retry-Content"; -// Send no content whith the next retry. -const char* kRetryContent_no_content = "no_content"; -// Send content from the last response when retrying. -const char* kRetryContent_from_response = "from_response"; -// Send content following the prefix (URL-encoded). -const char* kRetryContent_content = "content:"; - - CRPCClient_Base::CRPCClient_Base(const string& service, ESerialDataFormat format, unsigned int retry_limit) @@ -182,6 +162,9 @@ void CRPCClient_Base::x_Ask(const CSerialObject& request, CSerialObject& reply) // Retry context can be either the default one (m_RetryCtx), or provided // through an exception. for (;;) { + if ( IsCanceled() ) { + NCBI_THROW(CRPCClientException, eFailed, "Request canceled"); + } try { SetAffinity(x_GetAffinity(request)); Connect(); // No-op if already connected @@ -240,8 +223,9 @@ void CRPCClient_Base::x_Ask(const CSerialObject& request, CSerialObject& reply) if ((!limit_by_time && ++m_RetryCount >= m_RetryLimit) || !x_ShouldRetry(m_RetryCount)) { NCBI_THROW(CRPCClientException, eFailed, - "Failed to receive reply after " + - NStr::NumericToString(m_RetryCount) + " tries"); + "Failed to receive reply after " + + NStr::NumericToString(m_RetryCount) + + (m_RetryCount == 1 ? "try" : " tries")); } if ( m_RetryCtx.IsSetStop() ) { NCBI_THROW(CRPCClientException, eFailed, @@ -260,6 +244,9 @@ void CRPCClient_Base::x_Ask(const CSerialObject& request, CSerialObject& reply) } } // Always reconnect on retry. + if ( IsCanceled() ) { + NCBI_THROW(CRPCClientException, eFailed, "Request canceled"); + } try { Reset(); } STD_CATCH_ALL_XX(Serial_RPCClient, 1 ,"CRPCClient_Base::Reset()"); diff --git a/c++/src/serial/serial.cpp b/c++/src/serial/serial.cpp index fd092cc1..0544c0a4 100644 --- a/c++/src/serial/serial.cpp +++ b/c++/src/serial/serial.cpp @@ -1,4 +1,4 @@ -/* $Id: serial.cpp 403742 2013-06-18 15:26:09Z grichenk $ +/* $Id: serial.cpp 529265 2017-03-02 16:00:11Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -73,9 +73,13 @@ void Read(CObjectIStream& in, TObjectPtr object, TTypeInfo type) in.Read(object, type); } -void Serial_FilterSkip(CObjectIStream& in, CObjectTypeInfo& ctype) +bool Serial_FilterSkip(CObjectIStream& in, const CObjectTypeInfo& ctype) { - in.Skip(ctype); + if (!in.EndOfData()) { + in.Skip(ctype); + return true; + } + return false; } DEFINE_STATIC_FAST_MUTEX(s_ModuleNameMutex); diff --git a/c++/src/serial/typeinfo.cpp b/c++/src/serial/typeinfo.cpp index 146adc9a..a463c5c4 100644 --- a/c++/src/serial/typeinfo.cpp +++ b/c++/src/serial/typeinfo.cpp @@ -1,4 +1,4 @@ -/* $Id: typeinfo.cpp 507795 2016-07-21 17:24:14Z gouriano $ +/* $Id: typeinfo.cpp 532212 2017-04-03 13:24:13Z gouriano $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -96,6 +96,7 @@ CTypeInfo::CTypeInfo(ETypeFamily typeFamily, size_t size) : m_TypeFamily(typeFamily), m_Size(size), m_Name(), m_InfoItem(0), m_CodeVer(0), + m_DataSpec(EDataSpec::eUnknown), m_IsCObject(false), m_IsInternal(false), m_Tag(eNoExplicitTag), m_TagClass(CAsnBinaryDefs::eUniversal), @@ -116,6 +117,7 @@ CTypeInfo::CTypeInfo(ETypeFamily typeFamily, size_t size, const char* name) : m_TypeFamily(typeFamily), m_Size(size), m_Name(name), m_InfoItem(0), m_CodeVer(0), + m_DataSpec(EDataSpec::eUnknown), m_IsCObject(false), m_IsInternal(false), m_Tag(eNoExplicitTag), m_TagClass(CAsnBinaryDefs::eUniversal), @@ -135,6 +137,7 @@ CTypeInfo::CTypeInfo(ETypeFamily typeFamily, size_t size, const string& name) : m_TypeFamily(typeFamily), m_Size(size), m_Name(name), m_InfoItem(0), m_CodeVer(0), + m_DataSpec(EDataSpec::eUnknown), m_IsCObject(false), m_IsInternal(false), m_Tag(eNoExplicitTag), m_TagClass(CAsnBinaryDefs::eUniversal), diff --git a/c++/src/util/CMakeLists.txt b/c++/src/util/CMakeLists.txt new file mode 100644 index 00000000..176afc59 --- /dev/null +++ b/c++/src/util/CMakeLists.txt @@ -0,0 +1,21 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.util.lib.txt) + +# Recurse subdirectories +add_subdirectory(regexp) +add_subdirectory(xregexp) +add_subdirectory(compress) +add_subdirectory(diff) +add_subdirectory(image) +add_subdirectory(tables) +add_subdirectory(creaders) +add_subdirectory(sequtil) +add_subdirectory(bitset) +add_subdirectory(qparse) +add_subdirectory(lmdbxx) +add_subdirectory(test ) +add_subdirectory(demo ) diff --git a/c++/src/util/CMakeLists.util.lib.txt b/c++/src/util/CMakeLists.util.lib.txt new file mode 100644 index 00000000..8814871a --- /dev/null +++ b/c++/src/util/CMakeLists.util.lib.txt @@ -0,0 +1,16 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/util/Makefile.util.lib +# +add_library(xutil + random_gen utf8 checksum bytesrc strbuffer itree smalldns + thread_pool_old ddump_viewer strsearch logrotate format_guess ascii85 + md5 file_obsolete unicode dictionary dictionary_util thread_nonstop + sgml_entity static_set transmissionrw miscmath mutex_pool ncbi_cache + line_reader util_exception uttp multi_writer itransaction thread_pool + thread_pool_ctrl scheduler distribution rangelist util_misc + histogram_binning table_printer retry_ctx stream_source file_manifest +) + +target_link_libraries(xutil + xncbi +) diff --git a/c++/src/util/Makefile.in b/c++/src/util/Makefile.in index aff3182a..b94f66fc 100644 --- a/c++/src/util/Makefile.in +++ b/c++/src/util/Makefile.in @@ -1,10 +1,10 @@ -# $Id: Makefile.in 385270 2013-01-08 16:23:52Z ivanov $ +# $Id: Makefile.in 540083 2017-06-30 17:32:51Z ivanov $ # Meta-makefile ("UTIL" project) ################################# LIB_PROJ = util -SUB_PROJ = regexp xregexp compress diff image tables creaders sequtil bitset qparse test demo +SUB_PROJ = regexp xregexp compress diff image tables creaders sequtil bitset qparse lmdb lmdbxx test demo srcdir = @srcdir@ include @builddir@/Makefile.meta diff --git a/c++/src/util/bitset/CMakeLists.txt b/c++/src/util/bitset/CMakeLists.txt new file mode 100644 index 00000000..a0a4e648 --- /dev/null +++ b/c++/src/util/bitset/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory + +# Recurse subdirectories +add_subdirectory(test ) +add_subdirectory(demo ) diff --git a/c++/src/util/bytesrc.cpp b/c++/src/util/bytesrc.cpp index 0b3a01d2..da3343b0 100644 --- a/c++/src/util/bytesrc.cpp +++ b/c++/src/util/bytesrc.cpp @@ -1,4 +1,4 @@ -/* $Id: bytesrc.cpp 506679 2016-07-11 12:10:32Z gouriano $ +/* $Id: bytesrc.cpp 538188 2017-06-08 13:29:06Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/util/compress/CMakeLists.txt b/c++/src/util/compress/CMakeLists.txt new file mode 100644 index 00000000..4fc16dd7 --- /dev/null +++ b/c++/src/util/compress/CMakeLists.txt @@ -0,0 +1,15 @@ +############################################################################## +# +# + +# Include projects from this directory + +# Recurse subdirectories +if (BZIP2_INTERNAL) + add_subdirectory(bzip2) +endif() + +if (ZLIB_INTERNAL) + add_subdirectory(zlib) +endif() +add_subdirectory(api) diff --git a/c++/src/util/compress/api/CMakeLists.compress.lib.txt b/c++/src/util/compress/api/CMakeLists.compress.lib.txt new file mode 100644 index 00000000..d89d0f85 --- /dev/null +++ b/c++/src/util/compress/api/CMakeLists.compress.lib.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/util/compress/api/Makefile.compress.lib +# +add_library(xcompress + compress stream streambuf stream_util bzip2 zlib lzo reader_zlib tar + archive archive_ archive_zip +) +include_directories(SYSTEM ${CMPRS_INCLUDE}) + +target_link_libraries(xcompress + xutil + ${BZ2_LIB} ${Z_LIB} ${LZO_LIB} ${BZ2_LIBS} ${Z_LIBS} ${LZO_LIBS} +) diff --git a/c++/src/util/compress/api/CMakeLists.txt b/c++/src/util/compress/api/CMakeLists.txt new file mode 100644 index 00000000..6f169916 --- /dev/null +++ b/c++/src/util/compress/api/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.compress.lib.txt) + diff --git a/c++/src/util/compress/api/archive.cpp b/c++/src/util/compress/api/archive.cpp index 241215b2..0a853e7b 100644 --- a/c++/src/util/compress/api/archive.cpp +++ b/c++/src/util/compress/api/archive.cpp @@ -1,4 +1,4 @@ -/* $Id: archive.cpp 484782 2015-11-16 13:40:06Z ivanov $ +/* $Id: archive.cpp 534861 2017-05-03 12:50:28Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -314,7 +314,7 @@ void CArchive::Create(void) } -auto_ptr CArchive::List(void) +unique_ptr CArchive::List(void) { ARCHIVE_CHECK; x_Open(eList); @@ -322,7 +322,7 @@ auto_ptr CArchive::List(void) } -auto_ptr CArchive::Test(void) +unique_ptr CArchive::Test(void) { ARCHIVE_CHECK; x_Open(eTest); @@ -330,11 +330,11 @@ auto_ptr CArchive::Test(void) } -auto_ptr CArchive::Extract(void) +unique_ptr CArchive::Extract(void) { ARCHIVE_CHECK; x_Open(eExtract); - auto_ptr entries = x_ReadAndProcess(eExtract); + unique_ptr entries = x_ReadAndProcess(eExtract); // Restore attributes of "postponed" directory entries if (F_ISSET(fPreserveAll)) { ITERATE(TEntries, e, *entries) { @@ -439,7 +439,7 @@ void CArchive::ExtractFileToCallback(const CArchiveEntryInfo& info, } -auto_ptr CArchive::Append(const string& path, ELevel level, +unique_ptr CArchive::Append(const string& path, ELevel level, const string& comment) { ARCHIVE_CHECK; @@ -448,7 +448,7 @@ auto_ptr CArchive::Append(const string& path, ELevel level, } -auto_ptr +unique_ptr CArchive::AppendFileFromMemory(const string& name_in_archive, void* buf, size_t buf_size, ELevel level, const string& comment) { @@ -457,7 +457,7 @@ CArchive::AppendFileFromMemory(const string& name_in_archive, void* buf, size_t NCBI_THROW(CCoreException, eInvalidArg, "Bad memory buffer"); } x_Open(eAppend); - auto_ptr entries(new TEntries); + unique_ptr entries(new TEntries); // Clear the entry info m_Current = CArchiveEntryInfo(); @@ -587,10 +587,10 @@ void CArchive::x_Open(EAction action) } -auto_ptr CArchive::x_ReadAndProcess(EAction action) +unique_ptr CArchive::x_ReadAndProcess(EAction action) { _ASSERT(action); - auto_ptr entries(new TEntries); + unique_ptr entries(new TEntries); // Get number of files in archive size_t n = ARCHIVE->GetNumEntries(); @@ -672,7 +672,7 @@ void CArchive::x_ExtractEntry(const TEntries* prev_entries) CDirEntry::EType type = m_Current.GetType(); // Destination for extraction - auto_ptr dst( + unique_ptr dst( CDirEntry::CreateObject(type, CDirEntry::NormalizePath(CDirEntry::ConcatPath(m_BaseDir, m_Current.GetName())))); // Dereference link if requested @@ -790,7 +790,7 @@ void CArchive::x_ExtractEntry(const TEntries* prev_entries) void CArchive::x_RestoreAttrs(const CArchiveEntryInfo& info, const CDirEntry* dst) const { - auto_ptr path_ptr; // deleter + unique_ptr path_ptr; // deleter if (!dst) { path_ptr.reset(CDirEntry::CreateObject(CDirEntry::EType(info.GetType()), CDirEntry::NormalizePath(CDirEntry::ConcatPath(m_BaseDir, info.GetName())))); @@ -878,12 +878,12 @@ void CArchive::x_RestoreAttrs(const CArchiveEntryInfo& info, } -auto_ptr CArchive::x_Append(const string& src_path, +unique_ptr CArchive::x_Append(const string& src_path, ELevel level, const string& comment, const TEntries* toc) { - auto_ptr entries(new TEntries); + unique_ptr entries(new TEntries); const EFollowLinks follow_links = (m_Flags & fFollowLinks) ? eFollowLinks : eIgnoreLinks; bool update = true; @@ -1070,7 +1070,7 @@ auto_ptr CArchive::x_Append(const string& src_path, // Append/update all files from that directory CDir::TEntries dir = CDir(path).GetEntries("*", CDir::eIgnoreRecursive); ITERATE(CDir::TEntries, e, dir) { - auto_ptr add = x_Append((*e)->GetPath(), level, kEmptyStr, toc); + unique_ptr add = x_Append((*e)->GetPath(), level, kEmptyStr, toc); entries->splice(entries->end(), *add); } } diff --git a/c++/src/util/compress/api/bzip2.cpp b/c++/src/util/compress/api/bzip2.cpp index 605bb27b..940e1ee4 100644 --- a/c++/src/util/compress/api/bzip2.cpp +++ b/c++/src/util/compress/api/bzip2.cpp @@ -1,4 +1,4 @@ -/* $Id: bzip2.cpp 430126 2014-03-24 12:25:47Z ivanov $ +/* $Id: bzip2.cpp 539121 2017-06-19 14:00:47Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -46,9 +46,14 @@ BEGIN_NCBI_SCOPE // Get compression stream pointer #define STREAM ((bz_stream*)m_Stream) -// Convert 'size_t' to '[unsigned] int' which used internally in bzip2 -#define LIMIT_SIZE_PARAM(value) if (value > (size_t)kMax_Int) value = kMax_Int -#define LIMIT_SIZE_PARAM_U(value) if (value > kMax_UInt) value = kMax_UInt +// Limit 'size_t' values to max values of other used types to avoid overflow +#define LIMIT_SIZE_PARAM_INT(value) if (value > (size_t)kMax_Int) value = kMax_Int +#define LIMIT_SIZE_PARAM_UINT(value) if (value > kMax_UInt) value = kMax_UInt + +// Maximum size of the chuck compressed by bzip2, +// but there is no limit to the number of chunks in the buffer. +const unsigned int kMaxChunkSize = kMax_UInt; + ////////////////////////////////////////////////////////////////////////////// @@ -103,40 +108,51 @@ bool CBZip2Compression::CompressBuffer( *dst_len = 0; // Check parameters - if ( !src_len ) { - if ( !F_ISSET(fAllowEmptyData) ) { - src_buf = NULL; - } - } - if ( !src_buf ) { - SetError(BZ_PARAM_ERROR, "bad argument"); - ERR_COMPRESS(15, FormatErrorMessage("CBZip2Compression::CompressBuffer")); - return false; + if (!src_len && !F_ISSET(fAllowEmptyData)) { + src_buf = NULL; } - if ( !dst_buf || !dst_len ) { + if (!src_buf || !dst_buf || !dst_len) { SetError(BZ_PARAM_ERROR, "bad argument"); ERR_COMPRESS(15, FormatErrorMessage("CBZip2Compression::CompressBuffer")); return false; } - if (src_len > kMax_UInt) { - SetError(BZ_PARAM_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(16, FormatErrorMessage("CBZip2Compression::CompressBuffer")); - return false; + + STREAM->bzalloc = NULL; + STREAM->bzfree = NULL; + STREAM->opaque = NULL; + int errcode = BZ2_bzCompressInit(STREAM, GetLevel(), 0, 0); + + if (errcode == BZ_OK) { + // Pointer to the current positions in destination buffer + char* dst = (char*)dst_buf; + + STREAM->next_in = (char*)src_buf; + STREAM->avail_in = 0; + STREAM->next_out = dst; + STREAM->avail_out = 0; + + size_t left = src_len; + do { + if (STREAM->avail_in == 0) { + STREAM->avail_in = left > kMaxChunkSize ? kMaxChunkSize : (unsigned int)left; + left -= STREAM->avail_in; + } + if (STREAM->avail_out == 0) { + STREAM->avail_out = dst_size > kMaxChunkSize ? kMaxChunkSize : (unsigned int)dst_size; + dst_size -= STREAM->avail_out; + } + errcode = BZ2_bzCompress(STREAM, left ? BZ_RUN : BZ_FINISH); + } + while (errcode == BZ_RUN_OK); + + // Calculate length of output data. + *dst_len = STREAM->next_out - (char*)dst_buf; + BZ2_bzCompressEnd(STREAM); } - LIMIT_SIZE_PARAM_U(dst_size); - // Destination buffer size - unsigned int x_dst_len = (unsigned int)dst_size; - // Compress buffer - int errcode = BZ2_bzBuffToBuffCompress( - (char*)dst_buf, &x_dst_len, - (char*)src_buf, (unsigned int)src_len, - GetLevel(), 0, 0 ); - *dst_len = x_dst_len; SetError(errcode, GetBZip2ErrorDescription(errcode)); - if ( errcode != BZ_OK) { - ERR_COMPRESS(17, - FormatErrorMessage("CBZip2Compression::CompressBuffer")); + if ( errcode != BZ_STREAM_END) { + ERR_COMPRESS(17, FormatErrorMessage("CBZip2Compression::CompressBuffer")); return false; } return true; @@ -158,44 +174,60 @@ bool CBZip2Compression::DecompressBuffer( } src_buf = NULL; } - if ( !src_buf ) { + if (!src_buf || !dst_buf || !dst_len) { SetError(BZ_PARAM_ERROR, "bad argument"); ERR_COMPRESS(84, FormatErrorMessage("CBZip2Compression::DecompressBuffer")); return false; } - if ( !dst_buf || !dst_len ) { - SetError(BZ_PARAM_ERROR, "bad argument"); - ERR_COMPRESS(84, FormatErrorMessage("CBZip2Compression::DecompressBuffer")); - return false; - } - if (src_len > kMax_UInt) { - SetError(BZ_PARAM_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(18, FormatErrorMessage("CBZip2Compression::DecompressBuffer")); - return false; - } - LIMIT_SIZE_PARAM_U(dst_size); - // Destination buffer size - unsigned int x_dst_len = (unsigned int)dst_size; - // Decompress buffer - int errcode = BZ2_bzBuffToBuffDecompress( - (char*)dst_buf, &x_dst_len, - (char*)src_buf, (unsigned int)src_len, 0, 0 ); + STREAM->bzalloc = NULL; + STREAM->bzfree = NULL; + STREAM->opaque = NULL; + int errcode = BZ2_bzDecompressInit(STREAM, 0, 0); + + size_t dst_size_arg = dst_size; + + if (errcode == BZ_OK) { + // Pointer to the current positions in destination buffer + char* dst = (char*)dst_buf; + + STREAM->next_in = (char*)src_buf; + STREAM->avail_in = 0; + STREAM->next_out = dst; + STREAM->avail_out = 0; + + size_t left = src_len; + do { + if (STREAM->avail_in == 0) { + STREAM->avail_in = left > kMaxChunkSize ? kMaxChunkSize : (unsigned int)left; + left -= STREAM->avail_in; + } + if (STREAM->avail_out == 0) { + STREAM->avail_out = dst_size > kMaxChunkSize ? kMaxChunkSize : (unsigned int)dst_size; + dst_size -= STREAM->avail_out; + } + errcode = BZ2_bzDecompress(STREAM); + } + while (errcode == BZ_OK); + + // Calculate length of output data. + *dst_len = STREAM->next_out - (char*)dst_buf; + BZ2_bzDecompressEnd(STREAM); + } // Decompression error: data error if ((errcode == BZ_DATA_ERROR_MAGIC || errcode == BZ_DATA_ERROR) && F_ISSET(fAllowTransparentRead)) { // But transparent read is allowed - *dst_len = (dst_size < src_len) ? dst_size : src_len; + *dst_len = (dst_size_arg < src_len) ? dst_size_arg : src_len; memcpy(dst_buf, src_buf, *dst_len); - return (dst_size >= src_len); + return (dst_size_arg >= src_len); } + // Standard decompression results processing - *dst_len = x_dst_len; SetError(errcode, GetBZip2ErrorDescription(errcode)); - if ( errcode != BZ_OK ) { - ERR_COMPRESS(19, - FormatErrorMessage("CBZip2Compression::DecompressBuffer")); + if ( errcode != BZ_STREAM_END ) { + ERR_COMPRESS(19, FormatErrorMessage("CBZip2Compression::DecompressBuffer")); return false; } return true; @@ -206,8 +238,7 @@ bool CBZip2Compression::CompressFile(const string& src_file, const string& dst_file, size_t buf_size) { - CBZip2CompressionFile cf(GetLevel(), - m_Verbosity, m_WorkFactor, m_SmallDecompress); + CBZip2CompressionFile cf(GetLevel(), m_Verbosity, m_WorkFactor, m_SmallDecompress); cf.SetFlags(cf.GetFlags() | GetFlags()); // Open output file @@ -234,8 +265,7 @@ bool CBZip2Compression::DecompressFile(const string& src_file, const string& dst_file, size_t buf_size) { - CBZip2CompressionFile cf(GetLevel(), - m_Verbosity, m_WorkFactor, m_SmallDecompress); + CBZip2CompressionFile cf(GetLevel(), m_Verbosity, m_WorkFactor, m_SmallDecompress); cf.SetFlags(cf.GetFlags() | GetFlags()); // Open output file @@ -345,22 +375,19 @@ bool CBZip2CompressionFile::Open(const string& file_name, EMode mode) if ( mode == eMode_Read ) { m_FileStream = fopen(file_name.c_str(), "rb"); - m_File = BZ2_bzReadOpen (&errcode, m_FileStream, m_SmallDecompress, - m_Verbosity, 0, 0); + m_File = BZ2_bzReadOpen(&errcode, m_FileStream, m_SmallDecompress, m_Verbosity, 0, 0); m_DecompressMode = eMode_Unknown; m_EOF = false; } else { m_FileStream = fopen(file_name.c_str(), "wb"); - m_File = BZ2_bzWriteOpen(&errcode, m_FileStream, GetLevel(), - m_Verbosity, m_WorkFactor); + m_File = BZ2_bzWriteOpen(&errcode, m_FileStream, GetLevel(), m_Verbosity, m_WorkFactor); } m_Mode = mode; if ( errcode != BZ_OK ) { Close(); SetError(errcode, GetBZip2ErrorDescription(errcode)); - ERR_COMPRESS(20, - FormatErrorMessage("CBZip2CompressionFile::Open", false)); + ERR_COMPRESS(20, FormatErrorMessage("CBZip2CompressionFile::Open", false)); return false; }; SetError(BZ_OK); @@ -373,7 +400,7 @@ long CBZip2CompressionFile::Read(void* buf, size_t len) if ( m_EOF ) { return 0; } - LIMIT_SIZE_PARAM(len); + LIMIT_SIZE_PARAM_INT(len); // for BZ2_bzRead() int errcode; int nread = 0; @@ -391,8 +418,7 @@ long CBZip2CompressionFile::Read(void* buf, size_t len) m_DecompressMode = eMode_Decompress; SetError(errcode, GetBZip2ErrorDescription(errcode)); if ( errcode != BZ_OK && errcode != BZ_STREAM_END ) { - ERR_COMPRESS(21, - FormatErrorMessage("CBZip2CompressionFile::Read", false)); + ERR_COMPRESS(21, FormatErrorMessage("CBZip2CompressionFile::Read", false)); return -1; } if ( errcode == BZ_STREAM_END ) { @@ -401,7 +427,6 @@ long CBZip2CompressionFile::Read(void* buf, size_t len) } } if ( m_DecompressMode == eMode_TransparentRead ) { - // 'len' never exceed kMax_Int here. nread = (int)fread(buf, 1, len, m_FileStream); } if (nread) { @@ -416,7 +441,7 @@ long CBZip2CompressionFile::Write(const void* buf, size_t len) if (!len) { return 0; } - LIMIT_SIZE_PARAM(len); + LIMIT_SIZE_PARAM_INT(len); // for BZ2_bzWrite() m_HaveData = true; int errcode; @@ -424,8 +449,7 @@ long CBZip2CompressionFile::Write(const void* buf, size_t len) SetError(errcode, GetBZip2ErrorDescription(errcode)); if ( errcode != BZ_OK && errcode != BZ_STREAM_END ) { - ERR_COMPRESS(22, - FormatErrorMessage("CBZip2CompressionFile::Write", false)); + ERR_COMPRESS(22, FormatErrorMessage("CBZip2CompressionFile::Write", false)); return -1; }; return (long)len; @@ -454,8 +478,7 @@ bool CBZip2CompressionFile::Close(void) } if ( errcode != BZ_OK ) { - ERR_COMPRESS(23, - FormatErrorMessage("CBZip2CompressionFile::Close", false)); + ERR_COMPRESS(23, FormatErrorMessage("CBZip2CompressionFile::Close", false)); return false; }; return true; @@ -498,8 +521,7 @@ CCompressionProcessor::EStatus CBZip2Compressor::Init(void) // Initialize the compressor stream structure memset(STREAM, 0, sizeof(bz_stream)); // Create a compressor stream - int errcode = BZ2_bzCompressInit(STREAM, GetLevel(), m_Verbosity, - m_WorkFactor); + int errcode = BZ2_bzCompressInit(STREAM, GetLevel(), m_Verbosity, m_WorkFactor); SetError(errcode, GetBZip2ErrorDescription(errcode)); if ( errcode == BZ_OK ) { @@ -517,15 +539,14 @@ CCompressionProcessor::EStatus CBZip2Compressor::Process( /* out */ size_t* out_avail) { *out_avail = 0; - if (in_len > kMax_UInt) { - SetError(BZ_PARAM_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(25, FormatErrorMessage("CBZip2Compressor::Process")); - return eStatus_Error; - } if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); + // To simplify this method, limit input and output sizes, + // the upper level code will process all necessary data + // in the loop if necessary. + LIMIT_SIZE_PARAM_UINT(in_len); + LIMIT_SIZE_PARAM_UINT(out_size); STREAM->next_in = const_cast(in_buf); STREAM->avail_in = (unsigned int)in_len; @@ -536,8 +557,8 @@ CCompressionProcessor::EStatus CBZip2Compressor::Process( SetError(errcode, GetBZip2ErrorDescription(errcode)); *in_avail = STREAM->avail_in; *out_avail = out_size - STREAM->avail_out; - IncreaseProcessedSize((unsigned long)(in_len - *in_avail)); - IncreaseOutputSize((unsigned long)(*out_avail)); + IncreaseProcessedSize(in_len - *in_avail); + IncreaseOutputSize(*out_avail); if ( errcode == BZ_RUN_OK ) { return eStatus_Success; @@ -555,7 +576,10 @@ CCompressionProcessor::EStatus CBZip2Compressor::Flush( if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); + // To simplify this method, limit output size, + // the upper level code will process all necessary + // data in the loop if necessary. + LIMIT_SIZE_PARAM_UINT(out_size); STREAM->next_in = 0; STREAM->avail_in = 0; @@ -565,7 +589,7 @@ CCompressionProcessor::EStatus CBZip2Compressor::Flush( int errcode = BZ2_bzCompress(STREAM, BZ_FLUSH); SetError(errcode, GetBZip2ErrorDescription(errcode)); *out_avail = out_size - STREAM->avail_out; - IncreaseOutputSize((unsigned long)(*out_avail)); + IncreaseOutputSize(*out_avail); if ( errcode == BZ_RUN_OK ) { return eStatus_Success; @@ -590,7 +614,10 @@ CCompressionProcessor::EStatus CBZip2Compressor::Finish( if ( !GetProcessedSize() && !F_ISSET(fAllowEmptyData) ) { return eStatus_EndOfData; } - LIMIT_SIZE_PARAM_U(out_size); + // To simplify this method, limit output size, + // the upper level code will process all necessary + // data in the loop if necessary. + LIMIT_SIZE_PARAM_UINT(out_size); STREAM->next_in = 0; STREAM->avail_in = 0; @@ -600,7 +627,7 @@ CCompressionProcessor::EStatus CBZip2Compressor::Finish( int errcode = BZ2_bzCompress(STREAM, BZ_FINISH); SetError(errcode, GetBZip2ErrorDescription(errcode)); *out_avail = out_size - STREAM->avail_out; - IncreaseOutputSize((unsigned long)(*out_avail)); + IncreaseOutputSize(*out_avail); switch (errcode) { case BZ_FINISH_OK: @@ -657,8 +684,7 @@ CCompressionProcessor::EStatus CBZip2Decompressor::Init(void) // Initialize the decompressor stream structure memset(STREAM, 0, sizeof(bz_stream)); // Create a compressor stream - int errcode = BZ2_bzDecompressInit(STREAM, m_Verbosity, - m_SmallDecompress); + int errcode = BZ2_bzDecompressInit(STREAM, m_Verbosity, m_SmallDecompress); SetError(errcode, GetBZip2ErrorDescription(errcode)); if ( errcode == BZ_OK ) { @@ -676,15 +702,14 @@ CCompressionProcessor::EStatus CBZip2Decompressor::Process( /* out */ size_t* out_avail) { *out_avail = 0; - if (in_len > kMax_UInt) { - SetError(BZ_PARAM_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(31, FormatErrorMessage("CBZip2Decompressor::Process")); - return eStatus_Error; - } if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); + // To simplify this method, limit input and output sizes, + // the upper level code will process all necessary data + // in the loop if necessary. + LIMIT_SIZE_PARAM_UINT(in_len); + LIMIT_SIZE_PARAM_UINT(out_size); // By default we consider that data is compressed if ( m_DecompressMode == eMode_Unknown && @@ -716,8 +741,8 @@ CCompressionProcessor::EStatus CBZip2Decompressor::Process( SetError(errcode, GetBZip2ErrorDescription(errcode)); *in_avail = STREAM->avail_in; *out_avail = out_size - STREAM->avail_out; - IncreaseProcessedSize((unsigned long)(in_len - *in_avail)); - IncreaseOutputSize((unsigned long)(*out_avail)); + IncreaseProcessedSize(in_len - *in_avail); + IncreaseOutputSize(*out_avail); switch (errcode) { case BZ_OK: @@ -738,8 +763,8 @@ CCompressionProcessor::EStatus CBZip2Decompressor::Process( memcpy(out_buf, in_buf, n); *in_avail = in_len - n; *out_avail = n; - IncreaseProcessedSize((unsigned long)n); - IncreaseOutputSize((unsigned long)n); + IncreaseProcessedSize(n); + IncreaseOutputSize(n); return eStatus_Success; } diff --git a/c++/src/util/compress/api/compress.cpp b/c++/src/util/compress/api/compress.cpp index 645425a9..5a5c6644 100644 --- a/c++/src/util/compress/api/compress.cpp +++ b/c++/src/util/compress/api/compress.cpp @@ -1,4 +1,4 @@ -/* $Id: compress.cpp 489141 2016-01-08 18:55:07Z ivanov $ +/* $Id: compress.cpp 539121 2017-06-19 14:00:47Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -117,6 +117,8 @@ bool CCompression::x_CompressFile(const string& src_file, SetError(-1, "Buffer size cannot be zero"); return false; } + _ASSERT(buf_size <= kMax_Int); + CNcbiIfstream is(src_file.c_str(), IOS_BASE::in | IOS_BASE::binary); if ( !is.good() ) { SetError(-1, "Cannot open source file"); @@ -143,6 +145,11 @@ bool CCompression::x_DecompressFile(CCompressionFile& src_file, SetError(-1, "Buffer size cannot be zero"); return false; } + if ( buf_size > kMax_Int ) { + buf_size = kMax_Int; + } + _ASSERT(buf_size <= kMax_Int); + CNcbiOfstream os(dst_file.c_str(), IOS_BASE::out | IOS_BASE::binary); if ( !os.good() ) { SetError(-1, "Cannot open destination file"); diff --git a/c++/src/util/compress/api/lzo.cpp b/c++/src/util/compress/api/lzo.cpp index f2ca6f26..5a384c77 100644 --- a/c++/src/util/compress/api/lzo.cpp +++ b/c++/src/util/compress/api/lzo.cpp @@ -1,4 +1,4 @@ -/* $Id: lzo.cpp 430126 2014-03-24 12:25:47Z ivanov $ +/* $Id: lzo.cpp 539121 2017-06-19 14:00:47Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -98,9 +98,12 @@ const size_t kMaxHeaderSize = 512; // Macro to check flags #define F_ISSET(mask) ((GetFlags() & (mask)) == (mask)) -// Convert 'size_t' to '[unsigned] int' which used internally in LZO -#define LIMIT_SIZE_PARAM(value) if (value > (size_t)kMax_Int) value = kMax_Int -#define LIMIT_SIZE_PARAM_U(value) if (value > kMax_UInt) value = kMax_UInt +// Limit 'size_t' values to max values of other used types to avoid overflow +#define LIMIT_SIZE_PARAM_LONG(value) if (value > (size_t)kMax_Long) value = kMax_Long +#define LIMIT_SIZE_PARAM_STREAMSIZE(value) \ + if (value > (size_t)numeric_limits::max()) \ + value = (size_t)numeric_limits::max() + ////////////////////////////////////////////////////////////////////////////// @@ -128,6 +131,10 @@ struct SCompressionParam { CLZOCompression::CLZOCompression(ELevel level, size_t blocksize) : CCompression(level), m_BlockSize(blocksize) { + if (blocksize > kMax_UInt) { + ERR_COMPRESS(41, FormatErrorMessage("CLZOCompression:: block size is too big")); + return; + } m_Param.reset(new SCompressionParam); m_Param->workmem = 0; return; @@ -155,7 +162,7 @@ bool CLZOCompression::Initialize(void) CCompression::ELevel CLZOCompression::GetLevel(void) const { CCompression::ELevel level = CCompression::GetLevel(); - // LZO do not support a zero compression level -- make conversion + // LZO does not support a zero compression level -- make conversion if ( level == eLevel_NoCompression) { return eLevel_Lowest; } @@ -232,13 +239,11 @@ size_t s_CheckLZOHeader(const void* src_buf, size_t src_len, *lzo_flags |= CLZOCompression::fChecksum; } } - // File modification time if (info && ((flags & F_MTIME) != 0) && (pos + 4 < src_len)) { info->mtime = CCompressionUtil::GetUI4(buf + pos); pos += 4; } - // Skip the original file name if ((flags & F_NAME) > 0) { size_t start = pos; @@ -268,6 +273,8 @@ static size_t s_WriteLZOHeader(void* src_buf, size_t buf_size, if (buf_size < kMinHeaderSize) { return 0; } + _ASSERT(block_size <= kMax_UInt); + char* buf = (char*)src_buf; memset(buf, 0, kMinHeaderSize); memcpy(buf, kMagic, kMagicSize); @@ -286,8 +293,7 @@ static size_t s_WriteLZOHeader(void* src_buf, size_t buf_size, } // Original file name. // Store it only if buffer have enough size. - if ( info && !info->name.empty() && - buf_size > (info->name.length() + size) ) { + if ( info && !info->name.empty() && buf_size > (info->name.length() + size) ) { flags |= F_NAME; strncpy((char*)buf + size, info->name.data(), info->name.length()); size += info->name.length(); @@ -295,11 +301,9 @@ static size_t s_WriteLZOHeader(void* src_buf, size_t buf_size, } // File comment. // Store it only if buffer have enough size. - if ( info && !info->comment.empty() && - buf_size > (info->comment.length() + size) ) { + if ( info && !info->comment.empty() && buf_size > (info->comment.length() + size) ) { flags |= F_COMMENT; - strncpy((char*)buf + size, info->comment.data(), - info->comment.length()); + strncpy((char*)buf + size, info->comment.data(), info->comment.length()); size += info->comment.length(); buf[size++] = '\0'; } @@ -378,6 +382,7 @@ int CLZOCompression::CompressBlockStream(const void* src_buf, } // Compress buffer int errcode = CompressBlock(src_buf, src_len, (lzo_bytep)dst_buf + offset, dst_len); + _ASSERT(*dst_len <= kMax_UInt); // Write size of compressed block CCompressionUtil::StoreUI4(dst_buf, (unsigned long)(*dst_len)); @@ -472,43 +477,39 @@ bool CLZOCompression::CompressBuffer( *dst_len = 0; // Check parameters - if ( !src_len ) { - if ( !F_ISSET(fAllowEmptyData) ) { - src_buf = NULL; - } - } - if ( !src_buf ) { - SetError(LZO_E_ERROR, "bad argument"); - ERR_COMPRESS(35, FormatErrorMessage("CLZOCompression::CompressBuffer")); - return false; + if (!src_len && !F_ISSET(fAllowEmptyData)) { + src_buf = NULL; } - if ( !dst_buf || !dst_len ) { + if (!src_buf || !dst_buf || !dst_len) { SetError(LZO_E_ERROR, "bad argument"); ERR_COMPRESS(35, FormatErrorMessage("CLZOCompression::CompressBuffer")); return false; } - if (src_len > kMax_UInt) { - SetError(LZO_E_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(36, FormatErrorMessage("CLZOCompression::CompressBuffer")); - return false; - } - LIMIT_SIZE_PARAM_U(dst_size); // Determine block size used for compression. // For small amount of data use blocksize equal to the source - // buffer size, for big -- use specified block size (m_BlockSize). + // buffer size, for bigger -- use specified block size (m_BlockSize). // This can help to reduce memory usage at decompression stage. size_t block_size = src_len; - if ( F_ISSET(fStreamFormat) && block_size > m_BlockSize) { - block_size = m_BlockSize; + if ( F_ISSET(fStreamFormat) ) { + if ( block_size > m_BlockSize) { + block_size = m_BlockSize; + } + } else { + if (src_len > kMax_UInt) { + SetError(LZO_E_NOT_COMPRESSIBLE, + "size of the source buffer is too big, " \ + "please use CLZOCompression::fStreamFormat flag"); + } } - // LZO doesn't have "safe" algorithm for compression, so we should // check output buffer size to avoid memory overrun. if ( dst_size < EstimateCompressionBufferSize(src_len, block_size) ) { - SetError(LZO_E_OUTPUT_OVERRUN, - GetLZOErrorDescription(LZO_E_OUTPUT_OVERRUN)); - ERR_COMPRESS(37, FormatErrorMessage("CLZOCompression::CompressBuffer")); + SetError(LZO_E_OUTPUT_OVERRUN, GetLZOErrorDescription(LZO_E_OUTPUT_OVERRUN)); + } + + if ( GetErrorCode() != LZO_E_OK ) { + ERR_COMPRESS(36, FormatErrorMessage("CLZOCompression::CompressBuffer")); return false; } @@ -579,26 +580,15 @@ bool CLZOCompression::DecompressBuffer( } src_buf = NULL; } - if ( !src_buf ) { + if (!src_buf || !dst_buf || !dst_len) { SetError(LZO_E_ERROR, "bad argument"); ERR_COMPRESS(85, FormatErrorMessage("CLZOCompression::DecompressBuffer")); return false; } - if ( !dst_buf || !dst_len ) { - SetError(LZO_E_ERROR, "bad argument"); - ERR_COMPRESS(85, FormatErrorMessage("CLZOCompression::DecompressBuffer")); - return false; - } - if (src_len > kMax_UInt) { - SetError(LZO_E_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(39, FormatErrorMessage("CLZOCompression::DecompressBuffer")); - return false; - } - LIMIT_SIZE_PARAM_U(dst_size); // Size of destination buffer size_t out_len = dst_size; - int errcode = LZO_E_OK; + int errcode = LZO_E_ERROR; bool is_first_block = true; if ( F_ISSET(fStreamFormat) ) { @@ -634,10 +624,17 @@ bool CLZOCompression::DecompressBuffer( *dst_len = (char*)dst - (char*)dst_buf; } } else { - // Decompress whole buffer as one big block - errcode = DecompressBlock((lzo_bytep)src_buf, src_len, - (lzo_bytep)dst_buf, &out_len, GetFlags()); - *dst_len = out_len; + if (src_len > kMax_UInt) { + errcode = LZO_E_NOT_COMPRESSIBLE; + SetError(LZO_E_NOT_COMPRESSIBLE, + "size of the source data is too big, " \ + "probably you forgot to specify CLZOCompression::fStreamFormat flag"); + } else { + // Decompress whole buffer as one big block + errcode = DecompressBlock((lzo_bytep)src_buf, src_len, + (lzo_bytep)dst_buf, &out_len, GetFlags()); + *dst_len = out_len; + } } // Check on errors if ( errcode != LZO_E_OK) { @@ -658,8 +655,7 @@ bool CLZOCompression::DecompressBuffer( // Applicable for next algorithms: // LZO1, LZO1A, LZO1B, LZO1C, LZO1F, LZO1X, LZO1Y, LZO1Z. -size_t CLZOCompression::EstimateCompressionBufferSize(size_t src_len, - size_t block_size) +size_t CLZOCompression::EstimateCompressionBufferSize(size_t src_len, size_t block_size) { return EstimateCompressionBufferSize(src_len, block_size, GetFlags()); } @@ -848,8 +844,7 @@ bool CLZOCompressionFile::Open(const string& file_name, EMode mode) } -bool CLZOCompressionFile::Open(const string& file_name, EMode mode, - SFileInfo* info) +bool CLZOCompressionFile::Open(const string& file_name, EMode mode, SFileInfo* info) { m_Mode = mode; @@ -859,8 +854,7 @@ bool CLZOCompressionFile::Open(const string& file_name, EMode mode, IOS_BASE::in | IOS_BASE::binary); } else { m_File = new CNcbiFstream(file_name.c_str(), - IOS_BASE::out | IOS_BASE::binary | - IOS_BASE::trunc); + IOS_BASE::out | IOS_BASE::binary | IOS_BASE::trunc); } if ( !m_File->good() ) { Close(); @@ -919,7 +913,8 @@ bool CLZOCompressionFile::Open(const string& file_name, EMode mode, long CLZOCompressionFile::Read(void* buf, size_t len) { - LIMIT_SIZE_PARAM(len); + LIMIT_SIZE_PARAM_LONG(len); + LIMIT_SIZE_PARAM_STREAMSIZE(len); if ( !m_Stream || m_Mode != eMode_Read ) { NCBI_THROW(CCompressionException, eCompressionFile, @@ -957,8 +952,9 @@ long CLZOCompressionFile::Write(const void* buf, size_t len) if (len == 0) { return 0; } - LIMIT_SIZE_PARAM(len); - + LIMIT_SIZE_PARAM_LONG(len); + LIMIT_SIZE_PARAM_STREAMSIZE(len); + m_Stream->write((char*)buf, len); if ( m_Stream->good() ) { return (long)len; @@ -1027,8 +1023,7 @@ void CLZOBuffer::ResetBuffer(size_t in_bufsize, size_t out_bufsize) // -CLZOCompressor::CLZOCompressor( - ELevel level, size_t blocksize, TLZOFlags flags) +CLZOCompressor::CLZOCompressor(ELevel level, size_t blocksize, TLZOFlags flags) : CLZOCompression(level, blocksize), m_NeedWriteHeader(true) { SetFlags(flags | fStreamFormat); @@ -1075,23 +1070,15 @@ CCompressionProcessor::EStatus CLZOCompressor::Process( /* out */ size_t* out_avail) { *out_avail = 0; - if (in_len > kMax_UInt) { - SetError(LZO_E_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(41, FormatErrorMessage("CLZOCompressor::Process")); - return eStatus_Error; - } if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); - CCompressionProcessor::EStatus status = eStatus_Success; // Write file header if ( m_NeedWriteHeader ) { size_t header_len = s_WriteLZOHeader(m_OutEndPtr, m_OutSize, - m_BlockSize, - GetFlags(), &m_FileInfo); + m_BlockSize, GetFlags(), &m_FileInfo); if (!header_len) { SetError(-1, "Cannot write LZO header"); ERR_COMPRESS(42, FormatErrorMessage("LZOCompressor::Process")); @@ -1108,7 +1095,7 @@ CCompressionProcessor::EStatus CLZOCompressor::Process( memcpy(m_InBuf + m_InLen, in_buf, n); *in_avail = in_len - n; m_InLen += n; - IncreaseProcessedSize((unsigned long)n); + IncreaseProcessedSize(n); } else { // New data has not processed *in_avail = in_len; @@ -1138,8 +1125,7 @@ CCompressionProcessor::EStatus CLZOCompressor::Flush( if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); - + // If we have some data in the output cache buffer -- return it if ( m_OutEndPtr != m_OutBegPtr ) { if ( !out_size ) { @@ -1149,7 +1135,7 @@ CCompressionProcessor::EStatus CLZOCompressor::Flush( memcpy(out_buf, m_OutBegPtr, n); *out_avail = n; m_OutBegPtr += n; - IncreaseOutputSize((unsigned long)n); + IncreaseOutputSize(n); // Here is still some data in the output cache buffer if (m_OutBegPtr != m_OutEndPtr) { return eStatus_Overflow; @@ -1170,8 +1156,7 @@ CCompressionProcessor::EStatus CLZOCompressor::Finish( if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); - + // If we have some already processed data in the output cache buffer if ( m_OutEndPtr != m_OutBegPtr ) { EStatus status = Flush(out_buf, out_size, out_avail); @@ -1200,7 +1185,7 @@ CCompressionProcessor::EStatus CLZOCompressor::Finish( GetFlags(), &m_FileInfo); if (!header_len) { SetError(-1, "Cannot write LZO header"); - ERR_COMPRESS(42, FormatErrorMessage("LZOCompressor::Process")); + ERR_COMPRESS(44, FormatErrorMessage("LZOCompressor::Process")); return eStatus_Error; } m_OutEndPtr += header_len; @@ -1300,17 +1285,10 @@ CCompressionProcessor::EStatus CLZODecompressor::Process( /* out */ size_t* out_avail) { *out_avail = 0; - if (in_len > kMax_UInt) { - SetError(LZO_E_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(44, FormatErrorMessage("CLZODecompressor::Process")); - return eStatus_Error; - } - *in_avail = in_len; + *in_avail = in_len; if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); - CCompressionProcessor::EStatus status = eStatus_Success; try { @@ -1321,17 +1299,15 @@ CCompressionProcessor::EStatus CLZODecompressor::Process( size_t n = min(m_HeaderLen - m_Cache.size(), in_len); m_Cache.append(in_buf, n); *in_avail = in_len - n; - IncreaseProcessedSize((unsigned long)n); + IncreaseProcessedSize(n); if ( m_Cache.size() < kMaxHeaderSize ) { // All data was cached - success state return eStatus_Success; } } // Check header - size_t header_len = s_CheckLZOHeader(m_Cache.data(), - m_Cache.size(), - &m_BlockSize, - &m_HeaderFlags); + size_t header_len = s_CheckLZOHeader(m_Cache.data(), m_Cache.size(), + &m_BlockSize, &m_HeaderFlags); if ( !header_len ) { if ( !F_ISSET(fAllowTransparentRead) ) { SetError(LZO_E_ERROR, "LZO header missing"); @@ -1344,10 +1320,10 @@ CCompressionProcessor::EStatus CLZODecompressor::Process( // Initialize buffers. The input buffer should store // the block of data compressed with the same block size. // Output buffer should have size of uncompressed block. - ResetBuffer(EstimateCompressionBufferSize(m_BlockSize, - m_BlockSize, - m_HeaderFlags), - m_BlockSize); + ResetBuffer( + EstimateCompressionBufferSize(m_BlockSize, m_BlockSize, m_HeaderFlags), + m_BlockSize + ); // Move unprocessed data from cache to begin of the buffer. m_InLen = m_Cache.size() - header_len; memmove(m_InBuf, m_Cache.data() + header_len, m_InLen); @@ -1369,10 +1345,10 @@ CCompressionProcessor::EStatus CLZODecompressor::Process( n = min(*in_avail, out_size); memcpy(out_buf, in_buf + in_len - *in_avail, n); *in_avail -= n; - IncreaseProcessedSize((unsigned long)n); + IncreaseProcessedSize(n); } *out_avail = n; - IncreaseOutputSize((unsigned long)n); + IncreaseOutputSize(n); return eStatus_Success; } @@ -1390,7 +1366,7 @@ CCompressionProcessor::EStatus CLZODecompressor::Process( memcpy(m_InBuf + m_InLen, in_buf + in_len - *in_avail, n); *in_avail -= n; m_InLen += n; - IncreaseProcessedSize((unsigned long)n); + IncreaseProcessedSize(n); } if ( m_InLen >= 4 ) { size_t block_len = CCompressionUtil::GetUI4(m_InBuf); @@ -1418,12 +1394,11 @@ CCompressionProcessor::EStatus CLZODecompressor::Process( if ( m_BlockLen ) { // Cache data until whole block is not in the input buffer if ( m_InLen < m_BlockLen ) { - // Fill it in using data from 'in_buf' size_t n = min(m_BlockLen - m_InLen, *in_avail); memcpy(m_InBuf + m_InLen, in_buf + in_len - *in_avail, n); *in_avail -= n; m_InLen += n; - IncreaseProcessedSize((unsigned long)n); + IncreaseProcessedSize(n); } // If the input cache buffer have a full block and // no data in the output cache buffer -- decompress it @@ -1456,15 +1431,14 @@ CCompressionProcessor::EStatus CLZODecompressor::Flush( if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); - + // If we have some data in the output cache buffer -- return it if ( m_DecompressMode != eMode_Unknown && m_OutEndPtr != m_OutBegPtr ) { size_t n = min((size_t)(m_OutEndPtr - m_OutBegPtr), out_size); memcpy(out_buf, m_OutBegPtr, n); *out_avail = n; m_OutBegPtr += n; - IncreaseOutputSize((unsigned long)n); + IncreaseOutputSize(n); // Here is still some data in the output cache buffer if (m_OutBegPtr != m_OutEndPtr) { return eStatus_Overflow; @@ -1485,8 +1459,7 @@ CCompressionProcessor::EStatus CLZODecompressor::Finish( if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); - + if ( m_DecompressMode == eMode_Unknown ) { if (m_Cache.size() < kMinHeaderSize) { if ( !m_Cache.size() && F_ISSET(fAllowEmptyData) ) { @@ -1500,8 +1473,7 @@ CCompressionProcessor::EStatus CLZODecompressor::Finish( CCompressionProcessor::EStatus status = eStatus_Success; while (status == eStatus_Success) { size_t x_out_avail = 0; - status = Process(0, 0, out_buf, out_size, - &in_avail, &x_out_avail); + status = Process(0, 0, out_buf, out_size, &in_avail, &x_out_avail); if (status == eStatus_Success && !x_out_avail) { return eStatus_Error; } diff --git a/c++/src/util/compress/api/stream.cpp b/c++/src/util/compress/api/stream.cpp index 990555d0..48d5d7af 100644 --- a/c++/src/util/compress/api/stream.cpp +++ b/c++/src/util/compress/api/stream.cpp @@ -1,4 +1,4 @@ -/* $Id: stream.cpp 500279 2016-05-03 17:12:04Z ivanov $ +/* $Id: stream.cpp 539121 2017-06-19 14:00:47Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -86,12 +86,12 @@ void CCompressionStreamProcessor::Init(void) init_status = m_Processor->Init(); } } - m_InBuf = 0; - m_OutBuf = 0; - m_Begin = 0; - m_End = 0; - m_LastStatus = init_status; - m_State = eInit; + m_InBuf = 0; + m_OutBuf = 0; + m_Begin = 0; + m_End = 0; + m_LastStatus = init_status; + m_State = eInit; } @@ -133,12 +133,14 @@ void CCompressionStream::Create(CNcbiIos& stream, m_Ownership = ownership; // Create a new stream buffer - auto_ptr sb( - new CCompressionStreambuf(&stream, read_sp, write_sp)); + unique_ptr sb(new CCompressionStreambuf(&stream, read_sp, write_sp)); init(sb.get()); m_StreamBuf = sb.release(); if ( !m_StreamBuf->IsOkay() ) { setstate(badbit | eofbit); + } else { + // Copy state from the underlying stream + setstate(stream.rdstate()); } } @@ -216,8 +218,7 @@ bool CCompressionStream::x_GetError(CCompressionStream::EDirection dir, } -unsigned long CCompressionStream::x_GetProcessedSize( - CCompressionStream::EDirection dir) +size_t CCompressionStream::x_GetProcessedSize(CCompressionStream::EDirection dir) { CCompressionStreamProcessor* sp = (dir == eRead) ? m_Reader : m_Writer; if (!sp || !sp->m_Processor) { @@ -227,8 +228,7 @@ unsigned long CCompressionStream::x_GetProcessedSize( } -unsigned long CCompressionStream::x_GetOutputSize( - CCompressionStream::EDirection dir) +size_t CCompressionStream::x_GetOutputSize(CCompressionStream::EDirection dir) { CCompressionStreamProcessor* sp = (dir == eRead) ? m_Reader : m_Writer; if (!sp || !sp->m_Processor) { @@ -238,6 +238,81 @@ unsigned long CCompressionStream::x_GetOutputSize( } +size_t CCompressionIStream::Read(void* buf, size_t len) +{ + char* ptr = (char*)buf; + const streamsize kMax = numeric_limits::max(); + while (len) { + streamsize n = len > (size_t)kMax ? kMax : (streamsize)len; + read(ptr, n); + n = gcount(); + if (n <= 0) { + break; + } + len -= n; + ptr += n; + } + return ptr - (char*)buf; +} + + +size_t CCompressionOStream::Write(const void* buf, size_t len) +{ + if (!good()) { + return 0; + } + const char* ptr = (const char*)buf; + const streamsize kMax = numeric_limits::max(); + while (len) { + streamsize n = len > (size_t)kMax ? kMax : (streamsize)len; + write(ptr, n); + if (!good()) { + break; + } + len -= n; + ptr += n; + } + return ptr - (const char*)buf; +} + + +size_t CCompressionIOStream::Read(void* buf, size_t len) +{ + char* ptr = (char*)buf; + const streamsize kMax = numeric_limits::max(); + while (len) { + streamsize n = len > (size_t)kMax ? kMax : (streamsize)len; + read(ptr, n); + n = gcount(); + if (n <= 0) { + break; + } + len -= n; + ptr += n; + } + return ptr - (char*)buf; +} + + +size_t CCompressionIOStream::Write(const void* buf, size_t len) +{ + if (!good()) { + return 0; + } + const char* ptr = (const char*)buf; + const streamsize kMax = numeric_limits::max(); + while (len) { + streamsize n = len > (size_t)kMax ? kMax : (streamsize)len; + write(ptr, n); + if (!good()) { + break; + } + len -= n; + ptr += n; + } + return ptr - (const char*)buf; +} + ////////////////////////////////////////////////////////////////////////////// // @@ -276,8 +351,8 @@ CCompressionProcessor::EStatus CTransparentProcessor::Process( memcpy(out_buf, in_buf, n); *in_avail = in_len - n; *out_avail = n; - IncreaseProcessedSize((unsigned long)n); - IncreaseOutputSize((unsigned long)n); + IncreaseProcessedSize(n); + IncreaseOutputSize(n); return eStatus_Success; } diff --git a/c++/src/util/compress/api/tar.cpp b/c++/src/util/compress/api/tar.cpp index 3e5dfa00..6125f6ba 100644 --- a/c++/src/util/compress/api/tar.cpp +++ b/c++/src/util/compress/api/tar.cpp @@ -1,4 +1,4 @@ -/* $Id: tar.cpp 489095 2016-01-08 13:02:41Z ivanov $ +/* $Id: tar.cpp 534861 2017-05-03 12:50:28Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1565,10 +1565,10 @@ void CTar::x_Open(EAction action) } -auto_ptr CTar::Extract(void) +unique_ptr CTar::Extract(void) { x_Open(eExtract); - auto_ptr entries = x_ReadAndProcess(eExtract); + unique_ptr entries = x_ReadAndProcess(eExtract); // Restore attributes of "postponed" directory entries if (m_Flags & fPreserveAll) { @@ -1594,7 +1594,7 @@ const CTarEntryInfo* CTar::GetNextEntryInfo(void) } else { x_Open(eInternal); } - auto_ptr temp = x_ReadAndProcess(eInternal); + unique_ptr temp = x_ReadAndProcess(eInternal); _ASSERT(temp.get() && temp->size() < 2); if (temp->size() < 1) { return 0; @@ -2411,6 +2411,13 @@ CTar::EStatus CTar::x_ReadEntryInfo(bool dump, bool pax) } +static inline void sx_Signature(TBlock* block) +{ + _ASSERT(sizeof(block->header) + 4 < sizeof(block->buffer)); + memcpy(block->buffer + sizeof(*block) - 4, "NCBI", 4); +} + + void CTar::x_WriteEntryInfo(const string& name) { // Prepare block info @@ -2419,15 +2426,16 @@ void CTar::x_WriteEntryInfo(const string& name) memset(block.buffer, 0, sizeof(block.buffer)); SHeader* h = &block.header; - CTarEntryInfo::EType type = m_Current.GetType(); - // Name(s) ('\0'-terminated if fit entirely, otherwise not) - if (!x_PackName(h, m_Current, false)) { + if (!x_PackCurrentName(h, false)) { TAR_THROW(this, eNameTooLong, "Name '" + m_Current.GetName() + "' too long in" " entry '" + name + '\''); } - if (type == CTarEntryInfo::eSymLink && !x_PackName(h, m_Current, true)) { + + CTarEntryInfo::EType type = m_Current.GetType(); + + if (type == CTarEntryInfo::eSymLink && !x_PackCurrentName(h, true)) { TAR_THROW(this, eNameTooLong, "Link '" + m_Current.GetLinkName() + "' too long in" " entry '" + name + '\''); @@ -2564,8 +2572,7 @@ void CTar::x_WriteEntryInfo(const string& name) // NCBI signature if allowed if (!(m_Flags & fStandardHeaderOnly)) { - _ASSERT(sizeof(block.header) + 4 < sizeof(block.buffer)); - memcpy(block.buffer + sizeof(block) - 4, "NCBI", 4); + sx_Signature(&block); } // Final step: checksumming @@ -2582,11 +2589,11 @@ void CTar::x_WriteEntryInfo(const string& name) } -bool CTar::x_PackName(STarHeader* h, const CTarEntryInfo& info, bool link) +bool CTar::x_PackCurrentName(STarHeader* h, bool link) { - size_t size = link ? sizeof(h->linkname) : sizeof(h->name); - const string& name = link ? info.GetLinkName() : info.GetName(); - char* dst = link ? h->linkname : h->name; + const string& name = link ? m_Current.GetLinkName() : m_Current.GetName(); + size_t size = link ? sizeof(h->linkname) : sizeof(h->name); + char* dst = link ? h->linkname : h->name; const char* src = name.c_str(); size_t len = name.size(); @@ -2596,6 +2603,7 @@ bool CTar::x_PackName(STarHeader* h, const CTarEntryInfo& info, bool link) return true; } + bool packed = false; if (!link && len <= sizeof(h->prefix) + 1 + sizeof(h->name)) { // Try to split the long name into a prefix and a short name (POSIX) size_t i = len; @@ -2606,12 +2614,16 @@ bool CTar::x_PackName(STarHeader* h, const CTarEntryInfo& info, bool link) if (i && len - i <= sizeof(h->name) + 1) { memcpy(h->prefix, src, i); memcpy(h->name, src + i + 1, len - i - 1); - return true; + if (!(m_Flags & fLongNameSupplement)) + return true; + packed = true; } } // Still, store the initial part in the original header - memcpy(dst, src, size); + if (!packed) { + memcpy(dst, src, size); + } // Prepare extended block header with the long name info (old GNU style) _ASSERT(!OFFSET_OF(m_BufferPos) && m_BufferPos < m_BufferSize); @@ -2634,6 +2646,11 @@ bool CTar::x_PackName(STarHeader* h, const CTarEntryInfo& info, bool link) // Old GNU magic protrudes into adjacent version field memcpy(h->magic, "ustar ", 8); // 2 spaces and '\0'-terminated + // NCBI signature if allowed + if (!(m_Flags & fStandardHeaderOnly)) { + sx_Signature(block); + } + s_TarChecksum(block, true); // Write the header @@ -2731,9 +2748,9 @@ static bool s_MatchPattern(const list& elems, } -auto_ptr CTar::x_ReadAndProcess(EAction action) +unique_ptr CTar::x_ReadAndProcess(EAction action) { - auto_ptr done(new TEntries); + unique_ptr done(new TEntries); _ASSERT(!OFFSET_OF(m_StreamPos)); Uint8 pos = m_StreamPos; CTarEntryInfo xinfo; @@ -2971,13 +2988,13 @@ bool CTar::x_ProcessEntry(bool extract, Uint8 size, if (extract) { // Destination for extraction - auto_ptr dst + unique_ptr dst (CDirEntry::CreateObject(CDirEntry::EType(type), CDirEntry::NormalizePath (CDirEntry::ConcatPath (m_BaseDir, m_Current.GetName())))); // Source for extraction - auto_ptr src; + unique_ptr src; // Direntry pending removal AutoPtr pending; @@ -3142,7 +3159,7 @@ bool CTar::x_ExtractEntry(Uint8& size, const CDirEntry* dst, const CDirEntry* src) { CTarEntryInfo::EType type = m_Current.GetType(); - auto_ptr src_ptr; // deleter + unique_ptr src_ptr; // deleter bool result = true; // assume best if (type == CTarEntryInfo::eUnknown && !(m_Flags & fSkipUnsupported)) { @@ -3369,7 +3386,7 @@ void CTar::x_RestoreAttrs(const CTarEntryInfo& info, const CDirEntry* path, TTarMode perm) const { - auto_ptr path_ptr; // deleter + unique_ptr path_ptr; // deleter if (!path) { path_ptr.reset(CDirEntry::CreateObject (CDirEntry::EType(info.GetType()), @@ -3539,11 +3556,11 @@ static string s_ToArchiveName(const string& base_dir, const string& path) } -auto_ptr CTar::x_Append(const string& name, +unique_ptr CTar::x_Append(const string& name, const TEntries* toc) { - auto_ptr entries(new TEntries); - auto_ptr dir; + unique_ptr entries(new TEntries); + unique_ptr dir; const EFollowLinks follow_links = (m_Flags & fFollowLinks ? eFollowLinks : eIgnoreLinks); @@ -3703,7 +3720,7 @@ auto_ptr CTar::x_Append(const string& name, } // Append/update all files from that directory ITERATE(CDir::TEntries, e, *dir) { - auto_ptr add = x_Append((*e)->GetPath(), toc); + unique_ptr add = x_Append((*e)->GetPath(), toc); entries->splice(entries->end(), *add); } break; @@ -3740,10 +3757,10 @@ auto_ptr CTar::x_Append(const string& name, } -auto_ptr CTar::x_Append(const CTarUserEntryInfo& entry, +unique_ptr CTar::x_Append(const CTarUserEntryInfo& entry, CNcbiIstream& is) { - auto_ptr entries(new TEntries); + unique_ptr entries(new TEntries); // Create a temp entry info first m_Current = CTarEntryInfo(m_StreamPos); @@ -4079,16 +4096,16 @@ ERW_Result CTarReader::PendingCount(size_t* count) IReader* CTar::Extract(CNcbiIstream& is, const string& name, CTar::TFlags flags) { - auto_ptr tar(new CTar(is, 1/*blocking factor*/)); + unique_ptr tar(new CTar(is, 1/*blocking factor*/)); tar->SetFlags(flags & ~fStreamPipeThrough); - auto_ptr mask(new CMaskFileName); + unique_ptr mask(new CMaskFileName); mask->Add(name); tar->SetMask(mask.get(), eTakeOwnership); mask.release(); tar->x_Open(eInternal); - auto_ptr temp = tar->x_ReadAndProcess(eInternal); + unique_ptr temp = tar->x_ReadAndProcess(eInternal); _ASSERT(temp.get() && temp->size() < 2); if (temp->size() < 1) { return 0; diff --git a/c++/src/util/compress/api/zlib.cpp b/c++/src/util/compress/api/zlib.cpp index b3434c21..3661f748 100644 --- a/c++/src/util/compress/api/zlib.cpp +++ b/c++/src/util/compress/api/zlib.cpp @@ -1,4 +1,4 @@ -/* $Id: zlib.cpp 500279 2016-05-03 17:12:04Z ivanov $ +/* $Id: zlib.cpp 539121 2017-06-19 14:00:47Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -25,7 +25,7 @@ * * Authors: Vladimir Ivanov * Jean-loup Gailly, Mark Adler - * (used a part of zlib library code from files gzio.c, uncompr.c) + * (used a part of zlib library code from: gzio.c, uncompr.c) * * File Description: ZLib Compression API * @@ -70,13 +70,21 @@ BEGIN_NCBI_SCOPE // Get compression stream pointer #define STREAM ((z_stream*)m_Stream) -// Convert 'size_t' to '[unsigned] int' which used internally in zlib -#define LIMIT_SIZE_PARAM(value) if (value > (size_t)kMax_Int) value = kMax_Int -#define LIMIT_SIZE_PARAM_U(value) if (value > kMax_UInt) value = kMax_UInt +// Limit 'size_t' values to max values of other used types to avoid overflow +#define LIMIT_SIZE_PARAM_LONG(value) if (value > (size_t)kMax_Long) value = kMax_Long +#define LIMIT_SIZE_PARAM_UINT(value) if (value > kMax_UInt) value = kMax_UInt +#define LIMIT_SIZE_PARAM_STREAMSIZE(value) \ + if (value > (size_t)numeric_limits::max()) \ + value = (size_t)numeric_limits::max() // Maximum size of gzip file header const size_t kMaxHeaderSize = 1024*4; +// Maximum size of the chuck compressed by zlib, +// but there is no limit to the number of chunks in the buffer. +const unsigned int kMaxChunkSize = kMax_UInt; + + ////////////////////////////////////////////////////////////////////////////// // @@ -87,12 +95,9 @@ CZipCompression::CZipCompression(ELevel level, int window_bits, int mem_level, int strategy) : CCompression(level) { - m_WindowBits = ( window_bits == kZlibDefaultWbits ) ? MAX_WBITS : - window_bits; - m_MemLevel = ( mem_level == kZlibDefaultMemLevel )? DEF_MEM_LEVEL : - mem_level; - m_Strategy = ( strategy == kZlibDefaultStrategy ) ? Z_DEFAULT_STRATEGY : - strategy; + m_WindowBits = ( window_bits == kZlibDefaultWbits ) ? MAX_WBITS : window_bits; + m_MemLevel = ( mem_level == kZlibDefaultMemLevel ) ? DEF_MEM_LEVEL : mem_level; + m_Strategy = ( strategy == kZlibDefaultStrategy ) ? Z_DEFAULT_STRATEGY : strategy; // Initialize the compressor stream structure m_Stream = new z_stream; if ( m_Stream ) { @@ -186,22 +191,23 @@ size_t s_CheckGZipHeader(const void* src_buf, size_t src_len, } -static size_t s_WriteGZipHeader(void* src_buf, size_t buf_size, - const CZipCompression::SFileInfo* info = 0) +static +size_t s_WriteGZipHeader(void* dst_buf, size_t dst_size, + const CZipCompression::SFileInfo* info = 0) { - char* buf = (char*)src_buf; + char* buf = (char*)dst_buf; // .gz header cannot be less than 10 bytes - if (buf_size < 10) { + if (dst_size < 10) { + // error return 0; } unsigned char flags = 0; - size_t header_len = 10; // write beginnning of header later + size_t header_len = 10; // set first 10 bytes of header later // Store the original file name. // Store it only if buffer have enough size. - if ( info && !info->name.empty() && - buf_size > (info->name.length() + header_len) ) { + if ( info && !info->name.empty() && dst_size > (info->name.length() + header_len) ) { flags |= ORIG_NAME; strncpy((char*)buf+header_len, info->name.data(),info->name.length()); header_len += info->name.length(); @@ -210,7 +216,7 @@ static size_t s_WriteGZipHeader(void* src_buf, size_t buf_size, // Store file comment. // Store it only if buffer have enough size. if ( info && !info->comment.empty() && - buf_size > (info->comment.length() + header_len) ) { + dst_size > (info->comment.length() + header_len) ) { flags |= COMMENT; strncpy((char*)buf+header_len, info->comment.data(), info->comment.length()); @@ -235,27 +241,25 @@ static size_t s_WriteGZipHeader(void* src_buf, size_t buf_size, } -// For files > 4GB, gzip stores just the last 32 bits of the file size. -#define LOW32(i) (i & 0xFFFFFFFFL) - -static size_t s_WriteGZipFooter(void* buf, - size_t buf_size, - unsigned long total, - unsigned long crc) +static +size_t s_WriteGZipFooter(void* buf, size_t buf_size, size_t total, unsigned long crc) { - // .gz footer is 8 bytes length + // .gz footer have 8 bytes if (buf_size < 8) { + // error return 0; } + // 4 bytes for CRC value of the uncompressed data CCompressionUtil::StoreUI4(buf, crc); - CCompressionUtil::StoreUI4((unsigned char*)buf+4, LOW32(total)); - + // 4 bytes for the size of the original (uncompressed) data modulo 2^32 + // For files > 4GB, gzip stores just the last 32 bits of the file size. + CCompressionUtil::StoreUI4((unsigned char*)buf + 4, total & 0xFFFFFFFFL); return 8; } -void s_CollectFileInfo(const string& filename, - CZipCompression::SFileInfo& info) +static +void s_CollectFileInfo(const string& filename, CZipCompression::SFileInfo& info) { CFile file(filename); info.name = file.GetName(); @@ -265,6 +269,32 @@ void s_CollectFileInfo(const string& filename, } +static +unsigned long s_UpdateCRC32(unsigned long crc, const void* buf, size_t len) +{ +#if (ZLIB_VERNUM >= 0x1290) + return crc32_z(0L, (unsigned char*)buf, len); + +#else + unsigned char* ptr = (unsigned char*)buf; + while (len) { + unsigned int n = len > kMaxChunkSize ? kMaxChunkSize : (unsigned int)len; + crc = crc32(crc, ptr, n); + ptr += n; + len -= n; + } + return crc; +#endif +} + + +inline +unsigned long s_GetCRC32(const void* buf, size_t len) +{ + return s_UpdateCRC32(0L, buf, len); +} + + CVersionInfo CZipCompression::GetVersion(void) const { return CVersionInfo(ZLIB_VERSION, "zlib"); @@ -274,35 +304,24 @@ CVersionInfo CZipCompression::GetVersion(void) const bool CZipCompression::CompressBuffer( const void* src_buf, size_t src_len, void* dst_buf, size_t dst_size, - /* out */ size_t* dst_len) + /* out */ size_t* dst_len) { *dst_len = 0; // Check parameters - if ( !src_len ) { - if (!F_ISSET(fAllowEmptyData)) { - src_buf = NULL; - } - } - if ( !src_buf ) { - SetError(Z_STREAM_ERROR, "bad argument"); - ERR_COMPRESS(48, FormatErrorMessage("CZipCompression::CompressBuffer")); - return false; + if (!src_len && !F_ISSET(fAllowEmptyData)) { + src_buf = NULL; } - if ( !dst_buf || !dst_len ) { + if (!src_buf || !dst_buf || !dst_len) { SetError(Z_STREAM_ERROR, "bad argument"); ERR_COMPRESS(48, FormatErrorMessage("CZipCompression::CompressBuffer")); return false; } - if (src_len > kMax_UInt) { - SetError(Z_STREAM_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(49, FormatErrorMessage("CZipCompression::CompressBuffer")); - return false; - } - LIMIT_SIZE_PARAM_U(dst_size); size_t header_len = 0; - int errcode = Z_OK; + int errcode = Z_OK; + // Pointer to the current positions in destination buffer + unsigned char* dst = (unsigned char*)dst_buf; // Write gzip file header if ( F_ISSET(fWriteGZipFormat) ) { @@ -312,58 +331,56 @@ bool CZipCompression::CompressBuffer( ERR_COMPRESS(50, FormatErrorMessage("CZipCompression::CompressBuffer")); return false; } + dst += header_len; + dst_size -= header_len; } - STREAM->next_in = (unsigned char*)src_buf; - STREAM->avail_in = (unsigned int)src_len; -#ifdef MAXSEG_64K - // Check for source > 64K on 16-bit machine: - if ( STREAM->avail_in != src_len ) { - SetError(Z_BUF_ERROR, zError(Z_BUF_ERROR)); - ERR_COMPRESS(51, FormatErrorMessage("CZipCompression::CompressBuffer")); - return false; - } -#endif - STREAM->next_out = (unsigned char*)dst_buf + header_len; - STREAM->avail_out = (unsigned int)(dst_size - header_len); - if ( STREAM->avail_out != dst_size - header_len ) { - SetError(Z_BUF_ERROR, zError(Z_BUF_ERROR)); - ERR_COMPRESS(52, FormatErrorMessage("CZipCompression::CompressBuffer")); - return false; - } - - STREAM->zalloc = (alloc_func)0; - STREAM->zfree = (free_func)0; - STREAM->opaque = (voidpf)0; + STREAM->zalloc = NULL; + STREAM->zfree = NULL; + STREAM->opaque = NULL; errcode = deflateInit2_(STREAM, GetLevel(), Z_DEFLATED, header_len ? -m_WindowBits : m_WindowBits, m_MemLevel, m_Strategy, ZLIB_VERSION, (int)sizeof(z_stream)); if (errcode == Z_OK) { - errcode = deflate(STREAM, Z_FINISH); - *dst_len = STREAM->total_out + header_len; - if (errcode == Z_STREAM_END) { - errcode = deflateEnd(STREAM); - } else { - if ( errcode == Z_OK ) { - errcode = Z_BUF_ERROR; + + STREAM->next_in = (unsigned char*)src_buf; + STREAM->avail_in = 0; + STREAM->next_out = dst; + STREAM->avail_out = 0; + + size_t left = src_len; + do { + if (STREAM->avail_in == 0) { + STREAM->avail_in = left > kMaxChunkSize ? kMaxChunkSize : (unsigned int)left; + left -= STREAM->avail_in; } - deflateEnd(STREAM); - } + if (STREAM->avail_out == 0) { + STREAM->avail_out = dst_size > kMaxChunkSize ? kMaxChunkSize : (unsigned int)dst_size; + dst_size -= STREAM->avail_out; + } + errcode = deflate(STREAM, left ? Z_NO_FLUSH : Z_FINISH); + } + while (errcode == Z_OK); + + // Calculate length of output data. + // Don't use STREAM->total_out here, for source buffers greater + // than 4GB it works if (SIZEOF_LONG > 4) only. + *dst_len = STREAM->next_out - (unsigned char*)dst_buf; + deflateEnd(STREAM); } + SetError(errcode, zError(errcode)); - if ( errcode != Z_OK ) { + if ( errcode != Z_STREAM_END) { ERR_COMPRESS(53, FormatErrorMessage("CZipCompression::CompressBuffer")); return false; } // Write gzip file footer if ( F_ISSET(fWriteGZipFormat) ) { - unsigned long crc = crc32(0L, (unsigned char*)src_buf, - (unsigned int)src_len); - size_t footer_len = s_WriteGZipFooter( - (char*)dst_buf + *dst_len, dst_size, (unsigned long)src_len, crc); + unsigned long crc = s_GetCRC32(src_buf, src_len); + size_t footer_len = s_WriteGZipFooter(STREAM->next_out, dst_size + STREAM->avail_out, src_len, crc); if ( !footer_len ) { SetError(-1, "Cannot write gzip footer"); ERR_COMPRESS(54, FormatErrorMessage("CZipCompressor::CompressBuffer")); @@ -371,6 +388,7 @@ bool CZipCompression::CompressBuffer( } *dst_len += footer_len; } + return true; } @@ -390,102 +408,111 @@ bool CZipCompression::DecompressBuffer( } src_buf = NULL; } - if ( !src_buf ) { + if (!src_buf || !dst_buf || !dst_len) { SetError(Z_STREAM_ERROR, "bad argument"); ERR_COMPRESS(55, FormatErrorMessage("CZipCompression::DecompressBuffer")); return false; } - if ( !dst_buf || !dst_len ) { - SetError(Z_STREAM_ERROR, "bad argument"); - ERR_COMPRESS(55, FormatErrorMessage("CZipCompression::DecompressBuffer")); - return false; - } - if (src_len > kMax_UInt) { - SetError(Z_STREAM_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(56, FormatErrorMessage("CZipCompression::DecompressBuffer")); - return false; - } - LIMIT_SIZE_PARAM_U(dst_size); - - // - bool is_gzip = false; - bool check_header = true; - int errcode = Z_OK; - // Pointers to current positions in src and dst buffers + unsigned int gzip_chunk_count = 0; + int errcode = Z_OK; + // Pointers to the current positions in buffers unsigned char* src = (unsigned char*)src_buf; unsigned char* dst = (unsigned char*)dst_buf; + size_t dst_size_arg = dst_size; do { + STREAM->next_in = src; + STREAM->avail_in = 0; + STREAM->zalloc = NULL; + STREAM->zfree = NULL; + STREAM->opaque = NULL; + // Check file header size_t header_len = 0; - if ( F_ISSET(fCheckFileHeader) && check_header) { + if (F_ISSET(fCheckFileHeader)) { // Check gzip header in the buffer header_len = s_CheckGZipHeader(src_buf, src_len); + if (gzip_chunk_count && !header_len) { + // No more gzip chunks in the concatenated archive, stop processing + break; + } src += header_len; src_len -= header_len; + gzip_chunk_count++; } - STREAM->next_in = src; - STREAM->avail_in = (unsigned int)src_len; - STREAM->next_out = dst; - STREAM->avail_out = (unsigned int)dst_size; - STREAM->zalloc = (alloc_func)0; - STREAM->zfree = (free_func)0; // "window bits" is passed < 0 to tell that there is no zlib header. // Note that in this case inflate *requires* an extra "dummy" byte // after the compressed stream in order to complete decompression and - // return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are + // return Z_STREAM_END. Here the gzip's CRC32 ensures that 4 bytes are // present after the compressed stream. - + errcode = inflateInit2_(STREAM, header_len ? -m_WindowBits :m_WindowBits, ZLIB_VERSION, (int)sizeof(z_stream)); - if (errcode != Z_OK) { break; } - errcode = inflate(STREAM, Z_FINISH); - *dst_len += STREAM->total_out; - // Is decompresion sucess? + STREAM->next_in = src; + STREAM->avail_in = 0; + STREAM->next_out = dst; + STREAM->avail_out = 0; + + size_t left = src_len; + do { + if (STREAM->avail_in == 0) { + STREAM->avail_in = left > kMaxChunkSize ? kMaxChunkSize : (unsigned int)left; + left -= STREAM->avail_in; + } + if (STREAM->avail_out == 0) { + STREAM->avail_out = dst_size > kMaxChunkSize ? kMaxChunkSize : (unsigned int)dst_size; + dst_size -= STREAM->avail_out; + } + errcode = inflate(STREAM, Z_NO_FLUSH); + } while (errcode == Z_OK); + + // Calculate length of output data. + // Don't use STREAM->total_out for source buffers greater than 4GB, + // it works if (SIZEOF_LONG > 4) only. + *dst_len = STREAM->next_out - (unsigned char*)dst_buf; + + // Does decompression succeeded? if (errcode == Z_STREAM_END) { - is_gzip = (header_len > 0); - check_header = F_ISSET(fCheckFileHeader | fAllowConcatenatedGZip); - if ( check_header ) { - src = STREAM->next_in + 8; - src_len = (STREAM->avail_in < 8) ? 0 : (STREAM->avail_in - 8); - dst += STREAM->total_out; - dst_size = STREAM->avail_out; - } else { + + // Concatenated gzip? + if (gzip_chunk_count && F_ISSET(fAllowConcatenatedGZip)) { + // Update pointers and counters to process next gzip chunk. + // NOTE: Don't use STREAM->total_out! (see above) + + src = STREAM->next_in + 8; // skip gzip footer + size_t processed = src - (unsigned char*)src_buf; + src_len = (processed > src_len) ? 0 : (src_len - processed); + dst = STREAM->next_out; + dst_size += STREAM->avail_out; // compensate for unprocessed data + } + else { + // Finish processing src_len = 0; } - errcode = inflateEnd(STREAM); + inflateEnd(STREAM); } else { - // Error -- end decompression + // Error inflateEnd(STREAM); - if ( errcode == Z_OK ) { - // Possible incomplete input data - errcode = Z_BUF_ERROR; - } else { - // Decompression error - if (!is_gzip && F_ISSET(fAllowTransparentRead)) { - // But transparent read is allowed - *dst_len = (dst_size < src_len) ? dst_size : src_len; - memcpy(dst_buf, src_buf, *dst_len); - return (dst_size >= src_len); - } - // Error - break; + if (!gzip_chunk_count && !header_len && F_ISSET(fAllowTransparentRead)) { + // Decompression error, but transparent read is allowed + *dst_len = (dst_size_arg < src_len) ? dst_size_arg : src_len; + memcpy(dst_buf, src_buf, *dst_len); + return (dst_size_arg >= src_len); } + break; } - } while (is_gzip && src_len); + } while (src_len); - // Decompression results processing SetError(errcode, zError(errcode)); - if ( errcode != Z_OK ) { - ERR_COMPRESS(59, FormatErrorMessage - ("CZipCompression::DecompressBuffer", (unsigned long) - (STREAM->next_in - (unsigned char*) src_buf))); + if ( errcode != Z_STREAM_END ) { + ERR_COMPRESS(59, FormatErrorMessage("CZipCompression::DecompressBuffer", + STREAM->next_in - (unsigned char*) src_buf)); return false; } return true; @@ -494,7 +521,7 @@ bool CZipCompression::DecompressBuffer( long CZipCompression::EstimateCompressionBufferSize(size_t src_len) { -#if !defined(ZLIB_VERNUM) || ZLIB_VERNUM < 0x1200 +#if (ZLIB_VERNUM < 0x1200) return -1; #else size_t header_len = 0; @@ -504,9 +531,9 @@ long CZipCompression::EstimateCompressionBufferSize(size_t src_len) // Default empty GZIP header header_len = 10; } - STREAM->zalloc = (alloc_func)0; - STREAM->zfree = (free_func)0; - STREAM->opaque = (voidpf)0; + STREAM->zalloc = NULL; + STREAM->zfree = NULL; + STREAM->opaque = NULL; errcode = deflateInit2_(STREAM, GetLevel(), Z_DEFLATED, header_len ? -m_WindowBits : m_WindowBits, m_MemLevel, m_Strategy, @@ -652,15 +679,14 @@ bool CZipCompression::DecompressFileIntoDir(const string& src_file, } -string CZipCompression::FormatErrorMessage(string where, - unsigned long pos) const +string CZipCompression::FormatErrorMessage(string where, size_t pos) const { string str = "[" + where + "] " + GetErrorDescription(); if ( !pos ) { pos = STREAM->total_in; } str += "; error code = " + NStr::IntToString(GetErrorCode()) + - ", number of processed bytes = " + NStr::ULongToString(pos); + ", number of processed bytes = " + NStr::SizetToString(pos); return str + "."; } @@ -728,8 +754,7 @@ bool CZipCompressionFile::Open(const string& file_name, EMode mode) } -bool CZipCompressionFile::Open(const string& file_name, EMode mode, - SFileInfo* info) +bool CZipCompressionFile::Open(const string& file_name, EMode mode, SFileInfo* info) { m_Mode = mode; @@ -739,8 +764,7 @@ bool CZipCompressionFile::Open(const string& file_name, EMode mode, IOS_BASE::in | IOS_BASE::binary); } else { m_File = new CNcbiFstream(file_name.c_str(), - IOS_BASE::out | IOS_BASE::binary | - IOS_BASE::trunc); + IOS_BASE::out | IOS_BASE::binary | IOS_BASE::trunc); } if ( !m_File->good() ) { Close(); @@ -764,19 +788,14 @@ bool CZipCompressionFile::Open(const string& file_name, EMode mode, // Create compression stream for I/O if ( mode == eMode_Read ) { - CZipDecompressor* decompressor = - new CZipDecompressor(m_WindowBits, GetFlags()); + CZipDecompressor* decompressor = new CZipDecompressor(m_WindowBits, GetFlags()); CCompressionStreamProcessor* processor = new CCompressionStreamProcessor( decompressor, CCompressionStreamProcessor::eDelete, kCompressionDefaultBufSize, kCompressionDefaultBufSize); - m_Stream = - new CCompressionIOStream( - *m_File, processor, 0, CCompressionStream::fOwnReader); + m_Stream = new CCompressionIOStream(*m_File, processor, 0, CCompressionStream::fOwnReader); } else { - CZipCompressor* compressor = - new CZipCompressor( - GetLevel(), m_WindowBits, m_MemLevel, m_Strategy, GetFlags()); + CZipCompressor* compressor = new CZipCompressor(GetLevel(), m_WindowBits, m_MemLevel, m_Strategy, GetFlags()); if ( F_ISSET(fWriteGZipFormat) && info) { // Enable compressor to write info information about // compressed file into gzip file header @@ -786,9 +805,7 @@ bool CZipCompressionFile::Open(const string& file_name, EMode mode, new CCompressionStreamProcessor( compressor, CCompressionStreamProcessor::eDelete, kCompressionDefaultBufSize, kCompressionDefaultBufSize); - m_Stream = - new CCompressionIOStream( - *m_File, 0, processor, CCompressionStream::fOwnWriter); + m_Stream = new CCompressionIOStream(*m_File, 0, processor, CCompressionStream::fOwnWriter); } if ( !m_Stream->good() ) { Close(); @@ -801,7 +818,8 @@ bool CZipCompressionFile::Open(const string& file_name, EMode mode, long CZipCompressionFile::Read(void* buf, size_t len) { - LIMIT_SIZE_PARAM_U(len); + LIMIT_SIZE_PARAM_LONG(len); + LIMIT_SIZE_PARAM_STREAMSIZE(len); if ( !m_Stream || m_Mode != eMode_Read ) { NCBI_THROW(CCompressionException, eCompressionFile, @@ -812,8 +830,7 @@ long CZipCompressionFile::Read(void* buf, size_t len) } m_Stream->read((char*)buf, len); // Check decompression processor status - if ( m_Stream->GetStatus(CCompressionStream::eRead) - == CCompressionProcessor::eStatus_Error ) { + if ( m_Stream->GetStatus(CCompressionStream::eRead) == CCompressionProcessor::eStatus_Error ) { GetStreamError(); return -1; } @@ -835,11 +852,12 @@ long CZipCompressionFile::Write(const void* buf, size_t len) NCBI_THROW(CCompressionException, eCompressionFile, "[CZipCompressionFile::Write] File must be opened for writing"); } - // Redefine standard behaviour for case of writing zero bytes + // Redefine standard behavior for case of writing zero bytes if (len == 0) { return 0; } - LIMIT_SIZE_PARAM(len); + LIMIT_SIZE_PARAM_LONG(len); + LIMIT_SIZE_PARAM_STREAMSIZE(len); m_Stream->write((char*)buf, len); if ( m_Stream->good() ) { @@ -914,8 +932,7 @@ CCompressionProcessor::EStatus CZipCompressor::Init(void) memset(STREAM, 0, sizeof(z_stream)); // Create a compressor stream int errcode = deflateInit2_(STREAM, GetLevel(), Z_DEFLATED, - F_ISSET(fWriteGZipFormat) ? -m_WindowBits : - m_WindowBits, + F_ISSET(fWriteGZipFormat) ? -m_WindowBits : m_WindowBits, m_MemLevel, m_Strategy, ZLIB_VERSION, (int)sizeof(z_stream)); SetError(errcode, zError(errcode)); @@ -934,15 +951,14 @@ CCompressionProcessor::EStatus CZipCompressor::Process( /* out */ size_t* out_avail) { *out_avail = 0; - if (in_len > kMax_UInt) { - SetError(Z_STREAM_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(61, FormatErrorMessage("CZipCompressor::Process", GetProcessedSize())); - return eStatus_Error; - } if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); + // To simplify this method, limit input and output sizes, + // the upper level code will process all necessary data + // in the loop if necessary. + LIMIT_SIZE_PARAM_UINT(in_len); + LIMIT_SIZE_PARAM_UINT(out_size); size_t header_len = 0; @@ -965,8 +981,8 @@ CCompressionProcessor::EStatus CZipCompressor::Process( SetError(errcode, zError(errcode)); *in_avail = STREAM->avail_in; *out_avail = out_size - STREAM->avail_out; - IncreaseProcessedSize((unsigned long)(in_len - *in_avail)); - IncreaseOutputSize((unsigned long)(*out_avail)); + IncreaseProcessedSize(in_len - *in_avail); + IncreaseOutputSize(*out_avail); // If we writing in gzip file format if ( F_ISSET(fWriteGZipFormat) ) { @@ -990,7 +1006,10 @@ CCompressionProcessor::EStatus CZipCompressor::Flush( if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); + // To simplify this method, limit output size, + // the upper level code will process all necessary + // data in the loop if necessary. + LIMIT_SIZE_PARAM_UINT(out_size); STREAM->next_in = 0; STREAM->avail_in = 0; @@ -1000,7 +1019,7 @@ CCompressionProcessor::EStatus CZipCompressor::Flush( int errcode = deflate(STREAM, Z_SYNC_FLUSH); SetError(errcode, zError(errcode)); *out_avail = out_size - STREAM->avail_out; - IncreaseOutputSize((unsigned long)(*out_avail)); + IncreaseOutputSize(*out_avail); if ( errcode == Z_OK || errcode == Z_BUF_ERROR ) { if ( STREAM->avail_out == 0) { @@ -1021,7 +1040,10 @@ CCompressionProcessor::EStatus CZipCompressor::Finish( if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); + // To simplify this method, limit output size, + // the upper level code will process all necessary + // data in the loop if necessary. + LIMIT_SIZE_PARAM_UINT(out_size); // Default behavior on empty data -- don't write header/footer if ( !GetProcessedSize() && !F_ISSET(fAllowEmptyData) ) { @@ -1050,7 +1072,7 @@ CCompressionProcessor::EStatus CZipCompressor::Finish( int errcode = deflate(STREAM, Z_FINISH); SetError(errcode, zError(errcode)); *out_avail = out_size - STREAM->avail_out; - IncreaseOutputSize((unsigned long)(*out_avail)); + IncreaseOutputSize(*out_avail); switch (errcode) { case Z_OK: @@ -1065,7 +1087,7 @@ CCompressionProcessor::EStatus CZipCompressor::Finish( SetError(-1, "Cannot write gzip footer"); return eStatus_Overflow; } - IncreaseOutputSize((unsigned long)footer_len); + IncreaseOutputSize(footer_len); *out_avail += footer_len; } return eStatus_EndOfData; @@ -1129,12 +1151,10 @@ CCompressionProcessor::EStatus CZipDecompressor::Init(void) // Initialize the compressor stream structure memset(STREAM, 0, sizeof(z_stream)); + // Create a compressor stream - int errcode = inflateInit2_(STREAM, m_WindowBits, - ZLIB_VERSION, (int)sizeof(z_stream)); - + int errcode = inflateInit2_(STREAM, m_WindowBits, ZLIB_VERSION, (int)sizeof(z_stream)); SetError(errcode, zError(errcode)); - if ( errcode == Z_OK ) { return eStatus_Success; } @@ -1150,15 +1170,14 @@ CCompressionProcessor::EStatus CZipDecompressor::Process( /* out */ size_t* out_avail) { *out_avail = 0; - if (in_len > kMax_UInt) { - SetError(Z_STREAM_ERROR, "size of the source buffer is too big"); - ERR_COMPRESS(69, FormatErrorMessage("CZipDecompressor::Process", GetProcessedSize())); - return eStatus_Error; - } if ( !out_size ) { return eStatus_Overflow; } - LIMIT_SIZE_PARAM_U(out_size); + // To simplify this method, limit input and output sizes, + // the upper level code will process all necessary data + // in the loop if necessary. + LIMIT_SIZE_PARAM_UINT(in_len); + LIMIT_SIZE_PARAM_UINT(out_size); // By default we consider that data is compressed if ( m_DecompressMode == eMode_Unknown && @@ -1180,7 +1199,7 @@ CCompressionProcessor::EStatus CZipDecompressor::Process( size_t n = min(m_Cache.size(), m_SkipInput); m_Cache.erase(0, n); m_SkipInput -= n; - IncreaseProcessedSize((unsigned long)n); + IncreaseProcessedSize(n); } // And/or from input stream also if ( m_SkipInput ) { @@ -1188,7 +1207,7 @@ CCompressionProcessor::EStatus CZipDecompressor::Process( x_in_buf += n; x_in_len -= n; m_SkipInput -= n; - IncreaseProcessedSize((unsigned long)n); + IncreaseProcessedSize(n); if ( m_SkipInput ) { // Data block is very small... and was skipped. *in_avail = x_in_len; @@ -1231,7 +1250,7 @@ CCompressionProcessor::EStatus CZipDecompressor::Process( // If gzip header found, skip it if ( header_len ) { m_Cache.erase(0, header_len); - IncreaseProcessedSize((unsigned long)header_len); + IncreaseProcessedSize(header_len); m_DecompressMode = eMode_Decompress; m_IsGZ = true; } @@ -1300,10 +1319,10 @@ CCompressionProcessor::EStatus CZipDecompressor::Process( if ( from_cache ) { m_Cache.erase(0, old_avail_in - STREAM->avail_in); *in_avail = x_in_len; - IncreaseProcessedSize((unsigned long)(old_avail_in - STREAM->avail_in)); + IncreaseProcessedSize(old_avail_in - STREAM->avail_in); } else { *in_avail = STREAM->avail_in; - IncreaseProcessedSize((unsigned long)(x_in_len - *in_avail)); + IncreaseProcessedSize(x_in_len - *in_avail); x_in_len = *in_avail; } // In case of concatenated .gz files: @@ -1317,11 +1336,11 @@ CCompressionProcessor::EStatus CZipDecompressor::Process( x_in_len -= n; m_SkipInput -= n; *in_avail = x_in_len; - IncreaseProcessedSize((unsigned long)n); + IncreaseProcessedSize(n); } } *out_avail = out_size - STREAM->avail_out; - IncreaseOutputSize((unsigned long)(*out_avail)); + IncreaseOutputSize(*out_avail); // Analyze decompressor status switch (errcode) { @@ -1358,8 +1377,9 @@ CCompressionProcessor::EStatus CZipDecompressor::Process( } *in_avail = x_in_len; *out_avail = total; - IncreaseProcessedSize((unsigned long)total); - IncreaseOutputSize((unsigned long)total); + IncreaseProcessedSize(total); + IncreaseOutputSize(total); + return eStatus_Success; } @@ -1426,10 +1446,10 @@ void g_GZip_ScanForChunks(CNcbiIstream& is, IChunkHandler& handler) typedef IChunkHandler::TPosition TPos; // Use our own total counters to avoid 4GB limit - TPos in_total = 0; // Offset in input compressed data - TPos out_total = 0; // Offset in output decompressed data + TPos total_in = 0; // Offset in input compressed data + TPos total_out = 0; // Offset in output decompressed data z_stream strm; // Compressed stream structure - int ret = Z_STREAM_END; // zlib return status + int ret = Z_STREAM_END; // zlib return status, init with Z_STREAM_END to get a (0,0) bool initialized = false; @@ -1466,15 +1486,15 @@ void g_GZip_ScanForChunks(CNcbiIstream& is, IChunkHandler& handler) // Next gzip-file? if (ret == Z_STREAM_END) { // Save current position - action = handler.OnChunk(in_total, out_total); + action = handler.OnChunk(total_in, total_out); if (action == IChunkHandler::eAction_Stop) { // Stop scanning break; } // (Re)Initialize inflate - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; + strm.zalloc = NULL; + strm.zfree = NULL; + strm.opaque = NULL; ret = inflateInit2(&strm, 15+16 /* max windowbits + automatic gzip header decoding */); /* NCBI_FAKE_WARNING */ if (ret != Z_OK) { throw "inflateInit2() failed: " + string(zError(ret)); @@ -1492,8 +1512,8 @@ void g_GZip_ScanForChunks(CNcbiIstream& is, IChunkHandler& handler) throw "inflate() failed: " + string(zError(ret)); } // Increase counters - out_total += (out_size - strm.avail_out); - in_total += (nread - strm.avail_in); + total_out += (out_size - strm.avail_out); + total_in += (nread - strm.avail_in); nread = strm.avail_in; // If found end of compressed stream -- cleanup if (ret == Z_STREAM_END) { diff --git a/c++/src/util/compress/bzip2/CMakeLists.bzip2.lib.txt b/c++/src/util/compress/bzip2/CMakeLists.bzip2.lib.txt new file mode 100644 index 00000000..e2085b89 --- /dev/null +++ b/c++/src/util/compress/bzip2/CMakeLists.bzip2.lib.txt @@ -0,0 +1,8 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/util/compress/bzip2/Makefile.bzip2.lib +# +include_directories(${BZ2_INCLUDE}) + +add_library(bz2 + blocksort huffman crctable randtable ncbi_bz2_compress decompress bzlib +) diff --git a/c++/src/util/compress/bzip2/CMakeLists.txt b/c++/src/util/compress/bzip2/CMakeLists.txt new file mode 100644 index 00000000..2999b693 --- /dev/null +++ b/c++/src/util/compress/bzip2/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.bzip2.lib.txt) + diff --git a/c++/src/util/compress/zlib/CMakeLists.txt b/c++/src/util/compress/zlib/CMakeLists.txt new file mode 100644 index 00000000..9cd496be --- /dev/null +++ b/c++/src/util/compress/zlib/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.zlib.lib.txt) + diff --git a/c++/src/util/compress/zlib/CMakeLists.zlib.lib.txt b/c++/src/util/compress/zlib/CMakeLists.zlib.lib.txt new file mode 100644 index 00000000..ffed0661 --- /dev/null +++ b/c++/src/util/compress/zlib/CMakeLists.zlib.lib.txt @@ -0,0 +1,10 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/util/compress/zlib/Makefile.zlib.lib +# +add_library(z + adler32 crc32 deflate infback inffast inflate inftrees trees zutil + ncbi_z_compress uncompr gzclose gzlib gzread gzwrite +) + +include_directories(SYSTEM ${includedir}/util/compress/zlib) + diff --git a/c++/src/util/creaders/CMakeLists.creaders.lib.txt b/c++/src/util/creaders/CMakeLists.creaders.lib.txt new file mode 100644 index 00000000..36bbd26b --- /dev/null +++ b/c++/src/util/creaders/CMakeLists.creaders.lib.txt @@ -0,0 +1,6 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/util/creaders/Makefile.creaders.lib +# +add_library(creaders + alnread +) diff --git a/c++/src/util/creaders/CMakeLists.txt b/c++/src/util/creaders/CMakeLists.txt new file mode 100644 index 00000000..52f8cfa9 --- /dev/null +++ b/c++/src/util/creaders/CMakeLists.txt @@ -0,0 +1,7 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.creaders.lib.txt) + diff --git a/c++/src/util/creaders/alnread.c b/c++/src/util/creaders/alnread.c index e46153c7..d94496cf 100644 --- a/c++/src/util/creaders/alnread.c +++ b/c++/src/util/creaders/alnread.c @@ -1,5 +1,5 @@ /* - * $Id: alnread.c 489147 2016-01-08 19:29:35Z ivanov $ + * $Id: alnread.c 545073 2017-08-31 14:30:14Z ivanov $ * * =========================================================================== * @@ -2689,8 +2689,7 @@ static EBool s_IsOrganismComment (TCommentLocPtr clp) /* This function finds an organism comment, which includes the first bracketed - * comment with org= or organism=, plus any additional bracketed comments - * separated only by whitespace from the org= or organism= comment. + * comment with org= or organism=, plus any additional bracketed comments. * The function returns a pointer to a SCommentLoc structure describing * the location of the organism comment. */ @@ -2712,10 +2711,9 @@ static TCommentLocPtr s_FindOrganismComment (char * string) } next_clp = s_FindComment (clp->end); - while (next_clp != NULL && - (int) strspn (clp->end + 1, " \t\r") == next_clp->start - clp->end - 1 - && ! s_IsOrganismComment (next_clp)) - { + while (next_clp != NULL && + !s_IsOrganismComment(next_clp)) + { clp->end = next_clp->end; next_clp = s_FindComment (clp->end); } @@ -2932,6 +2930,7 @@ static void s_ReadOrgNamesFromText s_ReportOrgCommentError (string, afrp->report_error, afrp->report_error_userdata); } while (clp != NULL) { + org_name = s_CreateOrderedOrgName (clp); afrp->organisms = s_AddLineInfo (afrp->organisms, org_name, line_num, clp->start - string); @@ -3504,7 +3503,6 @@ s_AfrpInitLineData( if (s_IsASN1 (linestring)) { s_ReportASN1Error (afrp->report_error, afrp->report_error_userdata); - s_AlignFileRawFree (afrp); return eFalse; } @@ -5615,6 +5613,26 @@ s_FindBadDataCharsInSequence EBool match_not_in_beginning_gap; EBool match_not_in_end_gap; + char beginning_gap = '-'; + char middle_gap = '-'; + char end_gap = '-'; + + if (strlen(sip->beginning_gap) > 0 && + strchr(sip->beginning_gap, '-') == NULL){ + beginning_gap = sip->beginning_gap[0]; + } + + if (strlen(sip->middle_gap) > 0 && + strchr(sip->middle_gap, '-') == NULL){ + middle_gap = sip->middle_gap[0]; + } + + if (strlen(sip->end_gap) > 0 && + strchr(sip->end_gap, '-') == NULL){ + end_gap = sip->end_gap[0]; + } + + if (arsp == NULL || master_arsp == NULL || sip == NULL) { return eTrue; } @@ -5676,7 +5694,7 @@ s_FindBadDataCharsInSequence report_error, report_error_userdata); rval = eTrue; } else { - *lirp->curr_line_pos = '-'; + *lirp->curr_line_pos = beginning_gap; data_position ++; } } else { @@ -5741,7 +5759,7 @@ s_FindBadDataCharsInSequence data_position ++; } } else if (strchr (sip->middle_gap, curr_char) != NULL) { - *lirp->curr_line_pos = '-'; + *lirp->curr_line_pos = middle_gap; data_position ++; } else { /* Report error - found bad character in middle */ @@ -5765,7 +5783,7 @@ s_FindBadDataCharsInSequence report_error, report_error_userdata); rval = eTrue; } else { - *lirp->curr_line_pos = '-'; + *lirp->curr_line_pos = end_gap; data_position++; } curr_char = s_FindNthDataChar (lirp, data_position); @@ -5880,7 +5898,8 @@ s_ConvertDataToOutput afp->num_sequences++; } - if (afp->num_sequences != afrp->num_organisms + if (afp->num_organisms > 0 + && afp->num_sequences != afrp->num_organisms && afp->num_sequences / afp->num_segments != afrp->num_organisms) { s_ReportMissingOrganismInfo (afrp->report_error, afrp->report_error_userdata); diff --git a/c++/src/util/ddump_viewer.cpp b/c++/src/util/ddump_viewer.cpp index 7d0774a2..9b8fade6 100644 --- a/c++/src/util/ddump_viewer.cpp +++ b/c++/src/util/ddump_viewer.cpp @@ -1,4 +1,4 @@ -/* $Id: ddump_viewer.cpp 485909 2015-11-30 14:28:28Z gouriano $ +/* $Id: ddump_viewer.cpp 530228 2017-03-13 15:19:40Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -93,7 +93,7 @@ bool CDebugDumpViewer::x_CheckAddr( const void* addr, bool report) bool CDebugDumpViewer::x_CheckLocation(const char* file, int line) { - CNcbiRegistry& cfg = CNcbiApplication::Instance()->GetConfig(); + const CNcbiRegistry& cfg = CNcbiApplication::Instance()->GetConfig(); string section("DebugDumpBpt"); string value = cfg.Get( section, "enabled"); // the section is absent? - enable all @@ -106,7 +106,7 @@ bool CDebugDumpViewer::x_CheckLocation(const char* file, int line) // smth about this particular file? string name = CDirEntry(file).GetName(); - value = cfg.Get( section, name); + value = cfg.Get(section, name); if (value.empty() || (value=="none")) { return !enabled; // none are "enabled" } else if (value == "all") { diff --git a/c++/src/util/distribution.cpp b/c++/src/util/distribution.cpp index 3727aa6c..71a3f919 100644 --- a/c++/src/util/distribution.cpp +++ b/c++/src/util/distribution.cpp @@ -1,4 +1,4 @@ -/* $Id: distribution.cpp 448236 2014-10-03 14:05:43Z kazimird $ +/* $Id: distribution.cpp 512195 2016-08-29 13:53:40Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,11 +37,11 @@ BEGIN_NCBI_SCOPE -unsigned CDiscreteDistribution::GetNextValue() const +unsigned CDiscreteDistributionImpl::GetNextValue() const { CRandom::TValue random_number = m_RandomGen->GetRand(); - CRangeList::TRangeVector::const_iterator random_range = + CRangeListImpl::TRangeVector::const_iterator random_range = m_RangeVector.begin() + (random_number % m_RangeVector.size()); int diff = random_range->second - random_range->first; diff --git a/c++/src/util/format_guess.cpp b/c++/src/util/format_guess.cpp index 43b4f5c5..bdd2c3c8 100644 --- a/c++/src/util/format_guess.cpp +++ b/c++/src/util/format_guess.cpp @@ -1,4 +1,4 @@ -/* $Id: format_guess.cpp 518720 2016-11-07 18:16:47Z ivanov $ +/* $Id: format_guess.cpp 546439 2017-09-18 17:12:15Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -399,7 +399,13 @@ CFormatGuess::GuessFormat( return eUnknown; } if (!EnsureTestBuffer()) { - return eUnknown; + //one condition that won't allow us to get a good test buffer is an ascii + // file without any line breaks. so before giving up, let's specifically + // try any formats that would allow for that: + if(TestFormatNewick(eQuick)) { + return CFormatGuess::eNewick; + } + return CFormatGuess::eUnknown; } EMode mode = eQuick; @@ -569,6 +575,8 @@ CFormatGuess::EnsureTestBuffer() // If its all comment, read a twice as long buffer // Stop when its no longer all comment, end of the stream, // or Multiplier hits 1024 + + int Multiplier = 1; while(true) { m_iTestBufferSize = Multiplier * s_iTestBufferGranularity; @@ -629,7 +637,7 @@ CFormatGuess::EnsureStats() // m_iStatsCountBraces: Opening { and closing } braces // while ( ! TestBuffer.fail() ) { - NcbiGetlineEOL( TestBuffer, strLine ); + NcbiGetline( TestBuffer, strLine, "\r\n" ); // code in CFormatGuess::Format counts line ends // so, we will count them here as well if (!strLine.empty()) { @@ -1202,6 +1210,11 @@ CFormatGuess::TestFormatAlignment( return false; } + + if (TestFormatCLUSTAL()) { + return true; + } + // Alignment files come in all different shapes and broken formats, // and some of them are hard to recognize as such, in particular // if they have been hacked up in a text editor. @@ -1216,13 +1229,181 @@ CFormatGuess::TestFormatAlignment( if ( NPOS != it->find( "#NEXUS" ) ) { return true; } - if ( NPOS != it->find( "CLUSTAL" ) ) { - return true; - } } return false; } +// ----------------------------------------------------------------------------- +bool CFormatGuess::x_LooksLikeCLUSTALConservedInfo(const string& line) const +{ + + for (auto c : line) { + if ( isspace(c)) { + continue; + } + + if (c != ':' && + c != '*' && + c != '.') { + return false; + } + } + return true; +} + +// ----------------------------------------------------------------------------- +bool CFormatGuess::x_TryProcessCLUSTALSeqData(const string& line, string& id, size_t& seg_length) const +{ + vector toks; + NStr::Split(line, " \t", toks, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); + const size_t num_toks = toks.size(); + + if (num_toks != 2 && + num_toks != 3) { + return false; + } + + const string& seqdata = toks[1]; + + + unsigned int cumulated_res = 0; + if (num_toks == 3) { + cumulated_res = NStr::StringToUInt(toks[2], NStr::fConvErr_NoThrow); + if (cumulated_res == 0) { + return false; + } + } + + // Check sequence data + ESequenceType seqtype = + SequenceType(seqdata.c_str(), static_cast(seqdata.size()), eST_Strict); + + if (seqtype == eUndefined) { + return false; + } + + if (num_toks == 3) { + size_t num_gaps = count(seqdata.begin(), seqdata.end(), '-'); + if (((seqdata.size() - num_gaps) > cumulated_res)) { + return false; + } + } + + + id = toks[0]; + seg_length = seqdata.size(); + + return true; +} + + +// ----------------------------------------------------------------------------- + +namespace { // anonymous namespace + +struct SClustalBlockInfo +{ + bool m_InBlock; + unsigned int m_Size; + set m_Ids; + + + void Reset(void) { + m_InBlock = false; + m_Size = 0; + m_Ids.clear(); + } + + SClustalBlockInfo() { Reset(); } +}; + +} + +// ----------------------------------------------------------------------------- +bool +CFormatGuess::TestFormatCLUSTAL() +{ + + if (!EnsureTestBuffer()) { + return false; + } + + CNcbiIstrstream TestBuffer( + reinterpret_cast( m_pTestBuffer ), m_iTestDataSize ); + string strLine; + + SClustalBlockInfo block_info; + + bool has_valid_block = false; + size_t seg_length = 0; + size_t seg_length_prev = 0; + + + const bool buffer_full = m_iTestDataSize == m_iTestBufferSize; + + while ( !TestBuffer.eof() ) { + NcbiGetline(TestBuffer, strLine, "\r\n"); + + if (buffer_full && + TestBuffer.eof()) { // Skip last line if buffer is full + break; // to avoid misidentification due to line truncation + } + + if (TestBuffer.fail()) { + break; + } + + if (NStr::StartsWith(strLine, "CLUSTAL")) { + continue; + } + + if (NStr::IsBlank(strLine)) { + if (block_info.m_InBlock) { + if (block_info.m_Size < 2) { + return false; + } + block_info.Reset(); + } + continue; + } + + if (x_LooksLikeCLUSTALConservedInfo(strLine)) { + if (! block_info.m_InBlock || block_info.m_Size<2) { + return false; + } + block_info.Reset(); + continue; + } + + string seq_id; + if (!x_TryProcessCLUSTALSeqData(strLine, seq_id, seg_length)) { + return false; + } + + if (seg_length > 60) { + return false; + } + if (block_info.m_InBlock) { + if(seg_length != seg_length_prev) { + return false; + } + has_valid_block = true; + } + + if (block_info.m_Ids.find(seq_id) != block_info.m_Ids.end()) { + return false; + } + block_info.m_Ids.insert(seq_id); + + seg_length_prev = seg_length; + block_info.m_InBlock = true; + ++(block_info.m_Size); + } + + return has_valid_block; +} + + // ----------------------------------------------------------------------------- bool CFormatGuess::x_TestTableDelimiter(const string& delims) @@ -1745,13 +1926,21 @@ bool CFormatGuess::TestFormatSra(EMode /* not used */ ) bool CFormatGuess::TestFormatBam(EMode mode) { - // Check for a gzip header whose first (only) extra field spans - // at least six bytes and has the tag BC. - return (TestFormatGZip(mode) && m_iTestDataSize >= 18 - && (m_pTestBuffer[3] & 4) != 0 // extra field present - && (static_cast(m_pTestBuffer[10]) >= 6 - || m_pTestBuffer[11] != 0) // at least six bytes - && m_pTestBuffer[12] == 'B' && m_pTestBuffer[13] == 'C'); + //rw-9: + // the original heuristic to "guess" at the content of a gzip archive + // broke down and we found a whole class of false positives for the + // BAM format- on our very own FTP site no less! + //To really be sure we are dealing indeed with BAM we would have to + // decompress the beginning of the archive and peek inside- however, gzip + // decompression is not available in this module. + + //If reliable BAM detection is needed, use objtools/readers/format_guess_ex + // instead. It's a drop in replacement, and it's not any slower for any file + // format that can be detected reliably here (because it calls this code + // before doing any of the more fancy stuff). And because of the fancy + // stuff it does, it will even classify some files this code can't (though + // possibly at considerable extra expense). + return false; } @@ -1854,7 +2043,7 @@ size_t s_GetPrecedingFslashCount(const string& input, const size_t pos) return 0; } - int current_pos = pos-1; + int current_pos = static_cast(pos)-1; size_t num_fslash = 0; while ( current_pos >= 0 && input[current_pos] == '\\' ) { ++num_fslash; @@ -1896,7 +2085,7 @@ bool CFormatGuess::x_CheckStripJsonNumbers(string& testString) const list subStrings; // Split on white space - NStr::Split(testString, " \r\t\n", subStrings, NStr::fSplit_MergeDelims); + NStr::Split(testString, " \r\t\n", subStrings, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); for (auto it = subStrings.cbegin(); it != subStrings.cend(); ++it) { const string subString = *it; @@ -1983,7 +2172,7 @@ bool CFormatGuess::x_IsBlankOrNumbers(const string& testString) const list numStrings; // Split on white space - NStr::Split(testString, " \r\t\n", numStrings, NStr::fSplit_MergeDelims); + NStr::Split(testString, " \r\t\n", numStrings, NStr::fSplit_MergeDelimiters | NStr::fSplit_Truncate); for (auto numString : numStrings) { if (!x_IsNumber(numString)) { @@ -2746,7 +2935,8 @@ bool CFormatGuess::IsLineGff2( const string& line ) { vector tokens; - if ( NStr::Split(line, " \t", tokens, NStr::fSplit_Tokenize).size() < 8 ) { + const size_t num_cols = NStr::Split(line, " \t", tokens, NStr::fSplit_Tokenize).size(); + if ( num_cols < 8 || num_cols > 9 ) { return false; } if ( ! s_IsTokenPosInt( tokens[3] ) ) { diff --git a/c++/src/util/mutex_pool.cpp b/c++/src/util/mutex_pool.cpp index 94cd9793..4a4b7bbe 100644 --- a/c++/src/util/mutex_pool.cpp +++ b/c++/src/util/mutex_pool.cpp @@ -1,4 +1,4 @@ -/* $Id: mutex_pool.cpp 103491 2007-05-04 17:18:18Z kazimird $ +/* $Id: mutex_pool.cpp 534194 2017-04-25 14:02:33Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -50,13 +50,13 @@ CInitMutexPool::~CInitMutexPool(void) } -bool CInitMutexPool::AcquireMutex(CInitMutex_Base& init, CRef& mutex) +bool CInitMutexPool::AcquireMutex(CInitMutex_Base& init, CRef& mutex, bool force) { _ASSERT(!mutex); CRef local(init.m_Mutex); if ( !local ) { CFastMutexGuard guard(m_Pool_Mtx); - if ( init ) + if ( !force && init ) return false; local = init.m_Mutex; if ( !local ) { diff --git a/c++/src/util/rangelist.cpp b/c++/src/util/rangelist.cpp index 5f436604..b5f6ebaf 100644 --- a/c++/src/util/rangelist.cpp +++ b/c++/src/util/rangelist.cpp @@ -1,4 +1,4 @@ -/* $Id: rangelist.cpp 448238 2014-10-03 14:16:50Z kazimird $ +/* $Id: rangelist.cpp 511866 2016-08-25 03:53:47Z sadyrovr $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -44,7 +44,7 @@ static const char* s_SkipSpaces(const char* input_string) return input_string; } -void CRangeList::Parse(const char* init_string, +void CRangeListImpl::Parse(const char* init_string, const char* config_param_name, TRangeVector* range_vector) { diff --git a/c++/src/util/regexp/CMakeLists.regexp.lib.txt b/c++/src/util/regexp/CMakeLists.regexp.lib.txt new file mode 100644 index 00000000..85bda103 --- /dev/null +++ b/c++/src/util/regexp/CMakeLists.regexp.lib.txt @@ -0,0 +1,14 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/util/regexp/Makefile.regexp.lib +# +add_library(regexp + pcre_chartables pcre_compile pcre_config pcre_dfa_exec pcre_exec + pcre_fullinfo pcre_get pcre_globals pcre_info pcre_maketables + pcre_newline pcre_ord2utf8 pcre_refcount pcre_study pcre_tables + pcre_try_flipped pcre_ucd pcre_valid_utf8 pcre_version pcre_xclass + pcreposix +) + +include_directories(SYSTEM ${includedir}/util/regexp) +add_definitions(-DHAVE_CONFIG_H) + diff --git a/c++/src/util/regexp/CMakeLists.test_pcre.app.txt b/c++/src/util/regexp/CMakeLists.test_pcre.app.txt new file mode 100644 index 00000000..efee8419 --- /dev/null +++ b/c++/src/util/regexp/CMakeLists.test_pcre.app.txt @@ -0,0 +1,13 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/util/regexp/Makefile.test_pcre.app +# +add_executable(test_pcre-app + pcretest +) + +set_target_properties(test_pcre-app PROPERTIES OUTPUT_NAME test_pcre) + +target_link_libraries(test_pcre-app + ${PCRE_LIBS} +) + diff --git a/c++/src/util/regexp/CMakeLists.txt b/c++/src/util/regexp/CMakeLists.txt new file mode 100644 index 00000000..3f558c25 --- /dev/null +++ b/c++/src/util/regexp/CMakeLists.txt @@ -0,0 +1,10 @@ +############################################################################## +# +# + +# Include projects from this directory +if (USE_LOCAL_PCRE) + include(CMakeLists.regexp.lib.txt) + include(CMakeLists.test_pcre.app.txt) +endif() + diff --git a/c++/src/util/sequtil/CMakeLists.sequtil.lib.txt b/c++/src/util/sequtil/CMakeLists.sequtil.lib.txt new file mode 100644 index 00000000..98e83522 --- /dev/null +++ b/c++/src/util/sequtil/CMakeLists.sequtil.lib.txt @@ -0,0 +1,11 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/util/sequtil/Makefile.sequtil.lib +# +add_library(sequtil + sequtil sequtil_convert sequtil_convert_imp sequtil_manip sequtil_tables + sequtil_shared +) + +target_link_libraries(sequtil + xncbi +) diff --git a/c++/src/util/sequtil/CMakeLists.txt b/c++/src/util/sequtil/CMakeLists.txt new file mode 100644 index 00000000..21e7990f --- /dev/null +++ b/c++/src/util/sequtil/CMakeLists.txt @@ -0,0 +1,8 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.sequtil.lib.txt) + +# Recurse subdirectories diff --git a/c++/src/util/strbuffer.cpp b/c++/src/util/strbuffer.cpp index 26f9b9d7..d1c87975 100644 --- a/c++/src/util/strbuffer.cpp +++ b/c++/src/util/strbuffer.cpp @@ -1,4 +1,4 @@ -/* $Id: strbuffer.cpp 511367 2016-08-22 12:15:50Z ivanov $ +/* $Id: strbuffer.cpp 511084 2016-08-18 15:24:34Z vasilche $ * =========================================================================== * * PUBLIC DOMAIN NOTICE diff --git a/c++/src/util/stream_source.cpp b/c++/src/util/stream_source.cpp index 1fd4f79d..6341d7b5 100644 --- a/c++/src/util/stream_source.cpp +++ b/c++/src/util/stream_source.cpp @@ -1,4 +1,4 @@ -/* $Id: stream_source.cpp 497774 2016-04-11 11:24:26Z mozese2 $ +/* $Id: stream_source.cpp 533641 2017-04-18 18:00:24Z mozese2 $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -135,6 +135,11 @@ CInputStreamSource::CInputStreamSource(const CArgs& args, const string& prefix) InitArgs(args, prefix); } + +CInputStreamSource::~CInputStreamSource() +{ +} + void CInputStreamSource::InitArgs(const CArgs& args, const string &prefix) { m_Args.Assign(args); @@ -380,7 +385,7 @@ size_t CInputStreamSource::GetCurrentStreamIndex(size_t* count) const return m_CurrIndex; } -CInputStreamSource::operator bool() +CInputStreamSource::operator bool() const { // The stream contains data if it references a stream (given on input) // owns a stream (extracted from a manifest), or still has a non-empty diff --git a/c++/src/util/tables/CMakeLists.tables.lib.txt b/c++/src/util/tables/CMakeLists.tables.lib.txt new file mode 100644 index 00000000..314e91d3 --- /dev/null +++ b/c++/src/util/tables/CMakeLists.tables.lib.txt @@ -0,0 +1,8 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/util/tables/Makefile.tables.lib +# +add_library(tables + raw_scoremat +) + +target_link_libraries(tables) diff --git a/c++/src/util/tables/CMakeLists.txt b/c++/src/util/tables/CMakeLists.txt new file mode 100644 index 00000000..e6f049b7 --- /dev/null +++ b/c++/src/util/tables/CMakeLists.txt @@ -0,0 +1,9 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.tables.lib.txt) + +# Recurse subdirectories +add_subdirectory(test ) diff --git a/c++/src/util/thread_pool.cpp b/c++/src/util/thread_pool.cpp index 61e42c7d..f835c3e7 100644 --- a/c++/src/util/thread_pool.cpp +++ b/c++/src/util/thread_pool.cpp @@ -1,4 +1,4 @@ -/* $Id: thread_pool.cpp 497641 2016-04-08 15:17:34Z ucko $ +/* $Id: thread_pool.cpp 535328 2017-05-08 15:21:08Z ivanov $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -1662,7 +1662,7 @@ CThreadPool_Impl::AddTask(CThreadPool_Task* task, const CTimeSpan* timeout) } CThreadPool_Guard guard(this, false); - auto_ptr adjusted_timeout; + unique_ptr adjusted_timeout; if (!m_IsQueueAllowed) { guard.Guard(); diff --git a/c++/src/util/util_misc.cpp b/c++/src/util/util_misc.cpp index 315726c9..87d0d51e 100644 --- a/c++/src/util/util_misc.cpp +++ b/c++/src/util/util_misc.cpp @@ -1,4 +1,4 @@ -/* $Id: util_misc.cpp 485043 2015-11-18 14:43:31Z sadyrovr $ +/* $Id: util_misc.cpp 530021 2017-03-09 19:06:46Z ucko $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -190,5 +190,35 @@ void g_IgnoreDataFile(const string& pattern, bool do_ignore) } +bool g_IsDataFileOld(const CTempString& path, const CTempString& id_line) +{ + // $Id: FILENAME REVISION DATE TIME ... + SIZE_TYPE pos = id_line.find("$Id: "); + if (pos == NPOS) { + return false; + } + pos = id_line.find(' ', pos + 5); // skip filename + if (pos == NPOS) { + return false; + } + pos = id_line.find(' ', pos + 1); // skip revision + if (pos == NPOS) { + return false; + } + SIZE_TYPE end = id_line.find(' ', ++pos); + if (end == NPOS) { + return false; + } + end = id_line.find(' ', end + 1); // got date, now want time too + if (end == NPOS) { + return false; + } + CTempString builtin_timestamp_str = id_line.substr(pos, end - pos); + CTime builtin_timestamp(builtin_timestamp_str, "Y-M-D h:m:sZ"); + CTime file_timestamp; + CFile(path).GetTime(&file_timestamp); + return file_timestamp < builtin_timestamp; +} + END_NCBI_SCOPE diff --git a/c++/src/util/xregexp/CMakeLists.txt b/c++/src/util/xregexp/CMakeLists.txt new file mode 100644 index 00000000..076bdd1d --- /dev/null +++ b/c++/src/util/xregexp/CMakeLists.txt @@ -0,0 +1,8 @@ +############################################################################## +# +# + +# Include projects from this directory +include(CMakeLists.xregexp.lib.txt) +include(CMakeLists.xregexp_template_tester.lib.txt) + diff --git a/c++/src/util/xregexp/CMakeLists.xregexp.lib.txt b/c++/src/util/xregexp/CMakeLists.xregexp.lib.txt new file mode 100644 index 00000000..dc258bc9 --- /dev/null +++ b/c++/src/util/xregexp/CMakeLists.xregexp.lib.txt @@ -0,0 +1,11 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake.2015-01-24/src/util/xregexp/Makefile.xregexp.lib +# +add_library(xregexp + regexp arg_regexp mask_regexp +) +include_directories(SYSTEM ${PCRE_INCLUDE}) + +target_link_libraries(xregexp + ${PCRE_LIBS} xncbi +) diff --git a/c++/src/util/xregexp/CMakeLists.xregexp_template_tester.lib.txt b/c++/src/util/xregexp/CMakeLists.xregexp_template_tester.lib.txt new file mode 100644 index 00000000..5398baed --- /dev/null +++ b/c++/src/util/xregexp/CMakeLists.xregexp_template_tester.lib.txt @@ -0,0 +1,9 @@ +# +# Autogenerated from /export/home/dicuccio/cpp-cmake/cpp-cmake/src/util/xregexp/Makefile.xregexp_template_tester.lib +# +add_library(xregexp_template_tester + regexp_template_tester +) +target_link_libraries(xregexp_template_tester + xregexp +) diff --git a/debian/changelog b/debian/changelog index fddc044f..69b8ed00 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,19 @@ +ncbi-blast+ (2.7.1-1) UNRELEASED; urgency=medium + + * New upstream release + d/patches: update patch for new release + d/control: + go to standards 4.1.3 + add mbedtls dependency + + + [TODO] + new embedded library mbedtls in c++/src/connect/ + need to fix to use debian library rather than static link + compiled object in libxconnect.so + + -- Olivier Sallou Sat, 10 Feb 2018 17:35:31 +0000 + ncbi-blast+ (2.6.0-1) unstable; urgency=medium * New upstream release diff --git a/debian/control b/debian/control index d56e2cb4..374ba78e 100644 --- a/debian/control +++ b/debian/control @@ -11,10 +11,11 @@ Build-Depends: autotools-dev, libbz2-dev, libc-dev-bin, libgnutls28-dev, + libmbedtls-dev, libpcre3-dev, time, zlib1g-dev -Standards-Version: 3.9.8 +Standards-Version: 4.1.3 Vcs-Browser: https://anonscm.debian.org/cgit/debian-med/ncbi-blast+.git Vcs-Git: https://anonscm.debian.org/git/debian-med/ncbi-blast+.git Homepage: http://www.ncbi.nlm.nih.gov/IEB/ToolBox/CPP_DOC/ @@ -58,7 +59,7 @@ Package: blast2 Architecture: all Multi-Arch: foreign Section: oldlibs -Priority: extra +Priority: optional Depends: ncbi-blast+-legacy, ${misc:Depends} Description: transitional dummy package to ncbi-blast+-legacy diff --git a/debian/copyright b/debian/copyright index 03348288..53f040e4 100644 --- a/debian/copyright +++ b/debian/copyright @@ -2,6 +2,21 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: ncbi-blast+ Upstream-Contact: blastsoft@ncbi.nlm.nih.gov +Files: c++/src/connect/mbedtls/* +Copyright: 2006-2015, ARM Limited, All Rights Reserved +License: Apache-2.0 + Licensed under the Apache License, Version 2.0 (the "License"); you may + not use this file except in compliance with the License. + You may obtain a copy of the License at + . + http://www.apache.org/licenses/LICENSE-2.0 + . + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + Files: c++/src/html/ncbi_menu.js c++/src/html/ncbi_menu_dnd.js c++/src/html/ncbi_menu_dnd.js diff --git a/debian/patches/fix_lib_deps b/debian/patches/fix_lib_deps index 0692cafe..9182e5b8 100644 --- a/debian/patches/fix_lib_deps +++ b/debian/patches/fix_lib_deps @@ -14,26 +14,6 @@ Subject: ensure that all libraries link against all direct dependencies Debian-Bug: 633567. Author: Aaron M. Ucko Last-Update: 2016-12-05 ---- a/c++/src/algo/blast/api/Makefile.xblast.lib -+++ b/c++/src/algo/blast/api/Makefile.xblast.lib -@@ -76,14 +76,15 @@ - magicblast_options \ - magicblast - --SRC = $(SRC_C:%=.core_%) $(SRC_CXX) -+SRC = $(SRC_CXX) # $(SRC_C:%=.core_%) - - LIB = xblast - - DLL_LIB = xalgoblastdbindex composition_adjustment xalgowinmask \ - xalgodustmask seqmasks_io seqdb $(OBJREAD_LIBS) xobjutil \ - blastdb xnetblastcli xnetblast scoremat xconnect tables \ -- $(SOBJMGR_LIBS) -+ $(SOBJMGR_LIBS) blast seqdb seqset seq general \ -+ xser xconnect sequtil tables xutil xncbi - - CFLAGS = $(FAST_CFLAGS) - CPPFLAGS = -DNCBI_MODULE=BLAST $(ORIG_CPPFLAGS) --- a/c++/src/algo/blast/blastinput/Makefile.blastinput.lib +++ b/c++/src/algo/blast/blastinput/Makefile.blastinput.lib @@ -27,7 +27,9 @@ @@ -114,7 +94,7 @@ Last-Update: 2016-12-05 seqmasks_io --- a/c++/src/build-system/library_relations.txt +++ b/c++/src/build-system/library_relations.txt -@@ -1287,7 +1287,7 @@ +@@ -1308,7 +1308,7 @@ xbiosample_util needs $(XFORMAT_LIBS) xbiosample_util needs xalnmgr xbiosample_util needs xmlwrapp @@ -134,17 +114,6 @@ Last-Update: 2016-12-05 CPPFLAGS = $(ORIG_CPPFLAGS) $(FASTCGI_INCLUDE) WATCHERS = vakatov ---- a/c++/src/connect/Makefile.xconnect.lib -+++ b/c++/src/connect/Makefile.xconnect.lib -@@ -14,6 +14,8 @@ - LIB = xconnect - PROJ_TAG = core - -+DLL_LIB = xncbi -+ - LIBS = $(NETWORK_LIBS) $(ORIG_LIBS) - - WATCHERS = lavr elisovdn --- a/c++/src/corelib/Makefile.test_boost.lib +++ b/c++/src/corelib/Makefile.test_boost.lib @@ -3,6 +3,8 @@ @@ -233,17 +202,6 @@ Last-Update: 2016-12-05 WATCHERS = vasilche ---- a/c++/src/objects/seq/Makefile.seq.lib -+++ b/c++/src/objects/seq/Makefile.seq.lib -@@ -14,6 +14,8 @@ - - DLL_LIB = seqcode pub general xser sequtil - -+DLL_LIB = seqcode pub biblio general xser sequtil xutil xncbi -+ - WATCHERS = vasilche grichenk - - --- a/c++/src/objects/seqcode/Makefile.seqcode.lib +++ b/c++/src/objects/seqcode/Makefile.seqcode.lib @@ -1,6 +1,8 @@ @@ -266,17 +224,6 @@ Last-Update: 2016-12-05 USES_LIBRARIES = \ ---- a/c++/src/objects/seqset/Makefile.seqset.lib -+++ b/c++/src/objects/seqset/Makefile.seqset.lib -@@ -1,6 +1,8 @@ - LIB = seqset - SRC = seqset__ seqset___ gb_release_file - -+DLL_LIB = seq general xser xncbi -+ - - USES_LIBRARIES = \ - $(SEQ_LIBS) pub --- a/c++/src/objects/seqsplit/Makefile.seqsplit.lib +++ b/c++/src/objects/seqsplit/Makefile.seqsplit.lib @@ -1,6 +1,8 @@ @@ -312,9 +259,9 @@ Last-Update: 2016-12-05 --- a/c++/src/objmgr/util/Makefile.util.lib +++ b/c++/src/objmgr/util/Makefile.util.lib -@@ -11,6 +11,8 @@ +@@ -14,6 +14,8 @@ - DLL_LIB = $(SOBJMGR_LIBS) + DLL_LIB = submit $(SOBJMGR_LIBS) +DLL_LIB = xobjmgr seqset seq pub biblio general xser sequtil xutil xncbi + @@ -367,7 +314,7 @@ Last-Update: 2016-12-05 CXXFLAGS = $(FAST_CXXFLAGS) --- a/c++/src/objtools/blast/seqdb_writer/Makefile.writedb.lib +++ b/c++/src/objtools/blast/seqdb_writer/Makefile.writedb.lib -@@ -8,6 +8,9 @@ +@@ -11,6 +11,9 @@ LIB = writedb @@ -449,7 +396,7 @@ Last-Update: 2016-12-05 +++ b/c++/src/objtools/data_loaders/genbank/id1/Makefile.ncbi_xreader_id1.lib @@ -12,6 +12,8 @@ # Dependencies for shared library - DLL_LIB = xconnect ncbi_xreader$(DLL) + DLL_LIB = ncbi_xreader$(DLL) $(GENBANK_READER_LDEP) +DLL_DLIB = ncbi_xreader xobjmgr id1 seq general xser xconnect xutil xncbi + @@ -622,16 +569,6 @@ Last-Update: 2016-12-05 USES_LIBRARIES = \ xser ---- a/c++/src/objects/entrez2/Makefile.entrez2cli.lib -+++ b/c++/src/objects/entrez2/Makefile.entrez2cli.lib -@@ -5,6 +5,7 @@ - LIB = entrez2cli - SRC = entrez2_client entrez2_client_ - -+DLL_LIB = entrez2 xconnect xser xutil xncbi - - USES_LIBRARIES = \ - entrez2 xconnect --- a/c++/src/objects/gbseq/Makefile.gbseq.lib +++ b/c++/src/objects/gbseq/Makefile.gbseq.lib @@ -1,6 +1,7 @@ @@ -704,7 +641,7 @@ Last-Update: 2016-12-05 $(SEQ_LIBS) pub xconnect --- a/c++/src/objects/taxon3/Makefile.taxon3.lib +++ b/c++/src/objects/taxon3/Makefile.taxon3.lib -@@ -7,6 +7,7 @@ +@@ -8,6 +8,7 @@ WATCHERS = bollin holmesbr @@ -795,14 +732,63 @@ Last-Update: 2016-12-05 USES_LIBRARIES = \ xregexp $(PCRE_LIB) $(PCRE_LIBS) xncbi ---- a/c++/src/algo/blast/Makefile.blast_macros.mk -+++ b/c++/src/algo/blast/Makefile.blast_macros.mk -@@ -18,7 +18,7 @@ - BLAST_SRA_LIBS=blast_sra $(SRAXF_LIBS) vxf $(SRA_LIBS) - - # BLAST_FORMATTER_LIBS and BLAST_INPUT_LIBS need $BLAST_LIBS --BLAST_LIBS = xblast xalgoblastdbindex composition_adjustment \ -+BLAST_LIBS = xblast xalgoblastdbindex composition_adjustment blast \ - xalgodustmask xalgowinmask seqmasks_io seqdb blast_services xalnmgr \ - xobjutil $(OBJREAD_LIBS) xnetblastcli xnetblast blastdb scoremat tables - # BLAST additionally needs xconnect $(SOBJMGR_LIBS) or $(OBJMGR_LIBS) +--- a/c++/src/algo/blast/api/Makefile.xblast.lib ++++ b/c++/src/algo/blast/api/Makefile.xblast.lib +@@ -77,11 +77,11 @@ + magicblast_options \ + magicblast + +-SRC = $(SRC_C:%=.core_%) $(SRC_CXX) ++SRC = $(SRC_CXX) + + LIB = xblast + +-DLL_LIB = $(BLAST_LDEP) $(SOBJMGR_LIBS) ++DLL_LIB = $(BLAST_LDEP) $(SOBJMGR_LIBS) blast seqdb seqset seq general xser xconnect sequtil tables xutil xncbi + + CFLAGS = $(FAST_CFLAGS) + CPPFLAGS = -DNCBI_MODULE=BLAST $(ORIG_CPPFLAGS) +--- a/c++/src/connect/Makefile.xconnect.lib ++++ b/c++/src/connect/Makefile.xconnect.lib +@@ -14,6 +14,8 @@ + LIB = xconnect + PROJ_TAG = core + ++DLL_LIB = xncbi ++ + LIBS = $(NETWORK_LIBS) $(ORIG_LIBS) + + WATCHERS = lavr mcelhany +--- a/c++/src/objects/seq/Makefile.seq.lib ++++ b/c++/src/objects/seq/Makefile.seq.lib +@@ -12,7 +12,7 @@ + seq_loc_mapper_base seq_align_mapper_base seqlocinfo sofa_map so_map \ + seq_loc_from_string seq_loc_reverse_complementer + +-DLL_LIB = seqcode pub general xser sequtil ++DLL_LIB = seqcode pub biblio general xser sequtil xutil xncbi + + WATCHERS = vasilche grichenk bollin ludwigf + +--- a/c++/src/objects/seqset/Makefile.seqset.lib ++++ b/c++/src/objects/seqset/Makefile.seqset.lib +@@ -1,7 +1,7 @@ + LIB = seqset + SRC = seqset__ seqset___ gb_release_file + +-DLL_LIB = $(SEQ_LIBS) ++DLL_LIB = $(SEQ_LIBS) xser xncbi + + USES_LIBRARIES = \ + $(SEQ_LIBS) pub +--- a/c++/src/objects/entrez2/Makefile.entrez2cli.lib ++++ b/c++/src/objects/entrez2/Makefile.entrez2cli.lib +@@ -5,7 +5,7 @@ + LIB = entrez2cli + SRC = entrez2_client entrez2_client_ + +-DLL_LIB = entrez2 xconnect ++DLL_LIB = entrez2 xconnect xser xutil xncbi + + USES_LIBRARIES = \ + entrez2 xconnect diff --git a/debian/patches/hurd_fixes b/debian/patches/hurd_fixes index 13d20726..c664ef2a 100644 --- a/debian/patches/hurd_fixes +++ b/debian/patches/hurd_fixes @@ -9,7 +9,7 @@ Author: Aaron M. Ucko Last-Update: 2011-06-10 --- a/c++/src/build-system/configure +++ b/c++/src/build-system/configure -@@ -9157,7 +9157,7 @@ +@@ -9716,7 +9716,7 @@ solaris* ) CONF_f_runpath="-R" ;; @@ -20,7 +20,7 @@ Last-Update: 2011-06-10 irix*:* | linux*:KCC | *:Compaq ) --- a/c++/src/build-system/configure.ac +++ b/c++/src/build-system/configure.ac -@@ -1939,7 +1939,7 @@ +@@ -2081,7 +2081,7 @@ solaris* ) CONF_f_runpath="-R" ;; diff --git a/debian/patches/no_multiarch_rpath b/debian/patches/no_multiarch_rpath index 15cd5e30..a5601282 100644 --- a/debian/patches/no_multiarch_rpath +++ b/debian/patches/no_multiarch_rpath @@ -10,7 +10,7 @@ Author: Aaron M. Ucko Last-Update: 2011-08-28 --- a/c++/src/build-system/configure +++ b/c++/src/build-system/configure -@@ -9285,7 +9285,7 @@ +@@ -9823,7 +9823,7 @@ break ;; /* ) @@ -21,7 +21,7 @@ Last-Update: 2011-08-28 esac --- a/c++/src/build-system/configure.ac +++ b/c++/src/build-system/configure.ac -@@ -2006,7 +2006,7 @@ +@@ -2148,7 +2148,7 @@ break ;; /* ) diff --git a/debian/patches/suppress_gnutls_version_check b/debian/patches/suppress_gnutls_version_check index 7dca5fc0..3794f6c1 100644 --- a/debian/patches/suppress_gnutls_version_check +++ b/debian/patches/suppress_gnutls_version_check @@ -1,6 +1,6 @@ --- a/c++/src/connect/ncbi_gnutls.c +++ b/c++/src/connect/ncbi_gnutls.c -@@ -585,6 +585,7 @@ static EIO_Status s_GnuTlsInit(FSSLPull +@@ -661,6 +661,7 @@ assert(!s_GnuTlsCredAnon); @@ -8,11 +8,11 @@ version = gnutls_check_version(0); if (strcasecmp(GNUTLS_VERSION, version) != 0) { CORE_LOGF(eLOG_Critical, -@@ -592,6 +593,7 @@ static EIO_Status s_GnuTlsInit(FSSLPull +@@ -668,6 +669,7 @@ GNUTLS_VERSION, version)); assert(0); } +#endif - val = ConnNetInfo_GetValue(0, "GNUTLS_LOGLEVEL", buf, sizeof(buf), 0); - CORE_LOCK_READ; + if (!pull || !push) + return eIO_InvalidArg; diff --git a/debian/patches/use_pie_for_apps b/debian/patches/use_pie_for_apps index b43c7b4f..89bc7d7d 100644 --- a/debian/patches/use_pie_for_apps +++ b/debian/patches/use_pie_for_apps @@ -7,7 +7,7 @@ Author: Aaron M. Ucko Last-Update: 2012-05-10 --- a/c++/src/build-system/Makefile.app.in +++ b/c++/src/build-system/Makefile.app.in -@@ -24,8 +24,8 @@ default_rule: all +@@ -24,8 +24,8 @@ ### C/C++ source file compilation setup @@ -18,12 +18,12 @@ Last-Update: 2012-05-10 SOURCES = @UNIX_SRC@ $(SRC) ### Standard application build rules -@@ -53,7 +53,7 @@ ifneq "" "$(wildcard Makefile.$(TMPL).ap - endif - endif +@@ -56,7 +56,7 @@ + include $(builddir)/Makefile.$(Rules) --CMD_BASE = $(LINK_WRAPPER) $(LINK) $(LDFLAGS) $(APP_LDFLAGS) $(XOBJ) $(XOBJ2) $(PRE_LIBS) -+CMD_BASE = $(LINK_WRAPPER) $(LINK) $(LDFLAGS) $(APP_LDFLAGS) -fPIE -pie $(XOBJ) $(XOBJ2) $(PRE_LIBS) + CMD_BASE = $(LINK_WRAPPER) $(LINK) +-CMD_BASEARGS = $(LDFLAGS) $(APP_LDFLAGS) $(XOBJ) $(XOBJ2) $(PRE_LIBS) ++CMD_BASEARGS = $(LDFLAGS) $(APP_LDFLAGS) -fPIE -pie $(XOBJ) $(XOBJ2) $(PRE_LIBS) CMD_TAIL = @f_outexe@$(XAPP) $(LINK_FILTER) - CMD = $(CMD_BASE) $(XLIB) $(XAPP_LIBS) $(CMD_TAIL) - CMD2 = $(CMD_BASE) $(XLIB2) $(XAPP_LIBS2) $(CMD_TAIL) + CMD_ARGS = $(CMD_BASEARGS) $(XLIB) $(XAPP_LIBS) + CMD_ARGS2 = $(CMD_BASEARGS) $(XLIB2) $(XAPP_LIBS2) diff --git a/debian/rules b/debian/rules index 62ef3e39..65e6748e 100755 --- a/debian/rules +++ b/debian/rules @@ -13,7 +13,8 @@ endif DEB_CONFIGURE_EXTRA_FLAGS=--with-dll --with-mt --without-autodep \ --without-makefile-auto-update --with-flat-makefile --without-caution \ --without-dbapi --without-lzo --with-runpath=/usr/lib/ncbi-blast+ \ - --with-build-root=BUILD --without-debug --without-downloaded-vdb + --with-build-root=BUILD --without-debug --without-downloaded-vdb \ + --with-mbedtls proj=algo/blast/ app/ objmgr/ objtools/align_format/ objtools/blast/ #ifneq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) @@ -125,3 +126,4 @@ override_dh_gencontrol-indep: %: dh $@ -Dc++ --with autotools_dev + #dh $@ -Dc++ -- 2.30.2

  • 5}wG=90I6klwbNt-^s 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